diff --git a/.gitignore b/.gitignore index 748683d..0d2a029 100644 --- a/.gitignore +++ b/.gitignore @@ -172,3 +172,5 @@ UpgradeLog*.htm # Microsoft Fakes FakesAssemblies/ +/Scripts/Output/Scripts.CS.dll +/Scripts/Output/Scripts.CS.hash diff --git a/Data/App.config b/Data/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/Data/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Data/Assemblies.cfg b/Data/Assemblies.cfg new file mode 100644 index 0000000..e10eab9 --- /dev/null +++ b/Data/Assemblies.cfg @@ -0,0 +1,10 @@ +System.dll +System.Web.dll +System.Xml.dll +System.Data.dll +System.Drawing.dll +System.Windows.Forms.dll +Ultima.dll +OrbServerSDK.dll +UOArchitectInterface.dll +System.Runtime.Remoting.dll \ No newline at end of file diff --git a/Data/Assemblies_4_0.cfg b/Data/Assemblies_4_0.cfg new file mode 100644 index 0000000..7ae685d --- /dev/null +++ b/Data/Assemblies_4_0.cfg @@ -0,0 +1,11 @@ +System.dll +System.Core.dll +System.Web.dll +System.Xml.dll +System.Data.dll +System.Drawing.dll +System.Windows.Forms.dll +Ultima.dll +OrbServerSDK.dll +UOArchitectInterface.dll +System.Runtime.Remoting.dll \ No newline at end of file diff --git a/Data/Binary/Bounds.bin b/Data/Binary/Bounds.bin new file mode 100644 index 0000000..214ca6e Binary files /dev/null and b/Data/Binary/Bounds.bin differ diff --git a/Data/Bulk Orders/Blacksmith/armor.cfg b/Data/Bulk Orders/Blacksmith/armor.cfg new file mode 100644 index 0000000..75df809 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/armor.cfg @@ -0,0 +1,29 @@ +# Armor + +ChainChest 0x13BF +ChainLegs 0x13BE +Bascinet 0x140C +ChainCoif 0x13BB +CloseHelm 0x1408 +Helmet 0x140A +NorseHelm 0x140E +PlateHelm 0x1412 +FemalePlateChest 0x1C04 +PlateArms 0x1410 +PlateChest 0x1415 +PlateGloves 0x1414 +PlateGorget 0x1413 +PlateLegs 0x1411 +RingmailArms 0x13EE +RingmailChest 0x13EC +RingmailGloves 0x13EB +RingmailLegs 0x13F0 + +# Shields + +BronzeShield 0x1B72 +Buckler 0x1B73 +HeaterShield 0x1B76 +MetalKiteShield 0x1B74 +MetalShield 0x1B7B +WoodenKiteShield 0x1B78 \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largeaxes.cfg b/Data/Bulk Orders/Blacksmith/largeaxes.cfg new file mode 100644 index 0000000..43e9079 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largeaxes.cfg @@ -0,0 +1,8 @@ +# Large Axes bulk order + +Axe 0x0F49 +BattleAxe 0x0F47 +DoubleAxe 0x0F4B +ExecutionersAxe 0x0F45 +LargeBattleAxe 0x13FB +TwoHandedAxe 0x1443 \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largechain.cfg b/Data/Bulk Orders/Blacksmith/largechain.cfg new file mode 100644 index 0000000..67763b4 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largechain.cfg @@ -0,0 +1,5 @@ +# Large chainmail bulk order + +ChainCoif 0x13BB +ChainLegs 0x13BE +ChainChest 0x13BF \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largefencing.cfg b/Data/Bulk Orders/Blacksmith/largefencing.cfg new file mode 100644 index 0000000..ceb6d9e --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largefencing.cfg @@ -0,0 +1,7 @@ +# Large Fencing bulk order + +Dagger 0x0F52 +ShortSpear 0x1403 +Spear 0x0F62 +WarFork 0x1405 +Kryss 0x1401 diff --git a/Data/Bulk Orders/Blacksmith/largemaces.cfg b/Data/Bulk Orders/Blacksmith/largemaces.cfg new file mode 100644 index 0000000..e4407ca --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largemaces.cfg @@ -0,0 +1,8 @@ +# Large Maces bulk order + +WarAxe 0x13B0 +HammerPick 0x143D +Mace 0x0F5C +Maul 0x143B +WarHammer 0x1439 +WarMace 0x1407 \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largeplate.cfg b/Data/Bulk Orders/Blacksmith/largeplate.cfg new file mode 100644 index 0000000..0acfdd4 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largeplate.cfg @@ -0,0 +1,8 @@ +# Large platemail bulk order + +PlateArms 0x1410 +PlateLegs 0x1411 +PlateHelm 0x1412 +PlateGorget 0x1413 +PlateGloves 0x1414 +PlateChest 0x1415 \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largepolearms.cfg b/Data/Bulk Orders/Blacksmith/largepolearms.cfg new file mode 100644 index 0000000..d5ab77c --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largepolearms.cfg @@ -0,0 +1,4 @@ +# Large Polearms bulk order + +Bardiche 0x0F4D +Halberd 0x143E \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largering.cfg b/Data/Bulk Orders/Blacksmith/largering.cfg new file mode 100644 index 0000000..7f15dd7 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largering.cfg @@ -0,0 +1,6 @@ +# Large ringmail bulk order + +RingmailGloves 0x13EB +RingmailChest 0x13EC +RingmailArms 0x13EE +RingmailLegs 0x13F0 \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/largeswords.cfg b/Data/Bulk Orders/Blacksmith/largeswords.cfg new file mode 100644 index 0000000..cdc1841 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/largeswords.cfg @@ -0,0 +1,8 @@ +# Large Swords bulk order + +Broadsword 0x0F5E +Cutlass 0x1441 +Katana 0x13FF +Longsword 0x0F61 +Scimitar 0x13B6 +VikingSword 0x13B9 \ No newline at end of file diff --git a/Data/Bulk Orders/Blacksmith/weapons.cfg b/Data/Bulk Orders/Blacksmith/weapons.cfg new file mode 100644 index 0000000..ed04c43 --- /dev/null +++ b/Data/Bulk Orders/Blacksmith/weapons.cfg @@ -0,0 +1,28 @@ +# Weapons + +Axe 0x0F49 +BattleAxe 0x0F47 +Dagger 0x0F52 +DoubleAxe 0x0F4B +ExecutionersAxe 0x0F45 +LargeBattleAxe 0x13FB +TwoHandedAxe 0x1443 +WarAxe 0x13B0 +HammerPick 0x143D +Mace 0x0F5C +Maul 0x143B +WarHammer 0x1439 +WarMace 0x1407 +Bardiche 0x0F4D +Halberd 0x143E +ShortSpear 0x1403 +Spear 0x0F62 +WarFork 0x1405 +Broadsword 0x0F5E +Cutlass 0x1441 +Katana 0x13FF +Kryss 0x1401 +Longsword 0x0F61 +Scimitar 0x13B6 +#ThinLongsword 0x13B8 +VikingSword 0x13B9 \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/boneset.cfg b/Data/Bulk Orders/Tailoring/boneset.cfg new file mode 100644 index 0000000..af5a431 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/boneset.cfg @@ -0,0 +1,7 @@ +# Bone collection large bulk order + +BoneHelm 0x1451 +BoneGloves 0x1450 +BoneArms 0x144E +BoneLegs 0x1452 +BoneChest 0x144F \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/cloth.cfg b/Data/Bulk Orders/Tailoring/cloth.cfg new file mode 100644 index 0000000..f01860c --- /dev/null +++ b/Data/Bulk Orders/Tailoring/cloth.cfg @@ -0,0 +1,31 @@ +# Clothing + +SkullCap 0x1544 +Bandana 0x1540 +FloppyHat 0x1713 +Cap 0x1715 +WideBrimHat 0x1714 +StrawHat 0x1717 +TallStrawHat 0x1716 +WizardsHat 0x1718 +Bonnet 0x1719 +FeatheredHat 0x171A +TricorneHat 0x171B +JesterHat 0x171C +Doublet 0x1F7B +Shirt 0x1517 +FancyShirt 0x1EFD +Tunic 0x1FA1 +Surcoat 0x1FFD +PlainDress 0x1F01 +FancyDress 0x1EFF +Cloak 0x1515 +Robe 0x1F03 +JesterSuit 0x1F9F +ShortPants 0x152E +LongPants 0x1539 +Kilt 0x1537 +Skirt 0x1516 +BodySash 0x1541 +HalfApron 0x153B +FullApron 0x153D \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/farmer.cfg b/Data/Bulk Orders/Tailoring/farmer.cfg new file mode 100644 index 0000000..f4ab11d --- /dev/null +++ b/Data/Bulk Orders/Tailoring/farmer.cfg @@ -0,0 +1,6 @@ +# Farmer large bulk order + +StrawHat 0x1717 +Tunic 0x1FA1 +LongPants 0x1539 +Boots 0x170B \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/femaleleatherset.cfg b/Data/Bulk Orders/Tailoring/femaleleatherset.cfg new file mode 100644 index 0000000..61c1630 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/femaleleatherset.cfg @@ -0,0 +1,8 @@ +# Female leather collection large bulk order + +LeatherSkirt 0x1C08 +LeatherBustierArms 0x1C0A +LeatherShorts 0x1C00 +FemaleLeatherChest 0x1C06 +FemaleStuddedChest 0x1C02 +StuddedBustierArms 0x1C0C \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/fishergirl.cfg b/Data/Bulk Orders/Tailoring/fishergirl.cfg new file mode 100644 index 0000000..ef9a48e --- /dev/null +++ b/Data/Bulk Orders/Tailoring/fishergirl.cfg @@ -0,0 +1,6 @@ +# Fishergirl large bulk order + +FloppyHat 0x1713 +FullApron 0x153D +PlainDress 0x1F01 +Sandals 0x170D \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/gypsy.cfg b/Data/Bulk Orders/Tailoring/gypsy.cfg new file mode 100644 index 0000000..22ad4f3 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/gypsy.cfg @@ -0,0 +1,6 @@ +# Gypsy large bulk order + +Bandana 0x1540 +Shirt 0x1517 +Skirt 0x1516 +ThighBoots 0x1711 \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/hatset.cfg b/Data/Bulk Orders/Tailoring/hatset.cfg new file mode 100644 index 0000000..2dd49d9 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/hatset.cfg @@ -0,0 +1,6 @@ +# Hat collection large bulk order + +TricorneHat 0x171B +Cap 0x1715 +WideBrimHat 0x1714 +TallStrawHat 0x1716 \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/jester.cfg b/Data/Bulk Orders/Tailoring/jester.cfg new file mode 100644 index 0000000..d80fe5a --- /dev/null +++ b/Data/Bulk Orders/Tailoring/jester.cfg @@ -0,0 +1,6 @@ +# Jester large bulk order + +JesterHat 0x171C +JesterSuit 0x1F9F +Cloak 0x1515 +Shoes 0x170F \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/lady.cfg b/Data/Bulk Orders/Tailoring/lady.cfg new file mode 100644 index 0000000..98378d3 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/lady.cfg @@ -0,0 +1,6 @@ +# Lady large bulk order + +Bonnet 0x1719 +HalfApron 0x153B +FancyDress 0x1EFF +Sandals 0x170D \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/leather.cfg b/Data/Bulk Orders/Tailoring/leather.cfg new file mode 100644 index 0000000..be1083e --- /dev/null +++ b/Data/Bulk Orders/Tailoring/leather.cfg @@ -0,0 +1,40 @@ +# Leather Armor + +LeatherGorget 0x13C7 +LeatherCap 0x1DB9 +LeatherGloves 0x13C6 +LeatherArms 0x13CD +LeatherLegs 0x13CB +LeatherChest 0x13CC + +# Studded Armor + +StuddedGorget 0x13D6 +StuddedGloves 0x13D5 +StuddedArms 0x13DC +StuddedLegs 0x13DA +StuddedChest 0x13DB + +# Female Armor + +LeatherShorts 0x1C00 +LeatherSkirt 0x1C08 +LeatherBustierArms 0x1C0A +StuddedBustierArms 0x1C0C +FemaleLeatherChest 0x1C06 +FemaleStuddedChest 0x1C02 + +# Bone Armor + +BoneHelm 0x1451 +BoneGloves 0x1450 +BoneArms 0x144E +BoneLegs 0x1452 +BoneChest 0x144F + +# Shoes + +Boots 0x170B +ThighBoots 0x1711 +Shoes 0x170F +Sandals 0x170D \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/maleleatherset.cfg b/Data/Bulk Orders/Tailoring/maleleatherset.cfg new file mode 100644 index 0000000..d3c5f30 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/maleleatherset.cfg @@ -0,0 +1,8 @@ +# Male leather collection large bulk order + +LeatherGorget 0x13C7 +LeatherCap 0x1DB9 +LeatherGloves 0x13C6 +LeatherArms 0x13CD +LeatherLegs 0x13CB +LeatherChest 0x13CC \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/pirate.cfg b/Data/Bulk Orders/Tailoring/pirate.cfg new file mode 100644 index 0000000..560f839 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/pirate.cfg @@ -0,0 +1,6 @@ +# Pirate large bulk order + +SkullCap 0x1544 +Doublet 0x1F7B +Kilt 0x1537 +Shoes 0x170F \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/shoeset.cfg b/Data/Bulk Orders/Tailoring/shoeset.cfg new file mode 100644 index 0000000..546cbc4 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/shoeset.cfg @@ -0,0 +1,6 @@ +# Shoe collection (set) + +Sandals 0x170D +Shoes 0x170F +Boots 0x170B +ThighBoots 0x1711 \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/studdedset.cfg b/Data/Bulk Orders/Tailoring/studdedset.cfg new file mode 100644 index 0000000..e9dfb7e --- /dev/null +++ b/Data/Bulk Orders/Tailoring/studdedset.cfg @@ -0,0 +1,7 @@ +# Studded collection large bulk order + +StuddedGorget 0x13D6 +StuddedGloves 0x13D5 +StuddedArms 0x13DC +StuddedLegs 0x13DA +StuddedChest 0x13DB \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/towncrier.cfg b/Data/Bulk Orders/Tailoring/towncrier.cfg new file mode 100644 index 0000000..b953c0a --- /dev/null +++ b/Data/Bulk Orders/Tailoring/towncrier.cfg @@ -0,0 +1,7 @@ +# Town Crier large bulk order + +FeatheredHat 0x171A +Surcoat 0x1FFD +FancyShirt 0x1EFD +ShortPants 0x152E +ThighBoots 0x1711 \ No newline at end of file diff --git a/Data/Bulk Orders/Tailoring/wizard.cfg b/Data/Bulk Orders/Tailoring/wizard.cfg new file mode 100644 index 0000000..8f00437 --- /dev/null +++ b/Data/Bulk Orders/Tailoring/wizard.cfg @@ -0,0 +1,6 @@ +# Wizard large bulk order + +WizardsHat 0x1718 +BodySash 0x1541 +Robe 0x1F03 +Boots 0x170B \ No newline at end of file diff --git a/Data/Common.map b/Data/Common.map new file mode 100644 index 0000000..478c211 --- /dev/null +++ b/Data/Common.map @@ -0,0 +1,864 @@ +3 +-stairs: 5170 1569 1 +-healer: 575 537 3 +-healer: 682 297 3 +-baker: 1514 611 3 ++ruins: 1586 1004 3 abandoned building ++landmark: 478 1531 3 abandoned mage tower ++ruins: 412 1363 3 abandoned tower ++landmark: 575 1140 3 abandoned tower +-bank: 652 820 0 Abbey Banker +-inn: 610 810 0 Abbey Innkeeper ++scenic: 1738 174 3 the Abyss +-painter: 4525 1060 0 Academy of Arts +-provisioner: 5737 3262 0 Adventure Outfitters +-tailor: 1981 2838 0 Adventurer's Clothing +-provisioner: 535 867 0 The Adventurer's Friend +-tailor: 1355 3779 0 Adventurer's Needle +-provisioner: 2992 638 0 The Adventurer's Supplies +-inn: 3672 2654 1 The Albatross +-tavern: 3668 2652 2 The Albatross Bar and Grill +-mage: 5301 88 0 The Alchemist of Wind ++Terrain: 1460 448 3 Alexandrella's Bowl +-shipwright: 3632 2640 1 Anchors Aweigh ++ruins: 1516 542 3 Ancient Citadel ++landmark: 221 1363 3 ancient wyrm's lair ++scenic: 1414 317 3 ancient wyrm's lair +-arms: 808 697 3 Anglo-In-Lem +-arms: 808 586 3 Angra-Char-In-Lem +-gypsystable: 1225 563 3 animal pen +-gypsystable: 1388 428 3 animal pen ++shrine: 3359 2679 2 Ank of Sacrifice +-point of interest: 3746 2576 2 Archer Targets +-arms: 1497 614 3 an armourer +-armourers guild: 3587 2601 2 Armoury +-arms: 1637 1693 0 Artistic Armour +-rogues guild: 1442 1662 0 Artists' Guild +-bank: 854 680 3 Atri-Aur +-bank: 855 603 3 Atri-Aur +-tinker: 766 641 3 Atri-Ben-In-Ailem +-baker: 1880 2802 0 Baked Delights +-baker: 3755 2227 0 Baker's Dozen +-baker: 1364 3732 0 Baker's Dozen ++ruins: 512 546 3 bandit town ++landmark: 437 1558 3 bandstand ++scenic: 748 489 3 bandstand +-gypsybank: 1226 554 3 a bank +-bank: 1610 556 3 a bank +-bank: 1813 2825 0 Bank of Britannia: Trinsic Branch +-bank: 3734 2149 0 Bank of Magincia +-bank: 2503 552 0 Bank of Minoc +-bank: 3764 1317 0 Bank of Nujel'm +-bank: 3695 2511 1 Bank of Ocllo +-bank: 587 2146 0 Bank of Skara Brae +-bardic guild: 3740 1197 0 Bardic Guild +-bardic guild: 3666 2531 2 Bardic Guild +-bardic guild: 3665 2531 1 The Bardic Guild +-inn: 5197 4060 0 The Barely Inn +-tavern: 2475 397 0 The Barnacle +-point of interest: 1962 2691 0 Barracks +-point of interest: 1937 2711 0 Barracks +-point of interest: 1938 2688 0 Barracks ++Island: 2122 2755 0 Barrier Isle +-stable: 571 2119 0 Beasts of Burden ++Terrain: 5542 2999 0 Beggars Gorge +-provisioner: 826 679 3 Ben-In-Lem +-provisioner: 824 602 3 Ben-In-Lem +-tanner: 1431 1612 0 The Best Hides of Britain ++ruins: 1249 955 3 Bet-Lem Reg +-tanner: 3602 2615 1 Better Leather Tannery +-blacksmith: 3007 3408 0 Blacksmith +-blacksmith: 3594 2595 2 Blacksmith +-bowyer: 590 2205 0 Bloody Bowman +-carpenter: 565 1011 0 Bloody Thumb Woodworks +-tavern: 1498 1691 0 The Blue Boar +-inn: 3671 2615 2 The Bountiful Harvest +-inn: 3673 2614 1 The Bountiful Harvest +-butcher: 582 2186 0 Bountiful Meats +-bowyer: 3745 2585 2 Bowyers +-baker: 3683 2171 0 The Bread Basket +-bridge: 1789 2923 0 bridge +-bridge: 1778 2848 0 bridge ++landmark: 1123 1236 3 brigand tower ++town: 1546 1634 0 Britain ++graveyard: 1371 1482 0 Britain Cemetery +-docks: 1470 1765 0 Britain Docks ++moongate: 1336 1997 0 Britain Moongate +-library: 1409 1590 0 Britain Public Library +-blacksmiths guild: 1348 1778 0 Britain's Blacksmith Guild +-provisioner: 1469 1668 0 Britain's Premier Provisioners and Fish Shoppe +-reagents: 3013 3353 0 Britainian Herbs +-point of interest: 1507 1567 0 Britannia Animal Care ++landmark: 295 764 0 Britannia Prison +-provisioner: 1850 2796 0 Britannia Provisions +-docks: 1437 1761 0 Britain Docks +-docks: 1484 1755 0 Britain Docks ++landmark: 4511 1376 0 Britannia Royal Zoo +-inn: 2967 3408 0 The Broken Arrow Inn +-warriors guild: 1939 2739 0 The Brotherhood of Trinsic +-weapons guild: 1362 3700 0 Brothers In Arms +-mage: 2885 651 0 The Bubbling Brew +-point of interest: 2667 2087 0 Buccaneer's Bath ++town: 2720 2110 0 Buccaneer's Den +-docks: 2752 2155 0 Buccaneer's Den Docks +-tanner: 2707 2178 0 Buccaneer's Den Leatherworks ++moongate: 2711 2234 1 Buccaneer's Den Moongate +-stable: 1510 1543 0 The Bucking Horse Stables +-vet: 1509 1571 0 Britannia Animal Care +-carpenter: 628 2160 0 Builder's Delight +-inn: 5310 34 0 bunkhouse +-other: 1288 769 3 Burning Corpse +-beekeeper: 2959 707 0 The Busy Bees +-gypsymaiden: 1400 434 3 provisioner.. +-butcher: 2991 779 0 The Butcher's Knife +-provisioner: 2838 868 0 The Adventurer's Friend +-arms: 1475 3865 0 Call to Arms ++scenic: 768 1284 3 campfire +-carpenter: 3642 2504 2 Carpenters of Haven +-carpenter: 5691 3209 0 The Carpentry House +-tavern: 1427 1716 0 The Cat's Lair +-cavalry guild: 1578 1558 0 Cavalry Guild ++dungeon: 314 1329 3 cave passage ++dungeon: 226 1336 3 cave passage ++graveyard: 2437 1104 0 cemetery ++graveyard: 5696 3660 0 cemetery passage +-exit: 533 1532 3 central dungeon ++dungeon: 576 1156 3 central dungeon ++dungeon: 664 929 3 central dungeon +-exit: 155 1474 3 central dungeon +-exit: 4 1267 3 central dungeon +-point of interest: 1538 1597 0 The Chamber of Virtue ++champion: 462 926 3 Champ "Humility" ++champion: 1645 1108 3 Champ "Lord Oaks and the Forest Queen" ++champion: 383 329 3 Champ "Valor" ++champion: 5511 2360 1 Champ 1 "Ice West" ++champion: 5559 3757 1 Champ 10 "Wild" (Lord Oaks) ++champion: 5982 3882 1 Champ 11 "Khaldun" ++champion: 5724 3991 1 Champ 12 "Tortoise" ++champion: 6038 2400 1 Champ 2 "Ice East" ++champion: 5549 2640 1 Champ 3 "Oasis" ++champion: 5636 2916 1 Champ 4 "Desert" ++champion: 6035 2944 1 Champ 5 "Terra Sanctum" ++champion: 5267 3171 1 Champ 6 "Marble" ++champion: 5281 3368 1 Champ 7 "Damwin" ++champion: 5954 3475 1 Champ 8 "Hopper's Boog" ++champion: 5207 3637 1 Champ 9 "City of Death" ++champion: 5178 708 1 Champ Deceit: Neira (Unholy Terror) ++champion: 5259 837 1 Champ Destard: Rikktor (Cold Blood) ++champion: 5557 826 1 Champ of Despice: Barracoon (Vermin Horde) ++champion: 5814 1351 1 Champ of Fire: Semidar (Abyss) ++champion: 5189 1605 1 Champ of the Tera-Keep: Mephistis (Arachnid) +-warriors guild: 2841 907 0 The Champion's of Light ++moongate: 1721 218 3 Chaos ++shrine: 1749 234 3 Chaos ++shrine: 1458 844 0 Chaos +-point of interest: 3727 1361 0 The Chessboard ++Body of Water: 5260 3737 0 Cibilo Creek +-gate: 1370 3868 0 City Gate +-gate: 1475 3690 0 City Gate +-gate: 3657 1202 0 City Gates ++ruins: 5219 3645 0 City of the Dead +-butcher: 1449 1723 0 The Cleaver +-painter: 2906 710 0 The Colored Canvass ++marble patio: 3599 2491 2 Companion Hall ++moongate: 1215 467 3 Compassion ++shrine: 1210 477 3 Compassion ++shrine: 1858 874 0 Compassion ++landmark: 1091 703 3 Controller Tower +-guild: 2948 3349 0 Counselor's Guild +-guild: 3721 2177 0 Counselor's Guild +-guild: 610 2128 0 Counselor's Guild +-guild: 2434 438 0 Counselor's Guild +-guild: 1498 1518 0 Counselor's Guild +-guild: 3769 1190 0 Counselor's Guild +-guild: 616 980 0 Counselor's Guild +-guild: 4478 1126 0 Counselor's Guild +-guild: 1418 3703 0 Counselor's Guild +-guild: 2843 944 0 Counselor's Guild +-guild: 1893 2838 0 Counselor's Guild +-guild: 1628 1664 0 Counselor's Guild +-guild: 3667 2502 1 Counselor's Guild Hall ++landmark: 370 899 0 Court of Truth ++town: 2263 1237 0 Cove +-docks: 2256 1181 0 Cove Dock ++dungeon: 2499 916 0 Covetous +-exit: 5456 1863 0 Covetous +-customs: 1476 1745 0 Customs +-blacksmith: 2637 2090 0 Cutlass Smithing ++Terrain: 5139 2903 0 Cyclops Valley ++landmark: 758 208 3 cyclopse camp +-exit: 1014 1507 3 cyclopse dungeon ++dungeon: 904 1362 3 cyclopse dungeon ++scenic: 747 247 3 cyclopse garden ++landmark: 907 1283 3 cyclopse's pyramid +-bridge: 1521 1673 0 Cypress Bridge ++landmark: 894 1000 3 dam ++Terrain: 5265 3270 0 Damwin Thicket ++Terrain: 429 1433 3 dead forest +-arms: 1359 3763 0 Deadly Intentions +-point of interest: 3715 1383 0 Debtor's Prison ++dungeon: 4111 429 0 Deceit +-exit: 5188 638 0 Deceit +-healer: 647 1087 0 Deep Forest Healing ++town: 5227 3978 0 Delucia +-stable: 5297 4007 0 Delucia Stable +-tailor: 5234 4025 0 Delucia Tailor ++Terrain: 966 637 3 Desert ++town: 1506 622 3 Desert Outpost ++town: 1608 550 3 Desert Outpost ++dungeon: 1296 1082 0 Despise +-exit: 5588 632 0 Despise ++dungeon: 1176 2635 0 Destard +-exit: 5244 1007 0 Destard +-inn: 665 665 3 The Deuce's Vinculum Inn +-tavern: 2972 3425 0 The Dog and Lion Pub +-point of interest: 39 688 3 Dragon's Egg ++dungeon: 940 502 3 Dragon's Lair +-point of interest: 1397 3744 0 The Dueling Pit +-bank: 1655 1606 0 East Britain Bank ++scenic: 2587 492 0 The East Mines +-point of interest: 1608 1622 0 East Side Park +-bridge: 2083 2796 0 East Trinsic Bridge ++dungeon: 349 1428 3 Elemental Arena +-exit: 20 1197 3 Elemental Arena ++Terrain: 312 1442 3 Elemental Canyon ++landmark: 635 851 0 Empath Abbey +-mages guild: 4545 860 0 Encyclopedia Magicka +-mage: 1843 2711 0 Encyclopedia Magicka +-gate: 1200 704 3 Entrance ++landmark: 5165 246 0 entrance ++dungeon: 1236 583 3 Entrance to Central Area ++dungeon: 710 667 3 Entrance to Central Area +-reagents: 1498 1659 0 Ethereal Goods ++dungeon: 1363 1032 3 Etherial Tombs +-exit: 1982 1106 3 Etherial Tombs +-healer: 1364 1051 3 etherial warrior castle healer ++dungeon: 1140 593 3 Exit to Ilshenar ++dungeon: 911 451 3 Exit to Ilshenar +-inn: 606 2243 0 The Falconer's Inn +-jeweler: 3661 2183 0 The Family Jewels +-other: 3708 2588 2 Farm +-other: 3739 2563 2 Farm +-other: 3731 2635 2 Farm +-market: 4481 1085 0 Farmer's Market +-market: 1392 3824 0 Farmer's Market +-market: 611 2157 0 Farmer's Market +-market: 3019 766 0 Farmer's Market +-provisioner: 2216 1192 0 The Farmer's Market +-butcher: 4395 1137 0 The Fatted Calf +-butcher: 1455 4026 0 Finest Cuts ++dungeon: 2922 3402 0 Fire ++dungeon: 5757 2909 0 Fire +-exit: 5687 1424 0 Fire (B) +-exit: 5792 1415 0 Fire (LL) +-theater: 3685 2477 1 First Academy of Music +-bank: 1425 1690 0 The First Bank of Britain +-bank: 4471 1156 0 First Bank of Moonglow and Tinker's Guild +-blacksmith: 1395 3705 0 First Defense +-library: 1494 1715 0 The First Library of Britain +-stable: 2010 2807 0 First Trinsic Stablery +-tavern: 3012 3457 0 Fisherman's Brew +-fishermans guild: 2963 813 0 The Fisherman's Guild +-fishermans guild: 3685 2256 0 Fisherman's Guild and Supplies +-market: 3013 781 0 Fisherman's Warf ++scenic: 1589 1190 3 flowstone ++scenic: 596 946 3 a flowstone surrounded by runes +-blacksmith: 1261 582 3 a forge ++scenic: 1606 1265 3 forge +-blacksmith: 2471 564 0 The Forgery +-point of interest: 792 641 3 Fountain ++landmark: 447 1526 3 fountain +-other: 5331 707 1 from Ancient Wyrm's Lair - Teleporter +-other: 5201 1564 1 from Despice- and Ancient-Wyrm-Teleporter +-other: 5164 1009 1 from Despice-Teleporter +-other: 5606 802 1 from Fire-and Deceit-Teleporter +-other: 5171 1586 1 from Starroom-Teleporter +-other: 5814 3548 1 from Teleporter T1 "Ice West" +-other: 5958 2345 1 from Teleporter T2 "Ice East" +-other: 5522 3921 1 from Teleporter T3 "Ice East" +-other: 6089 2400 1 from Teleporter T4 Northeast of "Ice East" +-other: 5490 2348 1 from Teleporter T5 South of Papua +-other: 5972 2418 1 from Teleporter T6 East of Delucia +-other: 5143 1774 1 from Tera- Keep-Teleporter +-other: 5876 1378 1 from Tera-Keep-Teleporter +-carpenter: 1435 3820 0 From Tree to Yew +-shipwright: 3667 2252 0 The Furled Sail +-tinker: 2899 790 0 The Gadget's Corner +-tinker: 1404 3805 0 Gadgets and Things +-point of interest: 3633 2597 2 Garden with Waterfall ++landmark: 946 427 3 Gargoyle Mining Camp ++teleporter: 2618 980 0 gate to Buccaneer's Den ++teleporter: 2728 2133 0 gate to mainland +-point of interest: 1635 1561 0 Gazebo +-tinker: 2461 457 0 Gears and Gadgets ++Body of Water: 5804 3468 0 The Gentle River ++Body of Water: 5838 3766 0 The Gentle River ++scenic: 1197 1034 3 giant yew tree +-jeweler: 1655 1642 0 A Girl's Best Friend ++Terrain: 1352 664 3 glacier +-miners guild: 2505 432 0 The Golden Pick Axe +-baker: 1450 1617 0 Good Eats +-arms: 654 2163 0 Gore Galore ++graveyard: 327 889 3 graveyard ++graveyard: 3649 2859 2 Graveyard ++graveyard: 3404 2653 2 graveyard +-tavern: 3730 2218 0 Great Horns Tavern +-bowyer: 624 1147 0 Great Oak Bowyer +-shipwright: 634 1038 0 Great Oak Vessels +-bridge: 1383 1746 0 Gung Farmer's Bridge ++scenic: 2533 654 0 Gypsy Camp ++town: 1240 565 3 gypsy caravan ++town: 1380 425 3 gypsy caravan +-blacksmith: 1418 1547 0 The Hammer and Anvil +-carpenter: 2917 798 0 The Hammer and Nail +-arms: 3632 2595 1 Hammer and Steel Smithy +-armourers guild: 1437 3884 0 Hand of Death ++scenic: 1675 965 3 harpy nest ++town: 3664 2558 2 Haven +-blacksmith: 3645 2617 2 The Haven Blacksmith +-tinker: 3667 2506 2 Haven Clockworks and Tinker Shop +-docks: 3655 2665 2 Haven Docks ++moongate: 3763 2771 2 Haven Moongate +-library: 3615 2476 2 Haven Public Library +-thieves guild: 3693 2509 2 The Haven Thieves' Guild ++scenic: 1201 762 3 Hay Fields ++scenic: 1269 727 3 Hay Fields +-healer: 5191 3989 0 a Healer +-healer: 1472 1607 0 Healer of Britain +-healer: 2709 2130 0 Healer of Buccaneer's Den +-healer: 3687 2227 0 Healer of Magincia +-healer: 3629 2608 1 Healer of Ocllo +-healer: 623 2218 0 Healer of Skara Brae +-healer: 2920 856 0 Healer of Vesper +-healer: 532 958 0 Healer of Yew +-healer: 284 536 3 healer's hut +-fortuneteller: 1235 543 3 healer's hut +-fortuneteller: 1407 428 3 healer's hut +-healer: 1628 548 3 healer's hut +-healer: 1518 619 3 healer's hut +-healer: 3665 2581 2 The Healers of Haven +-healer: 2577 599 0 The Healing Hand +-healer: 2245 1231 0 The Healing Hand +-healer: 5737 3222 0 The Healing Hand +-healer: 1093 955 3 a healing temple +-arms: 1443 1650 0 Heavy Metal Armorer ++scenic: 1146 2215 0 Hedge Maze +-reagents: 4416 1133 0 Herbal Splendor ++moongate: 722 1366 3 Honesty ++shrine: 719 1351 3 Honesty ++shrine: 4212 563 0 Honesty ++moongate: 744 724 3 Honor ++shrine: 748 731 3 Honor ++shrine: 1723 3527 0 Honor +-blacksmith: 1937 2771 0 Honorable Arms ++Terrain: 5978 3447 0 Hoppers Bog +-tavern: 1452 3770 0 The Horse's Head ++moongate: 281 1016 3 Humility ++shrine: 287 1013 3 Humility ++shrine: 4274 3697 0 Humility ++landmark: 3715 2838 2 Hunters Cabin +-mage: 5296 3978 0 Hut of Magics ++dungeon: 4722 3814 0 Hythloth +-exit: 5904 16 0 Hythloth ++dungeon: 5203 2328 0 Ice ++dungeon: 1996 80 0 Ice +-exit: 5882 243 0 Ice (B) +-exit: 5875 147 0 Ice (LL) +-exit: 84 750 3 Ilshenar Central Area +-healer: 872 586 3 In-Mani-Lem +-mage: 1590 1654 0 Incantations & Enchantments +-inn: 1620 554 3 an inn +-inn: 2778 966 0 The Ironwood Inn +-arms: 2865 852 0 The Ironworks ++teleporter: 2494 3576 0 island temple portal ++Body of Water: 5274 2883 0 J'Fer Sok +-point of interest: 1855 2769 0 Jail ++landmark: 5291 1169 0 jail +-jeweler: 3778 1172 0 Jewel of the Isle +-jeweler: 1605 541 3 a jeweler ++town: 1359 3671 0 Jhelom +-arms: 1456 3850 0 Jhelom Armory +-bank: 1317 3773 0 Jhelom Bank and Jeweler ++graveyard: 1283 3731 0 Jhelom Cemetery +-docks: 1512 3989 0 Jhelom Docks +-docks: 1372 3908 0 Jhelom Docks +-docks: 1504 3693 0 Jhelom Docks +-docks: 1125 3687 0 Jhelom Docks +-healer: 1416 3779 0 Jhelom Healer +-library: 1387 3771 0 Jhelom Library +-mage: 1425 3980 0 Jhelom Mage ++moongate: 1500 3772 0 Jhelom Moongate +-tailor: 1455 4006 0 Jhelom's Fine Tailoring +-baker: 554 991 0 The Jolly Baker +-inn: 5775 3161 0 The Just Inn ++moongate: 987 1011 3 Justice ++shrine: 985 1005 3 Justice ++shrine: 1300 633 0 Justice +-tavern: 1935 2796 0 The Keg and Anchor ++dungeon: 6009 3775 1 Khaldun ++dungeon: 5882 3819 1 Khaldun +-theater: 1449 1590 0 The King's Men Theater +-jeweler: 859 698 3 Klar-Lap-In-Lem ++Terrain: 5382 2343 0 Kos Heb ++Terrain: 5954 2363 0 Kos Heb ++ruins: 1200 1127 3 Lakeshire/Mireg +-guild: 872 686 3 Lap-In-Lem +-guild: 792 617 3 Lap-In-Lem +-provisioner: 3673 2595 2 Last Chance Provisioners +-provisioner: 3635 2573 1 Last Chance Provisioners ++Terrain: 480 882 3 lava vent +-library: 5238 144 0 The Learned Mage ++Body of Water: 1688 840 3 Lenmir Antinmolas +-library: 868 657 3 Librum +-library: 869 625 3 Librum ++landmark: 3457 3056 2 Lighthouse ++landmark: 5671 2391 0 lighthouse passage +-mage: 3632 2573 2 The Little Shop of Magic ++ruins: 292 1356 3 lizard man camp +-gate: 401 1251 3 lizzardman gate +-gate: 367 1261 3 lizzardman gate ++landmark: 3595 2865 2 Loggers Camp ++landmark: 1530 1428 0 Lord Blackthorn's Castle ++landmark: 1323 1624 0 Lord British's Castle +-bard: 1455 1557 0 Lord British's Conservatory of Music +-tailor: 1385 1593 0 Lord British's Tailor +-arms: 1365 1575 0 The Lord's Arms +-tailor: 1467 1686 0 The Lord's Clothiers ++landmark: 4312 1000 0 The Lyceaeum +-gypsybank: 1405 439 3 a bank +-fortuneteller: 1394 441 3 a mage +-mage: 1505 611 3 a mage +-baker: 5351 56 0 Mage's Appetite +-baker: 4392 1068 0 Mage's Bread +-bridge: 1520 1578 0 Mage's Bridge +-carpenter: 4416 1085 0 The Mage's Seat +-provisioner: 5154 97 0 Mage's Things +-mage: 602 2180 0 Mages' Menagerie +-mage: 2918 672 0 The Magical Light +-reagents: 5215 117 0 Magical Supplies +-reagents: 2992 844 0 The Magician's Friend ++town: 3735 2200 0 Magincia +-docks: 3674 2293 0 Magincia Docks +-miners guild: 3665 2140 0 Magincia Miner's Guild ++moongate: 3564 2140 0 Magincia Moongate +-point of interest: 3796 2259 0 Magincia Parliment +-mage: 3704 2222 0 Magincia's Magicka +-gate: 1477 1638 0 The Main Gate +-shipwright: 2994 815 0 The Majestic Boat +-shipwright: 3636 2642 2 Mapmaker's of Haven +-tavern: 2901 908 0 The Marsh Hall +-illusionists guild: 4626 1207 0 Masters of Illusion +-miners guild: 2455 487 0 The Matewan ++scenic: 753 493 3 memorial to Gwenno +-merchants guild: 1474 1597 0 The Merchant's Guild +-merchants guild: 3703 2249 0 The Merchant's Guild +-other: 1947 2677 0 Mess Hall +-arms: 4392 1117 0 The Mighty Axe ++Minax's Fortress: 5778 3376 1 Minax's Fortress +-miners guild: 1417 1578 0 The Miner's Guild +-miners guild: 3754 2704 2 Miners ++landmark: 2590 532 0 Mining Camp ++landmark: 3498 2844 2 Mining Cave ++landmark: 3610 2740 2 Mining Cave ++town: 2502 522 0 Minoc ++moongate: 2702 692 0 Minoc Moongate +-point of interest: 2429 528 0 Minoc Town Hall +-bank: 2881 684 0 The Mint of Vesper ++landmark: 821 1060 3 Mistas +-inn: 774 1144 3 Mistas Regsit ++landmark: 3589 2808 2 Mongbat Tower ++landmark: 1668 292 3 Montor ++town: 4457 1117 0 Moonglow ++graveyard: 4541 1319 0 Moonglow Cemetery +-docks: 4406 1038 0 Moonglow Docks +-healer: 4388 1082 0 Moonglow Healer ++moongate: 4468 1284 0 Moonglow Moongate +-reagents: 4412 1111 0 Moonglow Reagent Shop +-inn: 4484 1064 0 Moonglow Student Hostel +-mage: 4448 1090 0 Moonglow's Finest Alchemy +-arms: 586 2170 0 More Than Just Mail +-inn: 1360 3815 0 The Morning Star Inn ++Terrain: 3690 2760 2 Mountain Pass ++dungeon: 1457 1329 3 mushroom caves +-exit: 1478 1495 3 mushroom caves +-other: 2891 744 0 The Musician's Hall +-mage: 659 2141 0 Mystic Treasures +-bard: 2424 555 0 The Mystical Lute +-tavern: 3769 1218 0 Mystical Spirits +-baker: 5746 3200 0 Nature's Best Baked Goods +-exit: 2188 319 3 ne dungeon ++dungeon: 1788 569 3 ne dungeon +-provisioner: 1441 3796 0 Needful Things +-warriors guild: 2482 428 0 The New World Order +-docks: 2940 3410 0 North Docks ++scenic: 2452 79 0 The North Mines +-inn: 1458 1525 0 The North Side Inn +-bridge: 1550 1529 0 The Northern Bridge +-baker: 3610 2572 1 Now You're Cookin' ++Terrain: 420 1196 3 Nox Tereg ++town: 3600 1231 0 Nujel'm +-blacksmith: 3546 1185 0 Nujel'm Blacksmith +-fletcher: 3546 1194 0 Nujel'm Bowry +-butcher: 3555 1171 0 Nujel'm Butcher ++graveyard: 3529 1141 0 Nujel'm Cemetery +-point of interest: 3723 1396 0 Nujel'm Court +-point of interest: 3690 1284 0 Nujel'm Palace +-tanner: 3545 1178 0 Nujel'm Tannery +-theater: 3739 1231 0 Nujel'm Theater ++dungeon: 548 454 3 nw dungeon +-exit: 427 112 3 nw dungeon ++dungeon: 556 427 3 nw dungeon +-carpenter: 2513 477 0 The Oak Throne +-shipwright: 1416 1754 0 The Oaken Oar ++Body of Water: 993 620 3 Oasis ++Terrain: 5543 2618 0 oasis +-fishermans guild: 1437 3750 0 Ocean's Treasure ++town: 3664 2558 1 Ocllo +-docks: 3633 2654 1 Ocllo Docks +-docks: 3654 2664 1 Ocllo Docks +-library: 3612 2466 1 Ocllo Public Library ++landmark: 3519 2787 2 Old Mine Entrance - Closed +-provisioner: 2456 428 0 The Old Miners' Supplies +-blacksmith: 630 2194 0 On Guard Armoury ++ruins: 5765 2618 0 Ophidian Lair ++landmark: 18 950 3 The Oracle ++dungeon: 1014 1434 0 Orc Cave ++ruins: 632 1484 0 Orc Fort ++ruins: 2176 1372 0 Orc Fort ++ruins: 5211 3611 0 Orc Fort ++scenic: 1183 1188 3 orchard +-miners guild: 2855 734 0 The Ore of Vesper +-painter: 3638 2499 1 Paint and More +-library: 2003 2726 0 Paladin's Library ++town: 5751 3231 0 Papua +-docks: 5827 3256 0 Papua dock +-tailor: 5754 3273 0 Papua Tailor +-point of interest: 1893 2763 0 park +-point of interest: 5251 58 0 park ++Terrain: 1028 272 3 Pass of Karnaugh ++landmark: 881 1303 3 passage ++landmark: 857 1312 3 passage ++dungeon: 6075 3330 0 passage to Britain ++dungeon: 1628 3318 0 passage to Delucia ++landmark: 2775 893 0 passage to Lost Cemetery ++landmark: 2404 218 0 passage to Lost Lands ++landmark: 6084 3674 0 passage to North Mines ++dungeon: 5150 4063 0 passage to Trinsic ++dungeon: 5138 3665 0 passage to Trinsic +-jeweler: 1447 3981 0 The Pearl of Jhelom +-jeweler: 1895 2809 0 The Pearl of Trinsic +-inn: 2715 2098 0 The Peg Leg Inn +-theater: 1424 4016 0 Performing Arts Centre +-shipwright: 5805 3270 0 Pier 39 +-thieves guild: 2659 2194 0 Pirate's Den +-tavern: 2680 2238 0 The Pirate's Plunder +-provisioner: 2735 2254 0 Pirate's Provisioners +-bank: 2731 2188 0 A Place Fer Yer Stuff +-baker: 2975 3358 0 Plenty O' Dough ++scenic: 1548 1192 3 pool +-gate: 1421 1633 0 Poor Gate ++Body of Water: 495 370 3 Pormir Felwis ++Body of Water: 706 469 3 Pormir Harm ++Body of Water: 1128 816 3 Pormir Priin "River of Unity" ++teleporter: 5905 4069 0 portal to island temple ++teleporter: 5733 3190 0 portal to Moonglow (recsu) ++teleporter: 4540 845 0 portal to Papua (recdu) ++landmark: 826 777 3 Power Core +-jeweler: 1451 1679 0 Premier Gems +-butcher: 3714 2651 2 The Prime Cut Butcher Shop +-provisioner: 1602 1712 0 Profuse Provisions +-provisioner: 1598 539 3 a provisioner +-blacksmith: 3554 1202 0 Public Smithing +-fletcher: 1470 1578 0 Quality Fletching +-fletcher: 2861 812 0 The Ranger's Tool +-warriors guild: 3740 2692 2 Rangers Cabin +-archers guild: 554 2145 0 Rangers' Guild ++landmark: 645 817 3 ratman lair +-exit: 1348 1510 3 ratman mine ++dungeon: 1030 1154 3 ratman mine ++ruins: 1069 1151 3 ratman village ++scenic: 1280 734 3 Reagent Garden +-reagents: 5714 3202 0 The Reagent Shop +-provisioner: 1852 2831 0 Red's Curious Goods ++landmark: 1362 1073 3 Reg Volom +-inn: 3732 1306 0 Restful Slumber +-healer: 369 1432 3 resurrection tree +-arms: 5805 3300 0 The Revenge Shoppe +-point of interest: 1280 779 3 Ridgeback Pen +-tailor: 1547 1659 0 The Right Fit +-bridge: 1512 1705 0 River's Gate Bridge ++Body of Water: 5360 3396 0 The Ru ++Body of Water: 5457 3831 0 The Ru ++ruins: 1084 651 3 Ruined Castle ++ruins: 653 933 3 ruined tower ++ruins: 875 524 3 Ruined Villa ++ruins: 337 864 3 ruins +-inn: 2033 2801 0 The Rusty Anchor ++moongate: 1174 1286 3 Sacrifice ++shrine: 1171 1288 3 Sacrifice ++shrine: 3355 289 0 Sacrifice +-shipwright: 1452 3747 0 Sailor's Keeper ++Terrain: 5724 2923 0 Sak Teb +-tavern: 1620 1586 0 The Salty Dog ++landmark: 1044 519 3 Savage Camp ++landmark: 1238 733 3 Savage Clan Settlement +-carpenter: 1430 1597 0 The Saw Horse +-tailor: 4458 1060 0 Scholar's Cut +-provisioner: 4417 1064 0 The Scholar's Goods +-inn: 4401 1165 0 The Scholar's Inn ++dungeon: 1747 1235 3 se dungeon +-exit: 2114 830 3 se dungeon ++Body of Water: 5937 2660 0 Sea of Harmony +-shipwright: 3700 1214 0 Seaborne Ships +-customs: 3717 1228 1 Seaborne Ships +-library: 5243 179 0 Seat of Knowledge +-bank: 3620 2617 2 The Second Bank of Haven +-arms: 4440 1162 0 Second Defense Armory +-arms: 1441 3719 0 Second Skin +-inn: 5165 30 0 Seeker's Inn +-point of interest: 1541 1685 0 Senator Robin's House and Office +-butcher: 2912 3485 0 Serpent Hold Meats ++landmark: 2986 2887 0 Serpent Pillar (doracron) ++landmark: 425 3279 0 Serpent Pillar (doracron) ++landmark: 5974 2694 0 Serpent Pillar (sueacron) ++landmark: 5266 2757 0 Serpent Pillar (sueacron) +-warriors guild: 3031 3350 0 Serpent Warriors +-arms: 3018 3433 0 Serpent's Arms ++town: 3025 3498 0 Serpent's Hold +-bank: 2880 3472 0 Serpent's Hold Bank +-healer: 2997 3428 0 Serpent's Hold Healer +-stable: 3036 3464 0 Serpent's Hold Stablery +-mage: 3002 3350 0 Serpent's Spells ++dungeon: 811 874 3 Serpentine Passage ++Terrain: 5470 3515 0 Serpents Cousins +-stable: 2905 3517 0 Serpents Hold Stablery ++dungeon: 1492 1641 0 sewer entrance +-baker: 3628 2540 2 The Shakin' Bakery ++Body of Water: 5902 3106 0 Shallow Sea +-exit: 5396 129 0 Shame ++dungeon: 512 1559 0 Shame +-inn: 554 2178 0 The Shattered Skull +-tailor: 650 2180 0 Shear Pleasure +-provisioner: 1318 1328 3 sheep farm +-jeweler: 2882 723 0 The Shimmering Jewel +-arms: 1895 2653 0 Shining Path Armory ++shrine: 1106 404 3 Shrine of the Virtues +-tavern: 3736 1255 0 The Silver Bow +-bowyer: 3054 3369 0 Silver Serpent Bows +-tailor: 2881 3503 0 Silver Serpent Tailors ++town: 595 2263 0 Skara Brae +-docks: 648 2235 0 Skara Brae Docks +-docks: 672 2235 0 Skara Brae Docks ++moongate: 645 2068 0 Skara Brae Moongate +-point of interest: 565 2213 0 Skara Brae Town Hall +-tailor: 896 610 3 Skis-In-Lem +-butcher: 2438 410 0 The Slaughtered Cow ++landmark: 1442 1122 3 small lumber camp ++Body of Water: 5789 2430 0 Sok' Gah +-shipwright: 2026 2845 0 Sons Of The Sea +-mage: 1485 1550 0 The Sorcerer's Delight +-sorcerers guild: 4684 1412 0 The Sorcerer's Guild +-mage: 3628 2541 1 The Sorceror's Guild +-stable: 1296 1759 0 Sosarian Steeds +-docks: 3006 3465 0 South Dock +-gate: 2003 2921 0 South Gate +-butcher: 5700 3279 0 The Southside Butchery +-stable: 5671 3287 0 Southside Stables ++dungeon: 1420 910 3 spider dungeon +-exit: 1787 993 3 spider dungeon ++dungeon: 1490 879 3 spider dungeon ++Terrain: 1447 964 3 spider wood +-tailor: 2961 621 0 The Spinning Wheel +-tailor: 2840 885 0 The Spinning Wheel ++moongate: 1532 1340 3 Spirituality ++shrine: 1526 1340 3 Spirituality ++shrine: 1595 2490 0 Spirituality +-stable: 1499 619 3 the stables +-stable: 2526 375 0 Stables +-stable: 1385 1658 0 The Stables +-inn: 3695 2160 0 The Stag and Lion ++moongate: 5153 1760 1 Standard-Moongate ++teleporter: 5173 1589 1 Starroom ++landmark: 466 1584 3 statue ++scenic: 1701 291 3 statue room +-point of interest: 2465 522 0 statues ++scenic: 728 475 3 stepping stones +-tailor: 3667 2586 1 A Stitch In Time +-tailor: 3687 2477 2 A Stitch in Time Tailor Shop +-tailor: 3666 2235 0 Stitchin' Time +-jeweler: 5662 3150 0 Strange Rocks +-arms: 1481 1584 0 Strength and Steel +-tanner: 2524 524 0 The Stretched Hide +-bowyer: 564 968 0 The Sturdy Bow +-provisioner: 578 2227 0 Sundry Supplies +-shipwright: 592 2277 0 Superior Ships +-provisioner: 3008 3389 0 Supplies +-provisioner: 5219 4012 0 The Supply Depot +-provisioner: 2530 551 0 The Survival Shop ++Terrain: 1124 739 3 Swamp +-inn: 1493 1619 0 Sweet Dreams +-butcher: 3708 2649 1 Sweet Meat ++teleporter: 5443 2325 1 T1 to the Southeast of Papua ++teleporter: 6053 2407 1 T2 to the Northwest of Champ 2 "Ice East" ++teleporter: 5996 2367 1 T3 to the East of Delucia ++teleporter: 6080 2340 1 T4 to the South of this Point ++teleporter: 5731 3420 1 T5 to "Ice West" ++teleporter: 5503 3971 1 T6 to "Ice East" +-tailor: 1600 552 3 a tailor +-tailor: 3774 1265 0 Tailor of the Isle +-tanner: 517 986 0 The Tanned Hide +-tanner: 2860 999 0 Tanner's Shop ++teleporter: 4442 1122 0 teleporter park ++teleporter: 1414 3829 0 teleporters ++scenic: 4708 1116 0 Telescope +-guild: 894 673 3 Ter-An-Eks-Por +-mage: 840 571 3 Ter-Ort-Lem +-inn: 840 707 3 Ter-Zu ++dungeon: 5426 3120 0 Terathan Keep +-exit: 5340 1599 0 Terathan Keep ++Body of Water: 1620 420 3 Termir Flam "The Lake of Fire" ++Body of Water: 1316 1120 3 Termir Ilshen "Ilshen's Lake" ++landmark: 580 420 3 Terort Skitas "Temple of Knowledge" ++Terrain: 6028 2933 0 Terra Sanctum +-tinker: 3720 2126 0 The Tic-Toc Shop +-tinker: 1253 588 3 a tinker +-tinker: 2940 3500 0 Tinker of the Isle +-tinkers guild: 1422 1654 0 Tinker's Guild +-tinkers guild: 1848 2680 0 Tinker's Guild +-tinker: 5726 3243 0 Tinker's Paradise ++teleporter: 5506 814 1 to Ancient Wyrm's Lair (Destard lvl 3) ++teleporter: 5682 1437 1 to Ancient Wyrm's Lair (Destard lvl 3) +-exit: 6031 1500 0 to Britain ++teleporter: 5682 1440 1 to Champ "Despice" ++teleporter: 5265 683 1 to Champ "Despice" ++teleporter: 5360 1540 1 to Champ "Fire" ++teleporter: 5265 669 1 to Champ "Fire" ++teleporter: 5145 973 1 to Champ "Terathan Keep" ++teleporter: 5506 817 1 to Champ "Terathan Keep" ++teleporter: 5140 1773 1 to Champ "Terathan Keep" +-exit: 6026 1344 0 to City of the Dead ++teleporter: 5356 1540 1 to Deceit (lvl 4) ++teleporter: 5140 973 1 to Deceit (lvl 4) +-exit: 6004 1379 0 to Delucia +-exit: 6141 1430 0 to Hoppers Bog ++landmark: 318 789 0 to lighthouse ++landmark: 1958 2068 0 to Lost Lands ++landmark: 5126 3144 0 to Marble Building ++teleporter: 5199 71 0 to park ++teleporter: 1516 879 3 to Reg Volom (the island) ++teleporter: 1363 1105 3 to spider dungeon +-exit: 5191 152 0 to surface ++teleporter: 5217 18 0 to town +-exit: 5899 1410 0 to Trinsic forest ++Body of Water: 5771 4050 0 Tortoise Lagoon ++landmark: 1675 1074 3 tower +-gate: 2281 1210 0 town gate +-point of interest: 3732 2583 2 Training Dummies +-point of interest: 1972 2698 0 Training Ground ++landmark: 1256 865 0 Training Tower +-inn: 1844 2735 0 The Traveler's Inn ++scenic: 1038 701 3 Tribal Berry Orchard +-mage: 5731 3183 0 Tricks of the Trade ++town: 1879 2766 0 Trinsic +-butcher: 1991 2887 0 The Trinsic Cut +-docks: 2072 2856 0 Trinsic Docks +-tanner: 1991 2867 0 Trinsic Fine Skins +-healer: 1911 2805 0 Trinsic Healer +-point of interest: 1895 2719 0 Trinsic Meeting Hall ++moongate: 1829 2949 0 Trinsic Moongate +-bank: 1897 2684 0 Trinsic Royal Bank +-stable: 1822 2739 0 Trinsic Stablery +-warriors guild: 2019 2748 0 Trinsic Training Hall +-inn: 1566 1049 3 Twin Oaks Tavern +-baker: 2998 760 0 The Twisted Oven ++ruins: 856 463 3 undead camp ++ruins: 360 1140 3 undead fort +-tavern: 1547 1768 0 The Unicorn's Horn ++landmark: 3610 2585 2 Uzeraan's Mansion +-point of interest: 3595 2588 2 Uzeraan, Keeper of Quests ++moongate: 528 216 3 Valor ++shrine: 529 212 3 Valor ++shrine: 2491 3933 0 Valor ++scenic: 1211 763 3 Vegetable Patch ++landmark: 836 641 3 Ver Lor Reg ++town: 2884 839 0 Vesper ++graveyard: 2753 867 0 Vesper Cemetery +-customs: 2944 934 0 Vesper Customs +-docks: 3017 827 0 Vesper Docks +-docks: 3034 827 0 Vesper Docks +-point of interest: 2743 980 0 Vesper Guard Tower +-point of interest: 2923 981 0 Vesper Museum +-inn: 2962 885 0 Vesper Youth Hostel +-carpenter: 2627 2100 0 Violente Woodworks +-bridge: 1520 1628 0 Virtue's Pass +-point of interest: 948 492 3 Volcano ++scenic: 1651 2890 0 Volcano Tunnel +-arms: 2533 576 0 Warrior's Battle Gear +-blacksmith: 1419 3859 0 Warrior's Bounty +-arms: 2835 805 0 Warrior's Companion +-arms: 2217 1170 0 The Warrior's Supplies +-warriors guild: 3058 3400 0 The Warriors' Guild +-warriors guild: 1341 1733 0 The Warriors' Guild +-gate: 5313 3970 0 Watch Gates +-point of interest: 1619 1760 0 The Watch Tower +-point of interest: 5265 3939 0 Watch Tower and Keep ++landmark: 917 993 3 watchpost +-point of interest: 2212 1115 0 watchtower ++scenic: 1712 3005 0 waterfall +-inn: 1585 1591 0 The Wayfarer's Inn +-weapons guild: 3731 2578 2 Weaponsmith +-gate: 1831 2779 0 West Trinsic Gate ++dungeon: 1361 890 0 Wind ++town: 5252 104 0 Wind +-mage: 5148 60 0 Wind Alchemy +-bank: 5346 74 0 Wind Bank +-healer: 5263 129 0 Wind Healer +-tailor: 5203 86 0 Windy Clothes +-inn: 5218 175 0 Windy Inn ++dungeon: 652 1301 3 wisp dungeon ++dungeon: 2042 226 0 Wrong +-exit: 5825 632 0 Wrong ++Terrain: 5604 2742 0 Y'Nah Teb +-bank: 5275 3977 0 Ye Olde Eleventh Bank +-bank: 5669 3131 0 Ye Olde Loan and Savings +-point of interest: 618 886 0 Ye Olde Winery ++town: 504 942 0 Yew ++graveyard: 722 1117 0 Yew Cemetery +-point of interest: 553 826 0 Yew Mill ++moongate: 771 754 0 Yew Moongate +-butcher: 529 1008 0 Yew's Finest Cuts +-blacksmith: 792 665 3 Zhel-In-Lem +-blacksmith: 5225 4000 0 Zoot's Hammer +-bank: 989 520 4 +-blacksmith: 976 512 4 +-tailor: 976 527 4 +-tanner: 978 528 4 +-chivalrykeeper: 1016 514 4 +-chivalrykeeper: 961 517 4 +-holymage: 1004 528 4 +-reagents: 1004 526 4 +-tinker: 1003 512 4 +-carpenter: 1004 514 4 +-jeweler: 995 510 4 +-provisioner: 991 510 4 +-inn: 989 527 4 +-stable: 1027 494 4 +-healer: 1029 520 4 +-healer: 950 520 4 +-blacksmith: 1977 1365 4 +-stable: 1992 1315 4 +-provisioner: 2011 1326 4 +-baker: 2017 1356 4 +-tavern: 2027 1353 4 +-mage: 2023 1379 4 +-reagents: 2025 1387 4 +-jeweler: 2045 1397 4 +-bank: 2048 1343 4 +-inn: 2037 1311 4 +-tinker: 2066 1282 4 +-carpenter: 2060 1283 4 +-tailor: 2083 1322 4 +-tanner: 2078 1327 4 +-healer: 2068 1372 4 +-inn: 1056 1434 4 +-tavern: 1051 1434 4 \ No newline at end of file diff --git a/Data/Components/doors.txt b/Data/Components/doors.txt new file mode 100644 index 0000000..f162757 --- /dev/null +++ b/Data/Components/doors.txt @@ -0,0 +1,39 @@ +int int int int int int int int int int string + +Category Piece1 Piece2 Piece3 Piece4 Piece5 Piece6 Piece7 Piece8 FeatureMask Comment + +0 1657 1659 1653 1655 1661 1663 1665 1667 0 Metal Door +1 8177 8179 8173 8175 8181 8183 8185 8187 0 Metal Gate +2 1689 1691 1685 1687 1693 1695 1697 1699 0 Rattan Door +3 1705 1707 1701 1703 1709 1711 1713 1715 0 Dark Wood Door +4 1721 1723 1717 1719 1725 1727 1729 1731 0 Wood Door +5 1753 1755 1749 1751 1757 1759 1761 1763 0 Light Wood Door +6 1769 1771 1765 1767 1773 1775 1777 1779 0 Wood and Metal Door +7 2088 2090 2084 2086 2092 2094 2096 2098 0 Tall Wrought Iron Gate +8 2109 2111 2105 2107 2113 2115 2117 2119 0 Light Wood Gate +9 2128 2130 2124 2126 2132 2134 2136 2138 0 Short Wrought Iron Gate +10 2154 2156 2150 2152 2158 2160 2162 2164 0 Dark Wood Gate +11 808 810 804 806 812 814 816 818 0 Weathered Stone Secret Door +12 824 826 820 822 828 830 832 834 0 Dark Wood Secret Door +13 840 842 836 838 844 846 848 850 0 Light Wood Secret Door +14 856 858 852 854 860 862 864 866 0 Grey Stone Secret Door +15 0 0 9251 0 0 9247 0 0 64 Japanese Doors +16 0 0 10767 10765 10771 10769 0 0 64 Sliding Doors 1 +17 0 0 10759 10757 10763 10761 0 0 64 Sliding Doors 2 +18 0 0 10775 10773 10779 10777 0 0 64 Sliding Doors 3 +19 0 0 12718 12716 11592 11590 0 0 128 Elvan Wood Door +20 0 0 11621 12704 11619 12706 0 0 128 Elvan White Wooden Door 1 +21 0 0 11625 12708 11623 12710 0 0 128 Elvan Ornate Door +22 0 0 11629 12714 11627 12712 0 0 128 Elvan Kia Wood Door 2 +23 0 0 12260 12700 12258 12702 0 0 128 Elvan Moon Door +24 13951 13953 13947 13949 13955 13957 13959 13961 512 Crystal Door +25 13967 13969 13963 13965 13971 13973 13975 13977 512 Shadow Door +26 0 0 16539 16541 16543 16545 0 0 65536 Gargish Carved Green Door +27 0 0 16652 16654 16656 16658 0 0 65536 Gargish Brown Door +28 0 0 16834 16836 16838 16840 0 0 65536 Sun Door +29 0 0 16847 16849 16851 16853 0 0 65536 Gargish Grey Door +30 17262 17264 17266 17268 17270 17272 17274 17276 65536 Gargish Set Door +31 0 0 18141 18143 18145 18147 0 0 65536 Ruined Door +32 0 0 19746 19748 19750 19752 0 0 65536 Gargish Blue Door +33 20680 20682 20688 20690 20684 20686 20692 20694 65536 Gargish Red Doors +34 0 0 20802 20804 20806 20808 0 0 65536 Gargish Prison Door diff --git a/Data/Components/floors.txt b/Data/Components/floors.txt new file mode 100644 index 0000000..51a45fb --- /dev/null +++ b/Data/Components/floors.txt @@ -0,0 +1,57 @@ +int int int int int int int int int int int int int int int int int int string +Category F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 FeatureMask Comment +0 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1181 1182 1183 1184 0 Grey Pavers and Flagstones +1 1317 1318 1319 1320 1321 1322 1323 1324 1327 1328 1329 1330 1331 1332 1333 1334 0 Sandstone Bricks +2 1280 1281 1282 1283 1407 1408 1409 1410 1276 1277 1278 1279 0 1411 1412 1413 0 More Sandstone +3 1250 1250 1250 1250 1250 1250 1250 1335 1336 1337 1338 0 0 0 0 0 0 Red Brick +4 1264 1265 1262 1263 1259 1260 1261 1258 1266 0 0 0 0 0 0 0 0 Blue Tile +5 1275 1272 1273 1274 1270 1271 1268 1269 1267 0 0 0 0 0 0 0 0 Red Tile +6 1293 1294 1297 1298 1299 1300 1179 1180 1295 1296 0 0 1173 1174 1175 1176 0 Misc Tile +7 1395 1396 1403 1404 1595 1596 1373 1374 1397 1398 1401 1402 1597 1598 1375 1376 0 Roof Tiles 2 +8 1204 1200 1203 1199 1201 1198 1202 1197 1189 1190 0 0 0 1193 1195 1196 0 Dark Wood 1 +9 1216 1212 1215 1211 1213 1210 1214 1209 1191 1192 0 0 1205 1206 1207 1208 0 Dark Wood 2 +10 1233 1228 1235 1230 1234 1229 1232 1231 1185 1186 1226 1227 1222 1223 1224 1225 0 Light Wood 1 +11 1247 1241 1249 1244 1248 1240 1246 1245 1187 1188 1242 1243 1236 1237 1238 1239 0 Light Wood 2 +12 1288 1284 1286 1287 1285 0 1289 1290 1220 1218 1217 1219 1221 0 1291 1292 0 Palm Logs +13 1040 1041 1039 1042 1035 1036 1038 1037 1339 1340 1341 1342 1043 1045 1044 1046 0 Dirt to Cave +14 6013 6014 6015 6016 6017 0 0 0 6077 6078 6079 6080 0 0 0 0 0 Grass and Snow +15 12788 12789 12790 12791 0 0 12792 12795 1301 1302 1303 1304 0 0 12793 12794 0 Dirt and Cobblestones +16 0 13465 13471 13477 13483 13522 0 0 4850 4862 4868 4874 4880 4886 4892 0 0 Water / Lava +17 4896 4899 4902 4905 4908 4911 4914 4917 4920 4923 4926 4929 4932 4935 4938 4941 0 Lava Transition +18 0 12906 12907 12908 12909 12910 12911 0 0 0 0 12809 12810 0 0 0 0 Swamp 1 +19 12888 12889 12890 12891 12892 12893 12894 0 12895 12896 12897 12898 12899 12900 12901 0 0 Swamp 2 +20 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10704 10705 10710 10711 64 Tatami Floor 1 +21 10812 10813 10814 10818 10815 10816 10817 10820 10785 10786 10787 10788 10789 10790 10791 10792 64 Tatami Floor 2 +22 9269 9270 9271 9272 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 64 Tatami Floor 3 +23 0 0 9265 9266 9267 9268 0 0 0 0 0 0 0 0 0 0 64 Tatami Floor 4 +24 0 9299 9300 9301 9302 9305 9306 0 0 9307 9303 9304 9308 9309 0 0 64 Pond +25 9310 9311 9312 9313 9314 9315 9320 9321 0 9322 9316 9317 9318 9319 9323 0 64 Gravel +26 0 9275 9276 9277 9278 9279 9280 0 0 9281 9282 9283 9284 9285 9286 0 64 Wood Floor 1 +27 0 9287 9288 9289 9290 9291 9292 0 0 9293 9294 9295 9296 9297 9298 0 64 Wood Floor 2 +28 0 10592 10593 10594 10595 10596 10598 0 0 10599 10600 10601 10602 10603 10604 0 64 Wood Floor 3 +29 0 10605 10606 10607 10608 10609 10610 0 0 10611 10612 10613 10614 10615 10597 0 64 Wood Floor 4 +30 0 10018 10019 10020 10021 10022 10023 0 0 10024 10025 10026 10027 10028 10029 0 64 Wood Floor 5 +31 0 10030 10031 10032 10033 10034 10035 0 0 10036 10037 10038 10039 10040 10041 0 64 Wood Floor 6 +32 0 10042 10043 10044 10045 10046 10047 0 0 10048 10049 10050 10051 10052 10053 0 64 Wood Floor 7 +33 0 10054 10055 10056 10057 10058 10059 0 0 10060 10061 10062 10063 10064 10065 0 64 Wood Floor 8 +34 0 10616 10617 10618 10619 10620 10621 0 0 10622 10623 10624 10625 10626 10627 0 64 Wood Floor 9 +35 0 10628 10629 10630 10631 10632 10633 0 0 10634 10635 10636 10637 10638 10639 0 64 Wood Floor 10 +36 0 0 11189 11190 11191 11192 0 0 0 0 0 0 0 0 0 0 128 Diagonal Floor +37 0 0 11215 11500 11501 11502 0 0 0 0 0 0 0 0 0 0 128 Parka Floor +38 0 0 11576 11577 11578 11579 0 0 0 0 0 0 0 0 0 0 128 Wormwood Floor +39 0 0 11723 11724 11725 11726 0 0 0 0 0 0 0 0 0 0 128 Deca Floor +40 0 0 13746 13747 13748 13749 13750 13751 13752 13753 13754 13755 13756 13757 0 0 512 Crystal Floor +41 0 0 0 13850 13851 13852 13853 13854 13855 13856 13857 13858 0 0 0 0 512 Shadow Floor +42 17196 17197 17192 17193 17194 17195 17206 17207 17208 17209 17210 17211 0 0 0 0 65536 Gargish Floor 1 +43 17198 17199 17200 17201 17202 17203 17204 17205 0 0 0 0 0 0 0 0 65536 Gargish Floor 2 +44 19946 19947 19948 19949 19950 19951 19952 19953 19954 19942 19943 19945 19755 19756 19757 19758 65536 Gargish Striped +45 20345 20340 20341 20342 20343 20336 20337 20338 20339 20332 20333 20334 20335 20329 20330 20331 65536 Gargish Blue Stripe +46 20706 20707 20708 20702 20703 20704 20705 20711 20712 20713 20714 20715 20716 20717 20718 20709 65536 Gargish Red +47 20723 20719 20720 20721 20722 20724 20725 20726 20727 0 0 0 0 0 0 0 65536 Gargish Dark +48 16815 16816 16817 16818 16821 16822 16823 16824 16825 16826 16827 16828 0 0 0 0 65536 Gargish Green +49 16884 16872 16873 16874 16875 16876 16877 16878 16879 16880 16881 16882 16883 16885 16886 16887 65536 Gargish Stone +50 16864 16860 16861 16862 16863 16865 16866 16867 16868 0 0 0 0 0 0 0 65536 Gargish Motif +51 16778 16774 16775 16776 16777 16779 16780 16781 16782 0 0 0 0 0 0 0 65536 Gargish Sun +52 16523 16524 16525 16526 16527 16528 16529 16530 16531 16532 16533 16534 16535 16536 16537 16538 65536 Gargish Green Stone +53 16514 16510 16511 16512 16513 16515 16516 16517 16518 16519 16520 16521 16522 0 0 0 65536 Gargish Green Stone 2 +54 18124 18125 18126 18127 18326 18327 18328 18329 0 0 0 0 0 0 0 0 65536 Gargish Ruins diff --git a/Data/Components/misc.txt b/Data/Components/misc.txt new file mode 100644 index 0000000..efeb2c2 --- /dev/null +++ b/Data/Components/misc.txt @@ -0,0 +1,93 @@ +int int int int int int int int int int int int string +Category Style TID Piece1 Piece2 Piece3 Piece4 Piece5 Piece6 Piece7 Piece8 FeatureMask Comment +0 0 1060056 44 0 41 40 42 0 43 29 0 Fieldstone Archways +1 0 1060070 470 0 471 469 473 0 472 466 0 Weathered Stone Square Archways +1 1 0 476 0 477 475 479 0 478 466 0 Weathered Stone Rounded Archways +1 2 0 480 481 482 483 484 485 0 0 0 Weathered Stone Miscellaneous 1 +1 3 0 474 486 487 0 0 0 0 0 0 Weathered Stone Miscellaneous 2 +2 0 1060071 0 16134 9541 9537 9538 9550 9551 9555 0 Weathered Stone Rounded Walls 1 +2 1 0 0 9541 9539 9543 9554 9553 9555 0 0 Weathered Stone Rounded Walls 2 +2 2 0 0 9555 9548 9549 9550 9544 9541 0 0 Weathered Stone Rounded Walls 3 +2 3 0 0 9555 9546 9543 9535 9536 9541 0 0 Weathered Stone Rounded Walls 4 +3 0 1060072 209 0 207 205 206 0 208 204 0 Granite Square Archways +3 1 0 218 0 216 212 215 0 217 204 0 Granite Rounded Archways +3 2 0 225 213 225 224 214 226 227 226 0 Granite Miscellaneous 1 +3 3 0 0 211 228 219 229 210 0 0 0 Granite Miscellaneous 2 +4 0 1060058 71 0 72 69 70 0 73 54 0 Grey Brick Archways +4 1 0 83 80 78 82 79 81 84 0 0 Grey Brick Archway Edging +5 0 1060059 111 0 112 109 110 0 113 90 0 Light Brick Archways +5 1 0 0 118 116 115 114 117 0 119 0 Light Brick Battlements +5 2 0 631 636 633 632 634 635 641 642 0 Light Brick Ruins +6 0 1060063 1082 0 1081 1080 1083 0 1084 251 0 Tan Marble Fancy Archways +6 1 0 1087 0 1086 1085 1088 0 1089 257 0 Tan Marble Medium Archways +6 2 0 276 0 275 274 277 0 278 263 0 Tan Marble Plain Archways +6 3 0 284 283 285 0 287 286 288 7978 0 Tan Marble Columns +6 4 0 0 289 290 0 292 291 0 0 0 Tan Marble Arcades +7 0 1060064 1096 0 1095 1094 1097 0 1098 672 0 White Marble Fancy Archways +7 1 0 1101 0 1100 1099 1102 0 1103 666 0 White Marble Medium Archways +7 2 0 690 0 689 688 691 0 692 660 0 White Marble Plain Archways +7 3 0 680 679 681 0 683 682 684 0 0 White Marble Columns +7 4 0 0 701 702 0 704 703 0 0 0 White Marble Arcades +8 0 1060065 368 370 365 364 366 369 367 353 0 Sandstone Archways +8 1 0 395 394 0 396 397 0 398 399 0 Sandstone Fancy Arcades +8 2 0 0 403 402 0 400 401 0 0 0 Sandstone Plain Arcades +8 3 0 373 374 375 376 386 387 388 389 0 Sandstone Battlements 1 +8 4 0 420 380 378 379 377 381 371 0 0 Sandstone Battlements 2 +8 5 0 382 383 384 385 390 391 392 393 0 Sandstone Battlements 3 +8 6 0 405 404 406 0 0 0 0 0 0 Sandstone Columns +8 7 0 951 952 953 954 955 956 957 0 0 Sandstone and Mortar Ruins 1 +8 8 0 959 963 964 965 966 0 0 0 0 Sandstone and Mortar Ruins 2 +9 0 1063391 10718 0 10719 10716 10725 10717 0 10720 64 Plaster Archways +10 0 1060073 538 536 534 535 528 530 529 531 0 Bamboo Rounded Walls 1 +10 1 0 538 533 529 532 528 527 534 537 0 Bamboo Rounded Walls 2 +11 0 1060074 24 25 49 50 85 86 120 121 0 Miscellaneous Roof Pieces 1 +11 1 0 456 457 162 163 164 165 193 194 0 Miscellaneous Roof Pieces 2 +11 2 0 230 231 293 294 330 331 433 434 0 Miscellaneous Roof Pieces 3 +11 3 0 435 436 409 410 494 495 407 408 0 Miscellaneous Roof Pieces 4 +11 4 0 492 493 523 524 554 555 677 678 0 Miscellaneous Roof Pieces 5 +11 5 0 10722 10721 10723 10724 10726 10727 0 0 64 Miscellaneous Roof Pieces 6 +12 0 1060075 711 715 714 713 716 717 712 0 0 Castle Battlements 1 +12 1 0 718 724 719 721 720 722 723 725 0 Castle Battlements 2 +12 2 0 0 0 726 727 728 729 0 0 0 Castle Battlements 3 +13 0 1061686 2083 2082 2081 0 2123 2122 2121 0 0 Fences 1 +13 1 0 2141 2140 2142 2143 2147 2146 2148 2149 0 Fences 2 +13 2 0 2226 2227 2228 2229 2243 2244 2245 2246 0 Fences 3 +13 3 0 0 2230 2231 2232 2233 2234 2235 0 0 Fences 4 +13 4 0 0 2236 2237 2238 2239 2240 2241 2242 0 Fences 5 +13 5 0 2285 2283 2284 2286 0 0 2299 2300 0 Fences 6 +13 6 0 2289 2287 2288 2290 0 0 2299 2300 0 Fences 7 +13 7 0 2294 2291 2292 2293 0 0 2299 2300 0 Fences 8 +13 8 0 2297 2295 2296 2298 0 0 2299 2300 0 Fences 9 +14 0 1062931 0 13550 13556 13559 13562 13568 13574 0 0 Waterfalls 1 +14 1 0 0 13582 13586 13592 13598 13604 0 0 0 Waterfalls 2 +15 0 1062932 0 6425 6424 6419 6427 6426 6417 0 0 Bar 1 +15 1 0 0 6429 6428 6416 6431 6430 6418 0 0 Bar 2 +16 0 1061020 0 6173 6174 6175 6176 6177 6178 0 0 Teleporters 1 +16 1 0 0 6179 6180 6181 6182 6183 6184 0 0 Teleporters 2 +17 0 1074416 11722 11713 11714 12059 11711 0 11721 11712 128 elven whitewood arch +18 0 1074417 11188 11179 11180 12060 11177 0 11187 11178 128 heartwood arch +19 0 1074418 11214 11205 11206 12061 11203 0 11213 11204 128 kiawood arch +20 0 1074419 11575 11542 11543 12062 11540 0 11574 11541 128 tanglewood arch +21 0 1076716 0 13802 13803 13804 13814 13815 0 0 512 Miscellaneous Crystal Pieces +22 0 1076717 0 13838 13839 13840 13841 13983 13842 0 512 Miscellaneous Shadow Pieces +23 0 1112089 17166 17167 17363 17364 17170 17171 17367 17368 65536 Gargish Battlement 1 +23 1 0 17168 17169 17365 17366 17162 17163 17345 17346 65536 Gargish Battlement 2 +23 2 0 17160 17161 17359 17360 17164 17165 17218 17219 65536 Gargish Battlement 3 +23 3 0 17232 17233 17371 17372 17234 17235 0 0 65536 Gargish Battlement 4 +24 0 1112089 17188 17185 17186 17187 17189 17172 17173 17174 65536 Gargish Battlement 5 +25 0 1112090 17212 17213 17214 17215 17216 17217 17177 0 65536 Dark Red Stone Arches +26 0 1060074 17319 17318 17369 17370 17321 17322 17325 17326 65536 Miscellaneous Roof Pieces 1 +26 1 0 17340 17342 17343 17341 17338 17339 17337 17336 65536 Miscellaneous Roof Pieces 2 +26 2 0 17320 17323 17324 17327 17221 17220 17222 17223 65536 Miscellaneous Roof Pieces 3 +27 0 1112091 17278 17282 17286 17290 17294 17298 17302 17306 65536 Gargish Fountain 1 +27 1 0 17310 17314 0 0 0 0 0 0 65536 Gargish Fountain 2 +28 0 1112092 16800 16801 16803 16804 16809 16810 16811 16812 65536 Green Marble Arches +29 0 1112093 16754 16755 16752 16753 16756 16750 16751 0 65536 Blue Marble Arches +30 0 1112094 16714 16715 16716 16717 16727 16726 16728 16729 65536 Two-Tone Stone Archways +30 1 0 0 0 0 16746 16747 0 0 0 65536 Two-Tone Stone Archways +31 0 1112095 16672 16671 16673 16674 16667 16668 16669 16670 65536 Gold Stone Battlement +32 0 1112096 20771 20772 20773 20774 20728 20729 20731 20732 65536 Gargish Marble Arches +33 0 1112097 18401 18402 18403 18407 18408 18409 0 0 65536 Gargish Ruined Arches +34 0 1112098 18600 18601 18602 18603 18604 18605 0 0 65536 Gargish Stone Heads +35 0 1150613 0 30705 30706 30707 30708 30709 0 30710 524288 Board and Batten Arches +36 0 1150624 0 19248 19192 19261 19249 19198 0 0 262144 Gothic Arches diff --git a/Data/Components/roof.txt b/Data/Components/roof.txt new file mode 100644 index 0000000..69a22c1 --- /dev/null +++ b/Data/Components/roof.txt @@ -0,0 +1,36 @@ +int int int int int int int int int int int int int int int int int int int int string +Category Style TID North East South West NSCrosspiece EWCrosspiece NDent EDent SDent WDent NTPiece ETPiece STPiece WTPiece XPiece Extra Piece FeatureMask Comment +0 0 1063375 11314 11301 11313 11302 11300 11312 11305 11304 11306 11303 11308 11311 11309 11310 11307 0 64 Tile Roof +1 0 1063376 11329 11316 11328 11317 11315 11327 11320 11319 11321 11318 11323 11326 11324 11325 11322 0 64 Wooden Shingles +2 0 1063377 11344 11331 11343 11332 11330 11342 11335 11334 11336 11333 11338 11341 11339 11340 11337 0 64 Log Roof +3 0 1063378 11350 11345 11348 11347 11346 11349 11353 11352 11354 11351 11356 11359 11357 11358 11355 0 64 Thatch Roof +4 0 1063379 11374 11369 11372 11371 11370 11373 11362 11361 11363 11360 11364 11368 11365 11367 11366 0 64 Palm Fronds +5 0 1063380 11389 11376 11388 11377 11375 11387 11380 11379 11381 11378 11383 11386 11384 11385 11382 0 64 Stone Roof +6 0 1063381 9964 9947 9963 9948 9946 9962 9951 9950 9952 9949 9954 9955 9956 9953 9957 9958 64 Straw Roof 1 +6 1 0 9959 9960 9961 0 0 0 0 0 0 0 0 0 0 0 0 0 64 Straw Roof 2 +7 0 1063382 9994 9977 9993 9978 9976 9992 9981 9980 9982 9979 9984 9985 9986 9983 9987 9988 64 Bark Roof 1 +7 1 0 9989 9990 9991 0 0 0 0 0 0 0 0 0 0 0 0 0 64 Bark Roof 2 +8 0 1063385 9159 9160 9155 9156 9153 9154 9157 9158 9163 9164 9165 9166 9167 9168 9161 9162 64 Ceramic Tiles 1 +8 1 0 0 0 9151 9150 9152 0 0 0 0 0 9171 9169 9170 0 0 0 64 Ceramic Tiles 2 +9 0 1063386 9184 9185 9180 9181 9178 9179 9182 9183 9188 9189 9190 9191 9192 9193 9186 9187 64 Red Ceramic Tiles 1 +9 1 0 0 0 9174 9172 9176 0 0 0 0 0 9177 9173 9175 0 0 0 64 Red Ceramic Tiles 2 +10 0 1063387 9206 9207 9202 9203 9200 9201 9204 9205 9210 9211 9212 9213 9214 9215 9208 9209 64 Green Ceramic Tiles 1 +10 1 0 0 0 9196 9194 9198 0 0 0 0 0 9199 9195 9197 0 0 0 64 Green Ceramic Tiles 2 +11 0 1063388 10540 10541 10536 10537 10534 10535 10538 10539 10544 10545 10546 10547 10548 10549 10542 10543 64 Orange Ceramic Tiles 1 +11 1 0 0 0 10530 10528 10532 0 0 0 0 0 10533 10529 10531 0 0 0 64 Orange Ceramic Tiles 2 +12 0 1063389 10492 10493 10488 10489 10486 10487 10490 10491 10496 10497 10498 10499 10500 10501 10494 10495 64 Gold Ceramic Tiles 1 +12 1 0 0 0 10482 10480 10484 0 0 0 0 0 10485 10481 10483 0 0 0 64 Gold Ceramic Tiles 2 +13 0 1063390 10514 10515 10510 10511 10508 10509 10512 10513 10518 10519 10520 10521 10522 10523 10516 10517 64 White Ceramic Tiles 1 +13 1 0 0 0 10504 10502 10506 0 0 0 0 0 10507 10503 10505 0 0 0 64 White Ceramic Tiles 2 +14 0 1063383 10436 10419 10435 10420 10418 10434 10423 10422 10424 10421 10426 10437 10427 10428 10425 0 64 Slate Roof 1 +14 1 0 0 10430 10431 10432 10433 10795 10796 0 0 10475 10476 10477 10478 10798 0 0 64 Slate Roof 2 +15 0 1063384 10458 10441 10457 10442 10440 10456 10445 10444 10446 10443 10448 10451 10449 10450 10447 0 64 Wooden Slats 1 +15 1 0 0 10452 10453 10454 10455 10473 10472 0 0 10459 10468 10469 10470 10474 10471 0 64 Wooden Slats 2 +16 0 1074420 11155 11138 11154 11139 11137 11153 11142 11141 11143 11140 11145 11148 11146 11147 11144 0 128 Elf Scaled Roof +16 1 0 11149 11150 11151 11152 12064 12065 12066 12067 0 0 12063 0 0 0 0 0 128 Elf Scaled Roof +17 0 1074421 11174 11157 11173 11158 11156 11172 11161 11160 11159 11162 11164 11167 11165 11166 11163 0 128 Elvan Natural Roof +17 1 0 11168 11169 11170 11171 12068 12069 12070 12071 11175 11176 12072 0 0 0 0 0 128 Elvan Natural Roof +18 0 1076718 13762 13759 13760 13761 13762 13763 13764 13765 13776 13777 13766 13767 13768 13769 13770 13771 512 Crystal Roof Tiles 1 +18 1 0 13772 13773 13774 13775 0 0 0 0 0 0 0 0 0 0 0 0 512 Crystal Roof Tiles 2 +19 0 1076719 13859 13860 13861 13862 13863 13864 13865 13875 13876 13866 13867 13868 13869 13870 13871 13872 512 Shadow Roof Tiles 1 +19 1 0 13873 13874 13877 0 0 0 0 0 0 0 0 0 0 0 0 0 512 Shadow Roof Tiles 2 diff --git a/Data/Components/stairs.txt b/Data/Components/stairs.txt new file mode 100644 index 0000000..8fa1129 --- /dev/null +++ b/Data/Components/stairs.txt @@ -0,0 +1,19 @@ +int int int int int int int int int int int int int int int string +Category Block North East South West Squared1 Squared2 Rounded1 Rounded2 MultiNorth MultiEast MultiSouth MultiWest FeatureMask Comment +0 1848 1849 1852 1851 1850 1856 1854 1862 1861 7600 7601 7602 7603 0 Dark Wood +1 1955 1956 1959 1958 1957 1963 1961 0 0 7604 7605 7606 7607 0 Grey Stone +2 1928 1929 1932 1931 1930 1936 1934 1939 1938 7608 7609 7610 7611 0 Weathered Stone +3 1825 1826 1829 1828 1827 1833 1831 1836 1835 7612 7613 7614 7615 0 Light Wood +4 1822 1823 1865 1847 1846 1869 1867 0 0 7616 7617 7618 7619 0 Granite +5 1801 1802 1805 1804 1803 1809 1807 1812 1811 7620 7621 7622 7623 0 Tan Marble +6 1006 1007 1010 1009 1008 1014 1012 1017 1016 7624 7625 7626 7627 0 Sandstone +7 1900 1901 1904 1903 1902 1908 1906 1911 1910 7628 7629 7630 7631 0 Sandstone Brick +8 1872 1873 1876 1875 1874 1880 1878 1883 1882 7632 7633 7634 7635 0 Light Stone +9 1978 1979 0 0 1980 0 0 0 1991 7636 0 0 7639 0 Red +10 13778 13780 13781 13782 13779 0 0 0 0 7640 7641 7642 7643 512 Crystal +11 13833 13835 13836 13837 13834 0 0 0 0 7644 7645 7646 7647 512 Shadow +12 17175 17248 17249 17247 17246 17261 17260 17257 17256 7648 7649 7650 7651 65536 Gargish 1 +13 17175 17244 17253 17243 17250 0 0 0 0 7652 7653 7654 7655 65536 Gargish 2 +14 17176 17252 17245 17251 17242 0 0 0 0 7656 7657 7658 7659 65536 Gargish 3 +15 19207 19205 19251 19252 19204 19202 19201 19262 19263 7660 7661 7662 7663 262144 Gothic +16 30727 30729 30731 30730 30728 30733 30732 30739 30738 7664 7665 7666 7667 524288 Board and Batten diff --git a/Data/Components/suppinfo.txt b/Data/Components/suppinfo.txt new file mode 100644 index 0000000..f0b3bb3 --- /dev/null +++ b/Data/Components/suppinfo.txt @@ -0,0 +1,1783 @@ + int int int int int int int int int int int int int int int string + tileNumber top bottom adj_UN adj_LN adj_UE adj_LE adj_US adj_LS adj_UW adj_LW directSupports cango W cango N cango NWC Comment +\ 10 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Dark Wood Std +\ 7 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 12 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 6 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 13 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 8 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 9 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 14 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 15 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 18 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 16 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 17 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 19 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 22 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 20 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 21 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 23 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 171 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Wood Std +\ 168 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 173 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 166 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 172 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 167 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 170 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 169 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 186 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9472 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9473 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 185 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9478 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9479 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 174 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +\ 175 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Wood Std +./ 176 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 177 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 178 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Wood Std +./ 179 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 180 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 181 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Wood Std +./ 187 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 188 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Wood Std +\ 948 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 947 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 949 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 950 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 191 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 189 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 190 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 192 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 30 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Field Stone Std +\ 28 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 33 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 26 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 32 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 27 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 31 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 29 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 34 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 35 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10668 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Fieldstone Stained Glass +\ 10669 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10670 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10671 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10672 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10673 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10674 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10675 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10676 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10677 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 37 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Field Stone Half +v 36 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 38 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 39 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 464 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Weathered Stone Std +v 463 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 465 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 466 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 467 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 468 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10660 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Weathered Stone Stained Glass +\ 10661 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10662 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10663 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10664 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10665 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10666 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10667 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 489 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Weathered Roof Edges +v 488 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 490 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 491 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 200 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Granite Std +v 199 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 201 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 204 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 202 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 203 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 222 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Granite Roof Edges +v 220 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 221 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 223 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 55 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Grey Brick Std +\ 52 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 57 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 51 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 58 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 53 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 56 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 54 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 59 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 60 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10678 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Grey Brick Stained Glass +\ 10679 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10680 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10681 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 10682 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10683 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10684 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10685 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10686 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10687 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 62 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Grey Brick Half +v 61 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 63 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 64 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 66 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Grey Brick Quarter +v 65 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 67 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 68 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 88 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Brick Std +v 89 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 87 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 90 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 92 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 94 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 93 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 91 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10656 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Light Brick Stained Glass +\ 10657 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10658 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10659 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 95 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Half +v 97 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 96 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 98 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 99 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +v 101 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 100 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 102 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 105 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Roof Edges +v 107 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 106 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 108 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 444 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Hide Walls +\ 440 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 438 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 439 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 445 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 441 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 452 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 453 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 446 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Hide Alternates +\ 450 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 448 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 449 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 451 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 447 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 454 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 455 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 427 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Woven Std +\ 422 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 423 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 421 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 426 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 425 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 428 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 424 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 429 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 430 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 432 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 431 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 8539 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Woven Short +v 8540 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 8538 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 149 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Logs Std +\ 146 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 151 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 144 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 150 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 145 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 148 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 147 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 152 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9460 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9461 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 153 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9466 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9467 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 159 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Logs Half +\ 156 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 161 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 154 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 160 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 155 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 158 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 157 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 552 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Palisades Std +v 550 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 551 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 553 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 1072 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Palisades Alts +\ 1058 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 546 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 547 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 1057 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 545 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 1059 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Palisades Roof Edges +v 1061 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 1060 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 249 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Tan Marble Fancy Std +v 248 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 250 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 251 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 252 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9484 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9485 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 253 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9490 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9491 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 255 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Tan Marble Medium Std +v 254 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 256 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 257 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 258 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9496 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9497 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 259 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9502 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9503 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 261 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Tan Marble Plain Std +v 260 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 262 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 263 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 264 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9508 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9509 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 265 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9514 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9515 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 267 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Tan Marble Half Walls +v 266 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 268 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 269 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 271 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Tan Marble Fancy Roof Edges +v 270 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 272 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 273 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 1091 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Tan Marble Medium Roof Edges +v 1090 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 1092 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 1093 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 280 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Tan Marble Plain Roof Edges +v 279 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 281 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 282 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 670 1 1 0 0 1 1 1 1 1 1 1 0 1 0 White Marble Fancy Std +v 669 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 671 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 672 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 686 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 685 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 664 1 1 0 0 1 1 1 1 1 1 1 0 1 0 White Marble Medium Std +v 663 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 665 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 666 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 667 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 668 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 658 1 1 0 0 1 1 1 1 1 1 1 0 1 0 White Marble Plain Std +v 657 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 659 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 660 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 661 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9532 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9533 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 662 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9940 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9941 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 674 1 1 0 0 0 1 0 1 0 1 0 0 1 0 White Marble Half Walls +v 673 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 675 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 676 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 698 1 1 0 0 0 1 0 1 0 1 0 0 1 0 White Marble Fancy Roof Edges +v 697 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 699 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 700 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 1105 1 1 0 0 0 1 0 1 0 1 0 0 1 0 White Marble Medium Roof Edges +v 1104 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 1106 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 1107 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 694 1 1 0 0 0 1 0 1 0 1 0 0 1 0 White Marble Plain Roof Edges +v 693 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 695 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 696 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +./ 289 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 290 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 291 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 292 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 345 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone Brick Fancy +v 344 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 346 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 347 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 348 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 349 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 352 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone Brick Plain +v 350 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 351 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 353 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 355 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 354 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 357 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Sandstone Fancy Brick Half Wall +v 356 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 358 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 359 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 362 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Sandstone Plain Brick Half Wall +v 360 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 361 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 363 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 517 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone and Plaster +\ 515 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 512 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 511 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 513 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 516 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 518 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 514 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 519 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9519 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9520 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 521 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 520 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 522 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9526 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9527 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 598 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Flat Stone Medium +v 597 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 599 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 601 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 592 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Flat Stone Plain +v 591 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 593 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 600 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 595 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Flat Stone Open +v 594 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 596 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 602 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 589 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Flat Stone Fancy +v 588 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 590 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 603 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 968 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone and Mortar +v 967 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 969 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 970 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 990 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 991 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 972 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone and Mortar +v 971 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 973 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 974 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 983 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone and Mortar +\ 980 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 993 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 979 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 994 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 981 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 984 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 982 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +v 992 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 960 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Sandstone and Mortar Half Wall +v 958 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 961 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 962 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 976 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Sandstone and Mortar Brick Half Wall +v 975 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 977 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 978 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 312 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Wood and Plaster Plain +\ 310 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 307 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 309 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 308 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 311 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 313 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 298 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 314 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 315 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 310 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 306 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 302 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Wood and Plaster Diagonal Beams 1 +\ 296 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 295 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 297 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 311 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 303 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 304 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Wood and Plaster Diagonal Beams 2 +\ 310 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 300 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 299 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 301 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 311 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 305 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 336 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Wood and Plaster Fancy +v 332 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 334 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 342 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 343 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 338 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Wood and Plaster Medium +v 335 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 339 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 340 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 341 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 910 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Damaged Plaster Plain +v 909 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 911 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 898 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 912 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Damaged Plaster Damaged +\ 915 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 907 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 914 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 908 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 916 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 913 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 906 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 902 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Damaged Plaster Damaged Diagonals 1 +\ 915 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 896 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 895 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 897 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 916 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 903 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 904 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Damaged Plaster Damaged Diagonals 2 +\ 915 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 900 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 899 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 901 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 916 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 905 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 9351 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Lacquered Panels Standard Walls +v 9349 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 9350 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 9354 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 9348 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Lacquered Panels Half Walls +v 9346 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 9347 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 9353 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 9345 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Lacquered Panels Quarter Walls +v 9343 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 9344 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 9352 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 9367 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Cherrywood Standard Walls +v 9365 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 9366 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 9368 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 9363 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Cherrywood Half Walls +v 9361 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 9362 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 9364 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 9359 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Cherrywood Quarter Walls +v 9357 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 9358 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 9360 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 9384 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Plaster Standard Walls +\ 9378 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 9373 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 9374 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9377 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 9383 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 10800 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 10803 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +o 10806 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 10809 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 9380 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Plaster Half Walls +\ 9371 1 1 0 0 1 1 1 1 1 1 0 0 1 0 +\ 9386 1 1 0 0 1 1 1 1 1 1 0 0 1 0 +./ 9372 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +./ 9379 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +./ 9385 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +v 10801 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +v 10804 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +o 10807 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +o 10810 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 9382 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Plaster Quarter Walls +\ 9376 1 1 0 0 1 1 1 1 1 1 0 0 1 0 +./ 9375 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +./ 9381 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +v 10802 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +o 10808 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10015 1 1 0 0 0 1 0 1 0 1 1 0 1 0 Paper Standard Walls +v 10005 1 1 0 1 0 1 0 1 0 1 1 0 0 0 +./ 10012 1 1 0 1 0 1 0 1 0 0 1 1 0 0 +\ 10014 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Paper Half Walls +v 10004 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 10011 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 10013 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Paper Quarter Walls +v 10003 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 10010 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 10082 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Lattice Standard Walls +v 10069 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 10079 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 10076 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 10081 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Lattice Half Walls +v 10068 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10078 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10075 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10080 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Lattice Quarter Walls +v 10067 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10077 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10074 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10650 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Wood Panel Standard Walls +v 10653 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 10647 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 10644 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 10649 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Wood Panel Half Walls +v 10652 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10646 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10643 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10648 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Wood Panel Quarter Walls +v 10651 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10645 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10642 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10560 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Clay Standard Walls +v 10554 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 10557 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 10563 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 10559 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Clay Half Walls +v 10553 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10556 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10562 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10558 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Clay Quarter Walls +v 10552 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10555 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10561 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10575 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Weathered Clay Standard Walls +v 10566 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 10569 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 10572 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 10574 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Weathered Clay Half Walls +v 10565 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10568 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10571 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10573 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Weathered Clay Quarter Walls +v 10564 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10567 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10570 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10581 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Limestone Standard Walls +v 10584 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 10578 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 10587 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 10580 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Limestone Half Walls +v 10583 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10577 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10586 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +\ 10579 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Limestone Quarter Walls +v 10582 1 1 1 1 1 1 1 1 1 1 0 0 0 0 +./ 10576 1 1 1 1 1 1 1 1 0 0 0 1 0 0 +o 10585 1 1 0 0 1 1 1 1 0 0 0 1 1 1 +v 10728 1 1 1 1 1 1 1 1 1 1 1 0 0 0 Dark Plaster Standard Walls +\ 10729 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10730 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 10731 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +v 10732 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 10733 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10734 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10735 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10736 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10737 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10738 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 10739 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 10740 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10741 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 10742 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 10743 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10744 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10745 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10746 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 10747 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 10748 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 44 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Weathered Stone Arches +\ 41 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 40 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 42 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 43 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 470 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Weathered Stone Arches 2 +\ 471 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 469 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 473 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 472 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 476 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Weathered Stone Arch Tops +\ 477 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 475 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 479 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 478 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 480 0 1 0 0 0 0 0 0 0 1 0 0 1 0 +\ 481 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Weathered Stone Misc +v 482 0 1 0 0 0 1 0 0 0 0 0 0 1 0 +./ 483 0 1 0 0 0 0 0 0 0 1 0 0 1 0 +./ 484 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +./ 485 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Weathered Stone Round Walls +. 474 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 486 0 1 1 1 0 0 0 0 0 0 0 1 0 0 +. 487 0 1 0 0 0 0 0 0 1 1 0 0 1 0 +. 16134 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9541 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9537 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9538 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9550 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9551 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9555 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9539 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9543 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9554 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9553 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9548 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9549 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9544 1 1 0 0 0 0 0 0 0 0 1 0 0 0 Granite Square Arches +. 9546 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9535 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 9536 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +\ 209 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Granite Rounded Arches +\ 207 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 205 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 206 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 208 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 218 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Granite Misc +\ 216 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 212 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 215 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 217 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 225 0 1 0 0 0 1 0 0 0 0 0 0 1 0 +\ 213 0 1 0 0 0 0 0 0 0 1 0 0 1 0 Granite Misc +\ 224 0 1 0 0 0 0 0 0 0 1 0 0 1 0 +./ 214 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +./ 226 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +./ 227 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +. 211 0 1 1 1 0 0 0 0 0 0 0 1 0 0 Grey Brick Arches +. 228 1 1 0 0 0 0 1 1 1 1 1 0 1 0 +. 219 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 229 1 1 1 1 1 1 0 0 0 0 1 1 0 0 +. 210 0 1 0 0 0 0 0 0 1 1 0 0 1 0 +\ 71 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Grey Brick Roof Trim +\ 72 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 69 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 70 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 73 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 83 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 80 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 78 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Arches +v 82 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 79 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 81 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 84 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 111 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Light Brick Battlements +\ 112 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 109 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 110 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 113 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +. 118 0 1 0 1 0 1 0 0 0 0 0 0 0 0 +. 116 0 1 1 1 0 1 0 0 0 1 0 0 0 0 Light Brick Ruins +. 115 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +. 114 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 117 0 1 0 0 0 0 0 1 0 1 0 0 0 0 +. 119 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +\ 631 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 636 0 1 0 1 0 0 0 1 0 0 0 1 0 0 +./ 633 0 1 0 1 0 0 0 1 0 0 0 1 0 0 +\ 632 0 1 0 0 0 1 0 0 0 1 0 0 1 0 Tan Marble Fancy Arches +./ 634 0 1 0 1 0 0 0 1 0 0 0 1 0 0 +\ 635 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +\ 641 0 1 0 0 1 1 0 0 1 1 1 0 1 0 +./ 642 0 1 1 1 0 0 1 1 0 0 1 1 0 0 +\ 1082 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Tan Marble Medium Arches +\ 1081 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 1080 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 1083 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 1084 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 1087 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Tan Marble Plain Arches +\ 1086 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 1085 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 1088 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 1089 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 276 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Tan Marble Columns +\ 275 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 274 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 277 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 278 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +. 284 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 283 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 285 1 1 0 0 0 0 0 0 0 0 1 0 0 0 White Marble Fancy Arches +. 287 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 286 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 288 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 7978 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +\ 1096 1 0 0 0 1 0 1 0 1 0 1 0 1 0 White Marble Medium Arches +\ 1095 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 1094 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 1097 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 1098 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 1101 1 0 0 0 1 0 1 0 1 0 1 0 1 0 White Marble Plain Arches +\ 1100 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 1099 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 1102 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 1103 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 690 1 0 0 0 1 0 1 0 1 0 1 0 1 0 White Marble Columns +\ 689 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 688 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 691 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 692 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +. 680 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 679 1 1 0 0 0 0 0 0 0 0 1 0 0 0 White Marble Plain Arcades +. 681 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 683 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 682 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 684 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +./ 701 1 1 1 0 1 1 1 1 0 0 1 0 0 0 Sandstone Arches +./ 702 1 1 1 1 0 0 1 0 0 0 1 0 0 0 +\ 704 1 1 0 0 0 1 0 0 1 1 1 0 0 0 +\ 703 1 1 0 0 1 1 1 1 1 0 1 0 0 0 +\ 368 1 0 0 0 1 0 1 0 1 0 1 0 1 0 +\ 370 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +\ 365 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Sandstone Fancy Arcades +v 364 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 366 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 369 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +./ 367 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +./ 395 1 1 1 0 1 1 1 1 0 0 1 1 0 0 +./ 394 1 0 1 1 0 0 1 0 0 0 1 1 0 0 Sandstone Plain Arcades +\ 396 1 0 0 0 0 1 0 0 1 1 1 0 1 0 +\ 397 1 1 0 0 1 1 1 1 1 0 1 0 1 0 +\ 398 1 0 0 0 1 0 0 0 1 1 1 0 1 0 +./ 399 1 0 1 1 0 0 0 0 1 0 1 1 0 0 +\ 403 1 0 0 0 0 1 0 0 1 1 1 0 1 0 Sandstone Battlements 1 +\ 402 1 1 0 0 1 1 1 1 1 0 1 0 1 0 +./ 400 1 1 1 0 1 1 1 1 0 0 1 1 0 0 +./ 401 1 0 1 1 0 0 1 0 0 0 1 1 0 0 +. 373 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 374 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 375 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 376 1 1 1 1 1 1 1 1 1 1 1 0 0 0 Sandstone Battlements 2 +. 386 0 1 0 0 0 1 0 1 0 1 0 0 0 0 +. 387 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +. 388 0 1 0 1 0 0 0 0 0 0 0 0 0 0 +. 389 0 1 0 0 0 0 0 0 0 1 0 0 0 0 +. 420 0 1 0 1 1 1 0 1 0 0 0 0 0 0 +. 380 0 1 0 1 0 1 0 0 0 0 0 0 0 0 +. 378 0 1 1 1 0 1 0 0 0 1 0 0 0 0 Sandstone Battlements 3 +. 379 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +. 377 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 381 0 1 0 0 0 0 0 1 0 1 0 0 0 0 +. 371 0 1 0 0 0 1 1 1 0 1 0 0 0 0 +. 382 1 0 1 0 0 0 0 0 0 0 1 0 0 0 +. 383 1 0 0 0 0 0 0 0 1 0 1 0 0 0 +.. 384 1 0 0 0 0 0 1 0 0 0 1 0 0 0 +. 385 1 0 0 0 1 0 0 0 0 0 1 0 0 0 Sandstone pillers +. 390 1 0 1 0 0 0 0 0 0 0 1 0 0 0 +. 391 1 0 0 0 0 0 0 0 1 0 1 0 0 0 +. 392 1 0 0 1 0 1 0 0 0 0 1 0 0 0 +. 393 1 0 0 1 0 1 0 0 0 0 1 0 0 0 Sandstone Ruins 1 +. 405 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 404 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 406 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +./ 951 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +v 952 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 953 0 1 0 1 0 0 0 1 0 0 0 1 0 0 Sandstone Ruins 2 +\ 954 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +. 955 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +. 956 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 957 0 1 0 0 0 0 0 0 0 1 0 1 1 0 +\ 10718 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Plaster Arches +\ 10719 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 10716 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 10725 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 10717 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10720 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +v 959 0 1 0 1 0 1 0 1 0 1 0 0 0 0 Bamboo Round Walls +\ 963 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 964 0 1 0 1 0 0 0 1 0 0 0 1 0 0 +\ 965 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 966 0 1 0 1 0 0 0 1 0 0 0 1 0 0 +. 538 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 536 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 534 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 535 1 1 0 0 0 0 0 0 0 0 1 0 0 0 Bamboo Round Walls 2 +. 528 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 530 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 529 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 531 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 533 1 1 0 0 0 0 0 0 0 0 1 0 0 0 Misc Roof1 +. 532 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 528 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 527 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 537 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +\ 24 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 25 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 49 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 50 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Misc Roof2 +\ 85 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 86 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 120 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 121 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 456 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 457 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 162 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 163 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Misc Roof3 +\ 164 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 165 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 193 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 194 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 230 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 231 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 293 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 294 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Misc Roof4 +\ 330 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 331 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 433 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 434 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 435 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 436 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 409 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 410 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Misc Roof5 +\ 494 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 495 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 407 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 408 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 492 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 493 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 523 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 10723 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Misc Roof6 +\ 10722 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 10727 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 10726 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +v 10721 0 1 0 1 0 1 0 0 0 1 0 0 0 0 +. 10724 0 1 0 1 0 1 0 0 0 1 0 1 1 0 +./ 524 0 1 0 1 0 0 0 0 0 0 0 1 0 0 Castle Battlements 1 +\ 554 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 555 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +\ 677 0 1 0 0 0 1 0 0 0 1 0 0 1 0 +./ 678 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +. 711 0 1 0 1 1 1 0 1 0 0 0 0 0 0 +. 715 0 1 0 1 0 1 0 0 0 0 0 0 0 0 +. 714 0 1 1 1 0 1 0 0 0 1 0 0 0 0 Castle Battlements 2 +. 713 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +. 716 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 717 0 1 0 0 0 0 0 1 0 1 0 0 0 0 +. 712 0 1 0 0 0 1 1 1 0 1 0 0 0 0 +. 718 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +. 724 0 1 0 1 0 1 0 1 0 0 0 0 0 0 +. 719 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +. 721 0 1 0 0 0 1 0 1 0 1 0 0 0 0 Castle Battlements +. 720 0 1 0 1 0 0 0 0 0 0 0 0 0 0 +. 722 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +. 723 0 1 0 0 0 0 0 0 0 1 0 0 0 0 +. 725 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +. 726 0 1 0 1 0 0 0 0 0 0 0 0 0 0 Metal Door +. 727 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +. 728 0 1 0 0 0 0 0 0 0 1 0 0 0 0 +. 729 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 1653 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1655 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1657 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1659 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Rattan +./ 1661 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1663 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1665 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1667 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 1685 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1687 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1689 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1691 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Dark Wood Door +./ 1693 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1695 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1697 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1699 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 1701 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1703 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1705 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1707 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Wood Door +./ 1709 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1711 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1713 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1715 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 1717 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1719 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1721 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1723 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Light Wood Door +./ 1725 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1727 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1729 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1731 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 1749 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1751 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1753 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1755 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Wood And Metal Door +./ 1757 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1759 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1761 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1763 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 1765 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1767 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1769 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 1771 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Tall Iron Gate +./ 1773 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1775 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1777 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 1779 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 2084 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2086 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2088 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2090 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Light Wood Gate +./ 2092 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2094 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2096 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2098 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 2105 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2107 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2109 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2111 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Short Iron Gate +./ 2113 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2115 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2117 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2119 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 2124 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2126 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2128 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2130 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Dark Wood Gate +./ 2132 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2134 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2136 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2138 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 2150 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2152 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2154 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 2156 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Weathered Stone Secret +./ 2158 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2160 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2162 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 2164 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 804 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 806 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 808 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 810 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Dark Wood Secret +./ 812 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 814 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 816 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 818 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 820 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 822 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 824 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 826 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Light Wood Secret +./ 828 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 830 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 832 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 834 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 836 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 838 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 840 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 842 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Grey Stone Secret +./ 844 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 846 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 848 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 850 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 9249 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Japanese Doors +\ 9251 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 9247 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 10765 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Sliding Doors 1 +\ 10769 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 10767 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 10771 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 10757 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Sliding Doors 2 +\ 10759 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 10761 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 10763 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 10773 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Sliding Doors 3 +\ 10775 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 10777 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 10779 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 852 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 854 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 856 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 858 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Barred Metal +./ 860 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 862 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 864 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 866 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 8173 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 8175 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 8177 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 8179 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Tall Wrought Iron +./ 8181 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 8183 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 8185 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 8187 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Medium Wrouoght Iron +\ 2083 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +v 2082 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +./ 2081 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Wood Fence 1 +\ 2123 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 2122 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 2121 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 2141 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Wood Fence 2 +v 2140 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 2142 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 2143 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 2147 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Bannisters +v 2146 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 2148 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 2149 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +* 2226 0 1 0 1 0 0 0 1 0 1 0 0 0 0 +* 2227 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +* 2228 0 1 0 1 0 1 0 0 0 1 0 0 0 0 +* 2229 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +* 2230 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +* 2231 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +* 2232 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +* 2233 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +* 2234 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +* 2235 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +* 2236 0 1 0 1 0 1 0 0 0 1 0 0 0 0 +* 2237 0 1 0 1 0 0 0 1 0 1 0 0 0 0 +* 2238 0 1 0 1 0 1 0 0 0 1 0 0 0 0 +* 2239 0 1 0 1 0 0 0 1 0 1 0 0 0 0 +* 2240 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +* 2241 0 1 0 0 0 1 0 1 0 1 0 0 1 0 +* 2242 0 1 0 1 0 1 0 1 0 0 0 1 0 0 Wood Fence 3 +* 2243 0 0 0 1 0 1 0 1 0 0 0 1 0 0 +* 2244 0 0 0 1 0 0 0 1 0 1 0 0 0 0 +* 2245 0 0 0 0 0 1 0 1 0 1 0 0 1 0 +* 2246 0 0 0 1 0 1 0 0 0 1 0 0 0 0 +\ 2231 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Wood/Stone Fence 1 +v 2230 0 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 2232 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 2233 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 2285 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Wood/Stone Fence 2 +. 2283 0 1 0 0 0 0 0 1 0 1 0 0 1 0 +./ 2286 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +` 2284 0 1 0 1 0 1 0 0 0 0 0 1 0 0 +\ 2289 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Wood/Stone Fence 2 +. 2287 0 1 0 0 0 0 0 1 0 1 0 0 1 0 +./ 2288 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +` 2290 0 1 0 1 0 1 0 0 0 0 0 1 0 0 +\ 2294 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Wood/Stone Fence 2 +. 2291 0 1 0 0 0 0 0 1 0 1 0 0 1 0 +./ 2292 0 1 0 1 0 1 0 1 0 0 0 1 0 0 +` 2293 0 1 0 1 0 1 0 0 0 0 0 1 0 0 +\ 2297 0 1 0 0 0 1 0 1 0 1 0 0 1 0 Wood Slats +. 2295 0 1 0 0 0 0 0 1 0 1 0 0 1 0 +./ 2296 0 1 0 1 0 1 0 1 0 0 0 1 0 0 Waterfalls +` 2298 0 1 0 1 0 1 0 0 0 0 0 1 0 0 +\\ 2299 0 0 0 0 0 1 0 0 0 1 0 0 1 0 +// 2300 0 0 0 1 0 0 0 1 0 0 0 1 0 0 +* 13550 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13582 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13556 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13586 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13559 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13592 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13562 0 1 0 0 0 0 0 0 0 0 0 0 0 0 Bars +* 13598 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13568 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13604 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 13574 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6424 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6429 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6425 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6428 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6416 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6419 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6427 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6431 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6426 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6430 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6417 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +* 6418 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +\ 11508 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 11197 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11509 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11131 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 11132 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11198 1 1 0 0 1 1 1 1 1 1 1 0 1 0 White Marble Fancy Std +./ 11507 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 11564 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11585 1 1 0 0 1 1 1 1 1 1 1 0 1 0 White Marble Fancy Std +v 11717 0 1 0 1 0 1 0 1 0 1 1 0 0 0 +v 11546 0 1 0 1 0 1 0 1 0 1 1 0 0 0 +v 11183 0 1 0 1 0 1 0 1 0 1 1 0 0 0 +v 11211 0 1 0 1 0 1 0 1 0 1 1 0 0 0 +v 11545 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11716 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11182 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11209 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11544 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11715 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11181 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11207 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11767 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 11771 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +o 11547 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11184 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11208 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11718 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11768 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11772 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11548 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11185 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11210 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11719 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 11549 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11186 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11212 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11720 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 11583 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 11196 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 11506 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 11130 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 11582 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11195 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11505 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11729 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11580 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11193 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11503 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11769 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 11727 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 11581 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +\ 11194 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +\ 11504 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +\ 11728 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +\ 11770 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +\ 11774 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Light Brick Quarter +\ 11510 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11512 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11587 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11569 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11133 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11136 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11200 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11202 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 11586 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11588 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 10687 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11137 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11135 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11199 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11201 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11511 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 11188 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +\ 11214 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +\ 11722 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +\ 11575 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +./ 11187 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +./ 11213 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +./ 11574 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +./ 11721 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +./ 11540 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11711 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11177 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11203 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 11541 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11712 1 1 0 0 1 1 1 1 0 0 1 1 0 0 +./ 11176 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +o 11204 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11542 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11713 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11179 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 11205 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 11543 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11714 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11180 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11208 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 11134 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 11590 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Elf Wooden Door +./ 11620 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12704 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 12708 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +./ 12714 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12718 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11624 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +o 11178 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +./ 11590 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11619 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11623 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11627 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12705 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12709 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12717 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11589 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 11592 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11621 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 11625 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 11629 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 12707 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 12711 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 12719 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 11593 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11622 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12706 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12710 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12712 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 12718 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 11584 0 1 0 0 0 0 0 0 0 0 1 1 0 0 +./ 11621 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 12260 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 11259 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Wood And Metal Door +./ 12258 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 11206 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 12716 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Wood Door +\ 12700 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Moon Door +./ 12702 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Moon Door +v 12059 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 12060 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 12061 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 12062 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 13790 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Crystal Quarter +\ 13792 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Half +\ 13795 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full +\ 13796 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full +\ 13798 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full Window +./ 13789 1 1 0 1 0 1 0 1 0 0 0 1 0 0 Quarter +./ 13791 1 1 0 1 0 1 0 1 0 0 0 1 0 0 Half +./ 13793 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full +./ 13794 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full +./ 13797 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full Window +v 13783 1 1 1 1 1 1 1 1 1 1 0 0 0 0 Quarter +v 13784 1 1 0 1 0 1 0 1 0 1 0 0 0 0 Half +v 13785 1 1 1 1 1 1 1 1 1 1 1 0 0 0 Full +o 13786 1 1 0 0 1 1 1 1 0 0 0 1 1 1 Quarter +o 13787 1 1 0 0 0 1 0 1 0 0 0 1 1 1 Half +o 13788 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Full +\ 13947 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +\ 13949 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +\ 13951 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +\ 13953 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +./ 13955 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +./ 13957 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +./ 13959 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +./ 13961 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +o 13802 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13803 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13804 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13814 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13815 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +\ 13879 1 1 0 0 1 1 1 1 1 1 0 0 1 0 Shadow Quarter +\ 13881 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Half +\ 13883 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full +\ 13897 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full +\ 13895 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full +\ 13885 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full Window +\ 13887 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Full Window +./ 13878 1 1 0 1 0 1 0 1 0 0 0 1 0 0 Quarter +./ 13880 1 1 0 1 0 1 0 1 0 0 0 1 0 0 Half +./ 13882 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full +./ 13898 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full +./ 13896 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full +./ 13884 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full Window +./ 13886 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Full Window +v 13844 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Quarter +v 13845 1 1 0 1 0 1 0 1 0 1 0 0 0 0 Half +v 13846 1 1 1 1 1 1 1 1 1 1 1 0 0 0 Full +v 13843 1 1 1 1 1 1 1 1 1 1 1 0 0 0 Full +o 13847 1 1 0 0 0 1 0 1 0 0 0 1 1 1 Quarter +o 13848 1 1 0 0 0 1 0 1 0 0 0 1 1 1 Half +o 13849 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Full +o 13842 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Full +\ 13963 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +\ 13965 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +\ 13967 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +\ 13969 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Door +./ 13971 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +./ 13973 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +./ 13975 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +./ 13977 0 1 0 0 0 0 0 0 0 0 0 1 0 0 Door +o 13802 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13803 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13804 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13814 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +o 13815 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Pillar +\ 13840 1 0 0 0 1 0 1 0 1 0 1 0 1 0 Arch +\ 13841 1 0 1 0 1 0 1 0 0 0 1 1 0 0 Arch +./ 13838 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Arch +./ 13839 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Arch +v 13983 1 1 1 1 1 1 1 1 1 1 1 0 0 0 Arch +\ 16784 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Green Marble Walls +./ 16785 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16786 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16787 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16788 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16789 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 16790 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16791 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +o 16796 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 16797 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 16799 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +v 16805 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 16800 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Green Marble Arches +./ 16801 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16803 1 0 0 0 1 0 1 0 1 0 1 0 1 0 +./ 16804 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +\ 16810 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16812 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16809 1 0 0 0 1 0 1 0 1 0 1 0 1 0 +./ 16811 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +v 16806 1 1 0 1 0 1 0 1 0 1 0 0 0 0 Dark blue quarter wall +\ 16792 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16793 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16794 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16795 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16807 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16808 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 16798 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +./ 17226 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Gargish Set Marble Walls +\ 17227 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17228 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 17229 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17232 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 17233 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17236 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 17237 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17238 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 17239 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17240 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 17241 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +o 17190 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 17191 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +v 17183 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 17184 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +o 17349 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 17348 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17347 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 17354 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 17355 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 17371 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17372 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 17224 1 1 0 1 0 1 0 1 0 0 0 1 0 0 Gargish Set Marble Half Walls +\ 17225 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 17230 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 17231 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 17234 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 17235 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 17178 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +./ 17179 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 17180 0 1 0 0 0 1 0 1 0 0 0 1 1 1 +v 17181 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +\ 17182 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +o 17191 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 17177 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17189 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +v 17344 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +o 17353 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +./ 17352 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 17351 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 17350 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 17356 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +o 17357 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +v 17358 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +. 17172 1 1 0 0 0 0 0 0 0 0 1 0 0 0 Gargish Set Pillar +. 17173 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 17174 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 17160 0 1 1 1 0 1 0 0 0 1 0 0 0 0 Gargish Set Battlement +. 17161 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17162 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17163 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17164 0 1 1 1 0 0 0 0 0 0 0 1 0 0 +. 17165 0 1 0 0 0 0 0 0 1 1 0 0 1 0 +. 17166 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 17167 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 17168 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17169 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17170 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17171 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17188 0 1 0 1 1 1 0 1 0 0 0 0 0 0 +. 17187 0 1 0 1 0 0 0 0 0 1 0 0 0 0 +. 17186 0 1 0 1 0 1 0 0 0 0 0 0 0 0 +. 17185 0 1 0 0 0 0 0 1 0 1 0 0 0 0 +. 17218 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17219 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17345 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17346 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17359 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17360 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17361 0 1 1 1 0 0 0 0 0 0 0 1 0 0 +. 17362 0 1 0 0 0 0 0 0 1 1 0 0 1 0 +. 17363 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 17364 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +. 17365 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17366 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +. 17367 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17368 0 1 0 1 0 0 0 1 1 1 0 0 0 0 +./ 17212 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Gargish Set Archway +o 17213 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +./ 17214 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +\ 17215 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +./ 17216 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 17217 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +*\ 17220 0 1 0 0 0 1 0 0 0 0 0 0 1 0 Gargish Set Misc +*/ 17221 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +*/ 17222 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +*\ 17223 0 1 0 0 0 1 0 0 0 0 0 0 1 0 +\ 16723 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Two-Tone Stone Walls +./ 16722 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16725 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16724 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16737 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16736 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 16720 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16721 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +o 16733 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 16734 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +v 16730 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 16727 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Two-Tone Stone Arches +./ 16726 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16729 1 0 0 0 1 0 1 0 1 0 1 0 1 0 +./ 16728 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +./ 16746 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +\ 16747 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +v 16731 1 1 0 1 0 1 0 1 0 1 0 0 0 0 Two-Tone Quarter Walls +v 16732 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +\ 16742 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16743 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16745 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16744 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16739 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16738 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16719 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16718 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 16735 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 16713 0 1 0 0 0 1 0 0 0 0 0 0 1 0 Grey Stone Ruins +\ 16715 0 1 0 0 0 0 0 0 0 1 0 0 1 0 +./ 16714 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +./ 16712 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +\ 16741 0 1 0 0 0 1 0 0 0 0 0 0 1 0 +\ 16749 0 1 0 0 0 0 0 0 0 1 0 0 1 0 +./ 16748 0 1 0 1 0 0 0 0 0 0 0 1 0 0 +./ 16740 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +\ 16761 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Blue Marble Walls +./ 16760 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16763 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16762 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16757 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16758 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 16756 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +v 16759 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 16750 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16751 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16755 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Blue Marble Arches +./ 16754 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 16753 1 0 0 0 1 0 1 0 1 0 1 0 1 0 +./ 16752 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +v 16766 1 1 0 1 0 1 0 1 0 1 0 0 0 0 Blue Marble Half Walls +\ 16768 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16765 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16770 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16767 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16769 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16771 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 16770 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 16772 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 16773 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 16764 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 16660 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Gold Stone Walls +\ 16661 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 16662 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16664 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 16665 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 16666 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 16663 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +v 16675 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 16677 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 16676 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +. 16668 1 1 1 1 1 1 1 1 1 1 1 1 1 0 Stone Battlement +. 16667 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16669 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16670 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16672 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16671 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16673 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16674 1 1 1 1 1 1 1 1 1 1 1 1 1 0 +. 16678 0 1 1 1 0 1 0 0 0 1 0 0 0 0 Gold Stone Blocks +. 16679 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +./ 20733 1 1 1 1 1 1 1 1 0 0 1 1 0 0 Queen Palace Red/Marble Walls +./ 20734 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20735 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20736 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20737 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20738 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20741 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20742 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20743 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20744 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20745 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20746 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20747 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20748 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20749 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20750 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20751 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20740 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20752 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20753 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20754 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20755 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20756 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20757 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20759 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20760 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20761 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20762 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20763 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20764 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20765 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20766 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20767 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20768 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20769 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 20770 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20786 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 20787 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20788 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 20789 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20790 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20791 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 20792 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20793 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20794 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 20795 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 20796 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 20797 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20799 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 20801 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 20758 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 20775 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 20779 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 20798 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +o 20800 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +v 20739 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 20778 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 20780 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 20781 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 20771 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Queen Palace Marble Arches +./ 20772 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 20773 1 0 0 0 1 0 1 0 1 0 1 0 1 0 +./ 20774 1 0 1 0 1 0 1 0 0 0 1 1 0 0 +./ 20728 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +\ 20729 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +v 20701 1 1 0 1 0 1 0 1 0 1 0 0 0 0 Queen Palace Half Walls +o 20700 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +o 16799 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 20699 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 20698 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 20782 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 20783 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 20784 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 20785 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +*\ 20731 0 1 0 0 0 1 0 0 0 0 0 0 1 0 +*/ 20732 0 1 0 0 0 0 0 1 0 0 0 1 0 0 +\ 18117 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Ruined Stone Walls +\ 18133 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18134 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18135 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 18116 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18129 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18130 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +o 18136 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +v 18140 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 18138 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 18139 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18301 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18304 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18305 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18306 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18307 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18308 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 18310 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18313 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18314 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18315 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18316 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18317 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 18319 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 18310 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 18113 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Ruined Stone Half Walls +./ 18110 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 18111 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 18112 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 18114 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 18116 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 18115 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 18131 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 18132 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 18128 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 18118 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 18119 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 18120 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18121 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 18122 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 18123 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 18201 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18202 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18203 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18204 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 18205 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18206 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18207 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18208 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 18302 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18303 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18309 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 18311 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18312 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18318 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18408 1 1 0 0 1 1 1 1 0 0 1 1 1 1 Ruined Stone Arches +\ 18409 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 18401 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 18402 1 1 0 0 1 1 1 1 0 0 1 1 0 0 +./ 18403 1 0 1 0 0 0 1 0 0 0 1 1 0 0 +\ 18407 1 0 0 0 1 0 0 0 1 0 1 0 1 0 +\ 18601 1 1 0 0 0 1 0 1 0 1 0 0 1 0 Gargish Stone Heads +./ 18600 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 18604 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 18605 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 18602 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 18603 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 17318 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 17319 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +. 17320 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +./ 17321 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 17322 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +. 17323 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17324 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +\ 17325 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 17326 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +. 17327 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +./ 17336 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 17337 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 17338 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 17339 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 17340 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 17341 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 17342 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 17343 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 17369 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 17370 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +. 17278 0 1 1 1 0 1 0 0 0 1 0 0 0 0 Gargish Canal +. 17282 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17286 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17290 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17294 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17298 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17302 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17306 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17310 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +. 17314 0 1 1 1 0 1 0 0 0 1 0 0 0 0 +\ 16539 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Carved Green Door +\ 16541 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 16543 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 16545 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 16652 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Brown Door +\ 16654 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 16656 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 16658 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 16834 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Sun Door +\ 16836 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 16838 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 16840 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 16847 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Grey Door +\ 16849 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 16851 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 16853 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 17262 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Set Door +\ 17264 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 17266 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 17268 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 17270 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 17272 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 17274 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 17276 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 18141 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Ruined Door +\ 18143 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 18145 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 18147 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 19746 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Blue Door +\ 19748 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 19750 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 19752 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 20680 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Red Doors +\ 20682 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 20684 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 20686 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 20688 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +\ 20690 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 20692 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 20694 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 20802 0 1 0 0 0 0 0 0 0 0 0 0 1 0 Gargish Prison Door +\ 20804 0 1 0 0 0 0 0 0 0 0 0 0 1 0 +./ 20806 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +./ 20808 0 1 0 0 0 0 0 0 0 0 0 1 0 0 +\ 19189 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Gothic Walls +\ 19190 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19191 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19192 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19193 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 19194 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 19195 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19196 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19197 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19198 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19199 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 19200 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 19206 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 19207 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +v 19208 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +v 19209 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +o 19210 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 19211 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +v 19212 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 19213 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +o 19214 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +. 19215 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +\ 19243 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +o 19244 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +./ 19245 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 19246 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 19247 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 19248 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 19249 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19253 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 19254 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +o 19255 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +./ 19256 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +./ 19257 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +o 19258 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 19259 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 19260 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +v 19261 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +\ 30694 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Board and Batten Walls +./ 30725 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 30726 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 30703 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 30705 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 30706 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 30697 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 30723 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +\ 30724 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 30704 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 30708 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 30709 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +v 30700 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +v 30707 1 1 1 1 1 1 1 1 1 1 1 0 0 0 +o 30710 1 1 0 0 1 1 1 1 0 0 1 1 1 1 +\ 30695 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 30698 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +v 30701 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +o 30711 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +\ 30696 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +./ 30699 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +v 30702 1 1 0 1 0 1 0 1 0 1 0 0 0 0 +o 30712 1 1 0 0 0 1 0 1 0 0 0 1 1 1 +. 30713 1 1 0 0 0 0 0 0 0 0 1 0 0 0 +. 30714 0 1 0 0 0 0 0 0 0 0 0 0 0 0 +./ 30736 1 1 0 1 0 1 0 1 0 0 0 1 0 0 +\ 30737 1 1 0 0 0 1 0 1 0 1 0 0 1 0 +\ 19216 1 1 0 0 1 1 1 1 1 1 1 0 1 0 Gothic Rose +\ 19217 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19218 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19219 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19220 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +\ 19221 1 1 0 0 1 1 1 1 1 1 1 0 1 0 +./ 19222 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19223 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19224 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19225 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19226 1 1 1 1 1 1 1 1 0 0 1 1 0 0 +./ 19227 1 1 1 1 1 1 1 1 0 0 1 1 0 0 diff --git a/Data/Components/teleprts.txt b/Data/Components/teleprts.txt new file mode 100644 index 0000000..599f6cd --- /dev/null +++ b/Data/Components/teleprts.txt @@ -0,0 +1,3 @@ +int int int int int int int int int int int int int int int int int int string +Category F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 FeatureMask Comment +0 0 6173 6174 6175 6176 6177 6178 0 0 6179 6180 6181 6182 6183 6184 0 0 Alchemical Tiles diff --git a/Data/Components/walls.txt b/Data/Components/walls.txt new file mode 100644 index 0000000..5df62bf --- /dev/null +++ b/Data/Components/walls.txt @@ -0,0 +1,173 @@ +int int int int int int int int int int int int int int int int int int string +Category Style TID South1 South2 South3 Corner East1 East2 East3 Post WindowS AltWindowS WindowE AltWindowE SecondAltWindowS SecondAltWindowE FeatureMask Comment +0 0 1060054 10 7 12 6 13 8 11 9 0 14 15 0 0 0 0 Dark Wood Standard Walls +0 1 0 18 18 18 16 17 17 17 19 0 0 0 0 0 0 0 Dark Wood Half Walls +0 2 0 22 22 22 20 21 21 21 23 0 0 0 0 0 0 0 Dark Wood Quarter Walls +1 0 1060055 171 168 173 166 172 167 170 169 186 9472 9479 9478 9473 185 0 Light Wood Standard Walls +1 1 0 178 175 181 174 180 176 179 177 0 188 187 0 0 0 0 Light Wood Alternative Walls +1 2 0 948 948 948 947 949 949 949 950 0 0 0 0 0 0 0 Light Wood Half Walls +1 3 0 191 191 191 189 190 190 190 192 0 0 0 0 0 0 0 Light Wood Quarter Walls +2 0 1060056 30 28 33 26 32 27 31 29 10670 34 35 10675 0 0 0 Fieldstone Standard Walls +2 1 0 10668 10669 10671 10672 10677 10676 10674 10673 0 0 0 0 0 0 64 Fieldstone Stained Glass Walls +2 2 0 37 37 37 36 38 38 38 39 0 0 0 0 0 0 0 Fieldstone Half Walls +3 0 1060057 464 464 464 463 465 465 465 466 0 467 468 0 0 0 0 Weathered Stone Standard Walls +3 1 0 10660 10661 10662 10663 10667 10666 10665 10664 0 0 0 0 0 0 64 Weathered Stone Stained Glass +3 2 0 489 489 489 488 490 490 490 491 0 0 0 0 0 0 0 Weathered Stone Roof Edging +3 3 0 200 200 200 199 201 201 201 204 0 202 203 0 0 0 0 Granite Standard Walls +3 4 0 222 222 222 220 221 221 221 223 0 0 0 0 0 0 0 Granite Roof Edging +4 0 1060058 55 52 57 51 58 53 56 54 10681 59 60 10686 0 0 0 Grey Brick Standard Walls +4 1 0 10678 10679 10680 10682 10687 10685 10684 10683 0 0 0 0 0 0 64 Grey Brick Stained Glass +4 2 0 62 62 62 61 63 63 63 64 0 0 0 0 0 0 0 Grey Brick Half Walls +4 3 0 66 66 66 65 67 67 67 68 0 0 0 0 0 0 0 Grey Brick Quarter Walls +5 0 1060059 88 88 88 89 87 87 87 90 92 94 93 91 0 0 0 Light Brick Standard Walls +5 1 0 0 10656 10657 0 10659 10658 0 0 0 0 0 0 0 0 64 Light Brick Stained Glass Walls +5 2 0 95 95 95 97 96 96 96 98 0 0 0 0 0 0 0 Light Brick Half Walls +5 3 0 99 99 99 101 100 100 100 102 0 0 0 0 0 0 0 Light Brick Quarter Walls +5 4 0 105 105 105 107 106 106 106 108 0 0 0 0 0 0 0 Light Brick Roof Edging +6 0 1060060 444 444 440 438 439 445 445 441 0 452 453 0 0 0 0 Hide Standard Walls +6 1 0 446 450 448 0 449 451 447 441 0 454 455 0 0 0 0 Hide Alternative Walls +6 2 0 427 422 423 421 426 425 428 424 429 430 432 431 0 0 0 Woven Standard Walls +6 3 0 8539 8539 8539 8540 8538 8538 8538 419 0 0 0 0 0 0 0 Woven Short Walls +7 0 1060061 149 146 151 144 150 145 148 147 152 9460 9467 9466 9461 153 0 Log Standard Walls +7 1 0 159 156 161 154 160 155 158 157 0 0 0 0 0 0 0 Log Half Walls +8 0 1060062 552 552 552 550 551 551 551 553 0 0 0 0 0 0 0 Palisades Standard Walls +8 1 0 1072 1058 546 547 1057 545 545 553 0 0 0 0 0 0 0 Palisades Alternative Walls +8 2 0 1059 1059 1059 1061 1060 1060 1060 0 0 0 0 0 0 0 0 Palisades Roof Edging +9 0 1060063 249 249 249 248 250 250 250 251 252 9484 9491 9490 9485 253 0 Tan Marble Fancy Walls +9 1 0 255 255 255 254 256 256 256 257 258 9496 9503 9502 9497 259 0 Tan Marble Medium Walls +9 2 0 261 261 261 260 262 262 262 263 264 9508 9515 9514 9509 265 0 Tan Marble Plain Walls +9 3 0 267 267 267 266 268 268 268 269 0 0 0 0 0 0 0 Tan Marble Half Walls +9 4 0 271 271 271 270 272 272 272 273 0 0 0 0 0 0 0 Tan Marble Fancy Roof Edging +9 5 0 1091 1091 1091 1090 1092 1092 1092 1093 0 0 0 0 0 0 0 Tan Marble Medium Roof Edging +9 6 0 280 280 280 279 281 281 281 282 0 0 0 0 0 0 0 Tan Marble Plain Roof Edging +10 0 1060064 670 670 670 669 671 671 671 672 0 686 685 0 0 0 0 White Marble Fancy Walls +10 1 0 664 664 664 663 665 665 665 666 0 667 668 0 0 0 0 White Marble Medium Walls +10 2 0 658 658 658 657 659 659 659 660 661 9532 9941 9940 9533 662 0 White Marble Plain Walls +10 3 0 674 674 674 673 675 675 675 676 0 0 0 0 0 0 0 White Marble Half Walls +10 4 0 698 698 698 697 699 699 699 700 0 0 0 0 0 0 0 White Marble Fancy Roof Edging +10 5 0 1105 1105 1105 1104 1106 1106 1106 1107 0 0 0 0 0 0 0 White Marble Medium Roof Edging +10 6 0 694 694 694 693 695 695 695 696 0 0 0 0 0 0 0 White Marble Plain Roof Edging\ +11 0 1060065 345 345 345 344 346 346 346 347 0 348 349 0 0 0 0 Sandstone Brick Fancy Walls +11 1 0 352 352 352 350 351 351 351 353 0 355 354 0 0 0 0 Sandstone Brick Plain Walls +11 2 0 357 357 357 356 358 358 358 359 0 0 0 0 0 0 0 Sandstone Brick Fancy Half Walls +11 3 0 362 362 362 360 361 361 361 363 0 0 0 0 0 0 0 Sandstone Brick Plain Half Walls +11 4 0 517 515 512 511 513 516 518 514 519 9519 9527 9526 9520 522 0 Sandstone and Plaster Standard Walls +12 0 1060066 598 598 598 597 599 599 599 601 0 0 0 0 0 0 0 Flat Stone Medium Walls +12 1 0 592 592 592 591 593 593 593 600 0 0 0 0 0 0 0 Flat Stone Plain Walls +12 2 0 595 595 595 594 596 596 596 602 0 0 0 0 0 0 0 Flat Stone Open Walls +12 3 0 589 589 589 588 590 590 590 603 0 0 0 0 0 0 0 Flat Stone Fancy Walls +13 0 1060067 968 968 968 967 969 969 969 970 0 990 991 0 0 0 0 Sandstone and Mortar Dark Walls +13 1 0 972 972 972 971 973 973 973 974 0 0 0 0 0 0 0 Sandstone and Mortar Light Walls +13 2 0 983 980 993 979 994 981 984 982 0 0 0 0 0 0 0 Sandstone and Mortar Multi Walls +13 3 0 983 980 993 992 994 981 984 982 0 0 0 0 0 0 0 Sandstone and Mortar Multi Walls +13 4 0 960 960 960 958 961 961 961 962 0 0 0 0 0 0 0 Sandstone and Mortar Multi Walls +13 5 0 976 976 976 975 977 977 977 978 0 0 0 0 0 0 0 Sandstone and Mortar Multi Walls +14 0 1060068 312 310 307 309 308 311 313 298 0 314 315 0 0 0 0 Wood and Plaster Plain Walls +14 1 0 312 310 307 306 308 311 313 298 0 0 0 0 0 0 0 Wood and Plaster Wood Trim Walls +14 2 0 302 310 296 295 297 311 303 298 0 0 0 0 0 0 0 Wood and Plaster Diagonal Beams 1 +14 3 0 304 310 300 299 301 311 305 298 0 0 0 0 0 0 0 Wood and Plaster Diagonal Beams 2 +14 4 0 336 336 336 332 334 334 334 298 0 342 343 0 0 0 0 Wood and Plaster Fancy Walls +14 5 0 338 338 338 335 339 339 339 298 0 340 341 0 0 0 0 Wood and Plaster Medium Walls +15 0 1060069 910 910 910 909 911 911 911 898 0 0 0 0 0 0 0 Damaged Plaster Plain Walls +15 1 0 912 915 907 914 908 916 913 898 0 0 0 0 0 0 0 Damaged Plaster Damaged Walls +15 2 0 912 915 907 906 908 916 913 898 0 0 0 0 0 0 0 Damaged Plaster Wood Trim Walls +15 3 0 902 915 896 895 897 916 903 898 0 0 0 0 0 0 0 Damaged Plaster Diagonal Beams 1 +15 4 0 904 915 900 899 901 916 905 898 0 0 0 0 0 0 0 Damaged Plaster Diagonal Beams 2 +16 0 1063365 9351 9351 9351 9349 9350 9350 9350 9354 0 0 0 0 0 0 64 Laquered Panel Standard Walls +16 1 0 9348 9348 9348 9346 9347 9347 9347 9353 0 0 0 0 0 0 64 Lacquered Panel Half Walls +16 2 0 9345 9345 9345 9343 9344 9344 9344 9352 0 0 0 0 0 0 64 Lacquered Panel Quarter Walls +17 0 1063366 10650 10650 10650 10653 10647 10647 10647 10644 0 0 0 0 0 0 64 Wood Panel Standard Walls +17 1 0 10649 10649 10649 10652 10646 10646 10646 10643 0 0 0 0 0 0 64 Wood Panel Half Walls +17 2 0 10648 10648 10648 10651 10645 10645 10645 10642 0 0 0 0 0 0 64 Wood Panel Quarter Walls +18 0 1063367 10015 10015 10015 10005 10012 10012 10012 10076 0 0 0 0 0 0 64 Paper Standard Walls +18 1 0 10014 10014 10014 10004 10011 10011 10011 10075 0 0 0 0 0 0 64 Paper Half Walls +18 2 0 10013 10013 10013 10003 10010 10010 10010 10074 0 0 0 0 0 0 64 Paper Quarter Walls +19 0 1063368 10082 10082 10082 10069 10079 10079 10079 10076 0 0 0 0 0 0 64 Lattice Standard Walls +19 1 0 10081 10081 10081 10068 10078 10078 10078 10075 0 0 0 0 0 0 64 Lattice Half Walls +19 2 0 10080 10080 10080 10067 10077 10077 10077 10074 0 0 0 0 0 0 64 Lattice Quarter Walls +20 0 1063369 10560 10560 10560 10554 10557 10557 10557 10563 0 0 0 0 0 0 64 Clay Standard Walls +20 1 0 10559 10559 10559 10553 10556 10556 10556 10562 0 0 0 0 0 0 64 Clay Half Walls +20 2 0 10558 10558 10558 10552 10555 10555 10555 10561 0 0 0 0 0 0 64 Clay Quarter Walls +21 0 1063370 10575 10575 10575 10566 10569 10569 10569 10572 0 0 0 0 0 0 64 Weathered Clay Standard Walls +21 1 0 10574 10574 10574 10565 10568 10568 10568 10571 0 0 0 0 0 0 64 Weathered Clay Half Walls +21 2 0 10573 10573 10573 10564 10567 10567 10567 10570 0 0 0 0 0 0 64 Weathered Clay Quarter Walls +22 0 1063371 10581 10581 10581 10584 10578 10578 10578 10587 0 0 0 0 0 0 64 Limestone Standard Walls +22 1 0 10580 10580 10580 10583 10577 10577 10577 10586 0 0 0 0 0 0 64 Limestone Half Walls +22 2 0 10579 10579 10579 10582 10576 10576 10576 10585 0 0 0 0 0 0 64 Limestone Quarter Walls +23 0 1063372 10745 10743 10740 10742 10741 10744 10746 10731 0 10747 10748 0 0 0 64 Dark Plaster Standard Walls +23 1 0 10745 10743 10740 10739 10741 10744 10746 10731 0 10747 10748 0 0 0 64 Dark Plaster Standard Walls 2 +23 2 0 10735 10729 10729 10728 10730 10736 10736 10731 0 0 0 0 0 0 64 Dark Plaster Standard Walls 3 +23 3 0 10737 10733 10733 10732 10734 10738 10738 10731 0 0 0 0 0 0 64 Dark Plaster Standard Walls 4 +23 4 0 0 10726 10722 10721 10723 10727 0 10724 0 0 0 0 0 0 64 Dark Plaster Standard Quarter Walls +24 0 1063373 9367 9367 9367 9365 9366 9366 9366 9368 0 0 0 0 0 0 64 Cherrywood Standard Walls +24 1 0 9363 9363 9363 9361 9362 9362 9362 9364 0 0 0 0 0 0 64 Cherrywood Half Walls +24 2 0 9359 9359 9359 9357 9358 9358 9358 9360 0 0 0 0 0 0 64 Cherrywood Quarter Walls +25 0 1063374 9373 9378 9373 10800 9374 9377 9374 10806 0 0 0 0 0 0 64 Plaster Standard Walls - Light +25 1 0 9373 9384 9373 10803 9374 9383 9374 10809 0 0 0 0 0 0 64 Plaster Standard Walls - Dark +25 2 0 9371 9380 9371 10801 9372 9379 9372 10807 0 0 0 0 0 0 64 Plaster Half Walls - Light +25 3 0 9371 9386 9371 10804 9372 9385 9372 10810 0 0 0 0 0 0 64 Plaster Half Walls - Dark +25 4 0 9382 9382 9376 10802 9375 9381 9381 10808 0 0 0 0 0 0 64 Plaster Quarter Walls +26 0 1074416 11132 11132 11132 11717 11131 11131 11131 11720 0 0 0 0 0 0 128 light Plaster Elf Wall 1 +26 1 0 11133 11133 11136 11136 11134 11135 11135 11720 0 0 0 0 0 0 128 light Plaster Elf Wall 1 +26 2 0 11130 11130 11130 11716 11729 11729 11729 11719 0 0 0 0 0 0 128 light Plaster Elf Wall 1 +26 3 0 11728 11728 11728 11715 11727 11727 11727 11718 0 0 0 0 0 0 128 light Plaster Elf Wall 1 +27 0 1074417 11198 11198 11198 11183 11197 11197 11197 11186 0 0 0 0 0 0 128 Dark Plaster Elf Wall 2 +27 1 0 11200 11200 11202 11202 11201 11201 11199 11199 0 0 0 0 0 0 128 Dark Plaster Elf Wall 2 +27 2 0 11196 11196 11196 11182 11195 11195 11195 11185 0 0 0 0 0 0 128 Dark Plaster Elf Wall 2 +27 3 0 11194 11194 11194 11181 11193 11193 11193 11184 0 0 0 0 0 0 128 Dark Plaster Elf Wall 2 +28 0 1074418 11508 11508 11508 11211 11507 11507 11507 11212 0 0 0 0 0 0 128 Plaster Elf Wall 3 +28 1 0 11510 11510 11512 11512 11511 11511 11509 11509 0 0 0 0 0 0 128 Plaster Elf Wall 3 +28 2 0 11506 11506 11506 11209 11505 11505 11505 11210 0 0 0 0 0 0 128 Plaster Elf Wall 3 +28 3 0 11504 11504 11504 11207 11503 11503 11503 11208 0 0 0 0 0 0 128 Plaster Elf Wall 3 +29 0 1074419 11585 11585 11585 11546 11584 11584 11584 11549 0 0 0 0 0 0 128 Carved Wood 1 +29 1 0 11587 11587 11589 11589 11588 11588 11586 11586 0 0 0 0 0 0 128 Carved Wood 1 +29 2 0 11583 11583 11583 11545 11582 11582 11582 11548 0 0 0 0 0 0 128 Carved Wood 1 +29 3 0 11581 11581 11581 11544 11580 11580 11580 11547 0 0 0 0 0 0 128 Carved Wood 1 +30 0 1076720 13795 13796 13796 13785 13794 13794 13793 13788 13798 13798 13797 13797 0 0 512 Crystal Walls 1 +30 1 0 13792 13792 13792 13784 13791 13791 13791 13787 0 0 0 0 0 0 512 Crystal Walls 2 +30 2 0 13790 13790 13790 13783 13789 13789 13789 13786 0 0 0 0 0 0 512 Crystal Walls 3 +31 0 1076721 13883 13897 13895 13846 13896 13898 13882 13849 13885 13885 13884 13884 0 0 512 Shadow Walls 1 +31 1 0 13881 13881 13881 13845 13880 13880 13880 13848 0 0 0 0 0 0 512 Shadow Walls 2 +31 2 0 13879 13879 13879 13844 13878 13878 13878 13847 0 0 0 0 0 0 512 Shadow Walls 3 +31 3 0 0 0 0 13843 0 0 0 0 0 0 0 0 0 0 512 Shadow Walls 3 +32 0 1112080 17229 17228 17226 17190 17227 17224 17225 17191 0 0 0 0 0 0 65536 Gargish Wall Set 1 +32 1 0 17354 17355 17358 17356 17357 0 0 0 0 0 0 0 0 0 65536 Gargish Wall Set 1 +33 0 1112080 17230 17231 17178 17180 17232 17233 17183 17181 0 0 0 0 0 0 65536 Gargish Wall Set 2 +33 1 0 17182 17179 0 0 0 0 0 0 0 0 0 0 0 0 65536 Gargish Wall Set 2 +34 0 1112080 17240 17237 17239 17238 17241 17236 0 0 0 0 0 0 0 0 65536 Gargish Windows 3 +35 0 1112082 16790 16791 16805 16785 16784 16786 16787 16796 16788 16789 0 0 0 0 65536 Gargish Green Marble 1 +35 1 0 16797 16799 16806 16807 16808 16792 16793 16794 0 0 0 0 0 0 65536 Gargish Green Marble 2 +35 2 0 16795 16798 0 0 0 0 0 0 0 0 0 0 0 0 65536 Gargish Green Marble 3 +36 0 1112083 16720 16721 16724 16725 16730 16722 16723 16733 16736 16737 0 0 0 0 65536 Gargish Two-Tone Stone Walls +36 1 0 16731 16738 16739 16734 16718 16719 16732 16735 0 0 0 0 0 0 65536 Gargish Two-tone Stone Half Walls +36 2 0 16742 16743 16744 16745 0 0 0 0 0 0 0 0 0 0 65536 Gargish Two-tone Stone Half Walls +37 0 1112084 16664 16665 16666 16675 16660 16661 16662 16663 0 0 0 0 0 0 65536 Gargish Gold Stone Walls 1 +37 1 0 16676 16677 16678 16679 0 0 0 0 0 0 0 0 0 0 65536 Gargish Gold Stone Walls 2 +38 0 1112086 20787 20786 20800 20781 20795 20796 20782 20783 20799 20801 20754 20735 0 0 65536 Gargish Red Marble Walls 1 +38 1 0 20734 20738 20753 20757 20736 20737 20755 20756 0 0 0 0 0 0 65536 Gargish Red Marble Walls 2 +38 2 0 20741 20742 20743 20744 20745 20746 20739 20758 0 0 0 0 0 0 65536 Gargish Red Marble Walls 3 +38 3 0 0 20733 20747 20748 20749 20750 20752 0 0 0 0 0 0 0 65536 Gargish Red Marble Walls 4 +38 4 0 20760 20761 20762 20763 20764 20765 20766 20767 0 0 0 0 0 0 65536 Gargish Red Marble Walls 5 +38 5 0 20768 20769 0 0 0 0 0 0 0 0 0 0 0 0 65536 Gargish Red Marble Walls 6 +39 0 1112085 20751 20759 20778 20775 20794 20797 20798 20784 0 0 0 0 0 0 65536 Gargish Marble Walls 1 +39 1 0 20785 20698 20699 20700 20701 20791 20792 20793 0 0 0 0 0 0 65536 Gargish Marble Walls 2 +39 2 0 20788 20789 20790 20780 20779 0 0 0 0 0 0 0 0 0 65536 Gargish Marble Tiles 2 +40 0 1112087 18139 18138 18136 18140 18304 18305 18306 18307 0 0 0 0 0 0 65536 Gargish Ruined Walls 1 +40 1 0 18308 18310 18313 18314 18315 18316 18317 18318 0 0 0 0 0 0 65536 Gargish Ruined Walls 2 +40 2 0 18309 18311 18312 18302 18303 18201 18202 18204 0 0 0 0 0 0 65536 Gargish Ruined Walls 3 +40 3 0 18205 18206 18207 18208 0 18129 18130 18131 0 0 0 0 0 0 65536 Gargish Ruined Walls 4 +40 4 0 18132 18133 18134 18135 18110 18111 18112 18113 0 0 0 0 0 0 65536 Gargish Ruined Walls 4 +40 5 0 18114 18115 18116 18117 18118 18122 18123 18120 0 0 0 0 0 0 65536 Gargish Ruined Walls 4 +41 0 1112088 16761 16760 16759 16756 16763 16762 16765 16766 16757 16758 0 0 0 0 65536 Gargish Blue Marble Walls +41 1 0 16764 16767 16768 16769 16770 16771 16772 16773 0 0 0 0 0 0 65536 Gargish Blue Marble Half Walls +41 2 0 16751 16750 16748 16749 0 0 0 0 0 0 0 0 0 0 65536 Gargish Blue Marble Half Walls 2 +42 0 1112080 17184 17349 17350 17347 17348 17351 17352 17353 0 0 0 0 0 0 65536 Gargish Wall Set 3 +43 0 1150629 19246 19189 19190 19213 19196 19195 19247 19214 0 19191 19197 0 0 0 262144 Gothic Walls 1 +43 1 0 19255 19254 19193 19209 19199 19253 19211 19210 0 0 0 0 0 0 262144 Gothic Walls 2 +43 2 0 19259 19257 19194 19208 19200 19260 19256 19206 0 0 0 0 0 0 262144 Gothic Walls 3 +43 3 0 0 19258 19243 19212 19245 0 19215 19244 0 0 0 0 0 0 262144 Gothic Walls 4 +43 4 0 0 19216 19217 19218 19219 19220 19221 0 0 0 0 0 0 0 262144 Rose Window 1 +43 5 0 0 19222 19223 19224 19225 19226 19227 0 0 0 0 0 0 0 262144 Rose Window 2 +44 0 1150630 0 30694 30724 30700 30723 30697 0 30710 0 30703 30704 0 0 0 524288 Board and Batten Walls 1 +44 1 0 0 30695 30726 30701 30725 30698 0 30711 0 0 0 0 0 0 524288 Board and Batten Walls 2 +44 2 0 0 30696 30737 30702 30736 30699 0 30712 0 0 0 0 0 0 524288 Board and Batten Walls 3 diff --git a/Data/Data.csproj b/Data/Data.csproj new file mode 100644 index 0000000..9d4560f --- /dev/null +++ b/Data/Data.csproj @@ -0,0 +1,417 @@ + + + + + Debug + AnyCPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D} + Exe + Properties + Data + Data + v4.5 + 512 + SAK + SAK + SAK + SAK + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Decoration/Britannia/NERUN-BritainSewers.cfg b/Data/Decoration/Britannia/NERUN-BritainSewers.cfg new file mode 100644 index 0000000..0149026 --- /dev/null +++ b/Data/Decoration/Britannia/NERUN-BritainSewers.cfg @@ -0,0 +1,49 @@ +# +# BRITAIN SEWERS +# + +# rock stairs +Static 0x07A7 +6082 1450 5 +6082 1449 5 + +# rock stairs +Static 0x07A5 +6084 1449 5 +6084 1450 5 + +# rock stairs +Static 0x07AA +6084 1448 5 + +# rock stairs +Static 0x07A6 +6084 1447 0 + +# Post +Static 0x1296 +6049 1430 5 + +# Sign +Static 0x129C +6049 1430 20 + +Lever 0x1095 (Name=lever) +6037 1435 8 + +Lever 0x108D (Name=lever) +6057 1442 4 +6048 1433 4 + +Lever 0x108E (Name=lever) +6057 1441 4 +6048 1432 4 + +Lever 0x1094 (Name=lever) +6049 1431 4 + +Lever 0x108F (Name=switch) +6036 1440 15 + +Lever 0x1090 (Name=switch) +6036 1439 15 \ No newline at end of file diff --git a/Data/Decoration/Britannia/NERUN-SeaMarket.cfg b/Data/Decoration/Britannia/NERUN-SeaMarket.cfg new file mode 100644 index 0000000..170b40f --- /dev/null +++ b/Data/Decoration/Britannia/NERUN-SeaMarket.cfg @@ -0,0 +1,152 @@ +# Saved By Static Exporter +# StaticExport by Nerun +# Version 2.1 + +BulletinBoard 0x1E5E +4544 2298 -1 +4539 2316 -1 + +Static 0x0DBA +4533 2400 -5 +4574 2350 -5 +4574 2329 -5 +4531 2333 -2 +4532 2384 -5 +4573 2379 0 +4575 2407 -5 +4575 2408 -5 +4545 2369 -5 +4528 2367 -5 +4574 2311 -1 +4575 2349 -5 +4559 2354 -5 +4556 2400 -5 +4573 2303 -2 +4538 2385 -5 +4574 2351 -5 +4531 2400 -5 +4529 2400 -5 +4547 2400 -5 +4529 2395 -5 +4531 2333 -2 +4540 2349 -2 + +Spyglass 0x14F6 +4546 2331 2 + +Static 0x10EF +4550 2336 -2 + +Static 0x0DBB +4574 2330 -5 +4575 2351 -5 +4529 2348 -5 +4529 2367 -5 +4531 2401 -5 +4556 2401 -5 +4536 2368 -5 +4574 2404 -5 +4529 2366 -5 +4532 2400 -5 +4558 2353 -5 +4568 2408 -5 +4573 2337 -5 +4559 2353 -5 +4574 2408 -5 +4574 2380 -5 +4574 2296 -5 + +Static 0x1BD6 +4552 2323 4 + +Static 0x14ED +4538 2328 2 +4552 2324 4 + +Static 0x1F28 (Name=Please Put Your Garbage In Here. Thank You!) +4546 2314 3 + +Static 0x14F4 +4539 2328 2 + +Static 0x0A93 +4552 2322 4 + +Static 0x14EE +4552 2324 4 + +Static 0x1DB7 +4540 2329 -2 +4540 2329 -2 + +Static 0x1EA6 +4543 2324 -2 + +Static 0x14F8 +4544 2315 -2 + +Static 0x0DD6 +4559 2333 -2 + +Static 0x0A6C +4552 2322 5 + +Static 0x154D +4541 2326 4 +4540 2326 4 + +Static 0x10F1 +4543 2324 -2 + +Anvil 0x0FAF +4567 2327 -2 + +Static 0x1E2B +4543 2326 -2 +4543 2316 -2 + +Static 0x0DD7 +4531 2350 -2 + +Forge 0x0FB1 +4568 2327 -2 + +TrashBarrel 0x0E77 (Hue=946) +4546 2314 -2 + +Static 0x44CA +4552 2303 -2 + +Static 0x3063 +4537 2324 3 + +Static 0x0BD1 (Name=Winds Tavern) +4548 2300 -6 + +FullBookcase 0x0A97 +4537 2316 -1 + +Static 0x0BCF (Name=General Store) +4543 2317 -2 + +Static 0xE83 +4537 2320 -1 + +Static 0x14F7 +4537 2319 7 +4537 2320 7 + +BarrelHoops 0x1DB7 +4540 2329 -2 + +Static 0x3062 +4537 2325 3 + +Static 0x0A15 +4568 2400 15 + +FishingPole 0x0DC0 +4544 2324 -2 + +Static 0x14EC +4552 2318 2 \ No newline at end of file diff --git a/Data/Decoration/Britannia/_covetous.cfg b/Data/Decoration/Britannia/_covetous.cfg new file mode 100644 index 0000000..5d52ec1 --- /dev/null +++ b/Data/Decoration/Britannia/_covetous.cfg @@ -0,0 +1,927 @@ +# switch +Static 0x108F +5552 1864 11 +5399 1875 17 +5435 1875 12 + +# stone stairs +Static 0x07A4 +5553 1807 0 +5558 1826 -12 +5558 1825 -5 +5551 1807 0 +5552 1807 0 +5556 1826 -12 +5552 1804 15 +5556 1825 -5 +5557 1825 -5 +5557 1826 -12 +5557 1828 -22 + +# cot +Static 0x11FD +5554 1889 0 +5554 1891 0 +5554 1895 0 +5554 1897 0 +5554 1899 0 +5554 1903 0 +5602 1889 0 +5602 1907 0 +5554 1907 0 +5602 1911 0 +5602 1915 0 +5554 1905 0 +5554 1911 0 +5554 1913 0 +5554 1915 0 +5602 1891 0 +5602 1895 0 +5602 1897 0 +5602 1899 0 +5602 1903 0 +5602 1905 0 +5602 1913 0 + +# metal door +MetalDoor2 0x06CF (Facing=NorthCCW) +5567 1829 0 +5581 1877 0 +5567 1863 0 +5563 1877 0 +5577 1877 0 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +5567 1830 0 +5563 1841 0 +5619 1859 0 +5559 1843 0 +5581 1878 0 +5551 1881 0 +5511 1809 0 +5577 1878 0 +5567 1864 0 +5559 1912 0 +5559 1905 0 +5559 1890 0 +5559 1876 0 +5559 1867 0 +5559 1859 0 +5559 1851 0 +5563 1903 0 +5563 1878 0 +5543 1881 0 +5559 1897 0 + +# floor spikes +SpikeTrap 0x11A0 +5410 1875 0 +5483 1913 0 +5409 1877 0 +5485 1911 0 +5492 2030 0 + +# barrel +Barrel 0x0E77 +5608 1832 10 +5610 1835 5 +5459 1968 0 +5610 1834 10 +5464 1809 0 +5610 1834 0 +5611 1835 0 +5609 1832 5 +5621 1844 5 +5464 1809 5 +5620 1846 15 +5620 1844 10 +5620 1845 5 +5621 1846 0 +5608 1833 5 +5608 1838 10 +5608 1838 5 +5620 1844 5 +5620 1846 10 +5608 1832 5 +5608 1833 0 +5610 1834 5 +5611 1834 5 +5464 1810 0 +5622 1845 0 +5622 1845 5 +5621 1845 0 +5620 1845 0 +5464 1810 10 +5621 1845 5 +5611 1834 0 +5620 1846 0 +5620 1846 5 +5464 1809 10 +5465 1809 0 +5465 1809 5 +5465 1810 0 +5608 1840 5 +5609 1838 0 +5465 1810 5 +5456 2003 0 +5620 1844 0 +5621 1844 0 +5609 1838 5 +5621 1844 10 +5464 1810 5 +5608 1832 0 +5608 1838 0 +5608 1839 0 +5608 1839 10 +5608 1839 5 +5608 1840 0 +5609 1832 0 +5609 1839 0 +5610 1835 0 +5621 1846 5 + +# crate +LargeCrate 0x0E3C +5418 1863 6 +5489 2009 0 +5489 2008 0 +5417 1868 0 +5384 1912 0 // spawning +5489 2008 3 +5418 1863 3 +5416 1866 0 +5417 1864 0 +5418 1863 0 +5418 1864 0 +5574 2000 0 // spawning +5417 1864 3 + +# metal door +MetalDoor2 0x06C5 (Facing=WestCW) +5589 1851 0 +5579 1871 0 +5569 1835 0 +5617 1871 0 +5617 1847 0 +5579 1887 0 +5603 1867 0 +5603 1871 0 +2545 853 0 + +# metal door +MetalDoor2 0x06C7 (Facing=EastCCW) +5580 1871 0 +5590 1851 0 +5618 1871 0 +5618 1847 0 +5580 1887 0 +2546 853 0 + +# scimitar +Static 0x13B5 (Hue=0x4F4) +5570 1906 0 + +# bookcase +FullBookcase 0x0A9B +5576 1824 0 +5584 1824 0 + +# flowstone +Static 0x08E3 +5445 1824 -5 +5444 1817 -5 +5438 1798 -5 +5441 1803 -5 +5442 1802 -5 + +# mushroom +Static 0x0D16 +5581 2011 0 +5493 2009 0 +5595 2009 0 +5494 2030 0 +5501 2025 0 +5508 2028 0 +5512 1998 0 +5509 2009 0 +5466 1879 0 +5604 2001 0 +5403 1902 0 +5405 1911 0 +5411 1901 0 +5507 1991 0 +5494 2003 0 +5500 2005 0 +5549 2029 0 +5571 2028 0 +5581 2026 0 +5595 2016 0 +5471 1928 0 +5472 1927 0 +5472 1927 5 +5473 1927 4 +5543 2036 0 +5585 2015 0 +5589 2011 0 + +# metal door +MetalDoor2 0x06D3 (Facing=NorthCW) +5611 1877 0 +5615 1877 0 +5595 1877 0 +5591 1903 0 +5563 1863 0 + +# wooden chest +WoodenChest 0x0E42 +5489 2011 0 // spawning +5461 1968 0 // spawning +5456 1810 0 // spawning +5453 2024 0 // spawning +5456 1978 0 // spawning +5507 1991 0 // spawning +5501 2004 0 // spawning +5403 1863 0 // spawning + +# crate +MediumCrate 0x0E3F +5613 1840 0 +5613 1840 6 +5613 1839 0 +5613 1839 3 +5613 1840 3 +5455 1891 0 // spawning +5613 1840 9 +5613 1839 6 + +# tray +Static 0x0992 +5620 1881 6 + +# crate +LargeCrate 0x0E3D +5618 1832 3 +5619 1840 3 +5618 1840 9 +5618 1839 9 +5616 1832 0 +5618 1832 0 +5618 1839 3 +5617 1833 3 +5617 1834 0 +5618 1840 3 +5576 2003 0 // spawning +5618 1840 6 +5415 2004 0 // spawning +5615 1832 0 +5617 1832 6 +5616 1832 3 +5616 1832 6 +5616 1832 9 +5616 1833 0 +5618 1839 0 +5617 1832 0 +5617 1832 3 +5617 1832 9 +5619 1839 3 +5384 1908 0 // spawning +5618 1839 6 +5616 1834 0 +5616 1833 3 +5617 1833 0 +5619 1839 0 +5618 1840 0 +5619 1839 6 +5619 1840 0 + +# candlabra +CandelabraStand 0x0A29 +5576 1848 0 +5582 1848 0 +5586 1856 0 +5568 1852 0 +5577 1855 0 + +# long pants +Static 0x1539 (Hue=0xE8) +5592 2010 0 + +# rack +Static 0x125B +5506 1811 0 + +# rack +Static 0x1258 +5506 1812 0 + +# metal door +MetalDoor2 0x06D1 (Facing=SouthCCW) +5591 1904 0 +5599 1905 0 +5599 1897 0 +5599 1890 0 +5543 1809 0 +5611 1878 0 +5599 1913 0 +5595 1878 0 +5563 1864 0 +5615 1878 0 + +# cauldron +Static 0x0974 +5407 1934 0 +5433 1976 0 +5501 1998 0 + +# candle +CandleLarge 0x0A26 +5454 1921 20 + +# oven +StoneOvenSouthAddon 0x0930 +5621 1872 0 + +# flowstone +Static 0x08E8 +5440 1813 -5 +5439 1823 -5 +5440 1797 -5 +5440 1804 -5 +5440 1806 -5 +5440 1807 -5 +5440 1808 -5 +5440 1814 -5 +5440 1821 -5 +5440 1824 -5 +5440 1825 -5 +5440 1827 -5 +5440 1828 -5 +5440 1812 -5 +5440 1817 -5 +5439 1828 -5 +5440 1799 -5 +5440 1800 -5 +5440 1801 -5 +5440 1802 -5 +5440 1803 -5 +5440 1805 -5 +5440 1809 -5 +5440 1810 -5 +5440 1811 -5 +5440 1815 -5 +5440 1816 -5 +5440 1819 -5 +5440 1820 -5 +5440 1823 -5 +5440 1826 -5 +5443 1808 -5 +5443 1821 -5 +5440 1822 -5 +5440 1798 -5 +5440 1818 -5 + +# bookcase +FullBookcase 0x0A99 +5568 1833 0 + +# bookcase +FullBookcase 0x0A97 +5571 1824 0 +5587 1824 0 + +# floor spikes +SpikeTrap 0x119A +5408 1878 0 + +# shackles +Static 0x1263 +5507 1804 16 + +# flowstone +Static 0x08E6 +5443 1807 -5 +5442 1803 -5 +5445 1817 -5 +5445 1825 -5 + +# floor saw +SawTrap 0x11AC +5466 2011 0 +5407 1873 0 + +# switch +Static 0x1092 +5428 1875 13 +5407 1873 19 +5425 1875 13 +5426 1875 13 +5427 1875 13 +5429 1875 13 + +# gas trap +GasTrap 0x113C +5491 2029 0 +5468 2007 0 +5493 2027 0 + +# open sack of flour +Static 0x103A +5625 1859 0 +5623 1861 0 + +# water barrel +Static 0x154D +5464 1810 0 +5465 1809 0 +5465 1810 0 + +# metal chest +MetalGoldenChest 0x0E40 +5415 1931 0 // spawning +5495 2012 0 // spawning +5615 1834 0 // spawning + +# cot +Static 0x11FE +5603 1895 0 +5555 1903 0 +5603 1905 0 +5603 1915 0 +5555 1913 0 +5555 1915 0 +5603 1889 0 +5603 1891 0 +5603 1899 0 +5603 1907 0 +5603 1911 0 +5555 1889 0 +5555 1891 0 +5555 1895 0 +5555 1897 0 +5555 1899 0 +5555 1905 0 +5555 1907 0 +5555 1911 0 +5603 1897 0 +5603 1903 0 +5603 1913 0 + +# metal chest +Metalchest 0x0E7C +5457 1810 0 // spawning +5400 1862 0 // spawning +5610 1832 0 // spawning +5569 2001 0 // spawning +5403 1928 0 // spawning +5450 1893 0 +5450 1894 0 + +# stalagmites +Static 0x08E5 +5439 1798 -5 +5447 1819 -5 + +# candle +CandleLarge 0x0B1A +5536 1879 6 +5536 1882 6 + +# dungeon wall +Static 0x02FF +5558 1825 0 + +# candelabra +CandelabraStand 0x0B26 +5568 1866 0 +5590 1866 0 + +# fireplace +Static 0x08DB +5616 1880 0 + +# stalagmites +Static 0x08EA +5441 1802 -5 +5446 1809 -5 +5444 1816 -5 +5447 1812 -5 + +# ruined painting +HintItem 0x0C2C (Range=2; WarningNumber=500715; HintNumber=500716) +5570 1876 0 + +# rack +Static 0x125C +5506 1810 0 + +# stalagmites +Static 0x08E4 +5443 1813 -5 +5443 1808 11 + +# rack +Static 0x1256 +5507 1813 0 + +# sack of flour +Static 0x1039 +5624 1861 0 +5621 1861 0 +5623 1860 0 +5624 1860 0 + +# block +Static 0x1276 +5501 1811 0 + +# barrel +Barrel 0x0FAE +5452 1807 0 +5452 1806 0 +5451 1807 0 + +# block +Static 0x127B +5502 1809 0 + +# switch +Static 0x1090 +5399 1875 17 +5552 1864 11 + +# barred metal door +BarredMetalDoor 0x0685 (Facing=WestCW) +5539 1811 0 +5515 1811 0 +5523 1811 0 +5531 1811 0 + +# rack +Static 0x1257 +5506 1813 0 + +# wooden chest +WoodenChest 0x0E43 +5573 2000 0 // spawning +5452 1796 0 // spawning +5496 1993 0 // spawning + +# wooden box +WoodenBox 0x09AA +5574 2000 3 // spawning + +# stone stairs +Static 0x07A5 +5465 1805 15 +5468 1805 0 +5468 1806 0 +5593 1841 -5 +5593 1842 -5 +5468 1804 0 +5593 1840 -5 +5594 1840 -11 +5594 1841 -11 +5594 1842 -12 +5596 1841 -22 + +# crate +SmallCrate 0x0E7E +5549 2019 0 // spawning +5455 1892 0 // spawning + +# crumbling floor +FireColumnTrap 0x11C5 +5467 1852 0 +5474 1852 0 +5474 1857 0 +5438 1917 0 +5440 1917 0 +5441 1908 0 +5441 1912 0 +5443 1912 0 +5562 2028 0 +5568 2027 0 +5451 1919 0 +5451 1923 0 +5459 1856 0 +5463 1852 0 +5463 1855 0 +5471 1854 0 +5471 1857 0 +5477 1854 0 +5479 1856 0 +5556 2023 0 +5561 2022 0 +5537 2001 0 +5541 2002 0 +5541 2007 0 +5542 2012 0 +5545 2008 0 + +# head +Static 0x1CE1 +5417 1865 0 + +# wooden shield +Static 0x1B7A +5417 1930 0 + +# cauldron +Static 0x0975 +5473 1876 0 + +# broken chair +Static 0x0C1A +5613 1843 0 +5572 1832 0 +5583 1826 0 +5576 1827 0 +5580 1832 0 +5597 1879 0 +5604 1862 0 +5614 1834 0 + +# bone shards +Static 0x1B1A +5421 1868 0 + +# bottles of liquor +Static 0x099E +5623 1856 6 +5621 1856 6 +5624 1857 0 + +# dirty frypan +Static 0x09DE +5619 1875 6 + +# broken chair +Static 0x0C19 +5571 1825 0 +5581 1827 0 +5621 1838 0 +5577 1831 0 +5588 1828 0 +5609 1836 0 + +# stalagmites +Static 0x08E7 +5443 1822 -5 + +# bookcase +FullBookcase 0x0A98 +5575 1824 0 + +# metal chest +MetalChest 0x09AB +5507 1808 0 +5388 1907 0 +5411 1925 0 +5507 1805 0 + +# metal chest +MetalGoldenChest 0x0E41 +5502 1807 0 // spawning +5408 1927 0 // spawning +5454 2031 0 // spawning + +# stalagmites +Static 0x08E1 +5439 1799 -5 +5444 1824 -5 + +# wand +Static 0x0DF3 +5404 1937 0 +5419 1928 0 + +# switch +Static 0x1091 +5407 1873 19 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016094) +2495 918 8 + +# shackles +Static 0x1262 +5501 1808 20 +5501 1806 20 + +# iron maiden +Static 0x124B +5502 1805 0 + +# block +Static 0x127A +5503 1809 0 + +# guillotine +Static 0x1245 +5505 1805 0 + +# rack +Static 0x125D +5507 1810 0 + +# rack +Static 0x125A +5507 1811 0 + +# rack +Static 0x1259 +5507 1812 0 + +# broken chair +Static 0x0C1D +5574 1832 0 + +# statue +WarningItem 0x12D9 (Range=3; WarningNumber=1010056; ResetDelay=00:00:25) +5577 1895 0 +5581 1895 0 + +# statue +WarningItem 0x12D9 (Range=3; WarningNumber=1010057; ResetDelay=00:00:25) +5577 1911 0 +5581 1911 0 + +# flowstone +Static 0x08E2 +5473 1802 0 + +# crate +MediumCrate 0x0E3E +5610 1837 0 // spawning +5402 1863 0 // spawning +5450 1892 0 // spawning + +# wooden bench +WoodenBench 0x0B2C +5539 1877 0 +5539 1878 0 +5539 1879 0 +5539 1883 0 +5539 1884 0 +5539 1885 0 +5541 1877 0 +5541 1878 0 +5541 1879 0 +5541 1883 0 +5541 1884 0 +5541 1885 0 + +# barred metal door +BarredMetalDoor 0x0689 (Facing=WestCCW) +5523 1806 0 +5515 1806 0 +5531 1806 0 +5539 1806 0 + +# stone stairs +Static 0x0751 +5475 1881 0 +5474 1881 0 + +# stone stairs +Static 0x0752 +5476 1880 0 +5476 1879 0 + +# stone stairs +Static 0x0761 (Hue=0x83B) +5475 1880 0 + +# stone stairs +Static 0x0764 (Hue=0x83B) +5475 1879 0 + +# stone stairs +Static 0x0753 +5474 1878 0 +5475 1878 0 + +# stone stairs +Static 0x0754 +5473 1880 0 +5473 1879 0 + +# stone stairs +Static 0x0763 (Hue=0x83B) +5474 1880 0 + +# stone stairs +Static 0x0762 (Hue=0x83B) +5474 1879 0 + +# floor saw +SawTrap 0x11B1 +5484 2028 0 + +# broken chair +Static 0x0C11 +5604 1880 0 +5600 1872 0 + +# broken chair +Static 0x0C10 +5606 1874 0 + +# skinning knife +Static 0x0EC4 +5416 1937 0 + +# necklace +Static 0x1089 +5416 1931 0 + +# wand +Static 0x0DF4 +5416 1929 0 + +# ring +Static 0x108A +5417 1926 0 + +# bones +Static 0x0ED2 +5423 1867 0 + +# stone chair +HintItem 0x1218 (Range=2; WarningNumber=500717; HintNumber=500718) +5579 1848 5 + +# block +Static 0x127C +5501 1809 0 + +# block +Static 0x1277 +5501 1810 0 + +# broken chair +Static 0x0C1E +5589 1826 0 +5600 1879 0 + +# block +Static 0x1278 +5502 1810 0 + +# block +Static 0x1275 +5502 1811 0 + +# block +Static 0x1279 +5503 1810 0 + +# block +Static 0x1274 +5503 1811 0 + +# goblet +Static 0x099A +5599 1876 4 + +# goblet +Static 0x09BF +5599 1877 4 + +# bed +Static 0x0A5B +5600 1863 0 + +# chair +WoodenChairCushion 0x0B53 +5600 1875 0 + +# goblet +Static 0x09CB +5600 1878 4 +5606 1878 4 + +# bed +Static 0x0A5A +5601 1863 0 + +# chair +WoodenChair 0x0B57 +5602 1875 0 + +# chair +WoodenChair 0x0B59 +5606 1879 0 + +# kettle +Static 0x09ED +5616 1879 0 + +# fireplace +Static 0x08DA +5616 1881 0 + +# tray +Static 0x0991 +5619 1877 6 diff --git a/Data/Decoration/Britannia/_deceit.cfg b/Data/Decoration/Britannia/_deceit.cfg new file mode 100644 index 0000000..3830cce --- /dev/null +++ b/Data/Decoration/Britannia/_deceit.cfg @@ -0,0 +1,883 @@ +# stone pavers +Static 0x051D +5194 579 5 +5177 572 5 +5178 572 5 +5179 572 5 +5180 572 5 +5182 572 5 +5198 579 5 +5197 579 5 +5196 579 5 +5195 579 5 +5193 579 5 +5192 579 5 +5181 572 5 +5183 572 5 +5183 579 5 +5182 579 5 +5181 579 5 +5180 579 5 +5179 579 5 +5178 579 5 +5177 579 5 +5198 572 5 +5197 572 5 +5196 572 5 +5194 572 5 +5193 572 5 +5192 572 5 +5195 572 5 + +# stone +Static 0x07A3 +5194 579 0 +5195 579 0 +5196 579 0 +5310 740 0 +5322 740 0 +5183 579 0 +5178 579 0 +5179 579 0 +5180 579 0 +5181 579 0 +5182 579 0 +5177 579 0 +5177 572 0 +5178 572 0 +5179 572 0 +5180 572 0 +5181 572 0 +5182 572 0 +5183 572 0 +5193 579 0 +5197 579 0 +5198 579 0 +5192 579 0 +5198 572 0 +5197 572 0 +5196 572 0 +5193 572 0 +5194 572 0 +5195 572 0 +5192 572 0 +5314 740 0 +5318 740 0 + +# barrel +Barrel 0x0E77 +5281 536 0 +5281 536 10 +5282 536 0 +5336 613 0 +5336 613 5 +5280 536 0 +5281 536 5 +5296 592 5 +5296 594 0 +5300 593 0 +5298 592 0 +5296 592 0 +5296 593 0 +5296 593 5 +5297 592 0 +5297 592 5 +5280 536 5 +5280 537 0 +5192 584 0 +5197 584 0 +5197 584 5 +5197 585 0 +5197 585 5 +5198 584 0 +5198 585 0 + +# floor spikes +SpikeTrap 0x11A0 +5133 713 0 +5322 747 -20 +5220 744 -20 +5187 690 0 + +# metal chest +MetalChest 0x09AB +5150 741 0 +5312 750 -20 +5141 577 -50 + +# crystal ball +Static 0x0E2F +5211 733 -15 +5228 733 -17 + +# crate +LargeCrate 0x0E3D +5280 541 0 +5280 541 3 +5280 543 3 +5280 701 0 +5280 701 3 +5284 688 0 +5288 611 0 +5288 611 3 +5288 612 0 +5280 700 0 +5280 700 3 +5285 688 0 +5184 629 3 +5280 542 0 +5280 542 3 +5280 542 6 +5280 543 0 +5280 543 6 +5184 629 0 +5184 629 6 + +# scroll%s% +Static 0x0E36 +5270 664 5 +5218 724 -20 + +# floor spikes +SpikeTrap 0x119A +5134 715 0 +5193 689 0 +5326 745 -20 +5228 701 -20 +5222 733 -20 + +# stone stairs +Static 0x07A4 +5305 531 10 +5306 649 15 +5183 573 1 +5217 587 -20 +5218 762 -35 +5217 586 -15 +5183 580 0 + +# crate +LargeCrate 0x0E3C +5280 573 0 +5280 573 6 +5283 648 0 +5340 544 0 +5341 544 0 +5285 648 3 +5339 544 0 +5340 544 3 +5341 544 3 +5341 544 6 +5342 544 0 +5342 544 3 +5342 544 6 +5342 544 9 +5284 648 0 +5285 649 0 +5285 648 0 +5280 573 3 + +# metal chest +Metalchest 0x0E7C +5147 611 -50 // spawning +5324 570 0 // spawning +5327 751 -20 // spawning +5264 676 5 // spawning + +# brazier +Brazier 0x0E32 +5294 625 -5 +5297 625 -5 +5294 622 -5 +5297 622 -5 +5309 737 0 + +# scroll%s% +Static 0x0E3A +5315 585 0 +5188 585 0 +5161 693 0 + +# stone face +StoneFaceTrap 0x10FC +5319 581 0 + +# lever +Static 0x108C +5320 568 0 +5328 544 15 +5280 552 0 + +# dungeon wall +SecretDungeonDoor 0x031E (Facing=NorthCCW) +5295 675 0 +5279 649 0 +5319 708 0 +5322 583 0 + +# metal chest +MetalGoldenChest 0x0E40 +5264 693 0 // spawning +5325 570 0 // spawning +5270 688 0 // spawning +5256 677 0 // spawning + +# floor saw +SawTrap 0x11B1 +5219 725 -20 +5222 734 -20 +5189 652 0 +5178 661 0 +5325 748 -20 +5303 736 0 +5222 712 -20 +5220 685 -20 +5304 735 0 + +# wand +Static 0x0DF4 +5228 694 -20 +5228 730 -14 +5188 694 5 +5230 562 0 +5310 589 0 + +# statue +Static 0x1227 +5327 538 0 + +# metal chest +MetalGoldenChest 0x0E41 +5153 739 0 // spawning +5150 627 -50 // spawning +5144 627 -50 // spawning +5320 754 -20 // spawning +5203 584 0 // spawning + +# studded gorget +Static 0x13D6 +5201 620 0 +5334 680 0 + +# scroll%s% +Static 0x0EF9 +5292 621 0 +5187 660 0 + +# woven mat +Static 0x11E8 +5337 549 0 + +# scroll%s% +Static 0x0EF4 +5337 589 0 + +# woven mat +Static 0x11E9 +5338 549 0 + +# metal door +MetalDoor2 0x06CF (Facing=NorthCCW) +5319 675 0 +5295 579 0 +5287 675 0 +5311 603 0 +5303 627 0 +5311 579 0 +5191 558 0 + +# butcher knife +Static 0x13F6 +5153 613 -50 +5142 658 0 +5311 722 0 + +# alchemical symbol +Static 0x1822 (Hue=0x482) +5336 600 0 +5336 585 0 + +# bones +Static 0x0ED0 +5341 548 0 + +# gas trap +GasTrap 0x113C +5314 750 -20 +5305 757 -20 +5155 603 -50 +5158 716 0 +5189 650 0 + +# statue +Static 0x1228 +5267 683 0 +5128 700 0 +5282 586 13 +5282 582 13 +5266 674 5 +5266 677 5 + +# Red Potion +Static 0x0F0B +5211 724 -16 +5227 723 -17 + +# straw pillow +Static 0x11EB +5337 549 1 + +# broadsword +Static 0x0F5E +5266 682 0 + +# stone stairs +Static 0x07A9 +5184 580 0 +5184 573 0 + +# stone stairs +Static 0x07A5 +5184 579 0 +5184 572 0 +5190 569 0 +5190 568 0 +5186 568 0 + +# stone stairs +Static 0x07AA +5184 578 0 +5184 571 0 + +# stone stairs +Static 0x07A8 +5176 578 0 +5176 571 0 +5191 578 0 +5191 571 0 + +# stone stairs +Static 0x07A7 +5176 579 0 +5191 579 0 +5191 572 0 +5176 572 0 + +# stone stairs +Static 0x07AB +5176 580 0 +5176 573 0 +5191 580 0 +5191 573 0 + +# stone stairs +Static 0x07AF +5177 580 0 +5177 573 0 +5192 580 0 +5192 573 0 + +# stone stairs +Static 0x07AC +5177 571 0 +5192 578 0 +5192 571 0 +5177 578 0 + +# dungeon wall +Static 0x0241 +5152 687 0 +5153 687 0 +5154 687 0 +5156 687 0 +5157 687 0 +5158 687 0 +5159 687 0 + +# wooden chest +WoodenChest 0x0E42 +5317 582 0 // spawning +5169 599 0 // spawning +5224 571 0 // spawning +5256 675 0 // spawning + +# statue +Static 0x1225 +5320 758 -20 +5137 579 -50 + +# floor saw +SawTrap 0x11AC +5315 735 0 +5153 611 -50 +5204 655 0 +5133 714 0 + +# wooden chest +WoodenChest 0x0E43 +5318 581 0 // spawning +5264 688 0 // spawning +5201 584 0 // spawning +5229 570 0 // spawning + +# metal door +MetalDoor2 0x06CB (Facing=EastCW) +5283 663 0 +5307 687 0 +5323 591 0 +5321 575 0 +5283 695 0 +5283 687 0 +5284 575 0 +5331 695 0 +5307 695 0 +5188 567 0 +5284 551 0 +5156 735 0 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +5311 580 0 +5287 699 0 +5319 676 0 +5295 580 0 +5303 699 0 +5303 628 0 +5191 559 0 +5311 604 0 +5287 676 0 + +# kite shield +Static 0x1B74 +5298 608 0 +5230 562 0 + +# empty tub +Static 0x0E83 +5338 544 0 + +# earrings +Static 0x1087 +5325 603 -20 +5230 691 -20 +5226 563 0 + +# feathered hat +Static 0x171A +5174 570 0 + +# mushroom +MushroomTrap 0x1125 +5304 757 -20 +5327 743 -20 +5319 747 -20 +5310 750 -20 + +# heating stand +HeatingStand 0x184A +5205 611 4 + +# dungeon wall +SecretDungeonDoor 0x0316 (Facing=EastCCW) +5266 687 0 + +# dungeon wall +SecretDungeonDoor 0x031A (Facing=EastCW) +5178 583 0 + +# keg +Keg 0x0E7F +5196 584 0 +5195 584 0 +5296 596 0 + +# small crate +SmallCrate 0x09A9 +5320 569 0 +5150 746 0 + +# crate +MediumCrate 0x0E3E +5296 595 0 +5296 595 3 +5280 654 0 +5280 658 0 +5280 653 0 + +# cleaver +Static 0x0EC3 +5319 744 -20 +5334 550 0 +5281 688 0 +5313 549 0 + +# kite shield +Static 0x1B78 +5333 614 0 + +# empty vial%s% +Static 0x0E24 +5212 723 -14 + +# dried onions +Static 0x0C3F +5224 573 0 + +# switch +Static 0x1092 +5293 672 11 + +# viking sword +Static 0x13B9 +5324 624 0 + +# metal door +MetalDoor2 0x06C9 (Facing=WestCCW) +5283 575 0 +5330 695 0 +5322 591 0 +5187 567 0 +5283 551 0 +5320 575 0 +5139 688 0 +5155 735 0 + +# ring +Static 0x108A +5294 587 0 + +# blank scroll%s% +Static 0x0EF3 +5211 730 -17 +5211 732 -16 +5202 608 0 + +# deer mask +Static 0x1548 +5141 680 0 + +# dagger +Static 0x0F51 +5286 573 0 + +# shoes +Static 0x170F +5286 566 0 + +# metal door +MetalDoor2 0x06C5 (Facing=WestCW) +5309 734 0 + +# metal door +MetalDoor2 0x06C7 (Facing=EastCCW) +5310 734 0 + +# long pants +Static 0x1539 (Hue=0x25) +5286 566 0 + +# stone chair +Static 0x1219 +5137 578 -50 +5165 565 0 +5165 567 0 +5165 569 0 + +# shackles +Static 0x1262 +5137 587 -37 +5137 594 -37 +5137 597 -37 + +# skull with candle +CandleSkull 0x1858 +5138 577 -45 +5167 566 6 + +# ceramic mug +CeramicMug 0x0997 +5138 593 -50 +5139 587 -50 +5142 586 -50 +5153 584 -50 +5153 590 -50 + +# iron maiden +Static 0x124B +5138 611 -50 + +# guillotine +Static 0x125E +5141 611 -50 + +# shackles +Static 0x1263 +5142 584 -37 +5138 584 -37 +5152 577 -37 +5154 577 -37 + +# shirt +Static 0x1517 (Hue=0x25) +5286 566 0 + +# wooden shield +Static 0x1B7A +5282 548 0 + +# White Potion +Static 0x0F09 +5210 724 -16 + +# statue +Static 0x1226 +5321 747 -8 +5313 747 -8 + +# dirty pot +Static 0x09DD +5151 584 -50 + +# dirty pan +Static 0x09E8 +5153 595 -50 + +# dungeon wall +SecretDungeonDoor 0x031C (Facing=SouthCW) +5263 672 0 + +# Black Potion +Static 0x0F06 +5226 722 -15 + +# Blue Potion +Static 0x0F08 +5228 722 -18 + +# barred metal door +BarredMetalDoor 0x0693 (Facing=NorthCW) +5150 579 -50 +5150 586 -50 +5150 597 -50 +5150 605 -50 + +# barred metal door +BarredMetalDoor 0x068F (Facing=NorthCCW) +5144 588 -50 +5144 595 -50 +5144 604 -50 + +# goblet +Static 0x09BF +5166 565 0 +5166 570 0 +5167 567 0 +5167 569 0 +5168 564 0 +5168 570 0 +5166 567 0 +5167 564 0 +5168 566 0 +5168 568 0 +5167 565 0 + +# stone chair +Static 0x1218 +5167 563 0 + +# skull with candle +CandleSkull 0x1854 +5167 568 7 + +# stone chair +Static 0x121A +5167 571 0 + +# stone face +StoneFaceTrap 0x10F5 +5168 584 0 + +# stone face +StoneFaceTrap 0x110F +5168 599 0 + +# stone chair +Static 0x121B +5169 567 0 +5169 569 0 +5169 565 0 +5202 597 0 +5202 599 0 +5202 601 0 + +# scroll%s% +Static 0x0E38 +5169 573 0 +5186 548 0 + +# scroll%s% +Static 0x0EF8 +5173 692 0 +5174 665 0 + +# bone +Static 0x1B12 +5184 605 0 + +# close helm +Static 0x1409 +5129 690 0 + +# brazier +Brazier 0x0E31 +5175 615 0 +5186 573 10 +5224 560 0 +5188 573 11 + +# spike trap +SpikeTrap 0x111B +5173 592 4 +5172 592 4 + +# dungeon wall +Static 0x0300 +5189 574 20 + +# tricorne hat +Static 0x171B +5190 727 0 + +# scroll%s% +Static 0x0EF7 +5195 589 0 + +# kettle +Static 0x09ED +5196 609 5 +5202 621 5 + +# goblet +Static 0x099A +5197 621 3 +5198 621 3 +5205 615 9 +5205 616 9 + +# scroll%s% +Static 0x0EF5 +5197 655 0 + +# crystal ball +Static 0x0E2E +5201 609 8 +5225 553 5 +5199 609 7 + +# Batwing%s% +Static 0x0F78 +5205 620 5 + +# statue +Static 0x139B +5317 751 -8 +5309 751 -8 + +# +Static 0x1519 +5211 554 -20 + +# crystal ball +Static 0x0E2D +5212 736 -20 +5221 532 0 +5227 735 -20 + +# ankh +Static 0x0005 +5205 774 0 + +# Yellow Potion +Static 0x0F0C +5211 723 -20 + +# dried flowers +Static 0x0C3B +5224 572 0 + +# dried flowers +Static 0x0C3E +5224 573 0 + +# dried herbs +Static 0x0C41 +5224 574 0 + +# Orange Potion +Static 0x0F07 +5228 723 -17 + +# platemail gloves +Static 0x1414 +5181 587 0 + +# candle +CandleLarge 0x0B1A +5174 614 0 +5174 616 2 +5176 614 2 +5176 616 3 +5226 562 0 + +# chainmail leggings +Static 0x13BE +5306 609 0 + +# bow +Static 0x13B2 +5221 735 -20 + +# goblet +Static 0x09B3 +5201 597 8 +5201 600 7 + +# pen and ink +Static 0x0FC0 +5201 598 6 + +# candle +CandleLarge 0x0A26 +5226 564 2 +5228 562 2 +5228 564 3 + +# switch +Static 0x108F +5305 676 -12 + +# stone stairs +Static 0x07A6 +5183 578 0 +5183 571 0 + +# metal door +MetalDoor 0x0679 (Facing=WestCCW) +5155 687 1 + +# heavy crossbow +Static 0x13FD +5339 605 0 +5192 655 0 + +# chainmail coif +Static 0x13BB +5193 575 0 + +# wizard's hat +Static 0x1718 (Hue=0x151) +5307 545 0 + +# bone armor +Static 0x144F +5289 542 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/_despise.cfg b/Data/Decoration/Britannia/_despise.cfg new file mode 100644 index 0000000..c3b3a52 --- /dev/null +++ b/Data/Decoration/Britannia/_despise.cfg @@ -0,0 +1,439 @@ +# crate +LargeCrate 0x0E3C +5408 607 45 +5384 552 60 +5487 631 28 +5488 630 25 +5488 631 25 +5488 631 28 +5491 574 59 +5491 574 62 +5492 574 60 +5492 574 63 +5492 576 58 +5493 574 60 +5497 623 25 +5476 898 30 +5505 629 28 +5479 560 60 +5489 575 59 +5497 520 60 +5497 624 25 +5500 520 60 +5505 629 25 +5487 631 25 +5407 612 45 +5505 629 31 +5487 631 31 +5407 612 48 +5384 521 65 +5384 552 63 +5384 552 66 +5384 553 60 +5384 554 60 +5384 555 60 +5384 555 63 +5384 555 66 +5385 525 65 +5385 527 65 +5385 552 60 +5385 552 63 +5385 679 20 +5498 520 60 +5386 552 63 +5386 552 66 +5407 611 45 +5407 611 48 +5407 611 51 +5407 613 45 +5407 613 48 +5407 613 51 +5408 613 45 +5384 522 65 +5384 525 65 +5384 526 65 +5384 526 68 +5384 527 65 +5384 553 63 +5384 556 60 +5386 552 60 +5408 613 48 +5479 560 63 +5479 561 60 + +# crate +LargeCrate 0x0E3D +5485 622 31 +5490 535 60 +5491 624 25 +5485 622 25 +5485 622 28 +5487 623 25 +5489 532 60 +5489 535 60 +5598 835 50 +5544 903 10 +5612 780 60 +5613 777 60 +5384 680 20 +5433 780 60 +5484 622 25 +5484 622 28 + +# barrel +Barrel 0x0E77 +5385 520 65 +5489 528 65 +5489 528 60 +5490 528 60 +5488 534 60 +5488 532 65 +5488 532 60 +5388 552 60 +5490 528 65 +5388 553 60 +5489 631 25 +5389 552 60 +5389 553 60 +5390 552 60 +5391 552 60 +5391 552 65 +5389 552 65 +5390 552 65 +5490 573 60 +5493 528 60 +5496 528 60 +5390 552 70 +5507 520 60 +5489 630 30 +5490 630 25 +5496 522 60 +5494 625 25 +5494 625 30 +5407 605 45 +5384 681 20 +5389 528 65 +5489 630 25 +5392 520 65 +5390 528 65 +5564 899 30 +5491 528 60 +5493 529 60 +5501 528 60 +5506 520 60 +5393 520 65 +5388 552 65 +5496 522 65 +5407 605 50 +5408 605 45 +5390 528 70 +5384 529 65 +5389 529 65 + +# crate +MediumCrate 0x0E3E +5388 601 45 +5488 531 60 +5488 530 60 +5388 522 65 +5510 813 60 +5510 812 60 +5386 585 45 +5608 822 60 + +# metal door +MetalDoor2 0x06C7 (Facing=EastCCW) +5387 693 20 + +# metal chest +MetalGoldenChest 0x0E40 +5408 929 20 +5512 656 30 +5387 698 15 +5479 564 60 +5604 807 60 + +# dirty pot +Static 0x09E7 +5392 525 66 +5400 590 45 + +# cauldron +Static 0x0975 +5398 907 31 +5413 723 16 +5410 664 20 +5459 741 5 + +# mushroom +Static 0x0D16 +5445 977 15 +5400 929 20 +5406 932 20 +5425 878 30 +5496 542 60 +5405 920 20 +5407 575 60 +5423 893 30 +5405 885 30 +5412 881 30 +5413 892 30 +5428 906 30 +5453 970 15 +5415 904 30 +5448 533 60 +5421 527 60 +5427 957 15 +5401 576 60 +5418 909 30 +5413 934 20 +5391 896 30 +5435 557 60 +5484 544 60 +5401 918 20 +5445 962 15 +5384 897 30 +5386 888 30 + +# dirty pot +Static 0x09DD +5495 624 25 +5490 623 25 +5486 631 25 +5497 625 25 + +# water +Static 0x179B +5401 703 14 +5395 704 14 + +# ceramic mug +CeramicMug 0x0995 +5497 563 65 +5506 527 60 +5499 561 65 +5508 526 60 +5501 524 60 +5503 523 60 +5503 533 60 +5504 524 60 +5505 531 60 + +# keg +Keg 0x0E7F +5495 625 25 +5493 625 25 +5507 653 20 + +# switch +Static 0x1092 +5425 569 78 +5506 625 39 + +# metal chest +Metalchest 0x0E7C +5395 1004 5 +5451 870 45 +5388 698 15 +5385 698 15 +5572 895 30 + +# crate +MediumCrate 0x0E3F +5490 529 60 +5514 803 60 +5565 900 30 + +# small crate +SmallCrate 0x09A9 +5517 809 60 +5613 779 60 +5385 680 20 +5387 680 20 +5391 522 65 + +# dirty frypan +Static 0x09DE +5484 622 31 +5487 624 25 + +# water barrel +Static 0x154D +5390 552 60 +5496 522 60 +5489 631 25 + +# metal chest +MetalChest 0x09AB +5510 660 20 +5567 897 30 +5615 776 60 + +# wooden chest +WoodenChest 0x0E43 +5504 650 30 +5384 656 30 +5539 877 30 +5386 698 15 +5505 656 30 +5391 703 15 +5614 776 60 +5401 932 20 +5587 815 45 + +# metal chest +MetalGoldenChest 0x0E41 +5553 831 45 +5567 900 30 +5390 604 30 +5394 600 45 +5555 824 45 +5387 587 45 +5539 872 45 + +# cauldron +Static 0x0974 +5502 541 61 +5391 966 15 +5434 853 45 + +# crate +SmallCrate 0x0E7E +5440 843 45 +5516 808 60 +5387 590 45 +5466 826 60 +5500 536 60 + +# wooden chest +WoodenChest 0x0E42 +5568 899 30 +5392 981 5 +5565 824 45 +5382 658 30 +5384 819 60 +5384 820 60 +5504 532 62 +5390 698 15 +5479 563 60 +5472 760 5 +5472 761 5 +5401 978 5 + +# metal door +MetalDoor2 0x06C5 (Facing=WestCW) +5386 693 20 + +# pot +Static 0x09E5 +5389 527 65 +5385 525 68 + +# dirty pot +Static 0x09DF +5389 591 45 +5390 591 45 + +# dirty pan +Static 0x09E8 +5389 591 45 +5393 586 45 +5497 523 60 +5497 527 60 +5503 533 60 +5504 524 60 +5504 530 60 + +# dirty pot +Static 0x09DC +5390 525 65 +5497 564 65 +5502 531 60 + +# kettle +Static 0x09ED +5391 526 65 +5500 523 60 + +# water +Static 0x1797 +5395 705 14 + +# water +Static 0x179C +5395 707 14 + +# water +Static 0x179A +5396 705 14 +5399 703 14 +5395 703 14 +5400 703 14 + +# water +Static 0x1799 +5397 703 14 +5397 705 14 + +# ankh +RejuvinationAnkhWest 0x0003 +5425 570 65 + +# fire pit +Static 0x0FAC +5502 541 60 + +# gruesome standard +Static 0x041F +5507 539 70 + +# blood smear +Static 0x122F +5410 550 60 +5413 549 60 + +# crystal ball +Static 0x0E2F +5450 1004 19 + +# stone +Static 0x07A3 +5453 612 45 + +# stone +Static 0x0788 +5458 610 45 + +# ankh +RejuvinationAnkhNorth 0x0004 +5474 525 79 + +# dirty pot +Static 0x09E6 +5480 630 25 +5503 529 60 + +# bone arms +Static 0x1453 +5561 905 30 + +# ceramic mug +CeramicMug 0x09CA +5498 528 60 +5502 533 60 + +# skeleton +Static 0x1B7F +5501 560 65 + +# campfire +Static 0x0DE3 +5502 541 60 + +# garbage +Static 0x10EE +5502 534 60 + +# skull mug +Static 0x0FFD +5507 529 60 \ No newline at end of file diff --git a/Data/Decoration/Britannia/_destard.cfg b/Data/Decoration/Britannia/_destard.cfg new file mode 100644 index 0000000..e72c2a4 --- /dev/null +++ b/Data/Decoration/Britannia/_destard.cfg @@ -0,0 +1,448 @@ +# crate +LargeCrate 0x0E3C +5177 1013 0 +5247 838 20 +5247 838 23 +5312 802 0 +5313 802 0 +5313 802 3 +5320 776 0 +5144 870 0 +5153 859 3 +5177 1014 0 +5177 1014 3 +5178 1014 0 +5153 859 0 +5154 859 0 + +# stalagmites +Static 0x08E9 +5149 962 25 +5145 960 25 +5142 960 25 +5140 958 25 +5139 957 25 +5131 965 25 +5131 967 25 +5131 968 25 +5131 969 25 +5131 970 25 +5132 972 25 +5136 978 25 +5132 987 25 +5133 990 25 +5153 999 0 +5153 1001 8 +5153 1001 0 +5155 1001 1 +5153 1004 25 +5153 1005 25 +5153 1006 25 +5155 1008 25 +5158 1011 25 +5165 991 25 +5166 991 25 +5136 976 25 +5151 962 25 +5150 962 25 +5148 962 25 +5147 962 25 +5147 961 25 +5146 961 25 +5143 960 25 +5142 959 25 +5141 959 25 +5140 957 25 +5131 972 25 +5132 973 25 +5133 973 25 +5133 974 25 +5134 975 25 +5135 975 25 +5135 976 25 +5135 978 25 +5135 979 25 +5134 979 25 +5133 980 25 +5132 980 25 +5132 981 25 +5132 982 25 +5132 984 25 +5132 985 25 +5132 986 25 +5132 988 25 +5132 989 25 +5133 991 25 +5133 992 25 +5133 993 25 +5133 994 25 +5133 995 25 +5155 1000 11 +5152 999 0 +5151 999 0 +5155 1002 1 +5153 1006 35 +5154 1007 25 +5145 961 25 +5160 991 25 +5161 991 25 +5162 991 25 +5163 991 25 +5164 991 25 +5136 977 25 +5154 1001 0 +5144 960 25 +5141 958 25 +5131 966 25 +5132 983 25 +5156 1009 25 +5159 1011 25 +5167 992 25 +5134 974 25 +5155 999 1 +5157 1010 25 + +# metal chest +MetalChest 0x09AB +5160 910 0 +5236 938 -33 +5136 994 0 +5307 810 0 + +# blood +Static 0x122D +5217 907 -30 +5245 954 -30 +5133 844 0 +5274 969 -40 +5268 948 -33 +5147 862 0 +5277 933 -40 +5264 925 -27 +5153 874 10 +5173 957 0 +5247 969 -40 +5247 898 -30 +5192 969 0 + +# stalagmites +Static 0x08EA +5163 1004 0 +5138 957 25 +5134 957 25 +5133 957 25 +5133 958 35 +5132 959 25 +5170 993 25 +5131 962 25 +5165 996 0 +5166 997 0 +5166 999 8 +5160 998 -2 +5164 1000 5 +5165 999 -2 +5165 1000 -5 +5162 1001 -5 +5164 1001 -5 +5166 1002 -2 +5168 1002 0 +5169 993 25 +5160 1003 0 +5137 957 25 +5135 957 25 +5133 958 25 +5131 958 25 +5131 959 25 +5131 960 25 +5131 961 25 +5131 963 25 +5131 964 25 +5161 996 0 +5162 996 0 +5163 996 0 +5160 997 0 +5161 997 -2 +5163 997 -2 +5164 997 -2 +5167 998 0 +5167 999 10 +5164 998 -2 +5164 999 5 +5162 999 5 +5161 999 5 +5160 999 -2 +5161 999 -5 +5162 999 -5 +5164 999 -5 +5166 999 -2 +5168 999 0 +5168 1000 0 +5166 1000 -2 +5164 1000 -5 +5162 1000 -5 +5161 1000 -5 +5160 1000 -2 +5166 1003 0 +5164 1003 -2 +5160 1004 0 +5163 1002 -5 +5171 993 25 +5172 993 25 +5173 995 35 +5173 996 35 +5173 995 25 +5174 996 25 +5174 998 35 +5174 999 35 +5174 998 25 +5175 999 25 +5176 999 25 +5177 999 25 +5175 1000 12 +5162 1004 0 +5136 957 25 +5164 1004 0 +5165 1004 0 +5132 958 25 +5160 996 0 +5162 997 -2 +5163 999 5 +5164 1001 5 +5160 1001 -2 +5161 1001 -2 +5163 1001 -5 +5166 1002 8 +5168 1003 0 +5165 1003 -2 +5163 1003 -2 +5162 1003 -2 +5161 1003 0 +5161 1004 0 +5168 993 25 +5173 996 25 +5174 999 25 +5178 999 25 + +# wooden chest +WoodenChest 0x0E43 +5133 849 0 +5324 977 0 +5154 993 0 +5309 803 0 + +# metal chest +MetalGoldenChest 0x0E41 +5285 850 0 +5136 959 0 +5175 830 1 +5249 940 -39 + +# crate +LargeCrate 0x0E3D +5144 907 0 +5311 982 0 +5311 982 3 +5311 983 0 +5311 983 3 +5311 983 6 +5312 983 0 + +# empty tub +Static 0x0E83 +5178 845 0 +5176 848 0 + +# blood smear +Static 0x122F +5263 981 -30 +5271 980 -27 +5265 916 -40 +5254 956 -30 +5177 958 0 +5200 964 -27 +5183 956 0 +5248 970 -30 + +# metal chest +MetalGoldenChest 0x0E40 +5239 944 -40 +5262 899 -40 +5151 990 0 +5303 809 0 +5325 983 0 +5175 1010 0 + +# blood +Static 0x122E +5247 924 -40 +5183 956 0 +5142 862 10 +5246 897 -40 +5181 958 0 +5221 935 -39 +5130 851 10 +5255 947 -34 + +# stalagmites +Static 0x08E4 +5246 837 20 + +# mushroom +Static 0x0D16 +5257 790 0 +5250 850 4 +5146 905 0 +5132 841 0 +5124 904 0 +5128 898 0 +5129 898 0 +5129 899 0 +5130 898 0 +5137 901 0 +5134 847 0 +5137 902 0 +5139 905 0 +5134 840 0 +5136 843 0 +5250 794 0 +5255 794 0 +5256 793 0 +5257 794 0 +5242 788 0 +5245 791 0 +5131 899 0 + +# metal chest +Metalchest 0x0E7C +5157 901 0 +5133 964 0 +5133 967 0 + +# bones +Static 0x0ED1 +5139 831 0 + +# blood +Static 0x122B +5271 968 -40 +5217 907 -30 +5221 935 -39 +5250 909 -37 +5140 857 0 +5192 970 10 +5194 961 0 +5175 957 0 + +# wooden chest +WoodenChest 0x0E42 +5205 778 0 +5311 981 0 +5311 985 0 +5175 1009 0 +5175 1011 0 +5163 864 0 + +# barrel +Barrel 0x0E77 +5176 1014 0 +5179 1014 0 +5176 1013 0 +5176 1014 5 +5229 828 2 +5314 776 0 +5228 828 1 + +# small crate +SmallCrate 0x09A9 +5304 809 0 + +# crate +MediumCrate 0x0E3E +5277 804 1 +5196 918 -40 + +# blood +Static 0x122C +5184 939 0 +5271 968 -40 +5181 956 0 +5234 988 -15 +5278 929 -40 +5217 912 -30 + +# flowstone +Static 0x08E2 +5139 799 0 + +# blood +Static 0x122A +5217 907 -30 +5180 954 0 +5202 963 -29 +5244 990 -28 + +# dirty pot +Static 0x09E6 +5153 873 0 + +# knife +Knife 0x09A6 +5153 871 0 + +# flowstone +Static 0x08E3 +5140 799 0 + +# stalagmites +Static 0x08E1 +5140 801 0 +5139 802 0 +5139 800 0 +5140 800 0 + +# crate +MediumCrate 0x0E3F +5311 800 0 + +# key ring +Static 0x1011 +5310 804 0 + +# mace +Static 0x0F5C +5308 805 0 + +# spoon +Spoon 0x09C3 +5152 869 0 + +# kettle +Static 0x09ED +5152 873 0 + +# dirty pot +Static 0x09DC +5153 868 0 + +# spoon +Spoon 0x09F9 +5157 869 0 + +# dirty pot +Static 0x09DF +5156 869 0 +5201 913 -40 + +# bowl of lettuce +Static 0x1600 +5156 868 0 + +# iron fence +Static 0x0821 +5196 793 0 +5196 794 0 +5196 795 0 + +# dirty frypan +Static 0x09DE +5201 912 -40 diff --git a/Data/Decoration/Britannia/_fire.cfg b/Data/Decoration/Britannia/_fire.cfg new file mode 100644 index 0000000..1e5d37c --- /dev/null +++ b/Data/Decoration/Britannia/_fire.cfg @@ -0,0 +1,203 @@ +############### +# Teleporters # +############### + +# teleporter +Teleporter 0x1BC3 (PointDest=(5690, 1352, -26)) +5691 1348 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5691, 1348, 0)) +5690 1352 -26 + +############### +# Decorations # +############### + +# bellows +Static 0x1986 (Light=Circle300) +5640 1410 0 + +# forge +Static 0x198A (Light=Circle300) +5640 1411 0 + +# forge +Static 0x1996 (Light=Circle300) +5640 1412 0 + +# bellows +Static 0x1992 (Light=Circle300) +5640 1413 0 + +# metal chest +MetalGoldenChest 0x0E40 +5675 1433 0 +5647 1434 0 +5640 1433 0 +5640 1435 0 +5640 1437 0 +5650 1438 0 + +# stalagmites +Static 0x08E0 +5690 1328 -1 +5717 1410 42 +5718 1409 42 +5718 1410 40 + +# fire column +FlameSpurtTrap 0x1 +5688 1353 -26 +5689 1354 -26 +5690 1354 -26 +5691 1354 -26 +5692 1353 -26 +5692 1352 -26 +5689 1350 -26 +5691 1350 -26 +5692 1351 -26 +5688 1351 -26 +5688 1352 -26 +5690 1350 -26 + +# pentagram +PentagramAddon 0x0FEA +5690 1352 -26 +5691 1348 0 + +# glowing rune +Static 0x0E68 +5686 1432 22 + +# boulder +Static 0x1362 +5696 1388 -1 +5694 1388 4 +5695 1388 4 +5695 1387 0 +5694 1387 2 + +# barrel +Barrel 0x0E77 +5645 1400 22 +5653 1400 22 + +# empty tub +Static 0x0E83 +5648 1400 0 + +# keg +Keg 0x0E7F +5720 1386 2 + +# wooden chest +WoodenChest 0x0E43 +5675 1436 0 +5728 1391 -1 +5673 1434 0 + +# metal door +MetalDoor2 0x06C5 (Facing=WestCW) +5835 1487 -1 +5835 1431 0 +5643 1408 0 +5651 1412 0 +5643 1416 22 +5851 1431 0 +5723 1295 0 +5731 1383 0 + +# metal chest +Metalchest 0x0E7C +5672 1434 0 + +# metal chest +MetalChest 0x09AB +5723 1384 -2 +5673 1433 0 + +# stone stairs +Static 0x07A6 +5786 1337 -5 +5787 1337 -5 +5788 1337 -5 + +# stone +Static 0x07A3 +5786 1338 -5 +5787 1338 -5 +5788 1338 -5 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +5647 1443 0 +5642 1401 22 +5655 1402 0 +5647 1420 0 +5644 1409 22 +5655 1363 -1 +5679 1434 0 +5679 1444 0 +5687 1441 -1 +5855 1475 0 +5855 1427 0 +5671 1315 0 + +# rock +Static 0x1773 +5711 1337 1 + +# metal chest +MetalGoldenChest 0x0E41 +5642 1432 0 + +# vines +Static 0x0CF1 +5854 1457 0 + +# rock +Static 0x1772 +5688 1328 1 +5712 1337 -3 + +# rock +Static 0x1778 +5710 1336 2 + +# rock +Static 0x1775 +5711 1336 -1 + +# metal door +MetalDoor2 0x06D1 (Facing=SouthCCW) +5647 1410 0 +5647 1402 0 + +# rock +Static 0x1774 +5712 1338 -2 + +# metal door +MetalDoor2 0x06C9 (Facing=WestCCW) +5691 1343 0 +5651 1439 0 +5650 1416 22 + +# barrel +Static 0x0FAE +5645 1413 22 +5643 1415 0 + +# wooden chest +WoodenChest 0x0E42 +5640 1403 0 +5640 1404 0 + +# metal door +MetalDoor2 0x06CB (Facing=EastCW) +5651 1416 22 + +# forge +Static 0x198A (Light=Circle300) +5640 1411 0 diff --git a/Data/Decoration/Britannia/_hedgemaze.cfg b/Data/Decoration/Britannia/_hedgemaze.cfg new file mode 100644 index 0000000..127f363 --- /dev/null +++ b/Data/Decoration/Britannia/_hedgemaze.cfg @@ -0,0 +1,906 @@ +############### +# Teleporters # +############### + +# teleporter +Teleporter 0x1BC3 (PointDest=(1163, 2205, 0)) +1166 2237 60 + +# teleporter +Teleporter 0x1BC3 (PointDest=(1163, 2211, 60)) +1165 2204 40 + +# teleporter +Teleporter 0x1BC3 (PointDest=(1165, 2214, 19)) +1163 2208 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(1171, 2202, 0)) +1163 2204 60 + + +############### +# Decorations # +############### + +# lantern +Lantern 0x0A22 +1132 2227 46 + +# grasses +Static 0x0CAC +1186 2216 0 + +# century plant +Static 0x0D30 +1194 2217 0 + +# peach tree +Static 0x0D9E +1195 2269 0 + +# pear tree +Static 0x0DAA +1205 2269 0 + +# pear tree +Static 0x0DA6 +1206 2184 0 + +# cactus +Static 0x0D27 +1206 2225 0 + +# crystal ball +Static 0x0E2F +1213 2191 13 + +# stone wall +Static 0x01E9 +1214 2258 25 + +# fountain +StoneFountainAddon 0x173A +1233 2219 0 + +# fork +Fork 0x09F4 +1128 2218 43 + +# pillow +Static 0x13AC +1129 2217 62 + +# cypress tree +Static 0x0CFE +1246 2200 0 + +# vines +Static 0x0C5F +1249 2173 0 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016380) +1252 2145 9 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016196) +1260 2316 9 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016385) +1260 2313 11 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016231) +1268 2190 7 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016412) +1284 2256 6 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016379) +1072 2322 7 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016382) +1128 2313 6 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016389) +1184 2316 6 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016378) +1212 2133 6 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016195) +1132 2145 8 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016125) +1024 2157 5 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016388) +1028 2238 7 + +# sign +LocalizedSign 0x1F28 (LabelNumber=1016109) +1028 2307 2 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +1131 2237 40 +1131 2237 50 + +# candelabra +CandelabraStand 0x0B26 +1132 2216 40 +1138 2231 40 +1166 2232 60 +1160 2209 40 + +# armoire +FancyArmoire 0x0A51 +1132 2231 40 +1132 2230 40 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +1132 2237 40 +1132 2237 50 + +# book +Static 0x1E20 +1133 2235 24 +1137 2221 64 +1164 2206 62 +1164 2236 60 + +# books +Static 0x1E21 +1135 2235 24 +1136 2230 44 +1163 2234 60 +1132 2227 46 +1162 2206 62 +1164 2208 41 +1164 2243 46 + +# plate +Plate 0x09D7 +1136 2219 44 +1134 2219 44 +1129 2218 43 +1129 2218 44 +1133 2220 44 + +# bookcase +FullBookcase 0x0A9B +1135 2225 40 + +# garbage +Static 0x10EF +1136 2220 44 +1163 2236 61 +1161 2209 41 +1129 2235 40 +1130 2217 40 +1165 2206 0 +1166 2235 40 + +# chair +FancyWoodenChairCushion 0x0B50 +1133 2221 40 +1136 2221 40 +1134 2221 40 +1135 2221 40 + +# books +Static 0x1E22 +1138 2222 64 +1165 2243 46 + +# glass +Static 0x1F83 +1132 2221 64 + +# pitcher of wine +Static 0x1F9B +1133 2221 64 + +# garbage +Static 0x10F1 +1134 2220 44 +1137 2234 40 +1163 2209 0 +1164 2207 41 + +# pile of garbage +Static 0x10F2 +1159 2234 21 + +# wall torch +Static 0x0A05 +1160 2206 54 + +# garbage +Static 0x10EE +1161 2235 21 +1138 2217 40 +1166 2237 40 + +# skull with candle +Static 0x1853 +1163 2207 41 + +# debris +Static 0x0C2E +1163 2236 61 +1165 2245 40 + +# dirt +Static 0x1DFD +1163 2240 40 + +# garbage +Static 0x10F0 +1164 2234 61 +1130 2217 40 +1161 2205 0 + +# sparkle +Static 0x375A +1165 2204 40 +1166 2237 62 +1163 2204 60 + +# broken chair +Static 0x0C1B +1165 2241 40 + +# Red Potion +Static 0x0F0B +1138 2223 64 + +# lilypad +Static 0x0D09 +1248 2200 1 + +# pear%s% +Static 0x172D +1207 2270 0 +1207 2269 0 +1205 2268 0 +1206 2270 0 + +# open sack of flour +Static 0x1046 +1130 2219 40 + +# dirt patch +Static 0x0914 +1083 2266 0 +1041 2248 0 + +# grave +Static 0x0EE1 +1083 2265 0 +1041 2247 0 + +# leaves +Static 0x1B24 (Hue=0x970) +1084 2265 0 +1042 2247 0 + +# grave +Static 0x0EE0 +1084 2266 0 +1042 2248 0 + +# leaves +Static 0x1B23 (Hue=0x970) +1084 2267 0 +1042 2249 0 + +# grave +Static 0x0ED3 +1083 2267 0 +1041 2249 0 + +# leaves +Static 0x1B26 (Hue=0x970) +1082 2267 0 +1040 2249 0 + +# bucket +Static 0x14E0 +1129 2238 40 +1138 2238 40 + +# coconut%s% +Static 0x1726 +1097 2193 0 +1092 2188 0 +1100 2191 0 +1101 2193 0 +1100 2193 0 +1090 2192 0 +1092 2192 0 +1090 2189 0 +1099 2191 0 + +# leaves +Static 0x1B25 (Hue=0x970) +1082 2265 0 +1040 2247 0 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +1162 2233 40 + +# apple%s% +Static 0x09D0 +1053 2228 0 +1052 2231 0 +1201 2263 0 +1202 2265 0 +1204 2265 0 +1204 2266 0 +1054 2228 0 +1054 2227 0 +1200 2265 0 +1052 2228 0 + +# metal chest +MetalChest 0x09AB +1213 2259 5 + +# book +Static 0x0FBD +1064 2202 10 + +# fireplace +StoneFireplaceEastAddon 0x0959 +1128 2216 40 +1128 2216 60 + +# blood +Static 0x122B +1115 2231 4 + +# blood +Static 0x122A (Hue=0x1) +1041 2248 0 + +# grave +Static 0x0EE2 +1040 2248 0 +1082 2266 0 + +# wedge%s% of cheese +Static 0x097C +1132 2221 64 + +# banana%s% +Static 0x1720 +1133 2222 64 + +# bunch%es% of dates +Static 0x1727 +1166 2280 0 +1165 2279 0 + +# wooden chest +WoodenChest 0x0E42 +1067 2268 5 +1134 2226 40 + +# wooden chest +WoodenChest 0x0E43 +1073 2195 5 + +# peach%es% +Static 0x09D2 +1193 2271 0 +1196 2271 0 +1197 2268 0 +1195 2269 0 + +# pizza%s% +Static 0x1040 +1136 2216 46 + +# barrel +Barrel 0x0E77 +1160 2204 0 + +# empty tub +Static 0x0E83 +1164 2205 0 + +# glass of water +Static 0x1F91 +1133 2221 64 + +# empty bottle%s% +Static 0x0F0E +1165 2234 63 +1132 2235 26 + +# heating stand +Static 0x184E +1161 2208 41 + +# glass +Static 0x1F81 +1133 2221 64 + +# dagger +Static 0x0F52 +1134 2235 23 + +# dagger +Static 0x0F51 +1129 2232 20 + +# wooden door +DarkWoodDoor 0x06B1 (Facing=SouthCCW) +1131 2228 40 +1135 2219 60 +1139 2236 40 + +# glass of water +Static 0x1F93 +1132 2221 64 +1133 2222 64 + +# pitcher of water +Static 0x1F9D +1133 2221 64 + +# armoire +Armoire 0x0A4F +1131 2216 60 + +# iron ore +Static 0x19B8 +1129 2223 20 + +# bulletin board +BulletinBoard 0x1E5E +1141 2234 40 + +# wooden door +DarkWoodDoor 0x06B3 (Facing=NorthCW) +1139 2235 40 + +# metal door +MetalDoor 0x0683 (Facing=NorthCW) +1140 2228 20 + +# wand +Static 0x0DF2 +1137 2221 66 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +1135 2230 44 + +# book +RedBook 0x0FF1 +1161 2207 41 +1164 2232 60 + +# books +Static 0x1E23 +1136 2229 44 + +# bucket of water +Static 0x0FFA +1129 2238 40 +1138 2238 40 + +# apple tree +Static 0x0D96 +1202 2265 0 +1054 2229 0 + +# bookcase +FullBookcase 0x0A99 +1064 2206 5 +1064 2206 17 +1064 2205 5 +1064 2204 17 +1064 2203 5 + +# alchemical symbol +Static 0x1822 +1163 2208 0 + +# bookcase +FullBookcase 0x0A9A +1064 2205 17 +1064 2204 5 +1064 2203 17 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +1132 2222 64 + +# cut%s% of raw ribs +Static 0x09F1 +1134 2216 46 + +# Yellow Potion +Static 0x0F0C +1163 2210 3 + +# Black Potion +Static 0x0F06 +1165 2233 63 + +# Blue Potion +Static 0x0F08 +1165 2235 63 + +# bed +LargeBedSouthAddon 0x0A83 +1133 2216 60 + +# chair +Static 0x0B4F +1136 2218 40 +1133 2218 40 +1134 2218 40 +1135 2218 40 + +# ham%s% +Static 0x09D3 +1133 2216 46 + +# flowerpot +PottedPlant 0x11CA +1138 2233 40 + +# pan of cookies +Static 0x160B +1135 2216 46 + +# broken chair +Static 0x0C1A +1163 2243 40 +1161 2240 40 + +# pewter mug +PewterMug 0x1000 +1164 2235 46 + +# debris +Static 0x0C2F +1164 2235 60 + +# pewter mug +PewterMug 0x1001 +1164 2236 46 + +# A Daemon Summoning Scroll +LocalizedStatic 0x1F69 (LabelNumber=1016017) +1165 2204 60 + +# pillow +Static 0x163B +1130 2216 62 +1129 2217 62 + +# wand +Static 0x0DF5 +1134 2218 65 + +# silverware +Static 0x09BE +1136 2219 44 +1134 2219 44 + +# small palm +Static 0x0C99 +1061 2248 0 + +# grasses +Static 0x0CAE +1063 2209 0 + +# clock +Static 0x104B +1064 2202 19 + +# chair +WoodenChair 0x0B58 +1065 2202 5 +1065 2207 5 + +# globe +Static 0x1047 +1068 2199 16 + +# tile roof +Static 0x05B4 +1070 2197 47 + +# hedge +Static 0x0DB8 +1082 2219 0 + +# coconut palm +Static 0x0C95 +1091 2190 0 +1099 2191 0 + +# orfluer flowers +Static 0x0C85 +1123 2165 0 + +# wedge%s% of cheese +Static 0x097D +1131 2216 46 + +# fork +Fork 0x09A3 +1128 2218 43 + +# potted tree +PottedTree1 0x11C9 +1128 2236 40 + +# kettle +Static 0x09ED +1129 2216 40 + +# pillow +Static 0x13AE (Hue=0xE8) +1129 2216 61 + +# knife +Knife 0x09F6 +1129 2218 44 + +# knife +Knife 0x09F7 +1129 2218 44 + +# stone pavers +Static 0x051D +1129 2230 20 +1132 2228 20 + +# pilllow +Static 0x163A +1130 2217 61 + +# tray +Static 0x0991 +1131 2216 46 + +# frypan +Static 0x09E2 +1131 2217 46 + +# spilled flour +Static 0x1881 +1131 2219 40 + +# candelabra +Static 0x0B1F +1132 2216 66 + +# pitcher +Static 0x09D6 +1132 2219 44 + +# glass of wine +Static 0x1F8F +1132 2221 64 +1133 2222 64 + +# brazier +Brazier 0x0E31 +1132 2223 23 + +# bed +Static 0x0A7F +1133 2217 60 + +# silverware +Static 0x09D4 +1133 2220 44 + +# tray +Static 0x0992 +1133 2220 64 + +# glass pitcher +Static 0x0FF6 +1133 2221 64 + +# stone +Static 0x071E +1133 2223 18 + +# bed +Static 0x0A82 +1134 2216 60 + +# bed +Static 0x0A7E +1134 2217 60 + +# folded sheet +Static 0x0A93 +1134 2218 64 + +# folded blanket +Static 0x0A6F +1134 2225 40 + +# chair +WoodenChair 0x0B56 +1134 2229 40 +1134 2230 40 +1136 2221 60 +1136 2223 60 + +# books +Static 0x1E24 +1135 2229 44 + +# goblet +Static 0x09BF +1135 2230 44 + +# chair +WoodenChair 0x0B57 +1136 2228 40 + +# goblet +Static 0x09B3 +1136 2229 44 + +# lantern +Static 0x0A25 +1132 2227 46 + +# candelabra +Static 0x0B27 +1137 2216 40 +1138 2223 40 + +# crystal ball +Static 0x0E2D +1137 2222 66 + +# pile of garbage +Static 0x10F3 +1138 2216 40 + +# chair +WoodenChair 0x0B59 +1138 2224 65 + +# books +Static 0x1E25 +1138 2225 46 + +# candelabra +Static 0x0B28 +1138 2226 40 + +# water trough +WaterTroughSouthAddon 0x0B43 +1140 2238 40 + +# swamp +Static 0x326F +1150 2276 -1 + +# empty vials +Static 0x185B +1160 2207 40 +1164 2210 46 + +# broken clock +Static 0x0C1F +1160 2240 48 + +# ruined painting +Static 0x0C2C +1161 2232 60 + +# dirt +Static 0x1DFE +1161 2239 40 + +# scales +Scales 0x1851 +1162 2210 46 + +# broken chair +Static 0x0C19 +1162 2234 40 + +# mud +Static 0x1E02 +1162 2239 40 +1162 2240 40 + +# book +BurningOfTrinsic 0x0FF4 +1163 2206 62 + +# mortar and pestle +Static 0x0E9B +1163 2208 41 + +# full vials +Static 0x185D +1163 2210 46 + +# ruined bookcase +Static 0x0C14 +1163 2232 40 + +# switch +Static 0x108F +1129 2230 30 + +# broken chair +Static 0x0C1C +1163 2236 40 + +# dirt +Static 0x1DFF +1163 2239 40 + +# goblet +Static 0x09CB +1164 2234 46 + +# broken chair +Static 0x0C1E +1164 2237 40 + +# debris +Static 0x0C2D +1164 2241 40 + +# flask stand +Static 0x1829 +1165 2210 46 + +# broken furniture +Static 0x0C24 +1165 2232 40 + +# banner +Static 0x15AA +1165 2232 60 + +# damaged books +Static 0x0C16 +1165 2233 40 +1165 2244 46 + +# broken chair +Static 0x0C1D +1165 2234 40 +1166 2243 40 + +# banner +Static 0x15AB +1166 2232 60 + +# bookcase +FullBookcase 0x0A9C +1160 2208 40 diff --git a/Data/Decoration/Britannia/_hythloth.cfg b/Data/Decoration/Britannia/_hythloth.cfg new file mode 100644 index 0000000..f85e11c --- /dev/null +++ b/Data/Decoration/Britannia/_hythloth.cfg @@ -0,0 +1,2000 @@ +####################### +# Special teleporters # +####################### + +# teleporter +Teleporter 0x1BC3 (PointDest=(5970, 147, 22)) +5926 145 22 +5926 146 22 +5926 147 22 +5926 148 22 +5926 149 22 +5933 146 22 +5933 145 22 +5933 149 22 +5944 148 22 +5944 147 22 +5944 146 22 +5944 145 22 +5944 144 22 +5955 148 22 +5955 146 22 +5955 145 22 +5955 144 22 +5955 149 22 +5955 150 22 +5963 146 22 +5963 145 22 +5963 144 22 +5933 147 22 +5963 148 22 +5963 147 22 + +# teleporter +Teleporter 0x1BC3 (PointDest=(6041, 204, 22)) +6044 226 44 + +# teleporter +Teleporter 0x1BC3 (PointDest=(6050, 227, 44)) +6039 204 22 + +# teleporter +Teleporter 0x1BC3 (PointDest=(6107, 176, 0)) +6115 176 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(6124, 155, 0)) +6107 179 0 + + +############### +# Decorations # +############### + +# crate +LargeCrate 0x0E3D +5948 216 22 +5904 109 0 +5979 24 22 +6044 195 21 +5922 229 44 +6060 101 28 +5987 47 22 +5916 60 22 +5989 26 22 +5913 57 22 +5965 227 22 +5930 74 0 +5961 56 0 +5966 66 0 +6080 93 22 +5985 47 22 +6085 93 25 +5986 184 44 +5988 46 22 +6026 196 22 +6060 101 25 +6061 101 22 +6062 101 25 +5918 91 0 +5919 236 44 +6080 91 22 +6085 94 22 + +# metal chest +MetalChest 0x09AB +5987 186 44 +6044 221 44 +5961 71 0 +6081 44 22 +5943 67 0 +6100 35 27 +6037 199 22 +6040 230 44 +5997 56 22 +5976 83 0 +6057 40 0 +6034 204 22 +6108 34 22 +6056 161 0 +6053 40 0 +6088 170 0 +6085 88 22 + +# small crate +SmallCrate 0x09A9 +5925 84 0 +5987 35 22 +5915 54 22 +5989 40 22 +5965 222 25 +6122 166 0 +6084 92 25 +6043 230 44 +5994 144 3 +6061 101 25 +5910 106 0 +5908 51 22 + +# crate +MediumCrate 0x0E3E +5967 74 0 +5987 81 0 +5984 32 22 +6056 97 22 +6056 98 22 +6056 98 25 +6080 90 22 +6080 91 25 +6080 92 25 +6080 93 25 +5947 216 22 +6056 99 22 +5961 79 0 +5984 149 0 +5965 222 22 +6104 93 0 +5989 185 44 + +# wooden chest +WoodenChest 0x0E42 +5965 216 22 +5912 237 44 +6068 97 22 +6080 184 0 +5944 233 22 +5931 84 0 + +# wooden chest +WoodenChest 0x0E43 +6120 160 0 +5988 188 44 +6109 42 22 +5913 229 44 +5974 84 0 +5976 191 44 +6110 68 0 +6069 92 22 +6059 157 0 +6083 40 22 +6080 40 22 +5948 66 0 +5993 149 0 +6122 229 22 +5905 108 0 +6037 203 22 +6085 88 22 +5917 234 44 +5929 71 0 +6117 227 22 + +# saw +Static 0x1034 +5952 230 28 + +# fitting +Static 0x112B +5953 200 22 +5956 200 22 +5954 200 22 +5955 200 22 +5957 200 22 +6107 152 -22 + +# scroll%s% +Static 0x0E37 +5953 213 22 +5936 188 22 +5959 217 22 + +# armoire +Armoire 0x0A53 +6112 211 22 + +# heart +Static 0x1CED +5954 228 28 +5961 225 28 +6059 69 0 +6112 226 28 +5949 226 28 + +# metal chest +MetalGoldenChest 0x0E40 +6109 93 0 +5978 171 0 +6026 198 22 +6054 159 0 +6104 82 0 +6108 70 0 +6089 172 0 +5926 81 0 +5989 188 44 +5989 169 0 +5966 69 0 +6115 223 22 +5976 194 44 + +# flask stand +Static 0x1829 +6112 80 6 + +# wooden box +Static 0x0E7D +6113 227 28 +5976 189 47 + +# barred metal door +BarredMetalDoor 0x0687 (Facing=EastCCW) +6115 87 0 +6107 87 0 + +# barred metal door +BarredMetalDoor 0x0685 (Facing=WestCW) +6114 87 0 +6106 87 0 +5980 28 22 +5989 28 22 +5985 28 22 + +# floor saw +SawTrap 0x11AC +6068 63 0 +5967 152 0 +5962 154 0 +5915 96 0 +6065 63 0 +6071 63 0 +6070 63 0 +5988 32 22 +6039 201 22 +6066 63 0 +6067 63 0 +6069 63 0 + +# bottle +Static 0x0EFD +6113 80 6 + +# thigh boots +Static 0x1712 +5952 238 22 +5959 222 22 + +# sledge hammer +Static 0x0FB4 +5958 226 28 + +# hammer +Static 0x102A +5952 226 28 + +# butcher knife +Static 0x13F6 +5957 217 22 +5983 174 0 +5926 240 44 +5944 147 22 + +# skinning knife +Static 0x0EC4 +5955 221 22 + +# metal door +MetalDoor2 0x06C9 (Facing=WestCCW) +5955 215 22 +6082 87 22 +6061 42 0 +6049 42 0 +5987 55 22 +6069 87 22 +5994 95 0 +5914 95 0 + +# metal door +MetalDoor2 0x06CB (Facing=EastCW) +5956 215 22 +6070 87 22 +5915 95 0 +6050 42 0 +6083 87 22 +6062 42 0 +5988 55 22 +5995 95 0 + +# gnarled staff +Static 0x13F9 +5956 214 22 +5978 193 44 +5924 240 44 +5926 213 22 +5948 223 22 +5949 176 0 +5946 173 0 +5916 225 44 +5915 184 22 + +# leather gorget +Static 0x13C7 +5952 210 22 + +# metal chest +MetalGoldenChest 0x0E41 +5909 101 0 +6121 152 0 +6122 154 0 +6119 208 22 +6082 42 22 +5910 110 0 +6121 208 22 +6124 152 0 +5922 86 0 + +# barrel +Static 0x0FAE +5953 176 0 +5978 200 44 +5976 200 44 +5924 229 44 +5944 170 0 +5965 223 22 +5989 221 44 + +# kite shield +Static 0x1B74 +5952 165 0 +5968 219 22 +5933 201 22 +5916 226 44 +5942 147 22 +5961 196 22 +5963 156 0 +5959 233 22 +5930 221 44 + +# buckler +Static 0x1B73 +5959 155 0 +5977 202 44 +5980 184 44 +5971 176 0 +5914 169 22 + +# broadsword +Static 0x0F5E +5953 157 0 + +# ringmail leggings +Static 0x13F0 +5952 153 0 + +# blank scroll%s% +Static 0x0EF3 +5960 209 22 +5952 145 22 + +# barred metal door +BarredMetalDoor 0x0693 (Facing=NorthCW) +6103 67 0 + +# barred metal door +BarredMetalDoor 0x0691 (Facing=SouthCCW) +6103 68 0 + +# bloody water +Static 0x0E23 +5960 227 28 +6114 81 6 +5958 225 28 +5947 225 26 + +# skeleton +Static 0x1B7F +6059 64 0 + +# candelabra +CandelabraStand 0x0B26 +5989 29 22 +6048 53 0 +6061 40 0 +6106 42 27 +5912 227 44 +6125 229 22 +6048 43 0 +5976 29 22 +6062 54 0 +5994 68 28 +6100 42 27 +6117 208 22 +5990 56 22 +6112 215 22 + +# small web +Static 0x10D4 +5961 144 22 +5915 48 22 +5930 48 22 +5975 168 0 +5980 216 44 +5984 144 0 +5984 80 0 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +5967 236 22 +5959 28 0 +5927 220 44 +6087 156 -22 +6111 220 22 +5951 99 22 +5919 156 22 +5919 52 22 +6079 172 0 +5911 28 44 +6063 52 0 +6047 204 22 + +# metal door +MetalDoor2 0x06CF (Facing=NorthCCW) +5967 235 22 +5959 27 0 +5927 219 44 +6063 51 0 +6087 155 -22 +6111 219 22 +5951 98 22 +5919 155 22 +5919 51 22 +6079 171 0 +5911 27 44 +6047 203 22 + +# Orange Potion +Static 0x0F07 +6052 155 0 + +# stone stairs +Static 0x07A6 +5961 46 17 + +# torch%es% +Static 0x0F64 +6062 90 22 + +# crate +SmallCrate 0x0E7E +5983 81 0 +6063 101 25 +5982 84 0 +5908 53 22 +5974 81 0 +5916 58 22 +6060 101 31 +6080 90 25 +6084 93 25 +5932 65 0 +5958 68 0 +6085 93 25 + +# gas trap +GasTrap 0x113C +5952 78 22 +5963 88 0 + +# bag +Bag 0x0E76 +5949 228 22 + +# crate +MediumCrate 0x0E3F +5972 172 0 +5984 24 22 +6084 92 22 +5989 30 22 +6060 102 22 +5985 184 44 +6045 196 22 +5984 154 0 +5914 93 0 + +# cleaver +Static 0x0EC3 +5946 171 0 +5920 184 22 +5948 225 26 +5944 218 22 +5944 148 22 +5937 180 22 + +# floor spikes +SpikeTrap 0x11A0 +5962 217 22 +5947 76 22 +5944 225 22 + +# water barrel +Static 0x154D +5907 16 44 +6057 206 22 + +# keg +Keg 0x0E7F +6041 224 44 +6040 227 44 +5944 169 0 +5944 168 0 +5908 28 44 +5904 27 44 +5908 17 44 +5988 221 44 +5988 220 44 +5931 48 22 +6033 204 22 + +# barrel +Barrel 0x0E77 +6040 226 44 +6057 101 22 +5977 201 44 +6032 201 22 +5952 176 0 +5959 237 22 +5915 92 0 +6056 100 22 +6056 101 22 +5985 173 0 +5912 231 44 +5917 60 22 +5907 16 44 +5965 225 22 +5965 224 22 +6056 96 22 +6069 100 22 +6069 101 22 +6032 202 22 +6032 204 22 +6032 205 22 +6033 205 22 +6034 205 22 +6040 225 44 +5908 19 44 +6084 93 22 + +# cocoon +Static 0x10DC +5981 24 22 +5940 96 22 + +# clean bandage%s% +Static 0x0E21 +5960 225 28 + +# quarter staff +Static 0x0E89 +5978 238 22 +5912 191 22 +5963 183 1 + +# leather sleeves +Static 0x13C5 +5981 228 44 + +# metal chest +Metalchest 0x0E7C +6065 97 22 +6084 176 0 +6085 42 22 +6040 223 44 +5977 187 44 +6079 40 22 +6120 152 0 +6040 221 44 +5980 188 44 +6057 162 0 +6108 68 0 + +# gnarled staff +Static 0x13F8 +5992 175 0 +5960 179 0 +5974 147 22 +5931 190 22 + +# studded tunic +Static 0x13DB +5995 158 0 +5966 231 22 + +# crossbow +Static 0x0F50 +5977 206 44 + +# garbage +Static 0x10EF +5985 33 22 +5912 50 22 +5912 59 22 +5917 26 44 +5923 35 44 +5924 25 44 +5924 44 -40 +5925 44 22 +5938 105 22 +5938 109 22 +5941 103 22 +5945 108 22 +5972 51 22 +5987 149 0 +5987 153 0 +5988 158 0 +5988 40 22 +5989 161 0 +5989 167 0 +5990 146 0 +5993 154 0 +5995 104 0 +5995 147 0 +5996 100 0 +5974 172 15 + +# pickaxe +Static 0x0E86 +5976 186 44 +5919 222 44 + +# pouch +Static 0x0E79 +5922 229 47 + +# garbage +Static 0x10F1 +5987 147 0 +5993 102 0 +5997 101 0 +5913 28 44 +5924 25 44 +5924 31 44 +5924 42 22 +5932 51 22 +5936 49 22 +5938 101 22 +5939 107 22 +5940 101 22 +5940 103 22 +5942 102 22 +5943 103 22 +5945 101 22 +5945 98 22 +5946 105 22 +5947 104 22 +5947 106 22 +5947 52 22 +5948 97 22 +5955 98 22 +5956 89 22 +5957 97 22 +5976 50 22 +5979 172 0 +5983 51 22 +5985 33 22 +5985 44 22 +5987 154 0 +5987 172 0 +5990 148 0 +5990 154 0 +5993 147 0 +5993 154 0 +5995 151 0 +6108 90 0 +6112 90 0 + +# carrot%s% +Static 0x0C77 +5989 104 6 + +# metal door +MetalDoor2 0x06C7 (Facing=EastCCW) +5988 31 22 +6083 47 22 +6100 47 22 +5987 207 44 +5988 159 0 +6060 167 0 + +# Blood Moss +Static 0x0F7B +2678 712 0 + +# garbage +Static 0x10F0 +5988 46 22 +5914 26 44 +5917 29 44 +5922 37 44 +5924 25 44 +5925 44 22 +5936 49 22 +5938 51 22 +5939 106 22 +5941 108 22 +5943 100 22 +5943 99 22 +5945 102 22 +5946 104 22 +5947 106 22 +5955 92 22 +5955 98 22 +5975 52 22 +6116 90 0 +5985 36 22 +5986 162 0 +5986 163 0 +5987 163 0 +5997 100 0 +5968 172 15 +6107 92 0 + +# crate +LargeCrate 0x0E3C +6063 101 22 +5977 30 22 +5994 144 0 +5976 189 44 +6080 92 22 +6080 93 22 +6085 93 22 +5986 33 22 +5982 29 22 +6045 195 22 +6060 101 22 +6061 102 22 +6062 101 22 +5958 67 0 +6064 101 22 +6064 101 25 +5929 76 0 +6080 90 22 +6080 91 22 +6085 92 22 +6084 93 22 + +# wand +Static 0x0DF3 +5921 226 44 +5966 174 0 + +# platemail arms +Static 0x1417 +5921 222 44 + +# plate helm +Static 0x1419 +5925 203 22 + +# close helm +Static 0x1409 +5925 200 22 +5926 169 1 + +# stone +Static 0x07A3 +5904 16 59 +5905 16 59 +5906 16 59 +6040 217 59 +6103 32 22 + +# broken armoire +Static 0x0C12 +5904 50 22 + +# stone pavers +Static 0x0522 +5904 97 0 +6044 226 44 + +# pitchfork +Static 0x0E87 +5926 158 22 +5990 144 0 + +# platemail gloves +Static 0x1414 +5923 155 22 + +# stone pavers +Static 0x0524 +5905 96 0 +5973 169 0 +6107 179 0 + +# stone pavers +Static 0x0523 +5905 97 0 + +# sparkle +Static 0x376A +5905 97 0 +5973 169 0 + +# stone stairs +Static 0x07A4 +5906 17 59 +5905 17 59 +5904 17 59 + +# ruined painting +Static 0x0C2C +5906 48 22 + +# candlabra +CandelabraStand 0x0A29 +6048 43 0 +6062 54 0 +5989 29 22 +5990 56 22 +6112 215 22 + +# pelvis bone +Static 0x1B16 +6057 67 0 +6058 68 0 + +# jaw bone +Static 0x1B14 +6059 67 0 + +# bottle +Static 0x0E2C +5993 65 28 + +# metal door +MetalDoor2 0x06D1 (Facing=SouthCCW) +6103 84 0 +6103 180 0 + +# barred metal door +BarredMetalDoor 0x068D (Facing=SouthCW) +6063 67 0 + +# barred metal door +BarredMetalDoor 0x068F (Facing=NorthCCW) +6063 66 0 + +# bones +Static 0x0ED0 +6058 66 0 +6106 68 0 + +# sheets +Static 0x0C33 +5908 48 22 + +# pan of cookies +Static 0x160B +5989 105 6 + +# pizza%s% +Static 0x1040 +5990 103 6 + +# ham%s% +Static 0x09C9 +5991 105 6 + +# debris +Static 0x0C2D +5910 49 22 +5985 145 0 +5986 160 0 +5996 68 22 +5997 97 0 + +# debris +Static 0x0C2E +5910 50 22 +5956 50 22 +5979 168 0 +5984 145 0 +5996 67 22 +5997 98 0 + +# head +Static 0x1CE9 +6035 198 22 +6119 218 32 + +# wall torch +Static 0x0A05 +5912 203 37 + +# gold belt +Static 0x1536 +5912 206 22 + +# stone pavers +Static 0x0521 +6039 204 22 +5904 96 0 + +# covered chair +Static 0x0C17 +5912 48 22 + +# stone face +StoneFaceTrap 0x10FC +5913 101 0 +5909 101 0 + +# scroll%s% +Static 0x0E39 +5913 163 22 +5920 224 44 +5956 208 22 + +# statue +Static 0x1226 +5913 240 44 + +# stone stairs +Static 0x07A5 +5922 168 4 +5922 169 4 +5922 170 4 +5923 168 -1 +5923 169 -1 +5923 170 -1 + +# open sack of flour +Static 0x103A +5990 108 0 + +# garbage +Static 0x10EE +5913 50 22 +5913 59 22 +5922 29 44 +5924 25 44 +5924 41 44 +5924 42 -40 +5924 43 22 +5925 44 -40 +5937 109 22 +5938 99 22 +5939 100 22 +5944 104 22 +5945 108 22 +5947 97 22 +5948 99 22 +5967 50 22 +5985 148 0 +5985 170 0 +5985 33 22 +5988 52 22 +5997 100 0 +5997 99 0 +5965 171 15 +5948 97 22 + +# bench +Static 0x0B66 +5914 229 44 + +# scroll%s% +Static 0x0E36 +5915 169 22 +5961 197 22 +5991 224 44 + +# bench +Static 0x0B65 +5915 229 44 + +# skull with candle +Static 0x1856 +6061 48 6 +5993 59 28 +5993 66 28 + +# dungeon wall +Static 0x02FA +6046 195 21 + +# lever +Static 0x1095 +5985 37 22 +5987 37 22 +5985 34 22 +5987 34 22 + +# rock +Static 0x1772 +6109 155 -22 +6110 155 -22 +6106 152 -22 +6107 154 -22 +6107 152 -22 +6106 154 -22 +6106 153 -22 +6111 152 -22 +6110 152 -22 +6110 154 -22 +6109 153 -22 +6109 152 -22 +6108 153 -22 +6108 152 -22 +6110 153 -22 +6109 154 -22 +6105 152 -22 +6108 155 -22 +6109 156 -22 +6110 156 -22 +6110 157 -22 +6107 152 -23 +6107 153 -22 +6108 154 -22 + +# roast pig%s% +Static 0x09BC +5991 82 6 + +# leg +Static 0x1CE2 +6053 160 0 + +# pile of garbage +Static 0x10F2 +5917 48 22 +5942 96 22 +5997 96 0 + +# scroll%s% +Static 0x0E38 +5918 228 44 + +# body part +Static 0x1CEA +6056 161 0 + +# wand +Static 0x0DF2 +5947 240 22 +5970 156 7 +5934 224 44 + +# small web +Static 0x10D7 +5920 144 22 +5944 166 0 +5952 93 22 +5976 83 0 +5995 144 0 + +# dungeon wall +Static 0x0241 +5920 167 0 +5920 167 22 +5921 167 0 +5921 167 22 +5922 167 0 +5922 167 22 +5923 167 0 +5924 167 0 +5924 167 22 +5925 167 22 +5926 167 22 +5926 167 3 +5927 228 44 +5991 71 22 +5993 71 22 +5994 71 22 +6068 87 22 +5923 167 22 +5925 167 0 + +# arm +Static 0x1CE5 +6057 154 0 +6053 155 0 + +# wall torch +Static 0x0A0A +5922 200 37 + +# scroll%s% +Static 0x0EF6 +5922 232 44 +5949 166 0 + +# pile of garbage +Static 0x10F3 +5922 40 22 +5949 96 22 +5984 145 1 + +# Mandrake Root%s% +Static 0x0F86 +2682 679 0 + +# bones +Static 0x0ECF +5948 229 22 +5948 97 22 + +# lever +Static 0x1093 +5985 37 22 +5985 34 22 +5987 34 22 +5987 37 22 + +# floor spikes +SpikeTrap 0x119A +5973 236 22 +5956 66 0 +5968 233 22 +6040 204 22 +6040 199 22 +6033 202 22 + +# pen and ink +Static 0x0FC0 +6060 47 6 +5948 221 34 +6107 83 6 + +# bones +Static 0x0ECE +5945 216 22 + +# dungeon wall +Static 0x0242 +5927 228 44 + +# bascinet +Static 0x140D +5950 166 0 + +# heating stand +HeatingStand 0x184A +5994 58 30 +6108 82 6 +5945 219 34 + +# scroll%s% +Static 0x0EF7 +5934 222 44 +5962 204 22 + +# dungeon arch +Static 0x024A +6067 87 22 +6067 83 22 + +# small web +Static 0x10D5 +5936 109 22 +5952 101 22 +5957 73 22 + +# ham%s% +Static 0x09D3 +5991 83 6 +5990 81 6 + +# web +Static 0x10BD +5939 103 22 + +# cocoon +Static 0x10DA +5939 96 22 + +# web +Static 0x10BE +5940 102 22 + +# bracelet +Static 0x1086 +5940 148 22 +5949 231 22 +5964 173 0 +5984 221 44 + +# web +Static 0x10BF +5941 101 22 + +# web +Static 0x10C0 +5942 100 22 + +# cave floor +Static 0x053E +5943 176 22 +5943 180 22 +5943 181 22 + +# cave floor +Static 0x053B +5943 177 22 +5943 178 22 +5957 51 22 +5957 52 22 + +# cave floor +Static 0x053C +5943 179 22 +5945 173 0 +5945 175 0 +5945 176 0 + +# small web +Static 0x10D3 +5943 96 22 +5952 200 22 +5971 73 0 +5984 154 0 +5986 200 44 + +# web +Static 0x10C1 +5943 99 22 + +# cave floor +Static 0x053D +5944 173 0 +5945 174 0 + +# crystal ball +Static 0x0E2D +5944 222 22 +5949 147 22 +5961 223 22 +5922 170 9 + +# entrails +Static 0x1CEF +6058 160 0 +6118 228 22 + +# dyeing tub +DyeTub 0x0FAB +5945 216 22 + +# flask +Static 0x1844 +5945 219 34 +6108 82 6 +5990 105 6 + +# empty vials +Static 0x185C +5945 220 34 +5993 62 28 +6109 80 6 + +# skull with candle +Static 0x1855 +5945 222 34 +5950 219 34 +5987 63 34 +5987 67 34 +6112 224 28 + +# tribal mask +Static 0x154B +5974 236 22 + +# full jars +Static 0x0E49 +5946 220 34 + +# flask +Static 0x1837 +5946 222 34 + +# scroll%s% +Static 0x0EF4 +5946 228 22 + +# necklace +Static 0x1088 +5972 173 0 +5913 234 44 +5988 205 44 +5984 158 0 + +# ring +Static 0x108A +5971 168 0 +5919 222 44 +5961 200 22 + +# stool +Stool 0x0A2A +5947 220 28 + +# full jar +Static 0x1006 +5947 222 34 + +# web +Static 0x10D1 +5948 101 22 + +# brain +Static 0x1CF0 +5948 233 28 +5949 229 28 + +# studded sleeves +Static 0x13D4 +5968 145 22 +5915 227 44 +5919 204 22 + +# web +Static 0x10D0 +5949 100 22 + +# scales +Scales 0x1851 +5949 219 34 +6108 80 6 +6112 227 28 + +# full vials +Static 0x185E +5949 222 34 +5993 60 28 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +6031 198 22 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +6031 197 22 + +# empty jars +Static 0x0E44 +5950 220 34 + +# blood +Static 0x122B +5950 222 22 +5986 102 6 +6124 212 22 + +# blood smear +Static 0x122F +5950 226 22 +5986 103 6 +5909 105 0 + +# dovetail saw +Static 0x1029 +5950 226 28 + +# torso +Static 0x1CE0 +5950 233 28 +5963 84 6 +5990 83 6 + +# pelvis bone +Static 0x1B15 +5950 234 28 +5950 225 28 + +# book +Static 0x0FBD +6108 83 6 +5961 228 28 + +# web +Static 0x10CF +5950 99 22 + +# block +Static 0x1273 +5951 218 22 +5986 98 6 + +# blood +Static 0x122C +5951 220 22 +5947 226 22 + +# legs +Static 0x1CE7 +5951 225 28 + +# flask +Static 0x182E +6111 81 6 + +# web +Static 0x10CE +5951 98 22 + +# scroll%s% +Static 0x0EF8 +5953 229 22 +5982 210 44 + +# book +TreatiseOnAlchemy 0x0FEF +6113 225 28 + +# book +ArmsAndWeaponsPrimer 0x0FEF (Name=the life of a travelling minstrel) +5985 66 36 + +# blood +Static 0x122E +5954 227 22 + +# studded gloves +Static 0x13D5 +5914 185 22 + +# flask +Static 0x182F +6114 80 6 +5993 61 28 + +# flask +Static 0x1834 +6115 81 6 + +# flask +Static 0x1832 +6115 83 6 + +# metal door +MetalDoor2 0x06C5 (Facing=WestCW) +6082 47 22 +6099 47 22 +5986 207 44 +5987 159 0 +5987 31 22 +6059 167 0 + +# bloody bandage%s% +Static 0x0E20 +5958 227 28 +5959 224 22 +5959 225 28 + +# hay +Static 0x1036 +5959 228 22 +5963 218 22 +5964 217 22 +5965 218 22 + +# barber scissors +Static 0x0DFD +5959 228 28 + +# kite shield +Static 0x1B78 +5992 158 0 +5995 148 0 +5928 213 44 + +# wooden shelf +EmptyBookcase 0x0A9D +5996 144 0 + +# statue +Static 0x1224 +5960 188 11 + +# chisels +Static 0x1027 +5960 226 28 + +# pen and ink +Static 0x0FBF +5960 228 28 + +# hay +Static 0x1037 +5961 217 22 +5962 223 22 +5963 221 22 + +# mortar and pestle +Static 0x0E9B +5961 226 28 +5994 59 28 +6114 228 28 + +# saw +Static 0x1035 +5961 226 28 + +# glass +Static 0x1F81 +5961 227 28 + +# bottle +Static 0x0E2A +5961 227 28 + +# statue +Static 0x1227 +5964 181 0 + +# blood +Static 0x122D +5964 218 22 + +# head +Static 0x1CE1 +5965 77 6 +5946 225 28 +6113 226 28 + +# scroll%s% +Static 0x0EF5 +5968 197 22 + +# brazier +Brazier 0x0E31 +5971 232 22 + +# egg case web +Static 0x10D8 +5976 24 32 +5986 24 22 + +# egg case +Static 0x10D9 +5976 24 32 +5986 24 22 +5994 60 28 +5994 63 28 + +# altar +Static 0x1216 +5977 25 22 + +# skull with candle +CandleSkull 0x1854 +6113 81 6 + +# foot stool +FootStool 0x0B5E +5980 29 22 + +# web +Static 0x10DD +5981 24 22 + +# small web +Static 0x10D6 +5983 168 0 + +# beef carcass +Static 0x1872 +5984 101 0 +5984 97 0 +5984 99 0 + +# oven +StoneOvenEastAddon 0x092C +5984 104 -1 + +# broken furniture +Static 0x0C25 +5984 156 0 + +# small web +Static 0x10D2 +5984 160 0 + +# bread loa%ves/f% +Static 0x103B +5959 228 28 + +# damaged books +Static 0x0C16 +5985 156 0 + +# flask +Static 0x1847 +5985 63 34 + +# book +TaleOfThreeTribes 0x0FF0 +5985 64 36 + +# book +DiversityOfOurLand 0x0FF4 +5985 65 36 + +# bottle +Static 0x0E2B +5985 66 36 +5993 58 28 + +# block +Static 0x1271 +5986 100 6 + +# chair +WoodenChairCushion 0x0B55 +5986 65 28 + +# sheep carcass +Static 0x1873 +5986 96 0 +5988 96 0 +5991 96 0 + +# block +Static 0x1272 +5986 99 6 + +# block +Static 0x1270 +5987 100 6 + +# +Static 0x1519 +5987 31 22 + +# brazier +Static 0x0E33 +5917 195 22 + +# earrings +Static 0x1087 +5937 149 22 +5960 176 0 +5919 202 22 + +# candelabra +Candelabra 0x0B1D +6103 38 31 + +# bones +Static 0x0ECD +5939 99 22 + +# bones +Static 0x0ECB +5940 98 22 + +# rusty iron key +Static 0x1013 +5987 58 22 + +# body part +Static 0x1CE3 +5987 83 0 + +# block +Static 0x126E +5987 98 6 + +# block +Static 0x126F +5987 99 6 + +# block +Static 0x126B +5988 100 6 + +# hourglass +Static 0x1813 +5988 104 6 +5994 64 28 + +# slab%s% of bacon +Static 0x0977 +5990 80 6 + +# block +Static 0x126D +5988 98 6 + +# block +Static 0x126C +5988 99 6 + +# body +Static 0x1CDE +5989 103 6 + +# wall torch +Static 0x0A0D +5989 184 59 +5908 16 59 +5984 184 59 + +# metal door +MetalDoor2 0x06D3 (Facing=NorthCW) +6103 179 0 +6103 83 0 + +# rolling pin +Static 0x1043 +5990 104 6 + +# floor saw +SawTrap 0x11B1 +5966 96 0 + +# counter +Static 0x0B3F +5990 80 0 +5990 81 0 +5990 82 0 +5990 83 0 +5990 84 0 +5991 80 0 +5991 81 0 +5991 82 0 +5991 83 0 +5991 84 0 + +# flour sifter +Static 0x103E +5991 103 6 + +# kettle +Static 0x09ED +5991 104 6 + +# vines +Static 0x0C60 +5991 80 6 + +# arm +Static 0x1CDD +5991 84 6 + +# bottles of wine +Static 0x09C5 +5992 104 6 + +# ruined bookcase +Static 0x0C14 +5992 144 0 + +# flask +Static 0x1838 +5993 58 28 + +# scales +Static 0x1852 +5993 63 28 + +# bottle +Static 0x0E29 +5993 64 28 + +# flask +Static 0x1843 +5993 64 28 + +# bottle +Static 0x0F00 +5994 61 28 +6115 81 6 + +# flask +Static 0x1836 +5994 65 28 + +# flask +Static 0x1831 +5994 66 28 + +# heating stand +Static 0x184C +5994 66 28 + +# bones +Static 0x0ECC +5944 216 22 + +# crook +Static 0x13F5 +5963 237 22 +5988 164 0 + +# bookcase +FullBookcase 0x0A9B +5960 216 22 + +# bookcase +FullBookcase 0x0A97 +5961 216 22 +5963 216 22 + +# bookcase +FullBookcase 0x0A98 +5962 216 22 + +# club +Static 0x13B4 +5963 178 0 + +# mace +Static 0x0F5C +5967 160 0 + +# stone pavers +Static 0x051D +6041 204 22 +6046 226 44 + +# broken chair +Static 0x0C19 +5905 51 22 +5913 60 22 + +# candelabra +Static 0x0B28 +6048 40 0 + +# skinning knife +Static 0x0EC5 +5947 226 26 + +# cave floor +Static 0x053F +5975 172 16 + +# platemail +Static 0x1415 +5911 183 22 + +# legs +Static 0x1CEB +6060 158 0 + +# book +Static 0x0FBE +6060 48 6 + +# raw bird%s% +Static 0x09B9 +5990 82 6 + +# watermelon%s% +Static 0x0C5C +5990 84 6 + +# sack of flour +Static 0x1039 +5989 109 0 + +# wooden box +Static 0x09AA +6056 98 28 + +# dungeon arch +Static 0x0246 +6067 80 22 +6067 84 22 + +# dungeon arch +Static 0x0248 +6067 81 22 +6067 85 22 +6067 86 22 +6067 82 22 + +# platemail gorget +Static 0x1413 +5984 153 0 + +# wooden shelf +EmptyBookcase 0x0A9E +5984 148 0 + +# studded gorget +Static 0x13D6 +5984 149 0 + +# butcher knife +Static 0x13F7 +5986 104 6 + +# bottle +Static 0x0E26 +6107 80 6 + +# deck%s% of tarot +Static 0x12AB +6114 224 28 + +# bookcase +FullBookcase 0x0A99 +5985 68 28 +5985 62 28 + +# Garlic +Static 0x0F84 +2682 678 0 + +# long pants +Static 0x1539 +5987 31 22 + +# blood +Static 0x1D12 +6086 178 0 + +# skeleton with meat +Static 0x1B1D +6056 67 0 + +# mug of ale +GlassMug 0x09EE +5961 227 28 + +# rock +Static 0x1773 +6106 153 -22 + +# rock +Static 0x1774 +6106 154 -22 + +# rock +Static 0x1771 +6107 154 -22 + +# blood +Static 0x122A +6107 156 -22 + +# stone pavers +Static 0x0520 +6107 176 0 +6115 176 0 +6115 179 0 + +# flask +Static 0x182D +6108 81 6 + +# bottle +Static 0x0EFC +6110 80 6 + +# chair +FancyWoodenChairCushion 0x0B50 +6111 82 0 + +# large battle axe +Static 0x13FB +5933 224 44 + +# chainmail coif +Static 0x13BB +5930 208 35 + +# Green Potion +Static 0x0F0A +5931 84 0 + +# empty vials +Static 0x185B +6114 223 28 + +# hourglass +Static 0x1810 +6114 82 6 + +# torso +Static 0x1CE8 +6118 226 22 diff --git a/Data/Decoration/Britannia/_ice.cfg b/Data/Decoration/Britannia/_ice.cfg new file mode 100644 index 0000000..6999b77 --- /dev/null +++ b/Data/Decoration/Britannia/_ice.cfg @@ -0,0 +1,162 @@ +# flag stones +Static 0x4FE +5837 330 40 +5838 329 40 + +# wooden wall +SecretWoodenDoor 0x0336 (Facing=EastCCW) +5831 367 0 + +# wooden fence +Static 0x0864 +5820 357 1 +5836 360 6 + +# metal chest +MetalChest 0x09AB +5832 240 -3 +5750 147 9 +5682 181 -3 +5763 145 -3 +5822 359 -1 + +# crate +LargeCrate 0x0E3C +5682 332 0 +5681 329 0 +5681 330 0 +5681 330 3 +5681 331 0 +5681 331 3 +5681 332 0 +5681 332 3 +5681 333 0 +5682 330 0 +5682 331 0 + +# crate +MediumCrate 0x0E3E +5686 321 0 +5686 322 0 + +# bookcase +FullBookcase 0x0A9B +5658 320 0 +5657 320 0 +5659 320 0 +5660 320 0 +5661 320 0 +5662 320 0 + +# wooden fence +Static 0x0863 +5839 349 1 +5823 349 1 +5834 345 6 + +# metal chest +MetalGoldenChest 0x0E41 +5717 144 -16 +5851 227 0 +5701 305 0 +5659 302 0 +5661 302 0 +5852 231 -9 +5687 311 0 +5833 247 -2 +5688 311 0 +5689 311 0 + +# palisade +Static 0x0223 +5843 367 0 + +# metal chest +MetalGoldenChest 0x0E40 +5702 306 0 +5727 147 -2 +5759 144 -4 +5753 211 -7 + +# wooden chest +WoodenChest 0x0E42 +5828 364 0 +5832 242 -4 +5760 187 -4 +5656 305 0 +5656 307 0 +5768 189 -5 + +# death vortex +Static 0x3798 +5673 325 -3 + +# wooden chest +WoodenChest 0x0E43 +5840 357 0 +5770 185 -1 +5849 233 -16 +5840 358 1 +5683 188 -2 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +5831 346 15 + +# wooden wall +SecretWoodenDoor 0x0334 (Facing=WestCW) +5830 367 0 + +# bookcase +FullBookcase 0x0A99 +5656 332 0 +5656 329 0 +5656 321 0 +5656 323 0 +5656 325 0 +5656 327 0 + +# bookcase +FullBookcase 0x0A9A +5656 328 0 +5656 330 0 +5656 331 0 +5656 333 0 +5656 322 0 +5656 324 0 +5656 326 0 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +5832 346 15 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +5839 363 0 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +5840 363 0 + +# metal chest +Metalchest 0x0E7C +5686 312 0 +5686 313 0 +5686 314 0 +5756 203 -2 + +# stone wall +SecretStoneDoor3 0x0354 (Facing=WestCW; Hue=1109) +5687 319 0 + +# stone wall +SecretStoneDoor3 0x0356 (Facing=EastCCW; Hue=1109) +5688 319 0 + +# palisade +Static 0x0424 +5819 361 20 + +# wood +Static 0x0738 +5851 233 -13 diff --git a/Data/Decoration/Britannia/_orccave.cfg b/Data/Decoration/Britannia/_orccave.cfg new file mode 100644 index 0000000..68ca984 --- /dev/null +++ b/Data/Decoration/Britannia/_orccave.cfg @@ -0,0 +1,3961 @@ +############### +# Teleporters # +############### + +# teleporter +Teleporter 0x1BC3 (PointDest=(5138, 2016, 0)) +1013 1433 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5138, 2016, 0)) +1013 1434 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(1014, 1434, 0)) +5139 2015 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(1014, 1434, 0)) +5139 2016 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(1014, 1434, 0)) +5139 2017 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5332, 1379, 0)) +5132 1946 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5332, 1379, 0)) +5133 1946 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5332, 1379, 0)) +5134 1946 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5332, 1379, 0)) +5135 1946 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5134, 1947, 0)) +5329 1381 10 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5134, 1947, 0)) +5330 1381 10 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5134, 1947, 0)) +5331 1381 10 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5134, 1947, 0)) +5332 1381 10 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5134, 1947, 0)) +5333 1381 10 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5134, 1947, 0)) +5334 1381 10 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5272, 2041, 4)) +5363 1289 4 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5272, 2041, 4)) +5364 1289 4 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5363, 1290, 4)) +5272 2043 4 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5363, 1290, 4)) +5273 2043 4 + + +############### +# Decorations # +############### + +# wooden fence +Static 0x0864 +5356 1992 10 +5336 1345 0 +5336 1346 0 +5336 1347 0 +5336 1348 0 +5336 1349 0 +5336 1350 0 +5336 1351 0 +5336 1352 0 +5340 1999 0 +5353 1991 30 +5353 1992 30 +5350 2017 0 +5350 2021 0 +5297 1971 10 +5286 2010 6 +5297 1972 10 +5297 1973 10 +5297 1974 10 +5297 1975 10 +5294 1998 10 +5294 1998 30 +5294 1999 10 +5294 1999 30 +5294 2000 10 +5294 2000 30 +5297 1998 10 +5297 1998 30 +5297 1999 10 +5297 1999 30 +5304 1961 30 +5304 1961 10 +5353 1993 30 +5356 1991 30 +5356 1992 30 +5296 1976 10 +5314 1982 10 +5314 1982 30 +5322 1974 10 +5322 1974 30 +5341 1998 0 +5325 2019 10 +5325 2019 30 +5152 1955 0 +5152 1956 0 +5152 1957 0 +5353 1991 10 +5353 1992 10 +5353 1993 10 +5353 1995 0 +5350 2021 17 +5356 1991 10 +5294 1312 0 +5294 1313 0 +5294 1314 0 +5294 1318 0 +5294 1319 0 +5294 1320 0 + +# log post +Static 0x0145 +5324 1287 0 +5324 1296 0 +5327 1359 0 +5327 1370 0 +5327 1374 0 +5327 1378 0 +5335 1287 0 +5335 1296 0 +5337 1359 0 +5337 1370 0 +5337 1374 0 +5337 1378 0 +5343 1345 0 +5343 1352 0 +5343 1359 0 +5284 2015 0 +5353 1359 0 +5353 1368 0 +5284 2010 0 +5295 1287 0 +5295 1296 0 +5295 1304 0 +5295 1335 0 +5295 1345 0 +5295 1351 0 +5295 1360 0 +5305 1287 0 +5305 1296 0 +5305 1304 0 +5306 1335 0 +5303 1351 0 +5306 1344 0 +5303 1360 0 +5314 1287 0 +5314 1296 0 +5311 1351 0 +5310 1358 0 +5310 1359 0 +5311 1358 0 +5311 1359 0 +5312 1368 0 +5312 1375 0 +5320 1351 0 +5322 1359 0 + +# rock +Static 0x1773 +5325 1287 0 +5360 1293 0 +5269 2033 0 +5293 2009 0 +5293 2010 0 +5294 2011 0 +5295 2010 0 + +# lever +Static 0x1093 +5347 1996 5 +5348 1996 6 +5316 1975 5 +5317 1975 6 + +# rock +Static 0x1774 +5325 1287 0 +5368 1298 0 +5270 2030 0 +5294 2009 0 + +# anvil +AnvilEastAddon 0x0FAF +5326 1287 0 +5326 1296 0 +5332 1287 0 +5336 1287 0 +5332 1296 0 +5342 1287 0 +5345 1304 0 +5345 1312 0 +5351 1304 0 +5351 1312 0 +5308 2009 5 +5317 1978 0 +5312 1287 0 +5306 1287 0 +5306 1296 0 +5315 1287 0 +5312 1296 0 +5315 1296 0 +5321 1287 0 +5321 1296 0 + +# bellows +Forge 0x197A (Light=Circle300) +5327 1287 0 +5327 1296 0 +5337 1287 0 +5346 1304 0 +5346 1312 0 +5316 1287 0 +5307 1287 0 +5307 1296 0 +5316 1296 0 + +# forge +Static 0x197E (Light=Circle300) +5328 1287 0 +5328 1296 0 +5338 1287 0 +5347 1304 0 +5347 1312 0 +5317 1287 0 +5308 1287 0 +5308 1296 0 +5317 1296 0 + +# forge +Forge 0x19A2 (Light=Circle300) +5329 1287 0 +5330 1287 0 +5329 1296 0 +5330 1296 0 +5348 1312 0 +5349 1312 0 +5339 1287 0 +5340 1287 0 +5348 1304 0 +5349 1304 0 +5309 1287 0 +5310 1287 0 +5309 1296 0 +5310 1296 0 +5318 1287 0 +5319 1287 0 +5318 1296 0 +5319 1296 0 + +# forge +Static 0x1982 (Light=Circle300) +5331 1287 0 +5331 1296 0 +5350 1312 0 +5341 1287 0 +5350 1304 0 +5311 1287 0 +5311 1296 0 +5320 1287 0 +5320 1296 0 + +# sledge hammer +Static 0x0FB5 +5327 1288 0 +5366 1296 0 +5318 1981 0 + +# tuscany pine +Static 0x1B7E +5324 1303 0 +5324 1312 0 +5328 1307 0 +5320 1307 0 + +# silver ingots +Static 0x1BFA +5325 1296 0 + +# Orc Frame +Static 0x20E0 (Hue=0x349;Name=an orcish idol) +5325 1303 10 +5328 1306 10 +5328 1308 10 +5325 1312 10 +5323 1303 10 +5320 1306 10 +5320 1308 10 +5323 1312 10 + +# rock +Static 0x1776 +5325 1303 0 +5328 1306 0 +5328 1308 0 +5325 1312 0 +1013 1433 21 +1012 1435 21 +5359 2019 0 +5360 2016 0 +5363 2004 0 +5333 2004 0 +5290 2017 0 +5290 2018 0 +5306 1961 0 +5349 2008 0 +5349 2009 0 +5357 1993 0 +5358 2013 0 +5360 2006 0 +5362 2005 0 +5314 1955 20 +5365 2009 0 +5362 2014 0 +5335 2002 0 +5349 1993 0 +5347 2010 0 +5157 1971 0 +5362 2008 0 +5362 2012 0 +5363 2010 0 +5363 2011 0 +5311 1960 0 +5323 1303 0 +5320 1306 0 +5320 1308 0 +5323 1312 0 + +# switch +Static 0x108F +5318 1974 11 +5349 1995 11 +5318 1975 12 +5349 1996 12 + +# pickaxe +Static 0x0E85 +5322 2019 0 +5275 2025 0 + +# switch +Static 0x1092 +5348 1997 12 +5317 1976 12 +5362 2012 23 + +# mushrooms +Static 0x0D14 +5324 1305 0 +5324 1309 0 +5326 1307 0 +5288 1316 0 +5288 1318 0 +5290 1313 0 +5290 1316 0 +5291 1312 0 +5291 1318 0 +5292 1312 0 +5292 1315 0 +5292 1317 0 +5293 1312 0 +5294 1316 0 +5322 1307 0 + +# water +Static 0x179F +5324 1306 0 + +# dishing stump +Static 0x1865 +5324 1307 1 + +# no draw +Static 0x21A4 +5324 1307 1 +5337 1303 8 +5336 1305 24 +5336 1311 24 +5337 1304 8 +5337 1305 8 +5337 1309 8 +5337 1310 8 +5337 1311 8 +5295 2000 40 +5296 2000 40 +5297 2000 40 +5297 1999 40 +5297 1998 40 +5333 2003 0 +5348 2009 0 +5334 2003 0 +5347 2009 0 +5348 2008 0 +5288 1337 49 +5288 1337 66 +5288 1338 25 +5288 1338 49 +5288 1338 69 +5288 1338 5 +5288 1339 69 +5288 1339 5 +5288 1340 25 +5288 1340 49 +5288 1340 69 +5288 1340 5 +5288 1341 49 +5288 1341 66 +5289 1339 0 +5290 1339 0 +5313 1329 0 +5313 1330 0 +5314 1329 0 +5309 1358 0 +5309 1359 0 +5322 1328 0 +5322 1329 0 +5323 1328 0 +5318 1342 0 +5318 1343 0 +5319 1342 0 + +# water +Static 0x1797 +5324 1307 0 +5312 1959 0 +5314 1958 0 +5314 1959 0 + +# water +Static 0x17A1 +5324 1308 0 +5313 1961 0 + +# water +Static 0x17A5 +5325 1306 0 +5320 1955 0 +5321 1956 0 + +# water +Static 0x179D +5325 1307 0 + +# water +Static 0x17A7 +5325 1308 0 +5317 1961 0 +5318 1960 0 +5319 1959 0 +5320 1958 0 + +# juniper bush +Static 0x0CC8 +5327 1304 0 +5327 1310 0 +5321 1304 0 +5321 1310 0 + +# rock +Static 0x1778 +5353 1311 0 +5338 1288 0 +5339 1312 0 +5288 2012 0 +5289 2018 0 +5332 2003 0 +5291 2017 0 +5346 1993 0 +5346 2009 0 +5348 2010 0 +5359 2007 0 +5360 2018 0 +5361 2015 0 +5334 2004 0 +5345 1995 0 +5343 2008 0 +5351 1993 0 +5363 2005 0 +5363 2009 0 +5363 2013 0 +5365 2012 0 +5310 1288 0 + +# flowstone +Static 0x08E8 +5349 1319 0 +1013 1436 0 +5335 1300 0 +5334 1384 0 +5344 1287 0 +5340 1335 0 +5343 1350 0 +1012 1432 0 +1013 1432 0 +1012 1434 0 +5362 1289 0 +5365 1287 0 +5310 1956 0 +5366 1289 0 +5271 2024 0 +5274 2044 0 +5283 2011 0 +5285 2021 -1 +5287 2033 0 +5329 2010 0 +5291 2027 -1 +5293 2024 -1 +5302 1986 0 +5303 1983 -1 +5310 1955 0 +5314 1986 0 +5314 1989 0 +5137 1945 0 +5134 1953 0 +5134 1971 0 +5134 2020 0 +5138 1956 0 +5143 1993 -1 +5165 1970 0 +5287 1316 0 +5287 1321 0 +5290 1344 0 +5295 1291 0 +5292 1311 0 +5295 1306 0 +5293 1335 0 +5295 1332 0 +5295 1348 0 +5336 2020 0 +5307 1312 0 +5306 1320 0 +5307 1335 0 +5311 1307 0 +5311 1363 0 +5311 1369 0 +5311 1374 0 +5322 1287 0 +5318 1327 0 + +# log post +Static 0x0093 +5328 1319 20 +5328 1319 0 +5328 1326 20 +5330 1326 20 +5336 1319 20 +5336 1319 0 +5334 1326 20 +5334 1326 0 +5336 1326 20 +5344 1319 20 +5344 1319 0 +5344 1326 20 +5346 1326 20 +5352 1319 20 +5352 1319 0 +5350 1326 20 +5350 1326 0 +5352 1326 20 +5354 1343 0 +5354 1352 0 +5360 1319 20 +5360 1319 0 +5360 1326 20 +5362 1326 20 +5359 1368 0 +5368 1319 20 +5368 1319 0 +5366 1326 20 +5366 1326 0 +5368 1326 20 +5368 1343 0 +5368 1368 0 +5307 2007 5 +5307 2011 5 +5311 2007 5 +5311 2011 5 + +# flowstone +Static 0x08E2 +5325 1327 0 +5327 1341 0 +5328 1384 0 +5329 1384 0 +5330 1384 0 +5332 1383 0 +5333 1383 0 +5334 1383 0 +5336 1382 0 +5332 1384 0 +5336 1384 0 +1012 1433 2 +1012 1435 0 +1012 1436 0 +5324 1959 -1 +5362 1287 0 +5361 1288 0 +5362 1288 0 +5357 1327 0 +5330 2011 0 +5335 2018 0 +5359 1368 -1 +5298 1979 -1 +5366 1287 0 +5366 1288 0 +5368 1343 -1 +5271 2044 0 +5274 2024 0 +5276 2037 0 +5282 2011 0 +5282 2014 0 +5283 2014 0 +5311 1376 0 +5329 2001 -1 +5293 2028 -1 +5301 1986 0 +5301 1989 0 +5302 1989 0 +5305 1993 -1 +5304 2026 -1 +5328 1381 0 +5313 1992 -1 +5361 1994 0 +5359 2020 0 +5314 1956 0 +5318 1995 -1 +5320 1996 0 +5131 1945 0 +5131 1946 0 +5137 1946 -1 +5135 1980 0 +5134 2013 -1 +5144 1949 0 +5145 1955 0 +5139 1983 -1 +5339 2022 0 +5141 2014 0 +5141 2019 0 +5152 1954 -1 +5153 1985 -1 +5147 1991 0 +5159 1957 -1 +5159 1980 -1 +5162 1971 0 +5287 1311 0 +5287 1335 0 +5290 1335 0 +5287 1344 0 +5363 2007 0 +5293 1344 0 +5302 1287 0 +5306 1311 0 +5306 1314 0 +5306 1317 0 +5307 1351 0 +5311 1333 0 +5311 1368 0 +5318 1303 0 +5316 1351 0 + +# log wall +Static 0x0094 +5328 1320 0 +5336 1320 0 +5344 1320 0 +5352 1320 0 +5360 1320 0 +5368 1320 0 + +# log wall +Static 0x0091 +5328 1321 0 +5328 1322 0 +5328 1323 0 +5328 1324 0 +5328 1325 0 +5352 1324 0 +5336 1321 0 +5336 1322 0 +5336 1324 0 +5336 1325 0 +5344 1321 0 +5344 1322 0 +5344 1323 0 +5344 1324 0 +5344 1325 0 +5352 1321 0 +5352 1322 0 +5352 1323 0 +5352 1325 0 +5360 1321 0 +5360 1322 0 +5360 1323 0 +5360 1324 0 +5360 1325 0 +5368 1321 0 +5368 1322 0 +5368 1323 0 +5368 1324 0 +5368 1325 0 +5336 1323 0 + +# block +Static 0x1271 +5353 1312 1 +5353 1312 2 +5353 1312 0 + +# log wall +Static 0x0096 +5328 1326 0 +5344 1326 0 +5360 1326 0 + +# water +Static 0x1799 +5315 1960 0 +5313 1959 0 +5313 1960 0 +5314 1960 0 +5315 1959 0 + +# gruesome standard +Static 0x0428 +5328 1327 0 +5330 1327 0 +5334 1327 0 +5336 1327 0 +5344 1327 0 +5346 1327 0 +5350 1327 0 +5352 1327 0 +5360 1327 0 +5362 1327 0 +5366 1327 0 +5368 1327 0 +5138 1957 0 +5145 1956 0 +5138 1971 0 +5141 1971 0 +5144 1971 0 +5152 1971 0 +5155 1971 0 +5158 1971 0 + +# skull +Static 0x1AE3 +5328 1327 29 +5330 1327 29 +5334 1327 29 +5336 1327 29 +5344 1327 29 +5346 1327 29 +5350 1327 29 +5352 1327 29 +5354 1344 22 +5354 1344 16 +5354 1344 11 +5354 1344 6 +5354 1353 22 +5354 1353 16 +5354 1353 11 +5354 1353 6 +5360 1327 29 +5362 1327 29 +5359 1369 22 +5359 1369 16 +5359 1369 11 +5359 1369 6 +5366 1327 29 +5368 1327 29 +5368 1344 22 +5368 1344 16 +5368 1344 11 +5368 1344 6 +5368 1369 22 +5368 1369 16 +5368 1369 11 +5368 1369 6 +5313 1304 6 + +# barrel +Static 0x0FAE +5329 1320 0 +5329 1320 7 +5329 1322 0 +5345 1322 3 +5136 1962 0 +5137 1961 0 + +# empty tub +Static 0x0E83 +5329 1321 0 +5334 1320 8 +5348 1996 16 +5317 1975 16 +5362 2011 26 + +# jug of cider +Jug 0x09C8 (Content=Cider) +5329 1322 4 + +# jugs of cider +Static 0x098D +5329 1323 0 +5331 1320 6 + +# barrel +Barrel 0x0E77 +5329 1324 0 +5348 1996 10 +5317 1975 10 +5137 1961 6 +5362 2011 20 + +# log wall +Static 0x0092 +5329 1326 0 +5335 1326 0 +5345 1326 0 +5351 1326 0 +5361 1326 0 +5367 1326 0 + +# tattered banner +Static 0x042D +5329 1327 0 +5334 1327 -1 +5334 1327 0 +5361 1327 0 +5357 1343 0 +5361 1343 0 +5366 1327 0 +5365 1343 0 +5136 1971 0 +5142 1971 0 +5153 1971 0 +5159 1971 0 + +# keg +Static 0x1AD6 +5330 1320 8 + +# counter +Static 0x0B40 +5330 1320 0 +5334 1320 0 + +# wooden wall +Static 0x0011 +5351 1320 0 +5351 1321 0 +5351 1322 0 +5351 1323 0 +5335 1320 0 +5335 1321 0 +5335 1322 0 +5335 1323 0 +5335 1324 0 +5335 1325 0 +5351 1324 0 +5351 1325 0 +5367 1320 0 +5367 1321 0 +5367 1322 0 +5367 1323 0 +5367 1324 0 +5367 1325 0 +5286 2010 20 +5287 2010 20 + +# wooden fence +Static 0x0863 +5315 1981 30 +5328 1344 0 +5329 1344 0 +5330 1344 0 +5334 1344 0 +5335 1344 0 +5336 1344 0 +5355 1990 30 +5356 1990 30 +5289 1314 7 +5289 1317 1 +5289 1317 8 +5295 2001 10 +5305 1960 10 +5354 1993 30 +5354 1990 10 +5287 2009 10 +5297 1970 20 +5297 1970 9 +5295 1997 10 +5295 1997 30 +5296 1997 10 +5296 1997 30 +5297 1997 10 +5297 1997 30 +5293 2001 10 +5294 2001 10 +5295 2000 10 +5295 2000 30 +5296 2000 10 +5296 2000 30 +5351 2016 0 +5354 1993 10 +5355 1990 10 +5355 1993 10 +5315 1981 10 +5323 1973 10 +5323 1973 30 +5326 2018 10 +5326 2018 30 +5153 1957 0 +5157 1957 0 +5158 1957 0 +5354 1990 30 +5289 1314 0 +5355 1993 30 +5356 1990 10 +5305 1960 30 + +# log wall +Static 0x0097 +5330 1326 0 +5346 1326 0 +5362 1326 0 + +# lever +Static 0x108E +5360 2010 6 + +# tattered banner +Static 0x042C +5330 1327 0 +5335 1327 0 +5362 1327 0 +5358 1343 0 +5362 1343 0 +5367 1327 0 +5366 1343 0 +5137 1971 0 +5143 1971 0 +5154 1971 0 +5160 1971 0 + +# counter +Static 0x0B3E +5331 1320 0 +5332 1320 0 +5333 1320 0 + +# blood smear +Static 0x122F (Hue=0x107) +5331 1322 0 + +# refuse +Static 0x1BB0 +5324 1328 0 +5315 1329 0 +5320 1342 0 + +# refuse +Static 0x1B9F +5324 1329 0 +5315 1330 0 +5320 1343 0 + +# bone pile +Static 0x1B0B +5324 1331 0 +5340 1339 0 +5141 1978 0 +5138 2003 0 +5319 1329 0 +5319 1339 0 +5317 1358 0 + +# bone pile +Static 0x1B0F +5325 1329 0 +5349 2006 0 +5148 1979 0 +5150 1972 0 +5302 1301 0 +5300 1343 0 +5313 1333 0 + +# garbage +Static 0x10EF +5325 1333 0 +5345 1351 0 +5361 1329 0 +5136 2015 0 +5141 1959 0 +5142 2002 0 +5146 1961 0 +5153 1959 0 +5298 1325 0 +5304 1293 0 +5303 1304 0 +5305 1369 0 +5308 1353 0 +5308 1374 0 + +# bone pile +Static 0x1B0C +5330 1335 0 +5348 1346 0 +5357 2011 0 +5142 1974 0 +5147 1993 0 +5299 1358 0 +5301 1319 0 +5316 1330 0 +5322 1331 0 + +# stalagmites +Static 0x08E0 +5327 1339 1 +1013 1437 0 +5343 1334 1 +1012 1431 0 +1012 1433 21 +5359 1355 1 +5367 1288 0 +5272 2024 22 +5285 2010 0 +5311 1375 0 +5325 2000 0 +5325 2009 0 +5304 1985 0 +5301 2028 0 +5303 2033 0 +5359 1993 -1 +5360 1993 0 +5308 2032 0 +5314 1987 17 +5137 1944 0 +5132 1952 0 +5135 1953 0 +5136 1954 0 +5137 1971 0 +5143 1971 0 +5332 2011 -1 +5337 2021 0 +5140 2019 0 +5153 1971 0 +5157 1955 0 +5160 1961 -1 +5161 1971 0 +5324 1976 0 +5324 1998 0 +5306 1312 0 +5306 1313 0 +5306 1319 0 +5308 1320 0 + +# wooden fence +Static 0x088A +5327 1344 0 +5333 1344 0 + +# wooden fence +Static 0x0878 +5327 1346 0 +5327 1348 0 +5327 1350 0 + +# shackles +Static 0x1263 +5327 1346 1 +5327 1348 1 +5327 1350 1 + +# blood +Static 0x122A +5328 1351 0 +5315 1311 0 +5309 1317 0 +5310 1315 0 +5315 1317 0 +5316 1309 0 +5316 1315 0 + +# hay +Static 0x0F34 +5329 1349 0 +5334 1350 0 +5335 1346 0 +5155 1955 0 + +# garbage +Static 0x10EE +5330 1347 0 +5330 1371 0 +5333 1340 0 +5333 1347 0 +5333 1351 0 +5338 1365 0 +5346 1339 0 +5346 1362 0 +5353 1330 0 +5352 1347 0 +5360 1334 0 +5141 1967 0 +5154 1993 0 +5298 1291 0 +5298 1307 0 +5298 1346 0 +5302 1330 0 +5305 1338 0 +5306 1358 0 +5306 1359 0 +5305 1373 0 +5306 1375 0 +5308 1369 0 +5317 1364 0 + +# horse dung +Static 0x0F3B +5330 1350 0 +5335 1347 0 +5153 1955 0 +5156 1956 0 + +# blood smear +Static 0x122F +5330 1351 0 +5345 1330 0 +5304 1373 0 +5313 1306 0 +5315 1310 0 +5309 1316 0 +5311 1317 0 +5315 1316 0 +5317 1311 0 +5317 1317 0 + +# hanging lantern +HangingLantern 0x0A1A +1015 1435 10 +1015 1432 10 + +# switch +Static 0x1091 +5317 1976 12 +5348 1997 12 +5362 2012 23 + +# stone wall +Static 0x01D0 +5324 1359 0 +5329 1359 0 +5331 1359 0 +5332 1359 0 +5333 1359 0 +5335 1359 0 +5340 1359 0 + +# pile of skulls +Static 0x1ADC +5326 1359 1 +5338 1359 1 + +# stalagmites +Static 0x08E5 +5363 1287 28 +5270 2043 0 +5283 2013 22 +5285 2032 0 +5328 2010 0 +5361 1995 0 +5310 2030 0 +5315 1961 0 +5302 1988 22 +5135 1972 0 +5138 1960 0 +5142 1971 0 +5139 1984 0 +5150 1983 0 +5152 1984 0 +5156 1971 0 +5160 1972 0 +5331 2011 0 +5334 2017 0 +5311 1364 0 +5311 1373 18 + +# stalagmites +Static 0x08E1 +5360 1288 0 +5327 1380 0 +5327 1382 0 +5327 1383 0 +5328 1382 0 +5328 1383 0 +5329 1383 0 +5331 1382 0 +5331 1383 0 +5331 1384 0 +5310 1957 0 +5332 1382 0 +5335 1381 0 +5335 1382 0 +5335 1383 0 +5336 1380 0 +5336 1383 0 +5333 1384 0 +5335 1384 0 +5359 1343 1 +5359 1361 1 +5336 2003 0 +5299 1968 0 +5300 1982 0 +5364 1287 23 +5365 1288 5 +5270 2042 0 +5278 2030 0 +5283 2012 22 +5289 2025 0 +5285 2031 0 +5288 2034 0 +5326 2007 0 +5327 2008 0 +5297 1978 0 +5291 2022 0 +5292 2024 0 +5295 2025 0 +5299 1981 0 +5302 1987 22 +5304 1992 0 +5304 1996 0 +5309 1968 0 +5312 1982 0 +5313 1986 0 +5313 1989 0 +5312 1991 0 +5312 2026 0 +5313 2024 0 +5314 1957 0 +5315 1956 0 +5363 2012 0 +5314 1993 -1 +5317 1994 0 +5316 2001 0 +5322 1958 -1 +5131 1944 0 +5136 1944 0 +5323 1978 0 +5135 1971 0 +5137 1981 0 +5136 2001 0 +5134 2014 -1 +5135 2020 0 +5139 1947 -1 +5141 1948 -1 +5332 2001 0 +5138 1982 0 +5339 1999 0 +5140 1994 0 +5145 1999 0 +5140 2009 0 +5143 2004 0 +5140 2014 0 +5147 1982 0 +5151 1983 0 +5153 1987 0 +5149 1990 0 +5158 1956 0 +5159 1964 0 +5159 1965 0 +5159 1966 0 +5159 1967 0 +5160 1966 0 +5160 1967 0 +5160 1968 0 +5160 1969 0 +5157 1992 0 +5164 1971 0 +5362 2003 0 +5300 1287 1 +5306 1321 0 + +# stone post +Static 0x01D2 +5330 1359 0 +5334 1359 0 +5339 1359 0 +5328 1359 0 +5288 1342 5 +5288 1342 24 +5288 1342 43 +5288 1342 53 +5288 1342 72 +5323 1359 0 + +# spike trap +SpikeTrap 0x1121 +5324 1360 5 +5329 1360 5 +5335 1360 5 +5340 1360 5 + +# pile of skulls +Static 0x1AD9 +5325 1360 1 +5330 1361 0 +5331 1361 0 +5332 1361 0 +5334 1360 10 +5337 1360 1 + +# pile of skulls +Static 0x1AD8 +5326 1360 1 +5333 1361 0 +5338 1360 1 + +# wooden fence +Static 0x0865 +5296 1970 10 +5350 2016 0 +5356 1993 0 +5323 1974 0 +5288 1317 6 +5287 2011 5 +5351 2021 6 +5353 1990 20 +5322 1973 30 +5288 1314 7 +5286 2009 0 +5286 2009 10 +5286 2010 0 +5287 2009 0 +5287 2010 0 +5323 1974 20 +5296 1970 20 +5325 2018 30 +5296 1975 0 +5325 2019 0 +5325 2019 20 +5296 1976 0 +5297 1975 0 +5297 1976 0 +5326 2018 20 +5294 1997 0 +5294 1997 10 +5294 1997 20 +5294 1997 30 +5297 1997 0 +5297 1997 20 +5292 2001 0 +5292 2001 6 +5294 2000 0 +5294 2000 20 +5295 2001 0 +5297 2000 0 +5297 2000 20 +5341 1997 0 +5304 1960 30 +5304 1961 20 +5304 1961 0 +5305 1960 20 +5305 1960 0 +5305 1961 20 +5286 2011 7 +5353 1993 0 +5350 2020 0 +5350 2021 11 +5315 1981 0 +5297 1970 0 +5356 1993 20 +5314 1981 30 +5315 1981 20 +5314 1982 0 +5314 1982 20 +5315 1982 0 +5315 1982 20 +5323 1973 0 +5323 1973 20 +5322 1974 0 +5322 1974 20 +5326 2018 0 +5326 2019 0 +5326 2019 20 +5341 1996 0 +5152 1954 0 +5352 1995 0 +5353 1990 30 +5353 1990 10 +5353 1990 0 +5353 1993 20 +5156 1957 0 +5350 2020 10 +5350 2021 26 +5288 1314 0 +5288 1317 0 +5356 1990 20 +5356 1990 0 +5296 1971 19 +5297 1971 19 +5297 1971 0 +5294 1311 0 +5294 1317 0 +5305 1961 0 + +# bone pile +Static 0x1B0E +5326 1365 0 +5333 1373 0 +5317 1369 0 +5138 1972 0 +5152 1978 0 +5360 2013 0 +5298 1314 0 +5304 1353 0 + +# pile of skulls +Static 0x1ADB +5330 1360 0 +5331 1360 0 +5331 1360 9 +5337 1359 0 +5332 1360 11 +5333 1360 0 +5333 1360 10 +5333 1361 11 +5325 1359 0 + +# waterfall +Static 0x351D +5311 1957 0 +5312 1954 17 +5311 1954 17 +5312 1957 0 +5313 1954 17 +5313 1957 0 + +# stone +Static 0x0788 +5362 1290 0 +5329 1381 0 +5330 1381 0 +5331 1381 0 +5332 1381 0 +5333 1381 0 +5334 1381 0 +5365 1290 0 +5284 2011 0 +5285 2011 0 +5286 2011 0 +5287 2011 0 +5288 1337 0 +5288 1337 44 +5288 1338 0 +5288 1338 20 +5288 1338 44 +5288 1338 56 +5288 1338 60 +5288 1338 64 +5288 1339 0 +5288 1339 20 +5288 1339 44 +5288 1339 48 +5288 1339 52 +5288 1339 56 +5288 1339 60 +5288 1339 64 +5288 1340 0 +5288 1340 20 +5288 1340 44 +5288 1340 56 +5288 1340 60 +5288 1340 64 +5288 1341 0 +5288 1341 44 +5289 1338 0 +5289 1340 0 +5290 1338 0 +5290 1340 0 +5291 1338 0 +5291 1339 0 +5291 1340 0 + +# wooden signpost +Static 0x0B99 +5327 1370 0 +5327 1378 0 +5284 2010 0 +5312 1368 0 +5284 2015 0 +5312 1375 0 + +# lantern +Static 0x0A15 (Light=Circle300) +5327 1370 9 +5327 1378 9 +5362 1291 15 +5365 1291 15 +5284 2010 9 +5284 2015 9 +5312 1368 9 +5312 1375 9 + +# flowstone +Static 0x08E6 +5327 1381 0 +5328 1380 0 +5322 1980 0 +5329 1382 0 +5330 1382 0 +5330 1383 0 +5327 1384 0 +5291 2001 -1 +5310 1958 0 +5333 1382 0 +5334 1382 0 +5336 1381 0 +5345 1319 0 +5343 1354 0 +1012 1434 21 +1013 1435 21 +5363 1287 21 +5333 2016 -2 +5364 1343 0 +5273 2024 22 +5269 2041 -2 +5276 2034 0 +5282 2012 18 +5282 2013 18 +5284 2030 0 +5328 2009 0 +5324 2020 0 +5290 2021 0 +5290 2026 -1 +5346 1994 0 +5298 1981 0 +5301 1982 0 +5301 1987 18 +5301 1988 18 +5305 1994 0 +5300 2018 0 +5311 1983 0 +5361 2006 0 +5354 2021 0 +5358 2020 0 +5362 2002 0 +5311 2029 0 +5309 2031 0 +5318 1967 0 +5314 1988 17 +5321 1997 0 +5322 1957 0 +5131 1951 -2 +5134 1954 0 +5137 1954 0 +5131 1971 0 +5135 1981 0 +5134 2019 0 +5140 1971 0 +5336 2002 0 +5336 2021 0 +5338 2022 0 +5142 2005 0 +5150 1982 0 +5147 1998 0 +5149 1997 0 +5157 1954 0 +5159 1971 0 +5158 1979 -1 +5156 1994 0 +5165 1971 0 +5295 1358 0 +5307 1311 0 +5307 1320 0 +5362 2007 0 + +# nodraw +Static 0x2198 +5363 1288 3 +5363 1289 3 +5363 1290 3 +5363 1291 3 +5363 1292 3 +5363 1293 3 +5363 1295 3 +5363 1296 3 +5363 1297 3 +5364 1288 3 +5364 1289 3 +5364 1290 3 +5364 1291 3 +5364 1292 3 +5364 1293 3 +5364 1294 3 +5364 1295 3 +5364 1296 3 +5364 1297 3 +5272 2025 3 +5272 2026 3 +5272 2027 3 +5272 2028 3 +5273 2025 3 +5273 2026 3 +5273 2027 3 +5272 2035 3 +5272 2036 3 +5272 2037 3 +5273 2036 3 +5273 2037 3 +5272 2038 3 +5272 2039 3 +5272 2040 3 +5272 2041 3 +5272 2042 3 +5272 2043 3 +5273 2038 3 +5273 2039 3 +5273 2040 3 +5273 2041 3 +5273 2042 3 +5273 2043 3 +5284 2012 3 +5284 2013 3 +5285 2012 3 +5285 2013 3 +5286 2012 3 +5286 2013 3 +5287 2012 3 +5287 2013 3 +5303 1987 3 +5303 1988 3 +5304 1987 3 +5304 1988 3 +5305 1987 3 +5305 1988 3 +5306 1987 3 +5306 1988 3 +5307 1987 3 +5307 1988 3 +5308 1987 3 +5308 1988 3 +5309 1987 3 +5309 1988 3 +5310 1987 3 +5310 1988 3 +5311 1987 3 +5311 1988 3 +5312 1987 3 +5312 1988 3 +5363 1294 3 + +# stone wall +Static 0x0082 +5363 1289 -23 +5363 1288 -23 +5363 1290 -23 +5363 1291 -23 +5364 1288 -23 +5364 1289 -23 +5364 1290 -23 +5364 1291 -23 + +# stone stairs +Static 0x078B +5329 1380 0 +5329 1381 5 +5330 1380 0 +5330 1381 5 +5331 1380 0 +5331 1381 5 +5332 1380 0 +5332 1381 5 +5333 1380 0 +5333 1381 5 +5334 1380 0 +5334 1381 5 +5272 2034 0 +5303 1986 0 +5304 1986 0 +5305 1986 0 +5306 1986 0 +5307 1986 0 +5308 1986 0 +5309 1986 0 +5310 1986 0 +5311 1986 0 +5312 1986 0 +5132 1945 -2 +5133 1945 -2 +5134 1945 -2 +5135 1945 -2 +5289 1337 0 +5290 1337 0 +5291 1337 0 + +# hook +Static 0x1E9B +5323 1975 19 + +# iron ingots +Static 0x1BF4 +5333 1287 0 +5341 1288 0 +5319 1982 0 + +# rock +Static 0x177C +5332 1295 0 +5340 1312 0 +5290 2007 0 +5291 2008 0 + +# rock +Static 0x177B +5332 1295 0 +5340 1312 2 +5291 2008 2 + +# sledge hammer +Static 0x0FB4 +5336 1288 0 +5337 1309 8 +5362 1298 0 +5321 1971 0 +5320 1977 0 + +# rock +Static 0x1777 +5337 1288 0 +5341 1311 0 +5352 1312 0 +5354 1344 0 +5289 2012 0 +5332 2003 0 +5333 2002 5 +5291 2017 2 +5346 2009 0 +5347 2008 5 +5356 1994 0 +5359 2018 0 +5317 1972 0 +5316 1994 0 +5350 1994 0 +5351 2005 0 +5360 2007 0 + +# silver ingots +Static 0x1BF7 +5333 1296 0 + +# stone wall +Static 0x0025 +5336 1302 0 +5336 1302 8 +5336 1302 16 +5337 1302 0 +5336 1305 0 +5336 1305 8 +5336 1308 16 +5336 1308 0 +5336 1308 8 +5336 1311 8 +5336 1311 0 +5337 1308 0 + +# lava +Static 0x1A3F +5336 1303 8 +5336 1309 8 + +# stone wall +Static 0x0026 +5336 1303 16 +5337 1303 0 +5336 1304 16 +5336 1309 16 +5336 1310 16 +5337 1304 0 +5337 1309 0 +5337 1310 0 + +# grey slate tile +Static 0x049C +5336 1303 24 +5337 1303 8 +5336 1305 24 +5336 1309 24 +5336 1311 24 +5337 1304 8 +5337 1305 8 +5337 1309 8 +5337 1310 8 +5337 1311 8 + +# stone wall +Static 0x0031 +5336 1303 24 +5336 1304 24 +5336 1309 24 +5336 1310 24 + +# switch +Static 0x1090 +5318 1974 11 +5349 1995 11 +5349 1996 12 +5318 1975 12 + +# wooden planks +Static 0x04DA +5296 1998 40 +5297 1971 20 +5355 1991 40 + +# rock +Static 0x1775 +5332 2002 0 +5313 1961 0 +5349 2010 3 +1013 1434 21 +5310 1953 12 +5289 2017 0 +5290 2016 0 +5291 2018 0 +5310 1954 13 +5346 2008 0 +5347 2007 0 +5310 1959 0 +5348 2007 0 +5351 2011 0 +5357 1995 0 +5359 2017 0 +5362 2011 0 +5314 1954 19 +5314 1955 14 +5136 1971 0 +5333 2001 0 +5334 2001 0 +5335 2003 0 +5335 2004 3 +5349 1992 0 +5351 1995 0 +5160 1971 0 +5361 2013 0 +5363 2008 0 +5364 2010 0 + +# lava +Static 0x1A37 +5336 1304 8 +5336 1310 8 + +# cave floor +Static 0x053F (Hue=0x1) +5333 2003 0 +5347 2008 0 +5348 2009 0 +5334 2003 0 +5347 2009 0 +5348 2008 0 + +# stone wall +Static 0x0032 +5336 1304 24 +5336 1310 24 + +# fire column +Static 0x3709 (Hue=0x835; Light=Circle300) +5336 1304 29 +5336 1310 29 + +# lava +Static 0x1A43 +5336 1305 8 +5336 1311 8 + +# stone wall +Static 0x0024 +5336 1305 16 +5336 1311 16 +5337 1305 0 +5337 1311 0 + +# anvil +AnvilSouthAddon 0x0FB0 +5336 1306 0 +5336 1307 0 + +# forged metal +Static 0x0FB7 +5337 1304 8 +5320 1970 0 + +# debris +Static 0x0C2D +5340 1997 0 +5323 1977 0 +5322 1976 0 +5342 1995 0 +5305 1963 0 +5298 1971 0 +5356 1995 0 +5357 1994 0 +5321 1975 0 +5322 1975 0 +5355 1994 0 + +# silver ingots +Static 0x1BF6 +5337 1305 10 + +# barred metal door +BarredMetalDoor2 0x1FF7 (Facing=NorthCCW) +5311 1371 0 + +# iron ingots +Static 0x1BF1 +5337 1311 10 +5363 1299 0 +5317 1982 0 + +# blood +Static 0x122B (Hue=0x107) +5332 1320 6 + +# flask +Static 0x1837 +5332 1320 8 + +# flask stand +Static 0x1829 +5333 1320 6 + +# flask +Static 0x183A +5333 1320 6 + +# flask +Static 0x1831 +5333 1320 9 + +# blood +Static 0x122D (Hue=0x107) +5333 1322 0 + +# wooden wall +Static 0x0012 +5334 1325 0 +5350 1325 0 +5366 1325 0 +5287 2009 20 + +# waterfall +Static 0x350B +5311 1956 2 +5312 1956 2 +5313 1956 2 + +# water +Static 0x17A8 +5312 1961 0 +5323 1308 0 + +# log wall +Static 0x0090 +5336 1326 0 +5352 1326 0 +5368 1326 0 + +# cauldron +Static 0x0974 +5364 1330 0 +5347 1330 0 +5313 1988 0 + +# debris +Static 0x0C2F +5348 2017 0 +5341 1999 0 +5341 2001 0 +5351 2016 0 +5352 2020 0 +5352 1995 0 + +# wooden planks +Static 0x04C9 +5350 2015 0 +5287 2010 20 +5353 1995 0 +5355 1995 0 + +# tattered banner +Static 0x0427 +5337 1359 0 +5345 1327 0 +5350 1327 0 +5355 1343 0 +5359 1343 0 +5363 1343 0 +5132 1971 18 +5139 1971 0 +5145 1971 0 +5150 1971 0 +5156 1971 0 +5162 1971 18 +5325 1359 0 + +# tattered banner +Static 0x0426 +5338 1359 0 +5346 1327 0 +5351 1327 0 +5356 1343 0 +5360 1343 0 +5364 1343 0 +5326 1359 0 +5133 1971 18 +5140 1971 0 +5146 1971 0 +5151 1971 0 +5157 1971 0 +5163 1971 18 + +# log post +Static 0x009D +5332 1360 12 +5360 1359 2 +5360 1363 2 +5368 1359 0 +5368 1363 0 +5312 1304 2 + +# pile of skulls +Static 0x1ADF +5334 1360 0 + +# stalagmites +Static 0x08E4 +5335 1380 0 +5275 2035 0 +5275 2036 0 +5284 2021 0 +5309 1959 0 +5315 1957 0 +5315 1993 0 +5132 1971 0 +5136 1981 0 +5340 2022 0 +5146 1955 0 +5153 1954 0 +5150 1996 0 +5158 1978 0 +5159 1973 0 +5160 1980 0 +5159 1991 0 +5308 1312 0 + +# vat +Static 0x1552 +5354 1992 41 +5295 1999 41 + +# wooden post +Static 0x0009 +1013 1435 0 +1013 1432 0 +1014 1432 1 +1014 1435 0 +5362 1289 6 +5362 1290 6 +5365 1289 6 +5365 1290 6 + +# smith's hammer +Static 0x13E4 +5308 2009 10 + +# dried onions +Static 0x0C40 +5289 1318 7 +5289 1315 7 + +# ore cart +Static 0x1A83 +5344 1303 0 +5368 1296 0 +5288 2013 0 +5324 2013 0 +5296 2010 0 +5299 1979 0 + +# ore cart +Static 0x1A82 +5344 1304 0 +5368 1297 0 +5288 2014 0 +5324 2014 0 +5296 2011 0 +5299 1980 0 + +# wooden planks +Static 0x04D8 +5355 1993 40 +5354 1993 40 +5297 1976 20 +5295 2000 40 +5296 2000 40 + +# ore cart +Static 0x1A8B +5341 1312 0 +5357 1296 0 +5290 2016 0 + +# ore cart +Static 0x1A88 +5342 1312 0 +5322 1997 0 +5358 1296 0 +5290 2010 0 +5291 2016 0 +5290 2034 0 +5303 2027 0 +5309 2003 0 +5311 1288 0 +5322 1296 0 + +# ore cart +Static 0x1A87 +5343 1312 0 +5323 1997 0 +5359 1296 0 +5291 2010 0 +5292 2016 0 +5291 2034 0 +5304 2027 0 +5310 2003 0 +5312 1288 0 +5323 1296 0 + +# fur%s% +Static 0x11FA +5346 1321 0 +5366 1321 0 + +# fur%s% +Static 0x11F6 +5346 1323 0 + +# fur%s% +Static 0x11F4 +5346 1325 0 +5348 1320 0 +5362 1322 0 + +# beef carcass +Static 0x1872 +5343 1333 0 + +# counter +Static 0x0B3F +5344 1329 0 +5344 1332 0 + +# skull +Static 0x1AE0 +5344 1329 6 + +# spine +Static 0x1B1B +5344 1329 7 + +# counter +Static 0x0B3D +5344 1330 0 +5344 1331 0 + +# pig's head +Static 0x1E8E +5344 1330 6 + +# cleaver +Static 0x0EC3 +5344 1330 3 + +# blood +Static 0x122B +5344 1331 9 +5305 1368 0 +5312 1309 6 + +# leg +Static 0x1CE2 +5344 1331 8 + +# rib cage +Static 0x1B17 +5344 1331 6 + +# skinned goat +Static 0x1E88 +5344 1332 6 +5365 1330 0 + +# blood +Static 0x122E +5345 1331 0 + +# fallen log +Static 0x0CF5 +5345 1333 0 +5348 1333 0 +5362 1333 0 +5365 1333 0 +5155 1965 0 + +# bone +Static 0x1B12 +5346 1332 0 +5312 1310 6 + +# fallen log +Static 0x0CF6 +5346 1333 0 +5349 1333 0 +5363 1333 0 +5366 1333 0 +5156 1965 0 + +# fire pit +Static 0x0FAC (Light=Circle150) +5347 1330 0 +5348 1322 0 +5349 1330 0 +5364 1322 0 +5364 1330 0 +5366 1330 0 +5156 1963 0 +5289 1338 5 +5289 1340 5 + +# bone shards +Static 0x1B19 +5347 1331 0 +5155 1964 0 + +# fallen log +Static 0x0CF7 +5347 1333 0 +5350 1333 0 +5364 1333 0 +5367 1333 0 +5157 1965 0 + +# bone pile +Static 0x1B0A +5341 1365 0 +5271 2030 0 +5137 2016 0 +5315 1343 0 +5320 1328 0 + +# water +Static 0x17A2 +5315 1961 0 +5311 1960 0 +5314 1961 0 +5316 1961 0 + +# crate +MediumCrate 0x0E3F +5352 1296 0 +5135 1964 3 + +# metal chest +MetalGoldenChest 0x0E41 +5354 1296 0 +5354 1296 4 +5355 1296 0 +5361 1343 0 +5366 1343 0 +5323 1287 0 +5317 1304 0 + +# block +Static 0x126E +5352 1311 0 +5352 1311 1 +5352 1311 2 + +# tapestry +Static 0x0FE4 (Hue=0x1) +1013 1433 -3 + +# stone rail +Static 0x08FB +1014 1432 0 +1014 1435 0 + +# curtain rod +Static 0x0434 +1015 1432 0 +1015 1435 0 + +# mushroom +Static 0x0D17 +5290 1314 0 +5290 1318 0 +5293 1314 0 +5290 1312 0 + +# mushroom +Static 0x0D16 +5323 1308 0 +5325 1306 0 +5325 1308 0 +5292 1319 0 +5289 1314 0 +5289 1317 0 + +# fur%s% +Static 0x11FB +5349 1321 0 + +# tapestry +Static 0x0FE3 (Hue=0x1) +1013 1435 -3 + +# bone pile +Static 0x1B0D +5348 1332 0 +5270 2035 0 +5146 1975 0 +5302 1290 0 + +# campfire +CampFire 0x0DE3 +5349 1330 2 +5156 1963 0 +5366 1330 2 + +# skull +Static 0x1AE2 +5355 1343 22 +5355 1343 16 +5355 1343 11 +5355 1343 6 +5355 1352 22 +5355 1352 16 +5355 1352 6 +5360 1368 22 +5360 1368 16 +5360 1368 11 +5360 1368 6 +5369 1343 22 +5369 1343 16 +5369 1343 11 +5369 1343 6 +5369 1368 22 +5369 1368 16 +5369 1368 11 +5369 1368 6 +5157 1963 0 +5355 1352 11 +5312 1310 8 + +# bone pile +Static 0x1B10 +5350 1358 0 +5137 1976 0 +5157 1974 0 +5159 1982 0 +5299 1297 0 +5296 1337 0 +5315 1332 0 +5317 1341 2 + +# vines +Static 0x0CF0 +5288 1316 1 +5287 1317 1 + +# wooden fence +Static 0x0862 +5323 1974 10 +5315 1982 30 +5287 2010 10 +5297 1976 10 +5297 2000 30 +5297 2000 10 +5305 1961 30 +5305 1961 10 +5356 1993 10 +5356 1993 30 +5315 1982 10 +5326 2019 10 +5326 2019 30 +5323 1974 30 + +# dried herbs +Static 0x0C41 +5290 1315 1 + +# candle +Static 0x1430 (Light=Circle150) +5312 1307 8 + +# stalagmites +Static 0x08E9 +5324 1977 0 +5357 1343 0 +5274 2024 25 +5277 2033 0 +5287 2034 0 +5314 2020 0 +5131 1943 -1 +5137 1943 -1 +5135 1977 0 +5144 2000 0 +5140 2010 0 +5154 1971 0 +5154 1995 0 +5308 1321 0 +5311 1370 18 + +# stalagmites +Static 0x08EA +5324 1997 0 +5304 1983 0 +5345 1994 0 +5363 2002 0 + +# stone wall +Static 0x0082 (Hue=0x1) +5363 1287 1 + +# bottle +Static 0x0E26 +5315 1304 9 + +# Bloodspawn +Static 0x0F7C +5315 1304 7 + +# rack +Static 0x1258 +5363 1288 0 +5363 1291 0 +5363 1289 0 +5363 1290 0 +5363 1292 0 +5363 1293 0 +5363 1294 0 +5363 1295 0 +5363 1296 0 +5363 1297 0 +5272 2023 0 +5272 2024 0 +5272 2025 0 +5272 2026 0 +5272 2027 0 +5272 2028 0 +5272 2035 0 +5272 2036 0 +5272 2037 0 +5272 2038 0 +5272 2039 0 +5272 2040 0 +5272 2041 0 +5272 2042 0 +5272 2043 0 + +# mace +Static 0x0F5D +5360 1360 7 +5360 1360 5 +5360 1361 6 +5368 1360 6 +5368 1360 4 +5368 1361 5 + +# stone rail +Static 0x08FC +5362 1290 6 +5365 1290 6 + +# club +Static 0x13B3 +5360 1361 8 +5368 1361 7 + +# skull with candle +CandleSkull 0x1854 +5360 1363 13 +5360 1359 13 +5368 1359 11 +5368 1363 11 +5312 1304 14 +5310 1316 0 +5316 1316 0 + +# lever +Static 0x108C +5360 2010 6 + +# curtain rod +Static 0x0433 +5362 1291 6 +5365 1291 6 + +# hatchet +Static 0x0F44 +5360 1365 7 +5368 1357 7 +5368 1365 7 + +# stone stairs +Static 0x078C +5362 1292 0 +5362 1293 0 +5362 1294 0 +5362 1295 0 +5362 1296 0 +5271 2025 0 +5271 2026 0 +5271 2027 0 +5271 2028 0 +5271 2029 0 +5271 2035 0 +5271 2036 0 +5271 2037 0 +5271 2038 0 +5271 2039 0 +5271 2040 0 +5271 2041 0 +5271 2042 0 +5271 2043 0 +5140 2015 0 +5140 2016 0 +5140 2017 0 +5140 2018 0 +5362 1291 0 + +# two handed axe +Static 0x1442 +5360 1366 7 +5368 1358 7 +5368 1366 7 + +# orc helm +Static 0x1F0B +5362 1368 8 +5363 1368 8 +5364 1368 7 +5365 1368 8 +5366 1368 8 + +# rack +Static 0x1259 +5364 1291 0 +5364 1288 0 +5364 1289 0 +5364 1290 0 +5364 1292 0 +5364 1293 0 +5364 1294 0 +5364 1295 0 +5364 1296 0 +5364 1297 0 +5364 1298 0 +5273 2023 0 +5273 2024 0 +5273 2025 0 +5273 2026 0 +5273 2027 0 +5273 2036 0 +5273 2037 0 +5273 2038 0 +5273 2039 0 +5273 2040 0 +5273 2041 0 +5273 2042 0 +5273 2043 0 + +# crate +LargeCrate 0x0E3D +5356 1296 0 + +# rock +Static 0x1772 +5357 1296 0 +5272 2029 0 +5294 2010 0 + +# stone stairs +Static 0x0790 +5362 1297 0 + +# stone wall +Static 0x01E9 +5363 1298 0 +5270 2032 0 + +# wooden planks +Static 0x04DC +5295 2001 22 +5293 2001 22 +5294 2001 22 + +# wooden planks +Static 0x04D7 +5297 1999 40 +5354 1992 40 +5297 1974 20 +5297 1975 20 +5295 1999 40 +5296 1999 40 +5297 1972 20 +5356 1992 40 +5341 1998 0 +5355 1992 40 +5297 1973 20 + +# wooden planks +Static 0x04E0 +5297 2000 40 +5356 1993 40 + +# fur%s% +Static 0x11F7 +5362 1320 0 +5362 1324 0 + +# wooden chest +WoodenChest 0x0E43 +5363 1320 0 +5365 1320 0 + +# shovel +Static 0x0F39 +5294 2008 0 +5290 2032 0 + +# entrails +Static 0x1CEF +5363 1332 0 + +# flowstone +Static 0x08E3 +5362 1343 0 +5359 1362 0 +5365 1287 22 +5324 2019 0 +5294 2025 0 +5297 2028 0 +5305 1975 0 +5313 1991 0 +5318 2015 0 +5131 1970 0 +5139 1971 0 +5331 2010 0 +5141 2006 2 +5295 1299 0 +5325 1999 0 +5295 1355 0 +5306 1318 0 + +# tattered banner +Static 0x042F +5359 1354 0 +5359 1358 0 +5359 1362 0 +5359 1366 0 + +# tattered banner +Static 0x042E +5359 1355 0 +5359 1359 0 +5359 1363 0 +5359 1367 0 + +# tattered banner +Static 0x042A +5359 1356 0 +5359 1360 0 +5359 1364 0 +5135 1968 18 +5165 1968 18 +5307 1313 0 +5307 1317 0 + +# tattered banner +Static 0x042B +5359 1357 0 +5359 1361 0 +5359 1365 0 +5135 1969 18 +5165 1969 18 +5307 1314 0 +5307 1318 0 + +# bow +Static 0x13B1 +5360 1356 4 +5360 1358 6 + +# log table +Static 0x11E0 +5360 1356 0 +5360 1360 0 +5360 1364 0 +5368 1356 0 +5368 1360 0 +5368 1364 0 +5312 1305 0 +5312 1308 0 + +# arrows +Static 0x0F41 +5360 1357 6 + +# log table +Static 0x11E1 +5360 1357 0 +5360 1361 0 +5360 1365 0 +5368 1357 0 +5368 1361 0 +5368 1365 0 +5312 1306 0 +5312 1309 0 + +# log table +Static 0x11DF +5360 1358 0 +5360 1362 0 +5360 1366 0 +5368 1358 0 +5368 1362 0 +5368 1366 0 +5312 1307 0 +5312 1310 0 + +# war mace +Static 0x1406 +5360 1361 11 +5360 1362 10 +5360 1362 7 +5368 1361 10 +5368 1362 9 +5368 1362 6 + +# war hammer +Static 0x1438 +5360 1361 4 +5368 1361 3 + +# axe +Static 0x0F4A +5360 1364 3 +5368 1356 3 +5368 1364 3 + +# large battle axe +Static 0x13FA +5360 1364 6 +5368 1356 6 +5368 1364 6 + +# double axe +Static 0x0F4C +5360 1365 4 +5368 1357 4 +5368 1365 4 + +# executioner's axe +Static 0x0F46 +5360 1366 4 +5368 1358 4 +5368 1366 4 + +# ringmail gloves +Static 0x13F2 +5361 1368 5 +5366 1368 7 + +# log table +Static 0x11DD +5361 1368 0 +5313 1304 0 + +# ringmail tunic +Static 0x13EC +5362 1368 6 +5363 1368 6 +5365 1368 6 +5366 1368 6 + +# log table +Static 0x11DE +5362 1368 0 +5363 1368 0 +5364 1368 0 +5365 1368 0 +5314 1304 0 + +# waterfall +Static 0x3511 +5313 1955 7 +5311 1955 7 +5312 1955 7 + +# stone stairs +Static 0x078A +5365 1288 0 +5365 1289 0 +5365 1291 0 +5365 1292 0 +5365 1293 0 +5365 1294 0 +5365 1295 0 +5365 1296 0 +5274 2025 0 +5274 2026 0 +5274 2027 0 +5274 2036 0 +5274 2037 0 +5274 2038 0 +5274 2039 0 +5274 2040 0 +5274 2041 0 +5274 2042 0 +5274 2043 0 +5292 1338 0 +5292 1339 0 +5292 1340 0 + +# whirlpool +Static 0x34B6 +5311 1959 0 + +# rock +Static 0x1771 +5368 1294 0 +5365 1298 0 +5270 2034 0 +5295 2009 0 + +# ore cart +Static 0x1A86 +5368 1295 0 + +# boards +Static 0x1BD9 +5364 1299 0 + +# boards +Static 0x1BDC +5365 1297 3 + +# stone wall +Static 0x01E8 +5365 1297 0 +5273 2028 0 +5270 2031 0 + +# stone wall +Static 0x01EB +5365 1299 0 +5273 2028 3 +5269 2030 0 +5269 2032 0 + +# cave floor +Static 0x0548 (Hue=0x1) +5348 2007 0 + +# fur%s% +Static 0x11F8 +5364 1321 0 + +# debris +Static 0x0C2E +5350 2016 0 +5353 1994 0 +5322 1976 5 +5339 2000 0 +5353 1996 0 +5350 2018 0 +5355 1996 0 +5323 1976 0 + +# rack +Static 0x1250 +5309 1987 0 +5282 2012 0 +5283 2012 0 +5284 2012 0 +5285 2012 0 +5286 2012 0 +5287 2012 0 +5301 1987 0 +5302 1987 0 +5303 1987 0 +5304 1987 0 +5305 1987 0 +5306 1987 0 +5307 1987 0 +5308 1987 0 +5310 1987 0 +5311 1987 0 +5312 1987 0 +5313 1987 0 + +# wooden ladder +Static 0x089F +5296 2001 12 +5298 1972 12 +5298 1975 12 + +# tool kit +Static 0x1EBA +5318 1974 9 + +# heating stand +HeatingStand 0x184A +5332 1320 8 + +# axle%s% with gears +Static 0x1051 +5318 1974 7 + +# bird +Static 0x1E84 +5364 1331 0 + +# arm +Static 0x1CE5 +5364 1332 0 + +# rib cage +Static 0x1B18 +5365 1331 0 +5154 1985 0 + +# bone +Static 0x1B11 +5365 1332 0 +5156 1964 0 + +# garbage +Static 0x10F0 +5367 1328 0 +5140 1996 0 +5155 1986 0 +5316 1373 0 + +# barred metal door +BarredMetalDoor2 0x1FF5 (Facing=SouthCW) +5311 1372 0 + +# wooden stairs +Static 0x073B +5307 2006 0 +5309 2006 0 +5311 2006 0 + +# wooden planks +Static 0x04E1 +5356 1991 40 +5297 1998 40 + +# ringmail gloves +Static 0x13EB +5364 1368 6 + +# log table +Static 0x11DC +5366 1368 0 +5315 1304 0 + +# shovel +Static 0x0F3A +5289 2012 2 + +# stone wall +Static 0x01EA +5270 2031 3 + +# stone arch +Static 0x01E1 +5270 2033 0 + +# cannon +Static 0x0E96 (Name=an orcish drilling device) +5362 2010 0 + +# water +Static 0x17AC +5316 1956 0 + +# water +Static 0x1798 +5317 1956 0 +5317 1957 0 +5315 1957 0 +5316 1957 0 +5318 1956 0 +5319 1956 0 +5315 1958 0 +5316 1958 0 +5317 1958 0 +5317 1959 0 +5318 1958 0 +5319 1957 0 + +# stone stairs +Static 0x078F +5273 2035 0 +5292 1337 0 + +# tinker's tools +Static 0x1EBC +5320 1979 0 + +# wooden shingles +Static 0x05CF +5287 2011 11 + +# bone pile +Static 0x1B09 +5276 2026 0 +5359 2003 0 +5147 1971 0 +5155 1992 0 +5313 1343 0 +5317 1332 0 + +# rack +Static 0x1251 +5282 2013 0 +5283 2013 0 +5284 2013 0 +5285 2013 0 +5286 2013 0 +5287 2013 0 +5301 1988 0 +5302 1988 0 +5303 1988 0 +5304 1988 0 +5305 1988 0 +5306 1988 0 +5307 1988 0 +5308 1988 0 +5309 1988 0 +5310 1988 0 +5311 1988 0 +5312 1988 0 +5313 1988 0 + +# crate +LargeCrate 0x0E3C +5284 2011 3 +5285 2011 3 +5135 1964 0 +5135 1965 3 +5135 1965 0 +5135 1966 0 + +# crate +MediumCrate 0x0E3E +5284 2011 7 + +# wooden wall +Static 0x0018 +5287 2010 26 + +# wooden ladder +Static 0x08A1 +5288 2010 0 +5297 2001 0 +5299 1972 0 +5299 1975 0 + +# diamond%s% +Static 0x0F29 +5288 2013 1 +5310 2009 8 + +# sapphire%s% +Static 0x0F11 +5288 2013 0 + +# rub%ies/y% +Static 0x0F1D +5288 2013 5 + +# rub%ies/y% +Static 0x0F2B +5288 2013 4 + +# citrine%s% +Static 0x0F2C +5288 2013 6 + +# lantern +Lantern 0x0A22 +5322 1980 9 + +# emerald%s% +Static 0x0F2F +5288 2013 6 + +# amethyst%s% +Static 0x0F22 +5288 2013 4 + +# rock +Static 0x1779 +5289 2008 0 +5290 2009 0 +5291 2007 0 + +# wooden signpost +Static 0x0B98 +5323 1975 19 +5305 1962 19 + +# stone stairs +Static 0x0789 +5284 2014 0 +5285 2014 0 +5286 2014 0 +5303 1989 0 +5304 1989 0 +5305 1989 0 +5307 1989 0 +5308 1989 0 +5309 1989 0 +5310 1989 0 +5311 1989 0 +5312 1989 0 +5289 1341 0 +5290 1341 0 +5291 1341 0 +5306 1989 0 + +# stone stairs +Static 0x078E +5287 2014 0 +5292 1341 0 + +# vat +Static 0x14DF +5296 1997 41 +5355 1990 41 + +# dried onions +Static 0x0C3F +5290 1315 3 + +# wooden planks +Static 0x04DF +5293 1998 29 +5295 1998 40 +5354 1991 40 + +# wooden planks +Static 0x04DE +5293 1999 29 + +# wooden ladder +Static 0x08A3 +5293 2000 21 +5354 1994 2 + +# vat +Static 0x14DE +5294 1999 41 +5353 1992 41 + +# cave floor +Static 0x0547 (Hue=0x1) +5332 2003 0 +5346 2009 0 + +# vat +Static 0x1558 +5295 1998 41 +5354 1991 41 + +# vat +Static 0x1554 +5296 1998 41 +5355 1991 41 + +# water +Static 0x1559 +5296 1999 41 +5355 1992 41 + +# vat +Static 0x1550 +5296 2001 41 +5355 1994 41 + +# rock +Static 0x177A +5290 2008 0 + +# bardiche +Static 0x0F4D +5347 1993 0 +5316 1972 0 + +# pitchfork +Static 0x0E87 +5347 1993 0 +5316 1972 0 + +# pullies +Static 0x1E9C +5305 1963 24 +5316 1982 19 + +# cannon +Static 0x0E8D (Name=an orcish drilling device) +5348 1994 0 +5317 1973 0 + +# cannon +Static 0x0E8C (Name=an orcish drilling device) +5348 1995 0 +5317 1974 0 + +# hook +Static 0x1E9A +5298 1971 17 + +# fizzle +Static 0x3735 +5348 1996 18 +5317 1975 18 + +# vat +Static 0x14D7 +5297 2000 41 +5356 1993 41 + +# blood +Static 0x122A (Hue=0x107) +5330 1321 0 + +# water trough +WaterTroughSouthAddon 0x0B43 +5299 1997 0 + +# water trough +Static 0x0B44 +5300 1997 0 + +# vat +Static 0x1556 +5298 1999 41 +5357 1992 41 + +# cave floor +Static 0x0549 (Hue=0x1) +5346 2008 0 +5347 2007 0 +5332 2002 0 + +# water +Static 0x17A3 +5310 1958 0 +5310 1959 0 +5323 1307 0 + +# waterfall +Static 0x3523 +5311 1958 0 +5312 1958 0 +5313 1958 0 + +# rock +Static 0x34AC +5312 1958 0 + +# water +Static 0x17AB +5312 1960 0 + +# skinned deer +Static 0x1E90 +5329 1352 0 + +# debris +Static 0x0C30 +5351 2015 0 +5342 1998 0 +5354 1995 0 + +# bones +Static 0x0ED1 +5351 2016 0 + +# wooden fence +Static 0x088B +5351 2017 0 +5351 2018 0 +5351 2021 0 + +# lever +Static 0x1095 +5347 1996 5 +5348 1996 6 +5317 1975 6 + +# wooden stairs +Static 0x073C +5306 2007 0 +5306 2009 0 +5306 2011 0 + +# wood +Static 0x0738 +5307 2007 0 +5307 2008 0 +5307 2009 0 +5307 2010 0 +5307 2011 0 +5308 2007 0 +5308 2008 0 +5308 2009 0 +5308 2010 0 +5308 2011 0 +5309 2007 0 +5309 2008 0 +5309 2009 0 +5309 2010 0 +5309 2011 0 +5310 2007 0 +5310 2008 0 +5310 2009 0 +5310 2010 0 +5310 2011 0 +5311 2007 0 +5311 2008 0 +5311 2009 0 +5311 2010 0 +5311 2011 0 + +# wooden stairs +Static 0x0739 +5307 2012 0 +5309 2012 0 +5311 2012 0 + +# rocks +Static 0x136A +5308 2008 5 + +# bones +Static 0x0ECF +5356 1995 0 + +# stool +Stool 0x0A2A +5309 2008 5 + +# forge +SmallForgeAddon 0x0FB1 +5309 2009 5 +5318 1978 0 + +# table +Static 0x0B36 +5310 2009 5 + +# wooden stairs +Static 0x073A +5312 2007 0 +5312 2009 0 +5312 2011 0 + +# water +Static 0x17A0 +5314 1957 0 +5317 1955 0 +5318 1955 0 +5319 1955 0 + +# water +Static 0x17A6 +5315 1956 0 +5316 1955 0 +5323 1306 0 + +# tongs +Static 0x0FBC +5310 2009 11 + +# water +Static 0x346E +5318 1957 0 + +# water +Static 0x17A9 +5320 1956 0 + +# water +Static 0x17AA +5320 1957 0 +5317 1960 0 +5318 1959 0 +5319 1958 0 + +# water +Static 0x17B1 +5321 1957 0 + +# rock +Static 0x3423 +5316 1958 0 + +# water +Static 0x179A +5316 1959 0 +5316 1960 0 + +# cannon +Static 0x0E8B (Name=an orcish drilling device) +5317 1975 0 +5348 1996 0 + +# empty jars +Static 0x0E46 +5318 1974 0 + +# table +Static 0x0B3C +5318 1974 0 + +# barrel hoops +Static 0x10E2 +5319 1981 0 +5321 1977 0 + +# cannon +Static 0x0E8E (Name=an orcish drilling device) +5321 1976 0 + +# barrel staves +Static 0x1EB1 +5321 1981 0 + +# wooden signpost +Static 0x0B97 +5316 1982 19 +5297 1970 6 + +# iron wire +Static 0x1876 +5318 1982 6 + +# bottle +Static 0x0E2C +5318 1982 10 +5314 1304 6 + +# table +Static 0x0B34 +5318 1982 0 +5320 1982 0 +5322 1978 0 + +# lever +Static 0x1094 +5320 1982 9 + +# unfinished barrel +Static 0x1EB5 +5321 1982 0 + +# tool kit +Static 0x1EBB +5322 1978 8 + +# palisade +Static 0x0221 +5131 1968 20 +5131 1969 20 +5131 1970 20 +5134 1968 20 +5134 1969 20 +5146 1969 0 +5149 1969 0 +5149 1970 0 +5161 1968 20 +5161 1969 20 +5161 1970 20 +5164 1968 20 +5164 1969 20 + +# palisade +Static 0x0424 +5131 1968 40 +5131 1970 40 +5134 1968 40 +5161 1968 40 +5161 1970 40 +5164 1968 40 + +# wooden wall +Static 0x0227 +5131 1968 0 +5131 1969 0 +5131 1970 0 +5134 1968 0 +5134 1969 0 +5161 1968 0 +5161 1969 0 +5164 1968 0 +5164 1969 0 + +# palisade +Static 0x0222 +5132 1967 20 +5132 1970 20 +5133 1967 20 +5133 1970 20 +5134 1967 20 +5135 1970 0 +5137 1970 0 +5139 1970 0 +5141 1970 0 +5143 1970 0 +5145 1970 0 +5150 1970 0 +5151 1970 0 +5153 1970 0 +5155 1970 0 +5157 1970 0 +5159 1970 0 +5162 1967 20 +5162 1970 20 +5163 1967 20 +5163 1970 20 +5164 1967 20 + +# palisade +Static 0x0423 +5132 1967 40 +5132 1970 40 +5134 1967 40 +5136 1970 20 +5138 1970 20 +5140 1970 20 +5142 1970 20 +5144 1970 20 +5152 1970 20 +5154 1970 20 +5156 1970 20 +5158 1970 20 +5160 1970 20 +5162 1967 40 +5162 1970 40 +5164 1967 40 + +# wooden wall +Static 0x0228 +5132 1967 0 +5132 1970 0 +5133 1967 0 +5133 1970 0 +5134 1967 0 +5136 1970 0 +5138 1970 0 +5140 1970 0 +5142 1970 0 +5144 1970 0 +5152 1970 0 +5154 1970 0 +5156 1970 0 +5158 1970 0 +5160 1970 0 +5162 1967 0 +5162 1970 0 +5163 1967 0 +5163 1970 0 +5164 1967 0 + +# palisade +Static 0x0223 +5134 1970 0 +5134 1970 20 +5146 1970 0 +5161 1970 0 +5164 1970 20 + +# palisade +Static 0x0425 +5134 1970 40 +5164 1970 40 + +# small crate +SmallCrate 0x09A9 +5135 1966 3 + +# wooden stairs +Static 0x0725 +5137 1969 0 + +# wood +Static 0x0721 +5138 1969 0 +5139 1969 0 +5140 1969 0 +5141 1969 0 +5142 1969 0 +5143 1969 0 +5144 1969 0 +5145 1969 0 +5150 1969 0 +5151 1969 0 +5152 1969 0 +5153 1969 0 +5154 1969 0 +5155 1969 0 +5156 1969 0 +5157 1969 0 + +# wooden stairs +Static 0x0724 +5145 1968 0 +5150 1968 0 + +# hay +Static 0x1036 +5154 1956 0 +5156 1956 0 + +# fallen log +Static 0x0CF3 +5154 1963 0 + +# fallen log +Static 0x0CF4 +5154 1964 0 + +# wooden stairs +Static 0x0723 +5158 1969 0 + +# wooden wall +Static 0x0226 +5164 1970 0 + +# vines +Static 0x0CF2 +5288 1311 2 +5288 1317 2 + +# vines +Static 0x0CEC +5288 1311 1 +5290 1311 1 +5289 1315 0 +5289 1318 0 +5293 1311 2 + +# vines +Static 0x0CEB +5289 1311 1 +5294 1311 2 + +# vines +Static 0x0CEE +5291 1311 1 +5287 1321 2 +5295 1311 8 + +# vines +Static 0x0CEF +5287 1312 1 +5287 1313 1 +5287 1314 1 +5287 1318 1 +5287 1319 1 + +# mushrooms +Static 0x0D0D +5288 1312 0 +5289 1319 0 +5290 1317 0 +5294 1313 0 + +# mushrooms +Static 0x0D12 +5288 1313 0 +5289 1316 0 +5291 1313 0 +5291 1315 0 +5291 1319 0 +5293 1317 0 + +# mushrooms +Static 0x0D15 +5288 1315 0 +5289 1312 0 +5290 1319 0 +5291 1317 0 +5293 1315 0 +5323 1306 0 + +# mushrooms +Static 0x0D13 +5288 1317 0 +5288 1319 0 +5289 1313 0 +5289 1315 0 +5289 1318 0 +5291 1314 0 +5292 1316 0 +5293 1313 0 +5293 1318 0 + +# light +Static 0x1ECF (Light=Circle300) +5289 1313 -2 +5290 1318 -2 +5292 1313 -2 + +# dried flowers +Static 0x0C3E +5289 1315 3 +5289 1318 1 + +# dried flowers +Static 0x0C3C +5289 1318 1 + +# cave wall +Static 0x0267 +5287 1320 0 + +# fire +Static 0x19AB (Light=Circle300) +5290 1335 28 +5289 1338 8 +5289 1340 8 +5290 1344 28 +5293 1335 28 +5293 1344 28 + +# stone wall +Static 0x01D1 +5288 1337 5 +5288 1337 28 +5288 1339 24 +5288 1341 5 + +# stone +Static 0x0787 +5288 1337 61 + +# stone +Static 0x0784 +5288 1341 61 +5288 1342 44 + +# cannon +Static 0x0E94 (Name=an orcish drilling device) +5360 2010 0 + +# cannon +Static 0x0E95 (Name=an orcish drilling device) +5361 2010 0 + +# stone pillar +Static 0x01DA +5288 1342 92 + +# blood +Static 0x1CD9 +5289 1339 0 +5290 1339 0 + +# mushrooms +Static 0x0D0E +5292 1313 0 + +# shackles +Static 0x1640 +5305 1367 0 +5307 1367 0 +5303 1370 0 +5303 1373 0 + +# skeleton +Static 0x1B80 +5304 1371 4 + +# bone shards +Static 0x1B1A +5312 1305 6 + +# blood +Static 0x122D +5312 1306 7 +5311 1315 0 +5316 1304 0 +5317 1309 0 +5317 1315 0 + +# bird%s +Static 0x1E85 +5312 1306 6 + +# pig's feet +Static 0x1E8C +5312 1307 6 + +# butcher knife +Static 0x13F7 +5312 1308 6 + +# chicken +Static 0x1E87 +5312 1309 0 + +# jaw bone +Static 0x1B13 +5312 1310 7 + +# Eye%s% of Newt +Static 0x0F87 +5313 1304 7 + +# bottle +Static 0x0E2B +5314 1304 7 + +# bottle +Static 0x0E25 +5315 1304 7 + +# refuse +Static 0x1BBA +5314 1327 0 +5315 1328 0 + +# refuse +Static 0x1BB4 +5311 1330 0 +5312 1331 0 +5321 1330 0 +5317 1344 0 + +# refuse +Static 0x1BB7 +5312 1328 0 +5320 1326 0 +5321 1327 0 +5317 1341 0 + +# refuse +Static 0x1BAB +5312 1329 0 +5321 1328 0 +5317 1342 0 + +# refuse +Static 0x1BB6 +5312 1330 0 +5321 1329 0 +5317 1343 0 + +# refuse +Static 0x1BAA +5313 1328 0 +5314 1328 0 +5321 1326 0 +5322 1326 0 +5322 1327 0 +5323 1327 0 +5318 1341 0 +5319 1341 0 + +# refuse +Static 0x1BA0 +5313 1331 0 +5322 1330 0 +5318 1344 0 + +# refuse +Static 0x1BB2 +5314 1330 0 +5323 1329 0 +5319 1343 0 + +# refuse +Static 0x1BBC +5314 1331 0 +5323 1330 0 +5319 1344 0 + +# skeleton with meat +Static 0x1B1E +5308 1368 1 +5316 1304 0 + +# window +Static 0x01D4 +5311 1370 0 +5311 1373 0 + +# skull with candle +CandleSkull 0x1858 +5316 1310 0 + +# pickaxe +Static 0x0E86 +5315 1994 0 diff --git a/Data/Decoration/Britannia/_shame.cfg b/Data/Decoration/Britannia/_shame.cfg new file mode 100644 index 0000000..3e2e182 --- /dev/null +++ b/Data/Decoration/Britannia/_shame.cfg @@ -0,0 +1,901 @@ +# lever +Static 0x108E +5420 240 10 + +# water +Static 0x179B +5705 41 -5 +5706 41 -5 +5751 17 -5 +5560 212 -5 +5672 43 -5 +5461 195 -5 +5516 245 -5 +5546 15 -5 +5620 66 -5 +5425 200 -5 +5424 198 -5 + +# floor spikes +SpikeTrap 0x11A0 +5591 241 0 +5607 18 10 +5570 117 5 +5616 189 0 +5553 204 0 +5430 139 20 +5588 218 0 + +# wooden box +Static 0x0E7D +5424 114 0 + +# wooden chest +WoodenChest 0x0E42 +5415 241 10 +5406 42 30 +5465 101 35 +5445 184 0 +5573 114 5 +5403 150 20 +5568 119 5 +5808 13 0 +5384 147 20 +5472 181 0 +5477 180 0 +5868 118 10 +5384 13 30 +5736 53 0 +5384 145 20 +5384 149 20 +5404 60 -20 + +# stalagmites +Static 0x08E4 +5409 138 10 +5411 137 10 + +# barrel +Barrel 0x0E77 +5456 82 20 +5456 84 20 +5456 84 25 +5577 186 0 +5523 214 0 +5523 214 5 +5524 212 0 +5524 212 5 +5608 30 10 +5575 190 10 +5576 186 10 +5442 178 5 +5442 177 5 +5442 177 10 +5441 177 5 +5441 177 0 +5440 182 5 +5440 182 0 +5440 179 10 +5440 179 0 +5440 178 5 +5440 178 0 +5440 177 5 +5440 177 10 +5440 177 0 +5440 179 5 +5442 177 0 +5442 178 0 +5436 102 20 +5437 102 20 +5728 90 5 +5437 102 25 +5455 84 20 +5455 84 25 +5489 58 20 +5489 59 20 +5489 59 25 +5491 60 20 +5609 30 10 +5610 29 10 +5610 29 15 +5727 90 5 +5727 91 0 +5522 60 0 +5522 60 5 +5522 61 0 +5522 61 5 +5522 62 0 +5388 205 10 +5733 89 0 +5734 88 0 +5734 88 5 +5734 89 0 +5510 222 0 +5522 200 5 +5510 221 5 +5510 221 0 +5509 222 5 +5509 222 0 +5574 190 10 +5576 185 0 +5576 186 5 +5727 90 0 +5439 182 5 +5439 182 0 +5434 181 5 +5434 180 5 +5434 180 10 +5434 180 0 +5433 181 0 +5433 180 5 +5433 180 10 +5433 180 0 +5433 181 10 +5434 181 0 +5578 190 5 +5578 190 10 +5578 190 0 +5578 189 5 +5578 189 0 +5577 190 5 +5577 190 0 +5577 185 5 +5577 185 0 +5576 186 0 +5576 185 5 +5727 91 5 +5728 90 0 +5433 181 5 +5433 180 15 +5733 88 0 +5733 88 5 +5734 89 5 +5569 189 5 +5522 201 0 +5523 201 5 +5523 201 0 +5523 200 5 +5523 200 0 +5522 201 5 +5609 12 10 +5522 200 0 +5395 40 30 +5395 40 35 +5396 40 30 +5525 204 0 +5525 204 5 +5569 188 15 +5569 188 0 +5575 190 5 +5610 10 10 +5610 10 15 +5610 11 10 +5611 11 10 +5611 11 15 +5575 190 0 +5574 190 5 +5574 190 0 +5571 188 0 +5570 190 5 +5570 190 0 +5570 189 5 +5570 189 0 +5570 188 5 +5570 188 0 +5569 190 5 +5569 190 10 +5569 190 0 +5569 189 10 +5569 189 0 +5569 188 5 +5569 188 10 + +# gas trap +GasTrap 0x113C +5540 213 0 +5552 203 0 +5427 215 0 +5413 192 0 +5538 188 0 + +# wooden chest +WoodenChest 0x0E43 +5424 45 10 +5434 195 22 +5621 27 10 +5494 57 20 +5440 191 22 +5817 78 0 +5698 19 10 +5525 62 0 +5422 244 10 +5608 8 10 +5480 198 0 + +# wooden planks +Static 0x04C6 +5460 185 0 +5460 187 0 +5460 186 0 +5460 188 0 + +# water +Static 0x179C +5617 57 -5 +5554 10 -5 + +# plate helm +Static 0x1412 +5829 23 13 + +# water +Static 0x179A +5596 74 -5 +5611 61 -5 +5549 15 -5 +5617 64 -5 +5621 67 -5 + +# stone pillar +Static 0x01DA +5570 186 44 +5570 190 44 +5574 186 44 +5570 194 44 +5570 197 44 +5570 201 44 +5570 205 44 +5574 198 44 +5574 193 44 +5575 189 44 +5575 190 44 +5575 191 44 +5575 192 44 +5575 193 44 +5575 198 44 +5575 199 44 +5575 200 44 +5575 201 44 +5575 202 44 +5574 205 44 +5576 198 44 +5576 193 44 +5577 193 44 +5577 198 44 +5578 198 44 +5578 193 44 +5578 186 44 +5578 205 44 +5579 202 44 +5579 201 44 +5579 200 44 +5579 199 44 +5579 197 44 +5579 196 44 +5579 195 44 +5579 194 44 +5579 193 44 +5579 192 44 +5579 191 44 +5579 190 44 +5579 189 44 +5580 189 44 +5580 191 44 +5580 192 44 +5580 193 44 +5580 194 44 +5580 195 44 +5580 196 44 +5580 197 44 +5580 198 44 +5580 199 44 +5580 200 44 +5580 201 44 +5580 202 44 +5581 205 44 +5581 198 44 +5581 193 44 +5581 186 44 +5582 193 44 +5583 193 44 +5585 186 44 +5584 189 44 +5584 190 44 +5584 191 44 +5584 193 44 +5584 198 44 +5584 199 44 +5584 200 44 +5584 201 44 +5585 193 44 +5585 198 44 +5585 205 44 +5589 205 44 +5589 201 44 +5589 197 44 +5589 194 44 +5589 190 44 +5589 186 44 +5580 190 44 +5584 192 44 +5579 198 44 +5582 198 44 +5583 198 44 +5584 202 44 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +5405 41 30 +5402 46 30 +5404 43 30 +5399 40 30 + +# bedroll +Static 0x0A57 +5514 215 0 +5526 58 0 +5515 220 0 + +# switch +Static 0x1092 +5569 199 11 +5492 200 16 +5493 200 16 +5595 62 12 +5448 184 11 +5581 192 11 + +# bedroll +Static 0x0A59 +5523 54 0 +5524 57 0 +5489 50 20 +5493 50 20 +5528 50 0 +5519 216 0 +5514 215 0 + +# empty jar +Static 0x1005 +5728 92 0 +5728 93 0 +5727 92 0 + +# lantern +Lantern 0x0A22 +5405 43 30 +5465 184 12 +5465 189 13 +5390 43 20 +5449 81 20 +5392 89 20 + +# vase +Static 0x0B46 +5734 94 0 + +# glowing rune +Static 0x0E5F +5736 48 5 + +# glowing rune +Static 0x0E5C +5736 50 5 + +# glowing rune +Static 0x0E62 +5738 48 5 + +# glowing rune +Static 0x0E65 +5738 50 5 + +# metal door +MetalDoor2 0x06C5 (Facing=WestCW) +5540 183 0 +5517 178 0 +5445 183 22 +5434 190 22 +5506 167 0 + +# floor saw +SawTrap 0x11B1 +5579 199 0 +5421 140 10 +5569 191 44 +5571 118 5 +5598 228 0 + +# barrel +Barrel 0x0FAE +5406 43 30 +5492 56 20 +5393 46 30 +5406 44 31 +5614 15 10 +5534 45 0 +5728 91 0 +5604 20 10 +5435 98 20 +5523 204 0 +5503 224 0 +5501 217 0 +5497 220 0 +5525 59 0 +5452 83 20 + +# platemail gloves +Static 0x1418 +5779 27 0 + +# cauldron +Static 0x0974 +5402 43 30 +5491 52 20 +5516 216 0 +5524 50 0 + +# pickaxe +Static 0x0E85 +5514 218 0 +5512 221 0 +5428 113 0 +5434 99 20 + +# backpack +Static 0x0E75 +5513 220 0 +5728 94 0 +5449 82 20 + +# backpack +Backpack 0x09B2 +5518 214 0 +5513 213 0 + +# bedroll +Static 0x0A55 +5515 220 0 + +# switch +Static 0x108F +5433 189 11 +5600 57 13 +5433 195 12 + +# floor saw +SawTrap 0x11AC +5615 237 0 +5573 217 0 +5572 222 0 +5441 186 22 +5572 203 0 + +# metal chest +MetalGoldenChest 0x0E41 +5703 58 2 +5475 196 0 +5819 82 0 +5483 205 0 +5436 182 0 +5477 201 0 +5572 117 5 + +# cot +Static 0x11FD +5433 194 22 + +# broken chair +Static 0x0C19 +5435 185 0 +5441 186 0 +5447 194 22 +5581 195 22 +5582 203 22 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +5441 194 0 +5441 193 22 +5443 180 0 +5442 179 22 +5440 187 22 +5447 187 0 +5823 51 0 +5818 54 0 +5579 202 22 +5583 195 0 +5577 188 22 +5579 187 0 +5504 179 0 + +# switch +Static 0x1091 +5595 62 12 +5493 200 16 +5581 192 11 + +# crate +SmallCrate 0x0E7E +5395 145 20 // spawning +5587 136 10 // spawning +5731 93 0 +5731 94 0 +5731 94 2 +5732 94 2 +5731 93 2 +5732 94 0 + +# bed +Static 0x11D2 +5451 177 22 +5447 177 22 +5575 199 22 +5586 185 22 + +# metal door +MetalDoor2 0x06CF (Facing=NorthCCW) +5447 186 0 +5823 50 0 +5583 194 0 +5504 178 0 + +# metal chest +MetalChest 0x09AB +5416 243 10 +5604 28 10 +5741 48 0 +5699 86 0 + +# cloak +Static 0x1515 (Hue=0x26) +5564 227 0 + +# switch +Static 0x1090 +5600 57 13 +5433 195 12 + +# lever +Static 0x108C +5420 240 10 +5496 205 0 + +# crate +MediumCrate 0x0E3E +5399 146 20 // spawning + +# metal chest +MetalGoldenChest 0x0E40 +5594 245 0 +5487 194 0 +5414 243 10 +5607 210 0 +5582 193 0 + +# fishing net +Static 0x0DCA +5500 221 0 + +# fishing net +Static 0x0DC9 +5500 222 0 + +# small crate +SmallCrate 0x09A9 +5588 137 10 // spawning + +# bedroll +Static 0x0A56 +5514 215 0 +5489 50 20 +5401 41 30 +5401 46 30 +5404 41 30 +5404 46 30 +5451 82 20 +5523 54 0 +5524 57 0 +5519 216 0 +5526 58 0 +5528 50 0 + +# cave floor +Static 0x053C +5518 175 0 + +# dungeon wall +Static 0x0242 +5541 172 0 +5541 168 0 +5541 169 0 +5541 171 0 + +# water tub +Static 0x0E7B +5435 98 20 + +# pickaxe +Static 0x0E86 +5430 113 0 +5452 87 20 +5511 222 0 +5520 216 0 + +# wooden logs +Static 0x050A +5542 13 0 + +# metal door +MetalDoor2 0x06D1 (Facing=SouthCCW) +5578 202 0 +5575 195 22 + +# crate +LargeCrate 0x0E3C +5728 95 0 +5727 94 0 +5727 94 3 +5727 95 0 +5727 95 3 +5727 95 6 +5727 93 0 + +# stalagmites +Static 0x08E0 +5482 25 -30 +5481 25 -30 +5481 27 -30 +5482 27 -30 +5482 26 -30 + +# water barrel +Static 0x154D +5728 91 0 + +# bottle +Static 0x0EFF +5436 188 28 + +# cloak +Static 0x1515 (Hue=0x1B5) +5557 138 20 + +# dungeon wall +SecretDungeonDoor 0x031E (Facing=NorthCCW) +5541 170 0 + +# flowstone +Static 0x08E2 +5410 137 10 + +# shoes +Static 0x170F +5579 195 0 + +# long pants +Static 0x1539 +5579 195 0 + +# shirt +Static 0x1517 +5579 195 0 + +# metal door +MetalDoor2 0x06C9 (Facing=WestCCW) +5581 191 22 +5435 190 0 +5570 198 0 +5571 198 22 +5507 182 0 + +# metal door +MetalDoor2 0x06CB (Facing=EastCW) +5508 182 0 + +# wooden planks +Static 0x04C8 +5456 186 0 +5456 185 0 +5456 187 0 +5456 188 0 + +# floor spikes +SpikeTrap 0x119A +5576 202 0 +5403 230 10 + +# bottles of liquor +Static 0x099E +5394 40 30 + +# bottles of liquor +Static 0x099D +5398 44 30 + +# mushroom +MushroomTrap 0x1125 +5868 56 0 + +# water +Static 0x1799 +5436 168 -5 +5461 195 -5 + +# candle +CandleLarge 0x0A26 +5438 186 4 + +# stone face +Static 0x10FD +5434 184 22 +5436 184 22 +5438 184 22 +5572 192 22 + +# cot +Static 0x11FE +5434 194 22 + +# bottle +Static 0x0F00 +5436 185 28 + +# bottle +Static 0x0F03 +5436 185 28 + +# broken chair +Static 0x0C1A +5436 186 23 +5437 188 22 +5438 195 0 +5441 187 0 +5443 192 0 +5444 195 22 +5571 203 22 +5575 203 0 +5582 202 0 + +# bottle +Static 0x0E29 +5436 188 28 + +# cot +Static 0x11FF +5436 191 22 +5438 191 22 + +# cot +Static 0x1200 +5436 192 22 +5438 192 22 + +# broken chair +Static 0x0C1E +5436 195 0 +5573 202 0 + +# gas trap +Static 0x11A8 +5441 181 0 +5569 159 -10 +5579 155 -10 + +# bed +Static 0x11D5 +5445 177 22 +5449 177 22 +5573 199 22 +5584 185 22 + +# bed +Static 0x11D4 +5445 179 22 +5449 179 22 +5573 201 22 +5584 187 22 + +# bed +Static 0x11D3 +5447 179 22 +5451 179 22 +5575 201 22 + +# stalagmites +Static 0x08E9 +5479 26 -30 + +# bedroll +Static 0x0A58 +5515 220 0 + +# dirt +Static 0x31F5 +5491 22 -52 + +# dyeing tub +DyeTub 0x0FAB (Hue=0x35) +5494 52 20 + +# iron ore +Static 0x19B9 (Hue=0x973) +5609 14 11 + +# fishing net +Static 0x0DD2 +5499 220 0 + +# fishing net +Static 0x0DD3 +5499 221 0 + +# fishing net +Static 0x0DD4 +5499 222 0 + +# fishing net +Static 0x0DC8 +5500 220 0 + +# fishing net +Static 0x0DD1 +5501 220 0 + +# fishing net +Static 0x0DCB +5501 221 0 + +# fishing net +Static 0x0DD5 +5501 222 0 + +# crate +MediumCrate 0x0E3F +5820 85 0 // spawning +5585 137 10 // spawning + +# keg +Keg 0x0E7F +5522 203 0 +5521 202 0 +5520 203 0 +5520 202 0 +5450 92 20 +5450 91 20 +5449 92 20 +5449 91 20 +5448 91 20 + +# stone stairs +Static 0x07A5 +5516 174 -23 + +# dungeon wall +Static 0x0243 +5541 173 0 + +# water +Static 0x1798 +5550 13 -5 + +# metal chest +Metalchest 0x0E7C +5389 223 10 +5572 192 0 + +# cloak +Static 0x1515 +5572 20 0 + +# stone face +Static 0x110F +5569 201 0 + +# bed +Static 0x11CF +5586 187 22 + +# fitting +Static 0x112B +5589 192 0 diff --git a/Data/Decoration/Britannia/_terathankeep.cfg b/Data/Decoration/Britannia/_terathankeep.cfg new file mode 100644 index 0000000..4c327fc --- /dev/null +++ b/Data/Decoration/Britannia/_terathankeep.cfg @@ -0,0 +1,183 @@ +# tightrope +Static 0x2710 +5158 1708 0 +5153 1708 0 +5151 1708 0 +5156 1708 0 + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +5349 1560 0 +5337 1560 0 + +# metal chest +MetalGoldenChest 0x0E40 +5363 1708 -75 + +# iron fence +Static 0x0821 +5432 3152 -55 +5432 3153 -55 +5432 3154 -55 +5432 3155 -55 +5437 3153 -55 +5437 3154 -55 +5437 3152 -55 + +# iron fence +Static 0x0823 +5433 3155 -55 +5434 3155 -55 +5435 3155 -55 +5436 3155 -55 + +# iron fence +Static 0x0849 +5454 3155 -53 +5454 3153 -55 +5454 3152 -55 +5458 3153 -55 +5458 3154 -55 +5458 3152 -55 +5454 3154 -53 +5477 3136 -60 + +# iron fence +Static 0x084B +5455 3151 -55 +5456 3151 -55 +5458 3151 -55 +5457 3155 -55 +5456 3155 -55 +5455 3155 -55 +5434 3151 -55 +5433 3151 -55 +5472 3141 -60 +5437 3151 -55 +5436 3151 -55 +5435 3151 -55 +5457 3151 -55 + +# iron fence +Static 0x0822 +5437 3155 -55 + +# iron fence +Static 0x084A +5476 3138 -60 +5475 3139 -60 +5474 3140 -60 +5473 3141 -60 +5458 3155 -55 +5477 3137 -60 + +# metal chest +Metalchest 0x0E7C +5337 1549 0 +5349 1551 0 + +# brambles +Static 0x0D3F +5484 3146 -45 +5484 3146 -51 +5478 3148 -45 + +# small palm +Static 0x0C9D +5460 3162 -45 + +# stalagmites +Static 0x08E1 +5367 1774 -118 + +# lever +Static 0x1093 +5143 1703 10 + +# metal door +MetalDoor 0x067B (Facing=EastCW) +5343 1571 0 +5343 1557 0 +5335 1543 0 +5355 1544 0 +5344 1577 0 + +# wooden door +StrongWoodDoor 0x06EB (Facing=EastCW) +5303 1568 0 +5300 1556 0 +5309 1556 0 +5294 1564 0 + +# metal door +MetalDoor 0x0683 (Facing=NorthCW) +5333 1556 0 +5333 1547 0 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +5353 1715 -85 +5242 1602 0 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +5356 1556 0 +5356 1548 0 +5242 1603 0 + +# lever +Static 0x108C +5251 1603 7 + +# egg case web +Static 0x10D8 +5302 1552 0 +5300 1548 0 + +# lever +Static 0x1095 +5143 1703 10 + +# metal chest +MetalGoldenChest 0x0E41 +5360 1715 -89 +5351 1551 0 + +# fire +Static 0x19AB +5169 1586 15 + +# wooden chest +WoodenChest 0x0E42 +5360 1705 -67 +5362 1718 -125 +5349 1739 -125 + +# metal door +MetalDoor 0x0679 (Facing=WestCCW) +5343 1577 0 + +# cave wall +Static 0x0274 +5342 1658 22 + +# cocoon +Static 0x10DA +5296 1547 0 + +# web +Static 0x10DD +5296 1547 0 + +# lever +Static 0x108E +5251 1603 7 + +# egg case +Static 0x10D9 +5300 1548 0 +5302 1552 0 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +5292 1560 0 diff --git a/Data/Decoration/Britannia/_wrong.cfg b/Data/Decoration/Britannia/_wrong.cfg new file mode 100644 index 0000000..9346d24 --- /dev/null +++ b/Data/Decoration/Britannia/_wrong.cfg @@ -0,0 +1,370 @@ +# teleporter +Teleporter 0x1BC3 (PointDest=(5690, 569, 25)) +5827 593 0 +5829 593 0 +5871 531 15 +5870 530 15 +5871 530 15 +5870 531 15 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5703, 639, 0)) +5867 528 15 +5868 528 15 +5868 529 15 +5867 529 15 +5705 625 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5793, 527, 10)) +5698 662 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5829, 595, 0)) +5733 554 20 +5690 569 25 + +# sparkle +Static 0x375A +5703 639 0 +5706 625 0 +5698 662 0 +5732 554 24 +5792 525 10 +5827 593 0 +5829 593 0 +5690 569 25 +5867 528 15 +5872 532 24 + +# crate +LargeCrate 0x0E3C +5683 521 0 +5678 521 0 +5682 521 0 + +# spike trap +GiantSpikeTrap 0x0001 +5653 568 20 + +# floor spikes +SpikeTrap 0x119A +5700 529 0 +5793 568 10 +5679 525 0 +5800 542 10 +5657 556 20 +5862 549 15 +5669 564 20 +5673 521 0 +5798 585 10 +5736 566 22 +5826 534 0 +5829 522 0 +5666 569 20 +5875 553 15 +5687 526 0 +5691 522 0 +5790 561 10 + +# barred metal door +BarredMetalDoor 0x0693 (Facing=NorthCW) +5857 562 15 +5857 570 15 +5857 578 15 +5857 586 15 +5857 594 15 +5848 580 15 + +# barred metal door +BarredMetalDoor 0x068F (Facing=NorthCCW) +5863 554 15 +5797 594 10 +5797 555 10 +5797 587 10 +5797 579 10 +5797 571 10 +5797 563 10 + +# barred metal door +BarredMetalDoor 0x068D (Facing=SouthCW) +5863 555 15 +5797 595 10 +5797 588 10 +5797 580 10 +5797 556 10 +5797 572 10 +5797 564 10 + +# metal chest +MetalGoldenChest 0x0E40 +5703 661 0 +5786 554 10 +5786 555 10 +5786 556 10 +5786 557 10 +5703 664 0 +5703 663 0 +5703 662 0 + +# metal chest +MetalGoldenChest 0x0E41 +5709 659 0 +5708 659 0 +5706 659 0 +5648 549 22 +5727 554 20 +5718 549 20 +5707 659 0 + +# switch +Static 0x108F +5786 589 24 +5798 593 24 +5786 572 24 +5849 586 15 +5798 581 23 + +# floor saw +SawTrap 0x11AC +5864 546 15 +5790 560 10 +5651 556 20 +5821 526 0 +5867 546 15 +5680 526 0 +5731 555 20 +5693 536 0 +5651 554 20 +5732 573 20 +5702 532 0 +5679 529 0 +5727 557 20 +5833 532 0 +5802 559 10 +5796 546 10 +5860 546 15 +5869 553 15 +5695 538 0 + +# iron maiden +Static 0x124B +5698 524 0 + +# floor saw +SawTrap 0x11B1 +5792 554 10 +5717 550 20 +5731 566 20 +5714 569 20 +5683 533 0 +5687 531 0 +5664 557 20 +5865 549 15 +5793 594 10 +5724 563 20 +5656 553 20 +5680 532 0 +5681 526 0 +5665 561 20 +5666 564 20 +5651 564 20 +5682 529 0 + +# switch +Static 0x1090 +5786 589 24 +5798 581 10 +5786 572 24 +5798 581 23 + +# glowing rune +Static 0x0E5F +5699 663 0 + +# barred metal door +BarredMetalDoor 0x0687 (Facing=EastCCW) +5667 567 20 +5727 567 20 +5653 567 20 +5660 567 20 + +# barred metal door +BarredMetalDoor 0x0685 (Facing=WestCW) +5666 567 20 +5726 567 20 +5652 567 20 +5659 567 20 + +# switch +Static 0x1091 +5650 568 30 +5657 568 30 +5664 568 30 + +# switch +Static 0x1092 +5793 592 24 +5657 568 30 +5793 560 24 +5792 576 24 +5650 568 30 +5664 568 30 + +# whip +Static 0x166E +5864 540 21 + +# wooden box +Static 0x09AA +5667 549 22 + +# gas trap +GasTrap 0x113C +5682 531 0 +5828 531 0 +5833 538 0 +5684 533 0 +5693 521 0 +5787 550 10 +5680 528 0 +5834 535 0 +5680 530 0 +5689 529 0 +5687 541 0 +5827 534 0 +5691 526 0 +5729 561 20 +5722 549 20 + +# butcher knife +Static 0x13F7 +5703 527 7 + +# skinning knife +Static 0x0EC4 +5703 526 7 + +# floor spikes +SpikeTrap 0x11A0 +5832 527 0 +5874 541 15 +5682 535 0 +5694 533 0 +5825 523 0 +5681 523 0 +5782 572 10 +5661 549 22 +5720 571 20 +5735 563 20 +5733 572 20 +5791 571 10 +5792 544 10 +5829 525 0 +5674 528 0 +5674 527 0 +5835 528 0 + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +2044 233 13 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +2045 233 13 + +# barred metal door +BarredMetalDoor 0x0691 (Facing=SouthCCW) +5848 581 15 +5857 563 15 +5857 571 15 +5857 579 15 +5857 587 15 +5857 595 15 + +# mushroom +MushroomTrap 0x1125 +5724 560 20 +5834 534 0 +5658 554 20 +5665 557 20 + +# crate +LargeCrate 0x0E3D +5718 554 23 +5715 556 20 +5715 556 23 +5718 554 20 + +# metal chest +MetalChest 0x09AB +5678 529 0 +5734 549 20 + +# dungeon wall +SecretDungeonDoor 0x0318 (Facing=WestCCW) +5679 520 0 +5722 553 20 + +# stone pavers +Static 0x0519 +5677 521 0 + +# oven +StoneOvenEastAddon 0x092C +5786 544 10 +5672 526 0 + +# hammer +Static 0x102B +5791 542 16 +5863 541 21 + +# pickaxe +Static 0x0E85 +5790 543 16 + +# dagger +Static 0x0F51 +5790 542 16 + +# cleaver +Static 0x0EC2 +5702 526 7 + +# strong box +MetalBox 0x0E80 +5669 520 0 + +# sledge hammer +Static 0x0FB4 +5863 542 21 + +# whip +Static 0x166F +5862 542 21 + +# rusty iron key +Static 0x1013 +5851 571 15 + +# dungeon wall +SecretDungeonDoor 0x031A (Facing=EastCW) +5652 552 20 + +# alchemical symbol +Static 0x1822 +2041 232 34 + +# stone +Static 0x07A3 +5692 566 20 + +# rock +Static 0x1773 +5694 564 3 +5694 565 16 + +# rock +Static 0x1778 +5694 566 20 diff --git a/Data/Decoration/Britannia/britain.cfg b/Data/Decoration/Britannia/britain.cfg new file mode 100644 index 0000000..06b1aca --- /dev/null +++ b/Data/Decoration/Britannia/britain.cfg @@ -0,0 +1,5373 @@ +# stone wall +Static 0x0063 +1517 1670 20 + +# stone wall +Static 0x0080 +1323 1627 50 + +# plaster wall +Static 0x012C +1224 1567 0 + +# wooden boards +Static 0x04AA +1497 1664 27 + +# wooden boards +Static 0x04B5 +1610 1591 -20 +1611 1591 -20 + +# wooden boards +Static 0x04B7 +1501 1611 40 +1619 1590 -20 + +# slate roof +Static 0x0596 +1559 1775 33 + +# thatch roof +Static 0x05A4 +1639 1504 58 + +# wooden shingles +Static 0x05C3 +1640 1690 56 + +# wooden shingles +Static 0x05C4 +1603 1519 69 + +# wooden shingles +Static 0x05C5 +1602 1518 66 + +# platform +Static 0x07C1 +1436 1559 30 + +# platform +Static 0x07C3 +1437 1548 30 +1436 1549 30 + +# platform +Static 0x07C4 +1442 1548 30 + +# fireplace +Static 0x08CF +1248 1704 0 + +# fireplace +Static 0x08D0 +1248 1703 0 + +# fireplace +Static 0x08D3 +1152 1616 0 +1190 1704 0 +1547 1704 20 + +# fireplace +Static 0x08D4 +1153 1616 0 +1191 1704 0 +1548 1704 20 + +# fireplace +Static 0x08DA +1424 1715 20 +1544 1762 10 +1486 1688 20 +1592 1516 40 + +# fireplace +Static 0x08DB +1424 1714 20 +1592 1515 40 +1486 1687 20 +1544 1761 10 + +# chimney +Static 0x08DD +1637 1656 43 +1549 1680 51 + +# fireplace +Static 0x08DE +1153 1544 0 +1478 1512 20 +1228 1568 0 + +# fireplace +Static 0x08DF +1152 1544 0 +1227 1568 0 +1477 1512 20 + +# oven +StoneOvenEastAddon 0x092C +1424 1712 20 +1448 1615 20 + +# fireplace +StoneFireplaceEastAddon 0x0959 +1648 1601 20 + +# fireplace +Static 0x095F +1549 1680 30 + +# fireplace +Static 0x0960 +1548 1680 30 + +# metal chest +MetalChest 0x09AB +1653 1600 26 +1651 1600 26 +1649 1600 26 + +# lantern post +Static 0x0A1F +1556 1612 10 + +# candelabra +CandelabraStand 0x0A29 (Unlit) +1558 1592 10 +1549 1585 10 + +# chest of drawers +Drawer 0x0A2C +1459 1517 20 +1588 1594 20 +1587 1584 40 +1459 1512 20 +1588 1594 40 +1505 1615 40 +1587 1584 20 +1494 1615 40 +1642 1576 0 +1503 1610 40 +1577 1594 40 +1242 1696 0 +1649 1560 10 +1468 1520 20 +1493 1610 40 +1579 1584 20 +1579 1584 40 +1469 1704 0 +1493 1620 40 +1386 1800 0 +1426 1752 10 +1503 1620 40 +1196 1714 0 +1577 1594 20 +1707 1557 50 + +# chest of drawers +FancyDrawer 0x0A30 +1675 1544 50 +1661 1600 20 +1637 1504 35 +1708 1552 50 +1502 1610 20 +1689 1568 20 +1549 1648 26 +1658 1576 5 +1676 1584 12 +1601 1648 10 + +# chest of drawers +Drawer 0x0A34 +1530 1413 15 +1530 1415 15 +1428 1595 20 +1533 1433 15 +1460 1705 0 +1416 1555 30 +1184 1715 0 +1454 1705 0 +1507 1595 10 +1448 1707 0 +1624 1584 -20 +1537 1739 35 +1537 1744 35 +1617 1564 50 +1689 1548 65 +1656 1644 0 +1384 1818 0 +1608 1517 40 +1144 1621 0 +1533 1425 15 +1456 1525 20 + +# chest of drawers +FancyDrawer 0x0A38 +1500 1621 20 +1352 1588 50 +1538 1706 20 +1538 1692 30 +1649 1547 45 +1342 1660 50 +1233 1573 0 +1352 1660 50 +1672 1573 20 +1538 1685 30 +1640 1701 36 +1428 1593 20 +1632 1506 35 +1349 1590 72 +1664 1547 30 + +# dresser +Static 0x0A3C +1444 1576 20 +1442 1576 20 + +# dresser +Static 0x0A3D +1443 1576 20 +1441 1576 20 + +# dresser +Static 0x0A44 +1529 1417 55 +1440 1580 20 + +# dresser +Static 0x0A45 +1440 1579 20 +1529 1416 55 + +# armoire +FancyArmoire 0x0A4D +1660 1576 5 +1677 1568 20 +1501 1610 20 +1710 1552 50 +1659 1600 20 +1547 1648 26 + +# armoire +Armoire 0x0A4F +1419 1552 30 +1580 1584 20 +1579 1594 20 +1578 1594 40 +1590 1584 40 +1536 1412 15 +1244 1696 0 +1644 1576 0 +1197 1714 0 +1651 1560 10 +1588 1584 20 +1589 1594 20 +1470 1520 20 +1534 1424 15 +1582 1584 40 +1589 1594 40 +1534 1432 15 +1459 1522 20 + +# armoire +FancyArmoire 0x0A51 +1500 1623 20 +1672 1549 50 +1352 1590 50 +1649 1549 45 +1538 1693 30 +1349 1587 73 +1538 1708 20 +1428 1596 20 +1342 1658 50 +1600 1653 10 +1672 1588 7 +1640 1697 36 +1664 1548 30 +1352 1658 50 +1688 1573 20 +1538 1684 30 + +# armoire +Armoire 0x0A53 +1689 1549 65 +1424 1753 10 +1608 1513 40 +1529 1415 55 +1428 1594 20 +1624 1589 -20 +1507 1597 10 + +# bed +Static 0x0A78 +1673 1547 50 + +# bed +Static 0x0A79 +1673 1546 50 + +# bookcase +LibraryBookcase 0x0A97 +1545 1736 15 +1341 1728 60 +1330 1642 72 +1548 1736 15 +1497 1656 27 +1531 1433 35 +1354 1655 72 +1532 1425 35 +1354 1659 72 +1354 1642 72 +1352 1650 72 +1352 1646 72 +1352 1655 72 +1414 1601 30 +1495 1544 30 +1619 1560 30 +1413 1588 30 +1425 1647 10 +1532 1429 35 +1427 1647 10 +1418 1597 50 +1418 1601 30 +1418 1593 50 +1418 1608 30 +1418 1601 50 +1187 1704 0 +1349 1642 72 +1469 1560 50 +1418 1544 30 +1633 1509 35 +1496 1551 70 +1497 1713 6 +1462 1553 50 +1419 1576 30 +1526 1433 35 +1417 1605 50 +1505 1656 27 +1461 1548 30 +1525 1429 35 +1525 1425 35 +1348 1728 60 +1459 1553 50 +1467 1560 50 +1497 1551 70 +1147 1616 0 +1250 1696 0 +1459 1548 30 +1527 1429 35 +1415 1605 50 +1528 1425 35 +1528 1422 35 +1473 1592 20 +1539 1712 20 +1487 1546 35 +1486 1546 35 +1489 1546 35 +1539 1736 15 +1351 1659 72 +1556 1656 26 +1444 1548 50 +1652 1544 25 +1495 1713 6 +1457 1548 30 +1478 1736 0 + +# bookcase +LibraryBookcase 0x0A98 +1445 1548 50 +1506 1656 27 +1470 1560 50 +1412 1601 30 +1413 1592 30 +1546 1736 15 +1415 1608 30 +1476 1592 20 +1419 1544 30 +1148 1616 0 +1529 1422 35 +1252 1696 0 +1543 1712 20 +1528 1433 35 +1477 1736 0 +1526 1429 35 +1455 1548 30 +1525 1433 35 +1498 1656 27 +1622 1560 30 +1460 1548 30 +1541 1736 15 +1557 1656 26 +1417 1593 50 +1417 1592 30 +1488 1546 35 +1620 1560 30 +1531 1429 35 +1416 1597 50 +1185 1704 0 +1446 1548 50 +1416 1588 30 +1426 1647 10 +1533 1429 35 +1416 1605 50 +1416 1601 30 +1472 1560 50 +1495 1551 70 +1415 1592 30 +1351 1650 72 +1351 1642 72 +1493 1551 70 +1415 1593 50 +1634 1509 35 +1526 1425 35 +1538 1736 15 +1420 1576 30 +1417 1601 50 +1416 1608 30 +1534 1433 35 +1474 1592 20 +1653 1544 25 +1354 1650 72 +1345 1728 60 +1356 1642 72 +1353 1659 72 +1496 1544 30 +1353 1655 72 +1337 1642 72 +1496 1713 6 +1414 1588 30 +1531 1425 35 + +# bookcase +LibraryBookcase 0x0A99 +1672 1596 7 +1522 1423 35 +1408 1608 50 +1408 1608 30 +1630 1662 35 +1412 1747 10 +1672 1593 7 +1492 1715 6 +1412 1752 10 +1522 1436 35 +1522 1432 35 +1522 1430 35 +1510 1613 10 +1491 1553 70 +1538 1713 20 +1416 1580 30 +1592 1597 20 +1491 1555 70 +1408 1594 30 +1632 1512 35 +1592 1595 20 +1416 1548 30 +1492 1614 20 +1408 1597 30 +1408 1606 30 +1600 1520 40 +1442 1553 50 +1491 1557 70 +1442 1557 50 +1544 1652 26 +1648 1641 0 +1408 1602 30 +1336 1732 20 +1184 1707 0 +1412 1756 10 +1576 1565 20 +1544 1737 15 +1364 1634 50 +1576 1699 35 +1472 1745 0 +1336 1733 60 +1472 1742 0 +1472 1740 0 +1568 1697 35 +1537 1740 15 +1537 1741 15 +1224 1579 0 +1537 1738 15 +1544 1688 30 +1537 1737 15 +1576 1707 35 +1347 1657 72 +1576 1563 20 +1464 1561 50 +1248 1701 0 + +# bookcase +LibraryBookcase 0x0A9A +1538 1714 20 +1600 1521 40 +1248 1697 0 +1576 1564 20 +1544 1653 26 +1544 1685 30 +1491 1556 70 +1442 1552 50 +1442 1558 50 +1648 1642 0 +1576 1708 35 +1672 1595 7 +1491 1552 70 +1649 1545 25 +1544 1687 30 +1492 1721 6 +1538 1717 20 +1544 1741 15 +1492 1718 6 +1464 1563 50 +1522 1435 35 +1492 1717 6 +1408 1605 30 +1224 1581 0 +1592 1594 20 +1408 1596 30 +1408 1597 50 +1408 1600 30 +1408 1593 30 +1408 1609 30 +1336 1735 20 +1408 1603 50 +1336 1733 20 +1576 1698 35 +1522 1429 35 +1522 1424 35 +1522 1428 35 +1522 1437 35 +1496 1666 27 +1347 1658 72 +1496 1657 27 +1568 1699 35 +1412 1746 10 +1468 1595 20 +1492 1615 20 +1632 1510 35 +1184 1711 0 +1184 1709 0 +1491 1554 70 +1416 1579 30 +1184 1706 0 +1364 1616 50 +1336 1737 60 +1412 1749 10 +1412 1755 10 + +# bookcase +LibraryBookcase 0x0A9B +1674 1568 20 +1477 1592 20 +1471 1560 50 +1458 1548 30 +1456 1548 30 +1468 1560 50 +1461 1553 50 +1476 1736 0 +1460 1553 50 +1415 1601 50 +1532 1433 35 +1355 1642 72 +1353 1646 72 +1354 1646 72 +1353 1650 72 +1527 1425 35 +1549 1736 15 +1528 1429 35 +1527 1433 35 +1352 1659 72 +1544 1712 20 +1540 1736 15 +1350 1642 72 +1533 1433 35 +1534 1425 35 +1351 1655 72 +1533 1425 35 +1534 1429 35 +1418 1592 30 +1417 1597 50 +1417 1588 30 +1417 1608 30 +1417 1601 30 +1416 1601 50 +1415 1601 30 +1494 1713 6 +1416 1593 50 +1416 1592 30 +1428 1647 10 +1530 1422 35 +1558 1656 26 +1421 1576 30 +1418 1605 50 +1424 1647 10 +1494 1544 30 +1494 1551 70 +1415 1597 50 +1414 1592 30 +1413 1601 30 +1415 1588 30 +1443 1548 50 +1414 1593 50 +1617 1560 30 +1336 1642 72 +1249 1696 0 +1650 1544 25 +1329 1642 72 +1638 1509 35 +1253 1696 0 +1675 1568 20 + +# bookcase +LibraryBookcase 0x0A9C +1408 1603 30 +1412 1750 10 +1408 1607 50 +1412 1753 10 +1408 1602 50 +1492 1714 6 +1496 1658 27 +1522 1426 35 +1496 1665 27 +1492 1720 6 +1576 1561 20 +1576 1562 20 +1408 1599 30 +1408 1598 50 +1492 1616 20 +1544 1689 30 +1468 1594 20 +1468 1596 20 +1328 1643 72 +1472 1748 0 +1472 1744 0 +1472 1741 0 +1472 1749 0 +1464 1564 50 +1672 1598 7 +1648 1643 0 +1576 1697 35 +1568 1698 35 +1522 1425 35 +1522 1431 35 +1522 1434 35 +1184 1705 0 +1184 1710 0 +1600 1526 40 +1592 1596 20 +1576 1709 35 +1336 1736 20 +1347 1656 72 +1224 1578 0 +1600 1525 40 +1416 1578 30 +1544 1686 30 +1364 1615 50 +1538 1716 20 + +# wooden shelf +EmptyBookcase 0x0A9D +1615 1584 -20 +1615 1587 -20 +1618 1587 -20 +1613 1587 -20 +1614 1587 -20 +1619 1587 -20 +1432 1592 20 +1433 1592 20 +1335 1642 72 +1616 1587 -20 +1331 1642 72 +1617 1587 -20 +1613 1584 -20 +1614 1584 -20 + +# wooden shelf +EmptyBookcase 0x0A9E +1656 1646 0 +1347 1654 72 +1347 1652 72 +1408 1617 30 +1616 1582 -20 +1492 1618 20 +1616 1583 -20 +1619 1583 -20 +1492 1617 20 +1619 1582 -20 +1408 1633 30 +1619 1581 -20 + +# lamp post +LampPost1 0x0B20 +1463 1569 30 +1516 1669 20 +1538 1576 20 +1463 1651 10 +1460 1587 20 +1508 1655 20 +1460 1600 20 +1502 1690 20 +1458 1678 0 +1440 1670 10 +1500 1701 20 +1472 1623 20 +1471 1676 0 +1472 1696 0 +1472 1636 20 +1501 1543 28 +1432 1665 10 +1501 1555 27 +1479 1676 0 +1479 1636 20 +1479 1623 20 +1427 1539 30 +1488 1592 19 +1441 1693 0 +1440 1623 20 +1429 1628 20 +1417 1628 20 +1417 1623 20 +1503 1576 22 +1422 1614 20 +1422 1599 20 +1422 1595 20 +1476 1569 30 +1448 1569 30 +1440 1591 20 +1440 1606 20 + +# lamp post +LampPost3 0x0B24 +1584 1607 19 +1663 1584 4 +1426 1745 14 +1656 1655 0 +1433 1725 20 +1459 1693 0 +1554 1776 10 +1431 1761 -3 +1439 1754 -3 +1694 1556 40 +1691 1578 11 +1484 1723 0 +1665 1608 13 +1669 1557 30 +1670 1626 -5 +1670 1621 -4 +1640 1686 27 +1539 1782 13 +1646 1567 10 +1647 1584 0 +1520 1701 20 +1520 1582 20 +1519 1633 10 +1568 1610 12 +1620 1672 20 +1465 1747 0 +1568 1618 10 +1632 1591 0 +1456 1728 0 +1616 1592 1 +1440 1705 1 +1648 1555 20 +1569 1532 40 +1598 1572 20 +1599 1560 20 +1597 1664 10 +1543 1669 20 +1537 1616 10 +1499 1724 2 +1561 1664 20 +1360 1772 15 +1579 1607 20 +1340 1744 20 +1377 1756 0 +1537 1720 20 +1640 1672 15 +1535 1625 2 +1588 1531 36 +1559 1688 30 +1488 1739 0 +1610 1567 25 +1531 1670 20 +1576 1719 35 +1599 1720 20 +1599 1600 20 +1588 1685 10 +1498 1626 10 +1552 1751 15 +1472 1704 0 +1552 1608 10 +1615 1672 19 +1567 1576 20 + +# candelabra +CandelabraStand 0x0B26 +1539 1745 35 +1416 1544 30 +1352 1586 50 +1428 1608 20 +1537 1736 15 +1669 1550 30 +1496 1656 27 +1349 1735 20 +1616 1581 -20 +1446 1548 29 +1565 1760 10 +1502 1615 40 +1502 1620 40 +1549 1614 10 +1494 1691 20 +1448 1596 20 +1448 1584 20 +1498 1549 70 +1538 1585 10 +1656 1576 5 +1430 1582 30 +1533 1432 15 +1654 1544 25 +1537 1420 55 +1533 1424 15 +1544 1771 10 +1348 1746 60 +1492 1610 40 +1336 1734 20 +1497 1676 20 +1530 1412 15 +1408 1610 50 +1416 1582 30 +1492 1620 40 +1412 1758 10 +1584 1590 20 +1612 1584 -20 +1537 1614 10 +1412 1744 10 +1416 1558 30 +1418 1610 50 +1558 1605 10 +1446 1563 30 +1489 1551 70 +1582 1702 35 +1472 1512 20 +1529 1412 35 +1568 1702 35 +1654 1640 0 +1537 1412 35 +1672 1592 7 +1500 1617 20 +1500 1612 20 +1502 1610 40 +1462 1526 20 +1462 1512 20 +1550 1742 35 +1456 1596 20 +1632 1504 35 +1608 1512 40 +1630 1583 -20 +1522 1419 55 +1648 1560 10 +1150 1616 0 +1522 1412 55 +1441 1668 -10 +1461 1558 30 +1449 1558 30 +1464 1548 30 + +# throne +Throne 0x0B33 +1540 1415 55 + +# water trough +WaterTroughEastAddon 0x0B41 +1508 1540 25 +1513 1540 25 +1519 1540 25 +1523 1540 25 + +# water trough +WaterTroughSouthAddon 0x0B43 +1513 1552 25 +1314 1800 0 +1519 1552 25 + +# writing table +WritingTable 0x0B49 +1350 1605 72 + +# writing table +WritingTable 0x0B4A +1355 1602 72 + +# table +Static 0x0B7F +1496 1664 27 + +# table +Static 0x0B80 +1497 1664 27 +1498 1664 27 + +# wooden signpost +Static 0x0B9A +1386 1664 30 + +# metal signpost +Static 0x0BA1 +1360 1776 15 + +# campion flowers +Static 0x0C83 +1364 1661 30 +1364 1660 30 +1371 1642 30 +1370 1642 30 +1366 1643 30 +1366 1644 30 +1365 1660 30 +1362 1657 30 +1367 1644 30 +1363 1658 30 +1369 1659 30 +1362 1658 30 +1368 1657 30 +1380 1617 30 +1380 1618 30 +1373 1660 30 +1374 1645 30 +1380 1619 30 +1374 1646 30 +1381 1619 30 +1380 1620 30 +1373 1659 30 +1381 1617 30 +1381 1620 30 +1380 1621 30 +1372 1642 30 +1373 1646 30 +1380 1616 30 +1381 1618 30 + +# walnut tree +Static 0x0CE0 +1614 1636 37 + +# walnut leaves +Static 0x0CE4 +1614 1636 37 + +# apple tree +Static 0x0D94 +1390 1579 30 +1367 1601 30 +1363 1595 30 +1386 1574 30 +1367 1606 30 +1386 1579 30 + +# leaves +Static 0x0D95 +1367 1606 30 +1367 1601 30 +1386 1579 30 +1363 1595 30 + +# apple tree +Static 0x0D96 +1390 1579 30 +1386 1574 30 + +# apple tree +Static 0x0D98 +1363 1601 30 +1363 1651 30 +1363 1606 30 + +# apple tree +Static 0x0D9A +1363 1606 30 +1363 1601 30 + +# peach tree +Static 0x0D9C +1378 1617 30 +1378 1620 30 +1363 1584 30 +1369 1658 30 +1369 1644 30 +1363 1589 30 + +# peach tree +Static 0x0D9E +1378 1617 30 +1363 1589 30 +1363 1584 30 +1378 1620 30 + +# peach tree +Static 0x0DA0 +1378 1574 30 +1378 1579 30 +1382 1579 30 +1367 1595 30 +1367 1589 30 +1382 1574 30 + +# leaves +Static 0x0DA1 +1378 1574 30 +1367 1589 30 +1367 1595 30 +1378 1579 30 +1382 1574 30 + +# peach tree +Static 0x0DA2 +1382 1579 30 + +# pear tree +Static 0x0DA4 +1376 1600 30 +1376 1585 30 +1376 1595 30 +1376 1590 30 + +# leaves +Static 0x0DA5 +1376 1600 30 +1376 1590 30 +1376 1585 30 + +# pear tree +Static 0x0DA6 +1376 1595 30 + +# pear tree +Static 0x0DA8 +1380 1595 30 +1380 1600 30 +1380 1585 30 +1380 1590 30 + +# leaves +Static 0x0DA9 +1380 1590 30 +1380 1585 30 + +# pear tree +Static 0x0DAA +1380 1600 30 +1380 1595 30 + +# small fish +Static 0x0DD8 +1491 1747 -2 +1452 1756 -2 +1435 1766 -2 +1497 1762 -3 +1482 1767 -2 +1451 1767 -3 +1443 1766 -2 +1489 1754 -2 +1439 1759 -2 +1490 1754 -2 +1493 1760 -2 + +# small fish +Static 0x0DD9 +1470 1756 -2 +1483 1755 -2 +1484 1769 -2 +1498 1761 -3 +1435 1765 -2 +1490 1755 -2 +1495 1748 -2 +1475 1760 -2 +1450 1757 -2 + +# crate +FillableLargeCrate 0x0E3C +1350 1780 35 +1464 1664 0 +1606 1704 23 +1561 1737 15 +1581 1737 15 +1464 1664 3 +1464 1664 6 +1464 1664 9 +1561 1738 18 +1562 1738 18 +1565 1746 15 +1572 1742 15 +1565 1747 18 +1572 1743 18 +1561 1738 24 +1577 1748 15 +1572 1743 15 +1561 1739 15 +1562 1737 18 +1606 1705 20 +1465 1664 6 +1465 1664 3 +1607 1704 26 +1576 1749 15 +1607 1704 23 +1565 1747 15 +1577 1747 15 +1576 1748 15 +1465 1664 0 +1607 1704 20 +1562 1737 15 +1572 1742 18 +1576 1748 18 +1437 1596 20 +1561 1738 21 +1348 1775 38 +1564 1748 18 +1577 1748 18 +1561 1739 18 +1572 1743 21 +1564 1747 18 +1576 1748 21 +1564 1748 15 +1564 1747 15 +1579 1737 15 +1562 1738 15 +1606 1704 20 +1579 1738 15 +1560 1738 18 +1580 1737 21 +1577 1749 18 +1564 1747 21 +1573 1743 15 +1580 1737 15 +1580 1737 18 +1579 1738 18 +1563 1747 15 +1578 1748 15 +1573 1742 15 +1563 1747 18 +1563 1748 15 +1564 1746 15 +1605 1704 23 +1605 1704 20 +1572 1742 21 +1563 1747 21 +1605 1704 26 +1560 1739 15 +1580 1738 15 +1577 1749 15 +1560 1738 15 +1561 1738 15 + +# crate +FillableLargeCrate 0x0E3D +1520 1432 21 +1608 1584 -20 +1520 1433 15 +1608 1585 -20 +1610 1584 -20 +1610 1584 -17 +1609 1584 -20 +1608 1584 -17 +1501 1521 60 +1609 1585 -20 +1511 1560 20 +1519 1433 15 +1520 1433 21 +1334 1740 29 +1520 1433 18 +1519 1432 21 +1332 1740 29 +1332 1740 26 +1519 1432 18 +1520 1432 15 +1519 1432 24 +1332 1746 29 +1333 1740 20 +1332 1746 26 +1333 1740 26 +1333 1740 29 +1333 1740 23 +1334 1740 26 +1332 1741 26 +1334 1740 23 +1332 1741 20 +1332 1741 23 +1332 1746 23 +1332 1746 20 +1334 1740 20 +1519 1432 15 +1510 1560 20 +1332 1740 23 +1510 1560 23 +1332 1740 20 +1518 1432 18 +1518 1432 15 +1520 1432 18 + +# crate +MediumCrate 0x0E3E +1332 1744 20 +1568 1749 15 +1332 1743 26 +1568 1747 15 +1332 1743 20 +1568 1748 15 +1332 1742 20 +1568 1747 18 +1568 1746 15 +1568 1749 18 +1332 1744 23 +1600 1709 23 +1600 1709 20 +1568 1748 18 +1568 1748 21 +1600 1708 20 +1332 1745 23 +1464 1669 0 +1464 1670 3 +1332 1745 20 +1600 1710 23 +1600 1710 20 +1464 1670 0 +1464 1669 3 +1464 1669 6 +1332 1744 26 +1565 1740 15 +1566 1739 15 +1512 1437 15 +1332 1743 23 +1600 1711 20 +1512 1436 18 +1512 1435 15 +1512 1436 15 +1512 1435 18 +1332 1742 23 +1566 1740 18 +1512 1437 18 +1566 1740 21 +1512 1436 21 +1565 1739 15 +1566 1739 18 +1566 1740 15 +1569 1747 15 +1566 1739 21 +1569 1748 15 + +# crate +MediumCrate 0x0E3F +1578 1736 15 +1578 1736 18 +1577 1736 15 +1579 1736 15 +1577 1736 18 + +# metal chest +MetalGoldenChest 0x0E40 +1424 1676 0 +1424 1678 0 +1424 1681 0 +1424 1680 0 +1424 1679 0 +1424 1677 0 + +# guard metal chest +FillableMetalGoldenChest 0x0E40 (ContentType=Guard) +1408 1718 20 +1408 1715 20 + +# metal chest +MetalGoldenChest 0x0E41 +1425 1675 0 +1429 1675 0 +1430 1675 0 +1427 1675 0 +1428 1675 0 +1650 1600 26 +1426 1675 0 + +# metal chest +FillableMetalGoldenChest 0x0E41 (ContentType=ThiefGuild) +1659 1632 6 +1662 1632 6 + +# guard metal chest +FillableMetalGoldenChest 0x0E41 (ContentType=Guard) +1515 1610 10 +1512 1610 10 + +# wooden chest +WoodenChest 0x0E42 +1608 1589 -20 +1608 1587 -20 +1608 1588 -20 +1384 1817 0 +1537 1743 35 +1537 1742 35 +1537 1741 35 + +# wooden chest +FillableWoodenChest 0x0E42 +1384 1586 30 +1584 1598 20 +1576 1598 20 +1492 1618 40 +1502 1611 40 +1502 1624 40 +1584 1598 40 +1576 1598 40 + +# wooden chest +WoodenChest 0x0E43 +1238 1568 0 +1652 1600 26 +1385 1800 0 + +# wooden chest +FillableWoodenChest 0x0E43 +1386 1584 30 +1586 1584 20 +1589 1584 40 +1495 1620 40 +1503 1615 40 +1578 1584 20 +1581 1584 40 + +# wooden chest +FillableWoodenChest 0x0E43 (ContentType=ThiefGuild) +1660 1632 6 +1661 1632 6 + +# wooden chest +FillableWoodenChest 0x0E43 (ContentType=Farm) +1246 1696 0 +1149 1544 0 + +# water tub +Static 0x0E7B +1385 1646 30 +1290 1766 10 +1290 1769 10 +1192 1704 2 +1299 1754 10 +1290 1775 10 +1306 1778 10 +1290 1772 10 +1391 1646 30 +1385 1661 30 +1391 1655 30 +1306 1772 10 +1391 1649 30 +1306 1775 10 +1290 1778 10 +1306 1769 10 +1385 1652 30 +1385 1655 30 +1293 1754 10 +1290 1781 10 +1385 1649 30 +1306 1781 10 +1391 1652 30 +1296 1754 10 +1391 1658 30 +1385 1658 30 + +# metal chest +FillableMetalChest 0x0E7C +1466 1691 0 + +# crate +SmallCrate 0x0E7E +1576 1736 19 +1576 1736 15 +1576 1737 17 +1576 1737 15 +1576 1736 17 + +# crate +FillableSmallCrate 0x0E7E +1487 1689 26 +1487 1689 20 +1437 1595 26 +1487 1689 24 +1487 1689 22 +1487 1689 23 +1437 1594 20 +1437 1595 20 +1437 1595 23 +1437 1594 23 + +# saddle +Static 0x0F38 +1309 1758 10 +1306 1758 10 + +# anvil +AnvilEastAddon 0x0FAF +1363 1574 30 +1423 1556 30 + +# anvil +AnvilSouthAddon 0x0FB0 +1355 1786 21 +1346 1782 21 +1346 1774 21 + +# forge +SmallForgeAddon 0x0FB1 +1355 1776 15 +1361 1574 30 +1424 1558 30 +1356 1784 15 +1344 1776 15 + +# archery butte +ArcheryButte 0x100A +1468 1579 20 + +# archery butte +ArcheryButte 0x100B +1473 1576 20 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +1545 1656 26 + +# spinning wheel +SpinningWheelEastAddon 0x1019 +1390 1604 30 + +# spinning wheel +SpinningWheelSouthAddon 0x101C +1473 1689 0 +1475 1689 0 + +# upright loom +LoomEastAddon 0x1060 +1545 1660 26 + +# upright loom +LoomSouthAddon 0x1061 +1392 1601 30 +1473 1685 0 + +# stretched hide +Static 0x106A +1428 1610 20 + +# training dummy +TrainingDummy 0x1070 +1589 1554 20 +1349 1779 35 +1593 1554 20 +1597 1554 20 +1351 1777 35 +1353 1778 35 + +# training dummy +TrainingDummy 0x1074 +1528 1431 55 +1346 1737 80 +1524 1436 55 +1350 1744 80 +1340 1737 80 +1340 1731 80 +1333 1728 80 +1528 1436 55 +1346 1731 80 +1524 1431 55 + +# stretched hide +Static 0x107A +1431 1608 20 + +# stretched hide +Static 0x107B +1438 1608 20 + +# stretched hide +Static 0x107C +1436 1608 20 + +# potted tree +PottedTree 0x11C8 +1538 1712 20 +1640 1576 0 +1680 1568 20 +1686 1568 20 +1150 1544 0 + +# potted tree +PottedTree1 0x11C9 +1238 1574 0 +1710 1555 50 +1646 1696 36 +1198 1718 0 +1654 1654 0 +1544 1694 30 +1558 1774 10 +1656 1606 20 +1678 1590 7 +1536 1422 55 +1342 1657 50 +1452 1704 0 +1450 1678 0 +1254 1696 0 +1576 1594 40 +1537 1420 35 +1675 1544 30 +1550 1736 15 +1468 1592 20 +1537 1744 15 +1576 1560 20 +1537 1416 15 +1659 1576 5 +1500 1610 20 +1537 1750 15 +1524 1412 15 +1463 1512 20 +1608 1584 0 +1528 1412 15 +1158 1622 0 +1522 1422 35 +1390 1806 0 +1480 1580 20 +1470 1704 0 +1486 1580 20 +1544 1736 15 +1522 1422 55 +1542 1680 30 +1586 1584 40 +1606 1512 40 +1357 1657 50 +1189 1718 0 +1184 1714 0 +1184 1704 0 +1649 1544 25 +1648 1654 0 +1537 1422 35 +1648 1638 0 +1608 1704 20 +1522 1438 35 +1606 1518 40 +1558 1686 30 +1522 1438 55 +1240 1696 0 +1654 1560 10 +1482 1592 20 +1604 1704 20 +1694 1544 45 +1357 1600 72 +1464 1704 0 +1542 1688 30 +1689 1544 45 +1584 1584 40 +1198 1704 0 +1550 1750 15 +1688 1568 20 +1248 1696 0 +1537 1438 55 +1592 1512 40 +1426 1550 30 +1231 1568 0 +1669 1544 30 +1672 1550 50 +1584 1594 40 +1672 1568 20 +1354 1746 60 +1512 1592 10 +1710 1566 50 +1390 1822 0 +1354 1740 60 +1430 1576 30 +1555 1656 26 +1584 1594 20 +1576 1594 20 +1158 1550 0 +1430 1758 10 +1646 1702 36 +1230 1582 0 +1598 1584 20 +1538 1704 20 +1514 1565 20 +1529 1420 35 +1144 1622 0 +1416 1576 30 +1550 1648 26 +1638 1710 36 +1614 1512 40 +1672 1590 7 +1420 1558 30 +1632 1509 35 +1630 1584 0 +1566 1766 10 +1537 1438 35 +1576 1552 20 +1600 1648 10 + +# flowerpot +PottedPlant 0x11CA +1592 1584 20 +1442 1660 -10 +1576 1584 20 +1480 1664 0 +1584 1584 20 +1191 1714 0 +1522 1422 15 +1500 1622 20 +1522 1436 15 +1632 1688 36 +1568 1696 35 +1448 1660 -10 +1648 1632 0 +1560 1648 26 +1470 1664 0 +1536 1412 55 +1576 1706 35 +1576 1696 35 +1492 1713 6 +1648 1640 0 + +# flowerpot +PottedPlant1 0x11CB +1454 1709 9 +1384 1804 5 +1603 1715 29 +1545 1709 30 +1460 1709 9 +1452 1682 9 +1600 1524 47 +1452 1614 29 + +# flowerpot +PottedPlant2 0x11CC +1446 1649 19 +1456 1725 16 +1605 1716 30 +1466 1709 9 +1471 1580 29 +1452 1709 9 +1594 1655 19 +1388 1816 5 +1550 1767 19 + +# water barrel +Static 0x154D +1453 1767 -2 +1452 1768 -2 +1453 1755 -2 +1573 1747 15 +1517 1436 15 +1288 1759 10 +1481 1764 -3 +1467 1668 0 +1383 1664 30 +1468 1667 0 +1617 1578 -20 +1467 1667 0 +1468 1771 -2 +1422 1560 30 +1581 1747 15 +1392 1823 0 +1392 1824 0 +1468 1668 0 +1392 1808 0 +1200 1705 0 +1304 1757 10 +1289 1757 10 +1496 1749 -2 +1495 1760 -2 +1572 1738 15 +1391 1808 0 +1292 1784 10 +1293 1784 10 +1489 1750 -2 +1447 1765 -2 +1447 1755 -2 +1486 1746 -2 +1471 1761 -2 +1485 1762 -3 +1384 1664 30 +1512 1434 15 +1200 1706 0 +1432 1767 -2 +1512 1423 15 +1561 1743 15 +1384 1641 30 + +# rock +Static 0x1773 +1569 1534 39 + +# rock +Static 0x1774 +1569 1537 29 + +# rock +Static 0x1777 +1452 1646 10 +1569 1536 30 + +# rock +Static 0x177B +1568 1533 39 + +# rock +Static 0x177C +1569 1535 31 + +# water +Static 0x1797 +1406 1596 -5 + +# water +Static 0x1799 +1407 1597 -5 + +# bellows +Forge 0x197A +1353 1779 15 + +# bellows +Forge 0x199F +1355 1779 15 + +# forge +Forge 0x19A2 +1354 1779 15 + +# book +Static 0x1E20 +1534 1418 61 + +# books +Static 0x1E21 +1535 1418 61 + +# bulletin board +BulletinBoard 0x1E5F +1492 1607 20 +1600 1595 20 + +# stone wall +SecretStoneDoor3 0x0356 (Facing=EastCCW) +1333 1652 72 + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +1411 1621 30 +1438 1692 0 +1516 1431 15 +1523 1439 15 +1619 1767 60 +1651 1639 0 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +1412 1621 30 +1439 1692 0 +1524 1439 15 +1620 1767 60 + +# metal door +MetalDoor 0x0679 (Facing=WestCCW) +1392 1678 30 +1411 1629 30 +1427 1682 0 + +# metal door +MetalDoor 0x067B (Facing=EastCW) +1393 1678 30 +1412 1629 30 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +1532 1420 15 +1532 1427 15 +1532 1435 15 + +# metal door +MetalDoor 0x0681 (Facing=SouthCCW) +1429 1684 0 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +1359 1625 50 + +# metal door +MetalDoor2 0x06CF (Facing=NorthCCW) +1359 1624 50 + +# wooden door +LightWoodDoor 0x06D5 (Facing=WestCW) +1388 1807 0 +1403 1807 0 + +# wooden door +LightWoodDoor 0x06DD (Facing=SouthCW) +1391 1819 0 +1407 1819 0 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +1309 1575 30 +1331 1593 50 +1333 1641 50 +1334 1599 72 +1338 1593 72 +1339 1593 50 +1339 1609 50 +1346 1656 50 +1347 1593 50 +1355 1593 50 +1371 1583 30 +1391 1594 30 +1392 1575 30 +1530 1421 55 +1534 1439 55 +1323 1609 50 +1385 1607 30 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +1310 1575 30 +1334 1641 50 +1339 1593 72 +1340 1609 50 +1355 1656 50 +1372 1583 30 +1392 1594 30 +1393 1575 30 +1531 1421 55 +1535 1439 55 +1386 1607 30 + +# wooden door +StrongWoodDoor 0x06E9 (Facing=WestCCW) +1345 1677 31 +1351 1593 72 +1339 1599 50 + +# wooden door +StrongWoodDoor 0x06EB (Facing=EastCW) +1334 1609 72 +1340 1599 50 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +1311 1681 30 +1340 1659 72 +1346 1660 72 +1351 1604 50 +1349 1675 30 +1360 1675 30 +1351 1646 50 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +1340 1658 72 +1346 1646 72 +1349 1674 30 +1351 1603 50 +1351 1645 50 +1311 1680 30 +1360 1674 30 + +# wooden door +StrongWoodDoor 0x06F1 (Facing=SouthCCW) +1327 1605 50 +1331 1676 30 +1493 1545 70 + +# wooden door +StrongWoodDoor 0x06F3 (Facing=NorthCW) +1327 1604 50 +1331 1675 30 +1340 1604 72 + +# wooden gate +LightWoodGate 0x0839 (Facing=WestCW) +1294 1755 10 +1297 1755 10 +1300 1755 10 +1509 1545 25 +1515 1545 25 +1520 1545 25 +1524 1545 25 + +# wooden gate +LightWoodGate 0x083B (Facing=EastCCW) +1510 1545 25 +1516 1545 25 +1521 1545 25 +1525 1545 25 + +# wooden gate +LightWoodGate 0x0841 (Facing=SouthCW) +1291 1767 10 +1291 1770 10 +1291 1773 10 +1291 1776 10 +1291 1779 10 +1311 1804 0 +1386 1647 30 +1386 1650 30 +1386 1653 30 +1386 1656 30 +1386 1659 30 +1386 1662 30 + +# wooden gate +LightWoodGate 0x0843 (Facing=NorthCCW) +1291 1782 10 +1311 1803 0 + +# wooden gate +LightWoodGate 0x0847 (Facing=NorthCW) +1299 1767 10 +1299 1770 10 +1299 1773 10 +1299 1776 10 +1299 1779 10 +1299 1782 10 +1390 1647 30 +1390 1650 30 +1390 1653 30 +1390 1656 30 +1390 1659 30 +1390 1662 30 + +# slab of bacon +Static 0x0976 +1448 1724 12 +1519 1422 21 +1659 1579 9 + +# slab of bacon +Static 0x0977 +1448 1723 12 + +# raw fish steak +RawFishSteak 0x097A +1156 1544 6 +1438 1776 -5 +1439 1776 -5 +1468 1772 -5 +1498 1746 -5 + +# fish steak +FishSteak 0x097B +1320 1600 56 + +# jugs of cider +Static 0x098D +1545 1760 16 + +# tray +Static 0x0991 +1137 1817 0 +1155 1616 6 +1194 1704 6 +1224 1570 6 +1322 1600 56 +1510 1600 14 +1516 1427 21 +1550 1707 26 +1597 1512 46 +1652 1565 14 +1692 1547 49 + +# tray +Static 0x0992 +1139 1816 6 +1156 1544 6 +1194 1848 6 +1256 1883 6 +1320 1600 56 +1469 1514 24 +1519 1422 21 +1545 1705 26 +1546 1680 36 +1659 1579 9 +1673 1546 34 + +# fruit basket +FruitBasket 0x0993 +1141 1816 6 +1224 1569 6 +1333 1604 54 +1338 1604 54 +1343 1604 54 +1512 1428 21 + +# pear +Pear 0x0994 +1379 1592 30 + +# ceramic mug +CeramicMug 0x0995 +1260 1883 4 + +# ceramic mug +CeramicMug 0x0996 +1198 1850 2 +1554 1682 34 +1674 1594 11 +1684 1570 24 +1706 1564 54 + +# ceramic mug +CeramicMug 0x0997 +1134 1819 2 +1261 1885 4 + +# goblet +Goblet 0x099A +1524 1425 19 +1524 1426 19 +1524 1428 19 +1524 1430 19 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +1132 1819 2 +1151 1620 2 +1152 1547 4 +1200 1850 2 +1261 1883 4 +1323 1674 34 +1324 1679 34 +1326 1674 34 +1326 1679 34 +1547 1771 12 +1549 1749 39 +1554 1762 14 +1608 1588 4 +1614 1587 4 +1626 1588 4 +1644 1578 4 +1644 1581 4 +1659 1580 9 +1704 1564 54 + +# bottles of liquor +Static 0x099E +1142 1816 6 +1157 1544 6 +1192 1850 6 +1224 1571 6 +1248 1710 6 +1259 1880 6 +1547 1760 16 + +# fork +Fork 0x09A3 +1192 1709 4 +1260 1884 4 +1331 1604 54 +1387 1817 2 +1403 1817 4 +1452 1708 6 +1509 1599 14 +1524 1425 19 +1524 1427 19 +1524 1429 19 +1524 1431 19 +1547 1715 24 +1600 1515 44 +1619 1563 34 +1634 1514 39 +1644 1579 4 +1644 1581 4 +1651 1547 29 +1691 1546 49 + +# fork +Fork 0x09A4 +1133 1819 2 +1151 1547 4 +1193 1708 4 +1199 1850 2 +1227 1575 4 +1252 1703 4 +1332 1603 54 +1334 1603 54 +1336 1603 54 +1338 1603 54 +1340 1603 54 +1342 1603 54 +1344 1603 54 +1385 1803 2 +1401 1803 2 +1467 1514 24 +1470 1514 24 +1525 1424 19 +1553 1682 34 +1672 1546 34 +1675 1594 11 +1683 1570 24 +1705 1564 54 + +# knife +Knife 0x09A5 +1192 1709 4 +1260 1884 4 +1331 1604 54 +1387 1817 2 +1403 1817 4 +1452 1708 6 +1509 1599 14 +1524 1425 19 +1524 1427 19 +1524 1429 19 +1524 1431 19 +1547 1715 24 +1600 1515 44 +1619 1563 34 +1634 1514 39 +1644 1578 4 +1644 1580 4 +1651 1547 29 +1691 1546 49 + +# knife +Knife 0x09A6 +1133 1819 2 +1151 1547 4 +1193 1708 4 +1199 1850 2 +1227 1575 4 +1252 1703 4 +1332 1603 54 +1334 1603 54 +1336 1603 54 +1338 1603 54 +1340 1603 54 +1342 1603 54 +1344 1603 54 +1385 1803 2 +1401 1803 2 +1467 1514 24 +1470 1514 24 +1525 1424 19 +1553 1682 34 +1672 1546 34 +1675 1594 11 +1683 1570 24 +1705 1564 54 + +# glass pitcher +Pitcher 0x09A7 +1322 1603 56 + +# metal box +FillableMetalBox 0x09A8 +1366 1572 36 +1421 1547 36 +1432 1608 26 +1446 1647 16 +1452 1613 26 +1453 1678 6 +1471 1577 26 +1494 1555 34 +1511 1565 26 +1553 1657 32 +1603 1711 26 +1635 1688 42 + +# goblet +Goblet 0x09B3 +1331 1604 54 +1332 1603 54 +1334 1603 54 +1336 1603 54 +1338 1603 54 +1340 1603 54 +1342 1603 54 +1344 1603 54 + +# cooked bird +CookedBird 0x09B7 +1224 1570 6 +1322 1600 56 +1510 1600 14 +1516 1427 21 + +# cooked bird +CookedBird 0x09B8 +1256 1883 6 +1469 1514 24 +1546 1680 36 + +# goblet +Goblet 0x09BF +1332 1605 54 +1334 1605 54 +1336 1605 54 +1338 1605 54 +1340 1605 54 +1342 1605 54 +1344 1605 54 +1525 1425 19 + +# sausage +Sausage 0x09C0 +1652 1565 14 + +# spoon +Spoon 0x09C2 +1192 1709 4 +1331 1604 54 +1509 1599 14 +1524 1425 19 +1524 1427 19 +1524 1429 19 +1524 1431 19 +1547 1715 24 +1600 1515 44 +1619 1563 34 +1634 1514 39 +1644 1578 4 +1644 1580 4 +1651 1547 29 +1691 1546 49 + +# spoon +Spoon 0x09C3 +1151 1547 4 +1193 1708 4 +1227 1575 4 +1252 1703 4 +1332 1603 54 +1334 1603 54 +1336 1603 54 +1338 1603 54 +1340 1603 54 +1342 1603 54 +1344 1603 54 +1467 1514 24 +1470 1514 24 +1525 1424 19 +1553 1682 34 +1675 1594 11 +1683 1570 24 +1705 1564 54 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +1452 1707 6 +1454 1707 6 +1456 1723 12 +1460 1707 6 +1466 1707 6 +1468 1514 24 +1469 1515 24 +1509 1598 14 +1539 1749 39 +1543 1749 39 +1547 1749 39 +1554 1768 14 +1614 1588 4 +1617 1582 6 +1619 1562 34 +1620 1564 34 +1635 1513 39 + +# jug of cider +Jug 0x09C8 (Content=Cider) +1384 1803 2 +1386 1804 2 +1387 1816 2 +1388 1818 2 +1400 1803 2 +1402 1804 2 +1403 1816 4 +1404 1818 4 +1554 1767 14 +1618 1588 4 +1619 1582 6 +1622 1587 4 +1676 1594 11 + +# ham +Ham 0x09C9 +1448 1725 12 + +# ceramic mug +CeramicMug 0x09CA +1132 1820 2 +1200 1851 2 +1552 1683 34 +1682 1571 24 +1706 1565 54 + +# goblet +Goblet 0x09CB +1526 1426 19 +1526 1428 19 +1526 1430 19 +1526 1432 19 + +# apple +Apple 0x09D0 +1362 1597 30 +1362 1651 30 +1362 1653 30 +1363 1650 30 +1364 1599 30 +1364 1651 30 +1365 1601 30 +1365 1608 30 +1365 1649 30 +1367 1598 30 +1367 1603 30 +1383 1574 30 +1388 1575 30 +1388 1579 30 + +# peach +Peach 0x09D2 +1367 1659 30 +1367 1660 30 +1368 1644 30 +1368 1659 30 +1368 1660 30 +1369 1644 30 +1369 1646 30 +1371 1643 30 +1371 1645 30 +1371 1660 30 +1376 1616 30 +1377 1619 30 +1378 1618 30 +1379 1622 30 +1380 1619 30 +1384 1575 30 + +# plate +Plate 0x09D7 +1133 1819 2 +1133 1820 2 +1150 1548 4 +1150 1620 2 +1151 1547 4 +1152 1548 4 +1152 1620 2 +1192 1709 4 +1193 1708 4 +1193 1710 4 +1199 1850 2 +1199 1851 2 +1227 1575 4 +1227 1577 4 +1252 1703 4 +1252 1704 4 +1260 1884 4 +1261 1884 4 +1331 1604 54 +1332 1603 54 +1332 1605 54 +1334 1603 54 +1334 1605 54 +1336 1603 54 +1336 1605 54 +1338 1603 54 +1338 1605 54 +1340 1603 54 +1340 1605 54 +1342 1603 54 +1342 1605 54 +1344 1603 54 +1344 1605 54 +1452 1708 6 +1454 1708 6 +1456 1724 12 +1460 1708 6 +1466 1708 6 +1467 1514 24 +1467 1515 24 +1470 1514 24 +1470 1515 24 +1509 1599 14 +1510 1599 14 +1524 1425 19 +1524 1427 19 +1524 1429 19 +1524 1431 19 +1525 1424 19 +1526 1425 19 +1526 1427 19 +1526 1429 19 +1526 1431 19 +1547 1715 24 +1553 1682 34 +1553 1683 34 +1600 1515 44 +1601 1515 44 +1619 1563 34 +1620 1563 34 +1634 1514 39 +1635 1514 39 +1651 1547 29 +1652 1547 29 +1652 1562 14 +1652 1564 14 +1660 1579 9 +1672 1546 34 +1672 1547 34 +1675 1594 11 +1683 1570 24 +1683 1571 24 +1691 1546 49 +1692 1546 49 +1705 1564 54 +1705 1565 54 + +# plate of food +Static 0x09D8 +1385 1803 2 +1385 1804 2 +1387 1817 2 +1388 1817 2 +1401 1803 2 +1401 1804 2 +1403 1817 4 +1404 1817 4 +1644 1579 4 +1644 1580 4 + +# pot +Static 0x09E0 +1193 1704 6 +1193 1852 2 +1318 1600 56 +1475 1512 20 +1545 1707 26 + +# frypan +Static 0x09E2 +1135 1816 2 +1192 1851 6 +1257 1885 3 +1319 1603 56 +1474 1512 26 +1514 1422 21 +1550 1706 26 +1593 1512 46 + +# pot +Static 0x09E3 +1249 1703 3 +1515 1422 21 + +# pot +Static 0x09E4 +1151 1617 0 +1154 1544 6 +1225 1568 6 +1256 1887 3 +1517 1425 21 + +# kettle +Static 0x09ED +1135 1817 0 +1137 1817 2 +1151 1616 2 +1152 1617 0 +1189 1705 2 +1190 1705 0 +1193 1853 2 +1228 1569 0 +1249 1704 1 +1258 1880 6 +1319 1604 56 +1448 1611 25 +1515 1425 21 +1544 1763 10 +1546 1704 20 +1550 1680 30 +1592 1514 40 + +# milk +Pitcher 0x09F0 (Content=Milk) +1193 1709 4 +1228 1576 4 +1253 1703 4 +1512 1425 21 +1525 1425 19 +1547 1714 24 +1552 1682 34 +1601 1514 44 +1652 1546 29 +1652 1563 14 +1671 1547 34 +1684 1571 24 + +# cut of raw ribs +RawRibs 0x09F1 +1448 1720 12 + +# pan +Static 0x09F3 +1140 1816 6 + +# fork +Fork 0x09F4 +1133 1820 2 +1150 1548 4 +1150 1620 2 +1152 1548 4 +1152 1620 2 +1193 1710 4 +1199 1851 2 +1227 1577 4 +1252 1704 4 +1332 1605 54 +1334 1605 54 +1336 1605 54 +1338 1605 54 +1340 1605 54 +1342 1605 54 +1344 1605 54 +1385 1804 2 +1401 1804 2 +1467 1515 24 +1470 1515 24 +1553 1683 34 +1672 1547 34 +1683 1571 24 +1705 1565 54 + +# fork +Fork 0x09F5 +1261 1884 4 +1388 1817 2 +1404 1817 4 +1453 1708 20 +1454 1708 6 +1456 1724 12 +1460 1708 6 +1466 1708 6 +1510 1599 14 +1526 1425 19 +1526 1427 19 +1526 1429 19 +1526 1431 19 +1548 1715 24 +1601 1515 44 +1620 1563 34 +1635 1514 39 +1652 1547 29 +1652 1562 14 +1652 1564 14 +1660 1579 9 +1692 1546 49 + +# knife +Knife 0x09F6 +1133 1820 2 +1150 1548 4 +1150 1620 2 +1152 1548 4 +1152 1620 2 +1193 1710 4 +1199 1851 2 +1227 1577 4 +1252 1704 4 +1332 1605 54 +1334 1605 54 +1336 1605 54 +1338 1605 54 +1340 1605 54 +1342 1605 54 +1344 1605 54 +1385 1804 2 +1401 1804 2 +1467 1515 24 +1470 1515 24 +1553 1683 34 +1672 1547 34 +1683 1571 24 +1705 1565 54 + +# knife +Knife 0x09F7 +1261 1884 4 +1388 1817 2 +1404 1817 4 +1454 1708 6 +1456 1724 12 +1460 1708 6 +1466 1708 6 +1510 1599 14 +1526 1425 19 +1526 1427 19 +1526 1429 19 +1526 1431 19 +1548 1715 24 +1601 1515 44 +1620 1563 34 +1635 1514 39 +1652 1547 29 +1652 1563 14 +1652 1564 14 +1660 1579 9 +1692 1546 49 + +# spoon +Spoon 0x09F8 +1150 1548 4 +1150 1620 2 +1152 1548 4 +1152 1620 2 +1193 1710 4 +1227 1577 4 +1252 1704 4 +1332 1605 54 +1334 1605 54 +1336 1605 54 +1338 1605 54 +1340 1605 54 +1342 1605 54 +1344 1605 54 +1467 1515 24 +1470 1515 24 +1553 1683 34 +1672 1547 34 +1683 1571 24 +1705 1565 54 + +# spoon +Spoon 0x09F9 +1454 1708 6 +1456 1724 12 +1460 1708 6 +1466 1708 6 +1510 1599 14 +1526 1425 19 +1526 1427 19 +1526 1429 19 +1526 1431 19 +1548 1715 24 +1601 1515 44 +1620 1563 34 +1635 1514 39 +1652 1547 29 +1652 1563 14 +1652 1564 14 +1660 1579 9 +1692 1546 49 + +# bowl of flour +Static 0x0A1E +1156 1616 6 +1192 1848 6 +1195 1704 6 +1256 1881 6 +1448 1613 25 +1517 1422 21 +1545 1680 36 +1545 1708 26 +1595 1512 46 + +# candle +CandleLarge 0x0A26 (Unlit) +1533 1418 61 +1534 1412 61 + +# stool +Stool 0x0A2A +1533 1417 55 +1533 1419 55 +1534 1417 55 +1534 1419 55 +1535 1417 55 +1535 1419 55 + +# folded sheet +Static 0x0A93 +1656 1640 2 + +# candle +CandleLarge 0x0B1A +1134 1820 2 +1151 1548 4 +1158 1544 6 +1194 1709 4 +1198 1851 2 +1224 1568 6 +1227 1576 4 +1251 1704 4 +1256 1880 6 +1260 1885 4 +1307 1566 34 +1307 1688 34 +1335 1672 36 +1340 1679 36 +1343 1732 64 +1343 1736 64 +1347 1678 36 +1355 1671 34 +1355 1678 34 +1366 1576 36 +1384 1584 36 +1384 1595 36 +1386 1803 2 +1387 1818 2 +1388 1604 36 +1396 1566 34 +1396 1687 34 +1402 1803 2 +1403 1818 4 +1408 1628 30 +1412 1617 34 +1412 1717 24 +1430 1752 16 +1448 1704 6 +1452 1609 26 +1453 1682 6 +1454 1704 6 +1456 1720 12 +1460 1704 6 +1466 1704 6 +1471 1576 26 +1473 1609 26 +1482 1586 26 +1495 1613 26 +1514 1613 14 +1516 1426 21 +1540 1716 24 +1544 1680 36 +1546 1688 34 +1550 1705 26 +1553 1656 32 +1580 1555 24 +1582 1555 24 +1583 1564 24 +1588 1564 24 +1592 1587 26 +1600 1516 44 +1600 1522 44 +1604 1711 26 +1619 1564 34 +1634 1515 39 +1634 1692 42 +1640 1582 6 +1640 1583 20 +1651 1635 4 +1655 1635 4 +1682 1570 24 +1691 1547 49 +1704 1565 54 + +# candelabra +Candelabra 0x0B1D +1334 1650 54 +1334 1656 54 +1335 1604 54 +1341 1604 54 +1342 1644 60 +1342 1647 60 +1525 1426 19 +1525 1430 19 + +# wooden chair +WoodenThrone 0x0B30 +1457 1724 6 + +# large vase +Static 0x0B45 +1454 1554 30 +1457 1554 30 +1568 1743 15 +1568 1744 15 +1578 1742 15 +1578 1743 15 +1579 1742 15 +1579 1743 15 + +# vase +Static 0x0B46 +1581 1738 15 + +# large vase +Static 0x0B47 +1560 1747 15 +1560 1748 15 +1560 1748 22 +1560 1749 15 +1560 1749 22 +1560 1750 15 +1568 1745 15 +1568 1745 22 +1569 1744 15 + +# vase +Static 0x0B48 +1580 1736 15 +1580 1736 19 +1581 1736 15 +1581 1736 19 + +# chair +FancyWoodenChairCushion 0x0B4E +1448 1551 30 +1470 1595 20 + +# chair +FancyWoodenChairCushion 0x0B4F +1450 1550 30 + +# chair +FancyWoodenChairCushion 0x0B50 +1456 1551 30 +1458 1551 30 +1460 1551 30 +1478 1597 20 + +# chair +FancyWoodenChairCushion 0x0B51 +1452 1551 30 +1480 1739 0 +1530 1417 55 + +# chair +WoodenChairCushion 0x0B52 +1331 1647 50 +1331 1649 50 +1331 1651 50 +1331 1655 50 +1331 1657 50 +1331 1659 50 +1414 1751 10 +1473 1739 0 +1545 1739 15 +1577 1555 20 +1649 1635 0 + +# chair +WoodenChairCushion 0x0B53 +1332 1587 72 +1332 1602 50 +1333 1644 72 +1334 1602 50 +1336 1587 72 +1336 1602 50 +1338 1602 50 +1339 1587 72 +1340 1602 50 +1342 1602 50 +1343 1587 72 +1343 1729 60 +1344 1602 50 +1348 1657 50 +1477 1594 20 +1479 1594 20 +1525 1423 15 + +# chair +WoodenChairCushion 0x0B54 +1332 1606 50 +1334 1606 50 +1336 1606 50 +1338 1606 50 +1340 1606 50 +1342 1606 50 +1344 1606 50 + +# chair +WoodenChairCushion 0x0B55 +1329 1589 72 +1337 1647 50 +1337 1649 50 +1337 1651 50 +1337 1653 50 +1337 1655 50 +1337 1657 50 +1337 1659 50 +1474 1594 20 +1474 1596 20 + +# chair +WoodenChair 0x0B56 +1259 1884 0 +1330 1603 72 +1341 1731 60 +1341 1733 60 +1341 1735 60 +1341 1737 60 +1409 1600 50 +1410 1596 30 +1410 1604 30 +1410 1606 30 +1418 1579 30 +1420 1548 30 +1423 1650 10 +1423 1655 10 +1427 1650 10 +1427 1655 10 +1450 1552 50 +1450 1553 50 +1450 1554 50 +1450 1555 50 +1451 1611 20 +1452 1680 0 +1473 1746 0 +1482 1588 20 +1493 1549 30 +1493 1551 30 +1493 1554 30 +1493 1554 70 +1493 1555 70 +1494 1615 20 +1508 1565 20 +1508 1567 20 +1508 1569 20 +1523 1425 15 +1523 1427 15 +1523 1429 15 +1523 1431 15 +1530 1415 35 +1530 1417 35 +1532 1429 55 +1532 1431 55 +1532 1433 55 +1539 1715 20 +1540 1417 55 +1545 1687 30 +1546 1715 20 +1552 1658 26 +1568 1707 35 +1568 1713 35 +1594 1595 20 +1599 1515 40 +1633 1514 35 +1634 1690 36 +1649 1604 20 +1649 1612 20 +1650 1547 25 +1658 1643 0 +1690 1546 45 + +# chair +WoodenChair 0x0B57 +1343 1735 20 +1368 1615 50 +1412 1594 30 +1414 1594 30 +1424 1685 0 +1426 1685 0 +1433 1684 0 +1435 1592 20 +1436 1592 20 +1436 1593 20 +1437 1592 20 +1437 1593 20 +1437 1684 0 +1438 1592 20 +1438 1593 20 +1443 1660 -10 +1447 1660 -10 +1448 1648 10 +1467 1513 20 +1470 1513 20 +1476 1609 20 +1495 1715 6 +1525 1435 35 +1527 1435 35 +1531 1413 35 +1532 1435 35 +1532 1441 55 +1533 1413 35 +1534 1435 35 +1536 1441 55 +1553 1681 30 +1571 1697 35 +1579 1553 20 +1579 1697 35 +1579 1707 35 +1581 1553 20 +1583 1553 20 +1594 1586 20 +1596 1654 10 +1650 1643 0 +1651 1633 0 +1653 1633 0 +1655 1633 0 +1672 1545 30 +1675 1593 7 +1683 1569 20 +1705 1563 50 + +# chair +WoodenChair 0x0B58 +1262 1884 0 +1332 1603 72 +1345 1731 60 +1345 1733 60 +1345 1735 60 +1345 1737 60 +1352 1742 60 +1412 1596 50 +1412 1598 50 +1412 1600 50 +1412 1602 50 +1412 1604 50 +1413 1604 30 +1413 1606 30 +1416 1596 30 +1416 1750 10 +1416 1752 10 +1417 1546 30 +1448 1663 -10 +1452 1552 50 +1452 1553 50 +1452 1554 50 +1452 1555 50 +1495 1550 30 +1495 1554 30 +1496 1554 70 +1496 1555 70 +1512 1567 20 +1527 1425 15 +1527 1427 15 +1527 1429 15 +1527 1431 15 +1535 1415 35 +1535 1417 35 +1535 1429 55 +1535 1431 55 +1535 1433 55 +1547 1738 15 +1547 1740 15 +1549 1715 20 +1585 1555 20 +1595 1650 10 +1595 1652 10 +1597 1595 20 +1601 1523 40 +1602 1515 40 +1604 1713 20 +1636 1514 35 +1652 1604 20 +1653 1547 25 +1653 1562 10 +1653 1564 10 +1657 1635 0 +1661 1579 5 +1693 1546 45 + +# chair +WoodenChair 0x0B59 +1342 1737 20 +1343 1739 60 +1344 1737 20 +1368 1635 50 +1412 1598 30 +1414 1598 30 +1466 1672 0 +1467 1516 20 +1470 1516 20 +1482 1672 0 +1496 1548 70 +1499 1665 27 +1532 1419 35 +1534 1419 35 +1553 1684 30 +1571 1699 35 +1579 1557 20 +1579 1699 35 +1579 1709 35 +1581 1557 20 +1582 1565 20 +1583 1557 20 +1587 1565 20 +1651 1637 0 +1653 1637 0 +1655 1637 0 +1659 1644 0 +1660 1644 0 +1672 1548 30 +1683 1572 20 +1705 1566 50 + +# chair +BambooChair 0x0B5A +1185 1708 0 +1191 1709 0 +1298 1566 30 +1298 1568 30 +1298 1685 30 +1298 1687 30 +1386 1817 0 +1400 1565 30 +1400 1567 30 +1400 1569 30 +1400 1685 30 +1400 1687 30 +1402 1817 0 +1411 1716 20 +1437 1550 32 +1438 1548 32 +1440 1549 32 +1451 1708 0 +1466 1562 30 +1467 1692 0 +1470 1578 20 +1478 1738 0 +1478 1739 0 +1485 1554 70 +1485 1555 70 +1508 1599 10 +1538 1739 15 +1577 1563 20 +1618 1563 30 +1643 1579 0 +1643 1580 0 + +# chair +BambooChair 0x0B5B +1133 1818 0 +1151 1546 0 +1193 1707 0 +1199 1849 0 +1227 1574 0 +1251 1697 0 +1252 1702 0 +1306 1565 30 +1354 1670 30 +1354 1677 30 +1385 1597 30 +1385 1802 0 +1392 1597 30 +1395 1565 30 +1401 1802 0 +1411 1616 30 +1467 1560 30 +1469 1548 30 +1469 1560 30 +1471 1560 30 +1471 1664 0 +1473 1664 0 +1477 1664 0 +1479 1664 0 +1495 1546 70 +1497 1546 70 +1499 1663 27 +1500 1663 27 +1513 1612 10 +1540 1748 35 +1544 1748 35 +1548 1748 35 +1582 1563 20 +1587 1563 20 + +# chair +BambooChair 0x0B5C +1133 1821 0 +1150 1549 0 +1150 1621 0 +1152 1549 0 +1152 1621 0 +1193 1711 0 +1199 1852 0 +1227 1578 0 +1252 1705 0 +1306 1689 30 +1354 1672 30 +1354 1679 30 +1385 1805 0 +1395 1688 30 +1401 1805 0 +1411 1633 30 +1432 1686 0 +1434 1686 0 +1436 1686 0 +1438 1686 0 +1467 1564 30 +1467 1565 50 +1469 1564 30 +1469 1565 50 +1471 1564 30 +1471 1565 50 +1475 1749 0 +1476 1749 0 +1477 1749 0 +1494 1717 6 +1495 1717 6 +1540 1750 35 +1544 1750 35 +1548 1750 35 + +# chair +BambooChair 0x0B5D +1301 1566 30 +1301 1568 30 +1301 1685 30 +1301 1687 30 +1389 1817 0 +1403 1565 30 +1403 1567 30 +1403 1569 30 +1403 1685 30 +1403 1687 30 +1405 1817 0 +1420 1578 30 +1420 1580 30 +1455 1708 0 +1461 1708 0 +1467 1708 0 +1472 1562 30 +1475 1738 0 +1475 1739 0 +1477 1743 0 +1477 1744 0 +1477 1745 0 +1487 1554 70 +1487 1555 70 +1511 1599 10 +1541 1739 15 +1579 1563 20 +1621 1563 30 + +# foot stool +FootStool 0x0B5E +1329 1657 72 +1425 1719 20 +1426 1719 20 +1427 1719 20 +1428 1719 20 +1430 1712 20 +1430 1713 20 +1430 1714 20 +1430 1715 20 +1430 1716 20 +1430 1717 20 +1441 1578 20 +1441 1580 20 +1442 1577 20 +1444 1577 20 +1467 1687 0 +1473 1687 0 +1475 1687 0 +1488 1685 20 +1489 1685 20 +1490 1685 20 +1491 1685 20 +1493 1686 20 +1493 1687 20 +1493 1688 20 +1493 1689 20 +1546 1768 10 +1547 1768 10 +1548 1768 10 +1549 1768 10 +1551 1762 10 +1551 1763 10 +1551 1764 10 +1551 1765 10 +1551 1766 10 +1616 1583 0 +1617 1583 0 +1618 1583 0 +1619 1583 0 +1620 1583 0 + +# broken chair +Static 0x0C10 +1435 1595 20 + +# broken chair +Static 0x0C11 +1431 1595 24 + +# small fish +Static 0x0DD6 +1437 1773 -3 +1444 1761 -3 +1451 1756 -3 +1468 1757 -2 +1476 1759 -3 +1482 1767 -3 +1487 1747 -1 +1494 1746 -2 +1494 1759 -2 + +# small fish +Static 0x0DD7 +1435 1760 -3 +1436 1765 -3 +1446 1755 -3 +1449 1766 -3 +1450 1755 -3 +1476 1761 -3 +1482 1757 -3 +1482 1768 -2 +1486 1747 -1 +1487 1747 -1 +1498 1762 -3 + +# knitting +Static 0x0DF7 +1328 1589 76 +1343 1588 76 +1551 1656 32 + +# pile of wool +Static 0x0DF8 +1544 1659 26 + +# pile of wool +Static 0x0DF8 (Hue=0xD) +1390 1603 30 + +# bale of cotton +Static 0x0DF9 (Hue=0x3) +1329 1587 72 +1344 1587 72 + +# chessmen +Static 0x0E12 +1300 1568 34 +1544 1749 40 +1548 1771 14 + +# chessmen +Static 0x0E13 +1497 1693 24 +1533 1429 59 +1622 1588 4 + +# chessmen +Static 0x0E14 +1497 1693 24 +1533 1429 59 +1622 1588 4 + +# cards +Static 0x0E17 +1299 1684 34 +1533 1434 59 + +# cards +Static 0x0E18 +1299 1685 34 +1299 1687 34 +1533 1433 59 +1547 1767 16 +1618 1589 4 +1626 1589 4 + +# cards +Static 0x0E19 +1300 1685 34 +1300 1687 34 +1534 1433 59 +1547 1767 16 +1618 1589 4 +1626 1589 4 + +# checkers +Static 0x0E1A +1562 1762 14 +1618 1587 4 + +# checkers +Static 0x0E1B +1562 1762 14 +1618 1587 4 + +# backgammon board +Backgammon 0x0E1C +1402 1686 34 +1497 1686 24 +1534 1431 59 +1554 1763 14 +1626 1587 4 + +# ball of yarn +Static 0x0E1D +1342 1588 76 + +# ball of yarn +Static 0x0E1F (Hue=0x3) +1328 1590 76 + +# bloody bandage +Static 0x0E22 +1511 1572 26 + +# bloody water +Static 0x0E23 +1468 1613 20 +1470 1608 20 +1473 1613 26 +1504 1566 20 +1511 1573 26 + +# bottle +Static 0x0E28 +1328 1606 78 + +# bottle +Static 0x0E29 +1328 1607 78 + +# crystal ball +Static 0x0E2F (Light=Circle150) +1336 1605 78 +1494 1549 36 +1594 1652 16 + +# blank scroll +Static 0x0E34 +1328 1601 78 +1336 1602 78 + +# backpack +Backpack 0x0E75 +1464 1666 5 + +# bag +Bag 0x0E76 +1464 1665 5 + +# barrel +Barrel 0x0E77 +1301 1680 52 +1301 1680 57 +1302 1560 52 +1302 1560 57 +1302 1567 52 +1302 1567 57 +1302 1568 52 +1302 1568 57 +1302 1680 52 +1302 1680 57 +1302 1681 52 +1302 1681 57 +1303 1560 52 +1303 1560 57 +1303 1561 52 +1303 1561 57 +1303 1567 52 +1303 1567 57 +1303 1568 52 +1303 1568 57 +1304 1687 52 +1304 1687 57 +1304 1688 52 +1304 1688 57 +1305 1687 52 +1305 1687 57 +1305 1688 52 +1305 1688 57 +1315 1607 50 +1315 1607 55 +1315 1607 60 +1316 1600 50 +1316 1607 50 +1316 1607 55 +1317 1600 50 +1317 1600 55 +1326 1677 52 +1326 1677 57 +1326 1678 52 +1326 1678 57 +1327 1677 52 +1327 1677 57 +1327 1678 52 +1327 1678 57 +1341 1674 52 +1341 1674 57 +1341 1675 52 +1341 1675 57 +1346 1682 52 +1346 1682 57 +1346 1683 52 +1346 1683 57 +1347 1682 52 +1347 1682 57 +1353 1676 52 +1353 1676 57 +1353 1677 52 +1353 1677 57 +1354 1676 52 +1354 1676 57 +1354 1677 52 +1354 1677 57 +1390 1824 0 +1390 1824 5 +1391 1824 0 +1391 1824 5 +1392 1806 0 +1392 1806 5 +1392 1807 0 +1392 1807 5 +1395 1688 52 +1395 1688 57 +1396 1687 52 +1396 1687 57 +1398 1684 52 +1398 1684 57 +1398 1685 52 +1398 1685 57 +1399 1567 52 +1399 1567 57 +1399 1568 52 +1399 1568 57 +1399 1684 52 +1399 1684 57 +1399 1685 52 +1399 1685 57 +1400 1560 52 +1400 1560 57 +1400 1561 52 +1400 1561 57 +1400 1567 52 +1400 1567 57 +1400 1568 52 +1400 1568 57 +1401 1560 52 +1401 1560 57 +1406 1824 0 +1406 1824 5 +1407 1824 0 +1407 1824 5 +1408 1806 0 +1408 1806 5 +1408 1807 0 +1408 1807 5 +1472 1720 0 +1472 1721 0 +1472 1722 0 +1473 1720 0 +1473 1724 0 +1473 1725 0 +1474 1725 0 +1477 1721 0 +1477 1722 0 +1478 1721 0 +1478 1722 0 +1480 1725 0 +1481 1724 0 +1481 1725 0 +1512 1432 15 +1512 1432 20 +1512 1432 25 +1512 1432 30 +1512 1433 15 +1512 1433 20 +1513 1432 15 +1513 1432 20 +1513 1432 25 +1516 1436 15 +1516 1436 20 +1517 1435 15 +1517 1435 20 +1517 1435 25 +1518 1435 15 +1518 1435 20 +1518 1436 15 +1560 1742 15 +1560 1743 15 +1560 1743 20 +1560 1743 25 +1560 1744 15 +1560 1744 20 +1561 1742 15 +1569 1739 15 +1570 1737 15 +1570 1737 20 +1570 1738 15 +1570 1738 20 +1570 1739 15 +1571 1737 15 +1571 1737 20 +1571 1738 15 +1571 1738 20 +1571 1739 15 +1571 1747 15 +1571 1748 15 +1572 1737 15 +1572 1747 15 +1572 1747 20 +1572 1747 25 +1572 1748 15 +1572 1748 20 +1572 1748 25 +1573 1746 15 +1576 1738 15 +1576 1739 15 +1576 1739 20 +1576 1740 15 +1576 1740 20 +1580 1746 15 +1580 1746 20 +1580 1746 25 +1580 1746 35 +1580 1747 15 +1581 1745 15 +1581 1746 15 +1581 1746 20 +1616 1578 -20 +1616 1578 -15 +1616 1579 -20 +1616 1579 -15 +1616 1580 -20 +1617 1579 -20 +1621 1646 35 + +# barrel +FillableBarrel 0x0E77 +1288 1757 10 +1288 1757 15 +1288 1758 10 +1288 1758 15 +1304 1758 10 +1429 1592 20 +1429 1592 25 +1429 1592 30 +1430 1592 20 +1430 1592 25 +1431 1762 -2 +1432 1763 -2 +1436 1754 -2 +1436 1755 -2 +1437 1754 -2 +1437 1774 -2 +1437 1775 -2 +1439 1761 -1 +1439 1762 -2 +1440 1761 -2 +1440 1762 -3 +1467 1667 5 +1467 1668 5 +1467 1668 10 +1468 1667 5 +1468 1668 5 +1468 1761 -2 +1470 1763 -2 +1472 1761 -2 +1474 1754 -2 +1474 1755 -2 +1475 1754 -2 +1475 1755 -2 +1481 1770 -2 +1481 1771 -2 +1483 1771 -2 +1484 1750 -2 +1484 1751 -2 +1485 1750 -2 +1486 1689 20 +1486 1689 25 +1486 1690 20 +1486 1690 25 +1486 1690 30 +1487 1690 20 +1487 1690 25 +1490 1761 -2 +1491 1762 -2 +1494 1760 -2 +1494 1761 -2 +1496 1746 -2 +1497 1746 -2 +1497 1748 -2 +1612 1710 20 +1613 1709 20 +1613 1710 20 +1613 1710 25 +1614 1708 20 +1614 1709 20 +1614 1709 25 +1614 1710 20 +1614 1710 25 +1614 1710 30 + +# wooden box +FillableWoodenBox 0x0E7D +1437 1597 20 + +# strong box +FillableMetalBox 0x0E80 +1464 1671 6 +1480 1671 6 +1481 1586 26 +1492 1613 26 +1596 1587 26 +1598 1655 16 +1648 1644 6 + +# empty tub +Static 0x0E83 +1256 1884 2 +1290 1766 10 +1290 1769 10 +1290 1772 10 +1290 1775 10 +1290 1778 10 +1290 1781 10 +1293 1754 10 +1296 1754 10 +1299 1754 10 +1306 1766 10 +1306 1769 10 +1306 1772 10 +1306 1775 10 +1306 1778 10 +1306 1781 10 +1321 1600 50 +1385 1646 30 +1385 1649 30 +1385 1652 30 +1385 1655 30 +1385 1658 30 +1385 1661 30 +1391 1649 30 +1391 1652 30 +1391 1655 30 +1391 1658 30 + +# pitchfork +Static 0x0E87 +1288 1764 16 + +# pitchfork +Static 0x0E88 +1291 1758 10 + +# mortar and pestle +Static 0x0E9B +1501 1656 33 +1502 1656 33 + +# drum +Static 0x0E9C +1439 1550 50 +1440 1557 31 +1440 1558 31 +1445 1549 51 +1445 1666 -10 +1452 1663 -10 +1452 1664 -10 +1469 1562 51 +1471 1549 30 + +# tambourine +Static 0x0E9D +1440 1554 31 +1447 1666 -10 +1450 1661 -10 +1451 1661 -10 +1467 1549 30 + +# tambourine +Static 0x0E9E +1439 1555 50 +1440 1553 31 +1444 1555 51 + +# standing harp +Static 0x0EB1 +1438 1550 33 +1439 1548 33 +1441 1549 33 +1444 1551 51 +1447 1663 -10 +1452 1665 -10 +1452 1666 -10 +1469 1549 32 + +# lap harp +Static 0x0EB2 +1439 1560 50 +1449 1663 -10 +1451 1667 -10 +1452 1667 -10 +1467 1562 51 + +# lute +Static 0x0EB3 +1438 1565 50 +1445 1663 -10 +1449 1666 -10 +1452 1661 -10 +1452 1662 -10 +1470 1562 51 + +# lute +Static 0x0EB4 +1437 1554 31 +1437 1555 31 +1437 1556 31 +1445 1553 51 + +# music stand +Static 0x0EB5 +1437 1551 32 +1438 1549 32 +1440 1550 32 +1445 1664 -10 +1447 1664 -10 +1449 1664 -10 +1467 1563 51 +1469 1563 51 + +# music stand +Static 0x0EB6 +1445 1665 -10 +1447 1665 -10 +1449 1665 -10 +1450 1660 -10 +1451 1660 -10 +1452 1660 -10 + +# music stand +Static 0x0EB7 +1441 1553 32 +1441 1554 32 +1441 1557 32 +1441 1558 32 +1445 1551 51 +1445 1555 51 +1446 1549 51 +1446 1553 51 +1471 1562 51 + +# music stand +Static 0x0EBA +1438 1554 32 +1438 1555 32 +1438 1556 32 + +# sheet music +Static 0x0EBD +1445 1665 -10 +1447 1665 -10 +1449 1665 -10 +1450 1660 -10 +1451 1660 -10 +1452 1660 -10 + +# cleaver +Static 0x0EC2 +1453 1720 6 + +# dress form +Static 0x0EC6 +1384 1601 30 +1440 1576 20 +1470 1684 0 +1471 1684 0 +1547 1658 26 + +# dress form +Static 0x0EC7 +1469 1684 0 +1549 1660 26 + +# clean bandage +Static 0x0EE9 +1508 1562 26 +1508 1563 26 + +# bottle +Static 0x0EFF +1336 1604 78 + +# bottle +Static 0x0F02 +1508 1561 26 + +# bottle +Static 0x0F03 +1336 1603 78 + +# Black Potion +Static 0x0F06 +1328 1600 78 + +# Green Potion +Static 0x0F0A +1328 1605 78 + +# amethyst +Static 0x0F16 +1660 1643 4 + +# ruby +Static 0x0F1A +1660 1643 4 + +# diamond +Static 0x0F27 +1659 1643 4 + +# hay +Static 0x0F34 +1288 1769 10 +1288 1773 10 +1288 1775 10 +1288 1776 10 +1288 1778 10 +1288 1781 10 +1289 1754 10 +1289 1755 10 +1289 1766 10 +1289 1767 10 +1289 1769 10 +1289 1772 10 +1289 1780 21 +1290 1754 10 +1290 1755 10 +1290 1778 10 +1293 1752 10 +1294 1752 10 +1296 1752 10 +1297 1752 10 +1299 1752 10 +1300 1752 10 +1300 1769 10 +1300 1772 10 +1300 1775 10 +1301 1767 10 +1301 1769 10 +1301 1773 10 +1301 1775 10 +1301 1779 10 +1301 1782 10 +1302 1753 10 +1302 1754 10 +1302 1767 10 +1302 1779 10 +1302 1782 10 +1321 1800 0 +1321 1802 0 +1322 1800 0 +1323 1801 0 +1323 1802 0 +1323 1804 0 +1324 1802 0 +1325 1803 0 +1325 1804 0 +1326 1804 0 +1326 1805 0 +1384 1646 30 +1384 1647 30 +1384 1649 30 +1384 1650 30 +1384 1652 30 +1384 1653 30 +1384 1655 30 +1384 1656 30 +1384 1658 30 +1384 1659 30 +1384 1661 30 +1384 1662 30 +1385 1641 30 +1386 1640 30 +1386 1642 30 +1387 1641 30 +1389 1640 30 +1392 1646 30 +1392 1647 30 +1392 1649 30 +1392 1650 30 +1392 1652 30 +1392 1653 30 +1392 1655 30 +1392 1656 30 +1392 1658 30 +1392 1659 30 +1516 1544 25 +1517 1541 25 +1521 1544 25 +1524 1544 25 +1525 1541 25 +1562 1550 -15 +1567 1554 20 + +# sheaf of hay +Static 0x0F36 +1288 1752 10 +1288 1753 10 +1288 1754 10 +1288 1755 10 +1289 1752 10 +1289 1753 10 +1290 1752 10 +1290 1753 10 +1291 1752 10 +1291 1753 10 +1291 1754 10 +1317 1644 30 +1324 1800 0 +1325 1800 0 +1325 1801 0 +1326 1800 0 +1326 1802 0 +1384 1640 30 +1385 1640 30 +1386 1640 30 +1386 1641 30 +1387 1640 30 +1387 1641 30 +1388 1640 30 +1388 1641 30 +1389 1640 30 +1389 1641 30 +1391 1661 30 +1391 1662 30 +1392 1661 30 +1392 1662 30 + +# executioner's axe +Static 0x0F45 +1449 1721 6 + +# easel with canvas +Static 0x0F66 +1354 1602 72 +1446 1662 10 +1449 1662 10 +1452 1662 10 + +# easel with canvas +Static 0x0F68 +1350 1604 72 + +# easel with canvas +Static 0x0F6A +1445 1666 10 +1448 1666 10 +1451 1666 10 + +# bolt of cloth +Static 0x0F98 +1440 1576 20 +1466 1684 0 +1466 1685 0 + +# bolt of cloth +Static 0x0F98 (Hue=0xD) +1389 1603 30 + +# bolt of cloth +Static 0x0F99 +1466 1693 0 +1466 1694 0 +1554 1656 26 + +# bolt of cloth +Static 0x0F99 (Hue=0xD) +1389 1604 30 + +# bolt of cloth +Static 0x0F9A +1554 1656 26 + +# bolt of cloth +Static 0x0F9A (Hue=0xD) +1389 1604 30 + +# bolt of cloth +Static 0x0F9B +1440 1576 20 +1466 1684 0 +1467 1684 0 +1549 1657 26 +1550 1657 26 + +# bolt of cloth +Static 0x0F9C +1549 1657 26 +1551 1657 26 + +# sewing kit +Static 0x0F9D +1388 1603 36 +1440 1578 26 +1466 1688 6 +1468 1691 6 +1553 1660 32 + +# scissors +Scissors 0x0F9E +1467 1686 0 +1472 1686 0 +1550 1656 32 + +# scissors +Scissors 0x0F9F +1344 1588 76 +1388 1602 36 +1441 1577 20 + +# spool of thread +Static 0x0FA1 +1468 1693 6 + +# playing cards +Static 0x0FA2 +1492 1688 26 +1548 1749 39 +1555 1772 12 + +# playing cards +Static 0x0FA3 +1435 1715 23 +1497 1681 23 +1497 1696 24 +1554 1769 14 + +# chess board +ChessBoard 0xFA6 +1497 1693 24 +1533 1429 59 +1622 1588 4 +1300 1567 34 +1544 1749 39 +1548 1771 13 + +# checker board +CheckerBoard 0xFA6 +1562 1762 14 +1618 1587 4 +1435 1720 23 + +# dice and cup +Dices 0x0FA7 +1402 1687 34 +1435 1714 23 +1497 1679 24 +1497 1685 24 +1533 1431 59 +1541 1749 39 +1550 1763 16 +1554 1764 14 +1626 1586 4 + +# chess pieces +Static 0x0FA8 +1300 1566 34 +1544 1749 40 +1548 1771 14 + +# backgammon game +Backgammon 0x0FAD +1497 1678 21 +1540 1749 39 +1550 1762 16 + +# sledge hammer +Static 0x0FB5 +1347 1778 21 +1356 1770 21 +1356 1774 21 +1356 1786 21 +1364 1574 30 + +# horse shoes +Static 0x0FB6 +1348 1770 21 + +# forged metal +Static 0x0FB7 +1362 1573 30 +1425 1557 30 + +# tongs +Static 0x0FBC +1362 1574 30 + +# book +Static 0x0FBD +1186 1708 4 +1332 1653 54 +1351 1742 64 +1366 1574 36 +1412 1716 24 +1415 1751 14 +1419 1579 34 +1421 1549 39 +1432 1610 26 +1452 1611 26 +1453 1680 6 +1468 1692 6 +1471 1578 26 +1471 1595 26 +1474 1739 6 +1474 1746 6 +1479 1739 6 +1483 1588 26 +1493 1714 11 +1494 1554 34 +1495 1615 26 +1504 1567 25 +1511 1567 26 +1540 1739 19 +1546 1739 19 +1553 1658 32 +1603 1713 26 +1635 1690 42 +1650 1612 24 +1650 1635 4 + +# book +Static 0x0FBE +1251 1698 4 +1306 1566 34 +1306 1688 34 +1332 1588 76 +1333 1645 76 +1343 1730 64 +1343 1736 24 +1354 1671 34 +1354 1678 34 +1368 1634 54 +1395 1566 34 +1395 1687 34 +1411 1617 34 +1411 1632 34 +1433 1685 4 +1437 1685 4 +1448 1649 16 +1466 1671 6 +1476 1610 24 +1478 1596 26 +1482 1671 6 +1496 1547 74 +1499 1664 31 +1513 1613 14 +1571 1698 39 +1579 1698 39 +1579 1708 39 +1582 1564 24 +1587 1564 24 +1594 1587 26 +1596 1655 16 +1650 1644 6 + +# pen and ink +Static 0x0FBF +1186 1708 4 +1332 1653 54 +1351 1742 64 +1366 1574 36 +1412 1716 24 +1415 1751 14 +1419 1579 34 +1432 1610 26 +1452 1611 26 +1453 1680 6 +1468 1691 6 +1471 1578 26 +1471 1595 26 +1474 1739 6 +1483 1588 26 +1493 1714 11 +1494 1554 34 +1495 1615 26 +1504 1567 25 +1511 1567 26 +1526 1436 39 +1533 1436 39 +1546 1739 19 +1553 1658 32 +1603 1713 26 +1635 1690 42 +1650 1612 24 +1650 1635 4 + +# pen and ink +Static 0x0FC0 +1251 1698 4 +1306 1566 34 +1306 1688 34 +1333 1645 76 +1343 1730 64 +1343 1736 24 +1354 1671 34 +1354 1678 34 +1368 1616 54 +1368 1634 54 +1395 1566 34 +1395 1687 34 +1411 1617 34 +1411 1632 34 +1421 1548 39 +1433 1685 4 +1437 1685 4 +1448 1649 16 +1466 1671 6 +1474 1745 6 +1476 1610 24 +1477 1596 26 +1479 1738 6 +1482 1671 6 +1496 1547 74 +1499 1664 31 +1513 1613 14 +1571 1698 39 +1579 1698 39 +1579 1708 39 +1582 1564 24 +1587 1564 24 +1594 1587 26 +1596 1655 16 +1650 1644 6 + +# paints and brush +Static 0x0FC1 +1355 1602 77 +1445 1665 10 +1446 1663 10 +1448 1665 10 +1449 1663 10 +1451 1665 10 +1452 1663 10 + +# book +SongOfSamlethe 0x0FEF +1401 1565 34 + +# book +QuestOfVirtues 0x0FEF +1532 1436 39 + +# book +DiversityOfOurLand 0x0FEF +1568 1709 39 + +# book +VirtueBook 0x0FF0 +1401 1564 34 + +# book +TalesOfVesperVol1 0x0FF0 +1402 1564 34 + +# book +RedBook 0x0FF1 +1402 1569 34 +1524 1436 39 + +# book +BlueBook 0x0FF2 +1401 1568 34 + +# book +CallToAnarchy 0x0FF3 +1401 1566 34 + +# book +TamingDragons 0x0FF4 +1402 1567 34 + +# book +EthicalHedonism 0x0FF4 +1534 1436 39 + +# book +LifeOfATravellingMinstrel 0x0FF4 +1539 1739 19 + +# book +TaleOfThreeTribes 0x0FF4 +1568 1708 39 + +# glass pitcher +Pitcher 0x0FF6 +1228 1576 4 +1253 1703 4 +1525 1425 19 +1547 1714 24 +1552 1682 34 +1601 1514 44 +1652 1563 14 +1671 1547 34 +1684 1571 24 + +# skull mug +Static 0x0FFC +1614 1586 4 +1622 1586 4 + +# skull mug +Static 0x0FFD +1616 1582 6 +1618 1582 6 +1620 1582 6 +1622 1589 4 + +# skull mug +Static 0x0FFE +1626 1589 4 + +# pewter mug +PewterMug 0x0FFF +1426 1718 26 +1426 1723 24 +1426 1724 24 +1426 1728 24 +1426 1730 24 +1426 1733 24 +1426 1734 24 +1427 1718 26 +1435 1713 24 +1435 1716 24 +1435 1721 24 +1452 1707 6 +1468 1515 24 +1469 1515 24 +1497 1677 24 +1497 1685 24 +1497 1687 24 +1497 1689 24 +1509 1600 14 +1546 1767 16 +1547 1716 24 +1550 1766 16 +1556 1772 14 +1558 1762 14 +1614 1587 4 +1614 1589 4 + +# pewter mug +PewterMug 0x1000 +1150 1548 4 +1152 1548 4 +1194 1710 4 +1228 1576 4 +1253 1704 4 +1323 1679 34 +1324 1674 34 +1328 1674 34 +1429 1713 26 +1429 1715 26 +1429 1717 26 +1454 1707 6 +1456 1723 12 +1460 1707 6 +1466 1707 6 +1468 1514 24 +1489 1686 26 +1491 1686 26 +1497 1694 24 +1497 1695 24 +1546 1771 12 +1548 1716 24 +1548 1767 16 +1550 1765 16 +1554 1772 12 +1562 1764 14 +1601 1516 44 +1635 1515 39 +1652 1548 29 +1660 1580 9 +1673 1547 34 + +# pewter mug +PewterMug 0x1001 +1149 1620 4 +1150 1547 4 +1153 1620 4 +1192 1708 4 +1226 1577 4 +1251 1703 4 +1426 1723 24 +1426 1724 24 +1426 1727 24 +1426 1729 24 +1426 1733 24 +1435 1713 24 +1435 1716 24 +1435 1719 24 +1470 1514 24 +1492 1687 26 +1492 1689 26 +1497 1680 24 +1497 1682 24 +1497 1688 24 +1497 1692 24 +1497 1695 24 +1497 1697 24 +1510 1598 14 +1553 1772 14 +1558 1762 14 +1558 1763 14 +1562 1763 14 +1608 1586 4 +1608 1587 4 +1671 1546 34 +1692 1545 49 + +# pewter mug +PewterMug 0x1002 +1192 1710 4 +1322 1674 34 +1322 1679 34 +1327 1674 34 +1327 1679 34 +1600 1514 44 +1634 1513 39 +1651 1546 29 +1691 1545 49 + +# spittoon +Static 0x1003 +1424 1721 20 +1424 1733 20 +1432 1712 20 +1437 1712 20 +1486 1684 20 +1494 1676 20 +1494 1697 20 +1544 1773 10 +1554 1765 10 +1558 1760 10 +1562 1765 10 + +# empty jar +Static 0x1005 +1512 1429 21 +1513 1561 26 +1515 1427 21 + +# full jar +Static 0x1006 +1513 1560 26 + +# hay sheave +Static 0x100C +1513 1544 25 + +# hay sheave +Static 0x100D +1317 1644 30 +1319 1644 30 +1321 1644 30 +1508 1543 25 +1519 1543 25 +1523 1543 25 + +# pile of wool +Static 0x101F +1475 1686 0 +1544 1657 26 + +# chisels +Static 0x1027 +1430 1596 26 + +# dovetail saw +Static 0x1028 +1430 1595 26 + +# hammer +Static 0x102A +1455 1579 30 + +# hammer +Static 0x102B +1393 1598 36 + +# nails +Static 0x102F +1392 1598 36 +1430 1597 26 + +# jointing plane +Static 0x1030 +1391 1598 36 +1431 1596 26 + +# saw +Static 0x1034 +1431 1596 26 +1452 1580 30 + +# saw +Static 0x1035 +1392 1598 36 +1431 1597 26 +1453 1579 30 + +# hay +Static 0x1036 +1289 1779 10 +1289 1782 10 +1290 1779 10 +1290 1782 10 +1294 1753 10 +1294 1754 10 +1297 1753 10 +1297 1754 10 +1298 1782 10 +1300 1754 10 +1301 1753 10 +1301 1754 10 +1301 1770 10 +1301 1773 10 +1301 1776 10 +1301 1779 10 +1301 1782 10 +1302 1770 10 +1302 1773 10 +1302 1776 10 +1302 1779 10 +1302 1782 10 +1303 1770 10 +1303 1773 10 +1305 1773 10 +1305 1776 10 +1305 1777 16 +1305 1779 10 +1305 1780 16 +1305 1783 16 +1306 1773 10 +1306 1776 10 +1306 1777 16 +1306 1779 10 +1306 1783 16 +1307 1780 16 +1307 1783 16 +1309 1664 30 +1310 1647 30 +1310 1648 30 +1310 1652 30 +1310 1659 30 +1311 1645 30 +1311 1654 30 +1311 1666 30 +1312 1646 30 +1312 1661 30 +1313 1649 30 +1314 1646 30 +1314 1661 30 +1315 1648 30 +1315 1650 30 +1316 1661 30 +1317 1646 30 +1317 1658 30 +1319 1646 30 +1319 1648 30 +1319 1649 30 +1319 1661 30 +1320 1648 30 +1320 1664 30 +1322 1647 30 +1322 1649 30 +1385 1644 30 +1385 1647 30 +1385 1650 30 +1385 1653 30 +1385 1656 30 +1385 1659 30 +1385 1662 30 +1385 1668 30 +1387 1644 30 +1388 1647 30 +1388 1650 30 +1388 1653 30 +1388 1654 30 +1388 1656 30 +1388 1659 30 +1388 1662 30 +1388 1664 30 +1389 1643 30 +1389 1646 30 +1389 1649 30 +1389 1655 30 +1389 1658 30 +1389 1659 30 +1389 1660 30 +1389 1661 30 +1390 1644 30 +1390 1652 41 +1390 1653 41 +1391 1643 30 +1392 1647 30 +1392 1650 30 +1392 1653 30 +1392 1656 30 +1392 1659 30 +1509 1547 25 +1510 1548 25 +1511 1548 25 +1511 1550 25 +1513 1547 25 +1513 1549 25 +1514 1543 25 +1515 1542 25 +1515 1544 25 +1515 1545 25 +1515 1550 25 +1516 1542 25 +1516 1544 25 +1516 1545 25 +1516 1547 25 +1517 1541 25 +1517 1543 25 +1517 1544 25 +1517 1549 25 +1518 1547 25 +1518 1550 25 +1519 1548 25 +1520 1549 25 +1521 1541 25 +1521 1544 25 +1521 1548 25 +1522 1549 25 +1522 1550 25 +1523 1547 25 +1524 1549 25 +1525 1548 25 +1525 1550 25 +1526 1548 25 +1587 1555 20 +1588 1553 20 +1588 1556 20 +1590 1553 20 +1590 1557 20 +1591 1555 20 +1592 1554 20 +1592 1558 20 +1593 1553 20 +1593 1556 20 +1594 1554 20 +1594 1555 20 +1595 1553 20 +1595 1555 20 +1595 1557 20 +1597 1554 20 +1597 1556 20 +1598 1558 20 + +# hay +Static 0x1037 +1289 1767 10 +1289 1770 10 +1289 1773 10 +1289 1776 10 +1290 1760 10 +1290 1761 10 +1290 1763 10 +1290 1767 10 +1290 1770 10 +1290 1773 10 +1290 1776 10 +1291 1760 10 +1291 1762 10 +1291 1765 21 +1292 1758 10 +1292 1761 10 +1293 1759 10 +1293 1760 10 +1293 1762 10 +1293 1764 10 +1293 1767 10 +1293 1771 10 +1293 1774 10 +1293 1778 10 +1293 1780 10 +1294 1757 10 +1294 1758 10 +1294 1760 10 +1294 1768 10 +1294 1771 10 +1294 1776 10 +1294 1782 10 +1294 1786 10 +1294 1788 10 +1295 1758 10 +1295 1764 10 +1295 1765 10 +1295 1774 10 +1295 1777 10 +1295 1783 10 +1296 1757 10 +1296 1758 10 +1296 1763 10 +1296 1765 10 +1296 1768 10 +1296 1772 10 +1296 1778 10 +1296 1780 10 +1296 1781 10 +1296 1785 10 +1297 1759 10 +1297 1760 10 +1297 1761 10 +1297 1765 10 +1297 1767 10 +1297 1769 10 +1297 1772 10 +1297 1775 10 +1297 1781 10 +1297 1787 10 +1298 1758 10 +1298 1763 10 +1298 1767 10 +1298 1770 10 +1298 1773 10 +1298 1777 10 +1298 1779 10 +1298 1785 10 +1299 1757 10 +1299 1762 10 +1299 1764 10 +1299 1788 10 +1300 1759 10 +1300 1765 21 +1300 1786 10 +1301 1758 10 +1301 1761 10 +1301 1764 10 +1301 1767 10 +1302 1757 10 +1302 1759 10 +1302 1761 10 +1302 1767 10 +1303 1761 10 +1303 1763 10 +1303 1767 10 +1304 1761 10 +1305 1760 10 +1305 1767 10 +1305 1771 16 +1306 1770 10 +1307 1768 16 +1313 1806 0 +1313 1818 0 +1313 1822 0 +1313 1825 0 +1313 1830 0 +1314 1808 0 +1314 1810 0 +1314 1814 0 +1314 1816 0 +1314 1819 0 +1314 1822 0 +1315 1803 0 +1315 1806 0 +1315 1818 0 +1315 1819 0 +1315 1820 0 +1315 1824 0 +1315 1828 0 +1315 1829 0 +1316 1804 0 +1316 1807 0 +1316 1808 0 +1316 1810 0 +1316 1811 0 +1316 1813 0 +1316 1817 0 +1316 1822 0 +1316 1826 0 +1317 1803 0 +1317 1806 0 +1317 1808 0 +1317 1814 0 +1317 1818 0 +1317 1819 0 +1317 1831 11 +1318 1805 0 +1318 1807 0 +1318 1811 0 +1318 1816 0 +1318 1818 0 +1318 1822 0 +1318 1826 0 +1319 1804 0 +1319 1806 0 +1319 1808 0 +1319 1810 0 +1319 1812 0 +1319 1815 0 +1319 1821 0 +1319 1823 0 +1319 1824 0 +1319 1828 0 +1319 1830 0 +1320 1801 0 +1320 1803 0 +1320 1805 0 +1320 1814 0 +1320 1815 0 +1320 1817 0 +1320 1818 0 +1320 1820 0 +1321 1804 0 +1321 1813 0 +1321 1826 0 +1321 1829 0 +1322 1803 0 +1322 1806 0 +1322 1807 0 +1322 1808 0 +1322 1810 0 +1322 1814 0 +1322 1815 0 +1322 1817 0 +1322 1818 0 +1322 1820 0 +1322 1823 0 +1323 1807 0 +1323 1812 0 +1323 1816 0 +1323 1817 0 +1323 1829 0 +1323 1830 0 +1324 1803 0 +1324 1805 0 +1324 1810 0 +1324 1811 0 +1324 1813 0 +1324 1819 0 +1324 1823 0 +1324 1825 0 +1325 1808 0 +1325 1813 0 +1325 1821 0 +1325 1827 0 +1326 1806 0 +1326 1810 0 +1326 1814 0 +1326 1817 0 +1326 1819 0 +1326 1821 0 +1326 1825 0 +1326 1830 0 +1509 1544 25 +1510 1541 25 +1510 1543 25 +1510 1545 25 +1511 1542 25 +1511 1543 25 +1511 1544 25 +1514 1544 25 +1515 1541 25 +1515 1548 25 +1515 1554 25 +1517 1553 25 +1518 1542 35 +1520 1543 25 +1520 1545 25 +1522 1544 35 +1523 1431 55 +1523 1436 55 +1524 1434 55 +1524 1437 55 +1524 1544 25 +1525 1429 55 +1525 1432 55 +1525 1542 25 +1525 1544 25 +1525 1545 25 +1526 1431 55 +1526 1435 55 +1526 1436 55 +1527 1432 55 +1528 1429 55 +1528 1433 55 +1528 1437 55 +1529 1430 55 +1529 1435 55 +1530 1431 55 +1530 1436 55 +1569 1556 26 +1570 1556 26 + +# wood curls +Static 0x1038 +1388 1596 30 +1388 1599 30 +1390 1597 30 +1390 1599 30 +1390 1601 30 +1391 1596 30 +1393 1596 30 +1430 1594 20 +1430 1596 20 +1430 1598 20 +1431 1595 20 +1431 1597 20 +1432 1595 20 +1432 1597 20 +1433 1594 20 +1433 1597 20 +1434 1595 20 +1451 1579 30 +1451 1581 30 +1453 1580 30 +1454 1580 30 +1455 1579 30 + +# sack of flour +Static 0x1039 +1448 1608 20 +1450 1608 20 +1452 1615 20 +1512 1422 15 +1512 1424 21 +1513 1436 15 +1513 1437 15 +1514 1432 15 +1518 1433 15 +1549 1704 20 +1564 1742 15 +1564 1743 15 +1565 1748 15 +1568 1737 15 +1569 1736 15 +1577 1737 15 +1577 1738 15 +1578 1737 15 +1592 1517 40 + +# open sack of flour +Static 0x103A +1448 1617 20 +1449 1608 20 +1513 1422 15 +1513 1433 15 +1545 1704 20 +1560 1745 15 +1562 1739 15 +1565 1743 15 +1568 1736 15 +1576 1744 15 +1581 1740 15 +1598 1512 40 + +# dough +Static 0x103D +1248 1707 6 +1448 1610 27 + +# cookie mix +Static 0x103F +1248 1708 6 +1448 1612 27 +1518 1422 21 +1594 1512 46 + +# rolling pin +Static 0x1043 +1156 1616 6 +1192 1848 6 +1195 1704 6 +1256 1881 6 +1448 1614 26 +1517 1422 21 +1545 1680 36 +1546 1708 20 +1595 1512 46 + +# globe +Static 0x1047 +1334 1644 72 +1338 1587 72 + +# loom bench +Static 0x104A +1392 1602 30 +1545 1658 26 + +# clock +Clock 0x104B +1423 1660 16 +1423 1661 16 +1423 1662 16 + +# clock +Clock 0x104C +1426 1660 16 +1426 1661 16 +1426 1662 16 +1426 1663 16 + +# clock frame +ClockFrame 0x104D +1337 1588 76 +1384 1598 36 +1424 1651 16 +1424 1654 16 +1428 1649 16 +1428 1656 16 + +# clock parts +ClockParts 0x104F +1337 1588 76 +1384 1598 36 +1424 1655 16 +1428 1651 16 + +# clock parts +ClockParts 0x1050 +1424 1649 16 +1428 1655 16 + +# axle with gears +AxleGears 0x1051 +1424 1656 16 + +# axle with gears +AxleGears 0x1052 +1424 1649 16 +1428 1649 16 +1428 1655 16 + +# gears +Gears 0x1053 +1337 1588 76 +1424 1650 16 +1424 1656 16 +1428 1651 16 +1428 1654 16 + +# gears +Gears 0x1054 +1386 1598 36 + +# sextant parts +SextantParts 0x1059 +1424 1650 16 +1428 1656 16 + +# sextant parts +SextantParts 0x105A +1385 1598 36 +1424 1654 16 +1428 1650 16 + +# springs +Springs 0x105D +1424 1655 16 +1428 1654 16 + +# springs +Springs 0x105E +1424 1651 16 +1428 1649 16 + +# pile of hides +Static 0x1078 +1429 1609 20 + +# pile of hides +Static 0x1079 +1429 1614 20 + +# cut leather +Static 0x1082 +1432 1609 26 + +# bracelet +Static 0x1086 +1660 1643 4 + +# ring +Static 0x108A +1660 1643 4 + +# fur +Static 0x11F5 +1436 1613 26 + +# fur +Static 0x11F7 +1436 1610 26 + +# fur +Static 0x11F8 +1432 1612 26 + +# tarot +Static 0x12A6 +1494 1551 36 +1594 1650 16 + +# tarot +Static 0x12AA +1331 1603 76 + +# deck of tarot +Static 0x12AC +1331 1602 76 + +# brush +Static 0x1371 +1391 1640 36 + +# brush +Static 0x1372 +1390 1640 36 + +# bridle +Static 0x1374 +1392 1640 36 + +# short spear +Static 0x1403 +1529 1413 59 + +# halberd +Static 0x143F +1372 1578 33 + +# map +Static 0x14EB +1332 1652 54 +1339 1588 76 + +# map +Static 0x14EC +1328 1644 78 + +# ship model +Static 0x14F3 +1414 1744 16 +1414 1758 16 +1420 1744 16 +1420 1758 16 + +# spyglass +Static 0x14F5 +1328 1648 78 + +# rope +Static 0x14F8 +1467 1766 -3 +1471 1770 -3 +1490 1756 -3 +1492 1749 -3 + +# rope +Static 0x14FA +1448 1764 -3 +1449 1758 -3 +1449 1768 -3 +1474 1762 -3 +1477 1762 -3 +1481 1768 -3 +1486 1762 -3 +1493 1762 -3 +1498 1759 -3 + +# skirt +Static 0x1516 (Hue=0x386) +1444 1580 20 + +# long pants +Static 0x1539 (Hue=0x386) +1443 1578 20 + +# wooden bowl +Static 0x15F8 +1192 1848 6 +1448 1613 25 +1545 1680 36 + +# pewter bowl +Static 0x15FD +1195 1848 6 +1196 1704 6 +1248 1709 6 + +# bowl of lettuce +Static 0x1600 +1322 1605 56 + +# large pewter bowl +Static 0x1603 +1151 1544 0 +1157 1616 6 +1192 1849 6 +1248 1706 6 +1324 1600 56 +1550 1709 26 + +# large wooden bowl +Static 0x1605 +1226 1568 6 + +# pear +Static 0x172D +1378 1598 30 +1379 1601 30 +1382 1588 30 + +# folded cloth +Static 0x1763 +1467 1685 0 + +# cut cloth +Static 0x1766 +1466 1687 4 + +# cloth +Static 0x1767 +1466 1689 0 + +# silver wire +Static 0x1877 +1345 1778 21 +1345 1786 21 +1354 1770 21 + +# gold wire +Static 0x1878 +1347 1786 21 +1354 1774 21 + +# copper wire +Static 0x1879 +1346 1770 21 + +# heater shield +Static 0x1B77 +1530 1412 55 + +# feather +Static 0x1BD1 +1468 1576 26 +1468 1577 26 +1468 1581 26 +1468 1582 26 + +# shaft +Static 0x1BD4 +1468 1577 26 +1468 1580 26 +1468 1581 26 + +# skinned goat +Static 0x1E89 +1453 1725 6 + +# plucked chicken +Static 0x1E8B +1450 1726 6 + +# skinned deer +Static 0x1E91 +1453 1724 6 + +# winch +Static 0x1EA8 +1521 1454 35 + +# earrings +Static 0x1F07 +1659 1643 4 + +# pitcher of water +Pitcher 0x1F9D (Content=Water) +1193 1709 4 +1512 1425 21 \ No newline at end of file diff --git a/Data/Decoration/Britannia/bucs.cfg b/Data/Decoration/Britannia/bucs.cfg new file mode 100644 index 0000000..deda623 --- /dev/null +++ b/Data/Decoration/Britannia/bucs.cfg @@ -0,0 +1,722 @@ +# stone pavers +Static 0x051E +2669 2071 -20 + +# stone pavers +Static 0x051F +2669 2072 -20 + +# stone pavers +Static 0x0520 +2669 2073 -20 + +# stone +Static 0x071E +2726 2133 0 +2727 2131 0 +2727 2131 5 +2727 2131 10 +2727 2131 15 +2727 2131 20 +2727 2131 25 +2727 2132 0 +2727 2132 30 +2727 2133 0 +2727 2133 30 +2727 2133 35 +2727 2134 0 +2727 2134 30 +2727 2135 0 +2727 2135 5 +2727 2135 10 +2727 2135 15 +2727 2135 20 +2727 2135 25 +2728 2133 0 + +# stone stairs +Static 0x071F +2727 2134 35 +2727 2135 30 + +# stone stairs +Static 0x0737 +2727 2131 30 +2727 2132 35 + +# stone stairs +Static 0x07A0 +2726 2132 0 + +# stone stairs +Static 0x07A1 +2728 2134 0 + +# stone stairs +Static 0x07A2 +2728 2132 0 + +# stone stairs +Static 0x07DA +2726 2134 0 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +2659 2187 8 +2660 2203 8 +2666 2234 8 +2668 2235 8 +2668 2236 8 +2673 2233 4 +2675 2238 4 +2684 2233 4 + +# bottles of ale +Static 0x09A0 +2666 2236 8 + +# metal box +FillableMetalBox 0x09A8 +2730 2185 6 + +# metal chest +MetalChest 0x09AB +2662 2250 -20 + +# metal chest +FillableMetalChest 0x09AB +2648 2192 4 +2649 2192 4 +2650 2192 4 +2718 2080 0 +2719 2080 20 + +# silverware +Static 0x09BD +2757 2219 6 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +2659 2201 8 +2660 2186 8 + +# silverware +Static 0x09D4 +2748 2113 4 + +# pitcher +Static 0x09D6 +2668 2129 4 +2692 2200 4 + +# plate +Plate 0x09D7 +2757 2219 6 + +# plate of food +Static 0x09DB +2748 2113 4 + +# mug of ale +GlassMug 0x09EE (Content=Ale) +2679 2233 4 + +# wall sconce +WallSconce 0x09FD (Light=WestBig) +2681 2245 16 + +# wall sconce +WallSconce 0x0A02 (Light=NorthBig) +2683 2241 16 +2678 2241 16 + +# wall torch +WallTorch 0x0A07 (Light=WestBig) +2728 2187 16 + +# wall torch +Static 0x0A0C (Light=NorthBig) +2729 2184 16 + +# candle +Candle 0x0A0F +2691 2200 4 + +# lantern +Lantern 0x0A18 (Unlit) +2744 2253 10 + +# hanging lantern +HangingLantern 0x0A1A +2717 2104 9 +2721 2085 0 +2721 2086 0 +2722 2086 0 +2736 2158 18 + +# hanging lantern +Static 0x0A1D +2736 2174 20 + +# lantern post +Static 0x0A20 +2735 2157 -1 +2735 2173 0 + +# candle +CandleLarge 0x0A26 (Unlit) +2632 2086 14 + +# stool +Stool 0x0A2A +2669 2076 5 +2709 2178 0 +2713 2086 0 +2723 2085 0 +2726 2086 0 +2730 2260 0 +2730 2261 0 +2731 2259 0 +2731 2262 0 +2732 2259 0 +2732 2262 0 +2733 2260 0 +2733 2261 0 + +# stool +Static 0x0A2B +2637 2080 10 +2638 2081 10 +2638 2082 10 + +# chest of drawers +Drawer 0x0A2C +2676 2152 0 + +# chest of drawers +Drawer 0x0A34 +2664 2131 0 +2744 2115 0 +2776 2132 0 + +# armoire +Armoire 0x0A53 +2624 2099 10 +2712 2084 0 +2720 2084 0 + +# bedroll +Static 0x0A55 +2689 2201 0 +2715 2209 0 + +# bedroll +Static 0x0A56 +2694 2201 0 +2718 2209 0 + +# bedroll +Static 0x0A57 +2718 2209 0 + +# bedroll +Static 0x0A58 +2689 2201 0 +2715 2209 0 + +# bed +Static 0x0A5C +2752 2217 0 + +# bed +Static 0x0A63 +2752 2216 0 + +# folded sheet +Static 0x0A92 +2632 2080 12 +2704 2146 2 +2704 2149 2 +2709 2132 2 +2726 2089 2 +2729 2260 -3 +2744 2112 2 + +# display case +Static 0x0AA0 +2733 2249 4 +2734 2249 4 +2739 2249 4 + +# display case +Static 0x0AA2 +2733 2248 4 +2734 2248 4 +2739 2248 4 + +# display case +Static 0x0AA3 +2732 2248 4 +2738 2248 4 + +# display case +Static 0x0AA4 +2735 2248 4 +2740 2248 4 + +# display case +Static 0x0AA5 +2732 2249 4 +2738 2249 4 + +# display case +Static 0x0B10 +2732 2248 0 +2738 2248 0 + +# display case +Static 0x0B11 +2735 2249 0 +2740 2249 0 + +# display case +Static 0x0B12 +2732 2249 0 +2738 2249 0 + +# display case +Static 0x0B13 +2735 2248 0 +2740 2248 0 + +# display case +Static 0x0B15 +2733 2249 0 +2734 2249 0 +2739 2249 0 + +# display case +Static 0x0B17 +2733 2248 0 +2734 2248 0 +2739 2248 0 + +# display case +Static 0x0B18 +2735 2249 4 +2740 2249 4 + +# candle +CandleLarge 0x0B1A +2672 2153 8 +2672 2156 6 +2728 2259 8 + +# candle +CandleLarge 0x0B1B +2634 2080 18 +2712 2212 7 +2732 2185 6 + +# counter +Static 0x0B3E +2731 2185 0 + +# counter +Static 0x0B3F +2728 2258 0 +2728 2259 0 +2730 2184 0 +2731 2260 0 +2731 2261 0 +2732 2260 0 +2732 2261 0 + +# counter +Static 0x0B40 +2730 2185 0 +2732 2185 0 + +# chair +FancyWoodenChairCushion 0x0B4E +2658 2187 4 +2658 2201 4 +2658 2203 4 +2712 2097 0 +2712 2101 0 +2720 2092 0 +2720 2093 0 + +# chair +FancyWoodenChairCushion 0x0B4F +2660 2185 4 +2713 2096 0 +2715 2080 0 +2715 2089 0 +2715 2096 0 +2724 2080 0 + +# chair +FancyWoodenChairCushion 0x0B50 +2660 2189 4 + +# chair +FancyWoodenChairCushion 0x0B51 +2661 2187 4 +2661 2201 4 +2661 2203 4 + +# chair +WoodenChair 0x0B56 +2624 2097 10 +2728 2251 0 + +# chair +WoodenChair 0x0B57 +2629 2096 10 +2730 2248 0 + +# chair +WoodenChair 0x0B59 +2748 2114 0 + +# chair +BambooChair 0x0B5A +2665 2235 2 +2672 2238 4 +2756 2219 0 +2779 2132 0 + +# chair +BambooChair 0x0B5B +2667 2128 0 +2667 2233 2 +2669 2128 0 +2674 2232 4 +2674 2237 2 +2679 2232 4 +2684 2232 4 +2712 2210 0 +2757 2218 0 + +# chair +BambooChair 0x0B5C +2667 2237 2 +2674 2239 4 +2712 2213 0 + +# chair +BambooChair 0x0B5D +2669 2235 2 +2781 2131 0 +2781 2133 0 + +# foot stool +FootStool 0x0B5E +2691 2201 0 +2692 2201 0 + +# bench +Static 0x0B60 +2728 2188 0 + +# bench +Static 0x0B65 +2755 2216 0 + +# table +Static 0x0B70 +2659 2188 4 +2659 2204 4 + +# table +Static 0x0B71 +2660 2188 4 +2660 2204 4 + +# table +Static 0x0B72 +2660 2186 4 +2660 2200 4 + +# table +Static 0x0B73 +2659 2186 4 +2659 2187 4 +2659 2200 4 +2659 2201 4 +2659 2202 4 +2659 2203 4 +2660 2187 4 +2660 2201 4 +2660 2202 4 +2660 2203 4 + +# wooden signpost +Static 0x0B97 +2632 2099 10 +2632 2102 10 +2664 2192 4 +2688 2234 4 +2688 2237 4 + +# wooden signpost +Static 0xB98 +2732 2192 0 +2666 2096 5 + +# broken chair +Static 0x0C11 +2627 2097 16 + +# bloody bandage +Static 0x0E20 +2704 2136 6 + +# crate +FillableLargeCrate 0x0E3D +2675 2241 2 +2676 2241 2 +2676 2245 2 +2677 2241 2 +2677 2245 2 + +# metal chest +FillableMetalGoldenChest 0x0E40 +2672 2243 2 + +# wooden chest +WoodenChest 0x0E42 +2712 2209 0 +2752 2221 0 + +# wooden chest +FillableWoodenChest 0x0E42 +2728 2187 0 + +# wooden chest +WoodenChest 0x0E43 +2677 2158 0 +2678 2157 0 + +# wooden chest +FillableWoodenChest 0x0E43 +2733 2184 0 +2734 2184 0 + +# barrel +Barrel 0x0E77 +2675 2245 -20 +2676 2244 -20 +2676 2245 -20 +2692 2205 0 +2693 2204 0 +2693 2205 0 +2746 2112 0 +2664 2133 0 + +# barrel +FillableBarrel 0x0E77 +2637 2084 10 +2637 2085 10 +2672 2245 2 +2673 2245 2 + +# metal chest +MetalChest 0x0E7C +2664 2134 0 +2744 2117 0 + +# clean bandage +Static 0x0EE9 +2704 2145 8 +2709 2136 6 +2710 2145 8 + +# playing cards +Static 0x0FA2 +2660 2202 8 +2667 2236 8 + +# playing cards +Static 0x0FA3 +2660 2187 8 +2668 2235 8 + +# checkers +Static 0x0FA4 +2674 2233 7 + +# checkers +Static 0x0FA5 +2674 2233 7 + +# checker board +CheckerBoard 0x0FA6 +2674 2233 6 + +# dice and cup +Dices 0x0FA7 +2678 2233 2 +2680 2233 4 + +# backgammon game +Backgammon 0x0FAD +2674 2238 6 + +# barrel +Static 0x0FAE +2633 2091 10 +2749 2164 -3 +2753 2164 -3 +2753 2169 -3 + +# anvil +AnvilEastAddon 0x0FAF +2634 2091 10 + +# forge +SmallForgeAddon 0x0FB1 +2634 2089 10 + +# sledge hammer +Static 0x0FB4 +2634 2090 10 + +# sledge hammer +Static 0x0FB5 +2636 2083 10 + +# tongs +Static 0x0FBB +2636 2083 11 + +# book +Static 0x0FBD +2632 2085 14 +2665 2090 11 +2714 2097 1 + +# book +Static 0x0FBE +2733 2248 2 + +# pen and ink +Static 0x0FBF +2734 2248 4 + +# pen and ink +Static 0x0FC0 +2666 2090 11 +2709 2177 6 +2715 2097 4 + +# chisels +Static 0x1027 +2627 2097 16 + +# moulding planes +Static 0x102D +2627 2096 16 + +# nails +Static 0x102F +2626 2097 16 + +# jointing plane +Static 0x1030 +2626 2097 16 + +# smoothing plane +Static 0x1033 +2627 2097 16 + +# saw +Static 0x1034 +2627 2097 16 + +# globe +Static 0x1047 +2728 2260 0 + +# clock frame +Static 0x104D +2627 2096 16 + +# axle +Axle 0x105B +2626 2096 16 +2627 2097 16 + +# cut leather +Static 0x1067 +2704 2177 0 +2705 2176 0 + +# pile of hides +Static 0x1078 +2706 2177 0 + +# pile of hides +Static 0x1079 +2705 2178 0 + +# hanging pole +Static 0x10AC +2718 2082 0 + +# hanging pole +Static 0x10AD +2718 2081 0 + +# hanging pole +Static 0x10AE +2718 2080 0 + +# flowerpot +PottedPlant1 0x11CB +2667 2072 11 + +# log table +Static 0x11DF +2632 2086 10 +2672 2157 0 + +# map +Static 0x14EC +2728 2258 6 + +# rope +Static 0x14FA +2744 2169 -3 +2749 2177 -3 +2752 2160 -3 +2752 2173 -3 +2758 2166 -3 + +# lockpick +Static 0x14FC +2732 2260 6 +2732 2261 6 + +# lockpicks +Static 0x14FE +2731 2261 6 + +# water barrel +Static 0x154D +2672 2244 2 +2741 2169 -3 +2749 2171 -3 + +# ore +Static 0x19B9 +2637 2082 16 + +# glass +GlassMug 0x1F81 +2679 2233 4 + +# glass of water +GlassMug 0x1F91 (Content=Water) +2679 2233 4 \ No newline at end of file diff --git a/Data/Decoration/Britannia/bucsportal.cfg b/Data/Decoration/Britannia/bucsportal.cfg new file mode 100644 index 0000000..9c180dc --- /dev/null +++ b/Data/Decoration/Britannia/bucsportal.cfg @@ -0,0 +1,137 @@ +############### +# Teleporters # +############### + +Teleporter 0x1BC3 (PointDest=(2727, 2133, 5)) +2618 977 5 + +Teleporter 0x1BC3 (PointDest=(2618, 977, 5)) +2727 2133 5 + + +############# +# Buc's Den # +############# + +# sign +Static 0xBD0 (Name=to the Mainland) +2728 2133 25 + +# stone +Static 0x071E +2726 2133 0 +2727 2131 0 +2727 2131 5 +2727 2131 10 +2727 2131 15 +2727 2131 20 +2727 2131 25 +2727 2132 0 +2727 2132 30 +2727 2133 0 +2727 2133 30 +2727 2133 35 +2727 2134 0 +2727 2134 30 +2727 2135 0 +2727 2135 5 +2727 2135 10 +2727 2135 15 +2727 2135 20 +2727 2135 25 +2728 2133 0 + +# stone stairs +Static 0x071F +2727 2134 35 +2727 2135 30 + +# stone stairs +Static 0x0737 +2727 2131 30 +2727 2132 35 + +# stone stairs +Static 0x07A0 +2726 2132 0 + +# stone stairs +Static 0x07A1 +2728 2134 0 + +# stone stairs +Static 0x07A2 +2728 2132 0 + +# stone stairs +Static 0x07DA +2726 2134 0 + + +############ +# Mainland # +############ + +# sign +Static 0xBCF (Name=to Buccaneer's Den) +2618 978 25 + +# stone +Static 0x07A3 +2616 977 0 +2616 977 5 +2616 977 10 +2616 977 15 +2616 977 20 +2616 977 25 +2617 977 0 +2617 977 30 +2618 977 0 +2618 977 30 +2618 977 35 +2619 977 0 +2619 977 30 +2620 977 0 +2620 977 5 +2620 977 10 +2620 977 15 +2620 977 20 +2620 977 25 + +# stone stairs +Static 0x07A4 +2617 978 0 +2618 978 0 +2619 978 0 + +# stone stairs +Static 0x07A5 +2619 977 35 +2620 977 30 + +# stone stairs +Static 0x07A6 +2617 976 0 +2618 976 0 +2619 976 0 + +# stone stairs +Static 0x07A7 +2616 977 30 +2617 977 35 + +# stone stairs +Static 0x07A8 +2616 976 0 + +# stone stairs +Static 0x07A9 +2620 978 0 + +# stone stairs +Static 0x07AA +2620 976 0 + +# stone stairs +Static 0x07AB +2616 978 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/cove.cfg b/Data/Decoration/Britannia/cove.cfg new file mode 100644 index 0000000..93a8161 --- /dev/null +++ b/Data/Decoration/Britannia/cove.cfg @@ -0,0 +1,317 @@ +# tent wall +Static 0x02EB (Hue=0x33) +2333 1220 0 +2337 1229 0 +2342 1214 0 +2346 1220 0 + +# tent wall +Static 0x02EC (Hue=0x33) +2334 1219 0 +2338 1228 0 +2343 1213 0 +2347 1219 0 + +# gruesome standard +Static 0x041F +2338 1214 0 + +# gruesome standard +Static 0x0420 +2347 1217 0 + +# gruesome standard +Static 0x0428 +2329 1221 0 + +# cauldron +Static 0x0974 +2337 1221 0 + +# tray +Static 0x0992 +2227 1218 6 +2236 1187 6 +2244 1203 6 +2259 1217 6 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +2228 1218 6 + +# fork +Fork 0x09A3 +2227 1217 6 + +# fork +Fork 0x09A4 +2237 1187 6 +2245 1203 6 +2260 1217 6 + +# knife +Knife 0x09A5 +2227 1217 6 + +# knife +Knife 0x09A6 +2237 1187 6 +2245 1203 6 +2260 1217 6 + +# metal box +FillableMetalBox 0x09A8 +2213 1165 6 + +# spoon +Spoon 0x09C2 +2227 1217 6 + +# spoon +Spoon 0x09C3 +2237 1187 7 +2245 1203 7 +2260 1217 7 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +2238 1188 6 +2246 1204 6 +2261 1218 6 + +# plate +Plate 0x09D7 +2227 1217 6 +2228 1217 6 +2237 1187 6 +2237 1188 6 +2245 1203 6 +2245 1204 6 +2260 1217 6 +2260 1218 6 + +# fork +Fork 0x09F4 +2237 1188 6 +2245 1204 6 +2260 1218 6 + +# fork +Fork 0x09F5 +2228 1217 6 + +# knife +Knife 0x09F6 +2237 1188 6 +2245 1204 6 +2260 1218 6 + +# knife +Knife 0x09F7 +2228 1217 6 + +# spoon +Spoon 0x09F8 +2237 1188 6 +2245 1204 6 +2260 1218 6 + +# spoon +Spoon 0x09F9 +2228 1217 6 + +# candle +CandleLarge 0x0A26 (Unlit) +2228 1216 6 + +# candle +CandleLarge 0x0B1A +2212 1116 26 +2212 1116 46 +2213 1164 6 +2213 1168 6 +2215 1191 6 +2217 1195 6 +2236 1188 6 +2243 1228 6 +2243 1231 6 +2244 1204 6 +2259 1218 6 +2275 1198 6 +2276 1200 26 +2283 1226 6 +2284 1228 26 + +# chair +WoodenChair 0x0B56 +2211 1115 20 +2212 1166 0 +2242 1229 0 +2275 1199 20 +2283 1227 20 + +# chair +WoodenChair 0x0B57 +2276 1197 0 +2284 1225 0 + +# chair +WoodenChair 0x0B58 +2213 1115 40 + +# chair +BambooChair 0x0B5A +2226 1217 0 + +# chair +BambooChair 0x0B5B +2237 1186 0 +2245 1202 0 +2260 1216 0 + +# chair +BambooChair 0x0B5C +2214 1192 0 +2237 1189 0 +2245 1205 0 +2260 1219 0 + +# chair +BambooChair 0x0B5D +2229 1217 0 + +# campfire +Static 0x0DE3 (Light=Circle225) +2337 1221 0 + +# crate +FillableLargeCrate 0x0E3C +2252 1190 -2 +2252 1190 1 + +# crate +MediumCrate 0x0E3E +2252 1190 4 +2253 1190 -2 + +# stump +Static 0x0E59 +2330 1220 0 + +# barrel +FillableBarrel 0x0E77 +2251 1189 -2 +2251 1189 3 +2251 1190 -2 +2252 1189 -2 +2259 1188 -2 +2259 1188 3 +2259 1189 -2 +2259 1189 3 +2259 1190 -2 +2260 1188 -2 +2260 1188 3 +2260 1189 -2 +2260 1189 3 +2260 1190 -2 + +# strong box +FillableMetalBox 0x0E80 +2212 1191 6 +2240 1231 6 + +# cleaver +Static 0x0EC3 +2217 1196 6 + +# skinning knife +Static 0x0EC5 +2212 1196 6 + +# executioner's axe +Static 0x0F46 +2331 1219 0s + +# fire pit +Static 0x0FAC (Light=Circle225) +2337 1221 0 + +# book +Static 0x0FBD +2212 1115 26 +2212 1115 46 +2213 1166 6 +2243 1229 6 +2276 1199 26 +2284 1227 26 + +# book +Static 0x0FBE +2214 1191 6 +2276 1198 6 +2284 1226 6 + +# pen and ink +Static 0x0FBF +2213 1166 6 +2243 1229 6 + +# pen and ink +Static 0x0FC0 +2213 1191 6 + +# glass pitcher +Pitcher 0x0FF6 +2261 1217 6 + +# garbage +Static 0x10EE +2332 1221 0 +2333 1223 0 +2336 1221 1 +2336 1222 0 +2338 1214 0 +2338 1218 0 +2338 1224 0 +2339 1221 2 +2340 1220 0 +2340 1224 0 + +# butcher knife +Static 0x13F7 +2212 1195 6 + +# rope +Static 0x14FA +2252 1191 -2 + +# water barrel +Static 0x154D +2281 1183 0 + +# skinned goat +Static 0x1E88 +2329 1225 3 + +# skinned goat +Static 0x1E89 +2337 1223 0 + +# skinned deer +Static 0x1E90 +2342 1221 0 + +# skinned deer +Static 0x1E91 +2338 1219 0 +2339 1219 0 + +# pitcher of water +Pitcher 0x1F9D (Content=Water) +2238 1187 6 +2246 1203 6 +2261 1217 6 + +# pitcher of water +Pitcher 0x1F9E (Content=Water) +2227 1216 6 diff --git a/Data/Decoration/Britannia/delucia.cfg b/Data/Decoration/Britannia/delucia.cfg new file mode 100644 index 0000000..8c87ad8 --- /dev/null +++ b/Data/Decoration/Britannia/delucia.cfg @@ -0,0 +1,229 @@ +# oven +Static 0x0461 +5195 4058 37 + +# oven +Static 0x0462 (Light=WestBig) +5195 4057 37 + +# fireplace +SandstoneFireplaceSouthAddon 0x047B +5198 4054 37 +5234 4014 37 +5265 3977 41 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +5233 4027 37 +5293 4003 40 +5272 3987 37 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +5273 3987 37 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +5295 3998 40 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +5295 3997 40 + +# wooden door +StrongWoodDoor 0x06F1 (Facing=SouthCCW) +5290 4008 40 + +# wooden door +StrongWoodDoor 0x06F3 (Facing=NorthCW) +5290 4007 40 + +# wooden fence +Static 0x0863 +5251 4021 39 +5252 4021 40 +5253 4002 46 +5253 4021 40 +5254 4002 46 +5254 4021 40 +5255 4021 38 + +# wooden fence +Static 0x0864 +5250 4015 40 +5250 4016 39 +5250 4017 40 +5250 4018 41 +5250 4019 39 +5250 4020 39 +5250 4021 39 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +5287 4015 40 +5297 4003 40 +5301 4003 40 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +5288 4015 40 +5298 4003 40 +5302 4003 40 + +# wooden gate +DarkWoodGate 0x086A (Facing=WestCCW) +5292 4012 40 +5297 4006 40 +5297 4012 40 +5301 4006 40 +5301 4012 40 + +# wooden gate +DarkWoodGate 0x086C (Facing=EastCW) +5293 4012 40 +5298 4006 40 +5298 4012 40 +5302 4006 40 +5302 4012 40 + +# wooden fence +Static 0x088A +5251 4014 39 +5256 4021 38 +5257 4021 38 + +# wooden fence +Static 0x088B +5251 4006 45 +5251 4007 45 +5279 4009 38 +5279 4010 39 + +# cauldron +Static 0x0975 +5195 3996 37 +5293 3986 37 + +# hanging lantern +HangingLantern 0x0A1A +5179 4070 40 + +# chest of drawers +FancyDrawer 0x0A30 +5199 4061 57 + +# chest of drawers +Drawer 0x0A34 +5195 4066 57 + +# armoire +FancyArmoire 0x0A4D +5202 4061 57 + +# armoire +Armoire 0x0A53 +5195 4067 57 + +# bookcase +LibraryBookcase 0x0A9B +5215 4007 37 + +# crate +FillableLargeCrate 0x0E3D +5236 4021 37 +5236 4021 40 +5236 4022 37 +5236 4022 40 +5236 4023 37 +5237 4020 57 +5237 4021 57 +5237 4022 57 +5237 4023 57 + +# wooden chest +WoodenChest 0x0E42 +5262 3980 38 +5262 3982 38 +5269 3977 37 +5269 3986 36 + +# wooden chest +WoodenChest 0x0E43 +5270 3971 37 +5276 3971 37 + +# pouch +Static 0x0E79 +5262 3984 42 + +# water tub +Static 0x0E7B +5296 4013 40 + +# empty tub +Static 0x0E83 +5291 4009 40 +5291 4010 40 +5296 4007 40 + +# pickaxe +Static 0x0E85 +5230 4021 43 +5288 3979 37 + +# pitchfork +Static 0x0E87 +5287 3979 37 + +# fire pit +Static 0x0FAC (Light=Circle225) +5195 3996 37 +5285 3980 37 +5293 3986 37 +5295 3977 37 + +# barrel +Static 0x0FAE +5230 4024 37 +5230 4025 37 +5291 4004 40 +5291 4005 40 +5291 4006 40 + +# anvil +AnvilSouthAddon 0x0FB0 +5228 4003 37 +5228 4005 37 +5235 4004 38 +5235 4006 37 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +5235 4016 37 + +# upright loom +LoomEastAddon 0x1060 +5231 4015 37 + +# bellows +Static 0x197B +5226 4004 37 +5234 4005 37 + +# forge +Static 0x197E (Light=Circle300) +5227 4004 37 +5235 4005 37 + +# bellows +Static 0x199E +5229 4004 37 +5237 4005 37 + +# forge +Static 0x19A3 +5236 4005 37 + +# forge +Static 0x19A4 +5228 4004 37 \ No newline at end of file diff --git a/Data/Decoration/Britannia/despise.cfg b/Data/Decoration/Britannia/despise.cfg new file mode 100644 index 0000000..71405ba --- /dev/null +++ b/Data/Decoration/Britannia/despise.cfg @@ -0,0 +1,17 @@ +# stone stairs +Static 0x78A +5572 628 45 +5572 629 45 +5572 630 45 +5505 570 39 + +# stone stairs +Static 0x78C +5571 633 10 +5523 673 35 +5385 756 -15 +5411 859 60 + +# stone +Static 0x788 +5507 568 54 \ No newline at end of file diff --git a/Data/Decoration/Britannia/destard.cfg b/Data/Decoration/Britannia/destard.cfg new file mode 100644 index 0000000..76385f3 --- /dev/null +++ b/Data/Decoration/Britannia/destard.cfg @@ -0,0 +1,3 @@ +# ankh +AnkhNorth 0x0004 +5204 774 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/hythloth.cfg b/Data/Decoration/Britannia/hythloth.cfg new file mode 100644 index 0000000..6eebb2d --- /dev/null +++ b/Data/Decoration/Britannia/hythloth.cfg @@ -0,0 +1,20 @@ +# stone stairs +Static 0x7A5 +6081 144 -12 +6081 145 -12 +6081 146 -12 +6080 144 -7 +6080 145 -7 +6080 146 -7 +6057 88 32 +6057 89 32 +6057 90 32 +6056 88 37 +6056 89 37 +6056 90 37 +6041 192 5 +6041 193 5 +6041 194 5 +6042 192 0 +6042 193 0 +6042 194 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/jhelom.cfg b/Data/Decoration/Britannia/jhelom.cfg new file mode 100644 index 0000000..4e68ca8 --- /dev/null +++ b/Data/Decoration/Britannia/jhelom.cfg @@ -0,0 +1,2769 @@ +# portcullis +Static 0x06F5 +1352 3869 20 +1353 3869 20 +1354 3869 20 +1355 3869 20 +1391 3869 20 +1388 3869 20 +1390 3869 20 +1389 3869 20 + +# chimney +Static 0x08D8 +1441 3782 30 + +# chimney +Static 0x08D9 +1441 3781 30 + +# oven +StoneOvenEastAddon 0x092C +1352 3731 0 +1441 3781 0 + +# fireplace +Static 0x0951 +1168 3636 0 + +# fireplace +Static 0x0952 +1168 3635 0 + +# fireplace +StoneFireplaceSouthAddon 0x0961 +1128 3608 0 + +# tray +Static 0x0991 +1130 3611 6 +1139 3658 6 + +# tray +Static 0x0992 +1172 3638 4 + +# fruit basket +FruitBasket 0x0993 +1384 3824 4 +1391 3824 0 +1422 3745 26 +1379 3750 26 +1419 3758 26 +1380 3728 26 +1422 3746 26 +1380 3750 26 + +# ceramic mug +CeramicMug 0x0997 +1458 3801 6 +1332 3728 6 +1332 3749 6 +1314 3749 6 +1332 3750 6 +1458 3825 6 +1392 3700 6 +1311 3749 6 +1408 3804 6 +1310 3749 6 +1316 3749 6 +1316 3729 6 +1332 3729 6 +1408 3853 6 +1404 4035 6 +1344 3755 6 +1395 4010 6 +1316 3728 6 +1451 3718 6 +1432 3963 6 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +1458 3801 6 +1460 3826 6 +1408 3804 6 +1418 3776 6 +1486 3849 6 +1332 3754 6 +1403 4035 6 +1432 3963 6 +1427 3960 6 +1344 3755 6 +1442 3848 6 +1332 3722 6 +1392 4020 6 +1340 3708 6 +1450 3718 9 +1452 4008 6 +1458 3825 6 +1458 3802 6 +1395 4010 6 +1397 4038 6 +1316 3724 6 + +# fork +Fork 0x09A3 +1460 3781 6 +1456 3781 6 +1403 4036 6 +1486 3850 6 +1444 3769 6 +1448 3769 6 + +# fork +Fork 0x09A4 +1459 3801 6 +1135 3658 4 +1316 3727 6 +1316 3749 6 +1451 3718 6 +1316 3724 6 +1314 3749 6 +1443 3776 6 +1309 3749 6 +1441 3776 6 +1171 3637 4 +1311 3749 6 +1459 3825 6 +1316 3729 6 +1133 3610 4 + +# knife +Knife 0x09A5 +1403 4036 6 +1460 3781 6 +1456 3781 6 +1444 3769 6 +1448 3769 6 +1486 3850 6 + +# knife +Knife 0x09A6 +1311 3749 6 +1135 3658 4 +1443 3776 6 +1459 3801 6 +1441 3776 6 +1316 3749 6 +1451 3718 6 +1309 3749 6 +1133 3610 4 +1459 3825 6 +1171 3637 4 +1314 3749 6 + +# metal box +FillableMetalBox 0x09A8 +1422 3976 8 +1452 3849 6 +1359 3782 6 +1453 4024 6 +1452 4000 6 +1481 3856 6 +1433 3743 6 + +# metal chest +MetalChest 0x09AB +1313 3768 0 +1314 3768 0 + +# bushel +Basket 0x09AC +1397 3824 0 +1384 3825 5 +1384 3828 0 +1384 3826 5 + +# basket +Basket 0x09B1 +1388 3826 6 +1385 3827 6 + +# backpack +Backpack 0x09B2 +1434 3793 3 + +# sausage +Static 0x09C1 +1448 4028 6 + +# spoon +Spoon 0x09C3 +1171 3637 4 +1133 3610 4 +1135 3658 4 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +1448 3771 4 +1440 3768 6 +1444 3768 6 +1179 3638 9 +1440 3770 6 +1446 3779 6 +1442 3776 6 + +# jug of cider +Jug 0x09C8 (Content=Cider) +1460 3779 4 +1315 3749 6 +1170 3637 4 +1452 3778 4 +1132 3610 4 +1408 3851 6 +1456 3780 4 + +# ceramic mug +CeramicMug 0x09CA +1308 3692 6 +1442 3848 6 +1310 3708 6 +1336 3708 6 +1330 3676 6 +1334 3708 6 +1486 3849 6 +1403 4035 6 +1339 3692 6 +1309 3692 6 +1315 3708 6 +1427 3960 6 +1338 3708 6 +1458 3802 6 +1340 3692 6 +1328 3676 6 +1454 4008 6 +1308 3708 6 +1335 3692 6 +1392 4020 6 +1313 3692 6 +1331 3676 6 +1313 3708 6 +1314 3692 6 +1458 3826 6 +1327 3676 6 +1336 3692 6 +1418 3776 6 + +# pitcher +Static 0x09D6 +1309 3692 6 +1339 3708 6 +1331 3676 6 +1309 3708 6 +1332 3749 6 +1316 3728 6 +1313 3692 6 +1314 3708 6 +1335 3708 6 +1332 3728 6 +1335 3692 6 +1339 3692 6 +1327 3676 6 +1310 3749 6 + +# plate +Plate 0x09D7 +1456 3781 6 +1393 4020 6 +1340 3692 6 +1404 4036 6 +1315 3708 6 +1451 3718 6 +1459 3826 6 +1408 3852 6 +1312 3692 6 +1448 3769 6 +1326 3676 6 +1443 3848 6 +1330 3676 6 +1344 3756 6 +1446 3777 6 +1345 3782 6 +1316 3727 6 +1332 3748 6 +1340 3708 6 +1460 3781 6 +1332 3754 6 +1419 3776 6 +1332 3722 6 +1334 3708 6 +1453 4008 6 +1443 3776 6 +1314 3692 6 +1313 3708 6 +1332 3729 6 +1459 3825 6 +1316 3724 6 +1316 3729 6 +1338 3692 6 +1441 3776 6 +1336 3692 6 +1328 3676 6 +1334 3692 6 +1133 3611 4 +1308 3692 6 +1310 3708 6 +1428 3960 6 +1459 3802 6 +1332 3727 6 +1171 3637 4 +1456 3779 4 +1133 3610 4 +1311 3749 6 +1316 3749 6 +1440 3771 4 +1135 3659 4 +1310 3692 6 +1309 3749 6 +1314 3749 6 +1332 3676 6 +1448 3770 4 +1408 3805 6 +1392 3699 6 +1403 4036 6 +1338 3708 6 +1336 3708 6 +1452 3780 4 +1332 3750 6 +1135 3658 4 +1486 3850 6 +1432 3964 6 +1171 3638 4 +1444 3769 6 +1459 3801 6 +1308 3708 6 +1395 4009 6 + +# pot +Static 0x09E4 +1130 3608 6 + +# kettle +Static 0x09ED +1355 3734 6 +1169 3632 6 +1126 3609 0 + +# fork +Fork 0x09F4 +1171 3638 4 +1443 3848 6 +1340 3708 6 +1340 3692 6 +1332 3676 6 +1135 3659 4 +1393 4020 6 +1459 3802 6 +1334 3692 6 +1310 3708 6 +1310 3692 6 +1459 3826 6 +1312 3692 6 +1315 3708 6 +1330 3676 6 +1336 3692 6 +1328 3676 6 +1336 3708 6 +1326 3676 6 +1313 3708 6 +1314 3692 6 +1338 3692 6 +1308 3708 6 +1133 3611 4 +1453 4008 6 +1308 3692 6 +1428 3960 6 +1338 3708 6 +1419 3776 6 +1334 3708 6 + +# fork +Fork 0x09F5 +1395 4009 6 +1456 3779 4 +1332 3748 6 +1408 3852 6 +1440 3771 4 +1332 3729 6 +1446 3777 6 +1332 3754 6 +1432 3964 6 +1332 3727 6 +1408 3805 6 +1392 3699 6 +1448 3770 4 +1452 3780 4 +1332 3750 6 +1404 4036 6 +1344 3756 6 +1332 3722 6 + +# knife +Knife 0x09F6 +1133 3611 4 +1312 3692 6 +1313 3708 6 +1135 3659 4 +1328 3676 6 +1459 3826 6 +1326 3676 6 +1459 3802 6 +1334 3692 6 +1419 3776 6 +1310 3708 6 +1330 3676 6 +1338 3708 6 +1315 3708 6 +1336 3692 6 +1336 3708 6 +1338 3692 6 +1393 4020 6 +1314 3692 6 +1334 3708 6 +1340 3692 6 +1308 3692 6 +1171 3638 4 +1453 4008 6 +1340 3708 6 +1428 3960 6 +1443 3848 6 +1332 3676 6 +1310 3692 6 +1308 3708 6 + +# knife +Knife 0x09F7 +1452 3780 4 +1395 4009 6 +1332 3729 6 +1332 3750 6 +1316 3729 6 +1408 3852 6 +1408 3805 6 +1404 4036 6 +1332 3722 6 +1440 3771 4 +1344 3756 6 +1332 3727 6 +1456 3779 4 +1332 3754 6 +1446 3777 6 +1392 3699 6 +1448 3770 4 +1432 3964 6 +1332 3748 6 +1316 3724 6 +1316 3727 6 + +# spoon +Spoon 0x09F8 +1332 3676 6 +1443 3848 6 +1310 3692 6 +1308 3708 6 +1340 3708 6 +1171 3638 4 +1453 4008 6 +1308 3692 6 +1340 3692 6 +1334 3708 6 +1336 3708 6 +1338 3692 6 +1336 3692 6 +1314 3692 6 +1313 3708 6 +1312 3692 6 +1310 3708 6 +1459 3826 6 +1330 3676 6 +1459 3802 6 +1328 3676 6 +1334 3692 6 +1135 3659 4 +1428 3960 6 +1338 3708 6 +1326 3676 6 +1393 4020 6 +1419 3776 6 +1315 3708 6 +1133 3611 4 + +# spoon +Spoon 0x09F9 +1408 3853 6 +1332 3750 6 +1316 3727 6 +1395 4009 6 +1344 3756 6 +1316 3729 6 +1432 3964 6 +1332 3754 6 +1316 3724 6 +1332 3722 6 +1392 3699 6 +1404 4036 6 +1332 3729 6 +1332 3748 6 +1408 3805 6 +1332 3727 6 + +# bowl of flour +Static 0x0A1E +1354 3734 6 + +# chest of drawers +Drawer 0x0A2C +1355 3800 0 +1328 3688 0 +1460 3768 0 +1354 3805 0 +1321 3672 0 +1363 3820 0 +1422 3776 0 +1413 3800 0 +1324 3672 0 +1337 3688 0 +1328 3672 0 +1393 3696 0 +1355 3820 0 +1309 3744 0 +1365 3800 0 +1365 3810 0 +1313 3688 0 +1355 3810 0 +1182 3632 0 +1306 3744 0 +1397 4032 0 +1354 3815 0 +1394 4032 0 +1363 3805 0 +1313 3704 0 +1349 3776 0 +1331 3688 0 +1305 3688 0 +1349 3752 0 +1332 3704 0 +1329 3704 0 +1307 3704 0 +1316 3704 0 +1317 3688 0 +1450 3712 0 +1331 3672 0 +1314 3744 0 +1337 3704 0 +1316 3744 0 +1413 3848 0 +1141 3664 0 +1484 3848 0 +1340 3704 0 +1309 3688 0 +1340 3688 0 +1304 3704 0 + +# chest of drawers +Drawer 0x0A34 +1392 4035 0 +1456 3821 0 +1432 3961 0 +1328 3733 0 +1424 3961 0 +1328 3730 0 +1312 3723 0 +1312 3720 0 +1328 3744 0 +1392 4019 0 +1456 3819 0 +1328 3748 0 +1392 4009 0 +1328 3725 0 +1448 4013 0 +1328 3722 0 +1456 3797 0 +1352 3829 0 +1328 3756 0 +1312 3732 0 +1312 3729 0 +1362 3829 0 +1328 3753 0 +1120 3612 0 +1456 3795 0 +1440 3849 0 + +# armoire +Armoire 0x0A4F +1409 3848 0 +1137 3664 0 +1426 3960 0 +1345 3752 0 +1181 3632 0 +1397 3696 0 +1348 3776 0 +1433 3960 0 +1417 3776 0 +1409 3800 0 +1482 3848 0 + +# armoire +Armoire 0x0A53 +1448 3713 0 +1448 4009 0 +1120 3610 0 +1440 3851 0 +1392 4017 0 +1392 4011 0 +1456 3771 0 + +# bed +LargeBedEastAddon 0xA7D +1352 3827 0 + +# bed +LargeBedSouthAddon 0xA83 +1364 3825 0 + +# bookcase +LibraryBookcase 0x0A97 +1485 3856 0 +1379 3776 0 +1386 3768 0 +1316 3720 0 +1130 3656 0 +1424 3848 0 +1412 3712 0 +1383 3776 0 +1419 3712 0 +1429 3872 0 +1385 3768 0 +1410 3696 0 +1429 3880 0 +1418 3976 0 +1321 3768 0 +1455 3848 0 +1355 3704 0 +1129 3656 0 +1417 3848 0 +1128 3656 0 +1393 3704 0 +1446 3712 0 +1352 3752 0 +1406 3800 0 +1458 3848 0 +1459 3792 0 +1331 3744 0 +1332 3720 0 +1400 4032 0 +1404 4032 0 +1391 3768 0 +1403 4032 0 +1454 3736 0 +1460 3816 0 +1450 3736 0 +1441 3976 0 + +# bookcase +LibraryBookcase 0x0A98 +1377 3776 0 +1417 3976 0 +1461 3816 0 +1420 3976 0 +1394 3704 0 +1460 3792 0 +1453 3736 0 +1449 3736 0 +1486 3856 0 +1332 3744 0 +1409 3696 0 +1333 3720 0 +1356 3704 0 +1380 3776 0 +1353 3752 0 +1452 3736 0 +1382 3776 0 +1353 3704 0 +1134 3656 0 +1444 3712 0 +1456 3848 0 +1398 3768 0 +1430 3880 0 +1412 3696 0 +1317 3720 0 +1405 3800 0 +1425 3872 0 +1417 3712 0 +1133 3656 0 +1405 4032 0 +1132 3656 0 +1420 3848 0 +1413 3712 0 +1442 3976 0 + +# bookcase +LibraryBookcase 0x0A99 +1440 3801 0 +1408 3716 0 +1328 3694 0 +1424 3884 0 +1304 3750 0 +1168 3645 0 +1344 3754 0 +1392 3812 0 +1440 3802 0 +1440 3978 0 +1376 3779 0 +1328 3710 0 +1352 3761 0 +1344 3780 0 +1176 3633 0 +1384 3772 0 +1304 3694 0 +1384 3773 0 +1408 3697 0 +1376 3781 0 +1376 3777 0 + +# bookcase +LibraryBookcase 0x0A9A +1408 3701 0 +1392 3813 0 +1344 3753 0 +1344 3779 0 +1320 3678 0 +1440 3804 0 +1376 3778 0 +1408 3714 0 +1176 3632 0 +1168 3638 0 +1168 3644 0 +1424 3882 0 + +# bookcase +LibraryBookcase 0x0A9B +1462 3816 0 +1354 3704 0 +1457 3848 0 +1418 3712 0 +1461 3792 0 +1354 3752 0 +1322 3768 0 +1445 3712 0 +1357 3704 0 +1431 3880 0 +1413 3696 0 +1443 3976 0 +1480 3856 0 +1401 4032 0 +1404 3800 0 +1378 3776 0 +1381 3776 0 +1421 3976 0 +1318 3720 0 +1334 3720 0 +1333 3744 0 + +# bookcase +LibraryBookcase 0x0A9C +1408 3698 0 +1376 3780 0 +1176 3637 0 +1176 3638 0 +1408 3700 0 +1352 3762 0 +1168 3646 0 +1440 3977 0 +1424 3885 0 +1424 3883 0 +1304 3710 0 +1344 3778 0 +1440 3805 0 +1168 3640 0 + +# candle +CandleLarge 0x0B1A +1332 3723 10 +1358 3734 10 +1356 3757 10 +1364 3700 4 +1359 3776 9 +1332 3753 9 +1142 3666 6 +1355 3708 7 +1344 3782 9 +1474 3698 4 +1460 3825 8 +1304 3693 6 +1476 3670 26 +1408 3853 8 +1481 3860 6 +1435 3743 9 +1304 3709 6 +1328 3693 6 +1139 3659 6 +1328 3709 9 +1320 3677 10 +1304 3749 9 +1316 3723 9 +1456 3768 10 +1381 3794 4 +1418 3747 6 +1381 3778 -14 +1432 3965 9 +1436 3877 4 +1436 3881 4 +1421 3758 26 +1422 3747 26 +1378 3750 26 +1420 3776 9 +1378 3728 26 +1372 3867 4 +1380 3772 4 +1381 3740 6 +1397 3891 4 +1408 3806 6 +1180 3638 10 +1168 3641 4 +1383 3773 -16 +1446 3780 6 +1429 3960 6 +1364 3704 4 +1456 3736 10 +1446 3776 6 +1441 3718 9 +1443 3800 10 +1423 3848 10 +1440 3776 6 +1392 3698 6 +1453 4028 11 +1452 3718 10 +1426 3874 4 +1344 3757 10 +1478 3718 26 +1452 3853 10 +1478 3715 4 +1394 4020 6 +1402 3804 10 +1348 3868 4 +1454 4008 9 +1396 3867 4 +1440 3980 10 +1474 3683 4 +1395 4008 10 +1462 3818 6 +1478 3684 26 +1378 3780 6 +1460 3801 9 +1372 3864 26 +1370 3864 26 +1388 3774 9 +1394 3768 6 +1388 3827 10 +1435 3824 10 +1455 4000 6 +1412 3776 6 +1427 3816 10 +1448 3749 6 +1452 3980 7 +1452 4002 6 +1444 3848 10 +1462 3794 6 +1403 4037 9 +1408 4008 9 +1408 3769 6 +1352 3765 6 +1128 3660 4 +1486 3851 10 +1134 3611 4 +1130 3612 6 + +# candelabra +CandelabraStand 0x0B26 +1358 3830 0 +1359 3800 0 +1446 3886 0 +1438 4008 0 +1416 4000 0 +1438 4014 0 +1416 4022 0 + +# wooden bench +WoodenBench 0x0B2C +1427 4014 0 +1427 4016 0 +1429 4014 0 +1427 4017 0 +1427 4009 0 +1426 4020 0 +1426 4021 0 +1427 4006 0 +1427 4005 0 +1429 4005 0 +1376 3748 0 +1429 4006 0 +1429 4008 0 +1376 3749 0 +1376 3744 0 +1428 4001 0 +1429 4013 0 +1376 3743 0 +1428 4020 0 +1428 4002 0 +1427 4013 0 +1425 4008 0 +1425 4016 0 +1428 4021 0 +1425 4009 0 +1427 4008 0 +1425 4013 0 +1425 4014 0 +1425 4017 0 +1425 4006 0 +1425 4005 0 +1429 4016 0 +1429 4009 0 +1426 4001 0 +1429 4017 0 +1426 4002 0 + +# wooden bench +WoodenBench 0x0B2D +1423 4022 0 +1419 4022 0 +1419 4020 0 +1419 4000 0 +1420 4000 0 +1420 4002 0 +1419 4002 0 +1423 4002 0 +1423 4000 0 +1422 4002 0 +1420 4020 0 +1420 4022 0 +1422 4000 0 +1422 4022 0 +1423 4020 0 +1422 4020 0 + +# wooden chair +WoodenThrone 0x0B2F +1451 3979 0 + +# throne +Throne 0x0B33 +1379 3771 0 + +# counter +Static 0x0B3D +1398 3891 20 + +# counter +Static 0x0B3F +1398 3890 20 +1398 3892 20 + +# chair +FancyWoodenChairCushion 0x0B50 +1315 3781 0 + +# chair +WoodenChairCushion 0x0B52 +1387 3771 0 +1354 3707 0 + +# chair +WoodenChairCushion 0x0B53 +1354 3756 0 +1364 3697 0 + +# chair +WoodenChairCushion 0x0B54 +1436 3884 0 +1420 3749 0 + +# chair +WoodenChairCushion 0x0B55 +1458 3740 0 +1345 3756 0 + +# chair +WoodenChair 0x0B56 +1485 3850 0 +1362 3705 0 +1452 4026 0 +1362 3699 0 +1461 3795 0 +1362 3701 0 +1461 3819 0 +1425 3875 0 +1425 3816 7 +1424 3817 0 +1362 3703 0 +1451 3851 0 + +# chair +WoodenChair 0x0B57 +1451 3717 0 +1372 3811 0 +1386 3826 0 +1315 3779 0 +1133 3609 0 +1179 3637 0 +1383 3769 -20 +1459 3824 0 +1459 3800 0 +1410 3775 0 + +# chair +WoodenChair 0x0B58 +1403 3803 0 +1442 3715 0 +1366 3699 0 +1366 3701 0 +1393 3699 0 +1482 3858 0 +1366 3705 0 +1409 3852 0 +1398 3805 0 +1366 3703 0 +1453 3979 0 +1395 3804 0 +1353 3764 0 + +# chair +WoodenChair 0x0B59 +1133 3612 0 +1419 3777 0 +1393 3709 0 +1434 3825 0 +1422 3849 0 +1459 3827 0 +1443 3849 0 +1459 3803 0 +1317 3769 0 +1442 3801 0 +1319 3769 0 + +# chair +BambooChair 0x0B5A +1434 3876 0 +1421 3980 0 +1347 3867 0 +1434 3882 0 +1434 3878 0 +1434 3880 0 +1381 3771 -20 +1402 4036 0 +1381 3773 -20 +1381 3775 -20 +1424 3818 0 +1433 3747 0 +1473 3684 0 +1473 3699 0 +1141 3667 0 + +# chair +BambooChair 0x0B5B +1314 3748 0 +1371 3866 0 +1316 3748 0 +1135 3657 0 +1171 3636 0 +1380 3739 0 +1380 3793 0 +1309 3748 0 +1311 3748 0 +1398 4037 0 +1395 3866 0 +1345 3781 0 + +# chair +BambooChair 0x0B5C +1338 3693 0 +1396 3892 0 +1310 3709 0 +1171 3639 0 +1310 3693 0 +1418 4006 5 +1336 3709 0 +1313 3709 0 +1418 4011 5 +1315 3709 0 +1395 3769 0 +1340 3693 0 +1428 3961 0 +1135 3660 0 +1312 3693 0 +1420 4011 5 +1340 3709 0 +1330 3677 0 +1453 4009 0 +1308 3709 0 +1477 3716 0 +1418 4014 5 +1308 3693 0 +1420 4014 5 +1314 3693 0 +1334 3693 0 +1411 4009 0 +1332 3677 0 +1334 3709 0 +1326 3677 0 +1328 3677 0 +1393 4021 0 +1336 3693 0 +1338 3709 0 +1393 3769 0 + +# chair +BambooChair 0x0B5D +1385 3773 -20 +1385 3771 -20 +1333 3752 0 +1385 3781 0 +1333 3750 0 +1385 3775 -20 +1385 3779 0 +1382 3779 0 +1382 3781 0 +1441 3981 0 +1356 3708 0 +1333 3754 0 +1317 3727 0 +1317 3722 0 +1321 3676 0 +1305 3692 0 +1388 3779 0 +1333 3722 0 +1317 3724 0 +1438 3876 0 +1333 3727 0 +1333 3724 0 +1396 4009 0 +1457 3769 0 +1405 4036 0 +1305 3748 0 +1388 3781 0 +1305 3708 0 +1356 3706 0 +1317 3729 0 +1427 3875 0 +1333 3748 0 +1333 3729 0 +1438 3880 0 +1438 3878 0 +1329 3692 0 +1379 3781 0 +1379 3779 0 +1438 3882 0 +1409 3805 0 +1129 3659 0 +1409 4012 0 +1329 3708 0 +1433 3964 0 +1169 3642 0 +1381 3771 0 +1429 3816 8 + +# foot stool +FootStool 0x0B5E +1447 3777 0 +1441 3775 0 +1447 3779 0 +1445 3775 0 +1443 3775 0 + +# bench +Static 0x0B5F +1449 3771 0 +1459 3781 0 +1441 3771 0 +1451 3781 0 +1445 3771 0 +1457 3781 0 +1453 3781 0 +1439 3771 0 +1447 3771 0 +1455 3781 0 +1443 3771 0 +1461 3781 0 + +# bench +Static 0x0B60 +1441 3768 0 +1445 3768 0 +1459 3778 0 +1455 3778 0 +1453 3778 0 +1439 3768 0 +1451 3778 0 +1457 3778 0 +1443 3768 0 +1461 3778 0 +1449 3768 0 +1447 3768 0 + +# bench +Static 0x0B61 +1455 3780 0 +1439 3769 0 +1455 3779 0 +1445 3770 0 +1457 3779 0 +1443 3770 0 +1451 3779 0 +1443 3769 0 +1461 3780 0 +1441 3770 0 +1453 3780 0 +1451 3780 0 +1453 3779 0 +1439 3770 0 +1447 3769 0 +1447 3770 0 +1461 3779 0 +1441 3769 0 +1457 3780 0 +1459 3780 0 +1449 3770 0 +1459 3779 0 +1445 3769 0 +1449 3769 0 + +# bench +Static 0x0B62 +1416 3701 0 + +# bench +Static 0x0B63 +1416 3700 0 + +# bench +Static 0x0B68 +1421 3696 0 +1412 3704 0 +1426 3696 0 + +# bench +Static 0x0B69 +1424 3696 0 +1410 3704 0 +1419 3696 0 + +# bench +Static 0x0B6A +1411 3704 0 +1420 3696 0 +1425 3696 0 + +# wooden signpost +Static 0x0B9A +1362 3768 0 + +# broken chair +Static 0x0C10 +1433 3818 0 + +# broken chair +Static 0x0C11 +1429 3817 0 +1435 3820 6 +1435 3816 6 +1433 3821 0 +1427 3817 0 + +# fishing net +Static 0x0DC8 +1129 3672 0 +1130 3672 0 + +# fishing net +Static 0x0DC9 +1129 3675 0 +1130 3675 0 + +# fishing net +Static 0x0DCA +1130 3674 0 +1130 3673 0 +1129 3673 0 +1129 3674 0 + +# fishing net +Static 0x0DCB +1131 3673 0 + +# fishing net +Static 0x0DD0 +1131 3674 0 + +# fishing net +Static 0x0DD1 +1131 3672 0 + +# fishing net +Static 0x0DD2 +1128 3672 0 + +# fishing net +Static 0x0DD3 +1128 3674 0 +1128 3673 0 + +# fishing net +Static 0x0DD4 +1128 3675 0 + +# fishing net +Static 0x0DD5 +1131 3675 0 + +# small fish +Static 0x0DD6 +1131 3695 -3 +1129 3686 -3 +1119 3683 -3 +1132 3667 0 + +# small fish +Static 0x0DD7 +1130 3665 0 +1120 3692 -3 +1132 3691 -3 + +# small fish +Static 0x0DD8 +1135 3675 0 +1124 3682 -3 +1130 3674 0 +1133 3694 -3 +1134 3684 -3 + +# small fish +Static 0x0DD9 +1127 3669 0 +1121 3689 -3 +1130 3674 0 +1132 3694 -3 + +# cards +Static 0x0E17 +1444 3771 4 + +# brazier +Brazier 0x0E31 +1423 3976 0 +1416 3976 0 + +# crate +LargeCrate 0x0E3C +1376 3851 0 +1377 3848 0 +1377 3852 0 +1376 3850 0 +1376 3850 3 +1483 3983 3 +1381 3853 0 +1381 3853 3 +1485 3976 0 +1381 3849 0 +1381 3852 0 +1381 3852 3 +1475 3988 0 +1475 3978 6 +1476 3978 3 +1474 3986 3 +1475 3987 6 +1475 3987 9 +1376 3848 3 +1376 3848 6 +1376 3848 9 +1476 3979 0 +1476 3979 3 +1376 3848 0 +1475 3988 3 +1475 3987 3 +1481 3989 0 +1480 3989 6 +1387 3848 6 +1480 3989 3 +1387 3848 3 +1475 3987 0 +1474 3987 0 +1474 3986 0 +1473 3987 3 +1475 3986 0 +1387 3848 0 +1386 3849 3 +1475 3986 3 +1364 3849 0 +1480 3988 0 +1480 3988 3 +1364 3850 0 +1364 3853 3 +1364 3853 0 +1364 3850 6 +1360 3852 3 +1475 3979 0 +1475 3978 3 +1480 3989 0 +1475 3979 3 +1360 3852 0 +1360 3851 3 +1360 3851 0 +1385 3849 6 +1385 3850 0 +1385 3850 3 +1390 3848 3 +1390 3848 6 +1390 3848 0 +1386 3849 0 +1387 3848 9 +1486 3976 0 +1475 3978 0 +1385 3849 0 +1484 3981 3 +1364 3850 3 +1483 3982 0 +1473 3987 0 +1385 3849 3 +1365 3849 0 +1484 3982 3 +1480 3980 0 +1480 3982 6 +1483 3982 6 +1480 3983 0 +1484 3982 0 +1485 3977 0 +1365 3854 0 +1485 3976 3 +1483 3983 0 +1366 3853 0 +1480 3981 6 +1486 3977 9 +1483 3981 6 +1483 3981 0 +1483 3981 3 +1480 3982 3 +1486 3977 0 +1483 3982 3 +1480 3982 0 +1486 3977 6 +1486 3977 3 +1486 3976 3 +1365 3850 0 +1365 3852 0 +1365 3852 3 +1486 3976 6 +1484 3976 0 +1390 3848 9 +1365 3850 3 +1484 3981 6 +1484 3981 0 +1480 3981 0 +1365 3853 3 +1365 3849 3 +1477 3978 0 +1480 3981 3 +1485 3977 3 +1365 3853 0 +1476 3978 0 + +# crate +FillableLargeCrate 0x0E3C +1443 3806 3 +1444 3805 0 +1444 3805 3 +1443 3806 0 +1444 3806 0 +1444 3806 6 +1444 3806 3 +1442 3805 0 +1443 3805 0 +1443 3805 3 +1442 3806 6 +1442 3805 3 +1442 3806 0 +1442 3806 3 + +# crate +LargeCrate 0x0E3D +1379 3850 3 +1353 3852 6 +1353 3852 3 +1353 3852 0 +1379 3850 0 +1382 3853 0 +1382 3853 3 +1382 3852 0 +1382 3852 3 +1379 3850 9 +1353 3853 0 +1464 3983 3 +1464 3982 0 +1379 3850 6 +1353 3852 9 +1464 3983 0 +1464 3982 6 +1464 3982 3 +1465 3977 0 +1465 3982 3 +1465 3982 0 +1465 3977 9 +1464 3977 0 +1464 3976 3 +1464 3977 3 +1465 3983 3 +1464 3976 9 +1464 3976 6 +1464 3976 0 +1465 3977 6 +1354 3852 0 +1353 3853 6 +1353 3853 3 +1356 3850 3 +1356 3850 0 +1465 3977 3 +1356 3849 0 +1357 3849 0 +1465 3976 0 +1465 3983 0 +1465 3982 6 +1357 3850 3 +1357 3849 6 +1357 3849 3 +1357 3850 0 + +# crate +MediumCrate 0x0E3E +1432 3797 3 +1376 3852 3 +1376 3852 0 +1376 3852 6 +1376 3853 3 +1376 3853 0 +1432 3796 3 +1432 3796 0 +1432 3796 6 +1432 3797 0 +1432 3795 0 +1432 3795 3 + +# crate +MediumCrate 0x0E3F +1388 3848 0 +1388 3848 3 +1378 3848 0 +1382 3848 3 +1382 3848 0 +1389 3848 3 +1389 3848 0 +1378 3848 3 +1381 3848 0 +1381 3848 3 +1381 3848 6 +1379 3848 0 +1379 3848 3 +1378 3848 6 + +# metal chest +MetalGoldenChest 0x0E40 +1312 3779 0 +1304 3690 0 +1328 3706 0 +1328 3751 0 + +# metal chest +MetalGoldenChest 0x0E41 +1311 3744 0 +1315 3768 0 +1327 3672 0 +1315 3720 0 +1335 3688 0 +1311 3704 0 +1331 3720 0 + +# wooden chest +WoodenChest 0x0E42 +1392 4034 0 +1456 3801 0 +1424 3965 0 +1312 3770 0 + +# wooden chest +FillableWoodenChest 0x0E42 +1352 3813 0 +1352 3816 0 +1352 3823 0 +1352 3806 0 +1352 3803 0 + +# wooden chest +WoodenChest 0x0E43 +1363 3825 0 +1362 3805 0 +1394 4016 0 +1437 3960 0 +1459 3816 0 +1362 3820 0 +1397 4008 0 +1355 3825 0 +1362 3800 0 +1362 3810 0 + +# bag +Bag 0x0E76 +1435 3793 3 + +# barrel +Barrel 0x0E77 +1130 3668 0 +1491 3683 -3 +1494 3695 2 +1495 3695 -3 +1129 3683 2 +1484 3987 5 +1495 3694 -3 +1484 3987 0 +1130 3668 5 +1518 3984 -3 +1130 3682 -3 +1130 3688 -3 +1130 3683 2 +1438 3736 0 +1483 3985 5 +1494 3695 -3 +1438 3736 5 +1438 3737 0 +1483 3986 0 +1495 3694 2 +1130 3682 2 +1373 3864 25 +1432 3794 0 +1432 3794 5 +1483 3986 10 +1472 3982 0 +1469 3985 0 +1502 3985 2 +1502 3986 -3 +1502 3986 2 +1440 3793 0 +1374 3864 25 +1472 3982 5 +1483 3987 0 +1476 3977 5 +1477 3976 5 +1483 3986 5 +1483 3986 15 +1472 3983 10 +1468 3985 5 +1472 3983 0 +1472 3983 5 +1469 3984 0 +1477 3977 5 +1473 3982 0 +1505 3991 -3 +1492 3703 2 +1493 3702 -3 +1438 3737 5 +1492 3702 2 +1398 3864 25 +1492 3703 -3 +1379 3744 25 +1484 3986 0 +1493 3703 2 +1493 3702 2 +1378 3744 25 +1492 3702 -3 +1506 3991 2 +1506 3992 -3 +1472 3984 0 +1394 3893 25 +1505 3991 2 +1505 3992 -3 +1505 3992 2 +1465 3988 0 +1394 3894 25 +1465 3987 5 +1466 3987 5 +1467 3984 0 +1466 3988 5 +1437 3736 5 +1368 3883 -3 +1368 3883 2 +1506 3693 2 +1368 3882 2 +1394 3892 20 +1133 3696 -3 +1373 3864 20 +1374 3864 20 +1506 3693 -3 +1374 3889 2 +1375 3889 -3 +1472 3685 20 +1374 3889 -3 +1375 3890 2 +1506 3692 -3 +1375 3889 2 +1375 3890 -3 +1378 3883 -3 +1398 3864 20 +1345 3870 20 +1480 3977 0 +1377 3884 -3 +1398 3865 20 +1346 3869 20 +1346 3869 25 +1480 3977 5 +1394 3893 20 +1379 3884 -3 +1132 3696 2 +1379 3884 2 +1344 3870 25 +1378 3883 2 +1344 3870 20 +1394 3894 20 +1480 3978 5 +1468 3985 0 +1372 3915 -3 +1372 3915 2 +1465 3986 5 +1480 3978 0 +1465 3986 0 +1372 3914 2 +1371 3914 -3 +1371 3914 2 +1481 3976 0 +1482 3977 0 +1485 3980 0 +1372 3914 -3 +1371 3915 -3 +1371 3915 2 +1504 3708 2 +1123 3688 2 +1502 3985 -3 +1130 3688 2 +1124 3688 2 +1500 3679 -3 +1472 3686 25 +1123 3688 -3 +1468 3979 0 +1438 3736 10 +1370 3897 -3 +1369 3898 -3 +1369 3898 2 +1467 3978 0 +1468 3978 0 +1370 3897 2 +1370 3898 2 +1346 3870 20 +1438 3758 0 +1507 3982 -3 +1515 3706 -3 +1129 3668 0 +1480 3976 0 +1515 3706 2 +1515 3711 2 +1467 3977 0 +1368 3882 -3 +1438 3757 5 +1515 3708 -3 +1515 3711 -3 +1515 3709 -3 +1491 3684 2 +1491 3684 -3 +1492 3684 2 +1492 3684 -3 +1491 3683 2 +1518 3984 2 +1519 3984 2 +1518 3985 2 +1129 3683 -3 +1124 3688 -3 +1370 3898 -3 +1438 3758 10 +1129 3668 5 +1129 3682 -3 +1438 3758 5 +1129 3669 0 +1129 3669 5 +1493 3703 -3 +1480 3976 5 +1498 3706 -3 +1477 3976 0 +1476 3976 5 +1476 3976 0 +1384 3826 0 +1476 3977 0 +1477 3977 0 +1398 3870 20 +1472 3697 20 +1398 3869 20 +1346 3870 25 +1468 3984 0 +1498 3706 2 +1503 3709 2 +1519 3984 -3 +1437 3758 5 +1119 3685 -3 +1382 3912 -3 +1438 3757 0 +1382 3913 -3 +1382 3912 2 +1119 3684 -3 +1473 3983 0 +1480 3976 10 +1345 3870 25 +1473 3983 5 +1119 3685 2 +1119 3684 2 +1437 3757 0 +1118 3688 -3 +1384 3850 0 +1385 3848 0 +1384 3849 5 +1384 3849 0 +1468 3984 5 +1500 3679 2 +1386 3848 5 +1386 3848 0 +1385 3848 5 +1468 3983 0 +1384 3848 5 +1379 3731 25 +1379 3732 20 +1379 3731 20 +1378 3745 20 +1378 3745 25 +1132 3696 -3 +1384 3848 10 +1384 3848 0 +1379 3732 25 +1379 3744 20 +1388 3851 0 +1390 3745 25 +1500 3680 -3 +1390 3745 20 +1467 3979 0 +1467 3979 5 +1400 3741 20 +1481 3977 0 +1398 3870 25 +1481 3976 5 +1390 3741 25 +1389 3852 0 +1466 3987 0 +1466 3988 0 +1388 3852 0 +1389 3851 0 +1120 3684 2 +1500 3680 2 +1120 3684 -3 +1390 3741 20 +1465 3987 0 +1353 3848 5 +1353 3848 10 +1368 3854 0 +1353 3849 5 +1353 3849 0 +1369 3853 5 +1468 3978 5 +1369 3853 0 +1368 3854 5 +1353 3848 0 +1368 3853 5 +1363 3850 0 +1362 3851 5 +1363 3850 5 +1363 3851 5 +1363 3851 0 +1354 3848 0 +1368 3853 0 +1362 3850 0 +1362 3851 0 +1362 3850 5 +1352 3850 0 +1506 3992 2 +1506 3991 -3 +1483 3985 0 +1372 3849 0 +1372 3850 0 +1384 3824 0 +1378 3744 20 +1373 3849 0 +1372 3850 5 +1131 3696 -3 +1352 3848 0 +1371 3849 0 +1352 3849 10 +1369 3854 5 +1369 3854 0 +1352 3849 5 +1371 3849 5 +1371 3850 0 +1352 3848 10 +1352 3849 0 +1352 3848 5 +1482 3985 5 +1420 3739 20 +1432 3793 0 +1440 3792 5 +1421 3739 25 +1421 3753 20 +1421 3753 25 +1400 3745 20 +1440 3792 0 +1409 3745 20 +1409 3745 25 +1367 3882 -3 +1503 3708 -3 +1497 3705 -3 +1472 3696 25 +1420 3753 25 +1473 3696 20 +1384 3825 0 +1420 3753 20 +1497 3705 2 +1420 3754 20 +1420 3740 20 +1472 3696 20 +1420 3739 25 +1421 3739 20 +1420 3754 25 +1129 3688 2 +1420 3740 25 +1504 3708 -3 +1439 3792 0 +1439 3792 5 +1482 3986 0 +1503 3709 -3 +1472 3686 20 +1473 3686 20 +1130 3683 -3 +1484 3986 5 +1482 3976 0 +1400 3741 25 +1482 3985 0 +1400 3745 25 +1482 3977 5 +1409 3741 20 +1409 3741 25 +1439 3793 0 +1367 3882 2 +1432 3793 5 +1503 3708 2 +1129 3682 2 +1380 3731 25 +1380 3731 20 +1492 3683 -3 +1518 3985 -3 +1492 3683 2 + +# metal chest +MetalChest 0x0E7C +1312 3780 0 +1312 3771 0 +1312 3769 0 +1312 3782 0 +1312 3781 0 + +# crate +SmallCrate 0x0E7E +1384 3853 2 +1384 3853 4 +1385 3852 0 +1384 3853 0 +1384 3852 0 +1384 3852 2 +1384 3852 4 +1385 3853 0 +1385 3852 2 +1385 3853 2 + +# keg +Keg 0x0E7F +1392 3870 20 +1478 3696 20 +1478 3697 20 +1396 3864 20 +1394 3864 20 +1472 3701 20 +1477 3696 20 +1472 3702 20 +1476 3677 20 +1476 3676 20 +1476 3678 20 +1473 3702 20 + +# strong box +MetalBox 0x0E80 +1416 3747 8 + +# strong box +FillableMetalBox 0x0E80 +1440 3800 6 +1432 3824 6 +1352 3757 8 +1390 3710 6 +1358 3733 6 +1408 3776 6 +1406 3806 6 +1384 3774 6 +1456 3742 6 +1421 3848 6 +1373 3812 6 +1314 3780 6 +1442 3718 6 + +# pickaxe +Static 0x0E86 +1445 3793 3 + +# cleaver +Static 0x0EC3 +1449 4024 9 + +# dress form +Dressform 0x0EC6 +1360 3776 0 +1448 4004 0 + +# dress form +Dressform 0x0EC7 +1353 3776 0 + +# spellbook +Static 0x0EFA +1426 3977 3 + +# bolt of cloth +Static 0x0F98 +1453 4001 0 +1360 3779 0 +1409 4009 0 + +# bolt of cloth +Static 0x0F99 +1409 4010 0 +1360 3779 0 +1453 4002 0 +1456 4000 0 + +# bolt of cloth +Static 0x0F9A +1456 4000 0 + +# bolt of cloth +Static 0x0F9B (Hue=0x39) +1358 3777 0 +1356 3777 0 + +# bolt of cloth +Static 0x0F9B +1454 4001 0 +1409 4009 0 + +# bolt of cloth +Static 0x0F9C +1452 4003 0 +1409 4009 0 +1357 3777 0 +1455 4001 0 + +# bolt of cloth +Static 0x0F9C (Hue=0x39) +1356 3777 0 + +# sewing kit +Static 0x0F9D +1359 3781 6 +1410 4008 6 +1453 4000 6 + +# scissors +Scissors 0x0F9E +1357 3776 6 +1454 4000 6 + +# scissors +Scissors 0x0F9F +1408 4013 6 +1359 3780 6 +1452 4001 6 + +# spool of thread +Static 0x0FA0 +1359 3781 6 + +# spool of thread +Static 0x0FA1 +1359 3779 6 + +# playing cards +Static 0x0FA3 +1456 3778 4 +1444 3770 4 + +# checker board +CheckerBoard 0x0FA6 +1445 3776 6 + +# chess board +ChessBoard 0x0FA6 +1460 3780 4 + +# dice and cup +Dices 0x0FA7 +1440 3769 4 +1452 3781 4 + +# dying tub +DyeTub 0x0FAB (Hue=0x26) +1476 3671 20 + +# backgammon game +Backgammon 0x0FAD +1452 3779 4 +1440 3769 4 + +# anvil +AnvilEastAddon 0x0FAF +1397 3714 0 +1421 3856 0 + +# anvil +AnvilSouthAddon 0x0FB0 +1416 3858 0 +1393 3712 0 + +# sledge hammer +Static 0x0FB4 +1416 3860 6 +1393 3713 0 + +# sledge hammer +Static 0x0FB5 +1396 3714 0 +1392 3714 6 +1420 3856 0 + +# horse shoes +Static 0x0FB6 +1417 3858 0 +1419 3856 0 + +# tongs +Static 0x0FBB +1392 3716 6 + +# book +Static 0x0FBD +1355 3707 4 +1426 3875 4 +1402 3803 6 +1332 3724 6 +1474 3684 4 +1328 3708 8 +1441 3715 6 +1304 3692 8 +1316 3722 6 +1481 3858 6 +1320 3676 8 +1380 3771 4 +1462 3795 8 +1474 3699 4 +1435 3747 8 +1328 3692 8 +1388 3771 6 +1178 3638 6 +1456 3740 6 +1440 3981 6 +1304 3708 8 +1348 3867 4 +1456 3769 6 +1422 3979 6 +1304 3748 6 +1452 3851 6 +1352 3764 6 +1452 3979 4 +1462 3819 6 +1332 3752 6 +1453 4026 7 +1128 3659 4 + +# book +Static 0x0FBE +1354 3757 9 +1396 3891 4 +1434 3824 6 +1395 3768 6 +1436 3883 4 +1395 3867 4 +1364 3698 4 +1380 3740 6 +1420 3747 7 +1386 3827 7 +1418 4005 9 +1477 3715 4 +1371 3864 26 +1380 3794 4 +1371 3867 4 +1442 3800 6 +1393 3708 6 +1383 3770 -16 +1398 4038 6 +1372 3812 8 +1410 3776 6 +1393 3768 6 + +# pen and ink +Static 0x0FBF +1462 3819 6 +1388 3770 6 +1304 3691 8 +1452 3979 4 +1481 3858 6 +1422 3978 6 +1304 3747 6 +1348 3867 4 +1435 3747 8 +1402 3802 7 +1380 3771 4 +1474 3699 4 +1440 3981 6 +1128 3659 4 +1441 3714 6 +1320 3675 8 +1332 3752 6 +1328 3691 8 +1452 3851 6 +1426 3875 4 +1453 4025 7 +1316 3722 6 +1456 3739 6 +1328 3707 8 +1332 3723 6 +1462 3795 6 +1352 3763 6 +1456 3769 6 +1304 3707 8 +1474 3684 4 + +# pen and ink +Static 0x0FC0 +1410 3776 6 +1380 3794 4 +1383 3770 -16 +1372 3812 8 +1395 3867 4 +1477 3715 4 +1420 3747 6 +1371 3867 4 +1371 3864 26 +1393 3708 6 +1396 3891 4 +1354 3757 9 +1436 3883 4 +1398 4038 6 +1380 3740 6 +1386 3827 6 +1418 4005 9 +1179 3638 7 +1441 3800 6 +1433 3824 6 +1364 3698 4 + +# book +BoldStranger 0x0FEF +1381 3779 4 + +# book +RedBook 0x0FF1 +1384 3780 6 +1377 3777 0 +1381 3781 7 + +# book +BlueBook 0x0FF2 +1386 3776 0 + +# book +ChildrenTalesVol2 0x0FF4 +1168 3642 4 + +# book +DimensionalTravel 0x0FF4 +1387 3779 4 + +# book +BritannianFlora 0x0FF4 +1378 3781 7 + +# pewter mug +PewterMug 0x0FFF +1136 3659 4 + +# pewter mug +PewterMug 0x1000 +1172 3637 4 +1134 3610 4 + +# pewter mug +PewterMug 0x1001 +1132 3611 4 +1134 3658 4 + +# pewter mug +PewterMug 0x1002 +1170 3638 4 + +# spittoon +Static 0x1003 +1451 3775 0 +1447 3775 0 + +# spinning wheel +SpinningwheelEastAddon 0x1019 +1453 4005 0 +1362 3781 0 + +# pile of wool +Static 0x101F (Hue=0xE9) +1454 4004 0 + +# pile of wool +Static 0x101F +1448 4002 0 + +# pile of wool +Static 0x101F (Hue=0x39) +1362 3777 0 +1363 3780 0 + +# chisels +Static 0x1026 +1433 3816 6 + +# hammer +Static 0x102A +1433 3820 6 + +# hammer +Static 0x102B +1437 3816 6 + +# nails +Static 0x102E +1437 3816 6 +1437 3820 6 + +# saw +Static 0x1034 +1434 3820 6 + +# saw +Static 0x1035 +1436 3816 6 + +# sack of flour +Static 0x1039 +1473 3988 0 +1371 3848 0 +1472 3976 0 +1368 3849 0 +1472 3977 0 +1373 3850 0 +1473 3976 0 +1474 3988 0 +1477 3979 0 +1372 3848 0 + +# open sack of flour +Static 0x103A +1373 3853 0 +1368 3848 0 +1373 3852 0 +1369 3851 0 +1477 3984 0 +1369 3848 0 +1472 3978 0 + +# dough +Static 0x103D +1168 3632 9 +1358 3731 9 + +# cookie mix +Static 0x103F +1358 3732 9 +1170 3632 10 + +# rolling pin +Static 0x1043 +1353 3734 6 + +# globe +Static 0x1047 +1317 3780 0 + +# globe +Static 0x1048 +1128 3661 0 + +# loom bench +Static 0x1049 +1455 4005 0 +1364 3781 0 + +# loom bench +Static 0x104A +1449 4002 0 +1364 3778 0 + +# clock frame +Static 0x104D +1394 3805 6 +1397 3805 6 + +# clock parts +Static 0x1050 +1404 3806 6 + +# axle with gears +Static 0x1051 +1394 3803 6 + +# axle with gears +Static 0x1052 +1402 3804 6 + +# gears +Static 0x1053 +1397 3804 6 +1403 3806 6 + +# hinge +Static 0x1055 +1394 3804 6 + +# sextant parts +Static 0x105A +1397 3803 6 + +# springs +Static 0x105D +1397 3802 6 + +# upright loom +LoomSouthAddon 0x1065 +1363 3777 0 +1449 4001 0 + +# training dummy +TrainingDummy 0x1074 +1443 3885 0 +1371 3699 0 +1371 3704 0 +1443 3881 0 +1443 3877 0 +1371 3709 0 + +# potted tree +PottedTree 0x11C8 +1432 3864 0 +1131 3656 0 +1384 3768 0 +1358 3800 0 +1458 3736 0 + +# potted tree +PottedTree1 0x11C9 +1416 3696 0 +1408 3800 0 +1408 3850 0 +1408 3768 0 +1408 3704 0 +1398 3704 0 +1360 3696 0 +1440 3848 0 +1352 3776 0 +1432 3768 0 +1448 3736 0 +1376 3776 0 +1432 3742 0 +1432 3792 0 +1456 3816 0 +1480 3848 0 +1432 3960 0 +1320 3672 0 +1456 3792 0 +1368 3808 0 +1448 3712 0 +1392 4032 0 +1392 4016 0 +1392 4008 0 +1472 3848 0 +1424 3872 0 +1424 3960 0 +1440 3976 0 +1391 3704 0 +1120 3608 0 +1328 3704 0 +1392 3800 0 +1392 3696 0 + +# flowerpot +PottedPlant 0x11CA +1136 3664 0 +1171 3632 0 +1453 4013 0 +1440 3803 0 +1311 3688 0 +1352 3758 0 +1416 3712 0 +1448 3848 0 +1408 3712 0 +1421 3776 0 +1344 3776 0 +1344 3752 0 +1432 3827 0 +1416 3776 0 +1352 3704 0 +1416 3848 0 +1451 3976 0 + +# flowerpot +PottedPlant1 0x11CB +1142 3668 9 +1356 3753 9 +1411 3776 9 +1387 3774 9 +1462 3796 9 +1481 3862 8 +1432 3743 9 +1432 3751 9 +1368 3812 9 +1456 3770 9 +1441 3716 9 +1404 4037 9 +1395 3708 9 +1402 3806 9 +1316 3780 8 + +# flowerpot +PottedPlant2 0x11CC +1402 3800 9 +1422 3747 9 +1388 3773 9 +1390 3708 9 +1399 4038 9 +1445 3718 9 +1408 3772 9 + +# tarot +Static 0x12A6 +1422 3981 6 + +# chainmail coif +Static 0x13C0 +1440 3725 3 + +# chainmail tunic +Static 0x13C2 +1448 3854 1 + +# chainmail leggings +Static 0x13C3 +1442 3725 3 + +# chainmail tunic +Static 0x13C4 +1441 3725 3 + +# leather sleeves +Static 0x13C8 +1439 3712 1 + +# leather leggings +Static 0x13C9 +1438 3712 0 + +# leather tunic +Static 0x13CA +1437 3712 0 + +# leather tunic +Static 0x13D1 +1448 3852 0 + +# studded sleeves +Static 0x13DE +1432 3720 1 + +# studded leggings +Static 0x13DF +1432 3719 0 + +# studded tunic +Static 0x13E0 +1432 3718 0 +1448 3853 0 + +# ringmail armor +Static 0x13E8 +1448 3855 0 +1432 3712 0 + +# war mace +Static 0x1407 +1387 3705 8 + +# moulding board +Static 0x14EA +1356 3734 6 + +# map +Static 0x14EC +1142 3667 6 + +# spyglass +Static 0x14F5 +1371 3870 26 +1381 3796 26 + +# spyglass +Static 0x14F6 +1398 3867 26 +1398 3891 26 +1478 3717 26 +1349 3864 26 +1128 3658 4 +1478 3685 26 + +# rope +Static 0x14F8 +1493 3710 -3 +1504 3709 -3 +1370 3905 -3 +1490 3685 -3 +1366 3882 -3 +1134 3687 -3 +1130 3669 0 +1521 3983 -3 +1505 3694 -3 +1395 3894 20 + +# rope +Static 0x14FA +1123 3695 -3 +1363 3899 -3 +1348 3864 26 +1375 3887 -3 +1373 3915 -3 +1395 3864 20 +1504 3679 -3 +1508 3993 -3 +1128 3657 0 + +# water barrel +Static 0x154D +1440 3745 0 +1432 3744 0 +1432 3752 0 +1432 3750 0 +1392 3864 20 +1368 3864 20 +1499 3679 -3 +1498 3711 -3 +1478 3701 20 +1497 3684 -3 +1497 3706 -3 +1362 3903 -3 +1375 3904 -3 +1128 3664 0 +1130 3689 -3 +1434 3760 0 +1437 3760 0 +1506 3683 -3 +1132 3695 -3 +1398 3888 20 +1129 3688 -3 +1376 3912 -3 +1421 3858 0 +1416 3859 0 +1118 3689 -3 +1378 3884 -3 +1498 3692 -3 +1137 3656 0 +1437 3758 0 +1437 3736 0 +1129 3664 0 +1472 3684 20 +1392 3717 0 +1123 3689 -3 +1392 3713 0 +1509 3709 -3 +1369 3917 -3 + +# large pewter bowl +Static 0x1603 +1130 3609 6 + +# large wooden bowl +Static 0x1605 +1139 3657 6 + +# raw leg of lamb +Static 0x1609 +1448 4029 6 + +# folded cloth +Static 0x1762 (Hue=0x39) +1354 3776 0 + +# folded cloth +Static 0x1763 (Hue=0x39) +1354 3776 1 + +# folded cloth +Static 0x1764 (Hue=0x39) +1354 3776 2 + +# teleporter +Static 0x17EE +1409 3824 5 + +# teleporter +Static 0x1800 +1419 3832 5 + +# teleporter +Static 0x1809 +1406 3996 5 +1142 3621 5 + +# silver wire +Static 0x1877 +1396 3708 6 + +# gold wire +Static 0x1878 +1392 3715 6 + +# bellows +Static 0x199E +1396 3717 0 +1420 3861 0 + +# forge +Static 0x19A2 +1395 3717 0 + +# forge +Static 0x19A6 +1394 3717 0 + +# board +Static 0x1BD7 +1396 3804 0 + +# bulletin board +BulletinBoard 0x1E5E +1452 3768 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/minoc.cfg b/Data/Decoration/Britannia/minoc.cfg new file mode 100644 index 0000000..d404580 --- /dev/null +++ b/Data/Decoration/Britannia/minoc.cfg @@ -0,0 +1,1568 @@ +# window +Static 0x0023 +2511 522 0 + +# stone wall +Static 0x0025 +2505 434 35 + +# log wall +Static 0x0091 +2592 610 0 +2577 588 0 + +# slate roof +Static 0x057F +2499 434 35 +2510 433 35 + +# slate roof +Static 0x0581 +2505 433 35 + +# slate roof +Static 0x0583 +2498 438 35 + +# slate roof +Static 0x0584 +2509 433 35 +2500 435 35 + +# thatch roof +Static 0x05A6 +2530 584 20 +2529 560 23 + +# oven +StoneOvenSouthAddon 0x0930 +2458 397 15 +2491 472 15 + +# fireplace +StoneFireplaceSouthAddon 0x0961 +2508 544 0 +2460 397 15 +2437 435 15 + +# cauldron +Static 0x0975 +2564 677 0 + +# tray +Static 0x0991 +2494 474 21 + +# tray +Static 0x0992 +2439 435 21 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +2548 652 5 +2549 656 5 +2549 654 5 +2479 401 19 +2483 407 19 +2500 383 4 +2517 652 5 +2517 656 5 +2532 578 6 +2468 399 19 +2454 432 21 +2480 597 6 +2484 407 19 +2485 397 19 +2421 494 21 +2421 468 21 +2468 405 19 +2491 400 19 +2486 400 19 +2593 640 6 +2480 400 19 +2468 409 19 +2417 484 21 +2593 612 6 +2522 544 6 +2493 597 6 +2598 623 6 +2508 593 6 +2450 455 21 +2516 656 5 +2474 398 19 +2491 399 19 +2473 397 19 +2486 476 19 +2618 615 6 +2467 398 19 +2501 380 4 + +# fork +Fork 0x09A3 +2485 400 19 +2479 397 19 +2548 654 5 +2483 408 19 +2491 397 19 +2467 406 19 +2473 400 19 +2485 399 19 +2548 656 5 +2500 382 4 + +# fork +Fork 0x09A4 +2487 475 19 + +# knife +Knife 0x09A5 +2473 400 19 +2491 397 19 +2500 382 4 +2548 654 5 +2548 656 5 +2467 406 19 +2483 408 19 +2485 400 19 +2479 397 19 +2485 399 19 + +# knife +Knife 0x09A6 +2487 475 19 + +# metal box +FillableMetalBox 0x09A8 +2580 595 6 +2452 429 21 +2528 549 6 +2462 450 21 +2437 408 21 +2520 521 6 + +# bushel +Basket 0x09AC +2492 475 15 + +# spoon +Spoon 0x09C2 +2479 397 19 +2483 408 19 +2548 654 5 +2548 656 5 +2473 400 19 +2500 382 4 +2485 400 19 +2491 397 19 +2467 406 19 +2485 399 19 + +# spoon +Spoon 0x09C3 +2487 475 19 + +# ham +Static 0x09D3 +2432 409 21 + +# plate +Plate 0x09D7 +2417 483 21 +2468 407 19 +2549 652 5 +2480 596 6 +2422 494 21 +2593 639 6 +2491 397 19 +2467 406 19 +2420 468 21 +2501 383 4 +2619 615 6 +2468 397 19 +2493 596 6 +2468 401 19 +2548 656 5 +2599 623 6 +2484 406 19 +2483 408 19 +2487 475 19 +2487 476 19 +2479 397 19 +2453 432 21 +2474 400 19 +2485 399 19 +2473 400 19 +2501 381 4 +2480 398 19 +2531 578 6 +2492 400 19 +2450 454 21 +2593 613 6 +2485 400 19 +2521 544 6 +2509 593 6 +2500 382 4 + +# frypan +Static 0x09E2 +2437 436 15 + +# kettle +Static 0x09ED +2441 437 21 +2494 472 21 + +# fork +Fork 0x09F4 +2420 468 21 +2531 578 6 +2599 623 6 +2619 615 6 +2521 544 6 +2509 593 6 +2453 432 21 +2422 494 21 +2487 476 19 + +# fork +Fork 0x09F5 +2549 652 5 +2480 398 19 +2417 483 21 +2480 596 6 +2493 596 6 +2492 400 19 +2593 613 6 +2468 407 19 +2484 406 19 +2501 381 4 +2468 401 19 +2474 400 19 +2593 639 6 +2450 454 21 +2501 383 4 +2468 397 19 + +# knife +Knife 0x09F6 +2509 593 6 +2420 468 21 +2453 432 21 +2531 578 6 +2521 544 6 +2619 615 6 +2599 623 6 +2487 476 19 +2422 494 21 + +# knife +Knife 0x09F7 +2417 483 21 +2474 400 19 +2468 397 19 +2549 652 5 +2450 454 21 +2501 381 4 +2593 639 6 +2501 383 4 +2468 407 19 +2493 596 6 +2593 613 6 +2480 398 19 +2492 400 19 +2484 406 19 +2468 401 19 +2480 596 6 + +# spoon +Spoon 0x09F8 +2599 623 6 +2619 615 6 +2487 476 19 +2453 432 21 +2531 578 6 +2521 544 6 +2509 593 6 +2422 494 21 +2420 468 21 + +# spoon +Spoon 0x09F9 +2593 639 6 +2450 454 21 +2501 383 4 +2474 400 19 +2501 381 4 +2417 483 21 +2480 398 19 +2484 406 19 +2468 397 19 +2549 652 5 +2493 596 6 +2468 401 19 +2492 400 19 +2593 613 6 +2468 407 19 +2480 596 6 + +# wall torch +WallTorch 0x0A07 (Light=WestBig) +2426 497 29 +2424 471 29 +2603 628 14 + +# wall torch +WallTorch 0x0A0C (Light=NorthBig) +2598 643 15 +2620 623 14 + +# bowl of flour +Static 0x0A1E +2435 436 15 + +# lantern +Lantern 0x0A22 +2479 405 27 +2474 405 27 +2530 658 0 +2574 603 12 +2549 657 5 + +# chest of drawers +Drawer 0x0A2C +2616 615 0 +2596 623 0 +2492 374 0 +2508 466 15 +2496 593 0 +2417 468 15 +2482 592 0 +2419 494 15 +2502 374 0 + +# chest of drawers +Drawer 0x0A34 +2448 434 15 +2593 636 0 +2593 610 0 +2450 451 15 +2505 595 0 +2480 469 15 +2427 429 15 +2417 480 15 +2530 581 0 +2512 522 0 +2520 547 0 + +# armoire +Armoire 0x0A4F +2494 593 0 +2514 520 0 +2452 450 15 +2494 374 0 +2595 609 0 +2595 635 0 +2500 374 0 +2419 479 15 + +# armoire +Armoire 0x0A53 +2595 625 0 +2480 467 15 +2418 496 15 +2480 593 0 +2505 594 0 +2506 468 15 +2615 617 0 +2416 470 15 +2427 431 15 + +# bedroll +Static 0x0A55 +2592 523 15 +2592 525 15 +2575 535 15 +2581 518 15 +2575 531 15 +2588 538 15 +2564 526 15 +2592 521 15 +2564 522 15 +2575 533 15 +2588 536 15 +2588 534 15 +2581 520 15 +2581 522 15 + +# bedroll +Static 0x0A57 +2564 524 15 +2564 526 15 +2592 525 15 + +# bedroll +Static 0x0A58 +2564 526 15 +2581 522 15 + +# bed +Static 0x0A69 +2570 595 0 +2595 627 0 +2520 549 0 +2570 591 0 +2418 498 15 +2489 376 0 +2489 378 0 +2416 472 15 +2570 593 0 +2505 597 0 +2448 436 15 +2570 589 0 +2570 599 0 +2615 619 0 +2530 583 0 +2570 597 0 + +# bed +Static 0x0A6B +2571 591 0 +2571 589 0 +2571 593 0 +2449 436 15 +2490 376 0 +2571 595 0 +2490 378 0 +2616 619 0 +2419 498 15 +2417 472 15 +2596 627 0 +2506 597 0 +2571 597 0 +2531 583 0 +2521 549 0 +2571 599 0 + +# bookcase +LibraryBookcase 0x0A97 +2425 552 0 +2417 520 0 +2481 472 15 +2431 528 0 +2582 595 0 +2429 435 15 +2448 483 15 +2483 592 0 +2482 472 15 +2476 424 15 +2507 471 15 +2421 528 0 + +# bookcase +LibraryBookcase 0x0A98 +2430 528 0 +2579 595 0 +2481 592 0 +2445 483 15 +2420 528 0 +2421 520 0 +2475 424 15 +2428 435 15 +2511 471 15 +2427 552 0 + +# bookcase +LibraryBookcase 0x0A99 +2496 434 15 +2416 522 0 +2496 429 15 +2497 381 0 +2497 387 0 +2465 560 5 +2480 473 15 +2506 472 15 + +# bookcase +LibraryBookcase 0x0A9A +2497 382 0 +2496 435 15 +2465 559 5 +2497 385 0 +2416 524 0 +2496 428 15 +2480 477 15 +2443 487 15 + +# bookcase +LibraryBookcase 0x0A9B +2581 595 0 +2432 528 0 +2578 595 0 +2422 528 0 +2428 552 0 +2477 424 15 + +# bookcase +LibraryBookcase 0x0A9C +2416 525 0 +2416 521 0 +2496 430 15 +2496 433 15 +2443 486 15 +2497 384 0 +2465 558 5 + +# candle +CandleLarge 0x0B1A +2462 454 21 +2511 474 21 +2520 544 6 +2446 485 19 +2454 484 19 +2520 525 6 +2427 437 19 +2450 453 21 +2501 427 19 +2528 545 6 +2530 578 6 +2500 380 4 +2452 427 21 +2480 474 19 +2452 432 21 +2531 574 6 +2505 427 19 +2454 480 19 +2441 439 21 +2488 475 19 +2437 412 21 + +# candelabra +Candelabra 0x0B1D +2419 522 4 +2431 523 4 +2427 554 4 +2437 523 4 +2580 599 6 +2599 609 6 +2433 528 6 +2600 623 6 +2595 629 6 +2615 621 6 +2570 587 6 +2570 601 6 +2599 635 6 +2574 592 6 +2593 614 6 +2620 615 6 +2574 596 6 +2593 638 6 +2468 563 11 +2478 567 11 +2465 553 11 +2472 563 11 +2471 553 11 +2485 399 19 +2479 399 19 +2483 407 19 +2467 407 19 +2473 399 19 +2491 399 19 +2467 399 19 +2483 428 21 +2475 426 21 +2463 397 21 + +# candelabra +CandelabraStand 0x0B26 +2486 424 15 +2422 544 2 +2457 403 15 +2429 528 0 +2486 435 15 +2422 549 0 +2481 410 15 +2423 528 0 +2465 411 15 +2495 403 15 +2416 556 0 +2416 532 0 +2416 530 0 +2416 549 0 +2480 435 15 +2478 430 15 +2416 544 2 +2478 424 15 + +# wooden bench +WoodenBench 0x0B2D +2418 528 0 +2426 520 0 +2427 520 0 +2425 520 0 +2424 520 0 + +# counter +Static 0x0B3E +2510 474 15 +2509 593 0 +2508 474 15 +2516 474 15 +2599 623 0 +2560 675 0 +2619 615 0 +2516 478 15 +2461 488 15 +2561 675 0 +2420 468 15 +2422 494 15 +2463 488 15 +2521 544 0 +2518 474 15 +2461 454 15 +2531 578 0 +2518 478 15 +2463 484 15 +2453 432 15 +2461 484 15 +2471 563 5 +2469 563 5 +2440 435 15 + +# chair +WoodenChairCushion 0x0B52 +2418 523 0 + +# chair +WoodenChairCushion 0x0B53 +2434 521 0 + +# chair +WoodenChair 0x0B56 +2531 656 1 +2451 428 15 +2498 427 15 +2474 427 15 +2445 486 15 + +# chair +WoodenChair 0x0B57 +2436 521 0 +2454 477 15 +2432 521 0 +2432 437 15 +2483 425 15 + +# chair +WoodenChair 0x0B58 +2481 475 15 +2420 524 0 +2420 522 0 +2581 597 0 +2434 530 0 +2428 438 15 + +# chair +WoodenChair 0x0B59 +2432 440 15 +2434 525 0 +2432 525 0 +2436 525 0 + +# chair +BambooChair 0x0B5A +2452 485 15 +2515 656 1 +2515 654 1 +2515 652 1 +2461 452 15 +2547 652 1 +2547 656 1 +2547 654 1 +2481 427 15 +2481 431 15 +2481 429 15 +2436 410 15 +2519 523 0 +2452 479 15 +2452 481 15 +2452 483 15 +2499 382 0 +2527 547 0 + +# chair +BambooChair 0x0B5B +2502 425 15 +2500 425 15 +2518 478 21 +2470 562 5 +2509 473 15 +2517 479 15 +2504 425 15 +2518 479 15 +2506 425 15 +2517 478 21 +2487 474 15 +2516 478 21 + +# chair +BambooChair 0x0B5C +2506 429 15 +2502 429 15 +2487 477 15 +2531 579 0 +2509 594 0 +2504 429 15 +2599 624 0 +2453 433 15 +2619 616 0 +2500 429 15 +2420 469 15 +2521 545 0 +2422 495 15 + +# chair +BambooChair 0x0B5D +2533 655 1 +2518 652 1 +2550 654 1 +2550 652 1 +2533 657 1 +2481 596 0 +2476 427 15 +2550 656 1 +2518 656 1 +2451 454 15 +2518 654 1 +2456 483 15 +2456 481 15 +2456 479 15 +2428 555 0 +2418 483 15 +2494 596 0 +2594 613 0 +2447 486 15 +2594 639 0 +2502 381 0 +2463 461 15 +2502 383 0 +2532 575 0 +2460 461 15 +2485 431 15 +2485 429 15 +2456 485 15 +2485 427 15 + +# foot stool +FootStool 0x0B5E +2464 398 15 +2464 400 15 + +# bench +Static 0x0B5F +2487 401 15 +2485 409 15 +2481 401 15 +2475 401 15 +2482 409 15 +2466 409 15 +2472 401 15 +2466 401 15 +2469 401 15 +2478 401 15 +2484 401 15 +2493 401 15 +2490 401 15 +2469 409 15 + +# bench +Static 0x0B60 +2472 397 15 +2484 397 15 +2481 397 15 +2478 397 15 +2475 397 15 +2482 405 15 +2485 405 15 +2466 397 15 +2469 397 15 +2466 405 15 +2487 397 15 +2490 397 15 +2493 397 15 +2469 405 15 + +# bench +Static 0x0B61 +2493 400 15 +2481 399 15 +2481 400 15 +2481 398 15 +2490 400 15 +2485 406 15 +2485 408 15 +2484 400 15 +2484 399 15 +2487 398 15 +2490 399 15 +2482 408 15 +2482 407 15 +2469 398 15 +2466 408 15 +2469 399 15 +2487 399 15 +2469 400 15 +2466 407 15 +2466 399 15 +2466 398 15 +2466 400 15 +2466 406 15 +2493 399 15 +2475 400 15 +2475 398 15 +2478 398 15 +2478 400 15 +2478 399 15 +2472 400 15 +2469 407 15 +2485 407 15 +2469 408 15 +2472 399 15 +2472 398 15 +2487 400 15 +2475 399 15 +2484 398 15 +2490 398 15 +2482 406 15 +2469 406 15 +2493 398 15 + +# bench +Static 0x0B65 +2418 557 0 +2418 555 0 +2418 553 0 +2422 551 0 +2418 551 0 +2422 553 0 +2422 555 0 + +# bench +Static 0x0B66 +2416 557 0 +2420 555 0 +2420 553 0 +2416 553 0 +2416 551 0 +2420 551 0 +2416 555 0 + +# bench +Static 0x0B67 +2421 553 0 +2421 551 0 +2417 553 0 +2421 555 0 +2417 551 0 +2417 555 0 +2417 557 0 + +# wooden signpost +Static 0x0B98 +2507 440 15 + +# wooden signpost +Static 0x0B9A +2436 443 15 + +# broken chair +Static 0x0C10 +2506 476 15 +2514 476 15 + +# broken chair +Static 0x0C11 +2519 474 21 + +# chessmen +Static 0x0E13 +2516 652 6 +2491 398 19 +2467 408 20 + +# chessmen +Static 0x0E14 +2491 398 19 +2516 652 6 +2467 408 20 + +# cards +Static 0x0E17 +2516 655 5 +2483 409 19 +2473 399 19 + +# cards +Static 0x0E18 +2516 654 5 +2483 409 19 +2473 399 19 + +# cards +Static 0x0E19 +2517 654 5 +2484 409 19 +2474 399 19 + +# backgammon board +Backgammon 0x0E1C +2467 400 19 + +# crystal ball +Static 0x0E2F (Light=Circle150) +2532 655 8 + +# crate +FillableLargeCrate 0x0E3D +2534 551 0 +2534 552 0 +2533 552 0 +2456 426 15 +2533 551 3 +2456 425 18 +2456 424 15 +2456 425 15 +2456 424 21 +2533 551 0 +2534 550 0 +2534 551 3 +2533 550 0 +2456 424 18 +2534 550 6 +2534 552 6 +2534 550 3 +2534 552 3 + +# crate +MediumCrate 0x0E3E +2528 553 3 +2528 552 0 +2528 553 0 +2529 557 0 +2528 558 0 +2528 557 3 + +# metal chest +MetalGoldenChest 0x0E40 +2498 549 0 +2500 545 0 +2497 549 0 +2498 545 0 +2496 545 0 + +# wooden chest +WoodenChest 0x0E42 +2522 635 1 +2498 547 0 +2541 673 1 +2522 636 1 +2541 674 1 + +# wooden chest +WoodenChest 0x0E43 +2594 520 15 +2577 530 15 +2528 670 1 +2533 652 1 +2532 652 1 +2529 670 1 +2566 521 15 +2583 517 15 +2507 632 1 +2542 632 1 +2590 533 15 +2543 632 1 +2506 632 1 + +# barrel +FillableBarrel 0x0E77 +2449 424 15 +2457 402 15 +2528 555 0 +2448 426 20 +2457 402 20 +2457 401 20 +2448 425 20 +2448 426 15 +2528 554 5 +2528 555 10 +2448 425 15 +2448 424 20 +2528 555 5 +2449 424 20 +2528 556 0 +2528 556 5 +2529 554 0 +2529 556 0 +2448 424 25 +2457 400 15 +2457 401 15 + +# water tub +Static 0x0E7B +2520 371 23 +2515 371 23 +2530 371 23 +2525 371 23 + +# metal chest +MetalChest 0x0E7C +2500 547 0 +2496 547 0 +2497 545 0 +2498 547 0 +2497 547 0 +2496 549 0 + +# strong box +FillableMetalBox 0x0E80 +2507 474 21 +2469 563 11 + +# empty tub +Static 0x0E83 +2525 371 23 +2515 371 23 +2530 371 23 +2520 371 23 + +# pickaxe +Static 0x0E85 +2585 520 15 + +# pickaxe +Static 0x0E86 +2581 527 15 +2589 536 15 +2593 524 15 +2504 427 21 +2463 488 21 +2565 524 15 +2596 528 15 +2461 484 21 + +# drum +Static 0x0E9C +2416 545 0 + +# tambourine +Static 0x0E9D +2420 546 0 + +# standing harp +Static 0x0EB1 +2420 544 2 + +# lute +Static 0x0EB3 +2418 546 0 + +# music stand +Static 0x0EB5 +2418 547 0 +2420 547 0 +2416 546 0 + +# music stand +Static 0x0EB9 +2421 545 0 + +# cleaver +Static 0x0EC3 +2435 403 21 +2432 412 21 + +# diamond +Static 0x0F28 +2460 484 21 + +# saddle +Static 0x0F37 +2523 380 23 +2523 382 23 + +# shovel +Static 0x0F3A +2593 533 15 +2582 520 15 + +# horse dung +Static 0x0F3B +2521 385 15 +2527 378 23 +2533 376 23 +2521 376 23 + +# horse dung +Static 0x0F3C +2524 376 23 +2516 375 23 +2535 374 23 +2527 381 22 + +# game board +ChessBoard 0x0FA6 +2516 652 5 +2467 408 19 +2492 398 19 + +# dice and cup +Dices 0x0FA7 +2468 400 19 +2486 397 19 + +# backgammon game +Backgammon 0x0FAD +2486 398 19 + +# anvil +AnvilEastAddon 0x0FAF +2560 501 0 +2534 571 0 +2467 553 5 + +# anvil +AnvilSouthAddon 0x0FB0 +2465 556 5 + +# forge +SmallForgeAddon 0x0FB1 +2561 501 0 +2535 571 0 + +# sledge hammer +Static 0x0FB4 +2534 572 0 +2465 557 5 + +# sledge hammer +Static 0x0FB5 +2468 553 5 + +# tongs +Static 0x0FBB +2535 572 0 +2469 553 5 +2465 555 5 + +# book +Static 0x0FBD +2462 452 21 +2528 547 6 +2531 575 6 +2427 555 4 +2480 475 19 +2433 530 6 +2475 427 19 +2437 410 21 +2419 523 4 +2446 486 19 +2499 427 19 +2520 523 6 +2427 438 19 +2580 597 6 +2452 428 21 + +# book +Static 0x0FBE +2483 426 19 +2470 563 11 +2434 522 4 +2509 474 21 +2454 478 19 + +# pen and ink +Static 0x0FBF +2419 523 4 +2520 523 6 +2475 427 19 +2580 597 6 +2499 427 19 +2462 452 21 +2480 475 19 +2528 547 6 +2437 410 21 +2446 486 19 +2427 555 4 +2427 438 19 +2531 575 6 +2433 530 6 +2452 428 21 + +# pen and ink +Static 0x0FC0 +2509 474 21 +2454 478 19 +2483 426 19 +2434 522 4 +2470 563 11 + +# pewter mug +PewterMug 0x0FFF +2421 468 21 +2483 406 19 +2473 400 19 +2532 578 6 +2598 623 6 +2467 409 19 +2508 593 6 +2467 399 19 +2479 400 19 +2454 432 21 +2618 615 6 +2467 401 19 +2485 401 19 +2421 494 21 +2522 544 6 +2488 476 19 + +# pewter mug +PewterMug 0x1000 +2480 399 19 +2501 384 4 +2593 640 6 +2450 455 21 +2493 597 6 +2492 401 19 +2593 612 6 +2486 399 19 +2492 399 19 +2484 408 19 +2480 597 6 +2463 400 21 +2417 484 21 +2480 401 19 +2463 398 21 + +# pewter mug +PewterMug 0x1001 +2501 382 4 +2492 397 19 +2484 405 19 +2486 401 19 +2480 397 19 +2486 475 19 +2474 397 19 +2474 401 19 +2468 406 19 +2468 398 19 +2549 651 5 + +# pewter mug +PewterMug 0x1002 +2467 407 19 +2548 653 5 +2473 398 19 +2491 401 19 +2467 405 19 +2479 398 19 +2485 398 19 +2500 381 4 +2467 397 19 +2548 655 5 +2483 405 19 + +# spittoon +Static 0x1003 +2465 404 15 +2488 397 15 +2470 397 15 +2481 404 15 + +# wash basin +Static 0x1008 +2574 590 6 +2574 599 6 +2574 597 6 + +# archery butte +ArcheryButte 0x100B +2514 408 15 + +# hammer +Static 0x102A +2515 474 21 +2459 461 21 + +# hammer +Static 0x102B +2462 459 21 + +# nails +Static 0x102E +2515 474 21 + +# jointing plane +Static 0x1030 +2517 474 21 + +# saw +Static 0x1035 +2510 474 21 +2461 454 21 + +# clock frame +Static 0x104D +2462 462 21 +2459 460 21 + +# clock parts +Static 0x104F +2459 462 21 + +# axle with gears +Static 0x1051 +2462 460 21 + +# gears +Static 0x1053 +2459 459 21 + +# hinge +Static 0x1055 +2462 461 21 + +# sextant +Static 0x1057 +2459 461 21 + +# sextant parts +Static 0x105A +2462 463 21 + +# axle +Static 0x105C +2459 459 21 + +# springs +Static 0x105D +2462 460 21 + +# training dummy +TrainingDummy 0x1070 +2480 424 15 + +# cot +Static 0x11FD +2504 637 2 +2504 639 2 +2504 635 2 +2541 676 2 +2539 637 2 +2525 671 2 +2522 640 2 +2522 638 2 +2539 633 2 +2525 677 2 +2525 675 2 +2525 673 2 +2539 639 2 +2541 678 2 +2539 635 2 +2530 659 2 + +# cot +Static 0x11FE +2526 671 2 +2505 635 2 +2526 677 2 +2540 639 2 +2505 637 2 +2526 675 2 +2542 676 2 +2542 678 2 +2526 673 2 +2531 659 2 +2540 635 2 +2540 637 2 +2523 638 2 +2540 633 2 +2523 640 2 +2505 639 2 + +# cot +Static 0x11FF +2508 638 2 +2524 633 2 +2526 633 2 +2545 671 2 +2543 671 2 + +# cot +Static 0x1200 +2508 639 2 +2545 672 2 +2543 672 2 +2526 634 2 +2524 634 2 + +# sign +LocalizedSign 0x129C (LabelNumber=1016190) +2525 498 26 + +# tarot +Static 0x12A6 +2532 657 7 + +# mallet and chisel +Static 0x12B3 +2462 523 5 +2468 523 5 + +# brush +Static 0x1371 +2519 375 23 +2536 372 23 + +# brush +Static 0x1373 +2530 375 23 + +# bridle +Static 0x1374 +2535 375 23 +2522 384 15 + +# bridle +Static 0x1375 +2524 381 23 + +# skirt +Static 0x1516 +2542 673 1 +2528 673 1 +2542 638 1 + +# shirt +Static 0x1517 +2545 678 0 +2523 635 0 + +# shirt +Static 0x1518 +2528 675 0 + +# long pants +Static 0x1539 +2525 637 1 +2542 635 0 +2529 672 1 + +# bandana +Static 0x153F +2522 633 1 +2541 633 1 + +# skullcap +Static 0x1543 +2540 634 0 + +# skullcap +Static 0x1544 +2527 672 1 +2523 636 1 + +# water barrel +Static 0x154D +2529 555 0 +2547 634 0 +2547 639 0 +2533 672 0 +2528 554 0 +2530 640 0 +2448 424 15 +2549 678 0 +2563 674 0 +2489 472 15 +2533 677 0 +2549 673 0 +2512 639 0 +2512 634 0 +2530 635 0 + +# wooden bowl +Static 0x15F8 +2435 436 15 + +# large pewter bowl +Static 0x1603 +2494 475 21 + +# large wooden bowl +Static 0x1605 +2441 435 21 + +# raw leg of lamb +Static 0x1609 +2432 411 21 + +# water +Static 0x1797 +2589 581 -5 + +# bellows +Static 0x197A +2467 557 5 +2467 555 5 + +# forge +Static 0x197E (Light=Circle300) +2468 555 5 +2468 557 5 + +# forge +Static 0x1982 +2469 557 5 +2469 555 5 + +# ore +Static 0x19B8 +2590 529 15 +2452 496 18 +2572 523 15 +2587 518 15 +2464 486 15 + +# ore +Static 0x19B8 (Amount=25) +2508 433 18 + +# ore +Static 0x19B9 (Amount=9) +2509 433 18 + +# ore +Static 0x19B9 +2463 484 21 +2587 521 15 +2599 528 15 +2506 427 20 + +# ore +Static 0x19BA +2585 529 15 +2582 533 15 +2595 535 15 +2599 522 15 +2580 527 15 +2459 484 15 +2461 486 15 +2569 525 15 +2503 427 19 + +# bulletin board +BulletinBoard 0x1E5E +2471 397 15 + +# fancy shirt +Static 0x1EFD +2541 636 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/moonglow.cfg b/Data/Decoration/Britannia/moonglow.cfg new file mode 100644 index 0000000..4e4dfb5 --- /dev/null +++ b/Data/Decoration/Britannia/moonglow.cfg @@ -0,0 +1,1990 @@ +# stone wall +Static 0x0080 +4460 1182 -14 +4461 1182 -14 +4462 1180 -14 +4462 1181 -14 +4462 1182 -14 +4463 1182 -14 +4464 1182 -14 +4465 1182 -14 +4466 1180 -14 +4466 1181 -14 +4466 1182 -14 +4467 1180 -14 +4467 1181 -14 +4467 1182 -14 +4468 1181 -14 +4468 1182 -14 +4469 1182 -14 +4470 1182 -14 +4471 1182 -14 +4472 1182 -14 +4473 1181 -14 +4473 1182 -14 +4474 1182 -14 +4475 1180 -14 +4475 1181 -14 +4475 1182 -14 +4476 1182 -14 +4477 1182 -14 +4478 1180 -14 +4478 1181 -14 +4478 1182 -14 +4479 1180 -14 +4479 1181 -14 +4479 1182 -14 +4480 1182 -14 +4481 1181 -14 +4481 1182 -14 +4482 1180 -14 +4482 1181 -14 +4482 1182 -14 +4483 1180 -14 +4483 1181 -14 +4483 1182 -14 + +# plaster wall +Static 0x014A +4401 1167 23 +4402 1167 26 + +# sandstone arch +Static 0x0170 +4544 871 30 + +# stone pavers +Static 0x0520 +4306 921 20 + +# iron fence +Static 0x084B +4460 1179 0 +4461 1179 0 +4462 1179 0 +4463 1179 0 +4464 1179 0 +4465 1179 0 +4466 1179 0 +4467 1179 0 +4468 1179 0 +4469 1179 0 +4470 1179 0 +4471 1179 0 +4472 1179 0 +4473 1179 0 +4474 1179 0 +4475 1179 0 +4476 1179 0 +4477 1179 0 +4478 1179 0 +4479 1179 0 +4480 1179 0 +4482 1179 0 +4483 1179 0 +4484 1179 0 + +# iron gate +IronGateShort 0x0850 (Facing=WestCW) +4465 1048 0 + +# iron gate +IronGateShort 0x0852 (Facing=EastCCW) +4466 1048 0 + +# iron gate +IronGateShort 0x0854 (Facing=SouthCW) +4379 1101 0 +4496 1094 0 + +# iron gate +IronGateShort 0x0856 (Facing=NorthCCW) +4379 1100 0 +4496 1093 0 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +4570 1481 0 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +4571 1481 0 + +# wooden gate +DarkWoodGate 0x086E (Facing=SouthCW) +4643 1317 0 + +# wooden gate +DarkWoodGate 0x0870 (Facing=NorthCCW) +4417 1447 0 +4643 1316 0 + +# oven +StoneOvenEastAddon 0x092C +4408 1465 0 + +# oven +StoneOvenSouthAddon 0x0930 +4628 1320 0 +4385 1056 0 + +# fireplace +StoneFireplaceEastAddon 0x0959 +4408 1468 0 +4552 1490 0 + +# fireplace +Static 0x095F +4557 1040 0 + +# fireplace +Static 0x0960 +4556 1040 0 + +# fireplace +StoneFireplaceSouthAddon 0x0961 +4389 1056 0 +4626 1320 0 + +# tray +Static 0x0991 +4408 1463 6 +4528 943 24 +4555 1488 6 +4630 1321 6 + +# tray +Static 0x0992 +4482 1218 4 +4555 1044 4 +4561 922 24 +4686 1221 4 +4692 1179 4 + +# ceramic mug +CeramicMug 0x0995 +4412 1466 4 +4480 1218 4 +4684 1221 4 + +# ceramic mug +CeramicMug 0x0996 +4634 1322 4 + +# ceramic mug +CeramicMug 0x0997 +4392 1213 4 +4392 1220 4 +4408 1205 4 +4408 1229 4 +4412 1208 4 +4414 1465 4 +4424 1204 4 +4428 1224 4 +4482 1217 4 +4556 1494 4 +4648 1220 4 +4664 1396 4 +4686 1220 4 + +# fork +Fork 0x09A3 +4527 942 24 + +# fork +Fork 0x09A4 +4413 1465 4 +4481 1217 4 +4554 1043 4 +4555 1494 4 +4560 921 24 +4635 1322 4 +4685 1220 4 +4691 1178 4 + +# knife +Knife 0x09A5 +4527 942 24 + +# knife +Knife 0x09A6 +4413 1465 4 +4481 1217 4 +4554 1043 4 +4555 1494 4 +4560 921 24 +4635 1322 4 +4685 1220 4 +4691 1178 4 + +# metal box +FillableMetalBox 0x09A8 +4391 1130 6 +4392 1064 6 +4392 1080 6 +4411 1109 6 +4457 1080 6 +4476 1080 6 +4482 1065 6 + +# spoon +Spoon 0x09C2 +4527 942 24 + +# spoon +Spoon 0x09C3 +4413 1465 4 +4481 1217 4 +4554 1043 4 +4555 1494 4 +4560 921 24 +4635 1322 4 +4685 1220 4 +4691 1178 4 + +# ceramic mug +CeramicMug 0x09CA +4396 1200 4 +4396 1224 4 +4412 1216 4 +4424 1212 4 +4428 1216 4 +4556 1495 4 +4636 1323 4 + +# plate +Plate 0x09D7 +4392 1212 4 +4392 1219 4 +4395 1200 4 +4395 1224 4 +4408 1204 4 +4408 1228 4 +4411 1208 4 +4411 1216 4 +4413 1465 4 +4413 1466 4 +4424 1203 4 +4424 1211 4 +4427 1216 4 +4427 1224 4 +4481 1217 4 +4481 1218 4 +4527 942 24 +4528 942 24 +4554 1043 4 +4554 1044 4 +4555 1494 4 +4555 1495 4 +4560 921 24 +4560 922 24 +4635 1322 4 +4635 1323 4 +4648 1219 4 +4664 1395 4 +4685 1220 4 +4685 1221 4 +4691 1178 4 +4691 1179 4 + +# frypan +Static 0x09E2 +4556 1488 6 +4624 1322 6 + +# pot +Static 0x09E4 +4554 1488 6 + +# muffins +Static 0x09EB +4554 1040 6 + +# kettle +Static 0x09ED +4410 1462 6 +4553 1488 6 +4555 1040 6 +4624 1323 6 + +# milk +Pitcher 0x09F0 (Content=Milk) +4558 1488 6 +4630 1322 6 + +# fork +Fork 0x09F4 +4395 1200 4 +4395 1224 4 +4411 1208 4 +4411 1216 4 +4413 1466 4 +4427 1216 4 +4427 1224 4 +4481 1218 4 +4554 1044 4 +4555 1495 4 +4560 922 24 +4635 1323 4 +4685 1221 4 +4691 1179 4 + +# fork +Fork 0x09F5 +4392 1212 4 +4392 1219 4 +4408 1204 4 +4408 1228 4 +4424 1203 4 +4424 1211 4 +4528 942 24 +4648 1219 4 +4664 1395 4 + +# knife +Knife 0x09F6 +4395 1200 4 +4395 1224 4 +4411 1208 4 +4411 1216 4 +4413 1466 4 +4427 1216 4 +4427 1224 4 +4481 1218 4 +4554 1044 4 +4555 1495 4 +4560 922 24 +4635 1323 4 +4685 1221 4 +4691 1179 4 + +# knife +Knife 0x09F7 +4392 1212 4 +4392 1219 4 +4408 1204 4 +4408 1228 4 +4424 1203 4 +4424 1211 4 +4528 942 24 +4648 1219 4 +4664 1395 4 + +# spoon +Spoon 0x09F8 +4395 1200 4 +4395 1224 4 +4411 1208 4 +4411 1216 4 +4413 1466 4 +4427 1216 4 +4427 1224 4 +4481 1218 4 +4554 1044 4 +4555 1495 4 +4560 922 24 +4635 1323 4 +4685 1221 4 +4691 1179 4 + +# spoon +Spoon 0x09F9 +4392 1212 4 +4392 1219 4 +4408 1204 4 +4408 1228 4 +4424 1203 4 +4424 1211 4 +4528 942 24 +4648 1219 4 +4664 1395 4 + +# bowl of flour +Static 0x0A1E +4384 1060 6 +4408 1462 6 + +# chest of drawers +Drawer 0x0A2C +4281 920 0 +4289 920 0 +4321 920 0 +4397 1208 0 +4397 1216 0 +4411 1200 0 +4412 1224 0 +4425 1208 0 +4429 1200 0 +4483 1056 0 +4561 1488 0 +4625 1328 0 +4653 1216 0 +4669 1392 0 +4691 1217 0 + +# chest of drawers +FancyDrawer 0x0A30 +4410 1456 0 +4683 1168 0 + +# chest of drawers +Drawer 0x0A34 +4384 1155 0 +4384 1161 0 +4384 1167 0 +4384 1173 0 +4392 1201 0 +4392 1227 0 +4408 1211 0 +4408 1217 0 +4424 1217 0 +4424 1229 0 +4448 1061 0 +4470 1215 0 +4476 1063 0 +4488 1062 0 +4525 932 20 +4544 1043 0 +4549 921 20 + +# chest of drawers +FancyDrawer 0x0A38 +4300 920 0 +4300 921 20 +4400 1156 0 + +# armoire +FancyArmoire 0x0A4D +4303 916 20 +4305 916 0 + +# armoire +Armoire 0x0A4F +4393 1208 0 +4393 1216 0 +4409 1200 0 +4425 1200 0 +4429 1208 0 +4472 1214 0 +4627 1328 0 +4649 1216 0 +4665 1392 0 + +# armoire +FancyArmoire 0x0A51 +4400 1155 0 +4408 1458 0 +4681 1169 0 + +# armoire +Armoire 0x0A53 +4392 1205 0 +4392 1225 0 +4408 1209 0 +4408 1221 0 +4408 1226 0 +4424 1221 0 +4424 1225 0 +4448 1060 0 +4525 934 20 +4544 1045 0 +4549 919 20 +4560 1490 0 +4690 1219 0 + +# bed +Static 0x0A69 +4384 1087 0 +4384 1089 0 +4384 1091 0 +4384 1093 0 +4389 1089 0 +4389 1091 0 +4389 1093 0 + +# bed +Static 0x0A6B +4385 1087 0 +4385 1089 0 +4385 1091 0 +4385 1093 0 +4390 1089 0 +4390 1091 0 +4390 1093 0 + +# bed +LargeBedSouthAddon 0x0A7D +4448 1058 0 +4470 1218 0 +4681 1172 0 + +# bed +LargeBedEastAddon 0x0A83 +4551 918 20 +4693 1217 0 + +# bookcase +LibraryBookcase 0x0A97 +4288 962 0 +4288 990 0 +4289 965 0 +4290 962 0 +4290 968 0 +4290 971 0 +4290 993 0 +4291 990 0 +4292 965 0 +4293 968 0 +4301 924 20 +4319 948 10 +4322 948 10 +4325 948 10 +4326 948 10 +4327 990 0 +4328 962 0 +4330 970 0 +4330 990 0 +4331 948 10 +4332 962 0 +4333 962 0 +4333 970 0 +4333 990 0 +4389 1080 0 +4393 1160 0 +4393 1224 0 +4394 1080 0 +4395 1160 0 +4397 1200 0 +4398 1160 0 +4409 1208 0 +4409 1216 0 +4413 1208 0 +4417 1460 0 +4419 1460 0 +4425 1224 0 +4429 1216 0 +4452 1056 0 +4468 1156 0 +4473 1214 0 +4474 1156 0 +4530 1056 0 +4532 939 20 +4551 856 30 +4555 856 30 +4559 918 20 +4684 1176 0 +4691 1407 0 +4693 1407 0 + +# bookcase +LibraryBookcase 0x0A98 +4287 962 0 +4289 971 0 +4289 990 0 +4289 993 0 +4290 965 0 +4291 962 0 +4291 971 0 +4292 968 0 +4292 990 0 +4292 993 0 +4293 962 0 +4293 971 0 +4301 924 0 +4321 948 10 +4323 948 10 +4327 948 10 +4327 962 0 +4328 948 10 +4328 990 0 +4330 962 0 +4331 990 0 +4332 948 10 +4332 970 0 +4388 1080 0 +4395 1080 0 +4396 1160 0 +4420 1460 0 +4429 1224 0 +4453 1056 0 +4470 1156 0 +4472 1156 0 +4474 1214 0 +4531 939 20 +4531 1056 0 +4533 939 20 +4552 856 30 +4558 918 20 +4617 1200 0 +4620 1200 0 +4682 1176 0 +4692 1407 0 + +# bookcase +LibraryBookcase 0x0A99 +4280 925 0 +4286 949 10 +4286 953 10 +4286 955 10 +4286 956 10 +4286 965 0 +4286 966 0 +4286 969 0 +4286 972 0 +4286 975 0 +4286 991 0 +4286 995 0 +4286 998 0 +4286 1002 0 +4300 925 0 +4300 925 20 +4312 921 0 +4320 921 0 +4326 964 0 +4326 966 0 +4326 971 0 +4326 977 0 +4326 995 0 +4384 1081 0 +4384 1108 0 +4392 1210 0 +4408 1111 0 +4408 1137 0 +4408 1202 0 +4424 1201 0 +4460 1089 0 +4460 1092 0 +4472 1083 0 +4478 1222 0 +4520 1066 0 +4534 859 30 +4552 1497 0 +4552 1501 0 +4557 927 20 +4616 1204 0 +4616 1206 0 +4648 1217 0 +4664 1393 0 +4682 1222 0 +4682 1226 0 +4682 1230 0 + +# bookcase +LibraryBookcase 0x0A9A +4280 921 0 +4286 950 10 +4286 954 10 +4286 957 10 +4286 964 0 +4286 970 0 +4286 977 0 +4286 994 0 +4286 997 0 +4286 1001 0 +4288 925 0 +4300 929 0 +4312 925 0 +4320 925 0 +4326 963 0 +4326 968 0 +4326 970 0 +4326 976 0 +4326 991 0 +4326 994 0 +4326 996 0 +4326 998 0 +4326 1003 0 +4384 1082 0 +4384 1109 0 +4392 1221 0 +4408 1112 0 +4408 1138 0 +4424 1205 0 +4447 1087 0 +4447 1088 0 +4447 1091 0 +4460 1088 0 +4460 1091 0 +4472 1084 0 +4478 1221 0 +4520 1067 0 +4534 858 30 +4552 1496 0 +4557 924 20 +4557 926 20 +4616 1203 0 +4624 1209 0 +4624 1212 0 +4664 1397 0 +4681 1177 0 +4681 1180 0 +4682 1224 0 + +# bookcase +LibraryBookcase 0x0A9B +4287 990 0 +4289 962 0 +4289 968 0 +4290 990 0 +4291 965 0 +4291 968 0 +4291 993 0 +4292 962 0 +4292 971 0 +4293 965 0 +4293 990 0 +4293 993 0 +4306 924 20 +4320 948 10 +4324 948 10 +4329 948 10 +4329 962 0 +4329 970 0 +4329 990 0 +4330 948 10 +4331 962 0 +4331 970 0 +4332 990 0 +4385 1080 0 +4386 1080 0 +4422 1460 0 +4430 1216 0 +4471 1156 0 +4533 1056 0 +4534 939 20 +4538 939 20 +4553 856 30 +4554 856 30 +4618 1200 0 +4621 1200 0 +4623 1200 0 +4683 1176 0 +4689 1407 0 + +# bookcase +LibraryBookcase 0x0A9C +4286 951 10 +4286 952 10 +4286 958 10 +4286 963 0 +4286 968 0 +4286 971 0 +4286 973 0 +4286 976 0 +4286 993 0 +4286 996 0 +4286 999 0 +4286 1003 0 +4288 921 0 +4300 929 20 +4326 965 0 +4326 969 0 +4326 972 0 +4326 973 0 +4326 975 0 +4326 992 0 +4326 997 0 +4326 999 0 +4326 1001 0 +4326 1002 0 +4392 1209 0 +4408 1139 0 +4408 1141 0 +4447 1090 0 +4447 1093 0 +4478 1220 0 +4478 1223 0 +4520 1069 0 +4534 857 30 +4534 860 30 +4534 861 30 +4552 1495 0 +4557 925 20 +4616 1201 0 +4624 1211 0 +4624 1214 0 +4681 1179 0 +4681 1182 0 +4682 1223 0 +4682 1225 0 + +# candle +CandleLarge 0x0B1A +4300 928 4 +4300 928 24 +4388 1085 6 +4392 1084 6 +4392 1211 4 +4392 1218 4 +4394 1200 4 +4394 1224 4 +4408 1203 4 +4408 1227 4 +4410 1208 4 +4410 1216 4 +4414 1466 4 +4424 1202 4 +4426 1216 4 +4426 1224 4 +4457 1063 6 +4470 1161 4 +4474 1161 4 +4478 1224 4 +4480 1217 4 +4539 859 34 +4552 860 34 +4552 1488 6 +4552 1498 4 +4553 1040 6 +4557 930 24 +4618 1202 0 +4626 1202 4 +4634 1323 4 +4648 1218 4 +4664 1394 4 +4682 1229 4 +4684 1180 4 +4684 1220 4 +4617 1204 0 +4619 1205 0 +4620 1201 0 +4621 1203 0 +4384 1063 6 +4392 1066 6 +4400 1163 6 +4424 1210 4 + +# lamp post +LampPost1 0x0B20 +4389 1075 0 +4399 1168 0 +4416 1136 0 +4419 1097 0 +4425 1116 0 +4428 1059 0 +4444 1168 0 +4471 1180 0 +4478 1071 0 + +# lamp post +LampPost2 0x0B22 +4279 928 0 +4285 983 0 +4296 964 0 +4296 1011 0 +4298 931 0 +4307 1012 0 +4313 934 0 +4313 1012 0 +4322 1011 0 +4324 964 0 +4328 927 0 +4335 983 0 +4380 1098 0 +4380 1103 0 +4395 1089 0 +4399 1121 0 +4399 1128 0 +4399 1146 0 +4400 1200 0 +4400 1215 0 +4400 1231 0 +4416 1200 0 +4416 1215 0 +4416 1231 0 +4428 1461 2 +4430 1142 0 +4432 1200 0 +4432 1215 0 +4432 1231 0 +4439 1174 0 +4445 1174 0 +4447 1072 0 +4452 1088 0 +4456 1121 0 +4456 1126 0 +4458 1088 0 +4462 1049 0 +4464 1143 0 +4469 1049 0 +4478 1134 0 +4480 1235 0 +4481 1134 0 +4539 1067 0 +4542 872 30 +4542 1047 0 +4544 947 10 +4549 872 30 +4558 944 10 +4559 1048 0 +4631 1198 0 +4632 1215 0 +4633 1329 0 +4648 1224 0 +4671 1400 0 +4686 1233 0 +4687 1423 0 +4692 1184 0 + +# candelabra +CandelabraStand 0x0B26 +4280 920 0 +4286 948 10 +4286 962 0 +4286 978 0 +4286 990 0 +4286 1004 0 +4288 920 0 +4302 948 10 +4306 922 0 +4306 922 20 +4312 920 0 +4318 948 10 +4320 920 0 +4326 962 0 +4326 978 0 +4326 990 0 +4326 1004 0 +4333 948 10 +4384 1104 0 +4384 1130 0 +4390 1104 0 +4390 1152 0 +4390 1174 0 +4398 1130 0 +4408 1056 0 +4408 1080 0 +4408 1094 0 +4408 1108 0 +4408 1114 0 +4408 1142 0 +4414 1142 0 +4422 1066 0 +4422 1108 0 +4422 1114 0 +4432 1160 0 +4446 1160 0 +4450 1094 0 +4454 1056 0 +4460 1094 0 +4480 1060 0 +4520 1056 0 +4525 939 20 +4525 945 20 +4526 1070 0 +4531 931 20 +4534 1062 0 +4549 924 20 +4557 918 20 +4560 1488 0 +4624 1208 0 +4624 1328 0 +4695 1176 0 +4416 1460 0 +4392 1160 0 +4406 1152 0 +4406 1160 0 +4470 1214 0 + +# writing table +WritingTable 0x0B49 +4522 1065 0 +4522 1069 0 +4528 1059 0 +4531 1059 0 + +# chair +WoodenChair 0x0B56 +4287 953 10 +4391 1082 0 +4520 1059 0 +4535 859 30 +4623 1202 0 + +# chair +WoodenChair 0x0B57 +4325 949 10 +4386 1084 0 + +# chair +WoodenChair 0x0B58 +4477 1154 0 +4477 1161 0 +4553 859 30 +4688 1410 0 + +# chair +WoodenChair 0x0B59 +4478 1153 0 +4627 1212 0 + +# chair +BambooChair 0x0B5A +4288 998 0 +4288 1000 0 +4329 993 0 +4329 997 0 +4329 1001 0 +4390 1132 0 +4410 1083 0 +4410 1111 0 +4411 1091 0 +4414 1083 0 +4475 1082 0 +4481 1067 0 +4526 942 20 +4551 858 30 +4551 860 30 +4683 1179 0 +4692 1410 0 + +# chair +BambooChair 0x0B5B +4289 973 0 +4291 973 0 +4329 964 0 +4329 973 0 +4331 964 0 +4331 973 0 +4386 1110 0 +4389 1065 0 +4401 1162 0 +4410 1059 0 +4413 1464 0 +4439 1158 0 +4455 1082 0 +4458 1062 0 +4469 1159 0 +4471 1159 0 +4473 1159 0 +4475 1159 0 +4481 1216 0 +4522 1057 0 +4524 1057 0 +4537 857 30 +4539 857 30 +4541 857 30 +4554 1042 0 +4555 1493 0 +4560 920 20 +4625 1200 0 +4626 1210 0 +4627 1200 0 +4628 1210 0 +4680 1408 0 +4682 1408 0 +4684 1408 0 +4685 1219 0 +4686 1408 0 +4691 1177 0 + +# chair +BambooChair 0x0B5C +4289 977 0 +4291 977 0 +4322 954 10 +4322 957 10 +4327 954 10 +4327 957 10 +4329 967 0 +4329 976 0 +4331 967 0 +4331 976 0 +4395 1201 0 +4395 1225 0 +4411 1209 0 +4411 1217 0 +4412 1137 0 +4413 1467 0 +4427 1217 0 +4427 1225 0 +4469 1163 0 +4471 1163 0 +4473 1163 0 +4475 1163 0 +4481 1219 0 +4522 1061 0 +4524 1061 0 +4536 940 20 +4537 861 30 +4539 861 30 +4541 861 30 +4554 1045 0 +4555 1496 0 +4560 923 20 +4625 1204 0 +4627 1204 0 +4680 1412 0 +4682 1412 0 +4684 1412 0 +4685 1169 0 +4685 1222 0 +4686 1412 0 +4691 1180 0 + +# chair +BambooChair 0x0B5D +4281 923 0 +4289 923 0 +4292 998 0 +4292 1000 0 +4293 951 10 +4293 956 10 +4296 951 10 +4296 956 10 +4299 951 10 +4299 956 10 +4301 927 0 +4301 927 20 +4313 923 0 +4321 923 0 +4332 993 0 +4332 997 0 +4332 1001 0 +4393 1212 0 +4393 1219 0 +4409 1204 0 +4409 1228 0 +4425 1203 0 +4425 1211 0 +4464 1154 0 +4464 1159 0 +4464 1164 0 +4479 1225 0 +4529 942 20 +4553 1499 0 +4558 929 20 +4649 1219 0 +4665 1395 0 +4683 1228 0 + +# table +Static 0x0B7E +4311 977 10 + +# table +Static 0x0B7F +4310 977 10 + +# metal signpost +Static 0x0B9E +4308 1012 0 + +# metal signpost +Static 0x0BA2 +4518 1402 21 + +# broken chair +Static 0x0C10 +4415 1083 6 + +# broken chair +Static 0x0C11 +4411 1082 6 + +# campion flowers +Static 0x0C83 +4461 1180 8 +4461 1181 8 +4461 1182 8 +4465 1180 8 +4465 1181 8 +4465 1182 8 +4469 1180 8 +4469 1181 8 +4469 1182 8 +4473 1180 8 +4473 1181 8 +4473 1182 8 +4477 1180 8 +4477 1181 8 +4477 1182 8 +4481 1180 8 +4481 1182 8 + +# poppies +Static 0x0C86 +4460 1181 8 +4460 1182 8 +4464 1180 8 +4464 1181 8 +4464 1182 8 +4468 1180 8 +4468 1181 8 +4468 1182 8 +4476 1180 8 +4476 1181 8 +4476 1182 8 +4480 1180 8 +4480 1181 8 +4480 1182 8 + +# snowdrops +Static 0x0C88 +4463 1180 8 +4463 1181 8 +4463 1182 8 +4467 1180 8 +4467 1181 8 +4467 1182 8 +4475 1180 8 +4475 1181 8 +4475 1182 8 +4479 1180 8 +4479 1181 8 +4479 1182 8 +4483 1180 8 +4483 1181 8 +4483 1182 8 + +# hedge +Static 0x0C8F +4444 1111 0 + +# orfluer flowers +Static 0x0CC1 +4462 1180 8 +4462 1182 8 +4466 1180 8 +4466 1181 8 +4466 1182 8 +4474 1180 0 +4474 1182 8 +4478 1180 8 +4478 1181 8 +4478 1182 8 +4482 1180 8 +4482 1181 8 +4482 1182 8 + +# knitting +Static 0x0DF7 +4459 1063 6 + +# pile of wool +Static 0x0DF8 (Hue=0x254) +4459 1057 0 + +# bale of cotton +Static 0x0DF9 (Hue=0x254) +4456 1056 0 + +# bloody water +Static 0x0E23 +4388 1093 0 + +# brazier +Brazier 0x0E33 +4619 1205 23 +4627 1203 23 + +# crate +FillableLargeCrate 0x0E3C +4409 1142 0 +4409 1142 3 +4410 1141 0 +4410 1142 0 +4410 1142 3 +4410 1142 6 +4411 1141 0 +4411 1142 0 +4411 1142 3 +4411 1142 6 +4412 1142 0 +4412 1142 3 + +# crate +FillableLargeCrate 0x0E3D +4408 1061 0 +4408 1061 3 +4408 1062 0 +4408 1062 3 +4408 1062 6 +4408 1066 0 +4408 1066 3 +4408 1066 6 + +# barrel +FillableBarrel 0x0E77 +4390 1023 3 +4391 1023 3 +4391 1024 -2 +4395 1045 3 +4395 1045 8 +4395 1046 3 +4395 1046 8 +4396 1045 3 +4396 1045 8 +4402 1041 3 +4403 1041 -2 +4403 1041 3 +4404 1032 -2 +4404 1032 3 +4404 1039 3 +4404 1040 -2 +4404 1040 3 +4404 1041 3 +4409 1032 -2 +4409 1032 3 +4410 1056 0 +4410 1056 5 +4411 1056 0 +4411 1056 5 +4411 1056 10 +4411 1057 0 +4412 1044 -2 +4412 1044 3 +4412 1045 -2 +4412 1056 0 +4412 1056 5 +4412 1056 10 +4412 1057 0 +4413 1044 3 +4413 1045 -2 +4413 1045 3 +4413 1056 0 +4413 1056 5 +4414 1044 3 +4416 1023 -2 +4416 1023 3 +4416 1023 8 +4416 1024 -2 +4416 1024 3 +4417 1023 -2 +4417 1023 3 +4420 1041 -2 +4421 1039 3 +4421 1040 -2 +4487 1083 25 +4487 1083 26 + +# water tub +Static 0x0E7B +4408 1033 -2 + +# strong box +FillableMetalBox 0x0E80 +4384 1111 6 +4408 1060 6 +4408 1089 6 +4410 1136 6 +4437 1159 6 +4456 1063 6 + +# pickaxe +Static 0x0E86 +4409 1068 3 + +# cleaver +Static 0x0EC2 +4384 1132 6 + +# cleaver +Static 0x0EC3 +4385 1130 6 + +# dress form +Static 0x0EC6 +4460 1068 0 + +# dress form +Static 0x0EC7 +4461 1066 0 + +# Blue Potion +Static 0x0F08 +4617 1206 27 + +# Green Potion +Static 0x0F0A +4617 1205 27 + +# Red Potion +Static 0x0F0B +4617 1202 27 + +# Purple Potion +Static 0x0F0D +4617 1201 27 + +# Batwing +Static 0x0F78 +4617 1203 27 +4623 1201 27 + +# Daemon Blood +Static 0x0F7D +4622 1201 27 + +# Mandrake Root +Static 0x0F86 +4620 1201 27 + +# Nightshade +Static 0x0F88 +4621 1201 27 + +# bolt of cloth +Static 0x0F98 +4459 1069 0 + +# bolt of cloth +Static 0x0F99 +4459 1067 0 + +# bolt of cloth +Static 0x0F9A +4459 1067 0 + +# bolt of cloth +Static 0x0F9B +4459 1064 0 + +# bolt of cloth +Static 0x0F9C +4460 1064 0 + +# sewing kit +Static 0x0F9D +4458 1068 6 + +# scissors +Scissors 0x0F9F +4458 1069 6 + +# dying tub +DyeTub 0x0FAB +4408 1467 0 + +# barrel +Static 0x0FAE +4384 1023 -2 +4384 1027 -2 +4387 1056 0 +4392 1028 -2 +4397 1023 -2 +4413 1046 -2 +4420 1040 -2 +4429 1023 -2 + +# anvil +AnvilEastAddon 0x0FAF +4438 1154 0 + +# forge +SmallForgeAddon 0x0FB1 +4440 1154 0 + +# sledge hammer +Static 0x0FB5 +4439 1154 0 + +# forged metal +Static 0x0FB7 +4441 1154 0 + +# tongs +Static 0x0FBB +4441 1155 0 + +# book +Static 0x0FBD +4280 923 4 +4288 923 4 +4288 953 14 +4300 927 4 +4300 927 24 +4312 923 4 +4320 923 4 +4391 1132 6 +4392 1082 6 +4411 1111 6 +4412 1091 6 +4476 1082 6 +4476 1161 4 +4478 1225 4 +4482 1067 6 +4521 1059 4 +4525 950 26 +4536 859 34 +4552 859 34 +4552 1499 4 +4557 929 24 +4624 1202 4 +4682 1228 4 +4684 1179 4 +4687 1410 4 +4693 1410 4 + +# book +Static 0x0FBE +4322 953 14 +4322 956 14 +4325 950 14 +4327 953 14 +4327 956 14 +4386 1111 6 +4389 1066 6 +4401 1163 6 +4410 1060 6 +4412 1136 6 +4439 1159 6 +4455 1083 6 +4458 1063 6 +4487 1214 6 +4536 939 24 +4566 918 26 +4627 1211 4 +4685 1168 4 + +# pen and ink +Static 0x0FBF +4280 923 4 +4288 923 4 +4288 953 14 +4300 927 4 +4300 927 24 +4312 923 4 +4320 923 4 +4391 1132 6 +4392 1082 6 +4411 1111 6 +4412 1091 6 +4476 1082 6 +4476 1161 4 +4478 1225 4 +4482 1067 6 +4521 1059 4 +4536 859 34 +4552 859 34 +4552 1499 4 +4557 929 24 +4624 1202 4 +4682 1228 4 +4684 1179 4 +4687 1410 4 +4693 1410 4 + +# pen and ink +Static 0x0FC0 +4322 953 14 +4322 956 14 +4325 950 14 +4327 953 14 +4327 956 14 +4386 1111 6 +4389 1066 6 +4401 1163 6 +4410 1060 6 +4412 1136 6 +4439 1159 6 +4455 1083 6 +4458 1063 6 +4536 939 24 +4627 1211 4 +4685 1168 4 + +# paints and brush +Static 0x0FC1 +4523 1065 0 +4523 1068 0 +4529 1059 0 +4532 1059 0 + +# pewter mug +PewterMug 0x0FFF +4692 1178 4 + +# pewter mug +PewterMug 0x1000 +4555 1043 4 + +# pewter mug +PewterMug 0x1001 +4528 941 24 +4559 921 24 + +# pewter mug +PewterMug 0x1002 +4527 941 24 +4553 1044 4 +4559 922 24 +4690 1179 4 + +# archery butte +ArcheryButte 0x100B +4489 1118 0 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +4457 1057 0 + +# hammer +Static 0x102A +4411 1083 6 +4415 1084 6 + +# nails +Static 0x102F +4411 1083 6 +4415 1084 6 + +# jointing plane +Static 0x1031 +4419 1081 6 + +# saw +Static 0x1035 +4411 1084 6 +4415 1082 6 +4419 1081 6 + +# sack of flour +Static 0x1039 +4384 1069 0 +4386 1056 0 +4386 1057 0 +4389 1061 0 +4393 1064 0 +4394 1064 0 + +# open sack of flour +Static 0x103A +4384 1059 6 +4389 1062 0 +4393 1065 0 +4410 1463 0 + +# rolling pin +Static 0x1043 +4384 1060 6 +4408 1462 6 + +# loom bench +Static 0x104A +4457 1058 0 +4461 1058 0 + +# clock frame +ClockFrame 0x104D +4463 1154 6 +4463 1160 6 +4463 1165 6 +4476 1154 6 + +# clock parts +ClockParts 0x104F +4463 1153 6 +4463 1163 6 +4476 1154 6 + +# axle with gears +AxleGears 0x1051 +4463 1159 6 + +# gears +Gears 0x1053 +4463 1163 6 +4476 1153 6 + +# gears +Gears 0x1054 +4463 1155 6 + +# hinge +Hinge 0x1055 +4463 1159 6 + +# sextant +Static 0x1057 +4463 1155 6 +4478 1152 6 + +# sextant parts +SextantParts 0x1059 +4477 1152 6 + +# sextant parts +SextantParts 0x105A +4463 1160 6 + +# axle +Axle 0x105B +4463 1164 6 + +# springs +Springs 0x105D +4463 1164 6 +4476 1152 6 + +# upright loom +LoomSouthAddon 0x1065 +4460 1057 0 + +# training dummy +TrainingDummyEastAddon 0x1074 +4384 1113 0 + +# potted tree +PottedTree1 0x11C9 +4300 924 0 +4305 916 20 +4384 1080 0 +4392 1208 0 +4392 1224 0 +4393 1200 0 +4400 1152 0 +4408 1208 0 +4408 1224 0 +4408 1456 0 +4413 1216 0 +4424 1209 0 +4424 1224 0 +4425 1216 0 +4448 1056 0 +4448 1064 0 +4472 1080 0 +4472 1086 0 +4478 1227 0 +4525 931 20 +4550 1040 0 +4552 1493 0 +4554 918 20 +4624 1334 0 +4629 1208 0 +4648 1216 0 +4682 1217 0 + +# flowerpot +PottedPlant 0x11CA +4300 924 20 +4392 1217 0 +4408 1201 0 +4418 1460 0 +4421 1460 0 +4478 1214 0 +4485 1060 0 +4544 1040 0 +4681 1168 0 +4681 1176 0 +4690 1217 0 + +# flowerpot +PottedPlant1 0x11CB +4384 1085 9 +4399 1160 9 +4403 1163 9 +4412 1089 9 +4476 1084 9 +4482 1069 9 +4683 1410 4 + +# flowerpot +PottedPlant2 0x11CC +4399 1163 9 + +# altar +Static 0x1216 +4545 851 30 +4619 1203 0 +4627 1207 20 + +# teleporter: recdu +KeywordTeleporter 0x1BC3 (Substring=recdu; Range=4; PointDest=(5735, 3195, 10)) +4545 851 30 + +# teleporter +Teleporter 0x1BC3 (PointDest=(4622, 1204, 23)) +4619 1203 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(4633, 1202, 0)) +4627 1207 20 + +# statue +Static 0x12D8 +4462 1181 8 +4481 1181 8 + +# moulding board +Static 0x14E9 +4387 1066 6 + +# moulding board +Static 0x14EA +4384 1061 6 + +# rope +Static 0x14F8 +4392 1040 -3 +4416 1040 -3 + +# rope +Static 0x14FA +4391 1027 -3 +4394 1046 -3 +4409 1033 -3 +4421 1028 -3 + +# lockpick +Static 0x14FB +4645 1312 0 + +# water barrel +Static 0x154D +4390 1023 -2 +4391 1023 -2 +4395 1045 -2 +4395 1046 -2 +4396 1045 -2 +4402 1041 -2 +4404 1033 -2 +4404 1039 -2 +4404 1041 -2 +4413 1044 -2 +4414 1044 -2 +4421 1039 -2 + +# wooden bowl +Static 0x15F8 +4408 1462 6 + +# pewter bowl +Static 0x15FD +4557 1488 6 +4624 1325 6 + +# large pewter bowl +Static 0x1603 +4384 1062 6 +4384 1135 6 +4411 1462 6 +4630 1320 6 + +# fountain +StoneFountainAddon 0x173A +4310 954 10 +4472 1182 11 + +# grass +Static 0x1781 +4704 1120 0 +4708 1111 0 +4708 1121 0 + +# grass +Static 0x1782 +4484 1096 0 + +# teleporter +Static 0x17DC +4449 1115 5 + +# teleporter +Static 0x17E5 +4436 1107 5 + +# teleporter +Static 0x17EE +4443 1137 5 +4449 1107 5 + +# teleporter +Static 0x1809 +4300 968 5 +4496 1475 15 +4540 898 32 +4663 1134 13 + +# flask +Static 0x183C +4628 1201 29 + +# flask +Static 0x183D +4627 1213 29 + +# flask +Static 0x183F +4626 1213 29 + +# flask +Static 0x1841 +4629 1213 29 + +# flask +Static 0x1846 +4628 1213 29 + +# scales +Static 0x1851 +4453 1083 6 +4627 1201 29 + +# skull with candle +CandleSkull 0x1854 +4488 1216 0 +4490 1218 0 +4527 949 20 +4529 951 20 +4544 850 30 +4546 852 30 +4567 920 20 +4569 922 20 +4626 1206 20 +4628 1208 20 +4673 1409 0 +4675 1411 0 + +# skull with candle +CandleSkull 0x1858 +4457 1083 6 +4488 1218 0 +4490 1216 0 +4527 951 20 +4529 949 20 +4544 852 30 +4546 850 30 +4567 922 20 +4569 920 20 +4626 1208 20 +4628 1206 20 +4673 1411 0 +4675 1409 0 +4681 1410 4 +4685 1410 4 + +# empty vials +Static 0x185B +4457 1082 6 +4626 1201 29 +4629 1201 29 + +# full vials +Static 0x185E +4457 1081 6 + +# bulletin board +BulletinBoard 0x1E5E +4404 1160 0 + +# skinned goat +Static 0x1E88 +4384 1133 6 + +# pig's feet +Static 0x1E8D +4386 1130 6 + +# pig's head +Static 0x1E8F +4388 1130 6 + +# Beware - animals cannot survive the journey through this portal! +LocalizedSign 0x1F29 (LabelNumber=1016062) +4545 848 47 + +# no draw +Blocker 0x21A4 +4704 1120 0 +4708 1121 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/nujelm.cfg b/Data/Decoration/Britannia/nujelm.cfg new file mode 100644 index 0000000..0c42b52 --- /dev/null +++ b/Data/Decoration/Britannia/nujelm.cfg @@ -0,0 +1,2121 @@ +######### +# Doors # +######### + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +3677 1316 20 +3683 1315 20 +3688 1237 20 +3690 1239 0 +3692 1315 20 +3763 1320 0 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +3678 1316 20 +3684 1315 20 +3688 1240 20 +3693 1315 20 +3764 1320 0 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +3682 1240 20 +3695 1280 20 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +3682 1239 20 +3695 1279 20 + +# barred metal door +BarredMetalDoor 0x0687 (Facing=EastCCW) +3727 1399 0 + +# barred metal door +BarredMetalDoor 0x068B (Facing=EastCW) +3709 1382 0 + +# iron gate +IronGateShort 0x084C (Facing=WestCW) +3536 1152 20 + +# iron gate +IronGateShort 0x084E (Facing=EastCCW) +3537 1152 20 + + +############ +# Standard # +############ + +# stone roof +Static 0x0637 +3691 1297 40 + +# oven +StoneOvenEastAddon 0x092C +3728 1335 0 +3728 1337 0 + +# oven +StoneOvenSouthAddon 0x0930 +3733 1264 -2 +3735 1264 -2 +3691 1296 20 + +# slab of bacon +Static 0x0976 +3687 1297 24 +3729 1249 13 +3731 1261 5 + +# slab of bacon +Static 0x0977 +3740 1249 10 + +# wedge of cheese +CheeseWedge 0x097D +3649 1144 4 +3651 1136 4 +3651 1168 4 + +# wheel of cheese +CheeseWheel 0x097E +3683 1115 4 + +# fruit basket +FruitBasket 0x0993 +3648 1114 4 +3648 1120 4 +3648 1122 4 +3657 1169 4 +3688 1301 22 +3692 1261 24 +3692 1265 24 +3699 1261 24 +3699 1265 24 +3747 1252 4 +3768 1171 4 +3778 1250 8 +3778 1251 8 +3788 1121 30 + +# ceramic mug +CeramicMug 0x0995 +3771 1227 4 + +# ceramic mug +CeramicMug 0x0996 +3768 1173 4 +3768 1173 8 +3769 1173 6 +3769 1173 9 + +# ceramic mug +CeramicMug 0x0997 +3683 1115 4 +3683 1116 6 +3684 1115 4 +3684 1116 4 +3731 1261 7 + +# mug +CeramicMug 0x0998 +3734 1248 4 +3734 1250 4 +3738 1259 6 +3739 1248 4 +3739 1258 6 + +# mug +CeramicMug 0x0999 +3735 1254 4 +3735 1255 4 +3736 1254 4 +3739 1250 4 + +# goblet +Goblet 0x099A +3746 1250 4 +3746 1251 4 +3746 1252 11 +3748 1250 4 +3748 1251 11 +3748 1252 11 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +3731 1257 5 +3736 1254 4 +3771 1222 4 +3772 1222 4 + +# bottles of liquor +Static 0x099C +3774 1232 2 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +3731 1255 5 +3736 1255 4 +3771 1221 4 +3772 1223 4 + +# bottles of ale +Static 0x09A2 +3766 1233 5 +3766 1236 4 +3766 1237 4 + +# glass pitcher +Pitcher 0x09A7 +3659 1072 6 +3672 1068 6 +3675 1072 6 + +# metal box +FillableMetalBox 0x09A8 +3771 1160 7 + +# metal chest +MetalChest 0x09AB +3657 1187 0 +3682 1186 0 + +# goblet +Goblet 0x09B3 +3697 1290 24 +3697 1291 24 +3697 1293 24 +3697 1295 24 +3697 1297 24 +3697 1299 24 +3699 1291 32 +3699 1293 32 +3699 1295 32 +3699 1297 32 +3699 1299 32 +3699 1300 32 +3770 1227 4 + +# eggs +Eggs 0x09B5 +3687 1296 25 + +# cooked bird +CookedBird 0x09B7 +3746 1264 6 + +# cooked bird +CookedBird 0x09B8 +3687 1301 22 + +# raw bird +RawBird 0x09B9 +3552 1170 6 +3552 1171 6 + +# roast pig +RoastPig 0x09BB +3695 1259 25 +3742 1264 6 + +# roast pig +RoastPig 0x09BC +3747 1251 4 + +# silverware +Static 0x09BD +3594 1232 4 +3594 1234 4 +3691 1259 24 +3691 1261 24 +3691 1263 24 +3691 1265 24 +3697 1291 24 +3697 1293 24 +3697 1295 24 +3697 1297 24 +3697 1299 24 +3730 1327 4 +3730 1329 4 +3734 1248 4 +3734 1250 4 +3738 1327 4 +3739 1248 4 +3739 1250 4 +3745 1331 4 +3745 1333 4 +3746 1251 4 +3771 1129 24 +3771 1131 24 + +# silverware +Static 0x09BE +3594 1231 4 +3596 1231 4 +3694 1258 22 +3696 1258 22 +3698 1258 22 +3698 1290 24 +3731 1326 4 +3739 1326 4 +3740 1337 4 +3743 1337 4 +3746 1250 4 +3746 1330 4 +3747 1338 4 +3748 1250 4 +3772 1128 24 + +# goblet +Goblet 0x09BF +3595 1232 4 +3692 1260 27 +3692 1262 27 +3692 1264 27 +3692 1266 27 +3694 1259 23 +3697 1259 22 +3698 1258 22 +3700 1259 24 +3700 1261 24 +3700 1263 24 +3700 1265 24 + +# sausage +Sausage 0x09C0 +3552 1172 6 +3552 1173 6 + +# bottles of wine +Static 0x09C4 +3766 1238 4 + +# bottles of wine +Static 0x09C6 +3735 1254 4 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +3730 1255 5 +3735 1255 4 + +# ham +Ham 0x09C9 +3552 1168 6 +3552 1169 6 +3745 1264 6 + +# ceramic mug +CeramicMug 0x09CA +3656 1058 6 +3656 1061 6 +3657 1096 4 +3657 1097 4 +3771 1227 4 + +# fish +Static 0x09CD +3749 1266 6 + +# fish +Static 0x09CF +3749 1265 6 + +# ham +Static 0x09D3 +3687 1296 22 + +# silverware +Static 0x09D4 +3595 1235 4 +3596 1235 4 +3698 1300 24 +3728 1250 4 +3731 1330 4 +3739 1328 4 +3740 1339 4 +3743 1339 4 +3746 1252 4 +3746 1334 4 +3746 1339 4 +3748 1252 4 +3772 1132 24 + +# silverware +Static 0x09D5 +3699 1291 24 +3699 1293 24 +3699 1295 24 +3699 1297 24 +3699 1299 24 +3700 1259 24 +3700 1261 24 +3700 1263 24 +3700 1265 24 +3729 1248 4 +3729 1250 4 +3731 1261 5 +3732 1327 4 +3732 1329 4 +3735 1248 4 +3735 1250 4 +3740 1248 4 +3740 1250 4 +3740 1327 4 +3747 1331 4 +3747 1333 4 +3748 1251 4 +3773 1129 24 +3773 1131 24 + +# pitcher +Static 0x09D6 +3594 1233 4 +3597 1235 4 +3656 1096 4 +3656 1168 4 +3666 1056 6 +3672 1076 6 +3674 1056 6 +3688 1164 2 + +# plate +Plate 0x09D7 +3594 1231 4 +3594 1232 4 +3594 1234 4 +3595 1235 4 +3596 1231 4 +3596 1235 4 +3650 1169 4 +3651 1137 4 +3651 1169 4 +3652 1137 4 +3656 1169 4 +3657 1096 4 +3657 1097 4 +3657 1168 4 +3666 1096 4 +3666 1097 4 +3667 1097 4 +3682 1115 4 +3683 1114 4 +3683 1116 4 +3684 1115 4 +3689 1164 2 +3689 1165 2 +3691 1259 24 +3691 1261 24 +3691 1263 24 +3691 1265 24 +3694 1258 22 +3696 1258 22 +3697 1291 24 +3697 1293 24 +3697 1295 24 +3697 1297 24 +3697 1299 24 +3698 1258 22 +3698 1290 24 +3698 1300 24 +3699 1291 24 +3699 1293 24 +3699 1295 24 +3699 1297 24 +3699 1299 24 +3700 1259 24 +3700 1261 24 +3700 1263 24 +3700 1265 24 +3729 1249 12 +3730 1327 4 +3730 1329 4 +3731 1326 4 +3731 1330 4 +3732 1327 4 +3732 1329 4 +3735 1249 8 +3738 1264 6 +3738 1327 4 +3739 1326 4 +3739 1328 4 +3740 1249 9 +3740 1327 4 +3740 1337 4 +3740 1339 4 +3743 1337 4 +3743 1339 4 +3745 1331 4 +3745 1333 4 +3746 1250 4 +3746 1251 4 +3746 1252 4 +3746 1330 4 +3746 1334 4 +3746 1339 4 +3747 1331 4 +3747 1333 4 +3747 1338 4 +3748 1250 4 +3748 1251 4 +3748 1252 4 +3771 1129 24 +3771 1131 24 +3772 1128 24 +3772 1132 24 +3773 1129 24 +3773 1131 24 + +# plate of food +Static 0x09D8 +3728 1250 4 +3729 1248 4 +3729 1250 4 +3731 1259 5 +3734 1248 4 +3734 1250 4 +3735 1248 4 +3735 1250 4 +3736 1400 4 +3739 1248 4 +3739 1250 4 +3740 1248 4 +3740 1250 4 + +# plate of food +Static 0x09D9 +3735 1400 4 + +# pot +Static 0x09E0 +3732 1334 2 +3747 1264 6 + +# frypan +Static 0x09E2 +3688 1296 26 +3732 1335 2 + +# pot +Static 0x09E3 +3691 1301 22 +3748 1264 6 + +# pot +Static 0x09E4 +3735 1335 2 + +# cake +Cake 0x09E9 +3680 1296 24 +3680 1299 24 + +# muffins +Muffins 0x09EB +3680 1300 24 + +# kettle +Static 0x09ED +3690 1301 22 +3734 1335 2 +3743 1264 0 + +# mug of ale +GlassMug 0x09EE (Content=Ale) +3594 1235 4 +3595 1235 4 +3596 1232 4 +3596 1235 4 +3731 1255 5 +3731 1259 5 +3736 1255 4 +3740 1250 4 + +# mug of ale +GlassMug 0x09EF (Content=Ale) +3728 1250 4 +3729 1248 4 +3729 1250 4 +3730 1255 5 +3735 1248 4 +3735 1250 4 +3740 1248 4 +3766 1219 4 +3766 1224 4 +3766 1225 4 +3767 1219 4 +3767 1220 4 +3767 1224 4 +3767 1225 4 + +# milk +Pitcher 0x09F0 (Content=Milk) +3692 1260 24 +3692 1264 24 +3697 1259 22 +3698 1291 24 +3698 1295 24 +3698 1299 24 +3699 1260 24 +3699 1264 24 +3739 1259 9 +3768 1172 4 + +# cut of raw ribs +RawRibs 0x09F1 +3688 1296 22 +3735 1249 9 + +# pan +Static 0x09F3 +3734 1334 2 + +# knife +Knife 0x09F6 +3745 1264 6 + +# spoon +Spoon 0x09F9 +3731 1259 5 + +# muffins +Static 0x09FA +3680 1301 24 + +# stool +Stool 0x0A2A +3684 1233 0 +3714 1402 0 +3717 1402 0 +3773 1161 0 +3784 1133 20 + +# stool +Static 0x0A2B +3735 1302 2 + +# chest of drawers +Drawer 0x0A2C +3593 1192 0 +3593 1208 0 +3593 1224 0 +3596 1192 0 +3596 1200 0 +3597 1208 0 +3601 1208 0 +3603 1208 0 +3605 1232 0 +3609 1208 0 +3618 1248 0 +3619 1256 0 +3625 1224 0 +3626 1208 0 +3649 1136 0 +3650 1112 0 +3651 1160 0 +3652 1120 0 +3664 1128 0 +3665 1128 0 +3668 1106 0 +3675 1144 0 +3676 1144 0 +3677 1128 0 +3733 1295 2 +3737 1289 2 +3737 1295 2 +3737 1301 1 +3747 1184 0 +3747 1288 0 +3748 1184 0 +3762 1232 0 +3787 1128 22 + +# chest of drawers +FancyDrawer 0x0A30 +3734 1323 24 + +# chest of drawers +Drawer 0x0A34 +3592 1225 0 +3600 1235 0 +3608 1209 0 +3616 1249 0 +3616 1261 0 +3616 1265 0 +3616 1269 0 +3624 1213 0 +3624 1225 0 +3648 1140 0 +3648 1148 0 +3648 1160 0 +3648 1172 0 +3662 1097 0 +3662 1102 0 +3664 1108 0 +3672 1133 0 +3675 1237 21 +3680 1100 0 +3680 1106 0 +3687 1232 20 +3688 1106 0 +3688 1161 0 +3688 1162 0 +3728 1299 0 +3744 1301 0 +3760 1251 21 + +# dresser +Static 0x0A44 +3674 1319 20 +3689 1326 20 + +# dresser +Static 0x0A45 +3674 1318 20 +3689 1325 20 + +# armoire +Armoire 0x0A4F +3733 1301 1 +3745 1297 2 +3746 1289 1 + +# armoire +FancyArmoire 0x0A51 +3687 1244 20 +3689 1318 20 +3689 1319 20 +3735 1309 20 +3735 1322 21 + +# armoire +Armoire 0x0A53 +3648 1171 0 +3672 1321 20 +3675 1241 20 +3687 1235 20 +3728 1293 0 +3783 1130 20 + +# bedroll +Static 0x0A55 +3594 1201 0 +3594 1203 0 +3594 1205 0 +3601 1211 0 +3601 1213 0 +3609 1211 0 +3617 1251 0 +3617 1253 0 +3625 1227 0 +3625 1245 0 +3730 1406 0 +3730 1409 0 +3733 1406 0 +3733 1409 0 +3736 1406 0 +3736 1409 0 + +# bedroll +Static 0x0A56 +3605 1210 0 +3612 1209 0 +3625 1243 0 +3627 1225 0 +3629 1225 0 +3629 1241 0 +3730 1403 0 +3732 1403 0 +3734 1403 0 +3736 1403 0 + +# bedroll +Static 0x0A58 +3592 1202 0 +3600 1208 0 +3608 1212 0 + +# bedroll +Static 0x0A59 +3610 1208 0 + +# bed +Static 0x0A5A +3593 1196 0 +3593 1211 0 +3593 1213 0 +3593 1227 0 +3601 1234 0 +3609 1260 0 +3617 1258 0 +3617 1260 0 +3617 1267 0 +3625 1212 0 +3649 1116 0 +3649 1118 0 +3649 1139 0 +3649 1147 0 +3649 1161 0 +3649 1164 0 +3657 1060 0 +3657 1073 0 +3657 1075 0 +3663 1096 0 +3663 1099 0 +3663 1101 0 +3665 1057 0 +3665 1059 0 +3665 1061 0 +3665 1149 0 +3665 1151 0 +3673 1062 0 +3673 1067 0 +3673 1072 0 +3673 1074 0 +3673 1132 0 +3673 1144 0 +3673 1146 0 +3673 1148 0 +3681 1096 0 +3681 1099 0 +3691 1128 0 +3761 1253 21 + +# bed +Static 0x0A5B +3592 1196 0 +3592 1211 0 +3592 1213 0 +3592 1227 0 +3600 1234 0 +3608 1260 0 +3616 1258 0 +3616 1260 0 +3616 1267 0 +3624 1212 0 +3648 1116 0 +3648 1118 0 +3648 1139 0 +3648 1147 0 +3648 1161 0 +3648 1164 0 +3656 1060 0 +3656 1073 0 +3656 1075 0 +3662 1096 0 +3662 1099 0 +3662 1101 0 +3664 1057 0 +3664 1059 0 +3664 1061 0 +3664 1149 0 +3664 1151 0 +3672 1062 0 +3672 1067 0 +3672 1072 0 +3672 1074 0 +3672 1132 0 +3672 1144 0 +3672 1146 0 +3672 1148 0 +3680 1096 0 +3680 1099 0 +3690 1128 0 +3760 1253 21 + +# bed +Static 0x0A64 +3595 1224 0 +3608 1256 0 +3610 1256 0 +3618 1264 0 +3620 1256 0 +3620 1264 0 +3624 1209 0 +3627 1208 0 +3648 1136 0 +3651 1120 0 +3652 1144 0 +3652 1160 0 +3656 1056 0 +3658 1056 0 +3660 1056 0 +3660 1072 0 +3664 1146 0 +3666 1146 0 +3667 1056 0 +3667 1128 0 +3669 1056 0 +3672 1056 0 +3672 1059 0 +3672 1064 0 +3674 1064 0 +3675 1056 0 +3676 1064 0 +3676 1072 0 +3676 1128 0 +3677 1056 0 +3688 1128 0 +3689 1104 0 +3690 1160 0 +3691 1104 0 +3693 1160 0 +3769 1248 21 + +# bed +Static 0x0A65 +3595 1225 0 +3608 1257 0 +3610 1257 0 +3618 1265 0 +3620 1257 0 +3620 1265 0 +3624 1210 0 +3627 1209 0 +3648 1137 0 +3651 1121 0 +3652 1145 0 +3652 1161 0 +3656 1057 0 +3658 1057 0 +3660 1057 0 +3660 1073 0 +3664 1147 0 +3666 1147 0 +3667 1057 0 +3667 1129 0 +3669 1057 0 +3672 1057 0 +3672 1060 0 +3672 1065 0 +3674 1065 0 +3675 1057 0 +3676 1065 0 +3676 1073 0 +3676 1129 0 +3677 1057 0 +3688 1129 0 +3689 1105 0 +3690 1161 0 +3691 1105 0 +3693 1161 0 +3769 1249 21 + +# bed +LargeBedEastAddon 0x0A7D +3689 1323 20 +3728 1289 0 +3728 1296 0 +3728 1303 0 +3744 1290 0 + +# bed +LargeBedSouthAddon 0x0A83 +3678 1237 20 +3690 1232 20 +3691 1241 20 + +# bookcase +LibraryBookcase 0x0A97 +3677 1312 0 +3679 1312 0 +3681 1312 0 +3729 1192 0 + +# bookcase +LibraryBookcase 0x0A98 +3682 1312 0 +3683 1312 0 +3684 1312 0 +3686 1312 0 +3687 1312 0 +3690 1312 0 +3704 1224 0 +3705 1224 0 +3779 1120 20 + +# bookcase +LibraryBookcase 0x0A99 +3674 1313 0 +3674 1314 0 +3674 1315 0 +3681 1320 20 +3704 1226 0 +3728 1192 0 +3728 1193 0 +3728 1195 0 +3728 1200 0 +3728 1202 0 +3760 1232 0 +3762 1186 30 +3762 1187 30 +3762 1188 30 +3762 1189 30 +3762 1190 30 +3762 1191 30 + +# bookcase +LibraryBookcase 0x0A9A +3681 1319 20 +3696 1217 0 +3728 1194 0 +3728 1196 0 +3728 1201 0 + +# bookcase +LibraryBookcase 0x0A9B +3675 1312 0 +3676 1312 0 +3678 1312 0 +3680 1312 0 +3685 1312 0 +3688 1312 0 +3689 1312 0 +3733 1192 0 +3734 1192 0 +3778 1120 20 +3784 1120 21 + +# bookcase +LibraryBookcase 0x0A9C +3681 1321 20 +3696 1218 0 +3704 1227 0 +3704 1228 0 +3728 1203 0 +3728 1204 0 +3728 1205 0 + +# candle +CandleLarge 0x0B1A +3746 1338 4 +3747 1339 4 + +# candelabra +Candelabra 0x0B1D +3685 1318 26 +3728 1197 7 +3730 1192 6 +3730 1204 7 +3739 1327 6 +3740 1338 6 +3743 1338 6 +3746 1295 4 +3746 1302 4 +3746 1331 6 +3746 1333 6 +3760 1250 6 +3767 1250 26 +3772 1130 26 +3773 1120 26 +3676 1321 6 +3677 1313 6 +3678 1321 5 +3679 1313 4 +3686 1320 4 +3687 1313 4 +3688 1320 4 +3689 1313 4 +3692 1262 24 +3692 1266 24 +3693 1259 22 +3698 1259 22 +3699 1262 24 +3699 1266 24 +3731 1327 6 +3731 1329 6 +3698 1292 26 +3698 1294 26 +3698 1296 26 +3698 1298 26 + +# lamp post +LampPost3 0x0B24 +3660 1199 0 +3660 1208 0 +3667 1188 0 +3670 1330 0 +3670 1335 0 +3674 1330 0 +3675 1188 0 +3681 1330 0 +3681 1335 0 +3705 1213 0 +3705 1216 0 +3720 1208 0 +3720 1226 0 +3720 1229 0 +3720 1240 0 +3720 1247 0 +3720 1344 0 +3720 1351 0 +3722 1276 0 +3722 1283 0 +3725 1376 3 +3725 1382 3 +3727 1240 0 +3727 1272 0 +3727 1344 0 +3727 1351 0 +3731 1376 3 +3731 1382 3 +3732 1391 0 +3732 1397 0 +3739 1398 0 +3747 1240 0 +3752 1176 0 +3752 1183 0 +3752 1208 0 +3752 1215 0 +3752 1235 0 +3752 1240 0 +3752 1247 0 +3752 1256 0 +3752 1262 0 +3752 1272 5 +3752 1287 5 +3752 1344 0 +3759 1208 0 +3759 1240 0 +3759 1272 5 +3759 1287 5 +3759 1304 0 +3760 1152 0 +3760 1159 0 +3760 1176 0 +3767 1152 0 +3767 1176 0 +3776 1152 24 +3776 1200 0 +3776 1204 0 +3776 1287 0 +3780 1200 0 +3780 1204 0 +3783 1152 24 +3783 1287 0 +3784 1176 0 +3784 1183 0 +3784 1200 0 +3784 1204 0 +3784 1224 0 +3784 1229 0 +3784 1272 0 +3791 1176 0 +3791 1183 0 +3791 1272 0 + +# candelabra +CandelabraStand 0x0B26 +3675 1235 20 +3675 1243 20 +3680 1256 20 +3680 1262 20 +3680 1265 20 +3680 1270 20 +3680 1288 20 +3680 1294 20 +3681 1235 20 +3681 1243 20 +3683 1240 0 +3683 1246 0 +3687 1246 20 +3690 1241 20 +3694 1232 20 +3694 1236 20 +3694 1240 0 +3694 1241 20 +3694 1246 0 +3728 1288 0 +3728 1295 0 +3728 1301 0 +3730 1308 0 +3735 1288 0 +3735 1320 20 +3736 1304 20 +3760 1252 20 +3763 1186 30 +3768 1120 20 +3768 1166 0 +3768 1174 0 +3770 1184 30 +3770 1191 30 +3782 1166 0 +3782 1174 0 +3790 1134 20 +3674 1312 0 +3674 1326 0 +3680 1326 0 + +# wooden bench +WoodenBench 0x0B2C +3760 1290 0 +3760 1291 0 +3760 1292 0 +3760 1293 0 +3760 1298 0 +3760 1299 0 +3760 1300 0 +3765 1288 0 +3765 1289 0 +3765 1290 0 +3772 1288 0 +3772 1289 0 +3772 1290 0 +3772 1291 0 +3772 1292 0 +3772 1298 0 +3772 1299 0 +3772 1300 0 +3772 1301 0 + +# wooden bench +WoodenBench 0x0B2D +3762 1291 0 +3762 1302 0 +3763 1291 0 +3763 1302 0 +3764 1291 0 +3764 1302 0 +3769 1302 0 +3770 1288 0 +3770 1302 0 +3771 1288 0 +3771 1302 0 +3772 1302 0 + +# wooden chair +WoodenThrone 0x0B2F +3675 1322 0 +3676 1314 0 +3685 1321 0 +3686 1314 0 + +# wooden chair +WoodenThrone 0x0B30 +3679 1322 0 +3680 1314 0 +3689 1321 0 +3690 1314 0 +3768 1188 30 + +# throne +Throne 0x0B32 +3694 1257 20 +3696 1257 20 +3698 1257 20 + +# chair +FancyWoodenChairCushion 0x0B4E +3690 1259 20 +3690 1261 20 +3690 1263 20 +3690 1265 20 +3696 1291 21 +3696 1293 21 +3696 1295 21 +3696 1297 20 +3696 1299 20 +3705 1227 0 +3729 1327 0 +3729 1329 0 +3737 1327 0 +3744 1331 0 +3744 1333 0 +3760 1315 0 +3770 1129 21 +3770 1131 21 +3783 1125 20 +3786 1121 21 + +# chair +FancyWoodenChairCushion 0x0B4F +3698 1289 21 +3710 1224 0 +3714 1224 0 +3731 1325 0 +3738 1325 21 +3739 1325 0 +3740 1336 0 +3743 1336 0 +3746 1329 0 +3747 1301 1 +3747 1337 0 +3772 1127 21 + +# chair +FancyWoodenChairCushion 0x0B50 +3698 1301 20 +3731 1331 0 +3733 1289 0 +3739 1329 0 +3740 1340 0 +3743 1340 0 +3746 1335 0 +3746 1340 0 +3761 1236 0 +3768 1169 0 +3770 1169 0 +3772 1133 21 + +# chair +FancyWoodenChairCushion 0x0B51 +3686 1319 20 +3700 1291 21 +3700 1293 21 +3700 1295 21 +3700 1297 20 +3700 1299 20 +3701 1259 20 +3701 1261 20 +3701 1263 20 +3701 1265 20 +3733 1327 0 +3733 1329 0 +3741 1327 0 +3748 1331 0 +3748 1333 0 +3774 1122 20 +3774 1129 21 +3774 1131 21 +3789 1120 20 +3790 1124 20 + +# chair +WoodenChairCushion 0x0B53 +3731 1203 0 +3739 1309 20 +3747 1294 0 +3769 1167 0 + +# chair +WoodenChairCushion 0x0B54 +3710 1229 0 +3714 1229 0 +3731 1193 0 + +# chair +WoodenChairCushion 0x0B55 +3729 1198 0 +3762 1253 4 + +# chair +WoodenChair 0x0B56 +3648 1145 0 +3650 1137 0 +3683 1096 0 +3713 1396 0 +3733 1248 0 +3733 1250 0 +3734 1254 0 +3737 1258 0 +3738 1248 0 +3738 1250 0 +3745 1251 0 + +# chair +WoodenChair 0x0B57 +3648 1112 0 +3665 1129 0 +3688 1107 0 +3689 1163 0 +3699 1209 0 +3701 1209 0 +3736 1253 0 +3739 1257 0 +3746 1249 0 +3748 1249 0 + +# chair +WoodenChair 0x0B58 +3650 1144 0 +3653 1137 0 +3658 1096 0 +3658 1168 0 +3681 1105 0 +3686 1096 0 +3689 1109 0 +3690 1165 0 +3730 1248 0 +3730 1250 0 +3736 1248 0 +3736 1250 0 +3737 1255 0 +3740 1259 0 +3741 1248 0 +3741 1250 0 +3749 1251 0 + +# chair +WoodenChair 0x0B59 +3648 1115 0 +3650 1170 0 +3651 1138 0 +3651 1170 0 +3656 1170 0 +3657 1098 0 +3664 1132 0 +3693 1129 0 +3694 1129 0 +3699 1212 0 +3701 1212 0 +3728 1251 0 +3735 1256 0 +3738 1260 0 +3746 1253 0 +3748 1253 0 + +# chair +BambooChair 0x0B5A +3592 1194 0 +3593 1232 0 +3593 1234 0 +3595 1205 0 +3600 1232 0 +3648 1163 0 +3665 1096 0 +3665 1156 0 +3681 1115 0 +3761 1219 0 +3761 1223 0 +3761 1227 0 +3765 1219 0 +3765 1224 0 +3769 1227 0 +3770 1222 0 + +# chair +BambooChair 0x0B5B +3594 1192 0 +3594 1230 0 +3596 1230 0 +3612 1256 0 +3625 1240 0 +3627 1240 0 +3667 1154 0 +3683 1113 0 +3766 1217 0 +3766 1222 0 +3770 1225 0 +3771 1220 0 + +# chair +BambooChair 0x0B5C +3594 1236 0 +3596 1236 0 +3648 1124 0 +3666 1098 0 +3667 1158 0 +3683 1117 0 +3767 1226 0 + +# chair +BambooChair 0x0B5D +3602 1232 0 +3649 1120 0 +3649 1122 0 +3668 1097 0 +3685 1115 0 +3763 1219 0 +3763 1223 0 +3763 1227 0 +3768 1219 0 +3768 1224 0 +3772 1227 0 +3773 1222 0 + +# foot stool +FootStool 0x0B5E +3593 1194 0 +3594 1193 0 +3601 1232 0 +3612 1257 0 +3625 1241 0 +3627 1241 0 +3672 1325 20 +3675 1319 20 +3683 1317 0 +3683 1318 0 +3683 1319 0 +3732 1255 0 +3732 1256 0 +3732 1257 0 +3732 1258 0 +3732 1259 0 +3732 1260 0 +3732 1261 0 +3784 1125 20 +3789 1125 20 + +# bench +Static 0x0B5F +3674 1129 0 +3776 1251 0 +3779 1251 0 + +# bench +Static 0x0B60 +3674 1128 0 +3776 1249 0 +3779 1249 0 + +# bench +Static 0x0B61 +3776 1250 0 +3779 1250 0 + +# bench +Static 0x0B65 +3673 1130 0 +3778 1248 0 +3778 1252 0 + +# bench +Static 0x0B66 +3672 1130 0 +3777 1248 0 +3777 1252 0 + +# bench +Static 0x0B91 +3732 1308 0 +3735 1308 0 +3738 1308 0 + +# bench +Static 0x0B92 +3731 1308 0 +3734 1308 0 +3737 1308 0 + +# bench +Static 0x0B93 +3675 1236 0 +3675 1244 0 +3696 1216 0 +3696 1222 0 +3730 1310 0 +3736 1204 0 + +# bench +Static 0x0B94 +3675 1235 0 +3675 1243 0 +3696 1215 0 +3696 1221 0 +3730 1309 0 +3736 1203 0 + +# metal signpost +Static 0x0B9B +3768 1313 0 + +# metal signpost +Static 0x0BA1 +3554 1199 0 + +# metal signpost +Static 0x0BA2 +3551 1178 0 +3551 1186 0 +3551 1194 0 + +# poppies +Static 0x0C86 +3760 1288 1 +3762 1288 0 +3762 1289 0 +3763 1288 0 +3763 1289 0 +3774 1288 0 +3774 1302 0 + +# tribarrel cactus +Static 0x0D27 +3543 1175 0 +3544 1172 10 +3545 1175 0 +3546 1172 0 +3546 1174 0 +3546 1175 0 +3547 1174 0 +3548 1171 0 +3548 1175 0 +3549 1173 0 +3550 1170 0 +3550 1175 0 +3551 1172 0 + +# prickly pear cactus +Static 0x0D2C +3544 1175 0 +3546 1171 0 +3546 1173 0 +3547 1175 0 +3548 1172 0 +3548 1173 0 +3549 1171 0 +3549 1174 0 +3550 1171 0 +3550 1172 0 +3550 1173 0 +3550 1174 0 +3551 1169 0 +3551 1170 0 +3551 1175 0 + +# cactus +Static 0x0D2E +3547 1171 0 +3547 1172 0 +3547 1173 0 +3548 1174 0 +3549 1172 0 +3549 1175 0 +3551 1168 0 +3551 1171 0 +3551 1173 0 +3551 1174 0 + +# knitting +Static 0x0DF7 +3693 1232 4 + +# bale of cotton +Static 0x0DF9 +3684 1232 0 + +# ball of yarn +Static 0x0E1D +3692 1232 4 + +# ball of yarn +Static 0x0E1F +3691 1232 4 + +# scroll +Static 0x0E35 +3706 1228 4 +3714 1225 4 + +# scroll +Static 0x0E37 +3710 1225 4 +3714 1228 4 + +# crate +LargeCrate 0x0E3C +3697 1178 0 +3698 1178 0 + +# metal chest +MetalGoldenChest 0x0E40 +3683 1242 0 +3683 1243 0 +3683 1244 0 +3760 1322 6 +3760 1324 6 +3760 1326 6 + +# metal chest +MetalGoldenChest 0x0E41 +3685 1240 0 +3686 1240 0 +3687 1240 0 +3692 1240 0 +3693 1240 0 + +# wooden chest +WoodenChest 0x0E42 +3768 1122 20 + +# wooden chest +WoodenChest 0x0E43 +3770 1120 20 + +# wooden chest +FillableWoodenChest 0x0E43 +3774 1160 0 + +# empty jars +Static 0x0E44 +3689 1301 22 + +# empty jars +Static 0x0E47 +3687 1302 22 + +# full jars +Static 0x0E4B +3728 1341 4 + +# jars +Static 0x0E4D +3728 1340 4 + +# jars +Static 0x0E4F +3728 1339 4 + +# barrel +Barrel 0x0E77 +3656 1220 0 +3684 1190 20 +3685 1190 20 +3686 1186 20 +3686 1187 20 +3686 1188 20 +3686 1189 20 +3686 1190 20 +3687 1300 20 +3731 1335 0 + +# metal chest +MetalChest 0x0E7C +3648 1235 20 +3648 1236 0 +3648 1237 0 +3680 1189 0 +3696 1179 0 +3696 1181 0 + +# metal chest +FillableMetalChest 0x0E7C +3544 1197 0 +3744 1203 0 +3744 1204 0 + +# wooden box +FillableWoodenBox 0x0E7D +3768 1163 8 + +# crate +SmallCrate 0x0E7E +3656 1221 0 +3680 1112 0 +3680 1113 0 +3688 1131 0 +3688 1132 0 + +# standing harp +Static 0x0EB1 +3737 1184 5 +3741 1184 5 +3744 1202 0 +3748 1202 0 +3749 1196 0 + +# lap harp +Static 0x0EB2 +3749 1202 0 + +# lute +Static 0x0EB3 +3745 1196 0 + +# lute +Static 0x0EB4 +3727 1222 20 +3744 1196 0 + +# music stand +Static 0x0EB8 +3744 1198 3 + +# music stand +Static 0x0EB9 +3737 1187 5 +3739 1188 5 +3741 1187 5 + +# cleaver +Static 0x0EC2 +3667 1155 4 + +# dress form +Static 0x0EC6 +3687 1232 0 +3763 1250 0 +3765 1266 0 +3765 1268 0 +3767 1266 0 +3767 1268 0 + +# gold coins +Static 0x0EEF +3761 1326 6 +3762 1326 6 +3763 1326 6 +3764 1326 6 +3765 1326 6 +3766 1326 6 + +# scroll +Static 0x0EF4 +3699 1211 6 + +# scroll +Static 0x0EF5 +3699 1211 7 + +# scroll +Static 0x0EF8 +3770 1168 4 + +# scroll +Static 0x0EF9 +3709 1228 4 + +# arrows +Static 0x0F41 +3544 1192 6 + +# axe +Static 0x0F4A +3544 1184 8 + +# bardiche +Static 0x0F4E +3548 1184 11 + +# crossbow +Static 0x0F50 +3544 1193 6 +3544 1194 6 + +# mace +Static 0x0F5C +3548 1184 8 + +# broadsword +Static 0x0F5E +3546 1184 9 + +# bolt of cloth +Static 0x0F99 +3761 1269 0 +3761 1270 0 +3764 1268 0 + +# bolt of cloth +Static 0x0F9C +3693 1233 0 + +# sewing kit +Static 0x0F9D +3689 1232 4 +3761 1268 6 + +# scissors +Scissors 0x0F9F +3690 1232 4 +3763 1268 6 + +# playing cards +Static 0x0FA3 +3762 1219 4 + +# chess board +ChessBoard 0x0FA6 +3762 1227 4 + +# dice and cup +Dices 0x0FA7 +3762 1224 4 + +# chess pieces +Static 0x0FA8 +3762 1228 4 + +# dyes +Static 0x0FA9 +3760 1268 6 + +# dying tub +Static 0x0FAB +3760 1263 0 +3760 1264 0 +3760 1265 0 +3760 1266 0 + +# backgammon game +Backgammon 0x0FAD +3762 1223 4 + +# barrel +Static 0x0FAE +3662 1072 0 +3668 1128 0 +3674 1072 0 +3677 1064 0 +3689 1296 20 +3731 1334 0 + +# anvil +AnvilSouthAddon 0x0FB0 +3547 1189 0 +3552 1202 0 + +# forge +SmallForgeAddon 0x0FB1 +3549 1189 0 +3552 1200 0 + +# sledge hammer +Static 0x0FB5 +3544 1189 6 +3552 1203 0 + +# horse shoes +Static 0x0FB6 +3552 1205 0 + +# forged metal +Static 0x0FB8 +3548 1188 0 + +# tongs +Static 0x0FBB +3552 1203 0 + +# book +Static 0x0FBD +3712 1398 4 +3760 1252 4 +3761 1315 4 + +# book +Static 0x0FBE +3714 1401 5 +3717 1401 5 +3731 1319 4 +3761 1250 4 + +# pen and ink +Static 0x0FBF +3714 1396 4 +3760 1252 4 +3761 1315 4 + +# pen and ink +Static 0x0FC0 +3700 1211 6 +3701 1211 6 +3706 1227 4 +3710 1225 4 +3710 1228 4 +3714 1225 4 +3714 1228 4 +3714 1401 5 +3717 1401 5 +3731 1319 4 +3761 1235 4 +3769 1168 4 +3773 1123 29 +3778 1225 3 + +# book +RedBook 0x0FF1 +3678 1322 7 +3679 1314 7 +3686 1321 7 +3713 1398 4 +3728 1199 6 +3768 1168 6 +3774 1120 27 +3777 1225 3 + +# book +CallToAnarchy 0x0FF4 +3714 1396 8 + +# book +TalesOfVesperVol1 0x0FF4 +3728 1198 6 + +# book +MyStory 0x0FF4 +3773 1122 27 + +# glass pitcher +Pitcher 0x0FF6 +3762 1223 4 + +# glass pitcher +Pitcher 0x0FF7 +3762 1235 4 +3766 1237 4 + +# pewter mug +PewterMug 0x0FFF +3738 1258 7 +3739 1259 7 + +# spittoon +Static 0x1003 +3767 1224 4 +3770 1226 4 + +# wash basin +Static 0x1008 +3783 1131 24 + +# key ring +Static 0x1011 +3768 1160 4 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +3683 1232 0 +3761 1257 0 +3761 1260 0 + +# pile of wool +Static 0x101F +3683 1234 0 +3761 1256 0 +3761 1259 0 + +# bread loaf +Static 0x103B +3682 1116 4 +3696 1259 26 +3729 1249 8 +3734 1249 4 +3747 1250 9 + +# bread loaf +Static 0x103C +3649 1145 8 +3650 1168 4 +3652 1136 4 +3680 1300 24 +3688 1165 7 +3692 1263 24 +3699 1263 24 +3739 1249 6 +3739 1264 9 + +# dough +Static 0x103D +3740 1264 8 + +# flour sifter +Static 0x103E +3688 1301 22 + +# pizza +Static 0x1040 +3680 1297 24 +3680 1298 24 +3749 1264 6 + +# baked pie +Static 0x1041 +3656 1076 10 +3680 1301 24 + +# unbaked pie +Static 0x1042 +3680 1297 24 + +# rolling pin +Static 0x1043 +3689 1301 22 + +# upright loom +LoomSouthAddon 0x1061 +3767 1257 0 + +# cut leather +Static 0x1068 +3548 1176 0 + +# stretched hide +Static 0x106E +3544 1181 0 + +# stretched hide +Static 0x106F +3544 1182 0 + +# pile of hides +Static 0x1078 +3544 1178 0 +3550 1177 0 + +# stretched hide +Static 0x107D +3546 1176 0 + +# stretched hide +Static 0x107E +3547 1176 0 + +# bracelet +Static 0x1086 +3778 1167 2 + +# hanging pole +Static 0x10AF +3596 1208 0 + +# hanging pole +Static 0x10B0 +3595 1208 0 + +# hanging pole +Static 0x10B1 +3594 1208 0 + +# flowerpot +PottedPlant1 0x11CB +3664 1130 4 + +# Guillotine +Static 0x1230 +3728 1379 5 + +# decorative armor +Static 0x151C +3523 1125 20 +3528 1125 20 + +# decorative weapons +Static 0x1566 +3521 1127 20 + +# decorative weapons +Static 0x1567 +3521 1126 20 + +# feather +Static 0x1BD1 +3761 1268 6 + +# sarcophagus +Static 0x1C60 +3526 1126 20 + +# sarcophagus +Static 0x1C61 +3525 1126 20 + +# sarcophagus +Static 0x1C62 +3524 1126 20 + +# sarcophagus +Static 0x1C63 +3524 1125 20 + +# sarcophagus +Static 0x1C64 +3525 1125 20 + +# sarcophagus +Static 0x1C65 +3526 1125 20 diff --git a/Data/Decoration/Britannia/papua.cfg b/Data/Decoration/Britannia/papua.cfg new file mode 100644 index 0000000..363a0e1 --- /dev/null +++ b/Data/Decoration/Britannia/papua.cfg @@ -0,0 +1,456 @@ +# stone pavers +Static 0x0521 +5736 3196 10 + +# thatch roof +Static 0x05A6 +5720 3262 35 +5720 3263 35 + +# rattan door +RattanDoor 0x0695 (Facing=WestCW) +5675 3138 12 +5698 3279 14 +5726 3248 15 +5730 3202 8 +5745 3206 15 +5764 3154 14 +5769 3168 14 +5770 3154 14 +5774 3168 14 +5776 3154 14 +5779 3168 14 +5800 3276 11 +5805 3274 32 +5698 3287 14 + +# rattan door +RattanDoor 0x0697 (Facing=EastCCW) +5662 3129 13 +5676 3138 12 +5727 3248 15 +5770 3168 14 +5775 3168 14 +5780 3168 14 +5801 3276 11 +5806 3274 32 +5812 3294 10 + +# rattan door +RattanDoor 0x069B (Facing=EastCW) +5691 3212 10 +5708 3203 11 +5731 3187 8 + +# rattan door +RattanDoor 0x069D (Facing=SouthCW) +5677 3285 11 +5702 3211 10 +5739 3218 10 +5761 3156 14 +5761 3160 14 +5761 3165 14 +5803 3273 11 +5815 3268 11 +5669 3149 12 +5694 3286 14 +5797 3290 10 + +# rattan door +RattanDoor 0x069F (Facing=NorthCCW) +5677 3284 11 +5739 3217 10 +5739 3268 14 +5755 3270 15 +5803 3272 11 +5815 3267 11 +5669 3148 12 + +# rattan door +RattanDoor 0x06A1 (Facing=SouthCCW) +5718 3206 11 +5783 3162 15 + +# rattan door +RattanDoor 0x06A3 (Facing=NorthCW) +5718 3205 11 +5783 3161 15 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +5698 3287 -6 + +# wooden gate +DarkWoodGate 0x086A (Facing=WestCCW) +5681 3286 -1 + +# wooden gate +DarkWoodGate 0x086C (Facing=EastCW) +5682 3286 -1 + +# oven +StoneOvenSouthAddon 0x0930 +5747 3189 18 +5781 3150 14 + +# cauldron +Static 0x0974 +5708 3214 -2 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +5785 3168 22 + +# candle +Candle 0x0A0F +5753 3194 21 + +# hanging lantern +HangingLantern 0x0A1A +5779 3171 14 +5781 3171 14 + +# hanging lantern +HangingLantern 0x0A1D (Unlit) +5759 3165 14 + +# chest of drawers +FancyDrawer 0x0A38 +5809 3291 11 + +# dresser +Static 0x0A44 +5799 3268 33 + +# dresser +Static 0x0A45 +5799 3267 33 + +# armoire +FancyArmoire 0x0A51 +5757 3151 16 + +# armoire +Armoire 0x0A53 +5723 3240 16 + +# bookcase +LibraryBookcase 0x0A97 +5727 3188 9 + +# bookcase +LibraryBookcase 0x0A98 +5717 3196 12 +5726 3188 9 + +# bookcase +LibraryBookcase 0x0A99 +5711 3203 12 +5724 3190 9 +5732 3216 11 +5804 3269 14 + +# bookcase +LibraryBookcase 0x0A9A +5711 3202 12 +5724 3191 9 +5733 3262 15 +5742 3195 16 +5804 3270 14 + +# bookcase +LibraryBookcase 0x0A9B +5669 3283 12 +5725 3188 9 +5809 3265 33 +5812 3287 11 + +# bookcase +LibraryBookcase 0x0A9C +5724 3189 9 +5742 3194 16 +5796 3265 11 +5796 3266 11 + +# ruined bookcase +Static 0x0C14 +5754 3268 16 + +# crate +FillableLargeCrate 0x0E3C +5690 3204 11 +5824 3261 3 +5824 3261 6 +5824 3262 3 +5824 3262 6 +5824 3262 9 +5824 3263 3 +5825 3261 3 +5825 3261 6 +5825 3261 9 +5825 3262 3 +5825 3262 6 +5825 3262 9 +5825 3263 3 +5825 3263 6 +5826 3261 3 +5826 3261 6 +5826 3261 9 +5826 3262 3 +5826 3262 6 + +# crate +FillableLargeCrate 0x0E3D +5741 3259 15 +5741 3259 18 +5809 3274 12 +5809 3275 12 +5809 3275 15 +5809 3275 18 +5810 3274 12 +5810 3275 14 +5810 3275 17 +5811 3275 12 + +# crate +MediumCrate 0x0E3F +5740 3258 15 +5740 3258 18 +5741 3258 15 +5741 3258 18 +5741 3258 21 + +# metal chest +FillableMetalGoldenChest 0x0E40 +5723 3242 16 +5723 3246 16 +5757 3156 16 + +# metal chest +MetalGoldenChest 0x0E41 +5662 3123 15 + +# wooden chest +WoodenChest 0x0E42 +5660 3124 15 +5660 3128 15 + +# wooden chest +FillableWoodenChest 0x0E42 +5762 3153 16 +5768 3153 16 +5774 3153 16 + +# wooden chest +WoodenChest 0x0E43 +5665 3123 15 + +# wooden chest +FillableWoodenChest 0x0E43 +5760 3158 16 +5760 3164 16 + +# barrel +FillableBarrel 0x0E77 +5666 3289 12 +5690 3284 15 +5690 3285 15 +5690 3286 15 +5691 3284 15 +5810 3265 -1 + +# basin +Static 0x0E78 +5757 3160 16 +5757 3166 16 +5759 3150 16 +5771 3150 16 + +# water tub +Static 0x0E7B +5666 3287 12 + +# metal chest +FillableMetalChest 0x0E7C +5733 3269 15 +5804 3271 11 + +# empty tub +Static 0x0E83 +5811 3303 12 + +# pickaxe +Static 0x0E86 +5737 3261 18 + +# chess board +ChessBoard 0x0FA6 +5808 3269 39 + +# fire pit +Static 0x0FAC (Light=Circle225) +5708 3214 -2 + +# barrel +Static 0x0FAE +5666 3283 12 +5667 3283 12 +5691 3288 -3 +5691 3289 -3 +5692 3287 -2 +5692 3288 -3 +5692 3289 -1 +5693 3287 -3 +5693 3288 -4 +5693 3289 -3 +5701 3204 16 +5804 3274 11 +5804 3275 11 +5805 3274 11 +5805 3275 11 +5806 3268 -15 +5806 3269 -15 +5806 3270 -15 +5806 3271 -15 +5806 3274 11 +5806 3275 11 +5807 3271 -15 +5807 3274 11 +5807 3275 11 +5808 3265 -5 +5808 3271 -15 +5808 3275 11 +5809 3264 -7 +5809 3265 -5 +5809 3268 -15 +5809 3269 -15 +5809 3270 -15 +5809 3271 -15 +5810 3267 -15 +5810 3268 -15 +5810 3269 -15 +5810 3270 -15 +5810 3271 -15 +5810 3275 11 +5811 3266 -8 +5812 3266 -3 +5812 3267 -2 +5823 3238 3 +5824 3238 3 +5824 3239 3 +5824 3259 3 +5824 3260 3 +5825 3259 5 +5825 3260 3 +5826 3260 3 +5826 3263 3 +5827 3262 3 + +# sledge hammer +Static 0x0FB5 +5738 3261 18 + +# pentagram +Static 0x0FEA +5736 3196 10 + +# teleporter: recsu +KeywordTeleporter 0x1BC3 (Substring=recsu; Range=4; PointDest=(4544, 850, 30)) +5736 3196 10 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +5753 3269 15 + +# hammer +Static 0x102B +5687 3206 17 + +# upright loom +LoomEastAddon 0x1060 +5751 3271 15 + +# earrings +Static 0x1087 +5662 3152 16 + +# necklace +Static 0x1088 +5660 3145 16 + +# an obelisk +Obelisk 0x1184 +5741 3313 3 +5742 3313 8 +5748 3313 8 +5749 3313 3 + +# leather tunic +Static 0x13CA +5809 3295 11 + +# studded tunic +Static 0x13D9 +5810 3295 11 + +# ringmail armor +Static 0x13E7 +5808 3295 11 + +# close helmet +Static 0x1408 +5804 3295 13 + +# plate helm +Static 0x1412 +5803 3295 13 + +# platemail gorget +Static 0x1413 +5802 3305 13 + +# map +Static 0x14EC +5797 3270 18 + +# water barrel +Static 0x154D +5808 3264 -7 + +# flour mill +FlourMillEastAddon 0x1920 +5755 3190 15 + +# bellows +Static 0x1986 +5813 3301 12 + +# forge +Static 0x198A (Light=Circle300) +5813 3302 12 + +# forge +Static 0x198E +5813 3303 12 + +# cooper's bench +Static 0x19FC +5694 3211 12 + +# earrings +Static 0x1F07 +5654 3145 19 +5663 3152 16 + +# necklace +Static 0x1F08 +5659 3145 16 +5661 3145 16 + +# ring +Static 0x1F09 +5662 3152 16 + +# hatch +Static 0x3E93 +5834 3260 2 diff --git a/Data/Decoration/Britannia/patches.cfg b/Data/Decoration/Britannia/patches.cfg new file mode 100644 index 0000000..76e0baa --- /dev/null +++ b/Data/Decoration/Britannia/patches.cfg @@ -0,0 +1,141 @@ +################################ +# Blockers # +# Makes dungeon teleporters # +# not have rubber-band effects # +################################ + +Blocker 0x21A4 +# Despise +5572 628 47 +5572 629 47 +5572 630 47 +5505 569 41 +5505 570 41 +5505 571 41 +5506 569 39 +5506 570 39 +5506 571 39 +5507 569 49 +5507 570 49 +5507 571 49 +5571 632 12 +5571 633 12 +5571 634 12 +5523 672 37 +5523 673 37 +5523 674 37 +5385 755 -13 +5385 756 -13 +5385 757 -13 +5410 858 57 +5410 859 57 +5410 860 57 +# Hythloth +6082 144 -15 +6082 145 -15 +6082 146 -15 +6058 88 29 +6058 89 29 +6058 90 29 +6041 192 7 +6041 193 7 +6041 194 7 +6042 194 10 +6043 194 16 +6044 194 16 +6045 194 21 +6046 194 22 + + +# teleporter +Static 0x1809 +1653 2963 0 +1677 2987 0 + +# water +Static 0x1797 +3807 1204 -5 +3801 1165 -5 +3584 1258 -5 +3454 104 -5 +3468 114 -5 +3440 176 -5 +3386 174 -5 +3332 194 -5 +3284 90 -5 +3522 366 -5 +3458 384 -5 +3478 394 -5 +3406 520 -5 +3418 580 -5 +3440 554 -5 +3448 546 -5 +3460 536 -5 +3482 512 -5 +3454 628 -5 + +# water +Static 0x1798 +3812 1202 -5 +3581 1258 -5 +3585 1258 -5 +3458 106 -5 +3470 116 -5 +3412 192 -5 +3352 178 -5 +3318 194 -5 +3502 334 -5 +3452 378 -5 +3464 388 -5 +3480 396 -5 +3412 524 -5 +3424 576 -5 +3442 552 -5 +3452 540 -5 +3466 522 -5 +3484 514 -5 +3264 726 -5 + + +# water +Static 0x1799 +3813 1201 -5 +3582 1258 -5 +3586 1258 -5 +3462 108 -5 +3472 118 -5 +3408 190 -5 +3346 182 -5 +3316 194 -5 +3508 338 -5 +3454 380 -5 +3468 390 -5 +3490 406 -5 +3410 586 -5 +3436 560 -5 +3444 550 -5 +3454 538 -5 +3470 514 -5 +3486 516 -5 +3266 724 -5 + +# water +Static 0x179A +3799 1165 -5 +3583 1258 -5 +3587 1258 -5 +3466 112 -5 +3414 94 -5 +3388 174 -5 +3334 192 -5 +3286 90 -5 +3510 340 -5 +3456 382 -5 +3472 392 -5 +3466 458 -5 +3412 584 -5 +3438 556 -5 +3446 548 -5 +3456 538 -5 +3472 512 -5 +3488 580 -5 \ No newline at end of file diff --git a/Data/Decoration/Britannia/serpent pillars.cfg b/Data/Decoration/Britannia/serpent pillars.cfg new file mode 100644 index 0000000..bd92d4d --- /dev/null +++ b/Data/Decoration/Britannia/serpent pillars.cfg @@ -0,0 +1,13 @@ +#Serpent pillars + +SerpentPillar 0x233F (Word=doracron; DestStart=(5922, 2645); DestEnd=(6022, 2745)) +2983 2888 -5 + +SerpentPillar 0x233F (Word=sueacron; DestStart=(2933, 2838); DestEnd=(3033, 2938)) +5972 2695 -5 + +SerpentPillar 0x233F (Word=doracron; DestStart=(5215, 2705); DestEnd=(5315, 2805)) +422 3281 -5 + +SerpentPillar 0x233F (Word=sueacron; DestStart=(372, 3231); DestEnd=(472, 3331)) +5265 2755 -5 \ No newline at end of file diff --git a/Data/Decoration/Britannia/serpentshold.cfg b/Data/Decoration/Britannia/serpentshold.cfg new file mode 100644 index 0000000..2ccff13 --- /dev/null +++ b/Data/Decoration/Britannia/serpentshold.cfg @@ -0,0 +1,1251 @@ +######### +# Doors # +######### + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +3058 3351 15 +3055 3407 15 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +3059 3351 15 +3056 3407 15 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +3023 3432 15 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +3023 3431 15 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +2902 3519 10 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +2903 3519 10 + +# wooden gate +DarkWoodGate 0x086E (Facing=SouthCW) +2911 3516 10 +2911 3522 10 +3041 3467 15 +3027 3467 15 + +# wooden gate +DarkWoodGate 0x0870 (Facing=NorthCCW) +2911 3515 10 +2911 3521 10 +3041 3466 15 + +# wooden door +LightWoodDoor 0x06D5 (Facing=WestCW) +3051 3375 15 + +# wooden door +LightWoodDoor 0x06D7 (Facing=EastCCW) +3052 3375 15 + +# wooden door +LightWoodDoor 0x06DB (Facing=EastCW) +3053 3364 15 + +# wooden door +LightWoodDoor 0x06DD (Facing=SouthCW) +2879 3508 10 +2887 3504 10 + +# wooden door +LightWoodDoor 0x06DF (Facing=NorthCCW) +2887 3503 10 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +3058 3391 15 + + +############ +# Standard # +############ + +# wooden wall +Static 0x00A7 +2879 3498 10 + +# wooden wall +Static 0x00AD +3050 3375 15 + +# stone wall +Static 0x00C8 +3036 3343 35 + +# stone pavers +Static 0x0523 +3016 3345 35 + +# thatch roof +Static 0x05A7 +2897 3520 30 + +# fireplace +Static 0x08DA +3008 3456 15 + +# fireplace +Static 0x08DB +3008 3455 15 + +# oven +StoneOvenEastAddon 0x092C +3008 3453 15 + +# oven +StoneOvenSouthAddon 0x0930 +2974 3352 15 + +# fireplace +Static 0x095F +2976 3352 15 + +# fireplace +Static 0x0960 +2975 3352 15 + +# jugs of cider +Static 0x098D +2969 3416 15 + +# fruit basket +FruitBasket 0x0993 +2969 3404 19 +2969 3410 19 + +# mug +CeramicMug 0x0999 +3031 3347 21 + +# bottles of ale +Static 0x09A2 +2968 3416 15 + +# metal chest +FillableMetalChest 0x09AB +3019 3424 15 + +# goblet +Goblet 0x09B3 +3030 3347 21 +3030 3355 21 +3031 3355 21 + +# silverware +Static 0x09BD +2914 3484 16 +3016 3458 19 + +# goblet +Goblet 0x09BF +2970 3419 21 + +# bottles of wine +Static 0x09C4 +2970 3416 15 + +# silverware +Static 0x09D5 +2915 3484 16 + +# pitcher +Static 0x09D6 +3053 3420 21 + +# plate +Plate 0x09D7 +2914 3484 16 +2915 3484 16 +3016 3458 19 + +# pot +Static 0x09E4 +3009 3455 15 + +# kettle +Static 0x09ED +3009 3456 15 + +# mug of ale +GlassMug 0x09EE (Content=Ale) +2969 3419 21 + +# mug of ale +GlassMug 0x09EF (Content=Ale) +2972 3419 21 + +# wall torch +WallTorch 0x0A0C (Light=NorthBig) +2961 3440 30 +3049 3376 25 +3054 3376 30 + +# lantern +Lantern 0x0A17 +3016 3389 24 + +# lantern +Lantern 0x0A18 (Unlit) +2976 3410 24 + +# stool +Stool 0x0A2A +3011 3351 35 +3052 3344 15 + +# chest of drawers +Drawer 0x0A2C +3017 3424 15 + +# chest of drawers +Drawer 0x0A34 +2911 3481 10 +2936 3498 10 +2936 3503 10 +3000 3387 15 +3048 3420 15 + +# chest of drawers +FancyDrawer 0x0A38 +3008 3428 15 +3032 3427 15 +3057 3388 15 + +# dresser +Static 0x0A44 +2872 3509 10 + +# dresser +Static 0x0A45 +2872 3508 10 + +# armoire +FancyArmoire 0x0A4D +3013 3424 15 + +# armoire +Armoire 0x0A4F +2915 3480 10 +2967 3400 35 +2967 3410 35 +2974 3400 35 +3054 3360 15 + +# armoire +Armoire 0x0A53 +3048 3349 15 + +# bed +Static 0x0A5A +2937 3500 10 +2993 3428 15 +2998 3424 15 +2998 3428 15 +3033 3425 15 +3033 3428 15 +3058 3384 15 +3058 3386 15 + +# bed +Static 0x0A5B +2936 3500 10 +2992 3428 15 +2997 3424 15 +2997 3428 15 +3032 3425 15 +3032 3428 15 +3057 3384 15 +3057 3386 15 + +# bed +SmallBedEastAddon 0x0A5D +2992 3426 15 +3000 3348 35 +3000 3351 35 +3000 3354 35 +3024 3352 35 +3024 3354 35 +3024 3356 35 +3028 3352 35 +3028 3354 35 +3028 3356 35 +3032 3352 35 +3032 3354 35 +3032 3356 35 + +# bed +Static 0x0A5E +3007 3344 35 +3013 3344 35 + +# bed +Static 0x0A5F +3007 3345 35 +3013 3345 35 + +# bed +SmallBedSouthAddon 0x0A63 +2872 3505 10 +2876 3505 10 +2917 3480 10 +3010 3344 35 + +# bed +Static 0x0A64 +2937 3496 10 +3000 3384 15 +3048 3344 15 +3048 3360 15 +3048 3416 15 +3050 3344 15 +3050 3416 15 +3051 3360 15 +3060 3384 15 + +# bed +Static 0x0A65 +2937 3497 10 +3000 3385 15 +3048 3345 15 +3048 3361 15 +3048 3417 15 +3050 3345 15 +3050 3417 15 +3051 3361 15 +3060 3385 15 + +# bed +Static 0x0A6A +2992 3424 15 + +# bed +LargeBedEastAddon 0x0A7D +2962 3412 35 +2969 3411 35 + +# bed +LargeBedSouthAddon 0x0A83 +2962 3400 35 +2969 3400 35 +3008 3424 15 + +# folded sheet +Static 0x0A93 (Hue=0x546) +3048 3416 17 +3050 3416 17 + +# bookcase +LibraryBookcase 0x0A97 +2941 3496 10 +2967 3400 15 + +# bookcase +LibraryBookcase 0x0A98 +2940 3496 10 +2971 3400 15 + +# bookcase +LibraryBookcase 0x0A99 +2992 3430 15 + +# bookcase +LibraryBookcase 0x0A9A +2992 3431 15 + +# bookcase +LibraryBookcase 0x0A9B +2939 3496 10 +2966 3400 15 +2968 3400 15 +2972 3400 15 + +# rug +Static 0x0AB5 +2966 3402 35 + +# rug +Static 0x0AB7 +2965 3402 35 + +# rug +Static 0x0AB8 +2965 3401 35 + +# rug +Static 0x0AB9 +2966 3401 35 + +# rug +Static 0x0ABA +2966 3403 35 + +# rug +Static 0x0ABB +2965 3403 35 + +# candle +CandleLarge 0x0B1A +2965 3404 23 +2965 3411 23 +2969 3403 19 +2969 3409 19 +3050 3360 23 +2962 3410 43 +2965 3400 43 +2969 3410 41 + +# lamp post +LampPost1 0x0B20 +2956 3458 24 +2961 3459 34 + +# candelabra +CandelabraStand 0x0B26 +2938 3362 15 +2939 3347 15 + +# counter +Static 0x0B3F +3000 3349 35 + +# counter +Static 0x0B40 +3052 3420 15 +3053 3420 15 + +# water trough +WaterTroughSouthAddon 0x0B43 +2906 3520 10 +2898 3520 10 + +# chair +FancyWoodenChairCushion 0x0B4E +2913 3484 10 + +# chair +FancyWoodenChairCushion 0x0B4F (Hue=0x21) +2878 3505 10 + +# chair +FancyWoodenChairCushion 0x0B4F (Hue=0x26) +2874 3505 10 + +# chair +FancyWoodenChairCushion 0x0B51 +2916 3484 10 + +# chair +FancyWoodenChairCushion 0x0B51 (Hue=0x1E) +2873 3509 10 + +# chair +WoodenChair 0x0B56 +2963 3407 15 +3029 3346 15 +3029 3348 15 +3029 3350 15 +3029 3352 15 +3029 3354 15 +3029 3356 15 + +# chair +WoodenChair 0x0B57 +3018 3427 15 + +# chair +WoodenChair 0x0B58 +3033 3346 15 +3033 3348 15 +3033 3350 15 +3033 3352 15 +3033 3354 15 +3033 3356 15 + +# chair +BambooChair 0x0B5D +2881 3496 10 +3049 3366 15 +3049 3371 15 + +# foot stool +FootStool 0x0B5E +2906 3487 10 +2909 3517 10 +2932 3504 10 +2939 3506 10 +2940 3505 10 +2968 3420 15 +2970 3420 15 +2972 3420 15 +2994 3433 15 +3005 3388 15 +3009 3451 15 +3009 3460 15 +3010 3451 15 +3010 3460 15 +3011 3451 15 +3011 3460 15 +3013 3453 15 +3013 3454 15 +3013 3455 15 +3013 3456 15 +3013 3457 15 +3013 3458 15 +3035 3427 15 +3035 3428 15 +3037 3427 15 +3037 3428 15 +3051 3403 15 +3052 3419 15 +3052 3421 15 +3053 3419 15 +3053 3421 15 + +# bench +Static 0x0B5F +2968 3403 15 +2968 3405 15 +2969 3425 15 +2969 3427 15 +2970 3403 15 +2970 3405 15 +2971 3425 15 +2971 3427 15 +2992 3437 15 +3015 3453 15 +3015 3455 15 +3015 3458 15 +3015 3460 15 +3017 3453 15 +3017 3455 15 +3017 3458 15 +3017 3460 15 + +# bench +Static 0x0B60 +2968 3402 15 +2968 3404 15 +2969 3424 15 +2969 3426 15 +2970 3402 15 +2970 3404 15 +2971 3424 15 +2971 3426 15 +2992 3436 15 +3015 3452 15 +3015 3454 15 +3015 3457 15 +3015 3459 15 +3017 3452 15 +3017 3454 15 +3017 3457 15 +3017 3459 15 + +# metal signpost +Static 0x0BA2 +3027 3360 15 + +# cards +Static 0x0E15 +3015 3526 21 + +# cards +Static 0x0E16 +3014 3527 21 +3033 3346 39 + +# cards +Static 0x0E17 +3034 3346 37 + +# cards +Static 0x0E19 +3015 3525 21 + +# backgammon board +Backgammon 0x0E1C +3035 3346 37 + +# bloody water +Static 0x0E23 +2993 3432 21 + +# bottle +Static 0x0E26 +3000 3349 41 + +# crate +LargeCrate 0x0E3C +2939 3381 15 +2941 3381 15 + +# crate +FillableLargeCrate 0x0E3C +2943 3401 0 +2943 3402 0 +2944 3401 0 +2944 3402 0 + +# crate +LargeCrate 0x0E3D +2885 3420 35 +2886 3420 35 +2952 3447 15 +2952 3448 15 +2963 3492 15 +2963 3493 15 +2964 3492 15 +2964 3493 15 +2964 3493 18 +2965 3491 15 +2965 3492 15 +2965 3492 18 +2965 3493 15 +2965 3493 18 +3011 3400 15 +3011 3401 15 +3011 3401 18 +3012 3401 15 +3012 3401 18 +3012 3402 15 +3013 3402 15 + +# crate +FillableLargeCrate 0x0E3D +2940 3401 1 +2940 3402 1 +2941 3401 1 +2941 3402 1 +2942 3401 1 +2942 3402 1 + +# crate +MediumCrate 0x0E3E +2888 3420 35 +2952 3444 15 +2952 3451 15 + +# crate +MediumCrate 0x0E3F +2887 3420 35 +2943 3401 3 +2943 3402 3 +2943 3403 0 +2944 3401 3 +2944 3402 3 + +# metal chest +MetalGoldenChest 0x0E40 +2872 3466 15 +2872 3476 15 + +# metal chest +FillableMetalGoldenChest 0x0E41 +3011 3424 15 + +# wooden chest +WoodenChest 0x0E42 +2872 3473 15 +2872 3474 15 +2873 3466 15 +2880 3415 35 +2936 3374 15 +2936 3381 15 +2952 3446 15 +2952 3450 15 +2952 3493 15 +3056 3348 15 + +# wooden chest +FillableWoodenChest 0x0E42 +3026 3352 35 +3030 3354 35 +3034 3352 35 + +# wooden chest +WoodenChest 0x0E43 +2963 3480 15 +2965 3480 15 +3064 3336 15 + +# bag +Bag 0x0E76 +3009 3384 16 + +# barrel +FillableBarrel 0x0E77 +2906 3480 10 +2906 3480 15 +2906 3480 20 +2907 3480 10 +2907 3480 15 +2907 3481 10 +2932 3401 0 +2932 3401 5 +2932 3402 0 +2932 3402 5 +2932 3403 0 +2933 3401 0 +2933 3401 5 +2933 3401 10 +2933 3402 0 +2933 3402 5 +2934 3401 0 +2934 3401 5 +2934 3402 0 +2934 3402 5 +2934 3403 0 +2935 3401 0 +3008 3457 15 +3008 3457 20 +3012 3406 15 +3048 3368 15 +3049 3365 15 + +# metal chest +MetalChest 0x0E7C +2872 3468 15 +2873 3468 15 +2873 3474 15 +2873 3476 15 +3008 3530 15 + +# metal chest +FillableMetalChest 0x0E7C +2904 3481 10 +2936 3502 10 +2962 3408 15 +3004 3389 15 +3048 3402 15 + +# wooden box +FillableWoodenBox 0x0E7D +2938 3500 10 +3026 3354 35 + +# crate +FillableSmallCrate 0x0E7E +2904 3483 10 +2904 3483 13 +2904 3483 16 +2904 3484 10 +2904 3484 13 + +# strong box +FillableMetalBox 0x0E80 +3026 3356 35 +3030 3356 35 +3034 3354 35 + +# mortar and pestle +Static 0x0E9B +2992 3432 21 + +# dress form +Static 0x0EC6 +2880 3502 10 + +# clean bandage +Static 0x0EE9 +3012 3353 41 + +# scroll +Static 0x0EF6 +2992 3434 21 + +# bottle +Static 0x0F03 +3011 3349 41 +3011 3353 41 + +# arrows +Static 0x0F40 +3010 3348 21 +3054 3389 43 + +# arrows +Static 0x0F41 +3009 3348 21 +3054 3388 43 + +# arrow +Static 0x0F42 +3054 3389 43 + +# hatchet +Static 0x0F43 +2956 3481 19 +3017 3434 19 + +# crossbow +Static 0x0F4F +2880 3418 39 +3048 3372 21 + +# crossbow +Static 0x0F50 +3048 3370 21 +3054 3390 43 +3054 3391 43 + +# dagger +Static 0x0F52 +3052 3401 19 + +# mace +Static 0x0F5D +3051 3397 15 + +# broadsword +Static 0x0F5E +2880 3417 39 + +# longsword +Static 0x0F60 +2936 3377 19 +3015 3434 19 +3052 3396 15 +3060 3398 19 +3060 3403 19 + +# spear +Static 0x0F62 +3053 3392 15 + +# bolt of cloth +Static 0x0F98 (Hue=0x26) +2880 3509 10 + +# bolt of cloth +Static 0x0F99 (Hue=0x21) +2880 3498 10 + +# bolt of cloth +Static 0x0F9A (Hue=0x1E) +2880 3507 10 + +# sewing kit +Static 0x0F9D +2881 3504 16 + +# scissors +Scissors 0x0F9E +2881 3505 13 + +# spool of thread +Static 0x0FA0 (Hue=0x21) +2880 3503 16 + +# spool of thread +Static 0x0FA1 (Hue=0x1E) +2880 3503 16 + +# playing cards +Static 0x0FA2 +3014 3525 21 + +# playing cards +Static 0x0FA3 +2970 3425 17 +3016 3454 18 +3058 3341 21 + +# chess board +ChessBoard 0x0FA6 +3058 3343 20 + +# dice and cup +Dices 0x0FA7 +3016 3455 19 + +# barrel +Static 0x0FAE +2904 3482 10 +3008 3531 15 + +# anvil +AnvilEastAddon 0x0FAF +3001 3410 15 +3003 3401 15 + +# forge +SmallForgeAddon 0x0FB1 +3007 3404 15 + +# sledge hammer +Static 0x0FB5 +3002 3410 15 +3004 3401 15 + +# horse shoes +Static 0x0FB6 +3010 3410 15 + +# forged metal +Static 0x0FB7 +3002 3401 15 + +# forged metal +Static 0x0FB8 +3003 3412 15 + +# book +Static 0x0FBD +2905 3487 15 +2930 3505 15 +3012 3351 41 +3030 3347 21 +3032 3350 21 + +# book +Static 0x0FBE +2885 3497 14 +2963 3404 23 +3018 3429 23 + +# pen and ink +Static 0x0FBF +2905 3487 15 +2930 3505 15 +3031 3347 21 + +# pen and ink +Static 0x0FC0 +2884 3497 14 +2963 3404 21 +3007 3387 25 +3012 3352 41 +3018 3429 23 +3030 3346 21 +3030 3351 21 +3031 3355 21 +3052 3402 19 + +# book +SongOfSamlethe 0x0FF4 +3007 3388 27 + +# glass pitcher +Pitcher 0x0FF6 +3012 3453 24 + +# skull mug +Static 0x0FFD +2970 3424 19 +3010 3452 24 +3010 3459 23 +3012 3458 23 +3016 3453 19 +3016 3459 19 +3032 3353 21 + +# skull mug +Static 0x0FFE +3016 3458 19 +3030 3350 21 + +# pewter mug +PewterMug 0x0FFF +3012 3455 24 + +# pewter mug +PewterMug 0x1001 +2970 3425 24 +3012 3456 24 +3016 3452 19 +3016 3457 19 + +# pewter mug +PewterMug 0x1002 +2970 3426 19 + +# spittoon +Static 0x1003 +2968 3429 15 +2973 3423 15 +3008 3461 15 +3018 3450 15 + +# archery butte +ArcheryButte 0x100A +3027 3381 15 +3048 3394 39 +3048 3396 39 +3048 3398 39 +3048 3400 39 +3048 3402 39 + +# archery butte +ArcheryButte 0x100B +3036 3379 15 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +2880 3496 10 + +# pile of wool +Static 0x101F +2881 3497 10 + +# hammer +Static 0x102B +2938 3507 14 +2941 3505 14 +2941 3508 14 + +# dough +Static 0x103D +2972 3353 21 + +# globe +Static 0x1047 +3029 3344 15 + +# globe +Static 0x1048 +3033 3344 15 + +# clock +Clock 0x104B +2936 3504 10 +2936 3506 10 + +# clock frame +ClockFrame 0x104E +2938 3505 14 +2941 3507 14 + +# clock parts +ClockParts 0x104F +2938 3507 14 +2941 3505 14 + +# axle with gears +AxleGears 0x1051 +2938 3506 14 +2941 3508 14 + +# gears +Gears 0x1054 +2938 3508 14 +2941 3505 14 + +# sextant +Static 0x1057 +2938 3506 14 +2941 3507 14 + +# sextant parts +SextantParts 0x1059 +2938 3505 14 +2941 3506 14 + +# springs +Springs 0x105D +2938 3507 14 +2941 3504 14 + +# upright loom +LoomEastAddon 0x1060 (Hue=0x1E) +2873 3499 10 + +# upright loom +LoomSouthAddon 0x1061 (Hue=0x21) +2875 3497 10 + +# upright loom +LoomSouthAddon 0x1061 (Hue=0x26) +2875 3502 10 + +# training dummy +TrainingDummySouthAddon 0x1070 +3029 3389 15 + +# training dummy +TrainingDummyEastAddon 0x1074 +3037 3389 15 + +# lever +Static 0x108D +2956 3454 15 + +# flowerpot +PottedPlant 0x11CA +2912 3480 10 +3048 3347 15 + +# flowerpot +PottedPlant1 0x11CB +2992 3435 21 + +# war axe +Static 0x13AF +3006 3348 21 + +# bow +Static 0x13B2 +3011 3348 21 + +# large battle axe +Static 0x13FB +3004 3348 21 + +# katana +Static 0x13FF +3016 3434 19 + +# map +Static 0x14EC +3030 3353 21 +3031 3350 21 +3032 3346 21 + +# rolled map +Static 0x14ED +3031 3348 21 +3031 3354 21 + +# rolled map +Static 0x14EE +3031 3356 21 +3032 3352 21 + +# water barrel +Static 0x154D +3003 3413 15 +3004 3400 15 + +# flask +Static 0x182B +3000 3355 41 + +# flask +Static 0x182F +3011 3354 41 + +# flask +Static 0x1831 +3013 3350 41 + +# flask +Static 0x1844 +3011 3350 41 + +# flask +Static 0x1847 +3011 3344 41 + +# heating stand +HeatingStand 0x184A +3011 3350 41 + +# scales +Scales 0x1852 +3012 3354 41 + +# empty vials +Static 0x185C +3007 3389 21 +3012 3350 41 + +# full vials +Static 0x185D +3010 3353 41 + +# full vials +Static 0x185E +3007 3390 21 + +# iron wire +Static 0x1876 +3002 3409 15 +3003 3403 15 +3005 3409 15 +3012 3412 15 + +# silver wire +Static 0x1877 +3005 3402 15 +3005 3404 15 +3008 3412 15 + +# bellows +Static 0x197B +3000 3403 15 +3000 3412 15 + +# forge +Static 0x197E (Light=Circle300) +3001 3403 15 +3001 3412 15 + +# forge +Static 0x1982 +3002 3403 15 +3002 3412 15 + +# ore +Static 0x19B7 +3011 3402 15 +3012 3403 15 +3013 3400 15 + +# ore +Static 0x19B7 (Amount=2) +3000 3404 15 +3001 3404 15 +3010 3407 15 +3011 3407 15 + +# ore +Static 0x19B8 (Amount=2) +3010 3407 15 +3011 3407 15 +3011 3408 15 + +# ore +Static 0x19B9 (Amount=2) +3000 3405 15 +3001 3405 15 +3010 3408 15 +3011 3408 15 + +# ore +Static 0x19BA (Amount=2) +3001 3406 15 +3010 3408 15 +3011 3407 15 +3011 3408 15 +3011 3409 15 +3012 3408 15 + +# ore cart +Static 0x1A83 +3002 3407 15 +3012 3410 15 + +# keg +Static 0x1AD6 +3010 3400 15 + +# shaft +Static 0x1BD4 +3048 3365 21 +3048 3366 21 +3048 3367 21 + +# bulletin board +BulletinBoard 0x1E5E +2963 3400 15 +3017 3450 15 \ No newline at end of file diff --git a/Data/Decoration/Britannia/shame.cfg b/Data/Decoration/Britannia/shame.cfg new file mode 100644 index 0000000..c814af9 --- /dev/null +++ b/Data/Decoration/Britannia/shame.cfg @@ -0,0 +1,71 @@ +# wooden logs +Static 0x0509 +5620 66 0 + +# wooden logs +Static 0x050A +5546 12 0 +5546 13 0 +5546 14 0 +5548 14 0 +5553 14 0 +5555 12 0 + +# stone pavers +Static 0x051E +5443 179 22 +5444 179 22 + +# stone pavers +Static 0x051F +5574 199 22 + +# stone +Static 0x071E +5513 9 0 +5514 10 0 +5490 19 -30 + +# suspension bridge +Static 0x07F0 +5617 70 0 + +# suspension bridge +Static 0x080F +5552 15 0 + +# water +Static 0x1797 +5546 15 -5 +5548 15 -5 +5549 15 -5 +5550 13 -5 +5554 10 -5 +5617 57 -5 +5617 64 -5 +5620 66 -5 +5621 67 -5 +5672 43 -5 +5436 168 -5 + +# wooden planks +Static 0x04C9 +5460 185 0 +5460 186 0 +5460 187 0 +5460 188 0 +5456 185 0 +5456 186 0 +5456 187 0 +5456 188 0 + +# moongate +Static 0x1FD4 (Light=Circle300) +5490 19 -24 +5514 10 6 +5604 102 6 +5514 147 26 +5538 170 6 +5513 176 6 +5507 162 6 +5875 19 -4 \ No newline at end of file diff --git a/Data/Decoration/Britannia/shrines.cfg b/Data/Decoration/Britannia/shrines.cfg new file mode 100644 index 0000000..46ce23d --- /dev/null +++ b/Data/Decoration/Britannia/shrines.cfg @@ -0,0 +1,120 @@ +# Chaos +AnkhWest 0x0003 +1456 843 5 + +CandelabraStand 0x0B26 +1457 841 0 +1457 846 0 + +Static 0x0788 +1456 843 0 +1456 844 0 +1457 843 0 +1457 844 0 +1458 843 0 +1458 844 0 + +Static 0x0789 +1456 845 0 +1457 845 0 +1458 845 0 + +Static 0x078A +1459 843 0 +1459 844 0 + +Static 0x078B +1456 842 0 +1457 842 0 +1458 842 0 + +Static 0x078E +1459 845 0 + +Static 0x078F +1459 842 0 + +Static 0x14E3 +1457 843 5 + +Static 0x14E4 +1457 844 5 + +Static 0x14E5 +1458 844 5 + +Static 0x14E6 +1458 843 5 + +# Compassion +AnkhNorth 0x0004 +1857 877 -1 + +# Honesty (locations unconfirmed) +AnkhWest 0x0003 +4208 561 42 +4208 565 42 + +# Humility (location unconfirmed) +AnkhWest 0x0003 +4272 3696 0 + +# Honor +AnkhWest 0x0003 +1723 3527 8 + +# Justice +AnkhNorth 0x0004 +1300 629 21 + +# Valor (location unconfirmed) +AnkhWest 0x0003 +2489 3930 2 + +# Sacrifice +AnkhNorth 0x1E5D (Bloodied) +3354 287 4 + +# Spirituality +AnkhWest 0x0003 +1592 2489 20 + +Static 0x00DB +1588 2488 5 + +Static 0x070A +1594 2491 15 +1595 2491 15 + +Static 0x070B +1600 2489 10 +1600 2490 10 +1596 2489 15 +1596 2490 15 + +Static 0x070C +1594 2488 15 +1595 2488 15 + +Static 0x070E +1593 2488 15 + +Static 0x070F +1596 2491 15 + +Static 0x0710 +1596 2488 15 + +Static 0x0711 +1593 2491 15 + +KeywordTeleporter 0x1BC3 (Substring=om om om; Range=0; PointDest=(1595, 2489, 20); SourceEffect=true; DestEffect=true; SoundID=0x1FE; Delay=0:0:1) +1600 2489 12 + +KeywordTeleporter 0x1BC3 (Substring=om om om; Range=0; PointDest=(1595, 2490, 20); SourceEffect=true; DestEffect=true; SoundID=0x1FE; Delay=0:0:1) +1600 2490 12 + +Teleporter 0x1BC3 (PointDest=(1600, 2489, 12)) +1593 2488 17 +1594 2488 17 +1595 2488 17 \ No newline at end of file diff --git a/Data/Decoration/Britannia/skara.cfg b/Data/Decoration/Britannia/skara.cfg new file mode 100644 index 0000000..73dfe19 --- /dev/null +++ b/Data/Decoration/Britannia/skara.cfg @@ -0,0 +1,2212 @@ +############### +# Teleporters # +############### + +KeywordTeleporter 0x1BC3 (PointDest=(709, 2236, -2); Range=3; Substring=cross) +683 2233 -2 + +KeywordTeleporter 0x1BC3 (PointDest=(683, 2233, -2); Range=3; Substring=cross) +709 2236 -2 + +KeywordTeleporter 0x1BC3 (PointDest=(709, 2238, -2); Range=3; Substring=cross) +683 2242 -2 + +KeywordTeleporter 0x1BC3 (PointDest=(683, 2242, -2); Range=3; Substring=cross) +709 2238 -2 + + +############### +# Main Island # +############### + +# fireplace +Static 0x08DA +552 2171 0 + +# fireplace +Static 0x08DB +552 2170 0 + +# oven +StoneOvenEastAddon 0x092C +552 2168 0 + +# basket +Basket 0x0990 +609 2152 0 + +# fruit basket +FruitBasket 0x0993 +611 2154 6 + +# ceramic mug +CeramicMug 0x0997 +592 2276 4 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +616 2195 4 +643 2176 4 +627 2173 4 +669 2146 4 +562 2188 4 +562 2170 4 +600 2187 4 +558 2175 6 +556 2175 6 +552 2175 6 +568 2114 4 +592 2164 4 +611 2216 4 +558 2181 4 +576 2234 4 +648 2154 4 +562 2181 4 +558 2186 4 +584 2138 4 +562 2174 4 +602 2200 4 + +# fork +Fork 0x09A3 +669 2147 4 + +# fork +Fork 0x09A4 +628 2173 4 + +# knife +Knife 0x09A5 +669 2147 4 + +# knife +Knife 0x09A6 +628 2173 4 + +# metal box +FillableMetalBox 0x09A8 +581 2230 6 +595 2200 6 +589 2144 6 +652 2160 6 +604 2178 6 +620 2215 6 +603 2272 6 +603 2232 6 + +# small crate +FillableSmallCrate 0x09A9 +636 2161 0 +634 2163 0 + +# metal chest +MetalChest 0x09AB +595 2147 3 +596 2147 3 +593 2147 3 + +# spoon +Spoon 0x09C2 +669 2147 4 + +# spoon +Spoon 0x09C3 +628 2173 4 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +558 2172 6 +562 2176 4 +558 2182 4 +554 2182 4 +554 2187 4 +562 2187 4 +554 2188 4 + +# plate +Plate 0x09D7 +554 2175 6 +592 2275 4 +584 2139 4 +592 2165 4 +628 2173 4 +669 2147 4 +558 2174 6 +603 2200 4 +616 2196 4 +600 2186 4 +568 2115 4 +576 2235 4 +648 2155 4 +644 2176 4 +612 2216 4 + +# fork +Fork 0x09F4 +603 2200 4 +612 2216 4 +644 2176 4 +554 2175 6 + +# fork +Fork 0x09F5 +568 2115 4 +558 2174 6 +616 2196 4 +600 2186 4 +584 2139 4 +592 2275 4 +592 2165 4 +576 2235 4 +648 2155 4 + +# knife +Knife 0x09F6 +644 2176 4 +612 2216 4 +554 2175 6 +603 2200 4 + +# knife +Knife 0x09F7 +616 2196 4 +576 2235 4 +648 2155 4 +558 2174 6 +568 2115 4 +600 2186 4 +584 2139 4 +592 2275 4 +592 2165 4 + +# spoon +Spoon 0x09F8 +603 2200 4 +644 2176 4 +612 2216 4 + +# spoon +Spoon 0x09F9 +568 2115 4 +592 2165 4 +648 2155 4 +616 2196 4 +584 2139 4 +592 2275 4 +600 2186 4 +576 2235 4 + +# lantern post +Static 0x0A20 +678 2238 -3 + +# candle +CandleLarge 0x0A26 (Unlit) +651 2181 6 + +# chest of drawers +Drawer 0x0A2C +569 2168 0 +649 2152 0 +617 2250 0 +597 2272 0 +573 2112 0 +593 2250 0 +580 2232 0 +585 2136 0 +617 2192 0 +605 2250 0 +593 2160 0 + +# chest of drawers +Static 0x0A30 +601 2200 0 +605 2184 0 +610 2216 0 + +# chest of drawers +FancyDrawer 0x0A34 +598 2241 0 +610 2241 0 +610 2252 0 +640 2178 0 +664 2145 0 +624 2173 0 +598 2252 0 +616 2241 0 +592 2241 0 + +# armoire +FancyArmoire 0x0A4D +605 2200 0 +604 2184 0 + +# armoire +Armoire 0x0A4F +621 2250 0 +569 2112 0 +642 2176 0 +589 2136 0 +653 2152 0 +597 2160 0 +596 2272 0 +621 2192 0 + +# armoire +FancyArmoire 0x0A51 +608 2221 0 + +# armoire +Armoire 0x0A53 +616 2243 0 +568 2173 0 +664 2149 0 +624 2169 0 +576 2237 0 + +# bookcase +LibraryBookcase 0x0A97 +578 2120 0 +561 2216 0 +562 2136 0 +597 2144 0 +670 2144 0 +585 2160 0 +545 2208 0 +582 2120 0 +617 2215 0 + +# bookcase +LibraryBookcase 0x0A98 +593 2144 0 +618 2215 0 +579 2120 0 +581 2120 0 +548 2208 0 +546 2208 0 +563 2136 0 +666 2144 0 + +# bookcase +LibraryBookcase 0x0A99 +600 2283 0 +648 2157 0 +560 2217 0 +600 2276 0 +624 2192 0 +552 2220 0 +560 2221 0 +616 2217 0 +656 2140 0 +600 2177 0 +624 2164 0 +592 2277 0 +592 2273 0 +576 2233 0 + +# bookcase +LibraryBookcase 0x0A9A +552 2218 0 +560 2219 0 +648 2158 0 +656 2141 0 +600 2181 0 +624 2197 0 +600 2277 0 +600 2284 0 +624 2193 0 +616 2221 0 +624 2165 0 + +# bookcase +LibraryBookcase 0x0A9B +589 2160 0 +549 2208 0 +594 2144 0 +619 2215 0 +596 2144 0 +665 2144 0 +574 2120 0 +564 2136 0 + +# bookcase +LibraryBookcase 0x0A9C +624 2198 0 +600 2178 0 +560 2220 0 +552 2217 0 +560 2218 0 +552 2221 0 +600 2180 0 +600 2285 0 +600 2278 0 +624 2166 0 + +# wooden shelf +EmptyBookcase 0x0A9D +565 2216 0 +557 2216 0 +553 2216 0 + +# wooden shelf +EmptyBookcase 0x0A9E +600 2236 0 +600 2235 0 +544 2209 0 +544 2213 0 + +# candle +CandleLarge 0x0B1A +620 2219 6 +584 2140 4 +556 2202 4 +645 2176 4 +556 2220 4 +595 2205 6 +592 2274 4 +648 2156 4 +630 2161 6 +609 2157 6 +564 2220 4 +652 2163 6 +613 2216 4 +669 2148 4 +616 2197 4 +554 2139 4 +572 2123 6 +589 2148 6 +563 2154 6 +581 2188 6 +576 2236 4 +564 2138 4 +581 2226 6 +546 2212 4 +568 2116 4 +554 2145 4 +592 2166 4 +589 2200 6 +626 2191 6 +586 2164 6 +604 2200 4 +629 2173 4 +562 2202 4 + +# lamp post +LampPost1 0x0B20 +584 2127 0 +624 2143 0 +624 2237 0 +655 2150 0 +592 2191 0 +632 2224 0 +600 2167 0 +591 2232 0 +599 2142 0 +607 2208 0 +591 2257 0 +575 2177 0 +575 2152 0 +608 2279 0 +616 2183 0 +640 2167 0 +639 2190 0 +575 2206 0 + +# candelabra +CandelabraStand 0x0B26 +552 2189 0 +630 2120 0 +592 2248 0 +609 2133 0 +629 2133 0 +608 2120 0 +565 2188 0 + +# water trough +WaterTroughEastAddon 0x0B41 +544 2124 0 +544 2120 0 + +# chair +FancyWoodenChairCushion 0x0B51 +565 2139 0 + +# chair +WoodenChairCushion 0x0B52 +602 2234 0 +603 2180 0 +553 2142 0 +545 2211 0 +619 2217 0 +571 2121 0 +636 2156 0 +636 2155 0 + +# chair +WoodenChairCushion 0x0B53 +637 2152 0 +636 2152 0 +559 2201 0 +588 2163 0 + +# chair +WoodenChairCushion 0x0B55 +596 2203 0 +565 2219 0 +557 2219 0 + +# chair +WoodenChair 0x0B56 +563 2138 0 +588 2146 0 +580 2228 0 +563 2220 0 +563 2218 0 +563 2140 0 +609 2155 0 +555 2218 0 +555 2220 0 +553 2146 0 +627 2193 0 +553 2138 0 +553 2140 0 +590 2203 0 +668 2147 0 +553 2144 0 + +# chair +WoodenChair 0x0B57 +634 2152 0 +566 2208 0 +562 2208 0 +628 2172 0 +557 2208 0 +633 2152 0 +650 2162 0 +557 2201 0 +635 2153 6 +553 2208 0 +650 2180 0 +561 2201 0 + +# chair +WoodenChair 0x0B58 +585 2139 0 +569 2115 0 +588 2202 0 +617 2196 0 +593 2275 0 +556 2142 0 +556 2138 0 +556 2144 0 +547 2210 0 +547 2212 0 +666 2138 0 +556 2140 0 +649 2155 0 +556 2146 0 +577 2235 0 +601 2186 0 +593 2165 0 +605 2180 0 + +# chair +WoodenChair 0x0B59 +644 2177 0 +560 2204 0 +612 2217 0 +562 2204 0 +603 2201 0 +627 2162 0 +558 2204 0 +556 2204 0 +628 2158 0 +628 2155 0 + +# chair +BambooChair 0x0B5A +635 2155 6 +602 2274 0 + +# foot stool +FootStool 0x0B5E +554 2176 0 +558 2176 0 +552 2176 0 +556 2176 0 +559 2174 0 +559 2172 0 +559 2170 0 + +# wooden signpost +Static 0x0B98 +678 2239 -3 + +# sign +Static 0x0BB2 (Name=Skara Brae Ferry : Step onto the boat and say "I would like to cross) +679 2240 7 + +# broken chair +Static 0x0C10 +630 2157 6 + +# broken chair +Static 0x0C11 +627 2157 6 +630 2154 6 + +# broken chair +Static 0x0C19 +626 2154 6 + +# small fish +Static 0x0DD6 +669 2237 -2 +661 2234 -2 +642 2245 -2 +678 2234 -3 +638 2228 -3 + + + + +# small fish +Static 0x0DD8 +661 2228 -2 +660 2243 -2 +641 2227 -2 +642 2234 -2 +676 2246 -2 +642 2233 -2 +676 2226 -2 + +# small fish +Static 0x0DD9 +644 2243 -2 +644 2234 -2 +661 2244 -2 +672 2234 -2 +679 2225 -2 + +# chessmen +Static 0x0E13 +554 2181 4 + +# chessmen +Static 0x0E14 +554 2181 4 + +# cards +Static 0x0E17 +562 2182 4 + +# cards +Static 0x0E18 +562 2183 4 + +# cards +Static 0x0E19 +562 2183 4 + +# checkers +Static 0x0E1A +562 2169 4 + +# checkers +Static 0x0E1B +562 2169 4 + +# clean bandage +Static 0x0E21 +651 2180 0 + +# bloody water +Static 0x0E23 +623 2211 0 +616 2209 0 +624 2208 0 + +# crystal ball +Static 0x0E2F (Light=Circle150) +604 2179 6 + +# brazier +Brazier 0x0E31 +600 2176 0 +600 2184 0 + +# brazier +Brazier 0x0E32 +656 2136 0 + +# crate +FillableLargeCrate 0x0E3C +635 2160 7 +634 2160 3 +634 2161 3 +634 2160 0 +634 2161 0 + +# crate +FillableLargeCrate 0x0E3D +585 2224 0 +584 2225 3 +585 2224 3 +584 2225 0 +585 2224 6 +584 2224 6 +586 2224 3 +584 2224 3 +586 2224 0 +584 2224 0 +586 2224 6 +586 2225 3 +585 2224 9 +585 2225 0 +586 2225 0 + +# crate +MediumCrate 0x0E3E +635 2162 7 +636 2159 3 +636 2159 0 + +# metal chest +FillableMetalGoldenChest 0x0E40 +592 2243 0 +610 2251 0 +610 2243 0 +584 2148 6 +604 2251 0 +616 2251 0 +592 2251 0 +598 2251 0 +598 2243 0 + +# metal chest +MetalGoldenChest 0x0E41 +594 2147 3 + +# metal chest +FillableMetalGoldenChest 0x0E41 +617 2240 0 + +# wooden chest +WoodenChest 0x0E42 +584 2146 6 + +# barrel +FillableBarrel 0x0E77 +583 2230 5 +639 2246 2 +582 2230 0 +583 2229 5 +608 2152 0 +582 2230 10 +582 2229 5 +639 2245 -2 +583 2229 0 +641 2235 -2 +640 2245 -2 +659 2224 -2 +677 2244 -2 +642 2236 -2 +552 2174 5 +576 2230 0 +552 2173 0 +641 2236 -2 +608 2153 0 +642 2235 -2 +583 2230 10 +608 2152 5 +582 2229 0 +555 2168 5 +552 2173 5 +658 2224 -2 +552 2174 0 +555 2168 0 +556 2168 0 +639 2246 -3 +676 2243 -2 +583 2230 0 +676 2244 -2 + +# metal chest +MetalChest 0x0E7C +584 2145 6 +584 2149 6 +584 2147 6 + +# crate +FillableSmallCrate 0x0E7E +635 2163 6 + +# strong box +FillableMetalBox 0x0E80 +608 2157 6 +625 2161 6 +590 2164 6 +624 2191 6 +577 2188 6 +648 2181 6 +570 2123 6 + +# cleaver +Static 0x0EC3 +576 2185 6 + +# dress form +Dressform 0x0EC6 +648 2180 0 + +# dress form +Dressform 0x0EC7 +648 2183 0 + +# saddle +Static 0x0F37 +562 2129 0 + +# bolt of cloth +Static 0x0F99 +653 2181 0 + +# bolt of cloth +Static 0x0F9A (Hue=0x1F2) +648 2179 0 + +# bolt of cloth +Static 0x0F9A (Hue=0x31E) +653 2181 0 + +# bolt of cloth +Static 0x0F9B (Hue=0x1ED) +651 2176 0 + +# bolt of cloth +Static 0x0F9C (Hue=0x58) +651 2176 0 + +# sewing kit +Static 0x0F9D +649 2181 6 + +# scissors +Scissors 0x0F9F +652 2181 6 + +# checker board +CheckerBoard 0x0FA6 +562 2169 4 + +# chess board +ChessBoard 0x0FA6 +554 2181 4 + +# dice and cup +Dices 0x0FA7 +558 2187 4 + +# backgammon game +Backgammon 0x0FAD +558 2188 4 + +# anvil +AnvilSouthAddon 0x0FB0 +633 2195 0 +632 2195 0 + +# sledge hammer +Static 0x0FB4 +632 2196 0 +634 2198 6 + +# horse shoes +Static 0x0FB6 +628 2195 6 +635 2196 0 + +# forged metal +Static 0x0FB8 +633 2195 0 + +# tongs +Static 0x0FBB +634 2194 0 +636 2198 6 + +# book +Static 0x0FBD +564 2219 4 +603 2234 6 +628 2193 6 +665 2138 6 +581 2228 6 +564 2139 4 +611 2155 6 +589 2146 6 +546 2211 4 +620 2217 6 +572 2121 6 +556 2219 4 +554 2142 4 +603 2274 6 +595 2203 6 +604 2180 6 + +# book +Static 0x0FBE +650 2181 6 +627 2161 6 +650 2163 6 +559 2202 4 +588 2164 6 +579 2188 6 + +# pen and ink +Static 0x0FBF +589 2146 6 +564 2219 4 +556 2219 4 +546 2211 4 +554 2142 4 +581 2228 6 +665 2138 6 +620 2217 6 +603 2274 6 +603 2234 6 +604 2180 6 +611 2155 6 +572 2121 6 +564 2139 4 +595 2202 6 +628 2193 6 + +# pen and ink +Static 0x0FC0 +559 2202 4 +588 2164 6 +650 2163 6 +650 2181 6 +579 2188 6 +627 2161 6 + +# book +TamingDragons 0x0FEF +564 2208 4 + +# book +RedBook 0x0FF1 +554 2208 4 +576 2120 4 + +# book +BlueBook 0x0FF2 +565 2208 4 + +# book +DeceitDungeonOfHorror 0x0FF3 +563 2208 4 + +# book +CallToAnarchy 0x0FF4 +575 2120 4 + +# book +TalkingToWisps 0x0FF4 +556 2208 4 + +# pewter mug +PewterMug 0x0FFF +558 2189 4 +562 2176 4 +562 2189 4 +562 2183 4 +554 2189 4 + +# pewter mug +PewterMug 0x1001 +600 2185 4 +562 2180 4 +558 2183 4 +562 2189 4 +554 2183 4 + +# spittoon +Static 0x1003 +561 2173 0 +558 2179 0 +552 2184 0 + +# spinning wheel +SpinningWheelEastAddon 0x1019 +648 2176 0 + +# pile of wool +Static 0x101F (Hue=0x1ED) +652 2178 0 + +# pile of wool +Static 0x101F (Hue=0x31E) +649 2177 0 + +# dovetail saw +Static 0x1029 +629 2157 6 + +# hammer +Static 0x102A +629 2154 6 +591 2203 6 +630 2164 6 +628 2157 6 + +# hammer +Static 0x102B +587 2203 6 + +# nails +Static 0x102E +628 2157 6 +628 2154 6 + +# nails +Static 0x102F +587 2201 6 +630 2163 6 +590 2200 6 + +# saw +Static 0x1034 +591 2200 6 + +# saw +Static 0x1035 +627 2154 6 + +# wood curls +Static 0x1038 +627 2156 0 +626 2159 0 +628 2153 0 +629 2156 0 +628 2159 0 +626 2153 0 +625 2155 0 +625 2153 0 +625 2156 0 +625 2158 0 +625 2157 0 +632 2158 0 +630 2159 0 +631 2159 0 +632 2157 0 +632 2155 0 +632 2154 0 +630 2156 0 +630 2153 0 +631 2153 0 +631 2156 0 + +# globe +Static 0x1047 +601 2272 0 + +# loom bench +Static 0x1049 +650 2176 0 + +# loom bench +Static 0x104A +653 2178 0 + +# upright loom +LoomSouthAddon 0x1061 +652 2177 0 + +# potted tree +PottedTree 0x11C8 +616 2192 0 +552 2216 0 +576 2232 0 +648 2152 0 + +# potted tree +PottedTree1 0x11C9 +584 2136 0 +568 2112 0 +544 2208 0 +584 2200 0 +592 2272 0 +600 2200 0 +640 2176 0 +600 2232 0 +624 2184 0 +552 2200 0 +600 2272 0 +566 2200 0 +560 2136 0 + +# flowerpot +PottedPlant 0x11CA +568 2168 0 +568 2120 0 +560 2216 0 +584 2160 0 +567 2208 0 +664 2144 0 +616 2215 0 +592 2160 0 +552 2208 0 +592 2246 0 +608 2216 0 +624 2168 0 +648 2160 0 + +# flowerpot +PottedPlant1 0x11CB +630 2162 9 +603 2236 9 +595 2206 9 +600 2279 9 +600 2282 9 +652 2162 9 +576 2188 8 + +# flowerpot +PottedPlant2 0x11CC +603 2276 9 +611 2157 8 +620 2216 9 +628 2191 10 +581 2186 8 +624 2161 9 + +# statue +Static 0x1228 +563 2152 8 + +# tarot +Static 0x12A6 +604 2181 6 + +# brush +Static 0x1370 +578 2123 6 + +# brush +Static 0x1372 +579 2123 6 + +# bridle +Static 0x1374 +577 2123 6 + +# bridle +Static 0x1375 +576 2123 6 + +# statue +Static 0x139B +563 2156 9 + +# ship model +Static 0x14F3 +600 2280 6 + +# ship model +Static 0x14F4 +600 2281 6 + +# rope +Static 0x14F8 +620 2274 -3 +658 2245 -3 +679 2234 -3 + +# rope +Static 0x14FA +645 2229 -3 + +# water barrel +Static 0x154D +677 2224 -2 +640 2225 -2 +639 2226 -2 +657 2224 -2 +657 2239 -2 +633 2193 0 +673 2233 -3 +582 2230 5 +639 2225 -2 + +# folded cloth +Static 0x175D +648 2187 6 + +# folded cloth +Static 0x175E (Hue=0x31E) +648 2185 6 + +# folded cloth +Static 0x1762 +649 2182 0 + +# folded cloth +Static 0x1764 (Hue=0x31E) +648 2182 0 + +# cloth +Static 0x1767 +648 2182 0 + +# cut cloth +Static 0x1768 (Hue=0x58) +648 2186 6 + +# hourglass +Static 0x1811 +669 2136 6 + +# scales +Scales 0x1851 +668 2136 6 + +# skull with candle +CandleSkull 0x1854 +665 2140 6 + +# skull with candle +CandleSkull 0x1858 +665 2136 6 + +# empty vials +Static 0x185B +670 2136 6 + +# full vials +Static 0x185D +667 2136 6 + +# bellows +Static 0x1986 +636 2193 0 + +# forge +Static 0x198A (Light=Circle300) +636 2194 0 + +# forge +Static 0x198E +636 2195 0 + +# feather +Static 0x1BD1 +587 2204 6 + +# shaft +Static 0x1BD4 +591 2204 6 +588 2200 6 +587 2202 6 +591 2202 6 + +# boards +Static 0x1BD8 +613 2273 0 + +# boards +Static 0x1BD9 +608 2277 0 +608 2278 0 + +# boards +Static 0x1BDB +615 2278 0 + +# bulletin board +BulletinBoard 0x1E5E +559 2168 0 + +# prow +Static 0x3E9A +683 2238 -5 +683 2230 -5 + +# ship +Static 0x3E9B +682 2231 -5 +682 2239 -5 + +# ship +Static 0x3E9C +684 2239 -5 +684 2231 -5 + +# ship +Static 0x3E9D +682 2240 -5 +682 2232 -5 + +# ship +Static 0x3E9E +684 2232 -5 +684 2240 -5 + +# ship +Static 0x3E9F +682 2241 -5 +682 2233 -5 + +# ship +Static 0x3EA0 +684 2241 -5 +684 2233 -5 + +# deck +Static 0x3EA1 +682 2242 -5 +682 2234 -5 + +# ship +Static 0x3EA6 +684 2234 -5 +684 2242 -5 + +# ship +Static 0x3EA7 +682 2235 -5 +682 2243 -5 + +# ship +Static 0x3EA8 +684 2235 -5 +684 2243 -5 + +# ship +Static 0x3EAB +684 2236 -5 +684 2244 -5 + +# deck +Static 0x3EAC +683 2235 -5 +683 2234 -5 +683 2243 -5 +683 2242 -5 + +# deck +Static 0x3EAD +683 2232 -5 +683 2240 -5 + +# hatch +Static 0x3EAE +683 2231 -5 +683 2239 -5 + +# deck +Static 0x3EB0 +683 2233 -5 +683 2241 -5 + +# ship +Static 0x3EB6 +682 2244 -5 +682 2236 -5 + +# rudder +Static 0x3EBC +683 2237 -5 +683 2245 -5 + +# deck +Static 0x3EC0 +683 2244 -5 +683 2236 -5 + +# gang plank +Static 0x3ED5 +681 2242 -5 +681 2234 -5 + + +############### +# East Island # +############### + +# tent wall +Static 0x02EB (Hue=0x33) +752 2210 4 +747 2208 9 +762 2200 0 +753 2197 6 + +# tent wall +Static 0x02EC (Hue=0x33) +753 2209 4 +754 2196 6 +763 2199 0 +748 2207 9 + +# gruesome standard +Static 0x041F +757 2193 12 + +# gruesome standard +Static 0x0420 +765 2201 0 + +# fireplace +Static 0x08DA +808 2333 0 +888 2396 0 + +# fireplace +Static 0x08DB +888 2395 0 +808 2332 0 + +# fireplace +Static 0x08DE +821 2192 0 +804 2264 0 + +# fireplace +Static 0x08DF +803 2264 0 +820 2192 0 + +# oven +StoneOvenEastAddon 0x092C +887 2393 0 +807 2330 0 + +# oven +StoneOvenSouthAddon 0x0930 +818 2191 0 +802 2264 0 + +# cauldron +Static 0x0974 +756 2267 0 +748 2350 0 +755 2203 0 + +# cauldron +Static 0x0975 +870 2324 0 +786 2233 0 + +# slab of bacon +Static 0x0976 +790 2232 6 + +# slab of bacon +Static 0x0977 +866 2320 6 + +# basket +Basket 0x0990 +892 2396 6 + +# tray +Static 0x0992 +810 2334 6 +890 2398 6 + +# ceramic mug +CeramicMug 0x0995 +813 2196 4 +796 2267 4 + +# ceramic mug +CeramicMug 0x0996 +796 2266 4 +813 2195 4 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +891 2387 4 +748 2264 6 +784 2220 16 +810 2322 4 +740 2344 6 +864 2316 6 + +# fork +Fork 0x09A3 +890 2385 4 +890 2387 4 +810 2321 4 +810 2323 4 + +# fork +Fork 0x09A4 +814 2195 4 +797 2266 4 + +# knife +Knife 0x09A5 +890 2385 4 +810 2323 4 +890 2387 4 +810 2321 4 + +# knife +Knife 0x09A6 +797 2266 4 +814 2195 4 + +# bushel +Basket 0x09AC +803 2268 6 +822 2192 6 +819 2195 0 +810 2332 0 + +# spoon +Spoon 0x09C2 +810 2323 4 +890 2385 4 +890 2386 4 +810 2321 4 + +# spoon +Spoon 0x09C3 +797 2266 4 +814 2195 4 + +# ham +Static 0x09D3 +754 2263 6 +866 2321 6 + +# plate +Plate 0x09D7 +810 2321 4 +739 2344 6 +890 2385 4 +797 2266 4 +811 2322 4 +810 2323 4 +891 2386 4 +797 2267 4 +890 2387 4 +814 2195 4 +747 2264 6 +814 2196 4 +864 2315 6 +784 2219 16 + +# kettle +Static 0x09ED +809 2334 6 +889 2398 6 +819 2192 0 +806 2265 6 + +# fork +Fork 0x09F4 +747 2264 6 +814 2196 4 +797 2267 4 +739 2344 6 + +# fork +Fork 0x09F5 +784 2219 16 +891 2386 4 +864 2315 6 +811 2322 4 + +# knife +Knife 0x09F6 +739 2344 6 +747 2264 6 +814 2196 4 +797 2267 4 + +# knife +Knife 0x09F7 +864 2315 6 +811 2322 4 +784 2219 16 +891 2386 4 + +# spoon +Spoon 0x09F8 +797 2267 4 +739 2344 6 +747 2264 6 +814 2196 4 + +# spoon +Spoon 0x09F9 +864 2315 6 +784 2219 16 +811 2322 4 +891 2386 4 + +# lantern post +Static 0x0A20 +712 2234 -3 + +# lantern +Lantern 0x0A22 +738 2344 6 +746 2264 6 +784 2218 16 +793 2272 12 +814 2200 12 +816 2320 12 +864 2314 6 +896 2384 13 + +# chest of drawers +Drawer 0x0A2C +818 2328 0 +897 2392 0 + +# chest of drawers +Drawer 0x0A34 +808 2186 0 +800 2273 0 + +# armoire +Armoire 0x0A4F +810 2184 0 +802 2272 0 + +# armoire +Armoire 0x0A53 +816 2330 0 +896 2394 0 + +# bookcase +LibraryBookcase 0x0A97 +809 2192 0 +814 2320 0 +737 2136 0 +893 2384 0 + +# bookcase +LibraryBookcase 0x0A98 +894 2384 0 +813 2192 0 +741 2136 0 + +# bookcase +LibraryBookcase 0x0A99 +736 2137 0 +736 2141 0 +792 2269 0 +888 2391 0 +888 2386 0 +808 2327 0 +808 2324 0 +808 2193 0 + +# bookcase +LibraryBookcase 0x0A9A +808 2197 0 +792 2270 0 +888 2390 0 +808 2326 0 + +# bookcase +LibraryBookcase 0x0A9B +813 2320 0 +814 2192 0 + +# bookcase +LibraryBookcase 0x0A9C +888 2387 0 +792 2265 0 +808 2325 0 +888 2389 0 + +# candle +CandleLarge 0x0B1A +893 2390 4 +753 2145 4 +753 2141 4 +738 2139 4 +798 2267 4 +815 2196 4 +812 2334 6 +811 2321 4 + +# candelabra +CandelabraStand 0x0B26 +757 2149 0 + +# chair +WoodenChairCushion 0x0B53 +739 2138 0 +753 2138 0 + +# chair +WoodenChair 0x0B56 +751 2140 0 +751 2146 0 +751 2144 0 +751 2142 0 + +# chair +WoodenChair 0x0B57 +797 2265 0 +814 2194 0 + +# chair +WoodenChair 0x0B58 +793 2267 0 +755 2144 0 +755 2146 0 +755 2142 0 +809 2195 0 +755 2140 0 + +# chair +WoodenChair 0x0B59 +740 2140 0 +738 2140 0 +814 2197 0 +797 2268 0 + +# chair +BambooChair 0x0B5A +809 2323 0 +809 2321 0 +889 2387 0 +892 2391 0 +812 2327 0 +889 2385 0 + +# chair +BambooChair 0x0B5C +739 2345 0 +747 2265 0 + +# chair +BambooChair 0x0B5D +865 2315 0 +812 2322 0 +892 2386 0 +785 2219 10 + +# wooden signpost +Static 0x0B98 +712 2235 -3 + +# sign +Static 0x0BB2 (Name=Skara Brae Ferry : Step onto the boat and say "I would like to cross) +713 2236 7 + +# small fish +Static 0x0DD6 +716 2236 -2 + +# small fish +Static 0x0DD8 +724 2239 -1 +715 2234 -3 + +# small fish +Static 0x0DD9 +724 2238 -3 +713 2238 -1 + +# campfire +Static 0x0DE3 (Light=Circle225) +755 2203 0 + +# wooden chest +WoodenChest 0x0E42 +864 2313 0 +736 2346 0 +744 2269 0 + +# wooden chest +WoodenChest 0x0E43 +785 2216 10 + +# stump +Static 0x0E58 +756 2201 0 + +# stump +Static 0x0E59 +753 2202 0 + +# barrel +Barrel 0x0E77 +744 2264 5 +784 2222 15 +718 2232 -2 +745 2264 5 +784 2221 10 +784 2222 10 +784 2221 15 +720 2232 -2 +729 2232 -2 +729 2233 -2 +744 2264 0 +744 2265 0 +745 2264 0 +728 2232 -2 + +# sheaf of hay +Static 0x0F36 +755 2153 0 +752 2153 0 + +# executioner's axe +Static 0x0F46 +754 2201 0 + +# dying tub +DyeTub 0x0FAB (Hue=0x8A) +864 2317 0 + +# dying tub +DyeTub 0x0FAB (Hue=0x2DD) +741 2344 0 + +# fire pit +Static 0x0FAC (Light=Circle225) +755 2203 0 +870 2324 0 +756 2267 0 +786 2233 0 +748 2350 0 + +# book +Static 0x0FBD +792 2267 4 +813 2327 4 +893 2391 4 +808 2195 4 + +# book +Static 0x0FBE +739 2139 4 +753 2139 4 + +# pen and ink +Static 0x0FBF +893 2391 4 +813 2327 4 +792 2267 4 +808 2195 4 + +# pen and ink +Static 0x0FC0 +739 2139 4 +753 2139 4 + +# pewter mug +PewterMug 0x0FFF +740 2344 6 +748 2264 6 +891 2385 4 + +# pewter mug +PewterMug 0x1000 +864 2316 6 +784 2220 16 +811 2323 4 + +# pewter mug +PewterMug 0x1001 +891 2385 4 + +# pewter mug +PewterMug 0x1002 +810 2323 4 +890 2386 4 +810 2321 4 + +# wash basin +Static 0x1008 +785 2217 10 +745 2265 0 +745 2346 6 +866 2322 6 + +# archery butte +ArcheryButte 0x100B +756 2153 0 +753 2153 0 + +# hay sheave +Static 0x100D +757 2153 0 +754 2153 0 + +# hay +Static 0x1036 +755 2159 0 +752 2161 0 +866 2317 0 +759 2153 0 +748 2268 0 +748 2269 0 +786 2222 10 +786 2218 10 +749 2267 0 +749 2269 0 +755 2153 0 +754 2155 0 +867 2315 0 +869 2316 0 +869 2317 0 +869 2315 0 +867 2316 0 +867 2318 0 +868 2318 0 +753 2156 0 +756 2155 0 +865 2318 0 +756 2157 0 +870 2313 0 +758 2156 2 +758 2154 0 +742 2350 0 +787 2221 10 +741 2350 0 +738 2346 0 +737 2350 0 +787 2218 10 +787 2220 10 +739 2349 0 +740 2350 0 +788 2220 10 +788 2221 10 +746 2269 0 +739 2347 0 +741 2348 0 +742 2349 0 +787 2217 10 +747 2268 0 +754 2159 0 +789 2222 10 +789 2221 10 +742 2347 0 +747 2267 0 + +# dough +Static 0x103D +806 2266 9 +822 2194 9 + +# cookie mix +Static 0x103F +806 2264 9 +822 2195 9 + +# rolling pin +Static 0x1043 +820 2196 0 + +# garbage +Static 0x10EE +754 2200 0 +757 2194 13 +761 2199 0 +754 2209 5 +761 2200 0 +753 2204 5 +754 2210 1 +756 2201 0 +755 2205 1 +757 2203 0 +762 2201 0 + +# potted tree +PottedTree 0x11C8 +902 2392 0 +808 2184 0 + +# potted tree +PottedTree1 0x11C9 +888 2384 0 +736 2144 0 +800 2272 0 +816 2328 0 + +# flowerpot +PottedPlant 0x11CA +808 2320 0 +896 2392 0 +792 2264 0 +808 2192 0 + +# Archer's Guild +LocalizedSign 0x1299 (LabelNumber=1016044) +742 2232 14 + +# Docks to Skara Brae +LocalizedSign 0x129A (LabelNumber=1016103) +742 2232 17 +772 2240 16 +813 2240 10 + +# Britain +LocalizedSign 0x129C (LabelNumber=1016070) +742 2232 10 +772 2240 13 +813 2240 15 + +# Ferry Out of Service +LocalizedSign 0x129D (LabelNumber=1016113) +712 2232 13 + +# plough +Static 0x1500 +899 2405 0 + +# plough +Static 0x1501 +898 2405 0 + +# plough +Static 0x1502 +810 2281 0 +833 2341 0 + +# plough +Static 0x1503 +833 2342 0 +810 2282 0 + +# harrow +Static 0x1505 +828 2338 0 +814 2276 0 + +# harrow +Static 0x1507 +895 2406 0 + +# water barrel +Static 0x154D +728 2233 -2 +752 2268 0 +871 2321 0 +719 2232 -2 +722 2238 -2 +784 2230 0 +748 2345 0 + +# bowl of carrots +Static 0x15F9 +806 2267 6 + +# bowl of lettuce +Static 0x15FB +805 2268 6 + +# pewter bowl +Static 0x15FD +813 2328 4 + +# large pewter bowl +Static 0x1603 +811 2334 6 + +# leaves +Static 0x1B23 (Hue=0x970) +875 2326 0 +887 2424 0 +861 2280 0 +789 2220 10 +804 2198 0 +795 2289 0 +803 2197 0 +831 2223 13 +794 2304 0 +855 2363 0 +894 2382 0 +859 2342 0 +842 2356 0 +805 2189 0 +890 2365 0 +863 2391 0 +806 2303 0 +835 2296 8 +839 2231 0 +879 2395 0 +892 2245 0 +872 2374 0 +831 2269 0 +878 2395 0 + +# leaves +Static 0x1B24 (Hue=0x970) +890 2363 0 +879 2393 0 +859 2340 0 +842 2354 0 +861 2278 0 +806 2301 0 +878 2393 0 +789 2218 10 +875 2324 0 +863 2389 0 +894 2380 0 +872 2372 0 +805 2187 0 +794 2302 0 +831 2221 13 +855 2361 0 +803 2195 0 +892 2243 0 +887 2422 0 +831 2267 0 +835 2294 6 +804 2196 0 +839 2229 0 + +# leaves +Static 0x1B25 (Hue=0x970) +853 2361 0 +837 2229 0 +803 2187 0 +890 2243 0 +804 2301 0 +833 2294 10 +792 2302 0 +888 2363 0 +859 2278 0 +877 2393 0 +787 2218 10 +876 2393 0 +873 2324 0 +829 2267 0 +861 2389 0 +885 2422 0 +870 2372 0 +840 2354 0 +857 2340 0 +829 2221 13 +801 2195 0 +802 2196 0 +904 2235 0 +892 2380 0 +793 2287 0 + +# leaves +Static 0x1B26 (Hue=0x970) +802 2198 0 +829 2223 13 +792 2304 0 +787 2220 10 +870 2374 0 +793 2289 0 +840 2356 0 +892 2382 0 +801 2197 0 +885 2424 0 +859 2280 0 +888 2365 0 +837 2231 0 +904 2237 0 +857 2342 0 +873 2326 0 +876 2395 0 +890 2245 0 +853 2363 0 +833 2296 10 +861 2391 0 +877 2395 0 +803 2189 0 +829 2269 0 +804 2303 0 + +# tightrope +Static 0x2710 +710 2236 -3 +711 2236 -3 + +# prow +Static 0x3E9A +709 2234 -5 + +# ship +Static 0x3E9B +708 2235 -5 + +# ship +Static 0x3E9C +710 2235 -5 + +# ship +Static 0x3E9D +708 2236 -5 + +# ship +Static 0x3E9E +710 2236 -5 + +# ship +Static 0x3E9F +708 2237 -5 + +# ship +Static 0x3EA0 +710 2237 -5 + +# deck +Static 0x3EA1 +708 2238 -5 + +# ship +Static 0x3EA7 +708 2239 -5 + +# ship +Static 0x3EA8 +710 2239 -5 + +# ship +Static 0x3EAB +710 2240 -5 + +# deck +Static 0x3EAC +709 2238 -5 +709 2239 -5 +710 2238 -5 + +# deck +Static 0x3EAD +709 2236 -5 + +# hatch +Static 0x3EAE +709 2235 -5 + +# deck +Static 0x3EB0 +709 2237 -5 + +# ship +Static 0x3EB1 +707 2238 -5 + +# ship +Static 0x3EB6 +708 2240 -5 + +# rudder +Static 0x3EBC +709 2241 -5 + +# deck +Static 0x3EC0 +709 2240 -5 + +# gang plank +Static 0x3ED4 +711 2238 -5 \ No newline at end of file diff --git a/Data/Decoration/Britannia/solen matriarch quest.cfg b/Data/Decoration/Britannia/solen matriarch quest.cfg new file mode 100644 index 0000000..8559b05 --- /dev/null +++ b/Data/Decoration/Britannia/solen matriarch quest.cfg @@ -0,0 +1,6 @@ +# Water Vats +WaterVatSouth 0x0 +5806 1919 5 + +WaterVatEast 0x0 +5797 1926 5 \ No newline at end of file diff --git a/Data/Decoration/Britannia/study of solen quest.cfg b/Data/Decoration/Britannia/study of solen quest.cfg new file mode 100644 index 0000000..bbc2575 --- /dev/null +++ b/Data/Decoration/Britannia/study of solen quest.cfg @@ -0,0 +1,7 @@ +# Naturalists +Spawner 0x1F13 (Spawn=Naturalist; Count=1; HomeRange=0) +1495 1721 7 +1414 1594 30 +1574 1697 35 +1393 3769 0 +5240 174 15 \ No newline at end of file diff --git a/Data/Decoration/Britannia/trinsic.cfg b/Data/Decoration/Britannia/trinsic.cfg new file mode 100644 index 0000000..1f36ec2 --- /dev/null +++ b/Data/Decoration/Britannia/trinsic.cfg @@ -0,0 +1,1996 @@ +# battlement +Static 0x0173 +1891 2706 40 + +# sandstone wall +Static 0x0176 +1884 2726 40 + +# sandstone wall +Static 0x0178 +1896 2707 20 + +# wooden ramp +Static 0x087A +1974 2782 10 + +# fireplace +Static 0x08DA +1877 2810 10 + +# fireplace +Static 0x08DB +1877 2809 10 + +# oven +StoneOvenEastAddon 0x092C +1877 2806 10 +1985 2894 5 + +# fireplace +StoneFireplaceEastAddon 0x0959 +1925 2788 0 +1985 2897 5 + +# fireplace +StoneFireplaceSouthAddon 0x0961 +1863 2824 10 + +# slab of bacon +Static 0x0976 +1987 2893 11 + +# tray +Static 0x0991 +1843 2829 14 +1846 2761 20 +1852 2761 20 +1859 2764 20 +1859 2830 16 +1951 2675 34 + +# tray +Static 0x0992 +1842 2759 0 +1847 2759 0 +1853 2759 0 +1856 2772 20 +1858 2757 20 +1858 2759 0 +1946 2675 34 + +# fruit basket +FruitBasket 0x0993 +1947 2683 34 +1949 2674 34 + +# ceramic mug +CeramicMug 0x0995 +2026 2747 54 + +# ceramic mug +CeramicMug 0x0996 +2027 2744 54 +2027 2746 54 + +# ceramic mug +CeramicMug 0x0997 +2026 2745 54 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +1866 2647 24 +1867 2646 24 + +# fork +Fork 0x09A3 +1842 2830 14 +1946 2680 34 +1946 2682 34 +1946 2684 34 +1946 2686 34 + +# fork +Fork 0x09A4 +1946 2679 34 +1948 2679 34 + +# knife +Knife 0x09A5 +1842 2830 14 +1946 2680 34 +1946 2682 34 +1946 2684 34 +1946 2686 34 + +# knife +Knife 0x09A6 +1946 2679 34 +1948 2679 34 + +# glass pitcher +Pitcher 0x09A7 +1842 2831 14 + +# metal box +FillableMetalBox 0x09A8 +1846 2738 6 +1846 2794 -2 +1882 2808 16 +1888 2657 16 +1918 2811 6 +1928 2794 6 +1984 2838 21 +1988 2865 26 +2034 2807 16 + +# metal chest +MetalChest 0x09AB +1811 2834 0 + +# bushel +Basket 0x09AC +2020 2835 0 +2020 2836 0 +2020 2840 0 +2024 2859 6 +2024 2862 6 +2024 2865 6 +2026 2832 0 +2029 2859 6 +2029 2862 6 +2029 2865 6 + +# cooked bird +Static 0x09B8 +1946 2675 34 +1985 2893 11 + +# raw bird +Static 0x09B9 +1993 2893 11 + +# spoon +Spoon 0x09C2 +1842 2830 14 +1946 2680 34 +1946 2682 34 +1946 2684 34 +1946 2686 34 + +# spoon +Spoon 0x09C3 +1946 2679 34 +1948 2679 34 + +# bottles of wine +Static 0x09C5 +1944 2674 34 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +1866 2646 24 +1867 2648 24 +1932 2795 2 +1947 2679 34 +1947 2680 34 +1947 2682 34 +1947 2684 34 +1947 2686 34 + +# ceramic mug +CeramicMug 0x09CA +2025 2746 54 +2025 2747 54 + +# fish +Static 0x09CC +2023 2862 6 + +# fish +Static 0x09CE +2028 2865 6 + +# silverware +Static 0x09D4 +1898 2687 16 + +# plate +Plate 0x09D7 +1842 2830 14 +1843 2830 14 +1946 2679 34 +1946 2680 34 +1946 2682 34 +1946 2684 34 +1946 2686 34 +1948 2679 34 +1948 2680 34 +1948 2682 34 +1948 2684 34 +1948 2686 34 + +# pot +Static 0x09E4 +1859 2832 16 + +# muffins +Muffins 0x09EB +1842 2759 0 +1847 2759 0 +1853 2759 0 +1856 2772 20 +1858 2757 20 +1858 2759 0 +1859 2764 20 + +# kettle +Static 0x09ED +1864 2824 16 +1878 2805 16 + +# fork +Fork 0x09F5 +1843 2830 14 +1948 2680 34 +1948 2682 34 +1948 2684 34 +1948 2686 34 + +# knife +Knife 0x09F7 +1843 2830 14 +1948 2680 34 +1948 2682 34 +1948 2684 34 +1948 2686 34 + +# spoon +Spoon 0x09F9 +1843 2830 14 +1948 2680 34 +1948 2682 34 +1948 2684 34 +1948 2686 34 + +# muffins +Static 0x09FA +1846 2761 20 +1852 2761 20 + +# wall sconce +WallSconce 0x0A00 (Unlit; Light=NorthBig) +1992 2724 45 + +# candle +Candle 0x0A0F +1897 2691 16 +2026 2716 25 +2030 2721 25 + +# hanging lantern +HangingLantern 0x0A1A +1841 2737 0 + +# bowl of flour +Static 0x0A1E +1880 2805 16 + +# candelabra +CandelabraStand 0x0A29 (Unlit) +1942 2760 10 + +# chest of drawers +Drawer 0x0A2C +1934 2683 20 +1935 2683 20 +1987 2858 20 +2025 2736 50 +2025 2799 10 +2026 2793 10 +2031 2784 30 +2034 2795 10 +2034 2801 10 +2036 2736 50 + +# chest of drawers +FancyDrawer 0x0A30 +1841 2710 10 +1893 2680 30 +1979 2829 15 + +# chest of drawers +Drawer 0x0A34 +1834 2729 0 +1834 2738 0 +1839 2729 0 +1844 2729 0 +1849 2730 0 +1851 2738 0 +1923 2803 0 +1932 2707 30 +1932 2708 30 +1954 2691 20 +1954 2692 20 +1985 2884 5 +2024 2785 10 +2024 2785 30 +2024 2796 30 +2033 2785 10 +2034 2798 30 + +# chest of drawers +FancyDrawer 0x0A38 +1847 2821 10 +1897 2804 20 +1942 2759 10 + +# dresser +Static 0x0A44 +1888 2685 30 + +# dresser +Static 0x0A45 +1888 2684 30 + +# armoire +FancyArmoire 0x0A4D +1839 2710 10 +1891 2680 30 +1899 2802 20 +1981 2829 15 +2027 2803 30 + +# armoire +Armoire 0x0A4F +1850 2728 0 +1932 2800 0 +1989 2858 20 +2037 2784 30 + +# armoire +FancyArmoire 0x0A51 +1847 2823 10 +1942 2762 10 + +# armoire +Armoire 0x0A53 +1985 2881 5 +2024 2789 30 +2024 2790 10 +2024 2799 30 +2033 2789 10 +2034 2802 30 + +# folded blanket +Static 0x0A6C +2034 2784 32 + +# bookcase +LibraryBookcase 0x0A97 +1812 2800 0 +1815 2800 0 +1827 2669 0 +1839 2673 0 +1841 2701 10 +1846 2673 0 +1851 2824 30 +1852 2767 0 +1854 2819 10 +1854 2824 30 +1856 2819 10 +1868 2640 0 +1869 2640 20 +1872 2640 0 +1872 2640 20 +1878 2726 20 +1881 2701 20 +1881 2726 20 +1886 2733 20 +1891 2688 30 +1894 2802 0 +1895 2688 30 +1898 2802 0 +1901 2701 20 +1904 2701 20 +1909 2701 20 +1982 2904 20 +1987 2904 0 +1993 2715 30 +2000 2720 30 +2004 2715 30 +2018 2744 30 +2021 2744 30 +2036 2805 30 + +# bookcase +LibraryBookcase 0x0A98 +1813 2800 0 +1840 2673 0 +1842 2701 10 +1844 2701 10 +1848 2819 10 +1850 2824 30 +1851 2767 0 +1852 2824 30 +1869 2640 0 +1870 2640 20 +1873 2640 0 +1880 2726 20 +1885 2733 20 +1892 2688 30 +1893 2688 30 +1894 2688 30 +1895 2802 0 +1899 2802 0 +1902 2701 20 +1905 2701 20 +1906 2701 20 +1988 2904 0 +1994 2715 30 +2005 2720 30 +2019 2744 30 +2035 2805 30 + +# bookcase +LibraryBookcase 0x0A99 +1838 2676 0 +1844 2712 10 +1850 2676 0 +1876 2727 20 +1876 2735 20 +1884 2656 10 +1889 2690 30 +1897 2808 20 +1900 2702 20 +1900 2705 20 +1932 2702 30 +1981 2905 20 +1992 2721 30 +1996 2721 30 +1996 2723 30 +2020 2838 20 + +# bookcase +LibraryBookcase 0x0A9A +1838 2675 0 +1838 2681 0 +1838 2685 0 +1844 2711 10 +1844 2716 10 +1850 2675 0 +1850 2681 0 +1876 2728 20 +1876 2733 20 +1876 2736 20 +1884 2653 10 +1889 2689 30 +1889 2693 30 +1897 2812 20 +1900 2704 20 +1932 2701 30 +1981 2906 20 +1992 2717 30 +1996 2722 30 +2020 2837 20 + +# bookcase +LibraryBookcase 0x0A9B +1814 2800 0 +1845 2701 10 +1847 2673 0 +1849 2819 10 +1853 2767 0 +1853 2824 30 +1855 2824 30 +1870 2640 0 +1871 2640 0 +1871 2640 20 +1873 2640 20 +1879 2726 20 +1882 2701 20 +1887 2733 20 +1890 2688 30 +1896 2802 0 +1900 2802 0 +1903 2701 20 +1907 2701 20 +1908 2701 20 +1989 2904 0 +2003 2715 30 +2020 2744 30 +2034 2805 30 + +# bookcase +LibraryBookcase 0x0A9C +1838 2674 0 +1838 2680 0 +1844 2717 10 +1850 2674 0 +1850 2680 0 +1876 2729 20 +1876 2732 20 +1876 2737 20 +1884 2654 10 +1884 2655 10 +1889 2692 30 +1900 2703 20 +1932 2700 30 +1981 2907 20 +1996 2724 30 +2020 2836 20 + +# candle +CandleLarge 0x0B1A +1812 2827 6 +1813 2812 4 +1814 2807 24 +1814 2809 24 +1825 2672 4 +1837 2710 16 +1846 2742 6 +1846 2772 4 +1848 2772 24 +1849 2798 -2 +1857 2772 4 +1877 2805 16 +1895 2806 4 +1918 2807 6 +1934 2700 36 +1940 2689 26 +1947 2681 34 +1947 2685 34 +1964 2690 26 +1984 2839 21 +1985 2909 4 +1985 2913 4 +2002 2720 36 +2024 2840 24 +2029 2739 34 +2031 2739 34 +2034 2809 16 +2036 2783 30 +1930 2701 20 +2063 2777 6 + +# candelabra +Candelabra 0x0B1D +1879 2707 24 +1907 2730 24 +1907 2734 24 +2028 2849 4 + +# lamp post +LampPost1 0x0B20 +1807 2743 7 +1808 2716 0 +1816 2728 7 +1816 2743 4 +1819 2818 0 +1819 2839 0 +1820 2803 0 +1825 2685 0 +1826 2744 0 +1828 2810 0 +1828 2848 0 +1832 2696 0 +1832 2721 0 +1845 2688 0 +1846 2744 0 +1847 2848 10 +1849 2776 0 +1849 2837 10 +1852 2715 10 +1854 2776 0 +1856 2856 11 +1858 2800 -8 +1863 2687 0 +1863 2696 3 +1863 2706 10 +1863 2715 10 +1863 2729 10 +1863 2743 3 +1863 2752 3 +1863 2810 0 +1865 2656 0 +1871 2856 20 +1871 2863 20 +1872 2663 -10 +1872 2672 -8 +1872 2775 0 +1872 2783 5 +1872 2813 0 +1880 2714 20 +1880 2723 20 +1881 2776 5 +1881 2783 5 +1887 2842 20 +1890 2706 20 +1890 2814 0 +1891 2733 20 +1897 2706 20 +1897 2733 20 +1900 2663 0 +1903 2716 20 +1903 2722 20 +1904 2684 0 +1904 2691 0 +1906 2813 0 +1911 2672 0 +1911 2683 0 +1911 2692 1 +1911 2740 20 +1911 2775 0 +1911 2822 1 +1911 2847 20 +1912 2757 0 +1912 2864 20 +1913 2856 20 +1919 2663 0 +1920 2822 1 +1930 2776 0 +1935 2694 20 +1939 2822 0 +1939 2831 12 +1940 2842 14 +1942 2735 10 +1942 2741 10 +1942 2798 0 +1943 2691 20 +1943 2705 20 +1947 2830 10 +1947 2842 15 +1948 2822 0 +1948 2847 8 +1948 2856 6 +1951 2704 20 +1951 2719 2 +1951 2734 10 +1951 2743 10 +1951 2775 10 +1951 2784 10 +1951 2789 9 +1951 2798 10 +1951 2813 0 +1953 2695 20 +1960 2704 20 +1960 2761 10 +1960 2813 0 +1961 2775 10 +1961 2784 10 +1966 2814 0 +1966 2820 0 +1974 2775 10 +1974 2784 10 +1978 2814 0 +1978 2821 0 +1983 2846 15 +1986 2775 11 +1986 2784 13 +1992 2846 15 +1997 2872 10 +1998 2742 30 +1998 2909 0 +1998 2914 0 +1999 2752 30 +1999 2764 26 +1999 2775 19 +1999 2784 20 +1999 2822 1 +1999 2847 15 +1999 2856 15 +2000 2880 5 +2000 2891 5 +2008 2728 30 +2008 2743 30 +2008 2752 30 +2008 2764 25 +2008 2775 20 +2008 2822 0 +2008 2887 5 +2008 2896 5 +2015 2723 30 +2020 2822 0 +2020 2886 0 +2020 2896 0 +2023 2870 0 +2026 2813 0 +2037 2839 0 +2037 2849 0 +2039 2822 0 +2039 2869 0 +2040 2813 0 +2040 2896 0 +2046 2782 0 +2048 2800 0 +2048 2888 0 +2051 2782 0 +2058 2790 0 +2058 2800 0 +2059 2784 0 +2066 2784 0 + +# candelabra +CandelabraStand 0x0B26 +1800 2702 20 +1800 2713 20 +1801 2701 0 +1801 2713 0 +1804 2810 20 +1805 2802 0 +1809 2819 0 +1815 2700 20 +1815 2701 0 +1815 2713 0 +1815 2713 20 +1817 2819 0 +1818 2800 0 +1822 2681 0 +1829 2669 0 +1834 2736 0 +1838 2673 0 +1838 2686 0 +1840 2835 10 +1845 2835 10 +1847 2835 10 +1847 2835 30 +1848 2673 0 +1851 2680 0 +1854 2736 0 +1857 2835 10 +1857 2835 30 +1860 2654 0 +1875 2640 0 +1876 2726 20 +1880 2688 10 +1882 2834 30 +1882 2840 30 +1884 2658 10 +1888 2738 20 +1888 2812 10 +1888 2832 30 +1889 2688 30 +1895 2832 30 +1900 2701 20 +1900 2834 30 +1900 2840 30 +1904 2812 20 +1907 2658 10 +1908 2844 20 +1910 2712 20 +1925 2786 0 +1932 2733 10 +1932 2751 10 +1940 2786 0 +1942 2714 30 +1942 2733 10 +1942 2751 10 +1948 2763 10 +1954 2684 20 +1980 2829 15 +1983 2909 20 +1985 2865 20 +1991 2879 5 +1992 2715 30 +1995 2913 20 +1998 2879 5 +2013 2715 30 +2016 2744 30 +2016 2750 30 +2023 2743 50 +2024 2736 50 +2032 2744 70 +2032 2750 30 +2038 2750 30 +2040 2780 0 +2054 2776 0 +2054 2780 0 +1833 2678 0 +1888 2680 10 +1895 2802 20 +1943 2677 30 +1943 2686 30 +1951 2677 30 +1933 2769 10 +1937 2684 20 +1938 2769 10 +1940 2765 10 +1951 2688 30 +1985 2858 20 +2031 2811 30 + +# wooden bench +WoodenBench 0x0B2C +1885 2722 20 +1885 2723 20 +1885 2724 20 +1885 2725 20 +1885 2726 20 +1885 2727 20 +1941 2771 10 +1941 2772 10 +1978 2842 15 + +# wooden bench +WoodenBench 0x0B2D +1889 2708 20 +1890 2708 20 +1897 2708 20 +1898 2708 20 +1899 2708 20 +1900 2708 20 +1945 2769 10 +1946 2769 10 +1980 2842 15 +1983 2831 15 +2000 2715 30 +2001 2715 30 +2002 2715 30 +2005 2715 30 +2006 2715 30 +2007 2715 30 + +# water trough +WaterTroughSouthAddon 0x0B43 +1959 2672 20 +1962 2672 20 + +# water trough +Static 0x0B44 +1960 2672 20 +1963 2672 20 + +# chair +WoodenChairCushion 0x0B52 +1841 2830 10 + +# chair +WoodenChairCushion 0x0B54 +1848 2715 10 + +# chair +WoodenChairCushion 0x0B55 +1844 2830 10 + +# chair +WoodenChair 0x0B56 +1852 2676 0 +1852 2678 0 +1861 2647 0 +1861 2649 0 +1865 2646 20 +1865 2648 20 +1870 2643 0 +1870 2645 0 +1878 2729 20 +1878 2731 20 +1887 2655 10 +1891 2691 30 +1894 2805 0 +1983 2840 15 +1987 2867 20 +1992 2889 5 +2024 2745 50 +2024 2747 50 +2025 2807 10 +2025 2809 10 +2025 2848 0 +2025 2850 0 +2041 2773 0 +2041 2775 0 +2041 2777 0 + +# chair +WoodenChair 0x0B57 +1847 2713 10 +1849 2713 10 +1853 2674 0 +1855 2674 0 +1857 2674 0 +1859 2674 0 +1870 2642 20 +1872 2642 20 +1903 2703 20 +1905 2703 20 +1907 2703 20 +1935 2767 10 +2026 2737 30 +2026 2743 50 +2027 2846 0 +2028 2737 30 +2029 2846 0 +2030 2737 30 +2032 2737 30 +2034 2737 30 +2035 2745 70 +2064 2775 0 + +# chair +WoodenChair 0x0B58 +1832 2680 0 +1839 2678 0 +1839 2683 0 +1842 2678 0 +1842 2682 0 +1846 2681 0 +1847 2740 0 +1860 2677 0 +1864 2647 0 +1864 2649 0 +1868 2646 20 +1868 2648 20 +1872 2650 0 +1873 2643 0 +1873 2645 0 +1886 2736 20 +1896 2804 0 +1896 2806 0 +1908 2709 20 +1919 2809 0 +1965 2691 20 +2028 2745 50 +2028 2747 50 +2028 2807 10 +2028 2809 10 +2031 2848 0 +2031 2850 0 +2035 2739 30 +2035 2808 10 +2036 2808 30 +2044 2773 0 +2044 2775 0 +2044 2777 0 + +# chair +WoodenChair 0x0B59 +1842 2674 0 +1844 2674 0 +1853 2680 0 +1855 2680 0 +1857 2680 0 +1859 2680 0 +1879 2711 20 +1879 2737 20 +1881 2737 20 +1907 2737 20 +2001 2721 30 +2004 2721 30 +2023 2841 20 +2026 2741 30 +2026 2749 50 +2027 2852 0 +2028 2741 30 +2029 2852 0 +2030 2741 30 +2032 2741 30 +2034 2741 30 +2035 2747 70 + +# chair +BambooChair 0x0B5A +1805 2805 0 +1805 2807 0 +1805 2809 0 +1805 2811 0 +1812 2806 20 +1812 2808 20 +1812 2810 20 +1829 2671 0 +1829 2673 0 +1829 2675 0 +1840 2739 0 +1840 2741 0 +1845 2771 0 +1848 2796 -8 +1856 2770 0 +1856 2772 0 +1877 2705 20 +1877 2707 20 +1877 2709 20 +1881 2810 10 +1905 2729 20 +1905 2731 20 +1905 2733 20 +1905 2735 20 +1927 2796 0 +1933 2701 30 +1939 2690 20 +1945 2680 30 +1945 2682 30 +1945 2684 30 +1945 2686 30 +1983 2908 0 +1983 2910 0 +1983 2912 0 +1983 2914 0 +1985 2910 20 +2058 2775 0 +2058 2780 0 + +# chair +BambooChair 0x0B5B +1811 2811 0 +1811 2819 0 +1813 2801 0 +1813 2811 0 +1813 2819 0 +1814 2804 20 +1815 2801 0 +1815 2819 0 +1824 2670 0 +1878 2703 20 +1880 2703 20 +1946 2678 30 +1948 2678 30 +1985 2906 0 +2022 2839 20 +2024 2839 20 + +# chair +BambooChair 0x0B5C +1812 2813 0 +1813 2825 0 +1814 2812 20 +1815 2825 0 +1849 2773 20 +1985 2916 0 +1992 2916 0 +2023 2860 0 +2023 2863 0 +2023 2866 0 +2028 2860 0 +2028 2863 0 +2028 2866 0 +2063 2778 0 +2064 2778 0 + +# chair +BambooChair 0x0B5D +1808 2805 0 +1808 2807 0 +1808 2809 0 +1808 2811 0 +1816 2806 20 +1816 2808 20 +1816 2810 20 +1832 2671 0 +1832 2673 0 +1832 2675 0 +1847 2770 0 +1847 2772 0 +1858 2771 0 +1881 2705 20 +1881 2707 20 +1881 2709 20 +1898 2810 20 +1909 2729 20 +1909 2731 20 +1909 2733 20 +1909 2735 20 +1949 2680 30 +1949 2682 30 +1949 2684 30 +1949 2686 30 +1987 2908 0 +1987 2910 0 +1987 2912 0 +1987 2914 0 +1988 2910 20 + +# foot stool +FootStool 0x0B5E +1889 2685 30 + +# bench +Static 0x0B5F +1928 2790 0 +1930 2790 0 +1932 2790 0 +1934 2790 0 +1936 2790 0 +1936 2796 0 +1938 2790 0 +1938 2796 0 + +# bench +Static 0x0B60 +1928 2787 0 +1930 2787 0 +1932 2787 0 +1934 2787 0 +1936 2787 0 +1936 2793 0 +1938 2787 0 +1938 2793 0 + +# bench +Static 0x0B61 +1928 2788 0 +1928 2789 0 +1930 2788 0 +1930 2789 0 +1932 2788 0 +1932 2789 0 +1934 2788 0 +1934 2789 0 +1936 2788 0 +1936 2789 0 +1936 2794 0 +1936 2795 0 +1938 2788 0 +1938 2789 0 +1938 2794 0 +1938 2795 0 + +# bench +Static 0x0B65 +1933 2794 0 +1933 2796 0 + +# bench +Static 0x0B66 +1930 2794 0 +1930 2796 0 + +# bench +Static 0x0B67 +1931 2794 0 +1931 2796 0 +1932 2794 0 +1932 2796 0 + +# metal signpost +Static 0x0B9C +2002 2728 30 + +# metal signpost +Static 0x0BA2 +2016 2753 30 + +# brambles +Static 0x0D3F +2023 2766 20 + +# chessmen +Static 0x0E12 +1931 2795 2 +2043 2772 4 + +# chessmen +Static 0x0E13 +1814 2810 24 +1831 2671 4 +1985 2908 4 + +# chessmen +Static 0x0E14 +1814 2810 24 +1831 2671 4 +1985 2908 4 +2042 2773 4 + +# cards +Static 0x0E15 +1985 2915 4 + +# cards +Static 0x0E17 +1807 2810 4 +1814 2808 24 +1830 2676 4 +1862 2647 4 +1862 2649 4 +1929 2790 4 +1985 2914 4 +2026 2745 54 +2026 2747 54 +2042 2775 4 + +# cards +Static 0x0E18 +1806 2809 4 +1813 2808 24 +1830 2675 4 +1862 2647 4 +1862 2649 4 +1929 2789 4 +1984 2914 4 +2025 2745 54 +2025 2747 54 +2042 2775 4 + +# cards +Static 0x0E19 +1807 2809 4 +1815 2808 24 +1831 2675 4 +1863 2647 4 +1863 2649 4 +1929 2789 4 +1986 2914 4 +2027 2745 54 +2027 2747 54 +2043 2775 4 + +# backgammon board +Backgammon 0x0E1C +1807 2805 4 +1985 2911 4 +2043 2777 4 + +# crystal ball +Static 0x0E2F (Light=Circle150) +1847 2714 16 + +# brazier +Brazier 0x0E32 +1844 2710 10 +1837 2701 10 + +# crate +FillableLargeCrate 0x0E3C +1853 2786 -8 +1853 2786 -5 +1853 2786 -2 +1853 2786 1 +1853 2788 -8 +1853 2788 -5 +1854 2786 -8 +1854 2786 -5 +1854 2786 -2 +1854 2786 1 +1854 2788 -8 +1854 2788 -5 +2023 2840 0 +2023 2840 3 +2023 2841 0 +2023 2841 3 +2024 2840 0 +2024 2840 3 +2024 2841 0 +2024 2841 3 + +# crate +FillableLargeCrate 0x0E3D +1853 2787 -8 +1853 2787 -5 +1853 2787 -2 +1854 2787 -8 +1854 2787 -5 +1854 2787 -2 + +# crate +FillableSmallCrate 0x0E3E +1849 2790 -8 +1849 2790 -5 +1849 2790 -2 +1849 2791 -8 +1849 2791 -5 +1849 2791 -2 +1850 2790 -8 +1850 2790 -5 +1850 2790 -2 +1850 2791 -8 +1850 2791 -5 +1850 2791 -2 + +# metal chest +FillableMetalGoldenChest 0x0E40 +2024 2739 50 + +# wooden chest +WoodenChest 0x0E42 +1804 2814 20 +1811 2801 20 +1860 2645 20 +1860 2648 20 +1860 2651 20 +1932 2704 30 +1932 2705 30 +1954 2685 20 +1954 2686 20 + +# wooden chest +FillableWoodenChest 0x0E42 +1834 2731 0 +1834 2742 0 +1839 2731 0 +1844 2731 0 +1851 2742 0 +1923 2805 0 + +# wooden chest +WoodenChest 0x0E43 +1817 2800 20 +1938 2683 20 +1939 2683 20 +2060 2774 0 +2061 2774 0 + +# wooden chest +FillableWoodenChest 0x0E43 +1854 2728 0 + +# barrel +Barrel 0x0E77 +2020 2832 0 +2020 2832 5 +2020 2832 10 +2020 2833 0 +2020 2833 5 +2020 2834 0 +2020 2837 0 +2020 2837 5 +2020 2837 10 +2020 2838 0 +2020 2838 5 +2020 2839 0 +2020 2856 0 +2020 2856 5 +2020 2857 0 +2020 2857 5 +2021 2832 0 +2021 2832 5 +2021 2833 0 +2021 2837 0 +2021 2838 0 +2021 2838 5 +2021 2856 0 +2021 2856 5 +2022 2832 0 +2024 2832 0 +2024 2832 5 +2025 2832 0 +2025 2832 5 +2025 2833 0 +2027 2856 0 +2027 2856 5 +2028 2856 0 +2028 2856 5 +2029 2856 0 +2029 2856 5 +2029 2856 10 +2030 2856 0 +2030 2856 5 +2030 2856 10 + +# barrel +FillableBarrel 0x0E77 +1844 2786 -3 +1844 2786 2 +1844 2787 -3 +1844 2788 -8 +1845 2786 -3 +1845 2787 -8 +1846 2786 -8 +1925 2797 0 +1925 2797 5 +1925 2798 0 +1925 2798 5 +1925 2798 10 +1926 2798 0 +1926 2798 5 +2056 2848 -3 +2056 2848 2 +2056 2849 -3 +2056 2849 2 +2057 2848 -3 +2057 2848 2 +2057 2849 -3 +2058 2857 -3 +2058 2857 2 +2058 2858 -3 +2058 2858 2 +2059 2857 -3 +2059 2857 2 +2059 2858 2 +2073 2858 -3 +2074 2857 -3 + +# crate +FillableSmallCrate 0x0E7E +2025 2836 0 +2025 2837 0 +2025 2837 3 +2025 2838 0 +2025 2838 3 +2026 2836 0 +2026 2837 0 +2026 2837 3 +2026 2837 6 +2026 2838 0 +2026 2838 3 + +# strong box +MetalBox 0x0E80 +1809 2828 6 + +# strong box +FillableMetalBox 0x0E80 +1846 2714 16 +1934 2768 16 +1991 2887 11 + +# pickaxe +Static 0x0E86 +1848 2787 -5 + +# cleaver +Static 0x0EC3 +1986 2893 11 + +# dress form +Dressform 0x0EC6 +1985 2838 15 + +# dress form +Dressform 0x0EC7 +1991 2837 15 + +# bolt of cloth +Static 0x0F99 (Hue=0x38) +1979 2838 15 + +# bolt of cloth +Static 0x0F9A (Hue=0x38) +1979 2838 15 + +# bolt of cloth +Static 0x0F9B (Hue=0x38) +1977 2839 15 +1982 2838 15 + +# bolt of cloth +Static 0x0F9C (Hue=0x38) +1978 2839 15 +1981 2838 15 +1982 2838 15 +1983 2838 15 + +# sewing kit +Static 0x0F9D +1976 2838 21 + +# scissors +Scissors 0x0F9E +1977 2838 21 +1984 2841 21 + +# chess board +Chessboard 0x0FA6 +1814 2810 24 +1831 2671 4 +1931 2795 2 +1985 2908 4 +2043 2773 4 + +# checker board +Checkerboard 0xFA6 +1863 2648 4 + +# dice and cup +Dices 0x0FA7 +1806 2805 4 +1814 2805 24 +1933 2787 4 +1985 2912 4 +2042 2777 4 + +# chess pieces +Static 0x0FA8 +1931 2795 2 + +# dying tub +DyeTub 0x0FAB (Hue=0x3) +1861 2824 10 + +# backgammon game +Backgammon 0x0FAD +1814 2806 24 +1933 2788 4 + +# anvil +AnvilSouthAddon 0x0FB0 +1885 2644 0 + +# forge +SmallForgeAddon 0x0FB1 +1884 2645 0 + +# sledge hammer +Static 0x0FB4 +1886 2646 0 + +# tongs +Static 0x0FBC +1886 2644 0 + +# book +Static 0x0FBD +1812 2826 6 +1831 2680 4 +1846 2740 6 +1846 2771 4 +1849 2796 -2 +1857 2771 4 +1871 2650 4 +1879 2729 26 +1882 2810 16 +1885 2736 26 +1888 2655 16 +1892 2691 34 +1895 2805 4 +1897 2810 24 +1907 2709 26 +1918 2809 6 +1928 2796 6 +1934 2701 36 +1940 2690 26 +1964 2691 26 +1984 2840 21 +1988 2867 26 +1993 2889 11 +2030 2849 4 +2034 2739 34 +2034 2808 16 +2035 2808 34 + +# book +Static 0x0FBE +1812 2812 4 +1813 2802 4 +1815 2802 4 +1824 2671 4 +1842 2673 6 +1844 2673 6 +1848 2714 16 +1849 2772 24 +1881 2736 26 +1905 2704 26 +1907 2704 26 +1907 2736 24 +1935 2768 16 +1992 2915 4 +2001 2720 36 +2004 2720 36 +2023 2840 24 +2035 2746 74 + +# pen and ink +Static 0x0FBF +1812 2826 6 +1831 2680 4 +1846 2740 6 +1846 2771 4 +1849 2796 -2 +1857 2771 4 +1871 2650 4 +1882 2810 16 +1888 2655 16 +1892 2691 34 +1895 2805 4 +1897 2810 24 +1918 2809 6 +1928 2796 6 +1934 2701 36 +1940 2690 26 +1964 2691 26 +1984 2840 21 +1988 2867 26 +1993 2889 11 +2030 2849 4 +2034 2739 34 +2034 2808 16 +2035 2808 34 + +# pen and ink +Static 0x0FC0 +1812 2812 4 +1824 2671 4 +1848 2714 16 +1849 2772 24 +1935 2768 16 +1992 2915 4 +2001 2720 36 +2023 2840 24 +2035 2746 74 + +# shell +Static 0x0FCC +2028 2706 7 + +# book +ChildrenTalesVol2 0x0FEF +1872 2645 4 + +# book +DeceitDungeonOfHorror 0x0FEF +1986 2909 24 + +# book +RedBook 0x0FF1 +1871 2643 4 +1986 2910 24 + +# book +GuideToGuilds 0x0FF3 +1871 2645 4 + +# book +MyStory 0x0FF4 +1872 2643 4 + +# book +WildGirlOfTheForest 0x0FF4 +1987 2910 24 + +# pewter mug +PewterMug 0x0FFF +1806 2807 4 +1806 2811 4 +1813 2806 24 +1813 2809 24 +1830 2673 4 +1842 2829 14 +1866 2646 24 +1929 2788 4 +1933 2790 4 +1937 2788 4 +1937 2795 4 +1946 2681 34 +1946 2683 34 +1946 2685 34 +1946 2687 34 +1947 2679 34 + +# pewter mug +PewterMug 0x1000 +1814 2811 24 +1867 2646 24 +1947 2680 34 +1948 2681 34 + +# pewter mug +PewterMug 0x1001 +1807 2807 4 +1807 2811 4 +1815 2806 24 +1815 2809 24 +1831 2673 4 +1843 2831 14 +1867 2647 24 +1929 2788 4 +1933 2789 4 +1937 2788 4 +1937 2789 4 +1937 2793 4 +1937 2795 4 +1948 2681 34 +1948 2683 34 +1948 2685 34 + +# pewter mug +PewterMug 0x1002 +1866 2648 24 +1930 2795 4 + +# spittoon +Static 0x1003 +1937 2792 0 +1983 2915 0 + +# wash basin +Static 0x1008 +1842 2760 0 +1843 2761 20 +1847 2760 0 +1849 2761 20 +1853 2760 0 +1855 2772 20 +1858 2756 20 +1858 2760 0 +1859 2763 20 + +# archery butte +ArcheryButte 0x100B +1989 2694 0 +1992 2694 0 +1995 2694 0 +1998 2694 0 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +1980 2840 15 +1983 2833 15 + +# pile of wool +Static 0x101F (Hue=0x1A0) +1976 2839 15 +1979 2841 15 +1982 2834 15 + +# sack of flour +Static 0x1039 +1860 2834 10 +1865 2824 16 +1877 2811 10 + +# open sack of flour +Static 0x103A +1862 2831 10 +1882 2800 10 +1882 2805 16 +1883 2800 10 +1884 2800 10 +1885 2800 10 + +# rolling pin +Static 0x1043 +1880 2805 16 +1902 2840 26 + +# globe +Static 0x1048 +1892 2692 36 + +# clock +Clock 0x104B +1838 2682 6 +1838 2683 6 +1838 2684 6 + +# clock frame +ClockFrame 0x104D +1838 2679 6 +1841 2677 6 +1841 2682 6 +1845 2682 6 + +# clock parts +ClockParts 0x1050 +1838 2678 6 + +# axle with gears +AxleGears 0x1052 +1845 2681 6 + +# gears +Gears 0x1053 +1841 2678 6 + +# hinge +Hinge 0x1055 +1841 2681 6 + +# sextant +Static 0x1057 +1838 2677 6 + +# sextant parts +SextantParts 0x1059 +1845 2680 6 + +# axle +Axle 0x105C +1841 2679 6 + +# springs +Springs 0x105D +1841 2682 6 + +# upright loom +LoomEastAddon 0x1060 +1977 2842 15 + +# upright loom +LoomSouthAddon 0x1061 +1983 2830 15 + +# training dummy +TrainingDummySouthAddon 0x1070 +1939 2758 10 +1981 2694 0 +1981 2698 0 +1981 2702 0 +1985 2694 0 +1985 2698 0 +1985 2702 0 +2019 2743 50 +2019 2750 50 + +# training dummy +TrainingDummyEastAddon 0x1074 +1933 2724 10 +1933 2728 10 +1933 2732 10 +1933 2746 10 +1933 2750 10 +1935 2760 9 +1935 2763 10 +1936 2724 10 +1936 2728 10 +1936 2732 10 +1936 2746 10 +1936 2750 10 +1939 2724 10 +1939 2728 10 +1939 2746 10 +1939 2750 10 +2016 2748 50 + +# pile of hides +Static 0x1078 +1988 2872 20 + +# pile of hides +Static 0x1079 +1987 2872 20 + +# potted tree +PottedTree1 0x11C9 +1821 2669 0 +1833 2669 0 +1834 2733 0 +1842 2769 0 +1847 2819 10 +1850 2673 0 +1854 2733 0 +1857 2819 10 +1861 2673 0 +1876 2701 20 +1887 2701 20 +1892 2660 0 +1895 2680 30 +1896 2680 10 +1897 2802 0 +1897 2802 20 +1898 2660 0 +1900 2687 30 +1900 2694 30 +1903 2726 20 +1904 2802 20 +1906 2802 0 +1921 2811 0 +1923 2802 0 +1933 2800 0 +1934 2765 10 +1942 2758 10 +1981 2904 20 +1985 2879 5 +1985 2888 5 +1991 2836 15 +1996 2720 30 +2009 2720 30 +2023 2744 30 +2024 2736 30 +2024 2784 10 +2024 2784 30 +2024 2793 10 +2024 2793 30 +2024 2799 10 +2024 2810 30 +2030 2784 30 +2033 2784 10 +2033 2795 10 +2033 2801 10 +2034 2796 30 +2037 2736 30 +2037 2741 50 +2037 2810 30 + +# flowerpot +PottedPlant 0x11CA +1897 2680 30 +1900 2733 20 +1976 2829 15 + +# flowerpot +PottedPlant1 0x11CB +1888 2652 19 + +# flowerpot +PottedPlant2 0x11CC +1849 2794 1 + +# cot +Static 0x11FD +1843 2763 20 +1849 2763 20 + +# cot +Static 0x11FE +1844 2763 20 +1850 2763 20 + +# cot +Static 0x11FF +1843 2756 0 +1848 2756 0 +1854 2756 0 +1859 2756 0 +1859 2756 20 +1859 2761 20 +1859 2767 20 + +# cot +Static 0x1200 +1843 2757 0 +1848 2757 0 +1854 2757 0 +1859 2757 0 +1859 2757 20 +1859 2762 20 +1859 2768 20 + +# tarot +Static 0x12A5 +1849 2714 16 + +# statue +Static 0x139B +1898 2691 16 + +# moulding board +Static 0x14E9 +1879 2805 16 + +# rope +Static 0x14F8 +1844 2789 -8 +1844 2790 -8 +2062 2861 -3 +2063 2852 -3 +2069 2851 -3 +2069 2861 -3 +2072 2849 -3 +2073 2859 -3 +2083 2852 -3 +2083 2861 -3 +2087 2849 -3 +2087 2858 -3 + +# water barrel +Static 0x154D +1828 2730 0 +1828 2731 0 +1844 2786 -8 +1844 2787 -8 +1845 2786 -8 +1877 2808 10 +2021 2859 0 +2021 2862 0 +2021 2865 0 +2023 2832 0 +2024 2833 0 +2026 2859 0 +2026 2862 0 +2026 2865 0 +2059 2858 -3 +2063 2848 -3 +2063 2849 -3 +2063 2862 -3 +2063 2863 -3 +2073 2848 -3 +2086 2854 -3 +2086 2855 -3 +2087 2863 -3 + +# bowl of lettuce +Static 0x1600 +1951 2675 34 + +# large pewter bowl +Static 0x1603 +1859 2834 16 + +# beef carcass +Static 0x1871 +1988 2893 11 + +# sheep carcass +Static 0x1873 +1992 2893 11 + +# bulletin board +BulletinBoard 0x1E5E +1932 2786 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/vesper.cfg b/Data/Decoration/Britannia/vesper.cfg new file mode 100644 index 0000000..cff5c43 --- /dev/null +++ b/Data/Decoration/Britannia/vesper.cfg @@ -0,0 +1,1905 @@ +# pier +Static 0x03AE +3008 794 -5 +3010 794 -5 +3009 798 -5 +3008 798 -5 +3009 794 -5 +3007 795 -5 +3010 798 -5 +3007 797 -5 +3007 796 -5 + +# pier +Static 0x03AF +3019 794 -5 +3019 798 -5 +3020 797 -5 +3017 794 -5 +3018 798 -5 +3018 794 -5 +3020 796 -5 +3020 795 -5 +3017 798 -5 + +# oven +StoneOvenEastAddon 0x092C +2992 760 0 + +# slab of bacon +Static 0x0977 +2987 781 6 + +# ceramic mug +CeramicMug 0x0995 +2987 832 4 +2890 784 4 + +# mug +CeramicMug 0x0998 +2852 1000 -17 +2902 909 2 +2852 998 -17 +2852 997 -17 +2746 988 4 +2744 988 4 + +# mug +CeramicMug 0x0999 +2744 987 4 +2903 914 4 + +# bottle of ale +BeverageBottle 0x099F (Content=Ale) +2952 699 4 +2872 715 4 +2864 857 4 +2920 796 4 + +# bottles of ale +Static 0x09A2 +2855 988 -15 +2861 992 -15 + +# fork +Fork 0x09A3 +3006 812 6 +2894 659 6 + +# fork +Fork 0x09A4 +2745 987 4 +2747 987 4 + +# knife +Knife 0x09A5 +2894 659 6 +3006 812 6 + +# knife +Knife 0x09A6 +2747 987 4 +2745 987 4 + +# metal box +FillableMetalBox 0x09A8 +2992 640 6 +2997 760 6 +2990 776 6 +2864 848 6 +2995 832 6 +2898 916 6 +2839 880 6 +2863 808 6 +2842 864 6 +2888 654 6 +2877 720 6 +2842 792 6 + +# small crate +SmallCrate 0x09A9 +2873 674 0 +2877 688 0 +2872 672 0 +2876 676 0 +2875 675 0 + +# spoon +Spoon 0x09C3 +2745 987 4 +2747 987 4 + +# bottles of wine +Static 0x09C4 +2896 912 6 +2892 912 6 +2856 988 -15 +2861 991 -15 + +# bottles of wine +Static 0x09C5 +2899 905 4 + +# bottles of wine +Static 0x09C6 +2898 915 6 + +# bottle of wine +Static 0x09C7 +2903 909 2 +2994 632 4 +3006 811 6 +2894 912 6 +2952 627 4 +2894 658 6 +2904 904 6 + +# ceramic mug +CeramicMug 0x09CA +3006 811 6 +2894 658 6 + +# plate +Plate 0x09D7 +2995 632 4 +2952 700 4 +2747 987 4 +2864 858 4 +2894 659 6 +2747 988 4 +2896 708 4 +2920 797 4 +2745 988 4 +2988 832 4 +2745 987 4 +2872 716 4 +2891 784 4 +2952 628 4 +3006 812 6 + +# kettle +Static 0x09ED +2992 766 6 + +# mug of ale +GlassMug 0x09EE (Content=Ale) +2861 990 -15 +2858 988 -15 +2859 988 -15 +2861 996 -15 +2861 995 -15 +2861 994 -15 +2899 904 4 +2895 908 2 +2854 988 -15 +2853 988 -15 +2861 989 -15 +2898 913 6 + +# mug of ale +Static 0x09EF (Content=Ale) +2904 903 4 + +# fork +Fork 0x09F4 +2747 988 4 +2988 832 4 +2995 632 4 +2891 784 4 +2745 988 4 + +# fork +Fork 0x09F5 +2952 628 4 +2872 716 4 +2952 700 4 +2864 858 4 +2920 797 4 +2896 708 4 + +# knife +Knife 0x09F6 +2747 988 4 +2891 784 4 +2988 832 4 +2995 632 4 +2745 988 4 + +# knife +Knife 0x09F7 +2864 858 4 +2872 716 4 +2952 700 4 +2896 708 4 +2952 628 4 +2920 797 4 + +# spoon +Spoon 0x09F8 +2988 832 4 +2747 988 4 +2995 632 4 +2745 988 4 +2891 784 4 + +# spoon +Spoon 0x09F9 +2864 858 4 +2872 716 4 +2952 700 4 +2920 797 4 +2896 708 4 +2952 628 4 + +# hanging lantern +HangingLantern 0x0A1A +2768 970 6 + +# lantern +Lantern 0x0A22 +2742 979 26 + +# stool +Stool 0x0A2A +2899 706 0 +2858 989 -21 +2860 994 -21 +2860 995 -21 +2860 996 -21 +2860 993 -21 +2859 989 -21 +2860 990 -21 +2860 991 -21 +2857 989 -21 +2855 989 -21 +2860 989 -21 +2854 989 -21 +2853 989 -21 +2852 989 -21 + +# chest of drawers +Drawer 0x0A2C +2789 958 0 +2789 964 0 +2789 952 0 +2779 970 0 +2789 970 0 +2778 952 0 +2779 958 0 + +# chest of drawers +FancyDrawer 0x0A30 +2955 870 0 +2963 882 0 +2954 882 0 +2955 876 0 +2787 976 0 +2923 792 0 +2913 857 0 +2963 864 0 +2953 696 0 +2963 870 0 +2955 864 0 +2865 856 0 +2997 632 0 +2777 976 0 +2889 784 0 +2955 888 0 + +# chest of drawers +FancyDrawer 0x0A38 +2872 714 0 +2962 889 0 +2984 834 0 +2952 626 0 +2896 706 0 +2888 661 0 +3000 813 0 + +# armoire +FancyArmoire 0x0A4D +2954 624 0 +3005 808 0 +2874 712 0 +2986 832 0 +2957 696 0 +2779 976 0 +2993 632 0 +2915 857 0 +2898 704 0 +2893 656 0 +2869 856 0 +2921 792 0 + +# armoire +FancyArmoire 0x0A51 +2888 786 0 +2952 893 0 +2962 893 0 +2786 978 0 + +# bookcase +LibraryBookcase 0x0A97 +2918 664 20 +2737 976 0 +2886 648 0 +2993 832 0 +2861 728 0 +2966 816 0 +2847 904 0 +2965 808 0 +2882 744 0 +2937 928 0 +2865 808 0 +2940 936 0 +2915 664 0 +2915 664 20 +2961 816 0 + +# bookcase +LibraryBookcase 0x0A98 +2866 808 0 +2851 728 0 +2937 936 0 +2962 808 0 +2993 640 0 +2887 648 0 +2994 832 0 +2997 640 0 +2913 664 0 +2884 744 0 +2848 904 0 +2996 832 0 +2941 928 0 +2741 976 0 +2917 664 0 +2967 816 0 +2916 664 20 +2960 816 0 +2860 728 0 + +# bookcase +LibraryBookcase 0x0A99 +2992 817 0 +2992 833 0 +2880 745 0 +2992 812 0 +2768 966 0 +2872 722 0 +2840 947 0 +2840 952 0 +2872 725 0 +2944 941 0 +2920 667 20 +2736 981 0 +2944 936 0 +2960 810 0 +2912 676 20 +2918 857 0 +2840 898 0 + +# bookcase +LibraryBookcase 0x0A9A +2944 930 0 +2840 899 0 +2840 950 0 +2912 665 0 +2736 977 0 +2960 813 0 +2920 668 20 +2736 980 0 +2918 858 0 +2840 953 0 +2872 721 0 +2768 967 0 +2840 946 0 +2992 810 0 +2880 749 0 +2944 935 0 +2992 816 0 +2936 937 0 + +# bookcase +LibraryBookcase 0x0A9B +2938 936 0 +2888 648 0 +2917 664 20 +2997 832 0 +2914 664 0 +2968 816 0 +2962 816 0 +2849 904 0 +2852 728 0 +2889 648 0 +2941 936 0 +2916 664 0 + +# bookcase +LibraryBookcase 0x0A9C +2936 941 0 +2872 724 0 +2840 948 0 +2912 674 20 +2768 968 0 +2912 675 20 +2920 669 20 +2840 900 0 +2918 862 0 +2840 949 0 +2912 666 0 +2880 746 0 +2912 677 20 +2992 821 0 +2880 748 0 + +# candle +CandleLarge 0x0B1A +2971 875 4 +2900 789 6 +3006 813 6 +2888 739 4 +2939 940 4 +2990 780 6 +2923 859 6 +2989 832 4 +2952 701 4 +3015 779 6 +2918 852 6 +2907 706 6 +2997 763 6 +2992 644 6 +2996 632 4 +2952 629 4 +2996 813 6 +2939 932 4 +2894 660 6 +2995 838 6 +2920 798 4 +2896 709 4 +2863 812 6 +2955 811 4 +2788 963 20 +2882 674 6 +2864 849 6 +2842 868 6 +2860 988 -15 +2884 739 4 +2883 746 4 +2861 998 6 +2864 859 4 +2872 717 4 +2916 801 6 +2842 810 6 +2837 912 4 +2957 707 6 +2892 784 4 +2841 912 4 +2964 624 6 +2877 721 6 +2964 811 4 +2959 616 6 +2844 899 4 +2887 675 6 +2850 740 4 +2856 728 6 +2746 987 4 +2850 730 4 +2955 817 4 +2856 993 -15 +3020 763 6 +2842 793 6 + +# candelabra +Candelabra 0x0B1D +2790 973 6 +2790 955 6 +2790 979 6 +2776 978 6 +2778 956 6 +2790 961 6 +2778 962 6 +2736 988 6 +2778 974 6 +2788 968 6 + +# lamp post +LampPost2 0x0B22 +2976 623 0 +2943 624 0 +2943 617 0 +2982 640 0 + +# lamp post +LampPost3 0x0B24 +3003 782 0 +2950 918 0 +2904 858 0 +2848 867 0 +2903 692 0 +2946 705 0 +2969 776 0 +2902 712 0 +3006 840 0 +3007 817 0 +2886 780 0 +2848 799 0 +2862 919 1 +2950 898 0 +2848 927 0 +2848 883 0 +2827 906 0 +2847 817 0 +2823 706 0 +2774 982 0 +2766 974 0 +2752 976 0 +2752 991 0 +2861 795 0 +2847 850 0 +2919 711 2 +2982 737 20 +2984 765 0 +2977 804 0 +2980 878 0 +2921 839 0 +2933 851 0 +2919 902 0 +2959 740 20 +2823 700 0 +2791 984 0 +2825 958 -1 +2907 786 0 +2807 996 0 +2825 952 0 +2828 889 2 +2905 924 0 +2836 996 0 +2828 927 0 +2905 988 0 +2807 990 0 +2929 936 -1 +2929 963 0 +2914 686 2 +2974 838 0 +2836 990 0 +2801 952 0 +2801 958 0 +2902 663 1 +2911 956 0 +3010 762 0 +2953 857 0 +2964 718 3 +2863 876 0 +2872 983 -1 +2879 663 0 +2880 790 0 +2866 700 1 +2952 837 -1 +2880 850 0 +2721 984 0 +2952 943 0 +3031 773 0 +2880 712 0 +2862 856 0 +2886 755 0 +2856 904 0 +2868 727 0 +2913 813 0 +2721 990 0 +2886 912 0 + +# candelabra +CandelabraStand 0x0B26 +2892 918 0 +2886 680 0 +2832 872 0 +2960 864 0 +2886 686 0 +2960 894 0 +2784 952 0 +2784 982 0 +2914 910 0 +2914 904 0 +2872 686 0 +2892 901 0 +2832 879 0 +2736 982 0 +2872 680 0 +2742 976 0 + +# counter +Static 0x0B3E +2907 706 0 +2995 813 0 +2996 808 0 +2971 882 0 +2899 789 0 +2895 912 0 +2915 668 0 +2954 707 0 +2884 648 0 +2922 859 0 +3019 763 0 +3017 763 0 +2915 801 0 +2771 963 0 +2769 963 0 +2893 912 0 +2994 838 0 +2909 706 0 +2995 808 0 +3014 779 0 +2993 813 0 +2913 801 0 +2913 668 0 +2898 784 0 +2883 674 0 +2858 998 0 +2858 989 0 +2963 624 0 +2859 989 0 +2900 784 0 +2860 998 0 +2956 707 0 +2858 988 -21 +2897 912 0 +2855 728 0 +2958 616 0 +2855 993 -21 +2897 789 0 +2961 624 0 +2857 728 0 +2969 882 0 +3012 779 0 + +# writing table +WritingTable 0x0B49 +2908 709 0 +2908 715 0 +2908 712 0 + +# chair +FancyWoodenChairCushion 0x0B50 +2914 971 0 + +# chair +WoodenChairCushion 0x0B52 +2989 778 0 +2849 735 0 +2938 931 0 +2996 762 0 +3005 812 0 +2834 912 0 +2873 683 0 +2921 668 0 +2876 722 0 +2938 939 0 +2994 835 0 +2881 739 0 +2882 747 0 + +# chair +WoodenChairCushion 0x0B53 +2914 667 0 +2994 812 0 +2858 998 -21 +2739 978 0 +2843 898 0 +2908 705 0 +3018 762 0 +2963 810 0 +2955 809 0 + +# chair +WoodenChairCushion 0x0B54 +2922 861 0 +2970 883 0 +3013 780 0 +2962 625 0 +2859 999 0 +2919 676 20 + +# chair +WoodenChairCushion 0x0B55 +2865 850 0 +2918 804 0 +2918 805 0 +2993 642 0 +2889 652 0 +2843 866 0 +2843 812 0 +2843 794 0 +2864 810 0 + +# chair +WoodenChair 0x0B56 +2886 676 0 +2768 973 0 +2768 969 0 +2953 818 0 +2849 731 0 +2953 816 0 +2924 668 20 +2849 733 0 +2840 937 0 +2849 739 0 +2953 810 0 +2916 667 20 +2953 814 0 +2849 737 0 +2912 805 0 +2893 659 0 +2944 934 0 +2832 873 0 +2851 1000 -21 +2832 878 0 +2840 941 0 +2912 804 0 +2832 801 0 +2969 875 0 +2953 812 0 +2944 937 0 +2832 806 0 +2851 998 -21 +2851 996 -21 + +# chair +WoodenChair 0x0B57 +2842 910 0 +2923 673 20 +2889 737 0 +2971 873 0 +2919 673 20 +2917 673 20 +2776 964 0 +2841 904 0 +2780 964 0 +2887 737 0 +2885 737 0 +2921 673 20 +2893 672 0 +2838 910 0 +2914 800 0 +2770 962 0 +2898 788 0 +2883 737 0 +2955 706 0 +2845 904 0 +2889 672 0 +2836 910 0 +2915 673 20 +2840 910 0 + +# chair +WoodenChair 0x0B58 +2852 739 0 +2888 676 0 +2852 733 0 +2921 797 0 +2854 996 -21 +2973 875 0 +2923 667 0 +2923 669 0 +2852 735 0 +2852 737 0 +2909 712 0 +2909 709 0 +2884 748 0 +2897 708 0 +2865 858 0 +2909 715 0 +2940 940 0 +2873 716 0 +2940 932 0 +2957 810 0 +2940 938 0 +2940 930 0 +2957 812 0 +2913 795 0 +2957 818 0 +2854 998 -21 +2884 746 0 +2953 700 0 +2953 628 0 +2891 739 0 +2854 1000 -21 +2852 731 0 +2957 814 0 +2916 794 0 +2957 816 0 + +# chair +WoodenChair 0x0B59 +2962 812 0 +2971 877 0 +2955 819 0 +2964 812 0 +2844 900 0 +2842 914 0 +2857 729 0 +2855 729 0 +2836 914 0 +2838 914 0 +2842 900 0 +2840 914 0 +2887 741 0 +2883 741 0 +2891 785 0 +2885 741 0 +2899 785 0 +2858 1000 -21 +2883 675 0 +2889 741 0 +2917 676 20 +2921 676 20 +2988 833 0 +2914 669 0 +2915 676 20 +2923 676 20 +2995 633 0 + +# chair +BambooChair 0x0B5A +2912 798 0 +2912 799 0 + +# chair +BambooChair 0x0B5B +2745 986 0 +2747 986 0 + +# chair +BambooChair 0x0B5C +2745 989 0 +2739 980 0 +2747 989 0 + +# chair +BambooChair 0x0B5D +2737 987 0 + +# foot stool +FootStool 0x0B5E +2899 915 0 +2912 803 0 +2899 913 0 +2893 911 0 +2895 911 0 +2897 911 0 +2912 802 0 + +# bench +Static 0x0B5F +2904 916 0 +2900 905 0 +2895 905 0 +2898 905 0 +2902 916 0 +2893 905 0 +2905 905 0 +2903 905 0 + +# bench +Static 0x0B60 +2900 902 0 +2905 902 0 +2904 913 0 +2893 902 0 +2902 913 0 +2895 902 0 +2898 902 0 +2903 902 0 + +# bench +Static 0x0B61 +2893 903 0 +2900 904 0 +2900 903 0 +2904 914 0 +2902 914 0 +2904 915 0 +2893 904 0 +2903 903 0 +2905 904 0 +2905 903 0 +2898 903 0 +2902 915 0 +2903 904 0 +2895 904 0 +2898 904 0 +2895 903 0 + +# bench +Static 0x0B65 +2904 910 0 +2897 907 0 +2904 908 0 +2897 909 0 + +# bench +Static 0x0B66 +2901 908 0 +2901 910 0 +2894 907 0 +2894 909 0 + +# bench +Static 0x0B67 +2896 909 0 +2896 907 0 +2902 908 0 +2903 910 0 +2902 910 0 +2903 908 0 +2895 909 0 +2895 907 0 + +# table +Static 0x0B7F +2857 999 24 + +# broken chair +Static 0x0C10 +2915 793 6 + +# broken chair +Static 0x0C11 +2912 796 6 + +# tree +Static 0x0CCA +2888 642 1 + +# tree +Static 0x0CCB +2884 641 1 + +# leaves +Static 0x0CCE +2888 642 1 +2884 641 1 + +# tree +Static 0x0CD0 +2793 938 0 + +# leaves +Static 0x0CD1 +2793 938 0 + +# knitting +Static 0x0DF7 +2839 881 6 + +# pile of wool +Static 0x0DF8 (Hue=0x58) +2956 616 0 + +# pile of wool +Static 0x0DF8 +2843 881 0 + +# pile of wool +Static 0x0DF8 (Hue=0x25) +2965 627 0 + +# bale of cotton +Static 0x0DF9 +2840 880 0 + +# bale of cotton +Static 0x0DF9 (Hue=0x25) +2965 628 0 + +# chessmen +Static 0x0E13 +2894 903 4 + +# chessmen +Static 0x0E14 +2894 903 4 + +# cards +Static 0x0E15 +2971 876 4 + +# cards +Static 0x0E16 +2971 874 4 + +# cards +Static 0x0E17 +2970 874 4 + +# cards +Static 0x0E18 +2970 875 4 + +# cards +Static 0x0E19 +2972 875 4 + +# crystal ball +Static 0x0E2F (Light=Circle150) +2913 668 6 +2917 667 26 + +# crate +FillableLargeCrate 0x0E3C +2835 864 6 +2835 864 0 +2835 864 3 +2989 776 9 +2989 776 6 +2989 776 3 +2989 776 0 + +# crate +LargeCrate 0x0E3D +2876 673 0 +2874 672 0 +2876 672 0 +2874 676 0 +2872 676 0 +2874 674 0 + +# crate +FillableLargeCrate 0x0E3D +2918 806 0 +3016 766 6 +2833 864 0 +3016 766 3 +2984 640 3 +2984 639 0 +3016 766 0 +2918 806 3 +3016 764 3 +3016 764 0 +2918 806 9 +3016 765 3 +3016 765 0 +3016 764 6 +2985 640 3 +2985 640 0 +2985 639 0 +2917 806 0 +2833 864 6 +2834 864 3 +2834 864 0 +2984 639 3 +2984 640 9 +2984 640 6 +2984 640 0 +2918 806 6 +2833 864 3 +2917 806 6 +2917 806 3 + +# crate +MediumCrate 0x0E3E +2989 640 0 +2872 673 0 +2989 639 0 +2989 639 3 +2990 638 0 +2989 639 6 +2877 674 0 +2991 640 0 +2874 689 0 +2886 689 0 +2991 640 3 +2990 639 0 +2990 638 6 +2876 674 0 +2990 639 3 +2990 639 6 +2990 640 0 +2990 640 3 +2990 638 3 + +# crate +MediumCrate 0x0E3F +2876 692 0 +2877 672 0 +2873 688 0 +2876 675 0 + +# metal chest +FillableMetalGoldenChest 0x0E40 (ContentType=Guard) +2736 985 0 +2736 989 0 + +# metal chest +FillableMetalGoldenChest 0x0E40 +2952 892 0 +2786 971 0 +2776 955 0 +2962 868 0 +2962 874 0 +2776 973 0 +2786 954 0 +2952 874 0 +2952 865 0 +2952 877 0 +2786 960 0 +2952 883 0 +2786 965 0 +2776 961 0 +2962 886 0 + +# metal chest +MetalGoldenChest 0x0E41 +2885 692 0 +2884 691 0 + +# metal chest +FillableMetalGoldenChest 0x0E41 +2963 888 0 + +# wooden chest +WoodenChest 0x0E42 +2880 688 0 +2884 690 0 + +# wooden chest +WoodenChest 0x0E43 +2881 690 0 + +# barrel +Barrel 0x0E77 +2744 985 25 +2739 978 20 +2738 979 25 +2745 986 25 +2738 979 20 +2745 986 20 +2744 986 20 +2738 978 25 +2745 985 20 +2744 986 25 +2745 985 25 +2744 985 20 +2738 978 20 + +# barrel +FillableBarrel 0x0E77 +2958 704 0 +2953 704 5 +2892 917 0 +2892 914 0 +2958 705 5 +2958 705 0 +2958 704 5 +3011 832 2 +3016 760 0 +2952 704 5 +2953 704 0 +2952 704 0 +2892 913 5 +3044 836 -3 +3035 830 2 +2984 633 5 +3036 830 2 +3028 835 -3 +3043 836 2 +3016 776 0 +2959 704 5 +2892 913 0 +2959 704 0 +3028 835 2 +3012 833 -3 +3026 824 -3 +3012 832 2 +3036 830 -3 +3012 833 2 +3016 760 5 +3011 833 -3 +3011 833 2 +3011 776 0 +3016 761 0 +3012 820 2 +3010 776 5 +3041 816 2 +2983 632 0 +2893 913 0 +3011 819 -3 +3009 776 5 +3010 776 0 +3009 776 0 +3016 761 5 +3004 826 0 +3004 826 5 +3011 819 2 +3004 827 5 +3005 826 0 +3004 827 0 +2845 864 5 +2846 870 5 +3014 776 0 +2892 914 5 +2844 864 0 +3015 776 0 +3015 776 5 +3037 830 -3 +3044 836 2 +3016 779 0 +3043 816 -3 +2845 870 5 +3011 832 -3 +2845 865 0 +3029 835 2 +3037 830 2 +3025 825 2 +3025 825 -3 +3029 836 -3 +3029 836 2 +2846 870 0 +2983 632 10 +2983 633 5 +3012 819 2 +3044 837 2 +3011 820 2 +3044 837 -3 +3043 836 -3 +3005 826 5 +3026 825 -3 +3016 760 10 +2983 632 5 +3016 762 0 +3016 762 5 +3026 824 2 +3026 825 2 +3017 760 0 +2984 632 5 +2846 864 10 +3016 776 10 +2846 864 5 +3029 835 -3 +2984 632 10 +2844 869 0 +3012 832 -3 +3012 819 -3 +2846 870 10 +2846 869 5 +3043 837 -3 +3012 820 -3 +3041 816 -3 +3042 816 -3 +3016 776 5 +2845 868 0 +3043 837 2 +2984 632 0 +2845 869 0 +3035 830 -3 + +# metal chest +MetalChest 0x0E7C +2880 692 0 +2874 694 0 +2884 694 0 + +# crate +SmallCrate 0x0E7E +2884 688 0 +2875 676 0 + +# keg +Keg 0x0E7F +2736 989 20 +2736 990 20 +2748 976 20 +2750 976 20 +2736 988 20 +2749 976 20 + +# strong box +FillableMetalBox 0x0E80 +2921 859 6 +2768 963 6 +2896 789 6 +2992 813 6 +3016 763 6 +2953 707 6 +2910 706 6 +2960 624 6 +2968 882 6 +3011 779 6 +2860 998 6 +2912 668 6 +2912 801 6 + +# pickaxe +Static 0x0E85 +2985 642 3 + +# pickaxe +Static 0x0E86 +2857 740 5 + +# pitchfork +Static 0x0E87 +2984 644 4 + +# drum +Static 0x0E9C +2885 740 4 + +# tambourine +Static 0x0E9D +2889 740 4 + +# tambourine +Static 0x0E9E +2887 740 4 + +# standing harp +Static 0x0EB1 +2880 736 0 +2919 983 0 + +# lap harp +Static 0x0EB2 +2887 738 4 +2889 738 4 + +# lute +Static 0x0EB3 +2885 738 4 +2883 740 4 + +# music stand +Static 0x0EB6 +2896 736 0 +2895 736 0 +2894 736 0 + +# music stand +Static 0x0EBB +2898 736 0 +2899 736 0 +2900 736 0 + +# cleaver +Static 0x0EC2 +2987 780 6 + +# dress form +Static 0x0EC6 +2841 880 0 +2959 622 0 + +# dress form +Static 0x0EC7 +2960 617 0 + +# easel with canvas +Static 0x0F66 +2899 708 0 + +# easel with canvas +Static 0x0F68 +2905 715 0 +2905 712 0 +2905 709 0 + +# scissors +Scissors 0x0F9E +2839 883 6 + +# scissors +Scissors 0x0F9F +2952 620 6 + +# spool of thread +Static 0x0FA1 +2839 882 6 + +# playing cards +Static 0x0FA3 +2904 905 4 + +# checkers +Static 0x0FA4 +2895 908 2 + +# checkers +Static 0x0FA5 +2897 908 4 + +# game board +CheckerBoard 0x0FA6 +2896 908 2 + +# chess board +ChessBoard 0x0FA6 +2894 903 4 + +# dice and cup +Dices 0x0FA7 +2903 915 4 + +# backgammon game +Backgammon 0x0FAD +2903 916 4 + +# barrel +Static 0x0FAE +2995 760 0 +3010 838 -3 +3046 816 -3 +3012 792 0 +3015 820 -3 +3028 818 -3 +3019 797 0 +3016 781 0 +3016 780 0 +3008 795 0 +3040 825 -3 +3015 792 0 +3008 797 0 +3019 795 0 + +# anvil +AnvilSouthAddon 0x0FB0 +2869 849 0 +2845 812 0 +2845 796 0 +2869 853 0 + +# forge +SmallForgeAddon 0x0FB1 +2845 797 0 +2869 848 0 +2869 852 0 +2845 813 0 + +# sledge hammer +Static 0x0FB5 +2843 792 0 +2864 851 6 +2842 811 6 +2868 850 0 + +# tongs +Static 0x0FBB +2842 795 6 +2842 813 6 +2865 848 0 +2869 850 0 + +# book +Static 0x0FBD +2842 794 6 +2850 735 4 +2922 668 4 +2842 866 6 +2835 912 4 +2842 812 6 +2990 778 6 +2992 642 6 +2864 850 6 +2939 939 4 +2908 709 5 +2997 762 6 +2908 712 5 +2908 715 5 +2995 835 6 +2939 931 4 +2877 722 6 +2883 747 4 +2887 676 6 +2888 652 6 +2863 810 6 +2882 739 4 +2874 683 4 + +# book +Static 0x0FBE +2914 801 6 +2955 810 4 +2955 707 6 +2855 728 6 +2970 882 6 +2914 970 4 +2898 789 6 +2739 979 4 +2908 706 6 +3018 763 6 +2859 998 6 +2994 813 6 +2883 674 6 +2766 963 0 +2919 675 24 +2922 859 6 +2858 999 -17 +2962 624 6 +2963 811 4 +2770 963 6 +2857 728 6 +2843 899 4 +3013 779 6 + +# pen and ink +Static 0x0FBF +2842 866 6 +2908 712 5 +2922 668 4 +2835 912 4 +2995 835 6 +2842 812 6 +2864 850 6 +2908 709 5 +2997 762 6 +2769 963 6 +2887 676 6 +2939 931 4 +2992 642 6 +2882 739 4 +2990 778 6 +2842 794 6 +2883 747 4 +2908 715 5 +2888 652 6 +2874 683 4 +2939 939 4 +2863 810 6 +2877 722 6 +2850 735 4 + +# pen and ink +Static 0x0FC0 +3018 763 6 +2994 813 6 +2739 979 4 +2913 970 4 +2955 707 6 +3013 779 6 +2922 859 6 +2883 674 6 +2859 998 6 +2857 728 6 +2962 624 6 +2908 706 6 +2855 728 6 +2955 810 4 +2914 801 6 +2858 999 -17 +2919 675 24 +2963 811 4 +2898 789 6 +2843 899 4 + +# paints and brush +Static 0x0FC1 +2905 710 0 +2905 713 0 +2905 716 0 + +# book +TalkingToWisps 0x0FF4 +2736 987 6 + +# skull mug +Static 0x0FFC +2903 913 4 + +# skull mug +Static 0x0FFD +2903 915 4 + +# skull mug +Static 0x0FFE +2902 909 2 +2904 909 4 + +# pewter mug +PewterMug 0x1001 +2896 707 4 + +# pewter mug +PewterMug 0x1002 +2897 912 8 +2899 903 6 +2893 912 9 +2894 904 6 + +# spittoon +Static 0x1003 +2904 901 0 +2893 908 0 +2899 911 0 +2905 909 0 + +# wash basin +Static 0x1008 +2913 850 0 +2918 854 6 +2992 764 6 + +# spinning wheel +SpinningWheelEastAddon 0x1019 +2955 620 0 +2843 884 0 +2961 629 0 + +# chisels +Static 0x1027 +2912 793 6 + +# dovetail saw +Static 0x1029 +2912 795 6 + +# hammer +Static 0x102A +2899 789 6 + +# hammer +Static 0x102B +2915 794 6 + +# nails +Static 0x102E +2915 795 6 + +# jointing plane +Static 0x1030 +2915 801 6 + +# smoothing plane +Static 0x1032 +2913 801 6 + +# saw +Static 0x1034 +2912 794 6 + +# sack of flour +Static 0x1039 +2999 760 0 +2998 761 0 +2992 765 6 + +# open sack of flour +Static 0x103A +2998 760 0 +2993 765 0 + +# dough +Static 0x103D +2992 763 6 + +# rolling pin +Static 0x1043 +2992 762 6 + +# globe +Static 0x1047 +2964 810 0 + +# loom bench +Static 0x1049 +2845 884 0 +2963 629 0 +2957 620 0 + +# loom bench +Static 0x104A +2954 618 0 +2845 882 0 + +# clock frame +Static 0x104E +2898 784 6 + +# clock parts +Static 0x1050 +2900 784 6 + +# axle with gears +Static 0x1051 +2899 784 6 + +# gears +Static 0x1053 +2899 784 6 + +# hinge +Static 0x1056 +2901 784 6 + +# sextant +Static 0x1057 +2897 784 6 + +# sextant parts +Static 0x105A +2901 784 6 + +# axle +Static 0x105C +2899 784 6 + +# springs +Static 0x105E +2897 784 6 + +# upright loom +LoomSouthAddon 0x1061 +2844 881 0 +2953 617 0 + +# training dummy +TrainingDummy 0x1070 +2838 898 0 +2838 903 0 +2834 903 0 +2834 898 0 + +# pile of hides +Static 0x1079 +2868 1002 -21 +2867 1003 -21 +2869 1003 -21 +2868 1003 -21 +2868 1001 -21 +2869 1002 -21 + +# post +Static 0x1296 +2909 597 0 + +# sign +LocalizedSign 0x129A (LabelNumber=1016180) +2909 597 15 + +# tarot +Static 0x12A5 +2917 675 24 +2915 668 6 + +# statue +Static 0x139A +2952 622 0 +2960 620 0 + +# Pot of Wax +Static 0x142A +2957 705 6 + +# Pot of Wax +Static 0x142B +2957 704 6 + +# Candle +Static 0x1433 +2957 706 6 + +# moulding board +Static 0x14E9 +2992 762 6 + +# moulding board +Static 0x14EA +2997 764 6 + +# map +Static 0x14EB +2995 808 6 +2947 928 4 + +# rolled map +Static 0x14ED +2962 811 4 + +# ship model +Static 0x14F3 +2994 808 6 +2997 808 6 + +# spyglass +Static 0x14F6 +2742 980 26 + +# rope +Static 0x14F8 +3015 822 -3 +3015 836 -3 + +# rope +Static 0x14FA +3037 825 -3 +3030 819 -3 + +# water barrel +Static 0x154D +2983 633 0 +2845 864 0 +2846 864 0 +2984 633 0 +2846 865 5 +2845 870 0 +2846 865 0 +3011 820 -3 +2846 869 0 + +# water +Static 0x1797 +2958 731 -5 + +# water +Static 0x179B +2964 763 -5 + +# water +Static 0x179C +2964 764 -5 +2964 762 -5 + +# hourglass +Static 0x1813 +2925 669 26 +2885 648 6 + +# scales +Scales 0x1851 +2883 648 6 +2925 667 26 + +# skull with candle +CandleSkull 0x1854 +2922 667 40 +2922 674 40 +2922 665 40 +2922 676 40 +2916 674 24 +2913 674 40 +2913 676 40 + +# skull with candle +CandleSkull 0x1858 +2924 676 40 +2915 674 40 +2922 674 24 +2915 676 40 +2924 665 40 +2924 667 40 +2924 674 40 +2888 650 6 + +# empty vials +Static 0x185B +2884 648 6 + +# full vials +Static 0x185E +2888 653 6 + +# ore +Static 0x19B8 +2856 740 3 + +# ore +Static 0x19B9 +2851 732 4 + +# ore +Static 0x19BA +2851 738 4 + +# board +Static 0x1BD7 +2917 805 0 + +# bulletin board +BulletinBoard 0x1E5E +2909 904 0 +2778 964 0 + +# glass of cider +GlassMug 0x1F7D (Content=Cider) +2895 908 2 + +# glass of milk +GlassMug 0x1F89 (Content=Milk) +2898 913 6 \ No newline at end of file diff --git a/Data/Decoration/Britannia/wind.cfg b/Data/Decoration/Britannia/wind.cfg new file mode 100644 index 0000000..695d467 --- /dev/null +++ b/Data/Decoration/Britannia/wind.cfg @@ -0,0 +1,773 @@ + +# marble wall +Static 0x02B5 +5310 93 35 + +# marble wall +Static 0x02B7 +5310 118 35 + +# cave floor +Static 0x053C +5258 198 15 + +# cave floor +Static 0x053D +5259 198 15 + +# cave floor +Static 0x053E +5258 199 15 + +# cave floor +Static 0x0551 +5259 199 15 + +# marble roof +Static 0x063B +5154 107 25 + +# marble +Static 0x0709 +5220 144 0 +5221 144 0 +5224 137 20 +5224 140 20 +5225 137 20 +5225 140 20 +5226 137 20 +5226 140 20 +5227 137 20 +5227 140 20 +5228 137 20 +5228 140 20 +5244 169 15 +5245 169 15 +5281 123 20 +5282 123 20 +5301 127 15 +5302 127 15 +5321 85 25 +5321 90 25 +5322 85 25 +5322 90 25 +5323 85 25 +5323 90 25 +5324 85 25 +5324 90 25 +5325 85 25 +5325 90 25 +5326 85 25 +5326 90 25 +5327 85 25 +5327 90 25 +5328 85 25 +5328 90 25 +5329 85 25 +5329 90 25 +5330 85 25 +5330 90 25 +5331 85 25 +5331 90 25 +5332 85 25 +5332 90 25 + +# marble stairs +Static 0x070A +5179 50 17 +5180 50 17 +5220 145 0 +5221 145 0 +5255 230 11 +5255 231 7 +5301 128 15 +5302 128 15 + +# marble stairs +Static 0x070B +5286 144 15 +5310 134 15 +5310 135 15 + +# marble stairs +Static 0x070C +5281 122 20 +5282 122 20 + +# marble stairs +Static 0x070D +5224 175 24 +5224 176 24 +5237 164 15 +5237 165 15 +5253 180 15 +5253 181 15 +5280 144 15 + +# stalagmites +Static 0x08E0 +5216 203 5 +5251 236 5 + +# flowstone +Static 0x08E3 +5251 235 5 + +# stalagmites +Static 0x08E4 +5211 233 25 + +# stalagmites +Static 0x08E7 +5297 158 15 + +# slab of bacon +Static 0x0977 +5348 56 19 + +# raw fish steak +RawFishSteak 0x097A +5343 57 19 + +# wedge of cheese +CheeseWedge 0x097D +5354 53 19 + +# French bread +FrenchBread 0x098C +5351 49 19 + +# ceramic mug +CeramicMug 0x0995 +5223 175 11 + +# ceramic mug +CeramicMug 0x0996 +5160 33 23 +5222 174 11 + +# bottles of liquor +Static 0x099D +5160 34 23 + +# fork +Fork 0x09A4 +5223 174 11 + +# knife +Knife 0x09A6 +5223 174 11 + +# metal box +FillableMetalBox 0x09A8 +5167 18 27 +5179 18 27 +5211 167 5 +5307 31 40 +5307 35 40 +5310 35 40 +5313 31 40 +5316 35 40 + +# wooden box +FillableWoodenBox 0x09AA +5161 18 27 +5164 18 27 +5170 18 27 +5173 18 27 +5176 18 27 +5207 167 5 +5207 174 5 +5209 167 5 +5209 174 5 +5211 174 5 +5213 167 5 +5213 174 5 +5310 31 40 +5313 35 40 +5316 31 40 + +# metal chest +MetalChest 0x09AB +5186 89 5 + +# eggs +Eggs 0x09B5 +5355 53 19 + +# cooked bird +CookedBird 0x09B7 +5348 57 19 + +# roast pig +RoastPig 0x09BC +5348 59 19 + +# sausage +Sausage 0x09C1 +5348 52 19 + +# spoon +Spoon 0x09C3 +5223 174 11 + +# bottles of wine +Static 0x09C5 +5160 36 23 + +# apple +Apple 0x09D0 +5345 53 19 + +# ham +Ham 0x09D3 +5348 55 19 + +# plate +Plate 0x09D7 +5223 174 11 +5224 175 11 +5346 74 31 + +# plate of food +Static 0x09D8 +5342 81 31 +5342 84 31 +5343 78 31 +5346 78 31 + +# plate of food +Static 0x09D9 +5344 74 31 + +# cake +Cake 0x09E9 +5349 49 19 + +# muffins +Muffins 0x09EB +5346 49 19 + +# milk +Pitcher 0x09F0 (Content=Milk) +5180 19 31 + +# cut of ribs +Ribs 0x09F2 +5348 53 19 + +# fork +Fork 0x09F4 +5224 175 11 +5344 78 31 + +# fork +Fork 0x09F5 +5342 83 31 + +# knife +Knife 0x09F6 +5224 175 11 +5345 74 31 + +# knife +Knife 0x09F7 +5342 82 31 + +# spoon +Spoon 0x09F8 +5224 175 11 + +# candelabra +CandelabraStand 0x0A29 (Unlit) +5345 59 15 +5346 50 15 +5351 61 15 + +# chest of drawers +FancyDrawer 0x0A30 +5308 108 15 + +# bookcase +LibraryBookcase 0x0A9A +5258 136 20 + +# bookcase +LibraryBookcase 0x0A9C +5258 135 20 + +# candelabra +Candelabra 0x0B1D +5152 53 31 + +# candelabra +Static 0x0B26 +5305 108 15 +5341 73 25 +5345 85 25 +5350 75 25 + +# candelabra +CandelabraStand 0x0B27 +5150 92 5 +5154 64 25 +5163 92 5 +5210 112 0 +5217 121 0 +5225 172 5 +5236 135 15 +5238 174 15 +5238 181 15 +5241 187 15 +5246 174 15 +5246 181 15 +5146 55 25 +5151 103 5 +5157 91 5 +5177 97 5 +5187 91 5 +5197 94 5 +5198 85 5 +5207 176 5 +5208 169 5 +5213 160 5 +5234 142 15 +5234 152 15 +5241 144 15 +5241 152 15 +5265 161 15 + +# large vase +Static 0x0B45 +5177 95 5 + +# chair +FancyWoodenChairCushion 0x0B50 +5151 55 25 +5237 138 15 + +# chair +WoodenChairCushion 0x0B52 +5239 178 15 +5239 180 15 +5243 178 15 +5243 180 15 +5341 81 25 +5341 83 25 +5341 84 25 + +# chair +WoodenChairCushion 0x0B53 +5222 173 5 +5224 173 5 +5240 174 15 +5242 174 15 +5343 73 25 +5343 77 25 +5344 73 25 +5345 77 25 +5346 73 25 +5346 77 25 + +# chair +WoodenChairCushion 0x0B54 +5222 176 5 +5224 176 5 +5240 176 15 +5242 176 15 +5268 124 20 +5343 75 25 +5343 79 25 +5344 79 25 +5345 75 25 +5346 75 25 +5346 79 25 + +# chair +WoodenChairCushion 0x0B55 +5237 145 15 +5237 149 15 +5240 145 15 +5240 149 15 +5241 178 15 +5241 180 15 +5245 178 15 +5245 180 15 +5305 31 40 +5305 33 40 +5305 36 40 +5305 38 40 +5343 81 25 +5343 82 25 +5343 84 25 + +# metal signpost +Static 0x0B9B +5158 107 5 + +# metal signpost +Static 0x0BA0 +5200 98 5 + +# metal signpost +Static 0x0BA1 +5267 131 20 + +# metal signpost +Static 0x0BA2 +5217 124 0 +5236 155 15 + +# wand +Static 0x0DF2 +5145 82 29 + +# wand +Static 0x0DF3 +5145 74 29 +5264 163 18 +5311 114 18 + +# brazier +Brazier 0x0E31 +5145 79 29 +5145 62 25 +5145 70 25 +5177 86 5 +5177 88 5 +5179 86 5 +5300 88 15 + +# scroll +Static 0x0E35 +5176 90 9 + +# scroll +Static 0x0E38 +5176 92 9 + +# spellbook +Static 0x0E3B +5145 64 30 +5145 76 29 +5264 162 18 +5304 36 46 +5311 113 18 + +# metal chest +MetalGoldenChest 0x0E41 +5261 237 5 + +# barrel +FillableBarrel 0x0E77 +5149 91 5 + +# metal chest +MetalChest 0x0E7C +5261 159 15 + +# wooden box +FillableWoodenBox 0x0E7D +5162 23 27 +5162 26 27 +5179 24 27 +5179 27 27 + +# strong box +MetalBox 0x0E80 +5308 110 15 + +# strong box +FillableMetalBox 0x0E80 +5162 20 27 +5215 161 5 + +# clean bandage +Static 0x0EE9 +5259 129 20 +5259 133 20 +5260 125 20 +5264 124 20 +5267 123 26 +5269 123 26 + +# scroll +Static 0x0EF5 +5291 93 21 + +# scroll +Static 0x0EF7 +5149 53 30 +5292 89 21 +5292 95 21 + +# scroll +Static 0x0EF9 +5150 54 31 +5151 53 31 + +# spellbook +Static 0x0EFA +5145 83 29 +5176 91 9 +5291 95 21 +5304 32 46 + +# bottle +Static 0x0EFD +5307 88 15 + +# Orange Potion +Static 0x0F07 +5301 87 19 + +# Blue Potion +Static 0x0F08 +5145 65 27 +5301 87 19 + +# Green Potion +Static 0x0F0A +5303 87 19 + +# Red Potion +Static 0x0F0B +5144 74 29 +5144 83 29 +5304 37 46 + +# Yellow Potion +Static 0x0F0C +5144 65 28 +5304 87 19 + +# Purple Potion +Static 0x0F0D +5144 66 25 +5304 87 19 + +# empty bottle +Static 0x0F0E +5145 66 28 + +# Batwing +Static 0x0F78 +5302 88 19 + +# Blackmoor +Static 0x0F79 +5302 87 19 + +# Blood Moss +Static 0x0F7B +5183 85 9 +5264 164 18 +5311 115 18 + +# Daemon Blood +Static 0x0F7D +5149 54 30 +5293 90 24 +5304 33 46 + +# Brimstone +Static 0x0F7F +5144 66 28 + +# Dragon's Blood +Static 0x0F82 +5292 90 23 + +# Garlic +Static 0x0F84 +5292 94 24 + +# Nightshade +Static 0x0F88 +5144 65 29 +5145 75 29 +5181 85 9 +5268 123 24 +5294 89 21 + +# Sulfurous Ash +Static 0x0F8C +5144 84 29 + +# Spiders' Silk +Static 0x0F8D +2685 708 0 +5145 81 29 + +# Nox Crystal +Static 0x0F8E +5304 37 46 + +# Wyrm's Heart +Static 0x0F91 +5294 90 24 + +# pentagram +Static 0x0FEA +1361 883 0 +5191 152 0 +5200 71 17 +5217 18 15 + +# entrance teleporter +SkillTeleporter 0x1BC3 (Skill=Magery; RequiredFixedPoint=715; MessageNumber=503382; PointDest=(5166, 245, 15)) +1361 883 0 + +# book +DimensionalTravel 0x0FEF +5241 175 22 + +# book +TheFight 0x0FEF +5244 179 22 + +# book +RedBook 0x0FF1 +5239 145 19 + +# book +SongOfSamlethe 0x0FF3 +5238 144 15 + +# book +MajorTradeAssociation 0x0FF3 +5240 178 21 + +# book +TalkingToWisps 0x0FF4 +5239 148 19 + +# book +GuideToGuilds 0x0FF4 +5240 179 21 + +# book +DeceitDungeonOfHorror 0x0FF4 +5244 178 21 + +# glass pitcher +Pitcher 0x0FF6 +5160 35 23 + +# pitcher of water +Pitcher 0x0FF9 (Content=Water) +5180 20 31 + +# skull mug +Static 0x0FFC +5180 21 31 + +# bread loaf +Static 0x103C +5350 49 19 + +# baked pie +Static 0x1041 +5347 49 19 + +# unbaked pie +Static 0x1042 +5348 49 19 + +# uncooked pizza +Static 0x1083 +5352 49 19 + +# potted tree +PottedTree1 0x11C9 +5160 31 17 + +# flowerpot +PottedPlant 0x11CA +5176 22 31 +5304 29 40 +5304 40 40 + +# leg of lamb +LambLeg 0x160A +5348 54 19 + +# bananas +Static 0x1721 +5341 53 19 + +# coconut +Static 0x1723 +5342 53 19 + +# lemon +Lemon 0x1728 +5344 53 19 + +# pear +Pear 0x172D +5343 53 19 + +# scales +Scales 0x1852 +5144 75 29 + +# skull with candle +CandleSkull 0x1854 +5144 81 29 +5145 73 29 +5178 91 5 +5180 92 5 +5181 88 7 +5182 90 5 +5267 153 18 +5268 156 15 +5314 104 18 +5315 107 15 +5144 64 29 +5270 154 15 +5317 105 15 + +# skull with candle +CandleSkull 0x1858 +5179 89 6 +5266 155 15 +5269 152 15 +5313 106 15 +5316 103 15 + +# raw fish +Static 0x1E16 +5343 58 19 + +# fish heads +Static 0x1E1B +5343 59 19 + +# book +Static 0x1E20 +5236 145 19 + +# books +Static 0x1E21 +5236 137 19 + +# books +Static 0x1E22 +5237 137 19 + +# books +Static 0x1E23 +5239 149 19 + +# books +Static 0x1E25 +5236 149 19 + +# Strength +Static 0x1F3C +5304 38 44 + +# Arch Cure +Static 0x1F45 +5304 88 19 \ No newline at end of file diff --git a/Data/Decoration/Britannia/witch apprentice quest.cfg b/Data/Decoration/Britannia/witch apprentice quest.cfg new file mode 100644 index 0000000..5c4769e --- /dev/null +++ b/Data/Decoration/Britannia/witch apprentice quest.cfg @@ -0,0 +1,48 @@ +# Grizelda +Spawner 0x1F13 (Spawn=Grizelda; Count=1; HomeRange=0) +850 1544 0 + +# Captain Blackheart +Spawner 0x1F13 (Spawn=Blackheart; Count=1; HomeRange=0) +2679 2234 2 + +# barrel +Barrel 0x0E77 +844 1547 0 +860 1547 0 + +# lantern +Lantern 0x0A15 +851 1537 0 + +# grasses +Static 0x0CB5 +851 1549 0 + +# empty tub +Static 0x0E83 +855 1534 0 + +# sledge hammer +Static 0x0FB4 +856 1537 0 + +# metal chest +MetalChest 0x09AB +858 1538 0 + +# pitchfork +Pitchfork 0x0E87 +861 1546 0 + +# stew +Static 0x0970 +849 1544 8 + +# fire pit +Static 0x0FAC +849 1544 0 + +# cauldron +Static 0x0974 +849 1544 0 \ No newline at end of file diff --git a/Data/Decoration/Britannia/yew.cfg b/Data/Decoration/Britannia/yew.cfg new file mode 100644 index 0000000..3340895 --- /dev/null +++ b/Data/Decoration/Britannia/yew.cfg @@ -0,0 +1,79 @@ +# ankh +AnkhNorth 0x0004 +634 816 0 + +# book +MyStory 0x0FEF +337 875 0 + +# book +TaleOfThreeTribes 0x0FEF +472 840 0 + +# book +TamingDragons 0x0FEF +624 836 0 + +# book +RegardingLlamas 0x0FEF +624 842 0 + +# book +QuestOfVirtues 0x0FEF +627 841 0 + +# book +DeceitDungeonOfHorror 0x0FEF +641 852 0 + +# book +WildGirlOfTheForest 0x0FF0 +337 873 0 + +# book +VirtueBook 0x0FF0 +337 875 20 + +# book +LifeOfATravellingMinstrel 0x0FF0 +338 884 20 + +# book +RedBook 0x0FF1 +336 877 6 +337 883 20 +338 873 20 +476 840 0 +625 852 0 +628 836 0 +640 819 26 +641 849 0 +643 850 6 + +# book +BlueBook 0x0FF2 +337 873 20 +339 883 0 +625 832 0 +628 848 0 +630 819 26 + +# book +MajorTradeAssociation 0x0FF4 +336 877 26 + +# book +ChildrenTalesVol2 0x0FF4 +338 873 0 + +# book +TheFight 0x0FF4 +473 842 0 + +# book +EthicalHedonism 0x0FF4 +562 810 4 + +# book +GrammarOfOrcish 0x0FF4 +631 819 26 \ No newline at end of file diff --git a/Data/Decoration/Felucca/_champion teleporters.cfg b/Data/Decoration/Felucca/_champion teleporters.cfg new file mode 100644 index 0000000..5733af9 --- /dev/null +++ b/Data/Decoration/Felucca/_champion teleporters.cfg @@ -0,0 +1,100 @@ +############### +# Teleporters # +############### + +# teleporter +Teleporter 0x1BC3 (PointDest=(5814, 3548, 0)) +5443 2325 35 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5522, 3921, 37)) +5996 2367 45 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5958, 2345, 25)) +6053 2407 27 + +# teleporter +Teleporter 0x1BC3 (PointDest=(6089, 2400, 24)) +6080 2340 26 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5972, 2418, 26)) +5503 3971 40 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5490, 2348, 20)) +5731 3420 14 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5606, 802, 60)) +5265 683 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5876, 1378, 0)) +5265 669 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5164, 1009, 0)) +5506 814 60 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5201, 1564, 0)) +5506 817 60 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5201, 1564, 0)) +5145 973 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5331, 707, 0)) +5140 973 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5606, 802, 60)) +5682 1440 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5164, 1009, 0)) +5682 1437 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5977, 169, 0)) +5905 97 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5876, 1378, 0)) +5360 1540 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5331, 707, 0)) +5356 1540 0 + + +########### +# Effects # +########### + +# sparkle +Static 0x375A +5443 2325 34 +5996 2367 45 +6053 2407 27 +6080 2340 26 +5503 3971 40 +5731 3420 14 +5265 683 0 +5265 669 0 +5506 814 60 +5506 817 60 +5145 973 0 +5140 973 0 +5682 1440 0 +5682 1437 0 +5905 97 0 +5360 1540 0 +5356 1540 0 + +# sparkle +Static 0x374A +5682 1437 5 \ No newline at end of file diff --git a/Data/Decoration/Felucca/_star room.cfg b/Data/Decoration/Felucca/_star room.cfg new file mode 100644 index 0000000..8eb9d86 --- /dev/null +++ b/Data/Decoration/Felucca/_star room.cfg @@ -0,0 +1,31 @@ +# teleporter +Teleporter 0x1BC3 (PointDest=(5171, 1586, 0)) +5140 1773 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5143, 1774, 0); SoundID=0x1FE) +5172 1589 -4 + +# champion skull platform +ChampionSkullPlatform 0x1 +5140 1761 1 + +# dark moongate +LocalizedStatic 0x1FD3 (LabelNumber=1049498; Light=Circle300) +5172 1589 -4 + +# music stand +Static 0x0EBA +5155 1762 1 + +# music stand +Static 0x0EBB +5151 1758 0 + +# sheet music +Static 0x0EBF +5151 1758 0 + +# moongate +PublicMoongate 0x0F6C +5153 1760 0 \ No newline at end of file diff --git a/Data/Decoration/Felucca/ambitious solen queen quest.cfg b/Data/Decoration/Felucca/ambitious solen queen quest.cfg new file mode 100644 index 0000000..7c10880 --- /dev/null +++ b/Data/Decoration/Felucca/ambitious solen queen quest.cfg @@ -0,0 +1,3 @@ +# Black Ambitious Solen Queen +Spawner 0x1F13 (Spawn=BlackAmbitiousSolenQueen; Count=1; HomeRange=14) +5790 1983 2 \ No newline at end of file diff --git a/Data/Decoration/Felucca/khaldun entrance.cfg b/Data/Decoration/Felucca/khaldun entrance.cfg new file mode 100644 index 0000000..73bc774 --- /dev/null +++ b/Data/Decoration/Felucca/khaldun entrance.cfg @@ -0,0 +1,439 @@ +############### +# Teleporters # +############### + +# teleporter +Teleporter 0x1BC3 (PointDest=(6012, 3786, 25)) +5571 1299 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(6013, 3786, 25)) +5572 1299 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5570, 1300, 0)) +6011 3787 22 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5571, 1300, 0)) +6012 3787 20 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5572, 1300, 0)) +6013 3787 20 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5573, 1300, 0)) +6014 3787 21 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5402, 1289, 0)) +5878 3817 -2 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5402, 1290, 0)) +5878 3818 -2 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5881, 3818, 0)) +5403 1288 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5881, 3819, 0)) +5403 1289 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5881, 3820, 0)) +5403 1290 0 + + +############### +# Decorations # +############### + +# tent wall +Static 0x036F (Hue=0x455) +5998 3764 20 +5998 3766 20 + +# tent wall +Static 0x036F (Hue=0x973) +5998 3763 20 +5998 3765 20 + +# tent pole +Static 0x036B +5998 3762 20 + +# tent wall +Static 0x036E (Hue=0x455) +5999 3762 20 +6001 3762 20 + +# tent wall +Static 0x036E (Hue=0x973) +6000 3762 20 +6002 3762 20 + +# tent wall +Static 0x036D (Hue=0x973) +6003 3762 20 + +# tent wall +Static 0x036A (Hue=0x455) +6003 3763 20 +6003 3765 20 + +# tent wall +Static 0x036A (Hue=0x973) +6003 3764 20 +6003 3766 20 + +# tent wall +Static 0x0368 (Hue=0x455) +6003 3767 20 + +# tent wall +Static 0x0369 (Hue=0x455) +6002 3767 20 +5999 3767 20 + +# pickaxe +Static 0x0E86 +6004 3772 21 + +# bamboo stool +Static 0x11FC +6002 3773 20 +6000 3773 21 + +# fire pit +Static 0x0FAC +6001 3772 21 + +# crate +LargeCrate 0x0E3C +5999 3770 19 + +# crate +MediumCrate 0x0E3E +5999 3770 22 + +# lantern +Static 0x0A15 +5999 3770 25 + +# wooden fence +Static 0x0835 +5998 3773 21 + +# wooden fence +Static 0x0837 +5998 3772 21 +5996 3772 21 +5996 3773 21 + +# wooden fence +Static 0x0836 +5998 3771 21 +5997 3771 21 +5997 3773 21 + +# wooden logs +Static 0x0504 +5997 3772 21 + +# flowstone +Static 0x08E8 +5876 3821 0 +5878 3820 -4 +5878 3816 -9 + +# rock +Static 0x1776 +5879 3815 -4 +5878 3819 22 +6009 3782 17 +6009 3785 32 +6007 3787 30 +6008 3788 30 +6008 3789 29 + +# rock +Static 0x1775 +5880 3815 -4 +5877 3820 22 +5878 3817 17 +6010 3782 19 +6010 3783 21 + +# rock +Static 0x1777 +5877 3818 22 +5878 3818 21 + +# rock +Static 0x1778 +5878 3818 21 +6005 3782 22 +6019 3786 46 +6008 3788 48 +6008 3787 30 + +# tapestry +Static 0x0FE3 (Hue=0x1;Name=a dark cavern) +5878 3819 -4 +5878 3818 -5 + +# tapestry +Static 0x0FE4 (Hue=0x1;Name=a dark cavern) +5878 3817 -5 +5878 3818 -4 + +# stone post +Static 0x01D2 +6015 3790 41 +6016 3784 31 +6013 3790 45 +6010 3784 28 + +# stone wall +Static 0x01EB +6014 3774 20 +6010 3778 22 + +# stone arch +Static 0x01E4 +6015 3777 21 + +# stone stairs +Static 0x078B +6013 3782 19 +6013 3783 25 +6014 3782 17 +6014 3783 23 +6013 3782 18 +6012 3782 18 +6012 3783 23 +6011 3782 18 +6011 3783 25 + +# stone +Static 0x0788 +6013 3783 19 +6013 3784 25 +6012 3784 25 +6011 3784 25 +6014 3783 17 +6014 3784 25 +6014 3784 19 +6014 3785 19 +6013 3784 19 +6013 3785 18 +6012 3783 17 +6012 3784 19 +6012 3785 19 +6011 3783 19 +6011 3784 19 +6011 3785 19 + +# stone stairs +Static 0x0789 +6012 3785 25 +6014 3785 25 +6014 3786 20 +6013 3785 25 +6013 3786 20 +6012 3786 21 +6011 3785 25 +6011 3786 21 + +# stone pavers +Static 0x0521 (Hue=0x1) +6013 3787 20 +6011 3787 22 +6012 3787 20 +6012 3786 20 +6013 3786 19 + +# shovel +Static 0x0F39 +6004 3771 19 + +# crate +MediumCrate 0x0E3F +6002 3771 22 + +# bottles of ale +Static 0x09A1 +6002 3771 27 + +# hay +Static 0x0F34 +5999 3773 21 +5998 3774 20 +5997 3774 19 + +# large vase +Static 0x0B45 +5997 3772 22 + +# large vase +Static 0x0B47 +5997 3774 20 + +# cave floor +Static 0x0548 +5878 3817 -2 + +# cave floor +Static 0x0546 +5878 3819 -2 +5878 3818 -2 + +# torch%es% +Static 0x0F64 +6003 3771 21 + +# torch%es% +Static 0x0F6B +6003 3771 22 + +# stone wall +Static 0x01E9 +6008 3785 32 + +# stone arch +Static 0x01E0 +6019 3785 32 + +# stone wall +Static 0x01EA +6019 3787 47 + +# stone arch +Static 0x01E3 +6020 3787 45 + +# stone pavers +Static 0x0521 +6013 3778 21 +6011 3779 22 +6012 3779 19 +6013 3779 20 +6012 3780 18 +6013 3781 17 +6011 3781 20 + +# stone arch +Static 0x01E2 +6009 3778 19 + +# stone wall +Static 0x01D1 +6016 3785 31 +6016 3786 27 +6016 3787 25 +6015 3787 20 +6015 3788 22 +6010 3785 25 +6010 3786 23 +6010 3787 22 +6012 3790 44 + +# stone arch +Static 0x01DC +6017 3786 30 +6017 3789 33 +6016 3790 45 +6014 3790 47 + +# stone arch +Static 0x01DE +6015 3791 45 +6014 3792 59 + +# stone pillar +Static 0x01DA +6016 3792 46 +6012 3792 44 + +# tent roof +Static 0x0665 (Hue=0x973) +5999 3763 38 + +# tent roof +Static 0x0600 (Hue=0x455) +6000 3763 38 +6002 3763 38 + +# tent roof +Static 0x0600 (Hue=0x973) +6001 3763 38 +6001 3764 41 + +# tent roof +Static 0x0664 (Hue=0x973) +6003 3763 38 + +# tent roof +Static 0x05FF (Hue=0x455) +5999 3764 38 +5999 3766 38 + +# tent roof +Static 0x0665 (Hue=0x455) +6000 3764 41 + +# tent roof +Static 0x0664 (Hue=0x455) +6002 3764 41 + +# tent roof +Static 0x0602 (Hue=0x455) +6003 3764 38 +6003 3766 38 + +# tent roof +Static 0x05FF (Hue=0x973) +5999 3765 38 +6000 3765 41 + +# tent roof +Static 0x0608 (Hue=0x973) +6001 3765 49 + +# tent roof +Static 0x0602 (Hue=0x973) +6002 3765 41 +6003 3765 38 + +# tent roof +Static 0x0666 (Hue=0x455) +6000 3766 41 + +# tent roof +Static 0x0601 (Hue=0x973) +6001 3766 41 +6001 3767 38 + +# tent roof +Static 0x0663 (Hue=0x455) +6002 3766 41 + +# tent roof +Static 0x0666 (Hue=0x973) +5999 3767 38 + +# tent roof +Static 0x0601 (Hue=0x455) +6000 3767 38 +6002 3767 38 + +# tent roof +Static 0x0663 (Hue=0x973) +6003 3767 38 + +# tent wall +Static 0x036C (Hue=0x973) +5998 3767 20 diff --git a/Data/Decoration/Felucca/khaldun.cfg b/Data/Decoration/Felucca/khaldun.cfg new file mode 100644 index 0000000..bc8c962 --- /dev/null +++ b/Data/Decoration/Felucca/khaldun.cfg @@ -0,0 +1,739 @@ +############### +# Teleporters # +############### + +# teleporter +Teleporter 0x1BC3 (PointDest=(5572, 1307, 0)) +5543 1355 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5412, 1396, 0)) +5527 1340 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5396, 1297, 0)) +5557 1317 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5620, 1341, 0)) +5566 1337 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5435, 1341, 0)) +5451 1360 5 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5436, 1341, 0)) +5453 1360 5 + +# teleporter +KhaldunPitTeleporter 0x053B +5479 1348 0 +5479 1346 0 +5478 1348 0 +5478 1347 0 +5478 1346 0 +5477 1347 0 +5477 1348 0 +5479 1347 0 + + +############### +# Decorations # +############### + +# decorative weapons +Static 0x1568 +5422 1344 0 +5410 1360 0 +5410 1344 0 + +# tavara's journal +TavarasJournal3 0x0FF2 +5486 1295 0 + +# tavara's journal +TavarasJournal11 0x0FF2 +5437 1337 0 + +# tavara's journal +TavarasJournal7 0x0FF2 +5440 1290 0 + +# tavara's journal +TavarasJournal1 0x0FF1 +5540 1288 0 + +# tavara's journal +TavarasJournal2 0x0FF1 +5531 1303 8 + +# tavara's journal +TavarasJournal6 0x0FF1 +5440 1326 0 + +# tavara's journal +TavarasJournal8 0x0FF1 +5394 1312 0 + +# tavara's journal +TavarasJournal9 0x0FF1 +5433 1339 0 + +# crate +SmallCrate 0x0E7E +5432 1346 6 +5517 1296 4 + +# crate +MediumCrate 0x0E3E +5432 1346 3 +5544 1290 3 +5518 1296 1 + +# crate +LargeCrate 0x0E3C +5432 1346 0 +5432 1345 6 +5432 1345 3 +5432 1345 0 +5520 1289 0 + +# scimitar +Static 0x13B6 +5405 1352 5 +5405 1352 6 +5409 1352 5 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x973) +5432 1348 5 +5416 1487 0 +5416 1481 0 +5416 1484 0 +5392 1444 0 +5448 1443 0 + +# sledge hammer +Static 0x0FB4 +5384 1341 5 +5386 1336 5 +5386 1342 0 + +# magical door +LocalizedStatic 0x1EFC (LabelNumber=1016469) +5520 1299 10 +5520 1306 10 + +# viking sword +Static 0x13B9 +5407 1352 5 +5391 1340 6 + +# scimitar +Static 0x13B5 +5391 1338 5 +5456 1408 4 +5410 1352 5 +5410 1352 6 +5391 1339 5 + +# magical door +LocalizedStatic 0x1EEA (LabelNumber=1016469) +5528 1288 10 +5535 1288 10 +5548 1296 10 +5547 1296 10 + +# bucket +Static 0x14E0 +5539 1288 0 + +# fur%s% +Static 0x11F7 +5539 1289 0 + +# fur%s% +Static 0x11F8 +5540 1291 0 + +# bone armor +Static 0x144F (Hue=0x835) +5384 1338 5 +5517 1340 5 + +# bone gloves +Static 0x1450 (Hue=0x835) +5384 1336 5 +5515 1339 5 + +# bone leggings +Static 0x1452 (Hue=0x835) +5385 1336 5 + +# pickaxe +Static 0x0E86 +5544 1289 9 + +# bone armor +Static 0x1454 (Hue=0x835) +5391 1336 5 +5389 1336 5 + +# crate +LargeCrate 0x0E3D +5544 1289 0 +5544 1289 3 +5544 1290 0 + +# wall carving +LocalizedStatic 0x12CC (Hue=0x978; LabelNumber=1016041) +5431 1287 2 + +# wall carving +LocalizedStatic 0x12CC (Hue=0x978; LabelNumber=1016032) +5395 1311 2 + +# sparkle +Static 0x375A +5557 1316 0 +5543 1355 0 +5527 1340 0 +5566 1336 0 + +# brass sign +LocalizedSign 0x0BD2 (Hue=0x835; LabelNumber=1016174) +5448 1483 -6 + +# brass sign +LocalizedSign 0x0BD2 (Hue=0x835; LabelNumber=1016043) +5452 1481 -6 + +# brass sign +LocalizedSign 0x0BD2 (Hue=0x835; LabelNumber=1016056) +5456 1483 -6 + +# brass sign +LocalizedSign 0x0BD2 (Hue=0x835; LabelNumber=1016161) +5445 1487 -6 + +# brass sign +LocalizedSign 0x0BD2 (Hue=0x835; LabelNumber=1016039) +5459 1487 -6 + +# broadsword +Static 0x0F5F +5456 1406 4 + +# swamp +Static 0x326A (Hue=0x21; Name=Blood) +5606 1344 0 +5604 1344 0 +5604 1342 0 +5422 1491 0 +5423 1492 0 +5421 1491 0 +5423 1491 0 +5422 1489 0 +5420 1490 0 +5423 1489 0 +5424 1490 0 +5424 1491 0 +5606 1343 0 +5606 1342 0 +5605 1342 0 +5605 1344 0 +5423 1490 0 +5604 1343 0 +5605 1343 0 + +# blank scroll%s% +LocalizedStatic 0x0E34 (Hue=0x66D; LabelNumber=1016462) +5561 1352 5 + +# viking sword +Static 0x13BA +5456 1407 4 +5402 1352 6 +5402 1352 7 +5391 1340 5 +5402 1352 5 + +# blank scroll%s% +LocalizedStatic 0x0EF3 (Hue=0x978; LabelNumber=1016459) +5562 1352 6 + +# blank scroll%s% +LocalizedStatic 0x0EF3 (Hue=0x8AE; LabelNumber=1016460) +5562 1352 5 + +# kryss +Static 0x1400 +5564 1352 5 +5616 1331 6 + +# skull +Static 0x1AE2 +5369 1343 16 +5369 1343 6 +5369 1368 22 +5369 1368 11 +5369 1343 22 +5369 1368 16 +5369 1368 6 +5369 1343 11 + +# wall carving +LocalizedStatic 0x12D3 (Hue=0x978; LabelNumber=1016023) +5391 1296 2 + +# wall carving +LocalizedStatic 0x12D3 (Hue=0x978; LabelNumber=1016025) +5407 1308 2 + +# wall carving +LocalizedStatic 0x1265 (Hue=0x978; LabelNumber=1016023) +5391 1297 2 + +# bone gloves +Static 0x1455 (Hue=0x835) +5391 1338 6 + +# decorative weapons +Static 0x1563 +5416 1359 0 + +# glowing rune +Static 0x0E68 +5453 1360 5 +5451 1360 5 + +# decorative weapons +Static 0x156A +5416 1356 0 + +# mushroom +Static 0x0D18 +5480 1329 0 +5473 1329 0 + +# skull mug +Static 0x0FFB +5544 1290 7 + +# wall carving +LocalizedStatic 0x12CF (Hue=0x978; LabelNumber=1016026) +5441 1287 3 + +# wall carving +LocalizedStatic 0x12CF (Hue=0x978; LabelNumber=1016029) +5556 1313 2 + +# wall carving +LocalizedStatic 0x12D0 (Hue=0x978; LabelNumber=1016026) +5443 1287 3 +5442 1287 3 + +# wall carving +LocalizedStatic 0x12D0 (Hue=0x978; LabelNumber=1016029) +5557 1313 2 + +# wall carving +LocalizedStatic 0x12CE (Hue=0x978; LabelNumber=1016029) +5558 1313 2 + +# wall carving +LocalizedStatic 0x12CE (Hue=0x978; LabelNumber=1016041) +5433 1287 2 + +# wall carving +LocalizedStatic 0x12CE (Hue=0x978; LabelNumber=1016032) +5397 1311 2 + +# puzzlechest +MetalGoldenPuzzleChest 0x0E40 (Hue=0x839) +5392 1468 0 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x96F) +5400 1408 5 + +# skull with candle +CandleSkull 0x1854 +5400 1410 5 +5432 1343 5 +5432 1337 7 +5435 1339 5 +5432 1340 5 +5434 1336 20 +5400 1405 5 +5515 1338 5 +5525 1352 6 +5389 1343 5 +5547 1330 6 +5547 1334 6 +5396 1290 20 + +# metal chest +MetalGoldenChest 0x0E40 +5456 1367 0 +5456 1362 0 +5448 1362 0 +5448 1371 0 +5610 1339 0 + +# khaldun puzzle chest +MetalGoldenPuzzleChest 0x0E40 +5448 1367 0 +5610 1343 0 + +# skull with candle +CandleSkull 0x1858 +5439 1337 5 +5439 1343 5 +5439 1340 5 +5437 1336 5 +5516 1340 5 +5550 1334 6 +5550 1330 6 +5547 1332 6 +5389 1348 5 + +# spike trap +GiantSpikeTrap 0x0 +5442 1395 0 +5443 1395 0 +5444 1395 0 +5445 1395 0 + +# mushroom +Static 0x0D19 +5472 1335 0 + +# coffin +Static 0x1C53 +5491 1393 -4 + +# coffin +Static 0x1C52 +5491 1392 -4 + +# double axe +Static 0x0F4C +5456 1409 3 +5408 1352 5 + +# kryss +Static 0x1401 +5523 1352 5 +5623 1330 5 + +# stone pavers +Static 0x0519 +5491 1394 -7 +5491 1393 -7 +5491 1392 -7 + +# stone wall +Static 0x01D0 +5524 1367 -20 + +# cutlass +Static 0x1440 +5456 1411 5 +5616 1328 5 + +# metal chest +MetalGoldenChest 0x0E41 +5605 1348 2 +5542 1287 0 + +# flask +Static 0x1841 +5432 1338 5 + +# mortar and pestle +Static 0x0E9B +5432 1339 5 + +# scales +Static 0x1852 +5432 1342 5 + +# book +LocalizedStatic 0x0FF4 (LabelNumber=1016445) +5436 1340 5 + +# wall carving +LocalizedStatic 0x121E (LabelNumber=1016028) +5406 1295 2 + +# wall carving +LocalizedStatic 0x121E (LabelNumber=1016027) +5573 1299 34 + +# wall carving +LocalizedStatic 0x121F (LabelNumber=1016028) +5407 1295 2 + +# wall carving +LocalizedStatic 0x121F (LabelNumber=1016027) +5574 1299 34 + +# shovel +Static 0x0F3A +5537 1298 0 + +# pickaxe +Static 0x0E85 +5536 1299 4 + +# platemail gloves +Static 0x1414 +5391 1343 5 + +# bone arms +Static 0x1453 (Hue=0x835) +5384 1339 5 + +# swamp +Static 0x326D (Hue=0x21; Name=Blood) +5424 1489 0 +5420 1492 0 +5421 1492 0 +5421 1489 0 + +# swamp +Static 0x326E (Hue=0x21; Name=Blood) +5424 1488 0 +5422 1488 0 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x973) +5416 1343 5 +5444 1392 5 +5443 1392 5 +5442 1392 5 +5445 1392 20 +5443 1392 20 +5442 1392 20 +5445 1392 5 +5418 1343 5 +5444 1392 20 +5420 1440 0 + +# blank scroll%s% +Static 0x0EF3 +5436 1336 7 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x974) +5400 1407 5 + +# light +Static 0x1ED0 (Light=Circle300) +5536 1337 0 +5537 1336 0 +5537 1337 0 +5536 1336 0 + +# wall carving +LocalizedStatic 0x121D (LabelNumber=1016028) +5405 1295 2 + +# wall carving +LocalizedStatic 0x121D (LabelNumber=1016027) +5572 1299 34 + +# executioner's axe +Static 0x0F45 +5456 1409 3 + +# decorative weapons +Static 0x1566 +5416 1358 0 + +# large battle axe +Static 0x13FA (Hue=0x835) +5395 1448 5 + +# dagger +Static 0x0F52 +5623 1329 5 + +# bone legs +Static 0x1457 (Hue=0x835) +5517 1338 5 + +# bone arms +Static 0x144E (Hue=0x835) +5516 1339 5 + +# viking sword +Static 0x13BA (Hue=0x835) +5517 1339 5 + +# khaldun puzzle chest +StrongBoxPuzzle 0x0E80 (Hue=0x66D) +5537 1337 9 + +# candelabra +Candelabra 0x0B1D +5470 1331 0 + +# candle +Static 0x0A0F (Light=Circle150) +5451 1375 -3 + +# decorative weapons +Static 0x1562 +5416 1354 0 + +# wall carving +LocalizedStatic 0x12CD (Hue=0x978; LabelNumber=1016041) +5432 1287 2 + +# decorative weapons +Static 0x156B +5416 1355 0 + +# statue +Static 0x139D (Hue=0x96E) +5491 1395 6 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x962) +5400 1409 5 + +# Corpser Frame +LocalizedStatic 0x20D2 (Hue=0x482; LabelNumber=1016465) +5564 1354 6 + +# fur%s% +Static 0x11F6 +5543 1291 0 + +# bellows +LargeForgeEastAddon 0x1986 +5387 1339 0 + +# wall carving +LocalizedStatic 0x12D4 (Hue=0x978; LabelNumber=1016025) +5407 1307 2 + +# blank scroll%s% +LocalizedStatic 0x0E34 (LabelNumber=1016461) +5566 1352 5 + +# platemail gloves +Static 0x1418 +5391 1341 5 + +# swamp +Static 0x326B (Hue=0x21; Name=Blood) +5420 1489 0 + +# statue +Static 0x1226 +5552 1333 16 + +# lantern +Static 0x0A25 +5543 1287 5 + +# khaldun puzzle chest +MetalGoldenPuzzleChest 0x0E7C (Hue=0x89E) +5445 1503 0 +5457 1503 0 + +# wave +Static 0x1FBC (Hue=0x21; Name=Blood) +5422 1491 0 + +# wooden chest +WoodenChest 0x0E43 +5541 1287 4 +5541 1287 0 + +# swamp +Static 0x3241 (Hue=0x21; Name=Blood) +5423 1488 0 +5422 1492 0 + +# swamp +Static 0x3228 (Hue=0x21; Name=Blood) +5420 1491 0 + +# no draw +Static 0x21A4 (Hue=0x44) +5392 1290 0 + +# wave +Static 0x1FA3 (Hue=0x21; Name=Blood) +5422 1489 0 + +# decorative weapons +Static 0x1567 +5416 1357 0 + +# axe +Static 0x0F4A +5456 1410 3 + +# decorative weapons +Static 0x1569 +5411 1360 0 +5411 1344 0 +5423 1344 0 + +# decorative weapons +Static 0x1560 +5414 1360 0 + +# table +Static 0x0B34 +5517 1296 0 + +# Pot%s% of Wax +LocalizedStatic 0x142A (Hue=0x835; LabelNumber=1016518) +5389 1347 5 + +# coffin +Static 0x1C54 +5491 1394 -5 + +# swamp +Static 0x3236 (Hue=0x21; Name=Blood) +5422 1490 0 + +# wall carving +LocalizedStatic 0x1220 (LabelNumber=1016030) +5417 1295 3 + +# wall carving +LocalizedStatic 0x1221 (LabelNumber=1016030) +5418 1295 3 + +# wall carving +LocalizedStatic 0x1222 (LabelNumber=1016030) +5419 1295 3 + +# blank scroll%s% +LocalizedStatic 0x0EF3 (Hue=0x44E; LabelNumber=1016463) +5562 1352 7 + +# statue +Static 0x139B +5552 1331 16 + +# decorative weapons +Static 0x155E +5400 1350 0 + +# decorative weapons +Static 0x155F +5400 1347 0 + +# stone +Static 0x0788 (Hue=0x1) +5564 1354 -3 \ No newline at end of file diff --git a/Data/Decoration/Felucca/ocllo.cfg b/Data/Decoration/Felucca/ocllo.cfg new file mode 100644 index 0000000..b4f2561 --- /dev/null +++ b/Data/Decoration/Felucca/ocllo.cfg @@ -0,0 +1,1318 @@ +# stone wall +Static 0x001A +3692 2508 0 + +# stone wall +Static 0x001B +3692 2504 0 +3692 2505 0 +3692 2506 0 +3692 2507 0 + +# stone wall +Static 0x001C +3688 2508 0 + +# stone wall +Static 0x001E +3691 2508 0 + +# stone wall +Static 0x0021 +3689 2508 0 + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +3690 2508 0 + +# chimney +Static 0x08DC +3740 2680 64 + +# chimney +Static 0x08DD +3741 2680 64 + +# oven +StoneOvenEastAddon 0x092C +3656 2506 0 + +# oven +StoneOvenSouthAddon 0x0930 +3615 2568 0 +3653 2464 0 +3666 2639 0 +3738 2679 40 + +# fireplace +StoneFireplaceEastAddon 0x0959 +3656 2508 0 + +# fireplace +Static 0x095F +3650 2464 0 +3669 2640 0 +3741 2680 40 + +# fireplace +Static 0x0960 +3649 2464 0 +3668 2640 0 +3740 2680 40 + +# cauldron +Static 0x0974 +3735 2645 40 +3736 2572 40 + +# slab of bacon +Static 0x0976 +3704 2650 26 + +# tray +Static 0x0991 +3651 2469 6 +3736 2683 46 + +# tray +Static 0x0992 +3658 2504 6 +3664 2644 6 + +# ceramic mug +CeramicMug 0x0995 +3595 2600 4 +3627 2632 4 +3634 2496 4 +3650 2475 4 +3672 2652 6 +3676 2653 4 +3731 2632 46 +3738 2689 44 + +# ceramic mug +CeramicMug 0x0996 +3650 2474 4 +3662 2507 4 +3738 2688 44 + +# ceramic mug +CeramicMug 0x0997 +3704 2589 26 +3736 2565 46 + +# fork +Fork 0x09A4 +3651 2474 4 +3663 2507 4 +3739 2688 44 + +# knife +Knife 0x09A6 +3651 2474 4 +3663 2507 4 +3739 2688 44 + +# metal box +FillableMetalBox 0x09A8 +3632 2568 6 +3641 2596 6 +3664 2584 6 + +# metal chest +MetalChest 0x09AB +3688 2504 0 +3690 2504 0 +3690 2505 0 + +# sausage +Sausage 0x09C1 +3704 2652 26 + +# spoon +Spoon 0x09C3 +3651 2474 4 +3663 2507 4 +3739 2688 44 + +# bottles of wine +Static 0x09C4 +3664 2642 6 + +# bottles of wine +Static 0x09C5 +3669 2644 0 + +# bottle of wine +BeverageBottle 0x09C7 (Content=Wine) +3668 2651 6 +3672 2653 4 +3676 2648 4 + +# ceramic mug +CeramicMug 0x09CA +3608 2467 4 +3664 2508 4 +3665 2651 6 +3667 2651 6 +3676 2649 4 + +# pitcher +Static 0x09D6 +3608 2568 6 + +# plate +Plate 0x09D7 +3596 2600 4 +3608 2466 4 +3628 2632 4 +3635 2496 4 +3651 2474 4 +3651 2475 4 +3663 2507 4 +3663 2508 4 +3704 2588 26 +3732 2632 46 +3736 2564 46 +3739 2688 44 +3739 2689 44 + +# pot +Static 0x09E0 +3653 2469 6 + +# pot +Static 0x09E1 +3652 2469 6 +3737 2681 40 + +# frypan +Static 0x09E2 +3657 2504 6 +3664 2641 6 + +# pot +Static 0x09E3 +3659 2504 6 +3669 2642 0 +3738 2683 40 + +# kettle +Static 0x09ED +3610 2569 6 +3651 2465 0 +3657 2508 0 +3667 2641 0 +3739 2680 40 + +# milk +Pitcher 0x09F0 (Content=Milk) +3664 2643 6 + +# fork +Fork 0x09F4 +3596 2600 4 +3628 2632 4 +3635 2496 4 +3651 2475 4 +3663 2508 4 +3732 2632 46 +3739 2689 44 + +# fork +Fork 0x09F5 +3608 2466 4 +3704 2588 26 +3736 2564 46 + +# knife +Knife 0x09F6 +3596 2600 4 +3628 2632 4 +3635 2496 4 +3651 2475 4 +3663 2508 4 +3732 2632 46 +3739 2689 44 + +# knife +Knife 0x09F7 +3608 2466 4 +3704 2588 26 +3736 2564 46 + +# spoon +Spoon 0x09F8 +3596 2600 4 +3628 2632 4 +3635 2496 4 +3651 2475 4 +3663 2508 4 +3732 2632 46 +3739 2689 44 + +# spoon +Spoon 0x09F9 +3608 2466 4 +3704 2588 26 +3736 2564 46 + +# stool +Static 0x0A2B +3664 2652 0 +3665 2652 0 +3666 2652 0 +3667 2652 0 +3668 2652 0 + +# chest of drawers +Drawer 0x0A2C +3594 2600 0 +3610 2464 0 +3617 2576 0 +3626 2632 0 +3633 2561 0 +3633 2592 0 +3633 2601 0 +3666 2496 0 +3666 2608 0 +3666 2613 0 +3673 2584 0 +3674 2613 0 +3675 2608 0 +3675 2618 0 +3705 2584 20 +3738 2561 40 +3745 2680 40 + +# chest of drawers +FancyDrawer 0x0A30 +3633 2544 0 + +# chest of drawers +Drawer 0x0A34 +3632 2501 0 +3640 2466 0 +3728 2634 40 + +# chest of drawers +FancyDrawer 0x0A38 +3600 2505 0 +3608 2498 0 + +# armoire +FancyArmoire 0x0A4D +3602 2504 0 +3609 2496 0 + +# armoire +Armoire 0x0A4F +3592 2600 0 +3621 2576 0 +3624 2632 0 +3635 2561 0 +3635 2592 0 +3641 2464 0 + +# armoire +FancyArmoire 0x0A51 +3632 2549 0 + +# armoire +Armoire 0x0A53 +3632 2497 0 +3632 2606 0 +3664 2497 0 +3672 2589 0 +3744 2685 40 + +# bookcase +LibraryBookcase 0x0A97 +3609 2504 0 +3617 2472 0 +3619 2472 0 +3620 2472 0 +3622 2475 0 +3633 2632 0 +3640 2592 0 +3663 2504 0 + +# bookcase +LibraryBookcase 0x0A98 +3609 2469 0 +3616 2472 0 +3619 2475 0 +3621 2475 0 +3634 2632 0 +3638 2592 0 +3664 2504 0 +3669 2504 0 + +# bookcase +LibraryBookcase 0x0A99 +3608 2470 0 +3608 2472 0 +3608 2505 0 +3615 2477 0 +3632 2602 0 +3648 2470 0 +3648 2473 0 +3672 2585 0 +3736 2686 40 + +# bookcase +LibraryBookcase 0x0A9A +3608 2473 0 +3615 2476 0 +3648 2471 0 +3648 2476 0 +3736 2688 40 + +# bookcase +LibraryBookcase 0x0A9B +3618 2475 0 +3620 2475 0 +3622 2472 0 +3639 2592 0 +3665 2504 0 + +# bookcase +LibraryBookcase 0x0A9C +3615 2475 0 +3648 2472 0 +3648 2475 0 +3736 2689 40 +3736 2692 40 + +# wooden shelf +EmptyBookcase 0x0A9D +3613 2469 0 +3614 2469 0 + +# wooden shelf +EmptyBookcase 0x0A9E +3736 2685 40 +3736 2691 40 + +# candle +CandleLarge 0x0B1A +3597 2600 4 +3603 2504 4 +3604 2573 6 +3604 2605 6 +3608 2465 4 +3608 2499 4 +3611 2477 4 +3614 2471 4 +3624 2605 4 +3629 2632 4 +3631 2500 20 +3632 2571 6 +3636 2496 4 +3640 2467 4 +3641 2594 6 +3643 2501 6 +3652 2475 4 +3654 2464 6 +3656 2504 6 +3664 2507 4 +3664 2588 6 +3669 2496 4 +3669 2651 6 +3704 2587 26 +3704 2653 26 +3714 2648 26 +3733 2632 46 +3736 2563 46 +3740 2688 44 + +# lamp post +LampPost1 0x0B20 +3599 2592 0 +3611 2582 0 +3614 2480 0 +3614 2593 0 +3614 2605 0 +3614 2617 0 +3614 2624 0 +3615 2520 0 +3616 2504 0 +3625 2489 0 +3625 2510 0 +3625 2593 0 +3627 2582 0 +3632 2536 0 +3632 2615 0 +3645 2478 0 +3646 2521 0 +3646 2534 0 +3646 2545 0 +3646 2582 0 +3646 2607 0 +3646 2614 0 +3646 2625 0 +3651 2510 0 +3657 2478 0 +3657 2521 0 +3657 2545 0 +3657 2598 0 +3657 2622 0 +3657 2633 0 +3657 2654 0 +3658 2563 0 +3658 2568 0 +3669 2478 0 +3669 2545 0 +3672 2510 0 +3672 2633 0 +3678 2489 0 +3678 2521 0 +3689 2480 0 +3694 2521 0 +3711 2592 20 +3720 2655 20 +3735 2640 40 +3735 2696 40 +3743 2568 40 + +# candelabra +CandelabraStand 0x0B26 +3614 2510 0 +3638 2550 0 +3656 2528 0 +3670 2528 0 +3670 2608 0 +3672 2472 0 +3672 2542 0 +3672 2622 0 +3677 2542 0 +3682 2472 0 + +# chair +WoodenChairCushion 0x0B52 +3608 2509 0 +3625 2531 0 + +# chair +WoodenChairCushion 0x0B53 +3613 2504 0 + +# chair +WoodenChairCushion 0x0B54 +3604 2505 0 + +# chair +WoodenChairCushion 0x0B55 +3609 2500 0 + +# chair +WoodenChair 0x0B56 +3672 2473 0 +3672 2477 0 +3673 2532 0 +3683 2473 0 +3683 2475 0 +3683 2477 0 +3685 2473 0 +3685 2475 0 +3685 2477 0 +3687 2473 0 +3687 2475 0 +3687 2477 0 + +# chair +WoodenChair 0x0B57 +3602 2572 0 +3602 2604 0 +3613 2470 0 +3626 2544 0 +3627 2529 0 +3629 2529 0 +3631 2529 0 +3633 2529 0 +3634 2636 0 +3635 2529 0 +3642 2500 0 +3651 2473 0 +3663 2506 0 +3666 2619 0 +3674 2472 0 +3678 2472 0 + +# chair +WoodenChair 0x0B58 +3625 2606 0 +3641 2468 0 +3665 2586 0 +3667 2531 0 +3676 2532 0 + +# chair +WoodenChair 0x0B59 +3596 2601 0 +3626 2546 0 +3627 2533 0 +3629 2533 0 +3631 2533 0 +3633 2533 0 +3635 2497 0 +3635 2533 0 +3651 2476 0 +3663 2509 0 +3668 2497 0 + +# chair +BambooChair 0x0B5A +3609 2475 0 +3609 2476 0 +3640 2595 0 +3665 2530 0 +3665 2532 0 +3673 2534 0 +3673 2536 0 +3673 2538 0 +3673 2540 0 +3713 2649 20 + +# chair +BambooChair 0x0B5B +3739 2687 40 + +# chair +BambooChair 0x0B5C +3666 2621 0 +3732 2633 40 +3739 2690 40 + +# chair +BambooChair 0x0B5D +3609 2466 0 +3612 2475 0 +3612 2476 0 +3676 2534 0 +3676 2536 0 +3676 2538 0 +3676 2540 0 +3705 2588 20 +3737 2564 40 + +# wooden signpost +Static 0x0B98 +3666 2512 0 + +# brass sign +LocalizedSign 0x0BD2 (LabelNumber=1023026) +3666 2512 0 + +# small fish +Static 0x0DD6 +3648 2668 -3 +3661 2671 -3 +3669 2659 -3 + +# small fish +Static 0x0DD7 +3660 2661 -3 +3662 2670 -3 + +# small fish +Static 0x0DD8 +3662 2666 -3 +3666 2660 -3 + +# small fish +Static 0x0DD9 +3646 2669 -3 +3663 2672 -3 +3667 2664 -3 + +# knitting +Static 0x0DF7 +3669 2590 6 + +# pile of wool +Static 0x0DF8 +3669 2581 0 + +# bale of cotton +Static 0x0DF9 +3664 2581 0 + +# chessmen +Static 0x0E13 +3672 2648 4 + +# chessmen +Static 0x0E14 +3672 2648 4 + +# bloody water +Static 0x0E23 +3625 2603 0 +3628 2601 0 +3629 2609 0 + +# crystal ball +Static 0x0E2F (Light=Circle150) +3626 2545 6 + +# brazier +Brazier 0x0E31 +3624 2536 0 + +# crate +FillableLargeCrate 0x0E3D +3637 2577 0 +3637 2577 3 +3637 2578 0 +3637 2578 3 +3638 2576 0 +3638 2576 3 +3638 2577 0 +3638 2577 3 +3638 2577 6 +3638 2578 0 +3638 2578 3 +3638 2578 6 +3638 2579 0 +3638 2579 3 + +# crate +MediumCrate 0x0E3E +3633 2568 0 +3633 2568 3 + +# metal chest +MetalGoldenChest 0x0E41 +3688 2505 0 + +# wooden chest +WoodenChest 0x0E42 +3744 2681 40 + +# wooden chest +FillableWoodenChest 0x0E42 +3674 2611 0 +3674 2622 0 + +# wooden chest +WoodenChest 0x0E43 +3690 2506 0 + +# wooden chest +FillableWoodenChest 0x0E43 +3665 2608 0 +3665 2613 0 +3678 2613 0 +3709 2584 20 +3730 2632 40 +3737 2561 40 + +# barrel +FillableBarrel 0x0E77 +3616 2652 -3 +3616 2653 -3 +3616 2653 2 +3616 2654 -3 +3616 2654 2 +3629 2574 0 +3629 2574 5 +3630 2574 0 +3630 2574 5 +3631 2574 0 +3631 2574 5 +3632 2574 0 +3632 2574 5 +3632 2575 0 +3632 2575 5 +3644 2649 -3 +3644 2649 2 +3645 2649 -3 +3645 2649 2 +3645 2650 -3 +3645 2650 2 +3646 2662 -3 +3646 2662 2 +3646 2663 -3 +3646 2663 2 +3647 2662 -3 +3647 2662 2 +3647 2679 -3 +3647 2679 2 +3647 2680 -3 +3647 2680 2 +3648 2680 -3 +3648 2680 2 +3651 2654 0 +3651 2654 5 +3651 2655 0 +3651 2655 5 +3652 2654 0 +3652 2654 5 +3652 2655 0 +3652 2655 5 +3658 2665 -3 +3658 2665 2 +3659 2665 -3 +3659 2665 2 +3659 2666 -3 +3659 2666 2 +3661 2673 -3 +3661 2673 2 +3664 2648 0 +3664 2648 5 +3664 2648 10 +3664 2649 0 +3664 2649 5 +3665 2648 0 +3665 2648 5 +3668 2662 -3 +3668 2662 2 +3668 2663 -3 +3668 2663 2 +3669 2662 -3 +3669 2662 2 +3669 2663 -3 +3669 2663 2 + +# strong box +FillableMetalBox 0x0E80 +3600 2573 6 +3600 2605 6 +3624 2545 6 +3640 2501 6 + +# drum +Static 0x0E9C +3674 2534 4 +3675 2540 4 +3691 2475 0 + +# tambourine +Static 0x0E9D +3674 2540 4 +3675 2536 4 + +# tambourine +Static 0x0E9E +3674 2536 4 +3675 2538 4 +3691 2477 0 + +# standing harp +Static 0x0EB1 +3663 2528 0 +3664 2528 0 +3665 2528 0 +3673 2528 0 +3676 2528 0 +3693 2472 2 +3693 2476 2 + +# lute +Static 0x0EB3 +3674 2538 4 +3675 2534 4 + +# lute +Static 0x0EB4 +3688 2474 0 + +# music stand +Static 0x0EB6 +3659 2528 0 +3660 2528 0 +3661 2528 0 +3662 2528 0 + +# music stand +Static 0x0EBB +3666 2528 0 +3667 2528 0 +3668 2528 0 +3669 2528 0 +3674 2528 0 +3675 2528 0 + +# music stand +Static 0x0EBC +3690 2473 1 +3690 2475 1 +3690 2477 1 +3692 2473 1 +3692 2477 1 + +# sheet music +Static 0x0EBF +3674 2528 0 +3675 2528 0 + +# sheet music +Static 0x0EC0 +3690 2473 1 +3690 2475 1 +3690 2477 1 +3692 2473 1 +3692 2477 1 + +# cleaver +Static 0x0EC2 +3704 2649 26 + +# dress form +Static 0x0EC6 +3664 2592 0 +3666 2580 0 + +# dress form +Static 0x0EC7 +3669 2579 0 + +# easel with canvas +Static 0x0F66 +3642 2496 0 + +# easel +Static 0x0F67 +3640 2510 0 + +# easel with canvas +Static 0x0F68 +3640 2508 0 + +# bolt of cloth +Static 0x0F96 (Hue=0x12) +3668 2577 0 +3668 2591 0 +3669 2591 0 + +# bolt of cloth +Static 0x0F97 (Hue=0x26) +3668 2577 0 + +# bolt of cloth +Static 0x0F98 (Hue=0x26) +3665 2579 0 +3665 2594 0 + +# bolt of cloth +Static 0x0F99 (Hue=0x1D) +3665 2579 0 + +# bolt of cloth +Static 0x0F9A (Hue=0x21) +3665 2578 0 +3665 2595 0 + +# bolt of cloth +Static 0x0F9B (Hue=0x21) +3669 2577 0 + +# bolt of cloth +Static 0x0F9C (Hue=0x26) +3669 2577 0 + +# sewing kit +Static 0x0F9D +3667 2590 6 + +# scissors +Scissors 0x0F9E +3668 2590 6 + +# scissors +Scissors 0x0F9F +3664 2596 6 + +# playing cards +Static 0x0FA3 +3676 2652 4 + +# chess board +ChessBoard 0x0FA6 +3672 2649 4 + +# dice and cup +Dices 0x0FA7 +3676 2650 4 + +# dying tub +DyeTub 0x0FAB +3642 2600 0 + +# fire pit +Static 0x0FAC (Light=Circle225) +3704 2596 20 +3735 2645 40 +3736 2572 40 + +# backgammon game +Backgammon 0x0FAD +3676 2650 4 + +# barrel +Static 0x0FAE +3616 2651 -3 +3632 2649 -3 +3645 2674 -3 +3661 2672 -3 +3671 2665 -3 + +# anvil +AnvilSouthAddon 0x0FB0 +3643 2603 0 + +# forge +SmallForgeAddon 0x0FB1 +3645 2603 0 + +# sledge hammer +Static 0x0FB4 +3643 2604 0 + +# horse shoes +Static 0x0FB6 +3641 2601 4 + +# tongs +Static 0x0FBB +3641 2603 4 + +# book +Static 0x0FBD +3608 2500 4 +3624 2606 4 +3626 2531 4 +3640 2468 4 +3641 2595 6 +3664 2586 6 +3666 2531 4 +3675 2532 4 +3714 2649 26 + +# book +Static 0x0FBE +3602 2573 6 +3602 2605 6 +3604 2504 4 +3613 2471 4 +3625 2545 6 +3634 2571 6 +3642 2501 6 +3666 2620 4 +3668 2496 4 +3676 2472 4 + +# pen and ink +Static 0x0FBF +3608 2500 4 +3624 2606 4 +3626 2531 4 +3640 2468 4 +3641 2595 6 +3664 2586 6 +3666 2531 4 +3675 2532 4 +3714 2649 26 + +# pen and ink +Static 0x0FC0 +3602 2573 6 +3602 2605 6 +3604 2504 4 +3613 2471 4 +3625 2545 6 +3634 2571 6 +3642 2501 6 +3666 2620 4 +3668 2496 4 + +# paints and brush +Static 0x0FC1 +3642 2497 0 + +# book +CallToAnarchy 0x0FEF +3610 2476 4 + +# book +GrammarOfOrcish 0x0FEF +3672 2474 4 + +# book +RedBook 0x0FF1 +3677 2472 4 + +# book +BlueBook 0x0FF2 +3610 2474 4 + +# book +BritannianFlora 0x0FF3 +3611 2476 4 + +# book +BirdsOfBritannia 0x0FF4 +3611 2475 4 + +# book +TreatiseOnAlchemy 0x0FF4 +3672 2475 4 + +# spinning wheel +Static 0x1019 +3667 2597 0 + +# pile of wool +Static 0x101F +3667 2578 0 + +# sack of flour +Static 0x1039 +3608 2570 0 +3621 2568 0 +3621 2569 0 + +# open sack of flour +Static 0x103A +3613 2572 0 +3614 2573 0 +3619 2568 6 +3740 2682 40 + +# dough +Static 0x103D +3616 2568 6 + +# cookie mix +Static 0x103F +3611 2568 6 +3618 2569 6 + +# rolling pin +Static 0x1043 +3610 2568 6 +3618 2568 6 + +# loom bench +Static 0x104A +3668 2594 0 + +# upright loom +LoomSouthAddon 0x1061 +3668 2594 0 + +# cut leather +Static 0x1068 +3605 2619 6 + +# stretched hide +Static 0x106A +3601 2612 0 + +# stretched hide +Static 0x106B +3601 2614 0 + +# pile of hides +Static 0x1078 +3605 2617 0 +3606 2601 0 + +# pile of hides +Static 0x1079 +3601 2601 0 +3603 2621 0 + +# cut leather +Static 0x1081 +3603 2600 6 +3604 2619 6 + +# cut leather +Static 0x1082 +3604 2600 6 + +# garbage +Static 0x10EE +3703 2597 20 +3706 2596 20 + +# potted tree +PottedTree 0x11C8 +3637 2496 0 +3641 2592 0 +3665 2496 0 +3736 2687 40 + +# potted tree +PottedTree1 0x11C9 +3600 2568 0 +3608 2504 0 +3633 2496 0 +3640 2465 0 +3656 2589 0 +3704 2584 20 + +# flowerpot +PottedPlant 0x11CA +3600 2504 0 +3632 2544 0 +3632 2601 0 +3637 2561 0 +3640 2496 0 +3673 2472 0 +3679 2472 0 +3728 2632 40 + +# flowerpot +PottedPlant1 0x11CB +3608 2501 7 +3632 2569 9 +3667 2620 7 + +# flowerpot +PottedPlant2 0x11CC +3636 2571 9 +3644 2501 9 + +# fur +Static 0x11F4 +3604 2615 6 + +# fur +Static 0x11F5 +3606 2615 6 + +# fur +Static 0x11F6 +3604 2609 6 + +# fur +Static 0x11F7 +3606 2609 6 + +# fur +Static 0x11F8 +3600 2613 6 + +# fur +Static 0x11F9 +3600 2618 6 + +# fur +Static 0x11FA +3600 2611 6 + +# fur +Static 0x11FB +3600 2620 6 + +# tarot +Static 0x12A5 +3627 2545 6 + +# moulding board +Static 0x14E9 +3617 2569 6 + +# moulding board +Static 0x14EA +3611 2569 7 + +# ship model +Static 0x14F3 +3635 2637 6 + +# rope +Static 0x14F8 +3632 2632 0 +3647 2669 -3 +3660 2677 -3 + +# rope +Static 0x14FA +3669 2660 -3 + +# plough +Static 0x1500 +3740 2645 40 + +# harrow +Static 0x1505 +3740 2643 40 + +# water barrel +Static 0x154D +3613 2573 0 + +# bowl of carrots +Static 0x15F9 +3736 2681 46 + +# pewter bowl +Static 0x15FD +3654 2465 6 + +# bowl of lettuce +Static 0x1600 +3736 2682 46 + +# large pewter bowl +Static 0x1603 +3654 2467 6 + +# folded cloth +Static 0x175F (Hue=0x6C5) +3664 2576 6 + +# folded cloth +Static 0x1761 (Hue=0x4BD) +3667 2576 6 + +# folded cloth +Static 0x1762 (Hue=0x21) +3664 2580 6 + +# folded cloth +Static 0x1762 (Hue=0x72B) +3666 2576 6 + +# folded cloth +Static 0x1763 (Hue=0x522) +3668 2576 6 + +# folded cloth +Static 0x1763 (Hue=0x5F6) +3664 2579 6 + +# folded cloth +Static 0x1764 (Hue=0x58A) +3669 2576 6 + +# folded cloth +Static 0x1764 (Hue=0x64D) +3664 2577 6 + +# rock +Static 0x1778 +3767 2718 21 + +# skull with candle +CandleSkull 0x1858 +3628 2531 4 +3628 2545 6 +3631 2531 4 +3634 2531 4 + +# silver wire +Static 0x1877 +3641 2602 4 + +# spilled flour +Static 0x187E +3615 2574 0 + +# spilled flour +Static 0x187F +3610 2572 0 diff --git a/Data/Decoration/Felucca/solen matriarch quest.cfg b/Data/Decoration/Felucca/solen matriarch quest.cfg new file mode 100644 index 0000000..37e05ae --- /dev/null +++ b/Data/Decoration/Felucca/solen matriarch quest.cfg @@ -0,0 +1,3 @@ +# Black Solen Matriarch +Spawner 0x1F13 (Spawn=BlackSolenMatriarch; Count=1; HomeRange=14) +5776 1898 22 \ No newline at end of file diff --git a/Data/Decoration/Felucca/yew.cfg b/Data/Decoration/Felucca/yew.cfg new file mode 100644 index 0000000..f1fe3ae --- /dev/null +++ b/Data/Decoration/Felucca/yew.cfg @@ -0,0 +1,2248 @@ +######### +# Doors # +######### + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +319 791 20 +299 764 20 +312 783 20 +313 791 20 +356 839 20 +369 903 0 +369 867 0 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +313 783 20 +357 839 20 +370 903 0 +370 867 0 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +289 771 0 +289 771 20 +343 884 20 +367 878 0 +371 871 0 +327 793 20 +343 885 0 +351 835 20 +367 878 20 +343 873 0 +367 873 0 +367 873 20 +343 873 20 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +327 792 20 +351 834 20 + + +# barred metal door +BarredMetalDoor 0x0685 (Facing=WestCW) +262 769 -2 +262 769 20 +268 769 -2 +268 769 20 +274 769 -2 +274 769 20 +280 769 -2 +280 769 20 +286 769 -2 +286 769 20 + +# barred metal door +BarredMetalDoor 0x0689 (Facing=WestCCW) +262 773 -2 +262 773 20 +268 773 -2 +268 773 20 +274 773 -2 +274 773 20 +280 773 -2 +280 773 20 +286 773 -2 +286 773 20 + + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +355 891 0 +666 951 0 +666 1191 0 +355 890 20 +562 1111 0 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +356 891 0 +667 951 0 +667 1191 0 +356 890 20 +563 1111 0 + + +# stone wall +SecretStoneDoor1 0x00E8 (Facing=WestCW) +308 791 0 + +# stone wall +SecretStoneDoor1 0x00EA (Facing=EastCCW) +261 763 0 +262 779 0 +262 779 20 +267 763 0 +268 779 0 +268 779 20 +273 763 0 +274 779 0 +274 779 20 +279 763 0 +280 779 0 +280 779 20 +285 763 0 +286 779 0 +286 779 20 +291 777 20 + +# stone wall +SecretStoneDoor1 0x00EC (Facing=WestCCW) +261 763 20 +267 763 20 +273 763 20 +279 763 20 +285 763 20 + +# stone wall +SecretStoneDoor1 0x00F0 (Facing=SouthCW) +296 761 20 +301 762 0 + +# stone wall +SecretStoneDoor1 0x00F2 (Facing=NorthCCW) +301 761 0 + + +############ +# Standard # +############ + +# stone wall +Static 0x00C8 +309 791 0 + +# stone wall +Static 0x00C9 +564 1307 0 + +# patch +Static 0x02F1 +597 837 0 + +# patch +Static 0x02F2 +597 837 0 + +# cobblestones +Static 0x0515 +383 917 0 + +# cobblestones +Static 0x0516 +309 786 0 +309 787 0 + +# oven +StoneOvenEastAddon 0x092C +552 1217 0 + +# oven +StoneOvenSouthAddon 0x0930 +394 1216 0 +553 984 -2 +682 1200 0 +665 1000 0 + +# slab of bacon +Static 0x0976 +457 1141 6 +603 1187 6 + +# slab of bacon +Static 0x0977 +392 1218 6 +602 1184 10 +603 1184 6 + +# wheel of cheese +CheeseWheel 0x097E +452 1110 6 + +# basket +Basket 0x0990 +416 1035 4 +656 1005 6 + +# tray +Static 0x0991 +392 1218 6 +539 1009 6 +603 1184 6 +642 844 4 +643 834 4 +654 938 6 + +# tray +Static 0x0992 +416 1037 4 +450 1117 6 +459 1141 6 +555 1221 6 +574 1123 6 +679 1202 6 + +# fruit basket +FruitBasket 0x0993 +284 986 4 +421 1035 6 +642 833 4 +656 1004 6 + +# ceramic mug +CeramicMug 0x0995 +642 834 4 +642 837 4 +642 838 4 +642 840 4 +642 842 4 + +# ceramic mug +CeramicMug 0x0997 +400 1219 6 +452 1112 6 +555 1210 6 +574 1122 6 +599 1187 6 +624 1149 6 +643 836 4 +643 838 4 +643 840 4 +643 842 4 +643 844 4 +648 938 6 +648 1084 6 +677 1202 6 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +261 774 0 +261 774 20 +262 766 0 +262 766 20 +267 774 0 +267 774 20 +268 766 0 +268 766 20 +273 774 0 +274 766 0 +274 766 20 +274 774 20 +279 774 0 +279 774 20 +280 766 0 +280 766 20 +285 774 0 +285 774 20 +286 766 0 +286 766 20 +324 1240 6 +398 1220 6 +400 1219 6 +420 1034 6 +450 963 6 +451 1112 6 +452 1112 6 +458 1135 6 +459 1133 6 +554 1212 6 +555 1210 6 +572 1123 6 +574 1122 6 +597 1188 6 +599 1187 6 +624 1147 6 +634 1040 6 +646 939 6 +648 938 6 +648 1084 6 +660 1003 6 +662 1002 6 +677 1202 6 +677 1203 6 +734 883 6 +736 882 6 + +# bottles of liquor +Static 0x099E +608 873 5 +608 876 0 +609 872 10 +611 872 0 +611 875 0 +613 875 5 +613 877 0 +615 872 0 +615 873 5 +615 875 0 +617 873 0 +617 874 0 +617 877 0 +619 876 0 +620 874 10 +621 874 0 + +# fork +Fork 0x09A3 +451 1111 6 +458 1134 6 +554 1211 6 +642 835 4 +642 837 4 +642 839 4 +642 841 4 +642 843 4 + +# fork +Fork 0x09A4 +399 1219 6 +573 1122 6 +598 1187 6 +647 938 6 +678 1202 6 + +# knife +Knife 0x09A5 +451 1111 6 +458 1134 6 +554 1211 6 +642 835 4 +642 837 4 +642 839 4 +642 841 4 +642 843 4 + +# knife +Knife 0x09A6 +399 1219 6 +535 1011 6 +573 1122 6 +598 1187 6 +647 938 6 +678 1202 6 + +# metal box +FillableMetalBox 0x09A8 +565 1307 0 + +# metal box +MetalBox 0x09A8 +555 988 6 +562 1008 6 +565 960 6 + +# wooden box +WoodenBox 0x09AA +731 880 0 +739 880 0 + +# metal chest +FillableMetalChest 0x09AB (ContentType=Inn) +603 808 0 +603 816 0 +604 826 0 +607 826 0 +617 824 0 +619 808 0 +649 808 0 +653 824 0 +668 808 0 +668 816 0 + +# bushel +Basket 0x09AC +656 1006 6 + +# cooked bird +CookedBird 0x09B7 +642 844 4 +643 834 4 + +# cooked bird +CookedBird 0x09B8 +459 1141 6 +555 1221 6 +574 1123 6 +679 1202 6 + +# roast pig +RoastPig 0x09BB +281 984 4 + +# roast pig +RoastPig 0x09BC +392 1220 9 + +# silverware +Static 0x09BD +283 986 4 + +# silverware +Static 0x09BE +421 1034 6 +481 850 4 +483 850 4 +661 1002 6 +735 882 6 + +# sausage +Sausage 0x09C0 +603 1188 6 + +# sausage +Sausage 0x09C1 +392 1221 6 + +# ham +Ham 0x09C9 +604 1184 11 + +# ceramic mug +CeramicMug 0x09CA +324 1240 6 +398 1220 6 +451 1112 6 +554 1212 6 +572 1123 6 +597 1188 6 +634 1040 6 +646 939 6 +677 1203 6 + +# grape bunch +Grapes 0x09D1 +594 846 0 +594 858 0 +597 853 0 +600 841 0 +600 846 0 +600 857 0 +603 848 0 +603 860 0 +606 845 0 +606 858 0 +609 854 0 +610 883 6 +610 884 6 +610 885 6 +610 886 6 +610 887 6 +610 892 6 +611 892 6 +612 846 0 +612 856 0 +612 892 6 +613 892 6 +614 883 6 +614 884 6 +614 885 6 +614 886 6 +614 887 6 +615 842 0 +615 850 0 +615 858 0 +615 892 6 +616 892 6 +617 892 6 +618 883 6 +618 884 6 +618 885 6 +618 886 6 +618 887 6 +618 892 6 + +# ham +Ham 0x09D3 +603 1189 6 + +# silverware +Static 0x09D4 +284 987 4 +286 987 4 +420 1035 6 +451 963 6 +480 851 4 +482 851 4 +661 1003 6 +735 883 6 + +# silverware +Static 0x09D5 +287 986 4 +328 1061 4 + +# pitcher +Static 0x09D6 +480 851 4 +481 850 4 +482 851 4 +483 850 4 + +# plate +Plate 0x09D7 +283 986 4 +284 987 4 +286 987 4 +287 986 4 +323 1240 6 +328 1061 4 +399 1219 6 +399 1220 6 +420 1035 6 +421 1034 6 +451 963 6 +451 1111 6 +452 1111 6 +458 1134 6 +459 1134 6 +480 851 4 +481 850 4 +482 851 4 +483 850 4 +554 1211 6 +555 1211 6 +573 1122 6 +573 1123 6 +598 1187 6 +598 1188 6 +624 1148 6 +633 1040 6 +642 835 4 +642 837 4 +642 839 4 +642 841 4 +642 843 4 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +647 938 6 +647 939 6 +648 1085 6 +661 1002 6 +661 1003 6 +678 1202 6 +678 1203 6 +735 882 6 +735 883 6 + +# cake +Cake 0x09E9 +451 1117 6 +555 1212 6 + +# kettle +Static 0x09ED +397 1216 0 +449 1117 6 +458 1141 6 +553 1221 6 +555 986 6 +654 936 6 +685 1201 6 + +# milk +Pitcher 0x09F0 (Content=Milk) +642 836 4 +643 842 4 + +# cut of raw ribs +RawRibs 0x09F1 +460 1141 6 +528 1011 3 + +# fork +Fork 0x09F4 +323 1240 6 +399 1220 6 +573 1123 6 +598 1188 6 +633 1040 6 +647 939 6 +678 1203 6 + +# fork +Fork 0x09F5 +452 1111 6 +459 1134 6 +555 1211 6 +624 1148 6 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +648 1085 6 + +# knife +Knife 0x09F6 +323 1240 6 +399 1220 6 +573 1123 6 +598 1188 6 +633 1040 6 +647 939 6 +678 1203 6 + +# knife +Knife 0x09F7 +452 1111 6 +459 1134 6 +555 1211 6 +603 1188 6 +624 1148 6 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +648 1085 6 + +# spoon +Spoon 0x09F8 +323 1240 6 +399 1220 6 +573 1123 6 +598 1188 6 +633 1040 6 +647 939 6 +678 1203 6 + +# spoon +Spoon 0x09F9 +452 1111 6 +459 1134 6 +555 1211 6 +624 1148 6 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +648 1085 6 + +# chest of drawers +Drawer 0x0A2C +331 1056 0 +333 1056 0 +392 1224 0 +426 1040 0 +449 1128 0 +457 960 0 +457 1112 0 +486 840 0 +578 1120 0 +595 1184 0 +625 1144 0 +637 1040 0 +648 944 0 +649 1080 0 +666 1008 0 +682 1208 0 +732 880 0 +738 880 0 + +# chest of drawers +FancyDrawer 0x0A30 +613 824 0 +665 808 0 +665 816 0 +669 824 0 + +# chest of drawers +Drawer 0x0A34 +320 1245 0 + +# chest of drawers +FancyDrawer 0x0A38 +336 883 20 +336 884 0 +480 841 0 +600 812 0 +600 820 0 +600 828 0 +616 811 0 +616 828 0 +648 811 0 +648 826 0 +656 828 0 + +# armoire +FancyArmoire 0x0A4D +609 824 0 +670 824 0 + +# armoire +Armoire 0x0A4F +280 976 0 +285 976 0 +394 1224 0 +453 1128 0 +461 960 0 +576 1120 0 +597 1184 0 +629 1144 0 +650 944 0 +653 1080 0 +670 1008 0 + +# armoire +FancyArmoire 0x0A51 +336 882 0 +336 882 20 +480 842 0 +600 811 0 +600 819 0 +600 827 0 +616 810 0 +616 829 0 +648 810 0 +648 827 0 +656 829 0 +664 813 0 +664 821 0 + +# armoire +Armoire 0x0A53 +320 1241 0 +328 1057 0 +456 1117 0 +560 1221 0 +632 1045 0 +680 1209 0 + +# folded sheet +Static 0x0A92 +529 960 2 +532 960 2 +535 960 2 +538 960 2 +541 960 2 + +# folded sheet +Static 0x0A93 +424 1043 2 +424 1045 2 + +# bookcase +LibraryBookcase 0x0A97 +291 976 0 +330 1240 0 +339 872 0 +339 872 20 +401 1216 0 +406 1216 0 +450 1104 0 +461 1128 0 +473 840 0 +556 1208 0 +568 960 0 +598 1184 0 +601 1184 0 +626 842 20 +628 1032 0 +630 816 20 +638 816 20 +641 936 0 +642 816 20 +642 1080 0 +644 1080 0 + +# bookcase +LibraryBookcase 0x0A98 +290 976 0 +292 976 0 +329 1240 0 +333 1240 0 +338 872 0 +338 872 20 +340 872 0 +340 872 20 +400 1216 0 +449 1104 0 +457 1128 0 +476 840 0 +477 840 0 +553 1208 0 +557 1208 0 +565 808 0 +569 960 0 +599 1184 0 +625 842 20 +625 1032 0 +631 816 20 +639 816 20 +641 848 0 +641 1080 0 +642 848 0 +642 936 0 +643 848 0 +643 1080 0 +644 848 0 +644 936 0 +645 848 0 + +# bookcase +LibraryBookcase 0x0A99 +320 1061 0 +448 1109 0 +456 1134 0 +528 968 0 +528 973 0 +560 968 0 +568 1124 0 +616 1146 0 +616 1148 0 +624 825 20 +624 838 0 +624 839 0 +624 840 0 +624 849 0 +624 850 0 +624 851 0 +624 851 20 +624 852 0 +624 852 20 +624 853 0 +624 853 20 +624 1033 0 +640 937 0 +640 941 0 +642 843 20 +642 844 20 +642 845 20 +642 846 20 +672 1201 0 +728 881 0 +728 882 0 +728 884 0 +728 885 0 + +# bookcase +LibraryBookcase 0x0A9A +320 1058 0 +320 1060 0 +336 884 20 +448 1110 0 +456 1129 0 +528 969 0 +528 972 0 +568 1122 0 +616 1147 0 +624 826 20 +624 843 0 +624 844 0 +624 845 0 +672 1202 0 +672 1204 0 + +# bookcase +LibraryBookcase 0x0A9B +289 976 0 +293 976 0 +332 1240 0 +337 872 0 +337 872 20 +341 872 0 +341 872 20 +405 1216 0 +452 1104 0 +453 1104 0 +474 840 0 +554 1208 0 +561 808 0 +563 808 0 +600 1184 0 +629 1032 0 +632 816 20 +640 816 20 +640 1080 0 +641 816 20 +643 842 20 +644 842 20 +645 842 20 +645 936 0 +645 1080 0 + +# bookcase +LibraryBookcase 0x0A9C +320 1057 0 +336 874 20 +448 1111 0 +456 1133 0 +560 969 0 +568 1121 0 +568 1125 0 +624 827 20 +624 833 0 +624 834 0 +624 835 0 +672 1205 0 + +# candle +CandleLarge 0x0B1A +280 981 4 +320 787 26 +322 1240 6 +328 1060 4 +328 1247 6 +356 834 26 +398 1219 6 +419 1034 6 +424 1040 6 +448 1106 6 +448 1128 6 +452 963 6 +456 1112 6 +458 1133 6 +474 844 6 +480 840 5 +515 988 6 +539 1008 6 +554 1210 6 +555 984 6 +560 1216 6 +562 1012 6 +565 966 6 +572 1122 6 +597 1187 6 +606 814 6 +606 816 6 +614 824 6 +616 814 6 +616 824 6 +621 1146 6 +627 845 6 +632 1040 6 +634 1032 6 +640 1087 6 +646 938 6 +648 808 6 +648 824 6 +648 1086 6 +656 824 6 +660 1002 6 +664 808 6 +664 816 6 +664 1008 6 +679 1203 6 +728 880 6 +742 880 6 +460 965 2 +632 816 6 +635 816 26 +638 816 6 + +# candelabra +Candelabra 0x0B1D +292 980 4 + +# candelabra +CandelabraStand 0x0B26 +282 989 0 +320 1048 0 +332 816 20 +336 872 0 +336 872 20 +344 816 20 +344 876 0 +344 876 20 +344 902 0 +344 902 20 +365 876 0 +365 876 20 +366 902 0 +366 902 20 +486 848 0 +528 960 0 +528 967 0 +542 960 0 +542 974 0 +624 842 20 +624 1032 0 +640 846 0 +642 842 20 + +# wooden bench +WoodenBench 0x0B2C +312 794 20 +312 795 20 +312 796 20 +312 797 20 + +# wooden bench +WoodenBench 0x0B2D +315 792 20 +316 792 20 +317 792 20 +348 880 0 +348 881 20 +348 882 0 +348 883 20 +348 884 0 +348 885 20 +348 886 0 +348 887 20 +348 888 0 +348 889 20 +348 890 0 +349 880 0 +349 881 20 +349 882 0 +349 883 20 +349 884 0 +349 885 20 +349 886 0 +349 887 20 +349 888 0 +349 889 20 +349 890 0 +350 880 0 +350 881 20 +350 882 0 +350 883 20 +350 884 0 +350 885 20 +350 886 0 +350 887 20 +350 888 0 +350 889 20 +350 890 0 +351 880 0 +351 881 20 +351 882 0 +351 883 20 +351 884 0 +351 885 20 +351 886 0 +351 887 20 +351 888 0 +351 889 20 +351 890 0 +352 880 0 +352 881 20 +352 882 0 +352 883 20 +352 884 0 +352 885 20 +352 886 0 +352 887 20 +352 888 0 +352 889 20 +352 890 0 +353 880 0 +353 881 20 +353 882 0 +353 883 20 +353 884 0 +353 885 20 +353 887 20 +353 888 0 +353 889 20 +353 890 0 +358 880 0 +358 881 20 +358 882 0 +358 883 20 +358 884 0 +358 885 20 +358 886 0 +358 887 20 +358 888 0 +358 889 20 +358 890 0 +359 880 0 +359 881 20 +359 882 0 +359 883 20 +359 884 0 +359 885 20 +359 886 0 +359 887 20 +359 888 0 +359 889 20 +359 890 0 +360 880 0 +360 881 20 +360 882 0 +360 883 20 +360 884 0 +360 885 20 +360 886 0 +360 887 20 +360 888 0 +360 889 20 +360 890 0 +361 880 0 +361 881 20 +361 882 0 +361 883 20 +361 884 0 +361 885 20 +361 886 0 +361 887 20 +361 888 0 +361 889 20 +361 890 0 +362 880 0 +362 881 20 +362 882 0 +362 883 20 +362 884 0 +362 885 20 +362 886 0 +362 887 20 +362 888 0 +362 889 20 +362 890 0 +363 880 0 +363 881 20 +363 882 0 +363 883 20 +363 884 0 +363 885 20 +363 886 0 +363 887 20 +363 888 0 +363 889 20 +363 890 0 + +# chair +FancyWoodenChairCushion 0x0B4E +282 986 0 + +# chair +FancyWoodenChairCushion 0x0B4F +475 849 0 +481 849 0 +483 849 0 + +# chair +FancyWoodenChairCushion 0x0B50 +284 988 0 +286 988 0 +480 852 0 +482 852 0 + +# chair +FancyWoodenChairCushion 0x0B51 +288 986 0 +644 851 0 + +# chair +WoodenChairCushion 0x0B52 +473 843 0 +529 970 0 +625 831 20 +625 836 20 +626 834 0 +626 839 0 +626 844 0 +626 851 0 +641 835 0 +641 837 0 +641 839 0 +641 841 0 +641 843 0 + +# chair +WoodenChairCushion 0x0B53 +291 978 0 +319 786 20 +355 833 20 +631 818 20 +640 818 20 + +# chair +WoodenChairCushion 0x0B54 +355 900 20 +355 901 0 +475 853 0 +636 817 20 + +# chair +WoodenChairCushion 0x0B55 +337 879 0 +337 879 20 +635 1034 0 +645 831 20 +645 835 0 +645 836 20 +645 837 0 +645 839 0 +645 841 0 +645 843 0 + +# chair +WoodenChair 0x0B56 +450 1111 0 +457 1134 0 +514 990 0 +553 1211 0 +561 1010 0 +563 963 0 + +# chair +WoodenChair 0x0B57 +329 1246 0 +350 892 20 +350 893 0 +352 892 20 +352 893 0 +359 892 20 +359 893 0 +361 892 20 +361 893 0 +399 1218 0 +421 1033 0 +534 972 0 +536 972 0 +537 1010 0 +563 810 0 +568 1011 6 +573 1121 0 +598 1186 0 +620 1145 0 +641 1086 0 +647 937 0 +661 1001 0 +678 1201 0 +735 881 0 + +# chair +WoodenChair 0x0B58 +449 1107 0 +453 1111 0 +460 1134 0 +556 1211 0 +571 964 0 +625 1148 0 +641 939 0 +641 1083 0 +649 1085 0 + +# chair +WoodenChair 0x0B59 +321 1056 0 +323 1241 0 +350 900 0 +350 900 20 +399 1221 0 +403 1217 0 +420 1036 0 +459 1129 0 +562 812 0 +564 812 0 +573 1124 0 +598 1189 0 +633 1041 0 +647 940 0 +661 1004 0 +678 1204 0 +735 884 0 + +# chair +BambooChair 0x0B5A +571 1011 6 +664 1003 0 + +# chair +BambooChair 0x0B5B +459 964 0 +567 1008 6 + +# chair +BambooChair 0x0B5C +451 964 0 +534 968 0 +536 968 0 + +# chair +BambooChair 0x0B5D +281 980 0 +329 1061 0 +541 962 0 +541 963 0 +669 1003 0 + +# foot stool +FootStool 0x0B5E +458 960 0 +531 960 0 +534 960 0 +537 960 0 +540 960 0 + +# bench +Static 0x0B5F +425 1035 0 +428 1035 0 + +# bench +Static 0x0B60 +425 1034 0 +428 1034 0 + +# bench +Static 0x0B65 +427 1036 0 +667 1004 0 + +# bench +Static 0x0B66 +426 1036 0 +666 1004 0 + +# wooden signpost +Static 0x0B98 +618 1152 0 +626 1040 0 + +# broken chair +Static 0x0C10 +562 1010 6 + +# pile of wool +Static 0x0DF8 +566 1122 0 +685 1198 0 + +# barber scissors +Static 0x0DFC +322 1048 6 + +# bloody bandage +Static 0x0E20 +539 960 0 + +# clean bandage +Static 0x0E21 +330 1247 6 + +# bloody bandage +Static 0x0E22 +329 1251 0 +531 960 0 +641 1089 0 + +# bloody water +Static 0x0E23 +320 1051 0 +330 1250 0 +533 960 0 +539 961 0 + +# crystal ball +Static 0x0E2E (Light=Circle150) +627 834 6 + +# crate +LargeCrate 0x0E3C +308 784 0 +308 784 3 +308 785 0 +308 786 0 +309 784 0 +309 784 3 +309 788 1 +309 788 4 +310 784 0 +310 787 0 +310 787 3 +310 787 6 +310 788 0 +310 788 3 +310 789 0 +310 789 3 +310 789 6 +311 789 0 +311 789 3 +317 784 0 +317 784 3 +317 784 6 +317 784 9 +317 785 0 +317 785 3 +317 794 0 +317 794 3 +317 794 6 +317 795 0 +317 795 3 +317 795 6 +318 784 0 +318 784 3 +318 785 0 +318 794 0 +318 794 3 +318 794 6 +318 795 0 +318 795 3 +318 795 6 +656 1002 0 +656 1003 0 + +# crate +LargeCrate 0x0E3D +311 788 -23 +312 790 -23 + +# crate +FillableLargeCrate 0x0E3D (ContentType=Mill) +546 810 0 +546 810 3 +546 811 0 +547 810 0 +547 810 3 +547 811 0 +547 811 3 + +# crate +MediumCrate 0x0E3E +323 795 0 +323 795 3 +323 796 0 +324 795 0 +324 796 0 +324 796 3 +416 1033 0 +416 1033 3 +416 1034 0 +448 961 0 +448 961 3 +448 962 0 +544 812 0 +544 812 3 +544 813 0 +544 813 3 +544 813 6 + +# crate +MediumCrate 0x0E3F +417 1032 0 +417 1032 3 +449 960 0 +449 960 3 + +# wooden chest +WoodenChest 0x0E42 +424 1042 0 +461 966 0 +664 1014 0 + +# wooden chest +WoodenChest 0x0E43 +311 784 0 +324 1061 0 +482 840 0 + +# empty jars +Static 0x0E46 +324 1048 6 + +# full jars +Static 0x0E4B +536 973 6 + +# stump +Static 0x0E59 +637 1155 0 + +# barrel +Barrel 0x0E77 +312 792 0 +312 792 5 +312 792 10 +312 793 0 +312 793 5 +312 794 0 +313 792 0 +313 792 5 +313 793 0 +314 785 6 +314 792 0 +323 790 0 +323 790 5 +323 790 10 +323 791 0 +324 790 5 +324 790 10 +324 791 0 +325 790 0 +325 790 5 +325 790 10 +325 791 0 +416 1032 0 +448 960 0 +448 960 5 +544 808 0 +544 808 5 +544 808 10 +544 809 0 +544 809 5 +545 808 0 +545 808 5 +549 808 0 +549 809 0 +549 812 0 +549 812 5 +549 813 0 +549 813 5 +550 808 0 +550 808 5 +550 809 0 +550 809 5 +550 812 0 +550 812 5 +550 813 0 +550 813 5 +608 872 0 +608 872 5 +608 872 10 +608 873 0 +609 872 0 +609 872 5 +609 873 0 +609 892 0 +610 882 0 +610 888 0 +612 874 0 +612 874 5 +612 874 10 +613 873 5 +613 873 10 +613 874 5 +614 873 5 +614 874 5 +614 882 0 +614 888 0 +614 892 0 +618 882 0 +618 888 0 +619 873 0 +619 892 0 +620 873 0 +620 873 5 +620 873 10 +620 874 0 +620 874 5 +621 873 0 +661 1008 0 +730 888 0 + +# metal chest +MetalChest 0x0E7C +260 766 0 +260 766 20 +260 774 20 +260 775 0 +266 766 0 +266 766 20 +266 774 20 +266 775 0 +272 766 0 +272 766 20 +272 774 20 +272 775 0 +278 766 0 +278 766 20 +278 774 20 +278 775 0 +283 774 40 +284 766 0 +284 766 20 +284 774 20 +284 775 0 + +# metal chest +FillableMetalChest 0x0E7C (ContentType=Inn) +656 826 0 +656 827 0 + +# crate +SmallCrate 0x0E7E +448 962 3 + +# strong box +FillableMetalBox 0x0E80 +512 988 6 + +# drum +Static 0x0E9C +627 821 20 + +# tambourine +Static 0x0E9D +627 823 20 + +# standing harp +Static 0x0EB1 +625 818 20 + +# lap harp +Static 0x0EB2 +627 818 20 + +# lute +Static 0x0EB4 +625 821 20 +625 823 20 + +# music stand +Static 0x0EB9 +625 819 20 +627 819 20 + +# music stand +Static 0x0EBC +624 821 20 +624 823 20 + +# sheet music +Static 0x0EC0 +624 821 20 +624 823 20 + +# cleaver +Static 0x0EC3 +281 984 4 +604 1184 11 + +# skinning knife +Static 0x0EC4 +602 1184 10 + +# clean bandage +Static 0x0EE9 +322 1048 6 +323 1048 6 +533 967 6 +535 967 6 +535 973 6 +536 967 6 +640 1084 6 +642 1087 6 +642 1092 0 + +# bottle +Static 0x0EFE +642 851 26 + +# bottle +Static 0x0EFF +642 852 26 + +# bottle +Static 0x0F00 +644 830 26 + +# bottle +Static 0x0F01 +642 850 26 + +# bottle +Static 0x0F03 +644 830 26 + +# Black Potion +Static 0x0F06 +644 835 26 +645 850 26 + +# Blue Potion +Static 0x0F08 +644 844 26 + +# Green Potion +Static 0x0F0A +642 853 26 + +# Red Potion +Static 0x0F0B +329 1254 6 +332 1254 6 +533 973 10 +534 973 9 +537 973 10 +640 1083 6 +640 1094 6 +644 846 26 + +# Yellow Potion +Static 0x0F0C +330 1254 6 +331 1254 6 +640 1082 6 +641 1094 6 +644 845 26 + +# Purple Potion +Static 0x0F0D +645 851 26 + +# empty bottle +Static 0x0F0E +644 837 26 +645 852 26 + +# arrows +Static 0x0F41 +616 1145 6 + +# crossbow +Static 0x0F4F +620 1146 6 + +# crossbow +Static 0x0F50 +616 1149 6 + +# easel with canvas +Static 0x0F68 +643 822 20 +643 825 20 +643 828 20 + +# Batwing +Static 0x0F78 +626 853 26 + +# Daemon Bone +Static 0x0F80 +624 845 26 + +# Ginseng +Static 0x0F85 +624 848 26 + +# Pig Iron +Static 0x0F8A +624 846 26 +626 835 26 + +# Nox Crystal +Static 0x0F8E +626 830 26 +626 852 26 + +# scissors +Scissors 0x0F9E +534 967 6 +535 973 6 + +# barrel +Static 0x0FAE +313 784 0 +313 784 7 +313 785 0 +313 785 7 +314 784 0 +314 784 7 +314 785 0 +314 786 0 +314 787 0 + +# book +Static 0x0FBD +280 980 4 +336 879 6 +336 879 26 +448 1107 6 +515 990 6 +530 970 6 +565 963 6 +626 831 26 +626 836 26 +627 844 6 +627 851 6 +640 939 6 +643 851 6 +644 831 26 +644 836 26 + +# book +Static 0x0FBE +291 979 4 +319 787 26 +321 1055 6 +329 1247 6 +352 893 24 +352 894 4 +355 834 26 +355 898 26 +355 899 6 +359 893 24 +359 894 4 +403 1216 6 +459 1128 6 +474 842 6 +537 1011 6 +563 811 4 +636 816 26 +641 1087 6 + +# pen and ink +Static 0x0FBF +280 979 4 +290 979 4 +336 879 6 +336 879 26 +351 893 24 +351 894 4 +358 893 24 +358 894 4 +448 1107 6 +474 843 6 +515 990 6 +530 970 6 +536 1011 6 +564 810 4 +565 963 6 +626 831 26 +626 836 26 +627 844 6 +627 851 6 +640 939 6 +643 851 6 +644 831 26 +644 836 26 + +# pen and ink +Static 0x0FC0 +318 787 26 +320 1055 6 +329 1247 6 +354 834 26 +354 898 26 +355 899 6 +403 1216 6 +458 965 2 +459 1128 6 +636 816 26 +641 1087 6 + +# paints and brush +Static 0x0FC1 +643 826 20 +644 822 20 +644 827 20 + +# glass pitcher +Pitcher 0x0FF6 +643 842 4 + +# pewter mug +PewterMug 0x0FFF +419 1035 6 +450 963 6 +458 1135 6 + +# pewter mug +PewterMug 0x1000 +336 878 26 +336 880 6 +420 1034 6 +459 1133 6 +660 1003 6 +662 1002 6 +734 882 6 +736 883 6 + +# wash basin +Static 0x1008 +534 967 6 + +# archery butte +ArcheryButte 0x100A +560 972 0 + +# archery butte +ArcheryButte 0x100B +573 960 0 + +# dovetail saw +Static 0x1028 +561 966 6 + +# hammer +Static 0x102A +563 966 6 + +# hammer +Static 0x102B +562 1009 6 +570 963 6 +619 1146 6 + +# nails +Static 0x102E +562 1011 6 +570 963 6 + +# nails +Static 0x102F +563 966 6 + +# saw +Static 0x1034 +570 965 6 +622 1153 0 + +# saw +Static 0x1035 +616 1144 6 + +# sack of flour +Static 0x1039 +544 810 0 +544 817 0 +544 818 6 +544 819 6 +544 824 0 +544 827 6 +545 821 0 +545 824 0 +545 828 0 +546 808 0 +548 808 0 +549 824 0 +550 816 0 +551 816 0 +552 815 0 +554 814 6 +554 828 0 +555 827 6 +556 824 0 +556 825 0 +556 984 0 +557 814 6 +557 815 0 +557 984 0 +558 814 0 +558 815 0 +560 816 0 +560 822 6 +562 821 0 +563 821 0 +565 816 0 + +# open sack of flour +Static 0x103A +544 811 0 +544 820 6 +544 823 0 +544 826 6 +545 829 0 +547 808 0 +552 814 0 +554 827 6 +555 814 6 +557 828 0 +562 822 6 +563 822 6 + +# bread loaf +Static 0x103C +261 766 0 +261 766 20 +262 775 0 +262 775 20 +267 766 0 +267 766 20 +268 774 20 +268 775 0 +273 766 0 +273 766 20 +274 774 0 +274 775 20 +279 766 0 +279 766 20 +280 774 20 +280 775 0 +285 766 0 +285 766 20 +286 774 0 +286 774 20 + +# dough +Static 0x103D +554 988 6 +554 1221 6 +685 1202 6 + +# cookie mix +Static 0x103F +555 987 6 +556 1221 6 +685 1204 6 + +# rolling pin +Static 0x1043 +448 1117 6 +552 1221 6 +553 988 6 +685 1203 6 + +# clock +Clock 0x104C +631 1032 6 +632 1032 6 + +# clock frame +ClockFrame 0x104E +569 1008 6 +636 1032 6 + +# clock parts +ClockParts 0x104F +628 1035 8 + +# axle with gears +AxleGears 0x1051 +627 1035 6 + +# axle with gears +AxleGears 0x1052 +636 1032 8 + +# gears +Gears 0x1053 +626 1035 6 +637 1032 6 + +# sextant +Static 0x1057 +634 1034 7 + +# sextant +Static 0x1058 +629 1035 6 + +# sextant parts +SextantParts 0x1059 +625 1035 7 + +# sextant parts +SextantParts 0x105A +634 1033 6 + +# springs +Springs 0x105D +627 1035 8 +635 1032 8 + +# potted tree +PottedTree 0x11C8 +532 967 0 +532 973 0 + +# flowerpot +PottedPlant 0x11CA +328 1240 0 +448 1104 0 +534 1008 0 +538 967 0 +538 973 0 +552 1208 0 +568 1120 0 +640 936 0 +648 1080 0 +665 1008 0 +672 1200 0 +733 880 0 +737 880 0 + +# flowerpot +PottedPlant1 0x11CB +451 1110 6 +459 1135 9 +514 992 10 +530 972 6 +539 1011 9 +648 939 10 + +# flowerpot +PottedPlant2 0x11CC +562 966 9 +565 965 9 + +# bed +Static 0x11D2 +485 840 0 + +# bed +Static 0x11D3 +485 842 0 + +# bed +Static 0x11D4 +483 842 0 + +# bed +Static 0x11D5 +483 840 0 + +# altar +AbbatoirAddon 0x1216 +311 786 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5750, 350, 5)) +311 786 0 + +# rock +Static 0x1363 +573 1307 0 + +# water barrel +Static 0x154D +324 790 0 +609 873 5 +613 873 0 +613 874 0 +613 875 0 +614 873 0 +614 874 0 +615 873 0 +641 850 40 +648 828 20 +651 811 20 + +# water +Static 0x1797 +443 1043 -5 +463 1280 -5 +464 1280 -5 +465 1280 -5 +466 1280 -5 +467 1280 -5 +468 1280 -5 +469 1280 15 + +# water +Static 0x1798 +443 1044 -5 + +# water +Static 0x179A +469 1281 -5 +470 1281 -5 + +# alchemical symbol +Static 0x1822 +311 786 -24 + +# teleporter +Teleporter 0x1BC3 (PointDest=(314, 784, 0)) +311 786 -24 + +# flour mill +FlourMillSouthAddon 0x192C +550 820 -2 +552 820 -2 +554 820 -2 + +# feather +Static 0x1BD1 +565 961 6 +570 962 6 + +# shaft +Static 0x1BD4 +564 966 6 +570 964 6 + +# boards +Static 0x1BD8 +623 1155 0 + +# logs +Static 0x1BE2 +616 1152 0 +617 1152 0 + +# Quarantine Area: No pets permitted beyond this point! +LocalizedSign 0x1F29 (LabelNumber=1016226) +315 786 -18 + +# Reactive Armor +Static 0x1F2D +624 841 0 +640 848 0 + +# Create Food +Static 0x1F2F +627 839 6 + +# Heal +Static 0x1F31 +624 837 0 +627 843 6 + +# Magic Untrap +Static 0x1F3A +624 832 0 + +# Protection +Static 0x1F3B +645 849 0 + +# Strength +Static 0x1F3C +625 848 0 + +# Arch Cure +Static 0x1F45 +627 852 6 + +# Curse +Static 0x1F47 +624 848 0 +643 853 0 + +# Dispel Field +Static 0x1F4E +627 850 6 + +# Mark +Static 0x1F59 +627 838 6 + +# Mass Dispel +Static 0x1F62 +627 835 6 + +# rock +Static 0x3426 +469 1280 -4 +470 1281 -4 + +# rock +Static 0x3427 +470 1280 -5 + +# rock +Static 0x3429 +469 1281 -4 diff --git a/Data/Decoration/Ilshenar/_blood.cfg b/Data/Decoration/Ilshenar/_blood.cfg new file mode 100644 index 0000000..0e98f0b --- /dev/null +++ b/Data/Decoration/Ilshenar/_blood.cfg @@ -0,0 +1,58 @@ +# stone pavers +Static 0x0521 (Hue=0x1) +1745 1236 -30 +1746 1236 -30 +1747 1236 -30 +1748 1236 -30 + +# studded gloves +Static 0x13D5 +2057 937 -28 + +# metal chest +MetalGoldenChest 0x0E40 +2051 932 -23 +2051 933 -23 +2153 907 -23 +2153 917 -23 +2177 932 -23 +2051 931 -23 +2075 906 -23 +2075 907 -23 +2075 908 -23 +2075 917 -23 +2075 918 -23 +2075 919 -23 +2153 906 -23 +2153 908 -23 +2153 918 -23 +2153 919 -23 +2177 931 -23 +2177 933 -23 + +# bones +Static 0x0ED2 +2110 903 -28 + +# barred metal door +BarredMetalDoor2 0x1FF7 (Facing=NorthCCW) +2046 835 -28 +2046 841 -28 + +# barred metal door +BarredMetalDoor2 0x1FEF (Facing=EastCCW) +2048 832 -28 +2052 832 -28 +2056 832 -28 +2172 832 -28 +2176 832 -28 +2180 832 -28 +2184 832 -28 + +# stone stairs +Static 0x0789 (Hue=0x96C) +2112 829 -13 +2113 829 -13 +2114 829 -13 +2115 829 -13 +2116 829 -13 diff --git a/Data/Decoration/Ilshenar/_central.cfg b/Data/Decoration/Ilshenar/_central.cfg new file mode 100644 index 0000000..d112c34 --- /dev/null +++ b/Data/Decoration/Ilshenar/_central.cfg @@ -0,0 +1,329 @@ +# bookcase +FullBookcase 0x0A97 +85 1464 -28 +86 1464 -28 +89 1464 -28 +90 1464 -28 +93 1464 -28 +56 1440 -28 +56 1464 -28 +58 1467 -28 +58 1470 -28 +59 1464 -28 +61 1464 -28 +61 1467 -28 +61 1470 -28 +64 1464 -28 +65 1470 -28 +66 1464 -28 +68 1467 -28 +68 1470 -28 +69 1464 -28 +80 1464 -28 +81 1464 -28 +84 1464 -28 + +# whip +Static 0x166E +98 1528 -22 +103 1530 -22 + +# bushel +Basket 0x09AC +98 1532 -28 + +# whip +Static 0x166F +100 1528 -22 + +# cleaver +Static 0x0EC3 +101 1528 -22 + +# butcher knife +Static 0x13F6 +102 1528 -23 + +# bookcase +FullBookcase 0x0A9A +56 1447 -28 +56 1467 -28 +56 1470 -28 +56 1473 -28 +56 1476 -28 +65 1473 -28 +65 1476 -28 +68 1473 -28 +68 1476 -28 + +# bookcase +FullBookcase 0x0A9C +56 1448 -28 +56 1469 -28 +56 1471 -28 +56 1475 -28 +56 1477 -28 +56 1479 -28 +56 1481 -28 +65 1475 -28 +65 1477 -28 +68 1475 -28 +68 1477 -28 + +# barred metal door +BarredMetalDoor 0x0693 (Facing=NorthCW) +15 1315 -28 +15 1291 -28 +15 1299 -28 +15 1307 -28 +55 1331 -28 +55 1339 -28 +127 1523 -28 +127 1531 -28 +127 1539 -28 +127 1547 -28 + +# barred metal door +BarredMetalDoor 0x0689 (Facing=WestCCW) +35 1311 -28 +67 1311 -28 +67 1527 -28 +67 1551 -28 +75 1311 -28 +75 1527 -28 +75 1551 -28 +139 1527 -28 +147 1527 -28 +155 1527 -28 +163 1527 -28 +171 1527 -28 + +# barred metal door +BarredMetalDoor 0x0685 (Facing=WestCW) +43 1303 -28 +59 1263 -28 +67 1263 -28 +67 1303 -28 +67 1543 -28 +75 1263 -28 +75 1303 -28 +75 1543 -28 +147 1519 -28 +155 1519 -28 +163 1519 -28 +171 1519 -28 +35 1303 -28 + +# bucket +Static 0x14E0 +139 1563 -23 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +41 1412 -28 +39 1356 -28 +51 1492 -28 +111 1522 -28 + +# sledge hammer +Static 0x0FB4 +24 1406 -20 +24 1411 -22 + +# large battle axe +Static 0x13FB +25 1406 -28 + +# candle +Static 0x0A0F +31 1404 -28 +29 1421 -22 +32 1406 -28 +32 1416 -22 + +# plate helm +Static 0x1412 +24 1412 -22 + +# platemail gloves +Static 0x1418 +24 1413 -22 + +# heavy crossbow +Static 0x13FC +28 1417 -22 + +# barrel +Static 0x0FAE +32 1352 -28 +32 1352 -22 +32 1353 -28 +32 1354 -22 +32 1357 -28 +33 1352 -28 +34 1352 -28 +35 1352 -28 +36 1357 -28 +37 1357 -28 +37 1357 -22 +32 1353 -22 +32 1355 -28 +65 1352 -28 +67 1352 -28 +68 1352 -28 +69 1352 -28 +32 1354 -28 +34 1355 -28 +64 1352 -28 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +39 1355 -28 +41 1411 -28 +51 1491 -28 +111 1521 -28 + +# wooden door +StrongWoodDoor 0x06E9 (Facing=WestCCW) +35 1451 -28 +59 1499 -28 +115 1499 -28 +51 1349 -28 + +# wooden door +StrongWoodDoor 0x06EB (Facing=EastCW) +36 1451 -28 +60 1499 -28 +116 1499 -28 +52 1349 -28 + +# crate +MediumCrate 0x0E3F +36 1352 -27 +36 1352 -30 + +# crate +SmallCrate 0x0E7E +36 1353 -30 +32 1356 -30 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +51 1385 -28 +59 1483 -28 +83 1483 -28 +107 1487 -28 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +52 1385 -28 +60 1483 -28 +84 1483 -28 +108 1487 -28 + +# barred metal door +BarredMetalDoor 0x068D (Facing=SouthCW) +55 1515 -28 +55 1523 -28 +95 1291 -28 +95 1299 -28 +95 1307 -28 +95 1315 -28 +111 1539 -28 +111 1547 -28 + +# wooden door +StrongWoodDoor 0x06F3 (Facing=NorthCW) +63 1292 -28 +63 1355 -28 +57 1411 -28 +127 1563 -28 +55 1443 -28 + +# wooden door +StrongWoodDoor 0x06F1 (Facing=SouthCCW) +63 1293 -28 +63 1356 -28 +57 1412 -28 +127 1564 -28 +55 1444 -28 + +# metal door +MetalDoor 0x0675 (Hue=0x8AB; Facing=WestCW) +83 1384 -28 + +# metal door +MetalDoor 0x0677 (Hue=0x8AB; Facing=EastCCW) +84 1384 -28 + +# metal door +MetalDoor 0x0679 (Hue=0x58B; Facing=WestCCW) +83 1436 -28 +99 1421 -28 + +# metal door +MetalDoor 0x067B (Hue=0x58B; Facing=EastCW) +84 1436 -28 +100 1421 -28 + +# metal door +MetalDoor 0x0683 (Hue=0x58B; Facing=NorthCW) +89 1411 -28 + +# metal door +MetalDoor 0x0681 (Hue=0x58B; Facing=SouthCCW) +89 1412 -28 + +# bookcase +FullBookcase 0x0A99 +56 1446 -28 +56 1468 -28 +56 1472 -28 +56 1474 -28 +56 1478 -28 +56 1480 -28 +56 1482 -28 +65 1474 -28 +68 1474 -28 + +# bookcase +FullBookcase 0x0A98 +57 1440 -28 +57 1464 -28 +59 1467 -28 +59 1470 -28 +60 1464 -28 +62 1464 -28 +62 1467 -28 +65 1464 -28 +66 1467 -28 +66 1470 -28 +67 1464 -28 +69 1467 -28 +69 1470 -28 + +# bookcase +FullBookcase 0x0A9B +58 1440 -28 +58 1464 -28 +60 1467 -28 +60 1470 -28 +63 1464 -28 +70 1440 -28 +67 1467 -28 +67 1470 -28 +68 1464 -28 + +# cleaver +Static 0x0EC2 +10 1368 -22 + +# small crate +SmallCrate 0x09A9 +64 1353 -28 + +# crate +LargeCrate 0x0E3D +64 1354 -28 +64 1354 -25 +64 1354 -22 diff --git a/Data/Decoration/Ilshenar/_exodus.cfg b/Data/Decoration/Ilshenar/_exodus.cfg new file mode 100644 index 0000000..be59113 --- /dev/null +++ b/Data/Decoration/Ilshenar/_exodus.cfg @@ -0,0 +1,1155 @@ +# marble wall +Static 0x011A (Hue=0x66D;Name=power level indicator) +2001 57 -5 +1935 26 -5 +2000 153 -5 +1985 71 -9 +1985 71 -6 +1857 116 -2 +1985 167 -6 +1934 26 -5 +1934 203 -13 +1985 167 -9 + +# hanging pole +Static 0x10B0 (Hue=0x44E;Name=metal piping) +2002 56 -8 +2002 56 -5 +1859 105 -31 +2001 152 -5 +2001 152 -8 +2037 80 -28 +2037 80 -31 +2037 80 -34 +2037 136 -28 +2037 136 -31 +2037 136 -34 +2049 80 -28 +2049 80 -31 +2051 80 -36 +2051 80 -29 +2050 136 -28 +2050 136 -30 +2052 136 -35 +2052 136 -33 +2049 80 -34 +1846 105 -28 +1848 105 -36 +1848 105 -33 +1859 105 -28 +1848 105 -30 +1925 25 -30 +1925 25 -28 +1926 25 -30 +1926 25 -28 +1861 105 -36 +1861 105 -33 +1936 25 -30 +1936 25 -28 +1937 25 -30 +1937 25 -28 +1846 105 -31 +1861 105 -30 + +# marble wall +Static 0x010D (Hue=0x48;Name=power level indicator) +1935 26 -15 +1985 68 -15 +1985 69 -15 +1985 69 -12 +1985 70 -15 +1985 164 -15 +1857 116 -9 +1985 165 -15 +1985 165 -12 +1985 166 -15 +1933 26 -12 +1934 26 -15 + +# lava +Static 0x1A47 (Hue=0x6;Name=pure energy) +1942 26 -24 +1944 26 -24 +1946 26 -24 +1916 26 -24 +1918 26 -24 +1920 26 -24 + +# target +Static 0x1ED3 (Name=generator panel) +1942 28 -37 +1944 28 -37 +1946 28 -37 +1949 28 -35 +1913 28 -35 +1916 28 -37 +1918 28 -37 +1920 28 -37 + +# target +Static 0x1ED3 (Name=repair station panel) +1968 35 -36 +1968 35 -14 +1973 35 -14 +1973 35 -36 +1976 187 -14 +1976 187 -36 +1981 187 -14 +1981 187 -36 +1985 35 -19 +1990 35 -19 + +# target +Static 0x1ED3 (Name=a metal grille) +1971 90 -33 +1972 90 -33 + +# marble wall +Static 0x010B (Hue=0x1;Name=a polished viewing crystal) +2003 57 -11 +2004 57 -11 +2002 153 -11 +2003 153 -11 +1930 26 -13 +1931 26 -13 + +# edging +Static 0x08CC (Hue=0x452;Name=metal piping) +1940 56 -8 +2026 40 -8 +1942 57 -8 +2068 191 -8 +1983 153 -8 +1912 195 -8 +1912 196 -8 +1912 197 -8 +1912 198 -8 +1912 200 -8 +1912 201 -8 +1912 202 -8 +1921 24 -8 +1919 175 -8 +1921 175 -8 +1912 199 -8 +1911 203 -8 +1941 24 -8 + +# lava +Static 0x1A4C (Hue=0x6;Name=pure energy) +2002 88 -23 +2002 120 -23 +1938 104 -23 +1939 184 -23 +2038 64 -23 +2051 40 -23 +1956 88 -23 +1956 120 -23 +2051 104 -23 +2052 184 -23 +1988 56 -23 +1883 88 -24 +1891 88 -24 +1893 152 -23 + +# marble wall +Static 0x011A (Hue=0x48;Name=power level indicator) +2000 153 -11 +2000 153 -8 +1985 71 -15 +1985 71 -12 +1928 26 -15 +1933 26 -15 +1934 203 -16 +1934 206 -16 +1934 206 -13 +1985 167 -12 +1985 167 -15 +2001 57 -11 +2001 57 -8 + +# edging +Static 0x08CE (Hue=0x44E;Name=metal piping) +2004 151 -8 +2005 153 -8 +2006 153 -8 +2007 151 -8 +2007 153 -8 +2024 68 -8 +2025 68 -8 +2024 111 -8 +2025 111 -8 +2026 111 -8 +2027 111 -8 +2029 111 -8 +2030 111 -8 +2026 119 -8 +2027 119 -8 +2028 115 -8 +1935 119 -8 +1936 115 -8 +1936 116 -8 +1937 115 -8 +1937 116 -8 +1938 115 -8 +1939 116 -8 +1940 116 -8 +1941 116 -8 +1942 116 -8 +1942 117 -8 +1943 116 -8 +1943 117 -8 +1944 159 -8 +2037 159 -8 +2038 159 -8 +2040 159 -8 +2041 159 -8 +2042 159 -8 +2043 159 -8 +2044 159 -8 +2045 159 -8 +2046 159 -8 +1946 162 -8 +1960 45 -8 +1961 45 -8 +1962 45 -8 +1960 50 -8 +1960 51 -7 +1960 52 -8 +1961 50 -8 +1961 52 -8 +1962 50 -8 +1963 52 -8 +1964 52 -8 +1965 52 -8 +1966 52 -8 +2047 159 -8 +2048 159 -8 +2066 39 -8 +2067 39 -8 +2068 43 -8 +2069 43 -8 +2070 43 -8 +2071 43 -8 +2078 122 -8 +1967 52 -8 +1967 53 -8 +2079 122 -8 +1923 57 -8 +1926 55 -8 +1920 58 -8 +1921 58 -8 +1922 58 -8 +1923 58 -8 +1924 58 -8 +1932 119 -8 +1933 119 -8 +1934 119 -8 + +# edging +Static 0x08CC (Hue=0x44E;Name=metal piping) +2004 152 -8 +2004 153 -8 +2006 152 -8 +2006 153 -8 +2007 154 -8 +2007 155 -8 +2023 62 -8 +2023 63 -8 +2023 64 -8 +2023 65 -8 +2023 66 -8 +2023 67 -8 +2023 68 -8 +2024 69 -8 +2024 70 -8 +2025 69 -8 +2025 70 -8 +2025 71 -8 +2023 109 -8 +2023 110 -8 +2023 111 -8 +2023 112 -8 +2027 112 -8 +2027 113 -8 +2028 112 -8 +2027 114 -8 +2027 115 -8 +2028 116 -8 +2028 117 -8 +2028 118 -8 +1935 110 -8 +1935 111 -8 +1935 112 -8 +1935 113 -8 +1935 114 -8 +1935 115 -8 +1935 116 -8 +1935 117 -8 +1935 118 -8 +1935 119 -8 +1941 117 -8 +1943 158 -8 +1943 159 -8 +1944 160 -8 +1944 161 -8 +1946 160 -8 +1946 161 -8 +1944 162 -8 +1944 163 -8 +1944 164 -8 +1944 165 -8 +1944 166 -8 +2039 155 -8 +2039 156 -8 +2039 157 -8 +2039 158 -8 +1944 167 -8 +1962 40 -8 +1962 41 -8 +1963 40 -8 +1959 46 -8 +1959 47 -8 +1959 48 -8 +1959 49 -8 +1963 42 -8 +1963 43 -8 +1963 44 -8 +1959 50 -8 +1960 51 -7 +1962 51 -8 +1966 53 -8 +2067 40 -8 +2067 41 -8 +2068 40 -8 +2067 42 -8 +2067 43 -8 +1946 162 -8 +2077 121 -8 +2077 122 -8 +1922 56 -8 +1922 57 -8 +1925 56 -8 +1925 57 -8 +1923 58 -8 + +# lava +Static 0x1A1E (Hue=0x6;Name=pure energy) +2016 109 -23 +2032 83 -19 +2032 87 -19 +2032 91 -19 +2032 123 -23 +2032 139 -19 +2032 143 -19 +2032 147 -19 +1952 171 -23 +2064 108 -23 +1968 197 -23 +1984 60 -23 +1845 109 -24 +1845 120 -24 +1984 156 -24 +1872 108 -24 +1872 123 -24 +1888 73 -23 +1920 126 -23 + +# edging +Static 0x08CE (Hue=0x452;Name=metal piping) +2027 40 -8 +2028 40 -8 +2029 40 -8 +2031 39 -8 +1942 56 -8 +1941 56 -8 +1943 56 -8 +1943 57 -8 +2070 190 -8 +2071 190 -8 +1969 33 15 +1970 33 15 +1971 33 15 +1972 33 15 +1973 33 15 +1977 185 15 +1978 185 15 +1979 185 15 +1980 185 15 +1981 185 15 +2069 190 -8 +1984 152 -8 +1985 152 -8 +1986 152 -8 +1987 152 -8 +1914 193 4 +1912 202 -8 +1920 174 -8 +1921 174 -8 + +# edging +Static 0x08CD (Hue=0x452;Name=metal piping) +2030 40 -8 +1988 152 -8 + +# edging +Static 0x08CD (Hue=0x44E;Name=metal piping) +2024 71 -8 +2028 113 -8 +2028 119 -8 +1938 116 -8 +2039 159 -8 +1945 163 -8 +1963 41 -8 +1963 45 -8 +1962 52 -8 +2068 41 -8 +1925 58 -8 + +# blood +Static 0x122B (Hue=0x2;Name=coolant) +2024 112 -28 + +# Field of Poison +Static 0x3915 (Hue=0x6;Name=raw energy) +2031 48 -20 +2031 49 -20 +2032 180 -20 +2032 181 -20 +2043 87 -20 +2043 88 -20 +2043 143 -20 +2043 144 -20 +2060 43 -20 +2060 44 -20 +2066 179 -20 +2066 180 -20 +1855 116 -3 + +# Field of Poison +Static 0x3921 (Hue=0x6;Name=raw energy) +2031 48 -20 +2032 48 -20 +2032 180 -20 +2033 180 -20 +2043 87 -20 +2044 87 -20 +2043 143 -20 +2044 143 -20 +2060 43 -20 +2061 43 -20 +2066 179 -20 +2067 179 -20 + +# lever +Static 0x1095 +2001 57 -20 +2000 153 -20 +2003 153 -20 +2004 57 -20 + +# switch +Static 0x1091 +2002 58 -27 +2001 154 -27 +2002 154 -27 +2003 58 -27 +1924 26 -24 +1938 26 -24 + +# millstones +Static 0x188A (Hue=0x44E;Name=generator gears) +2034 81 -7 +2034 85 -7 +2034 89 -7 +2034 93 -7 +2034 137 -7 +2034 141 -7 +2034 145 -7 +2034 149 -7 + +# chest of drawers +Static 0x1E71 (Hue=0x44E;Name=a strange metal cabinet) +2036 80 -28 +2036 80 -22 +2038 80 -28 +2038 80 -22 +2036 136 -28 +2038 136 -28 +2038 136 -22 +2048 80 -28 +2048 80 -22 +2050 80 -28 +2050 80 -22 +2052 80 -28 +2052 80 -22 +2053 80 -28 +2053 80 -22 +2048 136 -28 +2048 136 -22 +2049 136 -28 +2049 136 -22 +2051 136 -28 +2051 136 -22 +2053 136 -28 +2053 136 -22 +2036 136 -22 +1845 105 -28 +1845 105 -22 +1847 105 -22 +1850 105 -28 +1850 105 -22 +1858 105 -28 +1858 105 -22 +1860 105 -28 +1860 105 -22 +1863 105 -28 +1863 105 -22 +1847 105 -28 +1849 105 -28 +1849 105 -22 +1862 105 -28 +1862 105 -22 + +# lava +Static 0x12EE (Hue=0x6;Name=pure energy) +1935 204 -22 +1936 204 -22 +1937 204 -22 +1938 204 -22 +1939 204 -22 +1940 204 -22 +1941 204 -22 +1850 115 -11 +1852 115 -11 +1851 115 -11 +1853 115 -11 +1933 204 -22 +1934 204 -22 +1849 115 -11 + +# lever +Static 0x1093 +2000 153 -20 + +# lava +Static 0x130C (Hue=0x6;Name=pure energy) +1942 204 -22 +1942 205 -22 +1942 206 -22 + +# edging +Static 0x08CE (Hue=0x453;Name=metal piping) +1943 24 -8 +1944 24 -8 +1945 24 -8 +1946 24 -8 +1947 24 -8 +1969 88 -8 +1970 88 -8 +1971 88 -8 +1972 88 -8 +1973 88 -8 +1974 90 -8 +1969 141 -8 +1970 142 -8 +1975 91 -8 +1987 88 -8 +1988 88 -8 +1989 88 -8 +1984 94 -8 +1985 90 -8 +1985 138 -8 +1915 24 -8 +1916 24 -8 +1917 24 -8 +1918 24 -8 +1919 24 -8 +1920 24 -8 +1921 24 -8 +1942 24 -8 +1984 138 -8 + +# lava +Static 0x1312 (Hue=0x6;Name=pure energy) +1944 24 -18 +1946 24 -18 +1916 24 -18 +1918 24 -18 +1920 24 -18 +1942 24 -18 + +# wooden post +Static 0x00C0 (Hue=0x44E;Name=metal pipes) +1847 105 -6 +2038 80 -7 +2038 80 -2 +2050 80 -2 +2052 80 -7 +2052 80 -2 +2053 80 -7 +2053 80 -2 +2050 80 -7 +1860 105 -6 +1860 105 -1 +1863 105 -1 +1863 105 -6 +1847 105 -1 +1850 105 -6 +1850 105 -1 + +# edging +Static 0x08CC (Hue=0x453;Name=metal piping) +1948 25 -3 +1968 88 -8 +1974 89 -8 +1973 90 -8 +1974 91 -8 +1968 142 -8 +1968 143 -8 +1969 142 -8 +1970 143 -8 +1984 88 -8 +1984 89 -8 +1986 88 -8 +1986 89 -8 +1984 90 -8 +1984 91 -8 +1984 93 -8 +1984 94 -8 +1984 141 -8 +1973 89 -8 +1985 139 -8 +1913 26 5 +1974 90 -8 + +# flour mill +Static 0x1926 (Hue=0x44E;Name= generator gears) +2033 81 -28 +2033 85 -28 +2033 89 -28 +2033 93 -28 +2033 137 -28 +2033 141 -28 +2033 145 -28 +2033 149 -28 + +# dagges +Static 0x037D (Hue=0x48;Name=power level indicator) +2033 84 -33 +2033 88 -33 +2033 92 -33 +2033 140 -33 +2033 144 -33 +2033 148 -33 + +# dagges +Static 0x037D (Hue=0x66D;Name=power level indicator) +2033 84 -30 +2033 88 -30 +2033 92 -30 +2033 140 -30 +2033 144 -30 +2033 148 -30 + +# nodraw +Static 0x2198 +1978 114 -28 +1979 117 -28 +1980 116 -28 +1980 114 -28 +1978 115 -28 +1978 116 -28 +1978 117 -28 +1979 114 -28 +1979 115 -28 +1979 116 -28 +1980 115 -28 +1980 117 -28 +1981 114 -28 +1981 115 -28 +1981 116 -28 +1981 117 -28 +827 777 -80 +828 777 -80 +829 777 -80 +827 778 -80 +828 778 -80 +829 778 -80 +827 779 -80 +828 779 -80 +829 779 -80 + +# marble wall +Static 0x0107 (Hue=0x1;Name=a shimmering cube) +1963 99 -23 +1963 129 -23 +1973 109 -23 +1973 119 -23 +1983 109 -23 +1983 119 -23 +1905 107 -23 +1905 120 -23 +1993 99 -23 +1993 129 -23 + +# marble wall +Static 0x0106 (Hue=0x1;Name=a shimmering cube) +1963 100 -23 +1963 101 -23 +1965 100 -23 +1963 130 -23 +1963 131 -23 +1965 130 -23 +1973 110 -23 +1973 111 -23 +1973 120 -23 +1973 121 -23 +1975 110 -23 +1975 120 -23 +1983 110 -23 +1983 111 -23 +1985 110 -23 +1983 120 -23 +1983 121 -23 +1985 120 -23 +1905 108 -23 +1905 109 -23 +1907 108 -23 +1905 121 -23 +1907 121 -23 +1905 122 -23 +1993 100 -23 +1993 101 -23 +1995 100 -23 +1993 130 -23 +1993 131 -23 +1995 130 -23 + +# marble wall +Static 0x0105 (Hue=0x1;Name=a shimmering cube) +1964 99 -23 +1964 101 -23 +1964 129 -23 +1965 129 -23 +1964 131 -23 +1965 99 -23 +1974 109 -23 +1974 111 -23 +1974 119 -23 +1974 121 -23 +1975 109 -23 +1975 119 -23 +1984 109 -23 +1984 111 -23 +1985 109 -23 +1984 119 -23 +1984 121 -23 +1985 119 -23 +1906 107 -23 +1906 109 -23 +1907 107 -23 +1906 120 -23 +1907 120 -23 +1906 122 -23 +1994 99 -23 +1994 101 -23 +1995 99 -23 +1994 129 -23 +1995 129 -23 +1994 131 -23 + +# marble wall +Static 0x0104 (Hue=0x1;Name=a shimmering cube) +1965 101 -23 +1965 131 -23 +1975 111 -23 +1975 121 -23 +1985 111 -23 +1985 121 -23 +1907 109 -23 +1907 122 -23 +1995 101 -23 +1995 131 -23 + +# fire column +Static 0x3709 (Hue=0x835;Name=steam) +2077 113 -23 +2073 118 -23 +2077 118 -23 +1973 141 -22 +2073 113 -23 + +# rub%ies/y% +Static 0x0F1D (Name=overseer lens) +2075 121 -21 +2075 123 -22 + +# winch +Static 0x1EAF (Hue=0x839;Name=clockwork assembly) +2074 123 -22 + +# spyglass +Static 0x14F6 (Hue=0x8AA;Name=overseer part) +2075 122 -22 +1989 34 -16 + +# quarter staff +Static 0x0E8A (Hue=0x835;Name=metal rails) +1970 33 -20 +1970 33 -15 +1970 33 -10 +1970 33 -5 +1972 33 -5 +1972 33 -10 +1972 33 -15 +1972 33 -20 +1988 33 -16 + +# dagges +Static 0x037A (Hue=0x66D;Name=status indicator) +1969 35 -15 +1969 35 -24 +1977 187 -21 +1977 187 -18 + +# dagges +Static 0x037A (Hue=0x48;Name=status indicator) +1969 35 -18 +1969 35 -21 +1969 35 -27 +1977 187 -27 +1977 187 -24 +1977 187 -15 + +# magical crystal +Static 0x1F1A (Hue=0x835) +1872 112 -8 +1872 119 -8 +1873 112 -8 +1873 119 -8 +1875 112 -8 +1875 119 -8 +1876 112 -8 +1876 119 -8 +1878 112 -8 +1878 119 -8 +1879 112 -8 +1879 119 -8 + +# edging +Static 0x08CD (Hue=0x453;Name=metal piping) +1974 88 -8 +1990 88 -8 +1984 92 -8 +1986 90 -8 +1984 142 -8 +1985 140 -8 +1985 141 -8 + +# quarter staff +Static 0x0E8A (Hue=0x452;Name=metal rails) +1978 185 -20 +1978 185 -15 +1978 185 -10 +1978 185 -5 +1980 185 -20 +1980 185 -15 +1980 185 -10 +1980 185 -5 + +# spyglass +Static 0x14F5 (Hue=0x8AA;Name=overseer part) +1985 35 -16 + +# magical crystal +Static 0x1F1C (Name=magical power crystal) +1986 34 -16 +2074 121 -22 + +# hanging pole +Static 0x10AD (Hue=0x44E;Name=metal pipes) +1984 62 -8 +1984 62 -6 +1984 62 -31 +1984 62 -29 +1984 62 -27 +1984 63 -8 +1984 63 -6 +1984 63 -31 +1984 63 -29 +1984 63 -27 +1984 72 -30 +1984 72 -28 +1984 72 -23 +1984 73 -30 +1984 73 -28 +1984 73 -23 +1984 75 -30 +1984 75 -28 +1984 75 -26 +1984 75 -24 +1984 158 -31 +1984 158 -27 +1984 158 -29 +1984 159 -31 +1984 159 -27 +1984 159 -29 +1984 159 -6 +1984 159 -8 +1984 168 -23 +1984 168 -28 +1984 168 -30 +1984 169 -23 +1984 169 -28 +1984 169 -30 +1984 158 -8 +1984 158 -6 +1984 171 -30 +1984 171 -28 +1984 171 -26 +1984 171 -24 + +# marble wall +Static 0x010C (Hue=0x1;Name=a polished viewing crystal) +1985 66 -13 +1985 67 -13 +1985 162 -13 +1985 163 -13 + +# marble wall +Static 0x010D (Hue=0x66D;Name=power level indicator) +1985 68 -12 +1985 70 -12 +1985 164 -12 +1985 166 -12 +1928 26 -12 + +# book +DrakovsJournal 0x0FF2 +2074 107 -22 + +# Worldgem bit +Static 0x1EA7 (Name=an arcane gem) +2075 121 -22 + +# lava +Static 0x12EF (Hue=0x6;Name=pure energy) +1851 115 -17 +1852 115 -17 +1850 115 -17 +1849 115 -17 + +# lava +Static 0x1307 (Hue=0x6;Name=pure energy) +1855 109 -17 +1855 110 -17 +1855 111 -17 +1855 112 -17 +1855 116 -17 +1855 117 -17 +1855 118 -17 +1855 119 -17 +1855 120 -17 +1855 121 -17 + +# lava +Static 0x1306 (Hue=0x6;Name=pure energy) +1855 111 -11 +1855 112 -11 +1855 113 -11 +1855 116 -11 +1855 117 -11 +1855 118 -11 +1855 119 -11 +1855 120 -11 +1855 121 -11 +1855 109 -11 +1855 110 -11 + +# target +Static 0x1ED6 (Name=generator panel) +1916 193 -36 + +# target +Static 0x1ED6 (Name=a metal grille) +1916 196 -38 +1916 198 -38 +1916 200 -38 + +# lava +Static 0x1A43 (Hue=0x6;Name=pure energy) +1912 198 -18 +1912 200 -18 +1931 203 -13 +1931 204 -13 +1931 205 -13 +1931 205 -14 +1932 203 -13 +1932 204 -13 +1932 205 -13 +1912 196 -18 + +# lava +Static 0x1A19 (Hue=0x6;Name=pure energy) +1914 196 -24 +1914 198 -24 +1914 200 -24 + +# hanging pole +Static 0x10B0 (Hue=0x452;Name=metal pipes) +1927 207 -17 +1928 206 -31 +1928 206 -28 +1929 206 -31 +1929 206 -28 + +# Field of Poison +Static 0x3920 (Hue=0x6;Name=raw energy) +1856 115 -3 + +# Bardic Guild +Static 0xBDB (Hue=0x835;Name=repair station control panel) +1942 57 -30 +1983 35 -30 +1976 35 -30 +1985 153 -31 +1984 187 -30 +1854 105 -30 +1852 105 -30 + +# Bardic Guild +Static 0xBDB (Hue=0x835;Name=control panel) +2028 41 -30 + +# Traders' Guild +Static 0xBE1 (Hue=0x1;Name=a polished viewing crystal) +1983 35 -21 +1976 35 -21 +1984 187 -21 + +# Warriors' Guild +Static 0xC03 (Hue=0x835;Name=a control panel) +1854 105 -24 + +# Assassins' Guild +Static 0xBFF (Hue=0x835;Name=a control panel) +1852 105 -24 + + +########### +# Outside # +########### + +# power generator +Spawner 0x1F13 (Spawn=PowerGenerator; Count=1; HomeRange=0) +851 801 -60 +806 801 -60 +851 756 -60 +806 756 -60 + +# Bardic Guild +Static 0x0BDC (Hue=0x835;Name=a control panel) +820 778 -57 +824 777 -40 +830 778 -60 + +# wooden banister +Static 0x08BD (Hue=0x44E;Name=metal pipes) +824 775 -40 + +# wooden banister +Static 0x08B9 (Hue=0x44E;Name=metal pipes) +829 779 -60 +826 773 -40 +826 773 -31 +828 773 -30 +826 779 -60 +826 779 -51 +828 779 -50 + +# Assassins' Guild +Static 0x0BFF (Hue=0x835;Name=a control panel) +829 780 -60 +829 774 -40 + +# wooden banister +Static 0x08C0 (Hue=0x44E;Name=metal pipes) +824 775 -40 +825 774 -32 +824 775 -33 +824 778 -33 +824 780 -31 +824 780 -40 +828 770 -56 +828 770 -50 +829 770 -56 +829 770 -50 +830 774 -40 +831 774 -40 +831 774 -32 +830 777 -50 +830 777 -60 +830 779 -49 +830 780 -59 + +# wooden banister +Static 0x08BF (Hue=0x44E;Name=metal pipes) +824 775 -32 +824 776 -40 +824 778 -40 +824 780 -40 +830 777 -49 + +# wooden banister +Static 0x08BE (Hue=0x44E;Name=metal pipes) +825 774 -40 +827 774 -40 +827 774 -33 +829 770 -55 +827 780 -53 +827 780 -60 + +# switch +Static 0x108F +820 777 -50 +820 779 -50 +830 779 -58 +830 778 -59 + +# Assassins' Guild +Static 0x0C00 (Hue=0x835;Name=a control panel) +820 779 -57 + +# Miners' Guild +Static 0x0BEE (Hue=0x835;Name=a control panel) +824 779 -39 + +# Bardic Guild +Static 0x0BDB (Hue=0x835;Name=a control panel) +828 774 -40 +828 780 -60 + +# target +Static 0x1ED3 (Name=a metal grille) +828 774 -37 +828 780 -57 + +# wooden banister +Static 0x08BA (Hue=0x44E;Name=metal pipes) +829 773 -34 +829 779 -54 + +# dart trap +Static 0x1130 (Name=a strange device) +830 777 -55 +830 777 -58 + +# hanging pole +Static 0x10AD (Hue=0x44E;Name=metal pipes) +830 778 -55 +830 778 -52 +830 779 -57 + +# brass sign +Static 0x0BD2 (Hue=0x835;Name=a control panel) +830 779 -60 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/_gwenno.cfg b/Data/Decoration/Ilshenar/_gwenno.cfg new file mode 100644 index 0000000..76d102d --- /dev/null +++ b/Data/Decoration/Ilshenar/_gwenno.cfg @@ -0,0 +1,62 @@ +# no draw +Static 0x21A4 +752 492 -64 +757 493 -64 +753 492 -64 +755 492 -64 +756 492 -64 +757 492 -64 +752 493 -64 +757 490 -64 +753 493 -64 +754 493 -64 +755 493 -64 +752 491 -64 +754 491 -64 +755 490 -64 +753 491 -64 +756 490 -64 +752 489 -64 +753 489 -64 +756 493 -64 +755 489 -64 +756 489 -64 +757 489 -64 +754 489 -64 +755 491 -64 +752 490 -64 +754 490 -64 +756 491 -64 +753 490 -64 +757 491 -64 +754 492 -64 + +# memorial to Gwenno +Static 0x1185 (Name=In loving memory of Gwenno - You were my muse: I am your legacy.) +753 493 -64 + +# memorial to Gwenno +Static 0x1186 (Name=In loving memory of Gwenno - You were my muse: I am your legacy.) +755 493 -64 + +# memorial to Gwenno +Static 0x1187 (Name=In loving memory of Gwenno - You were my muse: I am your legacy.) +756 492 -64 + +# rock +Static 0x1772 +745 488 -66 +746 488 -66 + +# rock +Static 0x1771 +745 489 -66 +746 489 -66 + +# memorial to Gwenno +Static 0x1189 (Name=In loving memory of Gwenno - You were my muse: I am your legacy.) +757 489 -64 + +# memorial to Gwenno +Static 0x1188 (Name=In loving memory of Gwenno - You were my muse: I am your legacy.) +757 491 -64 diff --git a/Data/Decoration/Ilshenar/_ratcave.cfg b/Data/Decoration/Ilshenar/_ratcave.cfg new file mode 100644 index 0000000..f861569 --- /dev/null +++ b/Data/Decoration/Ilshenar/_ratcave.cfg @@ -0,0 +1,71 @@ +# crate +MediumCrate 0x0E3E +1307 1568 0 +1307 1528 -25 + +# crate +LargeCrate 0x0E3C +1307 1568 -3 +1308 1569 -3 +1307 1527 -28 +1307 1528 -28 +1308 1528 -28 + +# crate +SmallCrate 0x0E7E +1308 1568 -3 +1308 1528 -25 + +# small crate +SmallCrate 0x09A9 +1308 1569 0 + +# iron ore +Static 0x19B7 +1284 1538 -3 + +# metal chest +MetalGoldenChest 0x0E40 +1165 1513 -68 +1170 1508 -68 + +# metal chest +MetalChest 0x09AB +1173 1504 -68 + +# wooden chest +WoodenChest 0x0E42 +1169 1516 -68 + +# metal chest +MetalGoldenChest 0x0E41 +1171 1518 -68 + +# crumbling floor +Static 0x11C5 +1183 1477 -36 +1188 1504 -62 +1198 1473 -23 +1199 1513 -44 +1197 1546 -26 +1200 1530 -25 +1208 1502 -28 +1219 1517 -25 +1231 1529 -25 +1232 1472 -22 +1244 1474 -22 +1241 1504 -25 + +# crate +MediumCrate 0x0E3F +1281 1494 15 +1307 1527 -25 +1309 1528 -28 + +# crate +LargeCrate 0x0E3D +1281 1494 12 + +# wooden chest +WoodenChest 0x0E43 +1283 1492 12 diff --git a/Data/Decoration/Ilshenar/_regvolom.cfg b/Data/Decoration/Ilshenar/_regvolom.cfg new file mode 100644 index 0000000..537db62 --- /dev/null +++ b/Data/Decoration/Ilshenar/_regvolom.cfg @@ -0,0 +1,21 @@ +# metal box +MetalBox 0x09A8 (Hue=0x96E) +1349 1030 -5 + +# marble floor +Static 0x0511 (Hue=0x1) +1362 1031 -13 +1363 1031 -13 +1364 1031 -13 + +# bottle +Static 0x0F00 +1378 1049 -12 + +# sandstone stairs +Static 0x076F (Hue=0x961) +1980 1107 -18 +1981 1107 -18 +1982 1107 -18 +1983 1107 -18 +1984 1107 -18 diff --git a/Data/Decoration/Ilshenar/_serpentine.cfg b/Data/Decoration/Ilshenar/_serpentine.cfg new file mode 100644 index 0000000..c8e6e8f --- /dev/null +++ b/Data/Decoration/Ilshenar/_serpentine.cfg @@ -0,0 +1,28 @@ +# lute +Static 0x0EB3 +426 1557 -23 + +# lap harp +Static 0x0EB2 +426 1558 -23 + +# tambourine +Static 0x0E9E +427 1560 -23 + +# standing harp +Static 0x0EB1 +434 1557 -22 +436 1557 -22 + +# metal door +MetalDoor 0x0675 (Hue=0x8AB; Facing=WestCW) +478 1527 -27 + +# metal door +MetalDoor 0x0677 (Hue=0x8AB; Facing=EastCCW) +479 1527 -27 + +# drum +Static 0x0E9C +427 1557 -23 diff --git a/Data/Decoration/Ilshenar/_sheepfarm.cfg b/Data/Decoration/Ilshenar/_sheepfarm.cfg new file mode 100644 index 0000000..d3fde53 --- /dev/null +++ b/Data/Decoration/Ilshenar/_sheepfarm.cfg @@ -0,0 +1,31 @@ +# wooden gate +DarkWoodGate 0x086E (Facing=SouthCW) +1311 1325 -14 + +# wooden gate +DarkWoodGate 0x086C (Facing=EastCW) +1328 1321 -14 + +# upright loom +LoomEastAddon 0x1060 +1305 1319 -14 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +1306 1316 -14 + +# chest of drawers +Drawer 0x0A2C +1308 1314 6 + +# scissors +Scissors 0x0F9E +1309 1319 -10 + +# dyeing tub +DyeTub 0x0FAB (Hue=0x15C) +1311 1319 -14 + +# upright loom +Static 0x105F +1305 1320 -14 diff --git a/Data/Decoration/Ilshenar/_sorcerers.cfg b/Data/Decoration/Ilshenar/_sorcerers.cfg new file mode 100644 index 0000000..2beae9c --- /dev/null +++ b/Data/Decoration/Ilshenar/_sorcerers.cfg @@ -0,0 +1,344 @@ +# bookcase +FullBookcase 0x0A9B +250 88 -28 +253 88 -28 +259 69 -28 +265 69 -28 +267 69 -28 +269 69 -28 +273 69 -28 +444 9 -28 +448 9 -28 +99 36 -28 +101 36 -28 +108 36 -28 +110 36 -28 +114 36 -28 + +# bookcase +FullBookcase 0x0A97 +251 88 -28 +260 69 -28 +263 69 -28 +268 69 -28 +272 69 -28 +449 9 -28 +442 9 -28 +106 36 -28 +113 36 -28 +109 36 -28 + +# bookcase +FullBookcase 0x0A9C +257 70 -28 +257 78 -28 +261 76 -28 +269 56 -28 +270 96 -28 +261 78 -28 +261 74 -28 +270 98 -28 +247 92 -28 +247 94 -28 +247 98 -28 +247 99 -28 + +# bookcase +FullBookcase 0x0A9A +257 71 -28 +261 73 -28 +261 75 -28 +270 95 -28 +247 93 -28 +247 97 -28 + +# bookcase +FullBookcase 0x0A98 +258 69 -28 +261 69 -28 +264 69 -28 +266 69 -28 +271 69 -28 +274 69 -28 +450 9 -28 +443 9 -28 +100 36 -28 +447 9 -28 +107 36 -28 +248 88 -28 + +# bookcase +FullBookcase 0x0A99 +257 77 -28 +261 72 -28 +261 77 -28 +261 79 -28 +269 57 -28 +442 15 -28 +270 94 -28 +270 97 -28 +442 12 -28 +442 13 -28 +442 14 -28 +247 89 -28 +247 90 -28 +247 95 -28 + +# stone stairs +Static 0x0753 (Hue=0x835) +266 129 -38 +267 129 -38 +268 129 -38 +284 66 -38 +285 66 -38 +287 66 -38 +285 73 -18 +287 73 -18 +132 129 -18 +134 129 -18 +265 129 -38 +286 66 -38 +284 73 -18 +286 73 -18 +131 129 -18 +133 129 -18 + +# magical crystal +Static 0x1F19 +279 6 -22 +279 34 -22 +248 70 -22 +249 70 -22 +250 70 -22 + +# stone stairs +Static 0x0753 (Hue=0x848) +273 141 -18 + +# magical crystal +Static 0x1F1C +284 6 -22 +283 34 -22 + +# platemail gloves +Static 0x1414 +217 49 -28 + +# bellows +LargeForgeEastAddon 0x1986 +299 23 -28 + +# anvil +AnvilEastAddon 0x0FAF +301 24 -28 +301 25 -28 + +# wooden stairs +Static 0x073A +359 40 -43 +359 41 -43 +359 42 -43 +155 88 -18 +155 89 -18 +155 90 -18 + +# stone stairs +Static 0x0754 +370 29 -43 +370 30 -43 +370 31 -43 +242 25 -18 +242 26 -18 +242 27 -18 + +# bone armor +Static 0x1454 +130 109 -28 + +# crate +MediumCrate 0x0E3E +394 59 -28 +394 68 -28 +394 74 -28 +400 67 -28 +400 79 -28 +461 82 -28 + +# strong box +MetalBox 0x0E80 +394 62 -28 +394 65 -28 +394 80 -28 +400 58 -28 +400 64 -28 +400 73 -28 +400 76 -28 +433 96 -22 + +# metal chest +MetalChest 0x09AB +399 62 -28 +399 71 -28 +393 72 -28 +393 78 -28 + +# pen and ink +Static 0x0FBF +423 95 -22 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +272 87 -28 +266 87 -28 + +# book +Static 0x0FBD +423 96 -22 + +# barred metal door +BarredMetalDoor2 0x1FF5 (Facing=SouthCW) +418 28 -28 +474 29 -28 +106 31 -28 +231 139 -28 +231 132 -28 +231 123 -28 +231 117 -28 + +# stone pavers +Static 0x051B +427 113 -28 + +# stone pavers +Static 0x0519 +429 113 -28 + +# metal chest +MetalGoldenChest 0x0E41 +433 92 -28 +435 92 -28 +434 92 -28 + +# crate +LargeCrate 0x0E3C +462 82 -28 +462 82 -25 +139 52 -25 +139 52 -28 +140 53 -28 +140 52 -28 + +# crate +MediumCrate 0x0E3F +462 82 -22 +140 52 -25 +140 53 -25 + +# metal chest +MetalGoldenChest 0x0E40 +129 118 -28 +136 117 -28 +129 117 -28 +136 118 -28 + +# crate +SmallCrate 0x0E7E +140 52 -22 +140 53 -22 +139 52 -22 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +267 87 -28 +273 87 -28 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +104 35 -28 +249 80 -28 + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +248 80 -28 +103 35 -28 + +# stone stairs +Static 0x0753 (Hue=0x849) +274 141 -18 + +# ring +Static 0x1F09 +136 108 -28 + +# barred metal door +BarredMetalDoor2 0x1FED (Facing=WestCW) +100 29 -28 +161 14 -27 + +# stone stairs +Static 0x0753 (Hue=0x847) +272 141 -18 + +# barred metal door +BarredMetalDoor2 0x1FEF (Facing=EastCCW) +162 14 -28 + +# barred metal door +BarredMetalDoor2 0x1FF7 (Facing=NorthCCW) +231 138 -28 +231 131 -28 +231 122 -28 +231 116 -28 + +# barred metal door +BarredMetalDoor2 0x1FFB (Facing=NorthCW) +240 138 -28 + +# barred metal door +BarredMetalDoor2 0x1FF9 (Facing=SouthCCW) +240 139 -28 + +# stone pavers +Static 0x051C +426 113 -28 +428 113 -28 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +264 95 -28 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +264 96 -28 + +# skinning knife +Static 0x0EC5 +174 41 -28 + +# iron maiden +Static 0x124B +146 7 -28 + +# death vortex +Static 0x3798 (Hue=0x455) +232 45 -28 + +# bottle +Static 0x0F04 +238 42 -22 + +# bottle +Static 0x0EFD +239 42 -22 + +# death vortex +Static 0x3798 (Hue=0x59B) +232 54 -28 + +# death vortex +Static 0x3798 (Hue=0x84A) +246 45 -28 + +# death vortex +Static 0x3798 (Hue=0x66D) +246 54 -28 diff --git a/Data/Decoration/Ilshenar/_terortskitas.cfg b/Data/Decoration/Ilshenar/_terortskitas.cfg new file mode 100644 index 0000000..ed82a81 --- /dev/null +++ b/Data/Decoration/Ilshenar/_terortskitas.cfg @@ -0,0 +1,75 @@ +# fire +Static 0x19AB +579 408 33 +580 408 33 + +# stone stairs +Static 0x0753 (Hue=0x849) +555 425 -13 + +# stone stairs +Static 0x0753 (Hue=0x84A) +556 425 -13 + +# stone stairs +Static 0x0753 (Hue=0x847) +557 425 -13 + +# magical crystal +Static 0x1F19 +570 414 47 +570 415 47 +578 409 67 +578 410 67 + +# chest of drawers +FancyDrawer 0x0A38 +572 412 41 + +# bookcase +FullBookcase 0x0A9A +576 423 41 +576 426 41 +576 429 41 +579 421 61 +579 425 61 + +# bookcase +FullBookcase 0x0A9C +576 424 41 +576 428 41 +579 422 61 +579 424 61 + +# bookcase +FullBookcase 0x0A99 +576 425 41 +576 427 41 +576 430 41 +579 423 61 +579 426 61 + +# dresser +Static 0x0A3D +577 408 41 + +# dresser +Static 0x0A3C +578 408 41 + +# cactus +Static 0x0D26 (Hue=0x847) +579 408 26 +580 408 26 + +# book +Static 0x0FBE +579 409 26 +580 409 26 + +# magical crystal +Static 0x1F1C +579 428 67 +579 429 67 +585 416 47 +586 416 47 diff --git a/Data/Decoration/Ilshenar/_twinoaks.cfg b/Data/Decoration/Ilshenar/_twinoaks.cfg new file mode 100644 index 0000000..942a439 --- /dev/null +++ b/Data/Decoration/Ilshenar/_twinoaks.cfg @@ -0,0 +1,99 @@ +# fireplace +StoneFireplaceEastAddon 0x0959 +1547 1050 -7 +1547 1050 13 + +# fireplace +StoneFireplaceSouthAddon 0x0961 +1556 1038 13 + +# crate +MediumCrate 0x0E3E +1549 1040 -1 + +# clock +Static 0x104B +1548 1051 8 + +# wooden door +DarkWoodDoor 0x06A7 (Facing=EastCCW) +1549 1048 13 +1556 1048 13 +1562 1048 13 + +# wooden door +DarkWoodDoor 0x06AB (Facing=EastCW) +1556 1043 13 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +1565 1046 -7 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +1565 1047 -7 + +# dartboard +DartBoard 0x1E2F +1547 1046 -7 + +# crate +LargeCrate 0x0E3C +1549 1040 -4 +1549 1040 -7 +1549 1051 -27 +1549 1052 -27 +1549 1052 -24 + +# dartboard w/knives +Static 0x1E33 +1547 1048 -7 + +# crate +MediumCrate 0x0E3F +1549 1049 -27 + +# chest of drawers +Drawer 0x0A34 +1553 1049 13 + +# armoire +Armoire 0x0A53 +1553 1052 13 +1560 1054 13 + +# dresser +Static 0x0A3D +1558 1038 13 + +# dresser +Static 0x0A3C +1559 1038 13 + +# armoire +FancyArmoire 0x0A4D +1561 1038 13 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +1555 1052 -21 + +# chest of drawers +Drawer 0x0A2C +1564 1049 13 + +# Tavern +LocalizedSign 0x0BC3 (LabelNumber=1016410) +1566 1049 -6 + +# water barrel +Static 0x154D +1555 1041 -7 + +# fireplace +Static 0x0960 +1555 1038 13 + +# fireplace +Static 0x095F +1556 1038 13 diff --git a/Data/Decoration/Ilshenar/camp.cfg b/Data/Decoration/Ilshenar/camp.cfg new file mode 100644 index 0000000..4c2efd4 --- /dev/null +++ b/Data/Decoration/Ilshenar/camp.cfg @@ -0,0 +1,114 @@ +# wooden gate +LightWoodGate 0x0839 (Facing=WestCW) +1234 543 -6 +1253 588 -11 + +# wooden gate +LightWoodGate 0x083B (Facing=EastCCW) +1235 543 -6 +1254 588 -11 + +# wooden gate +LightWoodGate 0x0841 (Facing=SouthCW) +1227 555 -11 + +# wooden gate +LightWoodGate 0x0843 (Facing=NorthCCW) +1227 554 -11 + +# wooden gate +DarkWoodGate 0x0872 (Facing=SouthCCW) +1229 563 -19 + +# flowstone +Static 0x08E2 +1237 582 -19 +1237 586 -19 + +# pickaxe +Static 0x0E85 +1238 580 -19 + +# pickaxe +Static 0x0E86 +1239 586 -19 + +# anvil +AnvilEastAddon 0x0FAF +1260 583 -19 + +# tapestry +Static 0x0FE3 (Hue=0x1; Name=a cave entrance) +1237 585 -22 + +# tapestry +Static 0x0FE4 (Hue=0x1; Name=a cave entrance) +1237 583 -22 + +# boulder +Static 0x1355 +1237 585 5 + +# boulder +Static 0x1356 +1237 584 5 + +# boulder +Static 0x1361 +1236 586 -6 + +# boulder +Static 0x1362 +1237 586 -6 + +# rock +Static 0x1363 +1237 582 -1 + +# rock +Static 0x1364 +1237 583 4 + +# rock +Static 0x136B +1237 583 1 + +# rocks +Static 0x136D +1237 586 1 + +# rock +Static 0x1772 +1237 583 1 + +# rock +Static 0x1773 +1237 585 0 + +# rock +Static 0x1775 +1237 585 4 +1237 586 3 + +# rock +Static 0x1777 +1236 584 -1 + +# bellows +Static 0x197A +1258 585 -19 + +# forge +Static 0x197E (Light=Circle300) +1259 585 -19 + +# forge +Static 0x1982 +1260 585 -19 + +# nodraw--surface +Static 0x2198 +1139 592 -80 +1140 592 -80 +1141 592 -80 +1142 592 -80 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/camp2.cfg b/Data/Decoration/Ilshenar/camp2.cfg new file mode 100644 index 0000000..5b9668e --- /dev/null +++ b/Data/Decoration/Ilshenar/camp2.cfg @@ -0,0 +1,23 @@ +# wooden gate +LightWoodGate 0x0839 (Facing=WestCW) +1400 433 -6 + +# wooden gate +LightWoodGate 0x083B (Facing=EastCCW) +1401 433 -6 + +# wooden gate +LightWoodGate 0x0841 (Facing=SouthCW) +1395 441 13 + +# wooden gate +LightWoodGate 0x0843 (Facing=NorthCCW) +1395 440 13 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +1390 432 -16 + +# bag +Bag 0x0E76 (Hue=0x10) +1391 439 19 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/enslavedgargs.cfg b/Data/Decoration/Ilshenar/enslavedgargs.cfg new file mode 100644 index 0000000..68f6217 --- /dev/null +++ b/Data/Decoration/Ilshenar/enslavedgargs.cfg @@ -0,0 +1,87 @@ +# stalagmites +Static 0x08E1 +707 667 -37 +709 667 -16 + +# flowstone +Static 0x08E2 +708 667 -38 + +# stalagmites +Static 0x08E4 +710 667 -10 +714 668 -29 + +# stalagmites +Static 0x08E5 +712 667 -9 + +# flowstone +Static 0x08E6 +710 667 -17 +712 667 -15 + +# flowstone +Static 0x08E8 +712 667 -38 +713 667 -37 + +# anvil +AnvilEastAddon 0x0FAF +947 413 -80 +958 421 -80 +958 422 -80 + +# forge +SmallForgeAddon 0x0FB1 +946 413 -80 + +# sledge hammer +Static 0x0FB4 +957 427 -74 + +# sledge hammer +Static 0x0FB5 +955 415 -74 + +# tapestry +Static 0x0FE1 (Hue=0x1; Name=a cave entrance) +709 667 -42 + +# tapestry +Static 0x0FE2 (Hue=0x1; Name=a cave entrance) +710 667 -42 +711 667 -42 + +# butcher knife +Static 0x13F6 +864 468 7 + +# rock +Static 0x1774 +706 668 -36 + +# rock +Static 0x1776 +711 667 -16 + +# bellows +Static 0x1992 +958 420 -80 +958 425 -80 + +# forge +Static 0x1996 +958 419 -80 +958 424 -80 + +# forge +Static 0x199A +958 418 -80 +958 423 -80 + +# nodraw +Static 0x2198 +911 451 -80 +911 452 -80 +911 453 -80 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/gargoylecity.cfg b/Data/Decoration/Ilshenar/gargoylecity.cfg new file mode 100644 index 0000000..a330b93 --- /dev/null +++ b/Data/Decoration/Ilshenar/gargoylecity.cfg @@ -0,0 +1,192 @@ +# metal door +MetalDoor 0x0675 (Facing=WestCW; Hue=0x835) +856 677 -40 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW; Hue=0x835) +853 672 -40 + +# metal door +Static 0x067B (Facing=EastCW; Hue=0x835) +856 606 -40 +859 611 -40 + +# barred metal door +BarredMetalDoor2 0x1FED (Facing=WestCW; Hue=0x835) +892 674 -40 + +# barred metal door +BarredMetalDoor2 0x1FF5 (Facing=SouthCW; Hue=0x835) +896 657 -40 +896 662 -40 +896 667 -40 + +# metal chest +MetalChest 0x09AB +848 719 0 +850 719 0 +854 607 -40 +854 607 -35 +857 670 -40 + +# metal chest +MetalGoldenChest 0x0E40 +828 725 0 +844 717 0 +852 608 -40 +852 609 -40 +852 609 -36 +852 609 -32 +852 611 -40 +852 611 -36 +852 613 -40 +852 613 -36 +852 675 -40 +852 675 -36 +852 676 -40 +852 676 -36 + +# metal chest +MetalGoldenChest 0x0E41 +832 712 0 +856 670 -40 +856 670 -36 +856 670 -32 +858 670 -40 +858 670 -36 + +# metal chest +MetalChest 0x0E7C +852 612 -40 +852 675 -32 + +# skinning knife +Static 0x0EC5 +864 583 -34 + +# anvil +AnvilSouthAddon 0x0FB0 +786 662 0 +786 671 0 +791 662 0 +791 671 0 +796 662 0 +796 671 0 + +# spinning wheel +SpinningWheelEastAddon 0x1019 +893 620 -40 +893 622 -40 +893 624 -40 + +# upright loom +LoomEastAddon 0x1060 +893 617 -40 +893 626 -40 + +# lever +Static 0x1093 +760 645 10 + +# butcher knife +Static 0x13F7 +864 582 -34 + +# platemail arms +Static 0x1417 (Hue=0x44E) +768 631 5 + +# map +Static 0x14EB +876 661 -34 + +# bellows +Static 0x1986 +786 659 0 +786 668 0 +791 659 0 +791 668 0 +796 659 0 +796 668 0 + +# forge +Static 0x198A (Light=Circle300) +786 660 0 +786 669 0 +791 660 0 +791 669 0 +796 660 0 +796 669 0 + +# forge +Static 0x198E +786 661 0 +786 670 0 +791 661 0 +791 670 0 +796 661 0 +796 670 0 + +# bellows +Static 0x1992 +786 665 0 +786 674 0 +791 665 0 +791 674 0 +796 665 0 +796 674 0 + +# forge +Static 0x1996 +786 664 0 +786 673 0 +791 664 0 +791 673 0 +796 664 0 +796 673 0 + +# forge +Static 0x199A +786 663 0 +786 672 0 +791 663 0 +791 672 0 +796 663 0 +796 672 0 + +# heater shield +Static 0x1B76 (Hue=0x44E) +766 630 6 + +# heater shield +Static 0x1B77 (Hue=0x44E) +768 630 5 + +# Bell of Courage +Static 0x1C12 +846 601 -34 +846 682 -34 + +# brain +Static 0x1CF0 (Hue=0x96E) +771 631 11 + +# table leg +Static 0x1E7D (Hue=0x451) +766 631 6 + +# barrel staves +Static 0x1EB1 (Hue=0x44E) +775 632 -1 + +# barrel staves +Static 0x1EB2 (Hue=0x44E) +773 632 -1 + +# barrel staves +Static 0x1EB3 (Hue=0x44E) +767 631 2 + +# statue +Static 0x1F18 (Hue=0x451) +767 630 6 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/golemsandjukas.cfg b/Data/Decoration/Ilshenar/golemsandjukas.cfg new file mode 100644 index 0000000..f93fb28 --- /dev/null +++ b/Data/Decoration/Ilshenar/golemsandjukas.cfg @@ -0,0 +1,135 @@ +# metal door +MetalDoor 0x067D (Facing=SouthCW) +1089 707 -80 +1094 699 -60 +1094 708 -60 +1103 704 -80 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +1089 706 -80 +1094 707 -60 +1094 698 -60 +1103 703 -80 + +# metal door +MetalDoor2 0x06CD (Facing=SouthCW) +1103 652 -80 +1111 652 -80 + +# metal door +MetalDoor2 0x06CF (Facing=NorthCCW) +1103 651 -80 +1111 651 -80 + +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +1071 671 -80 +1083 632 -60 +1083 658 -80 +1083 671 -80 +1083 671 -60 +1096 671 -80 +1097 658 -80 +1098 632 -60 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +1062 635 -80 +1062 635 -60 +1062 635 -40 +1062 667 -80 +1062 667 -60 +1062 667 -40 +1083 632 -80 +1083 645 -80 +1096 632 -80 +1097 645 -80 +1105 635 -60 +1105 668 -80 +1105 668 -60 +1105 668 -40 +1105 635 -80 + +# wooden door +StrongWoodDoor 0x06E9 (Facing=WestCCW) +1071 634 -40 +1074 669 -40 +1090 634 -40 +1092 669 -40 +1092 679 -40 + +# wooden door +StrongWoodDoor 0x06EB (Facing=EastCW) +1105 635 -40 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +1064 651 -80 + +# wooden door +StrongWoodDoor 0x06F1 (Facing=SouthCCW) +1067 630 -80 +1067 630 -60 +1067 673 -80 +1067 673 -60 +1100 630 -80 +1100 630 -60 +1100 673 -80 +1100 673 -60 +1100 673 -40 + +# wooden door +StrongWoodDoor 0x06F3 (Facing=NorthCW) +1103 643 -60 +1103 660 -60 + +# iron gate +IronGate 0x082C (Facing=SouthCW) +1064 644 -40 +1064 659 -40 +1081 644 -40 +1081 659 -40 +1086 644 -40 +1086 659 -40 +1103 644 -40 +1103 659 -40 + +# bookcase +FullBookcase 0x0A97 +1092 696 -60 + +# bookcase +FullBookcase 0x0A98 +1086 703 -80 + +# bookcase +FullBookcase 0x0A99 +1081 707 -60 +1081 708 -80 + +# bookcase +FullBookcase 0x0A9A +1081 699 -60 +1081 704 -80 + +# bookcase +FullBookcase 0x0A9B +1082 703 -80 +1088 696 -60 + +# bookcase +FullBookcase 0x0A9C +1081 706 -60 + +# khabur's journal +KaburJournal 0x0FF1 +1073 633 -74 + +# fropoz's journal +FropozJournal 0x0FF1 +1084 707 -74 + +# translated gargoyle journal +TranslatedGargoyleJournal 0x0FF2 +1089 708 -54 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/lakeshire.cfg b/Data/Decoration/Ilshenar/lakeshire.cfg new file mode 100644 index 0000000..104782e --- /dev/null +++ b/Data/Decoration/Ilshenar/lakeshire.cfg @@ -0,0 +1,477 @@ +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +1219 1158 -26 +1221 1158 -26 +1223 1158 -26 + +# wooden gate +DarkWoodGate 0x086A (Facing=WestCCW) +1219 1161 -26 +1222 1161 -26 + +# bed +Static 0x0A69 +1199 1179 -25 +1224 1136 -5 + +# bed +Static 0x0A6B (Hue=0x541) +1200 1179 -25 + +# bed +Static 0x0A6B (Hue=0x59B) +1225 1136 -5 + +# table +Static 0x0B75 +1222 1130 -25 +1222 1134 -25 +1226 1130 -25 +1226 1134 -25 + +# table +Static 0x0B76 +1222 1129 -25 +1222 1133 -25 +1226 1129 -25 +1226 1133 -25 + +# broken chair +Static 0x0C10 +1220 1123 -25 +1223 1130 -25 + +# broken chair +Static 0x0C11 +1203 1174 -25 + +# broken armoire +Static 0x0C12 +1167 1166 -25 +1218 1150 -25 + +# broken armoire +Static 0x0C13 +1224 1123 -25 +1228 1123 -5 +1230 1133 -5 + +# ruined bookcase +Static 0x0C14 +1222 1123 -25 +1228 1123 -25 + +# ruined bookcase +Static 0x0C15 +1167 1162 -25 +1167 1164 -25 +1199 1176 -25 +1218 1154 -25 +1224 1134 -5 + +# damaged books +Static 0x0C16 +1167 1163 -25 +1221 1178 -25 +1223 1124 -25 +1225 1134 -5 + +# covered chair +Static 0x0C17 +1205 1173 -25 + +# broken chair +Static 0x0C19 +1167 1160 -25 +1218 1153 -25 + +# broken chair +Static 0x0C1A +1226 1131 -25 + +# broken chair +Static 0x0C1B +1199 1173 -25 + +# broken chair +Static 0x0C1C +1221 1175 -25 + +# broken clock +Static 0x0C1F +1199 1177 -25 + +# broken dresser +Static 0x0C20 +1224 1127 -5 + +# broken dresser +Static 0x0C21 +1224 1126 -5 + +# broken dresser +Static 0x0C22 +1203 1173 -25 + +# broken dresser +Static 0x0C23 +1202 1173 -25 + +# broken furniture +Static 0x0C24 +1201 1173 -25 +1229 1123 -5 + +# broken furniture +Static 0x0C25 +1218 1174 -25 + +# ruined bed +Static 0x0C29 +1226 1123 -5 + +# ruined bed +Static 0x0C2A +1225 1124 -5 + +# ruined bed +Static 0x0C2B +1224 1125 -5 + +# debris +Static 0x0C2E +1179 1156 -25 +1221 1182 -22 +1226 1123 -25 +1226 1133 -5 + +# debris +Static 0x0C2F +1177 1151 -25 +1177 1163 -25 +1181 1156 -25 +1205 1175 -25 +1207 1177 -25 +1226 1126 -5 +1229 1136 -5 + +# debris +Static 0x0C30 +1167 1167 -25 +1199 1178 -25 +1232 1129 -25 + +# sheets +Static 0x0C33 +1223 1176 -25 + +# sheets +Static 0x0C34 +1222 1176 -25 + +# sheets +Static 0x0C35 +1223 1174 -25 +1223 1175 -25 + +# sheets +Static 0x0C36 +1222 1174 -25 +1222 1175 -25 + +# grasses +Static 0x0CAC +1208 1159 -25 + +# grasses +Static 0x0CAD +1196 1163 -25 + +# grasses +Static 0x0CAF +1208 1174 -25 + +# grasses +Static 0x0CB0 +1204 1164 -25 +1228 1157 -25 + +# grasses +Static 0x0CB1 +1218 1182 -25 +1220 1139 -25 +1225 1182 -25 +1226 1139 -25 + +# grasses +Static 0x0CB3 +1230 1150 -25 + +# grasses +Static 0x0CB5 +1214 1185 -25 +1229 1139 -25 + +# grasses +Static 0x0CB6 +1212 1169 -25 +1219 1135 -25 +1227 1183 -25 + +# vines +Static 0x0CEB +1223 1182 -25 + +# vines +Static 0x0CEC +1220 1182 -25 +1221 1182 -25 +1226 1182 -25 + +# vines +Static 0x0CED +1218 1182 -25 +1221 1173 -25 +1224 1182 -25 + +# vines +Static 0x0CEF +1227 1175 -25 + +# vines +Static 0x0CF0 +1227 1176 -25 + +# vines +Static 0x0CF1 +1227 1177 -25 + +# apple tree +Static 0x0D94 +1175 1173 -25 +1180 1177 -25 +1182 1186 -25 + +# apple tree +Static 0x0D96 +1175 1173 -25 +1180 1177 -25 +1182 1186 -25 + +# apple tree +Static 0x0D98 +1172 1179 -25 +1175 1187 -25 +1185 1182 -25 + +# apple tree +Static 0x0D9A +1172 1179 -25 +1175 1187 -25 +1185 1182 -25 + +# peach tree +Static 0x0D9C +1174 1200 -25 +1175 1192 -25 + +# peach tree +Static 0x0D9E +1174 1200 -25 +1175 1192 -25 + +# pear tree +Static 0x0DA4 +1184 1195 -25 +1186 1197 -25 +1194 1185 -25 +1194 1198 -25 + +# pear tree +Static 0x0DA6 +1184 1195 -25 +1186 1197 -25 +1194 1185 -25 +1194 1198 -25 + +# pear tree +Static 0x0DA8 +1188 1189 -25 +1194 1189 -25 + +# pear tree +Static 0x0DAA +1188 1189 -25 +1194 1189 -25 + +# spiderweb +Static 0x0EE4 +1218 1157 -25 + +# spiderweb +Static 0x0EE6 +1224 1133 -5 + +# hay +Static 0x0F34 +1219 1160 -25 +1225 1160 -25 + +# garbage +Static 0x10EE +1202 1179 -25 +1220 1133 -25 +1221 1140 -25 +1221 1177 -25 +1222 1151 -25 +1222 1160 -25 +1228 1125 -25 +1229 1152 -25 + +# garbage +Static 0x10EF +1201 1174 -25 +1220 1154 -25 +1227 1145 -25 +1228 1135 -25 + +# garbage +Static 0x10F0 +1223 1153 -25 +1224 1179 -25 +1229 1160 -25 + +# garbage +Static 0x10F1 +1220 1178 -25 +1221 1174 -25 + +# bellows +Static 0x1986 +1228 1097 -25 +1228 1106 -25 + +# forge +Static 0x198A +1228 1098 -25 +1228 1107 -25 + +# forge +Static 0x198E +1228 1099 -25 +1228 1108 -25 + +# bellows +Static 0x1992 +1229 1099 -25 +1229 1108 -25 + +# forge +Static 0x1996 +1229 1098 -25 +1229 1107 -25 + +# forge +Static 0x199A +1229 1097 -25 +1229 1106 -25 + +# leaves +Static 0x1B1F +1222 1125 -25 +1228 1132 -25 + +# leaves +Static 0x1B23 +1218 1175 -25 +1232 1124 -25 + +# leaves +Static 0x1B24 +1218 1173 -25 +1232 1123 -25 + +# wall cracks +Static 0x1B6C +1195 1160 -25 +1227 1179 -25 + +# wall cracks +Static 0x1B6D +1195 1163 -25 + +# wall cracks +Static 0x1B6E +1205 1163 -25 + +# wall cracks +Static 0x1B6F +1202 1149 -25 +1204 1163 -25 +1208 1151 -25 +1218 1176 -25 + +# refuse +Static 0x1BB0 +1196 1149 -25 + +# refuse +Static 0x1BB1 +1196 1150 -25 + +# refuse +Static 0x1BB5 +1195 1150 -25 + +# refuse +Static 0x1BB6 +1195 1149 -25 + +# broken barrel +Static 0x1DB3 +1196 1154 -25 + +# broken barrel +Static 0x1DB4 +1196 1153 -25 + +# broken barrel +Static 0x1DB5 +1195 1153 -25 + +# broken barrel +Static 0x1DB6 +1195 1154 -25 + +# mud +Static 0x1E01 +1197 1157 -25 +1207 1155 -25 + +# mud +Static 0x1E02 +1200 1162 -25 +1201 1149 -25 +1204 1179 -25 +1205 1159 -25 +1220 1150 -25 +1228 1127 -25 + +# book +Static 0x1E20 +1168 1165 -25 +1200 1177 -25 + +# books +Static 0x1E21 +1168 1162 -25 +1202 1176 -25 + +# barrel staves +Static 0x1EB2 +1195 1154 -25 + +# unfinished barrel +Static 0x1EB5 +1195 1152 -24 +1225 1157 -25 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/meercatacombs.cfg b/Data/Decoration/Ilshenar/meercatacombs.cfg new file mode 100644 index 0000000..48e1c7d --- /dev/null +++ b/Data/Decoration/Ilshenar/meercatacombs.cfg @@ -0,0 +1,309 @@ +############### +# Teleporters # +############### + +Teleporter 0x1BC3 (PointDest=(1790, 66, -26)) +1037 579 -73 + +Teleporter 0x1BC3 (PointDest=(1790, 67, -26)) +1037 580 -73 + +Teleporter 0x1BC3 (PointDest=(1790, 68, -26)) +1037 581 -73 + +Teleporter 0x1BC3 (PointDest=(1786, 70, -26)) +1038 578 -73 + +Teleporter 0x1BC3 (PointDest=(1786, 70, -26)) +1038 579 -73 + +Teleporter 0x1BC3 (PointDest=(1786, 65, -26)) +1038 581 -73 + +Teleporter 0x1BC3 (PointDest=(1786, 65, -26)) +1038 582 -73 + +Teleporter 0x1BC3 (PointDest=(1787, 70, -26)) +1039 578 -73 + +Teleporter 0x1BC3 (PointDest=(1787, 65, -26)) +1039 582 -73 + +Teleporter 0x1BC3 (PointDest=(1788, 70, -26)) +1040 578 -73 + +Teleporter 0x1BC3 (PointDest=(1788, 70, -26)) +1040 579 -73 + +Teleporter 0x1BC3 (PointDest=(1788, 65, -26)) +1040 581 -73 + +Teleporter 0x1BC3 (PointDest=(1788, 65, -26)) +1040 582 -73 + +Teleporter 0x1BC3 (PointDest=(1785, 68, -26)) +1041 581 -73 + +Teleporter 0x1BC3 (PointDest=(1785, 67, -26)) +1041 580 -73 + +Teleporter 0x1BC3 (PointDest=(1785, 66, -26)) +1041 579 -73 + + + +Teleporter 0x1BC3 (PointDest=(1038, 583, -78)) +1786 66 -26 + +Teleporter 0x1BC3 (PointDest=(1042, 579, -78)) +1786 67 -26 + +Teleporter 0x1BC3 (PointDest=(1042, 580, -78)) +1786 68 -26 + +Teleporter 0x1BC3 (PointDest=(1042, 581, -78)) +1786 69 -26 + +Teleporter 0x1BC3 (PointDest=(1039, 583, -78)) +1787 66 -26 + +Teleporter 0x1BC3 (PointDest=(1040, 583, -78)) +1788 66 -26 + +Teleporter 0x1BC3 (PointDest=(1041, 583, -78)) +1789 66 -26 + +Teleporter 0x1BC3 (PointDest=(1038, 577, -78)) +1787 69 -26 + +Teleporter 0x1BC3 (PointDest=(1039, 577, -78)) +1788 69 -26 + +Teleporter 0x1BC3 (PointDest=(1036, 579, -78)) +1789 67 -26 + +Teleporter 0x1BC3 (PointDest=(1036, 578, -78)) +1789 68 -26 + +Teleporter 0x1BC3 (PointDest=(1036, 581, -78)) +1789 69 -26 + + +############ +# Mainland # +############ + +# stone +Static 0x07A3 (Hue=0x58F) +1037 578 -80 +1037 579 -80 +1037 580 -80 +1037 581 -80 +1037 582 -80 +1038 578 -80 +1038 579 -80 +1038 580 -80 +1038 581 -80 +1038 582 -80 +1039 578 -80 +1039 579 -80 +1039 580 -80 +1039 581 -80 +1039 582 -80 +1040 578 -80 +1040 579 -80 +1040 580 -80 +1040 581 -80 +1040 582 -80 +1041 578 -80 +1041 579 -80 +1041 580 -80 +1041 581 -80 +1041 582 -80 + +# stone stairs +Static 0x07A4 (Hue=0x58F) +1037 583 -80 +1038 583 -80 +1039 583 -80 +1040 583 -80 +1041 583 -80 + +# stone stairs +Static 0x07A5 (Hue=0x58F) +1042 578 -80 +1042 579 -80 +1042 580 -80 +1042 581 -80 +1042 582 -80 + +# stone stairs +Static 0x07A6 (Hue=0x58F) +1037 577 -80 +1038 577 -80 +1039 577 -80 +1040 577 -80 +1041 577 -80 + +# stone stairs +Static 0x07A7 (Hue=0x58F) +1036 578 -80 +1036 579 -80 +1036 580 -80 +1036 581 -80 +1036 582 -80 + +# stone stairs +Static 0x07A8 (Hue=0x58F) +1036 577 -80 + +# stone stairs +Static 0x07A9 (Hue=0x58F) +1042 583 -80 + +# stone stairs +Static 0x07AA (Hue=0x58F) +1042 577 -80 + +# stone stairs +Static 0x07AB (Hue=0x58F) +1036 583 -80 + +# platform +Static 0x07BD (Hue=0x40C) +1037 580 -75 +1038 579 -75 +1038 581 -75 +1039 578 -75 +1039 580 -75 +1039 582 -75 +1040 579 -75 +1040 581 -75 +1041 580 -75 + +# platform +Static 0x07BE (Hue=0x40C) +1037 579 -75 +1037 581 -75 +1038 578 -75 +1038 580 -75 +1038 582 -75 +1039 579 -75 +1039 581 -75 +1040 578 -75 +1040 580 -75 +1040 582 -75 +1041 579 -75 +1041 581 -75 + +# platform +Static 0x07BF (Hue=0x40C) +1037 578 -75 + +# platform +Static 0x07C0 (Hue=0x40C) +1041 578 -75 + +# platform +Static 0x07C1 (Hue=0x40C) +1037 582 -75 + +# platform +Static 0x07C2 (Hue=0x40C) +1041 582 -75 + +# glowing rune +Static 0x0E5D (Hue=0x40C) +1040 578 -73 + +# rune +Static 0x0E5E (Hue=0x40C) +1037 580 -73 +1040 580 -73 + +# glowing rune +Static 0x0E60 (Hue=0x40C) +1037 579 -73 +1038 581 -73 +1039 578 -73 +1041 581 -73 + +# rune +Static 0x0E61 (Hue=0x40C) +1039 580 -73 + +# glowing rune +Static 0x0E63 (Hue=0x40C) +1038 578 -73 +1038 580 -73 +1039 582 -73 +1040 581 -73 + +# rune +Static 0x0E64 (Hue=0x40C) +1041 579 -73 + +# glowing rune +Static 0x0E66 (Hue=0x40C) +1040 582 -73 + +# rune +Static 0x0E67 (Hue=0x40C) +1037 581 -73 +1039 579 -73 +1039 581 -73 + +# glowing rune +Static 0x0E69 (Hue=0x40C) +1038 579 -73 +1038 582 -73 +1040 579 -73 +1041 580 -73 + + +########### +# Place.. # +########### + +# glowing rune +Static 0x0E5D (Hue=0x40C) +1789 69 -26 + +# rune +Static 0x0E5E (Hue=0x40C) +1788 67 -26 + +# glowing rune +Static 0x0E60 (Hue=0x40C) +1786 68 -26 +1789 68 -26 + +# rune +Static 0x0E61 (Hue=0x40C) +1787 67 -26 + +# glowing rune +Static 0x0E63 (Hue=0x40C) +1786 67 -26 +1787 69 -26 +1788 68 -26 + +# rune +Static 0x0E64 (Hue=0x40C) +1789 66 -26 + +# glowing rune +Static 0x0E66 (Hue=0x40C) +1788 69 -26 + +# rune +Static 0x0E67 (Hue=0x40C) +1787 66 -26 +1787 68 -26 + +# glowing rune +Static 0x0E69 (Hue=0x40C) +1786 66 -26 +1786 69 -26 +1788 66 -26 +1789 67 -26 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/misc.cfg b/Data/Decoration/Ilshenar/misc.cfg new file mode 100644 index 0000000..8b5d31e --- /dev/null +++ b/Data/Decoration/Ilshenar/misc.cfg @@ -0,0 +1,87 @@ +# barrel +Static 0x0FAE +387 1255 -41 +388 1255 -42 + +# a swarm of flies +SwarmOfFlies 0x091B +1052 736 -80 +1082 750 -75 +1088 759 -80 +1107 735 -80 +1138 736 -80 +1156 767 -80 +1166 690 -80 +1183 661 -80 + +# tribal berry +TribalBerry 0x09D0 +1029 679 -65 +1029 680 -48 +1029 681 -60 +1029 700 -72 +1030 679 -63 +1030 700 -50 +1030 702 -50 +1031 705 -60 +1032 712 -39 +1033 706 -30 +1033 711 -43 +1033 712 -40 +1036 715 -51 +1037 714 -61 +1037 715 -62 +1038 689 -70 +1038 689 -60 +1038 709 -56 +1038 711 -58 +1040 679 -58 +1040 680 -66 +1040 680 -43 +1041 714 -54 +1041 715 -60 +1042 680 -38 +1043 686 -51 +1043 687 -63 +1043 688 -50 +1043 699 -60 +1043 701 -60 +1043 714 -58 +1044 686 -60 +1044 686 -57 +1044 699 -60 +1051 704 -50 +1051 705 -22 +1051 706 -20 + +# fern +Static 0x0C9F +1028 713 -80 +1034 704 -79 + +# fern +Static 0x0CA0 +1028 695 -80 +1045 678 -80 + +# large fern +Static 0x0CA1 +1030 718 -80 +1046 696 -80 + +# fern +Static 0x0CA2 +1031 708 -80 +1033 676 -80 +1036 692 -80 +1044 718 -80 + +# fern +Static 0x0CA3 +1029 691 -80 +1047 684 -80 +1051 707 -80 + +# fern +Static 0x0CA4 +1038 680 -80 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/mistas.cfg b/Data/Decoration/Ilshenar/mistas.cfg new file mode 100644 index 0000000..84a0ea0 --- /dev/null +++ b/Data/Decoration/Ilshenar/mistas.cfg @@ -0,0 +1,1311 @@ +# wooden door +StrongWoodDoor 0x06E5 (Facing=WestCW) +779 1071 -30 +779 1111 -30 +796 1071 -30 +835 1071 -30 +849 1087 -10 +861 1088 -10 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +780 1071 -30 +780 1111 -30 +795 1063 -10 +797 1071 -30 +836 1071 -30 +850 1087 -10 +862 1088 -10 + +# wooden door +StrongWoodDoor 0x06ED (Facing=SouthCW) +799 1059 -10 +803 1092 -30 +803 1104 -30 +807 1067 -30 +807 1084 -30 +815 1060 -30 +847 1060 -30 +847 1096 -30 +863 1052 -30 +867 1044 -10 +867 1060 -10 + +# wooden door +StrongWoodDoor 0x06EF (Facing=NorthCCW) +803 1091 -30 +803 1103 -30 +807 1066 -30 +807 1083 -30 +815 1059 -30 +847 1059 -30 +847 1095 -30 +863 1051 -30 +867 1043 -10 +867 1059 -10 + +# wooden door +StrongWoodDoor 0x06F1 (Facing=SouthCCW) +863 1096 -30 + +# wooden door +StrongWoodDoor 0x06F3 (Facing=NorthCW) +863 1095 -30 + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +768 1156 -29 +771 1156 -30 +774 1156 -30 +777 1156 -30 + +# wooden gate +DarkWoodGate 0x086A (Facing=WestCCW) +762 1164 -30 +765 1164 -30 +768 1164 -30 +771 1164 -30 +774 1164 -30 +777 1164 -30 +780 1164 -30 + +# candelabra +CandelabraStand 0x0A29 (Unlit) +776 1056 -9 +776 1070 -9 +782 1094 -30 +790 1056 -9 +790 1088 -30 +790 1094 -30 +792 1056 -9 +792 1080 -30 +792 1094 -30 +792 1096 -30 +792 1110 -30 +798 1062 -10 +798 1064 -10 +798 1070 -10 +800 1056 -30 +800 1056 -10 +800 1070 -30 +802 1094 -30 +802 1096 -30 +802 1110 -30 +806 1070 -30 +806 1070 -10 +806 1080 -30 +806 1086 -30 +814 1056 -30 +814 1062 -30 +824 1056 -30 +824 1062 -30 +832 1063 -30 +832 1070 -30 +838 1048 -30 +838 1070 -30 +839 1056 -30 +846 1056 -30 +846 1062 -30 + +# chest of drawers +Drawer 0x0A2C +754 1131 -10 +778 1152 -9 +780 1152 -9 + +# chest of drawers +FancyDrawer 0x0A30 +766 1131 -10 + +# chest of drawers +Drawer 0x0A34 +761 1163 -9 +761 1168 -9 +768 1154 -9 +768 1155 -9 +770 1163 -9 +770 1167 -9 +777 1163 -9 +777 1167 -9 + +# dresser +Static 0x0A3C +757 1131 -10 +766 1163 -9 + +# dresser +Static 0x0A3D +756 1131 -10 +765 1163 -9 + +# dresser +Static 0x0A44 +760 1133 -10 + +# dresser +Static 0x0A45 +760 1132 -10 + +# bookcase +LibraryBookcase 0x0A97 +761 1131 -10 +764 1163 -9 +772 1152 -9 +773 1163 -10 + +# bookcase +LibraryBookcase 0x0A98 +767 1163 -10 +773 1152 -9 + +# bookcase +LibraryBookcase 0x0A99 +776 1156 -9 + +# bookcase +LibraryBookcase 0x0A9A +776 1155 -9 + +# bookcase +LibraryBookcase 0x0A9B +752 1131 -9 +771 1152 -9 +780 1163 -10 +781 1163 -10 + +# bookcase +LibraryBookcase 0x0A9C +752 1136 -10 +776 1157 -9 + +# candelabra +CandelabraStand 0x0B26 +832 1048 -30 + +# counter +Static 0x0B3D +792 1106 -30 +808 1057 -30 +808 1058 -30 +808 1061 -30 + +# counter +Static 0x0B3E +785 1088 -30 +788 1088 -30 + +# counter +Static 0x0B3F +792 1105 -30 +792 1107 -30 +808 1056 -30 +808 1062 -30 + +# counter +Static 0x0B40 +784 1088 -30 +789 1088 -30 + +# broken armoire +Static 0x0C12 +841 1082 -10 +859 1033 -30 +860 1105 -30 +860 1109 -30 + +# broken armoire +Static 0x0C13 +777 1056 -9 +778 1088 -30 +783 1056 -9 + +# ruined bookcase +Static 0x0C14 +793 1096 -30 +800 1096 -30 + +# ruined bookcase +Static 0x0C15 +776 1060 -9 +776 1063 -9 +776 1068 -9 +792 1086 -30 +841 1089 -10 +856 1041 -30 +856 1046 -30 +856 1061 -30 +856 1065 -30 +856 1069 -30 +860 1081 -30 +860 1084 -30 + +# damaged books +Static 0x0C16 +763 1041 -30 +776 1060 -10 +785 1060 -10 +793 1109 -30 +794 1096 -30 +841 1088 -10 +857 1066 -30 +861 1082 -30 +867 1043 -30 +869 1063 -30 +869 1080 -30 + +# covered chair +Static 0x0C17 +780 1088 -30 +792 1056 -30 +793 1056 -30 +794 1056 -30 +795 1056 -30 +845 1080 -10 +865 1056 -30 +867 1080 -30 + +# covered chair +Static 0x0C18 +792 1060 -30 +792 1061 -30 +792 1100 -30 +856 1042 -30 +856 1056 -30 +856 1057 -30 +860 1106 -30 + +# broken chair +Static 0x0C19 +800 1107 -30 +845 1083 -10 +865 1067 -30 +866 1094 -30 + +# broken chair +Static 0x0C1A +759 1038 -30 +783 1059 -9 +784 1091 -30 +801 1066 -10 +810 1057 -30 +831 1058 -30 +838 1034 -30 +861 1067 -9 +867 1081 -9 + +# broken chair +Static 0x0C1B +795 1056 -10 +805 1056 -30 +834 1050 -30 +862 1080 -9 +863 1032 -30 + +# broken chair +Static 0x0C1C +792 1058 -30 +792 1059 -30 +792 1102 -30 +856 1060 -9 + +# broken clock +Static 0x0C1F +776 1061 -4 +776 1098 -22 + +# broken furniture +Static 0x0C25 +856 1060 11 + +# debris +Static 0x0C2D +776 1062 -10 +776 1097 -30 +784 1056 -10 +786 1088 -30 +800 1064 -10 +829 1032 -30 +831 1056 -30 +832 1049 -30 +832 1066 -30 +836 1048 -30 +839 1062 -30 +841 1083 -10 +841 1093 -10 +847 1006 -30 +847 1080 -10 +847 1103 -10 +857 1062 -9 +860 1080 -9 +860 1082 -30 +863 1104 -30 +864 1032 -30 +864 1032 -9 +864 1103 -30 +864 1104 -30 +869 1032 -30 + +# debris +Static 0x0C2E +763 1036 -30 +776 1057 -10 +776 1096 -30 +787 1088 -30 +788 1094 -30 +796 1096 -30 +800 1062 -30 +800 1064 -10 +800 1069 -10 +806 1057 -30 +829 1032 -30 +836 1048 -30 +847 1080 -10 +847 1104 -10 +856 1044 -9 +856 1045 -9 +856 1056 11 +859 1048 11 +860 1083 -30 +861 1080 -9 +864 1032 -9 +864 1089 -30 +864 1104 -30 +869 1032 -30 + +# debris +Static 0x0C2F +761 1034 -30 +776 1088 -30 +777 1103 -30 +781 1108 -30 +782 1056 -10 +788 1065 11 +792 1088 -30 +794 1097 -30 +797 1081 -30 +809 1061 -30 +840 1056 -30 +840 1064 -30 +841 1064 -30 +841 1065 -30 +856 1057 -9 +857 1005 -30 +859 1035 -30 +860 1104 -9 +860 1107 -30 +864 1056 -9 +867 1039 -30 + +# debris +Static 0x0C30 +761 1034 -30 +763 1036 -30 +779 1089 -30 +789 1064 11 +796 1096 -30 +797 1080 -30 +798 1081 -30 +801 1056 -9 +801 1096 -30 +803 1061 -30 +806 1057 -30 +809 1061 -30 +811 1064 -30 +833 1051 -30 +840 1064 -30 +840 1065 -30 +841 1056 -30 +841 1065 -30 +856 1042 -9 +856 1045 -9 +856 1056 11 +856 1057 -9 +856 1061 11 +858 1005 -30 +859 1032 -30 +859 1048 11 +860 1105 -9 +860 1107 -30 +863 1104 -30 +864 1032 -30 +864 1056 -9 +864 1100 -9 +864 1103 -30 +865 1045 -30 +867 1039 -30 + +# sheets +Static 0x0C31 +865 1059 -30 + +# sheets +Static 0x0C32 +865 1058 -30 + +# sheets +Static 0x0C33 +868 1058 -30 + +# sheets +Static 0x0C34 +867 1058 -30 + +# sheets +Static 0x0C35 +868 1057 -30 + +# sheets +Static 0x0C36 +867 1057 -30 + +# untrimmed hedge +Static 0x0C92 +815 1091 -30 +815 1092 -30 +815 1093 -30 +815 1094 -30 +815 1095 -30 +815 1096 -30 +815 1097 -30 +815 1098 -30 +815 1102 -30 +815 1103 -30 +815 1104 -30 +815 1105 -30 +815 1106 -30 +815 1107 -30 +815 1108 -30 +815 1109 -30 +824 1091 -30 +824 1092 -30 +824 1093 -30 +824 1094 -30 +824 1095 -30 +824 1096 -30 +824 1097 -30 +824 1098 -30 +824 1102 -30 +824 1103 -30 +824 1104 -30 +824 1105 -30 +824 1106 -30 +824 1107 -30 +824 1108 -30 +824 1109 -30 + +# chess board +ChessBoard 0x0FA6 +763 1149 -24 +764 1144 -24 + +# dice and cup +Dices 0x0FA7 +763 1137 -23 + +# backgammon game +Backgammon 0x0FAD +757 1147 -24 + +# barrel +Static 0x0FAE +784 1066 -30 +784 1066 -25 +784 1066 -20 +784 1067 -30 +784 1067 -25 +784 1068 -30 +784 1068 -25 +784 1068 -20 +784 1069 -30 +784 1070 -30 +796 1056 -30 +796 1056 -25 +796 1056 -20 +797 1056 -30 +797 1056 -25 +797 1056 -20 +798 1056 -30 +798 1056 -25 +798 1056 -20 + +# anvil +AnvilSouthAddon 0x0FB0 +764 1152 -30 + +# forge +SmallForgeAddon 0x0FB1 +765 1152 -30 + +# garbage +Static 0x10EE +759 1110 -30 +761 1033 -30 +765 1046 -30 +766 1034 -30 +767 1052 -30 +769 1109 -30 +771 1084 -30 +771 1115 -30 +772 1035 -30 +772 1096 -30 +773 1044 -30 +774 1034 -30 +775 1074 -30 +779 1059 -30 +779 1106 -30 +780 1066 -8 +782 1089 -30 +785 1057 -8 +786 1059 -30 +786 1079 -30 +789 1067 -30 +790 1071 -30 +791 1064 -8 +791 1084 -10 +795 1065 -8 +795 1084 -30 +796 1092 -30 +797 1063 -30 +797 1102 -30 +800 1081 -30 +800 1099 -30 +802 1061 -9 +802 1104 -30 +804 1060 -30 +806 1064 -30 +807 1027 -30 +807 1079 -30 +809 1072 -30 +810 1109 -30 +812 1085 -30 +812 1102 -30 +813 1075 -30 +814 1056 -30 +819 1030 -30 +819 1068 -30 +819 1108 -30 +820 1072 -30 +821 1048 -30 +821 1095 -30 +821 1111 -30 +824 1040 -30 +824 1043 -30 +826 1080 -30 +827 1073 -30 +828 1038 -30 +829 1104 -30 +831 1059 -30 +831 1103 -30 +833 1073 -30 +835 1034 -30 +837 1039 -30 +842 1110 -9 +845 1038 -30 +847 1083 -9 +848 1093 -9 +848 1104 -9 +853 1117 -30 +854 1072 -30 +859 1041 -10 +859 1058 -9 +860 1062 -30 +860 1067 -9 +860 1110 -30 +862 1039 11 +862 1042 -30 +862 1048 -30 +863 1058 11 +865 1084 -30 +866 1070 -30 +866 1107 -30 +867 1033 -30 +867 1042 -10 +867 1060 -30 +867 1063 -9 +867 1067 -30 +867 1092 -30 +867 1092 -9 +867 1104 -30 +868 1083 -9 +868 1103 -9 +869 1082 -30 +869 1113 -30 +870 1096 -30 +871 1097 -9 +873 1078 -30 +874 1075 -30 +874 1117 -30 +876 1095 -30 +878 1063 -30 +879 1106 -30 + +# garbage +Static 0x10EF +759 1107 -30 +761 1030 -30 +761 1113 -30 +763 1036 -30 +764 1037 -30 +765 1043 -30 +767 1049 -30 +767 1112 -30 +769 1055 -30 +770 1038 -30 +770 1099 -30 +771 1047 -30 +771 1081 -30 +771 1112 -30 +772 1037 -30 +773 1077 -30 +773 1087 -30 +773 1118 -30 +778 1068 -30 +780 1063 -8 +780 1092 -30 +782 1069 -8 +783 1060 -8 +784 1082 -30 +788 1074 -30 +789 1064 -30 +789 1067 -8 +789 1087 -10 +791 1070 -30 +795 1062 -8 +795 1066 -30 +795 1081 -30 +795 1085 -30 +797 1068 -8 +797 1087 -30 +797 1099 -30 +799 1105 -30 +800 1107 -30 +801 1090 -30 +804 1057 -30 +804 1067 -30 +805 1082 -30 +806 1063 -30 +807 1024 -30 +807 1075 -30 +809 1030 -30 +810 1105 -30 +810 1106 -30 +812 1059 -30 +812 1112 -30 +817 1071 -30 +819 1027 -30 +819 1051 -30 +819 1105 -30 +819 1114 -30 +821 1033 -30 +821 1092 -30 +821 1111 -30 +822 1043 -30 +822 1046 -30 +823 1098 -30 +828 1035 -30 +829 1101 -30 +829 1106 -30 +830 1041 -30 +831 1056 -30 +831 1076 -30 +831 1107 -30 +833 1037 -30 +833 1062 -30 +837 1036 -30 +839 1042 -30 +843 1041 -30 +845 1086 -9 +846 1096 -9 +846 1107 -9 +852 1075 -30 +853 1114 -30 +855 1120 -30 +858 1113 -30 +859 1038 -10 +860 1042 11 +860 1051 -30 +860 1059 -30 +860 1064 -9 +861 1044 -10 +861 1061 11 +862 1039 -30 +862 1065 -30 +862 1070 -9 +864 1045 -30 +864 1073 -30 +865 1036 -30 +865 1063 -30 +865 1081 -30 +865 1107 -30 +866 1086 -9 +866 1104 -30 +866 1106 -9 +867 1039 -10 +867 1060 -9 +867 1064 -30 +867 1085 -30 +867 1087 -30 +867 1089 -30 +867 1089 -9 +867 1116 -30 +868 1099 -30 +868 1110 -30 +869 1045 -10 +869 1066 -9 +869 1070 -30 +869 1095 -30 +869 1095 -9 +869 1100 -9 +873 1075 -30 +874 1072 -30 +874 1114 -30 +875 1081 -30 +876 1066 -30 +876 1078 -30 +876 1092 -30 +876 1120 -30 +878 1098 -30 +879 1103 -30 +881 1109 -30 + +# garbage +Static 0x10F0 +761 1037 -30 +764 1112 -30 +767 1038 -30 +767 1099 -30 +768 1047 -30 +769 1037 -30 +770 1077 -30 +777 1092 -30 +778 1063 -30 +779 1063 -30 +780 1060 -8 +781 1082 -30 +784 1057 -30 +785 1074 -30 +786 1067 -8 +786 1087 -10 +787 1059 -30 +792 1066 -30 +797 1107 -30 +801 1067 -30 +802 1082 -30 +804 1075 -30 +807 1105 -30 +809 1059 -30 +814 1071 -30 +816 1051 -30 +816 1114 -30 +819 1043 -30 +819 1046 -30 +826 1106 -30 +828 1076 -30 +830 1037 -30 +840 1041 -30 +842 1086 -9 +843 1096 -9 +843 1107 -9 +849 1075 -30 +855 1113 -30 +857 1042 11 +857 1051 -30 +858 1061 11 +861 1073 -30 +862 1036 -30 +862 1063 -30 +862 1083 -9 +862 1107 -30 +863 1059 -9 +863 1083 -9 +863 1086 -9 +863 1106 -9 +864 1085 -30 +864 1116 -30 +865 1099 -30 +866 1100 -9 +873 1066 -30 + +# garbage +Static 0x10F1 +757 1109 -30 +757 1111 -30 +759 1032 -30 +759 1034 -30 +762 1110 -30 +763 1040 -30 +763 1045 -30 +763 1047 -30 +764 1033 -30 +765 1051 -30 +765 1053 -30 +766 1115 -30 +768 1046 -30 +769 1041 -30 +769 1083 -30 +769 1085 -30 +769 1102 -30 +769 1114 -30 +769 1116 -30 +770 1050 -30 +770 1052 -30 +771 1040 -30 +772 1080 -30 +774 1084 -30 +774 1115 -30 +778 1065 -8 +778 1067 -8 +779 1095 -30 +781 1067 -30 +782 1063 -8 +783 1066 -8 +783 1085 -30 +787 1066 -30 +787 1068 -30 +787 1077 -30 +788 1070 -8 +788 1090 -10 +792 1067 -30 +793 1064 -8 +793 1066 -8 +793 1083 -30 +793 1085 -30 +794 1069 -30 +795 1101 -30 +795 1103 -30 +798 1065 -8 +798 1084 -30 +799 1110 -30 +800 1102 -30 +802 1059 -30 +802 1061 -30 +803 1070 -30 +804 1085 -30 +805 1026 -30 +805 1028 -30 +806 1078 -30 +807 1060 -30 +808 1108 -30 +808 1110 -30 +809 1108 -30 +810 1027 -30 +811 1062 -30 +813 1109 -30 +816 1074 -30 +817 1029 -30 +817 1031 -30 +817 1107 -30 +817 1109 -30 +818 1054 -30 +818 1117 -30 +819 1094 -30 +819 1096 -30 +821 1046 -30 +821 1049 -30 +822 1030 -30 +822 1108 -30 +824 1095 -30 +826 1037 -30 +826 1039 -30 +827 1103 -30 +827 1105 -30 +828 1109 -30 +829 1058 -30 +829 1060 -30 +830 1079 -30 +831 1038 -30 +832 1040 -30 +832 1104 -30 +834 1059 -30 +835 1038 -30 +835 1040 -30 +840 1039 -30 +842 1044 -30 +844 1089 -9 +845 1099 -9 +845 1110 -9 +851 1078 -30 +851 1116 -30 +851 1118 -30 +856 1117 -30 +857 1040 -10 +857 1042 -10 +857 1116 -30 +858 1061 -30 +858 1063 -30 +858 1066 -9 +858 1068 -9 +859 1045 11 +859 1054 -30 +860 1041 -30 +860 1043 -30 +860 1064 11 +862 1041 -10 +863 1062 -30 +863 1067 -9 +863 1076 -30 +863 1082 -9 +863 1083 -30 +863 1085 -30 +864 1039 -30 +864 1066 -30 +864 1106 -30 +864 1108 -30 +864 1110 -30 +865 1041 -10 +865 1042 -30 +865 1043 -10 +865 1062 -9 +865 1064 -9 +865 1066 -30 +865 1068 -30 +865 1089 -9 +865 1091 -30 +865 1091 -9 +865 1093 -30 +865 1093 -9 +865 1109 -9 +866 1088 -30 +866 1119 -30 +867 1102 -30 +868 1084 -30 +868 1103 -9 +869 1107 -30 +870 1042 -10 +870 1063 -9 +870 1067 -30 +870 1092 -30 +870 1092 -9 +871 1077 -30 +871 1079 -30 +872 1074 -30 +872 1076 -30 +872 1116 -30 +872 1118 -30 +874 1094 -30 +874 1096 -30 +875 1069 -30 +876 1078 -30 +877 1075 -30 +877 1105 -30 +877 1107 -30 +877 1117 -30 +879 1095 -30 +882 1106 -30 + +# pile of garbage +Static 0x10F2 +776 1098 -30 +792 1103 -30 +798 1080 -30 +848 1104 -9 +860 1080 -30 +868 1056 -9 + +# pile of garbage +Static 0x10F3 +800 1065 -9 +856 1038 -9 +857 1066 -9 +858 1038 -9 +861 1104 -9 +862 1080 -30 + +# water barrel +Static 0x154D +792 1063 -30 + +# bellows +Static 0x1986 +800 1059 -30 + +# forge +Static 0x198A +800 1060 -30 + +# forge +Static 0x198E +800 1061 -30 + +# bellows +Static 0x1992 +800 1067 -30 + +# forge +Static 0x1996 +800 1066 -30 + +# forge +Static 0x199A +800 1065 -30 + +# keg +Static 0x1AD6 +792 1057 -30 +792 1057 -27 + +# keg +Static 0x1AD7 +792 1057 -24 + +# skull +Static 0x1AE0 +779 1066 -30 + +# skull +Static 0x1AE2 +794 1088 -30 +864 1034 -30 + +# skull +Static 0x1AE3 +793 1060 -10 + +# bone pile +Static 0x1B09 +800 1064 -30 +843 1058 -30 +846 1073 -30 +858 1051 -30 +860 1057 -30 +869 1022 -30 + +# bone pile +Static 0x1B0A +764 1040 -30 +801 1066 11 +803 1066 -9 +834 1053 -30 +841 1095 -10 +843 1081 -10 +860 1009 -30 + +# bone pile +Static 0x1B0B +777 1062 -10 +856 1064 -30 + +# bone pile +Static 0x1B0C +853 1101 -30 + +# bone pile +Static 0x1B0D +790 1092 -10 +819 1083 -30 +851 1095 -9 +863 1043 11 +863 1066 -30 + +# bone pile +Static 0x1B0E +793 1098 -30 +794 1090 -30 +866 1057 -30 + +# bone pile +Static 0x1B0F +809 1059 -30 +844 1068 -30 + +# bone pile +Static 0x1B10 +788 1056 -10 +788 1061 -30 +791 1060 11 +835 1068 -30 +840 1061 -30 +854 1081 -30 +858 1059 11 +860 1045 -30 +860 1068 -30 +860 1108 -9 +861 1045 -30 +865 1091 -9 + +# bone +Static 0x1B11 +784 1057 -10 +796 1058 -10 +796 1060 -10 +819 1076 -30 +847 1070 -30 +859 1049 -30 +865 1037 -30 +865 1104 -9 + +# bone +Static 0x1B12 +794 1059 -10 +835 1055 -30 +836 1060 -30 + +# jaw bone +Static 0x1B13 +792 1059 -10 +867 1102 -9 + +# pelvis bone +Static 0x1B15 +795 1060 -10 +852 1021 -30 + +# rib cage +Static 0x1B17 +779 1061 -30 +784 1061 -10 +795 1059 -10 +796 1107 -30 +816 1079 -30 +835 1063 -30 +840 1070 -30 +842 1090 -9 +856 1094 -9 +863 1013 -30 +865 1038 -30 +868 1107 -9 + +# rib cage +Static 0x1B18 +781 1107 -30 +802 1083 -30 +849 1098 -30 +850 1068 -30 +854 1110 -30 +871 1116 -30 + +# bone shards +Static 0x1B19 +777 1058 -30 +778 1098 -30 +781 1084 -10 +792 1106 -24 +822 1084 -30 +853 1015 -30 +863 1034 -30 +867 1095 -9 + +# bone shards +Static 0x1B1A +781 1067 -10 +797 1083 -30 +858 1041 -30 +862 1060 -30 + +# spine +Static 0x1B1B +786 1090 -30 +796 1059 -10 +798 1097 -30 +799 1090 -30 +802 1068 -30 +841 1101 -9 +854 1074 -30 +855 1092 -30 +860 1047 11 + +# spine +Static 0x1B1C +822 1076 -30 + +# leaves +Static 0x1B1F +814 1090 -30 +815 1099 -30 +816 1088 -30 + +# leaves +Static 0x1B20 +808 1081 -30 +815 1112 -30 +816 1100 -30 +823 1101 -30 + +# leaves +Static 0x1B21 +808 1066 -30 + +# leaves +Static 0x1B22 +808 1065 -30 +823 1100 -30 + +# leaves +Static 0x1B23 +804 1088 -30 +805 1088 -30 +808 1064 -30 +809 1081 -30 +810 1087 -30 +824 1088 -30 +824 1101 -30 +824 1112 -30 +825 1091 -30 +825 1111 -30 + +# leaves +Static 0x1B25 +808 1064 -30 +808 1080 -30 +809 1064 -30 +814 1099 -30 +815 1101 -30 +815 1110 -30 +823 1090 -30 + +# leaves +Static 0x1B26 +808 1079 -30 +808 1081 -30 +814 1089 -30 +815 1090 -30 +816 1111 -30 +823 1110 -30 + +# refuse +Static 0x1BB4 +799 1096 -30 +856 1067 -9 +860 1085 -30 +869 1056 -9 +869 1080 -9 + +# refuse +Static 0x1BB6 +857 1038 -9 +861 1080 -30 + +# refuse +Static 0x1BB8 +856 1066 -9 + +# broken barrel +Static 0x1DB3 +794 1061 -30 + +# broken barrel +Static 0x1DB4 +794 1060 -30 + +# broken barrel +Static 0x1DB5 +793 1060 -30 + +# broken barrel +Static 0x1DB6 +793 1061 -30 + +# book +Static 0x1E20 +776 1066 -9 +800 1104 -30 +867 1036 -30 +868 1082 -30 + +# books +Static 0x1E21 +796 1104 -30 +799 1089 -30 +844 1093 -9 +860 1039 -30 +861 1085 -30 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/patches.cfg b/Data/Decoration/Ilshenar/patches.cfg new file mode 100644 index 0000000..c6100b8 --- /dev/null +++ b/Data/Decoration/Ilshenar/patches.cfg @@ -0,0 +1,27 @@ +# invisible tile, can walk over +Static 0x2198 +827 777 -80 +828 777 -80 +829 777 -80 +827 778 -80 +828 778 -80 +829 778 -80 +827 779 -80 +828 779 -80 +829 779 -80 +1978 114 -28 +1979 114 -28 +1980 114 -28 +1981 114 -28 +1978 115 -28 +1979 115 -28 +1980 115 -28 +1981 115 -28 +1978 116 -28 +1979 116 -28 +1980 116 -28 +1981 116 -28 +1978 117 -28 +1979 117 -28 +1980 117 -28 +1981 117 -28 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/ratfortress.cfg b/Data/Decoration/Ilshenar/ratfortress.cfg new file mode 100644 index 0000000..6b46421 --- /dev/null +++ b/Data/Decoration/Ilshenar/ratfortress.cfg @@ -0,0 +1,17 @@ +# metal door +MetalDoor 0x0675 (Facing=WestCW) +642 843 -54 +645 830 -44 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +637 816 -44 +643 843 -54 + +# rattan door +RattanDoor 0x0697 (Facing=EastCCW) +646 830 -44 + +# wooden door +StrongWoodDoor 0x06E7 (Facing=EastCCW) +646 816 -44 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/savagecamp.cfg b/Data/Decoration/Ilshenar/savagecamp.cfg new file mode 100644 index 0000000..20e6f6d --- /dev/null +++ b/Data/Decoration/Ilshenar/savagecamp.cfg @@ -0,0 +1,52 @@ +# tribal berry +TribalBerry 0x09D0 +1258 752 -74 +1259 752 -72 +1264 752 -74 +1267 752 -73 + +# tribal paint +TribalPaint 0x09EC +1259 765 -74 + +# horse dung +Static 0x0F3B +1276 785 -80 + +# horse dung +Static 0x0F3C +1287 777 -80 + +# spear +Static 0x0F62 +1270 756 -71 +1270 756 -70 + +# mask of orcish kin +OrcishKinMask 0x141B +1255 755 -74 +1255 760 -74 +1255 761 -74 + +# tribal mask +SavageMask 0x154B (Hue=0x84C) +1248 702 -74 +1258 765 -74 + +# tribal mask +SavageMask 0x154B (Hue=0x84E) +1260 765 -74 + +# tribal mask +SavageMask 0x154C (Hue=0x845) +1266 765 -74 + +# tribal mask +SavageMask 0x154C (Hue=0x851) +1257 765 -74 + +# bolas +Bola 0x26AC +1211 742 -74 +1217 740 -74 +1270 762 -74 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/shrines.cfg b/Data/Decoration/Ilshenar/shrines.cfg new file mode 100644 index 0000000..d2e2fcc --- /dev/null +++ b/Data/Decoration/Ilshenar/shrines.cfg @@ -0,0 +1,28 @@ +# Compassion +AnkhWest 0x0003 +1209 476 -14 + +# Honesty +AnkhNorth 0x0004 +718 1350 -55 + +# Humility +AnkhWest 0x0003 +286 1013 5 + +# Justice +AnkhNorth 0x0004 +986 996 -22 + +# Sacrifice +AnkhWest 0x0003 +1170 1287 -30 + +# Spirituality +AnkhWest 0x0003 +1525 1340 4 + +# Valor +AnkhNorth 0x0004 +524 211 -49 +532 211 -44 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/vinculuminn.cfg b/Data/Decoration/Ilshenar/vinculuminn.cfg new file mode 100644 index 0000000..e12b297 --- /dev/null +++ b/Data/Decoration/Ilshenar/vinculuminn.cfg @@ -0,0 +1,27 @@ +# chest of drawers +Drawer 0x0A34 +658 662 -15 + +# The Deuce's Vinculum Inn +LocalizedSign 0x0BC4 (LabelNumber=1016297) +667 680 -24 + +# skull with candle +CandleSkull 0x1853 (Unlit) +658 675 -29 +663 672 -30 +664 670 -29 +666 676 -29 +668 672 -30 +670 675 -29 + +# skull with candle +CandleSkull 0x1854 +660 661 -29 + +# skull with candle +CandleSkull 0x1857 (Unlit) +659 670 -29 +662 676 -29 +666 661 -29 +669 670 -29 \ No newline at end of file diff --git a/Data/Decoration/Ilshenar/wispdungeon.cfg b/Data/Decoration/Ilshenar/wispdungeon.cfg new file mode 100644 index 0000000..1d8159f --- /dev/null +++ b/Data/Decoration/Ilshenar/wispdungeon.cfg @@ -0,0 +1,520 @@ +##################### +# Friendly Entrance # +##################### + +# ankh +AnkhWest 0x0003 +286 1013 5 + +# metal door +MetalDoor 0x0675 (Facing=WestCW; Hue=0x451) +659 1535 -28 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW; Hue=0x451) +660 1535 -28 + +# metal door +MetalDoor 0x0679 (Facing=WestCCW; Hue=0x482) +699 1527 -28 + +# metal door +MetalDoor 0x067B (Facing=EastCW; Hue=0x482) +700 1527 -28 + +# metal door +MetalDoor 0x0681 (Facing=SouthCCW; Hue=0x482) +703 1572 -28 + +# metal door +MetalDoor 0x0683 (Facing=NorthCW; Hue=0x482) +703 1571 -28 + +# bookcase +FullBookcase 0x0A97 +659 1521 -28 +661 1521 -28 + +# bookcase +FullBookcase 0x0A98 +660 1521 -28 + +# bookcase +FullBookcase 0x0A99 +657 1525 -28 +657 1527 -28 + +# bookcase +FullBookcase 0x0A9A +657 1524 -28 + +# bookcase +FullBookcase 0x0A9B +658 1521 -28 +662 1521 -28 + +# bookcase +FullBookcase 0x0A9C +657 1523 -28 +657 1526 -28 + +# wisp +LocalizedStatic 0x2100 (LabelNumber=1016453) +689 1566 -15 +689 1570 -15 +691 1513 -15 +694 1513 -15 +697 1513 -15 +700 1513 -15 +657 1501 -15 +657 1506 -15 +661 1497 -15 +649 1297 -14 +649 1300 -19 +654 1297 -14 +654 1300 -21 + +# wisp +LocalizedStatic 0x2100 (LabelNumber=1016454) +718 1553 -18 +719 1553 -10 +720 1553 -18 + +# wisp +LocalizedStatic 0x2100 (Hue=0x8AB; LabelNumber=1016453) +641 1531 -16 +666 1497 -15 + + +############### +# Evil Bowels # +############### + +# stone wall +Static 0x00C8 (Hue=0x964) +836 1471 -28 + +# stone wall +SecretStoneDoor1 0x00F6 (Facing=NorthCW; Hue=0x96F) +752 1549 -28 + +# metal door +MetalDoor 0x0675 (Facing=WestCW; Hue=0x89D) +851 1559 -28 +907 1464 -28 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW; Hue=0x89D) +908 1464 -28 +852 1559 -28 + +# metal door +MetalDoor 0x067D (Facing=SouthCW; Hue=0x89D) +824 1475 -28 +872 1476 -28 + +# metal door +MetalDoor 0x067D (Facing=SouthCW; Hue=0x901) +872 1508 2 +879 1532 -28 + +# metal door +MetalDoor 0x067D (Facing=SouthCW; Hue=0x89E) +848 1476 -28 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW; Hue=0x89D) +872 1475 -28 +824 1474 -28 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW; Hue=0x901) +872 1507 2 +879 1531 -28 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW; Hue=0x89E) +848 1475 -28 + +# small crate +SmallCrate 0x09A9 +817 1467 -28 +818 1468 -25 + +# metal chest +MetalChest 0x09AB +858 1561 -28 +859 1561 -28 +893 1497 2 +898 1553 -28 +899 1465 -28 +901 1553 -28 +905 1497 2 + +# metal chest +MetalChest 0x09AB (Hue=0x454) +776 1476 -28 + +# metal chest +MetalChest 0x09AB (Hue=0x455) +837 1465 -28 + +# metal chest +MetalChest 0x09AB (Hue=0x4E4) +761 1537 -28 + +# metal chest +MetalChest 0x09AB (Hue=0x66D) +760 1537 -28 +762 1537 -28 +776 1483 -28 +836 1465 -28 + +# eggs +EasterEggs 0x09B5 +964 1547 -29 + +# wall torch +Static 0x0A05 +817 1478 -14 +834 1467 -14 + +# wooden shelf +EmptyBookcase 0x0A9D (Hue=0x717) +958 1496 -28 + +# wooden shelf +EmptyBookcase 0x0A9D (Hue=0x718) +923 1553 -28 + +# wooden shelf +EmptyBookcase 0x0A9E (Hue=0x717) +953 1502 -28 + +# wooden shelf +EmptyBookcase 0x0A9E (Hue=0x718) +920 1558 -28 +920 1562 -28 + +# crate +LargeCrate 0x0E3C +817 1470 -25 +817 1473 -25 +817 1474 -22 +817 1475 -25 + +# crate +MediumCrate 0x0E3E +873 1521 -30 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x4E4) +777 1575 -28 +784 1517 -28 +784 1578 -28 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x66D) +777 1574 -28 +777 1576 -28 +784 1521 -28 +784 1574 -28 + +# metal chest +MetalGoldenChest 0x0E41 +827 1465 -28 +828 1465 -28 +829 1465 -28 + +# wooden chest +WoodenChest 0x0E42 +817 1476 -28 +817 1477 -28 +920 1565 -28 +929 1571 -28 +953 1478 -28 +953 1508 -28 +953 1532 -28 +953 1539 -28 +961 1549 -29 +961 1558 -28 + +# wooden chest +WoodenChest 0x0E43 +926 1553 -27 +955 1496 -28 +955 1527 -27 +958 1552 -28 +961 1464 -28 +972 1480 -30 + +# metal chest +MetalChest 0x0E7C +865 1539 -28 +873 1469 -28 +873 1577 -28 +873 1579 -28 +889 1500 2 +889 1517 2 + +# metal chest +MetalChest 0x0E7C (Hue=0x454) +772 1482 -28 +779 1482 -28 + +# metal chest +MetalChest 0x0E7C (Hue=0x466) +834 1468 -28 + +# metal chest +MetalChest 0x0E7C (Hue=0x4E4) +753 1544 -28 +777 1520 -28 +777 1522 -28 + +# metal chest +MetalChest 0x0E7C (Hue=0x66D) +753 1545 -28 +772 1478 -28 +777 1519 -28 +777 1521 -28 +777 1523 -28 +779 1478 -28 + +# metal chest +MetalChest 0x0E7C (Hue=0x89F) +834 1467 -28 + +# metal chest +MetalChest 0x0E7C (Hue=0x8AB) +834 1469 -28 + +# keg +Static 0x0E7F +974 1484 -28 + +# cleaver +Static 0x0EC3 +874 1524 -22 + +# gravestone +LocalizedStatic 0x0ED4 (LabelNumber=1016086; Hue=0x835) +877 1561 -23 + +# gravestone +LocalizedStatic 0x0ED4 (LabelNumber=1016423; Hue=0x835) +883 1555 -23 + +# gravestone +LocalizedStatic 0x0ED5 (LabelNumber=1016150; Hue=0x835) +875 1563 -23 + +# gravestone +LocalizedStatic 0x0ED5 (LabelNumber=1016381; Hue=0x835) +879 1559 -23 + +# gravestone +LocalizedStatic 0x0ED5 (LabelNumber=1016210; Hue=0x835) +881 1557 -23 + +# barrel +Static 0x0FAE +821 1475 -28 +821 1475 -22 +821 1475 -16 +821 1476 -22 +822 1475 -22 +822 1475 -16 +822 1476 -22 +968 1484 -28 + +# tapestry +Static 0x0FE3 +825 1488 -28 + +# tapestry +Static 0x0FE4 +825 1486 -28 + +# gravestone +LocalizedStatic 0x1174 (LabelNumber=1016508;Hue=0x963) +898 1508 2 +901 1508 2 + +# statue +LocalizedStatic 0x1227 (LabelNumber=1016466) +874 1558 -8 + +# statue +LocalizedStatic 0x1227 (LabelNumber=1016467) +878 1554 -8 + +# melted wax +MeltedWax 0x122A +873 1570 -17 +879 1570 -23 +890 1570 -28 + +# melted wax +MeltedWax 0x122B +893 1573 -28 + +# melted wax +MeltedWax 0x122C +875 1570 -24 +879 1573 -26 +880 1572 -23 +893 1570 -28 + +# melted wax +MeltedWax 0x122D +878 1572 -23 + +# melted wax +MeltedWax 0x122E +873 1572 -17 +874 1570 -24 +878 1570 -24 +880 1571 -24 +890 1573 -28 + +# bust +Static 0x12CA +874 1554 -2 + +# statue +LocalizedStatic 0x139A (LabelNumber=1016468) +876 1556 -6 + +# earrings +Static 0x1F07 +858 1572 -22 + +# necklace +Static 0x1F08 +849 1566 -22 +849 1566 -21 +849 1567 -22 +849 1568 -22 + +# necklace +Static 0x1F08 (Hue=0x455) +850 1570 -22 +860 1570 -28 + +# silver necklace +Static 0x1F0A +850 1565 -21 +855 1572 -22 +858 1573 -22 + +# wisp +LocalizedStatic 0x2100 (LabelNumber=1016452; Hue=0x964) +890 1498 14 +890 1515 14 +896 1504 14 +896 1511 14 +903 1504 14 +903 1511 14 +907 1498 14 +907 1515 14 + +# wisp +LocalizedStatic 0x2100 (LabelNumber=1016452; Hue=0x966) +849 1562 -16 +849 1572 -16 +861 1562 -16 +861 1572 -16 +873 1567 -16 +873 1575 -16 +873 1582 -16 +880 1582 -16 +888 1553 -16 +888 1582 -16 +889 1555 -16 +889 1557 -16 +889 1559 -16 +894 1554 -16 +894 1556 -16 +894 1558 -16 +895 1553 -16 +896 1582 -16 +902 1559 -16 +902 1567 -16 +902 1575 -16 + +# no draw +Blocker 0x21A4 +777 1546 -28 +777 1549 -28 +778 1540 -28 +778 1542 -28 +778 1553 -28 +778 1555 -28 +780 1540 -28 +780 1542 -28 +780 1545 -28 +780 1547 -28 +780 1549 -28 +780 1551 -28 +780 1553 -28 +780 1555 -28 +782 1537 -28 +782 1539 -28 +782 1541 -28 +782 1543 -28 +782 1545 -28 +782 1547 -28 +782 1549 -28 +782 1551 -28 +782 1553 -28 +782 1555 -28 +784 1537 -28 +784 1539 -28 +784 1541 -28 +784 1543 -28 +784 1545 -28 +784 1547 -28 +784 1549 -28 +784 1551 -28 +784 1553 -28 +784 1555 -28 +786 1537 -28 +786 1539 -28 +786 1541 -28 +786 1543 -28 +786 1545 -28 +786 1547 -28 +786 1549 -28 +786 1551 -28 +786 1553 -28 +786 1555 -28 +788 1537 -28 +788 1539 -28 +788 1541 -28 +788 1543 -28 +788 1545 -28 +788 1547 -28 +788 1551 -28 +788 1553 -28 +788 1555 -28 +788 1557 -28 +790 1545 -28 +790 1547 -28 +790 1551 -28 +790 1553 -28 +790 1555 -28 +790 1557 -28 +791 1551 -28 +844 1433 -28 +844 1438 -28 +845 1433 -28 +845 1438 -28 +846 1433 -28 +846 1438 -28 +847 1433 -28 +847 1438 -28 +848 1432 -28 +848 1433 -28 +848 1438 -28 +848 1439 -28 \ No newline at end of file diff --git a/Data/Decoration/Malas/NERUN-Malas.cfg b/Data/Decoration/Malas/NERUN-Malas.cfg new file mode 100644 index 0000000..4beddca --- /dev/null +++ b/Data/Decoration/Malas/NERUN-Malas.cfg @@ -0,0 +1,19 @@ +# Saved By Static Exporter +# StaticExport by Nerun +# Version 2.0 + +# Orc Forts' Doors + +LightWoodDoor 0x06D7 (Facing=EastCCW) +1206 703 -88 +1258 1329 -90 +912 196 -79 +1599 1822 -110 +1666 358 -50 + +LightWoodDoor 0x06D5 (Facing=WestCW) +1205 703 -88 +1257 1329 -90 +911 196 -79 +1598 1822 -110 +1665 358 -50 \ No newline at end of file diff --git a/Data/Decoration/Malas/_luna.cfg b/Data/Decoration/Malas/_luna.cfg new file mode 100644 index 0000000..2bf8a4d --- /dev/null +++ b/Data/Decoration/Malas/_luna.cfg @@ -0,0 +1,184 @@ +# wooden door +DarkWoodDoor 0x06AD (Facing=SouthCW) +989 519 -30 +999 527 -50 + +# wooden door +DarkWoodDoor 0x06AF (Facing=NorthCCW) +999 512 -50 +989 518 -30 + +# wooden door +DarkWoodDoor 0x06A7 (Facing=EastCCW) +991 522 -30 +978 522 -50 +1002 522 -50 +1002 522 -30 + +# backpack +Backpack 0x0E75 +992 509 -47 + +# bookcase +LibraryBookcase 0x0A9B +950 493 -30 +951 498 -30 +953 493 -30 +952 496 -30 +952 498 -30 +953 496 -30 +986 525 -30 +1004 523 -50 + +# wooden shelf +EmptyBookcase 0x0A9E (Hue=0x47E) +947 496 -70 +947 498 -70 +947 499 -70 +947 540 -70 +947 542 -70 +948 543 -30 +949 541 -50 +947 544 -70 +1022 494 -50 +1022 495 -50 +1022 543 -70 +1022 544 -70 +1024 499 -50 +949 543 -50 +1024 500 -50 + +# empty tub +Static 0x0E83 (Hue=0x47E) +947 497 -70 + +# barrel +Barrel 0x0FAE (Hue=0x47E) +947 538 -70 +948 538 -70 +1028 541 -70 +1028 542 -64 +1028 542 -70 + +# wooden shelf +EmptyBookcase 0x0A9D (Hue=0x47E) +954 538 -30 +1025 493 -30 +1028 493 -30 +1026 538 -30 + +# forge +SmallForgeAddon 0x0FB1 +974 509 -50 +977 509 -50 + +# anvil +AnvilSouthAddon 0x0FB0 +975 509 -50 +976 509 -50 + +# anvil +AnvilEastAddon 0x0FAF +973 513 -50 + +# bellows +Static 0x1986 +973 514 -50 + +# forge +Static 0x198A +973 515 -50 + +# forge +Static 0x198E +973 516 -50 + +# metal chest +MetalChest 0x09AB (Hue=0x47E) +987 516 -44 +993 516 -44 +994 516 -44 +1004 509 -30 + +# metal chest +Metalchest 0x0E7C (Hue=0x47E) +985 523 -40 +985 523 -45 +985 523 -50 + +# dresser +Static 0x0A3D +987 525 -30 + +# dresser +Static 0x0A3C +988 525 -30 + +# armoire +Armoire 0x0A4F +999 523 -30 +1001 523 -30 + +# chest of drawers +Drawer 0x0A34 +996 530 -30 + +# bookcase +LibraryBookcase 0x0A99 +1000 524 -50 +1000 525 -50 +1000 529 -50 +1000 530 -50 + +# barrel +Barrel 0x0E77 (Hue=0x47E) +1022 538 -70 +1022 538 -64 +1022 539 -70 +1022 540 -70 +1023 538 -70 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +973 530 -50 + +# upright loom +LoomSouthAddon 0x1065 +975 523 -50 + +# wooden door +DarkWoodDoor 0x06AB (Facing=EastCW) +978 517 -50 +994 516 -30 + +# wooden door +DarkWoodDoor 0x06B3 (Facing=NorthCW) +980 527 -50 + +# wooden door +DarkWoodDoor 0x06B1 (Facing=SouthCCW) +980 512 -50 + +# wooden door +LightWoodDoor 0x06D5 (Facing=WestCW) +926 642 -90 + +# Bakery +LocalizedSign 0x0BA3 (LabelNumber=1061836) +962 633 -90 + +# Tavern +LocalizedSign 0x0BC3 (LabelNumber=1061835) +962 641 -90 + +# wooden door +LightWoodDoor 0x06D7 (Facing=EastCCW) +927 642 -90 + +# wooden gate +LightWoodGate 0x0843 (Facing=NorthCCW) +952 637 -90 + +# wooden door +LightWoodDoor 0x06DD (Facing=SouthCW) +928 637 -90 diff --git a/Data/Decoration/Malas/_umbra.cfg b/Data/Decoration/Malas/_umbra.cfg new file mode 100644 index 0000000..53cf9f4 --- /dev/null +++ b/Data/Decoration/Malas/_umbra.cfg @@ -0,0 +1,96 @@ +# spinning wheel +SpinningWheelSouthAddon 0x1015 +2088 1318 -80 + +# upright loom +LoomEastAddon 0x1060 +2088 1326 -80 +2088 1329 -80 + +# wooden door +StrongWoodDoor 0x06EB (Hue=0x497; Facing=EastCW) +2038 1320 -85 +2041 1321 -85 + +# oven +StoneOvenEastAddon 0x092C (Hue=0x44E) +2015 1360 -90 + +# training dummy +TrainingDummy 0x1074 (Hue=0x44F) +1961 1339 -75 +1977 1307 -75 + +# wooden bench +WoodenBench 0x0B2D (Hue=0x1A) +2040 1326 -65 + +# wooden door +StrongWoodDoor 0x06EF (Hue=0x497; Facing=NorthCCW) +2036 1317 -85 +2036 1323 -65 + +# barrel +Barrel 0x0E77 (Hue=0x497) +2059 1281 -80 +2059 1280 -80 +2061 1290 -80 +2062 1291 -80 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x497) +1975 1365 -74 +1975 1366 -74 +2034 1321 -65 + +# barrel +Static 0x0FAE (Hue=0x497) +1975 1369 -80 +1975 1370 -80 +1975 1370 -73 +1991 1315 -90 +2013 1365 -90 +2013 1366 -90 +2014 1366 -90 + +# stone wall +Static 0x005A (Hue=0x451) +1994 1325 -90 + +# chest of drawers +Drawer 0x0A2C (Hue=0x497) +2035 1311 -65 +2041 1311 -65 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x497) +2033 1313 -65 +2039 1313 -65 + +# wooden door +StrongWoodDoor 0x06E5 (Hue=0x497; Facing=WestCW) +2035 1315 -65 +2040 1315 -65 + +# chest of drawers +Drawer 0x0A34 (Hue=0x497) +2032 1323 -65 + +# metal chest +MetalChest 0x09AB (Hue=0x455) +2042 1339 -80 +2043 1339 -80 +2048 1344 -80 +2048 1344 -76 + +# cleaver +Static 0x0EC3 +2066 1372 -74 + +# bottles of liquor +Static 0x099E +2028 1354 -81 + +# butcher knife +Static 0x13F7 +2070 1370 -74 diff --git a/Data/Decoration/Malas/dark tides quest.cfg b/Data/Decoration/Malas/dark tides quest.cfg new file mode 100644 index 0000000..1184561 --- /dev/null +++ b/Data/Decoration/Malas/dark tides quest.cfg @@ -0,0 +1,121 @@ +# a magical teleporter +DarkTidesTeleporter 0x1822 +2105 1307 -50 +2018 1226 -90 +1068 458 -90 + +# Mardoth +Spawner 0x1F13 (Spawn=Mardoth; Count=1; HomeRange=0) +2110 1306 -50 + +# Maabus coffin +MaabusCoffin 0x0 (SpawnLocation=(2024, 1224, -90)) +2023 1223 -83 + +# Horus +Spawner 0x1F13 (Spawn=Horus; Count=1; HomeRange=0) +1192 513 -90 + +# Crystal cave barrier +CrystalCaveBarrier 0x3967 +1193 512 -90 +1194 512 -90 +1195 512 -90 +1196 512 -90 +1197 512 -90 + +# Kronus scroll box +KronusScrollBox 0xE80 +1185 451 -90 + +# Vault of secrets barrier +VaultOfSecretsBarrier 0x49E +1073 450 -90 +1073 451 -90 +1073 452 -90 +1078 450 -90 +1078 451 -90 +1078 452 -90 + +# metal chest +MetalChest 0x09AB (Hue=0x499) +1076 453 -84 +1076 449 -84 + +# Vault of secrets sign +LocalizedSign 0x0BD0 (Hue=0x482;LabelNumber=1060189) +1079 454 -84 + +# metal signpost +Static 0x0B9E + +# crate +MediumCrate 0x0E3E +1185 450 -90 +1185 450 -87 +1200 438 -87 +1203 439 -90 +1185 454 -87 + +# crate +MediumCrate 0x0E3F +1185 448 -90 +1186 439 -87 +1201 438 -87 +1194 447 -90 +1194 448 -90 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x835) +1185 447 -90 +1184 446 -90 +1184 443 -86 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x835) +1184 445 -90 +1188 437 -90 +1188 437 -86 +1189 437 -90 +1194 438 -90 + +# metal chest +MetalGoldenChest 0x0E40 +1184 444 -90 + +# metal chest +MetalGoldenChest 0x0E40 (Hue=0x849) +1184 443 -90 + +# bookcase +FullBookcase 0x0A9A +1185 440 -90 + +# crate +LargeCrate 0x0E3D +1186 439 -90 +1200 438 -90 +1201 438 -90 +1202 439 -90 +1202 439 -87 +1185 454 -90 +1185 453 -90 +1186 453 -87 +1186 453 -90 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x849) +1188 437 -82 +1190 437 -90 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x482) +1189 437 -86 + +# small fish +Static 0x0DD9 +1192 438 -90 + +# bookcase +FullBookcase 0x0A97 +1197 437 -90 \ No newline at end of file diff --git a/Data/Decoration/Malas/doom.cfg b/Data/Decoration/Malas/doom.cfg new file mode 100644 index 0000000..b193168 --- /dev/null +++ b/Data/Decoration/Malas/doom.cfg @@ -0,0 +1,135 @@ +# pedestal +Static 0x1F2A +467 92 -1 + +# alchemical symbol +Static 0x181D (Hue=0x482) +468 92 -1 + +# alchemical symbol +Static 0x1821 (Hue=0x3FD) +469 92 -1 + +# alchemical symbol +Static 0x1825 (Hue=0x66D) +470 92 -1 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +269 74 -1 +278 96 -1 +334 15 -1 +344 15 -1 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +269 73 -1 +278 95 -1 +334 14 -1 +344 14 -1 + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +308 88 -1 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +309 88 -1 + +# lever +Static 0x108C (Hue=0x83E) +307 143 5 + +# lever +Static 0x1095 (Hue=0x83F) +308 143 5 + +# lever +Static 0x1095 (Hue=0x843) +309 143 5 +308 146 8 + +# lever +Static 0x1093 (Hue=0x845) +310 143 5 + +# lever +Static 0x108C (Hue=0x83D) +307 144 5 + +# lever +Static 0x108E (Hue=0x83E) +307 145 5 +311 144 9 + +# lever +Static 0x1093 (Hue=0x835) +309 146 8 + +# lever +Static 0x1093 (Hue=0x83B) +310 146 8 + +# lever +Static 0x108C (Hue=0x845) +311 145 9 + +# crumbling floor +FireColumnTrap 0x11C5 (Hue=0x455) +2347 1264 -110 +2347 1271 -110 +2340 1272 -110 +2340 1264 -110 + +# metal door +MetalDoor 0x0681 (Hue=0x455; Facing=SouthCCW) +2333 1269 -110 + +# metal door +MetalDoor 0x067F (Hue=0x455; Facing=NorthCW) +2333 1268 -110 + +# floor spikes +SpikeTrap 0x11A0 +378 140 1 +378 139 2 +379 140 -1 +384 138 4 +385 138 -2 + +# iron gate +IronGate 0x082C (Facing=SouthCW) +351 40 -1 + +# switch +Static 0x108F +351 47 10 + +# skinning knife +Static 0x0EC4 +445 15 5 +445 15 6 +453 15 5 +452 16 5 + +# skinning knife +Static 0x0EC5 +444 16 5 +449 16 5 +449 16 6 + +# floor spikes +SpikeTrap 0x119A +379 139 0 +383 138 3 +383 140 -2 +386 144 -1 + +# empty tub +Static 0x0E83 +385 28 -1 +387 28 -1 + +# iron gate +IronGateShort 0x084C (Facing=WestCW) +391 29 -1 \ No newline at end of file diff --git a/Data/Decoration/Malas/emino's undertaking quest.cfg b/Data/Decoration/Malas/emino's undertaking quest.cfg new file mode 100644 index 0000000..c4bd5a4 --- /dev/null +++ b/Data/Decoration/Malas/emino's undertaking quest.cfg @@ -0,0 +1,142 @@ +# moongate +Static 0x1FD7 (Hue=0x3F1) +375 802 1 + +Teleporter 0x1BC3 (PointDest=(770, 1209, 25); MapDest=Tokuno) +375 802 1 + +# ankh +AnkhNorth 0x0004 (Hue=0xFA) +397 801 4 + +#Emino +Spawner 0x1F13 (Spawn=Emino; Count=1; HomeRange=0) +411 810 -1 + +#Zoel +Spawner 0x1F13 (Spawn=Zoel; Count=1; HomeRange=0) +388 817 -1 + +#Hidden figures +Spawner 0x1F13 (Spawn=HiddenFigure; Count=1; HomeRange=0) +403 1118 0 +405 1118 0 +403 1110 0 +403 1112 0 +403 1103 0 +404 1101 0 +419 1118 0 +418 1120 0 +419 1111 0 +418 1109 0 +419 1102 0 +418 1103 0 + +#Enshrouded figure +Spawner 0x1F13 (Spawn=EnshroudedFigure; Count=1; HomeRange=0) +403 1094 0 + +#Jedah Entille +Spawner 0x1F13 (Spawn=JedahEntille; Count=1; HomeRange=0) +404 1093 0 + +#Guardian barrier +GuardianBarrier 0x3967 +404 1140 0 +405 1140 0 +406 1140 0 +407 1140 0 +408 1140 0 +409 1140 0 + +# Green teleporters +GreenNinjaQuestTeleporter 0x051C +418 804 -1 + +Static 0x051C (Hue=0x17E) +412 1123 0 + +Teleporter 0x1BC3 (PointDest=(417, 806, -1)) +412 1123 0 + +# Blue teleporters +BlueNinjaQuestTeleporter 0x051C +423 805 -1 + +Static 0x051C (Hue=0x2) +411 1117 0 + +Teleporter 0x1BC3 (PointDest=(422, 806, -1)) +411 1117 0 + +# Red teleporter +Static 0x051C (Hue=0x21) +421 1092 0 + +Teleporter 0x1BC3 (PointDest=(391, 803, -1)) +421 1092 0 + +# White teleporters +WhiteNinjaQuestTeleporter 0x051C +392 802 -1 + +Static 0x051C (Hue=0x47E) +412 1086 0 + +Teleporter 0x1BC3 (PointDest=(391, 803, -1)) +412 1086 0 + +# wooden chest +EminosKatanaChest 0x0E42 +393 989 -15 + +# floor spikes +SpikeTrap 0x119A +418 1084 0 + +# floor saw +SawTrap 0x11AC +421 1077 0 + +# hole +FireColumnTrap 0x1B71 +403 1073 0 +410 1050 0 +408 1044 0 +409 1044 0 +410 1044 0 +411 1044 0 +412 1044 0 +413 1044 0 + +# haramaki-do +Static 0x2674 (Hue=0x48C) +409 1009 -13 + +# war mace +Static 0x1406 (Hue=0x47E) +409 1008 -13 + +# kabuto +Static 0x236D (Hue=0x48C) +409 1008 -13 + +# chest +OrnateWoodenChest 0x280D +436 999 -15 + +# kimono +Static 0x2681 +396 1149 0 + +# ninja pants +Static 0x2651 (Hue=0x530) +397 1146 1 + +# ninja mask +Static 0x26A4 (Hue=0x530) +395 1146 0 + +# ninja shirt +Static 0x2668 (Hue=0x530) +396 1146 0 \ No newline at end of file diff --git a/Data/Decoration/Malas/haochi's trials quest.cfg b/Data/Decoration/Malas/haochi's trials quest.cfg new file mode 100644 index 0000000..a51ede9 --- /dev/null +++ b/Data/Decoration/Malas/haochi's trials quest.cfg @@ -0,0 +1,85 @@ +# Candle +HonorCandle 0x1433 (Unlit; Unprotected) +419 731 17 +420 731 17 +422 731 17 +421 731 17 + +# stone pavers +Static 0x051C (Hue=0xFA) +389 704 -1 +426 780 -1 +331 769 -1 +355 745 -1 +330 706 -1 + +Teleporter 0x1BC3 (PointDest=(384, 733, -1); MapDest=Malas) +389 704 -1 +426 780 -1 +331 769 -1 +355 745 -1 +330 706 -1 + +# moongate +Static 0x1FD7 (Hue=0xFA) +391 777 -1 + +Teleporter 0x1BC3 (PointDest=(770, 1209, 25); MapDest=Tokuno) +391 777 -1 + +# ankh +AnkhNorth 0x0004 (Hue=0xFA) +351 733 18 +388 724 13 + +# brass sign +# Welcome to your new home, Samurai. +LocalizedSign 0x0BD1 (LabelNumber=1063295) +369 777 -1 + +# chest +HaochisTreasureChest 0x2811 +424 704 8 +424 705 8 +424 706 8 + +# katana +Static 0x13FF (Hue=0x482) +414 703 9 + +# Haochi's katana generator +HaochisKatanaGenerator 0x1B7B +415 703 1 + +#Haochi +Spawner 0x1F13 (Spawn=Haochi; Count=1; HomeRange=0) +377 742 1 + +#Haochi's Guardsmen +Spawner 0x1F13 (Spawn=HaochisGuardsman; Count=1; HomeRange=0) +367 749 -1 +367 750 -1 +367 739 -1 +367 740 -1 +367 730 -1 +367 729 -1 +379 727 -1 +380 727 -1 +392 730 -1 +392 731 -1 +392 739 -1 +392 740 -1 +397 749 -1 +398 748 -1 + +#Deadly Imp +Spawner 0x1F13 (Spawn=DeadlyImp; Count=1; HomeRange=0) +342 736 -1 + +#Fierce Dragon +Spawner 0x1F13 (Spawn=FierceDragon; Count=1; HomeRange=0) +339 741 -1 + +#Relnia +Spawner 0x1F13 (Spawn=Relnia; Count=1; HomeRange=0) +379 710 -1 \ No newline at end of file diff --git a/Data/Decoration/Malas/luna.cfg b/Data/Decoration/Malas/luna.cfg new file mode 100644 index 0000000..e158d16 --- /dev/null +++ b/Data/Decoration/Malas/luna.cfg @@ -0,0 +1,6 @@ +# Shrine of Wisdom +AnkhNorth 0x0004 (Hue=0x47E) +975 508 -30 + +ShrineOfWisdomAddon 0x14C3 +975 509 -30 \ No newline at end of file diff --git a/Data/Decoration/Malas/markcontainers.cfg b/Data/Decoration/Malas/markcontainers.cfg new file mode 100644 index 0000000..c1db65b --- /dev/null +++ b/Data/Decoration/Malas/markcontainers.cfg @@ -0,0 +1,17 @@ +# Standard pouches +MarkContainer 0xE79 (TargetMap=Malas) +951 546 -70 (1006, 994, -70) +914 192 -79 (1019, 1062, -70) +1614 143 -90 (1214, 1313, -90) +2176 324 -90 (1554, 172, -90) +864 812 -90 (1061, 1161, -70) +1326 523 -87 (1201, 1554, -70) +1313 1115 -85 (1183, 462, -45) + +# Auto-lock pouch +MarkContainer 0xE79 (TargetMap=Malas; Locked) +1051 1434 -85 (1076, 1244, -70) + +# Bone container +MarkContainer 0xECA (TargetMap=Malas; Bone) +424 189 -1 (2333, 1501, -90) \ No newline at end of file diff --git a/Data/Decoration/Malas/summoning quest.cfg b/Data/Decoration/Malas/summoning quest.cfg new file mode 100644 index 0000000..e432161 --- /dev/null +++ b/Data/Decoration/Malas/summoning quest.cfg @@ -0,0 +1,44 @@ +# Victoria spawner +Spawner 0x1F13 (Spawn=Victoria; HomeRange=2; Count=1; MinDelay=00:01:00; MinDelay=00:01:00) +423 195 -1 + +# Altar for summoning bone demons +SummoningAltar 0x1216 +441 205 -1 + +# Bell for summoning Chyloth +BellOfTheDead 0x091A +417 246 23 + +# No teleporting on Chyloth's spot +Blocker 0x21A4 +417 246 7 + +# Teleporter (pad) from first boat to second +Static 0x1822 (Hue=0x44E) +408 254 2 + +# Teleporter (obj) from first boat to second +Teleporter 0x1BC3 (PointDest=(428, 318, 2)) +407 254 2 +408 254 2 +409 254 2 + +# Teleporter (pad) from second boat to land +Static 0x1822 (Hue=0x44E) +428 321 2 + +# Teleporter (obj) from second boat to land +Teleporter 0x1BC3 (PointDest=(422, 327, -1); DestEffect=true; SoundID=0x1FE) +427 321 2 +428 321 2 +429 321 2 + +# Daemon Bones +Static 0x0F80 +421 198 -1 +422 195 -1 + +# book - The Akashic Records +LocalizedStatic 0x0FBE (Hue=0x482; LabelNumber=1060023) +420 192 8 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Blighted Grove.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Blighted Grove.cfg new file mode 100644 index 0000000..1c186e4 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Blighted Grove.cfg @@ -0,0 +1,5 @@ +Static 0x3967 +6477 862 10 + +Blocker 0x21A4 +6511 950 15 diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Covetous.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Covetous.cfg new file mode 100644 index 0000000..a41eea2 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Covetous.cfg @@ -0,0 +1,4 @@ +# Items +# Bones Of Frederic Smithson +Static 0xECE +2416 887 0 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Heartwood.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Heartwood.cfg new file mode 100644 index 0000000..a81597c --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Heartwood.cfg @@ -0,0 +1,7 @@ +#Entrance portal +Static 0x3967 +535 992 0 + +# Exit Portal +Static 0x3967 +6984 338 0 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Moonglow.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Moonglow.cfg new file mode 100644 index 0000000..697b9ae --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Moonglow.cfg @@ -0,0 +1,58 @@ +# Signs +LocalizedSign 0xBCF (LabelNumber=1074717) +4540 1375 21 + +LocalizedSign 0xBCF (LabelNumber=1073437) +4539 1375 21 + +LocalizedSign 0xBD2 (LabelNumber=1073212) +4521 1370 23 + +LocalizedSign 0xBD2 (LabelNumber=1073210) +4527 1365 23 + +LocalizedSign 0xBD1 (LabelNumber=1073218) +4524 1364 23 + +LocalizedSign 0xBD1 (LabelNumber=1073209) +4511 1364 23 + +LocalizedSign 0xBD2 (LabelNumber=1073207) +4501 1374 23 + +LocalizedSign 0xBD2 (LabelNumber=1073208) +4493 1378 23 + +LocalizedSign 0xBD2 (LabelNumber=1073215) +4493 1391 23 + +LocalizedSign 0xBD1 (LabelNumber=1073216) +4506 1386 23 + +LocalizedSign 0xBD2 (LabelNumber=1073214) +4506 1391 23 + +LocalizedSign 0xBD2 (LabelNumber=1073213) +4521 1383 23 + +LocalizedSign 0xBD2 (LabelNumber=1073211) +4525 1389 23 + +# Donation Box +Static 0x16B +4538 1375 23 + +# Walls +Static 0x15F +4492 1396 23 +4492 1397 23 +4500 1356 23 +4500 1357 23 +4513 1356 23 +4513 1357 23 + +Static 0x160 +4512 1376 23 +4513 1376 23 +4489 1375 23 +4490 1375 23 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Palace of Paroxysmus.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Palace of Paroxysmus.cfg new file mode 100644 index 0000000..f99e7a7 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Palace of Paroxysmus.cfg @@ -0,0 +1,3 @@ +# Items +Static 0x857 +6518 492 -50 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Prism of Light.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Prism of Light.cfg new file mode 100644 index 0000000..14344bf --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Prism of Light.cfg @@ -0,0 +1,56 @@ +# Items +# Signs +LocalizedSign 0xBCF (LabelNumber=1073037) +6476 168 -11 + +LocalizedSign 0xBD0 (LabelNumber=1073037) +6473 182 0 + +LocalizedSign 0xBD0 (LabelNumber=1073038) +6472 173 -11 + +LocalizedSign 0xBCF (LabelNumber=1073039) +6481 182 -11 + +LocalizedSign 0xBD0 (LabelNumber=1073040) +6484 178 -11 + +LocalizedSign 0xBCF (LabelNumber=1073041) +6488 175 -11 + +LocalizedSign 0xBCF (LabelNumber=1073042) +6489 169 -11 + +LocalizedSign 0xBCF (LabelNumber=1073043) +6484 169 -11 + +LocalizedSign 0xBCF (LabelNumber=1073044) +6478 176 -11 + +# Peerless Altar +# Arcane circle +Static 0x307F +6589 178 25 + +# Ankh +AnkhWest 0x0003 +6540 138 -15 + +# Key room moongate +Static 0xF6C (Hue=0x481) +6515 184 0 +6537 175 0 + +# Boss room red moongates +Static 0xDDA +6541 117 -15 +6523 136 -20 + +# Mobs +# Mage +Spawner 0x1F13 (Spawn=Mage; Count=1; HomeRange=2) +6579 184 32 + +# Wandering Healer +Spawner 0x1F13 (Spawn=WanderingHealer; Count=1; HomeRange=2) +6579 180 30 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Sanctuary.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Sanctuary.cfg new file mode 100644 index 0000000..db5a85a --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Sanctuary.cfg @@ -0,0 +1,11 @@ +# Items +# Traps +SpikeTrap 0x1D99 +6326 47 -20 +6327 46 -20 +6328 45 -20 +6368 78 -20 +6328 144 -20 +6326 140 -20 +6327 140 -20 + diff --git a/Data/Decoration/Mondain's Legacy/Felucca/Vesper.cfg b/Data/Decoration/Mondain's Legacy/Felucca/Vesper.cfg new file mode 100644 index 0000000..c15122c --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Felucca/Vesper.cfg @@ -0,0 +1,39 @@ +# Signs +LocalizedSign 0xBD2 (LabelNumber=1073409) +2926 980 -23 + +LocalizedSign 0xBD1 (LabelNumber=1073408) +2922 974 -23 + +LocalizedSign 0xBD2 (LabelNumber=1073410) +2920 984 -24 + +LocalizedSign 0xBD2 (LabelNumber=1073411) +2918 983 -20 + +LocalizedSign 0xBD2 (LabelNumber=1073412) +2912 984 -24 + +LocalizedSign 0xBD1 (LabelNumber=1073415) +2911 968 -22 + +LocalizedSign 0xBD1 (LabelNumber=1073416) +2915 963 -14 + +LocalizedSign 0xBD2 (LabelNumber=1073419) +2907 971 -22 + +LocalizedSign 0xBD2 (LabelNumber=1073418) +2908 976 -22 + +LocalizedSign 0xBD1 (LabelNumber=1073417) +2906 979 -27 + +LocalizedSign 0xBD1 (LabelNumber=1073413) +2912 978 -27 + +LocalizedSign 0xBD1 (LabelNumber=1073414) +2916 978 -27 + +LocalizedSign 0xBD1 (LabelNumber=1016415) +2920 963 0 diff --git a/Data/Decoration/Mondain's Legacy/Ilshenar/Misc.cfg b/Data/Decoration/Mondain's Legacy/Ilshenar/Misc.cfg new file mode 100644 index 0000000..2d1bee8 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Ilshenar/Misc.cfg @@ -0,0 +1,9 @@ +# Mobiles +Spawner 0x1F13 (Spawn=SpeckledScorpion; Count=1; HomeRange=5) +1546 631 -14 +1607 598 -14 +1600 629 -14 + +Spawner 0x1F13 (Spawn=SpeckledScorpion; Count=2; HomeRange=5) +1588 610 -14 +1576 597 -14 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Ilshenar/Twisted Weald.cfg b/Data/Decoration/Mondain's Legacy/Ilshenar/Twisted Weald.cfg new file mode 100644 index 0000000..54f8529 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Ilshenar/Twisted Weald.cfg @@ -0,0 +1,5 @@ +Static 0x375A +1450 1470 -22 + +Static 0x375A +2187 1251 2 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Malas/Bedlam.cfg b/Data/Decoration/Mondain's Legacy/Malas/Bedlam.cfg new file mode 100644 index 0000000..23ac219 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Malas/Bedlam.cfg @@ -0,0 +1,27 @@ +# Items +# Doors +Static 0x855 +101 1627 50 + +IronGate 0x82C (Facing=SouthCW) +92 1667 0 + +IronGate 0x82E (Facing=NorthCCW) +92 1666 0 + +StrongWoodDoor 0x6ED (Facing=SouthCW) +95 1640 0 +86 1651 0 +86 1651 20 +84 1651 0 +84 1651 20 +84 1646 0 +84 1646 20 +91 1628 0 + +StrongWoodDoor 0x6EF (Facing=NorthCCW) +95 1639 0 + +# Boss Exit +Static 0xDDA +99 1617 50 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Malas/Citadel.cfg b/Data/Decoration/Mondain's Legacy/Malas/Citadel.cfg new file mode 100644 index 0000000..fd99ca6 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Malas/Citadel.cfg @@ -0,0 +1,19 @@ +Static 0x17DC +85 1880 0 +90 1919 0 +122 1869 0 +137 1916 0 + +# Traps +SpikeTrap 0x11A0 +185 1916 0 +186 1916 0 +182 1891 0 +155 1899 0 +155 1898 0 +136 1975 0 +136 1976 0 +136 1977 0 + +SpikeTrap 0x119A +135 1870 0 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Malas/Labyrinth.cfg b/Data/Decoration/Mondain's Legacy/Malas/Labyrinth.cfg new file mode 100644 index 0000000..3aaa395 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Malas/Labyrinth.cfg @@ -0,0 +1,10 @@ +Static 0x1FD7 (Hue=0x4A) +1775 971 -85 + +# Items +# Iron gate +IronGateShort 0x856 (Facing=NorthCCW) +409 1935 0 + +IronGateShort 0x854 (Facing=SouthCW) +409 1936 0 diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Blighted Grove.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Blighted Grove.cfg new file mode 100644 index 0000000..813c21c --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Blighted Grove.cfg @@ -0,0 +1,5 @@ +Static 0x3967 +6477 862 10 + +Blocker 0x21A4 +6511 950 15 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Covetous.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Covetous.cfg new file mode 100644 index 0000000..a41eea2 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Covetous.cfg @@ -0,0 +1,4 @@ +# Items +# Bones Of Frederic Smithson +Static 0xECE +2416 887 0 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Heartwood.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Heartwood.cfg new file mode 100644 index 0000000..a81597c --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Heartwood.cfg @@ -0,0 +1,7 @@ +#Entrance portal +Static 0x3967 +535 992 0 + +# Exit Portal +Static 0x3967 +6984 338 0 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Moonglow.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Moonglow.cfg new file mode 100644 index 0000000..697b9ae --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Moonglow.cfg @@ -0,0 +1,58 @@ +# Signs +LocalizedSign 0xBCF (LabelNumber=1074717) +4540 1375 21 + +LocalizedSign 0xBCF (LabelNumber=1073437) +4539 1375 21 + +LocalizedSign 0xBD2 (LabelNumber=1073212) +4521 1370 23 + +LocalizedSign 0xBD2 (LabelNumber=1073210) +4527 1365 23 + +LocalizedSign 0xBD1 (LabelNumber=1073218) +4524 1364 23 + +LocalizedSign 0xBD1 (LabelNumber=1073209) +4511 1364 23 + +LocalizedSign 0xBD2 (LabelNumber=1073207) +4501 1374 23 + +LocalizedSign 0xBD2 (LabelNumber=1073208) +4493 1378 23 + +LocalizedSign 0xBD2 (LabelNumber=1073215) +4493 1391 23 + +LocalizedSign 0xBD1 (LabelNumber=1073216) +4506 1386 23 + +LocalizedSign 0xBD2 (LabelNumber=1073214) +4506 1391 23 + +LocalizedSign 0xBD2 (LabelNumber=1073213) +4521 1383 23 + +LocalizedSign 0xBD2 (LabelNumber=1073211) +4525 1389 23 + +# Donation Box +Static 0x16B +4538 1375 23 + +# Walls +Static 0x15F +4492 1396 23 +4492 1397 23 +4500 1356 23 +4500 1357 23 +4513 1356 23 +4513 1357 23 + +Static 0x160 +4512 1376 23 +4513 1376 23 +4489 1375 23 +4490 1375 23 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Palace of Paroxysmus.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Palace of Paroxysmus.cfg new file mode 100644 index 0000000..f99e7a7 --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Palace of Paroxysmus.cfg @@ -0,0 +1,3 @@ +# Items +Static 0x857 +6518 492 -50 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Prism of Light.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Prism of Light.cfg new file mode 100644 index 0000000..14344bf --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Prism of Light.cfg @@ -0,0 +1,56 @@ +# Items +# Signs +LocalizedSign 0xBCF (LabelNumber=1073037) +6476 168 -11 + +LocalizedSign 0xBD0 (LabelNumber=1073037) +6473 182 0 + +LocalizedSign 0xBD0 (LabelNumber=1073038) +6472 173 -11 + +LocalizedSign 0xBCF (LabelNumber=1073039) +6481 182 -11 + +LocalizedSign 0xBD0 (LabelNumber=1073040) +6484 178 -11 + +LocalizedSign 0xBCF (LabelNumber=1073041) +6488 175 -11 + +LocalizedSign 0xBCF (LabelNumber=1073042) +6489 169 -11 + +LocalizedSign 0xBCF (LabelNumber=1073043) +6484 169 -11 + +LocalizedSign 0xBCF (LabelNumber=1073044) +6478 176 -11 + +# Peerless Altar +# Arcane circle +Static 0x307F +6589 178 25 + +# Ankh +AnkhWest 0x0003 +6540 138 -15 + +# Key room moongate +Static 0xF6C (Hue=0x481) +6515 184 0 +6537 175 0 + +# Boss room red moongates +Static 0xDDA +6541 117 -15 +6523 136 -20 + +# Mobs +# Mage +Spawner 0x1F13 (Spawn=Mage; Count=1; HomeRange=2) +6579 184 32 + +# Wandering Healer +Spawner 0x1F13 (Spawn=WanderingHealer; Count=1; HomeRange=2) +6579 180 30 \ No newline at end of file diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Sanctuary.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Sanctuary.cfg new file mode 100644 index 0000000..db5a85a --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Sanctuary.cfg @@ -0,0 +1,11 @@ +# Items +# Traps +SpikeTrap 0x1D99 +6326 47 -20 +6327 46 -20 +6328 45 -20 +6368 78 -20 +6328 144 -20 +6326 140 -20 +6327 140 -20 + diff --git a/Data/Decoration/Mondain's Legacy/Trammel/Vesper.cfg b/Data/Decoration/Mondain's Legacy/Trammel/Vesper.cfg new file mode 100644 index 0000000..c15122c --- /dev/null +++ b/Data/Decoration/Mondain's Legacy/Trammel/Vesper.cfg @@ -0,0 +1,39 @@ +# Signs +LocalizedSign 0xBD2 (LabelNumber=1073409) +2926 980 -23 + +LocalizedSign 0xBD1 (LabelNumber=1073408) +2922 974 -23 + +LocalizedSign 0xBD2 (LabelNumber=1073410) +2920 984 -24 + +LocalizedSign 0xBD2 (LabelNumber=1073411) +2918 983 -20 + +LocalizedSign 0xBD2 (LabelNumber=1073412) +2912 984 -24 + +LocalizedSign 0xBD1 (LabelNumber=1073415) +2911 968 -22 + +LocalizedSign 0xBD1 (LabelNumber=1073416) +2915 963 -14 + +LocalizedSign 0xBD2 (LabelNumber=1073419) +2907 971 -22 + +LocalizedSign 0xBD2 (LabelNumber=1073418) +2908 976 -22 + +LocalizedSign 0xBD1 (LabelNumber=1073417) +2906 979 -27 + +LocalizedSign 0xBD1 (LabelNumber=1073413) +2912 978 -27 + +LocalizedSign 0xBD1 (LabelNumber=1073414) +2916 978 -27 + +LocalizedSign 0xBD1 (LabelNumber=1016415) +2920 963 0 diff --git a/Data/Decoration/RuinedMaginciaFel/Mag-Fel.cfg b/Data/Decoration/RuinedMaginciaFel/Mag-Fel.cfg new file mode 100644 index 0000000..68377ea --- /dev/null +++ b/Data/Decoration/RuinedMaginciaFel/Mag-Fel.cfg @@ -0,0 +1,7109 @@ +# stone ruins +Static 0x03B9 +3773 2220 12 +3771 2121 20 +3706 2062 5 +3781 2106 20 +3787 2101 26 +3713 2054 5 +3783 2118 20 +3733 2180 20 +3684 2233 20 +3703 2155 20 +3725 2143 20 +3758 2229 20 +3689 2194 20 +3791 2105 26 +3728 2200 20 +3654 2119 20 +3742 2068 5 +3701 2180 20 +3657 2112 20 +3699 2149 20 +3722 2053 5 +3727 2174 20 + +# fern +Static 0x0CA3 (Hue=0x3D9) +3583 2120 28 +3781 2107 20 +3579 2129 39 +3575 2127 34 +3567 2128 23 +3708 2157 20 +3605 2125 63 +3645 2087 20 +3619 2147 75 +3592 2142 65 + +# small palm +Static 0x0C9A (Hue=0x497) +3584 2163 44 +3561 2116 20 +3559 2143 25 +3739 2184 20 +3644 2082 20 +3592 2138 69 + +# grasses +Static 0x0D32 (Hue=0x497) +3586 2167 25 +3668 2045 20 +3592 2137 66 + +# tile roof +Static 0x05B4 +3693 2198 42 +3693 2194 42 +3692 2205 45 +3692 2204 45 +3692 2203 45 +3692 2198 45 +3692 2196 45 +3692 2192 45 +3691 2206 48 +3691 2204 48 +3691 2203 48 +3691 2202 48 +3691 2201 48 +3691 2200 48 +3691 2199 48 +3691 2198 48 +3691 2197 48 +3691 2196 48 +3695 2202 36 +3691 2194 48 +3691 2193 48 +3691 2192 48 +3695 2200 36 +3670 2261 46 +3694 2203 39 +3694 2195 39 +3693 2207 42 +3693 2204 42 +3693 2201 42 +3693 2199 42 +3693 2197 42 +3688 2261 40 +3692 2202 45 +3692 2193 45 +3691 2205 48 +3691 2195 48 +3695 2207 40 +3695 2204 36 +3695 2203 36 +3695 2199 36 +3695 2194 36 +3695 2193 36 +3694 2206 39 +3694 2205 39 +3694 2199 39 +3694 2197 39 +3693 2206 42 +3693 2203 42 +3693 2202 42 +3693 2200 42 +3693 2196 42 +3693 2195 42 +3693 2193 42 +3693 2192 42 +3686 2261 46 +3685 2261 49 +3692 2207 45 +3692 2206 45 +3692 2200 45 +3692 2199 45 +3692 2197 45 +3692 2195 45 +3692 2194 45 +3672 2261 40 +3691 2207 48 +3695 2198 36 +3695 2196 36 +3671 2261 43 +3669 2261 49 +3693 2205 42 +3692 2201 45 +3695 2206 39 +3695 2205 36 +3695 2201 36 +3695 2197 36 +3695 2195 36 +3695 2192 36 +3694 2207 39 +3687 2261 43 +3694 2204 39 +3694 2202 39 +3694 2201 39 +3694 2200 39 +3694 2198 39 +3694 2196 39 +3694 2194 39 +3694 2193 39 +3694 2192 39 + +# book +Static 0x0FF4 +3664 2254 24 +3664 2252 24 +3703 2211 44 + +# fern +Static 0x0CA4 (Hue=0x3DB) +3590 2142 62 +3537 2137 20 +3779 2080 22 +3754 2143 16 +3626 2202 20 +3636 2093 20 +3622 2157 61 +3629 2193 20 +3783 2134 29 + +# wooden ramp +Static 0x087D +3674 2229 20 +3677 2229 20 + +# sapling +Static 0x0CEA (Hue=0x3D9) +3579 2132 41 +3736 2240 20 +3792 2119 26 + +# fern +Static 0x0CA2 (Hue=0x3D8) +3585 2128 48 +3549 2163 20 +3683 2107 20 +3668 2101 20 +3643 2085 20 +3602 2104 20 +3649 2226 20 +3773 2132 20 +3598 2121 46 +3592 2125 49 + +# fern +Static 0x0C9F (Hue=0x497) +3596 2139 68 +3578 2125 34 +3587 2154 60 +3750 2137 21 +3660 2126 20 +3606 2164 41 +3627 2145 79 +3624 2151 74 +3611 2152 60 +3600 2175 22 +3598 2158 56 +3597 2121 45 + +# stone roof +Static 0x055D +3705 2210 60 +3686 2209 20 +3684 2212 20 +3700 2213 60 +3684 2209 20 +3682 2214 20 +3681 2211 20 +3698 2215 60 +3698 2211 60 +3704 2209 60 +3702 2211 60 +3701 2209 60 +3700 2215 60 +3700 2214 60 +3703 2213 60 +3697 2209 60 +3685 2212 20 +3697 2215 60 + +# garbage +Static 0x10F1 (Hue=0x3E1) +3546 2138 20 +3548 2140 20 +3547 2142 20 +3557 2165 20 +3555 2150 25 +3547 2140 20 +3539 2140 20 +3655 2065 20 +3553 2161 20 +3696 2122 20 + +# water tub +Static 0x0E7B +3722 2080 5 +3704 2206 20 +3705 2206 20 + +# sandstone stairs +Static 0x076D +3696 2212 25 +3698 2213 20 +3698 2212 25 +3698 2211 30 +3698 2210 35 +3697 2212 25 +3697 2211 30 +3697 2210 35 +3696 2213 20 +3696 2211 30 +3696 2210 35 +3697 2213 20 + +# tile roof +Static 0x05B3 +3690 2207 51 +3690 2206 51 +3690 2204 51 +3690 2203 51 +3690 2201 51 +3690 2200 51 +3690 2199 51 +3690 2198 51 +3690 2196 51 +3690 2195 51 +3690 2194 51 +3690 2193 51 +3690 2192 51 +3684 2261 52 +3690 2197 51 +3690 2205 51 +3668 2261 52 +3731 2154 20 + +# rock +Static 0x1777 +3540 2157 11 +3598 2150 61 +3651 2086 20 +3647 2075 20 +3591 2137 66 + +# large fern +Static 0x0CA1 (Hue=0x497) +3579 2160 41 +3550 2165 20 +3631 2103 20 +3633 2122 43 +3624 2210 20 +3770 2212 20 +3594 2120 43 +3591 2135 68 + +# chair +WoodenChairCushion 0x0B53 +3686 2184 20 +3683 2201 20 +3690 2184 20 + +# small palm +Static 0x0C9D (Hue=0x3D9) +3736 2250 20 +3591 2145 63 +3591 2128 55 + +# rock +Static 0x1778 +3689 2102 20 +3579 2133 42 +3571 2161 22 +3632 2167 60 +3795 2113 26 +3651 2080 20 +3636 2078 20 +3708 2176 20 +3743 2069 5 +3588 2131 58 +3800 2151 17 +3604 2137 68 +3591 2126 51 + +# fern +Static 0x0C9F (Hue=0x3D9) +3579 2130 39 +3547 2150 20 +3610 2156 59 +3646 2038 -15 +3623 2117 41 +3650 2223 20 +3737 2101 20 +3592 2153 60 + +# glow +Static 0x37B9 +3736 2173 20 +3737 2173 20 +3737 2176 20 +3734 2176 20 +3735 2173 20 +3734 2174 20 +3734 2175 22 + +# mushrooms +Static 0x0D12 (Hue=0x3D8) +3793 2127 28 + +# grasses +Static 0x0CAF (Hue=0x3DA) +3671 2085 20 +3612 2148 67 +3656 2144 20 +3590 2148 63 + +# grasses +Static 0x0CAC (Hue=0x3DB) +3554 2154 24 +3590 2142 62 + +# stone ruins +Static 0x03BD +3757 2231 20 +3683 2255 20 +3665 2137 20 +3697 2182 20 +3769 2094 20 +3785 2109 20 +3763 2231 20 +3699 2043 5 + +# fan plant +Static 0x0C98 (Hue=0x3DA) +3705 2200 20 +3627 2105 20 +3604 2114 33 +3590 2132 63 + +# sparkle +Static 0x377A +3735 2174 20 + +# stone step +Static 0x0917 (Hue=0x8AE) +3736 2175 20 +3736 2173 20 +3734 2175 20 +3734 2173 20 + +# stone wall +Static 0x0067 (Hue=0x8AE) +3736 2173 20 +3735 2173 20 +3734 2173 20 + +# stone wall +Static 0x0068 (Hue=0x8AE) +3734 2175 20 +3734 2174 20 +3734 2173 20 + +# bed +Static 0x0A5B +3688 2216 20 +3693 2217 20 +3693 2214 20 + +# stone roof +Static 0x0577 +3691 2217 40 +3691 2213 40 +3690 2215 40 +3689 2218 40 +3689 2214 40 +3689 2210 40 +3702 2216 40 +3692 2211 40 +3693 2215 40 +3693 2213 40 + +# fallen log +Static 0x0CF4 (Hue=0x497) +3542 2148 20 +3722 2248 20 +3590 2123 41 + +# fallen log +Static 0x0CF3 (Hue=0x497) +3634 2140 57 +3692 2114 20 +3614 2154 59 +3536 2151 20 +3789 2117 24 +3590 2122 41 + +# sapling +Static 0x0CE9 (Hue=0x3DA) +3779 2135 28 +3640 2099 22 +3593 2124 48 +3596 2124 53 + +# grasses +Static 0x0D33 (Hue=0x497) +3578 2122 25 +3593 2129 56 +3788 2112 25 + +# water barrel +Static 0x154D +3732 2026 -6 +3731 2025 -7 +3760 2230 31 +3732 2025 -8 +3732 2024 -5 +3760 2227 31 +3731 2024 -5 +3766 2225 31 +3760 2226 31 +3663 2290 -2 +3762 2225 31 +3760 2228 31 +3678 2281 6 +3693 2160 40 +3657 2091 20 +3760 2229 31 +3694 2198 20 +3657 2092 20 +3763 2225 31 +3760 2225 31 +3678 2288 -2 +3670 2282 -2 +3664 2291 -2 +3664 2290 -2 +3672 2261 21 +3665 2261 21 +3664 2261 21 +3765 2225 31 +3731 2026 -7 +3764 2225 31 +3704 2206 20 +3730 2025 -5 +3684 2017 -5 +3730 2024 -5 +3677 2281 9 +3705 2206 20 +3761 2225 31 +3683 2021 -5 + +# stone roof +Static 0x0578 +3692 2215 40 +3692 2213 40 +3691 2218 40 +3691 2211 40 +3690 2210 40 +3689 2216 40 +3689 2213 40 +3689 2211 40 +3693 2212 40 +3701 2216 40 +3702 2218 40 +3701 2215 40 +3691 2215 40 +3693 2217 40 +3693 2210 40 + +# stone roof +Static 0x0575 +3692 2216 40 +3692 2210 40 +3691 2212 40 +3695 2209 40 +3690 2214 40 +3689 2215 40 +3689 2209 40 +3695 2215 40 +3695 2214 40 +3695 2213 40 +3695 2211 40 +3694 2218 40 +3694 2213 40 +3695 2210 40 +3689 2212 40 +3695 2216 40 +3695 2212 40 +3695 2208 40 +3695 2207 40 +3694 2217 40 +3694 2216 40 +3694 2215 40 +3694 2214 40 +3694 2212 40 +3694 2211 40 +3694 2210 40 +3694 2209 40 +3694 2208 40 +3693 2218 40 +3693 2214 40 +3693 2211 40 +3693 2209 40 + +# table +Static 0x0B88 +3693 2208 20 + +# stone roof +Static 0x0571 +3692 2208 40 +3690 2208 40 +3689 2208 40 +3691 2208 40 +3694 2208 40 +3693 2208 40 + +# sandstone wall +Static 0x0159 +3691 2207 20 +3689 2207 20 +3687 2207 20 +3686 2207 20 +3685 2207 20 +3684 2207 20 +3683 2207 20 +3682 2207 20 +3681 2207 20 +3688 2207 20 +3694 2207 20 +3692 2207 20 +3690 2207 20 +3695 2207 20 +3680 2207 20 +3693 2207 20 + +# fern +Static 0x0CA0 (Hue=0x3D9) +3629 2147 74 +3651 2081 20 +3646 2089 20 +3631 2165 62 +3617 2149 68 +3613 2162 47 +3608 2119 44 +3601 2135 67 +3600 2133 68 +3584 2168 22 +3590 2139 66 +3589 2158 56 + +# metal signpost +Static 0x0B9B +3688 2196 20 + +# brass sign +LocalizedSign 0x0BD1 +3688 2196 20 + +# bulrushes +Static 0x0C94 (Hue=0x3DB) +3730 2250 20 +3638 2092 20 +3634 2140 57 +3656 2231 20 +3589 2150 63 + +# bulletin board +BulletinBoard 0x1E5F +3688 2161 20 +3688 2194 20 + +# small palm +Static 0x0C9C (Hue=0x3DB) +3710 2207 20 +3645 2084 20 +3650 2228 20 +3624 2205 9 +3625 2171 36 +3586 2159 50 + +# pampas grass +Static 0x0CC4 (Hue=0x3D8) +3580 2124 30 +3679 2110 20 +3611 2151 61 +3595 2137 69 + +# large fern +Static 0x0CA1 (Hue=0x3DA) +3721 2248 20 +3621 2187 8 +3683 2021 -15 +3641 2086 20 +3632 2102 20 +3627 2168 49 +3626 2150 79 +3613 2173 32 +3596 2150 62 +3711 2075 5 +3586 2168 23 + +# fern +Static 0x0CA0 (Hue=0x3D8) +3693 2149 20 +3787 2113 22 +3649 2119 21 +3629 2148 75 +3790 2117 25 +3593 2137 68 +3767 2089 24 +3590 2130 60 +3792 2119 26 + +# potted tree +PottedTree1 0x11C9 +3680 2214 20 +3680 2208 20 +3708 2222 40 +3708 2216 40 +3693 2200 20 + +# nodraw +Static 0x2198 +3556 2120 20 +3680 2144 20 +3549 2144 21 +3677 2230 20 +3674 2230 20 +3550 2140 25 +3545 2157 20 +3550 2137 25 +3556 2128 25 + +# sandstone table +Static 0x1DBB +3689 2204 20 +3690 2204 20 +3692 2204 20 +3691 2204 20 + +# fern +Static 0x0C9F (Hue=0x3DB) +3764 2220 20 +3618 2148 76 +3595 2123 50 +3655 2236 20 +3659 2237 20 +3770 2210 20 +3591 2132 66 +3588 2158 56 + +# stone ruins +Static 0x03C4 +3704 2253 20 +3691 2182 20 +3742 2223 20 +3701 2172 20 +3751 2117 20 +3758 2086 29 +3751 2219 20 +3698 2182 20 +3708 2174 20 +3640 2127 36 +3701 2176 20 +3684 2079 5 + +# fruit basket +FruitBasket 0x0993 +3719 2084 9 +3676 2100 24 +3772 2107 44 +3770 2106 24 +3683 2204 32 +3691 2164 24 + +# snake plant +Static 0x0CA9 (Hue=0x3D9) +3602 2127 64 +3786 2152 -15 +3588 2153 60 + +# bulrushes +Static 0x0C94 (Hue=0x3DA) +3604 2120 46 +3606 2159 52 +3594 2146 60 +3588 2149 64 + +# elephant ear plant +Static 0x0C97 (Hue=0x3D8) +3639 2079 20 +3609 2163 44 +3609 2137 78 +3609 2156 59 +3588 2147 63 + +# apple%s% +Static 0x09D0 +3661 2116 27 + +# wooden plank +Static 0x07CD +3673 2269 20 +3672 2285 -3 +3672 2266 20 +3671 2277 -3 +3671 2264 20 +3670 2291 -3 +3670 2290 -3 +3670 2289 -3 +3670 2270 20 +3670 2262 20 +3669 2296 -3 +3694 2299 -3 +3694 2297 -3 +3694 2296 -3 +3694 2295 -3 +3694 2293 -3 +3694 2292 -3 +3694 2291 -3 +3694 2290 -3 +3694 2288 -3 +3694 2287 -3 +3694 2286 -3 +3694 2284 -3 +3694 2283 -3 +3694 2281 -3 +3694 2279 -3 +3693 2296 -3 +3693 2293 -3 +3693 2292 -3 +3693 2289 -3 +3693 2288 -3 +3693 2285 -3 +3693 2284 -3 +3693 2283 -3 +3693 2280 -3 +3693 2279 -3 +3668 2299 -3 +3668 2297 -3 +3692 2299 -3 +3668 2294 -3 +3668 2292 -3 +3668 2291 -3 +3668 2290 -3 +3668 2289 -3 +3692 2297 -3 +3692 2296 -3 +3668 2266 20 +3692 2294 -3 +3692 2293 -3 +3692 2292 -3 +3692 2291 -3 +3692 2290 -3 +3692 2289 -3 +3692 2287 -3 +3692 2285 -3 +3692 2281 -3 +3692 2280 -3 +3691 2298 -3 +3691 2297 -3 +3691 2296 -3 +3691 2295 -3 +3691 2293 -3 +3691 2290 -3 +3691 2288 -3 +3691 2286 -3 +3691 2285 -3 +3691 2284 -3 +3691 2283 -3 +3691 2280 -3 +3690 2299 -3 +3690 2297 -3 +3690 2296 -3 +3690 2294 -3 +3690 2293 -3 +3690 2292 -3 +3690 2291 -3 +3690 2290 -3 +3690 2289 -3 +3690 2287 -3 +3690 2286 -3 +3690 2285 -3 +3690 2284 -3 +3690 2282 -3 +3690 2281 -3 +3690 2280 -3 +3667 2266 20 +3667 2265 20 +3667 2264 20 +3667 2262 20 +3689 2291 -3 +3689 2290 -3 +3689 2289 -3 +3666 2296 -3 +3666 2291 -3 +3688 2290 -3 +3688 2289 -3 +3687 2290 -3 +3687 2289 -3 +3687 2270 20 +3694 2280 -3 +3687 2269 20 +3687 2268 20 +3665 2266 20 +3665 2265 20 +3687 2267 20 +3687 2266 20 +3687 2265 20 +3687 2264 20 +3687 2263 20 +3687 2262 20 +3687 2261 20 +3686 2291 -3 +3686 2290 -3 +3686 2289 -3 +3686 2287 -3 +3686 2270 20 +3686 2269 20 +3686 2268 20 +3686 2267 20 +3686 2266 20 +3686 2264 20 +3686 2263 20 +3686 2262 20 +3686 2261 20 +3685 2290 -3 +3685 2289 -3 +3685 2288 -3 +3685 2270 20 +3685 2269 20 +3685 2268 20 +3685 2266 20 +3685 2265 20 +3685 2264 20 +3685 2263 20 +3684 2290 -3 +3684 2289 -3 +3684 2288 -3 +3684 2266 20 +3684 2265 20 +3684 2263 20 +3684 2262 20 +3677 2277 -3 +3683 2290 -3 +3683 2289 -3 +3683 2287 -3 +3683 2270 20 +3683 2268 20 +3683 2267 20 +3683 2266 20 +3683 2263 20 +3676 2264 20 +3653 2297 -3 +3682 2290 -3 +3682 2289 -3 +3682 2288 -3 +3682 2270 20 +3682 2269 20 +3682 2267 20 +3682 2265 20 +3682 2264 20 +3682 2261 20 +3681 2299 -3 +3681 2293 -3 +3681 2292 -3 +3681 2291 -3 +3681 2289 -3 +3681 2287 -3 +3681 2270 20 +3681 2269 20 +3681 2268 20 +3681 2267 20 +3681 2266 20 +3681 2264 20 +3681 2262 20 +3681 2261 20 +3664 2270 20 +3672 2269 20 +3680 2299 -3 +3680 2297 -3 +3680 2296 -3 +3680 2295 -3 +3680 2291 -3 +3680 2290 -3 +3680 2289 -3 +3672 2264 20 +3680 2287 -3 +3680 2270 20 +3680 2269 20 +3680 2268 20 +3680 2267 20 +3680 2264 20 +3671 2289 -3 +3679 2299 -3 +3679 2297 -3 +3679 2296 -3 +3679 2294 -3 +3679 2293 -3 +3679 2292 -3 +3679 2290 -3 +3679 2289 -3 +3679 2288 -3 +3679 2270 20 +3679 2267 20 +3679 2266 20 +3679 2265 20 +3679 2264 20 +3679 2263 20 +3670 2285 -3 +3694 2289 -3 +3678 2298 -3 +3678 2296 -3 +3678 2295 -3 +3678 2293 -3 +3678 2292 -3 +3694 2285 -3 +3678 2290 -3 +3678 2288 -3 +3678 2270 20 +3678 2269 20 +3678 2265 20 +3693 2297 -3 +3693 2295 -3 +3693 2290 -3 +3678 2264 20 +3678 2263 20 +3677 2299 -3 +3677 2298 -3 +3677 2296 -3 +3677 2294 -3 +3677 2293 -3 +3681 2263 20 +3677 2292 -3 +3677 2291 -3 +3677 2290 -3 +3693 2281 -3 +3677 2287 -3 +3677 2286 -3 +3677 2285 -3 +3677 2284 -3 +3677 2281 -3 +3677 2278 -3 +3677 2276 -3 +3677 2275 -3 +3692 2284 -3 +3692 2282 -3 +3677 2269 20 +3691 2292 -3 +3677 2267 20 +3677 2265 20 +3677 2264 20 +3691 2289 -3 +3676 2290 -3 +3676 2289 -3 +3691 2281 -3 +3676 2286 -3 +3676 2285 -3 +3676 2284 -3 +3676 2281 -3 +3676 2280 -3 +3676 2279 -3 +3676 2276 -3 +3676 2275 -3 +3676 2274 -3 +3690 2298 -3 +3676 2269 20 +3676 2268 20 +3676 2266 20 +3676 2265 20 +3676 2263 20 +3675 2290 -3 +3675 2288 -3 +3675 2286 -3 +3675 2285 -3 +3675 2280 -3 +3675 2278 -3 +3675 2276 -3 +3675 2275 -3 +3689 2287 -3 +3688 2288 -3 +3675 2269 20 +3675 2267 20 +3675 2266 20 +3687 2288 -3 +3675 2265 20 +3675 2263 20 +3674 2290 -3 +3674 2289 -3 +3674 2288 -3 +3674 2287 -3 +3674 2286 -3 +3674 2285 -3 +3674 2284 -3 +3674 2280 -3 +3674 2279 -3 +3674 2278 -3 +3674 2277 -3 +3674 2276 -3 +3674 2275 -3 +3674 2269 20 +3674 2268 20 +3674 2267 20 +3674 2265 20 +3674 2264 20 +3674 2263 20 +3673 2290 -3 +3673 2288 -3 +3673 2287 -3 +3673 2286 -3 +3673 2284 -3 +3673 2280 -3 +3673 2278 -3 +3673 2276 -3 +3685 2267 20 +3673 2274 -3 +3664 2268 20 +3664 2266 20 +3673 2270 20 +3673 2268 20 +3673 2266 20 +3673 2265 20 +3672 2291 -3 +3672 2290 -3 +3672 2289 -3 +3672 2288 -3 +3672 2286 -3 +3672 2284 -3 +3684 2264 20 +3672 2281 -3 +3672 2280 -3 +3672 2279 -3 +3672 2278 -3 +3672 2276 -3 +3672 2275 -3 +3672 2274 -3 +3683 2291 -3 +3672 2268 20 +3672 2265 20 +3671 2291 -3 +3671 2290 -3 +3671 2287 -3 +3671 2286 -3 +3671 2281 -3 +3671 2280 -3 +3671 2279 -3 +3671 2276 -3 +3671 2270 20 +3671 2267 20 +3671 2265 20 +3671 2263 20 +3671 2261 20 +3670 2299 -3 +3670 2298 -3 +3670 2297 -3 +3670 2296 -3 +3670 2295 -3 +3670 2293 -3 +3670 2292 -3 +3670 2288 -3 +3670 2287 -3 +3670 2286 -3 +3670 2280 -3 +3670 2279 -3 +3670 2278 -3 +3670 2277 -3 +3670 2276 -3 +3670 2275 -3 +3670 2268 20 +3670 2267 20 +3670 2266 20 +3670 2265 20 +3670 2264 20 +3670 2263 20 +3682 2262 20 +3670 2261 20 +3669 2299 -3 +3669 2297 -3 +3669 2295 -3 +3669 2293 -3 +3669 2292 -3 +3669 2290 -3 +3669 2289 -3 +3669 2288 -3 +3681 2298 -3 +3681 2297 -3 +3681 2296 -3 +3681 2295 -3 +3669 2270 20 +3669 2269 20 +3669 2268 20 +3669 2267 20 +3669 2266 20 +3669 2265 20 +3669 2264 20 +3681 2290 -3 +3669 2263 20 +3669 2261 20 +3681 2265 20 +3668 2296 -3 +3668 2293 -3 +3668 2287 -3 +3668 2268 20 +3668 2267 20 +3668 2265 20 +3668 2264 20 +3668 2261 20 +3667 2298 -3 +3667 2297 -3 +3667 2296 -3 +3667 2295 -3 +3667 2293 -3 +3680 2293 -3 +3667 2292 -3 +3667 2290 -3 +3667 2289 -3 +3667 2288 -3 +3667 2270 20 +3672 2267 20 +3667 2268 20 +3667 2267 20 +3667 2263 20 +3667 2261 20 +3666 2299 -3 +3666 2298 -3 +3666 2297 -3 +3666 2294 -3 +3666 2292 -3 +3666 2290 -3 +3666 2289 -3 +3666 2270 20 +3666 2269 20 +3666 2267 20 +3666 2265 20 +3666 2264 20 +3666 2263 20 +3666 2262 20 +3665 2291 -3 +3665 2290 -3 +3665 2289 -3 +3665 2287 -3 +3665 2269 20 +3665 2268 20 +3665 2267 20 +3665 2264 20 +3665 2263 20 +3665 2262 20 +3694 2298 -3 +3664 2290 -3 +3664 2289 -3 +3664 2288 -3 +3664 2269 20 +3664 2267 20 +3664 2265 20 +3664 2264 20 +3664 2263 20 +3664 2261 20 +3678 2297 -3 +3693 2299 -3 +3678 2289 -3 +3663 2290 -3 +3663 2289 -3 +3663 2288 -3 +3663 2270 20 +3663 2269 20 +3663 2268 20 +3678 2268 20 +3663 2267 20 +3663 2266 20 +3663 2265 20 +3663 2264 20 +3663 2262 20 +3663 2261 20 +3662 2291 -3 +3662 2290 -3 +3677 2297 -3 +3662 2289 -3 +3662 2287 -3 +3661 2290 -3 +3677 2289 -3 +3661 2289 -3 +3661 2288 -3 +3660 2290 -3 +3660 2289 -3 +3660 2288 -3 +3659 2291 -3 +3659 2290 -7 +3659 2289 -3 +3659 2287 -3 +3658 2291 -3 +3658 2290 -3 +3658 2290 -7 +3658 2289 -3 +3658 2288 -3 +3657 2299 -3 +3657 2298 -3 +3657 2297 -3 +3657 2296 -3 +3657 2295 -3 +3657 2293 -3 +3657 2292 -3 +3657 2291 -3 +3657 2290 -3 +3657 2289 -3 +3657 2288 -3 +3657 2287 -3 +3657 2286 -3 +3657 2285 -3 +3657 2284 -3 +3657 2283 -3 +3657 2281 -3 +3657 2280 -3 +3657 2279 -3 +3656 2299 -3 +3656 2297 -3 +3656 2296 -3 +3656 2295 -3 +3656 2293 -3 +3656 2292 -3 +3656 2291 -3 +3656 2290 -3 +3656 2289 -3 +3656 2287 -3 +3656 2285 -3 +3656 2284 -3 +3656 2283 -3 +3656 2281 -3 +3656 2280 -3 +3656 2279 -3 +3655 2299 -3 +3655 2297 -3 +3655 2296 -3 +3655 2294 -3 +3655 2293 -3 +3655 2292 -3 +3655 2290 -3 +3655 2289 -3 +3655 2288 -3 +3655 2285 -3 +3655 2284 -3 +3655 2282 -3 +3655 2281 -3 +3655 2280 -3 +3654 2298 -3 +3654 2297 -3 +3654 2296 -3 +3654 2295 -3 +3654 2293 -3 +3654 2292 -3 +3654 2290 -3 +3654 2289 -3 +3654 2288 -3 +3676 2291 -3 +3654 2286 -3 +3680 2292 -3 +3654 2285 -3 +3654 2284 -3 +3654 2283 -3 +3654 2281 -3 +3654 2280 -3 +3653 2299 -3 +3653 2298 -3 +3653 2296 -3 +3668 2263 20 +3690 2279 -3 +3653 2294 -3 +3653 2293 -3 +3676 2267 20 +3653 2292 -3 +3653 2291 -3 +3653 2290 -3 +3653 2289 -3 +3653 2287 -3 +3653 2286 -3 +3653 2285 -3 +3653 2284 -3 +3653 2282 -3 +3653 2281 -3 +3653 2280 -3 +3653 2279 -3 +3674 2274 -3 +3674 2270 20 +3666 2293 -3 +3666 2287 -3 +3666 2268 20 +3673 2277 -3 +3684 2269 20 +3684 2268 20 + +# pear%s% +Static 0x0994 +3661 2116 27 + +# pot +Static 0x09E0 +3690 2203 26 + +# sandstone table +Static 0x1DBD +3689 2202 20 +3689 2203 20 +3690 2203 20 +3691 2203 20 +3692 2203 20 + +# peach%es% +Static 0x09D2 +3661 2116 25 + +# grape bunch%es% +Static 0x09D1 +3661 2116 24 + +# fern +Static 0x0C9F (Hue=0x3D8) +3580 2124 34 +3730 2143 20 +3774 2144 16 +3633 2149 59 +3590 2107 22 +3627 2149 78 +3616 2149 69 +3537 2152 20 +3625 2145 82 +3607 2148 64 +3614 2131 79 +3616 2164 48 +3586 2142 64 + +# small palm +Static 0x0C9A (Hue=0x3D8) +3601 2137 67 +3625 2149 79 +3611 2158 58 +3586 2138 63 + +# rushes +Static 0x0CA7 (Hue=0x3D9) +3578 2126 36 +3642 2158 48 +3738 2087 5 +3662 2236 20 +3595 2146 60 +3600 2137 67 + +# sandstone table +Static 0x1DBC +3692 2202 20 +3691 2202 20 +3690 2202 20 + +# plate +Plate 0x09D7 +3683 2204 24 +3683 2203 24 +3683 2202 24 +3682 2204 24 +3682 2203 24 +3682 2202 24 +3720 2084 9 +3689 2204 26 +3692 2202 26 +3722 2084 9 +3692 2204 26 +3690 2204 26 +3691 2204 26 +3691 2202 26 +3690 2202 26 +3689 2202 26 + +# chair +WoodenChair 0x0B56 +3659 2117 20 +3659 2116 20 +3697 2062 5 +3700 2073 5 +3701 2211 40 +3717 2084 5 +3698 2073 5 +3689 2166 20 +3689 2164 20 + +# silverware +Static 0x09D4 +3683 2204 24 +3682 2204 24 +3690 2204 27 +3689 2204 27 +3720 2084 9 +3691 2204 27 +3692 2204 27 + +# fern +Static 0x0CA4 (Hue=0x497) +3557 2131 20 +3792 2101 24 +3640 2167 48 +3639 2099 22 +3628 2119 41 +3625 2111 37 +3620 2169 39 +3598 2137 68 +3589 2118 36 + +# fern +Static 0x0CA2 (Hue=0x3DB) +3585 2137 62 +3587 2105 -15 +3580 2119 24 +3641 2105 23 +3634 2105 23 +3584 2157 52 +3617 2158 60 +3622 2113 37 +3611 2161 50 +3612 2137 84 +3607 2156 58 +3650 2245 -15 +3609 2180 21 +3587 2154 60 + +# silverware +Static 0x09BE +3683 2202 24 +3682 2202 24 +3690 2202 27 +3691 2202 27 +3692 2202 27 +3689 2202 27 + +# grasses +Static 0x0CB6 (Hue=0x3D8) +3747 2212 20 +3587 2151 59 + +# small palm +Static 0x0C99 (Hue=0x3D9) +3669 2073 20 +3576 2127 36 +3572 2160 26 +3731 2256 20 +3626 2205 20 +3624 2170 39 +3736 2096 8 +3616 2108 22 +3630 2144 71 +3587 2147 63 + +# sandstone bench +Static 0x1DCA +3692 2201 20 +3692 2205 20 + +# tray +Static 0x0991 +3691 2203 26 + +# fern +Static 0x0CA3 (Hue=0x3DB) +3583 2160 46 +3578 2123 27 +3578 2130 38 +3636 2151 54 +3641 2083 20 +3637 2109 28 +3643 2066 20 +3613 2135 83 +3635 2103 22 +3620 2155 62 +3789 2116 25 +3794 2124 27 +3589 2141 65 +3587 2146 64 + +# candelabra +Static 0x0B1E +3656 2137 26 +3689 2203 26 +3692 2203 26 + +# stone ruins +Static 0x03B7 +3673 2214 20 +3718 2142 20 +3671 2222 20 +3717 2156 20 +3714 2150 20 +3781 2110 20 +3645 2200 20 +3733 2131 20 +3745 2145 20 +3779 2106 20 +3777 2098 20 +3658 2256 20 +3794 2117 26 + +# sandstone bench +Static 0x1DCC +3691 2201 20 +3690 2205 20 +3691 2205 20 +3690 2201 20 + +# sandstone bench +Static 0x1DCB +3689 2201 20 +3689 2205 20 + +# mushrooms +Static 0x0D10 (Hue=0x3DA) +3583 2156 54 + +# mushrooms +Static 0x0D0E (Hue=0x3D9) +3583 2152 59 + +# bulletin board +BulletinBoard 0x1E5E +3728 2216 20 + +# wooden door +DarkWoodDoor 0x06AF (Facing=NorthCCW) +3695 2250 20 + +# wooden door +DarkWoodDoor 0x06AD (Facing=SouthCW) +3695 2251 20 + +# small fish +Static 0x0DD8 +3683 2268 21 + +# gang plank +Static 0x3ED5 +3678 2281 -5 + +# ship +Static 0x3EB2 +3682 2281 -5 + +# hatch +Static 0x3EAE +3680 2277 -5 + +# +Static 0x4000 +3680 2281 -5 + +# fern +Static 0x0CA4 +3685 2197 20 +3685 2194 20 + +# large fern +Static 0x0CA1 +3684 2197 20 + +# chair +WoodenChairCushion 0x0B55 +3685 2204 20 +3685 2202 20 + +# grasses +Static 0x0CB5 (Hue=0x3DA) +3579 2124 31 + +# date palm +Static 0x0C96 +3684 2195 20 + +# bloody bandage%s% +Static 0x0E20 +3683 2224 24 + +# chair +WoodenChairCushion 0x0B54 +3683 2205 20 + +# coconut palm +Static 0x0C95 +3683 2196 20 + +# silverware +Static 0x09BD +3682 2203 24 + +# bulrushes +Static 0x0C94 +3685 2195 20 +3682 2196 20 + +# metal chest +MetalChest 0x09AB +3737 2147 20 + +# bench +Static 0x0B62 +3680 2212 20 + +# bench +Static 0x0B64 +3680 2211 20 + +# bench +Static 0x0B63 +3680 2210 20 + +# bottle of wine +Static 0x09C7 +3725 2218 24 + +# pampas grass +Static 0x0CA5 (Hue=0x497) +3580 2158 46 +3585 2129 49 + +# gravestone +Static 0x0EDC (Hue=0x52D) +3750 2241 20 + +# metal signpost +Static 0x0B9D +3673 2184 30 + +# fallen log +Static 0x0CF6 (Hue=0x3D9) +3572 2113 20 +3569 2163 21 + +# sewing kit +Static 0x0F9D +3666 2237 22 + +# mushrooms +Static 0x0D0D (Hue=0x3D8) +3771 2144 13 + +# tile roof +Static 0x05BD +3690 2202 51 + +# spool%s% of thread +Static 0x0FA0 +3668 2237 24 + +# metal chest +Metalchest 0x0E7C +3715 2086 5 + +# Garlic +Static 0x0F84 +3703 2209 25 + +# rock +Static 0x1772 +3560 2144 25 + +# Batwing%s% +Static 0x0F78 +3703 2208 24 + +# table +Static 0x0B89 +3689 2208 20 + +# scissors +Scissors 0x0F9E +3667 2237 22 +3665 2237 24 + +# globe +Static 0x1047 +3664 2256 20 + +# diamond%s% +Static 0x0F30 +3664 2134 24 + +# amethyst%s% +Static 0x0F2E +3664 2134 24 + +# citrine%s% +Static 0x0F2C +3664 2134 24 + +# star sapphire%s% +Static 0x0F1B +3664 2134 24 + +# rub%ies/y% +Static 0x0F2B +3664 2133 24 + +# rub%ies/y% +Static 0x0F1C +3664 2147 24 +3664 2145 24 +3664 2132 24 + +# amethyst%s% +Static 0x0F16 +3664 2132 24 + +# star sapphire%s% +Static 0x0F0F +3664 2133 24 +3664 2132 24 + +# emerald%s% +Static 0x0F10 +3664 2131 24 + +# MissingName +Static 0x1014 +3663 2229 20 + +# upright loom +Static 0x105F +3662 2238 20 +3662 2235 20 + +# upright loom +LoomEastAddon 0x1060 +3662 2237 20 +3662 2234 20 + +# spinning wheel +SpinningWheelEastAddon 0x1019 +3662 2231 20 + +# empty tile +Static 0x1018 +3662 2230 20 + +# Mage +LocalizedSign 0x0BAD +3712 2215 20 + +# grasses +Static 0x0CBA (Hue=0x3DA) +3537 2140 20 + +# mushroom +Static 0x0D19 (Hue=0x497) +3547 2151 20 + +# clock parts +Static 0x104F +3725 2128 24 + +# fallen log +Static 0x0CF7 (Hue=0x3D9) +3770 2132 20 + +# carpet +Static 0x0AD9 +3692 2205 20 +3691 2205 20 +3690 2205 20 +3689 2205 20 +3688 2205 20 + +# Tinker +LocalizedSign 0x0BA8 +3712 2136 20 + +# Inn +LocalizedSign 0x0BB3 +3704 2167 20 + +# Jeweler +LocalizedSign 0x0BC1 +3673 2184 30 + +# Tailor +LocalizedSign 0x0BA5 +3672 2232 20 + +# Tavern +LocalizedSign 0x0BC3 +3736 2230 20 + +# Shipwright +LocalizedSign 0x0BB6 +3669 2261 20 + +# bench +Static 0x0B5F +3723 2133 20 +3739 2217 20 + +# bottle +Static 0x0EFF +3696 2222 25 + +# Healer +LocalizedSign 0x0BAC +3685 2231 20 + +# Fishermens' Guild +LocalizedSign 0x0BF4 +3682 2261 20 + +# Bakery +LocalizedSign 0x0BA4 +3753 2232 20 +3681 2176 20 + +# Miners' Guild +LocalizedSign 0x0BED +3673 2138 24 + +# display case +Static 0x0B16 +3702 2209 20 + +# stone roof +Static 0x0565 +3687 2215 20 + +# cannon balls +Static 0x0E74 +3673 2261 20 + +# stone roof +Static 0x0568 +3687 2208 20 + +# carpet +Static 0x0AD4 +3687 2205 20 + +# carpet +Static 0x0AD6 +3687 2204 20 +3687 2203 20 +3687 2202 20 +3687 2201 20 + +# carpet +Static 0x0AD3 +3687 2200 20 + +# crate +MediumCrate 0x0E3F +3671 2279 -2 + +# crate +LargeCrate 0x0E3C +3670 2280 -2 + +# crate +MediumCrate 0x0E3E +3670 2280 1 + +# tile roof +Static 0x05B8 +3689 2201 48 +3688 2200 45 +3687 2199 42 + +# table +Static 0x0B79 +3671 2280 -2 + +# bed +Static 0x0A62 +3666 2268 21 +3666 2266 21 +3666 2264 21 + +# bed +Static 0x0A69 +3665 2264 21 + +# bed +Static 0x0A5E +3669 2262 21 + +# leather sleeves +Static 0x13C8 +3666 2261 20 + +# leather leggings +Static 0x13C9 +3669 2261 20 + +# leather tunic +Static 0x13CA +3670 2261 20 + +# bloody water +Static 0x0E23 +3684 2224 24 +3670 2262 20 + +# cannon +Static 0x0E8C +3677 2260 20 +3673 2260 20 + +# cannon +Static 0x0E8B +3677 2261 20 +3673 2261 20 + +# palisade +Static 0x0431 +3658 2248 20 + +# wooden ladder +Static 0x08A2 +3656 2234 31 +3656 2235 20 + +# tile roof +Static 0x05B6 +3689 2203 48 +3688 2204 45 +3687 2205 42 +3686 2206 39 +3685 2207 36 + +# rock +Static 0x34AE +3684 2017 -5 +3703 2021 -5 +3684 2019 -5 + +# mushroom +Static 0x0D18 (Hue=0x3DB) +3578 2132 41 +3770 2085 27 + +# pile%s% of wool +Static 0x101F +3663 2228 20 + +# bottle +Static 0x0EFD +3696 2227 26 + +# tray +Static 0x0992 +3661 2116 24 + +# small fish +Static 0x0DD6 +3667 2269 20 +3684 2268 20 + +# wooden door +DarkWoodDoor 0x06A7 (Facing=EastCCW) +3692 2199 20 + +# table +Static 0x0B71 +3683 2204 20 + +# sandstone arch +Static 0x016E +3695 2197 20 +3687 2214 20 +3782 2102 20 + +# blue moongate +Static 0x0F6C (Hue=0x484) +3563 2139 34 + +# small palm +Static 0x0C9A +3618 2149 80 +3761 2269 6 + +# baked pie +Static 0x1041 +3752 2227 24 +3680 2169 24 +3680 2171 24 +3752 2225 24 + +# mushroom +Static 0x0D19 (Hue=0x3D8) +3771 2067 -15 + +# fallen log +Static 0x0CF3 (Hue=0x3D8) +3716 2237 20 + +# gears +Static 0x1054 +3725 2126 24 + +# springs +Static 0x105D +3718 2131 24 +3719 2131 24 + +# table +Static 0x0B70 +3682 2204 20 + +# table +Static 0x0B73 +3683 2203 20 +3682 2203 20 +3682 2202 20 + +# gravestone +Static 0x0EDE +3712 2230 20 + +# gravestone +Static 0x1183 (Hue=0x66D) +3714 2235 20 + +# scroll%s% +Static 0x0EF5 +3696 2221 24 + +# dirt +Static 0x1E00 (Hue=0x3E4) +3545 2153 20 +3551 2150 22 +3718 2053 5 +3558 2132 20 +3712 2136 20 +3670 2249 20 +3552 2127 20 + +# fitting +Static 0x112F (Hue=0x3E1) +3559 2115 -15 + +# bookcase +FullBookcase 0x0A9C +3696 2245 20 + +# dirt patch +Static 0x0913 (Hue=0x1) +3739 2037 0 + +# window +Static 0x0163 +3685 2199 20 +3683 2199 20 +3681 2199 20 + +# roast pig%s% +Static 0x09BB +3720 2083 9 + +# sandstone wall +Static 0x0165 +3776 2104 20 +3686 2215 20 +3685 2215 20 +3684 2215 20 +3681 2215 20 +3680 2215 20 + +# stone roof +Static 0x0566 +3680 2215 20 + +# pile of garbage +Static 0x10F2 (Hue=0x3E1) +3552 2144 23 + +# gears +Static 0x1053 +3724 2131 24 +3723 2131 24 + +# chair +WoodenChairCushion 0x0B54 (Hue=0x1E) +3686 2184 20 + +# sextant parts +Static 0x105A +3720 2131 24 + +# rushes +Static 0x0CA7 (Hue=0x497) +3754 2085 28 +3608 2133 73 + +# springs +Static 0x105E +3714 2130 24 +3714 2129 24 + +# water +Static 0x34BF +3662 2296 -5 + +# pampas grass +Static 0x0CA5 +3628 2158 61 + +# fitting +Static 0x112F (Hue=0x3E3) +3775 2073 -15 + +# rolling pin +Static 0x1043 +3763 2216 24 + +# book +Static 0x0FBE +3685 2224 24 +3730 2228 24 + +# grasses +Static 0x0CB6 (Hue=0x3D9) +3759 2080 35 +3746 2064 5 +3672 2099 20 + +# fitting +Static 0x112F (Hue=0x3E4) +3557 2120 20 + +# pile of garbage +Static 0x10F2 (Hue=0x3E3) +3550 2134 20 + +# dirt patch +Static 0x0912 +3625 2211 20 +3551 2145 22 +3557 2165 20 +3702 2169 20 + +# grasses +Static 0x0D32 (Hue=0x3D8) +3657 2086 20 + +# blank scroll%s% +Static 0x0EF3 +3705 2224 24 + +# mushroom +Static 0x0D19 (Hue=0x3DB) +3771 2104 20 + +# sandstone arch +Static 0x0170 +3690 2199 20 +3705 2215 40 + +# sparkle +Static 0x376A +3675 2257 20 + +# teleporter +Static 0x1805 (Hue=0x45B) +3674 2256 20 + +# teleporter +Static 0x1807 (Hue=0x45B) +3675 2256 20 + +# teleporter +Static 0x180A (Hue=0x45B) +3676 2256 20 + +# teleporter +Static 0x1806 (Hue=0x45B) +3674 2257 20 + +# stone roof +Static 0x0562 +3680 2208 20 +3696 2208 60 + +# teleporter +Static 0x180C (Hue=0x45B) +3676 2257 20 + +# teleporter +Static 0x1808 (Hue=0x45B) +3674 2258 20 + +# teleporter +Static 0x180B (Hue=0x45B) +3675 2258 20 + +# teleporter +Static 0x180D (Hue=0x45B) +3676 2258 20 + +# flowerpot +PottedPlant 0x11CA +3772 2104 20 +3704 2221 40 +3704 2216 40 + +# book +Static 0x0FEF +3704 2211 44 + +# book +BlueBook 0x0FF2 +3702 2211 44 + +# dirt +Static 0x1DFE (Hue=0x3E2) +3684 2245 20 +3557 2128 20 + +# Ginseng +Static 0x0F85 +3705 2209 32 + +# Nox Crystal +Static 0x0F8E +3705 2209 20 + +# Mandrake Root%s% +Static 0x0F86 +3705 2209 24 + +# Daemon Blood +Static 0x0F7D +3705 2209 27 + +# Dragon's Blood +Static 0x0F82 +3705 2209 32 + +# rope +Static 0x14F8 +3663 2269 20 +3686 2261 21 +3678 2292 -3 + +# anchor +Static 0x14F7 +3678 2291 -3 + +# fallen log +Static 0x0CF5 (Hue=0x3D9) +3571 2165 21 +3593 2127 55 + +# sandstone wall +Static 0x015E +3695 2199 20 + +# rock +Static 0x1364 (Hue=0x15E) +3684 2186 20 + +# Blackmoor +Static 0x0F79 +3704 2209 24 + +# Daemon Bone%s% +Static 0x0F80 +3704 2209 28 + +# Bone%s% +Static 0x0F7E +3704 2209 26 + +# rock +Static 0x1365 (Hue=0x15E) +3683 2173 20 + +# palisade +Static 0x0424 +3647 2225 20 + +# grasses +Static 0x0CB0 (Hue=0x497) +3586 2154 59 + +# dirt patch +Static 0x0911 (Hue=0x3E1) +3550 2151 22 +3550 2165 20 +3557 2125 20 + +# post +Static 0x1296 +3691 2023 -7 + +# sign +Static 0x1F29 +3691 2023 6 + +# Red Potion +Static 0x0F0B +3696 2225 28 +3705 2224 22 + +# Yellow Potion +Static 0x0F0C +3696 2225 24 + +# Orange Potion +Static 0x0F07 +3705 2224 30 +3696 2222 24 + +# shells +Static 0x0FC6 +3708 2018 -7 + +# grasses +Static 0x0CAC (Hue=0x3DA) +3651 2064 20 + +# sandstone arch +Static 0x016F +3687 2210 20 +3695 2193 20 +3703 2217 20 + +# rope ladder +Static 0x08A6 +3667 2221 20 +3667 2213 20 +3667 2205 20 + +# wooden ladder +Static 0x08A0 +3672 2117 31 + +# sandstone wall +Static 0x0166 +3792 2102 24 +3703 2217 40 +3793 2111 27 +3679 2215 20 +3679 2214 20 +3679 2213 20 +3679 2212 20 +3679 2211 20 +3679 2210 20 +3679 2209 20 +3679 2208 20 +3703 2218 40 +3703 2216 40 + +# sapling +Static 0x0CEA (Hue=0x3D8) +3630 2165 62 +3634 2120 38 + +# wooden ladder +Static 0x08A4 +3676 2230 31 +3676 2231 20 +3675 2230 31 +3675 2231 20 +3682 2232 20 +3670 2186 20 + +# stone roof +Static 0x0567 +3686 2215 20 +3685 2215 20 +3684 2215 20 +3683 2215 20 +3682 2215 20 +3705 2215 60 +3704 2215 60 +3703 2215 60 +3681 2215 20 + +# metal chest +MetalChest 0x09AB (Hue=0x96F) +3741 2145 20 + +# dirt patch +Static 0x0912 (Hue=0x3E1) +3551 2162 20 +3672 2034 20 +3642 2121 33 + +# display case +Static 0x0B15 +3704 2210 20 +3705 2210 20 +3703 2210 20 + +# display case +Static 0x0B0F +3705 2209 20 +3704 2209 20 +3703 2209 20 + +# Blood Moss +Static 0x0F7B +3703 2209 29 + +# display case +Static 0x0B17 +3704 2208 20 +3705 2208 20 +3703 2208 20 + +# seaweed +Static 0x0DBB (Hue=0x497) +3675 2291 -2 + +# carpet +Static 0x0AD2 +3693 2205 20 + +# garbage +Static 0x10F1 (Hue=0x3E3) +3543 2145 20 +3556 2164 25 +3677 2230 20 +3662 2203 20 + +# chest of drawers +FancyDrawer 0x0A38 +3680 2157 20 +3680 2153 20 + +# log post +Static 0x0093 +3675 2270 0 +3675 2270 -15 + +# Green Potion +Static 0x0F0A +3696 2226 24 + +# candle +CandleLarge 0x0A26 +3767 2111 60 + +# dirt patch +Static 0x0912 (Hue=0x3E3) +3547 2150 20 +3548 2155 21 + +# seaweed +Static 0x0DBA (Hue=0x3DB) +3670 2294 -1 +3674 2290 -2 + +# sandstone arch +Static 0x016D +3694 2199 20 + +# chair +WoodenChairCushion 0x0B52 (Hue=0x1E) +3685 2202 20 + +# bookcase +FullBookcase 0x0A9B +3706 2208 40 +3697 2055 25 +3697 2056 5 +3701 2208 40 +3703 2208 40 +3701 2240 20 +3682 2200 20 + +# skull with candle +CandleSkull 0x1854 +3683 2202 26 +3683 2204 26 + +# statue +Static 0x1228 (Hue=0x96E) +3685 2200 26 + +# wooden chair +Static 0x0B30 +3684 2204 20 +3684 2202 20 + +# hinge%s% +Static 0x1055 +3718 2131 24 +3719 2131 24 + +# clock frame%s% +Static 0x104D +3718 2123 24 +3719 2131 24 + +# stone roof +Static 0x0569 +3702 2217 60 +3687 2214 20 +3687 2213 20 +3687 2212 20 +3687 2211 20 +3687 2210 20 +3687 2209 20 +3702 2218 60 +3702 2216 60 + +# wood +Static 0x1B81 (Hue=0x3E2) +3551 2145 22 +3548 2140 20 +3550 2133 20 +3549 2162 20 + +# stone roof +Static 0x062D +3702 2215 40 + +# stone roof +Static 0x0632 +3702 2215 60 + +# carpet +Static 0x0AC4 +3702 2214 20 + +# carpet +Static 0x0AD8 +3693 2204 20 +3693 2203 20 +3693 2201 20 +3693 2202 20 + +# pampas grass +Static 0x0CA5 (Hue=0x3D9) +3573 2168 20 +3637 2130 45 + +# water trough +Static 0x0B42 +3725 2039 52 + +# water trough +WaterTroughEastAddon 0x0B41 +3725 2038 52 + +# table +Static 0x0B85 +3702 2211 40 + +# carpet +Static 0x0AD5 +3693 2200 20 + +# blade plant +Static 0x0C93 (Hue=0x3DA) +3578 2125 31 +3655 2255 19 +3787 2136 29 + +# display case +Static 0x0B12 +3702 2210 20 + +# display case +Static 0x0AA1 +3702 2209 23 + +# display case +Static 0x0B10 +3702 2208 20 + +# candle +Static 0x0A11 +3707 2225 40 + +# candle +Static 0x0A10 +3680 2153 33 +3704 2228 40 +3707 2228 40 + +# chair +Static 0x0B4E (Hue=0x20) +3705 2250 20 + +# garbage +Static 0x10F0 (Hue=0x3E3) +3552 2143 21 +3737 2068 5 +3748 2061 11 + +# mushrooms +Static 0x0D10 (Hue=0x3D8) +3589 2110 24 +3646 2082 20 +3636 2132 49 + +# candle +Static 0x0B1C +3680 2258 28 +3772 2108 44 + +# bread loa%ves/f% +Static 0x103C +3681 2168 24 +3757 2216 24 +3756 2216 24 + +# sapling +Static 0x0CEA (Hue=0x497) +3736 2256 20 +3644 2071 20 + +# table +Static 0x0B3C +3685 2200 20 +3688 2200 20 + +# Spider's Silk +Static 0x0F8D +3705 2210 30 + +# mushrooms +Static 0x0D15 (Hue=0x3D9) +3677 2086 23 +3654 2080 20 + +# carpet +Static 0x0AF8 +3701 2217 20 +3701 2218 20 + +# stone roof +Static 0x0576 +3691 2209 40 +3690 2213 40 +3690 2211 40 +3689 2217 40 +3693 2216 40 +3701 2218 40 +3695 2218 40 +3695 2217 40 +3702 2215 40 +3692 2218 40 +3692 2214 40 +3692 2212 40 + +# morning glories +Static 0x0D34 (Hue=0x3D9) +3646 2087 20 + +# table +Static 0x0B8D +3691 2208 20 +3690 2208 20 +3692 2208 20 + +# chair +Static 0x0B4E (Hue=0x26) +3682 2254 20 + +# grasses +Static 0x0CB6 (Hue=0x3DB) +3649 2084 20 + +# fallen log +Static 0x0CF3 (Hue=0x3D9) +3588 2148 62 +3644 2088 20 + +# fallen log +Static 0x0CF7 (Hue=0x3DA) +3649 2083 20 + +# sextant parts +Static 0x1059 +3723 2123 24 + +# mushrooms +Static 0x0D0C (Hue=0x3D8) +3772 2144 16 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +3735 2147 20 + +# cookie mix +Static 0x103F +3680 2170 24 +3762 2216 24 + +# chess pieces +Static 0x0FA8 +3726 2218 24 + +# roast pig%s% +Static 0x09BC +3690 2165 24 +3660 2117 24 + +# dice and cup +Dices 0x0FA7 +3722 2229 24 + +# playing cards +Static 0x0FA2 +3722 2226 24 + +# fallen log +Static 0x0CF5 (Hue=0x3DA) +3542 2157 10 +3649 2082 20 + +# mug +CeramicMug 0x0998 +3722 2225 24 + +# mug of ale +GlassMug 0x09EE +3722 2222 24 + +# grasses +Static 0x0CB5 (Hue=0x3DB) +3655 2071 20 + +# goblet +Static 0x099A +3722 2217 24 + +# mushroom +Static 0x0D17 (Hue=0x3DA) +3641 2096 21 + +# sapling +Static 0x0CEA (Hue=0x3DA) +3584 2156 54 +3640 2088 20 + +# small palm +Static 0x0C9D (Hue=0x497) +3560 2125 20 +3642 2102 23 +3644 2086 20 + +# pampas grass +Static 0x0CA5 (Hue=0x3D8) +3641 2080 20 + +# blade plant +Static 0x0C93 (Hue=0x3DB) +3583 2168 21 +3573 2119 22 +3540 2156 19 +3756 2086 28 +3643 2094 21 + +# flowerpot +PottedPlant1 0x11CB +3760 2113 20 +3760 2110 20 + +# rock +Static 0x1773 +3580 2157 47 +3576 2159 37 +3564 2164 20 +3652 2078 20 + +# spittoon +Static 0x1003 +3720 2216 20 + +# display case +Static 0x0AA2 +3705 2208 24 +3703 2208 24 +3704 2208 23 + +# rushes +Static 0x0CA7 (Hue=0x3DA) +3583 2129 44 +3581 2155 52 +3614 2144 81 +3611 2164 43 + +# wooden bench +WoodenBench 0x0B2D +3705 2201 20 +3705 2192 20 +3704 2201 20 +3704 2192 20 + +# dirt patch +Static 0x0911 (Hue=0x3E4) +3555 2158 22 +3550 2141 20 +3665 2202 20 + +# mushrooms +Static 0x0D15 (Hue=0x497) +3636 2084 20 + +# fishing pole +Static 0x0DC0 +3682 2268 21 +3667 2269 21 + +# grasses +Static 0x0CB6 (Hue=0x3DA) +3749 2081 24 +3636 2146 54 +3639 2105 25 +3629 2150 76 + +# metal chest +MetalChest 0x09AB (Hue=0x971) +3739 2146 20 + +# carpet +Static 0x0AE9 +3700 2218 41 + +# carpet +Static 0x0AE6 +3700 2217 41 + +# oven +StoneOvenSouthAddon 0x0930 +3754 2215 20 + +# oven +Static 0x0931 +3753 2215 20 +3753 2215 20 + +# sapphire%s% +Static 0x0F11 +3664 2132 24 + +# bottle of ale +Static 0x099F +3729 2228 24 +3728 2228 26 +3722 2216 24 +3722 2224 24 +3727 2228 26 + +# small palm +Static 0x0C9D (Hue=0x3DA) +3658 2058 20 +3608 2163 43 +3632 2114 35 + +# scroll%s% +Static 0x0EF9 +3709 2224 24 + +# scroll%s% +Static 0x0EF7 +3707 2224 24 + +# stone roof +Static 0x0574 +3692 2209 40 +3691 2214 40 +3690 2218 40 +3690 2209 40 +3703 2214 40 +3702 2217 40 +3702 2214 40 +3690 2212 40 + +# fallen log +Static 0x0CF3 (Hue=0x3DA) +3635 2089 20 + +# grasses +Static 0x0CB5 (Hue=0x497) +3769 2125 20 +3639 2083 20 + +# mushrooms +Static 0x0D12 (Hue=0x3D9) +3581 2126 38 +3636 2104 25 + +# oven +Static 0x092B +3751 2218 20 + +# stone roof +Static 0x056B +3703 2217 40 +3703 2218 40 +3703 2216 40 + +# grasses +Static 0x0CB0 (Hue=0x3D8) +3639 2093 20 +3634 2095 20 + +# hanging lantern +HangingLantern 0x0A1A +3732 2147 29 +3684 2171 20 + +# mushrooms +Static 0x0D11 (Hue=0x497) +3640 2101 24 + +# carpet +Static 0x0AD1 +3692 2204 20 +3692 2203 20 +3691 2204 20 +3691 2203 20 +3691 2202 20 +3691 2201 20 +3691 2201 40 +3690 2204 20 +3690 2203 20 +3690 2202 20 +3690 2201 20 +3689 2204 20 +3689 2203 20 +3689 2202 20 +3689 2201 20 +3688 2203 20 +3688 2202 20 +3688 2201 20 +3688 2204 20 +3692 2202 20 +3692 2201 20 +3690 2202 40 + +# table +Static 0x0B86 +3736 2084 5 +3705 2211 40 +3704 2211 40 +3703 2211 40 + +# wall sconce +Static 0x0A04 +3700 2208 50 + +# grasses +Static 0x0CBD (Hue=0x3D9) +3654 2220 20 + +# small fish +Static 0x0DD7 +3685 2266 20 +3670 2297 -3 + +# chest of drawers +FancyDrawer 0x0A30 +3661 2096 20 + +# fan plant +Static 0x0C98 (Hue=0x3D8) +3640 2107 24 + +# fallen log +Static 0x0CF4 (Hue=0x3D9) +3792 2121 26 + +# pickaxe +Static 0x0E86 +3656 2138 24 + +# fallen log +Static 0x0CF3 (Hue=0x3DB) +3592 2151 53 +3562 2119 20 +3638 2092 20 +3618 2108 24 + +# small palm +Static 0x0C9C (Hue=0x3D9) +3757 2083 30 +3610 2160 53 +3615 2172 33 +3611 2152 60 +3624 2107 21 +3615 2106 21 + +# ponytail palm +Static 0x0CA6 (Hue=0x3DA) +3717 2249 20 +3615 2105 20 + +# mushroom +Static 0x0D16 (Hue=0x497) +3612 2105 20 + +# wood +Static 0x1B81 (Hue=0x3E3) +3542 2140 20 +3661 2038 20 +3745 2058 5 +3552 2162 20 + +# citrine%s% +Static 0x0F23 (Hue=0x497) +3546 2122 22 + +# book +Static 0x0FBD +3680 2254 24 +3670 2236 20 +3669 2236 24 +3664 2255 24 +3656 2194 24 +3683 2203 26 +3752 2221 24 +3699 2210 24 + +# axle%s% with gears +Static 0x1052 +3719 2123 24 +3722 2123 24 +3723 2131 24 +3724 2131 24 + +# snake plant +Static 0x0CA9 (Hue=0x3DB) +3740 2124 20 +3599 2140 69 + +# pampas grass +Static 0x0CC4 (Hue=0x3DA) +3630 2139 68 +3627 2145 79 + +# grasses +Static 0x0CAF (Hue=0x3D8) +3585 2127 45 +3591 2107 22 + +# rock +Static 0x34AC +3703 2023 -5 +3695 2023 -5 +3692 2020 -5 +3693 2022 -5 + +# glass of water +Static 0x1F91 +3722 2222 24 + +# bottle of liquor +Static 0x099B +3728 2228 29 +3727 2228 29 +3730 2218 24 + +# sandstone post +Static 0x0167 +3692 2207 40 +3690 2207 40 +3690 2207 47 +3689 2207 47 +3687 2213 40 +3687 2210 40 +3687 2207 40 +3705 2215 40 +3705 2215 60 +3705 2215 50 +3689 2207 40 + +# snake plant +Static 0x0CA9 (Hue=0x3DA) +3585 2147 65 +3627 2114 36 + +# mushrooms +Static 0x0D14 (Hue=0x3DB) +3773 2216 20 + +# shell +Static 0x0FC8 +3717 2032 4 + +# garbage +Static 0x10F1 (Hue=0x3E2) +3558 2146 25 +3555 2126 20 +3743 2073 5 +3769 2067 20 +3557 2145 23 + +# carpet +Static 0x0ABE +3700 2218 20 +3700 2217 20 +3705 2213 20 +3705 2212 20 +3704 2213 20 +3704 2212 20 +3703 2213 20 +3703 2212 20 +3699 2218 20 +3699 2217 20 + +# armoire +Armoire 0x0A53 +3768 2111 40 + +# carpet +Static 0x0AF7 +3705 2211 20 +3703 2211 20 +3704 2211 20 +3700 2216 20 +3699 2216 20 + +# chair +FancyWoodenChairCushion 0x0B51 (Hue=0x3F) +3773 2104 20 +3769 2117 20 + +# dirt +Static 0x1E00 (Hue=0x3E2) +3554 2120 23 +3714 2218 20 +3553 2130 25 +3551 2130 20 +3764 2059 20 +3680 2060 6 +3559 2130 20 + +# bottle +Static 0x0F04 +3696 2226 29 + +# scroll%s% +Static 0x0EF4 +3696 2223 24 + +# emerald%s% +Static 0x0F2F +3664 2146 24 +3664 2148 24 + +# citrine%s% +Static 0x0F23 +3664 2146 24 +3664 2132 24 +3664 2148 24 + +# amethyst%s% +Static 0x0F22 +3664 2146 24 +3664 2148 24 + +# rub%ies/y% +Static 0x0F2A +3664 2147 24 + +# diamond%s% +Static 0x0F27 +3664 2134 24 +3664 2147 24 + +# tourmaline%s% +Static 0x0F20 +3664 2145 24 +3664 2134 24 +3664 2147 24 + +# sapphire%s% +Static 0x0F1F +3664 2147 24 + +# table +Static 0x0B6D +3765 2095 20 + +# table +Static 0x0B75 +3671 2282 -2 +3699 2211 20 + +# hanging lantern +Static 0x0A1D +3684 2171 20 +3732 2147 29 + +# lilypad +Static 0x0D09 (Hue=0x3DB) +3699 2192 18 + +# grasses +Static 0x0CB6 (Hue=0x497) +3630 2113 35 + +# stone roof +Static 0x0570 +3688 2217 40 +3688 2216 40 +3688 2215 40 +3688 2214 40 +3688 2213 40 +3688 2212 40 +3688 2211 40 +3688 2210 40 +3688 2209 40 +3688 2218 40 + +# tree +Static 0x0D5A (Hue=0x497) +3631 2109 28 +3619 2149 67 +3601 2129 66 +3595 2144 63 +3595 2134 68 +3583 2159 45 +3559 2144 24 +3661 2089 20 + +# dirt +Static 0x1DFE (Hue=0x3E3) +3556 2162 21 +3659 2057 20 +3536 2132 -15 +3559 2127 20 +3726 2065 5 + +# wheel%s% of cheese +Static 0x097E +3684 2168 24 + +# cake +Static 0x09E9 +3759 2216 24 +3757 2226 24 +3757 2225 24 +3757 2227 24 +3683 2168 24 + +# display case +Static 0x0AA5 +3702 2210 24 + +# stone ruins +Static 0x03BF +3708 2159 20 +3692 2176 20 +3718 2152 20 +3765 2126 20 +3638 2066 20 +3677 2070 23 +3744 2225 20 +3775 2105 20 +3722 2144 20 +3769 2113 20 +3709 2250 20 +3688 2111 20 +3761 2231 20 +3772 2107 20 +3738 2099 20 +3785 2115 20 +3760 2080 37 + +# candle +Static 0x0B1B +3681 2184 28 +3664 2253 26 +3715 2090 13 +3696 2152 28 +3691 2184 28 +3690 2248 28 + +# cannon +Static 0x0E94 +3697 2257 20 + +# garbage +Static 0x10F0 (Hue=0x3E4) +3559 2130 20 +3550 2155 22 +3658 2171 20 + +# display case +Static 0x0AA3 +3702 2208 24 + +# carpet +Static 0x0AED +3699 2218 41 +3698 2218 41 + +# carpet +Static 0x0AE8 +3699 2217 41 +3698 2217 41 + +# carpet +Static 0x0AF6 +3702 2212 20 +3702 2213 20 +3698 2218 20 +3698 2217 20 + +# stone roof +Static 0x0561 +3702 2210 60 +3686 2214 20 +3686 2213 20 +3686 2211 20 +3683 2212 20 +3682 2211 20 +3681 2214 20 +3702 2213 60 +3700 2217 60 +3699 2212 60 +3699 2210 60 +3698 2217 60 + +# mushrooms +Static 0x0D0F (Hue=0x3DA) +3617 2152 60 + +# carpet +Static 0x0AD7 +3691 2200 20 +3690 2200 20 +3692 2200 20 +3689 2200 20 +3688 2200 20 + +# carpet +Static 0x0AC3 +3702 2211 20 +3698 2216 20 + +# sandstone floor +Static 0x052B +3705 2215 40 +3704 2211 40 +3704 2209 40 +3697 2218 40 +3705 2217 40 +3704 2213 40 +3702 2211 40 +3702 2209 40 +3700 2216 40 +3700 2215 40 +3700 2213 40 +3700 2211 40 +3700 2209 40 +3699 2209 40 +3699 2208 40 +3702 2213 40 +3698 2216 40 + +# small palm +Static 0x0C9B (Hue=0x3D8) +3621 2113 36 +3782 2147 14 +3794 2123 27 +3643 2103 22 +3582 2156 51 + +# grasses +Static 0x0CB5 (Hue=0x3D8) +3582 2157 50 +3788 2112 25 +3623 2161 55 + +# fallen log +Static 0x0CF6 (Hue=0x3DA) +3564 2135 26 +3654 2070 20 +3622 2155 63 + +# wooden banister +Static 0x08B6 +3698 2214 40 + +# chair +WoodenChairCushion 0x0B52 +3681 2204 20 +3681 2202 20 +3688 2197 20 +3688 2193 20 + +# wooden banister +Static 0x08B8 +3698 2213 40 +3698 2212 27 +3698 2211 40 + +# wooden banister +Static 0x08B9 +3698 2210 40 + +# grasses +Static 0x0D33 (Hue=0x3D8) +3616 2149 69 + +# sandstone post +Static 0x015B +3690 2199 20 +3703 2217 20 +3687 2213 20 +3687 2210 20 +3695 2193 20 +3679 2207 20 +3695 2196 20 +3693 2199 20 + +# spellbook +Static 0x0EFA +3696 2217 24 +3696 2219 24 +3706 2211 44 +3696 2218 24 + +# bunch%es% of dates +Static 0x1727 +3686 2194 20 +3682 2193 20 +3684 2195 20 +3682 2196 20 +3686 2196 20 + +# carpet +Static 0x0AC5 +3701 2216 20 + +# stone roof +Static 0x0573 +3692 2217 40 +3691 2216 40 +3691 2210 40 +3690 2217 40 +3690 2216 40 +3701 2217 40 +3701 2214 40 + +# sandstone wall +Static 0x0250 +3696 2207 20 +3700 2207 20 +3704 2215 20 +3704 2207 20 +3702 2207 20 +3698 2207 20 + +# bookcase +FullBookcase 0x0A9A +3664 2251 20 +3696 2246 20 +3691 2075 5 + +# sandstone wall +Static 0x015A +3687 2218 20 +3687 2216 20 +3687 2209 20 +3687 2208 20 +3687 2199 20 +3687 2198 20 +3687 2192 20 +3687 2215 20 + +# armoire +FancyArmoire 0x0A4D +3700 2152 20 +3687 2200 20 +3690 2152 20 + +# chair +Static 0x0B4F (Hue=0x1E) +3666 2255 20 + +# fallen log +Static 0x0CF7 (Hue=0x3DB) +3563 2142 31 +3686 2088 16 +3665 2070 20 +3620 2152 64 +3645 2193 20 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x96E) +3741 2146 20 +3741 2144 20 + +# wooden chest +WoodenChest 0x0E43 (Hue=0x971) +3739 2147 20 +3737 2146 20 +3739 2144 20 + +# metal chest +MetalGoldenChest 0x0E41 (Hue=0x96F) +3737 2145 20 +3737 2144 20 +3741 2147 20 +3739 2145 20 + +# grasses +Static 0x0CAC (Hue=0x497) +3742 2124 20 +3772 2097 22 + +# fern +Static 0x0C9F +3684 2196 20 + +# display case +Static 0x0AA0 +3705 2210 24 +3703 2210 24 +3704 2210 24 + +# fern +Static 0x0CA4 (Hue=0x3D9) +3637 2085 20 +3647 2119 22 +3641 2085 20 +3635 2101 21 +3598 2133 67 +3601 2160 48 +3657 2182 20 + +# tree +Static 0x0D41 (Hue=0x497) +3610 2147 78 +3598 2137 67 +3586 2147 62 +3586 2137 59 +3580 2157 54 +3580 2127 38 +3634 2087 20 +3598 2142 70 +3640 2092 20 + +# axle%s% with gears +Static 0x1051 +3725 2127 24 +3714 2126 24 + +# goblet +Static 0x09CB +3683 2203 24 +3682 2204 24 +3682 2203 24 +3770 2108 24 +3770 2107 24 +3683 2204 24 + +# fern +Static 0x0CA0 +3683 2195 20 + +# armoire +FancyArmoire 0x0A51 +3680 2185 20 +3680 2189 20 +3656 2096 20 +3689 2185 20 + +# window +Static 0x015D +3687 2197 20 +3687 2195 20 +3687 2193 20 +3687 2196 20 +3687 2194 20 + +# coconut%s% +Static 0x1726 +3684 2196 20 +3682 2197 20 +3681 2196 20 +3681 2198 20 + +# rope +Static 0x14FA +3678 2298 -3 +3691 2292 -3 +3680 2261 21 +3679 2270 21 +3666 2262 20 + +# carpet +Static 0x0AE4 +3697 2217 41 + +# fallen log +Static 0x0CF6 (Hue=0x497) +3635 2080 20 +3642 2092 20 +3576 2121 24 + +# dirt patch +Static 0x0911 (Hue=0x3E2) +3546 2149 20 +3556 2146 23 +3625 2207 20 +3725 2056 5 +3556 2123 20 +3756 2058 21 +3537 2141 20 +3548 2138 20 +3557 2118 20 + +# axle%s% +Static 0x105C +3714 2129 24 +3714 2130 24 + +# tree +Static 0x0D71 (Hue=0x497) +3787 2114 20 +3637 2139 55 +3619 2159 56 +3601 2149 63 +3583 2129 43 +3577 2159 35 +3565 2164 20 +3787 2119 24 +3601 2144 64 +3643 2084 20 +3637 2104 25 + +# tree +Static 0x0D6E (Hue=0x497) +3784 2122 24 +3634 2142 55 +3616 2162 50 +3784 2117 20 +3598 2152 61 +3598 2147 65 +3580 2132 42 +3574 2162 22 +3562 2167 20 +3640 2087 20 +3634 2107 25 + +# tile roof +Static 0x05BF +3689 2202 51 +3688 2202 51 +3687 2202 51 +3685 2202 51 +3684 2202 51 +3683 2202 51 +3682 2202 51 +3681 2202 51 +3680 2202 51 +3679 2202 51 +3686 2202 51 + +# stone roof +Static 0x0560 +3705 2209 60 +3704 2212 60 +3686 2212 20 +3685 2211 20 +3683 2211 20 +3683 2209 20 +3682 2213 20 +3705 2213 60 +3705 2211 60 +3703 2211 60 +3701 2217 60 +3701 2213 60 +3699 2217 60 +3699 2209 60 +3698 2212 60 +3701 2211 60 +3697 2217 60 +3697 2213 60 +3697 2211 60 + +# wooden shelf +EmptyBookcase 0x0A9D +3717 2120 20 +3721 2120 20 +3721 2080 5 +3720 2080 5 +3722 2120 20 +3716 2120 20 + +# tree +Static 0x0D86 (Hue=0x497) +3619 2144 82 +3607 2149 61 +3577 2119 23 +3649 2074 20 +3643 2099 22 +3637 2109 28 +3637 2099 20 + +# tree +Static 0x0D84 (Hue=0x497) +3617 2146 80 +3605 2151 61 +3575 2121 23 +3647 2076 20 +3641 2101 23 +3635 2111 29 +3635 2101 20 + +# tree +Static 0x0D85 (Hue=0x497) +3576 2120 23 +3618 2145 82 +3606 2150 61 +3648 2075 20 +3642 2100 23 +3636 2110 29 +3636 2100 20 + +# stone roof +Static 0x055E +3685 2213 20 +3685 2209 20 +3684 2210 20 +3683 2214 20 +3682 2209 20 +3681 2212 20 +3697 2216 60 +3697 2214 60 +3704 2214 60 +3703 2209 60 +3702 2212 60 +3701 2210 60 +3700 2218 60 +3700 2210 60 +3699 2216 60 +3699 2213 60 +3698 2218 60 +3698 2209 60 +3701 2216 60 +3701 2214 60 +3697 2210 60 + +# bookcase +FullBookcase 0x0A97 +3702 2208 40 +3696 2056 5 +3699 2240 20 +3702 2240 20 +3759 2120 20 +3707 2208 40 +3705 2208 40 +3666 2248 20 +3773 2104 40 + +# mug of ale +Static 0x09EF +3722 2218 24 +3731 2221 24 + +# anchor +Static 0x14F9 +3690 2292 -3 +3665 2262 21 + +# dirt +Static 0x1DFF (Hue=0x3E1) +3549 2142 20 +3716 2185 20 +3552 2159 21 +3557 2135 20 +3557 2127 20 +3680 2254 20 + +# pitcher of water +Static 0x1F9D +3722 2228 24 +3770 2107 24 + +# wooden plank +Static 0x07D0 +3670 2281 -3 +3685 2262 20 +3684 2267 20 +3680 2262 20 +3677 2263 20 +3668 2262 20 +3675 2284 -3 +3675 2274 -3 +3672 2270 20 +3671 2269 20 +3665 2261 20 + +# rushes +Static 0x0CA7 (Hue=0x3D8) +3647 2081 20 +3617 2151 65 + +# sandstone wall +Static 0x0251 +3695 2218 20 +3695 2216 20 +3695 2214 20 +3695 2210 20 +3695 2212 20 +3695 2208 20 + +# sandstone wall +Static 0x0256 +3705 2215 20 +3701 2207 20 +3705 2207 20 +3703 2207 20 +3699 2207 20 +3697 2207 20 + +# stone roof +Static 0x0572 +3688 2208 40 +3697 2206 40 + +# rock +Static 0x1776 +3747 2031 -5 +3742 2029 -5 +3747 2035 -5 +3686 2028 -5 +3745 2029 -5 +3720 2017 -3 +3683 2028 -5 +3719 2017 -3 +3719 2016 -2 + +# no draw +Static 0x21A4 +3760 2247 -5 +3765 2244 -5 +3765 2249 -5 +3773 2247 -5 +3773 2242 -5 +3768 2246 -5 + +# tree +Static 0x0D44 (Hue=0x497) +3613 2144 78 +3601 2134 67 +3589 2144 62 +3589 2134 59 +3583 2154 54 +3583 2124 38 +3601 2139 69 +3643 2089 20 +3637 2084 20 + +# tree +Static 0x0D42 (Hue=0x497) +3611 2146 78 +3599 2141 70 +3599 2136 67 +3587 2146 62 +3587 2136 59 +3581 2156 54 +3581 2126 38 +3641 2091 20 +3635 2086 20 + +# mushroom +Static 0x0D16 (Hue=0x3DA) +3608 2118 41 + +# tree +Static 0x0D43 (Hue=0x497) +3612 2145 78 +3600 2140 70 +3588 2145 62 +3588 2135 59 +3582 2155 54 +3582 2125 38 +3600 2135 67 +3642 2090 20 +3636 2085 20 + +# fern +Static 0x0CA2 (Hue=0x497) +3705 2201 20 +3563 2166 20 +3761 2092 20 +3704 2201 20 +3633 2139 58 +3642 2112 31 +3639 2136 44 +3635 2113 31 +3613 2181 16 + +# fallen log +Static 0x0CF4 (Hue=0x3DA) +3646 2083 20 +3638 2138 48 +3643 2086 20 +3629 2154 76 + +# fitting +Static 0x112F +3667 2071 20 +3707 2063 5 +3662 2071 20 +3557 2154 24 +3555 2157 22 + +# tile roof +Static 0x05C1 +3688 2201 48 +3687 2201 48 +3687 2200 45 +3686 2201 48 +3686 2200 45 +3686 2199 42 +3685 2201 48 +3685 2199 42 +3684 2201 48 +3684 2200 45 +3684 2199 42 +3683 2201 48 +3683 2200 45 +3683 2199 42 +3682 2201 48 +3682 2200 45 +3682 2199 42 +3681 2201 48 +3681 2200 45 +3681 2199 42 +3680 2200 45 +3680 2199 42 +3679 2201 48 +3679 2200 45 +3679 2199 42 +3680 2201 48 +3685 2200 45 + +# garbage +Static 0x10EE (Hue=0x3E2) +3536 2150 20 +3556 2158 22 +3554 2131 20 +3553 2156 23 +3716 2064 5 +3550 2145 22 +3689 2057 5 +3553 2159 22 +3559 2146 25 + +# mushrooms +Static 0x0D0D (Hue=0x3DB) +3617 2157 60 + +# cattails +Static 0x0CB7 (Hue=0x3D9) +3639 2216 20 + +# dirt +Static 0x1E00 (Hue=0x3E3) +3542 2139 20 +3557 2129 20 +3559 2135 21 +3558 2122 20 +3553 2127 20 +3544 2148 20 +3550 2165 20 +3558 2145 24 + +# blade plant +Static 0x0C93 (Hue=0x497) +3587 2129 52 +3758 2080 33 +3605 2128 66 +3786 2149 20 + +# wooden chest +WoodenChest 0x0E42 +3696 2228 40 +3680 2204 20 + +# pampas grass +Static 0x0CC4 (Hue=0x3D9) +3777 2126 20 +3618 2151 66 + +# stone roof +Static 0x0563 +3697 2208 60 +3686 2208 20 +3685 2208 20 +3684 2208 20 +3683 2208 20 +3682 2208 20 +3681 2208 20 +3704 2208 60 +3702 2208 60 +3705 2208 60 +3701 2208 60 +3700 2208 60 +3699 2208 60 +3698 2208 60 +3703 2208 60 + +# rock +Static 0x177B +3589 2129 58 +3670 2094 20 +3680 2075 6 +3632 2117 36 +3625 2115 39 +3618 2149 71 + +# tree +Static 0x0D72 (Hue=0x497) +3788 2118 23 +3788 2113 20 +3602 2148 63 +3644 2083 20 +3638 2138 55 +3620 2158 56 +3602 2143 65 +3584 2128 43 +3566 2163 20 +3638 2103 25 +3578 2158 35 + +# pen and ink +Static 0x0FC0 +3685 2224 24 +3729 2228 24 + +# tree +Static 0x0D6F (Hue=0x497) +3785 2116 20 +3635 2141 55 +3617 2161 55 +3785 2121 24 +3599 2151 63 +3599 2146 65 +3581 2131 42 +3563 2166 20 +3641 2086 20 +3635 2106 25 +3575 2161 26 + +# ceramic mug +CeramicMug 0x0995 +3729 2218 24 + +# counter +Static 0x0B3E +3730 2147 20 +3731 2147 20 +3729 2147 20 + +# bench +Static 0x0B93 +3696 2218 40 + +# table +Static 0x0B7A +3671 2281 -2 +3699 2210 20 +3696 2218 20 + +# bench +Static 0x0B94 +3696 2217 40 + +# table +Static 0x0B76 +3673 2134 20 +3699 2209 20 +3696 2217 20 + +# fan plant +Static 0x0C98 (Hue=0x3D9) +3704 2198 20 +3683 2093 23 +3618 2161 55 + +# sandstone floor +Static 0x052C +3705 2218 40 +3699 2216 40 +3705 2216 40 +3704 2212 40 +3704 2210 40 +3704 2208 40 +3702 2212 40 +3702 2210 40 +3702 2208 40 +3702 2207 40 +3700 2218 40 +3700 2217 40 +3700 2214 40 +3700 2210 40 +3699 2218 40 +3699 2217 40 +3698 2218 40 +3698 2217 40 +3700 2212 40 +3696 2218 40 +3700 2208 40 + +# sandstone floor +Static 0x0529 +3705 2209 40 +3705 2214 40 +3705 2212 40 +3705 2211 40 +3704 2217 40 +3703 2213 40 +3703 2211 40 +3703 2209 40 +3701 2213 40 +3701 2211 40 +3701 2209 40 +3701 2208 40 +3696 2217 40 +3696 2216 40 + +# wall sconce +Static 0x09FE +3696 2216 50 + +# pile of garbage +Static 0x10F2 (Hue=0x3E4) +3544 2142 20 +3558 2132 20 +3555 2160 21 + +# clean bandage%s% +Static 0x0EE9 +3687 2224 24 +3686 2224 24 +3693 2208 24 +3689 2208 24 +3683 2224 24 +3692 2208 24 +3691 2208 24 +3690 2208 24 + +# clock frame%s% +Static 0x104E +3725 2128 24 +3714 2130 24 +3714 2127 24 + +# dirt +Static 0x1DFF (Hue=0x3E2) +3669 2225 20 +3687 2257 20 +3550 2156 22 +3552 2129 20 +3552 2157 22 +3546 2158 20 +3787 2138 29 +3735 2064 5 + +# pizza%s% +Static 0x1040 +3752 2226 24 +3680 2173 24 +3721 2083 9 +3752 2228 24 +3752 2227 24 + +# wooden banister +Static 0x08B7 +3697 2214 40 +3696 2214 40 + +# pampas grass +Static 0x0CC4 (Hue=0x497) +3551 2127 20 +3643 2102 22 +3611 2157 57 +3614 2105 20 +3624 2207 16 + +# dirt patch +Static 0x0912 (Hue=0x3E2) +3683 2057 6 +3728 2061 5 + +# stone roof +Static 0x0564 +3680 2214 20 +3680 2213 20 +3680 2212 20 +3680 2211 20 +3680 2210 20 +3680 2209 20 +3696 2215 60 +3696 2214 60 +3696 2212 60 +3696 2218 60 +3696 2217 60 +3696 2216 60 +3696 2213 60 +3696 2211 60 +3696 2210 60 +3696 2209 60 + +# stone ruins +Static 0x03C5 +3778 2112 20 +3700 2182 20 +3692 2180 20 +3748 2084 25 +3674 2107 20 +3687 2188 20 +3784 2114 20 +3723 2143 20 +3666 2104 20 +3663 2251 20 +3736 2077 5 +3658 2171 20 +3713 2179 20 +3740 2061 5 +3653 2108 20 +3696 2181 20 +3790 2116 25 +3778 2104 20 +3688 2087 8 +3712 2066 5 + +# counter +Static 0x0B40 +3732 2147 20 +3728 2147 20 + +# stone step +Static 0x0917 (Hue=0x482) +3736 2174 20 +3735 2175 20 +3734 2174 20 +3735 2173 20 + +# death vortex +Static 0x378A +3735 2174 20 + +# stone column +Static 0x0077 (Hue=0x482) +3735 2174 20 + +# tree +Static 0x0D5B (Hue=0x497) +3632 2108 29 +3620 2148 67 +3602 2128 65 +3596 2143 63 +3596 2133 68 +3584 2158 45 +3560 2143 24 +3662 2088 20 +3614 2108 25 + +# sandstone +Static 0x076C +3698 2208 25 +3697 2210 25 +3697 2208 20 +3696 2211 25 +3696 2211 20 +3696 2210 30 +3696 2208 35 +3697 2209 35 +3698 2212 20 +3698 2211 25 +3698 2211 20 +3698 2210 30 +3698 2210 25 +3698 2210 20 +3698 2209 35 +3698 2209 30 +3698 2209 25 +3698 2209 20 +3698 2208 35 +3698 2208 30 +3698 2208 20 +3697 2212 20 +3697 2211 25 +3697 2211 20 +3697 2210 30 +3697 2210 20 +3697 2209 30 +3697 2209 25 +3697 2209 20 +3697 2208 35 +3697 2208 30 +3697 2208 25 +3696 2212 20 +3696 2210 25 +3696 2210 20 +3696 2209 35 +3696 2209 30 +3696 2209 25 +3696 2209 20 +3696 2208 30 +3696 2208 25 +3696 2208 20 + +# tree +Static 0x0D58 (Hue=0x497) +3629 2111 29 +3617 2151 67 +3593 2146 63 +3593 2136 68 +3581 2161 45 +3557 2146 23 +3659 2091 20 +3599 2131 67 +3611 2111 25 + +# tree +Static 0x0D57 (Hue=0x497) +3658 2092 20 +3616 2152 67 +3598 2132 67 +3592 2147 63 +3592 2137 68 +3580 2162 45 +3556 2147 24 +3628 2112 29 +3610 2112 25 + +# clock parts +Static 0x1050 +3718 2123 24 +3723 2131 24 +3714 2126 24 +3722 2131 24 + +# ponytail palm +Static 0x0CA6 (Hue=0x3D9) +3773 2124 20 + +# muffins +Static 0x09EB +3682 2168 24 +3757 2216 26 +3752 2222 24 +3758 2216 24 +3752 2223 24 + +# wooden chest +WoodenChest 0x0E43 +3684 2200 20 +3686 2200 20 + +# wooden door +DarkWoodDoor 0x06A5 (Facing=WestCW) +3691 2199 20 + +# grasses +Static 0x0D33 (Hue=0x3DB) +3616 2153 60 + +# fallen log +Static 0x0CF4 (Hue=0x3D8) +3586 2154 59 +3567 2111 20 +3558 2136 22 +3638 2220 20 + +# blood +Static 0x122C +3544 2154 20 + +# stone roof +Static 0x055F +3704 2211 60 +3686 2210 20 +3684 2214 20 +3684 2211 20 +3700 2211 60 +3682 2210 20 +3681 2213 20 +3681 2210 20 +3699 2214 60 +3704 2213 60 +3703 2210 60 +3702 2209 60 +3701 2218 60 +3701 2212 60 +3699 2211 60 +3700 2216 60 +3700 2209 60 +3699 2218 60 +3702 2214 60 +3698 2216 60 +3698 2213 60 +3698 2210 60 +3697 2218 60 +3697 2212 60 +3683 2213 20 + +# shells +Static 0x0FCA +3717 2029 3 + +# blood +Static 0x122A +3544 2154 20 + +# skull mug +Static 0x0FFD +3726 2228 21 +3728 2228 25 +3727 2228 25 + +# pewter mug +PewterMug 0x0FFF +3727 2218 24 + +# stone ruins +Static 0x03BB +3734 2120 20 +3697 2181 20 +3741 2067 5 +3689 2123 20 +3647 2119 22 +3719 2178 20 +3701 2179 20 +3770 2110 20 +3679 2240 20 +3798 2102 24 + +# fallen log +Static 0x0CF6 (Hue=0x3D8) +3632 2148 62 +3625 2105 20 +3612 2153 61 + +# table +Static 0x0B72 +3683 2202 20 + +# playing cards +Static 0x0FA3 +3722 2217 24 + +# fish +Static 0x09CC +3685 2258 24 +3685 2257 24 +3685 2255 24 +3685 2256 24 + +# fish +Static 0x09CD +3685 2257 24 +3685 2256 24 +3685 2258 24 +3685 2255 24 + +# game board +ChessBoard 0x0FA6 +3697 2061 9 +3730 2221 24 + +# sextant +Static 0x1057 +3719 2131 24 +3722 2123 24 + +# tree +Static 0x0D70 (Hue=0x497) +3786 2120 24 +3786 2115 20 +3636 2140 55 +3600 2150 63 +3600 2145 65 +3582 2130 43 +3576 2160 35 +3564 2165 20 +3618 2160 56 +3642 2085 20 +3636 2105 25 + +# unbaked pie +Static 0x1042 +3680 2172 24 +3752 2226 24 +3721 2083 9 + +# sandstone wall +Static 0x0257 +3687 2217 20 +3695 2211 20 +3703 2216 20 +3695 2217 20 +3695 2215 20 +3695 2213 20 +3695 2209 20 + +# glass of water +Static 0x1F93 +3731 2221 24 + +# wooden ladder +Static 0x08A1 +3673 2117 20 + +# sandstone post +Static 0x0161 +3679 2199 20 +3695 2207 40 +3703 2215 20 +3702 2215 40 +3695 2207 20 + +# wooden ladder +Static 0x08A3 +3676 2229 43 +3675 2229 43 +3682 2231 31 +3670 2185 21 + +# candelabra +Static 0x0B1F +3760 2118 24 +3691 2165 31 + +# elephant ear plant +Static 0x0C97 (Hue=0x3DB) +3690 2119 20 +3639 2136 44 +3615 2144 86 + +# stool +Static 0x0A2B +3682 2172 20 +3682 2170 20 +3684 2170 20 + +# diamond%s% +Static 0x0F28 +3664 2132 24 +3664 2147 24 +3664 2145 24 + +# sandstone wall +Static 0x015F +3695 2205 20 +3695 2201 20 +3695 2198 20 +3735 2151 20 +3695 2192 20 +3679 2207 20 +3679 2206 20 +3679 2205 20 +3679 2201 20 +3679 2200 20 +3695 2206 20 +3695 2204 20 +3695 2203 20 +3735 2150 20 +3735 2149 20 +3735 2148 20 +3735 2146 20 +3735 2145 20 +3735 2144 20 +3695 2207 20 +3695 2202 20 +3695 2200 20 + +# piece%s% of amber +Static 0x0F25 +3664 2133 24 + +# water +Static 0x179C +3810 2137 -5 +3531 2158 -5 + +# citrine%s% +Static 0x0F24 +3664 2132 24 + +# water +Static 0x1797 +3810 2137 -5 +3804 2116 -5 +3683 2271 -5 +3631 2088 -5 +3531 2158 -5 + +# rub%ies/y% +Static 0x0F1D +3664 2146 24 +3664 2148 24 +3664 2132 24 + +# fishing pole +Static 0x0DBF +3685 2270 21 +3667 2299 -2 + +# water +Static 0x1798 +3652 2237 -5 +3531 2158 -5 + +# water +Static 0x179B +3531 2158 -5 + +# rub%ies/y% +Static 0x0F14 +3664 2131 24 + +# diamond%s% +Static 0x0F29 +3665 2148 27 +3665 2146 27 + +# garbage +Static 0x10F1 (Hue=0x3E4) +3546 2152 20 +3550 2155 22 +3554 2125 20 + +# candelabra +CandelabraStand 0x0B26 +3680 2251 20 +3736 2067 5 +3696 2160 20 +3686 2254 20 +3656 2118 20 +3691 2071 5 +3752 2120 20 +3680 2168 20 +3656 2176 20 +3770 2104 20 +3710 2251 20 +3696 2240 20 +3691 2056 5 +3684 2064 5 +3678 2096 20 +3670 2250 20 +3670 2112 20 +3663 2192 20 + +# spinning wheel +SpinningWheelSouthAddon 0x1015 +3661 2229 20 + +# garbage +Static 0x10EF +3662 2288 0 +3655 2282 -1 + +# candlabra +CandelabraStand 0x0A29 +3752 2120 20 +3680 2251 20 +3680 2168 20 +3656 2176 20 +3656 2118 20 + +# clock +Static 0x104C +3719 2120 29 +3714 2125 24 + +# small palm +Static 0x0C9C (Hue=0x3DA) +3624 2156 63 +3614 2159 56 +3650 2220 20 + +# flowstone +Static 0x08E3 +3705 2019 -5 +3705 2016 -5 +3704 2017 -5 +3704 2016 -5 +3690 2018 -5 +3693 2016 -5 +3691 2020 -5 + +# mushrooms +Static 0x0D0E (Hue=0x497) +3536 2138 20 +3611 2161 50 + +# sapling +Static 0x0CE9 (Hue=0x3DB) +3597 2145 64 +3637 2110 29 +3613 2157 61 + +# grasses +Static 0x0CB0 (Hue=0x3DB) +3587 2128 51 +3613 2156 60 + +# grasses +Static 0x0CB5 (Hue=0x3D9) +3720 2136 20 +3647 2056 15 +3615 2161 57 +3613 2105 11 +3619 2136 87 +3613 2152 59 + +# o'hii tree +Static 0x0C9E (Hue=0x3D8) +3627 2114 36 +3593 2148 62 + +# sandstone wall +Static 0x024D +3701 2207 40 +3705 2207 40 +3704 2207 40 +3703 2215 40 +3703 2207 40 +3702 2207 40 +3700 2207 40 +3698 2207 40 +3697 2207 40 +3696 2207 40 +3699 2207 40 + +# sandstone wall +Static 0x025B +3775 2111 20 + +# tree +Static 0x0D59 (Hue=0x497) +3618 2150 67 +3600 2130 67 +3594 2145 63 +3594 2135 68 +3582 2160 45 +3558 2145 24 +3660 2090 20 +3630 2110 29 + +# chair +FancyWoodenChairCushion 0x0B51 +3682 2254 20 +3666 2255 20 +3666 2253 20 +3765 2123 20 +3709 2248 20 +3709 2246 20 + +# bottle +Static 0x0F01 +3709 2224 24 + +# dough +Static 0x103D +3680 2170 24 +3761 2216 24 + +# scroll%s% +Static 0x0EF8 +3708 2224 24 + +# bottle +Static 0x0F02 +3708 2224 22 + +# cattails +Static 0x0CB8 (Hue=0x3DB) +3624 2201 -15 + +# brass sign +LocalizedSign 0x0BD2 +3728 2160 20 +3720 2184 20 + +# metal signpost +Static 0x0BA2 +3682 2261 20 +3728 2160 20 +3669 2261 20 + +# scroll%s% +Static 0x0EF6 +3706 2224 24 + +# fallen log +Static 0x0CF5 (Hue=0x3D8) +3581 2111 21 +3758 2209 20 +3627 2107 22 +3624 2206 13 + +# grasses +Static 0x0CAF (Hue=0x3D9) +3624 2201 -15 +3704 2113 20 +3613 2132 77 +3611 2136 79 + +# tile roof +Static 0x05B5 +3689 2207 48 +3689 2206 48 +3689 2204 48 +3689 2199 48 +3689 2193 48 +3689 2192 48 +3688 2207 45 +3688 2206 45 +3688 2205 45 +3688 2199 45 +3688 2198 45 +3688 2197 45 +3688 2196 45 +3688 2195 45 +3688 2194 45 +3688 2193 45 +3688 2192 45 +3687 2207 42 +3687 2206 42 +3687 2197 42 +3687 2196 42 +3687 2194 42 +3687 2193 42 +3687 2192 42 +3686 2207 39 +3689 2200 48 +3689 2197 48 +3682 2261 46 +3681 2261 43 +3680 2261 40 +3665 2261 43 +3683 2261 49 +3689 2205 48 +3689 2196 48 +3689 2195 48 +3689 2194 48 +3667 2261 49 +3687 2198 42 +3687 2195 42 +3666 2261 46 +3664 2261 40 +3689 2198 48 + +# rushes +Static 0x0CA7 (Hue=0x3DB) +3589 2129 58 +3618 2170 37 + +# stone wall +Static 0x0062 (Hue=0x8AE) +3736 2175 20 + +# book +RedBook 0x0FF1 +3705 2211 44 + +# small palm +Static 0x0C9C (Hue=0x3D8) +3574 2125 26 +3607 2139 75 + +# stone ruins +Static 0x03B8 (Hue=0x497) +3570 2146 40 +3572 2142 38 +3565 2135 25 +3561 2137 22 +3570 2138 31 +3566 2148 33 +3559 2141 23 +3562 2145 26 + +# stone stairs +Static 0x0789 (Hue=0x497) +3568 2145 40 +3570 2141 38 +3563 2134 25 +3559 2136 22 +3564 2147 33 +3557 2140 23 +3568 2137 31 +3560 2144 26 + +# stone ruins +Static 0x03B9 (Hue=0x497) +3566 2145 40 +3568 2141 38 +3561 2134 25 +3557 2136 22 +3562 2147 33 +3555 2140 23 +3566 2137 31 +3558 2144 26 + +# stone step +Static 0x0917 (Hue=0x497) +3568 2144 40 +3570 2140 38 +3563 2133 25 +3559 2135 22 +3568 2136 31 +3564 2146 33 +3557 2139 23 +3560 2143 26 + +# ruined wall +Static 0x027A (Hue=0x497) +3567 2144 40 +3569 2140 38 +3562 2133 25 +3558 2135 22 +3567 2136 31 +3563 2146 33 +3556 2139 23 +3559 2143 26 + +# fallen log +Static 0x0CF5 (Hue=0x497) +3660 2067 20 +3668 2106 20 +3614 2162 48 + +# stone stairs +Static 0x0794 (Hue=0x497) +3569 2143 40 +3571 2139 38 +3564 2132 25 +3565 2145 33 +3560 2134 22 +3569 2135 31 +3558 2138 23 +3561 2142 26 + +# large fern +Static 0x0CA1 (Hue=0x3DB) +3571 2164 21 +3771 2099 20 +3607 2146 67 +3647 2095 21 +3631 2151 71 +3616 2107 21 +3620 2150 67 +3614 2147 75 +3613 2162 47 + +# ruined wall +Static 0x0278 (Hue=0x497) +3568 2143 40 +3570 2139 38 +3563 2132 24 +3564 2145 34 +3559 2134 22 +3568 2135 31 +3557 2138 23 +3560 2142 26 + +# stone ruins +Static 0x03BB (Hue=0x497) +3566 2143 40 +3568 2139 38 +3561 2132 25 +3562 2145 33 +3557 2134 22 +3566 2135 31 +3555 2138 23 +3558 2142 26 + +# stone stairs +Static 0x078B (Hue=0x497) +3567 2141 40 +3569 2137 38 +3562 2130 25 +3558 2132 22 +3567 2133 31 +3556 2136 23 +3563 2143 33 +3559 2140 26 + +# grasses +Static 0x0D32 (Hue=0x3DA) +3755 2241 20 +3661 2089 20 +3736 2160 20 +3651 2252 20 +3609 2151 63 + +# fan plant +Static 0x0C98 (Hue=0x3DB) +3541 2148 20 +3607 2145 66 + +# candle +CandleLarge 0x0B1A +3699 2061 11 +3699 2072 9 +3686 2152 28 +3656 2099 28 +3768 2112 48 + +# crystal ball +Static 0x0E2F +3696 2227 24 +3704 2224 24 + +# wooden plank +Static 0x07CF +3671 2285 -3 +3671 2278 -3 +3682 2263 20 +3694 2282 -3 +3693 2282 -3 +3668 2270 20 +3668 2269 20 +3692 2295 -3 +3692 2283 -3 +3691 2294 -3 +3691 2282 -3 +3690 2295 -3 +3690 2283 -3 +3688 2287 -3 +3687 2291 -3 +3685 2291 -3 +3685 2287 -3 +3685 2261 20 +3684 2287 -3 +3683 2262 20 +3682 2287 -3 +3681 2294 -3 +3680 2294 -3 +3680 2266 20 +3680 2265 20 +3679 2295 -3 +3679 2287 -3 +3679 2268 20 +3694 2294 -3 +3678 2294 -3 +3678 2291 -3 +3678 2266 20 +3693 2294 -3 +3677 2295 -3 +3677 2279 -3 +3676 2287 -3 +3676 2277 -3 +3676 2270 20 +3675 2264 20 +3674 2291 -3 +3674 2281 -3 +3674 2266 20 +3673 2285 -3 +3686 2265 20 +3673 2275 -3 +3673 2267 20 +3673 2264 20 +3673 2263 20 +3672 2287 -3 +3672 2277 -3 +3671 2288 -3 +3671 2284 -3 +3671 2275 -3 +3671 2274 -3 +3671 2268 20 +3671 2262 20 +3670 2294 -3 +3670 2269 20 +3682 2268 20 +3682 2266 20 +3669 2294 -3 +3669 2287 -3 +3669 2262 20 +3668 2295 -3 +3667 2294 -3 +3667 2287 -3 +3666 2295 -3 +3666 2266 20 +3666 2261 20 +3671 2266 20 +3664 2287 -3 +3663 2291 -3 +3663 2263 20 +3693 2287 -3 +3661 2291 -3 +3661 2287 -3 +3660 2287 -3 +3658 2287 -3 +3657 2294 -3 +3657 2282 -3 +3656 2294 -3 +3656 2282 -3 +3691 2287 -3 +3655 2295 -3 +3655 2287 -3 +3655 2283 -3 +3654 2294 -3 +3654 2291 -3 +3654 2282 -3 +3653 2295 -3 +3653 2283 -3 + +# mushrooms +Static 0x0D14 (Hue=0x3D9) +3612 2162 47 + +# fern +Static 0x0CA4 (Hue=0x3DA) +3569 2164 21 +3560 2118 20 +3543 2156 19 +3788 2113 25 +3723 2239 20 +3643 2127 35 +3624 2173 35 +3647 2087 20 +3643 2086 20 +3608 2152 60 +3633 2106 24 +3788 2128 26 +3621 2113 36 +3759 2081 33 +3606 2164 41 + +# fern +Static 0x0C9F (Hue=0x3DA) +3776 2133 25 +3760 2082 31 +3642 2091 20 +3661 2078 20 +3599 2146 60 +3634 2125 45 +3612 2164 43 +3612 2145 77 + +# tiller man +Static 0x3E4E +3681 2285 -5 + +# stone roof +Static 0x055C +3705 2212 60 +3704 2210 60 +3703 2214 60 +3701 2215 60 +3685 2210 20 +3684 2213 20 +3683 2210 20 +3682 2212 20 +3700 2212 60 +3705 2214 60 +3703 2212 60 +3699 2215 60 +3698 2214 60 +3685 2214 20 +3681 2209 20 + +# pile of garbage +Static 0x10F2 (Hue=0x497) +3543 2141 20 +3558 2148 26 +3554 2145 22 +3720 2068 5 +3553 2159 22 + +# morning glories +Static 0x0D34 (Hue=0x3D8) +3607 2142 74 + +# small palm +Static 0x0C9A (Hue=0x3DA) +3587 2139 64 +3584 2128 45 +3584 2127 45 +3743 2184 20 +3690 2261 20 +3770 2206 20 + +# mushrooms +Static 0x0D11 (Hue=0x3DB) +3741 2261 20 + +# small palm +Static 0x0C9C (Hue=0x497) +3633 2080 20 +3608 2114 34 +3608 2157 58 +3751 2251 9 + +# dirt +Static 0x1E00 (Hue=0x3E1) +3549 2146 21 +3549 2138 20 +3549 2144 21 +3551 2133 20 +3558 2126 20 +3558 2148 26 +3551 2147 22 +3714 2066 5 +3551 2159 21 +3554 2161 21 + +# pile of garbage +Static 0x10F2 +3549 2149 21 +3555 2136 20 +3559 2120 20 +3657 2062 20 +3656 2280 -1 +3552 2163 20 + +# fern +Static 0x0CA2 (Hue=0x3DA) +3585 2126 44 +3574 2127 33 +3745 2078 5 +3702 2109 20 +3632 2129 55 +3615 2155 58 +3648 2085 20 +3636 2080 20 +3637 2083 20 +3608 2154 59 +3670 2065 21 +3643 2064 20 +3623 2120 44 +3632 2214 20 +3749 2254 14 +3603 2140 72 + +# cattails +Static 0x0CB7 (Hue=0x497) +3626 2209 20 + +# candelabra +Candelabra 0x0B1D +3760 2115 24 +3705 2211 48 +3656 2141 26 + +# pile of garbage +Static 0x10F2 (Hue=0x3E2) +3551 2152 22 +3558 2142 24 + +# bed +Static 0x0A5A +3693 2218 20 +3694 2216 20 +3693 2215 20 +3688 2217 20 +3694 2218 20 +3694 2214 20 +3694 2212 20 + +# fern +Static 0x0CA0 (Hue=0x3DA) +3588 2158 53 +3682 2111 20 +3628 2151 78 +3737 2093 5 +3676 2140 20 +3630 2139 68 +3622 2151 66 +3639 2092 20 +3730 2256 20 +3635 2076 20 +3596 2145 62 +3600 2115 35 + +# bulrushes +Static 0x0C94 (Hue=0x3D8) +3562 2166 20 +3638 2140 48 +3644 2090 20 +3599 2122 49 +3612 2142 84 +3610 2124 60 + +# clock +Static 0x104B +3720 2123 24 +3722 2131 24 + +# silverware +Static 0x09D5 +3683 2203 24 +3722 2084 9 + +# pen and ink +Static 0x0FBF +3680 2253 24 +3669 2235 24 +3664 2254 27 +3683 2203 27 +3752 2220 24 +3699 2209 24 +3656 2193 24 + +# ponytail palm +Static 0x0CA6 (Hue=0x3D8) +3748 2087 26 +3730 2257 15 + +# sandstone floor +Static 0x052A +3705 2208 40 +3703 2208 40 +3701 2208 40 +3701 2207 40 +3699 2214 40 +3699 2212 40 +3705 2210 40 +3704 2218 40 +3704 2216 40 +3704 2215 40 +3704 2214 40 +3703 2212 40 +3703 2210 40 +3702 2208 40 +3705 2213 40 +3701 2212 40 +3701 2210 40 +3699 2215 40 +3699 2213 40 +3699 2211 40 +3699 2210 40 +3697 2217 40 +3697 2216 40 +3697 2215 40 +3696 2215 40 +3698 2215 40 + +# goblet +Static 0x09B3 +3726 2218 24 +3718 2084 9 +3718 2083 9 +3721 2084 9 + +# small palm +Static 0x0C99 (Hue=0x3D8) +3578 2122 25 +3627 2199 20 +3647 2084 20 +3624 2148 79 +3616 2152 58 +3611 2111 26 +3623 2190 15 + +# garbage +Static 0x10EE (Hue=0x3E4) +3538 2144 20 +3557 2164 20 +3554 2157 23 + +# fern +Static 0x0CA2 (Hue=0x3D9) +3579 2124 29 +3626 2116 40 +3617 2153 58 +3647 2206 20 +3611 2155 59 +3719 2244 20 + +# elephant ear plant +Static 0x0C97 (Hue=0x3D9) +3604 2125 62 + +# fitting +Static 0x112F (Hue=0x497) +3555 2125 20 +3664 2216 20 +3538 2157 -15 +3552 2147 23 +3545 2137 20 + +# rock +Static 0x1774 +3598 2145 61 +3739 2097 20 +3609 2143 75 +3633 2174 40 +3634 2103 20 +3634 2079 20 +3657 2174 20 +3615 2142 91 +3733 2231 20 + +# ponytail palm +Static 0x0CA6 (Hue=0x497) +3603 2127 63 + +# chair +FancyWoodenChairCushion 0x0B50 +3754 2125 20 +3769 2117 20 +3756 2125 20 +3708 2250 20 +3772 2117 20 +3705 2250 20 +3700 2253 20 +3698 2253 20 + +# chair +Static 0x0B4F +3773 2104 20 +3705 2240 20 +3698 2240 20 + +# stone ruins +Static 0x03C3 +3721 2181 20 +3747 2144 11 +3668 2105 20 +3778 2108 20 +3745 2067 5 +3645 2113 21 +3707 2157 20 +3782 2123 20 +3653 2093 20 +3732 2067 5 +3702 2075 5 +3728 2058 5 +3734 2103 20 + +# small palm +Static 0x0C9B (Hue=0x3DA) +3566 2113 20 +3675 2132 20 +3647 2074 20 +3635 2072 20 +3631 2098 20 +3614 2147 76 +3611 2154 59 + +# dirt +Static 0x1DFF +3546 2140 20 +3555 2162 21 +3547 2153 20 +3557 2154 24 +3552 2130 20 +3555 2133 20 +3675 2055 28 +3695 2066 5 +3714 2225 20 +3684 2222 20 +3555 2140 21 +3556 2125 20 +3555 2132 20 +3551 2159 21 +3668 2232 20 +3558 2150 27 +3637 2219 20 +3550 2154 22 +3557 2158 22 + +# blade plant +Static 0x0C93 (Hue=0x3D9) +3581 2127 40 +3627 2114 36 +3782 2106 20 + +# dirt +Static 0x1DFE (Hue=0x497) +3539 2144 20 +3551 2138 20 +3538 2157 -15 +3661 2053 20 +3744 2066 5 +3556 2147 25 +3650 2126 25 +3552 2156 23 +3675 2209 20 +3556 2152 25 +3559 2136 22 +3683 2021 -15 +3546 2157 20 +3551 2131 20 +3556 2128 20 +3558 2125 20 +3558 2124 20 +3672 2068 22 +3726 2066 5 +3559 2115 -15 +3546 2155 20 +3556 2151 25 + +# small palm +Static 0x0C9A (Hue=0x3D9) +3575 2127 34 +3720 2116 20 +3623 2115 39 +3617 2148 72 +3615 2164 46 +3596 2125 54 + +# small palm +Static 0x0C9D (Hue=0x3D8) +3580 2118 24 +3791 2106 26 +3653 2138 21 +3646 2130 33 +3624 2117 41 +3610 2159 58 +3598 2106 21 + +# blade plant +Static 0x0C93 (Hue=0x3D8) +3628 2125 56 +3628 2217 20 +3625 2190 20 +3623 2166 45 + +# tile roof +Static 0x05C0 +3688 2203 48 +3687 2204 45 +3687 2203 48 +3686 2205 42 +3686 2204 45 +3686 2203 48 +3686 2192 39 +3685 2206 39 +3685 2205 42 +3685 2204 45 +3685 2192 39 +3684 2207 36 +3684 2206 39 +3684 2205 42 +3684 2204 45 +3684 2203 48 +3684 2192 39 +3683 2207 36 +3683 2206 39 +3683 2205 42 +3683 2204 33 +3683 2203 48 +3683 2192 39 +3682 2207 36 +3682 2206 39 +3682 2205 42 +3682 2204 45 +3682 2203 48 +3682 2192 39 +3681 2207 36 +3681 2206 39 +3681 2205 42 +3681 2204 45 +3681 2203 48 +3680 2207 36 +3680 2206 39 +3680 2205 42 +3680 2204 45 +3680 2203 48 +3680 2192 39 +3679 2207 36 +3679 2206 39 +3679 2205 42 +3679 2204 45 +3679 2203 48 +3679 2192 39 +3685 2203 48 +3681 2192 39 + +# sapling +Static 0x0CEA (Hue=0x3DB) +3630 2184 24 + +# small palm +Static 0x0C99 (Hue=0x497) +3633 2076 8 +3603 2146 63 + +# small palm +Static 0x0C9A (Hue=0x3DB) +3578 2115 22 +3627 2196 20 +3602 2168 37 + +# stone ruins +Static 0x03B8 +3702 2258 20 +3723 2141 20 +3673 2123 20 +3699 2074 5 +3720 2174 20 +3677 2109 20 +3707 2177 20 +3700 2180 20 +3702 2155 20 +3651 2113 20 +3720 2054 5 +3796 2113 24 +3669 2257 20 +3777 2104 20 + +# wooden post +Static 0x00A9 +3623 2207 -15 + +# mushrooms +Static 0x0D13 (Hue=0x3D8) +3637 2171 46 +3601 2157 58 + +# wooden bench +WoodenBench 0x0B2C +3696 2201 20 +3696 2200 20 +3696 2199 20 +3773 2103 20 +3789 2097 25 + +# checkers +Static 0x0FA5 +3730 2221 24 +3697 2061 9 + +# checkers +Static 0x0FA4 +3730 2221 24 +3697 2061 9 + +# wooden shelf +EmptyBookcase 0x0A9E +3715 2084 5 +3712 2130 20 +3712 2125 20 +3680 2250 20 +3680 2249 20 +3664 2257 20 +3712 2124 20 +3712 2129 20 +3715 2085 5 + +# stone ruins +Static 0x03C6 +3789 2112 25 +3700 2181 20 +3694 2187 20 +3722 2194 20 +3699 2183 20 +3740 2121 20 +3733 2091 5 +3715 2247 20 +3770 2222 20 +3743 2135 21 +3727 2179 20 +3754 2088 27 +3737 2099 20 +3684 2258 20 +3642 2130 36 +3710 2178 20 +3714 2091 5 +3730 2130 20 +3660 2257 20 +3664 2184 20 +3692 2088 8 + +# dirt patch +Static 0x0911 (Hue=0x497) +3543 2145 20 +3541 2148 20 +3555 2139 21 +3545 2138 20 +3557 2145 23 +3557 2121 20 +3740 2129 20 +3552 2126 20 +3551 2144 22 +3687 2061 5 +3542 2154 20 +3552 2164 20 +3552 2161 27 +3697 2065 5 +3627 2191 20 +3545 2147 20 +3743 2070 5 +3553 2121 20 +3551 2155 22 +3555 2160 21 +3747 2066 6 + +# pier +Static 0x03AA +3687 2270 21 +3687 2261 21 +3663 2262 21 +3684 2270 21 +3682 2270 21 +3680 2270 21 +3679 2261 21 +3678 2270 21 +3671 2261 21 +3669 2270 21 +3667 2270 21 +3665 2270 21 +3663 2270 21 +3663 2268 21 +3663 2266 21 +3663 2264 21 +3687 2268 21 + +# sandstone wall +Static 0x024E +3702 2217 40 +3786 2116 20 +3702 2218 40 +3695 2215 40 +3695 2214 40 +3695 2213 40 +3695 2212 40 +3695 2211 40 +3695 2210 40 +3695 2209 40 +3695 2208 40 +3702 2216 40 +3695 2218 40 +3695 2217 40 +3695 2216 40 +3773 2106 20 + +# fallen log +Static 0x0CF4 (Hue=0x3DB) +3539 2150 20 +3614 2155 59 +3649 2087 20 +3621 2187 8 + +# stone ruins +Static 0x03BA +3717 2067 5 +3782 2111 20 +3780 2100 20 +3662 2162 20 +3736 2127 20 +3736 2094 10 +3640 2116 33 +3706 2067 5 +3745 2069 5 +3684 2248 20 +3736 2097 20 +3777 2118 20 +3665 2252 20 +3722 2105 20 +3701 2078 5 + +# dirt patch +Static 0x0911 (Hue=0x3E3) +3541 2139 20 +3551 2142 22 +3548 2158 21 +3742 2070 5 +3548 2151 21 + +# snake plant +Static 0x0CA9 (Hue=0x497) +3643 2095 22 +3627 2193 20 +3606 2130 68 +3625 2200 20 +3613 2178 27 + +# wood +Static 0x1B81 +3662 2043 20 +3553 2153 23 +3553 2128 20 +3557 2157 23 +3556 2150 26 +3555 2151 24 +3555 2142 21 +3537 2155 -15 +3557 2121 20 +3742 2073 5 +3555 2140 21 +3551 2132 20 +3550 2163 20 +3765 2072 32 +3764 2071 32 +3551 2146 22 +3731 2074 5 +3557 2118 20 +3773 2104 20 +3558 2132 20 +3649 2147 32 +3558 2160 21 +3536 2133 18 +3638 2072 20 + +# fern +Static 0x0CA0 (Hue=0x497) +3580 2141 50 +3569 2124 22 +3766 2140 22 +3761 2083 31 +3787 2116 22 +3798 2121 24 +3631 2112 34 +3610 2161 48 +3598 2124 54 +3611 2155 59 +3580 2131 41 +3601 2134 67 +3606 2179 21 + +# chair +Static 0x0B4E +3696 2248 20 + +# grasses +Static 0x0CB0 (Hue=0x3D9) +3565 2164 20 +3755 2143 16 +3623 2109 27 +3621 2176 31 +3611 2161 50 +3599 2133 69 + +# Merchants' Guild +LocalizedSign 0x0C09 +3712 2242 20 + +# fan plant +Static 0x0C98 (Hue=0x497) +3606 2154 59 + +# large fern +Static 0x0CA1 (Hue=0x3D8) +3583 2129 44 +3778 2134 28 +3675 2088 20 +3634 2097 20 +3635 2107 28 +3801 2099 20 +3603 2150 59 +3627 2198 20 +3627 2175 34 +3597 2146 60 + +# sandstone wall +Static 0x0160 +3689 2199 20 +3688 2199 20 +3687 2199 20 +3686 2199 20 +3771 2107 20 +3684 2199 20 +3682 2199 20 +3653 2111 20 +3704 2215 40 +3695 2207 20 +3680 2199 20 + +# pier +Static 0x03A5 +3692 2280 -2 +3694 2299 -3 +3694 2291 -3 +3694 2287 -3 +3694 2279 -3 +3690 2299 -3 +3690 2291 -3 +3690 2287 -3 +3690 2279 -3 +3666 2299 -3 +3666 2291 -3 +3687 2270 0 +3687 2270 10 +3687 2270 15 +3687 2268 0 +3687 2268 5 +3687 2268 10 +3687 2268 15 +3684 2270 -5 +3684 2270 0 +3684 2270 5 +3684 2270 10 +3684 2270 15 +3681 2271 -5 +3677 2269 -5 +3676 2269 -5 +3682 2270 5 +3682 2270 10 +3681 2299 -3 +3681 2291 -3 +3680 2270 -5 +3680 2270 0 +3680 2270 5 +3680 2270 10 +3680 2270 15 +3683 2271 -5 +3687 2268 -5 +3687 2267 -5 +3678 2270 -5 +3678 2270 0 +3678 2270 5 +3678 2270 10 +3678 2270 15 +3677 2299 -3 +3677 2291 -3 +3677 2287 -3 +3682 2270 -5 +3683 2270 -5 +3685 2270 -5 +3687 2270 5 +3682 2268 -5 +3684 2269 -5 +3687 2269 -5 +3670 2299 -3 +3670 2291 -3 +3670 2287 -3 +3682 2270 0 +3682 2270 15 +3663 2269 -5 +3663 2267 -5 +3669 2270 15 +3669 2270 10 +3681 2287 -3 +3669 2270 -5 +3663 2270 15 +3663 2270 10 +3663 2270 5 +3663 2270 0 +3663 2268 0 +3663 2268 -5 +3663 2266 -5 +3663 2266 0 +3657 2299 -3 +3657 2291 -3 +3657 2287 -3 +3657 2279 -3 +3653 2299 -3 +3653 2291 -3 +3653 2287 -3 +3653 2279 -3 +3686 2270 -5 + +# teleporter +Static 0x1809 (Hue=0x45B) +3675 2257 20 + +# sapling +Static 0x0CE9 (Hue=0x3D8) +3639 2100 23 +3614 2141 89 +3598 2138 68 + +# dirt +Static 0x1DFE +3552 2147 23 +3548 2144 21 +3539 2148 20 +3552 2145 22 +3553 2142 21 +3554 2163 20 +3556 2121 20 +3559 2153 25 +3554 2126 20 +3557 2127 20 +3550 2155 22 +3545 2150 20 +3546 2158 20 +3554 2121 20 +3559 2121 20 +3552 2131 20 +3557 2121 20 +3722 2073 5 +3558 2149 27 +3725 2057 5 +3538 2150 20 +3559 2149 26 +3736 2059 5 +3644 2069 20 +3546 2145 20 + +# garbage +Static 0x10F0 (Hue=0x3E2) +3544 2149 20 +3559 2151 27 +3559 2129 20 +3556 2123 20 +3553 2162 20 +3549 2145 21 + +# dirt +Static 0x1E00 (Hue=0x497) +3548 2150 21 +3542 2140 20 +3541 2145 20 +3556 2142 23 +3546 2138 20 +3550 2156 22 +3555 2162 21 +3622 2141 89 +3547 2138 20 +3546 2141 20 +3556 2153 24 +3552 2131 20 +3556 2125 20 +3549 2151 21 +3551 2158 21 +3693 2061 5 +3552 2167 20 +3745 2062 5 +3696 2180 20 +3540 2140 20 +3552 2165 20 +3744 2071 5 +3540 2151 20 +3553 2154 23 +3555 2120 20 +3555 2118 23 +3656 2070 20 +3676 2056 33 +3548 2152 21 +3558 2147 24 +3754 2142 20 +3550 2149 22 + +# garbage +Static 0x10EE +3558 2142 24 +3546 2142 20 +3541 2137 20 +3553 2120 17 +3556 2140 21 +3547 2137 20 +3547 2143 20 +3738 2066 5 +3554 2129 20 +3557 2152 25 +3656 2298 -2 +3559 2124 20 +3546 2161 -15 +3538 2156 -15 +3552 2164 20 +3711 2123 20 +3536 2134 24 +3655 2034 -15 +3549 2162 20 +3546 2157 20 +3732 2064 5 +3538 2149 20 +3542 2147 20 +3549 2154 21 +3551 2152 22 +3552 2139 20 +3741 2064 5 +3546 2145 20 + +# garbage +Static 0x10F0 (Hue=0x3E1) +3555 2140 21 +3671 2068 23 +3552 2152 23 +3549 2149 21 + +# garbage +Static 0x10F0 (Hue=0x497) +3657 2065 20 +3553 2148 23 +3615 2174 31 +3547 2142 20 +3770 2074 24 +3558 2124 20 +3559 2138 23 +3559 2118 20 +3670 2214 20 +3545 2147 20 +3550 2159 21 +3669 2061 20 +3552 2162 20 +3704 2173 20 +3558 2148 26 +3550 2149 22 +3718 2065 5 +3650 2072 20 +3553 2123 20 +3554 2156 23 +3550 2156 22 +3656 2042 20 +3553 2127 20 +3540 2138 24 +3542 2137 20 +3537 2150 20 + +# garbage +Static 0x10F1 (Hue=0x497) +3543 2143 20 +3549 2140 20 +3546 2141 20 +3554 2161 21 +3553 2160 21 +3543 2148 20 +3710 2057 5 +3552 2144 23 +3552 2160 21 +3725 2052 5 +3557 2147 24 +3550 2146 22 +3559 2122 20 +3655 2255 20 +3555 2142 21 +3757 2128 20 +3659 2113 20 +3641 2067 20 +3725 2058 5 +3548 2154 21 +3553 2122 23 +3557 2119 20 +3549 2155 21 +3553 2164 20 + +# dirt +Static 0x1DFE (Hue=0x3E1) +3540 2141 20 +3554 2164 20 +3555 2141 21 +3651 2069 20 +3555 2136 20 +3556 2140 21 +3552 2158 22 +3775 2071 -15 +3554 2122 20 +3554 2150 24 +3540 2149 20 + +# garbage +Static 0x10F0 +3546 2145 20 +3540 2140 20 +3557 2138 22 +3550 2140 20 +3751 2045 20 +3550 2144 21 +3553 2158 22 +3662 2059 20 +3552 2131 20 +3559 2119 20 +3559 2137 22 +3672 2049 20 +3718 2058 5 +3573 2125 24 +3558 2133 20 +3551 2145 22 +3557 2123 20 +3551 2152 22 +3762 2126 20 +3554 2154 24 +3547 2150 20 +3665 2071 20 + +# wood +Static 0x1B81 (Hue=0x497) +3540 2149 20 +3687 2247 20 +3668 2213 20 +3671 2046 20 +3724 2074 5 +3559 2154 24 +3554 2132 20 +3556 2127 20 +3559 2145 26 +3718 2068 5 +3761 2061 21 +3553 2123 20 +3705 2168 20 +3656 2225 20 +3739 2062 5 +3549 2144 21 +3536 2148 20 +3557 2156 23 +3649 2071 20 +3558 2153 25 +3550 2159 21 +3550 2153 22 +3540 2138 24 +3548 2142 20 + +# garbage +Static 0x10F1 +3544 2153 20 +3551 2143 21 +3540 2139 20 +3543 2140 20 +3559 2135 21 +3544 2137 20 +3550 2140 20 +3544 2138 20 +3543 2146 20 +3557 2153 24 +3747 2062 5 +3658 2072 20 +3658 2189 20 +3553 2125 20 +3558 2118 20 +3557 2164 20 +3555 2123 20 +3759 2069 35 +3549 2154 21 +3657 2066 20 +3549 2158 21 +3556 2155 23 +3554 2155 23 +3554 2157 23 +3742 2060 5 +3655 2196 20 +3661 2064 20 +3549 2147 21 + +# wooden stairs +Static 0x0739 +3672 2273 6 +3672 2271 16 +3676 2275 -3 +3677 2275 -3 +3677 2274 1 +3677 2273 6 +3677 2272 11 +3677 2271 16 +3676 2274 1 +3676 2273 6 +3676 2272 11 +3676 2271 16 +3675 2275 -3 +3675 2274 1 +3675 2273 6 +3675 2272 11 +3674 2275 -3 +3674 2273 6 +3674 2272 11 +3674 2271 16 +3673 2275 -3 +3673 2274 1 +3673 2273 6 +3673 2272 11 +3673 2271 16 +3672 2275 -3 +3672 2274 1 +3672 2272 11 +3671 2275 -3 +3671 2274 1 +3671 2273 6 +3671 2272 11 +3671 2271 16 +3670 2275 -3 +3670 2274 1 +3670 2273 6 +3670 2272 11 +3670 2271 16 +3675 2271 16 +3674 2274 1 + +# wood +Static 0x0738 +3681 2299 -15 +3694 2299 -15 +3694 2291 -14 +3694 2291 -15 +3694 2287 -14 +3694 2287 -15 +3690 2299 -15 +3677 2299 -15 +3681 2291 -15 +3672 2274 -2 +3679 2290 -14 +3677 2274 -4 +3677 2273 1 +3677 2273 -4 +3677 2272 6 +3677 2272 1 +3677 2272 -4 +3677 2271 11 +3677 2271 6 +3677 2271 1 +3677 2271 -4 +3676 2274 -2 +3676 2273 2 +3676 2272 8 +3676 2271 11 +3675 2290 -14 +3675 2281 -14 +3675 2274 -2 +3675 2273 2 +3675 2272 8 +3675 2271 11 +3675 2270 -5 +3674 2272 8 +3674 2271 11 +3674 2270 -5 +3673 2274 -2 +3673 2273 2 +3673 2272 8 +3673 2271 11 +3673 2270 -5 +3672 2273 2 +3672 2272 8 +3672 2271 11 +3672 2270 -5 +3671 2274 -2 +3671 2273 2 +3671 2272 8 +3671 2271 11 +3671 2270 -5 +3670 2299 -14 +3670 2291 -13 +3670 2274 -2 +3670 2273 2 +3670 2272 8 +3670 2270 -5 +3669 2270 -5 +3669 2270 0 +3666 2299 -14 +3657 2299 -14 +3653 2299 -14 +3674 2274 -2 +3674 2273 2 + +# brazier +Brazier 0x0E32 +3704 2217 20 +3704 2221 20 +3696 2224 20 +3696 2220 20 + +# cannon ball +Static 0x0E73 +3676 2261 20 + +# rock +Static 0x177C +3575 2119 23 +3742 2136 23 +3743 2114 20 +3638 2089 20 +3638 2100 22 +3616 2117 40 +3617 2146 78 +3613 2181 16 +3597 2141 66 + +# wood +Static 0x1B81 (Hue=0x3E1) +3550 2158 21 +3559 2126 20 +3559 2150 27 +3559 2152 26 +3553 2126 20 +3555 2150 25 +3647 2071 20 + +# dirt patch +Static 0x0911 +3557 2147 24 +3552 2127 20 +3549 2159 21 +3555 2130 20 +3556 2127 20 +3558 2151 27 +3656 2204 20 +3555 2137 20 +3559 2134 21 +3550 2161 20 +3733 2066 5 +3689 2069 5 +3539 2141 20 + +# garbage +Static 0x10EE (Hue=0x3E3) +3549 2149 21 +3556 2134 20 +3558 2154 24 +3541 2140 20 + +# small palm +Static 0x0C99 (Hue=0x3DB) +3637 2096 20 +3598 2126 59 +3684 2121 20 + +# large fern +Static 0x0CA1 (Hue=0x3D9) +3592 2144 61 +3590 2108 22 +3537 2150 20 +3726 2248 20 +3623 2115 39 +3635 2143 55 +3631 2106 22 +3615 2152 58 +3597 2141 66 +3595 2152 61 + +# garbage +Static 0x10EE (Hue=0x497) +3549 2159 21 +3558 2147 24 +3701 2176 20 +3552 2143 21 +3558 2156 23 +3555 2125 20 +3554 2152 24 +3555 2133 20 +3774 2073 20 +3548 2158 21 +3552 2120 -15 +3554 2139 20 +3689 2066 5 +3762 2055 20 +3555 2134 20 +3558 2125 20 +3555 2122 20 +3762 2065 24 +3552 2162 20 +3704 2069 5 +3655 2071 20 +3544 2142 20 +3706 2201 20 +3542 2149 20 +3541 2139 20 + +# fern +Static 0x0CA3 (Hue=0x3DA) +3585 2148 65 +3580 2158 46 +3767 2091 20 +3650 2085 20 +3644 2059 20 +3612 2107 21 +3567 2111 6 +3615 2117 41 +3596 2135 67 +3606 2156 58 +3601 2171 31 + +# candelabra +Static 0x0B27 +3684 2070 5 +3678 2110 20 +3670 2229 20 +3670 2118 20 +3664 2248 20 +3664 2096 20 +3656 2198 20 +3656 2190 20 +3656 2111 20 +3736 2062 5 +3766 2126 20 +3766 2096 20 +3704 2240 20 +3701 2165 20 +3680 2200 20 +3691 2078 5 +3767 2118 20 +3670 2176 20 +3702 2056 5 +3694 2170 20 + +# fern +Static 0x0CA3 (Hue=0x3D8) +3578 2122 25 +3763 2097 20 +3732 2259 20 +3644 2090 20 +3637 2157 63 +3771 2126 20 +3633 2080 20 +3634 2093 10 +3634 2080 20 +3596 2124 53 +3624 2153 68 +3618 2149 71 +3614 2118 42 +3618 2161 55 +3604 2138 68 +3607 2154 60 +3612 2174 31 +3595 2143 60 + +# small palm +Static 0x0C9B (Hue=0x3D9) +3648 2064 20 +3609 2106 21 +3615 2145 82 +3754 2081 28 +3601 2139 69 +3595 2135 67 + +# fallen log +Static 0x0CF7 (Hue=0x497) +3636 2150 53 +3597 2162 43 +3595 2127 55 + +# wooden plank +Static 0x07CE +3673 2262 20 +3673 2261 20 +3672 2272 7 +3693 2291 -3 +3693 2286 -3 +3668 2298 -3 +3692 2288 -3 +3691 2299 -3 +3691 2291 -3 +3690 2288 -3 +3689 2288 -3 +3688 2291 -3 +3687 2287 -3 +3664 2291 -3 +3686 2288 -3 +3684 2291 -3 +3684 2270 20 +3684 2261 20 +3683 2288 -3 +3683 2269 20 +3683 2264 20 +3683 2261 20 +3682 2291 -3 +3681 2288 -3 +3680 2298 -3 +3680 2288 -3 +3680 2263 20 +3680 2261 20 +3679 2298 -3 +3679 2291 -3 +3679 2269 20 +3679 2266 20 +3679 2262 20 +3679 2261 20 +3678 2299 -3 +3678 2287 -3 +3678 2267 20 +3693 2298 -3 +3678 2262 20 +3678 2261 20 +3677 2283 -3 +3677 2282 -3 +3692 2298 -3 +3692 2286 -3 +3677 2270 20 +3677 2268 20 +3677 2266 20 +3677 2262 20 +3677 2261 20 +3691 2279 -3 +3676 2288 -3 +3676 2283 -3 +3676 2282 -3 +3676 2278 -3 +3676 2272 7 +3676 2262 20 +3676 2261 20 +3675 2291 -3 +3675 2289 -3 +3675 2287 -3 +3675 2283 -3 +3675 2282 -3 +3675 2281 -3 +3675 2279 -3 +3675 2277 -3 +3675 2272 7 +3675 2270 20 +3675 2268 20 +3675 2262 20 +3675 2261 20 +3674 2283 -3 +3674 2282 -3 +3674 2262 20 +3674 2261 20 +3673 2289 -3 +3673 2283 -3 +3673 2282 -3 +3673 2281 -3 +3673 2279 -3 +3692 2279 -3 +3673 2272 7 +3672 2283 -3 +3672 2282 -3 +3683 2265 20 +3672 2263 20 +3672 2262 20 +3672 2261 20 +3671 2283 -3 +3671 2282 -3 +3671 2272 7 +3670 2284 -3 +3670 2283 -3 +3670 2282 -3 +3670 2274 -3 +3670 2272 7 +3669 2298 -3 +3669 2291 -3 +3668 2288 -3 +3667 2299 -3 +3667 2291 -3 +3667 2269 20 +3666 2288 -3 +3665 2288 -3 +3665 2270 20 +3664 2262 20 +3663 2287 -3 +3662 2288 -3 +3677 2288 -3 +3660 2291 -3 +3659 2290 -3 +3659 2288 -3 +3677 2280 -3 +3656 2298 -3 +3656 2288 -3 +3656 2286 -3 +3655 2298 -3 +3655 2291 -3 +3655 2286 -3 +3655 2279 -3 +3654 2299 -3 +3654 2287 -3 +3654 2279 -3 +3653 2288 -3 +3674 2272 7 +3673 2291 -3 + +# dirt +Static 0x1E00 +3550 2152 22 +3552 2147 23 +3541 2151 20 +3538 2149 20 +3553 2142 21 +3540 2141 20 +3548 2153 21 +3557 2157 23 +3721 2058 5 +3551 2142 22 +3548 2146 21 +3557 2162 20 +3543 2149 20 +3558 2137 22 +3555 2140 21 +3556 2136 20 +3733 2057 5 +3536 2133 18 +3671 2069 22 +3797 2150 24 +3632 2142 65 +3725 2066 5 +3736 2073 5 +3553 2121 20 +3556 2117 20 +3557 2118 20 +3559 2154 25 +3558 2155 24 +3670 2060 20 +3703 2057 5 +3771 2072 21 + +# garbage +Static 0x10EE (Hue=0x3E1) +3570 2113 20 +3558 2119 20 +3724 2068 5 + +# pampas grass +Static 0x0CA5 (Hue=0x3DA) +3580 2123 26 +3569 2120 21 +3636 2096 20 +3597 2149 62 + +# fern +Static 0x0CA0 (Hue=0x3DB) +3586 2131 52 +3577 2124 27 +3568 2166 20 +3768 2093 20 +3738 2259 20 +3699 2106 20 +3619 2146 77 +3636 2157 66 +3623 2148 79 +3637 2103 23 +3602 2152 58 +3630 2119 41 +3604 2126 62 +3605 2127 63 +3769 2205 14 + +# dirt patch +Static 0x0912 (Hue=0x497) +3548 2147 21 +3552 2144 23 +3555 2129 20 +3729 2131 20 +3687 2060 5 +3656 2136 20 +3542 2149 20 +3723 2069 5 + +# dirt +Static 0x1DFF (Hue=0x497) +3546 2139 20 +3536 2139 20 +3543 2139 20 +3719 2069 5 +3698 2074 5 +3551 2163 20 +3551 2164 20 +3550 2144 21 +3550 2132 20 +3554 2151 24 +3559 2150 27 +3721 2212 20 +3547 2141 20 +3547 2146 20 +3548 2151 21 +3549 2161 20 +3557 2137 21 +3759 2060 21 +3718 2061 5 +3551 2146 22 +3555 2160 21 +3744 2070 5 +3544 2157 19 +3555 2125 20 +3557 2122 20 +3552 2156 23 +3698 2227 20 +3550 2155 22 +3737 2069 5 +3555 2136 20 +3552 2138 20 + +# small palm +Static 0x0C9B (Hue=0x3DB) +3753 2141 20 +3638 2090 20 +3631 2104 20 +3598 2132 65 +3594 2142 64 + +# fern +Static 0x0CA4 (Hue=0x3D8) +3576 2122 24 +3576 2123 25 +3766 2090 24 +3644 2141 36 +3605 2131 68 +3598 2151 60 +3599 2144 63 +3597 2132 66 +3594 2137 69 + +# ponytail palm +Static 0x0CA6 (Hue=0x3DB) +3619 2167 41 +3601 2142 69 +3594 2136 68 + +# dirt +Static 0x1DFF (Hue=0x3E3) +3545 2137 20 +3552 2134 20 +3544 2137 20 +3554 2152 24 +3553 2146 24 +3555 2141 21 +3555 2123 20 +3542 2152 20 +3745 2068 5 +3656 2067 20 +3556 2149 26 +3749 2113 20 + +# dirt +Static 0x1DFE (Hue=0x3E4) +3539 2138 20 +3546 2138 20 +3552 2148 23 +3548 2160 20 +3551 2164 20 +3550 2165 20 +3746 2063 5 + +# stone ruins +Static 0x03BC +3685 2249 20 +3756 2122 20 +3783 2111 20 +3639 2097 21 +3658 2223 20 +3765 2214 20 +3743 2094 20 +3753 2082 27 +3727 2213 20 +3644 2115 28 +3689 2240 20 +3701 2182 20 +3696 2083 5 +3729 2157 20 +3697 2176 20 +3783 2110 20 +3739 2089 8 + +# bookcase +FullBookcase 0x0A98 +3698 2056 5 +3700 2240 20 +3704 2208 40 +3758 2120 20 +3681 2200 20 +3771 2104 40 +3669 2248 20 +3695 2056 5 + +# dirt +Static 0x1DFF (Hue=0x3E4) +3544 2138 20 +3741 2058 5 +3550 2131 20 +3537 2147 20 +3557 2136 20 +3557 2121 20 + +# fallen log +Static 0x0CF6 (Hue=0x3DB) +3587 2154 60 +3594 2127 55 + +# wooden chair +WoodenThrone 0x0B2F +3681 2203 20 +3670 2281 -2 + +# bushel +Basket 0x09AC +3684 2269 20 +3686 2268 20 + +# barrel +Barrel 0x0E77 +3680 2256 20 +3670 2279 -2 + +# metal box +MetalBox 0x09A8 +3671 2280 4 + +# chair +WoodenChair 0x0B58 +3662 2117 20 +3662 2116 20 +3773 2106 40 +3773 2108 40 +3723 2084 5 +3692 2164 20 +3700 2073 5 +3692 2166 20 + +# small palm +Static 0x0C9B (Hue=0x497) +3795 2092 20 +3643 2082 20 +3640 2100 23 +3595 2128 59 +3597 2118 40 +3590 2164 37 + +# morning glories +Static 0x0D34 (Hue=0x3DA) +3592 2156 58 +3590 2145 62 + +# grasses +Static 0x0CAF (Hue=0x3DB) +3800 2121 21 + +# small palm +Static 0x0C9D (Hue=0x3DB) +3734 2135 20 +3559 2165 20 +3650 2104 21 +3637 2084 20 +3606 2151 59 +3596 2145 64 +3593 2146 62 + +# elephant ear plant +Static 0x0C97 (Hue=0x3DA) +3594 2124 52 +3702 2100 15 +3788 2150 20 +3734 2260 20 +3633 2121 40 +3614 2143 86 +3593 2143 61 + +# bed +Static 0x0A5D +3665 2268 21 +3665 2266 21 + +# bookcase +FullBookcase 0x0A99 +3680 2206 20 +3664 2250 20 +3680 2202 20 +3680 2205 20 +3680 2201 20 +3696 2247 20 +3691 2077 5 +3691 2076 5 + +# bed +Static 0x0A5F +3694 2214 20 +3694 2218 20 +3694 2212 20 +3694 2216 20 +3669 2263 21 + +# window +Static 0x0162 +3679 2204 20 +3679 2203 20 +3679 2202 20 + +# jars +Static 0x0E4F +3666 2261 20 + +# lamp post +LampPost3 0x0B24 +3679 2261 21 +3679 2215 30 +3679 2208 30 +3679 2137 20 +3679 2112 20 +3672 2240 20 +3737 2076 5 +3711 2160 20 +3704 2136 20 +3704 2112 20 +3704 2048 5 +3743 2232 20 +3743 2215 20 +3696 2176 20 +3734 2087 5 +3727 2055 5 +3719 2232 20 +3744 2112 20 +3736 2252 20 +3736 2191 20 +3686 2215 30 +3735 2167 20 +3727 2112 20 +3727 2072 5 +3719 2208 20 +3711 2184 20 +3711 2072 5 +3704 2097 5 +3695 2232 20 +3742 2076 5 + +# snake plant +Static 0x0CA9 (Hue=0x3D8) +3592 2158 54 + +# cannon +Static 0x0E96 +3699 2257 20 + +# chair +WoodenChair 0x0B59 +3676 2101 20 +3719 2085 5 +3691 2162 20 +3721 2085 5 +3703 2212 40 +3707 2212 40 +3705 2212 40 +3698 2062 5 +3697 2062 5 +3691 2167 20 + +# milk +Static 0x09F0 +3671 2282 4 +3683 2203 29 +3722 2228 24 +3770 2107 24 +3691 2166 24 + +# bulrushes +Static 0x0C94 (Hue=0x497) +3667 2086 20 +3761 2085 30 +3625 2171 36 +3634 2072 11 +3617 2151 65 +3597 2126 58 +3672 2091 20 + +# cannon +Static 0x0E95 +3698 2257 20 + +# chair +WoodenChair 0x0B57 +3676 2098 20 +3703 2210 40 +3691 2152 20 +3721 2082 5 +3701 2152 20 +3719 2082 5 +3707 2210 40 +3705 2210 40 +3699 2056 5 +3698 2060 5 +3697 2060 5 +3694 2056 5 +3691 2162 20 + +# cannon +Static 0x0E8D +3673 2259 20 +3677 2259 20 + +# fern +Static 0x0CA3 (Hue=0x497) +3579 2124 31 +3537 2151 20 +3786 2127 23 +3773 2215 20 +3771 2211 20 +3783 2084 21 +3626 2119 42 +3612 2172 31 +3605 2134 71 +3601 2149 60 +3730 2255 20 +3610 2161 48 +3592 2143 61 + +# candelabra +Static 0x0B28 +3672 2110 20 +3670 2259 20 +3670 2198 20 +3666 2238 20 +3664 2102 20 +3663 2182 20 +3662 2104 20 +3661 2232 20 +3701 2160 20 +3760 2104 20 +3703 2250 20 +3742 2067 5 +3742 2062 5 +3688 2160 20 +3710 2240 20 +3702 2078 5 +3691 2063 5 + +# carpet +Static 0x0AE7 +3697 2218 41 + diff --git a/Data/Decoration/Stygian Abyss/Ter Mur/Stygian Abyss.cfg b/Data/Decoration/Stygian Abyss/Ter Mur/Stygian Abyss.cfg new file mode 100644 index 0000000..8455855 --- /dev/null +++ b/Data/Decoration/Stygian Abyss/Ter Mur/Stygian Abyss.cfg @@ -0,0 +1,14 @@ +################# +# Stygian Abyss # +################# + +############################ +# Entrance from Underworld # +############################ + +Teleporter 7107 (PointDest=(1125, 1076, -117); MapDestination=TerMur) +519 919 39 + +Teleporter 7107 (PointDest=(1126, 1076, -117); MapDestination=TerMur) +520 919 39 + diff --git a/Data/Decoration/Stygian Abyss/Ter Mur/UnderwordMegaStonePavers.cfg b/Data/Decoration/Stygian Abyss/Ter Mur/UnderwordMegaStonePavers.cfg new file mode 100644 index 0000000..f29bb71 --- /dev/null +++ b/Data/Decoration/Stygian Abyss/Ter Mur/UnderwordMegaStonePavers.cfg @@ -0,0 +1,591 @@ +# Saved By Static Exporter +# StaticExport by Nerun +# Version 2.3 + +#Go + +Teleporter 7107 (PointDest=(1062, 1067, -42); MapDestination=TerMur) +1062 1061 -42 + +Teleporter 7107 (PointDest=(1061, 1067, -42); MapDestination=TerMur) +1061 1061 -42 + +Teleporter 7107 (PointDest=(1060, 1067, -42); MapDestination=TerMur) +1060 1061 -42 + +Teleporter 7107 (PointDest=(1059, 1067, -42); MapDestination=TerMur) +1059 1061 -42 + +Teleporter 7107 (PointDest=(1058, 1067, -42); MapDestination=TerMur) +1058 1061 -42 + +Teleporter 7107 (PointDest=(1057, 1067, -42); MapDestination=TerMur) +1057 1061 -42 + +Teleporter 7107 (PointDest=(1063, 1067, -42); MapDestination=TerMur) +1063 1061 -42 + +#Back + +Teleporter 7107 (PointDest=(1061, 1061, -42); MapDestination=TerMur) +1061 990 -42 + +Teleporter 7107 (PointDest=(1058, 1061, -42); MapDestination=TerMur) +1058 990 -42 + +Teleporter 7107 (PointDest=(1057, 1061, -42); MapDestination=TerMur) +1057 990 -42 + +Teleporter 7107 (PointDest=(1062, 1061, -42); MapDestination=TerMur) +1062 990 -42 + +Teleporter 7107 (PointDest=(1059, 1061, -42); MapDestination=TerMur) +1059 990 -42 + +Teleporter 7107 (PointDest=(1060, 1061, -42); MapDestination=TerMur) +1060 990 -42 + +Teleporter 7107 (PointDest=(1063, 1061, -42); MapDestination=TerMur) +1063 990 -42 + +StonePaversDark 0x0521 +1063 1018 -42 +1063 1012 -42 +1063 1003 -42 +1063 1006 -42 +1061 1025 -42 +1063 1005 -42 +1062 1023 -42 +1064 1003 -42 +1064 1001 -42 +1064 1002 -42 +1063 1011 -42 +1063 1016 -42 +1063 1017 -42 +1064 992 -42 +1063 1022 -42 +1062 1025 -42 +1064 991 -42 +1063 997 -42 +1064 998 -42 +1063 995 -42 +1064 1024 -42 +1063 996 -42 +1063 1000 -42 +1064 1023 -42 +1063 1025 -42 +1063 1001 -42 +1061 1024 -42 +1064 996 -42 +1063 1009 -42 +1064 1025 -42 +1064 995 -42 +1064 1000 -42 +1062 1024 -42 +1064 999 -42 +1064 1007 -42 +1064 1006 -42 +1064 1020 -42 +1064 994 -42 +1064 993 -42 +1063 1004 -42 +1063 1010 -42 +1063 999 -42 +1063 998 -42 +1063 1014 -42 +1064 1005 -42 +1063 1020 -42 +1064 1004 -42 +1063 1019 -42 +1064 1013 -42 +1064 1010 -42 +1064 1011 -42 +1064 1017 -42 +1064 1012 -42 +1064 1009 -42 +1061 1023 -42 +1064 1019 -42 +1064 1018 -42 +1064 1008 -42 +1064 1016 -42 +1064 1015 -42 +1064 1014 -42 +1063 1023 -42 +1060 1025 -42 +1060 1024 -42 +1060 1023 -42 +1059 1025 -42 +1059 1024 -42 +1059 1023 -42 +1063 1013 -42 +1058 1025 -42 +1058 1024 -42 +1057 1024 -42 +1057 1023 -42 +1058 1023 -42 +1057 1025 -42 +1063 1002 -42 +1063 1007 -42 +1063 1008 -42 +1064 997 -42 +1063 1015 -42 +1063 1021 -42 +1063 993 -42 +1063 994 -42 +1063 1024 -42 +1057 997 -42 +1058 1019 -42 +1061 1004 -42 +1062 1016 -42 +1060 996 -42 +1059 1023 -42 +1062 998 -42 +1062 1001 -42 +1062 1005 -42 +1062 1000 -42 +1062 1004 -42 +1062 1003 -42 +1062 999 -42 +1059 991 -42 +1058 1020 -42 +1058 1018 -42 +1061 1007 -42 +1061 1012 -42 +1061 1013 -42 +1061 1014 -42 +1058 1021 -42 +1057 998 -42 +1061 1009 -42 +1061 1010 -42 +1061 1011 -42 +1060 1013 -42 +1060 1014 -42 +1060 1012 -42 +1060 1015 -42 +1060 1008 -42 +1060 1009 -42 +1060 1010 -42 +1060 1004 -42 +1057 1007 -42 +1058 1015 -42 +1057 1011 -42 +1057 1014 -42 +1060 1002 -42 +1060 1005 -42 +1060 1000 -42 +1057 1015 -42 +1057 1006 -42 +1061 1006 -42 +1061 1005 -42 +1057 1008 -42 +1057 1012 -42 +1061 1003 -42 +1061 1008 -42 +1057 991 -42 +1057 1005 -42 +1057 1004 -42 +1057 1010 -42 +1057 992 -42 +1057 1009 -42 +1057 1013 -42 +1058 998 -42 +1057 1023 -42 +1059 1002 -42 +1057 1003 -42 +1059 1001 -42 +1060 1003 -42 +1057 1000 -42 +1060 1023 -42 +1058 1001 -42 +1060 1021 -42 +1060 1011 -42 +1060 1001 -42 +1060 1007 -42 +1060 1006 -42 +1057 993 -42 +1057 1018 -42 +1060 1022 -42 +1057 1017 -42 +1057 1016 -42 +1057 994 -42 +1058 999 -42 +1060 1016 -42 +1060 1019 -42 +1058 1000 -42 +1060 1020 -42 +1060 1018 -42 +1060 1017 -42 +1059 1003 -42 +1061 991 -42 +1059 992 -42 +1058 1007 -42 +1057 995 -42 +1061 1016 -42 +1062 993 -42 +1061 998 -42 +1061 997 -42 +1061 1017 -42 +1061 1018 -42 +1061 1021 -42 +1062 992 -42 +1061 1020 -42 +1058 996 -42 +1061 1022 -42 +1061 1023 -42 +1062 991 -42 +1062 994 -42 +1062 997 -42 +1062 996 -42 +1062 995 -42 +1058 994 -42 +1062 1014 -42 +1061 1019 -42 +1058 991 -42 +1058 995 -42 +1059 1004 -42 +1060 999 -42 +1058 997 -42 +1057 999 -42 +1057 1021 -42 +1057 1020 -42 +1058 993 -42 +1058 992 -42 +1057 1022 -42 +1057 1019 -42 +1058 1009 -42 +1061 994 -42 +1061 992 -42 +1058 1003 -42 +1061 996 -42 +1058 1006 -42 +1061 995 -42 +1061 1002 -42 +1058 1002 -42 +1057 996 -42 +1058 1014 -42 +1058 1013 -42 +1059 1006 -42 +1058 1016 -42 +1061 1000 -42 +1058 1012 -42 +1061 993 -42 +1061 999 -42 +1058 1017 -42 +1058 1005 -42 +1058 1004 -42 +1061 1001 -42 +1058 1011 -42 +1058 1010 -42 +1058 1008 -42 +1059 995 -42 +1062 1006 -42 +1059 996 -42 +1058 1022 -42 +1058 1023 -42 +1061 1015 -42 +1059 1007 -42 +1059 1013 -42 +1064 1058 -42 +1059 1008 -42 +1059 1015 -42 +1059 1014 -42 +1062 1002 -42 +1059 1005 -42 +1060 993 -42 +1059 1010 -42 +1059 1009 -42 +1059 1012 -42 +1059 1011 -42 +1059 1054 -42 +1060 1052 -42 +1059 1020 -42 +1060 995 -42 +1060 991 -42 +1059 1019 -42 +1059 1021 -42 +1060 994 -42 +1059 1022 -42 +1060 992 -42 +1057 1002 -42 +1059 1035 -42 +1059 1049 -42 +1062 1007 -42 +1062 1012 -42 +1062 1009 -42 +1062 1010 -42 +1062 1008 -42 +1059 1018 -42 +1059 1017 -42 +1059 1041 -42 +1057 1001 -42 +1062 1013 -42 +1060 1051 -42 +1062 1011 -42 +1059 1045 -42 +1059 1048 -42 +1059 1047 -42 +1062 1017 -42 +1062 1022 -42 +1059 1058 -42 +1059 1040 -42 +1059 1044 -42 +1062 1018 -42 +1062 1021 -42 +1057 1060 -42 +1062 1020 -42 +1059 1055 -42 +1059 998 -42 +1059 1056 -42 +1059 1060 -42 +1058 1036 -42 +1058 1047 -42 +1062 1019 -42 +1060 1053 -42 +1060 1054 -42 +1059 1034 -42 +1060 1030 -42 +1059 1057 -42 +1057 1059 -42 +1059 1059 -42 +1060 1029 -42 +1060 1058 -42 +1060 1055 -42 +1060 1046 -42 +1060 1045 -42 +1059 1032 -42 +1060 1057 -42 +1060 1056 -42 +1058 1031 -42 +1059 994 -42 +1059 997 -42 +1058 1050 -42 +1059 993 -42 +1059 1000 -42 +1059 1016 -42 +1059 1036 -42 +1062 1015 -42 +1058 1049 -42 +1064 1055 -42 +1059 999 -42 +1064 1056 -42 +1059 1029 -42 +1060 997 -42 +1059 1033 -42 +1064 1059 -42 +1058 1033 -42 +1059 1031 -42 +1058 1034 -42 +1059 1046 -42 +1058 1060 -42 +1059 1030 -42 +1058 1032 -42 +1064 1060 -42 +1064 1053 -42 +1058 1035 -42 +1064 1057 -42 +1064 1052 -42 +1059 1050 -42 +1059 1042 -42 +1059 1037 -42 +1059 1051 -42 +1059 1043 -42 +1058 1048 -42 +1064 1054 -42 +1060 998 -42 +1059 1052 -42 +1059 1053 -42 +1059 1038 -42 +1059 1039 -42 +1057 1030 -42 +1057 1031 -42 +1057 1029 -42 +1057 1034 -42 +1057 1055 -42 +1057 1056 -42 +1057 1035 -42 +1057 1036 -42 +1057 1033 -42 +1057 1040 -42 +1057 1037 -42 +1057 1038 -42 +1057 1045 -42 +1057 1032 -42 +1057 1039 -42 +1057 1042 -42 +1057 1043 -42 +1057 1044 -42 +1057 1048 -42 +1057 1041 -42 +1057 1053 -42 +1057 1046 -42 +1057 1047 -42 +1057 1057 -42 +1057 1050 -42 +1057 1051 -42 +1057 1052 -42 +1057 1054 -42 +1057 1049 -42 +1058 1029 -42 +1060 1041 -42 +1058 1052 -42 +1058 1030 -42 +1058 1051 -42 +1060 1034 -42 +1057 1058 -42 +1058 1037 -42 +1058 1046 -42 +1058 1041 -42 +1058 1040 -42 +1060 1040 -42 +1058 1042 -42 +1058 1053 -42 +1058 1055 -42 +1060 1032 -42 +1058 1044 -42 +1058 1039 -42 +1058 1058 -42 +1058 1043 -42 +1058 1038 -42 +1060 1035 -42 +1058 1059 -42 +1058 1057 -42 +1058 1054 -42 +1058 1056 -42 +1060 1038 -42 +1060 1033 -42 +1060 1031 -42 +1060 1036 -42 +1058 1045 -42 +1060 1039 -42 +1060 1042 -42 +1060 1047 -42 +1060 1049 -42 +1060 1050 -42 +1060 1043 -42 +1060 1048 -42 +1060 1037 -42 +1060 1044 -42 +1060 1059 -42 +1060 1060 -42 +1061 1029 -42 +1061 1030 -42 +1061 1031 -42 +1061 1032 -42 +1061 1033 -42 +1061 1034 -42 +1061 1035 -42 +1061 1042 -42 +1061 1043 -42 +1061 1040 -42 +1061 1041 -42 +1061 1038 -42 +1061 1039 -42 +1061 1036 -42 +1061 1037 -42 +1061 1044 -42 +1061 1045 -42 +1061 1046 -42 +1061 1047 -42 +1061 1048 -42 +1061 1049 -42 +1061 1050 -42 +1062 1037 -42 +1062 1038 -42 +1062 1035 -42 +1062 1036 -42 +1062 1033 -42 +1062 1034 -42 +1062 1031 -42 +1062 1032 -42 +1062 1029 -42 +1062 1030 -42 +1061 1059 -42 +1061 1060 -42 +1061 1057 -42 +1061 1058 -42 +1061 1055 -42 +1061 1056 -42 +1061 1053 -42 +1061 1054 -42 +1061 1052 -42 +1061 1051 -42 +1062 1039 -42 +1064 1047 -42 +1064 1048 -42 +1064 1049 -42 +1062 1040 -42 +1062 1041 -42 +1062 1042 -42 +1064 1046 -42 +1062 1043 -42 +1062 1044 -42 +1062 1045 -42 +1062 1050 -42 +1062 1046 -42 +1062 1047 -42 +1062 1048 -42 +1062 1049 -42 +1062 1052 -42 +1062 1053 -42 +1062 1054 -42 +1062 1055 -42 +1062 1051 -42 +1062 1056 -42 +1062 1057 -42 +1062 1058 -42 +1062 1059 -42 +1062 1060 -42 +1063 1029 -42 +1063 1031 -42 +1063 1032 -42 +1063 1035 -42 +1063 1034 -42 +1063 1030 -42 +1063 1036 -42 +1063 1037 -42 +1063 1033 -42 +1063 1038 -42 +1063 1039 -42 +1063 1040 -42 +1063 1042 -42 +1063 1043 -42 +1063 1045 -42 +1063 1046 -42 +1063 1041 -42 +1063 1048 -42 +1063 1051 -42 +1063 1044 -42 +1063 1049 -42 +1063 1047 -42 +1063 1050 -42 +1063 1054 -42 +1063 1053 -42 +1063 1056 -42 +1063 1057 -42 +1063 1052 -42 +1063 1059 -42 +1063 1055 -42 +1063 1060 -42 +1064 1029 -42 +1063 1058 -42 +1064 1030 -42 +1064 1031 -42 +1064 1032 -42 +1064 1033 -42 +1064 1034 -42 +1064 1035 -42 +1064 1036 -42 +1064 1037 -42 +1064 1038 -42 +1064 1041 -42 +1064 1042 -42 +1064 1045 -42 +1064 1039 -42 +1064 1040 -42 +1064 1043 -42 +1064 1044 -42 +1062 1023 -42 +1064 1050 -42 +1064 1051 -42 +1063 991 -42 +1063 992 -42 \ No newline at end of file diff --git a/Data/Decoration/Stygian Abyss/Ter Mur/Underworld.cfg b/Data/Decoration/Stygian Abyss/Ter Mur/Underworld.cfg new file mode 100644 index 0000000..a66e747 --- /dev/null +++ b/Data/Decoration/Stygian Abyss/Ter Mur/Underworld.cfg @@ -0,0 +1,451 @@ +############## +# Underworld # +############## + +################################ +#Entrance - Underworld-Britain # +################################ + +Teleporter 7107 (PointDest=(4194, 3261, 5); MapDestination=Trammel) +1125 1215 5 + +Teleporter 7107 (PointDest=(4194, 3261, 5); MapDestination=Trammel) +1126 1215 5 + +Teleporter 7107 (PointDest=(4194, 3261, 5); MapDestination=Trammel) +1127 1215 5 + +Teleporter 7107 (PointDest=(4194, 3261, 5); MapDestination=Trammel) +1128 1215 5 + +Teleporter 7107 (PointDest=(4195, 3261, 5); MapDestination=Trammel) +1129 1215 5 + +Teleporter 7107 (PointDest=(4195, 3261, 5); MapDestination=Trammel) +1130 1215 5 + +Teleporter 7107 (PointDest=(4195, 3261, 5); MapDestination=Trammel) +1131 1215 5 + +# Water behind memorial stone +Static 0x1797 +1120 1203 -2 +1120 1204 -2 +1120 1205 -2 +1120 1205 -2 +1120 1206 -2 +1120 1207 -2 +1120 1208 -2 +1120 1209 -2 +1121 1202 -2 +1121 1203 -2 +1121 1204 -2 +1121 1209 -2 +1122 1202 -2 +1122 1203 -2 +1122 1204 -2 +1122 1209 -2 +1122 1210 -2 + +Static 0x117F (Name=Memorial Stone) +1121 1206 -2 + +# Barrel with lid +Static 0x0FAE +1133 1200 -2 +1123 1200 -2 +1124 1200 -2 + +Cannon 0 +1126 1200 -2 +1131 1200 -2 + +Static 0x0E73 (Name=Cannon Ball) +1131 1201 -2 + +# Three Cannon Balls +Static 0x0E74 +1124 1201 -2 +1124 1201 -2 +1132 1200 -2 + +# Rope +Static 0x14FA +1125 1201 -2 + +# Bag +Static 0x0E76 +1123 1200 3 + +# Secret Shadow Wall +SecretShadowWallNS 0x363A +1136 1166 -12 + +# Secret Passage: Stone stairs +Static 0x0752 (Hue=2000) +1139 1165 -27 +1138 1166 -22 +1139 1166 -27 +1140 1165 -32 +1137 1166 -17 + +# Secret Dungeon Wall +SecretDungeonWallNS 0x0242 +1140 1165 -32 + +########################## +# Blue Key Fragment Room # +########################## + +#Odd vines covering secret wall (need Acid Sac from Acid Slug) +StoneWallAndVineAddon 0 +1064 1184 -42 + +#Secret path to the blue key (Wall covered by Vine) +Static 0x0490 +1063 1185 -42 +1063 1186 -42 +1063 1184 -42 +1064 1184 -42 +1063 1187 -42 +1063 1192 -42 +1063 1193 -42 +1064 1195 -42 +1063 1195 -42 +1063 1194 -42 +1063 1189 -42 +1063 1188 -42 +1063 1191 -42 +1063 1190 -42 + +#Secret Room SouthWest +#Globe of Sosaria +Static 0x3660 (Hue=1000) +1070 1197 -39 + +#Secret Room SouthWest +UnderworldSwitchWE 0x1091 +1069 1193 -36 + +#Secret Room SouthWest +#Blue Key Fragment +Static 0x1012 (Hue=3; Name=Blue Key Fragment) +1070 1196 -35 + +#Secret Room SouthWest +Blocker 0x21A4 +1070 1197 -42 +1070 1196 -42 +1069 1196 -42 + +################################ +# Room with skeletons and magi # +################################ + +Teleporter 7107 (PointDest=(1012, 1071, -32); MapDestination=TerMur) +1006 1110 -42 + +Teleporter 7107 (PointDest=(1010, 1144, -65); MapDestination=TerMur) +1006 1127 -42 + +Teleporter 7107 (PointDest=(1006, 1127, -42); MapDestination=TerMur) +1010 1144 -65 + +Teleporter 7107 (PointDest=(1006, 1110, -42); MapDestination=TerMur) +1012 1071 -32 + +# Sparkles +Static 0x375A +1006 1110 -42 +1006 1127 -42 +1012 1071 -32 +1010 1144 -65 + +######################### +# Red Key Fragment Room # +######################### + +DungeonWallAndVineAddon 0 +1012 1049 -32 + +#Glowing Rune +Static 0x0E64 +1004 1051 -33 +1003 1050 -32 +1003 1052 -33 +1002 1051 -33 + +#Globe of Sosaria +Static 0x3660 (Hue=1000) +1004 1052 -31 + +#Red Key Fragment +Static 0x1012 (Hue=433; Name=Red Key Fragment) +1004 1051 -26 + +#Ruined books +Static 0x0C16 +1002 1045 -32 + +UnderworldSwitchWE 0x1091 +1005 1044 -21 + +#Dungeon stone block (braziers support) +Static 0x07A3 +1000 1044 -32 +1000 1054 -33 + +#Brazier +Static 0x19BB +1000 1044 -25 +1000 1054 -25 + +#Brazier's fire +Static 0x19AB +1000 1044 -23 +1000 1054 -23 + +#Mandrake root +Static 0x18DE +1004 1044 -26 + +#Magic crystal +Static 0x1F19 +1002 1044 -26 + +#Painting +Static 0x0EA0 +1004 1044 -28 + +#Table +Static 0x1206 (Hue=802) +1004 1044 -32 +1003 1044 -32 + +#Table +Static 0x1205 (Hue=802) +1002 1044 -32 + +#Table +Static 0x1204 (Hue=802) +1005 1044 -32 + +#Elven Alchemy Table +Static 0x3077 +1000 1052 -33 + +#Elven Alchemy Table +Static 0x3078 +1000 1051 -33 + +#Ruined fallen chair +Static 0x0C1A +1003 1046 -32 + +#Skull with candle +Static 0x1857 +1003 1044 -26 + +#Bookcase +Static 0x0A9C +1000 1047 -32 + +#Debris +Static 0x0C2E +1000 1050 -33 + +RuinedBookcase 0x0C15 +1000 1048 -33 + +#Spider web +Static 0x0EE4 +1000 1049 -33 + +#Spider web +Static 0x0EE5 +1006 1044 -32 + +######################### +# Water Elemental Ruins # +######################### + +Teleporter 7107 (PointDest=(1183, 1187, -45); MapDestination=TerMur) +1183 1189 -44 + +Teleporter 7107 (PointDest=(1183, 1189, -44); MapDestination=TerMur) +1183 1187 -45 + +Teleporter 7107 (PointDest=(1183, 1179, -45); MapDestination=TerMur) +1185 1179 -45 + +Teleporter 7107 (PointDest=(1183, 1182, -47); MapDestination=TerMur) +1183 1180 -45 + +Teleporter 7107 (PointDest=(1186, 1177, -45); MapDestination=TerMur) +1184 1177 -47 + +Teleporter 7107 (PointDest=(1184, 1177, -47); MapDestination=TerMur) +1186 1177 -45 + +Teleporter 7107 (PointDest=(1187, 1173, -47); MapDestination=TerMur) +1187 1175 -45 + +Teleporter 7107 (PointDest=(1187, 1175, -45); MapDestination=TerMur) +1187 1173 -47 + +Teleporter 7107 (PointDest=(1201, 1190, -73); MapDestination=TerMur) +1203 1190 -74 + +Teleporter 7107 (PointDest=(1201, 1186, -68); MapDestination=TerMur) +1201 1189 -71 + +Teleporter 7107 (PointDest=(1200, 1190, -64); MapDestination=TerMur) +1200 1187 -66 + +Teleporter 7107 (PointDest=(1195, 1189, -56); MapDestination=TerMur) +1197 1189 -58 + +Teleporter 7107 (PointDest=(1190, 1186, -41); MapDestination=TerMur) +1192 1186 -40 + +Teleporter 7107 (PointDest=(1190, 1183, -40); MapDestination=TerMur) +1190 1185 -40 + +Teleporter 7107 (PointDest=(1187, 1180, -45); MapDestination=TerMur) +1188 1182 -42 + +Teleporter 7107 (PointDest=(1204, 1181, -45); MapDestination=TerMur) +1206 1181 -47 + +Teleporter 7107 (PointDest=(1202, 1185, -45); MapDestination=TerMur) +1202 1183 -45 + +Teleporter 7107 (PointDest=(1196, 1187, -45); MapDestination=TerMur) +1198 1187 -45 + +Teleporter 7107 (PointDest=(1183, 1180, -45); MapDestination=TerMur) +1183 1182 -47 + +############# +# Ankh Room # +############# + +Moongate 3948 (Hue=34; PointDest=(1180, 885, 0); TargetMap=TerMur; Dispellable=false) +1187 1126 -42 + +Moongate 3948 (Target=(1187, 1126, -42); TargetMap=TerMur; Dispellable=false) +1180 885 0 + +############################# +# Entrance to Stygian Abyss # +############################# + +Teleporter 7107 (PointDest=(1147, 1089, -42); MapDestination=TerMur) +1162 1120 -42 + +#Sparkle +Static 0x375A +1162 1120 -42 + +Teleporter 7107 (PointDest=(519, 919, 39); MapDestination=TerMur) +1125 1076 -117 + +Teleporter 7107 (PointDest=(520, 919, 39); MapDestination=TerMur) +1126 1076 -117 + +##################### +# Other Teleporters # +##################### + +Teleporter 7107 (PointDest=(1042, 1047, -33); MapDestination=TerMur) +1238 1151 -42 + +Static 0x375A +1238 1151 -42 + +Teleporter 7107 (PointDest=(1238, 1151, -42); MapDestination=TerMur) +1042 1047 -33 + +Static 0x375A +1042 1047 -33 + +Teleporter 7107 (PointDest=(1238, 1151, -42); MapDestination=TerMur) +1140 951 -42 + +Static 0x375A +1140 951 -42 + +################## +# Spider's Place # +################## + +Teleporter 7107 (PointDest=(1080, 978, -23); MapDestination=TerMur) +1078 882 3 + +Static 0x1775 +1078 882 0 +1078 881 0 +1077 882 0 +1077 881 0 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1080 976 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1078 973 -19 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1079 973 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1082 974 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1081 976 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1082 975 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1079 976 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1079 974 -20 + +Teleporter 7107 (PointDest=(1080, 884, -4); MapDestination=TerMur) +1083 973 -20 + +########### +# No Name # +########### + +Static 0x0BD1 (Name=Please Return What You Borrow!) +1072 1055 -39 + +FishingPole 0x0DC0 +1073 1057 -43 + +Spyglass 0x14F6 +1070 1055 -37 + +Sextant 0x1057 +1071 1055 -37 + +Static 0x14ED +1072 1055 -36 + +Static 0x14EB +1072 1055 -37 + +Static 0x0C15 +1069 1059 -43 + +Static 0x1206 +1071 1055 -43 +1072 1055 -43 + +Static 0x1205 +1070 1055 -43 + +Static 0x1204 +1073 1055 -43 diff --git a/Data/Decoration/Stygian Abyss/Trammel/SA.cfg b/Data/Decoration/Stygian Abyss/Trammel/SA.cfg new file mode 100644 index 0000000..ae54f08 --- /dev/null +++ b/Data/Decoration/Stygian Abyss/Trammel/SA.cfg @@ -0,0 +1,7 @@ +#Underworld entrance (Fire Island) + +Teleporter 7107 (PointDest=(1128, 1213, -2); MapDestination=TerMur) +4194 3260 5 + +Teleporter 7107 (PointDest=(1129, 1213, -2); MapDestination=TerMur) +4195 3260 5 \ No newline at end of file diff --git a/Data/Decoration/Tokuno/terrible hatchlings quest.cfg b/Data/Decoration/Tokuno/terrible hatchlings quest.cfg new file mode 100644 index 0000000..19ca947 --- /dev/null +++ b/Data/Decoration/Tokuno/terrible hatchlings quest.cfg @@ -0,0 +1,3 @@ +#Ansella Gryen +Spawner 0x1F13 (Spawn=AnsellaGryen; Count=1; HomeRange=0) +760 1200 25 \ No newline at end of file diff --git a/Data/Decoration/Tokuno/tokuno.cfg b/Data/Decoration/Tokuno/tokuno.cfg new file mode 100644 index 0000000..dd5c4fa --- /dev/null +++ b/Data/Decoration/Tokuno/tokuno.cfg @@ -0,0 +1,127 @@ +# ankh +Static 0x0002 +296 712 55 +780 1219 46 +1042 508 15 +1051 508 15 + +# ankh +Static 0x0003 +296 711 55 +780 1218 46 +1042 507 15 +1051 507 15 + +# ankh +Static 0x0004 +717 1158 27 + +# ankh +Static 0x0005 +718 1158 27 + +# backgammon board +Backgammon 0x0E1C +691 1255 48 + +# backgammon game +Backgammon 0x0FAD +668 1258 47 + +# archery butte +ArcheryButte 0x100B +660 1193 25 +663 1193 25 + +# spinning wheel +SpinningWheelEastAddon 0x1019 +742 1205 25 +749 1203 25 + +# upright loom +LoomEastAddon 0x1060 +742 1208 25 +742 1219 25 +750 1208 25 + +# upright loom +LoomSouthAddon 0x1061 +746 1218 25 +746 1213 25 + +# training dummy +TrainingDummy 0x1074 +662 1206 25 +662 1212 25 + +# Valor -> Shrine of Isamu +LocalizedStatic 0x14B7 (LabelNumber=1070790) +1050 517 15 + +# Valor -> Shrine of Isamu +LocalizedStatic 0x14B8 (LabelNumber=1070790) +1050 518 15 + +# Valor -> Shrine of Isamu +LocalizedStatic 0x14B9 (LabelNumber=1070790) +1051 518 15 + +# Valor -> Shrine of Isamu +LocalizedStatic 0x14BA (LabelNumber=1070790) +1051 517 15 + +# bellows +Static 0x197A +767 1257 25 +767 1262 25 + +# bellows +Static 0x197D +767 1257 25 + +# forge +Static 0x197E (Light=Circle300) +768 1257 25 +768 1262 25 + +# forge +Static 0x1982 (Light=Circle300) +769 1257 25 +769 1262 25 + +# bellows +Static 0x1986 +638 1204 52 +638 1208 32 + +# forge +Static 0x198A (Light=Circle300) +638 1205 52 +638 1209 32 + +# forge +Static 0x198E (Light=Circle300) +764 1258 25 + +# forge +Static 0x1991 (Light=Circle300) +764 1258 25 + +# bellows +Static 0x1992 +638 1207 52 +638 1211 32 + +# forge +Static 0x1996 (Light=Circle300) +638 1206 52 +638 1210 32 + +# forge +Static 0x199D (Light=Circle300) +764 1257 25 + +# tower sculpture +# May the town of Zento prosper. Memorial tree planted by Dept and maha. +LocalizedStatic 0x241A (LabelNumber=1063344) +748 1231 25 \ No newline at end of file diff --git a/Data/Decoration/Tokuno/treasures of tokuno.cfg b/Data/Decoration/Tokuno/treasures of tokuno.cfg new file mode 100644 index 0000000..3d01174 --- /dev/null +++ b/Data/Decoration/Tokuno/treasures of tokuno.cfg @@ -0,0 +1,14 @@ +# Ihara Soko +Spawner 0x1F13 (Spawn=IharaSoko; Count=1; HomeRange=0) +678 1277 47 + +#blockers around him +Blocker 0x21A4 +677 1277 47 +679 1277 47 +678 1276 47 +678 1278 47 +677 1276 47 +677 1278 47 +679 1276 47 +679 1278 47 \ No newline at end of file diff --git a/Data/Decoration/Trammel/NERUN-HavenIsland.cfg b/Data/Decoration/Trammel/NERUN-HavenIsland.cfg new file mode 100644 index 0000000..9120ab5 --- /dev/null +++ b/Data/Decoration/Trammel/NERUN-HavenIsland.cfg @@ -0,0 +1,16 @@ +# Saved By Static Exporter +# StaticExport by Nerun +# Version 2.0 + +PublicMoongate 3948 +3450 2677 25 + +Forge 0x0FB1 +3505 2750 0 + +Static 0x100B +3746 2576 40 +3743 2576 40 + +AnvilSouthAddon 0x0000 +3506 2751 0 \ No newline at end of file diff --git a/Data/Decoration/Trammel/NERUN-NewHaven.cfg b/Data/Decoration/Trammel/NERUN-NewHaven.cfg new file mode 100644 index 0000000..a30e59a --- /dev/null +++ b/Data/Decoration/Trammel/NERUN-NewHaven.cfg @@ -0,0 +1,254 @@ +#################### +# New Haven Door's # +#################### + +# Metal + +MetalDoor 0x0677 (Facing=EastCCW) +#3526 1131 20 +3486 2503 51 +3485 2496 71 + +MetalDoor 0x0675 (Facing=WestCW) +#3525 1131 20 +3481 2579 20 +3481 2568 20 +3485 2503 51 +3484 2496 71 +3555 2466 15 + +MetalDoor 0x067F (Facing=NorthCCW) +3491 2571 21 + +MetalDoor 0x067D (Facing=SouthCW) +3491 2573 21 +3472 2489 91 +3550 2453 15 +3550 2458 15 +3550 2462 15 + +MetalDoor 0x0683 (Facing=NorthCW) +3559 2452 15 +3559 2458 15 +3559 2462 15 + +MetalDoor 0x0681 (Facing=SouthCCW) +3482 2489 91 + +# Wood + +DarkWoodDoor 0x06A7 (Facing=EastCCW) +3470 2522 68 +3500 2518 47 +3495 2518 47 + +DarkWoodDoor 0x06AB (Facing=EastCW) +3495 2516 47 +3500 2516 47 + +DarkWoodDoor 0x06A5 (Facing=WestCW) +3469 2522 68 +3442 2570 35 +3458 2526 53 +3458 2531 53 +3506 2526 27 +3508 2549 20 +3497 2549 20 +3497 2556 20 +3497 2554 40 +3508 2556 20 +3503 2549 40 + +DarkWoodDoor 0x06A9 (Facing=WestCCW) +3459 2596 15 +3508 2545 17 + +DarkWoodDoor 0x06AF (Facing=NorthCCW) +3461 2524 73 +3497 2534 27 + +DarkWoodDoor 0x06B3 (Facing=NorthCW) +3457 2599 18 +3496 2589 35 +3501 2547 20 +3491 2547 17 +3495 2547 40 +3501 2547 40 +3504 2547 40 +3496 2517 27 +3509 2513 47 +3509 2518 27 + +# +DarkWoodDoor 0x06AD (Facing=SouthCW) +3473 2530 68 +3477 2527 48 +3483 2533 38 +3474 2519 48 + +DarkWoodDoor 0x06B1 (Facing=SouthCCW) +3504 2527 47 +3504 2522 47 +3496 2518 27 + +# +LightWoodDoor 0x06DD (Facing=SouthCW) +3456 2567 32 +3465 2567 35 +3462 2551 35 +3468 2559 35 +3459 2558 32 +3447 2589 35 +3446 2579 35 +3446 2582 35 +3448 2552 35 +3449 2606 30 + +LightWoodDoor 0x06DF (Facing=NorthCCW) +3448 2551 35 + +LightWoodDoor 0x06D5 (Facing=WestCW) +3435 2572 53 +3443 2563 55 +3457 2555 35 +3462 2562 35 +3446 2603 30 + +LightWoodDoor 0x06D7 (Facing=EastCCW) +3436 2572 53 +3445 2563 35 + +LightWoodDoor 0x06DB (Facing=EastCW) +3436 2563 48 + +LightWoodDoor 0x06D9 (Facing=WestCCW) +3435 2563 49 + +# Gate's + +LightWoodGate 0x0845 (Facing=SouthCCW) +3522 2577 7 + +LightWoodGate 0x0847 (Facing=NorthCW) +3522 2576 7 + +# large forge +Forge 0x197A (Light=Circle300) +3474 2538 31 + +Static 0x197E (Light=Circle300) +3475 2538 31 + +Forge 0x19A2 (Light=Circle300) +3476 2538 31 + +Forge 0x199E (Light=Circle300) +3477 2538 31 + +# forge +Forge 0xFB1 (Light=Circle300) +3467 2539 36 +3467 2541 36 + +# anvil +AnvilSouthAddon 0xFB0 +3470 2535 41 + +AnvilSouthAddon 0xFB0 +3468 2535 41 + +# loom +Static 0x1062 +3499 2546 20 + +Static 0x1061 +3498 2546 20 + +# gem's +Static 0xF21 +3505 2552 23 + +Static 0xF13 +3505 2551 23 + +# regs +Static 0x F7B +3468 2519 51 + +Static 0xF8D +3468 2520 51 + +Static 0xF88 +3468 2518 51 + +########## +# Sign's # +########## + +Static 0xB9E +3473 2543 36 +3498 2557 24 +3459 2532 55 +3434 2573 55 +3510 2557 22 + +Static 0xBC8 +3473 2543 36 + +Static 0xBAE +3495 2536 28 + +Static 0xBC5 +3475 2520 52 + +Static 0xBB3 +3510 2525 27 + +Static 0xBA6 +3498 2557 24 + +Static 0xC0B +3494 2569 23 + +Static 0xBB5 +3497 2594 37 + +Static 0xBA3 +3469 2574 37 + +Static 0xBAB +3469 2558 37 + +Static 0xBC5 +3471 2566 20 + +Static 0xC02 +3459 2532 55 + +Static 0xBC3 +3451 2547 50 + +Static 0xBC4 +3434 2573 55 + +Static 0xBB7 +3522 2574 1 + +Static 0xBC2 +3510 2557 22 + +Static 0xB95 +3478 2528 50 + +Static 0xBA1 +3450 2607 27 +3478 2528 50 +3522 2574 1 +3451 2547 50 +3471 2566 20 +3469 2558 37 +3469 2574 37 +3497 2594 37 +3494 2569 23 +3475 2520 52 +3510 2525 27 \ No newline at end of file diff --git a/Data/Decoration/Trammel/NERUN-OldHaven.cfg b/Data/Decoration/Trammel/NERUN-OldHaven.cfg new file mode 100644 index 0000000..cf617cd --- /dev/null +++ b/Data/Decoration/Trammel/NERUN-OldHaven.cfg @@ -0,0 +1,83 @@ +# doors + +DarkWoodDoor 0x6A5 (Facing=WestCW) +3739 2567 40 +3739 2695 40 +3731 2639 40 + +DarkWoodDoor 0x6AD (Facing=SouthCW) +3719 2651 20 +3743 2683 40 +3710 2651 20 + +# butcher shop sign +Static 0xBA9 +3720 2650 20 + +Static 0xA55 +3689 2511 0 + +Static 0xA56 +3700 2505 0 +3696 2505 0 + +Static 0xA1A (Light=Circle300) +3694 2504 0 + +Static 0xB56 +3690 2506 0 + +Static 0xB57 +3691 2505 0 +3745 2680 40 + +Static 0xB58 +3692 2506 0 +3737 2565 40 +3737 2563 40 + +Static 0xB34 +3691 2506 0 +3728 2637 40 + +Static 0x1E21 +3691 2506 3 + +Static 0x1041 +3736 2563 44 + +Static 0x9B7 +3736 2564 44 + +Static 0xA4F +3729 2632 40 + +Static 0xA44 +3744 2681 40 + +Static 0xA51 +3744 2685 40 + +Static 0xB9E +3740 2696 44 + +Static 0xBCC +3740 2696 44 + +Static 0x24DB +3736 2686 40 + +Static 0xE7F +3736 2685 40 + +Static 0xE3D +3738 2680 40 + +Static 0x9A9 +3739 2680 40 + +Static 0xE77 +3741 2680 40 +3740 2680 40 +3734 2574 40 +3732 2640 40 \ No newline at end of file diff --git a/Data/Decoration/Trammel/_haven additions.cfg b/Data/Decoration/Trammel/_haven additions.cfg new file mode 100644 index 0000000..bf63699 --- /dev/null +++ b/Data/Decoration/Trammel/_haven additions.cfg @@ -0,0 +1 @@ +# Edited by Nerun's Distro \ No newline at end of file diff --git a/Data/Decoration/Trammel/_minoc camp.cfg b/Data/Decoration/Trammel/_minoc camp.cfg new file mode 100644 index 0000000..2953076 --- /dev/null +++ b/Data/Decoration/Trammel/_minoc camp.cfg @@ -0,0 +1,77 @@ +# gruesome standard +Static 0x041F +2635 701 0 + +# garbage +Static 0x10EE +2629 701 0 +2622 703 0 +2626 700 0 +2625 706 0 +2625 708 0 +2629 703 0 + +# tent wall +Static 0x02EB (Hue=0x33) +2620 702 0 +2622 707 0 +2627 698 0 +2627 708 0 +2620 702 1 + +# tent wall +Static 0x02EC (Hue=0x33) +2621 701 0 +2623 706 0 +2628 697 0 +2628 707 0 +2621 701 1 + +# skinned goat +Static 0x1E88 +2624 705 0 + +# fire pit +Static 0x0FAC +2625 703 0 + +# campfire +Static 0x0DE3 +2625 703 0 + +# cauldron +Static 0x0974 +2625 703 0 + +# stump +Static 0x0E59 +2624 709 0 + +# executioner's axe +Static 0x0F46 +2625 708 0 + +# gruesome standard +Static 0x0428 +2626 711 0 + +# gruesome standard +Static 0x0420 +2627 694 0 + +# skinned goat +Static 0x1E89 +2631 696 0 + +# skinned deer +Static 0x1E90 +2627 701 0 +2627 701 1 + +# stump +Static 0x0E58 +2627 703 0 + +# skinned deer +Static 0x1E91 +2627 705 0 diff --git a/Data/Decoration/Trammel/ambitious solen queen quest.cfg b/Data/Decoration/Trammel/ambitious solen queen quest.cfg new file mode 100644 index 0000000..57618ba --- /dev/null +++ b/Data/Decoration/Trammel/ambitious solen queen quest.cfg @@ -0,0 +1,3 @@ +# Red Ambitious Solen Queen +Spawner 0x1F13 (Spawn=RedAmbitiousSolenQueen; Count=1; HomeRange=14) +5790 1983 2 \ No newline at end of file diff --git a/Data/Decoration/Trammel/collector quest.cfg b/Data/Decoration/Trammel/collector quest.cfg new file mode 100644 index 0000000..c3a1109 --- /dev/null +++ b/Data/Decoration/Trammel/collector quest.cfg @@ -0,0 +1,23 @@ +# Elwood McCarrin +Spawner 0x1F13 (Spawn=ElwoodMcCarrin; Count=1; HomeRange=0) +3502 2563 20 + +# Alberta Giacco +Spawner 0x1F13 (Spawn=AlbertaGiacco; Count=1; HomeRange=0) +2899 709 0 + +# Gabriel Piete +Spawner 0x1F13 (Spawn=GabrielPiete; Count=1; HomeRange=0) +1443 1557 51 + +# Impresario +Spawner 0x1F13 (Spawn=Impresario; Count=1; HomeRange=0) +1454 1593 20 +3738 1230 0 +3736 1220 2 +1429 4011 0 +1424 4008 0 + +# Tomas O'Neerlan +Spawner 0x1F13 (Spawn=TomasONeerlan; Count=1; HomeRange=0) +1839 2674 0 \ No newline at end of file diff --git a/Data/Decoration/Trammel/haven.cfg b/Data/Decoration/Trammel/haven.cfg new file mode 100644 index 0000000..bf63699 --- /dev/null +++ b/Data/Decoration/Trammel/haven.cfg @@ -0,0 +1 @@ +# Edited by Nerun's Distro \ No newline at end of file diff --git a/Data/Decoration/Trammel/solen matriarch quest.cfg b/Data/Decoration/Trammel/solen matriarch quest.cfg new file mode 100644 index 0000000..bc611a5 --- /dev/null +++ b/Data/Decoration/Trammel/solen matriarch quest.cfg @@ -0,0 +1,3 @@ +# Red Solen Matriarch +Spawner 0x1F13 (Spawn=RedSolenMatriarch; Count=1; HomeRange=14) +5776 1898 22 \ No newline at end of file diff --git a/Data/Decoration/Trammel/uzeraan turmoil quest.cfg b/Data/Decoration/Trammel/uzeraan turmoil quest.cfg new file mode 100644 index 0000000..bf63699 --- /dev/null +++ b/Data/Decoration/Trammel/uzeraan turmoil quest.cfg @@ -0,0 +1 @@ +# Edited by Nerun's Distro \ No newline at end of file diff --git a/Data/Decoration/Trammel/yew.cfg b/Data/Decoration/Trammel/yew.cfg new file mode 100644 index 0000000..1aeb57d --- /dev/null +++ b/Data/Decoration/Trammel/yew.cfg @@ -0,0 +1,2247 @@ +######### +# Doors # +######### + +# metal door +MetalDoor 0x0675 (Facing=WestCW) +319 791 20 +299 764 20 +312 783 20 +313 791 20 +356 839 20 +369 903 0 +369 867 0 + +# metal door +MetalDoor 0x0677 (Facing=EastCCW) +313 783 20 +357 839 20 +370 903 0 +370 867 0 + +# metal door +MetalDoor 0x067D (Facing=SouthCW) +289 771 20 +367 878 0 +367 878 20 +289 771 0 +327 793 20 +343 884 20 +343 885 0 +351 835 20 +371 871 0 +367 873 20 +367 873 0 +343 873 20 +343 873 0 + +# metal door +MetalDoor 0x067F (Facing=NorthCCW) +327 792 20 +351 834 20 + + +# barred metal door +BarredMetalDoor 0x0685 (Facing=WestCW) +262 769 -2 +262 769 20 +268 769 -2 +268 769 20 +274 769 -2 +274 769 20 +280 769 -2 +280 769 20 +286 769 -2 +286 769 20 + +# barred metal door +BarredMetalDoor 0x0689 (Facing=WestCCW) +262 773 -2 +262 773 20 +268 773 -2 +268 773 20 +274 773 -2 +274 773 20 +280 773 -2 +280 773 20 +286 773 -2 +286 773 20 + + +# wooden gate +DarkWoodGate 0x0866 (Facing=WestCW) +355 891 0 +666 951 0 +666 1191 0 +355 890 20 +562 1111 0 + +# wooden gate +DarkWoodGate 0x0868 (Facing=EastCCW) +356 891 0 +667 951 0 +667 1191 0 +356 890 20 +563 1111 0 + + +# stone wall +SecretStoneDoor1 0x00E8 (Facing=WestCW) +308 791 0 + +# stone wall +SecretStoneDoor1 0x00EA (Facing=EastCCW) +261 763 0 +262 779 0 +262 779 20 +267 763 0 +268 779 0 +268 779 20 +273 763 0 +274 779 0 +274 779 20 +279 763 0 +280 779 0 +280 779 20 +285 763 0 +286 779 0 +286 779 20 +291 777 20 + +# stone wall +SecretStoneDoor1 0x00EC (Facing=WestCCW) +261 763 20 +267 763 20 +273 763 20 +279 763 20 +285 763 20 + +# stone wall +SecretStoneDoor1 0x00F0 (Facing=SouthCW) +296 761 20 +301 762 0 + +# stone wall +SecretStoneDoor1 0x00F2 (Facing=NorthCCW) +301 761 0 + + +############ +# Standard # +############ + +# stone wall +Static 0x00C8 +309 791 0 + +# stone wall +Static 0x00C9 +564 1307 0 + +# patch +Static 0x02F1 +597 837 0 + +# patch +Static 0x02F2 +597 837 0 + +# cobblestones +Static 0x0515 +383 917 0 + +# cobblestones +Static 0x0516 +309 786 0 +309 787 0 + +# oven +StoneOvenEastAddon 0x092C +552 1217 0 + +# oven +StoneOvenSouthAddon 0x0930 +394 1216 0 +553 984 -2 +665 1000 0 +682 1200 0 + +# slab of bacon +Static 0x0976 +457 1141 6 +603 1187 6 + +# slab of bacon +Static 0x0977 +392 1218 6 +602 1184 10 +603 1184 6 + +# wheel of cheese +CheeseWheel 0x097E +452 1110 6 + +# basket +Basket 0x0990 +284 986 4 +416 1035 4 +656 1005 6 + +# tray +Static 0x0991 +392 1218 6 +539 1009 6 +603 1184 6 +642 844 4 +643 834 4 +654 938 6 + +# tray +Static 0x0992 +416 1037 4 +450 1117 6 +459 1141 6 +555 1221 6 +574 1123 6 +679 1202 6 + +# fruit basket +FruitBasket 0x0993 +421 1035 6 +642 833 4 +656 1004 6 + +# ceramic mug +CeramicMug 0x0995 +642 834 4 +642 837 4 +642 838 4 +642 840 4 +642 842 4 + +# ceramic mug +CeramicMug 0x0997 +400 1219 6 +452 1112 6 +555 1210 6 +599 1187 6 +624 1149 6 +643 836 4 +643 838 4 +643 840 4 +643 842 4 +643 844 4 +648 938 6 +648 1084 6 +677 1202 6 + +# bottle of liquor +BeverageBottle 0x099B (Content=Liquor) +261 774 0 +261 774 20 +262 766 0 +262 766 20 +267 774 0 +267 774 20 +268 766 0 +268 766 20 +273 774 0 +274 766 0 +274 766 20 +274 774 20 +279 774 0 +279 774 20 +280 766 0 +280 766 20 +285 774 0 +285 774 20 +286 766 0 +286 766 20 +324 1240 6 +398 1220 6 +400 1219 6 +420 1034 6 +450 963 6 +451 1112 6 +452 1112 6 +458 1135 6 +459 1133 6 +554 1212 6 +555 1210 6 +597 1188 6 +599 1187 6 +624 1147 6 +634 1040 6 +646 939 6 +648 938 6 +648 1084 6 +660 1003 6 +662 1002 6 +677 1202 6 +677 1203 6 +734 883 6 +736 882 6 + +# bottles of liquor +Static 0x099E +608 873 5 +608 876 0 +609 872 10 +611 872 0 +611 875 0 +613 875 5 +613 877 0 +615 872 0 +615 873 5 +615 875 0 +617 873 0 +617 874 0 +617 877 0 +619 876 0 +620 874 10 +621 874 0 + +# fork +Fork 0x09A3 +451 1111 6 +458 1134 6 +554 1211 6 +642 835 4 +642 837 4 +642 839 4 +642 841 4 +642 843 4 + +# fork +Fork 0x09A4 +399 1219 6 +598 1187 6 +647 938 6 +678 1202 6 + +# knife +Knife 0x09A5 +451 1111 6 +458 1134 6 +554 1211 6 +642 835 4 +642 837 4 +642 839 4 +642 841 4 +642 843 4 + +# knife +Knife 0x09A6 +399 1219 6 +535 1011 6 +598 1187 6 +647 938 6 +678 1202 6 + +# metal box +FillableMetalBox 0x09A8 +555 988 6 +562 1008 6 +565 960 6 + +# wooden box +WoodenBox 0x09AA +731 880 0 +739 880 0 + +# metal chest +FillableMetalChest 0x09AB (ContentType=Inn) +603 808 0 +603 816 0 +604 826 0 +607 826 0 +617 824 0 +619 808 0 +649 808 0 +653 824 0 +668 808 0 +668 816 0 + +# bushel +Basket 0x09AC +656 1006 6 + +# cooked bird +CookedBird 0x09B7 +642 844 4 +643 834 4 + +# cooked bird +CookedBird 0x09B8 +459 1141 6 +555 1221 6 +679 1202 6 + +# roast pig +RoastPig 0x09BB +281 984 4 + +# roast pig +RoastPig 0x09BC +392 1220 9 + +# silverware +Static 0x09BD +283 986 4 + +# silverware +Static 0x09BE +421 1034 6 +481 850 4 +483 850 4 +661 1002 6 +735 882 6 + +# sausage +Sausage 0x09C0 +603 1188 6 + +# sausage +Sausage 0x09C1 +392 1221 6 + +# ham +Ham 0x09C9 +604 1184 11 + +# ceramic mug +CeramicMug 0x09CA +324 1240 6 +398 1220 6 +451 1112 6 +554 1212 6 +597 1188 6 +634 1040 6 +646 939 6 +677 1203 6 + +# grape bunch +Grapes 0x09D1 +594 846 0 +594 858 0 +597 853 0 +600 841 0 +600 846 0 +600 857 0 +603 848 0 +603 860 0 +606 845 0 +606 858 0 +609 854 0 +610 883 6 +610 884 6 +610 885 6 +610 886 6 +610 887 6 +610 892 6 +611 892 6 +612 846 0 +612 856 0 +612 892 6 +613 892 6 +614 883 6 +614 884 6 +614 885 6 +614 886 6 +614 887 6 +615 842 0 +615 850 0 +615 858 0 +615 892 6 +616 892 6 +617 892 6 +618 883 6 +618 884 6 +618 885 6 +618 886 6 +618 887 6 +618 892 6 + +# ham +Ham 0x09D3 +603 1189 6 + +# silverware +Static 0x09D4 +284 987 4 +286 987 4 +420 1035 6 +451 963 6 +480 851 4 +482 851 4 +661 1003 6 +735 883 6 + +# silverware +Static 0x09D5 +287 986 4 +328 1061 4 + +# pitcher +Static 0x09D6 +480 851 4 +481 850 4 +482 851 4 +483 850 4 + +# plate +Plate 0x09D7 +283 986 4 +284 987 4 +286 987 4 +287 986 4 +323 1240 6 +328 1061 4 +399 1219 6 +399 1220 6 +420 1035 6 +421 1034 6 +451 963 6 +451 1111 6 +452 1111 6 +458 1134 6 +459 1134 6 +480 851 4 +481 850 4 +482 851 4 +483 850 4 +554 1211 6 +555 1211 6 +598 1187 6 +598 1188 6 +624 1148 6 +633 1040 6 +642 835 4 +642 837 4 +642 839 4 +642 841 4 +642 843 4 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +647 938 6 +647 939 6 +648 1085 6 +661 1002 6 +661 1003 6 +678 1202 6 +678 1203 6 +735 882 6 +735 883 6 + +# cake +Cake 0x09E9 +451 1117 6 +555 1212 6 + +# kettle +Static 0x09ED +397 1216 0 +449 1117 6 +458 1141 6 +553 1221 6 +555 986 6 +654 936 6 +685 1201 6 + +# milk +Pitcher 0x09F0 (Content=Milk) +642 836 4 +643 842 4 + +# cut of raw ribs +RawRibs 0x09F1 +460 1141 6 +528 1011 3 + +# fork +Fork 0x09F4 +323 1240 6 +399 1220 6 +573 1123 6 +598 1188 6 +633 1040 6 +647 939 6 +678 1203 6 + +# fork +Fork 0x09F5 +452 1111 6 +459 1134 6 +555 1211 6 +624 1148 6 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +648 1085 6 + +# knife +Knife 0x09F6 +323 1240 6 +399 1220 6 +598 1188 6 +633 1040 6 +647 939 6 +678 1203 6 + +# knife +Knife 0x09F7 +452 1111 6 +459 1134 6 +555 1211 6 +603 1188 6 +624 1148 6 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +648 1085 6 + +# spoon +Spoon 0x09F8 +323 1240 6 +399 1220 6 +598 1188 6 +633 1040 6 +647 939 6 +678 1203 6 + +# spoon +Spoon 0x09F9 +452 1111 6 +459 1134 6 +555 1211 6 +624 1148 6 +643 835 4 +643 837 4 +643 839 4 +643 841 4 +643 843 4 +648 1085 6 + +# candle +CandleLarge 0x0A26 +419 1034 6 +452 963 6 + +# candelabra +CandelabraStand 0x0A29 +282 989 0 + +# chest of drawers +Drawer 0x0A2C +331 1056 0 +333 1056 0 +392 1224 0 +426 1040 0 +449 1128 0 +457 960 0 +457 1112 0 +486 840 0 +595 1184 0 +625 1144 0 +637 1040 0 +648 944 0 +649 1080 0 +666 1008 0 +682 1208 0 +732 880 0 +738 880 0 + +# chest of drawers +FancyDrawer 0x0A30 +613 824 0 +665 808 0 +665 816 0 +669 824 0 + +# chest of drawers +Drawer 0x0A34 +320 1245 0 + +# chest of drawers +FancyDrawer 0x0A38 +336 883 20 +336 884 0 +480 841 0 +600 812 0 +600 820 0 +600 828 0 +616 811 0 +616 828 0 +648 811 0 +648 826 0 +656 828 0 + +# armoire +FancyArmoire 0x0A4D +609 824 0 +670 824 0 + +# armoire +Armoire 0x0A4F +280 976 0 +285 976 0 +394 1224 0 +453 1128 0 +461 960 0 +597 1184 0 +629 1144 0 +650 944 0 +653 1080 0 +670 1008 0 + +# armoire +FancyArmoire 0x0A51 +336 882 0 +336 882 20 +480 842 0 +600 811 0 +600 819 0 +600 827 0 +616 810 0 +616 829 0 +648 810 0 +648 827 0 +656 829 0 +664 813 0 +664 821 0 + +# armoire +Armoire 0x0A53 +320 1241 0 +328 1057 0 +456 1117 0 +560 1221 0 +632 1045 0 +680 1209 0 + +# folded sheet +Static 0x0A92 +529 960 2 +532 960 2 +535 960 2 +538 960 2 +541 960 2 + +# folded sheet +Static 0x0A93 +424 1043 2 +424 1045 2 + +# bookcase +LibraryBookcase 0x0A97 +291 976 0 +330 1240 0 +339 872 0 +339 872 20 +401 1216 0 +406 1216 0 +450 1104 0 +461 1128 0 +473 840 0 +556 1208 0 +568 960 0 +598 1184 0 +601 1184 0 +626 842 20 +628 1032 0 +630 816 20 +638 816 20 +641 936 0 +642 816 20 +642 1080 0 +644 1080 0 + +# bookcase +LibraryBookcase 0x0A98 +290 976 0 +292 976 0 +329 1240 0 +333 1240 0 +338 872 0 +338 872 20 +340 872 0 +340 872 20 +400 1216 0 +449 1104 0 +457 1128 0 +476 840 0 +477 840 0 +553 1208 0 +557 1208 0 +565 808 0 +569 960 0 +599 1184 0 +625 842 20 +625 1032 0 +631 816 20 +639 816 20 +641 848 0 +641 1080 0 +642 848 0 +642 936 0 +643 848 0 +643 1080 0 +644 848 0 +644 936 0 +645 848 0 + +# bookcase +LibraryBookcase 0x0A99 +320 1061 0 +448 1109 0 +456 1134 0 +528 968 0 +528 973 0 +560 968 0 +616 1146 0 +616 1148 0 +624 825 20 +624 838 0 +624 839 0 +624 840 0 +624 849 0 +624 850 0 +624 851 0 +624 851 20 +624 852 0 +624 852 20 +624 853 0 +624 853 20 +624 1033 0 +640 937 0 +640 941 0 +642 843 20 +642 844 20 +642 845 20 +642 846 20 +672 1201 0 +728 881 0 +728 882 0 +728 884 0 +728 885 0 + +# bookcase +LibraryBookcase 0x0A9A +320 1058 0 +320 1060 0 +336 884 20 +448 1110 0 +456 1129 0 +528 969 0 +528 972 0 +616 1147 0 +624 826 20 +624 843 0 +624 844 0 +624 845 0 +672 1202 0 +672 1204 0 + +# bookcase +LibraryBookcase 0x0A9B +289 976 0 +293 976 0 +332 1240 0 +337 872 0 +337 872 20 +341 872 0 +341 872 20 +405 1216 0 +452 1104 0 +453 1104 0 +474 840 0 +554 1208 0 +561 808 0 +563 808 0 +600 1184 0 +629 1032 0 +632 816 20 +640 816 20 +640 1080 0 +641 816 20 +643 842 20 +644 842 20 +645 842 20 +645 936 0 +645 1080 0 + +# bookcase +LibraryBookcase 0x0A9C +320 1057 0 +336 874 20 +448 1111 0 +456 1133 0 +560 969 0 +568 1121 0 +624 827 20 +624 833 0 +624 834 0 +624 835 0 +672 1205 0 + +# candle +CandleLarge 0x0B1A +280 981 4 +320 787 26 +322 1240 6 +328 1060 4 +328 1247 6 +356 834 26 +398 1219 6 +424 1040 6 +448 1106 6 +448 1128 6 +456 1112 6 +458 1133 6 +474 844 6 +480 840 5 +515 988 6 +539 1008 6 +554 1210 6 +555 984 6 +560 1216 6 +562 1012 6 +565 966 6 +597 1187 6 +606 814 6 +606 816 6 +614 824 6 +616 814 6 +616 824 6 +621 1146 6 +627 845 6 +632 1040 6 +634 1032 6 +640 1087 6 +646 938 6 +648 808 6 +648 824 6 +648 1086 6 +656 824 6 +660 1002 6 +664 808 6 +664 816 6 +664 1008 6 +679 1203 6 +728 880 6 +742 880 6 +460 965 2 +632 816 6 +635 816 26 +638 816 6 + +# candelabra +Candelabra 0x0B1D +292 980 4 + +# candelabra +CandelabraStand 0x0B26 +320 1048 0 +332 816 20 +336 872 0 +336 872 20 +344 816 20 +344 902 0 +344 902 20 +366 902 0 +366 902 20 +486 848 0 +542 960 0 +542 974 0 +624 842 20 +624 1032 0 +640 846 0 +642 842 20 +528 960 0 +528 967 0 +344 876 0 +344 876 20 +365 876 0 +365 876 20 + +# wooden bench +WoodenBench 0x0B2C +312 794 20 +312 795 20 +312 796 20 +312 797 20 + +# wooden bench +WoodenBench 0x0B2D +315 792 20 +316 792 20 +317 792 20 +348 880 0 +348 881 20 +348 882 0 +348 883 20 +348 884 0 +348 885 20 +348 886 0 +348 887 20 +348 888 0 +348 889 20 +348 890 0 +349 880 0 +349 881 20 +349 882 0 +349 883 20 +349 884 0 +349 885 20 +349 886 0 +349 887 20 +349 888 0 +349 889 20 +349 890 0 +350 880 0 +350 881 20 +350 882 0 +350 883 20 +350 884 0 +350 885 20 +350 886 0 +350 887 20 +350 888 0 +350 889 20 +350 890 0 +351 880 0 +351 881 20 +351 882 0 +351 883 20 +351 884 0 +351 885 20 +351 886 0 +351 887 20 +351 888 0 +351 889 20 +351 890 0 +352 880 0 +352 881 20 +352 882 0 +352 883 20 +352 884 0 +352 885 20 +352 886 0 +352 887 20 +352 888 0 +352 889 20 +352 890 0 +353 880 0 +353 881 20 +353 882 0 +353 883 20 +353 884 0 +353 885 20 +353 887 20 +353 888 0 +353 889 20 +353 890 0 +358 880 0 +358 881 20 +358 882 0 +358 883 20 +358 884 0 +358 885 20 +358 886 0 +358 887 20 +358 888 0 +358 889 20 +358 890 0 +359 880 0 +359 881 20 +359 882 0 +359 883 20 +359 884 0 +359 885 20 +359 886 0 +359 887 20 +359 888 0 +359 889 20 +359 890 0 +360 880 0 +360 881 20 +360 882 0 +360 883 20 +360 884 0 +360 885 20 +360 886 0 +360 887 20 +360 888 0 +360 889 20 +360 890 0 +361 880 0 +361 881 20 +361 882 0 +361 883 20 +361 884 0 +361 885 20 +361 886 0 +361 887 20 +361 888 0 +361 889 20 +361 890 0 +362 880 0 +362 881 20 +362 882 0 +362 883 20 +362 884 0 +362 885 20 +362 886 0 +362 887 20 +362 888 0 +362 889 20 +362 890 0 +363 880 0 +363 881 20 +363 882 0 +363 883 20 +363 884 0 +363 885 20 +363 886 0 +363 887 20 +363 888 0 +363 889 20 +363 890 0 + +# chair +FancyWoodenChairCushion 0x0B4E +282 986 0 + +# chair +FancyWoodenChairCushion 0x0B4F +475 849 0 +481 849 0 +483 849 0 + +# chair +FancyWoodenChairCushion 0x0B50 +284 988 0 +286 988 0 +480 852 0 +482 852 0 + +# chair +FancyWoodenChairCushion 0x0B51 +288 986 0 +644 851 0 + +# chair +WoodenChairCushion 0x0B52 +473 843 0 +529 970 0 +625 831 20 +625 836 20 +626 834 0 +626 839 0 +626 844 0 +626 851 0 +641 835 0 +641 837 0 +641 839 0 +641 841 0 +641 843 0 + +# chair +WoodenChairCushion 0x0B53 +291 978 0 +319 786 20 +355 833 20 +631 818 20 +640 818 20 + +# chair +WoodenChairCushion 0x0B54 +355 900 20 +355 901 0 +475 853 0 +636 817 20 + +# chair +WoodenChairCushion 0x0B55 +337 879 0 +337 879 20 +635 1034 0 +645 831 20 +645 835 0 +645 836 20 +645 837 0 +645 839 0 +645 841 0 +645 843 0 + +# chair +WoodenChair 0x0B56 +450 1111 0 +457 1134 0 +514 990 0 +553 1211 0 +561 1010 0 +563 963 0 + +# chair +WoodenChair 0x0B57 +329 1246 0 +350 892 20 +350 893 0 +352 892 20 +352 893 0 +359 892 20 +359 893 0 +361 892 20 +361 893 0 +399 1218 0 +421 1033 0 +534 972 0 +536 972 0 +537 1010 0 +563 810 0 +568 1011 6 +598 1186 0 +620 1145 0 +641 1086 0 +647 937 0 +661 1001 0 +678 1201 0 +735 881 0 + +# chair +WoodenChair 0x0B58 +449 1107 0 +453 1111 0 +460 1134 0 +556 1211 0 +571 964 0 +625 1148 0 +641 939 0 +641 1083 0 +649 1085 0 + +# chair +WoodenChair 0x0B59 +321 1056 0 +323 1241 0 +350 900 0 +350 900 20 +399 1221 0 +403 1217 0 +420 1036 0 +459 1129 0 +562 812 0 +564 812 0 +598 1189 0 +633 1041 0 +647 940 0 +661 1004 0 +678 1204 0 +735 884 0 + +# chair +BambooChair 0x0B5A +571 1011 6 +664 1003 0 + +# chair +BambooChair 0x0B5B +459 964 0 +567 1008 6 + +# chair +BambooChair 0x0B5C +451 964 0 +534 968 0 +536 968 0 + +# chair +BambooChair 0x0B5D +281 980 0 +329 1061 0 +541 962 0 +541 963 0 +669 1003 0 + +# foot stool +FootStool 0x0B5E +458 960 0 +531 960 0 +534 960 0 +537 960 0 +540 960 0 + +# bench +Static 0x0B5F +425 1035 0 +428 1035 0 + +# bench +Static 0x0B60 +425 1034 0 +428 1034 0 + +# bench +Static 0x0B65 +427 1036 0 +667 1004 0 + +# bench +Static 0x0B66 +426 1036 0 +666 1004 0 + +# wooden signpost +Static 0x0B98 +618 1152 0 +626 1040 0 + +# broken chair +Static 0x0C10 +562 1010 6 + +# barber scissors +Static 0x0DFC +322 1048 6 + +# bloody bandage +Static 0x0E20 +539 960 0 + +# clean bandage +Static 0x0E21 +330 1247 6 + +# bloody bandage +Static 0x0E22 +329 1251 0 +531 960 0 +641 1089 0 + +# bloody water +Static 0x0E23 +320 1051 0 +330 1250 0 +533 960 0 +539 961 0 + +# crystal ball +Static 0x0E2E (Light=Circle150) +627 834 6 + +# crate +LargeCrate 0x0E3C +308 784 0 +308 784 3 +308 785 0 +308 786 0 +309 784 0 +309 784 3 +309 788 1 +309 788 4 +310 784 0 +310 787 0 +310 787 3 +310 787 6 +310 788 0 +310 788 3 +310 789 0 +310 789 3 +310 789 6 +311 789 0 +311 789 3 +317 784 0 +317 784 3 +317 784 6 +317 784 9 +317 785 0 +317 785 3 +317 794 0 +317 794 3 +317 794 6 +317 795 0 +317 795 3 +317 795 6 +318 784 0 +318 784 3 +318 785 0 +318 794 0 +318 794 3 +318 794 6 +318 795 0 +318 795 3 +318 795 6 +656 1002 0 +656 1003 0 + +# crate +LargeCrate 0x0E3D +311 788 -23 +312 790 -23 + +# mill crate +FillableLargeCrate 0x0E3D (ContentType=Mill) +546 810 0 +546 810 3 +546 811 0 +547 810 0 +547 810 3 +547 811 0 +547 811 3 + +# crate +MediumCrate 0x0E3E +323 795 0 +323 795 3 +323 796 0 +324 795 0 +324 796 0 +324 796 3 +416 1033 0 +416 1033 3 +416 1034 0 +448 961 0 +448 961 3 +448 962 0 +544 812 0 +544 812 3 +544 813 0 +544 813 3 +544 813 6 + +# crate +MediumCrate 0x0E3F +417 1032 0 +417 1032 3 +449 960 0 +449 960 3 + +# wooden chest +WoodenChest 0x0E42 +424 1042 0 +461 966 0 +664 1014 0 + +# wooden chest +WoodenChest 0x0E43 +311 784 0 +324 1061 0 +482 840 0 + +# empty jars +Static 0x0E46 +324 1048 6 + +# full jars +Static 0x0E4B +536 973 6 + +# stump +Static 0x0E59 +637 1155 0 + +# barrel +Barrel 0x0E77 +312 792 0 +312 792 5 +312 792 10 +312 793 0 +312 793 5 +312 794 0 +313 792 0 +313 792 5 +313 793 0 +314 785 6 +314 792 0 +323 790 0 +323 790 5 +323 790 10 +323 791 0 +324 790 0 +324 790 5 +324 790 10 +324 791 0 +325 790 0 +325 790 5 +325 790 10 +325 791 0 +416 1032 0 +448 960 0 +448 960 5 +544 808 0 +544 808 5 +544 808 10 +544 809 0 +544 809 5 +545 808 0 +545 808 5 +549 808 0 +549 809 0 +549 812 0 +549 812 5 +549 813 0 +549 813 5 +550 808 0 +550 808 5 +550 809 0 +550 809 5 +550 812 0 +550 812 5 +550 813 0 +550 813 5 +608 872 0 +608 872 5 +608 872 10 +608 873 0 +609 872 0 +609 872 5 +609 873 0 +609 873 5 +609 892 0 +610 882 0 +610 888 0 +612 874 0 +612 874 5 +612 874 10 +613 873 0 +613 873 5 +613 873 10 +613 874 0 +613 874 5 +613 875 0 +614 873 0 +614 873 5 +614 874 0 +614 874 5 +614 882 0 +614 888 0 +614 892 0 +615 873 0 +618 888 0 +619 873 0 +619 892 0 +620 873 0 +620 873 5 +620 873 10 +620 874 0 +620 874 5 +621 873 0 +661 1008 0 +730 888 0 + +# metal chest +MetalChest 0x0E7C +260 766 0 +260 766 20 +260 774 20 +260 775 0 +266 766 0 +266 766 20 +266 774 20 +266 775 0 +272 766 0 +272 766 20 +272 774 20 +272 775 0 +278 766 0 +278 766 20 +278 774 20 +278 775 0 +283 774 40 +284 766 0 +284 766 20 +284 774 20 +284 775 0 + +# inn metal chest +FillableMetalChest 0x0E7C (ContentType=Inn) +656 826 0 +656 827 0 + +# crate +SmallCrate 0x0E7E +448 962 3 + +# strong box +FillableMetalBox 0x0E80 +512 988 6 + +# drum +Static 0x0E9C +627 821 20 + +# tambourine +Static 0x0E9D +627 823 20 + +# standing harp +Static 0x0EB1 +625 818 20 + +# lap harp +Static 0x0EB2 +627 818 20 + +# lute +Static 0x0EB4 +625 821 20 +625 823 20 + +# music stand +Static 0x0EB9 +625 819 20 +627 819 20 + +# music stand +Static 0x0EBC +624 821 20 +624 823 20 + +# sheet music +Static 0x0EC0 +624 821 20 +624 823 20 + +# cleaver +Static 0x0EC3 +281 984 4 +604 1184 11 + +# skinning knife +Static 0x0EC4 +602 1184 10 + +# clean bandage +Static 0x0EE9 +322 1048 6 +323 1048 6 +533 967 6 +535 967 6 +535 973 6 +536 967 6 +640 1084 6 +642 1087 6 +642 1092 0 + +# bottle +Static 0x0EFE +642 851 26 + +# bottle +Static 0x0EFF +642 852 26 + +# bottle +Static 0x0F00 +644 830 26 + +# bottle +Static 0x0F01 +642 850 26 + +# bottle +Static 0x0F03 +644 830 26 + +# Black Potion +Static 0x0F06 +644 835 26 +645 850 26 + +# Blue Potion +Static 0x0F08 +644 844 26 + +# Green Potion +Static 0x0F0A +642 853 26 + +# Red Potion +Static 0x0F0B +329 1254 6 +332 1254 6 +533 973 10 +534 973 9 +537 973 10 +640 1083 6 +640 1094 6 +644 846 26 + +# Yellow Potion +Static 0x0F0C +330 1254 6 +331 1254 6 +640 1082 6 +641 1094 6 +644 845 26 + +# Purple Potion +Static 0x0F0D +645 851 26 + +# empty bottle +Static 0x0F0E +644 837 26 +645 852 26 + +# arrows +Static 0x0F41 +616 1145 6 + +# crossbow +Static 0x0F4F +620 1146 6 + +# crossbow +Static 0x0F50 +616 1149 6 + +# easel with canvas +Static 0x0F68 +643 822 20 +643 825 20 +643 828 20 + +# Batwing +Static 0x0F78 +626 853 26 + +# Daemon Bone +Static 0x0F80 +624 845 26 + +# Pig Iron +Static 0x0F8A +624 846 26 +626 835 26 + +# Sulfurous Ash +# Nox Crystal +Static 0x0F8E +626 830 26 +626 852 26 + +# scissors +Scissors 0x0F9E +534 967 6 +535 973 6 + +# barrel +Static 0x0FAE +313 784 0 +313 784 7 +313 785 0 +313 785 7 +314 784 0 +314 784 7 +314 785 0 +314 786 0 +314 787 0 + +# book +Static 0x0FBD +280 980 4 +336 879 6 +336 879 26 +448 1107 6 +515 990 6 +530 970 6 +626 831 26 +626 836 26 +627 844 6 +627 851 6 +640 939 6 +643 851 6 +644 831 26 +644 836 26 + +# book +Static 0x0FBE +291 979 4 +319 787 26 +321 1055 6 +329 1247 6 +352 893 24 +352 894 4 +355 834 26 +355 898 26 +355 899 6 +359 893 24 +359 894 4 +403 1216 6 +459 1128 6 +474 842 6 +537 1011 6 +563 811 4 +636 816 26 +641 1087 6 + +# pen and ink +Static 0x0FBF +280 979 4 +290 979 4 +336 879 6 +336 879 26 +351 893 24 +351 894 4 +358 893 24 +358 894 4 +448 1107 6 +474 843 6 +515 990 6 +530 970 6 +536 1011 6 +564 810 4 +565 963 6 +626 831 26 +626 836 26 +627 844 6 +627 851 6 +640 939 6 +643 851 6 +644 831 26 +644 836 26 + +# pen and ink +Static 0x0FC0 +318 787 26 +320 1055 6 +329 1247 6 +354 834 26 +354 898 26 +355 899 6 +403 1216 6 +458 965 2 +459 1128 6 +636 816 26 +641 1087 6 + +# paints and brush +Static 0x0FC1 +643 826 20 +644 822 20 +644 827 20 + +# glass pitcher +Pitcher 0x0FF6 +643 842 4 + +# pewter mug +PewterMug 0x0FFF +419 1035 6 +450 963 6 +458 1135 6 + +# pewter mug +PewterMug 0x1000 +336 878 26 +336 880 6 +420 1034 6 +459 1133 6 +660 1003 6 +662 1002 6 +734 882 6 +736 883 6 + +# wash basin +Static 0x1008 +534 967 6 + +# archery butte +ArcheryButte 0x100A +560 972 0 + +# archery butte +ArcheryButte 0x100B +573 960 0 + +# hammer +Static 0x102A +563 966 6 + +# hammer +Static 0x102B +562 1009 6 +619 1146 6 + +# nails +Static 0x102E +562 1011 6 + +# nails +Static 0x102F +563 966 6 + +# saw +Static 0x1034 +622 1153 0 + +# saw +Static 0x1035 +616 1144 6 + +# sack of flour +Static 0x1039 +556 984 0 +557 984 0 + +# open sack of flour +Static 0x103A +544 810 0 +544 811 0 +544 817 0 +544 818 6 +544 819 6 +544 820 6 +544 823 0 +544 824 0 +544 826 6 +544 827 6 +545 821 0 +545 824 0 +545 828 0 +545 829 0 +546 808 0 +547 808 0 +548 808 0 +549 824 0 +550 816 0 +551 816 0 +552 814 0 +552 815 0 +554 814 6 +554 827 6 +554 828 0 +555 814 6 +555 827 6 +556 824 0 +556 825 0 +557 814 6 +557 815 0 +557 828 0 +558 814 0 +558 815 0 +560 816 0 +560 822 6 +562 821 0 +562 822 6 +563 821 0 +563 822 6 +565 816 0 + +# bread loaf +Static 0x103C +261 766 0 +261 766 20 +262 775 0 +262 775 20 +267 766 0 +267 766 20 +268 774 20 +268 775 0 +273 766 0 +273 766 20 +274 774 0 +274 775 20 +279 766 0 +279 766 20 +280 774 20 +280 775 0 +285 766 0 +285 766 20 +286 774 0 +286 774 20 + +# dough +Static 0x103D +554 988 6 +554 1221 6 +685 1202 6 + +# cookie mix +Static 0x103F +555 987 6 +556 1221 6 +685 1204 6 + +# rolling pin +Static 0x1043 +448 1117 6 +552 1221 6 +553 988 6 +685 1203 6 + +# clock +Clock 0x104C +631 1032 6 +632 1032 6 + +# clock frame +ClockFrame 0x104E +569 1008 6 +636 1032 6 + +# clock parts +ClockParts 0x104F +628 1035 8 + +# axle with gears +AxleGears 0x1051 +627 1035 6 + +# axle with gears +AxleGears 0x1052 +636 1032 8 + +# gears +Gears 0x1053 +626 1035 6 +637 1032 6 + +# sextant +Static 0x1057 +634 1034 7 + +# sextant +Static 0x1058 +629 1035 6 + +# sextant parts +SextantParts 0x1059 +625 1035 7 + +# sextant parts +SextantParts 0x105A +634 1033 6 + +# springs +Springs 0x105D +627 1035 8 +635 1032 8 + +# potted tree +PottedTree 0x11C8 +532 967 0 +532 973 0 + +# flowerpot +PottedPlant 0x11CA +328 1240 0 +448 1104 0 +534 1008 0 +538 967 0 +538 973 0 +552 1208 0 +568 1120 0 +640 936 0 +648 1080 0 +665 1008 0 +672 1200 0 +733 880 0 +737 880 0 + +# flowerpot +PottedPlant1 0x11CB +451 1110 6 +459 1135 9 +514 992 10 +530 972 6 +539 1011 9 +648 939 10 + +# flowerpot +PottedPlant2 0x11CC +562 966 9 +565 965 9 + +# bed +Static 0x11D2 +485 840 0 + +# bed +Static 0x11D3 +485 842 0 + +# bed +Static 0x11D4 +483 842 0 + +# bed +Static 0x11D5 +483 840 0 + +# altar +AbbatoirAddon 0x1216 +311 786 0 + +# teleporter +Teleporter 0x1BC3 (PointDest=(5750, 350, 5)) +311 786 0 + +# water barrel +Static 0x154D +618 882 0 + +#REMOVED WITH ML -> yew changed back to normal +# a glowing pod +#Static 0x1728 (Hue=0x5F; Name=a glowing pod) +#383 1009 28 +#383 1009 41 +#384 1008 32 +#384 1008 47 +#386 1005 28 +#386 1005 43 +#386 1006 28 +#565 969 28 +#565 969 41 +#566 968 32 +#566 968 47 +#568 965 28 +#568 965 43 +#568 966 28 +#648 913 28 +#648 913 41 +#649 912 32 +#649 912 47 +#651 909 28 +#651 909 43 +#651 910 28 + +# water +Static 0x1797 +463 1280 -5 +464 1280 -5 +465 1280 -5 +466 1280 -5 +467 1280 -5 +468 1280 -5 +469 1280 15 + +# water +Static 0x179A +469 1281 -5 +470 1281 -5 + +# alchemical symbol +Static 0x1822 +311 786 -24 + +# teleporter +Teleporter 0x1BC3 (PointDest=(314, 784, 0)) +311 786 -24 + +# flour mill +FlourMillSouthAddon 0x192C +550 820 -2 +552 820 -2 +554 820 -2 + +# shaft +Static 0x1BD4 +564 966 6 + +# boards +Static 0x1BD8 +623 1155 0 + +# logs +Static 0x1BE2 +616 1152 0 +617 1152 0 + +# Quarantine Area: No pets permitted beyond this point! +LocalizedSign 0x1F29 (LabelNumber=1016226) +315 786 -18 + +# Reactive Armor +Static 0x1F2D +624 841 0 +640 848 0 + +# Create Food +Static 0x1F2F +627 839 6 + +# Heal +Static 0x1F31 +624 837 0 +627 843 6 + +# Magic Untrap +Static 0x1F3A +624 832 0 + +# Protection +Static 0x1F3B +645 849 0 + +# Strength +Static 0x1F3C +625 848 0 + +# Arch Cure +Static 0x1F45 +627 852 6 + +# Curse +Static 0x1F47 +624 848 0 +643 853 0 + +# Dispel Field +Static 0x1F4E +627 850 6 + +# Mark +Static 0x1F59 +627 838 6 + +# Mass Dispel +Static 0x1F62 +627 835 6 + +# rock +Static 0x3426 +469 1280 -4 +470 1281 -4 + +# rock +Static 0x3427 +470 1280 -5 + +# rock +Static 0x3429 +469 1281 -4 + +#REMOVED WITH ML -> yew changed back to normal +# a glowing pod +#Static 0x3EE8 (Hue=0x5F; Name=a glowing pod) +#381 1008 57 +#381 1010 47 +#382 1007 65 +#383 1009 59 +#386 1004 39 +#386 1006 76 +#387 1004 53 +#563 968 57 +#563 970 47 +#564 967 65 +#565 969 59 +#568 964 39 +#568 966 76 +#569 964 53 +#646 912 57 +#646 914 47 +#647 911 65 +#648 913 59 +#651 908 39 +#651 910 76 +#652 908 53 \ No newline at end of file diff --git a/Data/Locations/felucca.xml b/Data/Locations/felucca.xml new file mode 100644 index 0000000..e64d371 --- /dev/null +++ b/Data/Locations/felucca.xml @@ -0,0 +1,294 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/felucca.xml.bak b/Data/Locations/felucca.xml.bak new file mode 100644 index 0000000..11a9ef4 --- /dev/null +++ b/Data/Locations/felucca.xml.bak @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/ilshenar.xml b/Data/Locations/ilshenar.xml new file mode 100644 index 0000000..bd1c76b --- /dev/null +++ b/Data/Locations/ilshenar.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/malas.xml b/Data/Locations/malas.xml new file mode 100644 index 0000000..6c12fae --- /dev/null +++ b/Data/Locations/malas.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/termur.xml b/Data/Locations/termur.xml new file mode 100644 index 0000000..c34f0c1 --- /dev/null +++ b/Data/Locations/termur.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/tokuno.xml b/Data/Locations/tokuno.xml new file mode 100644 index 0000000..b143129 --- /dev/null +++ b/Data/Locations/tokuno.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/trammel.xml b/Data/Locations/trammel.xml new file mode 100644 index 0000000..683506e --- /dev/null +++ b/Data/Locations/trammel.xml @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/Locations/trammel.xml.bak b/Data/Locations/trammel.xml.bak new file mode 100644 index 0000000..5727c6b --- /dev/null +++ b/Data/Locations/trammel.xml.bak @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/MLQuests.cfg b/Data/MLQuests.cfg new file mode 100644 index 0000000..ff88183 --- /dev/null +++ b/Data/MLQuests.cfg @@ -0,0 +1,292 @@ +# Escorts +EscortToYew +EscortToVesper +EscortToTrinsic +EscortToSkaraBrae +EscortToSerpentsHold +EscortToNujelm +EscortToMoonglow +EscortToMinoc +EscortToMagincia +EscortToJhelom +EscortToCove +EscortToBritain +EscortToOcllo + +# Britannia +Aemaeth1 Aurelia +Aemaeth2 SkeletonOfSzandor +OddsAndEnds Patricus + +# Honest Beggar +HonestBeggar Evan +ReginasThanks Regina + +# Unfading Memories +# TODO: OneTimeOnly issue +#UnfadingMemoriesPartOne Emilio +#UnfadingMemoriesPartTwo Emilio +#UnfadingMemoriesPartThree Thalia + +# A Ghost Of Covetous +AGhostOfCovetous Ben +SaveHisDad Frederic +AFathersGratitude Leon Andros + +# Heartwood +TheyreBreedingLikeRabbits Saril Tamm Yorus +TheyllEatAnything Saril Tamm Yorus +NoGoodFishStealing Saril Tamm Yorus +AHeroInTheMaking Saril Yorus +BullfightingSortOf Saril Tamm Yorus +AFineFeast Saril Tamm Yorus +ForcedMigration Saril Tamm Yorus +FilthyPests Saril Tamm +DeadManWalking Vilo Saril Tamm Cailla Tiana +KingOfBears Vilo Cailla +Specimens Vilo Clehin Salaenih Cailla Landy +Spirits Cailla +RollTheBones Vilo Cailla +ItsAGhastlyJob Vilo Cailla +Troglodytes Cailla Canir +UnholyKnights Vilo Cailla +AFeatherInYerCap Vilo Cailla +ATaleOfTail Vilo Cailla +ATrogAndHisDog Cailla Canir +Overpopulation Saril Tamm Yorus ElderAcob +WildBoarCull Saril Tamm Yorus ElderAcob +ItsElemental Caelas Alejaha +CircleOfLife Brinnae Aniel Ciala Mielan +DustToDust Aniel Ciala +CreepyCrawlies Clehin Aulan Landy +VoraciousPlants Aulan Salaenih +GibberJabber Aulan +AnimatedMonstrosity Aulan Salaenih +BirdsOfAFeather Aulan +Frightmares Aulan +MoltenReptiles Aulan +BloodyNuisance Aulan +BloodSuckers Aulan +TheAfterlife Brinnae +ForkedTongue Brinnae Saril Tamm Tiana +ImpishDelights Brinnae +ThreeWishes Brinnae +EvilEye Brinnae +GargoylesWrath Brinnae +UndeadMages Brinnae +FriendlyNeighborhoodSpiderkiller Vilo Brinnae Cailla +MongbatMenace Clehin Brinnae Landy +StirringTheNest Brinnae +WarriorCaste Caelas Salaenih +BigWorms Caelas +OrcishElite Caelas +ThinningTheHerd Clehin Saril Tamm Landy Yorus +Squishy Salaenih +OrcSlaying LorekeeperOolua +ABigJob Salaenih +TrollingForTrolls Saril Tamm Tiana +ColdHearted Salaenih +ForkedTongues +ShakingThingsUp Salaenih +Arachnophobia Salaenih +MiniSwampThing Salaenih +ThePerilsOfFarming Vilo Tiana +IndustriousAsAnAntLion Vilo Tiana +UnholyConstruct Vilo Tiana Braen +AChillInTheAir Vilo Tiana +# TODO: Restart delays +#TheKingOfClothing Ahie Thallary +#ThePuffyShirt Ahie Thallary +#FromTheGaultierCollection Waelian Sleen Ahie Thallary +#HauteCouture Ahie Thallary +#TheSongOfTheWind Tholef Tillanil +#BeerGoggles Tholef Tillanil +#MessageInABottleQuest Tholef Tillanil +#NecessitysMother Waelian Sleen +#TickTock Waelian Sleen Danoel +ReptilianDentist Sleen Danoel +#StopHarpingOnMe Waelian Sleen Anolly Cillitha Jusae Unoelil +#TheFarEye Waelian Sleen Anolly Unoelil +#LethalDarts Cillitha Jusae +#ASimpleBow Cillitha Jusae +#IngeniousArcheryPartOne Cillitha Jusae +#IngeniousArcheryPartTwo Cillitha Jusae +#IngeniousArcheryPartThree Cillitha Jusae +ScaleArmor Ahie Thallary Tallinin +#CutsBothWays Lohn Olla +#DragonProtection Lohn Olla +#NothingFancy Anolly Lohn Olla Unoelil Danoel +#TheBulwark Lohn Olla +#ArchSupport Waelian Sleen Ciala Aniel +ParoxysmusSuccubi LorekeeperNillaen LorekeeperOolua +ParoxysmusMoloch LorekeeperNillaen LorekeeperOolua +ParoxysmusDaemons LorekeeperNillaen LorekeeperOolua +ParoxysmusArcaneDaemons LorekeeperNillaen LorekeeperOolua +CausticCombo LorekeeperNillaen LorekeeperOolua +PlagueLord LorekeeperNillaen LorekeeperOolua +GlassyFoe Ciala Aniel LorekeeperRyal LorekeeperRollarn +DaemonicPrism LorekeeperRyal LorekeeperRollarn +Hailstorm LorekeeperRyal LorekeeperRollarn +HowManyHeads LorekeeperRyal LorekeeperRollarn +DreadhornQuest LorekeeperCalendor LorekeeperOolua +NewLeadership ElderAcob +ExAssassins ElderAcob +ExtinguishingTheFlame ElderAcob +CrimeAndPunishment ElderAcob +DeathToTheNinja ElderAcob +AllThatGlittersIsNotGood LorekeeperSiarra ElderBrae + +# The Ancient World +TheAncientWorld LorekeeperBroolol +TheGoldenHorn LorekeeperBroolol +Bullish Braen +LostCivilization Braen + +# Warriors Of The Gemkeeper +WarriorsOfTheGemkeeper LorekeeperRollarn +CloseEnough LorekeeperRollarn +TakingTheBullByTheHorns Canir +EmissaryToTheMinotaur Canir + +# Sanctuary +# TODO: Restart delays +#BrokenShaft Beotham +#BendingTheBow Beotham +#ArmsRace Beotham +#ImprovedCrossbows Beotham +#BuildingTheBetterCrossbow Beotham +#InstrumentOfWar Danoel +#TheShield Danoel +#MusicToMyEars Danoel +#TheGlassEye Danoel +#LazyHumans Danoel +#InventiveTools Danoel +PixieDustToDust LorekeeperOolua +#AnImpressivePlaid Tallinin +#LeatherAndLace Danoel Tallinin +#FeyHeadgear Tallinin +NewCloak Tallinin +ADishBestServedCold Tiana Koole +ArchEnemies Tiana +Vermin Tiana +#ANiceShirt Tallinin +MougGuurMustDie Dallid +LeaderOfThePack Dallid +SayonaraSzavetra Dallid +#TappingTheKeg Dallid +#WaitingToBeFilled Dallid +#BreezesSong Dallid +ProofOfTheDeed ElderOnallan Tiana +Marauders ElderOnallan Tiana Koole +TheBrainsOfTheOperation ElderOnallan Tiana +TheBrawn ElderOnallan Tiana +TheBiggerTheyAre ElderOnallan Tiana +TroubleOnTheWing Koole +BrotherlyLove LorekeeperRollarn + +# Elven heritage +Seasons MaulTheBear +CaretakerOfTheLand Strongroot +WisdomOfTheSphynx Enigma +DefendingTheHerd Bravehorn +TheBalanceOfNature Huntsman +TheJoysOfLife Arielle + +# Human heritage +Ingenuity Sledge +HeaveHo Patricus +HumanInNeed +AllSeasonAdventurer Belulah + +# Ilshenar +Responsibility Lissbet +SomethingToWailAbout Jelrice +Runaways Jelrice +ViciousPredator Jelrice +GuileIrkAndSpite Yorus + +# New Haven +EscortToNHAlchemist +EscortToNHBard +EscortToNHWarrior +EscortToNHTailor +EscortToNHCarpenter +EscortToNHMapmaker +EscortToNHMage +EscortToNHInn +EscortToNHFarm +EscortToNHDocks +EscortToNHBowyer +EscortToNHBank + +# New Haven Training +# TODO: Restart delays +#SplitEnds Andric +IShotAnArrowIntoTheAir Kashiel +#BakersDozen Asandos +#AStitchInTime Clairesse +#BatteredBucklers Gervis +#MoreOrePlease Mugg +#ComfortableSeating Lowel +#ThePenIsMightier Lyle +#AClockworkPuzzle Nibbet +#DeliciousFishes Norton +#FleeAndFatigue Sadrah +#ChopChopOnTheDouble Hargrove + +# New Haven Skill Training +CleansingOldHaven Aelorn +TheRudimentsOfSelfDefense Dimethro +CrushingBonesAndTakingNames Churchill +SwiftAsAnArrow Robyn +EnGuarde Recaro +TheArtOfWar AldenArmstrong +TheWayOfTheBlade Jockles +ThouAndThineShield TylAriadne +DefyingTheArcane Alefian +StoppingTheWorld Gustar +ScribingArcaneKnowledge Jillian +TheMagesApprentice Kaelynna +ScholarlyTask Mithneral +TheRightToolForTheJob AmeliaYoungstone +KnowThineEnemy AndreasVesalius +BruisesBandagesAndBlood Avicenna +TheInnerWarrior SarsmeaSmythe +TheArtOfStealth Ryuichi +BecomingOneWithTheShadows Chiyo +WalkingSilently Jun +EyesOfARanger Walker +TheWayOfTheSamurai Hamato +TheAllureOfDarkMagic Mulcivikh +ChannelingTheSupernatural Morganna +TheDeluciansLostMine JacobWaltz +ItsHammerTime GeorgeHephaestus + +# Spellweaving +Patience Aeluva +NeedsOfTheManyHeartwood1 Aeluva +NeedsOfTheManyHeartwood2 Aeluva +MakingAContributionHeartwood Aeluva +UnnaturalCreations Aeluva + +Discipline Koole +NeedsOfTheManySanctuary Koole +MakingAContributionSanctuary Koole +SuppliesForSanctuary Koole +TheHumanBlight Koole + +FriendOfTheFey Synaeva +TokenOfFriendship Synaeva +Alliance Arielle + +FiendishFriends ElderBrae +CrackingTheWhipI ElderBrae +CrackingTheWhipII ElderBrae + +# ML dungeons +VilePoison Jamal +ARockAndAHardPlace Iosep +SympatheticMagic Iosep +AlreadyDead Iosep +Eureka Iosep +SubContracting Jamal \ No newline at end of file diff --git a/Data/Monsters/Ilshenar-exported.map b/Data/Monsters/Ilshenar-exported.map new file mode 100644 index 0000000..0e50573 --- /dev/null +++ b/Data/Monsters/Ilshenar-exported.map @@ -0,0 +1,105 @@ +####################################### +## Converted By RunUOSpawnerExporter ## +## Developed by Nerun ## +####################################### +*|herbalist||||||1515|539|85|3|1|1|4|4|1|1|0|0|0|0|0 +*|mage||||||1516|541|60|3|1|1|4|4|1|1|0|0|0|0|0 +*|mage||||||1516|540|85|3|1|1|4|4|1|1|0|0|0|0|0 +*|weaponsmith||||||1082|650|-40|3|1|1|4|4|1|1|0|0|0|0|0 +*|BlacksmithGuildmaster||||||792|665|0|3|2|10|5|5|1|1|0|0|0|0|0 +*|Blacksmith||||||792|665|0|3|2|10|5|5|1|2|0|0|0|0|0 +*|Innkeeper||||||1566|1049|-8|3|2|10|5|5|1|2|0|0|0|0|0 +*|TinkerGuildmaster||||||1253|588|-19|3|2|10|5|5|1|1|0|0|0|0|0 +*|Tinker||||||1253|588|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|Innkeeper||||||840|707|0|3|2|10|5|5|1|2|0|0|0|0|0 +*|MageGuildmaster||||||840|571|0|3|2|10|5|5|1|1|0|0|0|0|0 +*|Alchemist||||||840|571|0|3|2|10|5|5|1|2|0|0|0|0|0 +*|Mage||||||840|571|0|3|2|10|5|5|1|2|0|0|0|0|0 +*|TailorGuildmaster||||||1600|552|-16|3|2|10|5|5|1|1|0|0|0|0|0 +*|Weaver||||||1600|552|-16|3|2|10|5|5|1|2|0|0|0|0|0 +*|Tailor||||||1600|552|-16|3|2|10|5|5|1|2|0|0|0|0|0 +*|AnimalTrainer||||||1499|619|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|TailorGuildmaster||||||896|610|-40|3|2|10|5|5|1|1|0|0|0|0|0 +*|Weaver||||||896|610|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Tailor||||||896|610|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Cobbler||||||1318|1328|-14|3|2|10|5|5|1|2|0|0|0|0|0 +*|Provisioner||||||1318|1328|-14|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||369|1432|15|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||369|1432|15|3|2|10|5|5|1|2|0|0|0|0|0 +*|Cobbler||||||1598|539|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|Provisioner||||||1598|539|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|Innkeeper||||||774|1144|-30|3|2|10|5|5|1|2|0|0|0|0|0 +*|MageGuildmaster||||||1505|611|-19|3|2|10|5|5|1|1|0|0|0|0|0 +*|Alchemist||||||1505|611|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|Mage||||||1505|611|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|FortuneTeller||||||1394|441|14|3|2|10|5|5|1|2|0|0|0|0|0 +*|GypsyBanker||||||1405|439|2|3|2|10|5|5|1|2|0|0|0|0|0 +*|Scribe||||||869|625|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Scribe||||||868|657|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Jeweler||||||859|698|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Jeweler||||||1605|541|-13|3|2|10|5|5|1|2|0|0|0|0|0 +*|Innkeeper||||||1620|554|-20|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||872|586|-40|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||872|586|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||1093|955|-38|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||1093|955|-38|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||1518|619|-19|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||1518|619|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||1628|548|-11|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||1628|548|-11|3|2|10|5|5|1|2|0|0|0|0|0 +*|FortuneTeller||||||1407|428|-6|3|2|10|5|5|1|2|0|0|0|0|0 +*|FortuneTeller||||||1235|543|-15|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||284|536|-24|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||284|536|-24|3|2|10|5|5|1|2|0|0|0|0|0 +*|PowerGenerator||||||851|801|-60|3|5|10|0|0|1|1|0|0|0|0|0 +*|PowerGenerator||||||806|801|-60|3|5|10|0|0|1|1|0|0|0|0|0 +*|PowerGenerator||||||851|756|-60|3|5|10|0|0|1|1|0|0|0|0|0 +*|PowerGenerator||||||806|756|-60|3|5|10|0|0|1|1|0|0|0|0|0 +*|BlacksmithGuildmaster||||||1261|582|-18|3|2|10|5|5|1|1|0|0|0|0|0 +*|Blacksmith||||||1261|582|-18|3|2|10|5|5|1|2|0|0|0|0|0 +*|SpeckledScorpion||||||1546|631|-14|3|5|10|5|5|1|1|0|0|0|0|0 +*|SpeckledScorpion||||||1607|598|-14|3|5|10|5|5|1|1|0|0|0|0|0 +*|SpeckledScorpion||||||1600|629|-14|3|5|10|5|5|1|1|0|0|0|0|0 +*|SpeckledScorpion||||||1588|610|-14|3|5|10|5|5|1|2|0|0|0|0|0 +*|SpeckledScorpion||||||1576|597|-14|3|5|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||1364|1051|-13|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||1364|1051|-13|3|2|10|5|5|1|2|0|0|0|0|0 +*|Innkeeper||||||665|665|-35|3|2|10|5|5|1|2|0|0|0|0|0 +*|GypsyMaiden||||||1400|434|-11|3|2|10|5|5|1|2|0|0|0|0|0 +*|Cobbler||||||824|602|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Provisioner||||||824|602|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Provisioner||||||826|679|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Cobbler||||||826|679|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Minter||||||1610|556|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|Banker||||||1610|556|-19|3|2|10|5|5|1|2|0|0|0|0|0 +*|GypsyBanker||||||1226|554|-11|3|2|10|5|5|1|2|0|0|0|0|0 +*|Tinker||||||766|641|0|3|2|10|5|5|1|2|0|0|0|0|0 +*|TinkerGuildmaster||||||766|641|0|3|2|10|5|5|1|1|0|0|0|0|0 +*|Minter||||||855|603|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Banker||||||855|603|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Minter||||||854|680|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Banker||||||854|680|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Weaponsmith||||||1497|614|-14|3|2|10|5|5|1|2|0|0|0|0|0 +*|Armorer||||||1497|614|-14|3|2|10|5|5|1|2|0|0|0|0|0 +*|GypsyAnimalTrainer||||||1388|428|-22|3|2|10|5|5|1|2|0|0|0|0|0 +*|GypsyAnimalTrainer||||||1225|563|-18|3|2|10|5|5|1|2|0|0|0|0|0 +*|Weaponsmith||||||808|586|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Weaponsmith||||||808|697|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Armorer||||||808|586|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Armorer||||||808|697|-40|3|2|10|5|5|1|2|0|0|0|0|0 +*|Baker||||||1514|611|-14|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||682|297|-41|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||682|297|-41|3|2|10|5|5|1|2|0|0|0|0|0 +*|HealerGuildmaster||||||575|537|-69|3|2|10|5|5|1|1|0|0|0|0|0 +*|Healer||||||575|537|-69|3|2|10|5|5|1|2|0|0|0|0|0 +*|earthelemental set fireresistseed 100 name "Rocaille" hue 801||||||56|689|-28|3|30|60|20|12|1|4|0|0|0|0|0 +*|orcbanker set passivespeed 3 activespeed 1.5||||||38|679|-28|3|5|10|1|1|1|1|0|0|0|0|0 +*|FireColumnTrap set itemid 1342 maxdamage 15||||||113|715|-28|3|30|60|20|12|1|8|0|0|0|0|0 +*|earthelemental set fireresistseed 100 name "Rocaille" hue 801||||||59|721|-28|3|30|60|20|12|1|4|0|0|0|0|0 +*|FireColumnTrap set itemid 1342 maxdamage 15||||||55|689|-28|3|30|60|20|12|1|10|0|0|0|0|0 +*|earthelemental set fireresistseed 100 name "Rocaille" hue 801||||||114|716|-28|3|30|60|20|12|1|3|0|0|0|0|0 +*|FireColumnTrap set itemid 1342 maxdamage 15||||||60|721|-28|3|30|60|20|12|1|6|0|0|0|0|0 +*|earthelemental set fireresistseed 100 name "Rocaille" hue 801||||||79|689|-28|3|30|60|20|8|1|2|0|0|0|0|0 +*|FireColumnTrap set itemid 1342 maxdamage 15||||||78|689|-28|3|30|60|20|8|1|8|0|0|0|0|0 +*|earthelemental set fireresistseed 100 name "Rocaille" hue 801||||||87|721|-28|3|30|60|20|12|1|5|0|0|0|0|0 +*|FireColumnTrap set itemid 1342 maxdamage 15||||||87|722|-28|3|30|60|20|16|1|12|0|0|0|0|0 diff --git a/Data/Monsters/felucca/BlightedGrove.map b/Data/Monsters/felucca/BlightedGrove.map new file mode 100644 index 0000000..eb77c28 --- /dev/null +++ b/Data/Monsters/felucca/BlightedGrove.map @@ -0,0 +1,19 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 201 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Blighted Grove +## +*|giantserpent:gianttoad:harpy:silverserpent:snake:bogling||||||6513|871|0|1|5|10|35|35|1|17|0|0|0|0|0 +*|tangle:bogling:alligator:reaper:corpser:changeling:whippingvine||||||6507|843|0|1|5|10|10|10|1|8|0|0|0|0|0 +*|abscess:hydra:bogthing||||||6535|848|0|1|5|10|10|10|1|4|0|0|0|0|0 +*|thrasher:swamptentacle:reaper:bogling:alligator:coil:whippingvine||||||6518|870|0|1|5|10|40|40|1|9|0|0|0|0|0 +*|insanedryad||||||6540|872|0|1|5|10|5|5|1|1|0|0|0|0|0 +*|harpy:saliva:changeling||||||6585|878|0|1|5|10|10|10|1|7|0|0|0|0|0 +*|insanedryad||||||6489|897|0|1|5|10|5|5|1|1|0|0|0|0|0 +*|insanedryad||||||6518|879|0|1|5|10|5|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/felucca/BritainSewer.map b/Data/Monsters/felucca/BritainSewer.map new file mode 100644 index 0000000..a90ab1e --- /dev/null +++ b/Data/Monsters/felucca/BritainSewer.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 202 +overridemap 1 +overridemintime 0 +overridemaxtime 1 +## +## Britain Sewer +## +*|sewerrat:Rat|Bullfrog|||||6049|1447|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6091|1491|10|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6048|1487|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6065|1459|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6092|1448|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6107|1452|25|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6112|1462|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6039|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6115|1491|-15|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6084|1470|5|2|5|10|15|1|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6049|1470|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6034|1467|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6059|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6061|1490|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6041|1486|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|alligator||||||6090|1483|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6077|1492|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6108|1471|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6087|1443|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6052|1463|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6037|1494|0|2|5|10|10|4|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Covetous.map b/Data/Monsters/felucca/Covetous.map new file mode 100644 index 0000000..43e78df --- /dev/null +++ b/Data/Monsters/felucca/Covetous.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 203 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Covetous Dungeon +## +## Level 1 +## +*|Harpy||||||5472|1877|0|2|1|10|25|10|1|6|0|0|0|0|0 +*|Headlessone||||||5453|1905|0|2|2|10|25|5|1|4|0|0|0|0|0 +*|Stoneharpy||||||5443|1918|0|2|2|10|30|7|1|2|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5418|1876|0|2|2|10|30|10|1|4|2|0|0|0|0 +*|Gazer|Gazerlarva|||||5411|1901|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Corpser||||||5393|1921|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5400|1937|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5452|1891|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5399|1859|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5387|1911|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Corpser||||5411|1932|0|2|2|10|7|7|1|1|2|6|0|0|0 +## +## Level 2 +## +*|Headlessone||||||5577|2006|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5593|2017|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5558|2025|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Harpy|Stoneharpy|||||5498|1998|0|2|2|10|30|15|1|8|1|0|0|0|0 +*|Giantspider|Dreadspider|||||5474|2035|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Slime||||||5469|2019|0|2|2|10|25|10|1|5|0|0|0|0|0 +*|Waterelemental||||||5445|2030|-3|2|2|10|15|15|1|2|0|0|0|0|0 +*|Giantspider|Dreadspider|||||5440|2023|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Giantspider|Dreadspider|||||5473|1991|0|2|2|10|25|9|1|2|2|0|0|0|0 +*|Gazer|Gazerlarva|Eldergazer||||5457|1971|0|2|2|10|25|15|1|4|2|1|0|0|0 +*|Corpser||||||5436|1972|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5417|1975|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5429|1989|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Corpser||||||5425|1992|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|Gazer||||||5388|2012|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5503|2002|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|Corpser|||||5413|2000|0|2|2|10|10|10|1|1|7|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5460|1975|0|2|1|2|7|7|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5448|2027|0|2|1|2|8|8|1|1|2|0|0|0|0 +## +## Skeleton Passage +## +*|Skeleton||||||2456|861|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2480|863|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2493|883|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2513|862|0|2|2|10|25|10|1|4|0|0|0|0|0 +## +## Level 3 +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5596|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1876|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Boneknight|Skeleton|Zombie|Shade|||5603|1875|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|||5617|1861|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|TreasureLevel3|TreasureLevel4|5615|1838|0|2|2|10|25|8|1|3|1|1|1|1|2 +*|Lich|Spectre|Skeleton||||5579|1859|0|2|2|10|25|11|1|7|3|1|0|0|0 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1843|0|2|2|10|40|15|1|1|1|1|2|1|1 +## +## Undead Prison +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5528|1808|0|2|2|10|30|15|1|1|1|1|3|1|1 +*|Rottingcorpse|TreasureLevel3|TreasureLevel4||||5504|1808|0|2|2|10|12|3|1|1|1|2|0|0|0 +## +## Dragon's Lair +## +*|Dragon|Drake|||||5452|1799|0|2|2|10|30|20|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5461|1818|0|2|1|2|8|8|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Deceit.map b/Data/Monsters/felucca/Deceit.map new file mode 100644 index 0000000..9dd6957 --- /dev/null +++ b/Data/Monsters/felucca/Deceit.map @@ -0,0 +1,57 @@ +############## +## By Nerun ## +############## +overrideid 204 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Deceit Dungeon +## +## Level 1 +## +*|Mummy|Skeleton|Zombie||||5187|603|0|2|2|10|35|18|1|1|3|1|0|0|0 +*|Waterelemental||||||5186|575|0|2|2|10|12|8|1|2|0|0|0|0|0 +*|Skeleton||||||5187|545|0|2|2|10|25|6|1|2|0|0|0|0|0 +*|Mummy|Skeleton|Zombie||||5163|567|0|2|2|10|25|6|1|1|3|1|0|0|0 +*|Skeleton|Zombie|||||5145|553|-40|2|2|10|35|8|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|579|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|598|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5145|622|-50|2|2|10|25|8|1|2|2|0|0|0|0 +*|Skeleton|Spectre|||||5212|531|0|2|2|10|25|8|1|2|1|0|0|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|552|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|573|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|TreasureLevel2|TreasureLevel3|||||5145|618|-50|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ghoul|Skeleton|Wraith|Zombie|||5307|546|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5327|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5286|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Wraith|||||5283|583|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Ghoul|Mummy|Shade|Wraith|Zombie||5318|578|0|2|2|10|25|10|1|1|1|1|1|1|0 +*|Boneknight|Skeletalknight|||||5342|582|0|2|2|10|25|10|1|4|4|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|||5299|603|0|2|2|10|25|10|1|1|1|2|1|0|0 +*|Bonemagi||||||5295|623|-5|2|2|10|10|6|1|3|0|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|Zombie||5322|626|0|2|2|10|25|15|1|1|1|2|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5323|571|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## Level 3 +## +*|Ghoul|Shade|Spectre|Wraith|||5139|661|0|2|2|10|25|15|1|1|1|1|1|0|0 +*|Lich||||||5190|655|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5170|678|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Lich|Spectre|Wraith|||5151|718|0|2|2|10|25|10|1|1|3|1|1|0|0 +*|Ghoul|Poisonelemental|||||5192|695|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Poisonelemental|||||5183|727|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5212|674|-20|2|2|10|25|12|1|1|1|1|1|0|0 +*|Lich||||||5219|734|-20|2|2|10|25|15|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5150|742|0|2|2|10|15|3|1|1|2|2|0|0|0 +## +## Level 4 +## +*|Ghoul|Lich|||||5307|675|-20|2|2|10|25|10|1|2|1|0|0|0|0 +*|Fireelemental||||||5280|675|8|2|2|10|25|10|1|2|0|0|0|0|0 +*|Lich||||||5320|708|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|Lich|Lichlord|Silverserpent||5314|748|-20|2|2|10|25|8|1|1|2|3|1|2|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5267|690|0|2|2|10|35|2|1|1|2|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Despise.map b/Data/Monsters/felucca/Despise.map new file mode 100644 index 0000000..425ea82 --- /dev/null +++ b/Data/Monsters/felucca/Despise.map @@ -0,0 +1,63 @@ +############## +## By Nerun ## +############## +overrideid 205 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Despise Dungeon +## +## Note: Acidelemental do not exist then i used Toxicelemental instead. +## +## Level 1 +## +*|Lizardman|TreasureLevel2|TreasureLevel3||||5503|529|60|2|2|10|25|12|1|5|1|1|0|0|0 +*|Lizardman||||||5504|597|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5464|600|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5435|589|47|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5410|611|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman|TreasureLevel2|TreasureLevel3||||5386|612|45|2|2|10|25|12|1|5|1|2|0|0|0 +*|Lizardman||||||5405|576|61|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5411|541|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5460|526|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5394|525|65|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5390|587|45|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ettin||||||5490|676|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Ettin||||||5483|711|15|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental|Ettin|||||5505|747|5|2|2|10|25|18|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5475|748|5|2|2|10|25|12|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5420|746|5|2|2|10|25|18|1|4|6|0|0|0|0 +*|Ettin||||||5385|703|15|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|660|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental||||||5441|680|20|2|2|10|25|12|1|6|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5507|656|20|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5387|697|15|2|1|2|5|5|1|1|4|0|0|0|0 +## +## Level 3 +## +*|Troll||||||5439|851|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5470|860|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5426|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5482|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Ogre||||||5532|787|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogre||||||5604|789|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogrelord||||||5558|824|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Ogre||||||5590|871|45|2|2|10|35|20|1|3|0|0|0|0|0 +*|Ogre||||||5528|902|30|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ettin||||||5487|902|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5504|939|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Cyclops||||||5471|973|15|2|2|10|25|18|1|3|0|0|0|0|0 +*|Ettin||||||5426|943|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|905|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Toxicelemental||||||5398|996|5|2|2|10|25|15|1|3|0|0|0|0|0 +*|TreasureLevel2||||||5593|794|60|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5546|888|30|2|1|2|8|8|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5397|995|5|2|1|2|10|10|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5605|799|60|2|1|2|10|10|1|3|0|0|0|0|0 +*|TreasureLevel3||||||5557|828|45|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5398|995|5|2|1|2|10|10|1|2|0|0|0|0|0 +*|TreasureLevel4||||||5564|821|45|2|1|2|5|5|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Destard.map b/Data/Monsters/felucca/Destard.map new file mode 100644 index 0000000..66b8f02 --- /dev/null +++ b/Data/Monsters/felucca/Destard.map @@ -0,0 +1,55 @@ +############## +## By Nerun ## +############## +overrideid 206 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Destard Dungeon +## +## Level 1 - First Big Lair (entrance) +## +*|Dragon|Drake|Wyvern||||5209|965|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|||||5247|956|-40|2|2|10|50|30|1|1|2|0|0|0|0 +*|Dragon|Drake|Wyvern||||5280|955|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5284|926|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5214|917|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5241|945|-40|2|1|2|10|10|1|1|2|0|0|0|0 +## +## Level 1 - Left Arm +## +*|Giantserpent||||||5161|940|0|2|2|10|50|20|1|6|0|0|0|0|0 +*|Wyvern|Dragon|Drake||||5149|907|0|2|2|10|20|15|1|1|1|1|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5141|915|0|2|1|2|25|25|1|1|2|0|0|0|0 +## +## Level 1 - Right Arm +## +*|Waterelemental||||||5352|934|-5|2|2|10|10|10|1|4|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5317|980|0|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 1 - Second Big Lair (near Shrine) +## +*|Giantserpent||||||5250|869|0|2|2|10|50|30|1|6|0|0|0|0|0 +*|Dragon|Drake|Wyvern||||5226|826|0|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5269|811|7|2|2|10|50|30|1|1|2|1|0|0|0 +*|Drake|Wyvern|||||5307|815|0|2|2|10|50|30|1|1|1|0|0|0|0 +*|Waterelemental||||||5294|842|0|2|2|10|50|30|1|4|0|0|0|0|0 +*|Waterelemental||||||5203|787|5|2|2|10|25|12|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5229|841|1|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5205|778|0|2|1|2|7|7|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Drake|Shadowwyrm|Wyvern||||5141|834|0|2|2|10|50|30|1|1|1|1|0|0|0 +*|Daemon|Evilmage|||||5169|836|0|2|2|10|50|30|1|2|1|0|0|0|0 +*|Drake|Shadowwyrm|Wyvern||||5152|869|0|2|2|10|50|25|1|1|1|1|0|0|0 +*|TreasureLevel4:TreasureLevel3:TreasureLevel2||||||5153|842|0|2|1|2|40|40|1|4|0|0|0|0|0 +## +## Level 3 - Ancient Wyrm Lair +## +*|Fireelemental||||||5141|968|0|2|2|10|10|10|1|1|0|0|0|0|0 +*|Wyvern:Wyvern:Giantserpent||||||5157|997|0|2|2|10|50|20|1|3|0|0|0|0|0 +*|Ancientwyrm||||||5185|1006|0|2|2|10|50|20|1|1|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5143|986|0|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5183|1007|0|2|1|2|10|10|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Fire.map b/Data/Monsters/felucca/Fire.map new file mode 100644 index 0000000..fd81900 --- /dev/null +++ b/Data/Monsters/felucca/Fire.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 207 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Britain/Lost Lands +## Fire Dungeon - OSI Legends like +## +## Level 1 - Part I +## +*|Slime|Giantrat|Giantserpent||||5693|1415|38|2|5|10|20|10|1|1|2|1|0|0|0 +*|Slime||||||5695|1434|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Evilmagelord||||||5680|1438|0|2|5|10|20|10|1|2|0|0|0|0|0 +*|Giantrat|Lavasnake|Evilmage||||5733|1433|22|2|5|10|20|10|1|1|1|1|0|0|0 +*|Lavalizard||||||5787|1427|17|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5717|1465|-2|2|5|10|15|10|1|3|0|0|0|0|0 +*|Fireelemental|Lavasnake|Hellcat|Hellhound|||5744|1471|2|2|5|10|15|10|1|3|1|1|1|0|0 +*|Efreet|Lavaserpent|Hellhound|Fireelemental|||5790|1451|7|2|5|10|15|5|1|1|1|1|1|0|0 +## Graveyard +*|Lich|Bonemagi:Skeletalmage|Hellcat|Hellhound|Fireelemental|Lavalizard|5852|1468|1|2|5|10|30|25|1|4|6|1|3|2|1 +*|Lavasnake||||||5852|1468|1|2|5|10|30|25|1|1|0|0|0|0|0 +## +## Level 1 - Part II +## +*|Lavalizard||||||5859|1387|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Hellcat||||||5787|1386|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5818|1379|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5836|1364|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5809|1332|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5859|1341|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental|Efreet|Lavaserpent||||5835|1304|0|2|5|10|30|15|1|4|1|1|0|0|0 +*|Hellcat|Fireelemental|||||5867|1309|0|2|5|10|20|10|1|1|1|0|0|0|0 +## +## Level 2 +## +*|Fireelemental||||||5699|1302|1|2|5|10|15|15|1|1|0|0|0|0|0 +*|Fireelemental||||||5723|1291|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound||||||5732|1297|-1|2|5|10|20|5|1|1|0|0|0|0|0 +*|Efreet|Lavalizard|||||5667|1315|5|2|5|10|20|20|1|2|1|0|0|0|0 +*|Fireelemental|Lavaserpent|||||5747|1320|0|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lavalizard|Fireelemental|||||5717|1333|6|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lich|Lichlord|||||5731|1379|0|2|5|10|7|3|1|3|1|0|0|0|0 +*|Hellhound||||||5709|1364|-1|2|5|10|20|10|1|6|0|0|0|0|0 +*|Daemon||||||5691|1347|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound|Hellcat|||||5678|1340|-2|2|5|10|30|10|1|1|1|0|0|0|0 +*|Evilmage|Hellhound|Lavasnake|Hellcat|||5651|1363|0|2|5|10|3|3|1|1|5|1|1|0|0 +*|Evilmage||||||5654|1380|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5689|1387|1|2|5|10|10|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5656|1412|0|2|5|10|10|0|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1402|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1403|0|2|5|10|3|3|1|1|0|0|0|0|0 +*|Hellhound||||||5651|1408|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage|Evilmagelord|||||5651|1418|0|2|5|10|3|2|1|1|1|0|0|0|0 +*|Evilmage||||||5650|1419|22|2|5|10|5|2|1|1|0|0|0|0|0 +*|Evilmage||||||5647|1439|22|2|5|10|15|1|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1443|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmagelord||||||5638|1439|0|2|5|10|40|0|1|1|0|0|0|0|0 +## +## Treasures +## +*|TreasureLevel2||||||5714|1465|0|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|1390|2|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5679|1438|0|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|1465|-1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5722|1390|1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5679|1439|0|2|1|2|5|5|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5650|1434|0|2|1|2|2|2|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5643|1435|0|2|1|2|2|2|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Graveyards.map b/Data/Monsters/felucca/Graveyards.map new file mode 100644 index 0000000..1f18704 --- /dev/null +++ b/Data/Monsters/felucca/Graveyards.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 208 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Graveyards +## +## Britain Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 +## +## Jhelom Graveyard +*|Spectre:Wraith:Shade|Skeleton|Zombie||||1285|3731|0|2|5|10|15|10|1|2|3|4|0|0|0 +## +## Cove Graveyard +*|Spectre:Shade:Wraith|Lich|Skeleton|Zombie|||2438|1100|8|2|5|10|20|10|1|1|1|1|1|0|0 +## +## Moonglow Graveyard +*|Spectre:Shade:Wraith|Skeleton|Zombie||||4545|1317|8|2|5|10|20|10|1|1|1|2|0|0|0 +*|Lich||||||4543|1314|8|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Vesper Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||2758|867|0|2|5|10|20|20|1|2|3|4|0|0|0 +## +## Yew Graveyard +*|Skeleton||||||722|1119|0|2|5|10|20|20|1|10|0|0|0|0|0 +## +## Haven Graveyard +*|zombie:skeleton||||||3407|2652|48|2|5|10|15|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Hythloth.map b/Data/Monsters/felucca/Hythloth.map new file mode 100644 index 0000000..86bf072 --- /dev/null +++ b/Data/Monsters/felucca/Hythloth.map @@ -0,0 +1,102 @@ +############## +## By Nerun ## +############## +overrideid 209 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Hythloth Dungeon +## +## Level 1 +## +*|Imp|Hellhound|||||5923|48|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|TreasureLevel1|||||5911|55|22|2|2|10|25|10|1|2|3|0|0|0|0 +*|Imp|Hellhound|||||5948|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|Hellhound|||||5954|26|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Imp|Hellhound|||||5977|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Firegargoyle||||||5995|62|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5970|80|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle|Hellhound|||||5994|96|0|2|2|10|20|10|1|2|1|0|0|0|0 +*|Imp|Hellhound|||||5946|75|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5940|107|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5915|91|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5990|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5985|36|22|2|1|2|2|2|1|2|0|0|0|0|0 +*|TreasureLevel1||||||5989|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5983|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5979|26|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5981|84|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5966|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5958|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5937|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5921|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5972|86|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5917|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5929|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5945|78|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5967|80|0|2|1|2|6|6|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Imp|Hellhound|||||5961|169|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Daemon||||||5992|146|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5945|175|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5956|145|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||5917|156|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5914|195|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5918|223|44|2|2|10|20|10|1|4|0|0|0|0|0 +*|Daemon|TreasureLevel4|||||5918|235|44|2|2|10|20|10|1|2|1|0|0|0|0 +*|Gargoyle|TreasureLevel3|||||5954|225|22|2|2|10|20|12|1|4|1|0|0|0|0 +*|Gazer|Gazerlarva|||||5986|203|44|2|2|10|25|12|1|3|2|0|0|0|0 +*|TreasureLevel1||||||5983|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5992|147|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5970|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5997|145|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5978|185|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5962|217|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5989|186|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5926|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Imp|Hellhound|Gargoyle||||6094|154|-22|2|2|10|20|10|1|1|1|2|0|0|0 +*|Eldergazer|Gazer|Gazerlarva||||6122|170|0|2|2|10|20|10|1|1|3|2|0|0|0 +*|Balron|Gargoyle|Gazer||||6086|178|0|2|2|10|20|10|1|1|2|2|0|0|0 +*|Daemon|Gargoyle|Gazer||||6119|219|22|2|2|10|20|10|1|2|2|2|0|0|0 +*|Gargoyle||||||6058|193|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Daemon|Stonegargoyle|||||6033|199|22|2|2|10|20|10|1|2|1|0|0|0|0 +*|Daemon|Gazer|Gazerlarva||||6052|156|0|2|2|10|20|10|1|2|3|2|0|0|0 +*|TreasureLevel2||||||6121|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6124|159|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6087|186|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6060|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6046|199|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6041|222|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6125|221|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6120|229|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6092|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6041|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6033|205|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6058|153|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Daemon|Hellhound|Imp||||6064|96|22|2|2|10|20|10|1|2|1|1|0|0|0 +*|Gargoyle||||||6081|83|21|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6084|66|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6106|67|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Firegargoyle||||||6116|86|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6099|51|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Balron||||||6107|37|22|2|2|10|20|10|1|1|0|0|0|0|0 +*|Gazer|Imp|Stonegargoyle||||6054|45|0|2|2|10|20|10|1|1|1|1|0|0|0 +*|TreasureLevel2||||||6108|66|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||6117|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6058|92|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6113|92|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6107|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6081|44|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6097|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6064|96|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6086|45|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6108|36|22|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Ice.map b/Data/Monsters/felucca/Ice.map new file mode 100644 index 0000000..34769c3 --- /dev/null +++ b/Data/Monsters/felucca/Ice.map @@ -0,0 +1,53 @@ +############## +## By Nerun ## +############## +overrideid 210 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Ice Dungeon +## +## Level 1 +## +*|Arcticogrelord||||||5771|224|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Iceserpent|Snowelemental|Ratman|Frosttroll|Frostspider||5799|188|-6|2|5|10|25|10|1|2|1|1|1|1|0 +*|Frostspider|Frostooze|Icesnake||||5867|218|-4|2|5|10|25|15|1|1|2|1|0|0|0 +*|Ratmanmage||||||5850|219|-3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Arcticogrelord||||||5814|237|0|2|5|7|15|15|1|1|0|0|0|0|0 +*|Whitewyrm||||||5752|144|9|2|2|5|10|10|1|1|0|0|0|0|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5839|159|0|2|5|10|20|15|1|1|1|1|1|1|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5785|161|-6|2|5|10|20|18|1|1|1|1|1|1|0 +*|Iceserpent|Ratman|Snowelemental:Iceelemental|Frosttroll|||5757|213|-7|2|5|10|20|15|1|3|1|4|2|0|0 +*|Iceserpent|Snowelemental:Iceelemental|Frosttroll|Ratman|||5681|191|-6|2|5|10|20|15|1|3|4|1|1|0|0 +*|Iceserpent|Snowelemental:Iceelemental|||||5731|176|-5|2|5|10|35|25|1|9|9|0|0|0|0 +## Treasures +*|TreasureLevel2||||||5848|226|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5683|197|-4|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5721|147|-1|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5758|139|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5754|211|-6|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5833|242|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5854|227|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5772|188|-3|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5837|245|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5751|140|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5763|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5756|203|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5712|145|-34|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5684|181|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ratman Room +## +*|Ratman|Ratmanarcher|Ratmanmage||||5831|358|-1|2|5|10|25|15|1|12|7|5|0|0|0 +*|TreasureLevel2||||||5838|355|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5824|363|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ice Demon Lair +## +*|Icefiend||||||5680|306|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|Icefiend||||||5669|330|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5696|303|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5682|314|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5666|331|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5676|331|0|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Khaldun.map b/Data/Monsters/felucca/Khaldun.map new file mode 100644 index 0000000..12c9310 --- /dev/null +++ b/Data/Monsters/felucca/Khaldun.map @@ -0,0 +1,59 @@ +####################### +## By Requiem ## +## (www.drasnia.com) ## +## Adapted by Nerun ## +####################### +overrideid 228 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Dungeon Khaldun +## +*|Shadowfiend||||||5569|1306|0|1|1|6|10|5|1|1|0|0|0|0|0 +*|Cursed||||||5539|1301|0|1|1|6|30|20|1|4|0|0|0|0|0 +*|Shadowfiend||||||5525|1296|0|1|1|6|20|20|1|2|0|0|0|0|0 +*|Skeletalknight||||||5492|1294|0|1|1|6|20|10|1|2|0|0|0|0|0 +*|Zombie||||||5492|1297|0|1|2|6|20|10|1|2|0|0|0|0|0 +*|LysanderGathenwale||||||5458|1303|0|1|1|3|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5415|1312|0|1|1|8|20|20|1|1|0|0|0|0|0 +*|Skeletalknight||||||5399|1298|0|1|1|6|20|10|1|1|0|0|0|0|0 +*|MorgBergen||||||5398|1299|0|1|1|6|20|10|1|1|0|0|0|0|0 +*|Boneknight||||||5412|1330|0|1|1|6|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5415|1331|0|1|1|6|20|20|1|1|0|0|0|0|0 +*|Skeleton||||||5403|1332|0|1|1|6|20|20|1|2|0|0|0|0|0 +*|TavaraSewel||||||5420|1355|0|1|1|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5422|1355|0|1|1|6|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5435|1346|0|1|2|8|10|10|1|1|0|0|0|0|0 +*|Zombie||||||5396|1371|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Cursed||||||5395|1370|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5393|1369|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Khaldunzealot||||||5400|1397|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Skeletalknight||||||5444|1410|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5442|1411|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Khaldunsummoner||||||5400|1428|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5402|1430|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Shadowfiend||||||5404|1431|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5425|1451|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Skeleton||||||5418|1450|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Bonemagi||||||5425|1484|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Shadowfiend||||||5430|1485|0|1|2|8|30|30|1|3|0|0|0|0|0 +*|Skeleton||||||5433|1485|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Ancientlich||||||5458|1445|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Khaldunsummoner||||||5459|1449|0|1|2|8|30|30|1|1|0|0|0|0|0 +*|Khaldunzealot||||||5460|1451|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Skeletalmage||||||5465|1449|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5483|1446|0|1|2|8|30|30|1|2|0|0|0|0|0 +*|Zombie||||||5485|1434|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5499|1411|0|1|2|8|30|30|1|2|0|0|0|0|0 +*|Spectralarmour||||||5475|1402|0|1|2|8|30|30|1|2|0|0|0|0|0 +*|Skeleton||||||5491|1370|0|1|2|8|20|20|1|3|0|0|0|0|0 +*|Spectralarmour||||||5490|1367|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5521|1397|0|1|2|8|10|10|1|1|0|0|0|0|0 +*|HarrowerTentacles||||||5605|1343|0|1|30|55|20|1|1|1|0|0|0|0|0 +*|Khaldunsummoner||||||5536|1351|0|1|2|8|20|10|1|1|0|0|0|0|0 +*|Khaldunzealot||||||5536|1345|0|1|2|8|20|10|1|1|0|0|0|0|0 +*|Cursed||||||5549|1324|0|1|2|8|30|30|1|3|0|0|0|0|0 +*|Ancientlich||||||5549|1332|0|1|2|10|30|10|1|1|0|0|0|0|0 +*|Cursed||||||5505|1316|0|1|2|8|20|20|1|3|0|0|0|0|0 +*|GrimmochDrummel||||||5452|1366|0|1|2|8|10|5|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/LostLands.map b/Data/Monsters/felucca/LostLands.map new file mode 100644 index 0000000..0849014 --- /dev/null +++ b/Data/Monsters/felucca/LostLands.map @@ -0,0 +1,341 @@ +############## +## By Nerun ## +############## +overrideid 211 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## T2A - Lost Lands +## +## Papua +## +*|Swampdragon||||||5728|3209|-3|2|5|10|100|100|1|7|0|0|0|0|0 +## +## T2ADesertMain +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5457|2651|45|2|5|10|150|150|1|15|15|6|9|6|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5457|2651|45|2|5|10|150|150|1|3|6|4|6|0|0 +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5520|2890|33|2|5|10|100|100|1|10|10|4|6|4|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5520|2890|33|2|5|10|100|100|1|3|4|2|4|0|0 +## +## T2ADesCent +## +*|Gazer|Reaper|Scorpion|Giantserpent|Troll||5580|2885|6|2|5|10|15|15|1|3|2|3|2|2|0 +## +## T2ADryCenter +## +*|Corpser|Giantspider|Troll|Harpy|Ettin|Gazer|5557|2625|0|2|5|10|40|40|1|3|3|3|6|3|3 +## +## T2ACyclop +## +*|Cyclops|Titan|||||5394|2530|6|2|5|10|25|15|1|5|3|0|0|0|0 +## +## T2ADesertFinal +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Wyvern|5711|2494|46|2|5|10|80|80|1|3|3|1|3|2|1 +*|Ettin||||||5711|2494|46|2|5|10|80|80|1|2|0|0|0|0|0 +## +## T2ABaseOph +## +*|Ophidianarchmage|Ophidianmage|Ophidianmatriarch|Ophidianknight|Ophidianwarrior||5765|2637|39|2|5|10|30|25|1|3|6|3|4|10|0 +## +## T2AWyvern +## +*|Wyvern|Drake|Imp|Mongbat|||5697|2626|-2|2|5|10|30|25|1|2|4|1|2|0|0 +## +## T2ASmallDesert +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5729|2767|-1|2|5|10|70|60|1|8|8|3|5|3|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5729|2767|-1|2|5|10|70|60|1|3|3|3|5|0|0 +## +## T2ALava +## +*|Hellhound|Lavalizard|Fireelemental|Efreet|Hellcat|Lavaserpent|5724|2949|31|2|5|10|75|65|1|8|8|10|4|6|8 +*|Lavasnake||||||5724|2949|31|2|5|10|75|65|1|15|0|0|0|0|0 +## +## T2AWyvIsle +## +*|Wyvern||||||5863|2470|46|2|5|10|25|25|1|6|0|0|0|0|0 +## +## T2AIce1 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5501|2361|27|2|5|10|75|40|1|4|8|4|4|5|5 +*|Polarbear||||||5501|2361|27|2|5|10|75|40|1|5|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5351|2359|0|2|5|10|75|40|1|4|7|4|4|5|5 +*|Polarbear||||||5351|2359|0|2|5|10|75|40|1|5|0|0|0|0|0 +## +## T2AIce2 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5173|2368|21|2|5|10|50|30|1|4|10|4|4|3|3 +*|Polarbear||||||5173|2368|21|2|5|10|50|30|1|3|0|0|0|0|0 +## +## T2ALastIceIsle +## +*|Iceserpent|Icesnake|Snowelemental|Whitewolf|Walrus|Polarbear|6091|2379|25|2|5|10|60|30|1|6|10|3|3|3|3 +## +## T2AIceFinal +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5967|2370|44|2|5|10|75|50|1|6|4|4|4|4|4 +*|Polarbear||||||5967|2370|44|2|5|10|75|50|1|4|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5817|2367|42|2|5|10|75|50|1|6|3|3|3|4|4 +*|Polarbear||||||5817|2367|42|2|5|10|75|50|1|4|0|0|0|0|0 +## +## T2AFor3 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5756|3453|-2|2|5|10|130|130|1|10|10|10|2|10|0 +## +## T2ASwamp +## +*|Gianttoad|Swampdragon|Giantrat|Alligator|Sewerrat|Plaguebeast|5985|3441|17|2|5|10|90|80|1|8|5|12|12|11|2 +*|Bullfrog|Swamptentacle|Bogling|Bogthing|||5985|3441|17|2|5|10|90|80|1|15|5|13|3|0|0 +## +## T2AUndead +## +*|Boneknight|Skeletalknight|Bonemagi|Skeleton|Wraith|Ghoul|5220|3664|-1|2|5|10|25|20|1|3|3|3|6|4|4 +## +## T2ASavage +## +*|Savagerider|Savage|Savageshaman||||5212|3619|0|2|5|10|15|10|1|3|9|3|0|0|0 +## +## T2ADeer +## +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5347|3449|17|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5243|3548|14|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5250|3449|16|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5349|3547|-1|2|5|10|50|50|1|4|8|4|4|16|4 +## +## T2AWild1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5201|3162|53|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5201|3162|53|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5251|3301|-2|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5251|3301|-2|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5250|3401|1|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5250|3401|1|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5351|3401|30|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5351|3401|30|2|5|10|50|50|1|2|2|2|0|0|0 +## +## T2AWild1&2 - 1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6018|3673|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6018|3673|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6018|3673|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6018|3673|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 2 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3773|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3773|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3773|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3773|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 3 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|2874|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|2874|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|2874|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|2874|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 4 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3971|17|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3971|17|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3971|17|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3971|17|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 5 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5920|3675|12|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5920|3675|12|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5920|3675|12|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5920|3675|12|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 6 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5921|3777|28|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5921|3777|28|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5921|3777|28|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5921|3777|28|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 7 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5919|3875|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5919|3875|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5919|3875|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5919|3875|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 8 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5918|3975|1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5918|3975|1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5918|3975|1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5918|3975|1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 9 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3675|0|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3675|0|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3675|0|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3675|0|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 10 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3775|48|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3775|48|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3775|48|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3775|48|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 11 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5818|3876|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5818|3876|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5818|3876|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5818|3876|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 12 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5819|3974|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5819|3974|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5819|3974|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5819|3974|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 13 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3675|22|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3675|22|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3675|22|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3675|22|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 14 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5722|3776|32|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5722|3776|32|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5722|3776|32|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5722|3776|32|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 15 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3876|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3876|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 16 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3975|21|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3975|21|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3975|21|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3975|21|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 17 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3676|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3676|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 18 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5621|3775|2|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5621|3775|2|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5621|3775|2|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5621|3775|2|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 19 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3875|15|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3875|15|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3875|15|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3875|15|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 20 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5624|3975|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5624|3975|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 21 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5523|3676|45|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5523|3676|45|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5523|3676|45|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5523|3676|45|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 22 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3775|8|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3775|8|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3775|8|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3775|8|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 23 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3875|-1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3875|-1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 24 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5478|3587|3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5478|3587|3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5478|3587|3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5478|3587|3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild3 +## +*|Forestostard|Ridablellama|||||5520|3939|42|2|5|10|25|25|1|3|3|0|0|0|0 +## +## T2AFrenz +## +*|Frenziedostard||||||5784|3951|20|2|5|10|35|35|1|8|0|0|0|0|0 +## +## T2ASpawner1 +## +*|Imp|Mongbat|||||5764|2585|-4|2|5|10|75|2|1|2|5|0|0|0|0 +*|Imp|Harpy|Headlessone|Scorpion|Stoneharpy|Wyvern|5838|2651|0|2|5|10|75|2|1|1|1|1|1|1|1 +## +## T2ASpawner2 +## +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5218|3786|1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5218|3786|1|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5371|3820|-2|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5371|3820|-2|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5368|3887|0|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5368|3887|0|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5367|4003|19|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5367|4003|19|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5466|4005|-1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5466|4005|-1|2|5|10|50|50|1|4|1|0|0|0|0 +## +## T2ABull +## +*|Bull|Greathart|Cow||||5194|3885|-1|2|5|10|45|32|1|10|6|6|0|0|0 +*|Bull|Greathart|Cow||||5200|3895|2|2|5|10|20|10|1|2|2|2|0|0|0 +## +## T2ASheep +## +*|Sheep|Goat|Bull|Chicken|||5159|3913|1|2|2|5|10|15|10|7|1|1|1|1|0|0 +## +## T2AFor1 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5570|3153|14|2|5|10|80|60|1|6|6|6|1|6|0 +## +## T2AFor2 +## +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5440|3292|-4|2|5|10|62|56|1|5|5|5|5|1|0 +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5566|3292|4|2|5|10|62|56|1|5|5|5|5|1|0 +## +## T2ATera1 +## +*|Terathanmatriarch|Terathanavenger|Terathandrone|Terathanwarrior|||5454|3136|-60|2|5|10|25|25|1|2|4|10|10|0|0 +## +## T2Aopp +## +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5490|3071|15|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5467|3078|-3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5446|3074|3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5432|3079|-4|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5408|3077|16|2|5|10|25|5|1|1|1|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/OrcCaves.map b/Data/Monsters/felucca/OrcCaves.map new file mode 100644 index 0000000..284bc39 --- /dev/null +++ b/Data/Monsters/felucca/OrcCaves.map @@ -0,0 +1,38 @@ +############## +## By Nerun ## +############## +overrideid 212 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Britain +## Orc Caves +## +## Cave 1 +## +*|Orc|Orccaptain|Orcishlord||||5146|1995|0|2|5|15|8|8|1|1|1|1|0|0|0 +*|Orc||||||5153|1971|0|2|5|15|8|8|1|5|0|0|0|0|0 +*|Direwolf||||||5153|1961|0|2|5|15|8|8|1|2|0|0|0|0|0 +*|Orcishlord||||||5144|1960|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain||||||5141|1968|0|2|5|15|8|8|1|3|0|0|0|0|0 +## +## Cave 2 +## +*|Orc||||||5332|1365|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Noble||||||5308|1372|0|2|5|15|8|8|1|1|0|0|0|0|0 +*|Orcishlord|Orc|||||5302|1355|0|2|5|15|12|8|1|1|3|0|0|0|0 +*|Giantrat||||||5316|1332|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Direwolf||||||5331|1346|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain|Orcishlord|Orcishmage|Orcbomber|||5354|1332|0|2|5|15|8|8|1|1|1|1|1|0|0 +*|Orcbomber|Orccaptain|Orc||||5356|1304|0|2|5|15|10|8|1|1|1|2|0|0|0 +*|Orcishlord|Orcishmage|Orcbomber|Orc|||5317|1309|0|2|5|15|8|8|1|1|2|1|2|0|0 +*|Orc|Orcishmage|Orcishlord||||5300|1314|0|2|5|15|10|8|1|3|1|2|0|0|0 +*|Corpser||||||5292|1316|0|2|5|15|8|8|1|2|0|0|0|0|0 +## +## Cave 3 +## +*|Orc||||||5281|2029|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orcbrute|Orc|||||5308|2005|0|2|5|15|12|12|1|1|4|0|0|0|0 +*|Orcbomber|Orc|||||5310|1969|0|2|5|15|12|12|1|2|2|0|0|0|0 +*|Orcbomber|Earthelemental|||||5348|2011|0|2|5|15|15|10|1|1|4|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Outdoors.map b/Data/Monsters/felucca/Outdoors.map new file mode 100644 index 0000000..92538a5 --- /dev/null +++ b/Data/Monsters/felucca/Outdoors.map @@ -0,0 +1,513 @@ +############## +## By Nerun ## +############## +overrideid 213 +overridemap 1 +overridemintime 60 +overridemaxtime 60 +## +## OSI Light +## +*|hordeminion||||||3619|2814|21|2|5|10|50|50|1|17|0|0|0|0|0 +*|mongbat||||||3619|2814|21|2|5|10|50|50|1|17|0|0|0|0|0 +*|lizardman:ratman||||||1147|3524|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1266|1982|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1249|2030|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1232|2093|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1140|2087|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1089|2033|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1067|2117|5|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:harpy:ogre:troll||||||666|1825|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||741|1838|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||733|1937|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||798|1935|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||819|1841|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||893|1861|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||879|1956|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:ogre||||||809|1615|0|2|60|80|30|30|1|6|0|0|0|0|0 +*|orcishmage||||||4461|3106|0|2|60|80|30|30|1|5|0|0|0|0|0 +*|orc||||||4729|3485|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4519|3097|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4613|3272|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4576|3356|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4658|3376|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4607|3480|29|2|60|80|30|30|1|10|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3485|2595|12|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3446|2741|49|2|60|80|50|50|1|7|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3459|2655|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3379|2693|35|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3411|2592|44|2|60|80|40|40|1|6|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3464|2503|49|2|60|80|50|50|1|7|0|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3168|629|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3172|700|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3173|771|0|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1473|229|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1337|293|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1184|217|27|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1284|433|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1203|502|30|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1300|607|15|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1200|633|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1162|704|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1130|830|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1013|980|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||848|917|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||840|1063|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1038|1149|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||844|1235|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||617|1326|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1831|449|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1832|517|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1749|474|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1636|532|22|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1743|589|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1887|591|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1810|647|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1631|650|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1723|683|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|earthelemental:ratman||||||1980|832|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1905|883|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1849|953|7|2|60|80|30|30|1|4|0|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||1001|787|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||987|725|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|gargoyle:gazer||||||1912|1283|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1787|1280|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1799|1394|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1652|1400|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1755|1474|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|troll||||||1325|1071|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2369|3430|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2354|3503|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2503|3593|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2520|3983|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2438|3914|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2143|3953|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|airelemental:gargoyle||||||868|488|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||805|483|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||839|406|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||841|344|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|lizardman:ratman||||||1131|3415|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1158|3457|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1094|3482|0|2|60|80|30|30|1|8|0|0|0|0|0 +############## +## By Nerun ## +############## +overridemintime 20 +overridemaxtime 20 +## +## OSI Medium +## +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1312|613|10|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1214|617|13|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|522|19|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1226|449|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1276|431|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1231|192|6|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1143|180|14|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1191|288|11|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1295|328|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|275|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1491|238|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3440|405|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|375|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3327|344|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3434|316|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|280|9|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3322|271|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3360|218|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3390|259|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3446|213|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3462|136|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2589|204|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|136|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2659|147|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2621|99|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|86|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2478|100|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2468|144|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2485|191|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2454|248|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2533|240|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|airelemental:ettin:orc||||||2077|434|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2107|358|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2138|323|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2189|298|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2137|271|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2113|221|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2146|178|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2093|147|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2109|109|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2115|48|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1996|73|8|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1956|48|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1944|102|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:troll||||||2034|46|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2033|74|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2058|87|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2034|108|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2000|141|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1965|160|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1946|186|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1922|173|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1894|197|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1908|214|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1891|226|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1869|265|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1626|266|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1682|252|6|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1723|252|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1759|259|21|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1804|247|0|2|20|30|30|30|1|2|11|0|0|0|0 +*|giantspider:scorpion||||||1875|906|7|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1829|874|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1852|841|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1930|864|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1883|827|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1949|824|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1987|822|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||2013|839|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1979|885|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1947|912|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1915|928|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1866|938|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1838|957|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1802|1506|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1692|1463|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1833|1245|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1726|1362|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1640|1431|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1912|1302|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1967|1296|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1898|1265|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1872|1347|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1812|1314|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1797|1393|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1862|1434|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1877|1515|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1361|1392|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1445|1365|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1375|1330|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1474|1297|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1407|1281|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1225|1477|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1222|1418|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1244|1374|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1180|1354|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1240|1317|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1340|1268|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1305|1326|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1304|1413|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1300|1481|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1541|1895|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1534|1941|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1475|1958|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1435|1917|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1383|1949|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1416|1992|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1504|2007|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1447|2038|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1479|2094|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1525|2053|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2095|2352|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2077|2305|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2021|2313|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1968|2346|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1947|2294|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1915|2385|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1891|2331|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1890|2270|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1873|2426|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1837|2334|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1826|2250|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2109|2989|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2089|3017|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2074|3069|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2033|3041|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1970|3052|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1915|3050|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1866|3040|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1812|3036|5|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1841|3000|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1803|2981|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1867|2962|7|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1849|2915|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1911|2934|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1954|2903|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||851|495|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||805|463|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||837|361|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1029|1969|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1080|1963|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1042|1920|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||821|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||736|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||899|1851|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||759|1828|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||672|1825|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||892|1963|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|giantspider:orc:ratman:spectre:zombie||||||815|1603|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1055|1442|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1021|1415|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1060|1375|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1004|1369|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1037|1325|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||971|1308|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||1000|330|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||964|365|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||947|418|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||956|452|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||423|1595|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||418|1665|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||480|1641|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||516|1585|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||541|1645|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||141|1367|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||189|1344|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||232|1350|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||278|1355|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||229|1419|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||182|1428|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||157|1487|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||204|1483|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||240|1443|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||269|1474|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4013|239|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3929|235|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3920|287|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4090|325|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4162|395|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4206|471|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3928|393|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3963|508|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4066|569|0|2|20|30|80|80|1|8|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4153|601|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4214|655|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4264|725|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2963|3617|3|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2966|3591|11|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3013|3591|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3024|3566|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3042|3590|5|2|20|30|30|30|1|7|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2462|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2428|722|8|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2375|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2345|676|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2429|690|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2379|654|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2326|656|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2319|591|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||659|1318|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||579|1305|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||728|1242|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||793|1088|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||849|1262|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||909|1175|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||974|1186|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1059|1166|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||823|960|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||960|910|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1042|1024|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1147|1048|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1097|970|2|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1192|958|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1166|818|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1083|783|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1268|774|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1180|737|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1122|718|1|2|20|30|30|30|1|11|1|0|0|0|0 +############## +## By Nerun ## +############## +overridemintime 5 +overridemaxtime 10 +## +## OSI Heavy + Miscellaneous +## +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||423|1595|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||418|1665|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||480|1641|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||516|1585|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||541|1645|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4504|1458|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4494|1426|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1434|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4456|1405|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1358|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|greathart|hind|||||4550|1409|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4552|1447|10|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4615|1469|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4612|1418|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4605|1365|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4566|1359|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2372|210|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2355|179|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2351|148|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2345|112|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2328|67|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2177|3034|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2143|3068|20|2|5|10|30|30|1|7|0|0|0|0|0 +## +## Northeast Britain +## +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1983|1517|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1986|1463|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1969|1409|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|mongbat|orc|||||1912|1302|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1967|1296|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1898|1265|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1872|1347|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1812|1314|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1797|1393|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1862|1434|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1877|1515|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1802|1506|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1692|1463|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1833|1245|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1726|1362|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1640|1431|0|2|5|10|30|30|1|3|2|0|0|0|0 +## +## Orc Cave Entrance +## +*|orc:ratman||||||1055|1442|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1021|1415|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1060|1375|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1004|1369|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1037|1325|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||971|1308|0|2|5|10|30|30|1|6|0|0|0|0|0 +## +## Orc Fort (South Cove) +## +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2171|1356|0|2|5|10|30|30|1|1|3|2|5|3|2 +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2184|1376|0|2|5|10|30|15|1|1|3|2|5|3|2 +*|TreasureLevel2|TreasureLevel3|||||2155|1370|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2203|1379|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## The Bog of Desolation (West Covetous) +## +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2038|1023|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2079|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2067|989|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2028|987|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2033|936|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1990|976|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1993|1030|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2035|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2023|1052|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2069|1028|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2048|1066|0|2|5|10|30|30|1|3|1|3|0|0|0 +## +## East Skara Brae +## +*|orc|ettin|ratman|giantspider|reaper||1435|2261|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1651|2413|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1619|2725|10|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1427|2525|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1059|2461|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1243|2437|5|2|5|10|150|150|1|10|10|10|10|10|0 +## +## East Skara Brae: Hedge Maze +## +*|Daemon||||||1145|2231|20|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1072|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1070|2256|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1215|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1216|2259|5|2|5|10|30|20|1|4|0|0|0|0|0 +## +## South Destard / Trinsic +## +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1595|3045|0|2|5|10|100|60|1|5|5|5|5|5|5 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|2091|3413|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1931|3205|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1827|3429|10|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1635|3253|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1387|3109|0|2|5|10|150|150|1|10|10|10|10|10|10 +## +## Main Destard Orcs +## +*|Headlessone|Orc|Orccaptain|Orcishlord|Orcishmage||1110|2672|0|2|5|10|20|20|1|3|6|1|2|1|0 +## +## The Destard Swamps +## +*|Toxicelemental:Alligator:Bogthing:Bogling:Corpser:GiantRat:Giantserpent|Lizardman:strongmongbat:Plaguebeast:Plaguespawn:Ratman:Sewerrat:Snake|Wisp||||1158|2872|0|2|5|10|130|130|1|24|23|3|0|0|0 +*|Savage|Savagerider|Savageshaman||||1141|2959|0|2|5|10|20|20|1|2|1|1|0|0|0 +*|Savage|Savagerider|Savageshaman||||1166|2958|0|2|5|10|20|20|1|2|1|1|0|0|0 +## +## Yew-Britain Brigand Camp +## +*|Brigand||||||854|1686|0|2|1|10|20|15|1|7|0|0|0|0|0 +## +## Yew Liches +## +*|Lich||||||757|1401|0|2|1|10|30|30|1|8|0|0|0|0|0 +## +## Yew Orc Fort +## +*|Orc|Orcishlord|Orcishmage||||634|1504|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcishlord|Orcishmage||||634|1462|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcbomber|Orccaptain|Orcishlord|Orcishmage||633|1484|0|2|1|10|20|10|1|8|1|1|2|2|0 +## +## Yew Fort of the Damned +## +*|Skeleton||||||965|757|0|2|5|10|10|5|1|2|0|0|0|0|0 +*|Wraith:Shade:Spectre|Ghoul|||||955|707|0|2|5|10|12|8|1|4|4|0|0|0|0 +*|Wraith:Shade:Spectre||||||962|692|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Wraith:Shade:Spectre||||||948|703|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Lich||||||1016|821|0|2|5|10|10|2|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||1015|706|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||1017|826|0|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Hythloth Fire Pit +## +*|Daemon|Drake|||||4596|3607|30|2|5|10|50|25|1|1|2|0|0|0|0 +*|Dragon|Drake|||||4571|3572|31|2|1|10|50|25|1|1|2|0|0|0|0 +*|Daemon||||||4595|3574|75|2|1|10|50|25|1|3|0|0|0|0|0 +*|Dragon|Drake|||||4618|3570|30|2|1|10|50|25|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||4595|3570|30|2|1|2|8|8|1|3|3|0|0|0|0 +## +## Near Shame: The Wisp Circle +## +*|Wisp||||||608|1702|0|2|5|10|30|30|1|8|0|0|0|0|0 +## +## Moonglow Zoo +## +*|Ghoul|Giantrat|Giantserpent|Headlessone|Jwilson||4530|1387|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Iceserpent|Icesnake|Polarbear|Snowleopard|Whitewolf|Frostooze|4511|1394|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Frostspider|Frosttroll|||||4511|1394|23|2|5|10|10|4|1|1|4|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Rabbit:JackRabbit|Cougar:Panther|Bird:Eagle||4498|1394|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Corpser|Swamptentacle|||4485|1387|23|2|5|10|15|4|1|2|3|1|1|0|0 +*|Giantserpent|Giantspider|Boar|Greathart|Hind|Llama|4493|1364|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Horse|Rat|||||4493|1364|23|2|5|10|10|4|1|1|1|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Cougar:Panther|Giantserpent|Greathart||4506|1358|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Gorilla|Giantserpent|Gianttoad||4519|1358|23|2|5|10|15|4|1|1|1|1|1|1|0 +*|Mummy|Ophidianwarrior|Scorpion|Giantserpent|||4531|1363|23|2|5|10|15|4|1|1|1|1|1|0|0 +*|Rottingcorpse|Skeleton|Slime|Snake|Strongmongbat||4512|1372|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Ghoul|Giantserpent|Headlessone|Jwilson|Zombie||4512|1380|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Cat|Chicken|Dog|Pig|Sheep||4500|1382|23|2|5|10|10|1|1|1|1|1|1|1|0 +############## +## By Nerun ## +############## +overridemintime 45 +overridemaxtime 60 +## +## Camps +## +*|Orccamp:Ratcamp||||||821|675|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1042|1394|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2540|130|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3170|672|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2548|1173|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3602|2815|28|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||4480|1439|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1152|3471|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1530|999|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1871|1076|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||788|1894|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1064|2488|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2103|3371|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2044|2323|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1939|1310|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2349|722|0|2|45|60|10|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/PaintedCaves.map b/Data/Monsters/felucca/PaintedCaves.map new file mode 100644 index 0000000..e653fa6 --- /dev/null +++ b/Data/Monsters/felucca/PaintedCaves.map @@ -0,0 +1,13 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 214 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Painted Caves +## +*|cat:dog:rat|cat|dog|rat|||6279|879|-1|1|5|10|30|30|1|6|1|1|1|0|0 +*|troglodyte|grobu|lurg|giantrat|||6275|879|-2|1|5|10|30|30|1|3|3|3|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/PalaceOfParoxysmus.map b/Data/Monsters/felucca/PalaceOfParoxysmus.map new file mode 100644 index 0000000..02b1768 --- /dev/null +++ b/Data/Monsters/felucca/PalaceOfParoxysmus.map @@ -0,0 +1,25 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 215 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Palace of Paroxysmus +## +*|daemon:succubus|InterredGrizzle:poisonelemental|plaguebeast:plaguespawn|corrosiveslime|putrifier|plaguebeastlord|6295|616|-50|1|5|10|50|50|1|6|6|6|3|3|3 +*|InterredGrizzle|corrosiveslime|poisonelemental|balron:succubus:daemon|plaguebeastlord:plaguebeast:plaguespawn||6384|580|-50|1|5|10|30|30|1|4|4|3|9|11|0 +*|poisonelemental||||||6328|517|-50|1|5|10|10|10|1|4|0|0|0|0|0 +*|plaguebeast:corrosiveslime|poisonelemental:plaguespawn|||||6354|455|-40|1|5|10|20|20|1|5|5|0|0|0|0 +*|plaguebeast:plaguespawn|toxicelemental:corrosiveslime|||||6416|447|-40|1|5|10|20|20|1|8|7|0|0|0|0 +*|balron:succubus:daemon|corrosiveslime|plaguebeastlord:plaguebeast:plaguespawn|InterredGrizzle:poisonelemental|||6466|543|-50|1|5|10|30|30|1|6|3|8|5|0|0 +*|chaosdaemon:moloch|succubus:daemon|balron||||6292|462|-50|1|5|10|40|40|1|7|7|4|0|0|0 +*|earthelemental:corrosiveslime||||||6298|395|60|1|5|10|8|8|1|2|0|0|0|0|0 +*|toxicelemental:plaguespawn|toxicelemental|plaguespawn||||6404|378|-40|1|5|10|18|18|1|2|1|1|0|0|0 +*|plaguespawn:plaguebeast:toxicelemental:corrosiveslime:poisonelemental|plaguespawn|plaguebeast|toxicelemental|corrosiveslime|poisonelemental|6418|358|-40|1|5|10|25|25|1|12|2|2|2|2|2 +*|earthelemental:corrosiveslime:toxicelemental:plaguespawn|earthelemental|corrosiveslime|toxicelemental|plaguespawn||6319|348|60|1|5|10|20|20|1|5|1|1|1|1|0 +*|toxicelemental:earthelemental:corrosiveslime|toxicelemental|earthelemental|corrosiveslime|||6249|352|60|1|5|10|15|15|1|6|1|1|1|0|0 +*|poisonelemental||||||6285|353|60|1|5|10|5|5|1|1|0|0|0|0|0 +*|earthelemental:corrosiveslime||||||6353|400|60|1|5|10|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/PrismOfLight.map b/Data/Monsters/felucca/PrismOfLight.map new file mode 100644 index 0000000..13f54d4 --- /dev/null +++ b/Data/Monsters/felucca/PrismOfLight.map @@ -0,0 +1,32 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 216 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Prism of Light +## +*|CrystalLatticeSeeker||||||6553|157|0|1|5|10|8|8|1|3|0|0|0|0|0 +*|Rat:Icesnake||||||6474|74|-34|1|5|10|4|4|1|9|0|0|0|0|0 +*|wisp:CrystalWisp:treasurelevel2|treasurelevel2|||||6552|155|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|wisp||||||6521|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|wisp||||||6530|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalSeaSerpent||||||6576|91|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|UnfrozenMummy||||||6509|176|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalDaemon||||||6536|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalDaemon||||||6547|91|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalHydra||||||6572|89|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|treasurelevel4||||||6504|181|0|1|5|10|1|1|1|1|0|0|0|0|0 +*|ShadowWisp||||||6475|101|-44|1|5|10|5|5|1|5|0|0|0|0|0 +*|wisp:Crystalwisp||||||6478|174|4|1|5|10|10|10|1|6|0|0|0|0|0 +*|Crystalvortex:iceelemental||||||6566|120|0|1|5|10|15|15|1|7|0|0|0|0|0 +*|CrystalWisp||||||6534|178|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalWisp:CrystalLatticeSeeker:treasurelevel2|treasurelevel2|||||6535|179|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|treasurelevel3||||||6502|120|-10|1|5|10|0|0|1|1|0|0|0|0|0 +*|protector||||||6507|151|0|1|5|10|5|5|1|3|0|0|0|0|0 +*|CrystalDaemon||||||6532|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|Ferret||||||6578|183|31|1|5|10|5|5|1|2|0|0|0|0|0 +*|protector||||||6510|171|0|1|5|10|8|8|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Reagents.map b/Data/Monsters/felucca/Reagents.map new file mode 100644 index 0000000..8a02538 --- /dev/null +++ b/Data/Monsters/felucca/Reagents.map @@ -0,0 +1,70 @@ +############## +## By Nerun ## +############## +overrideid 229 +overridemap 1 +overridemintime 11 +overridemaxtime 23 +## +## Felucca Reagents +## +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2854|816|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4590|1448|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2490|1096|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1566|1140|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1514|1584|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1938|1408|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2374|652|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2054|516|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1286|504|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||746|636|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1134|964|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||718|1180|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||342|1464|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||702|1752|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1114|1416|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1150|1876|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1582|2028|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1934|2328|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1490|2472|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1070|2320|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1466|3032|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2062|964|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1846|3260|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1078|2772|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4710|3796|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5926|3888|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5474|3904|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5934|3436|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5462|3452|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5674|3120|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5618|2744|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5326|2492|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5966|2456|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5234|3068|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||6042|2916|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3602|2948|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3538|2536|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2734|2168|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3714|2152|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3674|1216|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3994|328|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4166|584|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3198|504|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2750|368|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1694|688|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||366|900|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||642|2216|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2226|3532|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1850|2796|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1658|236|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4426|1028|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2522|84|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3130|116|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2082|60|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2930|3476|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1410|3796|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1122|3524|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2474|3956|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4570|3340|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4282|3700|0|1|11|23|200|200|1|160|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Sanctuary.map b/Data/Monsters/felucca/Sanctuary.map new file mode 100644 index 0000000..1dc8030 --- /dev/null +++ b/Data/Monsters/felucca/Sanctuary.map @@ -0,0 +1,19 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 217 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Sanctuary +## +*|chicken:bird|dog|cat|cow:bull|pig|boar|6263|118|-10|1|5|10|20|20|1|6|3|3|6|3|3 +*|ratman:ratmanarcher:chiikkaha:titan:cyclops:rat|ratman:ratmanarcher|chiikkaha|titan|cyclops|rat|6349|89|-20|1|5|10|70|70|1|18|4|2|2|2|2 +*|ratman:ratmanarcher:ratmanmage:changeling:doppleganger|dog:chicken:cat:boar:bird|gargoyle|titan|cyclops|orcishmage:orcscout|6168|117|0|1|5|10|30|30|1|11|9|3|3|3|5 +*|ogrelord:orcishlord:ratman|bird:cow:bull:pig:chicken|||||6189|71|0|1|5|10|25|25|1|8|4|0|0|0|0 +*|titan:ettin:doppleganger:mougguur|dog:chicken:rat:cow:bull|orcbomber:orcbrute:orc|snake:gargoyle:ogre|||6187|101|0|1|5|10|25|25|1|10|10|7|7|0|0 +*|bird:chicken:rat:dog|doppleganger|||||6184|29|0|1|5|10|10|10|1|6|3|0|0|0|0 +*|szavetra:imp:titan:snake:ratman:doppleganger:gargoyle|cow:bull:chicken:bird:pig:dog:goat:cat:rat|orc:orccaptain:orcishmage|ogre:ogre:ogrelord|||6265|48|-10|1|5|10|30|30|1|22|18|9|4|0|0 +*|changeling:ratman:ettin:titan:ratmanarcher:ratmanmage|goat:pig:cow:bull:rat|gargoyleenforcer:gargoyledestroyer:gargoyle|snake|||6191|155|0|1|5|10|25|25|1|18|12|9|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/SeaLife.map b/Data/Monsters/felucca/SeaLife.map new file mode 100644 index 0000000..d04a9eb --- /dev/null +++ b/Data/Monsters/felucca/SeaLife.map @@ -0,0 +1,124 @@ +############## +## By Nerun ## +############## +overrideid 218 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1395|3421|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4888|375|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4352|215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3688|439|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4512|583|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|1127|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3576|823|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4016|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3992|1447|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4232|1655|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4600|1751|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|1519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3616|1807|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4032|2039|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4624|2199|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4400|2527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3984|2423|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|2119|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4912|2471|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4864|2831|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4536|2847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|3215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4192|2975|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4008|2767|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3328|2063|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3176|2383|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3088|2759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3888|3167|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4152|3415|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3968|3895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3240|3151|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3776|3519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3344|3479|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2792|2951|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2608|3295|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2744|2567|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2368|2799|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3560|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3168|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2768|3847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1720|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||544|3719|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||896|3695|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||824|3287|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||176|3551|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||480|3351|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||512|2919|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||192|2895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||208|2503|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||840|2863|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||600|2511|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|2103|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||168|1743|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|559|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||184|191|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||592|223|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2400|2399|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3008|1895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2392|2031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2624|1775|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3408|1407|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3256|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2952|1239|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2752|1455|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2208|1703|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1866|1798|-5|2|5|10|175|175|1|15|6|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||931|141|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3267|1717|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2395|1405|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||139|1173|-5|2|5|10|130|130|1|13|4|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3123|1485|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3811|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3931|1757|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2931|3245|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2291|3181|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||979|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||147|3213|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1891|3597|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2971|1605|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1580|75|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4275|1309|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4667|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||5003|101|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3603|125|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4112|791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3891|733|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3672|1535|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4363|1981|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4995|1829|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4283|2221|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2008|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2320|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4955|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4731|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4307|3965|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2227|3533|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1187|3885|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||731|3989|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||491|4013|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||107|909|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1792|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1336|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4048|63|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4392|823|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3520|2263|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3568|3215|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4992|3791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4984|3567|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2072|2527|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2040|3751|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2288|3767|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|1879|-5|2|5|10|100|100|1|10|2|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Shame.map b/Data/Monsters/felucca/Shame.map new file mode 100644 index 0000000..a155cbd --- /dev/null +++ b/Data/Monsters/felucca/Shame.map @@ -0,0 +1,135 @@ +############## +## By Nerun ## +############## +overrideid 219 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Shame Dungeon +## +## Level 1 +## +*|Earthelemental|Scorpion|||||5404|93|10|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5425|58|10|2|5|10|30|30|1|7|3|0|0|0|0 +*|Earthelemental|Scorpion|||||5387|41|20|2|2|10|30|30|1|4|1|0|0|0|0 +*|Earthelemental||||||5394|11|30|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental||||||5474|20|0|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental|Scorpion|||||5477|67|20|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5468|109|35|2|2|10|30|30|1|6|20|0|0|0|0 +*|TreasureLevel1||||||5423|112|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5468|106|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5434|100|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5492|56|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5416|59|-15|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5400|45|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5448|33|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5437|11|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5399|11|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5421|117|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5468|100|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5392|10|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5445|12|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5404|43|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5443|36|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5402|58|-20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5493|51|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5434|89|20|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Airelemental||||||5575|16|10|2|2|10|30|15|1|3|0|0|0|0|0 +*|Dullcopperelemental||||||5615|18|10|2|2|10|30|15|1|6|0|0|0|0|0 +*|Airelemental||||||5568|36|0|2|2|10|30|15|1|3|0|0|0|0|0 +*|Airelemental|Waterelemental|||||5549|60|0|2|2|10|30|15|1|3|2|0|0|0|0 +*|Kraken|Waterelemental|||||5549|79|0|2|2|10|30|10|1|1|3|0|0|0|0 +*|Kraken|Seaserpent|||||5595|82|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Dullcopperelemental||||||5603|93|0|2|2|10|25|12|1|2|0|0|0|0|0 +*|Dullcopperelemental||||||5603|116|0|2|2|10|30|15|1|4|0|0|0|0|0 +*|TreasureLevel1||||||5536|119|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5546|118|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5606|25|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5570|118|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5620|21|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5572|113|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5546|113|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Earthelemental||||||5474|139|20|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental|Poisonelemental|||||5477|183|0|2|2|10|30|15|1|1|4|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5469|211|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Evilmage|Evilmagelord|||||5441|187|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Airelemental|Earthelemental|||||5412|164|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5411|163|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental|Earthelemental|||||5412|201|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5412|200|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental||||||5394|230|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Eldergazer||||||5505|180|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Dullcopperelemental|Fireelemental|||||5527|210|0|2|2|10|30|15|1|4|2|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5557|222|0|2|2|10|25|10|1|2|2|3|0|0|0 +*|Evilmage|Evilmagelord|||||5577|194|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5594|182|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Earthelemental|Scorpion|||||5571|158|-10|2|2|10|30|15|1|4|2|0|0|0|0 +*|Earthelemental|Fireelemental|||||5593|141|10|2|2|10|30|15|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5398|148|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5545|153|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5594|139|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5604|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5608|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5605|202|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5439|137|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5390|145|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5456|157|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5410|170|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5415|189|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5396|226|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5553|146|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5595|147|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5615|173|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5616|184|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5456|143|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5432|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5474|176|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5406|177|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|185|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|200|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5403|235|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5475|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Airelemental||||||5875|44|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental||||||5856|107|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Airelemental||||||5845|57|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Kraken|Seaserpent|||||5828|42|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Evilmage|Evilmagelord|||||5819|50|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Eldergazer||||||5818|80|0|2|2|10|30|10|1|2|0|0|0|0|0 +*|Airelemental||||||5804|12|0|2|2|10|30|15|1|5|0|0|0|0|0 +*|Bloodelemental||||||5721|12|10|2|2|10|30|15|1|8|0|0|0|0|0 +*|Fireelemental||||||5661|16|-10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental||||||5649|101|10|2|2|10|30|15|1|4|0|0|0|0|0 +*|Bloodelemental||||||5684|117|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental|Fireelemental|||||5724|118|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Toxicelemental|Fireelemental|Scorpion||||5760|99|0|2|2|10|30|15|1|2|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5711|97|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5752|44|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Waterelemental|||||5708|43|0|2|2|10|25|10|1|1|3|0|0|0|0 +*|TreasureLevel1||||||5730|90|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5723|73|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5715|61|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5701|60|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5817|83|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5730|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5717|60|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5699|61|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5817|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5733|91|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5725|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|58|2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5698|57|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5733|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5727|72|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5717|58|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5701|58|2|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/SolenHive.map b/Data/Monsters/felucca/SolenHive.map new file mode 100644 index 0000000..7c5ad5f --- /dev/null +++ b/Data/Monsters/felucca/SolenHive.map @@ -0,0 +1,92 @@ +############## +## By Nerun ## +############## +overrideid 220 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Solen Hive Dungeon +## +## AREA A - Yew Lich Ruins (731 1452 0) +## +## Level 1 +## +*|Blacksolenworker||||||5670|1807|4|2|5|10|30|25|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5673|1846|1|2|5|10|20|6|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5693|1834|0|2|5|10|20|4|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5704|1807|4|2|5|10|20|6|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5722|1820|5|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Blacksolenwarrior||||||5709|1874|1|2|5|10|50|10|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5681|1886|2|2|5|10|50|10|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5756|1857|4|2|5|10|50|10|1|1|0|0|0|0|0 +## +## AREA B - Between Minoc/Covetous (2609 764 0) +## +## Level 1 +## +*|Blacksolenworker||||||5912|1800|1|2|5|10|30|20|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5920|1842|1|2|5|10|30|15|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Antlion||||||5887|1840|-18|2|5|10|25|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5847|1819|1|2|5|10|25|10|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5829|1798|1|2|5|10|15|10|1|1|0|0|0|0|0 +*|Blacksolenworker|Blacksolenqueen|||||5873|1798|0|2|5|10|15|10|1|2|1|0|0|0|0 +*|Blacksolenwarrior||||||5782|1793|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5799|1857|5|2|5|10|20|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5815|1881|2|2|5|10|20|7|1|1|0|0|0|0|0 +*|Beetle||||||5831|1910|3|2|5|10|15|10|1|2|0|0|0|0|0 +## +## AREA C - West Trinsic Main Gate (1691 2790 0) +## +## Level 1 +## +*|Blacksolenworker||||||5718|2024|4|2|5|10|25|15|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5776|2019|2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Antlion||||||5782|2021|-11|2|5|10|25|10|1|1|0|0|0|0|0 +*|Dreadspider||||||5767|1962|2|2|5|10|50|15|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5671|1979|0|2|5|10|30|20|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5703|1991|0|2|5|10|35|20|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Blacksolenwarrior||||||5699|1921|2|2|5|10|30|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5748|1923|0|2|5|10|20|5|1|1|0|0|0|0|0 +*|Blacksolenqueen|Blacksolenworker|||||5736|1939|7|2|5|10|20|10|1|1|2|0|0|0|0 +## +## AREA D - South Chaos/Compassion Road (1725 815 0) +## +## Level 1 +## +*|Blacksolenworker||||||5876|2018|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5856|2018|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5838|2019|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5910|1991|0|2|5|10|25|15|1|3|0|0|0|0|0 +*|Beetle||||||5837|1992|-2|2|5|10|15|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5863|1958|2|2|5|10|25|10|1|2|0|0|0|0|0 +*|Antlion||||||5884|1920|-15|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Blacksolenworker||||||5825|1968|4|2|5|10|25|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5855|1932|3|2|5|10|20|10|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5798|1963|0|2|5|10|35|10|1|2|0|0|0|0|0 +## +## AREA E - GreenThorn/Desert Entrance +## +*|Antlion||||||5665|1868|11|2|5|10|20|10|1|3|0|0|0|0|0 +*|Antlion||||||5707|1843|-15|2|5|10|10|10|1|1|0|0|0|0|0 +## +## INFILTRATORS +## +## Windemere +*|redsoleninfiltratorqueen|redsoleninfiltratorwarrior|||||3218|502|0|2|5|10|10|10|1|1|2|0|0|0|0 +## Trinsic +*|redsoleninfiltratorqueen|redsoleninfiltratorwarrior|||||1940|3261|1|2|5|10|10|10|1|1|2|0|0|0|0 +## Wind +*|redsoleninfiltratorqueen|redsoleninfiltratorwarrior|||||1361|894|0|2|5|10|8|4|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/TerathanKeep.map b/Data/Monsters/felucca/TerathanKeep.map new file mode 100644 index 0000000..44d2216 --- /dev/null +++ b/Data/Monsters/felucca/TerathanKeep.map @@ -0,0 +1,62 @@ +############## +## By Nerun ## +############## +overrideid 221 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Lost Lands +## Terathan Keep Dungeon +## +## Terathan Keep +## +*|Balron|Dragon|Drake|Nightmare|||5296|1561|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5296|1562|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5297|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5342|1553|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5342|1552|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5343|1551|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5334|1613|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5334|1614|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5335|1615|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5348|1552|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5345|1551|0|2|1|2|1|1|1|2|0|0|0|0|0 +## +## Ophidian Territory +## +*|Balron|Dragon|Drake|Nightmare|||5344|1757|-125|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5345|1757|-125|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5346|1756|-125|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5335|1706|-70|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5335|1707|-70|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5336|1708|-70|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5270|1695|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5270|1694|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5271|1693|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5365|1707|-71|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5363|1709|-75|2|1|2|1|1|1|2|0|0|0|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5176|1702|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5176|1701|2|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5177|1700|1|2|5|15|20|10|1|1|1|1|1|0|0 +## +## Champion Room +## +*|Balron|Dragon|Drake|Nightmare|||5132|1624|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5132|1623|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5134|1625|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5160|1586|-15|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5163|1585|-15|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5161|1584|-15|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5200|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5201|1566|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5200|1568|0|2|5|15|20|10|1|1|1|1|1|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/TownsLife.map b/Data/Monsters/felucca/TownsLife.map new file mode 100644 index 0000000..a3e6ee4 --- /dev/null +++ b/Data/Monsters/felucca/TownsLife.map @@ -0,0 +1,172 @@ +############## +## By Nerun ## +############## +overrideid 222 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Towns +## +## ----Mainland---- +## +## Wind +## +*|dragon|drake|||||5249|228|15|2|5|10|20|20|1|1|2|0|0|0|0 +*|lichlord|lich|||||5164|205|15|2|5|10|15|15|1|1|2|0|0|0|0 +*|daemon||||||5133|150|0|2|5|10|15|15|1|3|0|0|0|0|0 +## +## Britain Town +## +*|Bird|Cat|Dog|Rat|||1550|1658|26|2|5|15|120|120|1|15|15|15|15|0|0 +*|Cow||||||1319|1810|0|2|5|10|10|5|1|7|0|0|0|0|0 +*|Cow||||||1319|1821|0|2|5|10|10|5|1|7|0|0|0|0|0 +## ------------------- +## +## Britain Farm 1 +## +*|Bird|Cat|Dog|Rat|||1340|1790|15|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1339|1788|15|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 2 +## +*|Bird|Cat|Dog|Rat|||1217|1825|0|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1216|1823|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 3 +## +*|Bird|Cat|Dog|Rat|||1186|1633|0|2|5|15|80|80|1|7|7|7|7|0|0 +*|Chicken||||||1185|1632|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Trinsic Town +## +*|Bird|Cat|Dog|Rat|||1937|2760|10|2|5|15|120|120|1|12|12|12|12|0|0 +## +## Skara Brae Town +## +*|Bird|Cat|Dog|Rat|||608|2195|0|2|5|15|70|70|1|8|8|8|8|0|0 +*|Chicken:Sheep:Cow||||||813|2164|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||818|2269|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||830|2353|0|2|5|15|15|10|1|3|0|0|0|0|0 +## +## Yew Town +## +*|Bird|Cat|Dog|Rat|||536|962|0|2|5|15|160|160|1|20|20|20|20|0|0 +*|Sheep||||||676|1178|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||570|1099|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||675|939|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Chicken||||||382|1192|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||560|1239|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||688|1007|0|2|5|10|10|10|1|2|0|0|0|0|0 +## +## Cove Town +## +*|Bird|Cat|Dog|Rat|||2242|1197|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken||||||2223|1151|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## Vesper Town 1 +## +*|Bird|Cat|Dog|Rat|||2939|746|2|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Vesper Town 2 +## +*|Bird|Cat|Dog|Rat|||2904|906|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Minoc Town 1 +## +*|Bird|Cat|Dog|Rat|||2481|542|0|2|5|15|70|70|1|5|5|5|5|0|0 +## +## Minoc Town 2 +## +*|Bird|Cat|Dog|Rat|||2472|434|15|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Minoc Town 3 +## +*|Bird|Cat|Dog|Rat|||2566|622|0|2|5|15|50|50|1|3|3|3|3|0|0 +## +## ----Islands---- +## +## Jhelom Town 1 +## +*|Bird|Cat|Dog|Rat|||1154|3639|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken:Cow:Sheep||||||1127|3583|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken:Cow:Sheep||||||1183|3607|0|2|5|10|10|10|1|5|0|0|0|0|0 +## +## Jhelom Town 2 +## +*|Bird|Cat|Dog|Rat|||1400|3775|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Jhelom Town 3 +## +*|Bird|Cat|Dog|Rat|||1435|4000|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Serpents Hold Town +## +*|Bird|Cat|Dog|Rat|||2972|3436|15|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Haven/Occlo Town 1 +## +*|Bird|Cat|Dog|Rat|||3674|2624|0|2|5|15|80|80|1|10|10|10|10|0|0 +*|Chicken||||||3726|2647|0|2|5|10|25|25|1|10|0|0|0|0|0 +## +## Haven/Occlo Town 2 +## +*|Bird|Cat|Dog|Rat|||3652|2511|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Magincia Town 1 +## +*|Bird|Cat|Dog|Rat|||3714|2205|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Magincia Town 2 +## +*|Bird|Cat|Dog|Rat|||3717|2111|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Buccaneers Den Town 1 +## +*|Bird|Cat|Dog|Rat|||2682|2118|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Buccaneers Den Town 2 +## +*|Bird|Cat|Dog|Rat|||2687|2218|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Nujel'm Town +## +*|Bird|Cat|Dog|Rat|||3699|1238|0|2|5|15|160|160|1|18|18|18|18|0|0 +## +## Moonglow Town +## +*|Bird|Cat|Dog|Rat|||4438|1115|0|2|5|15|70|70|1|12|12|12|12|0|0 +*|Chicken:Cow:Sheep||||||4634|1302|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken||||||4567|1476|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Chicken||||||4422|1451|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## Heartwood +## +*|bird||||||7036|409|12|2|5|10|12|12|1|3|0|0|0|0|0 +*|bird||||||7048|424|0|2|5|10|20|20|1|5|0|0|0|0|0 +*|bird||||||7081|381|0|2|5|10|12|12|1|3|0|0|0|0|0 +*|bird||||||7002|382|0|2|5|10|20|12|1|5|0|0|0|0|0 +*|bird||||||6999|352|0|2|5|10|12|12|1|3|0|0|0|0|0 +*|bird||||||7047|382|0|2|5|10|12|12|1|5|0|0|0|0|0 +*|Bird||||||7033|385|0|1|5|10|50|50|1|10|0|0|0|0|0 +*|MiniatureMushroom||||||7032|411|7|1|5|10|10|10|1|4|0|0|0|0|0 +*|MiniatureMushroom||||||7044|429|0|1|5|10|10|10|1|4|0|0|0|0|0 +*|MiniatureMushroom||||||6986|384|0|1|5|10|10|10|1|4|0|0|0|0|0 +*|MiniatureMushroom||||||7063|410|0|1|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7052|386|0|1|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7035|387|0|1|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7007|382|0|1|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7087|382|1|1|5|10|10|10|1|2|0|0|0|0|0 +*|MiniatureMushroom||||||6992|345|0|1|5|10|10|10|1|2|0|0|0|0|0 +*|MiniatureMushroom||||||7007|360|0|1|5|10|10|10|1|2|0|0|0|0|0 +## +## ----Lostlands---- +## +## Papua Town +## +*|Bird|Cat|Dog|Rat|||5726|3211|-2|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Delucia Town +## +*|Bird|Cat|Dog|Rat|||5255|4000|37|2|5|15|80|80|1|6|6|6|6|0|0 +*|Chicken:Sheep:Cow:Bull||||||5267|4012|40|2|5|10|15|15|1|5|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/TownsPeople.map b/Data/Monsters/felucca/TownsPeople.map new file mode 100644 index 0000000..45c7e44 --- /dev/null +++ b/Data/Monsters/felucca/TownsPeople.map @@ -0,0 +1,75 @@ +############## +## By Nerun ## +############## +overrideid 223 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Britain Chaos/Order Guards +## +*|Orderguard||||||1400|1623|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Orderguard||||||1400|1628|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1521|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1525|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +## +## Town Criers +## +*|Towncrier||||||1662|1611|19|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1421|1698|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2254|1207|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5290|3987|37|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3652|2619|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1330|3778|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3721|2161|20|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2515|557|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||4451|1153|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3773|1308|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5685|3148|-4|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2891|3474|15|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||603|2141|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1914|2687|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1829|2811|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2895|686|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||627|864|0|2|5|10|5|1|1|1|0|0|0|0|0 +## +## Hire +## +*|HireBard:HireBardArcher:HireBeggar:HireFighter:HireMage|HireRanger:HireRangerArcher:HireSailor:HireThief:HirePaladin|||||1399|3743|-21|2|5|15|10|10|1|5|5|0|0|0|0 +## +## Escorts +## +*|Escortablemage:Seekerofadventure:Noble||||||1483|1760|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1372|3916|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1126|3688|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3674|2291|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||4398|1049|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3815|1217|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3749|1404|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3645|2661|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2994|3451|16|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||673|2235|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||573|2246|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2068|2854|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3041|827|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||631|883|0|2|5|15|20|10|1|3|0|0|0|0|0 +## +## Treasures +## +## Trinsic Bank +*|TreasureLevel3|TreasureLevel4|||||1813|2834|0|2|1|2|2|2|1|1|2|0|0|0|0 +## Vesper Bank +*|TreasureLevel1||||||2875|675|0|2|1|2|2|2|1|6|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||2874|692|0|2|1|2|1|1|1|1|1|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2884|692|0|2|1|2|1|1|1|2|1|0|0|0|0 +## +## Heartwood +## +*|olaeni||||||7082|367|0|2|5|10|4|4|1|1|0|0|0|0|0 +*|bolaevin|bird|||||7063|350|0|2|5|10|4|4|1|1|2|0|0|0|0 +*|athialon||||||7010|363|0|2|5|10|8|8|1|1|0|0|0|0|0 +*|abbein|taellia|vicaie|mallew|jothan|alethanian|7048|382|0|2|5|10|12|12|1|1|1|1|1|1|1 +*|tyeelor||||||6989|342|0|2|5|10|8|8|1|1|0|0|0|0|0 +*|aneen|bird|||||7053|338|0|2|5|10|6|6|1|1|1|0|0|0|0 +*|alelle|daelas|||||7031|409|7|2|5|10|10|10|1|1|1|0|0|0|0 +*|aluniol|rebinil|||||7090|387|0|2|5|10|8|8|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/TrinsicPassage.map b/Data/Monsters/felucca/TrinsicPassage.map new file mode 100644 index 0000000..745f3b1 --- /dev/null +++ b/Data/Monsters/felucca/TrinsicPassage.map @@ -0,0 +1,18 @@ +############## +## By Nerun ## +############## +overrideid 224 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Do not exist spiderlord, then i did 2 dreadspiders per block +## +## Trinsic Passage +## +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5976|1387|-22|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5940|1356|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5912|1326|0|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5956|1310|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5999|1327|10|2|5|15|20|10|1|2|1|1|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5915|1302|2|2|1|2|1|1|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/Vendors.map b/Data/Monsters/felucca/Vendors.map new file mode 100644 index 0000000..efc5a2e --- /dev/null +++ b/Data/Monsters/felucca/Vendors.map @@ -0,0 +1,427 @@ +############## +## By Nerun ## +############## +overrideid 225 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Hidden Valley Mages +## +*|Herbalist|Mage|||||1685|2985|0|1|5|10|20|10|1|2|2|0|0|0|0 +## +## Britain +## +*|jeweler||||||1451|1679|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1602|1712|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||1470|1578|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1547|1659|26|1|5|10|5|0|1|1|1|1|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1620|1586|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|carpenter|architect|realestatebroker||||1430|1597|20|1|5|10|5|0|1|1|1|1|0|0|0 +*|mage|alchemist|mageguildmaster||||1485|1550|30|1|5|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||1296|1759|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1481|1584|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||1493|1616|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1422|1654|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1547|1768|10|1|5|10|5|0|1|1|1|1|1|0|0 +*|warriorguildmaster|hirefighter|||||1341|1733|20|1|5|10|5|0|1|1|2|0|0|0|0 +*|innkeeper||||||1585|1591|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1637|1693|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|tanner|furtrader|||||1431|1612|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1498|1691|20|1|5|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||1470|1765|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||1409|1590|42|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster|blacksmith|||||1349|1778|15|2|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1469|1668|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1510|1543|25|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1427|1716|20|1|5|10|5|0|1|1|1|1|1|0|0 +*|butcher||||||1449|1723|6|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1650|1608|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||1498|1659|27|1|5|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||1425|1690|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1494|1715|6|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1650|1642|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|baker||||||1450|1617|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1418|1547|30|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1471|1611|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1447|1647|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1590|1654|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|bard|bardguildmaster|||||1455|1557|30|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1467|1686|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||1474|1597|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||1417|1578|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1458|1525|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1416|1754|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage||||||1405|1810|0|2|5|10|25|10|1|1|0|0|0|0|0 +*|towncrier||||||1482|1761|-2|2|5|10|4|0|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1228|1572|0|2|5|10|10|8|1|1|1|1|0|0|0 +*|orderguard|hirefighter|||||1355|1754|20|2|5|10|14|8|1|1|1|0|0|0|0 +*|farmer|rancher|||||1243|1699|0|2|5|10|4|4|1|1|1|0|0|0|0 +*|escortablemage||||||1351|1816|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|orderguard||||||1306|1804|0|2|5|10|6|4|1|1|0|0|0|0|0 +*|peasant||||||1304|1826|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|artist||||||1362|1825|0|2|5|10|12|6|1|1|0|0|0|0|0 +*|escortablewanderinghealer||||||1333|1808|0|2|5|10|4|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1150|1619|0|2|5|10|10|6|1|1|1|1|0|0|0 +*|farmer|rancher|hirepeasant||||1149|1547|0|2|5|10|10|10|1|1|1|1|0|0|0 +*|bridegroom||||||1295|1773|10|2|5|10|4|4|1|1|0|0|0|0|0 +*|hirefighter||||||1316|1747|10|2|5|10|20|15|1|3|0|0|0|0|0 +*|hirepeasant||||||1231|1714|0|2|5|10|10|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1190|1707|0|2|5|10|8|4|1|1|1|1|0|0|0 +*|hirebard||||||1427|1726|20|2|5|10|4|4|1|1|0|0|0|0|0 +*|hiresailor|fisherman|rat||||1438|1761|-2|2|5|10|10|6|1|1|1|2|0|0|0 +*|hiresailor||||||1477|1741|0|2|5|10|20|20|1|2|0|0|0|0|0 +*|harbormaster||||||1436|1752|14|2|5|10|4|4|1|1|0|0|0|0|0 +*|merchant||||||1434|1717|20|2|5|10|4|4|1|1|0|0|0|0|0 +## +## Faction Stronghold of True Britannians +## +*|animaltrainer||||||1388|1655|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1362|1574|30|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1388|1588|30|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Buccaneers Den +## +*|innkeeper||||||2715|2098|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|thiefguildmaster||||||2659|2194|4|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2680|2238|2|1|5|10|5|0|1|1|1|1|1|0|0 +*|provisioner|cobbler|||||2737|2250|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2731|2192|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2627|2100|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2752|2155|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2707|2178|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||2634|2083|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2709|2130|0|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Cove +## +*|armorer|weaponsmith|||||2216|1167|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||2256|1181|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||2216|1192|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2245|1231|0|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Jhelom +## +*|fisherman||||||1512|3989|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1504|3693|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1125|3687|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1447|3981|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1452|3747|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1441|3719|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1419|3859|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1356|3780|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1364|3732|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1475|3865|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1354|3754|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher|farmer|||||1386|3825|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||1450|4026|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1395|3705|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||1435|3820|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||1404|3802|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1452|3770|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|armorer|weaponsmith|||||1456|3850|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1317|3773|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||1372|3908|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1416|3779|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1387|3771|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1425|3981|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||1454|4003|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||1360|3815|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1442|3802|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherguildmaster||||||1437|3750|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Magincia +## +*|innkeeper||||||3699|2163|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||3666|2235|20|1|5|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||3720|2126|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3755|2227|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3734|2149|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3683|2171|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||3661|2183|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||3683|2252|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3667|2252|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3727|2224|20|1|5|10|5|0|1|1|1|1|1|0|0 +*|healer|healerguildmaster|||||3687|2227|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||3674|2289|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||3665|2140|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3699|2218|20|1|5|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||3703|2249|20|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Minoc +## +*|provisioner||||||2450|428|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|cobbler||||||2450|428|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2438|410|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||2526|375|23|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2522|524|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2526|546|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|architect||||||2513|477|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2533|572|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2503|552|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2475|397|15|1|5|10|5|0|1|1|1|1|1|0|0 +*|blacksmith|blacksmithguildmaster|||||2471|564|5|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2461|457|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2505|432|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||2577|599|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2455|487|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|bard|bardguildmaster|||||2424|555|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||2478|427|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|realestatebroker|||||2513|477|15|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Moonglow +## +*|tailor|weaver|tailorguildmaster||||4458|1060|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||4417|1064|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||4401|1165|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||4440|1162|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster||||||4545|860|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||4481|1085|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||4395|1137|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||4471|1156|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||4416|1133|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|baker||||||4392|1068|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||4416|1085|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||4392|1117|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||4406|1038|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||4394|1083|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||4409|1111|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||4484|1064|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||4448|1090|0|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Nujel'm +## +*|blacksmith|blacksmithguildmaster|||||3554|1202|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3731|1320|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3700|1214|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3729|1258|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|tailor|weaver|tailorguildmaster||||3774|1265|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tanner||||||3545|1178|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3764|1317|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bardguildmaster||||||3740|1197|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||3778|1172|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3769|1218|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|blacksmith|blacksmithguildmaster|||||3546|1185|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||3546|1194|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||3555|1171|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|furtrader||||||3545|1178|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Ocllo +## +*|fisherman||||||3647|2681|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||3612|2466|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3628|2541|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||3667|2586|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|butcher||||||3708|2649|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||3672|2654|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3632|2640|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||3695|2511|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bardguildmaster||||||3665|2531|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||3602|2615|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3673|2614|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||3632|2595|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||3629|2608|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||3636|2565|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3610|2577|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Serpents Hold +## +*|baker||||||2975|3353|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2906|3485|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||3031|3350|35|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||3018|3426|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2880|3472|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2997|3428|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||3036|3464|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3003|3355|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||2905|3517|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||3051|3367|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2883|3502|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2992|3451|16|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||3008|3389|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2940|3500|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||3058|3400|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||3007|3408|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||3013|3353|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||2967|3408|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2972|3425|15|1|5|10|5|0|1|1|1|1|1|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3009|3455|15|1|5|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||2940|3410|1|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Skara Brae +## +*|blacksmith|blacksmithguildmaster|||||630|2194|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|rangerguildmaster||||||562|2148|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||554|2178|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||650|2178|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||656|2235|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||578|2227|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||592|2277|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||587|2146|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||570|2121|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||590|2205|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||582|2186|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||627|2163|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||601|2235|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||611|2157|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||650|2161|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||620|2218|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||602|2180|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||586|2170|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||659|2141|0|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Trinsic +## +*|scribe||||||2002|2721|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1897|2805|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1852|2831|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2033|2801|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1895|2653|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||2026|2845|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinkerguildmaster||||||1848|2680|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||1990|2889|5|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||2072|2856|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||1991|2867|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1911|2805|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1897|2684|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1822|2739|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2019|2748|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1844|2735|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1981|2838|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1880|2802|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1813|2825|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1850|2796|-8|1|5|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||1939|2739|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1846|2715|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||2011|2804|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1935|2766|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1935|2796|0|1|5|10|5|0|1|1|1|1|1|0|0 +## +## Vesper +## +*|minerguildmaster||||||2855|734|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||2861|812|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||2882|723|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2961|621|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||2840|885|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tanner|furtrader|||||2860|999|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||2998|760|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||3034|827|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||2962|885|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2835|805|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2986|637|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2890|651|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|beekeeper||||||2954|705|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2987|777|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2841|907|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3017|761|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherguildmaster||||||2963|813|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3012|780|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2899|790|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2917|798|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||2920|856|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2782|969|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2865|852|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2918|672|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|herbalist|alchemist|customhairstylist||||2992|844|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|shipwright|mapmaker|||||2995|815|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2901|908|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|banker|minter|||||2881|684|0|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Wind +## +*|scribe||||||5242|180|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5161|32|17|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5148|60|25|1|5|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||5347|76|25|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||5263|129|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5203|86|5|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5218|175|5|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5300|90|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5306|37|40|1|5|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||5236|142|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5351|56|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||5154|97|5|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||5215|117|1|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Yew +## +*|bowyer||||||570|969|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||517|986|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||529|1008|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||652|820|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||610|810|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||535|867|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||564|1011|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||643|1083|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||624|1145|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||631|1034|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||540|966|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||553|985|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Delucia +## +*|provisioner|cobbler|||||5219|4012|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||5275|3977|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||5225|4000|38|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||5197|4060|37|1|5|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5297|4007|40|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5234|4025|37|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||5191|3989|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5296|3978|37|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Papua +## +*|minter|banker|||||5669|3131|14|2|2|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster|alchemist|mage||||5731|3192|9|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinkerguildmaster|tinker|||||5726|3243|16|2|2|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||5662|3150|13|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5671|3287|11|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||5698|3282|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|weaponsmith|armorer|||||5805|3300|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|customhairstylist|alchemist|herbalist||||5714|3202|12|2|2|10|5|0|1|1|1|1|0|0|0 +*|mapmaker|shipwright|||||5805|3270|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailorguildmaster|weaver|tailor||||5752|3272|16|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||5839|3256|2|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5746|3200|16|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5775|3161|14|2|2|10|5|0|1|1|0|0|0|0|0 +*|healerguildmaster|healer|||||5737|3222|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|realestatebroker|architect|carpenter||||5691|3209|11|2|2|10|5|0|1|1|1|1|0|0|0 +*|cobbler|provisioner|||||5736|3263|15|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Sea Market +## +*|fisherman||||||4571|2303|-2|2|5|10|-1|0|1|1|0|0|0|0|0 +*|tanner||||||4553|2318|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|wanderinghealer|bard|||||4550|2307|-2|2|5|10|-1|10|1|1|1|0|0|0|0 +*|fisherman||||||4557|2307|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|||||4540|2301|-1|2|5|10|-1|4|1|1|1|0|0|0|0 +*|bodysculptor||||||4547|2321|-2|2|5|10|-1|4|1|1|0|0|0|0|0 +*|shipwright||||||4551|2334|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4556|2330|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|tailor|provisioner|fisherman||||4533|2333|-2|2|5|10|-1|4|1|1|1|1|0|0|0 +*|dockmaster||||||4569|2304|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4549|2346|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|hiresailor||||||4562|2349|-2|2|5|10|-1|4|1|1|0|0|0|0|0 +*|fisherman|hiresailor|||||4570|2400|-2|2|5|10|7|4|1|1|1|0|0|0|0 +*|fisherguildmaster||||||4551|2327|-2|2|5|10|-1|7|1|1|0|0|0|0|0 +*|fisherman||||||4530|2382|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|boatpainter||||||4551|2320|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4573|2364|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4553|2351|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4537|2348|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|blacksmith||||||4549|2301|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4553|2343|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|tavernkeeper|cook|||||4544|2299|-1|2|5|10|-1|4|1|1|1|0|0|0|0 +*|tinker||||||4561|2328|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|wanderinghealer||||||4551|2381|-2|2|5|10|-1|15|1|1|0|0|0|0|0 +*|wanderinghealer||||||4552|2349|-2|2|5|10|-1|5|1|1|0|0|0|0|0 +*|hiresailor||||||4552|2390|-2|2|5|10|-1|7|1|1|0|0|0|0|0 +*|alchemist||||||4542|2329|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|banker||||||4551|2323|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|shipwright||||||4564|2298|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4547|2376|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|waiter||||||4540|2306|-1|2|5|10|-1|4|1|1|0|0|0|0|0 +*|fisherman||||||4554|2389|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|treasurelevel1h||||||4534|2349|-2|2|5|10|-1|0|1|1|0|0|0|0|0 +*|treasurelevel1h||||||4535|2349|-2|2|5|10|-1|0|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/felucca/WildLife.map b/Data/Monsters/felucca/WildLife.map new file mode 100644 index 0000000..d79ec94 --- /dev/null +++ b/Data/Monsters/felucca/WildLife.map @@ -0,0 +1,186 @@ +############## +## By Nerun ## +############## +overrideid 226 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3394|628|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3232|510|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4478|3218|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4446|3706|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4682|3662|77|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4692|3494|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4560|3504|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4612|3424|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3607|2417|45|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3555|2525|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3506|2477|28|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3452|2563|32|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3429|2650|43|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3449|2737|49|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3736|2512|35|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3718|2736|38|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3654|2866|61|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3662|2802|51|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3596|2804|51|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3546|2812|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3650|2080|21|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3608|2140|79|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4384|1218|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4468|1006|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4326|1046|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4544|1128|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4510|1262|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4590|1326|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4526|986|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4336|1130|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4448|1334|3|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4540|1454|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4632|1164|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4470|1430|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4592|1424|3|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|3500|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2998|3590|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2864|150|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3292|570|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3206|366|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3172|664|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3392|424|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3076|150|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3092|542|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2512|1066|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2554|1142|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2416|1172|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2188|1986|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2654|2286|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2946|2168|44|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2744|2014|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2786|2282|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2074|1972|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2122|2108|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1932|3125|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1824|3027|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1894|2942|19|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2499|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1005|2647|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|464|2059|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|559|2081|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|883|2129|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|968|2476|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|994|2361|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|964|2214|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1087|2401|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2378|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1334|2311|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1315|2192|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1426|2615|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1527|2609|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1582|2722|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1650|2796|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1724|2781|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1727|2702|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1634|2645|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1505|2445|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1699|2560|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1612|2526|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1722|2435|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1715|2307|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1531|2351|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1602|2426|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1628|2334|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1563|2277|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1503|2207|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1709|1992|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1498|2040|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1439|2104|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1387|2023|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1377|1911|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1459|1963|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1268|2018|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1173|2103|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1070|2069|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|958|2074|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|999|1839|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|1945|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1229|1655|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1725|1447|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1798|1471|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1958|1305|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1867|1244|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1865|1379|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1769|1330|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1666|1290|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1486|1301|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1351|1359|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1231|1462|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1017|1726|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|398|1305|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|485|1398|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|210|1447|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|851|1770|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|977|1638|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|919|1718|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|876|1639|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|1570|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|725|1483|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|623|1328|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|727|1394|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1020|1360|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1024|1244|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|802|1280|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|855|934|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|771|1013|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|846|1071|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|940|1028|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1152|812|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|896|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1057|765|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|974|374|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1063|541|16|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1018|629|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|951|542|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|576|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|937|743|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|890|657|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|895|830|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|689|753|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|748|669|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|764|822|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|834|751|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|782|1156|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|887|1223|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|916|1159|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|993|1130|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1047|1071|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1092|1010|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1172|974|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1388|784|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1631|640|22|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1526|960|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1545|813|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1695|809|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1728|691|6|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1802|495|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1857|600|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1884|735|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1973|751|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2085|658|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2367|748|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2289|917|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2338|989|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2418|999|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2495|978|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2583|993|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2513|782|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2748|660|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2765|754|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2668|1020|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2669|922|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2672|814|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2643|728|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2888|391|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2735|417|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2914|547|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|492|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2688|524|11|2|5|10|50|50|1|7|5|1|2|2|2 \ No newline at end of file diff --git a/Data/Monsters/felucca/Wrong.map b/Data/Monsters/felucca/Wrong.map new file mode 100644 index 0000000..8748614 --- /dev/null +++ b/Data/Monsters/felucca/Wrong.map @@ -0,0 +1,24 @@ +############## +## By Nerun ## +############## +overrideid 227 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Wrong Dungeon +## +## Level 1 +## +*|Jukawarrior||||||5819|591|0|2|2|10|25|5|1|2|0|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5808|588|12|2|2|10|30|15|1|1|1|3|0|0|0 +*|Golemcontroller|Golem|||||5792|544|10|2|2|10|30|6|1|4|4|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|586|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|562|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5828|530|0|2|2|10|30|8|1|1|1|3|0|0|0 +## +## Level 2 +## +*|Brigand|Jukalord|Jukamage|Jukawarrior|||5659|563|20|2|2|10|30|10|1|4|1|1|3|0|0 +*|Golem|Jukalord|Jukamage|Jukawarrior|||5724|561|20|2|2|10|30|8|1|1|1|1|3|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5690|534|0|2|2|10|30|8|1|1|1|3|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Ancientlair.map b/Data/Monsters/ilshenar/Ancientlair.map new file mode 100644 index 0000000..aed44f2 --- /dev/null +++ b/Data/Monsters/ilshenar/Ancientlair.map @@ -0,0 +1,15 @@ +############## +## By Nerun ## +############## +overrideid 301 +## +## Ancient LairCave +## +*|AncientWyrm||||||50|689|-28|3|10|20|15|30|1|1|0|0|0|0|0 +overridemintime 5 +overridemaxtime 10 +*|fireelemental:lavalizard||||||115|716|-28|3|5|10|15|15|1|3|0|0|0|0|0 +*|fireelemental:lavalizard||||||131|78|0|3|5|10|10|10|1|1|0|0|0|0|0 +*|fireelemental:lavalizard||||||54|718|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|fireelemental|lavalizard|||||82|718|-28|3|5|10|15|15|1|2|2|0|0|0|0 +*|fireelemental:lavalizard||||||79|687|-28|3|5|10|10|10|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Ankh.map b/Data/Monsters/ilshenar/Ankh.map new file mode 100644 index 0000000..692bf6e --- /dev/null +++ b/Data/Monsters/ilshenar/Ankh.map @@ -0,0 +1,47 @@ +############## +## By Nerun ## +############## +overrideid 302 +overridemintime 5 +overridemaxtime 10 +## +## Ankh Dungeon +## +## Level 1 +## +*|Ratman|Ratmanarcher|Ratmanmage||||129|1530|-28|3|5|10|40|20|1|5|2|2|0|0|0 +*|Hellhound|Imp|||||71|1521|-28|3|5|10|40|15|1|2|3|0|0|0|0 +*|Evilmage||||||87|1471|-22|3|5|10|7|7|1|3|0|0|0|0|0 +*|Evilmage||||||63|1471|-28|3|5|10|7|7|1|2|0|0|0|0|0 +*|Daemon||||||39|1491|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||34|1462|-28|3|5|10|10|10|1|3|0|0|0|0|0 +*|Imp||||||15|1503|-27|3|5|10|7|7|1|4|0|0|0|0|0 +*|Evilmage||||||62|1446|-28|3|5|10|7|7|1|3|0|0|0|0|0 +*|Skeletalknight||||||31|1410|-28|3|5|10|11|7|1|4|0|0|0|0|0 +*|Mummy||||||86|1447|-28|3|5|10|15|7|1|3|0|0|0|0|0 +*|Skeletalmage||||||124|1435|-16|3|5|10|20|10|1|4|0|0|0|0|0 +*|Lich||||||124|1436|-16|3|5|10|15|7|1|2|0|0|0|0|0 +*|Lich||||||107|1390|-28|3|5|10|10|10|1|2|0|0|0|0|0 +*|Lichlord|Rottingcorpse|||||131|1331|-28|3|5|10|20|20|1|1|2|0|0|0|0 +*|Zombie||||||132|1332|-28|3|5|10|20|20|1|4|0|0|0|0|0 +*|Skeleton|Skeletalknight|Skeletalmage||||55|1303|-28|3|5|10|30|20|1|3|2|1|0|0|0 +## +## Kirin Passage +## +*|Fireelemental||||||45|905|-29|3|5|10|30|15|1|2|0|0|0|0|0 +*|Poisonelemental||||||49|846|-30|3|5|10|12|12|1|1|0|0|0|0|0 +*|Earthelemental||||||114|908|-26|3|5|10|25|15|1|3|0|0|0|0|0 +*|Poisonelemental||||||102|959|-43|3|5|10|20|15|1|2|0|0|0|0|0 +*|Kirin||||||148|953|-29|3|5|10|15|15|1|1|0|0|0|0|0 +*|Dragon||||||29|1009|-27|3|5|10|35|15|1|2|0|0|0|0|0 +*|Drake||||||29|1016|-27|3|5|10|35|15|1|4|0|0|0|0|0 +*|Earthelemental|Mongbat|||||87|1051|-29|3|5|10|35|20|1|3|7|0|0|0|0 +*|Earthelemental||||||108|1110|-27|3|5|10|30|20|1|4|0|0|0|0|0 +*|Toxicelemental||||||99|1158|-23|3|5|10|10|10|1|2|0|0|0|0|0 +*|Nightmare||||||66|1171|-28|3|5|10|10|5|1|1|0|0|0|0|0 +## +## Serpentine Passage +## +*|Pixie||||||438|1552|-28|3|5|10|20|10|1|5|0|0|0|0|0 +*|Wisp||||||451|1552|-27|3|5|10|25|15|1|3|0|0|0|0|0 +*|Serpentinedragon||||||473|1552|-28|3|5|10|20|15|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Blood.map b/Data/Monsters/ilshenar/Blood.map new file mode 100644 index 0000000..b09aa07 --- /dev/null +++ b/Data/Monsters/ilshenar/Blood.map @@ -0,0 +1,27 @@ +############## +## By Nerun ## +############## +overrideid 303 +overridemintime 5 +overridemaxtime 10 +## +## Blood Dungeon +## +*|Imp||||||2114|846|-28|3|5|10|30|15|1|4|0|0|0|0|0 +*|Imp||||||2051|837|-28|3|5|10|15|7|1|4|0|0|0|0|0 +*|Hellcat||||||2050|859|-28|3|5|10|15|7|1|2|0|0|0|0|0 +*|Hellcat||||||2090|868|-14|3|5|10|15|7|1|3|0|0|0|0|0 +*|Imp||||||2177|836|-28|3|5|10|15|7|1|4|0|0|0|0|0 +*|Imp||||||2177|858|-28|3|5|10|15|7|1|4|0|0|0|0|0 +*|Imp||||||2138|868|-14|3|5|10|15|7|1|4|0|0|0|0|0 +*|Bloodelemental||||||2138|868|-14|3|5|10|7|7|1|1|0|0|0|0|0 +*|Balron||||||2083|911|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Balron||||||2115|917|-23|3|5|10|15|15|1|1|0|0|0|0|0 +*|Balron||||||2145|911|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||2170|920|-28|3|5|10|32|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||2058|907|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||2058|932|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Daemon||||||2083|951|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|Daemon||||||2114|951|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|Daemon||||||2146|951|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|Succubus|Hellcat|||||2113|1017|-28|3|5|10|30|15|1|2|4|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Exodus.map b/Data/Monsters/ilshenar/Exodus.map new file mode 100644 index 0000000..b33e874 --- /dev/null +++ b/Data/Monsters/ilshenar/Exodus.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 304 +overridemintime 5 +overridemaxtime 10 +## +## Exodus Dungeon +## +*|EnslavedGargoyle:GolemController||||||1980|116|-28|3|5|10|40|30|1|2|0|0|0|0|0 +*|ExodusMinion||||||1939|116|-28|3|5|10|25|15|1|1|0|0|0|0|0 +*|GolemController:ExodusOverseer||||||1894|116|-28|3|5|10|30|20|1|2|0|0|0|0|0 +*|GolemController||||||1964|164|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController||||||1932|164|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController:Golem||||||1932|196|-28|3|5|10|20|15|1|2|0|0|0|0|0 +*|GargoyleDestroyer||||||1895|160|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|ExodusOverseer:ExodusMinion||||||1979|192|-28|3|5|10|20|15|1|2|0|0|0|0|0 +*|GolemController||||||1996|164|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleEnforcer||||||2032|184|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleEnforcer||||||2063|183|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleEnforcer:GargoyleDestroyer||||||2058|163|-28|3|5|10|15|10|1|2|0|0|0|0|0 +*|GolemController:Golem:ExodusMinion||||||2044|143|-28|3|5|10|15|10|1|3|0|0|0|0|0 +*|GolemController:ExodusOverseer||||||2071|116|-28|3|5|10|15|10|1|2|0|0|0|0|0 +*|ExodusMinion:Golem||||||2044|87|-28|3|5|10|15|10|1|2|0|0|0|0|0 +*|GargoyleEnforcer||||||2031|48|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleDestroyer||||||2038|67|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController||||||1995|67|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|ExodusOverseer:ExodusMinion:GolemController||||||1980|39|-28|3|5|10|15|10|1|3|0|0|0|0|0 +*|GolemController||||||1931|67|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleDestroyer||||||1896|72|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController:Golem||||||1932|35|-28|3|5|10|20|15|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Mushroom.map b/Data/Monsters/ilshenar/Mushroom.map new file mode 100644 index 0000000..3f00318 --- /dev/null +++ b/Data/Monsters/ilshenar/Mushroom.map @@ -0,0 +1,15 @@ +############## +## By Nerun ## +############## +overrideid 305 +overridemintime 2 +overridemaxtime 5 +## +## Mushroom Cave +## +## Level 1 +## +*|mushroomtrap||||||1444|1519|-28|3|2|5|10|10|1|4|0|0|0|0|0 +*|mushroomtrap||||||1441|1532|-28|3|2|5|10|10|1|4|0|0|0|0|0 +*|mushroomtrap||||||1415|1498|-27|3|2|5|4|4|1|4|0|0|0|0|0 +*|mushroomtrap||||||1464|1495|-28|3|2|5|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Outdoors.map b/Data/Monsters/ilshenar/Outdoors.map new file mode 100644 index 0000000..a837752 --- /dev/null +++ b/Data/Monsters/ilshenar/Outdoors.map @@ -0,0 +1,360 @@ +############## +## By Nerun ## +############## +overrideid 306 +overridemintime 5 +overridemaxtime 10 +## +## Ilshenar Northeast +## +## South Montor +*|Dragon||||||1763|344|52|3|5|10|30|30|1|1|0|0|0|0|0 +*|Earthelemental||||||1790|435|-10|3|5|10|25|20|1|3|0|0|0|0|0 +*|Mongbat|Airelemental|Giantspider|Earthelemental|Scorpion||1805|469|-9|3|5|10|50|50|1|5|1|1|3|4|0 +*|Stonegargoyle||||||1852|484|-13|3|5|10|20|10|1|3|0|0|0|0|0 +*|Brigand||||||1856|517|-14|3|5|10|30|30|1|3|0|0|0|0|0 +*|Airelemental||||||1775|530|66|3|5|10|10|10|1|1|0|0|0|0|0 +*|Wyvern|Mummy|||||1828|601|38|3|5|10|40|40|1|2|6|0|0|0|0 +*|Orccamp||||||1717|606|17|3|5|10|0|0|1|1|0|0|0|0|0 +## Desert +*|Desertostard|Stoneharpy|Gargoyle|Wyvern|Efreet|Lichlord|1647|602|-14|3|5|10|30|30|1|5|1|2|2|1|1 +*|Desertostard|Stoneharpy|Gargoyle|Wyvern|Efreet||1593|602|7|3|5|10|30|30|1|5|2|2|1|2|0 +*|Earthelemental:Scorpion||||||1700|546|5|3|5|10|30|30|1|14|0|0|0|0|0 +*|Ratman|Ratmanarcher:Ratmanmage|||||1580|538|-14|3|5|10|7|5|1|2|1|0|0|0|0 +*|Ratman|Ratmanarcher:Ratmanmage|||||1580|554|-13|3|5|10|7|5|1|1|1|0|0|0|0 +*|Earthelemental||||||1534|631|-14|3|5|10|15|5|1|2|0|0|0|0|0 +*|Earthelemental||||||1530|667|-14|3|5|10|15|5|1|2|0|0|0|0|0 +*|Shade:Spectre:Wraith|Skeleton|Ghoul|Zombie|||1534|600|-14|3|5|10|25|15|1|7|5|2|2|0|0 +*|Imp||||||1445|681|-1|3|5|10|20|20|1|3|0|0|0|0|0 +## Glacier/Tunnels +*|Harpy||||||1400|687|32|3|5|10|25|25|1|3|0|0|0|0|0 +*|Frosttroll|Drake|Snowelemental|Iceelemental|||1352|667|111|3|5|10|22|22|1|3|2|2|2|0|0 +*|Frosttroll|Iceelemental|Iceserpent|Frostspider|||1372|623|111|3|5|10|30|25|1|4|1|2|2|0|0 +*|Frosttroll|Snowelemental|Iceelemental|Drake|||1316|633|106|3|5|10|30|10|1|2|1|1|1|0|0 +## Green/Mountains +*|Skeleton|Shade:Spectre:Wraith|Ghoul|Zombie|||1442|576|-11|3|5|10|15|10|1|5|6|2|2|0|0 +*|Skeleton|Shade:Spectre|Zombie|Efreet|||1400|572|-13|3|5|10|15|15|1|4|4|2|1|0|0 +*|Orc|Orccaptain|Ettin|Troll|Orcishmage||1421|517|1|3|5|10|40|30|1|3|1|2|2|1|0 +*|Healercamp||||||1358|498|3|3|5|10|0|0|1|1|0|0|0|0|0 +*|Gargoyle||||||1319|560|-4|3|5|10|15|15|1|3|0|0|0|0|0 +*|Ratman|Ratmanarcher|Ratmanmage||||1237|473|-4|3|5|10|20|15|1|3|1|1|0|0|0 +*|Drake|Harpy|||||1275|401|-1|3|5|10|40|35|1|2|4|0|0|0|0 +*|Troll||||||1445|384|22|3|5|10|30|30|1|4|0|0|0|0|0 +*|Ancientwyrm||||||1416|317|74|3|5|10|7|7|1|1|0|0|0|0|0 +*|Imp|Daemon|||||1496|280|-10|3|5|10|10|10|1|3|1|0|0|0|0 +*|Ettin||||||1464|241|2|3|5|10|20|10|1|1|0|0|0|0|0 +*|Ettin||||||1503|239|-7|3|5|10|20|10|1|1|0|0|0|0|0 +*|Imp||||||1571|253|14|3|5|10|25|10|1|3|0|0|0|0|0 +## Swamp near savage +*|Sewerrat|Corpser|Bogling|Giantrat|Alligator|Mongbat|1070|750|-80|3|5|10|30|30|1|4|2|2|2|2|2 +*|Lizardman|Plaguebeast|Toxicelemental||||1070|750|-80|3|5|10|30|30|1|4|2|1|0|0|0 +*|Sewerrat|Corpser|Bogling|Giantrat|Alligator|Mongbat|1135|743|-80|3|5|10|30|30|1|4|2|2|2|2|2 +*|Lizardman|Plaguebeast|Toxicelemental|Bogthing|||1135|743|-80|3|5|10|30|30|1|4|2|1|1|0|0 +*|Sewerrat|Corpser|Bogling|Giantrat|Alligator|Mongbat|1160|681|-80|3|5|10|30|30|1|4|2|1|2|2|1 +*|Lizardman|Plaguebeast|||||1160|681|-80|3|5|10|30|30|1|3|1|0|0|0|0 +## Controller Tower +*|Golemcontroller|Golem|||||1097|702|-79|3|5|10|7|5|1|1|1|0|0|0|0 +*|Golemcontroller|Golem|||||1087|698|-80|3|5|10|7|2|1|1|1|0|0|0|0 +*|Golemcontroller||||||1086|702|-60|3|5|10|5|5|1|2|0|0|0|0|0 +*|Golemcontroller|Golem|||||1098|698|-60|3|5|10|5|1|1|1|1|0|0|0|0 +*|Golem||||||1091|702|-40|3|5|10|10|5|1|1|0|0|0|0|0 +## +## Ruined Castle +## Level 1 +*|Jukamage||||||1084|675|-80|3|5|10|15|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1059|675|-79|3|5|10|7|7|1|1|0|0|0|0|0 +*|Jukawarrior||||||1060|659|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1060|643|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukamage||||||1075|628|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1092|628|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1083|638|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukamage||||||1095|638|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukawarrior||||||1095|664|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukalord||||||1083|664|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukalord||||||1070|639|-79|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukamage|Jukawarrior|||||1070|650|-79|3|5|10|7|5|1|1|1|0|0|0|0 +## Level 2 +*|Jukawarrior||||||1072|651|-60|3|5|10|6|6|1|1|0|0|0|0|0 +*|Jukawarrior||||||1083|628|-60|3|5|10|15|3|1|1|0|0|0|0|0 +*|Jukamage||||||1107|627|-59|3|5|10|7|3|1|1|0|0|0|0|0 +*|Betrayer||||||1083|675|-60|3|5|10|15|3|1|1|0|0|0|0|0 +*|Jukamage|Jukawarrior|Juggernaut||||1088|661|-60|3|5|10|10|9|1|1|1|1|0|0|0 +*|Betrayer|Jukalord|Jukawarrior||||1090|646|-60|3|5|10|10|3|1|1|1|1|0|0|0 +*|Jukamage|Jukalord|Jukawarrior||||1088|637|-60|3|5|10|10|4|1|2|1|1|0|0|0 +## Level 3 +*|Betrayer||||||1060|652|-40|3|5|10|15|3|1|1|0|0|0|0|0 +*|Betrayer|Golemcontroller|||||1083|651|-40|3|5|10|25|10|1|1|3|0|0|0|0 +*|Juggernaut|Golem|||||1083|651|-40|3|5|10|25|10|1|3|1|0|0|0|0 +## Level 4 +*|Golemcontroller|Gargoyle|||||1084|652|-20|3|5|10|25|10|1|2|2|0|0|0|0 +## +## Meer +## +*|Meerwarrior|Meermage|Meercaptain|Meereternal|||1772|67|-28|3|5|10|25|20|1|3|2|2|1|0|0 +*|Meerwarrior|Meermage|Meercaptain|Meereternal|||1803|66|-28|3|5|10|25|20|1|4|2|1|1|0|0 +############## +## By Nerun ## +############## +## +## Ilshenar Northwest +## +## Undead Camp +## +*|Skeleton|Wraith|Skeletalknight|Zombie|Skeletalmage|Wyvern|855|464|-2|3|5|10|20|20|1|6|2|4|3|3|2 +## +## Pass of Karnaugh +## +*|Dreadspider|Poisonelemental|Stonegargoyle|Wyvern|Skeleton|Skeletalknight|1041|272|56|3|5|10|25|25|1|2|1|1|1|1|1 +*|Lich|Shade:Spectre:Wraith|Zombie|Ghoul|||1041|272|56|3|5|10|25|25|1|1|3|1|1|0|0 +*|Dreadspider|Stonegargoyle|Wyvern|Skeleton|Skeletalmage|Eldergazer|1000|272|56|3|5|10|25|25|1|1|2|1|1|1|1 +*|Lichlord|Shade:Spectre:Wraith|Zombie|Ghoul|||1000|272|56|3|5|10|25|25|1|1|3|1|1|0|0 +## +## Memorial to Gwenno +## +*|Eldergazer|Gazer|||||748|492|-64|3|5|10|10|10|1|1|2|0|0|0|0 +## +## Near undead camp +## +*|Skeleton|Shade:Spectre:Wraith|Ghoul|Zombie|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|783|448|-47|3|5|10|25|25|1|4|4|2|2|2|2 +*|Lich|Lichlord|||||783|448|-47|3|5|10|25|25|1|1|1|0|0|0|0 +*|Skeleton|Shade:Spectre:Wraith|Ghoul|Zombie|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|742|440|-59|3|5|10|25|25|1|4|4|2|2|2|2 +*|Lich|Lichlord|||||742|440|-59|3|5|10|25|25|1|1|1|0|0|0|0 +## +## Cyclopse Garden / Camp +## +*|Cyclops||||||756|208|-40|3|5|10|10|10|1|4|0|0|0|0|0 +*|Cyclops|Titan|Ettin||||739|264|-54|3|5|10|35|35|1|1|1|2|0|0|0 +*|Cyclops|Titan|Ettin||||778|264|-38|3|5|10|35|35|1|1|1|2|0|0|0 +## +## Bandit Town +## +*|Brigand|Evilmage|||||511|545|-60|3|5|10|25|20|1|4|2|0|0|0|0 +## +*|Wyvern||||||638|555|-75|3|5|10|40|40|1|3|0|0|0|0|0 +*|Wyvern||||||565|343|-77|3|5|10|40|40|1|2|0|0|0|0|0 +*|Eldergazer|Gazer|||||489|488|-62|3|5|10|25|25|1|1|2|0|0|0|0 +*|Dragon||||||385|421|-62|3|5|10|30|20|1|1|0|0|0|0|0 +*|Dragon||||||447|425|-60|3|5|10|30|20|1|1|0|0|0|0|0 +*|Dragon||||||445|366|-66|3|5|10|30|30|1|1|0|0|0|0|0 +*|Dragon||||||445|318|-64|3|5|10|30|30|1|1|0|0|0|0|0 +*|Wyvern|Giantspider|Dreadspider||||370|264|-52|3|5|10|15|15|1|1|2|1|0|0|0 +*|Wyvern|Giantspider|Dreadspider||||409|264|-44|3|5|10|15|15|1|1|2|1|0|0|0 +*|Wyvern|Giantspider|Dreadspider||||449|264|-57|3|5|10|15|15|1|1|2|1|0|0|0 +## +## Desert near Gargoyle City +## +*|Mongbat|Earthelemental|Scorpion|Sandvortex|Ridgeback|Efreet|964|638|-80|3|5|10|50|40|1|5|5|5|5|1|1 +## +## Around Ancient Lair +## +*|Earthelemental||||||981|470|-80|3|5|10|15|10|1|1|0|0|0|0|0 +*|Imp|Golemcontroller|||||978|471|-80|3|5|10|15|10|1|1|1|0|0|0|0 +*|Lavalizard||||||973|460|-80|3|5|10|15|10|1|1|0|0|0|0|0 +*|Earthelemental||||||964|456|-80|3|5|10|15|10|1|1|0|0|0|0|0 +*|Exodusoverseer||||||963|456|-80|3|5|10|10|5|1|1|0|0|0|0|0 +*|Imp||||||941|471|-38|3|5|10|10|4|1|1|0|0|0|0|0 +*|Gargoyle||||||946|430|-80|3|5|10|15|10|1|4|0|0|0|0|0 +*|Lich|Ghoul|Zombie|Shade:Wraith:Spectre|||878|527|-77|3|5|10|20|10|1|1|1|4|1|0|0 +*|Imp||||||938|453|-80|3|5|10|15|10|1|2|0|0|0|0|0 +*|Earthelemental||||||960|524|-80|3|5|10|15|5|1|1|0|0|0|0|0 +*|Earthelemental||||||911|502|-80|3|5|10|15|5|1|1|0|0|0|0|0 +*|Imp||||||930|519|-80|3|5|10|15|5|1|1|0|0|0|0|0 +## +## Under Desert near Gargoyle City +## +*|golemcontroller||||||808|781|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|quagmire||||||853|762|-80|3|5|10|17|17|1|3|0|0|0|0|0 +*|chaosdaemon|Moloch|Doppleganger||||821|758|-80|3|5|10|17|17|1|1|1|1|0|0|0 +*|quagmire|Doppleganger|ArcaneDaemon||||821|802|-80|3|5|10|17|17|1|1|1|1|0|0|0 +*|chaosdaemon|Moloch|||||858|799|-80|3|5|10|17|17|1|2|1|0|0|0|0 +*|chaosdaemon||||||879|781|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|earthelemental||||||907|780|-80|3|5|10|20|20|1|4|0|0|0|0|0 +*|earthelemental||||||987|791|-80|3|5|10|20|20|1|4|0|0|0|0|0 +## +## Non-OSI spawns (animals) +## +*|Airelemental||||||275|453|-53|3|5|10|50|30|1|1|0|0|0|0|0 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|652|555|-72|3|5|10|75|50|1|5|2|5|3|3|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|685|340|-64|3|5|10|170|125|1|15|9|9|9|9|9 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|460|469|-49|3|5|10|75|50|1|5|2|5|3|3|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|377|340|-14|3|5|10|150|100|1|9|5|6|5|5|5 +############## +## By Nerun ## +############## +## +## Ilshenar Southeast +## +## Healing Temple +## +*|Wanderinghealer||||||1083|968|-38|3|5|10|30|30|1|5|0|0|0|0|0 +## +## Ratman Village +## +*|ratmanmage|ratmanarcher|ratman||||1059|1153|-24|3|5|10|15|15|1|2|2|4|0|0|0 +## +## Brigand Tower +## +*|Brigand||||||1129|1236|-4|3|5|10|12|12|1|4|0|0|0|0|0 +## +## Camps +## +*|Bankercamp||||||1186|1223|-20|3|5|10|0|0|1|1|0|0|0|0|0 +*|Healercamp||||||1519|1019|-6|3|5|10|0|0|1|1|0|0|0|0|0 +## +## Southeast forest +## +*|Pixie|Horse|||||1592|1191|-20|3|5|10|70|70|1|5|3|0|0|0|0 +*|Unicorn||||||1592|1191|-20|3|5|10|50|50|1|1|0|0|0|0|0 +*|Pixie|Horse|||||1480|1207|-18|3|5|10|70|70|1|5|3|0|0|0|0 +*|Unicorn||||||1480|1207|-18|3|5|10|50|50|1|1|0|0|0|0|0 +*|Pixie|Horse|||||1318|1246|-13|3|5|10|50|40|1|3|1|0|0|0|0 +## +## Sacrifice Graveyard +## +*|Skeleton:Zombie:Ghoul||||||1183|1287|-30|3|5|10|10|5|1|3|0|0|0|0|0 +## +## Sheep farm +## +*|Sheep||||||1319|1331|-14|3|5|10|10|10|1|3|0|0|0|0|0 +## +## Blood Dungeon entrance +## +*|Skeleton||||||1733|1161|-5|3|5|10|30|30|1|7|0|0|0|0|0 +*|Skeleton|Skeletalknight:Boneknight|Imp||||1747|1221|-1|3|5|10|25|15|1|4|4|3|0|0|0 +## +## Harpy Nest +## +*|Harpy|Stoneharpy|||||1678|971|10|3|5|10|15|15|1|3|1|0|0|0|0 +## +## Tower (near twin oaks tavern) +## +*|Evilmagelord||||||1674|1074|32|3|5|10|5|0|1|1|0|0|0|0|0 +## +## Abandoned building +## +*|Giantrat||||||1585|990|20|3|5|10|10|0|1|2|0|0|0|0|0 +## +## Spider Wood +## +*|Giantspider|Dreadspider|Reaper||||1436|960|-22|3|5|10|40|40|1|5|2|2|0|0|0 +## +## Bet-Lem Reg +## +*|Pixie||||||1249|957|-14|3|5|10|10|10|1|5|0|0|0|0|0 +## +## Exit Passage +## +*|Troll||||||1360|888|-21|3|5|10|40|10|1|3|0|0|0|0|0 +## +## Spider Dungeon +## +*|Dreadspider|Giantspider|||||1817|976|-28|3|5|10|45|45|1|7|13|0|0|0|0 +## +## Spider Dungeon Shrine +## +*|Giantspider||||||1504|878|10|3|5|10|20|15|1|4|0|0|0|0|0 +############## +## By Nerun ## +############## +## +## Ilshenar Southwest +## +## The Deuce's Vinculum Inn +## +*|ratmanmage|ratmanarcher|ratman||||664|668|5|3|5|10|10|7|1|1|1|1|0|0|0 +*|ratmanarcher|ratman|||||664|665|-15|3|5|10|10|7|1|2|2|0|0|0|0 +*|ratmanmage|ratman|||||664|665|-35|3|5|10|10|10|1|1|2|0|0|0|0 +## +## Ratman Lair +## +*|ratmanmage|ratmanarcher|ratman||||644|819|-44|3|5|10|25|20|1|3|3|9|0|0|0 +## +## Camps +## +*|Bankercamp||||||961|924|-37|3|5|10|0|0|1|1|0|0|0|0|0 +*|Magecamp||||||567|807|-74|3|5|10|0|0|1|1|0|0|0|0|0 +*|Magecamp||||||830|1206|-70|3|5|10|0|0|1|1|0|0|0|0|0 +## +## Lava Vent / Champ "Humility" +## +*|Ratman|Ratmanmage|Ratmanarcher|Giantspider|Hellhound|Slime|485|891|-82|3|5|10|40|40|1|5|1|2|2|2|2 +*|Jwilson||||||487|890|-82|3|5|10|40|40|1|1|0|0|0|0|0 +## +## Graveyard +## +*|Skeleton|Spectre:Shade:Wraith|Ghoul|Zombie|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|330|881|-73|3|5|10|25|25|1|4|5|1|1|2|4 +*|Lich||||||325|893|-72|3|5|10|10|10|1|1|0|0|0|0|0 +*|Lich||||||366|881|-73|3|5|10|7|7|1|1|0|0|0|0|0 +*|Lichlord||||||338|863|-72|3|5|10|7|7|1|1|0|0|0|0|0 +## +## Undead Fort +## +*|Skeleton|Spectre:Shade:Wraith|Ghoul|Zombie|||353|1140|-54|3|5|10|20|20|1|7|3|2|3|0|0 +*|Shade||||||354|1140|-52|3|5|10|5|5|1|1|0|0|0|0|0 +## +## Nox Tereg +## +*|Swamptentacle|Gianttoad|Alligator|Reaper|Corpser||430|1176|-68|3|5|10|60|60|1|4|12|14|4|6|0 +*|Swamptentacle|Gianttoad|Alligator|Reaper|Corpser||350|1204|-38|3|5|10|40|40|1|2|5|6|2|3|0 +## +## Abandoned Tower Swamp +## +*|Swamptentacle|Gianttoad|Lizardman|Alligator:Reaper:Corpser|||400|1334|-37|3|5|10|70|70|1|5|8|5|0|0|0 +## +## Lizardman Camp +## +*|Lizardman||||||291|1313|-25|3|5|10|30|30|1|7|0|0|0|0|0 +*|Lizardman||||||295|1348|-26|3|5|10|30|30|1|8|0|0|0|0|0 +## +## Lizardman camp / Cave Passage +## +*|Lizardman||||||302|1580|-29|3|5|10|15|10|1|2|0|0|0|0|0 +*|Lizardman||||||325|1576|-28|3|5|10|15|4|1|1|0|0|0|0|0 +## +## Ancient Wyrm's Lair +## +*|Ancientwyrm|Wyvern|Lavalizard||||223|1360|-15|3|5|10|20|20|1|1|2|3|0|0|0 +## +## Elemental Canyon +## +*|Efreet||||||278|1440|15|3|5|10|10|10|1|1|0|0|0|0|0 +*|Fireelemental|Airelemental|Imp||||314|1436|16|3|5|10|25|15|1|1|1|2|0|0|0 +*|Fireelemental|Airelemental|Imp||||350|1441|17|3|5|10|25|15|1|1|1|2|0|0|0 +## +## Dead Forest +## +*|Fireelemental|Airelemental|||||438|1431|15|3|5|10|30|20|1|2|2|0|0|0|0 +## +## Wisp Dungeon Entrance +## +*|Mongbat|Wisp|Imp||||648|1321|-57|3|5|10|25|25|1|6|2|4|0|0|0 +## +## Honesty +## +*|Imp|Gazer|||||722|1354|-61|3|5|10|20|20|1|4|2|0|0|0|0 +## +## Near "Justice" +## +*|Waterelemental||||||913|935|-34|3|5|10|10|10|1|2|0|0|0|0|0 +*|Reaper|Mongbat|Imp||||963|1028|-31|3|5|10|40|20|1|2|4|3|0|0|0 +*|Headlessone|Mongbat|Imp||||935|1159|13|3|5|10|40|20|1|3|3|4|0|0|0 +## +## Cyclopse's Pyramid +## +*|Ettin||||||822|1324|-80|3|5|10|25|25|1|6|0|0|0|0|0 +*|Titan|Cyclops|Ettin||||902|1308|-71|3|5|10|40|35|1|2|4|6|0|0|0 +## +## Non-OSI spawns (animals) +## +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|646|1209|-93|3|5|10|50|40|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|605|1061|-84|3|5|10|55|45|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|564|1142|-99|3|5|10|65|45|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|681|1125|-73|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|703|984|-68|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|605|973|-82|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|514|1225|-66|3|5|10|40|30|1|4|1|2|1|1|1 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|733|1238|-68|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|397|958|-80|3|5|10|70|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|468|874|-80|3|5|10|50|40|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|630|828|-55|3|5|10|110|85|1|7|3|4|4|4|3 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|588|674|-60|3|5|10|100|75|1|7|3|4|4|4|3 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Ratmancave.map b/Data/Monsters/ilshenar/Ratmancave.map new file mode 100644 index 0000000..b4c7794 --- /dev/null +++ b/Data/Monsters/ilshenar/Ratmancave.map @@ -0,0 +1,19 @@ +############## +## By Nerun ## +############## +overrideid 307 +overridemintime 5 +overridemaxtime 10 +## +## Ratman Cave +## +## Level 1 +## +*|Ratman|Ratmanmage|Earthelemental||||1310|1519|-28|3|5|10|50|50|1|7|7|7|0|0|0 +## +## Level 2 +## +*|Skeletalknight:Boneknight|Lavalizard|||||1224|1524|-28|3|5|10|30|30|1|5|5|0|0|0|0 +*|Skeletalknight:Boneknight|Lavalizard|||||1224|1494|-28|3|5|10|30|30|1|5|5|0|0|0|0 +*|Skeletaldragon||||||1181|1512|-68|3|5|10|10|10|1|1|0|0|0|0|0 +*|TreasureLevel3:TreasureLevel4||||||1171|1511|-68|3|5|10|5|5|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Rock.map b/Data/Monsters/ilshenar/Rock.map new file mode 100644 index 0000000..617c9b5 --- /dev/null +++ b/Data/Monsters/ilshenar/Rock.map @@ -0,0 +1,28 @@ +############## +## By Nerun ## +############## +overrideid 308 +overridemintime 5 +overridemaxtime 10 +## +## Rock Dungeon +## +## Level 1 +## +*|Skeleton:Wraith:Zombie||||||2188|310|-7|3|5|10|15|10|1|3|0|0|0|0|0 +## +## Level 2 +## +*|ToxicElemental||||||2220|75|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|StoneGargoyle||||||2207|113|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|TreasureLevel4||||||2185|168|-32|3|5|10|10|5|1|1|0|0|0|0|0 +*|EvilMage:Executioner||||||2229|143|-32|3|5|10|10|5|1|2|0|0|0|0|0 +*|Lich||||||2154|163|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|EvilMage:Executioner||||||2125|165|-32|3|5|10|10|5|1|2|0|0|0|0|0 +*|Lich||||||2125|137|-32|3|5|10|10|5|1|1|0|0|0|0|0 +*|ElderGazer||||||2138|97|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|EvilMage|EvilMageLord|||||2183|85|-32|3|5|10|10|5|1|1|1|0|0|0|0 +*|PoisonElemental:LichLord||||||2155|24|-32|3|5|10|10|5|1|2|0|0|0|0|0 +*|PoisonElemental:Lich|LichLord|||||2124|96|-32|3|5|10|15|8|1|2|1|0|0|0|0 +*|Executioner||||||2094|56|-32|3|5|10|10|5|1|1|0|0|0|0|0 +*|HellHound|LichLord|||||2127|29|-32|3|5|10|10|5|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Sorcerers.map b/Data/Monsters/ilshenar/Sorcerers.map new file mode 100644 index 0000000..5513abf --- /dev/null +++ b/Data/Monsters/ilshenar/Sorcerers.map @@ -0,0 +1,49 @@ +############## +## By Nerun ## +############## +overrideid 309 +overridemintime 5 +overridemaxtime 10 +## +## Sorcerers Dungeon +## +## Level 1 +## +*|Zombie||||||427|67|-28|3|5|10|25|25|1|2|0|0|0|0|0 +*|Toxicelemental:Fireelemental:Bloodelemental||||||455|70|-28|3|5|10|10|7|1|5|0|0|0|0|0 +*|Shade|Mongbat|||||394|69|-28|3|5|10|15|10|1|2|5|0|0|0|0 +*|Gargoyle|Stonegargoyle|Lich|Shade|||447|19|-28|3|5|10|25|10|1|3|1|1|1|0|0 +*|Headlessone|Mongbat|||||431|16|-28|3|5|10|15|5|1|2|2|0|0|0|0 +*|Headlessone|Mongbat|||||462|16|-28|3|5|10|15|5|1|2|2|0|0|0|0 +*|Earthelemental||||||462|16|-28|3|5|10|15|5|1|2|0|0|0|0|0 +*|Bloodelemental||||||383|29|-28|3|5|10|10|5|1|1|0|0|0|0|0 +*|Skeleton|Boneknight|||||427|95|-28|3|5|10|15|10|1|4|2|0|0|0|0 +## +## Level 2 +## +*|Bloodelemental||||||254|20|-28|3|5|10|10|5|1|1|0|0|0|0|0 +*|Eldergazer|Gazer|Gazerlarva||||281|20|-28|3|5|10|15|10|1|1|4|2|0|0|0 +*|Balron|Daemon|||||238|48|-28|3|5|10|10|7|1|1|2|0|0|0|0 +*|Imp||||||214|67|-28|3|5|10|40|15|1|4|0|0|0|0|0 +*|Shade|Zombie|Dreadspider||||262|84|-28|3|5|10|25|15|1|1|1|1|0|0|0 +*|Gargoyle|Wyvern|Evilmage||||262|84|-28|3|5|10|15|15|1|2|1|3|0|0|0 +*|Hellhound|Bloodelemental|||||278|53|-28|3|5|10|20|10|1|6|1|0|0|0|0 +*|Dullcopperelemental||||||305|20|-28|3|5|10|20|10|1|5|0|0|0|0|0 +*|Lichlord||||||310|92|-13|3|5|10|20|20|1|2|0|0|0|0|0 +*|Poisonelemental|Bloodelemental|||||311|91|-13|3|5|10|20|20|1|1|1|0|0|0|0 +*|Gargoyle||||||336|37|-28|3|5|10|10|8|1|2|0|0|0|0|0 +*|Gargoyle||||||336|48|-28|3|5|10|10|8|1|2|0|0|0|0|0 +*|Lich:Shade||||||336|42|-28|3|5|10|15|8|1|1|0|0|0|0|0 +*|Bloodelemental||||||350|42|-28|3|5|10|10|10|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Bloodelemental||||||146|83|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Evilmagelord||||||143|70|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||160|59|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Balron|Eldergazer|||||155|21|-28|3|5|10|15|10|1|2|1|0|0|0|0 +*|Efreet||||||160|9|-28|3|5|10|5|4|1|2|0|0|0|0|0 +*|Bonemagi:Skeletalmage|Mummy|||||109|44|-28|3|5|10|20|15|1|4|3|0|0|0|0 +*|Lichlord|Mummy|||||67|70|-28|3|5|10|15|15|1|2|4|0|0|0|0 +*|Boneknight:Skeletalknight||||||133|114|-28|3|5|10|25|20|1|1|0|0|0|0|0 +*|Bloodelemental||||||133|114|-28|3|5|10|20|10|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Spectre.map b/Data/Monsters/ilshenar/Spectre.map new file mode 100644 index 0000000..f9f172b --- /dev/null +++ b/Data/Monsters/ilshenar/Spectre.map @@ -0,0 +1,12 @@ +############## +## By Nerun ## +############## +overrideid 310 +overridemintime 5 +overridemaxtime 10 +## +## Spectre Dungeon +## +## Level 1 +## +*|Skeleton|Shade|Spectre|Wraith|Ghoul|Zombie|1981|1059|-28|3|5|10|40|40|1|3|2|2|2|2|2 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Towns.map b/Data/Monsters/ilshenar/Towns.map new file mode 100644 index 0000000..b081ab3 --- /dev/null +++ b/Data/Monsters/ilshenar/Towns.map @@ -0,0 +1,69 @@ +############## +## By Nerun ## +############## +overrideid 311 +overridemintime 5 +overridemaxtime 10 +## +## Towns +## +## Ancient Citadel +## +*|Skeleton||||||1517|558|5|3|5|10|35|20|1|6|0|0|0|0|0 +*|Spectre:Shade:Wraith||||||1517|552|10|3|5|10|30|15|1|6|0|0|0|0|0 +*|Ghoul|Zombie|||||1516|557|4|3|5|10|35|20|1|2|5|0|0|0|0 +*|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|||||1517|552|10|3|5|10|30|15|1|3|3|0|0|0|0 +*|Lich||||||1517|541|11|3|5|10|20|10|1|2|0|0|0|0|0 +*|Lichlord||||||1517|541|61|3|5|10|10|4|1|1|0|0|0|0|0 +## +## Lakeshire +## +*|MeerWarrior:MeerCaptain:MeerMage:MeerEternal||||||1203|1138|-25|3|5|10|55|40|1|16|0|0|0|0|0 +*|Direwolf:Timberwolf||||||1127|1112|-34|3|5|10|35|25|1|7|0|0|0|0|0 +*|Snake||||||1180|1188|-25|3|5|10|15|15|1|5|0|0|0|0|0 +*|Giantserpent||||||1181|1189|-25|3|5|10|12|12|1|1|0|0|0|0|0 +## +## Mistas +## +*|Ogre|Ogrelord|Ratman|Ratmanmage|Ratmanarcher||817|1065|-30|3|5|10|70|60|1|5|2|10|5|4|0 +## +## Montor +## +*|Phoenix|Fireelemental|Hellhound|Lavaserpent|Lavalizard|Daemon|1643|310|48|3|5|10|50|30|1|2|4|5|4|4|2 +*|Succubus|Efreet|||||1643|310|48|3|5|10|50|30|1|2|2|0|0|0|0 +*|Earthelemental|Drake|||||1665|244|93|3|5|10|25|25|1|3|2|0|0|0|0 +*|Stoneharpy|Stonegargoyle|Balron||||1715|228|78|3|5|10|10|10|1|3|2|1|0|0|0 +## +## Req Volon +## +*|Etherealwarrior||||||1363|1046|-13|3|5|10|30|15|1|4|0|0|0|0|0 +## +## Savage Camp 1 +## +*|savagerider|savage|||||1046|517|-80|3|5|10|15|15|1|3|4|0|0|0|0 +*|savageshaman||||||1046|517|-80|3|5|10|10|7|1|4|0|0|0|0|0 +*|savage|savageridgeback|||||1116|527|-80|3|5|10|15|15|1|1|1|0|0|0|0 +*|bird||||||1110|542|-77|3|5|10|25|25|1|3|0|0|0|0|0 +*|bird||||||1108|492|-80|3|5|10|25|25|1|3|0|0|0|0|0 +*|hind|greathart|blackbear|direwolf|||1110|542|-77|3|5|10|25|25|1|2|1|1|1|0|0 +*|hind|greathart|blackbear|direwolf|||1108|492|-80|3|5|10|25|25|1|2|1|1|1|0|0 +## +## Savage Camp 2 +## +*|savage||||||1161|668|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|savage||||||1181|691|-80|3|5|10|4|4|1|1|0|0|0|0|0 +*|savage||||||1187|685|-80|3|5|10|4|4|1|1|0|0|0|0|0 +*|savage||||||1191|696|-80|3|5|10|7|5|1|1|0|0|0|0|0 +*|savagerider||||||1191|696|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|savage||||||1203|762|-80|3|5|10|10|10|1|3|0|0|0|0|0 +*|savageshaman||||||1234|760|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|savage|savagerider|||||1213|719|-80|3|5|10|10|10|1|3|1|0|0|0|0 +*|savage||||||1214|744|-80|3|5|10|10|10|1|4|0|0|0|0|0 +*|savage|savageshaman|||||1231|694|-80|3|5|10|10|10|1|2|1|0|0|0|0 +*|savage||||||1251|703|-80|3|5|10|10|10|1|3|0|0|0|0|0 +*|savage||||||1274|728|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|savage||||||1292|755|-80|3|5|10|4|4|1|1|0|0|0|0|0 +*|savage||||||1280|770|-80|3|5|10|7|7|1|1|0|0|0|0|0 +*|ridgeback||||||1279|781|-80|3|5|10|5|5|1|2|0|0|0|0|0 +*|savage|savageshaman|savagerider||||1243|732|-80|3|5|10|10|10|1|1|3|1|0|0|0 +*|savage||||||1262|758|-80|3|5|10|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/TwistedWeald.map b/Data/Monsters/ilshenar/TwistedWeald.map new file mode 100644 index 0000000..345cc58 --- /dev/null +++ b/Data/Monsters/ilshenar/TwistedWeald.map @@ -0,0 +1,25 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 314 +overridemap 3 +overridemintime 5 +overridemaxtime 10 +## +## Twisted Weald +## +*|CuSidhe:DryadA:Changeling:Satyr|DireWolf|||||2171|1181|-44|3|5|10|20|20|1|8|2|0|0|0|0 +*|LadyLissith:LadySabrix||||||2177|1210|-60|3|5|10|10|10|1|2|0|0|0|0|0 +*|Quagmire:WhippingVine:Irk||||||2138|1212|-60|3|5|10|20|20|1|8|0|0|0|0|0 +*|Swoop||||||2224|1218|13|3|5|10|8|8|1|1|0|0|0|0|0 +*|Gnaw:DireWolf||||||2134|1174|-46|3|5|10|5|5|1|5|0|0|0|0|0 +*|CuSidhe||||||2206|1220|-8|3|5|10|20|20|1|2|0|0|0|0|0 +*|Corpser:spite:guile||||||2159|1223|-60|3|5|10|10|10|1|5|0|0|0|0|0 +*|Malefic:Virulent||||||2170|1247|-60|3|5|10|10|10|1|4|0|0|0|0|0 +*|Changeling||||||2163|1189|-48|3|5|10|8|8|1|2|0|0|0|0|0 +*|Cusidhe:Dryada:changeling:Satyr|DireWolf|||||2207|1180|-36|3|5|10|25|25|1|12|3|0|0|0|0 +*|silk||||||2137|1216|-60|3|5|10|5|5|1|4|0|0|0|0|0 +*|giantblackwidow||||||2177|1229|-60|3|5|10|5|5|1|4|0|0|0|0|0 +*|virulent||||||2157|1206|-60|3|5|10|5|5|1|3|0|0|0|0|0 +*|malefic||||||2167|1266|-60|3|5|10|5|5|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Vendors.map b/Data/Monsters/ilshenar/Vendors.map new file mode 100644 index 0000000..bcb35b0 --- /dev/null +++ b/Data/Monsters/ilshenar/Vendors.map @@ -0,0 +1,55 @@ +############## +## By Nerun ## +############## +overrideid 312 +overridemintime 5 +overridemaxtime 10 +## +*|stonecrafter||||||791|618|0|3|2|10|5|0|314|1|0|0|0|0|0 +*|armorer|weaponsmith|||||808|697|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|armorer|weaponsmith|||||808|586|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|gypsyanimaltrainer||||||1225|563|-18|3|2|10|5|0|314|1|0|0|0|0|0 +*|gypsyanimaltrainer||||||1388|428|-23|3|2|10|5|0|314|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1497|614|-14|3|2|10|5|0|314|1|1|0|0|0|0 +*|banker|minter|||||854|680|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|banker|minter|||||855|603|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||766|641|0|3|2|10|5|0|314|1|1|0|0|0|0 +*|gypsybanker||||||1226|554|-12|3|2|10|5|0|314|1|0|0|0|0|0 +*|banker|minter|||||1610|556|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|provisioner|cobbler|||||826|679|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|provisioner|cobbler|||||824|602|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|gypsymaiden||||||1400|434|-11|3|2|10|5|0|314|1|0|0|0|0|0 +*|innkeeper||||||665|665|-35|3|2|10|5|0|314|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1364|1051|-13|3|2|10|5|0|314|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1261|582|-18|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||284|536|-24|3|2|10|5|0|314|1|1|0|0|0|0 +*|fortuneteller||||||1235|543|-15|3|2|10|5|0|314|1|0|0|0|0|0 +*|fortuneteller||||||1407|428|-8|3|2|10|5|0|314|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1628|548|-11|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1518|619|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1093|955|-38|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||872|586|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|innkeeper||||||1620|554|-20|3|2|10|5|0|314|1|0|0|0|0|0 +*|jeweler||||||1605|541|-13|3|2|10|5|0|314|1|0|0|0|0|0 +*|jeweler||||||859|698|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|scribe||||||868|657|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|scribe||||||869|625|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|gypsybanker||||||1405|439|2|3|2|10|5|0|314|1|0|0|0|0|0 +*|fortuneteller||||||1394|441|13|3|2|10|5|0|314|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1505|611|-19|3|2|10|5|0|314|1|1|1|0|0|0 +*|innkeeper||||||774|1144|-30|3|2|10|5|0|314|1|0|0|0|0|0 +*|provisioner|cobbler|||||1598|539|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||369|1432|15|3|2|10|5|0|314|1|1|0|0|0|0 +*|provisioner|cobbler|||||1318|1328|-14|3|2|10|5|0|314|1|1|0|0|0|0 +*|tailor|weaver|||||896|610|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|tailorguildmaster||||||896|610|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|animaltrainer||||||1499|619|-19|3|2|10|5|0|314|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1600|552|-16|3|2|10|5|0|314|1|1|1|0|0|0 +*|mage|glassblower|mageguildmaster||||840|571|0|3|2|10|5|0|314|1|1|1|0|0|0 +*|innkeeper||||||840|707|0|3|2|10|5|0|314|1|0|0|0|0|0 +*|tinker|tinkerguildmaster|||||1253|588|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|innkeeper||||||1566|1049|-8|3|2|10|5|0|314|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||792|665|0|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||575|537|-69|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||682|297|-41|3|2|10|5|0|314|1|1|0|0|0|0 +*|baker||||||1514|611|-14|3|2|10|5|0|314|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/ilshenar/Wisp.map b/Data/Monsters/ilshenar/Wisp.map new file mode 100644 index 0000000..40cabeb --- /dev/null +++ b/Data/Monsters/ilshenar/Wisp.map @@ -0,0 +1,53 @@ +############## +## By Nerun ## +############## +overrideid 313 +overridemintime 5 +overridemaxtime 10 +## +## Wisp Dungeon +## +## Level 1 +## +*|Wisp||||||681|1535|-28|3|5|10|60|40|1|20|0|0|0|0|0 +## +## Level 2 +## +## no monsters +## +## Level 3 +## +*|Skeletalmage||||||855|1567|-28|3|5|10|6|6|1|1|0|0|0|0|0 +*|Shade||||||855|1566|-28|3|5|10|10|6|1|1|0|0|0|0|0 +*|Rottingcorpse||||||851|1498|-28|3|5|10|20|5|1|1|0|0|0|0|0 +*|Shade|Boneknight|Bonemagi||||827|1479|-28|3|5|10|15|10|1|2|2|2|0|0|0 +*|Shade|Boneknight|Bonemagi||||888|1471|-28|3|5|10|20|12|1|3|3|2|0|0|0 +*|Evilmagelord||||||901|1507|2|3|5|10|10|10|1|2|0|0|0|0|0 +*|Evilmage||||||871|1531|-28|3|5|10|10|6|1|3|0|0|0|0|0 +*|Rottingcorpse||||||891|1537|-28|3|5|10|10|6|1|1|0|0|0|0|0 +*|Evilmage|Evilmagelord|||||888|1568|-28|3|5|10|15|10|1|1|2|0|0|0|0 +## +## Level 4 +## +## no monsters +## +## Level 5 +## +*|Imp||||||939|1531|-28|3|5|10|10|5|1|2|0|0|0|0|0 +*|Imp||||||939|1492|-28|3|5|10|10|5|1|1|0|0|0|0|0 +*|Ettin||||||961|1502|-28|3|5|10|10|6|1|2|0|0|0|0|0 +*|Wraith:Spectre:Shade||||||962|1480|-28|3|5|10|15|10|1|4|0|0|0|0|0 +*|Titan|Cyclops|||||1000|1512|0|3|5|10|15|15|1|2|3|0|0|0|0 +*|Lich||Wraith:Spectre:Shade||||959|1530|-28|3|5|10|10|7|1|1|2|0|0|0|0 +*|Balron||||||936|1559|-22|3|5|10|25|10|1|1|0|0|0|0|0 +*|Lichlord||||||964|1554|-28|3|5|10|10|7|1|1|0|0|0|0|0 +## +## Level 6 and 7 +## +## no monsters +## +## Level 8 +## +*|Balron||||||775|1479|-28|3|5|10|15|15|1|2|0|0|0|0|0 +*|Imp||||||775|1480|-28|3|5|10|40|40|1|5|0|0|0|0|0 +*|TreasureLevel1:TreasureLevel2|TreasureLevel3:TreasureLevel4|||||776|1480|-28|3|30|60|3|3|1|9|6|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/Citadel.map b/Data/Monsters/malas/Citadel.map new file mode 100644 index 0000000..c65a498 --- /dev/null +++ b/Data/Monsters/malas/Citadel.map @@ -0,0 +1,26 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 406 +overridemap 4 +overridemintime 5 +overridemaxtime 10 +## +## Citadel +## +*|serpentsfangassassin:tigersclawthief||||||179|1869|0|4|5|10|10|10|1|4|0|0|0|0|0 +*|magedragonsflamemage||||||185|1920|0|4|5|10|7|7|1|2|0|0|0|0|0 +*|serpentsfangassassin:dragonsflamemage||||||155|1869|0|4|5|10|10|10|1|4|0|0|0|0|0 +*|serpentsfangassassin:tigersclawthief:eliteninjawarrior||||||145|1898|0|4|5|10|25|25|1|3|0|0|0|0|0 +*|serpentsfangassassin:dragonsflamemage:eliteninjawarrior||||||174|1900|0|4|5|10|20|20|1|5|0|0|0|0|0 +*|serpentsfangassassin:tigersclawthief:dragonsflamemage:eliteninjawarrior||||||181|1883|0|4|5|10|5|5|1|8|0|0|0|0|0 +*|dragonsflamemage:serpentsfangassassin||||||183|1961|0|4|5|10|20|20|1|2|0|0|0|0|0 +*|serpentsfangassassin:tigersclawthief:magedragonsflamemage:dragonsflamemage:eliteninjawarrior||||||139|1868|0|4|5|10|8|8|1|7|0|0|0|0|0 +*|serpentsfangassassin:serpentsfanghighexecutioner||||||170|1974|0|4|5|10|5|5|1|3|0|0|0|0|0 +*|magedragonsflamemage:serpentsfangassassin||||||140|1974|0|4|5|10|8|8|1|2|0|0|0|0|0 +*|magedragonsflamemage:dragonsflamemage||||||134|1947|0|4|5|10|7|7|1|2|0|0|0|0|0 +*|eliteninjawarrior:serpentsfangassassin:dragonsflamemage||||||81|1892|0|4|5|10|5|5|1|4|0|0|0|0|0 +*|tigersclawthief||||||142|1921|0|4|5|10|5|5|1|4|0|0|0|0|0 +*|dragonsflamemage:eliteninjawarrior||||||77|1883|0|4|5|10|5|5|1|4|0|0|0|0|0 +*|serpentsfangassassin:eliteninjawarrior||||||82|1875|0|4|5|10|5|5|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/Doom.map b/Data/Monsters/malas/Doom.map new file mode 100644 index 0000000..76473bf --- /dev/null +++ b/Data/Monsters/malas/Doom.map @@ -0,0 +1,57 @@ +####################### +## By Matador Doid�o ## +## Adapted by Nerun ## +####################### +overrideid 401 +## +## Dungeon Doom +## +## Doom Main +## +*|patchworkskeleton|vampirebat|||||379|147|-1|4|1|2|40|40|1|10|10|0|0|0|0 +*|skeleton|boneknight|||||372|201|-1|4|1|2|20|20|1|3|1|0|0|0|0 +*|bonedemon||||||442|205|-1|4|20|40|30|30|1|1|0|0|0|0|0 +*|patchworkskeleton|vampirebat|||||442|205|-1|4|1|2|30|30|1|6|5|0|0|0|0 +*|lich||||||480|227|-1|4|3|5|20|20|1|2|0|0|0|0|0 +*|lichlord||||||480|227|-1|4|5|10|20|20|1|1|0|0|0|0|0 +*|skeleton||||||480|227|-1|4|1|2|20|20|1|3|0|0|0|0|0 +*|skeleton||||||493|202|-1|4|1|2|12|12|1|6|0|0|0|0|0 +*|devourer|boneknight|||||479|168|-1|4|2|3|20|20|1|3|1|0|0|0|0 +*|skeleton||||||479|168|-1|4|1|2|20|20|1|5|0|0|0|0|0 +*|lich||||||468|141|-1|4|1|3|6|6|1|2|0|0|0|0|0 +*|skeleton|mummy|||||487|118|-1|4|1|2|8|8|1|3|2|0|0|0|0 +*|patchworkskeleton||||||496|75|0|4|1|2|8|8|1|3|0|0|0|0|0 +*|vampirebat||||||496|75|0|4|1|2|10|10|1|4|0|0|0|0|0 +*|skeleton||||||447|25|-1|4|1|2|10|10|1|6|0|0|0|0|0 +*|lich||||||447|25|-1|4|1|2|15|15|1|2|0|0|0|0|0 +*|patchworkskeleton|lich|||||470|30|-2|4|1|2|20|20|1|4|2|0|0|0|0 +*|fleshgolem|devourer|||||456|48|-1|4|1|2|15|15|1|6|6|0|0|0|0 +*|vampirebat||||||395|33|-1|4|1|2|8|8|1|4|0|0|0|0|0 +*|vampirebat|skeleton|||||356|40|-1|4|1|2|8|8|1|4|2|0|0|0|0 +*|gibberling||||||305|28|0|4|1|2|10|10|1|4|0|0|0|0|0 +*|gorefiend||||||290|28|0|4|1|2|10|10|1|4|0|0|0|0|0 +*|lichlord||||||266|26|0|4|1|2|8|5|1|2|0|0|0|0|0 +*|skeleton|bonemagi|boneknight||||309|15|0|4|1|2|10|10|1|4|2|1|0|0|0 +*|lich||||||366|13|-1|4|1|2|10|10|1|3|0|0|0|0|0 +*|skeleton|patchworkskeleton|||||323|90|-1|4|1|2|40|40|1|4|5|0|0|0|0 +*|zombie||||||320|114|-1|4|1|2|35|35|1|7|0|0|0|0|0 +*|mummy||||||320|114|-1|4|1|2|25|25|1|3|0|0|0|0|0 +*|lich||||||330|136|0|4|1|2|15|15|1|2|0|0|0|0|0 +*|lichlord||||||330|136|0|4|1|2|4|4|1|1|0|0|0|0|0 +*|patchworkskeleton|vampirebat|||||325|172|-1|4|1|2|35|35|1|3|3|0|0|0|0 +*|lichlord||||||289|154|5|4|1|2|5|5|1|1|0|0|0|0|0 +*|devourer||||||278|233|0|4|1|2|35|35|1|3|0|0|0|0|0 +*|patchworkskeleton|vampirebat|||||278|233|0|4|1|2|30|30|1|2|2|0|0|0|0 +*|lich||||||320|207|-1|4|1|2|15|15|1|2|0|0|0|0|0 +*|skeleton||||||356|234|-1|4|1|2|10|10|1|3|0|0|0|0|0 +*|devourer||||||356|234|-1|4|1|2|15|15|1|3|0|0|0|0|0 +*|devourer||||||378|236|-1|4|1|2|8|8|1|2|0|0|0|0|0 +*|lichlord|restlesssoul|||||427|256|-1|4|1|2|30|30|1|1|3|0|0|0|0 +*|rottingcorpse||||||427|256|-1|4|1|2|30|10|1|2|0|0|0|0|0 +*|rottingcorpse||||||478|206|-1|4|1|2|20|20|1|2|0|0|0|0|0 +*|patchworkskeleton|vampirebat|rottingcorpse||||443|128|-1|4|1|2|40|40|1|7|7|2|0|0|0 +*|lich||||||400|174|-1|4|1|2|5|5|1|1|0|0|0|0|0 +*|skeleton||||||287|81|-1|4|1|2|30|30|1|6|0|0|0|0|0 +*|vampirebat|rottingcorpse|||||287|81|-1|4|1|2|40|40|1|6|2|0|0|0|0 +*|patchworkskeleton|rottingcorpse|||||441|78|-1|4|1|2|30|30|1|4|2|0|0|0|0 +*|vampirebat||||||382|82|-1|4|1|2|40|40|1|6|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/Labyrinth.map b/Data/Monsters/malas/Labyrinth.map new file mode 100644 index 0000000..1b6e7b0 --- /dev/null +++ b/Data/Monsters/malas/Labyrinth.map @@ -0,0 +1,28 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 407 +overridemap 4 +overridemintime 5 +overridemaxtime 10 +## +## Labyrinth +## +*|drake:airelemental|rat:snake|||||366|1928|0|4|5|10|20|20|1|4|4|0|0|0|0 +*|minotaur|snake|||||384|1932|10|4|5|10|10|10|1|3|2|0|0|0|0 +*|miasma||||||335|1920|0|4|5|10|5|5|1|1|0|0|0|0|0 +*|wanderinghealer||||||1740|990|-80|4|5|10|15|15|1|1|0|0|0|0|0 +*|Scorpion|Snake|||||1742|990|-84|4|5|10|12|12|1|6|4|0|0|0|0 +*|minotaur:minotaurscout||||||336|1891|0|4|5|10|12|12|1|5|0|0|0|0|0 +*|rend||||||357|1898|5|4|5|10|10|10|1|1|0|0|0|0|0 +*|squirrel:rat||||||346|1959|0|4|5|10|10|10|1|4|0|0|0|0|0 +*|minotaurscout:minotaur:minotaurcaptain|squirrel:tropicalbird:bird:cat|||||392|1917|0|4|5|10|20|20|1|11|9|0|0|0|0 +*|eagle:cat:bird:tropicalbird||||||390|1883|0|4|5|10|10|10|1|8|0|0|0|0|0 +*|reptalon:minotaur||||||355|1918|0|4|5|10|20|20|1|6|0|0|0|0|0 +*|tropicalbird:bird||||||346|1910|0|4|5|10|12|12|1|6|0|0|0|0|0 +*|minotaurcaptain:minotaur:minotaurscout|rat:tropicalbird|||||427|1923|5|4|5|10|15|15|1|6|4|0|0|0|0 +*|tropicalbird:eagle:rat:bird|minotaurscout|||||348|1948|0|4|5|10|15|15|1|12|4|0|0|0|0 +*|pyre||||||415|1897|5|4|5|10|5|5|1|1|0|0|0|0|0 +*|flurry:grim:mistral:tempest||||||347|1888|5|4|5|10|20|20|1|4|0|0|0|0|0 +*|meraktus||||||382|1913|0|4|5|10|5|5|1|0|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/North.map b/Data/Monsters/malas/North.map new file mode 100644 index 0000000..5c52d4f --- /dev/null +++ b/Data/Monsters/malas/North.map @@ -0,0 +1,41 @@ +############## +## By Nerun ## +############## +overrideid 402 +overridemintime 5 +overridemaxtime 10 +## +## North Malas +## +## Crystal Forest +## +## birds = mutatch, nightingale and finch +*|bird|greathart|jackrabbit|hind|||1119|530|-90|4|5|10|60|39|1|10|1|10|1|0|0 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|JackRabbit|1674|659|-84|4|5|10|120|100|1|3|3|3|2|1|3 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|JackRabbit|1434|607|-89|4|5|10|120|100|1|3|3|3|2|1|3 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|JackRabbit|1194|638|-84|4|5|10|120|100|1|4|4|4|3|1|4 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|JackRabbit|920|356|-85|4|5|10|70|60|1|4|4|4|3|1|4 +## +## Ice Caves +## +## birds = kingfisher and swifts +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1659|112|-80|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1869|480|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|2121|597|-50|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1980|660|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|2233|555|-90|4|5|10|60|60|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1137|223|-50|4|5|10|40|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1381|340|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1710|403|-50|4|5|10|40|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|766|114|-90|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1206|191|-50|4|5|10|40|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|2030|500|-50|4|5|10|70|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1482|347|-50|4|5|10|60|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1023|192|-50|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1274|300|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1587|386|-50|4|5|10|40|40|1|2|1|1|1|1|1 +## +## Other +## +*|Unicorn||||||2205|145|-90|4|5|10|50|50|1|3|0|0|0|0|0 +*|Gorefiend||||||2291|295|-90|4|5|10|60|60|1|6|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/OrcForts.map b/Data/Monsters/malas/OrcForts.map new file mode 100644 index 0000000..4afa0ef --- /dev/null +++ b/Data/Monsters/malas/OrcForts.map @@ -0,0 +1,29 @@ +overrideid 403 +overridemintime 5 +overridemaxtime 15 +## +## Orc Forts Malas +## +## Main Orc Fort (Near Hanse's Hotel) +*|orc||||||1343|1248|-90|4|5|10|4|4|1|2|0|0|0|0|0 +*|orc||||||1343|1196|-90|4|5|10|4|4|1|2|0|0|0|0|0 +*|orcbrute|orcishlord|orc|orcishmage|orcbomber||1372|1225|-90|4|5|15|40|20|1|1|2|4|2|1|0 +*|orcbrute|orcishlord|orc|orcishmage|orcbomber||1322|1225|-90|4|5|15|40|20|1|1|2|4|2|1|0 +## +## North +## +## Orc Fort #1 +*|orc|orcishlord|orcishmage||||911|194|-79|4|5|15|15|4|1|2|1|1|0|0|0 +## Orc Fort #2 +*|orc|orcishlord|orcishmage||||1665|356|-50|4|5|15|25|4|1|2|1|1|0|0|0 +## Orc Fort #3 +*|orc|orcishlord|orcishmage||||1364|596|-86|4|5|15|15|4|1|2|1|1|0|0|0 +## Orc Fort #4 +*|orc|orcishlord|orcishmage||||1205|700|-88|4|5|15|20|4|1|2|1|1|0|0|0 +## +##South +## +## Orc Fort #5 +*|orc|orcishlord|orcishmage||||1257|1326|-90|4|5|15|15|4|1|2|1|1|0|0|0 +## Orc Fort #6 +*|orc|orcishlord|orcishmage||||1598|1819|-110|4|5|15|15|4|1|2|1|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/South.map b/Data/Monsters/malas/South.map new file mode 100644 index 0000000..ad0d711 --- /dev/null +++ b/Data/Monsters/malas/South.map @@ -0,0 +1,63 @@ +############## +## By Nerun ## +############## +overrideid 404 +overridemintime 5 +overridemaxtime 10 +## +## South Malas +## +*|wanderinghealer|ghoul|ogre|reaper|gargoyle:harpy|earthelemental:fireelemental|1920|1124|-90|4|5|10|140|120|1|1|15|15|15|15|10 +*|Brownbear:Grizzlybear:Blackbear|Cougar:Panther|Direwolf:Timberwolf:Greywolf|Bird:Eagle|jackrabbit:rabbit|hind:greathart|1920|1124|-90|4|5|10|140|120|1|5|5|5|5|8|4 +*|wanderinghealer|ghoul|ogre|reaper|gargoyle:harpy|Nightmare|2266|1218|-85|4|5|10|180|150|1|1|25|25|25|25|1 +*|Brownbear:Grizzlybear:Blackbear|Cougar:Panther|Direwolf:Timberwolf:Greywolf|Bird:Eagle|jackrabbit:rabbit|hind:greathart|2267|1218|-85|4|5|10|180|150|1|5|5|5|5|8|4 +*|corpser|ogre|earthelemental:fireelemental|wraith|zombie|gorilla|2303|1258|-86|4|5|10|70|70|1|6|4|4|4|4|4 +*|ettin|reaper|headlessone|troll|ghoul|wanderinghealer|2304|1258|-86|4|5|10|70|70|1|4|4|4|4|4|1 +# Open desert +*|sandvortex|scorpion|snake|desertostard|||1641|1797|-110|4|5|10|100|100|1|1|2|4|1|0|0 +*|sandvortex|scorpion|snake|desertostard|||1899|1609|-110|4|5|10|100|100|1|1|2|4|1|0|0 +*|sandvortex|scorpion|snake|desertostard|||1741|1487|-110|4|5|10|100|100|1|1|2|4|1|0|0 +*|sandvortex|scorpion|snake|desertostard|||1837|1803|-110|4|5|10|100|100|1|1|2|4|1|0|0 +# Inside Pyramid +*|skeletalknight:boneknight|zombie|skeleton|skeleton|sphynx||1823|1799|-90|4|5|10|15|4|1|2|3|1|1|1|0 +*|giantrat|mummy|zombie:skeleton||||1821|1798|-110|4|5|10|15|4|1|4|2|3|0|0|0 +# desert mitochondria-shaped +*|mongbat|sandvortex|scorpion|snake|spectre||2231|1605|-95|4|5|10|160|160|1|7|6|7|6|7|0 +## Snowy Forest at E, SE and S of Main Orc Forest +*|hind:greathart|vampirebat|skitteringhopper|treefellow|||1466|1418|-90|4|5|10|150|120|1|10|10|10|3|0|0 +*|hind:greathart|vampirebat|skitteringhopper|treefellow|||1477|1241|-85|4|5|10|70|50|1|2|3|1|1|0|0 +*|hind:greathart|vampirebat|skitteringhopper|sheep|||1347|1739|-110|4|5|10|130|130|1|3|1|1|6|0|0 +## Around Main Orc Fort +*|hind:greathart|vampirebat|skitteringhopper||||1327|1146|-90|4|5|10|70|35|1|1|1|1|0|0|0 +*|hind:greathart|vampirebat|skitteringhopper||||1256|1221|-90|4|5|10|70|35|1|1|1|1|0|0|0 +*|hind:greathart|vampirebat|skitteringhopper||||1345|1314|-85|4|5|10|70|50|1|1|1|1|0|0|0 +## Brigand Camp (NW from Hanse's Hotel) +*|brigand||||||943|1150|-90|4|5|10|20|10|1|6|0|0|0|0|0 +## Snowy forest behind Hanse's Hotel +*|hind:greathart|vampirebat|skitteringhopper||||900|1494|-90|4|5|10|26|26|1|1|1|1|0|0|0 +*|hind:greathart|vampirebat|skitteringhopper||||829|1474|-85|4|5|10|30|30|1|1|1|1|0|0|0 +*|hind:greathart|vampirebat|skitteringhopper||||989|1419|-82|4|5|10|50|40|1|1|1|1|0|0|0 +*|hind:greathart|vampirebat|skitteringhopper||||913|1335|-90|4|5|10|36|36|1|1|1|1|0|0|0 +## Pixies Tree +*|pixie||||||881|927|-90|4|5|10|30|15|1|6|0|0|0|0|0 +*|pixie||||||882|1000|-90|4|5|10|40|15|1|6|0|0|0|0|0 +*|pixie||||||989|1420|-82|4|5|10|40|15|1|6|0|0|0|0|0 +*|pixie||||||1455|1445|-90|4|5|10|30|10|1|6|0|0|0|0|0 +*|pixie||||||1429|1549|-110|4|5|10|25|15|1|6|0|0|0|0|0 +*|pixie||||||1305|1095|-90|4|5|10|30|15|1|6|0|0|0|0|0 +## Snowy Forest north of the Five Floating Islands archipelago +*|greathart:hind|skitteringhopper|vampirebat||||790|948|-90|4|5|10|140|120|1|3|1|2|0|0|0 +## Five Floating Islands Archipelago +*|greathart:hind|skitteringhopper|vampirebat||||766|1364|-90|4|5|10|60|50|1|1|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||656|1431|-90|4|5|10|60|50|1|1|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||805|1232|-90|4|5|10|75|65|1|1|1|1|2|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||672|1237|-90|4|5|10|60|50|1|2|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||684|1109|-90|4|5|10|60|50|1|1|1|1|0|0|0 +## Through path to hanse's hotel +*|greathart:hind|skitteringhopper|vampirebat||||1079|1440|-90|4|5|10|50|35|1|1|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||966|1213|-90|4|5|10|60|50|1|1|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||925|1105|-90|4|5|10|60|50|1|1|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||1049|1332|-90|4|5|10|60|50|1|1|1|1|0|0|0 +## Behind mountains through path to hanse's hotel +*|greathart:hind|skitteringhopper|vampirebat||||1086|1067|-90|4|5|10|60|30|1|1|1|1|0|0|0 +*|greathart:hind|skitteringhopper|vampirebat||||1062|988|-90|4|5|10|60|30|1|1|1|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/malas/Vendors.map b/Data/Monsters/malas/Vendors.map new file mode 100644 index 0000000..7b525c5 --- /dev/null +++ b/Data/Monsters/malas/Vendors.map @@ -0,0 +1,45 @@ +############## +## By Nerun ## +############## +overrideid 405 +overridemintime 5 +overridemaxtime 10 +## +## Luna +## +*|banker|minter|||||989|520|-50|4|2|10|5|0|402|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||976|512|-50|4|2|10|5|0|402|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster|tanner|furtrader||976|527|-50|4|2|10|5|0|402|1|1|1|1|1|0 +*|keeperofchivalry||||||1016|514|-70|4|2|10|5|0|402|1|0|0|0|0|0 +*|keeperofchivalry||||||961|517|-70|4|2|10|5|0|402|1|0|0|0|0|0 +*|holymage|herbalist|alchemist|customhairstylist|||1004|527|-50|4|2|10|5|0|402|1|1|1|1|0|0 +*|tinker|tinkerguildmaster|carpenter|architect|realestatebroker||1003|512|-50|4|2|10|5|0|402|1|1|1|1|1|0 +*|provisioner|cobbler|jeweler||||993|511|-50|4|2|10|5|0|402|1|1|1|0|0|0 +*|innkeeper||||||989|527|-50|4|2|10|5|0|402|1|0|0|0|0|0 +*|animaltrainer||||||1027|494|-70|4|2|10|5|0|402|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1029|520|-55|4|2|10|5|0|402|1|1|0|0|0|0 +*|healer|healerguildmaster|||||950|520|-55|4|2|10|5|0|402|1|1|0|0|0|0 +## +## Umbra +## +*|blacksmith|blacksmithguildmaster|||||1977|1365|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|animaltrainer||||||1992|1315|-90|4|2|10|5|0|402|1|0|0|0|0|0 +*|provisioner|cobbler|||||2011|1326|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|baker||||||2017|1356|-90|4|2|10|5|0|402|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2027|1353|-90|4|2|10|5|0|402|1|1|1|1|0|0 +*|mage|alchemist|mageguildmaster||||2023|1379|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|herbalist|alchemist|customhairstylist||||2025|1387|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|jeweler||||||2045|1397|-90|4|2|10|5|0|402|1|0|0|0|0|0 +*|banker|minter|||||2048|1343|-85|4|2|10|5|0|402|1|1|0|0|0|0 +*|innkeeper||||||2037|1311|-85|4|2|10|5|0|402|1|0|0|0|0|0 +*|tinker|tinkerguildmaster|||||2066|1282|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2060|1283|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||2083|1322|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|tanner|furtrader|||||2078|1327|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2068|1372|-75|4|2|10|5|0|402|1|1|0|0|0|0 +## +## Hanse's Hotel +## +*|innkeeper||||||1056|1434|-85|4|2|10|5|0|402|1|0|0|0|0|0 +*|waiter|cook|barkeeper||||1050|1434|-85|4|2|10|5|0|402|1|1|1|0|0|0 +*|animaltrainer|veterinarian|||||1042|1444|-90|4|5|10|6|4|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/overseers/Trammel/Overseers.cfg b/Data/Monsters/overseers/Trammel/Overseers.cfg new file mode 100644 index 0000000..ccfc544 --- /dev/null +++ b/Data/Monsters/overseers/Trammel/Overseers.cfg @@ -0,0 +1,15 @@ +############################### +# Trammel - Spawns' Overseers # +############################### +# +# This file control the Spawns' Overseer. It tells to +# "[GenSeers" command where to place Spawns' Overseers, +# and tells about your stats: Range, InRange Delay and OutRange Delay. +# Use [RemSeers to remove them. +# +# To add your ow Overseer, just add coordinates x y z bellow, or +# create a custom file with any name plus extension ".cfg", and place +# in this folder. + +#SpawnsOverseer 7966 +#5433 1102 0 diff --git a/Data/Monsters/termur/Underworld.map b/Data/Monsters/termur/Underworld.map new file mode 100644 index 0000000..ab3e121 --- /dev/null +++ b/Data/Monsters/termur/Underworld.map @@ -0,0 +1,51 @@ +## +## Underworld +## +overrideid 602 +overridemap 6 +##overridemintime 5 +##overridemaxtime 10 +*|gremlin||||||1108|1153|-22|6|5|10|-1|4|1|1|0|0|0|0|0 +*|bloodworm|rotworm|||||1039|1185|-56|6|5|10|20|16|1|3|5|0|0|0|0 +*|acidslug||||||1097|1189|-38|6|5|10|10|7|1|25|0|0|0|0|0 +*|genericguard||||||1127|1202|-2|6|5|10|-1|0|1|1|0|0|0|0|0 +*|GrayGoblinKeeper|WolfSpider|||||1177|995|-27|6|5|10|15|7|1|2|2|0|0|0|0 +*|tanglingroots||||||1095|1076|-71|6|5|10|-1|10|1|3|0|0|0|0|0 +*|GrayGoblinMage:GrayGoblin||||||1218|1049|-42|6|5|10|20|7|1|2|0|0|0|0|0 +*|rotworm||||||1058|1135|-37|6|5|10|15|10|1|1|0|0|0|0|0 +*|graygoblin||||||1178|971|-27|6|5|10|15|10|1|2|0|0|0|0|0 +*|Barreraak||||||1189|989|-27|6|5|10|-1|4|1|1|0|0|0|0|0 +*|GrayGoblin||||||1214|1026|-22|6|5|10|15|5|1|2|0|0|0|0|0 +*|skeleton:skeleton:boneknight:shade:spectre:wraith:skeletalmage:skeletalmage:bonemagi||||||1015|1118|-42|6|5|10|25|14|1|11|3|4|0|0|0 +*|GrayGoblinMage:GrayGoblin||||||1199|1053|-42|6|5|10|20|7|1|3|0|0|0|0|0 +*|Gretchen||||||1089|1128|-42|6|5|10|-1|4|1|1|0|0|0|0|0 +*|kraken||||||1064|1106|-65|6|5|10|25|10|1|2|0|0|0|0|0 +*|wolfspider|GrayGoblin|||||1208|984|-1|6|5|10|20|15|1|8|1|0|0|0|0 +*|skeleton:skeleton:boneknight:wraith:shade:spectre:bonemagi:skeletalmage:skeletalmage||||||1022|1087|-42|6|5|10|20|12|1|4|0|0|0|0|0 +*|rotworm||||||1153|1187|-32|6|5|10|20|14|1|3|0|0|0|0|0 +*|slime||||||1110|1169|-23|6|5|10|10|7|1|10|0|0|0|0|0 +*|waterelemental||||||1187|1186|-40|6|1s|1s|20|7|1|1|0|0|0|0|0 +*|genericguard||||||1130|1202|-2|6|5|10|-1|0|1|1|0|0|0|0|0 +*|rotworm|bloodworm:rotworm|||||1063|1159|-42|6|5|10|20|10|1|3|1|0|0|0|0 +*|QuartermasterFlint||||||1135|1132|-42|6|5|10|-1|4|1|1|0|0|0|0|0 +*|tanglingroots||||||1108|1086|-60|6|5|10|-1|4|1|2|0|0|0|0|0 +*|ElderDugan||||||1104|1128|-52|6|5|10|-1|4|1|1|0|0|0|0|0 +*|rotworm||||||1152|1130|-42|6|5|10|20|12|1|1|0|0|0|0|0 +*|FiddlingTobin||||||1121|1132|-42|6|5|10|-1|4|1|1|0|0|0|0|0 +*|NavreyNightEyes||||||1053|861|-32|6|5|10|20|15|1|1|0|0|0|0|0 +*|Jaacar||||||1204|1041|-42|6|5|10|-1|4|1|1|0|0|0|0|0 +*|WolfSpider|SentinelSpider|||||1094|1002|-16|6|5|10|15|15|1|8|1|0|0|0|0 +*|Garamon||||||1128|1165|-12|6|5|10|-1|4|1|1|0|0|0|0|0 +*|WolfSpider|BloodElemental|||||1124|1008|-43|6|5|10|20|15|1|9|1|0|0|0|0 +*|IronBeetle||||||1147|993|-41|6|5|10|7|7|1|1|0|0|0|0|0 +*|GreenGoblinAlchemist:GreenGoblin:GreenGoblinScout||||||1034|1028|-43|6|5|10|10|6|1|3|0|0|0|0|0 +*|NevilleBrightwhistle||||||1150|963|-43|6|5|10|-1|4|1|1|0|0|0|0|0 +*|lich|spectre:shade:wraith|skeleton:rottingcorpse|mummy|||1217|1074|-52|6|5|10|15|10|1|1|5|7|5|0|0 +*|GrayGoblin:GrayGoblinMage||||||1191|1022|-42|6|5|10|20|16|1|8|0|0|0|0|0 +*|GreenGoblinAlchemist||||||1015|1022|-43|6|5|10|10|3|1|2|0|0|0|0|0 +*|Xenrr|GreenGoblin|||||1014|1000|-43|6|5|10|-1|4|1|1|1|0|0|0|0 +*|GreenGoblin:GreenGoblinAlchemist||||||1034|1004|-43|6|5|10|15|7|1|3|0|0|0|0|0 +*|rotworm||||||1024|1018|-42|6|5|10|10|4|1|4|0|0|0|0|0 +*|Vernix|GreenGoblinAlchemist:GreenGoblin|||||1015|976|-27|6|5|10|10|6|1|1|3|0|0|0|0 +*|GreenGoblinAlchemist:GreenGoblin||||||1044|976|-30|6|5|10|25|17|1|12|0|0|0|0|0 +*|GreaterPoisonElemental||||||1039|1072|-32|6|5|10|10|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/termur/Vendors.map b/Data/Monsters/termur/Vendors.map new file mode 100644 index 0000000..ad9f221 --- /dev/null +++ b/Data/Monsters/termur/Vendors.map @@ -0,0 +1,42 @@ +############### +## By PsYiOn ## +############### +overrideid 601 +overridemap 6 +overridemintime 5 +overridemaxtime 10 +## +## Holy City +## +*|baker||||||976|3881|-42|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1010|3883|-42|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1013|3913|-42|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||977|3909|-42|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||943|3924|-42|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1020|3884|-42|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Royal City +## +*|innkeeper||||||740|3466|-19|2|2|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||772|3467|-20|1|5|10|5|0|1|1|0|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||773|3478|-20|1|5|10|5|0|1|1|1|1|0|0|0 +*|mage|alchemist|mageguildmaster||||772|3490|-20|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||783|3491|-20|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||797|3494|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||805|3491|-20|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||817|3456|-10|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||817|3438|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||817|3426|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||816|3419|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||805|3397|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tanner|furtrader|||||804|3387|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||851|3404|-20|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||833|3439|-20|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||843|3439|-20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|||||702|3435|-20|1|5|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||727|3425|-20|1|5|10|5|0|1|1|1|0|0|0|0 +*|farmer|farmer|||||715|3446|-20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|barkeeper||||713|3438|-20|1|5|10|5|0|1|1|1|1|1|0|0 +*|farmer|farmer|||||794|3446|-10|1|5|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||779|3431|-10|1|5|10|5|0|1|1|0|0|0|0|0 +*|towncrier||||||842|3453|-18|2|5|10|4|0|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/tokuno/FanDancersDojo.map b/Data/Monsters/tokuno/FanDancersDojo.map new file mode 100644 index 0000000..41ca136 --- /dev/null +++ b/Data/Monsters/tokuno/FanDancersDojo.map @@ -0,0 +1,29 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 501 +overridemintime 5 +overridemaxtime 10 +## +*|fandancer||||||977|218|23|5|5|20|15|15|1|4|0|0|0|0|0 +*|daemon|hellhound|succubus||||78|546|-1|4|5|20|15|15|1|1|2|1|0|0|0 +*|daemon|hellhound|succubus||||110|540|-1|4|5|20|15|15|1|1|2|1|0|0|0 +*|fandancer|ronin|||||96|540|-1|4|5|20|20|15|1|1|1|0|0|0|0 +*|daemon|headlessone|||||100|499|-1|4|5|20|20|20|1|1|1|0|0|0|0 +*|daemon|headlessone|hordeminion||||64|488|-1|4|5|20|20|20|1|2|2|2|0|0|0 +*|fandancer|headlessone|hordeminion|daemon|||70|376|-1|4|5|20|30|25|1|3|3|3|1|0|0 +*|hordeminion|headlessone|||||120|415|-1|4|5|20|10|10|1|2|2|0|0|0|0 +*|headlessone||||||99|387|-1|4|5|20|10|10|1|4|0|0|0|0|0 +*|headlessone||||||123|387|-1|4|5|20|10|10|1|4|0|0|0|0|0 +*|headlessone||||||79|521|-1|4|5|20|10|5|1|3|0|0|0|0|0 +*|fandancer||||||88|332|-1|4|5|20|20|20|1|4|0|0|0|0|0 +*|hordeminion|headlessone|succubus||||97|467|-1|4|5|20|20|20|1|2|1|1|0|0|0 +*|hordeminion|headlessone|||||111|352|-1|4|5|20|10|10|1|2|2|0|0|0|0 +*|hordeminion|fandancer|oni|daemon|||173|615|-1|4|5|20|20|20|1|2|2|2|2|0|0 +*|headlessone|fandancer|||||147|646|-1|4|5|20|5|5|1|2|2|0|0|0|0 +*|hordeminion|hellcat|balron||||175|660|-1|4|5|20|20|20|1|3|2|1|0|0|0 +*|fandancer||||||142|692|-1|4|5|20|20|20|1|2|0|0|0|0|0 +*|hellhound|succubus|||||106|685|-1|4|5|20|20|20|1|1|1|0|0|0|0 +*|fandancer|hellcat|balron||||110|649|-1|4|5|20|10|10|1|1|1|1|0|0|0 +*|fandancer|hellhound|hellcat||||134|651|-1|4|5|20|5|5|1|2|1|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/tokuno/Outdoors.map b/Data/Monsters/tokuno/Outdoors.map new file mode 100644 index 0000000..428f695 --- /dev/null +++ b/Data/Monsters/tokuno/Outdoors.map @@ -0,0 +1,221 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 502 +overridemintime 5 +overridemaxtime 10 +## +## Original file splited in WildLife and Outdoors maps by JadeFist +## +*|kappa||||||1215|1086|25|5|5|20|30|30|1|8|0|0|0|0|0 +*|bakekitsune:hellcat||||||643|540|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|bakekitsune:hellcat:kazekemono||||||615|556|37|5|5|20|30|30|1|8|0|0|0|0|0 +*|lesserhiryu||||||1184|837|36|5|1|5|30|30|1|2|0|0|0|0|0 +*|lesserhiryu:kazekemono:oni||||||499|530|32|5|1|5|30|30|1|6|0|0|0|0|0 +*|hiryu||||||1197|813|27|5|1|5|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1247|791|6|5|1|5|30|30|1|2|0|0|0|0|0 +*|kappa||||||1345|881|13|5|5|20|30|30|1|4|0|0|0|0|0 +*|lavaserpent||||||1377|882|21|5|5|20|30|10|1|4|0|0|0|0|0 +*|ronin||||||208|641|36|5|5|20|40|30|1|4|0|0|0|0|0 +*|bakekitsune:hellcat:kazekemono:hellhound||||||582|505|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|hiryu||||||1311|776|10|5|1|5|30|30|1|1|0|0|0|0|0 +*|bakekitsune||||||554|476|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|bakekitsune:kazekemono||||||571|550|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|bakekitsune:hellcat:kazekemono||||||526|556|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|eliteninja||||||1336|810|9|5|5|20|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1344|774|19|5|1|5|30|30|1|2|0|0|0|0|0 +*|lesserhiryu||||||528|552|32|5|1|5|10|10|1|1|0|0|0|0|0 +*|oni||||||502|553|32|5|1|5|10|10|1|1|0|0|0|0|0 +*|bakekitsune||||||517|513|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|lesserhiryu:revenantlion||||||1291|695|19|5|1|5|30|30|1|2|0|0|0|0|0 +*|eliteninja||||||1354|700|33|5|5|20|30|30|1|1|0|0|0|0|0 +*|mongbat||||||273|606|7|5|5|20|30|30|1|8|0|0|0|0|0 +*|bakekitsune||||||518|477|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||159|688|24|5|5|20|40|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||157|685|25|5|5|20|30|30|1|8|0|0|0|0|0 +*|earthelemental:yomotsuwarrior||||||246|768|55|5|5|20|30|30|1|6|0|0|0|0|0 +*|ronin||||||186|534|41|5|5|20|40|30|1|4|0|0|0|0|0 +*|raiju||||||374|820|34|5|5|15|20|20|1|3|0|0|0|0|0 +*|yomotsuwarrior||||||258|709|41|5|5|20|30|30|1|6|0|0|0|0|0 +*|ronin||||||124|646|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||123|647|36|5|5|20|30|30|1|8|0|0|0|0|0 +*|yomotsuwarrior||||||356|722|54|5|5|15|30|30|1|4|0|0|0|0|0 +*|yomotsuwarrior||||||201|731|30|5|5|20|30|30|1|6|0|0|0|0|0 +*|ronin||||||181|588|45|5|5|20|40|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||180|586|45|5|5|20|30|30|1|8|0|0|0|0|0 +*|yomotsuwarrior||||||200|803|62|5|5|20|30|30|1|6|0|0|0|0|0 +*|yamandon||||||166|583|49|5|5|20|40|40|1|1|0|0|0|0|0 +*|yomotsuwarrior:kazekemono||||||190|856|52|5|5|20|30|30|1|6|0|0|0|0|0 +*|mongbat||||||206|891|56|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer||||||1008|246|37|5|5|20|30|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||212|646|31|5|5|20|30|30|1|8|0|0|0|0|0 +*|mongbat||||||208|936|43|5|5|20|30|30|1|4|0|0|0|0|0 +*|yomotsuwarrior:kazekemono||||||248|928|36|5|5|20|30|30|1|6|0|0|0|0|0 +*|mongbat||||||221|968|34|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:lizardman:swamptentacle||||||192|1014|10|5|5|20|30|30|1|8|0|0|0|0|0 +*|ronin:fandancer||||||1016|292|30|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:DeathwatchBeetle:giantserpent||||||232|1116|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|ronin:fandancer:eliteninja||||||948|247|19|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:DeathwatchBeetle:giantserpent||||||285|1156|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|kappa||||||261|1186|20|5|5|20|30|10|1|4|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:DeathwatchBeetle:giantserpent||||||251|1074|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|ronin:fandancer:eliteninja||||||962|203|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer:eliteninja||||||916|225|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:evilmage||||||899|271|34|5|5|20|30|30|1|4|0|0|0|0|0 +*|runebeetle:evilmage:fandancer||||||819|208|38|5|5|20|30|30|1|4|0|0|0|0|0 +*|DeathwatchBeetle:kappa||||||248|525|41|5|5|20|20|20|1|6|0|0|0|0|0 +*|runebeetle:evilmage:fandancer||||||824|280|33|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||284|423|31|5|5|20|40|30|1|8|0|0|0|0|0 +*|eliteninja||||||265|406|22|5|5|20|40|30|1|1|0|0|0|0|0 +*|eliteninja||||||289|477|32|5|5|20|40|30|1|1|0|0|0|0|0 +*|ronin||||||326|454|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||765|189|42|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||360|466|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|mongbat||||||384|460|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|mongbat||||||418|463|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|ronin||||||425|443|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||472|433|27|5|5|20|40|30|1|8|0|0|0|0|0 +*|ronin||||||407|399|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|ronin||||||358|396|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||725|246|36|5|5|20|30|30|1|4|0|0|0|0|0 +*|runebeetle:evilmage:evilmagelord||||||769|152|12|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||323|374|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||773|229|64|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||415|351|28|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||789|276|56|5|5|20|40|30|1|4|0|0|0|0|0 +*|kappa:tsukiwolf||||||493|378|45|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:tsukiwolf||||||454|374|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||798|377|25|5|5|20|40|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||472|336|38|5|5|20|30|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage:evilmagelord:fandancer||||||841|326|32|5|5|20|40|30|1|6|0|0|0|0|0 +*|runebeetle:ronin:fandancer||||||907|292|19|5|5|20|40|30|1|4|0|0|0|0|0 +*|yamandon||||||526|299|26|5|5|20|30|30|1|1|0|0|0|0|0 +*|tsukiwolf||||||540|343|8|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:tsukiwolf||||||527|393|53|5|5|20|30|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||566|430|35|5|5|20|30|30|1|8|0|0|0|0|0 +*|DeathwatchBeetle:deathwatchbeetlehatchling:lizardman||||||892|391|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage:evilmagelord||||||873|326|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||594|362|22|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:ronin||||||861|335|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|kappa:ronin||||||853|386|19|5|5|20|40|30|1|4|0|0|0|0|0 +*|raiju||||||649|409|36|5|5|20|30|30|1|2|0|0|0|0|0 +*|revenantlion:bakekitsune:oni||||||677|446|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|DeathwatchBeetle:deathwatchbeetlehatchling:lizardman||||||907|394|10|5|5|20|40|30|1|8|0|0|0|0|0 +*|DeathwatchBeetle:deathwatchbeetlehatchling:lizardman||||||927|451|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||932|364|3|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||930|405|11|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||992|383|5|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||997|407|-2|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||951|409|9|5|5|20|40|30|1|8|0|0|0|0|0 +*|ronin||||||1036|366|7|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer||||||1034|293|21|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer||||||980|278|30|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||948|522|7|5|5|20|30|30|1|4|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||918|439|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||951|467|12|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:kappa||||||1150|1072|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||979|477|2|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||983|448|-1|5|5|20|40|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||1051|473|7|5|5|20|20|20|1|8|0|0|0|0|0 +*|direwolf:timberwolf||||||1062|469|8|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle:runebeetle:lizardman||||||1086|452|14|5|5|20|40|30|1|4|0|0|0|0|0 +*|yamandon||||||1084|464|15|5|5|20|20|20|1|1|0|0|0|0|0 +*|kazekemono:Tsukiwolf||||||999|580|14|5|5|20|40|30|1|4|0|0|0|0|0 +*|mountaingoat:sheep||||||921|593|20|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper||||||1042|559|22|5|5|20|3|3|1|1|0|0|0|0|0 +*|reaper||||||1062|564|22|5|5|20|3|3|1|1|0|0|0|0|0 +*|tsukiwolf||||||1092|563|22|5|5|20|30|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||1146|516|21|5|5|20|30|30|1|4|0|0|0|0|0 +*|mongbat||||||192|770|56|5|5|20|40|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||1214|531|28|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper:kazekemono||||||1172|535|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|lavaserpent||||||1184|616|19|5|5|20|10|10|1|3|0|0|0|0|0 +*|kappa||||||1058|799|13|5|5|20|30|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||1181|484|22|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper:kazekemono||||||1196|507|26|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper||||||1258|531|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||1285|573|30|5|5|20|30|30|1|8|0|0|0|0|0 +*|revenantlion:boneknight:skeletalknight:skeletalmage:bonemagi||||||1321|619|38|5|5|20|30|30|1|8|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent||||||1214|652|90|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent||||||1176|701|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent||||||1144|667|70|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent:lavalizard||||||1134|705|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellcat:lavalizard||||||1105|753|44|5|5|20|30|30|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1021|802|0|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa||||||931|833|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1006|857|15|5|5|20|30|30|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow:dreadspider||||||980|815|15|5|5|20|30|30|1|4|0|0|0|0|0 +*|kazekemono||||||892|652|17|5|5|20|30|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||968|753|3|5|5|20|30|30|1|4|0|0|0|0|0 +*|kazekemono||||||938|722|10|5|5|20|30|30|1|4|0|0|0|0|0 +*|kazekemono||||||932|685|12|5|5|20|30|30|1|4|0|0|0|0|0 +*|deathwatchbeetle:bonemagi:revenantlion:skeletalmage||||||1120|1099|25|5|5|20|30|30|1|8|0|0|0|0|0 +*|kazekemono:eliteninja||||||840|714|16|5|5|20|30|30|1|8|0|0|0|0|0 +*|hiryu||||||883|604|39|5|5|20|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1012|631|11|5|5|20|30|30|1|1|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1076|864|56|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa||||||1055|887|38|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:deathwatchbeetle||||||1052|976|26|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:deathwatchbeetle||||||1064|1029|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa||||||1092|980|33|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:eliteninja||||||1086|910|61|5|5|20|30|30|1|4|0|0|0|0|0 +*|revenantlion||||||637|357|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|oni||||||1282|898|12|5|1|5|30|30|1|2|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:deathwatchbeetle:giantserpent||||||243|1031|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||742|1012|33|5|5|20|20|20|1|6|0|0|0|0|0 +*|bakekitsune||||||662|495|28|5|5|20|30|30|1|4|0|0|0|0|0 +*|lesserhiryu||||||1293|864|-1|5|1|5|30|30|1|2|0|0|0|0|0 +*|eliteninja||||||1321|847|13|5|5|20|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1343|654|35|5|1|5|30|30|1|2|0|0|0|0|0 +*|yomotsuwarrior||||||294|748|55|5|5|20|30|30|1|6|0|0|0|0|0 +*|yomotsuwarrior:kazekemono||||||198|924|42|5|5|20|30|30|1|6|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:deathwatchbeetle||||||185|1046|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:deathwatchbeetle:giantserpent||||||210|1085|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|skeleton:shade:bonemagi:skeletalknight||||||581|953|33|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle||||||533|991|53|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||562|984|43|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle||||||511|956|27|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetle||||||524|934|19|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetle||||||535|918|14|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetle||||||526|889|11|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeleton:shade:bonemagi:skeletalknight||||||573|933|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeleton:shade:bonemagi:skeletalknight||||||612|888|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle||||||570|840|0|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeletalmage:deathwatchbeetle||||||601|930|32|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||638|866|23|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||666|896|28|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc||||||700|826|36|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc||||||715|831|36|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||725|823|24|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||771|824|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||737|853|35|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||709|877|18|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc||||||683|857|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||667|943|43|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||619|981|45|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||588|1012|62|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||644|1005|55|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||668|986|46|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||688|979|44|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeleton||||||680|956|44|5|5|20|20|20|1|6|0|0|0|0|0 +*|deathwatchbeetle||||||722|916|40|5|5|20|20|20|1|6|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||729|934|42|5|5|20|20|20|1|6|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||771|979|29|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||803|961|14|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||819|944|22|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||792|920|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:deathwatchbeetlehatchling||||||794|890|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||819|902|27|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||770|875|30|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||760|941|37|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||874|971|45|5|5|20|20|20|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1105|855|50|5|5|20|30|30|1|4|0|0|0|0|0 +## +## Isamu-Jima icelands +## +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||926|145|49|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||879|128|44|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||914|55|36|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||947|103|46|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||976|144|35|5|5|20|30|30|1|2|2|1|1|1|0 \ No newline at end of file diff --git a/Data/Monsters/tokuno/TownsLife.map b/Data/Monsters/tokuno/TownsLife.map new file mode 100644 index 0000000..19bbd29 --- /dev/null +++ b/Data/Monsters/tokuno/TownsLife.map @@ -0,0 +1,37 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 503 +overridemintime 5 +overridemaxtime 10 +## +*|rabbit||||||667|1343|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|dog|cat|bird|rat|||756|1236|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|cat||||||712|1238|25|5|5|20|20|20|1|1|0|0|0|0|0 +*|rat||||||683|1231|25|5|5|20|20|20|1|1|0|0|0|0|0 +*|bird||||||679|1224|25|5|5|20|20|20|1|2|0|0|0|0|0 +*|bird||||||706|1208|25|5|5|20|20|20|1|2|0|0|0|0|0 +*|bird|dog|cat|rat|||721|1274|25|5|5|20|20|20|1|2|1|1|1|0|0 +*|bird||||||740|1284|25|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane|cat|||||713|1351|25|5|5|20|20|20|1|2|2|0|0|0|0 +*|bird||||||710|1350|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|rabbit|pig|crane||||636|1331|25|5|5|20|20|20|1|2|1|1|0|0|0 +*|bird||||||628|1310|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane|goat|rabbit||||625|1317|25|5|5|20|20|20|1|2|1|1|0|0|0 +*|bird|crane|rabbit||||630|1225|25|5|5|20|20|20|1|3|3|2|0|0|0 +*|bird|cat|dog||||628|1272|25|5|5|20|20|20|1|3|3|2|0|0|0 +*|bird|rat|cat|dog|||768|1192|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|rat|bird|dog|||857|1166|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|rat|bird|dog|||853|1287|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|pig|||||843|1247|25|5|5|20|20|20|1|2|2|0|0|0|0 +*|dog|rat:rabbit|horse|pig|||844|1198|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|bird|cat|jackrabbit||||812|1222|25|5|5|20|20|20|1|2|1|1|0|0|0 +*|bird|dog|cat|jackrabbit|||807|1287|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|bird|crane|jackrabbit|dog:pig|||844|1318|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|crane||||||834|1351|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|rat|bird|||||803|1338|25|5|5|20|20|20|1|2|2|0|0|0|0 +*|bird|goat|pig|horse|||770|1344|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|dog|bird|rat|||744|1347|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|dog|bird|crane|sheep|||711|1322|25|5|5|20|20|20|1|2|2|2|2|0|0 +*|dog|rat|cat||||690|1288|25|5|5|20|20|20|1|2|2|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/tokuno/Vendors.map b/Data/Monsters/tokuno/Vendors.map new file mode 100644 index 0000000..052fa1a --- /dev/null +++ b/Data/Monsters/tokuno/Vendors.map @@ -0,0 +1,56 @@ +############## +## By Nerun ## +############## +overridemintime 5 +overridemaxtime 10 +overrideid 504 +*|bardguildmaster||||||668|1254|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|blacksmith||||||773|1248|26|5|5|10|4|0|1|1|0|0|0|0|0 +*|blacksmith||||||662|1210|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|baker|butcher|cook||||703|1262|25|5|5|10|10|0|1|1|1|1|0|0|0 +*|shipwright||||||669|1266|47|5|5|10|4|0|1|1|0|0|0|0|0 +*|tanner||||||720|1211|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|carpenter||||||739|1223|45|5|5|10|4|0|1|1|0|0|0|0|0 +*|Towncrier||||||732|1256|30|5|5|10|0|0|1|1|0|0|0|0|0 +*|bowyer||||||781|1301|26|5|5|10|4|0|1|1|0|0|0|0|0 +*|animaltrainer||||||789|1278|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|armorer||||||756|1302|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||692|1213|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|innkeeper||||||679|1207|25|5|5|10|0|0|1|1|0|0|0|0|0 +*|tinker||||||720|1213|45|5|5|10|4|0|1|1|0|0|0|0|0 +*|tailor||||||744|1219|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|mapmaker||||||691|1264|47|5|5|10|4|0|1|1|0|0|0|0|0 +*|bard||||||675|1265|25|5|5|10|4|4|1|1|0|0|0|0|0 +*|scribe||||||689|1255|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|herbalist||||||683|1298|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|alchemist||||||702|1298|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|mage||||||695|1297|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|jeweler||||||724|1297|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|provisioner||||||730|1282|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|healer||||||781|1219|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|banker||||||729|1249|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|armorer||||||742|1304|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|weaponsmith||||||806|1308|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||749|1303|25|5|5|10|4|4|1|1|1|0|0|0|0 +*|blacksmith||||||661|1209|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|weaver||||||744|1210|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|weaponsmith||||||779|1259|26|5|5|10|4|0|1|1|0|0|0|0|0 +*|noble:peasant:hirebeggar|samurai|ninja||||735|1256|30|5|5|10|80|60|1|10|10|10|0|0|0 +## +## wandering healers +## +*|wanderinghealer||||||1166|802|27|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||558|534|32|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||502|589|24|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||1177|985|38|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||399|549|15|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||226|786|57|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||297|637|15|5|1|5|2|2|1|1|0|0|0|0|0 +*|wanderinghealer||||||371|431|32|5|5|20|5|5|1|1|0|0|0|0|0 +*|wanderinghealer||||||763|247|71|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||1111|495|18|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||1221|494|27|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||895|519|53|5|5|20|2|2|1|1|0|0|0|0|0 +*|wanderinghealer||||||1152|936|65|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||979|238|21|5|5|20|5|5|1|1|0|0|0|0|0 +*|wanderinghealer||||||248|1089|10|5|1|5|3|3|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/tokuno/WildLife.map b/Data/Monsters/tokuno/WildLife.map new file mode 100644 index 0000000..00e0702 --- /dev/null +++ b/Data/Monsters/tokuno/WildLife.map @@ -0,0 +1,189 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 505 +overridemintime 5 +overridemaxtime 10 +## +## Original file splited in WildLife and Outdoors maps by JadeFist +## +## Animals (included gaman, crane, giant serpent) +## +*|bird|jackrabbit|||||1177|1002|34|5|5|20|30|30|1|2|2|0|0|0|0 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|629|510|32|5|5|20|30|30|1|1|2|1|1|1|2 +*|gaman|bird|jackrabbit||||1198|941|36|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit|horse|cat|dog|1141|894|57|5|5|20|30|30|1|1|1|1|1|1|1 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|623|551|32|5|5|20|30|30|1|2|2|1|1|1|1 +*|gaman|bird:jackrabbit|brownbear|horse|||1197|851|32|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|bird:jackrabbit|horse|dog|||1230|895|22|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|bird|jackrabbit||||1255|866|12|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit|horse|||1230|822|21|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|bird|jackrabbit||||1289|843|4|5|5|20|30|30|1|2|1|1|0|0|0 +*|llama|mountaingoat|||||1377|882|21|5|5|20|30|10|1|2|2|0|0|0|0 +*|gaman|bird|jackrabbit||||1299|814|9|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman||||||518|329|15|5|5|20|30|30|1|8|0|0|0|0|0 +*|gaman|bird|jackrabbit||||1263|754|-1|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit||||1311|777|9|5|5|20|30|30|1|2|1|1|0|0|0 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|551|544|32|5|5|20|30|30|1|2|2|1|1|1|1 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|502|532|32|5|5|20|30|30|1|2|2|1|1|1|1 +*|gaman|bird|jackrabbit||||1345|775|19|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit||||1312|704|21|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|blackbear:brownbear|bird|llama|horse|ridablellama|273|606|7|5|5|20|30|30|1|2|1|1|1|1|2 +*|sheep|bird|blackbear:brownbear||||505|474|31|5|5|20|30|30|1|3|3|2|0|0|0 +*|gaman|dog|jackrabbit||||364|565|15|5|5|20|30|30|1|3|3|2|0|0|0 +*|gaman|horse|brownbear|jackrabbit|||404|592|26|5|5|20|30|30|1|2|2|2|2|0|0 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|377|635|50|5|5|20|30|30|1|1|2|1|1|1|2 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|58|104|0|5|5|20|30|30|1|1|2|1|1|1|2 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|356|705|50|5|5|20|30|30|1|1|2|1|1|1|2 +*|gaman||||||190|856|52|5|5|20|30|30|1|6|0|0|0|0|0 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|324|664|29|5|5|20|30|30|1|1|2|1|1|1|2 +*|gaman|jackrabbit|horse|cat|||327|604|15|5|5|20|30|30|1|2|2|2|2|0|0 +*|bird|gaman|brownbear:blackbear|horse|||381|511|22|5|5|20|30|30|1|2|2|2|2|0|0 +*|bird|cat|brownbear:blackbear|horse|dog|jackrabbit|307|572|33|5|5|20|30|30|1|2|1|1|2|1|1 +*|bird|cat|brownbear:blackbear|horse|dog|jackrabbit|146|109|0|5|5|20|30|30|1|2|1|1|2|1|1 +*|gaman:bird|direwolf:timberwolf|blackbear:brownbear|llama:horse:ridablellama|||206|891|56|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman:bird|direwolf:timberwolf|blackbear:brownbear|llama:horse:ridablellama|||208|936|43|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|direwolf:timberwolf|blackbear:brownbear|bird|llama|horse:ridablellama|221|968|34|5|5|20|30|30|1|2|1|1|1|1|2 +## +## Isamu-Jima icelands (removed, see Outdoors.map) - since v5.1.9 +## +## +## REVISAR ABAIXO - NOVO FORMATO +## +*|crane:rat||||||192|1014|10|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf||||||1008|260|36|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||232|1116|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf||||||1021|297|28|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||285|1156|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||941|206|17|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane||||||261|1186|20|5|5|20|30|10|1|4|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||251|1074|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||901|264|31|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane||||||243|563|42|5|5|20|15|15|1|2|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||812|218|41|5|5|20|30|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:mongbat:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||384|460|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:mongbat:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||418|463|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||356|403|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1011|509|26|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman:crane||||||493|378|45|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||785|303|41|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman:crane||||||454|374|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||793|368|31|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman:crane||||||472|336|38|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||856|324|37|5|5|20|40|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||905|331|8|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman||||||527|393|53|5|5|20|30|30|1|8|0|0|0|0|0 +*|bird:sheep:gaman||||||566|430|35|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane||||||497|453|17|5|5|20|30|30|1|2|0|0|0|0|0 +*|crane||||||861|335|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|sheep:mountaingoat:bird:llama:ridablellama||||||565|447|31|5|5|20|30|30|1|8|0|0|0|0|0 +*|sheep:mountaingoat:bird:llama:ridablellama||||||656|411|33|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||857|376|25|5|5|20|40|30|1|8|0|0|0|0|0 +*|crane||||||702|419|18|5|5|20|10|10|1|3|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||955|391|4|5|5|20|40|30|1|8|0|0|0|0|0 +*|bird:sheep||||||935|521|16|5|5|20|20|20|1|3|0|0|0|0|0 +*|brownbear:timberwolf:greywolf:bird:blackbear:direwolf||||||1074|529|22|5|5|20|40|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf||||||1062|469|8|5|5|20|20|20|1|4|0|0|0|0|0 +*|brownbear:timberwolf:greywolf:blackbear:direwolf||||||1122|501|19|5|5|20|40|30|1|8|0|0|0|0|0 +*|brownbear:timberwolf:greywolf:bird:blackbear:direwolf:ridablellama||||||1027|562|29|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||949|589|7|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1105|539|22|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat:sheep||||||921|593|20|5|5|20|30|30|1|4|0|0|0|0|0 +*|bird:horse||||||192|770|56|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1181|547|23|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat||||||1184|616|19|5|5|20|10|10|1|3|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1235|506|28|5|5|20|40|30|1|8|0|0|0|0|0 +*|bird||||||1258|531|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|timberwolf:greywolf:bird||||||1307|559|31|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat||||||1176|701|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|mountaingoat||||||1144|667|70|5|5|20|30|30|1|4|0|0|0|0|0 +*|mountaingoat:llama||||||1134|705|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:brownbear:jackrabbit||||||1074|806|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:jackrabbit:bird||||||955|828|27|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:jackrabbit||||||1028|818|13|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:brownbear:jackrabbit||||||1101|832|37|5|5|20|30|30|1|4|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||967|755|3|5|5|20|40|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||956|705|16|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||911|643|15|5|5|20|40|30|1|8|0|0|0|0|0 +*|bird||||||868|660|7|5|5|20|40|30|1|4|0|0|0|0|0 +*|mountaingoat:bird:sheep:llama||||||889|516|47|5|5|20|30|30|1|4|0|0|0|0|0 +*|bird:sheep:mountaingoat||||||862|490|54|5|5|20|30|30|1|4|0|0|0|0|0 +*|horse:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||998|656|11|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat||||||1065|708|17|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane:horse||||||1227|1082|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1039|952|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1052|1030|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit||||||1092|1024|34|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog:cat||||||1133|957|64|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:dog||||||1088|980|30|5|5|20|30|30|1|4|0|0|0|0|0 +*|dog:bird:jackrabbit:cat||||||1091|897|69|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1056|904|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman||||||143|131|0|5|5|20|30|30|1|8|0|0|0|0|0 +*|sheep:mountaingoat:bird:llama:ridablellama:crane||||||687|439|26|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||823|279|33|5|5|20|30|30|1|8|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog||||||1265|927|19|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:jackrabbit||||||419|529|15|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||960|293|29|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||243|1031|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||988|335|17|5|5|20|40|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||771|228|63|5|5|20|40|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||443|402|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|gaman:bird:horse||||||1255|804|5|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman||||||288|652|15|5|5|20|40|40|1|8|0|0|0|0|0 +*|gaman||||||459|483|21|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat||||||185|1046|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||210|1085|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|bird:crane:pig:goat||||||596|1289|21|5|5|20|20|20|1|8|0|0|0|0|0 +*|bird:crane:rabbit||||||566|1287|22|5|5|20|20|20|1|8|0|0|0|0|0 +*|crane:rabbit:horse||||||525|1263|24|5|5|20|20|20|1|8|0|0|0|0|0 +*|bird:dog:cat:rabbit||||||547|1240|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|crane:bird:horse||||||534|1189|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|goat:sheep:bird:rabbit||||||572|1211|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|goat:horse:rabbit:llama||||||600|1198|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|llama:rabbit:dog||||||580|1170|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|direwolf:rabbit:llama||||||567|1160|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|ridablellama:direwolf:bird||||||563|1133|43|5|5|20|20|20|1|8|0|0|0|0|0 +*|greywolf:pig:timberwolf||||||561|1101|33|5|5|20|20|20|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:bird||||||550|1092|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|bird||||||524|1054|18|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane||||||504|1042|24|5|5|20|20|20|1|3|0|0|0|0|0 +*|bird||||||533|991|53|5|5|20|20|20|1|2|0|0|0|0|0 +*|bird||||||526|889|11|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||612|857|15|5|5|20|20|20|1|2|0|0|0|0|0 +*|jackrabbit:bird||||||558|862|6|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:bird||||||724|831|34|5|5|20|20|20|1|4|0|0|0|0|0 +*|bird||||||771|824|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||746|814|16|5|5|20|20|20|1|2|0|0|0|0|0 +*|jackrabbit||||||683|857|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:bird:jackrabbit||||||685|891|22|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:bird||||||635|966|44|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:bird||||||591|1010|58|5|5|20|20|20|1|4|0|0|0|0|0 +*|bird||||||680|987|47|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane:jackrabbit||||||722|916|40|5|5|20|20|20|1|6|0|0|0|0|0 +*|horse:dog:timberwolf||||||727|1071|39|5|5|20|20|20|1|6|0|0|0|0|0 +*|greywolf:timberwolf||||||710|1115|41|5|5|20|20|20|1|6|0|0|0|0|0 +*|direwolf:greywolf:timberwolf||||||644|1142|28|5|5|20|20|20|1|6|0|0|0|0|0 +*|ridablellama:blackbear:brownbear:bird||||||775|1127|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit||||||792|920|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||794|890|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||833|908|15|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:jackrabbit:bird||||||770|875|30|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||874|971|45|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:crane||||||911|1025|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|gaman:goat:bird||||||879|1038|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|bird||||||887|1072|20|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:rat||||||913|1055|19|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:pig:dog:cat||||||916|1120|17|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:rat:bird||||||883|1121|19|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||837|1075|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|sheep:pig:rabbit||||||884|1152|29|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:dog:cat:sheep||||||907|1143|11|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:cat:sheep||||||942|1170|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||939|1199|22|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||934|1233|19|5|5|20|20|20|1|4|0|0|0|0|0 +*|goat:rat||||||887|1286|13|5|5|20|20|20|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog:cat:horse||||||1139|999|48|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog:cat:horse:crane||||||1133|1036|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:crane||||||1207|1037|25|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1178|1076|19|5|5|20|30|30|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/tokuno/YomutsoMines.map b/Data/Monsters/tokuno/YomutsoMines.map new file mode 100644 index 0000000..26fa298 --- /dev/null +++ b/Data/Monsters/tokuno/YomutsoMines.map @@ -0,0 +1,17 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 506 +overridemintime 5 +overridemaxtime 10 +## +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||16|56|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||25|19|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||71|29|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||54|67|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||83|114|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||102|84|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||116|61|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||111|20|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|FireBeetle||||||107|23|-1|4|5|10|5|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/trammel/BlightedGrove.map b/Data/Monsters/trammel/BlightedGrove.map new file mode 100644 index 0000000..0bfff00 --- /dev/null +++ b/Data/Monsters/trammel/BlightedGrove.map @@ -0,0 +1,19 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 101 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Blighted Grove +## +*|tangle:bogling:alligator:reaper:corpser:changeling:whippingvine||||||6507|843|0|2|5|10|10|10|1|8|0|0|0|0|0 +*|giantserpent:gianttoad:harpy:silverserpent:snake:bogling||||||6513|871|0|2|5|10|35|35|1|17|0|0|0|0|0 +*|harpy:saliva:changeling||||||6585|878|0|2|5|10|10|10|1|7|0|0|0|0|0 +*|abscess:hydra:bogthing||||||6535|848|0|2|5|10|10|10|1|4|0|0|0|0|0 +*|insanedryad||||||6540|872|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|thrasher:swamptentacle:reaper:bogling:alligator:coil:whippingvine||||||6518|870|0|2|5|10|40|40|1|9|0|0|0|0|0 +*|insanedryad||||||6489|897|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|insanedryad||||||6518|879|0|2|5|10|5|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/trammel/BritainSewer.map b/Data/Monsters/trammel/BritainSewer.map new file mode 100644 index 0000000..7571fc5 --- /dev/null +++ b/Data/Monsters/trammel/BritainSewer.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 102 +overridemap 2 +overridemintime 0 +overridemaxtime 1 +## +## Britain Sewer +## +*|sewerrat:Rat|Bullfrog|||||6049|1447|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6091|1491|10|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6048|1487|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6065|1459|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6092|1448|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6107|1452|25|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6112|1462|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6039|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6115|1491|-15|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6084|1470|5|2|5|10|15|1|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6049|1470|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6034|1467|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6059|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6061|1490|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6041|1486|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|alligator||||||6090|1483|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6077|1492|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6108|1471|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6087|1443|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6052|1463|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6037|1494|0|2|5|10|10|4|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Covetous.map b/Data/Monsters/trammel/Covetous.map new file mode 100644 index 0000000..076b92c --- /dev/null +++ b/Data/Monsters/trammel/Covetous.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 103 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Covetous Dungeon +## +## Level 1 +## +*|Harpy||||||5472|1877|0|2|1|10|25|10|1|6|0|0|0|0|0 +*|Headlessone||||||5453|1905|0|2|2|10|25|5|1|4|0|0|0|0|0 +*|Stoneharpy||||||5443|1918|0|2|2|10|30|7|1|2|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5418|1876|0|2|2|10|30|10|1|4|2|0|0|0|0 +*|Gazer|Gazerlarva|||||5411|1901|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Corpser||||||5393|1921|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5400|1937|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5452|1891|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5399|1859|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5387|1911|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Corpser||||5411|1932|0|2|2|10|7|7|1|1|2|6|0|0|0 +## +## Level 2 +## +*|Headlessone||||||5577|2006|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5593|2017|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5558|2025|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Harpy|Stoneharpy|||||5498|1998|0|2|2|10|30|15|1|8|1|0|0|0|0 +*|Giantspider|Dreadspider|||||5474|2035|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Slime||||||5469|2019|0|2|2|10|25|10|1|5|0|0|0|0|0 +*|Waterelemental||||||5445|2030|-3|2|2|10|15|15|1|2|0|0|0|0|0 +*|Giantspider|Dreadspider|||||5440|2023|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Giantspider|Dreadspider|||||5473|1991|0|2|2|10|25|9|1|2|2|0|0|0|0 +*|Gazer|Gazerlarva|Eldergazer||||5457|1971|0|2|2|10|25|15|1|4|2|1|0|0|0 +*|Corpser||||||5436|1972|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5417|1975|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5429|1989|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Corpser||||||5425|1992|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|Gazer||||||5388|2012|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5503|2002|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|Corpser|||||5413|2000|0|2|2|10|10|10|1|1|7|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5460|1975|0|2|1|2|7|7|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5448|2027|0|2|1|2|8|8|1|1|2|0|0|0|0 +## +## Skeleton Passage +## +*|Skeleton||||||2456|861|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2480|863|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2493|883|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2513|862|0|2|2|10|25|10|1|4|0|0|0|0|0 +## +## Level 3 +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5596|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1876|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Boneknight|Skeleton|Zombie|Shade|||5603|1875|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|||5617|1861|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|TreasureLevel3|TreasureLevel4|5615|1838|0|2|2|10|25|8|1|3|1|1|1|1|2 +*|Lich|Spectre|Skeleton||||5579|1859|0|2|2|10|25|11|1|7|3|1|0|0|0 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1843|0|2|2|10|40|15|1|1|1|1|2|1|1 +## +## Undead Prison +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5528|1808|0|2|2|10|30|15|1|1|1|1|3|1|1 +*|Rottingcorpse|TreasureLevel3|TreasureLevel4||||5504|1808|0|2|2|10|12|3|1|1|1|2|0|0|0 +## +## Dragon's Lair +## +*|Dragon|Drake|||||5452|1799|0|2|2|10|30|20|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5461|1818|0|2|1|2|8|8|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Deceit.map b/Data/Monsters/trammel/Deceit.map new file mode 100644 index 0000000..55617c5 --- /dev/null +++ b/Data/Monsters/trammel/Deceit.map @@ -0,0 +1,57 @@ +############## +## By Nerun ## +############## +overrideid 104 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Deceit Dungeon +## +## Level 1 +## +*|Mummy|Skeleton|Zombie||||5187|603|0|2|2|10|35|18|1|1|3|1|0|0|0 +*|Waterelemental||||||5186|575|0|2|2|10|12|8|1|2|0|0|0|0|0 +*|Skeleton||||||5187|545|0|2|2|10|25|6|1|2|0|0|0|0|0 +*|Mummy|Skeleton|Zombie||||5163|567|0|2|2|10|25|6|1|1|3|1|0|0|0 +*|Skeleton|Zombie|||||5145|553|-40|2|2|10|35|8|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|579|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|598|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5145|622|-50|2|2|10|25|8|1|2|2|0|0|0|0 +*|Skeleton|Spectre|||||5212|531|0|2|2|10|25|8|1|2|1|0|0|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|552|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|573|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|TreasureLevel2|TreasureLevel3|||||5145|618|-50|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ghoul|Skeleton|Wraith|Zombie|||5307|546|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5327|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5286|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Wraith|||||5283|583|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Ghoul|Mummy|Shade|Wraith|Zombie||5318|578|0|2|2|10|25|10|1|1|1|1|1|1|0 +*|Boneknight|Skeletalknight|||||5342|582|0|2|2|10|25|10|1|4|4|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|||5299|603|0|2|2|10|25|10|1|1|1|2|1|0|0 +*|Bonemagi||||||5295|623|-5|2|2|10|10|6|1|3|0|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|Zombie||5322|626|0|2|2|10|25|15|1|1|1|2|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5323|571|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## Level 3 +## +*|Ghoul|Shade|Spectre|Wraith|||5139|661|0|2|2|10|25|15|1|1|1|1|1|0|0 +*|Lich||||||5190|655|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5170|678|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Lich|Spectre|Wraith|||5151|718|0|2|2|10|25|10|1|1|3|1|1|0|0 +*|Ghoul|Poisonelemental|||||5192|695|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Poisonelemental|||||5183|727|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5212|674|-20|2|2|10|25|12|1|1|1|1|1|0|0 +*|Lich||||||5219|734|-20|2|2|10|25|15|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5150|742|0|2|2|10|15|3|1|1|2|2|0|0|0 +## +## Level 4 +## +*|Ghoul|Lich|||||5307|675|-20|2|2|10|25|10|1|2|1|0|0|0|0 +*|Fireelemental||||||5280|675|8|2|2|10|25|10|1|2|0|0|0|0|0 +*|Lich||||||5320|708|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|Lich|Lichlord|Silverserpent||5314|748|-20|2|2|10|25|8|1|1|2|3|1|2|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5267|690|0|2|2|10|35|2|1|1|2|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Despise.map b/Data/Monsters/trammel/Despise.map new file mode 100644 index 0000000..42e3ee6 --- /dev/null +++ b/Data/Monsters/trammel/Despise.map @@ -0,0 +1,63 @@ +############## +## By Nerun ## +############## +overrideid 105 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Despise Dungeon +## +## Note: Acidelemental do not exist then i used Toxicelemental instead. +## +## Level 1 +## +*|Lizardman|TreasureLevel2|TreasureLevel3||||5503|529|60|2|2|10|25|12|1|5|1|1|0|0|0 +*|Lizardman||||||5504|597|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5464|600|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5435|589|47|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5410|611|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman|TreasureLevel2|TreasureLevel3||||5386|612|45|2|2|10|25|12|1|5|1|2|0|0|0 +*|Lizardman||||||5405|576|61|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5411|541|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5460|526|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5394|525|65|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5390|587|45|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ettin||||||5490|676|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Ettin||||||5483|711|15|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental|Ettin|||||5505|747|5|2|2|10|25|18|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5475|748|5|2|2|10|25|12|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5420|746|5|2|2|10|25|18|1|4|6|0|0|0|0 +*|Ettin||||||5385|703|15|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|660|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental||||||5441|680|20|2|2|10|25|12|1|6|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5507|656|20|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5387|697|15|2|1|2|5|5|1|1|4|0|0|0|0 +## +## Level 3 +## +*|Troll||||||5439|851|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5470|860|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5426|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5482|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Ogre||||||5532|787|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogre||||||5604|789|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogrelord||||||5558|824|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Ogre||||||5590|871|45|2|2|10|35|20|1|3|0|0|0|0|0 +*|Ogre||||||5528|902|30|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ettin||||||5487|902|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5504|939|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Cyclops||||||5471|973|15|2|2|10|25|18|1|3|0|0|0|0|0 +*|Ettin||||||5426|943|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|905|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Toxicelemental||||||5398|996|5|2|2|10|25|15|1|3|0|0|0|0|0 +*|TreasureLevel2||||||5593|794|60|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5546|888|30|2|1|2|8|8|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5397|995|5|2|1|2|10|10|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5605|799|60|2|1|2|10|10|1|3|0|0|0|0|0 +*|TreasureLevel3||||||5557|828|45|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5398|995|5|2|1|2|10|10|1|2|0|0|0|0|0 +*|TreasureLevel4||||||5564|821|45|2|1|2|5|5|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Destard.map b/Data/Monsters/trammel/Destard.map new file mode 100644 index 0000000..24567f9 --- /dev/null +++ b/Data/Monsters/trammel/Destard.map @@ -0,0 +1,55 @@ +############## +## By Nerun ## +############## +overrideid 106 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Destard Dungeon +## +## Level 1 - First Big Lair (entrance) +## +*|Dragon|Drake|Wyvern||||5209|965|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|||||5247|956|-40|2|2|10|50|30|1|1|2|0|0|0|0 +*|Dragon|Drake|Wyvern||||5280|955|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5284|926|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5214|917|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5241|945|-40|2|1|2|10|10|1|1|2|0|0|0|0 +## +## Level 1 - Left Arm +## +*|Giantserpent||||||5161|940|0|2|2|10|50|20|1|6|0|0|0|0|0 +*|Wyvern|Dragon|Drake||||5149|907|0|2|2|10|20|15|1|1|1|1|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5141|915|0|2|1|2|25|25|1|1|2|0|0|0|0 +## +## Level 1 - Right Arm +## +*|Waterelemental||||||5352|934|-5|2|2|10|10|10|1|4|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5317|980|0|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 1 - Second Big Lair (near Shrine) +## +*|Giantserpent||||||5250|869|0|2|2|10|50|30|1|6|0|0|0|0|0 +*|Dragon|Drake|Wyvern||||5226|826|0|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5269|811|7|2|2|10|50|30|1|1|2|1|0|0|0 +*|Drake|Wyvern|||||5307|815|0|2|2|10|50|30|1|1|1|0|0|0|0 +*|Waterelemental||||||5294|842|0|2|2|10|50|30|1|4|0|0|0|0|0 +*|Waterelemental||||||5203|787|5|2|2|10|25|12|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5229|841|1|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5205|778|0|2|1|2|7|7|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Drake|Shadowwyrm|Wyvern||||5141|834|0|2|2|10|50|30|1|1|1|1|0|0|0 +*|Daemon|Evilmage|||||5169|836|0|2|2|10|50|30|1|2|1|0|0|0|0 +*|Drake|Shadowwyrm|Wyvern||||5152|869|0|2|2|10|50|25|1|1|1|1|0|0|0 +*|TreasureLevel4:TreasureLevel3:TreasureLevel2||||||5153|842|0|2|1|2|40|40|1|4|0|0|0|0|0 +## +## Level 3 - Ancient Wyrm Lair +## +*|Fireelemental||||||5141|968|0|2|2|10|10|10|1|1|0|0|0|0|0 +*|Wyvern:Wyvern:Giantserpent||||||5157|997|0|2|2|10|50|20|1|3|0|0|0|0|0 +*|Ancientwyrm||||||5185|1006|0|2|2|10|50|20|1|1|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5143|986|0|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5183|1007|0|2|1|2|10|10|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Fire.map b/Data/Monsters/trammel/Fire.map new file mode 100644 index 0000000..6a1ee40 --- /dev/null +++ b/Data/Monsters/trammel/Fire.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 107 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Britain/Lost Lands +## Fire Dungeon - OSI Legends like +## +## Level 1 - Part I +## +*|Slime|Giantrat|Giantserpent||||5693|1415|38|2|5|10|20|10|1|1|2|1|0|0|0 +*|Slime||||||5695|1434|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Evilmagelord||||||5680|1438|0|2|5|10|20|10|1|2|0|0|0|0|0 +*|Giantrat|Lavasnake|Evilmage||||5733|1433|22|2|5|10|20|10|1|1|1|1|0|0|0 +*|Lavalizard||||||5787|1427|17|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5717|1465|-2|2|5|10|15|10|1|3|0|0|0|0|0 +*|Fireelemental|Lavasnake|Hellcat|Hellhound|||5744|1471|2|2|5|10|15|10|1|3|1|1|1|0|0 +*|Efreet|Lavaserpent|Hellhound|Fireelemental|||5790|1451|7|2|5|10|15|5|1|1|1|1|1|0|0 +## Graveyard +*|Lich|Bonemagi:Skeletalmage|Hellcat|Hellhound|Fireelemental|Lavalizard|5852|1468|1|2|5|10|30|25|1|4|6|1|3|2|1 +*|Lavasnake||||||5852|1468|1|2|5|10|30|25|1|1|0|0|0|0|0 +## +## Level 1 - Part II +## +*|Lavalizard||||||5859|1387|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Hellcat||||||5787|1386|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5818|1379|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5836|1364|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5809|1332|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5859|1341|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental|Efreet|Lavaserpent||||5835|1304|0|2|5|10|30|15|1|4|1|1|0|0|0 +*|Hellcat|Fireelemental|||||5867|1309|0|2|5|10|20|10|1|1|1|0|0|0|0 +## +## Level 2 +## +*|Fireelemental||||||5699|1302|1|2|5|10|15|15|1|1|0|0|0|0|0 +*|Fireelemental||||||5723|1291|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound||||||5732|1297|-1|2|5|10|20|5|1|1|0|0|0|0|0 +*|Efreet|Lavalizard|||||5667|1315|5|2|5|10|20|20|1|2|1|0|0|0|0 +*|Fireelemental|Lavaserpent|||||5747|1320|0|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lavalizard|Fireelemental|||||5717|1333|6|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lich|Lichlord|||||5731|1379|0|2|5|10|7|3|1|3|1|0|0|0|0 +*|Hellhound||||||5709|1364|-1|2|5|10|20|10|1|6|0|0|0|0|0 +*|Daemon||||||5691|1347|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound|Hellcat|||||5678|1340|-2|2|5|10|30|10|1|1|1|0|0|0|0 +*|Evilmage|Hellhound|Lavasnake|Hellcat|||5651|1363|0|2|5|10|3|3|1|1|5|1|1|0|0 +*|Evilmage||||||5654|1380|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5689|1387|1|2|5|10|10|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5656|1412|0|2|5|10|10|0|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1402|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1403|0|2|5|10|3|3|1|1|0|0|0|0|0 +*|Hellhound||||||5651|1408|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage|Evilmagelord|||||5651|1418|0|2|5|10|3|2|1|1|1|0|0|0|0 +*|Evilmage||||||5650|1419|22|2|5|10|5|2|1|1|0|0|0|0|0 +*|Evilmage||||||5647|1439|22|2|5|10|15|1|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1443|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmagelord||||||5638|1439|0|2|5|10|40|0|1|1|0|0|0|0|0 +## +## Treasures +## +*|TreasureLevel2||||||5714|1465|0|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|1390|2|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5679|1438|0|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|1465|-1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5722|1390|1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5679|1439|0|2|1|2|5|5|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5650|1434|0|2|1|2|2|2|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5643|1435|0|2|1|2|2|2|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Graveyards.map b/Data/Monsters/trammel/Graveyards.map new file mode 100644 index 0000000..6dbfe67 --- /dev/null +++ b/Data/Monsters/trammel/Graveyards.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 108 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Graveyards +## +## Britain Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 +## +## Jhelom Graveyard +*|Spectre:Wraith:Shade|Skeleton|Zombie||||1285|3731|0|2|5|10|15|10|1|2|3|4|0|0|0 +## +## Cove Graveyard +*|Spectre:Shade:Wraith|Lich|Skeleton|Zombie|||2438|1100|8|2|5|10|20|10|1|1|1|1|1|0|0 +## +## Moonglow Graveyard +*|Spectre:Shade:Wraith|Skeleton|Zombie||||4545|1317|8|2|5|10|20|10|1|1|1|2|0|0|0 +##*|Lich||||||4543|1314|8|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Vesper Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||2758|867|0|2|5|10|20|20|1|2|3|4|0|0|0 +## +## Yew Graveyard +*|Skeleton||||||722|1119|0|2|5|10|20|20|1|10|0|0|0|0|0 +## +## Haven Graveyard +*|zombie:skeleton||||||3407|2652|48|2|5|10|15|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Hythloth.map b/Data/Monsters/trammel/Hythloth.map new file mode 100644 index 0000000..671d5f0 --- /dev/null +++ b/Data/Monsters/trammel/Hythloth.map @@ -0,0 +1,102 @@ +############## +## By Nerun ## +############## +overrideid 109 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Hythloth Dungeon +## +## Level 1 +## +*|Imp|Hellhound|||||5923|48|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|TreasureLevel1|||||5911|55|22|2|2|10|25|10|1|2|3|0|0|0|0 +*|Imp|Hellhound|||||5948|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|Hellhound|||||5954|26|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Imp|Hellhound|||||5977|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Firegargoyle||||||5995|62|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5970|80|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle|Hellhound|||||5994|96|0|2|2|10|20|10|1|2|1|0|0|0|0 +*|Imp|Hellhound|||||5946|75|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5940|107|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5915|91|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5990|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5985|36|22|2|1|2|2|2|1|2|0|0|0|0|0 +*|TreasureLevel1||||||5989|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5983|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5979|26|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5981|84|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5966|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5958|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5937|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5921|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5972|86|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5917|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5929|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5945|78|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5967|80|0|2|1|2|6|6|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Imp|Hellhound|||||5961|169|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Daemon||||||5992|146|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5945|175|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5956|145|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||5917|156|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5914|195|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5918|223|44|2|2|10|20|10|1|4|0|0|0|0|0 +*|Daemon|TreasureLevel4|||||5918|235|44|2|2|10|20|10|1|2|1|0|0|0|0 +*|Gargoyle|TreasureLevel3|||||5954|225|22|2|2|10|20|12|1|4|1|0|0|0|0 +*|Gazer|Gazerlarva|||||5986|203|44|2|2|10|25|12|1|3|2|0|0|0|0 +*|TreasureLevel1||||||5983|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5992|147|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5970|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5997|145|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5978|185|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5962|217|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5989|186|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5926|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Imp|Hellhound|Gargoyle||||6094|154|-22|2|2|10|20|10|1|1|1|2|0|0|0 +*|Eldergazer|Gazer|Gazerlarva||||6122|170|0|2|2|10|20|10|1|1|3|2|0|0|0 +*|Balron|Gargoyle|Gazer||||6086|178|0|2|2|10|20|10|1|1|2|2|0|0|0 +*|Daemon|Gargoyle|Gazer||||6119|219|22|2|2|10|20|10|1|2|2|2|0|0|0 +*|Gargoyle||||||6058|193|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Daemon|Stonegargoyle|||||6033|199|22|2|2|10|20|10|1|2|1|0|0|0|0 +*|Daemon|Gazer|Gazerlarva||||6052|156|0|2|2|10|20|10|1|2|3|2|0|0|0 +*|TreasureLevel2||||||6121|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6124|159|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6087|186|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6060|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6046|199|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6041|222|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6125|221|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6120|229|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6092|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6041|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6033|205|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6058|153|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Daemon|Hellhound|Imp||||6064|96|22|2|2|10|20|10|1|2|1|1|0|0|0 +*|Gargoyle||||||6081|83|21|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6084|66|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6106|67|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Firegargoyle||||||6116|86|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6099|51|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Balron||||||6107|37|22|2|2|10|20|10|1|1|0|0|0|0|0 +*|Gazer|Imp|Stonegargoyle||||6054|45|0|2|2|10|20|10|1|1|1|1|0|0|0 +*|TreasureLevel2||||||6108|66|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||6117|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6058|92|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6113|92|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6107|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6081|44|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6097|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6064|96|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6086|45|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6108|36|22|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Ice.map b/Data/Monsters/trammel/Ice.map new file mode 100644 index 0000000..90784e5 --- /dev/null +++ b/Data/Monsters/trammel/Ice.map @@ -0,0 +1,53 @@ +############## +## By Nerun ## +############## +overrideid 110 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Ice Dungeon +## +## Level 1 +## +*|Arcticogrelord||||||5771|224|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Iceserpent|Snowelemental|Ratman|Frosttroll|Frostspider||5799|188|-6|2|5|10|25|10|1|2|1|1|1|1|0 +*|Frostspider|Frostooze|Icesnake||||5867|218|-4|2|5|10|25|15|1|1|2|1|0|0|0 +*|Ratmanmage||||||5850|219|-3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Arcticogrelord||||||5814|237|0|2|5|7|15|15|1|1|0|0|0|0|0 +*|Whitewyrm||||||5752|144|9|2|2|5|10|10|1|1|0|0|0|0|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5839|159|0|2|5|10|20|15|1|1|1|1|1|1|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5785|161|-6|2|5|10|20|18|1|1|1|1|1|1|0 +*|Iceserpent|Ratman|Snowelemental:Iceelemental|Frosttroll|||5757|213|-7|2|5|10|20|15|1|3|1|4|2|0|0 +*|Iceserpent|Snowelemental:Iceelemental|Frosttroll|Ratman|||5681|191|-6|2|5|10|20|15|1|3|4|1|1|0|0 +*|Iceserpent|Snowelemental:Iceelemental|||||5731|176|-5|2|5|10|35|25|1|9|9|0|0|0|0 +## Treasures +*|TreasureLevel2||||||5848|226|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5683|197|-4|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5721|147|-1|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5758|139|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5754|211|-6|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5833|242|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5854|227|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5772|188|-3|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5837|245|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5751|140|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5763|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5756|203|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5712|145|-34|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5684|181|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ratman Room +## +*|Ratman|Ratmanarcher|Ratmanmage||||5831|358|-1|2|5|10|25|15|1|12|7|5|0|0|0 +*|TreasureLevel2||||||5838|355|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5824|363|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ice Demon Lair +## +*|Icefiend||||||5680|306|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|Icefiend||||||5669|330|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5696|303|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5682|314|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5666|331|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5676|331|0|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/LostLands.map b/Data/Monsters/trammel/LostLands.map new file mode 100644 index 0000000..b57ac8d --- /dev/null +++ b/Data/Monsters/trammel/LostLands.map @@ -0,0 +1,341 @@ +############## +## By Nerun ## +############## +overrideid 111 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## T2A - Lost Lands +## +## Papua +## +*|Swampdragon||||||5728|3209|-3|2|5|10|100|100|1|7|0|0|0|0|0 +## +## T2ADesertMain +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5457|2651|45|2|5|10|150|150|1|15|15|6|9|6|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5457|2651|45|2|5|10|150|150|1|3|6|4|6|0|0 +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5520|2890|33|2|5|10|100|100|1|10|10|4|6|4|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5520|2890|33|2|5|10|100|100|1|3|4|2|4|0|0 +## +## T2ADesCent +## +*|Gazer|Reaper|Scorpion|Giantserpent|Troll||5580|2885|6|2|5|10|15|15|1|3|2|3|2|2|0 +## +## T2ADryCenter +## +*|Corpser|Giantspider|Troll|Harpy|Ettin|Gazer|5557|2625|0|2|5|10|40|40|1|3|3|3|6|3|3 +## +## T2ACyclop +## +*|Cyclops|Titan|||||5394|2530|6|2|5|10|25|15|1|5|3|0|0|0|0 +## +## T2ADesertFinal +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Wyvern|5711|2494|46|2|5|10|80|80|1|3|3|1|3|2|1 +*|Ettin||||||5711|2494|46|2|5|10|80|80|1|2|0|0|0|0|0 +## +## T2ABaseOph +## +*|Ophidianarchmage|Ophidianmage|Ophidianmatriarch|Ophidianknight|Ophidianwarrior||5765|2637|39|2|5|10|30|25|1|3|6|3|4|10|0 +## +## T2AWyvern +## +*|Wyvern|Drake|Imp|Mongbat|||5697|2626|-2|2|5|10|30|25|1|2|4|1|2|0|0 +## +## T2ASmallDesert +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5729|2767|-1|2|5|10|70|60|1|8|8|3|5|3|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5729|2767|-1|2|5|10|70|60|1|3|3|3|5|0|0 +## +## T2ALava +## +*|Hellhound|Lavalizard|Fireelemental|Efreet|Hellcat|Lavaserpent|5724|2949|31|2|5|10|75|65|1|8|8|10|4|6|8 +*|Lavasnake||||||5724|2949|31|2|5|10|75|65|1|15|0|0|0|0|0 +## +## T2AWyvIsle +## +*|Wyvern||||||5863|2470|46|2|5|10|25|25|1|6|0|0|0|0|0 +## +## T2AIce1 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5501|2361|27|2|5|10|75|40|1|4|8|4|4|5|5 +*|Polarbear||||||5501|2361|27|2|5|10|75|40|1|5|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5351|2359|0|2|5|10|75|40|1|4|7|4|4|5|5 +*|Polarbear||||||5351|2359|0|2|5|10|75|40|1|5|0|0|0|0|0 +## +## T2AIce2 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5173|2368|21|2|5|10|50|30|1|4|10|4|4|3|3 +*|Polarbear||||||5173|2368|21|2|5|10|50|30|1|3|0|0|0|0|0 +## +## T2ALastIceIsle +## +*|Iceserpent|Icesnake|Snowelemental|Whitewolf|Walrus|Polarbear|6091|2379|25|2|5|10|60|30|1|6|10|3|3|3|3 +## +## T2AIceFinal +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5967|2370|44|2|5|10|75|50|1|6|4|4|4|4|4 +*|Polarbear||||||5967|2370|44|2|5|10|75|50|1|4|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5817|2367|42|2|5|10|75|50|1|6|3|3|3|4|4 +*|Polarbear||||||5817|2367|42|2|5|10|75|50|1|4|0|0|0|0|0 +## +## T2AFor3 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5756|3453|-2|2|5|10|130|130|1|10|10|10|2|10|0 +## +## T2ASwamp +## +*|Gianttoad|Swampdragon|Giantrat|Alligator|Sewerrat|Plaguebeast|5985|3441|17|2|5|10|90|80|1|8|5|12|12|11|2 +*|Bullfrog|Swamptentacle|Bogling|Bogthing|||5985|3441|17|2|5|10|90|80|1|15|5|13|3|0|0 +## +## T2AUndead +## +*|Boneknight|Skeletalknight|Bonemagi|Skeleton|Wraith|Ghoul|5220|3664|-1|2|5|10|25|20|1|3|3|3|6|4|4 +## +## T2ASavage +## +*|Savagerider|Savage|Savageshaman||||5212|3619|0|2|5|10|15|10|1|3|9|3|0|0|0 +## +## T2ADeer +## +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5347|3449|17|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5243|3548|14|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5250|3449|16|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5349|3547|-1|2|5|10|50|50|1|4|8|4|4|16|4 +## +## T2AWild1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5201|3162|53|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5201|3162|53|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5251|3301|-2|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5251|3301|-2|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5250|3401|1|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5250|3401|1|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5351|3401|30|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5351|3401|30|2|5|10|50|50|1|2|2|2|0|0|0 +## +## T2AWild1&2 - 1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6018|3673|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6018|3673|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6018|3673|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6018|3673|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 2 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3773|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3773|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3773|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3773|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 3 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|2874|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|2874|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|2874|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|2874|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 4 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3971|17|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3971|17|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3971|17|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3971|17|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 5 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5920|3675|12|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5920|3675|12|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5920|3675|12|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5920|3675|12|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 6 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5921|3777|28|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5921|3777|28|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5921|3777|28|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5921|3777|28|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 7 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5919|3875|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5919|3875|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5919|3875|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5919|3875|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 8 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5918|3975|1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5918|3975|1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5918|3975|1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5918|3975|1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 9 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3675|0|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3675|0|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3675|0|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3675|0|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 10 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3775|48|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3775|48|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3775|48|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3775|48|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 11 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5818|3876|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5818|3876|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5818|3876|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5818|3876|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 12 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5819|3974|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5819|3974|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5819|3974|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5819|3974|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 13 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3675|22|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3675|22|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3675|22|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3675|22|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 14 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5722|3776|32|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5722|3776|32|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5722|3776|32|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5722|3776|32|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 15 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3876|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3876|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 16 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3975|21|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3975|21|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3975|21|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3975|21|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 17 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3676|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3676|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 18 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5621|3775|2|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5621|3775|2|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5621|3775|2|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5621|3775|2|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 19 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3875|15|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3875|15|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3875|15|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3875|15|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 20 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5624|3975|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5624|3975|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 21 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5523|3676|45|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5523|3676|45|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5523|3676|45|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5523|3676|45|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 22 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3775|8|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3775|8|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3775|8|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3775|8|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 23 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3875|-1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3875|-1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 24 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5478|3587|3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5478|3587|3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5478|3587|3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5478|3587|3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild3 +## +*|Forestostard|Ridablellama|||||5520|3939|42|2|5|10|25|25|1|3|3|0|0|0|0 +## +## T2AFrenz +## +*|Frenziedostard||||||5784|3951|20|2|5|10|35|35|1|8|0|0|0|0|0 +## +## T2ASpawner1 +## +*|Imp|Mongbat|||||5764|2585|-4|2|5|10|75|2|1|2|5|0|0|0|0 +*|Imp|Harpy|Headlessone|Scorpion|Stoneharpy|Wyvern|5838|2651|0|2|5|10|75|2|1|1|1|1|1|1|1 +## +## T2ASpawner2 +## +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5218|3786|1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5218|3786|1|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5371|3820|-2|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5371|3820|-2|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5368|3887|0|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5368|3887|0|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5367|4003|19|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5367|4003|19|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5466|4005|-1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5466|4005|-1|2|5|10|50|50|1|4|1|0|0|0|0 +## +## T2ABull +## +*|Bull|Greathart|Cow||||5194|3885|-1|2|5|10|45|32|1|10|6|6|0|0|0 +*|Bull|Greathart|Cow||||5200|3895|2|2|5|10|20|10|1|2|2|2|0|0|0 +## +## T2ASheep +## +*|Sheep|Goat|Bull|Chicken|||5159|3913|1|2|2|5|10|15|10|7|1|1|1|1|0|0 +## +## T2AFor1 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5570|3153|14|2|5|10|80|60|1|6|6|6|1|6|0 +## +## T2AFor2 +## +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5440|3292|-4|2|5|10|62|56|1|5|5|5|5|1|0 +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5566|3292|4|2|5|10|62|56|1|5|5|5|5|1|0 +## +## T2ATera1 +## +*|Terathanmatriarch|Terathanavenger|Terathandrone|Terathanwarrior|||5454|3136|-60|2|5|10|25|25|1|2|4|10|10|0|0 +## +## T2Aopp +## +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5490|3071|15|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5467|3078|-3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5446|3074|3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5432|3079|-4|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5408|3077|16|2|5|10|25|5|1|1|1|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/OrcCaves.map b/Data/Monsters/trammel/OrcCaves.map new file mode 100644 index 0000000..0382e7e --- /dev/null +++ b/Data/Monsters/trammel/OrcCaves.map @@ -0,0 +1,38 @@ +############## +## By Nerun ## +############## +overrideid 112 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Britain +## Orc Caves +## +## Cave 1 +## +*|Orc|Orccaptain|Orcishlord||||5146|1995|0|2|5|15|8|8|1|1|1|1|0|0|0 +*|Orc||||||5153|1971|0|2|5|15|8|8|1|5|0|0|0|0|0 +*|Direwolf||||||5153|1961|0|2|5|15|8|8|1|2|0|0|0|0|0 +*|Orcishlord||||||5144|1960|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain||||||5141|1968|0|2|5|15|8|8|1|3|0|0|0|0|0 +## +## Cave 2 +## +*|Orc||||||5332|1365|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Noble||||||5308|1372|0|2|5|15|8|8|1|1|0|0|0|0|0 +*|Orcishlord|Orc|||||5302|1355|0|2|5|15|12|8|1|1|3|0|0|0|0 +*|Giantrat||||||5316|1332|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Direwolf||||||5331|1346|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain|Orcishlord|Orcishmage|Orcbomber|||5354|1332|0|2|5|15|8|8|1|1|1|1|1|0|0 +*|Orcbomber|Orccaptain|Orc||||5356|1304|0|2|5|15|10|8|1|1|1|2|0|0|0 +*|Orcishlord|Orcishmage|Orcbomber|Orc|||5317|1309|0|2|5|15|8|8|1|1|2|1|2|0|0 +*|Orc|Orcishmage|Orcishlord||||5300|1314|0|2|5|15|10|8|1|3|1|2|0|0|0 +*|Corpser||||||5292|1316|0|2|5|15|8|8|1|2|0|0|0|0|0 +## +## Cave 3 +## +*|Orc||||||5281|2029|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orcbrute|Orc|||||5308|2005|0|2|5|15|12|12|1|1|4|0|0|0|0 +*|Orcbomber|Orc|||||5310|1969|0|2|5|15|12|12|1|2|2|0|0|0|0 +*|Orcbomber|Earthelemental|||||5348|2011|0|2|5|15|15|10|1|1|4|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Outdoors.map b/Data/Monsters/trammel/Outdoors.map new file mode 100644 index 0000000..671a23a --- /dev/null +++ b/Data/Monsters/trammel/Outdoors.map @@ -0,0 +1,552 @@ +overrideid 113 +overridemap 2 +################################################################## +## OSI Light ## +################################################################## +overridemintime 60 +overridemaxtime 60 +*|lizardman:ratman||||||1147|3524|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1266|1982|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1249|2030|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1232|2093|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1140|2087|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1089|2033|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1067|2117|5|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:harpy:ogre:troll||||||666|1825|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||741|1838|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||733|1937|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||798|1935|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||819|1841|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||893|1861|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||879|1956|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:ogre||||||809|1615|0|2|60|80|30|30|1|6|0|0|0|0|0 +*|orcishmage||||||4461|3106|0|2|60|80|30|30|1|5|0|0|0|0|0 +*|orc||||||4729|3485|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4519|3097|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4613|3272|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4576|3356|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4658|3376|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4607|3480|29|2|60|80|30|30|1|10|0|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3168|629|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3172|700|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3173|771|0|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1473|229|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1337|293|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1184|217|27|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1284|433|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1203|502|30|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1300|607|15|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1200|633|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1162|704|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1130|830|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1013|980|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||848|917|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||840|1063|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1038|1149|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||844|1235|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||617|1326|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1831|449|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1832|517|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1749|474|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1636|532|22|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1743|589|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1887|591|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1810|647|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1631|650|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1723|683|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|earthelemental:ratman||||||1980|832|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1905|883|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1849|953|7|2|60|80|30|30|1|4|0|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||1001|787|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||987|725|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|gargoyle:gazer||||||1912|1283|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1787|1280|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1799|1394|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1652|1400|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1755|1474|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|troll||||||1325|1071|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2369|3430|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2354|3503|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2503|3593|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2520|3983|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2438|3914|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2143|3953|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|airelemental:gargoyle||||||868|488|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||805|483|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||839|406|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||841|344|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|lizardman:ratman||||||1131|3415|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1158|3457|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1094|3482|0|2|60|80|30|30|1|8|0|0|0|0|0 +################################################################## +## OSI Medium ## +################################################################## +overridemintime 20 +overridemaxtime 20 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1312|613|10|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1214|617|13|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|522|19|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1226|449|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1276|431|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1231|192|6|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1143|180|14|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1191|288|11|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1295|328|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|275|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1491|238|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3440|405|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|375|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3327|344|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3434|316|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|280|9|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3322|271|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3360|218|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3390|259|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3446|213|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3462|136|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2589|204|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|136|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2659|147|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2621|99|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|86|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2478|100|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2468|144|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2485|191|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2454|248|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2533|240|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|airelemental:ettin:orc||||||2077|434|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2107|358|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2138|323|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2189|298|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2137|271|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2113|221|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2146|178|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2093|147|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2109|109|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2115|48|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1996|73|8|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1956|48|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1944|102|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:troll||||||2034|46|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2033|74|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2058|87|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2034|108|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2000|141|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1965|160|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1946|186|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1922|173|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1894|197|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1908|214|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1891|226|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1869|265|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1626|266|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1682|252|6|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1723|252|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1759|259|21|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1804|247|0|2|20|30|30|30|1|2|11|0|0|0|0 +*|giantspider:scorpion||||||1875|906|7|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1829|874|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1852|841|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1930|864|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1883|827|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1949|824|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1987|822|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||2013|839|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1979|885|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1947|912|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1915|928|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1866|938|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1838|957|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1802|1506|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1692|1463|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1833|1245|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1726|1362|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1640|1431|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1912|1302|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1967|1296|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1898|1265|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1872|1347|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1812|1314|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1797|1393|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1862|1434|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1877|1515|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1361|1392|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1445|1365|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1375|1330|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1474|1297|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1407|1281|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1225|1477|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1222|1418|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1244|1374|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1180|1354|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1240|1317|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1340|1268|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1305|1326|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1304|1413|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1300|1481|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1541|1895|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1534|1941|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1475|1958|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1435|1917|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1383|1949|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1416|1992|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1504|2007|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1447|2038|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1479|2094|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1525|2053|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2095|2352|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2077|2305|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2021|2313|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1968|2346|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1947|2294|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1915|2385|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1891|2331|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1890|2270|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1873|2426|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1837|2334|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1826|2250|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2109|2989|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2089|3017|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2074|3069|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2033|3041|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1970|3052|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1915|3050|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1866|3040|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1812|3036|5|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1841|3000|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1803|2981|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1867|2962|7|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1849|2915|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1911|2934|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1954|2903|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||851|495|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||805|463|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||837|361|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1029|1969|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1080|1963|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1042|1920|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||821|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||736|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||899|1851|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||759|1828|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||672|1825|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||892|1963|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|giantspider:orc:ratman:spectre:zombie||||||815|1603|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1055|1442|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1021|1415|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1060|1375|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1004|1369|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1037|1325|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||971|1308|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||1000|330|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||964|365|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||947|418|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||956|452|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||423|1595|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||418|1665|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||480|1641|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||516|1585|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||541|1645|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||141|1367|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||189|1344|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||232|1350|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||278|1355|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||229|1419|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||182|1428|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||157|1487|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||204|1483|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||240|1443|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||269|1474|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4013|239|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3929|235|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3920|287|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4090|325|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4162|395|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4206|471|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3928|393|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3963|508|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4066|569|0|2|20|30|80|80|1|8|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4153|601|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4214|655|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4264|725|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2963|3617|3|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2966|3591|11|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3013|3591|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3024|3566|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3042|3590|5|2|20|30|30|30|1|7|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2462|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2428|722|8|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2375|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2345|676|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2429|690|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2379|654|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2326|656|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2319|591|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||659|1318|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||579|1305|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||728|1242|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||793|1088|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||849|1262|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||909|1175|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||974|1186|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1059|1166|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||823|960|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||960|910|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1042|1024|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1147|1048|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1097|970|2|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1192|958|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1166|818|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1083|783|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1268|774|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1180|737|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1122|718|1|2|20|30|30|30|1|11|1|0|0|0|0 +################################################################## +## OSI Heavy + Miscellaneous ## +################################################################## +overridemintime 5 +overridemaxtime 10 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||423|1595|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||418|1665|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||480|1641|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||516|1585|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||541|1645|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4504|1458|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4494|1426|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1434|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4456|1405|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1358|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|greathart|hind|||||4550|1409|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4552|1447|10|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4615|1469|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4612|1418|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4605|1365|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4566|1359|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2372|210|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2355|179|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2351|148|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2345|112|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2328|67|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2177|3034|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2143|3068|20|2|5|10|30|30|1|7|0|0|0|0|0 +## +## Northeast Britain +## +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1983|1517|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1986|1463|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1969|1409|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|mongbat|orc|||||1912|1302|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1967|1296|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1898|1265|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1872|1347|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1812|1314|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1797|1393|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1862|1434|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1877|1515|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1802|1506|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1692|1463|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1833|1245|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1726|1362|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1640|1431|0|2|5|10|30|30|1|3|2|0|0|0|0 +## +## Orc Cave Entrance +## +*|orc:ratman||||||1055|1442|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1021|1415|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1060|1375|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1004|1369|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1037|1325|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||971|1308|0|2|5|10|30|30|1|6|0|0|0|0|0 +## +## Orc Fort (South Cove) +## +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2171|1356|0|2|5|10|30|30|1|1|3|2|5|3|2 +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2184|1376|0|2|5|10|30|15|1|1|3|2|5|3|2 +*|TreasureLevel2|TreasureLevel3|||||2155|1370|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2203|1379|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## The Bog of Desolation (West Covetous) +## +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2038|1023|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2079|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2067|989|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2028|987|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2033|936|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1990|976|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1993|1030|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2035|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2023|1052|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2069|1028|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2048|1066|0|2|5|10|30|30|1|3|1|3|0|0|0 +## +## East Skara Brae +## +*|orc|ettin|ratman|giantspider|reaper||1435|2261|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1651|2413|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1619|2725|10|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1427|2525|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1059|2461|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1243|2437|5|2|5|10|150|150|1|10|10|10|10|10|0 +## +## East Skara Brae: Hedge Maze +## +*|Daemon||||||1145|2231|20|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1072|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1070|2256|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1215|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1216|2259|5|2|5|10|30|20|1|4|0|0|0|0|0 +## +## South Destard / Trinsic +## +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1595|3045|0|2|5|10|100|60|1|5|5|5|5|5|5 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|2091|3413|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1931|3205|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1827|3429|10|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1635|3253|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1387|3109|0|2|5|10|150|150|1|10|10|10|10|10|10 +## +## Main Destard Orcs +## +*|Headlessone|Orc|Orccaptain|Orcishlord|Orcishmage||1110|2672|0|2|5|10|20|20|1|3|6|1|2|1|0 +## +## The Destard Swamps +## +*|Toxicelemental:Alligator:Bogthing:Bogling:Corpser:GiantRat:Giantserpent|Lizardman:strongmongbat:Plaguebeast:Plaguespawn:Ratman:Sewerrat:Snake|Wisp||||1158|2872|0|2|5|10|130|130|1|24|23|3|0|0|0 +*|Savage|Savagerider|Savageshaman||||1141|2959|0|2|5|10|20|20|1|2|1|1|0|0|0 +*|Savage|Savagerider|Savageshaman||||1166|2958|0|2|5|10|20|20|1|2|1|1|0|0|0 +## +## Yew-Britain Brigand Camp +## +*|Brigand||||||854|1686|0|2|1|10|20|15|1|7|0|0|0|0|0 +## +## Yew Liches +## +*|Lich||||||757|1401|0|2|1|10|30|30|1|8|0|0|0|0|0 +## +## Yew Orc Fort +## +*|Orc|Orcishlord|Orcishmage||||634|1504|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcishlord|Orcishmage||||634|1462|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcbomber|Orccaptain|Orcishlord|Orcishmage||633|1484|0|2|1|10|20|10|1|8|1|1|2|2|0 +## +## Yew Fort of the Damned +## +*|Skeleton||||||965|757|0|2|5|10|10|5|1|2|0|0|0|0|0 +*|Wraith:Shade:Spectre|Ghoul|||||955|707|0|2|5|10|12|8|1|4|4|0|0|0|0 +*|Wraith:Shade:Spectre||||||962|692|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Wraith:Shade:Spectre||||||948|703|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Lich||||||1016|821|0|2|5|10|10|2|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||1015|706|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||1017|826|0|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Hythloth Fire Pit +## +*|Daemon|Drake|||||4596|3607|30|2|5|10|50|25|1|1|2|0|0|0|0 +*|Dragon|Drake|||||4571|3572|31|2|1|10|50|25|1|1|2|0|0|0|0 +*|Daemon||||||4595|3574|75|2|1|10|50|25|1|3|0|0|0|0|0 +*|Dragon|Drake|||||4618|3570|30|2|1|10|50|25|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||4595|3570|30|2|1|2|8|8|1|3|3|0|0|0|0 +## +## Near Shame: The Wisp Circle +## +*|Wisp||||||608|1702|0|2|5|10|30|30|1|8|0|0|0|0|0 +## +## Moonglow Zoo +## +*|Ghoul|Giantrat|Giantserpent|Headlessone|Jwilson||4530|1387|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Iceserpent|Icesnake|Polarbear|Snowleopard|Whitewolf|Frostooze|4511|1394|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Frostspider|Frosttroll|||||4511|1394|23|2|5|10|10|4|1|1|4|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Rabbit:JackRabbit|Cougar:Panther|Bird:Eagle||4498|1394|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Corpser|Swamptentacle|||4485|1387|23|2|5|10|15|4|1|2|3|1|1|0|0 +*|Giantserpent|Giantspider|Boar|Greathart|Hind|Llama|4493|1364|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Horse|Rat|||||4493|1364|23|2|5|10|10|4|1|1|1|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Cougar:Panther|Giantserpent|Greathart||4506|1358|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Gorilla|Giantserpent|Gianttoad||4519|1358|23|2|5|10|15|4|1|1|1|1|1|1|0 +*|Mummy|Ophidianwarrior|Scorpion|Giantserpent|||4531|1363|23|2|5|10|15|4|1|1|1|1|1|0|0 +*|Rottingcorpse|Skeleton|Slime|Snake|Strongmongbat||4512|1372|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Ghoul|Giantserpent|Headlessone|Jwilson|Zombie||4512|1380|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Cat|Chicken|Dog|Pig|Sheep||4500|1382|23|2|5|10|10|1|1|1|1|1|1|1|0 +################################################################## +## CAMPS ## +################################################################## +overridemintime 45 +overridemaxtime 60 +*|Orccamp:Ratcamp||||||821|675|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1042|1394|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2540|130|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3170|672|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2548|1173|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||4480|1439|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1152|3471|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1530|999|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1871|1076|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||788|1894|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1064|2488|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2103|3371|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2044|2323|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1939|1310|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2349|722|0|2|45|60|10|1|1|1|0|0|0|0|0 +################################################################## +## HAVEN ISLAND (UO Client +6.0.0.0) ## +################################################################## +overridemintime 5 +overridemaxtime 10 +## +## Old Haven - north +## +*|zombie:skeleton|spellbinder|||||3650|2509|0|2|5|10|60|60|1|70|20|0|0|0|0 +*|spellbinder:zombie:skeleton||||||3598|2450|16|2|5|10|10|10|1|4|0|0|0|0|0 +## +## Old Haven - south +## +*|skeleton||||||3635|2625|0|2|5|10|15|6|1|7|0|0|0|0|0 +*|skeleton||||||3651|2627|0|2|5|10|15|8|1|10|0|0|0|0|0 +*|zombie||||||3625|2594|0|2|5|10|15|8|1|10|0|0|0|0|0 +*|zombie||||||3649|2591|0|2|5|10|15|8|1|10|0|0|0|0|0 +*|healer||||||3618|2614|0|2|5|10|4|4|1|1|0|0|0|0|0 +## +## Farmlands +## +*|sheep||||||3725|2670|35|2|5|10|40|40|1|10|0|0|0|0|0 +*|sheep||||||3727|2603|40|2|5|10|40|40|1|10|0|0|0|0|0 +*|pumpkin||||||3738|2586|40|2|5|10|12|12|1|40|0|0|0|0|0 +*|pumpkin||||||3711|2571|20|2|5|10|6|6|1|6|0|0|0|0|0 +*|pumpkin||||||3738|2610|40|2|5|10|12|12|1|40|0|0|0|0|0 +*|pumpkin||||||3716|2612|20|2|5|10|6|5|1|5|0|0|0|0|0 +*|pumpkin||||||3716|2617|20|2|5|10|6|5|1|5|0|0|0|0|0 +*|pumpkin||||||3716|2624|21|2|5|10|6|5|1|5|0|0|0|0|0 +*|pumpkin||||||3744|2660|40|2|5|10|12|12|1|50|0|0|0|0|0 +*|pumpkin||||||3716|2632|20|2|5|10|6|5|1|5|0|0|0|0|0 +*|pumpkin||||||3751|2704|39|2|5|10|6|6|1|12|0|0|0|0|0 +*|pumpkin||||||3711|2669|20|2|5|10|6|6|1|8|0|0|0|0|0 +*|pumpkin||||||3711|2690|20|2|5|10|6|6|1|8|0|0|0|0|0 +*|pumpkin||||||3711|2679|20|2|5|10|6|6|1|8|0|0|0|0|0 +## +## Small southeast island +## +*|corpser|lizardman|||||3772|2771|56|2|5|10|30|20|1|2|2|0|0|0|0 +## +## Wild life and monsters +## +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:gaman:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3396|2645|48|2|5|10|50|50|1|14|5|40|5|5|5 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3742|2520|47|2|5|10|40|40|1|12|4|28|4|4|4 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3403|2572|21|2|5|10|30|30|1|6|2|14|2|2|2 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3690|2422|40|2|5|10|50|47|1|12|4|28|4|4|4 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3615|2410|47|2|5|10|30|25|1|6|1|7|1|1|1 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3549|2409|16|2|5|10|40|40|1|10|4|28|4|4|4 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3483|2389|17|2|5|10|25|25|1|6|1|7|1|1|1 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3575|2523|0|2|5|10|40|30|1|6|2|14|2|2|2 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3524|2459|28|2|5|10|25|25|1|6|1|7|1|1|1 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3482|2459|35|2|5|10|25|25|1|6|1|7|1|1|1 +*|mongbat:bogling|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3436|2486|27|2|5|10|25|25|1|6|1|7|1|1|1 +*|mongbat:bogling:ettin|timberwolf:greywolf|bull:eagle:hind:bird:llama:goat:gaman:greathart|cougar:panther|blackbear:brownbear|rabbit:jackrabbit|3450|2734|49|2|5|10|70|50|1|36|10|80|10|10|10 +## +## Brigand camps +## +*|brigandcamp||||||3700|2699|20|2|5|10|4|4|1|1|0|0|0|0|0 +*|brigandcamp||||||3753|2705|40|2|5|10|4|4|1|1|0|0|0|0|0 +*|brigandcamp||||||3764|2662|62|2|5|10|0|0|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/PaintedCaves.map b/Data/Monsters/trammel/PaintedCaves.map new file mode 100644 index 0000000..eecfa10 --- /dev/null +++ b/Data/Monsters/trammel/PaintedCaves.map @@ -0,0 +1,13 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 114 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Painted Caves +## +*|cat:dog:rat|cat|dog|rat|||6279|880|1|2|5|10|30|30|1|6|1|1|1|0|0 +*|troglodyte|grobu|lurg|giantrat|||6275|879|-2|2|5|10|30|30|1|3|3|3|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/PalaceOfParoxysmus.map b/Data/Monsters/trammel/PalaceOfParoxysmus.map new file mode 100644 index 0000000..e018df2 --- /dev/null +++ b/Data/Monsters/trammel/PalaceOfParoxysmus.map @@ -0,0 +1,25 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 115 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Palace of Paroxysmus +## +*|daemon:succubus|InterredGrizzle:poisonelemental|plaguebeast:plaguespawn|corrosiveslime|putrifier|plaguebeastlord|6295|616|-50|1|5|10|50|50|1|6|6|6|3|3|3 +*|InterredGrizzle|corrosiveslime|poisonelemental|balron:succubus:daemon|plaguebeastlord:plaguebeast:plaguespawn||6384|580|-50|1|5|10|30|30|1|4|4|3|9|11|0 +*|poisonelemental||||||6328|517|-50|1|5|10|10|10|1|4|0|0|0|0|0 +*|plaguebeast:corrosiveslime|poisonelemental:plaguespawn|||||6354|455|-40|1|5|10|20|20|1|5|5|0|0|0|0 +*|plaguebeast:plaguespawn|toxicelemental:corrosiveslime|||||6416|447|-40|1|5|10|20|20|1|8|7|0|0|0|0 +*|balron:succubus:daemon|corrosiveslime|plaguebeastlord:plaguebeast:plaguespawn|InterredGrizzle:poisonelemental|||6466|543|-50|1|5|10|30|30|1|6|3|8|5|0|0 +*|chaosdaemon:moloch|succubus:daemon|balron||||6292|462|-50|1|5|10|40|40|1|7|7|4|0|0|0 +*|earthelemental:corrosiveslime||||||6298|395|60|1|5|10|8|8|1|2|0|0|0|0|0 +*|toxicelemental:plaguespawn|toxicelemental|plaguespawn||||6404|378|-40|1|5|10|18|18|1|2|1|1|0|0|0 +*|plaguespawn:plaguebeast:toxicelemental:corrosiveslime:poisonelemental|plaguespawn|plaguebeast|toxicelemental|corrosiveslime|poisonelemental|6418|358|-40|1|5|10|25|25|1|12|2|2|2|2|2 +*|earthelemental:corrosiveslime:toxicelemental:plaguespawn|earthelemental|corrosiveslime|toxicelemental|plaguespawn||6319|348|60|1|5|10|20|20|1|5|1|1|1|1|0 +*|toxicelemental:earthelemental:corrosiveslime|toxicelemental|earthelemental|corrosiveslime|||6249|352|60|1|5|10|15|15|1|6|1|1|1|0|0 +*|poisonelemental||||||6285|353|60|1|5|10|5|5|1|1|0|0|0|0|0 +*|earthelemental:corrosiveslime||||||6353|400|60|1|5|10|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/PrismOfLight.map b/Data/Monsters/trammel/PrismOfLight.map new file mode 100644 index 0000000..2f283fe --- /dev/null +++ b/Data/Monsters/trammel/PrismOfLight.map @@ -0,0 +1,32 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 116 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Prism of Light +## +*|CrystalLatticeSeeker||||||6553|157|0|1|5|10|8|8|1|3|0|0|0|0|0 +*|Rat:Icesnake||||||6474|74|-34|1|5|10|4|4|1|9|0|0|0|0|0 +*|wisp:CrystalWisp:treasurelevel2|treasurelevel2|||||6552|155|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|wisp||||||6521|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|wisp||||||6530|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalSeaSerpent||||||6576|91|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|UnfrozenMummy||||||6509|176|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalDaemon||||||6536|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalDaemon||||||6547|91|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalHydra||||||6572|89|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|treasurelevel4||||||6504|181|0|1|5|10|1|1|1|1|0|0|0|0|0 +*|ShadowWisp||||||6475|101|-44|1|5|10|5|5|1|5|0|0|0|0|0 +*|wisp:Crystalwisp||||||6478|174|4|1|5|10|10|10|1|6|0|0|0|0|0 +*|Crystalvortex:iceelemental||||||6566|120|0|1|5|10|15|15|1|7|0|0|0|0|0 +*|CrystalWisp||||||6534|178|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalWisp:CrystalLatticeSeeker:treasurelevel2|treasurelevel2|||||6535|179|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|treasurelevel3||||||6502|120|-10|1|5|10|0|0|1|1|0|0|0|0|0 +*|protector||||||6507|151|0|1|5|10|5|5|1|3|0|0|0|0|0 +*|CrystalDaemon||||||6532|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|Ferret||||||6578|183|31|1|5|10|5|5|1|2|0|0|0|0|0 +*|protector||||||6510|171|0|1|5|10|8|8|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Reagents.map b/Data/Monsters/trammel/Reagents.map new file mode 100644 index 0000000..0ef82f8 --- /dev/null +++ b/Data/Monsters/trammel/Reagents.map @@ -0,0 +1,70 @@ +############## +## By Nerun ## +############## +overrideid 129 +overridemap 2 +overridemintime 11 +overridemaxtime 23 +## +## Trammel Reagents +## +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2854|816|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4590|1448|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2490|1096|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1566|1140|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1514|1584|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1938|1408|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2374|652|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2054|516|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1286|504|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||746|636|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1134|964|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||718|1180|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||342|1464|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||702|1752|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1114|1416|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1150|1876|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1582|2028|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1934|2328|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1490|2472|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1070|2320|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1466|3032|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2062|964|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1846|3260|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1078|2772|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4710|3796|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5926|3888|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5474|3904|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5934|3436|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5462|3452|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5674|3120|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5618|2744|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5326|2492|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5966|2456|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5234|3068|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||6042|2916|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3602|2948|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3538|2536|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2734|2168|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3714|2152|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3674|1216|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3994|328|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4166|584|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3198|504|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2750|368|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1694|688|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||366|900|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||642|2216|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2226|3532|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1850|2796|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1658|236|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4426|1028|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2522|84|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3130|116|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2082|60|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2930|3476|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1410|3796|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1122|3524|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2474|3956|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4570|3340|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4282|3700|0|2|11|23|200|200|1|160|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Sanctuary.map b/Data/Monsters/trammel/Sanctuary.map new file mode 100644 index 0000000..6486f30 --- /dev/null +++ b/Data/Monsters/trammel/Sanctuary.map @@ -0,0 +1,19 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 117 +overridemap 2 +overrridemintime 5 +overridemaxtime 10 +## +## Sanctuary +## +*|chicken:bird|dog|cat|cow:bull|pig|boar|6263|118|-10|1|5|10|20|20|1|6|3|3|6|3|3 +*|ratman:ratmanarcher:chiikkaha:titan:cyclops:rat|ratman:ratmanarcher|chiikkaha|titan|cyclops|rat|6349|89|-20|1|5|10|70|70|1|18|4|2|2|2|2 +*|ratman:ratmanarcher:ratmanmage:changeling:doppleganger|dog:chicken:cat:boar:bird|gargoyle|titan|cyclops|orcishmage:orcscout|6168|117|0|1|5|10|30|30|1|11|9|3|3|3|5 +*|ogrelord:orcishlord:ratman|bird:cow:bull:pig:chicken|||||6189|71|0|1|5|10|25|25|1|8|4|0|0|0|0 +*|titan:ettin:doppleganger:mougguur|dog:chicken:rat:cow:bull|orcbomber:orcbrute:orc|snake:gargoyle:ogre|||6187|101|0|1|5|10|25|25|1|10|10|7|7|0|0 +*|bird:chicken:rat:dog|doppleganger|||||6184|29|0|1|5|10|10|10|1|6|3|0|0|0|0 +*|szavetra:imp:titan:snake:ratman:doppleganger:gargoyle|cow:bull:chicken:bird:pig:dog:goat:cat:rat|orc:orccaptain:orcishmage|ogre:ogre:ogrelord|||6265|48|-10|1|5|10|30|30|1|22|18|9|4|0|0 +*|changeling:ratman:ettin:titan:ratmanarcher:ratmanmage|goat:pig:cow:bull:rat|gargoyleenforcer:gargoyledestroyer:gargoyle|snake|||6191|155|0|1|5|10|25|25|1|18|12|9|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/SeaLife.map b/Data/Monsters/trammel/SeaLife.map new file mode 100644 index 0000000..756acea --- /dev/null +++ b/Data/Monsters/trammel/SeaLife.map @@ -0,0 +1,123 @@ +############## +## By Nerun ## +############## +overrideid 118 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1395|3421|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4888|375|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4352|215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3688|439|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4512|583|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|1127|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3576|823|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4016|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3992|1447|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4232|1655|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4600|1751|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|1519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3616|1807|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4032|2039|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4624|2199|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4400|2527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3984|2423|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|2119|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4912|2471|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4864|2831|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4536|2847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|3215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4192|2975|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4008|2767|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3328|2063|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3176|2383|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3088|2759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3888|3167|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3968|3895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3240|3151|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3776|3519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3344|3479|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2792|2951|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2608|3295|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2744|2567|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2368|2799|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3560|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3168|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2768|3847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1720|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||544|3719|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||896|3695|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||824|3287|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||176|3551|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||480|3351|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||512|2919|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||192|2895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||208|2503|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||840|2863|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||600|2511|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|2103|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||168|1743|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|559|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||184|191|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||592|223|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2400|2399|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3008|1895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2392|2031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2624|1775|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3408|1407|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3256|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2952|1239|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2752|1455|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2208|1703|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1866|1798|-5|2|5|10|175|175|1|15|6|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||931|141|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3267|1717|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2395|1405|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||139|1173|-5|2|5|10|130|130|1|13|4|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3123|1485|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3811|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3931|1757|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2931|3245|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2291|3181|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||979|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||147|3213|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1891|3597|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2971|1605|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1580|75|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4275|1309|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4667|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||5003|101|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3603|125|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4112|791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3891|733|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3672|1535|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4363|1981|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4995|1829|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4283|2221|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2008|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2320|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4955|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4731|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4307|3965|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2227|3533|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1187|3885|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||731|3989|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||491|4013|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||107|909|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1792|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1336|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4048|63|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4392|823|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3520|2263|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3568|3215|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4992|3791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4984|3567|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2072|2527|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2040|3751|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2288|3767|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|1879|-5|2|5|10|100|100|1|10|2|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Shame.map b/Data/Monsters/trammel/Shame.map new file mode 100644 index 0000000..358925a --- /dev/null +++ b/Data/Monsters/trammel/Shame.map @@ -0,0 +1,135 @@ +############## +## By Nerun ## +############## +overrideid 119 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Shame Dungeon +## +## Level 1 +## +*|Earthelemental|Scorpion|||||5404|93|10|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5425|58|10|2|5|10|30|30|1|7|3|0|0|0|0 +*|Earthelemental|Scorpion|||||5387|41|20|2|2|10|30|30|1|4|1|0|0|0|0 +*|Earthelemental||||||5394|11|30|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental||||||5474|20|0|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental|Scorpion|||||5477|67|20|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5468|109|35|2|2|10|30|30|1|6|20|0|0|0|0 +*|TreasureLevel1||||||5423|112|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5468|106|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5434|100|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5492|56|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5416|59|-15|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5400|45|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5448|33|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5437|11|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5399|11|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5421|117|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5468|100|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5392|10|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5445|12|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5404|43|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5443|36|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5402|58|-20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5493|51|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5434|89|20|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Airelemental||||||5575|16|10|2|2|10|30|15|1|3|0|0|0|0|0 +*|Dullcopperelemental||||||5615|18|10|2|2|10|30|15|1|6|0|0|0|0|0 +*|Airelemental||||||5568|36|0|2|2|10|30|15|1|3|0|0|0|0|0 +*|Airelemental|Waterelemental|||||5549|60|0|2|2|10|30|15|1|3|2|0|0|0|0 +*|Kraken|Waterelemental|||||5549|79|0|2|2|10|30|10|1|1|3|0|0|0|0 +*|Kraken|Seaserpent|||||5595|82|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Dullcopperelemental||||||5603|93|0|2|2|10|25|12|1|2|0|0|0|0|0 +*|Dullcopperelemental||||||5603|116|0|2|2|10|30|15|1|4|0|0|0|0|0 +*|TreasureLevel1||||||5536|119|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5546|118|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5606|25|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5570|118|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5620|21|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5572|113|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5546|113|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Earthelemental||||||5474|139|20|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental|Poisonelemental|||||5477|183|0|2|2|10|30|15|1|1|4|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5469|211|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Evilmage|Evilmagelord|||||5441|187|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Airelemental|Earthelemental|||||5412|164|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5411|163|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental|Earthelemental|||||5412|201|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5412|200|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental||||||5394|230|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Eldergazer||||||5505|180|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Dullcopperelemental|Fireelemental|||||5527|210|0|2|2|10|30|15|1|4|2|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5557|222|0|2|2|10|25|10|1|2|2|3|0|0|0 +*|Evilmage|Evilmagelord|||||5577|194|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5594|182|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Earthelemental|Scorpion|||||5571|158|-10|2|2|10|30|15|1|4|2|0|0|0|0 +*|Earthelemental|Fireelemental|||||5593|141|10|2|2|10|30|15|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5398|148|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5545|153|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5594|139|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5604|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5608|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5605|202|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5439|137|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5390|145|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5456|157|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5410|170|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5415|189|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5396|226|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5553|146|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5595|147|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5615|173|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5616|184|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5456|143|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5432|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5474|176|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5406|177|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|185|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|200|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5403|235|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5475|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Airelemental||||||5875|44|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental||||||5856|107|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Airelemental||||||5845|57|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Kraken|Seaserpent|||||5828|42|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Evilmage|Evilmagelord|||||5819|50|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Eldergazer||||||5818|80|0|2|2|10|30|10|1|2|0|0|0|0|0 +*|Airelemental||||||5804|12|0|2|2|10|30|15|1|5|0|0|0|0|0 +*|Bloodelemental||||||5721|12|10|2|2|10|30|15|1|8|0|0|0|0|0 +*|Fireelemental||||||5661|16|-10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental||||||5649|101|10|2|2|10|30|15|1|4|0|0|0|0|0 +*|Bloodelemental||||||5684|117|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental|Fireelemental|||||5724|118|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Toxicelemental|Fireelemental|Scorpion||||5760|99|0|2|2|10|30|15|1|2|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5711|97|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5752|44|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Waterelemental|||||5708|43|0|2|2|10|25|10|1|1|3|0|0|0|0 +*|TreasureLevel1||||||5730|90|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5723|73|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5715|61|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5701|60|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5817|83|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5730|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5717|60|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5699|61|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5817|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5733|91|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5725|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|58|2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5698|57|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5733|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5727|72|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5717|58|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5701|58|2|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/SolenHive.map b/Data/Monsters/trammel/SolenHive.map new file mode 100644 index 0000000..f5f2c5c --- /dev/null +++ b/Data/Monsters/trammel/SolenHive.map @@ -0,0 +1,92 @@ +############## +## By Nerun ## +############## +overrideid 120 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Solen Hive Dungeon +## +## AREA A - Yew Lich Ruins (731 1452 0) +## +## Level 1 +## +*|Redsolenworker||||||5670|1807|4|2|5|10|30|25|1|2|0|0|0|0|0 +*|Redsolenworker||||||5673|1846|1|2|5|10|20|6|1|1|0|0|0|0|0 +*|Redsolenworker||||||5693|1834|0|2|5|10|20|4|1|1|0|0|0|0|0 +*|Redsolenworker||||||5704|1807|4|2|5|10|20|6|1|1|0|0|0|0|0 +*|Redsolenworker||||||5722|1820|5|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Redsolenwarrior||||||5709|1874|1|2|5|10|50|10|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5681|1886|2|2|5|10|50|10|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5756|1857|4|2|5|10|50|10|1|1|0|0|0|0|0 +## +## AREA B - Between Minoc/Covetous (2609 764 0) +## +## Level 1 +## +*|Redsolenworker||||||5912|1800|1|2|5|10|30|20|1|1|0|0|0|0|0 +*|Redsolenworker||||||5920|1842|1|2|5|10|30|15|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Antlion||||||5887|1840|-18|2|5|10|25|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5847|1819|1|2|5|10|25|10|1|2|0|0|0|0|0 +*|Redsolenworker||||||5829|1798|1|2|5|10|15|10|1|1|0|0|0|0|0 +*|Redsolenworker|Redsolenqueen|||||5873|1798|0|2|5|10|15|10|1|2|1|0|0|0|0 +*|Redsolenwarrior||||||5782|1793|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5799|1857|5|2|5|10|20|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5815|1881|2|2|5|10|20|7|1|1|0|0|0|0|0 +*|Beetle||||||5831|1910|3|2|5|10|15|10|1|2|0|0|0|0|0 +## +## AREA C - West Trinsic Main Gate (1691 2790 0) +## +## Level 1 +## +*|Redsolenworker||||||5718|2024|4|2|5|10|25|15|1|2|0|0|0|0|0 +*|Redsolenworker||||||5776|2019|2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Antlion||||||5782|2021|-11|2|5|10|25|10|1|1|0|0|0|0|0 +*|Dreadspider||||||5767|1962|2|2|5|10|50|15|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5671|1979|0|2|5|10|30|20|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5703|1991|0|2|5|10|35|20|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Redsolenwarrior||||||5699|1921|2|2|5|10|30|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5748|1923|0|2|5|10|20|5|1|1|0|0|0|0|0 +*|Redsolenqueen|Redsolenworker|||||5736|1939|7|2|5|10|20|10|1|1|2|0|0|0|0 +## +## AREA D - South Chaos/Compassion Road (1725 815 0) +## +## Level 1 +## +*|Redsolenworker||||||5876|2018|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5856|2018|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5838|2019|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5910|1991|0|2|5|10|25|15|1|3|0|0|0|0|0 +*|Beetle||||||5837|1992|-2|2|5|10|15|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5863|1958|2|2|5|10|25|10|1|2|0|0|0|0|0 +*|Antlion||||||5884|1920|-15|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Redsolenworker||||||5825|1968|4|2|5|10|25|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5855|1932|3|2|5|10|20|10|1|2|0|0|0|0|0 +*|Redsolenworker||||||5798|1963|0|2|5|10|35|10|1|2|0|0|0|0|0 +## +## AREA E - GreenThorn/Desert Entrance +## +*|Antlion||||||5665|1868|11|2|5|10|20|10|1|3|0|0|0|0|0 +*|Antlion||||||5707|1843|-15|2|5|10|10|10|1|1|0|0|0|0|0 +## +## INFILTRATORS +## +## Windemere +*|blacksoleninfiltratorqueen|blacksoleninfiltratorwarrior|||||3218|502|0|2|5|10|10|10|1|1|2|0|0|0|0 +## Trinsic +*|blacksoleninfiltratorqueen|blacksoleninfiltratorwarrior|||||1940|3261|1|2|5|10|10|10|1|1|2|0|0|0|0 +## Wind +*|blacksoleninfiltratorqueen|blacksoleninfiltratorwarrior|||||1361|894|0|2|5|10|8|4|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/TerathanKeep.map b/Data/Monsters/trammel/TerathanKeep.map new file mode 100644 index 0000000..61eaee0 --- /dev/null +++ b/Data/Monsters/trammel/TerathanKeep.map @@ -0,0 +1,62 @@ +############## +## By Nerun ## +############## +overrideid 121 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Lost Lands +## Terathan Keep Dungeon +## +## Terathan Keep +## +*|Balron|Dragon|Drake|Nightmare|||5296|1561|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5296|1562|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5297|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5342|1553|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5342|1552|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5343|1551|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5334|1613|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5334|1614|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5335|1615|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5348|1552|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5345|1551|0|2|1|2|1|1|1|2|0|0|0|0|0 +## +## Ophidian Territory +## +*|Balron|Dragon|Drake|Nightmare|||5344|1757|-125|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5345|1757|-125|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5346|1756|-125|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5335|1706|-70|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5335|1707|-70|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5336|1708|-70|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5270|1695|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5270|1694|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5271|1693|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5365|1707|-71|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5363|1709|-75|2|1|2|1|1|1|2|0|0|0|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5176|1702|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5176|1701|2|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5177|1700|1|2|5|15|20|10|1|1|1|1|1|0|0 +## +## Champion Room +## +*|Balron|Dragon|Drake|Nightmare|||5132|1624|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5132|1623|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5134|1625|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5160|1586|-15|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5163|1585|-15|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5161|1584|-15|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5200|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5201|1566|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5200|1568|0|2|5|15|20|10|1|1|1|1|1|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/TownsLife.map b/Data/Monsters/trammel/TownsLife.map new file mode 100644 index 0000000..bcbf8f1 --- /dev/null +++ b/Data/Monsters/trammel/TownsLife.map @@ -0,0 +1,168 @@ +############## +## By Nerun ## +############## +overrideid 122 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Towns +## +## ----Mainland---- +## +## Wind +## +*|dragon|drake|||||5249|228|15|2|5|10|20|20|1|1|2|0|0|0|0 +*|lichlord|lich|||||5164|205|15|2|5|10|15|15|1|1|2|0|0|0|0 +*|daemon||||||5133|150|0|2|5|10|15|15|1|3|0|0|0|0|0 +## +## Britain Town +## +*|Bird|Cat|Dog|Rat|||1550|1658|26|2|5|15|120|120|1|15|15|15|15|0|0 +*|Cow||||||1319|1810|0|2|5|10|10|5|1|7|0|0|0|0|0 +*|Cow||||||1319|1821|0|2|5|10|10|5|1|7|0|0|0|0|0 +## ------------------- +## +## Britain Farm 1 +## +*|Bird|Cat|Dog|Rat|||1340|1790|15|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1339|1788|15|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 2 +## +*|Bird|Cat|Dog|Rat|||1217|1825|0|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1216|1823|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 3 +## +*|Bird|Cat|Dog|Rat|||1186|1633|0|2|5|15|80|80|1|7|7|7|7|0|0 +*|Chicken||||||1185|1632|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Trinsic Town +## +*|Bird|Cat|Dog|Rat|||1937|2760|10|2|5|15|120|120|1|12|12|12|12|0|0 +## +## Skara Brae Town +## +*|Bird|Cat|Dog|Rat|||608|2195|0|2|5|15|70|70|1|8|8|8|8|0|0 +*|Chicken:Sheep:Cow||||||813|2164|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||818|2269|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||830|2353|0|2|5|15|15|10|1|3|0|0|0|0|0 +## +## Yew Town +## +*|Bird|Cat|Dog|Rat|||536|962|0|2|5|15|160|160|1|20|20|20|20|0|0 +*|Sheep||||||676|1178|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||570|1099|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||675|939|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Chicken||||||382|1192|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||560|1239|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||688|1007|0|2|5|10|10|10|1|2|0|0|0|0|0 +## +## Cove Town +## +*|Bird|Cat|Dog|Rat|||2242|1197|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken||||||2223|1151|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## Vesper Town 1 +## +*|Bird|Cat|Dog|Rat|||2939|746|2|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Vesper Town 2 +## +*|Bird|Cat|Dog|Rat|||2904|906|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Minoc Town 1 +## +*|Bird|Cat|Dog|Rat|||2481|542|0|2|5|15|70|70|1|5|5|5|5|0|0 +## +## Minoc Town 2 +## +*|Bird|Cat|Dog|Rat|||2472|434|15|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Minoc Town 3 +## +*|Bird|Cat|Dog|Rat|||2566|622|0|2|5|15|50|50|1|3|3|3|3|0|0 +## +## ----Islands---- +## +## Jhelom Town 1 +## +*|Bird|Cat|Dog|Rat|||1154|3639|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken:Cow:Sheep||||||1127|3583|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken:Cow:Sheep||||||1183|3607|0|2|5|10|10|10|1|5|0|0|0|0|0 +## +## Jhelom Town 2 +## +*|Bird|Cat|Dog|Rat|||1400|3775|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Jhelom Town 3 +## +*|Bird|Cat|Dog|Rat|||1435|4000|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Serpents Hold Town +## +*|Bird|Cat|Dog|Rat|||2972|3436|15|2|5|15|100|100|1|12|12|12|12|0|0 +## +## New Haven +## +*|cat||||||3444|2556|30|2|5|10|3|3|1|3|0|0|0|0|0 +*|dog|cat|bird||||3487|2549|16|2|5|10|100|100|1|5|5|20|0|0|0 +## +## Magincia Town 1 +## +*|Bird|Cat|Dog|Rat|||3714|2205|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Magincia Town 2 +## +*|Bird|Cat|Dog|Rat|||3717|2111|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Buccaneers Den Town 1 +## +*|Bird|Cat|Dog|Rat|||2682|2118|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Buccaneers Den Town 2 +## +*|Bird|Cat|Dog|Rat|||2687|2218|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Nujel'm Town +## +*|Bird|Cat|Dog|Rat|||3699|1238|0|2|5|15|160|160|1|18|18|18|18|0|0 +## +## Moonglow Town +## +*|Bird|Cat|Dog|Rat|||4438|1115|0|2|5|15|70|70|1|12|12|12|12|0|0 +*|Chicken:Cow:Sheep||||||4634|1302|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken||||||4567|1476|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Chicken||||||4422|1451|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## Heartwood +## +*|bird||||||7036|409|12|2|5|10|12|12|1|3|0|0|0|0|0 +*|bird||||||7048|424|0|2|5|10|20|20|1|5|0|0|0|0|0 +*|bird||||||7081|381|0|2|5|10|12|12|1|3|0|0|0|0|0 +*|bird||||||7002|382|0|2|5|10|20|12|1|5|0|0|0|0|0 +*|bird||||||6999|352|0|2|5|10|12|12|1|3|0|0|0|0|0 +*|bird||||||7047|382|0|2|5|10|12|12|1|5|0|0|0|0|0 +*|Bird||||||7033|385|0|2|5|10|50|50|1|10|0|0|0|0|0 +*|MiniatureMushroom||||||7032|411|7|2|5|10|10|10|1|4|0|0|0|0|0 +*|MiniatureMushroom||||||7044|429|0|2|5|10|10|10|1|4|0|0|0|0|0 +*|MiniatureMushroom||||||6986|384|0|2|5|10|10|10|1|4|0|0|0|0|0 +*|MiniatureMushroom||||||7063|410|0|2|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7052|386|0|2|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7035|387|0|2|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7007|382|0|2|5|10|10|10|1|6|0|0|0|0|0 +*|MiniatureMushroom||||||7087|382|1|2|5|10|10|10|1|2|0|0|0|0|0 +*|MiniatureMushroom||||||6992|345|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|MiniatureMushroom||||||7007|360|0|2|5|10|10|10|1|2|0|0|0|0|0 +## +## ----Lostlands---- +## +## Papua Town +## +*|Bird|Cat|Dog|Rat|||5726|3211|-2|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Delucia Town +## +*|Bird|Cat|Dog|Rat|||5255|4000|37|2|5|15|80|80|1|6|6|6|6|0|0 +*|Chicken:Sheep:Cow:Bull||||||5267|4012|40|2|5|10|15|15|1|5|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/TownsPeople.map b/Data/Monsters/trammel/TownsPeople.map new file mode 100644 index 0000000..012abf9 --- /dev/null +++ b/Data/Monsters/trammel/TownsPeople.map @@ -0,0 +1,75 @@ +############## +## By Nerun ## +############## +overrideid 123 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Britain Chaos/Order Guards +## +*|Orderguard||||||1400|1623|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Orderguard||||||1400|1628|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1521|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1525|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +## +## Town Criers +## +*|Towncrier||||||1662|1611|19|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1421|1698|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2254|1207|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5290|3987|37|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3652|2619|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1330|3778|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3721|2161|20|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2515|557|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||4451|1153|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3773|1308|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5685|3148|-4|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2891|3474|15|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||603|2141|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1914|2687|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1829|2811|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2895|686|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||627|864|0|2|5|10|5|1|1|1|0|0|0|0|0 +## +## Hire +## +*|HireBard:HireBardArcher:HireBeggar:HireFighter:HireMage|HireRanger:HireRangerArcher:HireSailor:HireThief:HirePaladin|||||1399|3743|-21|2|5|15|10|10|1|5|5|0|0|0|0 +## +## Escorts +## +*|Escortablemage:Seekerofadventure:Noble||||||1483|1760|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1372|3916|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1126|3688|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3674|2291|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||4398|1049|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3815|1217|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3749|1404|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3645|2661|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2994|3451|16|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||673|2235|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||573|2246|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2068|2854|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3041|827|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||631|883|0|2|5|15|20|10|1|3|0|0|0|0|0 +## +## Treasures +## +## Trinsic Bank +*|TreasureLevel3|TreasureLevel4|||||1813|2834|0|2|1|2|2|2|1|1|2|0|0|0|0 +## Vesper Bank +*|TreasureLevel1||||||2875|675|0|2|1|2|2|2|1|6|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||2874|692|0|2|1|2|1|1|1|1|1|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2884|692|0|2|1|2|1|1|1|2|1|0|0|0|0 +## +## Heartwood +## +*|olaeni||||||7082|367|0|2|5|10|4|4|1|1|0|0|0|0|0 +*|bolaevin|bird|||||7063|350|0|2|5|10|4|4|1|1|2|0|0|0|0 +*|athialon||||||7010|363|0|2|5|10|8|8|1|1|0|0|0|0|0 +*|abbein|taellia|vicaie|mallew|jothan|alethanian|7048|382|0|2|5|10|12|12|1|1|1|1|1|1|1 +*|tyeelor||||||6989|342|0|2|5|10|8|8|1|1|0|0|0|0|0 +*|aneen|bird|||||7053|338|0|2|5|10|6|6|1|1|1|0|0|0|0 +*|alelle|daelas|||||7031|409|7|2|5|10|10|10|1|1|1|0|0|0|0 +*|aluniol|rebinil|||||7090|387|0|2|5|10|8|8|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/TrinsicPassage.map b/Data/Monsters/trammel/TrinsicPassage.map new file mode 100644 index 0000000..e81f2ab --- /dev/null +++ b/Data/Monsters/trammel/TrinsicPassage.map @@ -0,0 +1,18 @@ +############## +## By Nerun ## +############## +overrideid 124 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Do not exist spiderlord, then i did 2 dreadspiders per block +## +## Trinsic Passage +## +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5976|1387|-22|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5940|1356|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5912|1326|0|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5956|1310|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5999|1327|10|2|5|15|20|10|1|2|1|1|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5915|1302|2|2|1|2|1|1|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Vendors.map b/Data/Monsters/trammel/Vendors.map new file mode 100644 index 0000000..964cf16 --- /dev/null +++ b/Data/Monsters/trammel/Vendors.map @@ -0,0 +1,472 @@ +############## +## By Nerun ## +############## +overrideid 125 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Hidden Valley Mages +## +*|Herbalist|Mage|||||1685|2985|0|2|5|10|20|10|1|2|2|0|0|0|0 +## +## Britain +## +*|jeweler||||||1650|1642|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||1450|1617|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1418|1547|30|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1471|1611|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1447|1647|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1590|1654|10|2|2|10|5|0|1|1|1|1|0|0|0 +*|bard|bardguildmaster|||||1455|1557|30|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1388|1588|30|2|2|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||1362|1574|30|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1467|1686|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||1474|1597|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||1417|1578|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1458|1525|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1416|1754|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||1451|1679|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1602|1712|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||1470|1578|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1547|1659|26|2|2|10|5|0|1|1|1|1|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1620|1586|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|carpenter|architect|realestatebroker||||1430|1597|20|2|2|10|5|0|1|1|1|1|0|0|0 +*|mage|alchemist|mageguildmaster||||1485|1550|30|2|2|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||1296|1759|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||1388|1655|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1481|1584|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||1493|1616|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1422|1654|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1547|1768|10|2|2|10|5|0|1|1|1|1|1|0|0 +*|warriorguildmaster|hirefighter|||||1341|1733|20|2|5|10|5|0|1|1|2|0|0|0|0 +*|innkeeper||||||1585|1591|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1637|1693|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|tanner|furtrader|||||1431|1612|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1498|1691|20|2|2|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||1470|1765|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||1409|1590|42|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster|blacksmith|||||1349|1778|15|2|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1469|1668|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1510|1543|25|2|2|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1427|1716|20|2|2|10|5|0|1|1|1|1|1|0|0 +*|butcher||||||1449|1723|6|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1650|1608|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||1498|1659|27|2|2|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||1425|1690|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1494|1715|6|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage||||||1405|1810|0|2|5|10|25|10|1|1|0|0|0|0|0 +*|towncrier||||||1482|1761|-2|2|5|10|4|0|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1228|1572|0|2|5|10|10|8|1|1|1|1|0|0|0 +*|orderguard|hirefighter|||||1355|1754|20|2|5|10|14|8|1|1|1|0|0|0|0 +*|farmer|rancher|||||1243|1699|0|2|5|10|4|4|1|1|1|0|0|0|0 +*|escortablemage||||||1351|1816|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|orderguard||||||1306|1804|0|2|5|10|6|4|1|1|0|0|0|0|0 +*|peasant||||||1304|1826|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|artist||||||1362|1825|0|2|5|10|12|6|1|1|0|0|0|0|0 +*|escortablewanderinghealer||||||1333|1808|0|2|5|10|4|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1150|1619|0|2|5|10|10|6|1|1|1|1|0|0|0 +*|farmer|rancher|hirepeasant||||1149|1547|0|2|5|10|10|10|1|1|1|1|0|0|0 +*|bridegroom||||||1295|1773|10|2|5|10|4|4|1|1|0|0|0|0|0 +*|hirefighter||||||1316|1747|10|2|5|10|20|15|1|3|0|0|0|0|0 +*|hirepeasant||||||1231|1714|0|2|5|10|10|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1190|1707|0|2|5|10|8|4|1|1|1|1|0|0|0 +*|hirebard||||||1427|1726|20|2|5|10|4|4|1|1|0|0|0|0|0 +*|hiresailor|fisherman|rat||||1438|1761|-2|2|5|10|10|6|1|1|1|2|0|0|0 +*|hiresailor||||||1477|1741|0|2|5|10|20|20|1|2|0|0|0|0|0 +*|harbormaster||||||1436|1752|14|2|5|10|4|4|1|1|0|0|0|0|0 +*|merchant||||||1434|1717|20|2|5|10|4|4|1|1|0|0|0|0|0 +## +## Buccaneer's Den +## +*|healer|healerguildmaster|||||2709|2130|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2715|2098|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|thiefguildmaster||||||2659|2194|4|2|2|10|5|5|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2680|2238|2|2|2|10|5|0|1|1|1|1|1|0|0 +*|provisioner|cobbler|||||2737|2250|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2731|2192|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2627|2100|10|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2752|2155|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2707|2178|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||2634|2083|10|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Cove +## +*|healer|healerguildmaster|||||2245|1231|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||2216|1167|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2216|1192|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||2256|1181|-2|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Jhelom +## +*|carpenter|architect|realestatebroker||||1435|3820|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||1404|3802|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1452|3770|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|armorer|weaponsmith|||||1456|3850|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1317|3773|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||1372|3908|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1512|3989|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1504|3693|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1125|3687|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1416|3779|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1387|3771|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1425|3981|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||1454|4003|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||1360|3815|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner||||||1442|3802|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|cobbler||||||1442|3802|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||1437|3750|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1447|3981|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1452|3747|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1441|3719|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1419|3859|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1356|3780|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1364|3732|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1475|3865|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1354|3754|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher|farmer|||||1386|3825|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||1450|4026|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1395|3705|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Magincia +## +*|fisherguildmaster||||||3683|2252|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3667|2252|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3727|2224|20|2|2|10|5|0|1|1|1|1|1|0|0 +*|healer|healerguildmaster|||||3687|2227|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||3674|2289|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||3665|2140|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3699|2218|20|2|2|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||3703|2249|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||3699|2163|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||3666|2235|20|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||3720|2126|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3755|2227|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3734|2149|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3683|2171|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||3661|2183|20|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Minoc +## +*|blacksmith|blacksmithguildmaster|||||2471|564|5|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2461|457|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2505|432|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||2577|599|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2455|487|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|bard|bardguildmaster|||||2424|555|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||2478|427|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||2513|477|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||2450|428|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||2438|410|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||2526|375|23|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2522|524|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2526|546|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||2533|572|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2503|552|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2475|397|15|2|2|10|5|0|1|1|1|1|1|0|0 +## +## Moonglow +## +*|herbalist|alchemist|customhairstylist||||4416|1133|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|baker||||||4392|1068|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||4416|1085|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||4392|1117|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||4406|1038|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||4394|1083|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||4409|1111|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||4484|1064|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||4448|1090|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||4458|1060|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||4417|1064|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||4401|1165|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||4440|1162|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster||||||4545|860|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||4481|1085|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||4395|1137|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||4471|1156|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Nujel'm +## +*|jeweler||||||3778|1172|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3769|1218|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|blacksmith|blacksmithguildmaster|||||3546|1185|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||3546|1194|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||3555|1171|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||3545|1178|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||3554|1202|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3731|1320|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3700|1214|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3729|1258|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|tailor|weaver|tailorguildmaster||||3774|1265|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||3764|1317|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|bardguildmaster||||||3740|1197|0|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Haven +## +*|banker||||||3484|2570|20|2|5|10|2|0|1|1|0|0|0|0|0 +*|hairstylist||||||3470|2519|49|2|5|10|3|0|1|1|0|0|0|0|0 +*|fisherman||||||3504|2612|0|2|5|10|4|0|1|1|0|0|0|0|0 +*|shipwright||||||3495|2590|35|2|5|10|4|0|1|1|0|0|0|0|0 +*|weaver||||||3496|2547|20|2|5|10|4|0|1|1|0|0|0|0|0 +*|tailor||||||3497|2552|20|2|5|10|4|0|1|2|0|0|0|0|0 +*|tailorguildmaster||||||3494|2551|20|2|5|10|4|0|1|1|0|0|0|0|0 +*|minter||||||3481|2569|20|2|5|10|2|0|1|1|0|0|0|0|0 +*|minter||||||3481|2575|20|2|5|10|2|0|1|1|0|0|0|0|0 +*|healer||||||3463|2558|35|2|5|10|4|0|1|2|0|0|0|0|0 +*|healerguildmaster||||||3463|2558|36|2|5|10|4|0|1|1|0|0|0|0|0 +*|holymage||||||3502|2414|55|2|5|10|6|0|1|2|0|0|0|0|0 +*|evilwanderinghealer||||||3554|2457|15|2|5|10|6|0|1|2|0|0|0|0|0 +*|merchant||||||3480|2533|38|2|5|10|2|0|1|1|0|0|0|0|0 +*|actor||||||3412|2602|60|2|5|10|4|0|1|1|0|0|0|0|0 +*|noble||||||3527|2516|45|2|5|10|6|0|1|2|0|0|0|0|0 +*|noble||||||3473|2493|72|2|5|10|6|0|1|1|0|0|0|0|0 +*|noble||||||3485|2493|52|2|5|10|6|0|1|1|0|0|0|0|0 +*|noble||||||3526|2519|25|2|5|10|6|0|1|1|0|0|0|0|0 +*|blacksmith||||||3470|2539|36|2|5|10|2|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||3469|2536|41|2|5|10|2|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||3526|2536|20|2|5|10|2|0|1|1|0|0|0|0|0 +*|weaponsmith||||||3471|2539|36|2|5|10|2|0|1|1|0|0|0|0|0 +*|armorer||||||3474|2539|31|2|5|10|2|0|1|1|0|0|0|0|0 +*|scribe||||||3471|2528|48|2|5|10|3|0|1|2|0|0|0|0|0 +*|herbalist||||||3461|2566|36|2|5|10|3|0|1|2|0|0|0|0|0 +*|herbalist||||||3470|2519|48|2|5|10|3|0|1|2|0|0|0|0|0 +*|animaltrainer||||||3527|2576|7|2|5|10|4|0|1|1|0|0|0|0|0 +*|fisherman||||||3520|2598|0|2|5|10|4|0|1|2|0|0|0|0|0 +*|banker||||||3484|2576|20|2|5|10|2|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||3458|2524|53|2|5|10|4|0|1|1|0|0|0|0|0 +*|tinker||||||3458|2528|53|2|5|10|4|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||3495|2527|27|2|5|10|3|0|1|1|0|0|0|0|0 +*|thief||||||3450|2569|30|2|5|10|6|0|1|1|0|0|0|0|0 +*|baker||||||3463|2576|35|2|5|10|4|0|1|2|0|0|0|0|0 +*|alchemist||||||3461|2566|37|2|5|10|4|0|1|2|0|0|0|0|0 +*|waiter||||||3445|2552|55|2|5|10|6|0|1|1|0|0|0|0|0 +*|hairstylist||||||3461|2566|35|2|5|10|4|0|1|1|0|0|0|0|0 +*|waiter||||||3443|2552|35|2|5|10|6|0|1|1|0|0|0|0|0 +*|waiter||||||3442|2567|53|2|5|10|6|0|1|1|0|0|0|0|0 +*|waiter||||||3505|2518|27|2|5|10|6|0|1|2|0|0|0|0|0 +*|innkeeper||||||3501|2517|27|2|5|10|4|0|1|1|0|0|0|0|0 +*|cook||||||3497|2518|27|2|5|10|4|0|1|1|0|0|0|0|0 +*|mage||||||3495|2532|27|2|5|10|3|0|1|1|0|0|0|0|0 +*|mage||||||3495|2530|27|2|5|10|3|0|1|1|0|0|0|0|0 +*|leatherworker||||||3446|2606|32|2|5|10|4|0|1|1|0|0|0|0|0 +*|furtrader||||||3446|2606|31|2|5|10|4|0|1|1|0|0|0|0|0 +*|tanner||||||3446|2606|30|2|5|10|4|0|1|1|0|0|0|0|0 +*|jeweler||||||3508|2553|20|2|5|10|4|0|1|2|0|0|0|0|0 +*|miner||||||3506|2746|0|2|5|10|4|0|1|1|0|0|0|0|0 +*|ironworker||||||3526|2536|21|2|5|10|4|0|1|1|0|0|0|0|0 +*|baseescortable||||||3481|2506|45|2|5|10|1|0|1|1|0|0|0|0|0 +*|miner||||||3526|2536|22|2|5|10|4|0|1|1|0|0|0|0|0 +*|barkeeper||||||3434|2568|53|2|5|10|1|0|1|1|0|0|0|0|0 +*|vagabond||||||3432|2554|44|2|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||3437|2566|53|2|5|10|2|0|1|1|0|0|0|0|0 +*|Dryad||||||3555|2698|5|2|5|10|2|0|1|1|0|0|0|0|0 +*|baseescortable||||||3545|2563|5|2|5|10|1|0|1|1|0|0|0|0|0 +*|baseescortable||||||3471|2589|10|2|5|10|1|0|1|1|0|0|0|0|0 +*|peasant||||||3452|2586|30|2|5|10|4|0|1|1|0|0|0|0|0 +*|seekerofadventure||||||3443|2535|36|2|5|10|2|0|1|1|0|0|0|0|0 +## +## Serpents Hold +## +*|waiter|cook|barkeeper|tavernkeeper|||3009|3455|15|2|2|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||2940|3410|1|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||2975|3353|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||3051|3367|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2883|3502|10|2|2|10|5|0|1|1|1|1|0|0|0 +*|warriorguildmaster||||||3031|3350|35|2|2|10|5|5|1|1|0|0|0|0|0 +*|animaltrainer||||||3036|3464|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3003|3355|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||2905|3517|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||3008|3389|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmithguildmaster||||||3007|3408|15|2|2|10|5|5|1|1|0|0|0|0|0 +*|customhairstylist||||||3013|3353|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||2967|3408|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||2997|3428|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||3058|3400|15|2|2|10|5|5|1|1|0|0|0|0|0 +*|tinker|tinkerguildmaster|||||2940|3500|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper||||||2972|3425|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|herbalist|alchemist|||||3013|3353|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||2906|3485|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||3018|3426|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2880|3472|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|waiter|cook|barkeeper||||2972|3425|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2992|3451|16|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith||||||3007|3408|15|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Skara Brae +## +*|healerguildmaster||||||620|2218|0|2|2|10|5|5|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||602|2180|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|weaponsmith|armorer|||||650|2161|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||659|2141|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|tailorguildmaster|weaver||||650|2178|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||656|2235|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer||||||620|2218|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|rangerguildmaster||||||562|2148|0|2|2|10|5|5|1|1|0|0|0|0|0 +*|innkeeper||||||554|2178|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||578|2227|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||592|2277|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||590|2205|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||586|2170|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||630|2194|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||587|2146|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||627|2163|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|butcher|farmer|||||611|2157|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||570|2121|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||582|2186|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||601|2235|0|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Trinsic +## +*|animaltrainer||||||2011|2804|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1935|2766|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1935|2796|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|scribe||||||2002|2721|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1897|2805|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1852|2831|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2033|2801|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1895|2653|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||2026|2845|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinkerguildmaster||||||1848|2680|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1844|2735|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||1990|2889|5|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||2072|2856|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||1991|2867|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1911|2805|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1897|2684|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1822|2739|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2019|2748|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1981|2838|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1880|2802|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1813|2825|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1850|2796|-8|2|2|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||1939|2739|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1846|2715|10|2|2|10|5|0|1|1|1|1|0|0|0 +## +## Vesper +## +*|fisherguildmaster||||||2963|813|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3012|780|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2899|790|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2917|798|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||2920|856|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2782|969|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2865|852|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2918|672|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|herbalist|alchemist|customhairstylist||||2992|844|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|shipwright|mapmaker|||||2995|815|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2901|908|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|banker|minter|||||2881|684|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2855|734|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||2861|812|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||2882|723|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2961|621|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||2840|885|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tanner|furtrader|||||2860|999|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||2998|760|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||3034|827|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||2962|885|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2835|805|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2986|637|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2890|651|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|beekeeper||||||2954|705|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2987|777|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2841|907|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3017|761|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Wind +## +*|scribe||||||5236|142|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5351|56|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||5154|97|5|2|2|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||5215|117|1|2|2|10|5|0|1|1|1|1|0|0|0 +*|scribe||||||5242|180|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5161|32|17|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5148|60|25|2|2|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||5347|76|25|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||5263|129|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5203|86|5|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5218|175|5|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5300|90|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5306|37|40|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Yew +## +*|bowyer||||||624|1145|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||631|1034|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||540|966|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||553|985|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||570|969|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||517|986|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||529|1008|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||652|820|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||610|810|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||535|867|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||564|1011|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||643|1083|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Delucia +## +*|healer|healerguildmaster|||||5191|3989|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5296|3978|37|2|2|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||5219|4012|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||5275|3977|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmithguildmaster|blacksmith|||||5225|4000|38|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||5197|4060|37|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5297|4007|40|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5234|4025|37|2|2|10|5|0|1|1|1|1|0|0|0 +## +## Papua +## +*|minter|banker|||||5669|3131|14|2|2|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster|alchemist|mage||||5731|3192|9|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinkerguildmaster|tinker|||||5726|3243|16|2|2|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||5662|3150|13|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5671|3287|11|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||5698|3282|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|weaponsmith|armorer|||||5805|3300|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|customhairstylist|alchemist|herbalist||||5714|3202|12|2|2|10|5|0|1|1|1|1|0|0|0 +*|mapmaker|shipwright|||||5805|3270|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailorguildmaster|weaver|tailor||||5752|3272|16|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||5839|3256|2|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5746|3200|16|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5775|3161|14|2|2|10|5|0|1|1|0|0|0|0|0 +*|healerguildmaster|healer|||||5737|3222|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|realestatebroker|architect|carpenter||||5691|3209|11|2|2|10|5|0|1|1|1|1|0|0|0 +*|cobbler|provisioner|||||5736|3263|15|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Sea Market +## +*|fisherman||||||4571|2303|-2|2|5|10|-1|0|1|1|0|0|0|0|0 +*|tanner||||||4553|2318|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|wanderinghealer|bard|||||4550|2307|-2|2|5|10|-1|10|1|1|1|0|0|0|0 +*|fisherman||||||4557|2307|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|||||4540|2301|-1|2|5|10|-1|4|1|1|1|0|0|0|0 +*|bodysculptor||||||4547|2321|-2|2|5|10|-1|4|1|1|0|0|0|0|0 +*|shipwright||||||4551|2334|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4556|2330|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|tailor|provisioner|fisherman||||4533|2333|-2|2|5|10|-1|4|1|1|1|1|0|0|0 +*|dockmaster||||||4569|2304|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4549|2346|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|hiresailor||||||4562|2349|-2|2|5|10|-1|4|1|1|0|0|0|0|0 +*|fisherman|hiresailor|||||4570|2400|-2|2|5|10|7|4|1|1|1|0|0|0|0 +*|fisherguildmaster||||||4551|2327|-2|2|5|10|-1|7|1|1|0|0|0|0|0 +*|fisherman||||||4530|2382|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|boatpainter||||||4551|2320|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4573|2364|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4553|2351|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4537|2348|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|blacksmith||||||4549|2301|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4553|2343|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|tavernkeeper|cook|||||4544|2299|-1|2|5|10|-1|4|1|1|1|0|0|0|0 +*|tinker||||||4561|2328|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|wanderinghealer||||||4551|2381|-2|2|5|10|-1|15|1|1|0|0|0|0|0 +*|wanderinghealer||||||4552|2349|-2|2|5|10|-1|5|1|1|0|0|0|0|0 +*|hiresailor||||||4552|2390|-2|2|5|10|-1|7|1|1|0|0|0|0|0 +*|alchemist||||||4542|2329|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|banker||||||4551|2323|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|shipwright||||||4564|2298|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|fisherman||||||4547|2376|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|waiter||||||4540|2306|-1|2|5|10|-1|4|1|1|0|0|0|0|0 +*|fisherman||||||4554|2389|-2|2|5|10|-1|1|1|1|0|0|0|0|0 +*|treasurelevel1h||||||4534|2349|-2|2|5|10|-1|0|1|1|0|0|0|0|0 +*|treasurelevel1h||||||4535|2349|-2|2|5|10|-1|0|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/WildLife.map b/Data/Monsters/trammel/WildLife.map new file mode 100644 index 0000000..6d51abe --- /dev/null +++ b/Data/Monsters/trammel/WildLife.map @@ -0,0 +1,181 @@ +############## +## By Nerun ## +############## +overrideid 126 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4612|3424|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4682|3662|77|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4446|3706|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3232|510|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4560|3504|2|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4692|3494|1|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4478|3218|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3394|628|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3650|2080|21|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3608|2140|79|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4384|1218|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4468|1006|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4326|1046|8|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4544|1128|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4510|1262|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4590|1326|8|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4526|986|10|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4336|1130|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4448|1334|3|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4540|1454|8|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4632|1164|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4470|1430|8|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4592|1424|3|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|3500|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2998|3590|15|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2864|150|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3292|570|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3206|366|9|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3172|664|8|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3392|424|9|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3076|150|1|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3092|542|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2512|1066|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2554|1142|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2416|1172|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2188|1986|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2654|2286|9|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2946|2168|44|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2744|2014|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2786|2282|13|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2074|1972|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2122|2108|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1932|3125|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1824|3027|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1894|2942|19|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2499|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1005|2647|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|464|2059|8|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|559|2081|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|883|2129|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|968|2476|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|994|2361|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|964|2214|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1087|2401|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2378|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1334|2311|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1315|2192|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1426|2615|10|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1527|2609|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1582|2722|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1650|2796|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1724|2781|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1727|2702|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1634|2645|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1505|2445|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1699|2560|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1612|2526|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1722|2435|10|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1715|2307|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1531|2351|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1602|2426|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1628|2334|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1563|2277|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1503|2207|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1709|1992|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1498|2040|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1439|2104|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1387|2023|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1377|1911|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1459|1963|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1268|2018|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1173|2103|2|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1070|2069|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|958|2074|1|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|999|1839|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|1945|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1229|1655|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1725|1447|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1798|1471|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1958|1305|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1867|1244|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1865|1379|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1769|1330|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1666|1290|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1486|1301|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1351|1359|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1231|1462|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1017|1726|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|398|1305|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|485|1398|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|210|1447|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|851|1770|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|977|1638|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|919|1718|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|876|1639|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|1570|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|725|1483|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|623|1328|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|727|1394|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1020|1360|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1024|1244|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|802|1280|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|855|934|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|771|1013|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|846|1071|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|940|1028|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1152|812|5|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|896|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1057|765|1|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|974|374|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1063|541|16|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1018|629|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|951|542|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|576|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|937|743|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|890|657|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|895|830|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|689|753|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|748|669|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|764|822|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|834|751|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|782|1156|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|887|1223|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|916|1159|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|993|1130|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1047|1071|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1092|1010|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1172|974|2|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1388|784|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1631|640|22|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1526|960|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1545|813|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1695|809|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1728|691|6|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1802|495|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1857|600|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1884|735|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1973|751|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2085|658|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2367|748|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2289|917|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2338|989|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2418|999|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2495|978|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2583|993|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2513|782|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2748|660|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2765|754|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2668|1020|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2669|922|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2672|814|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2643|728|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2888|391|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2735|417|15|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2914|547|0|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|492|15|2|5|10|50|50|126|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2688|524|11|2|5|10|50|50|126|7|5|1|2|2|2 +## +## Haven Island (see Outdoors.map) +## +## +## Huntsman's Forrest +## +*|TimberWolf||||||1651|612|22|2|5|10|20|20|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/trammel/Wrong.map b/Data/Monsters/trammel/Wrong.map new file mode 100644 index 0000000..7f0aaa9 --- /dev/null +++ b/Data/Monsters/trammel/Wrong.map @@ -0,0 +1,24 @@ +############## +## By Nerun ## +############## +overrideid 127 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Wrong Dungeon +## +## Level 1 +## +*|Jukawarrior||||||5819|591|0|2|2|10|25|5|1|2|0|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5808|588|12|2|2|10|30|15|1|1|1|3|0|0|0 +*|Golemcontroller|Golem|||||5792|544|10|2|2|10|30|6|1|4|4|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|586|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|562|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5828|530|0|2|2|10|30|8|1|1|1|3|0|0|0 +## +## Level 2 +## +*|Brigand|Jukalord|Jukamage|Jukawarrior|||5659|563|20|2|2|10|30|10|1|4|1|1|3|0|0 +*|Golem|Jukalord|Jukamage|Jukawarrior|||5724|561|20|2|2|10|30|8|1|1|1|1|3|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5690|534|0|2|2|10|30|8|1|1|1|3|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoclassic/UOClassic.map b/Data/Monsters/uoclassic/UOClassic.map new file mode 100644 index 0000000..f8c9f11 --- /dev/null +++ b/Data/Monsters/uoclassic/UOClassic.map @@ -0,0 +1,1779 @@ +################################# +## UO Rebirth spawns (pre-T2A) ## +## Converted to PremiumSpawner ## +## By Nerun. (version 1.0.1) ## +################################# +overrideid 1000 +overridemap 1 +##overridemintime 5 +##overridemaxtime 10 +*|rat||||||1373|3910|-2|1|15|30|20|2|1|1|0|0|0|0|0 +*|rat||||||1372|3894|-3|1|30|45|12|2|1|1|0|0|0|0|0 +*|waitress:waiter||||||5626|1173|0|1|15|60|5|0|1|2|0|0|0|0|0 +*|baker||||||1356|3730|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|peasant||||||1459|3820|0|1|45|60|12|3|1|1|0|0|0|0|0 +*|peasant||||||1459|3797|0|1|45|60|12|3|1|1|0|0|0|0|0 +*|scribe||||||1378|3778|-20|1|30|45|12|2|1|1|0|0|0|0|0 +*|bridegroom:seekerofadventure:noble:bridegroom||||||1459|3724|0|1|240|240|12|12|1|1|0|0|0|0|0 +*|noble||||||5640|1163|0|1|15|60|2|0|1|1|0|0|0|0|0 +*|earthelemental||||||5154|870|0|1|15|60|5|0|1|5|0|0|0|0|0 +*|rat||||||4419|1027|-2|1|15|30|20|2|1|1|0|0|0|0|0 +*|sailor||||||4418|1026|-2|1|30|45|20|2|1|1|0|0|0|0|0 +*|fisherman||||||4417|1044|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|rat||||||4407|1039|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|rat||||||4395|1028|-2|1|30|45|20|2|1|1|0|0|0|0|0 +*|fisherman||||||4395|1034|-2|1|15|30|20|2|1|1|0|0|0|0|0 +*|rat||||||2256|1172|-2|1|30|45|20|2|1|1|0|0|0|0|0 +*|harbormaster||||||2255|1185|-2|1|15|30|12|3|1|1|0|0|0|0|0 +*|rat||||||1469|1765|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|rat||||||1490|1747|-2|1|30|45|12|1|1|1|0|0|0|0|0 +*|rat||||||1482|1764|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|sailor||||||1487|1759|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|fisherman||||||1472|1758|-2|1|30|45|12|3|1|1|0|0|0|0|0 +*|rat||||||1438|1761|-2|1|30|45|12|6|1|1|0|0|0|0|0 +*|fisherman||||||1435|1765|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|sailor||||||3666|2266|21|1|30|45|12|4|1|1|0|0|0|0|0 +*|rat||||||3674|2266|21|1|15|30|12|5|1|1|0|0|0|0|0 +*|fisherman||||||3681|2267|21|1|30|45|12|3|1|1|0|0|0|0|0 +*|rat||||||3673|2280|-2|1|30|45|20|3|1|1|0|0|0|0|0 +*|sailor||||||3673|2288|-2|1|15|30|12|3|1|1|0|0|0|0|0 +*|rat||||||3687|2289|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|rat||||||3655|2283|-2|1|30|45|12|2|1|1|0|0|0|0|0 +*|fisherman||||||3686|2289|-2|1|30|45|20|2|1|1|0|0|0|0|0 +*|harbormaster||||||3660|2289|-2|1|15|30|30|2|1|1|0|0|0|0|0 +*|bird||||||541|2228|0|1|15|30|20|6|1|2|0|0|0|0|0 +*|bird:bird:rat||||||611|2266|0|1|15|45|20|8|1|3|0|0|0|0|0 +*|rat||||||644|2235|-3|1|15|30|12|6|1|1|0|0|0|0|0 +*|rat||||||660|2235|-3|1|30|45|20|5|1|1|0|0|0|0|0 +*|fisherman||||||660|2232|-3|1|30|45|12|3|1|1|0|0|0|0|0 +*|rat||||||677|2242|-3|1|15|30|12|3|1|1|0|0|0|0|0 +*|ranger||||||867|2315|0|1|30|45|12|3|1|2|0|0|0|0|0 +*|ham||||||866|2321|6|1|90|120|0|0|1|1|0|0|0|0|0 +*|bird||||||744|2332|0|1|30|45|30|8|1|2|0|0|0|0|0 +*|ranger||||||739|2347|0|1|30|45|12|3|1|2|0|0|0|0|0 +*|ranger||||||787|2226|10|1|30|45|7|3|1|2|0|0|0|0|0 +*|ranger||||||747|2267|0|1|30|45|4|3|1|2|0|0|0|0|0 +*|ham||||||754|2263|6|1|90|120|0|0|1|1|0|0|0|0|0 +*|rat||||||718|2235|-3|1|15|30|12|3|1|1|0|0|0|0|0 +*|sailor||||||715|2236|-3|1|30|45|7|2|1|1|0|0|0|0|0 +*|harbormaster||||||715|2235|-3|1|15|30|7|2|1|1|0|0|0|0|0 +*|ranger||||||754|2159|0|1|45|60|12|4|1|1|0|0|0|0|0 +*|ranger||||||746|2151|0|1|30|45|9|2|1|1|0|0|0|0|0 +*|ranger||||||743|2147|0|1|30|45|9|2|1|1|0|0|0|0|0 +*|rangerguildmaster||||||746|2145|0|1|45|60|12|3|1|1|0|0|0|0|0 +*|ranger||||||561|2151|0|1|30|45|7|2|1|1|0|0|0|0|0 +*|bird||||||647|2086|0|1|30|45|30|20|1|3|0|0|0|0|0 +*|bird:bird:snake:bird:rat:bird||||||1439|3643|0|1|45|60|30|30|1|3|0|0|0|0|0 +*|rat||||||1501|3695|-3|1|15|30|20|2|1|1|0|0|0|0|0 +*|bird:bird:crow:bird:eagle||||||1461|3704|0|1|30|45|30|40|1|3|0|0|0|0|0 +*|bird||||||1487|3701|0|1|30|45|30|24|1|3|0|0|0|0|0 +*|warriorguard||||||1476|3714|20|1|30|45|12|2|1|1|0|0|0|0|0 +*|warriorguard||||||1475|3684|20|1|30|45|12|2|1|1|0|0|0|0|0 +*|beggar||||||1489|3691|-3|1|45|60|24|6|1|1|0|0|0|0|0 +*|fisherman||||||1502|3680|-3|1|30|45|4|2|1|1|0|0|0|0|0 +*|harbormaster||||||1508|3708|-3|1|15|30|4|2|1|1|0|0|0|0|0 +*|cow:bull||||||1121|3591|0|1|30|45|20|6|1|2|0|0|0|0|0 +*|peasant||||||1139|3667|0|1|45|60|3|2|1|1|0|0|0|0|0 +*|peasant||||||1133|3659|0|1|45|60|3|2|1|1|0|0|0|0|0 +*|farmer||||||1171|3640|0|1|45|60|3|2|1|2|0|0|0|0|0 +*|bird||||||1112|3666|0|1|15|45|14|8|1|2|0|0|0|0|0 +*|harbormaster||||||1133|3692|-2|1|30|45|3|2|1|1|0|0|0|0|0 +*|fisherman||||||1121|3693|-2|1|45|60|3|2|1|1|0|0|0|0|0 +*|farmer||||||1125|3611|0|1|45|60|3|3|1|1|0|0|0|0|0 +*|peasant||||||1404|1803|0|1|45|60|3|3|1|1|0|0|0|0|0 +*|armorer||||||1368|1576|30|1|15|30|4|2|1|1|0|0|0|0|0 +*|weaponsmith||||||1363|1575|30|1|15|30|3|3|1|1|0|0|0|0|0 +*|warriorguard||||||1389|1588|30|1|30|45|5|4|1|1|0|0|0|0|0 +*|tinker||||||1388|1598|30|1|15|30|5|3|1|1|0|0|0|0|0 +*|carpenter||||||1389|1598|30|1|15|30|5|3|1|1|0|0|0|0|0 +*|tailorguildmaster||||||1389|1599|30|1|15|30|5|3|1|1|0|0|0|0|0 +*|seaserpent||||||5441|1814|-5|1|15|60|15|5|1|2|0|0|0|0|0 +*|waterelemental||||||5453|1976|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|waterelemental||||||5448|2030|0|1|15|60|10|2|1|1|0|0|0|0|0 +*|skeleton||||||5398|1860|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|warrior||||||1366|3701|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|warriorguildmaster||||||1361|3701|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|jeweler||||||1316|3771|0|1|15|30|5|1|1|1|0|0|0|0|0 +*|brigand||||||770|1678|0|1|10|15|7|4|1|6|0|0|0|0|0 +*|lich||||||5716|58|5|1|10|30|4|0|1|1|0|0|0|0|0 +*|waterelemental||||||5724|75|0|1|10|30|4|0|1|1|0|0|0|0|0 +*|waterelemental||||||5731|92|0|1|10|30|2|0|1|1|0|0|0|0|0 +*|bloodelemental||||||5816|79|0|1|10|30|4|0|1|1|0|0|0|0|0 +*|airelemental||||||5824|25|0|1|10|30|3|0|1|2|0|0|0|0|0 +*|slime:slime:snake||||||5506|176|0|1|15|60|10|2|1|3|0|0|0|0|0 +*|gazer||||||5496|180|0|1|10|30|3|0|1|1|0|0|0|0|0 +*|eldergazer||||||5507|186|0|1|10|30|4|0|1|1|0|0|0|0|0 +*|fireelemental||||||5810|115|10|1|10|30|8|8|1|2|0|0|0|0|0 +*|fireelemental||||||5841|109|10|1|10|30|4|0|1|2|0|0|0|0|0 +*|bird:bird:bird:rabbit:rabbit:hind:mongbat||||||4549|820|20|1|15|45|12|12|1|3|0|0|0|0|0 +*|airelemental||||||5731|37|0|1|10|30|4|0|1|1|0|0|0|0|0 +*|airelemental||||||5717|13|10|1|10|30|7|6|1|2|0|0|0|0|0 +*|airelemental||||||5717|12|10|1|10|30|7|0|1|2|0|0|0|0|0 +*|bird:hind:hind:greathart:mongbat:snake:rabbit:rabbit:jackrabbit:jackrabbit:greywolf:timberwolf:bird||||||4540|923|20|1|15|45|15|60|1|15|0|0|0|0|0 +*|Slime:StrongMongbat:Mongbat:Snake||||||5760|70|0|1|15|90|15|100|1|35|0|0|0|0|0 +*|bloodelemental||||||5699|20|10|1|10|30|5|4|1|1|0|0|0|0|0 +*|bird:bird:hind:hind:greathart:timberwolf:timberwolf:greywolf:jackrabbit:rabbit:rabbit:rabbit:mongbat||||||4376|955|0|1|15|45|15|60|1|15|0|0|0|0|0 +*|bird||||||4302|893|0|1|15|45|12|15|1|3|0|0|0|0|0 +*|bird:bird:bird:bird:hind:rabbit:rabbit:greathart:greathart:timberwolf:timberwolf:mongbat:jackrabbit||||||4303|1095|0|1|15|45|15|60|1|15|0|0|0|0|0 +*|bird:bird:bird:hind:hind:jackrabbit:rabbit:timberwolf:timberwolf:greathart:greathart:mongbat:snake||||||4429|1417|0|1|15|45|15|60|1|15|0|0|0|0|0 +*|bloodelemental||||||5809|12|0|1|10|30|1|0|1|2|0|0|0|0|0 +*|airelemental||||||5802|18|0|1|10|30|7|0|1|2|0|0|0|0|0 +*|airelemental||||||5843|40|0|1|10|30|7|0|1|2|0|0|0|0|0 +*|airelemental||||||5877|37|-10|1|10|30|4|0|1|1|0|0|0|0|0 +*|airelemental||||||5876|57|0|1|10|30|4|0|1|2|0|0|0|0|0 +*|fireelemental||||||5867|83|0|1|10|30|6|5|1|1|0|0|0|0|0 +*|hind:rabbit:jackrabbit:hind:hind:hind:rabbit:rabbit:greathart:jackrabbit:mongbat:snake:bird||||||4503|1476|11|1|15|45|15|60|1|15|0|0|0|0|0 +*|fireelemental||||||5873|109|10|1|10|30|6|5|1|3|0|0|0|0|0 +*|bird||||||4503|1477|11|1|15|45|15|60|1|15|0|0|0|0|0 +*|bloodelemental||||||5757|94|0|1|10|30|5|0|1|1|0|0|0|0|0 +*|bloodelemental||||||5781|23|0|1|10|30|8|8|1|1|0|0|0|0|0 +*|waterelemental||||||5713|32|0|1|10|30|6|7|1|2|0|0|0|0|0 +*|fireelemental||||||5686|28|0|1|10|30|2|0|1|1|0|0|0|0|0 +*|earthelemental||||||5676|27|0|1|10|30|15|0|1|1|0|0|0|0|0 +*|earthelemental||||||5727|117|0|1|10|30|15|7|1|3|0|0|0|0|0 +*|earthelemental||||||5699|108|0|1|10|30|10|9|1|2|0|0|0|0|0 +*|earthelemental||||||5680|108|0|1|10|30|10|10|1|2|0|0|0|0|0 +*|airelemental:waterelemental||||||5760|53|0|1|10|30|10|7|1|2|0|0|0|0|0 +*|airelemental:waterelemental||||||5760|36|0|1|10|30|8|0|1|2|0|0|0|0|0 +*|evilmage||||||5821|50|0|1|10|30|1|0|1|2|0|0|0|0|0 +*|evilmagelord||||||5820|52|22|1|10|30|1|0|1|1|0|0|0|0|0 +*|fireelemental||||||5665|13|-10|1|10|30|11|0|1|2|0|0|0|0|0 +*|earthelemental||||||5654|61|0|1|10|30|8|0|1|2|0|0|0|0|0 +*|earthelemental||||||5669|81|0|1|10|30|10|0|1|2|0|0|0|0|0 +*|bloodelemental||||||5656|102|10|1|10|30|19|15|1|2|0|0|0|0|0 +*|dragon||||||4593|3599|30|1|60|360|25|15|1|3|0|0|0|0|0 +*|harpy||||||5474|1877|0|1|15|40|18|6|1|6|0|0|0|0|0 +*|crow||||||1285|3723|0|1|10|15|30|4|1|1|0|0|0|0|0 +*|skeleton||||||1296|3725|0|1|10|15|30|2|1|1|0|0|0|0|0 +*|spectre:shade||||||1292|3746|0|1|30|45|30|2|1|2|0|0|0|0|0 +*|skeleton||||||1287|3746|0|1|10|15|30|2|1|1|0|0|0|0|0 +*|zombie||||||1282|3746|0|1|10|15|30|2|1|1|0|0|0|0|0 +*|zombie||||||1275|3723|0|1|10|15|30|2|1|1|0|0|0|0|0 +*|zombie||||||1284|3714|0|1|10|15|30|2|1|1|0|0|0|0|0 +*|skeleton||||||1280|3721|0|1|10|15|30|2|1|1|0|0|0|0|0 +*|gypsy||||||3149|559|8|1|840|840|12|6|1|4|0|0|0|0|0 +*|evilhealer:evilhealer:evilhealer:healer||||||3150|560|8|1|60|120|18|12|1|1|0|0|0|0|0 +*|healer:healer:healer:evilhealer||||||2932|480|0|1|60|120|18|5|1|1|0|0|0|0|0 +*|brownbear:grizzlybear:sheep:brownbear:brownbear:hind:hind:hind:hind:greathart:greathart:greathart:greathart||||||2933|482|5|1|60|120|18|65|1|18|0|0|0|0|0 +*|bird||||||2932|482|5|1|60|120|18|65|1|30|0|0|0|0|0 +*|warriorguard||||||295|771|20|1|30|45|4|4|1|1|0|0|0|0|0 +*|warriorguard||||||387|891|0|1|30|45|3|0|1|1|0|0|0|0|0 +*|warriorguard||||||364|915|0|1|30|45|3|0|1|1|0|0|0|0|0 +*|warriorguard||||||346|878|20|1|30|45|20|2|1|1|0|0|0|0|0 +*|warriorguard||||||364|893|20|1|30|45|2|0|1|1|0|0|0|0|0 +*|warriorguard||||||364|878|0|1|30|45|20|2|1|1|0|0|0|0|0 +*|warriorguard||||||340|881|0|1|30|45|2|0|1|1|0|0|0|0|0 +*|warriorguard||||||368|892|0|1|30|45|2|0|1|1|0|0|0|0|0 +*|troll||||||1301|607|16|1|120|240|12|6|1|1|0|0|0|0|0 +*|tropicalbird||||||2363|3472|6|1|15|60|30|50|1|3|0|0|0|0|0 +*|brigand||||||1834|383|0|1|360|720|9|6|1|3|0|0|0|0|0 +*|gargoyle||||||1874|263|0|1|360|480|20|12|1|3|0|0|0|0|0 +*|warriorguard||||||1826|2675|0|1|15|30|7|3|1|1|0|0|0|0|0 +*|ettin||||||1823|1068|0|1|120|240|12|45|1|1|0|0|0|0|0 +*|ancientwyrm||||||4593|3598|30|1|60|360|25|1|1|1|0|0|0|0|0 +*|drake||||||4593|3597|30|1|60|360|25|15|1|3|0|0|0|0|0 +*|evilmage:evilmage:evilmage:evilmagelord||||||4593|3570|30|1|60|360|20|10|1|3|0|0|0|0|0 +*|evilmagelord||||||2494|3568|5|1|180|360|1|0|1|1|0|0|0|0|0 +*|daemon||||||2497|3590|5|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2497|3586|11|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2497|3594|11|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2497|3598|11|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2491|3598|11|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2491|3594|11|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2491|3590|5|1|180|180|1|1|1|1|0|0|0|0|0 +*|daemon||||||2491|3586|11|1|180|180|1|1|1|1|0|0|0|0|0 +*|greathart||||||1822|1073|0|1|120|240|12|45|1|5|0|0|0|0|0 +*|hind||||||1820|1092|0|1|120|240|12|45|1|5|0|0|0|0|0 +*|mongbat||||||2488|74|0|1|20|40|45|9|1|3|0|0|0|0|0 +*|mongbat:slime||||||2522|72|0|1|20|40|45|4|1|3|0|0|0|0|0 +*|bird:bird:bird:bird:hind:rabbit:brownbear:mongbat:rabbit:hind:brownbear:rabbit:bird||||||2748|499|15|1|45|120|18|55|1|35|0|0|0|0|0 +*|farmer||||||802|2267|0|1|60|360|7|3|1|1|0|0|0|0|0 +*|miner||||||2589|535|15|1|15|30|4|1|1|1|0|0|0|0|0 +*|pumpkin||||||825|2267|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|pumpkin||||||827|2263|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|pumpkin||||||823|2267|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|pumpkin||||||823|2262|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|pumpkin||||||827|2266|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|pumpkin||||||819|2264|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|pumpkin||||||817|2262|0|1|360|720|0|0|1|1|0|0|0|0|0 +*|orcishspirit||||||2093|787|0|1|180|360|24|6|1|3|0|0|0|0|0 +*|orc||||||1767|1098|0|1|1|1|18|14|1|3|0|0|0|0|0 +*|seaserpent||||||2764|31|-5|1|720|720|80|20|1|3|0|0|0|0|0 +*|crow||||||2751|875|0|1|60|120|14|3|1|1|0|0|0|0|0 +*|bonemagi:bonemagi:bonemagi:bonemagi:ghoul:ghoul||||||2746|864|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|bonemagi:bonemagi:bonemagi:ghoul||||||2746|851|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|lich:lich:lich:lich:lich:bonemagi||||||2741|858|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|crow||||||2755|846|0|1|60|120|14|3|1|1|0|0|0|0|0 +*|zombie:zombie:zombie:skeleton:skeleton:ghoul||||||2779|843|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|crow||||||2777|860|0|1|60|120|14|3|1|1|0|0|0|0|0 +*|zombie:zombie:zombie:skeleton:skeleton:ghoul:bonemagi:lich||||||2763|851|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|zombie:zombie:zombie:skeleton:ghoul||||||2763|860|0|1|30|60|9|3|1|2|0|0|0|0|0 +*|zombie:zombie:ghoul:skeleton:bonemagi:lich||||||2763|874|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|zombie:zombie:skeleton:ghoul||||||2775|885|0|1|60|120|7|3|1|1|0|0|0|0|0 +*|ghoul:ghoul:bonemagi:ghoul:ghoul||||||2763|888|0|1|30|60|9|3|1|2|0|0|0|0|0 +*|zombie:skeleton:skeleton:ghoul:skeleton||||||2744|882|0|1|30|60|9|3|1|2|0|0|0|0|0 +*|zombie:skeleton:skeleton:ghoul:skeleton||||||2744|888|0|1|30|60|9|3|1|2|0|0|0|0|0 +*|bonemagi:ghoul:ghoul:ghoul||||||2732|882|0|1|30|60|9|3|1|1|0|0|0|0|0 +*|zombie:zombie:zombie:skeleton:skeleton:ghoul||||||2732|889|0|1|30|60|9|3|1|3|0|0|0|0|0 +*|zombie:zombie:zombie:skeleton:skeleton:ghoul||||||2732|874|0|1|30|60|9|3|1|3|0|0|0|0|0 +*|dolphin||||||1893|2720|20|1|15|60|2|0|1|1|0|0|0|0|0 +*|seaserpent||||||3268|844|-5|1|120|240|250|20|1|1|0|0|0|0|0 +*|seaserpent||||||2084|1357|-5|1|120|240|250|15|1|1|0|0|0|0|0 +*|waterelemental||||||2300|232|-5|1|120|240|40|6|1|1|0|0|0|0|0 +*|seaserpent||||||2366|346|-5|1|120|240|250|15|1|1|0|0|0|0|0 +*|earthelemental||||||5387|78|20|1|60|180|7|3|1|1|0|0|0|0|0 +*|earthelemental||||||5387|61|20|1|60|180|7|3|1|1|0|0|0|0|0 +*|slime||||||5389|28|20|1|60|120|9|3|1|1|0|0|0|0|0 +*|slime||||||5470|12|0|1|120|180|7|3|1|1|0|0|0|0|0 +*|lizardman||||||5453|12|0|1|60|180|7|3|1|2|0|0|0|0|0 +*|slime||||||5442|12|0|1|120|180|9|4|1|1|0|0|0|0|0 +*|lizardman||||||5428|20|6|1|30|60|7|3|1|1|0|0|0|0|0 +*|lizardman||||||5407|27|20|1|30|60|7|3|1|1|0|0|0|0|0 +*|lizardman||||||5412|18|20|1|30|45|7|3|1|2|0|0|0|0|0 +*|lizardman||||||5403|12|30|1|30|60|7|3|1|1|0|0|0|0|0 +*|lizardman||||||5390|11|30|1|30|45|5|3|1|3|0|0|0|0|0 +*|orc||||||5404|75|10|1|30|60|7|3|1|1|0|0|0|0|0 +*|orc||||||5421|76|10|1|60|120|7|3|1|2|0|0|0|0|0 +*|orc:orc:orc:orccaptain:orcishmage||||||5408|60|-20|1|60|120|7|3|1|3|0|0|0|0|0 +*|orc||||||5427|57|10|1|120|300|5|3|1|1|0|0|0|0|0 +*|orc:orc:orc:orcishlord:orccaptain||||||5426|43|10|1|60|180|7|3|1|3|0|0|0|0|0 +*|orc:orc:orc:orcishlord||||||5445|63|-10|1|60|180|7|4|1|3|0|0|0|0|0 +*|orcishmage||||||5448|35|-10|1|120|300|7|3|1|1|0|0|0|0|0 +*|orc||||||5450|33|-10|1|60|180|7|4|1|3|0|0|0|0|0 +*|orc:orc:orcishlord||||||5457|29|-10|1|60|180|7|3|1|2|0|0|0|0|0 +*|orc:orcishlord:orc||||||5473|29|-30|1|60|180|7|3|1|2|0|0|0|0|0 +*|rat||||||5476|61|20|1|60|180|9|3|1|1|0|0|0|0|0 +*|lichlord||||||5691|525|0|1|40|60|9|3|1|1|0|0|0|0|0 +*|zombie||||||5691|528|0|1|30|50|7|3|1|5|0|0|0|0|0 +*|lich:lich:lich:lich:lichlord||||||5705|525|0|1|40|60|7|3|1|2|0|0|0|0|0 +*|slime||||||5471|77|35|1|180|300|9|3|1|1|0|0|0|0|0 +*|zombie||||||5705|524|0|1|30|50|7|3|1|5|0|0|0|0|0 +*|orc:orc:orccaptain||||||5453|87|20|1|60|120|7|3|1|2|0|0|0|0|0 +*|rat||||||5455|116|20|1|60|120|7|3|1|1|0|0|0|0|0 +*|orc:orc:orccaptain||||||5439|94|20|1|120|180|7|3|1|3|0|0|0|0|0 +*|orc||||||5420|91|20|1|180|300|7|3|1|1|0|0|0|0|0 +*|orc:orc:orc:orc:orccaptain||||||5404|91|10|1|120|180|7|4|1|1|0|0|0|0|0 +*|orc:orc:orc:orccaptain||||||527|1577|0|1|180|300|9|3|1|2|0|0|0|0|0 +*|orc:orc:orc:orccaptain||||||5400|109|3|1|120|180|9|4|1|1|0|0|0|0|0 +*|skeleton:skeleton:zombie||||||5432|116|0|1|60|120|7|3|1|2|0|0|0|0|0 +*|rat||||||5481|79|35|1|60|120|7|3|1|1|0|0|0|0|0 +*|ratman||||||5486|88|35|1|30|45|7|3|1|3|0|0|0|0|0 +*|rat||||||5492|100|35|1|60|120|7|3|1|1|0|0|0|0|0 +*|lich||||||5678|525|0|1|30|50|7|3|1|1|0|0|0|0|0 +*|rat||||||5480|116|24|1|60|120|7|3|1|1|0|0|0|0|0 +*|zombie||||||5676|529|0|1|30|50|5|3|1|3|0|0|0|0|0 +*|ratman||||||5490|114|20|1|30|45|7|3|1|3|0|0|0|0|0 +*|slime||||||5434|116|0|1|60|120|9|3|1|1|0|0|0|0|0 +*|zombie||||||5681|525|0|1|20|40|5|3|1|3|0|0|0|0|0 +*|zombie||||||5676|526|0|1|20|40|5|3|1|2|0|0|0|0|0 +*|skeleton:skeleton:zombie||||||5421|112|0|1|20|40|7|3|1|2|0|0|0|0|0 +*|zombie||||||5419|108|0|1|30|45|7|4|1|1|0|0|0|0|0 +*|skeleton||||||5419|111|0|1|30|45|7|4|1|3|0|0|0|0|0 +*|ratman||||||5690|550|0|1|40|60|7|3|1|3|0|0|0|0|0 +*|skeleton:zombie||||||5720|570|20|1|40|60|7|3|1|3|0|0|0|0|0 +*|lich||||||5721|559|20|1|40|60|9|3|1|1|0|0|0|0|0 +*|zombie||||||5722|559|20|1|20|40|7|4|1|5|0|0|0|0|0 +*|slime||||||5657|570|20|1|60|120|7|3|1|1|0|0|0|0|0 +*|lizardman||||||1939|2323|0|1|30|120|20|150|1|10|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||1938|2323|0|1|15|45|25|150|1|75|0|0|0|0|0 +*|lich||||||5651|558|20|1|30|50|7|1|1|1|0|0|0|0|0 +*|skeletalknight:zombie||||||5666|560|21|1|30|50|5|1|1|2|0|0|0|0|0 +*|zombie||||||5666|558|20|1|20|40|5|1|1|3|0|0|0|0|0 +*|zombie||||||5658|558|20|1|30|50|7|1|1|5|0|0|0|0|0 +*|skeletalknight:skeleton:zombie:rat||||||5652|559|20|1|30|50|7|1|1|1|0|0|0|0|0 +*|zombie||||||5651|560|20|1|20|40|5|1|1|3|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||2876|753|0|1|10|30|15|50|1|25|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||2953|931|0|1|10|30|15|50|1|25|0|0|0|0|0 +*|cat:dog||||||2253|1209|0|1|15|45|20|15|1|3|0|0|0|0|0 +*|slime||||||1364|1471|10|1|5|30|5|0|1|1|0|0|0|0|0 +*|weaponsmith||||||2530|573|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|zombie:skeleton||||||5852|588|15|1|40|60|9|3|1|2|0|0|0|0|0 +*|zombie:skeleton||||||5853|566|15|1|40|60|9|3|1|2|0|0|0|0|0 +*|lich||||||5869|554|15|1|30|50|5|2|1|1|0|0|0|0|0 +*|skeleton:skeletalknight:zombie||||||5859|548|15|1|30|50|7|3|1|3|0|0|0|0|0 +*|lichlord||||||5860|541|15|1|40|60|7|3|1|1|0|0|0|0|0 +*|zombie||||||5864|561|15|1|20|40|5|1|1|2|0|0|0|0|0 +*|zombie||||||5864|569|15|1|30|50|5|1|1|3|0|0|0|0|0 +*|zombie||||||5864|577|15|1|20|40|5|1|1|2|0|0|0|0|0 +*|zombie||||||5864|585|15|1|30|50|5|1|1|3|0|0|0|0|0 +*|brigand||||||1930|1151|0|1|15|45|7|2|1|2|0|0|0|0|0 +*|zombie||||||5863|594|15|1|20|40|5|1|1|2|0|0|0|0|0 +*|brigand||||||1936|1146|0|1|15|45|7|2|1|2|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1572|2233|5|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1571|2233|5|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1572|2232|5|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1571|2232|5|1|15|45|25|250|1|20|0|0|0|0|0 +*|orc:orc:orc:orc:orc:orc:orc:orccaptain:orcishlord:orcishlord:orcishmage:orcishmage:orcishmage||||||2630|716|0|1|120|240|10|4|1|13|0|0|0|0|0 +*|ratman||||||5836|586|0|1|60|120|7|4|1|2|0|0|0|0|0 +*|ratman||||||5826|606|0|1|60|120|7|4|1|1|0|0|0|0|0 +*|ratman||||||5819|593|0|1|60|120|7|4|1|2|0|0|0|0|0 +*|lichlord||||||5784|527|10|1|60|120|7|1|1|1|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:Hind:Cat:Goat:Rabbit:Sheep:Greathart:Pig:Llama:Mongbat||||||2577|154|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||2545|155|0|1|15|45|25|250|1|30|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:bird||||||2566|114|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|airelemental||||||5459|878|30|1|45|60|9|4|1|1|0|0|0|0|0 +*|earthelemental||||||5487|899|30|1|45|60|9|6|1|1|0|0|0|0|0 +*|drake||||||5510|940|20|1|30|45|14|6|1|2|0|0|0|0|0 +*|earthelemental||||||5466|932|20|1|30|45|9|6|1|2|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1560|2649|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1560|2648|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1559|2649|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1559|2648|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|waterelemental||||||5526|1004|5|1|20|40|12|6|1|1|0|0|0|0|0 +*|waterelemental||||||5503|1011|5|1|45|75|12|4|1|2|0|0|0|0|0 +*|earthelemental||||||5471|994|5|1|30|45|9|4|1|1|0|0|0|0|0 +*|earthelemental||||||5499|980|15|1|30|45|9|5|1|1|0|0|0|0|0 +*|earthelemental||||||5499|962|15|1|45|45|9|5|1|1|0|0|0|0|0 +*|airelemental||||||5474|969|15|1|45|75|9|6|1|2|0|0|0|0|0 +*|skeleton:zombie||||||5801|566|10|1|40|60|9|3|1|1|0|0|0|0|0 +*|skeleton||||||5801|587|10|1|40|60|7|3|1|1|0|0|0|0|0 +*|slime||||||5801|579|10|1|30|50|9|6|1|2|0|0|0|0|0 +*|zombie:skeleton||||||5789|595|10|1|20|40|5|1|1|2|0|0|0|0|0 +*|skeletalknight||||||5789|594|10|1|30|50|5|1|1|1|0|0|0|0|0 +*|skeleton:zombie||||||5789|587|10|1|30|50|5|1|1|2|0|0|0|0|0 +*|skeletalknight||||||5789|586|10|1|40|60|5|1|1|1|0|0|0|0|0 +*|skeletalknight||||||5789|579|11|1|40|60|5|1|1|1|0|0|0|0|0 +*|zombie:skeleton||||||5789|578|10|1|40|60|5|1|1|2|0|0|0|0|0 +*|skeleton:zombie||||||5789|571|10|1|40|60|5|1|1|1|0|0|0|0|0 +*|dragon||||||5508|939|20|1|30|45|9|6|1|1|0|0|0|0|0 +*|skeletalknight:bonemagi:skeletalknight||||||5789|570|10|1|40|60|5|1|1|2|0|0|0|0|0 +*|skeleton:zombie||||||5789|563|10|1|40|60|5|1|1|2|0|0|0|0|0 +*|skeletalknight||||||5789|562|10|1|40|60|5|1|1|1|0|0|0|0|0 +*|skeleton||||||5790|555|10|1|20|40|5|1|1|2|0|0|0|0|0 +*|skeletalknight||||||5790|554|10|1|30|50|5|1|1|1|0|0|0|0|0 +*|lich||||||5789|540|10|1|40|60|7|1|1|1|0|0|0|0|0 +*|lich||||||5789|545|10|1|30|50|7|2|1|1|0|0|0|0|0 +*|lich||||||5794|540|10|1|40|60|7|1|1|1|0|0|0|0|0 +*|daemon||||||5446|964|15|1|30|45|12|6|1|1|0|0|0|0|0 +*|earthelemental||||||5388|940|20|1|45|75|12|4|1|1|0|0|0|0|0 +*|snake||||||5822|535|0|1|20|40|14|6|1|2|0|0|0|0|0 +*|lizardman||||||5832|532|0|1|30|50|7|2|1|3|0|0|0|0|0 +*|monk||||||2070|813|0|1|15|60|15|4|1|1|0|0|0|0|0 +*|slime||||||5397|979|5|1|45|75|12|4|1|1|0|0|0|0|0 +*|lizardman||||||5823|526|0|1|20|40|7|2|1|3|0|0|0|0|0 +*|monk||||||2045|807|20|1|15|60|15|4|1|4|0|0|0|0|0 +*|lizardman||||||5401|996|5|1|20|40|9|4|1|2|0|0|0|0|0 +*|lizardman||||||5397|1000|5|1|30|45|9|4|1|5|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1912|3038|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1912|3039|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1911|3039|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1911|3038|0|1|15|45|25|150|1|20|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1597|3076|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||1598|3076|0|1|15|45|25|250|1|200|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||1088|3154|0|1|15|45|25|60|1|10|0|0|0|0|0 +*|dragon:drake||||||1087|3154|0|1|60|360|20|50|1|5|0|0|0|0|0 +*|lizardman||||||1136|2847|0|1|30|120|25|100|1|15|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||1135|2847|0|1|15|45|25|150|1|100|0|0|0|0|0 +*|earthelemental||||||5423|947|20|1|20|40|9|3|1|1|0|0|0|0|0 +*|earthelemental||||||5408|932|20|1|45|75|9|4|1|3|0|0|0|0|0 +*|earthelemental||||||5430|921|20|1|45|75|9|4|1|2|0|0|0|0|0 +*|zombie||||||2047|226|14|1|60|120|7|1|1|1|0|0|0|0|0 +*|zombie||||||2036|226|14|1|60|120|7|1|1|1|0|0|0|0|0 +*|rat||||||5392|901|30|1|30|45|12|4|1|2|0|0|0|0|0 +*|ratman||||||5393|900|30|1|20|40|9|4|1|2|0|0|0|0|0 +*|ratman||||||5387|897|30|1|30|45|9|3|1|3|0|0|0|0|0 +*|provisioner||||||2840|868|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||2840|867|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|earthelemental||||||5409|884|30|1|20|40|9|4|1|3|0|0|0|0|0 +*|banker||||||2508|550|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|armorer||||||2475|562|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|balron||||||6103|35|27|1|15|360|15|1|1|1|0|0|0|0|0 +*|banker||||||1433|1687|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|lizardman||||||1863|931|-1|1|15|60|15|0|1|5|0|0|0|0|0 +*|noble:noble:noble:bridegroom:escortablemage||||||2432|544|0|1|120|240|5|4|1|1|0|0|0|0|0 +*|miner||||||2458|485|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|slime||||||5430|867|45|1|45|75|9|4|1|1|0|0|0|0|0 +*|spiderssilk||||||4541|1320|8|1|60|120|10|10|1|3|0|0|0|0|0 +*|ghoul||||||4547|1305|8|1|30|50|7|4|1|3|0|0|0|0|0 +*|lich||||||4546|1305|8|1|30|50|7|3|1|1|0|0|0|0|0 +*|skeleton:zombie:skeleton||||||4534|1325|8|1|30|50|7|3|1|2|0|0|0|0|0 +*|zombie:skeleton:zombie||||||4534|1318|8|1|20|40|7|3|1|3|0|0|0|0|0 +*|skeleton:zombie:skeleton||||||4547|1325|8|1|30|50|7|3|1|2|0|0|0|0|0 +*|skeleton:zombie:zombie||||||4547|1318|8|1|20|40|7|3|1|3|0|0|0|0|0 +*|slime||||||5465|845|45|1|45|75|7|3|1|1|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1169|2545|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1168|2545|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1169|2544|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1168|2544|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|spiderssilk||||||1367|1472|10|1|60|60|20|20|1|4|0|0|0|0|0 +*|waiter:waitress||||||2467|402|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|tavernkeeper||||||2460|400|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|waitress:waiter||||||2485|402|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|garlic:ginseng:mandrakeroot:blackpearl:bloodmoss:nightshade||||||2722|434|15|1|60|120|100|100|1|100|0|0|0|0|0 +*|brigand||||||852|1686|0|1|20|40|12|6|1|2|0|0|0|0|0 +*|brigand||||||859|1678|0|1|20|40|12|4|1|2|0|0|0|0|0 +*|brigand||||||851|1695|0|1|20|40|12|4|1|2|0|0|0|0|0 +*|brigand||||||842|1680|0|1|20|40|12|4|1|2|0|0|0|0|0 +*|garlic:ginseng:mandrakeroot:blackpearl:nightshade:garlic:bloodmoss||||||1021|2659|0|1|60|120|100|100|1|100|0|0|0|0|0 +*|slime||||||6104|35|27|1|20|40|14|3|1|2|0|0|0|0|0 +*|strongmongbat:headlessone||||||6095|51|22|1|15|45|12|4|1|3|0|0|0|0|0 +*|lizardman||||||6082|92|23|1|15|30|7|3|1|4|0|0|0|0|0 +*|lizardman||||||6082|42|22|1|15|30|7|3|1|4|0|0|0|0|0 +*|lich:giantrat:headlessone:strongmongbat:rat:snake:slime||||||6068|83|22|1|20|40|14|6|1|6|0|0|0|0|0 +*|fireelemental||||||6083|67|27|1|15|30|9|3|1|1|0|0|0|0|0 +*|fireelemental||||||6084|51|22|1|15|30|9|3|1|2|0|0|0|0|0 +*|fireelemental||||||6083|81|19|1|15|30|9|3|1|2|0|0|0|0|0 +*|ratman:giantrat:giantrat:rat:ratman:ratman||||||6108|66|0|1|20|40|9|3|1|6|0|0|0|0|0 +*|slime:snake||||||6111|84|0|1|15|30|9|3|1|2|0|0|0|0|0 +*|lich:giantrat:headlessone:strongmongbat:rat:snake:slime||||||6098|78|0|1|20|40|14|6|1|6|0|0|0|0|0 +*|snake:slime||||||6049|52|0|1|15|30|12|3|1|3|0|0|0|0|0 +*|lich:giantrat:headlessone:strongmongbat:rat:snake:slime||||||6067|59|0|1|20|40|14|6|1|4|0|0|0|0|0 +*|ratman:giantrat:giantrat:rat:ratman:ratman||||||6059|67|0|1|20|40|9|3|1|6|0|0|0|0|0 +*|snake:snake:headlessone:strongmongbat:giantrat:slime:snake:headlessone:strongmongbat:giantrat||||||6081|67|0|1|15|30|14|6|1|9|0|0|0|0|0 +*|lichlord||||||6054|40|0|1|30|60|12|3|1|3|0|0|0|0|0 +*|lich||||||6049|47|0|1|20|40|12|3|1|4|0|0|0|0|0 +*|lich||||||6112|84|0|1|20|40|9|4|1|3|0|0|0|0|0 +*|lichlord||||||6106|92|0|1|30|60|9|2|1|2|0|0|0|0|0 +*|giantspider||||||6115|91|0|1|10|30|9|3|1|3|0|0|0|0|0 +*|daemon||||||6102|35|27|1|30|60|12|4|1|2|0|0|0|0|0 +*|slime:headlessone:headlessone||||||6060|93|22|1|20|40|10|3|1|2|0|0|0|0|0 +*|lichlord||||||6064|96|22|1|30|60|10|3|1|2|0|0|0|0|0 +*|lich||||||6064|95|22|1|20|40|10|3|1|3|0|0|0|0|0 +*|headlessone:strongmongbat||||||6102|170|-17|1|15|45|10|6|1|2|0|0|0|0|0 +*|ratman:ratman:ratman:giantrat:giantrat:rat:strongmongbat||||||6105|156|-22|1|15|45|10|6|1|2|0|0|0|0|0 +*|giantrat:ratman:ratman:rat:giantrat:ratman||||||6094|155|-22|1|20|40|10|3|1|6|0|0|0|0|0 +*|fireelemental:strongmongbat:scorpion||||||6119|178|0|1|15|30|9|3|1|1|0|0|0|0|0 +*|giantspider:fireelemental:fireelemental:headlessone:headlessone:snake:snake:slime:slime:giantrat:rat:strongmongbat:strongmongbat||||||6122|168|0|1|20|40|14|6|1|4|0|0|0|0|0 +*|scorpion||||||6123|158|0|1|15|45|14|8|1|4|0|0|0|0|0 +*|rat:slime:snake:headlessone:strongmongbat||||||6105|179|0|1|20|40|12|9|1|4|0|0|0|0|0 +*|snake:slime:headlessone||||||6098|207|22|1|20|40|12|6|1|4|0|0|0|0|0 +*|snake:giantrat:headlessone||||||6058|178|9|1|15|30|14|3|1|2|0|0|0|0|0 +*|giantspider||||||6059|189|22|1|15|45|12|5|1|3|0|0|0|0|0 +*|fireelemental||||||6055|202|22|1|20|40|10|6|1|2|0|0|0|0|0 +*|giantrat||||||6028|196|22|1|15|45|12|6|1|2|0|0|0|0|0 +*|slime:snake:headlessone:snake:headlessone:headlessone||||||6069|170|0|1|20|40|14|9|1|5|0|0|0|0|0 +*|fireelemental||||||6098|215|22|1|20|40|10|6|1|1|0|0|0|0|0 +*|fireelemental||||||6119|214|22|1|15|30|14|6|1|2|0|0|0|0|0 +*|rat||||||6118|220|22|1|15|45|12|3|1|1|0|0|0|0|0 +*|daemon||||||6119|218|27|1|30|60|10|3|1|1|0|0|0|0|0 +*|lichlord||||||6052|155|0|1|30|60|9|3|1|1|0|0|0|0|0 +*|lich||||||6051|158|0|1|15|30|9|3|1|3|0|0|0|0|0 +*|lich||||||6056|154|0|1|15|30|9|3|1|2|0|0|0|0|0 +*|eldergazer||||||6085|178|0|1|30|60|12|4|1|2|0|0|0|0|0 +*|gazer||||||6087|184|0|1|20|40|9|4|1|2|0|0|0|0|0 +*|gazer||||||6085|176|0|1|20|40|9|5|1|2|0|0|0|0|0 +*|scorpion:snake:scorpion:scorpion||||||5983|218|44|1|15|45|10|6|1|4|0|0|0|0|0 +*|scorpion||||||5986|207|44|1|15|30|9|5|1|2|0|0|0|0|0 +*|Orc:Orc:Orc:Orc:StrongMongbat:OrcCaptain:OrcCaptain:OrcishMage:OrcishLord:Ettin:Troll:Ogre:OgreLord||||||2170|1322|0|1|10|60|20|50|1|10|0|0|0|0|0 +*|snake:slime:headlessone:snake:headlessone||||||5979|202|44|1|20|40|12|4|1|4|0|0|0|0|0 +*|scorpion||||||5984|186|44|1|10|30|10|3|1|2|0|0|0|0|0 +*|Orc:Orc:Orc:Orc:StrongMongbat:OrcCaptain:OrcCaptain:OrcishMage:OrcishLord:Ettin:Troll:Ogre:OgreLord||||||2175|1331|0|1|10|60|20|50|1|10|0|0|0|0|0 +*|scorpion||||||5980|187|44|1|30|45|12|2|1|4|0|0|0|0|0 +*|slime:snake:snake||||||5972|235|22|1|20|40|7|2|1|1|0|0|0|0|0 +*|snake:slime:headlessone||||||5928|186|22|1|20|40|12|4|1|4|0|0|0|0|0 +*|wanderinghealer||||||2464|3618|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1002|2040|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1001|2040|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1002|2039|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1001|2039|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|giantspider:slime:snake||||||5916|202|22|1|20|40|12|4|1|4|0|0|0|0|0 +*|snake:headlessone||||||5931|213|44|1|15|45|12|6|1|4|0|0|0|0|0 +*|giantspider||||||5918|221|44|1|15|30|12|4|1|4|0|0|0|0|0 +*|giantspider||||||5917|233|44|1|15|30|10|4|1|4|0|0|0|0|0 +*|warrior||||||2481|430|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|lizardman:snake:snake||||||5966|146|22|1|12|28|10|3|1|3|0|0|0|0|0 +*|lizardman:snake:snake:slime||||||5949|146|22|1|12|28|14|3|1|3|0|0|0|0|0 +*|lizardman:lizardman:snake||||||5931|146|22|1|12|28|14|3|1|3|0|0|0|0|0 +*|lizardman||||||5922|148|22|1|20|40|10|3|1|2|0|0|0|0|0 +*|snake||||||5915|155|22|1|30|45|10|3|1|3|0|0|0|0|0 +*|lizardman||||||5913|164|22|1|20|40|10|3|1|4|0|0|0|0|0 +*|miner||||||2507|429|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|snake:slime:slime||||||5963|154|0|1|20|40|12|3|1|3|0|0|0|0|0 +*|giantspider||||||5950|154|0|1|20|40|10|3|1|3|0|0|0|0|0 +*|giantspider||||||5947|162|0|1|15|45|10|3|1|2|0|0|0|0|0 +*|horse||||||2669|767|0|1|120|180|140|60|1|2|0|0|0|0|0 +*|rat||||||5952|178|0|1|15|45|10|3|1|2|0|0|0|0|0 +*|slime:snake:snake:headlessone||||||5954|202|22|1|20|40|12|9|1|6|0|0|0|0|0 +*|harpy||||||3228|486|0|1|20|40|9|4|1|3|0|0|0|0|0 +*|harpy||||||3236|453|4|1|20|40|9|4|1|4|0|0|0|0|0 +*|daemon||||||5953|230|22|1|1|1|14|3|1|1|0|0|0|0|0 +*|snake||||||5953|226|22|1|15|30|12|4|1|5|0|0|0|0|0 +*|lizardman||||||5953|227|22|1|15|30|12|4|1|12|0|0|0|0|0 +*|rat||||||5963|170|0|1|15|30|10|3|1|2|0|0|0|0|0 +*|giantrat||||||5987|168|0|1|20|40|10|3|1|3|0|0|0|0|0 +*|rat||||||5991|149|0|1|20|40|10|3|1|3|0|0|0|0|0 +*|giantrat||||||5990|150|8|1|20|40|10|3|1|2|0|0|0|0|0 +*|ratman||||||5991|150|8|1|20|40|10|4|1|9|0|0|0|0|0 +*|slime||||||5930|74|0|1|20|40|12|6|1|1|0|0|0|0|0 +*|giantspider||||||5924|83|0|1|5|15|12|3|1|2|0|0|0|0|0 +*|giantspider||||||5915|87|0|1|15|30|12|3|1|3|0|0|0|0|0 +*|giantspider||||||5917|101|0|1|10|30|12|2|1|1|0|0|0|0|0 +*|giantspider||||||5909|104|6|1|10|30|12|1|1|2|0|0|0|0|0 +*|slime:snake:rat||||||5942|67|0|1|20|40|18|6|1|5|0|0|0|0|0 +*|slime:snake||||||5955|89|22|1|20|40|18|6|1|4|0|0|0|0|0 +*|banker||||||1651|1606|20|1|15|30|5|1|1|1|0|0|0|0|0 +*|scorpion||||||5950|75|22|1|15|30|10|6|1|2|0|0|0|0|0 +*|scorpion||||||5939|106|22|1|15|30|12|6|1|2|0|0|0|0|0 +*|scorpion||||||5942|102|22|1|20|40|12|3|1|6|0|0|0|0|0 +*|lizardman||||||5984|83|0|1|10|30|12|3|1|3|0|0|0|0|0 +*|snake:slime:snake||||||5994|83|0|1|20|40|10|4|1|3|0|0|0|0|0 +*|snake||||||5986|102|0|1|15|30|12|6|1|2|0|0|0|0|0 +*|sheep||||||674|1179|0|1|30|60|18|10|1|9|0|0|0|0|0 +*|slime||||||5994|104|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|lizardman||||||5990|101|0|1|20|40|12|6|1|9|0|0|0|0|0 +*|snake||||||5963|91|0|1|20|40|8|3|1|2|0|0|0|0|0 +*|giantspider||||||5965|79|0|1|20|40|10|3|1|6|0|0|0|0|0 +*|snake||||||5963|65|0|1|15|30|12|3|1|2|0|0|0|0|0 +*|slime||||||5963|50|0|1|30|45|12|3|1|1|0|0|0|0|0 +*|giantrat||||||5990|64|22|1|15|45|12|6|1|2|0|0|0|0|0 +*|rat||||||5990|63|22|1|15|30|12|6|1|3|0|0|0|0|0 +*|ratman||||||5990|62|22|1|20|40|12|6|1|7|0|0|0|0|0 +*|ratman||||||5984|29|22|1|20|40|12|1|1|2|0|0|0|0|0 +*|ratman||||||5978|29|22|1|15|30|10|1|1|2|0|0|0|0|0 +*|ratman||||||5987|26|22|1|15|45|6|2|1|2|0|0|0|0|0 +*|fisherman||||||3013|789|0|1|15|60|5|0|1|2|0|0|0|0|0 +*|harbormaster||||||3012|828|-3|1|15|60|5|0|1|1|0|0|0|0|0 +*|harbormaster||||||2060|2855|-3|1|15|60|5|0|1|1|0|0|0|0|0 +*|harbormaster||||||676|2235|-3|1|15|30|12|3|1|1|0|0|0|0|0 +*|harbormaster||||||2941|3408|1|1|15|60|5|0|1|1|0|0|0|0|0 +*|harbormaster||||||3647|2658|-2|1|15|60|5|0|1|1|0|0|0|0|0 +*|harbormaster||||||3802|1280|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|harbormaster||||||4407|1041|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|slime||||||5988|35|22|1|20|40|14|6|1|1|0|0|0|0|0 +*|rat||||||5987|42|22|1|15|30|14|6|1|2|0|0|0|0|0 +*|harbormaster||||||1372|3888|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|harbormaster||||||2750|2166|-2|1|60|180|12|3|1|1|0|0|0|0|0 +*|harbormaster||||||1484|1757|-2|1|15|30|12|3|1|1|0|0|0|0|0 +*|giantrat||||||5985|50|22|1|30|45|10|6|1|2|0|0|0|0|0 +*|harbormaster||||||1442|1762|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|rat:giantspider:rat:giantrat:slime||||||5970|50|22|1|15|30|10|6|1|5|0|0|0|0|0 +*|giantrat:giantrat:slime:headlessone:snake||||||5963|51|22|1|15|30|10|6|1|3|0|0|0|0|0 +*|giantspider:giantrat:slime:headlessone:snake:headlessone||||||5948|50|22|1|20|45|10|6|1|3|0|0|0|0|0 +*|snake:snake:slime||||||5962|36|0|1|20|45|10|3|1|3|0|0|0|0|0 +*|giantspider||||||5962|28|0|1|20|40|12|4|1|2|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||831|1691|0|1|15|120|25|250|1|50|0|0|0|0|0 +*|giantspider||||||5951|26|0|1|20|40|14|4|1|2|0|0|0|0|0 +*|giantspider||||||5950|26|0|1|10|30|10|4|1|4|0|0|0|0|0 +*|snake||||||5924|51|22|1|20|40|14|5|1|2|0|0|0|0|0 +*|giantspider||||||5908|59|22|1|10|30|14|2|1|2|0|0|0|0|0 +*|lizardman||||||5923|41|22|1|15|30|8|4|1|1|0|0|0|0|0 +*|slime||||||5922|26|44|1|30|45|18|8|1|1|0|0|0|0|0 +*|lizardman||||||5923|35|44|1|20|40|14|4|1|2|0|0|0|0|0 +*|snake||||||5923|36|44|1|15|30|14|4|1|2|0|0|0|0|0 +*|lizardman||||||5922|30|44|1|20|40|14|4|1|2|0|0|0|0|0 +*|snake||||||5915|27|44|1|20|40|14|4|1|2|0|0|0|0|0 +*|lizardman||||||5917|27|44|1|20|40|14|4|1|2|0|0|0|0|0 +*|jackrabbit:rabbit:bird:crow:hind:greathart:brownbear:sheep||||||2547|131|0|1|30|60|24|250|1|30|0|0|0|0|0 +*|tinkerguildmaster||||||4466|1160|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|bloodmoss:mandrakeroot:nightshade:ginseng:garlic||||||3563|2140|34|1|15|60|100|0|1|50|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||885|1683|0|1|15|30|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||884|1683|0|1|15|30|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||885|1682|0|1|15|30|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||884|1682|0|1|15|30|25|250|1|20|0|0|0|0|0 +*|orc||||||2187|1382|0|1|15|60|20|0|1|5|0|0|0|0|0 +*|lichlord||||||5577|1856|0|1|15|45|14|4|1|1|0|0|0|0|0 +*|garlic:bloodmoss:mandrakeroot:nightshade:ginseng||||||777|754|0|1|60|120|100|100|1|100|0|0|0|0|0 +*|bloodmoss:garlic:ginseng:mandrakeroot:nightshade||||||4468|1279|0|1|15|60|100|0|1|100|0|0|0|0|0 +*|bloodmoss:garlic:ginseng:mandrakeroot:nightshade||||||644|2063|0|1|60|120|100|100|1|100|0|0|0|0|0 +*|bloodmoss:garlic:ginseng:mandrakeroot:nightshade||||||1829|2944|-25|1|60|120|100|100|1|100|0|0|0|0|0 +*|bloodmoss:garlic:ginseng:mandrakeroot:nightshade||||||2702|686|0|1|15|60|200|100|1|200|0|0|0|0|0 +*|mage||||||2918|671|0|1|15|60|7|0|1|3|0|0|0|0|0 +*|bloodmoss:mandrakeroot:garlic:ginseng:nightshade||||||1337|1991|0|1|15|60|100|0|1|100|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||2253|1210|0|1|60|360|15|20|1|3|0|0|0|0|0 +*|Timberwolf||||||4498|1393|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|whitewolf||||||4498|1394|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|eagle||||||4496|1393|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||1475|1659|10|1|30|300|15|100|1|5|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||834|1182|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||833|1182|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||834|1181|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||833|1181|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||834|1180|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||833|1180|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Cougar||||||4515|1358|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|bull||||||4510|1357|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|Cow||||||4507|1357|24|1|15|60|5|1|1|1|0|0|0|0|0 +*|greathart||||||4504|1357|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|llama||||||4531|1358|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|horse||||||4530|1369|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|zombie||||||5460|704|15|1|30|45|8|4|1|3|0|0|0|0|0 +*|ghoul||||||5460|705|15|1|30|45|7|4|1|1|0|0|0|0|0 +*|slime||||||5442|725|15|1|30|60|9|3|1|1|0|0|0|0|0 +*|ratman||||||5464|739|5|1|20|40|7|3|1|2|0|0|0|0|0 +*|blackbear||||||4493|1358|23|1|15|60|5|1|1|1|0|0|0|0|0 +*|Polarbear:walrus||||||4511|1394|23|1|15|60|5|1|1|3|0|0|0|0|0 +*|wanderinghealer||||||3620|2553|0|1|15|60|25|200|1|10|0|0|0|0|0 +*|wanderinghealer||||||4060|482|0|1|15|60|25|250|1|10|0|0|0|0|0 +*|evilwanderinghealer||||||1278|1338|0|1|15|60|15|0|1|1|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||2520|513|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||2519|513|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||2521|513|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||863|757|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||862|757|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||863|756|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||862|756|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||863|755|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||862|755|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|MushroomTrap||||||781|1241|0|1|40|120|50|50|1|6|0|0|0|0|0 +*|thiefguildmaster||||||2720|2159|0|1|600|1439|5|0|1|1|0|0|0|0|0 +*|orderguard||||||1334|1624|50|1|30|45|12|7|1|2|0|0|0|0|0 +*|snake:giantspider:snake||||||5545|2014|0|1|15|30|18|6|1|2|0|0|0|0|0 +*|orderguard||||||1341|1624|50|1|30|45|7|7|1|3|0|0|0|0|0 +*|escortablemage||||||1867|2781|0|1|15|30|50|10|1|1|0|0|0|0|0 +*|warriorguard||||||1894|2737|20|1|45|60|7|1|1|1|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1307|2161|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1306|2162|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1305|2162|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1306|2161|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1305|2161|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|hirethief||||||2657|2201|4|1|60|180|12|1|1|1|0|0|0|0|0 +*|rat||||||2751|2167|-2|1|30|45|12|3|1|2|0|0|0|0|0 +*|evilwanderinghealer||||||4616|3664|80|1|15|60|25|200|1|5|0|0|0|0|0 +*|wanderinghealer||||||4615|3664|80|1|15|60|25|200|1|10|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2544|1006|0|1|15|30|25|250|1|50|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2544|1005|0|1|15|30|25|250|1|50|0|0|0|0|0 +*|bird:eagle:crow:eagle:bird:bird||||||1402|4025|0|1|15|30|30|20|1|6|0|0|0|0|0 +*|bird:eagle:bird||||||1422|3970|0|1|30|45|30|15|1|6|0|0|0|0|0 +*|bird:bird:bird:rat||||||1494|3987|0|1|15|30|30|15|1|3|0|0|0|0|0 +*|bird:bird:dog:cat:bird:bird||||||1474|4002|0|1|15|30|30|20|1|6|0|0|0|0|0 +*|bird:bird:cat:dog:bird||||||1439|3999|0|1|30|45|30|20|1|6|0|0|0|0|0 +*|tinker||||||1426|1651|10|1|15|30|5|0|1|2|0|0|0|0|0 +*|fireelemental||||||4619|3567|30|1|15|60|20|1|1|1|0|0|0|0|0 +*|fireelemental||||||4568|3570|30|1|15|60|10|1|1|1|0|0|0|0|0 +*|rat||||||1519|3990|-3|1|30|45|20|2|1|1|0|0|0|0|0 +*|skeleton:skeleton:boneknight:bonemagi:skeleton:skeleton||||||1348|1499|20|1|15|20|10|0|1|4|0|0|0|0|0 +*|fisherman||||||1513|3990|-3|1|15|30|12|2|1|1|0|0|0|0|0 +*|warriorguard||||||1395|3892|0|1|30|45|12|2|1|1|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1241|1761|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||1240|1761|0|1|15|30|25|200|1|50|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1343|1345|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1343|1344|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1342|1345|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1342|1344|0|1|15|45|25|150|1|20|0|0|0|0|0 +*|warriorguard||||||1346|3867|0|1|30|45|12|2|1|1|0|0|0|0|0 +*|slime||||||5579|1903|0|1|15|30|14|6|1|2|0|0|0|0|0 +*|slime||||||5578|1881|0|1|15|30|14|3|1|1|0|0|0|0|0 +*|slime||||||5404|572|62|1|20|40|7|3|1|1|0|0|0|0|0 +*|slime||||||5574|1864|0|1|15|30|18|6|1|1|0|0|0|0|0 +*|scorpion||||||5410|599|45|1|20|40|5|3|1|2|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||2543|1005|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||2543|1006|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||2542|1006|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||2542|1005|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|slime||||||5491|611|44|1|30|45|7|3|1|1|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||2138|864|0|1|15|45|25|100|1|40|0|0|0|0|0 +*|rabbit||||||1418|1519|14|1|45|60|250|30|1|3|0|0|0|0|0 +*|skeletalknight||||||5609|1834|0|1|15|30|14|2|1|2|0|0|0|0|0 +*|ghoul||||||5617|1839|0|1|15|30|22|4|1|3|0|0|0|0|0 +*|slime:slime:snake:strongmongbat||||||5245|948|-40|1|15|75|5|75|1|25|0|0|0|0|0 +*|bonemagi||||||5612|1835|0|1|15|30|14|6|1|2|0|0|0|0|0 +*|skeletalknight||||||5613|1838|0|1|15|30|14|6|1|3|0|0|0|0|0 +*|waterelemental||||||5227|916|-34|1|60|240|10|1|1|2|0|0|0|0|0 +*|skeletalmage||||||5623|1858|0|1|15|45|22|4|1|2|0|0|0|0|0 +*|lich||||||5623|1859|1|1|15|30|18|4|1|1|0|0|0|0|0 +*|drake||||||5144|985|0|1|60|180|25|20|1|2|0|0|0|0|0 +*|slime||||||5158|998|0|1|15|180|50|40|1|10|0|0|0|0|0 +*|ancientwyrm||||||5185|1006|0|1|180|360|10|0|1|1|0|0|0|0|0 +*|slime||||||5149|842|0|1|15|30|50|0|1|10|0|0|0|0|0 +*|ghoul||||||5617|1868|0|1|15|30|14|8|1|3|0|0|0|0|0 +*|fireelemental||||||5140|970|0|1|60|360|8|0|1|1|0|0|0|0|0 +*|boneknight||||||5617|1877|0|1|15|30|14|8|1|3|0|0|0|0|0 +*|drake||||||5151|842|0|1|60|180|20|50|1|5|0|0|0|0|0 +*|dragon||||||5150|842|0|1|60|180|20|50|1|5|0|0|0|0|0 +*|beggar||||||2779|2129|0|1|30|180|4|0|1|1|0|0|0|0|0 +*|ghoul||||||5603|1862|0|1|15|30|14|4|1|1|0|0|0|0|0 +*|skeleton||||||5604|1879|0|1|15|30|14|6|1|3|0|0|0|0|0 +*|dragon||||||5456|1822|0|1|15|30|18|8|1|1|0|0|0|0|0 +*|zombie:zombie:ghoul||||||5538|1815|0|1|15|30|22|4|1|4|0|0|0|0|0 +*|zombie:zombie:ghoul||||||5538|1802|0|1|15|30|22|4|1|4|0|0|0|0|0 +*|skeletalknight||||||5530|1808|0|1|15|30|18|3|1|1|0|0|0|0|0 +*|chaosguard||||||1523|1440|15|1|15|30|10|10|1|5|0|0|0|0|0 +*|ghoul||||||5530|1815|0|1|15|30|14|3|1|3|0|0|0|0|0 +*|ghoul||||||5530|1802|0|1|15|30|14|3|1|3|0|0|0|0|0 +*|skeletalknight||||||5514|1808|0|1|15|45|14|3|1|1|0|0|0|0|0 +*|skeletalknight||||||5523|1814|1|1|15|45|14|3|1|1|0|0|0|0|0 +*|skeletalknight||||||5522|1803|0|1|15|45|14|3|1|1|0|0|0|0|0 +*|bonemagi||||||5522|1814|0|1|15|30|14|3|1|2|0|0|0|0|0 +*|ghoul||||||5514|1814|1|1|15|30|14|3|1|2|0|0|0|0|0 +*|dragon||||||5319|792|0|1|15|30|10|0|1|2|0|0|0|0|0 +*|wanderinghealer||||||2069|791|20|1|15|60|10|0|1|3|0|0|0|0|0 +*|ghoul||||||5514|1802|0|1|15|30|14|3|1|2|0|0|0|0|0 +*|slime||||||2107|780|0|1|180|360|9|1|1|3|0|0|0|0|0 +*|slime||||||2084|783|0|1|180|360|9|1|1|3|0|0|0|0|0 +*|Slime:StrongMongbat:Mongbat:HeadlessOne:Snake||||||5249|820|10|1|15|90|15|50|1|15|0|0|0|0|0 +*|dragon:drake||||||5259|938|-40|1|15|30|5|40|1|3|0|0|0|0|0 +*|ghoul||||||5505|1809|0|1|15|45|12|3|1|2|0|0|0|0|0 +*|drake||||||5358|929|0|1|15|30|10|0|1|2|0|0|0|0|0 +*|dragon||||||5321|979|0|1|15|30|15|0|1|2|0|0|0|0|0 +*|lich||||||5504|1808|0|1|15|30|14|3|1|3|0|0|0|0|0 +*|skeleton||||||5578|1832|0|1|15|30|14|3|1|2|0|0|0|0|0 +*|zombie:skeleton||||||5587|1828|0|1|15|30|14|3|1|3|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1523|969|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1523|968|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1524|969|0|1|15|45|25|150|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1524|968|0|1|15|45|25|150|1|20|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1979|127|4|1|15|45|25|100|1|60|0|0|0|0|0 +*|zombie:skeleton||||||5570|1829|0|1|15|30|14|3|1|3|0|0|0|0|0 +*|ghoul||||||5561|1854|0|1|15|30|22|3|1|3|0|0|0|0|0 +*|zombie||||||5555|1851|0|1|15|30|18|3|1|3|0|0|0|0|0 +*|lich||||||5555|1858|0|1|15|30|14|2|1|1|0|0|0|0|0 +*|sheep||||||1183|3607|0|1|20|40|25|15|1|10|0|0|0|0|0 +*|cow||||||1134|3589|0|1|15|30|30|11|1|3|0|0|0|0|0 +*|zombie:ghoul:skeleton||||||2436|1106|8|1|15|30|10|10|1|5|0|0|0|0|0 +*|lich:lich:ghoul||||||2442|1087|28|1|15|30|3|0|1|1|0|0|0|0|0 +*|sheep||||||1139|3586|0|1|20|40|30|3|1|3|0|0|0|0|0 +*|sheep||||||1118|3573|0|1|20|40|30|2|1|2|0|0|0|0|0 +*|sheep||||||1116|3579|0|1|20|40|30|4|1|2|0|0|0|0|0 +*|sheep||||||1125|3583|0|1|20|40|30|15|1|3|0|0|0|0|0 +*|slime||||||5483|587|45|1|30|45|7|3|1|1|0|0|0|0|0 +*|lich||||||5555|1875|0|1|15|45|7|3|1|1|0|0|0|0|0 +*|lich||||||5555|1866|0|1|15|45|7|2|1|1|0|0|0|0|0 +*|slime||||||5466|570|60|1|20|40|9|3|1|1|0|0|0|0|0 +*|zombie||||||5555|1843|0|1|15|45|14|4|1|2|0|0|0|0|0 +*|slime||||||5453|577|60|1|20|40|7|1|1|1|0|0|0|0|0 +*|warriorguard||||||2281|1209|20|1|15|30|20|1|1|2|0|0|0|0|0 +*|warriorguard||||||2275|1227|0|1|15|30|10|3|1|2|0|0|0|0|0 +*|snake||||||5547|1881|0|1|15|45|4|0|1|1|0|0|0|0|0 +*|snake||||||5475|1811|0|1|15|30|18|4|1|1|0|0|0|0|0 +*|drake||||||5457|1798|0|1|15|30|14|4|1|1|0|0|0|0|0 +*|crow:bird:bird:bird:ghoul||||||723|1122|20|1|60|360|12|2|1|1|0|0|0|0|0 +*|warriorguard||||||2744|984|0|1|15|60|15|0|1|3|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1892|485|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||1892|484|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1891|484|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1892|483|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||1891|483|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|warriorguard||||||2744|983|22|1|15|60|5|0|1|3|0|0|0|0|0 +*|orc:orc:orc:orccaptain:orcishmage||||||2170|1354|0|1|720|720|20|20|1|35|0|0|0|0|0 +*|crow:crow:crow:rat||||||723|1118|0|1|20|40|20|10|1|3|0|0|0|0|0 +*|Orc:Orc:Orc:OrcishLord:OrcishMage:OrcCaptain:OrcCaptain:OrcishMage:OrcishLord:Ettin:Troll:Ogre:OgreLord||||||2171|1354|1|1|720|720|20|20|1|35|0|0|0|0|0 +*|waterelemental||||||2187|1421|-2|1|360|360|3|0|1|1|0|0|0|0|0 +*|orc||||||2171|1355|0|1|1|30|20|20|1|15|0|0|0|0|0 +*|ettin:troll:ogre||||||2189|1291|0|1|15|30|20|0|1|3|0|0|0|0|0 +*|mongbat:strongmongbat||||||2210|1253|0|1|15|30|15|0|1|3|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2457|975|0|1|15|30|25|250|1|100|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||2458|976|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||2457|976|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|slime||||||5454|621|30|1|15|30|7|2|1|1|0|0|0|0|0 +*|SewerRat:Magpie:Raven:Bird:Crow:HireMage:HireFighter:HireThief:Beggar||||||2252|1210|0|1|15|45|15|20|1|5|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2252|1209|0|1|15|45|25|30|1|16|0|0|0|0|0 +*|scorpion||||||5443|624|29|1|20|40|7|3|1|2|0|0|0|0|0 +*|ghost:ghoul:ghoul:ghoul:ghoul:zombie:ghoul:zombie:skeleton||||||730|1118|0|1|30|45|22|4|1|1|0|0|0|0|0 +*|snake||||||5569|1877|0|1|15|30|8|2|1|1|0|0|0|0|0 +*|ghost:ghoul:spectre:shade:shade:zombie:shade:zombie:skeleton||||||716|1121|0|1|30|45|22|4|1|1|0|0|0|0|0 +*|zombie:zombie:skeleton:zombie||||||730|1108|0|1|30|45|20|4|1|1|0|0|0|0|0 +*|ghoul||||||5588|1898|0|1|15|30|18|4|1|4|0|0|0|0|0 +*|ghoul||||||5569|1903|0|1|15|30|18|4|1|4|0|0|0|0|0 +*|skeleton:skeleton:zombie:skeleton||||||716|1108|0|1|30|45|20|4|1|1|0|0|0|0|0 +*|skeleton:zombie:skeleton:skeleton||||||726|1108|0|1|30|45|20|3|1|1|0|0|0|0|0 +*|zombie||||||5602|1889|0|1|15|45|14|2|1|2|0|0|0|0|0 +*|zombie||||||5601|1897|0|1|15|30|14|2|1|2|0|0|0|0|0 +*|skeleton:zombie:skeleton:skeleton||||||720|1108|0|1|30|45|20|3|1|1|0|0|0|0|0 +*|zombie||||||5602|1905|0|1|15|30|14|2|1|2|0|0|0|0|0 +*|zombie||||||5601|1912|0|1|15|45|14|2|1|2|0|0|0|0|0 +*|ghoul:shade:ghoul||||||723|1108|0|1|30|45|22|4|1|2|0|0|0|0|0 +*|skeleton||||||729|1112|0|1|30|45|20|4|1|1|0|0|0|0|0 +*|zombie||||||5556|1889|0|1|15|45|14|2|1|2|0|0|0|0|0 +*|zombie||||||5556|1897|0|1|15|30|14|2|1|2|0|0|0|0|0 +*|zombie||||||5556|1904|0|1|15|30|14|2|1|2|0|0|0|0|0 +*|skeleton:skeleton:zombie:skeleton||||||727|1111|0|1|30|45|20|4|1|1|0|0|0|0|0 +*|zombie:zombie:skeleton||||||723|1111|0|1|30|45|22|4|1|1|0|0|0|0|0 +*|scorpion||||||5428|625|30|1|20|40|7|3|1|2|0|0|0|0|0 +*|skeleton:skeleton:zombie:skeleton||||||719|1111|0|1|30|45|20|4|1|1|0|0|0|0|0 +*|zombie||||||5556|1912|0|1|15|45|14|2|1|2|0|0|0|0|0 +*|giantspider||||||5452|1933|0|1|20|90|14|4|1|2|0|0|0|0|0 +*|skeleton||||||2544|857|0|1|120|240|14|6|1|1|0|0|0|0|0 +*|rat||||||2532|861|0|1|30|45|18|7|1|1|0|0|0|0|0 +*|skeleton||||||716|1113|0|1|30|45|20|4|1|1|0|0|0|0|0 +*|snake||||||2515|860|0|1|30|45|18|8|1|1|0|0|0|0|0 +*|rat||||||2538|892|0|1|30|45|18|7|1|1|0|0|0|0|0 +*|rat||||||2520|885|0|1|30|45|18|10|1|1|0|0|0|0|0 +*|rat||||||2509|868|0|1|15|45|18|10|1|1|0|0|0|0|0 +*|bird:crow||||||2505|882|0|1|30|45|22|10|1|2|0|0|0|0|0 +*|snake||||||2486|877|0|1|30|45|18|10|1|1|0|0|0|0|0 +*|slime||||||5411|623|30|1|20|40|9|3|1|1|0|0|0|0|0 +*|snake||||||2479|863|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|zombie:skeleton:skeleton||||||722|1118|0|1|30|45|16|2|1|1|0|0|0|0|0 +*|crow:bird||||||2468|859|0|1|30|45|22|10|1|2|0|0|0|0|0 +*|skeleton||||||728|1127|0|1|30|45|16|4|1|1|0|0|0|0|0 +*|skeleton||||||720|1127|0|1|30|45|16|4|1|1|0|0|0|0|0 +*|rat||||||2455|864|0|1|30|45|14|7|1|1|0|0|0|0|0 +*|scorpion||||||5390|611|30|1|20|40|7|3|1|3|0|0|0|0|0 +*|rat||||||5400|2004|0|1|15|45|14|4|1|1|0|0|0|0|0 +*|scorpion||||||5388|607|53|1|20|40|7|3|1|2|0|0|0|0|0 +*|zombie||||||717|1127|0|1|30|45|16|4|1|1|0|0|0|0|0 +*|giantrat||||||5408|1995|0|1|15|45|14|6|1|1|0|0|0|0|0 +*|rat||||||5419|1998|0|1|15|45|14|4|1|1|0|0|0|0|0 +*|rat||||||5409|2003|0|1|15|45|14|4|1|1|0|0|0|0|0 +*|daemon||||||1446|908|0|1|1|1|14|3|1|1|0|0|0|0|0 +*|ratman||||||5415|2002|0|1|15|30|14|6|1|2|0|0|0|0|0 +*|scorpion||||||5393|606|53|1|20|40|7|3|1|2|0|0|0|0|0 +*|ratman||||||5419|2006|0|1|15|30|18|6|1|3|0|0|0|0|0 +*|rat||||||5426|1991|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|headlessone||||||5433|1984|0|1|15|45|14|6|1|2|0|0|0|0|0 +*|snake:headlessone||||||5455|1968|0|1|15|45|18|4|1|3|0|0|0|0|0 +*|snake||||||5466|1964|0|1|15|45|22|6|1|1|0|0|0|0|0 +*|gargoyle:troll:harpy:ettin||||||1378|946|0|1|60|180|7|3|1|1|0|0|0|0|0 +*|giantspider||||||5476|1963|0|1|15|45|14|4|1|2|0|0|0|0|0 +*|slime||||||5456|1981|1|1|15|45|18|8|1|2|0|0|0|0|0 +*|snake||||||5433|1974|0|1|15|45|18|8|1|2|0|0|0|0|0 +*|bird:eagle||||||1392|956|0|1|20|40|9|6|1|3|0|0|0|0|0 +*|ratman||||||5420|1974|0|1|15|30|18|6|1|3|0|0|0|0|0 +*|lizardman||||||5415|1976|0|1|15|45|14|6|1|4|0|0|0|0|0 +*|warriorguard||||||713|1484|0|1|30|45|9|3|1|2|0|0|0|0|0 +*|gargoyle||||||1405|941|0|1|60|120|7|6|1|3|0|0|0|0|0 +*|lizardman||||||5437|1957|1|1|15|45|18|6|1|6|0|0|0|0|0 +*|snake||||||5455|1990|0|1|15|45|14|4|1|1|0|0|0|0|0 +*|orc||||||629|1481|0|1|30|45|20|4|1|3|0|0|0|0|0 +*|daemon||||||1405|940|0|1|1|720|20|6|1|1|0|0|0|0|0 +*|snake||||||5457|2002|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|headlessone||||||5451|2002|0|1|15|45|14|4|1|2|0|0|0|0|0 +*|snake||||||5574|2001|0|1|15|30|14|4|1|1|0|0|0|0|0 +*|strongmongbat:rat||||||633|1482|7|1|20|40|20|12|1|3|0|0|0|0|0 +*|gargoyle||||||1433|940|0|1|20|40|7|3|1|2|0|0|0|0|0 +*|orc:orccaptain:orccaptain||||||634|1482|7|1|30|45|20|18|1|2|0|0|0|0|0 +*|orc:orc:orccaptain||||||633|1488|0|1|30|45|20|18|1|4|0|0|0|0|0 +*|ratman||||||5389|555|60|1|20|40|9|2|1|2|0|0|0|0|0 +*|troll||||||1447|947|0|1|30|60|9|3|1|1|0|0|0|0|0 +*|orc:orcishmage:orcishmage||||||633|1485|0|1|30|45|20|12|1|4|0|0|0|0|0 +*|orc:orc:orcishlord:orc||||||638|1485|0|1|30|45|20|12|1|5|0|0|0|0|0 +*|orc:orc:orcishlord:orc||||||628|1485|0|1|30|45|20|12|1|5|0|0|0|0|0 +*|giantspider||||||5475|1985|0|1|15|30|14|4|1|2|0|0|0|0|0 +*|slime||||||5411|532|60|1|20|40|10|4|1|2|0|0|0|0|0 +*|troll:gargoyle||||||1428|972|0|1|120|240|7|3|1|1|0|0|0|0|0 +*|giantspider||||||5470|1994|0|1|15|45|14|6|1|2|0|0|0|0|0 +*|giantspider||||||5467|2007|0|1|15|45|18|3|1|1|0|0|0|0|0 +*|giantspider||||||5452|2021|0|1|15|45|18|6|1|2|0|0|0|0|0 +*|giantspider||||||5437|2024|0|1|15|45|18|6|1|2|0|0|0|0|0 +*|troll||||||1446|979|0|1|60|120|9|4|1|2|0|0|0|0|0 +*|slime||||||5470|2019|0|1|30|60|14|3|1|1|0|0|0|0|0 +*|lich||||||5539|1881|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|snake||||||5469|2017|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|snake||||||5472|2023|0|1|15|45|14|6|1|1|0|0|0|0|0 +*|slime||||||5485|2028|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|giantspider||||||5474|2036|0|1|15|45|14|3|1|2|0|0|0|0|0 +*|bird:eagle||||||1446|980|0|1|20|40|9|12|1|6|0|0|0|0|0 +*|troll:gargoyle||||||1437|1004|0|1|120|240|7|3|1|1|0|0|0|0|0 +*|slime||||||5451|537|60|1|20|40|10|3|1|1|0|0|0|0|0 +*|snake||||||5511|2024|0|1|15|45|18|3|1|1|0|0|0|0|0 +*|ratman||||||5506|2006|0|1|15|30|18|6|1|1|0|0|0|0|0 +*|troll||||||1420|994|0|1|30|60|7|4|1|3|0|0|0|0|0 +*|giantrat||||||5507|2003|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|giantrat||||||5490|1999|0|1|15|45|18|6|1|1|0|0|0|0|0 +*|rat||||||5503|2010|0|1|15|30|18|4|1|1|0|0|0|0|0 +*|slime||||||5452|524|62|1|15|30|10|4|1|1|0|0|0|0|0 +*|eagle:bird||||||1404|984|0|1|20|40|9|6|1|3|0|0|0|0|0 +*|ratman||||||5499|2000|0|1|15|30|18|4|1|3|0|0|0|0|0 +*|rat||||||5512|1997|0|1|15|45|14|4|1|1|0|0|0|0|0 +*|ratman||||||5497|2010|0|1|15|45|14|4|1|3|0|0|0|0|0 +*|harpy||||||1393|992|0|1|20|40|7|3|1|7|0|0|0|0|0 +*|snake:silverserpent:giantspider:snake:scorpion||||||1903|884|0|1|5|30|20|100|1|50|0|0|0|0|0 +*|bird:eagle||||||1379|973|0|1|20|40|9|6|1|3|0|0|0|0|0 +*|troll||||||1355|981|0|1|60|120|9|3|1|1|0|0|0|0|0 +*|slime||||||5473|545|60|1|20|40|10|4|1|1|0|0|0|0|0 +*|bird:eagle||||||1370|941|0|1|20|40|9|6|1|3|0|0|0|0|0 +*|gargoyle||||||1351|949|0|1|20|40|12|4|1|2|0|0|0|0|0 +*|ratman||||||5502|1991|0|1|15|45|14|4|1|3|0|0|0|0|0 +*|troll||||||1373|911|0|1|60|120|9|3|1|1|0|0|0|0|0 +*|gargoyle||||||1352|926|0|1|20|40|12|4|1|2|0|0|0|0|0 +*|troll||||||1398|892|0|1|20|40|9|6|1|2|0|0|0|0|0 +*|rat||||||5503|537|60|1|15|30|14|4|1|1|0|0|0|0|0 +*|herbalist||||||4548|857|30|1|15|30|5|0|1|1|0|0|0|0|0 +*|troll||||||1417|851|0|1|60|120|9|3|1|1|0|0|0|0|0 +*|mage||||||4544|858|30|1|15|30|5|0|1|1|0|0|0|0|0 +*|bird:eagle||||||1417|876|0|1|20|40|9|12|1|3|0|0|0|0|0 +*|rat||||||5515|1985|0|1|15|45|14|3|1|1|0|0|0|0|0 +*|ratman||||||5510|1983|0|1|15|30|18|4|1|2|0|0|0|0|0 +*|snake:rat:slime:slime||||||1425|894|0|1|20|40|9|3|1|1|0|0|0|0|0 +*|snake:slime:headlessone||||||5534|2021|0|1|15|45|18|6|1|2|0|0|0|0|0 +*|troll||||||1441|904|0|1|30|60|7|3|1|3|0|0|0|0|0 +*|slime:slime:giantspider:headlessone:snake||||||5535|2000|0|1|15|30|14|5|1|3|0|0|0|0|0 +*|giantrat||||||5497|530|60|1|20|40|10|6|1|2|0|0|0|0|0 +*|Magpie:Bird:Raven:Crow||||||1476|1645|20|1|15|30|30|150|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||1479|1618|20|1|10|30|15|125|1|25|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||1476|1659|10|1|10|30|15|125|1|25|0|0|0|0|0 +*|rat||||||5548|2030|0|1|15|45|14|3|1|1|0|0|0|0|0 +*|ratman||||||5546|2034|0|1|15|45|14|4|1|2|0|0|0|0|0 +*|headlessone||||||5570|2029|0|1|15|45|14|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||2082|367|0|1|15|30|5|0|1|1|0|0|0|0|0 +*|slime||||||5482|556|60|1|30|45|12|4|1|1|0|0|0|0|0 +*|slime:snake:slime:headlessone:giantspider||||||5580|2028|0|1|15|30|18|5|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||5593|2017|0|1|15|30|14|3|1|3|0|0|0|0|0 +*|snake||||||5580|2011|0|1|10|30|18|3|1|1|0|0|0|0|0 +*|giantspider:scorpion||||||5570|2004|0|1|15|30|14|3|1|2|0|0|0|0|0 +*|bonemagi||||||5603|1863|0|1|15|30|14|4|1|2|0|0|0|0|0 +*|skeleton:ghoul||||||5601|1879|0|1|15|30|14|6|1|5|0|0|0|0|0 +*|skeleton||||||5579|1856|0|1|10|20|14|14|1|5|0|0|0|0|0 +*|lich||||||5579|1857|0|1|10|20|14|14|1|3|0|0|0|0|0 +*|snake||||||5596|2004|0|1|15|30|14|3|1|1|0|0|0|0|0 +*|bird:crow:eagle||||||5245|47|31|1|40|80|20|20|1|9|0|0|0|0|0 +*|cat:dog||||||5196|69|17|1|240|480|9|4|1|1|0|0|0|0|0 +*|closedbarrel||||||5191|587|0|1|1|1|0|0|1|1|0|0|0|0|0 +*|basket||||||1133|2220|66|1|1|1|0|0|1|1|0|0|0|0|0 +*|rat||||||2390|837|0|1|15|45|18|7|1|1|0|0|0|0|0 +*|rat||||||2391|858|0|1|15|45|22|7|1|1|0|0|0|0|0 +*|snake||||||2358|902|0|1|15|30|22|7|1|2|0|0|0|0|0 +*|snake||||||2412|861|0|1|15|30|22|7|1|2|0|0|0|0|0 +*|crow:bird||||||2394|889|0|1|15|45|22|12|1|2|0|0|0|0|0 +*|rat||||||2420|889|0|1|20|40|18|7|1|1|0|0|0|0|0 +*|slime||||||5496|571|60|1|30|60|12|4|1|1|0|0|0|0|0 +*|snake:slime:slime||||||5393|1948|0|1|15|30|14|3|1|1|0|0|0|0|0 +*|alligator||||||1729|3523|0|1|20|40|12|12|1|3|0|0|0|0|0 +*|corpser||||||5410|1933|0|1|10|40|14|10|1|6|0|0|0|0|0 +*|snake:slime:headlessone:slime||||||5391|1923|0|1|15|30|14|3|1|1|0|0|0|0|0 +*|giantspider||||||5387|1910|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|basket||||||2636|2081|16|1|1|1|0|0|1|1|0|0|0|0|0 +*|lizardman||||||2036|1006|0|1|30|120|25|50|1|10|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2035|1006|0|1|15|45|25|75|1|30|0|0|0|0|0 +*|snake||||||5398|1917|0|1|15|40|14|3|1|1|0|0|0|0|0 +*|snake||||||5406|1906|0|1|15|40|18|3|1|1|0|0|0|0|0 +*|zombie||||||5421|1897|0|1|15|40|14|3|1|1|0|0|0|0|0 +*|zombie:skeleton||||||5426|1900|0|1|20|40|14|3|1|3|0|0|0|0|0 +*|zombie||||||5424|1905|0|1|20|40|14|3|1|3|0|0|0|0|0 +*|snake||||||5403|1900|0|1|17|35|14|4|1|1|0|0|0|0|0 +*|headlessone||||||5150|36|27|1|480|960|9|3|1|1|0|0|0|0|0 +*|snake||||||5399|1882|0|1|20|40|14|4|1|1|0|0|0|0|0 +*|snake||||||5604|2001|0|1|15|30|14|4|1|2|0|0|0|0|0 +*|snake||||||5399|1858|0|1|20|40|14|4|1|1|0|0|0|0|0 +*|snake||||||5412|1877|0|1|20|60|14|4|1|1|0|0|0|0|0 +*|cat:dog||||||5192|101|5|1|360|480|9|3|1|1|0|0|0|0|0 +*|giantspider||||||5495|1921|0|1|20|40|14|4|1|2|0|0|0|0|0 +*|giantspider:rat:giantrat:mongbat:strongmongbat||||||5498|1891|0|1|20|40|14|4|1|2|0|0|0|0|0 +*|zombie||||||5404|1857|0|1|20|40|12|3|1|2|0|0|0|0|0 +*|zombie:skeleton||||||5395|1858|0|1|20|60|14|2|1|2|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2716|2204|0|1|60|180|25|250|1|50|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2715|2204|0|1|60|180|25|250|1|100|0|0|0|0|0 +*|giantspider||||||5420|1856|0|1|20|90|14|3|1|1|0|0|0|0|0 +*|gazer||||||5432|1882|0|1|20|60|18|4|1|1|0|0|0|0|0 +*|WhiteWolf:WhiteWolf:SnowLeopard:PolarBear:PolarBear:Walrus:MountainGoat:GrizzlyBear:BlackBear:TimberWolf:Cougar:StrongMongbat:SnowLeopard||||||3936|257|0|1|15|45|25|100|1|50|0|0|0|0|0 +*|WhiteWolf:WhiteWolf:SnowLeopard:PolarBear:PolarBear:Walrus:MountainGoat:GrizzlyBear:BlackBear:TimberWolf:Cougar:StrongMongbat:SnowLeopard||||||4057|575|0|1|15|45|25|150|1|100|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||4741|3821|0|1|15|30|25|500|1|100|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||4219|3683|0|1|15|45|25|250|1|100|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||4470|3723|0|1|15|45|25|200|1|50|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||4579|3676|60|1|15|45|25|200|1|100|0|0|0|0|0 +*|balron||||||4596|3574|75|1|15|15|12|1|1|1|0|0|0|0|0 +*|daemon||||||4595|3574|75|1|15|15|12|1|1|4|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2445|3926|3|1|15|45|30|125|1|75|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2146|3964|3|1|15|45|25|75|1|25|0|0|0|0|0 +*|giantspider||||||5433|1865|0|1|20|40|14|3|1|1|0|0|0|0|0 +*|giantspider:scorpion||||||2381|3389|3|1|15|30|30|25|1|5|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2364|3485|3|1|15|45|25|75|1|25|0|0|0|0|0 +*|giantspider:giantspider:giantspider:gazer||||||5452|1890|0|1|20|40|18|4|1|2|0|0|0|0|0 +*|Slime:StrongMongbat:Mongbat:HeadlessOne:Snake||||||5578|54|0|1|15|90|15|50|1|20|0|0|0|0|0 +*|rarerocks||||||2685|2060|31|1|1410|1410|0|0|1|1|0|0|0|0|0 +*|mage||||||5180|90|5|1|15|30|9|1|1|1|0|0|0|0|0 +*|brigand:pirate:evilmage||||||2002|2931|0|1|60|120|12|3|1|3|0|0|0|0|0 +*|Slime:StrongMongbat:Mongbat:HeadlessOne:Snake||||||5511|179|0|1|15|90|15|100|1|35|0|0|0|0|0 +*|Slime:StrongMongbat:Mongbat:HeadlessOne:Snake||||||5518|279|0|1|15|90|15|50|1|15|0|0|0|0|0 +*|slime:snake:headlessone:headlessone||||||5441|1913|0|1|20|40|18|8|1|4|0|0|0|0|0 +*|airelemental||||||5471|185|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|snake||||||5464|1913|0|1|20|40|18|4|1|1|0|0|0|0|0 +*|airelemental||||||5407|177|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|airelemental||||||5411|144|10|1|15|60|15|15|1|2|0|0|0|0|0 +*|giantspider||||||5461|1933|0|1|20|60|14|4|1|1|0|0|0|0|0 +*|airelemental||||||5468|139|20|1|15|60|15|15|1|3|0|0|0|0|0 +*|airelemental||||||5502|140|20|1|15|60|15|15|1|2|0|0|0|0|0 +*|fruitbasket||||||286|986|6|1|1|1|0|0|1|1|0|0|0|0|0 +*|airelemental||||||5571|238|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|airelemental||||||5606|236|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|airelemental||||||5612|192|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|airelemental||||||5611|192|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|airelemental||||||5602|160|0|1|15|60|15|15|1|4|0|0|0|0|0 +*|airelemental||||||5573|157|-10|1|15|60|15|15|1|4|0|0|0|0|0 +*|CandleLarge||||||5585|1829|6|1|1380|1380|0|0|1|1|0|0|0|0|0 +*|snake||||||5491|1905|0|1|20|60|18|4|1|1|0|0|0|0|0 +*|waterelemental||||||5501|221|0|1|15|60|20|1|1|2|0|0|0|0|0 +*|CandleLarge||||||5573|1829|6|1|1380|1380|0|0|1|1|0|0|0|0|0 +*|airelemental||||||5545|199|0|1|15|60|15|0|1|4|0|0|0|0|0 +*|horse||||||1346|1411|0|1|180|720|500|1250|1|10|0|0|0|0|0 +*|fulljars||||||3656|2506|0|1|1|1|0|0|1|1|0|0|0|0|0 +*|cat:dog||||||5219|128|0|1|60|120|9|3|1|1|0|0|0|0|0 +*|snake||||||5486|1851|0|1|20|90|18|4|1|1|0|0|0|0|0 +*|horse||||||777|755|0|1|180|1439|200|150|1|3|0|0|0|0|0 +*|bridegroom:escortablemage:noble||||||5212|136|0|1|240|360|9|3|1|1|0|0|0|0|0 +*|poisonelemental||||||5408|175|0|1|15|60|35|15|1|1|0|0|0|0|0 +*|snake||||||5467|1876|0|1|20|60|22|4|1|1|0|0|0|0|0 +*|evilmagelord||||||5446|179|22|1|15|60|8|3|1|2|0|0|0|0|0 +*|evilmage||||||5439|186|22|1|15|60|10|6|1|5|0|0|0|0|0 +*|evilmage||||||5439|179|0|1|15|60|10|2|1|1|0|0|0|0|0 +*|evilmage||||||5448|179|0|1|15|60|10|2|1|1|0|0|0|0|0 +*|evilmage||||||5444|193|0|1|15|60|10|8|1|2|0|0|0|0|0 +*|earthelemental||||||5387|240|10|1|15|60|15|0|1|2|0|0|0|0|0 +*|earthelemental||||||5439|138|20|1|15|60|15|0|1|2|0|0|0|0|0 +*|earthelemental||||||5516|140|20|1|15|60|15|0|1|2|0|0|0|0|0 +*|airelemental||||||5613|42|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|earthelemental:scorpion||||||5608|18|10|1|15|60|15|10|1|6|0|0|0|0|0 +*|corpser||||||5549|63|0|1|15|60|5|0|1|1|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||1916|2779|0|1|30|300|15|100|1|5|0|0|0|0|0 +*|waterelemental||||||5548|69|-1|1|15|60|15|1|1|2|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||600|2171|0|1|30|300|15|100|1|9|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||3022|3415|15|1|30|300|15|25|1|5|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||3651|2540|0|1|30|300|15|100|1|5|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||3124|353|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||3125|353|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||3125|352|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||3124|352|0|1|15|45|25|250|1|60|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||3125|351|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|Orc:Ettin:Troll:JackRabbit:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||3124|351|0|1|15|45|25|250|1|20|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||3725|1279|0|1|30|300|15|100|1|5|0|0|0|0|0 +*|Orc:Orc:Orc:Orc:StrongMongbat:OrcCaptain:OrcCaptain:OrcishMage:OrcishLord:Ettin:Troll:Ogre:OgreLord||||||2380|3485|3|1|10|30|20|20|1|10|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2494|3603|0|1|15|45|25|50|1|25|0|0|0|0|0 +*|balron||||||2494|3576|5|1|1|1|5|0|1|1|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||1145|3512|0|1|15|45|25|100|1|25|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||1143|3617|0|1|15|30|60|250|1|50|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure:escortablemage:escortablemage:escortablemage||||||4445|1123|0|1|30|300|15|100|1|5|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||1915|2779|0|1|15|30|25|125|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||1914|2779|0|1|10|30|15|100|1|25|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||2468|470|15|1|30|300|15|100|1|5|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||599|2171|0|1|15|30|25|50|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||598|2171|0|1|10|30|15|50|1|25|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2915|3377|16|1|15|45|25|20|1|5|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2467|470|15|1|15|30|25|50|1|30|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||3021|3415|15|1|15|30|25|250|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||3020|3415|15|1|10|30|15|40|1|25|0|0|0|0|0 +*|Orc:Ettin:Troll:Mongbat:StrongMongbat:AirElemental:Ratman:Slime:Reaper:Ogre:Corpser:Harpy||||||3436|2724|52|1|15|45|25|50|1|10|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||3519|2468|20|1|15|45|25|250|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||3445|2562|44|1|15|45|25|150|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||3444|2562|45|1|15|45|25|75|1|60|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||3634|2820|19|1|15|45|25|100|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||3633|2820|19|1|15|45|25|100|1|60|0|0|0|0|0 +*|SeaSerpent:Dolphin||||||3556|2683|-5|1|10|30|100|75|1|10|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||3642|2653|-2|1|15|30|25|150|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief||||||3650|2540|0|1|10|30|15|40|1|25|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||3704|2196|20|1|30|300|15|100|1|5|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||3724|1279|0|1|15|30|25|250|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||3723|1279|0|1|10|30|15|40|1|25|0|0|0|0|0 +*|wanderinghealer:monk:monk||||||1256|870|16|1|15|60|30|5|1|5|0|0|0|0|0 +*|cat:dog||||||5217|185|5|1|15|30|9|3|1|1|0|0|0|0|0 +*|TimberWolf:Goat:BrownBear:Bull:HellHound:Cat:Goat:Rabbit:Sheep:GiantRat:Pig:Llama:Mongbat||||||4477|1282|0|1|15|45|25|75|1|60|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||4476|1282|0|1|15|45|30|75|1|50|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||4446|1122|0|1|15|30|25|150|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||4445|1122|0|1|10|30|15|50|1|25|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2486|516|0|1|15|30|25|250|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||2485|516|0|1|10|30|15|40|1|25|0|0|0|0|0 +*|EscortableMage:BrideGroom:Noble:Peasant:Messenger:SeekerOfAdventure||||||1412|3824|0|1|30|300|15|50|1|5|0|0|0|0|0 +*|waterelemental||||||5594|88|0|1|15|60|15|1|1|2|0|0|0|0|0 +*|cat:dog||||||5277|162|15|1|60|120|9|3|1|1|0|0|0|0|0 +*|mage||||||5266|157|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|healerguildmaster||||||5260|133|20|1|15|30|7|1|1|1|0|0|0|0|0 +*|healer||||||5261|126|20|1|15|30|7|1|1|1|0|0|0|0|0 +*|cat||||||5310|121|15|1|360|720|9|3|1|1|0|0|0|0|0 +*|sheep||||||571|1099|0|1|15|120|12|0|1|8|0|0|0|0|0 +*|sheep||||||676|938|0|1|15|120|12|0|1|7|0|0|0|0|0 +*|mage||||||5313|108|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|cat||||||5304|101|15|1|60|120|9|3|1|1|0|0|0|0|0 +*|cow:bull:cow||||||1181|3607|0|1|15|30|25|12|1|12|0|0|0|0|0 +*|airelemental||||||5594|90|0|1|15|60|25|15|1|2|0|0|0|0|0 +*|escortablemage:noble:bridegroom||||||5350|93|15|1|120|240|9|3|1|1|0|0|0|0|0 +*|airelemental||||||5620|88|0|1|15|60|10|15|1|3|0|0|0|0|0 +*|waiter:waitress||||||5347|75|25|1|15|30|9|1|1|1|0|0|0|0|0 +*|airelemental||||||5586|56|0|1|15|60|10|15|1|3|0|0|0|0|0 +*|cat:dog||||||5342|66|15|1|120|240|9|3|1|1|0|0|0|0|0 +*|airelemental||||||5585|29|0|1|15|60|10|15|1|3|0|0|0|0|0 +*|airelemental||||||5548|49|0|1|15|60|10|15|1|3|0|0|0|0|0 +*|airelemental||||||5526|48|0|1|15|60|10|15|1|3|0|0|0|0|0 +*|airelemental||||||5563|14|0|1|15|60|10|15|1|4|0|0|0|0|0 +*|bridegroom:escortablemage:noble||||||5313|48|30|1|120|240|9|3|1|1|0|0|0|0|0 +*|cat:dog||||||5314|45|30|1|60|120|9|3|1|1|0|0|0|0|0 +*|butcher||||||529|1008|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||5217|168|5|1|15|30|9|1|1|1|0|0|0|0|0 +*|tailorguildmaster||||||5203|87|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|weaver||||||5201|88|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|tailor||||||5201|87|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|minter||||||5346|74|15|1|15|30|10|15|1|1|0|0|0|0|0 +*|banker||||||5346|74|15|1|15|30|10|15|1|1|0|0|0|0|0 +*|mageguildmaster||||||5148|60|25|1|15|30|7|1|1|1|0|0|0|0|0 +*|alchemist||||||5147|65|25|1|15|30|9|1|1|1|0|0|0|0|0 +*|warriorguard||||||1477|1659|10|1|15|30|15|100|1|20|0|0|0|0|0 +*|mage||||||5146|57|25|1|15|30|7|1|1|1|0|0|0|0|0 +*|innkeeper||||||1585|1591|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||1341|1733|20|1|15|30|10|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||3058|3400|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||2212|1167|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|armorer||||||2214|1167|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|weaponsmith||||||2835|805|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||2835|805|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||1419|3857|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|blacksmith||||||1417|3850|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|weaponsmith||||||2533|576|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|armorer||||||2533|572|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|architect||||||2625|2099|10|1|60|180|7|0|1|1|0|0|0|0|0 +*|carpenter||||||2625|2098|10|1|60|180|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||2962|885|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||3034|827|-3|1|15|30|7|0|1|1|0|0|0|0|0 +*|daemon||||||5299|158|15|1|1|1|9|3|1|1|0|0|0|0|0 +*|Tavernkeeper||||||1547|1768|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||1547|1768|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||1547|1768|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||1547|1768|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||2998|760|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2019|2748|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||1822|2739|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||1897|2684|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||1895|2691|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||1911|2805|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|healer||||||1915|2805|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|furtrader||||||1991|2867|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||1991|2866|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||2072|2856|-3|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||1992|2883|5|1|15|30|7|0|1|1|0|0|0|0|0 +*|dragon||||||5450|1810|0|1|15|30|16|3|1|1|0|0|0|0|0 +*|daemon||||||5285|187|5|1|45|75|7|3|1|1|0|0|0|0|0 +*|innkeeper||||||1844|2735|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1848|2680|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1426|1655|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|dragon:drake||||||5246|227|15|1|45|75|9|3|1|2|0|0|0|0|0 +*|tinkerguildmaster||||||2940|3500|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinker||||||2940|3500|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|dragon||||||5255|235|5|1|30|60|7|3|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||3720|2126|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinker||||||3720|2126|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|furtrader||||||2860|999|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||2860|999|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|furtrader||||||517|986|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||517|986|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||3774|1265|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||3774|1265|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||3774|1265|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||3708|2649|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||1496|1611|21|1|15|30|7|1|1|1|0|0|0|0|0 +*|cobbler||||||2530|547|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|provisioner||||||2526|548|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|cobbler||||||3008|3389|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||3008|3389|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5163|135|0|1|1|1|9|3|1|1|0|0|0|0|0 +*|mapmaker||||||592|2277|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||592|2277|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||578|2227|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||578|2227|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|bowyer||||||564|968|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|furtrader||||||2524|524|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||2524|524|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||1481|1584|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||1481|1584|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|daemon||||||5129|151|0|1|45|75|9|4|1|2|0|0|0|0|0 +*|tailorguildmaster||||||3666|2235|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||3666|2235|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||3666|2235|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||3667|2586|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||3667|2586|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||3667|2586|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||3690|2161|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|lichlord||||||5193|152|0|1|60|120|9|3|1|1|0|0|0|0|0 +*|animaltrainer||||||1388|1657|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|harpy||||||5473|1877|0|1|15|40|18|6|1|6|0|0|0|0|0 +*|animaltrainer||||||2520|375|23|1|15|30|7|1|1|1|0|0|0|0|0 +*|tailorguildmaster||||||2840|885|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||2840|885|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||2840|885|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||2963|621|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||2959|621|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||2966|620|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||3001|3466|-15|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||1296|1759|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||3628|2541|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||3628|2541|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||3628|2541|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||1491|1552|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5190|154|0|1|30|60|7|3|1|2|0|0|0|0|0 +*|alchemist||||||1491|1551|30|1|15|30|7|0|1|2|0|0|0|0|0 +*|mage||||||1491|1550|30|1|15|30|7|0|1|2|0|0|0|0|0 +*|mapmaker||||||2026|2845|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||2026|2845|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||2435|409|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|fisherman||||||643|2238|-3|1|15|30|7|3|1|1|0|0|0|0|0 +*|tailorguildmaster||||||2881|3503|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||2881|3503|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||2881|3503|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|bowyer||||||3054|3369|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||3736|1255|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||3736|1255|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||3736|1255|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||3736|1255|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5163|157|10|1|360|720|7|3|1|1|0|0|0|0|0 +*|weaponsmith||||||1895|2653|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||1895|2653|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|jeweler||||||2882|723|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|evilwanderinghealer||||||1721|3050|0|1|1|5|100|500|1|75|0|0|0|0|0 +*|wanderinghealer||||||1722|3049|0|1|1|5|100|500|1|200|0|0|0|0|0 +*|tailorguildmaster||||||650|2180|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||650|2180|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||650|2180|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||554|2178|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||2905|3517|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||3002|3350|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||3002|3350|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||3002|3350|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||3036|3464|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||2997|3428|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||2997|3428|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||2876|3471|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||2882|3470|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||3018|3433|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5166|183|25|1|720|720|7|3|1|2|0|0|0|0|0 +*|armorer||||||3018|3433|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||3031|3350|35|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||2912|3485|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||5163|24|27|1|15|30|12|1|1|1|0|0|0|0|0 +*|weaponsmith||||||1437|3718|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|armorer||||||1444|3715|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|weaponsmith||||||4440|1162|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||4440|1162|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|scribe||||||5242|178|15|1|15|30|9|1|1|1|0|0|0|0|0 +*|mapmaker||||||3700|1214|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||3700|1214|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||4401|1165|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||4417|1064|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||4417|1064|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||4458|1060|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||4458|1060|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||4458|1060|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|architect||||||1434|1595|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||1433|1595|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||1620|1586|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||1620|1586|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||1620|1586|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||1620|1586|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|mapmaker||||||1453|3739|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|shipwright||||||1452|3739|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|innkeeper||||||2033|2801|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||1547|1659|26|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||1547|1659|26|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||1547|1659|26|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||3732|1306|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5193|193|15|1|360|720|7|3|1|1|0|0|0|0|0 +*|cobbler||||||1852|2831|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||1852|2831|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|rangerguildmaster||||||556|2143|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||3703|2196|20|1|15|30|25|50|1|50|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||3702|2196|20|1|10|30|15|50|1|25|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||1413|3825|0|1|15|30|25|75|1|50|0|0|0|0|0 +*|bowyer||||||2861|812|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Cat:Dog:SewerRat:Magpie:Raven:Bird:Crow:Crow:Crow:HireMage:HireFighter:HireThief:Beggar||||||1412|3825|0|1|10|30|15|60|1|25|0|0|0|0|0 +*|bowyer||||||1472|1579|20|1|15|30|5|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||3554|1202|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmith||||||3554|1202|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5196|221|15|1|1|1|7|3|1|1|0|0|0|0|0 +*|cobbler||||||1602|1712|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||1602|1712|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|jeweler||||||1452|1683|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||2975|3358|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||2732|2253|0|1|60|180|12|2|1|1|0|0|0|0|0 +*|provisioner||||||2729|2255|0|1|60|180|12|2|1|1|0|0|0|0|0 +*|wanderinghealer||||||1344|1411|0|1|1|5|100|1250|1|201|0|0|0|0|0 +*|Tavernkeeper||||||2675|2235|2|1|60|180|12|3|1|1|0|0|0|0|0 +*|evilwanderinghealer||||||1345|1411|0|1|1|5|100|1250|1|50|0|0|0|0|0 +*|waiter||||||2678|2237|2|1|60|180|12|2|1|1|0|0|0|0|0 +*|CandleSkull||||||5166|565|6|1|1|1|0|0|1|1|0|0|0|0|0 +*|cook||||||2682|2242|2|1|60|180|12|2|1|1|0|0|0|0|0 +*|skeleton||||||1359|1458|10|1|5|30|15|5|1|2|0|0|0|0|0 +*|tavernkeeper||||||2683|2244|2|1|60|180|12|2|1|1|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2962|2172|48|1|15|45|30|75|1|25|0|0|0|0|0 +*|Alligator:Alligator:Snake:Snake:TropicalBird:TropicalBird:Panther:Gorilla:Boar:SilverSerpent:StrongMongbat:GiantRat:SewerRat||||||2950|2176|51|1|15|45|30|250|1|25|0|0|0|0|0 +*|HeadlessOne:HeadlessOne:Zombie:Zombie:Ghoul:Ghoul:Skeleton:Skeleton:SkeletalKnight:BoneMagi:Lich||||||1019|731|-40|1|15|45|10|0|1|8|0|0|0|0|0 +*|thiefguildmaster||||||2653|2195|4|1|60|180|12|2|1|1|0|0|0|0|0 +*|innkeeper||||||2715|2098|0|1|60|180|7|0|1|1|0|0|0|0|0 +*|jeweler||||||1897|2804|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|jeweler||||||1448|3979|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|scribe||||||2002|2721|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||2855|734|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||630|2194|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|lichlord||||||5160|207|15|1|60|120|9|3|1|1|0|0|0|0|0 +*|blacksmith||||||630|2194|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||2451|434|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|provisioner||||||2454|427|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|scribe||||||3612|2466|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||3647|2681|-2|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||1433|3744|0|1|15|30|12|1|1|1|0|0|0|0|0 +*|mapmaker||||||1416|1754|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||1416|1754|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||2512|475|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|architect||||||2509|472|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|furtrader||||||3545|1178|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||3545|1178|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|evilmage||||||1928|3421|0|1|15|30|5|0|1|1|0|0|0|0|0 +*|butcher||||||3555|1171|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|lich||||||5161|207|15|1|30|60|9|3|1|2|0|0|0|0|0 +*|bowyer||||||3546|1194|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||3546|1185|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmith||||||3546|1185|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||3610|2577|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|bonemagi:boneknight||||||1849|3203|0|1|15|30|5|0|1|4|0|0|0|0|0 +*|zombie:skeleton:zombie||||||1361|1481|10|1|5|30|16|8|1|3|0|0|0|0|0 +*|innkeeper||||||1458|1525|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||2940|3410|1|1|15|30|7|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2478|427|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|cobbler||||||1443|3798|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|provisioner||||||1441|3796|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|Tavernkeeper||||||3769|1218|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||3769|1218|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||3769|1218|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||3769|1218|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|bard||||||2418|556|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|bardguildmaster||||||2425|553|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|mageguildmaster||||||659|2141|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||659|2141|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||659|2141|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||1360|3815|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|weaponsmith||||||586|2170|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||586|2170|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||4448|1090|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||4448|1090|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||4448|1090|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||4484|1064|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||4418|1112|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|herbalist||||||4418|1111|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||4392|1089|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||4392|1089|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||4407|1038|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|minter||||||2880|683|0|1|15|30|7|0|1|2|0|0|0|0|0 +*|banker||||||2891|675|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||1418|1579|31|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||4392|1117|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||4392|1117|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|merchantguildmaster||||||3703|2249|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|merchantguildmaster||||||1474|1597|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||2450|485|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|Tavernkeeper||||||2901|908|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||2901|908|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||2901|908|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||2901|908|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mapmaker||||||2995|817|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||2994|819|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||3699|2220|20|1|15|30|10|0|1|1|0|0|0|0|0 +*|rangerguildmaster||||||1473|1579|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|alchemist||||||3699|2218|20|1|15|30|10|0|1|1|0|0|0|0|0 +*|mage||||||3699|2219|20|1|15|30|10|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||3665|2140|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||2995|839|0|1|15|30|7|0|1|2|0|0|0|0|0 +*|herbalist||||||2996|839|0|1|15|30|7|0|1|2|0|0|0|0|0 +*|alchemist||||||5215|116|1|1|15|30|7|1|1|1|0|0|0|0|0 +*|lich||||||5196|233|25|1|60|120|9|3|1|2|0|0|0|0|0 +*|herbalist||||||5212|116|1|1|15|30|7|1|1|1|0|0|0|0|0 +*|mageguildmaster||||||2918|672|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||602|2180|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||602|2180|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||602|2180|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||5153|97|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|provisioner||||||5160|95|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|architect||||||4417|1086|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||4416|1086|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||4392|1068|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||5351|55|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|tailorguildmaster||||||1468|1687|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||1470|1688|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||1470|1687|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|bardguildmaster||||||1455|1557|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|bard||||||1455|1557|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|scribe||||||5237|143|15|1|15|30|9|1|1|1|0|0|0|0|0 +*|cobbler||||||3636|2565|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||3636|2565|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||1935|2796|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||1935|2796|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||1935|2796|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||1935|2796|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||559|995|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||1452|4003|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|weaver||||||1450|4003|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|tailor||||||1454|4003|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|mageguildmaster||||||1423|3979|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|alchemist||||||1420|3979|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|mage||||||1425|3982|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|scribe||||||1387|3771|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|healerguildmaster||||||1413|3779|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|healer||||||1416|3771|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|fisherman||||||1125|3685|-2|1|45|60|7|3|1|1|0|0|0|0|0 +*|fisherman||||||1494|3694|-3|1|30|45|12|4|1|1|0|0|0|0|0 +*|fisherman||||||1372|3908|-2|1|15|30|20|2|1|1|0|0|0|0|0 +*|harbormaster||||||1508|3989|-3|1|15|30|12|2|1|1|0|0|0|0|0 +*|minter||||||1319|3770|0|1|15|30|7|2|1|1|0|0|0|0|0 +*|banker||||||1315|3776|0|1|15|30|7|2|1|1|0|0|0|0|0 +*|weaponsmith||||||1454|3853|0|1|15|30|10|2|1|1|0|0|0|0|0 +*|armorer||||||1450|3851|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|jeweler||||||3778|1172|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||2865|852|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||2865|852|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||2779|966|0|1|15|30|15|0|1|3|0|0|0|0|0 +*|mageguildmaster||||||1590|1654|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||1590|1654|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||1590|1654|11|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||1452|3771|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|cook||||||1443|3779|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|waiter||||||1455|3777|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|tavernkeeper||||||1449|3777|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||1934|2771|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmith||||||1934|2771|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|SeaSerpent:Dolphin:Dolphin||||||2999|2000|-5|1|1|30|250|2000|1|100|0|0|0|0|0 +*|alchemist||||||4414|1133|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|herbalist||||||4415|1131|0|1|15|30|7|0|1|2|0|0|0|0|0 +*|armorer||||||1438|1649|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|Eagle:Magpie:Bird:Raven:Crow||||||2087|1978|0|1|15|30|25|250|1|20|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||2086|1978|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|healerguildmaster||||||2242|1229|1|1|15|30|7|1|1|1|0|0|0|0|0 +*|healer||||||2242|1233|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|healerguildmaster||||||2577|599|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|SeaSerpent:Dolphin||||||2549|1717|-5|1|10|30|25|250|1|20|0|0|0|0|0 +*|healer||||||2575|595|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||532|958|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||532|958|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||2920|856|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||2920|856|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||620|2218|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||620|2218|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||3629|2608|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||3629|2608|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||3687|2227|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||3687|2227|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|healerguildmaster||||||2707|2131|0|1|60|180|7|0|1|1|0|0|0|0|0 +*|evilhealer||||||2707|2147|0|1|60|180|7|0|1|2|0|0|0|0|0 +*|healerguildmaster||||||1472|1611|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||1473|1611|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||3632|2595|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||3639|2595|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|architect||||||2915|798|1|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||2914|803|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||1417|1554|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmith||||||1423|1548|30|1|15|30|7|0|1|2|0|0|0|0|0 +*|mapmaker||||||634|1038|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||634|1038|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|bowyer||||||624|1147|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||3726|2223|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||3726|2224|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||3726|2222|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||652|2160|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||652|2160|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||1450|1617|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||2499|429|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||2461|457|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinker||||||2461|457|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1404|3804|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|tinker||||||1397|3808|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||2899|790|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tinker||||||2899|790|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mapmaker||||||3667|2252|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||3667|2252|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||1435|3820|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|architect||||||1436|3822|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|carpenter||||||1432|3818|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||2469|561|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|blacksmith||||||2467|559|5|1|15|30|7|1|1|1|0|0|0|0|0 +*|farmer||||||3022|762|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||3683|2255|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||2963|813|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||3012|3457|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||3012|3457|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||3012|3457|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||3012|3457|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||2010|2807|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||1395|3705|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|blacksmith||||||1395|3711|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|minter||||||4471|1164|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||4472|1159|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||1427|1678|0|1|15|30|5|0|1|1|0|0|0|0|0 +*|butcher||||||1451|4027|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|butcher||||||4395|1137|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||2214|1194|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|provisioner||||||2214|1195|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|farmer||||||3019|766|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||3019|766|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|farmer||||||611|2157|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||611|2157|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|farmer||||||1389|3826|0|1|15|30|10|2|1|1|0|0|0|0|0 +*|butcher||||||1390|3826|0|1|15|30|10|2|1|1|0|0|0|0|0 +*|farmer||||||4481|1085|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||4481|1085|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|jeweler||||||3661|2183|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||595|2248|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||1500|1661|27|1|15|30|7|0|1|2|0|0|0|0|0 +*|herbalist||||||1504|1659|27|1|15|30|7|0|1|2|0|0|0|0|0 +*|mageguildmaster||||||1843|2711|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||1843|2711|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||1843|2711|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||4545|860|30|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||2970|3417|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook:waiter||||||2972|3425|15|1|15|30|7|0|1|3|0|0|0|0|0 +*|healerguildmaster||||||647|1087|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|healer||||||647|1087|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaponsmith||||||1356|3758|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|armorer||||||1357|3756|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||2635|2085|10|1|60|180|7|2|1|1|0|0|0|0|0 +*|blacksmith||||||2633|2083|10|1|60|180|7|1|1|1|0|0|0|0|0 +*|fisherman||||||2255|1175|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|butcher||||||1451|1723|6|1|15|30|7|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2841|907|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||1427|1715|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||1425|1712|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter:waitress||||||1428|1725|20|1|15|30|7|0|1|3|0|0|0|0|0 +*|weaponsmith||||||1479|3859|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|armorer||||||1476|3854|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|butcher||||||2992|776|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|beekeeper||||||2957|705|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||5309|33|40|1|15|30|8|1|1|1|0|0|0|0|0 +*|artist||||||2906|713|0|1|1|30|5|0|1|2|0|0|0|0|0 +*|architect||||||632|2157|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||633|2163|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||1518|1546|25|1|15|30|7|0|1|1|0|0|0|0|0 +*|furtrader||||||2706|2179|0|1|60|180|7|0|1|1|0|0|0|0|0 +*|tanner||||||2705|2180|0|1|60|180|7|0|1|1|0|0|0|0|0 +*|fisherman||||||2751|2166|-2|1|60|180|12|3|1|1|0|0|0|0|0 +*|mageguildmaster||||||2892|654|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||2892|654|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mage||||||2892|654|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||1939|2739|10|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||2967|3408|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||1850|2796|-8|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||1850|2796|-8|1|15|30|7|0|1|1|0|0|0|0|0 +*|alchemist||||||3011|3356|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|herbalist||||||3010|3356|15|1|15|30|7|0|1|2|0|0|0|0|0 +*|cobbler||||||1468|1666|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||1469|1668|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||1348|1778|35|1|15|30|7|0|1|1|0|0|0|0|0 +*|fisherman||||||1476|1759|-2|1|15|30|12|2|1|1|0|0|0|0|0 +*|baker||||||3683|2171|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|butcher||||||582|2186|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||3673|2614|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|Tavernkeeper||||||1498|1691|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|cook||||||1498|1691|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|waiter||||||1498|1691|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||1498|1691|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|architect||||||570|1009|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|carpenter||||||564|1012|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|bowyer||||||590|2205|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster||||||3007|3408|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|blacksmith||||||3007|3408|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|furtrader||||||3602|2615|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||3602|2615|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|furtrader||||||1431|1612|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|tanner||||||1431|1612|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|animaltrainer||||||574|2122|0|1|15|30|7|2|1|1|0|0|0|0|0 +*|bardguildmaster||||||3665|2531|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|bardguildmaster||||||3740|1197|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||586|2146|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||590|2144|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||3690|2511|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||3696|2507|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||3764|1317|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||3762|1323|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||2501|547|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|banker||||||2500|555|0|1|15|30|7|1|1|1|0|0|0|0|0 +*|minter||||||3734|2149|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||3730|2154|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||1814|2828|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||1810|2825|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||1359|3731|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|baker||||||3755|2227|20|1|15|30|7|0|1|1|0|0|0|0|0 +*|baker||||||1882|2803|10|1|15|30|7|1|1|1|0|0|0|0|0 +*|weaponsmith||||||1635|1694|37|1|15|30|7|0|1|1|0|0|0|0|0 +*|armorer||||||1635|1695|37|1|15|30|7|0|1|1|0|0|0|0|0 +*|jackrabbit:rabbit:bird:crow:hind:greathart:brownbear:sheep||||||2500|146|0|1|30|60|24|250|1|30|0|0|0|0|0 +*|mapmaker||||||3632|2640|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|shipwright||||||3632|2640|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|mageguildmaster||||||5301|90|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|alchemist||||||5298|90|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|mage||||||5294|93|15|1|15|30|7|1|1|1|0|0|0|0|0 +*|miner||||||2565|523|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||3672|2654|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|cobbler||||||2992|638|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|provisioner||||||2992|638|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||1356|3780|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|weaver||||||1361|3779|0|1|15|30|12|2|1|1|0|0|0|0|0 +*|tailor||||||1354|3779|0|1|15|30|12|3|1|1|0|0|0|0|0 +*|cobbler||||||535|867|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|skeleton||||||1368|1452|10|1|5|10|10|0|1|1|0|0|0|0|0 +*|zombie||||||1382|1463|10|1|5|10|10|5|1|2|0|0|0|0|0 +*|provisioner||||||535|867|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|ghoul||||||1368|1479|10|1|5|10|15|0|1|2|0|0|0|0|0 +*|zombie||||||1379|1479|10|1|5|30|15|0|1|2|0|0|0|0|0 +*|zombie||||||1369|1496|10|1|5|10|15|4|1|2|0|0|0|0|0 +*|lich||||||1347|1499|20|1|15|20|10|0|1|1|0|0|0|0|0 +*|tailorguildmaster||||||1981|2838|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|weaver||||||1981|2838|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|tailor||||||1981|2838|15|1|15|30|7|0|1|1|0|0|0|0|0 +*|innkeeper||||||610|810|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|minter||||||652|820|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|banker||||||658|813|0|1|15|30|7|0|1|1|0|0|0|0|0 +*|hirefighter||||||2816|494|15|1|15|60|10|1|1|2|0|0|0|0|0 +*|skeleton:zombie||||||2437|1106|8|1|10|25|12|0|1|7|0|0|0|0|0 +*|robe||||||5430|1186|0|1|1|1|0|0|1|1|0|0|0|0|0 +*|robe||||||5430|1263|0|1|1|1|0|0|1|1|0|0|0|0|0 +*|Lich:Lich:Lich:SkeletalKnight:BoneMagi:LichLord||||||5743|982|0|1|15|90|10|0|1|4|0|0|0|0|0 +*|airelemental||||||5755|967|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|ogre||||||5708|967|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|waterelemental||||||5754|951|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|fireelemental||||||5755|935|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|ancientwyrm||||||5754|919|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|dragon||||||5707|919|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|poisonelemental||||||5754|903|-5|1|15|60|5|0|1|2|0|0|0|0|0 +*|lichlord||||||5707|903|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|eldergazer||||||5754|887|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|bloodelemental||||||5707|887|-5|1|15|60|5|0|1|5|0|0|0|0|0 +*|evilhealer:healer||||||4468|1266|0|1|15|60|5|0|1|2|0|0|0|0|0 +*|hellhound:orcishmage:ogrelord||||||2615|574|0|1|15|60|5|0|1|2|0|0|0|0|0 +*|earthelemental||||||5318|583|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5195|652|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5338|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5337|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5339|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5341|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|earthelemental||||||5327|537|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|earthelemental||||||5330|541|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|earthelemental||||||5324|540|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|earthelemental||||||5289|612|0|1|15|60|3|0|1|1|0|0|0|0|0 +*|earthelemental||||||5299|594|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|bonemagi||||||5297|624|-5|1|15|60|1|0|1|1|0|0|0|0|0 +*|bonemagi||||||5296|624|-5|1|15|60|1|0|1|1|0|0|0|0|0 +*|bonemagi||||||5295|624|-5|1|15|60|1|0|1|1|0|0|0|0|0 +*|bonemagi||||||5294|624|-5|1|15|60|1|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5340|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5336|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5343|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5342|576|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5342|578|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5338|581|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5304|745|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5316|744|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5321|754|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5311|756|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lichlord||||||5323|749|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lichlord||||||5305|752|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5329|706|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5283|654|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5269|648|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5267|691|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|fireelemental||||||5275|669|1|1|15|60|10|0|1|2|0|0|0|0|0 +*|fireelemental||||||5275|682|1|1|15|60|10|0|1|2|0|0|0|0|0 +*|lich||||||5307|675|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5306|676|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|poisonelemental||||||5220|735|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5213|674|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5194|653|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|poisonelemental||||||5172|658|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5153|742|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5148|742|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|bonemagi||||||5151|745|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|bonemagi||||||5147|746|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5151|717|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|poisonelemental||||||5130|709|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|waterelemental||||||5135|694|20|1|15|60|2|0|1|1|0|0|0|0|0 +*|poisonelemental||||||5149|700|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|waterelemental||||||5324|604|-3|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5323|570|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5319|577|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5298|579|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5287|583|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|slime||||||5287|582|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5286|583|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5283|559|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5283|565|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeletalknight||||||5284|545|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|headlessone||||||5309|531|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|bonemagi||||||5226|565|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5219|558|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|airelemental||||||5227|535|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5151|623|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5140|623|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5152|597|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5140|602|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|slime||||||5147|595|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5153|604|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5153|588|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5139|586|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5141|592|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5152|578|-50|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5160|539|-30|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5159|540|-30|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5159|540|-30|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5217|531|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5209|544|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5207|557|-20|1|15|60|10|0|1|1|0|0|0|0|0 +*|lich||||||5165|571|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5168|555|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5173|552|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|snake||||||5187|547|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5186|548|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5189|556|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|waterelemental||||||5180|572|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5187|584|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5186|591|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5180|601|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|skeleton||||||5195|600|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|slime||||||5196|612|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5178|626|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5187|614|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|zombie||||||5187|630|0|1|15|60|10|0|1|1|0|0|0|0|0 +*|scorpion||||||5453|563|63|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantrat||||||5439|547|60|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5412|548|60|1|15|60|5|0|1|5|0|0|0|0|0 +*|slime||||||5388|523|65|1|15|60|5|0|1|5|0|0|0|0|0 +*|slime||||||5606|790|60|1|15|60|5|0|1|5|0|0|0|0|0 +*|slime||||||5495|840|45|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5458|791|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5458|782|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5440|780|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5427|780|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5412|783|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|scorpion||||||5400|781|73|1|15|60|5|0|1|2|0|0|0|0|0 +*|giantrat||||||5399|786|65|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5395|821|60|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5392|862|45|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5394|856|45|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5473|740|5|1|15|60|5|0|1|3|0|0|0|0|0 +*|giantrat||||||5461|729|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantrat||||||5466|724|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantrat||||||5478|722|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5506|725|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5506|712|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5506|700|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|rat||||||5508|752|5|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5494|750|5|1|15|60|5|0|1|5|0|0|0|0|0 +*|jeweler:jeweler||||||1651|1641|0|1|15|60|5|0|1|2|0|0|0|0|0 +*|daemon||||||6038|199|22|1|30|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5537|807|45|1|15|60|10|0|1|7|0|0|0|0|0 +*|headlessone||||||5530|837|45|1|15|60|10|0|1|7|0|0|0|0|0 +*|headlessone||||||5551|823|45|1|15|60|10|0|1|7|0|0|0|0|0 +*|giantspider||||||5558|823|45|1|15|60|5|0|1|7|0|0|0|0|0 +*|wanderinghealer||||||1055|3136|0|1|1200|1200|5|0|1|1|0|0|0|0|0 +*|warriorguard||||||1411|1714|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|sheep||||||4411|1446|0|1|15|45|5|0|1|4|0|0|0|0|0 +*|headlessone||||||5516|810|60|1|15|60|10|0|1|5|0|0|0|0|0 +*|scorpion||||||5551|865|45|1|15|60|25|0|1|5|0|0|0|0|0 +*|scorpion||||||5580|861|45|1|15|60|25|0|1|5|0|0|0|0|0 +*|scorpion||||||5573|864|45|1|15|60|25|0|1|5|0|0|0|0|0 +*|giantspider||||||5591|883|30|1|15|60|25|0|1|5|0|0|0|0|0 +*|giantspider||||||5562|883|30|1|15|60|25|0|1|5|0|0|0|0|0 +*|giantspider||||||5537|883|31|1|15|60|25|0|1|5|0|0|0|0|0 +*|strongmongbat||||||5482|819|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|strongmongbat||||||5482|803|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|strongmongbat||||||5495|778|70|1|15|60|5|0|1|1|0|0|0|0|0 +*|mongbat||||||5494|780|70|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantspider||||||5479|794|60|1|15|60|5|0|1|2|0|0|0|0|0 +*|evilmage||||||5458|788|60|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5434|803|60|1|15|60|5|0|1|5|0|0|0|0|0 +*|headlessone||||||5390|753|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5435|697|21|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5431|700|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5418|691|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5407|689|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5386|691|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5385|683|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantspider||||||5388|699|15|1|15|60|5|0|1|5|0|0|0|0|0 +*|headlessone||||||5416|746|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5433|747|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5434|747|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|headlessone||||||5443|749|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantspider||||||5449|755|6|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantspider||||||5433|746|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantspider||||||5397|753|5|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantserpent||||||5407|725|15|1|15|60|5|0|1|1|0|0|0|0|0 +*|mongbat||||||5417|716|15|1|15|60|5|0|1|2|0|0|0|0|0 +*|giantspider||||||5387|662|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|giantspider||||||5415|667|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5441|681|20|1|15|60|5|0|1|5|0|0|0|0|0 +*|scorpion||||||5456|678|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|scorpion||||||5469|668|20|1|15|60|5|0|1|1|0|0|0|0|0 +*|slime||||||5491|663|20|1|15|60|5|0|1|2|0|0|0|0|0 +*|mongbat||||||5508|656|20|1|15|60|5|0|1|5|0|0|0|0|0 +*|giantrat||||||5502|675|22|1|15|60|25|0|1|3|0|0|0|0|0 +*|slime:mongbat:strongmongbat||||||5500|675|21|1|15|60|15|0|1|5|0|0|0|0|0 +*|rat||||||5582|628|30|1|15|60|5|0|1|5|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1440|1115|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1440|1115|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Cougar:Snake:TimberWolf:JackRabbit:StrongMongbat:MountainGoat:Goat:GreyWolf:GrizzlyBear:GiantRat:MountainGoat:Wisp:Gypsy||||||1603|1278|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1392|1323|20|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1338|1326|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1280|1326|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1231|1355|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1313|1410|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1367|1375|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|Hind:GreatHart:Boar:BlackBear:Cow:Chicken:DireWolf:Cat:Dog:JackRabbit:Sheep:Snake:GiantRat||||||1419|1435|0|1|15|45|25|250|1|25|0|0|0|0|0 +*|horse||||||1417|1494|8|1|300|360|5|0|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/BlightedGrove.map b/Data/Monsters/uoml/felucca/BlightedGrove.map new file mode 100644 index 0000000..3b26fe3 --- /dev/null +++ b/Data/Monsters/uoml/felucca/BlightedGrove.map @@ -0,0 +1,20 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2201 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Blighted Grove +## +*|giantserpent:gianttoad:harpy:silverserpent:snake:bogling||||||6513|871|0|1|5|10|35|35|1|17|0|0|0|0|0 +*|tangle:bogling:alligator:reaper:corpser:changeling:whippingvine||||||6507|843|0|1|5|10|10|10|1|8|0|0|0|0|0 +##*|frighteneddryad||||||6500|875|0|1|5|10|0|0|1|1|0|0|0|0|0 +*|abscess:hydra:bogthing||||||6535|848|0|1|5|10|10|10|1|4|0|0|0|0|0 +*|thrasher:swamptentacle:reaper:bogling:alligator:coil:whippingvine||||||6518|870|0|1|5|10|40|40|1|9|0|0|0|0|0 +*|insanedryad||||||6540|872|0|1|5|10|5|5|1|1|0|0|0|0|0 +*|harpy:saliva:changeling||||||6585|878|0|1|5|10|10|10|1|7|0|0|0|0|0 +*|insanedryad||||||6489|897|0|1|5|10|5|5|1|1|0|0|0|0|0 +*|insanedryad||||||6518|879|0|1|5|10|5|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/uoml/felucca/BritainSewer.map b/Data/Monsters/uoml/felucca/BritainSewer.map new file mode 100644 index 0000000..65f197a --- /dev/null +++ b/Data/Monsters/uoml/felucca/BritainSewer.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 2202 +overridemap 1 +overridemintime 0 +overridemaxtime 1 +## +## Britain Sewer +## +*|sewerrat:Rat|Bullfrog|||||6049|1447|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6091|1491|10|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6048|1487|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6065|1459|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6092|1448|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6107|1452|25|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6112|1462|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6039|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6115|1491|-15|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6084|1470|5|2|5|10|15|1|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6049|1470|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6034|1467|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6059|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6061|1490|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6041|1486|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|alligator||||||6090|1483|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6077|1492|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6108|1471|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6087|1443|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6052|1463|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6037|1494|0|2|5|10|10|4|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Covetous.map b/Data/Monsters/uoml/felucca/Covetous.map new file mode 100644 index 0000000..dd98f79 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Covetous.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 2203 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Covetous Dungeon +## +## Level 1 +## +*|Harpy||||||5472|1877|0|2|1|10|25|10|1|6|0|0|0|0|0 +*|Headlessone||||||5453|1905|0|2|2|10|25|5|1|4|0|0|0|0|0 +*|Stoneharpy||||||5443|1918|0|2|2|10|30|7|1|2|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5418|1876|0|2|2|10|30|10|1|4|2|0|0|0|0 +*|Gazer|Gazerlarva|||||5411|1901|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Corpser||||||5393|1921|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5400|1937|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5452|1891|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5399|1859|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5387|1911|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Corpser||||5411|1932|0|2|2|10|7|7|1|1|2|6|0|0|0 +## +## Level 2 +## +*|Headlessone||||||5577|2006|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5593|2017|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5558|2025|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Harpy|Stoneharpy|||||5498|1998|0|2|2|10|30|15|1|8|1|0|0|0|0 +*|Giantspider|Dreadspider|||||5474|2035|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Slime||||||5469|2019|0|2|2|10|25|10|1|5|0|0|0|0|0 +*|Waterelemental||||||5445|2030|-3|2|2|10|15|15|1|2|0|0|0|0|0 +*|Giantspider|Dreadspider|||||5440|2023|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Giantspider|Dreadspider|||||5473|1991|0|2|2|10|25|9|1|2|2|0|0|0|0 +*|Gazer|Gazerlarva|Eldergazer||||5457|1971|0|2|2|10|25|15|1|4|2|1|0|0|0 +*|Corpser||||||5436|1972|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5417|1975|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5429|1989|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Corpser||||||5425|1992|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|Gazer||||||5388|2012|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5503|2002|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|Corpser|||||5413|2000|0|2|2|10|10|10|1|1|7|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5460|1975|0|2|1|2|7|7|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5448|2027|0|2|1|2|8|8|1|1|2|0|0|0|0 +## +## Skeleton Passage +## +*|Skeleton||||||2456|861|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2480|863|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2493|883|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2513|862|0|2|2|10|25|10|1|4|0|0|0|0|0 +## +## Level 3 +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5596|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1876|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Boneknight|Skeleton|Zombie|Shade|||5603|1875|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|||5617|1861|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|TreasureLevel3|TreasureLevel4|5615|1838|0|2|2|10|25|8|1|3|1|1|1|1|2 +*|Lich|Spectre|Skeleton||||5579|1859|0|2|2|10|25|11|1|7|3|1|0|0|0 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1843|0|2|2|10|40|15|1|1|1|1|2|1|1 +## +## Undead Prison +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5528|1808|0|2|2|10|30|15|1|1|1|1|3|1|1 +*|Rottingcorpse|TreasureLevel3|TreasureLevel4||||5504|1808|0|2|2|10|12|3|1|1|1|2|0|0|0 +## +## Dragon's Lair +## +*|Dragon|Drake|||||5452|1799|0|2|2|10|30|20|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5461|1818|0|2|1|2|8|8|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Deceit.map b/Data/Monsters/uoml/felucca/Deceit.map new file mode 100644 index 0000000..6bb425e --- /dev/null +++ b/Data/Monsters/uoml/felucca/Deceit.map @@ -0,0 +1,57 @@ +############## +## By Nerun ## +############## +overrideid 2204 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Deceit Dungeon +## +## Level 1 +## +*|Mummy|Skeleton|Zombie||||5187|603|0|2|2|10|35|18|1|1|3|1|0|0|0 +*|Waterelemental||||||5186|575|0|2|2|10|12|8|1|2|0|0|0|0|0 +*|Skeleton||||||5187|545|0|2|2|10|25|6|1|2|0|0|0|0|0 +*|Mummy|Skeleton|Zombie||||5163|567|0|2|2|10|25|6|1|1|3|1|0|0|0 +*|Skeleton|Zombie|||||5145|553|-40|2|2|10|35|8|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|579|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|598|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5145|622|-50|2|2|10|25|8|1|2|2|0|0|0|0 +*|Skeleton|Spectre|||||5212|531|0|2|2|10|25|8|1|2|1|0|0|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|552|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|573|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|TreasureLevel2|TreasureLevel3|||||5145|618|-50|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ghoul|Skeleton|Wraith|Zombie|||5307|546|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5327|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5286|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Wraith|||||5283|583|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Ghoul|Mummy|Shade|Wraith|Zombie||5318|578|0|2|2|10|25|10|1|1|1|1|1|1|0 +*|Boneknight|Skeletalknight|||||5342|582|0|2|2|10|25|10|1|4|4|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|||5299|603|0|2|2|10|25|10|1|1|1|2|1|0|0 +*|Bonemagi||||||5295|623|-5|2|2|10|10|6|1|3|0|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|Zombie||5322|626|0|2|2|10|25|15|1|1|1|2|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5323|571|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## Level 3 +## +*|Ghoul|Shade|Spectre|Wraith|||5139|661|0|2|2|10|25|15|1|1|1|1|1|0|0 +*|Lich||||||5190|655|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5170|678|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Lich|Spectre|Wraith|||5151|718|0|2|2|10|25|10|1|1|3|1|1|0|0 +*|Ghoul|Poisonelemental|||||5192|695|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Poisonelemental|||||5183|727|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5212|674|-20|2|2|10|25|12|1|1|1|1|1|0|0 +*|Lich||||||5219|734|-20|2|2|10|25|15|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5150|742|0|2|2|10|15|3|1|1|2|2|0|0|0 +## +## Level 4 +## +*|Ghoul|Lich|||||5307|675|-20|2|2|10|25|10|1|2|1|0|0|0|0 +*|Fireelemental||||||5280|675|8|2|2|10|25|10|1|2|0|0|0|0|0 +*|Lich||||||5320|708|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|Lich|Lichlord|Silverserpent||5314|748|-20|2|2|10|25|8|1|1|2|3|1|2|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5267|690|0|2|2|10|35|2|1|1|2|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Despise.map b/Data/Monsters/uoml/felucca/Despise.map new file mode 100644 index 0000000..1286c05 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Despise.map @@ -0,0 +1,63 @@ +############## +## By Nerun ## +############## +overrideid 2205 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Despise Dungeon +## +## Note: Acidelemental do not exist then i used Toxicelemental instead. +## +## Level 1 +## +*|Lizardman|TreasureLevel2|TreasureLevel3||||5503|529|60|2|2|10|25|12|1|5|1|1|0|0|0 +*|Lizardman||||||5504|597|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5464|600|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5435|589|47|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5410|611|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman|TreasureLevel2|TreasureLevel3||||5386|612|45|2|2|10|25|12|1|5|1|2|0|0|0 +*|Lizardman||||||5405|576|61|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5411|541|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5460|526|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5394|525|65|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5390|587|45|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ettin||||||5490|676|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Ettin||||||5483|711|15|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental|Ettin|||||5505|747|5|2|2|10|25|18|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5475|748|5|2|2|10|25|12|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5420|746|5|2|2|10|25|18|1|4|6|0|0|0|0 +*|Ettin||||||5385|703|15|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|660|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental||||||5441|680|20|2|2|10|25|12|1|6|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5507|656|20|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5387|697|15|2|1|2|5|5|1|1|4|0|0|0|0 +## +## Level 3 +## +*|Troll||||||5439|851|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5470|860|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5426|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5482|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Ogre||||||5532|787|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogre||||||5604|789|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogrelord||||||5558|824|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Ogre||||||5590|871|45|2|2|10|35|20|1|3|0|0|0|0|0 +*|Ogre||||||5528|902|30|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ettin||||||5487|902|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5504|939|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Cyclops||||||5471|973|15|2|2|10|25|18|1|3|0|0|0|0|0 +*|Ettin||||||5426|943|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|905|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Toxicelemental||||||5398|996|5|2|2|10|25|15|1|3|0|0|0|0|0 +*|TreasureLevel2||||||5593|794|60|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5546|888|30|2|1|2|8|8|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5397|995|5|2|1|2|10|10|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5605|799|60|2|1|2|10|10|1|3|0|0|0|0|0 +*|TreasureLevel3||||||5557|828|45|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5398|995|5|2|1|2|10|10|1|2|0|0|0|0|0 +*|TreasureLevel4||||||5564|821|45|2|1|2|5|5|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Destard.map b/Data/Monsters/uoml/felucca/Destard.map new file mode 100644 index 0000000..88a0a3b --- /dev/null +++ b/Data/Monsters/uoml/felucca/Destard.map @@ -0,0 +1,55 @@ +############## +## By Nerun ## +############## +overrideid 2206 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Destard Dungeon +## +## Level 1 - First Big Lair (entrance) +## +*|Dragon|Drake|Wyvern||||5209|965|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|||||5247|956|-40|2|2|10|50|30|1|1|2|0|0|0|0 +*|Dragon|Drake|Wyvern||||5280|955|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5284|926|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5214|917|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5241|945|-40|2|1|2|10|10|1|1|2|0|0|0|0 +## +## Level 1 - Left Arm +## +*|Giantserpent||||||5161|940|0|2|2|10|50|20|1|6|0|0|0|0|0 +*|Wyvern|Dragon|Drake||||5149|907|0|2|2|10|20|15|1|1|1|1|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5141|915|0|2|1|2|25|25|1|1|2|0|0|0|0 +## +## Level 1 - Right Arm +## +*|Waterelemental||||||5352|934|-5|2|2|10|10|10|1|4|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5317|980|0|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 1 - Second Big Lair (near Shrine) +## +*|Giantserpent||||||5250|869|0|2|2|10|50|30|1|6|0|0|0|0|0 +*|Dragon|Drake|Wyvern||||5226|826|0|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5269|811|7|2|2|10|50|30|1|1|2|1|0|0|0 +*|Drake|Wyvern|||||5307|815|0|2|2|10|50|30|1|1|1|0|0|0|0 +*|Waterelemental||||||5294|842|0|2|2|10|50|30|1|4|0|0|0|0|0 +*|Waterelemental||||||5203|787|5|2|2|10|25|12|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5229|841|1|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5205|778|0|2|1|2|7|7|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Drake|Shadowwyrm|Wyvern||||5141|834|0|2|2|10|50|30|1|1|1|1|0|0|0 +*|Daemon|Evilmage|||||5169|836|0|2|2|10|50|30|1|2|1|0|0|0|0 +*|Drake|Shadowwyrm|Wyvern||||5152|869|0|2|2|10|50|25|1|1|1|1|0|0|0 +*|TreasureLevel4:TreasureLevel3:TreasureLevel2||||||5153|842|0|2|1|2|40|40|1|4|0|0|0|0|0 +## +## Level 3 - Ancient Wyrm Lair +## +*|Fireelemental||||||5141|968|0|2|2|10|10|10|1|1|0|0|0|0|0 +*|Wyvern:Wyvern:Giantserpent||||||5157|997|0|2|2|10|50|20|1|3|0|0|0|0|0 +*|Ancientwyrm||||||5185|1006|0|2|2|10|50|20|1|1|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5143|986|0|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5183|1007|0|2|1|2|10|10|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Fire.map b/Data/Monsters/uoml/felucca/Fire.map new file mode 100644 index 0000000..6939421 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Fire.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 2207 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Britain/Lost Lands +## Fire Dungeon - OSI Legends like +## +## Level 1 - Part I +## +*|Slime|Giantrat|Giantserpent||||5693|1415|38|2|5|10|20|10|1|1|2|1|0|0|0 +*|Slime||||||5695|1434|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Evilmagelord||||||5680|1438|0|2|5|10|20|10|1|2|0|0|0|0|0 +*|Giantrat|Lavasnake|Evilmage||||5733|1433|22|2|5|10|20|10|1|1|1|1|0|0|0 +*|Lavalizard||||||5787|1427|17|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5717|1465|-2|2|5|10|15|10|1|3|0|0|0|0|0 +*|Fireelemental|Lavasnake|Hellcat|Hellhound|||5744|1471|2|2|5|10|15|10|1|3|1|1|1|0|0 +*|Efreet|Lavaserpent|Hellhound|Fireelemental|||5790|1451|7|2|5|10|15|5|1|1|1|1|1|0|0 +## Graveyard +*|Lich|Bonemagi:Skeletalmage|Hellcat|Hellhound|Fireelemental|Lavalizard|5852|1468|1|2|5|10|30|25|1|4|6|1|3|2|1 +*|Lavasnake||||||5852|1468|1|2|5|10|30|25|1|1|0|0|0|0|0 +## +## Level 1 - Part II +## +*|Lavalizard||||||5859|1387|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Hellcat||||||5787|1386|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5818|1379|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5836|1364|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5809|1332|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5859|1341|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental|Efreet|Lavaserpent||||5835|1304|0|2|5|10|30|15|1|4|1|1|0|0|0 +*|Hellcat|Fireelemental|||||5867|1309|0|2|5|10|20|10|1|1|1|0|0|0|0 +## +## Level 2 +## +*|Fireelemental||||||5699|1302|1|2|5|10|15|15|1|1|0|0|0|0|0 +*|Fireelemental||||||5723|1291|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound||||||5732|1297|-1|2|5|10|20|5|1|1|0|0|0|0|0 +*|Efreet|Lavalizard|||||5667|1315|5|2|5|10|20|20|1|2|1|0|0|0|0 +*|Fireelemental|Lavaserpent|||||5747|1320|0|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lavalizard|Fireelemental|||||5717|1333|6|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lich|Lichlord|||||5731|1379|0|2|5|10|7|3|1|3|1|0|0|0|0 +*|Hellhound||||||5709|1364|-1|2|5|10|20|10|1|6|0|0|0|0|0 +*|Daemon||||||5691|1347|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound|Hellcat|||||5678|1340|-2|2|5|10|30|10|1|1|1|0|0|0|0 +*|Evilmage|Hellhound|Lavasnake|Hellcat|||5651|1363|0|2|5|10|3|3|1|1|5|1|1|0|0 +*|Evilmage||||||5654|1380|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5689|1387|1|2|5|10|10|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5656|1412|0|2|5|10|10|0|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1402|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1403|0|2|5|10|3|3|1|1|0|0|0|0|0 +*|Hellhound||||||5651|1408|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage|Evilmagelord|||||5651|1418|0|2|5|10|3|2|1|1|1|0|0|0|0 +*|Evilmage||||||5650|1419|22|2|5|10|5|2|1|1|0|0|0|0|0 +*|Evilmage||||||5647|1439|22|2|5|10|15|1|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1443|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmagelord||||||5638|1439|0|2|5|10|40|0|1|1|0|0|0|0|0 +## +## Treasures +## +*|TreasureLevel2||||||5714|1465|0|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|1390|2|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5679|1438|0|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|1465|-1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5722|1390|1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5679|1439|0|2|1|2|5|5|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5650|1434|0|2|1|2|2|2|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5643|1435|0|2|1|2|2|2|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Graveyards.map b/Data/Monsters/uoml/felucca/Graveyards.map new file mode 100644 index 0000000..56bdf46 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Graveyards.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 2208 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Graveyards +## +## Britain Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 +## +## Jhelom Graveyard +*|Spectre:Wraith:Shade|Skeleton|Zombie||||1285|3731|0|2|5|10|15|10|1|2|3|4|0|0|0 +## +## Cove Graveyard +*|Spectre:Shade:Wraith|Lich|Skeleton|Zombie|||2438|1100|8|2|5|10|20|10|1|1|1|1|1|0|0 +## +## Moonglow Graveyard +*|Spectre:Shade:Wraith|Skeleton|Zombie||||4545|1317|8|2|5|10|20|10|1|1|1|2|0|0|0 +*|Lich||||||4543|1314|8|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Vesper Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||2758|867|0|2|5|10|20|20|1|2|3|4|0|0|0 +## +## Yew Graveyard +*|Skeleton||||||722|1119|0|2|5|10|20|20|1|10|0|0|0|0|0 +## +## Haven Graveyard +*|zombie:skeleton||||||3407|2652|48|2|5|10|15|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Hythloth.map b/Data/Monsters/uoml/felucca/Hythloth.map new file mode 100644 index 0000000..90f6e54 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Hythloth.map @@ -0,0 +1,102 @@ +############## +## By Nerun ## +############## +overrideid 2209 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Hythloth Dungeon +## +## Level 1 +## +*|Imp|Hellhound|||||5923|48|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|TreasureLevel1|||||5911|55|22|2|2|10|25|10|1|2|3|0|0|0|0 +*|Imp|Hellhound|||||5948|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|Hellhound|||||5954|26|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Imp|Hellhound|||||5977|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Firegargoyle||||||5995|62|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5970|80|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle|Hellhound|||||5994|96|0|2|2|10|20|10|1|2|1|0|0|0|0 +*|Imp|Hellhound|||||5946|75|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5940|107|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5915|91|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5990|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5985|36|22|2|1|2|2|2|1|2|0|0|0|0|0 +*|TreasureLevel1||||||5989|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5983|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5979|26|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5981|84|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5966|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5958|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5937|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5921|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5972|86|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5917|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5929|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5945|78|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5967|80|0|2|1|2|6|6|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Imp|Hellhound|||||5961|169|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Daemon||||||5992|146|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5945|175|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5956|145|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||5917|156|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5914|195|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5918|223|44|2|2|10|20|10|1|4|0|0|0|0|0 +*|Daemon|TreasureLevel4|||||5918|235|44|2|2|10|20|10|1|2|1|0|0|0|0 +*|Gargoyle|TreasureLevel3|||||5954|225|22|2|2|10|20|12|1|4|1|0|0|0|0 +*|Gazer|Gazerlarva|||||5986|203|44|2|2|10|25|12|1|3|2|0|0|0|0 +*|TreasureLevel1||||||5983|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5992|147|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5970|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5997|145|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5978|185|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5962|217|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5989|186|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5926|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Imp|Hellhound|Gargoyle||||6094|154|-22|2|2|10|20|10|1|1|1|2|0|0|0 +*|Eldergazer|Gazer|Gazerlarva||||6122|170|0|2|2|10|20|10|1|1|3|2|0|0|0 +*|Balron|Gargoyle|Gazer||||6086|178|0|2|2|10|20|10|1|1|2|2|0|0|0 +*|Daemon|Gargoyle|Gazer||||6119|219|22|2|2|10|20|10|1|2|2|2|0|0|0 +*|Gargoyle||||||6058|193|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Daemon|Stonegargoyle|||||6033|199|22|2|2|10|20|10|1|2|1|0|0|0|0 +*|Daemon|Gazer|Gazerlarva||||6052|156|0|2|2|10|20|10|1|2|3|2|0|0|0 +*|TreasureLevel2||||||6121|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6124|159|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6087|186|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6060|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6046|199|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6041|222|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6125|221|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6120|229|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6092|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6041|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6033|205|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6058|153|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Daemon|Hellhound|Imp||||6064|96|22|2|2|10|20|10|1|2|1|1|0|0|0 +*|Gargoyle||||||6081|83|21|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6084|66|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6106|67|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Firegargoyle||||||6116|86|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6099|51|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Balron||||||6107|37|22|2|2|10|20|10|1|1|0|0|0|0|0 +*|Gazer|Imp|Stonegargoyle||||6054|45|0|2|2|10|20|10|1|1|1|1|0|0|0 +*|TreasureLevel2||||||6108|66|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||6117|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6058|92|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6113|92|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6107|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6081|44|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6097|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6064|96|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6086|45|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6108|36|22|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Ice.map b/Data/Monsters/uoml/felucca/Ice.map new file mode 100644 index 0000000..a166c8b --- /dev/null +++ b/Data/Monsters/uoml/felucca/Ice.map @@ -0,0 +1,53 @@ +############## +## By Nerun ## +############## +overrideid 2210 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Ice Dungeon +## +## Level 1 +## +*|Arcticogrelord||||||5771|224|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Iceserpent|Snowelemental|Ratman|Frosttroll|Frostspider||5799|188|-6|2|5|10|25|10|1|2|1|1|1|1|0 +*|Frostspider|Frostooze|Icesnake||||5867|218|-4|2|5|10|25|15|1|1|2|1|0|0|0 +*|Ratmanmage||||||5850|219|-3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Arcticogrelord||||||5814|237|0|2|5|7|15|15|1|1|0|0|0|0|0 +*|Whitewyrm||||||5752|144|9|2|2|5|10|10|1|1|0|0|0|0|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5839|159|0|2|5|10|20|15|1|1|1|1|1|1|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5785|161|-6|2|5|10|20|18|1|1|1|1|1|1|0 +*|Iceserpent|Ratman|Snowelemental:Iceelemental|Frosttroll|||5757|213|-7|2|5|10|20|15|1|3|1|4|2|0|0 +*|Iceserpent|Snowelemental:Iceelemental|Frosttroll|Ratman|||5681|191|-6|2|5|10|20|15|1|3|4|1|1|0|0 +*|Iceserpent|Snowelemental:Iceelemental|||||5731|176|-5|2|5|10|35|25|1|9|9|0|0|0|0 +## Treasures +*|TreasureLevel2||||||5848|226|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5683|197|-4|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5721|147|-1|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5758|139|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5754|211|-6|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5833|242|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5854|227|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5772|188|-3|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5837|245|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5751|140|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5763|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5756|203|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5712|145|-34|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5684|181|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ratman Room +## +*|Ratman|Ratmanarcher|Ratmanmage||||5831|358|-1|2|5|10|25|15|1|12|7|5|0|0|0 +*|TreasureLevel2||||||5838|355|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5824|363|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ice Demon Lair +## +*|Icefiend||||||5680|306|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|Icefiend||||||5669|330|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5696|303|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5682|314|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5666|331|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5676|331|0|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Khaldun.map b/Data/Monsters/uoml/felucca/Khaldun.map new file mode 100644 index 0000000..ff6a69b --- /dev/null +++ b/Data/Monsters/uoml/felucca/Khaldun.map @@ -0,0 +1,59 @@ +####################### +## By Requiem ## +## (www.drasnia.com) ## +## Adapted by Nerun ## +####################### +overrideid 2228 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Dungeon Khaldun +## +*|Shadowfiend||||||5569|1306|0|1|1|6|10|5|1|1|0|0|0|0|0 +*|Cursed||||||5539|1301|0|1|1|6|30|20|1|4|0|0|0|0|0 +*|Shadowfiend||||||5525|1296|0|1|1|6|20|20|1|2|0|0|0|0|0 +*|Skeletalknight||||||5492|1294|0|1|1|6|20|10|1|2|0|0|0|0|0 +*|Zombie||||||5492|1297|0|1|2|6|20|10|1|2|0|0|0|0|0 +*|LysanderGathenwale||||||5458|1303|0|1|1|3|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5415|1312|0|1|1|8|20|20|1|1|0|0|0|0|0 +*|Skeletalknight||||||5399|1298|0|1|1|6|20|10|1|1|0|0|0|0|0 +*|MorgBergen||||||5398|1299|0|1|1|6|20|10|1|1|0|0|0|0|0 +*|Boneknight||||||5412|1330|0|1|1|6|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5415|1331|0|1|1|6|20|20|1|1|0|0|0|0|0 +*|Skeleton||||||5403|1332|0|1|1|6|20|20|1|2|0|0|0|0|0 +*|TavaraSewel||||||5420|1355|0|1|1|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5422|1355|0|1|1|6|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5435|1346|0|1|2|8|10|10|1|1|0|0|0|0|0 +*|Zombie||||||5396|1371|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Cursed||||||5395|1370|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5393|1369|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Khaldunzealot||||||5400|1397|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Skeletalknight||||||5444|1410|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5442|1411|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Khaldunsummoner||||||5400|1428|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5402|1430|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Shadowfiend||||||5404|1431|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Zombie||||||5425|1451|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Skeleton||||||5418|1450|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Bonemagi||||||5425|1484|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Shadowfiend||||||5430|1485|0|1|2|8|30|30|1|3|0|0|0|0|0 +*|Skeleton||||||5433|1485|0|1|2|8|20|20|1|2|0|0|0|0|0 +*|Ancientlich||||||5458|1445|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Khaldunsummoner||||||5459|1449|0|1|2|8|30|30|1|1|0|0|0|0|0 +*|Khaldunzealot||||||5460|1451|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Skeletalmage||||||5465|1449|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5483|1446|0|1|2|8|30|30|1|2|0|0|0|0|0 +*|Zombie||||||5485|1434|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5499|1411|0|1|2|8|30|30|1|2|0|0|0|0|0 +*|Spectralarmour||||||5475|1402|0|1|2|8|30|30|1|2|0|0|0|0|0 +*|Skeleton||||||5491|1370|0|1|2|8|20|20|1|3|0|0|0|0|0 +*|Spectralarmour||||||5490|1367|0|1|2|8|20|20|1|1|0|0|0|0|0 +*|Shadowfiend||||||5521|1397|0|1|2|8|10|10|1|1|0|0|0|0|0 +*|HarrowerTentacles||||||5605|1343|0|1|30|55|20|1|1|1|0|0|0|0|0 +*|Khaldunsummoner||||||5536|1351|0|1|2|8|20|10|1|1|0|0|0|0|0 +*|Khaldunzealot||||||5536|1345|0|1|2|8|20|10|1|1|0|0|0|0|0 +*|Cursed||||||5549|1324|0|1|2|8|30|30|1|3|0|0|0|0|0 +*|Ancientlich||||||5549|1332|0|1|2|10|30|10|1|1|0|0|0|0|0 +*|Cursed||||||5505|1316|0|1|2|8|20|20|1|3|0|0|0|0|0 +*|GrimmochDrummel||||||5452|1366|0|1|2|8|10|5|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/LostLands.map b/Data/Monsters/uoml/felucca/LostLands.map new file mode 100644 index 0000000..f667bd0 --- /dev/null +++ b/Data/Monsters/uoml/felucca/LostLands.map @@ -0,0 +1,341 @@ +############## +## By Nerun ## +############## +overrideid 2211 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## T2A - Lost Lands +## +## Papua +## +*|Swampdragon||||||5728|3209|-3|2|5|10|100|100|1|7|0|0|0|0|0 +## +## T2ADesertMain +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5457|2651|45|2|5|10|150|150|1|15|15|6|9|6|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5457|2651|45|2|5|10|150|150|1|3|6|4|6|0|0 +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5520|2890|33|2|5|10|100|100|1|10|10|4|6|4|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5520|2890|33|2|5|10|100|100|1|3|4|2|4|0|0 +## +## T2ADesCent +## +*|Gazer|Reaper|Scorpion|Giantserpent|Troll||5580|2885|6|2|5|10|15|15|1|3|2|3|2|2|0 +## +## T2ADryCenter +## +*|Corpser|Giantspider|Troll|Harpy|Ettin|Gazer|5557|2625|0|2|5|10|40|40|1|3|3|3|6|3|3 +## +## T2ACyclop +## +*|Cyclops|Titan|||||5394|2530|6|2|5|10|25|15|1|5|3|0|0|0|0 +## +## T2ADesertFinal +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Wyvern|5711|2494|46|2|5|10|80|80|1|3|3|1|3|2|1 +*|Ettin||||||5711|2494|46|2|5|10|80|80|1|2|0|0|0|0|0 +## +## T2ABaseOph +## +*|Ophidianarchmage|Ophidianmage|Ophidianmatriarch|Ophidianknight|Ophidianwarrior||5765|2637|39|2|5|10|30|25|1|3|6|3|4|10|0 +## +## T2AWyvern +## +*|Wyvern|Drake|Imp|Mongbat|||5697|2626|-2|2|5|10|30|25|1|2|4|1|2|0|0 +## +## T2ASmallDesert +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5729|2767|-1|2|5|10|70|60|1|8|8|3|5|3|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5729|2767|-1|2|5|10|70|60|1|3|3|3|5|0|0 +## +## T2ALava +## +*|Hellhound|Lavalizard|Fireelemental|Efreet|Hellcat|Lavaserpent|5724|2949|31|2|5|10|75|65|1|8|8|10|4|6|8 +*|Lavasnake||||||5724|2949|31|2|5|10|75|65|1|15|0|0|0|0|0 +## +## T2AWyvIsle +## +*|Wyvern||||||5863|2470|46|2|5|10|25|25|1|6|0|0|0|0|0 +## +## T2AIce1 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5501|2361|27|2|5|10|75|40|1|4|8|4|4|5|5 +*|Polarbear||||||5501|2361|27|2|5|10|75|40|1|5|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5351|2359|0|2|5|10|75|40|1|4|7|4|4|5|5 +*|Polarbear||||||5351|2359|0|2|5|10|75|40|1|5|0|0|0|0|0 +## +## T2AIce2 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5173|2368|21|2|5|10|50|30|1|4|10|4|4|3|3 +*|Polarbear||||||5173|2368|21|2|5|10|50|30|1|3|0|0|0|0|0 +## +## T2ALastIceIsle +## +*|Iceserpent|Icesnake|Snowelemental|Whitewolf|Walrus|Polarbear|6091|2379|25|2|5|10|60|30|1|6|10|3|3|3|3 +## +## T2AIceFinal +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5967|2370|44|2|5|10|75|50|1|6|4|4|4|4|4 +*|Polarbear||||||5967|2370|44|2|5|10|75|50|1|4|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5817|2367|42|2|5|10|75|50|1|6|3|3|3|4|4 +*|Polarbear||||||5817|2367|42|2|5|10|75|50|1|4|0|0|0|0|0 +## +## T2AFor3 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5756|3453|-2|2|5|10|130|130|1|10|10|10|2|10|0 +## +## T2ASwamp +## +*|Gianttoad|Swampdragon|Giantrat|Alligator|Sewerrat|Plaguebeast|5985|3441|17|2|5|10|90|80|1|8|5|12|12|11|2 +*|Bullfrog|Swamptentacle|Bogling|Bogthing|||5985|3441|17|2|5|10|90|80|1|15|5|13|3|0|0 +## +## T2AUndead +## +*|Boneknight|Skeletalknight|Bonemagi|Skeleton|Wraith|Ghoul|5220|3664|-1|2|5|10|25|20|1|3|3|3|6|4|4 +## +## T2ASavage +## +*|Savagerider|Savage|Savageshaman||||5212|3619|0|2|5|10|15|10|1|3|9|3|0|0|0 +## +## T2ADeer +## +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5347|3449|17|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5243|3548|14|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5250|3449|16|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5349|3547|-1|2|5|10|50|50|1|4|8|4|4|16|4 +## +## T2AWild1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5201|3162|53|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5201|3162|53|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5251|3301|-2|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5251|3301|-2|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5250|3401|1|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5250|3401|1|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5351|3401|30|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5351|3401|30|2|5|10|50|50|1|2|2|2|0|0|0 +## +## T2AWild1&2 - 1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6018|3673|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6018|3673|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6018|3673|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6018|3673|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 2 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3773|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3773|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3773|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3773|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 3 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|2874|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|2874|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|2874|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|2874|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 4 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3971|17|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3971|17|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3971|17|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3971|17|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 5 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5920|3675|12|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5920|3675|12|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5920|3675|12|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5920|3675|12|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 6 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5921|3777|28|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5921|3777|28|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5921|3777|28|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5921|3777|28|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 7 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5919|3875|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5919|3875|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5919|3875|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5919|3875|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 8 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5918|3975|1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5918|3975|1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5918|3975|1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5918|3975|1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 9 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3675|0|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3675|0|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3675|0|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3675|0|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 10 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3775|48|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3775|48|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3775|48|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3775|48|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 11 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5818|3876|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5818|3876|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5818|3876|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5818|3876|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 12 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5819|3974|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5819|3974|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5819|3974|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5819|3974|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 13 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3675|22|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3675|22|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3675|22|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3675|22|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 14 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5722|3776|32|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5722|3776|32|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5722|3776|32|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5722|3776|32|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 15 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3876|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3876|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 16 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3975|21|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3975|21|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3975|21|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3975|21|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 17 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3676|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3676|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 18 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5621|3775|2|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5621|3775|2|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5621|3775|2|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5621|3775|2|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 19 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3875|15|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3875|15|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3875|15|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3875|15|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 20 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5624|3975|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5624|3975|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 21 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5523|3676|45|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5523|3676|45|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5523|3676|45|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5523|3676|45|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 22 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3775|8|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3775|8|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3775|8|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3775|8|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 23 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3875|-1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3875|-1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 24 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5478|3587|3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5478|3587|3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5478|3587|3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5478|3587|3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild3 +## +*|Forestostard|Ridablellama|||||5520|3939|42|2|5|10|25|25|1|3|3|0|0|0|0 +## +## T2AFrenz +## +*|Frenziedostard||||||5784|3951|20|2|5|10|35|35|1|8|0|0|0|0|0 +## +## T2ASpawner1 +## +*|Imp|Mongbat|||||5764|2585|-4|2|5|10|75|2|1|2|5|0|0|0|0 +*|Imp|Harpy|Headlessone|Scorpion|Stoneharpy|Wyvern|5838|2651|0|2|5|10|75|2|1|1|1|1|1|1|1 +## +## T2ASpawner2 +## +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5218|3786|1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5218|3786|1|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5371|3820|-2|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5371|3820|-2|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5368|3887|0|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5368|3887|0|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5367|4003|19|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5367|4003|19|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5466|4005|-1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5466|4005|-1|2|5|10|50|50|1|4|1|0|0|0|0 +## +## T2ABull +## +*|Bull|Greathart|Cow||||5194|3885|-1|2|5|10|45|32|1|10|6|6|0|0|0 +*|Bull|Greathart|Cow||||5200|3895|2|2|5|10|20|10|1|2|2|2|0|0|0 +## +## T2ASheep +## +*|Sheep|Goat|Bull|Chicken|||5159|3913|1|2|2|5|10|15|10|7|1|1|1|1|0|0 +## +## T2AFor1 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5570|3153|14|2|5|10|80|60|1|6|6|6|1|6|0 +## +## T2AFor2 +## +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5440|3292|-4|2|5|10|62|56|1|5|5|5|5|1|0 +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5566|3292|4|2|5|10|62|56|1|5|5|5|5|1|0 +## +## T2ATera1 +## +*|Terathanmatriarch|Terathanavenger|Terathandrone|Terathanwarrior|||5454|3136|-60|2|5|10|25|25|1|2|4|10|10|0|0 +## +## T2Aopp +## +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5490|3071|15|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5467|3078|-3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5446|3074|3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5432|3079|-4|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5408|3077|16|2|5|10|25|5|1|1|1|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/OrcCaves.map b/Data/Monsters/uoml/felucca/OrcCaves.map new file mode 100644 index 0000000..c4efd75 --- /dev/null +++ b/Data/Monsters/uoml/felucca/OrcCaves.map @@ -0,0 +1,38 @@ +############## +## By Nerun ## +############## +overrideid 2212 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Britain +## Orc Caves +## +## Cave 1 +## +*|Orc|Orccaptain|Orcishlord||||5146|1995|0|2|5|15|8|8|1|1|1|1|0|0|0 +*|Orc||||||5153|1971|0|2|5|15|8|8|1|5|0|0|0|0|0 +*|Direwolf||||||5153|1961|0|2|5|15|8|8|1|2|0|0|0|0|0 +*|Orcishlord||||||5144|1960|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain||||||5141|1968|0|2|5|15|8|8|1|3|0|0|0|0|0 +## +## Cave 2 +## +*|Orc||||||5332|1365|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Noble||||||5308|1372|0|2|5|15|8|8|1|1|0|0|0|0|0 +*|Orcishlord|Orc|||||5302|1355|0|2|5|15|12|8|1|1|3|0|0|0|0 +*|Giantrat||||||5316|1332|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Direwolf||||||5331|1346|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain|Orcishlord|Orcishmage|Orcbomber|||5354|1332|0|2|5|15|8|8|1|1|1|1|1|0|0 +*|Orcbomber|Orccaptain|Orc||||5356|1304|0|2|5|15|10|8|1|1|1|2|0|0|0 +*|Orcishlord|Orcishmage|Orcbomber|Orc|||5317|1309|0|2|5|15|8|8|1|1|2|1|2|0|0 +*|Orc|Orcishmage|Orcishlord||||5300|1314|0|2|5|15|10|8|1|3|1|2|0|0|0 +*|Corpser||||||5292|1316|0|2|5|15|8|8|1|2|0|0|0|0|0 +## +## Cave 3 +## +*|Orc||||||5281|2029|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orcbrute|Orc|||||5308|2005|0|2|5|15|12|12|1|1|4|0|0|0|0 +*|Orcbomber|Orc|||||5310|1969|0|2|5|15|12|12|1|2|2|0|0|0|0 +*|Orcbomber|Earthelemental|||||5348|2011|0|2|5|15|15|10|1|1|4|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Outdoors.map b/Data/Monsters/uoml/felucca/Outdoors.map new file mode 100644 index 0000000..974f337 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Outdoors.map @@ -0,0 +1,513 @@ +############## +## By Nerun ## +############## +overrideid 2213 +overridemap 1 +overridemintime 60 +overridemaxtime 60 +## +## OSI Light +## +*|hordeminion||||||3619|2814|21|2|5|10|50|50|1|17|0|0|0|0|0 +*|mongbat||||||3619|2814|21|2|5|10|50|50|1|17|0|0|0|0|0 +*|lizardman:ratman||||||1147|3524|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1266|1982|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1249|2030|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1232|2093|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1140|2087|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1089|2033|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1067|2117|5|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:harpy:ogre:troll||||||666|1825|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||741|1838|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||733|1937|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||798|1935|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||819|1841|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||893|1861|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||879|1956|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:ogre||||||809|1615|0|2|60|80|30|30|1|6|0|0|0|0|0 +*|orcishmage||||||4461|3106|0|2|60|80|30|30|1|5|0|0|0|0|0 +*|orc||||||4729|3485|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4519|3097|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4613|3272|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4576|3356|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4658|3376|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4607|3480|29|2|60|80|30|30|1|10|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3485|2595|12|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3446|2741|49|2|60|80|50|50|1|7|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3459|2655|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3379|2693|35|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3411|2592|44|2|60|80|40|40|1|6|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3464|2503|49|2|60|80|50|50|1|7|0|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3168|629|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3172|700|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3173|771|0|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1473|229|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1337|293|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1184|217|27|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1284|433|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1203|502|30|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1300|607|15|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1200|633|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1162|704|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1130|830|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1013|980|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||848|917|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||840|1063|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1038|1149|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||844|1235|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||617|1326|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1831|449|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1832|517|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1749|474|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1636|532|22|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1743|589|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1887|591|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1810|647|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1631|650|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1723|683|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|earthelemental:ratman||||||1980|832|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1905|883|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1849|953|7|2|60|80|30|30|1|4|0|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||1001|787|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||987|725|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|gargoyle:gazer||||||1912|1283|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1787|1280|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1799|1394|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1652|1400|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1755|1474|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|troll||||||1325|1071|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2369|3430|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2354|3503|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2503|3593|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2520|3983|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2438|3914|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2143|3953|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|airelemental:gargoyle||||||868|488|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||805|483|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||839|406|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||841|344|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|lizardman:ratman||||||1131|3415|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1158|3457|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1094|3482|0|2|60|80|30|30|1|8|0|0|0|0|0 +############## +## By Nerun ## +############## +overridemintime 20 +overridemaxtime 20 +## +## OSI Medium +## +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1312|613|10|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1214|617|13|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|522|19|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1226|449|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1276|431|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1231|192|6|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1143|180|14|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1191|288|11|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1295|328|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|275|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1491|238|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3440|405|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|375|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3327|344|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3434|316|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|280|9|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3322|271|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3360|218|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3390|259|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3446|213|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3462|136|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2589|204|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|136|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2659|147|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2621|99|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|86|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2478|100|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2468|144|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2485|191|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2454|248|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2533|240|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|airelemental:ettin:orc||||||2077|434|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2107|358|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2138|323|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2189|298|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2137|271|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2113|221|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2146|178|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2093|147|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2109|109|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2115|48|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1996|73|8|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1956|48|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1944|102|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:troll||||||2034|46|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2033|74|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2058|87|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2034|108|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2000|141|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1965|160|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1946|186|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1922|173|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1894|197|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1908|214|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1891|226|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1869|265|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1626|266|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1682|252|6|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1723|252|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1759|259|21|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1804|247|0|2|20|30|30|30|1|2|11|0|0|0|0 +*|giantspider:scorpion||||||1875|906|7|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1829|874|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1852|841|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1930|864|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1883|827|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1949|824|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1987|822|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||2013|839|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1979|885|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1947|912|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1915|928|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1866|938|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1838|957|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1802|1506|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1692|1463|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1833|1245|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1726|1362|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1640|1431|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1912|1302|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1967|1296|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1898|1265|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1872|1347|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1812|1314|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1797|1393|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1862|1434|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1877|1515|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1361|1392|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1445|1365|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1375|1330|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1474|1297|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1407|1281|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1225|1477|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1222|1418|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1244|1374|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1180|1354|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1240|1317|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1340|1268|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1305|1326|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1304|1413|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1300|1481|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1541|1895|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1534|1941|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1475|1958|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1435|1917|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1383|1949|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1416|1992|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1504|2007|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1447|2038|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1479|2094|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1525|2053|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2095|2352|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2077|2305|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2021|2313|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1968|2346|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1947|2294|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1915|2385|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1891|2331|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1890|2270|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1873|2426|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1837|2334|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1826|2250|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2109|2989|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2089|3017|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2074|3069|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2033|3041|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1970|3052|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1915|3050|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1866|3040|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1812|3036|5|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1841|3000|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1803|2981|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1867|2962|7|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1849|2915|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1911|2934|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1954|2903|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||851|495|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||805|463|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||837|361|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1029|1969|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1080|1963|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1042|1920|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||821|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||736|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||899|1851|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||759|1828|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||672|1825|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||892|1963|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|giantspider:orc:ratman:spectre:zombie||||||815|1603|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1055|1442|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1021|1415|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1060|1375|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1004|1369|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1037|1325|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||971|1308|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||1000|330|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||964|365|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||947|418|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||956|452|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||423|1595|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||418|1665|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||480|1641|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||516|1585|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||541|1645|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||141|1367|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||189|1344|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||232|1350|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||278|1355|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||229|1419|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||182|1428|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||157|1487|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||204|1483|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||240|1443|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||269|1474|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4013|239|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3929|235|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3920|287|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4090|325|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4162|395|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4206|471|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3928|393|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3963|508|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4066|569|0|2|20|30|80|80|1|8|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4153|601|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4214|655|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4264|725|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2963|3617|3|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2966|3591|11|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3013|3591|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3024|3566|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3042|3590|5|2|20|30|30|30|1|7|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2462|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2428|722|8|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2375|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2345|676|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2429|690|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2379|654|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2326|656|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2319|591|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||659|1318|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||579|1305|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||728|1242|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||793|1088|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||849|1262|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||909|1175|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||974|1186|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1059|1166|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||823|960|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||960|910|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1042|1024|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1147|1048|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1097|970|2|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1192|958|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1166|818|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1083|783|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1268|774|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1180|737|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1122|718|1|2|20|30|30|30|1|11|1|0|0|0|0 +############## +## By Nerun ## +############## +overridemintime 5 +overridemaxtime 10 +## +## OSI Heavy + Miscellaneous +## +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||423|1595|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||418|1665|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||480|1641|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||516|1585|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||541|1645|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4504|1458|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4494|1426|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1434|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4456|1405|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1358|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|greathart|hind|||||4550|1409|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4552|1447|10|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4615|1469|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4612|1418|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4605|1365|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4566|1359|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2372|210|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2355|179|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2351|148|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2345|112|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2328|67|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2177|3034|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2143|3068|20|2|5|10|30|30|1|7|0|0|0|0|0 +## +## Northeast Britain +## +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1983|1517|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1986|1463|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1969|1409|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|mongbat|orc|||||1912|1302|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1967|1296|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1898|1265|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1872|1347|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1812|1314|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1797|1393|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1862|1434|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1877|1515|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1802|1506|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1692|1463|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1833|1245|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1726|1362|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1640|1431|0|2|5|10|30|30|1|3|2|0|0|0|0 +## +## Orc Cave Entrance +## +*|orc:ratman||||||1055|1442|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1021|1415|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1060|1375|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1004|1369|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1037|1325|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||971|1308|0|2|5|10|30|30|1|6|0|0|0|0|0 +## +## Orc Fort (South Cove) +## +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2171|1356|0|2|5|10|30|30|1|1|3|2|5|3|2 +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2184|1376|0|2|5|10|30|15|1|1|3|2|5|3|2 +*|TreasureLevel2|TreasureLevel3|||||2155|1370|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2203|1379|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## The Bog of Desolation (West Covetous) +## +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2038|1023|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2079|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2067|989|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2028|987|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2033|936|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1990|976|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1993|1030|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2035|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2023|1052|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2069|1028|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2048|1066|0|2|5|10|30|30|1|3|1|3|0|0|0 +## +## East Skara Brae +## +*|orc|ettin|ratman|giantspider|reaper||1435|2261|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1651|2413|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1619|2725|10|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1427|2525|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1059|2461|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1243|2437|5|2|5|10|150|150|1|10|10|10|10|10|0 +## +## East Skara Brae: Hedge Maze +## +*|Daemon||||||1145|2231|20|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1072|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1070|2256|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1215|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1216|2259|5|2|5|10|30|20|1|4|0|0|0|0|0 +## +## South Destard / Trinsic +## +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1595|3045|0|2|5|10|100|60|1|5|5|5|5|5|5 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|2091|3413|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1931|3205|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1827|3429|10|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1635|3253|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1387|3109|0|2|5|10|150|150|1|10|10|10|10|10|10 +## +## Main Destard Orcs +## +*|Headlessone|Orc|Orccaptain|Orcishlord|Orcishmage||1110|2672|0|2|5|10|20|20|1|3|6|1|2|1|0 +## +## The Destard Swamps +## +*|Toxicelemental:Alligator:Bogthing:Bogling:Corpser:GiantRat:Giantserpent|Lizardman:strongmongbat:Plaguebeast:Plaguespawn:Ratman:Sewerrat:Snake|Wisp||||1158|2872|0|2|5|10|130|130|1|24|23|3|0|0|0 +*|Savage|Savagerider|Savageshaman||||1141|2959|0|2|5|10|20|20|1|2|1|1|0|0|0 +*|Savage|Savagerider|Savageshaman||||1166|2958|0|2|5|10|20|20|1|2|1|1|0|0|0 +## +## Yew-Britain Brigand Camp +## +*|Brigand||||||854|1686|0|2|1|10|20|15|1|7|0|0|0|0|0 +## +## Yew Liches +## +*|Lich||||||757|1401|0|2|1|10|30|30|1|8|0|0|0|0|0 +## +## Yew Orc Fort +## +*|Orc|Orcishlord|Orcishmage||||634|1504|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcishlord|Orcishmage||||634|1462|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcbomber|Orccaptain|Orcishlord|Orcishmage||633|1484|0|2|1|10|20|10|1|8|1|1|2|2|0 +## +## Yew Fort of the Damned +## +*|Skeleton||||||965|757|0|2|5|10|10|5|1|2|0|0|0|0|0 +*|Wraith:Shade:Spectre|Ghoul|||||955|707|0|2|5|10|12|8|1|4|4|0|0|0|0 +*|Wraith:Shade:Spectre||||||962|692|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Wraith:Shade:Spectre||||||948|703|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Lich||||||1016|821|0|2|5|10|10|2|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||1015|706|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||1017|826|0|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Hythloth Fire Pit +## +*|Daemon|Drake|||||4596|3607|30|2|5|10|50|25|1|1|2|0|0|0|0 +*|Dragon|Drake|||||4571|3572|31|2|1|10|50|25|1|1|2|0|0|0|0 +*|Daemon||||||4595|3574|75|2|1|10|50|25|1|3|0|0|0|0|0 +*|Dragon|Drake|||||4618|3570|30|2|1|10|50|25|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||4595|3570|30|2|1|2|8|8|1|3|3|0|0|0|0 +## +## Near Shame: The Wisp Circle +## +*|Wisp||||||608|1702|0|2|5|10|30|30|1|8|0|0|0|0|0 +## +## Moonglow Zoo +## +*|Ghoul|Giantrat|Giantserpent|Headlessone|Jwilson||4530|1387|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Iceserpent|Icesnake|Polarbear|Snowleopard|Whitewolf|Frostooze|4511|1394|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Frostspider|Frosttroll|||||4511|1394|23|2|5|10|10|4|1|1|4|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Rabbit:JackRabbit|Cougar:Panther|Bird:Eagle||4498|1394|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Corpser|Swamptentacle|||4485|1387|23|2|5|10|15|4|1|2|3|1|1|0|0 +*|Giantserpent|Giantspider|Boar|Greathart|Hind|Llama|4493|1364|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Horse|Rat|||||4493|1364|23|2|5|10|10|4|1|1|1|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Cougar:Panther|Giantserpent|Greathart||4506|1358|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Gorilla|Giantserpent|Gianttoad||4519|1358|23|2|5|10|15|4|1|1|1|1|1|1|0 +*|Mummy|Ophidianwarrior|Scorpion|Giantserpent|||4531|1363|23|2|5|10|15|4|1|1|1|1|1|0|0 +*|Rottingcorpse|Skeleton|Slime|Snake|Strongmongbat||4512|1372|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Ghoul|Giantserpent|Headlessone|Jwilson|Zombie||4512|1380|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Cat|Chicken|Dog|Pig|Sheep||4500|1382|23|2|5|10|10|1|1|1|1|1|1|1|0 +############## +## By Nerun ## +############## +overridemintime 45 +overridemaxtime 60 +## +## Camps +## +*|Orccamp:Ratcamp||||||821|675|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1042|1394|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2540|130|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3170|672|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2548|1173|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3602|2815|28|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||4480|1439|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1152|3471|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1530|999|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1871|1076|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||788|1894|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1064|2488|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2103|3371|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2044|2323|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1939|1310|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2349|722|0|2|45|60|10|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/PaintedCaves.map b/Data/Monsters/uoml/felucca/PaintedCaves.map new file mode 100644 index 0000000..b37fbb9 --- /dev/null +++ b/Data/Monsters/uoml/felucca/PaintedCaves.map @@ -0,0 +1,13 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2214 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Painted Caves +## +*|cat:dog:rat|cat|dog|rat|||6279|879|-1|1|5|10|30|30|1|6|1|1|1|0|0 +*|troglodyte|grobu|lurg|giantrat|||6275|879|-2|1|5|10|30|30|1|3|3|3|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/PalaceOfParoxysmus.map b/Data/Monsters/uoml/felucca/PalaceOfParoxysmus.map new file mode 100644 index 0000000..56600c1 --- /dev/null +++ b/Data/Monsters/uoml/felucca/PalaceOfParoxysmus.map @@ -0,0 +1,25 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2215 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Palace of Paroxysmus +## +*|daemon:succubus|InterredGrizzle:poisonelemental|plaguebeast:plaguespawn|corrosiveslime|putrifier|plaguebeastlord|6295|616|-50|1|5|10|50|50|1|6|6|6|3|3|3 +*|InterredGrizzle|corrosiveslime|poisonelemental|balron:succubus:daemon|plaguebeastlord:plaguebeast:plaguespawn||6384|580|-50|1|5|10|30|30|1|4|4|3|9|11|0 +*|poisonelemental||||||6328|517|-50|1|5|10|10|10|1|4|0|0|0|0|0 +*|plaguebeast:corrosiveslime|poisonelemental:plaguespawn|||||6354|455|-40|1|5|10|20|20|1|5|5|0|0|0|0 +*|plaguebeast:plaguespawn|toxicelemental:corrosiveslime|||||6416|447|-40|1|5|10|20|20|1|8|7|0|0|0|0 +*|balron:succubus:daemon|corrosiveslime|plaguebeastlord:plaguebeast:plaguespawn|InterredGrizzle:poisonelemental|||6466|543|-50|1|5|10|30|30|1|6|3|8|5|0|0 +*|chaosdaemon:moloch|succubus:daemon|balron||||6292|462|-50|1|5|10|40|40|1|7|7|4|0|0|0 +*|earthelemental:corrosiveslime||||||6298|395|60|1|5|10|8|8|1|2|0|0|0|0|0 +*|toxicelemental:plaguespawn|toxicelemental|plaguespawn||||6404|378|-40|1|5|10|18|18|1|2|1|1|0|0|0 +*|plaguespawn:plaguebeast:toxicelemental:corrosiveslime:poisonelemental|plaguespawn|plaguebeast|toxicelemental|corrosiveslime|poisonelemental|6418|358|-40|1|5|10|25|25|1|12|2|2|2|2|2 +*|earthelemental:corrosiveslime:toxicelemental:plaguespawn|earthelemental|corrosiveslime|toxicelemental|plaguespawn||6319|348|60|1|5|10|20|20|1|5|1|1|1|1|0 +*|toxicelemental:earthelemental:corrosiveslime|toxicelemental|earthelemental|corrosiveslime|||6249|352|60|1|5|10|15|15|1|6|1|1|1|0|0 +*|poisonelemental||||||6285|353|60|1|5|10|5|5|1|1|0|0|0|0|0 +*|earthelemental:corrosiveslime||||||6353|400|60|1|5|10|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/PrismOfLight.map b/Data/Monsters/uoml/felucca/PrismOfLight.map new file mode 100644 index 0000000..7bf7cab --- /dev/null +++ b/Data/Monsters/uoml/felucca/PrismOfLight.map @@ -0,0 +1,32 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2216 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Prism of Light +## +*|CrystalLatticeSeeker||||||6553|157|0|1|5|10|8|8|1|3|0|0|0|0|0 +*|Rat:Icesnake||||||6474|74|-34|1|5|10|4|4|1|9|0|0|0|0|0 +*|wisp:CrystalWisp:treasurelevel2|treasurelevel2|||||6552|155|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|wisp||||||6521|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|wisp||||||6530|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalSeaSerpent||||||6576|91|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|UnfrozenMummy||||||6509|176|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalDaemon||||||6536|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalDaemon||||||6547|91|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalHydra||||||6572|89|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|treasurelevel4||||||6504|181|0|1|5|10|1|1|1|1|0|0|0|0|0 +*|ShadowWisp||||||6475|101|-44|1|5|10|5|5|1|5|0|0|0|0|0 +*|wisp:Crystalwisp||||||6478|174|4|1|5|10|10|10|1|6|0|0|0|0|0 +*|Crystalvortex:iceelemental||||||6566|120|0|1|5|10|15|15|1|7|0|0|0|0|0 +*|CrystalWisp||||||6534|178|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalWisp:CrystalLatticeSeeker:treasurelevel2|treasurelevel2|||||6535|179|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|treasurelevel3||||||6502|120|-10|1|5|10|0|0|1|1|0|0|0|0|0 +*|protector||||||6507|151|0|1|5|10|5|5|1|3|0|0|0|0|0 +*|CrystalDaemon||||||6532|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|Ferret||||||6578|183|31|1|5|10|5|5|1|2|0|0|0|0|0 +*|protector||||||6510|171|0|1|5|10|8|8|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Reagents.map b/Data/Monsters/uoml/felucca/Reagents.map new file mode 100644 index 0000000..f5f0a18 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Reagents.map @@ -0,0 +1,70 @@ +############## +## By Nerun ## +############## +overrideid 2229 +overridemap 1 +overridemintime 11 +overridemaxtime 23 +## +## Felucca Reagents +## +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2854|816|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4590|1448|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2490|1096|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1566|1140|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1514|1584|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1938|1408|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2374|652|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2054|516|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1286|504|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||746|636|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1134|964|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||718|1180|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||342|1464|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||702|1752|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1114|1416|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1150|1876|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1582|2028|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1934|2328|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1490|2472|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1070|2320|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1466|3032|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2062|964|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1846|3260|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1078|2772|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4710|3796|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5926|3888|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5474|3904|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5934|3436|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5462|3452|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5674|3120|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5618|2744|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5326|2492|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5966|2456|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5234|3068|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||6042|2916|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3602|2948|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3538|2536|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2734|2168|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3714|2152|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3674|1216|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3994|328|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4166|584|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3198|504|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2750|368|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1694|688|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||366|900|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||642|2216|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2226|3532|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1850|2796|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1658|236|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4426|1028|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2522|84|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3130|116|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2082|60|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2930|3476|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1410|3796|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1122|3524|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2474|3956|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4570|3340|0|1|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4282|3700|0|1|11|23|200|200|1|160|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Sanctuary.map b/Data/Monsters/uoml/felucca/Sanctuary.map new file mode 100644 index 0000000..ea2c1d8 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Sanctuary.map @@ -0,0 +1,19 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2217 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Sanctuary +## +*|chicken:bird|dog|cat|cow:bull|pig|boar|6263|118|-10|1|5|10|20|20|1|6|3|3|6|3|3 +*|ratman:ratmanarcher:chiikkaha:titan:cyclops:rat|ratman:ratmanarcher|chiikkaha|titan|cyclops|rat|6349|89|-20|1|5|10|70|70|1|18|4|2|2|2|2 +*|ratman:ratmanarcher:ratmanmage:changeling:doppleganger|dog:chicken:cat:boar:bird|gargoyle|titan|cyclops|orcishmage:orcscout|6168|117|0|1|5|10|30|30|1|11|9|3|3|3|5 +*|ogrelord:orcishlord:ratman|bird:cow:bull:pig:chicken|||||6189|71|0|1|5|10|25|25|1|8|4|0|0|0|0 +*|titan:ettin:doppleganger:mougguur|dog:chicken:rat:cow:bull|orcbomber:orcbrute:orc|snake:gargoyle:ogre|||6187|101|0|1|5|10|25|25|1|10|10|7|7|0|0 +*|bird:chicken:rat:dog|doppleganger|||||6184|29|0|1|5|10|10|10|1|6|3|0|0|0|0 +*|szavetra:imp:titan:snake:ratman:doppleganger:gargoyle|cow:bull:chicken:bird:pig:dog:goat:cat:rat|orc:orccaptain:orcishmage|ogre:ogre:ogrelord|||6265|48|-10|1|5|10|30|30|1|22|18|9|4|0|0 +*|changeling:ratman:ettin:titan:ratmanarcher:ratmanmage|goat:pig:cow:bull:rat|gargoyleenforcer:gargoyledestroyer:gargoyle|snake|||6191|155|0|1|5|10|25|25|1|18|12|9|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/SeaLife.map b/Data/Monsters/uoml/felucca/SeaLife.map new file mode 100644 index 0000000..15ebd74 --- /dev/null +++ b/Data/Monsters/uoml/felucca/SeaLife.map @@ -0,0 +1,124 @@ +############## +## By Nerun ## +############## +overrideid 2218 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1395|3421|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4888|375|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4352|215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3688|439|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4512|583|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|1127|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3576|823|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4016|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3992|1447|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4232|1655|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4600|1751|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|1519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3616|1807|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4032|2039|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4624|2199|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4400|2527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3984|2423|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|2119|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4912|2471|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4864|2831|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4536|2847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|3215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4192|2975|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4008|2767|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3328|2063|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3176|2383|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3088|2759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3888|3167|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4152|3415|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3968|3895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3240|3151|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3776|3519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3344|3479|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2792|2951|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2608|3295|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2744|2567|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2368|2799|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3560|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3168|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2768|3847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1720|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||544|3719|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||896|3695|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||824|3287|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||176|3551|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||480|3351|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||512|2919|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||192|2895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||208|2503|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||840|2863|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||600|2511|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|2103|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||168|1743|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|559|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||184|191|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||592|223|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2400|2399|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3008|1895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2392|2031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2624|1775|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3408|1407|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3256|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2952|1239|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2752|1455|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2208|1703|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1866|1798|-5|2|5|10|175|175|1|15|6|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||931|141|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3267|1717|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2395|1405|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||139|1173|-5|2|5|10|130|130|1|13|4|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3123|1485|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3811|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3931|1757|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2931|3245|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2291|3181|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||979|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||147|3213|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1891|3597|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2971|1605|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1580|75|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4275|1309|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4667|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||5003|101|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3603|125|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4112|791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3891|733|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3672|1535|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4363|1981|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4995|1829|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4283|2221|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2008|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2320|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4955|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4731|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4307|3965|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2227|3533|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1187|3885|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||731|3989|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||491|4013|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||107|909|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1792|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1336|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4048|63|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4392|823|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3520|2263|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3568|3215|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4992|3791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4984|3567|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2072|2527|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2040|3751|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2288|3767|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|1879|-5|2|5|10|100|100|1|10|2|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Shame.map b/Data/Monsters/uoml/felucca/Shame.map new file mode 100644 index 0000000..496cddb --- /dev/null +++ b/Data/Monsters/uoml/felucca/Shame.map @@ -0,0 +1,135 @@ +############## +## By Nerun ## +############## +overrideid 2219 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Shame Dungeon +## +## Level 1 +## +*|Earthelemental|Scorpion|||||5404|93|10|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5425|58|10|2|5|10|30|30|1|7|3|0|0|0|0 +*|Earthelemental|Scorpion|||||5387|41|20|2|2|10|30|30|1|4|1|0|0|0|0 +*|Earthelemental||||||5394|11|30|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental||||||5474|20|0|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental|Scorpion|||||5477|67|20|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5468|109|35|2|2|10|30|30|1|6|20|0|0|0|0 +*|TreasureLevel1||||||5423|112|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5468|106|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5434|100|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5492|56|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5416|59|-15|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5400|45|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5448|33|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5437|11|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5399|11|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5421|117|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5468|100|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5392|10|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5445|12|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5404|43|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5443|36|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5402|58|-20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5493|51|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5434|89|20|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Airelemental||||||5575|16|10|2|2|10|30|15|1|3|0|0|0|0|0 +*|Dullcopperelemental||||||5615|18|10|2|2|10|30|15|1|6|0|0|0|0|0 +*|Airelemental||||||5568|36|0|2|2|10|30|15|1|3|0|0|0|0|0 +*|Airelemental|Waterelemental|||||5549|60|0|2|2|10|30|15|1|3|2|0|0|0|0 +*|Kraken|Waterelemental|||||5549|79|0|2|2|10|30|10|1|1|3|0|0|0|0 +*|Kraken|Seaserpent|||||5595|82|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Dullcopperelemental||||||5603|93|0|2|2|10|25|12|1|2|0|0|0|0|0 +*|Dullcopperelemental||||||5603|116|0|2|2|10|30|15|1|4|0|0|0|0|0 +*|TreasureLevel1||||||5536|119|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5546|118|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5606|25|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5570|118|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5620|21|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5572|113|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5546|113|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Earthelemental||||||5474|139|20|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental|Poisonelemental|||||5477|183|0|2|2|10|30|15|1|1|4|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5469|211|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Evilmage|Evilmagelord|||||5441|187|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Airelemental|Earthelemental|||||5412|164|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5411|163|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental|Earthelemental|||||5412|201|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5412|200|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental||||||5394|230|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Eldergazer||||||5505|180|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Dullcopperelemental|Fireelemental|||||5527|210|0|2|2|10|30|15|1|4|2|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5557|222|0|2|2|10|25|10|1|2|2|3|0|0|0 +*|Evilmage|Evilmagelord|||||5577|194|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5594|182|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Earthelemental|Scorpion|||||5571|158|-10|2|2|10|30|15|1|4|2|0|0|0|0 +*|Earthelemental|Fireelemental|||||5593|141|10|2|2|10|30|15|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5398|148|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5545|153|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5594|139|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5604|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5608|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5605|202|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5439|137|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5390|145|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5456|157|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5410|170|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5415|189|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5396|226|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5553|146|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5595|147|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5615|173|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5616|184|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5456|143|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5432|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5474|176|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5406|177|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|185|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|200|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5403|235|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5475|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Airelemental||||||5875|44|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental||||||5856|107|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Airelemental||||||5845|57|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Kraken|Seaserpent|||||5828|42|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Evilmage|Evilmagelord|||||5819|50|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Eldergazer||||||5818|80|0|2|2|10|30|10|1|2|0|0|0|0|0 +*|Airelemental||||||5804|12|0|2|2|10|30|15|1|5|0|0|0|0|0 +*|Bloodelemental||||||5721|12|10|2|2|10|30|15|1|8|0|0|0|0|0 +*|Fireelemental||||||5661|16|-10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental||||||5649|101|10|2|2|10|30|15|1|4|0|0|0|0|0 +*|Bloodelemental||||||5684|117|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental|Fireelemental|||||5724|118|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Toxicelemental|Fireelemental|Scorpion||||5760|99|0|2|2|10|30|15|1|2|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5711|97|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5752|44|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Waterelemental|||||5708|43|0|2|2|10|25|10|1|1|3|0|0|0|0 +*|TreasureLevel1||||||5730|90|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5723|73|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5715|61|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5701|60|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5817|83|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5730|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5717|60|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5699|61|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5817|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5733|91|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5725|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|58|2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5698|57|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5733|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5727|72|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5717|58|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5701|58|2|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/SolenHive.map b/Data/Monsters/uoml/felucca/SolenHive.map new file mode 100644 index 0000000..4fa5d00 --- /dev/null +++ b/Data/Monsters/uoml/felucca/SolenHive.map @@ -0,0 +1,92 @@ +############## +## By Nerun ## +############## +overrideid 2220 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Solen Hive Dungeon +## +## AREA A - Yew Lich Ruins (731 1452 0) +## +## Level 1 +## +*|Blacksolenworker||||||5670|1807|4|2|5|10|30|25|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5673|1846|1|2|5|10|20|6|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5693|1834|0|2|5|10|20|4|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5704|1807|4|2|5|10|20|6|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5722|1820|5|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Blacksolenwarrior||||||5709|1874|1|2|5|10|50|10|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5681|1886|2|2|5|10|50|10|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5756|1857|4|2|5|10|50|10|1|1|0|0|0|0|0 +## +## AREA B - Between Minoc/Covetous (2609 764 0) +## +## Level 1 +## +*|Blacksolenworker||||||5912|1800|1|2|5|10|30|20|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5920|1842|1|2|5|10|30|15|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Antlion||||||5887|1840|-18|2|5|10|25|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5847|1819|1|2|5|10|25|10|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5829|1798|1|2|5|10|15|10|1|1|0|0|0|0|0 +*|Blacksolenworker|Blacksolenqueen|||||5873|1798|0|2|5|10|15|10|1|2|1|0|0|0|0 +*|Blacksolenwarrior||||||5782|1793|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5799|1857|5|2|5|10|20|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5815|1881|2|2|5|10|20|7|1|1|0|0|0|0|0 +*|Beetle||||||5831|1910|3|2|5|10|15|10|1|2|0|0|0|0|0 +## +## AREA C - West Trinsic Main Gate (1691 2790 0) +## +## Level 1 +## +*|Blacksolenworker||||||5718|2024|4|2|5|10|25|15|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5776|2019|2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Antlion||||||5782|2021|-11|2|5|10|25|10|1|1|0|0|0|0|0 +*|Dreadspider||||||5767|1962|2|2|5|10|50|15|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5671|1979|0|2|5|10|30|20|1|1|0|0|0|0|0 +*|Blacksolenwarrior||||||5703|1991|0|2|5|10|35|20|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Blacksolenwarrior||||||5699|1921|2|2|5|10|30|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5748|1923|0|2|5|10|20|5|1|1|0|0|0|0|0 +*|Blacksolenqueen|Blacksolenworker|||||5736|1939|7|2|5|10|20|10|1|1|2|0|0|0|0 +## +## AREA D - South Chaos/Compassion Road (1725 815 0) +## +## Level 1 +## +*|Blacksolenworker||||||5876|2018|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5856|2018|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5838|2019|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Blacksolenworker||||||5910|1991|0|2|5|10|25|15|1|3|0|0|0|0|0 +*|Beetle||||||5837|1992|-2|2|5|10|15|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5863|1958|2|2|5|10|25|10|1|2|0|0|0|0|0 +*|Antlion||||||5884|1920|-15|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Blacksolenworker||||||5825|1968|4|2|5|10|25|10|1|2|0|0|0|0|0 +*|Blacksolenwarrior||||||5855|1932|3|2|5|10|20|10|1|2|0|0|0|0|0 +*|Blacksolenworker||||||5798|1963|0|2|5|10|35|10|1|2|0|0|0|0|0 +## +## AREA E - GreenThorn/Desert Entrance +## +*|Antlion||||||5665|1868|11|2|5|10|20|10|1|3|0|0|0|0|0 +*|Antlion||||||5707|1843|-15|2|5|10|10|10|1|1|0|0|0|0|0 +## +## INFILTRATORS +## +## Windemere +*|redsoleninfiltratorqueen|redsoleninfiltratorwarrior|||||3218|502|0|2|5|10|10|10|1|1|2|0|0|0|0 +## Trinsic +*|redsoleninfiltratorqueen|redsoleninfiltratorwarrior|||||1940|3261|1|2|5|10|10|10|1|1|2|0|0|0|0 +## Wind +*|redsoleninfiltratorqueen|redsoleninfiltratorwarrior|||||1361|894|0|2|5|10|8|4|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/TerathanKeep.map b/Data/Monsters/uoml/felucca/TerathanKeep.map new file mode 100644 index 0000000..eb4e20a --- /dev/null +++ b/Data/Monsters/uoml/felucca/TerathanKeep.map @@ -0,0 +1,62 @@ +############## +## By Nerun ## +############## +overrideid 2221 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Lost Lands +## Terathan Keep Dungeon +## +## Terathan Keep +## +*|Balron|Dragon|Drake|Nightmare|||5296|1561|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5296|1562|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5297|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5342|1553|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5342|1552|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5343|1551|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5334|1613|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5334|1614|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5335|1615|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5348|1552|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5345|1551|0|2|1|2|1|1|1|2|0|0|0|0|0 +## +## Ophidian Territory +## +*|Balron|Dragon|Drake|Nightmare|||5344|1757|-125|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5345|1757|-125|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5346|1756|-125|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5335|1706|-70|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5335|1707|-70|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5336|1708|-70|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5270|1695|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5270|1694|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5271|1693|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5365|1707|-71|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5363|1709|-75|2|1|2|1|1|1|2|0|0|0|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5176|1702|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5176|1701|2|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5177|1700|1|2|5|15|20|10|1|1|1|1|1|0|0 +## +## Champion Room +## +*|Balron|Dragon|Drake|Nightmare|||5132|1624|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5132|1623|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5134|1625|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5160|1586|-15|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5163|1585|-15|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5161|1584|-15|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5200|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5201|1566|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5200|1568|0|2|5|15|20|10|1|1|1|1|1|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/TownsLife.map b/Data/Monsters/uoml/felucca/TownsLife.map new file mode 100644 index 0000000..0abe6c1 --- /dev/null +++ b/Data/Monsters/uoml/felucca/TownsLife.map @@ -0,0 +1,152 @@ +############## +## By Nerun ## +############## +overrideid 2222 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Towns +## +## ----Mainland---- +## +## Wind +## +*|dragon|drake|||||5249|228|15|2|5|10|20|20|1|1|2|0|0|0|0 +*|lichlord|lich|||||5164|205|15|2|5|10|15|15|1|1|2|0|0|0|0 +*|daemon||||||5133|150|0|2|5|10|15|15|1|3|0|0|0|0|0 +## +## Britain Town +## +*|Bird|Cat|Dog|Rat|||1550|1658|26|2|5|15|120|120|1|15|15|15|15|0|0 +*|Cow||||||1319|1810|0|2|5|10|10|5|1|7|0|0|0|0|0 +*|Cow||||||1319|1821|0|2|5|10|10|5|1|7|0|0|0|0|0 +## ------------------- +## +## Britain Farm 1 +## +*|Bird|Cat|Dog|Rat|||1340|1790|15|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1339|1788|15|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 2 +## +*|Bird|Cat|Dog|Rat|||1217|1825|0|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1216|1823|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 3 +## +*|Bird|Cat|Dog|Rat|||1186|1633|0|2|5|15|80|80|1|7|7|7|7|0|0 +*|Chicken||||||1185|1632|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Trinsic Town +## +*|Bird|Cat|Dog|Rat|||1937|2760|10|2|5|15|120|120|1|12|12|12|12|0|0 +## +## Skara Brae Town +## +*|Bird|Cat|Dog|Rat|||608|2195|0|2|5|15|70|70|1|8|8|8|8|0|0 +*|Chicken:Sheep:Cow||||||813|2164|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||818|2269|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||830|2353|0|2|5|15|15|10|1|3|0|0|0|0|0 +## +## Yew Town +## +*|Bird|Cat|Dog|Rat|||536|962|0|2|5|15|160|160|1|20|20|20|20|0|0 +*|Sheep||||||676|1178|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||570|1099|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||675|939|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Chicken||||||382|1192|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||560|1239|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||688|1007|0|2|5|10|10|10|1|2|0|0|0|0|0 +## +## Cove Town +## +*|Bird|Cat|Dog|Rat|||2242|1197|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken||||||2223|1151|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## Vesper Town 1 +## +*|Bird|Cat|Dog|Rat|||2939|746|2|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Vesper Town 2 +## +*|Bird|Cat|Dog|Rat|||2904|906|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Minoc Town 1 +## +*|Bird|Cat|Dog|Rat|||2481|542|0|2|5|15|70|70|1|5|5|5|5|0|0 +## +## Minoc Town 2 +## +*|Bird|Cat|Dog|Rat|||2472|434|15|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Minoc Town 3 +## +*|Bird|Cat|Dog|Rat|||2566|622|0|2|5|15|50|50|1|3|3|3|3|0|0 +## +## ----Islands---- +## +## Jhelom Town 1 +## +*|Bird|Cat|Dog|Rat|||1154|3639|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken:Cow:Sheep||||||1127|3583|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken:Cow:Sheep||||||1183|3607|0|2|5|10|10|10|1|5|0|0|0|0|0 +## +## Jhelom Town 2 +## +*|Bird|Cat|Dog|Rat|||1400|3775|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Jhelom Town 3 +## +*|Bird|Cat|Dog|Rat|||1435|4000|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Serpents Hold Town +## +*|Bird|Cat|Dog|Rat|||2972|3436|15|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Haven/Occlo Town 1 +## +*|Bird|Cat|Dog|Rat|||3674|2624|0|2|5|15|80|80|1|10|10|10|10|0|0 +*|Chicken||||||3726|2647|0|2|5|10|25|25|1|10|0|0|0|0|0 +## +## Haven/Occlo Town 2 +## +*|Bird|Cat|Dog|Rat|||3652|2511|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Magincia Town 1 +## +*|Bird|Cat|Dog|Rat|||3714|2205|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Magincia Town 2 +## +*|Bird|Cat|Dog|Rat|||3717|2111|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Buccaneers Den Town 1 +## +*|Bird|Cat|Dog|Rat|||2682|2118|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Buccaneers Den Town 2 +## +*|Bird|Cat|Dog|Rat|||2687|2218|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Nujel'm Town +## +*|Bird|Cat|Dog|Rat|||3699|1238|0|2|5|15|160|160|1|18|18|18|18|0|0 +## +## Moonglow Town +## +*|Bird|Cat|Dog|Rat|||4438|1115|0|2|5|15|70|70|1|12|12|12|12|0|0 +*|Chicken:Cow:Sheep||||||4634|1302|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken||||||4567|1476|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Chicken||||||4422|1451|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## ----Lostlands---- +## +## Papua Town +## +*|Bird|Cat|Dog|Rat|||5726|3211|-2|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Delucia Town +## +*|Bird|Cat|Dog|Rat|||5255|4000|37|2|5|15|80|80|1|6|6|6|6|0|0 +*|Chicken:Sheep:Cow:Bull||||||5267|4012|40|2|5|10|15|15|1|5|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/TownsPeople.map b/Data/Monsters/uoml/felucca/TownsPeople.map new file mode 100644 index 0000000..c76642f --- /dev/null +++ b/Data/Monsters/uoml/felucca/TownsPeople.map @@ -0,0 +1,64 @@ +############## +## By Nerun ## +############## +overrideid 2223 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Britain Chaos/Order Guards +## +*|Orderguard||||||1400|1623|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Orderguard||||||1400|1628|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1521|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1525|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +## +## Town Criers +## +*|Towncrier||||||1662|1611|19|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1421|1698|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2254|1207|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5290|3987|37|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3652|2619|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1330|3778|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3721|2161|20|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2515|557|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||4451|1153|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3773|1308|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5685|3148|-4|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2891|3474|15|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||603|2141|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1914|2687|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1829|2811|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2895|686|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||627|864|0|2|5|10|5|1|1|1|0|0|0|0|0 +## +## Hire +## +*|HireBard:HireBardArcher:HireBeggar:HireFighter:HireMage|HireRanger:HireRangerArcher:HireSailor:HireThief:HirePaladin|||||1399|3743|-21|2|5|15|10|10|1|5|5|0|0|0|0 +## +## Escorts +## +*|Escortablemage:Seekerofadventure:Noble||||||1483|1760|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1372|3916|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1126|3688|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3674|2291|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||4398|1049|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3815|1217|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3749|1404|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3645|2661|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2994|3451|16|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||673|2235|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||573|2246|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2068|2854|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3041|827|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||631|883|0|2|5|15|20|10|1|3|0|0|0|0|0 +## +## Treasures +## +## Trinsic Bank +*|TreasureLevel3|TreasureLevel4|||||1813|2834|0|2|1|2|2|2|1|1|2|0|0|0|0 +## Vesper Bank +*|TreasureLevel1||||||2875|675|0|2|1|2|2|2|1|6|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||2874|692|0|2|1|2|1|1|1|1|1|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2884|692|0|2|1|2|1|1|1|2|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/TrinsicPassage.map b/Data/Monsters/uoml/felucca/TrinsicPassage.map new file mode 100644 index 0000000..77298d8 --- /dev/null +++ b/Data/Monsters/uoml/felucca/TrinsicPassage.map @@ -0,0 +1,18 @@ +############## +## By Nerun ## +############## +overrideid 2224 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Do not exist spiderlord, then i did 2 dreadspiders per block +## +## Trinsic Passage +## +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5976|1387|-22|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5940|1356|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5912|1326|0|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5956|1310|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5999|1327|10|2|5|15|20|10|1|2|1|1|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5915|1302|2|2|1|2|1|1|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Vendors.map b/Data/Monsters/uoml/felucca/Vendors.map new file mode 100644 index 0000000..9f8b6c1 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Vendors.map @@ -0,0 +1,390 @@ +############## +## By Nerun ## +############## +overrideid 2225 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Hidden Valley Mages +## +*|Herbalist|Mage|||||1685|2985|0|1|5|10|20|10|1|2|2|0|0|0|0 +## +## Britain +## +*|jeweler||||||1451|1679|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1602|1712|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||1470|1578|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1547|1659|26|1|5|10|5|0|1|1|1|1|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1620|1586|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|carpenter|architect|realestatebroker||||1430|1597|20|1|5|10|5|0|1|1|1|1|0|0|0 +*|mage|alchemist|mageguildmaster||||1485|1550|30|1|5|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||1296|1759|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1481|1584|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||1493|1616|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1422|1654|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1547|1768|10|1|5|10|5|0|1|1|1|1|1|0|0 +*|warriorguildmaster|hirefighter|||||1341|1733|20|1|5|10|5|0|1|1|2|0|0|0|0 +*|innkeeper||||||1585|1591|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1637|1693|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|tanner|furtrader|||||1431|1612|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1498|1691|20|1|5|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||1470|1765|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||1409|1590|42|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster|blacksmith|||||1349|1778|15|2|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1469|1668|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1510|1543|25|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1427|1716|20|1|5|10|5|0|1|1|1|1|1|0|0 +*|butcher||||||1449|1723|6|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1650|1608|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||1498|1659|27|1|5|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||1425|1690|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1494|1715|6|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1650|1642|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|baker||||||1450|1617|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1418|1547|30|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1471|1611|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1447|1647|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1590|1654|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|bard|bardguildmaster|||||1455|1557|30|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1467|1686|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||1474|1597|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||1417|1578|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1458|1525|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1416|1754|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage||||||1405|1810|0|2|5|10|25|10|1|1|0|0|0|0|0 +*|towncrier||||||1482|1761|-2|2|5|10|4|0|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1228|1572|0|2|5|10|10|8|1|1|1|1|0|0|0 +*|orderguard|hirefighter|||||1355|1754|20|2|5|10|14|8|1|1|1|0|0|0|0 +*|farmer|rancher|||||1243|1699|0|2|5|10|4|4|1|1|1|0|0|0|0 +*|escortablemage||||||1351|1816|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|orderguard||||||1306|1804|0|2|5|10|6|4|1|1|0|0|0|0|0 +*|peasant||||||1304|1826|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|artist||||||1362|1825|0|2|5|10|12|6|1|1|0|0|0|0|0 +*|escortablewanderinghealer||||||1333|1808|0|2|5|10|4|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1150|1619|0|2|5|10|10|6|1|1|1|1|0|0|0 +*|farmer|rancher|hirepeasant||||1149|1547|0|2|5|10|10|10|1|1|1|1|0|0|0 +*|bridegroom||||||1295|1773|10|2|5|10|4|4|1|1|0|0|0|0|0 +*|hirefighter||||||1316|1747|10|2|5|10|20|15|1|3|0|0|0|0|0 +*|hirepeasant||||||1231|1714|0|2|5|10|10|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1190|1707|0|2|5|10|8|4|1|1|1|1|0|0|0 +*|hirebard||||||1427|1726|20|2|5|10|4|4|1|1|0|0|0|0|0 +*|hiresailor|fisherman|rat||||1438|1761|-2|2|5|10|10|6|1|1|1|2|0|0|0 +*|hiresailor||||||1477|1741|0|2|5|10|20|20|1|2|0|0|0|0|0 +*|harbormaster||||||1436|1752|14|2|5|10|4|4|1|1|0|0|0|0|0 +*|merchant||||||1434|1717|20|2|5|10|4|4|1|1|0|0|0|0|0 +## +## Faction Stronghold of True Britannians +## +*|animaltrainer||||||1388|1655|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1362|1574|30|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1388|1588|30|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Buccaneers Den +## +*|innkeeper||||||2715|2098|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|thiefguildmaster||||||2659|2194|4|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2680|2238|2|1|5|10|5|0|1|1|1|1|1|0|0 +*|provisioner|cobbler|||||2737|2250|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2731|2192|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2627|2100|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2752|2155|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2707|2178|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||2634|2083|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2709|2130|0|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Cove +## +*|armorer|weaponsmith|||||2216|1167|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||2256|1181|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||2216|1192|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2245|1231|0|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Jhelom +## +*|fisherman||||||1512|3989|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1504|3693|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1125|3687|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1447|3981|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1452|3747|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1441|3719|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1419|3859|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1356|3780|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1364|3732|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1475|3865|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1354|3754|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher|farmer|||||1386|3825|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||1450|4026|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1395|3705|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||1435|3820|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||1404|3802|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1452|3770|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|armorer|weaponsmith|||||1456|3850|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1317|3773|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||1372|3908|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1416|3779|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1387|3771|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1425|3981|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||1454|4003|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||1360|3815|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1442|3802|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherguildmaster||||||1437|3750|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Magincia +## +*|innkeeper||||||3699|2163|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||3666|2235|20|1|5|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||3720|2126|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3755|2227|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3734|2149|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3683|2171|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||3661|2183|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||3683|2252|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3667|2252|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3727|2224|20|1|5|10|5|0|1|1|1|1|1|0|0 +*|healer|healerguildmaster|||||3687|2227|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||3674|2289|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||3665|2140|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3699|2218|20|1|5|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||3703|2249|20|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Minoc +## +*|provisioner||||||2450|428|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|cobbler||||||2450|428|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2438|410|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||2526|375|23|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2522|524|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2526|546|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|architect||||||2513|477|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2533|572|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2503|552|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2475|397|15|1|5|10|5|0|1|1|1|1|1|0|0 +*|blacksmith|blacksmithguildmaster|||||2471|564|5|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2461|457|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2505|432|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||2577|599|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2455|487|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|bard|bardguildmaster|||||2424|555|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||2478|427|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|realestatebroker|||||2513|477|15|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Moonglow +## +*|tailor|weaver|tailorguildmaster||||4458|1060|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||4417|1064|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||4401|1165|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||4440|1162|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster||||||4545|860|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||4481|1085|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||4395|1137|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||4471|1156|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||4416|1133|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|baker||||||4392|1068|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||4416|1085|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||4392|1117|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||4406|1038|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||4394|1083|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||4409|1111|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||4484|1064|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||4448|1090|0|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Nujel'm +## +*|blacksmith|blacksmithguildmaster|||||3554|1202|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3731|1320|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3700|1214|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3729|1258|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|tailor|weaver|tailorguildmaster||||3774|1265|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tanner||||||3545|1178|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3764|1317|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bardguildmaster||||||3740|1197|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||3778|1172|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3769|1218|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|blacksmith|blacksmithguildmaster|||||3546|1185|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||3546|1194|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||3555|1171|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|furtrader||||||3545|1178|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Ocllo +## +*|fisherman||||||3647|2681|-2|1|5|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||3612|2466|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3628|2541|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||3667|2586|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|butcher||||||3708|2649|20|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||3672|2654|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3632|2640|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||3695|2511|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bardguildmaster||||||3665|2531|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||3602|2615|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3673|2614|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||3632|2595|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||3629|2608|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||3636|2565|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3610|2577|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Serpents Hold +## +*|baker||||||2975|3353|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2906|3485|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||3031|3350|35|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||3018|3426|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2880|3472|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2997|3428|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||3036|3464|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3003|3355|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||2905|3517|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||3051|3367|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2883|3502|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2992|3451|16|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||3008|3389|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2940|3500|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||3058|3400|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||3007|3408|15|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||3013|3353|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||2967|3408|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2972|3425|15|1|5|10|5|0|1|1|1|1|1|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3009|3455|15|1|5|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||2940|3410|1|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Skara Brae +## +*|blacksmith|blacksmithguildmaster|||||630|2194|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|rangerguildmaster||||||562|2148|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||554|2178|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||650|2178|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||656|2235|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||578|2227|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||592|2277|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||587|2146|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||570|2121|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||590|2205|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||582|2186|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||627|2163|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||601|2235|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||611|2157|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||650|2161|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||620|2218|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||602|2180|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||586|2170|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||659|2141|0|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Trinsic +## +*|scribe||||||2002|2721|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1897|2805|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1852|2831|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2033|2801|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1895|2653|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||2026|2845|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinkerguildmaster||||||1848|2680|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||1990|2889|5|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||2072|2856|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||1991|2867|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1911|2805|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1897|2684|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1822|2739|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2019|2748|30|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1844|2735|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1981|2838|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1880|2802|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1813|2825|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1850|2796|-8|1|5|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||1939|2739|10|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1846|2715|10|1|5|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||2011|2804|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1935|2766|10|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1935|2796|0|1|5|10|5|0|1|1|1|1|1|0|0 +## +## Vesper +## +*|minerguildmaster||||||2855|734|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||2861|812|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||2882|723|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2961|621|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||2840|885|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|tanner|furtrader|||||2860|999|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||2998|760|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||3034|827|-3|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||2962|885|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2835|805|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2986|637|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2890|651|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|beekeeper||||||2954|705|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2987|777|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2841|907|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3017|761|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|fisherguildmaster||||||2963|813|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3012|780|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2899|790|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2917|798|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||2920|856|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2782|969|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2865|852|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2918|672|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|herbalist|alchemist|customhairstylist||||2992|844|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|shipwright|mapmaker|||||2995|815|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2901|908|0|1|5|10|5|0|1|1|1|1|1|0|0 +*|banker|minter|||||2881|684|0|1|5|10|5|0|1|1|1|0|0|0|0 +## +## Wind +## +*|scribe||||||5242|180|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5161|32|17|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5148|60|25|1|5|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||5347|76|25|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||5263|129|20|1|5|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5203|86|5|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5218|175|5|1|5|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5300|90|15|1|5|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5306|37|40|1|5|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||5236|142|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5351|56|15|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||5154|97|5|1|5|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||5215|117|1|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Yew +## +*|bowyer||||||570|969|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||517|986|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||529|1008|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||652|820|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||610|810|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||535|867|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||564|1011|0|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||643|1083|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||624|1145|0|1|5|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||631|1034|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||540|966|0|1|5|10|5|0|1|1|1|0|0|0|0 +*|baker||||||553|985|0|1|5|10|5|0|1|1|0|0|0|0|0 +## +## Delucia +## +*|provisioner|cobbler|||||5219|4012|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||5275|3977|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||5225|4000|38|1|5|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||5197|4060|37|1|5|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5297|4007|40|1|5|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5234|4025|37|1|5|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||5191|3989|37|1|5|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5296|3978|37|1|5|10|5|0|1|1|1|1|0|0|0 +## +## Papua +## +*|minter|banker|||||5669|3131|14|2|2|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster|alchemist|mage||||5731|3192|9|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinkerguildmaster|tinker|||||5726|3243|16|2|2|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||5662|3150|13|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5671|3287|11|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||5698|3282|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|weaponsmith|armorer|||||5805|3300|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|customhairstylist|alchemist|herbalist||||5714|3202|12|2|2|10|5|0|1|1|1|1|0|0|0 +*|mapmaker|shipwright|||||5805|3270|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailorguildmaster|weaver|tailor||||5752|3272|16|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||5839|3256|2|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5746|3200|16|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5775|3161|14|2|2|10|5|0|1|1|0|0|0|0|0 +*|healerguildmaster|healer|||||5737|3222|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|realestatebroker|architect|carpenter||||5691|3209|11|2|2|10|5|0|1|1|1|1|0|0|0 +*|cobbler|provisioner|||||5736|3263|15|2|2|10|5|0|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/WildLife.map b/Data/Monsters/uoml/felucca/WildLife.map new file mode 100644 index 0000000..0c04170 --- /dev/null +++ b/Data/Monsters/uoml/felucca/WildLife.map @@ -0,0 +1,186 @@ +############## +## By Nerun ## +############## +overrideid 2226 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3394|628|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3232|510|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4478|3218|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4446|3706|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4682|3662|77|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4692|3494|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4560|3504|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4612|3424|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3607|2417|45|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3555|2525|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3506|2477|28|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3452|2563|32|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3429|2650|43|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3449|2737|49|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3736|2512|35|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3718|2736|38|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3654|2866|61|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3662|2802|51|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3596|2804|51|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3546|2812|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3650|2080|21|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3608|2140|79|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4384|1218|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4468|1006|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4326|1046|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4544|1128|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4510|1262|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4590|1326|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4526|986|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4336|1130|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4448|1334|3|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4540|1454|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4632|1164|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4470|1430|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4592|1424|3|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|3500|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2998|3590|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2864|150|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3292|570|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3206|366|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3172|664|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3392|424|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3076|150|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3092|542|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2512|1066|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2554|1142|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2416|1172|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2188|1986|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2654|2286|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2946|2168|44|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2744|2014|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2786|2282|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2074|1972|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2122|2108|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1932|3125|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1824|3027|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1894|2942|19|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2499|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1005|2647|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|464|2059|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|559|2081|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|883|2129|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|968|2476|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|994|2361|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|964|2214|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1087|2401|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2378|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1334|2311|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1315|2192|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1426|2615|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1527|2609|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1582|2722|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1650|2796|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1724|2781|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1727|2702|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1634|2645|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1505|2445|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1699|2560|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1612|2526|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1722|2435|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1715|2307|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1531|2351|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1602|2426|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1628|2334|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1563|2277|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1503|2207|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1709|1992|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1498|2040|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1439|2104|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1387|2023|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1377|1911|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1459|1963|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1268|2018|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1173|2103|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1070|2069|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|958|2074|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|999|1839|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|1945|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1229|1655|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1725|1447|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1798|1471|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1958|1305|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1867|1244|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1865|1379|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1769|1330|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1666|1290|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1486|1301|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1351|1359|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1231|1462|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1017|1726|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|398|1305|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|485|1398|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|210|1447|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|851|1770|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|977|1638|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|919|1718|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|876|1639|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|1570|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|725|1483|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|623|1328|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|727|1394|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1020|1360|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1024|1244|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|802|1280|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|855|934|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|771|1013|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|846|1071|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|940|1028|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1152|812|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|896|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1057|765|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|974|374|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1063|541|16|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1018|629|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|951|542|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|576|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|937|743|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|890|657|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|895|830|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|689|753|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|748|669|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|764|822|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|834|751|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|782|1156|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|887|1223|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|916|1159|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|993|1130|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1047|1071|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1092|1010|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1172|974|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1388|784|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1631|640|22|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1526|960|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1545|813|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1695|809|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1728|691|6|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1802|495|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1857|600|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1884|735|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1973|751|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2085|658|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2367|748|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2289|917|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2338|989|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2418|999|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2495|978|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2583|993|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2513|782|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2748|660|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2765|754|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2668|1020|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2669|922|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2672|814|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2643|728|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2888|391|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2735|417|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2914|547|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|492|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2688|524|11|2|5|10|50|50|1|7|5|1|2|2|2 \ No newline at end of file diff --git a/Data/Monsters/uoml/felucca/Wrong.map b/Data/Monsters/uoml/felucca/Wrong.map new file mode 100644 index 0000000..42c9097 --- /dev/null +++ b/Data/Monsters/uoml/felucca/Wrong.map @@ -0,0 +1,24 @@ +############## +## By Nerun ## +############## +overrideid 2227 +overridemap 1 +overridemintime 5 +overridemaxtime 10 +## +## Wrong Dungeon +## +## Level 1 +## +*|Jukawarrior||||||5819|591|0|2|2|10|25|5|1|2|0|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5808|588|12|2|2|10|30|15|1|1|1|3|0|0|0 +*|Golemcontroller|Golem|||||5792|544|10|2|2|10|30|6|1|4|4|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|586|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|562|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5828|530|0|2|2|10|30|8|1|1|1|3|0|0|0 +## +## Level 2 +## +*|Brigand|Jukalord|Jukamage|Jukawarrior|||5659|563|20|2|2|10|30|10|1|4|1|1|3|0|0 +*|Golem|Jukalord|Jukamage|Jukawarrior|||5724|561|20|2|2|10|30|8|1|1|1|1|3|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5690|534|0|2|2|10|30|8|1|1|1|3|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Ancientlair.map b/Data/Monsters/uoml/ilshenar/Ancientlair.map new file mode 100644 index 0000000..e90885f --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Ancientlair.map @@ -0,0 +1,15 @@ +############## +## By Nerun ## +############## +overrideid 2301 +## +## Ancient LairCave +## +*|AncientWyrm||||||50|689|-28|3|10|20|15|30|1|1|0|0|0|0|0 +overridemintime 5 +overridemaxtime 10 +*|fireelemental:lavalizard||||||115|716|-28|3|5|10|15|15|1|3|0|0|0|0|0 +*|fireelemental:lavalizard||||||131|78|0|3|5|10|10|10|1|1|0|0|0|0|0 +*|fireelemental:lavalizard||||||54|718|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|fireelemental|lavalizard|||||82|718|-28|3|5|10|15|15|1|2|2|0|0|0|0 +*|fireelemental:lavalizard||||||79|687|-28|3|5|10|10|10|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Ankh.map b/Data/Monsters/uoml/ilshenar/Ankh.map new file mode 100644 index 0000000..2ff312f --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Ankh.map @@ -0,0 +1,47 @@ +############## +## By Nerun ## +############## +overrideid 2302 +overridemintime 5 +overridemaxtime 10 +## +## Ankh Dungeon +## +## Level 1 +## +*|Ratman|Ratmanarcher|Ratmanmage||||129|1530|-28|3|5|10|40|20|1|5|2|2|0|0|0 +*|Hellhound|Imp|||||71|1521|-28|3|5|10|40|15|1|2|3|0|0|0|0 +*|Evilmage||||||87|1471|-22|3|5|10|7|7|1|3|0|0|0|0|0 +*|Evilmage||||||63|1471|-28|3|5|10|7|7|1|2|0|0|0|0|0 +*|Daemon||||||39|1491|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||34|1462|-28|3|5|10|10|10|1|3|0|0|0|0|0 +*|Imp||||||15|1503|-27|3|5|10|7|7|1|4|0|0|0|0|0 +*|Evilmage||||||62|1446|-28|3|5|10|7|7|1|3|0|0|0|0|0 +*|Skeletalknight||||||31|1410|-28|3|5|10|11|7|1|4|0|0|0|0|0 +*|Mummy||||||86|1447|-28|3|5|10|15|7|1|3|0|0|0|0|0 +*|Skeletalmage||||||124|1435|-16|3|5|10|20|10|1|4|0|0|0|0|0 +*|Lich||||||124|1436|-16|3|5|10|15|7|1|2|0|0|0|0|0 +*|Lich||||||107|1390|-28|3|5|10|10|10|1|2|0|0|0|0|0 +*|Lichlord|Rottingcorpse|||||131|1331|-28|3|5|10|20|20|1|1|2|0|0|0|0 +*|Zombie||||||132|1332|-28|3|5|10|20|20|1|4|0|0|0|0|0 +*|Skeleton|Skeletalknight|Skeletalmage||||55|1303|-28|3|5|10|30|20|1|3|2|1|0|0|0 +## +## Kirin Passage +## +*|Fireelemental||||||45|905|-29|3|5|10|30|15|1|2|0|0|0|0|0 +*|Poisonelemental||||||49|846|-30|3|5|10|12|12|1|1|0|0|0|0|0 +*|Earthelemental||||||114|908|-26|3|5|10|25|15|1|3|0|0|0|0|0 +*|Poisonelemental||||||102|959|-43|3|5|10|20|15|1|2|0|0|0|0|0 +*|Kirin||||||148|953|-29|3|5|10|15|15|1|1|0|0|0|0|0 +*|Dragon||||||29|1009|-27|3|5|10|35|15|1|2|0|0|0|0|0 +*|Drake||||||29|1016|-27|3|5|10|35|15|1|4|0|0|0|0|0 +*|Earthelemental|Mongbat|||||87|1051|-29|3|5|10|35|20|1|3|7|0|0|0|0 +*|Earthelemental||||||108|1110|-27|3|5|10|30|20|1|4|0|0|0|0|0 +*|Toxicelemental||||||99|1158|-23|3|5|10|10|10|1|2|0|0|0|0|0 +*|Nightmare||||||66|1171|-28|3|5|10|10|5|1|1|0|0|0|0|0 +## +## Serpentine Passage +## +*|Pixie||||||438|1552|-28|3|5|10|20|10|1|5|0|0|0|0|0 +*|Wisp||||||451|1552|-27|3|5|10|25|15|1|3|0|0|0|0|0 +*|Serpentinedragon||||||473|1552|-28|3|5|10|20|15|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Blood.map b/Data/Monsters/uoml/ilshenar/Blood.map new file mode 100644 index 0000000..8180630 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Blood.map @@ -0,0 +1,27 @@ +############## +## By Nerun ## +############## +overrideid 2303 +overridemintime 5 +overridemaxtime 10 +## +## Blood Dungeon +## +*|Imp||||||2114|846|-28|3|5|10|30|15|1|4|0|0|0|0|0 +*|Imp||||||2051|837|-28|3|5|10|15|7|1|4|0|0|0|0|0 +*|Hellcat||||||2050|859|-28|3|5|10|15|7|1|2|0|0|0|0|0 +*|Hellcat||||||2090|868|-14|3|5|10|15|7|1|3|0|0|0|0|0 +*|Imp||||||2177|836|-28|3|5|10|15|7|1|4|0|0|0|0|0 +*|Imp||||||2177|858|-28|3|5|10|15|7|1|4|0|0|0|0|0 +*|Imp||||||2138|868|-14|3|5|10|15|7|1|4|0|0|0|0|0 +*|Bloodelemental||||||2138|868|-14|3|5|10|7|7|1|1|0|0|0|0|0 +*|Balron||||||2083|911|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Balron||||||2115|917|-23|3|5|10|15|15|1|1|0|0|0|0|0 +*|Balron||||||2145|911|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||2170|920|-28|3|5|10|32|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||2058|907|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||2058|932|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Daemon||||||2083|951|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|Daemon||||||2114|951|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|Daemon||||||2146|951|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|Succubus|Hellcat|||||2113|1017|-28|3|5|10|30|15|1|2|4|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Exodus.map b/Data/Monsters/uoml/ilshenar/Exodus.map new file mode 100644 index 0000000..6eefcaa --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Exodus.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 2304 +overridemintime 5 +overridemaxtime 10 +## +## Exodus Dungeon +## +*|EnslavedGargoyle:GolemController||||||1980|116|-28|3|5|10|40|30|1|2|0|0|0|0|0 +*|ExodusMinion||||||1939|116|-28|3|5|10|25|15|1|1|0|0|0|0|0 +*|GolemController:ExodusOverseer||||||1894|116|-28|3|5|10|30|20|1|2|0|0|0|0|0 +*|GolemController||||||1964|164|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController||||||1932|164|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController:Golem||||||1932|196|-28|3|5|10|20|15|1|2|0|0|0|0|0 +*|GargoyleDestroyer||||||1895|160|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|ExodusOverseer:ExodusMinion||||||1979|192|-28|3|5|10|20|15|1|2|0|0|0|0|0 +*|GolemController||||||1996|164|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleEnforcer||||||2032|184|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleEnforcer||||||2063|183|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleEnforcer:GargoyleDestroyer||||||2058|163|-28|3|5|10|15|10|1|2|0|0|0|0|0 +*|GolemController:Golem:ExodusMinion||||||2044|143|-28|3|5|10|15|10|1|3|0|0|0|0|0 +*|GolemController:ExodusOverseer||||||2071|116|-28|3|5|10|15|10|1|2|0|0|0|0|0 +*|ExodusMinion:Golem||||||2044|87|-28|3|5|10|15|10|1|2|0|0|0|0|0 +*|GargoyleEnforcer||||||2031|48|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleDestroyer||||||2038|67|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController||||||1995|67|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|ExodusOverseer:ExodusMinion:GolemController||||||1980|39|-28|3|5|10|15|10|1|3|0|0|0|0|0 +*|GolemController||||||1931|67|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GargoyleDestroyer||||||1896|72|-28|3|5|10|15|10|1|1|0|0|0|0|0 +*|GolemController:Golem||||||1932|35|-28|3|5|10|20|15|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Mushroom.map b/Data/Monsters/uoml/ilshenar/Mushroom.map new file mode 100644 index 0000000..698948c --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Mushroom.map @@ -0,0 +1,15 @@ +############## +## By Nerun ## +############## +overrideid 2305 +overridemintime 2 +overridemaxtime 5 +## +## Mushroom Cave +## +## Level 1 +## +*|mushroomtrap||||||1444|1519|-28|3|2|5|10|10|1|4|0|0|0|0|0 +*|mushroomtrap||||||1441|1532|-28|3|2|5|10|10|1|4|0|0|0|0|0 +*|mushroomtrap||||||1415|1498|-27|3|2|5|4|4|1|4|0|0|0|0|0 +*|mushroomtrap||||||1464|1495|-28|3|2|5|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Outdoors.map b/Data/Monsters/uoml/ilshenar/Outdoors.map new file mode 100644 index 0000000..b97a1bc --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Outdoors.map @@ -0,0 +1,360 @@ +############## +## By Nerun ## +############## +overrideid 2306 +overridemintime 5 +overridemaxtime 10 +## +## Ilshenar Northeast +## +## South Montor +*|Dragon||||||1763|344|52|3|5|10|30|30|1|1|0|0|0|0|0 +*|Earthelemental||||||1790|435|-10|3|5|10|25|20|1|3|0|0|0|0|0 +*|Mongbat|Airelemental|Giantspider|Earthelemental|Scorpion||1805|469|-9|3|5|10|50|50|1|5|1|1|3|4|0 +*|Stonegargoyle||||||1852|484|-13|3|5|10|20|10|1|3|0|0|0|0|0 +*|Brigand||||||1856|517|-14|3|5|10|30|30|1|3|0|0|0|0|0 +*|Airelemental||||||1775|530|66|3|5|10|10|10|1|1|0|0|0|0|0 +*|Wyvern|Mummy|||||1828|601|38|3|5|10|40|40|1|2|6|0|0|0|0 +*|Orccamp||||||1717|606|17|3|5|10|0|0|1|1|0|0|0|0|0 +## Desert +*|Desertostard|Stoneharpy|Gargoyle|Wyvern|Efreet|Lichlord|1647|602|-14|3|5|10|30|30|1|5|1|2|2|1|1 +*|Desertostard|Stoneharpy|Gargoyle|Wyvern|Efreet||1593|602|7|3|5|10|30|30|1|5|2|2|1|2|0 +*|Earthelemental:Scorpion||||||1700|546|5|3|5|10|30|30|1|14|0|0|0|0|0 +*|Ratman|Ratmanarcher:Ratmanmage|||||1580|538|-14|3|5|10|7|5|1|2|1|0|0|0|0 +*|Ratman|Ratmanarcher:Ratmanmage|||||1580|554|-13|3|5|10|7|5|1|1|1|0|0|0|0 +*|Earthelemental||||||1534|631|-14|3|5|10|15|5|1|2|0|0|0|0|0 +*|Earthelemental||||||1530|667|-14|3|5|10|15|5|1|2|0|0|0|0|0 +*|Shade:Spectre:Wraith|Skeleton|Ghoul|Zombie|||1534|600|-14|3|5|10|25|15|1|7|5|2|2|0|0 +*|Imp||||||1445|681|-1|3|5|10|20|20|1|3|0|0|0|0|0 +## Glacier/Tunnels +*|Harpy||||||1400|687|32|3|5|10|25|25|1|3|0|0|0|0|0 +*|Frosttroll|Drake|Snowelemental|Iceelemental|||1352|667|111|3|5|10|22|22|1|3|2|2|2|0|0 +*|Frosttroll|Iceelemental|Iceserpent|Frostspider|||1372|623|111|3|5|10|30|25|1|4|1|2|2|0|0 +*|Frosttroll|Snowelemental|Iceelemental|Drake|||1316|633|106|3|5|10|30|10|1|2|1|1|1|0|0 +## Green/Mountains +*|Skeleton|Shade:Spectre:Wraith|Ghoul|Zombie|||1442|576|-11|3|5|10|15|10|1|5|6|2|2|0|0 +*|Skeleton|Shade:Spectre|Zombie|Efreet|||1400|572|-13|3|5|10|15|15|1|4|4|2|1|0|0 +*|Orc|Orccaptain|Ettin|Troll|Orcishmage||1421|517|1|3|5|10|40|30|1|3|1|2|2|1|0 +*|Healercamp||||||1358|498|3|3|5|10|0|0|1|1|0|0|0|0|0 +*|Gargoyle||||||1319|560|-4|3|5|10|15|15|1|3|0|0|0|0|0 +*|Ratman|Ratmanarcher|Ratmanmage||||1237|473|-4|3|5|10|20|15|1|3|1|1|0|0|0 +*|Drake|Harpy|||||1275|401|-1|3|5|10|40|35|1|2|4|0|0|0|0 +*|Troll||||||1445|384|22|3|5|10|30|30|1|4|0|0|0|0|0 +*|Ancientwyrm||||||1416|317|74|3|5|10|7|7|1|1|0|0|0|0|0 +*|Imp|Daemon|||||1496|280|-10|3|5|10|10|10|1|3|1|0|0|0|0 +*|Ettin||||||1464|241|2|3|5|10|20|10|1|1|0|0|0|0|0 +*|Ettin||||||1503|239|-7|3|5|10|20|10|1|1|0|0|0|0|0 +*|Imp||||||1571|253|14|3|5|10|25|10|1|3|0|0|0|0|0 +## Swamp near savage +*|Sewerrat|Corpser|Bogling|Giantrat|Alligator|Mongbat|1070|750|-80|3|5|10|30|30|1|4|2|2|2|2|2 +*|Lizardman|Plaguebeast|Toxicelemental||||1070|750|-80|3|5|10|30|30|1|4|2|1|0|0|0 +*|Sewerrat|Corpser|Bogling|Giantrat|Alligator|Mongbat|1135|743|-80|3|5|10|30|30|1|4|2|2|2|2|2 +*|Lizardman|Plaguebeast|Toxicelemental|Bogthing|||1135|743|-80|3|5|10|30|30|1|4|2|1|1|0|0 +*|Sewerrat|Corpser|Bogling|Giantrat|Alligator|Mongbat|1160|681|-80|3|5|10|30|30|1|4|2|1|2|2|1 +*|Lizardman|Plaguebeast|||||1160|681|-80|3|5|10|30|30|1|3|1|0|0|0|0 +## Controller Tower +*|Golemcontroller|Golem|||||1097|702|-79|3|5|10|7|5|1|1|1|0|0|0|0 +*|Golemcontroller|Golem|||||1087|698|-80|3|5|10|7|2|1|1|1|0|0|0|0 +*|Golemcontroller||||||1086|702|-60|3|5|10|5|5|1|2|0|0|0|0|0 +*|Golemcontroller|Golem|||||1098|698|-60|3|5|10|5|1|1|1|1|0|0|0|0 +*|Golem||||||1091|702|-40|3|5|10|10|5|1|1|0|0|0|0|0 +## +## Ruined Castle +## Level 1 +*|Jukamage||||||1084|675|-80|3|5|10|15|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1059|675|-79|3|5|10|7|7|1|1|0|0|0|0|0 +*|Jukawarrior||||||1060|659|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1060|643|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukamage||||||1075|628|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1092|628|-80|3|5|10|7|3|1|1|0|0|0|0|0 +*|Jukawarrior||||||1083|638|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukamage||||||1095|638|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukawarrior||||||1095|664|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukalord||||||1083|664|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukalord||||||1070|639|-79|3|5|10|5|5|1|1|0|0|0|0|0 +*|Jukamage|Jukawarrior|||||1070|650|-79|3|5|10|7|5|1|1|1|0|0|0|0 +## Level 2 +*|Jukawarrior||||||1072|651|-60|3|5|10|6|6|1|1|0|0|0|0|0 +*|Jukawarrior||||||1083|628|-60|3|5|10|15|3|1|1|0|0|0|0|0 +*|Jukamage||||||1107|627|-59|3|5|10|7|3|1|1|0|0|0|0|0 +*|Betrayer||||||1083|675|-60|3|5|10|15|3|1|1|0|0|0|0|0 +*|Jukamage|Jukawarrior|Juggernaut||||1088|661|-60|3|5|10|10|9|1|1|1|1|0|0|0 +*|Betrayer|Jukalord|Jukawarrior||||1090|646|-60|3|5|10|10|3|1|1|1|1|0|0|0 +*|Jukamage|Jukalord|Jukawarrior||||1088|637|-60|3|5|10|10|4|1|2|1|1|0|0|0 +## Level 3 +*|Betrayer||||||1060|652|-40|3|5|10|15|3|1|1|0|0|0|0|0 +*|Betrayer|Golemcontroller|||||1083|651|-40|3|5|10|25|10|1|1|3|0|0|0|0 +*|Juggernaut|Golem|||||1083|651|-40|3|5|10|25|10|1|3|1|0|0|0|0 +## Level 4 +*|Golemcontroller|Gargoyle|||||1084|652|-20|3|5|10|25|10|1|2|2|0|0|0|0 +## +## Meer +## +*|Meerwarrior|Meermage|Meercaptain|Meereternal|||1772|67|-28|3|5|10|25|20|1|3|2|2|1|0|0 +*|Meerwarrior|Meermage|Meercaptain|Meereternal|||1803|66|-28|3|5|10|25|20|1|4|2|1|1|0|0 +############## +## By Nerun ## +############## +## +## Ilshenar Northwest +## +## Undead Camp +## +*|Skeleton|Wraith|Skeletalknight|Zombie|Skeletalmage|Wyvern|855|464|-2|3|5|10|20|20|1|6|2|4|3|3|2 +## +## Pass of Karnaugh +## +*|Dreadspider|Poisonelemental|Stonegargoyle|Wyvern|Skeleton|Skeletalknight|1041|272|56|3|5|10|25|25|1|2|1|1|1|1|1 +*|Lich|Shade:Spectre:Wraith|Zombie|Ghoul|||1041|272|56|3|5|10|25|25|1|1|3|1|1|0|0 +*|Dreadspider|Stonegargoyle|Wyvern|Skeleton|Skeletalmage|Eldergazer|1000|272|56|3|5|10|25|25|1|1|2|1|1|1|1 +*|Lichlord|Shade:Spectre:Wraith|Zombie|Ghoul|||1000|272|56|3|5|10|25|25|1|1|3|1|1|0|0 +## +## Memorial to Gwenno +## +*|Eldergazer|Gazer|||||748|492|-64|3|5|10|10|10|1|1|2|0|0|0|0 +## +## Near undead camp +## +*|Skeleton|Shade:Spectre:Wraith|Ghoul|Zombie|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|783|448|-47|3|5|10|25|25|1|4|4|2|2|2|2 +*|Lich|Lichlord|||||783|448|-47|3|5|10|25|25|1|1|1|0|0|0|0 +*|Skeleton|Shade:Spectre:Wraith|Ghoul|Zombie|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|742|440|-59|3|5|10|25|25|1|4|4|2|2|2|2 +*|Lich|Lichlord|||||742|440|-59|3|5|10|25|25|1|1|1|0|0|0|0 +## +## Cyclopse Garden / Camp +## +*|Cyclops||||||756|208|-40|3|5|10|10|10|1|4|0|0|0|0|0 +*|Cyclops|Titan|Ettin||||739|264|-54|3|5|10|35|35|1|1|1|2|0|0|0 +*|Cyclops|Titan|Ettin||||778|264|-38|3|5|10|35|35|1|1|1|2|0|0|0 +## +## Bandit Town +## +*|Brigand|Evilmage|||||511|545|-60|3|5|10|25|20|1|4|2|0|0|0|0 +## +*|Wyvern||||||638|555|-75|3|5|10|40|40|1|3|0|0|0|0|0 +*|Wyvern||||||565|343|-77|3|5|10|40|40|1|2|0|0|0|0|0 +*|Eldergazer|Gazer|||||489|488|-62|3|5|10|25|25|1|1|2|0|0|0|0 +*|Dragon||||||385|421|-62|3|5|10|30|20|1|1|0|0|0|0|0 +*|Dragon||||||447|425|-60|3|5|10|30|20|1|1|0|0|0|0|0 +*|Dragon||||||445|366|-66|3|5|10|30|30|1|1|0|0|0|0|0 +*|Dragon||||||445|318|-64|3|5|10|30|30|1|1|0|0|0|0|0 +*|Wyvern|Giantspider|Dreadspider||||370|264|-52|3|5|10|15|15|1|1|2|1|0|0|0 +*|Wyvern|Giantspider|Dreadspider||||409|264|-44|3|5|10|15|15|1|1|2|1|0|0|0 +*|Wyvern|Giantspider|Dreadspider||||449|264|-57|3|5|10|15|15|1|1|2|1|0|0|0 +## +## Desert near Gargoyle City +## +*|Mongbat|Earthelemental|Scorpion|Sandvortex|Ridgeback|Efreet|964|638|-80|3|5|10|50|40|1|5|5|5|5|1|1 +## +## Around Ancient Lair +## +*|Earthelemental||||||981|470|-80|3|5|10|15|10|1|1|0|0|0|0|0 +*|Imp|Golemcontroller|||||978|471|-80|3|5|10|15|10|1|1|1|0|0|0|0 +*|Lavalizard||||||973|460|-80|3|5|10|15|10|1|1|0|0|0|0|0 +*|Earthelemental||||||964|456|-80|3|5|10|15|10|1|1|0|0|0|0|0 +*|Exodusoverseer||||||963|456|-80|3|5|10|10|5|1|1|0|0|0|0|0 +*|Imp||||||941|471|-38|3|5|10|10|4|1|1|0|0|0|0|0 +*|Gargoyle||||||946|430|-80|3|5|10|15|10|1|4|0|0|0|0|0 +*|Lich|Ghoul|Zombie|Shade:Wraith:Spectre|||878|527|-77|3|5|10|20|10|1|1|1|4|1|0|0 +*|Imp||||||938|453|-80|3|5|10|15|10|1|2|0|0|0|0|0 +*|Earthelemental||||||960|524|-80|3|5|10|15|5|1|1|0|0|0|0|0 +*|Earthelemental||||||911|502|-80|3|5|10|15|5|1|1|0|0|0|0|0 +*|Imp||||||930|519|-80|3|5|10|15|5|1|1|0|0|0|0|0 +## +## Under Desert near Gargoyle City +## +*|golemcontroller||||||808|781|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|quagmire||||||853|762|-80|3|5|10|17|17|1|3|0|0|0|0|0 +*|chaosdaemon|Moloch|Doppleganger||||821|758|-80|3|5|10|17|17|1|1|1|1|0|0|0 +*|quagmire|Doppleganger|ArcaneDaemon||||821|802|-80|3|5|10|17|17|1|1|1|1|0|0|0 +*|chaosdaemon|Moloch|||||858|799|-80|3|5|10|17|17|1|2|1|0|0|0|0 +*|chaosdaemon||||||879|781|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|earthelemental||||||907|780|-80|3|5|10|20|20|1|4|0|0|0|0|0 +*|earthelemental||||||987|791|-80|3|5|10|20|20|1|4|0|0|0|0|0 +## +## Non-OSI spawns (animals) +## +*|Airelemental||||||275|453|-53|3|5|10|50|30|1|1|0|0|0|0|0 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|652|555|-72|3|5|10|75|50|1|5|2|5|3|3|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|685|340|-64|3|5|10|170|125|1|15|9|9|9|9|9 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|460|469|-49|3|5|10|75|50|1|5|2|5|3|3|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|377|340|-14|3|5|10|150|100|1|9|5|6|5|5|5 +############## +## By Nerun ## +############## +## +## Ilshenar Southeast +## +## Healing Temple +## +*|Wanderinghealer||||||1083|968|-38|3|5|10|30|30|1|5|0|0|0|0|0 +## +## Ratman Village +## +*|ratmanmage|ratmanarcher|ratman||||1059|1153|-24|3|5|10|15|15|1|2|2|4|0|0|0 +## +## Brigand Tower +## +*|Brigand||||||1129|1236|-4|3|5|10|12|12|1|4|0|0|0|0|0 +## +## Camps +## +*|Bankercamp||||||1186|1223|-20|3|5|10|0|0|1|1|0|0|0|0|0 +*|Healercamp||||||1519|1019|-6|3|5|10|0|0|1|1|0|0|0|0|0 +## +## Southeast forest +## +*|Pixie|Horse|||||1592|1191|-20|3|5|10|70|70|1|5|3|0|0|0|0 +*|Unicorn||||||1592|1191|-20|3|5|10|50|50|1|1|0|0|0|0|0 +*|Pixie|Horse|||||1480|1207|-18|3|5|10|70|70|1|5|3|0|0|0|0 +*|Unicorn||||||1480|1207|-18|3|5|10|50|50|1|1|0|0|0|0|0 +*|Pixie|Horse|||||1318|1246|-13|3|5|10|50|40|1|3|1|0|0|0|0 +## +## Sacrifice Graveyard +## +*|Skeleton:Zombie:Ghoul||||||1183|1287|-30|3|5|10|10|5|1|3|0|0|0|0|0 +## +## Sheep farm +## +*|Sheep||||||1319|1331|-14|3|5|10|10|10|1|3|0|0|0|0|0 +## +## Blood Dungeon entrance +## +*|Skeleton||||||1733|1161|-5|3|5|10|30|30|1|7|0|0|0|0|0 +*|Skeleton|Skeletalknight:Boneknight|Imp||||1747|1221|-1|3|5|10|25|15|1|4|4|3|0|0|0 +## +## Harpy Nest +## +*|Harpy|Stoneharpy|||||1678|971|10|3|5|10|15|15|1|3|1|0|0|0|0 +## +## Tower (near twin oaks tavern) +## +*|Evilmagelord||||||1674|1074|32|3|5|10|5|0|1|1|0|0|0|0|0 +## +## Abandoned building +## +*|Giantrat||||||1585|990|20|3|5|10|10|0|1|2|0|0|0|0|0 +## +## Spider Wood +## +*|Giantspider|Dreadspider|Reaper||||1436|960|-22|3|5|10|40|40|1|5|2|2|0|0|0 +## +## Bet-Lem Reg +## +*|Pixie||||||1249|957|-14|3|5|10|10|10|1|5|0|0|0|0|0 +## +## Exit Passage +## +*|Troll||||||1360|888|-21|3|5|10|40|10|1|3|0|0|0|0|0 +## +## Spider Dungeon +## +*|Dreadspider|Giantspider|||||1817|976|-28|3|5|10|45|45|1|7|13|0|0|0|0 +## +## Spider Dungeon Shrine +## +*|Giantspider||||||1504|878|10|3|5|10|20|15|1|4|0|0|0|0|0 +############## +## By Nerun ## +############## +## +## Ilshenar Southwest +## +## The Deuce's Vinculum Inn +## +*|ratmanmage|ratmanarcher|ratman||||664|668|5|3|5|10|10|7|1|1|1|1|0|0|0 +*|ratmanarcher|ratman|||||664|665|-15|3|5|10|10|7|1|2|2|0|0|0|0 +*|ratmanmage|ratman|||||664|665|-35|3|5|10|10|10|1|1|2|0|0|0|0 +## +## Ratman Lair +## +*|ratmanmage|ratmanarcher|ratman||||644|819|-44|3|5|10|25|20|1|3|3|9|0|0|0 +## +## Camps +## +*|Bankercamp||||||961|924|-37|3|5|10|0|0|1|1|0|0|0|0|0 +*|Magecamp||||||567|807|-74|3|5|10|0|0|1|1|0|0|0|0|0 +*|Magecamp||||||830|1206|-70|3|5|10|0|0|1|1|0|0|0|0|0 +## +## Lava Vent / Champ "Humility" +## +*|Ratman|Ratmanmage|Ratmanarcher|Giantspider|Hellhound|Slime|485|891|-82|3|5|10|40|40|1|5|1|2|2|2|2 +*|Jwilson||||||487|890|-82|3|5|10|40|40|1|1|0|0|0|0|0 +## +## Graveyard +## +*|Skeleton|Spectre:Shade:Wraith|Ghoul|Zombie|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|330|881|-73|3|5|10|25|25|1|4|5|1|1|2|4 +*|Lich||||||325|893|-72|3|5|10|10|10|1|1|0|0|0|0|0 +*|Lich||||||366|881|-73|3|5|10|7|7|1|1|0|0|0|0|0 +*|Lichlord||||||338|863|-72|3|5|10|7|7|1|1|0|0|0|0|0 +## +## Undead Fort +## +*|Skeleton|Spectre:Shade:Wraith|Ghoul|Zombie|||353|1140|-54|3|5|10|20|20|1|7|3|2|3|0|0 +*|Shade||||||354|1140|-52|3|5|10|5|5|1|1|0|0|0|0|0 +## +## Nox Tereg +## +*|Swamptentacle|Gianttoad|Alligator|Reaper|Corpser||430|1176|-68|3|5|10|60|60|1|4|12|14|4|6|0 +*|Swamptentacle|Gianttoad|Alligator|Reaper|Corpser||350|1204|-38|3|5|10|40|40|1|2|5|6|2|3|0 +## +## Abandoned Tower Swamp +## +*|Swamptentacle|Gianttoad|Lizardman|Alligator:Reaper:Corpser|||400|1334|-37|3|5|10|70|70|1|5|8|5|0|0|0 +## +## Lizardman Camp +## +*|Lizardman||||||291|1313|-25|3|5|10|30|30|1|7|0|0|0|0|0 +*|Lizardman||||||295|1348|-26|3|5|10|30|30|1|8|0|0|0|0|0 +## +## Lizardman camp / Cave Passage +## +*|Lizardman||||||302|1580|-29|3|5|10|15|10|1|2|0|0|0|0|0 +*|Lizardman||||||325|1576|-28|3|5|10|15|4|1|1|0|0|0|0|0 +## +## Ancient Wyrm's Lair +## +*|Ancientwyrm|Wyvern|Lavalizard||||223|1360|-15|3|5|10|20|20|1|1|2|3|0|0|0 +## +## Elemental Canyon +## +*|Efreet||||||278|1440|15|3|5|10|10|10|1|1|0|0|0|0|0 +*|Fireelemental|Airelemental|Imp||||314|1436|16|3|5|10|25|15|1|1|1|2|0|0|0 +*|Fireelemental|Airelemental|Imp||||350|1441|17|3|5|10|25|15|1|1|1|2|0|0|0 +## +## Dead Forest +## +*|Fireelemental|Airelemental|||||438|1431|15|3|5|10|30|20|1|2|2|0|0|0|0 +## +## Wisp Dungeon Entrance +## +*|Mongbat|Wisp|Imp||||648|1321|-57|3|5|10|25|25|1|6|2|4|0|0|0 +## +## Honesty +## +*|Imp|Gazer|||||722|1354|-61|3|5|10|20|20|1|4|2|0|0|0|0 +## +## Near "Justice" +## +*|Waterelemental||||||913|935|-34|3|5|10|10|10|1|2|0|0|0|0|0 +*|Reaper|Mongbat|Imp||||963|1028|-31|3|5|10|40|20|1|2|4|3|0|0|0 +*|Headlessone|Mongbat|Imp||||935|1159|13|3|5|10|40|20|1|3|3|4|0|0|0 +## +## Cyclopse's Pyramid +## +*|Ettin||||||822|1324|-80|3|5|10|25|25|1|6|0|0|0|0|0 +*|Titan|Cyclops|Ettin||||902|1308|-71|3|5|10|40|35|1|2|4|6|0|0|0 +## +## Non-OSI spawns (animals) +## +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|646|1209|-93|3|5|10|50|40|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|605|1061|-84|3|5|10|55|45|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|564|1142|-99|3|5|10|65|45|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|681|1125|-73|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|703|984|-68|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|605|973|-82|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|514|1225|-66|3|5|10|40|30|1|4|1|2|1|1|1 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|733|1238|-68|3|5|10|65|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|397|958|-80|3|5|10|70|50|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|468|874|-80|3|5|10|50|40|1|4|2|3|2|2|2 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|630|828|-55|3|5|10|110|85|1|7|3|4|4|4|3 +*|Tropicalbird|Boar|Snake:Giantserpent|Forestostard|Gorilla|Panther|588|674|-60|3|5|10|100|75|1|7|3|4|4|4|3 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Ratmancave.map b/Data/Monsters/uoml/ilshenar/Ratmancave.map new file mode 100644 index 0000000..3acc521 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Ratmancave.map @@ -0,0 +1,19 @@ +############## +## By Nerun ## +############## +overrideid 2307 +overridemintime 5 +overridemaxtime 10 +## +## Ratman Cave +## +## Level 1 +## +*|Ratman|Ratmanmage|Earthelemental||||1310|1519|-28|3|5|10|50|50|1|7|7|7|0|0|0 +## +## Level 2 +## +*|Skeletalknight:Boneknight|Lavalizard|||||1224|1524|-28|3|5|10|30|30|1|5|5|0|0|0|0 +*|Skeletalknight:Boneknight|Lavalizard|||||1224|1494|-28|3|5|10|30|30|1|5|5|0|0|0|0 +*|Skeletaldragon||||||1181|1512|-68|3|5|10|10|10|1|1|0|0|0|0|0 +*|TreasureLevel3:TreasureLevel4||||||1171|1511|-68|3|5|10|5|5|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Rock.map b/Data/Monsters/uoml/ilshenar/Rock.map new file mode 100644 index 0000000..9874157 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Rock.map @@ -0,0 +1,28 @@ +############## +## By Nerun ## +############## +overrideid 2308 +overridemintime 5 +overridemaxtime 10 +## +## Rock Dungeon +## +## Level 1 +## +*|Skeleton:Wraith:Zombie||||||2188|310|-7|3|5|10|15|10|1|3|0|0|0|0|0 +## +## Level 2 +## +*|ToxicElemental||||||2220|75|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|StoneGargoyle||||||2207|113|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|TreasureLevel4||||||2185|168|-32|3|5|10|10|5|1|1|0|0|0|0|0 +*|EvilMage:Executioner||||||2229|143|-32|3|5|10|10|5|1|2|0|0|0|0|0 +*|Lich||||||2154|163|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|EvilMage:Executioner||||||2125|165|-32|3|5|10|10|5|1|2|0|0|0|0|0 +*|Lich||||||2125|137|-32|3|5|10|10|5|1|1|0|0|0|0|0 +*|ElderGazer||||||2138|97|-27|3|5|10|10|5|1|1|0|0|0|0|0 +*|EvilMage|EvilMageLord|||||2183|85|-32|3|5|10|10|5|1|1|1|0|0|0|0 +*|PoisonElemental:LichLord||||||2155|24|-32|3|5|10|10|5|1|2|0|0|0|0|0 +*|PoisonElemental:Lich|LichLord|||||2124|96|-32|3|5|10|15|8|1|2|1|0|0|0|0 +*|Executioner||||||2094|56|-32|3|5|10|10|5|1|1|0|0|0|0|0 +*|HellHound|LichLord|||||2127|29|-32|3|5|10|10|5|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Sorcerers.map b/Data/Monsters/uoml/ilshenar/Sorcerers.map new file mode 100644 index 0000000..2b50675 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Sorcerers.map @@ -0,0 +1,49 @@ +############## +## By Nerun ## +############## +overrideid 2309 +overridemintime 5 +overridemaxtime 10 +## +## Sorcerers Dungeon +## +## Level 1 +## +*|Zombie||||||427|67|-28|3|5|10|25|25|1|2|0|0|0|0|0 +*|Toxicelemental:Fireelemental:Bloodelemental||||||455|70|-28|3|5|10|10|7|1|5|0|0|0|0|0 +*|Shade|Mongbat|||||394|69|-28|3|5|10|15|10|1|2|5|0|0|0|0 +*|Gargoyle|Stonegargoyle|Lich|Shade|||447|19|-28|3|5|10|25|10|1|3|1|1|1|0|0 +*|Headlessone|Mongbat|||||431|16|-28|3|5|10|15|5|1|2|2|0|0|0|0 +*|Headlessone|Mongbat|||||462|16|-28|3|5|10|15|5|1|2|2|0|0|0|0 +*|Earthelemental||||||462|16|-28|3|5|10|15|5|1|2|0|0|0|0|0 +*|Bloodelemental||||||383|29|-28|3|5|10|10|5|1|1|0|0|0|0|0 +*|Skeleton|Boneknight|||||427|95|-28|3|5|10|15|10|1|4|2|0|0|0|0 +## +## Level 2 +## +*|Bloodelemental||||||254|20|-28|3|5|10|10|5|1|1|0|0|0|0|0 +*|Eldergazer|Gazer|Gazerlarva||||281|20|-28|3|5|10|15|10|1|1|4|2|0|0|0 +*|Balron|Daemon|||||238|48|-28|3|5|10|10|7|1|1|2|0|0|0|0 +*|Imp||||||214|67|-28|3|5|10|40|15|1|4|0|0|0|0|0 +*|Shade|Zombie|Dreadspider||||262|84|-28|3|5|10|25|15|1|1|1|1|0|0|0 +*|Gargoyle|Wyvern|Evilmage||||262|84|-28|3|5|10|15|15|1|2|1|3|0|0|0 +*|Hellhound|Bloodelemental|||||278|53|-28|3|5|10|20|10|1|6|1|0|0|0|0 +*|Dullcopperelemental||||||305|20|-28|3|5|10|20|10|1|5|0|0|0|0|0 +*|Lichlord||||||310|92|-13|3|5|10|20|20|1|2|0|0|0|0|0 +*|Poisonelemental|Bloodelemental|||||311|91|-13|3|5|10|20|20|1|1|1|0|0|0|0 +*|Gargoyle||||||336|37|-28|3|5|10|10|8|1|2|0|0|0|0|0 +*|Gargoyle||||||336|48|-28|3|5|10|10|8|1|2|0|0|0|0|0 +*|Lich:Shade||||||336|42|-28|3|5|10|15|8|1|1|0|0|0|0|0 +*|Bloodelemental||||||350|42|-28|3|5|10|10|10|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Bloodelemental||||||146|83|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Evilmagelord||||||143|70|-28|3|5|10|20|10|1|1|0|0|0|0|0 +*|Bloodelemental||||||160|59|-28|3|5|10|10|10|1|1|0|0|0|0|0 +*|Balron|Eldergazer|||||155|21|-28|3|5|10|15|10|1|2|1|0|0|0|0 +*|Efreet||||||160|9|-28|3|5|10|5|4|1|2|0|0|0|0|0 +*|Bonemagi:Skeletalmage|Mummy|||||109|44|-28|3|5|10|20|15|1|4|3|0|0|0|0 +*|Lichlord|Mummy|||||67|70|-28|3|5|10|15|15|1|2|4|0|0|0|0 +*|Boneknight:Skeletalknight||||||133|114|-28|3|5|10|25|20|1|1|0|0|0|0|0 +*|Bloodelemental||||||133|114|-28|3|5|10|20|10|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Spectre.map b/Data/Monsters/uoml/ilshenar/Spectre.map new file mode 100644 index 0000000..7e2279b --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Spectre.map @@ -0,0 +1,12 @@ +############## +## By Nerun ## +############## +overrideid 2310 +overridemintime 5 +overridemaxtime 10 +## +## Spectre Dungeon +## +## Level 1 +## +*|Skeleton|Shade|Spectre|Wraith|Ghoul|Zombie|1981|1059|-28|3|5|10|40|40|1|3|2|2|2|2|2 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Towns.map b/Data/Monsters/uoml/ilshenar/Towns.map new file mode 100644 index 0000000..1c62522 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Towns.map @@ -0,0 +1,69 @@ +############## +## By Nerun ## +############## +overrideid 2311 +overridemintime 5 +overridemaxtime 10 +## +## Towns +## +## Ancient Citadel +## +*|Skeleton||||||1517|558|5|3|5|10|35|20|1|6|0|0|0|0|0 +*|Spectre:Shade:Wraith||||||1517|552|10|3|5|10|30|15|1|6|0|0|0|0|0 +*|Ghoul|Zombie|||||1516|557|4|3|5|10|35|20|1|2|5|0|0|0|0 +*|Skeletalknight:Boneknight|Skeletalmage:Bonemagi|||||1517|552|10|3|5|10|30|15|1|3|3|0|0|0|0 +*|Lich||||||1517|541|11|3|5|10|20|10|1|2|0|0|0|0|0 +*|Lichlord||||||1517|541|61|3|5|10|10|4|1|1|0|0|0|0|0 +## +## Lakeshire +## +*|MeerWarrior:MeerCaptain:MeerMage:MeerEternal||||||1203|1138|-25|3|5|10|55|40|1|16|0|0|0|0|0 +*|Direwolf:Timberwolf||||||1127|1112|-34|3|5|10|35|25|1|7|0|0|0|0|0 +*|Snake||||||1180|1188|-25|3|5|10|15|15|1|5|0|0|0|0|0 +*|Giantserpent||||||1181|1189|-25|3|5|10|12|12|1|1|0|0|0|0|0 +## +## Mistas +## +*|Ogre|Ogrelord|Ratman|Ratmanmage|Ratmanarcher||817|1065|-30|3|5|10|70|60|1|5|2|10|5|4|0 +## +## Montor +## +*|Phoenix|Fireelemental|Hellhound|Lavaserpent|Lavalizard|Daemon|1643|310|48|3|5|10|50|30|1|2|4|5|4|4|2 +*|Succubus|Efreet|||||1643|310|48|3|5|10|50|30|1|2|2|0|0|0|0 +*|Earthelemental|Drake|||||1665|244|93|3|5|10|25|25|1|3|2|0|0|0|0 +*|Stoneharpy|Stonegargoyle|Balron||||1715|228|78|3|5|10|10|10|1|3|2|1|0|0|0 +## +## Req Volon +## +*|Etherealwarrior||||||1363|1046|-13|3|5|10|30|15|1|4|0|0|0|0|0 +## +## Savage Camp 1 +## +*|savagerider|savage|||||1046|517|-80|3|5|10|15|15|1|3|4|0|0|0|0 +*|savageshaman||||||1046|517|-80|3|5|10|10|7|1|4|0|0|0|0|0 +*|savage|savageridgeback|||||1116|527|-80|3|5|10|15|15|1|1|1|0|0|0|0 +*|bird||||||1110|542|-77|3|5|10|25|25|1|3|0|0|0|0|0 +*|bird||||||1108|492|-80|3|5|10|25|25|1|3|0|0|0|0|0 +*|hind|greathart|blackbear|direwolf|||1110|542|-77|3|5|10|25|25|1|2|1|1|1|0|0 +*|hind|greathart|blackbear|direwolf|||1108|492|-80|3|5|10|25|25|1|2|1|1|1|0|0 +## +## Savage Camp 2 +## +*|savage||||||1161|668|-80|3|5|10|5|5|1|1|0|0|0|0|0 +*|savage||||||1181|691|-80|3|5|10|4|4|1|1|0|0|0|0|0 +*|savage||||||1187|685|-80|3|5|10|4|4|1|1|0|0|0|0|0 +*|savage||||||1191|696|-80|3|5|10|7|5|1|1|0|0|0|0|0 +*|savagerider||||||1191|696|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|savage||||||1203|762|-80|3|5|10|10|10|1|3|0|0|0|0|0 +*|savageshaman||||||1234|760|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|savage|savagerider|||||1213|719|-80|3|5|10|10|10|1|3|1|0|0|0|0 +*|savage||||||1214|744|-80|3|5|10|10|10|1|4|0|0|0|0|0 +*|savage|savageshaman|||||1231|694|-80|3|5|10|10|10|1|2|1|0|0|0|0 +*|savage||||||1251|703|-80|3|5|10|10|10|1|3|0|0|0|0|0 +*|savage||||||1274|728|-80|3|5|10|10|10|1|1|0|0|0|0|0 +*|savage||||||1292|755|-80|3|5|10|4|4|1|1|0|0|0|0|0 +*|savage||||||1280|770|-80|3|5|10|7|7|1|1|0|0|0|0|0 +*|ridgeback||||||1279|781|-80|3|5|10|5|5|1|2|0|0|0|0|0 +*|savage|savageshaman|savagerider||||1243|732|-80|3|5|10|10|10|1|1|3|1|0|0|0 +*|savage||||||1262|758|-80|3|5|10|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/TwistedWeald.map b/Data/Monsters/uoml/ilshenar/TwistedWeald.map new file mode 100644 index 0000000..9569781 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/TwistedWeald.map @@ -0,0 +1,25 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2314 +overridemap 3 +overridemintime 5 +overridemaxtime 10 +## +## Twisted Weald +## +*|CuSidhe:DryadA:Changeling:Satyr|DireWolf|||||2171|1181|-44|3|5|10|20|20|1|8|2|0|0|0|0 +*|LadyLissith:LadySabrix||||||2177|1210|-60|3|5|10|10|10|1|2|0|0|0|0|0 +*|Quagmire:WhippingVine:Irk||||||2138|1212|-60|3|5|10|20|20|1|8|0|0|0|0|0 +*|Swoop||||||2224|1218|13|3|5|10|8|8|1|1|0|0|0|0|0 +*|Gnaw:DireWolf||||||2134|1174|-46|3|5|10|5|5|1|5|0|0|0|0|0 +*|CuSidhe||||||2206|1220|-8|3|5|10|20|20|1|2|0|0|0|0|0 +*|Corpser:spite:guile||||||2159|1223|-60|3|5|10|10|10|1|5|0|0|0|0|0 +*|Malefic:Virulent||||||2170|1247|-60|3|5|10|10|10|1|4|0|0|0|0|0 +*|Changeling||||||2163|1189|-48|3|5|10|8|8|1|2|0|0|0|0|0 +*|Cusidhe:Dryada:changeling:Satyr|DireWolf|||||2207|1180|-36|3|5|10|25|25|1|12|3|0|0|0|0 +*|silk||||||2137|1216|-60|3|5|10|5|5|1|4|0|0|0|0|0 +*|giantblackwidow||||||2177|1229|-60|3|5|10|5|5|1|4|0|0|0|0|0 +*|virulent||||||2157|1206|-60|3|5|10|5|5|1|3|0|0|0|0|0 +*|malefic||||||2167|1266|-60|3|5|10|5|5|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Vendors.map b/Data/Monsters/uoml/ilshenar/Vendors.map new file mode 100644 index 0000000..2346f69 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Vendors.map @@ -0,0 +1,55 @@ +############## +## By Nerun ## +############## +overrideid 2312 +overridemintime 5 +overridemaxtime 10 +## +*|stonecrafter||||||791|618|0|3|2|10|5|0|314|1|0|0|0|0|0 +*|armorer|weaponsmith|||||808|697|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|armorer|weaponsmith|||||808|586|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|gypsyanimaltrainer||||||1225|563|-18|3|2|10|5|0|314|1|0|0|0|0|0 +*|gypsyanimaltrainer||||||1388|428|-23|3|2|10|5|0|314|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1497|614|-14|3|2|10|5|0|314|1|1|0|0|0|0 +*|banker|minter|||||854|680|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|banker|minter|||||855|603|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||766|641|0|3|2|10|5|0|314|1|1|0|0|0|0 +*|gypsybanker||||||1226|554|-12|3|2|10|5|0|314|1|0|0|0|0|0 +*|banker|minter|||||1610|556|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|provisioner|cobbler|||||826|679|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|provisioner|cobbler|||||824|602|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|gypsymaiden||||||1400|434|-11|3|2|10|5|0|314|1|0|0|0|0|0 +*|innkeeper||||||665|665|-35|3|2|10|5|0|314|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1364|1051|-13|3|2|10|5|0|314|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1261|582|-18|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||284|536|-24|3|2|10|5|0|314|1|1|0|0|0|0 +*|fortuneteller||||||1235|543|-15|3|2|10|5|0|314|1|0|0|0|0|0 +*|fortuneteller||||||1407|428|-8|3|2|10|5|0|314|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1628|548|-11|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1518|619|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1093|955|-38|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||872|586|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|innkeeper||||||1620|554|-20|3|2|10|5|0|314|1|0|0|0|0|0 +*|jeweler||||||1605|541|-13|3|2|10|5|0|314|1|0|0|0|0|0 +*|jeweler||||||859|698|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|scribe||||||868|657|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|scribe||||||869|625|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|gypsybanker||||||1405|439|2|3|2|10|5|0|314|1|0|0|0|0|0 +*|fortuneteller||||||1394|441|13|3|2|10|5|0|314|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1505|611|-19|3|2|10|5|0|314|1|1|1|0|0|0 +*|innkeeper||||||774|1144|-30|3|2|10|5|0|314|1|0|0|0|0|0 +*|provisioner|cobbler|||||1598|539|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||369|1432|15|3|2|10|5|0|314|1|1|0|0|0|0 +*|provisioner|cobbler|||||1318|1328|-14|3|2|10|5|0|314|1|1|0|0|0|0 +*|tailor|weaver|||||896|610|-40|3|2|10|5|0|314|1|1|0|0|0|0 +*|tailorguildmaster||||||896|610|-40|3|2|10|5|0|314|1|0|0|0|0|0 +*|animaltrainer||||||1499|619|-19|3|2|10|5|0|314|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1600|552|-16|3|2|10|5|0|314|1|1|1|0|0|0 +*|mage|glassblower|mageguildmaster||||840|571|0|3|2|10|5|0|314|1|1|1|0|0|0 +*|innkeeper||||||840|707|0|3|2|10|5|0|314|1|0|0|0|0|0 +*|tinker|tinkerguildmaster|||||1253|588|-19|3|2|10|5|0|314|1|1|0|0|0|0 +*|innkeeper||||||1566|1049|-8|3|2|10|5|0|314|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||792|665|0|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||575|537|-69|3|2|10|5|0|314|1|1|0|0|0|0 +*|healer|healerguildmaster|||||682|297|-41|3|2|10|5|0|314|1|1|0|0|0|0 +*|baker||||||1514|611|-14|3|2|10|5|0|314|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/ilshenar/Wisp.map b/Data/Monsters/uoml/ilshenar/Wisp.map new file mode 100644 index 0000000..e18a635 --- /dev/null +++ b/Data/Monsters/uoml/ilshenar/Wisp.map @@ -0,0 +1,53 @@ +############## +## By Nerun ## +############## +overrideid 2313 +overridemintime 5 +overridemaxtime 10 +## +## Wisp Dungeon +## +## Level 1 +## +*|Wisp||||||681|1535|-28|3|5|10|60|40|1|20|0|0|0|0|0 +## +## Level 2 +## +## no monsters +## +## Level 3 +## +*|Skeletalmage||||||855|1567|-28|3|5|10|6|6|1|1|0|0|0|0|0 +*|Shade||||||855|1566|-28|3|5|10|10|6|1|1|0|0|0|0|0 +*|Rottingcorpse||||||851|1498|-28|3|5|10|20|5|1|1|0|0|0|0|0 +*|Shade|Boneknight|Bonemagi||||827|1479|-28|3|5|10|15|10|1|2|2|2|0|0|0 +*|Shade|Boneknight|Bonemagi||||888|1471|-28|3|5|10|20|12|1|3|3|2|0|0|0 +*|Evilmagelord||||||901|1507|2|3|5|10|10|10|1|2|0|0|0|0|0 +*|Evilmage||||||871|1531|-28|3|5|10|10|6|1|3|0|0|0|0|0 +*|Rottingcorpse||||||891|1537|-28|3|5|10|10|6|1|1|0|0|0|0|0 +*|Evilmage|Evilmagelord|||||888|1568|-28|3|5|10|15|10|1|1|2|0|0|0|0 +## +## Level 4 +## +## no monsters +## +## Level 5 +## +*|Imp||||||939|1531|-28|3|5|10|10|5|1|2|0|0|0|0|0 +*|Imp||||||939|1492|-28|3|5|10|10|5|1|1|0|0|0|0|0 +*|Ettin||||||961|1502|-28|3|5|10|10|6|1|2|0|0|0|0|0 +*|Wraith:Spectre:Shade||||||962|1480|-28|3|5|10|15|10|1|4|0|0|0|0|0 +*|Titan|Cyclops|||||1000|1512|0|3|5|10|15|15|1|2|3|0|0|0|0 +*|Lich||Wraith:Spectre:Shade||||959|1530|-28|3|5|10|10|7|1|1|2|0|0|0|0 +*|Balron||||||936|1559|-22|3|5|10|25|10|1|1|0|0|0|0|0 +*|Lichlord||||||964|1554|-28|3|5|10|10|7|1|1|0|0|0|0|0 +## +## Level 6 and 7 +## +## no monsters +## +## Level 8 +## +*|Balron||||||775|1479|-28|3|5|10|15|15|1|2|0|0|0|0|0 +*|Imp||||||775|1480|-28|3|5|10|40|40|1|5|0|0|0|0|0 +*|TreasureLevel1:TreasureLevel2|TreasureLevel3:TreasureLevel4|||||776|1480|-28|3|30|60|3|3|1|9|6|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/Citadel.map b/Data/Monsters/uoml/malas/Citadel.map new file mode 100644 index 0000000..43f8682 --- /dev/null +++ b/Data/Monsters/uoml/malas/Citadel.map @@ -0,0 +1,26 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2406 +overridemap 4 +overridemintime 5 +overridemaxtime 10 +## +## Citadel +## +*|serpentsfangassassin:tigersclawthief||||||179|1869|0|4|5|10|10|10|1|4|0|0|0|0|0 +*|magedragonsflamemage||||||185|1920|0|4|5|10|7|7|1|2|0|0|0|0|0 +*|serpentsfangassassin:dragonsflamemage||||||155|1869|0|4|5|10|10|10|1|4|0|0|0|0|0 +*|serpentsfangassassin:tigersclawthief:eliteninjawarrior||||||145|1898|0|4|5|10|25|25|1|3|0|0|0|0|0 +*|serpentsfangassassin:dragonsflamemage:eliteninjawarrior||||||174|1900|0|4|5|10|20|20|1|5|0|0|0|0|0 +*|serpentsfangassassin:tigersclawthief:dragonsflamemage:eliteninjawarrior||||||181|1883|0|4|5|10|5|5|1|8|0|0|0|0|0 +*|dragonsflamemage:serpentsfangassassin||||||183|1961|0|4|5|10|20|20|1|2|0|0|0|0|0 +*|serpentsfangassassin:tigersclawthief:magedragonsflamemage:dragonsflamemage:eliteninjawarrior||||||139|1868|0|4|5|10|8|8|1|7|0|0|0|0|0 +*|serpentsfangassassin:serpentsfanghighexecutioner||||||170|1974|0|4|5|10|5|5|1|3|0|0|0|0|0 +*|magedragonsflamemage:serpentsfangassassin||||||140|1974|0|4|5|10|8|8|1|2|0|0|0|0|0 +*|magedragonsflamemage:dragonsflamemage||||||134|1947|0|4|5|10|7|7|1|2|0|0|0|0|0 +*|eliteninjawarrior:serpentsfangassassin:dragonsflamemage||||||81|1892|0|4|5|10|5|5|1|4|0|0|0|0|0 +*|tigersclawthief||||||142|1921|0|4|5|10|5|5|1|4|0|0|0|0|0 +*|dragonsflamemage:eliteninjawarrior||||||77|1883|0|4|5|10|5|5|1|4|0|0|0|0|0 +*|serpentsfangassassin:eliteninjawarrior||||||82|1875|0|4|5|10|5|5|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/Doom.map b/Data/Monsters/uoml/malas/Doom.map new file mode 100644 index 0000000..cd888c7 --- /dev/null +++ b/Data/Monsters/uoml/malas/Doom.map @@ -0,0 +1,57 @@ +####################### +## By Matador Doid�o ## +## Adapted by Nerun ## +####################### +overrideid 2401 +## +## Dungeon Doom +## +## Doom Main +## +*|patchworkskeleton|vampirebat|||||379|147|-1|4|1|2|40|40|1|10|10|0|0|0|0 +*|skeleton|boneknight|||||372|201|-1|4|1|2|20|20|1|3|1|0|0|0|0 +*|bonedemon||||||442|205|-1|4|20|40|30|30|1|1|0|0|0|0|0 +*|patchworkskeleton|vampirebat|||||442|205|-1|4|1|2|30|30|1|6|5|0|0|0|0 +*|lich||||||480|227|-1|4|3|5|20|20|1|2|0|0|0|0|0 +*|lichlord||||||480|227|-1|4|5|10|20|20|1|1|0|0|0|0|0 +*|skeleton||||||480|227|-1|4|1|2|20|20|1|3|0|0|0|0|0 +*|skeleton||||||493|202|-1|4|1|2|12|12|1|6|0|0|0|0|0 +*|devourer|boneknight|||||479|168|-1|4|2|3|20|20|1|3|1|0|0|0|0 +*|skeleton||||||479|168|-1|4|1|2|20|20|1|5|0|0|0|0|0 +*|lich||||||468|141|-1|4|1|3|6|6|1|2|0|0|0|0|0 +*|skeleton|mummy|||||487|118|-1|4|1|2|8|8|1|3|2|0|0|0|0 +*|patchworkskeleton||||||496|75|0|4|1|2|8|8|1|3|0|0|0|0|0 +*|vampirebat||||||496|75|0|4|1|2|10|10|1|4|0|0|0|0|0 +*|skeleton||||||447|25|-1|4|1|2|10|10|1|6|0|0|0|0|0 +*|lich||||||447|25|-1|4|1|2|15|15|1|2|0|0|0|0|0 +*|patchworkskeleton|lich|||||470|30|-2|4|1|2|20|20|1|4|2|0|0|0|0 +*|fleshgolem|devourer|||||456|48|-1|4|1|2|15|15|1|6|6|0|0|0|0 +*|vampirebat||||||395|33|-1|4|1|2|8|8|1|4|0|0|0|0|0 +*|vampirebat|skeleton|||||356|40|-1|4|1|2|8|8|1|4|2|0|0|0|0 +*|gibberling||||||305|28|0|4|1|2|10|10|1|4|0|0|0|0|0 +*|gorefiend||||||290|28|0|4|1|2|10|10|1|4|0|0|0|0|0 +*|lichlord||||||266|26|0|4|1|2|8|5|1|2|0|0|0|0|0 +*|skeleton|bonemagi|boneknight||||309|15|0|4|1|2|10|10|1|4|2|1|0|0|0 +*|lich||||||366|13|-1|4|1|2|10|10|1|3|0|0|0|0|0 +*|skeleton|patchworkskeleton|||||323|90|-1|4|1|2|40|40|1|4|5|0|0|0|0 +*|zombie||||||320|114|-1|4|1|2|35|35|1|7|0|0|0|0|0 +*|mummy||||||320|114|-1|4|1|2|25|25|1|3|0|0|0|0|0 +*|lich||||||330|136|0|4|1|2|15|15|1|2|0|0|0|0|0 +*|lichlord||||||330|136|0|4|1|2|4|4|1|1|0|0|0|0|0 +*|patchworkskeleton|vampirebat|||||325|172|-1|4|1|2|35|35|1|3|3|0|0|0|0 +*|lichlord||||||289|154|5|4|1|2|5|5|1|1|0|0|0|0|0 +*|devourer||||||278|233|0|4|1|2|35|35|1|3|0|0|0|0|0 +*|patchworkskeleton|vampirebat|||||278|233|0|4|1|2|30|30|1|2|2|0|0|0|0 +*|lich||||||320|207|-1|4|1|2|15|15|1|2|0|0|0|0|0 +*|skeleton||||||356|234|-1|4|1|2|10|10|1|3|0|0|0|0|0 +*|devourer||||||356|234|-1|4|1|2|15|15|1|3|0|0|0|0|0 +*|devourer||||||378|236|-1|4|1|2|8|8|1|2|0|0|0|0|0 +*|lichlord|restlesssoul|||||427|256|-1|4|1|2|30|30|1|1|3|0|0|0|0 +*|rottingcorpse||||||427|256|-1|4|1|2|30|10|1|2|0|0|0|0|0 +*|rottingcorpse||||||478|206|-1|4|1|2|20|20|1|2|0|0|0|0|0 +*|patchworkskeleton|vampirebat|rottingcorpse||||443|128|-1|4|1|2|40|40|1|7|7|2|0|0|0 +*|lich||||||400|174|-1|4|1|2|5|5|1|1|0|0|0|0|0 +*|skeleton||||||287|81|-1|4|1|2|30|30|1|6|0|0|0|0|0 +*|vampirebat|rottingcorpse|||||287|81|-1|4|1|2|40|40|1|6|2|0|0|0|0 +*|patchworkskeleton|rottingcorpse|||||441|78|-1|4|1|2|30|30|1|4|2|0|0|0|0 +*|vampirebat||||||382|82|-1|4|1|2|40|40|1|6|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/Labyrinth.map b/Data/Monsters/uoml/malas/Labyrinth.map new file mode 100644 index 0000000..80f9488 --- /dev/null +++ b/Data/Monsters/uoml/malas/Labyrinth.map @@ -0,0 +1,28 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2407 +overridemap 4 +overridemintime 5 +overridemaxtime 10 +## +## Labyrinth +## +*|drake:airelemental|rat:snake|||||366|1928|0|4|5|10|20|20|1|4|4|0|0|0|0 +*|minotaur|snake|||||384|1932|10|4|5|10|10|10|1|3|2|0|0|0|0 +*|miasma||||||335|1920|0|4|5|10|5|5|1|1|0|0|0|0|0 +*|wanderinghealer||||||1740|990|-80|4|5|10|15|15|1|1|0|0|0|0|0 +*|Scorpion|Snake|||||1742|990|-84|4|5|10|12|12|1|6|4|0|0|0|0 +*|minotaur:minotaurscout||||||336|1891|0|4|5|10|12|12|1|5|0|0|0|0|0 +*|rend||||||357|1898|5|4|5|10|10|10|1|1|0|0|0|0|0 +*|squirrel:rat||||||346|1959|0|4|5|10|10|10|1|4|0|0|0|0|0 +*|minotaurscout:minotaur:minotaurcaptain|squirrel:tropicalbird:bird:cat|||||392|1917|0|4|5|10|20|20|1|11|9|0|0|0|0 +*|eagle:cat:bird:tropicalbird||||||390|1883|0|4|5|10|10|10|1|8|0|0|0|0|0 +*|reptalon:minotaur||||||355|1918|0|4|5|10|20|20|1|6|0|0|0|0|0 +*|tropicalbird:bird||||||346|1910|0|4|5|10|12|12|1|6|0|0|0|0|0 +*|minotaurcaptain:minotaur:minotaurscout|rat:tropicalbird|||||427|1923|5|4|5|10|15|15|1|6|4|0|0|0|0 +*|tropicalbird:eagle:rat:bird|minotaurscout|||||348|1948|0|4|5|10|15|15|1|12|4|0|0|0|0 +*|pyre||||||415|1897|5|4|5|10|5|5|1|1|0|0|0|0|0 +*|flurry:grim:mistral:tempest||||||347|1888|5|4|5|10|20|20|1|4|0|0|0|0|0 +*|meraktus||||||382|1913|0|4|5|10|5|5|1|0|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/North.map b/Data/Monsters/uoml/malas/North.map new file mode 100644 index 0000000..a6f358b --- /dev/null +++ b/Data/Monsters/uoml/malas/North.map @@ -0,0 +1,40 @@ +############## +## By Nerun ## +############## +overrideid 2402 +overridemintime 5 +overridemaxtime 10 +## +## North Malas +## +## Crystal Forest +## +## birds = mutatch, nightingale and finch +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|Rabbit|1674|659|-84|4|5|10|120|100|1|3|3|3|2|1|3 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|Rabbit|1434|607|-89|4|5|10|120|100|1|3|3|3|2|1|3 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|Rabbit|1194|638|-84|4|5|10|120|100|1|4|4|4|3|1|4 +*|Crystalelemental|Skitteringhopper|Bird|Hind|Greathart|Rabbit|920|356|-85|4|5|10|70|60|1|4|4|4|3|1|4 +## +## Ice Caves +## +## birds = kingfisher and swifts +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1659|112|-80|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1869|480|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|2121|597|-50|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1980|660|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|2233|555|-90|4|5|10|60|60|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1137|223|-50|4|5|10|40|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1381|340|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1710|403|-50|4|5|10|40|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|766|114|-90|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1206|191|-50|4|5|10|40|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|2030|500|-50|4|5|10|70|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1482|347|-50|4|5|10|60|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1023|192|-50|4|5|10|20|20|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1274|300|-50|4|5|10|40|40|1|2|1|1|1|1|1 +*|bird|walrus|snowleopard|whitewolf|icesnake|polarbear|1587|386|-50|4|5|10|40|40|1|2|1|1|1|1|1 +## +## Other +## +*|Unicorn||||||2205|145|-90|4|5|10|50|50|1|3|0|0|0|0|0 +*|Gorefiend||||||2291|295|-90|4|5|10|60|60|1|6|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/OrcForts.map b/Data/Monsters/uoml/malas/OrcForts.map new file mode 100644 index 0000000..305e063 --- /dev/null +++ b/Data/Monsters/uoml/malas/OrcForts.map @@ -0,0 +1,30 @@ +####################### +## By Matador Doid�o ## +## revised by Nerun ## +####################### +overrideid 2403 +##overridemintime 5 +##overridemaxtime 10 +## +## Orc Forts Malas (v0.1) +## +## Main Orc Fort (Near Hanse's Hotel) +*|orc|orcishmage|||||1346|1225|-90|4|5|15|25|20|1|12|4|0|0|0|0 +*|orcishlord||||||1346|1225|-90|4|10|20|25|20|1|4|0|0|0|0|0 +*|orcbrute||||||1346|1225|-90|4|25|35|25|20|1|2|0|0|0|0|0 +*|orcbomber||||||1346|1225|-90|4|15|25|25|20|1|3|0|0|0|0|0 +## Orc Fort #1 +*|orc|orcishlord|||||911|194|-79|4|5|15|15|15|1|8|2|0|0|0|0 +## Orc Fort #2 +*|orc||||||1665|356|-50|4|5|15|25|10|1|6|0|0|0|0|0 +*|orcishlord|orcishmage|||||1665|356|-50|4|10|15|10|10|1|2|1|0|0|0|0 +## Orc Fort #3 +*|orc||||||1364|596|-86|4|5|15|15|15|1|8|0|0|0|0|0 +*|orcbrute||||||1364|596|-86|4|15|25|30|15|1|2|0|0|0|0|0 +## Orc Fort #4 +*|orc||||||1205|700|-88|4|5|15|15|15|1|8|0|0|0|0|0 +*|orcbrute||||||1205|700|-88|4|15|25|20|20|1|2|0|0|0|0|0 +## Orc Fort #5 +*|orc|orcishlord|||||1257|1328|-90|4|5|15|15|8|1|8|1|0|0|0|0 +## Orc Fort #6 +*|orc|orcishlord|orcishmage||||1598|1819|-110|4|5|15|25|10|1|6|2|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/South.map b/Data/Monsters/uoml/malas/South.map new file mode 100644 index 0000000..68ac44a --- /dev/null +++ b/Data/Monsters/uoml/malas/South.map @@ -0,0 +1,27 @@ +############## +## By Nerun ## +############## +overrideid 2404 +overridemintime 5 +overridemaxtime 10 +## +## South Malas +## +*|cat:dog:jackrabbit:rat|dreadspider:gazer:ghoul|lich:mummy:ogre|reaper:spectre:wraith|zombie|hind:horse|2267|1218|-85|4|5|10|180|180|1|4|3|3|2|1|2 +*|Brownbear:Grizzlybear:Blackbear|Cougar:Panther|Direwolf:Timberwolf:Greywolf|Bird:Eagle|||2267|1218|-85|4|5|10|180|180|1|1|1|1|1|0|0 +*|cat:dog:jackrabbit:rat|dreadspider:gazer:ghoul|lich:mummy:ogre|reaper:spectre:wraith|zombie|hind:horse|1943|1270|-90|4|5|10|180|180|1|4|3|3|2|1|2 +*|Brownbear:Grizzlybear:Blackbear|Cougar:Panther|Direwolf:Timberwolf:Greywolf|Bird:Eagle|||1943|1270|-90|4|5|10|180|180|1|1|1|1|1|0|0 +*|corpser|ogre:ettin|reaper:skeletalknight|skeletalmage:wraith|zombie|ghoul|2304|1258|-86|4|5|10|70|70|1|6|8|9|8|5|4 +*|gazer|greathart|hind|horse|sheep|treefellow|1471|1357|-85|4|5|10|180|180|1|4|2|6|5|4|5 +*|mummy|skeletalknight|skeletalmage|spectre|wraith|zombie|1837|1803|-110|4|5|10|100|100|1|6|6|6|7|7|8 +*|mongbat|sandvortex|scorpion|snake|spectre||2231|1605|-95|4|5|10|160|160|1|7|6|7|6|7|0 +*|mongbat|sandvortex|scorpion|snake|spectre||1641|1797|-110|4|5|10|100|100|1|2|1|1|2|1|0 +*|mongbat|sandvortex|scorpion|snake|||1899|1609|-110|4|5|10|100|100|1|6|5|6|5|0|0 +*|mongbat|sandvortex|scorpion|snake|spectre||1741|1487|-110|4|5|10|100|100|1|3|2|3|3|2|0 +*|pixie||||||881|927|-90|4|5|10|30|30|1|6|0|0|0|0|0 +*|titan|horse|||||769|1277|-90|4|5|10|220|220|1|3|6|0|0|0|0 +*|eagle||||||761|1283|-90|4|5|10|200|200|1|1|0|0|0|0|0 +*|evilhealer||||||743|1280|-90|4|5|10|100|100|1|1|0|0|0|0|0 +*|evilhealer||||||2304|1258|-86|4|5|10|70|70|1|1|0|0|0|0|0 +*|hind|sheep|ettin|harpy|||771|1277|-90|4|5|10|220|220|1|8|7|7|7|0|0 +*|sheep|horse|hind||||1347|1739|-110|4|5|10|130|130|1|5|1|3|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/malas/Vendors.map b/Data/Monsters/uoml/malas/Vendors.map new file mode 100644 index 0000000..4c83f54 --- /dev/null +++ b/Data/Monsters/uoml/malas/Vendors.map @@ -0,0 +1,44 @@ +############## +## By Nerun ## +############## +overrideid 2405 +overridemintime 5 +overridemaxtime 10 +## +## Luna +## +*|banker|minter|||||989|520|-50|4|2|10|5|0|402|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||976|512|-50|4|2|10|5|0|402|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster|tanner|furtrader||976|527|-50|4|2|10|5|0|402|1|1|1|1|1|0 +*|keeperofchivalry||||||1016|514|-70|4|2|10|5|0|402|1|0|0|0|0|0 +*|keeperofchivalry||||||961|517|-70|4|2|10|5|0|402|1|0|0|0|0|0 +*|holymage|herbalist|alchemist|customhairstylist|||1004|527|-50|4|2|10|5|0|402|1|1|1|1|0|0 +*|tinker|tinkerguildmaster|carpenter|architect|realestatebroker||1003|512|-50|4|2|10|5|0|402|1|1|1|1|1|0 +*|provisioner|cobbler|jeweler||||993|511|-50|4|2|10|5|0|402|1|1|1|0|0|0 +*|innkeeper||||||989|527|-50|4|2|10|5|0|402|1|0|0|0|0|0 +*|animaltrainer||||||1027|494|-70|4|2|10|5|0|402|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1029|520|-55|4|2|10|5|0|402|1|1|0|0|0|0 +*|healer|healerguildmaster|||||950|520|-55|4|2|10|5|0|402|1|1|0|0|0|0 +## +## Umbra +## +*|blacksmith|blacksmithguildmaster|||||1977|1365|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|animaltrainer||||||1992|1315|-90|4|2|10|5|0|402|1|0|0|0|0|0 +*|provisioner|cobbler|||||2011|1326|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|baker||||||2017|1356|-90|4|2|10|5|0|402|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2027|1353|-90|4|2|10|5|0|402|1|1|1|1|0|0 +*|mage|alchemist|mageguildmaster||||2023|1379|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|herbalist|alchemist|customhairstylist||||2025|1387|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|jeweler||||||2045|1397|-90|4|2|10|5|0|402|1|0|0|0|0|0 +*|banker|minter|||||2048|1343|-85|4|2|10|5|0|402|1|1|0|0|0|0 +*|innkeeper||||||2037|1311|-85|4|2|10|5|0|402|1|0|0|0|0|0 +*|tinker|tinkerguildmaster|||||2066|1282|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2060|1283|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||2083|1322|-80|4|2|10|5|0|402|1|1|1|0|0|0 +*|tanner|furtrader|||||2078|1327|-80|4|2|10|5|0|402|1|1|0|0|0|0 +*|healer|healerguildmaster|||||2068|1372|-75|4|2|10|5|0|402|1|1|0|0|0|0 +## +## Hanse's Hotel +## +*|innkeeper||||||1056|1434|-85|4|2|10|5|0|402|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1051|1434|-85|4|2|10|5|0|402|1|1|1|1|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/tokuno/FanDancersDojo.map b/Data/Monsters/uoml/tokuno/FanDancersDojo.map new file mode 100644 index 0000000..031d7f0 --- /dev/null +++ b/Data/Monsters/uoml/tokuno/FanDancersDojo.map @@ -0,0 +1,29 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 2501 +overridemintime 5 +overridemaxtime 10 +## +*|fandancer||||||977|218|23|5|5|20|15|15|1|4|0|0|0|0|0 +*|daemon|hellhound|succubus||||78|546|-1|4|5|20|15|15|1|1|2|1|0|0|0 +*|daemon|hellhound|succubus||||110|540|-1|4|5|20|15|15|1|1|2|1|0|0|0 +*|fandancer|ronin|||||96|540|-1|4|5|20|20|15|1|1|1|0|0|0|0 +*|daemon|headlessone|||||100|499|-1|4|5|20|20|20|1|1|1|0|0|0|0 +*|daemon|headlessone|hordeminion||||64|488|-1|4|5|20|20|20|1|2|2|2|0|0|0 +*|fandancer|headlessone|hordeminion|daemon|||70|376|-1|4|5|20|30|25|1|3|3|3|1|0|0 +*|hordeminion|headlessone|||||120|415|-1|4|5|20|10|10|1|2|2|0|0|0|0 +*|headlessone||||||99|387|-1|4|5|20|10|10|1|4|0|0|0|0|0 +*|headlessone||||||123|387|-1|4|5|20|10|10|1|4|0|0|0|0|0 +*|headlessone||||||79|521|-1|4|5|20|10|5|1|3|0|0|0|0|0 +*|fandancer||||||88|332|-1|4|5|20|20|20|1|4|0|0|0|0|0 +*|hordeminion|headlessone|succubus||||97|467|-1|4|5|20|20|20|1|2|1|1|0|0|0 +*|hordeminion|headlessone|||||111|352|-1|4|5|20|10|10|1|2|2|0|0|0|0 +*|hordeminion|fandancer|oni|daemon|||173|615|-1|4|5|20|20|20|1|2|2|2|2|0|0 +*|headlessone|fandancer|||||147|646|-1|4|5|20|5|5|1|2|2|0|0|0|0 +*|hordeminion|hellcat|balron||||175|660|-1|4|5|20|20|20|1|3|2|1|0|0|0 +*|fandancer||||||142|692|-1|4|5|20|20|20|1|2|0|0|0|0|0 +*|hellhound|succubus|||||106|685|-1|4|5|20|20|20|1|1|1|0|0|0|0 +*|fandancer|hellcat|balron||||110|649|-1|4|5|20|10|10|1|1|1|1|0|0|0 +*|fandancer|hellhound|hellcat||||134|651|-1|4|5|20|5|5|1|2|1|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/tokuno/Outdoors.map b/Data/Monsters/uoml/tokuno/Outdoors.map new file mode 100644 index 0000000..958ea7a --- /dev/null +++ b/Data/Monsters/uoml/tokuno/Outdoors.map @@ -0,0 +1,221 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 2502 +overridemintime 5 +overridemaxtime 10 +## +## Original file splited in WildLife and Outdoors maps by JadeFist +## +*|kappa||||||1215|1086|25|5|5|20|30|30|1|8|0|0|0|0|0 +*|bakekitsune:hellcat||||||643|540|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|bakekitsune:hellcat:kazekemono||||||615|556|37|5|5|20|30|30|1|8|0|0|0|0|0 +*|lesserhiryu||||||1184|837|36|5|1|5|30|30|1|2|0|0|0|0|0 +*|lesserhiryu:kazekemono:oni||||||499|530|32|5|1|5|30|30|1|6|0|0|0|0|0 +*|hiryu||||||1197|813|27|5|1|5|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1247|791|6|5|1|5|30|30|1|2|0|0|0|0|0 +*|kappa||||||1345|881|13|5|5|20|30|30|1|4|0|0|0|0|0 +*|lavaserpent||||||1377|882|21|5|5|20|30|10|1|4|0|0|0|0|0 +*|ronin||||||208|641|36|5|5|20|40|30|1|4|0|0|0|0|0 +*|bakekitsune:hellcat:kazekemono:hellhound||||||582|505|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|hiryu||||||1311|776|10|5|1|5|30|30|1|1|0|0|0|0|0 +*|bakekitsune||||||554|476|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|bakekitsune:kazekemono||||||571|550|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|bakekitsune:hellcat:kazekemono||||||526|556|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|eliteninja||||||1336|810|9|5|5|20|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1344|774|19|5|1|5|30|30|1|2|0|0|0|0|0 +*|lesserhiryu||||||528|552|32|5|1|5|10|10|1|1|0|0|0|0|0 +*|oni||||||502|553|32|5|1|5|10|10|1|1|0|0|0|0|0 +*|bakekitsune||||||517|513|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|lesserhiryu:revenantlion||||||1291|695|19|5|1|5|30|30|1|2|0|0|0|0|0 +*|eliteninja||||||1354|700|33|5|5|20|30|30|1|1|0|0|0|0|0 +*|mongbat||||||273|606|7|5|5|20|30|30|1|8|0|0|0|0|0 +*|bakekitsune||||||518|477|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||159|688|24|5|5|20|40|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||157|685|25|5|5|20|30|30|1|8|0|0|0|0|0 +*|earthelemental:yomotsuwarrior||||||246|768|55|5|5|20|30|30|1|6|0|0|0|0|0 +*|ronin||||||186|534|41|5|5|20|40|30|1|4|0|0|0|0|0 +*|raiju||||||374|820|34|5|5|15|20|20|1|3|0|0|0|0|0 +*|yomotsuwarrior||||||258|709|41|5|5|20|30|30|1|6|0|0|0|0|0 +*|ronin||||||124|646|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||123|647|36|5|5|20|30|30|1|8|0|0|0|0|0 +*|yomotsuwarrior||||||356|722|54|5|5|15|30|30|1|4|0|0|0|0|0 +*|yomotsuwarrior||||||201|731|30|5|5|20|30|30|1|6|0|0|0|0|0 +*|ronin||||||181|588|45|5|5|20|40|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||180|586|45|5|5|20|30|30|1|8|0|0|0|0|0 +*|yomotsuwarrior||||||200|803|62|5|5|20|30|30|1|6|0|0|0|0|0 +*|yamandon||||||166|583|49|5|5|20|40|40|1|1|0|0|0|0|0 +*|yomotsuwarrior:kazekemono||||||190|856|52|5|5|20|30|30|1|6|0|0|0|0|0 +*|mongbat||||||206|891|56|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer||||||1008|246|37|5|5|20|30|30|1|4|0|0|0|0|0 +*|bonemagi:skeletalknight:revenantlion:boneknight:skeletalmage:skeleton||||||212|646|31|5|5|20|30|30|1|8|0|0|0|0|0 +*|mongbat||||||208|936|43|5|5|20|30|30|1|4|0|0|0|0|0 +*|yomotsuwarrior:kazekemono||||||248|928|36|5|5|20|30|30|1|6|0|0|0|0|0 +*|mongbat||||||221|968|34|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:lizardman:swamptentacle||||||192|1014|10|5|5|20|30|30|1|8|0|0|0|0|0 +*|ronin:fandancer||||||1016|292|30|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:DeathwatchBeetle:giantserpent||||||232|1116|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|ronin:fandancer:eliteninja||||||948|247|19|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:DeathwatchBeetle:giantserpent||||||285|1156|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|kappa||||||261|1186|20|5|5|20|30|10|1|4|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:DeathwatchBeetle:giantserpent||||||251|1074|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|ronin:fandancer:eliteninja||||||962|203|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer:eliteninja||||||916|225|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:evilmage||||||899|271|34|5|5|20|30|30|1|4|0|0|0|0|0 +*|runebeetle:evilmage:fandancer||||||819|208|38|5|5|20|30|30|1|4|0|0|0|0|0 +*|DeathwatchBeetle:kappa||||||248|525|41|5|5|20|20|20|1|6|0|0|0|0|0 +*|runebeetle:evilmage:fandancer||||||824|280|33|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||284|423|31|5|5|20|40|30|1|8|0|0|0|0|0 +*|eliteninja||||||265|406|22|5|5|20|40|30|1|1|0|0|0|0|0 +*|eliteninja||||||289|477|32|5|5|20|40|30|1|1|0|0|0|0|0 +*|ronin||||||326|454|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||765|189|42|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||360|466|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|mongbat||||||384|460|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|mongbat||||||418|463|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|ronin||||||425|443|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||472|433|27|5|5|20|40|30|1|8|0|0|0|0|0 +*|ronin||||||407|399|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|ronin||||||358|396|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||725|246|36|5|5|20|30|30|1|4|0|0|0|0|0 +*|runebeetle:evilmage:evilmagelord||||||769|152|12|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||323|374|32|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||773|229|64|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||415|351|28|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||789|276|56|5|5|20|40|30|1|4|0|0|0|0|0 +*|kappa:tsukiwolf||||||493|378|45|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:tsukiwolf||||||454|374|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage||||||798|377|25|5|5|20|40|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||472|336|38|5|5|20|30|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage:evilmagelord:fandancer||||||841|326|32|5|5|20|40|30|1|6|0|0|0|0|0 +*|runebeetle:ronin:fandancer||||||907|292|19|5|5|20|40|30|1|4|0|0|0|0|0 +*|yamandon||||||526|299|26|5|5|20|30|30|1|1|0|0|0|0|0 +*|tsukiwolf||||||540|343|8|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:tsukiwolf||||||527|393|53|5|5|20|30|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||566|430|35|5|5|20|30|30|1|8|0|0|0|0|0 +*|DeathwatchBeetle:deathwatchbeetlehatchling:lizardman||||||892|391|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|runebeetle:evilmage:evilmagelord||||||873|326|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||594|362|22|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:ronin||||||861|335|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|kappa:ronin||||||853|386|19|5|5|20|40|30|1|4|0|0|0|0|0 +*|raiju||||||649|409|36|5|5|20|30|30|1|2|0|0|0|0|0 +*|revenantlion:bakekitsune:oni||||||677|446|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|DeathwatchBeetle:deathwatchbeetlehatchling:lizardman||||||907|394|10|5|5|20|40|30|1|8|0|0|0|0|0 +*|DeathwatchBeetle:deathwatchbeetlehatchling:lizardman||||||927|451|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||932|364|3|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||930|405|11|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||992|383|5|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||997|407|-2|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||951|409|9|5|5|20|40|30|1|8|0|0|0|0|0 +*|ronin||||||1036|366|7|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer||||||1034|293|21|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin:fandancer||||||980|278|30|5|5|20|30|30|1|4|0|0|0|0|0 +*|ronin||||||948|522|7|5|5|20|30|30|1|4|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||918|439|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||951|467|12|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:kappa||||||1150|1072|14|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||979|477|2|5|5|20|40|30|1|8|0|0|0|0|0 +*|deathwatchbeetle:deathwatchbeetlehatchling:lizardman||||||983|448|-1|5|5|20|40|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||1051|473|7|5|5|20|20|20|1|8|0|0|0|0|0 +*|direwolf:timberwolf||||||1062|469|8|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle:runebeetle:lizardman||||||1086|452|14|5|5|20|40|30|1|4|0|0|0|0|0 +*|yamandon||||||1084|464|15|5|5|20|20|20|1|1|0|0|0|0|0 +*|kazekemono:Tsukiwolf||||||999|580|14|5|5|20|40|30|1|4|0|0|0|0|0 +*|mountaingoat:sheep||||||921|593|20|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper||||||1042|559|22|5|5|20|3|3|1|1|0|0|0|0|0 +*|reaper||||||1062|564|22|5|5|20|3|3|1|1|0|0|0|0|0 +*|tsukiwolf||||||1092|563|22|5|5|20|30|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||1146|516|21|5|5|20|30|30|1|4|0|0|0|0|0 +*|mongbat||||||192|770|56|5|5|20|40|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||1214|531|28|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper:kazekemono||||||1172|535|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|lavaserpent||||||1184|616|19|5|5|20|10|10|1|3|0|0|0|0|0 +*|kappa||||||1058|799|13|5|5|20|30|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||1181|484|22|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper:kazekemono||||||1196|507|26|5|5|20|30|30|1|4|0|0|0|0|0 +*|reaper||||||1258|531|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|tsukiwolf||||||1285|573|30|5|5|20|30|30|1|8|0|0|0|0|0 +*|revenantlion:boneknight:skeletalknight:skeletalmage:bonemagi||||||1321|619|38|5|5|20|30|30|1|8|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent||||||1214|652|90|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent||||||1176|701|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent||||||1144|667|70|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellhound:fireelemental:lavaserpent:lavalizard||||||1134|705|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|hellcat:lavalizard||||||1105|753|44|5|5|20|30|30|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1021|802|0|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa||||||931|833|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1006|857|15|5|5|20|30|30|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow:dreadspider||||||980|815|15|5|5|20|30|30|1|4|0|0|0|0|0 +*|kazekemono||||||892|652|17|5|5|20|30|30|1|8|0|0|0|0|0 +*|tsukiwolf||||||968|753|3|5|5|20|30|30|1|4|0|0|0|0|0 +*|kazekemono||||||938|722|10|5|5|20|30|30|1|4|0|0|0|0|0 +*|kazekemono||||||932|685|12|5|5|20|30|30|1|4|0|0|0|0|0 +*|deathwatchbeetle:bonemagi:revenantlion:skeletalmage||||||1120|1099|25|5|5|20|30|30|1|8|0|0|0|0|0 +*|kazekemono:eliteninja||||||840|714|16|5|5|20|30|30|1|8|0|0|0|0|0 +*|hiryu||||||883|604|39|5|5|20|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1012|631|11|5|5|20|30|30|1|1|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1076|864|56|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa||||||1055|887|38|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:deathwatchbeetle||||||1052|976|26|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa:deathwatchbeetle||||||1064|1029|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|kappa||||||1092|980|33|5|5|20|30|30|1|4|0|0|0|0|0 +*|kappa:eliteninja||||||1086|910|61|5|5|20|30|30|1|4|0|0|0|0|0 +*|revenantlion||||||637|357|32|5|5|20|30|30|1|4|0|0|0|0|0 +*|oni||||||1282|898|12|5|1|5|30|30|1|2|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:deathwatchbeetle:giantserpent||||||243|1031|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||742|1012|33|5|5|20|20|20|1|6|0|0|0|0|0 +*|bakekitsune||||||662|495|28|5|5|20|30|30|1|4|0|0|0|0|0 +*|lesserhiryu||||||1293|864|-1|5|1|5|30|30|1|2|0|0|0|0|0 +*|eliteninja||||||1321|847|13|5|5|20|30|30|1|1|0|0|0|0|0 +*|lesserhiryu||||||1343|654|35|5|1|5|30|30|1|2|0|0|0|0|0 +*|yomotsuwarrior||||||294|748|55|5|5|20|30|30|1|6|0|0|0|0|0 +*|yomotsuwarrior:kazekemono||||||198|924|42|5|5|20|30|30|1|6|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:deathwatchbeetle||||||185|1046|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|kappa:lizardman:swamptentacle:deathwatchbeetle:giantserpent||||||210|1085|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|skeleton:shade:bonemagi:skeletalknight||||||581|953|33|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle||||||533|991|53|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||562|984|43|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle||||||511|956|27|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetle||||||524|934|19|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetle||||||535|918|14|5|5|20|20|20|1|2|0|0|0|0|0 +*|deathwatchbeetle||||||526|889|11|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeleton:shade:bonemagi:skeletalknight||||||573|933|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeleton:shade:bonemagi:skeletalknight||||||612|888|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetle||||||570|840|0|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeletalmage:deathwatchbeetle||||||601|930|32|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||638|866|23|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||666|896|28|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc||||||700|826|36|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc||||||715|831|36|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||725|823|24|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||771|824|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||737|853|35|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||709|877|18|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc||||||683|857|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||667|943|43|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||619|981|45|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||588|1012|62|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||644|1005|55|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||668|986|46|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||688|979|44|5|5|20|20|20|1|4|0|0|0|0|0 +*|skeleton||||||680|956|44|5|5|20|20|20|1|6|0|0|0|0|0 +*|deathwatchbeetle||||||722|916|40|5|5|20|20|20|1|6|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||729|934|42|5|5|20|20|20|1|6|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||771|979|29|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||803|961|14|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||819|944|22|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||792|920|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:deathwatchbeetlehatchling||||||794|890|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|orc:orccaptain||||||819|902|27|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||770|875|30|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling:deathwatchbeetle||||||760|941|37|5|5|20|20|20|1|4|0|0|0|0|0 +*|deathwatchbeetlehatchling||||||874|971|45|5|5|20|20|20|1|4|0|0|0|0|0 +*|giantspider:giantblackwidow||||||1105|855|50|5|5|20|30|30|1|4|0|0|0|0|0 +## +## Isamu-Jima icelands +## +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||926|145|49|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||879|128|44|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||914|55|36|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||947|103|46|5|5|20|30|30|1|2|2|1|1|1|0 +*|iceelemental:snowelemental|iceserpent:ladyofthesnow|polarbear|walrus|snowleopard||976|144|35|5|5|20|30|30|1|2|2|1|1|1|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/tokuno/TownsLife.map b/Data/Monsters/uoml/tokuno/TownsLife.map new file mode 100644 index 0000000..9b8ac52 --- /dev/null +++ b/Data/Monsters/uoml/tokuno/TownsLife.map @@ -0,0 +1,37 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 2503 +overridemintime 5 +overridemaxtime 10 +## +*|rabbit||||||667|1343|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|dog|cat|bird|rat|||756|1236|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|cat||||||712|1238|25|5|5|20|20|20|1|1|0|0|0|0|0 +*|rat||||||683|1231|25|5|5|20|20|20|1|1|0|0|0|0|0 +*|bird||||||679|1224|25|5|5|20|20|20|1|2|0|0|0|0|0 +*|bird||||||706|1208|25|5|5|20|20|20|1|2|0|0|0|0|0 +*|bird|dog|cat|rat|||721|1274|25|5|5|20|20|20|1|2|1|1|1|0|0 +*|bird||||||740|1284|25|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane|cat|||||713|1351|25|5|5|20|20|20|1|2|2|0|0|0|0 +*|bird||||||710|1350|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|rabbit|pig|crane||||636|1331|25|5|5|20|20|20|1|2|1|1|0|0|0 +*|bird||||||628|1310|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane|goat|rabbit||||625|1317|25|5|5|20|20|20|1|2|1|1|0|0|0 +*|bird|crane|rabbit||||630|1225|25|5|5|20|20|20|1|3|3|2|0|0|0 +*|bird|cat|dog||||628|1272|25|5|5|20|20|20|1|3|3|2|0|0|0 +*|bird|rat|cat|dog|||768|1192|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|rat|bird|dog|||857|1166|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|rat|bird|dog|||853|1287|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|pig|||||843|1247|25|5|5|20|20|20|1|2|2|0|0|0|0 +*|dog|rat:rabbit|horse|pig|||844|1198|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|bird|cat|jackrabbit||||812|1222|25|5|5|20|20|20|1|2|1|1|0|0|0 +*|bird|dog|cat|jackrabbit|||807|1287|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|bird|crane|jackrabbit|dog:pig|||844|1318|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|crane||||||834|1351|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|rat|bird|||||803|1338|25|5|5|20|20|20|1|2|2|0|0|0|0 +*|bird|goat|pig|horse|||770|1344|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|sheep|dog|bird|rat|||744|1347|25|5|5|20|20|20|1|1|1|1|1|0|0 +*|dog|bird|crane|sheep|||711|1322|25|5|5|20|20|20|1|2|2|2|2|0|0 +*|dog|rat|cat||||690|1288|25|5|5|20|20|20|1|2|2|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/tokuno/Vendors.map b/Data/Monsters/uoml/tokuno/Vendors.map new file mode 100644 index 0000000..5968e0d --- /dev/null +++ b/Data/Monsters/uoml/tokuno/Vendors.map @@ -0,0 +1,56 @@ +############## +## By Nerun ## +############## +overridemintime 5 +overridemaxtime 10 +overrideid 2504 +*|bardguildmaster||||||668|1254|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|blacksmith||||||773|1248|26|5|5|10|4|0|1|1|0|0|0|0|0 +*|blacksmith||||||662|1210|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|baker|butcher|cook||||703|1262|25|5|5|10|10|0|1|1|1|1|0|0|0 +*|shipwright||||||669|1266|47|5|5|10|4|0|1|1|0|0|0|0|0 +*|tanner||||||720|1211|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|carpenter||||||739|1223|45|5|5|10|4|0|1|1|0|0|0|0|0 +*|Towncrier||||||732|1256|30|5|5|10|0|0|1|1|0|0|0|0|0 +*|bowyer||||||781|1301|26|5|5|10|4|0|1|1|0|0|0|0|0 +*|animaltrainer||||||789|1278|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|armorer||||||756|1302|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|tavernkeeper||||||692|1213|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|innkeeper||||||679|1207|25|5|5|10|0|0|1|1|0|0|0|0|0 +*|tinker||||||720|1213|45|5|5|10|4|0|1|1|0|0|0|0|0 +*|tailor||||||744|1219|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|mapmaker||||||691|1264|47|5|5|10|4|0|1|1|0|0|0|0|0 +*|bard||||||675|1265|25|5|5|10|4|4|1|1|0|0|0|0|0 +*|scribe||||||689|1255|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|herbalist||||||683|1298|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|alchemist||||||702|1298|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|mage||||||695|1297|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|jeweler||||||724|1297|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|provisioner||||||730|1282|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|healer||||||781|1219|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|banker||||||729|1249|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|armorer||||||742|1304|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|weaponsmith||||||806|1308|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||749|1303|25|5|5|10|4|4|1|1|1|0|0|0|0 +*|blacksmith||||||661|1209|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|weaver||||||744|1210|25|5|5|10|4|0|1|1|0|0|0|0|0 +*|weaponsmith||||||779|1259|26|5|5|10|4|0|1|1|0|0|0|0|0 +*|noble:peasant:hirebeggar|samurai|ninja||||735|1256|30|5|5|10|80|60|1|10|10|10|0|0|0 +## +## wandering healers +## +*|wanderinghealer||||||1166|802|27|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||558|534|32|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||502|589|24|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||1177|985|38|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||399|549|15|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||226|786|57|5|1|5|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||297|637|15|5|1|5|2|2|1|1|0|0|0|0|0 +*|wanderinghealer||||||371|431|32|5|5|20|5|5|1|1|0|0|0|0|0 +*|wanderinghealer||||||763|247|71|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||1111|495|18|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||1221|494|27|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||895|519|53|5|5|20|2|2|1|1|0|0|0|0|0 +*|wanderinghealer||||||1152|936|65|5|5|20|3|3|1|1|0|0|0|0|0 +*|wanderinghealer||||||979|238|21|5|5|20|5|5|1|1|0|0|0|0|0 +*|wanderinghealer||||||248|1089|10|5|1|5|3|3|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/tokuno/WildLife.map b/Data/Monsters/uoml/tokuno/WildLife.map new file mode 100644 index 0000000..1afa3be --- /dev/null +++ b/Data/Monsters/uoml/tokuno/WildLife.map @@ -0,0 +1,191 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 2505 +overridemintime 5 +overridemaxtime 10 +## +## Original file splited in WildLife and Outdoors maps by JadeFist +## +## Animals (included gaman, crane, giant serpent) +## +*|bird|jackrabbit|||||1177|1002|34|5|5|20|30|30|1|2|2|0|0|0|0 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|629|510|32|5|5|20|30|30|1|1|2|1|1|1|2 +*|gaman|bird|jackrabbit||||1198|941|36|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit|horse|cat|dog|1141|894|57|5|5|20|30|30|1|1|1|1|1|1|1 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|623|551|32|5|5|20|30|30|1|2|2|1|1|1|1 +*|gaman|bird:jackrabbit|brownbear|horse|||1197|851|32|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|bird:jackrabbit|horse|dog|||1230|895|22|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|bird|jackrabbit||||1255|866|12|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit|horse|||1230|822|21|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|bird|jackrabbit||||1289|843|4|5|5|20|30|30|1|2|1|1|0|0|0 +*|llama|mountaingoat|||||1377|882|21|5|5|20|30|10|1|2|2|0|0|0|0 +*|gaman|bird|jackrabbit||||1299|814|9|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman||||||518|329|15|5|5|20|30|30|1|8|0|0|0|0|0 +*|gaman|bird|jackrabbit||||1263|754|-1|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit||||1311|777|9|5|5|20|30|30|1|2|1|1|0|0|0 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|551|544|32|5|5|20|30|30|1|2|2|1|1|1|1 +*|mountaingoat|hind|greathart|blackbear|brownbear|bird|502|532|32|5|5|20|30|30|1|2|2|1|1|1|1 +*|gaman|bird|jackrabbit||||1345|775|19|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|bird|jackrabbit||||1312|704|21|5|5|20|30|30|1|2|1|1|0|0|0 +*|gaman|blackbear:brownbear|bird|llama|horse|ridablellama|273|606|7|5|5|20|30|30|1|2|1|1|1|1|2 +*|sheep|bird|blackbear:brownbear||||505|474|31|5|5|20|30|30|1|3|3|2|0|0|0 +*|gaman|dog|jackrabbit||||364|565|15|5|5|20|30|30|1|3|3|2|0|0|0 +*|gaman|horse|brownbear|jackrabbit|||404|592|26|5|5|20|30|30|1|2|2|2|2|0|0 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|377|635|50|5|5|20|30|30|1|1|2|1|1|1|2 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|58|104|0|5|5|20|30|30|1|1|2|1|1|1|2 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|356|705|50|5|5|20|30|30|1|1|2|1|1|1|2 +*|gaman||||||190|856|52|5|5|20|30|30|1|6|0|0|0|0|0 +*|brownbear:blackbear|ridablellama:horse|timberwolf|direwolf|greywolf|bird:llama|324|664|29|5|5|20|30|30|1|1|2|1|1|1|2 +*|gaman|jackrabbit|horse|cat|||327|604|15|5|5|20|30|30|1|2|2|2|2|0|0 +*|bird|gaman|brownbear:blackbear|horse|||381|511|22|5|5|20|30|30|1|2|2|2|2|0|0 +*|bird|cat|brownbear:blackbear|horse|dog|jackrabbit|307|572|33|5|5|20|30|30|1|2|1|1|2|1|1 +*|bird|cat|brownbear:blackbear|horse|dog|jackrabbit|146|109|0|5|5|20|30|30|1|2|1|1|2|1|1 +*|gaman:bird|direwolf:timberwolf|blackbear:brownbear|llama:horse:ridablellama|||206|891|56|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman:bird|direwolf:timberwolf|blackbear:brownbear|llama:horse:ridablellama|||208|936|43|5|5|20|30|30|1|1|1|1|1|0|0 +*|gaman|direwolf:timberwolf|blackbear:brownbear|bird|llama|horse:ridablellama|221|968|34|5|5|20|30|30|1|2|1|1|1|1|2 +## +## REVISAR ABAIXO - NOVO FORMATO +## +*|crane:rat||||||192|1014|10|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf||||||1008|260|36|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||232|1116|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf||||||1021|297|28|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||285|1156|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||941|206|17|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane||||||261|1186|20|5|5|20|30|10|1|4|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||251|1074|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||901|264|31|5|5|20|30|30|1|8|0|0|0|0|0 +*|polarbear:walrus:snowleopard||||||926|145|49|5|5|20|30|30|1|8|0|0|0|0|0 +*|polarbear:walrus:snowleopard||||||879|128|44|5|5|20|30|30|1|8|0|0|0|0|0 +*|polarbear:walrus:snowleopard||||||914|55|36|5|5|20|30|30|1|8|0|0|0|0|0 +*|polarbear:walrus:snowleopard||||||947|103|46|5|5|20|30|30|1|8|0|0|0|0|0 +*|polarbear:walrus:snowleopard||||||976|144|35|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane||||||243|563|42|5|5|20|15|15|1|2|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||812|218|41|5|5|20|30|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:mongbat:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||384|460|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:mongbat:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||418|463|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||356|403|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1011|509|26|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman:crane||||||493|378|45|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||785|303|41|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman:crane||||||454|374|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||793|368|31|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman:crane||||||472|336|38|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||856|324|37|5|5|20|40|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||905|331|8|5|5|20|40|30|1|8|0|0|0|0|0 +*|gaman||||||527|393|53|5|5|20|30|30|1|8|0|0|0|0|0 +*|bird:sheep:gaman||||||566|430|35|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane||||||497|453|17|5|5|20|30|30|1|2|0|0|0|0|0 +*|crane||||||861|335|37|5|5|20|40|30|1|4|0|0|0|0|0 +*|sheep:mountaingoat:bird:llama:ridablellama||||||565|447|31|5|5|20|30|30|1|8|0|0|0|0|0 +*|sheep:mountaingoat:bird:llama:ridablellama||||||656|411|33|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||857|376|25|5|5|20|40|30|1|8|0|0|0|0|0 +*|crane||||||702|419|18|5|5|20|10|10|1|3|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||955|391|4|5|5|20|40|30|1|8|0|0|0|0|0 +*|bird:sheep||||||935|521|16|5|5|20|20|20|1|3|0|0|0|0|0 +*|brownbear:timberwolf:greywolf:bird:blackbear:direwolf||||||1074|529|22|5|5|20|40|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf||||||1062|469|8|5|5|20|20|20|1|4|0|0|0|0|0 +*|brownbear:timberwolf:greywolf:blackbear:direwolf||||||1122|501|19|5|5|20|40|30|1|8|0|0|0|0|0 +*|brownbear:timberwolf:greywolf:bird:blackbear:direwolf:ridablellama||||||1027|562|29|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||949|589|7|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1105|539|22|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat:sheep||||||921|593|20|5|5|20|30|30|1|4|0|0|0|0|0 +*|bird:horse||||||192|770|56|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1181|547|23|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat||||||1184|616|19|5|5|20|10|10|1|3|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||1235|506|28|5|5|20|40|30|1|8|0|0|0|0|0 +*|bird||||||1258|531|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|timberwolf:greywolf:bird||||||1307|559|31|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat||||||1176|701|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|mountaingoat||||||1144|667|70|5|5|20|30|30|1|4|0|0|0|0|0 +*|mountaingoat:llama||||||1134|705|72|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:brownbear:jackrabbit||||||1074|806|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:jackrabbit:bird||||||955|828|27|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:jackrabbit||||||1028|818|13|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:brownbear:jackrabbit||||||1101|832|37|5|5|20|30|30|1|4|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||967|755|3|5|5|20|40|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||956|705|16|5|5|20|40|30|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||911|643|15|5|5|20|40|30|1|8|0|0|0|0|0 +*|bird||||||868|660|7|5|5|20|40|30|1|4|0|0|0|0|0 +*|mountaingoat:bird:sheep:llama||||||889|516|47|5|5|20|30|30|1|4|0|0|0|0|0 +*|bird:sheep:mountaingoat||||||862|490|54|5|5|20|30|30|1|4|0|0|0|0|0 +*|horse:timberwolf:greywolf:brownbear:bird:blackbear:direwolf:llama||||||998|656|11|5|5|20|40|30|1|8|0|0|0|0|0 +*|mountaingoat||||||1065|708|17|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane:horse||||||1227|1082|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1039|952|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1052|1030|24|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit||||||1092|1024|34|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog:cat||||||1133|957|64|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane:dog||||||1088|980|30|5|5|20|30|30|1|4|0|0|0|0|0 +*|dog:bird:jackrabbit:cat||||||1091|897|69|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1056|904|23|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman||||||143|131|0|5|5|20|30|30|1|8|0|0|0|0|0 +*|sheep:mountaingoat:bird:llama:ridablellama:crane||||||687|439|26|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||823|279|33|5|5|20|30|30|1|8|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog||||||1265|927|19|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:jackrabbit||||||419|529|15|5|5|20|30|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||960|293|29|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||243|1031|13|5|5|20|30|30|1|12|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||988|335|17|5|5|20|40|30|1|8|0|0|0|0|0 +*|horse:timberwolf:greywolf:ridablellama:bird:blackbear:direwolf:llama||||||771|228|63|5|5|20|40|30|1|8|0|0|0|0|0 +*|direwolf:timberwolf:blackbear:brownbear:bird:llama:horse:ridablellama:greywolf||||||443|402|32|5|5|20|30|30|1|8|0|0|0|0|0 +*|gaman:bird:horse||||||1255|804|5|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman||||||288|652|15|5|5|20|40|40|1|8|0|0|0|0|0 +*|gaman||||||459|483|21|5|5|20|30|30|1|8|0|0|0|0|0 +*|crane:rat:bird:giantrat||||||185|1046|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|crane:rat:bird:giantrat:bullfrog:gianttoad||||||210|1085|10|5|5|20|30|30|1|12|0|0|0|0|0 +*|bird:crane:pig:goat||||||596|1289|21|5|5|20|20|20|1|8|0|0|0|0|0 +*|bird:crane:rabbit||||||566|1287|22|5|5|20|20|20|1|8|0|0|0|0|0 +*|crane:rabbit:horse||||||525|1263|24|5|5|20|20|20|1|8|0|0|0|0|0 +*|bird:dog:cat:rabbit||||||547|1240|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|crane:bird:horse||||||534|1189|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|goat:sheep:bird:rabbit||||||572|1211|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|goat:horse:rabbit:llama||||||600|1198|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|llama:rabbit:dog||||||580|1170|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|direwolf:rabbit:llama||||||567|1160|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|ridablellama:direwolf:bird||||||563|1133|43|5|5|20|20|20|1|8|0|0|0|0|0 +*|greywolf:pig:timberwolf||||||561|1101|33|5|5|20|20|20|1|8|0|0|0|0|0 +*|ridablellama:timberwolf:bird||||||550|1092|25|5|5|20|20|20|1|8|0|0|0|0|0 +*|bird||||||524|1054|18|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane||||||504|1042|24|5|5|20|20|20|1|3|0|0|0|0|0 +*|bird||||||533|991|53|5|5|20|20|20|1|2|0|0|0|0|0 +*|bird||||||526|889|11|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||612|857|15|5|5|20|20|20|1|2|0|0|0|0|0 +*|jackrabbit:bird||||||558|862|6|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:bird||||||724|831|34|5|5|20|20|20|1|4|0|0|0|0|0 +*|bird||||||771|824|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||746|814|16|5|5|20|20|20|1|2|0|0|0|0|0 +*|jackrabbit||||||683|857|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:bird:jackrabbit||||||685|891|22|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:bird||||||635|966|44|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:bird||||||591|1010|58|5|5|20|20|20|1|4|0|0|0|0|0 +*|bird||||||680|987|47|5|5|20|20|20|1|2|0|0|0|0|0 +*|crane:jackrabbit||||||722|916|40|5|5|20|20|20|1|6|0|0|0|0|0 +*|horse:dog:timberwolf||||||727|1071|39|5|5|20|20|20|1|6|0|0|0|0|0 +*|greywolf:timberwolf||||||710|1115|41|5|5|20|20|20|1|6|0|0|0|0|0 +*|direwolf:greywolf:timberwolf||||||644|1142|28|5|5|20|20|20|1|6|0|0|0|0|0 +*|ridablellama:blackbear:brownbear:bird||||||775|1127|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit||||||792|920|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||794|890|31|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||833|908|15|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:jackrabbit:bird||||||770|875|30|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||874|971|45|5|5|20|20|20|1|4|0|0|0|0|0 +*|jackrabbit:crane||||||911|1025|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|gaman:goat:bird||||||879|1038|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|bird||||||887|1072|20|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:rat||||||913|1055|19|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:pig:dog:cat||||||916|1120|17|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:rat:bird||||||883|1121|19|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||837|1075|16|5|5|20|20|20|1|4|0|0|0|0|0 +*|sheep:pig:rabbit||||||884|1152|29|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:dog:cat:sheep||||||907|1143|11|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane:cat:sheep||||||942|1170|25|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||939|1199|22|5|5|20|20|20|1|4|0|0|0|0|0 +*|crane||||||934|1233|19|5|5|20|20|20|1|4|0|0|0|0|0 +*|goat:rat||||||887|1286|13|5|5|20|20|20|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog:cat:horse||||||1139|999|48|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:jackrabbit:dog:cat:horse:crane||||||1133|1036|31|5|5|20|30|30|1|4|0|0|0|0|0 +*|gaman:bird:crane||||||1207|1037|25|5|5|20|30|30|1|4|0|0|0|0|0 +*|crane||||||1178|1076|19|5|5|20|30|30|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/tokuno/YomutsoMines.map b/Data/Monsters/uoml/tokuno/YomutsoMines.map new file mode 100644 index 0000000..ec05c4c --- /dev/null +++ b/Data/Monsters/uoml/tokuno/YomutsoMines.map @@ -0,0 +1,17 @@ +########################### +## By UltimaIX ## +## (aka Yrenwick Dragon) ## +########################### +overrideid 2506 +overridemintime 5 +overridemaxtime 10 +## +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||16|56|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||25|19|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||71|29|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||54|67|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||83|114|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||102|84|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||116|61|-1|4|5|20|30|30|1|2|2|1|1|0|0 +*|earthelemental|dullcopperelemental|yomotsuwarrior|yomotsupriest|||111|20|-1|4|5|20|30|30|1|1|1|2|2|0|0 +*|FireBeetle||||||107|23|-1|4|5|10|5|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/uoml/trammel/BlightedGrove.map b/Data/Monsters/uoml/trammel/BlightedGrove.map new file mode 100644 index 0000000..0c1b3dd --- /dev/null +++ b/Data/Monsters/uoml/trammel/BlightedGrove.map @@ -0,0 +1,20 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2101 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Blighted Grove +## +*|tangle:bogling:alligator:reaper:corpser:changeling:whippingvine||||||6507|843|0|2|5|10|10|10|1|8|0|0|0|0|0 +*|giantserpent:gianttoad:harpy:silverserpent:snake:bogling||||||6513|871|0|2|5|10|35|35|1|17|0|0|0|0|0 +##*|frighteneddryad||||||6500|875|0|2|5|10|0|0|1|1|0|0|0|0|0 +*|harpy:saliva:changeling||||||6585|878|0|2|5|10|10|10|1|7|0|0|0|0|0 +*|abscess:hydra:bogthing||||||6535|848|0|2|5|10|10|10|1|4|0|0|0|0|0 +*|insanedryad||||||6540|872|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|thrasher:swamptentacle:reaper:bogling:alligator:coil:whippingvine||||||6518|870|0|2|5|10|40|40|1|9|0|0|0|0|0 +*|insanedryad||||||6489|897|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|insanedryad||||||6518|879|0|2|5|10|5|5|1|1|0|0|0|0|0 diff --git a/Data/Monsters/uoml/trammel/BritainSewer.map b/Data/Monsters/uoml/trammel/BritainSewer.map new file mode 100644 index 0000000..74babaf --- /dev/null +++ b/Data/Monsters/uoml/trammel/BritainSewer.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 2102 +overridemap 2 +overridemintime 0 +overridemaxtime 1 +## +## Britain Sewer +## +*|sewerrat:Rat|Bullfrog|||||6049|1447|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6091|1491|10|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6048|1487|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6065|1459|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6092|1448|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6107|1452|25|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6112|1462|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6039|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6115|1491|-15|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6084|1470|5|2|5|10|15|1|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6049|1470|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6034|1467|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6059|1438|4|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6061|1490|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|sewerrat:Rat|Bullfrog|||||6041|1486|5|2|5|10|15|2|1|2|1|0|0|0|0 +*|alligator||||||6090|1483|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6077|1492|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6108|1471|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6087|1443|0|2|5|10|10|4|1|2|0|0|0|0|0 +*|alligator||||||6052|1463|0|2|5|10|25|5|1|8|0|0|0|0|0 +*|alligator||||||6037|1494|0|2|5|10|10|4|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Covetous.map b/Data/Monsters/uoml/trammel/Covetous.map new file mode 100644 index 0000000..7f6e0ea --- /dev/null +++ b/Data/Monsters/uoml/trammel/Covetous.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 2103 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Covetous Dungeon +## +## Level 1 +## +*|Harpy||||||5472|1877|0|2|1|10|25|10|1|6|0|0|0|0|0 +*|Headlessone||||||5453|1905|0|2|2|10|25|5|1|4|0|0|0|0|0 +*|Stoneharpy||||||5443|1918|0|2|2|10|30|7|1|2|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5418|1876|0|2|2|10|30|10|1|4|2|0|0|0|0 +*|Gazer|Gazerlarva|||||5411|1901|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Corpser||||||5393|1921|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5400|1937|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5452|1891|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5399|1859|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5387|1911|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Corpser||||5411|1932|0|2|2|10|7|7|1|1|2|6|0|0|0 +## +## Level 2 +## +*|Headlessone||||||5577|2006|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5593|2017|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Headlessone||||||5558|2025|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Harpy|Stoneharpy|||||5498|1998|0|2|2|10|30|15|1|8|1|0|0|0|0 +*|Giantspider|Dreadspider|||||5474|2035|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Slime||||||5469|2019|0|2|2|10|25|10|1|5|0|0|0|0|0 +*|Waterelemental||||||5445|2030|-3|2|2|10|15|15|1|2|0|0|0|0|0 +*|Giantspider|Dreadspider|||||5440|2023|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Giantspider|Dreadspider|||||5473|1991|0|2|2|10|25|9|1|2|2|0|0|0|0 +*|Gazer|Gazerlarva|Eldergazer||||5457|1971|0|2|2|10|25|15|1|4|2|1|0|0|0 +*|Corpser||||||5436|1972|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Corpser||||||5417|1975|0|2|2|10|5|5|1|3|0|0|0|0|0 +*|Gazer|Gazerlarva|||||5429|1989|0|2|2|10|25|15|1|2|2|0|0|0|0 +*|Corpser||||||5425|1992|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|Gazer||||||5388|2012|0|2|2|10|5|5|1|2|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5503|2002|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|Corpser|||||5413|2000|0|2|2|10|10|10|1|1|7|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5460|1975|0|2|1|2|7|7|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5448|2027|0|2|1|2|8|8|1|1|2|0|0|0|0 +## +## Skeleton Passage +## +*|Skeleton||||||2456|861|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2480|863|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2493|883|0|2|2|10|25|10|1|4|0|0|0|0|0 +*|Skeleton||||||2513|862|0|2|2|10|25|10|1|4|0|0|0|0|0 +## +## Level 3 +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5596|1903|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1876|0|2|2|10|25|15|1|1|1|1|2|1|1 +*|Boneknight|Skeleton|Zombie|Shade|||5603|1875|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|||5617|1861|0|2|2|10|25|8|1|3|1|1|1|0|0 +*|Boneknight|Skeleton|Zombie|Shade|TreasureLevel3|TreasureLevel4|5615|1838|0|2|2|10|25|8|1|3|1|1|1|1|2 +*|Lich|Spectre|Skeleton||||5579|1859|0|2|2|10|25|11|1|7|3|1|0|0|0 +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5560|1843|0|2|2|10|40|15|1|1|1|1|2|1|1 +## +## Undead Prison +## +*|Mummy|Shade|Skeletalknight|Skeleton:Zombie|Spectre|Wraith|5528|1808|0|2|2|10|30|15|1|1|1|1|3|1|1 +*|Rottingcorpse|TreasureLevel3|TreasureLevel4||||5504|1808|0|2|2|10|12|3|1|1|1|2|0|0|0 +## +## Dragon's Lair +## +*|Dragon|Drake|||||5452|1799|0|2|2|10|30|20|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5461|1818|0|2|1|2|8|8|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Deceit.map b/Data/Monsters/uoml/trammel/Deceit.map new file mode 100644 index 0000000..c21eab1 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Deceit.map @@ -0,0 +1,57 @@ +############## +## By Nerun ## +############## +overrideid 2104 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Deceit Dungeon +## +## Level 1 +## +*|Mummy|Skeleton|Zombie||||5187|603|0|2|2|10|35|18|1|1|3|1|0|0|0 +*|Waterelemental||||||5186|575|0|2|2|10|12|8|1|2|0|0|0|0|0 +*|Skeleton||||||5187|545|0|2|2|10|25|6|1|2|0|0|0|0|0 +*|Mummy|Skeleton|Zombie||||5163|567|0|2|2|10|25|6|1|1|3|1|0|0|0 +*|Skeleton|Zombie|||||5145|553|-40|2|2|10|35|8|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|579|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5147|598|-50|2|2|10|25|7|1|2|2|0|0|0|0 +*|Skeleton|Zombie|||||5145|622|-50|2|2|10|25|8|1|2|2|0|0|0|0 +*|Skeleton|Spectre|||||5212|531|0|2|2|10|25|8|1|2|1|0|0|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|552|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|Ghoul|Shade|Skeleton|Zombie|||5219|573|0|2|2|10|25|10|1|3|1|1|1|0|0 +*|TreasureLevel2|TreasureLevel3|||||5145|618|-50|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ghoul|Skeleton|Wraith|Zombie|||5307|546|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5327|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Skeleton|Wraith|Zombie|||5286|542|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Wraith|||||5283|583|0|2|2|10|25|10|1|2|1|0|0|0|0 +*|Ghoul|Mummy|Shade|Wraith|Zombie||5318|578|0|2|2|10|25|10|1|1|1|1|1|1|0 +*|Boneknight|Skeletalknight|||||5342|582|0|2|2|10|25|10|1|4|4|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|||5299|603|0|2|2|10|25|10|1|1|1|2|1|0|0 +*|Bonemagi||||||5295|623|-5|2|2|10|10|6|1|3|0|0|0|0|0 +*|Ghoul|Shade|Skeleton|Wraith|Zombie||5322|626|0|2|2|10|25|15|1|1|1|2|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5323|571|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## Level 3 +## +*|Ghoul|Shade|Spectre|Wraith|||5139|661|0|2|2|10|25|15|1|1|1|1|1|0|0 +*|Lich||||||5190|655|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5170|678|0|2|2|10|25|10|1|1|1|1|1|0|0 +*|Ghoul|Lich|Spectre|Wraith|||5151|718|0|2|2|10|25|10|1|1|3|1|1|0|0 +*|Ghoul|Poisonelemental|||||5192|695|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Poisonelemental|||||5183|727|0|2|2|10|20|10|1|1|1|0|0|0|0 +*|Ghoul|Shade|Spectre|Wraith|||5212|674|-20|2|2|10|25|12|1|1|1|1|1|0|0 +*|Lich||||||5219|734|-20|2|2|10|25|15|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5150|742|0|2|2|10|15|3|1|1|2|2|0|0|0 +## +## Level 4 +## +*|Ghoul|Lich|||||5307|675|-20|2|2|10|25|10|1|2|1|0|0|0|0 +*|Fireelemental||||||5280|675|8|2|2|10|25|10|1|2|0|0|0|0|0 +*|Lich||||||5320|708|0|2|2|10|25|10|1|2|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|Lich|Lichlord|Silverserpent||5314|748|-20|2|2|10|25|8|1|1|2|3|1|2|0 +*|TreasureLevel2|TreasureLevel3|Lich||||5267|690|0|2|2|10|35|2|1|1|2|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Despise.map b/Data/Monsters/uoml/trammel/Despise.map new file mode 100644 index 0000000..d2a9913 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Despise.map @@ -0,0 +1,63 @@ +############## +## By Nerun ## +############## +overrideid 2105 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Despise Dungeon +## +## Note: Acidelemental do not exist then i used Toxicelemental instead. +## +## Level 1 +## +*|Lizardman|TreasureLevel2|TreasureLevel3||||5503|529|60|2|2|10|25|12|1|5|1|1|0|0|0 +*|Lizardman||||||5504|597|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5464|600|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5435|589|47|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5410|611|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman|TreasureLevel2|TreasureLevel3||||5386|612|45|2|2|10|25|12|1|5|1|2|0|0|0 +*|Lizardman||||||5405|576|61|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5411|541|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|Lizardman||||||5460|526|60|2|2|10|25|12|1|5|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5394|525|65|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5390|587|45|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Ettin||||||5490|676|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Ettin||||||5483|711|15|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental|Ettin|||||5505|747|5|2|2|10|25|18|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5475|748|5|2|2|10|25|12|1|3|2|0|0|0|0 +*|Earthelemental|Ettin|||||5420|746|5|2|2|10|25|18|1|4|6|0|0|0|0 +*|Ettin||||||5385|703|15|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|660|20|2|2|10|25|12|1|4|0|0|0|0|0 +*|Earthelemental||||||5441|680|20|2|2|10|25|12|1|6|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5507|656|20|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5387|697|15|2|1|2|5|5|1|1|4|0|0|0|0 +## +## Level 3 +## +*|Troll||||||5439|851|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5470|860|45|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5426|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Troll||||||5482|791|60|2|2|10|25|12|1|3|0|0|0|0|0 +*|Ogre||||||5532|787|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogre||||||5604|789|60|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ogrelord||||||5558|824|45|2|2|10|25|12|1|5|0|0|0|0|0 +*|Ogre||||||5590|871|45|2|2|10|35|20|1|3|0|0|0|0|0 +*|Ogre||||||5528|902|30|2|2|10|25|15|1|3|0|0|0|0|0 +*|Ettin||||||5487|902|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5504|939|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Cyclops||||||5471|973|15|2|2|10|25|18|1|3|0|0|0|0|0 +*|Ettin||||||5426|943|20|2|2|10|25|15|1|4|0|0|0|0|0 +*|Ettin||||||5391|905|30|2|2|10|25|15|1|4|0|0|0|0|0 +*|Toxicelemental||||||5398|996|5|2|2|10|25|15|1|3|0|0|0|0|0 +*|TreasureLevel2||||||5593|794|60|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5546|888|30|2|1|2|8|8|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5397|995|5|2|1|2|10|10|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5605|799|60|2|1|2|10|10|1|3|0|0|0|0|0 +*|TreasureLevel3||||||5557|828|45|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5398|995|5|2|1|2|10|10|1|2|0|0|0|0|0 +*|TreasureLevel4||||||5564|821|45|2|1|2|5|5|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Destard.map b/Data/Monsters/uoml/trammel/Destard.map new file mode 100644 index 0000000..71a7c64 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Destard.map @@ -0,0 +1,55 @@ +############## +## By Nerun ## +############## +overrideid 2106 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Destard Dungeon +## +## Level 1 - First Big Lair (entrance) +## +*|Dragon|Drake|Wyvern||||5209|965|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|||||5247|956|-40|2|2|10|50|30|1|1|2|0|0|0|0 +*|Dragon|Drake|Wyvern||||5280|955|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5284|926|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5214|917|-40|2|2|10|50|30|1|1|2|1|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5241|945|-40|2|1|2|10|10|1|1|2|0|0|0|0 +## +## Level 1 - Left Arm +## +*|Giantserpent||||||5161|940|0|2|2|10|50|20|1|6|0|0|0|0|0 +*|Wyvern|Dragon|Drake||||5149|907|0|2|2|10|20|15|1|1|1|1|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5141|915|0|2|1|2|25|25|1|1|2|0|0|0|0 +## +## Level 1 - Right Arm +## +*|Waterelemental||||||5352|934|-5|2|2|10|10|10|1|4|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5317|980|0|2|1|2|7|7|1|1|2|0|0|0|0 +## +## Level 1 - Second Big Lair (near Shrine) +## +*|Giantserpent||||||5250|869|0|2|2|10|50|30|1|6|0|0|0|0|0 +*|Dragon|Drake|Wyvern||||5226|826|0|2|2|10|50|30|1|1|2|1|0|0|0 +*|Dragon|Drake|Wyvern||||5269|811|7|2|2|10|50|30|1|1|2|1|0|0|0 +*|Drake|Wyvern|||||5307|815|0|2|2|10|50|30|1|1|1|0|0|0|0 +*|Waterelemental||||||5294|842|0|2|2|10|50|30|1|4|0|0|0|0|0 +*|Waterelemental||||||5203|787|5|2|2|10|25|12|1|4|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||5229|841|1|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3||||||5205|778|0|2|1|2|7|7|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Drake|Shadowwyrm|Wyvern||||5141|834|0|2|2|10|50|30|1|1|1|1|0|0|0 +*|Daemon|Evilmage|||||5169|836|0|2|2|10|50|30|1|2|1|0|0|0|0 +*|Drake|Shadowwyrm|Wyvern||||5152|869|0|2|2|10|50|25|1|1|1|1|0|0|0 +*|TreasureLevel4:TreasureLevel3:TreasureLevel2||||||5153|842|0|2|1|2|40|40|1|4|0|0|0|0|0 +## +## Level 3 - Ancient Wyrm Lair +## +*|Fireelemental||||||5141|968|0|2|2|10|10|10|1|1|0|0|0|0|0 +*|Wyvern:Wyvern:Giantserpent||||||5157|997|0|2|2|10|50|20|1|3|0|0|0|0|0 +*|Ancientwyrm||||||5185|1006|0|2|2|10|50|20|1|1|0|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5143|986|0|2|1|2|10|10|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||5183|1007|0|2|1|2|10|10|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Fire.map b/Data/Monsters/uoml/trammel/Fire.map new file mode 100644 index 0000000..7dea4e4 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Fire.map @@ -0,0 +1,73 @@ +############## +## By Nerun ## +############## +overrideid 2107 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Britain/Lost Lands +## Fire Dungeon - OSI Legends like +## +## Level 1 - Part I +## +*|Slime|Giantrat|Giantserpent||||5693|1415|38|2|5|10|20|10|1|1|2|1|0|0|0 +*|Slime||||||5695|1434|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Evilmagelord||||||5680|1438|0|2|5|10|20|10|1|2|0|0|0|0|0 +*|Giantrat|Lavasnake|Evilmage||||5733|1433|22|2|5|10|20|10|1|1|1|1|0|0|0 +*|Lavalizard||||||5787|1427|17|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5717|1465|-2|2|5|10|15|10|1|3|0|0|0|0|0 +*|Fireelemental|Lavasnake|Hellcat|Hellhound|||5744|1471|2|2|5|10|15|10|1|3|1|1|1|0|0 +*|Efreet|Lavaserpent|Hellhound|Fireelemental|||5790|1451|7|2|5|10|15|5|1|1|1|1|1|0|0 +## Graveyard +*|Lich|Bonemagi:Skeletalmage|Hellcat|Hellhound|Fireelemental|Lavalizard|5852|1468|1|2|5|10|30|25|1|4|6|1|3|2|1 +*|Lavasnake||||||5852|1468|1|2|5|10|30|25|1|1|0|0|0|0|0 +## +## Level 1 - Part II +## +*|Lavalizard||||||5859|1387|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Hellcat||||||5787|1386|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5818|1379|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5836|1364|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Lavasnake||||||5809|1332|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental||||||5859|1341|-1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Fireelemental|Efreet|Lavaserpent||||5835|1304|0|2|5|10|30|15|1|4|1|1|0|0|0 +*|Hellcat|Fireelemental|||||5867|1309|0|2|5|10|20|10|1|1|1|0|0|0|0 +## +## Level 2 +## +*|Fireelemental||||||5699|1302|1|2|5|10|15|15|1|1|0|0|0|0|0 +*|Fireelemental||||||5723|1291|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound||||||5732|1297|-1|2|5|10|20|5|1|1|0|0|0|0|0 +*|Efreet|Lavalizard|||||5667|1315|5|2|5|10|20|20|1|2|1|0|0|0|0 +*|Fireelemental|Lavaserpent|||||5747|1320|0|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lavalizard|Fireelemental|||||5717|1333|6|2|5|10|20|10|1|1|1|0|0|0|0 +*|Lich|Lichlord|||||5731|1379|0|2|5|10|7|3|1|3|1|0|0|0|0 +*|Hellhound||||||5709|1364|-1|2|5|10|20|10|1|6|0|0|0|0|0 +*|Daemon||||||5691|1347|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Hellhound|Hellcat|||||5678|1340|-2|2|5|10|30|10|1|1|1|0|0|0|0 +*|Evilmage|Hellhound|Lavasnake|Hellcat|||5651|1363|0|2|5|10|3|3|1|1|5|1|1|0|0 +*|Evilmage||||||5654|1380|0|2|5|10|5|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5689|1387|1|2|5|10|10|5|1|1|0|0|0|0|0 +*|Evilmagelord||||||5656|1412|0|2|5|10|10|0|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1402|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1403|0|2|5|10|3|3|1|1|0|0|0|0|0 +*|Hellhound||||||5651|1408|0|2|5|10|3|2|1|1|0|0|0|0|0 +*|Evilmage|Evilmagelord|||||5651|1418|0|2|5|10|3|2|1|1|1|0|0|0|0 +*|Evilmage||||||5650|1419|22|2|5|10|5|2|1|1|0|0|0|0|0 +*|Evilmage||||||5647|1439|22|2|5|10|15|1|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1443|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5651|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmage||||||5643|1435|0|2|5|10|5|3|1|1|0|0|0|0|0 +*|Evilmagelord||||||5638|1439|0|2|5|10|40|0|1|1|0|0|0|0|0 +## +## Treasures +## +*|TreasureLevel2||||||5714|1465|0|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|1390|2|2|1|2|7|7|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5679|1438|0|2|1|2|5|5|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|1465|-1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5722|1390|1|2|1|2|7|7|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5679|1439|0|2|1|2|5|5|1|2|0|0|0|0|0 +*|TreasureLevel3||||||5650|1434|0|2|1|2|2|2|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5643|1435|0|2|1|2|2|2|1|2|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Graveyards.map b/Data/Monsters/uoml/trammel/Graveyards.map new file mode 100644 index 0000000..3650f86 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Graveyards.map @@ -0,0 +1,31 @@ +############## +## By Nerun ## +############## +overrideid 2108 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Graveyards +## +## Britain Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 +## +## Jhelom Graveyard +*|Spectre:Wraith:Shade|Skeleton|Zombie||||1285|3731|0|2|5|10|15|10|1|2|3|4|0|0|0 +## +## Cove Graveyard +*|Spectre:Shade:Wraith|Lich|Skeleton|Zombie|||2438|1100|8|2|5|10|20|10|1|1|1|1|1|0|0 +## +## Moonglow Graveyard +*|Spectre:Shade:Wraith|Skeleton|Zombie||||4545|1317|8|2|5|10|20|10|1|1|1|2|0|0|0 +##*|Lich||||||4543|1314|8|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Vesper Graveyard +*|Spectre:Wraith|Skeleton|Zombie||||2758|867|0|2|5|10|20|20|1|2|3|4|0|0|0 +## +## Yew Graveyard +*|Skeleton||||||722|1119|0|2|5|10|20|20|1|10|0|0|0|0|0 +## +## Haven Graveyard +*|zombie:skeleton||||||3407|2652|48|2|5|10|15|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Hythloth.map b/Data/Monsters/uoml/trammel/Hythloth.map new file mode 100644 index 0000000..4900169 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Hythloth.map @@ -0,0 +1,102 @@ +############## +## By Nerun ## +############## +overrideid 2109 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Hythloth Dungeon +## +## Level 1 +## +*|Imp|Hellhound|||||5923|48|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|TreasureLevel1|||||5911|55|22|2|2|10|25|10|1|2|3|0|0|0|0 +*|Imp|Hellhound|||||5948|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Imp|Hellhound|||||5954|26|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Imp|Hellhound|||||5977|49|22|2|2|10|20|10|1|1|1|0|0|0|0 +*|Firegargoyle||||||5995|62|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5970|80|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle|Hellhound|||||5994|96|0|2|2|10|20|10|1|2|1|0|0|0|0 +*|Imp|Hellhound|||||5946|75|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5940|107|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5915|91|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5990|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5985|36|22|2|1|2|2|2|1|2|0|0|0|0|0 +*|TreasureLevel1||||||5989|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5983|25|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5979|26|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5981|84|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5966|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5958|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5937|65|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5921|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5972|86|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5917|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5929|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5945|78|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||5967|80|0|2|1|2|6|6|1|1|2|0|0|0|0 +## +## Level 2 +## +*|Imp|Hellhound|||||5961|169|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Daemon||||||5992|146|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5945|175|0|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5956|145|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||5917|156|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Imp|Hellhound|||||5914|195|22|2|2|10|20|10|1|2|2|0|0|0|0 +*|Gargoyle||||||5918|223|44|2|2|10|20|10|1|4|0|0|0|0|0 +*|Daemon|TreasureLevel4|||||5918|235|44|2|2|10|20|10|1|2|1|0|0|0|0 +*|Gargoyle|TreasureLevel3|||||5954|225|22|2|2|10|20|12|1|4|1|0|0|0|0 +*|Gazer|Gazerlarva|||||5986|203|44|2|2|10|25|12|1|3|2|0|0|0|0 +*|TreasureLevel1||||||5983|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5992|147|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5970|169|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5997|145|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5978|185|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5962|217|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5989|186|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5926|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Imp|Hellhound|Gargoyle||||6094|154|-22|2|2|10|20|10|1|1|1|2|0|0|0 +*|Eldergazer|Gazer|Gazerlarva||||6122|170|0|2|2|10|20|10|1|1|3|2|0|0|0 +*|Balron|Gargoyle|Gazer||||6086|178|0|2|2|10|20|10|1|1|2|2|0|0|0 +*|Daemon|Gargoyle|Gazer||||6119|219|22|2|2|10|20|10|1|2|2|2|0|0|0 +*|Gargoyle||||||6058|193|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Daemon|Stonegargoyle|||||6033|199|22|2|2|10|20|10|1|2|1|0|0|0|0 +*|Daemon|Gazer|Gazerlarva||||6052|156|0|2|2|10|20|10|1|2|3|2|0|0|0 +*|TreasureLevel2||||||6121|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6124|159|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6087|186|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6060|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6046|199|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6041|222|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6125|221|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6120|229|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6092|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6041|230|44|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6033|205|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6058|153|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Daemon|Hellhound|Imp||||6064|96|22|2|2|10|20|10|1|2|1|1|0|0|0 +*|Gargoyle||||||6081|83|21|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6084|66|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6106|67|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Firegargoyle||||||6116|86|0|2|2|10|20|10|1|2|0|0|0|0|0 +*|Gargoyle||||||6099|51|22|2|2|10|20|10|1|2|0|0|0|0|0 +*|Balron||||||6107|37|22|2|2|10|20|10|1|1|0|0|0|0|0 +*|Gazer|Imp|Stonegargoyle||||6054|45|0|2|2|10|20|10|1|1|1|1|0|0|0 +*|TreasureLevel2||||||6108|66|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||6117|81|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6058|92|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6113|92|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6107|70|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6081|44|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||6097|36|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6064|96|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6086|45|22|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||6108|36|22|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Ice.map b/Data/Monsters/uoml/trammel/Ice.map new file mode 100644 index 0000000..a5e1151 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Ice.map @@ -0,0 +1,53 @@ +############## +## By Nerun ## +############## +overrideid 2110 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Ice Dungeon +## +## Level 1 +## +*|Arcticogrelord||||||5771|224|-2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Iceserpent|Snowelemental|Ratman|Frosttroll|Frostspider||5799|188|-6|2|5|10|25|10|1|2|1|1|1|1|0 +*|Frostspider|Frostooze|Icesnake||||5867|218|-4|2|5|10|25|15|1|1|2|1|0|0|0 +*|Ratmanmage||||||5850|219|-3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Arcticogrelord||||||5814|237|0|2|5|7|15|15|1|1|0|0|0|0|0 +*|Whitewyrm||||||5752|144|9|2|2|5|10|10|1|1|0|0|0|0|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5839|159|0|2|5|10|20|15|1|1|1|1|1|1|0 +*|Frostooze|Frostspider|Iceelemental:Snowelemental|Icesnake|Frosttroll||5785|161|-6|2|5|10|20|18|1|1|1|1|1|1|0 +*|Iceserpent|Ratman|Snowelemental:Iceelemental|Frosttroll|||5757|213|-7|2|5|10|20|15|1|3|1|4|2|0|0 +*|Iceserpent|Snowelemental:Iceelemental|Frosttroll|Ratman|||5681|191|-6|2|5|10|20|15|1|3|4|1|1|0|0 +*|Iceserpent|Snowelemental:Iceelemental|||||5731|176|-5|2|5|10|35|25|1|9|9|0|0|0|0 +## Treasures +*|TreasureLevel2||||||5848|226|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5683|197|-4|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5721|147|-1|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5758|139|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5754|211|-6|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5833|242|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5854|227|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5772|188|-3|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5837|245|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5751|140|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5763|187|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5756|203|-2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5712|145|-34|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5684|181|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ratman Room +## +*|Ratman|Ratmanarcher|Ratmanmage||||5831|358|-1|2|5|10|25|15|1|12|7|5|0|0|0 +*|TreasureLevel2||||||5838|355|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5824|363|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Ice Demon Lair +## +*|Icefiend||||||5680|306|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|Icefiend||||||5669|330|0|2|5|15|20|10|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5696|303|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5682|314|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5666|331|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5676|331|0|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/LostLands.map b/Data/Monsters/uoml/trammel/LostLands.map new file mode 100644 index 0000000..3138fa4 --- /dev/null +++ b/Data/Monsters/uoml/trammel/LostLands.map @@ -0,0 +1,341 @@ +############## +## By Nerun ## +############## +overrideid 2111 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## T2A - Lost Lands +## +## Papua +## +*|Swampdragon||||||5728|3209|-3|2|5|10|100|100|1|7|0|0|0|0|0 +## +## T2ADesertMain +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5457|2651|45|2|5|10|150|150|1|15|15|6|9|6|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5457|2651|45|2|5|10|150|150|1|3|6|4|6|0|0 +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5520|2890|33|2|5|10|100|100|1|10|10|4|6|4|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5520|2890|33|2|5|10|100|100|1|3|4|2|4|0|0 +## +## T2ADesCent +## +*|Gazer|Reaper|Scorpion|Giantserpent|Troll||5580|2885|6|2|5|10|15|15|1|3|2|3|2|2|0 +## +## T2ADryCenter +## +*|Corpser|Giantspider|Troll|Harpy|Ettin|Gazer|5557|2625|0|2|5|10|40|40|1|3|3|3|6|3|3 +## +## T2ACyclop +## +*|Cyclops|Titan|||||5394|2530|6|2|5|10|25|15|1|5|3|0|0|0|0 +## +## T2ADesertFinal +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Wyvern|5711|2494|46|2|5|10|80|80|1|3|3|1|3|2|1 +*|Ettin||||||5711|2494|46|2|5|10|80|80|1|2|0|0|0|0|0 +## +## T2ABaseOph +## +*|Ophidianarchmage|Ophidianmage|Ophidianmatriarch|Ophidianknight|Ophidianwarrior||5765|2637|39|2|5|10|30|25|1|3|6|3|4|10|0 +## +## T2AWyvern +## +*|Wyvern|Drake|Imp|Mongbat|||5697|2626|-2|2|5|10|30|25|1|2|4|1|2|0|0 +## +## T2ASmallDesert +## +*|Imp|Scorpion|Desertostard|Orc|Orcishlord|Stoneharpy|5729|2767|-1|2|5|10|70|60|1|8|8|3|5|3|3 +*|Stonegargoyle|Wyvern|Mummy|Ettin|||5729|2767|-1|2|5|10|70|60|1|3|3|3|5|0|0 +## +## T2ALava +## +*|Hellhound|Lavalizard|Fireelemental|Efreet|Hellcat|Lavaserpent|5724|2949|31|2|5|10|75|65|1|8|8|10|4|6|8 +*|Lavasnake||||||5724|2949|31|2|5|10|75|65|1|15|0|0|0|0|0 +## +## T2AWyvIsle +## +*|Wyvern||||||5863|2470|46|2|5|10|25|25|1|6|0|0|0|0|0 +## +## T2AIce1 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5501|2361|27|2|5|10|75|40|1|4|8|4|4|5|5 +*|Polarbear||||||5501|2361|27|2|5|10|75|40|1|5|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5351|2359|0|2|5|10|75|40|1|4|7|4|4|5|5 +*|Polarbear||||||5351|2359|0|2|5|10|75|40|1|5|0|0|0|0|0 +## +## T2AIce2 +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5173|2368|21|2|5|10|50|30|1|4|10|4|4|3|3 +*|Polarbear||||||5173|2368|21|2|5|10|50|30|1|3|0|0|0|0|0 +## +## T2ALastIceIsle +## +*|Iceserpent|Icesnake|Snowelemental|Whitewolf|Walrus|Polarbear|6091|2379|25|2|5|10|60|30|1|6|10|3|3|3|3 +## +## T2AIceFinal +## +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5967|2370|44|2|5|10|75|50|1|6|4|4|4|4|4 +*|Polarbear||||||5967|2370|44|2|5|10|75|50|1|4|0|0|0|0|0 +*|Iceserpent|Icesnake|Frosttroll|Snowelemental|Whitewolf|Walrus|5817|2367|42|2|5|10|75|50|1|6|3|3|3|4|4 +*|Polarbear||||||5817|2367|42|2|5|10|75|50|1|4|0|0|0|0|0 +## +## T2AFor3 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5756|3453|-2|2|5|10|130|130|1|10|10|10|2|10|0 +## +## T2ASwamp +## +*|Gianttoad|Swampdragon|Giantrat|Alligator|Sewerrat|Plaguebeast|5985|3441|17|2|5|10|90|80|1|8|5|12|12|11|2 +*|Bullfrog|Swamptentacle|Bogling|Bogthing|||5985|3441|17|2|5|10|90|80|1|15|5|13|3|0|0 +## +## T2AUndead +## +*|Boneknight|Skeletalknight|Bonemagi|Skeleton|Wraith|Ghoul|5220|3664|-1|2|5|10|25|20|1|3|3|3|6|4|4 +## +## T2ASavage +## +*|Savagerider|Savage|Savageshaman||||5212|3619|0|2|5|10|15|10|1|3|9|3|0|0|0 +## +## T2ADeer +## +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5347|3449|17|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5243|3548|14|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5250|3449|16|2|5|10|50|50|1|4|8|4|4|16|4 +*|Horse|Orc|Orcishlord|Greathart|Hind|Ridablellama|5349|3547|-1|2|5|10|50|50|1|4|8|4|4|16|4 +## +## T2AWild1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5201|3162|53|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5201|3162|53|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5251|3301|-2|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5251|3301|-2|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5250|3401|1|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5250|3401|1|2|5|10|50|50|1|2|2|2|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5351|3401|30|2|5|10|50|50|1|6|4|4|2|2|2 +*|Hind|Llama|Timberwolf||||5351|3401|30|2|5|10|50|50|1|2|2|2|0|0|0 +## +## T2AWild1&2 - 1 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6018|3673|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6018|3673|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6018|3673|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6018|3673|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 2 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3773|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3773|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3773|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3773|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 3 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|2874|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|2874|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|2874|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|2874|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 4 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|6022|3971|17|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|6022|3971|17|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|6022|3971|17|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||6022|3971|17|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 5 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5920|3675|12|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5920|3675|12|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5920|3675|12|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5920|3675|12|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 6 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5921|3777|28|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5921|3777|28|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5921|3777|28|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5921|3777|28|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 7 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5919|3875|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5919|3875|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5919|3875|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5919|3875|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 8 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5918|3975|1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5918|3975|1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5918|3975|1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5918|3975|1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 9 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3675|0|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3675|0|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3675|0|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3675|0|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 10 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5820|3775|48|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5820|3775|48|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5820|3775|48|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5820|3775|48|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 11 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5818|3876|18|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5818|3876|18|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5818|3876|18|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5818|3876|18|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 12 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5819|3974|16|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5819|3974|16|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5819|3974|16|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5819|3974|16|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 13 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3675|22|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3675|22|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3675|22|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3675|22|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 14 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5722|3776|32|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5722|3776|32|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5722|3776|32|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5722|3776|32|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 15 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3876|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3876|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3876|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 16 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5721|3975|21|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5721|3975|21|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5721|3975|21|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5721|3975|21|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 17 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3676|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3676|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3676|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 18 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5621|3775|2|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5621|3775|2|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5621|3775|2|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5621|3775|2|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 19 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5623|3875|15|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5623|3875|15|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5623|3875|15|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5623|3875|15|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 20 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5624|3975|-3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5624|3975|-3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5624|3975|-3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 21 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5523|3676|45|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5523|3676|45|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5523|3676|45|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5523|3676|45|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 22 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3775|8|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3775|8|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3775|8|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3775|8|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 23 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5521|3875|-1|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5521|3875|-1|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5521|3875|-1|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild1&2 - 24 +## +*|Brownbear:Grizzlybear:Blackbear|Horse:Ridablellama|Rabbit:JackRabbit|Bird|Cougar|Greathart|5478|3587|3|2|5|10|50|50|1|3|2|2|1|1|1 +*|Hind|Llama|Timberwolf|Corpser|Ettin|Forestostard|5478|3587|3|2|5|10|50|50|1|1|1|1|1|1|2 +*|Gazer|Giantspider|Harpy|Headlessone|Lizardman|Mongbat|5478|3587|3|2|5|10|50|50|1|1|1|1|1|3|1 +*|Rat|Ratman|Reaper|Troll|||5478|3587|3|2|5|10|50|50|1|1|1|1|2|0|0 +## +## T2AWild3 +## +*|Forestostard|Ridablellama|||||5520|3939|42|2|5|10|25|25|1|3|3|0|0|0|0 +## +## T2AFrenz +## +*|Frenziedostard||||||5784|3951|20|2|5|10|35|35|1|8|0|0|0|0|0 +## +## T2ASpawner1 +## +*|Imp|Mongbat|||||5764|2585|-4|2|5|10|75|2|1|2|5|0|0|0|0 +*|Imp|Harpy|Headlessone|Scorpion|Stoneharpy|Wyvern|5838|2651|0|2|5|10|75|2|1|1|1|1|1|1|1 +## +## T2ASpawner2 +## +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5218|3786|1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5218|3786|1|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5371|3820|-2|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5371|3820|-2|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5368|3887|0|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5368|3887|0|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5367|4003|19|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5367|4003|19|2|5|10|50|50|1|4|1|0|0|0|0 +*|Rabbit:JackRabbit|Bird|Rat|Hind|Llama|Horse|5466|4005|-1|2|5|10|50|50|1|20|15|5|4|3|3 +*|Mongbat|Greathart|||||5466|4005|-1|2|5|10|50|50|1|4|1|0|0|0|0 +## +## T2ABull +## +*|Bull|Greathart|Cow||||5194|3885|-1|2|5|10|45|32|1|10|6|6|0|0|0 +*|Bull|Greathart|Cow||||5200|3895|2|2|5|10|20|10|1|2|2|2|0|0|0 +## +## T2ASheep +## +*|Sheep|Goat|Bull|Chicken|||5159|3913|1|2|2|5|10|15|10|7|1|1|1|1|0|0 +## +## T2AFor1 +## +*|Gorilla|Panther|Giantserpent|Silverserpent|Mongbat||5570|3153|14|2|5|10|80|60|1|6|6|6|1|6|0 +## +## T2AFor2 +## +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5440|3292|-4|2|5|10|62|56|1|5|5|5|5|1|0 +*|Gorilla|Panther|Giantserpent|Mongbat|Silverserpent||5566|3292|4|2|5|10|62|56|1|5|5|5|5|1|0 +## +## T2ATera1 +## +*|Terathanmatriarch|Terathanavenger|Terathandrone|Terathanwarrior|||5454|3136|-60|2|5|10|25|25|1|2|4|10|10|0|0 +## +## T2Aopp +## +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5490|3071|15|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5467|3078|-3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5446|3074|3|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5432|3079|-4|2|5|10|25|5|1|1|1|2|0|0|0 +*|Ophidianmatriarch:Ophidianarchmage|Ophidianmage|Ophidianknight:Ophidianwarrior||||5408|3077|16|2|5|10|25|5|1|1|1|2|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/OrcCaves.map b/Data/Monsters/uoml/trammel/OrcCaves.map new file mode 100644 index 0000000..5f039d8 --- /dev/null +++ b/Data/Monsters/uoml/trammel/OrcCaves.map @@ -0,0 +1,38 @@ +############## +## By Nerun ## +############## +overrideid 2112 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Britain +## Orc Caves +## +## Cave 1 +## +*|Orc|Orccaptain|Orcishlord||||5146|1995|0|2|5|15|8|8|1|1|1|1|0|0|0 +*|Orc||||||5153|1971|0|2|5|15|8|8|1|5|0|0|0|0|0 +*|Direwolf||||||5153|1961|0|2|5|15|8|8|1|2|0|0|0|0|0 +*|Orcishlord||||||5144|1960|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain||||||5141|1968|0|2|5|15|8|8|1|3|0|0|0|0|0 +## +## Cave 2 +## +*|Orc||||||5332|1365|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Noble||||||5308|1372|0|2|5|15|8|8|1|1|0|0|0|0|0 +*|Orcishlord|Orc|||||5302|1355|0|2|5|15|12|8|1|1|3|0|0|0|0 +*|Giantrat||||||5316|1332|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Direwolf||||||5331|1346|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orccaptain|Orcishlord|Orcishmage|Orcbomber|||5354|1332|0|2|5|15|8|8|1|1|1|1|1|0|0 +*|Orcbomber|Orccaptain|Orc||||5356|1304|0|2|5|15|10|8|1|1|1|2|0|0|0 +*|Orcishlord|Orcishmage|Orcbomber|Orc|||5317|1309|0|2|5|15|8|8|1|1|2|1|2|0|0 +*|Orc|Orcishmage|Orcishlord||||5300|1314|0|2|5|15|10|8|1|3|1|2|0|0|0 +*|Corpser||||||5292|1316|0|2|5|15|8|8|1|2|0|0|0|0|0 +## +## Cave 3 +## +*|Orc||||||5281|2029|0|2|5|15|8|8|1|3|0|0|0|0|0 +*|Orcbrute|Orc|||||5308|2005|0|2|5|15|12|12|1|1|4|0|0|0|0 +*|Orcbomber|Orc|||||5310|1969|0|2|5|15|12|12|1|2|2|0|0|0|0 +*|Orcbomber|Earthelemental|||||5348|2011|0|2|5|15|15|10|1|1|4|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Outdoors.map b/Data/Monsters/uoml/trammel/Outdoors.map new file mode 100644 index 0000000..a1593e9 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Outdoors.map @@ -0,0 +1,513 @@ +############## +## By Nerun ## +############## +overrideid 2113 +overridemap 2 +overridemintime 60 +overridemaxtime 60 +## +## OSI Light +## +*|hordeminion||||||3619|2814|21|2|5|10|50|50|1|17|0|0|0|0|0 +*|mongbat||||||3619|2814|21|2|5|10|50|50|1|17|0|0|0|0|0 +*|lizardman:ratman||||||1147|3524|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1266|1982|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1249|2030|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1232|2093|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1140|2087|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1089|2033|0|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:giantspider|wisp|mongbat:orc:troll||||1067|2117|5|2|60|80|30|30|1|2|1|6|0|0|0 +*|ettin:harpy:ogre:troll||||||666|1825|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||741|1838|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||733|1937|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||798|1935|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||819|1841|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||893|1861|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:harpy:ogre:troll||||||879|1956|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|ettin:ogre||||||809|1615|0|2|60|80|30|30|1|6|0|0|0|0|0 +*|orcishmage||||||4461|3106|0|2|60|80|30|30|1|5|0|0|0|0|0 +*|orc||||||4729|3485|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4519|3097|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4613|3272|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4576|3356|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4658|3376|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|orc||||||4607|3480|29|2|60|80|30|30|1|10|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3485|2595|12|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3446|2741|49|2|60|80|50|50|1|7|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3459|2655|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3379|2693|35|2|60|80|30|30|1|3|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3411|2592|44|2|60|80|40|40|1|6|0|0|0|0|0 +*|brigand:harpy:lizardman:orcishmage:orc:ratman:spectre:troll||||||3464|2503|49|2|60|80|50|50|1|7|0|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3168|629|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3172|700|8|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:ettin:ogre:waterelemental|orc:troll:lizardman|||||3173|771|0|2|60|80|30|30|1|5|5|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1473|229|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1337|293|22|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1184|217|27|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1284|433|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1203|502|30|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1300|607|15|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1200|633|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1162|704|6|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1130|830|9|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1013|980|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||848|917|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||840|1063|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||1038|1149|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||844|1235|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental:gargoyle:gazer||||||617|1326|0|2|60|80|30|30|1|3|0|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1831|449|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1832|517|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1749|474|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1636|532|22|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1743|589|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1887|591|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1810|647|0|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1631|650|16|2|60|80|60|60|1|1|8|0|0|0|0 +*|airelemental|ettin:harpy:orc|||||1723|683|6|2|60|80|60|60|1|1|8|0|0|0|0 +*|earthelemental:ratman||||||1980|832|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1905|883|-1|2|60|80|30|30|1|4|0|0|0|0|0 +*|earthelemental:ratman||||||1849|953|7|2|60|80|30|30|1|4|0|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||1001|787|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|ghoul:lich:lichlord|skeleton:zombie|||||987|725|0|2|60|80|30|30|1|3|5|0|0|0|0 +*|gargoyle:gazer||||||1912|1283|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1787|1280|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1799|1394|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1652|1400|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|gargoyle:gazer||||||1755|1474|0|2|60|80|30|30|1|4|0|0|0|0|0 +*|troll||||||1325|1071|0|2|60|80|30|30|1|10|0|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2369|3430|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2354|3503|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2503|3593|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2520|3983|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2438|3914|0|2|60|80|30|30|1|8|2|0|0|0|0 +*|alligator:lizardman:silverserpent:snake|wisp|||||2143|3953|3|2|60|80|30|30|1|8|2|0|0|0|0 +*|airelemental:gargoyle||||||868|488|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||805|483|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||839|406|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|airelemental:gargoyle||||||841|344|0|2|60|80|30|30|1|2|0|0|0|0|0 +*|lizardman:ratman||||||1131|3415|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1158|3457|0|2|60|80|30|30|1|8|0|0|0|0|0 +*|lizardman:ratman||||||1094|3482|0|2|60|80|30|30|1|8|0|0|0|0|0 +############## +## By Nerun ## +############## +overridemintime 20 +overridemaxtime 20 +## +## OSI Medium +## +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1312|613|10|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1214|617|13|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|522|19|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1226|449|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1276|431|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1231|192|6|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1143|180|14|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1191|288|11|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1295|328|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1361|275|16|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1491|238|22|2|20|30|30|30|1|11|1|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3440|405|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|375|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3327|344|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3434|316|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3382|280|9|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3322|271|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3360|218|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3390|259|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3446|213|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:lizardman:ogre:orc:troll||||||3462|136|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2589|204|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|136|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2659|147|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2621|99|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2549|86|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2478|100|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2468|144|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2485|191|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2454|248|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ettin:headlessone:lizardman:ogre:orc:troll:waterelemental|wisp|||||2533|240|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|airelemental:ettin:orc||||||2077|434|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2080|400|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2107|358|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2138|323|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2189|298|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2137|271|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2113|221|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2146|178|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2093|147|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2109|109|3|2|20|30|30|30|1|3|0|0|0|0|0 +*|airelemental:ettin:orc||||||2115|48|0|2|20|30|30|30|1|3|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1996|73|8|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1956|48|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gargoyle:gazer:orc:troll||||||1944|102|4|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:troll||||||2034|46|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2033|74|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2058|87|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2034|108|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||2000|141|1|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1965|160|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1946|186|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1922|173|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1894|197|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1908|214|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1891|226|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|ettin:troll||||||1869|265|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1626|266|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1682|252|6|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1723|252|16|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1759|259|21|2|20|30|30|30|1|2|11|0|0|0|0 +*|airelemental:waterelemental|direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:skeleton:troll|||||1804|247|0|2|20|30|30|30|1|2|11|0|0|0|0 +*|giantspider:scorpion||||||1875|906|7|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1829|874|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1852|841|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1930|864|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1883|827|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1949|824|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1987|822|0|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||2013|839|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1979|885|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1947|912|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1915|928|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1866|938|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|giantspider:scorpion||||||1838|957|-1|2|20|30|30|30|1|2|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1802|1506|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1692|1463|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1833|1245|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1726|1362|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1640|1431|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1912|1302|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1967|1296|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1898|1265|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1872|1347|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1812|1314|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1797|1393|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1862|1434|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|corpser:direwolf:ettin:ogre:reaper:skeleton:zombie||||||1877|1515|0|2|20|30|30|30|1|7|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1361|1392|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1445|1365|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1375|1330|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1474|1297|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1407|1281|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1225|1477|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1222|1418|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1244|1374|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1180|1354|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1240|1317|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1340|1268|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1305|1326|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1304|1413|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|harpy:lizardman:orc:ratman:troll||||||1300|1481|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1541|1895|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1534|1941|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1475|1958|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1435|1917|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1383|1949|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1416|1992|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1504|2007|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1447|2038|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1479|2094|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:mongbat:orc:ratman:troll||||||1525|2053|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2095|2352|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2077|2305|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||2021|2313|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1968|2346|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1947|2294|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1915|2385|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1891|2331|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1890|2270|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1873|2426|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1837|2334|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|alligator:giantserpent:lizardman:ratman:slime:snake||||||1826|2250|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2109|2989|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2089|3017|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2074|3069|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||2033|3041|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1970|3052|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1915|3050|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1866|3040|15|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1812|3036|5|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1841|3000|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1803|2981|0|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1867|2962|7|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1849|2915|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1911|2934|10|2|20|30|30|30|1|4|1|0|0|0|0 +*|ettin:ghoul:ogre:orc|wisp|||||1954|2903|30|2|20|30|30|30|1|4|1|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||851|495|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||805|463|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:direwolf:ettin:harpy:lizardman:orc:ratman:reaper||||||837|361|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1029|1969|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1080|1963|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ettin:giantspider:harpy:lizardman:ogre:orc:skeleton:spectre:troll||||||1042|1920|0|2|20|30|30|30|1|9|0|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||821|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||736|1938|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||899|1851|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||759|1828|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||672|1825|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|ghoul:giantspider:headlessone:lizardman:orc:ratman:zombie|wisp|||||892|1963|0|2|20|30|30|30|1|7|1|0|0|0|0 +*|giantspider:orc:ratman:spectre:zombie||||||815|1603|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1055|1442|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1021|1415|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1060|1375|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1004|1369|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||1037|1325|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|ettin:gazer:harpy:headlessone:ogre:troll||||||971|1308|0|2|20|30|30|30|1|6|0|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||1000|330|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||964|365|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||947|418|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|airelemental:waterelemental|corpser:Direwolf:ettin:gargoyle:gazer:harpy:lizardman:orc:ratman:reaper|||||956|452|0|2|20|30|30|30|1|2|10|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||423|1595|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||418|1665|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||480|1641|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||516|1585|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|corpser:direwolf:harpy:reaper:skeleton||||||541|1645|0|2|20|30|30|30|1|5|0|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||141|1367|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||189|1344|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||232|1350|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||278|1355|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||229|1419|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||182|1428|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||157|1487|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||204|1483|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||240|1443|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|airelemental:waterelemental|corpser:direwolf:ettin:gargoyle:gazer:harpy:orc:reaper:troll|||||269|1474|0|2|20|30|30|30|1|2|9|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4057|300|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4013|239|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3929|235|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3920|287|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4090|325|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4162|395|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4206|471|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3928|393|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||3963|508|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4066|569|0|2|20|30|80|80|1|8|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4153|601|0|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4214|655|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|polarbear:snowleopard:walrus:whitewolf||||||4264|725|1|2|20|30|30|30|1|4|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2963|3617|3|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||2966|3591|11|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3013|3591|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3024|3566|15|2|20|30|30|30|1|7|0|0|0|0|0 +*|alligator:giantserpent:lizardman:mongbat:ratman:silverserpent:snake||||||3042|3590|5|2|20|30|30|30|1|7|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2462|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2428|722|8|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2375|725|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2345|676|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2429|690|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2379|654|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2326|656|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|ettin:ghoul:headlessone:ogre:orc:orcishmage:skeleton:troll||||||2319|591|0|2|20|30|30|30|1|8|0|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||659|1318|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||579|1305|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||728|1242|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||793|1088|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||849|1262|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||909|1175|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||974|1186|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1059|1166|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||823|960|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||960|910|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1042|1024|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1147|1048|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1097|970|2|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1192|958|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1166|818|5|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1083|783|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1268|774|0|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1180|737|1|2|20|30|30|30|1|11|1|0|0|0|0 +*|corpser:ettin:ghoul:giantspider:lizardman:ogre:orc:reaper:skeleton:troll:zombie|wisp|||||1122|718|1|2|20|30|30|30|1|11|1|0|0|0|0 +############## +## By Nerun ## +############## +overridemintime 5 +overridemaxtime 10 +## +## OSI Heavy + Miscellaneous +## +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||423|1595|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||418|1665|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||480|1641|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||516|1585|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|airelemental:ettin:gargoyle:gazer:orc:troll:waterelemental||||||541|1645|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4504|1458|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4494|1426|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1434|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4456|1405|8|2|5|10|30|30|1|7|0|0|0|0|0 +*|timberwolf||||||4455|1358|10|2|5|10|30|30|1|7|0|0|0|0|0 +*|greathart|hind|||||4550|1409|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4552|1447|10|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4615|1469|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4612|1418|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4605|1365|0|2|5|10|30|30|1|2|5|0|0|0|0 +*|greathart|hind|||||4566|1359|8|2|5|10|30|30|1|2|5|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2372|210|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2355|179|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2351|148|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2345|112|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:harpy:headlessone:lizardman:ogre:orc:skeleton:troll:zombie|wisp|||||2328|67|0|2|5|10|30|30|1|9|1|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2177|3034|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:ogre:orc:ratman:skeleton:spectre:zombie||||||2143|3068|20|2|5|10|30|30|1|7|0|0|0|0|0 +## +## Northeast Britain +## +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1983|1517|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1986|1463|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|ettin:gargoyle:gazer:ogre:orc:troll:waterelemental||||||1969|1409|0|2|5|10|30|30|1|7|0|0|0|0|0 +*|mongbat|orc|||||1912|1302|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1967|1296|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1898|1265|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1872|1347|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1812|1314|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1797|1393|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1862|1434|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1877|1515|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1802|1506|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1692|1463|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1833|1245|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1726|1362|0|2|5|10|30|30|1|3|2|0|0|0|0 +*|mongbat|orc|||||1640|1431|0|2|5|10|30|30|1|3|2|0|0|0|0 +## +## Orc Cave Entrance +## +*|orc:ratman||||||1055|1442|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1021|1415|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1060|1375|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1004|1369|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||1037|1325|0|2|5|10|30|30|1|6|0|0|0|0|0 +*|orc:ratman||||||971|1308|0|2|5|10|30|30|1|6|0|0|0|0|0 +## +## Orc Fort (South Cove) +## +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2171|1356|0|2|5|10|30|30|1|1|3|2|5|3|2 +*|Savageshaman|Savage|Savagerider|Orc|Orcishlord|Orcishmage|2184|1376|0|2|5|10|30|15|1|1|3|2|5|3|2 +*|TreasureLevel2|TreasureLevel3|||||2155|1370|0|2|1|2|2|2|1|1|2|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2203|1379|0|2|1|2|2|2|1|1|2|0|0|0|0 +## +## The Bog of Desolation (West Covetous) +## +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2038|1023|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2079|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2067|989|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2028|987|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2033|936|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1990|976|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||1993|1030|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2035|1018|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2023|1052|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2069|1028|0|2|5|10|30|30|1|3|1|3|0|0|0 +*|toxicelemental:alligator:bogthing:bogling:corpser:giantserpent:lizardman|wisp|strongmongbat:plaguebeast:plaguespawn:ratman:sewerrat:slime:snake||||2048|1066|0|2|5|10|30|30|1|3|1|3|0|0|0 +## +## East Skara Brae +## +*|orc|ettin|ratman|giantspider|reaper||1435|2261|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1651|2413|5|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1619|2725|10|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1427|2525|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1059|2461|0|2|5|10|150|150|1|10|10|10|10|10|0 +*|orc|ettin|ratman|giantspider|reaper||1243|2437|5|2|5|10|150|150|1|10|10|10|10|10|0 +## +## East Skara Brae: Hedge Maze +## +*|Daemon||||||1145|2231|20|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1072|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1070|2256|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1215|2195|5|2|5|10|30|20|1|4|0|0|0|0|0 +*|Imp||||||1216|2259|5|2|5|10|30|20|1|4|0|0|0|0|0 +## +## South Destard / Trinsic +## +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1595|3045|0|2|5|10|100|60|1|5|5|5|5|5|5 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|2091|3413|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1931|3205|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1827|3429|10|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1635|3253|0|2|5|10|150|150|1|10|10|10|10|10|10 +*|orc|giantspider|giantserpent|gorilla|tropicalbird|whippingvine|1387|3109|0|2|5|10|150|150|1|10|10|10|10|10|10 +## +## Main Destard Orcs +## +*|Headlessone|Orc|Orccaptain|Orcishlord|Orcishmage||1110|2672|0|2|5|10|20|20|1|3|6|1|2|1|0 +## +## The Destard Swamps +## +*|Toxicelemental:Alligator:Bogthing:Bogling:Corpser:GiantRat:Giantserpent|Lizardman:strongmongbat:Plaguebeast:Plaguespawn:Ratman:Sewerrat:Snake|Wisp||||1158|2872|0|2|5|10|130|130|1|24|23|3|0|0|0 +*|Savage|Savagerider|Savageshaman||||1141|2959|0|2|5|10|20|20|1|2|1|1|0|0|0 +*|Savage|Savagerider|Savageshaman||||1166|2958|0|2|5|10|20|20|1|2|1|1|0|0|0 +## +## Yew-Britain Brigand Camp +## +*|Brigand||||||854|1686|0|2|1|10|20|15|1|7|0|0|0|0|0 +## +## Yew Liches +## +*|Lich||||||757|1401|0|2|1|10|30|30|1|8|0|0|0|0|0 +## +## Yew Orc Fort +## +*|Orc|Orcishlord|Orcishmage||||634|1504|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcishlord|Orcishmage||||634|1462|0|2|1|10|15|10|1|3|1|1|0|0|0 +*|Orc|Orcbomber|Orccaptain|Orcishlord|Orcishmage||633|1484|0|2|1|10|20|10|1|8|1|1|2|2|0 +## +## Yew Fort of the Damned +## +*|Skeleton||||||965|757|0|2|5|10|10|5|1|2|0|0|0|0|0 +*|Wraith:Shade:Spectre|Ghoul|||||955|707|0|2|5|10|12|8|1|4|4|0|0|0|0 +*|Wraith:Shade:Spectre||||||962|692|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Wraith:Shade:Spectre||||||948|703|0|2|5|10|5|2|1|1|0|0|0|0|0 +*|Lich||||||1016|821|0|2|5|10|10|2|1|1|0|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||1015|706|0|2|1|2|5|5|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||1017|826|0|2|1|2|5|5|1|1|2|0|0|0|0 +## +## Hythloth Fire Pit +## +*|Daemon|Drake|||||4596|3607|30|2|5|10|50|25|1|1|2|0|0|0|0 +*|Dragon|Drake|||||4571|3572|31|2|1|10|50|25|1|1|2|0|0|0|0 +*|Daemon||||||4595|3574|75|2|1|10|50|25|1|3|0|0|0|0|0 +*|Dragon|Drake|||||4618|3570|30|2|1|10|50|25|1|1|2|0|0|0|0 +*|TreasureLevel3|TreasureLevel4|||||4595|3570|30|2|1|2|8|8|1|3|3|0|0|0|0 +## +## Near Shame: The Wisp Circle +## +*|Wisp||||||608|1702|0|2|5|10|30|30|1|8|0|0|0|0|0 +## +## Moonglow Zoo +## +*|Ghoul|Giantrat|Giantserpent|Headlessone|Jwilson||4530|1387|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Iceserpent|Icesnake|Polarbear|Snowleopard|Whitewolf|Frostooze|4511|1394|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Frostspider|Frosttroll|||||4511|1394|23|2|5|10|10|4|1|1|4|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Rabbit:JackRabbit|Cougar:Panther|Bird:Eagle||4498|1394|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Corpser|Swamptentacle|||4485|1387|23|2|5|10|15|4|1|2|3|1|1|0|0 +*|Giantserpent|Giantspider|Boar|Greathart|Hind|Llama|4493|1364|23|2|5|10|10|4|1|1|1|1|1|1|1 +*|Horse|Rat|||||4493|1364|23|2|5|10|10|4|1|1|1|0|0|0|0 +*|Brownbear:Grizzlybear:Blackbear|Direwolf:Timberwolf:Greywolf|Cougar:Panther|Giantserpent|Greathart||4506|1358|23|2|5|10|10|4|1|1|1|1|1|1|0 +*|Alligator|Bullfrog|Gorilla|Giantserpent|Gianttoad||4519|1358|23|2|5|10|15|4|1|1|1|1|1|1|0 +*|Mummy|Ophidianwarrior|Scorpion|Giantserpent|||4531|1363|23|2|5|10|15|4|1|1|1|1|1|0|0 +*|Rottingcorpse|Skeleton|Slime|Snake|Strongmongbat||4512|1372|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Ghoul|Giantserpent|Headlessone|Jwilson|Zombie||4512|1380|23|2|5|10|10|3|1|1|1|1|1|1|0 +*|Cat|Chicken|Dog|Pig|Sheep||4500|1382|23|2|5|10|10|1|1|1|1|1|1|1|0 +############## +## By Nerun ## +############## +overridemintime 45 +overridemaxtime 60 +## +## Camps +## +*|Orccamp:Ratcamp||||||821|675|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1042|1394|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2540|130|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3170|672|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2548|1173|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||3602|2815|28|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||4480|1439|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1152|3471|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1530|999|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1871|1076|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||788|1894|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1064|2488|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2103|3371|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2044|2323|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||1939|1310|0|2|45|60|10|1|1|1|0|0|0|0|0 +*|Orccamp:Ratcamp||||||2349|722|0|2|45|60|10|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/PaintedCaves.map b/Data/Monsters/uoml/trammel/PaintedCaves.map new file mode 100644 index 0000000..5596c39 --- /dev/null +++ b/Data/Monsters/uoml/trammel/PaintedCaves.map @@ -0,0 +1,13 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2114 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Painted Caves +## +*|cat:dog:rat|cat|dog|rat|||6279|880|1|2|5|10|30|30|1|6|1|1|1|0|0 +*|troglodyte|grobu|lurg|giantrat|||6275|879|-2|2|5|10|30|30|1|3|3|3|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/PalaceOfParoxysmus.map b/Data/Monsters/uoml/trammel/PalaceOfParoxysmus.map new file mode 100644 index 0000000..ff571a1 --- /dev/null +++ b/Data/Monsters/uoml/trammel/PalaceOfParoxysmus.map @@ -0,0 +1,25 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2115 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Palace of Paroxysmus +## +*|daemon:succubus|InterredGrizzle:poisonelemental|plaguebeast:plaguespawn|corrosiveslime|putrifier|plaguebeastlord|6295|616|-50|1|5|10|50|50|1|6|6|6|3|3|3 +*|InterredGrizzle|corrosiveslime|poisonelemental|balron:succubus:daemon|plaguebeastlord:plaguebeast:plaguespawn||6384|580|-50|1|5|10|30|30|1|4|4|3|9|11|0 +*|poisonelemental||||||6328|517|-50|1|5|10|10|10|1|4|0|0|0|0|0 +*|plaguebeast:corrosiveslime|poisonelemental:plaguespawn|||||6354|455|-40|1|5|10|20|20|1|5|5|0|0|0|0 +*|plaguebeast:plaguespawn|toxicelemental:corrosiveslime|||||6416|447|-40|1|5|10|20|20|1|8|7|0|0|0|0 +*|balron:succubus:daemon|corrosiveslime|plaguebeastlord:plaguebeast:plaguespawn|InterredGrizzle:poisonelemental|||6466|543|-50|1|5|10|30|30|1|6|3|8|5|0|0 +*|chaosdaemon:moloch|succubus:daemon|balron||||6292|462|-50|1|5|10|40|40|1|7|7|4|0|0|0 +*|earthelemental:corrosiveslime||||||6298|395|60|1|5|10|8|8|1|2|0|0|0|0|0 +*|toxicelemental:plaguespawn|toxicelemental|plaguespawn||||6404|378|-40|1|5|10|18|18|1|2|1|1|0|0|0 +*|plaguespawn:plaguebeast:toxicelemental:corrosiveslime:poisonelemental|plaguespawn|plaguebeast|toxicelemental|corrosiveslime|poisonelemental|6418|358|-40|1|5|10|25|25|1|12|2|2|2|2|2 +*|earthelemental:corrosiveslime:toxicelemental:plaguespawn|earthelemental|corrosiveslime|toxicelemental|plaguespawn||6319|348|60|1|5|10|20|20|1|5|1|1|1|1|0 +*|toxicelemental:earthelemental:corrosiveslime|toxicelemental|earthelemental|corrosiveslime|||6249|352|60|1|5|10|15|15|1|6|1|1|1|0|0 +*|poisonelemental||||||6285|353|60|1|5|10|5|5|1|1|0|0|0|0|0 +*|earthelemental:corrosiveslime||||||6353|400|60|1|5|10|10|10|1|4|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/PrismOfLight.map b/Data/Monsters/uoml/trammel/PrismOfLight.map new file mode 100644 index 0000000..35f56cf --- /dev/null +++ b/Data/Monsters/uoml/trammel/PrismOfLight.map @@ -0,0 +1,32 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2116 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Prism of Light +## +*|CrystalLatticeSeeker||||||6553|157|0|1|5|10|8|8|1|3|0|0|0|0|0 +*|Rat:Icesnake||||||6474|74|-34|1|5|10|4|4|1|9|0|0|0|0|0 +*|wisp:CrystalWisp:treasurelevel2|treasurelevel2|||||6552|155|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|wisp||||||6521|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|wisp||||||6530|139|-20|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalSeaSerpent||||||6576|91|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|UnfrozenMummy||||||6509|176|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalDaemon||||||6536|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalDaemon||||||6547|91|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|CrystalHydra||||||6572|89|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|treasurelevel4||||||6504|181|0|1|5|10|1|1|1|1|0|0|0|0|0 +*|ShadowWisp||||||6475|101|-44|1|5|10|5|5|1|5|0|0|0|0|0 +*|wisp:Crystalwisp||||||6478|174|4|1|5|10|10|10|1|6|0|0|0|0|0 +*|Crystalvortex:iceelemental||||||6566|120|0|1|5|10|15|15|1|7|0|0|0|0|0 +*|CrystalWisp||||||6534|178|0|1|5|10|4|4|1|2|0|0|0|0|0 +*|CrystalWisp:CrystalLatticeSeeker:treasurelevel2|treasurelevel2|||||6535|179|0|1|5|10|15|15|1|5|1|0|0|0|0 +*|treasurelevel3||||||6502|120|-10|1|5|10|0|0|1|1|0|0|0|0|0 +*|protector||||||6507|151|0|1|5|10|5|5|1|3|0|0|0|0|0 +*|CrystalDaemon||||||6532|79|-10|1|5|10|4|4|1|1|0|0|0|0|0 +*|Ferret||||||6578|183|31|1|5|10|5|5|1|2|0|0|0|0|0 +*|protector||||||6510|171|0|1|5|10|8|8|1|3|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Reagents.map b/Data/Monsters/uoml/trammel/Reagents.map new file mode 100644 index 0000000..bcbe9fe --- /dev/null +++ b/Data/Monsters/uoml/trammel/Reagents.map @@ -0,0 +1,70 @@ +############## +## By Nerun ## +############## +overrideid 2129 +overridemap 2 +overridemintime 11 +overridemaxtime 23 +## +## Trammel Reagents +## +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2854|816|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4590|1448|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2490|1096|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1566|1140|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1514|1584|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1938|1408|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2374|652|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2054|516|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1286|504|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||746|636|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1134|964|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||718|1180|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||342|1464|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||702|1752|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1114|1416|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1150|1876|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1582|2028|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1934|2328|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1490|2472|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1070|2320|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1466|3032|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2062|964|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1846|3260|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1078|2772|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4710|3796|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5926|3888|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5474|3904|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5934|3436|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5462|3452|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5674|3120|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5618|2744|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5326|2492|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5966|2456|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||5234|3068|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||6042|2916|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3602|2948|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3538|2536|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2734|2168|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3714|2152|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3674|1216|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3994|328|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4166|584|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3198|504|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2750|368|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1694|688|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||366|900|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||642|2216|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2226|3532|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1850|2796|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1658|236|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4426|1028|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2522|84|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||3130|116|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2082|60|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2930|3476|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1410|3796|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||1122|3524|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||2474|3956|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4570|3340|0|2|11|23|200|200|1|160|0|0|0|0|0 +*|BlackPearl:Bloodmoss:SpidersSilk:SulfurousAsh:Garlic:Ginseng:Nightshade:MandrakeRoot||||||4282|3700|0|2|11|23|200|200|1|160|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Sanctuary.map b/Data/Monsters/uoml/trammel/Sanctuary.map new file mode 100644 index 0000000..52802f2 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Sanctuary.map @@ -0,0 +1,19 @@ +############################## +## XML Spawns by Erica ## +## Convert/Adapted By Nerun ## +############################## +overrideid 2117 +overridemap 2 +overrridemintime 5 +overridemaxtime 10 +## +## Sanctuary +## +*|chicken:bird|dog|cat|cow:bull|pig|boar|6263|118|-10|1|5|10|20|20|1|6|3|3|6|3|3 +*|ratman:ratmanarcher:chiikkaha:titan:cyclops:rat|ratman:ratmanarcher|chiikkaha|titan|cyclops|rat|6349|89|-20|1|5|10|70|70|1|18|4|2|2|2|2 +*|ratman:ratmanarcher:ratmanmage:changeling:doppleganger|dog:chicken:cat:boar:bird|gargoyle|titan|cyclops|orcishmage:orcscout|6168|117|0|1|5|10|30|30|1|11|9|3|3|3|5 +*|ogrelord:orcishlord:ratman|bird:cow:bull:pig:chicken|||||6189|71|0|1|5|10|25|25|1|8|4|0|0|0|0 +*|titan:ettin:doppleganger:mougguur|dog:chicken:rat:cow:bull|orcbomber:orcbrute:orc|snake:gargoyle:ogre|||6187|101|0|1|5|10|25|25|1|10|10|7|7|0|0 +*|bird:chicken:rat:dog|doppleganger|||||6184|29|0|1|5|10|10|10|1|6|3|0|0|0|0 +*|szavetra:imp:titan:snake:ratman:doppleganger:gargoyle|cow:bull:chicken:bird:pig:dog:goat:cat:rat|orc:orccaptain:orcishmage|ogre:ogre:ogrelord|||6265|48|-10|1|5|10|30|30|1|22|18|9|4|0|0 +*|changeling:ratman:ettin:titan:ratmanarcher:ratmanmage|goat:pig:cow:bull:rat|gargoyleenforcer:gargoyledestroyer:gargoyle|snake|||6191|155|0|1|5|10|25|25|1|18|12|9|3|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/SeaLife.map b/Data/Monsters/uoml/trammel/SeaLife.map new file mode 100644 index 0000000..98af907 --- /dev/null +++ b/Data/Monsters/uoml/trammel/SeaLife.map @@ -0,0 +1,123 @@ +############## +## By Nerun ## +############## +overrideid 2118 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1395|3421|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4888|375|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4352|215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3688|439|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4512|583|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4904|1127|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3576|823|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4016|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3992|1447|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4232|1655|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4600|1751|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|1519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3616|1807|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4032|2039|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4624|2199|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4400|2527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3984|2423|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|2119|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4912|2471|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4864|2831|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4536|2847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4896|3215|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4192|2975|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4008|2767|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3328|2063|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3176|2383|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3088|2759|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3888|3167|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3968|3895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3240|3151|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3776|3519|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3344|3479|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2792|2951|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2608|3295|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2744|2567|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2368|2799|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3560|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3168|3871|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2768|3847|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1720|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|3879|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||544|3719|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||896|3695|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||824|3287|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||176|3551|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||480|3351|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||512|2919|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||192|2895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||208|2503|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||840|2863|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||600|2511|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|2103|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||168|1743|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||200|559|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||184|191|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||592|223|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|527|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2400|2399|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3008|1895|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2392|2031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2624|1775|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3408|1407|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3256|1031|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2952|1239|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2752|1455|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2208|1703|-5|2|5|10|175|175|1|15|6|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1866|1798|-5|2|5|10|175|175|1|15|6|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||931|141|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3267|1717|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2395|1405|-5|2|5|10|130|130|1|13|4|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||139|1173|-5|2|5|10|130|130|1|13|4|1|0|0|0 +## +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3123|1485|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3811|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3931|1757|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2931|3245|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2291|3181|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||979|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||147|3213|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1891|3597|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2971|1605|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1580|75|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4275|1309|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4667|109|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||5003|101|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3603|125|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4112|791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3891|733|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3672|1535|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4363|1981|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4995|1829|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4283|2221|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2008|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2320|4007|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4955|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4731|3997|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4307|3965|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2227|3533|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1187|3885|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||731|3989|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||491|4013|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||107|909|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1792|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||1336|79|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4048|63|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4392|823|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3520|2263|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||3568|3215|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4992|3791|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||4984|3567|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2072|2527|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2040|3751|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||2288|3767|-5|2|5|10|100|100|1|10|2|1|0|0|0 +*|DeepSeaSerpent:SeaSerpent:WaterElemental:Kraken|Dolphin|SeaHorse||||496|1879|-5|2|5|10|100|100|1|10|2|1|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Shame.map b/Data/Monsters/uoml/trammel/Shame.map new file mode 100644 index 0000000..6d17b63 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Shame.map @@ -0,0 +1,135 @@ +############## +## By Nerun ## +############## +overrideid 2119 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Shame Dungeon +## +## Level 1 +## +*|Earthelemental|Scorpion|||||5404|93|10|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5425|58|10|2|5|10|30|30|1|7|3|0|0|0|0 +*|Earthelemental|Scorpion|||||5387|41|20|2|2|10|30|30|1|4|1|0|0|0|0 +*|Earthelemental||||||5394|11|30|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental||||||5474|20|0|2|2|10|30|30|1|4|0|0|0|0|0 +*|Earthelemental|Scorpion|||||5477|67|20|2|2|10|30|30|1|4|2|0|0|0|0 +*|Earthelemental|Scorpion|||||5468|109|35|2|2|10|30|30|1|6|20|0|0|0|0 +*|TreasureLevel1||||||5423|112|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5468|106|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5434|100|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5492|56|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5416|59|-15|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5400|45|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5448|33|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5437|11|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5399|11|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5421|117|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5468|100|35|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5392|10|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5445|12|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5404|43|30|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5443|36|-10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5402|58|-20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5493|51|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5434|89|20|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Airelemental||||||5575|16|10|2|2|10|30|15|1|3|0|0|0|0|0 +*|Dullcopperelemental||||||5615|18|10|2|2|10|30|15|1|6|0|0|0|0|0 +*|Airelemental||||||5568|36|0|2|2|10|30|15|1|3|0|0|0|0|0 +*|Airelemental|Waterelemental|||||5549|60|0|2|2|10|30|15|1|3|2|0|0|0|0 +*|Kraken|Waterelemental|||||5549|79|0|2|2|10|30|10|1|1|3|0|0|0|0 +*|Kraken|Seaserpent|||||5595|82|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Dullcopperelemental||||||5603|93|0|2|2|10|25|12|1|2|0|0|0|0|0 +*|Dullcopperelemental||||||5603|116|0|2|2|10|30|15|1|4|0|0|0|0|0 +*|TreasureLevel1||||||5536|119|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5546|118|-5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5606|25|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5570|118|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5620|21|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5572|113|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5546|113|-5|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 3 +## +*|Earthelemental||||||5474|139|20|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental|Poisonelemental|||||5477|183|0|2|2|10|30|15|1|1|4|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5469|211|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Evilmage|Evilmagelord|||||5441|187|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Airelemental|Earthelemental|||||5412|164|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5411|163|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental|Earthelemental|||||5412|201|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Fireelemental|Poisonelemental|Scorpion||||5412|200|0|2|2|10|30|15|1|1|1|1|0|0|0 +*|Airelemental||||||5394|230|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Eldergazer||||||5505|180|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Dullcopperelemental|Fireelemental|||||5527|210|0|2|2|10|30|15|1|4|2|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5557|222|0|2|2|10|25|10|1|2|2|3|0|0|0 +*|Evilmage|Evilmagelord|||||5577|194|0|2|2|10|30|15|1|5|5|0|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5594|182|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Earthelemental|Scorpion|||||5571|158|-10|2|2|10|30|15|1|4|2|0|0|0|0 +*|Earthelemental|Fireelemental|||||5593|141|10|2|2|10|30|15|1|2|2|0|0|0|0 +*|TreasureLevel1||||||5398|148|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5545|153|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5594|139|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5604|166|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5608|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5605|202|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5439|137|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5390|145|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5456|157|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5410|170|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5415|189|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5396|226|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5553|146|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5595|147|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5615|173|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5616|184|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5456|143|20|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5432|158|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5474|176|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5406|177|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|185|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5405|200|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5403|235|10|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5475|190|0|2|1|2|1|1|1|1|0|0|0|0|0 +## +## Level 4 +## +*|Airelemental||||||5875|44|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Fireelemental||||||5856|107|10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Airelemental||||||5845|57|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Kraken|Seaserpent|||||5828|42|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Evilmage|Evilmagelord|||||5819|50|0|2|2|10|25|10|1|1|1|0|0|0|0 +*|Eldergazer||||||5818|80|0|2|2|10|30|10|1|2|0|0|0|0|0 +*|Airelemental||||||5804|12|0|2|2|10|30|15|1|5|0|0|0|0|0 +*|Bloodelemental||||||5721|12|10|2|2|10|30|15|1|8|0|0|0|0|0 +*|Fireelemental||||||5661|16|-10|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental||||||5649|101|10|2|2|10|30|15|1|4|0|0|0|0|0 +*|Bloodelemental||||||5684|117|0|2|2|10|30|15|1|2|0|0|0|0|0 +*|Earthelemental|Fireelemental|||||5724|118|0|2|2|10|30|15|1|2|2|0|0|0|0 +*|Toxicelemental|Fireelemental|Scorpion||||5760|99|0|2|2|10|30|15|1|2|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5711|97|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Seaserpent|Waterelemental||||5752|44|0|2|2|10|25|10|1|1|1|1|0|0|0 +*|Kraken|Waterelemental|||||5708|43|0|2|2|10|25|10|1|1|3|0|0|0|0 +*|TreasureLevel1||||||5730|90|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5723|73|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5715|61|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel1||||||5701|60|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5817|83|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5730|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5723|77|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5717|60|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel2||||||5699|61|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5817|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5733|91|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5725|78|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5715|58|2|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel3||||||5698|57|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5733|93|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5727|72|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5717|58|5|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5701|58|2|2|1|2|1|1|1|1|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/SolenHive.map b/Data/Monsters/uoml/trammel/SolenHive.map new file mode 100644 index 0000000..9f27cf1 --- /dev/null +++ b/Data/Monsters/uoml/trammel/SolenHive.map @@ -0,0 +1,92 @@ +############## +## By Nerun ## +############## +overrideid 2120 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Solen Hive Dungeon +## +## AREA A - Yew Lich Ruins (731 1452 0) +## +## Level 1 +## +*|Redsolenworker||||||5670|1807|4|2|5|10|30|25|1|2|0|0|0|0|0 +*|Redsolenworker||||||5673|1846|1|2|5|10|20|6|1|1|0|0|0|0|0 +*|Redsolenworker||||||5693|1834|0|2|5|10|20|4|1|1|0|0|0|0|0 +*|Redsolenworker||||||5704|1807|4|2|5|10|20|6|1|1|0|0|0|0|0 +*|Redsolenworker||||||5722|1820|5|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Redsolenwarrior||||||5709|1874|1|2|5|10|50|10|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5681|1886|2|2|5|10|50|10|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5756|1857|4|2|5|10|50|10|1|1|0|0|0|0|0 +## +## AREA B - Between Minoc/Covetous (2609 764 0) +## +## Level 1 +## +*|Redsolenworker||||||5912|1800|1|2|5|10|30|20|1|1|0|0|0|0|0 +*|Redsolenworker||||||5920|1842|1|2|5|10|30|15|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Antlion||||||5887|1840|-18|2|5|10|25|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5847|1819|1|2|5|10|25|10|1|2|0|0|0|0|0 +*|Redsolenworker||||||5829|1798|1|2|5|10|15|10|1|1|0|0|0|0|0 +*|Redsolenworker|Redsolenqueen|||||5873|1798|0|2|5|10|15|10|1|2|1|0|0|0|0 +*|Redsolenwarrior||||||5782|1793|1|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5799|1857|5|2|5|10|20|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5815|1881|2|2|5|10|20|7|1|1|0|0|0|0|0 +*|Beetle||||||5831|1910|3|2|5|10|15|10|1|2|0|0|0|0|0 +## +## AREA C - West Trinsic Main Gate (1691 2790 0) +## +## Level 1 +## +*|Redsolenworker||||||5718|2024|4|2|5|10|25|15|1|2|0|0|0|0|0 +*|Redsolenworker||||||5776|2019|2|2|5|10|20|10|1|1|0|0|0|0|0 +*|Antlion||||||5782|2021|-11|2|5|10|25|10|1|1|0|0|0|0|0 +*|Dreadspider||||||5767|1962|2|2|5|10|50|15|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5671|1979|0|2|5|10|30|20|1|1|0|0|0|0|0 +*|Redsolenwarrior||||||5703|1991|0|2|5|10|35|20|1|2|0|0|0|0|0 +## +## Level 2 +## +*|Redsolenwarrior||||||5699|1921|2|2|5|10|30|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5748|1923|0|2|5|10|20|5|1|1|0|0|0|0|0 +*|Redsolenqueen|Redsolenworker|||||5736|1939|7|2|5|10|20|10|1|1|2|0|0|0|0 +## +## AREA D - South Chaos/Compassion Road (1725 815 0) +## +## Level 1 +## +*|Redsolenworker||||||5876|2018|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5856|2018|0|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5838|2019|3|2|5|10|20|10|1|1|0|0|0|0|0 +*|Redsolenworker||||||5910|1991|0|2|5|10|25|15|1|3|0|0|0|0|0 +*|Beetle||||||5837|1992|-2|2|5|10|15|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5863|1958|2|2|5|10|25|10|1|2|0|0|0|0|0 +*|Antlion||||||5884|1920|-15|2|5|10|20|10|1|1|0|0|0|0|0 +## +## Level 2 +## +*|Redsolenworker||||||5825|1968|4|2|5|10|25|10|1|2|0|0|0|0|0 +*|Redsolenwarrior||||||5855|1932|3|2|5|10|20|10|1|2|0|0|0|0|0 +*|Redsolenworker||||||5798|1963|0|2|5|10|35|10|1|2|0|0|0|0|0 +## +## AREA E - GreenThorn/Desert Entrance +## +*|Antlion||||||5665|1868|11|2|5|10|20|10|1|3|0|0|0|0|0 +*|Antlion||||||5707|1843|-15|2|5|10|10|10|1|1|0|0|0|0|0 +## +## INFILTRATORS +## +## Windemere +*|blacksoleninfiltratorqueen|blacksoleninfiltratorwarrior|||||3218|502|0|2|5|10|10|10|1|1|2|0|0|0|0 +## Trinsic +*|blacksoleninfiltratorqueen|blacksoleninfiltratorwarrior|||||1940|3261|1|2|5|10|10|10|1|1|2|0|0|0|0 +## Wind +*|blacksoleninfiltratorqueen|blacksoleninfiltratorwarrior|||||1361|894|0|2|5|10|8|4|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/TerathanKeep.map b/Data/Monsters/uoml/trammel/TerathanKeep.map new file mode 100644 index 0000000..5ea9929 --- /dev/null +++ b/Data/Monsters/uoml/trammel/TerathanKeep.map @@ -0,0 +1,62 @@ +############## +## By Nerun ## +############## +overrideid 2121 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Lost Lands +## Terathan Keep Dungeon +## +## Terathan Keep +## +*|Balron|Dragon|Drake|Nightmare|||5296|1561|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5296|1562|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5297|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5342|1553|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5342|1552|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5343|1551|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5334|1613|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5334|1614|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5335|1615|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5348|1552|0|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5345|1551|0|2|1|2|1|1|1|2|0|0|0|0|0 +## +## Ophidian Territory +## +*|Balron|Dragon|Drake|Nightmare|||5344|1757|-125|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5345|1757|-125|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5346|1756|-125|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5335|1706|-70|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5335|1707|-70|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5336|1708|-70|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5270|1695|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5270|1694|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5271|1693|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|TreasureLevel3||||||5365|1707|-71|2|1|2|1|1|1|1|0|0|0|0|0 +*|TreasureLevel4||||||5363|1709|-75|2|1|2|1|1|1|2|0|0|0|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5176|1702|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5176|1701|2|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5177|1700|1|2|5|15|20|10|1|1|1|1|1|0|0 +## +## Champion Room +## +*|Balron|Dragon|Drake|Nightmare|||5132|1624|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5132|1623|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5134|1625|0|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5160|1586|-15|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5163|1585|-15|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5161|1584|-15|2|5|15|20|10|1|1|1|1|1|0|0 +## +*|Balron|Dragon|Drake|Nightmare|||5200|1565|0|2|5|15|20|10|1|1|1|1|1|0|0 +*|Ophidianarchmage|Ophidianknight|Ophidianmage|Ophidianwarrior|Ophidianmatriarch||5201|1566|0|2|5|15|20|10|1|1|1|1|1|1|0 +*|Terathanavenger|Terathandrone|Terathanmatriarch|Terathanwarrior|||5200|1568|0|2|5|15|20|10|1|1|1|1|1|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/TownsLife.map b/Data/Monsters/uoml/trammel/TownsLife.map new file mode 100644 index 0000000..45e2161 --- /dev/null +++ b/Data/Monsters/uoml/trammel/TownsLife.map @@ -0,0 +1,152 @@ +############## +## By Nerun ## +############## +overrideid 2122 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Towns +## +## ----Mainland---- +## +## Wind +## +*|dragon|drake|||||5249|228|15|2|5|10|20|20|1|1|2|0|0|0|0 +*|lichlord|lich|||||5164|205|15|2|5|10|15|15|1|1|2|0|0|0|0 +*|daemon||||||5133|150|0|2|5|10|15|15|1|3|0|0|0|0|0 +## +## Britain Town +## +*|Bird|Cat|Dog|Rat|||1550|1658|26|2|5|15|120|120|1|15|15|15|15|0|0 +*|Cow||||||1319|1810|0|2|5|10|10|5|1|7|0|0|0|0|0 +*|Cow||||||1319|1821|0|2|5|10|10|5|1|7|0|0|0|0|0 +## ------------------- +## +## Britain Farm 1 +## +*|Bird|Cat|Dog|Rat|||1340|1790|15|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1339|1788|15|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 2 +## +*|Bird|Cat|Dog|Rat|||1217|1825|0|2|5|15|80|80|1|5|5|5|5|0|0 +*|Chicken||||||1216|1823|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Britain Farm 3 +## +*|Bird|Cat|Dog|Rat|||1186|1633|0|2|5|15|80|80|1|7|7|7|7|0|0 +*|Chicken||||||1185|1632|0|2|5|15|80|80|1|5|0|0|0|0|0 +## +## Trinsic Town +## +*|Bird|Cat|Dog|Rat|||1937|2760|10|2|5|15|120|120|1|12|12|12|12|0|0 +## +## Skara Brae Town +## +*|Bird|Cat|Dog|Rat|||608|2195|0|2|5|15|70|70|1|8|8|8|8|0|0 +*|Chicken:Sheep:Cow||||||813|2164|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||818|2269|0|2|5|15|15|10|1|3|0|0|0|0|0 +*|Chicken:Sheep:Cow||||||830|2353|0|2|5|15|15|10|1|3|0|0|0|0|0 +## +## Yew Town +## +*|Bird|Cat|Dog|Rat|||536|962|0|2|5|15|160|160|1|20|20|20|20|0|0 +*|Sheep||||||676|1178|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||570|1099|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Sheep||||||675|939|0|2|5|10|15|10|1|15|0|0|0|0|0 +*|Chicken||||||382|1192|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||560|1239|0|2|5|10|10|10|1|2|0|0|0|0|0 +*|Chicken||||||688|1007|0|2|5|10|10|10|1|2|0|0|0|0|0 +## +## Cove Town +## +*|Bird|Cat|Dog|Rat|||2242|1197|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken||||||2223|1151|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## Vesper Town 1 +## +*|Bird|Cat|Dog|Rat|||2939|746|2|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Vesper Town 2 +## +*|Bird|Cat|Dog|Rat|||2904|906|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Minoc Town 1 +## +*|Bird|Cat|Dog|Rat|||2481|542|0|2|5|15|70|70|1|5|5|5|5|0|0 +## +## Minoc Town 2 +## +*|Bird|Cat|Dog|Rat|||2472|434|15|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Minoc Town 3 +## +*|Bird|Cat|Dog|Rat|||2566|622|0|2|5|15|50|50|1|3|3|3|3|0|0 +## +## ----Islands---- +## +## Jhelom Town 1 +## +*|Bird|Cat|Dog|Rat|||1154|3639|0|2|5|15|50|50|1|4|4|4|4|0|0 +*|Chicken:Cow:Sheep||||||1127|3583|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken:Cow:Sheep||||||1183|3607|0|2|5|10|10|10|1|5|0|0|0|0|0 +## +## Jhelom Town 2 +## +*|Bird|Cat|Dog|Rat|||1400|3775|0|2|5|15|100|100|1|10|10|10|10|0|0 +## +## Jhelom Town 3 +## +*|Bird|Cat|Dog|Rat|||1435|4000|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Serpents Hold Town +## +*|Bird|Cat|Dog|Rat|||2972|3436|15|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Haven/Occlo Town 1 +## +*|Bird|Cat|Dog|Rat|||3674|2624|0|2|5|15|80|80|1|10|10|10|10|0|0 +*|Chicken||||||3726|2647|0|2|5|10|25|25|1|10|0|0|0|0|0 +## +## Haven/Occlo Town 2 +## +*|Bird|Cat|Dog|Rat|||3652|2511|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Magincia Town 1 +## +*|Bird|Cat|Dog|Rat|||3714|2205|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Magincia Town 2 +## +*|Bird|Cat|Dog|Rat|||3717|2111|20|2|5|15|50|50|1|6|6|6|6|0|0 +## +## Buccaneers Den Town 1 +## +*|Bird|Cat|Dog|Rat|||2682|2118|0|2|5|15|50|50|1|5|5|5|5|0|0 +## +## Buccaneers Den Town 2 +## +*|Bird|Cat|Dog|Rat|||2687|2218|0|2|5|15|50|50|1|4|4|4|4|0|0 +## +## Nujel'm Town +## +*|Bird|Cat|Dog|Rat|||3699|1238|0|2|5|15|160|160|1|18|18|18|18|0|0 +## +## Moonglow Town +## +*|Bird|Cat|Dog|Rat|||4438|1115|0|2|5|15|70|70|1|12|12|12|12|0|0 +*|Chicken:Cow:Sheep||||||4634|1302|0|2|5|10|10|10|1|5|0|0|0|0|0 +*|Chicken||||||4567|1476|0|2|5|10|3|3|1|2|0|0|0|0|0 +*|Chicken||||||4422|1451|0|2|5|10|5|5|1|1|0|0|0|0|0 +## +## ----Lostlands---- +## +## Papua Town +## +*|Bird|Cat|Dog|Rat|||5726|3211|-2|2|5|15|100|100|1|12|12|12|12|0|0 +## +## Delucia Town +## +*|Bird|Cat|Dog|Rat|||5255|4000|37|2|5|15|80|80|1|6|6|6|6|0|0 +*|Chicken:Sheep:Cow:Bull||||||5267|4012|40|2|5|10|15|15|1|5|0|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/TownsPeople.map b/Data/Monsters/uoml/trammel/TownsPeople.map new file mode 100644 index 0000000..5fa233b --- /dev/null +++ b/Data/Monsters/uoml/trammel/TownsPeople.map @@ -0,0 +1,64 @@ +############## +## By Nerun ## +############## +overrideid 2123 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Britain Chaos/Order Guards +## +*|Orderguard||||||1400|1623|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Orderguard||||||1400|1628|28|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1521|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +*|Chaosguard||||||1525|1457|15|2|5|10|1|0|1|1|0|0|0|0|0 +## +## Town Criers +## +*|Towncrier||||||1662|1611|19|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1421|1698|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2254|1207|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5290|3987|37|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3652|2619|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1330|3778|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3721|2161|20|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2515|557|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||4451|1153|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||3773|1308|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||5685|3148|-4|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2891|3474|15|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||603|2141|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1914|2687|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||1829|2811|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||2895|686|0|2|5|10|5|1|1|1|0|0|0|0|0 +*|Towncrier||||||627|864|0|2|5|10|5|1|1|1|0|0|0|0|0 +## +## Hire +## +*|HireBard:HireBardArcher:HireBeggar:HireFighter:HireMage|HireRanger:HireRangerArcher:HireSailor:HireThief:HirePaladin|||||1399|3743|-21|2|5|15|10|10|1|5|5|0|0|0|0 +## +## Escorts +## +*|Escortablemage:Seekerofadventure:Noble||||||1483|1760|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1372|3916|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||1126|3688|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3674|2291|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||4398|1049|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3815|1217|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3749|1404|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3645|2661|-2|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2994|3451|16|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||673|2235|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||573|2246|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||2068|2854|0|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||3041|827|-3|2|5|15|20|10|1|3|0|0|0|0|0 +*|Escortablemage:Seekerofadventure:Noble||||||631|883|0|2|5|15|20|10|1|3|0|0|0|0|0 +## +## Treasures +## +## Trinsic Bank +*|TreasureLevel3|TreasureLevel4|||||1813|2834|0|2|1|2|2|2|1|1|2|0|0|0|0 +## Vesper Bank +*|TreasureLevel1||||||2875|675|0|2|1|2|2|2|1|6|0|0|0|0|0 +*|TreasureLevel1|TreasureLevel2|||||2874|692|0|2|1|2|1|1|1|1|1|0|0|0|0 +*|TreasureLevel2|TreasureLevel3|||||2884|692|0|2|1|2|1|1|1|2|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/TrinsicPassage.map b/Data/Monsters/uoml/trammel/TrinsicPassage.map new file mode 100644 index 0000000..d6d0303 --- /dev/null +++ b/Data/Monsters/uoml/trammel/TrinsicPassage.map @@ -0,0 +1,18 @@ +############## +## By Nerun ## +############## +overrideid 2124 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Do not exist spiderlord, then i did 2 dreadspiders per block +## +## Trinsic Passage +## +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5976|1387|-22|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5940|1356|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5912|1326|0|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5956|1310|-2|2|5|15|20|10|1|2|1|1|1|1|0 +*|Dreadspider|Fireelemental|Hellcat|Lavalizard|Lavasnake||5999|1327|10|2|5|15|20|10|1|2|1|1|1|1|0 +*|TreasureLevel2|TreasureLevel3|||||5915|1302|2|2|1|2|1|1|1|1|2|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Vendors.map b/Data/Monsters/uoml/trammel/Vendors.map new file mode 100644 index 0000000..52ec010 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Vendors.map @@ -0,0 +1,395 @@ +############## +## By Nerun ## +############## +overrideid 2125 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Hidden Valley Mages +## +*|Herbalist|Mage|||||1685|2985|0|2|5|10|20|10|1|2|2|0|0|0|0 +## +## Britain +## +*|jeweler||||||1650|1642|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||1450|1617|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1418|1547|30|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1471|1611|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1447|1647|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1590|1654|10|2|2|10|5|0|1|1|1|1|0|0|0 +*|bard|bardguildmaster|||||1455|1557|30|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1388|1588|30|2|2|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||1362|1574|30|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1467|1686|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||1474|1597|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||1417|1578|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1458|1525|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1416|1754|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||1451|1679|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1602|1712|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||1470|1578|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1547|1659|26|2|2|10|5|0|1|1|1|1|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1620|1586|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|carpenter|architect|realestatebroker||||1430|1597|20|2|2|10|5|0|1|1|1|1|0|0|0 +*|mage|alchemist|mageguildmaster||||1485|1550|30|2|2|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||1296|1759|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||1388|1655|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1481|1584|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||1493|1616|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|tinkerguildmaster||||||1422|1654|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1547|1768|10|2|2|10|5|0|1|1|1|1|1|0|0 +*|warriorguildmaster|hirefighter|||||1341|1733|20|2|5|10|5|0|1|1|2|0|0|0|0 +*|innkeeper||||||1585|1591|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1637|1693|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|tanner|furtrader|||||1431|1612|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1498|1691|20|2|2|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||1470|1765|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||1409|1590|42|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmithguildmaster|blacksmith|||||1349|1778|15|2|5|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1469|1668|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1510|1543|25|2|2|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1427|1716|20|2|2|10|5|0|1|1|1|1|1|0|0 +*|butcher||||||1449|1723|6|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1650|1608|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||1498|1659|27|2|2|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||1425|1690|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1494|1715|6|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage||||||1405|1810|0|2|5|10|25|10|1|1|0|0|0|0|0 +*|towncrier||||||1482|1761|-2|2|5|10|4|0|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1228|1572|0|2|5|10|10|8|1|1|1|1|0|0|0 +*|orderguard|hirefighter|||||1355|1754|20|2|5|10|14|8|1|1|1|0|0|0|0 +*|farmer|rancher|||||1243|1699|0|2|5|10|4|4|1|1|1|0|0|0|0 +*|escortablemage||||||1351|1816|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|orderguard||||||1306|1804|0|2|5|10|6|4|1|1|0|0|0|0|0 +*|peasant||||||1304|1826|0|2|5|10|1|1|1|1|0|0|0|0|0 +*|artist||||||1362|1825|0|2|5|10|12|6|1|1|0|0|0|0|0 +*|escortablewanderinghealer||||||1333|1808|0|2|5|10|4|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1150|1619|0|2|5|10|10|6|1|1|1|1|0|0|0 +*|farmer|rancher|hirepeasant||||1149|1547|0|2|5|10|10|10|1|1|1|1|0|0|0 +*|bridegroom||||||1295|1773|10|2|5|10|4|4|1|1|0|0|0|0|0 +*|hirefighter||||||1316|1747|10|2|5|10|20|15|1|3|0|0|0|0|0 +*|hirepeasant||||||1231|1714|0|2|5|10|10|4|1|1|0|0|0|0|0 +*|farmer|rancher|hirepeasant||||1190|1707|0|2|5|10|8|4|1|1|1|1|0|0|0 +*|hirebard||||||1427|1726|20|2|5|10|4|4|1|1|0|0|0|0|0 +*|hiresailor|fisherman|rat||||1438|1761|-2|2|5|10|10|6|1|1|1|2|0|0|0 +*|hiresailor||||||1477|1741|0|2|5|10|20|20|1|2|0|0|0|0|0 +*|harbormaster||||||1436|1752|14|2|5|10|4|4|1|1|0|0|0|0|0 +*|merchant||||||1434|1717|20|2|5|10|4|4|1|1|0|0|0|0|0 +## +## Buccaneer's Den +## +*|healer|healerguildmaster|||||2709|2130|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2715|2098|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|thiefguildmaster||||||2659|2194|4|2|2|10|5|5|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2680|2238|2|2|2|10|5|0|1|1|1|1|1|0|0 +*|provisioner|cobbler|||||2737|2250|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2731|2192|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2627|2100|10|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2752|2155|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2707|2178|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||2634|2083|10|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Cove +## +*|healer|healerguildmaster|||||2245|1231|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||2216|1167|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2216|1192|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||2256|1181|-2|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Jhelom +## +*|carpenter|architect|realestatebroker||||1435|3820|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||1404|3802|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1452|3770|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|armorer|weaponsmith|||||1456|3850|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1317|3773|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||1372|3908|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1512|3989|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1504|3693|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||1125|3687|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||1416|3779|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|scribe||||||1387|3771|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1425|3981|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||1454|4003|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||1360|3815|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner||||||1442|3802|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|cobbler||||||1442|3802|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherguildmaster||||||1437|3750|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1447|3981|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||1452|3747|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1441|3719|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1419|3859|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1356|3780|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1364|3732|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1475|3865|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||1354|3754|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher|farmer|||||1386|3825|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||1450|4026|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1395|3705|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Magincia +## +*|fisherguildmaster||||||3683|2252|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3667|2252|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3727|2224|20|2|2|10|5|0|1|1|1|1|1|0|0 +*|healer|healerguildmaster|||||3687|2227|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||3674|2289|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|minerguildmaster||||||3665|2140|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3699|2218|20|2|2|10|5|0|1|1|1|1|0|0|0 +*|merchantguildmaster||||||3703|2249|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||3699|2163|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||3666|2235|20|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinker|tinkerguildmaster|||||3720|2126|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3755|2227|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3734|2149|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3683|2171|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||3661|2183|20|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Minoc +## +*|blacksmith|blacksmithguildmaster|||||2471|564|5|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2461|457|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2505|432|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||2577|599|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2455|487|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|bard|bardguildmaster|||||2424|555|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||2478|427|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||2513|477|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||2450|428|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||2438|410|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||2526|375|23|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||2522|524|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2526|546|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|armorer|weaponsmith|||||2533|572|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2503|552|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2475|397|15|2|2|10|5|0|1|1|1|1|1|0|0 +## +## Moonglow +## +*|herbalist|alchemist|customhairstylist||||4416|1133|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|baker||||||4392|1068|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||4416|1085|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|armorer|weaponsmith|||||4392|1117|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||4406|1038|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||4394|1083|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||4409|1111|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||4484|1064|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||4448|1090|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||4458|1060|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||4417|1064|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||4401|1165|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||4440|1162|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster||||||4545|860|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||4481|1085|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||4395|1137|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||4471|1156|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Nujel'm +## +*|jeweler||||||3778|1172|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3769|1218|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|blacksmith|blacksmithguildmaster|||||3546|1185|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||3546|1194|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||3555|1171|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||3545|1178|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||3554|1202|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3731|1320|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||3700|1214|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3729|1258|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|tailor|weaver|tailorguildmaster||||3774|1265|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||3764|1317|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|bardguildmaster||||||3740|1197|0|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Haven +## +*|blacksmith|blacksmithguildmaster|||||3645|2617|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||3667|2506|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|fisherman||||||3655|2665|-2|2|2|10|5|0|1|1|0|0|0|0|0 +*|scribe||||||3615|2476|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|thiefguildmaster||||||3693|2509|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||3665|2581|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||3673|2595|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3632|2573|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|shipwright|mapmaker|||||3633|2635|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||3754|2704|40|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||3714|2651|20|2|2|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||3740|2692|40|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||3620|2617|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||3628|2540|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||3687|2477|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||3668|2652|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|bardguildmaster||||||3661|2531|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||3594|2595|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||3671|2615|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||3745|2585|40|2|2|10|5|0|1|1|0|0|0|0|0 +*|carpenter|architect|realestatebroker||||3642|2504|0|2|2|10|5|0|1|1|1|1|0|0|0 +## +## Serpents Hold +## +*|waiter|cook|barkeeper|tavernkeeper|||3009|3455|15|2|2|10|5|0|1|1|1|1|1|0|0 +*|fisherman||||||2940|3410|1|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||2975|3353|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||3051|3367|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2883|3502|10|2|2|10|5|0|1|1|1|1|0|0|0 +*|warriorguildmaster||||||3031|3350|35|2|2|10|5|5|1|1|0|0|0|0|0 +*|animaltrainer||||||3036|3464|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||3003|3355|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|animaltrainer||||||2905|3517|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||3008|3389|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmithguildmaster||||||3007|3408|15|2|2|10|5|5|1|1|0|0|0|0|0 +*|customhairstylist||||||3013|3353|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||2967|3408|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer|healerguildmaster|||||2997|3428|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||3058|3400|15|2|2|10|5|5|1|1|0|0|0|0|0 +*|tinker|tinkerguildmaster|||||2940|3500|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper||||||2972|3425|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|herbalist|alchemist|||||3013|3353|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||2906|3485|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||3018|3426|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||2880|3472|15|2|2|10|5|0|1|1|1|0|0|0|0 +*|waiter|cook|barkeeper||||2972|3425|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||2992|3451|16|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith||||||3007|3408|15|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Skara Brae +## +*|healerguildmaster||||||620|2218|0|2|2|10|5|5|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||602|2180|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|weaponsmith|armorer|||||650|2161|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||659|2141|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|tailorguildmaster|weaver||||650|2178|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||656|2235|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|healer||||||620|2218|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|rangerguildmaster||||||562|2148|0|2|2|10|5|5|1|1|0|0|0|0|0 +*|innkeeper||||||554|2178|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||578|2227|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||592|2277|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|bowyer||||||590|2205|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||586|2170|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||630|2194|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||587|2146|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||627|2163|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|butcher|farmer|||||611|2157|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||570|2121|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||582|2186|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||601|2235|0|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Trinsic +## +*|animaltrainer||||||2011|2804|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|blacksmith|blacksmithguildmaster|||||1935|2766|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||1935|2796|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|scribe||||||2002|2721|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||1897|2805|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||1852|2831|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2033|2801|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||1895|2653|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|shipwright|mapmaker|||||2026|2845|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinkerguildmaster||||||1848|2680|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||1844|2735|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||1990|2889|5|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||2072|2856|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||1991|2867|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||1911|2805|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||1897|2684|10|2|2|10|5|0|1|1|1|0|0|0|0 +*|animaltrainer||||||1822|2739|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2019|2748|30|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||1981|2838|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|baker||||||1880|2802|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||1813|2825|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||1850|2796|-8|2|2|10|5|0|1|1|1|0|0|0|0 +*|warriorguildmaster||||||1939|2739|10|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||1846|2715|10|2|2|10|5|0|1|1|1|1|0|0|0 +## +## Vesper +## +*|fisherguildmaster||||||2963|813|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3012|780|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tinker|tinkerguildmaster|||||2899|790|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||2917|798|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||2920|856|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||2782|969|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2865|852|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2918|672|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|herbalist|alchemist|customhairstylist||||2992|844|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|shipwright|mapmaker|||||2995|815|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|tavernkeeper|waiter|cook|barkeeper|||2901|908|0|2|2|10|5|0|1|1|1|1|1|0|0 +*|banker|minter|||||2881|684|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|minerguildmaster||||||2855|734|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||2861|812|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|jeweler||||||2882|723|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||2961|621|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tailor|weaver|tailorguildmaster||||2840|885|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|tanner|furtrader|||||2860|999|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||2998|760|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|fisherman||||||3034|827|-3|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||2962|885|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|armorer|weaponsmith|||||2835|805|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|provisioner|cobbler|||||2986|637|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||2890|651|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|beekeeper||||||2954|705|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||2987|777|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|warriorguildmaster||||||2841|907|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher|farmer|||||3017|761|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Wind +## +*|scribe||||||5236|142|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5351|56|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||5154|97|5|2|2|10|5|0|1|1|1|0|0|0|0 +*|herbalist|alchemist|customhairstylist||||5215|117|1|2|2|10|5|0|1|1|1|1|0|0|0 +*|scribe||||||5242|180|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5161|32|17|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5148|60|25|2|2|10|5|0|1|1|1|1|0|0|0 +*|banker|minter|||||5347|76|25|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||5263|129|20|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5203|86|5|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5218|175|5|2|2|10|5|0|1|1|0|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5300|90|15|2|2|10|5|0|1|1|1|1|0|0|0 +*|innkeeper||||||5306|37|40|2|2|10|5|0|1|1|0|0|0|0|0 +## +## Yew +## +*|bowyer||||||624|1145|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|shipwright|mapmaker|||||631|1034|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|healer|healerguildmaster|||||540|966|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|baker||||||553|985|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|bowyer||||||570|969|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|tanner|furtrader|||||517|986|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|butcher||||||529|1008|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|banker|minter|||||652|820|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||610|810|0|2|2|10|5|0|1|1|0|0|0|0|0 +*|provisioner|cobbler|||||535|867|0|2|2|10|5|0|1|1|1|0|0|0|0 +*|carpenter|architect|realestatebroker||||564|1011|0|2|2|10|5|0|1|1|1|1|0|0|0 +*|healer|healerguildmaster|||||643|1083|0|2|2|10|5|0|1|1|1|0|0|0|0 +## +## Delucia +## +*|healer|healerguildmaster|||||5191|3989|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|mage|alchemist|mageguildmaster||||5296|3978|37|2|2|10|5|0|1|1|1|1|0|0|0 +*|provisioner|cobbler|||||5219|4012|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|banker|minter|||||5275|3977|37|2|2|10|5|0|1|1|1|0|0|0|0 +*|blacksmithguildmaster|blacksmith|||||5225|4000|38|2|2|10|5|0|1|1|1|0|0|0|0 +*|innkeeper||||||5197|4060|37|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5297|4007|40|2|2|10|5|0|1|1|0|0|0|0|0 +*|tailor|weaver|tailorguildmaster||||5234|4025|37|2|2|10|5|0|1|1|1|1|0|0|0 +## +## Papua +## +*|minter|banker|||||5669|3131|14|2|2|10|5|0|1|1|1|0|0|0|0 +*|mageguildmaster|alchemist|mage||||5731|3192|9|2|2|10|5|0|1|1|1|1|0|0|0 +*|tinkerguildmaster|tinker|||||5726|3243|16|2|2|10|5|0|1|1|1|0|0|0|0 +*|jeweler||||||5662|3150|13|2|2|10|5|0|1|1|0|0|0|0|0 +*|animaltrainer||||||5671|3287|11|2|2|10|5|0|1|1|0|0|0|0|0 +*|butcher||||||5698|3282|15|2|2|10|5|0|1|1|0|0|0|0|0 +*|weaponsmith|armorer|||||5805|3300|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|customhairstylist|alchemist|herbalist||||5714|3202|12|2|2|10|5|0|1|1|1|1|0|0|0 +*|mapmaker|shipwright|||||5805|3270|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|tailorguildmaster|weaver|tailor||||5752|3272|16|2|2|10|5|0|1|1|1|1|0|0|0 +*|fisherman||||||5839|3256|2|2|2|10|5|0|1|1|0|0|0|0|0 +*|baker||||||5746|3200|16|2|2|10|5|0|1|1|0|0|0|0|0 +*|innkeeper||||||5775|3161|14|2|2|10|5|0|1|1|0|0|0|0|0 +*|healerguildmaster|healer|||||5737|3222|11|2|2|10|5|0|1|1|1|0|0|0|0 +*|realestatebroker|architect|carpenter||||5691|3209|11|2|2|10|5|0|1|1|1|1|0|0|0 +*|cobbler|provisioner|||||5736|3263|15|2|2|10|5|0|1|1|1|0|0|0|0 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/WildLife.map b/Data/Monsters/uoml/trammel/WildLife.map new file mode 100644 index 0000000..ff66cb5 --- /dev/null +++ b/Data/Monsters/uoml/trammel/WildLife.map @@ -0,0 +1,186 @@ +############## +## By Nerun ## +############## +overrideid 2126 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3394|628|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3232|510|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4478|3218|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4446|3706|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4682|3662|77|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4692|3494|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4560|3504|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4612|3424|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3607|2417|45|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3555|2525|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3506|2477|28|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3452|2563|32|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3429|2650|43|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3449|2737|49|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3736|2512|35|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3718|2736|38|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3654|2866|61|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3662|2802|51|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3596|2804|51|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3546|2812|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3650|2080|21|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3608|2140|79|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4384|1218|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4468|1006|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4326|1046|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4544|1128|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4510|1262|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4590|1326|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4526|986|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4336|1130|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4448|1334|3|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4540|1454|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4632|1164|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4470|1430|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|4592|1424|3|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|3500|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2998|3590|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2864|150|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3292|570|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3206|366|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3172|664|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3392|424|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3076|150|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|3092|542|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2512|1066|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2554|1142|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2416|1172|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2188|1986|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2654|2286|9|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2946|2168|44|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2744|2014|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2786|2282|13|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2074|1972|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2122|2108|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1932|3125|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1824|3027|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1894|2942|19|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2499|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1005|2647|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|464|2059|8|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|559|2081|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|883|2129|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|968|2476|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|994|2361|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|964|2214|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1087|2401|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1222|2378|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1334|2311|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1315|2192|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1426|2615|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1527|2609|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1582|2722|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1650|2796|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1724|2781|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1727|2702|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1634|2645|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1505|2445|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1699|2560|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1612|2526|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1722|2435|10|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1715|2307|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1531|2351|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1602|2426|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1628|2334|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1563|2277|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1503|2207|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1709|1992|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1498|2040|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1439|2104|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1387|2023|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1377|1911|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1459|1963|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1268|2018|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1173|2103|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1070|2069|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|958|2074|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|999|1839|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|1945|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1229|1655|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1725|1447|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1798|1471|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1958|1305|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1867|1244|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1865|1379|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1769|1330|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1666|1290|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1486|1301|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1351|1359|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1231|1462|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1017|1726|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|398|1305|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|485|1398|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|210|1447|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|851|1770|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|977|1638|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|919|1718|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|876|1639|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|1570|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|725|1483|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|623|1328|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|727|1394|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1020|1360|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1024|1244|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|802|1280|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|855|934|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|771|1013|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|846|1071|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|940|1028|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1152|812|5|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1011|896|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1057|765|1|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|974|374|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1063|541|16|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1018|629|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|951|542|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|805|576|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|937|743|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|890|657|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|895|830|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|689|753|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|748|669|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|764|822|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|834|751|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|782|1156|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|887|1223|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|916|1159|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|993|1130|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1047|1071|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1092|1010|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1172|974|2|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1388|784|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1631|640|22|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1526|960|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1545|813|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1695|809|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1728|691|6|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1802|495|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1857|600|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1884|735|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|1973|751|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2085|658|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2367|748|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2289|917|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2338|989|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2418|999|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2495|978|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2583|993|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2513|782|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2748|660|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2765|754|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2668|1020|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2669|922|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2672|814|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2643|728|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2888|391|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2735|417|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2914|547|0|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2814|492|15|2|5|10|50|50|1|7|5|1|2|2|2 +*|Boar:Cougar:Goat:Horse:Panther:Pig:Sheep|BlackBear:GrizzlyBear:BrownBear:TimberWolf:GreyWolf|WanderingHealer|Bird:Eagle|GreatHart:Hind|Bull:Cow|2688|524|11|2|5|10|50|50|1|7|5|1|2|2|2 \ No newline at end of file diff --git a/Data/Monsters/uoml/trammel/Wrong.map b/Data/Monsters/uoml/trammel/Wrong.map new file mode 100644 index 0000000..b59af81 --- /dev/null +++ b/Data/Monsters/uoml/trammel/Wrong.map @@ -0,0 +1,24 @@ +############## +## By Nerun ## +############## +overrideid 2127 +overridemap 2 +overridemintime 5 +overridemaxtime 10 +## +## Wrong Dungeon +## +## Level 1 +## +*|Jukawarrior||||||5819|591|0|2|2|10|25|5|1|2|0|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5808|588|12|2|2|10|30|15|1|1|1|3|0|0|0 +*|Golemcontroller|Golem|||||5792|544|10|2|2|10|30|6|1|4|4|0|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|586|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5857|562|15|2|2|10|30|7|1|1|1|3|0|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5828|530|0|2|2|10|30|8|1|1|1|3|0|0|0 +## +## Level 2 +## +*|Brigand|Jukalord|Jukamage|Jukawarrior|||5659|563|20|2|2|10|30|10|1|4|1|1|3|0|0 +*|Golem|Jukalord|Jukamage|Jukawarrior|||5724|561|20|2|2|10|30|8|1|1|1|1|3|0|0 +*|Jukalord|Jukamage|Jukawarrior||||5690|534|0|2|2|10|30|8|1|1|1|3|0|0|0 \ No newline at end of file diff --git a/Data/Premium Spawner Tutorial (EN-rev).txt b/Data/Premium Spawner Tutorial (EN-rev).txt new file mode 100644 index 0000000..57b9eb3 --- /dev/null +++ b/Data/Premium Spawner Tutorial (EN-rev).txt @@ -0,0 +1,520 @@ + +----------------------------------+ + | PREMIUM SPAWNER - Basic Tutorial | + +----------------------------------+ + + ------------------------------- + English last revision: Jan/2011 + ------------------------------- + + Premium Spawner project was born as a "mod" of "Ultimate Spawner" +script created by a brazilian scripter called Atomic, who had a SHARD +called AtomicShard. It was based on a script that reads the spawns +information from a bunch of "maps" files and then place it in the +world. The original script was modified by Nerun (myself) and when the +number of changes to the original script became great, i changed the +name of my version. The Premium is the successor of the Ultimate Spawner +v4.0 R5 (until then, the simple addition of "R", followed by a number +differentiated my version from original script designed by Atomic). +The fundamental differences between the default RunUO Spawner system are: + + - "Premium" has new properties: + 1. SpawnID - Spawners IDentity: used to unload or save spawns + 2. OverrideMap - automatically change all map files from the + spawners entries bellow it + 3. OverrideID - works as OverrideMap, but for SpawnID + 4. OverrideMinTime - works as OverrideMap, but for MinDelay + 5. OverrideMaxTime - works as OverrideMap, but for MaxDelay + + - "Premium" has it own engine, not using the default "Spawner" +that comes with RunUO, instead it uses the "PremiumSpawner". You can +use both systems simultaneously. + + - "Premium" has map files (pre-spawned world). + + - "Premium" is user friendly. + + The basics of basics that you need to know is that this system is +useful to remain "safe" (in a ".map" file) the spawners that you created +with so much effort. Well, suppose you have to erase everything and start +the world from scratch. You will have to place more than ten thousand +spawns, by hand, again? NO! You just use a command prompt, everything +will be generated again, and without effort. All effort is done in the +process of map file creation (that you can do in-game). + The current release is in version 5.2.x, and is considered very +mature (in terms of stability, reliability, features and ease of use) +and complete (in terms of world spawns). + + +INDEX: + 1. PREMIUM SPAWNER INSTALATION + 2. PART I - Main Menu + 3. PART II - Writing a Map File (Basics) + 4. PART III - Using Maps "In-Game" (B�sics) + 5. PART IV - Writing a Map File (Advanced) + 6. PART V - Using Maps "In-Game" (Advanced) + 7. PART VI - Edition Options + + +>>>>>>>>>>>>>>>>>>>>>>>>>>> +PREMIUM SPAWNER INSTALATION +<<<<<<<<<<<<<<<<<<<<<<<<<<< + + Spawner creation system, Premium "Spawner" consists in a collection +of scripts. As I added many scripts, I will not list them here. Today this +system is distributed in a package called "Nerun's Distro". There were +several packages in the beginning, but for convenience I have grouped in +a single distribution. This package also includes other resources, such as +spawns maps for use with this system, as gumps (menus) easy to use to further +facilitate the settlement of your world. This distro can be found in the +RunUO forum at http://www.runuo.com/. + +To install the distro: + +1) Unrar "NerunsDistro-rx.rar". + +2) You will se two folders inside: "Data" and "Scripts". Plus some files + (including this tutiorial, changes history, benchmark tests, SpawnsID of + all maps etc). Read the files for more usefull information if you want. + +3) Cut the folders "Data" and "Scripts". + +4) Go to "c:\RunUO 2.1\" (or where you install it) and paste it there. Windows + Explorer will say that those folders already exists, and will ask if you + want to overwrite, click "yes to all". + + +>>>>>>>>>>>>>>>>>> +PART I - Main Menu +<<<<<<<<<<<<<<<<<< + + To access the Main Menu wrote "[spawner" (without quotes) in the +command prompt. There are a lot of options in the menu, in two pages. These +options are self-explained: + + +GUMP NAME COMMAND PROMPT +=========================================================== +WORLD CREATION OPTIONS: + Create World Gump ------------------ [createworld +SPAWN OPTIONS: + Spawn Trammel/Felucca -------------- [spawntrammel or [spawnfelucca + Spawn Ilshenar --------------------- [spawnilshenar + Spawn Malas ------------------------ [spawnmalas + Spawn Tokuno ----------------------- [spawntokuno + Spawn Ter Mur ---------------------- [spawntermur +UNLOAD SPAWNS + Unload Trammel/Felucca spawns ------ [unloadtrammel or [unloadfelucca + Unload Ilshenar spawns ------------- [unloadilshenar + Unload Malas spawns ---------------- [unloadmalas + Unload Tokuno spawns --------------- [unloadtokuno + Unload Ter Mur Spawns -------------- [unloadtermur +SAVE OPTIONS: + Save All spawns (spawns.map) ------- [spawngen save + Save 'By Hand' spawns (byhand.map) - [spawngen savebyhand + Save spawns inside region ---------- [spawngen save RegionName + Save spawns by coordinates --------- [spawngen save x1 y1 x2 y2 +REMOVE OPTIONS: + Remove All spawners (all facets) --- [spawngen remove + Remove All spawners (current map) -- [spawnrem + Remove spawners by ID -------------- [spawngen unload SpawnID + Remove spawners by Coordinates ----- [spawngen remove x1 y1 x2 y2 + Remove spawners inside Region ------ [spawngen remove RegionName +EDITION OPTIONS: + Spawn Editor ----------------------- [editor + Clear All Facets ------------------- [clearall + Set my own body to GM Style -------- [gmbody +CONVERSION UTILITY: + RunUO Spawns to PremiumSpawner ----- [rse + + + As you can see, it centered on a single menu all the system commands, +you do not know how to write each line to use them, simply click, follow +the instructions and it is done. The following sections will describe how to +create a map file, and how to use the command line instead of the Menu. + + +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +PART II - Writing a Map File (Basics) +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + Notepad can be used to create map files. You will see the following +basic information on a map: + +## Britain Graveyard: +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 + + This map above provides information from all spawns of the Britain +Graveyard. Let's analyze it: + + - 1st Line: Starts with "##", this double "sharp" marks the beginning of + a comment. In other words, what comes after him will not be read by the + script. It is usually used to provide information about the script: + Dungeon map name, actual review and so on. + + - 2nd Line: The spawner itself. Each line is a spawner, but the advantage + of PremiumSpawner is that it contains up to 6 FakeSpawners within + themselves, which are nothing more than spawners with the same + attributes of distance, time etc, but with different creatures and + amounts: + + *|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3| + 4|0|0|0 + +- All Spawners starts with "*" followed by "|". This "|" separates the + information into the line. The first 6 spaces are the names of the + creatures, which in this case are: + + Spawner 1: Spectre OR Wraith (the ":" serves to add several + creatures in a random list) + + Spawner 2: Skeleton + + Spawner 3: Zombie + + Spawner 4: Empty (none) + + Spawner 5: Empty (none) + + Spawner 6: Empty (none) + + Each of them are called "Fake Spawner": are 6 spawners inside only + one spawner. + +- The three numbers that come after the creatures lists define the place + where the spawner will be created. Following the "XYZ" format (all + details of Spawners are separated by a "|"). In this case, the spawner + will appear at coordinates "1369 | 1475 | 10", in other words, + X = 1369, Y = 1475 and Z = 10. If you type "[go 1369 1475 10" you will + go to the place where this Spawner will appear. + + +- The fourth number says in wich facet the Spawner will be placed. Note + that this number is 2. The definition of the maps follow this pattern: + + 0 = Felucca AND Trammel + + 1 = Felucca + + 2 = Trammel + + 3 = Ilshenar + + 4 = Malas + + 5 = Tokuno + + So deduct that the spawner will be placed in Trammel, because the room + number (the map) is the number 2. + +- Next 2 numbers after facet number: defines respectively the minimum + and the maximum respawn time. That is, the creatures that spawn will + respawn in a randomly chosen interval between the minimum and maximum + time. In the example We have "5 | 10 |" (always a "|"). Time is in + minutes, so creatures will respawn between 5 and 10 min after being + killed by players. + +- Next 2 numbers after respawn time: defines WalkingRange and HomeRange. + In this case, 30 WalkingRange and 20 HomeRange. The creatures will walk + for up to 30 "boxes" (those who we see in a maximum zoom in game) + away from the spawner. But they will "respawn" randomly within a + radius of up to 20 "boxes" from the spawner. Note that the HomeRange + is always less than or equal to WalkingRange, NEVER MORE. + +- Next number after Ranges: identifies the spawn, is a "SpawnID", it + tell us to which "spawn group" it belongs. By default, it is always + 1. If you create any spawner in game using the "[add premiumspawner" + command, the SpawnID will be the number 1. This identifies the + spawners created "by hand". But the maps can have any number of + SpawnID. It is advisable that all spawners of the same map, have the + same SpawnID. We will see why bellow. + +- The last 6 numbers, also important, say how many monsters defined at + the beginning of the spawner (the first 6 spaces) will be generated + by that spawner. If the numbers are "2 | 3 | 4 | 0 | 0 | 0" will be + generated 2 Specters OR Wraiths (or 1 of each), 3 skeletons and 4 + Zombies. The latest figures are 0: nothing is created in the past + 3 spawners, even if you define a value, nothing could be generated, + because no creature was listed there (as we saw). + + As observation, note that most of spawner's properties, as +described above, can be defined without the need to "see" where the +spawner will appear, but the coordinates will need to "see". Because if +you choose coordinates randomly, risks creating a spawner in an +inaccessible place, for example, in the middle of the ocean! So you must +go to the place where you would like spawner appear and use the command +"[get location" or "[where" in that place. Then write down the details +that will appear on the screen. + Made the map, just save it in the folder Data / Monsters (if there +isn't a folder Date/Monsters, it's time to create one. Click "Save As", +select the Save as Type "All Files" and then type a name for the map, not +forgetting to set ".map" at the end of the name. In the above example, +if we had made that map, we could give him the name "graveyard.map". + +SUMMARIZING + Default spawner format: + +*|List1|List2|List3|List4|List5|List6|X|Y|Z|facet|MinTime|MaxTime| +WalkingRange|HomeRange|SpawnID|Count1|Count2|Count3|Count4|Count5|Count6 + + + +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +PART III - Using Maps "In-Game" (B�sics) +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + This is simple, are just a commands list to be used in game for +the PremiumSpawner's engine generates spawners from the maps created. On +the assumption that you already installed the required scripts in RunUO +folder, you can use the following commands: + + + - [spawngen MapName.map + Read maps and create spawners. In the example you should use + "[spawngen graveyard.map" (no quotes). + + - [spawngen remove + Dungerous command! It will DELETE all PremiumSpawners of ALL facets + of UO, done "by hand" or "by map"! + + - [spawngen save + Usefull command: saves in a file called "Spawns.map" ALL the + PremiumSpawners in ALL UO facets, done "by hand" or "by map"! + Usefull if tou did a lot of custom maps and use this distro too. + After this, a simple "[spawngen spawns.map" will spawn everything + again. + + - [spawnrem + It will DELETE all PremiumSpawners of actual facet (that one + where your character is standing). Other facets will remain + spawned. + + + +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +PART IV - Writing a Map File (Advanced) +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + +Multiple Creatures and Randomness +--------------------------------- + + You have learned to create maps using the class method, in other +words, you type the name of the creature and then the statistics (count, +delay, range etc). But what if you want more than one type of creature in +the same spawner? + + Use the method of two dots (":"). In this case, simply separate +the creatures that you want with a ":" as in the example below: + +*|Spectre:Wraith||||||1369|1475|10|2|5|10|30|20|1|10|0|0|0|0|0 + + As a result, the spawner randomly selecs within the amount +indicated, among the creatures on the list, separated by two dots. +Remembering that you can put as many creatures you like, all separated by +":". In the example, we could have 7 Wraith and 3 Specter, or 5 of each, +this number will vary, but the tendency is to remain in the ratio of +count / creatures. In the example: count = 10, creatures = 2. Ratio 5. +So the spawns will tend to 5 Wraith and 5 Specter. Now let's play with +statistics. And if we want to have a greater chance of appearing more +Spectres than Wraiths? So we can write in this way: + +*|Spectre:Spectre:Wraith||||||1369|1475|10|2|5|10|30|20|1|10|0|0|0|0|0 + + The ratio now is 3.3 for creature, so the chances will be now: +66.6% Spectres and 33.3% Wraiths. + As an advise, never place inside the same Spawner (FakeSpawner), +"target" creatures with "non-target" creatures or items. What i want to +say is: don't place a Spectre, a Wraith and a dog or a bottle to spawn +together: + +*|Spectre:Wraith:Dog||||||1369|1475|10|2|5|10|30|20|1|10|0|0|0|0|0 + + If you do it, sometime the players will kill all monsters, but +will not kill the dogs, and all the 10 creatures of that spawner will +be just dogs! It happens because the Spawner spawn just the remaning +amount (amount not spawned). If it spawn 10 creatures: 5 Spectres, +3 Wraiths and 2 Dog, and if players kill all monsters except the dogs, +next time the spawner will spawn 8 creatures (cause Dogs are alive) and +it can spawn a few Spectres and Wraiths and a lot of Dogs again! And +so on... I dit it in past releases, already fixed. + + +Override Maps +------------- + + And if you want to do a map that works both in Trammel and Felucca? +Instead of edit the facet number in each line (spawner) of your map, +you can superscribe the facet number with a simple, only, command line. +In our example above, that generates spawns only in Trammel, to generates +spawns in Trammel AND Felucca, we adds an "overridemap": + +overridemap 0 +## Britain Graveyard: +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 + + Here, the number "2" of that spawner (the facet), will be read as "0" +by the spawn generator engine. Facet numbers are the same as described in +"PART II - Writing a Map File (Basics)". + + +Override SpawnID +---------------- + + Do the same as OverrideMap, but for SpawnIDs. SpawnID "1" will be read +as "14", as bellow: + +overrideid 14 +overridemap 0 +## Britain Graveyard: +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 + + +Override DelayTime +------------------ + + Do the same as OverrideMap and OverrideID, but for delay time. + + overridemintime + + and or + + overridemaxtime + +Exemple: + +overridemintime 10 +overridemaxtime 20 +overrideid 14 +overridemap 0 +## Britain Graveyard: +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 + + The delays (min 5 and max 10 minutes) will be read as 10 and 20 +minutes. + + + +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +PART V - Using Maps "In-Game" (Advanced) +<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + +Settlement In-Game +------------------ + + Another way to settlement your world (place spawns) is to go "in-game" +and adds spawners by hand, with command [add premiumspawner CreatureName. +And "set" the attributes (x = number): + +[set count x homerange x spawnrange x maxdelay x mindelay x + + +Commands to Save and to Remove Spawns +------------------------------------- + + After spawn the desired area, you need to save yours spawns either with +[spawngen save or with some advanced options. Just type [spawner and look under +SAVE/REMOVE OPTIONS. There is a GUMP for each command. But you can use the +command prompt instead: + +[spawngen savebyhand + To save spawns done "by hand" ([add premiumspawner... all by hand premium + spawners has SpawnID = 1). Spawns will be saved in "byhand.map" file in + Data/Monsters folder. + +[spawngen save x1 y1 x2 y2 + To save all premium spawners in a spawns.map file. All premium spawners + inside the rectangle area (x1 y1 x2 y2) will be saved. + + X and Y are coordinates: + + (x1,y1)------+ All premium spawners between coordinates (x1,y1) + | | and coordinates (x2,y2) will be saved. + | | + | | + +---------(x2,y2) + +[spawngen save + Save premium spawners inside a region defined by RunUO to a spawns.map + file, in Data/Monsters. + Complete list of regions are in c:/RunUO/Data/Regions.xml. + Use [where to see the region where you are. + Open Regions.xml to understand regions: + + + + + + + + + + + + + + + As you see, a Region is a lot of rectangles. + +NOTE: "[spawngen remove" can be used with the same options as for +"[spawngen save" above, but will remove spawns instead of save. + +NOTE: Go to Data/Monsters and rename spawns.map or byhand.map to another name, +because each time you save with those options, the old file will be deleted and +a new one will be saved over it. + +EXAMPLE: + "[spawngen save minoc" (save spawns inside Minoc region) + We can rename the spawns.map to Minoc.map. + + +Unloading Maps (recommended) +---------------------------- + + The better way to remove spawns instead of using "[spawngen remove" +and other Spartan options is the "Unload" method: + +[spawngen unload SpawnID + + If you define a SpawnID to each custom map you has you can unload +or remove the entire map easier. Example: Graveyards.map saw above. All the +premium spawners inside that map has SpawnID = 1. Lets see: + +## Britain Graveyard: +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 + + The problem is that 1 is the default number to "by hand" maps. +Lets change the ID of this map. In the example above we just need to change +one number (that between numbers 20 and 2). But if the map had 100, maybe +1000 premium spawners? hard work uh? Because of it there is the "overrideid" +option. It set all the SpawnIDs bellow it to the desired ID. So lets do it: + +overrideid 14 +## Britain Graveyard: +*|Spectre:Wraith|Skeleton|Zombie||||1369|1475|10|2|5|10|30|20|1|2|3|4|0|0|0 + + Although each spawner still have 1 as ID on each line, the +"overrideid 14" will force the spawn generator engine to read that "1" as +if "14". Later in the game, if I want to remove this map is just type +"[spawngen unload 14" and ready. None of my other spawns will be changed +or removed. + + +>>>>>>>>>>>>>>>>>>>>>>>>> +PART VI - Edition Options +<<<<<<<<<<<<<<<<<<<<<<<<< + +[editor + Opens the spawn editor of course. This will list all the + PremiumSpawners in the left side. In the right column you can see + a bunch of options to select only the desired spawners, go to it, + see it properties, and see it creatures. + +[clearall + Works as [Clearfacet but for ALL facets. Caution here. + +[GMbody + Will set some common attributes to GMs. Target yourself. A lot of + items, skills, stats, robes, full spellbooks etc, will appear in + your backpack. You always set your body to human body. You add + titles to [GM], [Admin], etc. \ No newline at end of file diff --git a/Data/Regions.xml b/Data/Regions.xml new file mode 100644 index 0000000..4d937dc --- /dev/null +++ b/Data/Regions.xml @@ -0,0 +1,2450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/ShrinkConfig.xml b/Data/ShrinkConfig.xml new file mode 100644 index 0000000..fe5119d --- /dev/null +++ b/Data/ShrinkConfig.xml @@ -0,0 +1,39 @@ + + + + + true + false + false + 10 + false + + + BlessStatus.None + + 10 + 50 + + + Server.Mobiles.PackHorse + Server.Mobiles.PackLlama + Server.Mobiles.Beetle + + + diff --git a/Data/SpawnDefinitions.xml b/Data/SpawnDefinitions.xml new file mode 100644 index 0000000..8ad0766 --- /dev/null +++ b/Data/SpawnDefinitions.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/SpawnIDs Table.xls b/Data/SpawnIDs Table.xls new file mode 100644 index 0000000..ded2b0b Binary files /dev/null and b/Data/SpawnIDs Table.xls differ diff --git a/Data/Uninst/ND.uuf b/Data/Uninst/ND.uuf new file mode 100644 index 0000000..2af3110 --- /dev/null +++ b/Data/Uninst/ND.uuf @@ -0,0 +1,57 @@ +######################################### +# Nerun's Universal Uninstallation File # +# for RunUO # +# - don't remove it! # +# - don't edit it! # +# # +######################################### +rm/Data/signs.cfg +rn/Data/signs.cfg.bak +rm/Data/treasure.cfg +rn/Data/treasure.cfg.bak +rm/Data/Decoration/Britannia/britain.cfg +rn/Data/Decoration/Britannia/britain.cfg.bak +rm/Data/Decoration/Britannia/NERUN-BritainSewers.cfg +rm/Data/Decoration/Britannia/NERUN-SeaMarket.cfg +rm/Data/Decoration/Malas/NERUN-Malas.cfg +sh/Data/Decoration/Mondain's Legacy +rm/Data/Decoration/Trammel/_haven additions.cfg +rn/Data/Decoration/Trammel/_haven additions.cfg.bak +rm/Data/Decoration/Trammel/collector quest.cfg +rn/Data/Decoration/Trammel/collector quest.cfg.bak +rm/Data/Decoration/Trammel/haven.cfg +rn/Data/Decoration/Trammel/haven.cfg.bak +rm/Data/Decoration/Trammel/NERUN-HavenIsland.cfg +rm/Data/Decoration/Trammel/NERUN-NewHaven.cfg +rm/Data/Decoration/Trammel/NERUN-OldHaven.cfg +rm/Data/Decoration/Trammel/uzeraan turmoil quest.cfg +rn/Data/Decoration/Trammel/uzeraan turmoil quest.cfg.bak +rm/Data/Locations/felucca.xml +rn/Data/Locations/felucca.xml.bak +rm/Data/Locations/termur.xml +rm/Data/Locations/trammel.xml +rn/Data/Locations/trammel.xml.bak +sh/Data/Monsters +rm/Scripts/Commands/GenTeleporter.cs +rn/Scripts/Commands/GenTeleporter.cs.bak +sh/Scripts/Customs/Nerun's Distro +rm/Scripts/Engines/Plants/MainPlantGump.cs +rn/Scripts/Engines/Plants/MainPlantGump.cs.bak +rm/Scripts/Engines/Plants/PlantPourTarget.cs +rn/Scripts/Engines/Plants/PlantPourTarget.cs.bak +rm/Scripts/Engines/Quests/Core/QuestSystem.cs +rn/Scripts/Engines/Quests/Core/QuestSystem.cs.bak +rm/Scripts/Gumps/ConfirmReleaseGump.cs +rn/Scripts/Gumps/ConfirmReleaseGump.cs.bak +rm/Scripts/Gumps/Go/GoGump.cs +rn/Scripts/Gumps/Go/GoGump.cs.bak +rm/Scripts/Mobiles/BaseCreature.cs +rn/Scripts/Mobiles/BaseCreature.cs.bak +rm/Scripts/Mobiles/AI/BaseAI.cs +rn/Scripts/Mobiles/AI/BaseAI.cs.bak +rm/Scripts/Mobiles/Animals/Mounts/SeaHorse.cs +rn/Scripts/Mobiles/Animals/Mounts/SeaHorse.cs.bak +rm/Scripts/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs +rn/Scripts/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs.bak +rm/Scripts/Skills/Stealth.cs +rn/Scripts/Skills/Stealth.cs.bak \ No newline at end of file diff --git a/Data/bodyTable.cfg b/Data/bodyTable.cfg new file mode 100644 index 0000000..0aefa68 --- /dev/null +++ b/Data/bodyTable.cfg @@ -0,0 +1,966 @@ +########################################## +# +# Body type table +# +# Format: +# BodyID BodyType +# +# Types: +# Empty (default) +# Monster +# Sea +# Animal +# Human +# Equipment +# +########################################## + +1 Monster +2 Monster +3 Monster +4 Monster +5 Animal +6 Animal +7 Monster +8 Monster +9 Monster +10 Monster +11 Monster +12 Monster +13 Monster +14 Monster +15 Monster +16 Monster +17 Monster +18 Monster +19 Monster +20 Monster +21 Monster +22 Monster +23 Animal +24 Monster +25 Animal +26 Monster +27 Animal +28 Monster +29 Animal +30 Monster +31 Monster +33 Monster +34 Animal +35 Monster +36 Monster +37 Animal +38 Monster +39 Monster +40 Monster +41 Monster +42 Monster +43 Monster +44 Monster +45 Monster +46 Monster +47 Monster +48 Monster +49 Monster +50 Monster +51 Monster +52 Animal +53 Monster +54 Monster +55 Monster +56 Monster +57 Monster +58 Monster +59 Monster +60 Monster +61 Monster +62 Monster +63 Animal +64 Animal +65 Animal +66 Monster +67 Monster +68 Monster +69 Monster +70 Monster +71 Monster +72 Monster +73 Monster +74 Monster +75 Monster +76 Monster +77 Monster +78 Monster +79 Monster +80 Monster +81 Animal +82 Monster +83 Monster +84 Monster +85 Monster +86 Monster +87 Monster +88 Animal +89 Monster +90 Monster +91 Monster +92 Monster +93 Monster +94 Monster +96 Monster +97 Animal +98 Animal +99 Animal +100 Animal +101 Monster +102 Monster +103 Monster +104 Monster +106 Monster +107 Monster +108 Monster +109 Monster +110 Monster +111 Monster +112 Monster +113 Monster +114 Animal +115 Animal +116 Animal +117 Animal +118 Animal +119 Animal +120 Animal +121 Animal +122 Animal +123 Monster +124 Monster +125 Monster +126 Monster +127 Animal +128 Monster +129 Monster +130 Monster +131 Monster +132 Animal +133 Animal +134 Animal +135 Monster +136 Monster +137 Monster +138 Monster +139 Monster +140 Monster +141 Monster +142 Monster +143 Monster +144 Sea +145 Sea +146 Monster +147 Monster +148 Monster +149 Monster +150 Sea +151 Sea +152 Monster +153 Monster +154 Monster +155 Monster +157 Monster +158 Monster +159 Monster +160 Monster +161 Monster +162 Monster +163 Monster +164 Monster +165 Monster +166 Monster +167 Animal +168 Monster +170 Animal +171 Animal +172 Monster +173 Monster +174 Monster +175 Monster +176 Monster +177 Animal +178 Animal +179 Animal +180 Monster +181 Monster +182 Monster +183 Human +184 Human +185 Human +186 Human +187 Animal +188 Animal +189 Monster +190 Animal +191 Animal +192 Animal +193 Animal +194 Animal +195 Animal +200 Animal +201 Animal +202 Animal +203 Animal +204 Animal +205 Animal +206 Monster +207 Animal +208 Animal +209 Animal +210 Animal +211 Animal +212 Animal +213 Animal +214 Animal +215 Monster +216 Animal +217 Animal +218 Animal +219 Animal +220 Animal +221 Animal +223 Animal +225 Animal +226 Animal +228 Animal +231 Animal +232 Animal +233 Animal +234 Animal +237 Animal +238 Animal +268 Equipment +281 Equipment +283 Equipment +290 Animal +291 Animal +292 Animal +300 Monster +301 Monster +302 Monster +303 Monster +304 Monster +305 Monster +306 Monster +307 Monster +308 Monster +309 Monster +310 Monster +311 Monster +312 Monster +313 Monster +314 Monster +315 Monster +316 Monster +317 Monster +318 Monster +319 Monster +#325 Equipment +349 Equipment +400 Human +401 Human +402 Human +403 Human +404 Equipment +405 Equipment +406 Equipment +407 Equipment +408 Equipment +409 Equipment +410 Equipment +411 Equipment +412 Equipment +413 Equipment +414 Equipment +415 Equipment +416 Equipment +417 Equipment +418 Equipment +419 Equipment +430 Equipment +431 Equipment +434 Equipment +435 Equipment +447 Equipment +448 Equipment +449 Equipment +455 Equipment +465 Equipment +466 Equipment +468 Equipment +469 Equipment +476 Equipment +477 Equipment +479 Equipment +480 Equipment +481 Equipment +482 Equipment +483 Equipment +484 Equipment +485 Equipment +486 Equipment +490 Equipment +492 Equipment +500 Equipment +501 Equipment +502 Equipment +503 Equipment +504 Equipment +505 Equipment +521 Equipment +523 Equipment +525 Equipment +527 Equipment +528 Equipment +529 Equipment +530 Equipment +531 Equipment +538 Equipment +540 Equipment +541 Equipment +542 Equipment +543 Equipment +544 Equipment +545 Equipment +546 Equipment +548 Equipment +549 Equipment +550 Equipment +554 Equipment +555 Equipment +556 Equipment +557 Equipment +560 Equipment +561 Equipment +562 Equipment +563 Equipment +564 Equipment +565 Equipment +566 Equipment +574 Monster +576 Equipment +577 Equipment +578 Equipment +579 Equipment +580 Equipment +581 Equipment +582 Equipment +584 Equipment +585 Equipment +586 Equipment +587 Equipment +588 Equipment +589 Equipment +590 Equipment +591 Equipment +592 Equipment +593 Equipment +594 Equipment +595 Equipment +596 Equipment +597 Equipment +598 Equipment +599 Equipment +600 Equipment +601 Equipment +602 Equipment +603 Equipment +604 Equipment +611 Equipment +612 Equipment +613 Equipment +614 Equipment +615 Equipment +616 Equipment +617 Equipment +618 Equipment +619 Equipment +620 Equipment +621 Equipment +622 Equipment +623 Equipment +624 Equipment +625 Equipment +626 Equipment +627 Equipment +628 Equipment +629 Equipment +630 Equipment +631 Equipment +633 Equipment +635 Equipment +636 Equipment +637 Equipment +638 Equipment +639 Equipment +643 Equipment +644 Equipment +645 Equipment +646 Equipment +648 Equipment +649 Equipment +651 Equipment +653 Equipment +654 Equipment +655 Equipment +656 Equipment +657 Equipment +658 Equipment +659 Equipment +660 Equipment +661 Equipment +662 Equipment +663 Equipment +664 Equipment +665 Equipment +666 Equipment +667 Equipment +668 Equipment +669 Equipment +670 Equipment +671 Equipment +672 Equipment +674 Equipment +675 Equipment +676 Equipment +677 Equipment +678 Equipment +679 Equipment +680 Equipment +681 Equipment +682 Equipment +683 Equipment +687 Equipment +688 Equipment +690 Equipment +691 Equipment +692 Equipment +693 Equipment +694 Equipment +695 Equipment +696 Equipment +697 Equipment +698 Equipment +699 Equipment +700 Equipment +701 Equipment +702 Equipment +703 Equipment +710 Equipment +712 Equipment +713 Equipment +715 Equipment +716 Equipment +720 Equipment +721 Equipment +722 Equipment +723 Equipment +724 Equipment +725 Equipment +726 Equipment +727 Equipment +728 Equipment +729 Equipment +730 Equipment +731 Equipment +732 Equipment +733 Equipment +734 Equipment +735 Equipment +736 Equipment +740 Equipment +742 Equipment +743 Equipment +744 Human +745 Human +746 Monster +747 Monster +748 Monster +749 Monster +750 Human +751 Human +752 Monster +753 Monster +754 Monster +755 Monster +756 Monster +757 Monster +758 Monster +759 Equipment +760 Equipment +761 Equipment +762 Equipment +763 Monster +764 Monster +765 Monster +766 Monster +767 Monster +768 Monster +769 Monster +770 Monster +771 Monster +772 Monster +773 Monster +774 Monster +775 Monster +776 Monster +777 Monster +778 Monster +779 Monster +780 Monster +781 Monster +782 Monster +783 Monster +784 Monster +785 Monster +786 Monster +787 Monster +788 Monster +789 Monster +790 Monster +791 Animal +792 Monster +793 Animal +794 Animal +795 Monster +796 Monster +797 Monster +798 Monster +799 Animal +800 Equipment +801 Equipment +802 Equipment +803 Equipment +804 Monster +805 Monster +806 Monster +807 Monster +808 Monster +820 Equipment +824 Equipment +825 Equipment +826 Equipment +827 Equipment +828 Equipment +846 Equipment +848 Equipment +900 Equipment +901 Equipment +902 Equipment +903 Equipment +904 Equipment +905 Equipment +906 Equipment +909 Equipment +910 Equipment +911 Equipment +912 Equipment +913 Equipment +921 Equipment +922 Equipment +923 Equipment +924 Equipment +925 Equipment +926 Equipment +927 Equipment +928 Equipment +929 Equipment +930 Equipment +931 Equipment +932 Equipment +933 Equipment +934 Equipment +935 Equipment +936 Equipment +937 Equipment +938 Equipment +939 Equipment +971 Equipment +972 Equipment +973 Equipment +980 Equipment +981 Equipment +982 Equipment +983 Equipment +984 Equipment +985 Equipment +986 Equipment +987 Human +988 Human +990 Human +991 Human +992 Equipment +993 Equipment +994 Human +998 Monster +999 Monster +1268 Equipment +1281 Equipment +1283 Equipment +1325 Equipment +1349 Equipment +1404 Equipment +1405 Equipment +1406 Equipment +1407 Equipment +1408 Equipment +1409 Equipment +1410 Equipment +1411 Equipment +1412 Equipment +1413 Equipment +1414 Equipment +1415 Equipment +1416 Equipment +1417 Equipment +1418 Equipment +1419 Equipment +1430 Equipment +1431 Equipment +1434 Equipment +1435 Equipment +1447 Equipment +1448 Equipment +1449 Equipment +1455 Equipment +1465 Equipment +1466 Equipment +1468 Equipment +1469 Equipment +1476 Equipment +1477 Equipment +1479 Equipment +1480 Equipment +1481 Equipment +1482 Equipment +1483 Equipment +1484 Equipment +1485 Equipment +1486 Equipment +1490 Equipment +1492 Equipment +1521 Equipment +1523 Equipment +1525 Equipment +1527 Equipment +1528 Equipment +1529 Equipment +1530 Equipment +1531 Equipment +1538 Equipment +1540 Equipment +1542 Equipment +1543 Equipment +1544 Equipment +1545 Equipment +1546 Equipment +1548 Equipment +1549 Equipment +1550 Equipment +1554 Equipment +1555 Equipment +1556 Equipment +1557 Equipment +1560 Equipment +1561 Equipment +1562 Equipment +1563 Equipment +1564 Equipment +1565 Equipment +1566 Equipment +1672 Equipment +1674 Equipment +1675 Equipment +1676 Equipment +1677 Equipment +1678 Equipment +1679 Equipment +1680 Equipment +1681 Equipment +1682 Equipment +1683 Equipment +1684 Equipment +1685 Equipment +1686 Equipment +1687 Equipment +1688 Equipment +1690 Equipment +1691 Equipment +1692 Equipment +1693 Equipment +1694 Equipment +1695 Equipment +1696 Equipment +1697 Equipment +1698 Equipment +1699 Equipment +1700 Equipment +1701 Equipment +1702 Equipment +1703 Equipment +1710 Equipment +1712 Equipment +1713 Equipment +1715 Equipment +1716 Equipment +1720 Equipment +1721 Equipment +1722 Equipment +1723 Equipment +1724 Equipment +1725 Equipment +1726 Equipment +1727 Equipment +1728 Equipment +1729 Equipment +1730 Equipment +1731 Equipment +1732 Equipment +1733 Equipment +1734 Equipment +1735 Equipment +1736 Equipment +1740 Equipment +1742 Equipment +1743 Equipment +1759 Equipment +1761 Equipment +1762 Equipment +1900 Equipment +1901 Equipment +1902 Equipment +1903 Equipment +1909 Equipment +1910 Equipment +1911 Equipment +1912 Equipment +1913 Equipment +1921 Equipment +1922 Equipment +1923 Equipment +1924 Equipment +1925 Equipment +1926 Equipment +1927 Equipment +1928 Equipment +1929 Equipment +1971 Equipment +1973 Equipment + +# SE Creatures +242 Monster +247 Monster +240 Monster +252 Monster +241 Monster +244 Monster +255 Monster +253 Monster +245 Monster +250 Monster +251 Monster +249 Monster +254 Animal +243 Animal +246 Animal +248 Animal +196 Monster +199 Monster +169 Animal + +# SE Equipment +425 Equipment +426 Equipment +423 Equipment +424 Equipment +442 Equipment +443 Equipment +444 Equipment +445 Equipment +446 Equipment +450 Equipment +451 Equipment +456 Equipment +457 Equipment +458 Equipment +459 Equipment +460 Equipment +461 Equipment +462 Equipment +463 Equipment +464 Equipment +467 Equipment +470 Equipment +471 Equipment +472 Equipment +473 Equipment +474 Equipment +478 Equipment +487 Equipment +488 Equipment +489 Equipment +491 Equipment +506 Equipment +512 Equipment +513 Equipment +514 Equipment +516 Equipment +517 Equipment +518 Equipment +519 Equipment +520 Equipment +526 Equipment +532 Equipment +533 Equipment +534 Equipment +535 Equipment +536 Equipment +537 Equipment +539 Equipment +547 Equipment +551 Equipment +552 Equipment +553 Equipment +558 Equipment +559 Equipment +567 Equipment +568 Equipment +569 Equipment +570 Equipment +571 Equipment +572 Equipment +575 Equipment +583 Equipment +809 Equipment +810 Equipment +811 Equipment +812 Equipment +813 Equipment +814 Equipment +815 Equipment +816 Equipment +817 Equipment +818 Equipment +819 Equipment +821 Equipment +822 Equipment +823 Equipment +833 Equipment +834 Equipment +835 Equipment +836 Equipment +837 Equipment +838 Equipment +839 Equipment +840 Equipment +841 Equipment +842 Equipment + + +# ep1 Equipment +942 Equipment +943 Equipment +944 Equipment +945 Equipment +946 Equipment +947 Equipment +948 Equipment +950 Equipment +951 Equipment +952 Equipment +953 Equipment +954 Equipment +955 Equipment +956 Equipment +957 Equipment +958 Equipment +959 Equipment +960 Equipment +961 Equipment +962 Equipment +963 Equipment +964 Equipment +965 Equipment +966 Equipment +967 Equipment +968 Equipment +969 Equipment +974 Equipment +975 Equipment +976 Equipment +977 Equipment +#Added by JP +920 Equipment +907 Equipment +908 Equipment +914 Equipment +915 Equipment +941 Equipment +896 Equipment +897 Equipment +898 Equipment +899 Equipment +886 Equipment +916 Equipment +917 Equipment +918 Equipment +919 Equipment +978 Equipment +979 Equipment +995 Equipment +996 Equipment +989 Equipment +997 Equipment +890 Equipment #More Hair +891 Equipment #More Hair +892 Equipment #More Hair +893 Equipment #More Hair +894 Equipment #More Hair +895 Equipment #More Hair +889 Equipment #Elf Male Hair 11 + + + +#ep1 races +605 Human # elf male +606 Human # elf female +607 Human # elf male ghost +608 Human # elf female ghost + +#ep1 creatures +256 Monster # Chief Paroxysmus +257 Monster # Dread Horn +258 Monster # Lady M +259 Monster # Monstrous Interred Grizzle +260 Monster # Travesty +261 Monster # Shimmering Effusion +262 Monster # Tormented Minotaur +263 Monster # Minotaur +264 Monster # Changeling +265 Monster # Hydra +266 Monster # Dryad +267 Monster # Troglodyte +269 Monster # Thorn bat +270 Monster # Bulbous Putrification +271 Monster # Satyr +272 Monster # Interred Grizzle +273 Monster # Fetid Essence + +276 Animal # Chimera +277 Animal # Cu Sidhe +278 Animal # Squirrel +279 Animal # Ferret +280 Monster # Plate Armored Minotaur +281 Monster # Leather Armored Minotaur +282 Animal # Parrot +283 Animal # Crow +284 Animal # Mondains Steed +285 Monster # Reaper Form diff --git a/Data/containers.cfg b/Data/containers.cfg new file mode 100644 index 0000000..42e090d --- /dev/null +++ b/Data/containers.cfg @@ -0,0 +1,49 @@ +# All lines are trimmed. Empty lines and lines starting with '#' are ignored +# Container data table +# Format: +# GumpIDRectX RectY RectWidth RectHeightDropSound[ItemID1,ItemID2,...,ItemIDN] + +# Default: +0x3C 44 65 142 94 0x48 + +# Containers +0x9 20 85 104 111 0x42 0x2006,0xECA,0xECB,0xECC,0xECD,0xECE,0xECF,0xED0,0xED1,0xED2 +0x3D 29 34 108 94 0x48 0xE76,0x2256,0x2257 +0x3E 33 36 109 112 0x42 0xE77,0xE7F +0x3F 19 47 163 76 0x4F 0xE7A,0x24D5,0x24D6,0x24D9,0x24DA +0x41 35 38 110 78 0x4F 0x990,0x9AC,0x9B1,0x24D7,0x24D8,0x24DD +0x42 18 105 144 73 0x42 0xE40,0xE41 +0x43 16 51 168 73 0x42 0xE7D,0x9AA +0x44 20 10 150 90 0x42 0xE7E,0x9A9,0xE3C,0xE3D,0xE3E,0xE3F +0x48 76 12 64 56 0x42 0xA30,0xA38 +0x49 18 105 144 73 0x42 0xE42,0xE43,0x4025, 0x4026 +0x4A 18 105 144 73 0x42 0xE7C,0x9AB +0x4B 16 51 168 73 0x42 0xE80,0x9A8 +0x4C 46 74 150 110 0x42 0x3E65,0x3E93,0x3EAE,0x3EB9 +0x4D 76 12 64 56 0x42 0xA97,0xA98,0xA99,0xA9A,0xA9B,0xA9C,0xA9D,0xA9E +0x4E 24 96 74 56 0x42 0xA4C,0xA4D,0xA50,0xA51 +0x4F 24 96 74 56 0x42 0xA4E,0xA4F,0xA52,0xA53 +0x51 16 10 138 84 0x42 0xA2C,0xA34 +0x52 0 0 110 62 0x42 0x1E5E + +# Game Boards +0x91A 0 0 282 210 -1 0xFA6 +0x92E 0 0 282 230 -1 0xE1C,0xFAD + +# Gift Box +0x102 35 10 155 85 0x42 0x232A,0x232B + +# SE Containers +0x105 10 10 150 95 0x42 0x2857,0x2858 +0x106 10 10 150 95 0x42 0x285B,0x285C +0x107 10 10 150 95 0x42 0x285D,0x285E,0x2859,0x285A +0x108 10 10 116 71 0x4F 0x24DB,0x24DC +0x109 10 10 150 95 0x42 0x280B,0x280C +0x10A 10 10 150 95 0x42 0x280F,0x2810 +0x10B 10 10 150 95 0x42 0x280D,0x280E +0x10C 10 10 150 95 0x42 0x2811,0x2812,0x2815,0x2816,0x2817,0x2818 +0x10D 10 10 150 95 0x42 0x2813,0x2814 +0x10D 10 10 150 95 0x42 0x2813,0x2814 + +# Heart Shaped +0x120 56 30 102 74 0x42 0x49CA,0x49CB,0x49CC,0x49D0 \ No newline at end of file diff --git a/Data/items.cfg b/Data/items.cfg new file mode 100644 index 0000000..d282a9c --- /dev/null +++ b/Data/items.cfg @@ -0,0 +1,143 @@ +Items (Item) + + Bods & Rewards (SmallBOD; LargeBOD; BulkOrderBook; SturdyPickaxe; SturdyShovel; BaseGlovesOfMining; GargoylesPickaxe; ProspectorsTool; PowderOfTemperament; ColoredAnvil; RunicHammer; AncientSmithyHammer; SmallStretchedHideEastDeed; SmallStretchedHideEastAddon; SmallStretchedHideSouthDeed; SmallStretchedHideSouthAddon; MediumStretchedHideEastDeed; MediumStretchedHideEastAddon; MediumStretchedHideSouthDeed; MediumStretchedHideSouthAddon; LightFlowerTapestryEastDeed; LightFlowerTapestryEastAddon; LightFlowerTapestrySouthDeed; LightFlowerTapestrySouthAddon; DarkFlowerTapestryEastDeed; DarkFlowerTapestryEastAddon; DarkFlowerTapestrySouthDeed; DarkFlowerTapestrySouthAddon; BrownBearRugEastDeed; BrownBearRugEastAddon; BrownBearRugSouthDeed; BrownBearRugSouthAddon; PolarBearRugEastDeed; PolarBearRugEastAddon; PolarBearRugSouthDeed; PolarBearRugSouthAddon; ClothingBlessDeed; RunicSewingKit) + + Smithing (SmallSmithBOD; LargeSmithBOD; SturdyPickaxe; SturdyShovel; BaseGlovesOfMining; GargoylesPickaxe; ProspectorsTool; PowderOfTemperament; ColoredAnvil; RunicHammer; AncientSmithyHammer) + + Tailoring (SmallTailorBOD; LargeTailorBOD; SmallStretchedHideEastDeed; SmallStretchedHideEastAddon; SmallStretchedHideSouthDeed; SmallStretchedHideSouthAddon; MediumStretchedHideEastDeed; MediumStretchedHideEastAddon; MediumStretchedHideSouthDeed; MediumStretchedHideSouthAddon; LightFlowerTapestryEastDeed; LightFlowerTapestryEastAddon; LightFlowerTapestrySouthDeed; LightFlowerTapestrySouthAddon; DarkFlowerTapestryEastDeed; DarkFlowerTapestryEastAddon; DarkFlowerTapestrySouthDeed; DarkFlowerTapestrySouthAddon; BrownBearRugEastDeed; BrownBearRugEastAddon; BrownBearRugSouthDeed; BrownBearRugSouthAddon; PolarBearRugEastDeed; PolarBearRugEastAddon; PolarBearRugSouthDeed; PolarBearRugSouthAddon; ClothingBlessDeed; RunicSewingKit) + + Addons (BaseAddon; BaseAddonDeed) + + Constructed (BaseAddon) + + Deeds (BaseAddonDeed) + + Wearables (BaseArmor; BaseClothing; BaseSuit; BaseJewel; BaseWeapon) + + Armor (BaseArmor) + + Artifacts (ArmorOfFortune; GauntletsOfNobility; HelmOfInsight; HolyKnightsBreastplate; InquisitorsResolution; JackalsCollar; LeggingsOfBane; MidnightBracers; OrnateCrownOfTheHarrower; ShadowDancerLeggings; TunicOfFire; VoiceOfTheFallenKing) + + Bone (BoneArms; BoneChest; BoneGloves; BoneLegs; BoneHelm) + + Chain (ChainChest; ChainLegs; ChainCoif) + + Daemon Bone (DaemonArms; DaemonChest; DaemonGloves; DaemonLegs; DaemonHelm) + + Dragon (DragonArms; DragonChest; DragonGloves; DragonLegs; DragonHelm) + + Helmets (Bascinet; CloseHelm; Helmet; NorseHelm; OrcHelm) + + Leather (FemaleLeatherChest; LeatherArms; LeatherBustierArms; LeatherChest; LeatherGloves; LeatherGorget; LeatherLegs; LeatherShorts; LeatherSkirt; LeatherCap) + + Plate (FemalePlateChest; PlateArms; PlateChest; PlateGloves; PlateGorget; PlateLegs; PlateHelm) + + Ranger (RangerArms; RangerChest; RangerGloves; RangerGorget; RangerLegs) + + Ring (RingmailArms; RingmailChest; RingmailGloves; RingmailLegs) + + Studded Leather (FemaleStuddedChest; StuddedArms; StuddedBustierArms; StuddedChest; StuddedGloves; StuddedGorget; StuddedLegs) + + Shields (BaseShield) + + Artifacts (Aegis; ArcaneShield) + + Weapons (BaseWeapon) + + Artifacts (AxeOfTheHeavens; BladeOfInsanity; BladeOfTheRighteous; BoneCrusher; BreathOfTheDead; Frostbringer; LegacyOfTheDreadLord; SerpentsFang; StaffOfTheMagi; TheBeserkersMaul; TheDragonSlayer; TheTaskmaster; TitansHammer; ZyronicClaw) + + Wands (BaseWand) + + Axes (BaseAxe) + + Knives (BaseKnife) + + Bashing (BaseBashing) + + Pole Arms (BasePoleArm) + + Ranged (BaseRanged) + + Spears (BaseSpear) + + Staves (BaseStaff) + + Swords (BaseSword) + + Clothing (BaseClothing) + + Cloaks (BaseCloak) + + Hats (BaseHat) + + Robes (BaseOuterTorso) + + Shirts (BaseShirt) + + Pants (BasePants; BaseOuterLegs) + + Shoes (BaseShoes) + + Misc (BaseWaist; BaseMiddleTorso) + + Jewelry (BaseJewel) + + Artifacts (BraceletOfHealth; OrnamentOfTheMagician; RingOfTheElements; RingOfTheVile) + + Suits (BaseSuit) + + Addons (BaseAddonDeed; BaseAddon) + + Constructed (BaseAddon) + + Smithing (LargeForgeEastAddon; LargeForgeSouthAddon; SmallForgeAddon; AnvilEastAddon; AnvilSouthAddon) + + Tailoring (LoomEastAddon; LoomSouthAddon; SpinningWheelEastAddon; SpinningWheelSouthAddon) + + Cooking (FlourMillEastAddon; FlourMillSouthAddon; StoneOvenEastAddon; StoneOvenSouthAddon) + + Bedding (LargeBedEastAddon; LargeBedSouthAddon; SmallBedSouthAddon; SmallBedEastAddon) + + Training (TrainingDummyEastAddon; TrainingDummySouthAddon; PickpocketDipEastAddon; PickpocketDipSouthAddon; ArcheryButteAddon) + + Spiritual (PentagramAddon; BloodPentagram; AbbatoirAddon) + + Furniture (LargeStoneTableEastAddon; LargeStoneTableSouthAddon; MediumStoneTableEastAddon; MediumStoneTableSouthAddon) + + Misc (BaseAddon) + + Deeds (BaseAddonDeed) + + Smithing (LargeForgeEastDeed; LargeForgeSouthDeed; SmallForgeDeed; AnvilEastDeed; AnvilSouthDeed) + + Tailoring (LoomEastDeed; LoomSouthDeed; SpinningWheelEastDeed; SpinningWheelSouthDeed) + + Cooking (FlourMillEastDeed; FlourMillSouthDeed; StoneOvenEastDeed; StoneOvenSouthDeed) + + Bedding (LargeBedEastDeed; LargeBedSouthDeed; SmallBedEastDeed; SmallBedSouthDeed) + + Training (TrainingDummyEastDeed; TrainingDummySouthDeed; PickpocketDipEastDeed; PickpocketDipSouthDeed; ArcheryButteDeed) + + Spiritual (PentagramDeed; AbbatoirDeed) + + Furniture (LargeStoneTableEastDeed; LargeStoneTableSouthDeed; MediumStoneTableEastDeed; MediumStoneTableSouthDeed) + + Misc (BaseAddonDeed) + + Books (BaseBook) + + Resources (BaseIngot; BaseOre; BaseGranite; BaseScales; BaseReagent; BaseHides; BaseLeather; Log; Board; BaseClothMaterial; Bone; UncutCloth; BoltOfCloth; Cloth; Wool; Flax; Cotton; BagOfAllReagents; BagOfNecroReagents; BagOfReagents; AlchemyBag; BagOfIngots; ScribeBag; SmithBag; TailorBag; Fish; BigFish; BaseMagicFish; Arrow; Bolt; Feather; Shaft; AlchemyStone; IngotStone; RegStone; ScribeStone; SmithStone; TailorStone; Sand) + + Ingots (BaseIngot) + + Ore (BaseOre) + + Granite (BaseGranite) + + Scales (BaseScales) + + Reagents (BaseReagent) + + Standard (BlackPearl; Bloodmoss; Garlic; Ginseng; MandrakeRoot; Nightshade; SpidersSilk; SulfurousAsh) + + Necromancy (BatWing; DaemonBlood; GraveDust; NoxCrystal; PigIron) + + Wood (Log; Board) + + Fish (Fish; BigFish; BaseMagicFish) + + Tailoring (BaseHides; BaseLeather; BaseClothMaterial; Bone; BoltOfCloth; Cloth; UncutCloth; Wool; Flax; Cotton) + + Hides (BaseHides) + + Leather (BaseLeather) + + Cloth (BoltOfCloth; Cloth; UncutCloth) + + Materials (BaseClothMaterial; Wool; Flax; Cotton) + + Fletching (Arrow; Bolt; Feather; Shaft) + + Bags (BagOfAllReagents; BagOfNecroReagents; BagOfReagents; AlchemyBag; BagOfIngots; ScribeBag; SmithBag; TailorBag) + + Stones (AlchemyStone; IngotStone; RegStone; ScribeStone; SmithStone; TailorStone) + + Entertainment (BaseInstrument; BaseBoard; Dices) + + Instruments (BaseInstrument) + + Games (BaseBoard; Dices) + + Construction (BaseDoor; BaseFloor; Container; DecorativeShield1; DecorativeShield2; DecorativeShield3; DecorativeShield4; DecorativeShield5; DecorativeShield6; DecorativeShield7; DecorativeShield8; DecorativeShield9; DecorativeShield10; DecorativeShield11; DecorativeShieldSword1North; DecorativeShieldSword1West; DecorativeShieldSword2North; DecorativeShieldSword2West; DecorativeBowWest; DecorativeBowNorth; DecorativeAxeNorth; DecorativeAxeWest; DecorativeSwordNorth; DecorativeSwordWest; DecorativeDAxeNorth; DecorativeDAxeWest; LargePainting; WomanPortrait1; WomanPortrait2; ManPortrait1; ManPortrait2; LadyPortrait1; LadyPortrait2; Tapestry1N; Tapestry2N; Tapestry2W; Tapestry3N; Tapestry3W; Tapestry4N; Tapestry4W; Tapestry5N; Tapestry5W; Tapestry6N; Tapestry6W; RuinedFallenChairA; RuinedArmoire; RuinedBookcase; RuinedBooks; CoveredChair; RuinedFallenChairB; RuinedChair; RuinedClock; RuinedDrawers; RuinedPainting; WoodDebris; Rope; IronWire; SilverWire; GoldWire; CopperWire; Whip; PaintsAndBrush; WoodenBench; FancyWoodenChairCushion; WoodenChairCushion; WoodenChair; BambooChair; Stool; FootStool; Throne; WoodenThrone; LargeTable; Nightstand; YewWoodTable; WritingTable; Easle; TallMusicStand; ShortMusicStand) + + Decoration (DecorativeShield1; DecorativeShield2; DecorativeShield3; DecorativeShield4; DecorativeShield5; DecorativeShield6; DecorativeShield7; DecorativeShield8; DecorativeShield9; DecorativeShield10; DecorativeShield11; DecorativeShieldSword1North; DecorativeShieldSword1West; DecorativeShieldSword2North; DecorativeShieldSword2West; DecorativeBowWest; DecorativeBowNorth; DecorativeAxeNorth; DecorativeAxeWest; DecorativeSwordNorth; DecorativeSwordWest; DecorativeDAxeNorth; DecorativeDAxeWest; LargePainting; WomanPortrait1; WomanPortrait2; ManPortrait1; ManPortrait2; LadyPortrait1; LadyPortrait2; Tapestry1N; Tapestry2N; Tapestry2W; Tapestry3N; Tapestry3W; Tapestry4N; Tapestry4W; Tapestry5N; Tapestry5W; Tapestry6N; Tapestry6W) + + Shields (DecorativeShield1; DecorativeShield2; DecorativeShield3; DecorativeShield4; DecorativeShield5; DecorativeShield6; DecorativeShield7; DecorativeShield8; DecorativeShield9; DecorativeShield10; DecorativeShield11; DecorativeShieldSword1North; DecorativeShieldSword1West; DecorativeShieldSword2North; DecorativeShieldSword2West) + + Weapons (DecorativeBowWest; DecorativeBowNorth; DecorativeAxeNorth; DecorativeAxeWest; DecorativeSwordNorth; DecorativeSwordWest; DecorativeDAxeNorth; DecorativeDAxeWest) + + Paintings & Portraits (LargePainting; WomanPortrait1; WomanPortrait2; ManPortrait1; ManPortrait2; LadyPortrait1; LadyPortrait2) + + Tapestries (Tapestry1N; Tapestry2N; Tapestry2W; Tapestry3N; Tapestry3W; Tapestry4N; Tapestry4W; Tapestry5N; Tapestry5W; Tapestry6N; Tapestry6W) + + Broken (RuinedFallenChairA; RuinedArmoire; RuinedBookcase; RuinedBooks; CoveredChair; RuinedFallenChairB; RuinedChair; RuinedClock; RuinedDrawers; RuinedPainting; WoodDebris) + + Rares (Rope; IronWire; SilverWire; GoldWire; CopperWire; Whip; PaintsAndBrush) + + Doors (BaseDoor) + + Floors (BaseFloor) + + Containers (Container) + + Furniture (WoodenBench; FancyWoodenChairCushion; WoodenChairCushion; WoodenChair; BambooChair; Stool; FootStool; Throne; WoodenThrone; LargeTable; Nightstand; YewWoodTable; WritingTable; Easle; TallMusicStand; ShortMusicStand) + + Chairs (WoodenBench; FancyWoodenChairCushion; WoodenChairCushion; WoodenChair; BambooChair; Stool; FootStool; Throne; WoodenThrone) + + Tables (LargeTable; Nightstand; YewWoodTable; WritingTable) + + Other (Easle; TallMusicStand; ShortMusicStand) + + Lights (BaseLight) + + Food & Drink (Food; CookableFood; BaseBeverage; Glass) + + Ready to eat (Food) + + Needs cooking (CookableFood) + + Beverages (BaseBeverage; Glass) + + Cartography (MapItem) + + Hair (Hair; Beard) + + Stonecraft (Vase; LargeVase; StatueSouth; StatueNorth; StatueEast; StatuePegasus; StoneChair) + + Glassblowing (SmallFlask; MediumFlask; LargeFlask; CurvedFlask; LongFlask; SpinningHourglass; GreenBottle; RedBottle; SmallBrownBottle; SmallVioletBottle; TinyYellowBottle; SmallBlueFlask; SmallYellowFlask; SmallRedFlask; SmallEmptyFlask; YellowBeaker; RedBeaker; BlueBeaker; GreenBeaker; EmptyCurvedFlaskW; RedCurvedFlask; LtBlueCurvedFlask; EmptyCurvedFlaskE; BlueCurvedFlask; GreenCurvedFlask; RedRibbedFlask; VioletRibbedFlask; EmptyRibbedFlask; LargeYellowFlask; LargeVioletFlask; LargeEmptyFlask; AniRedRibbedFlask; AniLargeVioletFlask; AniSmallBlueFlask; SmallBlueBottle; SmallGreenBottle; EmptyVIalsWRack; FullVialsWRack; EmptyJar; FullJar; HalfEmptyJar; VioletStemmedBottle; EmptyJars3; EmptyJars4; FullJars3; FullJars4; EmptyJars2; FullJars2; HalfEmptyJars2; EmptyVial; HourglassAni; Hourglass; TinyRedBottle; SmallGreenBottle2; Glass) + + Pots & Plants (SmallEmptyPot; LargeEmptyPot; PottedCactus; PottedCactus1; PottedCactus2; PottedCactus3; PottedCactus4; PottedCactus5; PottedPlant; PottedPlant1; PottedPlant2; PottedTree; PottedTree1) + + Components (BarrelLid; BarrelStaves; BarrelHoops; BarrelTap; Gears; Springs; Hinge; Axle; AxleGears; SextantParts; ClockParts; ClockFrame; Clock; ClockRight; ClockLeft) + + Tools (BaseTool; BaseHarvestTool) + + Crafting (BaseTool) + + Harvesting (BaseHarvestTool) + + Traps (BaseTrap) + + Gems (Amber; Amethyst; Citrine; Diamond; Emerald; Ruby; Sapphire; StarSapphire; Tourmaline) + + Boats (BaseBoat; BaseBoatDeed) + + Constructed (BaseBoat) + + Deeds (BaseBoatDeed) + + House Deeds (HouseDeed; HousePlacementTool) + + Camps (BaseCamp) + + Magical (Spellbook; SpellScroll; BlankScroll; BasePotion; EtherealMount) + + Scrolls (SpellScroll; BlankScroll) + + Necromancy (AnimateDeadScroll; BloodOathScroll; CorpseSkinScroll; CurseWeaponScroll; EvilOmenScroll; HorrificBeastScroll; LichFormScroll; MindRotScroll; PainSpikeScroll; PoisonStrikeScroll; StrangleScroll; SummonFamiliarScroll; VampiricEmbraceScroll; VengefulSpiritScroll; WitherScroll; WraithFormScroll) + + Standard (SpellScroll) + + Circle #1 (ClumsyScroll; CreateFoodScroll; FeeblemindScroll; HealScroll; MagicArrowScroll; NightSightScroll; ReactiveArmorScroll; WeakenScroll) + + Circle #2 (AgilityScroll; CunningScroll; CureScroll; HarmScroll; MagicTrapScroll; MagicUnTrapScroll; ProtectionScroll; StrengthScroll) + + Circle #3 (BlessScroll; FireballScroll; MagicLockScroll; PoisonScroll; TelekinisisScroll; TeleportScroll; UnlockScroll; WallOfStoneScroll) + + Circle #4 (ArchCureScroll; ArchProtectionScroll; CurseScroll; FireFieldScroll; GreaterHealScroll; LightningScroll; ManaDrainScroll; RecallScroll) + + Circle #5 (BladeSpiritsScroll; DispelFieldScroll; IncognitoScroll; MagicReflectScroll; MindBlastScroll; ParalyzeScroll; PoisonFieldScroll; SummonCreatureScroll) + + Circle #6 (DispelScroll; EnergyBoltScroll; ExplosionScroll; InvisibilityScroll; MarkScroll; MassCurseScroll; ParalyzeFieldScroll; RevealScroll) + + Circle #7 (ChainLightningScroll; EnergyFieldScroll; FlamestrikeScroll; GateTravelScroll; ManaVampireScroll; MassDispelScroll; MeteorSwarmScroll; PolymorphScroll) + + Circle #8 (EarthquakeScroll; EnergyVortexScroll; ResurrectionScroll; SummonAirElementalScroll; SummonDaemonScroll; SummonEarthElementalScroll; SummonFireElementalScroll; SummonWaterElementalScroll) + + Potions (BasePotion) + + Agility (BaseAgilityPotion) + + Cure (BaseCurePotion) + + Explosion (BaseExplosionPotion) + + Heal (BaseHealPotion) + + Poison (BasePoisonPotion) + + Refresh (BaseRefreshPotion) + + Strength (BaseStrengthPotion) + + Ethereal Mounts (EtherealMount) + + Uncategorized (Item) \ No newline at end of file diff --git a/Data/mobiles.cfg b/Data/mobiles.cfg new file mode 100644 index 0000000..7925860 --- /dev/null +++ b/Data/mobiles.cfg @@ -0,0 +1,58 @@ +Mobiles (Mobile) + + Healers (BaseHealer) + + Champions (BaseChampion; Harrower; Silvani; HarrowerTentacles) + + Guards (BaseGuard; BaseShieldGuard) + + Escortables (BaseEscortable) + + Vendors (BaseVendor) + + Guildmasters (BaseGuildmaster) + + Dummies (DummyMace; DummyFence; DummySword; DummyNox; DummyStun; DummySuper; DummyHealer; DummyAssassin; DummyTheif) + + Creatures (BaseCreature) + + Animals (Gorilla; Walrus; Alligator; Llama; PackLlama; PackHorse; BullFrog; GiantToad; Hind; GreatHart; DireWolf; GreyWolf; TimberWolf; WhiteWolf; HellHound; Dog; GrizzlyBear; PolarBear; BlackBear; BrownBear; Bull; Cow; Bird; Eagle; Chicken; Boar; Pig; Rabbit; JackRabbit; Rat; SewerRat; GiantRat; Goat; MountainGoat; Sheep; Panther; PredatorHellCat; HellCat; SnowLeopard; Cougar; Cat; BaseMount) + + Mounts (BaseMount) + + War Horses (BaseWarHorse) + + Birds & Fowl (Bird; Eagle; Chicken) + + Bovines (Bull; Cow) + + Bruins (GrizzlyBear; PolarBear; BlackBear; BrownBear) + + Canines (DireWolf; GreyWolf; TimberWolf; WhiteWolf; HellHound; Dog) + + Deer (Hind; GreatHart) + + Felines (Panther; PredatorHellCat; HellCat; SnowLeopard; Cougar; Cat) + + Frogs & Toads (BullFrog; GiantToad) + + Lizards (Alligator) + + Llamas & Pack Animals (Llama; PackLlama; PackHorse) + + Rodents (Rabbit; JackRabbit; Rat; SewerRat; GiantRat) + + Porcines (Boar; Pig) + + Ruminants (Goat; MountainGoat; Sheep) + + Uncategorized (Gorilla; Walrus) + + Ants (RedSolenWorker; RedSolenWarrior; RedSolenQueen; RedSolenInfiltratorQueen; RedSolenInfiltratorWarrior; BlackSolenWorker; BlackSolenWarrior; BlackSolenQueen; BlackSolenInfiltratorQueen; BlackSolenInfiltratorWarrior) + + Red (RedSolenWorker; RedSolenWarrior; RedSolenQueen; RedSolenInfiltratorQueen; RedSolenInfiltratorWarrior) + + Black (BlackSolenWorker; BlackSolenWarrior; BlackSolenQueen; BlackSolenInfiltratorQueen; BlackSolenInfiltratorWarrior) + + Elementals (DullCopperElemental; ShadowIronElemental; CopperElemental; BronzeElemental; GoldenElemental; AgapiteElemental; VeriteElemental; ValoriteElemental; AirElemental; BloodElemental; FireElemental; IceElemental; WaterElemental; PoisonElemental; ToxicElemental; EarthElemental; SnowElemental) + + Ore Elementals (DullCopperElemental; ShadowIronElemental; CopperElemental; BronzeElemental; GoldenElemental; AgapiteElemental; VeriteElemental; ValoriteElemental) + + Marine (Dolphin; SeaSerpent; DeepSeaSerpent) + + Good (Pixie; Wisp; EtherealWarrior; Centaur) + + Evil (BaseCreature) + + Age of Shadows (FleshGolem; Gibberling; GoreFiend; Ravager; SkitteringHopper; Treefellow; VampireBat; WailingBanshee; AbysmalHorror; BoneDemon; CrystalElemental; DarknightCreeper; DemonKnight; Devourer; FleshRenderer; Impaler; MoundOfMaggots; PatchworkSkeleton; ShadowKnight; WandererOfTheVoid; ChaosDaemon; HordeMinion) + + Daemons (IceFiend; Balron; Daemon) + + Dragons & Wyrms (Dragon; WhiteWyrm; SerpentineDragon; AncientWyrm; ShadowWyrm; SkeletalDragon; Drake; Wyvern) + + Gargoyles (Gargoyle; FireGargoyle; StoneGargoyle) + + Harpies (Harpy; StoneHarpy) + + Humans (EvilMage; EvilMageLord; Betrayer; Brigand; Executioner; Guardian; KhaldunSummoner; KhaldunZealot) + + Lizards (LavaLizard; Lizardman) + + Mongbats, Imps, & Headless Ones (Mongbat; StrongMongbat; Imp; HeadlessOne) + + Ogres, Ettins, Trolls, Cyclopses, & Titans (Titan; Cyclops; Ettin; FrostTroll; Ogre; Troll; ArcticOgreLord; OgreLord) + + Ophidians (OphidianMage; OphidianArchmage; OphidianMatriarch; OphidianWarrior; OphidianKnight) + + Orcs (OrcishMage; Orc; OrcishLord; OrcBomber; OrcCaptain; OrcishLord; OrcBrute) + + Plague Beasts, Bog Things, & Slimes (Jwilson; FrostOoze; Slime; PlagueSpawn; PlagueBeast; BogThing; Bogling) + + Plants (Corpser; Quagmire; WhippingVine; SwampTentacle; Reaper) + + Ratmen (Ratman; RatmanArcher; RatmanMage) + + Serpents (IceSerpent; IceSnake; LavaSerpent; LavaSnake; GiantSerpent; SilverSerpent; Snake) + + Spiders (DreadSpider; FrostSpider; GiantSpider) + + Terathans (TerathanMatriarch; TerathanAvenger; TerathanDrone; TerathanWarrior) + + Undead (AncientLich; Bogle; BoneMagi; Lich; LichLord; Shade; SkeletalMage; Spectre; Wraith; BoneKnight; SkeletalKnight; Ghoul; RottingCorpse; Skeleton; Zombie; Mummy) + + Ghosts (Bogle; Shade; Spectre; Wraith; Ghoul) + + Skeletons (BoneMagi; SkeletalMage; BoneKnight; SkeletalKnight; Skeleton) + + Walking Dead (RottingCorpse; Zombie; Mummy) + + Liches (AncientLich; Lich; LichLord) + + Vortexes & Blade Spirits (EnergyVortex; SandVortex; BladeSpirits) + + Uncategorized (BaseCreature) + + Uncategorized (Mobile) \ No newline at end of file diff --git a/Data/names.xml b/Data/names.xml new file mode 100644 index 0000000..0c8edfb --- /dev/null +++ b/Data/names.xml @@ -0,0 +1,654 @@ + + + + Dosyaku, Warimoto, Ogino, Soutatsu, Wajida, Batsu, Hikoza, Adai, Ukita, Sanesue, + Chihu, Akiosa, Riku, Kongou, Numata, Kirzahn, Gakudai, Nakai, Ukita, Ashimaru, + Fuha, Gakudai, Numata, Waricika, Chihu, Sanesue, Yose, Shinsirou, Yasuke, Akisuke, + Naozumi, Numatta, Kichizo, Nasuno, Akaba, Arikoto, Kengi, Magosuke + + + Ahara, Yume, Ayane, Yuki, Wakae, Akala, Ikuha, Wayu, Haru, Zannia, Shino, Agate, + Akashi, Niji, Yochika, Toyoka, Wayo, Iroha, Nakai, Ayatsumi, Wayu, Yumiha, Enji, + Aasin, Akela, Chiwa, Suni, Wakumi, Ruri, Tama + + + a wren, a swallow, a warbler, a nuthatch, a chickadee, a thrush, + a nightingale, a starling, a skylark, a finch, a crossbill, a sparrow, a towhee, + a woodpecker, a kingfisher, a tern, a plover, a lapwing, a hawk, a cuckoo, a swift + + + Kaltivel, Anshu, Maliel, Baratoz, Almonjin + + + the Lord of the Abyss, the Collector of Souls, the Slayer + + + Pariah, Ydoc Llessue, Zhaan, Lorbna, Gragok, Thranger, Krygar, + Grothelfiend, Centibis, Farthak, Laitesach, Crenabil, Krullus, Legron, + Noirkrach, Blassarrabb, Gragragron, Vendodroth, Flaggroth, Vilithrar + + + Po-Kor, Manglar, Verolyn, Gathfe, Skred, Flandrith, Stavinfeks, + Steelbane, Crarigor, Empalk, Perfus, Cassiel, Magor, Xtul, Vladeer, Scrill, + Slix, Ix, Selminus, Victux + + + Hrallath, Heksen, Peinsluth, Keelus, Kra'an, Ankou, Turi'el, Azazel, + Armarus, Grigorus, Ga'ahp, Therion, Peirazo, Ponerus, Arhaios Ophis, + Vairocan, Arsat, Karnax, Taet Nu'uhn + + + Oghmus, Arametheus, Terxor, Erdok, Archatrix, Jonar, Marth'Fador, Helzigar, + Tyrnak, Krakus, Marcus Fel, Lord Kaos, Doomor, Uhn, Malashim, Samael, Nelokhiel, + Montobulus, Usuhl, Zul + + + a fiery gargoyle, a burning gargoyle, a smoldering gargoyle, a blistering gargoyle, + a sweltering gargoyle, a flaming gargoyle, a scorching gargoyle, + a blazing gargoyle, a searing gargoyle + + + Ansiraal, Aurlem, Betra, Draxsom, Fodus, Forbrak, ForLem, Horffe, Inforlem, Invis, + Laplem, Naxator, Quaeven, Sarpling, Silamo, Tereg, Volesh, Vraal, WisSur + + + Sophanon, Caryax, Daemeox, Phlegon, Aerophus, Euforus, Pallax, + Nikaon, Licouax, Lindsaon, Bastax, Magdanon, Thayax, Aethon, Ceridus, Galenon, + Rhysus, Auramax, Aldrax, Anaxus, Luceus, Quarax, Ariax, Balarax, Vincenus, + Loxias, Birhamus, Lekax, Nyctinus, Myrsinus + + + Galdrion, Briellis, Charpris, Jesurian, Agrast, Beldrion, Polis, + Arafel, Melestoref, Lanculis, Judaselo, Pietrov + + + Klian, Klistra, Laeri, Ciline, Shiale, Ourie, Piepe, Liera, Sili, + Sefi, Cynthe, Nedra, Hali, Jiki, Piku, Rael, Zanne, Zut, Sini, Os, Wienne, Xian, + Ybri, Calee, Shendri, Shri + + + Kahl, Ghrom, Ogger, Vek, Sai'ge, Groov'h, Khaonem, Malen, Atar, + Aicee, Vaype, Halex, Yar, Hanz, Evocah, Bishor, Jelak, Adrok, Praphut, Usile, + Sann, Sabba, Prie, Atuk, Chaca, ShoJo, Baccu, Bonkie, Alli, Jexa, La'Loh, Arda, + Cordee, Lana, Lar, Araka, Rhunda, Squee, Bhora, Niha, Olaufee, Sinthe, Karawyn, + Gruwulf, Masena, Nasha, Sargaza + + + Kahl, Ghrom, Ogger, Vek, Sai'ge, Groov'h, Khaonem, Malen, Atar, + Aicee, Vaype, Halex, Yar, Hanz, Evocah, Bishor, Jelak, Adrok, Praphut, Usile, + Sann, Sabba, Prie, Atuk, Chaca, ShoJo, Baccu, Bonkie, Alli + + + Jexa, La'Loh, Arda, Cordee, Lana, Lar, Araka, Rhunda, Squee, + Bhora, Niha, Olaufee, Sinthe, Karawyn, Gruwulf, Masena, Nasha, Sargaza + + + Zelik, Kronos, Zakron, Velis, Chujil, Hygraph, Dyntrall, Zarus, + Phoseph, Malkavik, Zevras, Vakel, Daklon, Zamog, Tavurk, Drakov, Zazik, Yyntrix, + Zazik, Fropoz, Noxtrag, Makzok, Galzan, Drakan, Drakzik, Vazmog + + + Aamon, Agalierept, Agares, Aglasis, Aiwaz, Astaroth, Ayperos, + Azatoth, Azmodaeus, Azrael, Ba'al, Baal, Barbatos, Bathim, Bathsin, Be'elzebub, + Be'elzebubba, Bechard, Beelzebuth, Botis, Brulefer, Bucon, Buer, Clauneck, + Clitheret, Cthulhu, Druzil, El Chupacabra, Eleogap, Eliezer, Eligor, Eracove, + Faraii, Fleurety, Frimost, Frucissiere, Fruitimiere, Glassyalabolas, Guland, + Gusoyn, Hael, Haristum, Heramael, Hiepacth, Huictiigara, Humots, Khil, Maleki, + Marbas, Mephistopheles, Mersilde, Minoson, Moloch, Molech, Morail, Musisin, + Naberrs, Nebiros, Nebirots, Nyarlathotep, Pentagnony, Proculo, Pruslas, Pursan, + Rofocale, Sargatans, Satanchia, Satanciae, Segal, Sergulath, Sergutthy, + Sidragrosam, Sirchade, Surgat, Sustugriel, Tarchimache, Tarihimal, Trimasel, + Vaelfar, Wormius, Yog-Sothoth, Y'reif Eci, Zoray + + + Xarot the Black Archmage, Kwan Li the Lord of the Mists, + Bazerion the Wizard-Lord, Ylthallynon the Insane + + + Ronlyn, Merkul, Zasfus, Zain, Doraghir, Danaghir, Staylin, + Kraylin, Limnoch, Kranor, Kraenor, Kranostil, Kranostir, Lilithack, Terus, + Thaelin, Thulack, Jiltharis, Garigor, Banothil, Bainothil, Quain, Ilzinias, + Mardis the Avenger, Phalil the Unexpected, Lord Adnoc, Leje the Invincible, + Master Akris, Sartan, Zejron the Wild, Pitt the Elder, Puzilan the Puzzler, + Vantrom, Singhe-Dul, Tyrin Kuhl, Xarot the Black, Kwan Li, Lord of the Mists, + Viktor Blackoak, Odilion, Raith, Lord of Rats, Bazerion, the Wizard-Lord, + Tybevriat Varn, Keldor the Modoc, Magelord Varsan, Izlay the Ebonheart, Slirith + Iceblood, Alcor, Vitar, Feenark, Sang Qui, Lyticant, Aegnor, Aelfric, Ainvar, + Arazion, Ardarion, Arkanis, Athrax, Barghest, Baros, Begarin, Beynlore, Burat, + Cairne, Carthon, Chamdar, Ciric, Cruzado, Cyphrak, D'Harun, Daelon, Daktar, + Darvain, Dracus, Dradar, Draelin, Draenor, Durodund, Eklor, Elrak, Fangorn, + Farynthane, Galtor, Gemma, Gragus, Irian, Israfel, Jaden, Jefahn, K'shar, + Kalimus, Kallomane, Kanax, Kelnos, Kharn, Khir, Kragon, Kylnath, Larac, Lathis, + Lenroc, Lonthorynthoryl, Lorreck, Mattrick, Mazrim, Mazrim, Modrei, Morturus, + Muktar, Murdon, Murron, Myndon, Mythran, Mytor, Nabius, Nalynkal, Nazgul, + Paorin, Quillan, Rendar, Scythyn, Shilor, Sobran, Soltak, Sorz, Taban, Telzar, + Teron, Trethovian, Tyrnar, Ulath, Vandor, Vermithrax, Vlade, Volan, Wydstrin, + X'calak, Xaelin, Xandor, Xarthos, Xaxtox, Xenix, Xiltanth, Xylor, Xystil, Yazad, + Yllthane, Ylthallynon, Ythoryn, Zalifar, Zathrix, Zunrek + + + Ccketakiki, Chachak, Chachaktak, Chackuk, Chak, Chaki, Chaki, + Chakreki, Chaktuki, Chakukki, Charitiki, Chatuki, Chectik, Chectik, Chek, + Chekeckaki, Cheki, Chekkakii, Cherek, Chetak, Chetickuki, Chiackukk, Chichachak, + Chichak, Chichak, Chichoki, Chichoki, Chickek, Chickek, Chickeki, Chickeki, + Chickekiaki, Chikavi, Chikchickeki, Chikckak, Chikek, Chiketckuki, Chiki, + Chikitchaki, Chiktaki, Chiritchek, Chitaviok, Chokchak, Chokirek, Chotechiki, + Ckak, Ckek, Ckekckuki, Ckeki, Ckekickuk, Ckikhiki, Ckikicheki, Ckukchik, + Ckukichek, Ctiktik, Dachek, Dackatuki, Dactuk, Dafactik, Deckarreki, Deektuk, + Defetav, Dekckuk, Detckiki, Detckuki, Detik, Dicchok, Dickiki, Dikfachok, + Ditecckek, Diwarek, Eachik, Eactiki, Ecckkekek, Eckaki, Eckechakiki, Ecketak, + Ecterek, Ectuk, Eekckuk, Eektuk, Eicchiki, Eickuki, Ekiuki, Etakheki, Etavchiki, + Etckuki, Etik, Fachchekiok, Fachok, Fackak, Fackek, Fackik, Factavi, Factik, + Fecckik, Fechaki, Feractav, Fetav, Fetckiki, Firchik, Firecheki, Fireki, + Fitactaki, Fitaki, Fitcheki, Frecckeki, Hekckeki, Hiki, Hikitchaki, Hokchek, + Ikchaki, Iki, Kackak, Kactavi, Kadicchok, Kakhoki, Kaki, Kakiki, Karrekichoki, + Katukickek, Kecckik, Kechaki, Kekachek, Kekachik, Kekkik, Kicchiki, Kichak, + Kickak, Kidikiki, Kietik, Kik, Kikechokii, Kikiaki, Kiktaki, Kirchik, Kireki, + Kireki, Kitak, Kitaki, Kitavi, Kitcheki, Ktukchok, Kukeckaki, Kuki, Kukiecckak, + Rackek, Ractav, Ratitchaki, Recckeki, Recheki, Rekchectik, Reki, Rektav, + Rektavi, Retchectik, Reteckaki, Retituki, Rikchickek, Rikecckak, Ritchek, + Ritchekckiki, Ritiki, Ritikituk, Tackik, Tactaki, Tactikiv, Tadectuk, Tak, Tak, + Taki, Taki, Taktav, Tavchichoki, Taviactak, Taviectuk, Tecckek, Techiki, + Techikickik, Teckak, Tedetik, Tekactiki, Tekchichak, Tickukitaki, Tictak, + Tidetckuki, Tikckek, Tikickeki, Titchaki, Tituki, Tukckaki, Tukitiki, Tukituki, + Vachichak, Vackuk, Vactak, Vaveckaki, Vechoki, Vectaki, Vevactak, Vevitavi, + Vitavi, Vitchak, Vitituki, Vivackuk, Vivitchak, Vovechoki, Warek, Warreki, + Wecckak, Weckaki, Wedachek, Wikchichoki, Wochickeki + + + Aissssaiss, Aisyths, Alasthsiyss, Alessitsl, Alsiths, Alssi, + Alsyth, Asahlysy, Asathsaisss, Asaysth, Asiashy, Asistsais, Asitssis, Asiyss, + Astha, Asthcieth, Astysah, Athcesth, Athys, Athysthes, Atslah, Aysthyss, + Cesthaysth, Cetys, Ciethlish, Citsy, Cythshi, Cytsi, Ekthsisthh, Essith, Estha, + Etys, Halasth, Haless, Halsasah, Hasits, Hekths, Hiiths, Hiitsl, Hissis, Hlyiss, + Hlylylyshi, Hlyshilyly, Hlysylyiss, Hlythilsyth, Hissalsthy, Hysslssi, Hsysylh, + Hthessthil, Hthissy, Htisthh, Htsiathys, Hyisass, Hysil, Hysyiss, Iasia, + Icythhlysy, Iithsissh, Iitsliss, Ilshy, Ilsyth, Isalraaat, Isassthys, Isathys, + Isiss, Isissil, Isshi, Isshlshy, Isstha, Issthas, Issthyl, Issysh, Issyt, + Isthhtis, Istis, Istththh, Isyts, Ithstsesh, Ithsy, Iththis, Itsesh, Itshas, + Itsltlish, Itsthil, Itsylh, Iyssysil, Kthystshas, Kthythes, Lasath, Lastha, + Lasthtsthih, Lesstslah, Lestha, Lilhals, Lilsyth, Lishaless, Lishath, Lissysh, + Lissyt, Lithekths, Litsylh, Llithlish, Lshyshas, Lssissi, Lsthyssy, Lsyth, + Lsythstha, Lyissisis, Lylsthy, Lylyisass, Lyshiisal, Lyssthih, Lyssthy, + Lysyiitsl, Lythiiiths, Lytsthih, Saisalasths, Saishtsi, Saisssmyss, Salsesh, + Salssi, Sasisthasth, Sasss, Sasth, Sath, Sathsthih, Sathys, Satslah, Saysth, + Scesthhals, Seshsthyl, Sessith, Shasits, Shassthy, Shisis, Shitha, Shysil, + Shythis, Siasia, Siaththh, Sicyth, Silshy, Silthyl, Sisal, Sisshi, Sisshlythi, + Sistlilh, Sithtththh, Sitsesh, Sitshas, Sitstsi, Siyss, Slahyisass, Slasath, + Slishless, Ssaisss, Ssasist, Sshiscesth, Ssisal, Ssithsiss, Ssiyth, Sssaisss, + Ssssshi, Ssthasssthas, Ssthihssthy, Ssthssss, Ssthyl, Ssthyssths, Ssyraaath, + Ssysah, Ssyshstha, Ssyssith, Ssytsth, Stasah, Sthasth, Sthasthas, Sthasthih, + Sthihaisss, Sthihasits, Sthilsthy, Sthlyly, Sthlyshi, Sthlysy, Sthlythi, + Sthmissa, Sthmyss, Sthsasist, Sthyss, Sthyasia, Sthycyth, Sthyltasah, Stissh, + Stththh, Stysah, Sycieth, Sylhsths, Syllith, Syraaat, Syshsyts, Syslish, + Syththil, Sythysth, Sytlilh, Sytlish, Sytsyth, Sytsyts, Syys, Tasahasath, + Thalasths, Thaless, Thals, Thatsylh, Thays, Thekths, Theshthis, Thiiths, + Thiitsl, Thilhlyshi, Thishthes, Thlyiss, Thlyly, Thlyshi, Thlysy, Thlythi, + Thmissa, Thmyss, Thsais, Thslish, Ththes, Ththhllith, Ththis, Thtisthh, + Thyisass, Thylmissa, Thys, Thysslah, Tisiss, Tissyth, Tisthhhsy, Tlilhlasth, + Tlishkths, Tseshsath, Tshassasisth, Tsicyth, Tsitys, Tslahsits, Tsthihssthih, + Tsthil, Tsycieth, Tsylhssyt, Tsytysah, Tththhsyt, Tysahyraaath, Tyscesth, + Tysycieth, Yciethhlyly, Yisasshmyss, Yisstisthh, Yllith, Ylsthy, Yraaathlythi, + Ysahlith, Ysasth, Ysath, Yscesth, Yshmissa, Yshtsi, Ysilsia, Yslish, Yssasisth, + Ysssal, Yssthih, Yssths, Yssthy, Ystasah, Ysthsith, Ystsy, Ythals, Ythssysh, + Ytlilh, Ytlish, Ytsais, Ytssysh, Ytsthih + + + Abghat, Adgulg, Aghed, Agugh, Aguk, Almthu, Alog, Ambilge, + Apaugh, Argha, Argigoth, Argug, Arpigig, Auhgan, Azhug, Bagdud, Baghig, + Bahgigoth, Bahgigoth, Bandagh, Barfu, Bargulg, Baugh, Bidgug, Bildud, Bilge, + Bog, Boghat, Bogugh, Borgan, Borug, Braugh, Brougha, Brugagh, Bruigig, Buadagh, + Buggug, Builge, Buimghig, Bulgan, Bumhug, Buomaugh, Buordud, Burghed, Buugug, + Cabugbu, Cagan, Carguk, Carthurg, Clog, Corgak, Crothu, Cubub, Cukgilug, Curbag, + Dabub, Dakgorim, Dakgu, Dalthu, Darfu, Deakgu, Dergu, Derthag, Digdug, Diggu, + Dilug, Ditgurat, Dorgarag, Dregu, Dretkag, Drigka, Drikdarok, Drutha, Dudagog, + Dugarod, Dugorim, Duiltag, Durbag, Eagungad, Eggha, Eggugat, Egharod, Eghuglat, + Eichelberbog, Ekganit, Epkagut, Ergoth, Ertguth, Ewkbanok, Fagdud, Faghig, + Fandagh, Farfu, Farghed, Fargigoth, Farod, Faugh, Feldgulg, Fidgug, Filge, + Fodagog, Fogugh, Fozhug, Frikug, Frug, Frukag, Fubdagog, Fudhagh, Fupgugh, + Furbog, Futgarek, Gaakt, Garekk, Gelub, Gholug, Gilaktug, Ginug, Gnabadug, + Gnadug, Gnalurg, Gnarg, Gnarlug, Gnorl, Gnorth, Gnoth, Gnurl, Golag, Golag, + Golub, Gomatug, Gomoku, Gorgu, Gorlag, Grikug, Grug, Grug, Grukag, Grukk, Grung, + Gruul, Guag, Gubdagog, Gudhagh, Gug, Gug, Gujarek, Gujek, Gujjab, Gulm, Gulrn, + Gunaakt, Gunag, Gunug, Gurukk, Guthakug, Guthug, Gutjja, Hagob, Hagu, Hagub, + Haguk, Hebub, Hegug, Hibub, Hig, Hogug, Hoknath, Hoknuk, Hokulk, Holkurg, + Horknuth, Hrolkug, Hugagug, Hugmug, Hugolm, Ig, Igmut, Ignatz, Ignorg, Igubat, + Igug, Igurg, Ikgnath, Ikkath, Inkathu, Inkathurg, Isagubat, Jogug, Jokgagu, + Jolagh, Jorgagu, Jregh, Jreghug, Jugag, Jughog, Jughragh, Jukha, Jukkhag, + Julakgh, Kabugbu, Kagan, Kaghed, Kahigig, Karfu, Karguk, Karrghed, Karrhig, + Karthurg, Kebub, Kegigoth, Kegth, Kerghug, Kertug, Kilug, Klapdud, Klapdud, + Klog, Klughig, Knagh, Knaraugh, Knodagh, Knorgh, Knuguk, Knurigig, Kodagog, Kog, + Kogan, Komarod, Korgak, Korgulg, Koughat, Kraugug, Krilge, Krothu, Krouthu, + Krugbu, Krugorim, Kubub, Kugbu, Kukgilug, Kulgha, Kupgugh, Kurbag, Kurmbag, + Laghed, Lamgugh, Mabub, Magdud, Malthu, Marfu, Margulg, Mazhug, Meakgu, + Mergigoth, Milug, Mudagog, Mugarod, Mughragh, Mugorim, Murbag, Naghat, Naghig, + Naguk, Nahgigoth, Nakgu, Narfu, Nargulg, Narhbub, Narod, Neghed, Nehrakgu, + Nildud, Nodagog, Nofhug, Nogugh, Nomgulg, Noogugh, Nugbu, Nughilug, Nulgha, + Numhug, Nurbag, Nurghed, Oagungad, Oakgu, Obghat, Oggha, Oggugat, Ogharod, + Oghuglat, Oguk, Ohomdud, Ohulhug, Oilug, Okganit, Olaghig, Olaugh, Olmthu, + Olodagh, Olog, Omaghed, Ombilge, Omegugh, Omogulg, Omugug, Onog, Onubub, Onugug, + Oodagh, Oogorim, Oogugbu, Oomigig, Opathu, Opaugh, Opeghat, Opilge, Opkagut, + Opoguk, Oquagan, Orgha, Orgoth, Orgug, Orpigig, Ortguth, Otugbu, Ougha, + Ougigoth, Ouhgan, Owkbanok, Paghorim, Pahgigoth, Pahgorim, Pakgu, Parfu, Pargu, + Parhbub, Parod, Peghed, Pehrakgu, Pergu, Perthag, Pigdug, Piggu, Pitgurat, + Podagog, Pofhug, Pomgulg, Poogugh, Porgarag, Pregu, Pretkag, Prigka, Prikdarok, + Prutha, Pughilug, Puiltag, Purbag, Qog, Quadagh, Quilge, Quimghig, Quomaugh, + Quordud, Quugug, Raghat, Raguk, Rakgu, Rarfu, Rebub, Rilug, Rodagog, Rogan, + Romarod, Routhu, Rugbu, Rugorim, Rurbag, Rurigig, Sabub, Saghig, Sahgigoth, + Sahgorim, Sakgu, Salthu, Saraugug, Sarfu, Sargulg, Sarhbub, Sarod, Sbghat, + Seakgu, Sguk, Shomdud, Shulhug, Sildud, Silge, Silug, Sinsbog, Slaghig, Slapdud, + Slaugh, Slodagh, Slog, Slughig, Smaghed, Smegugh, Smogulg, Snog, Snubub, Snugug, + Sodagh, Sog, Sogorim, Sogugbu, Sogugh, Sombilge, Somigig, Sonagh, Sorgulg, + Sornaraugh, Soughat, Spathu, Speghat, Spilge, Spoguk, Squagan, Stugbu, Sudagog, + Sugarod, Sugbu, Sugha, Sugigoth, Sugorim, Suhgan, Sulgha, Sulmthu, Sumhug, + Sunodagh, Sunuguk, Supaugh, Supgugh, Surbag, Surgha, Surghed, Surgug, Surpigig, + Tagdud, Taghig, Tandagh, Tandagh, Tarfu, Targhed, Targigoth, Tarod, Taugh, + Taugh, Teldgulg, Tidgug, Tidgug, Tilge, Todagog, Tog, Toghat, Togugh, Torgan, + Torug, Tozhug, Traugh, Trilug, Trougha, Trugagh, Truigig, Tuggug, Tulgan, + Turbag, Turge, Ug, Ugghra, Uggug, Ughat, Ulgan, Ulmragha, Ulmrougha, Umhra, + Umragig, Umruigig, Ungagh, Unrugagh, Urag, Uraugh, Urg, Urgan, Urghat, Urgran, + Urlgan, Urmug, Urug, Urulg, Vabugbu, Vagan, Vagrungad, Vagungad, Vakgar, Vakgu, + Vakmu, Valthurg, Vambag, Vamugbu, Varbu, Varbuk, Varfu, Vargan, Varguk, + Varkgorim, Varthurg, Vegum, Vergu, Verlgu, Verthag, Verthurg, Vetorkag, Vidarok, + Vigdolg, Vigdug, Viggu, Viggulm, Viguka, Vitgurat, Vitgut, Vlog, Vlorg, Vorgak, + Vorgarag, Vothug, Vregu, Vretkag, Vrigka, Vrikdarok, Vrogak, Vrograg, Vrothu, + Vruhag, Vrutha, Vubub, Vugub, Vuiltag, Vukgilug, Vultog, Vulug, Vurbag, Wakgut, + Wanug, Wapkagut, Waruk, Wauktug, Wegub, Welub, Wholug, Wilaktug, Wingloug, + Winug, Woabadug, Woggha, Woggugat, Woggugat, Wogharod, Wogharod, Woghuglat, + Woglug, Wokganit, Womkug, Womrikug, Wonabadug, Worthag, Wraog, Wrug, Wrukag, + Wrukaog, Wubdagog, Wudgh, Wudhagh, Wudugog, Wuglat, Wumanok, Wumkbanok, Wurgoth, + Wurmha, Wurtguth, Wurthu, Wutgarek, Xaakt, Xago, Xagok, Xagu, Xaguk, Xarlug, + Xarpug, Xegug, Xepug, Xig, Xnath, Xnaurl, Xnurl, Xoknath, Xokuk, Xolag, Xolkug, + Xomath, Xomkug, Xomoku, Xonoth, Xorag, Xorakk, Xoroku, Xoruk, Xothkug, Xruul, + Xuag, Xug, Xugaa, Xugag, Xugagug, Xugar, Xugarf, Xugha, Xugor, Xugug, Xujarek, + Xuk, Xulgag, Xunaakt, Xunag, Xunug, Xurek, Xurl, Xurug, Xurukk, Xutag, Xuthakug, + Xutjja, Yaghed, Yagnar, Yagnatz, Yahg, Yahigig, Yakgnath, Yakha, Yalakgh, + Yargug, Yegigoth, Yegoth, Yerghug, Yerug, Ymafubag, Yokgagu, Yokgu, Yolmar, + Yonkathu, Yregh, Yroh, Ysagubar, Yughragh, Yugug, Yugug, Yukgnath, Yukha, + Yulakgh, Yunkathu, Zabghat, Zabub, Zaghig, Zahgigoth, Zahgorim, Zalthu, + Zaraugug, Zarfu, Zargulg, Zarhbub, Zarod, Zeakgu, Zguk, Zildud, Zilge, Zilug, + Zinsbog, Zlapdud, Zlog, Zlughig, Zodagh, Zog, Zogugbu, Zogugh, Zombilge, Zonagh, + Zorfu, Zorgulg, Zorhgigoth, Zornaraugh, Zoughat, Zudagog, Zugarod, Zugbu, + Zugorim, Zuhgan, Zulgha, Zulmthu, Zumhug, Zunodagh, Zunuguk, Zupaugh, Zupgugh, + Zurbag, Zurgha, Zurghed, Zurgug, Zurpigig + + + Aba, Abby, Abella, Abey, Abigail, Abina, Abiona, Abira, Abra, + Abrah, Absinthe, Acacia, Acanit, Acantha, Accalia, Acelin, Achen, Ada, Adalia, + Adara, Addi, Adelaide, Adele, Adelia, Adeline, Adelle, Adena, Aderes, Adesina, + Adie, Adimina, Adiva, Adoncia, Adonia, Adora, Adrienne, Aelina, Afina, Afra, + Afrika, Afton, Agate, Agatha, Agnes, Ahara, Ahave, Ahimsa, Aida, Aiella, Aiko, + Aila, Aileen, Ailsa, Aimee, Ain, Aina, Ainhoa, Ainsley, Aintzane, Airlia, + Aisling, Aislinn, Aithne, Aiyana, Ajara, Ajay, Ajinora, Akako, Akala, Akanke, + Akasma, Akela, Akilah, Akili, Akilina, Akina, Alaina, Alake, Alala, Alamanada, + Alana, Alani, Alanna, Alaqua, Alavda, Alazne, Alberta, Albinka, Alcina, Aldea, + Aldercy, Aleka, Alenne, Alesia, Alessa, Alethea, Alexa, Alexandra, Alexandria, + Alexandrina, Alexis, Ali, Alia, Alice, Alicia, Alida, Alike, Alima, Alina, + Alison, Alita, Alix, Aliz, Aliza, Allele, Alligra, Allinora, Allison, Allyn, + Alma, Alodie, Aloysia, Althea, Alula, Alumit, Alvina, Alvita, Alysa, Alyssa, + Alyssand, Alzena, Ama, Amabel, Amadi, Amadika, Amadis, Amaia, Amala, Amalia, + Amanda, Amandine, Amara, Amarande, Amarante, Amaris, Amata, Ambar, Amber, + Ambika, Ambis, Ameerah, Amelia, Amelina, Amethyst, Amie, Amiella, Amina, Aminta, + Amissa, Amita, Amity, Amoke, Amy, Ananda, Anastasia, Ancelin, Andi, Andra, + Andraianna, Andras, Andrea, Andromeda, Aneida, Anella, Anemone, Anezka, Angela, + Angelica, Angeline, Angelique, Angeni, Ani, Anica, Anieli, Anisa, Anita, Anke, + Ann, Anna, Annabel, Annabelle, Annamarie, Anne, Annette, Annikka, Annora, + Anorah, Anoush, Ansreana, Anteia, Anthea, Antje, Antoinette, Antonia, Aolani, + Apara, Apirka, Apolline, Apolloina, Aponi, April, Aprille, Aprille, Aqua, + Aquene, Ara, Arabella, Arabelle, Araceli, Araminta, Araxie, Arcadia, Ardath, + Ardelia, Arden, Ardis, Ardith, Areiela, Arella, Aretha, Aretina, Ariadne, + Ariana, Aricia, Ariel, Ariene, Arista, Arlene, Arlinda, Armina, Arminda, + Artemisia, Aruna, Arziki, Asaria, Asenka, Ash, Asha, Ashlan, Ashleigh, Ashley, + Asia, Asisa, Aslinda, Aspasia, Asta, Aster, Astera, Astra, Astrea, Astrid, + Atalanta, Atara, Atenne, Ateri, Athalia, Athena, Athla, Atifa, Atta, Aubrey, + Auda, Audny, Audrey, Audrianna, Audun, Augustina, Aura, Aure, Aurelia, Aurilia, + Aurina, Aurkene, Aurora, Autumn, Ava, Avana, Avasa, Avella, Avena, Avie, Avis, + Aviva, Axella, Aya, Ayaluna, Ayame, Ayana, Ayasha, Aydee, Ayela, Ayiana, Ayila, + Ayisha, Ayita, Ayla, Aynora, Ayuna, Azaleah, Azalia, Azarael, Azera, Azha, + Azilea, Azina, Azize, Azora, Azura, Babette, Bacia, Bacia, Baka, Baka, Bakarne, + Balayna, Balea, Balia, Bambi, Banan, Banella, Bara, Barbara, Barika, Basha, + Basha, Basia, Basimah, Batakah, Bathsheba, Batya, Bay, Bayana, Bayo, Bayta, Bea, + Beatrice, Beatrix, Beauina, Becca, Becky, Bedelia, Bel, Belana, Belina, Belinda, + Belita, Bellanca, Belle, Belora, Bente, Beradine, Berilla, Berit, Bernadette, + Bernice, Beryl, Bess, Bessine, Beta, Beth, Bethana, Bethany, Betony, Betty, + Beulah, Beverly, Bevin, Bian, Bianca, Billie, Bina, Bindy, Binti, Birdie, + Birkita, Bixenta, Blanche, Blanda, Blenda, Bliss, Bly, Blythe, Bo, Bohdana, + Bonamy, Bonita, Bonnie, Bonny, Borgny, Braina, Brandi, Brandy, Bren, Brenda, + Brenna, Bretta, Bridget, Bridget, Brie, Brier, Brietta, Brigit, Brigitte, Brina, + Brina, Briona, Briony, Brites, Britta, Brittany, Bronwyn, Brooke, Brynn, Bucia, + Cadence, Caimile, Caitlin, Caitrin, Cala, Calandia, Calandra, Calendonia, Caley, + Calida, Calista, Calla, Callan, Callia, Callidora, Callie, Caltha, Calypso, Cam, + Camelia, Camilia, Camille, Canace, Candace, Candida, Candide, Candra, Cantara, + Caoimhe, Capri, Caprice, Cara, Caradoc, Caresse, Cari, Carina, Carine, Carissa, + Carita, Carla, Carleen, Carlen, Carling, Carlota, Carly, Carma, Carmel, + Carmelina, Carmen, Carna, Carnelian, Carol, Carolina, Caroline, Carolyn, Caron, + Carrie, Caryn, Casey, Casilda, Cassandra, Cassia, Casta, Castalia, Catalina, + Catava, Caterina, Catherine, Cathleen, Cathy, Catriona, Cayla, Ceara, Cecania, + Cecilia, Celandine, Celeste, Celia, Celina, Celina, Cellia, Cerelia, Chaitra, + Chanah, Chanda, Chandi, Chandra, Chane, Chanel, Channa, Chantal, Charis, + Charissa, Charity, Charlotte, Charmaine, Chastity, Chava, Chaviva, Chay, Chaya, + Chelsea, Chenoa, Cherica, Cherice, Cherie, Cheryl, Chesna, Chiara, Chika, + Chilali, Chimlis, Chipo, Chloe, Chloris, Cho, Christa, Christable, Christina, + Christine, Christy, Chyou, Cia, Ciannait, Ciar, Cicely, Cindy, Claire, Clara, + Clarinda, Clarissa, Claudette, Claudia, Claudine, Clementina, Clementine, + Cliantha, Clorinda, Clorinda, Clover, Cochiti, Coleene, Colette, Connie, + Constance, Constanza, Consuela, Cora, Coralie, Corazon, Corbey, Cordeali, + Coretta, Cori, Corinna, Coris, Corliss, Corrine, Cortney, Crescent, Cressida, + Crystal, Cybele, Cybil, Cynthia, Cyprien, Cyrene, Cyrilla, Cytheria, Dabria, + Dacey, Dacia, Dacie, Dacio, Dae, Dagmar, Dagna, Dai, Daily, Daisel, Daisy, + Dakota, Dale, Dalila, Dalilia, Damara, Damitri, Dana, Danett, Dania, Daniella, + Danyelle, Daphene, Daphne, Daphnie, Dar, Dara, Daralis, Darby, Daria, Darla, + Darlene, Dasha, Dasha, Davene, Davine, Davita, Dawn, Daya, Dayna, Deana, Deana, + Deandra, Deb, Debra, Dede, Dee, Deedee, Deianira, Deiene, Deirdre, Delana, + Delaney, Delbin, Delia, Delicia, Delilia, Della, Delphina, Dembe, Demi, + Demitria, Dena, Denby, Denice, Deva, Devaki, Deval, Devi, Devin, Devnet, Devon, + Diamanta, Diane, Dianthe, Diedre, Diella, Dillian, Dilly, Dilys, Dinah, Dionne, + Disa, Dita, diti, Dixie, Dodie, Dolores, Dominique, Dona, Donata, Donielle, + Donner, Dooriya, Dophina, Dora, Doreen, Dorinda, Doris, Dorithy, Dory, Drew, + Drina, Drucilla, Dulcie, Dulcinea, Dusty, Dyan, Dyani, Dymphna, Dyna, Eartha, + Easter, Ebony, Echo, Edana, Edie, Edith, Edlyn, Edna, Edolie, Edria, Edwina, + Efia, Eileen, Eirene, Elaine, Elana, Eleora, Elianor, Elina, Elina, Elisa, + Elise, Eliska, Elissa, Elita, Eliza, Elizabeeth, Elke, Ella, Elle, Ellen, Elly, + Elodie, Eloise, Elsa, Elsie, Elynor, Elyse, Elysia, Ema, Emajane, Emalia, Ember, + Emelie, Emelyne, Emily, Emma, Endora, Engracia, Enid, Enola, Enye, Erasma, + Erianthe, Erica, Erin, Erlina, Erwand, Eskarne, Esmerelda, Esperanza, Esta, + Estelle, Esther, Estu, Etain, Etaina, Etaina, Etanthe, Etta, Eudocia, Eugenia, + Eulalia, Eustacia, Eva, Evacsa, Evadine, Evadne, Evangeline, Evanthe, Eve, + Evelyn, Evita, Evonne, Eyota, Fabienne, Faifuza, Fainche, Faith, Faizah, Fallon, + Fantine, Farha, Farima, Farrah, Fatin, Fawne, Fay, Faye, Fayina, Fayme, Felcia, + Felicite, Felicity, Femi, Feridwyn, Fern, Feronia, Filinda, Fina, Finola, Fiona, + Fiorenza, Flavia, Fleta, Flora, Florence, Frances, Francesca, Francine, + Francisca, Freda, Frederica, Freya, Frida, Frieda, Fuscienne, Gabriella, + Gabrielle, Gaia, Gail, Galatea, Gali, Galina, Galya, Gana, Ganesa, Gauri, Gaye, + Gayle, Gelasia, Gemma, Genevieve, Geogia, Georgeanne, Georgetta, Georgette, + Georgiana, Geradline, Geraldine, Gerda, Gerri, Gertrude, Geva, Ghislaine, + Giacinta, Gianina, Gigi, Gilana, Gilda, Gilen, Gillian, Gin, Gina, Ginger, + Giselle, Gitana, Githa, Gizane, Gleda, Glenna, Glennys, Golda, Goldie, Gotzone, + Grace, Gracie, Grainne, Grazia, Grear, Greta, Gretchen, Grette, Gwen, Gwendolyn, + Gweneth, Gwynne, Gytha, Hadara, Hadassa, Hadiya, Haidee, Hailey, Haimi, Haldis, + Hale, Haley, Hali, Hali, Halima, Halle, Hallie, Hana, Hanan, Hannah, Hanne, + Harmoni, Harriet, Hasna, Hava, Haya, Haylee, Hazel, Hea, Heather, Hei, Heidi, + Heldegarde, Helen, Helena, Helene, Helki, Henka, Henrietta, Hesper, Hester, + Hilary, Hilda, Hinda, Hisa, Holly, Hope, Hoshi, Hyacinth, Hye, Hypatia, Ianthe, + Ida, Idola, Idonia, Ilene, Ilona, Iman, Imogene, India, Indira, Indra, Ines, + Inez, Inga, Ingrid, Iolana, Iolanthe, Iona, Iratze, Irena, Irene, Iris, Irma, + Isabeau, Isabel, Isabella, Isadora, Isaura, Isis, Isleta, Isobel, Isoke, Istas, + Ivana, Ivory, Ivy, Jacelyn, Jacinda, Jacinthe, Jada, Jael, Jaen, Jaimie, Jaione, + Jakinda, Jala, Jamie, Jamila, Jamilah, Jan, Jana, Jane, Janelle, Janet, Janice, + Janis, Janna, Jannelle, Jardena, Jarvia, Jarvinia, Jasmine, Jaya, Jayne, Jean, + Jean, Jeanette, Jeanine, Jelena, Jena, Jenay, Jendayi, Jendyose, Jenica, + Jennettia, Jennifer, Jensine, Jerrilyn, Jessica, Jewel, Jezebel, Jihan, Jillian, + Jin, Jina, Jinny, Jinx, Joakima, Joan, Joanne, Jobey, Jobihna, Jocasa, Jocelyn, + Jodi, Jody, Joelle, Joelliane, Johanna, Joia, Jolan, Jolanta, Jolene, Jolie, + Joline, Jonina, Jora, Jordane, Josephine, Josie, Jotha, Joy, Joyce, Joye, + Juanita, Judith, Juditha, Julia, Juliana, Juliane, Julie, Julietta, Julinka, + Jumoke, Jun, June, Justine, Kaatje, Kachine, Kaclyn, Kaede, Kaethe, Kai, Kaia, + Kaie, Kaili, Kaimi, Kairos, Kaiya, Kakra, Kala, Kalama, Kalanit, Kalare, Kalea, + Kali, Kalika, Kalila, Kalinda, Kalle, Kalli, Kalonice, Kalyca, Kama, Kamala, + Kamali, Kamaria, Kambo, Kameko, Kamilah, Kamilia, Kanda, Kane, Kanene, Kanika, + Kantha, Kanya, Kapera, Kara, Karan, Karayan, Karel, Karen, Karida, Karimah, + Karisa, Karka, Karla, Karlenne, Karli, Karlyn, Karmina, Karol, Karylin, Karyn, + Kasa, Kasen, Kasia, Kasinda, Kassia, Kate, Katherine, Kathleen, Katja, Katoka, + Katrien, Katrina, Kaula, Kaveri, Kavindra, Kay, Kaya, Kaye, Kayla, Kaysa, Kazia, + Keara, Keelin, Keely, Kefira, Kehinde, Kei, Keiko, Keisha, Kelda, Kelia, Kelley, + Kelli, Kellie, Kelly, Kelsey, Kendra, Kennis, Kenyangi, Kepa, Kerani, Kerensa, + Kerstan, Kesare, Kesi, Kesia, Kessie, Keturah, Ketzia, Khalida, Kichi, Kiele, + Kim, Kimberly, Kimmie, Kimmy, Kineta, Kiona, Kira, Kiran, Kirby, Kirima, + Kirsten, Kirti, Kisa, Kiska, Kismet, Kissa, Kita, Kohana, Kolina, Koren, + Koressa, Kristen, Kyly, Kyna, Kynthia, Kyoko, Lacey, Lacie, Laila, Lailie, + Lakeisha, Lala, Lalasa, Lan, Lana, Landra, Lane, Lani, Lara, Laraine, Laralee, + Lari, Larissa, Lark, Latika, Latonia, Laura, Laurana, Laurel, Laurie, Laurinda, + Lauryn, Laveda, Lavern, Laverne, Lavinia, Lea, Leah, Leah, Leala, Leandra, Leba, + Ledah, Lee, Leigh, Leiko, Leila, Leilana, Lena, Lene, Lenor, Lenora, Lenore, + Leona, Leora, Leslie, Letha, Letitia, Levana, Lexine, Lia, Liadan, Lian, Liana, + Liane, Libby, Lien, Lila, Lilith, Lillian, Lillie, Lily, Limber, Lina, Linda, + Lindsay, Lindsey, Linette, Linnae, Linnea, Lisa, Lisette, Litsa, Liv, Liza, + Lois, Lokelani, Lola, Loni, Lora, Lore, Lorelei, Lorelle, Loretta, Lori, + Lorraine, Lotus, Louise, Lucille, Lucine, Lucretia, Lucy, Ludia, Luela, Luisa, + Lukene, Lukina, Lulu, Luna, Lydia, Lynda, Lynelle, Lynn, Lynnda, Lynnette, + Lyris, Lysel, Lysnadra, Mabel, Macaria, Machi, Maddy, Madelaine, Madelina, + Madeline, Madelon, Madelyn, Mady, Mae, Magan, Magara, Magdalen, Magdalena, + Magdaline, Magena, Magenta, Maggie, Mahala, Mahalia, Mai, Maia, Maida, Maisie, + Maitane, Maizah, Maj, Malaya, Malila, Malina, Malinda, Malka, Mallory, Malu, + Mamie, Manda, Mandara, Mandisa, Mandy, Mangena, Manon, Mansi, Manya, Mara, + Marcella, Marcia, Marcy, Maren, Margaret, Margaret, Margarita, Margo, Margot, + Marguirte, Maria, Mariah, Mariam, Mariama, Marian, Mariana, Marianna, Marianne, + Maribel, Marie, Mariel, Marietta, Marily, Marilyn, Marina, Maris, Marisa, + Marisha, Marissa, Marjani, Marjeta, Marjorie, Marlene, Marlo, Marmara, Marnie, + Marnina, Marsha, Marta, Martha, Marti, Martina, Mary, Maryann, Marybeth, + Marylou, Marzia, Matana, Mathea, Matilda, Matrika, Maud, Maura, Maureen, + Maurita, Mavis, Maxine, May, Maya, Meara, Meara, Meda, Medea, Meg, Megan, + Megara, Meghan, Mei, Meira, Mela, Melanie, Melantha, Melba, Melia, Melian, + Melina, Melinda, Melisenda, Melissa, Mellinio, Melodie, Melody, Melosa, Melva, + Mercedes, Meredith, Merele, Mesha, Meta, Mia, Miakoda, Michaela, Michele, + Michelle, Midori, Migina, Mignon, Mika, Millicent, Millie, Min, Mina, Minda, + Mindel, Mindy, Minerva, Minka, Minna, Minnie, Mira, Miranda, Mirem, Miremba, + Mireya, Miriam, Mirielle, Missy, Misty, Mitena, Mitexi, Mitzi, Moira, Mollie, + Molly, Mona, Monique, Moon, Morena, Morgan, Morgana, Morgance, Moria, Moriah, + Muriel, Myra, Nada, Nadia, Nadine, Nadya, Naia, Nailah, Naimah, Nalini, Namazzi, + Nami, Nan, Nana, Nancy, Nanette, Nantale, Naomi, Napea, Nara, Narda, Narmada, + Nasiche, Nastassia, Natalie, Natane, Natasha, Natesa, Naysa, Nazirqah, Neala, + Neci, Nediva, Neely, Nekane, Nell, Neola, Neoma, Neona, Neria, Nerine, Nerissa, + Netti, Neva, Nevada, Neysa, Nicia, Nicola, Nicole, Nicolette, Nika, Nikki, + Nimah, Nina, Niobe, Niola, Nira, Nirvelli, Nissa, Nita, Nitara, Nixie, Noel, + Noelani, Noella, Nolita, Nona, Nona, Nora, Norah, Noreen, Nori, Noriko, Norma, + Nydia, Nyrna, Nyssa, Obelia, Octavia, Odelia, Odelia, Odera, Odessa, Odetta, + Odette, Odile, Ohanna, Okelani, Olathe, Olayinka, Olesia, Olga, Oliana, Olinda, + Olivette, Olivia, Ona, Onida, Opal, Ophelia, Oralie, Orane, Orenda, Oriana, + Orianna, Oriel, Oriole, Orlantha, Ornidaa, Paige, Pakuna, Palmiera, Paloma, + Pamela, Pandita, Pandora, Panthea, Pantzike, Panya, Panyin, Pascale, Patia, + Patience, Patricia, Patsy, Paula, Paulette, Pauline, Pavla, Pazia, Pearl, Peg, + Peggy, Pelagia, Pemba, Penda, Penelope, Peninna, Penny, Penthea, Peony, Perdita, + Perouze, Persis, Petra, Phaedra, Phedra, Philomena, Phoebe, Phylis, Phyllis, + Pia, Pier, Pila, Piper, Polly, Poloma, Porche, Portia, Priscilla, Prudence, + Prudy, Pyrena, Pythia, Qamra, Queena, Quella, Quenby, Quintina, Quiterie, + Rachel, Radella, Radinka, Rae, Rai, Raizel, Ramla, Ramona, Ramya, Randie, Rane, + Ranee, Rani, Raquel, Rashida, Rasine, Ratri, Raven, Rawnie, Rayna, Raynell, + Raziya, Reba, Rebecca, Regan, Regina, Reidun, Remy, Rena, Renata, Rene, Renee, + Rhea, Rhiamon, Rhianne, Rhiannon, Rhoda, Rhodanthe, Rhonda, Rhonna, Rhyssa, Ria, + Riane, Rica, Rihana, Rikki, Rio, Risa, Rita, Riva, Roanna, Roberta, Robin, + Robyn, Rochelle, Rohanna, Rona, Rorie, Rosa, Rosalind, Rosalinda, Rosalinde, + Rosaline, Rosanne, Rose, Roseanne, Rosemarie, Rosemary, Rowena, Roxana, Roxanne, + Ruby, Rumer, Ruth, Ruthann, Ryann, Ryanne, Ryba, Ryssa, Saba, Sabina, Sabiny, + Sabirah, Sabra, Sabrina, Sacha, Sachi, Sade, Sadira, Saffi, Safiya, Sagara, + Saidah, Sakari, Sakinah, Sakti, Sakura, Salihah, Salimah, Salina, Sally, Salome, + Samantha, Samara, Samirah, Sancia, Sandia, Sandra, Sandrine, Sandya, Sara, + Sarah, Sarai, Saraid, Saree, Sarena, Sari, Sarisha, Sasha, Sashenka, Satinka, + Savanna, Saxon, Scotia, Searlait, Season, Sebasten, Seema, Sela, Selena, Selina, + Selma, Semele, Senta, Serafina, Serilda, Sesha, Shaine, Shakira, Shako, + Shammara, Shana, Shanata, Shandra, Shandy, Shani, Shanley, Shanna, Shannon, + Shantay, Shantha, Sharman, Sharon, Sharri, Shashi, Shawn, Shayndel, Sheba, + Sheena, Sheila, Shela, Shelby, Shelley, Shelly, Sherri, Shika, Shin, Shina, + Shira, Shirley, Shobi, Shoshana, Sibley, Sibongile, Sibyl, Sidonia, Sidra, + Sierra, Sigourney, Siham, Sileas, Silva, Silvia, Simba, Simone, Sine, Sinead, + Siobhan, Siran, Sirena, Siroun, Sitara, Sitembile, Siv, Sive, Skyler, Sofi, + Solana, Solange, Soledad, Solita, Sondra, Sonia, Sonja, Sonya, Sophia, Sophie, + Sophronia, Spica, Stacey, Stacia, Stacy, Stefania, Stella, Stephani, Stephanie, + Ster, Stesha, Stockard, Storm, Sukatai, Suki, Sumi, Summer, Sun, Susan, Susanna, + Suzanne, Svetlana, Sybil, Sydelle, Sydney, Syeira, Sylvia, Syna, Synia, Tabitha, + Taci, Tacita, Tadi, Taffy, Tahirah, Tai, Taima, Tainn, Taipa, Taite, Taka, + Takara, Takiyah, Takoda, Talasi, Tale, Talia, Talia, Talitha, Tallulah, Tam, + Tama, Tamara, Tamary, Tamma, Tammy, Tanaka, Tani, Tansy, Tanya, Tao, Tara, Tate, + Tatyana, Tawnie, Tawny, Tayce, Taylor, Teague, Tehya, Tekla, Temina, Terentia, + Terese, Terrilyn, Tertia, Teryn, Tesia, Tess, Tessa, Thadea, Thais, Thalassa, + Thalia, Than, Thana, Thara, Thea, Thekla, Thelma, Theodosia, Theone, Thera, + Thirza, Thora, Thyra, Tia, Tiara, Tienette, Tierney, Tierra, Tiffany, Tilda, + Timandra, Tina, Tiponya, Tirza, Tivona, Tobey, Tola, Tora, Tori, Tory, Tosia, + Tove, Tracey, Tracy, Treasa, Tresa, Treva, Trianon, Tricia, Trilby, Trina, + Trind, Trish, Trisha, Trudy, Tryne, Tryphena, Tyne, Ula, Ulani, Ultima, Uma, + Una, Undine, Undine, Urania, Uriana, Ursula, Uta, Vala, Valentina, Valeria, + Valerie, Valeska, Valonia, Valora, Vanda, Vanessa, Vanora, Vanya, Vashti, Veda, + Velika, Velma, Venesssa, Vera, Verena, Verity, Veronica, Vesta, Vevila, + Victoria, Vidonia, Violet, Violet, Violetta, Virginia, Viridis, Viveka, Vivian, + Voleta, Vrinda, Wakanda, Wanda, Waneta, Wendy, Whilhelmina, Whitney, Wijdan, + Willow, Wilma, Wilona, Winda, Winema, Winifred, Winna, Winona, Wynee, Wynn, + Wynona, Xanthe, Xaveria, Xaviera, Xena, Xenia, Ximena, Xylia, Xylona, Yachne, + Yanice, Yarmilla, Yasmeen, Yasmin, Yelinda, Yenene, Yesmina, Yetta, Yeva, + Yokiko, Yolanda, Yolie, Yonina, Yovela, Yvella, Yvette, Yvonne, Zada, Zahara, + Zahirah, Zahra, Zakia, Zalea, Zalika, Zaltana, Zandra, Zara, Zarah, Zaza, + Zehava, Zelda, Zelenka, Zelia, Zella, Zena, Zenaide, Zenia, Zerlinda, Zeva, + Zevida, Zia, Ziazan, Zigana, Zila, Zina, Zinnia, Zita, Zoe, Zola, Zona, Zora, + Zorah, Zorda, Zosia, Zuleika, Zulema, Zuza, Zuzanny, Anatae, Cilis + + + Aaron, Aasin, Abbott, Abdel, Abdiel, Abel, Abijah, Abner, + Abraham, Abran, Ace, Achilles, Ackerley, Adair, Adam, Addison, Adeben, Adem, + Adiran, Adlai, Adler, Adley, Admon, Adolph, Adon, Adonis, Adrian, Adriel, + Aeneas, Agustin, Ahearn, Ahmik, Ahren, Aidan, Aiken, Aimery, Aitan, Ajayi, + Akando, Akbaar, Akello, Akil, Akshay, Alan, Aland, Alano, Alaric, Alastair, + Alben, Albert, Alcander, Alcott, Alden, Alder, Aldrick, Alec, Alek, Aleksy, + Aleron, Aleser, Alex, Alexander, Alfred, Alger, Alim, Alistair, Allaard, Allan, + Allard, Allen, Alonzo, Alphonse, Alphonso, Alston, Altair, Alton, Alvin, Amadeo, + Amadi, Amado, Ambrose, Amiel, Ammon, Amos, Amsden, Anders, Andre, Andreus, + Andrew, Andrey, Andries, Angelo, Angus, Anker, Anoki, Ansel, Anselme, Ansley, + Anson, Anthony, Antonio, Anwar, Archer, Archibald, Ardon, Aren, Ares, Argus, + Ari, Aricin, Arion, Aristo, Aristotle, Arkin, Arlen, Arley, Arlin, Arlo, Arman, + Armen, Armon, Armstrong, Arne, Arnold, Arnon, Aron, Arpiar, Arsen, Arsenio, + Arthur, Ashby, Asher, Ashford, Ashlin, Ashon, Ashur, Athan, Atheron, Atman, + Audric, Audun, Augustin, Augustus, Aurek, Austin, Averill, Avery, Axel, Bae, + Bailey, Baingana, Bakari, Balbo, Balder, Baldwin, Bale, Balendin, Bali, Balin, + Balint, Bancroft, Bandele, Bane, Banning, Baran, Barclay, Barden, Bardo, Bardon, + Barnabas, Barnaby, Barnett, Barney, Baron, Barrett, Barry, Barse, Bart, Barth, + Bartholomew, Barton, Basil, Bastiaan, Baul, Bavol, Baxter, Bay, Bayani, Bayard, + Baylor, Bazyli, Beacan, Beagan, Beaman, Beau, Beaumont, Beauregard, Beck, + Beldon, Belen, Bem, Beman, Ben, Benedict, Benen, Benjamin, Bennett, Benson, + Bent, Bentley, Benton, Berenger, Bergren, Berk, Berkeley, Bernard, Bersh, Bert, + Berthold, Berton, Bertram, Beval, Bevan, Bialy, Bilal, Bishop, Bitalo, Bjorn, + Blade, Blaine, Blair, Blaise, Blake, Blaz, Blorn, Bo, Boden, Bogart, Bohdan, + Bolton, Bond, Booker, Boone, Borden, Boris, Botan, Bowie, Bowman, Boyce, Boyd, + Boyden, Brad, Braden, Bradford, Bradney, Brady, Bram, Bran, Brand, Brandeis, + Brandon, Brant, Braxton, Bray, Braz, Brazil, Bren, Brencis, Brendan, Brendon, + Brennan, Brent, Brentan, Bret, Brett, Brewster, Briac, Brian, Briand, Brice, + Brieg, Brinley, Brishen, Brock, Broderick, Brodny, Brody, Bronson, Bront, Bruce, + Bruno, Brutus, Bryan, Bryant, Bryce, Bryson, Buck, Bud, Budo, Burgess, Burhan, + Burian, Burke, Burl, Burr, Burton, Byran, Byron, Cadeo, Cador, Caedmon, Cailan, + Cain, Caine, Calder, Caldwell, Caleb, Calvin, Cam, Camden, Cameron, Candan, + Canton, Canute, Carden, Carey, Carl, Carlin, Carlo, Carlos, Carlton, Carr, + Carrick, Carrocio, Carroll, Carson, Carson, Carter, Carver, Casey, Casper, + Cassidy, Cassius, Castel, Cato, Caton, Cavan, Ceasar, Cecil, Cedric, Cemal, + Chad, Chadwick, Chaim, Chal, Chale, Chalmers, Chander, Chandler, Chane, Chaney, + Channing, Chapin, Chapman, Charles, Charlton, Chase, Chatha, Chauncy, Chayton, + Chen, Cheney, Chester, Chet, Chevalier, Chike, Chin, Christian, Christoph, + Christopher, Christos, Chuck, Ciceron, Ciro, Clarence, Clark, Claude, Clay, + Clayton, Clement, Cleveland, Clifford, Clifton, Clint, Clinton, Clive, Clyde, + Cody, Colby, Cole, Coleman, Colin, Collin, Colon, Colton, Coman, Condon, Connor, + Conrad, Conway, Corbett, Corbin, Corcoran, Cordell, Corey, Cornelius, Cort, + Coty, Courtland, Craig, Crandall, Creighton, Crispin, Crosby, Cullen, Cullin, + Culver, Curran, Curtis, Cynric, Cyrano, Cyril, Cyrus, Dag, Dagan, Dakarai, + Dakota, Dale, Dallin, Dalton, Daly, Damek, Damen, Damian, Damien, Damion, Damon, + Dana, Dane, Daniel, Danior, Dannik, Dante, Daren, Darien, Dario, Darnell, + Darrel, Darrell, Darren, Daryl, David, Davin, Davis, Deacon, Dean, Decker, + Delaney, Delano, Delbert, Dellan, Delmore, Delsin, Deman, Dempsey, Dempster, + Denby, Dennis, Dennys, Denton, Denver, Der, Derek, Derrick, Derry, Deverell, + Devin, Devlin, Dewey, Diederik, Diego, Dieter, Dillon, Dimitri, Dirk, Dobry, + Dominic, Dominick, Donald, Donatien, Donato, Donnelley, Donnelly, Donovan, + Doron, Dougie, Douglas, Douglass, Dov, Doyle, Drake, Drew, Duane, Dugan, Duglas, + Duncan, Dunstan, Durand, Durriken, Dusan, Dustin, Dutch, Dwayne, Dwight, Dyami, + Dyastro, Dylan, Dymas, Eamon, Earl, Earle, Eaton, Edan, Edgan, Edgar, Edison, + Edmund, Edrin, Edward, Edwin, Edwin, Egan, Einar, Elad, Elden, Eldroth, Elek, + Eli, Elias, Elijah, Elkan, Ellery, Elliot, Elliott, Ellis, Ellsworth, Elmer, + Elmo, Elston, Elton, Elwood, Emanuel, Emil, Emilio, Emmett, Enoch, Enrico, + Enrique, Ephraim, Erek, Eric, Erik, Ernest, Erol, Errol, Erskine, Erwin, Eryx, + Essien, Esteban, Ethan, Eugene, Evan, Evander, Everett, Evzen, Ezekial, Ezra, + Fabio, Fairfax, Farley, Farrell, Faxon, Felix, Felix, Fenn, Fenton, Fergus, + Ferran, Ferris, Fielding, Filbert, Filmore, Finlay, Finley, Finn, Finnigan, + Fisk, Fitzgerald, Fletcher, Flindo, Flint, Floyd, Flynn, Forbes, Forrest, + Forsythe, Foster, Foster, Francis, Franek, Frank, Franklin, Frasier, Frazer, + Frazier, Fred, Frederick, Fremont, Fritz, Fuller, Fulton, Gabe, Gabriel, Gage, + Galen, Galeno, Galvin, Gamble, Gannon, Gareth, Garfield, Gargan, Garner, + Garrett, Garrick, Garridan, Garrison, Garritt, Garth, Garvin, Gary, Gaspar, + Gaston, Gavin, Gavrie, Gaynor, Geoff, Geoffrey, Geoffry, George, + Gerard, Gerik, Germain, Gerry, Gideon, Gilberto, Giles, Ginton, Givon, Glen, + Glenn, Glenno, Godfrey, Gordon, Gordy, Gorman, Grady, Graham, Gram, Granger, + Grant, Granville, Grayson, Greg, Greger, Gregor, Gregory, Gresham, Griffen, + Griffith, Guilhem, Gunnar, Gunther, Gus, Gustave, Guthrie, Guy, Hackett, Hadden, + Hadi, Hadley, Hadrian, Hagan, Hal, Halden, Hale, Halian, Halsey, Hamilton, + Hamlin, Hank, Hans, Harden, Hardy, Harith, Harlan, Harman, Harold, Harper, + Harrison, Harry, Hart, Hartley, Harvey, Hassan, Hastin, Hastings, Hayden, Hayes, + Haynes, Heath, Hector, Helaku, Henning, Henry, Herbert, Herman, Herschel, + Hilliard, Hilton, Hiroshi, Hobart, Hogan, Holden, Holt, Homes, Horace, Horton, + Houston, Howard, Howrence, Hoyt, Hugh, Hugo, Humphrey, Hunter, Huntley, Hyman, + Iain, Ian, Ilias, Ingmar, Ingram, Ira, Irvin, Irving, Irwin, Isaac, Isaiah, + Israel, Itzak, Ivan, Ivar, Jabari, Jabir, Jack, Jacob, Jacobe, Jacques, Jacson, + Jacy, Jafar, Jagger, Jake, Jal, Jaleel, Jamal, James, Jamison, Jared, Jarek, + Jarman, Jaron, Jarrod, Jarvis, Jason, Jasper, Javan, Javier, Jay, Jebidiah, Jed, + Jedidiah, Jedrek, Jeff, Jeffrey, Jelani, Jeremiah, Jeremy, Jerolin, Jerome, + Jeromy, Jerzy, Jesse, Jessee, Jethro, Jibril, Jin, Jiro, Jivin, Joel, Johann, + John, Jolon, Jonah, Jonathan, Jonathon, Jordan, Jordon, Jorgen, Jorvin, Joseph, + Joshua, Judd, Jude, Julian, Julius, Juma, Jung, Justin, Kadin, Kai, Kaikara, + Kaladin, Kalb, Kale, Kalil, Kalkin, Kalman, Kamal, Kane, Kaniel, Kardal, Karl, + Karsten, Kasch, Kasen, Kaspar, Kateb, Kayin, Keane, Kearney, Kedar, Keefe, + Keelan, Keenan, Kegan, Keir, Keir, Keith, Kelby, Keleman, Kell, Kellen, Kelvin, + Ken, Kenan, Kendall, Kendrick, Kenelm, Kenley, Kennard, Kennedy, Kenneth, Kent, + Kenton, Kenyon, Keona, Ker, Kerby, Kern, Kerry, Kers, Kersen, Kerwin, Kester, + Kevin, Khalil, Khoury, Kiefer, Kieran, Kiernan, Killian, Kin, Kinnel, Kinsey, + Kintan, Kip, Kirby, Kirk, Kiyoshi, Kliftin, Klog, Komor, Kontar, Krischan, + Krister, Kurt, Kyle, Kyler, Laethan, Laird, Lamar, Lamont, Lance, Lander, + Landon, Lane, Lang, Larry, Lars, Lawler, Lawrence, Lazarus, Lear, Lee, Leif, + Leighton, Leland, Len, Lennon, Lennor, Lennox, Lensar, Leo, Leon, Leonard, + Leron, Leroy, Lester, Lev, Levi, Lewis, Lewis, Li, Liam, Like, Lincoln, Lindsey, + Lionel, Llewellyn, Lloyd, Logan, Loren, Lorenzo, Lorne, Louis, Lowell, Lucas, + Lucian, Luis, Luke, Lukyan, Lunt, Luther, Lyle, Lyndon, Lysander, Mac, Macer, + Mack, Mackenzie, Magnus, Malcolm, Malik, Manco, Mandek, Mander, Manfred, + Manning, Mansur, Manuel, Marc, Marcos, Marcus, Marden, Marek, Mario, Mark, + Markham, Markos, Marlin, Marlon, Marlon, Marshal, Marshall, Marsten, Martin, + Martingo, Marvin, Mason, Matai, Mateo, Mather, Matthew, Matthias, Maurice, Max, + Maxwell, Maynard, Mayon, Mead, Meka, Mercer, Merill, Merle, Merrick, Merrik, + Meyer, Micael, Michael, Migon, Miguel, Mike, Mikkel, Mikos, Miles, Miles, Milo, + Milton, Miner, Mitchell, Monroe, Monte, Morgan, Morley, Morris, Mortimer, + Morton, Morven, Morz, Motega, Mukasa, Murdoch, Murdock, Murphy, Myles, Myron, + Naeem, Nalren, Nantan, Nathan, Nathaniel, Neal, Neale, Neil, Nelek, Nelson, + Neron, Nestor, Nevan, Neville, Nevin, Nevin, Nicanor, Nicholas, Nigel, Nikolos, + Nils, Noah, Nodin, Noe, Nolan, Norbert, Norman, Norris, Norton, Nuri, Nyle, + Oakes, Oakley, Ochen, Octavius, Odell, Odin, Odion, Odon, Ogden, Olaf, Olin, + Oliver, Omar, Ordano, Oren, Orion, Orman, Ormand, Orrin, Orson, Orville, Oscar, + Osgood, Osmond, Otis, Otto, Owen, Paco, Palmer, Paolo, Paris, Parker, Parnell, + Pascal, Patamon, Patrick, Patterson, Patton, Paul, Paulin, Pavel, Paxton, + Payton, Pearce, Peder, Pembroke, Penn, Percival, Perry, Peter, Peyton, Phearcy, + Philip, Phillip, Phillippe, Phoenix, Pierce, Pierre, Pierson, Pilan, Platon, + Porter, Prentice, Prescot, Prescott, Preston, Quentin, Quenton, Quillan, Quincy, + Quinlan, Quinn, Rad, Radcliffe, Radman, Rafael, Rafferty, Ragnar, Raidon, + Raleigh, Ralph, Ramiro, Ramon, Ramsay, Ramsey, Ranard, Rance, Randall, Randolph, + Ranen, Ranger, Rankin, Raoul, Raphael, Raul, Ravi, Ravi, Ravid, Ray, Raymond, + Raynor, Reade, Redford, Redmond, Reed, Reese, Reeve, Regan, Reginald, Regis, + Remington, Renaldo, Rendor, Renfry, Renny, Reuben, Rex, Reyhan, Rhett, Rhett, + Rhys, Ricardo, Richard, Richter, Rico, Rider, Ridgley, Rigby, Riley, Rimon, + Ringo, Ringo, Riodan, Riordan, Roarke, Robert, Roberto, Robi, Rockwell, Rod, + Roderick, Rodman, Rodney, Rodrigo, Roger, Roi, Roland, Roldan, Rolf, Ronald, + Ronan, Rooney, Rory, Roscoe, Ross, Roth, Rowan, Rowland, Roy, Royce, Ruben, + Rudd, Rudi, Rudyard, Rufus, Runako, Ruskin, Russ, Russell, Rusty, Rutherford, + Rutledge, Ryan, Ryder, Rylan, Sahale, Sahen, Salim, Saloman, Sam, Samien, + Sammon, Samson, Samuel, Sanders, Sandon, Sandor, Sanford, Sargent, Sarngin, + Sarojin, Saul, Saunders, Sawyer, Saxon, Schuyler, Scott, Sean, Sebastian, + Sebastien, Seif, Selby, Senon, Sergio, Seth, Seung, Severin, Sevilin, Seward, + Seymour, Shane, Shawn, Shea, Sheffield, Sheldon, Shen, Sheridan, Sherman, + Sherwin, Sherwood, Shing, Shunnar, Sidney, Siegfried, Silas, Simon, Sivan, Skip, + Skyler, Slade, Slevin, Smith, Solomon, Sorgan, Soterios, Spalding, Spencer, + Spenser, Standford, Stanley, Stanton, Stasio, Stefan, Stephan, Stephen, + Sterling, Stevan, Steve, Steven, Stewart, Stoke, Stoyan, Strom, Stuart, Subrey, + Sulaiman, Sullican, Sumner, Sutherland, Sutton, Sven, Sylvester, Tab, Tabari, + Tad, Tadi, Tai, Tajo, Talbart, Talbot, Talman, Talos, Tanek, Tanner, Tano, Taro, + Tate, Taurin, Taylor, Tem, Terence, Terrence, Terrill, Terry, Thaddeus, Thai, + Thaman, Thane, Thanos, Theobald, Theodore, Theron, Thierry, Thomas, Thorpe, + Thurston, Thurston, Tibalt, Tiernan, Timothy, Titus, Tobias, Toby, Tod, Todd, + Tomas, Tong, Tor, Torin, Torrance, Townsend, Travers, Travis, Tremain, Tremaine, + Trent, Trevor, Trey, Tristan, Troy, Tryon, Tucker, Tully, Tyee, Tyler, Tymon, + Tyrone, Upton, Uriah, Urian, Van, Vance, Vaughn, Vern, Vernon, Victor, Vincent, + Vinson, Virgil, Vito, Vlad, Vladimir, Vokes, Volf, Wade, Wagner, Walden, Waldo, + Walker, Wallace, Wally, Walter, Ward, Warner, Warren, Watson, Waylan, Wayland, + Waylon, Wayne, Webb, Webster, Wendell, Wesley, Weston, Weylin, Whitaker, Wilfen, + Will, Willard, Willem, William, Wilson, Winston, Winthrop, Wlby, Woody, Wyatt, + Xavier, Xenos, Xerxes, Ximen, Yakecan, Yale, Yancey, Yardley, Yarin, Yerik, + Yero, Yervant, York, Yusuf, Yves, Zachariah, Zachary, Zackery, Zaid, Zaide, + Zane, Zaniel, Zann, Zared, Zarek, Zeke, Zenon, Zion, Ziven, Zorn, Sareth, Ginko, Khorne, Tom, Clive + + + Bergeni, Callylili, Elaniana, Hanalea, Jerliai, Kaitha, Mesanial, Oquila, Sylievo, + Uliala, Vimaly, Yeldemi + + + Castoriel, Celebrindal, Chathmiru, Davlien, Gerrath, Jerraintho, Lewys, Misran, + Nandrien, Olonal, Peorilien, Regornolas, Rylvarn, Silnaliel, Talendeor, Uomo, + Verlolas + + \ No newline at end of file diff --git a/Data/objects.xml b/Data/objects.xml new file mode 100644 index 0000000..92f8b2a --- /dev/null +++ b/Data/objects.xml @@ -0,0 +1,2643 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Data/pageresponse.cfg b/Data/pageresponse.cfg new file mode 100644 index 0000000..1690190 --- /dev/null +++ b/Data/pageresponse.cfg @@ -0,0 +1,10 @@ +Not Enough Info Please provide a more informative description of your problem so that we may better help you. +Bad Stuck We apologize, but we do not move players unless they are physically stuck. Take care! +Cannot Teleport We apologize, but staff members do not move players across the map. +Item Request We apologize, but we do not give items to players. +Murder System Query Hello! Information regarding the murder system is available here. +Pet Bonding Hail! The pet bonding system works just as it does on Origin's official UO shards. You can find all the information you need about it here! Take care! +Thief Guild In order to join the thief guild, your character must be at least one week old, must have been logged into the game for a total of 48 hours, and must have 60.0 or more stealing skill. We are not be able to tell you how long until your character will meet these requirements. Take care! +Password Change In order to change your password, please type:
[password newpassword newpassword

Be sure to replace newpassword with the password you would like to use. Take care! +Cannot Help Sorry, we cannot help you with that. +Online Request We do not reveal the online status of players. diff --git a/Data/shrink.cfg b/Data/shrink.cfg new file mode 100644 index 0000000..e5a6e9e --- /dev/null +++ b/Data/shrink.cfg @@ -0,0 +1,361 @@ +# All lines are trimmed. Empty lines and lines starting with '#' are ignored +# Table for converting body values to item numbers +# Format: +# BodyItem + +1 0x20DF +2 0x20D8 +3 0x25B8 +4 0x20D9 +5 0x211D +6 0x211A +7 0x25AF +8 0x2582 +9 0x2584 +10 0x2584 +11 0x25C4 +12 0x20D6 +13 0x25D7 +14 0x20D7 +15 0x25D9 +16 0x25DD +17 0x25AE +18 0x20D8 +19 0x25C4 +20 0x25C5 +21 0x25BF +22 0x258F +23 0x25D0 +24 0x25A4 +25 0x25D1 +26 0x25C7 +27 0x25D1 +28 0x25C6 +29 0x2592 +30 0x20DC +31 0x2595 +33 0x20DE +34 0x25D2 +35 0x20DE +36 0x20DE +37 0x25D2 +38 0x2585 +39 0x25A6 +40 0x2586 +41 0x25AE +42 0x25B7 +43 0x2587 +44 0x25B7 +45 0x25B7 +46 0x20D6 +47 0x20FA +48 0x25B9 +49 0x20D6 +50 0x25BC +51 0x20E8 +52 0x25C2 +53 0x20E9 +54 0x20E9 +55 0x20E9 +56 0x25BC +57 0x25BC +58 0x2100 +59 0x20D6 +60 0x20D6 +61 0x20D6 +62 0x20D6 +63 0x2583 +64 0x25A3 +65 0x25A3 +66 0x25C8 +67 0x258E +68 0x258F +69 0x258F +70 0x25CC +71 0x25C9 +72 0x25CB +73 0x2594 +74 0x259F +75 0x212D +76 0x25CD +77 0x25A2 +78 0x25A5 +79 0x25A5 +80 0x258C +81 0x2130 +82 0x25A5 +83 0x25A8 +84 0x25A8 +85 0x25AB +86 0x25AD +87 0x25AC +88 0x2108 +89 0x25C0 +90 0x25C1 +91 0x25C2 +92 0x25C2 +93 0x25C2 +94 0x20E8 +96 0x20E8 +97 0x2596 +98 0x2596 +99 0x25D1 +100 0x25D2 +101 0x2581 +102 0x2584 +103 0x20D6 +104 0x20D6 +105 0x20D6 +106 0x20D6 +107 0x20D7 +108 0x20D7 +109 0x20D7 +110 0x20D7 +111 0x20D7 +112 0x20D7 +113 0x20D7 +114 0x259B +115 0x259B +116 0x259C +117 0x259D +118 0x259E +119 0x259E +120 0x259E +121 0x259E +122 0x25CE +123 0x2589 +124 0x258A +125 0x258B +126 0x258B +127 0x2597 +128 0x25B6 +129 0x25C8 +130 0x258D +131 0x2590 +132 0x25A0 +133 0x2131 +134 0x25A1 +135 0x25A8 +136 0x25A9 +137 0x25AA +138 0x25AF +139 0x25AF +140 0x25B1 +141 0x2106 +142 0x25B7 +143 0x25B7 +144 0x25BA +145 0x20FB +146 0x25BB +147 0x25BD +148 0x25BE +150 0x20FB +151 0x20F1 +152 0x25CA +153 0x2591 +154 0x25A7 +155 0x20EC +157 0x25C3 +158 0x25D6 +159 0x25D8 +160 0x25D8 +161 0x25DA +162 0x25DB +163 0x25DC +164 0x20ED +165 0x2100 +166 0x20D7 +167 0x2118 +168 0x259F +170 0x20F6 +171 0x25B2 +172 0x20D6 +173 0x25C3 +175 0x2589 +176 0x25B6 +177 0x259C +178 0x259C +179 0x259C +180 0x20D6 +181 0x25AE +182 0x25AE +183 0x2106 +184 0x2107 +185 0x2106 +186 0x2107 +187 0x2615 +188 0x2615 +189 0x25B0 +190 0x21F1 +191 0x25A0 +192 0x25CE +193 0x2615 +194 0x2619 +195 0x260F +200 0x2598 +201 0x211B +202 0x2131 +203 0x2101 +204 0x259A +205 0x2125 +206 0x2131 +207 0x20EB +208 0x20D1 +209 0x2580 +210 0x25B2 +211 0x2118 +212 0x211E +213 0x20E1 +214 0x25B5 +215 0x20D0 +216 0x2103 +217 0x2588 +218 0x25B3 +219 0x25B4 +220 0x20F6 +221 0x20FF +223 0x20EB +225 0x25D3 +226 0x2599 +228 0x259E +231 0x20EF +232 0x20EF +233 0x20F0 +234 0x20D4 +237 0x20D4 +238 0x2123 +290 0x2101 +291 0x2126 +292 0x2127 +300 0x2620 +301 0x2621 +302 0x2622 +303 0x2623 +304 0x2624 +305 0x2625 +306 0x2626 +307 0x2627 +308 0x2628 +309 0x2629 +310 0x262A +311 0x262B +312 0x262C +313 0x262D +314 0x262E +315 0x262F +316 0x2630 +317 0x2631 +318 0x2632 +319 0x2633 +400 0x2106 +401 0x2107 +402 0x2106 +403 0x2107 +744 0x2106 +745 0x2107 +746 0x260E +747 0x262A +748 0x25C7 +749 0x25A4 +750 0x2106 +751 0x2107 +752 0x2610 +753 0x258D +754 0x258D +755 0x258D +756 0x260C +757 0x260B +758 0x258D +763 0x260B +764 0x261F +765 0x261E +766 0x25FC +767 0x25F9 +768 0x2612 +769 0x25F9 +770 0x261C +771 0x261D +772 0x25F8 +773 0x25FA +774 0x25FB +775 0x2613 +776 0x2611 +777 0x260D +778 0x261A +779 0x2607 +780 0x2608 +781 0x2604 +782 0x2603 +783 0x2602 +784 0x2605 +785 0x260E +786 0x260A +787 0x260F +788 0x2618 +789 0x2614 +790 0x2616 +791 0x260F +792 0x2609 +793 0x2617 +794 0x2619 +795 0x2611 +796 0x2611 +797 0x20D6 +798 0x20D6 +799 0x2619 +804 0x2602 +805 0x2604 +806 0x2603 +807 0x2602 +808 0x2602 +820 0x259A +825 0x25B2 +826 0x25B3 +827 0x25B4 +828 0x20F6 +831 0x211A +832 0x211A +833 0x211A +834 0x2597 +835 0x2125 +837 0x25C0 +838 0x25C1 +839 0x2615 +840 0x2615 +841 0x2615 +842 0x2615 +843 0x2123 +846 0x2599 +848 0x259E +970 0x2106 +990 0x2106 +991 0x2106 +994 0x2106 +998 0x25A0 + +#SE Mobiles + +246 0x2763 +254 0x2764 +242 0x2765 +199 0x2766 +247 0x2767 +248 0x2768 +196 0x2769 +243 0x276A +240 0x276B +252 0x276C +241 0x276D +251 0x276E +244 0x276F +250 0x2770 +249 0x2771 +255 0x2772 +253 0x2773 +245 0x281B +169 0x281C + +#ML Mobiles + +276 0x2D95 +277 0x2D96 diff --git a/Data/signs.cfg b/Data/signs.cfg new file mode 100644 index 0000000..9cd2534 --- /dev/null +++ b/Data/signs.cfg @@ -0,0 +1,509 @@ +0 3032 373 904 -1 #1016093 +0 2996 2769 976 0 #1016315 +0 3016 2634 2088 10 #1016095 +0 2991 2632 2102 10 #1016417 +0 3026 2666 2096 5 #1016082 +0 3025 2664 2192 4 #1016216 +0 2988 2706 2152 0 #1016138 +0 2996 2714 2104 0 #1016345 +0 3011 2688 2232 -4 #1016346 +0 3023 2712 2178 0 #1016083 +0 3019 2744 2248 -4 #1016217 +0 3084 2732 2192 0 #1023083 +0 3019 2840 873 0 #1016274 +0 2981 2840 878 0 #1016361 +0 3007 2840 801 0 #1016421 +0 3053 2864 731 0 #1016342 +0 3016 2857 856 0 #1016316 +0 3021 2860 801 0 #1016347 +0 3025 2848 929 0 #1016091 +0 3075 2856 910 0 #1016293 +0 3083 2896 673 0 #1016333 +0 2990 2894 664 0 #1016286 +0 3009 2888 721 0 #1016356 +0 3018 2905 720 0 #1016296 +0 3035 2904 737 0 #1016335 +0 2983 2904 794 0 #1016308 +0 3050 2919 680 0 #1016294 +0 2990 2912 680 0 #1016325 +0 2992 2913 808 0 #1016312 +0 2987 2928 852 0 #1016142 +0 3011 2916 905 0 #1016328 +0 2982 2969 624 0 #1016361 +0 3140 2958 712 0 #1016288 +0 2993 2952 929 0 #1016414 +0 3020 2977 640 0 #1016275 +0 2995 2976 875 0 #1016416 +0 3057 2976 817 0 #1016305 +0 3013 3000 833 0 #1016326 +0 2994 2993 824 0 #1016327 +0 2980 2995 768 0 #1016373 +0 2985 3000 777 0 #1016289 +0 3025 3024 777 0 #1016120 +0 3084 2890 3479 15 #1023083 +0 2981 2888 3502 10 #1016256 +0 2986 2909 3496 10 #1016244 +0 2999 2912 3517 10 #1016249 +0 2984 2931 3512 10 #1016390 +0 2995 2976 3406 15 #1016285 +0 2988 2994 3440 15 #1016246 +0 2990 3005 3360 15 #1016247 +0 2980 2977 3360 15 #1016220 +0 3007 3024 3430 15 #1016248 +0 3019 3016 3386 15 #1016268 +0 3014 3009 3360 15 #1016077 +0 3053 3054 3408 15 #1016245 +0 3006 3053 3376 15 #1016255 +0 3025 3561 1174 9 #1016199 +0 2985 3554 1175 0 #1016204 +0 3006 3551 1194 0 #1016203 +0 3026 3551 1178 0 #1016205 +0 3016 3551 1186 0 #1016202 +0 3015 3554 1199 0 #1016224 +0 2997 3704 1213 0 #1016239 +0 3004 3743 1207 0 #1016057 +0 2993 3720 1224 0 #1022993 +0 2995 3740 1314 0 #1016232 +0 2987 3720 1380 0 #1016099 +0 3025 3732 1394 0 #1016198 +0 3085 3753 1240 14 #1016201 +0 3012 3748 1256 0 #1016357 +0 2981 3784 1264 0 #1016271 +0 3011 3784 1231 0 #1016192 +0 3026 3776 1196 0 #1016091 +0 3010 3778 1176 0 #1016153 +# 2 2979 3632 2537 0 The Shakin' Bakery +# 2 2982 3680 2480 0 A Stitch in Time Tailor Shop +# 2 2985 3720 2650 20 The Prime Cut Butcher Shop +# 2 2988 3658 2585 0 The Healers of Haven +# 2 2989 3632 2577 19 The Little Shop of Magic +# 2 2992 3646 2512 0 Carpenters of Haven +# 2 2996 3670 2624 0 The Bountiful Harvest Inn +# 2 2998 3634 2640 0 Mapmakers of Haven +# 2 3012 3665 2657 4 The Albatross Bar and Grill +# 2 3015 3645 2609 0 The Haven Blacksmith +# 2 3020 3666 2600 0 #1016162 +# 2 3025 3613 2585 0 Uzeraan's mansion +# 2 3026 3666 2512 0 Haven Clockworks and Tinker Shop +# 2 3026 3690 2520 0 The Haven Thieves' Guild +# 2 3036 3658 2536 0 #1016057 +# 2 3083 3624 2610 2 The Second Bank of Haven +# 2 2966 3617 2480 0 Haven Public Library +1 3025 3608 2609 0 #1016061 +1 2980 3602 2584 0 #1016197 +1 3049 3632 2537 0 #1023049 +1 3018 3646 2512 0 #1016211 +1 2966 3617 2480 0 #1016207 +1 2994 3634 2648 0 #1016042 +1 2988 3625 2616 0 #1016140 +1 3020 3634 2584 0 #1016162 +0 3053 3673 2138 24 #1016171 +0 3009 3673 2184 30 #1016300 +0 2981 3672 2232 20 #1016263 +0 2998 3669 2261 20 #1016307 +1 3036 3658 2536 0 #1016057 +1 3004 3675 2480 0 #1016115 +1 3012 3665 2657 4 #1016276 +1 2996 3670 2624 0 #1016283 +1 3016 3647 2600 0 #1016132 +1 2982 3656 2592 0 #1016022 +0 2995 3704 2167 20 #1016362 +0 2980 3681 2176 20 #1016284 +0 2988 3685 2231 20 #1016139 +0 3060 3682 2261 20 #1016121 +# 1 3084 3690 2520 0 #1016054 +0 3084 3728 2160 20 #1016051 +0 3026 3720 2184 20 #1016091 +0 2989 3712 2215 20 #1016173 +0 3011 3736 2230 20 #1016128 +0 3081 3712 2242 20 #1016178 +1 2985 3720 2650 20 #1016270 +0 2980 3753 2232 20 #1016049 +0 3048 4548 873 37 #1016107 +0 2992 4414 1096 0 #1016502 +0 2980 4390 1072 0 #1016165 +0 2988 4396 1088 0 #1016185 +0 3007 4400 1115 0 #1016331 +0 2985 4400 1132 0 #1016497 +0 2996 4407 1168 0 #1016354 +0 3014 4419 1136 0 #1016146 +0 3013 4424 1108 0 #1016186 +0 3019 4424 1062 0 #1016506 +0 3008 4436 1168 0 #1016241 +0 3026 4477 1130 0 #1016091 +0 3026 4478 1092 0 #1016111 +0 2982 4459 1072 0 #1016238 +0 2990 4451 1096 0 #1016188 +0 3084 4469 1176 0 #1016116 +0 2996 4483 1072 0 #1016187 +0 3017 4528 1069 0 #1016184 +0 3025 4537 1376 23 #1016076 +0 3026 4518 1402 21 #1016076 +0 3026 4308 1012 0 #1016324 +0 3051 4632 1200 0 #1016149 +0 3025 520 986 0 #1016367 +0 3026 547 832 0 #1016434 +0 2987 544 970 0 #1016143 +0 2985 544 1008 0 #1016436 +0 2979 557 1000 0 #1016317 +0 3022 563 976 0 #1016364 +0 2991 576 1009 0 #1016067 +0 3026 636 856 5 #1016106 +0 3025 624 886 2 #1016432 +0 3026 616 984 0 #1016091 +0 3011 568 2177 0 #1016355 +0 3084 595 2152 0 #1016055 +0 3055 576 2145 0 #1016229 +0 3007 592 2170 0 #1016189 +0 3024 578 2128 0 #1016060 +0 2986 582 2192 0 #1016069 +0 3022 593 2216 0 #1016066 +0 3019 592 2225 0 #1016266 +0 3021 600 2209 0 #1016066 +0 2985 592 2185 0 #1016069 +0 3023 576 2209 0 #1016258 +0 2992 633 2168 0 #1016084 +0 3026 617 2144 0 #1016091 +0 3023 616 2154 0 #1016111 +0 3024 610 2168 0 #1016111 +0 2997 608 2273 0 #1016267 +0 2995 616 2232 0 #1016299 +0 2988 621 2224 0 #1016141 +0 3015 632 2185 0 #1016208 +0 2990 609 2184 0 #1016168 +0 3008 648 2168 0 #1016127 +0 2990 656 2144 0 #1016191 +0 2982 648 2192 0 #1016251 +0 2989 5305 94 19 #1016277 +0 2995 5204 4060 37 #1016278 +0 3020 5217 4019 48 #1016365 +0 3016 5228 4008 37 #1016439 +0 3084 5270 3988 36 #1016430 +0 2989 5291 3982 37 #1016148 +0 3000 5304 3997 37 #1016262 +0 3084 5674 3139 10 #1016431 +0 3009 5671 3148 21 #1016264 +0 2999 5678 3286 10 #1016261 +0 2991 5703 3210 10 #1016290 +0 3013 5720 3205 19 #1016348 +0 2986 5698 3289 24 #1016360 +0 2980 5744 3209 16 #1016193 +0 2987 5740 3216 6 #1016313 +0 2990 5730 3204 19 #1016403 +0 2984 5729 3250 26 #1016391 +0 3019 5740 3267 13 #1016036 +0 2996 5774 3175 20 #1016318 +0 2994 5804 3282 16 #1016215 +0 3007 5802 3287 13 #1016349 +0 2999 1306 1761 25 #1016260 +0 3076 1342 1744 20 #1023075 +0 3008 1370 1584 30 #1016322 +0 3053 1360 1776 15 #1016072 +0 3000 1386 1664 30 #1016262 +0 3073 1432 1656 10 #1016369 +0 2992 1433 1600 20 #1016353 +0 3025 1420 1595 30 #1016071 +0 3054 1425 1584 30 #1016332 +0 7977 1421 1638 50 #1016221 +0 7977 1470 1643 34 #1016503 +0 7977 1480 1643 34 #1016503 +0 7977 1570 1526 46 #1016499 +0 7977 1539 1527 45 #1016505 +0 4762 1459 1622 35 #1016419 +0 4764 1428 1622 32 #1016419 +0 4762 1489 1627 34 #1016419 +0 4765 1428 1622 37 #1016504 +0 3015 1428 1546 30 #1016311 +0 3084 1436 1693 0 #1016302 +0 2997 1424 1747 10 #1016340 +0 3011 1432 1730 20 #1016291 +0 3008 1446 1654 10 #1016145 +0 2979 1460 1610 20 #1016126 +0 3086 1454 1600 20 #1016320 +0 3086 1441 1584 20 #1016320 +0 3023 1440 1611 20 #1016280 +0 3004 1454 1561 30 #1016163 +0 3009 1458 1683 0 #1016222 +0 2982 1470 1696 0 #1016323 +0 3020 1468 1676 0 #1016073 +0 2986 1449 1728 1 #1016295 +0 3070 1444 1670 10 #1016046 +0 2996 1474 1520 20 #1016338 +0 2987 1480 1610 20 #1016137 +0 2996 1501 1627 25 #1016269 +0 3007 1489 1587 32 #1016265 +0 2990 1488 1572 30 #1016359 +0 3022 1472 1584 20 #1016225 +0 3082 1477 1600 20 #1016178 +0 3011 1502 1689 20 #1016281 +0 2966 1493 1724 5 #1016304 +0 2993 1480 1746 0 #1022993 +0 3013 1508 1662 20 #1016110 +0 3026 1505 1576 20 #1016074 +0 3000 1516 1553 36 #1016287 +0 3083 1328 3771 0 #1016155 +0 2995 1368 3829 0 #1016334 +0 2981 1360 3786 0 #1016038 +0 3007 1368 3752 0 #1016098 +0 3008 1362 3768 0 #1016098 +0 3033 1368 3713 0 #1016080 +0 2979 1368 3733 0 #1016049 +0 3026 1391 3832 0 #1016111 +0 3025 1400 3825 0 #1016111 +0 2995 1376 3814 0 #1016334 +0 2965 1400 3769 0 #1016158 +0 3016 1385 3712 0 #1016117 +0 3026 1425 3704 0 #1016091 +0 2992 1425 3824 0 #1016122 +0 2984 1411 3808 0 #1016123 +0 3020 1434 3800 0 #1016194 +0 3012 1433 3776 0 #1016314 +0 2988 1409 3792 0 #1016157 +0 3015 1424 3859 0 #1016420 +0 2990 1427 3993 10 #1016159 +0 2998 1449 3752 0 #1016237 +0 3007 1448 3721 0 #1016242 +0 3059 1440 3746 0 #1016206 +0 3007 1448 3721 0 #1016242 +0 3029 1440 3864 0 #1016133 +0 3008 1449 3864 0 #1016154 +0 3007 1464 3849 0 #1016154 +0 3010 1443 3993 10 #1016343 +0 2985 1464 4024 0 #1016114 +0 2982 1458 4008 0 #1016038 +0 3085 1441 4010 10 #1016214 +0 3008 1472 3872 0 #1016085 +0 2982 1555 1665 37 #1016350 +0 3012 1549 1776 10 #1016374 +0 3077 1592 1562 20 #1016089 +0 2990 1590 1665 22 #1016151 +0 3024 1575 1721 46 #1016236 +0 3007 1640 1688 32 #1016045 +0 3026 1505 1528 40 #1016091 +0 3026 1376 3752 0 #1016156 +0 3025 624 2112 0 #1016091 +0 2992 561 1016 0 #1016067 +0 3012 2970 3432 15 #1016298 +0 3026 3019 768 0 #1016111 +0 3025 2863 989 0 #1016272 +0 3050 4686 1423 0 #1023050 +0 2999 3043 3463 25 #1016249 +0 3012 3011 3464 15 #1016119 +0 3025 2968 3367 15 #1016091 +0 2984 3712 2136 20 #1016368 +0 7977 1614 1636 40 #1016104 +0 7976 1400 1622 50 #1016088 +0 7976 1400 1630 50 #1016047 +0 7976 1495 1643 35 #1016250 +0 7976 1495 1640 35 #1016226 +0 4764 1584 1527 56 #1016500 +0 4765 1584 1527 52 #1016233 +0 4765 1546 1624 23 #1016233 +0 4764 1546 1624 27 #1016233 +0 4759 1565 1584 43 #1016233 +0 4766 1532 1705 35 #1016233 +0 4761 1537 1668 35 #1016233 +0 4762 1561 1670 36 #1016233 +0 4765 1566 1678 35 #1016233 +0 4759 1559 1695 45 #1016233 +0 4766 1599 1571 36 #1016233 +0 4761 1599 1571 33 #1016233 +0 4761 1572 1600 29 #1016233 +0 4765 1595 1678 22 #1016059 +0 4759 1595 1678 25 #1016059 +0 4762 1617 1679 35 #1016059 +0 4764 1562 1720 50 #1016059 +0 4765 1664 1592 15 #1016059 +0 4765 1676 1625 10 #1016059 +0 4759 1640 1680 33 #1016059 +0 4765 1667 1559 38 #1016059 +0 4765 1664 1574 20 #1016059 +0 4766 1558 1753 30 #1016059 +0 4762 1552 1728 37 #1016310 +0 4765 1552 1728 34 #1016310 +0 4765 1532 1705 33 #1016310 +0 4765 1485 1709 15 #1016310 +0 4761 1488 1731 15 #1016310 +0 4764 1468 1732 15 #1016310 +0 4764 1441 1732 19 #1016310 +0 4764 1415 1736 25 #1016310 +0 4761 1415 1736 31 #1016504 +0 4765 1424 1701 18 #1016504 +0 4765 1422 1672 25 #1016504 +0 4766 1439 1585 35 #1016504 +0 4765 1435 1570 45 #1016504 +0 4765 1432 1538 47 #1016504 +0 4764 1432 1538 42 #1016500 +0 4765 1498 1536 46 #1016500 +0 4764 1519 1525 55 #1016500 +0 4762 1362 1756 30 #1016396 +0 4764 1362 1756 23 #1016393 +0 4761 1375 1811 18 #1016393 +0 4759 1355 1835 16 #1016393 +0 4761 1392 1892 9 #1016393 +0 4764 1314 1749 26 #1016393 +0 4764 1262 1742 9 #1016393 +0 7976 1580 2484 4 Only a mind at peace can approach the shrine +0 7976 1604 2484 7 A calm mind may travel where others may not tread +0 4762 1262 1742 15 #1016401 +0 4766 1262 1742 12 #1016398 +0 4764 1392 1892 13 #1016402 +0 4765 1392 1892 18 #1016398 +0 4765 1355 1835 16 #1016398 +0 4766 1375 1811 14 #1016398 +0 4765 1362 1756 27 #1016398 +0 4764 1643 1521 50 #1016394 +0 3025 1557 1613 21 #1016292 +0 2995 1600 1589 20 #1016377 +0 3012 1610 1592 0 #1016352 +0 3024 1619 1769 70 #1016376 +0 3020 1602 1720 20 #1016223 +0 3010 1660 1648 0 #1016018 +0 3011 1632 1586 0 #1016352 +0 3026 1634 1673 26 #1016091 +0 3083 1819 2825 0 #1016050 +0 3024 1850 2777 0 #1016152 +0 2996 1841 2744 0 #1016371 +0 2999 1828 2743 0 #1016408 +0 2989 1852 2709 10 #1016107 +0 3074 1855 2688 0 #1016392 +0 3074 1844 2688 0 #1016392 +0 3020 1851 2800 -8 #1016078 +0 2980 1881 2814 6 #1016048 +0 3008 1899 2664 0 #1016252 +0 3083 1904 2686 10 #1016407 +0 3025 1912 2713 20 #1016406 +0 2988 1914 2813 0 #1016405 +0 3010 1901 2814 0 #1016344 +0 3026 1896 2842 20 #1016091 +0 3016 1933 2776 10 #1016147 +0 3075 1942 2736 10 #1016079 +0 3023 1939 2701 30 #1016179 +0 3024 1938 2694 20 #1016058 +0 3024 1947 2691 30 #1016058 +0 3011 1942 2791 0 #1016319 +0 3024 1959 2695 20 #1016058 +0 2966 2002 2728 30 #1016212 +0 3000 2005 2813 -1 #1016118 +0 2982 1986 2846 15 #1016037 +0 3023 1997 2864 10 #1016404 +0 2985 2000 2888 5 #1016372 +0 2996 2030 2813 9 #1016351 +0 3059 2037 2843 0 #1016259 +0 3023 2221 1193 4 #1016112 +0 3007 2224 1165 0 #1016375 +0 3083 2232 1199 0 Bank of Cove +0 2987 2248 1227 0 #1016313 +0 3024 2428 536 0 #1016181 +0 3053 2459 492 15 #1016329 +0 3020 2459 432 15 #1016341 +0 2986 2442 416 15 #1016358 +0 3003 2432 555 0 #1016336 +0 2984 2472 458 15 #1016124 +0 3076 2482 440 15 #1016337 +0 3012 2474 405 15 #1016279 +0 3008 2525 578 0 #1016422 +0 3000 2521 379 23 #1016262 +0 2992 2510 482 15 #1016339 +0 3028 2500 440 15 #1016309 +0 3026 2523 536 0 #1016363 +0 2988 2576 603 0 #1016313 +0 3084 2505 560 0 #1016052 +0 3020 2534 560 0 #1016366 +0 3016 2470 569 5 #1016306 +0 3076 2016 2753 30 #1016409 +0 3022 618 1152 0 #1016129 +0 2998 626 1040 0 #1016130 +0 3083 3768 1313 0 #1016053 +0 3024 5351 64 15 #1016164 +0 2987 5267 131 20 #1016425 +0 2965 5250 184 22 #1016240 +0 2966 5236 155 15 #1016321 +0 2995 5222 183 8 #1016427 +0 3014 5217 124 0 #1016170 +0 2982 5200 98 5 #1016426 +0 2995 5168 35 22 #1016243 +0 3019 5158 107 5 #1016169 +0 2990 5152 77 28 #1016424 +0 3056 745 2160 0 #1016229 +4 3083 996 517 -50 #1061816 +4 3015 981 511 -50 #1061813 +4 2981 981 526 -50 #1061814 +4 2990 1000 523 -50 #1061818 +4 2992 1001 518 -50 #1061817 +4 3020 994 509 -50 #1061815 +4 2995 1005 522 -30 #1061819 +4 3000 1021 505 -70 #1061820 +4 3015 1997 1369 -87 #1061800 +4 3000 1994 1326 -91 #1061804 +4 3020 2014 1338 -76 #1061809 +4 2979 2023 1347 -90 #1061810 +4 3011 2030 1348 -89 #1061807 +4 2989 2038 1385 -88 #1061799 +4 3009 2055 1390 -90 #1061802 +4 3083 2056 1338 -85 #1061803 +4 2995 2047 1312 -90 #1061808 +4 2992 2069 1298 -81 #1061805 +4 2982 2075 1339 -82 #1061801 +4 2988 2085 1379 -90 #1061806 +4 2995 1067 1431 -88 #1061616 +4 3011 962 641 -90 #1061835 +4 2979 962 633 -90 #1061836 +3 2965 860 654 -39 Librum +3 2965 877 654 -39 Librum +3 2965 861 632 -34 Librum +3 2965 865 632 -34 Librum +3 2965 873 632 -34 Librum +3 2965 877 632 -34 Librum +3 2981 882 616 -34 Skis-In-Lem +3 2981 886 616 -34 Skis-In-Lem +3 2984 780 638 1 Atri-Ben-In-Ailem +3 2984 780 646 1 Atri-Ben-In-Ailem +3 2987 858 592 -33 In-Mani-Lem +3 2987 862 592 -33 In-Mani-Lem +3 2990 837 582 1 Ter-Ort-Lem +3 2995 836 703 1 Ter-Zu +3 2995 845 703 1 Ter-Zu +3 3007 817 694 -38 Aglo-In-Lem +3 3007 822 694 -38 Aglo-In-Lem +3 3007 819 592 -34 Agra-Char-In-Lem +3 3007 823 592 -34 Agra-Char-In-Lem +3 3008 814 596 -34 Agra-Char-In-Lem +3 3008 814 600 -34 Agra-Char-In-Lem +3 3008 814 685 -34 Aglo-In-Lem +3 3008 814 689 -34 Aglo-In-Lem +3 3009 858 694 -39 Klar-Lap-In-Lem +3 3009 863 694 -39 Klar-Lap-In-Lem +3 3015 788 655 1 Zhel-In-Lem +3 3015 796 655 1 Zhel-In-Lem +3 3019 830 678 -39 Ben-In-Lem +3 3019 835 678 -39 Ben-In-Lem +3 3019 831 608 -34 Ben-In-Lem +3 3019 835 608 -34 Ben-In-Lem +3 3025 788 630 1 Lap-In-Lem +3 3025 796 630 1 Lap-In-Lem +3 3025 881 670 -39 Ter-An-Eks-Por +3 3025 886 670 -39 Ter-An-Eks-Por +3 3083 845 678 -39 Atri-Aur +3 3083 850 678 -39 Atri-Aur +3 3083 846 608 -34 Atri-Aur +3 3083 850 608 -34 Atri-Aur +3 3140 868 684 -39 Lap-In-Lem +3 3140 868 689 -39 Lap-In-Lem +3 2996 787 1137 -13 #1016183 +5 2996 677 1220 25 #1063398 +5 3012 694 1229 25 #1063399 +5 2966 675 1280 32 #1063400 +5 2966 680 1280 32 #1063400 +5 2989 707 1300 25 #1063401 +5 3010 718 1301 25 #1063402 +5 5019 736 1281 25 #1063403 +5 3025 768 1298 25 #1063404 +5 3021 789 1302 25 #1063405 +5 3000 790 1284 25 #1063406 +5 3016 764 1255 25 #1063407 +5 2988 780 1227 25 #1063408 +5 3024 729 1229 25 #1063409 +5 3025 710 1251 25 #1063410 +5 3025 710 1257 25 #1063410 +5 3025 710 1270 25 #1063410 \ No newline at end of file diff --git a/Data/signs.cfg.bak b/Data/signs.cfg.bak new file mode 100644 index 0000000..f1832f5 --- /dev/null +++ b/Data/signs.cfg.bak @@ -0,0 +1,509 @@ +0 3032 373 904 -1 #1016093 +0 2996 2769 976 0 #1016315 +0 3016 2634 2088 10 #1016095 +0 2991 2632 2102 10 #1016417 +0 3026 2666 2096 5 #1016082 +0 3025 2664 2192 4 #1016216 +0 2988 2706 2152 0 #1016138 +0 2996 2714 2104 0 #1016345 +0 3011 2688 2232 -4 #1016346 +0 3023 2712 2178 0 #1016083 +0 3019 2744 2248 -4 #1016217 +0 3084 2732 2192 0 #1023083 +0 3019 2840 873 0 #1016274 +0 2981 2840 878 0 #1016361 +0 3007 2840 801 0 #1016421 +0 3053 2864 731 0 #1016342 +0 3016 2857 856 0 #1016316 +0 3021 2860 801 0 #1016347 +0 3025 2848 929 0 #1016091 +0 3075 2856 910 0 #1016293 +0 3083 2896 673 0 #1016333 +0 2990 2894 664 0 #1016286 +0 3009 2888 721 0 #1016356 +0 3018 2905 720 0 #1016296 +0 3035 2904 737 0 #1016335 +0 2983 2904 794 0 #1016308 +0 3050 2919 680 0 #1016294 +0 2990 2912 680 0 #1016325 +0 2992 2913 808 0 #1016312 +0 2987 2928 852 0 #1016142 +0 3011 2916 905 0 #1016328 +0 2982 2969 624 0 #1016361 +0 3140 2958 712 0 #1016288 +0 2993 2952 929 0 #1016414 +0 3020 2977 640 0 #1016275 +0 2995 2976 875 0 #1016416 +0 3057 2976 817 0 #1016305 +0 3013 3000 833 0 #1016326 +0 2994 2993 824 0 #1016327 +0 2980 2995 768 0 #1016373 +0 2985 3000 777 0 #1016289 +0 3025 3024 777 0 #1016120 +0 3084 2890 3479 15 #1023083 +0 2981 2888 3502 10 #1016256 +0 2986 2909 3496 10 #1016244 +0 2999 2912 3517 10 #1016249 +0 2984 2931 3512 10 #1016390 +0 2995 2976 3406 15 #1016285 +0 2988 2994 3440 15 #1016246 +0 2990 3005 3360 15 #1016247 +0 2980 2977 3360 15 #1016220 +0 3007 3024 3430 15 #1016248 +0 3019 3016 3386 15 #1016268 +0 3014 3009 3360 15 #1016077 +0 3053 3054 3408 15 #1016245 +0 3006 3053 3376 15 #1016255 +0 3025 3561 1174 9 #1016199 +0 2985 3554 1175 0 #1016204 +0 3006 3551 1194 0 #1016203 +0 3026 3551 1178 0 #1016205 +0 3016 3551 1186 0 #1016202 +0 3015 3554 1199 0 #1016224 +0 2997 3704 1213 0 #1016239 +0 3004 3743 1207 0 #1016057 +0 2993 3720 1224 0 #1022993 +0 2995 3740 1314 0 #1016232 +0 2987 3720 1380 0 #1016099 +0 3025 3732 1394 0 #1016198 +0 3085 3753 1240 14 #1016201 +0 3012 3748 1256 0 #1016357 +0 2981 3784 1264 0 #1016271 +0 3011 3784 1231 0 #1016192 +0 3026 3776 1196 0 #1016091 +0 3010 3778 1176 0 #1016153 +2 2979 3632 2537 0 The Shakin' Bakery +2 2982 3680 2480 0 A Stitch in Time Tailor Shop +2 2985 3720 2650 20 The Prime Cut Butcher Shop +2 2988 3658 2585 0 The Healers of Haven +2 2989 3632 2577 19 The Little Shop of Magic +2 2992 3646 2512 0 Carpenters of Haven +2 2996 3670 2624 0 The Bountiful Harvest Inn +2 2998 3634 2640 0 Mapmakers of Haven +2 3012 3665 2657 4 The Albatross Bar and Grill +2 3015 3645 2609 0 The Haven Blacksmith +2 3020 3666 2600 0 #1016162 +2 3025 3613 2585 0 Uzeraan's mansion +2 3026 3666 2512 0 Haven Clockworks and Tinker Shop +2 3026 3690 2520 0 The Haven Thieves' Guild +2 3036 3658 2536 0 #1016057 +2 3083 3624 2610 2 The Second Bank of Haven +2 2966 3617 2480 0 Haven Public Library +1 3025 3608 2609 0 #1016061 +1 2980 3602 2584 0 #1016197 +1 3049 3632 2537 0 #1023049 +1 3018 3646 2512 0 #1016211 +1 2966 3617 2480 0 #1016207 +1 2994 3634 2648 0 #1016042 +1 2988 3625 2616 0 #1016140 +1 3020 3634 2584 0 #1016162 +0 3053 3673 2138 24 #1016171 +0 3009 3673 2184 30 #1016300 +0 2981 3672 2232 20 #1016263 +0 2998 3669 2261 20 #1016307 +1 3036 3658 2536 0 #1016057 +1 3004 3675 2480 0 #1016115 +1 3012 3665 2657 4 #1016276 +1 2996 3670 2624 0 #1016283 +1 3016 3647 2600 0 #1016132 +1 2982 3656 2592 0 #1016022 +0 2995 3704 2167 20 #1016362 +0 2980 3681 2176 20 #1016284 +0 2988 3685 2231 20 #1016139 +0 3060 3682 2261 20 #1016121 +1 3084 3690 2520 0 #1016054 +0 3084 3728 2160 20 #1016051 +0 3026 3720 2184 20 #1016091 +0 2989 3712 2215 20 #1016173 +0 3011 3736 2230 20 #1016128 +0 3081 3712 2242 20 #1016178 +1 2985 3720 2650 20 #1016270 +0 2980 3753 2232 20 #1016049 +0 3048 4548 873 37 #1016107 +0 2992 4414 1096 0 #1016502 +0 2980 4390 1072 0 #1016165 +0 2988 4396 1088 0 #1016185 +0 3007 4400 1115 0 #1016331 +0 2985 4400 1132 0 #1016497 +0 2996 4407 1168 0 #1016354 +0 3014 4419 1136 0 #1016146 +0 3013 4424 1108 0 #1016186 +0 3019 4424 1062 0 #1016506 +0 3008 4436 1168 0 #1016241 +0 3026 4477 1130 0 #1016091 +0 3026 4478 1092 0 #1016111 +0 2982 4459 1072 0 #1016238 +0 2990 4451 1096 0 #1016188 +0 3084 4469 1176 0 #1016116 +0 2996 4483 1072 0 #1016187 +0 3017 4528 1069 0 #1016184 +0 3025 4537 1376 23 #1016076 +0 3026 4518 1402 21 #1016076 +0 3026 4308 1012 0 #1016324 +0 3051 4632 1200 0 #1016149 +0 3025 520 986 0 #1016367 +0 3026 547 832 0 #1016434 +0 2987 544 970 0 #1016143 +0 2985 544 1008 0 #1016436 +0 2979 557 1000 0 #1016317 +0 3022 563 976 0 #1016364 +0 2991 576 1009 0 #1016067 +0 3026 636 856 5 #1016106 +0 3025 624 886 2 #1016432 +0 3026 616 984 0 #1016091 +0 3011 568 2177 0 #1016355 +0 3084 595 2152 0 #1016055 +0 3055 576 2145 0 #1016229 +0 3007 592 2170 0 #1016189 +0 3024 578 2128 0 #1016060 +0 2986 582 2192 0 #1016069 +0 3022 593 2216 0 #1016066 +0 3019 592 2225 0 #1016266 +0 3021 600 2209 0 #1016066 +0 2985 592 2185 0 #1016069 +0 3023 576 2209 0 #1016258 +0 2992 633 2168 0 #1016084 +0 3026 617 2144 0 #1016091 +0 3023 616 2154 0 #1016111 +0 3024 610 2168 0 #1016111 +0 2997 608 2273 0 #1016267 +0 2995 616 2232 0 #1016299 +0 2988 621 2224 0 #1016141 +0 3015 632 2185 0 #1016208 +0 2990 609 2184 0 #1016168 +0 3008 648 2168 0 #1016127 +0 2990 656 2144 0 #1016191 +0 2982 648 2192 0 #1016251 +0 2989 5305 94 19 #1016277 +0 2995 5204 4060 37 #1016278 +0 3020 5217 4019 48 #1016365 +0 3016 5228 4008 37 #1016439 +0 3084 5270 3988 36 #1016430 +0 2989 5291 3982 37 #1016148 +0 3000 5304 3997 37 #1016262 +0 3084 5674 3139 10 #1016431 +0 3009 5671 3148 21 #1016264 +0 2999 5678 3286 10 #1016261 +0 2991 5703 3210 10 #1016290 +0 3013 5720 3205 19 #1016348 +0 2986 5698 3289 24 #1016360 +0 2980 5744 3209 16 #1016193 +0 2987 5740 3216 6 #1016313 +0 2990 5730 3204 19 #1016403 +0 2984 5729 3250 26 #1016391 +0 3019 5740 3267 13 #1016036 +0 2996 5774 3175 20 #1016318 +0 2994 5804 3282 16 #1016215 +0 3007 5802 3287 13 #1016349 +0 2999 1306 1761 25 #1016260 +0 3076 1342 1744 20 #1023075 +0 3008 1370 1584 30 #1016322 +0 3053 1360 1776 15 #1016072 +0 3000 1386 1664 30 #1016262 +0 3073 1432 1656 10 #1016369 +0 2992 1433 1600 20 #1016353 +0 3025 1420 1595 30 #1016071 +0 3054 1425 1584 30 #1016332 +0 7977 1421 1638 50 #1016221 +0 7977 1470 1643 34 #1016503 +0 7977 1480 1643 34 #1016503 +0 7977 1570 1526 46 #1016499 +0 7977 1539 1527 45 #1016505 +0 4762 1459 1622 35 #1016419 +0 4764 1428 1622 32 #1016419 +0 4762 1489 1627 34 #1016419 +0 4765 1428 1622 37 #1016504 +0 3015 1428 1546 30 #1016311 +0 3084 1436 1693 0 #1016302 +0 2997 1424 1747 10 #1016340 +0 3011 1432 1730 20 #1016291 +0 3008 1446 1654 10 #1016145 +0 2979 1460 1610 20 #1016126 +0 3086 1454 1600 20 #1016320 +0 3086 1441 1584 20 #1016320 +0 3023 1440 1611 20 #1016280 +0 3004 1454 1561 30 #1016163 +0 3009 1458 1683 0 #1016222 +0 2982 1470 1696 0 #1016323 +0 3020 1468 1676 0 #1016073 +0 2986 1449 1728 1 #1016295 +0 3070 1444 1670 10 #1016046 +0 2996 1474 1520 20 #1016338 +0 2987 1480 1610 20 #1016137 +0 2996 1501 1627 25 #1016269 +0 3007 1489 1587 32 #1016265 +0 2990 1488 1572 30 #1016359 +0 3022 1472 1584 20 #1016225 +0 3082 1477 1600 20 #1016178 +0 3011 1502 1689 20 #1016281 +0 2966 1493 1724 5 #1016304 +0 2993 1480 1746 0 #1022993 +0 3013 1508 1662 20 #1016110 +0 3026 1505 1576 20 #1016074 +0 3000 1516 1553 36 #1016287 +0 3083 1328 3771 0 #1016155 +0 2995 1368 3829 0 #1016334 +0 2981 1360 3786 0 #1016038 +0 3007 1368 3752 0 #1016098 +0 3008 1362 3768 0 #1016098 +0 3033 1368 3713 0 #1016080 +0 2979 1368 3733 0 #1016049 +0 3026 1391 3832 0 #1016111 +0 3025 1400 3825 0 #1016111 +0 2995 1376 3814 0 #1016334 +0 2965 1400 3769 0 #1016158 +0 3016 1385 3712 0 #1016117 +0 3026 1425 3704 0 #1016091 +0 2992 1425 3824 0 #1016122 +0 2984 1411 3808 0 #1016123 +0 3020 1434 3800 0 #1016194 +0 3012 1433 3776 0 #1016314 +0 2988 1409 3792 0 #1016157 +0 3015 1424 3859 0 #1016420 +0 2990 1427 3993 10 #1016159 +0 2998 1449 3752 0 #1016237 +0 3007 1448 3721 0 #1016242 +0 3059 1440 3746 0 #1016206 +0 3007 1448 3721 0 #1016242 +0 3029 1440 3864 0 #1016133 +0 3008 1449 3864 0 #1016154 +0 3007 1464 3849 0 #1016154 +0 3010 1443 3993 10 #1016343 +0 2985 1464 4024 0 #1016114 +0 2982 1458 4008 0 #1016038 +0 3085 1441 4010 10 #1016214 +0 3008 1472 3872 0 #1016085 +0 2982 1555 1665 37 #1016350 +0 3012 1549 1776 10 #1016374 +0 3077 1592 1562 20 #1016089 +0 2990 1590 1665 22 #1016151 +0 3024 1575 1721 46 #1016236 +0 3007 1640 1688 32 #1016045 +0 3026 1505 1528 40 #1016091 +0 3026 1376 3752 0 #1016156 +0 3025 624 2112 0 #1016091 +0 2992 561 1016 0 #1016067 +0 3012 2970 3432 15 #1016298 +0 3026 3019 768 0 #1016111 +0 3025 2863 989 0 #1016272 +0 3050 4686 1423 0 #1023050 +0 2999 3043 3463 25 #1016249 +0 3012 3011 3464 15 #1016119 +0 3025 2968 3367 15 #1016091 +0 2984 3712 2136 20 #1016368 +0 7977 1614 1636 40 #1016104 +0 7976 1400 1622 50 #1016088 +0 7976 1400 1630 50 #1016047 +0 7976 1495 1643 35 #1016250 +0 7976 1495 1640 35 #1016226 +0 4764 1584 1527 56 #1016500 +0 4765 1584 1527 52 #1016233 +0 4765 1546 1624 23 #1016233 +0 4764 1546 1624 27 #1016233 +0 4759 1565 1584 43 #1016233 +0 4766 1532 1705 35 #1016233 +0 4761 1537 1668 35 #1016233 +0 4762 1561 1670 36 #1016233 +0 4765 1566 1678 35 #1016233 +0 4759 1559 1695 45 #1016233 +0 4766 1599 1571 36 #1016233 +0 4761 1599 1571 33 #1016233 +0 4761 1572 1600 29 #1016233 +0 4765 1595 1678 22 #1016059 +0 4759 1595 1678 25 #1016059 +0 4762 1617 1679 35 #1016059 +0 4764 1562 1720 50 #1016059 +0 4765 1664 1592 15 #1016059 +0 4765 1676 1625 10 #1016059 +0 4759 1640 1680 33 #1016059 +0 4765 1667 1559 38 #1016059 +0 4765 1664 1574 20 #1016059 +0 4766 1558 1753 30 #1016059 +0 4762 1552 1728 37 #1016310 +0 4765 1552 1728 34 #1016310 +0 4765 1532 1705 33 #1016310 +0 4765 1485 1709 15 #1016310 +0 4761 1488 1731 15 #1016310 +0 4764 1468 1732 15 #1016310 +0 4764 1441 1732 19 #1016310 +0 4764 1415 1736 25 #1016310 +0 4761 1415 1736 31 #1016504 +0 4765 1424 1701 18 #1016504 +0 4765 1422 1672 25 #1016504 +0 4766 1439 1585 35 #1016504 +0 4765 1435 1570 45 #1016504 +0 4765 1432 1538 47 #1016504 +0 4764 1432 1538 42 #1016500 +0 4765 1498 1536 46 #1016500 +0 4764 1519 1525 55 #1016500 +0 4762 1362 1756 30 #1016396 +0 4764 1362 1756 23 #1016393 +0 4761 1375 1811 18 #1016393 +0 4759 1355 1835 16 #1016393 +0 4761 1392 1892 9 #1016393 +0 4764 1314 1749 26 #1016393 +0 4764 1262 1742 9 #1016393 +0 7976 1580 2484 4 Only a mind at peace can approach the shrine +0 7976 1604 2484 7 A calm mind may travel where others may not tread +0 4762 1262 1742 15 #1016401 +0 4766 1262 1742 12 #1016398 +0 4764 1392 1892 13 #1016402 +0 4765 1392 1892 18 #1016398 +0 4765 1355 1835 16 #1016398 +0 4766 1375 1811 14 #1016398 +0 4765 1362 1756 27 #1016398 +0 4764 1643 1521 50 #1016394 +0 3025 1557 1613 21 #1016292 +0 2995 1600 1589 20 #1016377 +0 3012 1610 1592 0 #1016352 +0 3024 1619 1769 70 #1016376 +0 3020 1602 1720 20 #1016223 +0 3010 1660 1648 0 #1016018 +0 3011 1632 1586 0 #1016352 +0 3026 1634 1673 26 #1016091 +0 3083 1819 2825 0 #1016050 +0 3024 1850 2777 0 #1016152 +0 2996 1841 2744 0 #1016371 +0 2999 1828 2743 0 #1016408 +0 2989 1852 2709 10 #1016107 +0 3074 1855 2688 0 #1016392 +0 3074 1844 2688 0 #1016392 +0 3020 1851 2800 -8 #1016078 +0 2980 1881 2814 6 #1016048 +0 3008 1899 2664 0 #1016252 +0 3083 1904 2686 10 #1016407 +0 3025 1912 2713 20 #1016406 +0 2988 1914 2813 0 #1016405 +0 3010 1901 2814 0 #1016344 +0 3026 1896 2842 20 #1016091 +0 3016 1933 2776 10 #1016147 +0 3075 1942 2736 10 #1016079 +0 3023 1939 2701 30 #1016179 +0 3024 1938 2694 20 #1016058 +0 3024 1947 2691 30 #1016058 +0 3011 1942 2791 0 #1016319 +0 3024 1959 2695 20 #1016058 +0 2966 2002 2728 30 #1016212 +0 3000 2005 2813 -1 #1016118 +0 2982 1986 2846 15 #1016037 +0 3023 1997 2864 10 #1016404 +0 2985 2000 2888 5 #1016372 +0 2996 2030 2813 9 #1016351 +0 3059 2037 2843 0 #1016259 +0 3023 2221 1193 4 #1016112 +0 3007 2224 1165 0 #1016375 +0 3083 2232 1199 0 Bank of Cove +0 2987 2248 1227 0 #1016313 +0 3024 2428 536 0 #1016181 +0 3053 2459 492 15 #1016329 +0 3020 2459 432 15 #1016341 +0 2986 2442 416 15 #1016358 +0 3003 2432 555 0 #1016336 +0 2984 2472 458 15 #1016124 +0 3076 2482 440 15 #1016337 +0 3012 2474 405 15 #1016279 +0 3008 2525 578 0 #1016422 +0 3000 2521 379 23 #1016262 +0 2992 2510 482 15 #1016339 +0 3028 2500 440 15 #1016309 +0 3026 2523 536 0 #1016363 +0 2988 2576 603 0 #1016313 +0 3084 2505 560 0 #1016052 +0 3020 2534 560 0 #1016366 +0 3016 2470 569 5 #1016306 +0 3076 2016 2753 30 #1016409 +0 3022 618 1152 0 #1016129 +0 2998 626 1040 0 #1016130 +0 3083 3768 1313 0 #1016053 +0 3024 5351 64 15 #1016164 +0 2987 5267 131 20 #1016425 +0 2965 5250 184 22 #1016240 +0 2966 5236 155 15 #1016321 +0 2995 5222 183 8 #1016427 +0 3014 5217 124 0 #1016170 +0 2982 5200 98 5 #1016426 +0 2995 5168 35 22 #1016243 +0 3019 5158 107 5 #1016169 +0 2990 5152 77 28 #1016424 +0 3056 745 2160 0 #1016229 +4 3083 996 517 -50 #1061816 +4 3015 981 511 -50 #1061813 +4 2981 981 526 -50 #1061814 +4 2990 1000 523 -50 #1061818 +4 2992 1001 518 -50 #1061817 +4 3020 994 509 -50 #1061815 +4 2995 1005 522 -30 #1061819 +4 3000 1021 505 -70 #1061820 +4 3015 1997 1369 -87 #1061800 +4 3000 1994 1326 -91 #1061804 +4 3020 2014 1338 -76 #1061809 +4 2979 2023 1347 -90 #1061810 +4 3011 2030 1348 -89 #1061807 +4 2989 2038 1385 -88 #1061799 +4 3009 2055 1390 -90 #1061802 +4 3083 2056 1338 -85 #1061803 +4 2995 2047 1312 -90 #1061808 +4 2992 2069 1298 -81 #1061805 +4 2982 2075 1339 -82 #1061801 +4 2988 2085 1379 -90 #1061806 +4 2995 1067 1431 -88 #1061616 +4 3011 962 641 -90 #1061835 +4 2979 962 633 -90 #1061836 +3 2965 860 654 -39 Librum +3 2965 877 654 -39 Librum +3 2965 861 632 -34 Librum +3 2965 865 632 -34 Librum +3 2965 873 632 -34 Librum +3 2965 877 632 -34 Librum +3 2981 882 616 -34 Skis-In-Lem +3 2981 886 616 -34 Skis-In-Lem +3 2984 780 638 1 Atri-Ben-In-Ailem +3 2984 780 646 1 Atri-Ben-In-Ailem +3 2987 858 592 -33 In-Mani-Lem +3 2987 862 592 -33 In-Mani-Lem +3 2990 837 582 1 Ter-Ort-Lem +3 2995 836 703 1 Ter-Zu +3 2995 845 703 1 Ter-Zu +3 3007 817 694 -38 Aglo-In-Lem +3 3007 822 694 -38 Aglo-In-Lem +3 3007 819 592 -34 Agra-Char-In-Lem +3 3007 823 592 -34 Agra-Char-In-Lem +3 3008 814 596 -34 Agra-Char-In-Lem +3 3008 814 600 -34 Agra-Char-In-Lem +3 3008 814 685 -34 Aglo-In-Lem +3 3008 814 689 -34 Aglo-In-Lem +3 3009 858 694 -39 Klar-Lap-In-Lem +3 3009 863 694 -39 Klar-Lap-In-Lem +3 3015 788 655 1 Zhel-In-Lem +3 3015 796 655 1 Zhel-In-Lem +3 3019 830 678 -39 Ben-In-Lem +3 3019 835 678 -39 Ben-In-Lem +3 3019 831 608 -34 Ben-In-Lem +3 3019 835 608 -34 Ben-In-Lem +3 3025 788 630 1 Lap-In-Lem +3 3025 796 630 1 Lap-In-Lem +3 3025 881 670 -39 Ter-An-Eks-Por +3 3025 886 670 -39 Ter-An-Eks-Por +3 3083 845 678 -39 Atri-Aur +3 3083 850 678 -39 Atri-Aur +3 3083 846 608 -34 Atri-Aur +3 3083 850 608 -34 Atri-Aur +3 3140 868 684 -39 Lap-In-Lem +3 3140 868 689 -39 Lap-In-Lem +3 2996 787 1137 -13 #1016183 +5 2996 677 1220 25 #1063398 +5 3012 694 1229 25 #1063399 +5 2966 675 1280 32 #1063400 +5 2966 680 1280 32 #1063400 +5 2989 707 1300 25 #1063401 +5 3010 718 1301 25 #1063402 +5 5019 736 1281 25 #1063403 +5 3025 768 1298 25 #1063404 +5 3021 789 1302 25 #1063405 +5 3000 790 1284 25 #1063406 +5 3016 764 1255 25 #1063407 +5 2988 780 1227 25 #1063408 +5 3024 729 1229 25 #1063409 +5 3025 710 1251 25 #1063410 +5 3025 710 1257 25 #1063410 +5 3025 710 1270 25 #1063410 \ No newline at end of file diff --git a/Data/treasure.cfg b/Data/treasure.cfg new file mode 100644 index 0000000..a34abae --- /dev/null +++ b/Data/treasure.cfg @@ -0,0 +1,45 @@ +2946 2221 +4441 3900 +4575 3722 +4640 3642 +4725 3543 +4369 3464 +4454 3360 +4781 3848 +2773 3547 +2823 3447 +2959 3625 +3061 3598 +4180 3448 +4198 3406 +4271 3730 +4463 3110 +2794 2312 +2638 2292 +2730 1974 +3486 2386 +3769 2711 +3660 2651 +3633 2471 +3595 2445 +3534 2397 +3459 2469 +3392 2577 +3373 2650 +3461 2779 +3530 2757 +2634 2163 +2599 2226 +2712 2316 +2809 2274 +2719 2136 +2816 2130 +3679 2029 +3727 2071 +3805 2108 +3759 2199 +4239 3468 +2874 3490 +3060 3462 +2920 3364 +4398 3157 \ No newline at end of file diff --git a/Data/treasure.cfg.bak b/Data/treasure.cfg.bak new file mode 100644 index 0000000..7ca58c9 --- /dev/null +++ b/Data/treasure.cfg.bak @@ -0,0 +1,193 @@ +2643 851 +2672 392 +3404 238 +3369 637 +2740 435 +2770 345 +2781 289 +2836 233 +3014 250 +3082 202 +3246 245 +3375 458 +1314 317 +1470 229 +1504 366 +2340 645 +2350 688 +2395 723 +2433 767 +1319 889 +1414 771 +1529 753 +1555 806 +1511 967 +1510 1071 +1562 1058 +961 506 +1162 189 +2337 1159 +2392 1154 +2517 1066 +2458 1042 +1658 2030 +2062 1962 +2089 1987 +2097 1975 +2066 1979 +2058 1992 +2071 2007 +2093 2006 +2187 1991 +1689 1993 +1709 1964 +1726 1998 +1731 2016 +1743 2028 +1754 2020 +2033 1942 +2054 1962 +581 1455 +358 1337 +208 1444 +199 1461 +348 1565 +620 1706 +1027 1180 +1037 1975 +1042 1960 +1042 1903 +1034 1877 +1018 1859 +980 1849 +962 1858 +977 1879 +968 1884 +969 1893 +974 1992 +989 1992 +1024 1990 +2648 2167 +2956 2200 +2968 2170 +2957 2150 +2951 2177 +2629 2221 +2642 2289 +2682 2290 +2727 2309 +2782 2293 +2804 2255 +2850 2252 +2932 2240 +3425 2723 +3476 2761 +3594 2825 +4419 3117 +4471 3188 +4507 3227 +4496 3241 +4642 3369 +4694 3485 +4448 3130 +4453 3148 +4500 3108 +4513 3103 +4424 3152 +4466 3209 +4477 3230 +4477 3282 +2797 3452 +2803 3488 +2793 3519 +2831 3511 +2989 3606 +3035 3603 +1427 2405 +1466 2181 +1519 2214 +1523 2150 +1541 2115 +1534 2189 +1546 2221 +1595 2193 +1619 2236 +1654 2268 +1655 2304 +1433 2381 +1724 2288 +1703 2318 +1772 2321 +1758 2333 +1765 2430 +1647 2641 +1562 2705 +1670 2808 +1471 2340 +1562 2312 +1450 2301 +1437 2294 +1478 2273 +1464 2245 +1439 2217 +1383 2840 +1388 2984 +1415 3059 +1602 3012 +1664 3062 +2062 2144 +2178 2151 +2104 2123 +2098 2101 +2123 2120 +2130 2108 +2129 2132 +2153 2120 +2162 2148 +2186 2144 +492 2027 +477 2044 +451 2053 +468 2087 +465 2100 +958 2504 +1025 2702 +1290 2735 +2013 3269 +2149 3362 +2097 3384 +2039 3427 +2516 3999 +2453 3942 +2528 3982 +2513 3962 +2512 3918 +2513 3901 +2480 3908 +2421 3902 +2415 3920 +2422 3928 +2370 3428 +2341 3482 +2360 3507 +2387 3505 +2152 3950 +2157 3924 +2140 3940 +2143 3986 +2154 3983 +2162 3988 +2467 3581 +2527 3585 +2482 3624 +2535 3608 +1090 3110 +1094 3131 +1073 3133 +1076 3156 +1068 3182 +1096 3178 +1129 3403 +1135 3445 +1162 3469 +1128 3500 \ No newline at end of file diff --git a/Data/treasure.cfg.default b/Data/treasure.cfg.default new file mode 100644 index 0000000..29b7fb7 --- /dev/null +++ b/Data/treasure.cfg.default @@ -0,0 +1,191 @@ +2643 851 +2672 392 +3404 238 +3369 637 +2740 435 +2770 345 +2781 289 +2836 233 +3014 250 +3082 202 +3246 245 +3375 458 +1314 317 +1470 229 +1504 366 +2340 645 +2350 688 +2395 723 +2433 767 +1319 889 +1414 771 +1529 753 +1555 806 +1511 967 +1510 1071 +1562 1058 +961 506 +1162 189 +2337 1159 +2392 1154 +2517 1066 +2458 1042 +1658 2030 +2062 1962 +2089 1987 +2097 1975 +2066 1979 +2058 1992 +2071 2007 +2093 2006 +2187 1991 +1689 1993 +1709 1964 +1726 1998 +1731 2016 +1743 2028 +1754 2020 +2033 1942 +2054 1962 +581 1455 +358 1337 +208 1444 +199 1461 +348 1565 +620 1706 +1027 1180 +1037 1975 +1042 1960 +1042 1903 +1034 1877 +1018 1859 +980 1849 +962 1858 +977 1879 +968 1884 +969 1893 +974 1992 +989 1992 +1024 1990 +2648 2167 +2956 2200 +2968 2170 +2957 2150 +2951 2177 +2629 2221 +2642 2289 +2682 2290 +2727 2309 +2782 2293 +2804 2255 +2850 2252 +2932 2240 +3568 2402 +4419 3117 +4471 3188 +4507 3227 +4496 3241 +4642 3369 +4694 3485 +4448 3130 +4453 3148 +4500 3108 +4513 3103 +4424 3152 +4466 3209 +4477 3230 +4477 3282 +2797 3452 +2803 3488 +2793 3519 +2831 3511 +2989 3606 +3035 3603 +1427 2405 +1466 2181 +1519 2214 +1523 2150 +1541 2115 +1534 2189 +1546 2221 +1595 2193 +1619 2236 +1654 2268 +1655 2304 +1433 2381 +1724 2288 +1703 2318 +1772 2321 +1758 2333 +1765 2430 +1647 2641 +1562 2705 +1670 2808 +1471 2340 +1562 2312 +1450 2301 +1437 2294 +1478 2273 +1464 2245 +1439 2217 +1383 2840 +1388 2984 +1415 3059 +1602 3012 +1664 3062 +2062 2144 +2178 2151 +2104 2123 +2098 2101 +2123 2120 +2130 2108 +2129 2132 +2153 2120 +2162 2148 +2186 2144 +492 2027 +477 2044 +451 2053 +468 2087 +465 2100 +958 2504 +1025 2702 +1290 2735 +2013 3269 +2149 3362 +2097 3384 +2039 3427 +2516 3999 +2453 3942 +2528 3982 +2513 3962 +2512 3918 +2513 3901 +2480 3908 +2421 3902 +2415 3920 +2422 3928 +2370 3428 +2341 3482 +2360 3507 +2387 3505 +2152 3950 +2157 3924 +2140 3940 +2143 3986 +2154 3983 +2162 3988 +2467 3581 +2527 3585 +2482 3624 +2535 3608 +1090 3110 +1094 3131 +1073 3133 +1076 3156 +1068 3182 +1096 3178 +1129 3403 +1135 3445 +1162 3469 +1128 3500 \ No newline at end of file diff --git a/OrbServerSDK.dll b/OrbServerSDK.dll new file mode 100644 index 0000000..90a328a Binary files /dev/null and b/OrbServerSDK.dll differ diff --git a/Scripts/Accounting/AccessRestrictions.cs b/Scripts/Accounting/AccessRestrictions.cs new file mode 100644 index 0000000..fa953c1 --- /dev/null +++ b/Scripts/Accounting/AccessRestrictions.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using Server; +using Server.Misc; + +namespace Server +{ + public class AccessRestrictions + { + public static void Initialize() + { + EventSink.SocketConnect += new SocketConnectEventHandler( EventSink_SocketConnect ); + } + + private static void EventSink_SocketConnect( SocketConnectEventArgs e ) + { + try + { + IPAddress ip = ((IPEndPoint)e.Socket.RemoteEndPoint).Address; + + if ( Firewall.IsBlocked( ip ) ) + { + Console.WriteLine( "Client: {0}: Firewall blocked connection attempt.", ip ); + e.AllowConnection = false; + return; + } + else if ( IPLimiter.SocketBlock && !IPLimiter.Verify( ip ) ) + { + Console.WriteLine( "Client: {0}: Past IP limit threshold", ip ); + + using ( StreamWriter op = new StreamWriter( "ipLimits.log", true ) ) + op.WriteLine( "{0}\tPast IP limit threshold\t{1}", ip, DateTime.Now ); + + e.AllowConnection = false; + return; + } + } + catch + { + e.AllowConnection = false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/Account.cs b/Scripts/Accounting/Account.cs new file mode 100644 index 0000000..40bac03 --- /dev/null +++ b/Scripts/Accounting/Account.cs @@ -0,0 +1,1211 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Security; +using System.Security.Cryptography; +using System.Text; +using System.Xml; +using Server; +using Server.Misc; +using Server.Mobiles; +using Server.Multis; +using Server.Network; + +namespace Server.Accounting +{ + public class Account : IAccount, IComparable, IComparable + { + public static readonly TimeSpan YoungDuration = TimeSpan.FromHours( 40.0 ); + + public static readonly TimeSpan InactiveDuration = TimeSpan.FromDays( 180.0 ); + + public static readonly TimeSpan EmptyInactiveDuration = TimeSpan.FromDays(30.0); + + private string m_Username, m_PlainPassword, m_CryptPassword, m_NewCryptPassword; + private AccessLevel m_AccessLevel; + private int m_Flags; + private DateTime m_Created, m_LastLogin; + private TimeSpan m_TotalGameTime; + private List m_Comments; + private List m_Tags; + private Mobile[] m_Mobiles; + private string[] m_IPRestrictions; + private IPAddress[] m_LoginIPs; + private HardwareInfo m_HardwareInfo; + + /// + /// Deletes the account, all characters of the account, and all houses of those characters + /// + public void Delete() + { + for ( int i = 0; i < this.Length; ++i ) + { + Mobile m = this[i]; + + if ( m == null ) + continue; + + List list = BaseHouse.GetHouses( m ); + + for ( int j = 0; j < list.Count; ++j ) + list[j].Delete(); + + m.Delete(); + + m.Account = null; + m_Mobiles[i] = null; + } + + if (m_LoginIPs.Length != 0 && AccountHandler.IPTable.ContainsKey(m_LoginIPs[0])) + --AccountHandler.IPTable[m_LoginIPs[0]]; + + Accounts.Remove( m_Username ); + } + + /// + /// Object detailing information about the hardware of the last person to log into this account + /// + public HardwareInfo HardwareInfo + { + get { return m_HardwareInfo; } + set { m_HardwareInfo = value; } + } + + /// + /// List of IP addresses for restricted access. '*' wildcard supported. If the array contains zero entries, all IP addresses are allowed. + /// + public string[] IPRestrictions + { + get { return m_IPRestrictions; } + set { m_IPRestrictions = value; } + } + + /// + /// List of IP addresses which have successfully logged into this account. + /// + public IPAddress[] LoginIPs + { + get { return m_LoginIPs; } + set { m_LoginIPs = value; } + } + + /// + /// List of account comments. Type of contained objects is AccountComment. + /// + public List Comments + { + get { if ( m_Comments == null ) m_Comments = new List(); return m_Comments; } + } + + /// + /// List of account tags. Type of contained objects is AccountTag. + /// + public List Tags + { + get { if ( m_Tags == null ) m_Tags = new List(); return m_Tags; } + } + + /// + /// Account username. Case insensitive validation. + /// + public string Username + { + get { return m_Username; } + set { m_Username = value; } + } + + /// + /// Account password. Plain text. Case sensitive validation. May be null. + /// + public string PlainPassword + { + get { return m_PlainPassword; } + set { m_PlainPassword = value; } + } + + /// + /// Account password. Hashed with MD5. May be null. + /// + public string CryptPassword + { + get { return m_CryptPassword; } + set { m_CryptPassword = value; } + } + + /// + /// Account username and password hashed with SHA1. May be null. + /// + public string NewCryptPassword + { + get { return m_NewCryptPassword; } + set { m_NewCryptPassword = value; } + } + + /// + /// Initial AccessLevel for new characters created on this account. + /// + public AccessLevel AccessLevel + { + get { return m_AccessLevel; } + set { m_AccessLevel = value; } + } + + /// + /// Internal bitfield of account flags. Consider using direct access properties (Banned, Young), or GetFlag/SetFlag methods + /// + public int Flags + { + get { return m_Flags; } + set { m_Flags = value; } + } + + /// + /// Gets or sets a flag indiciating if this account is banned. + /// + public bool Banned + { + get + { + bool isBanned = GetFlag( 0 ); + + if ( !isBanned ) + return false; + + DateTime banTime; + TimeSpan banDuration; + + if ( GetBanTags( out banTime, out banDuration ) ) + { + if ( banDuration != TimeSpan.MaxValue && DateTime.Now >= ( banTime + banDuration ) ) + { + SetUnspecifiedBan( null ); // clear + Banned = false; + return false; + } + } + + return true; + } + set { SetFlag( 0, value ); } + } + + /// + /// Gets or sets a flag indicating if the characters created on this account will have the young status. + /// + public bool Young + { + get { return !GetFlag( 1 ); } + set + { + SetFlag( 1, !value ); + + if ( m_YoungTimer != null ) + { + m_YoungTimer.Stop(); + m_YoungTimer = null; + } + } + } + + /// + /// The date and time of when this account was created. + /// + public DateTime Created + { + get { return m_Created; } + } + + /// + /// Gets or sets the date and time when this account was last accessed. + /// + public DateTime LastLogin + { + get { return m_LastLogin; } + set { m_LastLogin = value; } + } + + /// + /// An account is considered inactive based upon LastLogin and InactiveDuration. If the account is empty, it is based upon EmptyInactiveDuration + /// + public bool Inactive + { + get + { + if (this.AccessLevel != AccessLevel.Player) + return false; + + TimeSpan inactiveLength = DateTime.Now - m_LastLogin; + + return (inactiveLength > ((this.Count == 0) ? EmptyInactiveDuration : InactiveDuration)); + } + } + + /// + /// Gets the total game time of this account, also considering the game time of characters + /// that have been deleted. + /// + public TimeSpan TotalGameTime + { + get + { + for ( int i = 0; i < m_Mobiles.Length; i++ ) + { + PlayerMobile m = m_Mobiles[i] as PlayerMobile; + + if ( m != null && m.NetState != null ) + return m_TotalGameTime + ( DateTime.Now - m.SessionStart ); + } + + return m_TotalGameTime; + } + } + + /// + /// Gets the value of a specific flag in the Flags bitfield. + /// + /// The zero-based flag index. + public bool GetFlag( int index ) + { + return ( m_Flags & ( 1 << index ) ) != 0; + } + + /// + /// Sets the value of a specific flag in the Flags bitfield. + /// + /// The zero-based flag index. + /// The value to set. + public void SetFlag( int index, bool value ) + { + if ( value ) + m_Flags |= ( 1 << index ); + else + m_Flags &= ~( 1 << index ); + } + + /// + /// Adds a new tag to this account. This method does not check for duplicate names. + /// + /// New tag name. + /// New tag value. + public void AddTag( string name, string value ) + { + Tags.Add( new AccountTag( name, value ) ); + } + + /// + /// Removes all tags with the specified name from this account. + /// + /// Tag name to remove. + public void RemoveTag( string name ) + { + for ( int i = Tags.Count - 1; i >= 0; --i ) + { + if ( i >= Tags.Count ) + continue; + + AccountTag tag = Tags[i]; + + if ( tag.Name == name ) + Tags.RemoveAt( i ); + } + } + + /// + /// Modifies an existing tag or adds a new tag if no tag exists. + /// + /// Tag name. + /// Tag value. + public void SetTag( string name, string value ) + { + for ( int i = 0; i < Tags.Count; ++i ) + { + AccountTag tag = Tags[i]; + + if ( tag.Name == name ) + { + tag.Value = value; + return; + } + } + + AddTag( name, value ); + } + + /// + /// Gets the value of a tag -or- null if there are no tags with the specified name. + /// + /// Name of the desired tag value. + public string GetTag( string name ) + { + for ( int i = 0; i < Tags.Count; ++i ) + { + AccountTag tag = Tags[i]; + + if ( tag.Name == name ) + return tag.Value; + } + + return null; + } + + public void SetUnspecifiedBan( Mobile from ) + { + SetBanTags( from, DateTime.MinValue, TimeSpan.Zero ); + } + + public void SetBanTags( Mobile from, DateTime banTime, TimeSpan banDuration ) + { + if ( from == null ) + RemoveTag( "BanDealer" ); + else + SetTag( "BanDealer", from.ToString() ); + + if ( banTime == DateTime.MinValue ) + RemoveTag( "BanTime" ); + else + SetTag( "BanTime", XmlConvert.ToString( banTime, XmlDateTimeSerializationMode.Local ) ); + + if ( banDuration == TimeSpan.Zero ) + RemoveTag( "BanDuration" ); + else + SetTag( "BanDuration", banDuration.ToString() ); + } + + public bool GetBanTags( out DateTime banTime, out TimeSpan banDuration ) + { + string tagTime = GetTag( "BanTime" ); + string tagDuration = GetTag( "BanDuration" ); + + if ( tagTime != null ) + banTime = Utility.GetXMLDateTime( tagTime, DateTime.MinValue ); + else + banTime = DateTime.MinValue; + + if ( tagDuration == "Infinite" ) + { + banDuration = TimeSpan.MaxValue; + } + else if ( tagDuration != null ) + { + banDuration = Utility.ToTimeSpan( tagDuration ); + } + else + { + banDuration = TimeSpan.Zero; + } + + return ( banTime != DateTime.MinValue && banDuration != TimeSpan.Zero ); + } + + private static MD5CryptoServiceProvider m_MD5HashProvider; + private static SHA1CryptoServiceProvider m_SHA1HashProvider; + private static byte[] m_HashBuffer; + + public static string HashMD5( string phrase ) + { + if ( m_MD5HashProvider == null ) + m_MD5HashProvider = new MD5CryptoServiceProvider(); + + if ( m_HashBuffer == null ) + m_HashBuffer = new byte[256]; + + int length = Encoding.ASCII.GetBytes( phrase, 0, phrase.Length > 256 ? 256 : phrase.Length, m_HashBuffer, 0 ); + byte[] hashed = m_MD5HashProvider.ComputeHash( m_HashBuffer, 0, length ); + + return BitConverter.ToString( hashed ); + } + + public static string HashSHA1( string phrase ) + { + if ( m_SHA1HashProvider == null ) + m_SHA1HashProvider = new SHA1CryptoServiceProvider(); + + if ( m_HashBuffer == null ) + m_HashBuffer = new byte[256]; + + int length = Encoding.ASCII.GetBytes( phrase, 0, phrase.Length > 256 ? 256 : phrase.Length, m_HashBuffer, 0 ); + byte[] hashed = m_SHA1HashProvider.ComputeHash( m_HashBuffer, 0, length ); + + return BitConverter.ToString( hashed ); + } + + public void SetPassword( string plainPassword ) + { + switch ( AccountHandler.ProtectPasswords ) + { + case PasswordProtection.None: + { + m_PlainPassword = plainPassword; + m_CryptPassword = null; + m_NewCryptPassword = null; + + break; + } + case PasswordProtection.Crypt: + { + m_PlainPassword = null; + m_CryptPassword = HashMD5( plainPassword ); + m_NewCryptPassword = null; + + break; + } + default: // PasswordProtection.NewCrypt + { + m_PlainPassword = null; + m_CryptPassword = null; + m_NewCryptPassword = HashSHA1( m_Username + plainPassword ); + + break; + } + } + } + + public bool CheckPassword( string plainPassword ) + { + bool ok; + PasswordProtection curProt; + + if ( m_PlainPassword != null ) + { + ok = ( m_PlainPassword == plainPassword ); + curProt = PasswordProtection.None; + } + else if ( m_CryptPassword != null ) + { + ok = ( m_CryptPassword == HashMD5( plainPassword ) ); + curProt = PasswordProtection.Crypt; + } + else + { + ok = ( m_NewCryptPassword == HashSHA1( m_Username + plainPassword ) ); + curProt = PasswordProtection.NewCrypt; + } + + if ( ok && curProt != AccountHandler.ProtectPasswords ) + SetPassword( plainPassword ); + + return ok; + } + + private Timer m_YoungTimer; + + public static void Initialize() + { + EventSink.Connected += new ConnectedEventHandler( EventSink_Connected ); + EventSink.Disconnected += new DisconnectedEventHandler( EventSink_Disconnected ); + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static void EventSink_Connected( ConnectedEventArgs e ) + { + Account acc = e.Mobile.Account as Account; + + if ( acc == null ) + return; + + if ( acc.Young && acc.m_YoungTimer == null ) + { + acc.m_YoungTimer = new YoungTimer( acc ); + acc.m_YoungTimer.Start(); + } + } + + private static void EventSink_Disconnected( DisconnectedEventArgs e ) + { + Account acc = e.Mobile.Account as Account; + + if ( acc == null ) + return; + + if ( acc.m_YoungTimer != null ) + { + acc.m_YoungTimer.Stop(); + acc.m_YoungTimer = null; + } + + PlayerMobile m = e.Mobile as PlayerMobile; + if ( m == null ) + return; + + acc.m_TotalGameTime += DateTime.Now - m.SessionStart; + } + + private static void EventSink_Login( LoginEventArgs e ) + { + PlayerMobile m = e.Mobile as PlayerMobile; + + if ( m == null ) + return; + + Account acc = m.Account as Account; + + if ( acc == null ) + return; + + if ( m.Young && acc.Young ) + { + TimeSpan ts = YoungDuration - acc.TotalGameTime; + int hours = Math.Max( (int) ts.TotalHours, 0 ); + + m.SendAsciiMessage( "You will enjoy the benefits and relatively safe status of a young player for {0} more hour{1}.", hours, hours != 1 ? "s" : "" ); + } + } + + public void RemoveYoungStatus( int message ) + { + this.Young = false; + + for ( int i = 0; i < m_Mobiles.Length; i++ ) + { + PlayerMobile m = m_Mobiles[i] as PlayerMobile; + + if ( m != null && m.Young ) + { + m.Young = false; + + if ( m.NetState != null ) + { + if ( message > 0 ) + m.SendLocalizedMessage( message ); + + m.SendLocalizedMessage( 1019039 ); // You are no longer considered a young player of Ultima Online, and are no longer subject to the limitations and benefits of being in that caste. + } + } + } + } + + public void CheckYoung() + { + if ( TotalGameTime >= YoungDuration ) + RemoveYoungStatus( 1019038 ); // You are old enough to be considered an adult, and have outgrown your status as a young player! + } + + private class YoungTimer : Timer + { + private Account m_Account; + + public YoungTimer( Account account ) + : base( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.0 ) ) + { + m_Account = account; + + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Account.CheckYoung(); + } + } + + public Account( string username, string password ) + { + m_Username = username; + + SetPassword( password ); + + m_AccessLevel = AccessLevel.Player; + + m_Created = m_LastLogin = DateTime.Now; + m_TotalGameTime = TimeSpan.Zero; + + m_Mobiles = new Mobile[7]; + + m_IPRestrictions = new string[0]; + m_LoginIPs = new IPAddress[0]; + + Accounts.Add( this ); + } + + public Account( XmlElement node ) + { + m_Username = Utility.GetText( node["username"], "empty" ); + + string plainPassword = Utility.GetText( node["password"], null ); + string cryptPassword = Utility.GetText( node["cryptPassword"], null ); + string newCryptPassword = Utility.GetText( node["newCryptPassword"], null ); + + switch ( AccountHandler.ProtectPasswords ) + { + case PasswordProtection.None: + { + if ( plainPassword != null ) + SetPassword( plainPassword ); + else if ( newCryptPassword != null ) + m_NewCryptPassword = newCryptPassword; + else if ( cryptPassword != null ) + m_CryptPassword = cryptPassword; + else + SetPassword( "empty" ); + + break; + } + case PasswordProtection.Crypt: + { + if ( cryptPassword != null ) + m_CryptPassword = cryptPassword; + else if ( plainPassword != null ) + SetPassword( plainPassword ); + else if ( newCryptPassword != null ) + m_NewCryptPassword = newCryptPassword; + else + SetPassword( "empty" ); + + break; + } + default: // PasswordProtection.NewCrypt + { + if ( newCryptPassword != null ) + m_NewCryptPassword = newCryptPassword; + else if ( plainPassword != null ) + SetPassword( plainPassword ); + else if ( cryptPassword != null ) + m_CryptPassword = cryptPassword; + else + SetPassword( "empty" ); + + break; + } + } + +#if Framework_4_0 + Enum.TryParse( Utility.GetText( node["accessLevel"], "Player" ), true, out m_AccessLevel ); +#else + m_AccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), Utility.GetText(node["accessLevel"], "Player"), true); +#endif + m_Flags = Utility.GetXMLInt32(Utility.GetText(node["flags"], "0"), 0); + m_Created = Utility.GetXMLDateTime( Utility.GetText( node["created"], null ), DateTime.Now ); + m_LastLogin = Utility.GetXMLDateTime( Utility.GetText( node["lastLogin"], null ), DateTime.Now ); + + m_Mobiles = LoadMobiles( node ); + m_Comments = LoadComments( node ); + m_Tags = LoadTags( node ); + m_LoginIPs = LoadAddressList( node ); + m_IPRestrictions = LoadAccessCheck( node ); + + for ( int i = 0; i < m_Mobiles.Length; ++i ) + { + if ( m_Mobiles[i] != null ) + m_Mobiles[i].Account = this; + } + + TimeSpan totalGameTime = Utility.GetXMLTimeSpan( Utility.GetText( node["totalGameTime"], null ), TimeSpan.Zero ); + if ( totalGameTime == TimeSpan.Zero ) + { + for ( int i = 0; i < m_Mobiles.Length; i++ ) + { + PlayerMobile m = m_Mobiles[i] as PlayerMobile; + + if ( m != null ) + totalGameTime += m.GameTime; + } + } + m_TotalGameTime = totalGameTime; + + if ( this.Young ) + CheckYoung(); + + Accounts.Add( this ); + } + + /// + /// Deserializes a list of string values from an xml element. Null values are not added to the list. + /// + /// The XmlElement from which to deserialize. + /// String list. Value will never be null. + public static string[] LoadAccessCheck( XmlElement node ) + { + string[] stringList; + XmlElement accessCheck = node["accessCheck"]; + + if ( accessCheck != null ) + { + List list = new List(); + + foreach ( XmlElement ip in accessCheck.GetElementsByTagName( "ip" ) ) + { + string text = Utility.GetText( ip, null ); + + if ( text != null ) + list.Add( text ); + } + + stringList = list.ToArray(); + } + else + { + stringList = new string[0]; + } + + return stringList; + } + + /// + /// Deserializes a list of IPAddress values from an xml element. + /// + /// The XmlElement from which to deserialize. + /// Address list. Value will never be null. + public static IPAddress[] LoadAddressList( XmlElement node ) + { + IPAddress[] list; + XmlElement addressList = node["addressList"]; + + if ( addressList != null ) + { + int count = Utility.GetXMLInt32( Utility.GetAttribute( addressList, "count", "0" ), 0 ); + + list = new IPAddress[count]; + + count = 0; + + foreach ( XmlElement ip in addressList.GetElementsByTagName( "ip" ) ) + { + if ( count < list.Length ) + { + IPAddress address; + + if( IPAddress.TryParse( Utility.GetText( ip, null ), out address ) ) + { + list[count] = Utility.Intern( address ); + count++; + } + } + } + + if ( count != list.Length ) + { + IPAddress[] old = list; + list = new IPAddress[count]; + + for ( int i = 0; i < count && i < old.Length; ++i ) + list[i] = old[i]; + } + } + else + { + list = new IPAddress[0]; + } + + return list; + } + + /// + /// Deserializes a list of Mobile instances from an xml element. + /// + /// The XmlElement instance from which to deserialize. + /// Mobile list. Value will never be null. + public static Mobile[] LoadMobiles( XmlElement node ) + { + Mobile[] list = new Mobile[7]; + XmlElement chars = node["chars"]; + + //int length = Accounts.GetInt32( Accounts.GetAttribute( chars, "length", "6" ), 6 ); + //list = new Mobile[length]; + //Above is legacy, no longer used + + if ( chars != null ) + { + foreach ( XmlElement ele in chars.GetElementsByTagName( "char" ) ) + { + try + { + int index = Utility.GetXMLInt32( Utility.GetAttribute( ele, "index", "0" ), 0 ); + int serial = Utility.GetXMLInt32( Utility.GetText( ele, "0" ), 0 ); + + if ( index >= 0 && index < list.Length ) + list[index] = World.FindMobile( serial ); + } + catch + { + } + } + } + + return list; + } + + /// + /// Deserializes a list of AccountComment instances from an xml element. + /// + /// The XmlElement from which to deserialize. + /// Comment list. Value will never be null. + public static List LoadComments( XmlElement node ) + { + List list = null; + XmlElement comments = node["comments"]; + + if ( comments != null ) + { + list = new List(); + + foreach ( XmlElement comment in comments.GetElementsByTagName( "comment" ) ) + { + try { list.Add( new AccountComment( comment ) ); } + catch { } + } + } + + return list; + } + + /// + /// Deserializes a list of AccountTag instances from an xml element. + /// + /// The XmlElement from which to deserialize. + /// Tag list. Value will never be null. + public static List LoadTags( XmlElement node ) + { + List list = null; + XmlElement tags = node["tags"]; + + if ( tags != null ) + { + list = new List(); + + foreach ( XmlElement tag in tags.GetElementsByTagName( "tag" ) ) + { + try { list.Add( new AccountTag( tag ) ); } + catch { } + } + } + + return list; + } + + /// + /// Checks if a specific NetState is allowed access to this account. + /// + /// NetState instance to check. + /// True if allowed, false if not. + public bool HasAccess( NetState ns ) + { + return ( ns != null && HasAccess( ns.Address ) ); + } + + public bool HasAccess( IPAddress ipAddress ) { + AccessLevel level = Misc.AccountHandler.LockdownLevel; + + if ( level > AccessLevel.Player ) + { + bool hasAccess = false; + + if ( m_AccessLevel >= level ) + { + hasAccess = true; + } + else + { + for ( int i = 0; !hasAccess && i < this.Length; ++i ) + { + Mobile m = this[i]; + + if ( m != null && m.AccessLevel >= level ) + hasAccess = true; + } + } + + if ( !hasAccess ) + return false; + } + + bool accessAllowed = ( m_IPRestrictions.Length == 0 || IPLimiter.IsExempt( ipAddress ) ); + + for ( int i = 0; !accessAllowed && i < m_IPRestrictions.Length; ++i ) + accessAllowed = Utility.IPMatch( m_IPRestrictions[i], ipAddress ); + + return accessAllowed; + } + + /// + /// Records the IP address of 'ns' in its 'LoginIPs' list. + /// + /// NetState instance to record. + public void LogAccess( NetState ns ) + { + if ( ns != null ) { + LogAccess( ns.Address ); + } + } + + public void LogAccess( IPAddress ipAddress ) { + if ( IPLimiter.IsExempt( ipAddress ) ) + return; + + if ( m_LoginIPs.Length == 0 ) { + if ( AccountHandler.IPTable.ContainsKey( ipAddress ) ) + AccountHandler.IPTable[ipAddress]++; + else + AccountHandler.IPTable[ipAddress] = 1; + } + + bool contains = false; + + for ( int i = 0; !contains && i < m_LoginIPs.Length; ++i ) + contains = m_LoginIPs[i].Equals( ipAddress ); + + if ( contains ) + return; + + IPAddress[] old = m_LoginIPs; + m_LoginIPs = new IPAddress[old.Length + 1]; + + for ( int i = 0; i < old.Length; ++i ) + m_LoginIPs[i] = old[i]; + + m_LoginIPs[old.Length] = ipAddress; + } + + /// + /// Checks if a specific NetState is allowed access to this account. If true, the NetState IPAddress is added to the address list. + /// + /// NetState instance to check. + /// True if allowed, false if not. + public bool CheckAccess( NetState ns ) + { + return ( ns != null && CheckAccess( ns.Address ) ); + } + + public bool CheckAccess( IPAddress ipAddress ) { + bool hasAccess = this.HasAccess( ipAddress ); + + if ( hasAccess ) { + LogAccess( ipAddress ); + } + + return hasAccess; + } + + /// + /// Serializes this Account instance to an XmlTextWriter. + /// + /// The XmlTextWriter instance from which to serialize. + public void Save( XmlTextWriter xml ) + { + xml.WriteStartElement( "account" ); + + xml.WriteStartElement( "username" ); + xml.WriteString( m_Username ); + xml.WriteEndElement(); + + if ( m_PlainPassword != null ) + { + xml.WriteStartElement( "password" ); + xml.WriteString( m_PlainPassword ); + xml.WriteEndElement(); + } + + if ( m_CryptPassword != null ) + { + xml.WriteStartElement( "cryptPassword" ); + xml.WriteString( m_CryptPassword ); + xml.WriteEndElement(); + } + + if ( m_NewCryptPassword != null ) + { + xml.WriteStartElement( "newCryptPassword" ); + xml.WriteString( m_NewCryptPassword ); + xml.WriteEndElement(); + } + + if ( m_AccessLevel != AccessLevel.Player ) + { + xml.WriteStartElement( "accessLevel" ); + xml.WriteString( m_AccessLevel.ToString() ); + xml.WriteEndElement(); + } + + if ( m_Flags != 0 ) + { + xml.WriteStartElement( "flags" ); + xml.WriteString( XmlConvert.ToString( m_Flags ) ); + xml.WriteEndElement(); + } + + xml.WriteStartElement( "created" ); + xml.WriteString( XmlConvert.ToString( m_Created, XmlDateTimeSerializationMode.Local ) ); + xml.WriteEndElement(); + + xml.WriteStartElement( "lastLogin" ); + xml.WriteString( XmlConvert.ToString( m_LastLogin, XmlDateTimeSerializationMode.Local ) ); + xml.WriteEndElement(); + + xml.WriteStartElement( "totalGameTime" ); + xml.WriteString( XmlConvert.ToString( TotalGameTime ) ); + xml.WriteEndElement(); + + xml.WriteStartElement( "chars" ); + + //xml.WriteAttributeString( "length", m_Mobiles.Length.ToString() ); //Legacy, Not used anymore + + for ( int i = 0; i < m_Mobiles.Length; ++i ) + { + Mobile m = m_Mobiles[i]; + + if ( m != null && !m.Deleted ) + { + xml.WriteStartElement( "char" ); + xml.WriteAttributeString( "index", i.ToString() ); + xml.WriteString( m.Serial.Value.ToString() ); + xml.WriteEndElement(); + } + } + + xml.WriteEndElement(); + + if ( m_Comments != null && m_Comments.Count > 0 ) + { + xml.WriteStartElement( "comments" ); + + for ( int i = 0; i < m_Comments.Count; ++i ) + m_Comments[i].Save( xml ); + + xml.WriteEndElement(); + } + + if ( m_Tags != null && m_Tags.Count > 0 ) + { + xml.WriteStartElement( "tags" ); + + for ( int i = 0; i < m_Tags.Count; ++i ) + m_Tags[i].Save( xml ); + + xml.WriteEndElement(); + } + + if ( m_LoginIPs.Length > 0 ) + { + xml.WriteStartElement( "addressList" ); + + xml.WriteAttributeString( "count", m_LoginIPs.Length.ToString() ); + + for ( int i = 0; i < m_LoginIPs.Length; ++i ) + { + xml.WriteStartElement( "ip" ); + xml.WriteString( m_LoginIPs[i].ToString() ); + xml.WriteEndElement(); + } + + xml.WriteEndElement(); + } + + if ( m_IPRestrictions.Length > 0 ) + { + xml.WriteStartElement( "accessCheck" ); + + for ( int i = 0; i < m_IPRestrictions.Length; ++i ) + { + xml.WriteStartElement( "ip" ); + xml.WriteString( m_IPRestrictions[i] ); + xml.WriteEndElement(); + } + + xml.WriteEndElement(); + } + + xml.WriteEndElement(); + } + + /// + /// Gets the current number of characters on this account. + /// + public int Count + { + get + { + int count = 0; + + for ( int i = 0; i < this.Length; ++i ) + { + if ( this[i] != null ) + ++count; + } + + return count; + } + } + + /// + /// Gets the maximum amount of characters allowed to be created on this account. Values other than 1, 5, 6, or 7 are not supported by the client. + /// + public int Limit + { + get { return 5; /*( Core.SA ? 7 : Core.AOS ? 6 : 5 );*/ } + } + + /// + /// Gets the maxmimum amount of characters that this account can hold. + /// + public int Length + { + get { return m_Mobiles.Length; } + } + + /// + /// Gets or sets the character at a specified index for this account. Out of bound index values are handled; null returned for get, ignored for set. + /// + public Mobile this[int index] + { + get + { + if ( index >= 0 && index < m_Mobiles.Length ) + { + Mobile m = m_Mobiles[index]; + + if ( m != null && m.Deleted ) + { + m.Account = null; + m_Mobiles[index] = m = null; + } + + return m; + } + + return null; + } + set + { + if ( index >= 0 && index < m_Mobiles.Length ) + { + if ( m_Mobiles[index] != null ) + m_Mobiles[index].Account = null; + + m_Mobiles[index] = value; + + if ( m_Mobiles[index] != null ) + m_Mobiles[index].Account = this; + } + } + } + + public override string ToString() + { + return m_Username; + } + + public int CompareTo( Account other ) + { + if ( other == null ) + return 1; + + return m_Username.CompareTo( other.m_Username ); + } + + public int CompareTo(IAccount other) + { + if (other == null) + return 1; + + return m_Username.CompareTo(other.Username); + } + + public int CompareTo( object obj ) + { + if ( obj is Account ) + return this.CompareTo( (Account) obj ); + + throw new ArgumentException(); + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/AccountAttackLimiter.cs b/Scripts/Accounting/AccountAttackLimiter.cs new file mode 100644 index 0000000..69713c2 --- /dev/null +++ b/Scripts/Accounting/AccountAttackLimiter.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using Server; +using Server.Network; + +namespace Server.Accounting +{ + public class AccountAttackLimiter + { + public static bool Enabled = true; + + public static void Initialize() + { + if ( !Enabled ) + return; + + PacketHandlers.RegisterThrottler( 0x80, new ThrottlePacketCallback( Throttle_Callback ) ); + PacketHandlers.RegisterThrottler( 0x91, new ThrottlePacketCallback( Throttle_Callback ) ); + PacketHandlers.RegisterThrottler( 0xCF, new ThrottlePacketCallback( Throttle_Callback ) ); + } + + public static bool Throttle_Callback( NetState ns ) + { + InvalidAccountAccessLog accessLog = FindAccessLog( ns ); + + if ( accessLog == null ) + return true; + + return ( DateTime.Now >= (accessLog.LastAccessTime + ComputeThrottle( accessLog.Counts )) ); + } + + private static List m_List = new List(); + + public static InvalidAccountAccessLog FindAccessLog( NetState ns ) + { + if ( ns == null ) + return null; + + IPAddress ipAddress = ns.Address; + + for ( int i = 0; i < m_List.Count; ++i ) + { + InvalidAccountAccessLog accessLog = m_List[i]; + + if ( accessLog.HasExpired ) + m_List.RemoveAt( i-- ); + else if ( accessLog.Address.Equals( ipAddress ) ) + return accessLog; + } + + return null; + } + + public static void RegisterInvalidAccess( NetState ns ) + { + if ( ns == null || !Enabled ) + return; + + InvalidAccountAccessLog accessLog = FindAccessLog( ns ); + + if ( accessLog == null ) + m_List.Add( accessLog = new InvalidAccountAccessLog( ns.Address ) ); + + accessLog.Counts += 1; + accessLog.RefreshAccessTime(); + + if ( accessLog.Counts >= 3 ) { + try { + using ( StreamWriter op = new StreamWriter( "throttle.log", true ) ) { + op.WriteLine( + "{0}\t{1}\t{2}", + DateTime.Now, + ns, + accessLog.Counts + ); + } + } + catch { + } + } + } + + public static TimeSpan ComputeThrottle( int counts ) + { + if ( counts >= 15 ) + return TimeSpan.FromMinutes( 5.0 ); + + if ( counts >= 10 ) + return TimeSpan.FromMinutes( 1.0 ); + + if ( counts >= 5 ) + return TimeSpan.FromSeconds( 20.0 ); + + if ( counts >= 3 ) + return TimeSpan.FromSeconds( 10.0 ); + + if ( counts >= 1 ) + return TimeSpan.FromSeconds( 2.0 ); + + return TimeSpan.Zero; + } + } + + public class InvalidAccountAccessLog + { + private IPAddress m_Address; + private DateTime m_LastAccessTime; + private int m_Counts; + + public IPAddress Address + { + get{ return m_Address; } + set{ m_Address = value; } + } + + public DateTime LastAccessTime + { + get{ return m_LastAccessTime; } + set{ m_LastAccessTime = value; } + } + + public bool HasExpired + { + get{ return ( DateTime.Now >= ( m_LastAccessTime + TimeSpan.FromHours( 1.0 ) ) ); } + } + + public int Counts + { + get{ return m_Counts; } + set{ m_Counts = value; } + } + + public void RefreshAccessTime() + { + m_LastAccessTime = DateTime.Now; + } + + public InvalidAccountAccessLog( IPAddress address ) + { + m_Address = address; + RefreshAccessTime(); + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/AccountComment.cs b/Scripts/Accounting/AccountComment.cs new file mode 100644 index 0000000..4083fe9 --- /dev/null +++ b/Scripts/Accounting/AccountComment.cs @@ -0,0 +1,77 @@ +using System; +using System.Xml; + +namespace Server.Accounting +{ + public class AccountComment + { + private string m_AddedBy; + private string m_Content; + private DateTime m_LastModified; + + /// + /// A string representing who added this comment. + /// + public string AddedBy + { + get{ return m_AddedBy; } + } + + /// + /// Gets or sets the body of this comment. Setting this value will reset LastModified. + /// + public string Content + { + get{ return m_Content; } + set{ m_Content = value; m_LastModified = DateTime.Now; } + } + + /// + /// The date and time when this account was last modified -or- the comment creation time, if never modified. + /// + public DateTime LastModified + { + get{ return m_LastModified; } + } + + /// + /// Constructs a new AccountComment instance. + /// + /// Initial AddedBy value. + /// Initial Content value. + public AccountComment( string addedBy, string content ) + { + m_AddedBy = addedBy; + m_Content = content; + m_LastModified = DateTime.Now; + } + + /// + /// Deserializes an AccountComment instance from an xml element. + /// + /// The XmlElement instance from which to deserialize. + public AccountComment( XmlElement node ) + { + m_AddedBy = Utility.GetAttribute( node, "addedBy", "empty" ); + m_LastModified = Utility.GetXMLDateTime( Utility.GetAttribute( node, "lastModified" ), DateTime.Now ); + m_Content = Utility.GetText( node, "" ); + } + + /// + /// Serializes this AccountComment instance to an XmlTextWriter. + /// + /// The XmlTextWriter instance from which to serialize. + public void Save( XmlTextWriter xml ) + { + xml.WriteStartElement( "comment" ); + + xml.WriteAttributeString( "addedBy", m_AddedBy ); + + xml.WriteAttributeString( "lastModified", XmlConvert.ToString( m_LastModified, XmlDateTimeSerializationMode.Local ) ); + + xml.WriteString( m_Content ); + + xml.WriteEndElement(); + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/AccountHandler.cs b/Scripts/Accounting/AccountHandler.cs new file mode 100644 index 0000000..aae6990 --- /dev/null +++ b/Scripts/Accounting/AccountHandler.cs @@ -0,0 +1,435 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using Server; +using Server.Accounting; +using Server.Commands; +using Server.Engines.Help; +using Server.Network; +using Server.Regions; + +namespace Server.Misc +{ + public enum PasswordProtection + { + None, + Crypt, + NewCrypt + } + + public class AccountHandler + { + private static int MaxAccountsPerIP = 1; + private static bool AutoAccountCreation = false; + private static bool RestrictDeletion = !TestCenter.Enabled; + private static TimeSpan DeleteDelay = TimeSpan.FromDays( 7.0 ); + + public static PasswordProtection ProtectPasswords = PasswordProtection.NewCrypt; + + private static AccessLevel m_LockdownLevel; + + public static AccessLevel LockdownLevel + { + get{ return m_LockdownLevel; } + set{ m_LockdownLevel = value; } + } + + private static CityInfo[] StartingCities = new CityInfo[] + { + new CityInfo( "New Haven", "New Haven Bank", 1150168, 3667, 2625, 0 ), + new CityInfo( "Yew", "The Empath Abbey", 1075072, 633, 858, 0 ), + new CityInfo( "Minoc", "The Barnacle", 1075073, 2476, 413, 15 ), + new CityInfo( "Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20 ), + new CityInfo( "Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0 ), + new CityInfo( "Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0 ), + new CityInfo( "Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0 ), + new CityInfo( "Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0 ), + new CityInfo( "Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0 ) + }; + + /* Old Haven/Magincia Locations + new CityInfo( "Britain", "Sweet Dreams Inn", 1496, 1628, 10 ); + // .. + // Trinsic + new CityInfo( "Magincia", "The Great Horns Tavern", 3734, 2222, 20 ), + // Jhelom + // .. + new CityInfo( "Haven", "Buckler's Hideaway", 3667, 2625, 0 ) + + if ( Core.AOS ) + { + //CityInfo haven = new CityInfo( "Haven", "Uzeraan's Mansion", 3618, 2591, 0 ); + CityInfo haven = new CityInfo( "Haven", "Uzeraan's Mansion", 3503, 2574, 14 ); + StartingCities[StartingCities.Length - 1] = haven; + } + */ + + private static bool PasswordCommandEnabled = true; // Scriptiz : on peut modifier son mot de passe + + public static void Initialize() + { + EventSink.DeleteRequest += new DeleteRequestEventHandler( EventSink_DeleteRequest ); + EventSink.AccountLogin += new AccountLoginEventHandler( EventSink_AccountLogin ); + EventSink.GameLogin += new GameLoginEventHandler( EventSink_GameLogin ); + + if ( PasswordCommandEnabled ) + CommandSystem.Register( "Password", AccessLevel.Player, new CommandEventHandler( Password_OnCommand ) ); + } + + [Usage( "Password " )] + [Description( "Changes the password of the commanding players account. Requires the same C-class IP address as the account's creator." )] + public static void Password_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + Account acct = from.Account as Account; + + if ( acct == null ) + return; + + IPAddress[] accessList = acct.LoginIPs; + + if ( accessList.Length == 0 ) + return; + + NetState ns = from.NetState; + + if ( ns == null ) + return; + + if ( e.Length == 0 ) + { + from.SendMessage( "You must specify the new password." ); + return; + } + else if ( e.Length == 1 ) + { + from.SendMessage( "To prevent potential typing mistakes, you must type the password twice. Use the format:" ); + from.SendMessage( "Password \"(newPassword)\" \"(repeated)\"" ); + return; + } + + string pass = e.GetString( 0 ); + string pass2 = e.GetString( 1 ); + + if ( pass != pass2 ) + { + from.SendMessage( "The passwords do not match." ); + return; + } + + bool isSafe = true; + + for ( int i = 0; isSafe && i < pass.Length; ++i ) + isSafe = (pass[i] >= 0x20 && pass[i] < 0x7F); + + if ( !isSafe ) + { + from.SendMessage( "That is not a valid password." ); + return; + } + + try + { + //IPAddress ipAddress = ns.Address; + + //if ( Utility.IPMatchClassC( accessList[0], ipAddress ) ) + //{ + acct.SetPassword( pass ); + from.SendMessage( "The password to your account has changed." ); + //} + //else + //{ + // PageEntry entry = PageQueue.GetEntry( from ); + + // if ( entry != null ) + // { + // if ( entry.Message.StartsWith( "[Automated: Change Password]" ) ) + // from.SendMessage( "You already have a password change request in the help system queue." ); + // else + // from.SendMessage( "Your IP address does not match that which created this account." ); + // } + // else if ( PageQueue.CheckAllowedToPage( from ) ) + // { + // from.SendMessage( "Your IP address does not match that which created this account. A page has been entered into the help system on your behalf." ); + + // from.SendLocalizedMessage( 501234, "", 0x35 ); /* The next available Counselor/Game Master will respond as soon as possible. + // * Please check your Journal for messages every few minutes. + // */ + + // PageQueue.Enqueue( new PageEntry( from, String.Format( "[Automated: Change Password]
Desired password: {0}
Current IP address: {1}
Account IP address: {2}", pass, ipAddress, accessList[0] ), PageType.Account ) ); + // } + + //} + } + catch + { + } + } + + private static void EventSink_DeleteRequest( DeleteRequestEventArgs e ) + { + NetState state = e.State; + int index = e.Index; + + Account acct = state.Account as Account; + + if ( acct == null ) + { + state.Dispose(); + } + else if ( index < 0 || index >= acct.Length ) + { + state.Send( new DeleteResult( DeleteResultType.BadRequest ) ); + state.Send( new CharacterListUpdate( acct ) ); + } + else + { + Mobile m = acct[index]; + + if ( m == null ) + { + state.Send( new DeleteResult( DeleteResultType.CharNotExist ) ); + state.Send( new CharacterListUpdate( acct ) ); + } + else if ( m.NetState != null ) + { + state.Send( new DeleteResult( DeleteResultType.CharBeingPlayed ) ); + state.Send( new CharacterListUpdate( acct ) ); + } + // Scriptiz : DeleteDelay uniquement pour les joueurs + else if (m.AccessLevel == AccessLevel.Player && RestrictDeletion && DateTime.Now < (m.CreationTime + DeleteDelay) ) + { + state.Send( new DeleteResult( DeleteResultType.CharTooYoung ) ); + state.Send( new CharacterListUpdate( acct ) ); + } + else if ( m.AccessLevel == AccessLevel.Player && Region.Find( m.LogoutLocation, m.LogoutMap ).GetRegion( typeof( Jail ) ) != null ) //Don't need to check current location, if netstate is null, they're logged out + { + state.Send( new DeleteResult( DeleteResultType.BadRequest ) ); + state.Send( new CharacterListUpdate( acct ) ); + } + else + { + Console.WriteLine( "Client: {0}: Deleting character {1} (0x{2:X})", state, index, m.Serial.Value ); + + acct.Comments.Add( new AccountComment( "System", String.Format( "Character #{0} {1} deleted by {2}", index + 1, m, state ) ) ); + + m.Delete(); + state.Send( new CharacterListUpdate( acct ) ); + } + } + } + + public static bool CanCreate( IPAddress ip ) + { + if ( !IPTable.ContainsKey( ip ) ) + return true; + + return ( IPTable[ip] < MaxAccountsPerIP ); + } + + private static Dictionary m_IPTable; + + public static Dictionary IPTable + { + get + { + if ( m_IPTable == null ) + { + m_IPTable = new Dictionary(); + + foreach ( Account a in Accounts.GetAccounts() ) + if ( a.LoginIPs.Length > 0 ) + { + IPAddress ip = a.LoginIPs[0]; + + if ( m_IPTable.ContainsKey( ip ) ) + m_IPTable[ip]++; + else + m_IPTable[ip] = 1; + } + } + + return m_IPTable; + } + } + + private static readonly char[] m_ForbiddenChars = new char[] + { + '<', '>', ':', '"', '/', '\\', '|', '?', '*' + }; + + private static bool IsForbiddenChar(char c) + { + for (int i = 0; i < m_ForbiddenChars.Length; ++i) + if (c == m_ForbiddenChars[i]) + return true; + + return false; + } + + private static Account CreateAccount(NetState state, string un, string pw) + { + if (un.Length == 0 || pw.Length == 0) + return null; + + bool isSafe = !(un.StartsWith(" ") || un.EndsWith(" ") || un.EndsWith(".")); + + for (int i = 0; isSafe && i < un.Length; ++i) + isSafe = (un[i] >= 0x20 && un[i] < 0x7F && !IsForbiddenChar(un[i])); + + for (int i = 0; isSafe && i < pw.Length; ++i) + isSafe = (pw[i] >= 0x20 && pw[i] < 0x7F); + + if ( !isSafe ) + return null; + + if ( !CanCreate( state.Address ) ) + { + Console.WriteLine( "Login: {0}: Account '{1}' not created, ip already has {2} account{3}.", state, un, MaxAccountsPerIP, MaxAccountsPerIP == 1 ? "" : "s" ); + return null; + } + + Console.WriteLine( "Login: {0}: Creating new account '{1}'", state, un ); + + Account a = new Account( un, pw ); + + return a; + } + + public static void EventSink_AccountLogin( AccountLoginEventArgs e ) + { + if ( !IPLimiter.SocketBlock && !IPLimiter.Verify( e.State.Address ) ) + { + e.Accepted = false; + e.RejectReason = ALRReason.InUse; + + Console.WriteLine( "Login: {0}: Past IP limit threshold", e.State ); + + using ( StreamWriter op = new StreamWriter( "ipLimits.log", true ) ) + op.WriteLine( "{0}\tPast IP limit threshold\t{1}", e.State, DateTime.Now ); + + return; + } + + string un = e.Username; + string pw = e.Password; + + e.Accepted = false; + Account acct = Accounts.GetAccount( un ) as Account; + + if ( acct == null ) + { + if ( AutoAccountCreation && un.Trim().Length > 0 ) //To prevent someone from making an account of just '' or a bunch of meaningless spaces + { + e.State.Account = acct = CreateAccount( e.State, un, pw ); + e.Accepted = acct == null ? false : acct.CheckAccess( e.State ); + + if ( !e.Accepted ) + e.RejectReason = ALRReason.BadComm; + } + else + { + Console.WriteLine( "Login: {0}: Invalid username '{1}'", e.State, un ); + e.RejectReason = ALRReason.Invalid; + } + } + else if ( !acct.HasAccess( e.State ) ) + { + Console.WriteLine( "Login: {0}: Access denied for '{1}'", e.State, un ); + e.RejectReason = ( m_LockdownLevel > AccessLevel.Player ? ALRReason.BadComm : ALRReason.BadPass ); + } + else if ( !acct.CheckPassword( pw ) ) + { + Console.WriteLine( "Login: {0}: Invalid password for '{1}'", e.State, un ); + e.RejectReason = ALRReason.BadPass; + } + else if ( acct.Banned ) + { + Console.WriteLine( "Login: {0}: Banned account '{1}'", e.State, un ); + e.RejectReason = ALRReason.Blocked; + } + else + { + Console.WriteLine( "Login: {0}: Valid credentials for '{1}'", e.State, un ); + e.State.Account = acct; + e.Accepted = true; + + acct.LogAccess( e.State ); + } + + if ( !e.Accepted ) + AccountAttackLimiter.RegisterInvalidAccess( e.State ); + } + + public static void EventSink_GameLogin( GameLoginEventArgs e ) + { + if ( !IPLimiter.SocketBlock && !IPLimiter.Verify( e.State.Address ) ) + { + e.Accepted = false; + + Console.WriteLine( "Login: {0}: Past IP limit threshold", e.State ); + + using ( StreamWriter op = new StreamWriter( "ipLimits.log", true ) ) + op.WriteLine( "{0}\tPast IP limit threshold\t{1}", e.State, DateTime.Now ); + + return; + } + + string un = e.Username; + string pw = e.Password; + + Account acct = Accounts.GetAccount( un ) as Account; + + if ( acct == null ) + { + e.Accepted = false; + } + else if ( !acct.HasAccess( e.State ) ) + { + Console.WriteLine( "Login: {0}: Access denied for '{1}'", e.State, un ); + e.Accepted = false; + } + else if ( !acct.CheckPassword( pw ) ) + { + Console.WriteLine( "Login: {0}: Invalid password for '{1}'", e.State, un ); + e.Accepted = false; + } + else if ( acct.Banned ) + { + Console.WriteLine( "Login: {0}: Banned account '{1}'", e.State, un ); + e.Accepted = false; + } + else + { + acct.LogAccess( e.State ); + + Console.WriteLine( "Login: {0}: Account '{1}' at character list", e.State, un ); + e.State.Account = acct; + e.Accepted = true; + e.CityInfo = StartingCities; + } + + if ( !e.Accepted ) + AccountAttackLimiter.RegisterInvalidAccess( e.State ); + } + public static bool CheckAccount(Mobile mobCheck, Mobile accCheck) + { + if (accCheck != null) + { + Account a = accCheck.Account as Account; + + if (a != null) + { + for (int i = 0; i < a.Length; ++i) + { + if (a[i] == mobCheck) + return true; + } + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/AccountTag.cs b/Scripts/Accounting/AccountTag.cs new file mode 100644 index 0000000..48f7c0f --- /dev/null +++ b/Scripts/Accounting/AccountTag.cs @@ -0,0 +1,61 @@ +using System; +using System.Xml; + +namespace Server.Accounting +{ + public class AccountTag + { + private string m_Name, m_Value; + + /// + /// Gets or sets the name of this tag. + /// + public string Name + { + get{ return m_Name; } + set{ m_Name = value; } + } + + /// + /// Gets or sets the value of this tag. + /// + public string Value + { + get{ return m_Value; } + set{ m_Value = value; } + } + + /// + /// Constructs a new AccountTag instance with a specific name and value. + /// + /// Initial name. + /// Initial value. + public AccountTag( string name, string value ) + { + m_Name = name; + m_Value = value; + } + + /// + /// Deserializes an AccountTag instance from an xml element. + /// + /// The XmlElement instance from which to deserialize. + public AccountTag( XmlElement node ) + { + m_Name = Utility.GetAttribute( node, "name", "empty" ); + m_Value = Utility.GetText( node, "" ); + } + + /// + /// Serializes this AccountTag instance to an XmlTextWriter. + /// + /// The XmlTextWriter instance from which to serialize. + public void Save( XmlTextWriter xml ) + { + xml.WriteStartElement( "tag" ); + xml.WriteAttributeString( "name", m_Name ); + xml.WriteString( m_Value ); + xml.WriteEndElement(); + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/Accounts.cs b/Scripts/Accounting/Accounts.cs new file mode 100644 index 0000000..3f10759 --- /dev/null +++ b/Scripts/Accounting/Accounts.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +namespace Server.Accounting +{ + public class Accounts + { + private static Dictionary m_Accounts = new Dictionary(); + + public static void Configure() + { + EventSink.WorldLoad += new WorldLoadEventHandler( Load ); + EventSink.WorldSave += new WorldSaveEventHandler( Save ); + } + + static Accounts() + { + } + + public static int Count { get { return m_Accounts.Count; } } + + public static ICollection GetAccounts() + { +#if !MONO + return m_Accounts.Values; +#else + return new List( m_Accounts.Values ); +#endif + } + + public static IAccount GetAccount( string username ) + { + IAccount a; + + m_Accounts.TryGetValue( username, out a ); + + return a; + } + + public static void Add( IAccount a ) + { + m_Accounts[a.Username] = a; + } + + public static void Remove( string username ) + { + m_Accounts.Remove( username ); + } + + public static void Load() + { + m_Accounts = new Dictionary( 32, StringComparer.OrdinalIgnoreCase ); + + string filePath = Path.Combine( "Saves/Accounts", "accounts.xml" ); + + if ( !File.Exists( filePath ) ) + return; + + XmlDocument doc = new XmlDocument(); + doc.Load( filePath ); + + XmlElement root = doc["accounts"]; + + foreach ( XmlElement account in root.GetElementsByTagName( "account" ) ) + { + try + { + Account acct = new Account( account ); + } + catch + { + Console.WriteLine( "Warning: Account instance load failed" ); + } + } + } + + public static void Save( WorldSaveEventArgs e ) + { + if ( !Directory.Exists( "Saves/Accounts" ) ) + Directory.CreateDirectory( "Saves/Accounts" ); + + string filePath = Path.Combine( "Saves/Accounts", "accounts.xml" ); + + using ( StreamWriter op = new StreamWriter( filePath ) ) + { + XmlTextWriter xml = new XmlTextWriter( op ); + + xml.Formatting = Formatting.Indented; + xml.IndentChar = '\t'; + xml.Indentation = 1; + + xml.WriteStartDocument( true ); + + xml.WriteStartElement( "accounts" ); + + xml.WriteAttributeString( "count", m_Accounts.Count.ToString() ); + + foreach ( Account a in GetAccounts() ) + a.Save( xml ); + + xml.WriteEndElement(); + + xml.Close(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/Firewall.cs b/Scripts/Accounting/Firewall.cs new file mode 100644 index 0000000..7416719 --- /dev/null +++ b/Scripts/Accounting/Firewall.cs @@ -0,0 +1,344 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; + +namespace Server +{ + public class Firewall + { + #region Firewall Entries + public interface IFirewallEntry + { + bool IsBlocked( IPAddress address ); + } + + public class IPFirewallEntry : IFirewallEntry + { + IPAddress m_Address; + public IPFirewallEntry( IPAddress address ) + { + m_Address = address; + } + + public bool IsBlocked( IPAddress address ) + { + return m_Address.Equals( address ); + } + + public override string ToString() + { + return m_Address.ToString(); + } + + public override bool Equals( object obj ) + { + if( obj is IPAddress ) + { + return obj.Equals( m_Address ); + } + else if( obj is string ) + { + IPAddress otherAddress; + + if( IPAddress.TryParse( (string)obj, out otherAddress ) ) + return otherAddress.Equals( m_Address ); + } + else if( obj is IPFirewallEntry ) + { + return m_Address.Equals( ((IPFirewallEntry)obj).m_Address ); + } + + return false; + } + + public override int GetHashCode() + { + return m_Address.GetHashCode(); + } + } + + public class CIDRFirewallEntry : IFirewallEntry + { + IPAddress m_CIDRPrefix; + int m_CIDRLength; + + public CIDRFirewallEntry( IPAddress cidrPrefix, int cidrLength ) + { + m_CIDRPrefix = cidrPrefix; + m_CIDRLength = cidrLength; + } + + public bool IsBlocked( IPAddress address ) + { + return Utility.IPMatchCIDR( m_CIDRPrefix, address, m_CIDRLength ); + } + + public override string ToString() + { + return String.Format( "{0}/{1}", m_CIDRPrefix, m_CIDRLength ); + } + + public override bool Equals( object obj ) + { + + if( obj is string ) + { + string entry= (string)obj; + + string[] str = entry.Split( '/' ); + + if( str.Length == 2 ) + { + IPAddress cidrPrefix; + + if( IPAddress.TryParse( str[0], out cidrPrefix ) ) + { + int cidrLength; + + if( int.TryParse( str[1], out cidrLength ) ) + return m_CIDRPrefix.Equals( cidrPrefix ) && m_CIDRLength.Equals( cidrLength ); + } + } + } + else if( obj is CIDRFirewallEntry ) + { + CIDRFirewallEntry entry = obj as CIDRFirewallEntry; + + return m_CIDRPrefix.Equals( entry.m_CIDRPrefix ) && m_CIDRLength.Equals( entry.m_CIDRLength ); + } + + return false; + } + + public override int GetHashCode() + { + return m_CIDRPrefix.GetHashCode() ^ m_CIDRLength.GetHashCode(); + } + } + + public class WildcardIPFirewallEntry : IFirewallEntry + { + string m_Entry; + + bool m_Valid = true; + + public WildcardIPFirewallEntry( string entry ) + { + m_Entry = entry; + } + + public bool IsBlocked( IPAddress address ) + { + if( !m_Valid ) + return false; //Why process if it's invalid? it'll return false anyway after processing it. + + return Utility.IPMatch( m_Entry, address, ref m_Valid ); + } + + public override string ToString() + { + return m_Entry.ToString(); + } + + public override bool Equals( object obj ) + { + if( obj is string ) + return obj.Equals( m_Entry ); + else if( obj is WildcardIPFirewallEntry ) + return m_Entry.Equals( ((WildcardIPFirewallEntry)obj).m_Entry ); + + return false; + } + + public override int GetHashCode() + { + return m_Entry.GetHashCode(); + } + } + #endregion + + private static List m_Blocked; + + static Firewall() + { + m_Blocked = new List(); + + string path = "firewall.cfg"; + + if ( File.Exists( path ) ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length == 0 ) + continue; + + m_Blocked.Add( ToFirewallEntry( line ) ); + + /* + object toAdd; + + IPAddress addr; + if( IPAddress.TryParse( line, out addr ) ) + toAdd = addr; + else + toAdd = line; + + m_Blocked.Add( toAdd.ToString() ); + * */ + } + } + } + } + + public static List List + { + get + { + return m_Blocked; + } + } + + public static IFirewallEntry ToFirewallEntry( object entry ) + { + if( entry is IFirewallEntry ) + return (IFirewallEntry)entry; + else if( entry is IPAddress ) + return new IPFirewallEntry( (IPAddress)entry ); + else if( entry is string ) + return ToFirewallEntry( (string)entry ); + + return null; + } + + public static IFirewallEntry ToFirewallEntry( string entry ) + { + IPAddress addr; + + if( IPAddress.TryParse( entry, out addr ) ) + return new IPFirewallEntry( addr ); + + //Try CIDR parse + string[] str = entry.Split( '/' ); + + if( str.Length == 2 ) + { + IPAddress cidrPrefix; + + if( IPAddress.TryParse( str[0], out cidrPrefix ) ) + { + int cidrLength; + + if( int.TryParse( str[1], out cidrLength ) ) + return new CIDRFirewallEntry( cidrPrefix, cidrLength ); + } + } + + return new WildcardIPFirewallEntry( entry ); + } + + public static void RemoveAt( int index ) + { + m_Blocked.RemoveAt( index ); + Save(); + } + + public static void Remove( object obj ) + { + IFirewallEntry entry = ToFirewallEntry( obj ); + + if( entry != null ) + { + m_Blocked.Remove( entry ); + Save(); + } + } + + public static void Add( object obj ) + { + if( obj is IPAddress ) + Add( (IPAddress)obj ); + else if( obj is string ) + Add( (string)obj ); + else if( obj is IFirewallEntry ) + Add( (IFirewallEntry)obj ); + } + + public static void Add( IFirewallEntry entry ) + { + if( !m_Blocked.Contains( entry ) ) + m_Blocked.Add( entry ); + + Save(); + } + + public static void Add( string pattern ) + { + IFirewallEntry entry = ToFirewallEntry( pattern ); + + if( !m_Blocked.Contains( entry ) ) + m_Blocked.Add( entry ); + + Save(); + } + + public static void Add( IPAddress ip ) + { + IFirewallEntry entry = new IPFirewallEntry( ip ); + + if( !m_Blocked.Contains( entry ) ) + m_Blocked.Add( entry ); + + Save(); + } + + public static void Save() + { + string path = "firewall.cfg"; + + using ( StreamWriter op = new StreamWriter( path ) ) + { + for ( int i = 0; i < m_Blocked.Count; ++i ) + op.WriteLine( m_Blocked[i] ); + } + } + + public static bool IsBlocked( IPAddress ip ) + { + for( int i = 0; i < m_Blocked.Count; i++ ) + { + if( m_Blocked[i].IsBlocked( ip ) ) + return true; + } + + return false; + /* + bool contains = false; + + for ( int i = 0; !contains && i < m_Blocked.Count; ++i ) + { + if ( m_Blocked[i] is IPAddress ) + contains = ip.Equals( m_Blocked[i] ); + else if ( m_Blocked[i] is String ) + { + string s = (string)m_Blocked[i]; + + contains = Utility.IPMatchCIDR( s, ip ); + + if( !contains ) + contains = Utility.IPMatch( s, ip ); + } + } + + return contains; + * */ + } + } +} \ No newline at end of file diff --git a/Scripts/Accounting/IPLimiter.cs b/Scripts/Accounting/IPLimiter.cs new file mode 100644 index 0000000..a7e4642 --- /dev/null +++ b/Scripts/Accounting/IPLimiter.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using Server; +using Server.Network; + +namespace Server.Misc +{ + public class IPLimiter + { + public static bool Enabled = true; + public static bool SocketBlock = true; // true to block at connection, false to block at login request + + public static int MaxAddresses = 10; + + public static IPAddress[] Exemptions = new IPAddress[] //For hosting services where there are cases where IPs can be proxied + { + //IPAddress.Parse( "127.0.0.1" ), + }; + + public static bool IsExempt( IPAddress ip ) + { + for ( int i = 0; i < Exemptions.Length; i++ ) + { + if ( ip.Equals( Exemptions[i] ) ) + return true; + } + + return false; + } + + public static bool Verify( IPAddress ourAddress ) + { + if ( !Enabled || IsExempt( ourAddress ) ) + return true; + + List netStates = NetState.Instances; + + int count = 0; + + for ( int i = 0; i < netStates.Count; ++i ) + { + NetState compState = netStates[i]; + + if ( ourAddress.Equals( compState.Address ) ) + { + ++count; + + if ( count >= MaxAddresses ) + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Add.cs b/Scripts/Commands/Add.cs new file mode 100644 index 0000000..f439327 --- /dev/null +++ b/Scripts/Commands/Add.cs @@ -0,0 +1,736 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Server; +using Server.Items; +using Server.Network; +using Server.Targeting; +using CPA = Server.CommandPropertyAttribute; + +namespace Server.Commands +{ + public class Add + { + public static void Initialize() + { + CommandSystem.Register("Tile", AccessLevel.GameMaster, new CommandEventHandler(Tile_OnCommand)); + CommandSystem.Register("TileRXYZ", AccessLevel.GameMaster, new CommandEventHandler(TileRXYZ_OnCommand)); + CommandSystem.Register("TileXYZ", AccessLevel.GameMaster, new CommandEventHandler(TileXYZ_OnCommand)); + CommandSystem.Register("TileZ", AccessLevel.GameMaster, new CommandEventHandler(TileZ_OnCommand)); + CommandSystem.Register("TileAvg", AccessLevel.GameMaster, new CommandEventHandler(TileAvg_OnCommand)); + + CommandSystem.Register("Outline", AccessLevel.GameMaster, new CommandEventHandler(Outline_OnCommand)); + CommandSystem.Register("OutlineRXYZ", AccessLevel.GameMaster, new CommandEventHandler(OutlineRXYZ_OnCommand)); + CommandSystem.Register("OutlineXYZ", AccessLevel.GameMaster, new CommandEventHandler(OutlineXYZ_OnCommand)); + CommandSystem.Register("OutlineZ", AccessLevel.GameMaster, new CommandEventHandler(OutlineZ_OnCommand)); + CommandSystem.Register("OutlineAvg", AccessLevel.GameMaster, new CommandEventHandler(OutlineAvg_OnCommand)); + } + + public static void Invoke(Mobile from, Point3D start, Point3D end, string[] args) + { + Invoke(from, start, end, args, null, false, false); + } + + public static void Invoke(Mobile from, Point3D start, Point3D end, string[] args, List packs) + { + Invoke(from, start, end, args, packs, false, false); + } + + public static void Invoke(Mobile from, Point3D start, Point3D end, string[] args, List packs, bool outline, bool mapAvg) + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat("{0} {1} building ", from.AccessLevel, CommandLogging.Format(from)); + + if (start == end) + sb.AppendFormat("at {0} in {1}", start, from.Map); + else + sb.AppendFormat("from {0} to {1} in {2}", start, end, from.Map); + + sb.Append(":"); + + for (int i = 0; i < args.Length; ++i) + sb.AppendFormat(" \"{0}\"", args[i]); + + CommandLogging.WriteLine(from, sb.ToString()); + + string name = args[0]; + + FixArgs(ref args); + + string[,] props = null; + + for (int i = 0; i < args.Length; ++i) + { + if (Insensitive.Equals(args[i], "set")) + { + int remains = args.Length - i - 1; + + if (remains >= 2) + { + props = new string[remains / 2, 2]; + + remains /= 2; + + for (int j = 0; j < remains; ++j) + { + props[j, 0] = args[i + (j * 2) + 1]; + props[j, 1] = args[i + (j * 2) + 2]; + } + + FixSetString(ref args, i); + } + + break; + } + } + + Type type = ScriptCompiler.FindTypeByName(name); + + if (!IsEntity(type)) + { + from.SendMessage("No type with that name was found."); + return; + } + + DateTime time = DateTime.Now; + + int built = BuildObjects(from, type, start, end, args, props, packs, outline, mapAvg); + + if (built > 0) + from.SendMessage("{0} object{1} generated in {2:F1} seconds.", built, built != 1 ? "s" : "", (DateTime.Now - time).TotalSeconds); + else + SendUsage(type, from); + } + + public static void FixSetString(ref string[] args, int index) + { + string[] old = args; + args = new string[index]; + + Array.Copy(old, 0, args, 0, index); + } + + public static void FixArgs(ref string[] args) + { + string[] old = args; + args = new string[args.Length - 1]; + + Array.Copy(old, 1, args, 0, args.Length); + } + + public static int BuildObjects(Mobile from, Type type, Point3D start, Point3D end, string[] args, string[,] props, List packs) + { + return BuildObjects(from, type, start, end, args, props, packs, false, false); + } + + public static int BuildObjects(Mobile from, Type type, Point3D start, Point3D end, string[] args, string[,] props, List packs, bool outline, bool mapAvg) + { + Utility.FixPoints(ref start, ref end); + + PropertyInfo[] realProps = null; + + if (props != null) + { + realProps = new PropertyInfo[props.GetLength(0)]; + + PropertyInfo[] allProps = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + for (int i = 0; i < realProps.Length; ++i) + { + PropertyInfo thisProp = null; + + string propName = props[i, 0]; + + for (int j = 0; thisProp == null && j < allProps.Length; ++j) + { + if (Insensitive.Equals(propName, allProps[j].Name)) + thisProp = allProps[j]; + } + + if (thisProp == null) + { + from.SendMessage("Property not found: {0}", propName); + } + else + { + CPA attr = Properties.GetCPA(thisProp); + + if (attr == null) + from.SendMessage("Property ({0}) not found.", propName); + else if (from.AccessLevel < attr.WriteLevel) + from.SendMessage("Setting this property ({0}) requires at least {1} access level.", propName, Mobile.GetAccessLevelName(attr.WriteLevel)); + else if (!thisProp.CanWrite || attr.ReadOnly) + from.SendMessage("Property ({0}) is read only.", propName); + else + realProps[i] = thisProp; + } + } + } + + ConstructorInfo[] ctors = type.GetConstructors(); + + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + if (!IsConstructable(ctor, from.AccessLevel)) + continue; + + ParameterInfo[] paramList = ctor.GetParameters(); + + if (args.Length == paramList.Length) + { + object[] paramValues = ParseValues(paramList, args); + + if (paramValues == null) + continue; + + int built = Build(from, start, end, ctor, paramValues, props, realProps, packs, outline, mapAvg); + + if (built > 0) + return built; + } + } + + return 0; + } + + public static object[] ParseValues(ParameterInfo[] paramList, string[] args) + { + object[] values = new object[args.Length]; + + for (int i = 0; i < args.Length; ++i) + { + object value = ParseValue(paramList[i].ParameterType, args[i]); + + if (value != null) + values[i] = value; + else + return null; + } + + return values; + } + + public static object ParseValue(Type type, string value) + { + try + { + if (IsEnum(type)) + { + return Enum.Parse(type, value, true); + } + else if (IsType(type)) + { + return ScriptCompiler.FindTypeByName(value); + } + else if (IsParsable(type)) + { + return ParseParsable(type, value); + } + else + { + object obj = value; + + if (value != null && value.StartsWith("0x")) + { + if (IsSignedNumeric(type)) + obj = Convert.ToInt64(value.Substring(2), 16); + else if (IsUnsignedNumeric(type)) + obj = Convert.ToUInt64(value.Substring(2), 16); + + obj = Convert.ToInt32(value.Substring(2), 16); + } + + if (obj == null && !type.IsValueType) + return null; + else + return Convert.ChangeType(obj, type); + } + } + catch + { + return null; + } + } + + public static IEntity Build(Mobile from, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, ref bool sendError) + { + object built = ctor.Invoke(values); + + if (built != null && realProps != null) + { + bool hadError = false; + + for (int i = 0; i < realProps.Length; ++i) + { + if (realProps[i] == null) + continue; + + string result = Properties.InternalSetValue(from, built, built, realProps[i], props[i, 1], props[i, 1], false); + + if (result != "Property has been set.") + { + if (sendError) + from.SendMessage(result); + + hadError = true; + } + } + + if (hadError) + sendError = false; + } + + return (IEntity)built; + } + + public static int Build(Mobile from, Point3D start, Point3D end, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, List packs) + { + return Build(from, start, end, ctor, values, props, realProps, packs, false, false); + } + + public static int Build(Mobile from, Point3D start, Point3D end, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, List packs, bool outline, bool mapAvg) + { + try + { + Map map = from.Map; + + int width = end.X - start.X + 1; + int height = end.Y - start.Y + 1; + + if (outline && (width < 3 || height < 3)) + outline = false; + + int objectCount; + + if (packs != null) + objectCount = packs.Count; + else if (outline) + objectCount = (width + height - 2) * 2; + else + objectCount = width * height; + + if (objectCount >= 20) + from.SendMessage("Constructing {0} objects, please wait.", objectCount); + + bool sendError = true; + + StringBuilder sb = new StringBuilder(); + sb.Append("Serials: "); + + if (packs != null) + { + for (int i = 0; i < packs.Count; ++i) + { + IEntity built = Build(from, ctor, values, props, realProps, ref sendError); + + sb.AppendFormat("0x{0:X}; ", built.Serial.Value); + + if (built is Item) + { + Container pack = packs[i]; + pack.DropItem((Item)built); + } + else if (built is Mobile) + { + Mobile m = (Mobile)built; + m.MoveToWorld(new Point3D(start.X, start.Y, start.Z), map); + } + } + } + else + { + int z = start.Z; + + for (int x = start.X; x <= end.X; ++x) + { + for (int y = start.Y; y <= end.Y; ++y) + { + if (outline && x != start.X && x != end.X && y != start.Y && y != end.Y) + continue; + + if (mapAvg) + z = map.GetAverageZ(x, y); + + IEntity built = Build(from, ctor, values, props, realProps, ref sendError); + + sb.AppendFormat("0x{0:X}; ", built.Serial.Value); + + if (built is Item) + { + Item item = (Item)built; + item.MoveToWorld(new Point3D(x, y, z), map); + } + else if (built is Mobile) + { + Mobile m = (Mobile)built; + m.MoveToWorld(new Point3D(x, y, z), map); + } + } + } + } + + CommandLogging.WriteLine(from, sb.ToString()); + + return objectCount; + } + catch (Exception ex) + { + Console.WriteLine(ex); + return 0; + } + } + + public static void SendUsage(Type type, Mobile from) + { + ConstructorInfo[] ctors = type.GetConstructors(); + bool foundCtor = false; + + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + if (!IsConstructable(ctor, from.AccessLevel)) + continue; + + if (!foundCtor) + { + foundCtor = true; + from.SendMessage("Usage:"); + } + + SendCtor(type, ctor, from); + } + + if (!foundCtor) + from.SendMessage("That type is not marked constructable."); + } + + public static void SendCtor(Type type, ConstructorInfo ctor, Mobile from) + { + ParameterInfo[] paramList = ctor.GetParameters(); + + StringBuilder sb = new StringBuilder(); + + sb.Append(type.Name); + + for (int i = 0; i < paramList.Length; ++i) + { + if (i != 0) + sb.Append(','); + + sb.Append(' '); + + sb.Append(paramList[i].ParameterType.Name); + sb.Append(' '); + sb.Append(paramList[i].Name); + } + + from.SendMessage(sb.ToString()); + } + + public class AddTarget : Target + { + private string[] m_Args; + + public AddTarget(string[] args) + : base(-1, true, TargetFlags.None) + { + m_Args = args; + } + + protected override void OnTarget(Mobile from, object o) + { + IPoint3D p = o as IPoint3D; + + if (p != null) + { + if (p is Item) + p = ((Item)p).GetWorldTop(); + else if (p is Mobile) + p = ((Mobile)p).Location; + + Point3D point = new Point3D(p); + Add.Invoke(from, point, point, m_Args); + } + } + } + + private enum TileZType + { + Start, + Fixed, + MapAverage + } + + private class TileState + { + public TileZType m_ZType; + public int m_FixedZ; + public string[] m_Args; + public bool m_Outline; + + public TileState(TileZType zType, int fixedZ, string[] args, bool outline) + { + m_ZType = zType; + m_FixedZ = fixedZ; + m_Args = args; + m_Outline = outline; + } + } + + private static void TileBox_Callback(Mobile from, Map map, Point3D start, Point3D end, object state) + { + TileState ts = (TileState)state; + bool mapAvg = false; + + switch (ts.m_ZType) + { + case TileZType.Fixed: + { + start.Z = end.Z = ts.m_FixedZ; + break; + } + case TileZType.MapAverage: + { + mapAvg = true; + break; + } + } + + Invoke(from, start, end, ts.m_Args, null, ts.m_Outline, mapAvg); + } + + private static void Internal_OnCommand(CommandEventArgs e, bool outline) + { + if (e.Length >= 1) + BoundingBoxPicker.Begin(e.Mobile, new BoundingBoxCallback(TileBox_Callback), new TileState(TileZType.Start, 0, e.Arguments, outline)); + else + e.Mobile.SendMessage("Format: {0} [params] [set {{ ...}}]", outline ? "Outline" : "Tile"); + } + + private static void InternalRXYZ_OnCommand(CommandEventArgs e, bool outline) + { + if (e.Length >= 6) + { + Point3D p = new Point3D(e.Mobile.X + e.GetInt32(0), e.Mobile.Y + e.GetInt32(1), e.Mobile.Z + e.GetInt32(4)); + Point3D p2 = new Point3D(p.X + e.GetInt32(2) - 1, p.Y + e.GetInt32(3) - 1, p.Z); + + string[] subArgs = new string[e.Length - 5]; + + for (int i = 0; i < subArgs.Length; ++i) + subArgs[i] = e.Arguments[i + 5]; + + Add.Invoke(e.Mobile, p, p2, subArgs, null, outline, false); + } + else + { + e.Mobile.SendMessage("Format: {0}RXYZ [params] [set {{ ...}}]", outline ? "Outline" : "Tile"); + } + } + + private static void InternalXYZ_OnCommand(CommandEventArgs e, bool outline) + { + if (e.Length >= 6) + { + Point3D p = new Point3D(e.GetInt32(0), e.GetInt32(1), e.GetInt32(4)); + Point3D p2 = new Point3D(p.X + e.GetInt32(2) - 1, p.Y + e.GetInt32(3) - 1, e.GetInt32(4)); + + string[] subArgs = new string[e.Length - 5]; + + for (int i = 0; i < subArgs.Length; ++i) + subArgs[i] = e.Arguments[i + 5]; + + Add.Invoke(e.Mobile, p, p2, subArgs, null, outline, false); + } + else + { + e.Mobile.SendMessage("Format: {0}XYZ [params] [set {{ ...}}]", outline ? "Outline" : "Tile"); + } + } + + private static void InternalZ_OnCommand(CommandEventArgs e, bool outline) + { + if (e.Length >= 2) + { + string[] subArgs = new string[e.Length - 1]; + + for (int i = 0; i < subArgs.Length; ++i) + subArgs[i] = e.Arguments[i + 1]; + + BoundingBoxPicker.Begin(e.Mobile, new BoundingBoxCallback(TileBox_Callback), new TileState(TileZType.Fixed, e.GetInt32(0), subArgs, outline)); + } + else + { + e.Mobile.SendMessage("Format: {0}Z [params] [set {{ ...}}]", outline ? "Outline" : "Tile"); + } + } + + private static void InternalAvg_OnCommand(CommandEventArgs e, bool outline) + { + if (e.Length >= 1) + BoundingBoxPicker.Begin(e.Mobile, new BoundingBoxCallback(TileBox_Callback), new TileState(TileZType.MapAverage, 0, e.Arguments, outline)); + else + e.Mobile.SendMessage("Format: {0}Avg [params] [set {{ ...}}]", outline ? "Outline" : "Tile"); + } + + [Usage("Tile [params] [set { ...}]")] + [Description("Tiles an item or npc by name into a targeted bounding box. Optional constructor parameters. Optional set property list.")] + public static void Tile_OnCommand(CommandEventArgs e) + { + Internal_OnCommand(e, false); + } + + [Usage("TileRXYZ [params] [set { ...}]")] + [Description("Tiles an item or npc by name into a given bounding box, (x, y) parameters are relative to your characters position. Optional constructor parameters. Optional set property list.")] + public static void TileRXYZ_OnCommand(CommandEventArgs e) + { + InternalRXYZ_OnCommand(e, false); + } + + [Usage("TileXYZ [params] [set { ...}]")] + [Description("Tiles an item or npc by name into a given bounding box. Optional constructor parameters. Optional set property list.")] + public static void TileXYZ_OnCommand(CommandEventArgs e) + { + InternalXYZ_OnCommand(e, false); + } + + [Usage("TileZ [params] [set { ...}]")] + [Description("Tiles an item or npc by name into a targeted bounding box at a fixed Z location. Optional constructor parameters. Optional set property list.")] + public static void TileZ_OnCommand(CommandEventArgs e) + { + InternalZ_OnCommand(e, false); + } + + [Usage("TileAvg [params] [set { ...}]")] + [Description("Tiles an item or npc by name into a targeted bounding box on the map's average Z elevation. Optional constructor parameters. Optional set property list.")] + public static void TileAvg_OnCommand(CommandEventArgs e) + { + InternalAvg_OnCommand(e, false); + } + + [Usage("Outline [params] [set { ...}]")] + [Description("Tiles an item or npc by name around a targeted bounding box. Optional constructor parameters. Optional set property list.")] + public static void Outline_OnCommand(CommandEventArgs e) + { + Internal_OnCommand(e, true); + } + + [Usage("OutlineRXYZ [params] [set { ...}]")] + [Description("Tiles an item or npc by name around a given bounding box, (x, y) parameters are relative to your characters position. Optional constructor parameters. Optional set property list.")] + public static void OutlineRXYZ_OnCommand(CommandEventArgs e) + { + InternalRXYZ_OnCommand(e, true); + } + + [Usage("OutlineXYZ [params] [set { ...}]")] + [Description("Tiles an item or npc by name around a given bounding box. Optional constructor parameters. Optional set property list.")] + public static void OutlineXYZ_OnCommand(CommandEventArgs e) + { + InternalXYZ_OnCommand(e, true); + } + + [Usage("OutlineZ [params] [set { ...}]")] + [Description("Tiles an item or npc by name around a targeted bounding box at a fixed Z location. Optional constructor parameters. Optional set property list.")] + public static void OutlineZ_OnCommand(CommandEventArgs e) + { + InternalZ_OnCommand(e, true); + } + + [Usage("OutlineAvg [params] [set { ...}]")] + [Description("Tiles an item or npc by name around a targeted bounding box on the map's average Z elevation. Optional constructor parameters. Optional set property list.")] + public static void OutlineAvg_OnCommand(CommandEventArgs e) + { + InternalAvg_OnCommand(e, true); + } + + private static Type m_EntityType = typeof(IEntity); + + public static bool IsEntity(Type t) + { + return m_EntityType.IsAssignableFrom(t); + } + + private static Type m_ConstructableType = typeof(ConstructableAttribute); + + public static bool IsConstructable(ConstructorInfo ctor, AccessLevel accessLevel) + { + object[] attrs = ctor.GetCustomAttributes(m_ConstructableType, false); + + if (attrs.Length == 0) + return false; + + return accessLevel >= ((ConstructableAttribute)attrs[0]).AccessLevel; + } + + private static Type m_EnumType = typeof(Enum); + + public static bool IsEnum(Type type) + { + return type.IsSubclassOf(m_EnumType); + } + + private static Type m_TypeType = typeof(Type); + + public static bool IsType(Type type) + { + return (type == m_TypeType || type.IsSubclassOf(m_TypeType)); + } + + private static Type m_ParsableType = typeof(ParsableAttribute); + + public static bool IsParsable(Type type) + { + return type.IsDefined(m_ParsableType, false); + } + + private static Type[] m_ParseTypes = new Type[] { typeof(string) }; + private static object[] m_ParseArgs = new object[1]; + + public static object ParseParsable(Type type, string value) + { + MethodInfo method = type.GetMethod("Parse", m_ParseTypes); + + m_ParseArgs[0] = value; + + return method.Invoke(null, m_ParseArgs); + } + + private static Type[] m_SignedNumerics = new Type[] + { + typeof( Int64 ), + typeof( Int32 ), + typeof( Int16 ), + typeof( SByte ) + }; + + public static bool IsSignedNumeric(Type type) + { + for (int i = 0; i < m_SignedNumerics.Length; ++i) + if (type == m_SignedNumerics[i]) + return true; + + return false; + } + + private static Type[] m_UnsignedNumerics = new Type[] + { + typeof( UInt64 ), + typeof( UInt32 ), + typeof( UInt16 ), + typeof( Byte ) + }; + + public static bool IsUnsignedNumeric(Type type) + { + for (int i = 0; i < m_UnsignedNumerics.Length; ++i) + if (type == m_UnsignedNumerics[i]) + return true; + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Attributes.cs b/Scripts/Commands/Attributes.cs new file mode 100644 index 0000000..d3f3a37 --- /dev/null +++ b/Scripts/Commands/Attributes.cs @@ -0,0 +1,40 @@ +using System; + +namespace Server +{ + public class UsageAttribute : Attribute + { + private string m_Usage; + + public string Usage{ get{ return m_Usage; } } + + public UsageAttribute( string usage ) + { + m_Usage = usage; + } + } + + public class DescriptionAttribute : Attribute + { + private string m_Description; + + public string Description{ get{ return m_Description; } } + + public DescriptionAttribute( string description ) + { + m_Description = description; + } + } + + public class AliasesAttribute : Attribute + { + private string[] m_Aliases; + + public string[] Aliases{ get{ return m_Aliases; } } + + public AliasesAttribute( params string[] aliases ) + { + m_Aliases = aliases; + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Batch.cs b/Scripts/Commands/Batch.cs new file mode 100644 index 0000000..7f09778 --- /dev/null +++ b/Scripts/Commands/Batch.cs @@ -0,0 +1,458 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Commands +{ + public class Batch : BaseCommand + { + private BaseCommandImplementor m_Scope; + private string m_Condition; + private ArrayList m_BatchCommands; + + public BaseCommandImplementor Scope + { + get{ return m_Scope; } + set{ m_Scope = value; } + } + + public string Condition + { + get{ return m_Condition; } + set{ m_Condition = value; } + } + + public ArrayList BatchCommands + { + get{ return m_BatchCommands; } + } + + public Batch() + { + Commands = new string[]{ "Batch" }; + ListOptimized = true; + + m_BatchCommands = new ArrayList(); + m_Condition = ""; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + if ( list.Count == 0 ) + { + LogFailure( "Nothing was found to use this command on." ); + return; + } + + try + { + BaseCommand[] commands = new BaseCommand[m_BatchCommands.Count]; + CommandEventArgs[] eventArgs = new CommandEventArgs[m_BatchCommands.Count]; + + for ( int i = 0; i < m_BatchCommands.Count; ++i ) + { + BatchCommand bc = (BatchCommand)m_BatchCommands[i]; + + string commandString, argString; + string[] args; + + bc.GetDetails( out commandString, out argString, out args ); + + BaseCommand command = m_Scope.Commands[commandString]; + + commands[i] = command; + eventArgs[i] = new CommandEventArgs( e.Mobile, commandString, argString, args ); + + if ( command == null ) + { + e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier: {0}.", commandString ); + return; + } + else if ( e.Mobile.AccessLevel < command.AccessLevel ) + { + e.Mobile.SendMessage( "You do not have access to that command: {0}.", commandString ); + return; + } + else if ( !command.ValidateArgs( m_Scope, eventArgs[i] ) ) + { + return; + } + } + + for ( int i = 0; i < commands.Length; ++i ) + { + BaseCommand command = commands[i]; + BatchCommand bc = (BatchCommand)m_BatchCommands[i]; + + if ( list.Count > 20 ) + CommandLogging.Enabled = false; + + ArrayList usedList; + + if ( Utility.InsensitiveCompare( bc.Object, "Current" ) == 0 ) + { + usedList = list; + } + else + { + Hashtable propertyChains = new Hashtable(); + + usedList = new ArrayList( list.Count ); + + for ( int j = 0; j < list.Count; ++j ) + { + object obj = list[j]; + + if ( obj == null ) + continue; + + Type type = obj.GetType(); + + PropertyInfo[] chain = (PropertyInfo[])propertyChains[type]; + + string failReason = ""; + + if ( chain == null && !propertyChains.Contains( type ) ) + propertyChains[type] = chain = Properties.GetPropertyInfoChain( e.Mobile, type, bc.Object, PropertyAccess.Read, ref failReason ); + + if ( chain == null ) + continue; + + PropertyInfo endProp = Properties.GetPropertyInfo( ref obj, chain, ref failReason ); + + if ( endProp == null ) + continue; + + try + { + obj = endProp.GetValue( obj, null ); + + if ( obj != null ) + usedList.Add( obj ); + } + catch + { + } + } + } + + command.ExecuteList( eventArgs[i], usedList ); + + if ( list.Count > 20 ) + CommandLogging.Enabled = true; + + command.Flush( e.Mobile, list.Count > 20 ); + } + } + catch ( Exception ex ) + { + e.Mobile.SendMessage( ex.Message ); + } + } + + public bool Run( Mobile from ) + { + if ( m_Scope == null ) + { + from.SendMessage( "You must select the batch command scope." ); + return false; + } + else if ( m_Condition.Length > 0 && !m_Scope.SupportsConditionals ) + { + from.SendMessage( "This command scope does not support conditionals." ); + return false; + } + else if ( m_Condition.Length > 0 && !Utility.InsensitiveStartsWith( m_Condition, "where" ) ) + { + from.SendMessage( "The condition field must start with \"where\"." ); + return false; + } + + string[] args = CommandSystem.Split( m_Condition ); + + m_Scope.Process( from, this, args ); + + return true; + } + + public static void Initialize() + { + CommandSystem.Register( "Batch", AccessLevel.Counselor, new CommandEventHandler( Batch_OnCommand ) ); + } + + [Usage( "Batch" )] + [Description( "Allows multiple commands to be run at the same time." )] + public static void Batch_OnCommand( CommandEventArgs e ) + { + Batch batch = new Batch(); + + e.Mobile.SendGump( new BatchGump( e.Mobile, batch ) ); + } + } + + public class BatchCommand + { + private string m_Command; + private string m_Object; + + public string Command + { + get{ return m_Command; } + set{ m_Command = value; } + } + + public string Object + { + get{ return m_Object; } + set{ m_Object = value; } + } + + public void GetDetails( out string command, out string argString, out string[] args ) + { + int indexOf = m_Command.IndexOf( ' ' ); + + if ( indexOf >= 0 ) + { + argString = m_Command.Substring( indexOf + 1 ); + + command = m_Command.Substring( 0, indexOf ); + args = CommandSystem.Split( argString ); + } + else + { + argString = ""; + command = m_Command.ToLower(); + args = new string[0]; + } + } + + public BatchCommand( string command, string obj ) + { + m_Command = command; + m_Object = obj; + } + } + + public class BatchGump : BaseGridGump + { + private Mobile m_From; + private Batch m_Batch; + + public BatchGump( Mobile from, Batch batch ) : base( 30, 30 ) + { + m_From = from; + m_Batch = batch; + + Render(); + } + + public void Render() + { + AddNewPage(); + + /* Header */ + AddEntryHeader( 20 ); + AddEntryHtml( 180, Center( "Batch Commands" ) ); + AddEntryHeader( 20 ); + AddNewLine(); + + AddEntryHeader( 9 ); + AddEntryLabel( 191, "Run Batch" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, 0 ), ArrowRightWidth, ArrowRightHeight ); + AddNewLine(); + + AddBlankLine(); + + /* Scope */ + AddEntryHeader( 20 ); + AddEntryHtml( 180, Center( "Scope" ) ); + AddEntryHeader( 20 ); + AddNewLine(); + + AddEntryHeader( 9 ); + AddEntryLabel( 191, m_Batch.Scope == null ? "Select Scope" : m_Batch.Scope.Accessors[0] ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, 1 ), ArrowRightWidth, ArrowRightHeight ); + AddNewLine(); + + AddBlankLine(); + + /* Condition */ + AddEntryHeader( 20 ); + AddEntryHtml( 180, Center( "Condition" ) ); + AddEntryHeader( 20 ); + AddNewLine(); + + AddEntryHeader( 9 ); + AddEntryText( 202, 0, m_Batch.Condition ); + AddEntryHeader( 9 ); + AddNewLine(); + + AddBlankLine(); + + /* Commands */ + AddEntryHeader( 20 ); + AddEntryHtml( 180, Center( "Commands" ) ); + AddEntryHeader( 20 ); + + for ( int i = 0; i < m_Batch.BatchCommands.Count; ++i ) + { + BatchCommand bc = (BatchCommand)m_Batch.BatchCommands[i]; + + AddNewLine(); + + AddImageTiled( CurrentX, CurrentY, 9, 2, 0x24A8 ); + AddImageTiled( CurrentX, CurrentY + 2, 2, EntryHeight + OffsetSize + EntryHeight - 4, 0x24A8 ); + AddImageTiled( CurrentX, CurrentY + EntryHeight + OffsetSize + EntryHeight - 2, 9, 2, 0x24A8 ); + AddImageTiled( CurrentX + 3, CurrentY + 3, 6, EntryHeight + EntryHeight - 4 - OffsetSize, HeaderGumpID ); + + IncreaseX( 9 ); + AddEntryText( 202, 1+(i*2), bc.Command ); + AddEntryHeader( 9, 2 ); + + AddNewLine(); + + IncreaseX( 9 ); + AddEntryText( 202, 2+(i*2), bc.Object ); + } + + AddNewLine(); + + AddEntryHeader( 9 ); + AddEntryLabel( 191, "Add New Command" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, 2 ), ArrowRightWidth, ArrowRightHeight ); + + FinishPage(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int type, index; + + if ( !SplitButtonID( info.ButtonID, 1, out type, out index ) ) + return; + + TextRelay entry = info.GetTextEntry( 0 ); + + if ( entry != null ) + m_Batch.Condition = entry.Text; + + for ( int i = m_Batch.BatchCommands.Count - 1; i >= 0; --i ) + { + BatchCommand sc = (BatchCommand)m_Batch.BatchCommands[i]; + + entry = info.GetTextEntry( 1 + (i * 2) ); + + if ( entry != null ) + sc.Command = entry.Text; + + entry = info.GetTextEntry( 2 + (i * 2) ); + + if ( entry != null ) + sc.Object = entry.Text; + + if ( sc.Command.Length == 0 && sc.Object.Length == 0 ) + m_Batch.BatchCommands.RemoveAt( i ); + } + + switch ( type ) + { + case 0: // main + { + switch ( index ) + { + case 0: // run + { + m_Batch.Run( m_From ); + break; + } + case 1: // set scope + { + m_From.SendGump( new BatchScopeGump( m_From, m_Batch ) ); + return; + } + case 2: // add command + { + m_Batch.BatchCommands.Add( new BatchCommand( "", "" ) ); + break; + } + } + + break; + } + } + + m_From.SendGump( new BatchGump( m_From, m_Batch ) ); + } + } + + public class BatchScopeGump : BaseGridGump + { + private Mobile m_From; + private Batch m_Batch; + + public BatchScopeGump( Mobile from, Batch batch ) : base( 30, 30 ) + { + m_From = from; + m_Batch = batch; + + Render(); + } + + public void Render() + { + AddNewPage(); + + /* Header */ + AddEntryHeader( 20 ); + AddEntryHtml( 140, Center( "Change Scope" ) ); + AddEntryHeader( 20 ); + + /* Options */ + for ( int i = 0; i < BaseCommandImplementor.Implementors.Count; ++i ) + { + BaseCommandImplementor impl = BaseCommandImplementor.Implementors[i]; + + if ( m_From.AccessLevel < impl.AccessLevel ) + continue; + + AddNewLine(); + + AddEntryLabel( 20 + OffsetSize + 140, impl.Accessors[0] ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, GetButtonID( 1, 0, i ), ArrowRightWidth, ArrowRightHeight ); + } + + FinishPage(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int type, index; + + if ( SplitButtonID( info.ButtonID, 1, out type, out index ) ) + { + switch ( type ) + { + case 0: + { + if ( index < BaseCommandImplementor.Implementors.Count ) + { + BaseCommandImplementor impl = BaseCommandImplementor.Implementors[index]; + + if ( m_From.AccessLevel >= impl.AccessLevel ) + m_Batch.Scope = impl; + } + + break; + } + } + } + + m_From.SendGump( new BatchGump( m_From, m_Batch ) ); + } + } +} diff --git a/Scripts/Commands/BoundingBoxPicker.cs b/Scripts/Commands/BoundingBoxPicker.cs new file mode 100644 index 0000000..c7a6352 --- /dev/null +++ b/Scripts/Commands/BoundingBoxPicker.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server +{ + public delegate void BoundingBoxCallback( Mobile from, Map map, Point3D start, Point3D end, object state ); + + public class BoundingBoxPicker + { + public static void Begin( Mobile from, BoundingBoxCallback callback, object state ) + { + from.SendMessage( "Target the first location of the bounding box." ); + from.Target = new PickTarget( callback, state ); + } + + private class PickTarget : Target + { + private Point3D m_Store; + private bool m_First; + private Map m_Map; + private BoundingBoxCallback m_Callback; + private object m_State; + + public PickTarget( BoundingBoxCallback callback, object state ) : this( Point3D.Zero, true, null, callback, state ) + { + } + + public PickTarget( Point3D store, bool first, Map map, BoundingBoxCallback callback, object state ) : base( -1, true, TargetFlags.None ) + { + m_Store = store; + m_First = first; + m_Map = map; + m_Callback = callback; + m_State = state; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + else if ( p is Item ) + p = ((Item)p).GetWorldTop(); + + if ( m_First ) + { + from.SendMessage( "Target another location to complete the bounding box." ); + from.Target = new PickTarget( new Point3D( p ), false, from.Map, m_Callback, m_State ); + } + else if ( from.Map != m_Map ) + { + from.SendMessage( "Both locations must reside on the same map." ); + } + else if ( m_Map != null && m_Map != Map.Internal && m_Callback != null ) + { + Point3D start = m_Store; + Point3D end = new Point3D( p ); + + Utility.FixPoints( ref start, ref end ); + + m_Callback( from, m_Map, start, end, m_State ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/ConvertPlayers.cs b/Scripts/Commands/ConvertPlayers.cs new file mode 100644 index 0000000..3dac3e4 --- /dev/null +++ b/Scripts/Commands/ConvertPlayers.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Commands +{ + public class ConvertPlayers + { + public static void Initialize() + { + CommandSystem.Register( "ConvertPlayers", AccessLevel.Administrator, new CommandEventHandler( Convert_OnCommand ) ); + } + + public static void Convert_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Converting all players to PlayerMobile. You will be disconnected. Please Restart the server after the world has finished saving." ); + List mobs = new List( World.Mobiles.Values ); + int count = 0; + + foreach ( Mobile m in mobs ) + { + if ( m.Player && !(m is PlayerMobile ) ) + { + count++; + if ( m.NetState != null ) + m.NetState.Dispose(); + + PlayerMobile pm = new PlayerMobile( m.Serial ); + pm.DefaultMobileInit(); + + List copy = new List( m.Items ); + for (int i=0;i 0 ) + { + NetState.ProcessDisposedQueue(); + World.Save(); + + Console.WriteLine( "{0} players have been converted to PlayerMobile. {1}.", count, Core.Service ? "The server is now restarting" : "Press any key to restart the server" ); + + if ( !Core.Service ) + Console.ReadKey( true ); + + Core.Kill( true ); + } + else + { + e.Mobile.SendMessage( "Couldn't find any Players to convert." ); + } + } + + private static void CopyProps( Mobile to, Mobile from ) + { + Type type = typeof( Mobile ); + + PropertyInfo[] props = type.GetProperties( BindingFlags.Public | BindingFlags.Instance ); + + for (int p=0;p= 0 ) + { + labelNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + break; + } + } + } + + item = new LocalizedSign( m_ItemID, labelNumber ); + } + else if ( m_Type == typeofAnkhWest || m_Type == typeofAnkhNorth ) + { + bool bloodied = false; + + for ( int i = 0; !bloodied && i < m_Params.Length; ++i ) + bloodied = ( m_Params[i] == "Bloodied" ); + + if ( m_Type == typeofAnkhWest ) + item = new AnkhWest( bloodied ); + else + item = new AnkhNorth( bloodied ); + } + else if ( m_Type == typeofMarkContainer ) + { + bool bone = false; + bool locked = false; + Map map = Map.Malas; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i] == "Bone" ) + { + bone = true; + } + else if ( m_Params[i] == "Locked" ) + { + locked = true; + } + else if ( m_Params[i].StartsWith( "TargetMap" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + map = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + MarkContainer mc = new MarkContainer( bone, locked ); + + mc.TargetMap = map; + mc.Description = "strange location"; + + item = mc; + } + else if ( m_Type == typeofHintItem ) + { + int range = 0; + int messageNumber = 0; + string messageString = null; + int hintNumber = 0; + string hintString = null; + TimeSpan resetDelay = TimeSpan.Zero; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "WarningString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "WarningNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "HintString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + hintString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "HintNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + hintNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "ResetDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + resetDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + HintItem hi = new HintItem( m_ItemID, range, messageNumber, hintNumber ); + + hi.WarningString = messageString; + hi.HintString = hintString; + hi.ResetDelay = resetDelay; + + item = hi; + } + else if ( m_Type == typeofWarningItem ) + { + int range = 0; + int messageNumber = 0; + string messageString = null; + TimeSpan resetDelay = TimeSpan.Zero; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "WarningString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "WarningNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "ResetDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + resetDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + WarningItem wi = new WarningItem( m_ItemID, range, messageNumber ); + + wi.WarningString = messageString; + wi.ResetDelay = resetDelay; + + item = wi; + } + else if ( m_Type == typeofCannon ) + { + CannonDirection direction = CannonDirection.North; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "CannonDirection" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + direction = (CannonDirection)Enum.Parse( typeof( CannonDirection ), m_Params[i].Substring( ++indexOf ), true ); + } + } + + item = new Cannon( direction ); + } + else if ( m_Type == typeofSerpentPillar ) + { + string word = null; + Rectangle2D destination = new Rectangle2D(); + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Word" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + word = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "DestStart" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + destination.Start = Point2D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEnd" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + destination.End = Point2D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + item = new SerpentPillar( word, destination ); + } + else if ( m_Type.IsSubclassOf( typeofBeverage ) ) + { + BeverageType content = BeverageType.Liquor; + bool fill = false; + + for ( int i = 0; !fill && i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Content" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + content = (BeverageType)Enum.Parse( typeof( BeverageType ), m_Params[i].Substring( ++indexOf ), true ); + fill = true; + } + } + } + + if ( fill ) + item = (Item)Activator.CreateInstance( m_Type, new object[]{ content } ); + else + item = (Item)Activator.CreateInstance( m_Type ); + } + else if ( m_Type.IsSubclassOf( typeofBaseDoor ) ) + { + DoorFacing facing = DoorFacing.WestCW; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Facing" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + facing = (DoorFacing)Enum.Parse( typeof( DoorFacing ), m_Params[i].Substring( ++indexOf ), true ); + break; + } + } + } + + item = (Item)Activator.CreateInstance( m_Type, new object[]{ facing } ); + } + else + { + item = (Item)Activator.CreateInstance( m_Type ); + } + } + catch ( Exception e ) + { + throw new Exception( String.Format( "Bad type: {0}", m_Type ), e ); + } + + if ( item is BaseAddon ) + { + if ( item is MaabusCoffin ) + { + MaabusCoffin coffin = (MaabusCoffin)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "SpawnLocation" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + coffin.SpawnLocation = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + } + else if ( m_ItemID > 0 ) + { + List comps = ((BaseAddon)item).Components; + + for ( int i = 0; i < comps.Count; ++i ) + { + AddonComponent comp = (AddonComponent)comps[i]; + + if ( comp.Offset == Point3D.Zero ) + comp.ItemID = m_ItemID; + } + } + } + else if ( item is BaseLight ) + { + bool unlit = false, unprotected = false; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( !unlit && m_Params[i] == "Unlit" ) + unlit = true; + else if ( !unprotected && m_Params[i] == "Unprotected" ) + unprotected = true; + + if ( unlit && unprotected ) + break; + } + + if ( !unlit ) + ((BaseLight)item).Ignite(); + if ( !unprotected ) + ((BaseLight)item).Protected = true; + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is Server.Mobiles.Spawner ) + { + Server.Mobiles.Spawner sp = (Server.Mobiles.Spawner)item; + + sp.NextSpawn = TimeSpan.Zero; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Spawn" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.SpawnNames.Add( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MinDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.MinDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MaxDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.MaxDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "NextSpawn" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.NextSpawn = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Count" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Count = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Team" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Team = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "HomeRange" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.HomeRange = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Running" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Running = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Group" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Group = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + } + } + else if ( item is RecallRune ) + { + RecallRune rune = (RecallRune)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Description" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.Description = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Marked" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.Marked = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "TargetMap" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.TargetMap = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Target" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.Target = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + } + else if ( item is SkillTeleporter ) + { + SkillTeleporter tp = (SkillTeleporter)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Skill" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Skill = (SkillName)Enum.Parse( typeof( SkillName ), m_Params[i].Substring( ++indexOf ), true ); + } + else if ( m_Params[i].StartsWith( "RequiredFixedPoint" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if (indexOf >= 0) + tp.Required = Utility.ToInt32(m_Params[i].Substring(++indexOf)) * 0.1; + } + else if ( m_Params[i].StartsWith( "Required" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Required = Utility.ToDouble( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MessageString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MessageString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "MessageNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MessageNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "PointDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.PointDest = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MapDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MapDest = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Creatures" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Creatures = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SourceEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SourceEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.DestEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SoundID" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SoundID = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Delay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Delay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is KeywordTeleporter ) + { + KeywordTeleporter tp = (KeywordTeleporter)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Substring" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Substring = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Keyword" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Keyword = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "PointDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.PointDest = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MapDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MapDest = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Creatures" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Creatures = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SourceEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SourceEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.DestEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SoundID" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SoundID = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Delay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Delay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is Teleporter ) + { + Teleporter tp = (Teleporter)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "PointDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.PointDest = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MapDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MapDest = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Creatures" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Creatures = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SourceEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SourceEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.DestEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SoundID" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SoundID = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Delay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Delay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is FillableContainer ) + { + FillableContainer cont = (FillableContainer) item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "ContentType" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + cont.ContentType = (FillableContentType)Enum.Parse( typeof( FillableContentType ), m_Params[i].Substring( ++indexOf ), true ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( m_ItemID > 0 ) + { + item.ItemID = m_ItemID; + } + + item.Movable = false; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Light" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + item.Light = (LightType)Enum.Parse( typeof( LightType ), m_Params[i].Substring( ++indexOf ), true ); + } + else if ( m_Params[i].StartsWith( "Hue" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + int hue = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + + if ( item is DyeTub ) + ((DyeTub)item).DyedHue = hue; + else + item.Hue = hue; + } + } + else if ( m_Params[i].StartsWith( "Name" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + item.Name = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Amount" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + // Must supress stackable warnings + + bool wasStackable = item.Stackable; + + item.Stackable = true; + item.Amount = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + item.Stackable = wasStackable; + } + } + } + + return item; + } + + private static Queue m_DeleteQueue = new Queue(); + + private static bool FindItem( int x, int y, int z, Map map, Item srcItem ) + { + int itemID = srcItem.ItemID; + + bool res = false; + + IPooledEnumerable eable; + + if ( srcItem is BaseDoor ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 1 ); + + foreach ( Item item in eable ) + { + if ( !(item is BaseDoor) ) + continue; + + BaseDoor bd = (BaseDoor)item; + Point3D p; + int bdItemID; + + if ( bd.Open ) + { + p = new Point3D( bd.X - bd.Offset.X, bd.Y - bd.Offset.Y, bd.Z - bd.Offset.Z ); + bdItemID = bd.ClosedID; + } + else + { + p = bd.Location; + bdItemID = bd.ItemID; + } + + if ( p.X != x || p.Y != y ) + continue; + + if ( item.Z == z && bdItemID == itemID ) + res = true; + else if ( Math.Abs( item.Z - z ) < 8 ) + m_DeleteQueue.Enqueue( item ); + } + } + else if ( (TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.LightSource) != 0 ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + LightType lt = srcItem.Light; + string srcName = srcItem.ItemData.Name; + + foreach ( Item item in eable ) + { + if ( item.Z == z ) + { + if ( item.ItemID == itemID ) + { + if ( item.Light != lt ) + m_DeleteQueue.Enqueue( item ); + else + res = true; + } + else if ( (item.ItemData.Flags & TileFlag.LightSource) != 0 && item.ItemData.Name == srcName ) + { + m_DeleteQueue.Enqueue( item ); + } + } + } + } + else if ( srcItem is Teleporter || srcItem is FillableContainer || srcItem is BaseBook ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + Type type = srcItem.GetType(); + + foreach ( Item item in eable ) + { + if ( item.Z == z && item.ItemID == itemID ) + { + if ( item.GetType() != type ) + m_DeleteQueue.Enqueue( item ); + else + res = true; + } + } + } + else + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + foreach ( Item item in eable ) + { + if ( item.Z == z && item.ItemID == itemID ) + { + eable.Free(); + return true; + } + } + } + + eable.Free(); + + while ( m_DeleteQueue.Count > 0 ) + ((Item)m_DeleteQueue.Dequeue()).Delete(); + + return res; + } + + public int Generate( Map[] maps ) + { + int count = 0; + + Item item = null; + + for ( int i = 0; i < m_Entries.Count; ++i ) + { + DecorationEntry entry = (DecorationEntry)m_Entries[i]; + Point3D loc = entry.Location; + string extra = entry.Extra; + + for ( int j = 0; j < maps.Length; ++j ) + { + if ( item == null ) + item = Construct(); + + if ( item == null ) + continue; + + if ( FindItem( loc.X, loc.Y, loc.Z, maps[j], item ) ) + { + } + else + { + item.MoveToWorld( loc, maps[j] ); + ++count; + + if ( item is BaseDoor ) + { + IPooledEnumerable eable = maps[j].GetItemsInRange( loc, 1 ); + + Type itemType = item.GetType(); + + foreach ( Item link in eable ) + { + if ( link != item && link.Z == item.Z && link.GetType() == itemType ) + { + ((BaseDoor)item).Link = (BaseDoor)link; + ((BaseDoor)link).Link = (BaseDoor)item; + break; + } + } + + eable.Free(); + } + else if ( item is MarkContainer ) + { + try{ ((MarkContainer)item).Target = Point3D.Parse( extra ); } + catch{} + } + + item = null; + } + } + } + + if ( item != null ) + item.Delete(); + + return count; + } + + public static ArrayList ReadAll( string path ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + ArrayList list = new ArrayList(); + + for ( DecorationList v = Read( ip ); v != null; v = Read( ip ) ) + list.Add( v ); + + return list; + } + } + + private static string[] m_EmptyParams = new string[0]; + + public static DecorationList Read( StreamReader ip ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length > 0 && !line.StartsWith( "#" ) ) + break; + } + + if ( string.IsNullOrEmpty( line ) ) + return null; + + DecorationList list = new DecorationList(); + + int indexOf = line.IndexOf( ' ' ); + + list.m_Type = ScriptCompiler.FindTypeByName( line.Substring( 0, indexOf++ ), true ); + + if ( list.m_Type == null ) + throw new ArgumentException( String.Format( "Type not found for header: '{0}'", line ) ); + + line = line.Substring( indexOf ); + indexOf = line.IndexOf( '(' ); + if ( indexOf >= 0 ) + { + list.m_ItemID = Utility.ToInt32( line.Substring( 0, indexOf - 1 ) ); + + string parms = line.Substring( ++indexOf ); + + if ( line.EndsWith( ")" ) ) + parms = parms.Substring( 0, parms.Length - 1 ); + + list.m_Params = parms.Split( ';' ); + + for ( int i = 0; i < list.m_Params.Length; ++i ) + list.m_Params[i] = list.m_Params[i].Trim(); + } + else + { + list.m_ItemID = Utility.ToInt32( line ); + list.m_Params = m_EmptyParams; + } + + list.m_Entries = new ArrayList(); + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length == 0 ) + break; + + if ( line.StartsWith( "#" ) ) + continue; + + list.m_Entries.Add( new DecorationEntry( line ) ); + } + + return list; + } + } + + public class DecorationEntry + { + private Point3D m_Location; + private string m_Extra; + + public Point3D Location{ get{ return m_Location; } } + public string Extra{ get{ return m_Extra; } } + + public DecorationEntry( string line ) + { + string x, y, z; + + Pop( out x, ref line ); + Pop( out y, ref line ); + Pop( out z, ref line ); + + m_Location = new Point3D( Utility.ToInt32( x ), Utility.ToInt32( y ), Utility.ToInt32( z ) ); + m_Extra = line; + } + + public void Pop( out string v, ref string line ) + { + int space = line.IndexOf( ' ' ); + + if ( space >= 0 ) + { + v = line.Substring( 0, space++ ); + line = line.Substring( space ); + } + else + { + v = line; + line = ""; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/DecorateMag.cs b/Scripts/Commands/DecorateMag.cs new file mode 100644 index 0000000..8c0e2ee --- /dev/null +++ b/Scripts/Commands/DecorateMag.cs @@ -0,0 +1,1147 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Engines.Quests.Haven; +using Server.Engines.Quests.Necro; + +namespace Server.Commands +{ + public class DecorateMag + { + public static void Initialize() + { + CommandSystem.Register( "DecorateMag", AccessLevel.Administrator, new CommandEventHandler( DecorateMag_OnCommand ) ); + } + + [Usage( "DecorateMag" )] + [Description( "Generates world decoration." )] + private static void DecorateMag_OnCommand( CommandEventArgs e ) + { + m_Mobile = e.Mobile; + m_Count = 0; + + m_Mobile.SendMessage( "Generating world decoration, please wait." ); + + Generate( "Data/Decoration/RuinedMaginciaTram", Map.Trammel ); + Generate( "Data/Decoration/RuinedMaginciaFel", Map.Felucca ); + + + m_Mobile.SendMessage( "World generating complete. {0} items were generated.", m_Count ); + } + + public static void Generate( string folder, params Map[] maps ) + { + if ( !Directory.Exists( folder ) ) + return; + + string[] files = Directory.GetFiles( folder, "*.cfg" ); + + for ( int i = 0; i < files.Length; ++i ) + { + ArrayList list = DecorationListMag.ReadAll( files[i] ); + + for ( int j = 0; j < list.Count; ++j ) + m_Count += ((DecorationListMag)list[j]).Generate( maps ); + } + } + + private static Mobile m_Mobile; + private static int m_Count; + } + + public class DecorationListMag + { + private Type m_Type; + private int m_ItemID; + private string[] m_Params; + private ArrayList m_Entries; + + public DecorationListMag() + { + } + + private static Type typeofStatic = typeof( Static ); + private static Type typeofLocalizedStatic = typeof( LocalizedStatic ); + private static Type typeofBaseDoor = typeof( BaseDoor ); + private static Type typeofAnkhWest = typeof( AnkhWest ); + private static Type typeofAnkhNorth = typeof( AnkhNorth ); + private static Type typeofBeverage = typeof( BaseBeverage ); + private static Type typeofLocalizedSign = typeof( LocalizedSign ); + private static Type typeofMarkContainer = typeof( MarkContainer ); + private static Type typeofWarningItem = typeof( WarningItem ); + private static Type typeofHintItem = typeof( HintItem ); + private static Type typeofCannon = typeof( Cannon ); + private static Type typeofSerpentPillar = typeof( SerpentPillar ); + + public Item Construct() + { + if (m_Type == null) + return null; + + Item item; + + try + { + if ( m_Type == typeofStatic ) + { + item = new Static( m_ItemID ); + } + else if ( m_Type == typeofLocalizedStatic ) + { + int labelNumber = 0; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "LabelNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + labelNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + break; + } + } + } + + item = new LocalizedStatic( m_ItemID, labelNumber ); + } + else if ( m_Type == typeofLocalizedSign ) + { + int labelNumber = 0; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "LabelNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + labelNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + break; + } + } + } + + item = new LocalizedSign( m_ItemID, labelNumber ); + } + else if ( m_Type == typeofAnkhWest || m_Type == typeofAnkhNorth ) + { + bool bloodied = false; + + for ( int i = 0; !bloodied && i < m_Params.Length; ++i ) + bloodied = ( m_Params[i] == "Bloodied" ); + + if ( m_Type == typeofAnkhWest ) + item = new AnkhWest( bloodied ); + else + item = new AnkhNorth( bloodied ); + } + else if ( m_Type == typeofMarkContainer ) + { + bool bone = false; + bool locked = false; + Map map = Map.Malas; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i] == "Bone" ) + { + bone = true; + } + else if ( m_Params[i] == "Locked" ) + { + locked = true; + } + else if ( m_Params[i].StartsWith( "TargetMap" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + map = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + MarkContainer mc = new MarkContainer( bone, locked ); + + mc.TargetMap = map; + mc.Description = "strange location"; + + item = mc; + } + else if ( m_Type == typeofHintItem ) + { + int range = 0; + int messageNumber = 0; + string messageString = null; + int hintNumber = 0; + string hintString = null; + TimeSpan resetDelay = TimeSpan.Zero; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "WarningString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "WarningNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "HintString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + hintString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "HintNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + hintNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "ResetDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + resetDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + HintItem hi = new HintItem( m_ItemID, range, messageNumber, hintNumber ); + + hi.WarningString = messageString; + hi.HintString = hintString; + hi.ResetDelay = resetDelay; + + item = hi; + } + else if ( m_Type == typeofWarningItem ) + { + int range = 0; + int messageNumber = 0; + string messageString = null; + TimeSpan resetDelay = TimeSpan.Zero; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "WarningString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "WarningNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + messageNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "ResetDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + resetDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + WarningItem wi = new WarningItem( m_ItemID, range, messageNumber ); + + wi.WarningString = messageString; + wi.ResetDelay = resetDelay; + + item = wi; + } + else if ( m_Type == typeofCannon ) + { + CannonDirection direction = CannonDirection.North; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "CannonDirection" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + direction = (CannonDirection)Enum.Parse( typeof( CannonDirection ), m_Params[i].Substring( ++indexOf ), true ); + } + } + + item = new Cannon( direction ); + } + else if ( m_Type == typeofSerpentPillar ) + { + string word = null; + Rectangle2D destination = new Rectangle2D(); + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Word" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + word = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "DestStart" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + destination.Start = Point2D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEnd" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + destination.End = Point2D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + item = new SerpentPillar( word, destination ); + } + else if ( m_Type.IsSubclassOf( typeofBeverage ) ) + { + BeverageType content = BeverageType.Liquor; + bool fill = false; + + for ( int i = 0; !fill && i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Content" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + content = (BeverageType)Enum.Parse( typeof( BeverageType ), m_Params[i].Substring( ++indexOf ), true ); + fill = true; + } + } + } + + if ( fill ) + item = (Item)Activator.CreateInstance( m_Type, new object[]{ content } ); + else + item = (Item)Activator.CreateInstance( m_Type ); + } + else if ( m_Type.IsSubclassOf( typeofBaseDoor ) ) + { + DoorFacing facing = DoorFacing.WestCW; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Facing" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + facing = (DoorFacing)Enum.Parse( typeof( DoorFacing ), m_Params[i].Substring( ++indexOf ), true ); + break; + } + } + } + + item = (Item)Activator.CreateInstance( m_Type, new object[]{ facing } ); + } + else + { + item = (Item)Activator.CreateInstance( m_Type ); + } + } + catch ( Exception e ) + { + throw new Exception( String.Format( "Bad type: {0}", m_Type ), e ); + } + + if ( item is BaseAddon ) + { + if ( item is MaabusCoffin ) + { + MaabusCoffin coffin = (MaabusCoffin)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "SpawnLocation" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + coffin.SpawnLocation = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + } + else if ( m_ItemID > 0 ) + { + List comps = ((BaseAddon)item).Components; + + for ( int i = 0; i < comps.Count; ++i ) + { + AddonComponent comp = (AddonComponent)comps[i]; + + if ( comp.Offset == Point3D.Zero ) + comp.ItemID = m_ItemID; + } + } + } + else if ( item is BaseLight ) + { + bool unlit = false, unprotected = false; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( !unlit && m_Params[i] == "Unlit" ) + unlit = true; + else if ( !unprotected && m_Params[i] == "Unprotected" ) + unprotected = true; + + if ( unlit && unprotected ) + break; + } + + if ( !unlit ) + ((BaseLight)item).Ignite(); + if ( !unprotected ) + ((BaseLight)item).Protected = true; + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is Server.Mobiles.Spawner ) + { + Server.Mobiles.Spawner sp = (Server.Mobiles.Spawner)item; + + sp.NextSpawn = TimeSpan.Zero; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Spawn" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.SpawnNames.Add( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MinDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.MinDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MaxDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.MaxDelay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "NextSpawn" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.NextSpawn = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Count" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Count = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Team" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Team = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "HomeRange" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.HomeRange = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Running" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Running = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Group" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Group = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + } + } + else if ( item is RecallRune ) + { + RecallRune rune = (RecallRune)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Description" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.Description = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Marked" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.Marked = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "TargetMap" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.TargetMap = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Target" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + rune.Target = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + } + else if ( item is SkillTeleporter ) + { + SkillTeleporter tp = (SkillTeleporter)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Skill" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Skill = (SkillName)Enum.Parse( typeof( SkillName ), m_Params[i].Substring( ++indexOf ), true ); + } + else if ( m_Params[i].StartsWith( "RequiredFixedPoint" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Required = Utility.ToInt32(m_Params[i].Substring(++indexOf)) * 0.1; + } + else if ( m_Params[i].StartsWith( "Required" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Required = Utility.ToDouble( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MessageString" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MessageString = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "MessageNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MessageNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "PointDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.PointDest = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MapDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MapDest = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Creatures" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Creatures = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SourceEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SourceEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.DestEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SoundID" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SoundID = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Delay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Delay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is KeywordTeleporter ) + { + KeywordTeleporter tp = (KeywordTeleporter)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Substring" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Substring = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Keyword" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Keyword = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "PointDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.PointDest = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MapDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MapDest = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Creatures" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Creatures = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SourceEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SourceEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.DestEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SoundID" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SoundID = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Delay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Delay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is Teleporter ) + { + Teleporter tp = (Teleporter)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "PointDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.PointDest = Point3D.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "MapDest" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.MapDest = Map.Parse( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Creatures" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Creatures = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SourceEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SourceEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "DestEffect" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.DestEffect = Utility.ToBoolean( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "SoundID" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.SoundID = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "Delay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + tp.Delay = TimeSpan.Parse( m_Params[i].Substring( ++indexOf ) ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( item is FillableContainer ) + { + FillableContainer cont = (FillableContainer) item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "ContentType" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + cont.ContentType = (FillableContentType)Enum.Parse( typeof( FillableContentType ), m_Params[i].Substring( ++indexOf ), true ); + } + } + + if ( m_ItemID > 0 ) + item.ItemID = m_ItemID; + } + else if ( m_ItemID > 0 ) + { + item.ItemID = m_ItemID; + } + + item.Movable = false; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Light" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + item.Light = (LightType)Enum.Parse( typeof( LightType ), m_Params[i].Substring( ++indexOf ), true ); + } + else if ( m_Params[i].StartsWith( "Hue" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + int hue = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + + if ( item is DyeTub ) + ((DyeTub)item).DyedHue = hue; + else + item.Hue = hue; + } + } + else if ( m_Params[i].StartsWith( "Name" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + item.Name = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Amount" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + // Must supress stackable warnings + + bool wasStackable = item.Stackable; + + item.Stackable = true; + item.Amount = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + item.Stackable = wasStackable; + } + } + } + + return item; + } + + private static Queue m_DeleteQueue = new Queue(); + + private static bool FindItem( int x, int y, int z, Map map, Item srcItem ) + { + int itemID = srcItem.ItemID; + + bool res = false; + + IPooledEnumerable eable; + + if ( srcItem is BaseDoor ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 1 ); + + foreach ( Item item in eable ) + { + if ( !(item is BaseDoor) ) + continue; + + BaseDoor bd = (BaseDoor)item; + Point3D p; + int bdItemID; + + if ( bd.Open ) + { + p = new Point3D( bd.X - bd.Offset.X, bd.Y - bd.Offset.Y, bd.Z - bd.Offset.Z ); + bdItemID = bd.ClosedID; + } + else + { + p = bd.Location; + bdItemID = bd.ItemID; + } + + if ( p.X != x || p.Y != y ) + continue; + + if ( item.Z == z && bdItemID == itemID ) + res = true; + else if ( Math.Abs( item.Z - z ) < 8 ) + m_DeleteQueue.Enqueue( item ); + } + } + else if ( (TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.LightSource) != 0 ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + LightType lt = srcItem.Light; + string srcName = srcItem.ItemData.Name; + + foreach ( Item item in eable ) + { + if ( item.Z == z ) + { + if ( item.ItemID == itemID ) + { + if ( item.Light != lt ) + m_DeleteQueue.Enqueue( item ); + else + res = true; + } + else if ( (item.ItemData.Flags & TileFlag.LightSource) != 0 && item.ItemData.Name == srcName ) + { + m_DeleteQueue.Enqueue( item ); + } + } + } + } + else if ( srcItem is Teleporter || srcItem is FillableContainer || srcItem is BaseBook ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + Type type = srcItem.GetType(); + + foreach ( Item item in eable ) + { + if ( item.Z == z && item.ItemID == itemID ) + { + if ( item.GetType() != type ) + m_DeleteQueue.Enqueue( item ); + else + res = true; + } + } + } + else + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + foreach ( Item item in eable ) + { + if ( item.Z == z && item.ItemID == itemID ) + { + eable.Free(); + return true; + } + } + } + + eable.Free(); + + while ( m_DeleteQueue.Count > 0 ) + ((Item)m_DeleteQueue.Dequeue()).Delete(); + + return res; + } + + public int Generate( Map[] maps ) + { + int count = 0; + + Item item = null; + + for ( int i = 0; i < m_Entries.Count; ++i ) + { + DecorationEntryMag entry = (DecorationEntryMag)m_Entries[i]; + Point3D loc = entry.Location; + string extra = entry.Extra; + + for ( int j = 0; j < maps.Length; ++j ) + { + if ( item == null ) + item = Construct(); + + if ( item == null ) + continue; + + if ( FindItem( loc.X, loc.Y, loc.Z, maps[j], item ) ) + { + } + else + { + item.MoveToWorld( loc, maps[j] ); + ++count; + + if ( item is BaseDoor ) + { + IPooledEnumerable eable = maps[j].GetItemsInRange( loc, 1 ); + + Type itemType = item.GetType(); + + foreach ( Item link in eable ) + { + if ( link != item && link.Z == item.Z && link.GetType() == itemType ) + { + ((BaseDoor)item).Link = (BaseDoor)link; + ((BaseDoor)link).Link = (BaseDoor)item; + break; + } + } + + eable.Free(); + } + else if ( item is MarkContainer ) + { + try{ ((MarkContainer)item).Target = Point3D.Parse( extra ); } + catch{} + } + + item = null; + } + } + } + + if ( item != null ) + item.Delete(); + + return count; + } + + public static ArrayList ReadAll( string path ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + ArrayList list = new ArrayList(); + + for ( DecorationListMag v = Read( ip ); v != null; v = Read( ip ) ) + list.Add( v ); + + return list; + } + } + + private static string[] m_EmptyParams = new string[0]; + + public static DecorationListMag Read( StreamReader ip ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length > 0 && !line.StartsWith( "#" ) ) + break; + } + + if ( string.IsNullOrEmpty( line ) ) + return null; + + DecorationListMag list = new DecorationListMag(); + + int indexOf = line.IndexOf( ' ' ); + + list.m_Type = ScriptCompiler.FindTypeByName( line.Substring( 0, indexOf++ ), true ); + + if ( list.m_Type == null ) + throw new ArgumentException( String.Format( "Type not found for header: '{0}'", line ) ); + + line = line.Substring( indexOf ); + indexOf = line.IndexOf( '(' ); + if ( indexOf >= 0 ) + { + list.m_ItemID = Utility.ToInt32( line.Substring( 0, indexOf - 1 ) ); + + string parms = line.Substring( ++indexOf ); + + if ( line.EndsWith( ")" ) ) + parms = parms.Substring( 0, parms.Length - 1 ); + + list.m_Params = parms.Split( ';' ); + + for ( int i = 0; i < list.m_Params.Length; ++i ) + list.m_Params[i] = list.m_Params[i].Trim(); + } + else + { + list.m_ItemID = Utility.ToInt32( line ); + list.m_Params = m_EmptyParams; + } + + list.m_Entries = new ArrayList(); + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length == 0 ) + break; + + if ( line.StartsWith( "#" ) ) + continue; + + list.m_Entries.Add( new DecorationEntryMag( line ) ); + } + + return list; + } + } + + public class DecorationEntryMag + { + private Point3D m_Location; + private string m_Extra; + + public Point3D Location{ get{ return m_Location; } } + public string Extra{ get{ return m_Extra; } } + + public DecorationEntryMag( string line ) + { + string x, y, z; + + Pop( out x, ref line ); + Pop( out y, ref line ); + Pop( out z, ref line ); + + m_Location = new Point3D( Utility.ToInt32( x ), Utility.ToInt32( y ), Utility.ToInt32( z ) ); + m_Extra = line; + } + + public void Pop( out string v, ref string line ) + { + int space = line.IndexOf( ' ' ); + + if ( space >= 0 ) + { + v = line.Substring( 0, space++ ); + line = line.Substring( space ); + } + else + { + v = line; + line = ""; + } + } + } +} diff --git a/Scripts/Commands/Docs.cs b/Scripts/Commands/Docs.cs new file mode 100644 index 0000000..cf47111 --- /dev/null +++ b/Scripts/Commands/Docs.cs @@ -0,0 +1,2608 @@ +using System; +using System.IO; +using System.Text; +using System.Reflection; +using System.Collections; +using Server; +using Server.Items; +using Server.Engines.BulkOrders; +using Server.Commands.Generic; +using System.Collections.Generic; + +namespace Server.Commands +{ + public class Docs + { + public static void Initialize() + { + CommandSystem.Register( "DocGen", AccessLevel.Administrator, new CommandEventHandler( DocGen_OnCommand ) ); + } + + [Usage( "DocGen" )] + [Description( "Generates RunUO documentation." )] + private static void DocGen_OnCommand( CommandEventArgs e ) + { + World.Broadcast( 0x35, true, "Documentation is being generated, please wait." ); + Console.WriteLine( "Documentation is being generated, please wait." ); + + Network.NetState.FlushAll(); + Network.NetState.Pause(); + + DateTime startTime = DateTime.Now; + + bool generated = Document(); + + DateTime endTime = DateTime.Now; + + Network.NetState.Resume(); + + if( generated ) + { + World.Broadcast( 0x35, true, "Documentation has been completed. The entire process took {0:F1} seconds.", (endTime - startTime).TotalSeconds ); + Console.WriteLine( "Documentation complete." ); + } + else + { + World.Broadcast( 0x35, true, "Docmentation failed: Documentation directories are locked and in use. Please close all open files and directories and try again." ); + Console.WriteLine( "Documentation failed." ); + } + } + + private class MemberComparer : IComparer + { + public int Compare( object x, object y ) + { + if( x == y ) + return 0; + + ConstructorInfo aCtor = x as ConstructorInfo; + ConstructorInfo bCtor = y as ConstructorInfo; + + PropertyInfo aProp = x as PropertyInfo; + PropertyInfo bProp = y as PropertyInfo; + + MethodInfo aMethod = x as MethodInfo; + MethodInfo bMethod = y as MethodInfo; + + bool aStatic = GetStaticFor( aCtor, aProp, aMethod ); + bool bStatic = GetStaticFor( bCtor, bProp, bMethod ); + + if( aStatic && !bStatic ) + return -1; + else if( !aStatic && bStatic ) + return 1; + + int v = 0; + + if( aCtor != null ) + { + if( bCtor == null ) + v = -1; + } + else if( bCtor != null ) + { + if( aCtor == null ) + v = 1; + } + else if( aProp != null ) + { + if( bProp == null ) + v = -1; + } + else if( bProp != null ) + { + if( aProp == null ) + v = 1; + } + + if( v == 0 ) + { + v = GetNameFrom( aCtor, aProp, aMethod ).CompareTo( GetNameFrom( bCtor, bProp, bMethod ) ); + } + + if( v == 0 && aCtor != null && bCtor != null ) + { + v = aCtor.GetParameters().Length.CompareTo( bCtor.GetParameters().Length ); + } + else if( v == 0 && aMethod != null && bMethod != null ) + { + v = aMethod.GetParameters().Length.CompareTo( bMethod.GetParameters().Length ); + } + + return v; + } + + private bool GetStaticFor( ConstructorInfo ctor, PropertyInfo prop, MethodInfo method ) + { + if( ctor != null ) + return ctor.IsStatic; + else if( method != null ) + return method.IsStatic; + + if( prop != null ) + { + MethodInfo getMethod = prop.GetGetMethod(); + MethodInfo setMethod = prop.GetGetMethod(); + + return (getMethod != null && getMethod.IsStatic) || (setMethod != null && setMethod.IsStatic); + } + + return false; + } + + private string GetNameFrom( ConstructorInfo ctor, PropertyInfo prop, MethodInfo method ) + { + if( ctor != null ) + return ctor.DeclaringType.Name; + else if( prop != null ) + return prop.Name; + else if( method != null ) + return method.Name; + else + return ""; + } + } + + private class TypeComparer : IComparer + { + public int Compare( TypeInfo x, TypeInfo y ) + { + if( x == null && y == null ) + return 0; + else if( x == null ) + return -1; + else if( y == null ) + return 1; + + return x.TypeName.CompareTo( y.TypeName ); + } + } + + private class TypeInfo + { + public Type m_Type, m_BaseType, m_Declaring; + public List m_Derived, m_Nested; + public Type[] m_Interfaces; + private string m_FileName, m_TypeName, m_LinkName; + + public TypeInfo( Type type ) + { + m_Type = type; + + m_BaseType = type.BaseType; + m_Declaring = type.DeclaringType; + m_Interfaces = type.GetInterfaces(); + + FormatGeneric( m_Type, ref m_TypeName, ref m_FileName, ref m_LinkName ); + + // Console.WriteLine( ">> inline typeinfo: "+m_TypeName ); + // m_TypeName = GetGenericTypeName( m_Type ); + // m_FileName = Docs.GetFileName( "docs/types/", GetGenericTypeName( m_Type, "-", "-" ), ".html" ); + // m_Writer = Docs.GetWriter( "docs/types/", m_FileName ); + } + + public string FileName { get { return m_FileName; } } + public string TypeName { get { return m_TypeName; } } + + public string LinkName( string dirRoot ) + { + return m_LinkName.Replace( "@directory@", dirRoot ); + } + } + + #region FileSystem + private static readonly char[] ReplaceChars = "<>".ToCharArray(); + + public static string GetFileName( string root, string name, string ext ) + { + if( name.IndexOfAny( ReplaceChars ) >= 0 ) + { + StringBuilder sb = new StringBuilder( name ); + + for( int i = 0; i < ReplaceChars.Length; ++i ) + { + sb.Replace( ReplaceChars[i], '-' ); + } + + name = sb.ToString(); + } + + int index = 0; + string file = String.Concat( name, ext ); + + while( File.Exists( Path.Combine( root, file ) ) ) + { + file = String.Concat( name, ++index, ext ); + } + + return file; + } + + private static string m_RootDirectory = Path.GetDirectoryName( Environment.GetCommandLineArgs()[0] ); + + private static void EnsureDirectory( string path ) + { + path = Path.Combine( m_RootDirectory, path ); + + if( !Directory.Exists( path ) ) + Directory.CreateDirectory( path ); + } + + private static void DeleteDirectory( string path ) + { + path = Path.Combine( m_RootDirectory, path ); + + if( Directory.Exists( path ) ) + Directory.Delete( path, true ); + } + + private static StreamWriter GetWriter( string root, string name ) + { + return new StreamWriter( Path.Combine( Path.Combine( m_RootDirectory, root ), name ) ); + } + + private static StreamWriter GetWriter( string path ) + { + return new StreamWriter( Path.Combine( m_RootDirectory, path ) ); + } + #endregion + + #region GetPair + + private static string[,] m_Aliases = new string[,] + { + { "System.Object", "object" }, + { "System.String", "string" }, + { "System.Boolean", "bool" }, + { "System.Byte", "byte" }, + { "System.SByte", "sbyte" }, + { "System.Int16", "short" }, + { "System.UInt16", "ushort" }, + { "System.Int32", "int" }, + { "System.UInt32", "uint" }, + { "System.Int64", "long" }, + { "System.UInt64", "ulong" }, + { "System.Single", "float" }, + { "System.Double", "double" }, + { "System.Decimal", "decimal" }, + { "System.Char", "char" }, + { "System.Void", "void" }, + }; + + private static int m_AliasLength = m_Aliases.GetLength( 0 ); + + public static string GetPair( Type varType, string name, bool ignoreRef ) + { + string prepend = ""; + StringBuilder append = new StringBuilder(); + + Type realType = varType; + + if( varType.IsByRef ) + { + if( !ignoreRef ) + prepend = RefString; + + realType = varType.GetElementType(); + } + + if( realType.IsPointer ) + { + if( realType.IsArray ) + { + append.Append( '*' ); + + do + { + append.Append( '[' ); + + for( int i = 1; i < realType.GetArrayRank(); ++i ) + append.Append( ',' ); + + append.Append( ']' ); + + realType = realType.GetElementType(); + } while( realType.IsArray ); + + append.Append( ' ' ); + } + else + { + realType = realType.GetElementType(); + append.Append( " *" ); + } + } + else if( realType.IsArray ) + { + do + { + append.Append( '[' ); + + for( int i = 1; i < realType.GetArrayRank(); ++i ) + append.Append( ',' ); + + append.Append( ']' ); + + realType = realType.GetElementType(); + } while( realType.IsArray ); + + append.Append( ' ' ); + } + else + { + append.Append( ' ' ); + } + + string fullName = realType.FullName; + string aliased = null;// = realType.Name; + + TypeInfo info = null; + m_Types.TryGetValue( realType, out info ); + + if( info != null ) + { + aliased = ""+info.LinkName( null ); + //aliased = String.Format( "{1}", info.m_FileName, info.m_TypeName ); + } + else + { + //FormatGeneric( ); + if( realType.IsGenericType ) + { + string typeName = ""; + string fileName = ""; + string linkName = ""; + + FormatGeneric( realType, ref typeName, ref fileName, ref linkName ); + linkName = linkName.Replace( "@directory@", null ); + aliased = linkName; + } + else + { + for( int i = 0; i < m_AliasLength; ++i ) + { + if( m_Aliases[i, 0] == fullName ) + { + aliased = m_Aliases[i, 1]; + break; + } + } + } + + if( aliased == null ) + aliased = realType.Name; + } + + string retval = String.Concat( prepend, aliased, append, name ); + //Console.WriteLine(">> getpair: "+retval); + return retval; + } + + #endregion + + private static Dictionary m_Types; + private static Dictionary> m_Namespaces; + + #region Root documentation + + private static bool Document() + { + try { DeleteDirectory( "docs/" ); } + catch { return false; } + + EnsureDirectory( "docs/" ); + EnsureDirectory( "docs/namespaces/" ); + EnsureDirectory( "docs/types/" ); + EnsureDirectory( "docs/bods/" ); + + GenerateStyles(); + GenerateIndex(); + + DocumentCommands(); + DocumentKeywords(); + DocumentBodies(); + + DocumentBulkOrders(); + + m_Types = new Dictionary(); + m_Namespaces = new Dictionary>(); + + List assemblies = new List(); + + assemblies.Add( Core.Assembly ); + + foreach( Assembly asm in ScriptCompiler.Assemblies ) + assemblies.Add( asm ); + + Assembly[] asms = assemblies.ToArray(); + + for( int i = 0; i < asms.Length; ++i ) + LoadTypes( asms[i], asms ); + + DocumentLoadedTypes(); + DocumentConstructableObjects(); + + return true; + } + + private static void AddIndexLink( StreamWriter html, string filePath, string label, string desc ) + { + html.WriteLine( "

{2}

", filePath, desc, label ); + } + + private static void GenerateStyles() + { + using( StreamWriter css = GetWriter( "docs/", "styles.css" ) ) + { + css.WriteLine( "body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }" ); + css.WriteLine( "a { color: #28435E; }" ); + css.WriteLine( "a:hover { color: #4878A9; }" ); + css.WriteLine( "td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }" ); + css.WriteLine( "td.lentry { background-color: #D7D7EB; width: 10%; }" ); + css.WriteLine( "td.rentry { background-color: #FFFFFF; width: 90%; }" ); + css.WriteLine( "td.entry { background-color: #FFFFFF; }" ); + css.WriteLine( "td { font-size: 11px; }" ); + css.WriteLine( ".tbl-border { background-color: #46465A; }" ); + + css.WriteLine( "td.ir {{ background-color: #{0:X6}; }}", Iron ); + css.WriteLine( "td.du {{ background-color: #{0:X6}; }}", DullCopper ); + css.WriteLine( "td.sh {{ background-color: #{0:X6}; }}", ShadowIron ); + css.WriteLine( "td.co {{ background-color: #{0:X6}; }}", Copper ); + css.WriteLine( "td.br {{ background-color: #{0:X6}; }}", Bronze ); + css.WriteLine( "td.go {{ background-color: #{0:X6}; }}", Gold ); + css.WriteLine( "td.ag {{ background-color: #{0:X6}; }}", Agapite ); + css.WriteLine( "td.ve {{ background-color: #{0:X6}; }}", Verite ); + css.WriteLine( "td.va {{ background-color: #{0:X6}; }}", Valorite ); + + css.WriteLine( "td.cl {{ background-color: #{0:X6}; }}", Cloth ); + css.WriteLine( "td.pl {{ background-color: #{0:X6}; }}", Plain ); + css.WriteLine( "td.sp {{ background-color: #{0:X6}; }}", Core.AOS ? SpinedAOS : SpinedLBR ); + css.WriteLine( "td.ho {{ background-color: #{0:X6}; }}", Core.AOS ? HornedAOS : HornedLBR ); + css.WriteLine( "td.ba {{ background-color: #{0:X6}; }}", Core.AOS ? BarbedAOS : BarbedLBR ); + } + } + + private static void GenerateIndex() + { + using( StreamWriter html = GetWriter( "docs/", "index.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Index" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + + AddIndexLink( html, "commands.html", "Commands", "Every available command. This contains command name, usage, aliases, and description." ); + AddIndexLink( html, "objects.html", "Constructable Objects", "Every constructable item or npc. This contains object name and usage. Hover mouse over parameters to see type description." ); + AddIndexLink( html, "keywords.html", "Speech Keywords", "Lists speech keyword numbers and associated match patterns. These are used in some scripts for multi-language matching of client speech." ); + AddIndexLink( html, "bodies.html", "Body List", "Every usable body number and name. Table is generated from a UO:3D client datafile. If you do not have UO:3D installed, this may be blank." ); + AddIndexLink( html, "overview.html", "Class Overview", "Scripting reference. Contains every class type and contained methods in the core and scripts." ); + AddIndexLink( html, "bods/bod_smith_rewards.html", "Bulk Order Rewards: Smithing", "Reference table for large and small smithing bulk order deed rewards." ); + AddIndexLink( html, "bods/bod_tailor_rewards.html", "Bulk Order Rewards: Tailoring", "Reference table for large and small tailoring bulk order deed rewards." ); + + html.WriteLine( " " ); + html.WriteLine( "" ); + } + } + + #endregion + + #region BODs + + private const int Iron = 0xCCCCDD; + private const int DullCopper = 0xAAAAAA; + private const int ShadowIron = 0x777799; + private const int Copper = 0xDDCC99; + private const int Bronze = 0xAA8866; + private const int Gold = 0xDDCC55; + private const int Agapite = 0xDDAAAA; + private const int Verite = 0x99CC77; + private const int Valorite = 0x88AABB; + + private const int Cloth = 0xDDDDDD; + private const int Plain = 0xCCAA88; + private const int SpinedAOS = 0x99BBBB; + private const int HornedAOS = 0xCC8888; + private const int BarbedAOS = 0xAABBAA; + private const int SpinedLBR = 0xAA8833; + private const int HornedLBR = 0xBBBBAA; + private const int BarbedLBR = 0xCCAA88; + + private static void DocumentBulkOrders() + { + using( StreamWriter html = GetWriter( "docs/bods/", "bod_smith_rewards.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Bulk Orders - Smith Rewards" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + + SmallBOD sbod = new SmallSmithBOD(); + + sbod.Type = typeof( Katana ); + sbod.Material = BulkMaterialType.None; + sbod.AmountMax = 10; + + WriteSmithBODHeader( html, "(Small) Weapons" ); + sbod.RequireExceptional = false; + DocumentSmithBOD( html, sbod.ComputeRewards( true ), "10, 15, 20: Normal", sbod.Material ); + sbod.RequireExceptional = true; + DocumentSmithBOD( html, sbod.ComputeRewards( true ), "10, 15, 20: Exceptional", sbod.Material ); + WriteSmithBODFooter( html ); + + html.WriteLine( "

" ); + html.WriteLine( "

" ); + + + sbod.Type = typeof( PlateArms ); + + WriteSmithBODHeader( html, "(Small) Armor: Normal" ); + + sbod.RequireExceptional = false; + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat ) + { + sbod.Material = mat; + sbod.AmountMax = 10; + DocumentSmithBOD( html, sbod.ComputeRewards( true ), "10, 15, 20", sbod.Material ); + } + + WriteSmithBODFooter( html ); + + html.WriteLine( "

" ); + + WriteSmithBODHeader( html, "(Small) Armor: Exceptional" ); + + sbod.RequireExceptional = true; + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat ) + { + sbod.Material = mat; + + for( int amt = 15; amt <= 20; amt += 5 ) + { + sbod.AmountMax = amt; + DocumentSmithBOD( html, sbod.ComputeRewards( true ), amt == 20 ? "20" : "10, 15", sbod.Material ); + } + } + + WriteSmithBODFooter( html ); + + html.WriteLine( "

" ); + html.WriteLine( "

" ); + + sbod.Delete(); + + WriteSmithLBOD( html, "Ringmail", LargeBulkEntry.LargeRing ); + WriteSmithLBOD( html, "Chainmail", LargeBulkEntry.LargeChain ); + WriteSmithLBOD( html, "Platemail", LargeBulkEntry.LargePlate ); + + html.WriteLine( " " ); + html.WriteLine( "" ); + } + + using( StreamWriter html = GetWriter( "docs/bods/", "bod_tailor_rewards.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Bulk Orders - Tailor Rewards" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + + SmallBOD sbod = new SmallTailorBOD(); + + WriteTailorBODHeader( html, "Small Bulk Order" ); + + html.WriteLine( " " ); + html.WriteLine( " Regular: 10, 15" ); + html.WriteLine( " " ); + + sbod.AmountMax = 10; + sbod.RequireExceptional = false; + + sbod.Type = typeof( SkullCap ); + sbod.Material = BulkMaterialType.None; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "10, 15", sbod.Material, sbod.Type ); + + sbod.Type = typeof( LeatherCap ); + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat ) + { + if( mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite ) + continue; + + sbod.Material = mat; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "10, 15", sbod.Material, sbod.Type ); + } + + html.WriteLine( " " ); + html.WriteLine( " Regular: 20" ); + html.WriteLine( " " ); + + sbod.AmountMax = 20; + sbod.RequireExceptional = false; + + sbod.Type = typeof( SkullCap ); + sbod.Material = BulkMaterialType.None; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "20", sbod.Material, sbod.Type ); + + sbod.Type = typeof( LeatherCap ); + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat ) + { + if( mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite ) + continue; + + sbod.Material = mat; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "20", sbod.Material, sbod.Type ); + } + + html.WriteLine( " " ); + html.WriteLine( " Exceptional: 10, 15" ); + html.WriteLine( " " ); + + sbod.AmountMax = 10; + sbod.RequireExceptional = true; + + sbod.Type = typeof( SkullCap ); + sbod.Material = BulkMaterialType.None; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "10, 15", sbod.Material, sbod.Type ); + + sbod.Type = typeof( LeatherCap ); + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat ) + { + if( mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite ) + continue; + + sbod.Material = mat; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "10, 15", sbod.Material, sbod.Type ); + } + + html.WriteLine( " " ); + html.WriteLine( " Exceptional: 20" ); + html.WriteLine( " " ); + + sbod.AmountMax = 20; + sbod.RequireExceptional = true; + + sbod.Type = typeof( SkullCap ); + sbod.Material = BulkMaterialType.None; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "20", sbod.Material, sbod.Type ); + + sbod.Type = typeof( LeatherCap ); + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat ) + { + if( mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite ) + continue; + + sbod.Material = mat; + DocumentTailorBOD( html, sbod.ComputeRewards( true ), "20", sbod.Material, sbod.Type ); + } + + WriteTailorBODFooter( html ); + + html.WriteLine( "

" ); + html.WriteLine( "

" ); + + sbod.Delete(); + + WriteTailorLBOD( html, "Large Bulk Order: 4-part", LargeBulkEntry.Gypsy, true, true ); + WriteTailorLBOD( html, "Large Bulk Order: 5-part", LargeBulkEntry.TownCrier, true, true ); + WriteTailorLBOD( html, "Large Bulk Order: 6-part", LargeBulkEntry.MaleLeatherSet, false, true ); + + html.WriteLine( " " ); + html.WriteLine( "" ); + } + } + + #region Tailor Bods + private static void WriteTailorLBOD( StreamWriter html, string name, SmallBulkEntry[] entries, bool expandCloth, bool expandPlain ) + { + WriteTailorBODHeader( html, name ); + + LargeBOD lbod = new LargeTailorBOD(); + + lbod.Entries = LargeBulkEntry.ConvertEntries( lbod, entries ); + + Type type = entries[0].Type; + + bool showCloth = !(type.IsSubclassOf( typeof( BaseArmor ) ) || type.IsSubclassOf( typeof( BaseShoes ) )); + + html.WriteLine( " " ); + html.WriteLine( " Regular" ); + html.WriteLine( " " ); + + lbod.RequireExceptional = false; + lbod.AmountMax = 10; + + if( showCloth ) + { + lbod.Material = BulkMaterialType.None; + + if( expandCloth ) + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15", lbod.Material, type ); + lbod.AmountMax = 20; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "20", lbod.Material, type ); + } + else + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material, type ); + } + } + + lbod.Material = BulkMaterialType.None; + + if( expandPlain ) + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material, typeof( LeatherCap ) ); + lbod.AmountMax = 20; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "20", lbod.Material, typeof( LeatherCap ) ); + } + else + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material, typeof( LeatherCap ) ); + } + + for( BulkMaterialType mat = BulkMaterialType.Spined; mat <= BulkMaterialType.Barbed; ++mat ) + { + lbod.Material = mat; + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15", lbod.Material, type ); + lbod.AmountMax = 20; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "20", lbod.Material, type ); + } + + html.WriteLine( " " ); + html.WriteLine( " Exceptional" ); + html.WriteLine( " " ); + + lbod.RequireExceptional = true; + lbod.AmountMax = 10; + + if( showCloth ) + { + lbod.Material = BulkMaterialType.None; + + if( expandCloth ) + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15", lbod.Material, type ); + lbod.AmountMax = 20; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "20", lbod.Material, type ); + } + else + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material, type ); + } + } + + lbod.Material = BulkMaterialType.None; + + if( expandPlain ) + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material, typeof( LeatherCap ) ); + lbod.AmountMax = 20; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "20", lbod.Material, typeof( LeatherCap ) ); + } + else + { + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material, typeof( LeatherCap ) ); + } + + for( BulkMaterialType mat = BulkMaterialType.Spined; mat <= BulkMaterialType.Barbed; ++mat ) + { + lbod.Material = mat; + lbod.AmountMax = 10; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "10, 15", lbod.Material, type ); + lbod.AmountMax = 20; + DocumentTailorBOD( html, lbod.ComputeRewards( true ), "20", lbod.Material, type ); + } + + WriteTailorBODFooter( html ); + + html.WriteLine( "

" ); + html.WriteLine( "

" ); + } + + private static void WriteTailorBODHeader( StreamWriter html, string title ) + { + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " ", title ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + } + + private static void WriteTailorBODFooter( StreamWriter html ) + { + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "
{0}
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
Power Scrolls
\"Small
\"Medium
\"Light
\"Dark
\"Brown
\"Polar
\"Clothing
Runic Kits
+5
+10
+15
+20
\"Runic
\"Runic
\"Runic
 
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
+5
+10
+15
+20
\"Small
\"Medium
\"Light
\"Dark
\"Brown
\"Polar
\"Clothing
\"Runic
\"Runic
\"Runic
Power Scrolls
Runic Kits
" ); + } + + private static void DocumentTailorBOD( StreamWriter html, List items, string amt, BulkMaterialType material, Type type ) + { + bool[] rewards = new bool[20]; + + for( int i = 0; i < items.Count; ++i ) + { + Item item = (Item)items[i]; + + if( item is Sandals ) + rewards[5] = true; + else if( item is SmallStretchedHideEastDeed || item is SmallStretchedHideSouthDeed ) + rewards[10] = rewards[11] = true; + else if( item is MediumStretchedHideEastDeed || item is MediumStretchedHideSouthDeed ) + rewards[10] = rewards[11] = true; + else if( item is LightFlowerTapestryEastDeed || item is LightFlowerTapestrySouthDeed ) + rewards[12] = rewards[13] = true; + else if( item is DarkFlowerTapestryEastDeed || item is DarkFlowerTapestrySouthDeed ) + rewards[12] = rewards[13] = true; + else if( item is BrownBearRugEastDeed || item is BrownBearRugSouthDeed ) + rewards[14] = rewards[15] = true; + else if( item is PolarBearRugEastDeed || item is PolarBearRugSouthDeed ) + rewards[14] = rewards[15] = true; + else if( item is ClothingBlessDeed ) + rewards[16] = true; + else if( item is PowerScroll ) + { + PowerScroll ps = (PowerScroll)item; + + if( ps.Value == 105.0 ) + rewards[6] = true; + else if( ps.Value == 110.0 ) + rewards[7] = true; + else if( ps.Value == 115.0 ) + rewards[8] = true; + else if( ps.Value == 120.0 ) + rewards[9] = true; + } + else if( item is UncutCloth ) + { + if( item.Hue == 0x483 || item.Hue == 0x48C || item.Hue == 0x488 || item.Hue == 0x48A ) + rewards[0] = true; + else if( item.Hue == 0x495 || item.Hue == 0x48B || item.Hue == 0x486 || item.Hue == 0x485 ) + rewards[1] = true; + else if( item.Hue == 0x48D || item.Hue == 0x490 || item.Hue == 0x48E || item.Hue == 0x491 ) + rewards[2] = true; + else if( item.Hue == 0x48F || item.Hue == 0x494 || item.Hue == 0x484 || item.Hue == 0x497 ) + rewards[3] = true; + else + rewards[4] = true; + } + else if( item is RunicSewingKit ) + { + RunicSewingKit rkit = (RunicSewingKit)item; + + rewards[16 + CraftResources.GetIndex( rkit.Resource )] = true; + } + + item.Delete(); + } + + string style = null; + string name = null; + + switch( material ) + { + case BulkMaterialType.None: + { + if( type.IsSubclassOf( typeof( BaseArmor ) ) || type.IsSubclassOf( typeof( BaseShoes ) ) ) + { + style = "pl"; + name = "Plain"; + } + else + { + style = "cl"; + name = "Cloth"; + } + + break; + } + case BulkMaterialType.Spined: style = "sp"; name = "Spined"; break; + case BulkMaterialType.Horned: style = "ho"; name = "Horned"; break; + case BulkMaterialType.Barbed: style = "ba"; name = "Barbed"; break; + } + + html.WriteLine( " " ); + html.WriteLine( "  - {0} {1}", name, amt ); + + int index = 0; + + while( index < 20 ) + { + if( rewards[index] ) + { + html.WriteLine( "
X
", style ); + ++index; + } + else + { + int count = 0; + + while( index < 20 && !rewards[index] ) + { + ++count; + ++index; + + if( index == 5 || index == 6 || index == 10 || index == 17 ) + break; + } + + html.WriteLine( "  ", count*25, count==1?"":String.Format( " colspan=\"{0}\"", count ) ); + } + } + + html.WriteLine( " " ); + } + + #endregion + + #region Smith Bods + private static void WriteSmithLBOD( StreamWriter html, string name, SmallBulkEntry[] entries ) + { + LargeBOD lbod = new LargeSmithBOD(); + + lbod.Entries = LargeBulkEntry.ConvertEntries( lbod, entries ); + + WriteSmithBODHeader( html, String.Format( "(Large) {0}: Normal", name ) ); + + lbod.RequireExceptional = false; + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat ) + { + lbod.Material = mat; + lbod.AmountMax = 10; + DocumentSmithBOD( html, lbod.ComputeRewards( true ), "10, 15, 20", lbod.Material ); + } + + WriteSmithBODFooter( html ); + + html.WriteLine( "

" ); + + WriteSmithBODHeader( html, String.Format( "(Large) {0}: Exceptional", name ) ); + + lbod.RequireExceptional = true; + for( BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat ) + { + lbod.Material = mat; + + for( int amt = 15; amt <= 20; amt += 5 ) + { + lbod.AmountMax = amt; + DocumentSmithBOD( html, lbod.ComputeRewards( true ), amt == 20 ? "20" : "10, 15", lbod.Material ); + } + } + + WriteSmithBODFooter( html ); + + html.WriteLine( "

" ); + html.WriteLine( "

" ); + } + + private static void WriteSmithBODHeader( StreamWriter html, string title ) + { + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " ", title ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + } + + private static void WriteSmithBODFooter( StreamWriter html ) + { + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "
{0}
\"Sturdy
Gloves
\"Gargoyles
\"Prospectors
\"Powder
\"Colored
Power Scrolls
Runic Hammers
Ancient Hammers
+1
+3
+5
+5
+10
+15
+20
Du
Sh
Co
Br
Go
Ag
Ve
Va
+10
+15
+30
+60
 
\"Sturdy
+1
 
+3
 
+5
 
\"Gargoyles
\"Prospectors
\"Powder
\"Colored
+5
+10
+15
+20
Du
Sh
Co
Br
Go
Ag
Ve
Va
+10
+15
+30
+60
Gloves
Power Scrolls
Runic Hammers
Ancient Hammers
" ); + } + + private static void DocumentSmithBOD( StreamWriter html, List items, string amt, BulkMaterialType material ) + { + bool[] rewards = new bool[24]; + + for( int i = 0; i < items.Count; ++i ) + { + Item item = (Item)items[i]; + + if( item is SturdyPickaxe || item is SturdyShovel ) + rewards[0] = true; + else if( item is LeatherGlovesOfMining ) + rewards[1] = true; + else if( item is StuddedGlovesOfMining ) + rewards[2] = true; + else if( item is RingmailGlovesOfMining ) + rewards[3] = true; + else if( item is GargoylesPickaxe ) + rewards[4] = true; + else if( item is ProspectorsTool ) + rewards[5] = true; + else if( item is PowderOfTemperament ) + rewards[6] = true; + else if( item is ColoredAnvil ) + rewards[7] = true; + else if( item is PowerScroll ) + { + PowerScroll ps = (PowerScroll)item; + + if( ps.Value == 105.0 ) + rewards[8] = true; + else if( ps.Value == 110.0 ) + rewards[9] = true; + else if( ps.Value == 115.0 ) + rewards[10] = true; + else if( ps.Value == 120.0 ) + rewards[11] = true; + } + else if( item is RunicHammer ) + { + RunicHammer rh = (RunicHammer)item; + + rewards[11 + CraftResources.GetIndex( rh.Resource )] = true; + } + else if( item is AncientSmithyHammer ) + { + AncientSmithyHammer ash = (AncientSmithyHammer)item; + + if( ash.Bonus == 10 ) + rewards[20] = true; + else if( ash.Bonus == 15 ) + rewards[21] = true; + else if( ash.Bonus == 30 ) + rewards[22] = true; + else if( ash.Bonus == 60 ) + rewards[23] = true; + } + + item.Delete(); + } + + string style = null; + string name = null; + + switch( material ) + { + case BulkMaterialType.None: style = "ir"; name = "Iron"; break; + case BulkMaterialType.DullCopper: style = "du"; name = "Dull Copper"; break; + case BulkMaterialType.ShadowIron: style = "sh"; name = "Shadow Iron"; break; + case BulkMaterialType.Copper: style = "co"; name = "Copper"; break; + case BulkMaterialType.Bronze: style = "br"; name = "Bronze"; break; + case BulkMaterialType.Gold: style = "go"; name = "Gold"; break; + case BulkMaterialType.Agapite: style = "ag"; name = "Agapite"; break; + case BulkMaterialType.Verite: style = "ve"; name = "Verite"; break; + case BulkMaterialType.Valorite: style = "va"; name = "Valorite"; break; + } + + html.WriteLine( " " ); + html.WriteLine( " {0} {1}", name, amt ); + + int index = 0; + + while( index < 24 ) + { + if( rewards[index] ) + { + html.WriteLine( "
X
", style ); + ++index; + } + else + { + int count = 0; + + while( index < 24 && !rewards[index] ) + { + ++count; + ++index; + + if( index == 4 || index == 8 || index == 12 || index == 20 ) + break; + } + + html.WriteLine( "  ", count*25, count==1?"":String.Format( " colspan=\"{0}\"", count ) ); + } + } + + html.WriteLine( " " ); + } + + #endregion + + #endregion + + #region Bodies + public static List LoadBodies() + { + List list = new List(); + + string path = Core.FindDataFile( "models/models.txt" ); + + if( File.Exists( path ) ) + { + using( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + string[] split = line.Split( '\t' ); + + if( split.Length >= 9 ) + { + Body body = Utility.ToInt32( split[0] ); + ModelBodyType type = (ModelBodyType)Utility.ToInt32( split[1] ); + string name = split[8]; + + BodyEntry entry = new BodyEntry( body, type, name ); + + if( !list.Contains( entry ) ) + list.Add( entry ); + } + } + } + } + + return list; + } + + private static void DocumentBodies() + { + List list = LoadBodies(); + + using( StreamWriter html = GetWriter( "docs/", "bodies.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Body List" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "

Back to the index

" ); + + if( list.Count > 0 ) + { + html.WriteLine( "

Body List

" ); + + list.Sort( new BodyEntrySorter() ); + + ModelBodyType lastType = ModelBodyType.Invalid; + + for( int i = 0; i < list.Count; ++i ) + { + BodyEntry entry = list[i]; + ModelBodyType type = entry.BodyType; + + if( type != lastType ) + { + if( lastType != ModelBodyType.Invalid ) + html.WriteLine( "
" ); + + lastType = type; + + html.WriteLine( " ", type ); + + switch( type ) + { + case ModelBodyType.Monsters: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

" ); break; + case ModelBodyType.Sea: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

" ); break; + case ModelBodyType.Animals: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

" ); break; + case ModelBodyType.Human: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

" ); break; + case ModelBodyType.Equipment: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

" ); break; + } + + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " ", type ); + } + + html.WriteLine( " ", entry.Body.BodyID, entry.Name ); + } + + html.WriteLine( "
{0}
{0}{1}
" ); + } + else + { + html.WriteLine( " This feature requires a UO:3D installation." ); + } + + html.WriteLine( " " ); + html.WriteLine( "" ); + } + } + #endregion + + #region Speech + private static void DocumentKeywords() + { + List> tables = LoadSpeechFile(); + + using( StreamWriter html = GetWriter( "docs/", "keywords.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Speech Keywords" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "

Back to the index

" ); + html.WriteLine( "

Speech Keywords

" ); + + for( int p = 0; p < 1 && p < tables.Count; ++p ) + { + Dictionary table = tables[p]; + + if( p > 0 ) + html.WriteLine( "
" ); + + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + + List list = new List( table.Values ); + list.Sort( new SpeechEntrySorter() ); + + for( int i = 0; i < list.Count; ++i ) + { + SpeechEntry entry = list[i]; + + html.Write( " " ); + } + + html.WriteLine( "
NumberText
0x{0:X4}", entry.Index ); + + entry.Strings.Sort();//( new EnglishPrioStringSorter() ); + + for( int j = 0; j < entry.Strings.Count; ++j ) + { + if( j > 0 ) + html.Write( "
" ); + + string v = entry.Strings[j]; + + for( int k = 0; k < v.Length; ++k ) + { + char c = v[k]; + + if( c == '<' ) + html.Write( "<" ); + else if( c == '>' ) + html.Write( ">" ); + else if( c == '&' ) + html.Write( "&" ); + else if( c == '"' ) + html.Write( """ ); + else if( c == '\'' ) + html.Write( "'" ); + else if (c >= 0x20 && c < 0x7F) + html.Write(c); + else + html.Write( "&#{0};", (int)c ); + } + } + + html.WriteLine( "
" ); + } + + html.WriteLine( " " ); + html.WriteLine( "" ); + } + } + + private class SpeechEntry + { + private int m_Index; + private List m_Strings; + + public int Index { get { return m_Index; } } + public List Strings { get { return m_Strings; } } + + public SpeechEntry( int index ) + { + m_Index = index; + m_Strings = new List(); + } + } + + private class SpeechEntrySorter : IComparer + { + public int Compare( SpeechEntry x, SpeechEntry y ) + { + return x.Index.CompareTo( y.Index ); + } + } + + private static List> LoadSpeechFile() + { + List> tables = new List>(); + int lastIndex = -1; + + Dictionary table = null; + + string path = Core.FindDataFile( "speech.mul" ); + + if( File.Exists( path ) ) + { + using( FileStream ip = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + BinaryReader bin = new BinaryReader( ip ); + + while( bin.PeekChar() >= 0 ) + { + int index = (bin.ReadByte() << 8) | bin.ReadByte(); + int length = (bin.ReadByte() << 8) | bin.ReadByte(); + string text = Encoding.UTF8.GetString( bin.ReadBytes( length ) ).Trim(); + + if( text.Length == 0 ) + continue; + + if( table == null || lastIndex > index ) + { + if( index == 0 && text == "*withdraw*" ) + tables.Insert( 0, table = new Dictionary() ); + else + tables.Add( table = new Dictionary() ); + } + + lastIndex = index; + + SpeechEntry entry = null; + table.TryGetValue( index, out entry ); + + if( entry == null ) + table[index] = entry = new SpeechEntry( index ); + + entry.Strings.Add( text ); + } + } + } + + return tables; + } + #endregion + + #region Commands + + public class DocCommandEntry + { + private AccessLevel m_AccessLevel; + private string m_Name; + private string[] m_Aliases; + private string m_Usage; + private string m_Description; + + public AccessLevel AccessLevel { get { return m_AccessLevel; } } + public string Name { get { return m_Name; } } + public string[] Aliases { get { return m_Aliases; } } + public string Usage { get { return m_Usage; } } + public string Description { get { return m_Description; } } + + public DocCommandEntry( AccessLevel accessLevel, string name, string[] aliases, string usage, string description ) + { + m_AccessLevel = accessLevel; + m_Name = name; + m_Aliases = aliases; + m_Usage = usage; + m_Description = description; + } + } + + public class CommandEntrySorter : IComparer + { + public int Compare( DocCommandEntry a, DocCommandEntry b ) + { + int v = b.AccessLevel.CompareTo( a.AccessLevel ); + + if( v == 0 ) + v = a.Name.CompareTo( b.Name ); + + return v; + } + } + + private static void DocumentCommands() + { + using( StreamWriter html = GetWriter( "docs/", "commands.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Commands" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "

Back to the index

" ); + html.WriteLine( "

Commands

" ); + + List commands = new List( CommandSystem.Entries.Values ); + List list = new List(); + + commands.Sort(); + commands.Reverse(); + Clean( commands ); + + for( int i = 0; i < commands.Count; ++i ) + { + CommandEntry e = commands[i]; + + MethodInfo mi = e.Handler.Method; + + object[] attrs = mi.GetCustomAttributes( typeof( UsageAttribute ), false ); + + if( attrs.Length == 0 ) + continue; + + UsageAttribute usage = attrs[0] as UsageAttribute; + + attrs = mi.GetCustomAttributes( typeof( DescriptionAttribute ), false ); + + if( attrs.Length == 0 ) + continue; + + DescriptionAttribute desc = attrs[0] as DescriptionAttribute; + + if( usage == null || desc == null ) + continue; + + attrs = mi.GetCustomAttributes( typeof( AliasesAttribute ), false ); + + AliasesAttribute aliases = (attrs.Length == 0 ? null : attrs[0] as AliasesAttribute); + + string descString = desc.Description.Replace( "<", "<" ).Replace( ">", ">" ); + + if( aliases == null ) + list.Add( new DocCommandEntry( e.AccessLevel, e.Command, null, usage.Usage, descString ) ); + else + list.Add( new DocCommandEntry( e.AccessLevel, e.Command, aliases.Aliases, usage.Usage, descString ) ); + } + + for( int i = 0; i < TargetCommands.AllCommands.Count; ++i ) + { + BaseCommand command = TargetCommands.AllCommands[i]; + + string usage = command.Usage; + string desc = command.Description; + + if( usage == null || desc == null ) + continue; + + string[] cmds = command.Commands; + string cmd = cmds[0]; + string[] aliases = new string[cmds.Length - 1]; + + for( int j = 0; j < aliases.Length; ++j ) + aliases[j] = cmds[j + 1]; + + desc = desc.Replace( "<", "<" ).Replace( ">", ">" ); + + if( command.Supports != CommandSupport.Single ) + { + StringBuilder sb = new StringBuilder( 50 + desc.Length ); + + sb.Append( "Modifiers: " ); + + if( (command.Supports & CommandSupport.Global) != 0 ) + sb.Append( "Global, " ); + + if( (command.Supports & CommandSupport.Online) != 0 ) + sb.Append( "Online, " ); + + if( (command.Supports & CommandSupport.Region) != 0 ) + sb.Append( "Region, " ); + + if( (command.Supports & CommandSupport.Contained) != 0 ) + sb.Append( "Contained, " ); + + if( (command.Supports & CommandSupport.Multi) != 0 ) + sb.Append( "Multi, " ); + + if( (command.Supports & CommandSupport.Area) != 0 ) + sb.Append( "Area, " ); + + if( (command.Supports & CommandSupport.Self) != 0 ) + sb.Append( "Self, " ); + + sb.Remove( sb.Length - 2, 2 ); + sb.Append( "
" ); + sb.Append( desc ); + + desc = sb.ToString(); + } + + list.Add( new DocCommandEntry( command.AccessLevel, cmd, aliases, usage, desc ) ); + } + + List commandImpls = BaseCommandImplementor.Implementors; + + for( int i = 0; i < commandImpls.Count; ++i ) + { + BaseCommandImplementor command = commandImpls[i]; + + string usage = command.Usage; + string desc = command.Description; + + if( usage == null || desc == null ) + continue; + + string[] cmds = command.Accessors; + string cmd = cmds[0]; + string[] aliases = new string[cmds.Length - 1]; + + for( int j = 0; j < aliases.Length; ++j ) + aliases[j] = cmds[j + 1]; + + desc = desc.Replace( "<", "<" ).Replace( ">", ">" ); + + list.Add( new DocCommandEntry( command.AccessLevel, cmd, aliases, usage, desc ) ); + } + + list.Sort( new CommandEntrySorter() ); + + AccessLevel last = AccessLevel.Player; + + foreach( DocCommandEntry e in list ) + { + if( e.AccessLevel != last ) + { + if( last != AccessLevel.Player ) + html.WriteLine( "

" ); + + last = e.AccessLevel; + + html.WriteLine( " ", last ); + + switch( last ) + { + case AccessLevel.Administrator: html.WriteLine( " Administrator | Game Master | Counselor | Player

" ); break; + case AccessLevel.GameMaster: html.WriteLine( " Administrator | Game Master | Counselor | Player

" ); break; + case AccessLevel.Seer: html.WriteLine( " Administrator | Game Master | Counselor | Player

" ); break; + case AccessLevel.Counselor: html.WriteLine( " Administrator | Game Master | Counselor | Player

" ); break; + case AccessLevel.Player: html.WriteLine( " Administrator | Game Master | Counselor | Player

" ); break; + } + + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " ", last == AccessLevel.GameMaster ? "Game Master" : last.ToString() ); + } + + DocumentCommand( html, e ); + } + + html.WriteLine( "
{0}
" ); + html.WriteLine( " " ); + html.WriteLine( "" ); + } + } + + public static void Clean( List list ) + { + for( int i = 0; i < list.Count; ++i ) + { + CommandEntry e = list[i]; + + for( int j = i + 1; j < list.Count; ++j ) + { + CommandEntry c = list[j]; + + if( e.Handler.Method == c.Handler.Method ) + { + list.RemoveAt( j ); + --j; + } + } + } + } + + private static void DocumentCommand( StreamWriter html, DocCommandEntry e ) + { + string usage = e.Usage; + string desc = e.Description; + string[] aliases = e.Aliases; + + html.Write( " {0}", e.Name ); + + if( aliases == null || aliases.Length == 0 ) + { + html.Write( "Usage: {0}
{1}", usage.Replace( "<", "<" ).Replace( ">", ">" ), desc ); + } + else + { + html.Write( "Usage: {0}
Alias{1}: ", usage.Replace( "<", "<" ).Replace( ">", ">" ), aliases.Length == 1 ? "" : "es" ); + + for( int i = 0; i < aliases.Length; ++i ) + { + if( i != 0 ) + html.Write( ", " ); + + html.Write( aliases[i] ); + } + + html.Write( "
{0}", desc ); + } + + html.WriteLine( "" ); + } + + #endregion + + private static void LoadTypes( Assembly a, Assembly[] asms ) + { + Type[] types = a.GetTypes(); + + for( int i = 0; i < types.Length; ++i ) + { + Type type = types[i]; + + string nspace = type.Namespace; + + if( nspace == null || type.IsSpecialName ) + continue; + + TypeInfo info = new TypeInfo( type ); + m_Types[type] = info; + + List nspaces = null; + m_Namespaces.TryGetValue( nspace, out nspaces ); + + if( nspaces == null ) + m_Namespaces[nspace] = nspaces = new List(); + + nspaces.Add( info ); + + Type baseType = info.m_BaseType; + + if( baseType != null && InAssemblies( baseType, asms ) ) + { + TypeInfo baseInfo = null; + m_Types.TryGetValue( baseType, out baseInfo ); + + if( baseInfo == null ) + m_Types[baseType] = baseInfo = new TypeInfo( baseType ); + + if( baseInfo.m_Derived == null ) + baseInfo.m_Derived = new List(); + + baseInfo.m_Derived.Add( info ); + } + + Type decType = info.m_Declaring; + + if( decType != null ) + { + TypeInfo decInfo = null; + m_Types.TryGetValue( decType, out decInfo ); + + if( decInfo == null ) + m_Types[decType] = decInfo = new TypeInfo( decType ); + + if( decInfo.m_Nested == null ) + decInfo.m_Nested = new List(); + + decInfo.m_Nested.Add( info ); + } + + for( int j = 0; j < info.m_Interfaces.Length; ++j ) + { + Type iface = info.m_Interfaces[j]; + + if( !InAssemblies( iface, asms ) ) + continue; + + TypeInfo ifaceInfo = null; + m_Types.TryGetValue( iface, out ifaceInfo ); + + if( ifaceInfo == null ) + m_Types[iface] = ifaceInfo = new TypeInfo( iface ); + + if( ifaceInfo.m_Derived == null ) + ifaceInfo.m_Derived = new List(); + + ifaceInfo.m_Derived.Add( info ); + } + } + } + + private static bool InAssemblies( Type t, Assembly[] asms ) + { + Assembly a = t.Assembly; + + for( int i = 0; i < asms.Length; ++i ) + if( a == asms[i] ) + return true; + + return false; + } + + #region Constructable Objects + private static Type typeofItem = typeof( Item ), typeofMobile = typeof( Mobile ), typeofMap = typeof( Map ); + private static Type typeofCustomEnum = typeof( CustomEnumAttribute ); + + private static bool IsConstructable( Type t, out bool isItem ) + { + if( isItem = typeofItem.IsAssignableFrom( t ) ) + return true; + + return typeofMobile.IsAssignableFrom( t ); + } + + private static bool IsConstructable( ConstructorInfo ctor ) + { + return ctor.IsDefined( typeof( ConstructableAttribute ), false ); + } + + private static void DocumentConstructableObjects() + { + List types = new List( m_Types.Values ); + types.Sort( new TypeComparer() ); + + ArrayList items = new ArrayList(), mobiles = new ArrayList(); + + for( int i = 0; i < types.Count; ++i ) + { + Type t = types[i].m_Type; + bool isItem; + + if( t.IsAbstract || !IsConstructable( t, out isItem ) ) + continue; + + ConstructorInfo[] ctors = t.GetConstructors(); + bool anyConstructable = false; + + for( int j = 0; !anyConstructable && j < ctors.Length; ++j ) + anyConstructable = IsConstructable( ctors[j] ); + + if( anyConstructable ) + { + (isItem ? items : mobiles).Add( t ); + (isItem ? items : mobiles).Add( ctors ); + } + } + + using( StreamWriter html = GetWriter( "docs/", "objects.html" ) ) + { + html.WriteLine( "" ); + html.WriteLine( " " ); + html.WriteLine( " RunUO Documentation - Constructable Objects" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "

Back to the index

" ); + html.WriteLine( "

Constructable Items and Mobiles

" ); + + html.WriteLine( " " ); + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + + for( int i = 0; i < items.Count; i += 2 ) + DocumentConstructableObject( html, (Type)items[i], (ConstructorInfo[])items[i + 1] ); + + html.WriteLine( "
Item NameUsage


" ); + + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( "
" ); + html.WriteLine( " " ); + html.WriteLine( " " ); + + for( int i = 0; i < mobiles.Count; i += 2 ) + DocumentConstructableObject( html, (Type)mobiles[i], (ConstructorInfo[])mobiles[i + 1] ); + + html.WriteLine( "
Mobile NameUsage
" ); + + html.WriteLine( " " ); + html.WriteLine( "" ); + } + } + + private static void DocumentConstructableObject( StreamWriter html, Type t, ConstructorInfo[] ctors ) + { + html.Write( " {0}", t.Name ); + + bool first = true; + + for( int i = 0; i < ctors.Length; ++i ) + { + ConstructorInfo ctor = ctors[i]; + + if( !IsConstructable( ctor ) ) + continue; + + if( !first ) + html.Write( "
" ); + + first = false; + + html.Write( "{0}Add {1}", CommandSystem.Prefix, t.Name ); + + ParameterInfo[] parms = ctor.GetParameters(); + + for( int j = 0; j < parms.Length; ++j ) + { + html.Write( "
{1}", GetTooltipFor( parms[j] ), parms[j].Name ); + } + } + + html.WriteLine( "" ); + } + + #endregion + + #region Tooltips + + private const string HtmlNewLine = " "; + + private static object[,] m_Tooltips = new object[,] + { + { typeof( Byte ), "Numeric value in the range from 0 to 255, inclusive." }, + { typeof( SByte ), "Numeric value in the range from negative 128 to positive 127, inclusive." }, + { typeof( UInt16 ), "Numeric value in the range from 0 to 65,535, inclusive." }, + { typeof( Int16 ), "Numeric value in the range from negative 32,768 to positive 32,767, inclusive." }, + { typeof( UInt32 ), "Numeric value in the range from 0 to 4,294,967,295, inclusive." }, + { typeof( Int32 ), "Numeric value in the range from negative 2,147,483,648 to positive 2,147,483,647, inclusive." }, + { typeof( UInt64 ), "Numeric value in the range from 0 through about 10^20." }, + { typeof( Int64 ), "Numeric value in the approximate range from negative 10^19 through 10^19." }, + { typeof( String ), "Text value. To specify a value containing spaces, encapsulate the value in quote characters:{0}{0}"Spaced text example"" }, + { typeof( Boolean ), "Boolean value which can be either True or False." }, + { typeof( Map ), "Map or facet name. Possible values include:{0}{0}- Felucca{0}- Trammel{0}- Ilshenar{0}- Malas" }, + { typeof( Poison ), "Poison name or level. Possible values include:{0}{0}- Lesser{0}- Regular{0}- Greater{0}- Deadly{0}- Lethal" }, + { typeof( Point3D ), "Three-dimensional coordinate value. Format as follows:{0}{0}"(, , )"" } + }; + + private static string GetTooltipFor( ParameterInfo param ) + { + Type paramType = param.ParameterType; + + for( int i = 0; i < m_Tooltips.GetLength( 0 ); ++i ) + { + Type checkType = (Type)m_Tooltips[i, 0]; + + if( paramType == checkType ) + return String.Format( (string)m_Tooltips[i, 1], HtmlNewLine ); + } + + if( paramType.IsEnum ) + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat( "Enumeration value or name. Possible named values include:{0}", HtmlNewLine ); + + string[] names = Enum.GetNames( paramType ); + + for( int i = 0; i < names.Length; ++i ) + sb.AppendFormat( "{0}- {1}", HtmlNewLine, names[i] ); + + return sb.ToString(); + } + else if( paramType.IsDefined( typeofCustomEnum, false ) ) + { + object[] attributes = paramType.GetCustomAttributes( typeofCustomEnum, false ); + + if( attributes != null && attributes.Length > 0 ) + { + CustomEnumAttribute attr = attributes[0] as CustomEnumAttribute; + + if( attr != null ) + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat( "Enumeration value or name. Possible named values include:{0}", HtmlNewLine ); + + string[] names = attr.Names; + + for( int i = 0; i < names.Length; ++i ) + sb.AppendFormat( "{0}- {1}", HtmlNewLine, names[i] ); + + return sb.ToString(); + } + } + } + else if( paramType == typeofMap ) + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat( "Enumeration value or name. Possible named values include:{0}", HtmlNewLine ); + + string[] names = Map.GetMapNames(); + + for( int i = 0; i < names.Length; ++i ) + sb.AppendFormat( "{0}- {1}", HtmlNewLine, names[i] ); + + return sb.ToString(); + } + + return ""; + } + + #endregion + + #region Const Strings + + private const string RefString = "ref "; + private const string GetString = " get;"; + private const string SetString = " set;"; + + private const string InString = "in "; + private const string OutString = "out "; + + private const string VirtString = "virtual "; + private const string CtorString ="(ctor) "; + private const string StaticString = "(static) "; + #endregion + + private static void DocumentLoadedTypes() + { + using( StreamWriter indexHtml = GetWriter( "docs/", "overview.html" ) ) + { + indexHtml.WriteLine( "" ); + indexHtml.WriteLine( " " ); + indexHtml.WriteLine( " RunUO Documentation - Class Overview" ); + indexHtml.WriteLine( " " ); + indexHtml.WriteLine( " " ); + indexHtml.WriteLine( "

Back to the index

" ); + indexHtml.WriteLine( "

Namespaces

" ); + + SortedList> nspaces = new SortedList>( m_Namespaces ); + + foreach( KeyValuePair> kvp in nspaces ) + { + kvp.Value.Sort( new TypeComparer() ); + + SaveNamespace( kvp.Key, kvp.Value, indexHtml ); + } + + indexHtml.WriteLine( " " ); + indexHtml.WriteLine( "" ); + } + } + + private static void SaveNamespace( string name, List types, StreamWriter indexHtml ) + { + string fileName = GetFileName( "docs/namespaces/", name, ".html" ); + + indexHtml.WriteLine( " {1}
", fileName, name ); + + using( StreamWriter nsHtml = GetWriter( "docs/namespaces/", fileName ) ) + { + nsHtml.WriteLine( "" ); + nsHtml.WriteLine( " " ); + nsHtml.WriteLine( " RunUO Documentation - Class Overview - {0}", name ); + nsHtml.WriteLine( " " ); + nsHtml.WriteLine( " " ); + nsHtml.WriteLine( "

Back to the namespace index

" ); + nsHtml.WriteLine( "

{0}

", name ); + + for( int i = 0; i < types.Count; ++i ) + SaveType( types[i], nsHtml, fileName, name ); + + nsHtml.WriteLine( " " ); + nsHtml.WriteLine( "" ); + } + } + + private static void SaveType( TypeInfo info, StreamWriter nsHtml, string nsFileName, string nsName ) + { + if( info.m_Declaring == null ) + nsHtml.WriteLine( " "+info.LinkName( "../types/" ) + "
" ); + + using( StreamWriter typeHtml = Docs.GetWriter( info.FileName ) ) + { + typeHtml.WriteLine( "" ); + typeHtml.WriteLine( " " ); + typeHtml.WriteLine( " RunUO Documentation - Class Overview - {0}", info.TypeName ); + typeHtml.WriteLine( " " ); + typeHtml.WriteLine( " " ); + typeHtml.WriteLine( "

Back to {1}

", nsFileName, nsName ); + + if( info.m_Type.IsEnum ) + WriteEnum( info, typeHtml ); + else + WriteType( info, typeHtml ); + + typeHtml.WriteLine( " " ); + typeHtml.WriteLine( "" ); + } + } + + #region Write[...] + private static void WriteEnum( TypeInfo info, StreamWriter typeHtml ) + { + Type type = info.m_Type; + + typeHtml.WriteLine( "

{0} (Enum)

", info.TypeName ); + + string[] names = Enum.GetNames( type ); + + bool flags = type.IsDefined( typeof( FlagsAttribute ), false ); + string format; + + if( flags ) + format = " {0:G} = 0x{1:X}{2}
"; + else + format = " {0:G} = {1:D}{2}
"; + + for( int i = 0; i < names.Length; ++i ) + { + object value = Enum.Parse( type, names[i] ); + + typeHtml.WriteLine( format, names[i], value, i < (names.Length - 1) ? "," : "" ); + } + } + + private static void WriteType( TypeInfo info, StreamWriter typeHtml ) + { + Type type = info.m_Type; + + typeHtml.Write( "

" ); + + Type decType = info.m_Declaring; + + if( decType != null ) + { + // We are a nested type + + typeHtml.Write( '(' ); + + TypeInfo decInfo = null; + m_Types.TryGetValue( decType, out decInfo ); + + if( decInfo == null ) + typeHtml.Write( decType.Name ); + else + //typeHtml.Write( "{1}", decInfo.m_FileName, decInfo.m_TypeName ); + typeHtml.Write( decInfo.LinkName( null ) ); + + typeHtml.Write( ") - " ); + } + + typeHtml.Write( info.TypeName ); + + Type[] ifaces = info.m_Interfaces; + Type baseType = info.m_BaseType; + + int extendCount = 0; + + if( baseType != null && baseType != typeof( object ) && baseType != typeof( ValueType ) && !baseType.IsPrimitive ) + { + typeHtml.Write( " : " ); + + TypeInfo baseInfo = null; + m_Types.TryGetValue( baseType, out baseInfo ); + + if( baseInfo == null ) + typeHtml.Write( baseType.Name ); + else + { + typeHtml.Write( ""+baseInfo.LinkName( null ) ); + } + + ++extendCount; + } + + if( ifaces.Length > 0 ) + { + if( extendCount == 0 ) + typeHtml.Write( " : " ); + + for( int i = 0; i < ifaces.Length; ++i ) + { + Type iface = ifaces[i]; + TypeInfo ifaceInfo = null; + m_Types.TryGetValue( iface, out ifaceInfo ); + + if( extendCount != 0 ) + typeHtml.Write( ", " ); + + ++extendCount; + + if( ifaceInfo == null ) + { + string typeName = ""; + string fileName = ""; + string linkName = ""; + FormatGeneric( iface, ref typeName, ref fileName, ref linkName ); + linkName = linkName.Replace( "@directory@", null ); + typeHtml.Write( ""+linkName ); + } + else + { + typeHtml.Write( ""+ifaceInfo.LinkName( null ) ); + } + } + } + + typeHtml.WriteLine( "

" ); + + List derived = info.m_Derived; + + if( derived != null ) + { + typeHtml.Write( "

Derived Types: " ); + + derived.Sort( new TypeComparer() ); + + for( int i = 0; i < derived.Count; ++i ) + { + TypeInfo derivedInfo = derived[i]; + + if( i != 0 ) + typeHtml.Write( ", " ); + + //typeHtml.Write( "{1}", derivedInfo.m_FileName, derivedInfo.m_TypeName ); + typeHtml.Write( ""+derivedInfo.LinkName( null ) ); + } + + typeHtml.WriteLine( "

" ); + } + + List nested = info.m_Nested; + + if( nested != null ) + { + typeHtml.Write( "

Nested Types: " ); + + nested.Sort( new TypeComparer() ); + + for( int i = 0; i < nested.Count; ++i ) + { + TypeInfo nestedInfo = nested[i]; + + if( i != 0 ) + typeHtml.Write( ", " ); + + //typeHtml.Write( "{1}", nestedInfo.m_FileName, nestedInfo.m_TypeName ); + typeHtml.Write( ""+nestedInfo.LinkName( null ) ); + } + + typeHtml.WriteLine( "

" ); + } + + MemberInfo[] membs = type.GetMembers( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly ); + + Array.Sort( membs, new MemberComparer() ); + + for( int i = 0; i < membs.Length; ++i ) + { + MemberInfo mi = membs[i]; + + if( mi is PropertyInfo ) + WriteProperty( (PropertyInfo)mi, typeHtml ); + else if( mi is ConstructorInfo ) + WriteCtor( info.TypeName, (ConstructorInfo)mi, typeHtml ); + else if( mi is MethodInfo ) + WriteMethod( (MethodInfo)mi, typeHtml ); + } + } + + private static void WriteProperty( PropertyInfo pi, StreamWriter html ) + { + html.Write( " " ); + + MethodInfo getMethod = pi.GetGetMethod(); + MethodInfo setMethod = pi.GetSetMethod(); + + if( (getMethod != null && getMethod.IsStatic) || (setMethod != null && setMethod.IsStatic) ) + html.Write( StaticString ); + + html.Write( GetPair( pi.PropertyType, pi.Name, false ) ); + html.Write( '(' ); + + if( pi.CanRead ) + html.Write( GetString ); + + if( pi.CanWrite ) + html.Write( SetString ); + + html.WriteLine( " )
" ); + } + + private static void WriteCtor( string name, ConstructorInfo ctor, StreamWriter html ) + { + if( ctor.IsStatic ) + return; + + html.Write( " " ); + html.Write( CtorString ); + html.Write( name ); + html.Write( '(' ); + + ParameterInfo[] parms = ctor.GetParameters(); + + if( parms.Length > 0 ) + { + html.Write( ' ' ); + + for( int i = 0; i < parms.Length; ++i ) + { + ParameterInfo pi = parms[i]; + + if( i != 0 ) + html.Write( ", " ); + + if( pi.IsIn ) + html.Write( InString ); + else if( pi.IsOut ) + html.Write( OutString ); + + html.Write( GetPair( pi.ParameterType, pi.Name, pi.IsOut ) ); + } + + html.Write( ' ' ); + } + + html.WriteLine( ")
" ); + } + + private static void WriteMethod( MethodInfo mi, StreamWriter html ) + { + if( mi.IsSpecialName ) + return; + + html.Write( " " ); + + if( mi.IsStatic ) + html.Write( StaticString ); + + if( mi.IsVirtual ) + html.Write( VirtString ); + + html.Write( GetPair( mi.ReturnType, mi.Name, false ) ); + html.Write( '(' ); + + ParameterInfo[] parms = mi.GetParameters(); + + if( parms.Length > 0 ) + { + html.Write( ' ' ); + + for( int i = 0; i < parms.Length; ++i ) + { + ParameterInfo pi = parms[i]; + + if( i != 0 ) + html.Write( ", " ); + + if( pi.IsIn ) + html.Write( InString ); + else if( pi.IsOut ) + html.Write( OutString ); + + html.Write( GetPair( pi.ParameterType, pi.Name, pi.IsOut ) ); + } + + html.Write( ' ' ); + } + + html.WriteLine( ")
" ); + } + #endregion + + public static void FormatGeneric( Type type, ref string typeName, ref string fileName, ref string linkName ) + { + string name = null; + string fnam = null; + string link = null; + + if( type.IsGenericType ) + { + int index = type.Name.IndexOf( '`' ); + + if( index > 0 ) + { + string rootType = type.Name.Substring( 0, index ); + + StringBuilder nameBuilder = new StringBuilder( rootType ); + StringBuilder fnamBuilder = new StringBuilder( "docs/types/" + Docs.SanitizeType( rootType ) ); + StringBuilder linkBuilder; + if( DontLink( type ) )//if( DontLink( rootType ) ) + linkBuilder = new StringBuilder( "" + rootType + "" ); + else + linkBuilder = new StringBuilder( "" + rootType + "" ); + + nameBuilder.Append( "<" ); + fnamBuilder.Append( "-" ); + linkBuilder.Append( "<" ); + + Type[] typeArguments = type.GetGenericArguments(); + + for( int i = 0; i < typeArguments.Length; i++ ) + { + if( i != 0 ) + { + nameBuilder.Append( ',' ); + fnamBuilder.Append( ',' ); + linkBuilder.Append( ',' ); + } + + string sanitizedName = Docs.SanitizeType( typeArguments[i].Name ); + string aliasedName = Docs.AliasForName( sanitizedName ); + + nameBuilder.Append( sanitizedName ); + fnamBuilder.Append( "T" ); + if( DontLink( typeArguments[i] ) )//if( DontLink( typeArguments[i].Name ) ) + linkBuilder.Append( "" + aliasedName + "" ); + else + linkBuilder.Append( "" + aliasedName + "" ); + } + + nameBuilder.Append( ">" ); + fnamBuilder.Append( "-" ); + linkBuilder.Append( ">" ); + + name = nameBuilder.ToString(); + fnam = fnamBuilder.ToString(); + link = linkBuilder.ToString(); + } + } + if( name == null ) typeName = type.Name; + else typeName = name; + + if( fnam == null ) fileName = "docs/types/" + Docs.SanitizeType( type.Name ) + ".html"; + else fileName = fnam + ".html"; + + if( link == null ) + { + if( DontLink( type ) ) //if( DontLink( type.Name ) ) + linkName = "" + Docs.SanitizeType( type.Name ) + ""; + else + linkName = "" + Docs.SanitizeType( type.Name ) + ""; + } + else linkName = link; + + //Console.WriteLine( typeName+":"+fileName+":"+linkName ); + } + + public static string SanitizeType( string name ) + { + bool anonymousType = false; + if( name.Contains( "<" ) ) anonymousType = true; + StringBuilder sb = new StringBuilder( name ); + for( int i = 0; i < ReplaceChars.Length; ++i ) { sb.Replace( ReplaceChars[i], '-' ); } + + if( anonymousType ) return "(Anonymous-Type)"+sb.ToString(); + else return sb.ToString(); + } + + public static string AliasForName( string name ) + { + for( int i = 0; i < m_AliasLength; ++i ) + { + if( m_Aliases[i, 0] == name ) + { + return m_Aliases[i, 1]; + } + } + return name; + } + + /* + // For stuff we don't want to links to + private static string[] m_DontLink = new string[] + { + "List", + "Stack", + "Queue", + "Dictionary", + "LinkedList", + "SortedList", + "SortedDictionary", + "IComparable", + "IComparer", + "ICloneable", + "Type" + }; + + public static bool DontLink( string name ) + { + foreach( string dontLink in m_DontLink ) + if( dontLink == name ) return true; + return false; + } + */ + public static bool DontLink( Type type ) + { + // MONO: type.Namespace is null/empty for generic arguments + + if ( type.Name == "T" || String.IsNullOrEmpty( type.Namespace ) || m_Namespaces == null ) + return true; + + if( type.Namespace.StartsWith( "Server" ) ) + return false; + + return !m_Namespaces.ContainsKey( type.Namespace ); + } + } + + #region BodyEntry & BodyType + public enum ModelBodyType + { + Invalid=-1, + Monsters, + Sea, + Animals, + Human, + Equipment + } + + public class BodyEntry + { + private Body m_Body; + private ModelBodyType m_BodyType; + private string m_Name; + + public Body Body { get { return m_Body; } } + public ModelBodyType BodyType { get { return m_BodyType; } } + public string Name { get { return m_Name; } } + + public BodyEntry( Body body, ModelBodyType bodyType, string name ) + { + m_Body = body; + m_BodyType = bodyType; + m_Name = name; + } + + public override bool Equals( object obj ) + { + BodyEntry e = (BodyEntry)obj; + + return (m_Body == e.m_Body && m_BodyType == e.m_BodyType && m_Name == e.m_Name); + } + + public override int GetHashCode() + { + return m_Body.BodyID ^ (int)m_BodyType ^ m_Name.GetHashCode(); + } + } + + public class BodyEntrySorter : IComparer + { + public int Compare( BodyEntry a, BodyEntry b ) + { + int v = a.BodyType.CompareTo( b.BodyType ); + + if( v == 0 ) + v = a.Body.BodyID.CompareTo( b.Body.BodyID ); + + if( v == 0 ) + v = a.Name.CompareTo( b.Name ); + + return v; + } + } + #endregion +} diff --git a/Scripts/Commands/DragEffects.cs b/Scripts/Commands/DragEffects.cs new file mode 100644 index 0000000..b537b19 --- /dev/null +++ b/Scripts/Commands/DragEffects.cs @@ -0,0 +1,29 @@ +using System; +using Server; + +namespace Server.Commands +{ + public static class DragEffects + { + public static void Initialize() + { + CommandSystem.Register("DragEffects", AccessLevel.Developer, new CommandEventHandler(DragEffects_OnCommand)); + } + + [Usage("DragEffects [enable=false]")] + [Description("Enables or disables the item drag and drop effects.")] + public static void DragEffects_OnCommand(CommandEventArgs e) + { + if (e.Length == 0) + { + e.Mobile.SendMessage("Drag effects are currently {0}.", Mobile.DragEffects ? "enabled" : "disabled"); + } + else + { + Mobile.DragEffects = e.GetBoolean(0); + + e.Mobile.SendMessage("Drag effects have been {0}.", Mobile.DragEffects ? "enabled" : "disabled"); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Dupe.cs b/Scripts/Commands/Dupe.cs new file mode 100644 index 0000000..3953322 --- /dev/null +++ b/Scripts/Commands/Dupe.cs @@ -0,0 +1,147 @@ +using System; +using System.Reflection; +using Server.Items; +using Server.Targeting; + +namespace Server.Commands +{ + public class Dupe + { + public static void Initialize() + { + CommandSystem.Register( "Dupe", AccessLevel.GameMaster, new CommandEventHandler( Dupe_OnCommand ) ); + CommandSystem.Register( "DupeInBag", AccessLevel.GameMaster, new CommandEventHandler( DupeInBag_OnCommand ) ); + } + + [Usage( "Dupe [amount]" )] + [Description( "Dupes a targeted item." )] + private static void Dupe_OnCommand( CommandEventArgs e ) + { + int amount = 1; + if ( e.Length >= 1 ) + amount = e.GetInt32( 0 ); + e.Mobile.Target = new DupeTarget( false, amount > 0 ? amount : 1 ); + e.Mobile.SendMessage( "What do you wish to dupe?" ); + } + + [Usage( "DupeInBag " )] + [Description( "Dupes an item at it's current location (count) number of times." )] + private static void DupeInBag_OnCommand( CommandEventArgs e ) + { + int amount = 1; + if ( e.Length >= 1 ) + amount = e.GetInt32( 0 ); + + e.Mobile.Target = new DupeTarget( true, amount > 0 ? amount : 1 ); + e.Mobile.SendMessage( "What do you wish to dupe?" ); + } + + private class DupeTarget : Target + { + private bool m_InBag; + private int m_Amount; + + public DupeTarget( bool inbag, int amount ) + : base( 15, false, TargetFlags.None ) + { + m_InBag = inbag; + m_Amount = amount; + } + + protected override void OnTarget( Mobile from, object targ ) + { + bool done = false; + if ( !( targ is Item ) ) + { + from.SendMessage( "You can only dupe items." ); + return; + } + + CommandLogging.WriteLine( from, "{0} {1} duping {2} (inBag={3}; amount={4})", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targ ), m_InBag, m_Amount ); + + Item copy = (Item)targ; + Container pack; + + if ( m_InBag ) + { + if ( copy.Parent is Container ) + pack = (Container)copy.Parent; + else if ( copy.Parent is Mobile ) + pack = ( (Mobile)copy.Parent ).Backpack; + else + pack = null; + } + else + pack = from.Backpack; + + Type t = copy.GetType(); + + //ConstructorInfo[] info = t.GetConstructors(); + + ConstructorInfo c = t.GetConstructor( Type.EmptyTypes ); + + if ( c != null ) + { + try + { + from.SendMessage( "Duping {0}...", m_Amount ); + for ( int i = 0; i < m_Amount; i++ ) + { + object o = c.Invoke( null ); + + if ( o != null && o is Item ) + { + Item newItem = (Item)o; + CopyProperties( newItem, copy );//copy.Dupe( item, copy.Amount ); + copy.OnAfterDuped( newItem ); + newItem.Parent = null; + + if ( pack != null ) + pack.DropItem( newItem ); + else + newItem.MoveToWorld( from.Location, from.Map ); + + newItem.InvalidateProperties(); + + CommandLogging.WriteLine( from, "{0} {1} duped {2} creating {3}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targ ), CommandLogging.Format( newItem ) ); + } + } + from.SendMessage( "Done" ); + done = true; + } + catch + { + from.SendMessage( "Error!" ); + return; + } + } + + if ( !done ) + { + from.SendMessage( "Unable to dupe. Item must have a 0 parameter constructor." ); + } + } + } + + public static void CopyProperties( Item dest, Item src ) + { + PropertyInfo[] props = src.GetType().GetProperties(); + + for ( int i = 0; i < props.Length; i++ ) + { + try + { + if ( props[i].CanRead && props[i].CanWrite ) + { + //Console.WriteLine( "Setting {0} = {1}", props[i].Name, props[i].GetValue( src, null ) ); + props[i].SetValue( dest, props[i].GetValue( src, null ), null ); + } + } + catch + { + //Console.WriteLine( "Denied" ); + } + } + } + } +} diff --git a/Scripts/Commands/ExportWSC.cs b/Scripts/Commands/ExportWSC.cs new file mode 100644 index 0000000..6faab34 --- /dev/null +++ b/Scripts/Commands/ExportWSC.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Items; + +namespace Server.Commands +{ + public class ExportCommand + { + private const string ExportFile = @"C:\Uo\WorldForge\items.wsc"; + + public static void Initialize() + { + CommandSystem.Register( "ExportWSC", AccessLevel.Administrator, new CommandEventHandler( Export_OnCommand ) ); + } + + public static void Export_OnCommand( CommandEventArgs e ) + { + StreamWriter w = new StreamWriter( ExportFile ); + ArrayList remove = new ArrayList(); + int count = 0; + + e.Mobile.SendMessage( "Exporting all static items to \"{0}\"...", ExportFile ); + e.Mobile.SendMessage( "This will delete all static items in the world. Please make a backup." ); + + foreach ( Item item in World.Items.Values ) + { + if ( ( item is Static || item is BaseFloor || item is BaseWall ) + && item.RootParent == null ) + { + w.WriteLine( "SECTION WORLDITEM {0}", count ); + w.WriteLine( "{" ); + w.WriteLine( "SERIAL {0}", item.Serial ); + w.WriteLine( "NAME #" ); + w.WriteLine( "NAME2 #" ); + w.WriteLine( "ID {0}", item.ItemID ); + w.WriteLine( "X {0}", item.X ); + w.WriteLine( "Y {0}", item.Y ); + w.WriteLine( "Z {0}", item.Z ); + w.WriteLine( "COLOR {0}", item.Hue ); + w.WriteLine( "CONT -1" ); + w.WriteLine( "TYPE 0" ); + w.WriteLine( "AMOUNT 1" ); + w.WriteLine( "WEIGHT 255" ); + w.WriteLine( "OWNER -1" ); + w.WriteLine( "SPAWN -1" ); + w.WriteLine( "VALUE 1" ); + w.WriteLine( "}" ); + w.WriteLine( "" ); + + count++; + remove.Add( item ); + w.Flush(); + } + } + + w.Close(); + + foreach( Item item in remove ) + item.Delete(); + + e.Mobile.SendMessage( "Export complete. Exported {0} statics.", count ); + } + } +} +/*SECTION WORLDITEM 1 +{ +SERIAL 1073741830 +NAME # +NAME2 # +ID 1709 +X 1439 +Y 1613 +Z 20 +CONT -1 +TYPE 12 +AMOUNT 1 +WEIGHT 25500 +OWNER -1 +SPAWN -1 +VALUE 1 +}*/ diff --git a/Scripts/Commands/GenCategorization.cs b/Scripts/Commands/GenCategorization.cs new file mode 100644 index 0000000..2679eee --- /dev/null +++ b/Scripts/Commands/GenCategorization.cs @@ -0,0 +1,426 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; +using System.Reflection; +using Server; +using Server.Items; + +namespace Server.Commands +{ + public class Categorization + { + private static CategoryEntry m_RootItems, m_RootMobiles; + + public static CategoryEntry Items + { + get + { + if ( m_RootItems == null ) + Load(); + + return m_RootItems; + } + } + + public static CategoryEntry Mobiles + { + get + { + if ( m_RootMobiles == null ) + Load(); + + return m_RootMobiles; + } + } + + public static void Initialize() + { + CommandSystem.Register( "RebuildCategorization", AccessLevel.Administrator, new CommandEventHandler( RebuildCategorization_OnCommand ) ); + } + + [Usage( "RebuildCategorization" )] + [Description( "Rebuilds the categorization data file used by the Add command." )] + public static void RebuildCategorization_OnCommand( CommandEventArgs e ) + { + CategoryEntry root = new CategoryEntry( null, "Add Menu", new CategoryEntry[]{ Items, Mobiles } ); + + Export( root, "Data/objects.xml", "Objects" ); + + e.Mobile.SendMessage( "Categorization menu rebuilt." ); + } + + public static void RecurseFindCategories( CategoryEntry ce, ArrayList list ) + { + list.Add( ce ); + + for ( int i = 0; i < ce.SubCategories.Length; ++i ) + RecurseFindCategories( ce.SubCategories[i], list ); + } + + public static void Export( CategoryEntry ce, string fileName, string title ) + { + XmlTextWriter xml = new XmlTextWriter( fileName, System.Text.Encoding.UTF8 ); + + xml.Indentation = 1; + xml.IndentChar = '\t'; + xml.Formatting = Formatting.Indented; + + xml.WriteStartDocument( true ); + + RecurseExport( xml, ce ); + + xml.Flush(); + xml.Close(); + } + + public static void RecurseExport( XmlTextWriter xml, CategoryEntry ce ) + { + xml.WriteStartElement( "category" ); + + xml.WriteAttributeString( "title", ce.Title ); + + ArrayList subCats = new ArrayList( ce.SubCategories ); + + subCats.Sort( new CategorySorter() ); + + for ( int i = 0; i < subCats.Count; ++i ) + RecurseExport( xml, (CategoryEntry)subCats[i] ); + + ce.Matched.Sort( new CategorySorter() ); + + for ( int i = 0; i < ce.Matched.Count; ++i ) + { + CategoryTypeEntry cte = (CategoryTypeEntry)ce.Matched[i]; + + xml.WriteStartElement( "object" ); + + xml.WriteAttributeString( "type", cte.Type.ToString() ); + + object obj = cte.Object; + + if ( obj is Item ) + { + Item item = (Item)obj; + + int itemID = item.ItemID; + + if ( item is BaseAddon && ((BaseAddon)item).Components.Count == 1 ) + itemID = ((AddonComponent)(((BaseAddon)item).Components[0])).ItemID; + + if ( itemID > TileData.MaxItemValue ) + itemID = 1; + + xml.WriteAttributeString( "gfx", XmlConvert.ToString( itemID ) ); + + int hue = item.Hue & 0x7FFF; + + if ( (hue & 0x4000) != 0 ) + hue = 0; + + if ( hue != 0 ) + xml.WriteAttributeString( "hue", XmlConvert.ToString( hue ) ); + + item.Delete(); + } + else if ( obj is Mobile ) + { + Mobile mob = (Mobile)obj; + + int itemID = ShrinkTable.Lookup( mob, 1 ); + + xml.WriteAttributeString( "gfx", XmlConvert.ToString( itemID ) ); + + int hue = mob.Hue & 0x7FFF; + + if ( (hue & 0x4000) != 0 ) + hue = 0; + + if ( hue != 0 ) + xml.WriteAttributeString( "hue", XmlConvert.ToString( hue ) ); + + mob.Delete(); + } + + xml.WriteEndElement(); + } + + xml.WriteEndElement(); + } + + public static void Load() + { + ArrayList types = new ArrayList(); + + AddTypes( Core.Assembly, types ); + + for ( int i = 0; i < ScriptCompiler.Assemblies.Length; ++i ) + AddTypes( ScriptCompiler.Assemblies[i], types ); + + m_RootItems = Load( types, "Data/items.cfg" ); + m_RootMobiles = Load( types, "Data/mobiles.cfg" ); + } + + private static CategoryEntry Load( ArrayList types, string config ) + { + CategoryLine[] lines = CategoryLine.Load( config ); + + if ( lines.Length > 0 ) + { + int index = 0; + CategoryEntry root = new CategoryEntry( null, lines, ref index ); + + Fill( root, types ); + + return root; + } + + return new CategoryEntry(); + } + + private static Type typeofItem = typeof( Item ); + private static Type typeofMobile = typeof( Mobile ); + private static Type typeofConstructable = typeof( ConstructableAttribute ); + + private static bool IsConstructable( Type type ) + { + if ( !type.IsSubclassOf( typeofItem ) && !type.IsSubclassOf( typeofMobile ) ) + return false; + + ConstructorInfo ctor = type.GetConstructor( Type.EmptyTypes ); + + return ( ctor != null && ctor.IsDefined( typeofConstructable, false ) ); + } + + private static void AddTypes( Assembly asm, ArrayList types ) + { + Type[] allTypes = asm.GetTypes(); + + for ( int i = 0; i < allTypes.Length; ++i ) + { + Type type = allTypes[i]; + + if ( type.IsAbstract ) + continue; + + if ( IsConstructable( type ) ) + types.Add( type ); + } + } + + private static void Fill( CategoryEntry root, ArrayList list ) + { + for ( int i = 0; i < list.Count; ++i ) + { + Type type = (Type)list[i]; + CategoryEntry match = GetDeepestMatch( root, type ); + + if ( match == null ) + continue; + + try + { + match.Matched.Add( new CategoryTypeEntry( type ) ); + } + catch + { + } + } + } + + private static CategoryEntry GetDeepestMatch( CategoryEntry root, Type type ) + { + if ( !root.IsMatch( type ) ) + return null; + + for ( int i = 0; i < root.SubCategories.Length; ++i ) + { + CategoryEntry check = GetDeepestMatch( root.SubCategories[i], type ); + + if ( check != null ) + return check; + } + + return root; + } + } + + public class CategorySorter : IComparer + { + public int Compare( object x, object y ) + { + string a = null, b = null; + + if ( x is CategoryEntry ) + a = ((CategoryEntry)x).Title; + else if ( x is CategoryTypeEntry ) + a = ((CategoryTypeEntry)x).Type.Name; + + if ( y is CategoryEntry ) + b = ((CategoryEntry)y).Title; + else if ( y is CategoryTypeEntry ) + b = ((CategoryTypeEntry)y).Type.Name; + + if ( a == null && b == null ) + return 0; + + if ( a == null ) + return 1; + + if ( b == null ) + return -1; + + return a.CompareTo( b ); + } + } + + public class CategoryTypeEntry + { + private Type m_Type; + private object m_Object; + + public Type Type{ get{ return m_Type; } } + public object Object{ get{ return m_Object; } } + + public CategoryTypeEntry( Type type ) + { + m_Type = type; + m_Object = Activator.CreateInstance( type ); + } + } + + public class CategoryEntry + { + private string m_Title; + private Type[] m_Matches; + private CategoryEntry[] m_SubCategories; + private CategoryEntry m_Parent; + private ArrayList m_Matched; + + public string Title{ get{ return m_Title; } } + public Type[] Matches{ get{ return m_Matches; } } + public CategoryEntry Parent{ get{ return m_Parent; } } + public CategoryEntry[] SubCategories{ get{ return m_SubCategories; } } + public ArrayList Matched{ get{ return m_Matched; } } + + public CategoryEntry() + { + m_Title = "(empty)"; + m_Matches = new Type[0]; + m_SubCategories = new CategoryEntry[0]; + m_Matched = new ArrayList(); + } + + public CategoryEntry( CategoryEntry parent, string title, CategoryEntry[] subCats ) + { + m_Parent = parent; + m_Title = title; + m_SubCategories = subCats; + m_Matches = new Type[0]; + m_Matched = new ArrayList(); + } + + public bool IsMatch( Type type ) + { + bool isMatch = false; + + for ( int i = 0; !isMatch && i < m_Matches.Length; ++i ) + isMatch = ( type == m_Matches[i] || type.IsSubclassOf( m_Matches[i] ) ); + + return isMatch; + } + + public CategoryEntry( CategoryEntry parent, CategoryLine[] lines, ref int index ) + { + m_Parent = parent; + + string text = lines[index].Text; + + int start = text.IndexOf( '(' ); + + if ( start < 0 ) + throw new FormatException( String.Format( "Input string not correctly formatted ('{0}')", text ) ); + + m_Title = text.Substring( 0, start ).Trim(); + + int end = text.IndexOf( ')', ++start ); + + if ( end < start ) + throw new FormatException( String.Format( "Input string not correctly formatted ('{0}')", text ) ); + + text = text.Substring( start, end-start ); + string[] split = text.Split( ';' ); + + ArrayList list = new ArrayList(); + + for ( int i = 0; i < split.Length; ++i ) + { + Type type = ScriptCompiler.FindTypeByName( split[i].Trim() ); + + if ( type == null ) + Console.WriteLine( "Match type not found ('{0}')", split[i].Trim() ); + else + list.Add( type ); + } + + m_Matches = (Type[])list.ToArray( typeof( Type ) ); + list.Clear(); + + int ourIndentation = lines[index].Indentation; + + ++index; + + while ( index < lines.Length && lines[index].Indentation > ourIndentation ) + list.Add( new CategoryEntry( this, lines, ref index ) ); + + m_SubCategories = (CategoryEntry[])list.ToArray( typeof( CategoryEntry ) ); + list.Clear(); + + m_Matched = list; + } + } + + public class CategoryLine + { + private int m_Indentation; + private string m_Text; + + public int Indentation{ get{ return m_Indentation; } } + public string Text{ get{ return m_Text; } } + + public CategoryLine( string input ) + { + int index; + + for ( index = 0; index < input.Length; ++index ) + { + if ( Char.IsLetter( input, index ) ) + break; + } + + if ( index >= input.Length ) + throw new FormatException( String.Format( "Input string not correctly formatted ('{0}')", input ) ); + + m_Indentation = index; + m_Text = input.Substring( index ); + } + + public static CategoryLine[] Load( string path ) + { + ArrayList list = new ArrayList(); + + if ( File.Exists( path ) ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + list.Add( new CategoryLine( line ) ); + } + } + + return (CategoryLine[])list.ToArray( typeof( CategoryLine ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/GenTeleporter.cs b/Scripts/Commands/GenTeleporter.cs new file mode 100644 index 0000000..62dfa32 --- /dev/null +++ b/Scripts/Commands/GenTeleporter.cs @@ -0,0 +1,1189 @@ +// Look for +// >>> Nerun's Distro >>> +// to find the changes +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Commands +{ + public class GenTeleporter + { + public GenTeleporter() + { + } + + public static void Initialize() + { + CommandSystem.Register( "TelGen", AccessLevel.Administrator, new CommandEventHandler( GenTeleporter_OnCommand ) ); + } + + [Usage( "TelGen" )] + [Description( "Generates world/dungeon teleporters for all facets." )] + public static void GenTeleporter_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Generating teleporters, please wait." ); + + int count = new TeleportersCreator().CreateTeleporters(); + + count += new SHTeleporter.SHTeleporterCreator().CreateSHTeleporters(); + + e.Mobile.SendMessage( "Teleporter generating complete. {0} teleporters were generated.", count ); + } + + public class TeleportersCreator + { + private int m_Count; + + public TeleportersCreator() + { + } + + private static Queue m_Queue = new Queue(); + + public static bool FindTeleporter( Map map, Point3D p ) + { + IPooledEnumerable eable = map.GetItemsInRange( p, 0 ); + + foreach ( Item item in eable ) + { + if ( item is Teleporter && !(item is KeywordTeleporter) && !(item is SkillTeleporter) ) + { + int delta = item.Z - p.Z; + + if ( delta >= -12 && delta <= 12 ) + m_Queue.Enqueue( item ); + } + } + + eable.Free(); + + while ( m_Queue.Count > 0 ) + ((Item)m_Queue.Dequeue()).Delete(); + + return false; + } + + public void CreateTeleporter( Point3D pointLocation, Point3D pointDestination, Map mapLocation, Map mapDestination, bool back ) + { + if ( !FindTeleporter( mapLocation, pointLocation ) ) + { + m_Count++; + + Teleporter tel = new Teleporter( pointDestination, mapDestination ); + + tel.MoveToWorld( pointLocation, mapLocation ); + } + + if ( back && !FindTeleporter( mapDestination, pointDestination ) ) + { + m_Count++; + + Teleporter telBack = new Teleporter( pointLocation, mapLocation ); + + telBack.MoveToWorld( pointDestination, mapDestination ); + } + } + + public void CreateTeleporter( int xLoc, int yLoc, int zLoc, int xDest, int yDest, int zDest, Map map, bool back ) + { + CreateTeleporter( new Point3D( xLoc, yLoc, zLoc ), new Point3D( xDest, yDest, zDest ), map, map, back); + } + + public void CreateTeleporter( int xLoc, int yLoc, int zLoc, int xDest, int yDest, int zDest, Map mapLocation, Map mapDestination, bool back ) + { + CreateTeleporter( new Point3D( xLoc, yLoc, zLoc ), new Point3D( xDest, yDest, zDest ), mapLocation, mapDestination, back); + } + + public void DestroyTeleporter( int x, int y, int z, Map map ) + { + Point3D p = new Point3D( x, y, z ); + IPooledEnumerable eable = map.GetItemsInRange( p, 0 ); + + foreach ( Item item in eable ) + { + if ( item is Teleporter && !(item is KeywordTeleporter) && !(item is SkillTeleporter) && item.Z == p.Z ) + m_Queue.Enqueue( item ); + } + + eable.Free(); + + while ( m_Queue.Count > 0 ) + ((Item)m_Queue.Dequeue()).Delete(); + } + + public void CreateTeleportersMap( Map map ) + { + // Shame + CreateTeleporter( 512, 1559, 0, 5394, 127, 0, map, true ); + CreateTeleporter( 513, 1559, 0, 5395, 127, 0, map, true ); + CreateTeleporter( 514, 1559, 0, 5396, 127, 0, map, true ); + CreateTeleporter( 5490, 19, -25, 5514, 10, 5, map, true ); + CreateTeleporter( 5875, 19, -5, 5507, 162, 5, map, true ); + CreateTeleporter( 5604, 102, 5, 5514, 147, 25, map, true ); + + CreateTeleporter( 5513, 176, 5, 5540, 187, 0, map, false ); + CreateTeleporter( 5538, 170, 5, 5517, 176, 0, map, false ); + + // Hythloth + CreateTeleporter( 4721, 3813, 0, 5904, 16, 64, map, true ); + CreateTeleporter( 4722, 3813, 0, 5905, 16, 64, map, true ); + CreateTeleporter( 4723, 3813, 0, 5906, 16, 64, map, true ); + CreateTeleporter( 6040, 192, 12, 6059, 88, 24, map, true ); + CreateTeleporter( 6040, 193, 12, 6059, 89, 24, map, true ); + CreateTeleporter( 6040, 194, 12, 6059, 90, 24, map, true ); + + DestroyTeleporter( 5920, 168, 16, map ); + DestroyTeleporter( 5920, 169, 17, map ); + DestroyTeleporter( 5920, 170, 16, map ); + + CreateTeleporter( 5920, 168, 16, 6083, 144, -20, map, false ); + CreateTeleporter( 5920, 169, 16, 6083, 145, -20, map, false ); + CreateTeleporter( 5920, 170, 16, 6083, 146, -20, map, false ); + + CreateTeleporter( 6083, 144, -20, 5920, 168, 22, map, false ); + CreateTeleporter( 6083, 145, -20, 5920, 169, 22, map, false ); + CreateTeleporter( 6083, 146, -20, 5920, 170, 22, map, false ); + + DestroyTeleporter( 5906, 96, 0, map ); + + CreateTeleporter( 5972, 168, 0, 5905, 100, 0, map, false ); + CreateTeleporter( 5906, 96, 0, 5977, 169, 0, map, false ); + + // Covetous + CreateTeleporter( 2498, 916, 0, 5455, 1864, 0, map, true ); + CreateTeleporter( 2499, 916, 0, 5456, 1864, 0, map, true ); + CreateTeleporter( 2500, 916, 0, 5457, 1864, 0, map, true ); + CreateTeleporter( 2384, 836, 0, 5615, 1996, 0, map, true ); + CreateTeleporter( 2384, 837, 0, 5615, 1997, 0, map, true ); + CreateTeleporter( 2384, 838, 0, 5615, 1998, 0, map, true ); + CreateTeleporter( 2420, 883, 0, 5392, 1959, 0, map, true ); + CreateTeleporter( 2421, 883, 0, 5393, 1959, 0, map, true ); + CreateTeleporter( 2422, 883, 0, 5394, 1959, 0, map, true ); + CreateTeleporter( 2455, 858, 0, 5388, 2027, 0, map, true ); + CreateTeleporter( 2456, 858, 0, 5389, 2027, 0, map, true ); + CreateTeleporter( 2457, 858, 0, 5390, 2027, 0, map, true ); + CreateTeleporter( 2544, 850, 0, 5578, 1927, 0, map, true ); + CreateTeleporter( 2545, 850, 0, 5579, 1927, 0, map, true ); + CreateTeleporter( 2546, 850, 0, 5580, 1927, 0, map, true ); + + CreateTeleporter( 5551, 1805, 12, 5556, 1825, -3, map, false ); + CreateTeleporter( 5552, 1805, 12, 5557, 1825, -3, map, false ); + CreateTeleporter( 5553, 1805, 12, 5557, 1825, -3, map, false ); + + DestroyTeleporter( 5551, 1807, 0, map ); + DestroyTeleporter( 5552, 1807, 0, map ); + DestroyTeleporter( 5553, 1807, 0, map ); + + CreateTeleporter( 5556, 1826, -10, 5551, 1806, 7, map, false ); + CreateTeleporter( 5557, 1826, -10, 5552, 1806, 7, map, false ); + + DestroyTeleporter( 5556, 1825, -7, map ); + DestroyTeleporter( 5556, 1827, -13, map ); + DestroyTeleporter( 5557, 1825, -7, map ); + DestroyTeleporter( 5557, 1827, -13, map ); + DestroyTeleporter( 5558, 1825, -7, map ); + + DestroyTeleporter( 5468, 1804, 0, map ); + DestroyTeleporter( 5468, 1805, 0, map ); + DestroyTeleporter( 5468, 1806, 0, map ); + + CreateTeleporter( 5466, 1804, 12, 5593, 1840, -3, map, false ); + CreateTeleporter( 5466, 1805, 12, 5593, 1841, -3, map, false ); + CreateTeleporter( 5466, 1806, 12, 5593, 1842, -3, map, false ); + + DestroyTeleporter( 5595, 1840, -14, map ); + DestroyTeleporter( 5595, 1840, -14, map ); + + CreateTeleporter( 5594, 1840, -9, 5467, 1804, 7, map, false ); + CreateTeleporter( 5594, 1841, -9, 5467, 1805, 7, map, false ); + + // Wrong + CreateTeleporter( 5824, 631, 5, 2041, 215, 14, map, true ); + CreateTeleporter( 5825, 631, 5, 2042, 215, 14, map, true ); + CreateTeleporter( 5825, 631, 5, 2043, 215, 14, map, true ); + CreateTeleporter( 5698, 662, 0, 5793, 527, 10, map, false ); + + DestroyTeleporter( 5863, 525, 15, map ); + DestroyTeleporter( 5863, 526, 15, map ); + DestroyTeleporter( 5863, 527, 15, map ); + DestroyTeleporter( 5868, 537, 15, map ); + DestroyTeleporter( 5868, 538, 15, map ); + DestroyTeleporter( 5869, 538, 15, map ); + DestroyTeleporter( 5733, 554, 20, map ); + DestroyTeleporter( 5862, 527, 15, map ); + + // Deceit + CreateTeleporter( 4110, 430, 5, 5187, 639, 0, map, false ); + CreateTeleporter( 4111, 430, 5, 5188, 639, 0, map, false ); + CreateTeleporter( 4112, 430, 5, 5189, 639, 0, map, false ); + CreateTeleporter( 5187, 639, 0, 4110, 430, 5, map, false ); + CreateTeleporter( 5188, 639, 0, 4111, 430, 5, map, false ); + CreateTeleporter( 5189, 639, 0, 4112, 430, 5, map, false ); + CreateTeleporter( 5216, 586, -13, 5304, 533, 2, map, false ); + CreateTeleporter( 5217, 586, -13, 5305, 533, 2, map, false ); + CreateTeleporter( 5218, 586, -13, 5306, 533, 2, map, false ); + CreateTeleporter( 5304, 532, 7, 5216, 585, -8, map, false ); + CreateTeleporter( 5305, 532, 7, 5217, 585, -8, map, false ); + CreateTeleporter( 5306, 532, 7, 5218, 585, -8, map, false ); + CreateTeleporter( 5218, 761, -28, 5305, 651, 7, map, false ); + CreateTeleporter( 5219, 761, -28, 5306, 651, 7, map, false ); + CreateTeleporter( 5305, 650, 12, 5218, 760, -23, map, false ); + CreateTeleporter( 5306, 650, 12, 5219, 760, -23, map, false ); + CreateTeleporter( 5346, 578, 5, 5137, 649, 5, map, true ); + + CreateTeleporter( 5186, 639, 0, 4110, 430, 5, map, false ); + + // Despise + CreateTeleporter( 5504, 569, 46, 5574, 628, 37, map, false ); + CreateTeleporter( 5504, 570, 46, 5574, 629, 37, map, false ); + CreateTeleporter( 5504, 571, 46, 5574, 630, 37, map, false ); + CreateTeleporter( 5572, 632, 17, 5521, 672, 27, map, false ); + CreateTeleporter( 5572, 633, 17, 5521, 673, 27, map, false ); + CreateTeleporter( 5572, 634, 17, 5521, 674, 27, map, false ); + CreateTeleporter( 5573, 628, 42, 5503, 569, 51, map, false ); + CreateTeleporter( 5573, 629, 42, 5503, 570, 51, map, false ); + CreateTeleporter( 5573, 630, 42, 5503, 571, 51, map, false ); + CreateTeleporter( 5588, 632, 30, 1296, 1082, 0, map, true ); + CreateTeleporter( 5588, 630, 30, 1296, 1080, 0, map, true ); + CreateTeleporter( 5588, 631, 30, 1296, 1081, 0, map, true ); + CreateTeleporter( 5522, 672, 32, 5573, 632, 22, map, false ); + CreateTeleporter( 5522, 673, 32, 5573, 633, 22, map, false ); + CreateTeleporter( 5522, 674, 32, 5573, 634, 22, map, false ); + CreateTeleporter( 5386, 756, -8, 5408, 859, 47, map, false ); + CreateTeleporter( 5386, 757, -8, 5408, 860, 47, map, false ); + CreateTeleporter( 5386, 755, -8, 5408, 858, 47, map, false ); + CreateTeleporter( 5409, 860, 52, 5387, 757, -3, map, false ); + CreateTeleporter( 5409, 858, 52, 5387, 755, -3, map, false ); + CreateTeleporter( 5409, 859, 52, 5387, 756, -3, map, false ); + + // Destard + CreateTeleporter( 5242, 1007, 0, 1175, 2635, 0, map, true ); + CreateTeleporter( 5243, 1007, 0, 1176, 2635, 0, map, true ); + CreateTeleporter( 5244, 1007, 0, 1177, 2635, 0, map, true ); + CreateTeleporter( 5142, 797, 22, 5129, 908, -23, map, false ); + CreateTeleporter( 5143, 797, 22, 5130, 908, -23, map, false ); + CreateTeleporter( 5144, 797, 22, 5131, 908, -23, map, false ); + CreateTeleporter( 5145, 797, 22, 5132, 908, -23, map, false ); + CreateTeleporter( 5153, 808, -25, 5134, 984, 17, map, false ); + CreateTeleporter( 5153, 809, -25, 5134, 985, 17, map, false ); + CreateTeleporter( 5153, 810, -25, 5134, 986, 17, map, false ); + CreateTeleporter( 5153, 811, -25, 5134, 987, 17, map, false ); + CreateTeleporter( 5129, 909, -28, 5142, 798, 17, map, false ); + CreateTeleporter( 5130, 909, -28, 5143, 798, 17, map, false ); + CreateTeleporter( 5131, 909, -28, 5144, 798, 17, map, false ); + CreateTeleporter( 5132, 909, -28, 5145, 798, 17, map, false ); + CreateTeleporter( 5133, 984, 22, 5152, 808, -19, map, false ); + CreateTeleporter( 5133, 985, 22, 5152, 809, -19, map, false ); + CreateTeleporter( 5133, 986, 22, 5152, 810, -19, map, false ); + CreateTeleporter( 5133, 987, 22, 5152, 811, -19, map, false ); + + // Buccaneer's Den underground tunnels + + DestroyTeleporter( 2666, 2073, 5, map ); + DestroyTeleporter( 2669, 2072, -20, map ); + DestroyTeleporter( 2669, 2073, -20, map ); + DestroyTeleporter( 2649, 2194, 4, map ); + DestroyTeleporter( 2649, 2195, -14, map ); + + CreateTeleporter( 2603, 2121, -20, 2605, 2130, 8, map, false ); + CreateTeleporter( 2603, 2120, -20, 2605, 2130, 8, map, false ); + CreateTeleporter( 2669, 2071, -20, 2666, 2099, 3, map, false ); + CreateTeleporter( 2669, 2072, -20, 2666, 2099, 3, map, false ); + CreateTeleporter( 2669, 2073, -20, 2666, 2099, 3, map, false ); + CreateTeleporter( 2676, 2241, -18, 2691, 2234, 2, map, false ); + CreateTeleporter( 2676, 2242, -18, 2691, 2234, 2, map, false ); + CreateTeleporter( 2758, 2092, -20, 2756, 2097, 38, map, false ); + CreateTeleporter( 2759, 2092, -20, 2756, 2097, 38, map, false ); + CreateTeleporter( 2685, 2063, 39, 2685, 2063, -20, map, false ); // that should not be a teleporter: on OSI you simply fall under the ground + + // Misc + CreateTeleporter( 5217, 18, 15, 5204, 74, 17, map, false ); + CreateTeleporter( 5200, 71, 17, 5211, 22, 15, map, false ); + CreateTeleporter( 1997, 81, 7, 5881, 242, 0, map, false ); + CreateTeleporter( 5704, 146, -45, 5705, 305, 7, map, false ); + CreateTeleporter( 5704, 147, -45, 5705, 306, 7, map, false ); + CreateTeleporter( 5874, 146, 27, 5208, 2323, 31, map, false ); + CreateTeleporter( 5875, 146, 27, 5208, 2322, 32, map, false ); + CreateTeleporter( 5876, 146, 27, 5208, 2322, 32, map, false ); + CreateTeleporter( 5877, 146, 27, 5208, 2322, 32, map, false ); + CreateTeleporter( 5923, 169, 1, 5925, 171, 22, map, false ); + CreateTeleporter( 2399, 198, 0, 5753, 436, 79, map, false ); + CreateTeleporter( 2400, 198, 0, 5754, 436, 80, map, false ); + DestroyTeleporter( 5166, 245, 15, map ); + DestroyTeleporter( 1361, 883, 0, map ); + CreateTeleporter( 5191, 152, 0, 1367, 891, 0, map, false ); + CreateTeleporter( 5849, 239, -25, 5831, 324, 27, map, false ); + CreateTeleporter( 5850, 239, -25, 5832, 324, 26, map, false ); + CreateTeleporter( 5851, 239, -25, 5833, 324, 28, map, false ); + CreateTeleporter( 5852, 239, -25, 5834, 324, 27, map, false ); + CreateTeleporter( 5853, 239, -23, 5835, 324, 27, map, false ); + CreateTeleporter( 5882, 241, 0, 1998, 81, 5, map, false ); + CreateTeleporter( 5882, 242, 0, 1998, 81, 5, map, false ); + CreateTeleporter( 5882, 243, 0, 1998, 81, 5, map, false ); + CreateTeleporter( 5706, 305, 12, 5705, 146, -45, map, false ); + CreateTeleporter( 5706, 306, 12, 5705, 147, -45, map, false ); + CreateTeleporter( 5748, 362, 2, 313, 786, -24, map, false ); + CreateTeleporter( 5749, 362, 0, 313, 786, -24, map, false ); + CreateTeleporter( 5750, 362, 3, 314, 786, -24, map, false ); + CreateTeleporter( 5753, 324, 21, 5670, 2391, 40, map, false ); + CreateTeleporter( 5831, 323, 34, 5849, 238, -25, map, false ); + CreateTeleporter( 5832, 323, 34, 5850, 238, -25, map, false ); + CreateTeleporter( 5833, 323, 33, 5851, 238, -25, map, false ); + CreateTeleporter( 5834, 323, 33, 5852, 238, -25, map, false ); + CreateTeleporter( 5835, 323, 33, 5853, 238, -23, map, false ); + CreateTeleporter( 5658, 423, 8, 5697, 3659, 2, map, false ); + CreateTeleporter( 5686, 385, 2, 2777, 894, -23, map, false ); + CreateTeleporter( 5686, 386, 2, 2777, 894, -23, map, false ); + CreateTeleporter( 5686, 387, 2, 2777, 895, -23, map, false ); + CreateTeleporter( 5731, 445, -18, 6087, 3676, 18, map, false ); + CreateTeleporter( 5753, 437, 78, 2400, 199, 0, map, false ); + CreateTeleporter( 5850, 432, 0, 5127, 3143, 97, map, false ); + CreateTeleporter( 5850, 433, -2, 5127, 3143, 97, map, false ); + CreateTeleporter( 5850, 434, -1, 5127, 3143, 97, map, false ); + CreateTeleporter( 5850, 431, 2, 5127, 3143, 97, map, false ); + CreateTeleporter( 5826, 465, -1, 1987, 2063, -40, map, false ); + CreateTeleporter( 5827, 465, -1, 1988, 2063, -40, map, false ); + CreateTeleporter( 5828, 465, 0, 1989, 2063, -40, map, false ); + CreateTeleporter( 313, 786, -24, 5748, 361, 2, map, false ); + CreateTeleporter( 314, 786, -24, 5749, 361, 2, map, false ); + CreateTeleporter( 2776, 895, -23, 5685, 387, 2, map, false ); + //CreateTeleporter( 4545, 851, 30, 5736, 3196, 8, map, false ); + DestroyTeleporter( 4545, 851, 30, map ); + CreateTeleporter( 4540, 898, 32, 4442, 1122, 5, map, false ); + CreateTeleporter( 4300, 968, 5, 4442, 1122, 5, map, false ); + CreateTeleporter( 4436, 1107, 5, 4300, 992, 5, map, false ); + CreateTeleporter( 4443, 1137, 5, 4487, 1475, 5, map, false ); + CreateTeleporter( 4449, 1107, 5, 4539, 890, 28, map, false ); + CreateTeleporter( 4449, 1115, 5, 4671, 1135, 10, map, false ); + CreateTeleporter( 4663, 1134, 13, 4442, 1122, 5, map, false ); + CreateTeleporter( 5701, 1320, 16, 5786, 1336, -8, map, false ); + CreateTeleporter( 5702, 1320, 16, 5787, 1336, -8, map, false ); + CreateTeleporter( 5703, 1320, 16, 5788, 1336, -8, map, false ); + CreateTeleporter( 5786, 1335, -13, 5701, 1319, 13, map, false ); + CreateTeleporter( 5787, 1335, -13, 5702, 1319, 13, map, false ); + CreateTeleporter( 5788, 1335, -13, 5703, 1319, 13, map, false ); + CreateTeleporter( 6005, 1380, 1, 5151, 4063, 37, map, false ); + CreateTeleporter( 6005, 1378, 0, 5151, 4062, 37, map, false ); + CreateTeleporter( 6005, 1379, 2, 5151, 4062, 37, map, false ); + CreateTeleporter( 6025, 1344, -26, 5137, 3664, 27, map, false ); + CreateTeleporter( 6025, 1345, -26, 5137, 3664, 27, map, false ); + CreateTeleporter( 6025, 1346, -26, 5137, 3665, 31, map, false ); + CreateTeleporter( 5687, 1424, 38, 2923, 3406, 8, map, false ); + CreateTeleporter( 5792, 1416, 41, 5758, 2908, 15, map, false ); + CreateTeleporter( 5792, 1417, 41, 5758, 2909, 15, map, false ); + CreateTeleporter( 5792, 1415, 41, 5758, 2907, 15, map, false ); + CreateTeleporter( 5899, 1411, 43, 1630, 3320, 0, map, false ); + CreateTeleporter( 5900, 1411, 42, 1630, 3320, 0, map, false ); + CreateTeleporter( 5918, 1412, -29, 5961, 1409, 59, map, false ); + CreateTeleporter( 5918, 1410, -29, 5961, 1408, 59, map, false ); + CreateTeleporter( 5918, 1411, -29, 5961, 1408, 59, map, false ); + CreateTeleporter( 5961, 1408, 59, 5918, 1411, -29, map, false ); + CreateTeleporter( 5961, 1409, 59, 5918, 1412, -29, map, false ); + CreateTeleporter( 6125, 1411, 15, 6075, 3332, 4, map, false ); + CreateTeleporter( 6126, 1411, 15, 6075, 3332, 4, map, false ); + CreateTeleporter( 6127, 1411, 15, 6075, 3332, 4, map, false ); + CreateTeleporter( 6137, 1409, 2, 6140, 1432, 4, map, false ); + CreateTeleporter( 6138, 1409, 2, 6140, 1432, 4, map, false ); + CreateTeleporter( 6140, 1431, 4, 6137, 1408, 2, map, false ); + CreateTeleporter( 4496, 1475, 15, 4442, 1122, 5, map, false ); + CreateTeleporter( 6031, 1501, 42, 1491, 1642, 24, map, false ); + CreateTeleporter( 6031, 1499, 42, 1491, 1640, 24, map, false ); + CreateTeleporter( 1491, 1640, 24, 6032, 1499, 31, map, false ); + CreateTeleporter( 1491, 1642, 24, 6032, 1501, 31, map, false ); + DestroyTeleporter( 5341, 1602, 0, map ); + CreateTeleporter( 5340, 1599, 40, 5426, 3122, -74, map, false ); + CreateTeleporter( 5341, 1599, 40, 5426, 3122, -74, map, false ); + CreateTeleporter( 1987, 2062, -40, 5826, 464, 0, map, false ); + CreateTeleporter( 1988, 2062, -40, 5827, 464, -1, map, false ); + CreateTeleporter( 1989, 2062, -40, 5828, 464, -1, map, false ); + CreateTeleporter( 5203, 2327, 27, 5876, 147, 25, map, false ); + CreateTeleporter( 5207, 2322, 27, 5877, 147, 25, map, false ); + CreateTeleporter( 5207, 2323, 26, 5876, 147, 25, map, false ); + CreateTeleporter( 5670, 2391, 40, 5753, 325, 10, map, false ); + CreateTeleporter( 5974, 2697, 35, 2985, 2890, 35, map, false ); + CreateTeleporter( 5267, 2757, 35, 424, 3283, 35, map, false ); + CreateTeleporter( 5757, 2908, 14, 5791, 1416, 38, map, false ); + CreateTeleporter( 5757, 2909, 15, 5791, 1417, 40, map, false ); + CreateTeleporter( 5757, 2907, 15, 5791, 1415, 38, map, false ); + CreateTeleporter( 1653, 2963, 0, 1677, 2987, 0, map, false ); + CreateTeleporter( 1677, 2987, 0, 1675, 2987, 20, map, false ); + CreateTeleporter( 5426, 3123, -80, 5341, 1602, 0, map, false ); + CreateTeleporter( 5126, 3143, 99, 5849, 432, 1, map, false ); + //CreateTeleporter( 5736, 3196, 8, 4545, 851, 30, map, false ); + DestroyTeleporter( 5736, 3196, 8, map ); + CreateTeleporter( 424, 3283, 35, 5267, 2757, 35, map, false ); + CreateTeleporter( 1629, 3320, 0, 5899, 1411, 43, map, false ); + CreateTeleporter( 6075, 3332, 4, 6126, 1410, 15, map, false ); + CreateTeleporter( 2923, 3405, 6, 5687, 1423, 39, map, false ); + CreateTeleporter( 1142, 3621, 5, 1414, 3828, 5, map, false ); + CreateTeleporter( 5137, 3664, 27, 6025, 1344, -26, map, false ); + CreateTeleporter( 5137, 3665, 31, 6025, 1345, -26, map, false ); + CreateTeleporter( 5697, 3660, -5, 5658, 424, 0, map, false ); + CreateTeleporter( 6086, 3676, 16, 5731, 446, -16, map, false ); + CreateTeleporter( 1409, 3824, 5, 1124, 3623, 5, map, false ); + CreateTeleporter( 1419, 3832, 5, 1466, 4015, 5, map, false ); + CreateTeleporter( 1406, 3996, 5, 1414, 3828, 5, map, false ); + CreateTeleporter( 5150, 4062, 38, 6005, 1378, 0, map, false ); + CreateTeleporter( 5150, 4063, 38, 6005, 1380, 1, map, false ); + CreateTeleporter( 5906, 4069, 26, 2494, 3576, 5, map, true ); + CreateTeleporter( 2985, 2890, 35, 5974, 2697, 35, map, false ); + + // Mondain's Legacy dungeons + + // Sanctuary + CreateTeleporter( 6172, 21, 0, 765, 1645, 0, map, false ); // Entrance gate + CreateTeleporter( 6172, 22, 0, 765, 1646, 0, map, false ); + CreateTeleporter( 6172, 23, 0, 765, 1647, 0, map, false ); + CreateTeleporter( 766, 1645, 0, 6174, 21, 0, map, false ); + CreateTeleporter( 766, 1646, 0, 6174, 22, 0, map, false ); + CreateTeleporter( 766, 1647, 0, 6174, 23, 0, map, false ); + + CreateTeleporter( 6173, 176, -10, 6233, 15, -10, map, false ); // Zone change + CreateTeleporter( 6174, 176, -10, 6234, 15, -10, map, false ); + CreateTeleporter( 6175, 176, -10, 6235, 15, -10, map, false ); + CreateTeleporter( 6176, 176, -10, 6236, 15, -10, map, false ); + CreateTeleporter( 6177, 176, -10, 6237, 15, -10, map, false ); + CreateTeleporter( 6178, 176, -10, 6238, 15, -10, map, false ); + CreateTeleporter( 6179, 176, -10, 6239, 15, -10, map, false ); + CreateTeleporter( 6233, 14, -10, 6172, 174, -10, map, false ); + CreateTeleporter( 6234, 14, -10, 6173, 174, -10, map, false ); + CreateTeleporter( 6235, 14, -10, 6174, 174, -10, map, false ); + CreateTeleporter( 6236, 14, -10, 6175, 174, -10, map, false ); + CreateTeleporter( 6237, 14, -10, 6176, 174, -10, map, false ); + CreateTeleporter( 6238, 14, -10, 6177, 174, -10, map, false ); + CreateTeleporter( 6239, 14, -10, 6177, 174, -10, map, false ); + CreateTeleporter( 6240, 14, -10, 6178, 174, -10, map, false ); + + CreateTeleporter( 6256, 97, -4, 6257, 95, -10, map, false ); // Ladders + CreateTeleporter( 6260, 97, -4, 6260, 95, -10, map, false ); + CreateTeleporter( 6263, 97, -4, 6262, 95, -10, map, false ); + CreateTeleporter( 6269, 97, -4, 6269, 95, -10, map, false ); + CreateTeleporter( 6273, 97, -4, 6272, 95, -10, map, false ); + CreateTeleporter( 6262, 95, -10, 6262, 99, -10, map, false ); + + CreateTeleporter( 6159, 130, 0, 6317, 63, -20, map, false ); // Holes + CreateTeleporter( 6164, 73, 0, 6320, 22, -20, map, false ); + CreateTeleporter( 6161, 163, -10, 6321, 106, -20, map, false ); + CreateTeleporter( 6276, 40, -10, 6374, 124, -20, map, false ); + CreateTeleporter( 6211, 106, 0, 6355, 34, -20, map, false ); + + CreateTeleporter( 6316, 62, -5, 6160, 131, 0, map, false ); // Cave ladders + CreateTeleporter( 6319, 19, -20, 6165, 74, 0, map, false ); // This actually goes to (6165, 75) inside the wall... + CreateTeleporter( 6356, 32, -9, 6210, 105, 0, map, false ); + CreateTeleporter( 6374, 125, -20, 6277, 41, -10, map, false ); + + CreateTeleporter( 6373, 49, -20, 801, 1682, 0, map, false ); + CreateTeleporter( 6374, 49, -20, 801, 1682, 0, map, false ); + CreateTeleporter( 6375, 49, -20, 801, 1682, 0, map, false ); + CreateTeleporter( 6376, 49, -20, 801, 1682, 0, map, false ); + CreateTeleporter( 6377, 49, -20, 801, 1682, 0, map, false ); + + // Painted Caves + CreateTeleporter( 1714, 2996, 0, 6308, 892, 0, map, false ); // Entrance + CreateTeleporter( 1714, 2997, 0, 6308, 892, 0, map, false ); + CreateTeleporter( 6310, 890, 0, 1716, 2997, 0, map, false ); + CreateTeleporter( 6310, 891, 0, 1716, 2997, 0, map, false ); + CreateTeleporter( 6310, 892, 0, 1716, 2997, 0, map, false ); + CreateTeleporter( 6310, 893, 0, 1716, 2997, 0, map, false ); + } + + public void CreateTeleportersMap2( Map map ) + { + // Dungeon of rock + CreateTeleporter( 2186, 294, -27, 2186, 33, -27, map, true ); + CreateTeleporter( 2187, 294, -27, 2187, 33, -27, map, true ); + CreateTeleporter( 2188, 294, -27, 2188, 33, -27, map, true ); + CreateTeleporter( 2189, 294, -27, 2189, 33, -27, map, true ); + CreateTeleporter( 2189, 320, -7, 1788, 569, 74, map, true ); + CreateTeleporter( 2188, 320, -7, 1787, 569, 74, map, true ); + CreateTeleporter( 2187, 320, -7, 1787, 569, 74, map, false ); + + // Spider Cave + DestroyTeleporter( 1783, 993, -28, map ); + DestroyTeleporter( 1784, 993, -28, map ); + DestroyTeleporter( 1785, 993, -28, map ); + DestroyTeleporter( 1786, 993, -28, map ); + DestroyTeleporter( 1787, 993, -28, map ); + DestroyTeleporter( 1788, 993, -28, map ); + + DestroyTeleporter( 1419, 910, -10, map ); + DestroyTeleporter( 1420, 910, -10, map ); + DestroyTeleporter( 1421, 910, -10, map ); + DestroyTeleporter( 1422, 910, -10, map ); + + CreateTeleporter( 1419, 909, -10, 1784, 994, -28, map, true ); + CreateTeleporter( 1420, 909, -10, 1785, 994, -28, map, true ); + CreateTeleporter( 1421, 909, -10, 1786, 994, -28, map, true ); + CreateTeleporter( 1787, 994, -28, 1421, 909, -10, map, false ); + CreateTeleporter( 1788, 994, -28, 1421, 909, -10, map, false ); + CreateTeleporter( 1783, 994, -28, 1419, 909, -10, map, false ); + + CreateTeleporter( 1861, 980, -28, 1490, 877, 10, map, true ); + CreateTeleporter( 1861, 981, -28, 1490, 878, 10, map, true ); + CreateTeleporter( 1861, 982, -28, 1490, 879, 10, map, true ); + CreateTeleporter( 1861, 983, -28, 1490, 880, 10, map, true ); + CreateTeleporter( 1861, 984, -28, 1490, 880, 10, map, false ); + CreateTeleporter( 1516, 879, 10, 1363, 1105, -26, map, true ); + + // Spectre Dungeon + CreateTeleporter( 1362, 1031, -13, 1981, 1107, -16, map, true ); + CreateTeleporter( 1363, 1031, -13, 1982, 1107, -16, map, true ); + CreateTeleporter( 1364, 1031, -13, 1983, 1107, -16, map, true ); + CreateTeleporter( 1980, 1107, -16, 1362, 1031, -13, map, false ); + CreateTeleporter( 1984, 1107, -16, 1364, 1031, -13, map, false ); + + // BLOOD DUNGEON + CreateTeleporter( 1745, 1236, -30, 2112, 829, -11, map, true ); + CreateTeleporter( 1746, 1236, -30, 2113, 829, -11, map, true ); + CreateTeleporter( 1747, 1236, -30, 2114, 829, -11, map, true ); + CreateTeleporter( 1748, 1236, -30, 2115, 829, -11, map, true ); + CreateTeleporter( 2116, 829, -11, 1748, 1236, -30, map, false ); + + // Mushroom Cave + CreateTeleporter( 1456, 1328, -27, 1479, 1494, -28, map, true ); + CreateTeleporter( 1456, 1329, -27, 1479, 1495, -28, map, true ); + CreateTeleporter( 1456, 1330, -27, 1479, 1496, -28, map, true ); + CreateTeleporter( 1479, 1493, -28, 1456, 1328, -27, map, false ); + CreateTeleporter( 1479, 1497, -28, 1456, 1330, -27, map, false ); + + // RATMAN CAVE + CreateTeleporter( 1029, 1155, -24, 1349, 1512, -3, map, true ); + CreateTeleporter( 1029, 1154, -24, 1349, 1511, -3, map, true ); + CreateTeleporter( 1029, 1153, -24, 1349, 1510, -3, map, true ); + CreateTeleporter( 1349, 1509, -3, 1030, 1153, -24, map, false ); + CreateTeleporter( 1268, 1508, -28, 1250, 1508, -28, map, true ); + CreateTeleporter( 1268, 1509, -28, 1250, 1509, -28, map, true ); + CreateTeleporter( 1268, 1510, -28, 1250, 1510, -28, map, true ); + CreateTeleporter( 1250, 1511, -28, 1268, 1510, -28, map, false ); + CreateTeleporter( 1250, 1512, -28, 1268, 1510, -28, map, false ); + + // Serpentine Passage + DestroyTeleporter( 532, 1532, -7, map ); + DestroyTeleporter( 533, 1532, -7, map ); + DestroyTeleporter( 534, 1532, -7, map ); + + CreateTeleporter( 810, 874, -39, 532, 1532, -7, map, false ); + CreateTeleporter( 811, 874, -39, 533, 1532, -7, map, false ); + CreateTeleporter( 812, 874, -39, 534, 1532, -7, map, false ); + CreateTeleporter( 531, 1533, -4, 810, 875, -40, map, false ); + CreateTeleporter( 532, 1533, -4, 811, 875, -39, map, false ); + CreateTeleporter( 533, 1533, -4, 812, 875, -39, map, false ); + CreateTeleporter( 534, 1533, -4, 813, 875, -40, map, false ); + + CreateTeleporter( 393, 1587, -13, 78, 1366, -36, map, false ); + CreateTeleporter( 394, 1587, -13, 79, 1366, -36, map, false ); + CreateTeleporter( 395, 1587, -13, 80, 1366, -36, map, false ); + CreateTeleporter( 396, 1587, -13, 81, 1366, -36, map, false ); + CreateTeleporter( 78, 1365, -41, 393, 1586, -16, map, false ); + CreateTeleporter( 79, 1365, -41, 394, 1586, -16, map, false ); + CreateTeleporter( 80, 1365, -41, 395, 1586, -16, map, false ); + CreateTeleporter( 81, 1365, -41, 396, 1586, -16, map, false ); + DestroyTeleporter( 82, 1365, -38, map ); + + // ANKH DUNGEON + DestroyTeleporter( 4, 1267, -11, map ); + DestroyTeleporter( 4, 1268, -11, map ); + DestroyTeleporter( 4, 1269, -11, map ); + CreateTeleporter( 668, 928, -84, 3, 1267, -8, map, true ); + CreateTeleporter( 668, 929, -84, 3, 1268, -8, map, true ); + CreateTeleporter( 668, 930, -82, 3, 1269, -8, map, true ); + + DestroyTeleporter( 154, 1473, -8, map ); + DestroyTeleporter( 155, 1473, -8, map ); + DestroyTeleporter( 156, 1473, -8, map ); + CreateTeleporter( 575, 1156, -121, 154, 1473, -8, map, false ); + CreateTeleporter( 576, 1156, -121, 155, 1473, -8, map, false ); + CreateTeleporter( 577, 1156, -121, 156, 1473, -8, map, false ); + CreateTeleporter( 154, 1472, -8, 575, 1155, -121, map, false ); + CreateTeleporter( 155, 1472, -8, 576, 1155, -120, map, false ); + CreateTeleporter( 156, 1472, -8, 577, 1155, -120, map, false ); + + DestroyTeleporter( 10, 1518, -28, map ); + DestroyTeleporter( 10, 1518, -27, map ); + DestroyTeleporter( 10, 1518, -27, map ); + CreateTeleporter( 10, 872, -28, 10, 1518, -27, map, false ); + CreateTeleporter( 11, 872, -28, 11, 1518, -28, map, false ); + CreateTeleporter( 12, 872, -27, 12, 1518, -28, map, false ); + CreateTeleporter( 10, 1519, -28, 10, 873, -28, map, false ); + CreateTeleporter( 11, 1519, -27, 11, 873, -28, map, false ); + CreateTeleporter( 12, 1519, -27, 12, 873, -27, map, false ); + + // Ratman Lair + CreateTeleporter( 636, 813, -62, 164, 743, -28, map, false ); + CreateTeleporter( 164, 746, -16, 636, 815, -52, map, false ); + + // WISP DUNGEON + CreateTeleporter( 348, 1427, 15, 18, 1198, -5, map, true ); + CreateTeleporter( 349, 1427, 15, 19, 1198, -5, map, true ); + CreateTeleporter( 350, 1427, 15, 20, 1198, -5, map, true ); + CreateTeleporter( 351, 1427, 15, 21, 1198, -5, map, true ); + CreateTeleporter( 712, 1490, -3, 686, 1490, -28, map, false ); + CreateTeleporter( 712, 1491, -3, 686, 1491, -28, map, false ); + CreateTeleporter( 712, 1492, -3, 686, 1492, -28, map, false ); + CreateTeleporter( 712, 1493, -3, 686, 1493, -28, map, false ); + CreateTeleporter( 694, 1490, -53, 719, 1490, -28, map, false ); + CreateTeleporter( 694, 1491, -53, 719, 1491, -28, map, false ); + CreateTeleporter( 694, 1492, -53, 719, 1492, -28, map, false ); + CreateTeleporter( 694, 1493, -53, 719, 1493, -28, map, false ); + CreateTeleporter( 775, 1467, -28, 658, 1498, -28, map, false ); + DestroyTeleporter( 658, 1498, -28, map ); + CreateTeleporter( 838, 1550, -6, 728, 1505, -28, map, false ); + CreateTeleporter( 838, 1551, -6, 728, 1506, -28, map, false ); + CreateTeleporter( 838, 1552, -6, 728, 1507, -28, map, false ); + CreateTeleporter( 838, 1553, -6, 728, 1508, -28, map, false ); + CreateTeleporter( 722, 1505, -53, 833, 1550, -28, map, false ); + CreateTeleporter( 722, 1506, -53, 833, 1551, -28, map, false ); + CreateTeleporter( 722, 1507, -53, 833, 1552, -28, map, false ); + CreateTeleporter( 722, 1508, -53, 833, 1553, -28, map, false ); + CreateTeleporter( 954, 1425, -53, 874, 1490, 2, map, false ); + CreateTeleporter( 954, 1426, -53, 874, 1491, 2, map, false ); + CreateTeleporter( 954, 1427, -53, 874, 1492, 2, map, false ); + CreateTeleporter( 954, 1428, -53, 874, 1493, 2, map, false ); + CreateTeleporter( 954, 1429, -53, 874, 1493, 2, map, false ); + CreateTeleporter( 879, 1490, 24, 960, 1425, -28, map, false ); + CreateTeleporter( 879, 1491, 24, 960, 1426, -28, map, false ); + CreateTeleporter( 879, 1492, 24, 960, 1427, -28, map, false ); + CreateTeleporter( 879, 1493, 24, 960, 1428, -28, map, false ); + CreateTeleporter( 948, 1464, -56, 951, 1442, -6, map, true ); + CreateTeleporter( 948, 1465, -56, 951, 1443, -6, map, true ); + CreateTeleporter( 948, 1466, -56, 951, 1444, -6, map, true ); + CreateTeleporter( 948, 1467, -56, 951, 1445, -6, map, true ); + CreateTeleporter( 871, 1433, -6, 897, 1449, -28, map, false ); + CreateTeleporter( 871, 1434, -6, 897, 1450, -28, map, false ); + CreateTeleporter( 871, 1435, -6, 897, 1451, -28, map, false ); + CreateTeleporter( 871, 1436, -6, 897, 1452, -28, map, false ); + CreateTeleporter( 871, 1437, -6, 897, 1453, -28, map, false ); + CreateTeleporter( 892, 1449, -51, 866, 1433, -28, map, false ); + CreateTeleporter( 892, 1450, -51, 866, 1434, -28, map, false ); + CreateTeleporter( 892, 1451, -51, 866, 1435, -28, map, false ); + CreateTeleporter( 892, 1452, -51, 866, 1436, -28, map, false ); + CreateTeleporter( 892, 1453, -51, 866, 1437, -28, map, false ); + CreateTeleporter( 812, 1546, -6, 848, 1434, -28, map, false ); + CreateTeleporter( 812, 1547, -6, 848, 1435, -28, map, false ); + CreateTeleporter( 812, 1548, -6, 848, 1436, -28, map, false ); + CreateTeleporter( 812, 1549, -6, 848, 1437, -28, map, false ); + CreateTeleporter( 843, 1434, -51, 807, 1546, -28, map, false ); + CreateTeleporter( 843, 1435, -51, 807, 1547, -28, map, false ); + CreateTeleporter( 843, 1436, -51, 807, 1548, -28, map, false ); + CreateTeleporter( 843, 1437, -51, 807, 1549, -28, map, false ); + CreateTeleporter( 751, 1473, -28, 763, 1479, -28, map, false ); + DestroyTeleporter( 763, 1479, -28, map ); + CreateTeleporter( 751, 1479, -28, 763, 1555, -28, map, false ); + DestroyTeleporter( 763, 1555, -28, map ); + CreateTeleporter( 752, 1549, -28, 751, 1484, -28, map, false ); + DestroyTeleporter( 751, 1484, -28, map ); + CreateTeleporter( 775, 1492, -28, 827, 1515, -28, map, false ); + DestroyTeleporter( 827, 1515, -28, map ); + DestroyTeleporter( 1013, 1506, 0, map ); + DestroyTeleporter( 1013, 1507, 0, map ); + DestroyTeleporter( 1013, 1508, 0, map ); + DestroyTeleporter( 1013, 1509, 0, map ); + CreateTeleporter( 904, 1360, -21, 1014, 1506, 0, map, true ); + CreateTeleporter( 904, 1361, -21, 1014, 1507, 0, map, true ); + CreateTeleporter( 904, 1362, -21, 1014, 1508, 0, map, true ); + CreateTeleporter( 904, 1363, -21, 1014, 1509, 0, map, true ); + + /*CreateTeleporter( 650, 1297, -58, 626, 1526, -28, map, true ); + CreateTeleporter( 651, 1297, -58, 627, 1526, -28, map, true ); + CreateTeleporter( 652, 1297, -58, 628, 1526, -28, map, true ); + CreateTeleporter( 653, 1297, -58, 629, 1526, -28, map, true );*/ + + // Update: remove old teleporters + DestroyTeleporter( 650, 1297, -58, map ); + DestroyTeleporter( 651, 1297, -58, map ); + DestroyTeleporter( 652, 1297, -58, map ); + DestroyTeleporter( 653, 1297, -58, map ); + DestroyTeleporter( 626, 1526, -28, map ); + DestroyTeleporter( 627, 1526, -28, map ); + DestroyTeleporter( 628, 1526, -28, map ); + DestroyTeleporter( 629, 1526, -28, map ); + + // Update: add new ones + for ( int i = 0; i < 4; ++i ) + { + CreateTeleporter( 650 + i, 1297, -58, 626 + i, 1526, -28, map, false ); + CreateTeleporter( 626 + i, 1527, -28, 650 + i, 1298, i == 1 ? -59 : -58, map, false ); + } + + // WISP DUNGEON MAZE + CreateTeleporter( 747, 1539, -28, 785, 1514, -28, map, false ); + CreateTeleporter( 785, 1524, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 747, 1555, -28, 785, 1570, -28, map, false ); + CreateTeleporter( 784, 1580, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 791, 1548, -28, 781, 1547, -28, map, false ); + CreateTeleporter( 782, 1550, -28, 783, 1538, -28, map, false ); + CreateTeleporter( 783, 1539, -28, 787, 1542, -28, map, false ); + CreateTeleporter( 787, 1543, -28, 781, 1554, -28, map, false ); + CreateTeleporter( 781, 1555, -28, 789, 1556, -28, map, false ); + CreateTeleporter( 789, 1557, -28, 785, 1550, -28, map, false ); + CreateTeleporter( 784, 1550, -28, 777, 1554, -28, map, false ); + CreateTeleporter( 778, 1554, -28, 787, 1538, -28, map, false ); + CreateTeleporter( 787, 1537, -28, 781, 1546, -28, map, false ); + CreateTeleporter( 781, 1545, -28, 789, 1552, -28, map, false ); + CreateTeleporter( 789, 1553, -28, 789, 1546, -28, map, false ); + CreateTeleporter( 789, 1545, -28, 779, 1541, -28, map, false ); + CreateTeleporter( 780, 1541, -28, 785, 1554, -28, map, false ); + CreateTeleporter( 785, 1555, -28, 783, 1542, -28, map, false ); + CreateTeleporter( 782, 1542, -28, 785, 1546, -28, map, false ); + CreateTeleporter( 784, 1546, -28, 776, 1548, -28, map, false ); + CreateTeleporter( 777, 1555, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 777, 1553, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 776, 1549, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 777, 1548, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 777, 1547, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 776, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 778, 1541, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 779, 1540, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 779, 1542, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 780, 1554, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 781, 1553, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 782, 1554, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 780, 1550, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 781, 1549, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 781, 1551, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 780, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 781, 1547, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 782, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 783, 1543, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 784, 1542, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 783, 1541, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 782, 1538, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 783, 1537, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 784, 1538, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 786, 1538, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 787, 1539, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 788, 1538, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 788, 1542, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 787, 1541, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 786, 1542, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 785, 1545, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 786, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 785, 1547, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 785, 1549, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 785, 1551, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 786, 1550, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 784, 1554, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 785, 1553, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 786, 1554, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 788, 1556, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 789, 1555, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 790, 1556, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 788, 1552, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 789, 1551, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 790, 1552, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 790, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 788, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 789, 1547, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 791, 1545, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 791, 1546, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 791, 1547, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 791, 1549, -28, 798, 1547, -28, map, false ); + CreateTeleporter( 791, 1550, -28, 798, 1547, -28, map, false ); + + // Sorcerer`s Dungeon + CreateTeleporter( 546, 455, -40, 426, 113, -28, map, true ); + CreateTeleporter( 547, 455, -40, 427, 113, -28, map, true ); + CreateTeleporter( 548, 455, -40, 428, 113, -28, map, true ); + CreateTeleporter( 429, 113, -28, 548, 455, -40, map, false ); + + CreateTeleporter( 242, 27, -16, 372, 31, -31, map, false ); // stairs - 0x754 + CreateTeleporter( 242, 26, -16, 372, 30, -31, map, false ); // stairs - 0x754 + CreateTeleporter( 242, 25, -16, 372, 29, -31, map, false ); // stairs - 0x754 + CreateTeleporter( 371, 31, -36, 241, 27, -18, map, false ); // stairs - 0x754 + CreateTeleporter( 371, 30, -36, 241, 26, -18, map, false ); // stairs - 0x754 + + DestroyTeleporter( 371, 29, -36, map ); //To remove old erroneous teleporter + + CreateTeleporter( 371, 29, -36, 241, 25, -18, map, false ); // stairs - 0x754 + + CreateTeleporter( 272, 141, -16, 555, 427, -1, map, false ); // stairs - 1st 0x753 + CreateTeleporter( 273, 141, -16, 556, 427, -1, map, false ); // stairs - 1st 0x753 + CreateTeleporter( 274, 141, -16, 557, 427, -1, map, false ); // stairs - 1st 0x753 + CreateTeleporter( 555, 426, -6, 272, 140, -21, map, false ); // stairs - 1st 0x753 + CreateTeleporter( 556, 426, -6, 273, 140, -21, map, false ); // stairs - 1st 0x753 + CreateTeleporter( 557, 426, -6, 274, 140, -21, map, false ); // stairs - 1st 0x753 + + CreateTeleporter( 265, 130, -31, 284, 72, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 266, 130, -31, 285, 72, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 267, 130, -31, 286, 72, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 268, 130, -31, 287, 72, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 284, 73, -16, 265, 131, -28, map, false ); // stairs - 0x753 + CreateTeleporter( 285, 73, -16, 266, 131, -28, map, false ); // stairs - 0x753 + CreateTeleporter( 286, 73, -16, 267, 131, -28, map, false ); // stairs - 0x753 + CreateTeleporter( 287, 73, -16, 268, 131, -28, map, false ); // stairs - 0x753 + + CreateTeleporter( 284, 67, -30, 131, 128, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 285, 67, -30, 132, 128, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 286, 67, -30, 133, 128, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 287, 67, -30, 134, 128, -21, map, false ); // stairs - 0x753 + CreateTeleporter( 131, 129, -16, 284, 68, -28, map, false ); // stairs - 0x753 + CreateTeleporter( 132, 129, -16, 285, 68, -28, map, false ); // stairs - 0x753 + CreateTeleporter( 133, 129, -16, 286, 68, -28, map, false ); // stairs - 0x753 + CreateTeleporter( 134, 129, -16, 287, 68, -28, map, false ); // stairs - 0x753 + + CreateTeleporter( 358, 40, -36, 156, 88, -18, map, false ); // stairs - 0x73A + CreateTeleporter( 358, 41, -36, 156, 89, -18, map, false ); // stairs - 0x73A + CreateTeleporter( 358, 42, -36, 156, 90, -18, map, false ); // stairs - 0x73A + CreateTeleporter( 155, 88, -16, 357, 40, -31, map, false ); // stairs - 0x73A + CreateTeleporter( 155, 89, -16, 357, 41, -31, map, false ); // stairs - 0x73A + CreateTeleporter( 155, 90, -16, 357, 42, -31, map, false ); // stairs - 0x73A + + CreateTeleporter( 259, 90, -28, 236, 113, -28, map, true ); + + // Ancient Lair + + DestroyTeleporter( 83, 747, -28, map ); + DestroyTeleporter( 84, 747, -28, map ); + DestroyTeleporter( 85, 747, -28, map ); + DestroyTeleporter( 86, 747, -28, map ); + CreateTeleporter( 938, 494, -40, 83, 749, -23, map, true ); + CreateTeleporter( 939, 494, -40, 84, 749, -23, map, true ); + CreateTeleporter( 940, 494, -40, 85, 749, -23, map, true ); + CreateTeleporter( 941, 494, -40, 86, 749, -23, map, true ); + + // Lizard Passage + + DestroyTeleporter( 313, 1330, -39, map ); + DestroyTeleporter( 314, 1330, -37, map ); + DestroyTeleporter( 315, 1330, -35, map ); + CreateTeleporter( 313, 1329, -40, 327, 1593, -13, map, true ); + CreateTeleporter( 314, 1329, -38, 328, 1593, -13, map, true ); + CreateTeleporter( 315, 1329, -36, 329, 1593, -13, map, true ); + CreateTeleporter( 330, 1593, -13, 315, 1329, -35, map, false ); + + DestroyTeleporter( 225, 1335, -20, map ); + DestroyTeleporter( 226, 1335, -20, map ); + DestroyTeleporter( 227, 1335, -19, map ); + CreateTeleporter( 265, 1587, -28, 225, 1334, -20, map, true ); + CreateTeleporter( 266, 1587, -28, 226, 1334, -20, map, true ); + CreateTeleporter( 267, 1587, -28, 227, 1334, -20, map, true ); + + // Central Ilshenar + /*CreateTeleporter( 1139, 593, -80, 1237, 582, -19, map, true ); + CreateTeleporter( 1140, 593, -80, 1237, 583, -19, map, true ); + CreateTeleporter( 1141, 593, -80, 1237, 584, -19, map, true ); + CreateTeleporter( 1142, 593, -80, 1237, 585, -19, map, true ); + CreateTeleporter( 912, 451, -80, 708, 667, -39, map, true ); + CreateTeleporter( 912, 452, -80, 709, 667, -39, map, true ); + CreateTeleporter( 912, 453, -80, 710, 667, -39, map, true ); + CreateTeleporter( 711, 667, -39, 912, 453, -80, map, false );*/ + + // Update: remove old teleporters.. + DestroyTeleporter( 1139, 593, -80, map ); + DestroyTeleporter( 1140, 593, -80, map ); + DestroyTeleporter( 1141, 593, -80, map ); + DestroyTeleporter( 1142, 593, -80, map ); + DestroyTeleporter( 1237, 582, -19, map ); + DestroyTeleporter( 1237, 583, -19, map ); + DestroyTeleporter( 1237, 584, -19, map ); + DestroyTeleporter( 1237, 585, -19, map ); + + DestroyTeleporter( 912, 451, -80, map ); + DestroyTeleporter( 912, 452, -80, map ); + DestroyTeleporter( 912, 453, -80, map ); + DestroyTeleporter( 708, 667, -39, map ); + DestroyTeleporter( 709, 667, -39, map ); + DestroyTeleporter( 710, 667, -39, map ); + DestroyTeleporter( 711, 667, -39, map ); + + // Update: add new ones... + CreateTeleporter( 1139, 592, -80, 1238, 583, -19, map, false ); + CreateTeleporter( 1140, 592, -80, 1238, 584, -19, map, false ); + CreateTeleporter( 1141, 592, -80, 1238, 585, -19, map, false ); + CreateTeleporter( 1142, 592, -80, 1238, 585, -19, map, false ); + CreateTeleporter( 1237, 583, -19, 1139, 593, -80, map, false ); + CreateTeleporter( 1237, 584, -19, 1140, 593, -80, map, false ); + CreateTeleporter( 1237, 585, -19, 1141, 593, -80, map, false ); + + CreateTeleporter( 709, 667, -39, 912, 451, -80, map, false ); + CreateTeleporter( 710, 667, -39, 912, 452, -80, map, false ); + CreateTeleporter( 711, 667, -39, 912, 453, -80, map, false ); + + CreateTeleporter( 911, 451, -80, 709, 668, -39, map, false ); + CreateTeleporter( 911, 452, -80, 710, 668, -39, map, false ); + CreateTeleporter( 911, 453, -80, 711, 668, -38, map, false ); + + // Exodus Dungeon + CreateTeleporter( 827, 777, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 827, 778, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 827, 779, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 828, 777, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 828, 778, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 828, 779, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 829, 777, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 829, 778, -80, 1975, 114, -28, map, false ); + CreateTeleporter( 829, 779, -80, 1975, 114, -28, map, false ); + + CreateTeleporter( 1978, 114, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1978, 115, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1978, 116, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1978, 117, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1979, 114, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1979, 115, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1979, 116, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1979, 117, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1980, 114, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1980, 115, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1980, 116, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1980, 117, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1981, 114, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1981, 115, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1981, 116, -28, 835, 778, -80, map, false ); + CreateTeleporter( 1981, 117, -28, 835, 778, -80, map, false ); + } + + public void CreateTeleportersMap3( Map map ) + { + // CreateTeleporter( 408, 254, 2, 428, 319, 2, map, false ); // for doom quest; use blockers to avoid players teleporting into the ship! + // CreateTeleporter( 428, 321, 2, 422, 328, -1, map, false ); // for doom quest; use blockers to avoid players teleporting into the ship! + + // Doom Dungeon + CreateTeleporter( 2317, 1269, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2317, 1268, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2317, 1267, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2317, 1266, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2316, 1269, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2315, 1269, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2315, 1268, -110, 381, 132, 33, map, false ); + CreateTeleporter( 2315, 1267, -109, 381, 132, 33, map, false ); + CreateTeleporter( 2316, 1267, -110, 381, 132, 33, map, false ); + CreateTeleporter( 496, 49, 6, 2350, 1270, -85, map, false ); + DestroyTeleporter( 433, 326, 4, map ); + DestroyTeleporter( 365, 15, -1, map ); + + //Yomotsu Mines Exit + CreateTeleporter( 3, 128, -1, 259, 785, 64, map, Map.Tokuno, false ); + CreateTeleporter( 4, 128, -1, 259, 785, 64, map, Map.Tokuno, false ); + CreateTeleporter( 5, 128, -1, 259, 785, 64, map, Map.Tokuno, false ); + CreateTeleporter( 6, 128, -1, 259, 785, 64, map, Map.Tokuno, false ); + CreateTeleporter( 7, 128, -1, 259, 785, 64, map, Map.Tokuno, false ); + CreateTeleporter( 8, 128, -1, 259, 785, 64, map, Map.Tokuno, false ); + + //Fan Dancer Exit + CreateTeleporter( 64, 336, 11, 983, 195, 24, map, Map.Tokuno, false ); + CreateTeleporter( 64, 337, 11, 983, 195, 24, map, Map.Tokuno, false ); + CreateTeleporter( 64, 338, 11, 983, 195, 24, map, Map.Tokuno, false ); + CreateTeleporter( 64, 339, 11, 983, 195, 24, map, Map.Tokuno, false ); + + //Fan Dancer Levels + CreateTeleporter( 66, 351, -7, 63, 524, -1, map, false ); + CreateTeleporter( 66, 352, -7, 63, 524, -1, map, false ); + CreateTeleporter( 66, 353, -7, 63, 524, -1, map, false ); + CreateTeleporter( 66, 354, -7, 63, 524, -1, map, false ); + + CreateTeleporter( 61, 523, 6, 63, 352, -3, map, false ); + CreateTeleporter( 61, 524, 6, 63, 352, -3, map, false ); + CreateTeleporter( 61, 525, 6, 63, 352, -3, map, false ); + CreateTeleporter( 61, 526, 6, 63, 352, -3, map, false ); + + CreateTeleporter( 103, 555, -6, 76, 691, -1, map, false ); + CreateTeleporter( 103, 556, -6, 76, 691, -1, map, false ); + CreateTeleporter( 103, 557, -6, 76, 691, -1, map, false ); + CreateTeleporter( 103, 558, -6, 76, 691, -1, map, false ); + + CreateTeleporter( 73, 688, 6, 100, 556, -2, map, false ); + CreateTeleporter( 73, 689, 6, 100, 556, -2, map, false ); + CreateTeleporter( 73, 690, 6, 100, 556, -2, map, false ); + CreateTeleporter( 73, 691, 6, 100, 556, -2, map, false ); + CreateTeleporter( 73, 692, 6, 100, 556, -2, map, false ); + CreateTeleporter( 73, 693, 6, 100, 556, -2, map, false ); + CreateTeleporter( 73, 694, 6, 100, 556, -2, map, false ); + + //Ninja cave + CreateTeleporter( 384, 810, -1, 403, 1167, 0, map, false ); + + CreateTeleporter( 403, 1169, 0, 385, 811, -1, map, false ); + CreateTeleporter( 404, 1169, 0, 385, 808, -1, map, false ); + CreateTeleporter( 405, 1169, 0, 385, 808, -1, map, false ); + + // Dungeon Labyrinth + CreateTeleporter( 328, 1972, 5, 1731, 978, -80, map, false ); // Door exit + CreateTeleporter( 328, 1973, 5, 1731, 978, -80, map, false ); + CreateTeleporter( 328, 1974, 5, 1731, 978, -80, map, false ); + CreateTeleporter( 328, 1975, 5, 1731, 978, -80, map, false ); + + // Dungeon Bedlam + CreateTeleporter(119, 1684, 0, 2068, 1372, -75, map, false); + CreateTeleporter(120, 1684, 0, 2068, 1372, -75, map, false); + CreateTeleporter(121, 1684, 0, 2068, 1372, -75, map, false); + CreateTeleporter(84, 1673, -2, 156, 1613, 0, map, false); + CreateTeleporter(156, 1609, 17, 87, 1673, 0, map, false); + CreateTeleporter(157, 1609, 17, 87, 1673, 0, map, false); + } + + public void CreateTeleportersMap4( Map map ) + { + //Yomotso Mines Entrance + CreateTeleporter( 257, 783, 63, 5, 128, -1, map, Map.Malas, false ); + CreateTeleporter( 258, 783, 63, 5, 128, -1, map, Map.Malas, false ); + CreateTeleporter( 259, 783, 63, 5, 128, -1, map, Map.Malas, false ); + CreateTeleporter( 260, 783, 63, 5, 128, -1, map, Map.Malas, false ); + + //Fan dancer Entrance + CreateTeleporter( 988, 194, 15, 67, 337, -1, map, Map.Malas, false ); + CreateTeleporter( 988, 195, 15, 67, 337, -1, map, Map.Malas, false ); + CreateTeleporter( 987, 196, 15, 67, 337, -1, map, Map.Malas, false ); + CreateTeleporter( 988, 197, 18, 67, 337, -1, map, Map.Malas, false ); + + } +// >>> Nerun's Distro >>> (removed because Old Haven is now in ruins) +/* + public void CreateTeleportersTrammel( Map map ) + { + // Haven >>> this is Old Haven! + CreateTeleporter( 3632, 2566, 0, 3632, 2566, 20, map, true ); + } +*/ + public void CreateTeleportersFelucca( Map map ) + { + // Star room + CreateTeleporter( 5140, 1773, 0, 5171, 1586, 0, map, false ); + } + +// >>> Nerun's Distro >>> + public void NerunsDistroFeluTram( Map map ) + { + // Britain Sewer + CreateTeleporter( 6141, 1431, 4, 6138, 1408, 2, map, false ); + // Others Mondain's Legacy places + //Heartwood + CreateTeleporter( 6984, 338, 0, 535, 992, 0, map, true ); + //Blighted Grove + CreateTeleporter( 587, 1638, 0, 6478, 863, 11, map, false ); + CreateTeleporter( 588, 1638, 0, 6478, 863, 11, map, false ); + CreateTeleporter( 589, 1638, 0, 6478, 863, 11, map, false ); + CreateTeleporter( 6477, 862, 10, 587, 1641, -1, map, false ); + CreateTeleporter( 6471, 869, 21, 6574, 889, 0, map, false ); + CreateTeleporter( 6472, 869, 20, 6574, 889, 0, map, false ); + CreateTeleporter( 6473, 869, 20, 6574, 889, 0, map, false ); + CreateTeleporter( 6474, 869, 18, 6574, 889, 0, map, false ); + CreateTeleporter( 6588, 868, 0, 6488, 849, 40, map, false ); + CreateTeleporter( 6588, 867, 0, 6488, 849, 40, map, false ); + //Palace of Paroxysmus + CreateTeleporter( 5577, 3018, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5578, 3019, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5578, 3018, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5578, 3017, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5578, 3016, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5579, 3017, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5579, 3018, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 5579, 3019, 25, 6222, 335, 60, map, false ); + CreateTeleporter( 6303, 328, 65, 5623, 3038, 15, map, false ); + CreateTeleporter( 6304, 328, 65, 5623, 3038, 15, map, false ); + //Prism of Light + CreateTeleporter( 3784, 1098, 12, 6474, 188, 0, map, false ); + CreateTeleporter( 3785, 1098, 12, 6474, 188, 0, map, false ); + CreateTeleporter( 6506, 89, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6508, 84, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6509, 86, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6510, 87, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6512, 87, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6512, 83, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6513, 88, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6513, 88, -4, 6502, 87, 0, map, false ); + CreateTeleporter( 6469, 97, -50, 6503, 87, 0, map, false ); + CreateTeleporter( 6568, 77, -10, 6576, 72, 0, map, false ); + CreateTeleporter( 6554, 104, 0, 6555, 115, 0, map, false ); + CreateTeleporter( 6582, 109, 0, 6552, 142, 0, map, false ); + CreateTeleporter( 6537, 175, 0, 6514, 184, 0, map, false ); + CreateTeleporter( 6515, 184, 0, 6536, 177, 0, map, false ); + CreateTeleporter( 6477, 94, -49, 6476, 76, -35, map, false ); + CreateTeleporter( 6471, 75, -23, 6476, 94, -49, map, false ); + CreateTeleporter( 6578, 160, 12, 6577, 178, 30, map, false ); + CreateTeleporter( 6577, 176, 30, 6579, 159, 7, map, false ); + CreateTeleporter( 6471, 187, 15, 3784, 1097, 14, map, false ); + CreateTeleporter( 6472, 187, 15, 3784, 1098, 14, map, false ); + CreateTeleporter( 6541, 117, -15, 6523, 136, -20, map, false ); + CreateTeleporter( 6523, 136, -20, 6541, 117, -15, map, false ); + } + public void NerunsDistroIlshenar( Map map ) + { + // Others Mondain's Legacy places + //Twisted Weald + CreateTeleporter( 1450, 1470, -22, 2189, 1253, 0, map, false ); + CreateTeleporter( 2187, 1251, 2, 1450, 1474, -24, map, false ); + CreateTeleporter( 2139, 1263, -60, 2139, 1265, -57, map, false ); + CreateTeleporter( 2139, 1265, -57, 2139, 1263, -60, map, false ); + } + public void NerunsDistroMalas( Map map ) + { + // Others Mondain's Legacy places + //Bedlam + CreateTeleporter( 2068, 1371, -75, 120, 1680, 0, map, false ); + CreateTeleporter( 117, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 118, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 119, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 120, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 121, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 122, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 123, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 124, 1684, 0, 2068, 1372, -75, map, false ); + CreateTeleporter( 125, 1684, 0, 2068, 1372, -75, map, false ); + //Citadel + CreateTeleporter( 85, 1880, 0, 100, 1875, 0, map, false ); + CreateTeleporter( 90, 1919, 0, 100, 1875, 0, map, false ); + CreateTeleporter( 122, 1869, 0, 100, 1875, 0, map, false ); + CreateTeleporter( 137, 1916, 0, 100, 1875, 0, map, false ); + CreateTeleporter( 83, 1883, -8, 182, 1929, 0, map, false ); + CreateTeleporter( 180, 1932, 12, 83, 1885, 0, map, false ); + CreateTeleporter( 181, 1932, 12, 83, 1885, 0, map, false ); + CreateTeleporter( 182, 1932, 12, 83, 1885, 0, map, false ); + CreateTeleporter( 175, 1894, -13, 102, 1921, 0, map, false ); + CreateTeleporter( 101, 1925, 17, 175, 1897, 0, map, false ); + CreateTeleporter( 102, 1925, 17, 175, 1897, 0, map, false ); + CreateTeleporter( 103, 1925, 17, 175, 1897, 0, map, false ); + CreateTeleporter( 104, 1925, 17, 175, 1897, 0, map, false ); + CreateTeleporter( 174, 1880, 0, 82, 1950, 30, map, false ); + CreateTeleporter( 174, 1879, 0, 82, 1950, 30, map, false ); + CreateTeleporter( 159, 1976, 17, 7, 1921, 0, map, false ); + CreateTeleporter( 159, 1975, 17, 7, 1921, 0, map, false ); + CreateTeleporter( 159, 1974, 17, 7, 1921, 0, map, false ); + CreateTeleporter( 90, 1920, -7, 64, 1976, 0, map, false ); + CreateTeleporter( 90, 1921, -7, 64, 1976, 0, map, false ); + CreateTeleporter( 91, 1917, 15, 44, 1901, 0, map, false ); + CreateTeleporter( 91, 1918, 15, 44, 1901, 0, map, false ); + CreateTeleporter( 142, 1901, -7, 7, 1918, 0, map, false ); + CreateTeleporter( 123, 1877, -11, 61, 1921, 2, map, false ); + CreateTeleporter( 125, 1877, -11, 61, 1921, 2, map, false ); + CreateTeleporter( 161, 1919, 12, 23, 1874, -1, map, false ); + CreateTeleporter( 162, 1919, 12, 23, 1874, -1, map, false ); + CreateTeleporter( 161, 1924, -12, 29, 1975, 0, map, false ); + CreateTeleporter( 129, 1972, 12, 61, 1921, 2, map, false ); + CreateTeleporter( 130, 1972, 12, 61, 1921, 2, map, false ); + CreateTeleporter( 131, 1972, 12, 61, 1921, 2, map, false ); + CreateTeleporter( 114, 1907, 20, 18, 1921, 0, map, false ); + CreateTeleporter( 115, 1907, 20, 18, 1921, 0, map, false ); + CreateTeleporter( 116, 1907, 20, 18, 1921, 0, map, false ); + CreateTeleporter( 118, 1918, -14, 14, 1902, 0, map, false ); + CreateTeleporter( 119, 1918, -14, 14, 1902, 0, map, false ); + CreateTeleporter( 106, 1881, 0, 355, 779, 1, map, false ); + //Labyrinth + CreateTeleporter( 1717, 1156, -95, 1371, 978, -80, map, false ); + CreateTeleporter( 1775, 971, -85, 1723, 1158, -90, map, false ); + CreateTeleporter( 1732, 972, -75, 330, 1973, 0, map, false ); + CreateTeleporter( 1734, 972, -75, 330, 1973, 0, map, false ); + } +// >>> end + + public int CreateTeleporters() + { + CreateTeleportersMap( Map.Felucca ); + CreateTeleportersMap( Map.Trammel ); +// >>> Nerun's Distro >>> +// CreateTeleportersTrammel( Map.Trammel ); + NerunsDistroFeluTram( Map.Felucca ); + NerunsDistroFeluTram( Map.Trammel ); + NerunsDistroIlshenar( Map.Ilshenar ); + NerunsDistroMalas( Map.Malas ); +// >>> end + CreateTeleportersFelucca( Map.Felucca ); + CreateTeleportersMap2( Map.Ilshenar ); + CreateTeleportersMap3( Map.Malas ); + CreateTeleportersMap4( Map.Tokuno ); + return m_Count; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Commands/BaseCommand.cs b/Scripts/Commands/Generic/Commands/BaseCommand.cs new file mode 100644 index 0000000..3ef65ba --- /dev/null +++ b/Scripts/Commands/Generic/Commands/BaseCommand.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Server.Commands.Generic +{ + public enum ObjectTypes + { + Both, + Items, + Mobiles, + All + } + + public abstract class BaseCommand + { + private string[] m_Commands; + private AccessLevel m_AccessLevel; + private CommandSupport m_Implementors; + private ObjectTypes m_ObjectTypes; + private bool m_ListOptimized; + private string m_Usage; + private string m_Description; + + public bool ListOptimized + { + get{ return m_ListOptimized; } + set{ m_ListOptimized = value; } + } + + public string[] Commands + { + get{ return m_Commands; } + set{ m_Commands = value; } + } + + public string Usage + { + get{ return m_Usage; } + set{ m_Usage = value; } + } + + public string Description + { + get{ return m_Description; } + set{ m_Description = value; } + } + + public AccessLevel AccessLevel + { + get{ return m_AccessLevel; } + set{ m_AccessLevel = value; } + } + + public ObjectTypes ObjectTypes + { + get{ return m_ObjectTypes; } + set{ m_ObjectTypes = value; } + } + + public CommandSupport Supports + { + get{ return m_Implementors; } + set{ m_Implementors = value; } + } + + public BaseCommand() + { + m_Responses = new ArrayList(); + m_Failures = new ArrayList(); + } + + public static bool IsAccessible( Mobile from, object obj ) + { + if ( from.AccessLevel >= AccessLevel.Administrator || obj == null ) + return true; + + Mobile mob; + + if ( obj is Mobile ) + mob = (Mobile)obj; + else if ( obj is Item ) + mob = ((Item)obj).RootParent as Mobile; + else + mob = null; + + if ( mob == null || mob == from || from.AccessLevel > mob.AccessLevel ) + return true; + + return false; + } + + public virtual void ExecuteList( CommandEventArgs e, ArrayList list ) + { + for ( int i = 0; i < list.Count; ++i ) + Execute( e, list[i] ); + } + + public virtual void Execute( CommandEventArgs e, object obj ) + { + } + + public virtual bool ValidateArgs( BaseCommandImplementor impl, CommandEventArgs e ) + { + return true; + } + + private ArrayList m_Responses, m_Failures; + + private class MessageEntry + { + public string m_Message; + public int m_Count; + + public MessageEntry( string message ) + { + m_Message = message; + m_Count = 1; + } + + public override string ToString() + { + if ( m_Count > 1 ) + return String.Format( "{0} ({1})", m_Message, m_Count ); + + return m_Message; + } + } + + public void AddResponse( string message ) + { + for ( int i = 0; i < m_Responses.Count; ++i ) + { + MessageEntry entry = (MessageEntry)m_Responses[i]; + + if ( entry.m_Message == message ) + { + ++entry.m_Count; + return; + } + } + + if ( m_Responses.Count == 10 ) + return; + + m_Responses.Add( new MessageEntry( message ) ); + } + + public void AddResponse( Gump gump ) + { + m_Responses.Add( gump ); + } + + public void LogFailure( string message ) + { + for ( int i = 0; i < m_Failures.Count; ++i ) + { + MessageEntry entry = (MessageEntry)m_Failures[i]; + + if ( entry.m_Message == message ) + { + ++entry.m_Count; + return; + } + } + + if ( m_Failures.Count == 10 ) + return; + + m_Failures.Add( new MessageEntry( message ) ); + } + + public void Flush( Mobile from, bool flushToLog ) + { + if ( m_Responses.Count > 0 ) + { + for ( int i = 0; i < m_Responses.Count; ++i ) + { + object obj = m_Responses[i]; + + if ( obj is MessageEntry ) + { + from.SendMessage( ((MessageEntry)obj).ToString() ); + + if ( flushToLog ) + CommandLogging.WriteLine( from, ((MessageEntry)obj).ToString() ); + } + else if ( obj is Gump ) + { + from.SendGump( (Gump) obj ); + } + } + } + else + { + for ( int i = 0; i < m_Failures.Count; ++i ) + from.SendMessage( ((MessageEntry)m_Failures[i]).ToString() ); + } + + m_Responses.Clear(); + m_Failures.Clear(); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Commands/Commands.cs b/Scripts/Commands/Generic/Commands/Commands.cs new file mode 100644 index 0000000..722de4e --- /dev/null +++ b/Scripts/Commands/Generic/Commands/Commands.cs @@ -0,0 +1,1120 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using Server; +using Server.Accounting; +using Server.Engines.Help; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Network; +using Server.Spells; + +namespace Server.Commands.Generic +{ + public class TargetCommands + { + public static void Initialize() + { + Register( new KillCommand( true ) ); + Register( new KillCommand( false ) ); + Register( new HideCommand( true ) ); + Register( new HideCommand( false ) ); + Register( new KickCommand( true ) ); + Register( new KickCommand( false ) ); + Register( new FirewallCommand() ); + Register( new TeleCommand() ); + Register( new SetCommand() ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "Immortal", "blessed", "true", ObjectTypes.Mobiles ) ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "Invul", "blessed", "true", ObjectTypes.Mobiles ) ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "Mortal", "blessed", "false", ObjectTypes.Mobiles ) ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "NoInvul", "blessed", "false", ObjectTypes.Mobiles ) ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "Squelch", "squelched", "true", ObjectTypes.Mobiles ) ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "Unsquelch", "squelched", "false", ObjectTypes.Mobiles ) ); + + Register( new AliasedSetCommand( AccessLevel.GameMaster, "ShaveHair", "HairItemID", "0", ObjectTypes.Mobiles ) ); + Register( new AliasedSetCommand( AccessLevel.GameMaster, "ShaveBeard", "FacialHairItemID", "0", ObjectTypes.Mobiles ) ); + + Register( new GetCommand() ); + Register( new GetTypeCommand() ); + Register( new DeleteCommand() ); + Register( new RestockCommand() ); + Register( new DismountCommand() ); + Register( new AddCommand() ); + Register( new AddToPackCommand() ); + Register(new TellCommand(true)); + Register(new TellCommand(false)); + Register( new PrivSoundCommand() ); + Register( new IncreaseCommand() ); + Register( new OpenBrowserCommand() ); + Register( new CountCommand() ); + Register( new InterfaceCommand() ); + Register( new RefreshHouseCommand() ); + Register( new ConditionCommand() ); + Register( new Factions.FactionKickCommand( Factions.FactionKickType.Kick ) ); + Register( new Factions.FactionKickCommand( Factions.FactionKickType.Ban ) ); + Register( new Factions.FactionKickCommand( Factions.FactionKickType.Unban ) ); + Register( new BringToPackCommand() ); + Register(new TraceLockdownCommand()); + } + + private static List m_AllCommands = new List(); + + public static List AllCommands{ get{ return m_AllCommands; } } + + public static void Register( BaseCommand command ) + { + m_AllCommands.Add( command ); + + List impls = BaseCommandImplementor.Implementors; + + for ( int i = 0; i < impls.Count; ++i ) + { + BaseCommandImplementor impl = impls[i]; + + if ( (command.Supports & impl.SupportRequirement) != 0 ) + impl.Register( command ); + } + } + } + + public class ConditionCommand : BaseCommand + { + public ConditionCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Simple | CommandSupport.Complex | CommandSupport.Self; + Commands = new string[]{ "Condition" }; + ObjectTypes = ObjectTypes.All; + Usage = "Condition "; + Description = "Checks that the given condition matches a targeted object."; + ListOptimized = true; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + try + { + string[] args = e.Arguments; + ObjectConditional condition = ObjectConditional.Parse( e.Mobile, ref args ); + + for ( int i = 0; i < list.Count; ++i ) + { + if ( condition.CheckCondition( list[i] ) ) + AddResponse( "True - that object matches the condition." ); + else + AddResponse( "False - that object does not match the condition." ); + } + } + catch ( Exception ex ) + { + e.Mobile.SendMessage( ex.Message ); + } + } + } + + public class BringToPackCommand : BaseCommand + { + public BringToPackCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllItems; + Commands = new string[]{ "BringToPack" }; + ObjectTypes = ObjectTypes.Items; + Usage = "BringToPack"; + Description = "Brings a targeted item to your backpack."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Item item = obj as Item; + + if ( item != null ) + { + if ( e.Mobile.PlaceInBackpack( item ) ) + AddResponse( "The item has been placed in your backpack." ); + else + AddResponse( "Your backpack could not hold the item." ); + } + } + } + + public class RefreshHouseCommand : BaseCommand + { + public RefreshHouseCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Simple; + Commands = new string[]{ "RefreshHouse" }; + ObjectTypes = ObjectTypes.Items; + Usage = "RefreshHouse"; + Description = "Refreshes a targeted house sign."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( obj is HouseSign ) + { + BaseHouse house = ((HouseSign)obj).Owner; + + if ( house == null ) + { + LogFailure( "That sign has no house attached." ); + } + else + { + house.RefreshDecay(); + AddResponse( "The house has been refreshed." ); + } + } + else + { + LogFailure( "That is not a house sign." ); + } + } + } + + public class CountCommand : BaseCommand + { + public CountCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Complex; + Commands = new string[]{ "Count" }; + ObjectTypes = ObjectTypes.All; + Usage = "Count"; + Description = "Counts the number of objects that a command modifier would use. Generally used with condition arguments."; + ListOptimized = true; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + if ( list.Count == 1 ) + AddResponse( "There is one matching object." ); + else + AddResponse( String.Format( "There are {0} matching objects.", list.Count ) ); + } + } + + public class OpenBrowserCommand : BaseCommand + { + public OpenBrowserCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllMobiles; + Commands = new string[] { "OpenBrowser", "OB" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "OpenBrowser "; + Description = "Opens the web browser of a targeted player to a specified url."; + } + + public static void OpenBrowser_Callback(Mobile from, bool okay, object state) + { + object[] states = (object[])state; + Mobile gm = (Mobile)states[0]; + string url = (string)states[1]; + bool echo = (bool)states[2]; + + if (okay) + { + if (echo) + gm.SendMessage("{0} : has opened their web browser to : {1}", from.Name, url); + + from.LaunchBrowser(url); + } + else + { + if (echo) + gm.SendMessage("{0} : has chosen not to open their web browser to : {1}", from.Name, url); + + from.SendMessage("You have chosen not to open your web browser."); + } + } + + public void Execute(CommandEventArgs e, object obj, bool echo) + { + if (e.Length == 1) + { + Mobile mob = (Mobile)obj; + Mobile from = e.Mobile; + + if (mob.Player) + { + NetState ns = mob.NetState; + + if (ns == null) + { + LogFailure("That player is not online."); + } + else + { + string url = e.GetString(0); + + CommandLogging.WriteLine(from, "{0} {1} requesting to open web browser of {2} to {3}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(mob), url); + + if (echo) + AddResponse("Awaiting user confirmation..."); + else + AddResponse("Open web browser request sent."); + + mob.SendGump(new WarningGump(1060637, 30720, String.Format("A game master is requesting to open your web browser to the following URL:
{0}", url), 0xFFC000, 320, 240, new WarningGumpCallback(OpenBrowser_Callback), new object[] { from, url, echo })); + } + } + else + { + LogFailure("That is not a player."); + } + } + else + { + LogFailure("Format: OpenBrowser "); + } + } + + public override void Execute(CommandEventArgs e, object obj) + { + Execute(e, obj, true); + } + + public override void ExecuteList(CommandEventArgs e, ArrayList list) + { + for (int i = 0; i < list.Count; ++i) + Execute(e, list[i], false); + } + } + + public class IncreaseCommand : BaseCommand + { + public IncreaseCommand() + { + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.All; + Commands = new string[]{ "Increase", "Inc" }; + ObjectTypes = ObjectTypes.Both; + Usage = "Increase { ...}"; + Description = "Increases the value of a specified property by the specified offset."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( obj is BaseMulti ) + { + LogFailure( "This command does not work on multis." ); + } + else if ( e.Length >= 2 ) + { + string result = Properties.IncreaseValue( e.Mobile, obj, e.Arguments ); + + if ( result == "The property has been increased." || result == "The properties have been increased." || result == "The property has been decreased." || result == "The properties have been decreased." || result == "The properties have been changed." ) + AddResponse( result ); + else + LogFailure( result ); + } + else + { + LogFailure( "Format: Increase { ...}" ); + } + } + } + + public class PrivSoundCommand : BaseCommand + { + public PrivSoundCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllMobiles; + Commands = new string[]{ "PrivSound" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "PrivSound "; + Description = "Plays a sound to a given target."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile from = e.Mobile; + + if ( e.Length == 1 ) + { + int index = e.GetInt32( 0 ); + Mobile mob = (Mobile)obj; + + CommandLogging.WriteLine( from, "{0} {1} playing sound {2} for {3}", from.AccessLevel, CommandLogging.Format( from ), index, CommandLogging.Format( mob ) ); + mob.Send( new PlaySound( index, mob.Location ) ); + } + else + { + from.SendMessage( "Format: PrivSound " ); + } + } + } + + public class TellCommand : BaseCommand + { + private bool m_InGump; + + public TellCommand(bool inGump) + { + m_InGump = inGump; + + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.AllMobiles; + ObjectTypes = ObjectTypes.Mobiles; + + if (inGump) + { + Commands = new string[] { "Message", "Msg" }; + Usage = "Message \"text\""; + Description = "Sends a message to a targeted player."; + } + else + { + Commands = new string[] { "Tell" }; + Usage = "Tell \"text\""; + Description = "Sends a system message to a targeted player."; + } + } + + public override void Execute(CommandEventArgs e, object obj) + { + Mobile mob = (Mobile)obj; + Mobile from = e.Mobile; + + CommandLogging.WriteLine(from, "{0} {1} {2} {3} \"{4}\"", from.AccessLevel, CommandLogging.Format(from), m_InGump ? "messaging" : "telling", CommandLogging.Format(mob), e.ArgString); + + if (m_InGump) + mob.SendGump(new MessageSentGump(mob, from.Name, e.ArgString)); + else + mob.SendMessage(e.ArgString); + } + } + + public class AddToPackCommand : BaseCommand + { + public AddToPackCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.All; + Commands = new string[]{ "AddToPack", "AddToCont" }; + ObjectTypes = ObjectTypes.Both; + ListOptimized = true; + Usage = "AddToPack [params] [set { ...}]"; + Description = "Adds an item by name to the backpack of a targeted player or npc, or a targeted container. Optional constructor parameters. Optional set property list."; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + if ( e.Arguments.Length == 0 ) + return; + + List packs = new List( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + { + object obj = list[i]; + Container cont = null; + + if ( obj is Mobile ) + cont = ((Mobile)obj).Backpack; + else if ( obj is Container ) + cont = (Container)obj; + + if ( cont != null ) + packs.Add( cont ); + else + LogFailure( "That is not a container." ); + } + + Add.Invoke( e.Mobile, e.Mobile.Location, e.Mobile.Location, e.Arguments, packs ); + } + } + + public class AddCommand : BaseCommand + { + public AddCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Simple | CommandSupport.Self; + Commands = new string[]{ "Add" }; + ObjectTypes = ObjectTypes.All; + Usage = "Add [ [params] [set { ...}]]"; + Description = "Adds an item or npc by name to a targeted location. Optional constructor parameters. Optional set property list. If no arguments are specified, this brings up a categorized add menu."; + } + + public override bool ValidateArgs( BaseCommandImplementor impl, CommandEventArgs e ) + { + if ( e.Length >= 1 ) + { + Type t = ScriptCompiler.FindTypeByName( e.GetString( 0 ) ); + + if ( t == null ) + { + e.Mobile.SendMessage( "No type with that name was found." ); + + string match = e.GetString( 0 ).Trim(); + + if ( match.Length < 3 ) + { + e.Mobile.SendMessage( "Invalid search string." ); + e.Mobile.SendGump( new AddGump( e.Mobile, match, 0, Type.EmptyTypes, false ) ); + } + else + { + e.Mobile.SendGump( new AddGump( e.Mobile, match, 0, AddGump.Match( match ).ToArray(), true ) ); + } + } + else + { + return true; + } + } + else + { + e.Mobile.SendGump( new CategorizedAddGump( e.Mobile ) ); + } + + return false; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + IPoint3D p = obj as IPoint3D; + + if ( p == null ) + return; + + if ( p is Item ) + p = ((Item)p).GetWorldTop(); + else if ( p is Mobile ) + p = ((Mobile)p).Location; + + Add.Invoke( e.Mobile, new Point3D( p ), new Point3D( p ), e.Arguments ); + } + } + + public class TeleCommand : BaseCommand + { + public TeleCommand() + { + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.Simple; + Commands = new string[]{ "Teleport", "Tele" }; + ObjectTypes = ObjectTypes.All; + Usage = "Teleport"; + Description = "Teleports your character to a targeted location."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + IPoint3D p = obj as IPoint3D; + + if ( p == null ) + return; + + Mobile from = e.Mobile; + + SpellHelper.GetSurfaceTop( ref p ); + + //CommandLogging.WriteLine( from, "{0} {1} teleporting to {2}", from.AccessLevel, CommandLogging.Format( from ), new Point3D( p ) ); + + Point3D fromLoc = from.Location; + Point3D toLoc = new Point3D( p ); + + from.Location = toLoc; + from.ProcessDelta(); + + if ( !from.Hidden ) + { + Effects.SendLocationParticles( EffectItem.Create( fromLoc, from.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + Effects.SendLocationParticles( EffectItem.Create( toLoc, from.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + + from.PlaySound( 0x1FE ); + } + } + } + + public class DismountCommand : BaseCommand + { + public DismountCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllMobiles; + Commands = new string[]{ "Dismount" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "Dismount"; + Description = "Forcefully dismounts a given target."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile from = e.Mobile; + Mobile mob = (Mobile)obj; + + CommandLogging.WriteLine( from, "{0} {1} dismounting {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( mob ) ); + + bool takenAction = false; + + for ( int i = 0; i < mob.Items.Count; ++i ) + { + Item item = mob.Items[i]; + + if ( item is IMountItem ) + { + IMount mount = ((IMountItem)item).Mount; + + if ( mount != null ) + { + mount.Rider = null; + takenAction = true; + } + + if ( mob.Items.IndexOf( item ) == -1 ) + --i; + } + } + + for ( int i = 0; i < mob.Items.Count; ++i ) + { + Item item = mob.Items[i]; + + if ( item.Layer == Layer.Mount ) + { + takenAction = true; + item.Delete(); + --i; + } + } + + if ( takenAction ) + AddResponse( "They have been dismounted." ); + else + LogFailure( "They were not mounted." ); + } + } + + public class RestockCommand : BaseCommand + { + public RestockCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllNPCs; + Commands = new string[]{ "Restock" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "Restock"; + Description = "Manually restocks a targeted vendor, refreshing the quantity of every item the vendor sells to the maximum. This also invokes the maximum quantity adjustment algorithms."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( obj is BaseVendor ) + { + CommandLogging.WriteLine( e.Mobile, "{0} {1} restocking {2}", e.Mobile.AccessLevel, CommandLogging.Format( e.Mobile ), CommandLogging.Format( obj ) ); + + ((BaseVendor)obj).Restock(); + AddResponse( "The vendor has been restocked." ); + } + else + { + AddResponse( "That is not a vendor." ); + } + } + } + + public class GetTypeCommand : BaseCommand + { + public GetTypeCommand() + { + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.All; + Commands = new string[]{ "GetType" }; + ObjectTypes = ObjectTypes.All; + Usage = "GetType"; + Description = "Gets the type name of a targeted object."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( obj == null ) + { + AddResponse( "The object is null." ); + } + else + { + Type type = obj.GetType(); + + if ( type.DeclaringType == null ) + AddResponse( String.Format( "The type of that object is {0}.", type.Name ) ); + else + AddResponse( String.Format( "The type of that object is {0}.", type.FullName ) ); + } + } + } + + public class GetCommand : BaseCommand + { + public GetCommand() + { + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.All; + Commands = new string[]{ "Get" }; + ObjectTypes = ObjectTypes.All; + Usage = "Get "; + Description = "Gets one or more property values by name of a targeted object."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( e.Length >= 1 ) + { + for ( int i = 0; i < e.Length; ++i ) + { + string result = Properties.GetValue( e.Mobile, obj, e.GetString( i ) ); + + if ( result == "Property not found." || result == "Property is write only." || result.StartsWith( "Getting this property" ) ) + LogFailure( result ); + else + AddResponse( result ); + } + } + else + { + LogFailure( "Format: Get " ); + } + } + } + + public class AliasedSetCommand : BaseCommand + { + private string m_Name; + private string m_Value; + + public AliasedSetCommand( AccessLevel level, string command, string name, string value, ObjectTypes objects ) + { + m_Name = name; + m_Value = value; + + AccessLevel = level; + + if ( objects == ObjectTypes.Items ) + Supports = CommandSupport.AllItems; + else if ( objects == ObjectTypes.Mobiles ) + Supports = CommandSupport.AllMobiles; + else + Supports = CommandSupport.All; + + Commands = new string[]{ command }; + ObjectTypes = objects; + Usage = command; + Description = String.Format( "Sets the {0} property to {1}.", name, value ); + } + + public override void Execute( CommandEventArgs e, object obj ) + { + string result = Properties.SetValue( e.Mobile, obj, m_Name, m_Value ); + + if ( result == "Property has been set." ) + AddResponse( result ); + else + LogFailure( result ); + } + } + + public class SetCommand : BaseCommand + { + public SetCommand() + { + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.All; + Commands = new string[]{ "Set" }; + ObjectTypes = ObjectTypes.Both; + Usage = "Set [...]"; + Description = "Sets one or more property values by name of a targeted object."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( e.Length >= 2 ) + { + for ( int i = 0; (i+1) < e.Length; i += 2 ) + { + string result = Properties.SetValue( e.Mobile, obj, e.GetString( i ), e.GetString( i+1 ) ); + + if ( result == "Property has been set." ) + AddResponse( result ); + else + LogFailure( result ); + } + } + else + { + LogFailure( "Format: Set " ); + } + } + } + + public class DeleteCommand : BaseCommand + { + public DeleteCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllNPCs | CommandSupport.AllItems; + Commands = new string[]{ "Delete", "Remove" }; + ObjectTypes = ObjectTypes.Both; + Usage = "Delete"; + Description = "Deletes a targeted item or mobile. Does not delete players."; + } + + private void OnConfirmCallback( Mobile from, bool okay, object state ) + { + object[] states = (object[])state; + CommandEventArgs e = (CommandEventArgs)states[0]; + ArrayList list = (ArrayList)states[1]; + + bool flushToLog = false; + + if ( okay ) + { + AddResponse( "Delete command confirmed." ); + + if ( list.Count > 20 ) + { + CommandLogging.Enabled = false; + NetState.Pause(); + } + + base.ExecuteList( e, list ); + + if ( list.Count > 20 ) + { + NetState.Resume(); + flushToLog = true; + CommandLogging.Enabled = true; + } + } + else + { + AddResponse( "Delete command aborted." ); + } + + Flush( from, flushToLog ); + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + if ( list.Count > 1 ) + { + e.Mobile.SendGump( new WarningGump( 1060637, 30720, String.Format( "You are about to delete {0} objects. This cannot be undone without a full server revert.

Continue?", list.Count ), 0xFFC000, 420, 280, new WarningGumpCallback( OnConfirmCallback ), new object[]{ e, list } ) ); + AddResponse( "Awaiting confirmation..." ); + } + else + { + base.ExecuteList( e, list ); + } + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( obj is Item ) + { + CommandLogging.WriteLine( e.Mobile, "{0} {1} deleting {2}", e.Mobile.AccessLevel, CommandLogging.Format( e.Mobile ), CommandLogging.Format( obj ) ); + ((Item)obj).Delete(); + AddResponse( "The item has been deleted." ); + } + else if ( obj is Mobile && !((Mobile)obj).Player ) + { + CommandLogging.WriteLine( e.Mobile, "{0} {1} deleting {2}", e.Mobile.AccessLevel, CommandLogging.Format( e.Mobile ), CommandLogging.Format( obj ) ); + ((Mobile)obj).Delete(); + AddResponse( "The mobile has been deleted." ); + } + else + { + LogFailure( "That cannot be deleted." ); + } + } + } + + public class KillCommand : BaseCommand + { + private bool m_Value; + + public KillCommand( bool value ) + { + m_Value = value; + + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllMobiles; + Commands = value ? new string[]{ "Kill" } : new string[]{ "Resurrect", "Res" }; + ObjectTypes = ObjectTypes.Mobiles; + + if ( value ) + { + Usage = "Kill"; + Description = "Kills a targeted player or npc."; + } + else + { + Usage = "Resurrect"; + Description = "Resurrects a targeted ghost."; + } + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile mob = (Mobile)obj; + Mobile from = e.Mobile; + + if ( m_Value ) + { + if ( !mob.Alive ) + { + LogFailure( "They are already dead." ); + } + else if ( !mob.CanBeDamaged() ) + { + LogFailure( "They cannot be harmed." ); + } + else + { + CommandLogging.WriteLine( from, "{0} {1} killing {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( mob ) ); + mob.Kill(); + + AddResponse( "They have been killed." ); + } + } + else + { + if ( mob.IsDeadBondedPet ) + { + BaseCreature bc = mob as BaseCreature; + + if ( bc != null ) + { + CommandLogging.WriteLine( from, "{0} {1} resurrecting {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( mob ) ); + + bc.PlaySound( 0x214 ); + bc.FixedEffect( 0x376A, 10, 16 ); + + bc.ResurrectPet(); + + AddResponse( "It has been resurrected." ); + } + } + else if ( !mob.Alive ) + { + CommandLogging.WriteLine( from, "{0} {1} resurrecting {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( mob ) ); + + mob.PlaySound( 0x214 ); + mob.FixedEffect( 0x376A, 10, 16 ); + + mob.Resurrect(); + + AddResponse( "They have been resurrected." ); + } + else + { + LogFailure( "They are not dead." ); + } + } + } + } + + public class HideCommand : BaseCommand + { + private bool m_Value; + + public HideCommand( bool value ) + { + m_Value = value; + + AccessLevel = AccessLevel.Counselor; + Supports = CommandSupport.AllMobiles; + Commands = new string[]{ value ? "Hide" : "Unhide" }; + ObjectTypes = ObjectTypes.Mobiles; + + if ( value ) + { + Usage = "Hide"; + Description = "Makes a targeted mobile disappear in a puff of smoke."; + } + else + { + Usage = "Unhide"; + Description = "Makes a targeted mobile appear in a puff of smoke."; + } + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile m = (Mobile)obj; + + CommandLogging.WriteLine( e.Mobile, "{0} {1} {2} {3}", e.Mobile.AccessLevel, CommandLogging.Format( e.Mobile ), m_Value ? "hiding" : "unhiding", CommandLogging.Format( m ) ); + + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y, m.Z + 4 ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y, m.Z ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y, m.Z - 4 ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X, m.Y + 1, m.Z + 4 ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X, m.Y + 1, m.Z ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X, m.Y + 1, m.Z - 4 ), m.Map, 0x3728, 13 ); + + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y + 1, m.Z + 11 ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y + 1, m.Z + 7 ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y + 1, m.Z + 3 ), m.Map, 0x3728, 13 ); + Effects.SendLocationEffect( new Point3D( m.X + 1, m.Y + 1, m.Z - 1 ), m.Map, 0x3728, 13 ); + + m.PlaySound( 0x228 ); + m.Hidden = m_Value; + + if ( m_Value ) + AddResponse( "They have been hidden." ); + else + AddResponse( "They have been revealed." ); + } + } + + public class FirewallCommand : BaseCommand + { + public FirewallCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.AllMobiles; + Commands = new string[]{ "Firewall" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "Firewall"; + Description = "Adds a targeted player to the firewall (list of blocked IP addresses). This command does not ban or kick."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile from = e.Mobile; + Mobile targ = (Mobile)obj; + NetState state = targ.NetState; + + if ( state != null ) + { + CommandLogging.WriteLine( from, "{0} {1} firewalling {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targ ) ); + + try + { + Firewall.Add( state.Address ); + AddResponse( "They have been firewalled." ); + } + catch ( Exception ex ) + { + LogFailure( ex.Message ); + } + } + else + { + LogFailure( "They are not online." ); + } + } + } + + public class KickCommand : BaseCommand + { + private bool m_Ban; + + public KickCommand( bool ban ) + { + m_Ban = ban; + + AccessLevel = ( ban ? AccessLevel.Administrator : AccessLevel.GameMaster ); + Supports = CommandSupport.AllMobiles; + Commands = new string[]{ ban ? "Ban" : "Kick" }; + ObjectTypes = ObjectTypes.Mobiles; + + if ( ban ) + { + Usage = "Ban"; + Description = "Bans the account of a targeted player."; + } + else + { + Usage = "Kick"; + Description = "Disconnects a targeted player."; + } + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile from = e.Mobile; + Mobile targ = (Mobile)obj; + + if ( from.AccessLevel > targ.AccessLevel ) + { + NetState fromState = from.NetState, targState = targ.NetState; + + if ( fromState != null && targState != null ) + { + Account fromAccount = fromState.Account as Account; + Account targAccount = targState.Account as Account; + + if ( fromAccount != null && targAccount != null ) + { + CommandLogging.WriteLine( from, "{0} {1} {2} {3}", from.AccessLevel, CommandLogging.Format( from ), m_Ban ? "banning" : "kicking", CommandLogging.Format( targ ) ); + + targ.Say( "I've been {0}!", m_Ban ? "banned" : "kicked" ); + + AddResponse( String.Format( "They have been {0}.", m_Ban ? "banned" : "kicked" ) ); + + targState.Dispose(); + + if ( m_Ban ) + { + targAccount.Banned = true; + targAccount.SetUnspecifiedBan( from ); + from.SendGump( new BanDurationGump( targAccount ) ); + } + } + } + else if ( targState == null ) + { + LogFailure( "They are not online." ); + } + } + else + { + LogFailure( "You do not have the required access level to do this." ); + } + } + } + public class TraceLockdownCommand : BaseCommand + { + public TraceLockdownCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.Simple; + Commands = new string[] { "TraceLockdown" }; + ObjectTypes = ObjectTypes.Items; + Usage = "TraceLockdown"; + Description = "Finds the BaseHouse for which a targeted item is locked down or secured."; + } + + public override void Execute(CommandEventArgs e, object obj) + { + Item item = obj as Item; + + if (item == null) + return; + + if (!item.IsLockedDown && !item.IsSecure) + { + LogFailure("That is not locked down."); + return; + } + + foreach (BaseHouse house in BaseHouse.AllHouses) + { + if (house.IsSecure(item) || house.IsLockedDown(item)) + { + e.Mobile.SendGump(new PropertiesGump(e.Mobile, house)); + return; + } + } + + LogFailure("No house was found."); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Commands/DesignInsert.cs b/Scripts/Commands/Generic/Commands/DesignInsert.cs new file mode 100644 index 0000000..f0a1f58 --- /dev/null +++ b/Scripts/Commands/Generic/Commands/DesignInsert.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Multis; +using Server.Targeting; + +namespace Server.Commands.Generic +{ + public class DesignInsertCommand : BaseCommand + { + public static void Initialize() + { + TargetCommands.Register( new DesignInsertCommand() ); + } + + public DesignInsertCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Single | CommandSupport.Area; + Commands = new string[] { "DesignInsert" }; + ObjectTypes = ObjectTypes.Items; + Usage = "DesignInsert [allItems=false]"; + Description = "Inserts multiple targeted items into a customizable house's design."; + } + + #region Single targeting mode + public override void Execute( CommandEventArgs e, object obj ) + { + Target t = new DesignInsertTarget( new List(), ( e.Length < 1 || !e.GetBoolean( 0 ) ) ); + t.Invoke( e.Mobile, obj ); + } + + private class DesignInsertTarget : Target + { + private List m_Foundations; + private bool m_StaticsOnly; + + public DesignInsertTarget( List foundations, bool staticsOnly ) + : base( -1, false, TargetFlags.None ) + { + m_Foundations = foundations; + m_StaticsOnly = staticsOnly; + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + if ( m_Foundations.Count != 0 ) + { + from.SendMessage( "Your changes have been committed. Updating..." ); + + foreach ( HouseFoundation house in m_Foundations ) + house.Delta( ItemDelta.Update ); + } + } + + protected override void OnTarget( Mobile from, object obj ) + { + HouseFoundation house; + DesignInsertResult result = ProcessInsert( obj as Item, m_StaticsOnly, out house ); + + switch ( result ) + { + case DesignInsertResult.Valid: + { + if ( m_Foundations.Count == 0 ) + from.SendMessage( "The item has been inserted into the house design. Press ESC when you are finished." ); + else + from.SendMessage( "The item has been inserted into the house design." ); + + if ( !m_Foundations.Contains( house ) ) + m_Foundations.Add( house ); + + break; + } + case DesignInsertResult.InvalidItem: + { + from.SendMessage( "That cannot be inserted. Try again." ); + break; + } + case DesignInsertResult.NotInHouse: + case DesignInsertResult.OutsideHouseBounds: + { + from.SendMessage( "That item is not inside a customizable house. Try again." ); + break; + } + } + + from.Target = new DesignInsertTarget( m_Foundations, m_StaticsOnly ); + } + } + #endregion + + #region Area targeting mode + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + e.Mobile.SendGump( new WarningGump( 1060637, 30720, String.Format( "You are about to insert {0} objects. This cannot be undone without a full server revert.

Continue?", list.Count ), 0xFFC000, 420, 280, new WarningGumpCallback( OnConfirmCallback ), new object[] { e, list, ( e.Length < 1 || !e.GetBoolean( 0 ) ) } ) ); + AddResponse( "Awaiting confirmation..." ); + } + + private void OnConfirmCallback( Mobile from, bool okay, object state ) + { + object[] states = (object[])state; + CommandEventArgs e = (CommandEventArgs)states[0]; + ArrayList list = (ArrayList)states[1]; + bool staticsOnly = (bool)states[2]; + + bool flushToLog = false; + + if ( okay ) + { + List foundations = new List(); + flushToLog = ( list.Count > 20 ); + + for ( int i = 0; i < list.Count; ++i ) + { + HouseFoundation house; + DesignInsertResult result = ProcessInsert( list[i] as Item, staticsOnly, out house ); + + switch ( result ) + { + case DesignInsertResult.Valid: + { + AddResponse( "The item has been inserted into the house design." ); + + if ( !foundations.Contains( house ) ) + foundations.Add( house ); + + break; + } + case DesignInsertResult.InvalidItem: + { + LogFailure( "That cannot be inserted." ); + break; + } + case DesignInsertResult.NotInHouse: + case DesignInsertResult.OutsideHouseBounds: + { + LogFailure( "That item is not inside a customizable house." ); + break; + } + } + } + + foreach ( HouseFoundation house in foundations ) + house.Delta( ItemDelta.Update ); + } + else + { + AddResponse( "Command aborted." ); + } + + Flush( from, flushToLog ); + } + #endregion + + public enum DesignInsertResult + { + Valid, + InvalidItem, + NotInHouse, + OutsideHouseBounds + } + + public static DesignInsertResult ProcessInsert( Item item, bool staticsOnly, out HouseFoundation house ) + { + house = null; + + if ( item == null || item is BaseMulti || item is HouseSign || ( staticsOnly && !( item is Static ) ) ) + return DesignInsertResult.InvalidItem; + + house = BaseHouse.FindHouseAt( item ) as HouseFoundation; + + if ( house == null ) + return DesignInsertResult.NotInHouse; + + int x = item.X - house.X; + int y = item.Y - house.Y; + int z = item.Z - house.Z; + + if ( !TryInsertIntoState( house.CurrentState, item.ItemID, x, y, z ) ) + return DesignInsertResult.OutsideHouseBounds; + + TryInsertIntoState( house.DesignState, item.ItemID, x, y, z ); + item.Delete(); + + return DesignInsertResult.Valid; + } + + private static bool TryInsertIntoState( DesignState state, int itemID, int x, int y, int z ) + { + MultiComponentList mcl = state.Components; + + if ( x < mcl.Min.X || y < mcl.Min.Y || x > mcl.Max.X || y > mcl.Max.Y ) + return false; + + mcl.Add( itemID, x, y, z ); + state.OnRevised(); + + return true; + } + } +} diff --git a/Scripts/Commands/Generic/Commands/Interface.cs b/Scripts/Commands/Generic/Commands/Interface.cs new file mode 100644 index 0000000..18d1427 --- /dev/null +++ b/Scripts/Commands/Generic/Commands/Interface.cs @@ -0,0 +1,570 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Targeting; +using Server.Targets; + +namespace Server.Commands.Generic +{ + public class InterfaceCommand : BaseCommand + { + public InterfaceCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Complex | CommandSupport.Simple; + Commands = new string[]{ "Interface" }; + ObjectTypes = ObjectTypes.Both; + Usage = "Interface [view ]"; + Description = "Opens an interface to interact with matched objects. Generally used with condition arguments."; + ListOptimized = true; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + if ( list.Count > 0 ) + { + List columns = new List(); + + columns.Add( "Object" ); + + if ( e.Length > 0 ) + { + int offset = 0; + + if ( Insensitive.Equals( e.GetString( 0 ), "view" ) ) + ++offset; + + while ( offset < e.Length ) + columns.Add( e.GetString( offset++ ) ); + } + + e.Mobile.SendGump( new InterfaceGump( e.Mobile, columns.ToArray(), list, 0, null ) ); + } + else + { + AddResponse( "No matching objects found." ); + } + } + } + + public class InterfaceGump : BaseGridGump + { + private Mobile m_From; + + private string[] m_Columns; + + private ArrayList m_List; + private int m_Page; + + private object m_Select; + + private const int EntriesPerPage = 15; + + public InterfaceGump( Mobile from, string[] columns, ArrayList list, int page, object select ) : base( 30, 30 ) + { + m_From = from; + + m_Columns = columns; + + m_List = list; + m_Page = page; + + m_Select = select; + + Render(); + } + + public void Render() + { + AddNewPage(); + + if ( m_Page > 0 ) + AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight ); + else + AddEntryHeader( 20 ); + + AddEntryHtml( 40 + ( m_Columns.Length * 130 ) - 20 + ( ( m_Columns.Length - 2 ) * OffsetSize ), Center( String.Format( "Page {0} of {1}", m_Page+1, (m_List.Count + EntriesPerPage - 1) / EntriesPerPage ) ) ); + + if ( (m_Page + 1) * EntriesPerPage < m_List.Count ) + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight ); + else + AddEntryHeader( 20 ); + + if ( m_Columns.Length > 1 ) + { + AddNewLine(); + + for ( int i = 0; i < m_Columns.Length; ++i ) + { + if ( i > 0 && m_List.Count > 0 ) + { + object obj = m_List[0]; + + if ( obj != null ) + { + string failReason = null; + PropertyInfo[] chain = Properties.GetPropertyInfoChain( m_From, obj.GetType(), m_Columns[i], PropertyAccess.Read, ref failReason ); + + if ( chain != null && chain.Length > 0 ) + { + m_Columns[i] = ""; + + for ( int j = 0; j < chain.Length; ++j ) + { + if ( j > 0 ) + m_Columns[i] += '.'; + + m_Columns[i] += chain[j].Name; + } + } + } + } + + AddEntryHtml( 130 + ( i == 0 ? 40 : 0 ), m_Columns[i] ); + } + + AddEntryHeader( 20 ); + } + + for ( int i = m_Page * EntriesPerPage, line = 0; line < EntriesPerPage && i < m_List.Count; ++i, ++line ) + { + AddNewLine(); + + object obj = m_List[i]; + bool isDeleted = false; + + if ( obj is Item ) + { + Item item = (Item)obj; + + if ( !(isDeleted = item.Deleted) ) + AddEntryHtml( 40 + 130, item.GetType().Name ); + } + else if ( obj is Mobile ) + { + Mobile mob = (Mobile)obj; + + if ( !(isDeleted = mob.Deleted) ) + AddEntryHtml( 40 + 130, mob.Name ); + } + + if ( isDeleted ) + { + AddEntryHtml( 40 + 130, "(deleted)" ); + + for ( int j = 1; j < m_Columns.Length; ++j ) + AddEntryHtml( 130, "---" ); + + AddEntryHeader( 20 ); + } + else + { + for ( int j = 1; j < m_Columns.Length; ++j ) + { + object src = obj; + + string value; + string failReason = ""; + + PropertyInfo[] chain = Properties.GetPropertyInfoChain( m_From, src.GetType(), m_Columns[j], PropertyAccess.Read, ref failReason ); + + if ( chain == null || chain.Length == 0 ) + { + value = "---"; + } + else + { + PropertyInfo p = Properties.GetPropertyInfo( ref src, chain, ref failReason ); + + if ( p == null ) + value = "---"; + else + value = PropertiesGump.ValueToString( src, p ); + } + + AddEntryHtml( 130, value ); + } + + bool isSelected = ( m_Select != null && obj == m_Select ); + + AddEntryButton( 20, ( isSelected ? 9762 : ArrowRightID1 ), ( isSelected ? 9763 : ArrowRightID2 ), 3 + i, ArrowRightWidth, ArrowRightHeight ); + } + } + + FinishPage(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 1: + { + if ( m_Page > 0 ) + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page - 1, m_Select ) ); + + break; + } + case 2: + { + if ( (m_Page + 1) * EntriesPerPage < m_List.Count ) + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page + 1, m_Select ) ); + + break; + } + default: + { + int v = info.ButtonID - 3; + + if ( v >= 0 && v < m_List.Count ) + { + object obj = m_List[v]; + + if ( !BaseCommand.IsAccessible( m_From, obj ) ) + { + m_From.SendMessage( "That is not accessible." ); + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Select ) ); + break; + } + + if ( obj is Item && !((Item)obj).Deleted ) + m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, (Item) obj ) ); + else if ( obj is Mobile && !((Mobile)obj).Deleted ) + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, (Mobile) obj ) ); + else + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Select ) ); + } + + break; + } + } + } + } + + public class InterfaceItemGump : BaseGridGump + { + private Mobile m_From; + + private string[] m_Columns; + + private ArrayList m_List; + private int m_Page; + + private Item m_Item; + + public InterfaceItemGump( Mobile from, string[] columns, ArrayList list, int page, Item item ) : base( 30, 30 ) + { + m_From = from; + + m_Columns = columns; + + m_List = list; + m_Page = page; + + m_Item = item; + + Render(); + } + + public void Render() + { + AddNewPage(); + + AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight ); + AddEntryHtml( 160, m_Item.GetType().Name ); + AddEntryHeader( 20 ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Properties" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Delete" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Go there" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Move to target" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Bring to pack" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight ); + + FinishPage(); + } + + private void InvokeCommand( string ip ) + { + CommandSystem.Handle( m_From, String.Format( "{0}{1}", CommandSystem.Prefix, ip ) ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Item.Deleted ) + { + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + return; + } + else if ( !BaseCommand.IsAccessible( m_From, m_Item ) ) + { + m_From.SendMessage( "That is no longer accessible." ); + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + return; + } + + switch ( info.ButtonID ) + { + case 0: + case 1: + { + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + break; + } + case 2: // Properties + { + m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + m_From.SendGump( new PropertiesGump( m_From, m_Item ) ); + break; + } + case 3: // Delete + { + CommandLogging.WriteLine( m_From, "{0} {1} deleting {2}", m_From.AccessLevel, CommandLogging.Format( m_From ), CommandLogging.Format( m_Item ) ); + m_Item.Delete(); + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + break; + } + case 4: // Go there + { + m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + InvokeCommand( String.Format( "Go {0}", m_Item.Serial.Value ) ); + break; + } + case 5: // Move to target + { + m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + m_From.Target = new MoveTarget( m_Item ); + break; + } + case 6: // Bring to pack + { + Mobile owner = m_Item.RootParent as Mobile; + + if ( owner != null && (owner.Map != null && owner.Map != Map.Internal) && !BaseCommand.IsAccessible( m_From, owner ) /* !m_From.CanSee( owner )*/ ) + { + m_From.SendMessage( "You can not get what you can not see." ); + } + else if ( owner != null && (owner.Map == null || owner.Map == Map.Internal) && owner.Hidden && owner.AccessLevel >= m_From.AccessLevel ) + { + m_From.SendMessage( "You can not get what you can not see." ); + } + else + { + m_From.SendGump( new InterfaceItemGump( m_From, m_Columns, m_List, m_Page, m_Item ) ); + m_From.AddToBackpack( m_Item ); + } + + break; + } + } + } + } + + public class InterfaceMobileGump : BaseGridGump + { + private Mobile m_From; + + private string[] m_Columns; + + private ArrayList m_List; + private int m_Page; + + private Mobile m_Mobile; + + public InterfaceMobileGump( Mobile from, string[] columns, ArrayList list, int page, Mobile mob ) + : base( 30, 30 ) + { + m_From = from; + + m_Columns = columns; + + m_List = list; + m_Page = page; + + m_Mobile = mob; + + Render(); + } + + public void Render() + { + AddNewPage(); + + AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight ); + AddEntryHtml( 160, m_Mobile.Name ); + AddEntryHeader( 20 ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Properties" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight ); + + if ( !m_Mobile.Player ) + { + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Delete" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight ); + } + + if ( m_Mobile != m_From ) + { + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Go to there" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight ); + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Bring them here" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight ); + } + + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Move to target" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight ); + + if ( m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel ) + { + AddNewLine(); + if ( m_Mobile.Alive ) + { + AddEntryHtml( 20 + OffsetSize + 160, "Kill" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 7, ArrowRightWidth, ArrowRightHeight ); + } + else + { + AddEntryHtml( 20 + OffsetSize + 160, "Resurrect" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 8, ArrowRightWidth, ArrowRightHeight ); + } + } + + if ( m_Mobile.NetState != null ) + { + AddNewLine(); + AddEntryHtml( 20 + OffsetSize + 160, "Client" ); + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 9, ArrowRightWidth, ArrowRightHeight ); + } + + FinishPage(); + } + + private void InvokeCommand( string ip ) + { + CommandSystem.Handle( m_From, String.Format( "{0}{1}", CommandSystem.Prefix, ip ) ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Mobile.Deleted ) + { + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + return; + } + else if ( !BaseCommand.IsAccessible( m_From, m_Mobile ) ) + { + m_From.SendMessage( "That is no longer accessible." ); + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + return; + } + + switch ( info.ButtonID ) + { + case 0: + case 1: + { + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + break; + } + case 2: // Properties + { + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + m_From.SendGump( new PropertiesGump( m_From, m_Mobile ) ); + break; + } + case 3: // Delete + { + if ( !m_Mobile.Player ) + { + CommandLogging.WriteLine( m_From, "{0} {1} deleting {2}", m_From.AccessLevel, CommandLogging.Format( m_From ), CommandLogging.Format( m_Mobile ) ); + m_Mobile.Delete(); + m_From.SendGump( new InterfaceGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + } + + break; + } + case 4: // Go there + { + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + InvokeCommand( String.Format( "Go {0}", m_Mobile.Serial.Value ) ); + break; + } + case 5: // Bring them here + { + if ( m_From.Map == null || m_From.Map == Map.Internal ) + { + m_From.SendMessage( "You cannot bring that person here." ); + } + else + { + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + m_Mobile.MoveToWorld( m_From.Location, m_From.Map ); + } + + break; + } + case 6: // Move to target + { + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + m_From.Target = new MoveTarget( m_Mobile ); + break; + } + case 7: // Kill + { + if ( m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel ) + m_Mobile.Kill(); + + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + + break; + } + case 8: // Res + { + if ( m_From == m_Mobile || m_From.AccessLevel > m_Mobile.AccessLevel ) + { + m_Mobile.PlaySound( 0x214 ); + m_Mobile.FixedEffect( 0x376A, 10, 16 ); + + m_Mobile.Resurrect(); + } + + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + + break; + } + case 9: // Client + { + m_From.SendGump( new InterfaceMobileGump( m_From, m_Columns, m_List, m_Page, m_Mobile ) ); + + if ( m_Mobile.NetState != null ) + m_From.SendGump( new ClientGump( m_From, m_Mobile.NetState ) ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Extensions/BaseExtension.cs b/Scripts/Commands/Generic/Extensions/BaseExtension.cs new file mode 100644 index 0000000..b6a0902 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/BaseExtension.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Server.Commands.Generic +{ + public delegate BaseExtension ExtensionConstructor(); + + public sealed class ExtensionInfo + { + private static Dictionary m_Table = new Dictionary( StringComparer.InvariantCultureIgnoreCase ); + + public static Dictionary Table + { + get { return m_Table; } + } + + public static void Register( ExtensionInfo ext ) + { + m_Table[ext.m_Name] = ext; + } + + private int m_Order; + + private string m_Name; + private int m_Size; + + private ExtensionConstructor m_Constructor; + + public int Order + { + get { return m_Order; } + } + + public string Name + { + get { return m_Name; } + } + + public int Size + { + get { return m_Size; } + } + + public bool IsFixedSize + { + get { return ( m_Size >= 0 ); } + } + + public ExtensionConstructor Constructor + { + get { return m_Constructor; } + } + + public ExtensionInfo( int order, string name, int size, ExtensionConstructor constructor ) + { + m_Name = name; + m_Size = size; + + m_Order = order; + + m_Constructor = constructor; + } + } + + public sealed class Extensions : List + { + public Extensions() + { + } + + public bool IsValid( object obj ) + { + for ( int i = 0; i < this.Count; ++i ) + { + if ( !this[i].IsValid( obj ) ) + return false; + } + + return true; + } + + public void Filter( ArrayList list ) + { + for ( int i = 0; i < this.Count; ++i ) + this[i].Filter( list ); + } + + public static Extensions Parse( Mobile from, ref string[] args ) + { + Extensions parsed = new Extensions(); + + int size = args.Length; + + Type baseType = null; + + for ( int i = args.Length - 1; i >= 0; --i ) + { + ExtensionInfo extInfo = null; + + if ( !ExtensionInfo.Table.TryGetValue( args[i], out extInfo ) ) + continue; + + if ( extInfo.IsFixedSize && i != ( size - extInfo.Size - 1 ) ) + throw new Exception( "Invalid extended argument count." ); + + BaseExtension ext = extInfo.Constructor(); + + ext.Parse( from, args, i + 1, size - i - 1 ); + + if ( ext is WhereExtension ) + baseType = ( ext as WhereExtension ).Conditional.Type; + + parsed.Add( ext ); + + size = i; + } + + parsed.Sort( delegate( BaseExtension a, BaseExtension b ) + { + return ( a.Order - b.Order ); + } ); + + AssemblyEmitter emitter = null; + + foreach ( BaseExtension update in parsed ) + update.Optimize( from, baseType, ref emitter ); + + if ( size != args.Length ) + { + string[] old = args; + args = new string[size]; + + for ( int i = 0; i < args.Length; ++i ) + args[i] = old[i]; + } + + return parsed; + } + } + + public abstract class BaseExtension + { + public abstract ExtensionInfo Info { get; } + + public string Name + { + get { return Info.Name; } + } + + public int Size + { + get { return Info.Size; } + } + + public bool IsFixedSize + { + get { return Info.IsFixedSize; } + } + + public int Order + { + get { return Info.Order; } + } + + public virtual void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly ) + { + } + + public virtual void Parse( Mobile from, string[] arguments, int offset, int size ) + { + } + + public virtual bool IsValid( object obj ) + { + return true; + } + + public virtual void Filter( ArrayList list ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs b/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs new file mode 100644 index 0000000..8c924f1 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs @@ -0,0 +1,569 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using Server; + +namespace Server.Commands.Generic +{ + public interface IConditional + { + bool Verify( object obj ); + } + + public interface ICondition + { + // Invoked during the constructor + void Construct( TypeBuilder typeBuilder, ILGenerator il, int index ); + + // Target object will be loaded on the stack + void Compile( MethodEmitter emitter ); + } + + public sealed class TypeCondition : ICondition + { + public static TypeCondition Default = new TypeCondition(); + + void ICondition.Construct( TypeBuilder typeBuilder, ILGenerator il, int index ) + { + } + + void ICondition.Compile( MethodEmitter emitter ) + { + // The object was safely cast to be the conditionals type + // If it's null, then the type cast didn't work... + + emitter.LoadNull(); + emitter.Compare( OpCodes.Ceq ); + emitter.LogicalNot(); + } + } + + public sealed class PropertyValue + { + private Type m_Type; + private object m_Value; + private FieldInfo m_Field; + + public Type Type + { + get { return m_Type; } + } + + public object Value + { + get { return m_Value; } + } + + public FieldInfo Field + { + get { return m_Field; } + } + + public bool HasField + { + get { return ( m_Field != null ); } + } + + public PropertyValue( Type type, object value ) + { + m_Type = type; + m_Value = value; + } + + public void Load( MethodEmitter method ) + { + if ( m_Field != null ) + { + method.LoadArgument( 0 ); + method.LoadField( m_Field ); + } + else if ( m_Value == null ) + { + method.LoadNull( m_Type ); + } + else + { + if ( m_Value is int ) + method.Load( (int) m_Value ); + else if ( m_Value is long ) + method.Load( (long) m_Value ); + else if ( m_Value is float ) + method.Load( (float) m_Value ); + else if ( m_Value is double ) + method.Load( (double) m_Value ); + else if ( m_Value is char ) + method.Load( (char) m_Value ); + else if ( m_Value is bool ) + method.Load( (bool) m_Value ); + else if ( m_Value is string ) + method.Load( (string) m_Value ); + else if ( m_Value is Enum ) + method.Load( (Enum) m_Value ); + else + throw new InvalidOperationException( "Unrecognized comparison value." ); + } + } + + public void Acquire( TypeBuilder typeBuilder, ILGenerator il, string fieldName ) + { + if ( m_Value is string ) + { + string toParse = (string) m_Value; + + if ( !m_Type.IsValueType && toParse == "null" ) + { + m_Value = null; + } + else if ( m_Type == typeof( string ) ) + { + if ( toParse == @"@""null""" ) + toParse = "null"; + + m_Value = toParse; + } + else if ( m_Type.IsEnum ) + { + m_Value = Enum.Parse( m_Type, toParse, true ); + } + else + { + MethodInfo parseMethod = null; + object[] parseArgs = null; + + MethodInfo parseNumber = m_Type.GetMethod( + "Parse", + BindingFlags.Public | BindingFlags.Static, + null, + new Type[] { typeof( string ), typeof( NumberStyles ) }, + null + ); + + if ( parseNumber != null ) + { + NumberStyles style = NumberStyles.Integer; + + if ( Insensitive.StartsWith( toParse, "0x" ) ) + { + style = NumberStyles.HexNumber; + toParse = toParse.Substring( 2 ); + } + + parseMethod = parseNumber; + parseArgs = new object[] { toParse, style }; + } + else + { + MethodInfo parseGeneral = m_Type.GetMethod( + "Parse", + BindingFlags.Public | BindingFlags.Static, + null, + new Type[] { typeof( string ) }, + null + ); + + parseMethod = parseGeneral; + parseArgs = new object[] { toParse }; + } + + if ( parseMethod != null ) + { + m_Value = parseMethod.Invoke( null, parseArgs ); + + if ( !m_Type.IsPrimitive ) + { + m_Field = typeBuilder.DefineField( + fieldName, + m_Type, + FieldAttributes.Private | FieldAttributes.InitOnly + ); + + il.Emit( OpCodes.Ldarg_0 ); + + il.Emit( OpCodes.Ldstr, toParse ); + + if ( parseArgs.Length == 2 ) // dirty evil hack :-( + il.Emit( OpCodes.Ldc_I4, (int) parseArgs[1] ); + + il.Emit( OpCodes.Call, parseMethod ); + il.Emit( OpCodes.Stfld, m_Field ); + } + } + else + { + throw new InvalidOperationException( + String.Format( + "Unable to convert string \"{0}\" into type '{1}'.", + m_Value, + m_Type + ) + ); + } + } + } + } + } + + public abstract class PropertyCondition : ICondition + { + protected Property m_Property; + protected bool m_Not; + + public PropertyCondition( Property property, bool not ) + { + m_Property = property; + m_Not = not; + } + + public abstract void Construct( TypeBuilder typeBuilder, ILGenerator il, int index ); + + public abstract void Compile( MethodEmitter emitter ); + } + + public enum StringOperator + { + Equal, + NotEqual, + + Contains, + + StartsWith, + EndsWith + } + + public sealed class StringCondition : PropertyCondition + { + private StringOperator m_Operator; + private PropertyValue m_Value; + + private bool m_IgnoreCase; + + public StringCondition( Property property, bool not, StringOperator op, object value, bool ignoreCase ) + : base( property, not ) + { + m_Operator = op; + m_Value = new PropertyValue( property.Type, value ); + + m_IgnoreCase = ignoreCase; + } + + public override void Construct( TypeBuilder typeBuilder, ILGenerator il, int index ) + { + m_Value.Acquire( typeBuilder, il, "v" + index ); + } + + public override void Compile( MethodEmitter emitter ) + { + bool inverse = false; + + string methodName; + + switch ( m_Operator ) + { + case StringOperator.Equal: + methodName = "Equals"; + break; + + case StringOperator.NotEqual: + methodName = "Equals"; + inverse = true; + break; + + case StringOperator.Contains: + methodName = "Contains"; + break; + + case StringOperator.StartsWith: + methodName = "StartsWith"; + break; + + case StringOperator.EndsWith: + methodName = "EndsWith"; + break; + + default: + throw new InvalidOperationException( "Invalid string comparison operator." ); + } + + if ( m_IgnoreCase || methodName == "Equals" ) + { + Type type = ( m_IgnoreCase ? typeof( Insensitive ) : typeof( String ) ); + + emitter.BeginCall( + type.GetMethod( + methodName, + BindingFlags.Public | BindingFlags.Static, + null, + new Type[] + { + typeof( string ), + typeof( string ) + }, + null + ) + ); + + emitter.Chain( m_Property ); + m_Value.Load( emitter ); + + emitter.FinishCall(); + } + else + { + Label notNull = emitter.CreateLabel(); + Label moveOn = emitter.CreateLabel(); + + LocalBuilder temp = emitter.AcquireTemp( m_Property.Type ); + + emitter.Chain( m_Property ); + + emitter.StoreLocal( temp ); + emitter.LoadLocal( temp ); + + emitter.BranchIfTrue( notNull ); + + emitter.Load( false ); + emitter.Pop(); + emitter.Branch( moveOn ); + + emitter.MarkLabel( notNull ); + emitter.LoadLocal( temp ); + + emitter.BeginCall( + typeof( string ).GetMethod( + methodName, + BindingFlags.Public | BindingFlags.Instance, + null, + new Type[] + { + typeof( string ) + }, + null + ) + ); + + m_Value.Load( emitter ); + + emitter.FinishCall(); + + emitter.MarkLabel( moveOn ); + } + + if ( m_Not != inverse ) + emitter.LogicalNot(); + } + } + + public enum ComparisonOperator + { + Equal, + NotEqual, + Greater, + GreaterEqual, + Lesser, + LesserEqual + } + + public sealed class ComparisonCondition : PropertyCondition + { + private ComparisonOperator m_Operator; + private PropertyValue m_Value; + + public ComparisonCondition( Property property, bool not, ComparisonOperator op, object value ) + : base( property, not ) + { + m_Operator = op; + m_Value = new PropertyValue( property.Type, value ); + } + + public override void Construct( TypeBuilder typeBuilder, ILGenerator il, int index ) + { + m_Value.Acquire( typeBuilder, il, "v" + index ); + } + + public override void Compile( MethodEmitter emitter ) + { + emitter.Chain( m_Property ); + + bool inverse = false; + + bool couldCompare = + emitter.CompareTo( 1, delegate() + { + m_Value.Load( emitter ); + } ); + + if ( couldCompare ) + { + emitter.Load( 0 ); + + switch ( m_Operator ) + { + case ComparisonOperator.Equal: + emitter.Compare( OpCodes.Ceq ); + break; + + case ComparisonOperator.NotEqual: + emitter.Compare( OpCodes.Ceq ); + inverse = true; + break; + + case ComparisonOperator.Greater: + emitter.Compare( OpCodes.Cgt ); + break; + + case ComparisonOperator.GreaterEqual: + emitter.Compare( OpCodes.Clt ); + inverse = true; + break; + + case ComparisonOperator.Lesser: + emitter.Compare( OpCodes.Clt ); + break; + + case ComparisonOperator.LesserEqual: + emitter.Compare( OpCodes.Cgt ); + inverse = true; + break; + + default: + throw new InvalidOperationException( "Invalid comparison operator." ); + } + } + else + { + // This type is -not- comparable + // We can only support == and != operations + + m_Value.Load( emitter ); + + switch ( m_Operator ) + { + case ComparisonOperator.Equal: + emitter.Compare( OpCodes.Ceq ); + break; + + case ComparisonOperator.NotEqual: + emitter.Compare( OpCodes.Ceq ); + inverse = true; + break; + + case ComparisonOperator.Greater: + case ComparisonOperator.GreaterEqual: + case ComparisonOperator.Lesser: + case ComparisonOperator.LesserEqual: + throw new InvalidOperationException( "Property does not support relational comparisons." ); + + default: + throw new InvalidOperationException( "Invalid operator." ); + } + } + + if ( m_Not != inverse ) + emitter.LogicalNot(); + } + } + + public static class ConditionalCompiler + { + public static IConditional Compile( AssemblyEmitter assembly, Type objectType, ICondition[] conditions, int index ) + { + TypeBuilder typeBuilder = assembly.DefineType( + "__conditional" + index, + TypeAttributes.Public, + typeof( object ) + ); + + #region Constructor + { + ConstructorBuilder ctor = typeBuilder.DefineConstructor( + MethodAttributes.Public, + CallingConventions.Standard, + Type.EmptyTypes + ); + + ILGenerator il = ctor.GetILGenerator(); + + // : base() + il.Emit( OpCodes.Ldarg_0 ); + il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) ); + + for ( int i = 0; i < conditions.Length; ++i ) + conditions[i].Construct( typeBuilder, il, i ); + + // return; + il.Emit( OpCodes.Ret ); + } + #endregion + + #region IComparer + typeBuilder.AddInterfaceImplementation( typeof( IConditional ) ); + + MethodBuilder compareMethod; + + #region Compare + { + MethodEmitter emitter = new MethodEmitter( typeBuilder ); + + emitter.Define( + /* name */ "Verify", + /* attr */ MethodAttributes.Public | MethodAttributes.Virtual, + /* return */ typeof( bool ), + /* params */ new Type[] { typeof( object ) } ); + + LocalBuilder obj = emitter.CreateLocal( objectType ); + LocalBuilder eq = emitter.CreateLocal( typeof( bool ) ); + + emitter.LoadArgument( 1 ); + emitter.CastAs( objectType ); + emitter.StoreLocal( obj ); + + Label done = emitter.CreateLabel(); + + for ( int i = 0; i < conditions.Length; ++i ) + { + if ( i > 0 ) + { + emitter.LoadLocal( eq ); + + emitter.BranchIfFalse( done ); + } + + emitter.LoadLocal( obj ); + + conditions[i].Compile( emitter ); + + emitter.StoreLocal( eq ); + } + + emitter.MarkLabel( done ); + + emitter.LoadLocal( eq ); + + emitter.Return(); + + typeBuilder.DefineMethodOverride( + emitter.Method, + typeof( IConditional ).GetMethod( + "Verify", + new Type[] + { + typeof( object ) + } + ) + ); + + compareMethod = emitter.Method; + } + #endregion + #endregion + + Type conditionalType = typeBuilder.CreateType(); + + return (IConditional) Activator.CreateInstance( conditionalType ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Extensions/Compilers/DistinctCompiler.cs b/Scripts/Commands/Generic/Extensions/Compilers/DistinctCompiler.cs new file mode 100644 index 0000000..7a9ece8 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/Compilers/DistinctCompiler.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using Server; + +namespace Server.Commands.Generic +{ + public static class DistinctCompiler + { + public static IComparer Compile( AssemblyEmitter assembly, Type objectType, Property[] props ) + { + TypeBuilder typeBuilder = assembly.DefineType( + "__distinct", + TypeAttributes.Public, + typeof( object ) + ); + + #region Constructor + { + ConstructorBuilder ctor = typeBuilder.DefineConstructor( + MethodAttributes.Public, + CallingConventions.Standard, + Type.EmptyTypes + ); + + ILGenerator il = ctor.GetILGenerator(); + + // : base() + il.Emit( OpCodes.Ldarg_0 ); + il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) ); + + // return; + il.Emit( OpCodes.Ret ); + } + #endregion + + #region IComparer + typeBuilder.AddInterfaceImplementation( typeof( IComparer ) ); + + MethodBuilder compareMethod; + + #region Compare + { + MethodEmitter emitter = new MethodEmitter( typeBuilder ); + + emitter.Define( + /* name */ "Compare", + /* attr */ MethodAttributes.Public | MethodAttributes.Virtual, + /* return */ typeof( int ), + /* params */ new Type[] { typeof( object ), typeof( object ) } ); + + LocalBuilder a = emitter.CreateLocal( objectType ); + LocalBuilder b = emitter.CreateLocal( objectType ); + + LocalBuilder v = emitter.CreateLocal( typeof( int ) ); + + emitter.LoadArgument( 1 ); + emitter.CastAs( objectType ); + emitter.StoreLocal( a ); + + emitter.LoadArgument( 2 ); + emitter.CastAs( objectType ); + emitter.StoreLocal( b ); + + emitter.Load( 0 ); + emitter.StoreLocal( v ); + + Label end = emitter.CreateLabel(); + + for ( int i = 0; i < props.Length; ++i ) + { + if ( i > 0 ) + { + emitter.LoadLocal( v ); + emitter.BranchIfTrue( end ); // if ( v != 0 ) return v; + } + + Property prop = props[i]; + + emitter.LoadLocal( a ); + emitter.Chain( prop ); + + bool couldCompare = + emitter.CompareTo( 1, delegate() + { + emitter.LoadLocal( b ); + emitter.Chain( prop ); + } ); + + if ( !couldCompare ) + throw new InvalidOperationException( "Property is not comparable." ); + + emitter.StoreLocal( v ); + } + + emitter.MarkLabel( end ); + + emitter.LoadLocal( v ); + emitter.Return(); + + typeBuilder.DefineMethodOverride( + emitter.Method, + typeof( IComparer ).GetMethod( + "Compare", + new Type[] + { + typeof( object ), + typeof( object ) + } + ) + ); + + compareMethod = emitter.Method; + } + #endregion + #endregion + + #region IEqualityComparer + typeBuilder.AddInterfaceImplementation( typeof( IEqualityComparer ) ); + + #region Equals + { + MethodEmitter emitter = new MethodEmitter( typeBuilder ); + + emitter.Define( + /* name */ "Equals", + /* attr */ MethodAttributes.Public | MethodAttributes.Virtual, + /* return */ typeof( bool ), + /* params */ new Type[] { typeof( object ), typeof( object ) } ); + + emitter.Generator.Emit( OpCodes.Ldarg_0 ); + emitter.Generator.Emit( OpCodes.Ldarg_1 ); + emitter.Generator.Emit( OpCodes.Ldarg_2 ); + + emitter.Generator.Emit( OpCodes.Call, compareMethod ); + + emitter.Generator.Emit( OpCodes.Ldc_I4_0 ); + + emitter.Generator.Emit( OpCodes.Ceq ); + + emitter.Generator.Emit( OpCodes.Ret ); + + typeBuilder.DefineMethodOverride( + emitter.Method, + typeof( IEqualityComparer ).GetMethod( + "Equals", + new Type[] + { + typeof( object ), + typeof( object ) + } + ) + ); + } + #endregion + + #region GetHashCode + { + MethodEmitter emitter = new MethodEmitter( typeBuilder ); + + emitter.Define( + /* name */ "GetHashCode", + /* attr */ MethodAttributes.Public | MethodAttributes.Virtual, + /* return */ typeof( int ), + /* params */ new Type[] { typeof( object ) } ); + + LocalBuilder obj = emitter.CreateLocal( objectType ); + + emitter.LoadArgument( 1 ); + emitter.CastAs( objectType ); + emitter.StoreLocal( obj ); + + for ( int i = 0; i < props.Length; ++i ) + { + Property prop = props[i]; + + emitter.LoadLocal( obj ); + emitter.Chain( prop ); + + Type active = emitter.Active; + + MethodInfo getHashCode = active.GetMethod( "GetHashCode", Type.EmptyTypes ); + + if ( getHashCode == null ) + getHashCode = typeof( object ).GetMethod( "GetHashCode", Type.EmptyTypes ); + + if ( active != typeof( int ) ) + { + if ( !active.IsValueType ) + { + LocalBuilder value = emitter.AcquireTemp( active ); + + Label valueNotNull = emitter.CreateLabel(); + Label done = emitter.CreateLabel(); + + emitter.StoreLocal( value ); + emitter.LoadLocal( value ); + + emitter.BranchIfTrue( valueNotNull ); + + emitter.Load( 0 ); + emitter.Pop( typeof( int ) ); + + emitter.Branch( done ); + + emitter.MarkLabel( valueNotNull ); + + emitter.LoadLocal( value ); + emitter.Call( getHashCode ); + + emitter.ReleaseTemp( value ); + + emitter.MarkLabel( done ); + } + else + { + emitter.Call( getHashCode ); + } + } + + if ( i > 0 ) + emitter.Xor(); + } + + emitter.Return(); + + typeBuilder.DefineMethodOverride( + emitter.Method, + typeof( IEqualityComparer ).GetMethod( + "GetHashCode", + new Type[] + { + typeof( object ) + } + ) + ); + } + #endregion + #endregion + + Type comparerType = typeBuilder.CreateType(); + + return (IComparer) Activator.CreateInstance( comparerType ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs b/Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs new file mode 100644 index 0000000..8e996a2 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using Server; + +namespace Server.Commands.Generic +{ + public sealed class OrderInfo + { + private Property m_Property; + private int m_Order; + + public Property Property + { + get { return m_Property; } + set { m_Property = value; } + } + + public bool IsAscending + { + get { return ( m_Order > 0 ); } + set { m_Order = ( value ? +1 : -1 ); } + } + + public bool IsDescending + { + get { return ( m_Order < 0 ); } + set { m_Order = ( value ? -1 : +1 ); } + } + + public int Sign + { + get { return Math.Sign( m_Order ); } + set + { + m_Order = Math.Sign( value ); + + if ( m_Order == 0 ) + throw new InvalidOperationException( "Sign cannot be zero." ); + } + } + + public OrderInfo( Property property, bool isAscending ) + { + m_Property = property; + + this.IsAscending = isAscending; + } + } + + public static class SortCompiler + { + public static IComparer Compile( AssemblyEmitter assembly, Type objectType, OrderInfo[] orders ) + { + TypeBuilder typeBuilder = assembly.DefineType( + "__sort", + TypeAttributes.Public, + typeof( object ) + ); + + #region Constructor + { + ConstructorBuilder ctor = typeBuilder.DefineConstructor( + MethodAttributes.Public, + CallingConventions.Standard, + Type.EmptyTypes + ); + + ILGenerator il = ctor.GetILGenerator(); + + // : base() + il.Emit( OpCodes.Ldarg_0 ); + il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) ); + + // return; + il.Emit( OpCodes.Ret ); + } + #endregion + + #region IComparer + typeBuilder.AddInterfaceImplementation( typeof( IComparer ) ); + + MethodBuilder compareMethod; + + #region Compare + { + MethodEmitter emitter = new MethodEmitter( typeBuilder ); + + emitter.Define( + /* name */ "Compare", + /* attr */ MethodAttributes.Public | MethodAttributes.Virtual, + /* return */ typeof( int ), + /* params */ new Type[] { typeof( object ), typeof( object ) } ); + + LocalBuilder a = emitter.CreateLocal( objectType ); + LocalBuilder b = emitter.CreateLocal( objectType ); + + LocalBuilder v = emitter.CreateLocal( typeof( int ) ); + + emitter.LoadArgument( 1 ); + emitter.CastAs( objectType ); + emitter.StoreLocal( a ); + + emitter.LoadArgument( 2 ); + emitter.CastAs( objectType ); + emitter.StoreLocal( b ); + + emitter.Load( 0 ); + emitter.StoreLocal( v ); + + Label end = emitter.CreateLabel(); + + for ( int i = 0; i < orders.Length; ++i ) + { + if ( i > 0 ) + { + emitter.LoadLocal( v ); + emitter.BranchIfTrue( end ); // if ( v != 0 ) return v; + } + + OrderInfo orderInfo = orders[i]; + + Property prop = orderInfo.Property; + int sign = orderInfo.Sign; + + emitter.LoadLocal( a ); + emitter.Chain( prop ); + + bool couldCompare = + emitter.CompareTo( sign, delegate() + { + emitter.LoadLocal( b ); + emitter.Chain( prop ); + } ); + + if ( !couldCompare ) + throw new InvalidOperationException( "Property is not comparable." ); + + emitter.StoreLocal( v ); + } + + emitter.MarkLabel( end ); + + emitter.LoadLocal( v ); + emitter.Return(); + + typeBuilder.DefineMethodOverride( + emitter.Method, + typeof( IComparer ).GetMethod( + "Compare", + new Type[] + { + typeof( object ), + typeof( object ) + } + ) + ); + + compareMethod = emitter.Method; + } + #endregion + #endregion + + Type comparerType = typeBuilder.CreateType(); + + return (IComparer) Activator.CreateInstance( comparerType ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Extensions/DistinctExtension.cs b/Scripts/Commands/Generic/Extensions/DistinctExtension.cs new file mode 100644 index 0000000..366ccd2 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/DistinctExtension.cs @@ -0,0 +1,89 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Server.Commands.Generic +{ + public sealed class DistinctExtension : BaseExtension + { + public static ExtensionInfo ExtInfo = new ExtensionInfo( 30, "Distinct", -1, delegate() { return new DistinctExtension(); } ); + + public static void Initialize() + { + ExtensionInfo.Register( ExtInfo ); + } + + public override ExtensionInfo Info + { + get { return ExtInfo; } + } + + private List m_Properties; + + private IComparer m_Comparer; + + public DistinctExtension() + { + m_Properties = new List(); + } + + public override void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly ) + { + if ( baseType == null ) + throw new Exception( "Distinct extension may only be used in combination with an object conditional." ); + + foreach ( Property prop in m_Properties ) + { + prop.BindTo( baseType, PropertyAccess.Read ); + prop.CheckAccess( from ); + } + + if ( assembly == null ) + assembly = new AssemblyEmitter( "__dynamic", false ); + + m_Comparer = DistinctCompiler.Compile( assembly, baseType, m_Properties.ToArray() ); + } + + public override void Parse( Mobile from, string[] arguments, int offset, int size ) + { + if ( size < 1 ) + throw new Exception( "Invalid distinction syntax." ); + + int end = offset + size; + + while ( offset < end ) + { + string binding = arguments[offset++]; + + m_Properties.Add( new Property( binding ) ); + } + } + + public override void Filter( ArrayList list ) + { + if ( m_Comparer == null ) + throw new InvalidOperationException( "The extension must first be optimized." ); + + ArrayList copy = new ArrayList( list ); + + copy.Sort( m_Comparer ); + + list.Clear(); + + object last = null; + + for ( int i = 0; i < copy.Count; ++i ) + { + object obj = copy[i]; + + if ( last == null || m_Comparer.Compare( obj, last ) != 0 ) + { + list.Add( obj ); + last = obj; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Extensions/LimitExtension.cs b/Scripts/Commands/Generic/Extensions/LimitExtension.cs new file mode 100644 index 0000000..1dd5ef0 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/LimitExtension.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections; +using System.Text; + +namespace Server.Commands.Generic +{ + public sealed class LimitExtension : BaseExtension + { + public static ExtensionInfo ExtInfo = new ExtensionInfo( 80, "Limit", 1, delegate() { return new LimitExtension(); } ); + + public static void Initialize() + { + ExtensionInfo.Register( ExtInfo ); + } + + public override ExtensionInfo Info + { + get { return ExtInfo; } + } + + private int m_Limit; + + public int Limit + { + get { return m_Limit; } + } + + public LimitExtension() + { + } + + public override void Parse( Mobile from, string[] arguments, int offset, int size ) + { + m_Limit = Utility.ToInt32( arguments[offset] ); + + if ( m_Limit < 0 ) + throw new Exception( "Limit cannot be less than zero." ); + } + + public override void Filter( ArrayList list ) + { + if ( list.Count > m_Limit ) + list.RemoveRange( m_Limit, list.Count - m_Limit ); + } + } +} diff --git a/Scripts/Commands/Generic/Extensions/SortExtension.cs b/Scripts/Commands/Generic/Extensions/SortExtension.cs new file mode 100644 index 0000000..696a249 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/SortExtension.cs @@ -0,0 +1,109 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace Server.Commands.Generic +{ + public sealed class SortExtension : BaseExtension + { + public static ExtensionInfo ExtInfo = new ExtensionInfo( 40, "Order", -1, delegate() { return new SortExtension(); } ); + + public static void Initialize() + { + ExtensionInfo.Register( ExtInfo ); + } + + public override ExtensionInfo Info + { + get { return ExtInfo; } + } + + private List m_Orders; + + private IComparer m_Comparer; + + public SortExtension() + { + m_Orders = new List(); + } + + public override void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly ) + { + if ( baseType == null ) + throw new Exception( "The ordering extension may only be used in combination with an object conditional." ); + + foreach ( OrderInfo order in m_Orders ) + { + order.Property.BindTo( baseType, PropertyAccess.Read ); + order.Property.CheckAccess( from ); + } + + if ( assembly == null ) + assembly = new AssemblyEmitter( "__dynamic", false ); + + m_Comparer = SortCompiler.Compile( assembly, baseType, m_Orders.ToArray() ); + } + + public override void Parse( Mobile from, string[] arguments, int offset, int size ) + { + if ( size < 1 ) + throw new Exception( "Invalid ordering syntax." ); + + if ( Insensitive.Equals( arguments[offset], "by" ) ) + { + ++offset; + --size; + + if ( size < 1 ) + throw new Exception( "Invalid ordering syntax." ); + } + + int end = offset + size; + + while ( offset < end ) + { + string binding = arguments[offset++]; + + bool isAscending = true; + + if ( offset < end ) + { + string next = arguments[offset]; + + switch ( next.ToLower() ) + { + case "+": + case "up": + case "asc": + case "ascending": + isAscending = true; + ++offset; + break; + + case "-": + case "down": + case "desc": + case "descending": + isAscending = false; + ++offset; + break; + } + } + + Property property = new Property( binding ); + + m_Orders.Add( new OrderInfo( property, isAscending ) ); + } + } + + public override void Filter( ArrayList list ) + { + if ( m_Comparer == null ) + throw new InvalidOperationException( "The extension must first be optimized." ); + + list.Sort( m_Comparer ); + } + } +} diff --git a/Scripts/Commands/Generic/Extensions/WhereExtension.cs b/Scripts/Commands/Generic/Extensions/WhereExtension.cs new file mode 100644 index 0000000..b633443 --- /dev/null +++ b/Scripts/Commands/Generic/Extensions/WhereExtension.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Server.Commands; + +namespace Server.Commands.Generic +{ + public sealed class WhereExtension : BaseExtension + { + public static ExtensionInfo ExtInfo = new ExtensionInfo( 20, "Where", -1, delegate() { return new WhereExtension(); } ); + + public static void Initialize() + { + ExtensionInfo.Register( ExtInfo ); + } + + public override ExtensionInfo Info + { + get { return ExtInfo; } + } + + private ObjectConditional m_Conditional; + + public ObjectConditional Conditional + { + get { return m_Conditional; } + } + + public WhereExtension() + { + } + + public override void Optimize( Mobile from, Type baseType, ref AssemblyEmitter assembly ) + { + if ( baseType == null ) + throw new InvalidOperationException( "Insanity." ); + + m_Conditional.Compile( ref assembly ); + } + + public override void Parse( Mobile from, string[] arguments, int offset, int size ) + { + if ( size < 1 ) + throw new Exception( "Invalid condition syntax." ); + + m_Conditional = ObjectConditional.ParseDirect( from, arguments, offset, size ); + } + + public override bool IsValid( object obj ) + { + return m_Conditional.CheckCondition( obj ); + } + } +} diff --git a/Scripts/Commands/Generic/Implementors/AreaCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/AreaCommandImplementor.cs new file mode 100644 index 0000000..599c53e --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/AreaCommandImplementor.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Commands.Generic +{ + public class AreaCommandImplementor : BaseCommandImplementor + { + private static AreaCommandImplementor m_Instance; + + public static AreaCommandImplementor Instance + { + get { return m_Instance; } + } + + public AreaCommandImplementor() + { + Accessors = new string[]{ "Area", "Group" }; + SupportRequirement = CommandSupport.Area; + SupportsConditionals = true; + AccessLevel = AccessLevel.GameMaster; + Usage = "Area [condition]"; + Description = "Invokes the command on all appropriate objects in a targeted area. Optional condition arguments can further restrict the set of objects."; + + m_Instance = this; + } + + public override void Process( Mobile from, BaseCommand command, string[] args ) + { + BoundingBoxPicker.Begin( from, new BoundingBoxCallback( OnTarget ), new object[]{ command, args } ); + } + + public void OnTarget( Mobile from, Map map, Point3D start, Point3D end, object state ) + { + try + { + object[] states = (object[])state; + BaseCommand command = (BaseCommand)states[0]; + string[] args = (string[])states[1]; + + Rectangle2D rect = new Rectangle2D( start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1 ); + + Extensions ext = Extensions.Parse( from, ref args ); + + bool items, mobiles; + + if (!CheckObjectTypes(from, command, ext, out items, out mobiles)) + return; + + IPooledEnumerable eable; + + if ( items && mobiles ) + eable = map.GetObjectsInBounds( rect ); + else if ( items ) + eable = map.GetItemsInBounds( rect ); + else if ( mobiles ) + eable = map.GetMobilesInBounds( rect ); + else + return; + + ArrayList objs = new ArrayList(); + + foreach ( object obj in eable ) + { + if ( mobiles && obj is Mobile && !BaseCommand.IsAccessible( from, obj ) ) + continue; + + if ( ext.IsValid( obj ) ) + objs.Add( obj ); + } + + eable.Free(); + + ext.Filter( objs ); + + RunCommand( from, objs, command, args ); + } + catch ( Exception ex ) + { + from.SendMessage( ex.Message ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs new file mode 100644 index 0000000..aee896c --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs @@ -0,0 +1,344 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Server; + +namespace Server.Commands.Generic +{ + [Flags] + public enum CommandSupport + { + Single = 0x0001, + Global = 0x0002, + Online = 0x0004, + Multi = 0x0008, + Area = 0x0010, + Self = 0x0020, + Region = 0x0040, + Contained = 0x0080, + IPAddress = 0x0100, + + All = Single | Global | Online | Multi | Area | Self | Region | Contained | IPAddress, + AllMobiles = All & ~Contained, + AllNPCs = All & ~(IPAddress | Online | Self | Contained), + AllItems = All & ~(IPAddress | Online | Self | Region), + + Simple = Single | Multi, + Complex = Global | Online | Area | Region | Contained | IPAddress + } + + public abstract class BaseCommandImplementor + { + public static void RegisterImplementors() + { + Register(new RegionCommandImplementor()); + Register(new GlobalCommandImplementor()); + Register(new OnlineCommandImplementor()); + Register(new SingleCommandImplementor()); + Register(new SerialCommandImplementor()); + Register(new MultiCommandImplementor()); + Register(new AreaCommandImplementor()); + Register(new SelfCommandImplementor()); + Register(new ContainedCommandImplementor()); + Register(new IPAddressCommandImplementor()); + + Register(new RangeCommandImplementor()); + Register(new ScreenCommandImplementor()); + Register(new FacetCommandImplementor()); + } + + private string[] m_Accessors; + private AccessLevel m_AccessLevel; + private CommandSupport m_SupportRequirement; + private Dictionary m_Commands; + private string m_Usage; + private string m_Description; + private bool m_SupportsConditionals; + + public bool SupportsConditionals + { + get { return m_SupportsConditionals; } + set { m_SupportsConditionals = value; } + } + + public string[] Accessors + { + get { return m_Accessors; } + set { m_Accessors = value; } + } + + public string Usage + { + get { return m_Usage; } + set { m_Usage = value; } + } + + public string Description + { + get { return m_Description; } + set { m_Description = value; } + } + + public AccessLevel AccessLevel + { + get { return m_AccessLevel; } + set { m_AccessLevel = value; } + } + + public CommandSupport SupportRequirement + { + get { return m_SupportRequirement; } + set { m_SupportRequirement = value; } + } + + public Dictionary Commands + { + get { return m_Commands; } + } + + public BaseCommandImplementor() + { + m_Commands = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + public virtual void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj) + { + obj = null; + } + + public virtual void Register(BaseCommand command) + { + for (int i = 0; i < command.Commands.Length; ++i) + m_Commands[command.Commands[i]] = command; + } + + public bool CheckObjectTypes(Mobile from, BaseCommand command, Extensions ext, out bool items, out bool mobiles) + { + items = mobiles = false; + + ObjectConditional cond = ObjectConditional.Empty; + + foreach (BaseExtension check in ext) + { + if (check is WhereExtension) + { + cond = (check as WhereExtension).Conditional; + + break; + } + } + + bool condIsItem = cond.IsItem; + bool condIsMobile = cond.IsMobile; + + switch (command.ObjectTypes) + { + case ObjectTypes.All: + case ObjectTypes.Both: + { + if (condIsItem) + items = true; + + if (condIsMobile) + mobiles = true; + + break; + } + case ObjectTypes.Items: + { + if (condIsItem) + { + items = true; + } + else if (condIsMobile) + { + from.SendMessage("You may not use a mobile type condition for this command."); + return false; + } + + break; + } + case ObjectTypes.Mobiles: + { + if (condIsMobile) + { + mobiles = true; + } + else if (condIsItem) + { + from.SendMessage("You may not use an item type condition for this command."); + return false; + } + + break; + } + } + + return true; + } + + public void RunCommand(Mobile from, BaseCommand command, string[] args) + { + try + { + object obj = null; + + Compile(from, command, ref args, ref obj); + + RunCommand(from, obj, command, args); + } + catch (Exception ex) + { + from.SendMessage(ex.Message); + } + } + + public string GenerateArgString(string[] args) + { + if (args.Length == 0) + return ""; + + // NOTE: this does not preserve the case where quotation marks are used on a single word + + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < args.Length; ++i) + { + if (i > 0) + sb.Append(' '); + + if (args[i].IndexOf(' ') >= 0) + { + sb.Append('"'); + sb.Append(args[i]); + sb.Append('"'); + } + else + { + sb.Append(args[i]); + } + } + + return sb.ToString(); + } + + public void RunCommand(Mobile from, object obj, BaseCommand command, string[] args) + { + // try + // { + CommandEventArgs e = new CommandEventArgs(from, command.Commands[0], GenerateArgString(args), args); + + if (!command.ValidateArgs(this, e)) + return; + + bool flushToLog = false; + + if (obj is ArrayList) + { + ArrayList list = (ArrayList)obj; + + if (list.Count > 20) + CommandLogging.Enabled = false; + else if (list.Count == 0) + command.LogFailure("Nothing was found to use this command on."); + + command.ExecuteList(e, list); + + if (list.Count > 20) + { + flushToLog = true; + CommandLogging.Enabled = true; + } + } + else if (obj != null) + { + if (command.ListOptimized) + { + ArrayList list = new ArrayList(); + list.Add(obj); + command.ExecuteList(e, list); + } + else + { + command.Execute(e, obj); + } + } + + command.Flush(from, flushToLog); + // } + // catch ( Exception ex ) + // { + // from.SendMessage( ex.Message ); + // } + } + + public virtual void Process(Mobile from, BaseCommand command, string[] args) + { + RunCommand(from, command, args); + } + + public virtual void Execute(CommandEventArgs e) + { + if (e.Length >= 1) + { + BaseCommand command = null; + m_Commands.TryGetValue(e.GetString(0), out command); + + if (command == null) + { + e.Mobile.SendMessage("That is either an invalid command name or one that does not support this modifier."); + } + else if (e.Mobile.AccessLevel < command.AccessLevel) + { + e.Mobile.SendMessage("You do not have access to that command."); + } + else + { + string[] oldArgs = e.Arguments; + string[] args = new string[oldArgs.Length - 1]; + + for (int i = 0; i < args.Length; ++i) + args[i] = oldArgs[i + 1]; + + Process(e.Mobile, command, args); + } + } + else + { + e.Mobile.SendMessage("You must supply a command name."); + } + } + + public void Register() + { + if (m_Accessors == null) + return; + + for (int i = 0; i < m_Accessors.Length; ++i) + CommandSystem.Register(m_Accessors[i], m_AccessLevel, new CommandEventHandler(Execute)); + } + + public static void Register(BaseCommandImplementor impl) + { + m_Implementors.Add(impl); + impl.Register(); + } + + private static List m_Implementors; + + public static List Implementors + { + get + { + if (m_Implementors == null) + { + m_Implementors = new List(); + RegisterImplementors(); + } + + return m_Implementors; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs new file mode 100644 index 0000000..1895a74 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/ContainedCommandImplementor.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Commands.Generic +{ + public class ContainedCommandImplementor : BaseCommandImplementor + { + public ContainedCommandImplementor() + { + Accessors = new string[]{ "Contained" }; + SupportRequirement = CommandSupport.Contained; + AccessLevel = AccessLevel.GameMaster; + Usage = "Contained [condition]"; + Description = "Invokes the command on all child items in a targeted container. Optional condition arguments can further restrict the set of objects."; + } + + public override void Process( Mobile from, BaseCommand command, string[] args ) + { + if ( command.ValidateArgs( this, new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args ) ) ) + from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } ); + } + + public void OnTarget( Mobile from, object targeted, object state ) + { + if ( !BaseCommand.IsAccessible( from, targeted ) ) + { + from.SendMessage( "That is not accessible." ); + return; + } + + object[] states = (object[])state; + BaseCommand command = (BaseCommand)states[0]; + string[] args = (string[])states[1]; + + if ( command.ObjectTypes == ObjectTypes.Mobiles ) + return; // sanity check + + if ( !(targeted is Container) ) + { + from.SendMessage( "That is not a container." ); + } + else + { + try + { + Extensions ext = Extensions.Parse( from, ref args ); + + bool items, mobiles; + + if (!CheckObjectTypes(from, command, ext, out items, out mobiles)) + return; + + if ( !items ) + { + from.SendMessage( "This command only works on items." ); + return; + } + + Container cont = (Container)targeted; + + Item[] found = cont.FindItemsByType( typeof( Item ), true ); + + ArrayList list = new ArrayList(); + + for ( int i = 0; i < found.Length; ++i ) + { + if ( ext.IsValid( found[i] ) ) + list.Add( found[i] ); + } + + ext.Filter( list ); + + RunCommand( from, list, command, args ); + } + catch ( Exception e ) + { + from.SendMessage( e.Message ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/FacetCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/FacetCommandImplementor.cs new file mode 100644 index 0000000..cfba9aa --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/FacetCommandImplementor.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Commands.Generic +{ + public class FacetCommandImplementor : BaseCommandImplementor + { + public FacetCommandImplementor() + { + Accessors = new string[]{ "Facet" }; + SupportRequirement = CommandSupport.Area; + SupportsConditionals = true; + AccessLevel = AccessLevel.GameMaster; + Usage = "Facet [condition]"; + Description = "Invokes the command on all appropriate objects within your facet's map bounds. Optional condition arguments can further restrict the set of objects."; + } + + public override void Process( Mobile from, BaseCommand command, string[] args ) + { + AreaCommandImplementor impl = AreaCommandImplementor.Instance; + + if ( impl == null ) + return; + + Map map = from.Map; + + if ( map == null || map == Map.Internal ) + return; + + impl.OnTarget( from, map, Point3D.Zero, new Point3D( map.Width - 1, map.Height - 1, 0 ), new object[] { command, args } ); + } + } +} diff --git a/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs new file mode 100644 index 0000000..c63f296 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/GlobalCommandImplementor.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Commands.Generic +{ + public class GlobalCommandImplementor : BaseCommandImplementor + { + public GlobalCommandImplementor() + { + Accessors = new string[]{ "Global" }; + SupportRequirement = CommandSupport.Global; + SupportsConditionals = true; + AccessLevel = AccessLevel.Administrator; + Usage = "Global [condition]"; + Description = "Invokes the command on all appropriate objects in the world. Optional condition arguments can further restrict the set of objects."; + } + + public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj ) + { + try + { + Extensions ext = Extensions.Parse( from, ref args ); + + bool items, mobiles; + + if (!CheckObjectTypes(from, command, ext, out items, out mobiles)) + return; + + ArrayList list = new ArrayList(); + + if ( items ) + { + foreach ( Item item in World.Items.Values ) + { + if ( ext.IsValid( item ) ) + list.Add( item ); + } + } + + if ( mobiles ) + { + foreach ( Mobile mob in World.Mobiles.Values ) + { + if ( ext.IsValid( mob ) ) + list.Add( mob ); + } + } + + ext.Filter( list ); + + obj = list; + } + catch ( Exception ex ) + { + from.SendMessage( ex.Message ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/IPAdressCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/IPAdressCommandImplementor.cs new file mode 100644 index 0000000..8364a52 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/IPAdressCommandImplementor.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; +using Server; +using Server.Network; + +namespace Server.Commands.Generic +{ + public class IPAddressCommandImplementor : BaseCommandImplementor + { + public IPAddressCommandImplementor() + { + Accessors = new string[] { "IPAddress" }; + SupportRequirement = CommandSupport.IPAddress; + SupportsConditionals = true; + AccessLevel = AccessLevel.Administrator; + Usage = "IPAddress [condition]"; + Description = "Invokes the command on one mobile from each IP address that is logged in. Optional condition arguments can further restrict the set of objects."; + } + + public override void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj) + { + try + { + Extensions ext = Extensions.Parse(from, ref args); + + bool items, mobiles; + + if (!CheckObjectTypes(from, command, ext, out items, out mobiles)) + return; + + if (!mobiles) // sanity check + { + command.LogFailure("This command does not support items."); + return; + } + + ArrayList list = new ArrayList(); + ArrayList addresses = new ArrayList(); + + System.Collections.Generic.List states = NetState.Instances; + + for (int i = 0; i < states.Count; ++i) + { + NetState ns = (NetState)states[i]; + Mobile mob = ns.Mobile; + + if (mob != null && !addresses.Contains(ns.Address) && ext.IsValid(mob)) + { + list.Add(mob); + addresses.Add(ns.Address); + } + } + + ext.Filter(list); + + obj = list; + } + catch (Exception ex) + { + from.SendMessage(ex.Message); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/MultiCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/MultiCommandImplementor.cs new file mode 100644 index 0000000..bb53c01 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/MultiCommandImplementor.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Server.Commands.Generic +{ + public class MultiCommandImplementor : BaseCommandImplementor + { + public MultiCommandImplementor() + { + Accessors = new string[]{ "Multi", "m" }; + SupportRequirement = CommandSupport.Multi; + AccessLevel = AccessLevel.Counselor; + Usage = "Multi "; + Description = "Invokes the command on multiple targeted objects."; + } + + public override void Process( Mobile from, BaseCommand command, string[] args ) + { + if ( command.ValidateArgs( this, new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args ) ) ) + from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } ); + } + + public void OnTarget( Mobile from, object targeted, object state ) + { + object[] states = (object[])state; + BaseCommand command = (BaseCommand)states[0]; + string[] args = (string[])states[1]; + + if ( !BaseCommand.IsAccessible( from, targeted ) ) + { + from.SendMessage( "That is not accessible." ); + from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } ); + return; + } + + switch ( command.ObjectTypes ) + { + case ObjectTypes.Both: + { + if ( !(targeted is Item) && !(targeted is Mobile) ) + { + from.SendMessage( "This command does not work on that." ); + return; + } + + break; + } + case ObjectTypes.Items: + { + if ( !(targeted is Item) ) + { + from.SendMessage( "This command only works on items." ); + return; + } + + break; + } + case ObjectTypes.Mobiles: + { + if ( !(targeted is Mobile) ) + { + from.SendMessage( "This command only works on mobiles." ); + return; + } + + break; + } + } + + RunCommand( from, targeted, command, args ); + + from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/ObjectConditional.cs b/Scripts/Commands/Generic/Implementors/ObjectConditional.cs new file mode 100644 index 0000000..c8a5504 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/ObjectConditional.cs @@ -0,0 +1,266 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Targeting; +using CPA = Server.CommandPropertyAttribute; + +namespace Server.Commands.Generic +{ + public sealed class ObjectConditional + { + private static readonly Type typeofItem = typeof( Item ); + private static readonly Type typeofMobile = typeof( Mobile ); + + private Type m_ObjectType; + + private ICondition[][] m_Conditions; + + private IConditional[] m_Conditionals; + + public Type Type + { + get { return m_ObjectType; } + } + + public bool IsItem + { + get { return ( m_ObjectType == null || m_ObjectType == typeofItem || m_ObjectType.IsSubclassOf( typeofItem ) ); } + } + + public bool IsMobile + { + get { return ( m_ObjectType == null || m_ObjectType == typeofMobile || m_ObjectType.IsSubclassOf( typeofMobile ) ); } + } + + public static readonly ObjectConditional Empty = new ObjectConditional( null, null ); + + public bool HasCompiled + { + get { return ( m_Conditionals != null ); } + } + + public void Compile( ref AssemblyEmitter emitter ) + { + if ( emitter == null ) + emitter = new AssemblyEmitter( "__dynamic", false ); + + m_Conditionals = new IConditional[m_Conditions.Length]; + + for ( int i = 0; i < m_Conditionals.Length; ++i ) + m_Conditionals[i] = ConditionalCompiler.Compile( emitter, m_ObjectType, m_Conditions[i], i ); + } + + public bool CheckCondition( object obj ) + { + if ( m_ObjectType == null ) + return true; // null type means no condition + + if ( !HasCompiled ) + { + AssemblyEmitter emitter = null; + + Compile( ref emitter ); + } + + for ( int i = 0; i < m_Conditionals.Length; ++i ) + { + if ( m_Conditionals[i].Verify( obj ) ) + return true; + } + + return false; // all conditions false + } + + public static ObjectConditional Parse( Mobile from, ref string[] args ) + { + string[] conditionArgs = null; + + for ( int i = 0; i < args.Length; ++i ) + { + if ( Insensitive.Equals( args[i], "where" ) ) + { + string[] origArgs = args; + + args = new string[i]; + + for ( int j = 0; j < args.Length; ++j ) + args[j] = origArgs[j]; + + conditionArgs = new string[origArgs.Length - i - 1]; + + for ( int j = 0; j < conditionArgs.Length; ++j ) + conditionArgs[j] = origArgs[i + j + 1]; + + break; + } + } + + return ParseDirect( from, conditionArgs, 0, conditionArgs.Length ); + } + + public static ObjectConditional ParseDirect( Mobile from, string[] args, int offset, int size ) + { + if ( args == null || size == 0 ) + return ObjectConditional.Empty; + + int index = 0; + + Type objectType = ScriptCompiler.FindTypeByName( args[offset + index], true ); + + if ( objectType == null ) + throw new Exception( String.Format( "No type with that name ({0}) was found.", args[offset + index] ) ); + + ++index; + + List conditions = new List(); + List current = new List(); + + current.Add( TypeCondition.Default ); + + while ( index < size ) + { + string cur = args[offset + index]; + + bool inverse = false; + + if ( Insensitive.Equals( cur, "not" ) || cur == "!" ) + { + inverse = true; + ++index; + + if ( index >= size ) + throw new Exception( "Improperly formatted object conditional." ); + } + else if ( Insensitive.Equals( cur, "or" ) || cur == "||" ) + { + if ( current.Count > 1 ) + { + conditions.Add( current.ToArray() ); + + current.Clear(); + current.Add( TypeCondition.Default ); + } + + ++index; + + continue; + } + + string binding = args[offset + index]; + index++; + + if ( index >= size ) + throw new Exception( "Improperly formatted object conditional." ); + + string oper = args[offset + index]; + index++; + + if ( index >= size ) + throw new Exception( "Improperly formatted object conditional." ); + + string val = args[offset + index]; + index++; + + Property prop = new Property( binding ); + + prop.BindTo( objectType, PropertyAccess.Read ); + prop.CheckAccess( from ); + + ICondition condition = null; + + switch ( oper ) + { + #region Equality + case "=": + case "==": + case "is": + condition = new ComparisonCondition( prop, inverse, ComparisonOperator.Equal, val ); + break; + + case "!=": + condition = new ComparisonCondition( prop, inverse, ComparisonOperator.NotEqual, val ); + break; + #endregion + + #region Relational + case ">": + condition = new ComparisonCondition( prop, inverse, ComparisonOperator.Greater, val ); + break; + + case "<": + condition = new ComparisonCondition( prop, inverse, ComparisonOperator.Lesser, val ); + break; + + case ">=": + condition = new ComparisonCondition( prop, inverse, ComparisonOperator.GreaterEqual, val ); + break; + + case "<=": + condition = new ComparisonCondition( prop, inverse, ComparisonOperator.LesserEqual, val ); + break; + #endregion + + #region Strings + case "==~": + case "~==": + case "=~": + case "~=": + case "is~": + case "~is": + condition = new StringCondition( prop, inverse, StringOperator.Equal, val, true ); + break; + + case "!=~": + case "~!=": + condition = new StringCondition( prop, inverse, StringOperator.NotEqual, val, true ); + break; + + case "starts": + condition = new StringCondition( prop, inverse, StringOperator.StartsWith, val, false ); + break; + + case "starts~": + case "~starts": + condition = new StringCondition( prop, inverse, StringOperator.StartsWith, val, true ); + break; + + case "ends": + condition = new StringCondition( prop, inverse, StringOperator.EndsWith, val, false ); + break; + + case "ends~": + case "~ends": + condition = new StringCondition( prop, inverse, StringOperator.EndsWith, val, true ); + break; + + case "contains": + condition = new StringCondition( prop, inverse, StringOperator.Contains, val, false ); + break; + + case "contains~": + case "~contains": + condition = new StringCondition( prop, inverse, StringOperator.Contains, val, true ); + break; + #endregion + } + + if ( condition == null ) + throw new InvalidOperationException( String.Format( "Unrecognized operator (\"{0}\").", oper ) ); + + current.Add( condition ); + } + + conditions.Add( current.ToArray() ); + + return new ObjectConditional( objectType, conditions.ToArray() ); + } + + public ObjectConditional( Type objectType, ICondition[][] conditions ) + { + m_ObjectType = objectType; + m_Conditions = conditions; + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs new file mode 100644 index 0000000..88b137d --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/OnlineCommandImplementor.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; + +namespace Server.Commands.Generic +{ + public class OnlineCommandImplementor : BaseCommandImplementor + { + public OnlineCommandImplementor() + { + Accessors = new string[]{ "Online" }; + SupportRequirement = CommandSupport.Online; + SupportsConditionals = true; + AccessLevel = AccessLevel.GameMaster; + Usage = "Online [condition]"; + Description = "Invokes the command on all mobiles that are currently logged in. Optional condition arguments can further restrict the set of objects."; + } + + public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj ) + { + try + { + Extensions ext = Extensions.Parse( from, ref args ); + + bool items, mobiles; + + if (!CheckObjectTypes(from, command, ext, out items, out mobiles)) + return; + + if (!mobiles) // sanity check + { + command.LogFailure("This command does not support items."); + return; + } + + ArrayList list = new ArrayList(); + + List states = NetState.Instances; + + for ( int i = 0; i < states.Count; ++i ) + { + NetState ns = states[i]; + Mobile mob = ns.Mobile; + + if ( mob == null ) + continue; + + if( !BaseCommand.IsAccessible( from, mob ) ) + continue; + + if ( ext.IsValid( mob ) ) + list.Add( mob ); + } + + ext.Filter( list ); + + obj = list; + } + catch ( Exception ex ) + { + from.SendMessage( ex.Message ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/RangeCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/RangeCommandImplementor.cs new file mode 100644 index 0000000..0e10f4c --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/RangeCommandImplementor.cs @@ -0,0 +1,86 @@ +using System; +using Server; + +namespace Server.Commands.Generic +{ + public class RangeCommandImplementor : BaseCommandImplementor + { + private static RangeCommandImplementor m_Instance; + + public static RangeCommandImplementor Instance + { + get { return m_Instance; } + } + + public RangeCommandImplementor() + { + Accessors = new string[]{ "Range" }; + SupportRequirement = CommandSupport.Area; + SupportsConditionals = true; + AccessLevel = AccessLevel.GameMaster; + Usage = "Range [condition]"; + Description = "Invokes the command on all appropriate objects within a specified range of you. Optional condition arguments can further restrict the set of objects."; + + m_Instance = this; + } + + public override void Execute( CommandEventArgs e ) + { + if ( e.Length >= 2 ) + { + int range = e.GetInt32( 0 ); + + if ( range < 0 ) + { + e.Mobile.SendMessage( "The range must not be negative." ); + } + else + { + BaseCommand command = null; + Commands.TryGetValue( e.GetString( 1 ), out command ); + + if ( command == null ) + { + e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier." ); + } + else if ( e.Mobile.AccessLevel < command.AccessLevel ) + { + e.Mobile.SendMessage( "You do not have access to that command." ); + } + else + { + string[] oldArgs = e.Arguments; + string[] args = new string[oldArgs.Length - 2]; + + for ( int i = 0; i < args.Length; ++i ) + args[i] = oldArgs[i + 2]; + + Process( range, e.Mobile, command, args ); + } + } + } + else + { + e.Mobile.SendMessage( "You must supply a range and a command name." ); + } + } + + public void Process( int range, Mobile from, BaseCommand command, string[] args ) + { + AreaCommandImplementor impl = AreaCommandImplementor.Instance; + + if ( impl == null ) + return; + + Map map = from.Map; + + if ( map == null || map == Map.Internal ) + return; + + Point3D start = new Point3D( from.X - range, from.Y - range, from.Z ); + Point3D end = new Point3D( from.X + range, from.Y + range, from.Z ); + + impl.OnTarget( from, map, start, end, new object[] { command, args } ); + } + } +} diff --git a/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs new file mode 100644 index 0000000..071dc90 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/RegionCommandImplementor.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Commands.Generic +{ + public class RegionCommandImplementor : BaseCommandImplementor + { + public RegionCommandImplementor() + { + Accessors = new string[]{ "Region" }; + SupportRequirement = CommandSupport.Region; + SupportsConditionals = true; + AccessLevel = AccessLevel.GameMaster; + Usage = "Region [condition]"; + Description = "Invokes the command on all appropriate mobiles in your current region. Optional condition arguments can further restrict the set of objects."; + } + + public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj ) + { + try + { + Extensions ext = Extensions.Parse( from, ref args ); + + bool items, mobiles; + + if (!CheckObjectTypes(from, command, ext, out items, out mobiles)) + return; + + Region reg = from.Region; + + ArrayList list = new ArrayList(); + + if ( mobiles ) + { + foreach ( Mobile mob in reg.GetMobiles() ) + { + if( !BaseCommand.IsAccessible( from, mob ) ) + continue; + + if ( ext.IsValid( mob ) ) + list.Add( mob ); + } + } + else + { + command.LogFailure( "This command does not support items." ); + return; + } + + ext.Filter( list ); + + obj = list; + } + catch ( Exception ex ) + { + from.SendMessage( ex.Message ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/ScreenCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/ScreenCommandImplementor.cs new file mode 100644 index 0000000..24c0d9f --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/ScreenCommandImplementor.cs @@ -0,0 +1,28 @@ +using System; +using Server; + +namespace Server.Commands.Generic +{ + public class ScreenCommandImplementor : BaseCommandImplementor + { + public ScreenCommandImplementor() + { + Accessors = new string[]{ "Screen" }; + SupportRequirement = CommandSupport.Area; + SupportsConditionals = true; + AccessLevel = AccessLevel.GameMaster; + Usage = "Screen [condition]"; + Description = "Invokes the command on all appropriate objects in your screen. Optional condition arguments can further restrict the set of objects."; + } + + public override void Process( Mobile from, BaseCommand command, string[] args ) + { + RangeCommandImplementor impl = RangeCommandImplementor.Instance; + + if ( impl == null ) + return; + + impl.Process( 18, from, command, args ); + } + } +} diff --git a/Scripts/Commands/Generic/Implementors/SelfCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/SelfCommandImplementor.cs new file mode 100644 index 0000000..5bd67bb --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/SelfCommandImplementor.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Server.Commands.Generic +{ + public class SelfCommandImplementor : BaseCommandImplementor + { + public SelfCommandImplementor() + { + Accessors = new string[]{ "Self" }; + SupportRequirement = CommandSupport.Self; + AccessLevel = AccessLevel.Counselor; + Usage = "Self "; + Description = "Invokes the command on the commanding player."; + } + + public override void Compile( Mobile from, BaseCommand command, ref string[] args, ref object obj ) + { + if ( command.ObjectTypes == ObjectTypes.Items ) + return; // sanity check + + obj = from; + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs new file mode 100644 index 0000000..06dc252 --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/SerialCommandImplementor.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Server.Commands.Generic +{ + public class SerialCommandImplementor : BaseCommandImplementor + { + public SerialCommandImplementor() + { + Accessors = new string[]{ "Serial" }; + SupportRequirement = CommandSupport.Single; + AccessLevel = AccessLevel.Counselor; + Usage = "Serial "; + Description = "Invokes the command on a single object by serial."; + } + + public override void Execute( CommandEventArgs e ) + { + if ( e.Length >= 2 ) + { + Serial serial = e.GetInt32( 0 ); + + object obj = null; + + if ( serial.IsItem ) + obj = World.FindItem( serial ); + else if ( serial.IsMobile ) + obj = World.FindMobile( serial ); + + if ( obj == null ) + { + e.Mobile.SendMessage( "That is not a valid serial." ); + } + else + { + BaseCommand command = null; + Commands.TryGetValue( e.GetString( 1 ), out command ); + + if ( command == null ) + { + e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier." ); + } + else if ( e.Mobile.AccessLevel < command.AccessLevel ) + { + e.Mobile.SendMessage( "You do not have access to that command." ); + } + else + { + switch (command.ObjectTypes) + { + case ObjectTypes.Both: + { + if (!(obj is Item) && !(obj is Mobile)) + { + e.Mobile.SendMessage("This command does not work on that."); + return; + } + + break; + } + case ObjectTypes.Items: + { + if (!(obj is Item)) + { + e.Mobile.SendMessage("This command only works on items."); + return; + } + + break; + } + case ObjectTypes.Mobiles: + { + if (!(obj is Mobile)) + { + e.Mobile.SendMessage("This command only works on mobiles."); + return; + } + + break; + } + } + string[] oldArgs = e.Arguments; + string[] args = new string[oldArgs.Length - 2]; + + for ( int i = 0; i < args.Length; ++i ) + args[i] = oldArgs[i + 2]; + + RunCommand( e.Mobile, obj, command, args ); + } + } + } + else + { + e.Mobile.SendMessage( "You must supply an object serial and a command name." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Generic/Implementors/SingleCommandImplementor.cs b/Scripts/Commands/Generic/Implementors/SingleCommandImplementor.cs new file mode 100644 index 0000000..0931a3d --- /dev/null +++ b/Scripts/Commands/Generic/Implementors/SingleCommandImplementor.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Server.Commands.Generic +{ + public class SingleCommandImplementor : BaseCommandImplementor + { + public SingleCommandImplementor() + { + Accessors = new string[]{ "Single" }; + SupportRequirement = CommandSupport.Single; + AccessLevel = AccessLevel.Counselor; + Usage = "Single "; + Description = "Invokes the command on a single targeted object. This is the same as just invoking the command directly."; + } + + public override void Register( BaseCommand command ) + { + base.Register( command ); + + for ( int i = 0; i < command.Commands.Length; ++i ) + CommandSystem.Register( command.Commands[i], command.AccessLevel, new CommandEventHandler( Redirect ) ); + } + + public void Redirect( CommandEventArgs e ) + { + BaseCommand command = null; + + Commands.TryGetValue( e.Command, out command ); + + if ( command == null ) + e.Mobile.SendMessage( "That is either an invalid command name or one that does not support this modifier." ); + else if ( e.Mobile.AccessLevel < command.AccessLevel ) + e.Mobile.SendMessage( "You do not have access to that command." ); + else if ( command.ValidateArgs( this, e ) ) + Process( e.Mobile, command, e.Arguments ); + } + + public override void Process( Mobile from, BaseCommand command, string[] args ) + { + if ( command.ValidateArgs( this, new CommandEventArgs( from, command.Commands[0], GenerateArgString( args ), args ) ) ) + from.BeginTarget( -1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback( OnTarget ), new object[]{ command, args } ); + } + + public void OnTarget( Mobile from, object targeted, object state ) + { + if ( !BaseCommand.IsAccessible( from, targeted ) ) + { + from.SendMessage( "That is not accessible." ); + return; + } + + object[] states = (object[])state; + BaseCommand command = (BaseCommand)states[0]; + string[] args = (string[])states[1]; + + switch ( command.ObjectTypes ) + { + case ObjectTypes.Both: + { + if ( !(targeted is Item) && !(targeted is Mobile) ) + { + from.SendMessage( "This command does not work on that." ); + return; + } + + break; + } + case ObjectTypes.Items: + { + if ( !(targeted is Item) ) + { + from.SendMessage( "This command only works on items." ); + return; + } + + break; + } + case ObjectTypes.Mobiles: + { + if ( !(targeted is Mobile) ) + { + from.SendMessage( "This command only works on mobiles." ); + return; + } + + break; + } + } + + RunCommand( from, targeted, command, args ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Handlers.cs b/Scripts/Commands/Handlers.cs new file mode 100644 index 0000000..d21433d --- /dev/null +++ b/Scripts/Commands/Handlers.cs @@ -0,0 +1,1019 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using Server; +using Server.Accounting; +using Server.Mobiles; +using Server.Items; +using Server.Menus; +using Server.Menus.Questions; +using Server.Menus.ItemLists; +using Server.Network; +using Server.Spells; +using Server.Targeting; +using Server.Targets; +using Server.Gumps; +using Server.Commands.Generic; + +namespace Server.Commands +{ + public class CommandHandlers + { + public static void Initialize() + { + CommandSystem.Prefix = "."; + + Register( "Go", AccessLevel.Counselor, new CommandEventHandler( Go_OnCommand ) ); + + Register( "DropHolding", AccessLevel.Counselor, new CommandEventHandler( DropHolding_OnCommand ) ); + + Register( "GetFollowers", AccessLevel.GameMaster, new CommandEventHandler( GetFollowers_OnCommand ) ); + + Register( "ClearFacet", AccessLevel.Administrator, new CommandEventHandler( ClearFacet_OnCommand ) ); + + Register( "Where", AccessLevel.Counselor, new CommandEventHandler( Where_OnCommand ) ); + + Register( "AutoPageNotify", AccessLevel.Counselor, new CommandEventHandler( APN_OnCommand ) ); + Register( "APN", AccessLevel.Counselor, new CommandEventHandler( APN_OnCommand ) ); + + Register( "Animate", AccessLevel.GameMaster, new CommandEventHandler( Animate_OnCommand ) ); + + Register( "Cast", AccessLevel.Counselor, new CommandEventHandler( Cast_OnCommand ) ); + + Register( "Stuck", AccessLevel.Counselor, new CommandEventHandler( Stuck_OnCommand ) ); + + Register( "Help", AccessLevel.Player, new CommandEventHandler( Help_OnCommand ) ); + + Register( "Save", AccessLevel.Administrator, new CommandEventHandler( Save_OnCommand ) ); + Register( "BackgroundSave", AccessLevel.Administrator, new CommandEventHandler( BackgroundSave_OnCommand ) ); + Register( "BGSave", AccessLevel.Administrator, new CommandEventHandler( BackgroundSave_OnCommand ) ); + Register( "SaveBG", AccessLevel.Administrator, new CommandEventHandler( BackgroundSave_OnCommand ) ); + + Register( "Move", AccessLevel.GameMaster, new CommandEventHandler( Move_OnCommand ) ); + Register( "Client", AccessLevel.Counselor, new CommandEventHandler( Client_OnCommand ) ); + + Register( "SMsg", AccessLevel.Counselor, new CommandEventHandler( StaffMessage_OnCommand ) ); + Register( "SM", AccessLevel.Counselor, new CommandEventHandler( StaffMessage_OnCommand ) ); + Register( "S", AccessLevel.Counselor, new CommandEventHandler( StaffMessage_OnCommand ) ); + + Register( "BCast", AccessLevel.GameMaster, new CommandEventHandler( BroadcastMessage_OnCommand ) ); + Register( "BC", AccessLevel.GameMaster, new CommandEventHandler( BroadcastMessage_OnCommand ) ); + Register( "B", AccessLevel.GameMaster, new CommandEventHandler( BroadcastMessage_OnCommand ) ); + + Register( "Bank", AccessLevel.GameMaster, new CommandEventHandler( Bank_OnCommand ) ); + + Register( "Echo", AccessLevel.Counselor, new CommandEventHandler( Echo_OnCommand ) ); + + Register( "Sound", AccessLevel.GameMaster, new CommandEventHandler( Sound_OnCommand ) ); + + Register( "ViewEquip", AccessLevel.GameMaster, new CommandEventHandler( ViewEquip_OnCommand ) ); + + Register( "Light", AccessLevel.Counselor, new CommandEventHandler( Light_OnCommand ) ); + Register( "Stats", AccessLevel.Counselor, new CommandEventHandler( Stats_OnCommand ) ); + + Register( "ReplaceBankers", AccessLevel.Administrator, new CommandEventHandler( ReplaceBankers_OnCommand ) ); + + Register( "SpeedBoost", AccessLevel.Counselor, new CommandEventHandler( SpeedBoost_OnCommand ) ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + CommandSystem.Register( command, access, handler ); + } + + [Usage( "SpeedBoost [true|false]" )] + [Description( "Enables a speed boost for the invoker. Disable with paramaters." )] + private static void SpeedBoost_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + + if ( e.Length <= 1 ) + { + if ( e.Length == 1 && !e.GetBoolean( 0 ) ) + { + from.Send( SpeedControl.Disable ); + from.SendMessage( "Speed boost has been disabled." ); + } + else + { + from.Send( SpeedControl.MountSpeed ); + from.SendMessage( "Speed boost has been enabled." ); + } + } + else + { + from.SendMessage( "Format: SpeedBoost [true|false]" ); + } + } + + [Usage( "Where" )] + [Description( "Tells the commanding player his coordinates, region, and facet." )] + public static void Where_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + Map map = from.Map; + + from.SendMessage( "You are at {0} {1} {2} in {3}.", from.X, from.Y, from.Z, map ); + + if ( map != null ) + { + Region reg = from.Region; + + if ( !reg.IsDefault ) + { + StringBuilder builder = new StringBuilder(); + + builder.Append( reg.ToString() ); + reg = reg.Parent; + + while ( reg != null ) + { + builder.Append( " <- " + reg.ToString() ); + reg = reg.Parent; + } + + from.SendMessage( "Your region is {0}.", builder.ToString() ); + } + } + } + + [Usage( "DropHolding" )] + [Description( "Drops the item, if any, that a targeted player is holding. The item is placed into their backpack, or if that's full, at their feet." )] + public static void DropHolding_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( DropHolding_OnTarget ) ); + e.Mobile.SendMessage( "Target the player to drop what they are holding." ); + } + + public static void DropHolding_OnTarget( Mobile from, object obj ) + { + if ( obj is Mobile && ((Mobile)obj).Player ) + { + Mobile targ = (Mobile)obj; + Item held = targ.Holding; + + if ( held == null ) + { + from.SendMessage( "They are not holding anything." ); + } + else + { + if ( from.AccessLevel == AccessLevel.Counselor ) + { + Engines.Help.PageEntry pe = Engines.Help.PageQueue.GetEntry( targ ); + + if ( pe == null || pe.Handler != from ) + { + if ( pe == null ) + from.SendMessage( "You may only use this command on someone who has paged you." ); + else + from.SendMessage( "You may only use this command if you are handling their help page." ); + + return; + } + } + + if ( targ.AddToBackpack( held ) ) + from.SendMessage( "The item they were holding has been placed into their backpack." ); + else + from.SendMessage( "The item they were holding has been placed at their feet." ); + + held.ClearBounce(); + + targ.Holding = null; + } + } + else + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( DropHolding_OnTarget ) ); + from.SendMessage( "That is not a player. Try again." ); + } + } + + public static void DeleteList_Callback( Mobile from, bool okay, object state ) + { + if ( okay ) + { + List list = (List)state; + + CommandLogging.WriteLine( from, "{0} {1} deleting {2} object{3}", from.AccessLevel, CommandLogging.Format( from ), list.Count, list.Count == 1 ? "" : "s" ); + + NetState.Pause(); + + for ( int i = 0; i < list.Count; ++i ) + list[i].Delete(); + + NetState.Resume(); + + from.SendMessage( "You have deleted {0} object{1}.", list.Count, list.Count == 1 ? "" : "s" ); + } + else + { + from.SendMessage( "You have chosen not to delete those objects." ); + } + } + + [Usage( "ClearFacet" )] + [Description( "Deletes all items and mobiles in your facet. Players and their inventory will not be deleted." )] + public static void ClearFacet_OnCommand( CommandEventArgs e ) + { + Map map = e.Mobile.Map; + + if ( map == null || map == Map.Internal ) + { + e.Mobile.SendMessage( "You may not run that command here." ); + return; + } + + List list = new List(); + + foreach ( Item item in World.Items.Values ) + if ( item.Map == map && item.Parent == null ) + list.Add( item ); + + foreach ( Mobile m in World.Mobiles.Values ) + if ( m.Map == map && !m.Player ) + list.Add( m ); + + if ( list.Count > 0 ) + { + CommandLogging.WriteLine( e.Mobile, "{0} {1} starting facet clear of {2} ({3} object{4})", e.Mobile.AccessLevel, CommandLogging.Format( e.Mobile ), map, list.Count, list.Count == 1 ? "" : "s" ); + + e.Mobile.SendGump( + new WarningGump( 1060635, 30720, + String.Format( "You are about to delete {0} object{1} from this facet. Do you really wish to continue?", + list.Count, list.Count == 1 ? "" : "s" ), + 0xFFC000, 360, 260, new WarningGumpCallback( DeleteList_Callback ), list ) ); + } + else + { + e.Mobile.SendMessage( "There were no objects found to delete." ); + } + } + + [Usage( "GetFollowers" )] + [Description( "Teleports all pets of a targeted player to your location." )] + public static void GetFollowers_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( GetFollowers_OnTarget ) ); + e.Mobile.SendMessage( "Target a player to get their pets." ); + } + + public static void GetFollowers_OnTarget( Mobile from, object obj ) + { + if ( obj is PlayerMobile ) + { + PlayerMobile master = (PlayerMobile)obj; + List pets = master.AllFollowers; + + if ( pets.Count > 0 ) + { + CommandLogging.WriteLine( from, "{0} {1} getting all followers of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( master ) ); + + from.SendMessage( "That player has {0} pet{1}.", pets.Count, pets.Count != 1 ? "s" : "" ); + + for ( int i = 0; i < pets.Count; ++i ) + { + Mobile pet = (Mobile)pets[i]; + + if ( pet is IMount ) + ((IMount)pet).Rider = null; // make sure it's dismounted + + pet.MoveToWorld( from.Location, from.Map ); + } + } + else + { + from.SendMessage( "There were no pets found for that player." ); + } + } + else if ( obj is Mobile && ((Mobile)obj).Player ) + { + Mobile master = (Mobile)obj; + ArrayList pets = new ArrayList(); + + foreach ( Mobile m in World.Mobiles.Values ) + { + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( (bc.Controlled && bc.ControlMaster == master) || (bc.Summoned && bc.SummonMaster == master) ) + pets.Add( bc ); + } + } + + if ( pets.Count > 0 ) + { + CommandLogging.WriteLine( from, "{0} {1} getting all followers of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( master ) ); + + from.SendMessage( "That player has {0} pet{1}.", pets.Count, pets.Count != 1 ? "s" : "" ); + + for ( int i = 0; i < pets.Count; ++i ) + { + Mobile pet = (Mobile)pets[i]; + + if ( pet is IMount ) + ((IMount)pet).Rider = null; // make sure it's dismounted + + pet.MoveToWorld( from.Location, from.Map ); + } + } + else + { + from.SendMessage( "There were no pets found for that player." ); + } + } + else + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( GetFollowers_OnTarget ) ); + from.SendMessage( "That is not a player. Try again." ); + } + } + + public static void ReplaceBankers_OnCommand( CommandEventArgs e ) + { + List list = new List(); + + foreach ( Mobile m in World.Mobiles.Values ) + if ( (m is Banker) && !(m is BaseCreature) ) + list.Add( m ); + + foreach ( Mobile m in list ) + { + Map map = m.Map; + + if ( map != null ) + { + bool hasBankerSpawner = false; + + foreach ( Item item in m.GetItemsInRange( 0 ) ) + { + if ( item is Spawner ) + { + Spawner spawner = (Spawner)item; + + for ( int i = 0; !hasBankerSpawner && i < spawner.SpawnNames.Count; ++i ) + hasBankerSpawner = Insensitive.Equals( (string)spawner.SpawnNames[i], "banker" ); + + if ( hasBankerSpawner ) + break; + } + } + + if ( !hasBankerSpawner ) + { + Spawner spawner = new Spawner( 1, 1, 5, 0, 4, "banker" ); + + spawner.MoveToWorld( m.Location, map ); + } + } + } + } + + private class ViewEqTarget : Target + { + public ViewEqTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !BaseCommand.IsAccessible( from, targeted ) ) + { + from.SendMessage( "That is not accessible." ); + return; + } + + if ( targeted is Mobile ) + from.SendMenu( new EquipMenu( from, (Mobile)targeted, GetEquip( (Mobile)targeted ) ) ); + } + + private static ItemListEntry[] GetEquip( Mobile m ) + { + ItemListEntry[] entries = new ItemListEntry[m.Items.Count]; + + for ( int i = 0; i < m.Items.Count; ++i ) + { + Item item = m.Items[i]; + + entries[i] = new ItemListEntry( String.Format( "{0}: {1}", item.Layer, item.GetType().Name ), item.ItemID, item.Hue ); + } + + return entries; + } + + private class EquipMenu : ItemListMenu + { + private Mobile m_Mobile; + + public EquipMenu( Mobile from, Mobile m, ItemListEntry[] entries ) : base( "Equipment", entries ) + { + m_Mobile = m; + + CommandLogging.WriteLine( from, "{0} {1} viewing equipment of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( m ) ); + } + + public override void OnResponse( NetState state, int index ) + { + if ( index >= 0 && index < m_Mobile.Items.Count ) + { + Item item = m_Mobile.Items[index]; + + state.Mobile.SendMenu( new EquipDetailsMenu( m_Mobile, item ) ); + } + } + + private class EquipDetailsMenu : QuestionMenu + { + private Mobile m_Mobile; + private Item m_Item; + + public EquipDetailsMenu( Mobile m, Item item ) : base( String.Format( "{0}: {1}", item.Layer, item.GetType().Name ), new string[]{"Move","Delete","Props"}) + { + m_Mobile = m; + m_Item = item; + } + + public override void OnCancel( NetState state ) + { + state.Mobile.SendMenu( new EquipMenu( state.Mobile, m_Mobile, ViewEqTarget.GetEquip( m_Mobile ) ) ); + } + + public override void OnResponse( NetState state, int index ) + { + if ( index == 0 ) + { + CommandLogging.WriteLine( state.Mobile, "{0} {1} moving equipment item {2} of {3}", state.Mobile.AccessLevel, CommandLogging.Format( state.Mobile ), CommandLogging.Format( m_Item ), CommandLogging.Format( m_Mobile ) ); + state.Mobile.Target = new MoveTarget( m_Item ); + } + else if ( index == 1 ) + { + CommandLogging.WriteLine( state.Mobile, "{0} {1} deleting equipment item {2} of {3}", state.Mobile.AccessLevel, CommandLogging.Format( state.Mobile ), CommandLogging.Format( m_Item ), CommandLogging.Format( m_Mobile ) ); + m_Item.Delete(); + } + else if ( index == 2 ) + { + CommandLogging.WriteLine( state.Mobile, "{0} {1} opening properties for equipment item {2} of {3}", state.Mobile.AccessLevel, CommandLogging.Format( state.Mobile ), CommandLogging.Format( m_Item ), CommandLogging.Format( m_Mobile ) ); + state.Mobile.SendGump( new PropertiesGump( state.Mobile, m_Item ) ); + } + } + } + } + } + + [Usage( "ViewEquip" )] + [Description( "Lists equipment of a targeted mobile. From the list you can move, delete, or open props." )] + public static void ViewEquip_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new ViewEqTarget(); + } + + [Usage( "Sound [toAll=true]" )] + [Description( "Plays a sound to players within 12 tiles of you. The (toAll) argument specifies to everyone, or just those who can see you." )] + public static void Sound_OnCommand( CommandEventArgs e ) + { + if ( e.Length == 1 ) + PlaySound( e.Mobile, e.GetInt32( 0 ), true ); + else if ( e.Length == 2 ) + PlaySound( e.Mobile, e.GetInt32( 0 ), e.GetBoolean( 1 ) ); + else + e.Mobile.SendMessage( "Format: Sound [toAll]" ); + } + + private static void PlaySound( Mobile m, int index, bool toAll ) + { + Map map = m.Map; + + if ( map == null ) + return; + + CommandLogging.WriteLine( m, "{0} {1} playing sound {2} (toAll={3})", m.AccessLevel, CommandLogging.Format( m ), index, toAll ); + + Packet p = new PlaySound( index, m.Location ); + + p.Acquire(); + + foreach ( NetState state in m.GetClientsInRange( 12 ) ) + { + if ( toAll || state.Mobile.CanSee( m ) ) + state.Send( p ); + } + + p.Release(); + } + + private class BankTarget : Target + { + public BankTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + Mobile m = (Mobile)targeted; + + BankBox box = ( m.Player ? m.BankBox : m.FindBankNoCreate() ); + + if ( box != null ) + { + CommandLogging.WriteLine( from, "{0} {1} opening bank box of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targeted ) ); + + if ( from == targeted ) + box.Open(); + else + box.DisplayTo( from ); + } + else + { + from.SendMessage( "They have no bank box." ); + } + } + } + } + + [Usage( "Echo " )] + [Description( "Relays (text) as a system message." )] + public static void Echo_OnCommand( CommandEventArgs e ) + { + string toEcho = e.ArgString.Trim(); + + if ( toEcho.Length > 0 ) + e.Mobile.SendMessage( toEcho ); + else + e.Mobile.SendMessage( "Format: Echo \"\"" ); + } + + [Usage( "Bank" )] + [Description( "Opens the bank box of a given target." )] + public static void Bank_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new BankTarget(); + } + + private class DismountTarget : Target + { + public DismountTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + CommandLogging.WriteLine( from, "{0} {1} dismounting {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targeted ) ); + + Mobile targ = (Mobile)targeted; + + for ( int i = 0; i < targ.Items.Count; ++i ) + { + Item item = targ.Items[i]; + + if ( item is IMountItem ) + { + IMount mount = ((IMountItem)item).Mount; + + if ( mount != null ) + mount.Rider = null; + + if ( targ.Items.IndexOf( item ) == -1 ) + --i; + } + } + + for ( int i = 0; i < targ.Items.Count; ++i ) + { + Item item = targ.Items[i]; + + if ( item.Layer == Layer.Mount ) + { + item.Delete(); + --i; + } + } + } + } + } + + private class ClientTarget : Target + { + public ClientTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + Mobile targ = (Mobile)targeted; + + if ( targ.NetState != null ) + { + CommandLogging.WriteLine( from, "{0} {1} opening client menu of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targeted ) ); + from.SendGump( new ClientGump( from, targ.NetState ) ); + } + } + } + } + + [Usage( "Client" )] + [Description( "Opens the client gump menu for a given player." )] + private static void Client_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new ClientTarget(); + } + + [Usage( "Move" )] + [Description( "Repositions a targeted item or mobile." )] + private static void Move_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new PickMoveTarget(); + } + + [Usage( "Save" )] + [Description( "Saves the world." )] + private static void Save_OnCommand( CommandEventArgs e ) + { + Misc.AutoSave.Save(); + } + + [Usage("BackgroundSave")] + [Aliases("BGSave", "SaveBG")] + [Description("Saves the world, writing to the disk in the background")] + private static void BackgroundSave_OnCommand(CommandEventArgs e) + { + Misc.AutoSave.Save( true ); + } + + private static bool FixMap( ref Map map, ref Point3D loc, Item item ) + { + if ( map == null || map == Map.Internal ) + { + Mobile m = item.RootParent as Mobile; + + return ( m != null && FixMap( ref map, ref loc, m ) ); + } + + return true; + } + + private static bool FixMap( ref Map map, ref Point3D loc, Mobile m ) + { + if ( map == null || map == Map.Internal ) + { + map = m.LogoutMap; + loc = m.LogoutLocation; + } + + return ( map != null && map != Map.Internal ); + } + + [Usage( "Go [name | serial | (x y [z]) | (deg min (N | S) deg min (E | W))]" )] + [Description( "With no arguments, this command brings up the go menu. With one argument, (name), you are moved to that regions \"go location.\" Or, if a numerical value is specified for one argument, (serial), you are moved to that object. Two or three arguments, (x y [z]), will move your character to that location. When six arguments are specified, (deg min (N | S) deg min (E | W)), your character will go to an approximate of those sextant coordinates." )] + private static void Go_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + + if ( e.Length == 0 ) + { + GoGump.DisplayTo( from ); + return; + } + + if ( e.Length == 1 ) + { + try + { + int ser = e.GetInt32( 0 ); + + IEntity ent = World.FindEntity( ser ); + + if ( ent is Item ) + { + Item item = (Item)ent; + + Map map = item.Map; + Point3D loc = item.GetWorldLocation(); + + Mobile owner = item.RootParent as Mobile; + + if( owner != null && (owner.Map != null && owner.Map != Map.Internal) && !BaseCommand.IsAccessible( from, owner ) /* !from.CanSee( owner )*/ ) + { + from.SendMessage( "You can not go to what you can not see." ); + return; + } + else if ( owner != null && (owner.Map == null || owner.Map == Map.Internal) && owner.Hidden && owner.AccessLevel >= from.AccessLevel ) + { + from.SendMessage( "You can not go to what you can not see." ); + return; + } + else if ( !FixMap( ref map, ref loc, item ) ) + { + from.SendMessage( "That is an internal item and you cannot go to it." ); + return; + } + + from.MoveToWorld( loc, map ); + + return; + } + else if ( ent is Mobile ) + { + Mobile m = (Mobile)ent; + + Map map = m.Map; + Point3D loc = m.Location; + + Mobile owner = m; + + if ( owner != null && (owner.Map != null && owner.Map != Map.Internal) && !BaseCommand.IsAccessible( from, owner ) /* !from.CanSee( owner )*/ ) + { + from.SendMessage( "You can not go to what you can not see." ); + return; + } + else if ( owner != null && (owner.Map == null || owner.Map == Map.Internal) && owner.Hidden && owner.AccessLevel >= from.AccessLevel ) + { + from.SendMessage( "You can not go to what you can not see." ); + return; + } + else if ( !FixMap( ref map, ref loc, m ) ) + { + from.SendMessage( "That is an internal mobile and you cannot go to it." ); + return; + } + + from.MoveToWorld( loc, map ); + + return; + } + else + { + string name = e.GetString( 0 ); + Map map; + + for ( int i = 0; i < Map.AllMaps.Count; ++i ) + { + map = Map.AllMaps[i]; + + if ( map.MapIndex == 0x7F || map.MapIndex == 0xFF ) + continue; + + if ( Insensitive.Equals( name, map.Name ) ) + { + from.Map = map; + return; + } + } + + Dictionary list = from.Map.Regions; + + foreach( KeyValuePair kvp in list ) + { + Region r = kvp.Value; + + if ( Insensitive.Equals( r.Name, name ) ) + { + from.Location = new Point3D( r.GoLocation ); + return; + } + } + + for( int i = 0; i < Map.AllMaps.Count; ++i ) + { + Map m = Map.AllMaps[i]; + + if( m.MapIndex == 0x7F || m.MapIndex == 0xFF || from.Map == m ) + continue; + + foreach( Region r in m.Regions.Values ) + { + if( Insensitive.Equals( r.Name, name ) ) + { + from.MoveToWorld( r.GoLocation, m ); + return; + } + } + } + + if ( ser != 0 ) + from.SendMessage( "No object with that serial was found." ); + else + from.SendMessage( "No region with that name was found." ); + + return; + } + } + catch + { + } + + from.SendMessage( "Region name not found" ); + } + else if ( e.Length == 2 || e.Length == 3 ) + { + Map map = from.Map; + + if ( map != null ) + { + try + { + /* + * This to avoid being teleported to (0,0) if trying to teleport + * to a region with spaces in its name. + */ + int x = int.Parse( e.GetString( 0 ) ); + int y = int.Parse( e.GetString( 1 ) ); + int z = (e.Length == 3 ) ? int.Parse( e.GetString( 2 ) ) : map.GetAverageZ( x, y ); + + from.Location = new Point3D( x, y, z ); + } + catch + { + from.SendMessage( "Region name not found." ); + } + } + } + else if ( e.Length == 6 ) + { + Map map = from.Map; + + if ( map != null ) + { + Point3D p = Sextant.ReverseLookup( map, e.GetInt32( 3 ), e.GetInt32( 0 ), e.GetInt32( 4 ), e.GetInt32( 1 ), Insensitive.Equals( e.GetString( 5 ), "E" ), Insensitive.Equals( e.GetString( 2 ), "S" ) ); + + if ( p != Point3D.Zero ) + from.Location = p; + else + from.SendMessage( "Sextant reverse lookup failed." ); + } + } + else + { + from.SendMessage( "Format: Go [name | serial | (x y [z]) | (deg min (N | S) deg min (E | W)]" ); + } + } + + [Usage( "Help" )] + [Description( "Lists all available commands." )] + public static void Help_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + + List list = new List(); + + foreach ( CommandEntry entry in CommandSystem.Entries.Values ) + if ( m.AccessLevel >= entry.AccessLevel ) + list.Add( entry ); + + list.Sort(); + + StringBuilder sb = new StringBuilder(); + + if ( list.Count > 0 ) + sb.Append( list[0].Command ); + + for ( int i = 1; i < list.Count; ++i ) + { + string v = list[i].Command; + + if ( (sb.Length + 1 + v.Length) >= 256 ) + { + m.SendAsciiMessage( 0x482, sb.ToString() ); + sb = new StringBuilder(); + sb.Append( v ); + } + else + { + //sb.Append( ' ' ); + sb.Append(" ; "); // Scriptiz : d�limiteur + sb.Append( v ); + } + } + + if ( sb.Length > 0 ) + m.SendAsciiMessage( 0x482, sb.ToString() ); + } + + [Usage( "SMsg " )] + [Aliases( "S", "SM" )] + [Description( "Broadcasts a message to all online staff." )] + public static void StaffMessage_OnCommand( CommandEventArgs e ) + { + BroadcastMessage( AccessLevel.Counselor, e.Mobile.SpeechHue, String.Format( "[{0}] {1}", e.Mobile.Name, e.ArgString ) ); + } + + [Usage( "BCast " )] + [Aliases( "B", "BC" )] + [Description( "Broadcasts a message to everyone online." )] + public static void BroadcastMessage_OnCommand( CommandEventArgs e ) + { + BroadcastMessage( AccessLevel.Player, 0x482, String.Format( "Staff message from {0}:", e.Mobile.Name ) ); + BroadcastMessage( AccessLevel.Player, 0x482, e.ArgString ); + } + + public static void BroadcastMessage ( AccessLevel ac, int hue, string message ) + { + foreach ( NetState state in NetState.Instances ) + { + Mobile m = state.Mobile; + + if ( m != null && m.AccessLevel >= ac ) + m.SendMessage( hue, message ); + } + } + + [Usage( "AutoPageNotify" )] + [Aliases( "APN" )] + [Description( "Toggles your auto-page-notify status." )] + public static void APN_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + + m.AutoPageNotify = !m.AutoPageNotify; + + m.SendMessage( "Your auto-page-notify has been turned {0}.", m.AutoPageNotify ? "on" : "off" ); + } + + [Usage( "Animate " )] + [Description( "Makes your character do a specified animation." )] + public static void Animate_OnCommand( CommandEventArgs e ) + { + if ( e.Length == 6 ) + { + e.Mobile.Animate( e.GetInt32( 0 ), e.GetInt32( 1 ), e.GetInt32( 2 ), e.GetBoolean( 3 ), e.GetBoolean( 4 ), e.GetInt32( 5 ) ); + } + else + { + e.Mobile.SendMessage( "Format: Animate " ); + } + } + + [Usage( "Cast " )] + [Description( "Casts a spell by name." )] + public static void Cast_OnCommand( CommandEventArgs e ) + { + if ( e.Length == 1 ) + { + if ( !Multis.DesignContext.Check( e.Mobile ) ) + return; // They are customizing + + Spell spell = SpellRegistry.NewSpell( e.GetString( 0 ), e.Mobile, null ); + + if ( spell != null ) + spell.Cast(); + else + e.Mobile.SendMessage( "That spell was not found." ); + } + else + { + e.Mobile.SendMessage( "Format: Cast " ); + } + } + + private class StuckMenuTarget : Target + { + public StuckMenuTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + if( ((Mobile)targeted).AccessLevel >= from.AccessLevel && targeted != from ) + from.SendMessage( "You can't do that to someone with higher Accesslevel than you!" ); + else + from.SendGump( new StuckMenu( from, (Mobile) targeted, false ) ); + } + } + } + + [Usage( "Stuck" )] + [Description( "Opens a menu of towns, used for teleporting stuck mobiles." )] + public static void Stuck_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new StuckMenuTarget(); + } + + [Usage( "Light ")] + [Description( "Set your local lightlevel." )] + public static void Light_OnCommand( CommandEventArgs e ) + { + e.Mobile.LightLevel = e.GetInt32( 0 ); + } + + [Usage( "Stats")] + [Description( "View some stats about the server." )] + public static void Stats_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Open Connections: {0}", Network.NetState.Instances.Count ); + e.Mobile.SendMessage( "Mobiles: {0}", World.Mobiles.Count ); + e.Mobile.SendMessage( "Items: {0}", World.Items.Count ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/HelpInfo.cs b/Scripts/Commands/HelpInfo.cs new file mode 100644 index 0000000..ff131ad --- /dev/null +++ b/Scripts/Commands/HelpInfo.cs @@ -0,0 +1,422 @@ +using System; +using Server; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using Server.Gumps; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; +using CommandInfo=Server.Commands.Docs.DocCommandEntry; +using CommandInfoSorter=Server.Commands.Docs.CommandEntrySorter; + +namespace Server.Commands +{ + public class HelpInfo + { + + private static Dictionary m_HelpInfos = new Dictionary(); + private static List m_SortedHelpInfo = new List(); //No need for SortedList cause it's only sorted once at creation... + + public static Dictionary HelpInfos{ get { return m_HelpInfos; } } + public static List SortedHelpInfo { get { return m_SortedHelpInfo; } } + + [CallPriority( 100 )] + public static void Initialize() + { + CommandSystem.Register( "HelpInfo", AccessLevel.Player, new CommandEventHandler( HelpInfo_OnCommand ) ); + + FillTable(); + } + + [Usage( "HelpInfo []" )] + [Description( "Gives information on a specified command, or when no argument specified, displays a gump containing all commands" )] + private static void HelpInfo_OnCommand( CommandEventArgs e ) + { + if( e.Length > 0 ) + { + string arg = e.GetString( 0 ).ToLower(); + CommandInfo c; + + if( m_HelpInfos.TryGetValue( arg, out c ) ) + { + Mobile m = e.Mobile; + + if( m.AccessLevel >= c.AccessLevel ) + m.SendGump( new CommandInfoGump( c ) ); + else + m.SendMessage( "You don't have access to that command." ); + + return; + } + else + e.Mobile.SendMessage( String.Format( "Command '{0}' not found!", arg ) ); + } + + e.Mobile.SendGump( new CommandListGump( 0, e.Mobile, null ) ); + + } + + public static void FillTable() + { + List commands = new List( CommandSystem.Entries.Values ); + List list = new List(); + + commands.Sort(); + commands.Reverse(); + Docs.Clean( commands ); + + for( int i = 0; i < commands.Count; ++i ) + { + CommandEntry e =commands[i]; + + MethodInfo mi = e.Handler.Method; + + object[] attrs = mi.GetCustomAttributes( typeof( UsageAttribute ), false ); + + if( attrs.Length == 0 ) + continue; + + UsageAttribute usage = attrs[0] as UsageAttribute; + + attrs = mi.GetCustomAttributes( typeof( DescriptionAttribute ), false ); + + if( attrs.Length == 0 ) + continue; + + DescriptionAttribute desc = attrs[0] as DescriptionAttribute; + + if( usage == null || desc == null ) + continue; + + attrs = mi.GetCustomAttributes( typeof( AliasesAttribute ), false ); + + AliasesAttribute aliases = (attrs.Length == 0 ? null : attrs[0] as AliasesAttribute); + + string descString = desc.Description.Replace( "<", "(" ).Replace( ">", ")" ); + + if( aliases == null ) + list.Add( new CommandInfo( e.AccessLevel, e.Command, null, usage.Usage, descString ) ); + else + { + list.Add( new CommandInfo( e.AccessLevel, e.Command, aliases.Aliases, usage.Usage, descString ) ); + + for( int j = 0; j < aliases.Aliases.Length; j++ ) + { + string[] newAliases = new string[aliases.Aliases.Length]; + + aliases.Aliases.CopyTo( newAliases, 0 ); + + newAliases[j] = e.Command; + + list.Add( new CommandInfo( e.AccessLevel, aliases.Aliases[j], newAliases, usage.Usage, descString ) ); + } + } + } + + + for( int i = 0; i < TargetCommands.AllCommands.Count; ++i ) + { + BaseCommand command = TargetCommands.AllCommands[i]; + + string usage = command.Usage; + string desc = command.Description; + + if( usage == null || desc == null ) + continue; + + string[] cmds = command.Commands; + string cmd = cmds[0]; + string[] aliases = new string[cmds.Length - 1]; + + for( int j = 0; j < aliases.Length; ++j ) + aliases[j] = cmds[j + 1]; + + desc = desc.Replace( "<", "(" ).Replace( ">", ")" ); + + if( command.Supports != CommandSupport.Single ) + { + StringBuilder sb = new StringBuilder( 50 + desc.Length ); + + sb.Append( "Modifiers: " ); + + if( (command.Supports & CommandSupport.Global) != 0 ) + sb.Append( ", " ); + + if( (command.Supports & CommandSupport.Online) != 0 ) + sb.Append( "Online, " ); + + if( (command.Supports & CommandSupport.Region) != 0 ) + sb.Append( "Region, " ); + + if( (command.Supports & CommandSupport.Contained) != 0 ) + sb.Append( "Contained, " ); + + if( (command.Supports & CommandSupport.Multi) != 0 ) + sb.Append( "Multi, " ); + + if( (command.Supports & CommandSupport.Area) != 0 ) + sb.Append( "Area, " ); + + if( (command.Supports & CommandSupport.Self) != 0 ) + sb.Append( "Self, " ); + + sb.Remove( sb.Length - 2, 2 ); + sb.Append( "
" ); + sb.Append( desc ); + + desc = sb.ToString(); + } + + list.Add( new CommandInfo( command.AccessLevel, cmd, aliases, usage, desc ) ); + + for( int j = 0; j < aliases.Length; j++ ) + { + string[] newAliases = new string[aliases.Length]; + + aliases.CopyTo( newAliases, 0 ); + + newAliases[j] = cmd; + + list.Add( new CommandInfo( command.AccessLevel, aliases[j], newAliases, usage, desc ) ); + } + } + + List commandImpls = BaseCommandImplementor.Implementors; + + for( int i = 0; i < commandImpls.Count; ++i ) + { + BaseCommandImplementor command = commandImpls[i]; + + string usage = command.Usage; + string desc = command.Description; + + if( usage == null || desc == null ) + continue; + + string[] cmds = command.Accessors; + string cmd = cmds[0]; + string[] aliases = new string[cmds.Length - 1]; + + for( int j = 0; j < aliases.Length; ++j ) + aliases[j] = cmds[j + 1]; + + desc = desc.Replace( "<", ")" ).Replace( ">", ")" ); + + list.Add( new CommandInfo( command.AccessLevel, cmd, aliases, usage, desc ) ); + + for( int j = 0; j < aliases.Length; j++ ) + { + string[] newAliases = new string[aliases.Length]; + + aliases.CopyTo( newAliases, 0 ); + + newAliases[j] = cmd; + + list.Add( new CommandInfo( command.AccessLevel, aliases[j], newAliases, usage, desc ) ); + } + } + + list.Sort( new CommandInfoSorter() ); + + m_SortedHelpInfo = list; + + foreach( CommandInfo c in m_SortedHelpInfo ) + { + if( !m_HelpInfos.ContainsKey( c.Name.ToLower() ) ) + m_HelpInfos.Add( c.Name.ToLower(), c ); + } + } + + public class CommandListGump : BaseGridGump + { + private const int EntriesPerPage = 15; + + int m_Page; + List m_List; + + public CommandListGump( int page, Mobile from, List list ) + : base( 30, 30 ) + { + m_Page = page; + + if( list == null ) + { + m_List = new List(); + + foreach( CommandInfo c in m_SortedHelpInfo ) + { + if( from.AccessLevel >= c.AccessLevel ) + m_List.Add( c ); + } + } + else + m_List = list; + + + AddNewPage(); + + if( m_Page > 0 ) + AddEntryButton( 20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight ); + else + AddEntryHeader( 20 ); + + AddEntryHtml( 160, Center( String.Format( "Page {0} of {1}", m_Page+1, (m_List.Count + EntriesPerPage - 1) / EntriesPerPage ) ) ); + + if( (m_Page + 1) * EntriesPerPage < m_List.Count ) + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight ); + else + AddEntryHeader( 20 ); + + int last = (int)AccessLevel.Player - 1; + + for( int i = m_Page * EntriesPerPage, line = 0; line < EntriesPerPage && i < m_List.Count; ++i, ++line ) + { + CommandInfo c = m_List[i]; + if( from.AccessLevel >= c.AccessLevel ) + { + if( (int)c.AccessLevel != last ) + { + AddNewLine(); + + AddEntryHtml( 20 + OffsetSize + 160, Color( c.AccessLevel.ToString(), 0xFF0000 ) ); + AddEntryHeader( 20 ); + line++; + } + + last = (int)c.AccessLevel; + + AddNewLine(); + + AddEntryHtml( 20 + OffsetSize + 160, c.Name ); + + AddEntryButton( 20, ArrowRightID1, ArrowRightID2, 3 + i, ArrowRightWidth, ArrowRightHeight ); + } + } + + FinishPage(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile m = sender.Mobile; + switch( info.ButtonID ) + { + case 0: + { + m.CloseGump( typeof( CommandInfoGump ) ); + break; + } + case 1: + { + if( m_Page > 0 ) + m.SendGump( new CommandListGump( m_Page - 1, m, m_List ) ); + + break; + } + case 2: + { + if( (m_Page + 1) * EntriesPerPage < m_SortedHelpInfo.Count ) + m.SendGump( new CommandListGump( m_Page + 1, m, m_List ) ); + + break; + } + default: + { + + int v = info.ButtonID - 3; + + if( v >= 0 && v < m_List.Count ) + { + CommandInfo c = m_List[v]; + + if( m.AccessLevel >= c.AccessLevel ) + { + m.SendGump( new CommandInfoGump( c ) ); + m.SendGump( new CommandListGump( m_Page, m, m_List ) ); + } + else + { + m.SendMessage( "You no longer have access to that command." ); + m.SendGump( new CommandListGump( m_Page, m, null ) ); + } + } + break; + } + } + } + } + + + public class CommandInfoGump : Gump + { + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public CommandInfoGump( CommandInfo info ) + : this( info, 320, 200 ) + { + } + + public CommandInfoGump( CommandInfo info, int width, int height ) + : base( 300, 50 ) + { + AddPage( 0 ); + + AddBackground( 0, 0, width, height, 5054 ); + + //AddImageTiled( 10, 10, width - 20, 20, 2624 ); + //AddAlphaRegion( 10, 10, width - 20, 20 ); + //AddHtmlLocalized( 10, 10, width - 20, 20, header, headerColor, false, false ); + AddHtml( 10, 10, width - 20, 20, Color( Center( info.Name ), 0xFF0000 ), false, false ); + + //AddImageTiled( 10, 40, width - 20, height - 80, 2624 ); + //AddAlphaRegion( 10, 40, width - 20, height - 80 ); + + StringBuilder sb = new StringBuilder(); + + sb.Append( "Usage: " ); + sb.Append( info.Usage.Replace( "<", "(" ).Replace( ">", ")" ) ); + sb.Append( "
" ); + + string[] aliases = info.Aliases; + + if( aliases != null && aliases.Length != 0 ) + { + sb.Append( String.Format( "Alias{0}: ", aliases.Length == 1 ? "" : "es" ) ); + + for( int i = 0; i < aliases.Length; ++i ) + { + if( i != 0 ) + sb.Append( ", " ); + + sb.Append( aliases[i] ); + } + + sb.Append( "
" ); + } + + sb.Append( "AccessLevel: " ); + sb.Append( info.AccessLevel.ToString() ); + sb.Append( "
" ); + sb.Append( "
" ); + + sb.Append( info.Description ); + + AddHtml( 10, 40, width - 20, height - 80, sb.ToString(), false, true ); + + //AddImageTiled( 10, height - 30, width - 20, 20, 2624 ); + //AddAlphaRegion( 10, height - 30, width - 20, 20 ); + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Logging.cs b/Scripts/Commands/Logging.cs new file mode 100644 index 0000000..edd559f --- /dev/null +++ b/Scripts/Commands/Logging.cs @@ -0,0 +1,147 @@ +using System; +using System.IO; +using Server; +using Server.Accounting; + +namespace Server.Commands +{ + public class CommandLogging + { + private static StreamWriter m_Output; + private static bool m_Enabled = true; + + public static bool Enabled{ get{ return m_Enabled; } set{ m_Enabled = value; } } + + public static StreamWriter Output{ get{ return m_Output; } } + + public static void Initialize() + { + EventSink.Command += new CommandEventHandler( EventSink_Command ); + + if ( !Directory.Exists( "Logs" ) ) + Directory.CreateDirectory( "Logs" ); + + string directory = "Logs/Commands"; + + if ( !Directory.Exists( directory ) ) + Directory.CreateDirectory( directory ); + + try + { + m_Output = new StreamWriter( Path.Combine( directory, String.Format( "{0}.log", DateTime.Now.ToLongDateString() ) ), true ); + + m_Output.AutoFlush = true; + + m_Output.WriteLine( "##############################" ); + m_Output.WriteLine( "Log started on {0}", DateTime.Now ); + m_Output.WriteLine(); + } + catch + { + } + } + + public static object Format( object o ) + { + if ( o is Mobile ) + { + Mobile m = (Mobile)o; + + if ( m.Account == null ) + return String.Format( "{0} (no account)", m ); + else + return String.Format( "{0} ('{1}')", m, m.Account.Username ); + } + else if ( o is Item ) + { + Item item = (Item)o; + + return String.Format( "0x{0:X} ({1})", item.Serial.Value, item.GetType().Name ); + } + + return o; + } + + public static void WriteLine( Mobile from, string format, params object[] args ) + { + if ( !m_Enabled ) + return; + + WriteLine( from, String.Format( format, args ) ); + } + + public static void WriteLine( Mobile from, string text ) + { + if ( !m_Enabled ) + return; + + try + { + m_Output.WriteLine( "{0}: {1}: {2}", DateTime.Now, from.NetState, text ); + + string path = Core.BaseDirectory; + + Account acct = from.Account as Account; + + string name = ( acct == null ? from.Name : acct.Username ); + + AppendPath( ref path, "Logs" ); + AppendPath( ref path, "Commands" ); + AppendPath( ref path, from.AccessLevel.ToString() ); + path = Path.Combine( path, String.Format( "{0}.log", name ) ); + + using ( StreamWriter sw = new StreamWriter( path, true ) ) + sw.WriteLine( "{0}: {1}: {2}", DateTime.Now, from.NetState, text ); + } + catch + { + } + } + + private static char[] m_NotSafe = new char[]{ '\\', '/', ':', '*', '?', '"', '<', '>', '|' }; + + public static void AppendPath( ref string path, string toAppend ) + { + path = Path.Combine( path, toAppend ); + + if ( !Directory.Exists( path ) ) + Directory.CreateDirectory( path ); + } + + public static string Safe( string ip ) + { + if ( ip == null ) + return "null"; + + ip = ip.Trim(); + + if ( ip.Length == 0 ) + return "empty"; + + bool isSafe = true; + + for ( int i = 0; isSafe && i < m_NotSafe.Length; ++i ) + isSafe = ( ip.IndexOf( m_NotSafe[i] ) == -1 ); + + if ( isSafe ) + return ip; + + System.Text.StringBuilder sb = new System.Text.StringBuilder( ip ); + + for ( int i = 0; i < m_NotSafe.Length; ++i ) + sb.Replace( m_NotSafe[i], '_' ); + + return sb.ToString(); + } + + public static void EventSink_Command( CommandEventArgs e ) + { + WriteLine( e.Mobile, "{0} {1} used command '{2} {3}'", e.Mobile.AccessLevel, Format( e.Mobile ), e.Command, e.ArgString ); + } + + public static void LogChangeProperty( Mobile from, object o, string name, string value ) + { + WriteLine( from, "{0} {1} set property '{2}' of {3} to '{4}'", from.AccessLevel, Format( from ), name, Format( o ), value ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Profiling.cs b/Scripts/Commands/Profiling.cs new file mode 100644 index 0000000..5812aac --- /dev/null +++ b/Scripts/Commands/Profiling.cs @@ -0,0 +1,404 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Diagnostics; + +namespace Server.Commands +{ + public class Profiling + { + public static void Initialize() + { + CommandSystem.Register( "DumpTimers", AccessLevel.Administrator, new CommandEventHandler( DumpTimers_OnCommand ) ); + CommandSystem.Register( "CountObjects", AccessLevel.Administrator, new CommandEventHandler( CountObjects_OnCommand ) ); + CommandSystem.Register( "ProfileWorld", AccessLevel.Administrator, new CommandEventHandler( ProfileWorld_OnCommand ) ); + CommandSystem.Register( "TraceInternal", AccessLevel.Administrator, new CommandEventHandler( TraceInternal_OnCommand ) ); + CommandSystem.Register( "TraceExpanded", AccessLevel.Administrator, new CommandEventHandler( TraceExpanded_OnCommand ) ); + CommandSystem.Register( "WriteProfiles", AccessLevel.Administrator, new CommandEventHandler( WriteProfiles_OnCommand ) ); + CommandSystem.Register( "SetProfiles", AccessLevel.Administrator, new CommandEventHandler( SetProfiles_OnCommand ) ); + } + + [Usage( "WriteProfiles" )] + [Description( "Generates a log files containing performance diagnostic information." )] + public static void WriteProfiles_OnCommand( CommandEventArgs e ) + { + try + { + using ( StreamWriter sw = new StreamWriter( "profiles.log", true ) ) + { + sw.WriteLine( "# Dump on {0:f}", DateTime.Now ); + sw.WriteLine( "# Core profiling for " + Core.ProfileTime ); + + sw.WriteLine( "# Packet send" ); + BaseProfile.WriteAll( sw, PacketSendProfile.Profiles ); + sw.WriteLine(); + + sw.WriteLine( "# Packet receive" ); + BaseProfile.WriteAll( sw, PacketReceiveProfile.Profiles ); + sw.WriteLine(); + + sw.WriteLine( "# Timer" ); + BaseProfile.WriteAll( sw, TimerProfile.Profiles ); + sw.WriteLine(); + + sw.WriteLine( "# Gump response" ); + BaseProfile.WriteAll( sw, GumpProfile.Profiles ); + sw.WriteLine(); + + sw.WriteLine( "# Target response" ); + BaseProfile.WriteAll( sw, TargetProfile.Profiles ); + sw.WriteLine(); + } + } + catch + { + } + } + + [Usage( "SetProfiles [true | false]" )] + [Description( "Enables, disables, or toggles the state of core packet and timer profiling." )] + public static void SetProfiles_OnCommand( CommandEventArgs e ) + { + if ( e.Length == 1 ) + Core.Profiling = e.GetBoolean( 0 ); + else + Core.Profiling = !Core.Profiling; + + e.Mobile.SendMessage( "Profiling has been {0}.", Core.Profiling ? "enabled" : "disabled" ); + } + + [Usage( "DumpTimers" )] + [Description( "Generates a log file of all currently executing timers. Used for tracing timer leaks." )] + public static void DumpTimers_OnCommand( CommandEventArgs e ) + { + try + { + using ( StreamWriter sw = new StreamWriter( "timerdump.log", true ) ) + Timer.DumpInfo( sw ); + } + catch + { + } + } + + private class CountSorter : IComparer + { + public int Compare( object x, object y ) + { + DictionaryEntry a = (DictionaryEntry)x; + DictionaryEntry b = (DictionaryEntry)y; + + int aCount = GetCount( a.Value ); + int bCount = GetCount( b.Value ); + + int v = -aCount.CompareTo( bCount ); + + if ( v == 0 ) + { + Type aType = (Type)a.Key; + Type bType = (Type)b.Key; + + v = aType.FullName.CompareTo( bType.FullName ); + } + + return v; + } + + private int GetCount( object obj ) + { + if ( obj is int ) + return (int) obj; + + if ( obj is int[] ) + { + int[] list = (int[]) obj; + + int total = 0; + + for ( int i = 0; i < list.Length; ++i ) + total += list[i]; + + return total; + } + + return 0; + } + } + + [Usage( "CountObjects" )] + [Description( "Generates a log file detailing all item and mobile types in the world." )] + public static void CountObjects_OnCommand( CommandEventArgs e ) + { + using ( StreamWriter op = new StreamWriter( "objects.log" ) ) + { + Hashtable table = new Hashtable(); + + foreach ( Item item in World.Items.Values ) + { + Type type = item.GetType(); + + object o = (object)table[type]; + + if ( o == null ) + table[type] = 1; + else + table[type] = 1 + (int)o; + } + + ArrayList items = new ArrayList( table ); + + table.Clear(); + + foreach ( Mobile m in World.Mobiles.Values ) + { + Type type = m.GetType(); + + object o = (object)table[type]; + + if ( o == null ) + table[type] = 1; + else + table[type] = 1 + (int)o; + } + + ArrayList mobiles = new ArrayList( table ); + + items.Sort( new CountSorter() ); + mobiles.Sort( new CountSorter() ); + + op.WriteLine( "# Object count table generated on {0}", DateTime.Now ); + op.WriteLine(); + op.WriteLine(); + + op.WriteLine( "# Items:" ); + + foreach ( DictionaryEntry de in items ) + op.WriteLine( "{0}\t{1:F2}%\t{2}", de.Value, (100 * (int)de.Value) / (double)World.Items.Count, de.Key ); + + op.WriteLine(); + op.WriteLine(); + + op.WriteLine( "#Mobiles:" ); + + foreach ( DictionaryEntry de in mobiles ) + op.WriteLine( "{0}\t{1:F2}%\t{2}", de.Value, (100 * (int)de.Value) / (double)World.Mobiles.Count, de.Key ); + } + + e.Mobile.SendMessage( "Object table has been generated. See the file : /objects.log" ); + } + + [Usage( "TraceExpanded" )] + [Description( "Generates a log file describing all items using expanded memory." )] + public static void TraceExpanded_OnCommand( CommandEventArgs e ) + { + Hashtable typeTable = new Hashtable(); + + foreach ( Item item in World.Items.Values ) + { + ExpandFlag flags = item.GetExpandFlags(); + + if ( ( flags & ~(ExpandFlag.TempFlag | ExpandFlag.SaveFlag) ) == 0 ) + continue; + + Type itemType = item.GetType(); + + do + { + int[] countTable = typeTable[itemType] as int[]; + + if ( countTable == null ) + typeTable[itemType] = countTable = new int[9]; + + if ( ( flags & ExpandFlag.Name ) != 0 ) + ++countTable[0]; + + if ( ( flags & ExpandFlag.Items ) != 0 ) + ++countTable[1]; + + if ( ( flags & ExpandFlag.Bounce ) != 0 ) + ++countTable[2]; + + if ( ( flags & ExpandFlag.Holder ) != 0 ) + ++countTable[3]; + + if ( ( flags & ExpandFlag.Blessed ) != 0 ) + ++countTable[4]; + + /*if ( ( flags & ExpandFlag.TempFlag ) != 0 ) + ++countTable[5]; + + if ( ( flags & ExpandFlag.SaveFlag ) != 0 ) + ++countTable[6];*/ + + if ( ( flags & ExpandFlag.Weight ) != 0 ) + ++countTable[7]; + + if ((flags & ExpandFlag.Spawner) != 0) + ++countTable[8]; + + itemType = itemType.BaseType; + } while ( itemType != typeof( object ) ); + } + + try + { + using ( StreamWriter op = new StreamWriter( "expandedItems.log", true ) ) + { + string[] names = new string[] + { + "Name", + "Items", + "Bounce", + "Holder", + "Blessed", + "TempFlag", + "SaveFlag", + "Weight", + "Spawner" + }; + + ArrayList list = new ArrayList( typeTable ); + + list.Sort( new CountSorter() ); + + foreach ( DictionaryEntry de in list ) + { + Type itemType = de.Key as Type; + int[] countTable = de.Value as int[]; + + op.WriteLine( "# {0}", itemType.FullName ); + + for ( int i = 0; i < countTable.Length; ++i ) + { + if ( countTable[i] > 0 ) + op.WriteLine( "{0}\t{1:N0}", names[i], countTable[i] ); + } + + op.WriteLine(); + } + } + } + catch + { + } + } + + [Usage( "TraceInternal" )] + [Description( "Generates a log file describing all items in the 'internal' map." )] + public static void TraceInternal_OnCommand( CommandEventArgs e ) + { + int totalCount = 0; + Hashtable table = new Hashtable(); + + foreach ( Item item in World.Items.Values ) + { + if ( item.Parent != null || item.Map != Map.Internal ) + continue; + + ++totalCount; + + Type type = item.GetType(); + int[] parms = (int[])table[type]; + + if ( parms == null ) + table[type] = parms = new int[]{ 0, 0 }; + + parms[0]++; + parms[1] += item.Amount; + } + + using ( StreamWriter op = new StreamWriter( "internal.log" ) ) + { + op.WriteLine( "# {0} items found", totalCount ); + op.WriteLine( "# {0} different types", table.Count ); + op.WriteLine(); + op.WriteLine(); + op.WriteLine( "Type\t\tCount\t\tAmount\t\tAvg. Amount" ); + + foreach ( DictionaryEntry de in table ) + { + Type type = (Type)de.Key; + int[] parms = (int[])de.Value; + + op.WriteLine( "{0}\t\t{1}\t\t{2}\t\t{3:F2}", type.Name, parms[0], parms[1], (double)parms[1] / parms[0] ); + } + } + } + + [Usage( "ProfileWorld" )] + [Description( "Prints the amount of data serialized for every object type in your world file." )] + public static void ProfileWorld_OnCommand( CommandEventArgs e ) + { + ProfileWorld( "items", "worldprofile_items.log" ); + ProfileWorld( "mobiles", "worldprofile_mobiles.log" ); + } + + public static void ProfileWorld( string type, string opFile ) + { + try + { + ArrayList types = new ArrayList(); + + using ( BinaryReader bin = new BinaryReader( new FileStream( String.Format( "Saves/{0}/{0}.tdb", type ), FileMode.Open, FileAccess.Read, FileShare.Read ) ) ) + { + int count = bin.ReadInt32(); + + for ( int i = 0; i < count; ++i ) + types.Add( ScriptCompiler.FindTypeByFullName( bin.ReadString() ) ); + } + + long total = 0; + + Hashtable table = new Hashtable(); + + using ( BinaryReader bin = new BinaryReader( new FileStream( String.Format( "Saves/{0}/{0}.idx", type ), FileMode.Open, FileAccess.Read, FileShare.Read ) ) ) + { + int count = bin.ReadInt32(); + + for ( int i = 0; i < count; ++i ) + { + int typeID = bin.ReadInt32(); + int serial = bin.ReadInt32(); + long pos = bin.ReadInt64(); + int length = bin.ReadInt32(); + Type objType = (Type)types[typeID]; + + while ( objType != null && objType != typeof( object ) ) + { + object obj = table[objType]; + + if ( obj == null ) + table[objType] = length; + else + table[objType] = length + (int)obj; + + objType = objType.BaseType; + total += length; + } + } + } + + ArrayList list = new ArrayList( table ); + + list.Sort( new CountSorter() ); + + using ( StreamWriter op = new StreamWriter( opFile ) ) + { + op.WriteLine( "# Profile of world {0}", type ); + op.WriteLine( "# Generated on {0}", DateTime.Now ); + op.WriteLine(); + op.WriteLine(); + + foreach ( DictionaryEntry de in list ) + op.WriteLine( "{0}\t{1:F2}%\t{2}", de.Value, (100 * (int)de.Value) / (double)total, de.Key ); + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Properties.cs b/Scripts/Commands/Properties.cs new file mode 100644 index 0000000..9ab7c40 --- /dev/null +++ b/Scripts/Commands/Properties.cs @@ -0,0 +1,846 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Items; +using Server.Gumps; +using CPA = Server.CommandPropertyAttribute; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Commands +{ + public enum PropertyAccess + { + Read = 0x01, + Write = 0x02, + ReadWrite = Read | Write + } + + public class Properties + { + public static void Initialize() + { + CommandSystem.Register( "Props", AccessLevel.Counselor, new CommandEventHandler( Props_OnCommand ) ); + } + + private class PropsTarget : Target + { + public PropsTarget() : base( -1, true, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( !BaseCommand.IsAccessible( from, o ) ) + from.SendMessage( "That is not accessible." ); + else + from.SendGump( new PropertiesGump( from, o ) ); + } + } + + [Usage( "Props [serial]" )] + [Description( "Opens a menu where you can view and edit all properties of a targeted (or specified) object." )] + private static void Props_OnCommand( CommandEventArgs e ) + { + if ( e.Length == 1 ) + { + IEntity ent = World.FindEntity( e.GetInt32( 0 ) ); + + if ( ent == null ) + e.Mobile.SendMessage( "No object with that serial was found." ); + else if ( !BaseCommand.IsAccessible( e.Mobile, ent ) ) + e.Mobile.SendMessage( "That is not accessible." ); + else + e.Mobile.SendGump( new PropertiesGump( e.Mobile, ent ) ); + } + else + { + e.Mobile.Target = new PropsTarget(); + } + } + + private static bool CIEqual( string l, string r ) + { + return Insensitive.Equals( l, r ); + } + + private static Type typeofCPA = typeof( CPA ); + + public static CPA GetCPA( PropertyInfo p ) + { + object[] attrs = p.GetCustomAttributes( typeofCPA, false ); + + if ( attrs.Length == 0 ) + return null; + + return attrs[0] as CPA; + } + + public static PropertyInfo[] GetPropertyInfoChain( Mobile from, Type type, string propertyString, PropertyAccess endAccess, ref string failReason ) + { + string[] split = propertyString.Split( '.' ); + + if ( split.Length == 0 ) + return null; + + PropertyInfo[] info = new PropertyInfo[split.Length]; + + for ( int i = 0; i < info.Length; ++i ) + { + string propertyName = split[i]; + + if ( CIEqual( propertyName, "current" ) ) + continue; + + PropertyInfo[] props = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public ); + + bool isFinal = ( i == (info.Length - 1) ); + + PropertyAccess access = endAccess; + + if ( !isFinal ) + access |= PropertyAccess.Read; + + for ( int j = 0; j < props.Length; ++j ) + { + PropertyInfo p = props[j]; + + if ( CIEqual( p.Name, propertyName ) ) + { + CPA attr = GetCPA( p ); + + if ( attr == null ) + { + failReason = String.Format( "Property '{0}' not found.", propertyName ); + return null; + } + else if ( (access & PropertyAccess.Read) != 0 && from.AccessLevel < attr.ReadLevel ) + { + failReason = String.Format( "You must be at least {0} to get the property '{1}'.", + Mobile.GetAccessLevelName( attr.ReadLevel ), propertyName ); + + return null; + } + else if ( (access & PropertyAccess.Write) != 0 && from.AccessLevel < attr.WriteLevel ) + { + failReason = String.Format( "You must be at least {0} to set the property '{1}'.", + Mobile.GetAccessLevelName( attr.WriteLevel ), propertyName ); + + return null; + } + else if ( (access & PropertyAccess.Read) != 0 && !p.CanRead ) + { + failReason = String.Format( "Property '{0}' is write only.", propertyName ); + return null; + } + else if ( (access & PropertyAccess.Write) != 0 && (!p.CanWrite || attr.ReadOnly) && isFinal ) + { + failReason = String.Format( "Property '{0}' is read only.", propertyName ); + return null; + } + + info[i] = p; + type = p.PropertyType; + break; + } + } + + if ( info[i] == null ) + { + failReason = String.Format( "Property '{0}' not found.", propertyName ); + return null; + } + } + + return info; + } + + public static PropertyInfo GetPropertyInfo( Mobile from, ref object obj, string propertyName, PropertyAccess access, ref string failReason ) + { + PropertyInfo[] chain = GetPropertyInfoChain( from, obj.GetType(), propertyName, access, ref failReason ); + + if ( chain == null ) + return null; + + return GetPropertyInfo( ref obj, chain, ref failReason ); + } + + public static PropertyInfo GetPropertyInfo( ref object obj, PropertyInfo[] chain, ref string failReason ) + { + if ( chain == null || chain.Length == 0 ) + { + failReason = "Property chain is empty."; + return null; + } + + for ( int i = 0; i < chain.Length - 1; ++i ) + { + if ( chain[i] == null ) + continue; + + obj = chain[i].GetValue( obj, null ); + + if ( obj == null ) + { + failReason = String.Format( "Property '{0}' is null.", chain[i] ); + return null; + } + } + + return chain[chain.Length-1]; + } + + public static string GetValue( Mobile from, object o, string name ) + { + string failReason = ""; + + PropertyInfo[] chain = GetPropertyInfoChain( from, o.GetType(), name, PropertyAccess.Read, ref failReason ); + + if ( chain == null || chain.Length == 0 ) + return failReason; + + PropertyInfo p = GetPropertyInfo( ref o, chain, ref failReason ); + + if ( p == null ) + return failReason; + + return InternalGetValue( o, p, chain ); + } + + public static string IncreaseValue( Mobile from, object o, string[] args ) + { + Type type = o.GetType(); + + object[] realObjs = new object[args.Length/2]; + PropertyInfo[] realProps = new PropertyInfo[args.Length/2]; + int[] realValues = new int[args.Length/2]; + + bool positive = false, negative = false; + + for ( int i = 0; i < realProps.Length; ++i ) + { + string name = args[i*2]; + + try + { + string valueString = args[1 + (i*2)]; + + if ( valueString.StartsWith( "0x" ) ) + { + realValues[i] = Convert.ToInt32( valueString.Substring( 2 ), 16 ); + } + else + { + realValues[i] = Convert.ToInt32( valueString ); + } + } + catch + { + return "Offset value could not be parsed."; + } + + if ( realValues[i] > 0 ) + positive = true; + else if ( realValues[i] < 0 ) + negative = true; + else + return "Zero is not a valid value to offset."; + + string failReason = null; + realObjs[i] = o; + realProps[i] = GetPropertyInfo( from, ref realObjs[i], name, PropertyAccess.ReadWrite, ref failReason ); + + if ( failReason != null ) + return failReason; + + if ( realProps[i] == null ) + return "Property not found."; + } + + for ( int i = 0; i < realProps.Length; ++i ) + { + object obj = realProps[i].GetValue( realObjs[i], null ); + + if( !( obj is IConvertible ) ) + return "Property is not IConvertable."; + + try + { + + long v = (long)Convert.ChangeType( obj, TypeCode.Int64 ); + v += realValues[i]; + + realProps[i].SetValue( realObjs[i], Convert.ChangeType( v, realProps[i].PropertyType ), null ); + } + catch + { + return "Value could not be converted"; + } + } + + if ( realProps.Length == 1 ) + { + if ( positive ) + return "The property has been increased."; + + return "The property has been decreased."; + } + + if ( positive && negative ) + return "The properties have been changed."; + + if ( positive ) + return "The properties have been increased."; + + return "The properties have been decreased."; + } + + private static string InternalGetValue( object o, PropertyInfo p ) + { + return InternalGetValue( o, p, null ); + } + + private static string InternalGetValue( object o, PropertyInfo p, PropertyInfo[] chain ) + { + Type type = p.PropertyType; + + object value = p.GetValue( o, null ); + string toString; + + if ( value == null ) + toString = "null"; + else if ( IsNumeric( type ) ) + toString = String.Format( "{0} (0x{0:X})", value ); + else if ( IsChar( type ) ) + toString = String.Format( "'{0}' ({1} [0x{1:X}])", value, (int) value ); + else if ( IsString( type ) ) + toString = ( (string) value == "null" ? @"@""null""" : String.Format( "\"{0}\"", value ) ); + else if (IsText(type)) + toString = ((TextDefinition)value).Format(false); + else + toString = value.ToString(); + + if ( chain == null ) + return String.Format( "{0} = {1}", p.Name, toString ); + + string[] concat = new string[chain.Length*2+1]; + + for ( int i = 0; i < chain.Length; ++i ) + { + concat[(i*2)+0] = chain[i].Name; + concat[(i*2)+1] = ( i < (chain.Length - 1) ) ? "." : " = "; + } + + concat[concat.Length-1] = toString; + + return String.Concat( concat ); + } + + public static string SetValue( Mobile from, object o, string name, string value ) + { + object logObject = o; + + string failReason = ""; + PropertyInfo p = GetPropertyInfo( from, ref o, name, PropertyAccess.Write, ref failReason ); + + if ( p == null ) + return failReason; + + return InternalSetValue( from, logObject, o, p, name, value, true ); + } + + private static Type typeofSerial = typeof( Serial ); + + private static bool IsSerial( Type t ) + { + return ( t == typeofSerial ); + } + + private static Type typeofType = typeof( Type ); + + private static bool IsType( Type t ) + { + return ( t == typeofType ); + } + + private static Type typeofChar = typeof( Char ); + + private static bool IsChar( Type t ) + { + return ( t == typeofChar ); + } + + private static Type typeofString = typeof( String ); + + private static bool IsString( Type t ) + { + return ( t == typeofString ); + } + + private static Type typeofText = typeof(TextDefinition); + + private static bool IsText(Type t) + { + return (t == typeofText); + } + + private static bool IsEnum( Type t ) + { + return t.IsEnum; + } + + private static Type typeofTimeSpan = typeof( TimeSpan ); + private static Type typeofParsable = typeof( ParsableAttribute ); + + private static bool IsParsable( Type t ) + { + return ( t == typeofTimeSpan || t.IsDefined( typeofParsable, false ) ); + } + + private static Type[] m_ParseTypes = new Type[]{ typeof( string ) }; + private static object[] m_ParseParams = new object[1]; + + private static object Parse( object o, Type t, string value ) + { + MethodInfo method = t.GetMethod( "Parse", m_ParseTypes ); + + m_ParseParams[0] = value; + + return method.Invoke( o, m_ParseParams ); + } + + private static Type[] m_NumericTypes = new Type[] + { + typeof( Byte ), typeof( SByte ), + typeof( Int16 ), typeof( UInt16 ), + typeof( Int32 ), typeof( UInt32 ), + typeof( Int64 ), typeof( UInt64 ) + }; + + private static bool IsNumeric( Type t ) + { + return ( Array.IndexOf( m_NumericTypes, t ) >= 0 ); + } + + public static string ConstructFromString( Type type, object obj, string value, ref object constructed ) + { + object toSet; + bool isSerial = IsSerial( type ); + + if ( isSerial ) // mutate into int32 + type = m_NumericTypes[4]; + + if ( value == "(-null-)" && !type.IsValueType ) + value = null; + + if ( IsEnum( type ) ) + { + try + { + toSet = Enum.Parse( type, value, true ); + } + catch + { + return "That is not a valid enumeration member."; + } + } + else if ( IsType( type ) ) + { + try + { + toSet = ScriptCompiler.FindTypeByName( value ); + + if ( toSet == null ) + return "No type with that name was found."; + } + catch + { + return "No type with that name was found."; + } + } + else if ( IsParsable( type ) ) + { + try + { + toSet = Parse( obj, type, value ); + } + catch + { + return "That is not properly formatted."; + } + } + else if ( value == null ) + { + toSet = null; + } + else if ( value.StartsWith( "0x" ) && IsNumeric( type ) ) + { + try + { + toSet = Convert.ChangeType( Convert.ToUInt64( value.Substring( 2 ), 16 ), type ); + } + catch + { + return "That is not properly formatted."; + } + } + else + { + try + { + toSet = Convert.ChangeType( value, type ); + } + catch + { + return "That is not properly formatted."; + } + } + + if ( isSerial ) // mutate back + toSet = (Serial)((Int32)toSet); + + constructed = toSet; + return null; + } + + public static string SetDirect( Mobile from, object logObject, object obj, PropertyInfo prop, string givenName, object toSet, bool shouldLog ) + { + try + { + if ( toSet is AccessLevel ) + { + AccessLevel newLevel = (AccessLevel) toSet; + AccessLevel reqLevel = AccessLevel.Administrator; + + if ( newLevel == AccessLevel.Administrator ) + reqLevel = AccessLevel.Administrator; + else if ( newLevel >= AccessLevel.Developer ) + reqLevel = AccessLevel.Owner; + + if ( from.AccessLevel < reqLevel ) + return "You do not have access to that level."; + } + + if ( shouldLog ) + CommandLogging.LogChangeProperty( from, logObject, givenName, toSet == null ? "(-null-)" : toSet.ToString() ); + + prop.SetValue( obj, toSet, null ); + return "Property has been set."; + } + catch + { + return "An exception was caught, the property may not be set."; + } + } + + public static string SetDirect( object obj, PropertyInfo prop, object toSet ) + { + try + { + if ( toSet is AccessLevel ) + { + return "You do not have access to that level."; + } + + prop.SetValue( obj, toSet, null ); + return "Property has been set."; + } + catch + { + return "An exception was caught, the property may not be set."; + } + } + + public static string InternalSetValue( Mobile from, object logobj, object o, PropertyInfo p, string pname, string value, bool shouldLog ) + { + object toSet = null; + string result = ConstructFromString( p.PropertyType, o, value, ref toSet ); + + if ( result != null ) + return result; + + return SetDirect( from, logobj, o, p, pname, toSet, shouldLog ); + } + + public static string InternalSetValue( object o, PropertyInfo p, string value ) + { + object toSet = null; + string result = ConstructFromString( p.PropertyType, o, value, ref toSet ); + + if ( result != null ) + return result; + + return SetDirect( o, p, toSet ); + } + } +} + +namespace Server +{ + public abstract class PropertyException : ApplicationException + { + protected Property m_Property; + + public Property Property + { + get { return m_Property; } + } + + public PropertyException( Property property, string message ) + : base( message ) + { + m_Property = property; + } + } + + public abstract class BindingException : PropertyException + { + public BindingException( Property property, string message ) + : base( property, message ) + { + } + } + + public sealed class NotYetBoundException : BindingException + { + public NotYetBoundException( Property property ) + : base( property, String.Format( "Property has not yet been bound." ) ) + { + } + } + + public sealed class AlreadyBoundException : BindingException + { + public AlreadyBoundException( Property property ) + : base( property, String.Format( "Property has already been bound." ) ) + { + } + } + + public sealed class UnknownPropertyException : BindingException + { + public UnknownPropertyException( Property property, string current ) + : base( property, String.Format( "Property '{0}' not found.", current ) ) + { + } + } + + public sealed class ReadOnlyException : BindingException + { + public ReadOnlyException( Property property ) + : base( property, "Property is read-only." ) + { + } + } + + public sealed class WriteOnlyException : BindingException + { + public WriteOnlyException( Property property ) + : base( property, "Property is write-only." ) + { + } + } + + public abstract class AccessException : PropertyException + { + public AccessException( Property property, string message ) + : base( property, message ) + { + } + } + + public sealed class InternalAccessException : AccessException + { + public InternalAccessException( Property property ) + : base( property, "Property is internal." ) + { + } + } + + public abstract class ClearanceException : AccessException + { + protected AccessLevel m_PlayerAccess; + protected AccessLevel m_NeededAccess; + + public AccessLevel PlayerAccess + { + get { return m_PlayerAccess; } + } + + public AccessLevel NeededAccess + { + get { return m_NeededAccess; } + } + + public ClearanceException( Property property, AccessLevel playerAccess, AccessLevel neededAccess, string accessType ) + : base( property, string.Format( + "You must be at least {0} to {1} this property.", + Mobile.GetAccessLevelName( neededAccess ), + accessType + ) ) + { + } + } + + public sealed class ReadAccessException : ClearanceException + { + public ReadAccessException( Property property, AccessLevel playerAccess, AccessLevel neededAccess ) + : base( property, playerAccess, neededAccess, "read" ) + { + } + } + + public sealed class WriteAccessException : ClearanceException + { + public WriteAccessException( Property property, AccessLevel playerAccess, AccessLevel neededAccess ) + : base( property, playerAccess, neededAccess, "write" ) + { + } + } + + public sealed class Property + { + private string m_Binding; + + private PropertyInfo[] m_Chain; + private PropertyAccess m_Access; + + public string Binding + { + get { return m_Binding; } + } + + public bool IsBound + { + get { return ( m_Chain != null ); } + } + + public PropertyAccess Access + { + get { return m_Access; } + } + + public PropertyInfo[] Chain + { + get + { + if ( !IsBound ) + throw new NotYetBoundException( this ); + + return m_Chain; + } + } + + public Type Type + { + get + { + if ( !IsBound ) + throw new NotYetBoundException( this ); + + return m_Chain[m_Chain.Length - 1].PropertyType; + } + } + + public bool CheckAccess( Mobile from ) + { + if ( !IsBound ) + throw new NotYetBoundException( this ); + + for ( int i = 0; i < m_Chain.Length; ++i ) + { + PropertyInfo prop = m_Chain[i]; + + bool isFinal = ( i == ( m_Chain.Length - 1 ) ); + + PropertyAccess access = m_Access; + + if ( !isFinal ) + access |= PropertyAccess.Read; + + CPA security = Properties.GetCPA( prop ); + + if ( security == null ) + throw new InternalAccessException( this ); + + if ( ( access & PropertyAccess.Read ) != 0 && from.AccessLevel < security.ReadLevel ) + throw new ReadAccessException( this, from.AccessLevel, security.ReadLevel ); + + if ( ( access & PropertyAccess.Write ) != 0 && (from.AccessLevel < security.WriteLevel || security.ReadOnly) ) + throw new WriteAccessException( this, from.AccessLevel, security.ReadLevel ); + } + + return true; + } + + public void BindTo( Type objectType, PropertyAccess desiredAccess ) + { + if ( IsBound ) + throw new AlreadyBoundException( this ); + + string[] split = m_Binding.Split( '.' ); + + PropertyInfo[] chain = new PropertyInfo[split.Length]; + + for ( int i = 0; i < split.Length; ++i ) + { + bool isFinal = ( i == ( chain.Length - 1 ) ); + + chain[i] = objectType.GetProperty( split[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase ); + + if ( chain[i] == null ) + throw new UnknownPropertyException( this, split[i] ); + + objectType = chain[i].PropertyType; + + PropertyAccess access = desiredAccess; + + if ( !isFinal ) + access |= PropertyAccess.Read; + + if ( ( access & PropertyAccess.Read ) != 0 && !chain[i].CanRead ) + throw new WriteOnlyException( this ); + + if ( ( access & PropertyAccess.Write ) != 0 && !chain[i].CanWrite ) + throw new ReadOnlyException( this ); + } + + m_Access = desiredAccess; + m_Chain = chain; + } + + public Property( string binding ) + { + m_Binding = binding; + } + + public Property( PropertyInfo[] chain ) + { + m_Chain = chain; + } + + public override string ToString() + { + if ( !IsBound ) + return m_Binding; + + string[] toJoin = new string[m_Chain.Length]; + + for ( int i = 0; i < toJoin.Length; ++i ) + toJoin[i] = m_Chain[i].Name; + + return string.Join( ".", toJoin ); + } + + public static Property Parse( Type type, string binding, PropertyAccess access ) + { + Property prop = new Property( binding ); + + prop.BindTo( type, access ); + + return prop; + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/ShardTime.cs b/Scripts/Commands/ShardTime.cs new file mode 100644 index 0000000..38c3144 --- /dev/null +++ b/Scripts/Commands/ShardTime.cs @@ -0,0 +1,19 @@ +using System; + +namespace Server.Commands +{ + public class ShardTime + { + public static void Initialize() + { + CommandSystem.Register("Time", AccessLevel.Player, new CommandEventHandler(Time_OnCommand)); + } + + [Usage("Time")] + [Description("Returns the server's local time.")] + private static void Time_OnCommand(CommandEventArgs e) + { + e.Mobile.SendMessage(DateTime.Now.ToString()); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/SignParser.cs b/Scripts/Commands/SignParser.cs new file mode 100644 index 0000000..d8bdd71 --- /dev/null +++ b/Scripts/Commands/SignParser.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Server; +using Server.Items; + +namespace Server.Commands +{ + public class SignParser + { + private class SignEntry + { + public string m_Text; + public Point3D m_Location; + public int m_ItemID; + public int m_Map; + + public SignEntry( string text, Point3D pt, int itemID, int mapLoc ) + { + m_Text = text; + m_Location = pt; + m_ItemID = itemID; + m_Map = mapLoc; + } + } + + public static void Initialize() + { + CommandSystem.Register( "SignGen", AccessLevel.Administrator, new CommandEventHandler( SignGen_OnCommand ) ); + } + + [Usage( "SignGen" )] + [Description( "Generates world/shop signs on all facets." )] + public static void SignGen_OnCommand( CommandEventArgs c ) + { + Parse( c.Mobile ); + } + + public static void Parse( Mobile from ) + { + string cfg = Path.Combine( Core.BaseDirectory, "Data/signs.cfg" ); + + if ( File.Exists( cfg ) ) + { + List list = new List(); + from.SendMessage( "Generating signs, please wait." ); + + using ( StreamReader ip = new StreamReader( cfg ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + string[] split = line.Split( ' ' ); + + SignEntry e = new SignEntry( + line.Substring( split[0].Length + 1 + split[1].Length + 1 + split[2].Length + 1 + split[3].Length + 1 + split[4].Length + 1 ), + new Point3D( Utility.ToInt32( split[2] ), Utility.ToInt32( split[3] ), Utility.ToInt32( split[4] ) ), + Utility.ToInt32( split[1] ), Utility.ToInt32( split[0] ) ); + + list.Add( e ); + } + } + + Map[] brit = new Map[]{ Map.Felucca, Map.Trammel }; + Map[] fel = new Map[]{ Map.Felucca }; + Map[] tram = new Map[]{ Map.Trammel }; + Map[] ilsh = new Map[]{ Map.Ilshenar }; + Map[] malas = new Map[]{ Map.Malas }; + Map[] tokuno = new Map[]{ Map.Tokuno }; + + for ( int i = 0; i < list.Count; ++i ) + { + SignEntry e = list[i]; + Map[] maps = null; + + switch ( e.m_Map ) + { + case 0: maps = brit; break; // Trammel and Felucca + case 1: maps = fel; break; // Felucca + case 2: maps = tram; break; // Trammel + case 3: maps = ilsh; break; // Ilshenar + case 4: maps = malas; break; // Malas + case 5: maps = tokuno; break; // Tokuno Islands + } + + for ( int j = 0; maps != null && j < maps.Length; ++j ) + Add_Static( e.m_ItemID, e.m_Location, maps[j], e.m_Text ); + } + + from.SendMessage( "Sign generating complete." ); + } + else + { + from.SendMessage( "{0} not found!", cfg ); + } + } + + private static Queue m_ToDelete = new Queue(); + + public static void Add_Static( int itemID, Point3D location, Map map, string name ) + { + IPooledEnumerable eable = map.GetItemsInRange( location, 0 ); + + foreach ( Item item in eable ) + { + if ( item is Sign && item.Z == location.Z && item.ItemID == itemID ) + m_ToDelete.Enqueue( item ); + } + + eable.Free(); + + while ( m_ToDelete.Count > 0 ) + m_ToDelete.Dequeue().Delete(); + + Item sign; + + if ( name.StartsWith( "#" ) ) + { + sign = new LocalizedSign( itemID, Utility.ToInt32( name.Substring( 1 ) ) ); + } + else + { + sign = new Sign( itemID ); + sign.Name = name; + } + + if ( map == Map.Malas ) + { + if ( location.X >= 965 && location.Y >= 502 && location.X <= 1012 && location.Y <= 537 ) + sign.Hue = 0x47E; + else if ( location.X >= 1960 && location.Y >= 1278 && location.X < 2106 && location.Y < 1413 ) + sign.Hue = 0x44E; + } + + sign.MoveToWorld( location, map ); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Skills.cs b/Scripts/Commands/Skills.cs new file mode 100644 index 0000000..0cccac6 --- /dev/null +++ b/Scripts/Commands/Skills.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Server.Commands +{ + public class SkillsCommand + { + public static void Initialize() + { + CommandSystem.Register("SetSkill", AccessLevel.GameMaster, new CommandEventHandler(SetSkill_OnCommand)); + CommandSystem.Register("GetSkill", AccessLevel.GameMaster, new CommandEventHandler(GetSkill_OnCommand)); + CommandSystem.Register("SetAllSkills", AccessLevel.GameMaster, new CommandEventHandler(SetAllSkills_OnCommand)); + } + + [Usage("SetSkill ")] + [Description("Sets a skill value by name of a targeted mobile.")] + public static void SetSkill_OnCommand(CommandEventArgs arg) + { + if (arg.Length != 2) + { + arg.Mobile.SendMessage("SetSkill "); + } + else + { + SkillName skill; +#if Framework_4_0 + if( Enum.TryParse( arg.GetString( 0 ), true, out skill ) ) + { + arg.Mobile.Target = new SkillTarget( skill, arg.GetDouble( 1 ) ); + } + else + { + arg.Mobile.SendLocalizedMessage( 1005631 ); // You have specified an invalid skill to set. + } +#else + try + { + skill = (SkillName)Enum.Parse(typeof(SkillName), arg.GetString(0), true); + } + catch + { + arg.Mobile.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + return; + } + arg.Mobile.Target = new SkillTarget(skill, arg.GetDouble(1)); +#endif + } + } + + [Usage("SetAllSkills ")] + [Description("Sets all skill values of a targeted mobile.")] + public static void SetAllSkills_OnCommand(CommandEventArgs arg) + { + if (arg.Length != 1) + { + arg.Mobile.SendMessage("SetAllSkills "); + } + else + { + arg.Mobile.Target = new AllSkillsTarget(arg.GetDouble(0)); + } + } + + [Usage("GetSkill ")] + [Description("Gets a skill value by name of a targeted mobile.")] + public static void GetSkill_OnCommand(CommandEventArgs arg) + { + if (arg.Length != 1) + { + arg.Mobile.SendMessage("GetSkill "); + } + else + { + SkillName skill; +#if Framework_4_0 + if( Enum.TryParse( arg.GetString( 0 ), true, out skill ) ) + { + arg.Mobile.Target = new SkillTarget( skill ); + } + else + { + arg.Mobile.SendMessage( "You have specified an invalid skill to get." ); + } +#else + try + { + skill = (SkillName)Enum.Parse(typeof(SkillName), arg.GetString(0), true); + } + catch + { + arg.Mobile.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + return; + } + + arg.Mobile.Target = new SkillTarget(skill); +#endif + } + } + + public class AllSkillsTarget : Target + { + private double m_Value; + + public AllSkillsTarget(double value) + : base(-1, false, TargetFlags.None) + { + m_Value = value; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile) + { + Mobile targ = (Mobile)targeted; + Server.Skills skills = targ.Skills; + + for (int i = 0; i < skills.Length; ++i) + skills[i].Base = m_Value; + + CommandLogging.LogChangeProperty(from, targ, "EverySkill.Base", m_Value.ToString()); + } + else + { + from.SendMessage("That does not have skills!"); + } + } + } + + public class SkillTarget : Target + { + private bool m_Set; + private SkillName m_Skill; + private double m_Value; + + public SkillTarget(SkillName skill, double value) + : base(-1, false, TargetFlags.None) + { + m_Set = true; + m_Skill = skill; + m_Value = value; + } + + public SkillTarget(SkillName skill) + : base(-1, false, TargetFlags.None) + { + m_Set = false; + m_Skill = skill; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile) + { + Mobile targ = (Mobile)targeted; + Skill skill = targ.Skills[m_Skill]; + + if (skill == null) + return; + + if (m_Set) + { + skill.Base = m_Value; + CommandLogging.LogChangeProperty(from, targ, String.Format("{0}.Base", m_Skill), m_Value.ToString()); + } + + from.SendMessage("{0} : {1} (Base: {2})", m_Skill, skill.Value, skill.Base); + } + else + { + from.SendMessage("That does not have skills!"); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/SkillsMenu.cs b/Scripts/Commands/SkillsMenu.cs new file mode 100644 index 0000000..136543c --- /dev/null +++ b/Scripts/Commands/SkillsMenu.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Commands +{ + public class Skills + { + public static void Initialize() + { + Register(); + } + + public static void Register() + { + CommandSystem.Register( "Skills", AccessLevel.Counselor, new CommandEventHandler( Skills_OnCommand ) ); + } + + private class SkillsTarget : Target + { + public SkillsTarget( ) : base( -1, true, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + from.SendGump( new SkillsGump( from, (Mobile)o ) ); + } + } + + [Usage( "Skills" )] + [Description( "Opens a menu where you can view or edit skills of a targeted mobile." )] + private static void Skills_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new SkillsTarget(); + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/Statics.cs b/Scripts/Commands/Statics.cs new file mode 100644 index 0000000..966d1a3 --- /dev/null +++ b/Scripts/Commands/Statics.cs @@ -0,0 +1,570 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Commands; +using Server.Targeting; +using System.Collections.Generic; + +namespace Server +{ + public class Statics + { + public static void Initialize() + { + CommandSystem.Register( "Freeze", AccessLevel.Administrator, new CommandEventHandler( Freeze_OnCommand ) ); + CommandSystem.Register( "FreezeMap", AccessLevel.Administrator, new CommandEventHandler( FreezeMap_OnCommand ) ); + CommandSystem.Register( "FreezeWorld", AccessLevel.Administrator, new CommandEventHandler( FreezeWorld_OnCommand ) ); + + CommandSystem.Register( "Unfreeze", AccessLevel.Administrator, new CommandEventHandler( Unfreeze_OnCommand ) ); + CommandSystem.Register( "UnfreezeMap", AccessLevel.Administrator, new CommandEventHandler( UnfreezeMap_OnCommand ) ); + CommandSystem.Register( "UnfreezeWorld", AccessLevel.Administrator, new CommandEventHandler( UnfreezeWorld_OnCommand ) ); + } + + private static Point3D NullP3D = new Point3D( int.MinValue, int.MinValue, int.MinValue ); + + [Usage( "Freeze" )] + [Description( "Makes a targeted area of dynamic items static." )] + public static void Freeze_OnCommand( CommandEventArgs e ) + { + BoundingBoxPicker.Begin( e.Mobile, new BoundingBoxCallback( FreezeBox_Callback ), null ); + } + + [Usage( "FreezeMap" )] + [Description( "Makes every dynamic item in your map static." )] + public static void FreezeMap_OnCommand( CommandEventArgs e ) + { + Map map = e.Mobile.Map; + + if ( map != null && map != Map.Internal ) + SendWarning( e.Mobile, "You are about to freeze all items in {0}.", BaseFreezeWarning, map, NullP3D, NullP3D, new WarningGumpCallback( FreezeWarning_Callback ) ); + } + + [Usage( "FreezeWorld" )] + [Description( "Makes every dynamic item on all maps static." )] + public static void FreezeWorld_OnCommand( CommandEventArgs e ) + { + SendWarning( e.Mobile, "You are about to freeze every item on every map.", BaseFreezeWarning, null, NullP3D, NullP3D, new WarningGumpCallback( FreezeWarning_Callback ) ); + } + + public static void SendWarning( Mobile m, string header, string baseWarning, Map map, Point3D start, Point3D end, WarningGumpCallback callback ) + { + m.SendGump( new WarningGump( 1060635, 30720, String.Format( baseWarning, String.Format( header, map ) ), 0xFFC000, 420, 400, callback, new StateInfo( map, start, end ) ) ); + } + + private const string BaseFreezeWarning = "{0} " + + "Those items will be removed from the world and placed into the server data files. " + + "Other players will not see the changes unless you distribute your data files to them.

" + + "This operation may not complete unless the server and client are using different data files. " + + "If you receive a message stating 'output data files could not be opened,' then you are probably sharing data files. " + + "Create a new directory for the world data files (statics*.mul and staidx*.mul) and add that to Scritps/Misc/DataPath.cs.

" + + "The change will be in effect immediately on the server, however, you must restart your client and update it's data files for the changes to become visible. " + + "It is strongly recommended that you make backup of the data files mentioned above. " + + "Do you wish to proceed?"; + + private static void FreezeBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state ) + { + SendWarning( from, "You are about to freeze a section of items.", BaseFreezeWarning, map, start, end, new WarningGumpCallback( FreezeWarning_Callback ) ); + } + + private static void FreezeWarning_Callback( Mobile from, bool okay, object state ) + { + if ( !okay ) + return; + + StateInfo si = (StateInfo)state; + + Freeze( from, si.m_Map, si.m_Start, si.m_End ); + } + + public static void Freeze( Mobile from, Map targetMap, Point3D start3d, Point3D end3d ) + { + Hashtable mapTable = new Hashtable(); + + if ( start3d == NullP3D && end3d == NullP3D ) + { + if ( targetMap == null ) + CommandLogging.WriteLine( from, "{0} {1} invoking freeze for every item in every map", from.AccessLevel, CommandLogging.Format( from ) ); + else + CommandLogging.WriteLine( from, "{0} {1} invoking freeze for every item in {0}", from.AccessLevel, CommandLogging.Format( from ), targetMap ); + + foreach ( Item item in World.Items.Values ) + { + if ( targetMap != null && item.Map != targetMap ) + continue; + + if ( item.Parent != null ) + continue; + + if ( item is Static || item is BaseFloor || item is BaseWall ) + { + Map itemMap = item.Map; + + if ( itemMap == null || itemMap == Map.Internal ) + continue; + + Hashtable table = (Hashtable)mapTable[itemMap]; + + if ( table == null ) + mapTable[itemMap] = table = new Hashtable(); + + Point2D p = new Point2D( item.X >> 3, item.Y >> 3 ); + + DeltaState state = (DeltaState)table[p]; + + if ( state == null ) + table[p] = state = new DeltaState( p ); + + state.m_List.Add( item ); + } + } + } + else if ( targetMap != null ) + { + Point2D start = targetMap.Bound( new Point2D( start3d ) ), end = targetMap.Bound( new Point2D( end3d ) ); + + CommandLogging.WriteLine( from, "{0} {1} invoking freeze from {2} to {3} in {4}", from.AccessLevel, CommandLogging.Format( from ), start, end, targetMap ); + + IPooledEnumerable eable = targetMap.GetItemsInBounds( new Rectangle2D( start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1 ) ); + + foreach ( Item item in eable ) + { + if ( item is Static || item is BaseFloor || item is BaseWall ) + { + Map itemMap = item.Map; + + if ( itemMap == null || itemMap == Map.Internal ) + continue; + + Hashtable table = (Hashtable)mapTable[itemMap]; + + if ( table == null ) + mapTable[itemMap] = table = new Hashtable(); + + Point2D p = new Point2D( item.X >> 3, item.Y >> 3 ); + + DeltaState state = (DeltaState)table[p]; + + if ( state == null ) + table[p] = state = new DeltaState( p ); + + state.m_List.Add( item ); + } + } + + eable.Free(); + } + + if ( mapTable.Count == 0 ) + { + from.SendGump( new NoticeGump( 1060637, 30720, "No freezable items were found. Only the following item types are frozen:
- Static
- BaseFloor
- BaseWall", 0xFFC000, 320, 240, null, null ) ); + return; + } + + bool badDataFile = false; + + int totalFrozen = 0; + + foreach ( DictionaryEntry de in mapTable ) + { + Map map = (Map)de.Key; + Hashtable table = (Hashtable)de.Value; + + TileMatrix matrix = map.Tiles; + + using ( FileStream idxStream = OpenWrite( matrix.IndexStream ) ) + { + using ( FileStream mulStream = OpenWrite( matrix.DataStream ) ) + { + if ( idxStream == null || mulStream == null ) + { + badDataFile = true; + continue; + } + + BinaryReader idxReader = new BinaryReader( idxStream ); + + BinaryWriter idxWriter = new BinaryWriter( idxStream ); + BinaryWriter mulWriter = new BinaryWriter( mulStream ); + + foreach ( DeltaState state in table.Values ) + { + int oldTileCount; + StaticTile[] oldTiles = ReadStaticBlock( idxReader, mulStream, state.m_X, state.m_Y, matrix.BlockWidth, matrix.BlockHeight, out oldTileCount ); + + if ( oldTileCount < 0 ) + continue; + + int newTileCount = 0; + StaticTile[] newTiles = new StaticTile[state.m_List.Count]; + + for ( int i = 0; i < state.m_List.Count; ++i ) + { + Item item = state.m_List[i]; + + int xOffset = item.X - (state.m_X * 8); + int yOffset = item.Y - (state.m_Y * 8); + + if ( xOffset < 0 || xOffset >= 8 || yOffset < 0 || yOffset >= 8 ) + continue; + + StaticTile newTile = new StaticTile( (ushort)item.ItemID, (byte)xOffset, (byte)yOffset, (sbyte)item.Z, (short)item.Hue ); + + newTiles[newTileCount++] = newTile; + + item.Delete(); + + ++totalFrozen; + } + + int mulPos = -1; + int length = -1; + int extra = 0; + + if ( (oldTileCount + newTileCount) > 0 ) + { + mulWriter.Seek( 0, SeekOrigin.End ); + + mulPos = (int)mulWriter.BaseStream.Position; + length = (oldTileCount + newTileCount) * 7; + extra = 1; + + for ( int i = 0; i < oldTileCount; ++i ) + { + StaticTile toWrite = oldTiles[i]; + + mulWriter.Write( (ushort) toWrite.ID ); + mulWriter.Write( (byte) toWrite.X ); + mulWriter.Write( (byte) toWrite.Y ); + mulWriter.Write( (sbyte) toWrite.Z ); + mulWriter.Write( (short) toWrite.Hue ); + } + + for ( int i = 0; i < newTileCount; ++i ) + { + StaticTile toWrite = newTiles[i]; + + mulWriter.Write( (ushort) toWrite.ID ); + mulWriter.Write( (byte) toWrite.X ); + mulWriter.Write( (byte) toWrite.Y ); + mulWriter.Write( (sbyte) toWrite.Z ); + mulWriter.Write( (short) toWrite.Hue ); + } + + mulWriter.Flush(); + } + + int idxPos = ((state.m_X * matrix.BlockHeight) + state.m_Y) * 12; + + idxWriter.Seek( idxPos, SeekOrigin.Begin ); + idxWriter.Write( mulPos ); + idxWriter.Write( length ); + idxWriter.Write( extra ); + + idxWriter.Flush(); + + matrix.SetStaticBlock( state.m_X, state.m_Y, null ); + } + } + } + } + + if ( totalFrozen == 0 && badDataFile ) + from.SendGump( new NoticeGump( 1060637, 30720, "Output data files could not be opened and the freeze operation has been aborted.

This probably means your server and client are using the same data files. Instructions on how to resolve this can be found in the first warning window.", 0xFFC000, 320, 240, null, null ) ); + else + from.SendGump( new NoticeGump( 1060637, 30720, String.Format( "Freeze operation completed successfully.

{0} item{1} frozen.

You must restart your client and update it's data files to see the changes.", totalFrozen, totalFrozen != 1 ? "s were" : " was" ), 0xFFC000, 320, 240, null, null ) ); + } + + private const string BaseUnfreezeWarning = "{0} " + + "Those items will be removed from the static files and exchanged with unmovable dynamic items. " + + "Other players will not see the changes unless you distribute your data files to them.

" + + "This operation may not complete unless the server and client are using different data files. " + + "If you receive a message stating 'output data files could not be opened,' then you are probably sharing data files. " + + "Create a new directory for the world data files (statics*.mul and staidx*.mul) and add that to Scritps/Misc/DataPath.cs.

" + + "The change will be in effect immediately on the server, however, you must restart your client and update it's data files for the changes to become visible. " + + "It is strongly recommended that you make backup of the data files mentioned above. " + + "Do you wish to proceed?"; + + [Usage( "Unfreeze" )] + [Description( "Makes a targeted area of static items dynamic." )] + public static void Unfreeze_OnCommand( CommandEventArgs e ) + { + BoundingBoxPicker.Begin( e.Mobile, new BoundingBoxCallback( UnfreezeBox_Callback ), null ); + } + + [Usage( "UnfreezeMap" )] + [Description( "Makes every static item in your map dynamic." )] + public static void UnfreezeMap_OnCommand( CommandEventArgs e ) + { + Map map = e.Mobile.Map; + + if ( map != null && map != Map.Internal ) + SendWarning( e.Mobile, "You are about to unfreeze all items in {0}.", BaseUnfreezeWarning, map, NullP3D, NullP3D, new WarningGumpCallback( UnfreezeWarning_Callback ) ); + } + + [Usage( "UnfreezeWorld" )] + [Description( "Makes every static item on all maps dynamic." )] + public static void UnfreezeWorld_OnCommand( CommandEventArgs e ) + { + SendWarning( e.Mobile, "You are about to unfreeze every item on every map.", BaseUnfreezeWarning, null, NullP3D, NullP3D, new WarningGumpCallback( UnfreezeWarning_Callback ) ); + } + + private static void UnfreezeBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state ) + { + SendWarning( from, "You are about to unfreeze a section of items.", BaseUnfreezeWarning, map, start, end, new WarningGumpCallback( UnfreezeWarning_Callback ) ); + } + + private static void UnfreezeWarning_Callback( Mobile from, bool okay, object state ) + { + if ( !okay ) + return; + + StateInfo si = (StateInfo)state; + + Unfreeze( from, si.m_Map, si.m_Start, si.m_End ); + } + + private static void DoUnfreeze( Map map, Point2D start, Point2D end, ref bool badDataFile, ref int totalUnfrozen ) + { + start = map.Bound( start ); + end = map.Bound( end ); + + int xStartBlock = start.X >> 3; + int yStartBlock = start.Y >> 3; + int xEndBlock = end.X >> 3; + int yEndBlock = end.Y >> 3; + + int xTileStart = start.X, yTileStart = start.Y; + int xTileWidth = end.X - start.X + 1, yTileHeight = end.Y - start.Y + 1; + + TileMatrix matrix = map.Tiles; + + using ( FileStream idxStream = OpenWrite( matrix.IndexStream ) ) + { + using ( FileStream mulStream = OpenWrite( matrix.DataStream ) ) + { + if ( idxStream == null || mulStream == null ) + { + badDataFile = true; + return; + } + + BinaryReader idxReader = new BinaryReader( idxStream ); + + BinaryWriter idxWriter = new BinaryWriter( idxStream ); + BinaryWriter mulWriter = new BinaryWriter( mulStream ); + + for ( int x = xStartBlock; x <= xEndBlock; ++x ) + { + for ( int y = yStartBlock; y <= yEndBlock; ++y ) + { + int oldTileCount; + StaticTile[] oldTiles = ReadStaticBlock( idxReader, mulStream, x, y, matrix.BlockWidth, matrix.BlockHeight, out oldTileCount ); + + if ( oldTileCount < 0 ) + continue; + + int newTileCount = 0; + StaticTile[] newTiles = new StaticTile[oldTileCount]; + + int baseX = (x << 3) - xTileStart, baseY = (y << 3) - yTileStart; + + for ( int i = 0; i < oldTileCount; ++i ) + { + StaticTile oldTile = oldTiles[i]; + + int px = baseX + oldTile.X; + int py = baseY + oldTile.Y; + + if ( px < 0 || px >= xTileWidth || py < 0 || py >= yTileHeight ) + { + newTiles[newTileCount++] = oldTile; + } + else + { + ++totalUnfrozen; + + Item item = new Static( oldTile.ID ); + + item.Hue = oldTile.Hue; + + item.MoveToWorld( new Point3D( px + xTileStart, py + yTileStart, oldTile.Z ), map ); + } + } + + int mulPos = -1; + int length = -1; + int extra = 0; + + if ( newTileCount > 0 ) + { + mulWriter.Seek( 0, SeekOrigin.End ); + + mulPos = (int)mulWriter.BaseStream.Position; + length = newTileCount * 7; + extra = 1; + + for ( int i = 0; i < newTileCount; ++i ) + { + StaticTile toWrite = newTiles[i]; + + mulWriter.Write( (ushort) toWrite.ID ); + mulWriter.Write( (byte) toWrite.X ); + mulWriter.Write( (byte) toWrite.Y ); + mulWriter.Write( (sbyte) toWrite.Z ); + mulWriter.Write( (short) toWrite.Hue ); + } + + mulWriter.Flush(); + } + + int idxPos = ((x * matrix.BlockHeight) + y) * 12; + + idxWriter.Seek( idxPos, SeekOrigin.Begin ); + idxWriter.Write( mulPos ); + idxWriter.Write( length ); + idxWriter.Write( extra ); + + idxWriter.Flush(); + + matrix.SetStaticBlock( x, y, null ); + } + } + } + } + } + + public static void DoUnfreeze( Map map, ref bool badDataFile, ref int totalUnfrozen ) + { + DoUnfreeze( map, Point2D.Zero, new Point2D( map.Width - 1, map.Height - 1 ), ref badDataFile, ref totalUnfrozen ); + } + + public static void Unfreeze( Mobile from, Map map, Point3D start, Point3D end ) + { + int totalUnfrozen = 0; + bool badDataFile = false; + + if ( map == null ) + { + CommandLogging.WriteLine( from, "{0} {1} invoking unfreeze for every item in every map", from.AccessLevel, CommandLogging.Format( from ) ); + + DoUnfreeze( Map.Felucca, ref badDataFile, ref totalUnfrozen ); + DoUnfreeze( Map.Trammel, ref badDataFile, ref totalUnfrozen ); + DoUnfreeze( Map.Ilshenar, ref badDataFile, ref totalUnfrozen ); + DoUnfreeze( Map.Malas, ref badDataFile, ref totalUnfrozen ); + DoUnfreeze( Map.Tokuno, ref badDataFile, ref totalUnfrozen ); + } + else if ( start == NullP3D && end == NullP3D ) + { + CommandLogging.WriteLine( from, "{0} {1} invoking unfreeze for every item in {2}", from.AccessLevel, CommandLogging.Format( from ), map ); + + DoUnfreeze( map, ref badDataFile, ref totalUnfrozen ); + } + else + { + CommandLogging.WriteLine( from, "{0} {1} invoking unfreeze from {2} to {3} in {4}", from.AccessLevel, CommandLogging.Format( from ), new Point2D( start ), new Point2D( end ), map ); + + DoUnfreeze( map, new Point2D( start ), new Point2D( end ), ref badDataFile, ref totalUnfrozen ); + } + + if ( totalUnfrozen == 0 && badDataFile ) + from.SendGump( new NoticeGump( 1060637, 30720, "Output data files could not be opened and the unfreeze operation has been aborted.

This probably means your server and client are using the same data files. Instructions on how to resolve this can be found in the first warning window.", 0xFFC000, 320, 240, null, null ) ); + else + from.SendGump( new NoticeGump( 1060637, 30720, String.Format( "Unfreeze operation completed successfully.

{0} item{1} unfrozen.

You must restart your client and update it's data files to see the changes.", totalUnfrozen, totalUnfrozen != 1 ? "s were" : " was" ), 0xFFC000, 320, 240, null, null ) ); + } + + private static FileStream OpenWrite( FileStream orig ) + { + if ( orig == null ) + return null; + + try{ return new FileStream( orig.Name, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite ); } + catch{ return null; } + } + + private static byte[] m_Buffer; + + private static StaticTile[] m_TileBuffer = new StaticTile[128]; + + private static StaticTile[] ReadStaticBlock( BinaryReader idxReader, FileStream mulStream, int x, int y, int width, int height, out int count ) + { + try + { + if ( x < 0 || x >= width || y < 0 || y >= height ) + { + count = -1; + return m_TileBuffer; + } + + idxReader.BaseStream.Seek( ((x * height) + y) * 12, SeekOrigin.Begin ); + + int lookup = idxReader.ReadInt32(); + int length = idxReader.ReadInt32(); + + if ( lookup < 0 || length <= 0 ) + { + count = 0; + } + else + { + count = length / 7; + + mulStream.Seek( lookup, SeekOrigin.Begin ); + + if ( m_TileBuffer.Length < count ) + m_TileBuffer = new StaticTile[count]; + + StaticTile[] staTiles = m_TileBuffer; + + if ( m_Buffer == null || length > m_Buffer.Length ) + m_Buffer = new byte[length]; + + mulStream.Read( m_Buffer, 0, length ); + + int index = 0; + + for ( int i = 0; i < count; ++i ) + { + staTiles[i].Set((ushort)(m_Buffer[index++] | (m_Buffer[index++] << 8)), + (byte)m_Buffer[index++], (byte)m_Buffer[index++], (sbyte)m_Buffer[index++], + (short)(m_Buffer[index++] | (m_Buffer[index++] << 8))); + } + } + } + catch + { + count = -1; + } + + return m_TileBuffer; + } + + private class DeltaState + { + public int m_X, m_Y; + public List m_List; + + public DeltaState( Point2D p ) + { + m_X = p.X; + m_Y = p.Y; + m_List = new List(); + } + } + + private class StateInfo + { + public Map m_Map; + public Point3D m_Start, m_End; + + public StateInfo( Map map, Point3D start, Point3D end ) + { + m_Map = map; + m_Start = start; + m_End = end; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Commands/VisibilityList.cs b/Scripts/Commands/VisibilityList.cs new file mode 100644 index 0000000..134cad7 --- /dev/null +++ b/Scripts/Commands/VisibilityList.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Commands +{ + public class VisibilityList + { + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( OnLogin ); + + CommandSystem.Register( "Vis", AccessLevel.Counselor, new CommandEventHandler( Vis_OnCommand ) ); + CommandSystem.Register( "VisList", AccessLevel.Counselor, new CommandEventHandler( VisList_OnCommand ) ); + CommandSystem.Register( "VisClear", AccessLevel.Counselor, new CommandEventHandler( VisClear_OnCommand ) ); + } + + public static void OnLogin( LoginEventArgs e ) + { + if ( e.Mobile is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)e.Mobile; + + pm.VisibilityList.Clear(); + } + } + + [Usage( "Vis" )] + [Description( "Adds or removes a targeted player from your visibility list. Anyone on your visibility list will be able to see you at all times, even when you're hidden." )] + public static void Vis_OnCommand( CommandEventArgs e ) + { + if ( e.Mobile is PlayerMobile ) + { + e.Mobile.Target = new VisTarget(); + e.Mobile.SendMessage( "Select person to add or remove from your visibility list." ); + } + } + + [Usage( "VisList" )] + [Description( "Shows the names of everyone in your visibility list." )] + public static void VisList_OnCommand( CommandEventArgs e ) + { + if ( e.Mobile is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)e.Mobile; + List list = pm.VisibilityList; + + if ( list.Count > 0 ) + { + pm.SendMessage( "You are visible to {0} mobile{1}:", list.Count, list.Count == 1 ? "" : "s" ); + + for ( int i = 0; i < list.Count; ++i ) + pm.SendMessage( "#{0}: {1}", i+1, list[i].Name ); + } + else + { + pm.SendMessage( "Your visibility list is empty." ); + } + } + } + + [Usage( "VisClear" )] + [Description( "Removes everyone from your visibility list." )] + public static void VisClear_OnCommand( CommandEventArgs e ) + { + if ( e.Mobile is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)e.Mobile; + List list = new List( pm.VisibilityList ); + + pm.VisibilityList.Clear(); + pm.SendMessage( "Your visibility list has been cleared." ); + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = list[i]; + + if ( !m.CanSee( pm ) && Utility.InUpdateRange( m, pm ) ) + m.Send( pm.RemovePacket ); + } + } + } + + private class VisTarget : Target + { + public VisTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( from is PlayerMobile && targeted is Mobile ) + { + PlayerMobile pm = (PlayerMobile)from; + Mobile targ = (Mobile)targeted; + + if ( targ.AccessLevel <= from.AccessLevel ) + { + List list = pm.VisibilityList; + + if ( list.Contains( targ ) ) + { + list.Remove( targ ); + from.SendMessage( "{0} has been removed from your visibility list.", targ.Name ); + } + else + { + list.Add( targ ); + from.SendMessage( "{0} has been added to your visibility list.", targ.Name ); + } + + if ( Utility.InUpdateRange( targ, from ) ) + { + NetState ns = targ.NetState; + + if ( ns != null ) { + if ( targ.CanSee( from ) ) + { + ns.Send(MobileIncoming.Create(ns, targ, from)); + + if ( ObjectPropertyList.Enabled ) + { + ns.Send( from.OPLPacket ); + + foreach ( Item item in from.Items ) + ns.Send( item.OPLPacket ); + } + } + else + { + ns.Send( from.RemovePacket ); + } + } + } + } + else + { + from.SendMessage( "They can already see you!" ); + } + } + else + { + from.SendMessage( "Add only mobiles to your visibility list." ); + } + } + } + } +} diff --git a/Scripts/Commands/Wipe.cs b/Scripts/Commands/Wipe.cs new file mode 100644 index 0000000..7eccc86 --- /dev/null +++ b/Scripts/Commands/Wipe.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Multis; +using Server.Targeting; + +namespace Server.Commands +{ + public class Wipe + { + [Flags] + public enum WipeType + { + Items = 0x01, + Mobiles = 0x02, + Multis = 0x04, + All = Items | Mobiles | Multis + } + + public static void Initialize() + { + CommandSystem.Register( "Wipe", AccessLevel.GameMaster, new CommandEventHandler( WipeAll_OnCommand ) ); + CommandSystem.Register( "WipeItems", AccessLevel.GameMaster, new CommandEventHandler( WipeItems_OnCommand ) ); + CommandSystem.Register( "WipeNPCs", AccessLevel.GameMaster, new CommandEventHandler( WipeNPCs_OnCommand ) ); + CommandSystem.Register( "WipeMultis", AccessLevel.GameMaster, new CommandEventHandler( WipeMultis_OnCommand ) ); + } + + [Usage( "Wipe" )] + [Description( "Wipes all items and npcs in a targeted bounding box." )] + private static void WipeAll_OnCommand( CommandEventArgs e ) + { + BeginWipe( e.Mobile, WipeType.Items | WipeType.Mobiles ); + } + + [Usage( "WipeItems" )] + [Description( "Wipes all items in a targeted bounding box." )] + private static void WipeItems_OnCommand( CommandEventArgs e ) + { + BeginWipe( e.Mobile, WipeType.Items ); + } + + [Usage( "WipeNPCs" )] + [Description( "Wipes all npcs in a targeted bounding box." )] + private static void WipeNPCs_OnCommand( CommandEventArgs e ) + { + BeginWipe( e.Mobile, WipeType.Mobiles ); + } + + [Usage( "WipeMultis" )] + [Description( "Wipes all multis in a targeted bounding box." )] + private static void WipeMultis_OnCommand( CommandEventArgs e ) + { + BeginWipe( e.Mobile, WipeType.Multis ); + } + + public static void BeginWipe( Mobile from, WipeType type ) + { + BoundingBoxPicker.Begin( from, new BoundingBoxCallback( WipeBox_Callback ), type ); + } + + private static void WipeBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state ) + { + DoWipe( from, map, start, end, (WipeType)state ); + } + + public static void DoWipe( Mobile from, Map map, Point3D start, Point3D end, WipeType type ) + { + CommandLogging.WriteLine( from, "{0} {1} wiping from {2} to {3} in {5} ({4})", from.AccessLevel, CommandLogging.Format( from ), start, end, type, map ); + + bool mobiles = ( (type & WipeType.Mobiles) != 0 ); + bool multis = ( (type & WipeType.Multis) != 0 ); + bool items = ( (type & WipeType.Items) != 0 ); + + List toDelete = new List(); + + Rectangle2D rect = new Rectangle2D( start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1 ); + + IPooledEnumerable eable; + + if ( (items || multis) && mobiles ) + eable = map.GetObjectsInBounds( rect ); + else if ( items || multis ) + eable = map.GetItemsInBounds( rect ); + else if ( mobiles ) + eable = map.GetMobilesInBounds( rect ); + else + return; + + foreach ( IEntity obj in eable ) + { + if ( items && (obj is Item) && !((obj is BaseMulti) || (obj is HouseSign)) ) + toDelete.Add( obj ); + else if ( multis && (obj is BaseMulti) ) + toDelete.Add( obj ); + else if ( mobiles && (obj is Mobile) && !((Mobile)obj).Player ) + toDelete.Add( obj ); + } + + eable.Free(); + + for ( int i = 0; i < toDelete.Count; ++i ) + toDelete[i].Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Context Menus/AddToParty.cs b/Scripts/Context Menus/AddToParty.cs new file mode 100644 index 0000000..18f9cb2 --- /dev/null +++ b/Scripts/Context Menus/AddToParty.cs @@ -0,0 +1,39 @@ +using System; +using Server.Mobiles; +using Server.Engines.PartySystem; + +namespace Server.ContextMenus +{ + public class AddToPartyEntry : ContextMenuEntry + { + private Mobile m_From; + private Mobile m_Target; + + public AddToPartyEntry( Mobile from, Mobile target ) : base( 0197, 12 ) + { + m_From = from; + m_Target = target; + } + + public override void OnClick() + { + Party p = Party.Get( m_From ); + Party mp = Party.Get( m_Target ); + + if ( m_From == m_Target ) + m_From.SendLocalizedMessage( 1005439 ); // You cannot add yourself to a party. + else if ( p != null && p.Leader != m_From ) + m_From.SendLocalizedMessage( 1005453 ); // You may only add members to the party if you are the leader. + else if ( p != null && (p.Members.Count + p.Candidates.Count) >= Party.Capacity ) + m_From.SendLocalizedMessage( 1008095 ); // You may only have 10 in your party (this includes candidates). + else if ( !m_Target.Player ) + m_From.SendLocalizedMessage( 1005444 ); // The creature ignores your offer. + else if ( mp != null && mp == p ) + m_From.SendLocalizedMessage( 1005440 ); // This person is already in your party! + else if ( mp != null ) + m_From.SendLocalizedMessage( 1005441 ); // This person is already in a party! + else + Party.Invite( m_From, m_Target ); + } + } +} diff --git a/Scripts/Context Menus/AddToSpellbookEntry.cs b/Scripts/Context Menus/AddToSpellbookEntry.cs new file mode 100644 index 0000000..d0a2040 --- /dev/null +++ b/Scripts/Context Menus/AddToSpellbookEntry.cs @@ -0,0 +1,64 @@ +using System; +using Server.Items; +using Server.Network; +using Server.Targeting; + +namespace Server.ContextMenus +{ + public class AddToSpellbookEntry : ContextMenuEntry + { + public AddToSpellbookEntry() : base( 6144, 3 ) + { + } + + public override void OnClick() + { + if ( Owner.From.CheckAlive() && Owner.Target is SpellScroll ) + Owner.From.Target = new InternalTarget( (SpellScroll)Owner.Target ); + } + + private class InternalTarget : Target + { + private SpellScroll m_Scroll; + + public InternalTarget( SpellScroll scroll ) : base( 3, false, TargetFlags.None ) + { + m_Scroll = scroll; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Spellbook ) + { + if ( from.CheckAlive() && !m_Scroll.Deleted && m_Scroll.Movable && m_Scroll.Amount >= 1 && m_Scroll.CheckItemUse( from ) ) + { + Spellbook book = (Spellbook)targeted; + + SpellbookType type = Spellbook.GetTypeForSpell( m_Scroll.SpellID ); + + if ( type != book.SpellbookType ) + { + } + else if ( book.HasSpell( m_Scroll.SpellID ) ) + { + from.SendLocalizedMessage( 500179 ); // That spell is already present in that spellbook. + } + else + { + int val = m_Scroll.SpellID - book.BookOffset; + + if ( val >= 0 && val < book.BookCount ) + { + book.Content |= (ulong)1 << val; + + m_Scroll.Consume(); + + from.Send( new Network.PlaySound( 0x249, book.GetWorldLocation() ) ); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Context Menus/EatEntry.cs b/Scripts/Context Menus/EatEntry.cs new file mode 100644 index 0000000..b9d3fbd --- /dev/null +++ b/Scripts/Context Menus/EatEntry.cs @@ -0,0 +1,25 @@ +using System; +using Server.Items; + +namespace Server.ContextMenus +{ + public class EatEntry : ContextMenuEntry + { + private Mobile m_From; + private Food m_Food; + + public EatEntry( Mobile from, Food food ) : base( 6135, 1 ) + { + m_From = from; + m_Food = food; + } + + public override void OnClick() + { + if ( m_Food.Deleted || !m_Food.Movable || !m_From.CheckAlive() || !m_Food.CheckItemUse( m_From ) ) + return; + + m_Food.Eat( m_From ); + } + } +} \ No newline at end of file diff --git a/Scripts/Context Menus/EjectPlayer.cs b/Scripts/Context Menus/EjectPlayer.cs new file mode 100644 index 0000000..3ecb550 --- /dev/null +++ b/Scripts/Context Menus/EjectPlayer.cs @@ -0,0 +1,31 @@ +using System; +using Server.Mobiles; +using Server.Multis; + +namespace Server.ContextMenus +{ + public class EjectPlayerEntry : ContextMenuEntry + { + private Mobile m_From; + private Mobile m_Target; + private BaseHouse m_TargetHouse; + + public EjectPlayerEntry( Mobile from, Mobile target ) : base( 6206, 12 ) + { + m_From = from; + m_Target = target; + m_TargetHouse = BaseHouse.FindHouseAt( m_Target ); + } + + public override void OnClick() + { + if ( !m_From.Alive || m_TargetHouse.Deleted || !m_TargetHouse.IsFriend( m_From ) ) + return; + + if ( m_Target is Mobile ) + { + m_TargetHouse.Kick( m_From, (Mobile)m_Target ); + } + } + } +} diff --git a/Scripts/Context Menus/OpenBankEntry.cs b/Scripts/Context Menus/OpenBankEntry.cs new file mode 100644 index 0000000..c35c610 --- /dev/null +++ b/Scripts/Context Menus/OpenBankEntry.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.ContextMenus +{ + public class OpenBankEntry : ContextMenuEntry + { + private Mobile m_Banker; + + public OpenBankEntry( Mobile from, Mobile banker ) : base( 6105, 12 ) + { + m_Banker = banker; + } + + public override void OnClick() + { + if ( !Owner.From.CheckAlive() ) + return; + + if ( Owner.From.Criminal ) + { + m_Banker.Say( 500378 ); // Thou art a criminal and cannot access thy bank box. + } + else + { + // Scriptiz : si ligne de vue ok, sinon message + if (this.Owner.From.InLOS(m_Banker)) + this.Owner.From.BankBox.Open(); + else + this.Owner.From.SendMessage("You can't reach that."); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Context Menus/TeachEntry.cs b/Scripts/Context Menus/TeachEntry.cs new file mode 100644 index 0000000..da0fbe3 --- /dev/null +++ b/Scripts/Context Menus/TeachEntry.cs @@ -0,0 +1,30 @@ +using System; +using Server.Mobiles; + +namespace Server.ContextMenus +{ + public class TeachEntry : ContextMenuEntry + { + private SkillName m_Skill; + private BaseCreature m_Mobile; + private Mobile m_From; + + public TeachEntry( SkillName skill, BaseCreature m, Mobile from, bool enabled ) : base( 6000 + (int)skill ) + { + m_Skill = skill; + m_Mobile = m; + m_From = from; + + if ( !enabled ) + Flags |= Network.CMEFlags.Disabled; + } + + public override void OnClick() + { + if ( !m_From.CheckAlive() ) + return; + + m_Mobile.Teach( m_Skill, m_From, 0, false ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/BloodyBandageSystemV2.0/BloodyBandage.cs b/Scripts/Customs/BloodyBandageSystemV2.0/BloodyBandage.cs new file mode 100644 index 0000000..c02ae1b --- /dev/null +++ b/Scripts/Customs/BloodyBandageSystemV2.0/BloodyBandage.cs @@ -0,0 +1,560 @@ +/************************************** +* Bloody Bandage System V2.0 * +* Distro files: Bandage.cs * +* * +* Made by Demortris AKA Joeku * +* 10/11/2005 * +* * +* Anyone can modify/redistribute this * +* DO NOT REMOVE/CHANGE THIS HEADER! * +**************************************/ + +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Items +{ + //[FlipableAttribute( 0xE20, 0xE22 )] + public class BloodyBandage : Item + { + + [Constructable] + public BloodyBandage() + : this(1) + { + } + + [Constructable] + public BloodyBandage(int amount) + : base(0xE20) + { + Stackable = true; + Weight = 0.1; + Amount = amount; + } + + public BloodyBandage(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + from.RevealingAction(); + if (this.Amount > 1) + { + from.SendMessage("What will you wash the bloody bandages in?"); + } + else + { + from.SendMessage("What will you wash the bloody bandage in?"); + } + from.Target = new InternalTarget(this); + } + + private class InternalTarget : Target + { + private BloodyBandage m_Bandage; + + public InternalTarget(BloodyBandage bandage) + : base(3, true, TargetFlags.Beneficial) + { + m_Bandage = bandage; + } + + protected override void OnTarget(Mobile from, object targeted) + { + StaticTarget a = targeted as StaticTarget; + Item b = targeted as Item; + LandTarget c = targeted as LandTarget; + + if (m_Bandage.Deleted) + return; + + if (targeted == a) + { + if ((a.ItemID >= 5937 && a.ItemID <= 5978) || (a.ItemID >= 6038 && a.ItemID <= 6066) || (a.ItemID >= 6595 && a.ItemID <= 6636) || (a.ItemID >= 8093 && a.ItemID <= 8094) || (a.ItemID >= 8099 && a.ItemID <= 8138) || (a.ItemID >= 9299 && a.ItemID <= 9309) || (a.ItemID >= 13422 && a.ItemID <= 13525) || (a.ItemID >= 13549 && a.ItemID <= 13616) || (a.ItemID == 3707) || (a.ItemID >= 4088 && a.ItemID <= 4089) || (a.ItemID == 4104) || (a.ItemID == 5453) || (a.ItemID >= 5458 && a.ItemID <= 5460) || (a.ItemID == 5465) || (a.ItemID >= 2881 && a.ItemID <= 2884)) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else + { + from.SendMessage("You can only wash bloody bandages in water."); + } + } + else if (targeted == b) + { + if ((b.ItemID >= 5937 && b.ItemID <= 5978) || (b.ItemID >= 6038 && b.ItemID <= 6066) || (b.ItemID >= 6595 && b.ItemID <= 6636) || (b.ItemID >= 8099 && b.ItemID <= 8138) || (b.ItemID >= 9299 && b.ItemID <= 9309) || (b.ItemID >= 13422 && b.ItemID <= 13525) || (b.ItemID >= 13549 && b.ItemID <= 13616) || (b.ItemID == 3707) || (b.ItemID == 4104) || (b.ItemID == 5453) || (b.ItemID >= 5458 && b.ItemID <= 5460) || (b.ItemID == 5465) || (b.ItemID >= 2881 && b.ItemID <= 2884)) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (b is BaseBeverage) + { + BaseBeverage bev = b as BaseBeverage; + + if (bev.Content == BeverageType.Water) + { + if (bev.Quantity == 10 && m_Bandage.Amount <= 100) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 91) + { + bev.Quantity = (bev.Quantity - 10); + } + else if (m_Bandage.Amount >= 81) + { + bev.Quantity = (bev.Quantity - 9); + } + else if (m_Bandage.Amount >= 71) + { + bev.Quantity = (bev.Quantity - 8); + } + else if (m_Bandage.Amount >= 61) + { + bev.Quantity = (bev.Quantity - 7); + } + else if (m_Bandage.Amount >= 51) + { + bev.Quantity = (bev.Quantity - 6); + } + else if (m_Bandage.Amount >= 41) + { + bev.Quantity = (bev.Quantity - 5); + } + else if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 9 && m_Bandage.Amount <= 90) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 81) + { + bev.Quantity = (bev.Quantity - 9); + } + else if (m_Bandage.Amount >= 71) + { + bev.Quantity = (bev.Quantity - 8); + } + else if (m_Bandage.Amount >= 61) + { + bev.Quantity = (bev.Quantity - 7); + } + else if (m_Bandage.Amount >= 51) + { + bev.Quantity = (bev.Quantity - 6); + } + else if (m_Bandage.Amount >= 41) + { + bev.Quantity = (bev.Quantity - 5); + } + else if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 8 && m_Bandage.Amount <= 80) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 71) + { + bev.Quantity = (bev.Quantity - 8); + } + else if (m_Bandage.Amount >= 61) + { + bev.Quantity = (bev.Quantity - 7); + } + else if (m_Bandage.Amount >= 51) + { + bev.Quantity = (bev.Quantity - 6); + } + else if (m_Bandage.Amount >= 41) + { + bev.Quantity = (bev.Quantity - 5); + } + else if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 7 && m_Bandage.Amount <= 70) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 61) + { + bev.Quantity = (bev.Quantity - 7); + } + else if (m_Bandage.Amount >= 51) + { + bev.Quantity = (bev.Quantity - 6); + } + else if (m_Bandage.Amount >= 41) + { + bev.Quantity = (bev.Quantity - 5); + } + else if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 6 && m_Bandage.Amount <= 60) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 51) + { + bev.Quantity = (bev.Quantity - 6); + } + else if (m_Bandage.Amount >= 41) + { + bev.Quantity = (bev.Quantity - 5); + } + else if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 5 && m_Bandage.Amount <= 50) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 41) + { + bev.Quantity = (bev.Quantity - 5); + } + else if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 4 && m_Bandage.Amount <= 40) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 31) + { + bev.Quantity = (bev.Quantity - 4); + } + else if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 3 && m_Bandage.Amount <= 30) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 21) + { + bev.Quantity = (bev.Quantity - 3); + } + else if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 2 && m_Bandage.Amount <= 20) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + if (m_Bandage.Amount >= 11) + { + bev.Quantity = (bev.Quantity - 2); + } + else if (m_Bandage.Amount >= 1) + { + bev.Quantity = (bev.Quantity - 1); + } + from.SendMessage("Some of the water in the container has been depleted."); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else if (bev.Quantity == 1 && m_Bandage.Amount <= 10) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + from.SendMessage("Some of the water in the container has been depleted."); + bev.Quantity = (bev.Quantity - 1); + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else + { + from.SendMessage("There isn't enough water in that to wash with."); + } + } + else + { + from.SendMessage("You can only wash bloody bandages in water."); + } + } + else + { + from.SendMessage("You can only wash bloody bandages in water."); + } + } + else if (targeted == c) + { + if ((c.TileID >= 168 && c.TileID <= 171) || (c.TileID >= 310 && c.TileID <= 311)) + { + int amount = m_Bandage.Amount; + from.AddToBackpack(new Bandage(amount)); + if (m_Bandage.Amount > 1) + { + from.SendMessage("You wash {0} bloody bandages and put the clean bandages in your pack.", amount); + } + else + { + from.SendMessage("You wash the bloody bandage and put the clean bandage in your pack."); + } + m_Bandage.Amount = 1; + m_Bandage.Consume(); + } + else + { + from.SendMessage("You can only wash bloody bandages in water."); + } + } + else + { + from.SendMessage("You can only wash bloody bandages in water."); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Cat Jail System/JailRC1.cs b/Scripts/Customs/Cat Jail System/JailRC1.cs new file mode 100644 index 0000000..e4d8886 --- /dev/null +++ b/Scripts/Customs/Cat Jail System/JailRC1.cs @@ -0,0 +1,3547 @@ +/* + * Updated to RunUO 2.1 by Scriptiz + * Jail script by Cat 6/17/2004, RunUO-rc-1 + * Started on b30. + * + * Thanks to Kennie-Insane, I reused his code for handling turning the sentence + * length into a timeSpan. + * + * release now verifies the existance of all mobiles on the jailing and removes + * any releases for mobiles that do not exisit, this will allow jailings + * to remove themselves when there are no more characters on the jailing + * + * History since updated to RunUO 2.1 : + * 2.1b : Enabling player's context menus is now working well + * 2.1 : Complete script ported to RunUO 2.1 + * + ********************************* + * ENABLING PLAYER CONTEXT MENUS * + ********************************* + * The script will work without enabling the context menus. This is optional ! + * + * To add context menu just do this : + * 1) add "using Server.Commands;" to your playermobile file top (near others using) + * 2) in your playermobile add "JailSystem.GetContextMenus(from, this, list);" right after + * "base.GetContextMenuEntries( from, list );" + * should look something like this + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + // Scriptiz : Here is what you have to add ! + JailSystem.GetContextMenus(from, this, list); +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server.Accounting; +using Server.ContextMenus; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Regions; +using Server.Targeting; +using Server.Misc; + +namespace Server.Commands +{ + public class JailSystem + { + public static bool warnspeedy = false; + const string scriptVersion = "2.1b"; // Scriptiz : updated to RunUO 2.1 thus increasing script version + public static bool timersRunning = false; + public static string statusCommand = "jailtime"; + public static string timeCommand = "what time is it"; + public static string ooclistCommand = "ooclist"; + public static bool SingleFacetOnly = true; + public static string JSName = "JailSystem"; + public static bool useSmokingFootGear = true; + public static bool useLanguageFilter = true; + public static string foulJailorName = "Language Auto Jailor"; + public static bool allowStaffBadWords = true; + public static string oocJailorName = "OOC Jailor"; + public static bool blockOOCSpeech = true; + public static bool useOOCFilter = true; + public static bool AllowStaffOOC = true; + public static int oocwarns = 2; + + public static ArrayList defaultRelease = new ArrayList();//done + public static ArrayList badWords = new ArrayList();//done text entry 13 + public static ArrayList FoulMouthJailTimes = new ArrayList();//done + public static ArrayList oocWords = new ArrayList();//done + public static ArrayList oocParts = new ArrayList();//done + public static ArrayList oocJailTimes = new ArrayList();//done + public static ArrayList cells = new ArrayList();//done + + public static Map jailMap; + public static Map defaultReleaseFacet; + + private static Hashtable m_jailings; + private static Hashtable m_warnings; + private static string jailDirectory = @"Saves\Jailings"; + private static string idxPath = Path.Combine(jailDirectory, "Jailings.idx"); + private static string binPath = Path.Combine(jailDirectory, "Jailings.bin"); + static int m_NextID = 0; + + public static void defaultSettings() + { + statusCommand = "temps prison"; + timeCommand = "quelle heure"; + ooclistCommand = "ooclist"; + SingleFacetOnly = true; + JSName = "JailSystem"; + useSmokingFootGear = true; + jailMap = Map.Trammel; + defaultReleaseFacet = Map.Trammel; + defaultRelease.Clear(); + defaultRelease.Add(new Point3D(3503, 2574, 14)); + useLanguageFilter = true; + foulJailorName = "Language Auto Jailor"; + allowStaffBadWords = true; + badWords.Clear(); + badWords.Add("fuck"); + badWords.Add("go jail"); + FoulMouthJailTimes.Clear(); + FoulMouthJailTimes.Add(new TimeSpan(0, 0, 5, 0)); + //FoulMouthJailTimes.Add(new TimeSpan(0, 0, 30, 0)); + //FoulMouthJailTimes.Add(new TimeSpan(0, 2, 0, 0)); + //FoulMouthJailTimes.Add(new TimeSpan(0, 4, 0, 0)); + //FoulMouthJailTimes.Add(new TimeSpan(0, 8, 0, 0)); + //FoulMouthJailTimes.Add(new TimeSpan(1, 0, 0, 0)); + //ooc section + oocJailorName = "OOC Jailor"; + blockOOCSpeech = false; + useOOCFilter = false; + oocWords.Add("lol"); + AllowStaffOOC = true; + oocJailTimes.Clear(); + oocJailTimes.Add(new TimeSpan(0, 0, 5, 0)); + //oocJailTimes.Add(new TimeSpan(0, 0, 10, 0)); + //oocJailTimes.Add(new TimeSpan(0, 0, 20, 0)); + //oocJailTimes.Add(new TimeSpan(0, 0, 30, 0)); + //oocJailTimes.Add(new TimeSpan(0, 0, 40, 0)); + //oocJailTimes.Add(new TimeSpan(0, 1, 0, 0)); + oocwarns = 25; // 2 + cells.Clear(); + cells.Add(new Point3D(5276, 1164, 0)); + cells.Add(new Point3D(5286, 1164, 0)); + cells.Add(new Point3D(5296, 1164, 0)); + cells.Add(new Point3D(5306, 1164, 0)); + cells.Add(new Point3D(5276, 1174, 0)); + cells.Add(new Point3D(5286, 1174, 0)); + cells.Add(new Point3D(5296, 1174, 0)); + cells.Add(new Point3D(5306, 1174, 0)); + cells.Add(new Point3D(5283, 1184, 0)); + } + + public static Hashtable warns + { + get + { + if (m_warnings == null) + m_warnings = new Hashtable(); + return m_warnings; + } + } + + public static Hashtable list + { + get + { + if (m_jailings == null) + m_jailings = new Hashtable(); + return m_jailings; + } + } + + public static JailSystem fromMobile(Mobile m) + { + return fromAccount((Account)m.Account); + } + + public static JailSystem fromAccount(Account a) + { + string un = a.Username; + foreach (JailSystem js in list.Values) + { + try + { + if (js.Name == un) + return js; + } + catch { } + } + return null; + } + + public static JailSystem lockup(Mobile m) + { + try + { + JailSystem js = JailSystem.fromMobile(m); + if (js == null) + js = new JailSystem(m); + + js.lockupMobile(m); + return js; + } + catch + { + System.Console.WriteLine("{0}: Lockup call failed on-{1}", JailSystem.JSName, m.Name); + return null; + } + } + + public static void Jail(Mobile badBoy, bool foul, string reason, bool releasetoJailing, string jailedBy, AccessLevel l) + { + Jail(badBoy, getJailTerm(badBoy, foul), reason, releasetoJailing, jailedBy, l); + } + + public static void Jail(Mobile badBoy, TimeSpan ts, string reason, bool releasetoJailing, string jailedBy, AccessLevel l) + { + Jail(badBoy, ts, reason, releasetoJailing, jailedBy, l, true); + } + + public static void Jail(Mobile badBoy, TimeSpan ts, string reason, bool releasetoJailing, string jailedBy, AccessLevel l, bool useBoot) + { + DateTime dt = DateTime.Now.Add(ts); + Jail(badBoy, dt, reason, releasetoJailing, jailedBy, l, useBoot); + } + + public static void Jail(Mobile badBoy, int days, int hours, int minutes, string reason, bool releasetoJailing, string jailedBy, AccessLevel l) + { + DateTime dt = DateTime.Now.AddDays(days).AddHours(hours).AddMinutes(minutes); + Jail(badBoy, dt, reason, releasetoJailing, jailedBy, l); + } + + public static void Jail(Mobile badBoy, DateTime dt, string reason, bool releasetoJailing, string jailedBy, AccessLevel l) + { + Jail(badBoy, dt, reason, releasetoJailing, jailedBy, l, true); + } + + public static void Jail(Mobile badBoy, DateTime dt, string reason, bool releasetoJailing, string jailedBy, AccessLevel l, bool useBoot) + { + JailSystem js = JailSystem.fromMobile(badBoy); + if (js == null) + { + js = new JailSystem(badBoy, l); + } + else + { + if (js.jailed) + { + js.lockupMobile(badBoy, useBoot); + return; + } + } + js.fillJailReport(badBoy, dt, reason, releasetoJailing, jailedBy); + js.lockupMobile(badBoy, useBoot); + } + + public static void Jail(Mobile badBoy, bool foul, string reason, bool releasetoJailing, string jailedBy) + { + Jail(badBoy, getJailTerm(badBoy, foul), reason, releasetoJailing, jailedBy, AccessLevel.Counselor); + } + + public static void Jail(Mobile badBoy, TimeSpan ts, string reason, bool releasetoJailing, string jailedBy) + { + DateTime dt = DateTime.Now.Add(ts); + Jail(badBoy, dt, reason, releasetoJailing, jailedBy, AccessLevel.Counselor); + } + + public static void Jail(Mobile badBoy, int days, int hours, int minutes, string reason, bool releasetoJailing, string jailedBy) + { + DateTime dt = DateTime.Now.AddDays(days).AddHours(hours).AddMinutes(minutes); + Jail(badBoy, dt, reason, releasetoJailing, jailedBy, AccessLevel.Counselor); + } + + public static void Jail(Mobile badBoy, DateTime dt, string reason, bool releasetoJailing, string jailedBy) + { + Jail(badBoy, dt, reason, releasetoJailing, jailedBy, AccessLevel.Counselor); + } + + public static void Configure() + { + m_jailings = new Hashtable(); + EventSink.WorldLoad += new WorldLoadEventHandler(onLoad); + EventSink.WorldSave += new WorldSaveEventHandler(onSave); + } + + public static void onLoad() + { + //System.Console.WriteLine("Loading Jailings"); + FileStream idxFileStream; + FileStream binFileStream; + //BinaryReader idxReader; + BinaryFileReader idxReader; + BinaryFileReader binReader; + //GenericReader idxReader; + long tPos; + int tID; + int tLength; + JailSystem tJail; + int JailCount = 0; + int temp = 0; + + // Scriptiz : false pour annuler le if et pour qu'on charge toujours les param�tres par d�faut ! + if (false && (File.Exists(idxPath)) && (File.Exists(binPath))) + { + idxFileStream = new FileStream(idxPath, (FileMode)3, (FileAccess)1, (FileShare)1); + binFileStream = new FileStream(binPath, (FileMode)3, (FileAccess)1, (FileShare)1); + try + { + idxReader = new BinaryFileReader(new BinaryReader(idxFileStream)); + binReader = new BinaryFileReader(new BinaryReader(binFileStream)); + JailCount = idxReader.ReadInt(); + + if (JailCount > 0) + { + for (int i = 0; i < JailCount; i++) + { + temp = idxReader.ReadInt();//catch the version number which we wont use + tID = idxReader.ReadInt(); + tPos = idxReader.ReadLong(); + tLength = idxReader.ReadInt(); + tJail = new JailSystem(tID); + binReader.Seek(tPos, 0); + try + { + tJail.Deserialize((GenericReader)binReader); + if (binReader.Position != ((long)tPos + tLength)) + throw new Exception(String.Format("***** Bad serialize on {0} *****", tID)); + } + catch + { } + } + } + loadingameeditsettings((GenericReader)binReader); + + } + finally + { + if (idxFileStream != null) + idxFileStream.Close(); + if (binFileStream != null) + binFileStream.Close(); + } + } + else + { + JailSystem.defaultSettings(); + //System.Console.WriteLine("{0}: No prior Jailsystem save, using default settings", JailSystem.JSName); + } + //System.Console.WriteLine("{0} Jailings Loaded:{1}", JailCount, list.Count); + } + + public static void loadingameeditsettings(GenericReader idxReader) + { + // Scriptiz : on charge les param�tres par d�faut d'office ! + JailSystem.defaultSettings(); + return; + + int version = 0; + int temp = 0; + try + { + try + { + version = idxReader.ReadInt(); + } + catch + { + JailSystem.defaultSettings(); + System.Console.WriteLine("{0}: settings not found in save file, using default settings.", JailSystem.JSName); + return; + } + switch (version) + { + case 0: + try + { + JSName = idxReader.ReadString().Trim(); + statusCommand = idxReader.ReadString().Trim(); + timeCommand = idxReader.ReadString().Trim(); + ooclistCommand = idxReader.ReadString().Trim(); + foulJailorName = idxReader.ReadString().Trim(); + oocJailorName = idxReader.ReadString().Trim(); + oocwarns = idxReader.ReadInt(); + jailMap = idxReader.ReadMap(); + defaultReleaseFacet = idxReader.ReadMap(); + SingleFacetOnly = idxReader.ReadBool(); + useSmokingFootGear = idxReader.ReadBool(); + useLanguageFilter = idxReader.ReadBool(); + allowStaffBadWords = idxReader.ReadBool(); + blockOOCSpeech = idxReader.ReadBool(); + useOOCFilter = idxReader.ReadBool(); + AllowStaffOOC = idxReader.ReadBool(); + + //load default releases + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + defaultRelease.Add(idxReader.ReadPoint3D()); + } + + //load cells + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + cells.Add(idxReader.ReadPoint3D()); + } + + //load bad words + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + badWords.Add(idxReader.ReadString().Trim()); + } + + //load ooc words + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + oocWords.Add(idxReader.ReadString().Trim()); + } + + //load ooc part words + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + oocParts.Add(idxReader.ReadString().Trim()); + } + + //load oocjail times + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + oocJailTimes.Add(idxReader.ReadTimeSpan()); + } + + //load foul mouth jail times + temp = idxReader.ReadInt(); + for (int i = 0; i < temp; i++) + { + FoulMouthJailTimes.Add(idxReader.ReadTimeSpan()); + } + } + catch + { + JailSystem.defaultSettings(); + System.Console.WriteLine("{0}: settings not found in save file, using default settings.", JailSystem.JSName); + return; + } + break; + case -1: + JailSystem.defaultSettings(); + break; + default: + System.Console.WriteLine("{0} warning:{1}-{2}", JailSystem.JSName, "Loading-", "Unknown version"); + break; + } + } + catch + { + JailSystem.defaultSettings(); + System.Console.WriteLine("{0}: settings not found in save file, using default settings:", JailSystem.JSName); + return; + } + } + + public static void saveingameeditsettings(GenericWriter idxWriter) + { + idxWriter.Write((int)0);//version# + idxWriter.Write((string)JailSystem.JSName.Trim()); + idxWriter.Write((string)JailSystem.statusCommand.Trim()); + idxWriter.Write((string)JailSystem.timeCommand.Trim()); + idxWriter.Write((string)JailSystem.ooclistCommand.Trim()); + idxWriter.Write((string)JailSystem.foulJailorName.Trim()); + idxWriter.Write((string)JailSystem.oocJailorName.Trim()); + idxWriter.Write((int)JailSystem.oocwarns); + idxWriter.Write((Map)JailSystem.jailMap); + idxWriter.Write((Map)JailSystem.defaultReleaseFacet); + idxWriter.Write((bool)JailSystem.SingleFacetOnly); + idxWriter.Write((bool)JailSystem.useSmokingFootGear); + idxWriter.Write((bool)JailSystem.useLanguageFilter); + idxWriter.Write((bool)JailSystem.allowStaffBadWords); + idxWriter.Write((bool)JailSystem.blockOOCSpeech); + idxWriter.Write((bool)JailSystem.useOOCFilter); + idxWriter.Write((bool)JailSystem.AllowStaffOOC); + idxWriter.Write((int)JailSystem.defaultRelease.Count); + foreach (Point3D p in defaultRelease) + { + idxWriter.Write((Point3D)p); + } + idxWriter.Write((int)cells.Count); + foreach (Point3D p in cells) + { + idxWriter.Write((Point3D)p); + } + + idxWriter.Write((int)badWords.Count); + foreach (string s in badWords) + { + idxWriter.Write((string)s.Trim()); + } + + idxWriter.Write((int)oocWords.Count); + foreach (string s in oocWords) + { + idxWriter.Write((string)s.Trim()); + } + + idxWriter.Write((int)oocParts.Count); + foreach (string s in oocParts) + { + idxWriter.Write((string)s.Trim()); + } + idxWriter.Write((int)oocJailTimes.Count); + foreach (TimeSpan t in oocJailTimes) + { + idxWriter.Write((TimeSpan)t); + } + idxWriter.Write((int)FoulMouthJailTimes.Count); + foreach (TimeSpan t in FoulMouthJailTimes) + { + idxWriter.Write((TimeSpan)t); + } + } + + public static void onSave(WorldSaveEventArgs e) + { + System.Console.WriteLine("Saving Jailings"); + if (!Directory.Exists(jailDirectory)) + Directory.CreateDirectory(jailDirectory); + GenericWriter idxWriter; + GenericWriter binWriter; + long tPos; + /*if (World.SaveType == 0) + { + idxWriter = new BinaryFileWriter(idxPath, false); + binWriter = new BinaryFileWriter(binPath, true); + } + else + {*/ + idxWriter = new AsyncWriter(idxPath, false); + binWriter = new AsyncWriter(binPath, true); + //} + idxWriter.Write((int)m_jailings.Count); + try + { + foreach (JailSystem tJail in m_jailings.Values) + { + tPos = binWriter.Position; + idxWriter.Write((int)0); + idxWriter.Write((int)tJail.ID); + idxWriter.Write((long)tPos); + try + { + tJail.Serialize((GenericWriter)binWriter); + } + catch (Exception err) + { + System.Console.WriteLine("{0}, {1} serialize", err.Message, err.TargetSite); + } + idxWriter.Write((int)(binWriter.Position - tPos)); + } + saveingameeditsettings((GenericWriter)binWriter); + + } + catch (Exception er) + { + System.Console.WriteLine("{0}, {1}", er.Message, er.TargetSite); + } + finally + { + } + idxWriter.Close(); + binWriter.Close(); + System.Console.WriteLine("Jailings Saved"); + } + + private bool returnToPoint = true; + private Hashtable releasePoints = new Hashtable(); + + public JailSystem() + : base() + { + buildJail(); + } + + public JailSystem(Mobile m) + : this(m, AccessLevel.Counselor) + { + } + + public JailSystem(Mobile m, AccessLevel l) + : base() + { + buildJail(); + this.Name = ((Account)m.Account).Username; + this.m_jailorAC = l; + } + + public void buildJail() + { + this.m_id = JailSystem.m_NextID; + m_releaseTime = DateTime.Now.AddDays(1); + JailSystem.m_NextID += 1; + m_jailings.Add(this.m_id, this); + jailor = JailSystem.JSName; + this.m_jailorAC = AccessLevel.Counselor; + reason = "Please wait while the gm fills in a jailing report"; + } + + public void addNote(string from, string text) + { + this.Prisoner.Comments.Add(new AccountComment(JailSystem.JSName + "-note", text + " by: " + from)); + } + + public void fillJailReport(Mobile badBoy, int days, int hours, int minutes, string why, bool mreturn, string Jailor) + { + DateTime dt_unJail = DateTime.Now.Add(new TimeSpan(days, hours, minutes, 0)); + fillJailReport(badBoy, dt_unJail, why, mreturn, Jailor); + } + + public void fillJailReport(Mobile badBoy, DateTime dt_unJail, string why, bool mreturn, string Jailor) + { + Name = ((Account)badBoy.Account).Username; + m_releaseTime = dt_unJail; + this.reason = why; + this.jailor = Jailor; + ((Account)badBoy.Account).Comments.Add(new AccountComment(JailSystem.JSName + "-jailed", "Jailed for \"" + why + "\" By:" + Jailor + " On:" + DateTime.Now + " Until:" + dt_unJail.ToString())); + this.returnToPoint = mreturn; + this.StartTimer(); + } + + public JailSystem(Serial serial) + { + buildJail(); + } + + public virtual void Serialize(GenericWriter writer) + { + writer.Write((int)2); + //new version here + //version 2 + writer.Write((int)m_jailorAC); + //version 1 + writer.Write((string)freedBy); + //version 0 here + writer.Write((string)m_name); + writer.Write((DateTime)m_releaseTime); + writer.Write((int)releasePoints.Count); + foreach (ReleaseLoc rl in releasePoints.Values) + { + writer.Write((Map)rl.map); + writer.Write((Point3D)rl.location); + writer.Write((int)rl.mobile); + writer.Write((bool)rl.returnToPoint); + } + writer.Write((string)jailor); + writer.Write((string)reason); + } + + public virtual void Deserialize(GenericReader reader) + { + int imax = 0; + int version = reader.ReadInt(); + switch (version) + { + case 2: + m_jailorAC = (AccessLevel)reader.ReadInt(); + goto case 1; + case 1: + freedBy = reader.ReadString().Trim(); + goto case 0; + case 0: + m_name = reader.ReadString().Trim(); + m_releaseTime = reader.ReadDateTime(); + imax = reader.ReadInt(); + for (int i = 0; i < imax; i++) + { + ReleaseLoc rl = new ReleaseLoc(); + rl.map = reader.ReadMap(); + rl.location = reader.ReadPoint3D(); + rl.mobile = reader.ReadInt(); + rl.returnToPoint = reader.ReadBool(); + releasePoints.Add(rl.mobile, rl); + } + jailor = reader.ReadString().Trim(); + reason = reader.ReadString().Trim(); + break; ; + default: + break; + } + //System.Console.WriteLine("Loaded Jail object:{0} releases:{1}", m_name, imax); + } + + private DateTime m_releaseTime; + + public DateTime ReleaseDate + { + get { return m_releaseTime; } + } + + private jailing autoReleasor; + private int m_id; + private AccessLevel m_jailorAC = AccessLevel.Counselor; + + public bool jailed + { + get + { + return (ReleaseDate > DateTime.Now); + } + } + + public int ID + { + get { return m_id; } + } + + private string m_name; + public string jailor; + public string reason; + public string freedBy = JailSystem.JSName; + + public Account Prisoner + { + get { return (Account)Accounts.GetAccount(Name); } + } + + public string Name + { + get + { + // Scriptiz : bizarre que le nom soit null + if (m_name == null) + { + Logging.DebugLog(String.Format("JailSystem - m_name est null")); + return ""; + } + + return m_name; + } + set + { + m_name = value; + } + } + + public override string ToString() + { + return Name; + } + + public void TimerRelease() + { + if (m_releaseTime <= System.DateTime.Now) + { + release(); + } + else + Console.WriteLine("JailSystem: A Jail Timer fired but the timer was incorrect so the release was not honored."); + } + + public void forceRelease(Mobile releasor) + { + try + { + if (m_jailorAC > releasor.AccessLevel) + { + releasor.SendLocalizedMessage(1061637); + return; + } + } + catch (Exception err) + { + System.Console.WriteLine("{0}: access level error, resume release-{1}", JailSystem.JSName, err.ToString()); + } + freedBy = releasor.Name + " (At:" + DateTime.Now.ToString() + ")"; + try + { + if (autoReleasor != null) + autoReleasor.Stop(); + } + catch { } + m_releaseTime = DateTime.Now.Subtract(new TimeSpan(1, 0, 0, 0, 0)); + release(); + } + + public void release(NetState ns) + { + try + { + try + { + if (!(ns.Mobile.Region is Regions.Jail)) return; + ns.Mobile.SendLocalizedMessage(501659); + } + catch (Exception err) + { + System.Console.WriteLine("{0}: {1} Mobile not released", JailSystem.JSName, err.ToString()); + return; + } + + if (autoReleasor != null) + { + if (autoReleasor.Running) autoReleasor.Stop(); + autoReleasor = null; + } + ReleaseLoc rl; + try + { + rl = (ReleaseLoc)releasePoints[ns.Mobile.Serial.Value]; + } + catch + { + rl = new ReleaseLoc(); + rl.mobile = ns.Mobile.Serial.Value; + releasePoints.Add(ns.Mobile.Serial.Value, rl); + } + if (rl.release(this.freedBy)) + releasePoints.Remove(ns.Mobile.Serial.Value); + } + catch (Exception err) + { + System.Console.WriteLine("{0}: {1}", JailSystem.JSName, err.ToString()); + } + if (releasePoints.Count == 0) + { + System.Console.WriteLine("Jailing removed for account {0}", this.Name); + try + { + list.Remove(this.ID); + } + catch + { + } + } + } + public void ban(Mobile from) + { + try + { + this.Prisoner.Comments.Add(new AccountComment(JailSystem.JSName + "-jailed", string.Format("{0} banned this account on {1}.", from.Name, DateTime.Now.ToString()))); + this.Prisoner.Banned = true; + CommandLogging.WriteLine(from, "{0} {1} {3} account {2}", from.AccessLevel, CommandLogging.Format(from), this.Prisoner.Username, this.Prisoner.Banned ? "banning" : "unbanning"); + list.Remove(this.ID); + } + catch + { + from.SendMessage("Banning Failed. If you are trying to remove the jailing release the person, or use 'killjail {0}'", this.ID); + from.SendMessage("Using killjail on an unbanned account can cause problems for that account."); + } + } + + static public void killJailing(int tID) + { + list.Remove(tID); + } + + public void release() + { + try + { + if (!(autoReleasor == null)) + { + if (autoReleasor.Running) autoReleasor.Stop(); + //autoReleasor=null; + } + } + catch (Exception err) + { + System.Console.WriteLine("{0}: auto releasor not found-{1}", JailSystem.JSName, err.ToString()); + } + try + { + verifyMobs(); + } + catch (Exception err) + { + System.Console.WriteLine("{0}: Verify Mobiles failed-{1}", JailSystem.JSName, err.ToString()); + } + try + { + foreach (NetState ns in NetState.Instances) + { + if (((Account)ns.Account).Username == m_name) + { + release(ns); + } + } + } + catch (Exception err) + { + System.Console.WriteLine("{0}: Release failed-{1} **The most common occurance of this is when an account has been deleted while in jail ***Use the adminjail command to cycle through the jailings and automaticly remove them.", JailSystem.JSName, err.ToString()); + } + if (releasePoints.Count == 0) + { + try + { + list.Remove(this.ID); + System.Console.WriteLine("Jailing removed for account {0}", this.Name); + } + catch + { + } + } + } + + public void verifyMobs() + { + ArrayList temp = new ArrayList(); + foreach (ReleaseLoc r in this.releasePoints.Values) + { + try + { + Mobile m = World.FindMobile(r.mobile); + if (m == null) + { + temp.Add(r); + } + } + catch + { + temp.Add(r); + } + } + foreach (ReleaseLoc r in temp) + { + this.releasePoints.Remove(r.mobile); + } + } + + public void killJail() + { + if (this.Prisoner == null) + m_jailings.Remove(this.m_id); + } + + public void lockupMobile(Mobile m) + { + lockupMobile(m, true); + } + + public void lockupMobile(Mobile m, bool useFootWear) + { + if (!releasePoints.Contains(m.Serial.Value)) + releasePoints.Add(m.Serial.Value, new ReleaseLoc(m.Location, m.Map, m.Serial.Value, returnToPoint)); + m.SendMessage("While in jail, you can say \"{0}\" at any time to check your jail status", statusCommand); + m.SendMessage("You can say \"{0}\" at any time to check the time according to the server", JailSystem.timeCommand); + if (JailSystem.useOOCFilter) + m.SendMessage("You can say \"{0}\" at any time to see the list of words marked as being out of character", JailSystem.ooclistCommand); + if (m.Region is Regions.Jail) return; + //if they are already in jail there is no need to do this + Point3D cell; + cell = (Point3D)cells[((new System.Random()).Next(0, cells.Count - 1))]; + if ((useSmokingFootGear) && (useFootWear)) new SmokingFootGear((Mobile)m); + m.Location = cell; + m.Map = JailSystem.jailMap; + } + + public void StartTimer() + { + if (autoReleasor != null) + { + if (autoReleasor.Running) autoReleasor.Stop(); + autoReleasor = null; + } + if (!jailed) + { + release(); + return; + } + autoReleasor = new jailing(this); + autoReleasor.Start(); + } + + public void resetReleaseDateOneDay() + { + m_releaseTime = DateTime.Now.AddDays(1); + StartTimer(); + } + + public void resetReleaseDateNow() + { + m_releaseTime = DateTime.Now; + } + + public void AddDays(int days) + { + m_releaseTime = m_releaseTime.AddDays(days); + StartTimer(); + } + + public void AddMonths(int months) + { + m_releaseTime = m_releaseTime.AddMonths(months); + StartTimer(); + } + + public void AddHours(int hours) + { + m_releaseTime = m_releaseTime.AddHours(hours); + StartTimer(); + } + + public void AddMinutes(int minutes) + { + m_releaseTime = m_releaseTime.AddMinutes(minutes); + StartTimer(); + } + + public void subtractDays(int days) + { + removeTime(days, 0, 0); + } + + public void subtractHours(int hours) + { + removeTime(0, hours, 0); + } + + public void subtractMinutes(int minutes) + { + removeTime(0, 0, minutes); + } + + public void removeTime(int days, int hours, int minutes) + { + m_releaseTime = m_releaseTime.Subtract(new TimeSpan(days, hours, minutes, 0, 0)); + StartTimer(); + } + + public static void EventSink_Speech(SpeechEventArgs args) + { + try + { + if (args.Mobile is PlayerMobile) + { + if ((useLanguageFilter) && (!(args.Mobile.Region is Regions.Jail))) + foreach (string s in badWords) + { + if (args.Speech.ToLower().Trim().IndexOf(s.ToLower()) >= 0) + { + if ((((Account)args.Mobile.Account).AccessLevel > AccessLevel.Player) && (allowStaffBadWords)) + args.Mobile.SendMessage("If you were not staff you�d be in jail now. Behave yourself"); + else + { + JailSystem.Jail(args.Mobile, true, string.Format("Foul language, \"{0}\" \"{1}\"", s, args.Speech), true, foulJailorName); + return; + } + } + } + if ((args.Speech.ToLower().Trim() == timeCommand) || (args.Speech.ToLower().Trim() == timeCommand + "?"))//time query + args.Mobile.SendMessage("It is currently {0} by the servers clock", System.DateTime.Now.ToString()); + else if (args.Speech.ToLower().Trim() == "jailsystem")//credit speech + { + args.Mobile.SendMessage("This server is running Cat's JailSystem Version:{0}", scriptVersion); + args.Blocked = true; + return; + } + else if (args.Speech.ToLower().Trim() == statusCommand)//status command + { + if (args.Mobile.Region is Regions.Jail)//ignore it if they rant in jail + { + JailSystem js = JailSystem.fromMobile(args.Mobile); + if (js != null) + { + args.Mobile.SendMessage("You were jailed by: {0}", js.jailor); + args.Mobile.SendMessage("You were jailed for: {0}", js.reason); + args.Mobile.SendMessage("You are to be released at: {0}", js.ReleaseDate.ToString()); + } + else + { + args.Mobile.SendMessage("You are missing a jailing object, page a gm"); + } + }//end status area + args.Blocked = true; + return; + } + else if (args.Speech.ToLower().Trim() == ooclistCommand)//status command + { + string ooclst = "Here is the list of words that can land you in jail:"; + foreach (string s in oocWords) + ooclst += " " + s; + foreach (string s in oocParts) + ooclst += " " + s; + args.Mobile.SendMessage(ooclst); + args.Blocked = true; + return; + } + + if ((useOOCFilter) && (!(args.Mobile.Region is Regions.Jail)) && (!(args.Mobile.Region.Name.ToLower().IndexOf("ooc") >= 0))) + { + foreach (string s in oocParts) + { + if (args.Speech.ToLower().Trim().IndexOf(s.ToLower()) >= 0) + { + if ((((Account)args.Mobile.Account).AccessLevel == AccessLevel.Player) || (!AllowStaffOOC)) + { + JailSystem.oocWarn(args.Mobile, s); + args.Blocked = blockOOCSpeech; + return; + } + else + args.Mobile.SendMessage("Your staff, but please avoid ooc stuff as much as possible-triggered on '{0}'. say '{1}' to see the list of ooc words", s, ooclistCommand); + } + } + foreach (string s in oocWords) + { + if (args.Speech.ToLower().Trim() == s.ToLower()) + { + if ((((Account)args.Mobile.Account).AccessLevel == AccessLevel.Player) || (!AllowStaffOOC)) + { + JailSystem.oocWarn(args.Mobile, s); + args.Blocked = blockOOCSpeech; + return; + } + else + args.Mobile.SendMessage("Your staff, but please avoid ooc stuff as much as possible-triggered on '{0}'. say '{1}' to see the list of ooc words", s, ooclistCommand); + } + } + } + } + } + catch (NullReferenceException ne) + { + Console.WriteLine("EX : JailSpeech by " + (args.Mobile != null ? args.Mobile.Name : "")); + } + } + + public static void OnLoginJail(LoginEventArgs e) + { + if (!timersRunning)//start the timers on the first user to login + { + timersRunning = true;//so no-one else causes the process to run + bool loopdone = false; + while (!loopdone) + { + try + { + foreach (JailSystem tjs in JailSystem.list.Values) + tjs.StartTimer(); + loopdone = true; + } + catch (Exception err) + { + System.Console.WriteLine("Restarting the Jail timer load process:{0}", err.Message); + } + } + System.Console.WriteLine("The Jail timer load process has finished"); + } + if (e.Mobile == null) return; + JailSystem js = JailSystem.fromMobile(e.Mobile);//check to see if they have a jail object + if (js == null) + { + return;//they don�t so we bail + } + if (js.jailed)//are they jailed? + { + js.lockupMobile(e.Mobile);//yup so lock them up + } + else + js.release(e.Mobile.NetState);//no so we release them + } + + public static void oocWarn(Mobile m, string s) + { + if (!warns.Contains(((Account)m.Account).Username)) + { + warns.Add(((Account)m.Account).Username, new Hashtable()); + } + Hashtable w = (Hashtable)warns[((Account)m.Account).Username]; + if (w == null) + { + JailSystem.Jail(m, false, "Going OOC, warning system was unable to issue a warning and jailed you.", true, "OOC Jailor"); + } + DateTime k = DateTime.Now; + int i = 0; + while (w.Contains(k)) + { + k = k.Subtract(new TimeSpan(0, 0, 1)); + if (i > 10) continue; + i++; + } + if (i <= 10) + { + w.Add(k, s); + new warnRemover(w, k); + } + if (w.Count > oocwarns) + { + JailSystem.Jail(m, false, "Going OOC after repeated warnings.", true, oocJailorName); + warns.Remove(((Account)m.Account).Username); + } + else + { + m.SendMessage(k.ToString()); + m.SendMessage("'{0}' is an out of character term. Going ooc too much can land you in Jail. For a list of ooc words say '{1}'", s, ooclistCommand); + } + } + + public class warnRemover : Timer + { + public DateTime key; + public Hashtable issuedWarnings; + public warnRemover(Hashtable w, DateTime k) + : base(new TimeSpan(1, 0, 0, 0)) + { + key = k; + issuedWarnings = w; + this.Start(); + } + protected override void OnTick() + { + if (issuedWarnings.Contains(key)) + { + issuedWarnings.Remove(key); + } + } + } + + public static TimeSpan getJailTerm(Mobile m, bool foul) + { + int visits = countJailings(m, foul); + if (foul) + return getFoulJailTerm(visits); + else + return getOOCJailTerm(visits); + } + + public static TimeSpan getOOCJailTerm(int visits) + { + oocJailTimes.Sort(); + if (visits >= oocJailTimes.Count) visits = oocJailTimes.Count - 1; + if (visits < 0) visits = 0; + return (TimeSpan)oocJailTimes[visits]; + } + + public static TimeSpan getFoulJailTerm(int visits) + { + FoulMouthJailTimes.Sort(); + if (visits >= FoulMouthJailTimes.Count) visits = FoulMouthJailTimes.Count - 1; + if (visits < 0) visits = 0; + return (TimeSpan)FoulMouthJailTimes[visits]; + } + + public static int countJailings(Mobile m, bool foul) + { + return countJailings(((Account)m.Account), foul); + } + + public static int countJailings(Account a, bool foul) + { + int foulCt = 0; + int oocCt = 0; + foreach (AccountComment note in a.Comments) + { + if (note.Content.IndexOf(" By:" + oocJailorName) >= 0) + oocCt++; + if (note.Content.IndexOf(" By:" + foulJailorName) >= 0) + foulCt++; + } + if (foul) + return foulCt; + else + return oocCt; + } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler(OnLoginJail); + EventSink.Speech += new SpeechEventHandler(EventSink_Speech); + CommandSystem.Register("unjail", AccessLevel.GameMaster, new CommandEventHandler(unjail_OnCommand)); + CommandSystem.Register("release", AccessLevel.GameMaster, new CommandEventHandler(unjail_OnCommand)); + CommandSystem.Register("jail", AccessLevel.Counselor, new CommandEventHandler(jail_OnCommand)); + CommandSystem.Register("review", AccessLevel.Counselor, new CommandEventHandler(review_OnCommand)); + CommandSystem.Register("warn", AccessLevel.Counselor, new CommandEventHandler(warn_OnCommand)); + CommandSystem.Register("macroJail", AccessLevel.Counselor, new CommandEventHandler(macroCheck_OnCommand)); + CommandSystem.Register("adminJail", AccessLevel.Administrator, new CommandEventHandler(adminJail_OnCommand)); + CommandSystem.Register("killJail", AccessLevel.Administrator, new CommandEventHandler(KillJail_OnCommand)); + CommandSystem.Register("cage", AccessLevel.Administrator, new CommandEventHandler(cage_OnCommand)); + } + + public static void GetContextMenus(Mobile from, Mobile player, List list) + { + if (from.AccessLevel >= AccessLevel.Counselor) + list.Add(new JailEntry(from, player)); + if (from.AccessLevel >= AccessLevel.GameMaster) + list.Add(new UnJailEntry(from, player)); + if (from.AccessLevel >= AccessLevel.Counselor) + list.Add(new ReviewEntry(from, player)); + if (from.AccessLevel >= AccessLevel.Counselor) + list.Add(new MacroEntry(from, player)); + } + + [Usage("AdminJail")] + [Description("Displays the jail sentence gump.")] + public static void adminJail_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.SendGump(new JailAdminGump()); + } + } + + [Usage("killJail ")] + [Description("Deletes the jailing with the specified ID. Used only to recover from deadly errors")] + public static void KillJail_OnCommand(CommandEventArgs e) + { + try + { + int tID = Convert.ToInt32(e.ArgString.Trim()); + JailSystem.killJailing(tID); + } + catch (Exception err) + { + e.Mobile.SendMessage("Kill jailing failed: {0}", err.ToString()); + } + } + + [Usage("UnJail")] + [Description("Releases the selected player from jail.")] + public static void unjail_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new JailTarget(true); + e.Mobile.SendLocalizedMessage(3000218); + } + } + + [Usage("Cage")] + [Description("places a cage around the target.")] + public static void cage_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new cageTarget(); + e.Mobile.SendMessage("Who would you like to cage?"); + } + } + + [Usage("Macro")] + [Description("Issues a macroing check dialog.")] + public static void macroCheck_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new macroTarget(); + e.Mobile.SendLocalizedMessage(3000218); + } + } + + [Usage("Jail")] + [Description("Places the selected player in jail.")] + public static void jail_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new JailTarget(false); + e.Mobile.SendLocalizedMessage(3000218); + } + } + + [Usage("Warn")] + [Description("Issues a warning to the player.")] + public static void warn_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new warnTarget(); + e.Mobile.SendLocalizedMessage(3000218); + } + } + + [Usage("Review")] + [Description("Reviews the jailings, GM notes and warnings of the selected player.")] + public static void review_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new warnTarget(false); + e.Mobile.SendLocalizedMessage(3000218); + } + } + + public static void macroTest(Mobile from, Mobile badBoy) + { + if (badBoy.NetState == null) + { + from.SendMessage("They are not online."); + return; + } + badBoy.SendGump(new UnattendedMacroGump(from, badBoy)); + } + + public class ReleaseLoc + { + public Point3D location; + public Map map; + public int mobile; + public bool returnToPoint; + public ReleaseLoc() + { + returnToPoint = false; + } + public ReleaseLoc(bool rel2JailPoint) + { + returnToPoint = rel2JailPoint; + } + public ReleaseLoc(Point3D loc, Map m, int mob, bool rel2JailPoint) + { + location = loc; + map = m; + mobile = mob; + returnToPoint = rel2JailPoint; + } + public bool release(string releasor) + { + Mobile m = World.FindMobile((Serial)mobile); + if (m == null) + { + System.Console.WriteLine("release location error, Mobile not found."); + return false; + } + if (!returnToPoint) + {//not returning to the jailing point so rewrites this release point info + if (JailSystem.SingleFacetOnly) + map = JailSystem.defaultReleaseFacet; + else + { + if (m.Kills >= 5) + map = Map.Felucca; + else + map = Map.Trammel; + } + location = (Point3D)JailSystem.defaultRelease[(new System.Random()).Next(0, JailSystem.defaultRelease.Count - 1)]; + } + try + { + m.Location = location; + m.Map = map; + } + catch { } + if (m.Region is Regions.Jail) + { + try + { + ((Account)m.Account).Comments.Add(new AccountComment(JailSystem.JSName, releasor + "'s release Failed for " + m.Name + "(" + ((Account)m.Account).Username + ") at " + DateTime.Now + " to " + location.ToString() + "(" + map + ")")); + } + catch { } + return false; + } + else + { + try + { + ((Account)m.Account).Comments.Add(new AccountComment(JailSystem.JSName, releasor + " released " + m.Name + "(" + ((Account)m.Account).Username + ") at " + DateTime.Now + " to " + location.ToString() + "(" + map + ")")); + } + catch { } + return true; + } + + + } + } + + public static void newJailingFromGMandPlayer(Mobile from, Mobile m) + { + JailSystem js = JailSystem.fromMobile(m); + if (js == null) + { + js = new JailSystem(); + } + else + { + if (js.jailed) + { + from.SendMessage("{0} is already jailed", m.Name); + js.lockupMobile(m); + return; + } + } + js.resetReleaseDateOneDay(); + js.lockupMobile(m); + js.jailor = from.Name; + + if (m.Equals(from)) + m.SendLocalizedMessage(503315); + else + m.SendLocalizedMessage(503316); + + from.SendGump((new JailGump(js, from, m, 0, "", ""))); + } + + public class jailing : Timer + { + public JailSystem Prisoner; + public jailing(JailSystem js) + : base(js.ReleaseDate.Subtract(System.DateTime.Now)) + { + Prisoner = js; + } + protected override void OnTick() + { + Prisoner.TimerRelease(); + } + } + } + + #region jail system target objects (used by commands) + public class warnTarget : Target + { + private bool m_warn = false; + public warnTarget(bool warn) + : base(-1, false, TargetFlags.None) + { + m_warn = warn; + } + public warnTarget() + : base(-1, false, TargetFlags.None) + { + m_warn = true; + } + protected override void OnTarget(Mobile from, object targeted) + { + if (from is PlayerMobile && targeted is PlayerMobile) + { + Mobile m = (Mobile)targeted; + if (m_warn) + from.SendGump(new JailWarnGump(from, m, "", 0, null)); + else + { + from.SendGump(new JailReviewGump(from, m, 0, null)); + } + } + } + } + + public class macroTarget : Target + { + public macroTarget() + : base(-1, false, TargetFlags.None) + { + } + protected override void OnTarget(Mobile from, object targeted) + { + if (from is PlayerMobile && targeted is PlayerMobile) + { + Mobile m = (Mobile)targeted; + JailSystem.macroTest(from, m); + } + } + } + + public class cageTarget : Target + { + public cageTarget() + : base(-1, false, TargetFlags.None) + { + } + protected override void OnTarget(Mobile from, object targeted) + { + if (from is PlayerMobile && targeted is PlayerMobile) + { + if (from is PlayerMobile && targeted is PlayerMobile) + { + Mobile m = (Mobile)targeted; + new Cage(m); + Point3D newcell = m.Location; + m.Location = new Point3D(0, 0, 0); + m.Location = newcell; + } + } + } + } + + public class JailTarget : Target + { + bool m_releasing = false; + + public JailTarget(bool releasing) + : base(-1, false, TargetFlags.None) + { + m_releasing = releasing; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (from is PlayerMobile && targeted is PlayerMobile) + { + string temp = "jail"; + Mobile m = (Mobile)targeted; + if (from.AccessLevel < m.AccessLevel) + { + from.SendMessage("{0} has a higher access level than you and you can not do that.", m.Name); + if (m_releasing) temp = "release"; + CommandLogging.WriteLine(from, from.Name + " tried to " + temp + " " + m.Name); + m.SendMessage(from.Name + " tried to " + temp + " you"); + } + else + {//jailor has a higher (or equal) access level than the target + if (m_releasing) + { + JailSystem js = JailSystem.fromAccount((Account)m.Account); + if (js == null) + { + from.SendMessage(m.Name + " no jail object"); + return; + } + js.forceRelease(from); + m.SendLocalizedMessage(501659); + } + else + { + //temp="jailed"; + JailSystem.newJailingFromGMandPlayer(from, m); + } + } + } + else + { + from.SendLocalizedMessage(503312); + } + } + } + #endregion + + #region jail System gumps + public class JailReviewGump : Gump + { + private Mobile badBoy; + private Mobile jailor; + private string m_reason = "Breaking Shard Rules"; + private ArrayList m_warn; + private int m_id; + private bool displayReleases = false; + + public JailReviewGump(Mobile from, Mobile m) + : base(1, 30) + { + buildit(from, m, 0, null, ""); + } + + public JailReviewGump(Mobile from, Mobile m, int id, ArrayList warnings) + : base(1, 30) + { + buildit(from, m, id, warnings, ""); + } + + public JailReviewGump(Mobile from, Mobile m, int id, ArrayList warnings, string note) + : base(1, 30) + { + buildit(from, m, id, warnings, note); + } + + public JailReviewGump(Mobile from, Mobile m, int id, ArrayList warnings, bool showRelease) + : base(1, 30) + { + buildit(from, m, id, warnings, "", true, showRelease); + } + + public JailReviewGump(Mobile from, Mobile m, int id, ArrayList warnings, string note, bool showRelease) + : base(1, 30) + { + buildit(from, m, id, warnings, note, true, showRelease); + } + + public void buildit(Mobile from, Mobile m, int id, ArrayList warnings, string aNote) + { + buildit(from, m, id, warnings, aNote, true, false); + } + + public void buildit(Mobile from, Mobile m, int id, ArrayList warnings, string aNote, bool tGo, bool showRelease) + { + displayReleases = showRelease; + from.CloseGump(typeof(JailReviewGump)); + jailor = from; + badBoy = m; + m_id = id; + Closable = true; + Dragable = true; + AddPage(0); + AddBackground(0, 0, 326, 230, 5054); + AddLabel(12, 4, 200, "Reviewing: " + badBoy.Name + " (" + ((Account)badBoy.Account).Username + ")"); + if (tGo) + { + AddLabel(300, 17, 200, "GO"); + AddButton(280, 20, 2223, 2224, 2, GumpButtonType.Reply, 0); + } + AddLabel(12, 200, 200, "Note"); + AddBackground(42, 198, 268, 24, 0x2486); + AddTextEntry(46, 200, 250, 20, 200, 0, aNote); + //add button + AddButton(70, 150, 2460, 2461, 1, GumpButtonType.Reply, 0); + //previous button + AddButton(120, 150, 2466, 2467, 20, GumpButtonType.Reply, 0); + //next Button + AddButton(200, 150, 2469, 2470, 21, GumpButtonType.Reply, 0); + //release toggle + AddButton(115, 167, displayReleases ? 2154 : 2151, displayReleases ? 2151 : 2154, 22, GumpButtonType.Reply, 0); + AddLabel(147, 171, 200, "Show Releases"); + if (warnings == null) + { + m_warn = new ArrayList(); + foreach (AccountComment note in ((Account)m.Account).Comments) + { + if ((note.AddedBy == JailSystem.JSName + "-warning") || (note.AddedBy == JailSystem.JSName + "-jailed") || (note.AddedBy == JailSystem.JSName + "-note") || ((displayReleases) && ((note.AddedBy == JailSystem.JSName)))) + { + m_warn.Add(note); + } + } + m_id = m_warn.Count - 1; + } + else + { + m_warn = warnings; + } + AddImageTiled(9, 36, 308, 110, 2624); + AddAlphaRegion(9, 36, 308, 110); + string temp = "No prior warnings."; + if (m_warn.Count > 0) + { + if (m_id < 0) m_id = m_warn.Count - 1; + if (m_id >= m_warn.Count) m_id = 0; + temp = ((AccountComment)m_warn[m_id]).Content; + if (((AccountComment)m_warn[m_id]).AddedBy == JailSystem.JSName + "-warning") + AddLabel(12, 40, 53, "Warned"); + else if (((AccountComment)m_warn[m_id]).AddedBy == JailSystem.JSName + "-jailed") + AddLabel(12, 40, 38, "Jailed"); + else if (((AccountComment)m_warn[m_id]).AddedBy == JailSystem.JSName + "-note") + AddLabel(12, 40, 2, "Note"); + else + AddLabel(12, 40, 2, "Release"); + AddLabel(60, 40, 200, "Issued: " + ((AccountComment)m_warn[m_id]).LastModified.ToString()); + } + else + { + //no prior warning + m_id = -1; + } + AddLabel(12, 60, 200, "Event " + (m_id + 1) + " of " + m_warn.Count.ToString()); + //AddLabel( 12, 230, 200, temp ); + AddHtml(12, 80, 300, 62, temp, true, true); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + switch (info.ButtonID) + { + case 22: + displayReleases = (!displayReleases); + from.SendGump(new JailReviewGump(from, badBoy, 0, null, info.GetTextEntry(0).Text, displayReleases)); + break; + case 20: + //previous button + m_id--; + if (m_id < 0) m_id = m_warn.Count - 1; + from.SendGump(new JailReviewGump(from, badBoy, m_id, m_warn, info.GetTextEntry(0).Text, displayReleases)); + break; + case 21: + //next button + m_id++; + if (m_id >= m_warn.Count) m_id = 0; + from.SendGump(new JailReviewGump(from, badBoy, m_id, m_warn, info.GetTextEntry(0).Text, displayReleases)); + break; + //reason buttons + case 2: + from.SendGump(new JailReviewGump(from, badBoy, m_id, m_warn, info.GetTextEntry(0).Text, displayReleases)); + from.Hidden = true; + from.Location = badBoy.Location; + from.Map = badBoy.Map; + break; + case 1: + if (info.GetTextEntry(0).Text != "note added") + { + ((Account)badBoy.Account).Comments.Add(new AccountComment(JailSystem.JSName + "-note", info.GetTextEntry(0).Text + " by: " + from.Name)); + from.SendGump(new JailReviewGump(from, badBoy, 0, null, "note added", displayReleases)); + } + else + from.SendGump(new JailReviewGump(from, badBoy, 0, null, "", displayReleases)); + break; + default: + break; + } + } + } + + public class JailWarnGump : Gump + { + private Mobile badBoy; + private Mobile jailor; + private string m_reason = "Breaking Shard Rules"; + private ArrayList m_warn; + private int m_id; + public JailWarnGump(Mobile from, Mobile m, string why, int id, ArrayList warnings) + : base(100, 40) + { + from.CloseGump(typeof(JailWarnGump)); + if ((why == null) || (why == "")) why = JailGump.reasons[0]; + jailor = from; + badBoy = m; + m_reason = why; + m_id = id; + Closable = true; + Dragable = true; + AddPage(0); + AddBackground(0, 0, 326, 320, 5054); + AddImageTiled(9, 6, 308, 140, 2624); + AddAlphaRegion(9, 6, 308, 140); + AddLabel(16, 98, 200, "Reason"); + AddBackground(14, 114, 290, 24, 0x2486); + AddTextEntry(18, 116, 282, 20, 200, 0, m_reason); + AddButton(14, 11, 1209, 1210, 3, GumpButtonType.Reply, 0); + AddLabel(30, 7, 200, JailGump.reasons[0]); + AddButton(14, 29, 1209, 1210, 4, GumpButtonType.Reply, 0); + AddLabel(30, 25, 200, JailGump.reasons[1]); + AddButton(14, 47, 1209, 1210, 5, GumpButtonType.Reply, 0); + AddLabel(30, 43, 200, JailGump.reasons[2]); + AddButton(150, 11, 1209, 1210, 6, GumpButtonType.Reply, 0); + AddLabel(170, 7, 200, JailGump.reasons[3]); + AddButton(150, 29, 1209, 1210, 7, GumpButtonType.Reply, 0); + AddLabel(170, 24, 200, JailGump.reasons[4]); + AddButton(150, 47, 1209, 1210, 8, GumpButtonType.Reply, 0); + AddLabel(170, 43, 200, JailGump.reasons[5]); + AddButton(14, 66, 1209, 1210, 9, GumpButtonType.Reply, 0); + AddLabel(30, 62, 200, JailGump.reasons[6]); + AddButton(14, 84, 1209, 1210, 10, GumpButtonType.Reply, 0); + AddLabel(30, 80, 200, JailGump.reasons[7]); + //warn button + AddButton(218, 152, 2472, 2473, 1, GumpButtonType.Reply, 0); + AddLabel(248, 155, 200, "Warn them"); + //Jail button + AddButton(20, 152, 2472, 2473, 2, GumpButtonType.Reply, 0); + AddLabel(50, 155, 200, "Jail them"); + //previous button + AddButton(10, 300, 2466, 2467, 20, GumpButtonType.Reply, 0); + //next Button + AddButton(90, 300, 2469, 2470, 21, GumpButtonType.Reply, 0); + if (warnings == null) + { + m_warn = new ArrayList(); + foreach (AccountComment note in ((Account)m.Account).Comments) + { + if ((note.AddedBy == JailSystem.JSName + "-warning") || (note.AddedBy == JailSystem.JSName + "-jailed")) + { + m_warn.Add(note); + } + } + m_id = m_warn.Count - 1; + } + else + { + m_warn = warnings; + } + AddImageTiled(9, 186, 308, 110, 2624); + AddAlphaRegion(9, 186, 308, 110); + string temp = "No prior warnings."; + if (m_warn.Count > 0) + { + if (m_id < 0) m_id = m_warn.Count - 1; + if (m_id >= m_warn.Count) m_id = 0; + temp = ((AccountComment)m_warn[m_id]).Content; + AddLabel(12, 190, 200, "Issued: " + ((AccountComment)m_warn[m_id]).LastModified.ToString()); + } + else + { + //no prior warning + m_id = -1; + } + AddLabel(12, 210, 200, "Event " + (m_id + 1) + " of " + m_warn.Count.ToString() + " warnings/Jailings"); + //AddLabel( 12, 230, 200, temp ); + AddHtml(12, 230, 300, 62, temp, true, true); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + switch (info.ButtonID) + { + case 20: + //previous button + m_id--; + if (m_id < 0) m_id = m_warn.Count - 1; + from.SendGump(new JailWarnGump(from, badBoy, info.GetTextEntry(0).Text, m_id, m_warn)); + break; + case 21: + //next button + m_id++; + if (m_id >= m_warn.Count) m_id = 0; + from.SendGump(new JailWarnGump(from, badBoy, info.GetTextEntry(0).Text, m_id, m_warn)); + break; + //reason buttons + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + from.SendGump(new JailWarnGump(from, badBoy, JailGump.reasons[info.ButtonID - 3], m_id, m_warn)); + break; + case 1: + //warn them + from.CloseGump(typeof(JailWarnGump)); + if (m_reason == JailGump.reasons[0]) + { + //they are macroing + JailSystem.macroTest(from, badBoy); + } + else + { + //not Unattended macroing + badBoy.SendGump(new JailWarningGump(from, badBoy, m_reason)); + } + break; + case 2: + //jail them + from.CloseGump(typeof(JailWarnGump)); + from.SendGump(new JailGump(JailSystem.lockup(badBoy), from, badBoy, 0, "", m_reason, "0", "0", "1", "0", "0", true)); + break; + default: + break; + } + } + } + + public class UnattendedMacroGump : Gump + { + private Mobile badBoy; + private Mobile jailor; + DateTime issued = DateTime.Now; + UAResponseTimer myTimer; + int tbutton = 2; + bool caughtFired = false; + public UnattendedMacroGump(Mobile from, Mobile m) + : base(70, 40) + { + tbutton = (new System.Random()).Next(6); + if (tbutton < 1) tbutton = 1; + if (tbutton > 6) tbutton = 6; + ((Account)m.Account).Comments.Add(new AccountComment(JailSystem.JSName + "-warning", from.Name + " checked to see if " + m.Name + " was macroing unattended on: " + DateTime.Now)); + jailor = from; + badBoy = m; + Closable = false; + Dragable = true; + AddPage(0); + AddBackground(0, 0, 326, 320, 5054); + AddImageTiled(9, 65, 308, 240, 2624); + AddAlphaRegion(9, 65, 308, 240); + //AddLabel( 16, 20, 200, string.Format("{0} is checking to see if you are macroing unattended", jailor.Name)); + this.AddHtml(16, 10, 250, 50, string.Format("{0} is checking to see if you are macroing unattended", jailor.Name), false, false); + //let them show that they are there by selecting these buttons + AddButton(20, 72, 2472, 2473, 5, GumpButtonType.Reply, 0); + AddLabel(50, 75, 200, tbutton == 5 ? "I'm here!" : "I confess I was macroing unattended."); + AddButton(20, 112, 2472, 2473, 1, GumpButtonType.Reply, 0); + AddLabel(50, 115, 200, tbutton == 1 ? "I'm here!" : "I confess I was macroing unattended."); + AddButton(20, 152, 2472, 2473, 2, GumpButtonType.Reply, 0); + AddLabel(50, 155, 200, tbutton == 2 ? "I'm here!" : "I confess I was macroing unattended."); + AddButton(20, 192, 2472, 2473, 3, GumpButtonType.Reply, 0); + AddLabel(50, 195, 200, tbutton == 3 ? "I'm here!" : "I confess I was macroing unattended."); + AddButton(20, 232, 2472, 2473, 4, GumpButtonType.Reply, 0); + AddLabel(50, 235, 200, tbutton == 4 ? "I'm here!" : "I confess I was macroing unattended."); + AddButton(20, 272, 2472, 2473, 6, GumpButtonType.Reply, 0); + AddLabel(50, 275, 200, tbutton == 6 ? "I'm here!" : "I confess I was macroing unattended."); + myTimer = new UAResponseTimer(this); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + if (myTimer != null) + myTimer.Stop(); + if (tbutton == info.ButtonID) + { + string mtemp = string.Format("{0} responded to the unattended macroing check in {1} seconds.", from.Name, ((TimeSpan)(DateTime.Now.Subtract(issued))).Seconds); + ((Account)badBoy.Account).Comments.Add(new AccountComment(JailSystem.JSName + "-warning", mtemp)); + jailor.SendMessage(mtemp); + } + else + { + caughtInTheAct(false); + } + from.CloseGump(typeof(UnattendedMacroGump)); + } + + public class UAResponseTimer : Timer + { + public UnattendedMacroGump m_gump; + int counts = 60; + + public UAResponseTimer(UnattendedMacroGump myGump) + : base(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)) + { + m_gump = myGump; + this.Start(); + } + + protected override void OnTick() + { + counts -= this.Interval.Seconds; + switch (counts) + { + case 50: + case 40: + case 30: + case 20: + this.Interval = TimeSpan.FromSeconds(1); + goto case 10; + case 10: + case 9: + case 8: + case 7: + case 6: + case 5: + case 4: + case 3: + case 2: + case 1: + m_gump.badBoy.SendMessage("Warning closing in {0} seconds", counts); + break; + case 0: + m_gump.caughtInTheAct(false); + m_gump.badBoy.CloseGump(typeof(UnattendedMacroGump)); + this.Stop(); + break; + default: + break; + } + } + } + + public void caughtInTheAct(bool confessed) + { + if (caughtFired) return; + caughtFired = true; + if (!confessed) + { + JailSystem.Jail(badBoy, 1, 0, 0, JailGump.reasons[0], true, jailor.Name); + jailor.SendMessage("{0} has been jailed for {1} from the warning you issued.", badBoy.Name, JailGump.reasons[0]); + } + else + { + JailSystem.Jail(badBoy, 0, 5, 0, JailGump.reasons[0], true, jailor.Name); + jailor.SendMessage("{0} was been jailed for {1} when they confessed on the warning you issued.", badBoy.Name, JailGump.reasons[0]); + } + if (myTimer != null) + { + myTimer.Stop(); + } + } + } + + public class JailWarningGump : Gump + { + public JailWarningGump(Mobile from, Mobile m, string why) + : base(70, 40) + { + //from.CloseGump(typeof ( JailWarningGump )); + ((Account)m.Account).Comments.Add(new AccountComment(JailSystem.JSName + "-warning", m.Name + " warned for \"" + why + "\" by:" + from.Name + " on:" + DateTime.Now)); + Closable = false; + Dragable = false; + Resizable = false; + AddPage(0); + if ((why == null) || (why == "")) why = "Your actions are a violation of the shard rules"; + AddBackground(0, 0, 500, 400, 5054); + //ok button + AddLabel(26, 30, 200, from.Name + " has issued a you a warning"); + AddLabel(26, 50, 200, why); + AddLabel(26, 100, 200, "Click ok to dismiss this window"); + AddButton(30 + ((int)(new System.Random()).Next(100)), 142 + ((int)(new System.Random()).Next(100)), 2128, 2130, 1, GumpButtonType.Reply, 0); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + switch (info.ButtonID) + { + case 1: + from.CloseGump(typeof(JailWarningGump)); + break; + default: + break; + } + } + } + + public class JailGump : Gump + { + private Mobile badBoy; + private Mobile jailor; + private int m_page; + private bool m_return; + private JailSystem js; + private string m_reason = "Breaking Shard Rules"; + public static string[] reasons ={"Unattended Macroing", "Disruptive behavior", "Arguing with Staff", "Harassing other players", + "Exploiting Bugs", "Scamming", "Breaking out of Character", "Exposing a Staff Members Player Account"}; + + public JailGump(JailSystem tjs, Mobile owner, Mobile prisoner, int page, string error, string reason) + : base(100, 40) + { + buildIt(tjs, owner, prisoner, page, error, reason, "0", "0", "1", "0", "0", true); + } + + public JailGump(JailSystem tjs, Mobile owner, Mobile prisoner, int page, string error, string reason, string month, string week, string day, string hour, string minute, bool fullreturn) + : base(100, 40) + { + buildIt(tjs, owner, prisoner, page, error, reason, month, week, day, hour, minute, fullreturn); + } + + public void buildIt(JailSystem tjs, Mobile owner, Mobile prisoner, int page, string error, string reason, string month, string week, string day, string hour, string minute, bool fullreturn) + { + js = tjs; + m_return = fullreturn; + m_page = page; + if ((reason != "") && (reason != null)) + m_reason = reason; + else + m_reason = reasons[1]; + jailor = owner; + badBoy = prisoner; + m_reason = reason; + jailor.CloseGump(typeof(JailGump)); + Closable = false; + Dragable = false; + AddPage(0); + AddBackground(0, 0, 326, 295, 5054); + AddImageTiled(9, 6, 308, 140, 2624); + AddAlphaRegion(9, 6, 308, 140); + AddLabel(16, 98, 200, "Reason"); + AddBackground(14, 114, 290, 24, 0x2486); + AddTextEntry(18, 116, 282, 20, 200, 0, m_reason); + AddButton(14, 11, 1209, 1210, 3, GumpButtonType.Reply, 0); + AddLabel(30, 7, 200, reasons[0]); + AddButton(14, 29, 1209, 1210, 4, GumpButtonType.Reply, 0); + AddLabel(30, 25, 200, reasons[1]); + AddButton(14, 47, 1209, 1210, 5, GumpButtonType.Reply, 0); + AddLabel(30, 43, 200, reasons[2]); + AddButton(150, 11, 1209, 1210, 6, GumpButtonType.Reply, 0); + AddLabel(170, 7, 200, reasons[3]); + AddButton(150, 29, 1209, 1210, 7, GumpButtonType.Reply, 0); + AddLabel(170, 24, 200, reasons[4]); + AddButton(150, 47, 1209, 1210, 8, GumpButtonType.Reply, 0); + AddLabel(170, 43, 200, reasons[5]); + AddButton(14, 66, 1209, 1210, 9, GumpButtonType.Reply, 0); + AddLabel(30, 62, 200, reasons[6]); + AddButton(14, 84, 1209, 1210, 10, GumpButtonType.Reply, 0); + AddLabel(30, 80, 200, reasons[7]); + //ok button + AddButton(258, 268, 2128, 2130, 1, GumpButtonType.Reply, 0); + AddImageTiled(8, 153, 308, 113, 2624); + AddAlphaRegion(8, 153, 308, 113); + if (m_return == true) + AddButton(15, 210, 2153, 2151, 2, GumpButtonType.Reply, 0); + else + AddButton(15, 210, 2151, 2153, 2, GumpButtonType.Reply, 0); + AddLabel(50, 212, 200, "Return to where jailed from on release"); + if ((error != "") && (error != null)) + { + AddLabel(10, 235, 200, error); + } + if (m_page == 0) + { + //auto + //auto/manual + AddButton(11, 268, 2111, 2114, 25, GumpButtonType.Reply, 0); + AddLabel(16, 160, 200, "Months"); + AddBackground(19, 178, 34, 24, 0x2486); + AddTextEntry(21, 180, 30, 20, 0, 7, month); + AddLabel(62, 160, 200, "Weeks"); + AddBackground(63, 178, 34, 24, 0x2486); + AddTextEntry(65, 180, 30, 20, 0, 6, week); + AddLabel(106, 160, 200, "Days"); + AddBackground(104, 178, 34, 24, 0x2486); + AddTextEntry(107, 180, 30, 20, 0, 5, day); + AddLabel(145, 160, 200, "Hours"); + AddBackground(145, 178, 34, 24, 0x2486); + AddTextEntry(147, 180, 30, 20, 0, 9, hour); + AddLabel(185, 160, 200, "Minutes"); + AddBackground(191, 178, 34, 24, 0x2486); + AddTextEntry(194, 180, 30, 20, 0, 8, minute); + } + else + { + AddButton(11, 268, 2114, 2111, 27, GumpButtonType.Reply, 0); + AddLabel(14, 160, 200, "Account will be Jailed for one year"); + AddLabel(14, 178, 200, "or until released, which comes first"); + + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + switch (info.ButtonID) + { + //reason buttons + case 25: + from.SendGump((new JailGump(js, from, badBoy, 1, "", info.TextEntries[0].Text, "0", "0", "1", "0", "0", m_return))); + //, info.GetTextEntry(7), info.GetTextEntry(6), info.GetTextEntry(5), info.GetTextEntry(9), info.GetTextEntry(8),m_return + break; + case 27: + from.SendGump((new JailGump(js, from, badBoy, 0, "", info.TextEntries[0].Text, "0", "0", "1", "0", "0", m_return))); + break; + case 2: + m_return = !m_return; + if (m_page == 1) + from.SendGump((new JailGump(js, from, badBoy, m_page, "", info.TextEntries[0].Text, "0", "0", "1", "0", "0", m_return))); + else + from.SendGump((new JailGump(js, from, badBoy, m_page, "", info.TextEntries[0].Text, info.GetTextEntry(7).Text, info.GetTextEntry(6).Text, info.GetTextEntry(5).Text, info.GetTextEntry(9).Text, info.GetTextEntry(8).Text, m_return))); + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + if (m_page == 1) + from.SendGump((new JailGump(js, from, badBoy, m_page, "", reasons[info.ButtonID - 3], "0", "0", "1", "0", "0", m_return))); + else + from.SendGump((new JailGump(js, from, badBoy, m_page, "", reasons[info.ButtonID - 3], info.GetTextEntry(7).Text, info.GetTextEntry(6).Text, info.GetTextEntry(5).Text, info.GetTextEntry(9).Text, info.GetTextEntry(8).Text, m_return))); + break; + case 1: + { + DateTime dt_unJail = DateTime.Now; + string m_Error = ""; + int i_days = 0; + int i_weeks = 0; + int i_months = 0; + int i_minutes = 0; + int i_hours = 0; + if (m_page == 0) + { + try + { + i_days = Convert.ToInt32((info.GetTextEntry(5)).Text.Trim()); + } + catch + { + m_Error = "Bad day(s) entry! No negative values or chars."; + } + try + { + i_weeks = Convert.ToInt32((info.GetTextEntry(6)).Text.Trim()); + } + catch + { + if (m_Error == "") + m_Error = "Bad week(s) entry! No negative values or chars."; + } + try + { + i_months = Convert.ToInt32((info.GetTextEntry(7)).Text.Trim()); + } + catch + { + if (m_Error == "") + m_Error = "Bad month(s) entry! No negative values or chars."; + } + try + { + i_minutes = Convert.ToInt32((info.GetTextEntry(8)).Text.Trim()); + } + catch + { + if (m_Error == "") + m_Error = "Bad minute(s) entry! No negative values or chars."; + } + try + { + i_hours = Convert.ToInt32((info.GetTextEntry(9)).Text.Trim()); + } + catch + { + if (m_Error == "") + m_Error = "Bad hour(s) entry! No negative values or chars."; + } + if (((i_days > 7) || (i_days < 0)) && (m_Error == "")) + { + if (m_Error == "") + m_Error = "Bad day(s) entry! No negative values. 7 days max."; + } + if (((i_weeks > 4) || (i_weeks < 0)) && (m_Error == "")) + { + if (m_Error == "") + m_Error = "Bad week(s) entry! No negative values. 4 weeks max."; + } + if (((i_months > 12) || (i_months < 0)) && (m_Error == "")) + { + if (m_Error == "") + m_Error = "Bad month(s) entry! No negative values. 1 year max."; + } + if (((i_minutes > 60) || (i_minutes < 0)) && (m_Error == "")) + { + if (m_Error == "") + m_Error = "Bad minute(s) entry! No negative values. 1 hour max."; + } + if (((i_hours > 24) || (i_hours < 0)) && (m_Error == "")) + { + if (m_Error == "") + m_Error = "Bad hour(s) entry! No negative values. 1 day max."; + } + if (m_Error != "") + { + from.SendGump(new JailGump(js, from, badBoy, m_page, m_Error, info.TextEntries[0].Text, i_months.ToString(), i_weeks.ToString(), i_days.ToString(), i_hours.ToString(), i_minutes.ToString(), m_return)); + break; + } + if (i_days > 0) + dt_unJail = dt_unJail.AddDays(i_days); + if (i_weeks > 0) + dt_unJail = dt_unJail.AddDays((i_weeks * 7)); + if (i_months > 0) + dt_unJail = dt_unJail.AddMonths(i_months); + if (i_minutes > 0) + dt_unJail = dt_unJail.AddMinutes(i_minutes); + if (i_hours > 0) + dt_unJail = dt_unJail.AddHours(i_hours); + if (dt_unJail.Ticks <= DateTime.Now.Ticks) + { + m_Error = "Calculated date is in the past. Adjust your entries."; + from.SendGump(new JailGump(js, from, badBoy, m_page, m_Error, info.TextEntries[0].Text, i_months.ToString(), i_weeks.ToString(), i_days.ToString(), i_hours.ToString(), i_minutes.ToString(), m_return)); + break; + } + } + else + { + //page isn�t the time span + dt_unJail = dt_unJail.AddYears(1); + if (dt_unJail.Ticks <= DateTime.Now.Ticks) + { + m_Error = "Calculated date is in the past. Adjust your entries."; + from.SendGump(new JailGump(js, from, badBoy, m_page, m_Error, info.TextEntries[0].Text, "12", "0", "0", "0", "0", m_return)); + break; + } + } + js.fillJailReport(badBoy, dt_unJail, info.TextEntries[0].Text, m_return, from.Name); + } + from.CloseGump(typeof(JailGump)); + from.SendGump(new JailReviewGump(from, badBoy, 0, null)); + break; + default: + //they hit an unknown button + if (m_page == 1) + from.SendGump((new JailGump(js, from, badBoy, m_page, "", info.TextEntries[0].Text, "0", "0", "1", "0", "0", m_return))); + else + from.SendGump((new JailGump(js, from, badBoy, m_page, "", info.TextEntries[0].Text, info.GetTextEntry(7).Text, info.GetTextEntry(6).Text, info.GetTextEntry(5).Text, info.GetTextEntry(9).Text, info.GetTextEntry(8).Text, m_return))); + //close the Gump, we're done + break; + } + } + } + + public class JailBanGump : Gump + { + private JailSystem m_js = null; + public JailBanGump(JailSystem js) + : base(10, 30) + { + + buildit(js); + } + private const int LabelColor32 = 0xFFFFFF; + private const int SelectedColor32 = 0x8080FF; + private const int DisabledColor32 = 0x808080; + public void AddBlackAlpha(int x, int y, int width, int height) + { + AddImageTiled(x, y, width, height, 2624); + AddAlphaRegion(x, y, width, height); + } + + public string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + + public void AddColorLabel(int x, int y, int width, int height, string text) + { + AddHtml(x, y, width, height, Color(text, LabelColor32), false, false); + } + + public void buildit(JailSystem js) + { + m_js = js; + AddBackground(0, 0, 300, 300, 5054); + AddBlackAlpha(5, 5, 290, 290); + AddColorLabel(8, 8, 288, 288, Color("Are you sure you wish to ban this account?", SelectedColor32)); + AddButton(120, 200, 241, 243, 10, GumpButtonType.Reply, 0); + AddButton(50, 200, 239, 240, 6, GumpButtonType.Reply, 0); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + if (info.ButtonID == 6) + { + m_js.ban(from); + //ban them here + } + } + } + + public class JailAdminGump : Gump + { + public enum AdminJailGumpPage + { + General, + OOC, + Language, + Review + } + private const int LabelColor = 0x7FFF; + private const int SelectedColor = 0x421F; + private const int DisabledColor = 0x4210; + + private const int LabelColor32 = 0xFFFFFF; + private const int SelectedColor32 = 0x8080FF; + private const int DisabledColor32 = 0x808080; + + private AdminJailGumpPage m_page = AdminJailGumpPage.General; + private int m_subpage = 0; + private int m_id = 0; + private const int TitleX = 210; + private const int TitleY = 7; + private const int BodyX = 5; + private const int BodyY = 111; + private const int MessageX = 5; + private const int MessageY = 387; + private const int gutterOffset = 3; + private const int LineStep = 25; + private JailSystem js = null; + + public void AddTextField(int x, int y, int width, int height, int index) + { + AddTextField(x, y, width, height, index, ""); + } + + public void AddTextField(int x, int y, int width, int height, int index, string content) + { + AddBackground(x - 2, y - 2, width + 4, height + 4, 0x2486); + AddTextEntry(x + 2, y + 2, width - 4, height - 4, 0, index, content); + } + + public string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + + public void AddButtonLabeled(int x, int y, int buttonID, string text) + { + AddButton(x, y - 1, 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, Color(text, LabelColor32), false, false); + } + + public void AddToggleLabeled(int x, int y, int buttonID, string text, bool selected) + { + AddButton(x, y - 1, selected ? 2154 : 2152, selected ? 2152 : 2154, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, Color(text, LabelColor32), false, false); + } + + public void AddPageLabeled(int x, int y, int buttonID, string text, AdminJailGumpPage page) + { + AddButton(x, y - 1, (m_page == page) ? 4006 : 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, (m_page == page) ? Color(text, LabelColor32) : Color(text, SelectedColor32), false, false); + } + + public void AddBlackAlpha(int x, int y, int width, int height) + { + AddImageTiled(x, y, width, height, 2624); + AddAlphaRegion(x, y, width, height); + } + + public JailAdminGump() + : base(10, 30) + { + buildit(AdminJailGumpPage.Review, 0, 0); + } + + public void message(string text) + { + AddColorLabel(MessageX + gutterOffset, MessageY + gutterOffset, 390, 40, text); + } + + public void message() + { + this.message("Settings changes will be saved during the world save."); + } + + private int basex(int x) + { + return x + gutterOffset; + } + + private int basey(int y) + { + return basey(y, 0); + } + + private int basey(int y, int lines) + { + return (y + gutterOffset) + (lines * LineStep); + } + + public void AddColorLabel(int x, int y, string text) + { + AddColorLabel(x, y, 240, 20, text); + } + + public void AddColorLabel(int x, int y, int width, int height, string text) + { + AddHtml(x, y, width, height, Color(text, LabelColor32), false, false); + } + + public void AddColorLabelScroll(int x, int y, int width, int height, string text) + { + AddHtml(x, y, width, height, Color(text, LabelColor32), true, true); + } + + public JailAdminGump(AdminJailGumpPage page) + : base(10, 30) + { + buildit(page, 0, 0); + } + + public JailAdminGump(AdminJailGumpPage page, int subpage, int id) + : base(10, 30) + { + buildit(page, subpage, id); + } + + private void buildit(AdminJailGumpPage page, int subpage, int id) + { + Closable = true; + Dragable = true; + m_id = id; + m_page = page; + m_subpage = subpage; + AddPage(0); + + AddBackground(0, 0, 412, 439, 5054); + AddBlackAlpha(5, 8, 200, 98); + AddBlackAlpha(TitleX, TitleY, 190, 98); + AddBlackAlpha(BodyX, BodyY, 396, 271); + AddBlackAlpha(MessageX, MessageY, 396, 46); + AddPageLabeled(7, 12, 4, "Review Current Jailings", AdminJailGumpPage.Review); + AddPageLabeled(7, 36, 3, "Language Settings", AdminJailGumpPage.Language); + AddPageLabeled(7, 59, 2, "OOC Settings", AdminJailGumpPage.OOC); + AddPageLabeled(7, 82, 1, "General Settings", AdminJailGumpPage.General); + + AddButton(TitleX + 120, TitleY + 75, 241, 243, 5, GumpButtonType.Reply, 0); + switch (m_page) + { + case AdminJailGumpPage.Review: + buildReviews(); + break; + case AdminJailGumpPage.General: + buildSettings(); + break; + case AdminJailGumpPage.Language: + buildLanguage(); + break; + case AdminJailGumpPage.OOC: + buildOOC(); + break; + default: + break; + } + } + + private void buildLanguage() + { + this.AddToggleLabeled(basex(TitleX), basey(TitleY, 0), 13, "Use Language", JailSystem.useLanguageFilter); + message(); + if (!JailSystem.useLanguageFilter) return; + AddButton(TitleX + 50, TitleY + 75, 239, 240, 15, GumpButtonType.Reply, 0); + AddLabel(basex(BodyX), basey(BodyY, 0), 200, "Misc."); + AddLabel(basex(BodyX) + 15, basey(BodyY, 1), 200, "Foul Jailor"); + this.AddTextField(basex(BodyX) + 80, basey(BodyY, 1), 150, 20, 12, JailSystem.foulJailorName); + this.AddToggleLabeled(basex(BodyX) + 15, basey(BodyY, 2), 14, "Allow Staff to use bad words", JailSystem.allowStaffBadWords); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 0), 200, "Bad words"); + string temp = ""; + foreach (string p in JailSystem.badWords) + temp += string.Format("{0}\n", p.ToString()); + this.AddColorLabelScroll(basex(BodyX) + 240, basey(BodyY, 1), 150, 60, temp.Trim()); + + this.AddTextField(basex(BodyX) + 240, basey(BodyY, 1) + 65, 150, 20, 13); + AddButton(BodyX + 240, basey(BodyY, 1) + 90, 2461, 2462, 26, GumpButtonType.Reply, 0); + AddButton(BodyX + 295, basey(BodyY, 1) + 90, 2464, 2465, 27, GumpButtonType.Reply, 0); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 5) + 10, 200, "Jail Terms"); + temp = ""; + foreach (TimeSpan t in JailSystem.FoulMouthJailTimes) + temp += string.Format("d={0} h={1} m={2}\n", t.Days, t.Hours, t.Minutes); + this.AddColorLabelScroll(basex(BodyX) + 240, basey(BodyY, 6) + 10, 150, 60, temp.Trim()); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 6) + 75, 200, "D"); + AddLabel(basex(BodyX) + 290, basey(BodyY, 6) + 75, 200, "H"); + AddLabel(basex(BodyX) + 340, basey(BodyY, 6) + 75, 200, "M"); + this.AddTextField(basex(BodyX) + 255, basey(BodyY, 6) + 75, 30, 20, 8); + this.AddTextField(basex(BodyX) + 305, basey(BodyY, 6) + 75, 30, 20, 9); + this.AddTextField(basex(BodyX) + 355, basey(BodyY, 6) + 75, 30, 20, 10); + AddButton(BodyX + 240, basey(BodyY, 6) + 100, 2461, 2462, 28, GumpButtonType.Reply, 0); + AddButton(BodyX + 295, basey(BodyY, 6) + 100, 2464, 2465, 29, GumpButtonType.Reply, 0); + } + + private void buildOOC() + { + this.AddToggleLabeled(basex(TitleX), basey(TitleY, 0), 9, "Use OOC Filter", JailSystem.useOOCFilter); + message(); + if (!JailSystem.useOOCFilter) return; + AddButton(TitleX + 50, TitleY + 75, 239, 240, 10, GumpButtonType.Reply, 0); + //AddLabel(basex( BodyX),basey(BodyY,0),200,"Commands"); + AddLabel(basex(BodyX) + 15, basey(BodyY, 0), 200, "OOCList"); + this.AddTextField(basex(BodyX) + 90, basey(BodyY, 0), 130, 20, 11, JailSystem.ooclistCommand); + //AddLabel(basex( BodyX),basey(BodyY,2),200,"Misc."); + AddLabel(basex(BodyX) + 15, basey(BodyY, 1), 200, "OOC Jailor"); + this.AddTextField(basex(BodyX) + 90, basey(BodyY, 1), 130, 20, 12, JailSystem.oocJailorName); + this.AddToggleLabeled(basex(BodyX) + 15, basey(BodyY, 2), 11, "Block OOC speech", JailSystem.blockOOCSpeech); + this.AddToggleLabeled(basex(BodyX) + 15, basey(BodyY, 3), 12, "Allow Staff to go OOC", JailSystem.AllowStaffOOC); + AddLabel(basex(BodyX) + 15, basey(BodyY, 4), 200, "OOC Warnings"); + this.AddTextField(basex(BodyX) + 120, basey(BodyY, 4), 50, 20, 13, JailSystem.oocwarns.ToString()); + + AddLabel(basex(BodyX), basey(BodyY, 5), 200, "OOC Parts"); + string temp = ""; + foreach (string p in JailSystem.oocParts) + temp += string.Format("{0}\n", p.ToString()); + this.AddColorLabelScroll(basex(BodyX), basey(BodyY, 6), 150, 60, temp.Trim()); + + this.AddTextField(basex(BodyX), basey(BodyY, 6) + 65, 150, 20, 15); + AddButton(basex(BodyX), basey(BodyY, 6) + 90, 2461, 2462, 34, GumpButtonType.Reply, 0); + AddButton(basex(BodyX) + 55, basey(BodyY, 6) + 90, 2464, 2465, 35, GumpButtonType.Reply, 0); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 0), 200, "OOC Words"); + temp = ""; + foreach (string p in JailSystem.oocWords) + temp += string.Format("{0}\n", p.ToString()); + this.AddColorLabelScroll(basex(BodyX) + 240, basey(BodyY, 1), 150, 60, temp.Trim()); + + this.AddTextField(basex(BodyX) + 240, basey(BodyY, 1) + 65, 150, 20, 14); + AddButton(BodyX + 240, basey(BodyY, 1) + 90, 2461, 2462, 32, GumpButtonType.Reply, 0); + AddButton(BodyX + 295, basey(BodyY, 1) + 90, 2464, 2465, 33, GumpButtonType.Reply, 0); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 5) + 10, 200, "Jail Terms"); + temp = ""; + foreach (TimeSpan t in JailSystem.FoulMouthJailTimes) + temp += string.Format("d={0} h={1} m={2}\n", t.Days, t.Hours, t.Minutes); + this.AddColorLabelScroll(basex(BodyX) + 240, basey(BodyY, 6) + 10, 150, 60, temp.Trim()); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 6) + 75, 200, "D"); + AddLabel(basex(BodyX) + 290, basey(BodyY, 6) + 75, 200, "H"); + AddLabel(basex(BodyX) + 340, basey(BodyY, 6) + 75, 200, "M"); + this.AddTextField(basex(BodyX) + 255, basey(BodyY, 6) + 75, 30, 20, 8); + this.AddTextField(basex(BodyX) + 305, basey(BodyY, 6) + 75, 30, 20, 9); + this.AddTextField(basex(BodyX) + 355, basey(BodyY, 6) + 75, 30, 20, 10); + AddButton(BodyX + 240, basey(BodyY, 6) + 100, 2461, 2462, 30, GumpButtonType.Reply, 0); + AddButton(BodyX + 295, basey(BodyY, 6) + 100, 2464, 2465, 31, GumpButtonType.Reply, 0); + } + + private void buildSettings() + { + message(); + AddButton(TitleX + 50, TitleY + 75, 239, 240, 6, GumpButtonType.Reply, 0); + + AddLabel(basex(BodyX), basey(BodyY, 0), 200, "Commands"); + AddLabel(basex(BodyX) + 15, basey(BodyY, 1), 200, "Status"); + AddLabel(basex(BodyX) + 15, basey(BodyY, 2), 200, "Time"); + this.AddTextField(basex(BodyX) + 60, basey(BodyY, 1), 150, 20, 1, JailSystem.statusCommand); + this.AddTextField(basex(BodyX) + 60, basey(BodyY, 2), 150, 20, 2, JailSystem.timeCommand); + + AddLabel(basex(BodyX), basey(BodyY, 3), 200, "Misc."); + AddLabel(basex(BodyX) + 15, basey(BodyY, 4), 200, "Name"); + this.AddTextField(basex(BodyX) + 60, basey(BodyY, 4), 150, 20, 3, JailSystem.JSName); + AddLabel(basex(BodyX) + 65, basey(BodyY, 5), 200, string.Format("Jail Facet:{0}", JailSystem.jailMap.Name)); + AddButton(basex(BodyX) + 15, basey(BodyY, 5), 2471, 2470, 20, GumpButtonType.Reply, 0); + this.AddToggleLabeled(basex(BodyX) + 15, basey(BodyY, 6), 7, "Use Smoking Shoes", JailSystem.useSmokingFootGear); + + AddLabel(basex(BodyX), basey(BodyY, 7), 200, "Non-Default Release Setting"); + this.AddToggleLabeled(basex(BodyX) + 15, basey(BodyY, 8), 8, "Single Facet release", JailSystem.SingleFacetOnly); + AddLabel(basex(BodyX) + 65, basey(BodyY, 9) + 10, 200, string.Format("Release Facet:{0}", JailSystem.defaultReleaseFacet.Name)); + AddButton(BodyX + 15, basey(BodyY, 9) + 10, 2471, 2470, 21, GumpButtonType.Reply, 0); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 0), 200, "Cells"); + string temp = ""; + foreach (Point3D p in JailSystem.cells) + temp += p.ToString() + "\n"; + this.AddColorLabelScroll(basex(BodyX) + 240, basey(BodyY, 1), 150, 60, temp.Trim()); + + this.AddTextField(basex(BodyX) + 240, basey(BodyY, 1) + 65, 45, 20, 5); + this.AddTextField(basex(BodyX) + 290, basey(BodyY, 1) + 65, 45, 20, 6); + this.AddTextField(basex(BodyX) + 340, basey(BodyY, 1) + 65, 45, 20, 7); + AddButton(BodyX + 240, basey(BodyY, 1) + 90, 2461, 2462, 22, GumpButtonType.Reply, 0); + AddButton(BodyX + 295, basey(BodyY, 1) + 90, 2464, 2465, 23, GumpButtonType.Reply, 0); + + AddLabel(basex(BodyX) + 240, basey(BodyY, 5) + 10, 200, "Default Release Loctions"); + temp = ""; + foreach (Point3D p in JailSystem.defaultRelease) + temp += p.ToString() + "\n"; + this.AddColorLabelScroll(basex(BodyX) + 240, basey(BodyY, 6) + 10, 150, 60, temp.Trim()); + + this.AddTextField(basex(BodyX) + 240, basey(BodyY, 6) + 75, 45, 20, 8); + this.AddTextField(basex(BodyX) + 290, basey(BodyY, 6) + 75, 45, 20, 9); + this.AddTextField(basex(BodyX) + 340, basey(BodyY, 6) + 75, 45, 20, 10); + AddButton(BodyX + 240, basey(BodyY, 6) + 100, 2461, 2462, 24, GumpButtonType.Reply, 0); + AddButton(BodyX + 295, basey(BodyY, 6) + 100, 2464, 2465, 25, GumpButtonType.Reply, 0); + } + + private void buildReviews() + { + if (JailSystem.list.Count < m_id) m_id = 0; + if (m_id < 0) m_id = JailSystem.list.Count - 1; + if (JailSystem.list.Count == 0) m_id = -1; + int i = 0; + if (m_id >= 0) + foreach (JailSystem tj in JailSystem.list.Values) + { + if ((i == 0) || (i == m_id)) + js = tj; + i++; + } + if (m_id == -1) + { + AddLabel(BodyX + gutterOffset, BodyY + gutterOffset, 200, "No accounts are currently jailed."); + return; + } + AddLabel(TitleX + gutterOffset, TitleY + gutterOffset, 200, "Reviewing: " + js.Name); + AddLabel(TitleX + gutterOffset, TitleY + gutterOffset + LineStep, 200, string.Format("Jailed Account {0} of {1}", m_id + 1, JailSystem.list.Count)); + //previous button + AddButton(TitleX + gutterOffset, TitleY + gutterOffset + LineStep + LineStep + 5, 2466, 2467, 44, GumpButtonType.Reply, 0); + //next Button + AddButton(TitleX + gutterOffset + 80, TitleY + gutterOffset + LineStep + LineStep + 5, 2469, 2470, 45, GumpButtonType.Reply, 0); + string temp = ""; + if (js.Prisoner == null) + js.killJail(); + else + { + foreach (AccountComment note in js.Prisoner.Comments) + { + if ((note.AddedBy == JailSystem.JSName + "-warning") || (note.AddedBy == JailSystem.JSName + "-jailed") || (note.AddedBy == JailSystem.JSName + "-note")) + { + temp = temp + note.AddedBy + "\n\r" + note.Content + "\n\r***********\n\r"; + } + } + AddLabel(BodyX + 17, BodyY + 8, 200, "History"); + AddHtml(BodyX + 13, 141, 300, 82, temp, true, true); + //release + AddButton(BodyX + 13, BodyY + 120, 2472, 2473, 41, GumpButtonType.Reply, 0); + AddLabel(BodyX + 43, BodyY + 123, 200, "Release"); + AddButton(BodyX + 13, BodyY + 150, 2472, 2473, 50, GumpButtonType.Reply, 0); + AddLabel(BodyX + 43, BodyY + 153, 200, "Ban"); + //add day + AddButton(BodyX + 101, BodyY + 120, 250, 251, 43, GumpButtonType.Reply, 0); + AddButton(BodyX + 116, BodyY + 120, 252, 253, 47, GumpButtonType.Reply, 0); + AddLabel(135 + BodyX, BodyY + 123, 200, "Week"); + //add week + AddButton(BodyX + 176, BodyY + 120, 250, 251, 42, GumpButtonType.Reply, 0); + AddButton(BodyX + 191, BodyY + 120, 252, 253, 46, GumpButtonType.Reply, 0); + AddLabel(BodyX + 210, BodyY + 123, 200, "Day"); + //hours + AddButton(BodyX + 251, BodyY + 120, 250, 251, 48, GumpButtonType.Reply, 0); + AddButton(BodyX + 266, BodyY + 120, 252, 253, 49, GumpButtonType.Reply, 0); + AddLabel(BodyX + 284, BodyY + 123, 200, "Hour"); + + AddLabel(BodyX + 13, BodyY + 170, 200, "Release at: " + js.ReleaseDate.ToString()); + if (!js.jailed) + { + message("This account has been released but currently has characters in jail."); + } + else + { + message("This account is currently jailed."); + } + AddHtml(BodyX + 13, BodyY + 189, 300, 74, js.reason, true, true); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + string temp = ""; + switch (info.ButtonID) + { + case 50: + //ban an account; + from.SendGump(new JailBanGump(js)); + break; + case 10: + temp = info.GetTextEntry(11).Text.ToString().Trim().ToLower(); + if (!(temp == "") && !(temp == null)) + JailSystem.ooclistCommand = temp; + temp = info.GetTextEntry(12).Text.ToString().Trim(); + if (!(temp == "") && !(temp == null)) + JailSystem.oocJailorName = temp; + + temp = info.GetTextEntry(13).Text.ToString().Trim().ToLower(); + if (!(temp == "") && !(temp == null)) + try + { + JailSystem.oocwarns = Convert.ToInt32(temp); + } + catch + { + from.SendMessage("Bad number of OOC Warnings."); + } + goto case 2; + case 11: + JailSystem.blockOOCSpeech = !JailSystem.blockOOCSpeech; + goto case 10; + case 12: + JailSystem.AllowStaffOOC = !JailSystem.AllowStaffOOC; + goto case 10; + case 15: + //language section + temp = info.GetTextEntry(12).Text.ToString().Trim(); + if (!(temp == "") && !(temp == null)) + JailSystem.foulJailorName = temp; + JailSystem.FoulMouthJailTimes.Sort(); + goto case 3; + case 13: + JailSystem.useLanguageFilter = !JailSystem.useLanguageFilter; + goto case 3; + case 14: + JailSystem.allowStaffBadWords = !JailSystem.allowStaffBadWords; + goto case 15; + case 9: + JailSystem.useOOCFilter = !JailSystem.useOOCFilter; + goto case 2; + //generenal section + case 1: + from.SendGump(new JailAdminGump(AdminJailGumpPage.General)); + break; + case 2: + from.SendGump(new JailAdminGump(AdminJailGumpPage.OOC)); + break; + case 3: + from.SendGump(new JailAdminGump(AdminJailGumpPage.Language)); + break; + case 4: + from.SendGump(new JailAdminGump(AdminJailGumpPage.Review)); + break; + case 5: + from.CloseGump(typeof(JailAdminGump)); + break; + case 6: + temp = info.GetTextEntry(1).Text.ToString().Trim().ToLower(); + if (!(temp == "") && !(temp == null)) + JailSystem.statusCommand = temp; + + temp = info.GetTextEntry(2).Text.ToString().Trim().ToLower(); + if (!(temp == "") && !(temp == null)) + JailSystem.timeCommand = temp; + + temp = info.GetTextEntry(3).Text.ToString().Trim(); + if (!(temp == "") && !(temp == null)) + JailSystem.JSName = temp; + goto case 1; + case 7: + JailSystem.useSmokingFootGear = !JailSystem.useSmokingFootGear; + goto case 6; + case 8: + JailSystem.SingleFacetOnly = !JailSystem.SingleFacetOnly; + goto case 6; + case 20: + if (JailSystem.jailMap == Map.Felucca) + JailSystem.jailMap = Map.Trammel; + else if (JailSystem.jailMap == Map.Trammel) + JailSystem.jailMap = Map.Ilshenar; + else if (JailSystem.jailMap == Map.Ilshenar) + JailSystem.jailMap = Map.Malas; + else if (JailSystem.jailMap == Map.Malas) + JailSystem.jailMap = Map.Felucca; + goto case 6; + case 21: + if (JailSystem.defaultReleaseFacet == Map.Felucca) + JailSystem.defaultReleaseFacet = Map.Trammel; + else if (JailSystem.defaultReleaseFacet == Map.Trammel) + JailSystem.defaultReleaseFacet = Map.Ilshenar; + else if (JailSystem.defaultReleaseFacet == Map.Ilshenar) + JailSystem.defaultReleaseFacet = Map.Malas; + else if (JailSystem.defaultReleaseFacet == Map.Malas) + JailSystem.defaultReleaseFacet = Map.Felucca; + //change facet + goto case 6; + case 22: + //add cell + try + { + Point3D p = new Point3D(Convert.ToInt32(info.GetTextEntry(5).Text.Trim()), Convert.ToInt32(info.GetTextEntry(6).Text.Trim()), Convert.ToInt32(info.GetTextEntry(7).Text.Trim())); + if (JailSystem.cells.Contains(p)) + from.SendMessage("Unable to add jail cell. It is already listed."); + else + JailSystem.cells.Add(p); + } + catch + { + from.SendMessage("Unable to add jail cell. Bad x,y,z."); + } + goto case 6; + case 23: + //remove cell + try + { + Point3D p = new Point3D(Convert.ToInt32(info.GetTextEntry(5).Text.Trim()), Convert.ToInt32(info.GetTextEntry(6).Text.Trim()), Convert.ToInt32(info.GetTextEntry(7).Text.Trim())); + if (JailSystem.cells.Contains(p)) + JailSystem.cells.Remove(p); + else + from.SendMessage("Unable to remove jail cell. Cell not listed."); + } + catch + { + from.SendMessage("Unable to remove jail cell. Bad x,y,z."); + } + goto case 6; + case 24: + //add release + try + { + Point3D p = new Point3D(Convert.ToInt32(info.GetTextEntry(8).Text.Trim()), Convert.ToInt32(info.GetTextEntry(9).Text.Trim()), Convert.ToInt32(info.GetTextEntry(10).Text.Trim())); + if (JailSystem.defaultRelease.Contains(p)) + from.SendMessage("Unable to add default release location. It is already listed."); + else + JailSystem.defaultRelease.Add(p); + } + catch + { + from.SendMessage("Unable to add release location. Bad x,y,z."); + } + goto case 6; + case 25: + //remove release + try + { + Point3D p = new Point3D(Convert.ToInt32(info.GetTextEntry(8).Text.Trim()), Convert.ToInt32(info.GetTextEntry(9).Text.Trim()), Convert.ToInt32(info.GetTextEntry(10).Text.Trim())); + if (JailSystem.defaultRelease.Contains(p)) + JailSystem.defaultRelease.Remove(p); + else + from.SendMessage("Release location not listed."); + } + catch + { + from.SendMessage("Unable to remove release location. Bad x,y,z."); + } + goto case 6; + case 26: + //add foul word + try + { + temp = info.GetTextEntry(13).Text.ToLower().Trim(); + if ((temp == "") || (temp == null)) + from.SendMessage("Unable to add word"); + else if (JailSystem.badWords.Contains(temp)) + from.SendMessage("Word is already in the list."); + else + JailSystem.badWords.Add(temp); + } + catch + { + from.SendMessage("Unable to add word"); + } + goto case 15; + case 27: + //remove foul word + try + { + temp = info.GetTextEntry(13).Text.ToLower().Trim(); + if ((temp == "") || (temp == null)) + from.SendMessage("Unable to remove word"); + else if (JailSystem.badWords.Contains(temp)) + JailSystem.badWords.Remove(temp); + else + from.SendMessage("Word is not in the list."); + } + catch + { + from.SendMessage("Unable to remove word"); + } + goto case 15; + case 28: + //add jail term + try + { + TimeSpan p = new TimeSpan(Convert.ToInt32(info.GetTextEntry(8).Text.Trim()), Convert.ToInt32(info.GetTextEntry(9).Text.Trim()), Convert.ToInt32(info.GetTextEntry(10).Text.Trim()), 0, 0); + if (JailSystem.FoulMouthJailTimes.Contains(p)) + from.SendMessage("Unable to add jail term. It is already listed."); + else + JailSystem.FoulMouthJailTimes.Add(p); + } + catch + { + from.SendMessage("Unable to add jail term. Bad D,H,M."); + } + goto case 15; + case 29: + //remove jail term + try + { + TimeSpan p = new TimeSpan(Convert.ToInt32(info.GetTextEntry(8).Text.Trim()), Convert.ToInt32(info.GetTextEntry(9).Text.Trim()), Convert.ToInt32(info.GetTextEntry(10).Text.Trim()), 0, 0); + if (JailSystem.FoulMouthJailTimes.Contains(p)) + JailSystem.FoulMouthJailTimes.Remove(p); + else + from.SendMessage("Jail term not listed."); + } + catch + { + from.SendMessage("Unable to remove Jail term. Bad D,H,M."); + } + goto case 15; + + case 30: + //add jail term + try + { + TimeSpan p = new TimeSpan(Convert.ToInt32(info.GetTextEntry(8).Text.Trim()), Convert.ToInt32(info.GetTextEntry(9).Text.Trim()), Convert.ToInt32(info.GetTextEntry(10).Text.Trim()), 0, 0); + if (JailSystem.oocJailTimes.Contains(p)) + from.SendMessage("Unable to add jail term. It is already listed."); + else + JailSystem.oocJailTimes.Add(p); + } + catch + { + from.SendMessage("Unable to add jail term. Bad D,H,M."); + } + goto case 10; + case 31: + //remove jail term + try + { + TimeSpan p = new TimeSpan(Convert.ToInt32(info.GetTextEntry(8).Text.Trim()), Convert.ToInt32(info.GetTextEntry(9).Text.Trim()), Convert.ToInt32(info.GetTextEntry(10).Text.Trim()), 0, 0); + if (JailSystem.oocJailTimes.Contains(p)) + JailSystem.oocJailTimes.Remove(p); + else + from.SendMessage("Jail term not listed."); + } + catch + { + from.SendMessage("Unable to remove Jail term. Bad D,H,M."); + } + goto case 10; + case 32: + //add ooc word + try + { + temp = info.GetTextEntry(14).Text.ToLower().Trim(); + if ((temp == "") || (temp == null)) + from.SendMessage("Unable to add word"); + else if (JailSystem.oocWords.Contains(temp)) + from.SendMessage("Word is already in the list."); + else + JailSystem.oocWords.Add(temp); + } + catch + { + from.SendMessage("Unable to add word"); + } + goto case 10; + case 33: + //remove ooc word + try + { + temp = info.GetTextEntry(14).Text.ToLower().Trim(); + if ((temp == "") || (temp == null)) + from.SendMessage("Unable to remove word"); + else if (JailSystem.oocWords.Contains(temp)) + JailSystem.oocWords.Remove(temp); + else + from.SendMessage("Word is not in the list."); + } + catch + { + from.SendMessage("Unable to remove word"); + } + goto case 10; + case 34: + //add ooc part + try + { + temp = info.GetTextEntry(15).Text.ToLower().Trim(); + if ((temp == "") || (temp == null)) + from.SendMessage("Unable to add word"); + else if (JailSystem.oocParts.Contains(temp)) + from.SendMessage("Word is already in the list."); + else + JailSystem.oocParts.Add(temp); + } + catch + { + from.SendMessage("Unable to add word"); + } + goto case 10; + case 35: + //remove ooc part + try + { + temp = info.GetTextEntry(15).Text.ToLower().Trim(); + if ((temp == "") || (temp == null)) + from.SendMessage("Unable to remove word"); + else if (JailSystem.oocParts.Contains(temp)) + JailSystem.oocParts.Remove(temp); + else + from.SendMessage("Word is not in the list."); + } + catch + { + from.SendMessage("Unable to remove word"); + } + goto case 10; + case 41: + js.forceRelease(from); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 42: + js.AddDays(1); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 46: + js.subtractDays(1); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 47: + js.subtractDays(7); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 48: + js.AddHours(1); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 49: + js.subtractHours(1); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 43: + js.AddDays(7); + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 44: + //previous button + m_id--; + if (m_id < 0) m_id = JailSystem.list.Count - 1; + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + case 45: + //next button + m_id++; + if (m_id >= JailSystem.list.Count) m_id = 0; + from.SendGump(new JailAdminGump(m_page, m_subpage, m_id)); + break; + default: + break; + } + //from.CloseGump(typeof ( JailAdminGump )); + } + } + #endregion + + #region context menu objects + public class ReviewEntry : ContextMenuEntry + { + private Mobile m_gm; + private Mobile m_player; + + public ReviewEntry(Mobile gm, Mobile player) + : base(10004, 200) + { + m_gm = gm; + m_player = player; + } + public override void OnClick() + { + m_gm.SendGump(new JailReviewGump(m_gm, m_player, 0, null)); + } + } + + public class JailEntry : ContextMenuEntry + { + private Mobile m_gm; + private Mobile m_player; + + public JailEntry(Mobile gm, Mobile player) + : base(5008, 200) + { + m_gm = gm; + m_player = player; + } + public override void OnClick() + { + JailSystem.newJailingFromGMandPlayer(m_gm, m_player); + //this is where we jail them + } + } + + public class UnJailEntry : ContextMenuEntry + { + private Mobile m_gm; + private Mobile m_player; + private JailSystem js; + public UnJailEntry(Mobile gm, Mobile player) + : base(5135, 200) + { + m_gm = gm; + m_player = player; + js = JailSystem.fromMobile(m_player); + if (js == null) + Flags |= Network.CMEFlags.Disabled; + else if (!js.jailed) + Flags |= Network.CMEFlags.Disabled; + } + public override void OnClick() + { + if (js == null) + m_gm.SendMessage("They are not jailed"); + else if (js.jailed) + js.forceRelease(m_gm); + } + } + + public class MacroEntry : ContextMenuEntry + { + private Mobile m_gm; + private Mobile m_player; + private JailSystem js; + + public MacroEntry(Mobile gm, Mobile player) + : base(394, 200) + { + m_gm = gm; + m_player = player; + js = JailSystem.fromMobile(m_player); + if (js == null) + { } + else if (js.jailed) + Flags |= Network.CMEFlags.Disabled; + } + + public override void OnClick() + { + if (js == null) + JailSystem.macroTest(m_gm, m_player); + else if (!js.jailed) + JailSystem.macroTest(m_gm, m_player); + else + m_gm.SendMessage("They are already in jail."); + } + } + #endregion +} + +namespace Server.Items +{ + #region smoking boots + public class SmokingFootGear : Item + { + const int defaultShoes = 5899; + + public SmokingFootGear() + : base(defaultShoes) + { + Name = "Smoking boots"; + } + + public new TimeSpan DecayTime + { + get { return TimeSpan.FromSeconds(5); } + } + + public new bool Movable + { + get { return false; } + } + + public new bool Decays + { + get { return true; } + } + + public SmokingFootGear(Mobile m) + : base(findFootGear(m)) + { + Name = m.Name + "'s smoking boots"; + MoveToWorld(m.Location, m.Map); + new sTimer(this); + } + + static public int findFootGear(Mobile m) + { + try + { + foreach (Item i in m.Items) + { + if (i is Server.Items.BaseShoes) + { + if (i.Parent.Equals(m)) + //return i.ItemID; + return defaultShoes; + } + } + return defaultShoes; + } + catch + { + m.SendMessage("Flying Monkeys ate your shoes"); + return defaultShoes; + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + } + + public SmokingFootGear(Serial s) + : base(s) + { + } + + private class sTimer : Timer + { + SmokingFootGear footwear; + int tI = 1; + public sTimer(SmokingFootGear i) + : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5)) + { + footwear = i; + this.Start(); + } + protected override void OnTick() + { + if (tI == 1) + { + Point3D p = new Point3D(footwear.Location.X, footwear.Location.Y, footwear.Location.Z + 2); + Effects.SendLocationEffect(p, footwear.Map, 0x3735, 30); + Effects.PlaySound(p, footwear.Map, 0x5C); + tI++; + } + else + { + Effects.SendLocationEffect(footwear.Location, footwear.Map, 0x36BD, 10); + Effects.PlaySound(footwear.Location, footwear.Map, 0x307); + this.Stop(); + footwear.Delete(); + } + } + } + } + #endregion + + #region Cage + public class Cage : Item + { + private ArrayList m_Components; + + private class CagePart : Item + { + private Cage m_parent; + public override int LabelNumber { get { return 1016152; } } // a tree ornament + + public CagePart(int itemID, Cage parent) + : base(itemID) + { + m_parent = parent; + Movable = false; + } + + public override void OnDelete() + { + if (m_parent != null) + { + if (!m_parent.Deleted) + m_parent.Delete(); + } + base.OnDelete(); + } + + public CagePart(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + writer.Write((Item)m_parent); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 1: + m_parent = (Cage)reader.ReadItem(); + break; + default: + break; + } + } + } + + private HoldingCell cellblock; + + public Cage(Mobile from) + : base(1180) + { + this.Movable = false; + MoveToWorld(from.Location, from.Map); + m_Components = new ArrayList(); + cellblock = new HoldingCell(from.Location.X, from.Location.Y, from.Map); + AddItem(from, 1, 0, 0, new CagePart(1180, this), true);// right upper + AddItem(from, 1, 1, 0, new CagePart(1180, this), true);// right lower + AddItem(from, 0, 1, 0, new CagePart(1180, this), true);// left lower + + AddItem(from, 1, 1, 0, new CagePart(2082, this), true);// right lower + AddItem(from, 1, 0, 0, new CagePart(2081, this), true);//right center + AddItem(from, 1, -1, 0, new CagePart(2083, this), true);//right upper + AddItem(from, -1, 1, 0, new CagePart(2081, this), true);//left lower + AddItem(from, -1, 0, 0, new CagePart(2081, this), true);//left center + //AddItem( from, -1, -1, 0, new cagePart( 2083 ),true );//left upper + AddItem(from, 0, 1, 0, new CagePart(2083, this), true);//center lower + AddItem(from, 0, -1, 0, new CagePart(2083, this), true);//center upper + } + + private void AddItem(Mobile from, int x, int y, int z, Item item, bool vis) + { + item.Visible = vis; + item.MoveToWorld(new Point3D(from.Location.X + x, from.Location.Y + y, from.Location.Z + z), from.Map); + + m_Components.Add(item); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((int)m_Components.Count); + + for (int i = 0; i < m_Components.Count; ++i) + writer.Write((Item)m_Components[i]); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + default: + { + int count = reader.ReadInt(); + + m_Components = new ArrayList(count); + + for (int i = 0; i < count; ++i) + { + Item item = reader.ReadItem(); + + if (item != null) + m_Components.Add(item); + } + + break; + } + } + cellblock = new HoldingCell(this.X, this.Y, this.Map); + } + + public override void OnAfterDelete() + { + foreach (Item item in m_Components) + { + if ((item != null) && (!item.Deleted)) + item.Delete(); + } + cellblock.Unregister(); + } + + public Cage(Serial serial) + : base(serial) + { + } + } + #endregion +} + +namespace Server.Regions +{ + public class HoldingCell : Region + { + public HoldingCell(int x, int y, Map map) + : base("Cellule de d�tention", map, 100, new Rectangle2D(x - 1, y - 1, 4, 4)) + { + GoLocation = new Point3D(x, y, map.GetAverageZ(x, y)); + this.Register(); + } + + public override bool AllowBeneficial(Mobile from, Mobile target) + { + if (from.AccessLevel == AccessLevel.Player) + from.SendMessage("You may not do that in jail."); + + return (from.AccessLevel > AccessLevel.Player); + } + + public override bool AllowHarmful(Mobile from, Mobile target) + { + if (from.AccessLevel == AccessLevel.Player) + from.SendMessage("You may not do that in jail."); + + return (from.AccessLevel > AccessLevel.Player); + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + global = LightCycle.JailLevel; + } + + public override bool OnBeginSpellCast(Mobile from, ISpell s) + { + if (from.AccessLevel == AccessLevel.Player) + from.SendLocalizedMessage(502629); // You cannot cast spells here. + + return (from.AccessLevel > AccessLevel.Player); + } + + public override bool OnSkillUse(Mobile from, int Skill) + { + if (from.AccessLevel == AccessLevel.Player) + from.SendMessage("You may not use skills in jail."); + + return (from.AccessLevel > AccessLevel.Player); + } + + public override bool CanUseStuckMenu(Mobile m) + { + return false; + } + + public override bool OnCombatantChange(Mobile from, Mobile Old, Mobile New) + { + return (from.AccessLevel > AccessLevel.Player); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Cat Jail System/WarithJailEffect.cs b/Scripts/Customs/Cat Jail System/WarithJailEffect.cs new file mode 100644 index 0000000..417b8a2 --- /dev/null +++ b/Scripts/Customs/Cat Jail System/WarithJailEffect.cs @@ -0,0 +1,374 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Misc; +using Server.Items; +using Server.Targeting; +using Server.Network; +using Server.Multis; + +namespace Server.Commands +{ + public class WraithJailEffect + { + private PlayerMobile m_prisoner; + private PlayerMobile m_jailor; + + public Mobile Prisoner + { + get { return m_prisoner; } + } + + public WraithJailEffect(PlayerMobile prisoner, PlayerMobile jailor) + { + m_jailor = jailor; + m_prisoner = prisoner; + ((Mobile)m_prisoner).CantWalk = true; + ((Mobile)m_prisoner).Squelched = true; + Effects.PlaySound(jailor.Location, jailor.Map, 0x1DD); + + Point3D loc = new Point3D(prisoner.X, prisoner.Y, prisoner.Z); + int mushx; + int mushy; + int mushz; + + + InternalItem firstFlamea = new InternalItem(prisoner.Location, prisoner.Map, jailor); + mushx = loc.X - 2; + mushy = loc.Y - 2; + mushz = loc.Z; + Point3D mushxyz = new Point3D(mushx, mushy, mushz); + firstFlamea.MoveToWorld(mushxyz, prisoner.Map); + + InternalItem firstFlamec = new InternalItem(prisoner.Location, prisoner.Map, jailor); + mushx = loc.X; + mushy = loc.Y - 3; + mushz = loc.Z; + Point3D mushxyzb = new Point3D(mushx, mushy, mushz); + firstFlamec.MoveToWorld(mushxyzb, prisoner.Map); + + InternalItem firstFlamed = new InternalItem(prisoner.Location, prisoner.Map, jailor); + firstFlamed.ItemID = 0x3709; + mushx = loc.X + 2; + mushy = loc.Y - 2; + mushz = loc.Z; + Point3D mushxyzc = new Point3D(mushx, mushy, mushz); + firstFlamed.MoveToWorld(mushxyzc, prisoner.Map); + InternalItem firstFlamee = new InternalItem(prisoner.Location, prisoner.Map, jailor); + mushx = loc.X + 3; + firstFlamee.ItemID = 0x3709; + mushy = loc.Y; + mushz = loc.Z; + Point3D mushxyzd = new Point3D(mushx, mushy, mushz); + firstFlamee.MoveToWorld(mushxyzd, prisoner.Map); + InternalItem firstFlamef = new InternalItem(prisoner.Location, prisoner.Map, jailor); + firstFlamef.ItemID = 0x3709; + mushx = loc.X + 2; + mushy = loc.Y + 2; + mushz = loc.Z; + Point3D mushxyze = new Point3D(mushx, mushy, mushz); + firstFlamef.MoveToWorld(mushxyze, prisoner.Map); + InternalItem firstFlameg = new InternalItem(prisoner.Location, prisoner.Map, jailor); + mushx = loc.X; + firstFlameg.ItemID = 0x3709; + mushy = loc.Y + 3; + mushz = loc.Z; + Point3D mushxyzf = new Point3D(mushx, mushy, mushz); + firstFlameg.MoveToWorld(mushxyzf, prisoner.Map); + InternalItem firstFlameh = new InternalItem(prisoner.Location, prisoner.Map, jailor); + mushx = loc.X - 2; + firstFlameh.ItemID = 0x3709; + mushy = loc.Y + 2; + mushz = loc.Z; + Point3D mushxyzg = new Point3D(mushx, mushy, mushz); + firstFlameh.MoveToWorld(mushxyzg, prisoner.Map); + InternalItem firstFlamei = new InternalItem(prisoner.Location, prisoner.Map, jailor); + mushx = loc.X - 3; + firstFlamei.ItemID = 0x3709; + mushy = loc.Y; + mushz = loc.Z; + Point3D mushxyzh = new Point3D(mushx, mushy, mushz); + firstFlamei.MoveToWorld(mushxyzh, prisoner.Map); + new JailWraith(this, prisoner.X + 15, prisoner.Y + 15, m_jailor); + } + + public void jail() + { + JailSystem.Jail((m_prisoner as Mobile), TimeSpan.FromDays(2), "Interefering with a Role-Playing event.", true, (m_jailor as Mobile).Name, AccessLevel.Seer); + ((Mobile)m_prisoner).CantWalk = false; + ((Mobile)m_prisoner).Squelched = false; + (m_prisoner as Mobile).SendMessage("You are now in jail for disrupting an event. Do not expect to see the staff member who jailed you until after the event has ended."); + } + public static void Initialize() + { + CommandSystem.Register("jailwraith", AccessLevel.GameMaster, new CommandEventHandler(jail_OnCommand)); + } + + [Usage("jailwraith")] + [Description("Places the selected player in jail by a wraith.")] + public static void jail_OnCommand(CommandEventArgs e) + { + if (e.Mobile is PlayerMobile) + { + e.Mobile.Target = new InternalTarget(); + e.Mobile.SendLocalizedMessage(3000218); + } + } + + private class InternalTarget : Target + { + public InternalTarget() + : base(-1, false, TargetFlags.None) + { + } + protected override void OnTarget(Mobile from, object targeted) + { + if (from is PlayerMobile && targeted is PlayerMobile) + { + new WraithJailEffect(targeted as PlayerMobile, from as PlayerMobile); + } + } + } + + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Caster; + + public override bool BlocksFit { get { return true; } } + + public InternalItem(Point3D loc, Map map, Mobile caster) + : base(0x3709) + { + Visible = false; + Movable = false; + Light = LightType.Circle150; + MoveToWorld(loc, map); + m_Caster = caster; + Visible = true; + m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(30.0)); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds(30.0); + } + + public InternalItem(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write(m_End - DateTime.Now); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + TimeSpan duration = reader.ReadTimeSpan(); + + m_Timer = new InternalTimer(this, duration); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds(10.0); + + m_Timer = new InternalTimer(this, duration); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Timer != null) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + + private InternalItem m_Item; + + public InternalTimer(InternalItem item, TimeSpan duration) + : base(duration) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + } + + [CorpseName("a errie corpse")] + public class JailWraith : BaseCreature + { + private WraithJailEffect m_effect; + private bool drag = false; + private int m_endPointX; + private int m_endPointY; + + public JailWraith(WraithJailEffect effect, int endPointX, int endPointY, Mobile m_jailor) + : base(AIType.AI_Use_Default, FightMode.None, 10, 1, 0.2, 0.4) + { + m_endPointY = endPointY; + m_endPointX = endPointX; + m_effect = effect; + Name = "a soulless demon"; + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + this.Blessed = true; + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + this.CantWalk = true; + new InternalTimer(this); + this.X = m_jailor.X; + this.Y = m_jailor.Y; + this.Map = m_jailor.Map; + + } + + public JailWraith(Serial serial) + : base(serial) + { + } + + protected override void OnLocationChange(Point3D loc) + { + base.OnLocationChange(loc); + m_effect.Prisoner.Hidden = false; + this.Stam = 1000; + if (drag) + { + this.Direction = this.GetDirectionTo(m_endPointX, m_endPointY); + if ((this.X == m_endPointX) && (this.Y == m_endPointY)) + { + this.m_effect.jail(); + this.Delete(); + } + else + { + if (!(m_effect.Prisoner.Region is Regions.Jail)) + { + m_effect.Prisoner.Location = loc; + } + } + } + else + { + if ((this.X == m_effect.Prisoner.X) && (this.Y == m_effect.Prisoner.Y)) + { + this.Direction = this.GetDirectionTo(m_endPointX, m_endPointY); + m_effect.Prisoner.Kill(); + m_effect.Prisoner.Hidden = false; + drag = true; + this.PlaySound(this.GetAngerSound()); + } + else + this.Direction = this.GetDirectionTo(m_effect.Prisoner.Location); + + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private JailWraith m_Item; + + public InternalTimer(JailWraith item) + : base(TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(200)) + { + m_Item = item; + this.Start(); + this.Priority = TimerPriority.FiftyMS; + + } + + protected override void OnTick() + { + //yeah baby move me + if (m_Item.Deleted) this.Stop(); + int x; + int y; + x = m_Item.X; + y = m_Item.Y; + switch (m_Item.Direction) + { + case Direction.North: + x = x - 1; + break; + case Direction.Left: + y++; + x = x - 1; + break; + case Direction.West: + y++; + break; + case Direction.Down: + y++; + x++; + break; + case Direction.South: + x++; + break; + case Direction.Right: + y = y - 1; + x++; + break; + case Direction.East: + y = y - 1; + break; + case Direction.Up: + y = y - 1; + x = x - 1; + break; + default: + break; + } + m_Item.Location = new Point3D(x, y, m_Item.Z); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/BeginGump.cs b/Scripts/Customs/Challenge Game 2.0/BeginGump.cs new file mode 100644 index 0000000..9c7560c --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/BeginGump.cs @@ -0,0 +1,136 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Gumps +{ + public class BeginGump : Gump + { + private string message = "Please choose the type of challenge you wish to commence below or use the checkbox above to enable/disable the ability for others to challenge you."; + private PlayerMobile m_Challenger; + private ArrayList m_Stones; + private ChallengeGameType m_Game; + + public BeginGump(PlayerMobile challenger, ArrayList stones) + : base(0, 0) + { + m_Challenger = challenger; + m_Stones = stones; + + AddImageTiled(107, 132, 14, 14, 83); + AddImageTiled(121, 130, 245, 14, 84); + AddImageTiled(366, 132, 14, 14, 85); + AddImageTiled(107, 145, 14, 140, 86); + AddImageTiled(118, 144, 252, 143, 87); + AddImageTiled(366, 145, 14, 140, 88); + AddImageTiled(107, 285, 14, 14, 89); + AddImageTiled(121, 285, 245, 11, 90); + AddImageTiled(366, 285, 14, 14, 91); + AddHtml(105, 145, 233, 44, "
Accept challenges?
", false, false); + AddHtml(125, 170, 237, 77, "" + message + "", false, false); + AddLabel(169, 270, 43, string.Format("1vs1")); + AddLabel(242, 270, 43, string.Format("2vs2")); + + AddButton(197, 270, 0x15A2, 0x15A3, 1, GumpButtonType.Reply, 0); + AddButton(277, 270, 0x15A2, 0x15A3, 2, GumpButtonType.Reply, 0); + + if (m_Challenger.CanBeChallenged) + AddButton(280, 145, 0xD3, 0xD2, 3, GumpButtonType.Reply, 0); + else + AddButton(280, 145, 0xD2, 0xD3, 3, GumpButtonType.Reply, 0); + } + + public override void OnResponse(Server.Network.NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + PlayerMobile m = from as PlayerMobile; + + switch (info.ButtonID) + { + case 3: // Chal on/off + { + if (((PlayerMobile)from).CanBeChallenged) + { + ((PlayerMobile)from).CanBeChallenged = false; + from.SendMessage(63, "You will no longer accept challenge invitations!"); + } + else + { + ((PlayerMobile)from).CanBeChallenged = true; + from.SendMessage(63, "You may now accept challenge invitations!"); + } + from.SendGump(new BeginGump((PlayerMobile)from, m_Stones)); + + return; + } + case 2: // 2vs2 + { + m_Game = ChallengeGameType.TwoPlayerTeam; + break; + } + case 1: // 1vs1 + { + m_Game = ChallengeGameType.OnePlayerTeam; + break; + } + case 0: + { + from.SendMessage(43, "Cancelled!"); + + return; + } + } + + foreach (Item chall in m_Stones) + { + ChallengeStone challstone = chall as ChallengeStone; + if (challstone.Active == true && challstone.Game == m_Game) + { + if (m.Frozen == true) + { + from.SendMessage(43, "You cannot use right now because you are frozen!"); + return; + } + else if (m.GameTime < TimeSpan.FromMinutes(30.0)) + { + from.SendMessage(43, "The ladder system is usable by characters who have a character age of at least 30 minutes of in-game play!"); + return; + } + else if (m.IsInChallenge) + { + from.SendMessage(43, "You are already in the process of using the ladder system!"); + return; + } + else if (m.Hits != m.HitsMax) + { + from.SendMessage(43, "You must be fully healed before using the ladder system!"); + return; + } + else if (!m.CanBeChallenged) + { + from.SendMessage(43, "You currently have the challenge feature disabled, please enable it via the menu!"); + from.SendGump(new BeginGump((PlayerMobile)from, m_Stones)); + return; + } + else + { + challstone.ClearAll(); + m_Challenger.IsInChallenge = true; + challstone.OnDoubleClick(from); + return; + } + } + } + from.SendMessage(43, "There are no open ladder arenas for that type of challenge right now, please try again soon!"); + return; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/Challenge Keywords.cs b/Scripts/Customs/Challenge Game 2.0/Challenge Keywords.cs new file mode 100644 index 0000000..8e73bfc --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/Challenge Keywords.cs @@ -0,0 +1,98 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Challenge; + + +namespace Server +{ + public class DuelKeywords + { + public static void Initialize() + { + EventSink.Speech += new SpeechEventHandler(EventSink_Speech); + } + + private static void EventSink_Speech(SpeechEventArgs e) + { + Mobile from = e.Mobile; + string s_PlayersSpeech = e.Speech; + + if (!(e.Mobile is PlayerMobile)) + return; + + PlayerMobile x = (PlayerMobile)(e.Mobile); + + if (s_PlayersSpeech.ToLower().IndexOf("i challenge thee") >= 0) + StartDuel(false, x, Challenge.Challenge.WorldStones); + if (s_PlayersSpeech.ToLower().IndexOf("as a team we challenge thee") >= 0) + StartDuel(true, x, Challenge.Challenge.WorldStones); + } + public static void StartDuel(bool TwoPlayers, PlayerMobile challenger, ArrayList m_Stones) + { + Mobile from = (Mobile)challenger; + PlayerMobile m = from as PlayerMobile; + Items.ChallengeGameType m_Game; + + if (TwoPlayers) + m_Game = ChallengeGameType.TwoPlayerTeam; + else + m_Game = ChallengeGameType.OnePlayerTeam; + + + foreach (Item chall in m_Stones) + { + ChallengeStone challstone = chall as ChallengeStone; + if (challstone.Active == true && challstone.Game == m_Game) + { + if (m.Frozen == true) + { + from.SendMessage(43, "You cannot use right now because you are frozen!"); + return; + } + else if (m.Young) + { + from.SendMessage(43, "You can not use the ladder system if your young!"); + return; + } + else if (m.IsInChallenge) + { + from.SendMessage(43, "You are already in the process of using the ladder system!"); + return; + } + /* else if ( from.Map == Map.Trammel || from.Map == Map.Malas || from.Map == Map.Ilshenar ) + { + from.SendMessage(1266, "You can only duel in Felucca as we are having problems dueling in other facets!" ); + } */ + + + else + { + challstone.ClearAll(); + challenger.IsInChallenge = true; + challstone.OnDoubleClick(from); + { + if (m.Hits != m.HitsMax) + { + m.Hits = m.HitsMax; + m.Mana = 125; + m.Stam = 125; + } + return; + } + } + } + + } + } + } +} diff --git a/Scripts/Customs/Challenge Game 2.0/ChallengeRing.cs b/Scripts/Customs/Challenge Game 2.0/ChallengeRing.cs new file mode 100644 index 0000000..ff99a89 --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/ChallengeRing.cs @@ -0,0 +1,95 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using System.Collections; + +namespace Server.Items +{ + public class ChallengeRing : BaseRing + { + private ChallengeStone m_Item; + private ArrayList m_Players = new ArrayList(); + private int m_Kills; + private int m_Fame; + private int m_Karma; + private int m_ShortMurders; + + public ChallengeRing() + : base(0x108a) + { + } + [Constructable] + public ChallengeRing(ChallengeStone game, ArrayList players) + : base(0x108a) + { + Weight = 0.1; + Movable = false; + m_Item = game; + m_Players = players; + Name = " Challenege Ring "; + Attributes.LowerManaCost = 100; + Attributes.LowerRegCost = 100; + } + public ChallengeRing(Serial serial) + : base(serial) + { + } + public int Kills + { + get { return m_Kills; } + } + public override bool OnEquip(Mobile from) + { + m_Kills = from.Kills; + m_Fame = from.Fame; + m_Karma = from.Karma; + m_ShortMurders = from.ShortTermMurders; + from.Kills = 10; + return base.OnEquip(from); + } + public override void OnDelete() + { + if (this.Parent is PlayerMobile) + { + PlayerMobile m = (PlayerMobile)Parent; + m.Kills = m_Kills; + m.Fame = m_Fame; + m.Karma = m_Karma; + m.ShortTermMurders = m_ShortMurders; + m.Criminal = false; + } + base.OnDelete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + writer.Write((int)m_Kills); + writer.Write((int)m_Fame); + writer.Write((int)m_Karma); + writer.Write((int)m_ShortMurders); + } + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 0: + { + m_Kills = reader.ReadInt(); + m_Fame = reader.ReadInt(); + m_Karma = reader.ReadInt(); + m_ShortMurders = reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/ChallengeStone.cs b/Scripts/Customs/Challenge Game 2.0/ChallengeStone.cs new file mode 100644 index 0000000..0f76cdc --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/ChallengeStone.cs @@ -0,0 +1,668 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using System.Collections; +using Server.Commands; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; +using Server.Spells.Second; + +namespace Server.Challenge +{ + public class Challenge + { + private static ArrayList worldStones = new ArrayList(); + + public static void Initialize() + { + CommandSystem.Register( "Challenge", AccessLevel.Administrator, new CommandEventHandler( Challenge_OnCommand ) ); + Configure(); + } + + public static void Configure() + { + EventSink.WorldLoad+= new WorldLoadEventHandler(onLoad); + } + + public static ArrayList WorldStones + { + get { return worldStones; } + set { worldStones = value; } + } + public static void onLoad() + { + foreach ( Mobile mob in World.Mobiles.Values ) + { + if ( mob is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)mob; + if( pm.IsInChallenge ) + { + pm.IsInChallenge = false; + int kills = 0; + + if( pm.FindItemOnLayer( Layer.Ring ) is ChallengeRing ) + { + pm.FindItemOnLayer( Layer.Ring ).Delete(); + ChallengeRing ring = pm.FindItemOnLayer(Layer.Ring )as ChallengeRing; + kills = ring.Kills; + } + + pm.LogoutMap = Map.Trammel; + if( kills >= 5 ) + pm.LogoutLocation = new Point3D(3503, 2574, 14); // New Haven + else + pm.LogoutLocation = new Point3D(3503, 2574, 14); // New Haven + + if( pm.TempMount != null ) + { + pm.TempMount.Rider = pm; + pm.TempMount = null; + } + } + } + } + foreach ( Item item in World.Items.Values ) + { + if (item is ChallengeStone) + { + WorldStones.Add(item); + } + } + } + + [Usage( "Challenge" )] + [Description( "Initiates Challenge Game!" )] + public static void Challenge_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + + from.CloseGump( typeof( BeginGump ) ); + from.SendGump( new BeginGump( (PlayerMobile)from, WorldStones ) ); + + return; + } + } +} + +namespace Server.Items +{ + public enum ChallengeGameType + { + OnePlayerTeam, TwoPlayerTeam + } + + [Serializable()] + public class ChallengeStone : Item + { + public bool m_Active; + public Point3D m_ChallengerPointDest; + public Point3D m_OpponentPointDest; + public Point3D m_ChallengerExitPointDest; + public Point3D m_OpponentExitPointDest; + public Map m_MapDest; + public Map m_MapOrig; + private Mobile m_OpponentMobile; + private Mobile m_ChallengerMobile; + private ChallengeGameType m_Game = ChallengeGameType.OnePlayerTeam; + private ArrayList m_ChallengePlayers = new ArrayList(); + private ArrayList m_OpponentPlayers = new ArrayList(); + private ArrayList m_ChallengerDead = new ArrayList(); + private ArrayList m_OpponentDead = new ArrayList(); + private int duelLength = 30; + + public ArrayList ChallengeTeam { get { return m_ChallengePlayers; } } + public ArrayList OpponentTeam { get { return m_OpponentPlayers; } } + public ArrayList ChallengerDead { get { return m_ChallengerDead; } } + public ArrayList OpponentDead { get { return m_OpponentDead; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int DuelLength + { + get { return duelLength; } + set { duelLength = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public ChallengeGameType Game + { + get { return m_Game; } + set { m_Game = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Active + { + get { return m_Active; } + set + { + m_Active = value; InvalidateProperties(); + if (m_Active == true) + Name = "Pierre de Duel [Libre]"; + if (m_Active == false) + Name = "Pierre de Duel [Occup�e]"; + } + + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D ChallengerPointDest + { + get { return m_ChallengerPointDest; } + set { m_ChallengerPointDest = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D OpponentPointDest + { + get { return m_OpponentPointDest; } + set { m_OpponentPointDest = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map MapDest + { + get { return m_MapDest; } + set { m_MapDest = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map MapOrig + { + get { return m_MapOrig; } + set { m_MapOrig = value; } + } + + + [Constructable] + public ChallengeStone() + : this(new Point3D(0, 0, 0), new Point3D(0, 0, 0), new Point3D(0, 0, 0), new Point3D(0, 0, 0), null, null, false) + { + } + + [Constructable] + public ChallengeStone(Point3D challengerpointDest, Point3D opponentpointDest, Point3D challengerexit, Point3D opponentexit, Map mapDest, Map mapOrig, bool creatures) + : base(0xED4) + { + Movable = false; + Hue = 0; + Name = "a Ladder Dueling stone"; + + Active = true; + m_ChallengerPointDest = challengerpointDest; + m_OpponentPointDest = opponentpointDest; + m_ChallengerExitPointDest = challengerexit; + m_OpponentExitPointDest = opponentexit; + m_MapDest = mapDest; + m_MapOrig = mapOrig; + m_ChallengePlayers = new ArrayList(); + m_OpponentPlayers = new ArrayList(); + m_ChallengerDead = new ArrayList(); + m_OpponentDead = new ArrayList(); + Challenge.Challenge.WorldStones.Add(this); + } + public override void OnSingleClick(Mobile from) + { + if (Active == true) + { + LabelTo(from, Name); + LabelTo(from, "Not in use"); + } + if (Active == false) + { + LabelTo(from, Name); + LabelTo(from, "In Use"); + } + } + + public void AddChallengePlayer(PlayerMobile player) + { + ChallengeTeam.Add(player); + } + public void AddOpponentPlayer(PlayerMobile player) + { + OpponentTeam.Add(player); + } + public void RemoveChallengePlayer(PlayerMobile player) + { + ChallengeTeam.Remove(player); + } + public void RemoveOpponentPlayer(PlayerMobile player) + { + OpponentTeam.Remove(player); + } + public void AddChallengerDead(PlayerMobile player) + { + ChallengerDead.Add(player); + } + public void AddOpponentDead(PlayerMobile player) + { + OpponentDead.Add(player); + } + public void ClearAll() + { + Active = true; + foreach (PlayerMobile opponent in OpponentTeam) + { + opponent.IsInChallenge = false; + } + foreach (PlayerMobile challenger in ChallengeTeam) + { + challenger.IsInChallenge = false; + } + ChallengeTeam.Clear(); + ChallengerDead.Clear(); + OpponentTeam.Clear(); + OpponentDead.Clear(); + } + + public override void OnDelete() + { + base.OnDelete(); + if (Challenge.Challenge.WorldStones.Contains(this)) + { + Challenge.Challenge.WorldStones.Remove(this); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (Active) + { + PlayerMobile pm = from as PlayerMobile; + Active = false; + pm.IsInChallenge = true; + + from.Hidden = false; + this.ChallengeTeam.Add(pm); + from.Target = new ChallengeTarget(pm, this, 0); + + if (m_Game == ChallengeGameType.TwoPlayerTeam) + from.SendMessage(33, "Please Choose Your Partner "); + else + from.SendMessage(33, "Please Choose Your Opponent "); + } + + } + public void makeready(Mobile who) + { + PlayerMobile c = (PlayerMobile)who; + if (!who.Alive) + who.Resurrect(); + + Container bp = c.Backpack; + Container bankbag = new Bag(); + bankbag.Hue = 63; + BankBox bank = c.BankBox; + Item oncurs = c.Holding; + + if (oncurs != null) + bp.DropItem(oncurs); + + c.SendMessage("You have 10 seconds until the duel begins"); + c.SendMessage(63, "After one of you dies, both of you will be teleported out"); + + c.Criminal = true; + c.CurePoison(c); + + c.Blessed = true; + c.Frozen = true; + + c.Hits = c.HitsMax; + c.Mana = c.ManaMax; + c.Stam = c.StamMax; + + c.StatMods.Clear(); + + if (bp != null) + { + Item toDisarm = c.FindItemOnLayer(Layer.OneHanded); + + if (toDisarm == null || !toDisarm.Movable) + toDisarm = c.FindItemOnLayer(Layer.TwoHanded); + + if (toDisarm != null) + bp.DropItem(toDisarm); + + if (c.Mount != null) + { + IMount mount = c.Mount; + mount.Rider = null; + if (mount is BaseMount) + { + BaseMount oldMount = (BaseMount)mount; + oldMount.Map = Map.Internal; + c.TempMount = oldMount; + } + } + + while ((BasePotion)bp.FindItemByType(typeof(BasePotion)) != null) + { + BasePotion potion = (BasePotion)bp.FindItemByType(typeof(BasePotion)); + bankbag.DropItem(potion); + } + while ((EtherealMount)bp.FindItemByType(typeof(EtherealMount)) != null) + { + EtherealMount mount = (EtherealMount)bp.FindItemByType(typeof(EtherealMount)); + bankbag.DropItem(mount); + } + /*Item[] weps = bp.FindItemsByType( typeof( BaseWeapon ) ); + for ( int i = 0; i < weps.Length; ++i ) + { + Item item = (Item)weps[i]; + BaseWeapon weapon = item as BaseWeapon; + if( weapon.DamageLevel > WeaponDamageLevel.Regular ) + bankbag.DropItem( item ); + }*/ + if (bankbag.Items.Count > 0) + bank.DropItem(bankbag); + else + bankbag.Delete(); + } + } + public void TimerStart() + { + new InternalTimer(this).Start(); + } + public class InternalTimer : Timer + { + private int m_Count = 10; + private ChallengeStone m_Item; + private ArrayList m_Players = new ArrayList(); + private DateTime duelstart; + + public InternalTimer(ChallengeStone item) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Item = item; + m_Players.AddRange(item.ChallengeTeam); + m_Players.AddRange(item.OpponentTeam); + } + + public void nocheat(Mobile who) + { + Targeting.Target.Cancel(who); + who.MagicDamageAbsorb = 0; + who.MeleeDamageAbsorb = 0; + ProtectionSpell.Registry.Remove(who); + DefensiveSpell.Nullify(who); + } + protected override void OnTick() + { + m_Count--; + + if ((m_Count % 5) == 0 && m_Count > 10) + { + foreach (PlayerMobile pm in m_Players) + pm.SendMessage("{0} seconds until the duel begins.", m_Count); + } + else if (m_Count <= 10 && m_Count > 0) + { + foreach (PlayerMobile pm in m_Players) + pm.SendMessage("{0}", m_Count); + } + else if (m_Count == 0) + { + foreach (PlayerMobile pm in m_Players) + { + nocheat((Mobile)pm); + pm.Frozen = false; + pm.Blessed = false; + pm.Warmode = true; + ChallengeRing ring = new ChallengeRing(m_Item, m_Players); + pm.EquipItem(ring); + pm.SendMessage(43, "GO GO GO GO GO!"); + } + new FightTimer(m_Item, m_Players).Start(); + Stop(); + } + } + } + public class FightTimer : Timer + { + private double m_Count; + private int m_Seconds; + private ChallengeStone m_Item; + private ArrayList m_Players; + + public FightTimer(ChallengeStone item, ArrayList players) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Item = item; + m_Players = players; + m_Count = item.DuelLength; + m_Seconds = item.DuelLength * 60; + } + + public void attrib(Mobile who) + { + PlayerMobile m = who as PlayerMobile; + + RemoveRing(m); + m.Aggressed.Clear(); + m.Aggressors.Clear(); + if (!who.Alive) + who.Resurrect(); + + if (m.TempMount != null) + { + m.TempMount.Rider = m; + m.TempMount = null; + } + m.Criminal = false; + m.Warmode = false; + m.PlaySound(0x214); + m.FixedEffect(0x376A, 10, 16); + m.Hits = m.HitsMax; + m.Mana = m.ManaMax; + m.Stam = m.StamMax; + } + public void RemoveRing(PlayerMobile m) + { + ChallengeRing ring = new ChallengeRing(); + + foreach (Item item in m.Items) + { + if (item is ChallengeRing) + ring = item as ChallengeRing; + } + if (ring != null) + ring.Delete(); + } + public void winner(PlayerMobile winner) + { + winner.BankBox.Open(); + winner.SendMessage(43, "Congratulations on winning the duel!!"); + winner.SendMessage(43, "Don't forget to retreive your items from the bank!!"); + //winner.Wins += 1; + } + + public void loser(PlayerMobile loser) + { + loser.BankBox.Open(); + loser.SendMessage(43, "Somebody get owned?"); + loser.SendMessage(43, "Don't forget to retreive your items from the bank!!"); + loser.Corpse.MoveToWorld(loser.Location); + //loser.Loses += 1; + } + protected override void OnTick() + { + m_Seconds--; + m_Count = (m_Seconds / 60); + + if ((m_Count % 5) == 0 && m_Count <= 30 && (double)m_Count == (double)m_Seconds / 60) + { + foreach (PlayerMobile pm in m_Players) + pm.SendMessage("The Duel will end in {0} minutes ", m_Count); + } + else if (m_Count == 1 && (double)m_Count == (double)m_Seconds / 60) + { + foreach (PlayerMobile pm in m_Players) + pm.SendMessage("1 minute left"); + } + else if (m_Seconds <= 10) + { + foreach (PlayerMobile pm in m_Players) + pm.SendMessage("{0}", m_Seconds); + } + else if (m_Count == 0) + { + foreach (PlayerMobile pm in m_Players) + { + pm.SendMessage(43, "You failed to kill your opponent. The game is ending..."); + pm.SendMessage(43, "Don't forget to retreive your items from the bank!!"); + attrib(pm as Mobile); + } + + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + { + challenger.Location = m_Item.m_ChallengerExitPointDest; + challenger.Map = m_Item.m_MapOrig; + } + + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + { + opponent.Location = m_Item.m_OpponentExitPointDest; + opponent.Map = m_Item.m_MapOrig; + } + + m_Item.ClearAll(); + Stop(); + } + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + { + if (!challenger.Alive) + { + if (!m_Item.ChallengerDead.Contains(challenger)) + m_Item.AddChallengerDead(challenger); + } + } + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + { + if (!opponent.Alive) + { + if (!m_Item.OpponentDead.Contains(opponent)) + m_Item.AddOpponentDead(opponent); + } + } + if (m_Item.ChallengerDead.Count == m_Item.ChallengeTeam.Count || m_Item.OpponentDead.Count == m_Item.OpponentTeam.Count) + { + foreach (PlayerMobile pm in m_Players) + { + attrib(pm as Mobile); + } + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + { + if (challenger.NetState != null) + { + challenger.Location = m_Item.m_ChallengerExitPointDest; + challenger.Map = m_Item.m_MapOrig; + } + else + challenger.LogoutLocation = m_Item.m_ChallengerExitPointDest; + } + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + { + if (opponent.NetState != null) + { + opponent.Location = m_Item.m_OpponentExitPointDest; + opponent.Map = m_Item.m_MapOrig; + } + else + opponent.LogoutLocation = m_Item.m_OpponentExitPointDest; + } + if (m_Item.ChallengerDead.Count == m_Item.ChallengeTeam.Count && m_Item.OpponentDead.Count == m_Item.OpponentTeam.Count) + { + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + challenger.SendMessage(63, "Neither side lost, due to all fighters being dead.."); + + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + opponent.SendMessage(63, "Neither side lost, due to all fighters being dead.."); + } + if (m_Item.ChallengerDead.Count == m_Item.ChallengeTeam.Count) + { + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + winner(opponent); + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + loser(challenger); + } + if (m_Item.OpponentDead.Count == m_Item.OpponentTeam.Count) + { + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + winner(challenger); + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + loser(opponent); + } + m_Item.ClearAll(); + Stop(); + } + } + } + public ChallengeStone(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)4);// version + + writer.Write(m_MapOrig); + writer.Write((int)duelLength); + writer.Write((int)m_Game); + writer.Write(m_ChallengerExitPointDest); + writer.Write(m_OpponentExitPointDest); + writer.Write(true); + writer.Write(m_ChallengerPointDest); + writer.Write(m_OpponentPointDest); + writer.Write(m_MapDest); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 4: + { + m_MapOrig = reader.ReadMap(); + goto case 3; + } + case 3: + { + duelLength = reader.ReadInt(); + goto case 2; + } + case 2: + { + m_Game = (ChallengeGameType)reader.ReadInt(); + goto case 1; + } + + case 1: + { + m_ChallengerExitPointDest = reader.ReadPoint3D(); + m_OpponentExitPointDest = reader.ReadPoint3D(); + goto case 0; + } + + case 0: + { + m_Active = reader.ReadBool(); + m_ChallengerPointDest = reader.ReadPoint3D(); + m_OpponentPointDest = reader.ReadPoint3D(); + m_MapDest = reader.ReadMap(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/ChallengeTarget.cs b/Scripts/Customs/Challenge Game 2.0/ChallengeTarget.cs new file mode 100644 index 0000000..8136d58 --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/ChallengeTarget.cs @@ -0,0 +1,142 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using System.Collections; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Targeting; +using Server.Multis; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Items +{ + public class ChallengeTarget : Target + { + private PlayerMobile pm; + private ChallengeStone m_Item; + private const string ChallengeeFormat = "{0} is challenging me!"; + private const string TeamFormat = "{0} is selecting me to be a teammate!"; + private int i; + + public ChallengeTarget(PlayerMobile from, ChallengeStone item, int count) + : base(100, false, TargetFlags.None) + { + pm = from; + m_Item = item; + i = count; + } + + protected override void OnCantSeeTarget(Mobile from, object target) + { m_Item.ClearAll(); } + + protected override void OnTargetCancel(Mobile from, TargetCancelType Overriden) + { m_Item.ClearAll(); } + + protected override void OnTargetDeleted(Mobile from, object target) + { m_Item.ClearAll(); } + + protected override void OnTargetNotAccessible(Mobile from, object target) + { m_Item.ClearAll(); } + + protected override void OnTargetOutOfLOS(Mobile from, object target) + { m_Item.ClearAll(); } + + protected override void OnTargetOutOfRange(Mobile from, object target) + { m_Item.ClearAll(); } + + protected override void OnTargetUntargetable(Mobile from, object target) + { m_Item.ClearAll(); } + + protected override void OnTarget(Mobile from, object target) + { + if (m_Item.ChallengeTeam.Contains(target)) + { + from.SendMessage("You can't add someone already on your team"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (m_Item.OpponentTeam.Contains(target)) + { + from.SendMessage("You can't challenge someone already on the opposing team"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (!(target is PlayerMobile)) + { + from.SendMessage("You can't target that"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (target is PlayerMobile) + { + PlayerMobile m = (PlayerMobile)target; + + if (m.Young == true) + { + from.SendMessage(33, "You can not challenge someone who is young, select again!"); + m.SendMessage(33, "The ladder system is not usable by characters who are young!"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (m.Frozen == true) + { + from.SendMessage(33, "That player is frozen, select again!"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (m.Hits != m.HitsMax) + { + from.SendMessage(33, "Player's health must be full in order to be challenged, select again!"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (m.IsInChallenge) + { + from.SendMessage(33, "That player is currently being invited into a challenge, select again!"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else if (!m.CanBeChallenged) + { + from.SendMessage(33, "That player is currently not accepting challenge invitations, select again!"); + from.Target = new ChallengeTarget(pm, m_Item, i); + } + else + { + if (m_Item.Game == ChallengeGameType.OnePlayerTeam) + { + m_Item.AddOpponentPlayer(m); + m.IsInChallenge = true; + m.PublicOverheadMessage(MessageType.Regular, 1153, true, String.Format(ChallengeeFormat, from.Name)); + m.SendGump(new FinalGump(pm, m, m_Item)); + } + else if (m_Item.Game == ChallengeGameType.TwoPlayerTeam) + { + m.IsInChallenge = true; + + if (i < 2) + { + if (i == 0) + { + m_Item.ChallengeTeam.Add(m); + m.PublicOverheadMessage(MessageType.Regular, 1153, true, String.Format(TeamFormat, from.Name)); + } + if (i == 1) + { + m_Item.OpponentTeam.Add(m); + m.PublicOverheadMessage(MessageType.Regular, 1153, true, String.Format(ChallengeeFormat, from.Name)); + } + i++; + m.SendGump(new PartnerGump(pm, m_Item, i, m)); + } + else if (i == 2) + { + m_Item.OpponentTeam.Add(m); + m.PublicOverheadMessage(MessageType.Regular, 1153, true, String.Format(ChallengeeFormat, from.Name)); + m.SendGump(new FinalGump(pm, m, m_Item)); + i = 0; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/FinalGump.cs b/Scripts/Customs/Challenge Game 2.0/FinalGump.cs new file mode 100644 index 0000000..b77e428 --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/FinalGump.cs @@ -0,0 +1,170 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using System.Collections; +using Server.Targeting; + +namespace Server.Gumps +{ + public class FinalGump : Gump + { + private Mobile m_OpponentMobile; + private Mobile m_ChallengerMobile; + private ChallengeStone m_Item; + private ArrayList m_Players = new ArrayList(); + public ResponseTimers m_Timer; + private string message = "All protective spells will be removed before fight begins. All illegal items will be returned to your bank after the fight is finished."; + private const string Affraid = "{0} got scared and refused the challenge!"; + private const string Error = "There was an error while trying to form this challenge, please try again shortly!"; + + public FinalGump(PlayerMobile challenger, PlayerMobile opponent, ChallengeStone item) + : base(0, 0) + { + m_OpponentMobile = opponent; + m_ChallengerMobile = challenger; + m_Item = item; + m_Timer = new ResponseTimers(m_Item, m_OpponentMobile); + m_Timer.Start(); + + Closable = false; + Dragable = false; + + Targeting.Target.Cancel(m_ChallengerMobile); + Targeting.Target.Cancel(m_OpponentMobile); + + AddImageTiled(107, 132, 14, 14, 83); + AddImageTiled(121, 130, 245, 14, 84); + AddImageTiled(366, 132, 14, 14, 85); + AddImageTiled(107, 145, 14, 140, 86); + AddImageTiled(118, 144, 252, 143, 87); + AddImageTiled(366, 145, 14, 140, 88); + AddImageTiled(107, 285, 14, 14, 89); + AddImageTiled(121, 285, 245, 11, 90); + AddImageTiled(366, 285, 14, 14, 91); + AddHtml(123, 154, 233, 20, "
Will you accept " + challenger.Name + "'s challenge?
", false, false); + AddHtml(125, 175, 237, 77, "" + message + "", false, false); + AddButton(135, 260, 2128, 2130, 1, GumpButtonType.Reply, 0); + AddButton(300, 260, 2119, 2121, 2, GumpButtonType.Reply, 0); + + } + public class ResponseTimers : Timer + { + private int m_Count = 20; + private ChallengeStone m_Item; + private Mobile m_ChallengerMobile; + + public ResponseTimers(ChallengeStone item, Mobile challenger) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Item = item; + m_ChallengerMobile = challenger; + } + protected override void OnTick() + { + m_Count--; + + if (m_Count == 0) + { + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + { + opponent.SendMessage(43, String.Format(Error)); + } + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + { + challenger.SendMessage(43, String.Format(Error)); + } + + m_Item.ClearAll(); + m_ChallengerMobile.CloseGump(typeof(FinalGump)); + Stop(); + } + + if (m_ChallengerMobile.NetState == null) + { + m_Item.ClearAll(); + Stop(); + } + } + } + + public override void OnResponse(NetState state, RelayInfo info) //Function for GumpButtonType.Reply Buttons + { + Mobile from = state.Mobile; + m_Timer.Stop(); + m_Players.AddRange(m_Item.ChallengeTeam); + m_Players.AddRange(m_Item.OpponentTeam); + + switch (info.ButtonID) + { + case 2: + { + foreach (PlayerMobile pm in m_Players) + { + pm.SendMessage(43, String.Format(Affraid, from.Name)); + } + + m_Item.ClearAll(); + break; + } + + case 1: + { + m_Item.m_ChallengerExitPointDest = m_ChallengerMobile.Location; + m_Item.m_OpponentExitPointDest = from.Location; + m_Item.m_MapOrig = m_ChallengerMobile.Map; + + foreach (PlayerMobile pm in m_Players) + { + Mobile fighters = pm as Mobile; + pm.SendMessage(63, "The Challenge is accepted. Let the duel begin!"); + m_Item.makeready(fighters); + } + + Point3D temp1 = m_Item.m_ChallengerPointDest; + Point3D temp2 = m_Item.m_OpponentPointDest; + Map map = m_Item.m_MapDest; + + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + { + Point3D p = new Point3D((temp1.X + 1), temp1.Y, temp1.Z); + if (p == Point3D.Zero) + p = challenger.Location; + + if (map == null || map == Map.Internal) + map = challenger.Map; + + challenger.MoveToWorld(p, map); + } + + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + { + Point3D q = new Point3D((temp2.X - 1), temp2.Y, temp2.Z); + if (q == Point3D.Zero) + q = opponent.Location; + + if (map == null || map == Map.Internal) + map = opponent.Map; + + opponent.MoveToWorld(q, map); + } + m_Item.TimerStart(); + break; + } + + case 0: + { + m_Item.ClearAll(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/PartnerGump.cs b/Scripts/Customs/Challenge Game 2.0/PartnerGump.cs new file mode 100644 index 0000000..71aa2a3 --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/PartnerGump.cs @@ -0,0 +1,96 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Gumps +{ + public class PartnerGump : Gump + { + private PlayerMobile m_ChallengerMobile; + private PlayerMobile m_OpponentMobile; + private ChallengeStone m_Item; + private int i; + public ResponseTimers m_Timer2; + private string message = "All protective spells will be removed before fight begins. All illegal items will be returned to your bank after the fight is finished."; + private const string Affraid = "{0} got scared and refused the challenge!"; + private const string Error = "There was an error while trying to form this challenge, please try again shortly!"; + + public PartnerGump(PlayerMobile challenger, ChallengeStone item, int counter, PlayerMobile opponent) + : base(0, 0) + { + i = counter; + m_ChallengerMobile = challenger; + m_OpponentMobile = opponent; + m_Item = item; + m_Timer2 = new ResponseTimers(m_Item, m_OpponentMobile); + m_Timer2.Start(); + + Closable = false; + Dragable = false; + + AddImageTiled(107, 132, 14, 14, 83); + AddImageTiled(121, 130, 245, 14, 84); + AddImageTiled(366, 132, 14, 14, 85); + AddImageTiled(107, 145, 14, 140, 86); + AddImageTiled(118, 144, 252, 143, 87); + AddImageTiled(366, 145, 14, 140, 88); + AddImageTiled(107, 285, 14, 14, 89); + AddImageTiled(121, 285, 245, 11, 90); + AddImageTiled(366, 285, 14, 14, 91); + AddHtml(115, 145, 233, 44, "
Will you join " + m_ChallengerMobile.Name + " as your partner in a challenge?
", false, false); + AddHtml(125, 190, 237, 77, "" + message + "", false, false); + AddButton(135, 270, 2128, 2130, 1, GumpButtonType.Reply, 0); + AddButton(300, 270, 2119, 2121, 2, GumpButtonType.Reply, 0); + } + + public override void OnResponse(Server.Network.NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + m_Timer2.Stop(); + switch (info.ButtonID) + { + case 2: + { + foreach (PlayerMobile opponent in m_Item.OpponentTeam) + { + opponent.SendMessage(43, String.Format(Affraid, from.Name)); + } + foreach (PlayerMobile challenger in m_Item.ChallengeTeam) + { + challenger.SendMessage(43, String.Format(Affraid, from.Name)); + } + + m_Item.ClearAll(); + break; + } + case 1: + { + if (m_Item.Game == ChallengeGameType.TwoPlayerTeam) + { + if (i == 1) + m_ChallengerMobile.SendMessage("Choose each of your opponents."); + else if (i == 2) + m_ChallengerMobile.SendMessage("Choose the last opponent."); + } + + m_ChallengerMobile.Target = new ChallengeTarget(m_ChallengerMobile, m_Item, i); + break; + } + + case 0: + { + m_Item.ClearAll(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/PlayerMobile.cs mods.txt b/Scripts/Customs/Challenge Game 2.0/PlayerMobile.cs mods.txt new file mode 100644 index 0000000..03a97e0 --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/PlayerMobile.cs mods.txt @@ -0,0 +1,35 @@ +add these flags: + + isinchal = 0x00100001, + canbechal = 0x00100002, + TempMount = 0x00100003 + +Under private int m_Profession; + + add + + private int m_Profession; + private bool isinchal = false; + private bool canbechal = true; + private BaseMount m_TempMount; + + [CommandProperty( AccessLevel.GameMaster ) ] + public BaseMount TempMount + { + get { return m_TempMount; } + set { m_TempMount = value; } + } + + [CommandProperty(AccessLevel.Counselor)] + public bool IsInChallenge + { + get{return isinchal;} + set{isinchal = value;} + } + + [CommandProperty(AccessLevel.Counselor)] + public bool CanBeChallenged + { + get{return canbechal;} + set{canbechal = value;} + } \ No newline at end of file diff --git a/Scripts/Customs/Challenge Game 2.0/ResponseTimer.cs b/Scripts/Customs/Challenge Game 2.0/ResponseTimer.cs new file mode 100644 index 0000000..97e13bd --- /dev/null +++ b/Scripts/Customs/Challenge Game 2.0/ResponseTimer.cs @@ -0,0 +1,61 @@ +/* + Challenge Game 2.0 + Update for RunUO 2.0 by Lokai + 7/18/2006 +*/ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Items +{ + public class ResponseTimers : Timer + { + private int m_Count = 20; + private ChallengeStone m_Item; + private Mobile m_ChallengerMobile; + private PlayerMobile m; + private const string Affraid = "{0} got scared and refused the challenge!"; + private const string Error = "There was an error while trying to form this challenge, please try again shortly!"; + + public ResponseTimers( ChallengeStone item, Mobile challenger ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 )) + { + m_Item = item; + m_ChallengerMobile = challenger; + m = challenger as PlayerMobile; + } + protected override void OnTick() + { + m_Count--; + if( m_Count == 0 ) + { + if(m_Item.ChallengeTeam.Count == 0) + { + m_ChallengerMobile.SendMessage( 43, "Timer has expired, try again later."); + m.IsInChallenge = false; + } + foreach ( PlayerMobile opponent in m_Item.OpponentTeam ) + { + opponent.SendMessage(43, String.Format( Error ) ); + } + foreach( PlayerMobile challenger in m_Item.ChallengeTeam ) + { + challenger.SendMessage(43, String.Format( Error ) ); + } + m_Item.ClearAll(); + m_ChallengerMobile.CloseGump( typeof( FinalGump )); + m_ChallengerMobile.CloseGump( typeof( PartnerGump )); + Stop(); + } + + if( m_ChallengerMobile.NetState == null ) + { + m_Item.ClearAll(); + Stop(); + } + } + } +} diff --git a/Scripts/Customs/Encryption/Configuration.cs b/Scripts/Customs/Encryption/Configuration.cs new file mode 100644 index 0000000..3f69923 --- /dev/null +++ b/Scripts/Customs/Encryption/Configuration.cs @@ -0,0 +1,63 @@ + +namespace Server.Engines.Encryption +{ + public class Configuration + { + // Set this to true to enable this subsystem. + public static bool Enabled = true; + + // Set this to false to disconnect unencrypted connections. + public static bool AllowUnencryptedClients = true; + + // This is the list of supported game encryption keys. + // You can use the utility found at http://www.hartte.de/ExtractKeys.exe + // to extract the neccesary keys from any client version. + public static LoginKey[] LoginKeys = new LoginKey[] + { + new LoginKey("7.0.34.6", 0x28EAAFDD, 0xA157227F), + new LoginKey("7.0.34.2", 0x28EAAFDD, 0xA157227F), + new LoginKey("7.0.34.0", 0x28EAAFDD, 0xA157227F), + new LoginKey("7.0.33.0", 0x28A325ED, 0xA1767E7F), + new LoginKey("7.0.32.11", 0x289BA7FD, 0xA169527F), + new LoginKey("7.0.31.0", 0x295C260D, 0xA197BE7F), + new LoginKey("7.0.30.1", 0x2904AC1D, 0xA1BCA27F), + new LoginKey("7.0.29.2", 0x29CD362D, 0xA1D59E7F), + new LoginKey("7.0.29.0", 0x29CD362D, 0xA1D59E7F), + new LoginKey("7.0.28.0", 0x29B5843D, 0xA1EA127F), + new LoginKey("7.0.27.66", 0x2A7E164D, 0xA0081E7F), + new LoginKey("7.0.27.9", 0x2A7E164D, 0xA0081E7F), + new LoginKey("7.0.27.8", 0x2A7E164D, 0xA0081E7F), + // previous keys + new LoginKey("7.0.27.7", 0x2A7E164D, 0xA0081E7F), + new LoginKey("7.0.26.5", 0x2A26EC5D, 0xA019A27F), + new LoginKey("7.0.26.4", 0x2A26EC5D, 0xA019A27F), + new LoginKey("7.0.25.7", 0x2AEF466D, 0xA07F3E7F), + new LoginKey("7.0.25.6", 0x2AEF466D, 0xA07F3E7F), + new LoginKey("7.0.25.0", 0x2AEF466D, 0xA07F3E7F), + new LoginKey("7.0.24.5", 0x2AD7247D, 0xA065527F), + new LoginKey("7.0.24.3", 0x2AD7247D, 0xA065527F), + new LoginKey("7.0.24.2", 0x2AD7247D, 0xA065527F), + new LoginKey("7.0.23.1", 0x2A9F868D, 0xA0437E7F), + new LoginKey("7.0.23.0", 0x2A9F868D, 0xA0437E7F), + new LoginKey("7.0.22.8", 0x2B406C9D, 0xA0A1227F), + new LoginKey("7.0.22.0", 0x2B406C9D, 0xA0A1227F), + new LoginKey("7.0.21.2", 0x2B08D6AD, 0xA0875E7F), + new LoginKey("7.0.21.1", 0x2B08D6AD, 0xA0875E7F), + new LoginKey("7.0.21.0", 0x2B08D6AD, 0xA0875E7F), + new LoginKey("7.0.20.0", 0x2BF084BD, 0xA0FD127F), + //new LoginKey("7.0.19.1", 0x2BB976CD, 0xA0DBDE7F), + //new LoginKey("7.0.19.0", 0x2BB976CD, 0xA0DBDE7F), + //new LoginKey("7.0.18.0", 0x2C612CDD, 0xA328227F), + //new LoginKey("7.0.17.0", 0x2C29E6ED, 0xA30EFE7F), + //new LoginKey("7.0.16.3", 0x2C11A4FD, 0xA313527F), + //new LoginKey("7.0.16.1", 0x2C11A4FD, 0xA313527F), + //new LoginKey("7.0.16.0", 0x2C11A4FD, 0xA313527F), + //new LoginKey("7.0.15.1", 0x2CDA670D, 0xA3723E7F), + //new LoginKey("7.0.15.0", 0x2CDA670D, 0xA3723E7F), + //new LoginKey("7.0.14.4", 0x2C822D1D, 0xA35DA27F), + //new LoginKey("7.0.14.3", 0x2C822D1D, 0xA35DA27F), + //new LoginKey("7.0.14.2", 0x2C822D1D, 0xA35DA27F), + //new LoginKey("7.0.14.0", 0x2C822D1D, 0xA35DA27F), + }; + } +} diff --git a/Scripts/Customs/Encryption/Encryption12OCT2009.cs b/Scripts/Customs/Encryption/Encryption12OCT2009.cs new file mode 100644 index 0000000..0519be1 --- /dev/null +++ b/Scripts/Customs/Encryption/Encryption12OCT2009.cs @@ -0,0 +1,372 @@ +//11JUN2008 RunUO SVN fix +//11JUN2008 Client 6.0.5 Encryption fix +//05MAR2009 Smjert's fix for double log in. +using System; +using System.Net; +using System.Net.Sockets; +using System.Collections; +using Server.Accounting; +using Server; +using Server.Network; +using Server.Misc; + +namespace Server.Engines.Encryption +{ + // This class handles OSI client encryption for clients newer than 2.0.3. (not including 2.0.3) + public class Encryption : IPacketEncoder + { + // Encryption state information + private uint m_Seed; + private bool m_Seeded; + private ByteQueue m_Buffer; + private IClientEncryption m_Encryption; + private bool m_AlreadyRelayed; + + public Encryption() + { + m_AlreadyRelayed = false; + m_Encryption = null; + m_Buffer = new ByteQueue(); + m_Seeded = false; + m_Seed = 0; + } + + static public void Initialize() + { + // Only initialize our subsystem if we're enabled + if (Configuration.Enabled) + { + // Initialize static members and connect to the creation callback of a NetState. + NetState.CreatedCallback = new NetStateCreatedCallback(NetStateCreated); + + // Overwrite the packet handler for the relay packet since we need to change the + // encryption mode then. + PacketHandlers.Register(0xA0, 3, false, new OnPacketReceive(HookedPlayServer)); + } + } + + public static void NetStateCreated(NetState state) + { + state.PacketEncoder = new Encryption(); + } + + public static void HookedPlayServer(NetState state, PacketReader pvSrc) + { + // Call the original handler + PacketHandlers.PlayServer(state, pvSrc); + + // Now indicate, that the state has been relayed already. If it's used again, + // it means we're entering a special encryption state + Encryption context = (Encryption)(state.PacketEncoder); + context.m_AlreadyRelayed = true; + } + + // Try to encrypt outgoing data. + public void EncodeOutgoingPacket(NetState to, ref byte[] buffer, ref int length) + { + if (m_Encryption != null) + { + m_Encryption.serverEncrypt(ref buffer, length); + return; + } + } + + public void RejectNoEncryption(NetState ns) + { + // Log it on the console + Console.WriteLine("Client: {0}: Unencrypted client detected, disconnected", ns); + + // Send the client the typical "Bad communication" packet and also a sysmessage stating the error + ns.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", "Unencrypted connections are not allowed on this server.")); + ns.Send(new AccountLoginRej(ALRReason.BadComm)); + + // Disconnect the client + ns.Dispose(true); + } + + // Try to decrypt incoming data. + public void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length) + { + #region m_Encryption != null + if (m_Encryption != null) + { + /* // If we're decrypting using LoginCrypt and we've already been relayed, + // only decrypt a single packet using logincrypt and then disable it + if (m_AlreadyRelayed && m_Encryption is LoginEncryption) + { + uint newSeed = ((((LoginEncryption)(m_Encryption)).Key1 + 1) ^ ((LoginEncryption)(m_Encryption)).Key2); + + // Swap the seed + newSeed = ((newSeed >> 24) & 0xFF) | ((newSeed >> 8) & 0xFF00) | ((newSeed << 8) & 0xFF0000) | ((newSeed << 24) & 0xFF000000); + + // XOR it with the old seed + newSeed ^= m_Seed; + + IClientEncryption newEncryption = new GameEncryption(newSeed); + + // Game Encryption comes first + newEncryption.clientDecrypt(ref buffer, length); + + // The login encryption is still used for this one packet + m_Encryption.clientDecrypt(ref buffer, length); + + // Swap the encryption schemes + m_Encryption = newEncryption; + m_Seed = newSeed; + + return; + }*/ + + m_Encryption.clientDecrypt(ref buffer, length); + return; + } + #endregion + + #region Port Scan + //11JUN2008 RunUO SVN fix ** START *** + // If the client did not connect on the game server port, + // it's not our business to handle encryption for it + //if (((IPEndPoint)from.Socket.LocalEndPoint).Port != Listener.Port) + //{ + // m_Encryption = new NoEncryption(); + // return; + //} + bool handle = false; + + for (int i = 0; i < Listener.EndPoints.Length; i++) + { + IPEndPoint ipep = (IPEndPoint)Listener.EndPoints[i]; + + if (((IPEndPoint)from.Socket.LocalEndPoint).Port == ipep.Port) + handle = true; + } + + if (!handle) + { + m_Encryption = new NoEncryption(); + return; + } + //11JUN2008 RunUO SVN fix ** END *** + #endregion + + #region !m_Seeded + // For simplicities sake, enqueue what we just received as long as we're not initialized + m_Buffer.Enqueue(buffer, 0, length); + // Clear the array + length = 0; + + // If we didn't receive the seed yet, queue data until we can read the seed + //if (!m_Seeded) + //{ + // // Now check if we have at least 4 bytes to get the seed + // if (m_Buffer.Length >= 4) + // { + // byte[] m_Peek = new byte[m_Buffer.Length]; + // m_Buffer.Dequeue( m_Peek, 0, m_Buffer.Length ); // Dequeue everything + // m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); + // m_Seeded = true; + + // Buffer.BlockCopy(m_Peek, 0, buffer, 0, 4); + // length = 4; + // } + // else + // { + // return; + // } + //} + //http://uodev.de/viewtopic.php?t=5097&postdays=0&postorder=asc&start=15&sid=dfb8e6c73b9e3eb95c1634ca3586e8a7 + //if (!m_Seeded) + //{ + // int seed_length = m_Buffer.GetSeedLength(); + + // if (m_Buffer.Length >= seed_length) + // { + // byte[] m_Peek = new byte[m_Buffer.Length]; + // m_Buffer.Dequeue(m_Peek, 0, seed_length); + + // if (seed_length == 4) + // m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); + // else if (seed_length == 21) + // m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); + + // m_Seeded = true; + + // Buffer.BlockCopy(m_Peek, 0, buffer, 0, seed_length); + // length = seed_length; + // } + // else + // { + // return; + // } + //} + + //11JUN2008 My Version + + if (!m_Seeded) + { + if (m_Buffer.Length <= 3) //Short Length, try again. + { + Console.WriteLine("Encryption: Failed - Short Lenght"); + return; + } + //else if ((m_Buffer.Length == 83) && (m_Buffer.GetPacketID() == 239)) //New Client + //{ + // byte[] m_Peek = new byte[21]; + // m_Buffer.Dequeue(m_Peek, 0, 21); + + // m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); + // m_Seeded = true; + + // Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); + // length = 21; + + // Console.WriteLine("Encryption: Passed - New Client"); + //} + + //05MAR2009 Smjert's fix for double log in. *** START *** + else if ((m_Buffer.Length == 83 || m_Buffer.Length == 21) && (m_Buffer.GetPacketID() == 239)) //New Client + { + length = m_Buffer.Length; + byte[] m_Peek = new byte[21]; + m_Buffer.Dequeue(m_Peek, 0, 21); + + m_Seed = (uint)((m_Peek[1] << 24) | (m_Peek[2] << 16) | (m_Peek[3] << 8) | m_Peek[4]); + m_Seeded = true; + + Buffer.BlockCopy(m_Peek, 0, buffer, 0, 21); + + + Console.WriteLine("Encryption: Passed - New Client"); + + // We need to wait the next packet + if (length == 21) + return; + + length = 21; + } + + else if (m_Buffer.Length >= 4) //Old Client + //05MAR2009 Smjert's fix for double log in. *** END *** + { + byte[] m_Peek = new byte[4]; + m_Buffer.Dequeue(m_Peek, 0, 4); + + m_Seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]); + m_Seeded = true; + + Buffer.BlockCopy(m_Peek, 0, buffer, 0, 4); + length = 4; + + Console.WriteLine("Encryption: Passed - Old Client"); + } + else //It should never reach here. + { + Console.WriteLine("Encryption: Failed - It should never reach here"); + return; + } + } + #endregion + + // If the context isn't initialized yet, that means we haven't decided on an encryption method yet + #region m_Encryption == null + if (m_Encryption == null) + { + int packetLength = m_Buffer.Length; + int packetOffset = length; + m_Buffer.Dequeue(buffer, length, packetLength); // Dequeue everything + length += packetLength; + + // This is special handling for the "special" UOG packet + if (packetLength >= 3) + { + if (buffer[packetOffset] == 0xf1 && buffer[packetOffset + 1] == ((packetLength >> 8) & 0xFF) && buffer[packetOffset + 2] == (packetLength & 0xFF)) + { + m_Encryption = new NoEncryption(); + return; + } + } + + // Check if the current buffer contains a valid login packet (62 byte + 4 byte header) + // Please note that the client sends these in two chunks. One 4 byte and one 62 byte. + if (packetLength == 62) + { + Console.WriteLine("Checking packetLength 62 == " + packetLength); + // Check certain indices in the array to see if the given data is unencrypted + if (buffer[packetOffset] == 0x80 && buffer[packetOffset + 30] == 0x00 && buffer[packetOffset + 60] == 0x00) + { + if (Configuration.AllowUnencryptedClients) + { + m_Encryption = new NoEncryption(); + } + else + { + RejectNoEncryption(from); + from.Dispose(); + return; + } + } + else + { + LoginEncryption encryption = new LoginEncryption(); + if (encryption.init(m_Seed, buffer, packetOffset, packetLength)) + { + Console.WriteLine("Client: {0}: Encrypted client detected, using keys of client {1}", from, encryption.Name); + m_Encryption = encryption; + Console.WriteLine("Encryption: Check 1"); + byte[] packet = new byte[packetLength]; + Console.WriteLine("Encryption: Check 2"); + Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); + Console.WriteLine("Encryption: Check 3"); + encryption.clientDecrypt(ref packet, packet.Length); + Console.WriteLine("Encryption: Check 4"); + Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); + Console.WriteLine("Encryption: Check 5"); + //return; //Just throwing this in. + } + else + { + Console.WriteLine("Detected an unknown client."); + } + } + } + else if (packetLength == 65) + { + Console.WriteLine("Checking packetLength 65 == " + packetLength); + // If its unencrypted, use the NoEncryption class + if (buffer[packetOffset] == '\x91' && buffer[packetOffset + 1] == ((m_Seed >> 24) & 0xFF) && buffer[packetOffset + 2] == ((m_Seed >> 16) & 0xFF) && buffer[packetOffset + 3] == ((m_Seed >> 8) & 0xFF) && buffer[packetOffset + 4] == (m_Seed & 0xFF)) + { + if (Configuration.AllowUnencryptedClients) + { + m_Encryption = new NoEncryption(); + } + else + { + RejectNoEncryption(from); + from.Dispose(); + } + } + else + { + // If it's not an unencrypted packet, simply assume it's encrypted with the seed + m_Encryption = new GameEncryption(m_Seed); + + byte[] packet = new byte[packetLength]; + Buffer.BlockCopy(buffer, packetOffset, packet, 0, packetLength); + m_Encryption.clientDecrypt(ref packet, packet.Length); + Buffer.BlockCopy(packet, 0, buffer, packetOffset, packetLength); + } + } + + // If it's still not initialized, copy the data back to the queue and wait for more + if (m_Encryption == null) + { + Console.WriteLine("Encryption: Check - Waiting"); + m_Buffer.Enqueue(buffer, packetOffset, packetLength); + length -= packetLength; + return; + } + } + #endregion + } + } +} diff --git a/Scripts/Customs/Encryption/GameEncryption.cs b/Scripts/Customs/Encryption/GameEncryption.cs new file mode 100644 index 0000000..e9ab68b --- /dev/null +++ b/Scripts/Customs/Encryption/GameEncryption.cs @@ -0,0 +1,87 @@ + +using System; +using System.Collections; +using System.Security.Cryptography; + +namespace Server.Engines.Encryption +{ + public class GameEncryption : IClientEncryption + { + private TwofishEncryption engine; + + private ushort recvPos; // Position in our CipherTable (Recv) + private byte sendPos; // Offset in our XOR Table (Send) + private byte[] cipherTable; + private byte[] xorData; // This table is used for encrypting the server->client stream + + public GameEncryption(uint seed) + { + cipherTable = new byte[0x100]; + + // Set up the crypt key + byte[] key = new byte[16]; + key[0] = key[4] = key[8] = key[12] = (byte)((seed >> 24) & 0xff); + key[1] = key[5] = key[9] = key[13] = (byte)((seed >> 16) & 0xff); + key[2] = key[6] = key[10] = key[14] = (byte)((seed >> 8) & 0xff); + key[3] = key[7] = key[11] = key[15] = (byte)(seed & 0xff); + + byte[] iv = new byte[0]; + engine = new TwofishEncryption(128, ref key, ref iv, CipherMode.ECB, TwofishBase.EncryptionDirection.Decrypting); + + // Initialize table + for ( int i = 0; i < 256; ++i ) + cipherTable[i] = (byte)i; + + sendPos = 0; + + // We need to fill the table initially to calculate the MD5 hash of it + refreshCipherTable(); + + // Create a MD5 hash of the twofish crypt data and use it as a 16-byte xor table + // for encrypting the server->client stream. + MD5 md5 = new MD5CryptoServiceProvider(); + xorData = md5.ComputeHash(cipherTable); + } + + private void refreshCipherTable() + { + uint[] block = new uint[4]; + + for (int i = 0; i < 256; i += 16) + { + Buffer.BlockCopy(cipherTable, i, block, 0, 16); + engine.blockEncrypt(ref block); + Buffer.BlockCopy(block, 0, cipherTable, i, 16); + } + + recvPos = 0; + } + + public void serverEncrypt(ref byte[] buffer, int length) + { + byte[] packet = new byte[length]; + for ( int i = 0; i < length; ++i ) + { + packet[i] = (byte)(buffer[i] ^ xorData[sendPos++]); + sendPos &= 0x0F; // Maximum Value is 0xF = 15, then 0xF + 1 = 0 again + } + buffer = packet; + } + + public void clientDecrypt(ref byte[] buffer, int length) + { + for (int i = 0; i < length; ++i) + { + // Recalculate table + if ( recvPos >= 0x100 ) + { + byte[] tmpBuffer = new byte[0x100]; + refreshCipherTable(); + } + + // Simple XOR operation + buffer[i] ^= cipherTable[recvPos++]; + } + } + } +} diff --git a/Scripts/Customs/Encryption/IClientEncryption.cs b/Scripts/Customs/Encryption/IClientEncryption.cs new file mode 100644 index 0000000..fadcb59 --- /dev/null +++ b/Scripts/Customs/Encryption/IClientEncryption.cs @@ -0,0 +1,12 @@ + +namespace Server.Engines.Encryption +{ + public interface IClientEncryption + { + // Encrypt outgoing data + void serverEncrypt(ref byte[] buffer, int length); + + // Decrypt incoming data + void clientDecrypt(ref byte[] buffer, int length); + } +} diff --git a/Scripts/Customs/Encryption/LoginEncryption.cs b/Scripts/Customs/Encryption/LoginEncryption.cs new file mode 100644 index 0000000..50f165f --- /dev/null +++ b/Scripts/Customs/Encryption/LoginEncryption.cs @@ -0,0 +1,115 @@ + +using System; +using System.Collections; + +namespace Server.Engines.Encryption +{ + public class LoginEncryption : IClientEncryption + { + private String name; + private uint key1; + private uint key2; + private uint table1; + private uint table2; + + public String Name + { + get + { + return name; + } + } + + public uint Key1 + { + get + { + return key1; + } + } + + public uint Key2 + { + get + { + return key2; + } + } + + // Try to initialize the login encryption with the given buffer + public bool init(uint seed, byte[] buffer, int offset, int length) + { + if (length < 62) // includes the 4 byte header + return false; + + // Try to find a valid key + byte[] packet = new byte[62]; + + // Initialize our tables (cache them, they will be modified) + uint orgTable1 = ( ( ( ~seed ) ^ 0x00001357 ) << 16 ) | ( ( seed ^ 0xffffaaaa ) & 0x0000ffff ); + uint orgTable2 = ( ( seed ^ 0x43210000 ) >> 16 ) | ( ( ( ~seed ) ^ 0xabcdffff ) & 0xffff0000 ); + + for (int i = 0; i < Configuration.LoginKeys.Length; ++i) + { + // Check if this key works on this packet + Buffer.BlockCopy(buffer, offset, packet, 0, 62); + table1 = orgTable1; + table2 = orgTable2; + key1 = Configuration.LoginKeys[i].Key1; + key2 = Configuration.LoginKeys[i].Key2; + + clientDecrypt( ref packet, packet.Length ); + + // Check if it decrypted correctly + if ( packet[0] == 0x80 && packet[30] == 0x00 && packet[60] == 0x00 ) + { + // Reestablish our current state + table1 = orgTable1; + table2 = orgTable2; + key1 = Configuration.LoginKeys[i].Key1; + key2 = Configuration.LoginKeys[i].Key2; + name = Configuration.LoginKeys[i].Name; + return true; + } + } + + return false; + } + + public void init(uint seed, uint key1, uint key2) + { + table1 = ( ( ( ~seed ) ^ 0x00001357 ) << 16 ) | ( ( seed ^ 0xffffaaaa ) & 0x0000ffff ); + table2 = ( ( seed ^ 0x43210000 ) >> 16 ) | ( ( ( ~seed ) ^ 0xabcdffff ) & 0xffff0000 ); + this.key1 = key1; + this.key2 = key2; + } + + public void serverEncrypt(ref byte[] buffer, int length) + { + // There is no server->client encryption in the login stage + } + + public void clientDecrypt(ref byte[] buffer, int length) + { + uint eax, ecx, edx, esi; + for ( int i = 0; i < length; ++i ) + { + buffer[i] = (byte)(buffer[i] ^ (byte) ( table1 & 0xFF )); + edx = table2; + esi = table1 << 31; + eax = table2 >> 1; + eax |= esi; + eax ^= key1 - 1; + edx <<= 31; + eax >>= 1; + ecx = table1 >> 1; + eax |= esi; + ecx |= edx; + eax ^= key1; + ecx ^= key2; + table1 = ecx; + table2 = eax; + } + } + } +} diff --git a/Scripts/Customs/Encryption/LoginKey.cs b/Scripts/Customs/Encryption/LoginKey.cs new file mode 100644 index 0000000..05e4ca1 --- /dev/null +++ b/Scripts/Customs/Encryption/LoginKey.cs @@ -0,0 +1,42 @@ +using System; + +namespace Server.Engines.Encryption +{ + public class LoginKey + { + private uint m_Key1; + private uint m_Key2; + private String m_Name; + + public LoginKey(String name, uint key1, uint key2) + { + m_Key1 = key1; + m_Key2 = key2; + m_Name = name; + } + + public String Name + { + get + { + return m_Name; + } + } + + public uint Key1 + { + get + { + return m_Key1; + } + } + + public uint Key2 + { + get + { + return m_Key2; + } + } + } +} diff --git a/Scripts/Customs/Encryption/NoEncryption.cs b/Scripts/Customs/Encryption/NoEncryption.cs new file mode 100644 index 0000000..87d9080 --- /dev/null +++ b/Scripts/Customs/Encryption/NoEncryption.cs @@ -0,0 +1,14 @@ + +namespace Server.Engines.Encryption +{ + public class NoEncryption : IClientEncryption + { + public void serverEncrypt(ref byte[] buffer, int length) + { + } + + public void clientDecrypt(ref byte[] buffer, int length) + { + } + } +} diff --git a/Scripts/Customs/Encryption/TwofishBase.cs b/Scripts/Customs/Encryption/TwofishBase.cs new file mode 100644 index 0000000..b7b4dbb --- /dev/null +++ b/Scripts/Customs/Encryption/TwofishBase.cs @@ -0,0 +1,630 @@ +//#define FEISTEL + +using System; +using System.Diagnostics; +using System.Security.Cryptography; + +/* + * This implementation of Twofish has been published here: + * http://www.codetools.com/csharp/twofish_csharp.asp + */ + +namespace Server.Engines.Encryption +{ + + /// + /// Summary description for TwofishBase. + /// + internal class TwofishBase + { + public enum EncryptionDirection + { + Encrypting, + Decrypting + } + + public TwofishBase() + { + } + + protected int inputBlockSize = BLOCK_SIZE/8; + protected int outputBlockSize = BLOCK_SIZE/8; + + /* + +***************************************************************************** + * + * Function Name: f32 + * + * Function: Run four bytes through keyed S-boxes and apply MDS matrix + * + * Arguments: x = input to f function + * k32 = pointer to key dwords + * keyLen = total key length (k32 --> keyLey/2 bits) + * + * Return: The output of the keyed permutation applied to x. + * + * Notes: + * This function is a keyed 32-bit permutation. It is the major building + * block for the Twofish round function, including the four keyed 8x8 + * permutations and the 4x4 MDS matrix multiply. This function is used + * both for generating round subkeys and within the round function on the + * block being encrypted. + * + * This version is fairly slow and pedagogical, although a smartcard would + * probably perform the operation exactly this way in firmware. For + * ultimate performance, the entire operation can be completed with four + * lookups into four 256x32-bit tables, with three dword xors. + * + * The MDS matrix is defined in TABLE.H. To multiply by Mij, just use the + * macro Mij(x). + * + -****************************************************************************/ + private static uint f32(uint x,ref uint[] k32,int keyLen) + { + byte[] b = {b0(x),b1(x),b2(x),b3(x)}; + + /* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */ + /* Note that each byte goes through a different combination of S-boxes.*/ + + //*((DWORD *)b) = Bswap(x); /* make b[0] = LSB, b[3] = MSB */ + switch (((keyLen + 63)/64) & 3) + { + case 0: /* 256 bits of key */ + b[0] = (byte)(P8x8[P_04,b[0]] ^ b0(k32[3])); + b[1] = (byte)(P8x8[P_14,b[1]] ^ b1(k32[3])); + b[2] = (byte)(P8x8[P_24,b[2]] ^ b2(k32[3])); + b[3] = (byte)(P8x8[P_34,b[3]] ^ b3(k32[3])); + /* fall thru, having pre-processed b[0]..b[3] with k32[3] */ + goto case 3; + case 3: /* 192 bits of key */ + b[0] = (byte)(P8x8[P_03,b[0]] ^ b0(k32[2])); + b[1] = (byte)(P8x8[P_13,b[1]] ^ b1(k32[2])); + b[2] = (byte)(P8x8[P_23,b[2]] ^ b2(k32[2])); + b[3] = (byte)(P8x8[P_33,b[3]] ^ b3(k32[2])); + /* fall thru, having pre-processed b[0]..b[3] with k32[2] */ + goto case 2; + case 2: /* 128 bits of key */ + b[0] = P8x8[P_00, P8x8[P_01, P8x8[P_02, b[0]] ^ b0(k32[1])] ^ b0(k32[0])]; + b[1] = P8x8[P_10, P8x8[P_11, P8x8[P_12, b[1]] ^ b1(k32[1])] ^ b1(k32[0])]; + b[2] = P8x8[P_20, P8x8[P_21, P8x8[P_22, b[2]] ^ b2(k32[1])] ^ b2(k32[0])]; + b[3] = P8x8[P_30, P8x8[P_31, P8x8[P_32, b[3]] ^ b3(k32[1])] ^ b3(k32[0])]; + break; + } + + + /* Now perform the MDS matrix multiply inline. */ + return (uint)((M00(b[0]) ^ M01(b[1]) ^ M02(b[2]) ^ M03(b[3]))) ^ + (uint)((M10(b[0]) ^ M11(b[1]) ^ M12(b[2]) ^ M13(b[3])) << 8) ^ + (uint)((M20(b[0]) ^ M21(b[1]) ^ M22(b[2]) ^ M23(b[3])) << 16) ^ + (uint)((M30(b[0]) ^ M31(b[1]) ^ M32(b[2]) ^ M33(b[3])) << 24) ; + } + + /* + +***************************************************************************** + * + * Function Name: reKey + * + * Function: Initialize the Twofish key schedule from key32 + * + * Arguments: key = ptr to keyInstance to be initialized + * + * Return: TRUE on success + * + * Notes: + * Here we precompute all the round subkeys, although that is not actually + * required. For example, on a smartcard, the round subkeys can + * be generated on-the-fly using f32() + * + -****************************************************************************/ + protected bool reKey(int keyLen, ref uint[] key32) + { + int i,k64Cnt; + keyLength = keyLen; + rounds = numRounds[(keyLen-1)/64]; + int subkeyCnt = ROUND_SUBKEYS + 2*rounds; + uint A,B; + uint[] k32e = new uint[MAX_KEY_BITS/64]; + uint[] k32o = new uint[MAX_KEY_BITS/64]; /* even/odd key dwords */ + + k64Cnt=(keyLen+63)/64; /* round up to next multiple of 64 bits */ + for (i=0;i=0;r--) /* main Twofish decryption loop */ + { + t0 = f32( x[0] ,ref sboxKeys,keyLength); + t1 = f32(ROL(x[1],8),ref sboxKeys,keyLength); + + x[2] = ROL(x[2],1); + x[2]^= t0 + t1 + subKeys[ROUND_SUBKEYS+2*r ]; /* PHT, round keys */ + x[3]^= t0 + 2*t1 + subKeys[ROUND_SUBKEYS+2*r+1]; + x[3] = ROR(x[3],1); + + if (r>0) /* unswap, except for last round */ + { + t0 = x[0]; x[0]= x[2]; x[2] = t0; + t1 = x[1]; x[1]= x[3]; x[3] = t1; + } + } + + for (int i=0;i0) ? k0 : k1; /* merge in 32 more key bits */ + for (j=0;j<4;j++) /* shift one byte at a time */ + RS_rem(ref r); + } + return r; + } + + protected uint[] sboxKeys = new uint[MAX_KEY_BITS/64]; /* key bits used for S-boxes */ + protected uint[] subKeys = new uint[TOTAL_SUBKEYS]; /* round subkeys, input/output whitening bits */ + protected uint[] Key = {0,0,0,0,0,0,0,0}; //new int[MAX_KEY_BITS/32]; + protected uint[] IV = {0,0,0,0}; // this should be one block size + private int keyLength; + private int rounds; + protected CipherMode cipherMode = CipherMode.ECB; + + + #region These are all the definitions that were found in AES.H + static private readonly int BLOCK_SIZE = 128; /* number of bits per block */ + static private readonly int MAX_ROUNDS = 16; /* max # rounds (for allocating subkey array) */ + static private readonly int ROUNDS_128 = 16; /* default number of rounds for 128-bit keys*/ + static private readonly int ROUNDS_192 = 16; /* default number of rounds for 192-bit keys*/ + static private readonly int ROUNDS_256 = 16; /* default number of rounds for 256-bit keys*/ + static private readonly int MAX_KEY_BITS = 256; /* max number of bits of key */ + static private readonly int MIN_KEY_BITS = 128; /* min number of bits of key (zero pad) */ + +//#define VALID_SIG 0x48534946 /* initialization signature ('FISH') */ +//#define MCT_OUTER 400 /* MCT outer loop */ +//#define MCT_INNER 10000 /* MCT inner loop */ +//#define REENTRANT 1 /* nonzero forces reentrant code (slightly slower) */ + + static private readonly int INPUT_WHITEN = 0; /* subkey array indices */ + static private readonly int OUTPUT_WHITEN = (INPUT_WHITEN + BLOCK_SIZE/32); + static private readonly int ROUND_SUBKEYS = (OUTPUT_WHITEN + BLOCK_SIZE/32); /* use 2 * (# rounds) */ + static private readonly int TOTAL_SUBKEYS = (ROUND_SUBKEYS + 2*MAX_ROUNDS); + + + #endregion + + #region These are all the definitions that were found in TABLE.H that we need + /* for computing subkeys */ + static private readonly uint SK_STEP = 0x02020202u; + static private readonly uint SK_BUMP = 0x01010101u; + static private readonly int SK_ROTL = 9; + + /* Reed-Solomon code parameters: (12,8) reversible code + g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1 + where a = primitive root of field generator 0x14D */ + static private readonly uint RS_GF_FDBK = 0x14D; /* field generator */ + static private void RS_rem(ref uint x) + { + byte b = (byte) (x >> 24); + // TODO: maybe change g2 and g3 to bytes + uint g2 = (uint)(((b << 1) ^ (((b & 0x80)==0x80) ? RS_GF_FDBK : 0 )) & 0xFF); + uint g3 = (uint)(((b >> 1) & 0x7F) ^ (((b & 1)==1) ? RS_GF_FDBK >> 1 : 0 ) ^ g2) ; + x = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; + } + + /* Macros for the MDS matrix + * The MDS matrix is (using primitive polynomial 169): + * 01 EF 5B 5B + * 5B EF EF 01 + * EF 5B 01 EF + * EF 01 EF 5B + *---------------------------------------------------------------- + * More statistical properties of this matrix (from MDS.EXE output): + * + * Min Hamming weight (one byte difference) = 8. Max=26. Total = 1020. + * Prob[8]: 7 23 42 20 52 95 88 94 121 128 91 + * 102 76 41 24 8 4 1 3 0 0 0 + * Runs[8]: 2 4 5 6 7 8 9 11 + * MSBs[8]: 1 4 15 8 18 38 40 43 + * HW= 8: 05040705 0A080E0A 14101C14 28203828 50407050 01499101 A080E0A0 + * HW= 9: 04050707 080A0E0E 10141C1C 20283838 40507070 80A0E0E0 C6432020 07070504 + * 0E0E0A08 1C1C1410 38382820 70705040 E0E0A080 202043C6 05070407 0A0E080E + * 141C101C 28382038 50704070 A0E080E0 4320C620 02924B02 089A4508 + * Min Hamming weight (two byte difference) = 3. Max=28. Total = 390150. + * Prob[3]: 7 18 55 149 270 914 2185 5761 11363 20719 32079 + * 43492 51612 53851 52098 42015 31117 20854 11538 6223 2492 1033 + * MDS OK, ROR: 6+ 7+ 8+ 9+ 10+ 11+ 12+ 13+ 14+ 15+ 16+ + * 17+ 18+ 19+ 20+ 21+ 22+ 23+ 24+ 25+ 26+ + */ + static private readonly int MDS_GF_FDBK = 0x169; /* primitive polynomial for GF(256)*/ + static private int LFSR1(int x) + { + return ( ((x) >> 1) ^ ((((x) & 0x01)==0x01) ? MDS_GF_FDBK/2 : 0)); + } + + static private int LFSR2(int x) + { + return ( ((x) >> 2) ^ ((((x) & 0x02)==0x02) ? MDS_GF_FDBK/2 : 0) ^ + ((((x) & 0x01)==0x01) ? MDS_GF_FDBK/4 : 0)); + } + + // TODO: not the most efficient use of code but it allows us to update the code a lot quicker we can possibly optimize this code once we have got it all working + static private int Mx_1(int x) + { + return x; /* force result to int so << will work */ + } + + static private int Mx_X(int x) + { + return x ^ LFSR2(x); /* 5B */ + } + + static private int Mx_Y(int x) + { + return x ^ LFSR1(x) ^ LFSR2(x); /* EF */ + } + + static private int M00(int x) + { + return Mul_1(x); + } + static private int M01(int x) + { + return Mul_Y(x); + } + static private int M02(int x) + { + return Mul_X(x); + } + static private int M03(int x) + { + return Mul_X(x); + } + + static private int M10(int x) + { + return Mul_X(x); + } + static private int M11(int x) + { + return Mul_Y(x); + } + static private int M12(int x) + { + return Mul_Y(x); + } + static private int M13(int x) + { + return Mul_1(x); + } + + static private int M20(int x) + { + return Mul_Y(x); + } + static private int M21(int x) + { + return Mul_X(x); + } + static private int M22(int x) + { + return Mul_1(x); + } + static private int M23(int x) + { + return Mul_Y(x); + } + + static private int M30(int x) + { + return Mul_Y(x); + } + static private int M31(int x) + { + return Mul_1(x); + } + static private int M32(int x) + { + return Mul_Y(x); + } + static private int M33(int x) + { + return Mul_X(x); + } + + static private int Mul_1(int x) + { + return Mx_1(x); + } + static private int Mul_X(int x) + { + return Mx_X(x); + } + static private int Mul_Y(int x) + { + return Mx_Y(x); + } + /* Define the fixed p0/p1 permutations used in keyed S-box lookup. + By changing the following constant definitions for P_ij, the S-boxes will + automatically get changed in all the Twofish source code. Note that P_i0 is + the "outermost" 8x8 permutation applied. See the f32() function to see + how these constants are to be used. + */ + static private readonly int P_00 = 1; /* "outermost" permutation */ + static private readonly int P_01 = 0; + static private readonly int P_02 = 0; + static private readonly int P_03 = (P_01^1); /* "extend" to larger key sizes */ + static private readonly int P_04 = 1; + + static private readonly int P_10 = 0; + static private readonly int P_11 = 0; + static private readonly int P_12 = 1; + static private readonly int P_13 = (P_11^1); + static private readonly int P_14 = 0; + + static private readonly int P_20 = 1; + static private readonly int P_21 = 1; + static private readonly int P_22 = 0; + static private readonly int P_23 = (P_21^1); + static private readonly int P_24 = 0; + + static private readonly int P_30 = 0; + static private readonly int P_31 = 1; + static private readonly int P_32 = 1; + static private readonly int P_33 = (P_31^1); + static private readonly int P_34 = 1; + + /* fixed 8x8 permutation S-boxes */ + + /*********************************************************************** + * 07:07:14 05/30/98 [4x4] TestCnt=256. keySize=128. CRC=4BD14D9E. + * maxKeyed: dpMax = 18. lpMax =100. fixPt = 8. skXor = 0. skDup = 6. + * log2(dpMax[ 6..18])= --- 15.42 1.33 0.89 4.05 7.98 12.05 + * log2(lpMax[ 7..12])= 9.32 1.01 1.16 4.23 8.02 12.45 + * log2(fixPt[ 0.. 8])= 1.44 1.44 2.44 4.06 6.01 8.21 11.07 14.09 17.00 + * log2(skXor[ 0.. 0]) + * log2(skDup[ 0.. 6])= --- 2.37 0.44 3.94 8.36 13.04 17.99 + ***********************************************************************/ + static private byte[,] P8x8 = + { + /* p0: */ + /* dpMax = 10. lpMax = 64. cycleCnt= 1 1 1 0. */ + /* 817D6F320B59ECA4.ECB81235F4A6709D.BA5E6D90C8F32471.D7F4126E9B3085CA. */ + /* Karnaugh maps: + * 0111 0001 0011 1010. 0001 1001 1100 1111. 1001 1110 0011 1110. 1101 0101 1111 1001. + * 0101 1111 1100 0100. 1011 0101 0010 0000. 0101 1000 1100 0101. 1000 0111 0011 0010. + * 0000 1001 1110 1101. 1011 1000 1010 0011. 0011 1001 0101 0000. 0100 0010 0101 1011. + * 0111 0100 0001 0110. 1000 1011 1110 1001. 0011 0011 1001 1101. 1101 0101 0000 1100. + */ + { + 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, + 0x9A, 0x92, 0x80, 0x78, 0xE4, 0xDD, 0xD1, 0x38, + 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C, + 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, + 0xF2, 0xD0, 0x8B, 0x30, 0x84, 0x54, 0xDF, 0x23, + 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82, + 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, + 0xA6, 0xEB, 0xA5, 0xBE, 0x16, 0x0C, 0xE3, 0x61, + 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B, + 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, + 0xE1, 0xE6, 0xBD, 0x45, 0xE2, 0xF4, 0xB6, 0x66, + 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7, + 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, + 0xEA, 0x77, 0x39, 0xAF, 0x33, 0xC9, 0x62, 0x71, + 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8, + 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, + 0xA1, 0x1D, 0xAA, 0xED, 0x06, 0x70, 0xB2, 0xD2, + 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90, + 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, + 0x9E, 0x9C, 0x52, 0x1B, 0x5F, 0x93, 0x0A, 0xEF, + 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B, + 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, + 0x2A, 0xCE, 0xCB, 0x2F, 0xFC, 0x97, 0x05, 0x7A, + 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A, + 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, + 0xB8, 0xDA, 0xB0, 0x17, 0x55, 0x1F, 0x8A, 0x7D, + 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, + 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, + 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, + 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, + 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, + 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0 + }, + /* p1: */ + /* dpMax = 10. lpMax = 64. cycleCnt= 2 0 0 1. */ + /* 28BDF76E31940AC5.1E2B4C376DA5F908.4C75169A0ED82B3F.B951C3DE647F208A. */ + /* Karnaugh maps: + * 0011 1001 0010 0111. 1010 0111 0100 0110. 0011 0001 1111 0100. 1111 1000 0001 1100. + * 1100 1111 1111 1010. 0011 0011 1110 0100. 1001 0110 0100 0011. 0101 0110 1011 1011. + * 0010 0100 0011 0101. 1100 1000 1000 1110. 0111 1111 0010 0110. 0000 1010 0000 0011. + * 1101 1000 0010 0001. 0110 1001 1110 0101. 0001 0100 0101 0111. 0011 1011 1111 0010. + */ + { + 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, + 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, + 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, + 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, + 0x5E, 0xBA, 0xAE, 0x5B, 0x8A, 0x00, 0xBC, 0x9D, + 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5, + 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, + 0xB2, 0x73, 0x4C, 0x54, 0x92, 0x74, 0x36, 0x51, + 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96, + 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, + 0x13, 0x95, 0x9C, 0xC7, 0x24, 0x46, 0x3B, 0x70, + 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8, + 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, + 0x03, 0x6F, 0x08, 0xBF, 0x40, 0xE7, 0x2B, 0xE2, + 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9, + 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, + 0x66, 0x94, 0xA1, 0x1D, 0x3D, 0xF0, 0xDE, 0xB3, + 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E, + 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, + 0x81, 0x88, 0xEE, 0x21, 0xC4, 0x1A, 0xEB, 0xD9, + 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01, + 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, + 0x4F, 0xF2, 0x65, 0x8E, 0x78, 0x5C, 0x58, 0x19, + 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64, + 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, + 0xCE, 0xE9, 0x68, 0x44, 0xE0, 0x4D, 0x43, 0x69, + 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E, + 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, + 0x22, 0xC9, 0xC0, 0x9B, 0x89, 0xD4, 0xED, 0xAB, + 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9, + 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, + 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 + } + }; + #endregion + + #region These are all the definitions that were found in PLATFORM.H that we need + // left rotation + private static uint ROL(uint x, int n) + { + return ( ((x) << ((n) & 0x1F)) | (x) >> (32-((n) & 0x1F)) ); + } + + // right rotation + private static uint ROR(uint x,int n) + { + return (((x) >> ((n) & 0x1F)) | ((x) << (32-((n) & 0x1F)))); + } + + // first byte + protected static byte b0(uint x) + { + return (byte)(x );//& 0xFF); + } + // second byte + protected static byte b1(uint x) + { + return (byte)((x >> 8));// & (0xFF)); + } + // third byte + protected static byte b2(uint x) + { + return (byte)((x >> 16));// & (0xFF)); + } + // fourth byte + protected static byte b3(uint x) + { + return (byte)((x >> 24));// & (0xFF)); + } + + #endregion + } +} diff --git a/Scripts/Customs/Encryption/TwofishEncryption.cs b/Scripts/Customs/Encryption/TwofishEncryption.cs new file mode 100644 index 0000000..6b18283 --- /dev/null +++ b/Scripts/Customs/Encryption/TwofishEncryption.cs @@ -0,0 +1,182 @@ +using System; +using System.Diagnostics; +using System.Security.Cryptography; + +/* + * This implementation of Twofish has been published here: + * http://www.codetools.com/csharp/twofish_csharp.asp + */ + +namespace Server.Engines.Encryption +{ + /// + /// Summary description for TwofishEncryption. + /// + internal class TwofishEncryption : TwofishBase, ICryptoTransform + { + public TwofishEncryption(int keyLen, ref byte[] key, ref byte[] iv, CipherMode cMode, EncryptionDirection direction) + { + // convert our key into an array of ints + for (int i=0;i + /// Transform a block depending on whether we are encrypting or decrypting + /// + /// + /// + /// + /// + /// + /// + public int TransformBlock( + byte[] inputBuffer, + int inputOffset, + int inputCount, + byte[] outputBuffer, + int outputOffset + ) + { + uint[] x=new uint[4]; + + // load it up + for (int i=0;i<4;i++) + { + x[i]= (uint)(inputBuffer[i*4+3+inputOffset]<<24) | (uint)(inputBuffer[i*4+2+inputOffset] << 16) | + (uint)(inputBuffer[i*4+1+inputOffset] << 8) | (uint)(inputBuffer[i*4+0+inputOffset]); + + } + + if (encryptionDirection == EncryptionDirection.Encrypting) + { + blockEncrypt(ref x); + } + else + { + blockDecrypt(ref x); + } + + + // load it up + for (int i=0;i<4;i++) + { + outputBuffer[i*4+0+outputOffset] = b0(x[i]); + outputBuffer[i*4+1+outputOffset] = b1(x[i]); + outputBuffer[i*4+2+outputOffset] = b2(x[i]); + outputBuffer[i*4+3+outputOffset] = b3(x[i]); + } + + + return inputCount; + } + + public byte[] TransformFinalBlock( + byte[] inputBuffer, + int inputOffset, + int inputCount + ) + { + byte[] outputBuffer;// = new byte[0]; + + if (inputCount>0) + { + outputBuffer = new byte[16]; // blocksize + uint[] x=new uint[4]; + + // load it up + for (int i=0;i<4;i++) // should be okay as we have already said to pad with zeros + { + x[i]= (uint)(inputBuffer[i*4+3+inputOffset]<<24) | (uint)(inputBuffer[i*4+2+inputOffset] << 16) | + (uint)(inputBuffer[i*4+1+inputOffset] << 8) | (uint)(inputBuffer[i*4+0+inputOffset]); + + } + + if (encryptionDirection == EncryptionDirection.Encrypting) + { + blockEncrypt(ref x); + } + else + { + blockDecrypt(ref x); + } + + // load it up + for (int i=0;i<4;i++) + { + outputBuffer[i*4+0] = b0(x[i]); + outputBuffer[i*4+1] = b1(x[i]); + outputBuffer[i*4+2] = b2(x[i]); + outputBuffer[i*4+3] = b3(x[i]); + } + } + else + { + outputBuffer = new byte[0]; // the .NET framework doesn't like it if you return null - this calms it down + } + + return outputBuffer; + } + + // not worked out this property yet - placing break points here just don't get caught. + private bool canReuseTransform = true; + public bool CanReuseTransform + { + get + { + return canReuseTransform; + } + } + + // I normally set this to false when block encrypting so that I can work on one block at a time + // but for compression and stream type ciphers this can be set to true so that you get all the data + private bool canTransformMultipleBlocks = false; + public bool CanTransformMultipleBlocks + { + get + { + return canTransformMultipleBlocks; + } + } + + public int InputBlockSize + { + get + { + return inputBlockSize; + } + } + + public int OutputBlockSize + { + get + { + return outputBlockSize; + } + } + + private EncryptionDirection encryptionDirection; + } +} diff --git a/Scripts/Customs/KniveChat/Beta 9.doc b/Scripts/Customs/KniveChat/Beta 9.doc new file mode 100644 index 0000000..d122b56 Binary files /dev/null and b/Scripts/Customs/KniveChat/Beta 9.doc differ diff --git a/Scripts/Customs/KniveChat/Channels/Alliance.cs b/Scripts/Customs/KniveChat/Channels/Alliance.cs new file mode 100644 index 0000000..a92df6e --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Alliance.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class Alliance : Channel + { + public Alliance() : base("Alliance") + { + Commands.Add("ally"); + Commands.Add("a"); + DefaultC = 0x9E; + NewChars = true; + + Register(this); + } + + public override ArrayList GetHistory(Mobile m) + { + return new ArrayList(); + } + + public override void AddHistory(Mobile m, string msg) + { + } + + public override void UpdateHistory(Mobile m) + { + } + + public override bool CanChat(Mobile m, bool say) + { + if (m.Guild == null) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(36)); + return false; + } + + return base.CanChat(m, say); + } + + protected override void Broadcast(Mobile m, string msg) + { + foreach (Data data in Data.Datas.Values) + { + if (data.Mobile.Guild == null) + continue; + + if (data.Mobile.AccessLevel >= m.AccessLevel && ((data.GlobalG && !data.GIgnores.Contains(m)) || data.GListens.Contains(m))) + data.Mobile.SendMessage(data.GlobalGC, String.Format("(Alliance) <{0}> {1}: {2}", NameFor(m), m.RawName, msg )); + else if (IsIn(data.Mobile) && !data.Ignores.Contains(m) && (data.Mobile.Guild == m.Guild || ((Server.Guilds.Guild)data.Mobile.Guild).Allies.Contains((Server.Guilds.Guild)m.Guild))) + data.Mobile.SendMessage(m.AccessLevel == AccessLevel.Player ? ColorFor(data.Mobile) : Data.GetData(m).StaffC, String.Format("<{0}{1}> {2}: {3}", NameFor(m), (Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.RawName, msg)); + } + } + + public override ArrayList BuildList(Mobile m) + { + ArrayList list = base.BuildList(m); + + foreach (Mobile mob in new ArrayList(list)) + if (mob.Guild == null || m.Guild == null || (mob.Guild != m.Guild && !((Server.Guilds.Guild)mob.Guild).Allies.Contains((Server.Guilds.Guild)m.Guild))) + list.Remove(mob); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Channel.cs b/Scripts/Customs/KniveChat/Channels/Channel.cs new file mode 100644 index 0000000..4753247 --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Channel.cs @@ -0,0 +1,533 @@ +// Chat karma titles, with settable points required for the title +// Custom chat titles by staff +// Change filter display to number based and staff can input number to remove them +// A suite of text tools for private messages, including the text color, html formatting +// Current addition to status selection on ListGump +// Chat emotes +// QUick chatting (Players can assign text to morph into other text) +// Find a way to get Alliance history working +// Fun filter word exchanges (*bleep*) +// Filter exceptions (Jew -> Jewelery) +// Chatting duels, ratings +// Let players chose how to display their chat (like: {Chat} or (Chat) or /Chat\ etc) +// Method to send Web Pms, Irc Pms +// Link chat to the EA chat interface +// Debug var that displays various timer information +// Conversations +// Skin 1.0 +// Set up the script regions +// Kick filter penalty +// Expand History gump to include links to other channels +// Status and other similar commands for getting RunUO status from IRC + +using System; +using System.Collections; +using System.IO; +using Server; + +namespace Knives.Chat3 +{ + public enum ChatStyle { Global, Regional } + + public class Channel + { + #region Statics + + private static ArrayList s_Channels = new ArrayList(); + + public static ArrayList Channels { get{ return s_Channels; } } + + public static void Register(Channel c) + { + foreach (string str in c.Commands) + RUOVersion.AddCommand(str, AccessLevel.Player, new ChatCommandHandler(ChannelCommand)); + } + + public static Channel GetByName(string str) + { + foreach (Channel c in s_Channels) + if (c.Name == str) + return c; + + return null; + } + + public static Channel GetByType(Type type) + { + foreach (Channel c in s_Channels) + if (c.GetType() == type) + return c; + + return null; + } + + public static ArrayList GetHistoryFrom(Mobile m, string name) + { + Channel c = GetByName(name); + if (c == null) + return null; + + return c.GetHistory(m); + } + + private static void ChannelCommand(CommandInfo e) + { + foreach (Channel c in s_Channels) + foreach (string str in c.Commands) + if (str == e.Command) + { + c.OnChat(e.Mobile, e.ArgString); + return; + } + } + + public static void AddCommand(string str) + { + RUOVersion.AddCommand(str, AccessLevel.Player, new ChatCommandHandler(ChannelCommand)); + } + + public static void RemoveCommand(string str) + { + RUOVersion.RemoveCommand(str); + } + + public static void Save() + { + try + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "Channels.bin"), true); + + writer.Write(0); // version + + writer.Write(s_Channels.Count); + foreach (Channel c in s_Channels) + { + writer.Write(c.GetType().ToString()); + c.Save(writer); + } + + writer.Close(); + } + catch (Exception e) + { + Errors.Report(General.Local(187)); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + public static void Load() + { + try + { + if (!File.Exists(Path.Combine(General.SavePath, "Channels.bin"))) + { + PredefinedChannels(); + return; + } + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "Channels.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + int count = reader.ReadInt(); + Channel c; + for (int i = 0; i < count; ++i) + { + c = Activator.CreateInstance(ScriptCompiler.FindTypeByFullName(reader.ReadString())) as Channel; + if (c == null) + { + c = new Channel(); + c.Load(reader); + s_Channels.Remove(c); + } + else + { + c.Load(reader); + } + } + } + + PredefinedChannels(); + } + catch(Exception e) + { + Errors.Report(General.Local(186)); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + private static void PredefinedChannels() + { + if (!Exists(typeof(Alliance))) + new Alliance(); + if (!Exists(typeof(Faction))) + new Faction(); + if (!Exists(typeof(Guild))) + new Guild(); + if (!Exists(typeof(Irc))) + new Irc(); + if (!Exists(typeof(Staff))) + new Staff(); + if (!Exists(typeof(Public))) + new Public(); + if (!Exists(typeof(Multi))) + new Multi(); + } + + public static bool Exists(Type type) + { + foreach (Channel c in s_Channels) + if (c.GetType().ToString() == type.ToString()) + return true; + + return false; + } + + #endregion + + #region Class Definitions + + private string c_Name; + private ArrayList c_Mobiles = new ArrayList(); + private Hashtable c_Colors = new Hashtable(); + private ArrayList c_Commands = new ArrayList(); + private ArrayList c_History = new ArrayList(); + private int c_DefaultC; + private ChatStyle c_Style; + private bool c_ToIrc, c_NewChars, c_Filter, c_Delay, c_ShowStaff, c_Enabled; + + public string Name { get { return c_Name; } set { c_Name = value; } } + public Hashtable Colors { get { return c_Colors; } } + public ArrayList Commands { get { return c_Commands; } } + public ArrayList History { get { return c_History; } } + public int DefaultC { get { return c_DefaultC; } set { c_DefaultC = value; } } + public ChatStyle Style { get { return c_Style; } set { c_Style = value; } } + public bool ToIrc { get { return c_ToIrc; } set { c_ToIrc = value; } } + public bool NewChars { get { return c_NewChars; } set { c_NewChars = value; } } + public bool Filter { get { return c_Filter; } set { c_Filter = value; } } + public bool Delay { get { return c_Delay; } set { c_Delay = value; } } + public bool ShowStaff { get { return c_ShowStaff; } set { c_ShowStaff = value; } } + public bool Enabled { get { return c_Enabled; } set { c_Enabled = value; } } + + #endregion + + #region Constructors + + public Channel( string name ) + { + c_Name = name; + + c_DefaultC = 0x47E; + c_Filter = true; + c_Delay = true; + c_Enabled = true; + + s_Channels.Add(this); + } + + public Channel() + { + // For Loading + + s_Channels.Add(this); + } + + #endregion + + #region Methods + + public virtual bool IsIn(Mobile m) + { + return c_Mobiles.Contains(m); + } + + public void Join(Mobile m) + { + if (!c_Mobiles.Contains(m)) + c_Mobiles.Add(m); + } + + public void Leave(Mobile m) + { + c_Mobiles.Remove(m); + } + + public virtual ArrayList GetHistory(Mobile m) + { + return c_History; + } + + public virtual void AddHistory(Mobile m, string msg) + { + c_History.Add(new ChatHistory(m, msg)); + } + + public virtual void UpdateHistory(Mobile m) + { + if (c_History.Count > 50) + c_History.RemoveAt(0); + } + + public virtual int ColorFor(Mobile m) + { + if (c_Colors[m] == null) + c_Colors[m] = c_DefaultC; + + return (int)c_Colors[m]; + } + + public virtual string NameFor(Mobile m) + { + if (c_Style == ChatStyle.Regional && m.Region != null && m.Region.Name != "") + return c_Name + " (" + m.Region.Name + ")"; + + return c_Name; + } + + public virtual bool CanChat(Mobile m, bool say) + { + if (!Enabled) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(213)); + return false; + } + + if (m.Squelched) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(260)); + return false; + } + + if (Data.GetData(m).Banned) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(33)); + return false; + } + + if (c_Style == ChatStyle.Regional && (m.Region == null || m.Region.Name == "")) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(35)); + return false; + } + + return true; + } + + private void OnChat(object o) + { + if (!(o is object[])) + return; + + object[] obj = (object[])o; + + if (obj.Length != 2 || !(obj[0] is Mobile) || !(obj[1] is string)) + return; + + OnChat((Mobile)obj[0], obj[1].ToString(), false); + } + + public virtual void OnChat(Mobile m, string msg) + { + OnChat(m, msg, true); + } + + public virtual void OnChat(Mobile m, string msg, bool spam) + { + if (msg == null || msg == "") + { + if (!CanChat(m, false)) + { + General.List(m, 0); + return; + } + + if (c_Mobiles.Contains(m)) + Data.GetData(m).CurrentChannel = this; + + General.List(m, 1); + return; + } + + if (!CanChat(m, true)) + return; + + if(c_Filter) + msg = Chat3.Filter.FilterText(m, msg); + + if (!CanChat(m, false)) + return; + + if (!c_Mobiles.Contains(m)) + { + m.SendMessage(Data.GetData(m).SystemC, General.Local(34)); + return; + } + + if (c_Delay && !TrackSpam.LogSpam(m, "Chat", TimeSpan.FromSeconds(Data.ChatSpam))) + { + if (spam) m.SendMessage(Data.GetData(m).SystemC, General.Local(97)); + Timer.DelayCall(TimeSpan.FromSeconds(4), new TimerStateCallback(OnChat), new object[] { m, msg }); + return; + } + + AddHistory(m, msg); + UpdateHistory(m); + Events.InvokeChat(new ChatEventArgs(m, this, msg)); + + if (Data.LogChat) + Logging.LogChat(String.Format(DateTime.Now + " <{0}{1}> {2}: {3}", c_Name, (c_Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.RawName, msg)); + + Data.TotalChats++; + Data.GetData(m).Karma++; + + Broadcast(m, msg); + + if (c_ToIrc && IrcConnection.Connection.Connected) + IrcConnection.Connection.SendUserMessage(m, "(" + c_Name + ") " + msg); + } + + protected virtual void Broadcast(Mobile m, string msg) + { + foreach (Data data in Data.Datas.Values) + { + if (c_Mobiles.Contains(data.Mobile) && !data.Ignores.Contains(m)) + { + if (c_Style == ChatStyle.Regional && data.Mobile.Region != m.Region) + continue; + + data.Mobile.SendMessage(m.AccessLevel == AccessLevel.Player ? ColorFor(data.Mobile) : Data.GetData(m).StaffC, String.Format("<{0}{1}> {2}: {3}", NameFor(m), (c_Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.RawName, msg)); + } + else if (data.Mobile.AccessLevel >= m.AccessLevel && ((data.GlobalC && !data.GIgnores.Contains(m)) || data.GListens.Contains(m))) + data.Mobile.SendMessage(data.GlobalCC, String.Format("(Global) <{0}{1}> {2}: {3}", c_Name, (c_Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.RawName, msg )); + } + } + + public void BroadcastSystem(string msg) + { + foreach (Mobile m in c_Mobiles) + if (!Data.GetData(m).Banned) + m.SendMessage(Data.GetData(m).SystemC, msg); + } + + public virtual ArrayList BuildList(Mobile m) + { + ArrayList list = new ArrayList(); + + foreach (Mobile tolist in new ArrayList(c_Mobiles)) + { + if (tolist.NetState == null) + continue; + + if (m.AccessLevel < tolist.AccessLevel && !c_ShowStaff) + continue; + + if (Data.GetData(tolist).Status == OnlineStatus.Hidden && tolist.AccessLevel >= m.AccessLevel) + continue; + + if (c_Style == ChatStyle.Regional && tolist.Region != m.Region) + continue; + + list.Add(tolist); + } + + return list; + } + + protected void Save(GenericWriter writer) + { + writer.Write(1); // Version + + writer.WriteMobileList(c_Mobiles, true); + writer.Write(c_Filter); + writer.Write(c_Delay); + writer.Write(c_Name); + writer.Write((int)c_Style); + writer.Write(c_ToIrc); + writer.Write(c_NewChars); + writer.Write(c_ShowStaff); + writer.Write(c_Enabled); + + writer.Write(c_Colors.Count); + foreach(Mobile m in c_Colors.Keys) + { + writer.Write(m); + writer.Write((int)c_Colors[m]); + } + + writer.Write(c_Commands.Count); + foreach (string str in c_Commands) + writer.Write(str); + } + + protected void Load(GenericReader reader) + { + int version = reader.ReadInt(); + + c_Mobiles = reader.ReadMobileList(); + c_Filter = reader.ReadBool(); + c_Delay = reader.ReadBool(); + c_Name = reader.ReadString(); + c_Style = (ChatStyle)reader.ReadInt(); + c_ToIrc = reader.ReadBool(); + c_NewChars = reader.ReadBool(); + c_ShowStaff = reader.ReadBool(); + c_Enabled = reader.ReadBool(); + + int count = reader.ReadInt(); + Mobile m; + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + c_Colors[m] = reader.ReadInt(); + else + reader.ReadInt(); + } + + c_Commands.Clear(); + count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + c_Commands.Add(reader.ReadString()); + + foreach (string str in c_Commands) + AddCommand(str); + + ArrayList list = new ArrayList(); + foreach(Mobile mob in c_Mobiles) + if (!list.Contains(mob)) + list.Add(mob); + + c_Mobiles = new ArrayList(list); + } + + #endregion + + #region Internal Classes + + public class ChatHistory + { + private Mobile c_Mobile; + private string c_Txt; + + public Mobile Mobile { get { return c_Mobile; } } + public string Txt { get { return c_Txt; } } + + public ChatHistory(Mobile m, string txt) + { + c_Mobile = m; + c_Txt = txt; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Faction.cs b/Scripts/Customs/KniveChat/Channels/Faction.cs new file mode 100644 index 0000000..1f4b351 --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Faction.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class Faction : Channel + { + public Faction() : base("Faction") + { + Commands.Add("faction"); + Commands.Add("f"); + DefaultC = 0x17; + NewChars = true; + + Register(this); + } + + public override bool CanChat(Mobile m, bool say) + { + if (!General.IsInFaction(m)) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(37)); + return false; + } + + return base.CanChat(m, say); + } + + protected override void Broadcast(Mobile m, string msg) + { + foreach (Data data in Data.Datas.Values) + { + if (IsIn(data.Mobile) && !data.Ignores.Contains(m) && General.FactionName(data.Mobile) == General.FactionName(m)) + data.Mobile.SendMessage(m.AccessLevel == AccessLevel.Player ? ColorFor(data.Mobile) : Data.GetData(m).StaffC, String.Format("<{0}{1}> {2}: {3}", NameFor(m), (Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.RawName, msg)); + else if (data.Mobile.AccessLevel >= m.AccessLevel && ((data.GlobalF && !data.GIgnores.Contains(m)) || data.GListens.Contains(m))) + data.Mobile.SendMessage(data.GlobalFC, String.Format("(Global) <{0}> {1}: {2}", NameFor(m), m.RawName, msg)); + } + } + + public override ArrayList BuildList(Mobile m) + { + ArrayList list = base.BuildList(m); + + foreach (Mobile mob in new ArrayList(list)) + if (General.FactionName(mob) != General.FactionName(m)) + list.Remove(mob); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Guild.cs b/Scripts/Customs/KniveChat/Channels/Guild.cs new file mode 100644 index 0000000..896ba08 --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Guild.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class Guild : Channel + { + private Hashtable c_History = new Hashtable(); + + public Guild() : base("Guild") + { + Commands.Add("guild"); + Commands.Add("g"); + DefaultC = 0x44; + NewChars = true; + Filter = false; + Delay = false; + + Register(this); + } + + public override ArrayList GetHistory(Mobile m) + { + if (m.Guild == null) + return new ArrayList(); + + if (c_History[m.Guild] == null) + c_History[m.Guild] = new ArrayList(); + + return (ArrayList)c_History[m.Guild]; + } + + public override void AddHistory(Mobile m, string msg) + { + if (m.Guild == null) + return; + + if (c_History[m.Guild] == null) + c_History[m.Guild] = new ArrayList(); + + ((ArrayList)c_History[m.Guild]).Add(new ChatHistory(m, msg)); + } + + public override void UpdateHistory(Mobile m) + { + if(m.Guild == null) + return; + + if (c_History[m.Guild] == null) + c_History[m.Guild] = new ArrayList(); + + if (((ArrayList)c_History[m.Guild]).Count > 50) + ((ArrayList)c_History[m.Guild]).RemoveAt(0); + } + + public override string NameFor(Mobile m) + { + if (m.Guild == null) + return Name; + + if (m.Guild.Abbreviation == "") + return Name; + + return m.Guild.Abbreviation; + } + + public override bool CanChat(Mobile m, bool say) + { + if (m.Guild == null) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(36)); + return false; + } + + return base.CanChat(m, say); + } + + protected override void Broadcast(Mobile m, string msg) + { + foreach (Data data in Data.Datas.Values) + { + if (data.Mobile.AccessLevel >= m.AccessLevel && ((data.GlobalG && !data.GIgnores.Contains(m)) || data.GListens.Contains(m))) + data.Mobile.SendMessage(data.GlobalGC, String.Format("(Global) <{0}> {1}: {2}", NameFor(m), m.RawName, msg)); + else if (IsIn(data.Mobile) && !data.Ignores.Contains(m) && data.Mobile.Guild == m.Guild) + data.Mobile.SendMessage(m.AccessLevel == AccessLevel.Player ? ColorFor(data.Mobile) : Data.GetData(m).StaffC, String.Format("<{0}{1}> {2}: {3}", NameFor(m), (Style == ChatStyle.Regional && m.Region != null ? "-" + m.Region.Name : ""), m.RawName, msg)); + } + } + + public override ArrayList BuildList(Mobile m) + { + ArrayList list = base.BuildList(m); + + foreach (Mobile mob in new ArrayList(list)) + if (mob.Guild != m.Guild) + list.Remove(mob); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Irc.cs b/Scripts/Customs/KniveChat/Channels/Irc.cs new file mode 100644 index 0000000..8132e27 --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Irc.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class Irc : Channel + { + public Irc() : base("IRC") + { + Commands.Add("irc"); + Commands.Add("i"); + DefaultC = 0x1FC; + NewChars = true; + + Register(this); + } + + public override string NameFor(Mobile m) + { + return Data.IrcRoom; + } + + public override bool CanChat(Mobile m, bool say) + { + if (IrcConnection.Connection == null || !IrcConnection.Connection.Connected) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(158)); + return false; + } + + return base.CanChat(m, say); + } + + public void Broadcast(string name, string msg) + { + foreach (Data data in Data.Datas.Values) + { + if (IsIn(data.Mobile) && !data.IrcIgnores.Contains(name)) + data.Mobile.SendMessage(ColorFor(data.Mobile), msg); + else if (data.GlobalC) + data.Mobile.SendMessage(data.GlobalCC, String.Format("(Global) <{0}> {1}: {2}", Name, name, msg )); + } + } + + protected override void Broadcast(Mobile m, string msg) + { + base.Broadcast(m, msg); + + IrcConnection.Connection.SendUserMessage(m, msg); + } + + public override ArrayList BuildList(Mobile m) + { + ArrayList list = base.BuildList(m); + + foreach (string str in Data.IrcList) + list.Add(str); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Multi.cs b/Scripts/Customs/KniveChat/Channels/Multi.cs new file mode 100644 index 0000000..a4ffe9c --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Multi.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class Multi : Channel + { + public Multi() : base("Multi") + { + Commands.Add("Mult"); + Commands.Add("mu"); + DefaultC = 0x1FC; + + Register(this); + } + + public override string NameFor(Mobile m) + { + return Server.Misc.ServerList.ServerName; + } + + public override bool CanChat(Mobile m, bool say) + { + if (MultiConnection.Connection == null || !MultiConnection.Connection.Connected) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(158)); + return false; + } + + return base.CanChat(m, say); + } + + public void Broadcast(string msg) + { + foreach (Data data in Data.Datas.Values) + { + if (IsIn(data.Mobile)) + data.Mobile.SendMessage(ColorFor(data.Mobile), msg); + else if (data.GlobalC) + data.Mobile.SendMessage(data.GlobalCC, String.Format("(Global) {0}", msg )); + } + } + + protected override void Broadcast(Mobile m, string msg) + { + //base.Broadcast(m, msg); + + MultiConnection.Connection.SendMessage(m, msg); + } + + public override ArrayList BuildList(Mobile m) + { + ArrayList list = base.BuildList(m); + + //foreach (string str in Data.IrcList) + // list.Add(str); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Public.cs b/Scripts/Customs/KniveChat/Channels/Public.cs new file mode 100644 index 0000000..0316a12 --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Public.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class Public : Channel + { + public Public() : base("Public") + { + Commands.Add("chat"); + Commands.Add("c"); + NewChars = true; + + Register(this); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Channels/Staff.cs b/Scripts/Customs/KniveChat/Channels/Staff.cs new file mode 100644 index 0000000..2aacf09 --- /dev/null +++ b/Scripts/Customs/KniveChat/Channels/Staff.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class Staff : Channel + { + public Staff() : base("Staff") + { + Commands.Add("staff"); + Commands.Add("st"); + DefaultC = 0x26; + ShowStaff = true; + + Register(this); + } + + public override bool CanChat(Mobile m, bool say) + { + if (m.AccessLevel == AccessLevel.Player) + { + if (say) m.SendMessage(Data.GetData(m).SystemC, General.Local(191)); + return false; + } + + return base.CanChat(m, say); + } + + public override ArrayList BuildList(Mobile m) + { + ArrayList list = base.BuildList(m); + + foreach (Data data in Data.Datas.Values) + if (!list.Contains(data.Mobile) && data.Mobile.AccessLevel > AccessLevel.Player) + list.Add(data.Mobile); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Commands/All.cs b/Scripts/Customs/KniveChat/Commands/All.cs new file mode 100644 index 0000000..907eae8 --- /dev/null +++ b/Scripts/Customs/KniveChat/Commands/All.cs @@ -0,0 +1,21 @@ +using System; +using Server; +using Server.Network; + +namespace Knives.Chat3 +{ + public class All + { + public static void Initialize() + { + RUOVersion.AddCommand("All", AccessLevel.GameMaster, new ChatCommandHandler(OnAll)); + } + + private static void OnAll(CommandInfo e) + { + foreach (NetState ns in NetState.Instances) + if (ns.Mobile != null) + ns.Mobile.SendMessage(Data.GetData(e.Mobile).StaffC, "<{0}> {1}: {2}", General.Local(261), e.Mobile.RawName, e.ArgString ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Commands/Friends.cs b/Scripts/Customs/KniveChat/Commands/Friends.cs new file mode 100644 index 0000000..4c7fca7 --- /dev/null +++ b/Scripts/Customs/KniveChat/Commands/Friends.cs @@ -0,0 +1,19 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class Friends + { + public static void Initialize() + { + RUOVersion.AddCommand("Friends", AccessLevel.Player, new ChatCommandHandler(OnFriends)); + RUOVersion.AddCommand("Fri", AccessLevel.Player, new ChatCommandHandler(OnFriends)); + } + + private static void OnFriends(CommandInfo e) + { + General.List(e.Mobile, 3); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Commands/HelpContents.cs b/Scripts/Customs/KniveChat/Commands/HelpContents.cs new file mode 100644 index 0000000..46c0135 --- /dev/null +++ b/Scripts/Customs/KniveChat/Commands/HelpContents.cs @@ -0,0 +1,20 @@ +using System; +using Server; +using Server.Network; + +namespace Knives.Chat3 +{ + public class HelpContents + { + public static void Initialize() + { + RUOVersion.AddCommand("HelpContents", AccessLevel.Player, new ChatCommandHandler(OnHelp)); + RUOVersion.AddCommand("hc", AccessLevel.Player, new ChatCommandHandler(OnHelp)); + } + + private static void OnHelp(CommandInfo e) + { + new HelpContentsGump(e.Mobile); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Commands/Mail.cs b/Scripts/Customs/KniveChat/Commands/Mail.cs new file mode 100644 index 0000000..c5b9b08 --- /dev/null +++ b/Scripts/Customs/KniveChat/Commands/Mail.cs @@ -0,0 +1,19 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class Mail + { + public static void Initialize() + { + RUOVersion.AddCommand("Mail", AccessLevel.Player, new ChatCommandHandler(OnMail)); + RUOVersion.AddCommand("Ma", AccessLevel.Player, new ChatCommandHandler(OnMail)); + } + + private static void OnMail(CommandInfo e) + { + General.List(e.Mobile, 2); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Commands/Pm.cs b/Scripts/Customs/KniveChat/Commands/Pm.cs new file mode 100644 index 0000000..8a9de51 --- /dev/null +++ b/Scripts/Customs/KniveChat/Commands/Pm.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class Pm + { + public static void Initialize() + { + RUOVersion.AddCommand("pm", AccessLevel.Player, new ChatCommandHandler(OnMessage)); + RUOVersion.AddCommand("msg", AccessLevel.Player, new ChatCommandHandler(OnMessage)); + } + + private static void OnMessage(CommandInfo e) + { + if (e.ArgString == null || e.ArgString == "") + return; + + string name = e.GetString(0); + string text = ""; + + if (e.Arguments.Length > 1) + text = e.ArgString.Substring(name.Length + 1, e.ArgString.Length - name.Length - 1); + + ArrayList list = GetMsgCanidates(e.Mobile, name); + + if (list.Count > 10) + e.Mobile.SendMessage(Data.GetData(e.Mobile).SystemC, General.Local(112)); + else if (list.Count == 0) + e.Mobile.SendMessage(Data.GetData(e.Mobile).SystemC, General.Local(113)); + else if (list.Count == 1) + new SendMessageGump(e.Mobile, (Mobile)list[0], text, null, MsgType.Normal); + else + new InternalGump(e.Mobile, list, text); + } + + private static ArrayList GetMsgCanidates(Mobile m, string name) + { + ArrayList list = new ArrayList(); + + foreach (Data data in new ArrayList(Data.Datas.Values)) + if (data.Mobile.RawName.ToLower().IndexOf(name.ToLower()) != -1 && Message.CanMessage(m, data.Mobile)) + list.Add(data.Mobile); + + return list; + } + + + private class InternalGump : GumpPlus + { + private ArrayList c_List; + private string c_Text; + + public InternalGump(Mobile m, ArrayList list, string txt) : base(m, 100, 100) + { + c_List = list; + c_Text = txt; + } + + protected override void BuildGump() + { + int y = 10; + + AddHtml(0, y, 150, 21, HTML.White + "
" + General.Local(114), false, false); + + y += 5; + + foreach (Mobile m in c_List) + { + AddHtml(60, y += 20, 90, 21, HTML.White + m.RawName, false, false); + AddButton(45, y + 3, 0x2716, 0x2716, "Select", new GumpStateCallback(Select), m); + } + + AddBackgroundZero(0, 0, 150, y + 40, 0x1400); + } + + private void Select(object o) + { + if (!(o is Mobile)) + return; + + new SendMessageGump(Owner, (Mobile)o, c_Text, null, MsgType.Normal); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Commands/ViewAll.cs b/Scripts/Customs/KniveChat/Commands/ViewAll.cs new file mode 100644 index 0000000..dceaf31 --- /dev/null +++ b/Scripts/Customs/KniveChat/Commands/ViewAll.cs @@ -0,0 +1,19 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class ViewAll + { + public static void Initialize() + { + RUOVersion.AddCommand("ViewAll", AccessLevel.Player, new ChatCommandHandler(OnView)); + RUOVersion.AddCommand("Va", AccessLevel.Player, new ChatCommandHandler(OnView)); + } + + private static void OnView(CommandInfo e) + { + General.List(e.Mobile, 0); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Avatar.cs b/Scripts/Customs/KniveChat/General/Avatar.cs new file mode 100644 index 0000000..8438703 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Avatar.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class Avatar + { + private static Hashtable s_Avatars = new Hashtable(); + + public static Hashtable Avatars { get { return s_Avatars; } } + public static ArrayList AvaKeys { get { return new ArrayList(s_Avatars.Keys); } } + + public static void Initialize() + { + new Avatar(0x69, 8, 8); + new Avatar(0x6A, 8, 8); + new Avatar(0x6B, 8, 8); + new Avatar(0x6C, 8, 8); + new Avatar(0x6D, 8, 8); + new Avatar(0x6E, 8, 8); + new Avatar(0x6F, 8, 8); + new Avatar(0x70, 8, 8); + new Avatar(0x71, 25, 25); + new Avatar(0x8BA, 20, 17); + new Avatar(0x8C0, 18, 18); + new Avatar(0x8C1, 18, 18); + new Avatar(0x8C2, 18, 18); + new Avatar(0x8C3, 18, 18); + new Avatar(0x8C4, 18, 18); + new Avatar(0x8C5, 18, 18); + new Avatar(0x8C6, 18, 18); + new Avatar(0x8C7, 18, 18); + new Avatar(0x8C8, 18, 18); + new Avatar(0x8C9, 18, 18); + new Avatar(0x8CA, 18, 18); + new Avatar(0x8CB, 18, 18); + new Avatar(0x8CC, 18, 18); + new Avatar(0x8CD, 18, 18); + new Avatar(0x8CE, 18, 18); + new Avatar(0x8CF, 18, 18); + new Avatar(0x8D0, 18, 18); + new Avatar(0x8D1, 18, 18); + new Avatar(0x8D2, 18, 18); + new Avatar(0x8D3, 18, 18); + new Avatar(0x8D4, 18, 18); + new Avatar(0x8D5, 18, 18); + new Avatar(0x8D6, 18, 18); + new Avatar(0x8D7, 18, 18); + new Avatar(0x8D8, 18, 18); + new Avatar(0x8D9, 18, 18); + new Avatar(0x8DA, 18, 18); + new Avatar(0x8DB, 18, 18); + new Avatar(0x8DC, 18, 18); + new Avatar(0x8DD, 18, 18); + new Avatar(0x8DE, 18, 18); + new Avatar(0x8DF, 18, 18); + new Avatar(0x8E0, 18, 18); + new Avatar(0x8E1, 18, 18); + new Avatar(0x8E2, 18, 18); + new Avatar(0x8E3, 18, 18); + new Avatar(0x8E4, 18, 18); + new Avatar(0x8E5, 18, 18); + new Avatar(0x8E6, 18, 18); + new Avatar(0x8E7, 18, 18); + new Avatar(0x8E8, 18, 18); + new Avatar(0x8E9, 18, 18); + new Avatar(0x8EA, 18, 18); + new Avatar(0x8EB, 18, 18); + new Avatar(0x8EC, 18, 18); + new Avatar(0x8ED, 18, 18); + new Avatar(0x8EE, 18, 18); + new Avatar(0x8EF, 18, 18); + new Avatar(0x8F0, 18, 18); + new Avatar(0x8F1, 18, 18); + new Avatar(0x8F2, 18, 18); + new Avatar(0x8F3, 18, 18); + new Avatar(0x8F4, 18, 18); + new Avatar(0x8F5, 18, 18); + new Avatar(0x8F6, 18, 18); + new Avatar(0x8F7, 18, 18); + new Avatar(0x8F8, 18, 18); + new Avatar(0x8F9, 18, 18); + new Avatar(0x8FA, 18, 18); + new Avatar(0x8FB, 18, 18); + new Avatar(0x8FC, 18, 18); + new Avatar(0x8FD, 18, 18); + new Avatar(0x8FE, 18, 18); + new Avatar(0x8FF, 18, 18); + new Avatar(0x139D, 18, 16); + new Avatar(0x15A9, 10, 10); + new Avatar(0x15AB, 10, 10); + new Avatar(0x15AD, 10, 10); + new Avatar(0x15AF, 10, 10); + new Avatar(0x15B1, 10, 10); + new Avatar(0x15B3, 10, 10); + new Avatar(0x15B5, 10, 10); + new Avatar(0x15B7, 10, 10); + new Avatar(0x15B9, 10, 10); + new Avatar(0x15BB, 10, 10); + new Avatar(0x15BD, 10, 10); + new Avatar(0x15BF, 10, 10); + new Avatar(0x15C1, 10, 10); + new Avatar(0x15C3, 10, 10); + new Avatar(0x15C5, 10, 10); + new Avatar(0x15C7, 10, 10); + new Avatar(0x15C9, 10, 10); + new Avatar(0x15CB, 10, 10); + new Avatar(0x15CD, 10, 10); + new Avatar(0x15CF, 10, 10); + new Avatar(0x15D1, 10, 10); + new Avatar(0x15D3, 10, 10); + new Avatar(0x15D5, 10, 10); + new Avatar(0x15D7, 10, 10); + new Avatar(0x15E8, 10, 10); + new Avatar(0x264C, 5, 20); + new Avatar(0x28D2, 25, 16); + new Avatar(0x28E0, 21, 17); + new Avatar(0x2B03, 20, 17); + new Avatar(0x2B04, 20, 17); + new Avatar(0x2B05, 20, 17); + new Avatar(0x2B08, 20, 17); + new Avatar(0x2B09, 20, 17); + new Avatar(0x2B2D, 20, 17); + new Avatar(0x5000, 18, 18); + new Avatar(0x5001, 18, 18); + new Avatar(0x5002, 18, 18); + new Avatar(0x5003, 18, 18); + new Avatar(0x5004, 18, 18); + new Avatar(0x5005, 18, 18); + new Avatar(0x5006, 18, 18); + new Avatar(0x5007, 18, 18); + new Avatar(0x5008, 18, 18); + new Avatar(0x5009, 18, 18); + new Avatar(0x500A, 18, 18); + new Avatar(0x500B, 18, 18); + new Avatar(0x500C, 18, 18); + new Avatar(0x500D, 18, 18); + new Avatar(0x500E, 18, 18); + new Avatar(0x500F, 18, 18); + new Avatar(0x5010, 18, 18); + new Avatar(0x5100, 18, 18); + new Avatar(0x5101, 18, 18); + new Avatar(0x5102, 18, 18); + new Avatar(0x5103, 18, 18); + new Avatar(0x5104, 18, 18); + new Avatar(0x5105, 18, 18); + new Avatar(0x5106, 18, 18); + new Avatar(0x5107, 18, 18); + new Avatar(0x5108, 18, 18); + new Avatar(0x5109, 18, 18); + new Avatar(0x5200, 18, 18); + new Avatar(0x5201, 18, 18); + new Avatar(0x5202, 18, 18); + new Avatar(0x5203, 18, 18); + new Avatar(0x5204, 18, 18); + new Avatar(0x5205, 18, 18); + new Avatar(0x5206, 18, 18); + new Avatar(0x5207, 18, 18); + new Avatar(0x5208, 18, 18); + new Avatar(0x5209, 18, 18); + new Avatar(0x520A, 18, 18); + new Avatar(0x520B, 18, 18); + new Avatar(0x520C, 18, 18); + new Avatar(0x520D, 18, 18); + new Avatar(0x520E, 18, 18); + new Avatar(0x520F, 18, 18); + new Avatar(0x5210, 18, 18); + new Avatar(0x5211, 18, 18); + new Avatar(0x5212, 18, 18); + new Avatar(0x5213, 18, 18); + new Avatar(0x5214, 18, 18); + new Avatar(0x5215, 18, 18); + new Avatar(0x5216, 18, 18); + new Avatar(0x5217, 18, 18); + new Avatar(0x5218, 18, 18); + new Avatar(0x5219, 18, 18); + new Avatar(0x521A, 18, 18); + new Avatar(0x521B, 18, 18); + new Avatar(0x521C, 18, 18); + new Avatar(0x5308, 18, 18); + new Avatar(0x5309, 18, 18); + new Avatar(0x5320, 18, 18); + new Avatar(0x5321, 18, 18); + new Avatar(0x5322, 18, 18); + new Avatar(0x5323, 18, 18); + new Avatar(0x5324, 18, 18); + new Avatar(0x5325, 18, 18); + new Avatar(0x5326, 18, 18); + new Avatar(0x5327, 18, 18); + new Avatar(0x5420, 18, 18); + new Avatar(0x5421, 18, 18); + new Avatar(0x5422, 18, 18); + new Avatar(0x5423, 18, 18); + new Avatar(0x5424, 18, 18); + new Avatar(0x5425, 18, 18); + new Avatar(0x5426, 18, 18); + new Avatar(0x59D8, 18, 18); + new Avatar(0x59D9, 18, 18); + new Avatar(0x59DA, 18, 18); + new Avatar(0x59DB, 18, 18); + new Avatar(0x59DC, 18, 18); + new Avatar(0x59DD, 18, 18); + new Avatar(0x59DE, 18, 18); + new Avatar(0x59DF, 18, 18); + new Avatar(0x59E1, 18, 18); + new Avatar(0x59E2, 18, 18); + new Avatar(0x59E3, 18, 18); + new Avatar(0x59E4, 18, 18); + new Avatar(0x59E5, 18, 18); + new Avatar(0x59E6, 18, 18); + new Avatar(0x59E7, 18, 18); + new Avatar(104354, 15, 16); + + General.LoadAvatarFile(); + } + + public static Avatar GetAvatar(Mobile m) + { + if (s_Avatars[Data.GetData(m).Avatar] == null) + Data.GetData(m).Avatar = (int)AvaKeys[0]; + + return (Avatar)s_Avatars[Data.GetData(m).Avatar]; + } + + private int c_Id, c_X, c_Y; + + public int Id { get { return c_Id; } } + public int X { get { return c_X; } } + public int Y { get { return c_Y; } } + + public Avatar(int id, int x, int y) + { + c_Id = id; + c_X = x; + c_Y = y; + + s_Avatars[id] = this; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Chat3Guild.cs b/Scripts/Customs/KniveChat/General/Chat3Guild.cs new file mode 100644 index 0000000..ae43b87 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Chat3Guild.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Network; +using Knives.Chat3; + +namespace Server.Engines.PartySystem +{ + public class Chat3Guild + { + public static void Initialize() + { + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(AfterInit)); + } + + public static void AfterInit() + { + PacketHandlers.Register(0x03, 0, true, new OnPacketReceive(AsciiSpeechChat3)); + PacketHandlers.Register(0xAD, 0, true, new OnPacketReceive(UnicodeSpeechChat3)); + } + + public static void AsciiSpeechChat3(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + + MessageType type = (MessageType)pvSrc.ReadByte(); + int hue = pvSrc.ReadInt16(); + pvSrc.ReadInt16(); // font + string text = pvSrc.ReadStringSafe().Trim(); + + if (text.Length <= 0 || text.Length > 128) + return; + + if (!Enum.IsDefined(typeof(MessageType), type)) + type = MessageType.Regular; + + Channel c = Channel.GetByType(typeof(Guild)); + if (RUOVersion.GuildChat(type) && c != null) + c.OnChat(from, text); + else + from.DoSpeech(text, c_EmptyInts, type, Utility.ClipDyedHue(hue)); + } + + private static KeywordList c_KeywordList = new KeywordList(); + private static int[] c_EmptyInts = new int[0]; + + public static void UnicodeSpeechChat3(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + + MessageType type = (MessageType)pvSrc.ReadByte(); + int hue = pvSrc.ReadInt16(); + pvSrc.ReadInt16(); // font + string lang = pvSrc.ReadString(4); + string text; + + bool isEncoded = (type & MessageType.Encoded) != 0; + int[] keywords; + + if (isEncoded) + { + int value = pvSrc.ReadInt16(); + int count = (value & 0xFFF0) >> 4; + int hold = value & 0xF; + + if (count < 0 || count > 50) + return; + + KeywordList keyList = c_KeywordList; + + for (int i = 0; i < count; ++i) + { + int speechID; + + if ((i & 1) == 0) + { + hold <<= 8; + hold |= pvSrc.ReadByte(); + speechID = hold; + hold = 0; + } + else + { + value = pvSrc.ReadInt16(); + speechID = (value & 0xFFF0) >> 4; + hold = value & 0xF; + } + + if (!keyList.Contains(speechID)) + keyList.Add(speechID); + } + + text = pvSrc.ReadUTF8StringSafe(); + + keywords = keyList.ToArray(); + } + else + { + text = pvSrc.ReadUnicodeStringSafe(); + + keywords = c_EmptyInts; + } + + text = text.Trim(); + + if (text.Length <= 0 || text.Length > 128) + return; + + type &= ~MessageType.Encoded; + + if (!Enum.IsDefined(typeof(MessageType), type)) + type = MessageType.Regular; + + from.Language = lang; + + Channel c = Channel.GetByType(typeof(Guild)); + if (RUOVersion.GuildChat(type) && c != null) + { + if(c.CanChat(from, true)) + c.OnChat(from, text); + } + else + from.DoSpeech(text, keywords, type, Utility.ClipDyedHue(hue)); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Chat3Party.cs b/Scripts/Customs/KniveChat/General/Chat3Party.cs new file mode 100644 index 0000000..07ec68d --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Chat3Party.cs @@ -0,0 +1,135 @@ +using System; +using Server; +using Server.Network; +using Knives.Chat3; + +namespace Server.Engines.PartySystem +{ + public class Chat3Party : PartyCommands + { + public static void Initialize() + { + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(AfterInit)); + } + + private static void AfterInit() + { + PartyCommands.Handler = new Chat3Party(); + } + + public override void OnAdd( Mobile from ) + { + Party p = Party.Get( from ); + + if ( p != null && p.Leader != from ) + from.SendLocalizedMessage( 1005453 ); // You may only add members to the party if you are the leader. + else if ( p != null && (p.Members.Count + p.Candidates.Count) >= Party.Capacity ) + from.SendLocalizedMessage( 1008095 ); // You may only have 10 in your party (this includes candidates). + else + from.Target = new AddPartyTarget( from ); + } + + public override void OnRemove( Mobile from, Mobile target ) + { + Party p = Party.Get( from ); + + if ( p == null ) + { + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + return; + } + + if ( p.Leader == from && target == null ) + { + from.SendLocalizedMessage( 1005455 ); // Who would you like to remove from your party? + from.Target = new RemovePartyTarget(); + } + else if ( (p.Leader == from || from == target) && p.Contains( target ) ) + { + p.Remove( target ); + } + } + + public override void OnPrivateMessage( Mobile from, Mobile target, string text ) + { + if ( text.Length > 128 || (text = text.Trim()).Length == 0 ) + return; + + Party p = Party.Get( from ); + + if ( p != null && p.Contains( target ) ) + p.SendPrivateMessage( from, target, text ); + else + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + } + + public override void OnPublicMessage( Mobile from, string text ) + { + if ( text.Length > 128 || (text = text.Trim()).Length == 0 ) + return; + + Party p = Party.Get( from ); + + if (p != null) + { + p.SendPublicMessage(from, text); + + foreach (Data data in Data.Datas.Values) + if (data.GlobalW && !p.Contains(data.Mobile)) + data.Mobile.SendMessage(data.GlobalWC, "(Global) Party> {0}: {1}", from.Name, text); + } + else + from.SendLocalizedMessage(3000211); // You are not in a party. + } + + public override void OnSetCanLoot( Mobile from, bool canLoot ) + { + Party p = Party.Get( from ); + + if ( p == null ) + { + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + } + else + { + PartyMemberInfo mi = p[from]; + + if ( mi != null ) + { + mi.CanLoot = canLoot; + + if ( canLoot ) + from.SendLocalizedMessage( 1005447 ); // You have chosen to allow your party to loot your corpse. + else + from.SendLocalizedMessage( 1005448 ); // You have chosen to prevent your party from looting your corpse. + } + } + } + + public override void OnAccept( Mobile from, Mobile sentLeader ) + { + Mobile leader = from.Party as Mobile; + from.Party = null; + + Party p = Party.Get( leader ); + + if ( leader == null || p == null || !p.Candidates.Contains( from ) ) + from.SendLocalizedMessage( 3000222 ); // No one has invited you to be in a party. + else if ( (p.Members.Count + p.Candidates.Count) <= Party.Capacity ) + p.OnAccept( from ); + } + + public override void OnDecline( Mobile from, Mobile sentLeader ) + { + Mobile leader = from.Party as Mobile; + from.Party = null; + + Party p = Party.Get( leader ); + + if ( leader == null || p == null || !p.Candidates.Contains( from ) ) + from.SendLocalizedMessage( 3000222 ); // No one has invited you to be in a party. + else + p.OnDecline( from, leader ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/CommandInfo.cs b/Scripts/Customs/KniveChat/General/CommandInfo.cs new file mode 100644 index 0000000..43a9b3f --- /dev/null +++ b/Scripts/Customs/KniveChat/General/CommandInfo.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public delegate void ChatCommandHandler(CommandInfo info); + + public class CommandInfo + { + private Mobile c_Mobile; + private string c_Command; + private string c_ArgString; + private string[] c_Arguments; + + public Mobile Mobile { get { return c_Mobile; } } + public string Command { get { return c_Command; } } + public string ArgString { get { return c_ArgString; } } + public string[] Arguments { get { return c_Arguments; } } + + public CommandInfo(Mobile m, string com, string args, string[] arglist) + { + c_Mobile = m; + c_Command = com; + c_ArgString = args; + c_Arguments = arglist; + } + + public string GetString(int num) + { + if (c_Arguments.Length > num) + return c_Arguments[num]; + + return ""; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Data.cs b/Scripts/Customs/KniveChat/General/Data.cs new file mode 100644 index 0000000..0de76d5 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Data.cs @@ -0,0 +1,1240 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Accounting; + +namespace Knives.Chat3 +{ + public enum OnlineStatus { Online, Away, Busy, Hidden } + public enum Skin { Three, Two, One } + + public class Data + { + #region Statics + + public static void Save() + { + try { SaveGlobalOptions(); } + catch (Exception e) + { + Errors.Report(General.Local(175), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { SavePlayerOptions(); } + catch (Exception e) + { + Errors.Report(General.Local(228), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { SaveFriends(); } + catch (Exception e) + { + Errors.Report(General.Local(230), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { SaveIgnores(); } + catch (Exception e) + { + Errors.Report(General.Local(232), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { SaveGlobalListens(); } + catch (Exception e) + { + Errors.Report(General.Local(234), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { SaveMsgs(); } + catch (Exception e) + { + Errors.Report(General.Local(236), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + public static void Load() + { + try { LoadGlobalOptions(); } + catch (Exception e) + { + Errors.Report(General.Local(174), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { LoadPlayerOptions(); } + catch (Exception e) + { + Errors.Report(General.Local(227), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { LoadFriends(); } + catch (Exception e) + { + Errors.Report(General.Local(229), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { LoadIgnores(); } + catch (Exception e) + { + Errors.Report(General.Local(231), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { LoadGlobalListens(); } + catch (Exception e) + { + Errors.Report(General.Local(233), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + try { LoadMsgs(); } + catch (Exception e) + { + Errors.Report(General.Local(235), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + public static void SaveGlobalOptions() + { + CleanUpData(); + + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "GlobalOptions.bin"), true); + + writer.Write(2); // version + + writer.Write(s_MultiPort); + writer.Write(s_MultiServer); + + writer.Write(s_Notifications.Count); + foreach (Notification not in s_Notifications) + not.Save(writer); + + writer.Write(s_Filters.Count); + foreach (string str in s_Filters) + writer.Write(str); + + writer.Write((int)s_FilterPenalty); + writer.Write((int)s_MacroPenalty); + writer.Write(s_MaxMsgs); + writer.Write(s_ChatSpam); + writer.Write(s_MsgSpam); + writer.Write(s_RequestSpam); + writer.Write(s_FilterBanLength); + writer.Write(s_FilterWarnings); + writer.Write(s_AntiMacroDelay); + writer.Write(s_IrcPort); + writer.Write(s_IrcMaxAttempts); + writer.Write(s_IrcEnabled); + writer.Write(s_IrcAutoConnect); + writer.Write(s_IrcAutoReconnect); + writer.Write(s_FilterSpeech); + writer.Write(s_FilterMsg); + writer.Write(s_Debug); + writer.Write(s_LogChat); + writer.Write(s_LogPms); + writer.Write((int)s_IrcStaffColor); + writer.Write(s_IrcServer); + writer.Write(s_IrcRoom); + writer.Write(s_IrcNick); + writer.Write(s_TotalChats+1); + + writer.Close(); + } + + public static void SavePlayerOptions() + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "PlayerOptions.bin"), true); + + writer.Write(0); // version + + writer.Write(s_Datas.Count); + foreach (Data data in s_Datas.Values) + { + writer.Write(data.Mobile); + data.SaveOptions(writer); + } + + writer.Close(); + } + + public static void SaveFriends() + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "Friends.bin"), true); + + writer.Write(0); // version + + writer.Write(s_Datas.Count); + foreach (Data data in s_Datas.Values) + { + writer.Write(data.Mobile); + data.SaveFriends(writer); + } + + writer.Close(); + } + + public static void SaveIgnores() + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "Ignores.bin"), true); + + writer.Write(0); // version + + writer.Write(s_Datas.Count); + foreach (Data data in s_Datas.Values) + { + writer.Write(data.Mobile); + data.SaveIgnores(writer); + } + + writer.Close(); + } + + public static void SaveGlobalListens() + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "GlobalListens.bin"), true); + + writer.Write(0); // version + + writer.Write(s_Datas.Count); + foreach (Data data in s_Datas.Values) + { + writer.Write(data.Mobile); + data.SaveGlobalListens(writer); + } + + writer.Close(); + } + + public static void SaveMsgs() + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "Pms.bin"), true); + + writer.Write(0); // version + + writer.Write(s_Datas.Count); + foreach (Data data in s_Datas.Values) + { + writer.Write(data.Mobile); + data.SaveMsgs(writer); + } + + writer.Close(); + } + + public static void LoadGlobalOptions() + { + if (!File.Exists(Path.Combine(General.SavePath, "GlobalOptions.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "GlobalOptions.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + if (version >= 2) s_MultiPort = reader.ReadInt(); + if (version >= 2) s_MultiServer = reader.ReadString(); + + int count = 0; + if (version >= 1) + { + count = reader.ReadInt(); + Notification not = null; + for (int i = 0; i < count; ++i) + { + not = new Notification(); + not.Load(reader); + } + } + + count = reader.ReadInt(); + string txt = ""; + for (int i = 0; i < count; ++i) + { + txt = reader.ReadString(); + if(!s_Filters.Contains(txt)) + s_Filters.Add(txt); + } + + s_FilterPenalty = (FilterPenalty)reader.ReadInt(); + if(version >= 1) s_MacroPenalty = (MacroPenalty)reader.ReadInt(); + s_MaxMsgs = reader.ReadInt(); + s_ChatSpam = reader.ReadInt(); + s_MsgSpam = reader.ReadInt(); + s_RequestSpam = reader.ReadInt(); + s_FilterBanLength = reader.ReadInt(); + s_FilterWarnings = reader.ReadInt(); + if (version >= 1) s_AntiMacroDelay = reader.ReadInt(); + s_IrcPort = reader.ReadInt(); + s_IrcMaxAttempts = reader.ReadInt(); + s_IrcEnabled = reader.ReadBool(); + s_IrcAutoConnect = reader.ReadBool(); + s_IrcAutoReconnect = reader.ReadBool(); + s_FilterSpeech = reader.ReadBool(); + s_FilterMsg = reader.ReadBool(); + s_Debug = reader.ReadBool(); + s_LogChat = reader.ReadBool(); + s_LogPms = reader.ReadBool(); + s_IrcStaffColor = (IrcColor)reader.ReadInt(); + s_IrcServer = reader.ReadString(); + s_IrcRoom = reader.ReadString(); + s_IrcNick = reader.ReadString(); + s_TotalChats = reader.ReadULong() - 1; + } + } + + public static void LoadPlayerOptions() + { + if (!File.Exists(Path.Combine(General.SavePath, "PlayerOptions.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "PlayerOptions.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + Mobile m = null; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + GetData(m).LoadOptions(reader); + else + (new Data()).LoadOptions(reader); + } + } + } + + public static void LoadFriends() + { + if (!File.Exists(Path.Combine(General.SavePath, "Friends.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "Friends.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + Mobile m = null; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + GetData(m).LoadFriends(reader); + else + (new Data()).LoadFriends(reader); + } + } + } + + public static void LoadIgnores() + { + if (!File.Exists(Path.Combine(General.SavePath, "Ignores.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "Ignores.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + Mobile m = null; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + GetData(m).LoadIgnores(reader); + else + (new Data()).LoadIgnores(reader); + } + } + } + + public static void LoadGlobalListens() + { + if (!File.Exists(Path.Combine(General.SavePath, "GlobalListens.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "GlobalListens.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + Mobile m = null; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + GetData(m).LoadGlobalListens(reader); + else + (new Data()).LoadGlobalListens(reader); + } + } + } + + public static void LoadMsgs() + { + if (!File.Exists(Path.Combine(General.SavePath, "Pms.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "Pms.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + Mobile m = null; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + GetData(m).LoadMsgs(reader); + else + (new Data()).LoadMsgs(reader); + } + } + } + + private static void CleanUpData() + { + Data data = null; + foreach (Mobile m in new ArrayList(s_Datas.Keys)) + { + data = (Data)s_Datas[m]; + + if (m.Deleted || data.Mobile == null || data.Mobile.Deleted) + s_Datas.Remove(data.Mobile); + else if (data.Mobile.Player && data.Mobile.Account != null && ((Account)data.Mobile.Account).LastLogin < DateTime.Now - TimeSpan.FromDays(30)) + s_Datas.Remove(data.Mobile); + } + } + + #endregion + + #region Static Definitions + + private static Hashtable s_Datas = new Hashtable(); + private static ArrayList s_Notifications = new ArrayList(); + private static ArrayList s_MultiBlocks = new ArrayList(); + private static ArrayList s_Filters = new ArrayList(); + private static ArrayList s_IrcList = new ArrayList(); + private static FilterPenalty s_FilterPenalty; + private static MacroPenalty s_MacroPenalty; + private static int s_MaxMsgs = 50; + private static int s_ChatSpam = 2; + private static int s_MsgSpam = 5; + private static int s_RequestSpam = 24; + private static int s_FilterBanLength = 5; + private static int s_FilterWarnings = 3; + private static int s_AntiMacroDelay = 60; + private static int s_IrcPort = 6667; + private static int s_IrcMaxAttempts = 3; + private static int s_MultiPort = 8112; + private static ulong s_TotalChats; + private static bool s_IrcEnabled = false; + private static bool s_IrcAutoConnect = false; + private static bool s_IrcAutoReconnect = false; + private static bool s_MultiMaster = false; + private static bool s_FilterSpeech = false; + private static bool s_FilterMsg = false; + private static bool s_Debug = false; + private static bool s_LogChat = false; + private static bool s_LogPms = false; + private static IrcColor s_IrcStaffColor = IrcColor.Black; + private static string s_IrcServer = ""; + private static string s_IrcRoom = ""; + private static string s_IrcNick = Server.Misc.ServerList.ServerName; + private static string s_MultiServer = "127.0.0.1"; + + public static Hashtable Datas { get { return s_Datas; } } + public static ArrayList Notifications { get { return s_Notifications; } } + public static ArrayList MultiBlocks { get { return s_MultiBlocks; } } + public static ArrayList Filters { get { return s_Filters; } } + public static ArrayList IrcList { get { return s_IrcList; } } + public static FilterPenalty FilterPenalty { get { return s_FilterPenalty; } set { s_FilterPenalty = value; } } + public static MacroPenalty MacroPenalty { get { return s_MacroPenalty; } set { s_MacroPenalty = value; } } + public static int MaxMsgs { get { return s_MaxMsgs; } set { s_MaxMsgs = value; } } + public static int ChatSpam { get { return s_ChatSpam; } set { s_ChatSpam = value; } } + public static int MsgSpam { get { return s_MsgSpam; } set { s_MsgSpam = value; } } + public static int RequestSpam { get { return s_RequestSpam; } set { s_RequestSpam = value; } } + public static int FilterBanLength { get { return s_FilterBanLength; } set { s_FilterBanLength = value; } } + public static int FilterWarnings { get { return s_FilterWarnings; } set { s_FilterWarnings = value; } } + public static int AntiMacroDelay { get { return s_AntiMacroDelay; } set { s_AntiMacroDelay = value; } } + public static int IrcPort { get { return s_IrcPort; } set { s_IrcPort = value; } } + public static int IrcMaxAttempts { get { return s_IrcMaxAttempts; } set { s_IrcMaxAttempts = value; } } + public static int MultiPort { get { return s_MultiPort; } set { s_MultiPort = value; } } + public static ulong TotalChats { get { return s_TotalChats; } set { s_TotalChats = value; } } + public static bool IrcAutoConnect { get { return s_IrcAutoConnect; } set { s_IrcAutoConnect = value; } } + public static bool IrcAutoReconnect { get { return s_IrcAutoReconnect; } set { s_IrcAutoReconnect = value; } } + public static bool FilterSpeech { get { return s_FilterSpeech; } set { s_FilterSpeech = value; } } + public static bool FilterMsg { get { return s_FilterMsg; } set { s_FilterMsg = value; } } + public static bool Debug { get { return s_Debug; } set { s_Debug = value; } } + public static bool LogChat { get { return s_LogChat; } set { s_LogChat = value; } } + public static bool LogPms { get { return s_LogPms; } set { s_LogPms = value; } } + public static string IrcServer { get { return s_IrcServer; } set { s_IrcServer = value; } } + public static string IrcNick { get { return s_IrcNick; } set { s_IrcNick = value; } } + public static string MultiServer { get { return s_MultiServer; } set { s_MultiServer = value; } } + + public static bool IrcEnabled + { + get { return s_IrcEnabled; } + set + { + s_IrcEnabled = value; + if (!value) + { + IrcConnection.Connection.CancelConnect(); + IrcConnection.Connection.Disconnect(false); + } + } + } + + public static bool MultiMaster + { + get { return s_MultiMaster; } + set + { + s_MultiMaster = value; + if (!value) + { + MultiConnection.Connection.CloseMaster(); + MultiConnection.Connection.CloseSlave(); + } + } + } + + public static IrcColor IrcStaffColor + { + get { return s_IrcStaffColor; } + set + { + if ((int)value > 15) + value = (IrcColor)0; + + if ((int)value < 0) + value = (IrcColor)15; + + s_IrcStaffColor = value; + } + } + + public static Data GetData(Mobile m) + { + if (s_Datas[m] == null) + return new Data(m); + + return (Data)s_Datas[m]; + } + + public static string IrcRoom + { + get { return s_IrcRoom; } + set + { + s_IrcRoom = value; + + if (s_IrcRoom.IndexOf("#") != 0) + s_IrcRoom = "#" + s_IrcRoom; + } + } + + #endregion + + #region Class Definitions + + private Mobile c_Mobile; + private Channel c_CurrentChannel; + private OnlineStatus c_Status; + private Skin c_MenuSkin; + private object c_Recording; + private ArrayList c_Friends, c_Ignores, c_Messages, c_GIgnores, c_GListens, c_IrcIgnores; + private Hashtable c_Sounds; + private int c_GlobalMC, c_GlobalCC, c_GlobalGC, c_GlobalFC, c_GlobalWC, c_SystemC, c_MultiC, c_MsgC, c_PerPage, c_DefaultSound, c_StaffC, c_Avatar, c_Karma, c_Warnings; + private bool c_GlobalAccess, c_Global, c_GlobalM, c_GlobalC, c_GlobalG, c_GlobalF, c_GlobalW, c_Banned, c_FriendsOnly, c_MsgSound, c_ByRequest, c_FriendAlert, c_SevenDays, c_WhenFull, c_ReadReceipt, c_IrcRaw, c_QuickBar, c_ExtraPm; + private string c_AwayMsg, c_Signature; + private DateTime c_BannedUntil, c_LastKarma; + + public Mobile Mobile { get { return c_Mobile; } } + public Channel CurrentChannel { get { return c_CurrentChannel; } set { c_CurrentChannel = value; } } + public OnlineStatus Status { get { return c_Status; } set { c_Status = value; } } + public Skin MenuSkin { get { return c_MenuSkin; } set { c_MenuSkin = value; } } + public object Recording{ get{ return c_Recording; } set{ c_Recording = value; } } + public ArrayList Friends { get { return c_Friends; } } + public ArrayList Ignores { get { return c_Ignores; } } + public ArrayList Messages { get { return c_Messages; } } + public ArrayList GIgnores { get { return c_GIgnores; } } + public ArrayList GListens { get { return c_GListens; } } + public ArrayList IrcIgnores { get { return c_IrcIgnores; } } + public bool Global { get { return c_Global; } set { c_Global = value; } } + public bool GlobalM { get { return c_GlobalM && c_Global; } set { c_GlobalM = value; } } + public bool GlobalC { get { return c_GlobalC && c_Global; } set { c_GlobalC = value; } } + public bool GlobalG { get { return c_GlobalG && c_Global; } set { c_GlobalG = value; } } + public bool GlobalF { get { return c_GlobalF && c_Global; } set { c_GlobalF = value; } } + public bool GlobalW { get { return c_GlobalW && c_Global; } set { c_GlobalW = value; } } + public bool FriendsOnly { get { return c_FriendsOnly; } set { c_FriendsOnly = value; } } + public bool MsgSound { get { return c_MsgSound; } set { c_MsgSound = value; } } + public bool ByRequest { get { return c_ByRequest; } set { c_ByRequest = value; } } + public bool FriendAlert { get { return c_FriendAlert; } set { c_FriendAlert = value; } } + public bool SevenDays { get { return c_SevenDays; } set { c_SevenDays = value; } } + public bool WhenFull { get { return c_WhenFull; } set { c_WhenFull = value; } } + public bool ReadReceipt { get { return c_ReadReceipt; } set { c_ReadReceipt = value; } } + public bool IrcRaw { get { return c_IrcRaw; } set { c_IrcRaw = value; } } + public bool QuickBar { get { return c_QuickBar; } set { c_QuickBar = value; } } + public bool ExtraPm { get { return c_ExtraPm; } set { c_ExtraPm = value; } } + public int GlobalMC { get { return c_GlobalMC; } set { c_GlobalMC = value; } } + public int GlobalCC { get { return c_GlobalCC; } set { c_GlobalCC = value; } } + public int GlobalGC { get { return c_GlobalGC; } set { c_GlobalGC = value; } } + public int GlobalFC { get { return c_GlobalFC; } set { c_GlobalFC = value; } } + public int GlobalWC { get { return c_GlobalWC; } set { c_GlobalWC = value; } } + public int SystemC { get { return c_SystemC; } set { c_SystemC = value; } } + public int MultiC { get { return c_MultiC; } set { c_MultiC = value; } } + public int MsgC { get { return c_MsgC; } set { c_MsgC = value; } } + public int StaffC { get { return c_StaffC; } set { c_StaffC = value; } } + public int Avatar { get { return c_Avatar; } set { c_Avatar = value; } } + public int Warnings { get { return c_Warnings; } set { c_Warnings = value; } } + public string AwayMsg { get { return c_AwayMsg; } set { c_AwayMsg = value; } } + public string Signature { get { return c_Signature; } set { c_Signature = value; c_Mobile.SendMessage(c_SystemC, General.Local(246));} } + + public int Karma + { + get { return c_Karma; } + set + { + if (c_LastKarma + TimeSpan.FromHours(24) > DateTime.Now) + return; + + c_Karma = value; + c_LastKarma = DateTime.Now; + } + } + + public int PerPage + { + get { return c_PerPage; } + set + { + c_PerPage = value; + + if (c_PerPage < 5) + c_PerPage = 5; + if (c_PerPage > 15) + c_PerPage = 15; + } + } + + public int DefaultSound + { + get { return c_DefaultSound; } + set + { + foreach (Mobile m in c_Sounds.Keys) + if ((int)c_Sounds[m] == c_DefaultSound) + c_Sounds[m] = value; + + c_DefaultSound = value; + + if (c_DefaultSound < 0) + c_DefaultSound = 0; + } + } + + public bool GlobalAccess + { + get { return c_GlobalAccess || c_Mobile.AccessLevel >= AccessLevel.Administrator; } + set + { + c_GlobalAccess = value; + + if (value) + c_Mobile.SendMessage(c_SystemC, General.Local(92)); + else + c_Mobile.SendMessage(c_SystemC, General.Local(93)); + } + } + + public bool Banned + { + get{ return c_Banned; } + set + { + c_Banned = value; + + if (value) + c_Mobile.SendMessage(c_SystemC, General.Local(90)); + else + c_Mobile.SendMessage(c_SystemC, General.Local(91)); + } + } + + public int DefaultBack + { + get + { + switch (c_MenuSkin) + { + case Skin.Three: + return 0x1400; + case Skin.Two: + return 0x13BE; + default: + return 0xE10; + } + } + } + + #endregion + + #region Constructors + + public Data(Mobile m) + { + c_Mobile = m; + + c_Friends = new ArrayList(); + c_Ignores = new ArrayList(); + c_Messages = new ArrayList(); + c_GIgnores = new ArrayList(); + c_GListens = new ArrayList(); + c_IrcIgnores = new ArrayList(); + c_Sounds = new Hashtable(); + c_PerPage = 10; + c_SystemC = 0x161; + c_GlobalMC = 0x26; + c_GlobalCC = 0x47E; + c_GlobalGC = 0x44; + c_GlobalFC = 0x17; + c_GlobalWC = 0x3; + c_StaffC = 0x3B4; + c_MsgC = 0x480; + c_AwayMsg = ""; + c_Signature = ""; + c_BannedUntil = DateTime.Now; + + if (m.AccessLevel >= AccessLevel.Administrator) + c_GlobalAccess = true; + + s_Datas[m] = this; + + foreach (Channel c in Channel.Channels) + if (c.NewChars) + c.Join(m); + } + + public Data() + { + c_Friends = new ArrayList(); + c_Ignores = new ArrayList(); + c_Messages = new ArrayList(); + c_GIgnores = new ArrayList(); + c_GListens = new ArrayList(); + c_IrcIgnores = new ArrayList(); + c_Sounds = new Hashtable(); + c_PerPage = 10; + c_SystemC = 0x161; + c_GlobalMC = 0x26; + c_GlobalCC = 0x47E; + c_GlobalGC = 0x44; + c_GlobalFC = 0x17; + c_GlobalWC = 0x3; + c_StaffC = 0x3B4; + c_MsgC = 0x480; + c_AwayMsg = ""; + c_Signature = ""; + c_BannedUntil = DateTime.Now; + } + + #endregion + + #region Methods + + public bool NewMsg() + { + foreach (Message msg in c_Messages) + if (!msg.Read) + return true; + + return false; + } + + public bool NewMsgFrom(Mobile m) + { + foreach (Message msg in c_Messages) + if (!msg.Read && msg.From == m) + return true; + + return false; + } + + public Message GetNewMsgFrom(Mobile m) + { + foreach (Message msg in c_Messages) + if (!msg.Read && msg.From == m) + return msg; + + return null; + } + + public void CheckMsg() + { + foreach( Message msg in c_Messages ) + if (!msg.Read) + { + new MessageGump(c_Mobile, msg); + return; + } + } + + public Message GetMsg() + { + if (c_Messages.Count == 0) + return null; + + return (Message)c_Messages[c_Messages.Count - 1]; + } + + public void CheckMsgFrom(Mobile m) + { + foreach(Message msg in c_Messages) + if (!msg.Read && msg.From == m) + { + new MessageGump(c_Mobile, msg); + return; + } + } + + public int GetSound(Mobile m) + { + if (c_Sounds[m] == null) + c_Sounds[m] = c_DefaultSound; + + return (int)c_Sounds[m]; + } + + public void SetSound(Mobile m, int num) + { + if (num < 0) + num = 0; + + c_Sounds[m] = num; + } + + public void AddFriend(Mobile m) + { + if (c_Friends.Contains(m) || m == c_Mobile) + return; + + c_Friends.Add(m); + c_Mobile.SendMessage(c_SystemC, m.Name + " " + General.Local(73)); + } + + public void RemoveFriend(Mobile m) + { + if (!c_Friends.Contains(m)) + return; + + c_Friends.Remove(m); + c_Mobile.SendMessage(c_SystemC, m.Name + " " + General.Local(72)); + } + + public void AddIgnore(Mobile m) + { + if (c_Mobile == m) + return; + + if (c_Ignores.Contains(m) || m == c_Mobile) + return; + + c_Ignores.Add(m); + c_Mobile.SendMessage(c_SystemC, General.Local(68) + " " + m.Name); + } + + public void RemoveIgnore(Mobile m) + { + if (!c_Ignores.Contains(m)) + return; + + c_Ignores.Remove(m); + c_Mobile.SendMessage(c_SystemC, General.Local(74) + " " + m.Name); + } + + public void AddGIgnore(Mobile m) + { + if (c_GIgnores.Contains(m)) + return; + + c_GIgnores.Add(m); + c_Mobile.SendMessage(c_SystemC, General.Local(80) + " " + m.Name); + } + + public void RemoveGIgnore(Mobile m) + { + if (!c_GIgnores.Contains(m)) + return; + + c_GIgnores.Remove(m); + c_Mobile.SendMessage(c_SystemC, General.Local(79) + " " + m.Name); + } + + public void AddGListen(Mobile m) + { + if (c_GListens.Contains(m)) + return; + + c_GListens.Add(m); + c_Mobile.SendMessage(c_SystemC, General.Local(82) + " " + m.Name); + } + + public void RemoveGListen(Mobile m) + { + if (!c_GListens.Contains(m)) + return; + + c_GListens.Remove(m); + c_Mobile.SendMessage(c_SystemC, General.Local(81) + " " + m.Name); + } + + public void AddIrcIgnore(string str) + { + if (c_IrcIgnores.Contains(str)) + return; + + c_IrcIgnores.Add(str); + c_Mobile.SendMessage(c_SystemC, General.Local(68) + " " + str); + } + + public void RemoveIrcIgnore(string str) + { + if (!c_IrcIgnores.Contains(str)) + return; + + c_IrcIgnores.Remove(str); + c_Mobile.SendMessage(c_SystemC, General.Local(74) + " " + str); + } + + public void AddMessage(Message msg) + { + c_Messages.Add(msg); + + if(c_MsgSound) + c_Mobile.SendSound(GetSound(msg.From)); + + if (c_WhenFull && c_Messages.Count > s_MaxMsgs) + c_Messages.RemoveAt(0); + } + + public void DeleteMessage(Message msg) + { + c_Messages.Remove(msg); + + c_Mobile.SendMessage(c_SystemC, General.Local(69)); + } + + public void Ban(TimeSpan ts) + { + c_BannedUntil = DateTime.Now + ts; + c_Banned = true; + Mobile.SendMessage(c_SystemC, General.Local(90)); + + Timer.DelayCall(ts, new TimerCallback(RemoveBan)); + } + + public void RemoveBan() + { + c_BannedUntil = DateTime.Now; + c_Banned = false; + if(Mobile != null) + Mobile.SendMessage(c_SystemC, General.Local(91)); + } + + public void AvatarUp() + { + if (c_Avatar == 0) + { + c_Avatar = (int)Chat3.Avatar.AvaKeys[0]; + return; + } + + ArrayList list = new ArrayList(Chat3.Avatar.AvaKeys); + + for (int i = 0; i < list.Count; ++i) + if (c_Avatar == (int)list[i]) + { + if (i == list.Count - 1) + { + c_Avatar = (int)list[0]; + return; + } + + c_Avatar = (int)list[i + 1]; + return; + } + } + + public void AvatarDown() + { + if (c_Avatar == 0) + { + c_Avatar = (int)Chat3.Avatar.AvaKeys[0]; + return; + } + + ArrayList list = new ArrayList(Chat3.Avatar.AvaKeys); + + for (int i = 0; i < list.Count; ++i) + if (c_Avatar == (int)list[i]) + { + if (i == 0) + { + c_Avatar = (int)list[list.Count - 1]; + return; + } + + c_Avatar = (int)list[i - 1]; + return; + } + } + + public void SaveOptions(GenericWriter writer) + { + writer.Write(3); // Version + + writer.Write(c_MultiC); + + writer.Write(c_Karma); + + writer.Write(c_ReadReceipt); + writer.Write(c_QuickBar); + writer.Write(c_ExtraPm); + writer.Write((int)c_Status); + + foreach (Mobile m in new ArrayList(c_Sounds.Keys)) + if (m.Deleted) + c_Sounds.Remove(m); + + writer.Write(c_Sounds.Count); + foreach (Mobile m in c_Sounds.Keys) + { + writer.Write(m); + writer.Write((int)c_Sounds[m]); + } + + writer.Write(c_GlobalMC); + writer.Write(c_GlobalCC); + writer.Write(c_GlobalGC); + writer.Write(c_GlobalFC); + writer.Write(c_GlobalWC); + writer.Write(c_SystemC); + writer.Write(c_MsgC); + writer.Write(c_PerPage); + writer.Write(c_DefaultSound); + writer.Write(c_StaffC); + writer.Write(c_Avatar); + writer.Write((int)c_MenuSkin); + writer.Write(c_GlobalAccess); + writer.Write(c_Global); + writer.Write(c_GlobalM); + writer.Write(c_GlobalC); + writer.Write(c_GlobalG); + writer.Write(c_GlobalF); + writer.Write(c_GlobalW); + writer.Write(c_Banned); + writer.Write(c_FriendsOnly); + writer.Write(c_MsgSound); + writer.Write(c_ByRequest); + writer.Write(c_FriendAlert); + writer.Write(c_SevenDays); + writer.Write(c_WhenFull); + writer.Write(c_IrcRaw); + writer.Write(c_AwayMsg); + writer.Write(c_Signature); + writer.Write(c_BannedUntil); + } + + public void SaveFriends(GenericWriter writer) + { + writer.Write(1); // Version + + writer.WriteMobileList(c_Friends, true); + } + + public void SaveIgnores(GenericWriter writer) + { + writer.Write(1); // Version + + writer.WriteMobileList(c_Ignores, true); + } + + public void SaveMsgs(GenericWriter writer) + { + writer.Write(1); // Version + + foreach (Message msg in new ArrayList(c_Messages)) + if (msg.From.Deleted ) + c_Messages.Remove(msg); + + writer.Write(c_Messages.Count); + foreach (Message msg in c_Messages) + msg.Save(writer); + } + + public void SaveGlobalListens(GenericWriter writer) + { + writer.Write(1); // Version + + writer.WriteMobileList(c_GIgnores, true); + writer.WriteMobileList(c_GListens, true); + } + + public void LoadOptions(GenericReader reader) + { + int version = reader.ReadInt(); + + if (version >= 3) + c_MultiC = reader.ReadInt(); + if (version >= 2) + c_Karma = reader.ReadInt(); + + c_ReadReceipt = reader.ReadBool(); + c_QuickBar = reader.ReadBool(); + c_ExtraPm = reader.ReadBool(); + c_Status = (OnlineStatus)reader.ReadInt(); + + Mobile m; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + m = reader.ReadMobile(); + if (m != null) + c_Sounds[m] = reader.ReadInt(); + else + reader.ReadInt(); + } + + c_GlobalMC = reader.ReadInt(); + c_GlobalCC = reader.ReadInt(); + c_GlobalGC = reader.ReadInt(); + c_GlobalFC = reader.ReadInt(); + c_GlobalWC = reader.ReadInt(); + c_SystemC = reader.ReadInt(); + c_MsgC = reader.ReadInt(); + c_PerPage = reader.ReadInt(); + c_DefaultSound = reader.ReadInt(); + c_StaffC = reader.ReadInt(); + c_Avatar = reader.ReadInt(); + c_MenuSkin = (Skin)reader.ReadInt(); + c_GlobalAccess = reader.ReadBool(); + c_Global = reader.ReadBool(); + c_GlobalM = reader.ReadBool(); + c_GlobalC = reader.ReadBool(); + c_GlobalG = reader.ReadBool(); + c_GlobalF = reader.ReadBool(); + c_GlobalW = reader.ReadBool(); + c_Banned = reader.ReadBool(); + c_FriendsOnly = reader.ReadBool(); + c_MsgSound = reader.ReadBool(); + c_ByRequest = reader.ReadBool(); + c_FriendAlert = reader.ReadBool(); + c_SevenDays = reader.ReadBool(); + c_WhenFull = reader.ReadBool(); + c_IrcRaw = reader.ReadBool(); + c_AwayMsg = reader.ReadString(); + c_Signature = reader.ReadString(); + c_BannedUntil = reader.ReadDateTime(); + + if (c_BannedUntil > DateTime.Now) + Ban(c_BannedUntil - DateTime.Now); + else + RemoveBan(); + } + + public void LoadFriends(GenericReader reader) + { + int version = reader.ReadInt(); + + c_Friends = reader.ReadMobileList(); + } + + public void LoadIgnores(GenericReader reader) + { + int version = reader.ReadInt(); + + c_Ignores = reader.ReadMobileList(); + } + + public void LoadMsgs(GenericReader reader) + { + int version = reader.ReadInt(); + + Message msg; + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + { + msg = new Message(); + msg.Load(reader); + + if (msg.From != null ) + c_Messages.Add(msg); + } + } + + public void LoadGlobalListens(GenericReader reader) + { + int version = reader.ReadInt(); + + c_GIgnores = reader.ReadMobileList(); + c_GListens = reader.ReadMobileList(); + } + + #endregion + + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/DefaultLocal.cs b/Scripts/Customs/KniveChat/General/DefaultLocal.cs new file mode 100644 index 0000000..e15590a --- /dev/null +++ b/Scripts/Customs/KniveChat/General/DefaultLocal.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections; + +namespace Knives.Chat3 +{ + public class DefaultLocal + { + public static ArrayList Load() + { + ArrayList list = new ArrayList(); + + list.Add("Friend"); + list.Add("Views"); + list.Add("Ignore"); + list.Add("Remove Ignore"); + list.Add("Grant Global"); + list.Add("Revoke Global"); + list.Add("Ban"); + list.Add("Remove Ban"); + list.Add("Global Ignore"); + list.Add("Global Unignore"); + list.Add("Listen"); + list.Add("Remove Listen"); + list.Add("Set your away message"); + list.Add("Send Message"); + list.Add("Become User"); + list.Add("Client"); + list.Add("Goto"); + list.Add("Message Sound"); + list.Add("Friend and Messaging Options"); + list.Add("Online"); + list.Add("Away"); + list.Add("Busy"); + list.Add("Hidden"); + list.Add("You must unhide to see the player list"); + list.Add("Only friends can send messages"); + list.Add("Require friend requests"); + list.Add("Global Messages"); + list.Add("Sound on message receive"); + list.Add("Default Message Sound"); + list.Add("Friends speech shortcut"); + list.Add("Friend online alert"); + list.Add("Please select a channel to view"); + list.Add("Friends"); + list.Add("You are banned from chat"); + list.Add("You must join the channel first"); + list.Add("You are not in a chatting region"); + list.Add("You are not in a guild"); + list.Add("You are not in a faction"); + list.Add("Channels"); + list.Add("General Channel Options"); + list.Add("Options"); + list.Add("Channels speech shortcut"); + list.Add("Commands"); + list.Add("Global"); + list.Add("Global Chat"); + list.Add("Global World"); + list.Add("View All"); + list.Add("System Color"); + list.Add("Staff Color"); + list.Add("Color"); + list.Add("Channel"); + list.Add("Ignores"); + list.Add("GIgnores"); + list.Add("GListens"); + list.Add("Bans"); + list.Add("Display"); + list.Add("Mail"); + list.Add("Mail and Messaging Options"); + list.Add("Auto delete week old messages"); + list.Add("Mail speech shortcut"); + list.Add("from"); + list.Add("You must target a book"); + list.Add("Message to"); + list.Add("Recording. Press send when finished."); + list.Add("Recording stopped"); + list.Add("Now recording. Everything you enter on the command line will appear in the message."); + list.Add("You must have a message to send"); + list.Add("Message sent to"); + list.Add("You are now ignoring"); + list.Add("You delete the message"); + list.Add("Speech command set to"); + list.Add("Speech command cleared"); + list.Add("is no longer on your friend list"); + list.Add("is now on your friend list"); + list.Add("You are no longer ignoring"); + list.Add("now has global listening access"); + list.Add("no longer has global access"); + list.Add("You ban"); + list.Add("You lift the ban from"); + list.Add("You are no longer global ignoring"); + list.Add("You are now global ignoring"); + list.Add("You are no longer globally listening to"); + list.Add("You are now globally listening to"); + list.Add("is no longer online"); + list.Add("Friend Request"); + list.Add("Do you want to add this player as a friend?"); + list.Add("You have sent a friend request to"); + list.Add("has accepted your friend request"); + list.Add("has denied your friend request"); + list.Add("You deny"); + list.Add("You are now banned from chat"); + list.Add("Your chat ban has been lifted"); + list.Add("You've been granted global access"); + list.Add("Your global access has been revoked"); + list.Add("Broadcast to all"); + list.Add("Broadcast"); + list.Add("You can send another request in"); + list.Add("You must wait a few moments between messages"); + list.Add("Enable IRC"); + list.Add("Filter and Spam Options"); + list.Add("IRC Options"); + list.Add("Misc Options"); + list.Add("The server is already attempting to connect"); + list.Add("The server is already connected"); + list.Add("IRC connection failed"); + list.Add("Attempting to connect..."); + list.Add("Connection could not be established"); + list.Add("Connecting to IRC server..."); + list.Add("Server is now connected to IRC channel"); + list.Add("IRC names list updating"); + list.Add("IRC connection down"); + list.Add("Filter violation detected:"); + list.Add("Too many search results, be more specific"); + list.Add("No matching names found"); + list.Add("Select a name"); + list.Add("Auto Connect"); + list.Add("Auto Reconnect"); + list.Add("Nickname"); + list.Add("Server"); + list.Add("Room"); + list.Add("Port"); + list.Add("White"); + list.Add("Black"); + list.Add("Blue"); + list.Add("Green"); + list.Add("Light Red"); + list.Add("Brown"); + list.Add("Purple"); + list.Add("Orange"); + list.Add("Yellow"); + list.Add("Light Green"); + list.Add("Cyan"); + list.Add("Light Cyan"); + list.Add("Light Blue"); + list.Add("Pink"); + list.Add("Grey"); + list.Add("Light Grey"); + list.Add("Select a Color"); + list.Add("Staff Color"); + list.Add("Connect"); + list.Add("Cancel Connect"); + list.Add("Close Connection"); + list.Add("Apply filter to world speech"); + list.Add("Apply filter to private messages"); + list.Add("Chat Spam"); + list.Add("Pm Spam"); + list.Add("Request Spam"); + list.Add("Filter Ban"); + list.Add("Add/Remove Filter"); + list.Add("You remove the filter:"); + list.Add("You add the filter:"); + list.Add("Filters:"); + list.Add("Show staff in channel lists"); + list.Add("Max Mailbox Size"); + list.Add("Filter Penalty"); + list.Add("None"); + list.Add("Ban"); + list.Add("Jail"); + list.Add("IRC connection is down"); + list.Add("IRC Raw"); + list.Add("Select Ban Time"); + list.Add("30 minutes"); + list.Add("1 hour"); + list.Add("12 hours"); + list.Add("1 day"); + list.Add("1 week"); + list.Add("1 month"); + list.Add("1 year"); + list.Add("Local file reloaded"); + list.Add("Reload localized text file"); + list.Add("days"); + list.Add("hours"); + list.Add("minutes"); + list.Add("is now online"); + list.Add("Error loading global options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving global options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error filtering text. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Channel Options"); + list.Add("New Channel"); + list.Add("Please select a channel"); + list.Add("Name"); + list.Add("Style"); + list.Add("Global"); + list.Add("Regional"); + list.Add("Send Chat to IRC"); + list.Add("Add/Remove Command"); + list.Add("Error loading channel information. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving channel information. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Auto join new players"); + list.Add("You have left the channel"); + list.Add("You have joined the channel"); + list.Add("You must be staff to chat here"); + list.Add("Global Guild"); + list.Add("Global Faction"); + list.Add("The message needs a subject before you can begin recording"); + list.Add("Quick Bar"); + list.Add("Message Read Receipts"); + list.Add("has read"); + list.Add("Error loading gump information. Details on the RunUO Console. Please report to Knives at kmwill23@hotmail.com"); + list.Add("Error saving gump information. Details on the RunUO Console. Please report to Knives at kmwill23@hotmail.com"); + list.Add("Errors reported by either this chat system or other staff members! Administrators have the power to clear this list. All staff members can report an error using the [chaterrors command."); + list.Add("Chat Error Log"); + list.Add("Clear"); + list.Add("Friends"); + list.Add("Global Ignores"); + list.Add("Global Listens"); + list.Add("History"); + list.Add("General"); + list.Add("Filter"); + list.Add("Spam"); + list.Add("Irc"); + list.Add("Delete Channel"); + list.Add("Enable Channel"); + list.Add("This channel is disabled"); + list.Add("Filter Options"); + list.Add("Spam Options"); + list.Add("Colors"); + list.Add("Mail Options"); + list.Add("Your mailbox is full, please delete some messages so others may send to you."); + list.Add("Press the button above to select a channel. When adding commands, do not include the command prefix."); + list.Add("Delay"); + list.Add("General Options"); + list.Add("Debug"); + list.Add("Show Staff"); + list.Add("Viewing"); + list.Add("You cannot send messages while under another user's identity."); + list.Add("Global Options"); + list.Add("Error loading player options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving player options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error loading friends. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving friends. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error loading ignores. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving ignores. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error loading global listens. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving global listens. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error loading private messages. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Error saving private messages. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com"); + list.Add("Logging"); + list.Add("Log Chat"); + list.Add("Log Pms"); + list.Add("Chat save completed in"); + list.Add("Chat information saving..."); + list.Add("The background you set will now be forced on all players."); + list.Add("Players can now set their own backgrounds."); + list.Add("Clear"); + list.Add("Submit"); + list.Add("Signature updated"); + list.Add("Your signature:"); + list.Add("Reply"); + list.Add("Delete"); + list.Add("Accept"); + list.Add("Deny"); + list.Add("Send"); + list.Add("Chat Karma:"); + list.Add("Filter Warnings"); + list.Add("You can't chat while squelched."); + list.Add("Broadcast to Staff"); + list.Add("Staff"); + list.Add("You have {0} of max {1} in your mailbox."); + list.Add("Auto-delete old when mailbox full"); + list.Add("You are squelched and cannot chat."); + list.Add("Staff Announcement"); + list.Add("To use help, simply enter a word in the search line and all topics matching will pop up here!"); + list.Add("Your search returned no results."); + list.Add(" results"); + list.Add(" result"); + list.Add("Error reported in connecting IRC. More information is available on the console."); + list.Add("Error reported in handling IRC input. More information is available on the console."); + list.Add("Error reported in disconnecting IRC. More information is available on the console."); + list.Add("Notifications"); + list.Add("New Notification"); + list.Add("Automated System Message"); + list.Add("Text"); + list.Add("Gump"); + list.Add("Set Recur Time"); + list.Add("Anti-Macro check"); + list.Add("You have been flagged for violating afk macroing rules."); + list.Add("Afk Macroing"); + list.Add(" has been flagged for violating afk macroing rules."); + list.Add("You have been kicked for violating afk macroing rules."); + list.Add("Macro Penalty"); + list.Add("Kick"); + list.Add("Delay before penalty"); + list.Add("Multi Server Chat"); + list.Add("Run Multi Server"); + list.Add("Multi Server"); + list.Add("Start Server"); + list.Add("Multi"); + list.Add("Error connecting to master server."); + list.Add("Connected to master server."); + list.Add("Disconnecting from master server."); + list.Add(" has disconnected."); + list.Add(" has connected."); + list.Add("Reload Help Contents"); + list.Add("Help contents reloaded"); + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Events.cs b/Scripts/Customs/KniveChat/General/Events.cs new file mode 100644 index 0000000..863fb14 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Events.cs @@ -0,0 +1,99 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public delegate void ChatEventHandler(ChatEventArgs e); + public delegate void FilterViolationEventHandler(FilterViolationEventArgs e); + public delegate void ErrorEventHandler(ErrorEventArgs e); + public delegate void GumpCreatedEventHandler(GumpCreatedEventArgs e); + + public class ChatEventArgs : EventArgs + { + private Mobile c_Mobile; + public Mobile Mobile { get { return c_Mobile; } } + + private Channel c_Channel; + public Channel Channel { get { return c_Channel; } } + + private string c_Speech; + public string Speech { get { return c_Speech; } } + + public ChatEventArgs(Mobile m, Channel c, string txt) + { + c_Mobile = m; + c_Channel = c; + c_Speech = txt; + } + } + + public class FilterViolationEventArgs : EventArgs + { + private Mobile c_Mobile; + public Mobile Mobile { get { return c_Mobile; } } + + public FilterViolationEventArgs(Mobile m) + { + c_Mobile = m; + } + } + + public class ErrorEventArgs : EventArgs + { + private string c_Text; + public string Text { get { return c_Text; } } + + public ErrorEventArgs(string txt) + { + c_Text = txt; + } + } + + public class GumpCreatedEventArgs : EventArgs + { + private Mobile c_Mobile; + public Mobile Mobile { get { return c_Mobile; } } + + private GumpPlus c_Gump; + public GumpPlus Gump { get { return c_Gump; } } + + public GumpCreatedEventArgs(Mobile m, GumpPlus g) + { + c_Mobile = m; + c_Gump = g; + } + } + + public class Events + { + public static event ChatEventHandler Chat; + public static event FilterViolationEventHandler FilterViolation; + public static event ErrorEventHandler Error; + public static event GumpCreatedEventHandler GumpCreated; + + public static void InvokeChat(ChatEventArgs args) + { + if (Chat != null) + Chat(args); + } + + public static void InvokeFilterViolation(FilterViolationEventArgs args) + { + if (FilterViolation != null) + FilterViolation(args); + } + + public static void InvokeError(ErrorEventArgs args) + { + if (Error != null) + Error(args); + } + + public static void InvokeGumpCreated(GumpCreatedEventArgs args) + { + if (GumpCreated != null) + GumpCreated(args); + } + } + +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Filter.cs b/Scripts/Customs/KniveChat/General/Filter.cs new file mode 100644 index 0000000..c0d5137 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Filter.cs @@ -0,0 +1,80 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public enum FilterPenalty { None, Ban, Jail } + + public class Filter + { + public static string FilterText(Mobile m, string s) + { + return FilterText(m, s, true); + } + + public static string FilterText(Mobile m, string s, bool punish) + { + try + { + string filter = ""; + string subOne = ""; + string subTwo = ""; + string subThree = ""; + int index = 0; + + for (int i = 0; i < Data.Filters.Count; ++i) + { + filter = Data.Filters[i].ToString(); + + if (filter == "") + { + Data.Filters.Remove(filter); + continue; + } + + index = s.ToLower().IndexOf(filter); + + if (index >= 0) + { + if (m.AccessLevel == AccessLevel.Player && punish) + { + if (++Data.GetData(m).Warnings <= Data.FilterWarnings) + m.SendMessage(Data.GetData(m).SystemC, General.Local(111) + " " + filter); + else + { + Data.GetData(m).Warnings = 0; + + Events.InvokeFilterViolation(new FilterViolationEventArgs(m)); + + if (Data.FilterPenalty == FilterPenalty.Ban) + Data.GetData(m).Ban(TimeSpan.FromMinutes(Data.FilterBanLength)); + + if (Data.FilterPenalty == FilterPenalty.Jail) + ChatJail.SendToJail(m); + + if (Data.FilterPenalty != FilterPenalty.None) + return ""; + } + } + + subOne = s.Substring(0, index); + subTwo = ""; + + for (int ii = 0; ii < filter.Length; ++ii) + subTwo += "*"; + + subThree = s.Substring(index + filter.Length, s.Length - filter.Length - index); + + s = subOne + subTwo + subThree; + + i--; + } + } + + } + catch { Errors.Report(General.Local(176)); } + + return s; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/General.cs b/Scripts/Customs/KniveChat/General/General.cs new file mode 100644 index 0000000..4ca7ef6 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/General.cs @@ -0,0 +1,430 @@ +// Reload help contents + +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Knives.Chat3 +{ + public class General + { + private static string s_Version = "3.0 Beta 9"; + private static string s_SavePath = "Saves/ChatBeta8"; + private static DateTime s_ReleaseDate = new DateTime(2007, 3, 1); + + public static string Version { get { return s_Version; } } + public static string SavePath { get { return s_SavePath; } } + public static DateTime ReleaseDate { get { return s_ReleaseDate; } } + + private static ArrayList s_Locals = new ArrayList(); + + private static Hashtable s_Help = new Hashtable(); + public static Hashtable Help { get { return s_Help; } } + + public static void Configure() + { + EventSink.WorldLoad += new WorldLoadEventHandler(OnLoad); + EventSink.WorldSave += new WorldSaveEventHandler(OnSave); + } + + public static void Initialize() + { + EventSink.Speech += new SpeechEventHandler(OnSpeech); + EventSink.Login += new LoginEventHandler(OnLogin); + EventSink.CharacterCreated += new CharacterCreatedEventHandler(OnCreate); + } + + private static void OnLoad() + { + LoadLocalFile(); + LoadHelpFile(); + LoadFilterFile(); + Data.Load(); + Channel.Load(); + GumpInfo.Load(); + + if (Data.IrcAutoConnect) + IrcConnection.Connection.Connect(); + } + + private static void OnSave(WorldSaveEventArgs args) + { + DateTime time = DateTime.Now; + if (Data.Debug) + { + Console.WriteLine(""); + Console.WriteLine(General.Local(241)); + } + + Data.Save(); + Channel.Save(); + GumpInfo.Save(); + + foreach (Data data in Data.Datas.Values) + if (data.SevenDays) + foreach (Message msg in new ArrayList(data.Messages)) + if (msg.Received < DateTime.Now - TimeSpan.FromDays(7)) + data.Messages.Remove(msg); + + if (Data.Debug) + { + TimeSpan elapsed = DateTime.Now - time; + Console.WriteLine(General.Local(240) + " {0}", (elapsed.Minutes != 0 ? elapsed.Minutes + " minutes" : "") + (elapsed.Seconds != 0 ? elapsed.Seconds + " seconds" : "") + elapsed.Milliseconds + " milliseconds"); + } + } + + private static void OnSpeech(SpeechEventArgs args) + { + if (Data.GetData(args.Mobile).Recording is SendMessageGump) + { + if (!args.Mobile.HasGump(typeof(SendMessageGump))) + { + Data.GetData(args.Mobile).Recording = null; + return; + } + + args.Mobile.CloseGump(typeof(SendMessageGump)); + ((SendMessageGump)Data.GetData(args.Mobile).Recording).AddText(" " + args.Speech); + args.Handled = true; + args.Speech = ""; + return; + } + + if (Data.FilterSpeech) + args.Speech = Filter.FilterText(args.Mobile, args.Speech, false); + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.AccessLevel >= args.Mobile.AccessLevel && ((data.GlobalW && !data.GIgnores.Contains(args.Mobile)) || data.GListens.Contains(args.Mobile)) && !data.Mobile.InRange(args.Mobile.Location, 10)) + data.Mobile.SendMessage(data.GlobalWC, String.Format("(Global) {0}: {1}", args.Mobile.RawName, args.Speech)); + } + + private static void OnLogin(LoginEventArgs args) + { + if (Data.GetData(args.Mobile).NewMsg()) + PmNotify(args.Mobile); + + if(!Data.GetData(args.Mobile).WhenFull) + args.Mobile.SendMessage(Data.GetData(args.Mobile).SystemC, General.Local(258), Data.GetData(args.Mobile).Messages.Count, Data.MaxMsgs); + + foreach (Data data in Data.Datas.Values) + { + if (data.Friends.Contains(args.Mobile) && data.FriendAlert) + data.Mobile.SendMessage(data.SystemC, args.Mobile.RawName + " " + Local(173)); + } + } + + private static void OnCreate(CharacterCreatedEventArgs args) + { + if (args.Mobile == null) + return; + + Data data = Data.GetData(args.Mobile); + + foreach (Channel c in Channel.Channels) + if (c.NewChars) + c.Join(args.Mobile); + } + + public static void LoadLocalFile() + { + s_Locals.Clear(); + + if (File.Exists("Data/ChatLocal.txt")) + { + using (FileStream bin = new FileStream("Data/ChatLocal.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + StreamReader reader = new StreamReader(bin); + string text = ""; + + while (true) + { + try + { + text = reader.ReadLine(); + + if (text.IndexOf("//") == 0 || text.Trim().Length == 0) + continue; + + if (text == "EndOfFile") + break; + + s_Locals.Add(text); + } + catch { break; } + } + + reader.Close(); + } + } + + if (s_Locals.Count == 0) + s_Locals = DefaultLocal.Load(); + } + + public static void LoadHelpFile() + { + s_Help.Clear(); + + if (File.Exists("Data/HelpContents.txt")) + { + using (FileStream bin = new FileStream("Data/HelpContents.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + StreamReader reader = new StreamReader(bin); + string name = ""; + string text = ""; + + while (true) + { + try + { + name = reader.ReadLine(); + + if (name.IndexOf("//") == 0 || name.Trim().Length == 0) + continue; + + if (name == "EndOfFile") + break; + + text = reader.ReadLine(); + + if (text.IndexOf("//") == 0 || text.Trim().Length == 0) + continue; + + if (text == "EndOfFile") + break; + + s_Help[name] = text; + } + catch { break; } + } + + reader.Close(); + } + } + } + + public static string Local(int num) + { + if (num < 0 || num >= s_Locals.Count) + return "Local Error"; + + return s_Locals[num].ToString(); + } + + public static string GetHelp(string str) + { + if (s_Help[str] == null) + return "Help Error"; + + return s_Help[str].ToString(); + } + + public static void LoadFilterFile() + { + if (File.Exists("Data/ChatFilters.txt")) + { + using (FileStream bin = new FileStream("Data/ChatFilters.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + StreamReader reader = new StreamReader(bin); + string text = ""; + + while (true) + { + try + { + text = reader.ReadLine(); + + if (text.IndexOf("//") == 0 || text.Trim().Length == 0) + continue; + + if (text == "EndOfFile") + break; + + if (!Data.Filters.Contains(text.ToLower())) + Data.Filters.Add(text.ToLower()); + } + catch { break; } + } + + reader.Close(); + } + } + } + + public static void LoadBacksFile() + { + if (File.Exists("Data/ChatBacks.txt")) + { + using (FileStream bin = new FileStream("Data/ChatBacks.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + StreamReader reader = new StreamReader(bin); + string text = ""; + + while (true) + { + try + { + text = reader.ReadLine(); + + if (text.IndexOf("//") == 0 || text.Trim().Length == 0) + continue; + + if (text == "EndOfFile") + break; + + if(!GumpInfo.Backgrounds.Contains(Utility.ToInt32(text))) + GumpInfo.Backgrounds.Add(Utility.ToInt32(text)); + } + catch { break; } + } + + reader.Close(); + } + } + } + + public static void LoadColorsFile() + { + if (File.Exists("Data/ChatColors.txt")) + { + using (FileStream bin = new FileStream("Data/ChatColors.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + StreamReader reader = new StreamReader(bin); + string text = ""; + + while (true) + { + try + { + text = reader.ReadLine(); + + if (text.IndexOf("//") == 0 || text.Trim().Length == 0) + continue; + + if (text == "EndOfFile") + break; + + if (!GumpInfo.TextColors.Contains(text)) + GumpInfo.TextColors.Add(text); + } + catch { break; } + } + + reader.Close(); + } + } + } + + public static void LoadAvatarFile() + { + if (File.Exists("Data/ChatAvatars.txt")) + { + using (FileStream bin = new FileStream("Data/ChatAvatars.txt", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + StreamReader reader = new StreamReader(bin); + string id = ""; + string xoff = ""; + string yoff = ""; + + while (true) + { + try + { + id = reader.ReadLine(); + + if (id.IndexOf("//") == 0 || id.Trim().Length == 0) + continue; + + if (id == "EndOfFile") + break; + + xoff = reader.ReadLine(); + yoff = reader.ReadLine(); + + if (!Avatar.Avatars.Contains(Utility.ToInt32(id))) + new Avatar(Utility.ToInt32(id), Utility.ToInt32(xoff), Utility.ToInt32(yoff)); + } + catch { break; } + } + + reader.Close(); + } + } + } + + public static void List(Mobile m, int page) + { + switch (Data.GetData(m).MenuSkin) + { + case Skin.Three: + new ListGump(m, page); + break; + case Skin.Two: + new ListGump20(m, page); + break; + default: + new ListGump10(m, page); + break; + } + } + + public static void List(Mobile m, Mobile targ) + { + switch (Data.GetData(m).MenuSkin) + { + case Skin.Three: + new ListGump(m, targ); + break; + case Skin.Two: + new ListGump20(m, targ); + break; + default: + break; + } + } + + public static void PmNotify(Mobile m) + { + switch (Data.GetData(m).MenuSkin) + { + case Skin.Three: + new PmNotifyGump(m); + break; + case Skin.Two: + new PmNotifyGump20(m); + break; + default: + new PmNotifyGump10(m); + break; + } + } + + public static bool IsInFaction(Mobile m) + { + if (m == null || !m.Player) + return false; + + return (((PlayerMobile)m).FactionPlayerState != null && ((PlayerMobile)m).FactionPlayerState.Faction != null); + } + + public static string FactionName(Mobile m) + { + if (!IsInFaction(m)) + return ""; + + return ((PlayerMobile)m).FactionPlayerState.Faction.Definition.PropName; + } + + public static string FactionTitle(Mobile m) + { + if (!IsInFaction(m)) + return ""; + + return ((PlayerMobile)m).FactionPlayerState.Rank.Title; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/IrcConnection.cs b/Scripts/Customs/KniveChat/General/IrcConnection.cs new file mode 100644 index 0000000..6cfbbe7 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/IrcConnection.cs @@ -0,0 +1,436 @@ +using System; +using System.Net.Sockets; +using System.Threading; +using System.IO; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Knives.Chat3 +{ + public enum IrcColor + { + White = 0, + Black = 1, + Blue = 2, + Green = 3, + LightRed = 4, + Brown = 5, + Purple = 6, + Orange = 7, + Yellow = 8, + LightGreen = 9, + Cyan = 10, + LightCyan = 11, + LightBlue = 12, + Pink = 13, + Grey = 14, + LightGrey = 15, + }; + + public class IrcConnection + { + private static IrcConnection s_Connection = new IrcConnection(); + + public static IrcConnection Connection{ get{ return s_Connection; } } + + private TcpClient c_Tcp; + private Thread c_Thread; + private StreamReader c_Reader; + private StreamWriter c_Writer; + private bool c_Connecting, c_Connected; + private int c_Attempts; + private DateTime c_LastPong; + private DateTime c_NextStatus = DateTime.Now; + private Server.Timer c_ConnectTimer; + + public bool Connecting{ get{ return c_Connecting; } } + public bool Connected{ get{ return c_Connected; } } + public bool HasMoreAttempts{ get{ return c_Attempts <= Data.IrcMaxAttempts; } } + + public string Status + { + get + { + return "Server: RunUO 2.0 Creatures: " + World.Mobiles.Count + " Items: " + World.Items.Count + " Guilds: " + BaseGuild.List.Count + " Players: " + NetState.Instances.Count; + } + } + + public IrcConnection() + { + } + + public void Connect( Mobile m ) + { + Data data = Data.GetData( m ); + + if ( c_Connecting ) + { + m.SendMessage( data.SystemC, General.Local(102) ); + return; + } + + if ( c_Connected ) + { + m.SendMessage( data.SystemC, General.Local(103) ); + return; + } + + Connect(); + } + + public void Connect() + { + new Thread( new ThreadStart( ConnectTcp ) ).Start(); + } + + public void CancelConnect() + { + c_Attempts = Data.IrcMaxAttempts; + } + + private void Reconnect() + { + c_Attempts++; + + if ( !HasMoreAttempts ) + { + c_Attempts = 1; + BroadcastSystem( General.Local(104) ); + return; + } + + BroadcastSystem( General.Local(105) + c_Attempts ); + + Connect(); + } + + private void ConnectTcp() + { + try{ c_Tcp = new TcpClient( Data.IrcServer, Data.IrcPort ); } + catch + { + BroadcastSystem( General.Local(106) ); + + Reconnect(); + + return; + } + + ConnectStream(); + } + + private void ConnectStream() + { + try + { + c_Connecting = true; + c_ConnectTimer = Server.Timer.DelayCall(TimeSpan.FromSeconds(30), new Server.TimerCallback(TimerFail)); + c_LastPong = DateTime.Now; + + c_Reader = new StreamReader(c_Tcp.GetStream(), System.Text.Encoding.Default); + c_Writer = new StreamWriter(c_Tcp.GetStream(), System.Text.Encoding.Default); + + BroadcastSystem(General.Local(107)); + + SendMessage(String.Format("USER {0} 1 * :Hello!", Data.IrcNick)); + SendMessage(String.Format("NICK {0}", Data.IrcNick)); + + c_Thread = new Thread(new ThreadStart(ReadStream)); + c_Thread.Start(); + + Server.Timer.DelayCall(TimeSpan.FromSeconds(15.0), new Server.TimerCallback(Names)); + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.HasGump(typeof(IrcGump))) + GumpPlus.RefreshGump(data.Mobile, typeof(IrcGump)); + + } + catch(Exception e) + { + Errors.Report(General.Local(266), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + private void TimerFail() + { + if (!c_Connecting || c_Connected) + return; + + c_Connecting = false; + BroadcastSystem("IRC connection attempt timed out."); + + try + { + if (c_Thread != null) + c_Thread.Abort(); + } + catch + { + } + + c_Thread = null; + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.HasGump(typeof(IrcGump))) + GumpPlus.RefreshGump(data.Mobile, typeof(IrcGump)); + } + + private void Names() + { + if (c_Connected) + SendMessage("NAMES " + Data.IrcRoom); + else + return; + + Server.Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), new Server.TimerCallback( Names ) ); + } + + private void PingPong(string str) + { + if (!c_Connecting && !c_Connected) + return; + + if (str.IndexOf("PING") != -1) + str = str.Replace("PING", "PONG"); + else + str = str.Replace("PONG", "PING"); + + SendMessage( str ); + } + + public void SendMessage( string msg ) + { + try{ + + BroadcastRaw( msg ); + + c_Writer.WriteLine( msg ); + c_Writer.Flush(); + + }catch{ Disconnect(); } + } + + public void SendUserMessage( Mobile m, string msg ) + { + if ( !Connected ) + return; + + msg = OutParse(m, m.RawName + ": " + msg); + s_Connection.SendMessage( String.Format( "PRIVMSG {0} : {1}", Data.IrcRoom, msg )); + + if (msg.ToLower().IndexOf("!status") != -1 && c_NextStatus < DateTime.Now) + { + c_NextStatus = DateTime.Now + TimeSpan.FromSeconds(15); + s_Connection.SendMessage(String.Format("PRIVMSG {0} : {1}", Data.IrcRoom, Status)); + BroadcastSystem(Status); + } + + BroadcastRaw(String.Format("PRIVMSG {0} : {1}", Data.IrcRoom, msg)); + } + + private string OutParse( Mobile m, string str ) + { + if ( m.AccessLevel != AccessLevel.Player ) + return str = '\x0003' + ((int)Data.IrcStaffColor).ToString() + str; + + return str; + } + + private void BroadcastSystem( string msg ) + { + if (Channel.GetByType(typeof(Irc)) == null) + return; + + Channel.GetByType(typeof(Irc)).BroadcastSystem(msg); + } + + private void Broadcast( string name, string msg ) + { + if (Channel.GetByType(typeof(Irc)) == null) + return; + + ((Irc)Channel.GetByType(typeof(Irc))).Broadcast(name, msg); + } + + private void Broadcast( Mobile m, string msg ) + { + } + + private void BroadcastRaw( string msg ) + { + foreach( Data data in Data.Datas.Values ) + if ( data.IrcRaw ) + data.Mobile.SendMessage( data.SystemC, "RAW: " + msg ); + } + + private void ReadStream() + { + try + { + + string input = ""; + + while (c_Thread.IsAlive) + { + input = c_Reader.ReadLine(); + + if (input == null) + break; + + HandleInput(input); + } + + if (c_Connected) + Disconnect(); + + } + catch { if (c_Connected) Disconnect(); } + } + + private void HandleInput(string str) + { + try + { + if (str == null) + return; + + BroadcastRaw(str); + + if (str.IndexOf("PONG") != -1 || str.IndexOf("PING") != -1) + { + PingPong(str); + return; + } + + if (str.IndexOf("353") != -1) + { + BroadcastRaw(General.Local(109)); + + int index = str.ToLower().IndexOf(Data.IrcRoom.ToLower()) + Data.IrcRoom.Length + 2; + + if (index == 1) + return; + + string strList = str.Substring(index, str.Length - index); + + string[] strs = strList.Trim().Split(' '); + + Data.IrcList.Clear(); + Data.IrcList.AddRange(strs); + Data.IrcList.Remove(Data.IrcNick); + } + + if (str.IndexOf("001") != -1 && c_Connecting) + { + c_Connected = true; + c_Connecting = false; + + if (c_ConnectTimer != null) + c_ConnectTimer.Stop(); + + BroadcastSystem(General.Local(108)); + c_Attempts = 1; + + SendMessage(String.Format("JOIN {0}", Data.IrcRoom)); + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.HasGump(typeof(IrcGump))) + GumpPlus.RefreshGump(data.Mobile, typeof(IrcGump)); + } + + if (str.Length > 300) + return; + + if (str.IndexOf("PRIVMSG") != -1) + { + string parOne = str.Substring(1, str.IndexOf("!") - 1); + + string parThree = str.Substring(str.IndexOf("!") + 1, str.Length - str.IndexOf("!") - (str.Length - str.IndexOf("PRIVMSG")) - 1); + + int index = 0; + + index = str.ToLower().IndexOf(Data.IrcRoom.ToLower()) + Data.IrcRoom.Length + 2; + + if (index == 1) + return; + + string parTwo = str.Substring(index, str.Length - index); + + if (parTwo.IndexOf("ACTION") != -1) + { + index = parTwo.IndexOf("ACTION") + 7; + parTwo = parTwo.Substring(index, parTwo.Length - index); + str = String.Format("<{0}> {1} {2}", Data.IrcRoom, parOne, parTwo); + } + else + str = String.Format("<{0}> {1}: {2}", Data.IrcRoom, parOne, parTwo); + + Broadcast(parOne, str); + + if (str.ToLower().IndexOf("!status") != -1 && c_NextStatus < DateTime.Now) + { + c_NextStatus = DateTime.Now + TimeSpan.FromSeconds(15); + s_Connection.SendMessage(String.Format("PRIVMSG {0} : {1}", Data.IrcRoom, Status)); + BroadcastSystem(Status); + } + } + } + catch (Exception e) + { + Errors.Report(General.Local(267), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Message); + Console.WriteLine(e.Message); + } + } + + public void Disconnect() + { + Disconnect( true ); + } + + public void Disconnect(bool reconn) + { + try + { + if (c_Connected) + BroadcastSystem(General.Local(110)); + + c_Connected = false; + c_Connecting = false; + + if (c_Thread != null) + { + try { c_Thread.Abort(); } + catch { } + c_Thread = null; + } + if (c_Reader != null) + c_Reader.Close(); + if (c_Writer != null) + c_Writer.Close(); + if (c_Tcp != null) + c_Tcp.Close(); + + if (reconn) + Reconnect(); + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.HasGump(typeof(IrcGump))) + GumpPlus.RefreshGump(data.Mobile, typeof(IrcGump)); + } + catch (Exception e) + { + Errors.Report(General.Local(268), e); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Logging.cs b/Scripts/Customs/KniveChat/General/Logging.cs new file mode 100644 index 0000000..45f7067 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Logging.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using Server; + +namespace Knives.Chat3 +{ + public class Logging + { + public static void LogChat(string msg) + { + if (!Directory.Exists("Logs")) + Directory.CreateDirectory("Logs"); + + string directory = "Logs/Chat"; + + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + try + { + StreamWriter writer = new StreamWriter(Path.Combine(directory, String.Format("Chat-{0}.log", DateTime.Now.ToLongDateString())), true); + + writer.AutoFlush = true; + writer.WriteLine(msg); + } + catch + { + } + } + + public static void LogPm(string msg) + { + if (!Directory.Exists("Logs")) + Directory.CreateDirectory("Logs"); + + string directory = "Logs/Chat"; + + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + try + { + StreamWriter writer = new StreamWriter(Path.Combine(directory, String.Format("Pm-{0}.log", DateTime.Now.ToLongDateString())), true); + + writer.AutoFlush = true; + writer.WriteLine(msg); + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Message.cs b/Scripts/Customs/KniveChat/General/Message.cs new file mode 100644 index 0000000..bdeb8a1 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Message.cs @@ -0,0 +1,105 @@ +using System; +using System.IO; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public enum MsgType { Normal, Invite, Staff, System } + + public class Message + { + public static bool CanMessage(Mobile from, Mobile to) + { + if (from == to) + return false; + + if (from.AccessLevel > to.AccessLevel) + return true; + + Data df = Data.GetData(from); + Data dt = Data.GetData(to); + + if (df.Banned || dt.Banned) + return false; + if (df.FriendsOnly && !df.Friends.Contains(to)) + return false; + if (dt.FriendsOnly && !dt.Friends.Contains(from)) + return false; + if (df.Ignores.Contains(to)) + return false; + if (dt.Ignores.Contains(from)) + return false; + if (dt.Messages.Count >= Data.MaxMsgs && !dt.WhenFull) + return false; + + return true; + } + + public static bool StaffTimeout(Message msg) + { + return (msg.From.AccessLevel > AccessLevel.Player && msg.Received + TimeSpan.FromHours(5) < DateTime.Now); + } + + private Mobile c_From; + private string c_Msg, c_Subject; + private MsgType c_Type; + private DateTime c_Received; + private bool c_Read; + + public Mobile From { get { return c_From; } } + public string Msg { get { return c_Msg; } } + public string Subject { get { return c_Subject; } } + public MsgType Type { get { return c_Type; } } + public DateTime Received { get { return c_Received; } } + + public bool Read + { + get { return c_Read; } + set + { + c_Read = value; + } + } + + public Message() + { + c_Msg = ""; + c_Subject = ""; + } + + public Message(Mobile from, string sub, string msg, MsgType type) + { + c_From = from; + c_Msg = msg; + c_Subject = sub; + c_Type = type; + + c_Received = DateTime.Now; + } + + public void Save(GenericWriter writer) + { + writer.Write(0); // Version + + writer.Write(c_From); + writer.Write(c_Msg); + writer.Write(c_Subject); + writer.Write((int)c_Type); + writer.Write(c_Received); + writer.Write(c_Read); + } + + public void Load(GenericReader reader) + { + int version = reader.ReadInt(); + + c_From = reader.ReadMobile(); + c_Msg = reader.ReadString(); + c_Subject = reader.ReadString(); + c_Type = (MsgType)reader.ReadInt(); + c_Received = reader.ReadDateTime(); + c_Read = reader.ReadBool(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/MultiConnection.cs b/Scripts/Customs/KniveChat/General/MultiConnection.cs new file mode 100644 index 0000000..3de7965 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/MultiConnection.cs @@ -0,0 +1,323 @@ +// Get name lists for online players not hidden + +using System; +using System.IO; +using System.Collections; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Server; + +namespace Knives.Chat3 +{ + public class MultiConnection + { + private static MultiConnection s_Connection = new MultiConnection(); + public static MultiConnection Connection { get { return s_Connection; } } + + private Socket c_Master, c_Slave; + private ArrayList c_Clients = new ArrayList(); + private Hashtable c_Names = new Hashtable(); + private bool c_Server; + + private bool c_Connecting, c_Connected; + private Server.Timer c_ConnectTimer; + + public Hashtable Names { get { return c_Names; } } + public bool Connecting { get { return c_Connecting; } } + public bool Connected { get { return c_Connected; } } + + public MultiConnection() + { + } + + public void Block(string str) + { + foreach (Socket s in c_Clients) + if (c_Names[s].ToString() == str) + { + c_Names.Remove(s); + c_Clients.Remove(s); + s.Close(); + } + } + + public void ConnectMaster() + { + if (c_Connected && c_Server) + return; + + try + { + c_Server = true; + //Console.WriteLine("CM Close Slave"); + CloseSlave(); + + c_Master = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + c_Master.Bind(new IPEndPoint(IPAddress.Any, Data.MultiPort)); + c_Master.Listen(4); + c_Master.BeginAccept(new AsyncCallback(OnClientConnect), null); + //Console.WriteLine("Started"); + + c_Connecting = false; + c_Connected = true; + } + catch (Exception e) + { + c_Server = false; + //Console.WriteLine(e.Message); + //Console.WriteLine(e.StackTrace); + } + } + + public void CloseMaster() + { + if (c_Master != null) + c_Master.Close(); + + foreach (Socket sok in c_Clients) + sok.Close(); + + c_Clients.Clear(); + c_Names.Clear(); + + c_Connecting = false; + c_Connected = false; + } + + public void ConnectSlave() + { + if (c_Connected && !c_Server) + return; + + CloseMaster(); + new Thread(new ThreadStart(ConnectToMaster)).Start(); + } + + private void ConnectToMaster() + { + try + { + c_Slave = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); + c_Slave.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse(Data.MultiServer), Data.MultiPort)); + } + catch(Exception e) + { + BroadcastSystem(General.Local(288)); + Console.WriteLine(e.Message); + Console.WriteLine(e.StackTrace); + return; + } + + BeginReceive(); + } + + private void BeginReceive() + { + try + { + BroadcastSystem(General.Local(289)); + + byte[] msg = System.Text.Encoding.ASCII.GetBytes(" " + Server.Misc.ServerList.ServerName); + + c_Slave.Send(msg, 0, msg.Length, SocketFlags.None); + + c_Connected = true; + c_Connecting = false; + + WaitForData(c_Slave); + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.HasGump(typeof(MultiGump))) + GumpPlus.RefreshGump(data.Mobile, typeof(MultiGump)); + } + catch (Exception e) + { + Errors.Report("Error opening stream for slave."); + //Console.WriteLine(e.Message); + //Console.WriteLine(e.StackTrace); + } + } + + private void HandleInput(string str) + { + Broadcast(str); + //Console.WriteLine(str); + } + + public void CloseSlave() + { + try + { + if (c_Connected) + BroadcastSystem(General.Local(290)); + + c_Connected = false; + c_Connecting = false; + + if (c_Slave != null) + c_Slave.Close(); + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.HasGump(typeof(MultiGump))) + GumpPlus.RefreshGump(data.Mobile, typeof(MultiGump)); + } + catch (Exception e) + { + Errors.Report("Error disconnecting slave."); + //Console.WriteLine(e.Message); + //Console.WriteLine(e.Source); + //Console.WriteLine(e.StackTrace); + } + } + + private void OnClientConnect(IAsyncResult asyn) + { + try + { + //Console.WriteLine("Connection Made"); + Socket sok = c_Master.EndAccept(asyn); + c_Clients.Add(sok); + //sok.Close(); + WaitForData(sok); + } + catch (Exception e) + { + //Console.WriteLine("Connection Died"); + //Console.WriteLine(e.Message); + //Console.WriteLine(e.StackTrace); + } + } + + public void WaitForData(Socket sok) + { + try + { + MultiPacket pak = new MultiPacket(); + pak.Socket = sok; + //Console.WriteLine("Waiting for input."); + sok.BeginReceive(pak.Buffer, 0, pak.Buffer.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), pak); + } + catch (Exception e) + { + if (c_Server) + { + if(c_Names[sok] != null) + BroadcastSystem(c_Names[sok].ToString() + General.Local(291)); + c_Clients.Remove(sok); + c_Names.Remove(sok); + } + else + { + BroadcastSystem(General.Local(290)); + CloseSlave(); + } + } + } + + public void OnDataReceived(IAsyncResult asyn) + { + try + { + MultiPacket pak = (MultiPacket)asyn.AsyncState; + + byte[] buffer = new byte[1024]; + int count = pak.Socket.Receive(buffer); + char[] chars = new char[count]; + System.Text.Encoding.ASCII.GetDecoder().GetChars(buffer, 0, count, chars, 0); + string input = new System.String(chars).Trim(); + + //Console.WriteLine(pak.Socket + " " + input); + + if (c_Server) + { + if (input.ToLower().IndexOf("<") != 0) + { + c_Names[pak.Socket] = input; + BroadcastSystem(input + General.Local(292)); + } + else + { + Broadcast(input); + SendMaster(input); + } + } + else + { + HandleInput(input); + } + + WaitForData(pak.Socket); + } + catch (Exception e) + { + if (c_Server) + CloseMaster(); + else + CloseSlave(); + + //Console.WriteLine(e.Message); + //Console.WriteLine(e.StackTrace); + } + } + + public void Broadcast(string str) + { + if (Channel.GetByType(typeof(Multi)) == null) + return; + + ((Multi)Channel.GetByType(typeof(Multi))).Broadcast(str); + } + + public void SendMaster(string str) + { + if (!c_Server || c_Master == null) + return; + + try + { + byte[] msg = System.Text.Encoding.ASCII.GetBytes(" " + str); + + foreach (Socket sok in c_Clients) + sok.Send(msg, 0, msg.Length, SocketFlags.None); + } + catch + { + Errors.Report("Error in sending to clients."); + } + } + + private void BroadcastSystem(string msg) + { + if (Channel.GetByType(typeof(Multi)) == null) + return; + + Channel.GetByType(typeof(Multi)).BroadcastSystem(msg); + } + + public void SendMessage(Mobile m, string str) + { + //Console.WriteLine("Sending: {0} {1}", c_Server, str); + + if(c_Server) + { + SendMaster("<" + Server.Misc.ServerList.ServerName + "> " + m.RawName + ": " + str); + Broadcast("<" + Server.Misc.ServerList.ServerName + "> " + m.RawName + ": " + str); + } + else + { + byte[] msg = System.Text.Encoding.ASCII.GetBytes(" <" + Server.Misc.ServerList.ServerName + "> " + m.RawName + ": " + str); + + //Console.WriteLine("Sending to Master: <" + Server.Misc.ServerList.ServerName + "> " + m.RawName + ": " + str); + c_Slave.Send(msg, 0, msg.Length, SocketFlags.None); + } + } + + + public class MultiPacket + { + public Socket Socket; + public byte[] Buffer = new byte[1]; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/Notification.cs b/Scripts/Customs/KniveChat/General/Notification.cs new file mode 100644 index 0000000..a1cde1a --- /dev/null +++ b/Scripts/Customs/KniveChat/General/Notification.cs @@ -0,0 +1,153 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Network; + +namespace Knives.Chat3 +{ + public enum MacroPenalty { None, Kick } + + public class Notification + { + private string c_Text, c_Name; + private bool c_Gump, c_AntiMacro; + private TimeSpan c_Recur = TimeSpan.Zero; + private Timer c_Timer; + + public string Text { get { return c_Text; } set { c_Text = value; } } + public string Name { get { return c_Name; } set { c_Name = value; } } + public bool Gump { get { return c_Gump; } set { c_Gump = value; } } + public bool AntiMacro { get { return c_AntiMacro; } set { c_AntiMacro = value; } } + public TimeSpan Recur { get { return c_Recur; } set { c_Recur = value; StartNotify(); } } + + public Notification() + { + c_Name = "New"; + + Data.Notifications.Add(this); + } + + private void StartNotify() + { + if (c_Timer != null) + c_Timer.Stop(); + + if (c_Recur != TimeSpan.Zero && Data.Notifications.Contains(this)) + c_Timer = Timer.DelayCall(c_Recur+TimeSpan.FromSeconds(Utility.Random(20)), new TimerCallback(Notify)); + } + + private void Notify() + { + StartNotify(); + + if (c_Gump) + { + foreach (NetState ns in NetState.Instances) + if (ns.Mobile != null) + new NotAlertGump(ns.Mobile, this); + } + else + { + foreach (NetState ns in NetState.Instances) + if (ns.Mobile != null) + ns.Mobile.SendMessage(Data.GetData(ns.Mobile).SystemC, c_Text); + } + } + + public void Save(GenericWriter writer) + { + writer.Write(0); // Version + + writer.Write(c_Text); + writer.Write(c_Name); + writer.Write(c_Gump); + writer.Write(c_AntiMacro); + writer.Write(c_Recur); + } + + public void Load(GenericReader reader) + { + int version = reader.ReadInt(); + + c_Text = reader.ReadString(); + c_Name = reader.ReadString(); + c_Gump = reader.ReadBool(); + c_AntiMacro = reader.ReadBool(); + c_Recur = reader.ReadTimeSpan(); + + StartNotify(); + } + + private class NotAlertGump : GumpPlus + { + private Notification c_Not; + private Timer c_Timer; + + public NotAlertGump(Mobile m, Notification not) + : base(m, 300, 50) + { + c_Not = not; + + if(c_Not.AntiMacro) + c_Timer = Timer.DelayCall(TimeSpan.FromSeconds(Data.AntiMacroDelay), new TimerCallback(AntiMacro)); + } + + protected override void BuildGump() + { + AddImage(0, 0, 0x15D5, Data.GetData(Owner).SystemC); + AddButton(13, 13, 0xFC4, "Open", new GumpCallback(Open)); + } + + private void AntiMacro() + { + switch (Data.MacroPenalty) + { + case MacroPenalty.None: + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(276)); + break; + case MacroPenalty.Kick: + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(279)); + Owner.NetState.Dispose(); + break; + } + + foreach (Data data in Data.Datas.Values) + if (data.Mobile.AccessLevel >= AccessLevel.GameMaster) + data.AddMessage(new Message(data.Mobile, General.Local(277), Owner.RawName + General.Local(278), MsgType.System)); + } + + private void Open() + { + new NotMessageGump(Owner, c_Not); + if (c_Timer != null) + c_Timer.Stop(); + } + } + + private class NotMessageGump : GumpPlus + { + private Notification c_Not; + + public NotMessageGump(Mobile m, Notification not) + : base(m, 100, 100) + { + c_Not = not; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(50, y, 100, 45, "
" + General.Local(271), false, false); + AddImage(width / 2 - 80, y + 7, 0x39); + AddImage(width / 2 + 50, y + 7, 0x3B); + + AddHtml(20, y += 45, width - 40, 80, HTML.Black + c_Not.Text, true, true); + + AddBackgroundZero(0, 0, width, y += 100, Data.GetData(Owner).DefaultBack); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/General/TrackSpam.cs b/Scripts/Customs/KniveChat/General/TrackSpam.cs new file mode 100644 index 0000000..dc8d773 --- /dev/null +++ b/Scripts/Customs/KniveChat/General/TrackSpam.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class TrackSpam + { + private static Hashtable s_Log = new Hashtable(); + + public static bool LogSpam( Mobile m, string type, TimeSpan limit ) + { + if ( s_Log.Contains( m ) ) + { + Hashtable table = (Hashtable)s_Log[m]; + + if ( table.Contains( type ) ) + { + if ( (DateTime)table[type] > DateTime.Now-limit ) + return false; + + table[type] = DateTime.Now; + } + } + else + { + Hashtable table = new Hashtable(); + table[type] = DateTime.Now; + s_Log[m] = table; + } + + return true; + } + + public static TimeSpan NextAllowedIn( Mobile m, string type, TimeSpan limit ) + { + if ( s_Log[m] == null ) + return TimeSpan.FromSeconds( 1 ); + + Hashtable table = (Hashtable)s_Log[m]; + + if ( table[type] == null || (DateTime)table[type]+limit < DateTime.Now ) + return TimeSpan.FromSeconds( 1 ); + + return (DateTime)table[type]+limit-DateTime.Now; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/1.0 Skin/ListGump10.cs b/Scripts/Customs/KniveChat/Gumps/1.0 Skin/ListGump10.cs new file mode 100644 index 0000000..32940a8 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/1.0 Skin/ListGump10.cs @@ -0,0 +1,1233 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class ListGump10 : GumpPlus + { + public enum ListPage { All, Channel, Mail, Friends, Ignores, GIgnores, GListens, Bans, Notifications } + + #region Class Definitions + + private ListPage c_ListPage; + private Mobile c_Target; + private int c_Page; + private bool c_Menu, c_Search; + private string c_TxtSearch = ""; + private string c_CharSearch = ""; + + protected ListPage CurrentPage { get { return c_ListPage; } } + public Mobile Current { get { return (c_Target == null ? Owner : c_Target); } } + + #endregion + + #region Constructors + + public ListGump10(Mobile m, int page) + : base(m, 100, 100) + { + c_ListPage = (ListPage)page; + + m.CloseGump(typeof(ListGump10)); + + Override = true; + } + + public ListGump10(Mobile m, Mobile targ) + : base(m, 100, 100) + { + c_Target = targ; + + m.CloseGump(typeof(ListGump10)); + + Override = true; + } + + public ListGump10(Mobile m) + : this(m, null) + { + m.CloseGump(typeof(ListGump10)); + + Override = true; + } + + #endregion + + #region Methods + + protected override void BuildGump() + { + if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel == null) + c_ListPage = ListPage.All; + + int width = Data.GetData(Current).QuickBar ? 250 : 200; + int y = 10; + int perpage = 10; + int bar = width - 18; + + if (c_ListPage == ListPage.Mail || (c_ListPage == ListPage.Channel && (Data.GetData(Current).CurrentChannel is Guild || Data.GetData(Current).CurrentChannel is Faction))) + perpage /= 2; + + AddBackground(width, 0, 39, 55, Data.GetData(Owner).DefaultBack); + + if (c_Search) + ShowSearch(width); + else + AddButton(width + 10, 55, c_Search ? 0xFA : 0xFC, c_Search ? 0xFB : 0xFD, "Search", new GumpCallback(Search)); + + ArrayList list = GetList(); + SearchFilter(list); + list.Sort(new InternalSort(this)); + + if (c_Page != 0) + AddButton(width / 2 - 10, y - 5, 0x15E0, 0x15E4, "Page Down", new GumpCallback(PageDown)); + + if (c_Target != null) + { + AddHtml(0, y += 25, width, "
" + General.Local(224) + " " + c_Target.RawName); + AddButton(width / 2 - 80, y, 0x5686, "Clear Viewing", new GumpCallback(ClearViewing)); + AddButton(width / 2 + 65, y, 0x5686, "Clear Viewing", new GumpCallback(ClearViewing)); + } + + y += 5; + + if (c_Page != 0) + AddButton(width + 12, 10, 0x15E2, 0x15E6, "Page Down", new GumpCallback(PageDown)); + if (perpage * (c_Page + 1) < list.Count) + AddButton(width + 12, 30, 0x15E2, 0x15E6, "Page Up", new GumpCallback(PageUp)); + + y -= 25; + + for (int i = c_Page * perpage; i < (c_Page + 1) * perpage && i < list.Count; ++i) + { + if (list[i] is string) + { + if (list[i].ToString().IndexOf("@") == 0) + list[i] = list[i].ToString().Substring(1, list[i].ToString().Length - 1); + + AddHtml(35, y += 20, width - 35, list[i].ToString()); + AddButton(width - 40, y, Data.GetData(Current).IrcIgnores.Contains(list[i].ToString()) ? 0x5687 : 0x5686, "Ignore IRC", new GumpStateCallback(IgnoreIrc), list[i]); + } + else if(list[i] is Mobile) + { + AddHtml(20, y += 25, width - 40, ColorFor((Mobile)list[i]) + (Data.GetData(Owner).QuickBar ? "" : "
") + ((Mobile)list[i]).RawName + StatusFor((Mobile)list[i])); + + if(Current == Owner && Data.GetData(Owner).NewMsgFrom((Mobile)list[i])) + AddButton(width - 20, y, 0x1523, "Check Msg", new GumpStateCallback(CheckMsg), (Mobile)list[i]); + else + AddButton(width - 20, y + 2, 0x15E1, 0x15E5, "Profile", new GumpStateCallback(Profile), (Mobile)list[i]); + + if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel is Guild) + AddHtml(35, y += 20, width - 35, ((Mobile)list[i]).GuildTitle); + else if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel is Faction) + AddHtml(35, y += 20, width - 35, General.FactionTitle((Mobile)list[i])); + + if (list[i] != Current && Data.GetData(Current).QuickBar) + { + bar = width - 18; + + if (Current.AccessLevel > ((Mobile)list[i]).AccessLevel) + { + if (Data.GetData(Current).GlobalAccess) + { + if (Data.GetData(Current).Global) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ignore", new GumpStateCallback(GIgnore), list[i]); + AddLabel(bar + 4, y, Data.GetData(Current).GIgnores.Contains(list[i]) ? 0x44 : 0x26, "I"); + } + else + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Listen", new GumpStateCallback(GListen), list[i]); + AddLabel(bar + 4, y, Data.GetData(Current).GListens.Contains(list[i]) ? 0x44 : 0x26, "L"); + } + } + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ban", new GumpStateCallback(Ban), list[i]); + AddLabel(bar + 4, y, Data.GetData((Mobile)list[i]).Banned ? 0x44 : 0x26, "b"); + } + + if (Current.AccessLevel >= AccessLevel.GameMaster && ((Mobile)list[i]).NetState != null) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Goto", new GumpStateCallback(Goto), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "g"); + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Client", new GumpStateCallback(Client), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "c"); + } + + if (Chat3.Message.CanMessage(Current, (Mobile)list[i])) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Message", new GumpStateCallback(Message), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "m"); + } + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ignore", new GumpStateCallback(Ignore), list[i]); + AddLabel(bar + 5, y - 1, Data.GetData(Current).Ignores.Contains(list[i]) ? 0x44 : 0x26, "i"); + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Friend", new GumpStateCallback(Friend), list[i]); + AddLabel(bar + 3, y, Data.GetData(Current).Friends.Contains(list[i]) ? 0x44 : 0x26, "f"); + } + } + else if (list[i] is Message) + { + Message msg = (Message)list[i]; + + AddHtml(45, y += 20, width-85, ColorFor(msg) + (msg.Read ? "" : "") + msg.Subject, false); + AddHtml(45, y += 16, width-85, General.Local(60) + " " + msg.From.RawName); + + AddButton(20, y - 10, 0x2716, "Open", new GumpStateCallback(Open), (Message)list[i]); + AddButton(width - 40, y - 10, 0x5686, 0x5687, "Delete", new GumpStateCallback(Delete), (Message)list[i]); + } + else if (list[i] is Notification) + { + Notification not = (Notification)list[i]; + + AddHtml(45, y += 20, width-85, ColorFor(not) + not.Name); + + AddButton(20, y + 3, 0x2716, "Edit Notif", new GumpStateCallback(EditNotif), (Notification)list[i]); + AddButton(width - 40, y + 3, 0x5686, 0x5687, "Delete", new GumpStateCallback(Delete), (Notification)list[i]); + } + + AddBackground(25, y + 20, width - 50, 3, Data.GetData(Owner).DefaultBack); + } + + if (c_ListPage == ListPage.Mail && Current.AccessLevel >= AccessLevel.GameMaster) + { + AddHtml(0, y += 25, width, "
" + General.Local(95), false); + AddButton(width / 2 - 50, y + 3, 0x2716, "Broadcast", new GumpCallback(Broadcast)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Broadcast", new GumpCallback(Broadcast)); + + AddHtml(0, y += 20, width, "
" + General.Local(257), false); + AddButton(width / 2 - 50, y + 3, 0x2716, "Staff", new GumpCallback(BroadcastStaff)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Staff", new GumpCallback(BroadcastStaff)); + } + else if (c_ListPage == ListPage.Notifications) + { + AddHtml(0, y += 25, width, "
" + General.Local(270), false); + AddButton(width / 2 - 70, y + 3, 0x2716, "New Notif", new GumpCallback(NewNotif)); + AddButton(width / 2 + 60, y + 3, 0x2716, "New Notif", new GumpCallback(NewNotif)); + } + + if (c_ListPage == ListPage.Mail) + AddHtml(0, y += 20, width, "
" + Data.GetData(Owner).Messages.Count + " / " + Data.MaxMsgs); + + if (c_ListPage == ListPage.Channel) + { + ArrayList states = new ArrayList(Server.Network.NetState.Instances); + foreach (Server.Network.NetState state in Server.Network.NetState.Instances) + if (state.Mobile != null && state.Mobile.AccessLevel != AccessLevel.Player) + states.Remove(state); + + AddHtml(0, 260, width, "
" + states.Count + " " + General.Local(19)); + } + + AddButton(width - 80, 280, 0x5689, "Help", new GumpCallback(Help)); + AddButton(width - 65, 280, 0x5689, "Status", new GumpCallback(Status)); + AddLabel(width - 62, 279, Data.GetData(Current).Status == OnlineStatus.Online ? 0x47E : 0x34, "A"); + AddButton(width - 50, 280, 0x5689, "QuickBar", new GumpCallback(QuickBar)); + AddLabel(width - 47, 279, Data.GetData(Current).QuickBar ? 0x34 : 0x47E, "Q"); + + AddBackgroundZero(0, 0, width, 300, Data.GetData(Current).DefaultBack); + + BuildTabs(width, 300); + } + + private void BuildTabs(int width, int y) + { + AddButton(width / 2 - 90, y, 0x98B, "Channels", new GumpCallback(Channels)); + if(Data.GetData(Current).CurrentChannel != null) + AddHtml(width / 2 - 90, y + 3, 60, (c_ListPage == ListPage.Channel ? HTML.Green : HTML.White) + "
" + Data.GetData(Current).CurrentChannel.NameFor(Current)); + + AddButton(width / 2 - 30, y, 0x98B, "Page", new GumpStateCallback(Page), ListPage.Friends); + AddHtml(width / 2 - 30, y + 3, 60, (c_ListPage == ListPage.Friends ? HTML.Green : HTML.White) + "
" + General.Local(203)); + + AddButton(width / 2 + 30, y, 0x98B, "Page", new GumpStateCallback(Page), ListPage.Ignores); + AddHtml(width / 2 + 30, y + 3, 60, (c_ListPage == ListPage.Ignores ? HTML.Green : HTML.White) + "
" + General.Local(51)); + + AddButton(width / 2 - 90, y += 23, 0x98B, "Page", new GumpStateCallback(Page), ListPage.Mail); + AddHtml(width / 2 - 90, y + 3, 60, (c_ListPage == ListPage.Mail ? HTML.Green : HTML.White) + "
" + General.Local(56)); + + AddButton(width / 2 - 30, y, 0x98B, "Options", new GumpCallback(Options)); + AddHtml(width / 2 - 30, y + 3, 60, "
" + General.Local(39)); + + AddButton(width / 2 + 30, y, 0x98B, "Views", new GumpCallback(Views)); + AddHtml(width / 2 + 30, y + 3, 60, "
" + General.Local(1)); + + AddButton(width / 2 - 30, y += 25, 0x8B1, "1.0", new GumpStateCallback(SkinChange), Skin.One); + AddButton(width / 2 - 10, y, 0x8B2, "2.0", new GumpStateCallback(SkinChange), Skin.Two); + AddButton(width / 2 + 10, y, 0x8B3, "3.0", new GumpStateCallback(SkinChange), Skin.Three); + } + + private void ShowSearch(int x) + { + int width = 130; + + AddBackground(x+39, 0, width, 50, Data.GetData(Current).DefaultBack, false); + + AddTextField(x+15+39, 15, 90, 21, 0x480, 0xBBC, "Search", c_TxtSearch); + AddButton(x + width-17+39, 19, 0x2716, "Text Search", new GumpCallback(TxtSearch)); + + char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + + int difx = x-20; + int y = 55; + + foreach (char c in chars) + { + AddButton(difx += 20, y, 0x2344, "Char Search", new GumpStateCallback(CharSearch), c.ToString()); + AddHtml(difx + 6, y, 20, (c_CharSearch == c.ToString() ? HTML.Green : "") + c, false); + + if (difx >= x + 19) + { + difx = x-20; + y += 20; + } + } + + AddButton(x + 10, y, c_Search ? 0xFA : 0xFC, c_Search ? 0xFB : 0xFD, "Search", new GumpCallback(Search)); + } + + private string GetTitle() + { + switch (c_ListPage) + { + case ListPage.All: return General.Local(46); + case ListPage.Channel: return Data.GetData(Current).CurrentChannel.NameFor(Current); + case ListPage.Mail: return General.Local(56); + case ListPage.Friends: return General.Local(203); + case ListPage.Ignores: return General.Local(51); + case ListPage.GIgnores: return General.Local(204); + case ListPage.GListens: return General.Local(205); + case ListPage.Bans: return General.Local(54); + case ListPage.Notifications: return General.Local(269); + } + + return ""; + } + + private ArrayList GetList() + { + ArrayList list; + + switch (c_ListPage) + { + case ListPage.All: + list = new ArrayList(); + foreach (Data data in Data.Datas.Values) + if (Current.AccessLevel >= data.Mobile.AccessLevel) + list.Add(data.Mobile); + return list; + case ListPage.Channel: return new ArrayList(Data.GetData(Current).CurrentChannel.BuildList(Current)); + case ListPage.Mail: return new ArrayList(Data.GetData(Current).Messages); + case ListPage.Friends: return new ArrayList(Data.GetData(Current).Friends); + case ListPage.Ignores: return new ArrayList(Data.GetData(Current).Ignores); + case ListPage.GIgnores: return new ArrayList(Data.GetData(Current).GIgnores); + case ListPage.GListens: return new ArrayList(Data.GetData(Current).GListens); + case ListPage.Bans: + list = new ArrayList(); + foreach (Data data in Data.Datas.Values) + if (data.Banned) + list.Add(data.Mobile); + return list; + case ListPage.Notifications: return new ArrayList(Data.Notifications); + } + + return new ArrayList(); + } + + private void SearchFilter(ArrayList list) + { + string txt = ""; + foreach (object obj in new ArrayList(list)) + { + if (obj is Mobile) + txt = ((Mobile)obj).RawName; + else if (obj is Message) + txt = ((Message)obj).From.RawName; + else + txt = obj.ToString(); + + if (c_CharSearch.ToLower() != "" && txt.ToLower().IndexOf(c_CharSearch) != 0) + list.Remove(obj); + else if (c_TxtSearch.ToLower() != "" && txt.ToLower().IndexOf(c_TxtSearch) == -1) + list.Remove(obj); + } + } + + private string ColorFor(Message msg) + { + switch (msg.Type) + { + case MsgType.Normal: return HTML.White; + case MsgType.Invite: return HTML.Yellow; + case MsgType.System: return HTML.Red; + case MsgType.Staff: return HTML.Purple; + default: return HTML.White; + } + } + + private string ColorFor(Notification not) + { + return HTML.White; + } + + private string ColorFor(Mobile m) + { + if (Current == m) + return HTML.Yellow; + if (Data.GetData(m).Banned) + return HTML.Red; + if (Data.GetData(Current).Ignores.Contains(m)) + return HTML.AshRed; + if (Data.GetData(Current).Global && Data.GetData(Current).GIgnores.Contains(m)) + return HTML.AshRed; + if (!Data.GetData(Current).Global && Data.GetData(Current).GListens.Contains(m)) + return HTML.Blue; + if (m.NetState == null || Data.GetData(m).Status == OnlineStatus.Hidden) + return HTML.DarkGray; + if (Data.GetData(m).Status == OnlineStatus.Away || Data.GetData(m).Status == OnlineStatus.Busy) + return HTML.Gray; + if (m.AccessLevel > AccessLevel.Player) + return HTML.LightPurple; + if (m.Guild != null && (m.Guild == Current.Guild)) + return HTML.Green; + + return HTML.White; + } + + private string StatusFor(Mobile m) + { + if (Data.GetData(m).Status == OnlineStatus.Away) + return " (Away)"; + else if (Data.GetData(m).Status == OnlineStatus.Busy) + return " (Busy)"; + else if (Data.GetData(m).Status == OnlineStatus.Hidden) + return " (Hidden)"; + + return ""; + } + + #endregion + + #region Responses + + private void PageUp() + { + c_Page++; + NewGump(); + } + + private void PageDown() + { + c_Page--; + NewGump(); + } + + private void Help() + { + NewGump(); + new HelpContentsGump(Owner); + } + + private void IgnoreIrc(object o) + { + if (!(o is string)) + return; + + if (Data.GetData(Current).IrcIgnores.Contains(o.ToString())) + Data.GetData(Current).RemoveIrcIgnore(o.ToString()); + else + Data.GetData(Current).AddIrcIgnore(o.ToString()); + + NewGump(); + } + + private void Profile(object o) + { + if (!(o is Mobile)) + return; + + NewGump(); + new ProfileGump(Owner, (Mobile)o); + } + + private void Open(object o) + { + Message m = o as Message; + + if (m == null) + return; + + if (Data.GetData(Owner).Messages.Contains(m)) + m.Read = true; + + NewGump(); + + if (m.Read && Data.GetData(m.From).ReadReceipt && m.From.AccessLevel >= Owner.AccessLevel) + m.From.SendMessage(Data.GetData(m.From).SystemC, Owner.RawName + " " + General.Local(197) + " " + m.Subject); + + new MessageGump(Owner, m); + } + + private void EditNotif(object o) + { + if (!(o is Notification)) + return; + + NewGump(); + new EditNotGump(Owner, (Notification)o); + } + + private void Delete(object o) + { + if (o is Message) + Data.GetData(Current).DeleteMessage((Message)o); + else if (o is Notification) + Data.Notifications.Remove(o); + + NewGump(); + } + + private void Friend(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (Data.GetData(m).ByRequest && !Data.GetData(Current).Friends.Contains(m)) + { + if (!TrackSpam.LogSpam(Current, "Request " + m.RawName, TimeSpan.FromHours(Data.RequestSpam))) + { + TimeSpan ts = TrackSpam.NextAllowedIn(Current, "Request " + m.RawName, TimeSpan.FromHours(Data.RequestSpam)); + string txt = (ts.Days != 0 ? ts.Days + " " + General.Local(170) + " " : "") + (ts.Hours != 0 ? ts.Hours + " " + General.Local(171) + " " : "") + (ts.Minutes != 0 ? ts.Minutes + " " + General.Local(172) + " " : ""); + + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(96) + " " + txt); + NewGump(); + return; + } + + Data.GetData(m).AddMessage(new Message(Current, General.Local(84), General.Local(85), MsgType.Invite)); + + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(86) + " " + m.RawName); + + NewGump(); + return; + } + + if (Data.GetData(Current).Friends.Contains(m)) + Data.GetData(Current).RemoveFriend(m); + else + Data.GetData(Current).AddFriend(m); + + NewGump(); + } + + private void Ignore(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).Ignores.Contains(o)) + Data.GetData(Current).RemoveIgnore((Mobile)o); + else + Data.GetData(Current).AddIgnore((Mobile)o); + + NewGump(); + } + + private void Message(object o) + { + if (!(o is Mobile)) + return; + + NewGump(); + + if (Current != Owner) + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(225)); + else if (Chat3.Message.CanMessage(Owner, (Mobile)o)) + new SendMessageGump(Owner, (Mobile)o, "", null, MsgType.Normal); + } + + private void Ban(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (Data.GetData(m).Banned) + { + Data.GetData(m).RemoveBan(); + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(78) + " " + m.RawName); + NewGump(); + } + else + new BanGump(m, this); + } + + private void GIgnore(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).GIgnores.Contains(o)) + Data.GetData(Current).RemoveGIgnore((Mobile)o); + else + Data.GetData(Current).AddGIgnore((Mobile)o); + + NewGump(); + } + + private void GListen(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).GListens.Contains(o)) + Data.GetData(Current).RemoveGListen((Mobile)o); + else + Data.GetData(Current).AddGListen((Mobile)o); + + NewGump(); + } + + private void Client(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + NewGump(); + + if (m.NetState == null) + Owner.SendMessage(Data.GetData(Current).SystemC, m.RawName + " " + General.Local(83)); + else + Owner.SendGump(new ClientGump(Owner, m.NetState)); + } + + private void Goto(object o) + { + if (!(o is Mobile)) + return; + + Mobile m = (Mobile)o; + + if (m.NetState == null) + Owner.SendMessage(Data.GetData(Current).SystemC, m.RawName + " " + General.Local(83)); + else + { + Owner.Location = m.Location; + Owner.Map = m.Map; + } + + NewGump(); + } + + private void QuickBar() + { + Data.GetData(Current).QuickBar = !Data.GetData(Current).QuickBar; + NewGump(); + } + + private void Search() + { + c_Search = !c_Search; + NewGump(); + } + + protected void ViewChannel(object o) + { + if (!(o is Channel)) + return; + + Data.GetData(Current).CurrentChannel = (Channel)o; + c_ListPage = ListPage.Channel; + NewGump(); + } + + protected void Page(object o) + { + if (!(o is ListPage)) + return; + + c_ListPage = (ListPage)o; + NewGump(); + } + + protected void History() + { + NewGump(); + new HistoryGump(Owner, Data.GetData(Current).CurrentChannel); + } + + protected void GenOpt() + { + NewGump(); + new GeneralGump(Owner); + } + + protected void Logging() + { + NewGump(); + new LoggingGump(Owner); + } + + protected void Filter() + { + NewGump(); + new FilterGump(Owner); + } + + protected void Spam() + { + NewGump(); + new SpamGump(Owner); + } + + protected void Colors() + { + NewGump(); + + if(c_Target == null ) + new ColorsGump(Owner); + else + new ColorsGump(Owner, c_Target); + } + + protected void Irc() + { + NewGump(); + new IrcGump(Owner); + } + + protected void Multi() + { + NewGump(); + new MultiGump(Owner); + } + + protected void Mail() + { + NewGump(); + + if (c_Target == null) + new MailGump(Owner); + else + new MailGump(Owner, c_Target); + } + + protected void GlobalMenu() + { + NewGump(); + new GlobalGump(Current); + } + + protected void Channel() + { + NewGump(); + new ChannelGump(Owner); + } + + private void TxtSearch() + { + c_TxtSearch = GetTextField("Search"); + c_CharSearch = ""; + + NewGump(); + } + + private void CharSearch(object o) + { + if (!(o is string)) + return; + + if (c_CharSearch == o.ToString()) + c_CharSearch = ""; + else + c_CharSearch = o.ToString(); + + c_TxtSearch = ""; + + NewGump(); + } + + private void Status() + { + new StatusGump(Owner, this); + } + + private void Broadcast() + { + NewGump(); + new SendMessageGump(Owner, null, "", null, MsgType.System); + } + + private void BroadcastStaff() + { + NewGump(); + new SendMessageGump(Owner, null, "", null, MsgType.Staff); + } + + private void NewNotif() + { + new Notification(); + NewGump(); + } + + private void ClearViewing() + { + c_Target = null; + NewGump(); + } + + private void CheckMsg(object obj) + { + if (!(obj is Mobile)) + return; + + NewGump(); + Data.GetData(Owner).CheckMsgFrom((Mobile)obj); + } + + private void Views() + { + new ViewsGump(Current, this); + } + + private void Channels() + { + new ChannelSelectGump(Current, this); + } + + private void Options() + { + new OptionsGump(Current, this); + } + + private void SkinChange(object obj) + { + if (!(obj is Skin)) + return; + + Data.GetData(Owner).MenuSkin = (Skin)obj; + General.List(Owner, (int)c_ListPage); + } + + #endregion + + #region Internal Classes + + private class InternalSort : IComparer + { + GumpPlus c_Gump; + + public InternalSort(GumpPlus g) + { + c_Gump = g; + } + + public int Compare(object x, object y) + { + if (x is Mobile && y is Mobile) + { + if (((Mobile)x).NetState == null && ((Mobile)y).NetState != null) + return 1; + if (((Mobile)x).NetState != null && ((Mobile)y).NetState == null) + return -1; + + if (!Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)x)) && Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)y))) + return 1; + if (Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)x)) && !Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)y))) + return -1; + + if (((Mobile)x).AccessLevel < ((Mobile)y).AccessLevel) + return 1; + if (((Mobile)x).AccessLevel > ((Mobile)y).AccessLevel) + return -1; + + return Insensitive.Compare(((Mobile)x).Name, ((Mobile)y).Name); + } + else if (x is string && y is string) + return Insensitive.Compare(x.ToString(), y.ToString()); + else if (x is string) + return 1; + else if (y is string) + return -1; + else if (x is Message && y is Message) + { + if (((Message)x).Received > ((Message)y).Received) + return -1; + if (((Message)x).Received < ((Message)y).Received) + return 1; + } + + return Insensitive.Compare(x.ToString(), y.ToString()); + } + } + + private class BanGump : GumpPlus + { + private GumpPlus c_Gump; + private Mobile c_Target; + + public BanGump(Mobile m, GumpPlus g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(160)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + AddHtml(0, y += 20, width, General.Local(161)); + AddButton(width / 2 - 60, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddHtml(0, y += 20, width, General.Local(162)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddHtml(0, y += 20, width, General.Local(163)); + AddButton(width / 2 - 60, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddButton(width / 2 + 50, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddHtml(0, y += 20, width, General.Local(164)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddHtml(0, y += 20, width, General.Local(165)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddHtml(0, y += 20, width, General.Local(166)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddHtml(0, y += 20, width, General.Local(167)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack); + } + + private void BanTime(object o) + { + if (!(o is TimeSpan)) + return; + + Data.GetData(c_Target).Ban((TimeSpan)o); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(77) + " " + c_Target.RawName); + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class ChannelSelectGump : GumpPlus + { + private ListGump10 c_Gump; + private Mobile c_Target; + + public ChannelSelectGump(Mobile m, ListGump10 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(38)); + AddImage(10, y + 2, 0x39); + AddImage(width - 40, y + 2, 0x3B); + + y += 5; + + foreach (Chat3.Channel c in Chat3.Channel.Channels) + { + if (!c.CanChat(c_Target, false)) + continue; + + AddHtml(40, y += 20, width - 40, (Data.GetData(c_Target).CurrentChannel == c ? HTML.Yellow : HTML.White) + "
" + (c.Style == ChatStyle.Regional ? c.Name : c.NameFor(c_Target))); + AddButton(20, y, c.IsIn(c_Target) ? 0x2343 : 0x2342, "Join Channel", new GumpStateCallback(JoinChannel), c); + + if (c.IsIn(c_Target)) + { + AddButton(40 + (width - 40) / 2 - 40, y + 3, 0x2716, "View Channel", new GumpStateCallback(c_Gump.ViewChannel), c); + AddButton(40 + (width - 40) / 2 + 30, y + 3, 0x2716, "View Channel", new GumpStateCallback(c_Gump.ViewChannel), c); + } + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + private void JoinChannel(object o) + { + Channel c = o as Channel; + + if (c == null) + return; + + if (c.IsIn(c_Target)) + c.Leave(c_Target); + else + c.Join(c_Target); + + NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class OptionsGump : GumpPlus + { + private ListGump10 c_Gump; + private Mobile c_Target; + + public OptionsGump(Mobile m, ListGump10 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(40)); + AddImage(10, y + 2, 0x39); + AddImage(width - 40, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(49)); + AddButton(20, y + 3, 0x2716, "Colors", new GumpCallback(c_Gump.Colors)); + AddButton(width - 30, y + 3, 0x2716, "Colors", new GumpCallback(c_Gump.Colors)); + AddHtml(0, y += 20, width, "
" + General.Local(56)); + AddButton(20, y + 3, 0x2716, "Mail", new GumpCallback(c_Gump.Mail)); + AddButton(width - 30, y + 3, 0x2716, "Mail", new GumpCallback(c_Gump.Mail)); + + if (Data.GetData(c_Target).GlobalAccess) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(43)); + AddButton(20, y + 3, 0x2716, "Global Menu", new GumpCallback(c_Gump.GlobalMenu)); + AddButton(width - 30, y + 3, 0x2716, "Global Menu", new GumpCallback(c_Gump.GlobalMenu)); + } + + if (c_Target.AccessLevel >= AccessLevel.Administrator) + { + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(207)); + AddButton(20, y + 3, 0x2716, "General", new GumpCallback(c_Gump.GenOpt)); + AddButton(width - 30, y + 3, 0x2716, "General", new GumpCallback(c_Gump.GenOpt)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(237)); + AddButton(20, y + 3, 0x2716, "Logging", new GumpCallback(c_Gump.Logging)); + AddButton(width - 30, y + 3, 0x2716, "Logging", new GumpCallback(c_Gump.Logging)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(208)); + AddButton(20, y + 3, 0x2716, "Filter", new GumpCallback(c_Gump.Filter)); + AddButton(width - 30, y + 3, 0x2716, "Filter", new GumpCallback(c_Gump.Filter)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(209)); + AddButton(20, y + 3, 0x2716, "Spam", new GumpCallback(c_Gump.Spam)); + AddButton(width - 30, y + 3, 0x2716, "Spam", new GumpCallback(c_Gump.Spam)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(210)); + AddButton(20, y + 3, 0x2716, "Irc", new GumpCallback(c_Gump.Irc)); + AddButton(width - 30, y + 3, 0x2716, "Irc", new GumpCallback(c_Gump.Irc)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(287)); + AddButton(20, y + 3, 0x2716, "Multi", new GumpCallback(c_Gump.Multi)); + AddButton(width - 30, y + 3, 0x2716, "Multi", new GumpCallback(c_Gump.Multi)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(50)); + AddButton(20, y + 3, 0x2716, "Channel", new GumpCallback(c_Gump.Channel)); + AddButton(width - 30, y + 3, 0x2716, "Channel", new GumpCallback(c_Gump.Channel)); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class ViewsGump : GumpPlus + { + private ListGump10 c_Gump; + private Mobile c_Target; + + public ViewsGump(Mobile m, ListGump10 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(1)); + AddImage(0 + 10, y + 2, 0x39); + AddImage(0 + width - 40, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(46)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.All); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.All); + AddHtml(0, y += 20, width, "
" + General.Local(56)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Mail); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Mail); + AddHtml(0, y += 20, width, "
" + General.Local(203)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Friends); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Friends); + AddHtml(0, y += 20, width, "
" + General.Local(51)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Ignores); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Ignores); + + AddHtml(0, y += 20, width, (c_Gump.CurrentPage == ListPage.Channel ? "" : HTML.Gray) + "
" + General.Local(206)); + if (c_Gump.CurrentPage == ListPage.Channel) + { + AddButton(20, y + 3, 0x2716, "History", new GumpCallback(c_Gump.History)); + AddButton(width - 30, y + 3, 0x2716, "History", new GumpCallback(c_Gump.History)); + } + + if (Data.GetData(c_Target).GlobalAccess) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(204)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GIgnores); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GIgnores); + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(205)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GListens); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GListens); + } + + if (c_Target.AccessLevel > AccessLevel.GameMaster) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(54)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Bans); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Bans); + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(269)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Notifications); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Notifications); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class StatusGump : GumpPlus + { + private GumpPlus c_Gump; + + public StatusGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + m.CloseGump(typeof(StatusGump)); + + c_Gump = g; + } + + protected override void BuildGump() + { + int width = 100; + int y = 20; + + AddHtml(0, y, width, "
" + General.Local(19)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Online", new GumpStateCallback(Status), OnlineStatus.Online); + AddButton(width / 2 + 40, y + 3, 0x2716, "Online", new GumpStateCallback(Status), OnlineStatus.Online); + AddHtml(0, y += 20, width, "
" + General.Local(20)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Away", new GumpStateCallback(Status), OnlineStatus.Away); + AddButton(width / 2 + 40, y + 3, 0x2716, "Away", new GumpStateCallback(Status), OnlineStatus.Away); + AddHtml(0, y += 20, width, "
" + General.Local(21)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Busy", new GumpStateCallback(Status), OnlineStatus.Busy); + AddButton(width / 2 + 40, y + 3, 0x2716, "Busy", new GumpStateCallback(Status), OnlineStatus.Busy); + AddHtml(0, y += 20, width, "
" + General.Local(22)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Hidden", new GumpStateCallback(Status), OnlineStatus.Hidden); + AddButton(width / 2 + 40, y + 3, 0x2716, "Hidden", new GumpStateCallback(Status), OnlineStatus.Hidden); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Status(object o) + { + if (!(o is OnlineStatus)) + return; + + Data.GetData(Owner).Status = (OnlineStatus)o; + + if ((OnlineStatus)o == OnlineStatus.Away || (OnlineStatus)o == OnlineStatus.Busy) + new AwayGump(Owner, c_Gump); + else + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + + private class AwayGump : GumpPlus + { + private GumpPlus c_Gump; + + public AwayGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + m.CloseGump(typeof(AwayGump)); + + c_Gump = g; + } + + protected override void BuildGump() + { + AddBackground(0, 0, 200, 200, Data.GetData(Owner).DefaultBack); + + AddHtml(0, 10, 200, "
" + General.Local(12)); + AddTextField(10, 30, 180, 120, 0x480, 0xBBC, "Away", Data.GetData(Owner).AwayMsg); + AddButton(60, 160, 0xFB1, 0xFB3, "Clear", new GumpCallback(ClearMsg)); + AddButton(120, 160, 0xFB7, 0xFB9, "Submit", new GumpCallback(Submit)); + } + + private void ClearMsg() + { + Data.GetData(Owner).AwayMsg = ""; + + NewGump(); + } + + private void Submit() + { + Data.GetData(Owner).AwayMsg = GetTextField("Away"); + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/1.0 Skin/PmNotifyGump10.cs b/Scripts/Customs/KniveChat/Gumps/1.0 Skin/PmNotifyGump10.cs new file mode 100644 index 0000000..0779033 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/1.0 Skin/PmNotifyGump10.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class PmNotifyGump10 : GumpPlus + { + public PmNotifyGump10( Mobile m ) : base( m, 200, 50 ) + { + m.CloseGump( typeof( PmNotifyGump10 ) ); + } + + protected override void BuildGump() + { + if (Data.GetData(Owner).GetMsg() != null) + { + int offset = 30; + int width = 120; + + AddBackground(offset, 0, width, 60, Data.GetData(Owner).DefaultBack); + + AddButton(0, 15, 0x2634, 0x2635, "Message", new GumpCallback(Message)); + AddHtml(offset, 8, width, 45, "
Message from
" + Data.GetData(Owner).GetMsg().From.RawName, false, false); + AddHtml(5, 17, 25, "
" + Data.GetData(Owner).Messages.Count); + } + } + + private void Message() + { + Data.GetData(Owner).CheckMsg(); + + if (Data.GetData(Owner).NewMsg()) + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/2.0 Skin/ListGump20.cs b/Scripts/Customs/KniveChat/Gumps/2.0 Skin/ListGump20.cs new file mode 100644 index 0000000..2ec4a14 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/2.0 Skin/ListGump20.cs @@ -0,0 +1,1399 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class ListGump20 : GumpPlus + { + public enum ListPage { All, Channel, Mail, Friends, Ignores, GIgnores, GListens, Bans, Notifications } + + #region Class Definitions + + private ListPage c_ListPage; + private Mobile c_Target; + private int c_Page; + private bool c_Menu, c_Search; + private string c_TxtSearch = ""; + private string c_CharSearch = ""; + + protected ListPage CurrentPage { get { return c_ListPage; } } + public Mobile Current { get { return (c_Target == null ? Owner : c_Target); } } + + #endregion + + #region Constructors + + public ListGump20(Mobile m, int page) + : base(m, 100, 100) + { + c_ListPage = (ListPage)page; + + m.CloseGump(typeof(ListGump20)); + + Override = true; + } + + public ListGump20(Mobile m, Mobile targ) + : base(m, 100, 100) + { + c_Target = targ; + + m.CloseGump(typeof(ListGump20)); + + Override = true; + } + + public ListGump20(Mobile m) + : this(m, null) + { + m.CloseGump(typeof(ListGump20)); + + Override = true; + } + + #endregion + + #region Methods + + protected override void BuildGump() + { + if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel == null) + c_ListPage = ListPage.All; + + int width = Data.GetData(Current).QuickBar ? 250 : 200; + int y = 10; + int perpage = 10; + int bar = width - 18; + + if (c_ListPage == ListPage.Mail || (c_ListPage == ListPage.Channel && (Data.GetData(Current).CurrentChannel is Guild || Data.GetData(Current).CurrentChannel is Faction))) + perpage /= 2; + + if (c_Search) + ShowSearch(width); + + ArrayList list = GetList(); + SearchFilter(list); + list.Sort(new InternalSort(this)); + + if (c_Page != 0) + AddButton(width / 2 - 10, y - 5, 0x15E0, 0x15E4, "Page Down", new GumpCallback(PageDown)); + + if (c_Target != null) + { + AddHtml(0, y += 25, width, "
" + General.Local(224) + " " + c_Target.RawName); + AddButton(width / 2 - 80, y, 0x5686, "Clear Viewing", new GumpCallback(ClearViewing)); + AddButton(width / 2 + 65, y, 0x5686, "Clear Viewing", new GumpCallback(ClearViewing)); + } + + y += 5; + + for (int i = c_Page * perpage; i < (c_Page + 1) * perpage && i < list.Count; ++i) + { + if (list[i] is string) + { + if (list[i].ToString().IndexOf("@") == 0) + list[i] = list[i].ToString().Substring(1, list[i].ToString().Length - 1); + + AddHtml(35, y += 20, width - 35, list[i].ToString()); + AddButton(width - 40, y, Data.GetData(Current).IrcIgnores.Contains(list[i].ToString()) ? 0x5687 : 0x5686, "Ignore IRC", new GumpStateCallback(IgnoreIrc), list[i]); + } + else if(list[i] is Mobile) + { + AddHtml(35, y += 20, width - 35, ColorFor((Mobile)list[i]) + ((Mobile)list[i]).RawName + StatusFor((Mobile)list[i])); + if(Current == Owner && Data.GetData(Owner).NewMsgFrom((Mobile)list[i])) + AddButton(20, y, 0x1523, "Check Msg", new GumpStateCallback(CheckMsg), (Mobile)list[i]); + else + AddButton(20, y + 3, 0x2716, "Profile", new GumpStateCallback(Profile), (Mobile)list[i]); + + if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel is Guild) + AddHtml(35, y += 20, width - 35, ((Mobile)list[i]).GuildTitle); + else if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel is Faction) + AddHtml(35, y += 20, width - 35, General.FactionTitle((Mobile)list[i])); + + if (list[i] != Current && Data.GetData(Current).QuickBar) + { + bar = width - 18; + + if (Current.AccessLevel > ((Mobile)list[i]).AccessLevel) + { + if (Data.GetData(Current).GlobalAccess) + { + if (Data.GetData(Current).Global) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ignore", new GumpStateCallback(GIgnore), list[i]); + AddLabel(bar + 4, y, Data.GetData(Current).GIgnores.Contains(list[i]) ? 0x44 : 0x26, "I"); + } + else + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Listen", new GumpStateCallback(GListen), list[i]); + AddLabel(bar + 4, y, Data.GetData(Current).GListens.Contains(list[i]) ? 0x44 : 0x26, "L"); + } + } + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ban", new GumpStateCallback(Ban), list[i]); + AddLabel(bar + 4, y, Data.GetData((Mobile)list[i]).Banned ? 0x44 : 0x26, "b"); + } + + if (Current.AccessLevel >= AccessLevel.GameMaster && ((Mobile)list[i]).NetState != null) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Goto", new GumpStateCallback(Goto), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "g"); + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Client", new GumpStateCallback(Client), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "c"); + } + + if (Chat3.Message.CanMessage(Current, (Mobile)list[i])) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Message", new GumpStateCallback(Message), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "m"); + } + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ignore", new GumpStateCallback(Ignore), list[i]); + AddLabel(bar + 5, y - 1, Data.GetData(Current).Ignores.Contains(list[i]) ? 0x44 : 0x26, "i"); + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Friend", new GumpStateCallback(Friend), list[i]); + AddLabel(bar + 3, y, Data.GetData(Current).Friends.Contains(list[i]) ? 0x44 : 0x26, "f"); + } + } + else if (list[i] is Message) + { + Message msg = (Message)list[i]; + + AddHtml(45, y += 20, width-85, ColorFor(msg) + (msg.Read ? "" : "") + msg.Subject, false); + AddHtml(45, y += 16, width-85, General.Local(60) + " " + msg.From.RawName); + + AddButton(20, y - 10, 0x2716, "Open", new GumpStateCallback(Open), (Message)list[i]); + AddButton(width - 40, y - 10, 0x5686, 0x5687, "Delete", new GumpStateCallback(Delete), (Message)list[i]); + } + else if (list[i] is Notification) + { + Notification not = (Notification)list[i]; + + AddHtml(45, y += 20, width-85, ColorFor(not) + not.Name); + + AddButton(20, y + 3, 0x2716, "Edit Notif", new GumpStateCallback(EditNotif), (Notification)list[i]); + AddButton(width - 40, y + 3, 0x5686, 0x5687, "Delete", new GumpStateCallback(Delete), (Notification)list[i]); + } + + if (i + 1 < list.Count && i + 1 < (c_Page+1)*perpage) + AddBackground(50, y + 18, width - 100, 3, 0x13BE); + } + + if (c_ListPage == ListPage.Mail && Current.AccessLevel >= AccessLevel.GameMaster) + { + AddHtml(0, y += 25, width, "
" + General.Local(95), false); + AddButton(width / 2 - 50, y + 3, 0x2716, "Broadcast", new GumpCallback(Broadcast)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Broadcast", new GumpCallback(Broadcast)); + + AddHtml(0, y += 20, width, "
" + General.Local(257), false); + AddButton(width / 2 - 50, y + 3, 0x2716, "Staff", new GumpCallback(BroadcastStaff)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Staff", new GumpCallback(BroadcastStaff)); + } + else if (c_ListPage == ListPage.Notifications) + { + AddHtml(0, y += 25, width, "
" + General.Local(270), false); + AddButton(width / 2 - 70, y + 3, 0x2716, "New Notif", new GumpCallback(NewNotif)); + AddButton(width / 2 + 60, y + 3, 0x2716, "New Notif", new GumpCallback(NewNotif)); + } + + if (perpage * (c_Page + 1) < list.Count) + AddButton(width / 2 - 10, y+=25, 0x15E2, 0x15E6, "Page Up", new GumpCallback(PageUp)); + + if (c_ListPage == ListPage.Mail) + AddHtml(0, y += 20, width, "
" + Data.GetData(Owner).Messages.Count + " / " + Data.MaxMsgs); + else if(c_ListPage != ListPage.Notifications) + { + ArrayList states = new ArrayList(Server.Network.NetState.Instances); + foreach (Server.Network.NetState state in Server.Network.NetState.Instances) + if (state.Mobile != null && state.Mobile.AccessLevel != AccessLevel.Player) + states.Remove(state); + + AddHtml(0, y += 20, width, "
" + states.Count + " " + General.Local(19)); + } + + if (c_Menu) + y = ShowFullMenu(y, width); + else + { + AddButton(33+(50/2), (y += 25)+3, 0x29F6, "Full List", new GumpCallback(FullList)); + AddHtml(40, y, 50, "
" + GetTitle()); + AddButton(10, y, c_Menu ? 0x15E0 : 0x15E2, c_Menu ? 0x15E4 : 0x15E6, "Menu", new GumpCallback(Menu)); + } + + AddButton(width- 110, y, 0x5689, "Help", new GumpCallback(Help)); + AddButton(width - 95, y, 0x5689, "Profile", new GumpStateCallback(Profile), Current); + AddLabel(width - 92, y-1, 0x47E, "P"); + AddButton(width - 80, y, 0x5689, "Options", new GumpCallback(Options)); + AddLabel(width - 77, y-1, 0x47E, "O"); + AddButton(width - 65, y, 0x5689, "Status", new GumpCallback(Status)); + AddLabel(width - 62, y-1, Data.GetData(Current).Status == OnlineStatus.Online ? 0x47E : 0x34, "A"); + AddButton(width - 50, y, 0x5689, "QuickBar", new GumpCallback(QuickBar)); + AddLabel(width - 47, y-1, Data.GetData(Current).QuickBar ? 0x34 : 0x47E, "Q"); + AddButton(width - 35, y, 0x5689, "Search", new GumpCallback(Search)); + AddLabel(width - 32, y-1, c_Search ? 0x34 : 0x47E, "S"); + + AddBackgroundZero(0, 0, width, y + 20, Data.GetData(Current).DefaultBack); + } + + private int ShowFullMenu(int y, int width) + { + AddButton(width / 2 - 83 + (50/2), (y += 25)+3, 0x29F6, "Channels", new GumpCallback(Channels)); + AddHtml(width / 2 - 75, y, 50, (c_ListPage == ListPage.Channel ? HTML.Green : "") + "
" + (c_ListPage == ListPage.Channel ? GetTitle() : General.Local(38))); + + AddButton(width / 2 - 33 + (50 / 2), y + 3, 0x29F6, "Friends", new GumpStateCallback(Page), ListPage.Friends); + AddHtml(width / 2 - 25, y, 50, (c_ListPage == ListPage.Friends ? HTML.Green : "") + "
" + General.Local(203)); + + AddButton(width / 2 + 27 + (50 / 2), y + 3, 0x29F6, "Ignores", new GumpStateCallback(Page), ListPage.Ignores); + AddHtml(width / 2 + 35, y, 50, (c_ListPage == ListPage.Ignores ? HTML.Green : "") + "
" + General.Local(51)); + + AddButton(width / 2 - 83 + (50 / 2), (y += 15) + 3, 0x29F6, "All", new GumpStateCallback(Page), ListPage.All); + AddHtml(width / 2 - 75, y, 50, (c_ListPage == ListPage.All ? HTML.Green : "") + "
" + General.Local(46)); + + AddButton(width / 2 - 33 + (50 / 2), y + 3, 0x29F6, "Mail", new GumpStateCallback(Page), ListPage.Mail); + AddHtml(width / 2 - 25, y, 50, (c_ListPage == ListPage.Mail ? HTML.Green : "") + "
" + General.Local(56)); + + AddButton(width / 2 + 27 + (50 / 2), y + 3, 0x29F6, "Views", new GumpCallback(Views)); + AddHtml(width / 2 + 35, y, 50, "
" + General.Local(1)); + + AddButton(width / 2 - 30, y += 25, 0x8B1, "1.0", new GumpStateCallback(SkinChange), Skin.One); + AddButton(width / 2 - 10, y, 0x8B2, "2.0", new GumpStateCallback(SkinChange), Skin.Two); + AddButton(width / 2 + 10, y, 0x8B3, "3.0", new GumpStateCallback(SkinChange), Skin.Three); + + AddButton(10, y += 25, c_Menu ? 0x15E0 : 0x15E2, c_Menu ? 0x15E4 : 0x15E6, "Menu", new GumpCallback(Menu)); + + return y; + } + + private void ShowSearch(int x) + { + int width = 130; + + AddBackground(x, 0, width, 50, Data.GetData(Current).DefaultBack, false); + + AddImage(x - 8, 10, 0x100); + AddTextField(x+15, 15, 90, 21, 0x480, 0xBBC, "Search", c_TxtSearch); + AddButton(x + width-17, 19, 0x2716, "Text Search", new GumpCallback(TxtSearch)); + + char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + + int difx = x-13; + int y = 61; + + foreach (char c in chars) + { + AddButton(difx += 20, y, 0x2344, "Char Search", new GumpStateCallback(CharSearch), c.ToString()); + AddHtml(difx + 6, y, 20, (c_CharSearch == c.ToString() ? HTML.Green : "") + c, false); + + if (difx >= x + 102) + { + difx = x-13; + y += 20; + } + } + } + + private string GetTitle() + { + switch (c_ListPage) + { + case ListPage.All: return General.Local(46); + case ListPage.Channel: return Data.GetData(Current).CurrentChannel.NameFor(Current); + case ListPage.Mail: return General.Local(56); + case ListPage.Friends: return General.Local(203); + case ListPage.Ignores: return General.Local(51); + case ListPage.GIgnores: return General.Local(204); + case ListPage.GListens: return General.Local(205); + case ListPage.Bans: return General.Local(54); + case ListPage.Notifications: return General.Local(269); + } + + return ""; + } + + private ArrayList GetList() + { + ArrayList list; + + switch (c_ListPage) + { + case ListPage.All: + list = new ArrayList(); + foreach (Data data in Data.Datas.Values) + if (Current.AccessLevel >= data.Mobile.AccessLevel) + list.Add(data.Mobile); + return list; + case ListPage.Channel: return new ArrayList(Data.GetData(Current).CurrentChannel.BuildList(Current)); + case ListPage.Mail: return new ArrayList(Data.GetData(Current).Messages); + case ListPage.Friends: return new ArrayList(Data.GetData(Current).Friends); + case ListPage.Ignores: return new ArrayList(Data.GetData(Current).Ignores); + case ListPage.GIgnores: return new ArrayList(Data.GetData(Current).GIgnores); + case ListPage.GListens: return new ArrayList(Data.GetData(Current).GListens); + case ListPage.Bans: + list = new ArrayList(); + foreach (Data data in Data.Datas.Values) + if (data.Banned) + list.Add(data.Mobile); + return list; + case ListPage.Notifications: return new ArrayList(Data.Notifications); + } + + return new ArrayList(); + } + + private void SearchFilter(ArrayList list) + { + string txt = ""; + foreach (object obj in new ArrayList(list)) + { + if (obj is Mobile) + txt = ((Mobile)obj).RawName; + else if (obj is Message) + txt = ((Message)obj).From.RawName; + else + txt = obj.ToString(); + + if (c_CharSearch.ToLower() != "" && txt.ToLower().IndexOf(c_CharSearch) != 0) + list.Remove(obj); + else if (c_TxtSearch.ToLower() != "" && txt.ToLower().IndexOf(c_TxtSearch) == -1) + list.Remove(obj); + } + } + + private string ColorFor(Message msg) + { + switch (msg.Type) + { + case MsgType.Normal: return HTML.White; + case MsgType.Invite: return HTML.Yellow; + case MsgType.System: return HTML.Red; + case MsgType.Staff: return HTML.Purple; + default: return HTML.White; + } + } + + private string ColorFor(Notification not) + { + return HTML.White; + } + + private string ColorFor(Mobile m) + { + if (Current == m) + return HTML.Yellow; + if (Data.GetData(m).Banned) + return HTML.Red; + if (Data.GetData(Current).Ignores.Contains(m)) + return HTML.AshRed; + if (Data.GetData(Current).Global && Data.GetData(Current).GIgnores.Contains(m)) + return HTML.AshRed; + if (!Data.GetData(Current).Global && Data.GetData(Current).GListens.Contains(m)) + return HTML.Blue; + if (m.NetState == null || Data.GetData(m).Status == OnlineStatus.Hidden) + return HTML.DarkGray; + if (Data.GetData(m).Status == OnlineStatus.Away || Data.GetData(m).Status == OnlineStatus.Busy) + return HTML.Gray; + if (m.AccessLevel > AccessLevel.Player) + return HTML.LightPurple; + if (m.Guild != null && (m.Guild == Current.Guild)) + return HTML.Green; + + return HTML.White; + } + + private string StatusFor(Mobile m) + { + if (Data.GetData(m).Status == OnlineStatus.Away) + return " (Away)"; + else if (Data.GetData(m).Status == OnlineStatus.Busy) + return " (Busy)"; + else if (Data.GetData(m).Status == OnlineStatus.Hidden) + return " (Hidden)"; + + return ""; + } + + #endregion + + #region Responses + + private void PageUp() + { + c_Page++; + NewGump(); + } + + private void PageDown() + { + c_Page--; + NewGump(); + } + + private void Help() + { + NewGump(); + new HelpContentsGump(Owner); + } + + private void IgnoreIrc(object o) + { + if (!(o is string)) + return; + + if (Data.GetData(Current).IrcIgnores.Contains(o.ToString())) + Data.GetData(Current).RemoveIrcIgnore(o.ToString()); + else + Data.GetData(Current).AddIrcIgnore(o.ToString()); + + NewGump(); + } + + private void Profile(object o) + { + if (!(o is Mobile)) + return; + + NewGump(); + new ProfileGump(Owner, (Mobile)o); + } + + private void Open(object o) + { + Message m = o as Message; + + if (m == null) + return; + + if (Data.GetData(Owner).Messages.Contains(m)) + m.Read = true; + + NewGump(); + + if (m.Read && Data.GetData(m.From).ReadReceipt && m.From.AccessLevel >= Owner.AccessLevel) + m.From.SendMessage(Data.GetData(m.From).SystemC, Owner.RawName + " " + General.Local(197) + " " + m.Subject); + + new MessageGump(Owner, m); + } + + private void EditNotif(object o) + { + if (!(o is Notification)) + return; + + NewGump(); + new EditNotGump(Owner, (Notification)o); + } + + private void Delete(object o) + { + if (o is Message) + Data.GetData(Current).DeleteMessage((Message)o); + else if (o is Notification) + Data.Notifications.Remove(o); + + NewGump(); + } + + private void Friend(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (Data.GetData(m).ByRequest && !Data.GetData(Current).Friends.Contains(m)) + { + if (!TrackSpam.LogSpam(Current, "Request " + m.RawName, TimeSpan.FromHours(Data.RequestSpam))) + { + TimeSpan ts = TrackSpam.NextAllowedIn(Current, "Request " + m.RawName, TimeSpan.FromHours(Data.RequestSpam)); + string txt = (ts.Days != 0 ? ts.Days + " " + General.Local(170) + " " : "") + (ts.Hours != 0 ? ts.Hours + " " + General.Local(171) + " " : "") + (ts.Minutes != 0 ? ts.Minutes + " " + General.Local(172) + " " : ""); + + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(96) + " " + txt); + NewGump(); + return; + } + + Data.GetData(m).AddMessage(new Message(Current, General.Local(84), General.Local(85), MsgType.Invite)); + + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(86) + " " + m.RawName); + + NewGump(); + return; + } + + if (Data.GetData(Current).Friends.Contains(m)) + Data.GetData(Current).RemoveFriend(m); + else + Data.GetData(Current).AddFriend(m); + + NewGump(); + } + + private void Ignore(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).Ignores.Contains(o)) + Data.GetData(Current).RemoveIgnore((Mobile)o); + else + Data.GetData(Current).AddIgnore((Mobile)o); + + NewGump(); + } + + private void Message(object o) + { + if (!(o is Mobile)) + return; + + NewGump(); + + if (Current != Owner) + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(225)); + else if (Chat3.Message.CanMessage(Owner, (Mobile)o)) + new SendMessageGump(Owner, (Mobile)o, "", null, MsgType.Normal); + } + + private void Ban(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (Data.GetData(m).Banned) + { + Data.GetData(m).RemoveBan(); + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(78) + " " + m.RawName); + NewGump(); + } + else + new BanGump(m, this); + } + + private void GIgnore(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).GIgnores.Contains(o)) + Data.GetData(Current).RemoveGIgnore((Mobile)o); + else + Data.GetData(Current).AddGIgnore((Mobile)o); + + NewGump(); + } + + private void GListen(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).GListens.Contains(o)) + Data.GetData(Current).RemoveGListen((Mobile)o); + else + Data.GetData(Current).AddGListen((Mobile)o); + + NewGump(); + } + + private void Client(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + NewGump(); + + if (m.NetState == null) + Owner.SendMessage(Data.GetData(Current).SystemC, m.RawName + " " + General.Local(83)); + else + Owner.SendGump(new ClientGump(Owner, m.NetState)); + } + + private void Goto(object o) + { + if (!(o is Mobile)) + return; + + Mobile m = (Mobile)o; + + if (m.NetState == null) + Owner.SendMessage(Data.GetData(Current).SystemC, m.RawName + " " + General.Local(83)); + else + { + Owner.Location = m.Location; + Owner.Map = m.Map; + } + + NewGump(); + } + + private void QuickBar() + { + Data.GetData(Current).QuickBar = !Data.GetData(Current).QuickBar; + NewGump(); + } + + private void Menu() + { + c_Menu = !c_Menu; + NewGump(); + } + + private void Search() + { + c_Search = !c_Search; + NewGump(); + } + + protected void ViewChannel(object o) + { + if (!(o is Channel)) + return; + + Data.GetData(Current).CurrentChannel = (Channel)o; + c_ListPage = ListPage.Channel; + NewGump(); + } + + protected void Page(object o) + { + if (!(o is ListPage)) + return; + + c_ListPage = (ListPage)o; + NewGump(); + } + + protected void History() + { + NewGump(); + new HistoryGump(Owner, Data.GetData(Current).CurrentChannel); + } + + protected void GenOpt() + { + NewGump(); + new GeneralGump(Owner); + } + + protected void Logging() + { + NewGump(); + new LoggingGump(Owner); + } + + protected void Filter() + { + NewGump(); + new FilterGump(Owner); + } + + protected void Spam() + { + NewGump(); + new SpamGump(Owner); + } + + protected void Colors() + { + NewGump(); + + if(c_Target == null ) + new ColorsGump(Owner); + else + new ColorsGump(Owner, c_Target); + } + + protected void Irc() + { + NewGump(); + new IrcGump(Owner); + } + + protected void Multi() + { + NewGump(); + new MultiGump(Owner); + } + + protected void Mail() + { + NewGump(); + + if (c_Target == null) + new MailGump(Owner); + else + new MailGump(Owner, c_Target); + } + + protected void GlobalMenu() + { + NewGump(); + new GlobalGump(Current); + } + + protected void Channel() + { + NewGump(); + new ChannelGump(Owner); + } + + private void TxtSearch() + { + c_TxtSearch = GetTextField("Search"); + c_CharSearch = ""; + + NewGump(); + } + + private void CharSearch(object o) + { + if (!(o is string)) + return; + + if (c_CharSearch == o.ToString()) + c_CharSearch = ""; + else + c_CharSearch = o.ToString(); + + c_TxtSearch = ""; + + NewGump(); + } + + private void Status() + { + new StatusGump(Owner, this); + } + + private void Broadcast() + { + NewGump(); + new SendMessageGump(Owner, null, "", null, MsgType.System); + } + + private void BroadcastStaff() + { + NewGump(); + new SendMessageGump(Owner, null, "", null, MsgType.Staff); + } + + private void NewNotif() + { + new Notification(); + NewGump(); + } + + private void ClearViewing() + { + c_Target = null; + NewGump(); + } + + private void CheckMsg(object obj) + { + if (!(obj is Mobile)) + return; + + NewGump(); + Data.GetData(Owner).CheckMsgFrom((Mobile)obj); + } + + private void FullList() + { + new FullGump(Current, this); + } + + private void Views() + { + new ViewsGump(Current, this); + } + + private void Channels() + { + new ChannelSelectGump(Current, this); + } + + private void Options() + { + new OptionsGump(Current, this); + } + + private void SkinChange(object obj) + { + if (!(obj is Skin)) + return; + + Data.GetData(Owner).MenuSkin = (Skin)obj; + General.List(Owner, (int)c_ListPage); + } + + #endregion + + #region Internal Classes + + private class InternalSort : IComparer + { + GumpPlus c_Gump; + + public InternalSort(GumpPlus g) + { + c_Gump = g; + } + + public int Compare(object x, object y) + { + if (x is Mobile && y is Mobile) + { + if (((Mobile)x).NetState == null && ((Mobile)y).NetState != null) + return 1; + if (((Mobile)x).NetState != null && ((Mobile)y).NetState == null) + return -1; + + if (!Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)x)) && Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)y))) + return 1; + if (Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)x)) && !Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)y))) + return -1; + + if (((Mobile)x).AccessLevel < ((Mobile)y).AccessLevel) + return 1; + if (((Mobile)x).AccessLevel > ((Mobile)y).AccessLevel) + return -1; + + return Insensitive.Compare(((Mobile)x).Name, ((Mobile)y).Name); + } + else if (x is string && y is string) + return Insensitive.Compare(x.ToString(), y.ToString()); + else if (x is string) + return 1; + else if (y is string) + return -1; + else if (x is Message && y is Message) + { + if (((Message)x).Received > ((Message)y).Received) + return -1; + if (((Message)x).Received < ((Message)y).Received) + return 1; + } + + return Insensitive.Compare(x.ToString(), y.ToString()); + } + } + + private class BanGump : GumpPlus + { + private GumpPlus c_Gump; + private Mobile c_Target; + + public BanGump(Mobile m, GumpPlus g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(160)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + AddHtml(0, y += 20, width, General.Local(161)); + AddButton(width / 2 - 60, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddHtml(0, y += 20, width, General.Local(162)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddHtml(0, y += 20, width, General.Local(163)); + AddButton(width / 2 - 60, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddButton(width / 2 + 50, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddHtml(0, y += 20, width, General.Local(164)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddHtml(0, y += 20, width, General.Local(165)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddHtml(0, y += 20, width, General.Local(166)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddHtml(0, y += 20, width, General.Local(167)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack); + } + + private void BanTime(object o) + { + if (!(o is TimeSpan)) + return; + + Data.GetData(c_Target).Ban((TimeSpan)o); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(77) + " " + c_Target.RawName); + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class FullGump : GumpPlus + { + private ListGump20 c_Gump; + private Mobile c_Target; + + public FullGump(Mobile m, ListGump20 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(38)); + AddImage(10, y + 2, 0x39); + AddImage(width - 40, y + 2, 0x3B); + + y += 5; + + foreach (Chat3.Channel c in Chat3.Channel.Channels) + { + if (!c.CanChat(c_Target, false)) + continue; + + AddHtml(40, y += 20, width - 40, (Data.GetData(c_Target).CurrentChannel == c ? HTML.Yellow : HTML.White) + "
" + (c.Style == ChatStyle.Regional ? c.Name : c.NameFor(c_Target))); + AddButton(20, y, c.IsIn(c_Target) ? 0x2343 : 0x2342, "Join Channel", new GumpStateCallback(JoinChannel), c); + + if (c.IsIn(c_Target)) + { + AddButton(40 + (width - 40) / 2 - 40, y + 3, 0x2716, "View Channel", new GumpStateCallback(c_Gump.ViewChannel), c); + AddButton(40 + (width - 40) / 2 + 30, y + 3, 0x2716, "View Channel", new GumpStateCallback(c_Gump.ViewChannel), c); + } + } + + AddHtml(0, y += 25, width, "
" + General.Local(1)); + AddImage(0 + 10, y + 2, 0x39); + AddImage(0 + width - 40, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(46)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.All); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.All); + AddHtml(0, y += 20, width, "
" + General.Local(56)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Mail); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Mail); + AddHtml(0, y += 20, width, "
" + General.Local(203)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Friends); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Friends); + AddHtml(0, y += 20, width, "
" + General.Local(51)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Ignores); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Ignores); + + AddHtml(0, y += 20, width, (c_Gump.CurrentPage == ListPage.Channel ? "" : HTML.Gray) + "
" + General.Local(206)); + if (c_Gump.CurrentPage == ListPage.Channel) + { + AddButton(20, y + 3, 0x2716, "History", new GumpCallback(c_Gump.History)); + AddButton(width - 30, y + 3, 0x2716, "History", new GumpCallback(c_Gump.History)); + } + + if (Data.GetData(c_Target).GlobalAccess) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(204)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GIgnores); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GIgnores); + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(205)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GListens); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GListens); + } + + if (c_Target.AccessLevel > AccessLevel.GameMaster) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(54)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Bans); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Bans); + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(269)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Notifications); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Notifications); + } + + AddHtml(0, y += 25, width, "
" + General.Local(40)); + AddImage(10, y + 2, 0x39); + AddImage(width - 40, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(49)); + AddButton(20, y + 3, 0x2716, "Colors", new GumpCallback(c_Gump.Colors)); + AddButton(width - 30, y + 3, 0x2716, "Colors", new GumpCallback(c_Gump.Colors)); + AddHtml(0, y += 20, width, "
" + General.Local(56)); + AddButton(20, y + 3, 0x2716, "Mail", new GumpCallback(c_Gump.Mail)); + AddButton(width - 30, y + 3, 0x2716, "Mail", new GumpCallback(c_Gump.Mail)); + + if (Data.GetData(c_Target).GlobalAccess) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(43)); + AddButton(20, y + 3, 0x2716, "Global Menu", new GumpCallback(c_Gump.GlobalMenu)); + AddButton(width - 30, y + 3, 0x2716, "Global Menu", new GumpCallback(c_Gump.GlobalMenu)); + } + + if (c_Target.AccessLevel >= AccessLevel.Administrator) + { + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(207)); + AddButton(20, y + 3, 0x2716, "General", new GumpCallback(c_Gump.GenOpt)); + AddButton(width - 30, y + 3, 0x2716, "General", new GumpCallback(c_Gump.GenOpt)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(237)); + AddButton(20, y + 3, 0x2716, "Logging", new GumpCallback(c_Gump.Logging)); + AddButton(width - 30, y + 3, 0x2716, "Logging", new GumpCallback(c_Gump.Logging)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(208)); + AddButton(20, y + 3, 0x2716, "Filter", new GumpCallback(c_Gump.Filter)); + AddButton(width - 30, y + 3, 0x2716, "Filter", new GumpCallback(c_Gump.Filter)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(209)); + AddButton(20, y + 3, 0x2716, "Spam", new GumpCallback(c_Gump.Spam)); + AddButton(width - 30, y + 3, 0x2716, "Spam", new GumpCallback(c_Gump.Spam)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(210)); + AddButton(20, y + 3, 0x2716, "Irc", new GumpCallback(c_Gump.Irc)); + AddButton(width - 30, y + 3, 0x2716, "Irc", new GumpCallback(c_Gump.Irc)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(287)); + AddButton(20, y + 3, 0x2716, "Multi", new GumpCallback(c_Gump.Multi)); + AddButton(width - 30, y + 3, 0x2716, "Multi", new GumpCallback(c_Gump.Multi)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(50)); + AddButton(20, y + 3, 0x2716, "Channel", new GumpCallback(c_Gump.Channel)); + AddButton(width - 30, y + 3, 0x2716, "Channel", new GumpCallback(c_Gump.Channel)); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + protected void JoinChannel(object o) + { + Channel c = o as Channel; + + if (c == null) + return; + + if (c.IsIn(c_Target)) + c.Leave(c_Target); + else + c.Join(c_Target); + + NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class ChannelSelectGump : GumpPlus + { + private ListGump20 c_Gump; + private Mobile c_Target; + + public ChannelSelectGump(Mobile m, ListGump20 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(38)); + AddImage(10, y + 2, 0x39); + AddImage(width - 40, y + 2, 0x3B); + + y += 5; + + foreach (Chat3.Channel c in Chat3.Channel.Channels) + { + if (!c.CanChat(c_Target, false)) + continue; + + AddHtml(40, y += 20, width - 40, (Data.GetData(c_Target).CurrentChannel == c ? HTML.Yellow : HTML.White) + "
" + (c.Style == ChatStyle.Regional ? c.Name : c.NameFor(c_Target))); + AddButton(20, y, c.IsIn(c_Target) ? 0x2343 : 0x2342, "Join Channel", new GumpStateCallback(JoinChannel), c); + + if (c.IsIn(c_Target)) + { + AddButton(40 + (width - 40) / 2 - 40, y + 3, 0x2716, "View Channel", new GumpStateCallback(c_Gump.ViewChannel), c); + AddButton(40 + (width - 40) / 2 + 30, y + 3, 0x2716, "View Channel", new GumpStateCallback(c_Gump.ViewChannel), c); + } + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + private void JoinChannel(object o) + { + Channel c = o as Channel; + + if (c == null) + return; + + if (c.IsIn(c_Target)) + c.Leave(c_Target); + else + c.Join(c_Target); + + NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class OptionsGump : GumpPlus + { + private ListGump20 c_Gump; + private Mobile c_Target; + + public OptionsGump(Mobile m, ListGump20 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(40)); + AddImage(10, y + 2, 0x39); + AddImage(width - 40, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(49)); + AddButton(20, y + 3, 0x2716, "Colors", new GumpCallback(c_Gump.Colors)); + AddButton(width - 30, y + 3, 0x2716, "Colors", new GumpCallback(c_Gump.Colors)); + AddHtml(0, y += 20, width, "
" + General.Local(56)); + AddButton(20, y + 3, 0x2716, "Mail", new GumpCallback(c_Gump.Mail)); + AddButton(width - 30, y + 3, 0x2716, "Mail", new GumpCallback(c_Gump.Mail)); + + if (Data.GetData(c_Target).GlobalAccess) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(43)); + AddButton(20, y + 3, 0x2716, "Global Menu", new GumpCallback(c_Gump.GlobalMenu)); + AddButton(width - 30, y + 3, 0x2716, "Global Menu", new GumpCallback(c_Gump.GlobalMenu)); + } + + if (c_Target.AccessLevel >= AccessLevel.Administrator) + { + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(207)); + AddButton(20, y + 3, 0x2716, "General", new GumpCallback(c_Gump.GenOpt)); + AddButton(width - 30, y + 3, 0x2716, "General", new GumpCallback(c_Gump.GenOpt)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(237)); + AddButton(20, y + 3, 0x2716, "Logging", new GumpCallback(c_Gump.Logging)); + AddButton(width - 30, y + 3, 0x2716, "Logging", new GumpCallback(c_Gump.Logging)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(208)); + AddButton(20, y + 3, 0x2716, "Filter", new GumpCallback(c_Gump.Filter)); + AddButton(width - 30, y + 3, 0x2716, "Filter", new GumpCallback(c_Gump.Filter)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(209)); + AddButton(20, y + 3, 0x2716, "Spam", new GumpCallback(c_Gump.Spam)); + AddButton(width - 30, y + 3, 0x2716, "Spam", new GumpCallback(c_Gump.Spam)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(210)); + AddButton(20, y + 3, 0x2716, "Irc", new GumpCallback(c_Gump.Irc)); + AddButton(width - 30, y + 3, 0x2716, "Irc", new GumpCallback(c_Gump.Irc)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(287)); + AddButton(20, y + 3, 0x2716, "Multi", new GumpCallback(c_Gump.Multi)); + AddButton(width - 30, y + 3, 0x2716, "Multi", new GumpCallback(c_Gump.Multi)); + AddHtml(0, y += 20, width, HTML.LightPurple + "
" + General.Local(50)); + AddButton(20, y + 3, 0x2716, "Channel", new GumpCallback(c_Gump.Channel)); + AddButton(width - 30, y + 3, 0x2716, "Channel", new GumpCallback(c_Gump.Channel)); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class ViewsGump : GumpPlus + { + private ListGump20 c_Gump; + private Mobile c_Target; + + public ViewsGump(Mobile m, ListGump20 g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = -10; + + AddHtml(0, y += 25, width, "
" + General.Local(1)); + AddImage(0 + 10, y + 2, 0x39); + AddImage(0 + width - 40, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(46)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.All); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.All); + AddHtml(0, y += 20, width, "
" + General.Local(56)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Mail); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Mail); + AddHtml(0, y += 20, width, "
" + General.Local(203)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Friends); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Friends); + AddHtml(0, y += 20, width, "
" + General.Local(51)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Ignores); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Ignores); + + AddHtml(0, y += 20, width, (c_Gump.CurrentPage == ListPage.Channel ? "" : HTML.Gray) + "
" + General.Local(206)); + if (c_Gump.CurrentPage == ListPage.Channel) + { + AddButton(20, y + 3, 0x2716, "History", new GumpCallback(c_Gump.History)); + AddButton(width - 30, y + 3, 0x2716, "History", new GumpCallback(c_Gump.History)); + } + + if (Data.GetData(c_Target).GlobalAccess) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(204)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GIgnores); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GIgnores); + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(205)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GListens); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.GListens); + } + + if (c_Target.AccessLevel > AccessLevel.GameMaster) + { + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(54)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Bans); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Bans); + AddHtml(0, y += 20, width, HTML.Red + "
" + General.Local(269)); + AddButton(20, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Notifications); + AddButton(width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(c_Gump.Page), ListPage.Notifications); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class StatusGump : GumpPlus + { + private GumpPlus c_Gump; + + public StatusGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + m.CloseGump(typeof(StatusGump)); + + c_Gump = g; + } + + protected override void BuildGump() + { + int width = 100; + int y = 20; + + AddHtml(0, y, width, "
" + General.Local(19)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Online", new GumpStateCallback(Status), OnlineStatus.Online); + AddButton(width / 2 + 40, y + 3, 0x2716, "Online", new GumpStateCallback(Status), OnlineStatus.Online); + AddHtml(0, y += 20, width, "
" + General.Local(20)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Away", new GumpStateCallback(Status), OnlineStatus.Away); + AddButton(width / 2 + 40, y + 3, 0x2716, "Away", new GumpStateCallback(Status), OnlineStatus.Away); + AddHtml(0, y += 20, width, "
" + General.Local(21)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Busy", new GumpStateCallback(Status), OnlineStatus.Busy); + AddButton(width / 2 + 40, y + 3, 0x2716, "Busy", new GumpStateCallback(Status), OnlineStatus.Busy); + AddHtml(0, y += 20, width, "
" + General.Local(22)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Hidden", new GumpStateCallback(Status), OnlineStatus.Hidden); + AddButton(width / 2 + 40, y + 3, 0x2716, "Hidden", new GumpStateCallback(Status), OnlineStatus.Hidden); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Status(object o) + { + if (!(o is OnlineStatus)) + return; + + Data.GetData(Owner).Status = (OnlineStatus)o; + + if ((OnlineStatus)o == OnlineStatus.Away || (OnlineStatus)o == OnlineStatus.Busy) + new AwayGump(Owner, c_Gump); + else + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + + private class AwayGump : GumpPlus + { + private GumpPlus c_Gump; + + public AwayGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + m.CloseGump(typeof(AwayGump)); + + c_Gump = g; + } + + protected override void BuildGump() + { + AddBackground(0, 0, 200, 200, Data.GetData(Owner).DefaultBack); + + AddHtml(0, 10, 200, "
" + General.Local(12)); + AddTextField(10, 30, 180, 120, 0x480, 0xBBC, "Away", Data.GetData(Owner).AwayMsg); + AddButton(60, 160, 0xFB1, 0xFB3, "Clear", new GumpCallback(ClearMsg)); + AddButton(120, 160, 0xFB7, 0xFB9, "Submit", new GumpCallback(Submit)); + } + + private void ClearMsg() + { + Data.GetData(Owner).AwayMsg = ""; + + NewGump(); + } + + private void Submit() + { + Data.GetData(Owner).AwayMsg = GetTextField("Away"); + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/2.0 Skin/PmNotifyGump20.cs b/Scripts/Customs/KniveChat/Gumps/2.0 Skin/PmNotifyGump20.cs new file mode 100644 index 0000000..92913b8 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/2.0 Skin/PmNotifyGump20.cs @@ -0,0 +1,32 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class PmNotifyGump20 : GumpPlus + { + public PmNotifyGump20( Mobile m ) : base( m, 200, 50 ) + { + m.CloseGump( typeof( PmNotifyGump20 ) ); + } + + protected override void BuildGump() + { + if (Data.GetData(Owner).GetMsg() != null) + { + AddButton(30, 10, 0x82E, "Message", new GumpCallback(Message)); + AddImage(0, 0, 0x9CB); + AddImageTiled(35, 7, 20, 8, 0x9DC); + AddHtml(23, 1, 50, "
" + HTML.Black + Data.GetData(Owner).GetMsg().From.RawName); + } + } + + private void Message() + { + Data.GetData(Owner).CheckMsg(); + + if (Data.GetData(Owner).NewMsg()) + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ChannelGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ChannelGump.cs new file mode 100644 index 0000000..747061c --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ChannelGump.cs @@ -0,0 +1,277 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class ChannelGump : GumpPlus + { + private Channel c_Channel; + protected Channel Channel { get { return c_Channel; } set { c_Channel = value; } } + + public ChannelGump(Mobile m) + : this(m, null) + { + } + + public ChannelGump(Mobile m, Channel c) + : base(m, 100, 100) + { + m.CloseGump(typeof(ChannelGump)); + + c_Channel = c; + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(177)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddImage(width/2-73, (y += 25) - 1, 0x9C5); + AddHtml(width/2-50, y, 100, "
" + (c_Channel == null ? "" : c_Channel.Name)); + AddButton(width / 2 - 65, y + 3, 0x2716, "Channel Select", new GumpCallback(ChannelSelect)); + AddButton(width / 2 + 52, y + 3, 0x2716, "Channel Select", new GumpCallback(ChannelSelect)); + + AddHtml(0, y += 25, width, "
" + General.Local(178)); + AddButton(width/2-60, y+3, 0x2716, "New Channel", new GumpCallback(NewChannel)); + AddButton(width/2+50, y+3, 0x2716, "New Channel", new GumpCallback(NewChannel)); + + if (c_Channel == null) + { + AddHtml(0, y += 25, width, "
" + General.Local(179)); + AddHtml(0, y += 25, width, 61, "
" + General.Local(219), false, false); + AddBackgroundZero(0, 0, width, y + 100, Data.GetData(Owner).DefaultBack); + return; + } + + if (c_Channel.GetType() == typeof(Channel)) + { + AddHtml(0, y += 20, width, "
" + General.Local(211)); + AddButton(width / 2 - 65, y + 1, 0x5686, 0x5687, "Delete Channel", new GumpCallback(DeleteChannel)); + AddButton(width / 2 + 50, y + 1, 0x5686, 0x5687, "Delete Channel", new GumpCallback(DeleteChannel)); + } + + AddHtml(0, y += 25, width/2-10, "
" + General.Local(180)); + AddTextField(width / 2 + 10, y, 70, 21, 0x480, 0xBBA, "Channel Name", "" + c_Channel.Name); + AddButton(width/2-5, y + 3, 0x2716, "Channel Name", new GumpCallback(ChannelName)); + + AddHtml(0, y += 25, width, "
" + General.Local(212)); + AddButton(width / 2 - 100, y, c_Channel.Enabled ? 0x2343 : 0x2342, "Enable", new GumpCallback(Enable)); + AddButton(width / 2 + 80, y, c_Channel.Enabled ? 0x2343 : 0x2342, "Enable", new GumpCallback(Enable)); + + AddHtml(0, y += 25, width, "
" + General.Local(182) + " | " + General.Local(183)); + AddButton(width/2-100, y + 3, c_Channel.Style == ChatStyle.Global ? 0x939 : 0x2716, "Global", new GumpCallback(Global)); + AddButton(width/2+90, y + 3, c_Channel.Style == ChatStyle.Regional ? 0x939 : 0x2716, "Regional", new GumpCallback(Regional)); + + AddHtml(0, y += 20, width, "
" + General.Local(223)); + AddButton(width / 2 - 100, y, c_Channel.ShowStaff ? 0x2343 : 0x2342, "Show Staff", new GumpCallback(ShowStaff)); + AddButton(width / 2 + 80, y, c_Channel.ShowStaff ? 0x2343 : 0x2342, "Show Staff", new GumpCallback(ShowStaff)); + + AddHtml(0, y += 20, width, "
" + General.Local(184)); + AddButton(width / 2 - 100, y, c_Channel.ToIrc ? 0x2343 : 0x2342, "Send to IRC", new GumpCallback(SendToIrc)); + AddButton(width / 2 + 80, y, c_Channel.ToIrc ? 0x2343 : 0x2342, "Send to IRC", new GumpCallback(SendToIrc)); + + AddHtml(0, y += 20, width, "
" + General.Local(188)); + AddButton(width / 2 - 100, y, c_Channel.NewChars ? 0x2343 : 0x2342, "Auto join new characters", new GumpCallback(AutoNewChars)); + AddButton(width / 2 + 80, y, c_Channel.NewChars ? 0x2343 : 0x2342, "Auto join new characters", new GumpCallback(AutoNewChars)); + + AddHtml(0, y += 20, width, "
" + General.Local(208)); + AddButton(width / 2 - 100, y, c_Channel.Filter ? 0x2343 : 0x2342, "Apply Filter", new GumpCallback(ApplyFilter)); + AddButton(width / 2 + 80, y, c_Channel.Filter ? 0x2343 : 0x2342, "Apply Filter", new GumpCallback(ApplyFilter)); + + AddHtml(0, y += 20, width, "
" + General.Local(220)); + AddButton(width/2-100, y, c_Channel.Delay ? 0x2343 : 0x2342, "Apply Delay", new GumpCallback(ApplyDelay)); + AddButton(width/2+80, y, c_Channel.Delay ? 0x2343 : 0x2342, "Apply Delay", new GumpCallback(ApplyDelay)); + + AddHtml(0, y += 25, width/2-10, "
" + General.Local(185)); + AddTextField(width/2+10, y, 70, 21, 0x480, 0xBBA, "Add/Remove", ""); + AddButton(width/2-5, y + 4, 0x2716, "Add/Remove Command", new GumpCallback(AddCommand)); + + string txt = General.Local(42) + ": "; + + foreach (string str in c_Channel.Commands) + txt += str + " "; + + AddHtml(20, y += 25, width-40, 60, txt, false, false); + + AddBackgroundZero(0, 0, width, y+100, Data.GetData(Owner).DefaultBack); + } + + private void ChannelSelect() + { + new ChannelSelectGump(this); + } + + private void NewChannel() + { + c_Channel = new Channel("New"); + + NewGump(); + } + + private void DeleteChannel() + { + if (c_Channel == null) + return; + + foreach (string str in c_Channel.Commands) + Channel.RemoveCommand(str); + Channel.Channels.Remove(c_Channel); + + c_Channel = null; + + NewGump(); + } + + private void AutoNewChars() + { + if (c_Channel == null) + return; + + c_Channel.NewChars = !c_Channel.NewChars; + + if (c_Channel.NewChars) + foreach (Data data in Data.Datas.Values) + c_Channel.Join(data.Mobile); + + NewGump(); + } + + private void Enable() + { + if (c_Channel != null) + c_Channel.Enabled = !c_Channel.Enabled; + + NewGump(); + } + + private void ShowStaff() + { + if (c_Channel != null) + c_Channel.ShowStaff = !c_Channel.ShowStaff; + + NewGump(); + } + + private void ApplyFilter() + { + if (c_Channel != null) + c_Channel.Filter = !c_Channel.Filter; + + NewGump(); + } + + private void ApplyDelay() + { + if (c_Channel != null) + c_Channel.Delay = !c_Channel.Delay; + + NewGump(); + } + + private void ChannelName() + { + if(c_Channel != null) + c_Channel.Name = GetTextField("Channel Name"); + + NewGump(); + } + + private void AddCommand() + { + if (GetTextField("Add/Remove") == "") + { + NewGump(); + return; + } + + if (c_Channel.Commands.Contains(GetTextField("Add/Remove").ToLower())) + { + c_Channel.Commands.Remove(GetTextField("Add/Remove").ToLower()); + Channel.RemoveCommand(GetTextField("Add/Remove").ToLower()); + } + else + { + c_Channel.Commands.Add(GetTextField("Add/Remove").ToLower()); + Channel.AddCommand(GetTextField("Add/Remove").ToLower()); + } + + NewGump(); + } + + private void Global() + { + if(c_Channel != null) + c_Channel.Style = ChatStyle.Global; + + NewGump(); + } + + private void Regional() + { + if(c_Channel != null) + c_Channel.Style = ChatStyle.Regional; + + NewGump(); + } + + private void SendToIrc() + { + if(c_Channel != null) + c_Channel.ToIrc = !c_Channel.ToIrc; + + NewGump(); + } + + + private class ChannelSelectGump : GumpPlus + { + private ChannelGump c_Gump; + + public ChannelSelectGump(ChannelGump g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(38)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + foreach (Channel c in Channel.Channels) + { + AddHtml(0, y += 20, width, "
" + c.NameFor(Owner)); + AddButton(width / 2 - 60, y + 3, 0x2716, "Select Channel", new GumpStateCallback(SelectChannel), c); + AddButton(width / 2 + 50, y + 3, 0x2716, "Select Channel", new GumpStateCallback(SelectChannel), c); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void SelectChannel(object o) + { + Channel c = o as Channel; + + if (c == null) + return; + + c_Gump.Channel = c; + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ColorsGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ColorsGump.cs new file mode 100644 index 0000000..2e86f9b --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ColorsGump.cs @@ -0,0 +1,162 @@ +using System; +using Server; +using Server.HuePickers; + +namespace Knives.Chat3 +{ + public class ColorsGump : GumpPlus + { + private Mobile c_Target; + + public Mobile Current { get { return (c_Target == null ? Owner : c_Target); } } + + public ColorsGump(Mobile m, Mobile targ) + : base(m, 100, 100) + { + m.CloseGump(typeof(ColorsGump)); + + c_Target = targ; + } + + public ColorsGump(Mobile m) + : this(m, null) + { + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(216)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + if (c_Target != null) + AddHtml(0, y += 25, width, "
" + General.Local(224) + " " + c_Target.RawName); + + foreach (Channel c in Channel.Channels) + if(c.CanChat(Current, false)) + { + AddHtml(0, y+=25, width, "
" + c.NameFor(Current)); + AddImage(width / 2 - 70, y, 0x2342, c.ColorFor(Current)); + AddButton(width / 2 - 66, y + 4, 0x2716, "Channel Color", new GumpStateCallback(ChannelColor), c); + AddImage(width / 2 + 50, y, 0x2342, c.ColorFor(Current)); + AddButton(width / 2 + 55, y + 4, 0x2716, "Channel Color", new GumpStateCallback(ChannelColor), c); + } + + AddHtml(0, y += 25, width, "
" + General.Local(47)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).SystemC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 2); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).SystemC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 2); + + if (Current.AccessLevel > AccessLevel.Player) + { + AddHtml(0, y += 25, width, "
" + General.Local(48)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).StaffC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 3); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).StaffC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 3); + } + + if (Data.GetData(Current).GlobalAccess) + { + y += 20; + + AddHtml(0, y += 25, width, "
" + General.Local(44)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).GlobalCC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 0); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).GlobalCC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 0); + + AddHtml(0, y += 25, width, "
" + General.Local(45)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).GlobalWC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 1); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).GlobalWC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 1); + + AddHtml(0, y += 25, width, "
" + General.Local(192)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).GlobalGC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 4); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).GlobalGC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 4); + + AddHtml(0, y += 25, width, "
" + General.Local(193)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).GlobalFC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 5); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).GlobalFC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 5); + + AddHtml(0, y += 25, width, "
" + General.Local(26)); + AddImage(width / 2 - 70, y, 0x2342, Data.GetData(Current).GlobalMC); + AddButton(width / 2 - 66, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 6); + AddImage(width / 2 + 50, y, 0x2342, Data.GetData(Current).GlobalMC); + AddButton(width / 2 + 55, y + 4, 0x2716, "Colors", new GumpStateCallback(Colors), 6); + } + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(Current).DefaultBack); + } + + private void ChannelColor(object o) + { + if (!(o is Channel)) + return; + + Owner.SendHuePicker(new InternalPicker(this, (Channel)o)); + } + + private void Colors(object o) + { + if (!(o is int)) + return; + + Owner.SendHuePicker(new InternalPicker(this, (int)o)); + } + + + private class InternalPicker : HuePicker + { + private ColorsGump c_Gump; + private int c_Num; + private Channel c_Channel; + + public InternalPicker(ColorsGump g, int num) + : base(0x1018) + { + c_Gump = g; + c_Num = num; + } + + public InternalPicker(ColorsGump g, Channel c) + : base(0x1018) + { + c_Gump = g; + c_Channel = c; + } + + public override void OnResponse(int hue) + { + if (c_Channel != null) + { + c_Channel.Colors[c_Gump.Current] = hue; + c_Gump.NewGump(); + return; + } + + switch (c_Num) + { + case 0: Data.GetData(c_Gump.Current).GlobalCC = hue; break; + case 1: Data.GetData(c_Gump.Current).GlobalWC = hue; break; + case 2: Data.GetData(c_Gump.Current).SystemC = hue; break; + case 3: Data.GetData(c_Gump.Current).StaffC = hue; break; + case 4: Data.GetData(c_Gump.Current).GlobalGC = hue; break; + case 5: Data.GetData(c_Gump.Current).GlobalFC = hue; break; + case 6: Data.GetData(c_Gump.Current).GlobalMC = hue; break; + } + + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/EditNotGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/EditNotGump.cs new file mode 100644 index 0000000..346f20b --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/EditNotGump.cs @@ -0,0 +1,179 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class EditNotGump : GumpPlus + { + private Notification c_Not; + + public EditNotGump(Mobile m, Notification not) + : base(m, 100, 100) + { + c_Not = not; + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddTextField(width / 2 -50, y, 100, 21, 0x480, 0xBBC, "Name", c_Not.Name); + AddButton(width / 2 - 90, y+3, 0x2716, "Name", new GumpCallback(Name)); + AddButton(width / 2 + 70, y+3, 0x2716, "Name", new GumpCallback(Name)); + + AddHtml(0, y += 25, width, "
" + General.Local(272) + " | " + General.Local(273)); + AddButton(width / 2 - 60, y + 3, !c_Not.Gump ? 0x939 : 0x2716, "NotGump", new GumpCallback(NotGump)); + AddButton(width / 2 + 50, y + 3, c_Not.Gump ? 0x939 : 0x2716, "Gump", new GumpCallback(Gump)); + + AddHtml(0, y += 25, width, "
" + General.Local(274)); + AddButton(width / 2 - 80, y + 3, 0x2716, "Set Time", new GumpCallback(SetTime)); + AddButton(width / 2 + 70, y + 3, 0x2716, "Set Time", new GumpCallback(SetTime)); + AddHtml(0, y += 25, width, "
" + (c_Not.Recur.Days != 0 ? c_Not.Recur.Days + " days " : "") + (c_Not.Recur.Hours != 0 ? c_Not.Recur.Hours + "h " : "") + (c_Not.Recur.Minutes != 0 ? c_Not.Recur.Minutes + "m " : "") + (c_Not.Recur.Seconds != 0 ? c_Not.Recur.Seconds + "s" : "")); + + if (c_Not.Gump) + { + AddHtml(0, y += 25, width, "
" + General.Local(275)); + AddButton(width / 2 - 90, y, c_Not.AntiMacro ? 0x2343 : 0x2342, "Anti Macro", new GumpCallback(AntiMacro)); + AddButton(width / 2 + 70, y, c_Not.AntiMacro ? 0x2343 : 0x2342, "Anti Macro", new GumpCallback(AntiMacro)); + } + + if (c_Not.AntiMacro) + { + AddHtml(0, y += 25, width, "
" + General.Local(280)); + AddHtml(0, y += 20, width, "
" + General.Local(155) + " | " + General.Local(281)); + AddButton(width / 2 - 60, y + 3, Data.MacroPenalty == MacroPenalty.None ? 0x939 : 0x2716, "None", new GumpCallback(None)); + AddButton(width / 2 + 50, y + 3, Data.MacroPenalty == MacroPenalty.Kick ? 0x939 : 0x2716, "Kick", new GumpCallback(Kick)); + + AddHtml(0, y += 25, width/2-20, "
" + General.Local(282)); + AddTextField(width / 2 + 20, y, 50, 21, 0x480, 0xBBC, "Delay", "" + Data.AntiMacroDelay); + AddHtml(width/2+80, y += 25, 10, "s"); + AddButton(width / 2 + 90, y + 3, 0x2716, "Delay", new GumpCallback(Delay)); + } + + AddTextField(20, y += 25, width - 40, 80, 0x480, 0xBBC, "Text", c_Not.Text); + AddButton(width / 2 - 32, y += 90, 0x98B, "Text", new GumpCallback(Text)); + AddHtml(width / 2 - 32 + 6, y + 3, 51, "
" + General.Local(245)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Name() + { + c_Not.Name = GetTextField("Name"); + NewGump(); + } + + private void NotGump() + { + c_Not.Gump = false; + c_Not.AntiMacro = false; + NewGump(); + } + + private void Gump() + { + c_Not.Gump = true; + NewGump(); + } + + private void AntiMacro() + { + c_Not.AntiMacro = !c_Not.AntiMacro; + + if (c_Not.AntiMacro) + c_Not.Gump = true; + + NewGump(); + } + + private void Text() + { + c_Not.Text = GetTextField("Text"); + NewGump(); + } + + private void Delay() + { + Data.AntiMacroDelay = GetTextFieldInt("Delay"); + NewGump(); + } + + private void SetTime() + { + new TimeGump(Owner, this, c_Not); + } + + private void None() + { + Data.MacroPenalty = MacroPenalty.None; + NewGump(); + } + + private void Kick() + { + Data.MacroPenalty = MacroPenalty.Kick; + NewGump(); + } + + + private class TimeGump : GumpPlus + { + private GumpPlus c_Gump; + private Notification c_Not; + + public TimeGump(Mobile m, GumpPlus g, Notification not) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Not = not; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(274)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + AddHtml(0, y += 20, width, "
" + General.Local(161)); + AddButton(width / 2 - 60, y + 3, 0x2716, "30 minutes", new GumpStateCallback(Time), TimeSpan.FromMinutes(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "30 minutes", new GumpStateCallback(Time), TimeSpan.FromMinutes(30)); + AddHtml(0, y += 20, width, "
" + General.Local(162)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 hour", new GumpStateCallback(Time), TimeSpan.FromHours(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 hour", new GumpStateCallback(Time), TimeSpan.FromHours(1)); + AddHtml(0, y += 20, width, "
" + General.Local(163)); + AddButton(width / 2 - 60, y + 3, 0x2716, "12 hours", new GumpStateCallback(Time), TimeSpan.FromHours(12)); + AddButton(width / 2 + 50, y + 3, 0x2716, "12 hours", new GumpStateCallback(Time), TimeSpan.FromHours(12)); + AddHtml(0, y += 20, width, "
" + General.Local(164)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 day", new GumpStateCallback(Time), TimeSpan.FromDays(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 day", new GumpStateCallback(Time), TimeSpan.FromDays(1)); + AddHtml(0, y += 20, width, "
" + General.Local(165)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 week", new GumpStateCallback(Time), TimeSpan.FromDays(7)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 week", new GumpStateCallback(Time), TimeSpan.FromDays(7)); + AddHtml(0, y += 20, width, "
" + General.Local(166)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 month", new GumpStateCallback(Time), TimeSpan.FromDays(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 month", new GumpStateCallback(Time), TimeSpan.FromDays(30)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Time(object o) + { + if (!(o is TimeSpan)) + return; + + c_Not.Recur = (TimeSpan)o; + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/FilterGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/FilterGump.cs new file mode 100644 index 0000000..0852e76 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/FilterGump.cs @@ -0,0 +1,160 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class FilterGump : GumpPlus + { + public FilterGump(Mobile m) + : base(m, 100, 100) + { + m.CloseGump(typeof(FilterGump)); + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(214)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(142)); + AddButton(width / 2 - 120, y, Data.FilterSpeech ? 0x2343 : 0x2342, "Filter Speech", new GumpCallback(FilterSpeech)); + AddButton(width / 2 + 100, y, Data.FilterSpeech ? 0x2343 : 0x2342, "Filter Speech", new GumpCallback(FilterSpeech)); + AddHtml(0, y += 20, width, "
" + General.Local(143)); + AddButton(width / 2 - 120, y, Data.FilterMsg ? 0x2343 : 0x2342, "Filter Messages", new GumpCallback(FilterMsg)); + AddButton(width / 2 + 100, y, Data.FilterMsg ? 0x2343 : 0x2342, "Filter Messages", new GumpCallback(FilterMsg)); + + AddHtml(0, y += 25, width, "
" + General.Local(154) + ": " + General.Local(155 + (int)Data.FilterPenalty)); + AddButton(width / 2 - 80, y + 4, 0x2716, "Filter Penalty", new GumpCallback(FilterPenalty)); + AddButton(width / 2 + 70, y + 4, 0x2716, "Filter Penalty", new GumpCallback(FilterPenalty)); + + if (Data.FilterPenalty == Chat3.FilterPenalty.Ban) + { + AddHtml(0, y += 25, width / 2 - 10, "
" + General.Local(147)); + AddTextField(width / 2 + 15, y, 30, 21, 0x480, 0xBBA, "Ban Length", "" + Data.FilterBanLength); + AddHtml(width / 2 + 45, y, 100, "m"); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + } + + if (Data.FilterPenalty != Chat3.FilterPenalty.None) + { + AddHtml(0, y += 25, width / 2 - 10, "
" + General.Local(254)); + AddTextField(width / 2 + 15, y, 30, 21, 0x480, 0xBBA, "Warnings", "" + Data.FilterWarnings); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + } + + AddHtml(0, y += 25, width/2-10, "
" + General.Local(148)); + AddTextField(width/2+15, y, 70, 21, 0x480, 0xBBA, "Add/Remove", ""); + AddButton(width/2-5, y + 4, 0x2716, "Add/Remove Filter", new GumpCallback(AddFilter)); + + string txt = General.Local(151) + " "; + + foreach (string filter in Data.Filters) + txt += filter + " "; + + AddHtml(20, y += 25, width-40, 60, txt, false, false); + + AddBackgroundZero(0, 0, width, y+80, Data.GetData(Owner).DefaultBack); + } + + private void FilterSpeech() + { + Data.FilterSpeech = !Data.FilterSpeech; + + NewGump(); + } + + private void FilterMsg() + { + Data.FilterMsg = !Data.FilterMsg; + + NewGump(); + } + + private void Submit() + { + Data.FilterBanLength = GetTextFieldInt("Ban Length"); + Data.FilterWarnings = GetTextFieldInt("Warnings"); + + NewGump(); + } + + private void AddFilter() + { + if (GetTextField("Add/Remove").Trim() == "") + { + NewGump(); + return; + } + + if (Data.Filters.Contains(GetTextField("Add/Remove").ToLower())) + { + Data.Filters.Remove(GetTextField("Add/Remove").ToLower()); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(149) + " " + GetTextField("Add/Remove").ToLower()); + } + else + { + Data.Filters.Add(GetTextField("Add/Remove").ToLower()); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(150) + " " + GetTextField("Add/Remove").ToLower()); + } + + NewGump(); + } + + private void FilterPenalty() + { + new FilterPenaltyGump(Owner, this); + } + + + private class FilterPenaltyGump : GumpPlus + { + private GumpPlus c_Gump; + + public FilterPenaltyGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + c_Gump = g; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(154)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + y += 5; + + for (int i = 0; i < 3; ++i) + { + AddHtml(0, y += 20, width, "
" + General.Local(155 + i)); + AddButton(width / 2 - 60, y + 3, 0x2716, "Select", new GumpStateCallback(Select), i); + AddButton(width / 2 + 50, y + 3, 0x2716, "Select", new GumpStateCallback(Select), i); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + + private void Select(object o) + { + if (!(o is int)) + return; + + Data.FilterPenalty = (FilterPenalty)(int)o; + + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/GeneralGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/GeneralGump.cs new file mode 100644 index 0000000..0fd2c51 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/GeneralGump.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class GeneralGump : GumpPlus + { + public GeneralGump(Mobile m) + : base(m, 100, 100) + { + m.CloseGump(typeof(GeneralGump)); + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(221)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(222)); + AddButton(width / 2 - 60, y, Data.Debug ? 0x2343 : 0x2342, "Debug", new GumpCallback(Debug)); + AddButton(width / 2 + 40, y, Data.Debug ? 0x2343 : 0x2342, "Debug", new GumpCallback(Debug)); + + AddHtml(0, y += 25, width, "
" + General.Local(169)); + AddButton(width / 2 - 100, y + 3, 0x2716, "Reload Local", new GumpCallback(ReloadLocal)); + AddButton(width / 2 + 80, y + 3, 0x2716, "Reload Local", new GumpCallback(ReloadLocal)); + + AddHtml(0, y += 25, width, "
" + General.Local(293)); + AddButton(width / 2 - 100, y + 3, 0x2716, "Reload Help", new GumpCallback(ReloadHelp)); + AddButton(width / 2 + 80, y + 3, 0x2716, "Reload Help", new GumpCallback(ReloadHelp)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Debug() + { + Data.Debug = !Data.Debug; + + NewGump(); + } + + private void ReloadLocal() + { + General.LoadLocalFile(); + + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(168)); + + NewGump(); + } + + private void ReloadHelp() + { + General.LoadHelpFile(); + + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(294)); + + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/GlobalGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/GlobalGump.cs new file mode 100644 index 0000000..6b15f88 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/GlobalGump.cs @@ -0,0 +1,114 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class GlobalGump : GumpPlus + { + private Mobile c_Target; + + public Mobile Current { get { return (c_Target == null ? Owner : c_Target); } } + + public GlobalGump(Mobile m, Mobile targ) + : base(m, 100, 100) + { + m.CloseGump(typeof(GlobalGump)); + + c_Target = targ; + } + + public GlobalGump(Mobile m) + : this(m, null) + { + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(226)); + AddImage(width / 2 - 80, y + 2, 0x39); + AddImage(width / 2 + 50, y + 2, 0x3B); + + if (c_Target != null) + AddHtml(0, y += 25, width, "
" + General.Local(224) + " " + c_Target.RawName); + + AddHtml(0, y += 25, width, "
" + General.Local(43) + " | " + General.Local(10)); + AddButton(width / 2 - 70, y + 3, Data.GetData(Current).Global ? 0x939 : 0x2716, "Global", new GumpCallback(Global)); + AddButton(width / 2 + 60, y + 3, !Data.GetData(Current).Global ? 0x939 : 0x2716, "Listen", new GumpCallback(Listen)); + + if (Data.GetData(Current).Global) + { + AddHtml(0, y += 25, width, "
" + General.Local(44)); + AddButton(width / 2 - 70, y, Data.GetData(Current).GlobalC ? 0x2343 : 0x2342, "Chat", new GumpCallback(GlobalChat)); + AddButton(width / 2 + 50, y, Data.GetData(Current).GlobalC ? 0x2343 : 0x2342, "Chat", new GumpCallback(GlobalChat)); + AddHtml(0, y += 20, width, "
" + General.Local(45)); + AddButton(width / 2 - 70, y, Data.GetData(Current).GlobalW ? 0x2343 : 0x2342, "World", new GumpCallback(GlobalWorld)); + AddButton(width / 2 + 50, y, Data.GetData(Current).GlobalW ? 0x2343 : 0x2342, "World", new GumpCallback(GlobalWorld)); + AddHtml(0, y += 20, width, "
" + General.Local(26)); + AddButton(width / 2 - 70, y, Data.GetData(Current).GlobalM ? 0x2343 : 0x2342, "Msg", new GumpCallback(GlobalMsg)); + AddButton(width / 2 + 50, y, Data.GetData(Current).GlobalM ? 0x2343 : 0x2342, "Msg", new GumpCallback(GlobalMsg)); + AddHtml(0, y += 20, width, "
" + General.Local(192)); + AddButton(width / 2 - 70, y, Data.GetData(Current).GlobalG ? 0x2343 : 0x2342, "Guild", new GumpCallback(GlobalGuild)); + AddButton(width / 2 + 50, y, Data.GetData(Current).GlobalG ? 0x2343 : 0x2342, "Guild", new GumpCallback(GlobalGuild)); + AddHtml(0, y += 20, width, "
" + General.Local(193)); + AddButton(width / 2 - 70, y, Data.GetData(Current).GlobalF ? 0x2343 : 0x2342, "Faction", new GumpCallback(GlobalFaction)); + AddButton(width / 2 + 50, y, Data.GetData(Current).GlobalF ? 0x2343 : 0x2342, "Faction", new GumpCallback(GlobalFaction)); + AddHtml(0, y += 20, width, "
" + General.Local(159)); + AddButton(width / 2 - 70, y, Data.GetData(Current).IrcRaw ? 0x2343 : 0x2342, "Irc Raw", new GumpCallback(IrcRaw)); + AddButton(width / 2 + 50, y, Data.GetData(Current).IrcRaw ? 0x2343 : 0x2342, "Irc Raw", new GumpCallback(IrcRaw)); + } + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(Current).DefaultBack); + } + + private void Global() + { + Data.GetData(Current).Global = true; + NewGump(); + } + + private void Listen() + { + Data.GetData(Current).Global = false; + NewGump(); + } + + private void GlobalChat() + { + Data.GetData(Current).GlobalC = !Data.GetData(Current).GlobalC; + NewGump(); + } + + private void GlobalWorld() + { + Data.GetData(Current).GlobalW = !Data.GetData(Current).GlobalW; + NewGump(); + } + + private void GlobalMsg() + { + Data.GetData(Current).GlobalM = !Data.GetData(Current).GlobalM; + NewGump(); + } + + private void GlobalGuild() + { + Data.GetData(Current).GlobalG = !Data.GetData(Current).GlobalG; + NewGump(); + } + + private void GlobalFaction() + { + Data.GetData(Current).GlobalF = !Data.GetData(Current).GlobalF; + NewGump(); + } + + private void IrcRaw() + { + Data.GetData(Current).IrcRaw = !Data.GetData(Current).IrcRaw; + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/HelpContentsGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/HelpContentsGump.cs new file mode 100644 index 0000000..5c6b51f --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/HelpContentsGump.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class HelpContentsGump : GumpPlus + { + private string c_Search = ""; + private string c_Topic = ""; + private int c_Page; + + public HelpContentsGump(Mobile m) + : base(m, 100, 100) + { + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + if (c_Topic != "") + width = 300; + + AddHtml(0, y, width, "
Help Contents Search"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddTextField(width/2-70, y+=25, 140, 21, 0x480, 0xBBC, "Search", c_Search); + AddButton(width / 2 - 90, y+3, 0x2716, "Search", new GumpCallback(Search)); + AddButton(width / 2 + 80, y+3, 0x2716, "Search", new GumpCallback(Search)); + + if (c_Topic != "") + { + AddHtml(0, y+=35, width, "
" + c_Topic); + + AddHtml(20, y += 25, width - 20, 100, General.GetHelp(c_Topic), false, true); + AddBackgroundZero(0, 0, width, y+=120, 0x1400); + return; + } + + if (c_Search == "") + { + AddHtml(20, y+=35, width-40, 90, "
" + General.Local(262), false, false); + AddBackgroundZero(0, 0, width, y+110, 0x1400); + return; + } + + ArrayList list = new ArrayList(); + foreach (string str in General.Help.Keys) + { + if (str.ToLower().IndexOf(c_Search.ToLower()) != -1) + list.Add(str); + else if (General.GetHelp(str).ToLower().IndexOf(c_Search.ToLower()) != -1) + list.Add(str); + } + + if (list.Count == 0) + { + AddHtml(0, y += 35, width, "
" + General.Local(263)); + AddBackgroundZero(0, 0, width, y + 40, 0x1400); + return; + } + + AddHtml(0, y += 25, width, "
" + list.Count + (list.Count == 0 ? General.Local(265) : General.Local(264))); + + list.Sort(new InternalSort()); + + int perpage = 10; + + if (list.Count < c_Page * perpage) + c_Page = 0; + + if (c_Page != 0) + AddButton(width / 2 - 20, y - 3, 0x25E4, 0x25E5, "Page Down", new GumpCallback(PageDown)); + if (perpage * (c_Page + 1) < list.Count) + AddButton(width / 2, y - 3, 0x25E8, 0x25E9, "Page Up", new GumpCallback(PageUp)); + + y += 5; + + for (int i = c_Page * perpage; i < (c_Page + 1) * perpage && i < list.Count; ++i) + { + AddHtml(30, y+=20, width-30, list[i].ToString()); + AddButton(10, y+3, 0x2716, "Select", new GumpStateCallback(Select), list[i]); + } + + AddBackgroundZero(0, 0, width, y+40, 0x1400); + } + + private void PageUp() + { + c_Page++; + NewGump(); + } + + private void PageDown() + { + c_Page--; + NewGump(); + } + + private void Search() + { + c_Topic = ""; + c_Search = GetTextField("Search"); + NewGump(); + } + + private void Select(object obj) + { + c_Topic = obj.ToString(); + NewGump(); + } + + + private class InternalSort : IComparer + { + public InternalSort() + { + } + + public int Compare(object x, object y) + { + return Insensitive.Compare(x.ToString(), y.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/HistoryGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/HistoryGump.cs new file mode 100644 index 0000000..8d0bc7f --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/HistoryGump.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class HistoryGump : GumpPlus + { + private Channel c_Channel; + + public HistoryGump(Mobile m, Channel c) + : base(m, 100, 100) + { + m.CloseGump(typeof(HistoryGump)); + + c_Channel = c; + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + c_Channel.NameFor(Owner) + " " + General.Local(206)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + AddButton(20, y + 3, 0x2716, "Refresh", new GumpCallback(Refresh)); + + string txt = ""; + Channel.ChatHistory ch; + ArrayList list = c_Channel.GetHistory(Owner); + for(int i = list.Count-1; i >= 0; --i) + { + ch = (Channel.ChatHistory)list[i]; + + txt += String.Format(" {0}: {1}
", HTML.Yellow + ch.Mobile.RawName, ch.Txt); + } + + AddHtml(10, y+=25, width-20, 300, txt, false, true); + + y += 300; + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Refresh() + { + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/IrcGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/IrcGump.cs new file mode 100644 index 0000000..d661e63 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/IrcGump.cs @@ -0,0 +1,182 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class IrcGump : GumpPlus + { + public IrcGump(Mobile m) + : base(m, 100, 100) + { + m.CloseGump(typeof(IrcGump)); + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(100)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(177)); + AddButton(width / 2 - 80, y, 0x2716, "Channel Options", new GumpCallback(ChannelOptions)); + AddButton(width / 2 + 60, y, 0x2716, "Channel Options", new GumpCallback(ChannelOptions)); + + AddHtml(0, y += 20, width, "
" + General.Local(98)); + AddButton(width/2-80, y+3, Data.IrcEnabled ? 0x2343 : 0x2342, "IRC Enabled", new GumpCallback(IrcEnabled)); + AddButton(width/2+60, y+3, Data.IrcEnabled ? 0x2343 : 0x2342, "IRC Enabled", new GumpCallback(IrcEnabled)); + + if (!Data.IrcEnabled) + { + AddBackgroundZero(0, 0, width, y + 100, Data.GetData(Owner).DefaultBack); + return; + } + + AddHtml(0, y += 25, width, "
" + General.Local(115)); + AddButton(width/2-80, y, Data.IrcAutoConnect ? 0x2343 : 0x2342, "IRC Auto Connect", new GumpCallback(IrcAutoConnect)); + AddButton(width/2+60, y, Data.IrcAutoConnect ? 0x2343 : 0x2342, "IRC Auto Connect", new GumpCallback(IrcAutoConnect)); + + AddHtml(0, y+=20, width, "
" + General.Local(116)); + AddButton(width / 2 - 80, y, Data.IrcAutoReconnect ? 0x2343 : 0x2342, "IRC Auto Reconnect", new GumpCallback(IrcAutoReconnect)); + AddButton(width / 2 + 60, y, Data.IrcAutoReconnect ? 0x2343 : 0x2342, "IRC Auto Reconnect", new GumpCallback(IrcAutoReconnect)); + + AddHtml(0, y += 25, width, "
" + General.Local(138) + ": " + General.Local(121 + (int)Data.IrcStaffColor)); + AddButton(width / 2 - 80, y + 4, 0x2716, "Irc Staff Color", new GumpCallback(IrcStaffColor)); + AddButton(width / 2 + 70, y + 4, 0x2716, "Irc Staff Color", new GumpCallback(IrcStaffColor)); + + AddHtml(0, y += 25, width / 2 - 10, "
" + General.Local(117)); + AddTextField(width / 2 + 10, y, 100, 21, 0x480, 0xBBA, "Nick", Data.IrcNick); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddHtml(0, y += 20, width / 2 - 10, "
" + General.Local(118)); + AddTextField(width / 2 + 10, y, 100, 21, 0x480, 0xBBA, "Server", Data.IrcServer); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddHtml(0, y += 20, width / 2 - 10, "
" + General.Local(119)); + AddTextField(width / 2 + 10, y, 100, 21, 0x480, 0xBBA, "Room", Data.IrcRoom); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddHtml(0, y += 20, width / 2 - 10, "
" + General.Local(120)); + AddTextField(width / 2 + 10, y, 70, 21, 0x480, 0xBBA, "Port", "" + Data.IrcPort); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + int num = 139; + + if (IrcConnection.Connection.Connected) + num = 141; + if (IrcConnection.Connection.Connecting) + num = 140; + + AddHtml(0, y += 40, width, "
" + General.Local(num)); + AddButton(width / 2 - 60, y + 4, 0x2716, "Connect or Cancel or Close", new GumpCallback(ConnectCancelClose)); + AddButton(width / 2 + 50, y + 4, 0x2716, "Connect or Cancel or Close", new GumpCallback(ConnectCancelClose)); + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(Owner).DefaultBack); + } + + private void ChannelOptions() + { + NewGump(); + new ChannelGump(Owner, Channel.GetByType(typeof(Irc))); + } + + private void IrcEnabled() + { + Data.IrcEnabled = !Data.IrcEnabled; + NewGump(); + } + + private void IrcAutoConnect() + { + Data.IrcAutoConnect = !Data.IrcAutoConnect; + NewGump(); + } + + private void IrcAutoReconnect() + { + Data.IrcAutoReconnect = !Data.IrcAutoReconnect; + NewGump(); + } + + private void Submit() + { + Data.IrcNick = GetTextField("Nick"); + Data.IrcServer = GetTextField("Server"); + Data.IrcRoom = GetTextField("Room"); + Data.IrcPort = GetTextFieldInt("Port"); + + NewGump(); + } + + private void IrcStaffColor() + { + new IrcStaffColorGump(Owner, this); + } + + private void ConnectCancelClose() + { + Data.IrcNick = GetTextField("Nick"); + Data.IrcServer = GetTextField("Server"); + Data.IrcRoom = GetTextField("Room"); + Data.IrcPort = GetTextFieldInt("Port"); + + if (IrcConnection.Connection.Connected) + IrcConnection.Connection.Disconnect(false); + else if (IrcConnection.Connection.Connecting) + IrcConnection.Connection.CancelConnect(); + else if (!IrcConnection.Connection.Connected) + IrcConnection.Connection.Connect(Owner); + + NewGump(); + } + + + private class IrcStaffColorGump : GumpPlus + { + private GumpPlus c_Gump; + + public IrcStaffColorGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + c_Gump = g; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(137)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + y += 5; + + for (int i = 0; i < 16; ++i) + { + AddHtml(0, y += 20, width, "
" + General.Local(121 + i)); + AddButton(width / 2 - 60, y + 3, 0x2716, "Select", new GumpStateCallback(Select), i); + AddButton(width / 2 + 50, y + 3, 0x2716, "Select", new GumpStateCallback(Select), i); + } + + AddBackgroundZero(0, 0, 150, y + 40, Data.GetData(Owner).DefaultBack); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + + private void Select(object o) + { + if (!(o is int)) + return; + + Data.IrcStaffColor = (IrcColor)(int)o; + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ListGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ListGump.cs new file mode 100644 index 0000000..464a6b7 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ListGump.cs @@ -0,0 +1,1152 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class ListGump : GumpPlus + { + public enum ListPage { All, Channel, Mail, Friends, Ignores, GIgnores, GListens, Bans, Notifications } + + #region Class Definitions + + private ListPage c_ListPage; + private Mobile c_Target; + private int c_Page; + private bool c_Menu, c_Search; + private string c_TxtSearch = ""; + private string c_CharSearch = ""; + + public Mobile Current { get { return (c_Target == null ? Owner : c_Target); } } + + #endregion + + #region Constructors + + public ListGump(Mobile m, int page) + : base(m, 100, 100) + { + c_ListPage = (ListPage)page; + + m.CloseGump(typeof(ListGump)); + + Override = true; + } + + public ListGump(Mobile m, Mobile targ) + : base(m, 100, 100) + { + c_Target = targ; + + m.CloseGump(typeof(ListGump)); + + Override = true; + } + + public ListGump(Mobile m) + : this(m, 0) + { + } + + #endregion + + #region Methods + + protected override void BuildGump() + { + if (c_ListPage == ListPage.Channel && Data.GetData(Current).CurrentChannel == null) + c_ListPage = ListPage.All; + + int width = Data.GetData(Current).QuickBar ? 250 : 200; + int y = 10; + int perpage = Data.GetData(Current).PerPage; + int bar = width - 18; + + if (c_ListPage == ListPage.Mail) + perpage /= 2; + + if (c_Menu) + ShowMenu(width); + if (c_Search) + ShowSearch(width); + + AddButton(5, y-5, 0x5689, "Help", new GumpCallback(Help)); + AddButton(30, y - 1, 0x983, "PerPage Down", new GumpCallback(PerPageDown)); + AddButton(40, y-1, 0x985, "PerPage Up", new GumpCallback(PerPageUp)); + AddButton(width - 80, y - 5, 0x768, "Profile", new GumpStateCallback(Profile), Current); + AddLabel(width - 75, y - 5, 0x47E, "P"); + AddButton(width - 65, y - 5, 0x768, "QuickBar", new GumpCallback(QuickBar)); + AddLabel(width - 60, y - 5, Data.GetData(Current).QuickBar ? 0x34 : 0x47E, "Q"); + AddButton(width - 50, y - 5, 0x768, "Menu", new GumpCallback(Menu)); + AddLabel(width - 46, y-5, c_Menu ? 0x34 : 0x47E, "M"); + AddButton(width - 35, y - 5, 0x768, "Search", new GumpCallback(Search)); + AddLabel(width - 30, y - 5, c_Search ? 0x34 : 0x47E, "S"); + + ArrayList list = GetList(); + SearchFilter(list); + list.Sort(new InternalSort(this)); + + if (list.Count < c_Page * perpage) + c_Page = 0; + + if (c_Page != 0) + AddButton(width / 2 - 20, y-3, 0x25E4, 0x25E5, "Page Down", new GumpCallback(PageDown)); + if (perpage * (c_Page + 1) < list.Count) + AddButton(width / 2, y-3, 0x25E8, 0x25E9, "Page Up", new GumpCallback(PageUp)); + + if (c_Target != null) + { + AddHtml(0, y += 25, width, "
" + General.Local(224) + " " + c_Target.RawName); + AddButton(width / 2 - 80, y, 0x5686, "Clear Viewing", new GumpCallback(ClearViewing)); + AddButton(width / 2 + 65, y, 0x5686, "Clear Viewing", new GumpCallback(ClearViewing)); + } + + AddImage(width / 2 - 72, (y += 25) - 1, 0x9C5); + AddHtml(0, y, width, "
" + GetTitle()); + + if (c_ListPage == ListPage.Mail) + AddHtml(0, y += 20, width, "
" + Data.GetData(Owner).Messages.Count + " / " + Data.MaxMsgs); + else if(c_ListPage != ListPage.Notifications) + { + ArrayList states = new ArrayList(Server.Network.NetState.Instances); + foreach (Server.Network.NetState state in Server.Network.NetState.Instances) + if (state.Mobile != null && state.Mobile.AccessLevel != AccessLevel.Player) + states.Remove(state); + + AddHtml(0, y += 20, width, "
" + states.Count + " " + General.Local(19)); + } + + y += 5; + + for (int i = c_Page * perpage; i < (c_Page + 1) * perpage && i < list.Count; ++i) + { + if (list[i] is string) + { + if (list[i].ToString().IndexOf("@") == 0) + list[i] = list[i].ToString().Substring(1, list[i].ToString().Length - 1); + + AddHtml(35, y += 20, width - 35, list[i].ToString()); + AddButton(width - 40, y, Data.GetData(Current).IrcIgnores.Contains(list[i].ToString()) ? 0x5687 : 0x5686, "Ignore IRC", new GumpStateCallback(IgnoreIrc), list[i]); + } + else if(list[i] is Mobile) + { + AddHtml(35, y += 20, width - 35, ColorFor((Mobile)list[i]) + ((Mobile)list[i]).RawName + StatusFor((Mobile)list[i])); + if(Current == Owner && Data.GetData(Owner).NewMsgFrom((Mobile)list[i])) + AddButton(20, y, 0x1523, "Check Msg", new GumpStateCallback(CheckMsg), (Mobile)list[i]); + else + AddButton(20, y + 3, 0x2716, "Profile", new GumpStateCallback(Profile), (Mobile)list[i]); + + if (list[i] == Current) + continue; + + if (Data.GetData(Current).QuickBar) + { + bar = width - 18; + + if (Current.AccessLevel > ((Mobile)list[i]).AccessLevel) + { + if (Data.GetData(Current).GlobalAccess) + { + if (Data.GetData(Current).Global) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ignore", new GumpStateCallback(GIgnore), list[i]); + AddLabel(bar + 4, y, Data.GetData(Current).GIgnores.Contains(list[i]) ? 0x44 : 0x26, "I"); + } + else + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Listen", new GumpStateCallback(GListen), list[i]); + AddLabel(bar + 4, y, Data.GetData(Current).GListens.Contains(list[i]) ? 0x44 : 0x26, "L"); + } + } + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ban", new GumpStateCallback(Ban), list[i]); + AddLabel(bar + 4, y, Data.GetData((Mobile)list[i]).Banned ? 0x44 : 0x26, "b"); + } + + if (Current.AccessLevel >= AccessLevel.GameMaster && ((Mobile)list[i]).NetState != null) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Goto", new GumpStateCallback(Goto), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "g"); + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Client", new GumpStateCallback(Client), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "c"); + } + + if (Chat3.Message.CanMessage(Current, (Mobile)list[i])) + { + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Message", new GumpStateCallback(Message), list[i]); + AddLabel(bar + 3, y - 2, 0x47E, "m"); + } + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Ignore", new GumpStateCallback(Ignore), list[i]); + AddLabel(bar + 5, y - 1, Data.GetData(Current).Ignores.Contains(list[i]) ? 0x44 : 0x26, "i"); + + AddButton(bar -= 12, y + 3, 0x13A8, "Mini Friend", new GumpStateCallback(Friend), list[i]); + AddLabel(bar + 3, y, Data.GetData(Current).Friends.Contains(list[i]) ? 0x44 : 0x26, "f"); + } + } + else if (list[i] is Message) + { + Message msg = (Message)list[i]; + + AddHtml(45, y += 20, width-85, ColorFor(msg) + (msg.Read ? "" : "") + msg.Subject, false); + AddHtml(45, y += 16, width-85, General.Local(60) + " " + msg.From.RawName); + + AddButton(20, y - 10, 0x2716, "Open", new GumpStateCallback(Open), (Message)list[i]); + AddButton(width - 40, y - 10, 0x5686, 0x5687, "Delete", new GumpStateCallback(Delete), (Message)list[i]); + } + else if (list[i] is Notification) + { + Notification not = (Notification)list[i]; + + AddHtml(45, y += 20, width-85, ColorFor(not) + not.Name); + + AddButton(20, y + 3, 0x2716, "Edit Notif", new GumpStateCallback(EditNotif), (Notification)list[i]); + AddButton(width - 40, y + 3, 0x5686, 0x5687, "Delete", new GumpStateCallback(Delete), (Notification)list[i]); + } + } + + if (c_ListPage == ListPage.Mail && Current.AccessLevel >= AccessLevel.GameMaster) + { + AddHtml(0, y += 25, width, "
" + General.Local(95), false); + AddButton(width / 2 - 50, y + 3, 0x2716, "Broadcast", new GumpCallback(Broadcast)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Broadcast", new GumpCallback(Broadcast)); + + AddHtml(0, y += 20, width, "
" + General.Local(257), false); + AddButton(width / 2 - 50, y + 3, 0x2716, "Staff", new GumpCallback(BroadcastStaff)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Staff", new GumpCallback(BroadcastStaff)); + } + else if (c_ListPage == ListPage.Notifications) + { + AddHtml(0, y += 25, width, "
" + General.Local(270), false); + AddButton(width / 2 - 70, y + 3, 0x2716, "New Notif", new GumpCallback(NewNotif)); + AddButton(width / 2 + 60, y + 3, 0x2716, "New Notif", new GumpCallback(NewNotif)); + } + + AddImage(width / 2 - 32, (y+=30) - 2, 0x98C); + AddHtml(0, y, width, "
" + General.Local(19 + (int)Data.GetData(Current).Status)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Status", new GumpCallback(Status)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Status", new GumpCallback(Status)); + + AddBackgroundZero(0, 0, width, y+50, Data.GetData(Current).DefaultBack); + } + + private void ShowMenu(int x) + { + int width = 150; + int y = -10; + + AddImage(x-8, 10, 0x100); + AddHtml(x, y += 25, width, "
" + General.Local(38)); + AddImage(x + 10, y + 2, 0x39); + AddImage(x + width - 40, y + 2, 0x3B); + + y += 5; + + foreach (Chat3.Channel c in Chat3.Channel.Channels) + { + if (!c.CanChat(Current, false)) + continue; + + AddHtml(x+40, y+=20, width-40, (Data.GetData(Current).CurrentChannel == c ? HTML.Yellow : HTML.White) + "
" + (c.Style == ChatStyle.Regional ? c.Name : c.NameFor(Current))); + AddButton(x+20, y, c.IsIn(Current) ? 0x2343 : 0x2342, "Join Channel", new GumpStateCallback(JoinChannel), c); + + if (c.IsIn(Current)) + { + AddButton(x + 40 + (width-40)/2-40, y + 3, 0x2716, "View Channel", new GumpStateCallback(ViewChannel), c); + AddButton(x + 40 + (width-40)/2+30, y + 3, 0x2716, "View Channel", new GumpStateCallback(ViewChannel), c); + } + } + + AddHtml(x, y += 25, width, "
" + General.Local(1)); + AddImage(x + 10, y + 2, 0x39); + AddImage(x + width - 40, y + 2, 0x3B); + + AddHtml(x, y += 25, width, "
" + General.Local(46)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.All); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.All); + AddHtml(x, y += 20, width, "
" + General.Local(56)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Mail); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Mail); + AddHtml(x, y += 20, width, "
" + General.Local(203)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Friends); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Friends); + AddHtml(x, y += 20, width, "
" + General.Local(51)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Ignores); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Ignores); + + AddHtml(x, y += 20, width, (c_ListPage == ListPage.Channel ? "" : HTML.Gray) + "
" + General.Local(206)); + if (c_ListPage == ListPage.Channel) + { + AddButton(x + 20, y + 3, 0x2716, "History", new GumpCallback(History)); + AddButton(x + width - 30, y + 3, 0x2716, "History", new GumpCallback(History)); + } + + if (Data.GetData(Current).GlobalAccess) + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(204)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.GIgnores); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.GIgnores); + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(205)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.GListens); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.GListens); + } + + if (Current.AccessLevel > AccessLevel.GameMaster) + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(54)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Bans); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Bans); + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(269)); + AddButton(x + 20, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Notifications); + AddButton(x + width - 30, y + 3, 0x2716, "Page", new GumpStateCallback(Page), ListPage.Notifications); + } + + AddHtml(x, y+=25, width, "
" + General.Local(40)); + AddImage(x + 10, y + 2, 0x39); + AddImage(x + width - 40, y + 2, 0x3B); + + AddHtml(x, y += 25, width, "
" + General.Local(49)); + AddButton(x + 20, y + 3, 0x2716, "Colors", new GumpCallback(Colors)); + AddButton(x + width - 30, y + 3, 0x2716, "Colors", new GumpCallback(Colors)); + AddHtml(x, y += 20, width, "
" + General.Local(56)); + AddButton(x + 20, y + 3, 0x2716, "Mail", new GumpCallback(Mail)); + AddButton(x + width - 30, y + 3, 0x2716, "Mail", new GumpCallback(Mail)); + + if (Data.GetData(Current).GlobalAccess) + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(43)); + AddButton(x + 20, y + 3, 0x2716, "Global Menu", new GumpCallback(GlobalMenu)); + AddButton(x + width - 30, y + 3, 0x2716, "Global Menu", new GumpCallback(GlobalMenu)); + } + + if (Current.AccessLevel >= AccessLevel.Administrator) + { + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(207)); + AddButton(x + 20, y + 3, 0x2716, "General", new GumpCallback(GenOpt)); + AddButton(x + width - 30, y + 3, 0x2716, "General", new GumpCallback(GenOpt)); + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(237)); + AddButton(x + 20, y + 3, 0x2716, "Logging", new GumpCallback(Logging)); + AddButton(x + width - 30, y + 3, 0x2716, "Logging", new GumpCallback(Logging)); + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(208)); + AddButton(x + 20, y + 3, 0x2716, "Filter", new GumpCallback(Filter)); + AddButton(x + width - 30, y + 3, 0x2716, "Filter", new GumpCallback(Filter)); + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(209)); + AddButton(x + 20, y + 3, 0x2716, "Spam", new GumpCallback(Spam)); + AddButton(x + width - 30, y + 3, 0x2716, "Spam", new GumpCallback(Spam)); + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(210)); + AddButton(x + 20, y + 3, 0x2716, "Irc", new GumpCallback(Irc)); + AddButton(x + width - 30, y + 3, 0x2716, "Irc", new GumpCallback(Irc)); + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(287)); + AddButton(x + 20, y + 3, 0x2716, "Multi", new GumpCallback(Multi)); + AddButton(x + width - 30, y + 3, 0x2716, "Multi", new GumpCallback(Multi)); + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(50)); + AddButton(x + 20, y + 3, 0x2716, "Channel", new GumpCallback(Channel)); + AddButton(x + width - 30, y + 3, 0x2716, "Channel", new GumpCallback(Channel)); + } + + AddButton(x + width / 2 - 30, y += 25, 0x8B1, "1.0", new GumpStateCallback(SkinChange), Skin.One); + AddButton(x + width / 2 - 10, y, 0x8B2, "2.0", new GumpStateCallback(SkinChange), Skin.Two); + AddButton(x + width / 2 + 10, y, 0x8B3, "3.0", new GumpStateCallback(SkinChange), Skin.Three); + + AddBackgroundZero(x, 0, width, y + 40, Data.GetData(Current).DefaultBack, false); + } + + private void ShowSearch(int x) + { + int width = 130; + + AddBackground(x, 0, width, 50, Data.GetData(Current).DefaultBack, false); + + AddImage(x - 8, 10, 0x100); + AddTextField(x+15, 15, 90, 21, 0x480, 0xBBC, "Search", c_TxtSearch); + AddButton(x + width-17, 19, 0x2716, "Text Search", new GumpCallback(TxtSearch)); + + char[] chars = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; + + int difx = x-13; + int y = 61; + + foreach (char c in chars) + { + AddButton(difx += 20, y, 0x2344, "Char Search", new GumpStateCallback(CharSearch), c.ToString()); + AddHtml(difx + 6, y, 20, (c_CharSearch == c.ToString() ? HTML.Green : "") + c, false); + + if (difx >= x + 102) + { + difx = x-13; + y += 20; + } + } + } + + private string GetTitle() + { + switch (c_ListPage) + { + case ListPage.All: return General.Local(46); + case ListPage.Channel: return Data.GetData(Current).CurrentChannel.NameFor(Current); + case ListPage.Mail: return General.Local(56); + case ListPage.Friends: return General.Local(203); + case ListPage.Ignores: return General.Local(51); + case ListPage.GIgnores: return General.Local(204); + case ListPage.GListens: return General.Local(205); + case ListPage.Bans: return General.Local(54); + case ListPage.Notifications: return General.Local(269); + } + + return ""; + } + + private ArrayList GetList() + { + ArrayList list; + + switch (c_ListPage) + { + case ListPage.All: + list = new ArrayList(); + foreach (Data data in Data.Datas.Values) + if (Current.AccessLevel >= data.Mobile.AccessLevel) + list.Add(data.Mobile); + return list; + case ListPage.Channel: return new ArrayList(Data.GetData(Current).CurrentChannel.BuildList(Current)); + case ListPage.Mail: return new ArrayList(Data.GetData(Current).Messages); + case ListPage.Friends: return new ArrayList(Data.GetData(Current).Friends); + case ListPage.Ignores: return new ArrayList(Data.GetData(Current).Ignores); + case ListPage.GIgnores: return new ArrayList(Data.GetData(Current).GIgnores); + case ListPage.GListens: return new ArrayList(Data.GetData(Current).GListens); + case ListPage.Bans: + list = new ArrayList(); + foreach (Data data in Data.Datas.Values) + if (data.Banned) + list.Add(data.Mobile); + return list; + case ListPage.Notifications: return new ArrayList(Data.Notifications); + } + + return new ArrayList(); + } + + private void SearchFilter(ArrayList list) + { + string txt = ""; + foreach (object obj in new ArrayList(list)) + { + if (obj is Mobile) + txt = ((Mobile)obj).RawName; + else if (obj is Message) + txt = ((Message)obj).From.RawName; + else + txt = obj.ToString(); + + if (c_CharSearch.ToLower() != "" && txt.ToLower().IndexOf(c_CharSearch) != 0) + list.Remove(obj); + else if (c_TxtSearch.ToLower() != "" && txt.ToLower().IndexOf(c_TxtSearch) == -1) + list.Remove(obj); + } + } + + private string ColorFor(Message msg) + { + switch (msg.Type) + { + case MsgType.Normal: return HTML.White; + case MsgType.Invite: return HTML.Yellow; + case MsgType.System: return HTML.Red; + case MsgType.Staff: return HTML.Purple; + default: return HTML.White; + } + } + + private string ColorFor(Notification not) + { + return HTML.White; + } + + private string ColorFor(Mobile m) + { + if (Current == m) + return HTML.Yellow; + if (Data.GetData(m).Banned) + return HTML.Red; + if (Data.GetData(Current).Ignores.Contains(m)) + return HTML.AshRed; + if (Data.GetData(Current).Global && Data.GetData(Current).GIgnores.Contains(m)) + return HTML.AshRed; + if (!Data.GetData(Current).Global && Data.GetData(Current).GListens.Contains(m)) + return HTML.Blue; + if (m.NetState == null || Data.GetData(m).Status == OnlineStatus.Hidden) + return HTML.DarkGray; + if (Data.GetData(m).Status == OnlineStatus.Away || Data.GetData(m).Status == OnlineStatus.Busy) + return HTML.Gray; + if (m.AccessLevel > AccessLevel.Player) + return HTML.LightPurple; + if (m.Guild != null && (m.Guild == Current.Guild)) + return HTML.Green; + + return HTML.White; + } + + private string StatusFor(Mobile m) + { + if (Data.GetData(m).Status == OnlineStatus.Away) + return " (Away)"; + else if (Data.GetData(m).Status == OnlineStatus.Busy) + return " (Busy)"; + else if (Data.GetData(m).Status == OnlineStatus.Hidden) + return " (Hidden)"; + + return ""; + } + + #endregion + + #region Responses + + private void PageUp() + { + c_Page++; + NewGump(); + } + + private void PageDown() + { + c_Page--; + NewGump(); + } + + private void Help() + { + NewGump(); + new HelpContentsGump(Owner); + } + + private void PerPageUp() + { + Data.GetData(Current).PerPage++; + NewGump(); + } + + private void PerPageDown() + { + Data.GetData(Current).PerPage--; + NewGump(); + } + + private void IgnoreIrc(object o) + { + if (!(o is string)) + return; + + if (Data.GetData(Current).IrcIgnores.Contains(o.ToString())) + Data.GetData(Current).RemoveIrcIgnore(o.ToString()); + else + Data.GetData(Current).AddIrcIgnore(o.ToString()); + + NewGump(); + } + + private void Profile(object o) + { + if (!(o is Mobile)) + return; + + NewGump(); + new ProfileGump(Owner, (Mobile)o); + } + + private void Open(object o) + { + Message m = o as Message; + + if (m == null) + return; + + if (Data.GetData(Owner).Messages.Contains(m)) + m.Read = true; + + NewGump(); + + if (m.Read && Data.GetData(m.From).ReadReceipt && m.From.AccessLevel >= Owner.AccessLevel) + m.From.SendMessage(Data.GetData(m.From).SystemC, Owner.RawName + " " + General.Local(197) + " " + m.Subject); + + new MessageGump(Owner, m); + } + + private void EditNotif(object o) + { + if (!(o is Notification)) + return; + + NewGump(); + new EditNotGump(Owner, (Notification)o); + } + + private void Delete(object o) + { + if (o is Message) + Data.GetData(Current).DeleteMessage((Message)o); + else if (o is Notification) + Data.Notifications.Remove(o); + + NewGump(); + } + + private void Friend(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (Data.GetData(m).ByRequest && !Data.GetData(Current).Friends.Contains(m)) + { + if (!TrackSpam.LogSpam(Current, "Request " + m.RawName, TimeSpan.FromHours(Data.RequestSpam))) + { + TimeSpan ts = TrackSpam.NextAllowedIn(Current, "Request " + m.RawName, TimeSpan.FromHours(Data.RequestSpam)); + string txt = (ts.Days != 0 ? ts.Days + " " + General.Local(170) + " " : "") + (ts.Hours != 0 ? ts.Hours + " " + General.Local(171) + " " : "") + (ts.Minutes != 0 ? ts.Minutes + " " + General.Local(172) + " " : ""); + + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(96) + " " + txt); + NewGump(); + return; + } + + Data.GetData(m).AddMessage(new Message(Current, General.Local(84), General.Local(85), MsgType.Invite)); + + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(86) + " " + m.RawName); + + NewGump(); + return; + } + + if (Data.GetData(Current).Friends.Contains(m)) + Data.GetData(Current).RemoveFriend(m); + else + Data.GetData(Current).AddFriend(m); + + NewGump(); + } + + private void Ignore(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).Ignores.Contains(o)) + Data.GetData(Current).RemoveIgnore((Mobile)o); + else + Data.GetData(Current).AddIgnore((Mobile)o); + + NewGump(); + } + + private void Message(object o) + { + if (!(o is Mobile)) + return; + + NewGump(); + + if (Current != Owner) + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(225)); + else if (Chat3.Message.CanMessage(Owner, (Mobile)o)) + new SendMessageGump(Owner, (Mobile)o, "", null, MsgType.Normal); + } + + private void Ban(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (Data.GetData(m).Banned) + { + Data.GetData(m).RemoveBan(); + Owner.SendMessage(Data.GetData(Current).SystemC, General.Local(78) + " " + m.RawName); + NewGump(); + } + else + new BanGump(m, this); + } + + private void GIgnore(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).GIgnores.Contains(o)) + Data.GetData(Current).RemoveGIgnore((Mobile)o); + else + Data.GetData(Current).AddGIgnore((Mobile)o); + + NewGump(); + } + + private void GListen(object o) + { + if (!(o is Mobile)) + return; + + if (Data.GetData(Current).GListens.Contains(o)) + Data.GetData(Current).RemoveGListen((Mobile)o); + else + Data.GetData(Current).AddGListen((Mobile)o); + + NewGump(); + } + + private void Client(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + NewGump(); + + if (m.NetState == null) + Owner.SendMessage(Data.GetData(Current).SystemC, m.RawName + " " + General.Local(83)); + else + Owner.SendGump(new ClientGump(Owner, m.NetState)); + } + + private void Goto(object o) + { + Mobile m = o as Mobile; + + if (m == null) + return; + + if (m.NetState == null) + Owner.SendMessage(Data.GetData(Current).SystemC, m.RawName + " " + General.Local(83)); + else + { + Owner.Location = m.Location; + Owner.Map = m.Map; + } + + NewGump(); + } + + private void QuickBar() + { + Data.GetData(Current).QuickBar = !Data.GetData(Current).QuickBar; + NewGump(); + } + + private void Menu() + { + c_Menu = !c_Menu; + + if (c_Menu) + c_Search = false; + + NewGump(); + } + + private void Search() + { + c_Search = !c_Search; + + if (c_Search) + c_Menu = false; + + NewGump(); + } + + private void JoinChannel(object o) + { + Channel c = o as Channel; + + if (c == null) + return; + + if (c.IsIn(Current)) + c.Leave(Current); + else + c.Join(Current); + + NewGump(); + } + + private void ViewChannel(object o) + { + if (!(o is Channel)) + return; + + Data.GetData(Current).CurrentChannel = (Channel)o; + c_ListPage = ListPage.Channel; + NewGump(); + } + + private void Page(object o) + { + if (!(o is ListPage)) + return; + + c_ListPage = (ListPage)o; + NewGump(); + } + + private void History() + { + NewGump(); + new HistoryGump(Owner, Data.GetData(Current).CurrentChannel); + } + + private void GenOpt() + { + NewGump(); + new GeneralGump(Owner); + } + + private void Logging() + { + NewGump(); + new LoggingGump(Owner); + } + + private void Filter() + { + NewGump(); + new FilterGump(Owner); + } + + private void Spam() + { + NewGump(); + new SpamGump(Owner); + } + + private void Colors() + { + NewGump(); + + if(c_Target == null ) + new ColorsGump(Owner); + else + new ColorsGump(Owner, c_Target); + } + + private void Irc() + { + NewGump(); + new IrcGump(Owner); + } + + private void Multi() + { + NewGump(); + new MultiGump(Owner); + } + + private void Mail() + { + NewGump(); + + if (c_Target == null) + new MailGump(Owner); + else + new MailGump(Owner, c_Target); + } + + private void GlobalMenu() + { + NewGump(); + new GlobalGump(Current); + } + + private void Channel() + { + NewGump(); + new ChannelGump(Owner); + } + + private void TxtSearch() + { + c_TxtSearch = GetTextField("Search"); + c_CharSearch = ""; + NewGump(); + } + + private void CharSearch(object o) + { + if (!(o is string)) + return; + + if (c_CharSearch == o.ToString()) + c_CharSearch = ""; + else + c_CharSearch = o.ToString(); + + c_TxtSearch = ""; + + NewGump(); + } + + private void Status() + { + new StatusGump(Owner, this); + } + + private void Broadcast() + { + NewGump(); + new SendMessageGump(Owner, null, "", null, MsgType.System); + } + + private void BroadcastStaff() + { + NewGump(); + new SendMessageGump(Owner, null, "", null, MsgType.Staff); + } + + private void NewNotif() + { + new Notification(); + NewGump(); + } + + private void ClearViewing() + { + c_Target = null; + NewGump(); + } + + private void CheckMsg(object obj) + { + Mobile m = obj as Mobile; + + if (m == null) + return; + + Message msg = Data.GetData(Owner).GetNewMsgFrom(m); + if (msg == null) + NewGump(); + else + Open(msg); + } + + private void SkinChange(object obj) + { + if (!(obj is Skin)) + return; + + Data.GetData(Owner).MenuSkin = (Skin)obj; + General.List(Owner, (int)c_ListPage); + } + + #endregion + + #region Internal Classes + + private class InternalSort : IComparer + { + private GumpPlus c_Gump; + + public InternalSort(GumpPlus gump) + { + c_Gump = gump; + } + + public int Compare(object x, object y) + { + if (x is Mobile && y is Mobile) + { + if (((Mobile)x).NetState == null && ((Mobile)y).NetState != null) + return 1; + if (((Mobile)x).NetState != null && ((Mobile)y).NetState == null) + return -1; + + if (!Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)x)) && Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)y))) + return 1; + if (Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)x)) && !Data.GetData(c_Gump.Owner).NewMsgFrom(((Mobile)y))) + return -1; + + if (((Mobile)x).AccessLevel < ((Mobile)y).AccessLevel) + return 1; + if (((Mobile)x).AccessLevel > ((Mobile)y).AccessLevel) + return -1; + + return Insensitive.Compare(((Mobile)x).RawName, ((Mobile)y).RawName); + } + else if (x is string && y is string) + return Insensitive.Compare(x.ToString(), y.ToString()); + else if (x is string) + return 1; + else if (y is string) + return -1; + else if (x is Message && y is Message) + { + if (((Message)x).Received > ((Message)y).Received) + return -1; + if (((Message)x).Received < ((Message)y).Received) + return 1; + } + + return Insensitive.Compare(x.ToString(), y.ToString()); + } + } + + private class BanGump : GumpPlus + { + private GumpPlus c_Gump; + private Mobile c_Target; + + public BanGump(Mobile m, GumpPlus g) + : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 200; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(160)); + AddImage(width / 2 - 70, y + 2, 0x39); + AddImage(width / 2 + 40, y + 2, 0x3B); + + AddHtml(0, y += 20, width, "
" + General.Local(161)); + AddButton(width / 2 - 60, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddHtml(0, y += 20, width, "
" + General.Local(162)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddHtml(0, y += 20, width, "
" + General.Local(163)); + AddButton(width / 2 - 60, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddButton(width / 2 + 50, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddHtml(0, y += 20, width, "
" + General.Local(164)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddHtml(0, y += 20, width, "
" + General.Local(165)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddHtml(0, y += 20, width, "
" + General.Local(166)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddHtml(0, y += 20, width, "
" + General.Local(167)); + AddButton(width / 2 - 60, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + AddButton(width / 2 + 50, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack); + } + + private void BanTime(object o) + { + if (!(o is TimeSpan)) + return; + + Data.GetData(c_Target).Ban((TimeSpan)o); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(77) + " " + c_Target.RawName); + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + private class StatusGump : GumpPlus + { + private GumpPlus c_Gump; + + public StatusGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + m.CloseGump(typeof(StatusGump)); + + c_Gump = g; + } + + protected override void BuildGump() + { + int width = 100; + int y = 20; + + AddHtml(0, y, width, "
" + General.Local(19)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Online", new GumpStateCallback(Status), OnlineStatus.Online); + AddButton(width / 2 + 40, y + 3, 0x2716, "Online", new GumpStateCallback(Status), OnlineStatus.Online); + AddHtml(0, y += 20, width, "
" + General.Local(20)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Away", new GumpStateCallback(Status), OnlineStatus.Away); + AddButton(width / 2 + 40, y + 3, 0x2716, "Away", new GumpStateCallback(Status), OnlineStatus.Away); + AddHtml(0, y += 20, width, "
" + General.Local(21)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Busy", new GumpStateCallback(Status), OnlineStatus.Busy); + AddButton(width / 2 + 40, y + 3, 0x2716, "Busy", new GumpStateCallback(Status), OnlineStatus.Busy); + AddHtml(0, y += 20, width, "
" + General.Local(22)); + AddButton(width / 2 - 50, y + 3, 0x2716, "Hidden", new GumpStateCallback(Status), OnlineStatus.Hidden); + AddButton(width / 2 + 40, y + 3, 0x2716, "Hidden", new GumpStateCallback(Status), OnlineStatus.Hidden); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + } + + private void Status(object o) + { + if (!(o is OnlineStatus)) + return; + + Data.GetData(Owner).Status = (OnlineStatus)o; + + if ((OnlineStatus)o == OnlineStatus.Away || (OnlineStatus)o == OnlineStatus.Busy) + new AwayGump(Owner, c_Gump); + else + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + + private class AwayGump : GumpPlus + { + private GumpPlus c_Gump; + + public AwayGump(Mobile m, GumpPlus g) + : base(m, 100, 100) + { + m.CloseGump(typeof(AwayGump)); + + c_Gump = g; + } + + protected override void BuildGump() + { + AddBackground(0, 0, 200, 200, Data.GetData(Owner).DefaultBack); + + AddHtml(0, 10, 200, "
" + General.Local(12)); + AddTextField(10, 30, 180, 120, 0x480, 0xBBC, "Away", Data.GetData(Owner).AwayMsg); + AddButton(60, 160, 0xFB1, 0xFB3, "Clear", new GumpCallback(ClearMsg)); + AddButton(120, 160, 0xFB7, 0xFB9, "Submit", new GumpCallback(Submit)); + } + + private void ClearMsg() + { + Data.GetData(Owner).AwayMsg = ""; + NewGump(); + } + + private void Submit() + { + Data.GetData(Owner).AwayMsg = GetTextField("Away"); + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/LoggingGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/LoggingGump.cs new file mode 100644 index 0000000..f04e34f --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/LoggingGump.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class LoggingGump : GumpPlus + { + public LoggingGump(Mobile m) + : base(m, 100, 100) + { + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(237)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(238)); + AddButton(width / 2 - 60, y, Data.LogChat ? 0x2343 : 0x2342, "Log Chat", new GumpCallback(Chat)); + AddButton(width / 2 + 40, y, Data.LogChat ? 0x2343 : 0x2342, "Log Chat", new GumpCallback(Chat)); + + AddHtml(0, y += 25, width, "
" + General.Local(239)); + AddButton(width / 2 - 60, y, Data.LogPms ? 0x2343 : 0x2342, "Log Pms", new GumpCallback(Pms)); + AddButton(width / 2 + 40, y, Data.LogPms ? 0x2343 : 0x2342, "Log Pms", new GumpCallback(Pms)); + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(Owner).DefaultBack); + } + + private void Chat() + { + Data.LogChat = !Data.LogChat; + NewGump(); + } + + private void Pms() + { + Data.LogPms = !Data.LogPms; + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MailGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MailGump.cs new file mode 100644 index 0000000..0f4e709 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MailGump.cs @@ -0,0 +1,131 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class MailGump : GumpPlus + { + private Mobile c_Target; + + public Mobile Current { get { return (c_Target == null ? Owner : c_Target); } } + + public MailGump(Mobile m, Mobile targ) + : base(m, 100, 100) + { + c_Target = targ; + } + + public MailGump(Mobile m) + : this(m, null) + { + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(217)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + if (c_Target != null) + AddHtml(0, y += 25, width, "
" + General.Local(224) + " " + c_Target.RawName); + + AddHtml(0, y += 25, width, "
" + General.Local(58)); + AddButton(width / 2 - 120, y, Data.GetData(Current).SevenDays ? 0x2343 : 0x2342, "Seven Days", new GumpCallback(SevenDays)); + AddButton(width / 2 + 100, y, Data.GetData(Current).SevenDays ? 0x2343 : 0x2342, "Seven Days", new GumpCallback(SevenDays)); + AddHtml(0, y += 20, width, "
" + General.Local(259)); + AddButton(width / 2 - 120, y, Data.GetData(Current).WhenFull ? 0x2343 : 0x2342, "When Full", new GumpCallback(WhenFull)); + AddButton(width / 2 + 100, y, Data.GetData(Current).WhenFull ? 0x2343 : 0x2342, "When Full", new GumpCallback(WhenFull)); + AddHtml(0, y += 20, width, "
" + General.Local(24)); + AddButton(width / 2 - 120, y, Data.GetData(Current).FriendsOnly ? 0x2343 : 0x2342, "Friends Only", new GumpCallback(FriendsOnly)); + AddButton(width / 2 + 100, y, Data.GetData(Current).FriendsOnly ? 0x2343 : 0x2342, "Friends Only", new GumpCallback(FriendsOnly)); + AddHtml(0, y += 20, width, "
" + General.Local(25)); + AddButton(width / 2 - 120, y, Data.GetData(Current).ByRequest ? 0x2343 : 0x2342, "Friend Request", new GumpCallback(FriendRequest)); + AddButton(width / 2 + 100, y, Data.GetData(Current).ByRequest ? 0x2343 : 0x2342, "Friend Request", new GumpCallback(FriendRequest)); + AddHtml(0, y += 20, width, "
" + General.Local(30)); + AddButton(width / 2 - 120, y, Data.GetData(Current).FriendAlert ? 0x2343 : 0x2342, "Friend Alert", new GumpCallback(FriendAlert)); + AddButton(width / 2 + 100, y, Data.GetData(Current).FriendAlert ? 0x2343 : 0x2342, "Friend Alert", new GumpCallback(FriendAlert)); + AddHtml(0, y += 20, width, "
" + General.Local(196)); + AddButton(width / 2 - 120, y, Data.GetData(Current).ReadReceipt ? 0x2343 : 0x2342, "Read Receipt", new GumpCallback(ReadReceipt)); + AddButton(width / 2 + 100, y, Data.GetData(Current).ReadReceipt ? 0x2343 : 0x2342, "Read Receipt", new GumpCallback(ReadReceipt)); + + AddHtml(0, y += 25, width, "
" + General.Local(27)); + AddButton(width / 2 - 120, y, Data.GetData(Current).MsgSound ? 0x2343 : 0x2342, "Message Sound", new GumpCallback(MessageSound)); + AddButton(width / 2 + 100, y, Data.GetData(Current).MsgSound ? 0x2343 : 0x2342, "Message Sound", new GumpCallback(MessageSound)); + + if (Data.GetData(Current).MsgSound) + { + AddHtml(0, y += 30, width, "
" + General.Local(28)); + AddTextField(width/2-25, y, 50, 21, 0x480, 0xBBA, "Sound", Data.GetData(Current).DefaultSound.ToString()); + AddButton(width/2+30, y + 3, 0x15E1, 0x15E5, "Play Sound", new GumpCallback(PlaySound)); + AddButton(width/2-40, y, 0x983, "Sound Up", new GumpCallback(SoundUp)); + AddButton(width/2-40, y + 10, 0x985, "Sound Down", new GumpCallback(SoundDown)); + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Current).DefaultBack); + } + + private void SevenDays() + { + Data.GetData(Current).SevenDays = !Data.GetData(Current).SevenDays; + NewGump(); + } + + private void WhenFull() + { + Data.GetData(Current).WhenFull = !Data.GetData(Current).WhenFull; + NewGump(); + } + + private void FriendsOnly() + { + Data.GetData(Current).FriendsOnly = !Data.GetData(Current).FriendsOnly; + NewGump(); + } + + private void FriendRequest() + { + Data.GetData(Current).ByRequest = !Data.GetData(Current).ByRequest; + NewGump(); + } + + private void FriendAlert() + { + Data.GetData(Current).FriendAlert = !Data.GetData(Current).FriendAlert; + NewGump(); + } + + private void ReadReceipt() + { + Data.GetData(Current).ReadReceipt = !Data.GetData(Current).ReadReceipt; + NewGump(); + } + + private void MessageSound() + { + Data.GetData(Current).MsgSound = !Data.GetData(Current).MsgSound; + NewGump(); + } + + private void PlaySound() + { + Data.GetData(Current).DefaultSound = GetTextFieldInt("Sound"); + Owner.SendSound(Data.GetData(Current).DefaultSound); + NewGump(); + } + + private void SoundUp() + { + Data.GetData(Current).DefaultSound = Data.GetData(Current).DefaultSound + 1; + NewGump(); + } + + private void SoundDown() + { + Data.GetData(Current).DefaultSound = Data.GetData(Current).DefaultSound - 1; + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MessageGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MessageGump.cs new file mode 100644 index 0000000..1387706 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MessageGump.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; +using Server; + +namespace Knives.Chat3 +{ + public class MessageGump : GumpPlus + { + + #region Class Definitions + + private Message c_Message; + + #endregion + + #region Constructors + + public MessageGump(Mobile m, Message msg) : base(m, 200, 400) + { + Override = true; + + c_Message = msg; + + if (Data.GetData(Owner).Messages.Contains(msg)) + msg.Read = true; + } + + #endregion + + #region Methods + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddImage(10, y, 0x589); + Avatar av = Avatar.GetAvatar(c_Message.From); + + if (av.Id < 100000) + AddImage(10 + av.X, y + av.Y, av.Id); + else + AddItem(10 + av.X, y + av.Y, av.Id-100000); + + AddButton(20, 20, 0x2716, "Profile", new GumpCallback(Profile)); + + AddHtml(95, y += 15, width-105, General.Local(60) + " " + c_Message.From.RawName); + AddHtml(95, y += 20, width-105, 42, c_Message.Subject, false, false); + + AddHtml(20, y += 50, width-40, 80, HTML.Black + c_Message.Msg, true, true); + y += 90; + + if (Data.GetData(Owner).Messages.Contains(c_Message)) + { + if (c_Message.Type == MsgType.Normal) + { + if (Message.CanMessage(Owner, c_Message.From) && !Message.StaffTimeout(c_Message)) + { + AddHtml(width - 85, y, 50, General.Local(248)); + AddButton(width - 100, y+3, 0x2716, "Reply", new GumpCallback(Reply)); + } + + AddHtml(width - 145, y, 50, General.Local(249)); + AddButton(width-160, y+3, 0x2716, "Delete", new GumpCallback(Delete)); + + if (c_Message.From.AccessLevel == AccessLevel.Player) + { + AddHtml(95, y, 50, General.Local(2)); + AddButton(80, y+3, 0x2716, "Ignore", new GumpCallback(Ignore)); + } + } + else if (c_Message.Type == MsgType.Invite) + { + AddHtml(width - 85, y, 50, General.Local(250)); + AddButton(width - 100, y+3, 0x2716, "Accept", new GumpCallback(Accept)); + + AddHtml(width - 145, y, 50, General.Local(251)); + AddButton(width - 160, y+3, 0x2716, "Deny", new GumpCallback(Deny)); + + if (c_Message.From.AccessLevel == AccessLevel.Player) + { + AddHtml(95, y, 50, General.Local(2)); + AddButton(80, y+3, 0x2716, "Ignore", new GumpCallback(Ignore)); + } + } + } + + AddBackgroundZero(0, 0, width, y + 30, Data.GetData(Owner).DefaultBack); + } + + #endregion + + #region Responses + + private void Profile() + { + NewGump(); + new ProfileGump(Owner, c_Message.From); + } + + private void Reply() + { + if (Message.CanMessage(Owner, c_Message.From)) + new SendMessageGump(Owner, c_Message.From, "", c_Message, MsgType.Normal); + } + + private void Delete() + { + Data.GetData(Owner).DeleteMessage(c_Message); + } + + private void Ignore() + { + Data.GetData(Owner).Ignores.Add(c_Message.From); + + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(68) + " " + c_Message.From.RawName); + if (c_Message.Type == MsgType.Invite) + Deny(); + } + + private void Accept() + { + c_Message.From.SendMessage(Data.GetData(c_Message.From).SystemC, Owner.RawName + " " + General.Local(87)); + + Data.GetData(Owner).AddFriend(c_Message.From); + Data.GetData(c_Message.From).AddFriend(Owner); + + Data.GetData(Owner).Messages.Remove(c_Message); + } + + private void Deny() + { + c_Message.From.SendMessage(Data.GetData(c_Message.From).SystemC, Owner.RawName + " " + General.Local(88)); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(89) + " " + c_Message.From.RawName); + + Data.GetData(Owner).Messages.Remove(c_Message); + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MultiGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MultiGump.cs new file mode 100644 index 0000000..2c570bc --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/MultiGump.cs @@ -0,0 +1,126 @@ +// ALlow Pms over the Multi, track with name, server, serial +// Mc, MultiChat, change the channel options to go to Multi + +using System; +using Server; + +namespace Knives.Chat3 +{ + public class MultiGump : GumpPlus + { + public MultiGump(Mobile m) + : base(m, 100, 100) + { + m.CloseGump(typeof(MultiGump)); + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(283)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
" + General.Local(177)); + AddButton(width / 2 - 80, y+3, 0x2716, "Channel Options", new GumpCallback(ChannelOptions)); + AddButton(width / 2 + 60, y+3, 0x2716, "Channel Options", new GumpCallback(ChannelOptions)); + + AddHtml(0, y += 25, width, "
" + General.Local(284)); + AddButton(width/2-80, y, Data.MultiMaster ? 0x2343 : 0x2342, "Multi Master", new GumpCallback(MultiMaster)); + AddButton(width/2+60, y, Data.MultiMaster ? 0x2343 : 0x2342, "Multi Master", new GumpCallback(MultiMaster)); + + if (Data.MultiMaster) + { + if (!MultiConnection.Connection.Connected) + { + AddHtml(0, y += 40, width, "
" + General.Local(286)); + AddButton(width / 2 - 60, y + 4, 0x2716, "Start", new GumpCallback(Start)); + AddButton(width / 2 + 50, y + 4, 0x2716, "Start", new GumpCallback(Start)); + } + else + { + y += 10; + + foreach (string name in MultiConnection.Connection.Names.Values) + { + AddHtml(35, y += 20, width - 35, name); + AddButton(width - 40, y, Data.MultiBlocks.Contains(name) ? 0x5687 : 0x5686, "Multi Block", new GumpStateCallback(MultiBlock), name); + } + } + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(Owner).DefaultBack); + return; + } + + AddHtml(0, y += 25, width / 2 - 10, "
" + General.Local(118)); + AddTextField(width / 2 + 10, y, 100, 21, 0x480, 0xBBA, "Server", Data.MultiServer); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddHtml(0, y += 20, width / 2 - 10, "
" + General.Local(120)); + AddTextField(width / 2 + 10, y, 70, 21, 0x480, 0xBBA, "Port", "" + Data.MultiPort); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + int num = 139; + + if (MultiConnection.Connection.Connected) + num = 141; + if (MultiConnection.Connection.Connecting) + num = 140; + + AddHtml(0, y += 40, width, "
" + General.Local(num)); + AddButton(width / 2 - 60, y + 4, 0x2716, "Connect or Cancel or Close", new GumpCallback(ConnectCancelClose)); + AddButton(width / 2 + 50, y + 4, 0x2716, "Connect or Cancel or Close", new GumpCallback(ConnectCancelClose)); + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(Owner).DefaultBack); + } + + private void ChannelOptions() + { + NewGump(); + new ChannelGump(Owner, Channel.GetByType(typeof(Multi))); + } + + private void MultiBlock(object obj) + { + Data.MultiBlocks.Add(obj.ToString()); + MultiConnection.Connection.Block(obj.ToString()); + NewGump(); + } + + private void MultiMaster() + { + Data.MultiMaster = !Data.MultiMaster; + NewGump(); + } + + private void Submit() + { + Data.MultiServer = GetTextField("Server"); + Data.MultiPort = GetTextFieldInt("Port"); + NewGump(); + } + + private void Start() + { + MultiConnection.Connection.ConnectMaster(); + NewGump(); + } + + private void ConnectCancelClose() + { + Data.MultiServer = GetTextField("Server"); + Data.MultiPort = GetTextFieldInt("Port"); + + if (MultiConnection.Connection.Connected) + MultiConnection.Connection.CloseSlave(); + else if (MultiConnection.Connection.Connecting) + MultiConnection.Connection.CloseSlave(); + else if (!MultiConnection.Connection.Connected) + MultiConnection.Connection.ConnectSlave(); + + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/PmNotifyGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/PmNotifyGump.cs new file mode 100644 index 0000000..42708e6 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/PmNotifyGump.cs @@ -0,0 +1,24 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class PmNotifyGump : GumpPlus + { + public PmNotifyGump( Mobile m ) : base( m, 200, 50 ) + { + m.CloseGump( typeof( PmNotifyGump ) ); + } + + protected override void BuildGump() + { + AddImage(0, 0, 0x15D5); + AddButton(13, 13, 0xFC4, "Message", new GumpCallback(Message)); + } + + private void Message() + { + General.List(Owner, 2); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ProfileGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ProfileGump.cs new file mode 100644 index 0000000..664e2c8 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/ProfileGump.cs @@ -0,0 +1,395 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class ProfileGump : GumpPlus + { + private Mobile c_Target; + + public ProfileGump(Mobile m, Mobile targ) + : base(m, 100, 100) + { + Override = true; + + c_Target = targ; + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddImage(10, y, 0x589); + Avatar av = Avatar.GetAvatar(c_Target); + if (av.Id < 100000) + AddImage(10 + av.X, y + av.Y, av.Id); + else + AddItem(10 + av.X, y + av.Y, av.Id - 100000); + + AddHtml(95, y, width-95, Server.Misc.Titles.ComputeTitle(Owner, c_Target)); + + if (Owner.AccessLevel != AccessLevel.Player) + AddHtml(95, y += 20, width - 95, "Access: " + c_Target.AccessLevel); + else if (c_Target.AccessLevel != AccessLevel.Player) + AddHtml(95, y += 20, width - 95, "" + c_Target.AccessLevel); + else + { + if (c_Target.Guild != null) + AddHtml(95, y += 20, width - 95, "[" + c_Target.Guild.Abbreviation + "] " + c_Target.GuildTitle); + if (General.IsInFaction(c_Target)) + AddHtml(95, y += 20, width - 95, General.FactionName(c_Target) + " " + General.FactionTitle(c_Target)); + } + + if (y < 89) + y = 89; + + if (Owner == c_Target) + { + AddButton(32, y, 0x2626, 0x2627, "Avatar Down", new GumpCallback(AvatarDown)); + AddButton(52, y, 0x2622, 0x2623, "Avatar Up", new GumpCallback(AvatarUp)); + } + + AddHtml(0, y+=20, width, "
" + General.Local(253) + " " + Data.GetData(c_Target).Karma); + + if (Owner == c_Target) + { + AddHtml(20, y += 25, 100, General.Local(247)); + AddTextField(20, y+=25, width - 40, 65, 0x480, 0xBBC, "Signature", Data.GetData(c_Target).Signature); + AddHtml(width - 125, y += 65, 50, General.Local(244)); + AddHtml(width - 65, y, 50, General.Local(245)); + AddButton(width - 140, y + 3, 0x2716, "Clear Sig", new GumpCallback(ClearSig)); + AddButton(width - 80, y + 3, 0x2716, "Submit Sig", new GumpCallback(SubmitSig)); + } + else + { + AddHtml(20, y += 25, width - 40, 65, "'" + Data.GetData(c_Target).Signature + "'", false, false); + y += 65; + } + + if (Owner != c_Target) + ViewOptions(width); + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(c_Target).DefaultBack); + } + + private void ViewOptions(int x) + { + int y = 10; + int width = 150; + + AddHtml(x, y += 10, width, "
" + General.Local(0)); + AddButton(x + width / 2 - 60, y, Data.GetData(Owner).Friends.Contains(c_Target) ? 0x2343 : 0x2342, "Friend", new GumpCallback(Friend)); + AddButton(x + width / 2 + 40, y, Data.GetData(Owner).Friends.Contains(c_Target) ? 0x2343 : 0x2342, "Friend", new GumpCallback(Friend)); + + AddHtml(x, y += 20, width, "
" + General.Local(2)); + AddButton(x + width / 2 - 60, y, Data.GetData(Owner).Ignores.Contains(c_Target) ? 0x2343 : 0x2342, "Ignore", new GumpCallback(Ignore)); + AddButton(x + width / 2 + 40, y, Data.GetData(Owner).Ignores.Contains(c_Target) ? 0x2343 : 0x2342, "Ignore", new GumpCallback(Ignore)); + + if (Chat3.Message.CanMessage(Owner, c_Target)) + { + AddHtml(x, y += 20, width, "
" + General.Local(13)); + AddButton(x + width / 2 - 60, y + 3, 0x2716, "Send Message", new GumpCallback(Message)); + AddButton(x + width / 2 + 50, y + 3, 0x2716, "Send Message", new GumpCallback(Message)); + } + + if (Owner.AccessLevel >= AccessLevel.Administrator) + { + if (Owner.AccessLevel > c_Target.AccessLevel) + { + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(14), false); + AddButton(x + width / 2 - 60, y + 3, 0x2716, "Become User", new GumpCallback(BecomeUser)); + AddButton(x + width / 2 + 50, y + 3, 0x2716, "Become User", new GumpCallback(BecomeUser)); + } + + if (c_Target.AccessLevel < AccessLevel.Administrator && c_Target.AccessLevel != AccessLevel.Player) + { + AddHtml(x, y += 20, width, HTML.LightPurple + "
" + General.Local(4), false); + AddButton(x + width / 2 - 60, y, Data.GetData(c_Target).GlobalAccess ? 0x2343 : 0x2342, "Global Access", new GumpCallback(GlobalAccess)); + AddButton(x + width / 2 + 40, y, Data.GetData(c_Target).GlobalAccess ? 0x2343 : 0x2342, "Global Access", new GumpCallback(GlobalAccess)); + } + } + + if (Owner.AccessLevel >= AccessLevel.GameMaster && c_Target.AccessLevel == AccessLevel.Player) + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(6), false); + AddButton(x + width / 2 - 60, y, Data.GetData(c_Target).Banned ? 0x2343 : 0x2342, "Ban", new GumpCallback(Ban)); + AddButton(x + width / 2 + 40, y, Data.GetData(c_Target).Banned ? 0x2343 : 0x2342, "Ban", new GumpCallback(Ban)); + } + + if (Data.GetData(Owner).GlobalAccess) + { + y += 20; + + if (Data.GetData(Owner).Global) + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(8), false); + AddButton(x + width / 2 - 60, y, Data.GetData(Owner).GIgnores.Contains(c_Target) ? 0x2343 : 0x2342, "Global Ignore", new GumpCallback(GIgnore)); + AddButton(x + width / 2 + 40, y, Data.GetData(Owner).GIgnores.Contains(c_Target) ? 0x2343 : 0x2342, "Global Ignore", new GumpCallback(GIgnore)); + } + else + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(10), false); + AddButton(x + width / 2 - 60, y, Data.GetData(Owner).GListens.Contains(c_Target) ? 0x2343 : 0x2342, "Global Listen", new GumpCallback(GListen)); + AddButton(x + width / 2 + 40, y, Data.GetData(Owner).GListens.Contains(c_Target) ? 0x2343 : 0x2342, "Global Listen", new GumpCallback(GListen)); + } + } + + if (Owner.AccessLevel >= AccessLevel.GameMaster && c_Target.NetState != null) + { + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(15), false); + AddButton(x + width / 2 - 60, y + 3, 0x2716, "Client", new GumpCallback(Client)); + AddButton(x + width / 2 + 50, y + 3, 0x2716, "Client", new GumpCallback(Client)); + + AddHtml(x, y += 20, width, HTML.Red + "
" + General.Local(16), false); + AddButton(x + width / 2 - 60, y + 3, 0x2716, "Goto", new GumpCallback(Goto)); + AddButton(x + width / 2 + 50, y + 3, 0x2716, "Goto", new GumpCallback(Goto)); + } + + if (Data.GetData(Owner).MsgSound) + { + AddHtml(x, y += 25, width, "
" + General.Local(17)); + AddImageTiled(x + width / 2 - 25, y += 25, 50, 21, 0xBBA); + AddTextField(x + width / 2 - 25, y, 50, 21, 0x480, 0xBBA, "Sound", Data.GetData(Owner).GetSound(c_Target).ToString()); + AddButton(x + width / 2 + 30, y + 3, 0x15E1, 0x15E5, "Play Sound", new GumpCallback(PlaySound)); + AddButton(x + width / 2 - 40, y, 0x983, "Sound Up", new GumpCallback(SoundUp)); + AddButton(x + width / 2 - 40, y + 10, 0x985, "Sound Down", new GumpCallback(SoundDown)); + } + + AddBackgroundZero(x, 0, width, y + 40, Data.GetData(c_Target).DefaultBack, false); + } + + private void ClearSig() + { + Data.GetData(Owner).Signature = ""; + NewGump(); + } + + private void SubmitSig() + { + Data.GetData(Owner).Signature = GetTextField("Signature"); + NewGump(); + } + + private void Friend() + { + if (Data.GetData(c_Target).ByRequest && !Data.GetData(Owner).Friends.Contains(c_Target)) + { + if (!TrackSpam.LogSpam(Owner, "Request " + c_Target.Name, TimeSpan.FromHours(Data.RequestSpam))) + { + TimeSpan ts = TrackSpam.NextAllowedIn(Owner, "Request " + c_Target.Name, TimeSpan.FromHours(Data.RequestSpam)); + string txt = (ts.Days != 0 ? ts.Days + " " + General.Local(170) + " " : "") + (ts.Hours != 0 ? ts.Hours + " " + General.Local(171) + " " : "") + (ts.Minutes != 0 ? ts.Minutes + " " + General.Local(172) + " " : ""); + + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(96) + " " + txt); + NewGump(); + return; + } + + Data.GetData(c_Target).AddMessage(new Message(Owner, General.Local(84), General.Local(85), MsgType.Invite)); + + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(86) + " " + c_Target.Name); + + NewGump(); + + return; + } + + if (Data.GetData(Owner).Friends.Contains(c_Target)) + Data.GetData(Owner).RemoveFriend(c_Target); + else + Data.GetData(Owner).AddFriend(c_Target); + + NewGump(); + } + + private void Ignore() + { + if (Data.GetData(Owner).Ignores.Contains(c_Target)) + Data.GetData(Owner).RemoveIgnore(c_Target); + else + Data.GetData(Owner).AddIgnore(c_Target); + + NewGump(); + } + + private void Message() + { + NewGump(); + + if (Chat3.Message.CanMessage(Owner, c_Target)) + new SendMessageGump(Owner, c_Target, "", null, MsgType.Normal); + } + + private void GlobalAccess() + { + Data.GetData(c_Target).GlobalAccess = !Data.GetData(c_Target).GlobalAccess; + + if (Data.GetData(c_Target).GlobalAccess) + Owner.SendMessage(Data.GetData(Owner).SystemC, c_Target.Name + " " + General.Local(75)); + else + Owner.SendMessage(Data.GetData(Owner).SystemC, c_Target.Name + " " + General.Local(76)); + + NewGump(); + } + + private void Ban() + { + if (Data.GetData(c_Target).Banned) + { + Data.GetData(c_Target).RemoveBan(); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(78) + " " + c_Target.Name); + NewGump(); + } + else + new BanGump(c_Target, this); + } + + private void GIgnore() + { + if (Data.GetData(Owner).GIgnores.Contains(c_Target)) + Data.GetData(Owner).RemoveGIgnore(c_Target); + else + Data.GetData(Owner).AddGIgnore(c_Target); + + NewGump(); + } + + private void GListen() + { + if (Data.GetData(Owner).GListens.Contains(c_Target)) + Data.GetData(Owner).RemoveGListen(c_Target); + else + Data.GetData(Owner).AddGListen(c_Target); + + NewGump(); + } + + private void Client() + { + NewGump(); + + if (c_Target.NetState == null) + Owner.SendMessage(Data.GetData(Owner).SystemC, c_Target.Name + " " + General.Local(83)); + else + Owner.SendGump(new ClientGump(Owner, c_Target.NetState)); + } + + private void Goto() + { + if (c_Target.NetState == null) + Owner.SendMessage(Data.GetData(Owner).SystemC, c_Target.Name + " " + General.Local(83)); + else + { + Owner.Location = c_Target.Location; + Owner.Map = c_Target.Map; + } + + NewGump(); + } + + private void BecomeUser() + { + NewGump(); + + General.List(Owner, c_Target); + } + + private void PlaySound() + { + Data.GetData(Owner).SetSound(c_Target, GetTextFieldInt("Sound")); + Owner.SendSound(Data.GetData(Owner).GetSound(c_Target)); + + NewGump(); + } + + private void SoundUp() + { + Data.GetData(Owner).SetSound(c_Target, Data.GetData(Owner).GetSound(c_Target) + 1); + + NewGump(); + } + + private void SoundDown() + { + Data.GetData(Owner).SetSound(c_Target, Data.GetData(Owner).GetSound(c_Target) - 1); + + NewGump(); + } + + private void AvatarUp() + { + Data.GetData(c_Target).AvatarUp(); + + NewGump(); + } + + private void AvatarDown() + { + Data.GetData(c_Target).AvatarDown(); + + NewGump(); + } + + + private class BanGump : GumpPlus + { + private GumpPlus c_Gump; + private Mobile c_Target; + + public BanGump(Mobile m, GumpPlus g) : base(g.Owner, 100, 100) + { + c_Gump = g; + c_Target = m; + } + + protected override void BuildGump() + { + int width = 150; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(160)); + + AddHtml(0, y += 20, width, "
" + General.Local(161)); + AddButton(width / 2 - 50, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddButton(width / 2 + 40, y + 3, 0x2716, "30 minutes", new GumpStateCallback(BanTime), TimeSpan.FromMinutes(30)); + AddHtml(0, y += 20, width, "
" + General.Local(162)); + AddButton(width / 2 - 50, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddButton(width / 2 + 40, y + 3, 0x2716, "1 hour", new GumpStateCallback(BanTime), TimeSpan.FromHours(1)); + AddHtml(0, y += 20, width, "
" + General.Local(163)); + AddButton(width / 2 - 50, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddButton(width / 2 + 40, y + 3, 0x2716, "12 hours", new GumpStateCallback(BanTime), TimeSpan.FromHours(12)); + AddHtml(0, y += 20, width, "
" + General.Local(164)); + AddButton(width / 2 - 50, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddButton(width / 2 + 40, y + 3, 0x2716, "1 day", new GumpStateCallback(BanTime), TimeSpan.FromDays(1)); + AddHtml(0, y += 20, width, "
" + General.Local(165)); + AddButton(width / 2 - 50, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddButton(width / 2 + 40, y + 3, 0x2716, "1 week", new GumpStateCallback(BanTime), TimeSpan.FromDays(7)); + AddHtml(0, y += 20, width, "
" + General.Local(166)); + AddButton(width / 2 - 50, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddButton(width / 2 + 40, y + 3, 0x2716, "1 month", new GumpStateCallback(BanTime), TimeSpan.FromDays(30)); + AddHtml(0, y += 20, width, "
" + General.Local(167)); + AddButton(width / 2 - 50, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + AddButton(width / 2 + 40, y + 3, 0x2716, "1 year", new GumpStateCallback(BanTime), TimeSpan.FromDays(365)); + + AddBackgroundZero(0, 0, width, y + 40, Data.GetData(c_Target).DefaultBack); + } + + private void BanTime(object o) + { + if (!(o is TimeSpan)) + return; + + Data.GetData(c_Target).Ban((TimeSpan)o); + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(77) + " " + c_Target.Name); + + c_Gump.NewGump(); + } + + protected override void OnClose() + { + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/SendMessageGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/SendMessageGump.cs new file mode 100644 index 0000000..59170cb --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/SendMessageGump.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections; +using Server; +using Server.HuePickers; + +namespace Knives.Chat3 +{ + public class SendMessageGump : GumpPlus + { + #region Class Definitions + + private Mobile c_From, c_To; + private Message c_Reply; + private string c_Text, c_Subject; + private MsgType c_MsgType; + + #endregion + + #region Constructors + + public SendMessageGump(Mobile from, Mobile to, string txt, Message reply, MsgType type) + : base(from, 200, 200) + { + from.CloseGump(typeof(SendMessageGump)); + + Override = true; + + c_From = from; + c_To = to; + c_Text = txt; + c_Subject = ""; + c_Reply = reply; + c_MsgType = type; + + if (c_Reply != null) + { + if (c_Reply.Subject.IndexOf("RE:") != 0) + c_Subject = "RE: " + c_Reply.Subject; + else + c_Subject = c_Reply.Subject; + } + } + + #endregion + + #region Methods + + protected override void BuildGump() + { + int width = Data.GetData(Owner).ExtraPm ? 400 : 300; + int y = 10; + int field = Data.GetData(Owner).ExtraPm ? 300 : 150; + + if (c_MsgType == MsgType.System) + AddHtml(0, y, width, "
" + General.Local(94)); + else if (c_MsgType == MsgType.Staff) + AddHtml(0, y, width, "
" + General.Local(256)); + else + AddHtml(0, y, width, "
" + General.Local(62) + " " + c_To.RawName); + + AddImage(width / 2 - 120, y + 2, 0x39); + AddImage(width / 2 + 90, y + 2, 0x3B); + + if (Data.GetData(Owner).Recording == this) + { + AddHtml(30, y+=20, width-60, 25, c_Subject, true, false); + AddHtml(20, y+=30, width-40, field, c_Text, true, true); + AddHtml(0, y+=(field+20), width, "
" + General.Local(63)); + } + else + { + AddTextField(30, y+=20, width - 60, 21, Data.GetData(Owner).MsgC, 0xBBC, "Subject", c_Subject); + AddTextField(20, y+=30, width - 40, field, Data.GetData(Owner).MsgC, 0xBBC, "Text", c_Text); + + y+=(field+15); + + if(Data.GetData(Owner).ExtraPm) + AddButton(20, y, 0x2333, "Record", new GumpCallback(Record)); + + AddButton(50, y, Data.GetData(Owner).ExtraPm ? 0x25E4 : 0x25E8, Data.GetData(Owner).ExtraPm ? 0x25E5 : 0x25E9, "ExtraPm", new GumpCallback(ExtraPm)); + } + + AddImage(width / 2 - 10, y, 0x2342, Data.GetData(Owner).MsgC); + AddButton(width / 2 - 6, y + 4, 0x2716, "Channel Color", new GumpCallback(Color)); + AddHtml(width - 85, y, 50, General.Local(252)); + AddButton(width-100, y+3, 0x2716, "Send", new GumpCallback(Send)); + + AddBackgroundZero(0, 0, width, y + 30, Data.GetData(Owner).DefaultBack); + } + + #endregion + + #region Responses + + private void ExtraPm() + { + Data.GetData(Owner).ExtraPm = !Data.GetData(Owner).ExtraPm; + NewGump(); + } + + public void AddText(string txt) + { + c_Text += txt; + NewGump(); + } + + private void Save() + { + c_Subject = GetTextField("Subject"); + c_Text = GetTextField("Text"); + } + + private void Record() + { + Save(); + + if (c_Subject.Trim() == "") + c_Subject = "No Subject"; + + Data.GetData(Owner).Recording = this; + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(65)); + + NewGump(); + } + + private void Send() + { + if( Data.GetData(Owner).Recording == null ) + Save(); + + if (c_Text.Trim() == "") + { + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(66)); + NewGump(); + return; + } + + if (c_Subject.Trim() == "") + c_Subject = "No subject"; + + if (!TrackSpam.LogSpam(Owner, "Message", TimeSpan.FromSeconds(Data.MsgSpam))) + { + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(97)); + NewGump(); + return; + } + + if (Data.GetData(Owner).Recording == this) + Data.GetData(Owner).Recording = null; + + if (Data.FilterMsg) + { + c_Text = Filter.FilterText(Owner, c_Text, false); + c_Subject = Filter.FilterText(Owner, c_Subject, false); + } + + if (c_MsgType == MsgType.System) + { + foreach (Data data in Data.Datas.Values) + { + data.AddMessage(new Message(Owner, c_Subject, c_Text, MsgType.System)); + General.PmNotify(data.Mobile); + } + } + else if (c_MsgType == MsgType.Staff) + { + foreach (Data data in Data.Datas.Values) + { + if (data.Mobile.AccessLevel != AccessLevel.Player) + { + data.AddMessage(new Message(Owner, c_Subject, c_Text, MsgType.Staff)); + General.PmNotify(data.Mobile); + } + } + } + else + { + Data.GetData(c_To).AddMessage(new Message(Owner, c_Subject, c_Text, MsgType.Normal)); + General.PmNotify(c_To); + + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(67) + " " + c_To.RawName); + if (Data.GetData(c_To).Status != OnlineStatus.Online) + Owner.SendMessage(Data.GetData(Owner).SystemC, c_To.RawName + ": " + Data.GetData(c_To).AwayMsg); + } + + if (Data.LogPms) + Logging.LogPm(String.Format(DateTime.Now + " {0} to {1}: {2}", Owner.RawName, (c_To == null ? "All" : c_To.RawName), c_Text)); + + foreach( Data data in Data.Datas.Values) + if (data.Mobile.AccessLevel >= c_From.AccessLevel && ((data.GlobalM && !data.GIgnores.Contains(c_From)) || data.GListens.Contains(c_From))) + data.Mobile.SendMessage(data.GlobalMC, String.Format("(Global) {0} to {1}: {2}", Owner.RawName, (c_To == null ? "All" : c_To.RawName), c_Text )); + } + + private void Color() + { + Owner.SendHuePicker(new InternalPicker(this)); + } + + #endregion + + #region Internal Classes + + private class InternalPicker : HuePicker + { + private GumpPlus c_Gump; + + public InternalPicker(GumpPlus g) + : base(0x1018) + { + c_Gump = g; + } + + public override void OnResponse(int hue) + { + Data.GetData(c_Gump.Owner).MsgC = hue; + + c_Gump.NewGump(); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/3.0 Skin/SpamGump.cs b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/SpamGump.cs new file mode 100644 index 0000000..c4c95f9 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/3.0 Skin/SpamGump.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class SpamGump : GumpPlus + { + public SpamGump(Mobile m) + : base(m, 100, 100) + { + } + + protected override void BuildGump() + { + int width = 300; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(215)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width/2-10, "
" + General.Local(144)); + AddTextField(width/2+10, y, 30, 21, 0x480, 0xBBA, "Chat Spam", "" + Data.ChatSpam); + AddHtml(width/2+45, y, 20, "s"); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddHtml(0, y+=25, width/2-10, "
" + General.Local(145)); + AddTextField(width/2+10, y, 30, 21, 0x480, 0xBBA, "Msg Spam", "" + Data.MsgSpam); + AddHtml(width/2+45, y, 20, "s"); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddHtml(0, y += 25, width/2-10, "
" + General.Local(146)); + AddTextField(width/2+10, y, 30, 21, 0x480, 0xBBA, "Request Spam", "" + Data.RequestSpam); + AddHtml(width/2+45, y, 100, "h"); + AddButton(width / 2 - 5, y + 4, 0x2716, "Submit", new GumpCallback(Submit)); + + AddBackgroundZero(0, 0, width, y+40, Data.GetData(Owner).DefaultBack); + } + + private void Submit() + { + Data.ChatSpam = GetTextFieldInt("Chat Spam"); + Data.MsgSpam = GetTextFieldInt("Msg Spam"); + Data.RequestSpam = GetTextFieldInt("Request Spam"); + + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Error Reporting/Errors.cs b/Scripts/Customs/KniveChat/Gumps/Error Reporting/Errors.cs new file mode 100644 index 0000000..189f38a --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Error Reporting/Errors.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections; +using System.Web.Mail; +using System.Threading; +using Server; +using Server.Network; + +namespace Knives.Chat3 +{ + public class Errors + { + private static ArrayList s_ErrorLog = new ArrayList(); + private static ArrayList s_Checked = new ArrayList(); + + public static ArrayList ErrorLog{ get{ return s_ErrorLog; } } + public static ArrayList Checked{ get{ return s_Checked; } } + + public static void Initialize() + { + RUOVersion.AddCommand("ChatErrors", AccessLevel.Counselor, new ChatCommandHandler(OnErrors)); + RUOVersion.AddCommand("ce", AccessLevel.Counselor, new ChatCommandHandler(OnErrors)); + + EventSink.Login += new LoginEventHandler( OnLogin ); + } + + private static void OnErrors( CommandInfo e ) + { + if ( e.ArgString == null || e.ArgString == "" ) + new ErrorsGump( e.Mobile ); + else + Report( e.ArgString + " - " + e.Mobile.Name ); + } + + private static void OnLogin( LoginEventArgs e ) + { + if ( e.Mobile.AccessLevel != AccessLevel.Player + && s_ErrorLog.Count != 0 + && !s_Checked.Contains( e.Mobile ) ) + new ErrorsNotifyGump( e.Mobile ); + } + + public static void Report(string error) + { + s_ErrorLog.Add(String.Format("{0}
{1}
", DateTime.Now, error)); + + Events.InvokeError(new ErrorEventArgs(error)); + + s_Checked.Clear(); + + Notify(); + } + + public static void Report(string error, Exception e) + { + s_ErrorLog.Add(String.Format("{0}
{1}
", DateTime.Now, error)); + + Events.InvokeError(new ErrorEventArgs(error)); + + s_Checked.Clear(); + + Notify(); + + s_Error = error; + s_Exception = e; + new Thread(new ThreadStart(SendEmail)).Start(); + } + + private static void Notify() + { + foreach( NetState state in NetState.Instances ) + { + if ( state.Mobile == null ) + continue; + + if ( state.Mobile.AccessLevel != AccessLevel.Player ) + Notify( state.Mobile ); + } + } + + private static string s_Error = ""; + private static Exception s_Exception; + + private static void SendEmail() + { + string txt = s_Error; + Exception e = s_Exception; + + try + { + MailMessage mail = new MailMessage(); + mail.To = "kmwill23@hotmail.com"; + mail.From = Server.Misc.ServerList.ServerName; + mail.Subject = "Automated Chat Error Report"; + mail.Body = Server.Misc.ServerList.ServerName + " \r \r " + txt + " \r \r " + e.Message + " \r \r " + e.Source + " \r \r " + e.StackTrace; + string schema = "http://schemas.microsoft.com/cdo/configuration/"; + mail.Fields.Add(schema + "smtpserverport", "465"); + mail.Fields.Add(schema + "smtpusessl", "true"); + mail.Fields[schema + "smtpauthenticate"] = "1"; + mail.Fields[schema + "sendusername"] = "kniveschat@gmail.com"; + mail.Fields[schema + "sendpassword"] = "openmail"; + SmtpMail.SmtpServer = "smtp.gmail.com"; + SmtpMail.Send(mail); + } + catch(Exception ex) + { + Console.WriteLine("Email failed to send."); + Console.WriteLine(ex.Message); + Console.WriteLine(ex.Source); + Console.WriteLine(ex.StackTrace); + } + } + + public static void Notify( Mobile m ) + { + if ( m.HasGump( typeof( ErrorsGump ) ) ) + new ErrorsGump( m ); + else + new ErrorsNotifyGump( m ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Error Reporting/ErrorsGump.cs b/Scripts/Customs/KniveChat/Gumps/Error Reporting/ErrorsGump.cs new file mode 100644 index 0000000..3e38d06 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Error Reporting/ErrorsGump.cs @@ -0,0 +1,55 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class ErrorsGump : GumpPlus + { + public ErrorsGump( Mobile m ) : base( m, 100, 100 ) + { + Errors.Checked.Add(m); + + m.CloseGump( typeof( ErrorsGump ) ); + } + + protected override void BuildGump() + { + int width = 400; + int y = 10; + + AddHtml(0, y, width, "
" + General.Local(201)); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddButton(width - 20, y, 0x5689, "Help", new GumpCallback(Help)); + + string str = HTML.Black; + foreach( string text in Errors.ErrorLog ) + str += text; + + AddHtml( 20, y+=25, width-40, 200, str, true, true ); + + y += 200; + + if ( Owner.AccessLevel >= AccessLevel.Administrator ) + { + AddButton( width/2-30, y+=10, 0x98B, 0x98B, "Clear", new GumpCallback( ClearLog ) ); + AddHtml( width/2-23, y+3, 51, "
" + General.Local(202)); + } + + AddBackgroundZero(0, 0, width, y + 40, 0x1400); + } + + private void Help() + { + NewGump(); + new Chat3.InfoGump( Owner, 300, 300, HTML.White +" " + General.Local(200), true ); + } + + private void ClearLog() + { + Errors.ErrorLog.Clear(); + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Error Reporting/ErrorsNotifyGump.cs b/Scripts/Customs/KniveChat/Gumps/Error Reporting/ErrorsNotifyGump.cs new file mode 100644 index 0000000..f40d567 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Error Reporting/ErrorsNotifyGump.cs @@ -0,0 +1,23 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class ErrorsNotifyGump : GumpPlus + { + public ErrorsNotifyGump( Mobile m ) : base( m, 200, 100 ) + { + m.CloseGump( typeof( ErrorsNotifyGump ) ); + } + + protected override void BuildGump() + { + AddButton( 0, 0, 0xDF, 0xDF, "Errors", new GumpCallback( Errors ) ); + } + + private void Errors() + { + new ErrorsGump( Owner ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/BackgroundPlus.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/BackgroundPlus.cs new file mode 100644 index 0000000..443e7e9 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/BackgroundPlus.cs @@ -0,0 +1,23 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class BackgroundPlus : GumpBackground + { + private bool c_Override; + + public bool Override{ get{ return c_Override; } set{ c_Override = value; } } + + public BackgroundPlus( int x, int y, int width, int height, int back ) : base( x, y, width, height, back ) + { + c_Override = true; + } + + public BackgroundPlus( int x, int y, int width, int height, int back, bool over ) : base( x, y, width, height, back ) + { + c_Override = over; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/ButtonPlus.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/ButtonPlus.cs new file mode 100644 index 0000000..adb02a7 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/ButtonPlus.cs @@ -0,0 +1,37 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class ButtonPlus : GumpButton + { + private string c_Name; + private object c_Callback; + private object c_Param; + + public string Name{ get{ return c_Name; } } + + public ButtonPlus( int x, int y, int normalID, int pressedID, int buttonID, string name, GumpCallback back ) : base( x, y, normalID, pressedID, buttonID, GumpButtonType.Reply, 0 ) + { + c_Name = name; + c_Callback = back; + c_Param = ""; + } + + public ButtonPlus( int x, int y, int normalID, int pressedID, int buttonID, string name, GumpStateCallback back, object param ) : base( x, y, normalID, pressedID, buttonID, GumpButtonType.Reply, 0 ) + { + c_Name = name; + c_Callback = back; + c_Param = param; + } + + public void Invoke() + { + if ( c_Callback is GumpCallback ) + ((GumpCallback)c_Callback)(); + else if ( c_Callback is GumpStateCallback ) + ((GumpStateCallback)c_Callback)( c_Param ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/GumpInfo.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/GumpInfo.cs new file mode 100644 index 0000000..7db5cdc --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/GumpInfo.cs @@ -0,0 +1,366 @@ +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Accounting; + +namespace Knives.Chat3 +{ + public class GumpInfo + { + private static Hashtable s_Infos = new Hashtable(); + private static ArrayList s_Backgrounds = new ArrayList(); + private static ArrayList s_TextColors = new ArrayList(); + + private static bool s_ForceMenu = false; + private static Hashtable s_ForceInfos = new Hashtable(); + + public static ArrayList Backgrounds { get { return s_Backgrounds; } } + public static ArrayList TextColors { get { return s_TextColors; } } + public static bool ForceMenu { get { return s_ForceMenu; } set { s_ForceMenu = value; } } + public static Hashtable ForceInfos { get { return s_ForceInfos; } } + + public static void Initialize() + { + s_Backgrounds.Add( 0xA3C ); + s_Backgrounds.Add( 0x53 ); + s_Backgrounds.Add( 0x2486 ); + s_Backgrounds.Add( 0xDAC ); + s_Backgrounds.Add( 0xE10 ); + s_Backgrounds.Add( 0x13EC ); + s_Backgrounds.Add( 0x1400 ); + s_Backgrounds.Add( 0x2422 ); + s_Backgrounds.Add( 0x242C ); + s_Backgrounds.Add( 0x13BE ); + s_Backgrounds.Add( 0x2436 ); + s_Backgrounds.Add( 0x2454 ); + s_Backgrounds.Add( 0x251C ); + s_Backgrounds.Add( 0x254E ); + s_Backgrounds.Add( 0x24A4 ); + s_Backgrounds.Add( 0x24AE ); + + General.LoadBacksFile(); + + s_TextColors.Add("FFFFFF"); + s_TextColors.Add("111111"); + s_TextColors.Add("FF0000"); + s_TextColors.Add("FF9999"); + s_TextColors.Add("00FF00"); + s_TextColors.Add("0000FF"); + s_TextColors.Add("999999"); + s_TextColors.Add("333333"); + s_TextColors.Add("FFFF00"); + s_TextColors.Add("990099"); + s_TextColors.Add("CC00FF"); + + General.LoadColorsFile(); + } + + public static void Save() + { + try + { + if (!Directory.Exists(General.SavePath)) + Directory.CreateDirectory(General.SavePath); + + GenericWriter writer = new BinaryFileWriter(Path.Combine(General.SavePath, "Gumps.bin"), true); + + writer.Write(0); // version + + writer.Write(s_ForceMenu); + writer.Write(s_ForceInfos.Count); + foreach (GumpInfo ginfo in s_ForceInfos.Values) + ginfo.Save(writer); + + ArrayList list = new ArrayList(); + GumpInfo info; + + foreach (object o in new ArrayList(s_Infos.Values)) + { + if (!(o is Hashtable)) + continue; + + foreach (object ob in new ArrayList(((Hashtable)o).Values)) + { + if (!(ob is GumpInfo)) + continue; + + info = (GumpInfo)ob; + + if (info.Mobile != null + && info.Mobile.Player + && !info.Mobile.Deleted + && info.Mobile.Account != null + && ((Account)info.Mobile.Account).LastLogin > DateTime.Now - TimeSpan.FromDays(30)) + list.Add(ob); + } + } + + writer.Write(list.Count); + + foreach (GumpInfo ginfo in list) + ginfo.Save(writer); + + writer.Close(); + } + catch (Exception e) + { + Errors.Report(General.Local(199)); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + public static void Load() + { + try + { + if (!File.Exists(Path.Combine(General.SavePath, "Gumps.bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine(General.SavePath, "Gumps.bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + + int version = reader.ReadInt(); + + if (version >= 0) + { + s_ForceMenu = reader.ReadBool(); + int count = reader.ReadInt(); + GumpInfo info; + + for (int i = 0; i < count; ++i) + { + info = new GumpInfo(); + info.Load(reader); + + if (info.Type == null) + continue; + + s_ForceInfos[info.Type] = info; + } + + count = reader.ReadInt(); + + for (int i = 0; i < count; ++i) + { + info = new GumpInfo(); + info.Load(reader); + + if (info.Mobile == null || info.Type == null) + continue; + + if (s_Infos[info.Mobile] == null) + s_Infos[info.Mobile] = new Hashtable(); + + ((Hashtable)s_Infos[info.Mobile])[info.Type] = info; + } + } + + reader.End(); + } + } + catch (Exception e) + { + Errors.Report(General.Local(198)); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + public static GumpInfo GetInfo( Mobile m, Type type ) + { + if (s_ForceMenu) + { + if (s_ForceInfos[type] == null) + s_ForceInfos[type] = new GumpInfo(null, type); + + return (GumpInfo)s_ForceInfos[type]; + } + + if (s_Infos[m] == null) + s_Infos[m] = new Hashtable(); + + Hashtable table = (Hashtable)s_Infos[m]; + + if (table[type] == null) + table[type] = new GumpInfo( m, type ); + + return (GumpInfo)table[type]; + } + + public static bool HasMods( Mobile m, Type type ) + { + if (s_ForceMenu) + return s_ForceInfos[type] != null; + + if (s_Infos[m] == null) + s_Infos[m] = new Hashtable(); + + if ( ((Hashtable)s_Infos[m])[type] == null ) + return false; + + return true; + } + + private Mobile c_Mobile; + private Type c_Type; + private bool c_Transparent, c_DefaultTrans; + private string c_TextColorRGB; + private int c_Background; + + public Mobile Mobile{ get{ return c_Mobile; } } + public Type Type{ get{ return c_Type; } } + public bool Transparent { get { return c_Transparent; } set { c_Transparent = value; c_DefaultTrans = false; } } + public bool DefaultTrans{ get{ return c_DefaultTrans; } set{ c_DefaultTrans = value; } } + public string TextColorRGB{ get{ return c_TextColorRGB; } set{ c_TextColorRGB = value; } } + public string TextColor{ get{ return String.Format( "", c_TextColorRGB ); } } + public int Background{ get{ return c_Background; } } + + public GumpInfo() + { + } + + public GumpInfo( Mobile m, Type type ) + { + c_Mobile = m; + c_Type = type; + c_TextColorRGB = ""; + c_Background = -1; + c_DefaultTrans = true; + } + + public void BackgroundUp() + { + if (c_Background == -1) + { + c_Background = (int)s_Backgrounds[0]; + return; + } + + for (int i = 0; i < s_Backgrounds.Count; ++i) + if (c_Background == (int)s_Backgrounds[i]) + { + if (i == s_Backgrounds.Count - 1) + { + c_Background = (int)s_Backgrounds[0]; + return; + } + + c_Background = (int)s_Backgrounds[i + 1]; + return; + } + } + + public void BackgroundDown() + { + if (c_Background == -1) + { + c_Background = (int)s_Backgrounds[s_Backgrounds.Count - 1]; + return; + } + + for (int i = 0; i < s_Backgrounds.Count; ++i) + if (c_Background == (int)s_Backgrounds[i]) + { + if (i == 0) + { + c_Background = (int)s_Backgrounds[s_Backgrounds.Count - 1]; + return; + } + + c_Background = (int)s_Backgrounds[i - 1]; + return; + } + } + + public void TextColorUp() + { + if (c_TextColorRGB == "") + { + c_TextColorRGB = s_TextColors[0].ToString(); + return; + } + + for (int i = 0; i < s_TextColors.Count; ++i) + if (c_TextColorRGB == s_TextColors[i].ToString()) + { + if (i == s_TextColors.Count - 1) + { + c_TextColorRGB = s_TextColors[0].ToString(); + return; + } + + c_TextColorRGB = s_TextColors[i + 1].ToString(); + return; + } + } + + public void TextColorDown() + { + if (c_TextColorRGB == "") + { + c_TextColorRGB = s_TextColors[s_TextColors.Count - 1].ToString(); + return; + } + + for (int i = 0; i < s_TextColors.Count; ++i) + if (c_TextColorRGB == s_TextColors[i].ToString()) + { + if (i == 0) + { + c_TextColorRGB = s_TextColors[s_TextColors.Count - 1].ToString(); + return; + } + + c_TextColorRGB = s_TextColors[i - 1].ToString(); + return; + } + } + + public void Default() + { + if (s_ForceMenu) + { + s_ForceInfos.Remove(c_Type); + return; + } + + if (c_Mobile == null || s_Infos[c_Mobile] == null) + return; + + ((Hashtable)s_Infos[c_Mobile]).Remove(c_Type); + } + + private void Save(GenericWriter writer) + { + writer.Write( 0 ); // version + + // Version 0 + writer.Write( c_Mobile ); + writer.Write( c_Type.ToString() ); + writer.Write( c_Transparent ); + writer.Write( c_DefaultTrans ); + writer.Write( c_TextColorRGB ); + writer.Write( c_Background ); + } + + private void Load( GenericReader reader ) + { + int version = reader.ReadInt(); + + if ( version >= 0 ) + { + c_Mobile = reader.ReadMobile(); + c_Type = ScriptCompiler.FindTypeByFullName( reader.ReadString() ); + c_Transparent = reader.ReadBool(); + c_DefaultTrans = reader.ReadBool(); + c_TextColorRGB = reader.ReadString(); + c_Background = reader.ReadInt(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/GumpPlus.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/GumpPlus.cs new file mode 100644 index 0000000..529c6b7 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/GumpPlus.cs @@ -0,0 +1,450 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Knives.Chat3 +{ + public delegate void GumpStateCallback(object obj); + public delegate void GumpCallback(); + + public abstract class GumpPlus : Gump + { + public static void RefreshGump(Mobile m, Type type) + { + if (m.NetState == null) + return; + + foreach (Gump g in m.NetState.Gumps) + if (g is GumpPlus && g.GetType() == type) + { + m.CloseGump(type); + ((GumpPlus)g).NewGump(); + return; + } + } + + private Mobile c_Owner; + private Hashtable c_Buttons, c_Fields; + private bool c_Override; + + public Mobile Owner{ get{ return c_Owner; } } + public GumpInfo Info { get { return GumpInfo.GetInfo(c_Owner, this.GetType()); } } + public bool Override{ get{ return c_Override; } set{ c_Override = value; } } + + public GumpPlus( Mobile m, int x, int y ) : base( x, y ) + { + c_Owner = m; + + c_Buttons = new Hashtable(); + c_Fields = new Hashtable(); + + Events.InvokeGumpCreated(new GumpCreatedEventArgs(m, this)); + + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(NewGump)); + } + + public void Clear() + { + Entries.Clear(); + c_Buttons.Clear(); + c_Fields.Clear(); + } + + public virtual void NewGump() + { + NewGump( true ); + } + + public void NewGump( bool clear ) + { + if ( clear ) + Clear(); + + BuildGump(); + + if ( c_Override ) + ModifyGump(); + + c_Owner.SendGump( this ); + } + + public void SameGump() + { + c_Owner.SendGump( this ); + } + + protected abstract void BuildGump(); + + private void ModifyGump() + { + try + { + AddPage(0); + + int maxWidth = 0; + int maxHeight = 0; + GumpBackground bg; + + foreach (GumpEntry entry in Entries) + if (entry is GumpBackground) + { + bg = (GumpBackground)entry; + + if (bg.X + bg.Width > maxWidth) + maxWidth = bg.X + bg.Width; + if (bg.Y + bg.Height > maxHeight) + maxHeight = bg.Y + bg.Height; + } + + if (Owner.AccessLevel >= AccessLevel.Administrator || !GumpInfo.ForceMenu) + { + AddImage(maxWidth, maxHeight, 0x28DC, GumpInfo.ForceMenu ? 0x26 : 0x387); + AddButton(maxWidth + 10, maxHeight + 4, 0x93A, 0x93A, "Transparency", new GumpCallback(Trans)); + AddButton(maxWidth + 10, maxHeight + 15, 0x938, 0x938, "Default", new GumpCallback(Default)); + if (Owner.AccessLevel >= AccessLevel.Administrator) + AddButton(maxWidth + 10, maxHeight + 26, 0x82C, 0x82C, "ForceMenu", new GumpCallback(Force)); + AddButton(maxWidth - 5, maxHeight + 2, 0x2626, 0x2627, "BackgroundDown", new GumpCallback(BackDown)); + AddButton(maxWidth + 19, maxHeight + 2, 0x2622, 0x2623, "BackgroundUp", new GumpCallback(BackUp)); + AddButton(maxWidth - 5, maxHeight + 13, 0x2626, 0x2627, "TextColorDown", new GumpCallback(TextDown)); + AddButton(maxWidth + 19, maxHeight + 13, 0x2622, 0x2623, "TextColorUp", new GumpCallback(TextUp)); + } + + if (!GumpInfo.HasMods(c_Owner, GetType())) + return; + + ArrayList backs = new ArrayList(); + + foreach (GumpEntry entry in new ArrayList(Entries)) + { + if (entry is GumpBackground) + { + if (entry is BackgroundPlus && !((BackgroundPlus)entry).Override) + continue; + + if (Info.Background != -1) + ((GumpBackground)entry).GumpID = Info.Background; + + backs.Add(entry); + } + else if (entry is GumpAlphaRegion && !Info.DefaultTrans && !Info.Transparent) + { + ((GumpAlphaRegion)entry).Width = 0; + ((GumpAlphaRegion)entry).Height = 0; + } + else if (entry is HtmlPlus) + { + if (!((HtmlPlus)entry).Override || Info.TextColorRGB == "") + continue; + + string text = ((HtmlPlus)entry).Text; + int num = 0; + int length = 0; + char[] chars; + + if (text == null) + continue; + + while ((num = text.ToLower().IndexOf("') + { + length = i - num + 1; + break; + } + + if (length == 0) + break; + + text = text.Substring(0, num) + text.Substring(num + length, text.Length - num - length); + } + + ((HtmlPlus)entry).Text = Info.TextColor + text; + } + } + + if (!Info.DefaultTrans && Info.Transparent) + foreach (GumpBackground back in backs) + AddAlphaRegion(back.X, back.Y, back.Width, back.Height); + + SortEntries(); + + } + catch { Errors.Report("GumpPlus-> ModifyGump-> " + GetType()); } + } + + private void SortEntries() + { + ArrayList list = new ArrayList(); + + foreach( GumpEntry entry in new ArrayList( Entries ) ) + if ( entry is GumpBackground ) + { + list.Add( entry ); + Entries.Remove( entry ); + } + + foreach( GumpEntry entry in new ArrayList( Entries ) ) + if ( entry is GumpAlphaRegion ) + { + list.Add( entry ); + Entries.Remove( entry ); + } + + list.AddRange( Entries ); + + Entries.Clear(); + + foreach (GumpEntry entry in list) + Entries.Add(entry); + } + + private int UniqueButton() + { + int random = 0; + + do + { + random = Utility.Random( 20000 ); + + }while( c_Buttons[random] != null ); + + return random; + } + + private int UniqueTextId() + { + int random = 0; + + do + { + random = Utility.Random(20000); + + } while (c_Buttons[random] != null); + + return random; + } + + public void AddBackgroundZero(int x, int y, int width, int height, int back) + { + AddBackgroundZero(x, y, width, height, back, true); + } + + public void AddBackgroundZero(int x, int y, int width, int height, int back, bool over) + { + BackgroundPlus plus = new BackgroundPlus(x, y, width, height, back, over); + + Entries.Insert(0, plus); + } + + public new void AddBackground(int x, int y, int width, int height, int back) + { + AddBackground(x, y, width, height, back, true); + } + + public void AddBackground(int x, int y, int width, int height, int back, bool over) + { + BackgroundPlus plus = new BackgroundPlus(x, y, width, height, back, over); + + Add(plus); + } + + public void AddButton(int x, int y, int id, GumpCallback callback) + { + AddButton(x, y, id, id, "None", callback); + } + + public void AddButton(int x, int y, int id, GumpStateCallback callback, object arg) + { + AddButton(x, y, id, id, "None", callback, arg); + } + + public void AddButton(int x, int y, int id, string name, GumpCallback callback) + { + AddButton(x, y, id, id, name, callback); + } + + public void AddButton(int x, int y, int id, string name, GumpStateCallback callback, object arg) + { + AddButton(x, y, id, id, name, callback, arg); + } + + public void AddButton(int x, int y, int up, int down, GumpCallback callback) + { + AddButton(x, y, up, down, "None", callback); + } + + public void AddButton(int x, int y, int up, int down, string name, GumpCallback callback) + { + int id = UniqueButton(); + + ButtonPlus button = new ButtonPlus( x, y, up, down, id, name, callback ); + + Add( button ); + + c_Buttons[id] = button; + } + + public void AddButton( int x, int y, int up, int down, GumpStateCallback callback, object arg ) + { + AddButton( x, y, up, down, "None", callback, arg ); + } + + public void AddButton( int x, int y, int up, int down, string name, GumpStateCallback callback, object arg ) + { + int id = UniqueButton(); + + ButtonPlus button = new ButtonPlus( x, y, up, down, id, name, callback, arg ); + + Add( button ); + + c_Buttons[id] = button; + } + + public void AddHtml(int x, int y, int width, string text) + { + AddHtml(x, y, width, 21, HTML.White + text, false, false, true); + } + + public void AddHtml(int x, int y, int width, string text, bool over) + { + AddHtml(x, y, width, 21, HTML.White + text, false, false, over); + } + + public new void AddHtml(int x, int y, int width, int height, string text, bool back, bool scroll) + { + AddHtml(x, y, width, height, HTML.White + text, back, scroll, true); + } + + public void AddHtml(int x, int y, int width, int height, string text, bool back, bool scroll, bool over) + { + HtmlPlus html = new HtmlPlus(x, y, width, height, HTML.White + text, back, scroll, over); + + Add(html); + } + + public void AddTextField(int x, int y, int width, int height, int color, int back, string name, string text) + { + int id = UniqueTextId(); + + AddImageTiled(x, y, width, height, back); + base.AddTextEntry(x, y, width, height, color, id, text); + + c_Fields[id] = name; + c_Fields[name] = text; + } + + public string GetTextField(string name) + { + if (c_Fields[name] == null) + return ""; + + return c_Fields[name].ToString(); + } + + public int GetTextFieldInt(string name) + { + return Utility.ToInt32(GetTextField(name)); + } + + protected virtual void OnClose() + { + } + + public override void OnResponse(NetState state, RelayInfo info) + { + string name = ""; + + try + { + if (info.ButtonID == -5) + { + NewGump(); + return; + } + + foreach (TextRelay t in info.TextEntries) + c_Fields[c_Fields[t.EntryID].ToString()] = t.Text; + + if (info.ButtonID == 0) + OnClose(); + + if (c_Buttons[info.ButtonID] == null || !(c_Buttons[info.ButtonID] is ButtonPlus)) + return; + + name = ((ButtonPlus)c_Buttons[info.ButtonID]).Name; + + ((ButtonPlus)c_Buttons[info.ButtonID]).Invoke(); + + } + catch (Exception e) + { + Errors.Report("An error occured during a gump response. More information can be found on the console."); + if(name != "") + Console.WriteLine("{0} gump name triggered an error.", name); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + private void Trans() + { + Info.Transparent = !Info.Transparent; + + NewGump(); + } + + private void BackUp() + { + Info.BackgroundUp(); + + NewGump(); + } + + private void BackDown() + { + Info.BackgroundDown(); + + NewGump(); + } + + private void TextUp() + { + Info.TextColorUp(); + + NewGump(); + } + + private void TextDown() + { + Info.TextColorDown(); + + NewGump(); + } + + private void Default() + { + Info.Default(); + + NewGump(); + } + + private void Force() + { + GumpInfo.ForceMenu = !GumpInfo.ForceMenu; + + if (GumpInfo.ForceMenu) + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(242)); + else + Owner.SendMessage(Data.GetData(Owner).SystemC, General.Local(243)); + + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/HTML.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/HTML.cs new file mode 100644 index 0000000..54eedcf --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/HTML.cs @@ -0,0 +1,20 @@ +using System; +using Server; + +namespace Knives.Chat3 +{ + public class HTML + { + public static string White{ get { return ""; } } + public static string Red{ get { return ""; } } + public static string AshRed{ get { return ""; } } + public static string Green{ get { return ""; } } + public static string Blue{ get { return ""; } } + public static string Gray{ get { return ""; } } + public static string DarkGray{ get { return ""; } } + public static string Black{ get { return ""; } } + public static string Yellow{ get { return ""; } } + public static string Purple{ get { return ""; } } + public static string LightPurple{ get { return ""; } } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/HtmlPlus.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/HtmlPlus.cs new file mode 100644 index 0000000..fbc3b47 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/HtmlPlus.cs @@ -0,0 +1,23 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class HtmlPlus : GumpHtml + { + private bool c_Override; + + public bool Override{ get{ return c_Override; } set{ c_Override = value; } } + + public HtmlPlus( int x, int y, int width, int height, string text, bool back, bool scroll ) : base( x, y, width, height, text, back, scroll ) + { + c_Override = true; + } + + public HtmlPlus( int x, int y, int width, int height, string text, bool back, bool scroll, bool over ) : base( x, y, width, height, text, back, scroll ) + { + c_Override = over; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Gumps/Gumps Plus/InfoGump.cs b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/InfoGump.cs new file mode 100644 index 0000000..6ba1b47 --- /dev/null +++ b/Scripts/Customs/KniveChat/Gumps/Gumps Plus/InfoGump.cs @@ -0,0 +1,30 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.Chat3 +{ + public class InfoGump : GumpPlus + { + private int c_Width, c_Height; + private string c_Text; + private bool c_Scroll; + + public InfoGump( Mobile m, int width, int height, string text, bool scroll ) : base( m, 100, 100 ) + { + c_Width = width; + c_Height = height; + c_Text= text; + c_Scroll = scroll; + + NewGump(); + } + + protected override void BuildGump() + { + AddBackground( 0, 0, c_Width, c_Height, 0x13BE ); + + AddHtml( 20, 20, c_Width-40, c_Height-40, HTML.White + c_Text, false, c_Scroll ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Jail.cs b/Scripts/Customs/KniveChat/Jail.cs new file mode 100644 index 0000000..1a07555 --- /dev/null +++ b/Scripts/Customs/KniveChat/Jail.cs @@ -0,0 +1,24 @@ +/* + * The line following this entry determines if your server combines Xanthos's Jail + * features with the Chat filter. To enable, remove the '//' in front of the + * '#define Use_Jail'. If there is ever a change which makes Xanthos's Jail no + * longer work with Chat, readd the '//' to disable. + */ + +//#define Use_Xanthos + +using System; +using Server; + +namespace Knives.Chat3 +{ + public class ChatJail + { + public static void SendToJail(Mobile m) + { + #if (Use_Xanthos) + Xanthos.JailSystem.Jail.JailThem((Server.Mobiles.PlayerMobile)m, Xanthos.JailSystem.Jail.JailOption.None); + #endif + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/RUOVersion.cs b/Scripts/Customs/KniveChat/RUOVersion.cs new file mode 100644 index 0000000..0ade8ff --- /dev/null +++ b/Scripts/Customs/KniveChat/RUOVersion.cs @@ -0,0 +1,65 @@ +/* + * The two lines following this entry specify what RunUO version you are running. + * In order to switch to RunUO 1.0 Final, remove the '//' in front of that setting + * and add '//' in front of '#define RunUO_2_RC1'. Warning: If you comment both + * out, many commands in this system will not work. Enjoy! + */ + +#define RunUO_2_RC1 +//#define RunUO_1_Final + +using System; +using System.Collections; +using Server; +using Server.Network; + +#if (RunUO_2_RC1) + using Server.Commands; +#endif + +namespace Knives.Chat3 +{ + public class RUOVersion + { + private static Hashtable s_Commands = new Hashtable(); + + public static void AddCommand(string com, AccessLevel acc, ChatCommandHandler cch) + { + s_Commands[com.ToLower()] = cch; + + #if(RunUO_1_Final) + Server.Commands.Register(com, acc, new CommandEventHandler(OnCommand)); + #elif(RunUO_2_RC1) + Server.Commands.CommandSystem.Register(com, acc, new CommandEventHandler(OnCommand)); + #endif + } + + public static void RemoveCommand(string com) + { + s_Commands[com.ToLower()] = null; + + #if (RunUO_1_Final) + Server.Commands.Entries.Remove(com); + #else + Server.Commands.CommandSystem.Entries.Remove(com); + #endif + } + + public static void OnCommand(CommandEventArgs e) + { + if (s_Commands[e.Command.ToLower()] == null) + return; + + ((ChatCommandHandler)s_Commands[e.Command.ToLower()])(new CommandInfo(e.Mobile, e.Command, e.ArgString, e.Arguments)); + } + + public static bool GuildChat(MessageType type) + { + #if (RunUO_1_Final) + return false; + #else + return type == MessageType.Guild; + #endif + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Read.doc b/Scripts/Customs/KniveChat/Read.doc new file mode 100644 index 0000000..c92f872 --- /dev/null +++ b/Scripts/Customs/KniveChat/Read.doc @@ -0,0 +1,230 @@ +{\rtf1\ansi\ansicpg1252\uc1\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} +{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f10\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;} +{\f36\froman\fcharset238\fprq2 Times New Roman CE;}{\f37\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f39\froman\fcharset161\fprq2 Times New Roman Greek;}{\f40\froman\fcharset162\fprq2 Times New Roman Tur;} +{\f41\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f42\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f43\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f44\froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\f46\fswiss\fcharset238\fprq2 Arial CE;}{\f47\fswiss\fcharset204\fprq2 Arial Cyr;}{\f49\fswiss\fcharset161\fprq2 Arial Greek;}{\f50\fswiss\fcharset162\fprq2 Arial Tur;}{\f51\fswiss\fcharset177\fprq2 Arial (Hebrew);} +{\f52\fswiss\fcharset178\fprq2 Arial (Arabic);}{\f53\fswiss\fcharset186\fprq2 Arial Baltic;}{\f54\fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f56\fmodern\fcharset238\fprq1 Courier New CE;}{\f57\fmodern\fcharset204\fprq1 Courier New Cyr;} +{\f59\fmodern\fcharset161\fprq1 Courier New Greek;}{\f60\fmodern\fcharset162\fprq1 Courier New Tur;}{\f61\fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f62\fmodern\fcharset178\fprq1 Courier New (Arabic);} +{\f63\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f64\fmodern\fcharset163\fprq1 Courier New (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0; +\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{ +\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\* +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\listtable{\list\listtemplateid263214400 +\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid1036939456\'01-;}{\levelnumbers;}\fs20\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480 +\jclisttab\tx6480\lin6480 }{\listname ;}\listid423459582}{\list\listtemplateid-2096845188\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid1814465516 +\'01\u-3913 ?;}{\levelnumbers;}\loch\af3\hich\af3\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691 +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} +\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880 +\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid480735794}{\list\listtemplateid1492679702\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid-371975270\'01-;}{\levelnumbers;}\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691 +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} +\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 +\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid831146619} +{\list\listtemplateid1659899392\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid521150660\'01-;}{\levelnumbers;}\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li720 +\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691 +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} +\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid928544353}{\list\listtemplateid-689036010\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext +\leveltemplateid-787716772\'01-;}{\levelnumbers;}\loch\af0\hich\af0\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} +\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600 +\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid1016730154}{\list\listtemplateid2094531610\listhybrid{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid-1597994076\'01-;}{\levelnumbers;}\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;} +\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760 +\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 } +{\listname ;}\listid1712919034}}{\*\listoverridetable{\listoverride\listid480735794\listoverridecount0\ls1}{\listoverride\listid928544353\listoverridecount0\ls2}{\listoverride\listid831146619\listoverridecount0\ls3}{\listoverride\listid1712919034 +\listoverridecount0\ls4}{\listoverride\listid1016730154\listoverridecount0\ls5}{\listoverride\listid423459582\listoverridecount0\ls6}}{\*\rsidtbl \rsid136057\rsid215240\rsid474949\rsid685904\rsid1137675\rsid1515379\rsid1993206\rsid1998663\rsid2097447 +\rsid2164528\rsid2243826\rsid2629020\rsid2891301\rsid2970612\rsid3219579\rsid3219815\rsid3293690\rsid3474054\rsid3542521\rsid3609592\rsid3673131\rsid3676129\rsid3884232\rsid3964756\rsid4016229\rsid4533635\rsid4726250\rsid4806749\rsid4984422\rsid5002060 +\rsid5135562\rsid5530051\rsid5983512\rsid6228220\rsid6235869\rsid6638712\rsid6691810\rsid7210765\rsid7239847\rsid7284320\rsid7358823\rsid7887838\rsid8069067\rsid8325154\rsid8333502\rsid8334579\rsid8671087\rsid8723068\rsid8808284\rsid9109621\rsid9308608 +\rsid9392704\rsid9571899\rsid9704262\rsid9797101\rsid9851181\rsid9855981\rsid9975213\rsid10051896\rsid10174989\rsid10180233\rsid10683748\rsid10843650\rsid10959784\rsid10960510\rsid10964469\rsid11354635\rsid11470933\rsid11603577\rsid12015873\rsid12413488 +\rsid12457823\rsid12546303\rsid12583005\rsid12663109\rsid12862567\rsid12865895\rsid12981213\rsid13062140\rsid13442825\rsid13656871\rsid14048820\rsid14160888\rsid14497712\rsid14751431\rsid14833682\rsid14965633\rsid15104084\rsid15147074\rsid15351652 +\rsid15478193\rsid15615323\rsid15676091\rsid15678272\rsid15797721\rsid16021146\rsid16148038\rsid16153030\rsid16387851\rsid16457168\rsid16465683\rsid16530520}{\*\generator Microsoft Word 11.0.5604;}{\info{\author Kevin}{\operator Kevin} +{\creatim\yr2006\mo5\dy19\hr20\min29}{\revtim\yr2007\mo3\dy1\hr14\min39}{\version91}{\edmins248}{\nofpages4}{\nofwords1403}{\nofchars7998}{\*\company }{\nofcharsws9383}{\vern24689}} +\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\nolnhtadjtbl\rsidroot4806749 \fet0\sectd +\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4 +\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (} +{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\b\f1\fs20\insrsid3676129 Summary:}{\f1\fs20\insrsid3676129 +\par +\par }{\f1\fs20\insrsid4533635 Version 3.0 Beta 9}{\f1\fs20\insrsid3676129 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid9571899 {\f1\fs20\insrsid14497712 Supports RunUO 2.0 RC1, RunUO 1.0 Final}{\f1\fs20\insrsid9571899\charrsid9571899 +\par +\par ***}{\f1\fs20\insrsid14497712 This version may work with the current RunUO 2.0 SVN, and this may change as the SVN changes. Please report this to me, as I can add}{\f1\fs20\insrsid2164528 patches to allow functionality.}{\f1\fs20\insrsid14497712 + +\par }{\f1\fs20\insrsid2164528 +\par }{\b\f1\fs20\insrsid1993206 Supported Systems:}{\f1\fs20\insrsid1993206 +\par +\par }{\b\f1\fs20\insrsid15797721 *** I do not offer support for these systems, nor do I specifically endorse any of them. You are not required to use any of them, nor will you ever be required to. If you have a popular system you sup +port and feel would make a great addition, let me know!}{\b\f1\fs20\insrsid15797721\charrsid15797721 +\par }{\f1\fs20\insrsid15797721 +\par }{\f1\fs20\insrsid1993206 Xanthos\rquote s Jail System}{\f1\fs20\insrsid3673131 \endash Filter violations can now send you to jail!}{\f1\fs20\insrsid1993206\charrsid1993206 +\par }{\f1\fs20\insrsid1993206 +\par }{\b\f1\fs20\insrsid2970612 Beta 9}{\b\f1\fs20\insrsid2164528 News}{\f1\fs20\insrsid2164528 +\par +\par }{\f1\fs20\insrsid2970612 \tab This is a huge day for the chat system! With all the major features well established, +ideas for ways to expand the chat system into new realms have been few and far between. Well, somehow I managed to think of quite a few, and even include a couple here for you all today. This is all just a preview of thin +gs to come! So what is it I claim is so fascinating about this update? Read on!}{\f1\fs20\insrsid6638712 +\par }{\f1\fs20\insrsid2970612 +\par \tab The major addition for this update is the new +Multi-Server connection tool. This one took a lot of learning on my side to pull off, which I feel will also help expand more on the IRC interface as well. The connection tool can be found in Options -> Multi. You can run in two modes: Client or S +erver. If you run as a server, other shards can connect to you and you act as the hub sending out everyone\rquote s messages. If you chose client, you can connect to another server. }{\b\f1\fs20\insrsid2970612 Be warned: I am no expert on issues +regarding routers and firewalls. These can block you from connecting to other servers.}{\f1\fs20\insrsid2970612 Play around with it some if you wish, and report back to me! +\par +\par \tab }{\f1\fs20\insrsid136057 The major issue with Beta 8 has been the double names bug. While by no means a show-stopper, seeing names multiple times can get annoying. I squashed it. There\rquote s no way it can return. Squash! +\par +\par \tab As a second major addition this update, you can now set up automated messages in game through the Notifications Int +erface. You can use two styles: Broadcast or Gump. Sending a gump also has a neat little feature attached to it: if you want, you can have it track macroers. }{\b\f1\fs20\insrsid2970612 }{\f1\fs20\insrsid136057 I know I personally don\rquote +t mind them, but I am sure someone will find the feature useful.}{\f1\fs20\insrsid2970612 +\par }{\f1\fs20\insrsid136057 +\par \tab The last major addition is the new Chat 1.0 skin. Oh Nostalgia! You realize I released the original chat}{\f1\fs20\insrsid15478193 about 3 years ago? How time flies!}{\f1\fs20\insrsid5983512 + Of course the skin does have a few changes, notably the buttons at the bottom have different names. This is so I could cram all the features in while keeping the look and feel =) Comments appreciated!}{\f1\fs20\insrsid136057 +\par }{\f1\fs20\insrsid1137675 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid1137675 {\f1\fs20\insrsid1137675 \tab Here\rquote s the rest of the changes (Wow a lot): +\par }{\f1\fs20\insrsid1137675\charrsid1137675 +\par {\listtext\pard\plain\f1\fs20\insrsid10960510 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls6\rin0\lin720\itap0\pararsid1137675 {\f1\fs20\insrsid10960510 Many changes to the background Gump interface. + +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid1137675\charrsid1137675 Avatars can now be created with itemIDs by adding 100000 to the number. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Opened message gump text color now black against that white by default. Wow that change improved the appearance tons. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Removed the \'93Deleted\'94 message when auto deleting a Pm as a result of auto delete when inbox full. Was annoying to see that every time I got a Pm. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Regional setting now only shows people in your region. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Chat karma now saves. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Players with new messages for you float to the top of all lists. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Message opening now updates the gump the first time you click it. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}List page resets to zero if it goes above the count, which would result in a blank list page. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Perpage on the mail gump now half of the list perpage. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}New command: [All . This is a staff command for sending an announcement to all online players. Similar in effect to the [bcast command, only using the ch +at interface. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}New command: [ViewAll, [Va . A quick command to bring up the Veiw All chat page, which displays all chatters, including those offline. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Event delegates for Chat, Filter Violation, Gump Created, and Errors. If you are familiar with RunUO and Ev +ents, you might welcome this addition which will allow you to create custom scripts which react to those events without having to modify my code. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Help button added to main menu pages. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}New Help Contents interface. Imagine the very familiar searchable help interface that comes with most Windows applications. It\rquote +s a searchable help interface that can easily be expanded by shard admins via text file. I am still in the process of adding all the chat-related helps. It\rquote s not as fun as coding! +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}There is a new IRC channel command: !status . This command, when input from the IRC server, will display some server stats in the IRC channel and in game. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Errors will now generate an email to send to me. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}Changed Jail class name to get rid of that warning. +\par {\listtext\pard\plain\f1\fs20\insrsid1137675\charrsid1137675 \hich\af1\dbch\af0\loch\f1 -\tab}IRC connection timer added. It will reset if it takes too long to connect. +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid9571899 {\f1\fs20\insrsid2970612 +\par }\pard \ql \li720\ri0\nowidctlpar\faauto\rin0\lin720\itap0\pararsid8808284 {\f1\fs20\insrsid8808284 As always, }{\f1\fs20\insrsid6235869 this}{\f1\fs20\insrsid3676129 system }{\b\f1\fs20\insrsid3676129 requires no existing script modifications}{ +\f1\fs20\insrsid3676129 . +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\f1\fs20\insrsid3676129 +\par \tab }{\f1\fs20\insrsid7887838 And of course\'85}{\b\f1\fs20\insrsid3676129 The IRC capability of this chat system does not handle nickname registration. You will have to do this for your shard using another client. +\par }{\f1\fs20\insrsid3676129 +\par }{\b\f1\fs20\insrsid3676129 Features included in this system: +\par }{\b\f1\fs20\insrsid15147074 +\par {\listtext\pard\plain\f1\fs20\insrsid15147074 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid15147074 {\f1\fs20\insrsid15147074 Public or regional chatting +\par {\listtext\pard\plain\f1\fs20\insrsid15147074 \hich\af1\dbch\af0\loch\f1 -\tab}Channel creation or removal}{\f1\fs20\insrsid15147074\charrsid15147074 +\par {\listtext\pard\plain\f1\fs20\insrsid15147074 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid15147074 Guild, Alliance, Faction and IRC chatting}{\f1\fs20\insrsid15147074\charrsid15147074 +\par {\listtext\pard\plain\f1\fs20\insrsid15147074 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid15147074 Channel listings with simple navigation}{\f1\fs20\insrsid15147074\charrsid15147074 +\par {\listtext\pard\plain\f1\fs20\insrsid15147074 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid15147074 Ignoring, banning, listening, global listening}{\f1\fs20\insrsid15147074\charrsid15147074 +\par {\listtext\pard\plain\f1\fs20\insrsid16465683 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid16465683 Filtering and s}{\f1\fs20\insrsid15147074 pam prevention}{\f1\fs20\insrsid15147074\charrsid15147074 +\par {\listtext\pard\plain\f1\fs20\insrsid1998663 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid1998663 In-game integrated IRC client +\par {\listtext\pard\plain\f1\fs20\insrsid3542521 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid3542521 M}{\f1\fs20\insrsid14833682 u}{\f1\fs20\insrsid8333502 l}{\f1\fs20\insrsid14833682 ti-server chat connection tool +\par {\listtext\pard\plain\f1\fs20\insrsid13442825 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid13442825 Automated player notification system +\par {\listtext\pard\plain\f1\fs20\insrsid8333502 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid8333502 Searchable help contents +\par {\listtext\pard\plain\f1\fs20\insrsid10683748 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid9109621 {\f1\fs20\insrsid10683748 Localized text file for easy language changes}{ +\f1\fs20\insrsid9109621\charrsid15147074 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\f1\fs20\insrsid3676129 +\par }{\b\f1\fs20\insrsid3676129 Commands included in this system:}{\f1\fs20\insrsid3676129 }{\f1\fs20\insrsid13062140 +\par +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid13062140 {\f1\fs20\insrsid13062140 +You control the commands for your public channels! +\par {\listtext\pard\plain\f1\fs20\insrsid8325154 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid8325154 Public: }{\b\f1\fs20\insrsid8325154 C, Ch}{\f1\fs20\insrsid8325154 +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid13062140 Guild: }{\b\f1\fs20\insrsid13062140 G, Guild}{\f1\fs20\insrsid13062140 +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}Alliance: }{\b\f1\fs20\insrsid13062140 A, Ally}{\f1\fs20\insrsid13062140 +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}Faction: }{\b\f1\fs20\insrsid13062140 F, Faction}{\f1\fs20\insrsid13062140 +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}IRC: }{\b\f1\fs20\insrsid13062140 I, IRC}{\f1\fs20\insrsid13062140\charrsid16530520 +\par {\listtext\pard\plain\f1\fs20\insrsid16530520 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid16530520 Multi Server: }{\b\f1\fs20\insrsid16530520 Mu}{\f1\fs20\insrsid16530520 +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid13062140 Private Message: }{\b\f1\fs20\insrsid13062140 Pm, Msg}{\f1\fs20\insrsid13062140 (Followed by a player\rquote s name and text to include in message) + +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}Mail: }{\b\f1\fs20\insrsid13062140 Ma, Mail}{\f1\fs20\insrsid13062140 +\par {\listtext\pard\plain\f1\fs20\insrsid13062140 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid2243826 {\f1\fs20\insrsid13062140 Friends: }{\b\f1\fs20\insrsid13062140 F, Friends +}{\f1\fs20\insrsid2243826\charrsid13656871 +\par {\listtext\pard\plain\f1\fs20\insrsid13656871 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid13656871 Staff: }{\b\f1\fs20\insrsid13656871 St, Staff}{\f1\fs20\insrsid13656871\charrsid16457168 +\par {\listtext\pard\plain\f1\fs20\insrsid16457168 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid16457168 View all: }{\b\f1\fs20\insrsid16457168 Va}{\f1\fs20\insrsid16457168\charrsid16457168 +\par {\listtext\pard\plain\f1\fs20\insrsid16457168 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid16457168 Staff Announcements: }{\b\f1\fs20\insrsid16457168 All}{\f1\fs20\insrsid16457168\charrsid12413488 +\par {\listtext\pard\plain\f1\fs20\insrsid12413488 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid12413488 Help}{\b\f1\fs20\insrsid12413488 }{\f1\fs20\insrsid12413488 Contents: }{\b\f1\fs20\insrsid12413488 Hc}{\f1\fs20\insrsid12413488\charrsid10964469 + +\par {\listtext\pard\plain\f1\fs20\insrsid10964469 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid10964469 Errors: }{\b\f1\fs20\insrsid10964469 ChatErrors, CE}{\f1\fs20\insrsid10964469 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid12865895 {\f1\fs20\insrsid12865895 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\f1\fs20\insrsid13062140 +\par }{\b\f1\fs20\insrsid3676129 Interface details:}{\f1\fs20\insrsid1993206 +\par +\par }{\f1\fs20\insrsid9855981 \tab Most of you have been here before! For all you newer folks, here\rquote s a short take on this Chat system. You log into the game, type in the usual [c or [ch to open the menu. There you\rquote +ll see your first channel list, with all the players who are currently in the public channel, if your server has that channel enabled!}{\f1\fs20\insrsid3676129 +\par }{\f1\fs20\insrsid9855981 +\par \tab There\rquote s a number of useful buttons on that first page. Up on the top-left are little arrows to change the number of names that appear on the list, from 5 to 15. On the right you\rquote ll see the \lquote M\rquote , \lquote S\rquote and +\lquote Q\rquote buttons. The \lquote M\rquote is the menu, which will open up +on the right, and will list available channels, allow you to join or view them, change the view to others types like Mail and Friend listings, and finally allow you to change the many options available to you. \lquote S\rquote + is for Search, which filters your list by whatever you chose. Lastly, \lquote Q\rquote gives you tiny little buttons next to each name for fast access to features like Friend, Ignore, Pm, and more for staffers. +\par +\par \tab On the bottom of the list you\rquote ll find the Status setting. Here you can hide or tell everyone you are away or busy. Under the listing you\rquote +ll find what looks like a little stoplight. By pressing these buttons you can change the look of your list, cycling through backgrounds, text colors, and adding transparencies. +\par }{\f1\fs20\insrsid16148038 +\par \tab Of course, if you prefer the Chat 2.0 }{\f1\fs20\insrsid16457168 or Chat 1.0 }{\f1\fs20\insrsid16148038 interface,}{\f1\fs20\insrsid11603577 you can now change back to either}{\f1\fs20\insrsid16148038 through the \lquote M\rquote + menu. Just look at the little spell-circle buttons at the bottom of the }{\f1\fs20\insrsid11603577 list! It only changes the look;}{\f1\fs20\insrsid16148038 you get to keep all the new features of Chat 3.0. +\par }{\f1\fs20\insrsid12583005 +\par \tab +For all my non-english users, I also included a ChatLocal.txt file that will allow you to change the in-game text to whatever you wish! Just be sure you keep the line order intact! Drop this file in your RunUO/Data directory for it to work. You can als +o update this file and press a button in the General options to reload it without restarting the server. +\par }{\f1\fs20\insrsid14751431 +\par \tab Another text file of note is the Help Contents file. Using this, you can give players a searchable interface for help on the chat system. You can also expand it and add help information about your shard. Curious? Open up HelpContents.txt +, read how to add new entries, and move the saved file to your RunUO/Data folder! You can even reload the file in game without restarting the server. +\par }{\f1\fs20\insrsid11470933 +\par \tab I\rquote ve also included text files to make other features changeable! Inside the \lquote Text Data Files\rquote you\rquote ll find text files for filters, colors, backgrounds +, and avatars. Follow the directions in each file to put them to use. They must also be placed in your RunUO/Data folder to work. It might be a good idea to keep an unmodified copy of these files as well, just in case. +\par }{\f1\fs20\insrsid12981213 +\par \tab What? This is all!?!? Never! I just decided I don\rquote t need to write a 5 page description! This is just the icing. Once you take a bite, you\rquote +ll find the cake is filled with all sorts of goodness. Plug it in, explore the features! You won\rquote t be disappointed. +\par }{\f1\fs20\insrsid9855981 +\par }{\b\f1\fs20\insrsid3676129 Installing:}{\f1\fs20\insrsid3676129 +\par +\par {\listtext\pard\plain\f1\fs20\insrsid3609592 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid3609592 {\f1\fs20\insrsid3609592 Remove all previous installations of Knives +\rquote Chat +\par {\listtext\pard\plain\f1\fs20\insrsid12015873 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid12015873 If you don\rquote t need it for Town}{\f1\fs20\insrsid16387851 }{\f1\fs20\insrsid12015873 Houses, remove Knives\rquote Utilities. +\par {\listtext\pard\plain\f1\fs20\insrsid3609592 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid3609592 Drop the new Knives\rquote Chat into your custom folder. +\par {\listtext\pard\plain\f1\fs20\insrsid3609592 \hich\af1\dbch\af0\loch\f1 -\tab}If you want to use the Localization file, move ChatLocal.txt to your \lquote \\RunUO\\data\\\rquote folder. +\par {\listtext\pard\plain\f1\fs20\insrsid3219579 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid3219579 Run the server! }{\b\f1\fs20\insrsid3219579 No existing script modifications required!}{\f1\fs20\insrsid3219579\charrsid16387851 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid16387851 {\b\f1\fs20\insrsid16387851 +\par Enabling RunUO 1.0 Final:}{\f1\fs20\insrsid16387851 +\par +\par {\listtext\pard\plain\f1\fs20\insrsid16387851 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid16387851 {\f1\fs20\insrsid16387851 +In the main Chat directory, open up RUOVersion.cs +\par {\listtext\pard\plain\f1\fs20\insrsid16387851 \hich\af1\dbch\af0\loch\f1 -\tab}Follow the directions at the top of this file. +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid3884232 {\f1\fs20\insrsid3884232 +\par }{\b\f1\fs20\insrsid3884232 Enabling Xanthos\rquote s Jail System:}{\f1\fs20\insrsid3884232 +\par +\par {\listtext\pard\plain\f1\fs20\insrsid3884232 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls2\rin0\lin720\itap0\pararsid3884232 {\f1\fs20\insrsid3884232 In the main Chat directory, open up Jail.cs +\par {\listtext\pard\plain\f1\fs20\insrsid3884232 \hich\af1\dbch\af0\loch\f1 -\tab}Follow the directions at the top of this file. +\par {\listtext\pard\plain\f1\fs20\insrsid3884232 \hich\af1\dbch\af0\loch\f1 -\tab}}{\b\f1\fs20\insrsid3884232 You must have Xanthos\rquote s Jail System installed for this to work.}{\f1\fs20\insrsid3884232\charrsid3884232 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\b\f1\fs20\insrsid9797101 +\par }{\b\f1\fs20\insrsid3676129 Contact Info:}{\f1\fs20\insrsid3676129 Send me an email day or night (Though I will likely be sleeping at night)! kmwill23@hotmail.com}{\b\f1\fs20\insrsid3676129 +\par }} \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Text Data Files/ChatAvatars.txt b/Scripts/Customs/KniveChat/Text Data Files/ChatAvatars.txt new file mode 100644 index 0000000..2a940ca --- /dev/null +++ b/Scripts/Customs/KniveChat/Text Data Files/ChatAvatars.txt @@ -0,0 +1,36 @@ +// Here you can add custom Avatars to the chat system! +// Avatars appear in player profiles and private messages, and are limited to +// images available within Ultime Online's data files. If you aren't familiar +// with how to access these, I suggest you not use this file. If you are curious, +// see if you can find the program InsideUO. Improper IDs can cause client crashes. +// NOTE: Be sure you use the Integer ID value. +// TO USE THIS: Place your ChatAvatars.txt file in your RunUO/Data folder. + +// Unlike the other customizing text files, this requires multiple lines to add an +// Avatar. Not following these directions will skew the results. +// Three pieces of information are required for Avatars: + +// Image ID +// X Offset +// Y Offset + +// The offsets change the position of the image within the circle Avatar background. +// If your Image ID is above 100,000, it will use ItemIDs instead of Menu art. +// I personally like to center them, but that is your decision. You may have to +// play with the offsets to get the image in the right place. You can seperate +// your custom entries with blank spaces to make it easily readable. Here's an +// example: + +105 +8 +8 + +106 +8 +8 + +// Both of these entries already exist so they will be ignored by the system. +// Now it's your turn, place all your custom Avatars above the 'EndOfFile' tag. + + +EndOfFile \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Text Data Files/ChatBacks.txt b/Scripts/Customs/KniveChat/Text Data Files/ChatBacks.txt new file mode 100644 index 0000000..0e1accb --- /dev/null +++ b/Scripts/Customs/KniveChat/Text Data Files/ChatBacks.txt @@ -0,0 +1,16 @@ +// Here you can add more backgrounds to the menu customizations! +// This requires some knowledge of how gumps get their IDs, so please +// don't use this unless you know what you are doing. Improper definitions +// can cause client crashes. NOTE: Use the Integer ID value. +// TO USE THIS: Place your ChatBacks.txt file into your RunUO/Data folder. + +// Adding entries here is simple! If you add an entry which already exists +// it won't cause duplicates. So my example already exists! Here it is: + +83 + +// That's all! To get the IDs for the menus, I suggest the InsideUO program. +// Now, place your custom entries before the 'ENdOfFile' below. + + +EndOfFile \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Text Data Files/ChatColors.txt b/Scripts/Customs/KniveChat/Text Data Files/ChatColors.txt new file mode 100644 index 0000000..3a8e142 --- /dev/null +++ b/Scripts/Customs/KniveChat/Text Data Files/ChatColors.txt @@ -0,0 +1,17 @@ +// Here you can add new text colors to the gump customization! +// This system uses RGB values to determine its text colors, just like HTML. +// If you don't understand how to use RGB (RedGreenBlue), you can either +// Google them to get a color listing or not use this file at all. I don't +// think there is any risk of client crashes with bad entries. +// TO USE THIS: Place your ChatColors.txt file in your RunUO/Data folder. + +// Adding entries here is simple! You just put the 6 digit integer RGB value +// on its own line below, like this: + +111111 + +// Since this value already exists in the gump customizations, nothing will happen. +// Now add your custom colors before the 'EndOfFile' tag below! + + +EndOfFile \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Text Data Files/ChatFilters.txt b/Scripts/Customs/KniveChat/Text Data Files/ChatFilters.txt new file mode 100644 index 0000000..f8f5e82 --- /dev/null +++ b/Scripts/Customs/KniveChat/Text Data Files/ChatFilters.txt @@ -0,0 +1,14 @@ +// Here you can create filters that automatically add when your restart the server! +// Just in case you lose your save files, you'll never have to re-input your filters. +// TO USE THIS: Place your ChatFilters.txt file into the RunUO/Data folder. + +// The process is simple: Write your filter on its own line below! +// Just follow this example... + +Knives Rulz + +// In game, this filter will appear as "knives rulz" which will catch upper case as well. +// Be sure to add your filters before the "EndOfFile" line! + + +EndOfFile \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Text Data Files/ChatLocal.txt b/Scripts/Customs/KniveChat/Text Data Files/ChatLocal.txt new file mode 100644 index 0000000..cdc2a5f --- /dev/null +++ b/Scripts/Customs/KniveChat/Text Data Files/ChatLocal.txt @@ -0,0 +1,296 @@ +Friend +Views +Ignore +Remove Ignore +Grant Global +Revoke Global +Ban +Remove Ban +Global Ignore +Global Unignore +Listen +Remove Listen +Set your away message +Send Message +Become User +Client +Goto +Message Sound +Friend and Messaging Options +Online +Away +Busy +Hidden +You must unhide to see the player list +Only friends can send messages +Require friend requests +Global Messages +Sound on message receive +Default Message Sound +Friends speech shortcut +Friend online alert +Please select a channel to view +Friends +You are banned from chat +You must join the channel first +You are not in a chatting region +You are not in a guild +You are not in a faction +Channels +General Channel Options +Options +Channels speech shortcut +Commands +Global +Global Chat +Global World +View All +System Color +Staff Color +Color +Channel +Ignores +GIgnores +GListens +Bans +Display +Mail +Mail and Messaging Options +Auto delete week old messages +Mail speech shortcut +from +You must target a book +Message to +Recording. Press send when finished. +Recording stopped +Now recording. Everything you enter on the command line will appear in the message. +You must have a message to send +Message sent to +You are now ignoring +You delete the message +Speech command set to +Speech command cleared +is no longer on your friend list +is now on your friend list +You are no longer ignoring +now has global listening access +no longer has global access +You ban +You lift the ban from +You are no longer global ignoring +You are now global ignoring +You are no longer globally listening to +You are now globally listening to +is no longer online +Friend Request +Do you want to add this player as a friend? +You have sent a friend request to +has accepted your friend request +has denied your friend request +You deny +You are now banned from chat +Your chat ban has been lifted +You've been granted global access +Your global access has been revoked +Broadcast to all +Broadcast +You can send another request in +You must wait a few moments between messages +Enable IRC +Filter and Spam Options +IRC Options +Misc Options +The server is already attempting to connect +The server is already connected +IRC connection failed +Attempting to connect... +Connection could not be established +Connecting to IRC server... +Server is now connected to IRC channel +IRC names list updating +IRC connection down +Filter violation detected: +Too many search results, be more specific +No matching names found +Select a name +Auto Connect +Auto Reconnect +Nickname +Server +Room +Port +White +Black +Blue +Green +Light Red +Brown +Purple +Orange +Yellow +Light Green +Cyan +Light Cyan +Light Blue +Pink +Grey +Light Grey +Select a Color +Staff Color +Connect +Cancel Connect +Close Connection +Apply filter to world speech +Apply filter to private messages +Chat Spam +Pm Spam +Request Spam +Filter Ban +Add/Remove Filter +You remove the filter: +You add the filter: +Filters: +Show staff in channel lists +Max Mailbox Size +Filter Penalty +None +Ban +Jail +IRC connection is down +IRC Raw +Select Ban Time +30 minutes +1 hour +12 hours +1 day +1 week +1 month +1 year +Local file reloaded +Reload localized text file +days +hours +minutes +is now online +Error loading global options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving global options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error filtering text. Please report this to Knives at kmwill23@hotmail.com +Channel Options +New Channel +Please select a channel +Name +Style +Global +Regional +Send Chat to IRC +Add/Remove Command +Error loading channel information. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving channel information. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Auto join new players +You have left the channel +You have joined the channel +You must be staff to chat here +Global Guild +Global Faction +The message needs a subject before you can begin recording +Quick Bar +Message Read Receipts +has read +Error loading gump information. Details on the RunUO Console. Please report to Knives at kmwill23@hotmail.com +Error saving gump information. Details on the RunUO Console. Please report to Knives at kmwill23@hotmail.com +Errors reported by either this chat system or other staff members! Administrators have the power to clear this list. All staff members can report an error using the [chaterrors command. +Chat Error Log +Clear +Friends +Global Ignores +Global Listens +History +General +Filter +Spam +Irc +Delete Channel +Enable Channel +This channel is disabled +Filter Options +Spam Options +Colors +Mail Options +Your mailbox is full, please delete some messages so others may send to you. +Press the button above to select a channel. When adding commands, do not include the command prefix. +Delay +General Options +Debug +Show Staff +Viweing +You cannot send messages while under another user's identity. +Global Options +Error loading player options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving player options. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error loading friends. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving friends. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error loading ignores. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving ignores. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error loading global listens. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving global listens. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error loading private messages. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Error saving private messages. Details on the RunUO Console. Please report this to Knives at kmwill23@hotmail.com +Logging +Log Chat +Log Pms +Chat save completed in +Chat information saving... +The background you set will now be forced on all players. +Players can now set their own backgrounds. +Clear +Submit +Signature updated +Your signature: +Reply +Delete +Accept +Deny +Send +Chat Karma: +Filter Warnings +You can't chat while squelched. +Broadcast to Staff +Staff +You have {0} of max {1} in your mailbox. +Auto-delete old when mailbox full +You are squelched and cannot chat. +Staff Announcement +To use help, simply enter a word in the search line and all topics matching will pop up here! +Your search returned no results. +{0} results +{0} result +Error reported in connecting IRC. More information is available on the console. +Error reported in handling IRC input. More information is available on the console. +Error reported in disconnecting IRC. More information is available on the console. +Notifications +New Notification +Automated System Message +Text +Gump +Set Recur Time +Anti-Macro check +You have been flagged for violating afk macroing rules. +Afk Macroing + has been flagged for violating afk macroing rules. +You have been kicked for violating afk macroing rules. +Macro Penalty +Kick +Delay before penalty +Multi Server Chat +Run Multi Server +Multi Server +Start Server +Multi +Error connecting to master server. +Connected to master server. +Disconnecting from master server. + has disconnected. + has connected. +Reload Help Contents +Help contents reloaded +EndOfFile \ No newline at end of file diff --git a/Scripts/Customs/KniveChat/Text Data Files/HelpContents.txt b/Scripts/Customs/KniveChat/Text Data Files/HelpContents.txt new file mode 100644 index 0000000..05b196f --- /dev/null +++ b/Scripts/Customs/KniveChat/Text Data Files/HelpContents.txt @@ -0,0 +1,111 @@ +// The Help Contents menu can be found in game by either typing [HelpContents +// or pressing the '?' button on the chat gump in game. While I use it to +// provide help for the chat system, it can also be used by you to give info +// about your shard! + +// Here you can add new Help Contents entries! The process is very simple. +// Each entry has two lines. The first is the Subject, the second the Details. +// Here's a good example: + +Contact Knives +You can email me at kmwill23@hotmail.com, or visit www.runuo.com and leave me a private message. My MSN address is also kmwill23@hotmail.com. + +// The first line, Contact Knives, will appear as a selectable subject. +// The second line will appear when the player selects the subject entry. +// Be careful when you add entries! If you don't add two lines of text, +// it won't appear in the Help Contents menu. You can also apply updates to +// this file in game through the General Options menu. Press Relad Help Contents. +// Now go forth and add help contents! Good idea to add them at the bottom. + +Public Chat +Unless changed by your shard administrators, to use public chat begin your chat with '[c'. Try this: [c Hello world! + +Guild Chat +To use guild chat, you must first be in a guild. Once you have joined a guild, there are two ways you can chat with your new friends: [g and \g + +Private Messages +You can send private messages, or PMs, to other players whether they are online or not. There are many ways to do this. First, you can open up the Chat menu ( [c ) and press the gold button next to the player's name. You will now see an option to send them a message. For faster PMing, try turning on the Quickbar by pressing the 'Q' button on the main Chat menu. Then you can click the little 'm' button next to the player. If you can't see either of these, then they aren't allowing messages from you. This can be an ignore or they could require you to be friends first.

You can also use the command '[pm ' for ultra-fast PMing! + +Mail +By typing '[ma' you can access all your stored private message, which display kind of like an email list. From here you can view old messages, reply to them again, or delete them. You have many different mail options available to you: Auto deleting, friends only, friend online alert, read receipts, and received sounds. Check them out! + +Auto delete week old messages +By selecting this in Mail options, every time the world saves it will clear out any of your old messages. This can help keep you under your server's private message limit. + +Auto delete old when mailbox is full +By selecting this in Mail options, your mailbox will never prevent you from receiving new private messages. When you are at the limit, it will simply remove the oldest. + +Only freinds can send messages +Selecting this option in Mail options will limit who can send you private messages to prevent spam. Only those you have on your friends list can send you messages. + +Require friend requests +Just like most instant messengers, you can turn this Mail option on if you wish to approve who adds you as a friend. You get these requests in your mailbox. + +Friend online alert +A simple Mail option that will send you a message when one of your friends logs in. + +Message Read Receipts +Selecting this will inform you when another player first opens a private message you have sent them. Handy when you want to know if they are AFK and forgot to set their Away! + +Sound on message receive +If you have this Mail option enabled and your Ultima Online sound on, you can use this to give each person their own neat sound when they send you a private message. + +Channel Options +If you are an administrator, you can use this menu to modify each and every channel on your shard. Begin by pressing the button in the empty box and selecting the channel. You can also create new ones by pressing the New Channel button! For more info on each of the options, search for them in Help. + +Enable Channel +For staff, in the Channel Options menu you can chose to disable a channel. For example, if you don't want your shard to have a Public channel, simply uncheck the Enabled button. + +Regional Channel +For staff, in the Channel Options menu you can chose to make many channels Regional. This setting makes it so when a player chats in this channel, it is sent to those in the same town or dungeon, not to everyone. + +Global Channel +For staff, in the Channel Options menu you can chose to make any channel Global. The global setting is just like the default Public chat room, when a player sends a message it will be sent to all those online in that channel. + +Show Staff in Channel +For staff, in the Channel Options menu you can chose to show or not show staff in that channel. This will make it so players won't be able to see when staff are online. + +Send Channel Chat to IRC +For staff, in the Channel Options menu you can chose to send all player chat to your IRC channel. Your IRC channel must be connected for this option to work! + +Auto Joining to Channels +For staff, in the Channel Options menu you can chose to automaticaly join all new players to the selected channel. This allows them to be able to chat without first needing to know the details of the chat menu. + +Applying Filters to Channels +For staff, in the Channel Options menu you can chose to apply your filters to the selected channel. This option is enabled by default, so it is mroe likely you will disable it. Handy for allowing more chat freedom in Guild channels. + +Applying Spam Delay to Channels +For staff, in the Channel Options menu you can chose to allow spam protection to the selected channel. This option is enabled default. + +Adding Commands to Channels +For staff, in the Channel Options menu you can add and remove channel commands. To remove one, type in the command name as it displays on the command list. To add one, enter the command, without the prefix, that isn't already on the command list. + +Changing Chat Colors +You can change many of the colors in the chat system through the Color Options menu. You can change the following colors: Channels, System messages, and for staff your personal Staff chat color and the many Global color types. + +Notifications +If you are an administrator, Notifications allow you to send periodic messages to every online player. They come in two forms: Gump and Broadcast. If you select the Gump style, you can also apply an anti-macro check to the gump. If the player doesn't check this message after a time you specify, you will receive a Pm and you can then have them disconnected. Notifications are handy for remingins players to vote, telling them about features and events, and anything else you can imagine! + +Anti-Macro Chat Check +If you are an administrator, you can create anti-macro checks by using the Notifications system. Open up the Notifications View and create a new Notification. Select Gump and you will see options for enabling anti-macro check. Set the time and chose whether to disconnect them or not! Either way, you will receive a Pm notifying you when a player doesn't respond to the notification. + +Chat Filter Options +If you are an administrator, you can open the Filter options to add new filters and modify a few filter settings. For information on those settings, search for them here. + +Filter Speech +For administrators, in the Filter Options menu you can chose to have your filters applied to world speech. + +Filter Messages +For administrators, in the Filter Options menu you can chose to have your filters applied to private messages. + +Filter Penalties +For administrators, in the Filter Options menu you can change the penalty for violating filters. You can have them banned from chat, sent to jail if you have a jail system connected, or you can go light on them and just filter out the words! + +Filter Ban Length +For administrators, in the Filter Options menu you can change the amount of time a player is banned for when the Ban penalty is selected. + +Filter Warnings +For administrators, in the Filter Options menu you can change the amount of warnings a player gets before they face the chosen chat penalty. + +Adding and Removing Filters +For Administrators, in the Filter Options you can add and remove filters by either adding one which doesn;t appear in the list or entering one that is on the list to remove it. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Commands/DecorateML.cs b/Scripts/Customs/Nerun's Distro/ML/Commands/DecorateML.cs new file mode 100644 index 0000000..49a19c2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Commands/DecorateML.cs @@ -0,0 +1,33 @@ +using System; +using Server; +using System.IO; +using Server.Commands; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server +{ + public static class DecorateML + { + public static void Initialize() + { + CommandSystem.Register( "DecorateML", AccessLevel.Administrator, new CommandEventHandler( DecorateML_OnCommand ) ); + } + + [Usage( "DecorateML" )] + [Description( "Generates Mondain's Legacy world decoration." )] + private static void DecorateML_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Generating Mondain's Legacy world decoration, please wait." ); + + Decorate.Generate( "Data/Decoration/Mondain's Legacy/Trammel", Map.Trammel ); + Decorate.Generate( "Data/Decoration/Mondain's Legacy/Felucca", Map.Felucca ); + Decorate.Generate( "Data/Decoration/Mondain's Legacy/Ilshenar", Map.Ilshenar ); + Decorate.Generate( "Data/Decoration/Mondain's Legacy/Malas", Map.Malas ); + Decorate.Generate( "Data/Decoration/Mondain's Legacy/Tokuno", Map.Tokuno ); + + e.Mobile.SendMessage( "Mondain's Legacy world generation complete." ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Bedlam/MonstrousInterredGrizzle.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Bedlam/MonstrousInterredGrizzle.cs new file mode 100644 index 0000000..256f6a1 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Bedlam/MonstrousInterredGrizzle.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Monstrous Interred Grizzle corpse" )] + public class MonstrousInterredGrizzle : BaseCreature + { + [Constructable] + public MonstrousInterredGrizzle() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a monstrous interred grizzle"; + Body = 0x103; + BaseSoundID = 589; + + SetStr( 1198, 1207 ); + SetDex( 127, 135 ); + SetInt( 595, 646 ); + + SetHits( 50000 ); + + SetDamage( 27, 31 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 48, 52 ); + SetResistance( ResistanceType.Fire, 77, 82 ); + SetResistance( ResistanceType.Cold, 56, 61 ); + SetResistance( ResistanceType.Poison, 32, 40 ); + SetResistance( ResistanceType.Energy, 69, 71 ); + + SetSkill( SkillName.Wrestling, 112.6, 116.9 ); + SetSkill( SkillName.Tactics, 118.5, 119.2 ); + SetSkill( SkillName.MagicResist, 120 ); + SetSkill( SkillName.Anatomy, 111.0, 111.7 ); + SetSkill( SkillName.Magery, 100.0 ); + SetSkill( SkillName.EvalInt, 100 ); + SetSkill( SkillName.Meditation, 100 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 80; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosSuperBoss, 8 ); + } + + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public void DrainLife() + { + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 10 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team) ) + list.Add( m ); + else if ( m.Player ) + list.Add( m ); + } + + foreach ( Mobile m in list ) + { + DoHarmful( m ); + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist ); + m.PlaySound( 0x231 ); + + m.SendMessage( "Your Life is Mine to feed on!" ); + + int toDrain = Utility.RandomMinMax( 10, 40 ); + + Hits += toDrain; + m.Damage( toDrain, this ); + } + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 >= Utility.RandomDouble() ) + DrainLife(); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.1 >= Utility.RandomDouble() ) + DrainLife(); + } + + public MonstrousInterredGrizzle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Blighted Grove/Jamal.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Blighted Grove/Jamal.cs new file mode 100644 index 0000000..fdedb3d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Blighted Grove/Jamal.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Jamal : Fisherman + { + [Constructable] + public Jamal() : base() + { + Name = "Jamal"; + } + + public Jamal( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Human; + + Hue = 0x83FB; + HairItemID = 0x2049; + HairHue = 0x45E; + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new ThighBoots( 0x901 ) ); + AddItem( new ShortPants( 0x730 ) ); + AddItem( new Shirt( 0x1BB ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnSpeech( SpeechEventArgs m ) + { + if ( m.Mobile.InRange( this, 5 ) ) + { + Say( String.Format( "Hi {0}! My name is Jamal. I am supposed to be a Quest NPC.", m.Mobile.Name ) ); + Say( String.Format( "Sorry, but this Quest is currently not working." ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Blighted Grove/LadyMelisande.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Blighted Grove/LadyMelisande.cs new file mode 100644 index 0000000..459b5b0 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Blighted Grove/LadyMelisande.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a lady's corpse" )] + public class LadyMelisande : BaseCreature + { + [Constructable] + public LadyMelisande() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a lady melisande"; + Body = 0x102; + BaseSoundID = 451; + + SetStr( 420, 976 ); + SetDex( 306, 327 ); + SetInt( 1588, 1676 ); + + SetHits( 30000 ); + + SetDamage( 27, 31 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 49, 55 ); + SetResistance( ResistanceType.Fire, 41, 48 ); + SetResistance( ResistanceType.Cold, 57, 63 ); + SetResistance( ResistanceType.Poison, 70, 72 ); + SetResistance( ResistanceType.Energy, 74, 80 ); + + SetSkill( SkillName.Wrestling, 100.7, 102.0 ); + SetSkill( SkillName.Tactics, 100.1, 101.9 ); + SetSkill( SkillName.MagicResist, 120 ); + SetSkill( SkillName.Magery, 120 ); + SetSkill( SkillName.EvalInt, 120 ); + SetSkill( SkillName.Meditation, 120 ); + SetSkill( SkillName.Necromancy, 120 ); + SetSkill( SkillName.SpiritSpeak, 120 ); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 50; + + PackItem( new GnarledStaff() ); + PackNecroReg( 50, 80 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosSuperBoss, 8 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 4; } } + + public LadyMelisande( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Changeling.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Changeling.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Changeling.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/EliteNinjaWarrior.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/EliteNinjaWarrior.cs new file mode 100644 index 0000000..82991b5 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/EliteNinjaWarrior.cs @@ -0,0 +1,177 @@ + +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "an elite ninja corpse" )] + public class EliteNinjaWarrior : BaseCreature + { + private DateTime m_DecayTime; + private Timer m_Timer; + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool BardImmune { get { return true; } } + public override bool CanRummageCorpses { get { return true; } } + + + [Constructable] + public EliteNinjaWarrior() : base( AIType.AI_Ninja, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an elite ninja"; + Body = 0x190; + Hue = Utility.RandomSkinHue(); + + SetStr( 125, 175 ); + SetDex( 175, 275 ); + SetInt( 85, 105 ); + + SetHits( 250, 350 ); + + SetDamage( 8, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 60 ); + SetResistance( ResistanceType.Fire, 45, 65 ); + SetResistance( ResistanceType.Cold, 25, 45 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 65 ); + + Fame = 5000; + Karma = -5000; + + SetSkill( SkillName.MagicResist, 80.0, 100.0 ); + SetSkill( SkillName.Tactics, 115.0, 130.0 ); + SetSkill( SkillName.Wrestling, 95.0, 120.0 ); + SetSkill( SkillName.Anatomy, 105.0, 120.0 ); + SetSkill( SkillName.Fencing, 78.0, 100.0 ); + + SetSkill( SkillName.Ninjitsu, 90.0, 120.0 ); + SetSkill( SkillName.Hiding, 100.0, 120.0 ); + SetSkill( SkillName.Stealth, 100.0, 120.0 ); + + + AddItem( new LeatherNinjaHood() ); + AddItem( new LeatherNinjaJacket() ); + AddItem( new LeatherNinjaPants() ); + AddItem( new LeatherNinjaBelt() ); + AddItem( new LeatherNinjaMitts() ); + AddItem( new NinjaTabi() ); + + if( Utility.RandomDouble() < 0.33 ) + AddItem( new SmokeBomb() ); + + switch ( Utility.Random( 8 )) + { + case 0: AddItem( new Tessen() ); break; + case 1: AddItem( new Wakizashi() ); break; + case 2: AddItem( new Nunchaku() ); break; + case 3: AddItem( new Daisho() ); break; + case 4: AddItem( new Sai() ); break; + case 5: AddItem( new Tekagi() ); break; + case 6: AddItem( new Kama() ); break; + case 7: AddItem( new Katana() ); break; + } + + Utility.AssignRandomHair( this ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + c.DropItem( new BookOfNinjitsu() ); + } + + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 2 ); + //} + + m_DecayTime = DateTime.Now + TimeSpan.FromMinutes( 10.0 ); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + } + + + + public EliteNinjaWarrior( Serial serial ) : base( serial ) + { + } + /* public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 4 ); + }*/ + + + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + base.OnAfterDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_DecayTime = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + + break; + } + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mob; + + public InternalTimer( Mobile mob, DateTime end ) : base( end - DateTime.Now ) + { + m_Mob = mob; + } + + protected override void OnTick() + { + m_Mob.FixedParticles( 14120, 10, 15, 5012, EffectLayer.Waist ); + m_Mob.PlaySound( 510 ); + m_Mob.Delete(); + Stop(); + } + } + } +} + + + + + + \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/HumanBrigand.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/HumanBrigand.cs new file mode 100644 index 0000000..7fa6057 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/HumanBrigand.cs @@ -0,0 +1,113 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a human corpse" )] + public class HumanBrigand : BaseCreature + { + public override bool AlwaysMurderer{ get{ return true; } } + + [Constructable] + public HumanBrigand() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Hue = Race.Human.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 401; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 400; + Name = NameList.RandomName( "male" ); + } + + Title = "the brigand"; + + SetStr( 86, 100 ); + SetDex( 81, 95 ); + SetInt( 61, 75 ); + + SetDamage( 15, 27 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 25.0, 47.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 15.0, 37.5 ); + + Fame = 1000; + Karma = -1000; + + // outfit + AddItem( new Shirt( Utility.RandomNeutralHue() ) ); + + switch( Utility.Random( 4 ) ) + { + case 0: AddItem( new Sandals() ); break; + case 1: AddItem( new Shoes() ); break; + case 2: AddItem( new Boots() ); break; + case 3: AddItem( new ThighBoots() ); break; + } + + if ( Female ) + { + if ( Utility.RandomBool() ) + AddItem( new Skirt( Utility.RandomNeutralHue() ) ); + else + AddItem( new Kilt( Utility.RandomNeutralHue() ) ); + } + else + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + + // hair, facial hair + HairItemID = Race.Human.RandomHair( Female ); + HairHue = Race.Human.RandomHairHue(); + FacialHairItemID = Race.Human.RandomFacialHair( Female ); + + // weapon, shield + AddItem( Loot.RandomWeapon() ); + + if ( Utility.RandomBool() ) + AddItem( Loot.RandomShield() ); + + PackGold( 50, 150 ); + } + + public HumanBrigand( Serial serial ) : base( serial ) + { + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); +/* + if ( Utility.RandomDouble() < 0.75 ) + c.DropItem( new SeveredHumanEars() ); +*/ + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Flurry.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Flurry.cs new file mode 100644 index 0000000..4bceced --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Flurry.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a flurry corpse" )] + public class Flurry : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public Flurry () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Flurry"; + Body = 13; + Hue = 3; + BaseSoundID = 263; + + SetStr( 149, 195 ); + SetDex( 218, 264 ); + SetInt( 130, 199 ); + + SetHits( 474, 477 ); + + SetDamage( 10, 15 ); // Erica's + + SetDamageType( ResistanceType.Energy, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 56, 57 ); + SetResistance( ResistanceType.Fire, 38, 44 ); + SetResistance( ResistanceType.Cold, 40, 45 ); + SetResistance( ResistanceType.Poison, 31, 37 ); + SetResistance( ResistanceType.Energy, 39, 41 ); + + SetSkill( SkillName.EvalInt, 99.1, 100.2 ); + SetSkill( SkillName.Magery, 105.1, 108.8 ); + SetSkill( SkillName.MagicResist, 104.0, 112.8 ); + SetSkill( SkillName.Tactics, 113.1, 119.8 ); + SetSkill( SkillName.Wrestling, 105.6, 106.4 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 10 ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public Flurry( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 655; + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Grim.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Grim.cs new file mode 100644 index 0000000..5ea7219 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Grim.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "the remains of Grim" )] + public class Grim : Drake // Varchild's + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.CrushingBlow; + } + + [Constructable] + public Grim () : base() + { + Name = "Grim"; + Hue = 1744; + + SetStr( 527, 580 ); + SetDex( 284, 322 ); + SetInt( 249, 386 ); + + SetHits( 1762, 2502 ); + + SetResistance( ResistanceType.Physical, 55, 60 ); + SetResistance( ResistanceType.Fire, 62, 68 ); + SetResistance( ResistanceType.Cold, 52, 57 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 40, 44 ); + + SetSkill( SkillName.MagicResist, 105.8, 115.6 ); + SetSkill( SkillName.Tactics, 102.8, 120.8 ); + SetSkill( SkillName.Wrestling, 111.7, 119.2 ); + SetSkill( SkillName.Anatomy, 105.0, 128.4 ); + } + + public Grim( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Mistral.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Mistral.cs new file mode 100644 index 0000000..52ea280 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Mistral.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a mistral corpse" )] + public class Mistral : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public Mistral () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Mistral"; + Body = 13; + Hue = 924; + BaseSoundID = 263; + + SetStr( 134, 201 ); + SetDex( 226, 238 ); + SetInt( 126, 134 ); + + SetHits( 386, 609 ); + + SetDamage( 17, 20 ); // Erica's + + SetDamageType( ResistanceType.Energy, 20 ); + SetDamageType( ResistanceType.Cold, 40 ); + SetDamageType( ResistanceType.Physical, 40 ); + + SetResistance( ResistanceType.Physical, 55, 64 ); + SetResistance( ResistanceType.Fire, 36, 40 ); + SetResistance( ResistanceType.Cold, 33, 39 ); + SetResistance( ResistanceType.Poison, 30, 39 ); + SetResistance( ResistanceType.Energy, 49, 53 ); + + SetSkill( SkillName.EvalInt, 96.2, 97.8 ); + SetSkill( SkillName.Magery, 100.8, 112.9 ); + SetSkill( SkillName.MagicResist, 106.2, 111.2 ); + SetSkill( SkillName.Tactics, 110.2, 117.1 ); + SetSkill( SkillName.Wrestling, 100.3, 104.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public Mistral( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 655; + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Tempest.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Tempest.cs new file mode 100644 index 0000000..e646f9e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Makaar's Labyrinth Unreleased Mobiles/Tempest.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "the remains of Tempest" )] + public class Tempest : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public Tempest () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Tempest"; + Body = 13; + Hue = 1175; + BaseSoundID = 263; + + SetStr( 116, 135 ); + SetDex( 166, 185 ); + SetInt( 101, 125 ); + + SetHits( 602 ); + + SetDamage( 18, 20 ); // Erica's + + SetDamageType( ResistanceType.Energy, 80 ); + SetDamageType( ResistanceType.Cold, 20 ); + + SetResistance( ResistanceType.Physical, 46 ); + SetResistance( ResistanceType.Fire, 39 ); + SetResistance( ResistanceType.Cold, 33 ); + SetResistance( ResistanceType.Poison, 36 ); + SetResistance( ResistanceType.Energy, 58 ); + + SetSkill( SkillName.EvalInt, 99.6 ); + SetSkill( SkillName.Magery, 101.0 ); + SetSkill( SkillName.MagicResist, 104.6 ); + SetSkill( SkillName.Tactics, 111.8 ); + SetSkill( SkillName.Wrestling, 116.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 2; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public Tempest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 655; + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Miasma.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Miasma.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Miasma.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Pyre.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Pyre.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Pyre.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Rend.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Rend.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Labyrinth/Rend.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/OrcScout/OrcScout.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/OrcScout/OrcScout.cs new file mode 100644 index 0000000..e005a2d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/OrcScout/OrcScout.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class OrcScout : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public OrcScout() : base( AIType.AI_OrcScout, FightMode.Closest, 10, 7, 0.2, 0.4 ) + { + Name = "an orc scout"; + Body = 0xB5; + BaseSoundID = 0x45A; + + SetStr( 96, 120 ); + SetDex( 101, 130 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + SetMana( 30, 60 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 15, 20 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 50.1, 75.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + + SetSkill( SkillName.Fencing, 50.1, 70.0 ); + SetSkill( SkillName.Archery, 80.1, 120.0 ); + SetSkill( SkillName.Parry, 40.1, 60.0 ); + SetSkill( SkillName.Healing, 80.1, 100.0 ); + SetSkill( SkillName.Anatomy, 50.1, 90.0 ); + SetSkill( SkillName.DetectHidden, 100.1, 120.0 ); + SetSkill( SkillName.Hiding, 100.0, 120.0 ); + SetSkill( SkillName.Stealth, 80.1, 120.0 ); + + Fame = 1500; + Karma = -1500; + + Apple fruit = new Apple(Utility.RandomMinMax(3, 5)); + if (Utility.RandomDouble() <= 0.15) + fruit.Poison = Poison.Regular; + + PackItem( fruit ); + PackItem( new Arrow( Utility.RandomMinMax( 60, 70 ) ) ); + PackItem( new Bandage( Utility.RandomMinMax( 1, 15 ) ) ); + + if ( 0.1 > Utility.RandomDouble() ) + AddItem( new OrcishBow() ); + else + AddItem( new Bow() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + private Mobile FindTarget() + { + foreach ( Mobile m in this.GetMobilesInRange( 10 ) ) + { + if ( m.Player && m.Hidden && m.AccessLevel == AccessLevel.Player ) + { + return m; + } + } + + return null; + } + + private void TryToDetectHidden() + { + Mobile m = FindTarget(); + + if ( m != null ) + { + if ( DateTime.Now >= this.NextSkillTime && UseSkill( SkillName.DetectHidden ) ) + { + Target targ = this.Target; + + if ( targ != null ) + targ.Invoke( this, this ); + + Effects.PlaySound( this.Location, this.Map, 0x340 ); + } + } + } + + private void HealSelf() + { + if ( BandageContext.GetContext( this ) == null ) + { + BandageContext.BeginHeal( this, this ); + } + + return; + } + + public override void OnThink() + { + if ( Utility.RandomDouble() < 0.6 && Hits < ( HitsMax - 15 ) && !Hidden ) + HealSelf(); + + if ( Utility.RandomDouble() < 0.2 ) + TryToDetectHidden(); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + + public OrcScout( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/OrcScout/OrcishBow.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/OrcScout/OrcishBow.cs new file mode 100644 index 0000000..40192e3 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/OrcScout/OrcishBow.cs @@ -0,0 +1,75 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B2, 0x13B1 )] + public class OrcishBow : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosMinDamage{ get{ return 25; } } + public override int AosMaxDamage{ get{ return 35; } } + public override int AosSpeed{ get{ return 35; } } + + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 41; } } + public override int OldSpeed{ get{ return 20; } } + + public override int DefMaxRange{ get{ return 13; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 60; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } } + + [Constructable] + public OrcishBow() : base( 0x13B2 ) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + Name = "Orcish Bow"; + StrRequirement = 60; + Hue = 2106; + } + + public OrcishBow( Serial serial ) : base( serial ) + { + } + + public override bool OnFired( Mobile attacker, Mobile defender ) + { + Container pack = attacker.Backpack; + + if ( attacker.Player && (pack == null || !pack.ConsumeTotal( AmmoType, 2 )) ) + return false; + + attacker.MovingEffect( defender, EffectID, 18, 1, false, false ); + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 7.0 ) + Weight = 6.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Painted Caves/Grobu.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Painted Caves/Grobu.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Painted Caves/Grobu.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Painted Caves/Lurg.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Painted Caves/Lurg.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Painted Caves/Lurg.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/BulbousPutrification.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/BulbousPutrification.cs new file mode 100644 index 0000000..c6e2434 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/BulbousPutrification.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a bulbous putrification corpse" )] + public class BulbousPutrification : BaseCreature + { + [Constructable] + public BulbousPutrification() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bulbous putrification"; + Body = 0x28; + Hue = 0x55C; + BaseSoundID = 0x165; + + SetStr( 755, 800 ); + SetDex( 53, 60 ); + SetInt( 51, 59 ); + + SetHits( 1211, 1231 ); + + SetDamage( 22, 29 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 55, 70 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 104.8, 114.7 ); + SetSkill( SkillName.Tactics, 111.9, 119.1 ); + SetSkill( SkillName.MagicResist, 55.5, 64.1 ); + SetSkill( SkillName.Anatomy, 110.0 ); + SetSkill( SkillName.Poisoning, 80.0 ); + } + + public BulbousPutrification( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 5 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/ChiefParoxysmus.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/ChiefParoxysmus.cs new file mode 100644 index 0000000..2ffe766 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/ChiefParoxysmus.cs @@ -0,0 +1,136 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a chief paroxysmus corpse" )] + public class ChiefParoxysmus: BaseCreature + { + [Constructable] + public ChiefParoxysmus() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a chief paroxysmus"; + Body = 0x100; + + SetStr( 1232, 1400 ); + SetDex( 76, 82 ); + SetInt( 76, 85 ); + + SetHits( 50000 ); + + SetDamage( 27, 31 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 75, 85 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Poisoning, 120.0 ); + + } + + public ChiefParoxysmus( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosSuperBoss, 8 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); +/* + c.DropItem( new LardOfParoxysmus() ); + + switch ( Utility.Random( 3 ) ) + { + case 0: c.DropItem( new ParoxysmusDinner() ); break; + case 1: c.DropItem( new ParoxysmusCorrodedStein() ); break; + case 2: c.DropItem( new StringOfPartsOfParoxysmusVictims() ); break; + } + + if ( Utility.RandomDouble() < 0.6 ) + c.DropItem( new ParrotItem() ); + + if ( Utility.RandomBool() ) + c.DropItem( new SweatOfParoxysmus() ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new ParoxysmusSwampDragonStatuette() ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new ScepterOfTheChief() ); + + if ( Utility.RandomDouble() < 0.025 ) + c.DropItem( new CrimsonCincture() ); +*/ + } + +// public override bool GivesMinorArtifact{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + +// public override bool CanAreaPoison{ get{ return true; } } +// public override Poison HitAreaPoison{ get{ return Poison.Lethal; } } + + public override int GetDeathSound() { return 0x56F; } + public override int GetAttackSound() { return 0x570; } + public override int GetIdleSound() { return 0x571; } + public override int GetAngerSound() { return 0x572; } + public override int GetHurtSound() { return 0x573; } +/* + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + base.OnDamage( amount, from, willKill ); + + // eats pet or summons + if ( from is BaseCreature ) + { + BaseCreature creature = (BaseCreature) from; + + if ( creature.Controlled || creature.Summoned ) + { + Heal( creature.Hits ); + creature.Kill(); + + Effects.PlaySound( Location, Map, 0x574 ); + } + } + + // teleports player near + if ( from is PlayerMobile && !InRange( from.Location, 1 ) ) + { + Combatant = from; + + from.MoveToWorld( GetSpawnPosition( 1 ), Map ); + from.FixedParticles( 0x376A, 9, 32, 0x13AF, EffectLayer.Waist ); + from.PlaySound( 0x1FE ); + } + } +*/ + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/Putrifier.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/Putrifier.cs new file mode 100644 index 0000000..bb26f3e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Palace of Paroxysmus/Putrifier.cs @@ -0,0 +1 @@ +//Commented because added in RunUO SVN 847. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Prism of Light/CrystalHydra.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Prism of Light/CrystalHydra.cs new file mode 100644 index 0000000..c06163f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Prism of Light/CrystalHydra.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a crystal hydra corpse" )] + public class CrystalHydra : BaseCreature + { + [Constructable] + public CrystalHydra() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a crystal hydra"; + Body = 0x109; + Hue = 0x47E; + BaseSoundID = 362; + + SetStr( 804, 827 ); + SetDex( 103, 119 ); + SetInt( 101, 109 ); + + SetHits( 1486, 1500 ); + + SetDamage( 21, 26 ); + + SetDamageType( ResistanceType.Physical, 5 ); + SetDamageType( ResistanceType.Fire, 5 ); + SetDamageType( ResistanceType.Cold, 80 ); + SetDamageType( ResistanceType.Poison, 5 ); + SetDamageType( ResistanceType.Energy, 5 ); + + SetResistance( ResistanceType.Physical, 67, 74 ); + SetResistance( ResistanceType.Fire, 20, 29 ); + SetResistance( ResistanceType.Cold, 87, 98 ); + SetResistance( ResistanceType.Poison, 36, 45 ); + SetResistance( ResistanceType.Energy, 80, 100 ); + + SetSkill( SkillName.Wrestling, 100.6, 115.1 ); + SetSkill( SkillName.Tactics, 101.7, 108.1 ); + SetSkill( SkillName.MagicResist, 89.9, 99.5 ); + SetSkill( SkillName.Anatomy, 75.2, 79.1 ); + } + + public CrystalHydra( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 3 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); +/* + if ( Utility.RandomDouble() < 0.4 ) + c.DropItem( new ShatteredCrystals() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); +*/ + } + + #region Breath + public override int BreathFireDamage{ get{ return 0; } } + public override int BreathColdDamage{ get{ return 100; } } + public override int BreathEffectHue{ get{ return 0x47E; } } + public override int BreathEffectSound{ get{ return 0x56D; } } + public override bool HasBreath{ get{ return true; } } + #endregion + + public override int Hides{ get{ return 40; } } + public override int Meat{ get{ return 19; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Prism of Light/ShimmeringEffusion.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Prism of Light/ShimmeringEffusion.cs new file mode 100644 index 0000000..cb04988 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Prism of Light/ShimmeringEffusion.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Shimmering Effusion corpse" )] + public class ShimmeringEffusion : BaseCreature + { + [Constructable] + public ShimmeringEffusion() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a shimmering effusion"; + Body = 0x105; + + SetStr( 509, 538 ); + SetDex( 354, 381 ); + SetInt( 1513, 1578 ); + + SetHits( 20000 ); + + SetDamage( 27, 31 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 75, 76 ); + SetResistance( ResistanceType.Fire, 60, 65 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 76, 80 ); + SetResistance( ResistanceType.Energy, 75, 78 ); + + SetSkill( SkillName.Wrestling, 100.2, 101.4 ); + SetSkill( SkillName.Tactics, 105.5, 102.1 ); + SetSkill( SkillName.MagicResist, 150 ); + SetSkill( SkillName.Magery, 150.0 ); + SetSkill( SkillName.EvalInt, 150.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 70; + + PackItem( new GnarledStaff() ); + PackNecroReg( 15, 25 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosSuperBoss, 8 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override bool AutoDispel{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public ShimmeringEffusion( Serial serial ) : base( serial ) + { + } + + public override int GetIdleSound() + { + return 0x1BF; + } + + public override int GetAttackSound() + { + return 0x1C0; + } + + public override int GetHurtSound() + { + return 0x1C1; + } + + public override int GetDeathSound() + { + return 0x1C2; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/Chiikkaha.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/Chiikkaha.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/Chiikkaha.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/MougGuur.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/MougGuur.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/MougGuur.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/Szavetra.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/Szavetra.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Sanctuary/Szavetra.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/SpeckledScorpion.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/SpeckledScorpion.cs new file mode 100644 index 0000000..6e0981c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/SpeckledScorpion.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a speckled scorpion corpse" )] + public class SpeckledScorpion : Scorpion + { + [Constructable] + public SpeckledScorpion() : base() + { + Name = "a speckled scorpion"; + } + + public SpeckledScorpion( Serial serial ) : base( serial ) + { + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); +/* + if ( Utility.RandomDouble() < 0.4 ) + c.DropItem( new SpeckledPoisonSac() ); +*/ + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/DragonsFlameGrandMage.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/DragonsFlameGrandMage.cs new file mode 100644 index 0000000..aaee09a --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/DragonsFlameGrandMage.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a black order grand mage corpse" )] + public class DragonsFlameGrandMage : DragonsFlameMage + { + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + + [Constructable] + public DragonsFlameGrandMage() : base() + { + Name = "Black Order Grand Mage"; + Title = "of the Dragon's Flame Sect"; + } + + public DragonsFlameGrandMage( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 6 ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/DragonsFlameMage.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/DragonsFlameMage.cs new file mode 100644 index 0000000..ee972e1 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/DragonsFlameMage.cs @@ -0,0 +1,157 @@ + +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a black order mage corpse" )] + public class DragonsFlameMage : BaseCreature + { + private DateTime m_DecayTime; + private Timer m_Timer; + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + [Constructable] + public DragonsFlameMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Black Order Mage"; + Title = "of the Dragon's Flame Sect"; + Female = Utility.RandomBool(); + Race = Race.Human; + Hue = Race.RandomSkinHue(); + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + AddItem( new NinjaTabi() ); + AddItem( new FancyShirt( 0x51D ) ); + AddItem( new Hakama( 0x51D ) ); + AddItem( new Kasa( 0x51D ) ); + + + SetStr( 476, 505 ); + SetDex( 89, 95 ); + SetInt( 301, 325 ); + + SetHits( 286, 303 ); + + SetDamage( 10, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 60 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 70.1, 80.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 85.1, 95.0 ); + SetSkill( SkillName.Tactics, 70.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 58; + + + + m_DecayTime = DateTime.Now + TimeSpan.FromMinutes( 10.0 ); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + } + + + + public DragonsFlameMage( Serial serial ) : base( serial ) + { + } + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 4 ); + } + + public override void AlterSpellDamageFrom( Mobile from, ref int damage ) + { + if ( from != null ) + from.Damage( damage / 2, from ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + +// if ( Utility.RandomDouble() < 0.3 ) +// c.DropItem( new DragonFlameSectBadge() ); + +// if ( Utility.RandomDouble() < 0.1 ) +// c.DropItem( new ParrotItem() ); + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + base.OnAfterDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_DecayTime = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + + break; + } + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mob; + + public InternalTimer( Mobile mob, DateTime end ) : base( end - DateTime.Now ) + { + m_Mob = mob; + } + + protected override void OnTick() + { + m_Mob.FixedParticles( 14120, 10, 15, 5012, EffectLayer.Waist ); + m_Mob.PlaySound( 510 ); + m_Mob.Delete(); + Stop(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/MageDragonsFlameMage.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/MageDragonsFlameMage.cs new file mode 100644 index 0000000..202452d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/MageDragonsFlameMage.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Items; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a black order mage corpse" )] + public class MageDragonsFlameMage : DragonsFlameMage + { + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + + [Constructable] + public MageDragonsFlameMage() : base() + { + Name = "Black Order Mage"; + Title = "of the Dragon's Flame Mage"; + } + + public MageDragonsFlameMage( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 6 ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/SerpentsFangAssassin.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/SerpentsFangAssassin.cs new file mode 100644 index 0000000..270aa58 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/SerpentsFangAssassin.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a black order assassin corpse" )] + public class SerpentsFangAssassin : BaseCreature + { + private DateTime m_DecayTime; + private Timer m_Timer; + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + [Constructable] + public SerpentsFangAssassin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Black Order Assassin"; + Title = "of the Serpent's Fang Sect"; + Female = Utility.RandomBool(); + Race = Race.Human; + Hue = Race.RandomSkinHue(); + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + AddItem( new ThighBoots( 0x51D ) ); + AddItem( new FancyShirt( 0x51D ) ); + AddItem( new StuddedMempo() ); + AddItem( new JinBaori( 0x2A ) ); + + Item item; + + item = new StuddedGloves(); + item.Hue = 0x2A; + AddItem( item ); + + item = new LeatherNinjaPants(); + item.Hue = 0x51D; + AddItem( item ); + + item = new LightPlateJingasa(); + item.Hue = 0x51D; + AddItem( item ); + + item = new Sai(); + item.Hue = 0x51D; + AddItem( item ); + + + + + SetStr( 325, 375 ); + SetDex( 175, 275 ); + SetInt( 85, 105 ); + + SetHits( 350, 375 ); + + SetDamage( 14, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 60 ); + SetResistance( ResistanceType.Fire, 45, 65 ); + SetResistance( ResistanceType.Cold, 25, 45 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 65 ); + + SetSkill( SkillName.MagicResist, 80.0, 100.0 ); + SetSkill( SkillName.Tactics, 115.0, 130.0 ); + SetSkill( SkillName.Wrestling, 95.0, 120.0 ); + SetSkill( SkillName.Anatomy, 105.0, 120.0 ); + SetSkill( SkillName.Fencing, 78.0, 100.0 ); + SetSkill( SkillName.Swords, 90.1, 105.0 ); + SetSkill( SkillName.Ninjitsu, 90.0, 120.0 ); + SetSkill( SkillName.Hiding, 100.0, 120.0 ); + SetSkill( SkillName.Stealth, 100.0, 120.0 ); + + + + + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 58; + + + + m_DecayTime = DateTime.Now + TimeSpan.FromMinutes( 10.0 ); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + } + + + + public SerpentsFangAssassin( Serial serial ) : base( serial ) + { + } + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 4 ); + } + + + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + +// if ( Utility.RandomDouble() < 0.3 ) +// c.DropItem( new SerpentFangSectBadge() ); + + + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + base.OnAfterDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_DecayTime = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + + break; + } + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mob; + + public InternalTimer( Mobile mob, DateTime end ) : base( end - DateTime.Now ) + { + m_Mob = mob; + } + + protected override void OnTick() + { + m_Mob.FixedParticles( 14120, 10, 15, 5012, EffectLayer.Waist ); + m_Mob.PlaySound( 510 ); + m_Mob.Delete(); + Stop(); + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/SerpentsFangHighExecutioner.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/SerpentsFangHighExecutioner.cs new file mode 100644 index 0000000..6b99049 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/SerpentsFangHighExecutioner.cs @@ -0,0 +1,58 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a black order high executioner corpse" )] + public class SerpentsFangHighExecutioner : SerpentsFangAssassin + { + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + + [Constructable] + public SerpentsFangHighExecutioner() : base() + { + Name = "Black Order High Executioner"; + Title = "of the Serpent's Fang Sect"; + } + + public SerpentsFangHighExecutioner( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 6 ); + } + + public override void AlterMeleeDamageFrom( Mobile from, ref int damage ) + { + if ( from != null ) + from.Damage( damage / 2, from ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + +// if ( Utility.RandomDouble() < 0.2 ) +// c.DropItem( new SerpentFangKey() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/TigersClawMaster.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/TigersClawMaster.cs new file mode 100644 index 0000000..1bbeff3 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/TigersClawMaster.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a black order master corpse" )] + public class TigersClawMaster : TigersClawThief + { + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + + [Constructable] + public TigersClawMaster() : base() + { + Name = "Black Order Master"; + Title = "of the Serpent's Fang Sect"; + } + + public TigersClawMaster( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 6 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + +// if ( Utility.RandomDouble() < 0.2 ) +// c.DropItem( new TigerClawKey() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/TigersClawThief.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/TigersClawThief.cs new file mode 100644 index 0000000..fe66946 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/TigersClawThief.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a black order thief corpse" )] + public class TigersClawThief : BaseCreature + { + private DateTime m_DecayTime; + private Timer m_Timer; + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + [Constructable] + public TigersClawThief() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Black Order Thief"; + Title = "of the Tiger's Claw Sect"; + Female = Utility.RandomBool(); + Race = Race.Human; + Hue = Race.RandomSkinHue(); + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + AddItem( new ThighBoots( 0x51D ) ); + AddItem( new Wakizashi() ); + AddItem( new FancyShirt( 0x51D ) ); + AddItem( new StuddedMempo() ); + AddItem( new JinBaori( 0x69 ) ); + + Item item; + + item = new StuddedGloves(); + item.Hue = 0x69; + AddItem( item ); + + item = new LeatherNinjaPants(); + item.Hue = 0x51D; + AddItem( item ); + + item = new LightPlateJingasa(); + item.Hue = 0x51D; + AddItem( item ); + + // TODO quest items + + + SetStr( 225, 275 ); + SetDex( 175, 275 ); + SetInt( 85, 105 ); + + SetHits( 250, 275 ); + + SetDamage( 14, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 60 ); + SetResistance( ResistanceType.Fire, 45, 65 ); + SetResistance( ResistanceType.Cold, 25, 45 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 65 ); + + SetSkill( SkillName.MagicResist, 80.0, 100.0 ); + SetSkill( SkillName.Tactics, 115.0, 130.0 ); + SetSkill( SkillName.Wrestling, 95.0, 120.0 ); + SetSkill( SkillName.Anatomy, 105.0, 120.0 ); + SetSkill( SkillName.Fencing, 78.0, 100.0 ); + SetSkill( SkillName.Swords, 90.1, 105.0 ); + SetSkill( SkillName.Ninjitsu, 90.0, 120.0 ); + SetSkill( SkillName.Hiding, 100.0, 120.0 ); + SetSkill( SkillName.Stealth, 100.0, 120.0 ); + + + + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 58; + + + + m_DecayTime = DateTime.Now + TimeSpan.FromMinutes( 10.0 ); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + } + + + + public TigersClawThief( Serial serial ) : base( serial ) + { + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosFilthyRich, 4 ); + } + + + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + +// if ( Utility.RandomDouble() < 0.3 ) +// c.DropItem( new TigerClawSectBadge() ); + + + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + base.OnAfterDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_DecayTime = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + + break; + } + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mob; + + public InternalTimer( Mobile mob, DateTime end ) : base( end - DateTime.Now ) + { + m_Mob = mob; + } + + protected override void OnTick() + { + m_Mob.FixedParticles( 14120, 10, 15, 5012, EffectLayer.Waist ); + m_Mob.PlaySound( 510 ); + m_Mob.Delete(); + Stop(); + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/Travesty.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/Travesty.cs new file mode 100644 index 0000000..70ececc --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/The Citadel/Travesty.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a travesty's corpse" )] + public class Travesty : BaseCreature + { + [Constructable] + public Travesty() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a travesty"; + Body = 0x108; + + SetStr( 909, 949 ); + SetDex( 901, 948 ); + SetInt( 903, 947 ); + + SetHits( 35000 ); + + SetDamage( 25, 30 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 52, 67 ); + SetResistance( ResistanceType.Fire, 51, 68 ); + SetResistance( ResistanceType.Cold, 51, 69 ); + SetResistance( ResistanceType.Poison, 51, 70 ); + SetResistance( ResistanceType.Energy, 50, 68 ); + + SetSkill( SkillName.Wrestling, 100.1, 119.7 ); + SetSkill( SkillName.Tactics, 102.3, 118.5 ); + SetSkill( SkillName.MagicResist, 101.2, 119.6 ); + SetSkill( SkillName.Anatomy, 100.1, 117.5 ); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 50; + + PackItem( new GnarledStaff() ); + PackNecroReg( 15, 25 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosSuperBoss, 8 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public Travesty( Serial serial ) : base( serial ) + { + } + + public override int GetIdleSound() + { + return 0x1BF; + } + + public override int GetAttackSound() + { + return 0x1C0; + } + + public override int GetHurtSound() + { + return 0x1C1; + } + + public override int GetDeathSound() + { + return 0x1C2; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Abbein.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Abbein.cs new file mode 100644 index 0000000..e139726 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Abbein.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Abbein : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Abbein() : base( "the wise" ) + { + Name = "Elder Abbein"; + } + + public Abbein( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x824D; + HairItemID = 0x2FD1; + HairHue = 0x321; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x74B ) ); + AddItem( new FemaleElvenRobe( 0x8A8 ) ); + AddItem( new RoyalCirclet() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Alelle.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Alelle.cs new file mode 100644 index 0000000..3919df3 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Alelle.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Alelle : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Alelle() : base( "the aborist" ) + { + Name = "Alelle"; + } + + public Alelle( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x8374; + HairItemID = 0x2FCC; + HairHue = 0x238; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x1BB ) ); + + Item item; + + item = new LeafGloves(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new LeafChest(); + item.Hue = 0x37; + AddItem( item ); + + item = new LeafLegs(); + item.Hue = 0x746; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Alethanian.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Alethanian.cs new file mode 100644 index 0000000..bb22e26 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Alethanian.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Alethanian : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Alethanian() : base( "the wise" ) + { + Name = "Elder Alethanian"; + } + + public Alethanian( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x876C; + HairItemID = 0x2FC2; + HairHue = 0x368; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots() ); + AddItem( new GemmedCirclet()); + AddItem( new HidePants() ); + AddItem( new HideFemaleChest() ); + AddItem( new HidePauldrons() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aluniol.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aluniol.cs new file mode 100644 index 0000000..d429b86 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aluniol.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Aluniol : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Aluniol() : base( "the healer" ) + { + Name = "Aluniol"; + } + + public Aluniol( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x8383; + HairItemID = 0x2FBF; + HairHue = 0x323; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new MaleElvenRobe( 0x47E ) ); + AddItem( new WildStaff() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aminia.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aminia.cs new file mode 100644 index 0000000..b197656 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aminia.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Aminia : BaseCreature + { + [Constructable] + public Aminia() : base( AIType.AI_Melee, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Aminia"; + Title = "the master weaponsmith's wife"; + Blessed = true; + + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Human; + + Hue = 0x83ED; + HairItemID = 0x203B; + HairHue = 0x454; + + AddItem( new Backpack() ); + AddItem( new Sandals( 0x75B ) ); + AddItem( new Tunic( 0x4BF ) ); + AddItem( new Skirt( 0x8FD ) ); + } + + public Aminia( Serial serial ) : base( serial ) + { + } + + public override void OnThink() + { + int hours = 0; + int minutes = 0; + + Clock.GetTime( Map, Location.X, Location.Y, out hours, out minutes ); + + if ( hours == 21 ) + { + Blessed = false; + Body = 0x17; + } + else + { + Blessed = true; + Body = 0x191; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aneen.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aneen.cs new file mode 100644 index 0000000..da032e2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Aneen.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Aneen : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Aneen() : base( "the keeper of tradition" ) + { + Name = "Lorekeeper Aneen"; + } + + public Aneen( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x83E5; + HairItemID = 0x2FBF; + HairHue = 0x90; + } + + public override void InitOutfit() + { + AddItem( new Sandals( 0x1BB ) ); + AddItem( new MaleElvenRobe( 0x48F ) ); + AddItem( new Item( 0xDF2 ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Athialon.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Athialon.cs new file mode 100644 index 0000000..69dcbae --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Athialon.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Athialon : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Athialon() : base( "the expeditionist" ) + { + Name = "Athialon"; + } + + public Athialon( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x8382; + HairItemID = 0x2FC0; + HairHue = 0x35; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new DiamondMace() ); + AddItem( new WoodlandBelt() ); + + Item item; + + item = new WoodlandLegs(); + item.Hue = 0x3B2; + AddItem( item ); + + item = new WoodlandChest(); + item.Hue = 0x3B2; + AddItem( item ); + + item = new WoodlandArms(); + item.Hue = 0x3B2; + AddItem( item ); + + item = new WingedHelm(); + item.Hue = 0x3B2; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Bolaevin.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Bolaevin.cs new file mode 100644 index 0000000..a5d4c6c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Bolaevin.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Bolaevin : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Bolaevin() : base( "the arcanist" ) + { + Name = "Bolaevin"; + } + + public Bolaevin( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x84DE; + HairItemID = 0x2FC0; + HairHue = 0x36; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x3B3 ) ); + AddItem( new RoyalCirclet() ); + AddItem( new LeafChest() ); + AddItem( new LeafArms() ); + + Item item; + + item = new LeafLegs(); + item.Hue = 0x1BB; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Daelas.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Daelas.cs new file mode 100644 index 0000000..b62d02d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Daelas.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Daelas : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Daelas() : base( "the aborist" ) + { + Name = "Daelas"; + } + + public Daelas( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x84DE; + HairItemID = 0x2FCF; + HairHue = 0x8F; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new ElvenPants( 0x8AB ) ); + + Item item; + + item = new LeafGloves(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new LeafChest(); + item.Hue = 0x8B0; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Georgio.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Georgio.cs new file mode 100644 index 0000000..f40b6f1 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Georgio.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Georgio : HumanBrigand + { + public override bool InitialInnocent{ get{ return true; } } + + [Constructable] + public Georgio() : base() + { + Name = "Georgio"; + Title = "the brigand"; + Female = false; + Hue = 0x8412; + + while ( Items.Count > 1 ) + if ( !( Items[ 0 ] is Backpack ) ) + Items[ 0 ].Delete(); + + AddItem( new Sandals( 0x75E ) ); + AddItem( new Shirt() ); + AddItem( new ShortPants( 0x66C ) ); + AddItem( new SkullCap( 0x649 ) ); + AddItem( new Pitchfork() ); + + HairItemID = 0x203C; + HairHue = 0x47A; + FacialHairItemID = 0x204D; + FacialHairHue = 0x47A; + } + + public Georgio( Serial serial ) : base( serial ) + { + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if ( from is PlayerMobile ) + base.OnDamage( amount, from, willKill ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Jothan.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Jothan.cs new file mode 100644 index 0000000..7e37f97 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Jothan.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Jothan : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Jothan() : base( "the wise" ) + { + Name = "Elder Jothan"; + } + + public Jothan( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x8579; + HairItemID = 0x2FC2; + HairHue = 0x2C2; + } + + public override void InitOutfit() + { + AddItem( new ThighBoots() ); + AddItem( new ElvenPants( 0x57A ) ); + AddItem( new ElvenShirt( 0x711 ) ); + AddItem( new Cloak( 0x21 ) ); + AddItem( new Circlet() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Mallew.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Mallew.cs new file mode 100644 index 0000000..2f80d60 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Mallew.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Mallew : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Mallew() : base( "the wise" ) + { + Name = "Elder Mallew"; + } + + public Mallew( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x876C; + HairItemID = 0x2FD1; + HairHue = 0x31E; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new Circlet() ); + AddItem( new Cloak( 0x3B2 ) ); + + Item item; + + item = new LeafChest(); + item.Hue = 0x53E; + AddItem( item ); + + item = new LeafArms(); + item.Hue = 0x53E; + AddItem( item ); + + item = new LeafTonlet(); + item.Hue = 0x53E; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Nythalia.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Nythalia.cs new file mode 100644 index 0000000..53c7f77 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Nythalia.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Nythalia : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Nythalia() : base( "the student" ) + { + Name = "Nythalia"; + } + + public Nythalia( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x840C; + HairItemID = 0x2045; + HairHue = 0x453; + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new Sandals( 0x74A ) ); + AddItem( new Robe( 0x498 ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Olaeni.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Olaeni.cs new file mode 100644 index 0000000..003b46f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Olaeni.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Olaeni : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Olaeni() : base( "the thaumaturgist" ) + { + Name = "Olaeni"; + } + + public Olaeni( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x851D; + HairItemID = 0x2FCF; + HairHue = 0x322; + } + + public override void InitOutfit() + { + AddItem( new Shoes( 0x736 ) ); + AddItem( new FemaleElvenRobe( 0x1C ) ); + AddItem( new GemmedCirclet() ); + AddItem( new Item( 0xDF2 ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Rebinil.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Rebinil.cs new file mode 100644 index 0000000..a7397e7 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Rebinil.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Rebinil : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Rebinil() : base( "the healer" ) + { + Name = "Rebinil"; + } + + public Rebinil( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x83E7; + HairItemID = 0x2FD0; + HairHue = 0x26B; + } + + public override void InitOutfit() + { + AddItem( new Sandals( 0x719 ) ); + AddItem( new FemaleElvenRobe( 0xAD ) ); + AddItem( new RoyalCirclet() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Taellia.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Taellia.cs new file mode 100644 index 0000000..f135bff --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Taellia.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Taellia : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Taellia() : base( "the wise" ) + { + Name = "Elder Taellia"; + + m_Spoken = DateTime.Now; + } + + public Taellia( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x8385; + HairItemID = 0x2FCD; + HairHue = 0x368; + } + + public override void InitOutfit() + { + AddItem( new Boots( 0x74B ) ); + AddItem( new FemaleElvenRobe( 0x44 ) ); + AddItem( new Circlet() ); + AddItem( new Item( 0xDF2 ) ); + } + + private DateTime m_Spoken; + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Alive && m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + int range = 5; + + if ( range >= 0 && InRange( m, range ) && !InRange( oldLocation, range ) && DateTime.Now >= m_Spoken + TimeSpan.FromMinutes( 1 ) ) + { + /* Welcome Seeker. Do you wish to embrace your elven heritage, casting + aside your humanity, and accepting the responsibilities of a caretaker + of our beloved Sosaria. Then seek out Darius the Wise in Moonglow. + He will place you on the path. */ + + Say( 1072800 ); + + m_Spoken = DateTime.Now; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Spoken = DateTime.Now; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Tyeelor.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Tyeelor.cs new file mode 100644 index 0000000..bba4781 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Tyeelor.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Tyeelor : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Tyeelor() : base( "the expeditionist" ) + { + Name = "Tyeelor"; + } + + public Tyeelor( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = false; + Race = Race.Elf; + + Hue = 0x8367; + HairItemID = 0x2FC1; + HairHue = 0x38; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots( 0x1BB ) ); + + Item item; + + item = new WoodlandLegs(); + item.Hue = 0x236; + AddItem( item ); + + item = new WoodlandChest(); + item.Hue = 0x236; + AddItem( item ); + + item = new WoodlandArms(); + item.Hue = 0x236; + AddItem( item ); + + item = new WoodlandBelt(); + item.Hue = 0x237; + AddItem( item ); + + item = new VultureHelm(); + item.Hue = 0x236; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Vicaie.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Vicaie.cs new file mode 100644 index 0000000..8ebfaef --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Vicaie.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Vicaie : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Vicaie() : base( "the wise" ) + { + Name = "Elder Vicaie"; + } + + public Vicaie( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Race = Race.Elf; + + Hue = 0x8362; + HairItemID = 0x2FCD; + HairHue = 0x90; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots() ); + AddItem( new Tunic( 0x1FA1 ) ); + + Item item; + + item = new LeafLegs(); + item.Hue = 0x3B3; + AddItem( item ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Yellienir.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Yellienir.cs new file mode 100644 index 0000000..53aa670 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Townfolk/Yellienir.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Yellienir : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool CanTeach{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + [Constructable] + public Yellienir() : base( "the bark weaver" ) + { + Name = "Yellienir"; + + m_Spoken = DateTime.Now; + } + + public Yellienir( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + CantWalk = true; + Race = Race.Elf; + + Hue = 0x851D; + HairItemID = 0x2FCE; + HairHue = 0x35; + } + + public override void InitOutfit() + { + AddItem( new ElvenBoots() ); + AddItem( new Cloak( 0x3B2 ) ); + AddItem( new FemaleLeafChest() ); + AddItem( new LeafArms() ); + AddItem( new LeafTonlet() ); + } + + private DateTime m_Spoken; + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Alive && m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + int range = 5; + + if ( range >= 0 && InRange( m, range ) && !InRange( oldLocation, range ) && DateTime.Now >= m_Spoken + TimeSpan.FromMinutes( 1 ) ) + { + /* Human. Do you crave the chance to denounce your humanity and prove your elven ancestry. + Do you yearn to accept the responsibilities of a caretaker of our beloved Sosaria and so + redeem yourself. Then human, seek out Darius the Wise in Moonglow. */ + + Say( 1072801 ); + + m_Spoken = DateTime.Now; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Spoken = DateTime.Now; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/DreadHorn.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/DreadHorn.cs new file mode 100644 index 0000000..a5c4558 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/DreadHorn.cs @@ -0,0 +1,88 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dread horn corpse" )] + + public class DreadHorn : BaseCreature + { + + [Constructable] + public DreadHorn() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Dread Horn"; + Body = 257; + BaseSoundID = 0xA8; + + SetStr( 812, 999 ); + SetDex( 507, 669 ); + SetInt( 1206, 1389 ); + + SetHits( 50000 ); + SetStam( 507, 669 ); + SetMana( 1206, 1389 ); + + SetDamage( 27, 31 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Poison, 60 ); + + SetResistance( ResistanceType.Physical, 40, 53 ); + SetResistance( ResistanceType.Fire, 50, 63 ); + SetResistance( ResistanceType.Cold, 50, 62 ); + SetResistance( ResistanceType.Poison, 67, 73 ); + SetResistance( ResistanceType.Energy, 60, 73 ); + + SetSkill( SkillName.Wrestling, 90.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.MagicResist, 110.0 ); + SetSkill( SkillName.Poisoning, 120.0 ); + SetSkill( SkillName.Magery, 110.0 ); + SetSkill( SkillName.EvalInt, 110.0 ); + SetSkill( SkillName.Meditation, 110.0 ); + + Fame = 11500; + Karma = -11500; + + VirtualArmor = 75; + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosSuperBoss, 8 ); + } + + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Regular; } } + + public override int Meat{ get{ return 5; } } + public override MeatType MeatType{ get{ return MeatType.Ribs; } } + + public override bool AutoDispel{ get{ return true; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override bool Unprovokable{ get{ return true; } } + public override bool BardImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public DreadHorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/DryadA.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/DryadA.cs new file mode 100644 index 0000000..4938c3e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/DryadA.cs @@ -0,0 +1,106 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dryad corpse" )] + public class DryadA : BaseCreature + { + public override bool InitialInnocent{ get{ return true; } } + + [Constructable] + public DryadA() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a Dryad"; + Body = 266; + BaseSoundID = 0x467; + + SetStr( 135, 150 ); + SetDex( 153, 166 ); + SetInt( 253, 281 ); + + SetHits( 302, 314 ); + SetStam( 153, 166 ); + SetMana( 253, 281 ); + + SetDamage( 11, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 41, 50 ); + SetResistance( ResistanceType.Fire, 15, 24 ); + SetResistance( ResistanceType.Cold, 40, 45 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 25, 32 ); + + SetSkill( SkillName.Wrestling, 71.5, 77.8 ); + SetSkill( SkillName.Tactics, 70.1, 77.3 ); + SetSkill( SkillName.MagicResist, 100.7, 118.8 ); + SetSkill( SkillName.Magery, 72.1, 77.3 ); + SetSkill( SkillName.EvalInt, 71.0, 79.5 ); + SetSkill( SkillName.Meditation, 80.1, 89.7 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosRich, 3 ); + } + + public override double WeaponAbilityChance{ get{ return 0.05; } } + public override int Meat{ get{ return 1; } } +/* + public override WeaponAbility GetWeaponAbility() + { + AreaPeace(); + + return null; + } + + public virtual int PeaceRange{ get{ return 5; } } + public virtual TimeSpan PeaceDuration{ get{ return TimeSpan.FromMinutes( 1 ); } } + + public virtual void AreaPeace() + { + IPooledEnumerable eable = Map.GetClientsInRange( Location, PeaceRange ); + + foreach( Server.Network.NetState state in eable ) + { + if ( state.Mobile is PlayerMobile && state.Mobile.CanSee( this ) ) + { + PlayerMobile player = (PlayerMobile) state.Mobile; + + if ( player.PeacedUntil < DateTime.Now ) + { + player.PeacedUntil = DateTime.Now + PeaceDuration; + player.SendLocalizedMessage( 1072065 ); // You gaze upon the dryad's beauty, and forget to continue battling! + } + } + } + } +*/ + public override int GetDeathSound() { return 0x57A; } + public override int GetAttackSound() { return 0x57B; } + public override int GetIdleSound() { return 0x57C; } + public override int GetAngerSound() { return 0x57D; } + public override int GetHurtSound() { return 0x57E; } + + public DryadA( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Gnaw.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Gnaw.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Gnaw.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Guile.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Guile.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Guile.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Irk.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Irk.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Irk.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/LadyLissith.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/LadyLissith.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/LadyLissith.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/LadySabrix.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/LadySabrix.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/LadySabrix.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Malefic.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Malefic.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Malefic.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Silk.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Silk.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Silk.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Spite.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Spite.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Spite.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Swoop.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Swoop.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Swoop.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Virulent.cs b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Virulent.cs new file mode 100644 index 0000000..a52d47d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/ML/Mobiles/Twisted Weald/Virulent.cs @@ -0,0 +1 @@ +// Commented because added in SVN 837. \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/AddonGenerator.cs b/Scripts/Customs/Nerun's Distro/New/Commands/AddonGenerator.cs new file mode 100644 index 0000000..64ac14c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/AddonGenerator.cs @@ -0,0 +1,904 @@ +/* +Package Name: CEO's Yet Another Arya Addon Generator (YAAAG) +Author: CEO +Version: 1.2 +Public Release: 09/25/07 +Purpose: Generates AddOns from statics, items, and tiles. Oh my! +*/ +// If you're using an SVN that supports List<> methods (remove the //s) to use those instead of arrays or add them for RC1. +#define RC2 +//#define DEBUG +#undef DEBUG +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Commands; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Network; +using Server.Targeting; + +namespace Arya.Misc +{ + public class AddonGenerator + { + /// + /// Set this value if you wish the scripts to be output somewhere else rather than in the default RunUO\TheBox + /// directory. This should be a full valid path on your computer + /// + /// Example: + /// + /// private static string m_CustomOutputDirector = @"C:\Program Files\RunUO\Scripts\Custom\Addons"; + /// + private static string m_CustomOutputDirectory = null; + + #region Template + + private const string m_SimpleCode = @" + for (int i = 0; i < m_AddOnSimpleComponents.Length / 4; i++) + AddComponent( new AddonComponent( m_AddOnSimpleComponents[i,0] ), m_AddOnSimpleComponents[i,1], m_AddOnSimpleComponents[i,2], m_AddOnSimpleComponents[i,3] );"; + + private const string m_ComplexCode = @" + for (int i = 0; i < m_AddOnComplexComponents.Length / 6; i++) + AddComplexComponent( (BaseAddon)this, m_AddOnComplexComponents[i,0], m_AddOnComplexComponents[i,1], m_AddOnComplexComponents[i,2], m_AddOnComplexComponents[i,3], m_AddOnComplexComponents[i,4], m_AddOnComplexComponents[i,5] );"; + + private const string m_ComplexNameCode = @" + private static void AddComplexComponent(BaseAddon addon, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource) + { + AddComplexComponent(addon, item, xoffset, yoffset, zoffset, hue, lightsource, null, 1); + } + + private static void AddComplexComponent(BaseAddon addon, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource, string name, int amount) + { + AddonComponent ac; + ac = new AddonComponent(item); + if (name != null && name.Length > 0) + ac.Name = name; + if (hue != 0) + ac.Hue = hue; + if (amount > 1) + { + ac.Stackable = true; + ac.Amount = amount; + } + if (lightsource != -1) + ac.Light = (LightType) lightsource; + addon.AddComponent(ac, xoffset, yoffset, zoffset); + }"; + + private const string m_Template = @" +//////////////////////////////////////// +// // +// Generated by CEO's YAAAG - V1.2 // +// (Yet Another Arya Addon Generator) // +// // +//////////////////////////////////////// +using System; +using Server; +using Server.Items; + +namespace {namespace} +{ + public class {name}Addon : BaseAddon + { + {simplelist} + {complexlist} + public override BaseAddonDeed Deed + { + get + { + return new {name}AddonDeed(); + } + } + + [ Constructable ] + public {name}Addon() + { +{simplecomponentscode} +{complexcomponentscode} +{namedcomponentscode} + } + + public {name}Addon( Serial serial ) : base( serial ) + { + } +{complexnamecomponentscode} + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class {name}AddonDeed : BaseAddonDeed + { + public override BaseAddon Addon + { + get + { + return new {name}Addon(); + } + } + + [Constructable] + public {name}AddonDeed() + { + Name = ""{name}""; + } + + public {name}AddonDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +}"; + + #endregion + + public static void Initialize() + { + CommandSystem.Register("AddonGen", AccessLevel.Administrator, new CommandEventHandler(OnAddonGen)); + } + + #region Command + [Usage("AddonGen [ [namespace]]"), + Description("Brings up the addon script generator gump. When used with the name (and eventually namespace) parameter generates an addon script from the targeted region.")] + private static void OnAddonGen(CommandEventArgs e) + { + + object[] state = new object[18]; + + state[0] = ""; + state[1] = "Server.Items"; + state[2] = true; + state[3] = false; + state[4] = false; + state[5] = true; + state[6] = true; + state[7] = true; + state[8] = true; + state[9] = -128; + state[10] = 127; + state[11] = state[13] = state[15] = 2; + state[12] = state[14] = state[16] = 16384; + + if (e.Arguments.Length > 0) + { + state[0] = e.Arguments[0]; + + if (e.Arguments.Length > 1) + state[1] = e.Arguments[1]; + } + e.Mobile.SendGump(new InternalGump(e.Mobile, state)); + } + #endregion + + private static void PickerCallback(Mobile from, Map map, Point3D start, Point3D end, object state) + { + object[] args = state as object[]; + int m_SimpleComponents = 0; + int m_ComplexComponents = 0; + int m_NamedComponents = 0; + int m_TotalComponents = 0; + + if (start.X > end.X) + { + int x = start.X; + start.X = end.X; + end.X = x; + } + + if (start.Y > end.Y) + { + int y = start.Y; + start.Y = end.Y; + end.Y = y; + } + + Rectangle2D bounds = new Rectangle2D(start, end); + + string name = args[0] as string; + string ns = args[1] as string; + + bool getStatics = (bool)args[2]; + bool getItems = (bool)args[3]; + bool getTiles = (bool)args[4]; + bool includeStaticRange = (bool)args[5]; + bool includeItemRange = (bool)args[6]; + bool includeTileRange = (bool)args[7]; + bool includeZRange = (bool)args[8]; + bool generateTest = (bool)args[17]; + + sbyte min = sbyte.MinValue; + sbyte max = sbyte.MaxValue; + + short minStaticID = 2; + short maxStaticID = 16384; + short minItemID = 2; + short maxItemID = 16384; + short minTileID = 2; + short maxTileID = 16384; + + try { min = sbyte.Parse(args[9] as string); } + catch { } + try { max = sbyte.Parse(args[10] as string); } + catch { } + try { minStaticID = short.Parse(args[11] as string); } + catch { } + try { maxStaticID = short.Parse(args[12] as string); } + catch { } + try { minItemID = short.Parse(args[13] as string); } + catch { } + try { maxItemID = short.Parse(args[14] as string); } + catch { } + try { minTileID = short.Parse(args[15] as string); } + catch { } + try { maxTileID = short.Parse(args[16] as string); } + catch { } + + Hashtable tiles = new Hashtable(); + + if (getTiles) + { + for (int x = start.X; x <= end.X; x++) + { + for (int y = start.Y; y <= end.Y; y++) + { +#if RC2 + StaticTile[] stlist = map.Tiles.GetStaticTiles(x, y, true); + List list = new List(); + List remove = new List(); +#else + ArrayList list = map.GetTilesAt(new Point2D(x, y), false, false, true); + ArrayList remove = new ArrayList(); +#endif + + foreach (StaticTile t in stlist) + { + list.Add(t); + + int id = t.ID - 16384; + if (id < 2 || id > 16382) + remove.Add(t); + else if (includeZRange && (t.Z < min || t.Z > max)) + remove.Add(t); + else if (!includeZRange && (t.Z >= min && t.Z <= max)) + remove.Add(t); + else if (includeTileRange && (id < minTileID || id > maxTileID)) + remove.Add(t); + else if (!includeTileRange && (id >= minTileID && id <= maxTileID)) + remove.Add(t); + } + + foreach (StaticTile t in remove) + { + list.Remove(t); + } + + if (list != null && list.Count > 0) + { + tiles[new Point2D(x, y)] = list; + } + } + } + } + + IPooledEnumerable en = map.GetItemsInBounds(bounds); + ArrayList target = new ArrayList(); + bool fail = false; + + try + { + foreach (object o in en) + { + if (getStatics) + { + Static s = o as Static; + if (s == null) + { } + else if (s.Deleted) + { } + else if (includeZRange && (s.Z < min || s.Z > max)) + continue; + else if (!includeZRange && (s.Z >= min && s.Z <= max)) + continue; + else if (includeStaticRange && (s.ItemID < minStaticID || s.ItemID > maxStaticID)) + continue; + else if (!includeStaticRange && (s.ItemID >= minStaticID && s.ItemID <= maxStaticID)) + continue; + else + { + target.Add(o); +#if DEBUG + Console.WriteLine("Static={0}:{1}", s.GetType().ToString(), s.ItemID); +#endif + continue; + } + } + if (getItems) + { + Static s = o as Static; + if (s != null) // Don't want a static + continue; + Item i = o as Item; + if (i == null) + continue; + else if (i.Deleted) + continue; + else if (i is BaseAddon) // Not a good idea to add a BaseAddOn for obvious reasons + continue; + else if (i.ItemID < 2 || i.ItemID > 16382) // This is not an Item within the normal artwork.. multi... etc.. Toss it + continue; + else if (includeZRange && (i.Z < min || i.Z > max)) + continue; + else if (!includeZRange && (i.Z >= min && i.Z <= max)) + continue; + else if (includeItemRange && (i.ItemID < minItemID || i.ItemID > maxItemID)) + continue; + else if (!includeItemRange && (i.ItemID >= minItemID && i.ItemID <= maxItemID)) + continue; +#if DEBUG + Console.WriteLine("item={0}:{1}, {2}-map{3}", i.GetType().ToString(), i.ItemID, i.Deleted, i.Map); +#endif + target.Add(o); + } + } + } + catch (Exception err) + { + Console.WriteLine(err.ToString()); + from.SendMessage(0x40, "The targeted components have been modified. Please retry."); + fail = true; + } + finally + { + en.Free(); + } + + if (fail) + return; + + if (target.Count == 0 && tiles.Keys.Count == 0) + { + from.SendMessage(0x40, "No components have been selected."); + from.SendGump(new InternalGump(from, args)); + return; + } + + // Get center + Point3D center = new Point3D(); + center.Z = 127; + + int x1 = bounds.End.X; + int y1 = bounds.End.Y; + int x2 = bounds.Start.X; + int y2 = bounds.Start.Y; + + // Get correct bounds + foreach (Item item in target) + { + if (item.Z < center.Z) + { + center.Z = item.Z; + } + + x1 = Math.Min(x1, item.X); + y1 = Math.Min(y1, item.Y); + x2 = Math.Max(x2, item.X); + y2 = Math.Max(y2, item.Y); + } + CEOIdentifyAddon IdentifyAddon = null; + + if (generateTest) + IdentifyAddon = new CEOIdentifyAddon("init"); + + foreach (Point2D p in tiles.Keys) + { +#if RC2 + List list = tiles[p] as List; +#else + ArrayList list = tiles[p] as ArrayList; +#endif + + if (list == null) + { + Console.WriteLine("The list is null... "); + return; + } + + foreach (StaticTile t in list) + { + if (t.Z < center.Z) + { + center.Z = t.Z; + } + } + + x1 = Math.Min(x1, p.X); + y1 = Math.Min(y1, p.Y); + x2 = Math.Max(x2, p.X); + y2 = Math.Max(y2, p.Y); + } + + center.X = x1 + ((x2 - x1) / 2); + center.Y = y1 + ((y2 - y1) / 2); + + // Build items + System.Text.StringBuilder nc = new System.Text.StringBuilder(); + nc.Append("\n"); + System.Text.StringBuilder sl = new System.Text.StringBuilder(); + sl.Append("private static int[,] m_AddOnSimpleComponents = new int[,] {\n\t\t\t "); + System.Text.StringBuilder cl = new System.Text.StringBuilder(); + cl.Append("private static int[,] m_AddOnComplexComponents = new int[,] {\n\t\t\t "); + System.Text.StringBuilder sc = new System.Text.StringBuilder(); + sc.Append("// "); + System.Text.StringBuilder cc = new System.Text.StringBuilder(); + cc.Append("// "); + + int simplecount = 0; + int complexcount = 0; + // Tiles + foreach (Point2D p in tiles.Keys) + { +#if RC2 + List list = tiles[p] as List; +#else + ArrayList list = tiles[p] as ArrayList; +#endif + int xOffset = p.X - center.X; + int yOffset = p.Y - center.Y; + + foreach (StaticTile t in list) + { + int zOffset = t.Z - center.Z; + int id = t.ID - 16384; + m_SimpleComponents++; + simplecount++; + m_TotalComponents++; + sc.AppendFormat("{0}\t ", m_TotalComponents); + if (simplecount > 1) + sl.Append(", "); + sl.Append("{"); + sl.AppendFormat("{0}, {1}, {2}, {3}", id, xOffset, yOffset, zOffset); + sl.Append("}"); + if (simplecount % 3 == 0) + { + sl.AppendFormat("{0}\n\t\t\t", sc.ToString()); + sc.Length = 0; + sc.Append("// "); + } + if (generateTest) + AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, 0, -1, string.Format("({0}):{1},{2},{3}", m_TotalComponents, xOffset, yOffset, zOffset), 0); + } + } + // Statics & Items + foreach (Item item in target) + { + if (item.Deleted) + continue; + int xOffset = item.X - center.X; + int yOffset = item.Y - center.Y; + int zOffset = item.Z - center.Z; + int id = item.ItemID; + + if (((item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource) || (item.Hue != 0) || (item.Name != null) || item.Amount > 1) // Use old method + { + if (item.Name != null || item.Amount != 0) // Have to do this one the old method + { + m_NamedComponents++; + m_TotalComponents++; + int lightsource = -1; + if ((item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource) + lightsource = (int)item.Light; + nc.AppendFormat("\t\t\tAddComplexComponent( (BaseAddon) this, {0}, {1}, {2}, {3}, {4}, {5}, \"{6}\", {7});// {8}\n", id, xOffset, yOffset, zOffset, item.Hue, lightsource, item.Name, item.Amount, m_TotalComponents); + if (generateTest) + AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, item.Hue, -1, string.Format("({0},{1}): {2}, {3}, {4}", m_TotalComponents, id, xOffset, yOffset, zOffset), item.Amount); + + } + else //if (item.Hue != 0 || (item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource) + { + int lightsource = -1; + if ((item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource) + lightsource = (int)item.Light; + m_ComplexComponents++; + m_TotalComponents++; + cc.AppendFormat("{0}\t", m_TotalComponents); + complexcount++; + if (complexcount > 1) + cl.Append(", "); + cl.Append("{"); + cl.AppendFormat("{0}, {1}, {2}, {3}, {4}, {5} ", id, xOffset, yOffset, zOffset, item.Hue, lightsource); + cl.Append("}"); + if (complexcount % 3 == 0) + { + cl.AppendFormat("{0}\n\t\t\t", cc.ToString()); + cc.Length = 0; + cc.Append("// "); + } + if (generateTest) + AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, item.Hue, -1, string.Format("({0},{1}): {2}, {3}, {4}", m_TotalComponents, id, xOffset, yOffset, zOffset), 0); + } + } + else // Add data to static table + { + m_SimpleComponents++; + m_TotalComponents++; + sc.AppendFormat("{0}\t", m_TotalComponents); + simplecount++; + if (simplecount > 1) + sl.Append(", "); + sl.Append("{"); + sl.AppendFormat("{0}, {1}, {2}, {3}", id, xOffset, yOffset, zOffset); + sl.Append("}"); + if (simplecount % 3 == 0) + { + sl.AppendFormat("{0}\n\t\t\t", sc.ToString()); + sc.Length = 0; + sc.Append("// "); + } + if (generateTest) + AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, item.Hue, -1, string.Format("({0},{1}): {2}, {3}, {4}", m_TotalComponents, id, xOffset, yOffset, zOffset), 0); + } + } + if (sc.Length > 4) + sl.AppendFormat("{0}\n", sc.ToString()); + if (cc.Length > 4) + cl.AppendFormat("{0}\n", cc.ToString()); + if (m_SimpleComponents > 0) + sl.Append("\t\t};\n\n"); + if (m_ComplexComponents > 0) + cl.Append("\t\t};\n\n"); + + string output = m_Template.Replace("{name}", name); + output = output.Replace("{simplelist}", m_SimpleComponents > 0 ? sl.ToString() : ""); + output = output.Replace("{simplecomponentscode}", m_SimpleComponents > 0 ? m_SimpleCode : ""); + output = output.Replace("{complexlist}", m_ComplexComponents > 0 ? cl.ToString() : ""); + output = output.Replace("{complexcomponentscode}", m_ComplexComponents > 0 ? m_ComplexCode : ""); + output = output.Replace("{namedcomponentscode}", m_NamedComponents > 0 ? nc.ToString() : ""); + output = output.Replace("{complexnamecomponentscode}", (m_ComplexComponents > 0 || m_NamedComponents > 0) ? m_ComplexNameCode : ""); + + output = output.Replace("{namespace}", ns); + + StreamWriter writer = null; + string path = null; + + if (m_CustomOutputDirectory != null) + path = Path.Combine(m_CustomOutputDirectory, string.Format(@"TheBox\{0}Addon.cs", name)); + else + path = Path.Combine(Core.BaseDirectory, string.Format(@"TheBox\{0}Addon.cs", name)); + + fail = false; + + try + { + string folder = Path.GetDirectoryName(path); + + if (!Directory.Exists(folder)) + { + Directory.CreateDirectory(folder); + } + + writer = new StreamWriter(path, false); + writer.Write(output); + } + catch + { + from.SendMessage(0x40, "An error occurred when writing the file."); + fail = true; + } + finally + { + if (writer != null) + writer.Close(); + } + + if (!fail) + { + from.SendMessage(0x40, "Script saved to {0}", path); + from.SendMessage(0x40, "Total components in AddOn: {0}", m_TotalComponents); + if (generateTest && IdentifyAddon != null) + { + from.SendMessage(0x37, "Now target a land tile to place a your addon."); + from.Target = new InternalTarget(IdentifyAddon); + } + } + } + + private static void AddIdentifyAddOnComponent(CEOIdentifyAddon ai, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource, string name, int amount) + { + if (ai == null) + return; + AddonComponent ac; + ac = new AddonComponent(item); + if (name != null && name.Length > 0) + ac.Name = name; + if (hue != 0) + ac.Hue = hue; + if (amount > 1) // Note: a warning will show on the console regarding a non-stackable item.... + { + ac.Stackable = true; + ac.Amount = amount; + } + if (lightsource != -1) + ac.Light = (LightType)lightsource; + ai.AddComponent(ac, xoffset, yoffset, zoffset); + } + + private class InternalTarget : Target + { + private CEOIdentifyAddon m_IdentifyAddon; + + public InternalTarget(CEOIdentifyAddon IdentifyAddon) + : base(12, false, TargetFlags.None) + { + m_IdentifyAddon = IdentifyAddon; + CheckLOS = true; + AllowGround = true; + DisallowMultis = true; + Range = 15; + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + if (m_IdentifyAddon != null) + m_IdentifyAddon.Delete(); + } + + protected override void OnTarget(Mobile from, object o) + { + if (o != null) + { + if (o is LandTarget) + { + LandTarget l = o as LandTarget; + m_IdentifyAddon.MoveToWorld(l.Location, from.Map); + } + else + { + from.SendMessage(37, "Use must target a land tile to place your addon."); + if (m_IdentifyAddon != null) + m_IdentifyAddon.Delete(); + } + + } + } + + } + #region Gump + private class InternalGump : Gump + { + private const int LabelHue = 0x480; + private const int TitleHue = 0x35; + private object[] m_State; + + public InternalGump(Mobile m, object[] state) + : base(100, 50) + { + m.CloseGump(typeof(InternalGump)); + m_State = state; + MakeGump(); + } + + private void MakeGump() + { + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + AddPage(0); + AddBackground(0, 0, 440, 260, 9260); + //AddAlphaRegion(10, 10, 430, 260); //uncomment this line if you like see-thru menus + AddHtml(0, 15, 440, 20, Center(Color("CEO's Yet Another Arya Addon Generator(YAAAG)", 0x000080)), false, false); + int x = 40; + AddLabel(20, x, LabelHue, @"Name"); + AddImageTiled(95, x, 165, 18, 9274); + AddTextEntry(95, x, 165, 20, LabelHue, 0, m_State[0] as string); // Name + x += 20; + AddLabel(20, x, LabelHue, @"Namespace"); + AddImageTiled(95, x, 165, 18, 9274); + AddTextEntry(95, x, 165, 20, LabelHue, 1, m_State[1] as string); // Namespace + AddLabel(340, x, TitleHue, @"ID Range"); + x += 20; + AddLabel(20, x, TitleHue, @"Export"); + AddLabel(170, x, TitleHue, @"ID Range"); + AddLabel(320, x, TitleHue, @"Include/Exclude"); + x += 25; + // Export Statics, Items, and Tiles + string[] exportString = new string[] { "Statics", "Items", "Tiles" }; + for (int i = 0; i < 3; i++) + { + DisplayExportLine(x, i, ((bool)m_State[i + 2]), ((bool)m_State[i + 5]), exportString[i], m_State[11 + (i * 2)].ToString(), m_State[12 + (i * 2)].ToString()); + x += (i < 2 ? 25 : 15); + } + AddImageTiled(15, x + 15, 420, 1, 9304); + x += 25; + // Z Range + AddCheck(350, x, 9026, 9027, ((bool)m_State[8]), 6); + AddLabel(20, x, LabelHue, @"Z Range"); + AddImageTiled(115, x + 15, 50, 1, 9274); + AddTextEntry(115, x - 5, 50, 20, LabelHue, 2, m_State[9].ToString()); + AddLabel(185, x, LabelHue, @"to"); + AddImageTiled(225, x + 15, 50, 1, 9274); + AddTextEntry(225, x - 5, 50, 20, LabelHue, 3, m_State[10].ToString()); + x += 25; + + // Buttons + AddButton(20, x, 4020, 4021, 0, GumpButtonType.Reply, 0); + AddLabel(55, x, LabelHue, @"Cancel"); + AddButton(155, x, 4005, 4006, 1, GumpButtonType.Reply, 0); + AddLabel(195, x, LabelHue, @"Generate"); + AddButton(300, x, 4005, 4006, 2, GumpButtonType.Reply, 0); + AddLabel(340, x, LabelHue, @"Test & Gen"); + } + + private void DisplayExportLine(int x, int index, bool state, bool include, string heading, string min, string max) + { + AddCheck(20, x, 9026, 9027, state, index); + AddLabel(40, x, LabelHue, heading); + AddImageTiled(115, x + 15, 50, 1, 9274); + AddTextEntry(115, x - 5, 50, 20, LabelHue, 4 + (index * 2), min);// Tile ID Min + AddLabel(185, x, LabelHue, @"to"); + AddImageTiled(225, x + 15, 50, 1, 9274); + AddTextEntry(225, x - 5, 50, 20, LabelHue, 5 + (index * 2), max);// Tile ID Max + AddCheck(350, x, 9026, 9027, include, index + 3); // Include or Exclude compare? + } + + private string Center(string text) + { + return String.Format("
{0}
", text); + } + + private string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + + public override void OnResponse(Server.Network.NetState sender, RelayInfo info) + { + if (info.ButtonID == 0) + return; + else if (info.ButtonID == 1) + m_State[17] = false; + else + m_State[17] = true; + + foreach (TextRelay text in info.TextEntries) + m_State[text.EntryID < 2 ? text.EntryID : text.EntryID + 7] = text.Text; + + // Reset checks + for (int x = 2; x <= 8; x++) + m_State[x] = false; + + foreach (int check in info.Switches) + m_State[check + 2] = true; // Offset by 2 in the state object + + if (Verify(sender.Mobile, m_State)) + { + BoundingBoxPicker.Begin(sender.Mobile, new BoundingBoxCallback(AddonGenerator.PickerCallback), m_State); + } + else + { + sender.Mobile.SendMessage(0x40, "Please review the generation parameters, some are invalid."); + sender.Mobile.SendGump(new InternalGump(sender.Mobile, m_State)); + } + } + + private static bool Verify(Mobile from, object[] state) + { + if (state[0] == null || (state[0] as string).Length == 0) + { + from.SendMessage(0x40, "Name field is invalid or missing."); + return false; + } + + if (state[1] == null || (state[1] as string).Length == 0) + { + from.SendMessage(0x40, "Namespace field is invalid or missing."); + return false; + } + + if (!((bool)state[2] || (bool)state[3] || (bool)state[4])) + { + from.SendMessage(0x40, "You must have least one Export button selected. (Static/Items/Tiles)"); + return false; + } + + string[] errors = new string[] {"Z Range Min", "Z Range Max","Static Min ID", "Static Max ID", + "Item Min ID", "Item Max ID", "Tile Min ID", "Tile Max ID"}; + + for (int x = 0; x < 8; x++) + if (!CheckNumber(x < 2 ? 0 : 1, state[x + 9] as string, errors[x], from)) + return false; + return true; + } + + private static bool CheckNumber(int numType, string number, string error, Mobile from) + { + sbyte sbyteTemp; + short shortTemp; + try + { + if (numType == 0) + sbyteTemp = sbyte.Parse(number); + else + shortTemp = short.Parse(number); + } + catch + { + from.SendMessage(0x40, "There's a problem with the {0} field.", error); + return false; + } + + return true; + } + } + #endregion + } +} + +#region CEOIdentifyAddon +namespace Server.Items +{ + public class CEOIdentifyAddon : BaseAddon + { + + [Constructable] + public CEOIdentifyAddon(string init) + { + // Nothing really here, just prevents adding a null contruct via [add command + } + + [Constructable] + public CEOIdentifyAddon() + { + this.Delete(); + } + + public CEOIdentifyAddon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // Version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + if (this.Map == null || this.Map == Map.Internal) + this.Delete(); // Remove it because it's most + } + + public void ReDeed(Mobile m) + { + this.Delete(); + } + + } +} +#endregion diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/AutoSpeedBooster.cs b/Scripts/Customs/Nerun's Distro/New/Commands/AutoSpeedBooster.cs new file mode 100644 index 0000000..0bf8597 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/AutoSpeedBooster.cs @@ -0,0 +1,110 @@ +/************************************** +*Script Name: Automatic Speed Booster +*Author: Joeku +*For use with RunUO 2.0 RC2 +*Client Tested with: 6.0.9.1 +*Version: 1.00 +*Initial Release: 08/06/08 +*Revision Date: 08/06/08 +**************************************/ + +using System; +using Server; +using Server.Accounting; +using Server.Commands; + +namespace Joeku.ASB +{ + public class ASB_Main + { + public const int Version = 100; // Script version (do not change) + public static AccessLevel HasAccess; // Who has access to the ASB? Mirrors that of the SpeedBoost command (default Counselor) + public static bool Initialized = false; // Has the script been initialized yet? (activated upon first player login) + public static bool Running = true; // Is the script active? (deactivates if SpeedBoost command is not found) + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler(EventSink_OnLogin); + } + + // Cannot fully initialize until shard is completely loaded, due to conflicts with the CommandSystem + public static void Start() + { + CommandEntry entry = CommandSystem.Entries["SpeedBoost"]; // Find the SpeedBoost CommandEntry + if( entry != null ) // The SpeedBoost command exists... + { + HasAccess = entry.AccessLevel; // Set the access to the system to the AccessLevel required to use the SpeedBoost command + CommandSystem.Register("AutoSpeedBooster", HasAccess, new CommandEventHandler(EventSink_OnCommand)); // Register the ASB command in the CommandSystem + HelpInfo.FillTable(); // Refresh the HelpInfo dictionary to include the ASB command + Initialized = true; // The script has now been initialized + } + else // The SpeedBoost command does not exist... + Running = false; // Deactivate the script + } + + public static void EventSink_OnLogin(LoginEventArgs e) + { + if( !Running ) // The script has been deactivated + return; + + if( !Initialized ) // The script has not yet been initialized... + Start(); // Initialize the script + + e.Mobile.SendMessage(String.Empty); // Skip a line + if( e.Mobile.AccessLevel >= HasAccess ) // Does the player have access to the ASB? + { + if( GetASB(e.Mobile) ) // The player's ASB is enabled (default)... + { + CommandSystem.Handle(e.Mobile, String.Format("{0}SpeedBoost", CommandSystem.Prefix)); // Force the player to invoke the SpeedBoost command + e.Mobile.SendMessage("Automatic speed boost is enabled for this account. To disable it, use the \"AutoSpeedBooster\" command."); + } + else // The player's ASB is disabled + e.Mobile.SendMessage("Automatic speed boost is disabled for this account. To enable it, use the \"AutoSpeedBooster\" command."); + } + e.Mobile.SendMessage(String.Empty); // Skip a line + } + + [Usage( "AutoSpeedBooster [true|false]" )] + [Description( "Toggles automatic speed boost upon login for the invoker." )] + public static void EventSink_OnCommand(CommandEventArgs e) + { + if( e.Length == 1 ) // There is one argument present... + { + if( Insensitive.Equals(e.Arguments[0], "true") ) // The argument is "true"... + SetASB(e.Mobile, true); // Enable the player's ASB + else if( Insensitive.Equals(e.Arguments[0], "false") ) // The argument is "false"... + SetASB(e.Mobile, false); // Disable the player's ASB + else // The argument is not a boolean value... + e.Mobile.SendMessage("Format: AutoSpeedBooster [true|false]"); + } + else if( e.Length > 1 ) // There is more than one argument present... + e.Mobile.SendMessage("Format: AutoSpeedBooster [true|false]"); + else // There are no arguments present + SetASB(e.Mobile, !GetASB(e.Mobile)); // Toggle the player's SpeedBooster + } + + public static bool GetASB(Mobile mob){ return GetASB((Account)mob.Account); } + public static bool GetASB(Account acc) + { + if( acc.GetTag("ASB") != null ) // Since the account has a SpeedBooster tag, the player's ASB has been disabled + return false; + return true; + } + + public static void SetASB(Mobile mob, bool set) + { + Account acc = (Account)mob.Account; + + if( set ) // Enable the player's ASB... + { + acc.RemoveTag("ASB"); // Remove any ASB tags the player's account might have + mob.SendMessage("Automatic speed boost has been enabled for this account."); + } + else // Disable the player's ASB... + { + acc.SetTag("ASB", "Automatic speed boost has been disabled for this account."); // Add an ASB tag to the player's account + mob.SendMessage("Automatic speed boost has been disabled for this account."); + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/ClearAll.cs b/Scripts/Customs/Nerun's Distro/New/Commands/ClearAll.cs new file mode 100644 index 0000000..cf04f15 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/ClearAll.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using Server; +using System.Text; +using System.Collections; +using System.Net; +using Server.Mobiles; +using Server.Network; +using Server.Commands; + +namespace Server.Commands +{ + public class WorldItemWipeCommand + { + public static void Initialize() + { + Register( "Clearall", AccessLevel.Administrator, new CommandEventHandler( Clearall_OnCommand ) ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + CommandSystem.Register( command, access, handler ); + } + + [Usage( "ClearAll" )] + [Description( "Clear all facets." )] + public static void Clearall_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + DateTime time = DateTime.Now; + + int countItems = 0; + int countMobs = 0; + ArrayList itemsdel = new ArrayList(); + + foreach ( Item itemdel in World.Items.Values ) + { + if ( itemdel.Parent == null ) + { + itemsdel.Add( itemdel ); + countItems +=1; + } + } + + foreach ( Mobile mobdel in World.Mobiles.Values ) + { + if ( !mobdel.Player ) + { + itemsdel.Add( mobdel ); + countMobs +=1; + } + } + + foreach ( object itemdel2 in itemsdel ) + { + if(itemdel2 is Item) ((Item)itemdel2).Delete(); + if(itemdel2 is Mobile) ((Mobile)itemdel2).Delete(); + + } + + double totalTime = ( ( DateTime.Now - time ).TotalSeconds ); + from.SendMessage( "{0} items removed. {1} mobs removed. Took {2} seconds!", countItems, countMobs, totalTime ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/CreateWorld.cs b/Scripts/Customs/Nerun's Distro/New/Commands/CreateWorld.cs new file mode 100644 index 0000000..ff4e254 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/CreateWorld.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Commands; +using Server.Network; +using Server.Gumps; + +namespace Server.Commands +{ + public class CreateWorld + { + public CreateWorld() + { + } + + public static void Initialize() + { + CommandSystem.Register( "Createworld", AccessLevel.Administrator, new CommandEventHandler( Create_OnCommand ) ); + } + + [Usage( "[createworld" )] + [Description( "Create world with a menu." )] + private static void Create_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new CreateWorldGump( e ) ); + } + } +} + +namespace Server.Gumps +{ + + public class CreateWorldGump : Gump + { + private CommandEventArgs m_CommandEventArgs; + public CreateWorldGump( CommandEventArgs e ) : base( 50,50 ) + { + m_CommandEventArgs = e; + Closable = true; + Dragable = true; + + AddPage(1); + + //fundo cinza + //x, y, largura, altura, item + AddBackground( 0, 0, 200, 415, 5054 ); + //---------- + AddLabel( 30, 2, 200, "CREATE WORLD GUMP" ); + //fundo branco + //x, y, largura, altura, item + AddImageTiled( 10, 20, 180, 355, 3004 ); + //---------- + AddLabel( 20, 26, 200, "Moongen" ); + AddLabel( 20, 51, 200, "DoorGen" ); + AddLabel( 20, 76, 200, "Decorate" ); + AddLabel( 20, 101, 200, "SignGen" ); + AddLabel( 20, 126, 200, "TelGen" ); + AddLabel( 20, 151, 200, "GenGauntlet" ); + AddLabel( 20, 176, 246, "GenChampions" ); + AddLabel( 20, 201, 200, "GenKhaldun" ); + AddLabel( 20, 226, 200, "GenerateFactions" ); + AddLabel( 20, 251, 200, "GenStealArties" ); + AddLabel( 20, 276, 200, "SHTelGen" ); + AddLabel( 20, 301, 200, "SecretLocGen" ); + AddLabel( 20, 326, 246, "DecorateML" ); + AddLabel( 20, 351, 246, "DecorateSA" ); + //Options + AddCheck( 160, 23, 210, 211, true, 101 ); + AddCheck( 160, 48, 210, 211, true, 102 ); + AddCheck( 160, 73, 210, 211, true, 103 ); + AddCheck( 160, 98, 210, 211, true, 104 ); + AddCheck( 160, 123, 210, 211, true, 105 ); + AddCheck( 160, 148, 210, 211, true, 106 ); + AddCheck( 160, 173, 210, 211, true, 107 ); + AddCheck( 160, 198, 210, 211, true, 108 ); + AddCheck( 160, 223, 210, 211, true, 109 ); + AddCheck( 160, 248, 210, 211, true, 110 ); + AddCheck( 160, 273, 210, 211, true, 111 ); + AddCheck( 160, 298, 210, 211, true, 112 ); + AddCheck( 160, 323, 210, 211, true, 113 ); + AddCheck( 160, 348, 210, 211, true, 114 ); + //Ok, Cancel (x, y, ?, ?, ?) + AddButton( 30, 384, 247, 249, 1, GumpButtonType.Reply, 0 ); + AddButton( 100, 384, 241, 243, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + switch( info.ButtonID ) + { + case 0: // Closed or Cancel + { + return; + } + + default: + { + // Make sure that the OK, button was pressed + if( info.ButtonID == 1 ) + { + // Get the array of switches selected + ArrayList Selections = new ArrayList( info.Switches ); + string prefix = Server.Commands.CommandSystem.Prefix; + + from.Say( "CREATING WORLD..." ); + + // Now use any selected command + if( Selections.Contains( 101 ) == true ) + { + from.Say( "Generating moongates..." ); + CommandSystem.Handle( from, String.Format( "{0}moongen", prefix ) ); + } + + if( Selections.Contains( 102 ) == true ) + { + from.Say( "Generating doors..." ); + CommandSystem.Handle( from, String.Format( "{0}doorgen", prefix ) ); + } + + if( Selections.Contains( 103 ) == true ) + { + from.Say( "Decorating world..." ); + CommandSystem.Handle( from, String.Format( "{0}decorate", prefix ) ); + } + + if( Selections.Contains( 104 ) == true ) + { + from.Say( "Generating signs..." ); + CommandSystem.Handle( from, String.Format( "{0}signgen", prefix ) ); + } + + if( Selections.Contains( 105 ) == true ) + { + from.Say( "Generating teleporters..." ); + CommandSystem.Handle( from, String.Format( "{0}telgen", prefix ) ); + } + + if( Selections.Contains( 106 ) == true ) + { + from.Say( "Generating Gauntlet spawners..." ); + CommandSystem.Handle( from, String.Format( "{0}gengauntlet", prefix ) ); + } + + if( Selections.Contains( 107 ) == true ) + { + // champions message in champions script + CommandSystem.Handle( from, String.Format( "{0}genchampions", prefix ) ); + } + + if( Selections.Contains( 108 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}genkhaldun", prefix ) ); + } + + if( Selections.Contains( 109 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}generatefactions", prefix ) ); + from.Say( "Factions Generated!" ); + } + + if( Selections.Contains( 110 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}genstealarties", prefix ) ); + from.Say( "Stealable Artifacts Generated!" ); + } + + if( Selections.Contains( 111 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}shtelgen", prefix ) ); + } + + if( Selections.Contains( 112 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}secretlocgen", prefix ) ); + } + + if( Selections.Contains( 113 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}decorateml", prefix ) ); + } + if( Selections.Contains( 114 ) == true ) + { + CommandSystem.Handle( from, String.Format( "{0}decoratesa", prefix ) ); + } + } + + from.Say( "World generation completed!" ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/GMbody.cs b/Scripts/Customs/Nerun's Distro/New/Commands/GMbody.cs new file mode 100644 index 0000000..e9842c0 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/GMbody.cs @@ -0,0 +1,211 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; +using Server; +using Server.Targeting; +using Server.Targets; +using Server.Mobiles; +using Server.Items; +using Server.Misc; + +namespace Server.Commands +{ + public class GMbody + { + public static void Initialize() + { + Register( "GMbody", AccessLevel.Counselor, new CommandEventHandler( GM_OnCommand ) ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + CommandSystem.Register( command, access, handler ); + } + + [Usage( "GMbody" )] + [Description( "Helps senior staff members set their body to GM style." )] + public static void GM_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new GMmeTarget(); + } + + private class GMmeTarget : Target + { + public GMmeTarget() : base( -1, false, TargetFlags.None ) + { + } + + private static void DisRobe( Mobile m_from, Container cont, Layer layer ) + { + if ( m_from.FindItemOnLayer( layer ) != null ) + { + Item item = m_from.FindItemOnLayer( layer ); + cont.AddItem( item ); + } + } + + private static Mobile m_Mobile; + + private static void EquipItem( Item item ) + { + EquipItem( item, false ); + } + + private static void EquipItem( Item item, bool mustEquip ) + { + if ( !Core.AOS ) + item.LootType = LootType.Newbied; + + if ( m_Mobile != null && m_Mobile.EquipItem( item ) ) + return; + + Container pack = m_Mobile.Backpack; + + if ( !mustEquip && pack != null ) + pack.DropItem( item ); + else + item.Delete(); + } + + private static void PackItem( Item item ) + { + if ( !Core.AOS ) + item.LootType = LootType.Newbied; + + Container pack = m_Mobile.Backpack; + + if ( pack != null ) + pack.DropItem( item ); + else + item.Delete(); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + Mobile targ = (Mobile)targeted; + if ( from != targ ) + from.SendMessage( "You may only set your own body to GM style." ); + + else + { + m_Mobile = from; + + CommandLogging.WriteLine( from, "{0} {1} is assuming a GM body", from.AccessLevel, CommandLogging.Format( from ) ); + + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}AutoSpeedBooster true", prefix ) ); + + Container pack = from.Backpack; + + List ItemsToDelete = new List(); + + foreach (Item item in from.Items) + { + if (item.Layer != Layer.Bank && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair && item.Layer != Layer.Mount && item.Layer != Layer.Backpack) + { + ItemsToDelete.Add(item); + } + } + foreach (Item item in ItemsToDelete) + { + item.Delete(); + } + + if ( pack == null ) + { + pack = new Backpack(); + pack.Movable = false; + + from.AddItem( pack ); + } + else + { + pack.Delete(); + pack = new Backpack(); + pack.Movable = false; + + from.AddItem( pack ); + } + + from.Hunger = 20; + from.Thirst = 20; + from.Fame = 0; + from.Karma = 0; + from.Kills = 0; + from.Hidden = true; + from.Blessed = true; + from.Hits = from.HitsMax; + from.Mana = from.ManaMax; + from.Stam = from.StamMax; + + if(from.AccessLevel >= AccessLevel.Counselor) + { + EquipItem( new StaffRing() ); + Spellbook book1 = new Spellbook( (ulong)18446744073709551615 ); + Spellbook book2 = new NecromancerSpellbook( (ulong)0xffff ); + Spellbook book3 = new BookOfChivalry(); + Spellbook book4 = new BookOfBushido(); + Spellbook book5 = new BookOfNinjitsu(); + + PackItem( book1 ); + PackItem( book2 ); + PackItem( book3 ); + PackItem( book4 ); + PackItem( book5 ); + + from.RawStr = 100; + from.RawDex = 100; + from.RawInt = 100; + from.Hits = from.HitsMax; + from.Mana = from.ManaMax; + from.Stam = from.StamMax; + + for ( int i = 0; i < targ.Skills.Length; ++i ) + targ.Skills[i].Base = 120; + } + + if(from.AccessLevel == AccessLevel.Counselor) + { + EquipItem( new CounselorRobe() ); + EquipItem( new ThighBoots( 3 ) ); + from.Title = "[Counselor]"; + } + + if(from.AccessLevel == AccessLevel.GameMaster) + { + EquipItem( new GMRobe() ); + EquipItem( new ThighBoots( 39 ) ); + from.Title = "[GM]"; + } + + if(from.AccessLevel == AccessLevel.Seer) + { + EquipItem( new SeerRobe() ); + EquipItem( new ThighBoots( 467 ) ); + from.Title = "[Seer]"; + } + + if(from.AccessLevel >= AccessLevel.Administrator) + { + PackItem( new StaffCloak() ); + EquipItem( new ThighBoots( 1001 ) ); + EquipItem( new AdminRobe() ); + } + + if(from.AccessLevel == AccessLevel.Administrator) + from.Title = "[Admin]"; + + if(from.AccessLevel == AccessLevel.Developer) + from.Title = "[Developer]"; + + if(from.AccessLevel == AccessLevel.Owner) + from.Title = "[Owner]"; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/GenChampion.cs b/Scripts/Customs/Nerun's Distro/New/Commands/GenChampion.cs new file mode 100644 index 0000000..2c0c84c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/GenChampion.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.CannedEvil; +using Server.Commands; + +namespace Server.Commands +{ + public class GenChampionSpawn + { + public static void Initialize() + { + CommandSystem.Register( "GenChampions" , AccessLevel.Administrator, new CommandEventHandler( Champ_OnCommand ) ); + } + + [Usage( "GenChampions" )] + [Description( "Install ChampionSpawnController at 1415 1695." )] + public static void Champ_OnCommand( CommandEventArgs e ) + { + Map map1 = Map.Felucca; + + ChampionSpawnController controller = new ChampionSpawnController(); + + controller.Active = true; + controller.MoveToWorld( new Point3D( 1415, 1695, 0 ), map1 ); + + e.Mobile.SendMessage( "Done. Look for ChampionSpawnController at 1415 1695." ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/PSCount.cs b/Scripts/Customs/Nerun's Distro/New/Commands/PSCount.cs new file mode 100644 index 0000000..ed914fd --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/PSCount.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using Server; +using System.Text; +using System.Collections.Generic; +using System.Net; +using Server.Mobiles; +using Server.Network; +using Server.Commands; + +namespace Server.Commands +{ + public class PSpawnerCount + { + public static void Initialize() + { + Register( "pscount", AccessLevel.Administrator, new CommandEventHandler( Clearall_OnCommand ) ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + CommandSystem.Register( command, access, handler ); + } + + [Usage( "pscount" )] + [Description( "Count PremiumSpawners." )] + public static void Clearall_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + DateTime time = DateTime.Now; + + List pspawnerlist = new List(); + + foreach ( Item pspawner in World.Items.Values ) + { + if ( pspawner.Parent == null && pspawner is PremiumSpawner) + { + pspawnerlist.Add( pspawner ); + } + } + + from.SendMessage( "Premium Spawners: {0}", pspawnerlist.Count ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/PremiumSpawnerGumps.cs b/Scripts/Customs/Nerun's Distro/New/Commands/PremiumSpawnerGumps.cs new file mode 100644 index 0000000..48c3a4d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/PremiumSpawnerGumps.cs @@ -0,0 +1,420 @@ +// By Nerun +// Engine r25 +using System; +using System.Collections; +using System.IO; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Commands; +using Server.Network; +using Server.Gumps; +using Server.Regions; + +namespace Server.Commands +{ + public class OptionsGumps + { + public OptionsGumps() + { + } + + public static void Initialize() + { + CommandSystem.Register( "GumpSaveRegion", AccessLevel.Administrator, new CommandEventHandler( OptionsGumps1_OnCommand ) ); + CommandSystem.Register( "GumpSaveCoordinate", AccessLevel.Administrator, new CommandEventHandler( OptionsGumps2_OnCommand ) ); + CommandSystem.Register( "GumpRemoveID", AccessLevel.Administrator, new CommandEventHandler( OptionsGumps3_OnCommand ) ); + CommandSystem.Register( "GumpRemoveCoordinate", AccessLevel.Administrator, new CommandEventHandler( OptionsGumps4_OnCommand ) ); + CommandSystem.Register( "GumpRemoveRegion", AccessLevel.Administrator, new CommandEventHandler( OptionsGumps5_OnCommand ) ); + } + + [Usage( "[GumpSaveRegion" )] + [Description( "Gump to Save inside Region" )] + private static void OptionsGumps1_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new GumpSaveRegion( e ) ); + } + + [Usage( "[GumpSaveCoordinate" )] + [Description( "Gump to save by coordinates" )] + private static void OptionsGumps2_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new GumpSaveCoordinate( e ) ); + } + + [Usage( "[GumpRemoveID" )] + [Description( "Gump to remove by ID" )] + private static void OptionsGumps3_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new GumpRemoveID( e ) ); + } + + [Usage( "[GumpRemoveCoordinate" )] + [Description( "Gump to remove by coordinates" )] + private static void OptionsGumps4_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new GumpRemoveCoordinate( e ) ); + } + + [Usage( "[GumpRemoveRegion" )] + [Description( "Gump to remove inside region" )] + private static void OptionsGumps5_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new GumpRemoveRegion( e ) ); + } + } +} + +namespace Server.Gumps +{ + public class GumpSaveRegion : Gump + { + private CommandEventArgs m_CommandEventArgs; + + public GumpSaveRegion( CommandEventArgs e ) : base( 50,50 ) + { + m_CommandEventArgs = e; + Closable = true; + Dragable = true; + Mobile from = e.Mobile; + + AddPage(1); + //x, y, width, hight + AddBackground( 0, 0, 232, 210, 5054 ); + + AddImageTiled( 15, 30, 120, 20, 3004 ); + AddTextEntry( 15, 30, 120, 20, 0, 0, @"region to save"); + AddLabel( 15, 10, 52, "Enter a Region:" ); + AddButton( 140, 32, 0x15E1, 0x15E5, 101, GumpButtonType.Reply, 0 ); + + AddLabel( 15, 60, 52, "Tip:" ); + AddHtml( 15, 80, 200, 110, "This will SAVE the spawners, in a specified region, to Data/Monsters/'region name'.map. Type [where if you don't know the region you are. Copy to the text box the name of the region. You also can open Data/Regions.xml to a full list of regions.
Example: you type [where and appear 'your region is town of Britain'. Type 'Britain' in text box.", true, true ); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // close the gump + { + break; + } + + case 101: + { + TextRelay oRegion = info.GetTextEntry( 0 ); + string sRegion = oRegion.Text; + if( sRegion != "" ) + { + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}Spawngen save {1}", prefix, sRegion ) ); + } + else + { + from.SendMessage( "You must specify a region!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpSaveRegion", prefix ) ); + } + break; + } + } + } + } + + public class GumpRemoveRegion : Gump + { + private CommandEventArgs m_CommandEventArgs; + + public GumpRemoveRegion( CommandEventArgs e ) : base( 50,50 ) + { + m_CommandEventArgs = e; + Closable = true; + Dragable = true; + Mobile from = e.Mobile; + + AddPage(1); + + AddBackground( 0, 0, 232, 210, 5054 ); + + AddImageTiled( 15, 30, 120, 20, 3004 ); + AddTextEntry( 15, 30, 120, 20, 0, 0, @"region to remove"); + AddLabel( 15, 10, 52, "Enter a Region:" ); + AddButton( 140, 32, 0x15E1, 0x15E5, 101, GumpButtonType.Reply, 0 ); + + AddLabel( 15, 60, 52, "Tip:" ); + AddHtml( 15, 80, 200, 110, "This will REMOVE the spawners, in a specified region. Type [where if you don't know the region you are. Copy to the text box the name of the region. You also can open Data/Regions.xml to a full list of regions.
Example: you type [where and appear 'your region is town of Britain'. Type 'Britain' in text box.", true, true ); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // close the gump + { + break; + } + + case 101: + { + TextRelay oRegion = info.GetTextEntry( 0 ); + string sRegion = oRegion.Text; + if( sRegion != "" ) + { + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}Spawngen remove {1}", prefix, sRegion ) ); + } + else + { + from.SendMessage( "You must specify a region!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpRemoveRegion", prefix ) ); + } + break; + } + } + } + } + + public class GumpRemoveID : Gump + { + private CommandEventArgs m_CommandEventArgs; + + public GumpRemoveID( CommandEventArgs e ) : base( 50,50 ) + { + m_CommandEventArgs = e; + Closable = true; + Dragable = true; + Mobile from = e.Mobile; + + AddPage(1); + + AddBackground( 0, 0, 232, 210, 5054 ); + + AddImageTiled( 15, 30, 120, 20, 3004 ); + AddTextEntry( 15, 30, 120, 20, 0, 0, @"SpawnID to remove"); + AddLabel( 15, 10, 52, "Enter a SpawnID:" ); + AddButton( 140, 32, 0x15E1, 0x15E5, 101, GumpButtonType.Reply, 0 ); + + AddLabel( 15, 60, 52, "Tip:" ); + AddHtml( 15, 80, 200, 110, "This command was made to UNLOAD your own custom maps. This will REMOVE the spawners with the specified ID. Type '[get spawnid' in a spawner to know your ID. Remember: 'By Hand' spawns, i.e., those done with '[add premiumspawner' have ID = 1.", true, true ); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // close the gump + { + break; + } + + case 101: + { + TextRelay oID = info.GetTextEntry( 0 ); + string sID = oID.Text; + if( sID != "" ) + { + try + { + int UnloadID = Convert.ToInt32( sID ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}Spawngen unload {1}", prefix, UnloadID ) ); + } + catch + { + from.SendMessage( "SpawnID must be a number!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpRemoveID", prefix ) ); + } + } + + else + { + from.SendMessage( "You must specify an SpawnID!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpRemoveID", prefix ) ); + } + break; + } + } + } + } + + public class GumpSaveCoordinate : Gump + { + private CommandEventArgs m_CommandEventArgs; + + public GumpSaveCoordinate( CommandEventArgs e ) : base( 50,50 ) + { + m_CommandEventArgs = e; + Closable = true; + Dragable = true; + Mobile from = e.Mobile; + + AddPage(1); + + AddBackground( 0, 0, 232, 235, 5054 ); + + AddImageTiled( 15, 30, 37, 20, 3004 ); + AddTextEntry( 15, 30, 37, 20, 0, 0, @"X1"); + + AddImageTiled( 57, 30, 37, 20, 3004 ); + AddTextEntry( 57, 30, 37, 20, 0, 1, @"Y1"); + + AddImageTiled( 15, 55, 37, 20, 3004 ); + AddTextEntry( 15, 55, 37, 20, 0, 2, @"X2"); + + AddImageTiled( 57, 55, 37, 20, 3004 ); + AddTextEntry( 57, 55, 37, 20, 0, 3, @"Y2"); + + AddLabel( 15, 10, 52, "Enter Coordinates:" ); + AddButton( 140, 32, 0x15E1, 0x15E5, 101, GumpButtonType.Reply, 0 ); + + AddLabel( 15, 85, 52, "Tip:" ); + AddHtml( 15, 105, 200, 110, "This will SAVE spawners inside specified coordinates. You can use [where in the first point and again [where in the second point to get the X and Y coordinates. You need 2: X1, Y1 for first point and X2, Y2 for the second point. The objective is determine a 'box'. This command will save all spawners inside this box.", true, true ); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // close the gump + { + break; + } + + case 101: + { + TextRelay oX1 = info.GetTextEntry( 0 ); + TextRelay oY1 = info.GetTextEntry( 1 ); + TextRelay oX2 = info.GetTextEntry( 2 ); + TextRelay oY2 = info.GetTextEntry( 3 ); + string sX1 = oX1.Text; + string sY1 = oY1.Text; + string sX2 = oX2.Text; + string sY2 = oY2.Text; + if( sX1 != "" && sY1 != "" && sX2 != "" && sY2 != "" ) + { + try + { + int iX1 = Convert.ToInt32( sX1 ); + int iY1 = Convert.ToInt32( sY1 ); + int iX2 = Convert.ToInt32( sX2 ); + int iY2 = Convert.ToInt32( sY2 ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}Spawngen save {1} {2} {3} {4}", prefix, iX1, iY1, iX2, iY2 ) ); + } + catch + { + from.SendMessage( "Coordinates must be numbers!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpSaveCoordinate", prefix ) ); + } + } + + else + { + from.SendMessage( "You must specify all coordinates!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpSaveCoordinate", prefix ) ); + } + break; + } + } + } + } + + public class GumpRemoveCoordinate : Gump + { + private CommandEventArgs m_CommandEventArgs; + + public GumpRemoveCoordinate( CommandEventArgs e ) : base( 50,50 ) + { + m_CommandEventArgs = e; + Closable = true; + Dragable = true; + Mobile from = e.Mobile; + + AddPage(1); + + AddBackground( 0, 0, 232, 235, 5054 ); + + AddImageTiled( 15, 30, 37, 20, 3004 ); + AddTextEntry( 15, 30, 37, 20, 0, 0, @"X1"); + + AddImageTiled( 57, 30, 37, 20, 3004 ); + AddTextEntry( 57, 30, 37, 20, 0, 1, @"Y1"); + + AddImageTiled( 15, 55, 37, 20, 3004 ); + AddTextEntry( 15, 55, 37, 20, 0, 2, @"X2"); + + AddImageTiled( 57, 55, 37, 20, 3004 ); + AddTextEntry( 57, 55, 37, 20, 0, 3, @"Y2"); + + AddLabel( 15, 10, 52, "Enter Coordinates:" ); + AddButton( 140, 32, 0x15E1, 0x15E5, 101, GumpButtonType.Reply, 0 ); + + AddLabel( 15, 85, 52, "Tip:" ); + AddHtml( 15, 105, 200, 110, "This will REMOVE spawners inside specified coordinates. You can use [where in the first point and again [where in the second point to get the X and Y coordinates. You need 2: X1, Y1 for first point and X2, Y2 for the second point. The objective is determine a 'box'. This command will remove all spawners inside this box.", true, true ); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // close the gump + { + break; + } + + case 101: + { + TextRelay oX1 = info.GetTextEntry( 0 ); + TextRelay oY1 = info.GetTextEntry( 1 ); + TextRelay oX2 = info.GetTextEntry( 2 ); + TextRelay oY2 = info.GetTextEntry( 3 ); + string sX1 = oX1.Text; + string sY1 = oY1.Text; + string sX2 = oX2.Text; + string sY2 = oY2.Text; + if( sX1 != "" && sY1 != "" && sX2 != "" && sY2 != "" ) + { + try + { + int iX1 = Convert.ToInt32( sX1 ); + int iY1 = Convert.ToInt32( sY1 ); + int iX2 = Convert.ToInt32( sX2 ); + int iY2 = Convert.ToInt32( sY2 ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}Spawngen remove {1} {2} {3} {4}", prefix, iX1, iY1, iX2, iY2 ) ); + } + catch + { + from.SendMessage( "Coordinates must be numbers!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpRemoveCoordinate", prefix ) ); + } + } + + else + { + from.SendMessage( "You must specify all coordinates!" ); + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}GumpRemoveCoordinate", prefix ) ); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/PremiumSpawnerMainGump.cs b/Scripts/Customs/Nerun's Distro/New/Commands/PremiumSpawnerMainGump.cs new file mode 100644 index 0000000..174b9cb --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/PremiumSpawnerMainGump.cs @@ -0,0 +1,297 @@ +// Engine r29 +#define RunUo2_0 +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class PremiumSpawnerMainGump : Gump + { + Mobile caller; + + public static void Initialize() + { +#if(RunUo2_0) + CommandSystem.Register("PremiumSpawner", AccessLevel.Administrator, new CommandEventHandler(PremiumSpawner_OnCommand)); + CommandSystem.Register("Spawner", AccessLevel.Administrator, new CommandEventHandler(PremiumSpawner_OnCommand)); +#else + Register("PremiumSpawner", AccessLevel.Administrator, new CommandEventHandler(PremiumSpawner_OnCommand)); + Register("Spawner", AccessLevel.Administrator, new CommandEventHandler(PremiumSpawner_OnCommand)); +#endif + } + + [Usage("PremiumSpawner")] + [Aliases( "Spawner" )] + [Description("PremiumSpawner main gump.")] + public static void PremiumSpawner_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from.HasGump(typeof(PremiumSpawnerMainGump))) + from.CloseGump(typeof(PremiumSpawnerMainGump)); + from.SendGump(new PremiumSpawnerMainGump(from)); + } + + public PremiumSpawnerMainGump(Mobile from) : this() + { + caller = from; + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public PremiumSpawnerMainGump() : base( 0, 0 ) + { + this.Closable=true; + this.Disposable=true; + this.Dragable=true; + //PAGE 1 + AddPage(1); + AddBackground(93, 68, 256, 423, 9200); + AddHtml( 98, 75, 244, 44, " PREMIUM SPAWNER
" + "by Nerun Rev.89", (bool)true, (bool)false); + AddBlackAlpha(100, 124, 241, 71); + AddLabel(109, 126, 52, @"WORLD CREATION"); + AddLabel(126, 148, 52, @"Let there be light (Create World)"); + AddLabel(126, 170, 52, @"Apocalypse now (Clear All Facets)"); + AddButton(109, 151, 1210, 1209, 101, GumpButtonType.Reply, 0); + AddButton(109, 173, 1210, 1209, 102, GumpButtonType.Reply, 0); + AddBlackAlpha(100, 200, 241, 89); + AddLabel(109, 202, 52, @"SELECT SPAWNS BY EXPANSION"); + AddLabel(126, 224, 52, @"UO Classic spawns (pre-T2A)"); + AddLabel(126, 244, 52, @"UO Mondain's Legacy spawns"); + AddLabel(126, 264, 52, @"UO KR, SA and HS spawns"); + //AddLabel(238, 224, 52, @"UO:ML spawns"); + //AddLabel(238, 244, 52, @"UO:KR, SA and HS spawns"); + //AddLabel(238, 264, 52, @"teste"); + AddButton(109, 227, 1210, 1209, 103, GumpButtonType.Reply, 0); + AddButton(109, 247, 1210, 1209, 104, GumpButtonType.Reply, 0); + AddButton(109, 267, 1210, 1209, 105, GumpButtonType.Reply, 0); + //AddButton(221, 227, 1210, 1209, 106, GumpButtonType.Reply, 0); + //AddButton(221, 247, 1210, 1209, 107, GumpButtonType.Reply, 0); + //AddButton(221, 267, 1210, 1209, 108, GumpButtonType.Reply, 0); + AddBlackAlpha(100, 294, 241, 89); + AddLabel(109, 296, 52, @"REMOVE SPAWNS BY EXPANSION"); + AddLabel(126, 318, 52, @"UO Classic spawns (pre-T2A)"); + AddLabel(126, 338, 52, @"UO Mondain's Legacy spawns"); + AddLabel(126, 358, 52, @"UO KR, SA and HS spawns"); + //AddLabel(238, 318, 52, @"Ter Mur"); + //AddLabel(238, 338, 52, @"Tokuno"); + //AddLabel(238, 358, 52, @"Trammel"); + AddButton(109, 321, 1210, 1209, 109, GumpButtonType.Reply, 0); + AddButton(109, 341, 1210, 1209, 110, GumpButtonType.Reply, 0); + AddButton(109, 361, 1210, 1209, 111, GumpButtonType.Reply, 0); + //AddButton(221, 321, 1210, 1209, 112, GumpButtonType.Reply, 0); + //AddButton(221, 341, 1210, 1209, 113, GumpButtonType.Reply, 0); + //AddButton(221, 361, 1210, 1209, 114, GumpButtonType.Reply, 0); + AddBlackAlpha(100, 388, 241, 68); + AddLabel(109, 391, 52, @"SMART PLAYER RANGE SENSITIVE"); + AddLabel(126, 413, 52, @"Generate Spawns' Overseer"); + AddLabel(126, 432, 52, @"Remove Spawns' Overseer"); + AddButton(109, 416, 1210, 1209, 115, GumpButtonType.Reply, 0); + AddButton(109, 435, 1210, 1209, 116, GumpButtonType.Reply, 0); + //Page change + AddLabel(207, 463, 200, @"1/3"); + AddButton(235, 465, 5601, 5605, 0, GumpButtonType.Page, 2); //advance + + // PAGE 2 + AddPage(2); + AddBackground(93, 68, 256, 423, 9200); + AddHtml( 98, 75, 244, 44, " PREMIUM SPAWNER
" + "by Nerun Rev.89", (bool)true, (bool)false); + AddBlackAlpha(100, 124, 241, 114); + AddLabel(109, 126, 52, @"SAVE SPAWNERS"); + AddLabel(126, 148, 52, @"All spawns (spawns.map)"); + AddLabel(126, 170, 52, @"'By hand' spawns (byhand.map)"); + AddLabel(126, 192, 52, @"Spawns inside region (region.map)"); + AddLabel(126, 214, 52, @"Spawns inside coordinates"); + AddButton(109, 151, 1210, 1209, 117, GumpButtonType.Reply, 0); + AddButton(109, 173, 1210, 1209, 118, GumpButtonType.Reply, 0); + AddButton(109, 195, 1210, 1209, 119, GumpButtonType.Reply, 0); + AddButton(109, 217, 1210, 1209, 120, GumpButtonType.Reply, 0); + AddBlackAlpha(100, 244, 241, 134); + AddLabel(109, 246, 52, @"REMOVE SPAWNERS"); + AddLabel(126, 268, 52, @"All spawners in ALL facets"); + AddLabel(126, 290, 52, @"All spawners in THIS facet"); + AddLabel(126, 312, 52, @"Remove spawners by SpawnID"); + AddLabel(126, 334, 52, @"Remove inside coordinates"); + AddLabel(126, 355, 52, @"Remove spawners inside region"); + AddButton(109, 271, 1210, 1209, 121, GumpButtonType.Reply, 0); + AddButton(109, 293, 1210, 1209, 122, GumpButtonType.Reply, 0); + AddButton(109, 315, 1210, 1209, 123, GumpButtonType.Reply, 0); + AddButton(109, 337, 1210, 1209, 124, GumpButtonType.Reply, 0); + AddButton(109, 358, 1210, 1209, 125, GumpButtonType.Reply, 0); + AddBlackAlpha(100, 385, 241, 71); + AddLabel(109, 387, 52, @"EDITOR"); + AddLabel(126, 408, 52, @"Spawn Editor (edit, find and list"); + AddLabel(126, 427, 52, @"all PremiumSpawners in the world)"); + AddButton(109, 411, 1210, 1209, 126, GumpButtonType.Reply, 0); + //Page change + AddLabel(207, 463, 200, @"2/3"); + AddButton(189, 465, 5603, 5607, 0, GumpButtonType.Page, 1); //back + AddButton(235, 465, 5601, 5605, 0, GumpButtonType.Page, 3); //advance + + //PAGE 3 + AddPage(3); + AddBackground(93, 68, 256, 423, 9200); + AddHtml( 98, 75, 244, 44, " PREMIUM SPAWNER
" + "by Nerun Rev.89", (bool)true, (bool)false); + AddBlackAlpha(101, 124, 241, 47); + AddLabel(109, 126, 52, @"CONVERSION UTILITY"); + AddLabel(127, 148, 52, @"RunUO Spawners to Premium"); + AddButton(110, 151, 1210, 1209, 127, GumpButtonType.Reply, 0); + AddBlackAlpha(101, 177, 241, 134); + AddLabel(109, 179, 52, @"CUSTOM REGIONS IN A BOX"); + AddLabel(127, 201, 52, @"Add a Region Controler"); + AddLabel(127, 222, 52, @"(double-click the Region"); + AddLabel(127, 243, 52, @"Controller to configure it region."); + AddLabel(127, 264, 52, @"Every Controller control one"); + AddLabel(127, 286, 52, @"region. Don't forget to prop)"); + AddButton(110, 204, 1210, 1209, 128, GumpButtonType.Reply, 0); + //Page change + AddLabel(207, 463, 200, @"3/3"); + AddButton(189, 465, 5603, 5607, 0, GumpButtonType.Page, 2); //back + } + + public static void DoThis( Mobile from, string command) + { + string prefix = Server.Commands.CommandSystem.Prefix; + CommandSystem.Handle( from, String.Format( "{0}{1}", prefix, command ) ); + CommandSystem.Handle( from, String.Format( "{0}spawner", prefix ) ); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + switch(info.ButtonID) + { + case 0: + { + //Quit + break; + } + case 101: + { + DoThis( from, "createworld" ); + break; + } + case 102: + { + DoThis( from, "clearall" ); + break; + } + case 103: + { + from.Say( "SPAWNING UO Classic..." ); + DoThis( from, "spawngen uoclassic/UOClassic.map" ); + break; + } + case 104: + { + DoThis( from, "SpawnUOML" ); + break; + } + case 105: + { + DoThis( from, "SpawnCurrent" ); + break; + } + //DoThis( from106, "" ); + //DoThis( from107, "" ); + //DoThis( from108, "" ); + case 109: + { + DoThis( from, "spawngen unload 1000" ); + break; + } + case 110: + { + DoThis( from, "UnloadUOML" ); + break; + } + case 111: + { + DoThis( from, "UnloadCurrent" ); + break; + } + //DoThis( from112, "" ); + //DoThis( from113, "" ); + //DoThis( from114, "" ); + case 115: + { + DoThis( from, "GenSeers" ); + break; + } + case 116: + { + DoThis( from, "RemSeers" ); + break; + } + case 117: + { + DoThis( from, "spawngen save" ); + break; + } + case 118: + { + DoThis( from, "spawngen savebyhand" ); + break; + } + case 119: + { + DoThis( from, "GumpSaveRegion" ); + break; + } + case 120: + { + DoThis( from, "GumpSaveCoordinate" ); + break; + } + case 121: + { + DoThis( from, "spawngen remove" ); + break; + } + case 122: + { + DoThis( from, "spawngen cleanfacet" ); + break; + } + case 123: + { + DoThis( from, "GumpRemoveID" ); + break; + } + case 124: + { + DoThis( from, "GumpRemoveCoordinate" ); + break; + } + case 125: + { + DoThis( from, "GumpRemoveRegion" ); + break; + } + case 126: + { + DoThis( from, "SpawnEditor" ); + break; + } + case 127: + { + DoThis( from, "RunUOSpawnerExporter" ); + break; + } + case 128: + { + DoThis( from, "Add RegionControl" ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/Recover.cs b/Scripts/Customs/Nerun's Distro/New/Commands/Recover.cs new file mode 100644 index 0000000..e1d529c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/Recover.cs @@ -0,0 +1,67 @@ +// Recover v1.2 (mod of "Raisor's Heal v1.2") +// By Nerun +// Recover Hits, Stamina, Mana, Thirst and Hunger +// Ressurrect if dead +// +using System; +using Server; +using Server.Targeting; +using Server.Items; +using Server.Commands.Generic; + +namespace Server.Commands +{ + public class Recover + { + public static void Initialize() + { + Register(); + } + + public static void Register() + { + CommandSystem.Register( "Recover", AccessLevel.GameMaster, new CommandEventHandler( Recover_OnCommand ) ); + CommandSystem.Register( "Rec", AccessLevel.GameMaster, new CommandEventHandler( Recover_OnCommand ) ); + } + + private class RecoverTarget : Target + { + public RecoverTarget( Mobile m ) : base( -1, true, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object o ) + { + Mobile m; + + if ( !BaseCommand.IsAccessible( from, o ) ) + from.SendMessage( "That is not accessible." ); + else if ( o is Mobile ) + { + m = (Mobile)o; + if ( !m.Alive ) + { + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + m.Resurrect(); + } + m.Hits = m.HitsMax; + m.Stam = m.StamMax; + m.Mana = m.ManaMax; + m.Thirst = 20; + m.Hunger = 20; + } + else + from.SendMessage( "That is not a mobile." ); + } + } + + [Usage( "Recover" )] + [Aliases( "Rec" )] + [Description( "Ressurrects and recovers Thirst, Hunger, Hits, Stam and Mana of the targeted at the maximum level." )] + private static void Recover_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new RecoverTarget( e.Mobile ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/RunUOSpawnerExporter.cs b/Scripts/Customs/Nerun's Distro/New/Commands/RunUOSpawnerExporter.cs new file mode 100644 index 0000000..cfb168c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/RunUOSpawnerExporter.cs @@ -0,0 +1,145 @@ +//Engine r32 +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Commands +{ + public class RunUOSpawnerExporter + { + public const bool Enabled = true; + + public static void Initialize() + { + CommandSystem.Register( "RunUOSpawnerExporter" , AccessLevel.Administrator, new CommandEventHandler( RunUOSpawnerExporter_OnCommand ) ); + CommandSystem.Register( "RSE" , AccessLevel.Administrator, new CommandEventHandler( RunUOSpawnerExporter_OnCommand ) ); + } + + public static int ConvertToInt( TimeSpan ts ) + { + return ( ( ts.Hours * 60 ) + ts.Minutes + (ts.Seconds/60) ); + } + + [Usage( "RunUOSpawnerExporter" )] + [Aliases( "RSE" )] + [Description( "Convert RunUO Spawners to PremiumSpawners." )] + public static void RunUOSpawnerExporter_OnCommand( CommandEventArgs e ) + { + Map map = e.Mobile.Map; + List list = new List(); + + if ( !Directory.Exists( @".\Data\Monsters\" ) ) + Directory.CreateDirectory( @".\Data\Monsters\" ); + + using ( StreamWriter op = new StreamWriter( String.Format( @".\Data\Monsters\{0}-exported.map", map ) ) ) + { + + if ( map == null || map == Map.Internal ) + { + e.Mobile.SendMessage( "You may not run that command here." ); + return; + } + + e.Mobile.SendMessage( "Converting Spawners..." ); + + op.WriteLine( "#######################################" ); + op.WriteLine( "## Converted By RunUOSpawnerExporter ##" ); + op.WriteLine( "## Developed by Nerun ##" ); + op.WriteLine( "#######################################" ); + + foreach ( Item item in World.Items.Values ) + { + if ( item.Map == map && item.Parent == null && item is Spawner ) + list.Add( item ); + } + + foreach ( Spawner spawner in list ) + { + string mapfinal = ""; + + string walkrange = ""; + + if(map == Map.Maps[0]) + { + mapfinal = "1"; + } + else if(map == Map.Maps[1]) + { + mapfinal = "2"; + } + else if(map == Map.Maps[2]) + { + mapfinal = "3"; + } + else if(map == Map.Maps[3]) + { + mapfinal = "4"; + } + else if(map == Map.Maps[4]) + { + mapfinal = "5"; + } + else + { + mapfinal = "6"; + } + + if( spawner.WalkingRange == -1 ) + { + walkrange = spawner.HomeRange.ToString(); + } + else + { + walkrange = spawner.WalkingRange.ToString(); + } + + int MinDelay = ConvertToInt(spawner.MinDelay); + + if (MinDelay < 1) + { + MinDelay = 1; + } + + int MaxDelay = ConvertToInt(spawner.MaxDelay); + + if (MaxDelay < MinDelay) + { + MaxDelay = MinDelay; + } + + string towrite = "*|"; + + if( spawner.SpawnNames.Count > 0 ) + { + towrite = "*|" + spawner.SpawnNames[0]; + + for ( int i = 1; i < spawner.SpawnNames.Count; ++i ) + { + towrite = towrite + ":" + spawner.SpawnNames[i].ToString(); + } + } + + if ( spawner.SpawnNames.Count > 0 && spawner.Running == true ) + { + op.WriteLine( "{0}||||||{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|1|{9}|0|0|0|0|0", towrite, spawner.X, spawner.Y, spawner.Z, mapfinal, MinDelay, MaxDelay, walkrange, spawner.HomeRange, spawner.Count); + } + + if( spawner.SpawnNames.Count == 0 ) + { + op.WriteLine( "## Void: {0}||||||{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|1|{9}|0|0|0|0|0", towrite, spawner.X, spawner.Y, spawner.Z, mapfinal, MinDelay, MaxDelay, walkrange, spawner.HomeRange, spawner.Count); + } + + if( spawner.SpawnNames.Count > 0 && spawner.Running == false ) + { + op.WriteLine( "## Inactive: {0}||||||{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|1|{9}|0|0|0|0|0", towrite, spawner.X, spawner.Y, spawner.Z, mapfinal, MinDelay, MaxDelay, walkrange, spawner.HomeRange, spawner.Count); + } + } + e.Mobile.SendMessage( String.Format( "You exported {0} RunUO Spawner{1} from this facet.", list.Count, list.Count == 1 ? "" : "s" ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/SpawnEditor.cs b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnEditor.cs new file mode 100644 index 0000000..4951a00 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnEditor.cs @@ -0,0 +1,1069 @@ +///////////////////////////////////// +// SPAWN EDITOR // +// This SpawnEditor is a huge mod // +// of "ZenArcher's SpawnEditor v2" // +// By Nerun // +///////////////////////////////////// +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Regions; +using Server.Commands; + +namespace Server.Gumps +{ + public class SpawnEditorGump : Gump + { + private int m_page; + private ArrayList m_tempList; + public Item m_selSpawner; + + public int page + { + get{ return m_page; } + set{ m_page = value; } + } + + public Item selSpawner + { + get{ return m_selSpawner; } + set{ m_selSpawner = value; } + } + + public ArrayList tempList + { + get{ return m_tempList; } + set{ m_tempList = value; } + } + + public static void Initialize() + { + CommandSystem.Register( "SpawnEditor", AccessLevel.GameMaster, new CommandEventHandler( SpawnEditor_OnCommand ) ); + CommandSystem.Register( "Editor", AccessLevel.GameMaster, new CommandEventHandler( SpawnEditor_OnCommand ) ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + CommandSystem.Register( command, access, handler ); + } + + [Usage( "SpawnEditor" )] + [Aliases( "Editor" )] + [Description( "Used to find and edit spawns" )] + public static void SpawnEditor_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + SpawnEditor_OnCommand( from ); + } + + public static void SpawnEditor_OnCommand( Mobile from ) + { + ArrayList worldList = new ArrayList(); + ArrayList facetList = new ArrayList(); + + Type type = ScriptCompiler.FindTypeByName( "PremiumSpawner", true ); + + if ( type == typeof( Item ) || type.IsSubclassOf( typeof( Item ) ) ) + { + bool isAbstract = type.IsAbstract; + + foreach ( Item item in World.Items.Values ) + { + if ( isAbstract ? item.GetType().IsSubclassOf( type ) : item.GetType() == type ) + worldList.Add( item ); + } + } + + foreach( PremiumSpawner worldSpnr in worldList ) + { + if( worldSpnr.Map == from.Map ) + facetList.Add( worldSpnr ); + } + +//TODO: Sort spawner list + + SpawnEditor_OnCommand( from, 0, facetList ); + } + + public static void SpawnEditor_OnCommand( Mobile from, int page, ArrayList currentList ) + { + SpawnEditor_OnCommand( from, page, currentList, 0 ); + } + + public static void SpawnEditor_OnCommand( Mobile from, int page, ArrayList currentList, int selected ) + { + SpawnEditor_OnCommand( from, page, currentList, selected, null ); + } + + public static void SpawnEditor_OnCommand( Mobile from, int page, ArrayList currentList, int selected, Item selSpawner ) + { + from.SendGump( new SpawnEditorGump( from, page, currentList, selected, selSpawner ) ); + } + + public SpawnEditorGump( Mobile from, int page, ArrayList currentList, int selected, Item spwnr ) : base( 50, 40 ) + { + tempList = new ArrayList(); + Mobile m = from; + m_page = page; + Region r = from.Region; + Map map = from.Map; + int buttony = 60; + int buttonID = 1; + int listnum = 0; + + tempList = currentList; + + selSpawner = spwnr; + + AddPage(0); + + AddBackground( 0, 0, 600, 450, 5054 ); + AddImageTiled( 8, 8, 584, 40, 2624 ); + AddAlphaRegion( 8, 8, 584, 40 ); + AddImageTiled( 8, 50, 250, 396, 2624 ); + AddAlphaRegion( 8, 50, 250, 396 ); + AddImageTiled( 260, 50, 332, 396, 2624 ); + AddAlphaRegion( 260, 50, 332, 396 ); + AddLabel( 220, 20, 52, "PREMIUM SPAWNER EDITOR" ); + AddButton( 550, 405, 0x158A, 0x158B, 10002, GumpButtonType.Reply, 1 ); //Quit Button + AddButton( 275, 412, 0x845, 0x846, 10008, GumpButtonType.Reply, 0 ); + AddLabel( 300, 410, 52, "Refresh" ); + + if( currentList.Count == 0 ) + AddLabel( 50, 210, 52, "No Premium Spawners Found" ); + else + { + if( page == 0 ) + { + if( currentList.Count < 15 ) + listnum = currentList.Count; + else + listnum = 15; + + for( int x = 0; x < listnum; x++ ) + { + Item spawnr = null; + + if( currentList[x] is Item ) + spawnr = currentList[x] as Item; + + string gumpMsg = ""; + + Point3D spawnr3D = new Point3D( ( new Point2D( spawnr.X, spawnr.Y ) ), spawnr.Z ); + Region spawnrRegion = Region.Find( spawnr3D, map ); + + if( spawnrRegion.ToString() == "" ) + gumpMsg = "PremiumSpawner at " + spawnr.X.ToString() + ", " + spawnr.Y.ToString(); + else + gumpMsg = spawnrRegion.ToString(); + + AddButton( 25, buttony, 0x845, 0x846, buttonID, GumpButtonType.Reply, 0 ); + AddLabel( 55, buttony, 52, gumpMsg ); + buttony += 25; + buttonID += 1; + } + } + + else if( page > 0 ) + { + if( currentList.Count < 15 + ( 15 * page ) ) + listnum = currentList.Count; + else + listnum = 15 + ( 15 * page ); + + for( int x = 15 * page; x < listnum; x++ ) + { + Item spawnr = null; + buttonID = x+1; + + if( currentList[x] is Item ) + spawnr = currentList[x] as Item; + + string gumpMsg = ""; + + Point3D spawnr3D = new Point3D( ( new Point2D( spawnr.X, spawnr.Y ) ), spawnr.Z ); + Region spawnrRegion = Region.Find( spawnr3D, map ); + + if( spawnrRegion.ToString() == "" ) + gumpMsg = "PremiumSpawner at " + spawnr.X.ToString() + ", " + spawnr.Y.ToString(); + else + gumpMsg = spawnrRegion.ToString(); + + AddButton( 25, buttony, 0x845, 0x846, buttonID, GumpButtonType.Reply, 0 ); + AddLabel( 55, buttony, 52, gumpMsg ); + buttony += 25; + } + } + } + + if( page == 0 && currentList.Count > 15 ) + AddButton( 450, 20, 0x15E1, 0x15E5, 10000, GumpButtonType.Reply, 0 ); + else if( page > 0 && currentList.Count > 15 + ( page * 15 ) ) + AddButton( 450, 20, 0x15E1, 0x15E5, 10000, GumpButtonType.Reply, 0 ); + + if( page != 0 ) + AddButton( 150, 20, 0x15E3, 0x15E7, 10001, GumpButtonType.Reply, 0 ); + + int pageNum = (int)currentList.Count / 15; + int rem = currentList.Count % 15; + int totPages = 0; + + string stotPages = ""; + + if( rem > 0 ) + { + totPages = pageNum + 1; + stotPages = totPages.ToString(); + } + else + stotPages = pageNum.ToString(); + + string pageText = "Page " + ( page + 1 ) + " of " + stotPages; + + AddLabel( 40, 20, 52, pageText ); + + if( selected == 0 ) + InitializeStartingRightPanel(); + else if( selected == 1 ) + InitializeSelectedRightPanel(); + } + + public void InitializeStartingRightPanel() + { + AddLabel( 275, 65, 52, "Filter to current region only" ); + AddButton( 500, 65, 0x15E1, 0x15E5, 10003, GumpButtonType.Reply, 0 ); + + AddTextField( 275, 140, 50, 20, 0 ); + AddLabel( 275, 115, 52, "Filter by Distance" ); + AddButton( 500, 115, 0x15E1, 0x15E5, 10004, GumpButtonType.Reply, 0 ); + + AddTextField( 275, 190, 120, 20, 1 ); + AddLabel( 275, 165, 52, "Search Spawners by Creature" ); + AddButton( 500, 165, 0x15E1, 0x15E5, 10009, GumpButtonType.Reply, 0 ); + + AddTextField( 275, 240, 50, 20, 2 ); + AddLabel( 275, 215, 52, "Search Spawners by SpawnID" ); + AddButton( 500, 215, 0x15E1, 0x15E5, 10010, GumpButtonType.Reply, 0 ); + } + + public void InitializeSelectedRightPanel() + { + string spX = selSpawner.X.ToString(); + string spY = selSpawner.Y.ToString(); + string spnText = "PremiumSpawner at " + spX + ", " + spY; + + AddLabel( 350, 65, 52, spnText ); + + PremiumSpawner initSpn = selSpawner as PremiumSpawner; + int strNum = 0; + string spns = "Containing: "; + string spnsNEW = ""; + string spns1 = ""; + string spns2 = ""; + string spns3 = ""; + + for( int i = 0; i < initSpn.CreaturesName.Count; i++ ) + { + if( strNum == 0 ) + { + if( i < initSpn.CreaturesName.Count - 1 ) + { + if( spns.Length + initSpn.CreaturesName[i].ToString().Length < 50 ) + spnsNEW += (string)initSpn.CreaturesName[i] + ", "; + else + { + strNum = 1; + spns1 += (string)initSpn.CreaturesName[i] + ", "; + } + } + else + spnsNEW += (string)initSpn.CreaturesName[i]; + } + else if( strNum == 1 ) + { + if( i < initSpn.CreaturesName.Count - 1 ) + { + if( spns1.Length + initSpn.CreaturesName[i].ToString().Length < 50 ) + spns1 += (string)initSpn.CreaturesName[i] + ", "; + else + { + strNum = 2; + spns2 += (string)initSpn.CreaturesName[i] + ", "; + } + } + else + { + if( spns1.Length + initSpn.CreaturesName[i].ToString().Length < 50 ) + spns1 += (string)initSpn.CreaturesName[i]; + else + { + strNum = 3; + spns2 += (string)initSpn.CreaturesName[i]; + } + } + } + else if( strNum == 2 ) + { + if( i < initSpn.CreaturesName.Count - 1 ) + { + if( spns2.Length + initSpn.CreaturesName[i].ToString().Length < 50 ) + spns2 += (string)initSpn.CreaturesName[i] + ", "; + else + { + strNum = 3; + spns3 += (string)initSpn.CreaturesName[i] + ", "; + } + } + else + { + if( spns2.Length + initSpn.CreaturesName[i].ToString().Length < 50 ) + spns2 += (string)initSpn.CreaturesName[i]; + else + { + strNum = 4; + spns3 += (string)initSpn.CreaturesName[i]; + } + } + } + else if( strNum == 3 ) + { + if( i < initSpn.CreaturesName.Count - 1 ) + spns3 += (string)initSpn.CreaturesName[i] + ", "; + else + spns3 += (string)initSpn.CreaturesName[i]; + } + } + + string spnsNEWa = ""; + string spns1a = ""; + string spns2a = ""; + string spns3a = ""; + + for( int i = 0; i < initSpn.SubSpawnerA.Count; i++ ) + { + if( strNum == 0 ) + { + if( i < initSpn.SubSpawnerA.Count - 1 ) + { + if( spns.Length + initSpn.SubSpawnerA[i].ToString().Length < 50 ) + spnsNEWa += (string)initSpn.SubSpawnerA[i] + ", "; + else + { + strNum = 1; + spns1a += (string)initSpn.SubSpawnerA[i] + ", "; + } + } + else + spnsNEWa += (string)initSpn.SubSpawnerA[i]; + } + else if( strNum == 1 ) + { + if( i < initSpn.SubSpawnerA.Count - 1 ) + { + if( spns1a.Length + initSpn.SubSpawnerA[i].ToString().Length < 50 ) + spns1a += (string)initSpn.SubSpawnerA[i] + ", "; + else + { + strNum = 2; + spns2a += (string)initSpn.SubSpawnerA[i] + ", "; + } + } + else + { + if( spns1a.Length + initSpn.SubSpawnerA[i].ToString().Length < 50 ) + spns1a += (string)initSpn.SubSpawnerA[i]; + else + { + strNum = 3; + spns2a += (string)initSpn.SubSpawnerA[i]; + } + } + } + else if( strNum == 2 ) + { + if( i < initSpn.SubSpawnerA.Count - 1 ) + { + if( spns2a.Length + initSpn.SubSpawnerA[i].ToString().Length < 50 ) + spns2a += (string)initSpn.SubSpawnerA[i] + ", "; + else + { + strNum = 3; + spns3a += (string)initSpn.SubSpawnerA[i] + ", "; + } + } + else + { + if( spns2a.Length + initSpn.SubSpawnerA[i].ToString().Length < 50 ) + spns2a += (string)initSpn.SubSpawnerA[i]; + else + { + strNum = 4; + spns3a += (string)initSpn.SubSpawnerA[i]; + } + } + } + else if( strNum == 3 ) + { + if( i < initSpn.SubSpawnerA.Count - 1 ) + spns3a += (string)initSpn.SubSpawnerA[i] + ", "; + else + spns3a += (string)initSpn.SubSpawnerA[i]; + } + } + + string spnsNEWb = ""; + string spns1b = ""; + string spns2b = ""; + string spns3b = ""; + + for( int i = 0; i < initSpn.SubSpawnerB.Count; i++ ) + { + if( strNum == 0 ) + { + if( i < initSpn.SubSpawnerB.Count - 1 ) + { + if( spns.Length + initSpn.SubSpawnerB[i].ToString().Length < 50 ) + spnsNEWb += (string)initSpn.SubSpawnerB[i] + ", "; + else + { + strNum = 1; + spns1b += (string)initSpn.SubSpawnerB[i] + ", "; + } + } + else + spnsNEWb += (string)initSpn.SubSpawnerB[i]; + } + else if( strNum == 1 ) + { + if( i < initSpn.SubSpawnerB.Count - 1 ) + { + if( spns1b.Length + initSpn.SubSpawnerB[i].ToString().Length < 50 ) + spns1b += (string)initSpn.SubSpawnerB[i] + ", "; + else + { + strNum = 2; + spns2b += (string)initSpn.SubSpawnerB[i] + ", "; + } + } + else + { + if( spns1b.Length + initSpn.SubSpawnerB[i].ToString().Length < 50 ) + spns1b += (string)initSpn.SubSpawnerB[i]; + else + { + strNum = 3; + spns2b += (string)initSpn.SubSpawnerB[i]; + } + } + } + else if( strNum == 2 ) + { + if( i < initSpn.SubSpawnerB.Count - 1 ) + { + if( spns2b.Length + initSpn.SubSpawnerB[i].ToString().Length < 50 ) + spns2b += (string)initSpn.SubSpawnerB[i] + ", "; + else + { + strNum = 3; + spns3b += (string)initSpn.SubSpawnerB[i] + ", "; + } + } + else + { + if( spns2b.Length + initSpn.SubSpawnerB[i].ToString().Length < 50 ) + spns2b += (string)initSpn.SubSpawnerB[i]; + else + { + strNum = 4; + spns3b += (string)initSpn.SubSpawnerB[i]; + } + } + } + else if( strNum == 3 ) + { + if( i < initSpn.SubSpawnerB.Count - 1 ) + spns3b += (string)initSpn.SubSpawnerB[i] + ", "; + else + spns3b += (string)initSpn.SubSpawnerB[i]; + } + } + + string spnsNEWc = ""; + string spns1c = ""; + string spns2c = ""; + string spns3c = ""; + + for( int i = 0; i < initSpn.SubSpawnerC.Count; i++ ) + { + if( strNum == 0 ) + { + if( i < initSpn.SubSpawnerC.Count - 1 ) + { + if( spns.Length + initSpn.SubSpawnerC[i].ToString().Length < 50 ) + spnsNEWc += (string)initSpn.SubSpawnerC[i] + ", "; + else + { + strNum = 1; + spns1c += (string)initSpn.SubSpawnerC[i] + ", "; + } + } + else + spnsNEWc += (string)initSpn.SubSpawnerC[i]; + } + else if( strNum == 1 ) + { + if( i < initSpn.SubSpawnerC.Count - 1 ) + { + if( spns1c.Length + initSpn.SubSpawnerC[i].ToString().Length < 50 ) + spns1c += (string)initSpn.SubSpawnerC[i] + ", "; + else + { + strNum = 2; + spns2c += (string)initSpn.SubSpawnerC[i] + ", "; + } + } + else + { + if( spns1c.Length + initSpn.SubSpawnerC[i].ToString().Length < 50 ) + spns1c += (string)initSpn.SubSpawnerC[i]; + else + { + strNum = 3; + spns2c += (string)initSpn.SubSpawnerC[i]; + } + } + } + else if( strNum == 2 ) + { + if( i < initSpn.SubSpawnerC.Count - 1 ) + { + if( spns2c.Length + initSpn.SubSpawnerC[i].ToString().Length < 50 ) + spns2c += (string)initSpn.SubSpawnerC[i] + ", "; + else + { + strNum = 3; + spns3c += (string)initSpn.SubSpawnerC[i] + ", "; + } + } + else + { + if( spns2c.Length + initSpn.SubSpawnerC[i].ToString().Length < 50 ) + spns2c += (string)initSpn.SubSpawnerC[i]; + else + { + strNum = 4; + spns3c += (string)initSpn.SubSpawnerC[i]; + } + } + } + else if( strNum == 3 ) + { + if( i < initSpn.SubSpawnerC.Count - 1 ) + spns3c += (string)initSpn.SubSpawnerC[i] + ", "; + else + spns3c += (string)initSpn.SubSpawnerC[i]; + } + } + + string spnsNEWd = ""; + string spns1d = ""; + string spns2d = ""; + string spns3d = ""; + + for( int i = 0; i < initSpn.SubSpawnerD.Count; i++ ) + { + if( strNum == 0 ) + { + if( i < initSpn.SubSpawnerD.Count - 1 ) + { + if( spns.Length + initSpn.SubSpawnerD[i].ToString().Length < 50 ) + spnsNEWd += (string)initSpn.SubSpawnerD[i] + ", "; + else + { + strNum = 1; + spns1d += (string)initSpn.SubSpawnerD[i] + ", "; + } + } + else + spnsNEWd += (string)initSpn.SubSpawnerD[i]; + } + else if( strNum == 1 ) + { + if( i < initSpn.SubSpawnerD.Count - 1 ) + { + if( spns1d.Length + initSpn.SubSpawnerD[i].ToString().Length < 50 ) + spns1d += (string)initSpn.SubSpawnerD[i] + ", "; + else + { + strNum = 2; + spns2d += (string)initSpn.SubSpawnerD[i] + ", "; + } + } + else + { + if( spns1d.Length + initSpn.SubSpawnerD[i].ToString().Length < 50 ) + spns1d += (string)initSpn.SubSpawnerD[i]; + else + { + strNum = 3; + spns2d += (string)initSpn.SubSpawnerD[i]; + } + } + } + else if( strNum == 2 ) + { + if( i < initSpn.SubSpawnerD.Count - 1 ) + { + if( spns2d.Length + initSpn.SubSpawnerD[i].ToString().Length < 50 ) + spns2d += (string)initSpn.SubSpawnerD[i] + ", "; + else + { + strNum = 3; + spns3d += (string)initSpn.SubSpawnerD[i] + ", "; + } + } + else + { + if( spns2d.Length + initSpn.SubSpawnerD[i].ToString().Length < 50 ) + spns2d += (string)initSpn.SubSpawnerD[i]; + else + { + strNum = 4; + spns3d += (string)initSpn.SubSpawnerD[i]; + } + } + } + else if( strNum == 3 ) + { + if( i < initSpn.SubSpawnerD.Count - 1 ) + spns3d += (string)initSpn.SubSpawnerD[i] + ", "; + else + spns3d += (string)initSpn.SubSpawnerD[i]; + } + } + + string spnsNEWe = ""; + string spns1e = ""; + string spns2e = ""; + string spns3e = ""; + + for( int i = 0; i < initSpn.SubSpawnerE.Count; i++ ) + { + if( strNum == 0 ) + { + if( i < initSpn.SubSpawnerE.Count - 1 ) + { + if( spns.Length + initSpn.SubSpawnerE[i].ToString().Length < 50 ) + spnsNEWe += (string)initSpn.SubSpawnerE[i] + ", "; + else + { + strNum = 1; + spns1e += (string)initSpn.SubSpawnerE[i] + ", "; + } + } + else + spnsNEWe += (string)initSpn.SubSpawnerE[i]; + } + else if( strNum == 1 ) + { + if( i < initSpn.SubSpawnerE.Count - 1 ) + { + if( spns1e.Length + initSpn.SubSpawnerE[i].ToString().Length < 50 ) + spns1e += (string)initSpn.SubSpawnerE[i] + ", "; + else + { + strNum = 2; + spns2e += (string)initSpn.SubSpawnerE[i] + ", "; + } + } + else + { + if( spns1e.Length + initSpn.SubSpawnerE[i].ToString().Length < 50 ) + spns1e += (string)initSpn.SubSpawnerE[i]; + else + { + strNum = 3; + spns2e += (string)initSpn.SubSpawnerE[i]; + } + } + } + else if( strNum == 2 ) + { + if( i < initSpn.SubSpawnerE.Count - 1 ) + { + if( spns2e.Length + initSpn.SubSpawnerE[i].ToString().Length < 50 ) + spns2e += (string)initSpn.SubSpawnerE[i] + ", "; + else + { + strNum = 3; + spns3e += (string)initSpn.SubSpawnerE[i] + ", "; + } + } + else + { + if( spns2e.Length + initSpn.SubSpawnerE[i].ToString().Length < 50 ) + spns2e += (string)initSpn.SubSpawnerE[i]; + else + { + strNum = 4; + spns3e += (string)initSpn.SubSpawnerE[i]; + } + } + } + else if( strNum == 3 ) + { + if( i < initSpn.SubSpawnerE.Count - 1 ) + spns3e += (string)initSpn.SubSpawnerE[i] + ", "; + else + spns3e += (string)initSpn.SubSpawnerE[i]; + } + } + + AddLabel( 275, 85, 52, spns ); + AddLabel( 280, 110, 52, "[1]" ); + AddLabel( 280, 180, 52, "[2]" ); + AddLabel( 280, 250, 52, "[3]" ); + AddLabel( 425, 110, 52, "[4]" ); + AddLabel( 425, 180, 52, "[5]" ); + AddLabel( 425, 250, 52, "[6]" ); + AddHtml( 300, 110, 115, 65, spnsNEW, true, true ); + AddHtml( 300, 180, 115, 65, spnsNEWa, true, true ); + AddHtml( 300, 250, 115, 65, spnsNEWb, true, true ); + AddHtml( 445, 110, 115, 65, spnsNEWc, true, true ); + AddHtml( 445, 180, 115, 65, spnsNEWd, true, true ); + AddHtml( 445, 250, 115, 65, spnsNEWe, true, true ); + if( spns1 != "" ) + AddLabel( 275, 105, 200, spns1 ); + + if( spns2 != "" ) + AddLabel( 275, 125, 200, spns2 ); + + if( spns3 != "" ) + AddLabel( 275, 145, 200, spns3 ); + + AddLabel( 320, 320, 52, "Go to Spawner" ); + AddButton( 525, 320, 0x15E1, 0x15E5, 10005, GumpButtonType.Reply, 1 ); + AddLabel( 320, 345, 52, "Delete Selected Spawner" ); + AddButton( 525, 345, 0x15E1, 0x15E5, 10006, GumpButtonType.Reply, 0 ); + AddLabel( 320, 370, 52, "Edit Spawns" ); + AddButton( 525, 370, 0x15E1, 0x15E5, 10007, GumpButtonType.Reply, 0 ); + } + + public List CreateArray( RelayInfo info, Mobile from ) + { + List creaturesName = new List(); + + for ( int i = 0; i < 13; i++ ) + { + TextRelay te = info.GetTextEntry( i ); + + if ( te != null ) + { + string str = te.Text; + + if ( str.Length > 0 ) + { + str = str.Trim(); + + Type type = SpawnerType.GetType( str ); + + if ( type != null ) + creaturesName.Add( str ); + else + AddLabel( 70, 230, 39, "Invalid Search String" ); + } + } + } + + return creaturesName; + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + int buttonNum = 0; + ArrayList currentList = new ArrayList( tempList ); + int page = m_page; + + if( info.ButtonID > 0 && info.ButtonID < 10000 ) + buttonNum = 1; + else if( info.ButtonID > 20004 ) + buttonNum = 30000; + else + buttonNum = info.ButtonID; + + switch( buttonNum ) + { + case 0: + { + //Close + break; + } + case 1: + { + selSpawner = currentList[ info.ButtonID - 1 ] as Item; + SpawnEditor_OnCommand( from, page, currentList, 1, selSpawner ); + break; + } + case 10000: + { + if( m_page * 10 < currentList.Count ) + { + page = m_page += 1; + SpawnEditor_OnCommand( from, page, currentList ); + } + break; + } + case 10001: + { + if( m_page != 0 ) + { + page = m_page -= 1; + SpawnEditor_OnCommand( from, page, currentList ); + } + break; + } + case 10002: + { + //Close + break; + } + case 10003: + { + FilterByRegion( from, tempList, from.Region, from.Map, page ); + break; + } + case 10004: + { + TextRelay oDis = info.GetTextEntry( 0 ); + string sDis = ( oDis == null ? "" : oDis.Text.Trim() ); + if( sDis != "" ) + { + try + { + int distance = Convert.ToInt32( sDis ); + FilterByDistance( tempList, from, distance, page ); } + catch + { + from.SendMessage( "Distance must be a number" ); + SpawnEditor_OnCommand( from, page, currentList ); + } + } + else + { + from.SendMessage( "You must specify a distance" ); + SpawnEditor_OnCommand( from, page, currentList ); + } + break; + } + case 10005: + { + from.Location = new Point3D( selSpawner.X, selSpawner.Y, selSpawner.Z ); + SpawnEditor_OnCommand( from, page, currentList, 1, selSpawner ); + break; + } + case 10006: + { + selSpawner.Delete(); + SpawnEditor_OnCommand( from ); + break; + } + case 10007: + { + from.SendGump( new PremiumSpawnerGump( selSpawner as PremiumSpawner ) ); + SpawnEditor_OnCommand( from, page, currentList, 1, selSpawner ); + break; + } + case 10008: + { + SpawnEditor_OnCommand( from ); + break; + } + case 10009: + { + TextRelay oSearch = info.GetTextEntry( 1 ); + string sSearch = ( oSearch == null ? null : oSearch.Text.Trim() ); + SearchByName( tempList, from, sSearch, page ); + break; + } + case 10010: + { + TextRelay oID = info.GetTextEntry( 2 ); + string sID = ( oID == null ? "" : oID.Text.Trim() ); + if( sID != "" ) + { + try + { + int SearchID = Convert.ToInt32( sID ); + SearchByID( tempList, from, SearchID, page ); } + catch + { + from.SendMessage( "SpawnID must be a number" ); + SpawnEditor_OnCommand( from, page, currentList ); + } + } + else + { + from.SendMessage( "You must specify a SpawnID" ); + SpawnEditor_OnCommand( from, page, currentList ); + } + break; + } + case 20000: + { + PremiumSpawner spawner = selSpawner as PremiumSpawner; + spawner.CreaturesName = CreateArray( info, state.Mobile ); + break; + } + case 20001: + { + PremiumSpawner spawner = selSpawner as PremiumSpawner; + SpawnEditor_OnCommand( from, page, currentList, 2, selSpawner ); + spawner.BringToHome(); + break; + } + case 20002: + { + PremiumSpawner spawner = selSpawner as PremiumSpawner; + SpawnEditor_OnCommand( from, page, currentList, 2, selSpawner ); + spawner.Respawn(); + break; + } + case 20003: + { + PremiumSpawner spawner = selSpawner as PremiumSpawner; + SpawnEditor_OnCommand( from, page, currentList, 2, selSpawner ); + state.Mobile.SendGump( new PropertiesGump( state.Mobile, spawner ) ); + break; + } + case 30000: + { + int buttonID = info.ButtonID - 20004; + int index = buttonID / 2; + int type = buttonID % 2; + + PremiumSpawner spawner = selSpawner as PremiumSpawner; + + TextRelay entry = info.GetTextEntry( index ); + + if ( entry != null && entry.Text.Length > 0 ) + { + if ( type == 0 ) // Spawn creature + spawner.Spawn( entry.Text ); + else // Remove creatures + spawner.RemoveCreatures( entry.Text ); + //spawner.RemoveCreaturesA( entry.Text ); + + spawner.CreaturesName = CreateArray( info, state.Mobile ); + } + + break; + } + } + } + + + public static void FilterByRegion( Mobile from, ArrayList facetList, Region regr, Map regmap, int page ) + { + ArrayList filregList = new ArrayList(); + + foreach( Item regItem in facetList ) + { + Point2D p2 = new Point2D( regItem.X, regItem.Y ); + Point3D p = new Point3D( p2, regItem.Z ); + + if( Region.Find( p, regmap ) == regr ) + filregList.Add( regItem ); + } + + from.SendGump( new SpawnEditorGump( from, 0, filregList, 0, null ) ); + } + + public static void FilterByDistance( ArrayList currentList, Mobile m, int dis, int page ) + { + ArrayList fildisList = new ArrayList(); + + for( int z = 0; z < currentList.Count; z ++ ) + { + Item disItem = currentList[z] as Item; + + if( disItem.X >= m.X - dis && disItem.X <= m.X + dis && disItem.Y >= m.Y - dis && disItem.Y <= m.Y + dis ) + fildisList.Add( disItem ); + } + + m.SendGump( new SpawnEditorGump( m, 0, fildisList, 0, null ) ); + } + + public static void SearchByName( ArrayList currentList, Mobile from, string search, int page ) + { + ArrayList searchList = new ArrayList(); + + foreach( PremiumSpawner spn in currentList ) + { + foreach( string str in spn.CreaturesName ) + { + if( str.ToLower().IndexOf( search ) >= 0 ) + searchList.Add( spn ); + } + + foreach( string str in spn.SubSpawnerA ) + { + if( str.ToLower().IndexOf( search ) >= 0 ) + searchList.Add( spn ); + } + + foreach( string str in spn.SubSpawnerB ) + { + if( str.ToLower().IndexOf( search ) >= 0 ) + searchList.Add( spn ); + } + + foreach( string str in spn.SubSpawnerC ) + { + if( str.ToLower().IndexOf( search ) >= 0 ) + searchList.Add( spn ); + } + + foreach( string str in spn.SubSpawnerD ) + { + if( str.ToLower().IndexOf( search ) >= 0 ) + searchList.Add( spn ); + } + + foreach( string str in spn.SubSpawnerE ) + { + if( str.ToLower().IndexOf( search ) >= 0 ) + searchList.Add( spn ); + } + } + + from.SendGump( new SpawnEditorGump( from, 0, searchList, 0, null ) ); + } + + public static void SearchByID( ArrayList currentList, Mobile from, int SearchID, int page ) + { + ArrayList searchList = new ArrayList(); + + foreach( PremiumSpawner spn in currentList ) + { + if ( ((PremiumSpawner)spn).SpawnID == SearchID ) + { + searchList.Add( spn ); + } + } + + from.SendGump( new SpawnEditorGump( from, 0, searchList, 0, null ) ); + } + + public void AddTextField( int x, int y, int width, int height, int index ) + { + AddBackground( x - 2, y - 2, width + 4, height + 4, 0x2486 ); + AddTextEntry( x + 2, y + 2, width - 4, height - 4, 0, index, "" ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/SpawnGen.cs b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnGen.cs new file mode 100644 index 0000000..510f975 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnGen.cs @@ -0,0 +1,643 @@ +//Engine r55 +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.Commands; +using Server.Regions; + + +namespace Server +{ + public class SpawnGenerator + { + private static int m_Count; + private static int m_MapOverride = -1; + private static int m_IDOverride = -1; + private static double m_MinTimeOverride = -1; + private static double m_MaxTimeOverride = -1; + private const bool TotalRespawn = true; + private const int Team = 0; + + public static void Initialize() + { + CommandSystem.Register( "SpawnGen", AccessLevel.Administrator, new CommandEventHandler( SpawnGen_OnCommand ) ); + } + + [Usage( "SpawnGen []|[unload ]|[remove |]|[save |][savebyhand][cleanfacet]" )] + [Description( "Complex command, it generate and remove spawners." )] + private static void SpawnGen_OnCommand( CommandEventArgs e ) + { + //wrog use + if ( e.ArgString == null || e.ArgString == "" ) + { + e.Mobile.SendMessage( "Usage: SpawnGen []|[remove ||]|[save ||]" ); + } + //[spawngen remove and [spawngen remove region + else if ( e.Arguments[0].ToLower() == "remove" && e.Arguments.Length == 2 ) + { + Remove( e.Mobile, e.Arguments[1].ToLower() ); + } + //[spawngen remove x1 y1 x2 y2 + else if ( e.Arguments[0].ToLower() == "remove" && e.Arguments.Length == 5 ) + { + int x1 = Utility.ToInt32( e.Arguments[1] ); + int y1 = Utility.ToInt32( e.Arguments[2] ); + int x2 = Utility.ToInt32( e.Arguments[3] ); + int y2 = Utility.ToInt32( e.Arguments[4] ); + RemoveByCoord( e.Mobile, x1, y1, x2, y2 ); + } + //[spawngen remove + else if ( e.ArgString.ToLower() == "remove" ) + { + Remove( e.Mobile, "" ); + } + //[spawngen save and [spawngen save region + else if ( e.Arguments[0].ToLower() == "save" && e.Arguments.Length == 2 ) + { + Save( e.Mobile, e.Arguments[1].ToLower() ); + } + //[spawngen unload SpawnID + else if ( e.Arguments[0].ToLower() == "unload" && e.Arguments.Length == 2 ) + { + int ID = Utility.ToInt32( e.Arguments[1] ); + Unload( ID ); + } + //[spawngen savebyhand + else if ( e.Arguments[0].ToLower() == "savebyhand" ) + { + SaveByHand(); + } + //[spawngen cleanfacet + else if ( e.Arguments[0].ToLower() == "cleanfacet" ) + { + CleanFacet( e.Mobile ); + } + ////[spawngen save x1 y1 x2 y2 + else if ( e.Arguments[0].ToLower() == "save" && e.Arguments.Length == 5 ) + { + int x1 = Utility.ToInt32( e.Arguments[1] ); + int y1 = Utility.ToInt32( e.Arguments[2] ); + int x2 = Utility.ToInt32( e.Arguments[3] ); + int y2 = Utility.ToInt32( e.Arguments[4] ); + SaveByCoord( e.Mobile, x1, y1, x2, y2 ); + } + //[spawngen save + else if ( e.ArgString.ToLower() == "save" ) + { + Save( e.Mobile, "" ); + } + else + { + Parse( e.Mobile, e.ArgString ); + } + } + + public static void Talk( string alfa ) + { + World.Broadcast( 0x35, true, "Spawns are being {0}, please wait.", alfa ); + } + + public static string GetRegion(Item item) + { + Region re = Region.Find(item.Location, item.Map); + string regname = re.ToString().ToLower(); + return regname; + } + + //[spawngen remove and [spawngen remove region + private static void Remove( Mobile from, string region ) + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + + string prefix = Server.Commands.CommandSystem.Prefix; + + if( region == null || region == "" ) + { + CommandSystem.Handle( from, String.Format( "{0}Global remove where premiumspawner", prefix ) ); + } + else + { + foreach( Item itemdel in World.Items.Values ) + { + if( itemdel is PremiumSpawner && itemdel.Map == from.Map ) + { + if( GetRegion(itemdel) == region ) + { + itemtodo.Add(itemdel); + count += 1; + } + } + } + + GenericRemove( itemtodo, count, aTime); + } + } + + //[spawngen unload SpawnID + private static void Unload( int ID ) + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + + foreach ( Item itemremove in World.Items.Values ) + { + if ( itemremove is PremiumSpawner && ((PremiumSpawner)itemremove).SpawnID == ID ) + { + itemtodo.Add( itemremove ); + count +=1; + } + } + + GenericRemove( itemtodo, count, aTime); + } + + //[spawngen remove x1 y1 x2 y2 + private static void RemoveByCoord( Mobile from, int x1, int y1, int x2, int y2 ) + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + + foreach ( Item itemremove in World.Items.Values ) + { + if ( itemremove is PremiumSpawner && ( ( itemremove.X >= x1 && itemremove.X <= x2 ) && ( itemremove.Y >= y1 && itemremove.Y <= y2 ) && itemremove.Map == from.Map ) ) + { + itemtodo.Add( itemremove ); + count +=1; + } + } + + GenericRemove( itemtodo, count, aTime); + } + + //[spawngen cleanfacet + //this is the old [SpawnRem + public static void CleanFacet( Mobile from ) + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + + foreach ( Item itemremove in World.Items.Values ) + { + if ( itemremove is PremiumSpawner && itemremove.Map == from.Map && itemremove.Parent == null ) + { + itemtodo.Add( itemremove ); + count +=1; + } + } + + GenericRemove( itemtodo, count, aTime); + } + + private static void GenericRemove( List colecao, int count, DateTime aTime ) + { + if( colecao.Count == 0 ) + { + World.Broadcast( 0x35, true, "There are no PremiumSpawners to be removed." ); + } + else + { + Talk("removed"); + + foreach ( Item item in colecao ) + { + item.Delete(); + } + + DateTime bTime = DateTime.Now; + World.Broadcast( 0x35, true, "{0} PremiumSpawners have been removed in {1:F1} seconds.", count, (bTime - aTime).TotalSeconds ); + } + } + + //[spawngen save and [spawngen save region + private static void Save( Mobile from, string region ) + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + string mapanome = region; + + if( region == "" ) + mapanome = "Spawns"; + + foreach ( Item itemsave in World.Items.Values ) + { + if ( itemsave is PremiumSpawner && ( region == null || region == "" ) ) + { + itemtodo.Add( itemsave ); + count +=1; + } + + else if ( itemsave is PremiumSpawner && itemsave.Map == from.Map ) + { + if ( GetRegion(itemsave) == region ) + { + itemtodo.Add( itemsave ); + count += 1; + } + } + } + + GenericSave( itemtodo, mapanome, count, aTime ); + } + + //[spawngen SaveByHand + private static void SaveByHand() + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + string mapanome = "SpawnsByHand"; + + foreach ( Item itemsave in World.Items.Values ) + { + if ( itemsave is PremiumSpawner && ((PremiumSpawner)itemsave).SpawnID == 1 ) + { + itemtodo.Add( itemsave ); + count +=1; + } + } + + GenericSave( itemtodo, mapanome, count, aTime ); + } + + //[spawngen save x1 y1 x2 y2 + private static void SaveByCoord( Mobile from, int x1, int y1, int x2, int y2 ) + { + DateTime aTime = DateTime.Now; + int count = 0; + List itemtodo = new List(); + string mapanome = "SpawnsByCoords"; + + foreach ( Item itemsave in World.Items.Values ) + { + if ( itemsave is PremiumSpawner && ( ( itemsave.X >= x1 && itemsave.X <= x2 ) && ( itemsave.Y >= y1 && itemsave.Y <= y2 ) && itemsave.Map == from.Map ) ) + { + itemtodo.Add( itemsave ); + count +=1; + } + } + + GenericSave( itemtodo, mapanome, count, aTime ); + } + + private static void GenericSave( List colecao, string mapa, int count, DateTime startTime ) + { + List itemssave = new List( colecao ); + string mapanome = mapa; + + if( itemssave.Count == 0 ) + { + World.Broadcast( 0x35, true, "There are no PremiumSpawners to be saved." ); + } + else + { + Talk("saved"); + + if ( !Directory.Exists( "Data/Monsters" ) ) + Directory.CreateDirectory( "Data/Monsters" ); + + string escreva = "Data/Monsters/" + mapanome + ".map"; + + using ( StreamWriter op = new StreamWriter( escreva ) ) + { + foreach ( PremiumSpawner itemsave2 in itemssave ) + { + int mapnumber = 0; + switch ( itemsave2.Map.ToString() ) + { + case "Felucca": + mapnumber = 1; + break; + case "Trammel": + mapnumber = 2; + break; + case "Ilshenar": + mapnumber = 3; + break; + case "Malas": + mapnumber = 4; + break; + case "Tokuno": + mapnumber = 5; + break; + case "TerMur": + mapnumber = 6; + break; + default: + mapnumber = 7; + Console.WriteLine( "Monster Parser: Warning, unknown map {0}", itemsave2.Map ); + break; + } + + string timer1a = itemsave2.MinDelay.ToString(); + string[] timer1b = timer1a.Split( ':' ); //Broke the string hh:mm:ss in an array (hh, mm, ss) + int timer1c = ( Utility.ToInt32( timer1b[0] ) * 60 ) + Utility.ToInt32( timer1b[1] ); //multiply hh * 60 to find mm, then add mm + string timer1d = timer1c.ToString(); + if ( Utility.ToInt32( timer1b[0] ) == 0 && Utility.ToInt32( timer1b[1] ) == 0 ) //If hh and mm are 0, use seconds, else drop ss + timer1d = Utility.ToInt32( timer1b[2] ) + "s"; + + string timer2a = itemsave2.MaxDelay.ToString(); + string[] timer2b = timer2a.Split( ':' ); + int timer2c = ( Utility.ToInt32( timer2b[0] ) * 60 ) + Utility.ToInt32( timer2b[1] ); + string timer2d = timer2c.ToString(); + if ( Utility.ToInt32( timer2b[0] ) == 0 && Utility.ToInt32( timer2b[1] ) == 0 ) + timer2d = Utility.ToInt32( timer2b[2] ) + "s"; + + string towrite = ""; + string towriteA = ""; + string towriteB = ""; + string towriteC = ""; + string towriteD = ""; + string towriteE = ""; + + if ( itemsave2.CreaturesName.Count > 0 ) + towrite = itemsave2.CreaturesName[0].ToString(); + + if ( itemsave2.SubSpawnerA.Count > 0 ) + towriteA = itemsave2.SubSpawnerA[0].ToString(); + + if ( itemsave2.SubSpawnerB.Count > 0 ) + towriteB = itemsave2.SubSpawnerB[0].ToString(); + + if ( itemsave2.SubSpawnerC.Count > 0 ) + towriteC = itemsave2.SubSpawnerC[0].ToString(); + + if ( itemsave2.SubSpawnerD.Count > 0 ) + towriteD = itemsave2.SubSpawnerD[0].ToString(); + + if ( itemsave2.SubSpawnerE.Count > 0 ) + towriteE = itemsave2.SubSpawnerE[0].ToString(); + + for ( int i = 1; i < itemsave2.CreaturesName.Count; ++i ) + { + if ( itemsave2.CreaturesName.Count > 0 ) + towrite = towrite + ":" + itemsave2.CreaturesName[i].ToString(); + } + + for ( int i = 1; i < itemsave2.SubSpawnerA.Count; ++i ) + { + if ( itemsave2.SubSpawnerA.Count > 0 ) + towriteA = towriteA + ":" + itemsave2.SubSpawnerA[i].ToString(); + } + + for ( int i = 1; i < itemsave2.SubSpawnerB.Count; ++i ) + { + if ( itemsave2.SubSpawnerB.Count > 0 ) + towriteB = towriteB + ":" + itemsave2.SubSpawnerB[i].ToString(); + } + + for ( int i = 1; i < itemsave2.SubSpawnerC.Count; ++i ) + { + if ( itemsave2.SubSpawnerC.Count > 0 ) + towriteC = towriteC + ":" + itemsave2.SubSpawnerC[i].ToString(); + } + + for ( int i = 1; i < itemsave2.SubSpawnerD.Count; ++i ) + { + if ( itemsave2.SubSpawnerD.Count > 0 ) + towriteD = towriteD + ":" + itemsave2.SubSpawnerD[i].ToString(); + } + + for ( int i = 1; i < itemsave2.SubSpawnerE.Count; ++i ) + { + if ( itemsave2.SubSpawnerE.Count > 0 ) + towriteE = towriteE + ":" + itemsave2.SubSpawnerE[i].ToString(); + } + + op.WriteLine( "*|{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|{9}|{10}|{11}|{12}|{13}|{14}|{15}|{16}|{17}|{18}|{19}|{20}", towrite, towriteA, towriteB, towriteC, towriteD, towriteE, itemsave2.X, itemsave2.Y, itemsave2.Z, mapnumber, timer1d, timer2d, itemsave2.WalkingRange, itemsave2.HomeRange, itemsave2.SpawnID, itemsave2.Count, itemsave2.CountA, itemsave2.CountB, itemsave2.CountC, itemsave2.CountD, itemsave2.CountE ); + } + } + + DateTime endTime = DateTime.Now; + World.Broadcast( 0x35, true, "{0} spawns have been saved. The entire process took {1:F1} seconds.", count, (endTime - startTime).TotalSeconds ); + } + } + + public static void Parse( Mobile from, string filename ) + { + string monster_path1 = Path.Combine( Core.BaseDirectory, "Data/Monsters" ); + string monster_path = Path.Combine( monster_path1, filename ); + m_Count = 0; + + if ( File.Exists( monster_path ) ) + { + from.SendMessage( "Spawning {0}...", filename ); + m_MapOverride = -1; + m_IDOverride = -1; + m_MinTimeOverride = -1; + m_MaxTimeOverride = -1; + + using ( StreamReader ip = new StreamReader( monster_path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + string[] split = line.Split( '|' ); + string[] splitA = line.Split( ' ' ); + + if ( splitA.Length == 2 ) + { + if ( splitA[0].ToLower() == "overridemap" ) + m_MapOverride = Utility.ToInt32( splitA[1] ); + if ( splitA[0].ToLower() == "overrideid" ) + m_IDOverride = Utility.ToInt32( splitA[1] ); + if ( splitA[0].ToLower() == "overridemintime" ) + m_MinTimeOverride = Utility.ToDouble( splitA[1] ); + if ( splitA[0].ToLower() == "overridemaxtime" ) + m_MaxTimeOverride = Utility.ToDouble( splitA[1] ); + } + + if ( split.Length < 19 ) + continue; + + switch( split[0].ToLower() ) + { + //Comment Line + case "##": + break; + //Place By class + case "*": + PlaceNPC( split[2].Split(':'), split[3].Split(':'), split[4].Split(':'), split[5].Split(':'), split[6].Split(':'), split[7], split[8], split[9], split[10], split[11], split[12], split[14], split[13], split[15], split[16], split[17], split[18], split[19], split[20], split[21], split[1].Split(':') ); + break; + //Place By Type + case "r": + PlaceNPC( split[2].Split(':'), split[3].Split(':'), split[4].Split(':'), split[5].Split(':'), split[6].Split(':'), split[7], split[8], split[9], split[10], split[11], split[12], split[14], split[13], split[15], split[16], split[17], split[18], split[19], split[20], split[1], "bloodmoss", "sulfurousash", "spiderssilk", "mandrakeroot", "gravedust", "nightshade", "ginseng", "garlic", "batwing", "pigiron", "noxcrystal", "daemonblood", "blackpearl"); + break; + } + } + } + + m_MapOverride = -1; + m_IDOverride = -1; + m_MinTimeOverride = -1; + m_MaxTimeOverride = -1; + + from.SendMessage( "Done, added {0} spawners",m_Count ); + } + else + { + from.SendMessage( "{0} not found!", monster_path ); + } + } + + public static void PlaceNPC( string[] fakespawnsA, string[] fakespawnsB, string[] fakespawnsC, string[] fakespawnsD, string[] fakespawnsE, string sx, string sy, string sz, string sm, string smintime, string smaxtime, string swalkingrange, string shomerange, string sspawnid, string snpccount, string sfakecountA, string sfakecountB, string sfakecountC, string sfakecountD, string sfakecountE, params string[] types ) + { + if ( types.Length == 0 ) + return; + + int x = Utility.ToInt32( sx ); + int y = Utility.ToInt32( sy ); + int z = Utility.ToInt32( sz ); + int map = Utility.ToInt32( sm ); + + //MinTime + string samintime = smintime; + + if ( smintime.Contains("s") || smintime.Contains("m") || smintime.Contains("h") ) + samintime = smintime.Remove(smintime.Length - 1); + + double dmintime = Utility.ToDouble( samintime ); + + if ( m_MinTimeOverride != -1 ) + dmintime = m_MinTimeOverride; + + TimeSpan mintime = TimeSpan.FromMinutes( dmintime ); + + if ( smintime.Contains("s") ) + mintime = TimeSpan.FromSeconds( dmintime ); + else if ( smintime.Contains("m") ) + mintime = TimeSpan.FromMinutes( dmintime ); + else if ( smintime.Contains("h") ) + mintime = TimeSpan.FromHours( dmintime ); + + //MaxTime + + string samaxtime = smaxtime; + + if ( smaxtime.Contains("s") || smaxtime.Contains("m") || smaxtime.Contains("h") ) + samaxtime = smaxtime.Remove(smaxtime.Length - 1); + + double dmaxtime = Utility.ToDouble( samaxtime ); + + if ( m_MaxTimeOverride != -1 ) + { + if ( m_MaxTimeOverride < dmintime ) + dmaxtime = dmintime; + else + dmaxtime = m_MaxTimeOverride; + } + + TimeSpan maxtime = TimeSpan.FromMinutes( dmaxtime ); + + if ( smaxtime.Contains("s") ) + maxtime = TimeSpan.FromSeconds( dmaxtime ); + else if ( smaxtime.Contains("m") ) + maxtime = TimeSpan.FromMinutes( dmaxtime ); + else if ( smaxtime.Contains("h") ) + maxtime = TimeSpan.FromHours( dmaxtime ); + + // + int homerange = Utility.ToInt32( shomerange ); + int walkingrange = Utility.ToInt32( swalkingrange ); + int spawnid = Utility.ToInt32( sspawnid ); + int npccount = Utility.ToInt32( snpccount ); + int fakecountA = Utility.ToInt32( sfakecountA ); + int fakecountB = Utility.ToInt32( sfakecountB ); + int fakecountC = Utility.ToInt32( sfakecountC ); + int fakecountD = Utility.ToInt32( sfakecountD ); + int fakecountE = Utility.ToInt32( sfakecountE ); + + if ( m_MapOverride != -1 ) + map = m_MapOverride; + + if ( m_IDOverride != -1 ) + spawnid = m_IDOverride; + + switch ( map ) + { + case 0://Trammel and Felucca + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Felucca, mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Trammel, mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + case 1://Felucca + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Felucca, mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + case 2://Trammel + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Trammel, mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + case 3://Ilshenar + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Ilshenar, mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + case 4://Malas + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Malas, mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + case 5://Tokuno + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Maps[4], mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + case 6://TerMur + MakeSpawner( types, fakespawnsA, fakespawnsB, fakespawnsC, fakespawnsD, fakespawnsE, x, y, z, Map.Maps[5], mintime, maxtime, walkingrange, homerange, spawnid, npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE ); + break; + + default: + Console.WriteLine( "Spawn Parser: Warning, unknown map {0}", map ); + break; + } + } + + private static void MakeSpawner( string[] types, string[] fakespawnsA, string[] fakespawnsB, string[] fakespawnsC, string[] fakespawnsD, string[] fakespawnsE, int x, int y, int z, Map map, TimeSpan mintime, TimeSpan maxtime, int walkingrange, int homerange, int spawnid, int npccount, int fakecountA, int fakecountB, int fakecountC, int fakecountD, int fakecountE ) + { + if ( types.Length == 0 ) + return; + + List tipos = new List( types ); + List noneA = new List(); + List noneB = new List(); + List noneC = new List(); + List noneD = new List(); + List noneE = new List(); + + if ( fakespawnsA[0] != "" ) + noneA = new List( fakespawnsA ); + + if ( fakespawnsB[0] != "" ) + noneB = new List( fakespawnsB ); + + if ( fakespawnsC[0] != "" ) + noneC = new List( fakespawnsC ); + + if ( fakespawnsD[0] != "" ) + noneD = new List( fakespawnsD ); + + if ( fakespawnsE[0] != "" ) + noneE = new List( fakespawnsE ); + + PremiumSpawner spawner = new PremiumSpawner( npccount, fakecountA, fakecountB, fakecountC, fakecountD, fakecountE, spawnid, mintime, maxtime, Team, walkingrange, homerange, tipos, noneA, noneB, noneC, noneD, noneE ); + + spawner.MoveToWorld( new Point3D( x, y, z ), map ); + + if ( TotalRespawn ) + { + spawner.Respawn(); + + if ( ((PremiumSpawner)spawner).SpawnID == 132 ) // if is ChampionSpawn + { + spawner.BringToHome(); + } + } + + m_Count++; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/SpawnMaps.cs b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnMaps.cs new file mode 100644 index 0000000..fe0fcb2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnMaps.cs @@ -0,0 +1,409 @@ +// Engine r63 +#define RunUo2_0 +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SpawnCurrentGump : Gump + { + Mobile caller; + + public static void Initialize() + { +#if(RunUo2_0) + CommandSystem.Register("SpawnCurrent", AccessLevel.Administrator, new CommandEventHandler(SpawnCurrent_OnCommand)); +#else + Register("SpawnCurrent", AccessLevel.Administrator, new CommandEventHandler(SpawnCurrent_OnCommand)); +#endif + } + + [Usage("SpawnCurrent")] + [Description("Generate PremiumSpawners around the world with a gump.")] + public static void SpawnCurrent_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from.HasGump(typeof(SpawnCurrentGump))) + from.CloseGump(typeof(SpawnCurrentGump)); + from.SendGump(new SpawnCurrentGump(from)); + } + + public SpawnCurrentGump(Mobile from) : this() + { + caller = from; + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public SpawnCurrentGump() : base( 30, 30 ) + { + this.Closable=true; + this.Disposable=true; + this.Dragable=true; + AddPage(1); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO SPAWN"); + AddBlackAlpha(66, 87, 239, 447); + AddLabel(69, 67, 200, @"DUNGEONS"); + AddLabel(69, 90, 52, @"Blighted Grove"); + AddLabel(69, 112, 52, @"Britain Sewer"); + AddLabel(69, 133, 52, @"Covetous"); + AddLabel(69, 154, 52, @"Deceit"); + AddLabel(69, 174, 52, @"Despise"); + AddLabel(69, 196, 52, @"Destard"); + AddLabel(69, 217, 52, @"Fire"); + AddLabel(69, 237, 52, @"Graveyards"); + AddLabel(69, 258, 52, @"Hythloth"); + AddLabel(69, 280, 52, @"Ice"); + AddLabel(69, 301, 52, @"Khaldun"); + AddLabel(69, 322, 52, @"Orc Caves"); + AddLabel(69, 343, 52, @"Painted Caves"); + AddLabel(69, 363, 52, @"Palace of Paroxysmus"); + AddLabel(69, 384, 52, @"Prism of Light"); + AddLabel(69, 405, 52, @"Sanctuary"); + AddLabel(69, 427, 52, @"Shame"); + AddLabel(69, 448, 52, @"Solen Hive"); + AddLabel(69, 469, 52, @"Terathan Keep"); + AddLabel(69, 489, 52, @"Trinsic Passage"); + AddLabel(69, 510, 52, @"Wrong"); + AddLabel(194, 66, 200, @"Felucca"); + AddCheck(210, 91, 210, 211, true, 201); + AddCheck(210, 112, 210, 211, true, 202); + AddCheck(210, 133, 210, 211, true, 203); + AddCheck(210, 154, 210, 211, true, 204); + AddCheck(210, 175, 210, 211, true, 205); + AddCheck(210, 196, 210, 211, true, 206); + AddCheck(210, 217, 210, 211, true, 207); + AddCheck(210, 238, 210, 211, true, 208); + AddCheck(210, 259, 210, 211, true, 209); + AddCheck(210, 280, 210, 211, true, 210); + AddCheck(210, 301, 210, 211, true, 228); + AddCheck(210, 322, 210, 211, true, 212); + AddCheck(210, 343, 210, 211, true, 214); + AddCheck(210, 364, 210, 211, true, 215); + AddCheck(210, 385, 210, 211, true, 216); + AddCheck(210, 406, 210, 211, true, 217); + AddCheck(210, 427, 210, 211, true, 219); + AddCheck(210, 448, 210, 211, true, 220); + AddCheck(210, 469, 210, 211, true, 221); + AddCheck(210, 490, 210, 211, true, 224); + AddCheck(210, 511, 210, 211, true, 227); + AddLabel(250, 66, 200, @"Trammel"); + AddCheck(268, 91, 210, 211, true, 101); + AddCheck(268, 112, 210, 211, true, 102); + AddCheck(268, 133, 210, 211, true, 103); + AddCheck(268, 154, 210, 211, true, 104); + AddCheck(268, 175, 210, 211, true, 105); + AddCheck(268, 196, 210, 211, true, 106); + AddCheck(268, 217, 210, 211, true, 107); + AddCheck(268, 238, 210, 211, true, 108); + AddCheck(268, 259, 210, 211, true, 109); + AddCheck(268, 280, 210, 211, true, 110); + //There is no Khaldun in Trammel (ID 128 reserved) + AddCheck(268, 322, 210, 211, true, 112); + AddCheck(268, 343, 210, 211, true, 114); + AddCheck(268, 364, 210, 211, true, 115); + AddCheck(268, 385, 210, 211, true, 116); + AddCheck(268, 406, 210, 211, true, 117); + AddCheck(268, 427, 210, 211, true, 119); + AddCheck(268, 448, 210, 211, true, 120); + AddCheck(268, 469, 210, 211, true, 121); + AddCheck(268, 490, 210, 211, true, 124); + AddCheck(268, 511, 210, 211, true, 127); + AddBlackAlpha(311, 87, 213, 70); + AddLabel(315, 67, 200, @"TOWNS"); + AddLabel(315, 91, 52, @"Animals"); + AddLabel(315, 112, 52, @"People (*)"); + AddLabel(315, 133, 52, @"Vendors"); + AddLabel(413, 66, 200, @"Felucca"); + AddCheck(429, 91, 210, 211, true, 222); + AddCheck(429, 112, 210, 211, true, 223); + AddCheck(429, 133, 210, 211, true, 225); + AddLabel(469, 66, 200, @"Trammel"); + AddCheck(487, 91, 210, 211, true, 122); + AddCheck(487, 112, 210, 211, true, 123); + AddCheck(487, 133, 210, 211, true, 125); + AddBlackAlpha(311, 183, 213, 114); + AddLabel(315, 162, 200, @"OUTDOORS"); + AddLabel(316, 187, 52, @"Animals"); + AddLabel(316, 207, 52, @"Lost Lands"); + AddLabel(316, 229, 52, @"Monsters"); + AddLabel(316, 249, 52, @"Reagents"); + AddLabel(316, 270, 52, @"Sea Life"); + AddLabel(413, 162, 200, @"Felucca"); + AddCheck(429, 187, 210, 211, true, 226); + AddCheck(429, 208, 210, 211, true, 211); + AddCheck(429, 229, 210, 211, true, 213); + AddCheck(429, 250, 210, 211, true, 229); + AddCheck(429, 271, 210, 211, true, 218); + AddLabel(469, 162, 200, @"Trammel"); + AddCheck(487, 187, 210, 211, true, 126); + AddCheck(487, 208, 210, 211, true, 111); + AddCheck(487, 229, 210, 211, true, 113); + AddCheck(487, 250, 210, 211, true, 129); + AddCheck(487, 271, 210, 211, true, 118); + AddLabel(316, 305, 200, @"(*) Escortables, Hireables,"); + AddLabel(316, 324, 200, @"Town Criers, Order and Chaos"); + AddLabel(316, 344, 200, @"guards etc."); + // END + AddLabel(361, 453, 52, @"Page: 1/2"); //Page + AddButton(423, 455, 5601, 5605, 0, GumpButtonType.Page, 2); // Change Page + + //PAGE 2 + AddPage(2); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO SPAWN"); + AddBlackAlpha(66, 87, 174, 300); + AddLabel(74, 67, 200, @"ILSHENAR"); + AddLabel(74, 90, 52, @"Ancient Lair"); + AddLabel(74, 112, 52, @"Ankh"); + AddLabel(74, 133, 52, @"Blood"); + AddLabel(74, 154, 52, @"Exodus"); + AddLabel(74, 174, 52, @"Mushroom"); + AddLabel(74, 196, 52, @"Outdoors"); + AddLabel(74, 217, 52, @"Ratman Cave"); + AddLabel(74, 237, 52, @"Rock"); + AddLabel(74, 258, 52, @"Sorcerers"); + AddLabel(74, 280, 52, @"Spectre"); + AddLabel(74, 301, 52, @"Towns"); + AddLabel(74, 322, 52, @"Twisted Weald"); + AddLabel(74, 343, 52, @"Vendors"); + AddLabel(74, 363, 52, @"Wisp"); + AddCheck(215, 91, 210, 211, true, 301); + AddCheck(215, 112, 210, 211, true, 302); + AddCheck(215, 133, 210, 211, true, 303); + AddCheck(215, 154, 210, 211, true, 304); + AddCheck(215, 175, 210, 211, true, 305); + AddCheck(215, 196, 210, 211, true, 306); + AddCheck(215, 217, 210, 211, true, 307); + AddCheck(215, 238, 210, 211, true, 308); + AddCheck(215, 259, 210, 211, true, 309); + AddCheck(215, 280, 210, 211, true, 310); + AddCheck(215, 301, 210, 211, true, 311); + AddCheck(215, 322, 210, 211, true, 314); + AddCheck(215, 343, 210, 211, true, 312); + AddCheck(215, 364, 210, 211, true, 313); + AddBlackAlpha(66, 414, 174, 133); + AddLabel(74, 393, 200, @"TOKUNO"); + AddLabel(74, 416, 52, @"Fan Dancers Dojo"); + AddLabel(74, 438, 52, @"Outdoors"); + AddLabel(74, 459, 52, @"Towns Life"); + AddLabel(74, 480, 52, @"Vendors"); + AddLabel(74, 500, 52, @"Wild Life"); + AddLabel(74, 522, 52, @"Yomutso Mines"); + AddCheck(215, 417, 210, 211, true, 501); + AddCheck(215, 438, 210, 211, true, 502); + AddCheck(215, 459, 210, 211, true, 503); + AddCheck(215, 480, 210, 211, true, 504); + AddCheck(215, 501, 210, 211, true, 505); + AddCheck(215, 522, 210, 211, true, 506); + AddBlackAlpha(246, 87, 174, 156); + AddLabel(253, 67, 200, @"MALAS"); + AddLabel(253, 90, 52, @"Citadel"); + AddLabel(253, 112, 52, @"Doom"); + AddLabel(253, 133, 52, @"Labyrinth"); + AddLabel(253, 154, 52, @"North (*)"); + AddLabel(253, 174, 52, @"Orc Forts"); + AddLabel(253, 196, 52, @"South (*)"); + AddLabel(253, 217, 52, @"Vendors"); + AddCheck(394, 91, 210, 211, true, 406); + AddCheck(394, 112, 210, 211, true, 401); + AddCheck(394, 133, 210, 211, true, 407); + AddCheck(394, 154, 210, 211, true, 402); + AddCheck(394, 175, 210, 211, true, 403); + AddCheck(394, 196, 210, 211, true, 404); + AddCheck(394, 217, 210, 211, true, 405); + AddLabel(428, 91, 200, @"(*) Wild"); + AddLabel(428, 109, 200, @"Animals and"); + AddLabel(428, 129, 200, @"monsters."); + AddBlackAlpha(246, 270, 174, 117); + AddLabel(253, 250, 200, @"TER MUR"); + AddLabel(253, 273, 52, @"Abyss"); + AddLabel(253, 294, 52, @"TerMur"); + AddLabel(253, 315, 52, @"Underworld"); + AddLabel(253, 336, 52, @"Vendors"); + AddCheck(394, 274, 210, 211, true, 601); + AddCheck(394, 295, 210, 211, true, 602); + AddCheck(394, 316, 210, 211, true, 603); + AddCheck(394, 337, 210, 211, true, 604); + //END + AddLabel(381, 453, 52, @"Page: 2/2"); //Page + AddButton(361, 455, 5603, 5607, 0, GumpButtonType.Page, 1); //Change Page + AddButton(282, 452, 240, 239, 1, GumpButtonType.Reply, 0); // Apply + } + + public static void SpawnThis( Mobile from, List ListSwitches, int switche, int map, string mapfile) + { + string folder = ""; + + if( map == 1 ) + folder = "felucca"; + else if( map == 2) + folder = "trammel"; + else if( map == 3) + folder = "ilshenar"; + else if( map == 4) + folder = "malas"; + else if( map == 5) + folder = "tokuno"; + else if( map == 6) + folder = "termur"; + + string prefix = Server.Commands.CommandSystem.Prefix; + + if( ListSwitches.Contains( switche ) == true ) + CommandSystem.Handle( from, String.Format( "{0}Spawngen {1}/{2}.map", prefix, folder, mapfile ) ); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + switch(info.ButtonID) + { + case 0: //Closed or Cancel + { + break; + } + default: + { + // Make sure that the APPLY button was pressed + if( info.ButtonID == 1 ) + { + // Get the array of switches selected + List Selections = new List( info.Switches ); + + //TRAMMEL + from.Say( "SPAWNING TRAMMEL..." ); + // DUNGEONS + SpawnThis(from, Selections, 101, 2, "BlightedGrove"); + SpawnThis(from, Selections, 102, 2, "BritainSewer"); + SpawnThis(from, Selections, 103, 2, "Covetous"); + SpawnThis(from, Selections, 104, 2, "Deceit"); + SpawnThis(from, Selections, 105, 2, "Despise"); + SpawnThis(from, Selections, 106, 2, "Destard"); + SpawnThis(from, Selections, 107, 2, "Fire"); + SpawnThis(from, Selections, 108, 2, "Graveyards"); + SpawnThis(from, Selections, 109, 2, "Hythloth"); + SpawnThis(from, Selections, 110, 2, "Ice"); + //There is no Khaldun (118) + SpawnThis(from, Selections, 112, 2, "OrcCaves"); + SpawnThis(from, Selections, 114, 2, "PaintedCaves"); + SpawnThis(from, Selections, 115, 2, "PalaceOfParoxysmus"); + SpawnThis(from, Selections, 116, 2, "PrismOfLight"); + SpawnThis(from, Selections, 117, 2, "Sanctuary"); + SpawnThis(from, Selections, 119, 2, "Shame"); + SpawnThis(from, Selections, 120, 2, "SolenHive"); + SpawnThis(from, Selections, 121, 2, "TerathanKeep"); + SpawnThis(from, Selections, 124, 2, "TrinsicPassage"); + SpawnThis(from, Selections, 127, 2, "Wrong"); + //TOWNS + SpawnThis(from, Selections, 122, 2, "TownsLife"); + SpawnThis(from, Selections, 123, 2, "TownsPeople"); + SpawnThis(from, Selections, 125, 2, "Vendors"); + //OUTDOORS + SpawnThis(from, Selections, 126, 2, "WildLife"); + SpawnThis(from, Selections, 111, 2, "LostLands"); + SpawnThis(from, Selections, 113, 2, "Outdoors"); + SpawnThis(from, Selections, 129, 2, "Reagents"); + SpawnThis(from, Selections, 118, 2, "SeaLife"); + + //FELUCCA + from.Say( "SPAWNING FELUCCA..." ); + // DUNGEONS + SpawnThis(from, Selections, 201, 1, "BlightedGrove"); + SpawnThis(from, Selections, 202, 1, "BritainSewer"); + SpawnThis(from, Selections, 203, 1, "Covetous"); + SpawnThis(from, Selections, 204, 1, "Deceit"); + SpawnThis(from, Selections, 205, 1, "Despise"); + SpawnThis(from, Selections, 206, 1, "Destard"); + SpawnThis(from, Selections, 207, 1, "Fire"); + SpawnThis(from, Selections, 208, 1, "Graveyards"); + SpawnThis(from, Selections, 209, 1, "Hythloth"); + SpawnThis(from, Selections, 210, 1, "Ice"); + SpawnThis(from, Selections, 229, 1, "Khaldun"); + SpawnThis(from, Selections, 212, 1, "OrcCaves"); + SpawnThis(from, Selections, 214, 1, "PaintedCaves"); + SpawnThis(from, Selections, 215, 1, "PalaceOfParoxysmus"); + SpawnThis(from, Selections, 216, 1, "PrismOfLight"); + SpawnThis(from, Selections, 217, 1, "Sanctuary"); + SpawnThis(from, Selections, 219, 1, "Shame"); + SpawnThis(from, Selections, 220, 1, "SolenHive"); + SpawnThis(from, Selections, 221, 1, "TerathanKeep"); + SpawnThis(from, Selections, 224, 1, "TrinsicPassage"); + SpawnThis(from, Selections, 227, 1, "Wrong"); + //TOWNS + SpawnThis(from, Selections, 222, 1, "TownsLife"); + SpawnThis(from, Selections, 223, 1, "TownsPeople"); + SpawnThis(from, Selections, 225, 1, "Vendors"); + //OUTDOORS + SpawnThis(from, Selections, 226, 1, "WildLife"); + SpawnThis(from, Selections, 211, 1, "LostLands"); + SpawnThis(from, Selections, 213, 1, "Outdoors"); + SpawnThis(from, Selections, 229, 1, "Reagents"); + SpawnThis(from, Selections, 218, 1, "SeaLife"); + + //ILSHENAR + from.Say( "SPAWNING ILSHENAR..." ); + SpawnThis(from, Selections, 301, 3, "Ancientlair"); + SpawnThis(from, Selections, 302, 3, "Ankh"); + SpawnThis(from, Selections, 303, 3, "Blood"); + SpawnThis(from, Selections, 304, 3, "Exodus"); + SpawnThis(from, Selections, 305, 3, "Mushroom"); + SpawnThis(from, Selections, 306, 3, "Outdoors"); + SpawnThis(from, Selections, 307, 3, "Ratmancave"); + SpawnThis(from, Selections, 308, 3, "Rock"); + SpawnThis(from, Selections, 309, 3, "Sorcerers"); + SpawnThis(from, Selections, 310, 3, "Spectre"); + SpawnThis(from, Selections, 311, 3, "Towns"); + SpawnThis(from, Selections, 314, 3, "TwistedWeald"); + SpawnThis(from, Selections, 312, 3, "Vendors"); + SpawnThis(from, Selections, 313, 3, "Wisp"); + + //MALAS + from.Say( "SPAWNING MALAS..." ); + SpawnThis(from, Selections, 406, 4, "Citadel"); + SpawnThis(from, Selections, 401, 4, "Doom"); + SpawnThis(from, Selections, 407, 4, "Labyrinth"); + SpawnThis(from, Selections, 402, 4, "North"); + SpawnThis(from, Selections, 403, 4, "OrcForts"); + SpawnThis(from, Selections, 404, 4, "South"); + SpawnThis(from, Selections, 405, 4, "Vendors"); + + //TOKUNO + from.Say( "SPAWNING TOKUNO..." ); + SpawnThis(from, Selections, 501, 5, "FanDancersDojo"); + SpawnThis(from, Selections, 502, 5, "Outdoors"); + SpawnThis(from, Selections, 503, 5, "TownsLife"); + SpawnThis(from, Selections, 504, 5, "Vendors"); + SpawnThis(from, Selections, 505, 5, "WildLife"); + SpawnThis(from, Selections, 506, 5, "YomutsoMines"); + + //TER MUR + from.Say( "SPAWNING TER MUR..." ); + SpawnThis(from, Selections, 601, 6, "Abyss"); + SpawnThis(from, Selections, 602, 6, "TerMur"); + SpawnThis(from, Selections, 603, 6, "Underworld"); + SpawnThis(from, Selections, 604, 6, "Vendors"); + + from.Say( "SPAWN GENERATION COMPLETED" ); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/SpawnMapsUOML.cs b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnMapsUOML.cs new file mode 100644 index 0000000..72b6e27 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnMapsUOML.cs @@ -0,0 +1,390 @@ +// Engine r29 +#define RunUo2_0 +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SpawnUOMLGump : Gump + { + Mobile caller; + + public static void Initialize() + { +#if(RunUo2_0) + CommandSystem.Register("SpawnUOML", AccessLevel.Administrator, new CommandEventHandler(SpawnUOML_OnCommand)); +#else + Register("SpawnUOML", AccessLevel.Administrator, new CommandEventHandler(SpawnUOML_OnCommand)); +#endif + } + + [Usage("SpawnUOML")] + [Description("Generate PremiumSpawners around the world with a gump.")] + public static void SpawnUOML_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from.HasGump(typeof(SpawnUOMLGump))) + from.CloseGump(typeof(SpawnUOMLGump)); + from.SendGump(new SpawnUOMLGump(from)); + } + + public SpawnUOMLGump(Mobile from) : this() + { + caller = from; + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public SpawnUOMLGump() : base( 30, 30 ) + { + this.Closable=true; + this.Disposable=true; + this.Dragable=true; + AddPage(1); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO SPAWN"); + AddBlackAlpha(66, 87, 239, 447); + AddLabel(69, 67, 200, @"DUNGEONS"); + AddLabel(69, 90, 52, @"Blighted Grove"); + AddLabel(69, 112, 52, @"Britain Sewer"); + AddLabel(69, 133, 52, @"Covetous"); + AddLabel(69, 154, 52, @"Deceit"); + AddLabel(69, 174, 52, @"Despise"); + AddLabel(69, 196, 52, @"Destard"); + AddLabel(69, 217, 52, @"Fire"); + AddLabel(69, 237, 52, @"Graveyards"); + AddLabel(69, 258, 52, @"Hythloth"); + AddLabel(69, 280, 52, @"Ice"); + AddLabel(69, 301, 52, @"Khaldun"); + AddLabel(69, 322, 52, @"Orc Caves"); + AddLabel(69, 343, 52, @"Painted Caves"); + AddLabel(69, 363, 52, @"Palace of Paroxysmus"); + AddLabel(69, 384, 52, @"Prism of Light"); + AddLabel(69, 405, 52, @"Sanctuary"); + AddLabel(69, 427, 52, @"Shame"); + AddLabel(69, 448, 52, @"Solen Hive"); + AddLabel(69, 469, 52, @"Terathan Keep"); + AddLabel(69, 489, 52, @"Trinsic Passage"); + AddLabel(69, 510, 52, @"Wrong"); + AddLabel(194, 66, 200, @"Felucca"); + AddCheck(210, 91, 210, 211, true, 201); + AddCheck(210, 112, 210, 211, true, 202); + AddCheck(210, 133, 210, 211, true, 203); + AddCheck(210, 154, 210, 211, true, 204); + AddCheck(210, 175, 210, 211, true, 205); + AddCheck(210, 196, 210, 211, true, 206); + AddCheck(210, 217, 210, 211, true, 207); + AddCheck(210, 238, 210, 211, true, 208); + AddCheck(210, 259, 210, 211, true, 209); + AddCheck(210, 280, 210, 211, true, 210); + AddCheck(210, 301, 210, 211, true, 228); + AddCheck(210, 322, 210, 211, true, 212); + AddCheck(210, 343, 210, 211, true, 214); + AddCheck(210, 364, 210, 211, true, 215); + AddCheck(210, 385, 210, 211, true, 216); + AddCheck(210, 406, 210, 211, true, 217); + AddCheck(210, 427, 210, 211, true, 219); + AddCheck(210, 448, 210, 211, true, 220); + AddCheck(210, 469, 210, 211, true, 221); + AddCheck(210, 490, 210, 211, true, 224); + AddCheck(210, 511, 210, 211, true, 227); + AddLabel(250, 66, 200, @"Trammel"); + AddCheck(268, 91, 210, 211, true, 101); + AddCheck(268, 112, 210, 211, true, 102); + AddCheck(268, 133, 210, 211, true, 103); + AddCheck(268, 154, 210, 211, true, 104); + AddCheck(268, 175, 210, 211, true, 105); + AddCheck(268, 196, 210, 211, true, 106); + AddCheck(268, 217, 210, 211, true, 107); + AddCheck(268, 238, 210, 211, true, 108); + AddCheck(268, 259, 210, 211, true, 109); + AddCheck(268, 280, 210, 211, true, 110); + //There is no Khaldun in Trammel (ID 128 reserved) + AddCheck(268, 322, 210, 211, true, 112); + AddCheck(268, 343, 210, 211, true, 114); + AddCheck(268, 364, 210, 211, true, 115); + AddCheck(268, 385, 210, 211, true, 116); + AddCheck(268, 406, 210, 211, true, 117); + AddCheck(268, 427, 210, 211, true, 119); + AddCheck(268, 448, 210, 211, true, 120); + AddCheck(268, 469, 210, 211, true, 121); + AddCheck(268, 490, 210, 211, true, 124); + AddCheck(268, 511, 210, 211, true, 127); + AddBlackAlpha(311, 87, 213, 70); + AddLabel(315, 67, 200, @"TOWNS"); + AddLabel(315, 91, 52, @"Animals"); + AddLabel(315, 112, 52, @"People (*)"); + AddLabel(315, 133, 52, @"Vendors"); + AddLabel(413, 66, 200, @"Felucca"); + AddCheck(429, 91, 210, 211, true, 222); + AddCheck(429, 112, 210, 211, true, 223); + AddCheck(429, 133, 210, 211, true, 225); + AddLabel(469, 66, 200, @"Trammel"); + AddCheck(487, 91, 210, 211, true, 122); + AddCheck(487, 112, 210, 211, true, 123); + AddCheck(487, 133, 210, 211, true, 125); + AddBlackAlpha(311, 183, 213, 114); + AddLabel(315, 162, 200, @"OUTDOORS"); + AddLabel(316, 187, 52, @"Animals"); + AddLabel(316, 207, 52, @"Lost Lands"); + AddLabel(316, 229, 52, @"Monsters"); + AddLabel(316, 249, 52, @"Reagents"); + AddLabel(316, 270, 52, @"Sea Life"); + AddLabel(413, 162, 200, @"Felucca"); + AddCheck(429, 187, 210, 211, true, 226); + AddCheck(429, 208, 210, 211, true, 211); + AddCheck(429, 229, 210, 211, true, 213); + AddCheck(429, 250, 210, 211, true, 229); + AddCheck(429, 271, 210, 211, true, 218); + AddLabel(469, 162, 200, @"Trammel"); + AddCheck(487, 187, 210, 211, true, 126); + AddCheck(487, 208, 210, 211, true, 111); + AddCheck(487, 229, 210, 211, true, 113); + AddCheck(487, 250, 210, 211, true, 129); + AddCheck(487, 271, 210, 211, true, 118); + AddLabel(316, 305, 200, @"(*) Escortables, Hireables,"); + AddLabel(316, 324, 200, @"Town Criers, Order and Chaos"); + AddLabel(316, 344, 200, @"guards etc."); + // END + AddLabel(361, 453, 52, @"Page: 1/2"); //Page + AddButton(423, 455, 5601, 5605, 0, GumpButtonType.Page, 2); // Change Page + + //PAGE 2 + AddPage(2); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO SPAWN"); + AddBlackAlpha(66, 87, 174, 300); + AddLabel(74, 67, 200, @"ILSHENAR"); + AddLabel(74, 90, 52, @"Ancient Lair"); + AddLabel(74, 112, 52, @"Ankh"); + AddLabel(74, 133, 52, @"Blood"); + AddLabel(74, 154, 52, @"Exodus"); + AddLabel(74, 174, 52, @"Mushroom"); + AddLabel(74, 196, 52, @"Outdoors"); + AddLabel(74, 217, 52, @"Ratman Cave"); + AddLabel(74, 237, 52, @"Rock"); + AddLabel(74, 258, 52, @"Sorcerers"); + AddLabel(74, 280, 52, @"Spectre"); + AddLabel(74, 301, 52, @"Towns"); + AddLabel(74, 322, 52, @"Twisted Weald"); + AddLabel(74, 343, 52, @"Vendors"); + AddLabel(74, 363, 52, @"Wisp"); + AddCheck(215, 91, 210, 211, true, 301); + AddCheck(215, 112, 210, 211, true, 302); + AddCheck(215, 133, 210, 211, true, 303); + AddCheck(215, 154, 210, 211, true, 304); + AddCheck(215, 175, 210, 211, true, 305); + AddCheck(215, 196, 210, 211, true, 306); + AddCheck(215, 217, 210, 211, true, 307); + AddCheck(215, 238, 210, 211, true, 308); + AddCheck(215, 259, 210, 211, true, 309); + AddCheck(215, 280, 210, 211, true, 310); + AddCheck(215, 301, 210, 211, true, 311); + AddCheck(215, 322, 210, 211, true, 314); + AddCheck(215, 343, 210, 211, true, 312); + AddCheck(215, 364, 210, 211, true, 313); + AddBlackAlpha(66, 414, 174, 133); + AddLabel(74, 393, 200, @"TOKUNO"); + AddLabel(74, 416, 52, @"Fan Dancers Dojo"); + AddLabel(74, 438, 52, @"Outdoors"); + AddLabel(74, 459, 52, @"Towns Life"); + AddLabel(74, 480, 52, @"Vendors"); + AddLabel(74, 500, 52, @"Wild Life"); + AddLabel(74, 522, 52, @"Yomutso Mines"); + AddCheck(215, 417, 210, 211, true, 501); + AddCheck(215, 438, 210, 211, true, 502); + AddCheck(215, 459, 210, 211, true, 503); + AddCheck(215, 480, 210, 211, true, 504); + AddCheck(215, 501, 210, 211, true, 505); + AddCheck(215, 522, 210, 211, true, 506); + AddBlackAlpha(246, 87, 174, 156); + AddLabel(253, 67, 200, @"MALAS"); + AddLabel(253, 90, 52, @"Citadel"); + AddLabel(253, 112, 52, @"Doom"); + AddLabel(253, 133, 52, @"Labyrinth"); + AddLabel(253, 154, 52, @"North (*)"); + AddLabel(253, 174, 52, @"Orc Forts"); + AddLabel(253, 196, 52, @"South (*)"); + AddLabel(253, 217, 52, @"Vendors"); + AddCheck(394, 91, 210, 211, true, 406); + AddCheck(394, 112, 210, 211, true, 401); + AddCheck(394, 133, 210, 211, true, 407); + AddCheck(394, 154, 210, 211, true, 402); + AddCheck(394, 175, 210, 211, true, 403); + AddCheck(394, 196, 210, 211, true, 404); + AddCheck(394, 217, 210, 211, true, 405); + AddLabel(428, 91, 200, @"(*) Wild"); + AddLabel(428, 109, 200, @"Animals and"); + AddLabel(428, 129, 200, @"monsters."); + //END + AddLabel(381, 453, 52, @"Page: 2/2"); //Page + AddButton(361, 455, 5603, 5607, 0, GumpButtonType.Page, 1); //Change Page + AddButton(282, 452, 240, 239, 1, GumpButtonType.Reply, 0); // Apply + } + + public static void SpawnThis( Mobile from, List ListSwitches, int switche, int map, string mapfile) + { + string folder = ""; + + if( map == 1 ) + folder = "felucca"; + else if( map == 2) + folder = "trammel"; + else if( map == 3) + folder = "ilshenar"; + else if( map == 4) + folder = "malas"; + else if( map == 5) + folder = "tokuno"; + + string prefix = Server.Commands.CommandSystem.Prefix; + + if( ListSwitches.Contains( switche ) == true ) + CommandSystem.Handle( from, String.Format( "{0}Spawngen uoml/{1}/{2}.map", prefix, folder, mapfile ) ); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + switch(info.ButtonID) + { + case 0: //Closed or Cancel + { + break; + } + default: + { + // Make sure that the APPLY button was pressed + if( info.ButtonID == 1 ) + { + // Get the array of switches selected + List Selections = new List( info.Switches ); + + //TRAMMEL + from.Say( "SPAWNING TRAMMEL..." ); + // DUNGEONS + SpawnThis(from, Selections, 101, 2, "BlightedGrove"); + SpawnThis(from, Selections, 102, 2, "BritainSewer"); + SpawnThis(from, Selections, 103, 2, "Covetous"); + SpawnThis(from, Selections, 104, 2, "Deceit"); + SpawnThis(from, Selections, 105, 2, "Despise"); + SpawnThis(from, Selections, 106, 2, "Destard"); + SpawnThis(from, Selections, 107, 2, "Fire"); + SpawnThis(from, Selections, 108, 2, "Graveyards"); + SpawnThis(from, Selections, 109, 2, "Hythloth"); + SpawnThis(from, Selections, 110, 2, "Ice"); + //There is no Khaldun (118) + SpawnThis(from, Selections, 112, 2, "OrcCaves"); + SpawnThis(from, Selections, 114, 2, "PaintedCaves"); + SpawnThis(from, Selections, 115, 2, "PalaceOfParoxysmus"); + SpawnThis(from, Selections, 116, 2, "PrismOfLight"); + SpawnThis(from, Selections, 117, 2, "Sanctuary"); + SpawnThis(from, Selections, 119, 2, "Shame"); + SpawnThis(from, Selections, 120, 2, "SolenHive"); + SpawnThis(from, Selections, 121, 2, "TerathanKeep"); + SpawnThis(from, Selections, 124, 2, "TrinsicPassage"); + SpawnThis(from, Selections, 127, 2, "Wrong"); + //TOWNS + SpawnThis(from, Selections, 122, 2, "TownsLife"); + SpawnThis(from, Selections, 123, 2, "TownsPeople"); + SpawnThis(from, Selections, 125, 2, "Vendors"); + //OUTDOORS + SpawnThis(from, Selections, 126, 2, "WildLife"); + SpawnThis(from, Selections, 111, 2, "LostLands"); + SpawnThis(from, Selections, 113, 2, "Outdoors"); + SpawnThis(from, Selections, 129, 2, "Reagents"); + SpawnThis(from, Selections, 118, 2, "SeaLife"); + + //FELUCCA + from.Say( "SPAWNING FELUCCA..." ); + // DUNGEONS + SpawnThis(from, Selections, 201, 1, "BlightedGrove"); + SpawnThis(from, Selections, 202, 1, "BritainSewer"); + SpawnThis(from, Selections, 203, 1, "Covetous"); + SpawnThis(from, Selections, 204, 1, "Deceit"); + SpawnThis(from, Selections, 205, 1, "Despise"); + SpawnThis(from, Selections, 206, 1, "Destard"); + SpawnThis(from, Selections, 207, 1, "Fire"); + SpawnThis(from, Selections, 208, 1, "Graveyards"); + SpawnThis(from, Selections, 209, 1, "Hythloth"); + SpawnThis(from, Selections, 210, 1, "Ice"); + SpawnThis(from, Selections, 229, 1, "Khaldun"); + SpawnThis(from, Selections, 212, 1, "OrcCaves"); + SpawnThis(from, Selections, 214, 1, "PaintedCaves"); + SpawnThis(from, Selections, 215, 1, "PalaceOfParoxysmus"); + SpawnThis(from, Selections, 216, 1, "PrismOfLight"); + SpawnThis(from, Selections, 217, 1, "Sanctuary"); + SpawnThis(from, Selections, 219, 1, "Shame"); + SpawnThis(from, Selections, 220, 1, "SolenHive"); + SpawnThis(from, Selections, 221, 1, "TerathanKeep"); + SpawnThis(from, Selections, 224, 1, "TrinsicPassage"); + SpawnThis(from, Selections, 227, 1, "Wrong"); + //TOWNS + SpawnThis(from, Selections, 222, 1, "TownsLife"); + SpawnThis(from, Selections, 223, 1, "TownsPeople"); + SpawnThis(from, Selections, 225, 1, "Vendors"); + //OUTDOORS + SpawnThis(from, Selections, 226, 1, "WildLife"); + SpawnThis(from, Selections, 211, 1, "LostLands"); + SpawnThis(from, Selections, 213, 1, "Outdoors"); + SpawnThis(from, Selections, 229, 1, "Reagents"); + SpawnThis(from, Selections, 218, 1, "SeaLife"); + + //ILSHENAR + from.Say( "SPAWNING ILSHENAR..." ); + SpawnThis(from, Selections, 301, 3, "Ancientlair"); + SpawnThis(from, Selections, 302, 3, "Ankh"); + SpawnThis(from, Selections, 303, 3, "Blood"); + SpawnThis(from, Selections, 304, 3, "Exodus"); + SpawnThis(from, Selections, 305, 3, "Mushroom"); + SpawnThis(from, Selections, 306, 3, "Outdoors"); + SpawnThis(from, Selections, 307, 3, "Ratmancave"); + SpawnThis(from, Selections, 308, 3, "Rock"); + SpawnThis(from, Selections, 309, 3, "Sorcerers"); + SpawnThis(from, Selections, 310, 3, "Spectre"); + SpawnThis(from, Selections, 311, 3, "Towns"); + SpawnThis(from, Selections, 314, 3, "TwistedWeald"); + SpawnThis(from, Selections, 312, 3, "Vendors"); + SpawnThis(from, Selections, 313, 3, "Wisp"); + + //MALAS + from.Say( "SPAWNING MALAS..." ); + SpawnThis(from, Selections, 406, 4, "Citadel"); + SpawnThis(from, Selections, 401, 4, "Doom"); + SpawnThis(from, Selections, 407, 4, "Labyrinth"); + SpawnThis(from, Selections, 402, 4, "North"); + SpawnThis(from, Selections, 403, 4, "OrcForts"); + SpawnThis(from, Selections, 404, 4, "South"); + SpawnThis(from, Selections, 405, 4, "Vendors"); + + //TOKUNO + from.Say( "SPAWNING TOKUNO..." ); + SpawnThis(from, Selections, 501, 5, "FanDancersDojo"); + SpawnThis(from, Selections, 502, 5, "Outdoors"); + SpawnThis(from, Selections, 503, 5, "TownsLife"); + SpawnThis(from, Selections, 504, 5, "Vendors"); + SpawnThis(from, Selections, 505, 5, "WildLife"); + SpawnThis(from, Selections, 506, 5, "YomutsoMines"); + + from.Say( "SPAWN GENERATION COMPLETED" ); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/SpawnsOverseerCommand.cs b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnsOverseerCommand.cs new file mode 100644 index 0000000..3f53ecc --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/SpawnsOverseerCommand.cs @@ -0,0 +1,451 @@ +// Engine r75 +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Engines.Quests.Haven; +using Server.Engines.Quests.Necro; + +namespace Server.Commands +{ + public class GenOverseer + { + public static void Initialize() + { + CommandSystem.Register( "GenSeers", AccessLevel.Administrator, new CommandEventHandler( GenOverseer_OnCommand ) ); + CommandSystem.Register( "GenOverseers", AccessLevel.Administrator, new CommandEventHandler( GenOverseer_OnCommand ) ); + CommandSystem.Register( "GenSeer", AccessLevel.Administrator, new CommandEventHandler( GenOverseer_OnCommand ) ); + CommandSystem.Register( "GenOverseer", AccessLevel.Administrator, new CommandEventHandler( GenOverseer_OnCommand ) ); + } + + [Usage( "GenSeers" )] + [Aliases( "GenSeer, GenOverseer and GenOverseers" )] + [Description( "Generates Spawns' Overseers around the world." )] + private static void GenOverseer_OnCommand( CommandEventArgs e ) + { + m_Mobile = e.Mobile; + m_Count = 0; + + m_Mobile.SendMessage( "Generating Spawns' Overseers, please wait." ); + + Generate( "Data/Monsters/overseers/Trammel", Map.Trammel ); + Generate( "Data/Monsters/overseers/Felucca", Map.Felucca ); + Generate( "Data/Monsters/overseers/Ilshenar", Map.Ilshenar ); + Generate( "Data/Monsters/overseers/Malas", Map.Malas ); + Generate( "Data/Monsters/overseers/Tokuno", Map.Tokuno ); + Generate( "Data/Monsters/overseers/Termur", Map.TerMur ); + + m_Mobile.SendMessage( "Spawns' Overseers generation complete. {0} seers were generated.", m_Count ); + } + + public static void Generate( string folder, params Map[] maps ) + { + if ( !Directory.Exists( folder ) ) + return; + + string[] files = Directory.GetFiles( folder, "*.cfg" ); + + for ( int i = 0; i < files.Length; ++i ) + { + ArrayList list = DecorationListSeers.ReadAll( files[i] ); + + for ( int j = 0; j < list.Count; ++j ) + m_Count += ((DecorationListSeers)list[j]).Generate( maps ); + } + } + + private static Mobile m_Mobile; + private static int m_Count; + } + + public class DecorationListSeers + { + private Type m_Type; + private int m_ItemID; + private string[] m_Params; + private ArrayList m_Entries; + + public DecorationListSeers() + { + } + + private static Type typeofStatic = typeof( Static ); + private static Type typeofLocalizedStatic = typeof( LocalizedStatic ); + + public Item Construct() + { + Item item; + + try + { + if ( m_Type == typeofStatic ) + { + item = new Static( m_ItemID ); + } + else if ( m_Type == typeofLocalizedStatic ) + { + int labelNumber = 0; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "LabelNumber" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + labelNumber = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + break; + } + } + } + + item = new LocalizedStatic( m_ItemID, labelNumber ); + } + else + { + item = (Item)Activator.CreateInstance( m_Type ); + } + } + catch ( Exception e ) + { + throw new Exception( String.Format( "Bad type: {0}", m_Type ), e ); + } + + if ( item is Server.Items.SpawnsOverseer ) + { + Server.Items.SpawnsOverseer sp = (Server.Items.SpawnsOverseer)item; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Range" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.Range = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "InRangeDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.InRangeDelay = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + else if ( m_Params[i].StartsWith( "OutRangeDelay" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + sp.OutRangeDelay = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + } + } + } + + item.Movable = false; + + for ( int i = 0; i < m_Params.Length; ++i ) + { + if ( m_Params[i].StartsWith( "Light" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + item.Light = (LightType)Enum.Parse( typeof( LightType ), m_Params[i].Substring( ++indexOf ), true ); + } + else if ( m_Params[i].StartsWith( "Hue" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + int hue = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + + if ( item is DyeTub ) + ((DyeTub)item).DyedHue = hue; + else + item.Hue = hue; + } + } + else if ( m_Params[i].StartsWith( "Name" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + item.Name = m_Params[i].Substring( ++indexOf ); + } + else if ( m_Params[i].StartsWith( "Amount" ) ) + { + int indexOf = m_Params[i].IndexOf( '=' ); + + if ( indexOf >= 0 ) + { + // Must supress stackable warnings + + bool wasStackable = item.Stackable; + + item.Stackable = true; + item.Amount = Utility.ToInt32( m_Params[i].Substring( ++indexOf ) ); + item.Stackable = wasStackable; + } + } + } + + return item; + } + + private static Queue m_DeleteQueue = new Queue(); + + private static bool FindItem( int x, int y, int z, Map map, Item srcItem ) + { + int itemID = srcItem.ItemID; + + bool res = false; + + IPooledEnumerable eable; + + if ( (TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.LightSource) != 0 ) + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + LightType lt = srcItem.Light; + string srcName = srcItem.ItemData.Name; + + foreach ( Item item in eable ) + { + if ( item.Z == z ) + { + if ( item.ItemID == itemID ) + { + if ( item.Light != lt ) + m_DeleteQueue.Enqueue( item ); + else + res = true; + } + else if ( (item.ItemData.Flags & TileFlag.LightSource) != 0 && item.ItemData.Name == srcName ) + { + m_DeleteQueue.Enqueue( item ); + } + } + } + } + else + { + eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + foreach ( Item item in eable ) + { + if ( item.Z == z && item.ItemID == itemID ) + { + eable.Free(); + return true; + } + } + } + + eable.Free(); + + while ( m_DeleteQueue.Count > 0 ) + ((Item)m_DeleteQueue.Dequeue()).Delete(); + + return res; + } + + public int Generate( Map[] maps ) + { + int count = 0; + + Item item = null; + + for ( int i = 0; i < m_Entries.Count; ++i ) + { + DecorationEntrySeers entry = (DecorationEntrySeers)m_Entries[i]; + Point3D loc = entry.Location; + string extra = entry.Extra; + + for ( int j = 0; j < maps.Length; ++j ) + { + if ( item == null ) + item = Construct(); + + if ( item == null ) + continue; + + if ( FindItem( loc.X, loc.Y, loc.Z, maps[j], item ) ) + { + } + else + { + item.MoveToWorld( loc, maps[j] ); + ++count; + + item = null; + } + } + } + + if ( item != null ) + item.Delete(); + + return count; + } + + public static ArrayList ReadAll( string path ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + ArrayList list = new ArrayList(); + + for ( DecorationListSeers v = Read( ip ); v != null; v = Read( ip ) ) + list.Add( v ); + + return list; + } + } + + private static string[] m_EmptyParams = new string[0]; + + public static DecorationListSeers Read( StreamReader ip ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length > 0 && !line.StartsWith( "#" ) ) + break; + } + + if ( string.IsNullOrEmpty( line ) ) + return null; + + DecorationListSeers list = new DecorationListSeers(); + + int indexOf = line.IndexOf( ' ' ); + + list.m_Type = ScriptCompiler.FindTypeByName( line.Substring( 0, indexOf++ ), true ); + + if ( list.m_Type == null ) + throw new ArgumentException( String.Format( "Type not found for header: '{0}'", line ) ); + + line = line.Substring( indexOf ); + indexOf = line.IndexOf( '(' ); + if ( indexOf >= 0 ) + { + list.m_ItemID = Utility.ToInt32( line.Substring( 0, indexOf - 1 ) ); + + string parms = line.Substring( ++indexOf ); + + if ( line.EndsWith( ")" ) ) + parms = parms.Substring( 0, parms.Length - 1 ); + + list.m_Params = parms.Split( ';' ); + + for ( int i = 0; i < list.m_Params.Length; ++i ) + list.m_Params[i] = list.m_Params[i].Trim(); + } + else + { + list.m_ItemID = Utility.ToInt32( line ); + list.m_Params = m_EmptyParams; + } + + list.m_Entries = new ArrayList(); + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length == 0 ) + break; + + if ( line.StartsWith( "#" ) ) + continue; + + list.m_Entries.Add( new DecorationEntrySeers( line ) ); + } + + return list; + } + } + + public class DecorationEntrySeers + { + private Point3D m_Location; + private string m_Extra; + + public Point3D Location{ get{ return m_Location; } } + public string Extra{ get{ return m_Extra; } } + + public DecorationEntrySeers( string line ) + { + string x, y, z; + + Pop( out x, ref line ); + Pop( out y, ref line ); + Pop( out z, ref line ); + + m_Location = new Point3D( Utility.ToInt32( x ), Utility.ToInt32( y ), Utility.ToInt32( z ) ); + m_Extra = line; + } + + public void Pop( out string v, ref string line ) + { + int space = line.IndexOf( ' ' ); + + if ( space >= 0 ) + { + v = line.Substring( 0, space++ ); + line = line.Substring( space ); + } + else + { + v = line; + line = ""; + } + } + } + + public class RemOverseer + { + public static void Initialize() + { + CommandSystem.Register( "RemOverseers", AccessLevel.Administrator, new CommandEventHandler( RemOverseers_OnCommand ) ); + CommandSystem.Register( "RemSeers", AccessLevel.Administrator, new CommandEventHandler( RemOverseers_OnCommand ) ); + CommandSystem.Register( "RemOverseer", AccessLevel.Administrator, new CommandEventHandler( RemOverseers_OnCommand ) ); + CommandSystem.Register( "RemSeer", AccessLevel.Administrator, new CommandEventHandler( RemOverseers_OnCommand ) ); + } + + [Usage( "RemSeers" )] + [Aliases( "RemSeer, RemOverseer, RemOverseers" )] + [Description( "Remove all Overseers in all facets." )] + public static void RemOverseers_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + World.Broadcast( 0x35, true, "Overseers are being removed, please wait." ); + DateTime startTime = DateTime.Now; + int count = 0; + List itemsremove = new List(); + + foreach ( Item itemremove in World.Items.Values ) + { + if ( itemremove is SpawnsOverseer && itemremove.Parent == null ) + { + itemsremove.Add( itemremove ); + count +=1; + } + } + + foreach ( Item itemremove2 in itemsremove ) + { + itemremove2.Delete(); + } + + DateTime endTime = DateTime.Now; + World.Broadcast( 0x35, true, "{0} Overseers has been removed in {1:F1} seconds.", count, (endTime - startTime).TotalSeconds ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/StaticExport.cs b/Scripts/Customs/Nerun's Distro/New/Commands/StaticExport.cs new file mode 100644 index 0000000..fbb1a5b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/StaticExport.cs @@ -0,0 +1,329 @@ +/************************************** +*Script Name: Static Exporter +*Author: Nerun +*Rewritten by: Joeku +*For use with RunUO 2.0 RC2 +*Client Tested with: 6.0.9.1 +*Version: 2.00 +*Initial Release: 04/13/05 +*Revision Date: 08/09/08 +**************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Commands; +using Server.Targeting; +using Server.Engines.Quests.Haven; +using Server.Engines.Quests.Necro; + +namespace Joeku.SE +{ + public class SE_Main + { + public const int Version = 200; // Script version (do not change) + public static string FilePath = @".\Export\"; + + public static void Initialize() + { + CommandSystem.Register("StaticExport" , AccessLevel.Administrator, new CommandEventHandler(StaticExport_OnCommand)); + CommandSystem.Register("StaEx" , AccessLevel.Administrator, new CommandEventHandler(StaticExport_OnCommand)); + } + + [Usage( "StaticExport [string filename]" )] + [Aliases( "StaEx" )] + [Description( "Exports statics to a cfg decoration file." )] + public static void StaticExport_OnCommand(CommandEventArgs e ) + { + if( e.Arguments.Length > 0 ) + BeginStaEx(e.Mobile, e.ArgString ); + else + e.Mobile.SendMessage("Format: StaticExport [string filename]" ); + } + + public static void BeginStaEx(Mobile mob, string file ) + { + BoundingBoxPicker.Begin(mob, new BoundingBoxCallback(StaExBox_Callback), new object[]{ file }); + } + + private static void StaExBox_Callback(Mobile mob, Map map, Point3D start, Point3D end, object state) + { + object[] states = (object[])state; + string file = (string)states[0]; + + Export(mob, file, new Rectangle2D(new Point2D(start.X, start.Y), new Point2D(end.X+1, end.Y+1))); + } + + private static void Export(Mobile mob, string file, Rectangle2D rect) + { + Map map = mob.Map; + + if( !Directory.Exists(FilePath) ) + Directory.CreateDirectory(FilePath); + + using(StreamWriter op = new StreamWriter(String.Format(@".\Export\{0}.cfg", file))) + { + + mob.SendMessage("Exporting statics..."); + + op.WriteLine("# Saved By Static Exporter"); + op.WriteLine("# StaticExport by Nerun"); + op.WriteLine("# Rewritten by Joeku"); + op.WriteLine(); + + IPooledEnumerable eable = mob.Map.GetItemsInBounds(rect); + int i = 0; + + try + { + foreach(Item item in eable) + { + if( item == null || item.Deleted ) + continue; + if( item is AddonComponent ) + continue; + + string s = Construct(item); + if( !s.Substring(0, s.IndexOf(' ')+1).Contains("+") ) // Make sure this isn't an InternalItem of a class... + { + op.WriteLine(s); + op.WriteLine("{0} {1} {2}", item.X, item.Y, item.Z); + op.WriteLine(); + i++; + } + } + + mob.SendMessage("You exported {0} statics from this facet.", i); + } + catch(Exception e){ mob.SendMessage(e.Message); } + + eable.Free(); + } + } + + public static List List = new List(); + + public static void Add(string s){ Add(s, ""); } + public static void Add(string s1, string s2) + { + List.Add(new string[]{s1, s2}); + } + + public static string Construct(Item item) + { + string s; + + int itemID = item.ItemID; + + if( item is BaseAddon ) + for( int i = 0; i < ((BaseAddon)item).Components.Count; i++ ) + if( ((BaseAddon)item).Components[i].Offset == Point3D.Zero ) + { + itemID = ((BaseAddon)item).Components[i].ItemID; + break; + } + + if( item is LocalizedStatic ) + Add("LabelNumber", ((LocalizedStatic)item).Number.ToString()); + else if( item is LocalizedSign ) + Add("LabelNumber", ((LocalizedSign)item).Number.ToString()); + else if( item is AnkhWest ) + Add("Bloodied", (item.ItemID == 0x1D98).ToString()); + else if( item is AnkhNorth ) + Add("Bloodied", (item.ItemID == 0x1E5D).ToString()); + else if( item is MarkContainer ) + { + Add("Bone", ((MarkContainer)item).Bone.ToString()); + Add("Locked", ((MarkContainer)item).AutoLock.ToString()); + if( ((MarkContainer)item).TargetMap != null ) + Add("TargetMap", ((MarkContainer)item).TargetMap.ToString()); + } + else if( item is WarningItem ) + { + Add("Range", ((WarningItem)item).Range.ToString()); + if( VS(((WarningItem)item).WarningString) ) + Add("WarningString", ((WarningItem)item).WarningString); + Add("WarningNumber", ((WarningItem)item).WarningNumber.ToString()); + if( item is HintItem ) + { + if( VS(((HintItem)item).HintString) ) + Add("HintString", ((HintItem)item).HintString); + Add("HintNumber", ((HintItem)item).HintNumber.ToString()); + } + Add("Range", ((WarningItem)item).ResetDelay.ToString()); + } + else if( item is Cannon ) + Add("CannonDirection", ((Cannon)item).CannonDirection.ToString()); + else if( item is SerpentPillar ) + { + if( VS(((SerpentPillar)item).Word) ) + Add("Word", ((SerpentPillar)item).Word); + Add("DestStart", ((SerpentPillar)item).Destination.Start.ToString()); + Add("DestEnd", ((SerpentPillar)item).Destination.End.ToString()); + } + else if( item.GetType().IsSubclassOf(typeof(BaseBeverage)) ) + Add("Content", ((BaseBeverage)item).Content.ToString()); + else if( item.GetType().IsSubclassOf(typeof(BaseDoor)) ) + Add("Facing", GetFacing(((BaseDoor)item).Offset).ToString()); + + if( item is MaabusCoffin ) + Add("SpawnLocation", ((MaabusCoffin)item).SpawnLocation.ToString()); + else if( item is BaseLight ) + { + if( !((BaseLight)item).Burning ) + Add("Unlit", String.Empty); + if( !((BaseLight)item).Protected ) + Add("Unprotected", String.Empty); + } + else if( item is Spawner ) + { + Spawner sp = (Spawner)item; + + for(int i = 0; i < sp.SpawnNames.Count; i++) + if( VS(sp.SpawnNames[i]) ) + Add("Spawn", sp.SpawnNames[i]); + // if( sp.MinDelay > TimeSpan.Zero ) + Add("MinDelay", sp.MinDelay.ToString()); + // if( sp.MaxDelay > TimeSpan.Zero ) + Add("MaxDelay", sp.MaxDelay.ToString()); + // if( sp.NextSpawn > TimeSpan.Zero ) + Add("NextSpawn", sp.NextSpawn.ToString()); + // if( sp.Count > 0 ) + Add("Count", sp.Count.ToString()); + // if( sp.Team > 0 ) + Add("Team", sp.Team.ToString()); + // if( sp.HomeRange > 0 ) + Add("HomeRange", sp.HomeRange.ToString()); + // if( sp.Running ) + Add("Running", sp.Running.ToString()); + // if( sp.Group ) + Add("Group", sp.Group.ToString()); + } + else if( item is RecallRune ) + { + RecallRune rune = (RecallRune)item; + + if( VS(rune.Description) ) + Add("Description", rune.Description); + Add("Marked", rune.Marked.ToString()); + if( rune.TargetMap != null ) + Add("TargetMap", rune.TargetMap.ToString()); + Add("Target", rune.Target.ToString()); + } + else if( item is Teleporter ) + { + Teleporter tp = (Teleporter)item; + + if( item is SkillTeleporter ) + { + SkillTeleporter st = (SkillTeleporter)item; + + Add("Skill", st.Skill.ToString()); + // "RequiredFixedPoint" == Required * 0.1 ? + Add("Required", st.Required.ToString()); + if( VS(st.MessageString) ) + Add("MessageString", st.MessageString); + Add("MessageNumber", st.MessageNumber.ToString()); + } + else if( item is KeywordTeleporter ) + { + KeywordTeleporter kt = (KeywordTeleporter)item; + + if( VS(kt.Substring) ) + Add("Substring", kt.Substring); + Add("Keyword", kt.Keyword.ToString()); + Add("Range", kt.Range.ToString()); + } + Add("PointDest", tp.PointDest.ToString()); + if( tp.MapDest != null ) + Add("MapDest", tp.MapDest.ToString()); + Add("Creatures", tp.Creatures.ToString()); + Add("SourceEffect", tp.SourceEffect.ToString()); + Add("DestEffect", tp.DestEffect.ToString()); + Add("SoundID", tp.SoundID.ToString()); + Add("Delay", tp.Delay.ToString()); + } + else if( item is FillableContainer ) + Add("ContentType", ((FillableContainer)item).ContentType.ToString()); + + if( item.Light != LightType.ArchedWindowEast ) + Add("Light", item.Light.ToString()); + if( item.Hue > 0 ) + Add("Hue", item.Hue.ToString()); + if( VS(item.Name) ) + Add("Name", item.Name); + if( item.Amount > 1 ) + Add("Amount", item.Amount.ToString()); + + s = String.Format("{0} {1}", ConstructType(item), itemID); + + if( List.Count > 0 ) + { + s += " ("; + for( int i = 0; i < List.Count; i++ ) + { + if( List[i][1] == String.Empty ) + s += String.Format("{0}{1}", List[i][0], (i < List.Count-1 ? "; " : String.Empty)); + else + s += String.Format("{0}={1}{2}", List[i][0], List[i][1], (i < List.Count-1 ? "; " : String.Empty)); + } + s += ")"; + } + + List.Clear(); + return s; + } + + public static bool VS(string s) + { + if( s == null || s == String.Empty ) + return false; + return true; + } + + public static string ConstructType(Item item) + { + string s = item.GetType().ToString(); + + if( s.LastIndexOf('.') > -1 ) + s = s.Remove(0, s.LastIndexOf('.')+1); + + return s; + } + + public static DoorFacing GetFacing(Point3D p) + { + DoorFacing facing = DoorFacing.WestCW; + for(int i = 0; i < m_Offsets.Length; i++) + { + if( p == m_Offsets[i] ) + { + facing = (DoorFacing)i; + break; + } + } + + return facing; + } + private static Point3D[] m_Offsets = new Point3D[] + { + new Point3D(-1, 1, 0 ), + new Point3D( 1, 1, 0 ), + new Point3D(-1, 0, 0 ), + new Point3D( 1,-1, 0 ), + new Point3D( 1, 1, 0 ), + new Point3D( 1,-1, 0 ), + new Point3D( 0, 0, 0 ), + new Point3D( 0,-1, 0 ), + + new Point3D( 0, 0, 0 ), + new Point3D( 0, 0, 0 ), + new Point3D( 0, 0, 0 ), + new Point3D( 0, 0, 0 ) + }; + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/Toolbar.cs b/Scripts/Customs/Nerun's Distro/New/Commands/Toolbar.cs new file mode 100644 index 0000000..f08a640 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/Toolbar.cs @@ -0,0 +1,1064 @@ +/************************************** +*Script Name: Toolbar * +*Author: Joeku AKA Demortris * +*For use with RunUO 2.0 * +*Client Tested with: 5.0.7.1 * +*Version: 1.3 * +*Initial Release: 08/23/06 * +*Revision Date: 01/22/07 * +*************************************** +*Changed by Nerun * +*For use with RunUO 2.1 and 2.2 * +*Client Tested with: from 7.0.8.2 up * +* to 7.0.18.0 * +**************************************/ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Accounting; +using Server.Commands; +using Server.Gumps; +using Server.Network; + +namespace Joeku +{ + public class ToolbarHelper + { + public static int Version = 130; // Version identification + public static string ReleaseDate = "January 22, 2007"; // release date =D + public static ToolbarInfos Infos = null; // DO NOT CHANGE THIS! Used for the persistance item... + + public static void Initialize() + { + if( Infos == null ) + Infos = new ToolbarInfos(); + + CommandHandlers.Register("Toolbar", AccessLevel.Counselor, new CommandEventHandler(Toolbar_OnCommand)); + EventSink.Login += new LoginEventHandler(OnLogin); + // Talow and AlphaDragon fix 1/3 + // http://www.runuo.com/community/threads/joeku-toolbar-after-gm-death.477771/#post-3722174 + EventSink.PlayerDeath += new PlayerDeathEventHandler(OnPlayerDeath); + } + + /// + /// Sends a toolbar to staff members upon death. + /// + // Talow and AlphaDragon fix 2/3 + public static void OnPlayerDeath(PlayerDeathEventArgs e) + { + if (e.Mobile.AccessLevel >= AccessLevel.Counselor) + { + e.Mobile.CloseGump(typeof(Toolbar)); + object[] arg = new object[] {e.Mobile}; + Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( SendToolbar ), arg); + } + } + + /// + /// Sends a toolbar to staff members upon login. + /// + private static void OnLogin(LoginEventArgs e) + { + if (e.Mobile.AccessLevel >= AccessLevel.Counselor) + { + e.Mobile.CloseGump(typeof(Toolbar)); + SendToolbar(e.Mobile); + } + } + + [Usage("Toolbar")] + public static void Toolbar_OnCommand(CommandEventArgs e) + { + e.Mobile.CloseGump(typeof(Toolbar)); + SendToolbar(e.Mobile); + } + + /// + /// Sends a toolbar to the mobile + /// + public static void SendToolbar(Mobile mob) + { + ToolbarInfo info; + ReadInfo(mob, out info); + + mob.SendGump(new Toolbar(info)); + } + + // Talow and AlphaDragon fix 3/3 + public static void SendToolbar(object state) + { + object[] states = (object[])state; + + Mobile m = (Mobile)states[0]; + SendToolbar(m); + } + + /// + /// Reads the information in the persistance item and exports it into a new ToolbarInfo class. + /// + public static void ReadInfo(Mobile mob, out ToolbarInfo info) + { + EnsureMaxed( mob ); + Account acc = mob.Account as Account; + info = null; + for(int i = 0; i < ToolbarHelper.Infos.Info.Count; i++) + { + if(ToolbarHelper.Infos.Info[i].Account == acc.Username) + info = ToolbarHelper.Infos.Info[i]; + } + if(info == null) + info = ToolbarInfo.CreateNew(mob, acc); + } + + public static void EnsureMaxed( Mobile mob ) + { + //AccessLevel level = (AccessLevel)ToolbarInfo.GetAccess( mob.Account as Account ); + + if( mob.AccessLevel > ((Account)mob.Account).AccessLevel ) + { + mob.Account.AccessLevel = mob.AccessLevel; + //else if( mob.AccessLevel < acc.AccessLevel ) + //mob.AccessLevel = level; + Console.WriteLine("***TOOLBAR*** Account {0}, Mobile {1}: AccessLevel resolved to {2}.", ((Account)mob.Account).Username, mob, mob.AccessLevel ); + } + } + } + + public class ToolbarInfos : Item + { + private List p_ToolbarInfo = new List(); + public List Info{ get{ return p_ToolbarInfo; } set{ p_ToolbarInfo = value; }} + + public ToolbarInfos(){} + + public ToolbarInfos(Serial serial) : base( serial ){} + + public override void Delete(){ return; } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) ToolbarHelper.Version); + + writer.Write((int) Info.Count); + + for(int i = 0; i < Info.Count; i++) + { + ToolbarInfo t = Info[i] as ToolbarInfo; + + // Version 1.3 + writer.Write((int)t.Font ); + writer.Write((bool)t.Phantom ); + writer.Write((bool)t.Stealth ); + writer.Write((bool)t.Reverse ); + writer.Write((bool)t.Lock ); + + // Version 1.0 + writer.Write((string) t.Account); + + writer.Write((int) t.Dimensions.Count); + for(int j = 0; j < t.Dimensions.Count; j++) + writer.Write((int) t.Dimensions[j]); + + writer.Write((int) t.Entries.Count); + for(int k = 0; k < t.Entries.Count; k++) + writer.Write((string) t.Entries[k]); + + writer.Write((int) t.Skin); + + writer.Write((int) t.Points.Count); + for(int l = 0; l < t.Points.Count; l++) + writer.Write((Point3D) t.Points[l]); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + ToolbarHelper.Infos = this; + + int count = reader.ReadInt(); + + // Version 1.3 + int font = 0; + bool phantom = true, stealth = false, reverse = false, locked = true; + + // Version 1.0 + string account; + List dimensions; + List entries; + int subcount, skin; + List points; + for(int i = 0; i < count; i++) + { + switch(version) + { + case 130: + { + font = reader.ReadInt(); + phantom = reader.ReadBool(); + stealth = reader.ReadBool(); + reverse = reader.ReadBool(); + locked = reader.ReadBool(); + goto case 100; + } + default: + case 100: + { + account = reader.ReadString(); + + dimensions = new List(); + + subcount = reader.ReadInt(); + for(int j = 0; j < subcount; j++) + dimensions.Add(reader.ReadInt()); + + entries = new List(); + + subcount = reader.ReadInt(); + for(int k = 0; k < subcount; k++) + entries.Add(reader.ReadString()); + + skin = reader.ReadInt(); + + points = new List(); + + subcount = reader.ReadInt(); + for(int l = 0; l < subcount; l++) + points.Add(reader.ReadPoint3D()); + + break; + } + } + + ToolbarInfo info = new ToolbarInfo(account, dimensions, entries, skin, points, font, new bool[]{ phantom, stealth, reverse, locked }); + } + } + } + + public class ToolbarInfo + { + // Version 1.3 + private int p_Font; + public int Font{ get{ return p_Font; } set{ p_Font = value; }} + private bool p_Phantom; + public bool Phantom{ get{ return p_Phantom; } set{ p_Phantom = value; }} + private bool p_Stealth; + public bool Stealth{ get{ return p_Stealth; } set{ p_Stealth = value; }} + private bool p_Reverse; + public bool Reverse{ get{ return p_Reverse; } set{ p_Reverse = value; }} + private bool p_Lock; + public bool Lock{ get{ return p_Lock; } set{ p_Lock = value; }} + + // Version 1.0 + private string p_Account; + public string Account{ get{ return p_Account; } set{ p_Account = value; }} + + private List p_Dimensions; + public List Dimensions{ get{ return p_Dimensions; } set{ p_Dimensions = value; }} + + private List p_Entries; + public List Entries{ get{ return p_Entries; } set{ p_Entries = value; }} + + private int p_Skin; + public int Skin{ get{ return p_Skin; } set{ p_Skin= value; }} + + private List p_Points; // Marker + public List Points{ get{ return p_Points; } set{ p_Points = value; }} + + public ToolbarInfo(string account, List dimensions, List entries, int skin, List points, int font, bool[] switches ) + { + p_Dimensions = new List(); + p_Entries = new List(); + p_Points = new List(); + + SetAttributes(account, dimensions, entries, skin, points, font, switches); + ToolbarHelper.Infos.Info.Add(this); + } + + /// + /// Sets the attributes of a ToolbarInfo. + /// + public void SetAttributes(string account, List dimensions, List entries, int skin, List points, int font, bool[] switches ) + { + // Version 1.3 + p_Font = font; + p_Phantom = switches[0]; + p_Stealth = switches[1]; + p_Reverse = switches[2]; + p_Lock = switches[3]; + + // Version 1.0 + p_Account = account; + p_Dimensions = dimensions; + p_Entries = entries; + p_Skin = skin; + + p_Points = points; + } + + /// + /// Creates a new ToolbarInfo... + /// + public static ToolbarInfo CreateNew(Mobile mob, Account acc) + { + string account = acc.Username; + int access = (int)mob.AccessLevel; + List dimensions = DefaultDimensions( access ); + List entries = DefaultEntries( access ); + int skin = 0; + List points = new List(); + + for( int i = entries.Count; i <= 135; i++ ) + entries.Add("-*UNUSED*-"); + + return new ToolbarInfo(account, dimensions, entries, skin, points, 0, new bool[]{ true, false, false, true } ); + } + + /// + /// Gets the highest accesslevel of a character on an account. + /// + /*public static int GetAccess( Account acc ) + { + int access = 0; + for( int i = 0; i < 6; i++ ) + { + if( ((Mobile)acc[i]) == null ) + break; + if( (int)((Mobile)acc[i]).AccessLevel > access ) + access = (int)((Mobile)acc[i]).AccessLevel; + } + return access; + }*/ + + /// + /// Calculates the default command entries based on one's AccessLevel. + /// + public static List DefaultEntries( int i ) + { + List entries = new List(); + switch(i) + { + case 0: // Player + break; + case 1: // Counselor + entries.Add(".GMBody"); entries.Add(".StaffRunebook"); entries.Add(".Stuck"); entries.Add(".M Tele"); for( int j = 0; j < 5; j++ ){entries.Add("-");} + entries.Add(".Where"); entries.Add(".who"); entries.Add(".Self Hide"); entries.Add(".Self Unhide"); + break; + case 2: // GameMaster + entries.Add(".GMBody"); entries.Add(".StaffRunebook"); entries.Add(".Props"); entries.Add(".M Tele"); entries.Add(".Where"); entries.Add(".Who"); entries.Add(".Self Hide"); for( int j = 0; j < 2; j++ ){entries.Add("-");} + entries.Add(".SpawnEditor"); entries.Add(".Move"); entries.Add(".M Remove"); entries.Add(".Wipe"); entries.Add(".Kill"); entries.Add(".Recover"); entries.Add(".Self Unhide"); + break; + case 3: // Seer + goto case 2; + case 4: // Administrator + entries.Add(".Admin"); entries.Add(".GMBody"); entries.Add(".StaffRunebook"); entries.Add(".StaEx MyDeco"); entries.Add(".M Tele"); entries.Add(".Where"); entries.Add(".Who"); entries.Add(".Self Hide"); for( int j = 0; j < 1; j++ ){entries.Add("-");} + entries.Add(".PremiumSpawner"); entries.Add(".SpawnEditor"); entries.Add(".Move"); entries.Add(".M Remove"); entries.Add(".Wipe"); entries.Add(".Props"); entries.Add(".Recover"); entries.Add(".Self Unhide"); for( int j = 0; j < 1; j++ ){entries.Add("-");} + entries.Add(".AddonGen"); entries.Add(".Get Location"); entries.Add(".Get ItemID"); entries.Add(".AddDoor"); + break; + case 5: // Developer + goto case 4; + case 6: // Owner + goto case 4; + } + return entries; + } + + public static List DefaultDimensions( int i ) + { + List dimensions = new List(); + switch(i) + { + case 0: // Player + dimensions.Add(0); dimensions.Add(0); + break; + case 1: // Counselor + dimensions.Add(4); dimensions.Add(2); + break; + case 2: // GameMaster + dimensions.Add(7); dimensions.Add(2); + break; + case 3: // Seer + goto case 2; + case 4: // Administrator + dimensions.Add(8); dimensions.Add(3); + break; + case 5: // Developer + goto case 4; + case 6: // Owner + goto case 4; + } + + return dimensions; + } + } + + public class Toolbar : Gump + { + /******************* + * BUTTON ID'S + * 0 - Close + * 1 - Edit + *******************/ + + private ToolbarInfo p_Info; + + // Version 1.3 + private int p_Font; + public int Font{ get{ return p_Font; } set{ p_Font = value; } } + private bool p_Phantom, p_Stealth, p_Reverse, p_Lock; + public bool Phantom{ get{ return p_Phantom; } set{ p_Phantom = value; } } + public bool Stealth{ get{ return p_Stealth; } set{ p_Stealth = value; } } + public bool Reverse{ get{ return p_Reverse; } set{ p_Reverse = value; } } + public bool Lock{ get{ return p_Lock; } set{ p_Lock = value; } } + + // Version 1.0 + private List p_Commands; + private int p_Skin, p_Columns, p_Rows; + + public List Commands{ get{ return p_Commands; } set{ p_Commands = value; } } + public int Skin{ get{ return p_Skin; } set{ p_Skin = value; } } + public int Columns{ get{ return p_Columns; } set{ p_Columns = value; } } + public int Rows{ get{ return p_Rows; } set{ p_Rows = value; } } + + public int InitOptsW, InitOptsH; + + public Toolbar(ToolbarInfo info) : base(0, 28) + { + p_Info = info; + + // Version 1.3 + p_Font = info.Font; + p_Phantom = info.Phantom; + p_Stealth = info.Stealth; + p_Reverse = info.Reverse; + p_Lock = info.Lock; + + // Version 1.0 + p_Commands = info.Entries; + p_Skin = info.Skin; + p_Columns = info.Dimensions[0]; + p_Rows = info.Dimensions[1]; + +//original +// if( Lock ) +// Closable = false; +//AlphaDragon's mod: + if( Lock ) + { + Closable = false; + Disposable = false; + } +//I moded end so that will remain even when editing house + + int offset = GumpIDs.Misc[(int)GumpIDs.MiscIDs.ButtonOffset].Content[p_Skin,0]; + int bx = ((offset * 2) + (Columns * 110)), by = ((offset * 2) + (Rows * 24)), byx = by, cy = 0; + + SetCoords( offset ); + + if( Reverse ) + { + cy = InitOptsH; + by = 0; + } + + AddPage( 0 ); + AddPage( 1 ); + if( Stealth ) + { + AddMinimized( by, offset ); + AddPage( 2 ); + } + + AddInitOpts( by, offset ); + + AddBackground(0, cy, bx, byx, GumpIDs.Misc[(int)GumpIDs.MiscIDs.Background].Content[p_Skin,0]); + + string font = GumpIDs.Fonts[Font]; + if( Phantom ) + font += ""; + + int temp = 0, x = 0, y = 0; + for(int i = 0; i < Columns*Rows; i++) + { + x = offset + ((i % Columns) * 110); + y = offset + (int)(Math.Floor((double)(i / Columns)) * 24) + cy; + AddButton(x + 1, y, 2445, 2445, temp + 10, GumpButtonType.Reply, 0); + AddBackground(x, y, 110, 24, GumpIDs.Misc[(int)GumpIDs.MiscIDs.Buttonground].Content[p_Skin,0]); + + if( Phantom ) + { + AddImageTiled( x + 2, y + 2, 106, 20, 2624 ); // Alpha Area 1_1 + AddAlphaRegion( x + 2, y + 2, 106, 20 ); // Alpha Area 1_2 + } + + AddHtml( x + 5, y + 3, 100, 20, String.Format( "
{0}{1}", font, Commands[temp]), false, false ); + //AddLabelCropped(x + 5, y + 3, 100, 20, GumpIDs.Misc[(int)GumpIDs.MiscIDs.Color].Content[p_Skin,0], Commands[temp]); + + if( i%Columns == Columns-1 ) + temp += 9-Columns; + temp++; + } + + /*TEST--- + 0%5 == 0 + 1%5 == 1 + 2%5 == 2 + 3%5 == 3 + 4%5 == 4 + 5%5 == 0 + END TEST---*/ + + if( !Stealth ) + { + AddPage(2); + AddMinimized( by, offset ); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile mob = sender.Mobile; + + switch(info.ButtonID) + { + default: // Command + mob.SendGump(this); + if(Commands[info.ButtonID - 10].StartsWith(CommandSystem.Prefix)) + { + mob.SendMessage( Commands[info.ButtonID - 10]); + CommandSystem.Handle(mob, Commands[info.ButtonID - 10]); + } + else + { + //SpeechEventArgs args = new SpeechEventArgs( mob, Commands[info.ButtonID - 10], MessageType.Regular, mob.SpeechHue, null ); + mob.DoSpeech( Commands[info.ButtonID - 10], new int[0], MessageType.Regular, mob.SpeechHue ); + //mob.Say(Commands[info.ButtonID - 10]); + } + break; + case 0: // Close + break; + case 1: // Edit + mob.SendGump(this); + mob.CloseGump( typeof( ToolbarEdit ) ); + mob.SendGump(new ToolbarEdit( p_Info )); + break; + } + } + + /// + /// Sets coordinates and sizes. + /// + public void SetCoords( int offset ) + { + InitOptsW = 50 + (offset * 2) + GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Minimize].Content[p_Skin,2] + 5 + GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,2]; + InitOptsH = (offset * 2) + GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Minimize].Content[p_Skin,3]; + if(GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,3] + (offset * 2) > InitOptsH) + InitOptsH = GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,3] + (offset * 2); + } + + /// + /// Adds initial options. + /// + public void AddInitOpts( int y, int offset ) + { + AddBackground(0, y, InitOptsW, InitOptsH, GumpIDs.Misc[(int)GumpIDs.MiscIDs.Background].Content[p_Skin,0]); + AddButton(offset, y + offset, GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Minimize].Content[p_Skin,0], GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Minimize].Content[p_Skin,1], 0, GumpButtonType.Page, Stealth ? 1 : 2); + AddButton(offset + GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Minimize].Content[p_Skin,2] + 5, y + offset, GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,0], GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,1], 1, GumpButtonType.Reply, 0); // 1 Edit + } + + /// + /// Adds minimized page. + /// + public void AddMinimized( int y, int offset ) + { + AddBackground(0, y, InitOptsW, InitOptsH, GumpIDs.Misc[(int)GumpIDs.MiscIDs.Background].Content[p_Skin,0]); + AddButton(offset, y + offset, GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Maximize].Content[p_Skin,0], GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Maximize].Content[p_Skin,1], 0, GumpButtonType.Page, Stealth ? 2 : 1); + AddButton(offset + GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Minimize].Content[p_Skin,2] + 5, y + offset, GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,0], GumpIDs.Buttons[(int)GumpIDs.ButtonIDs.Customize].Content[p_Skin,1], 1, GumpButtonType.Reply, 0); // 1 Edit + } + } + + public class ToolbarEdit : Gump + { + public static string HTML = String.Format( "
Command Toolbar v{0}
Made by Joeku AKA Demortris
{1}
- Customized to Nerun's Distro -

This toolbar is extremely versatile. You can switch skins and increase or decrease columns or rows. The toolbar operates like a spreadsheet; you can use the navigation menu to scroll through different commands and bind them. Enjoy!

If you have questions, concerns, or bug reports, please e-mail me.", ((double)ToolbarHelper.Version) / 100, ToolbarHelper.ReleaseDate); + private bool p_Expanded; + private int p_ExpandedInt; + + private int p_Font; + public int Font{ get{ return p_Font; } set{ p_Font = value; } } + + private bool p_Phantom, p_Stealth, p_Reverse, p_Lock; + public bool Phantom{ get{ return p_Phantom; } set{ p_Phantom = value; } } + public bool Stealth{ get{ return p_Stealth; } set{ p_Stealth = value; } } + public bool Reverse{ get{ return p_Reverse; } set{ p_Reverse = value; } } + public bool Lock{ get{ return p_Lock; } set{ p_Lock = value; } } + + private List p_Commands; + private int p_Skin, p_Columns, p_Rows; + private ToolbarInfo p_Info; + private List TextRelays = null; + + public List Commands{ get{ return p_Commands; } set{ p_Commands = value; } } + public int Skin{ get{ return p_Skin; } set{ p_Skin = value; } } + public int Columns{ get{ return p_Columns; } set{ p_Columns = value; } } + public int Rows{ get{ return p_Rows; } set{ p_Rows = value; } } + + public ToolbarEdit( ToolbarInfo info ) : this( info, false ){} + public ToolbarEdit( ToolbarInfo info, bool expanded ) : this( info, expanded, info.Entries, info.Skin, info.Dimensions[0], info.Dimensions[1], info.Font, new bool[]{ info.Phantom, info.Stealth, info.Reverse, info.Lock } ){} + + public ToolbarEdit( ToolbarInfo info, List commands, int skin, int columns, int rows, int font, bool[] switches ) : this( info, false, commands, skin, columns, rows, font, switches ){} + public ToolbarEdit( ToolbarInfo info, bool expanded, List commands, int skin, int columns, int rows, int font, bool[] switches ) : base(0, 28) + { + p_Info = info; + p_Expanded = expanded; + p_ExpandedInt = expanded ? 2 : 1; + + p_Font = font; + p_Phantom = switches[0]; + p_Stealth = switches[1]; + p_Reverse = switches[2]; + p_Lock = switches[3]; + + p_Commands = commands; + p_Skin = skin; + p_Columns = columns; + p_Rows = rows; + + AddInit(); + AddControls(); + AddNavigation(); + AddResponses(); + AddEntries(); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile m = sender.Mobile; + TextRelays = CreateList( info.TextEntries ); + + + bool[] switches = new bool[4] + { + info.IsSwitched( 21 ), + info.IsSwitched( 23 ), + info.IsSwitched( 25 ), + info.IsSwitched( 27 ) + }; + + switch( info.ButtonID ) + { + case 0: break; + case 1: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin + 1, Columns, Rows, Font, switches )); break; + case 2: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin - 1, Columns, Rows, Font, switches )); break; + case 3: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows + 1, Font, switches )); break; + case 4: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows - 1, Font, switches )); break; + case 5: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns + 1, Rows, Font, switches )); break; + case 6: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns - 1, Rows, Font, switches )); break; + //case 7: + //m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font, switches )); + //m.SendMessage( 32, "The Marker utility is not an active feature yet; please be patient." ); + //goto case 0; + case 9: // Default + List toolbarinfo = ToolbarInfo.DefaultEntries( (int)m.AccessLevel ); + CombineEntries( toolbarinfo ); + toolbarinfo.AddRange( AnalyzeEntries( toolbarinfo.Count ) ); + m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, toolbarinfo, Skin, Columns, Rows, Font, switches )); + break; + case 10: // Okay + goto case 12; + case 11: // Cancel + goto case 0; + case 12: // Apply + Account acc = m.Account as Account; + ToolbarInfo infos = null; + for(int i = 0; i < ToolbarHelper.Infos.Info.Count; i++) + { + if(ToolbarHelper.Infos.Info[i].Account == acc.Username) + infos = ToolbarHelper.Infos.Info[i]; + } + if(infos == null) + infos = ToolbarInfo.CreateNew(m, acc); + List dims = new List(); + dims.Add( Columns ); + dims.Add( Rows ); + + infos.SetAttributes(acc.Username, dims, AnalyzeEntries(), Skin, infos.Points, Font, switches ); + + if( info.ButtonID == 12 ) + m.SendGump( new ToolbarEdit( infos, this.p_Expanded ) ); + m.CloseGump( typeof( Toolbar ) ); + m.SendGump( new Toolbar( infos ) ); + break; + case 18: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font + 1, switches )); break; + case 19: m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font - 1, switches )); break; + case 20: + m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font, switches )); + m.SendMessage( 2101, "Phantom mode turns the toolbar semi-transparent." ); + break; + case 22: + m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font, switches )); + m.SendMessage( 2101, "Stealth mode makes the toolbar automatically minimize when you click a button." ); + break; + case 24: + m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font, switches )); + m.SendMessage( 2101, "Reverse mode puts the minimize bar above the toolbar instead of below." ); + break; + case 26: + m.SendGump( new ToolbarEdit( p_Info, this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font, switches )); + m.SendMessage( 2101, "Lock mode disables closing the toolbar with right-click." ); + break; + case 28: // Expand + m.SendGump( new ToolbarEdit( p_Info, !this.p_Expanded, AnalyzeEntries(), Skin, Columns, Rows, Font, switches )); + m.SendMessage( 2101, "Expanded view {0}activated.", this.p_Expanded ? "de" : "" ); + break; + } + } + + ///

+ /// Takes the gump relay entries and converts them from an Array into a List. + /// + public static List CreateList( TextRelay[] entries ) + { + List list = new List(); + for( int i = 0; i < entries.Length; i++ ) + list.Add( entries[i] ); + + return list; + } + + public void CombineEntries( List list ) + { + string temp; + for( int i = 0; i < list.Count; i++ ) + { + if( list[i] == "-*UNUSED*-" && (temp = GetEntry( i+13, this ).Text) != "" ) + list[i] = temp; + } + } + + public List AnalyzeEntries() + { return AnalyzeEntries( 0 ); } + + /// + /// Organizes the gump relay entries into a usable collection. + /// + public List AnalyzeEntries( int i ) + { + List list = new List(); + + string temp; + for( int j = i; j < 135; j++ ) + { + if( (temp = GetEntry( j+13, this ).Text) == "" ) + list.Add( "-*UNUSED*-" ); + else + list.Add( temp ); + } + + return list; + } + + /// + /// Gets entry # in the gump relay. + /// + public static TextRelay GetEntry( int entryID, ToolbarEdit gump ) + { + int temp = 0; + TextRelay relay = null; + for( int i = 0; i < gump.TextRelays.Count; i++ ) + { + if( gump.TextRelays[i].EntryID == entryID ) + { + temp = i; + relay = gump.TextRelays[i]; + } + } + gump.TextRelays.RemoveAt( temp ); + return relay; + } + + /// + /// Adds the skeleton gump. + /// + public void AddInit() + { + AddPage(0); + AddBackground(0, 0, 620, 120, 9200); + AddHtml(10, 10, 240, 100, HTML, true, true); + } + + /// + /// Adds other dynamic options. + /// + public void AddControls() + { + AddBackground(260, 0, 240, 120, 9200); + AddLabel(274, 11, 0, String.Format("Skin - {0}", p_Skin + 1 )); + if( p_Skin < GumpIDs.Skins - 1 ) + AddButton(359, 10, 2435, 2436, 1, GumpButtonType.Reply, 0); + if( p_Skin > 0 ) + AddButton(359, 21, 2437, 2438, 2, GumpButtonType.Reply, 0); + AddLabel(274, 36, 0, String.Format("Rows - {0}", p_Rows )); + if( p_Rows < 15 ) + AddButton(359, 35, 2435, 2436, 3, GumpButtonType.Reply, 0); + if( p_Rows > 1 ) + AddButton(359, 46, 2437, 2438, 4, GumpButtonType.Reply, 0); + AddLabel(274, 61, 0, String.Format("Columns - {0}", p_Columns )); + if( p_Columns < 9 ) + AddButton(359, 60, 2435, 2436, 5, GumpButtonType.Reply, 0); + if( p_Columns > 1 ) + AddButton(359, 71, 2437, 2438, 6, GumpButtonType.Reply, 0); + + AddHtml( 276, 87, 100, 20, String.Format("{0}Font - {1}", GumpIDs.Fonts[p_Font], p_Font+1), false, false ); + if( p_Font < GumpIDs.Fonts.Length-1 ) + AddButton(359, 85, 2435, 2436, 18, GumpButtonType.Reply, 0); + if( p_Font > 0 ) + AddButton(359, 96, 2437, 2438, 19, GumpButtonType.Reply, 0); + + + /*AddLabel(274, 86, 0, "Marker"); + AddButton(326, 88, 22153, 22155, 7, GumpButtonType.Reply, 0); + AddCheck(349, 86, 210, 211, true, 8); */ + + // Version 1.3 + AddLabel(389, 11, 0, "Phantom"); + AddButton(446, 13, 22153, 22155, 20, GumpButtonType.Reply, 0); + AddCheck(469, 11, 210, 211, Phantom, 21); + AddLabel(389, 36, 0, "Stealth"); + AddButton(446, 38, 22153, 22155, 22, GumpButtonType.Reply, 0); + AddCheck(469, 36, 210, 211, Stealth, 23); + AddLabel(389, 61, 0, "Reverse"); + AddButton(446, 63, 22153, 22155, 24, GumpButtonType.Reply, 0); + AddCheck(469, 61, 210, 211, Reverse, 25); + AddLabel(389, 86, 0, "Lock"); + AddButton(446, 88, 22153, 22155, 26, GumpButtonType.Reply, 0); + AddCheck(469, 86, 210, 211, Lock, 27); + } + + /// + /// Adds the skeleton navigation section. + /// + public void AddNavigation() + { + AddBackground(500, 0, 120, 120, 9200); + AddHtml(500, 10, 120, 20, @"
Navigation
", false, false); + AddLabel( 508, 92, 0, "Expanded View" ); + AddButton( 595, 95, this.p_Expanded ? 5603 : 5601, this.p_Expanded ? 5607 : 5605, 28, GumpButtonType.Reply, 0 ); + } + + /// + /// Adds response buttons. + /// + public void AddResponses() + { + int temp = 170 + (p_ExpandedInt * 100); + AddBackground(0, temp, 500, 33, 9200); + AddButton( 50, temp + 5, 246, 244, 9, GumpButtonType.Reply, 0 ); // Default + AddButton( 162, temp + 5, 249, 248, 10, GumpButtonType.Reply, 0 ); // Okay + AddButton( 275, temp + 5, 243, 241, 11, GumpButtonType.Reply, 0 ); // Cancel + AddButton( 387, temp + 5, 239, 240, 12, GumpButtonType.Reply, 0 ); // Apply + } + + /// + /// Adds the actual command/phrase entries. + /// + public void AddEntries() + { + int buffer = 2; + // CALC + int entryX = p_ExpandedInt * 149, entryY = p_ExpandedInt * 20; + int bgX = 10 + 4 + (buffer * 3) + (entryX * 3), bgY = 10 + 8 + (entryY * 5); + int divX = bgX - 10, divY = bgY - 10; + // ENDCALC + + AddBackground(0, 120, 33 + bgX, 32 + bgY, 9200); + + AddBackground(33, 152, bgX, bgY, 9200); + + // Add vertical dividers + for( int m = 1; m <= 2; m++ ) + AddImageTiled( 38 + ( m * entryX ) + buffer + ((m-1)*4), 157, 2, divY, 10004); + + // Add horizontal dividers + for( int n = 1; n <= 4; n++ ) + AddImageTiled( 38, 155 + (n * ( entryY + 2)), divX, 2, 10001); + + int start = -3, temp = 0; + + for( int i = 1; i <= 9; i++ ) + { + start += 3; + if( i == 4 ) + start = 45; + else if( i == 7 ) + start = 90; + temp = start; + /******** + * PAGES * + *-------* + * 1 2 3 * + * 4 5 6 * + * 7 8 9 * + ********/ + + AddPage(i); + CalculatePages(i); + + // Add column identifiers + for( int j = 0; j < 3; j++ ) + AddHtml( 38 + buffer + ((j % 3) * (buffer + entryX + 2)), 128, entryX, 20, String.Format("
Column {0}
", (j+1) + CalculateColumns(i) ), false, false); + + AddHtml( 2, 128, 30, 20, "
Row
", false, false ); + + int tempInt = 0; + if( p_Expanded ) + tempInt = 11; + // Add row identifiers + for( int k = 0; k < 5; k++ ) + AddHtml(0, 157 + (k * (entryY + 2)) + tempInt, 32, 20, String.Format("
{0}
", (k+1) + CalculateRows(i) ), false, false); + + // Add command entries + for( int l = 0; l < 15; l++ ) + { + AddTextEntry( 38 + buffer + ((l % 3) * ((buffer*2) + entryX )), 157 + ((int)Math.Floor((double)l / 3) * (entryY + 2)), entryX-1, entryY, 2101, temp+13, Commands[temp] /*,int size*/); + + if( l%3 == 2 ) + temp += 6; + temp++; + } + } + } + + /// + /// Calculates what navigation button takes you to what page. + /// + public void CalculatePages( int i ) + { + int up = 0, down = 0, left = 0, right = 0; + switch( i ) + { + case 1: down = 4; right = 2; break; + case 2: down = 5; left = 1; right = 3; break; + case 3: down = 6; left = 2; break; + case 4: up = 1; down = 7; right = 5; break; + case 5: up = 2; down = 8; left = 4; right = 6; break; + case 6: up = 3; down = 9; left = 5; break; + case 7: up = 4; right = 8; break; + case 8: up = 5; left = 7; right = 9; break; + case 9: up = 6; left = 8; break; + } + + AddNavigation( up, down, left, right ); + } + + /// + /// Adds navigation buttons for each page. + /// + public void AddNavigation( int up, int down, int left, int right ) + { + if( up > 0 ) + AddButton(549, 34, 9900, 9902, 0, GumpButtonType.Page, up); + if( down > 0 ) + AddButton(549, 65, 9906, 9908, 0, GumpButtonType.Page, down); + if( left > 0 ) + AddButton(523, 50, 9909, 9911, 0, GumpButtonType.Page, left); + if( right > 0 ) + AddButton(575, 50, 9903, 9905, 0, GumpButtonType.Page, right); + } + + /// + /// Damn I've forgotten... + /// + public static int CalculateColumns( int i ) + { + if( i == 1 || i == 4 || i == 7 ) + return 0; + else if( i == 2 || i == 5 || i == 8 ) + return 3; + else + return 6; + } + + /// + /// Same as above! =( + /// + public static int CalculateRows( int i ) + { + if( i >= 1 && i <= 3 ) + return 0; + else if( i >= 4 && i <= 6 ) + return 5; + else + return 10; + } + } + + public class GumpIDs + { + public enum MiscIDs + { + Background = 0, + Color = 1, + Buttonground = 2, + ButtonOffset = 3, + } + + public enum ButtonIDs + { + Minimize = 0, + Maximize = 1, + Customize = 2, + SpecialCommand = 3, + + Send = 4, + Teleport = 5, + Gate = 6, + } + + private int p_ID; + public int ID{ get{ return p_ID; } set{ p_ID = value; }} + private int[,] p_Content; + public int[,] Content{ get{ return p_Content; } set{ p_Content = value; }} + private string p_Name; + public string Name{ get{ return p_Name; } set{ p_Name = value; }} + + public GumpIDs(int iD, string name, int[,] content) + { + p_ID = iD; + p_Content = content; + p_Name = name; + } + + private static string[] p_Fonts = new string[] + { "", "", "", "", "", "", "", "", "", "", "", "" }; + public static string[] Fonts{ get{ return p_Fonts; } set{ p_Fonts = value; }} + + public static int Skins = 2; + private static GumpIDs[] m_Misc = new GumpIDs[] + { + new GumpIDs( 0, "Background", new int[2,1]{{ 9200 }, { 9270 }}), + new GumpIDs( 1, "Color", new int[2,1]{{ 0 }, { 0 }}), + new GumpIDs( 2, "Buttonground", new int[2,1]{{ 9200 }, { 9350 }}), + new GumpIDs( 3, "ButtonOffset", new int[2,1]{{ 5 }, { 7 }}), + }; + public static GumpIDs[] Misc{ get{ return m_Misc; } set{ m_Misc = value; }} + + private static GumpIDs[] m_Buttons = new GumpIDs[] + { + new GumpIDs( 0, "Minimize", new int[2,4]{{ 5603, 5607, 16, 16 }, { 5537, 5539, 19, 21 }}), + new GumpIDs( 1, "Maximize", new int[2,4]{{ 5601, 5605, 16, 16 }, { 5540, 5542, 19, 21 }}), + new GumpIDs( 2, "Customize", new int[2,4]{{ 22153, 22155, 16, 16 }, { 5525, 5527, 62, 24 }}), + new GumpIDs( 3, "SpecialCommand", new int[2,4]{{ 2117, 2118, 15, 15 }, { 9720, 9722, 29, 29 }}), + + new GumpIDs( 4, "Send", new int[2,4]{{ 2360, 2360, 11, 11 }, { 2360, 2360, 11, 11 }}), + new GumpIDs( 5, "Teleport", new int[2,4]{{ 2361, 2361, 11, 11 }, { 2361, 2361, 11, 11 }}), + new GumpIDs( 6, "Gate", new int[2,4]{{ 2362, 2362, 11, 11 }, { 2361, 2361, 11, 11 }}), + }; + public static GumpIDs[] Buttons{ get{ return m_Buttons; } set{ m_Buttons = value; }} + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/UnloadMaps.cs b/Scripts/Customs/Nerun's Distro/New/Commands/UnloadMaps.cs new file mode 100644 index 0000000..ff5d863 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/UnloadMaps.cs @@ -0,0 +1,388 @@ +// Engine r63 +#define RunUo2_0 +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class UnloadCurrentGump : Gump + { + Mobile caller; + + public static void Initialize() + { +#if(RunUo2_0) + CommandSystem.Register("UnloadCurrent", AccessLevel.Administrator, new CommandEventHandler(UnloadCurrent_OnCommand)); +#else + Register("UnloadCurrent", AccessLevel.Administrator, new CommandEventHandler(UnloadCurrent_OnCommand)); +#endif + } + + [Usage("UnloadCurrent")] + [Description("Unload PremiumSpawners around the world with a gump.")] + public static void UnloadCurrent_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from.HasGump(typeof(UnloadCurrentGump))) + from.CloseGump(typeof(UnloadCurrentGump)); + from.SendGump(new UnloadCurrentGump(from)); + } + + public UnloadCurrentGump(Mobile from) : this() + { + caller = from; + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public UnloadCurrentGump() : base( 30, 30 ) + { + this.Closable=true; + this.Disposable=true; + this.Dragable=true; + AddPage(1); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO UNLOAD"); + AddBlackAlpha(66, 87, 239, 447); + AddLabel(69, 67, 200, @"DUNGEONS"); + AddLabel(69, 90, 52, @"Blighted Grove"); + AddLabel(69, 112, 52, @"Britain Sewer"); + AddLabel(69, 133, 52, @"Covetous"); + AddLabel(69, 154, 52, @"Deceit"); + AddLabel(69, 174, 52, @"Despise"); + AddLabel(69, 196, 52, @"Destard"); + AddLabel(69, 217, 52, @"Fire"); + AddLabel(69, 237, 52, @"Graveyards"); + AddLabel(69, 258, 52, @"Hythloth"); + AddLabel(69, 280, 52, @"Ice"); + AddLabel(69, 301, 52, @"Khaldun"); + AddLabel(69, 322, 52, @"Orc Caves"); + AddLabel(69, 343, 52, @"Painted Caves"); + AddLabel(69, 363, 52, @"Palace of Paroxysmus"); + AddLabel(69, 384, 52, @"Prism of Light"); + AddLabel(69, 405, 52, @"Sanctuary"); + AddLabel(69, 427, 52, @"Shame"); + AddLabel(69, 448, 52, @"Solen Hive"); + AddLabel(69, 469, 52, @"Terathan Keep"); + AddLabel(69, 489, 52, @"Trinsic Passage"); + AddLabel(69, 510, 52, @"Wrong"); + AddLabel(194, 66, 200, @"Felucca"); + AddCheck(210, 91, 210, 211, true, 201); + AddCheck(210, 112, 210, 211, true, 202); + AddCheck(210, 133, 210, 211, true, 203); + AddCheck(210, 154, 210, 211, true, 204); + AddCheck(210, 175, 210, 211, true, 205); + AddCheck(210, 196, 210, 211, true, 206); + AddCheck(210, 217, 210, 211, true, 207); + AddCheck(210, 238, 210, 211, true, 208); + AddCheck(210, 259, 210, 211, true, 209); + AddCheck(210, 280, 210, 211, true, 210); + AddCheck(210, 301, 210, 211, true, 228); + AddCheck(210, 322, 210, 211, true, 212); + AddCheck(210, 343, 210, 211, true, 214); + AddCheck(210, 364, 210, 211, true, 215); + AddCheck(210, 385, 210, 211, true, 216); + AddCheck(210, 406, 210, 211, true, 217); + AddCheck(210, 427, 210, 211, true, 219); + AddCheck(210, 448, 210, 211, true, 220); + AddCheck(210, 469, 210, 211, true, 221); + AddCheck(210, 490, 210, 211, true, 224); + AddCheck(210, 511, 210, 211, true, 227); + AddLabel(250, 66, 200, @"Trammel"); + AddCheck(268, 91, 210, 211, true, 101); + AddCheck(268, 112, 210, 211, true, 102); + AddCheck(268, 133, 210, 211, true, 103); + AddCheck(268, 154, 210, 211, true, 104); + AddCheck(268, 175, 210, 211, true, 105); + AddCheck(268, 196, 210, 211, true, 106); + AddCheck(268, 217, 210, 211, true, 107); + AddCheck(268, 238, 210, 211, true, 108); + AddCheck(268, 259, 210, 211, true, 109); + AddCheck(268, 280, 210, 211, true, 110); + //There is no Khaldun in Trammel (ID 128 reserved) + AddCheck(268, 322, 210, 211, true, 112); + AddCheck(268, 343, 210, 211, true, 114); + AddCheck(268, 364, 210, 211, true, 115); + AddCheck(268, 385, 210, 211, true, 116); + AddCheck(268, 406, 210, 211, true, 117); + AddCheck(268, 427, 210, 211, true, 119); + AddCheck(268, 448, 210, 211, true, 120); + AddCheck(268, 469, 210, 211, true, 121); + AddCheck(268, 490, 210, 211, true, 124); + AddCheck(268, 511, 210, 211, true, 127); + AddBlackAlpha(311, 87, 213, 70); + AddLabel(315, 67, 200, @"TOWNS"); + AddLabel(315, 91, 52, @"Animals"); + AddLabel(315, 112, 52, @"People (*)"); + AddLabel(315, 133, 52, @"Vendors"); + AddLabel(413, 66, 200, @"Felucca"); + AddCheck(429, 91, 210, 211, true, 222); + AddCheck(429, 112, 210, 211, true, 223); + AddCheck(429, 133, 210, 211, true, 225); + AddLabel(469, 66, 200, @"Trammel"); + AddCheck(487, 91, 210, 211, true, 122); + AddCheck(487, 112, 210, 211, true, 123); + AddCheck(487, 133, 210, 211, true, 125); + AddBlackAlpha(311, 183, 213, 114); + AddLabel(315, 162, 200, @"OUTDOORS"); + AddLabel(316, 187, 52, @"Animals"); + AddLabel(316, 207, 52, @"Lost Lands"); + AddLabel(316, 229, 52, @"Monsters"); + AddLabel(316, 249, 52, @"Reagents"); + AddLabel(316, 270, 52, @"Sea Life"); + AddLabel(413, 162, 200, @"Felucca"); + AddCheck(429, 187, 210, 211, true, 226); + AddCheck(429, 208, 210, 211, true, 211); + AddCheck(429, 229, 210, 211, true, 213); + AddCheck(429, 250, 210, 211, true, 229); + AddCheck(429, 271, 210, 211, true, 218); + AddLabel(469, 162, 200, @"Trammel"); + AddCheck(487, 187, 210, 211, true, 126); + AddCheck(487, 208, 210, 211, true, 111); + AddCheck(487, 229, 210, 211, true, 113); + AddCheck(487, 250, 210, 211, true, 129); + AddCheck(487, 271, 210, 211, true, 118); + AddLabel(316, 305, 200, @"(*) Escortables, Hireables,"); + AddLabel(316, 324, 200, @"Town Criers, Order and Chaos"); + AddLabel(316, 344, 200, @"guards etc."); + // END + AddLabel(361, 453, 52, @"Page: 1/2"); //Page + AddButton(423, 455, 5601, 5605, 0, GumpButtonType.Page, 2); // Change Page + + //PAGE 2 + AddPage(2); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO SPAWN"); + AddBlackAlpha(66, 87, 174, 300); + AddLabel(74, 67, 200, @"ILSHENAR"); + AddLabel(74, 90, 52, @"Ancient Lair"); + AddLabel(74, 112, 52, @"Ankh"); + AddLabel(74, 133, 52, @"Blood"); + AddLabel(74, 154, 52, @"Exodus"); + AddLabel(74, 174, 52, @"Mushroom"); + AddLabel(74, 196, 52, @"Outdoors"); + AddLabel(74, 217, 52, @"Ratman Cave"); + AddLabel(74, 237, 52, @"Rock"); + AddLabel(74, 258, 52, @"Sorcerers"); + AddLabel(74, 280, 52, @"Spectre"); + AddLabel(74, 301, 52, @"Towns"); + AddLabel(74, 322, 52, @"Twisted Weald"); + AddLabel(74, 343, 52, @"Vendors"); + AddLabel(74, 363, 52, @"Wisp"); + AddCheck(215, 91, 210, 211, true, 301); + AddCheck(215, 112, 210, 211, true, 302); + AddCheck(215, 133, 210, 211, true, 303); + AddCheck(215, 154, 210, 211, true, 304); + AddCheck(215, 175, 210, 211, true, 305); + AddCheck(215, 196, 210, 211, true, 306); + AddCheck(215, 217, 210, 211, true, 307); + AddCheck(215, 238, 210, 211, true, 308); + AddCheck(215, 259, 210, 211, true, 309); + AddCheck(215, 280, 210, 211, true, 310); + AddCheck(215, 301, 210, 211, true, 311); + AddCheck(215, 322, 210, 211, true, 314); + AddCheck(215, 343, 210, 211, true, 312); + AddCheck(215, 364, 210, 211, true, 313); + AddBlackAlpha(66, 414, 174, 133); + AddLabel(74, 393, 200, @"TOKUNO"); + AddLabel(74, 416, 52, @"Fan Dancers Dojo"); + AddLabel(74, 438, 52, @"Outdoors"); + AddLabel(74, 459, 52, @"Towns Life"); + AddLabel(74, 480, 52, @"Vendors"); + AddLabel(74, 500, 52, @"Wild Life"); + AddLabel(74, 522, 52, @"Yomutso Mines"); + AddCheck(215, 417, 210, 211, true, 501); + AddCheck(215, 438, 210, 211, true, 502); + AddCheck(215, 459, 210, 211, true, 503); + AddCheck(215, 480, 210, 211, true, 504); + AddCheck(215, 501, 210, 211, true, 505); + AddCheck(215, 522, 210, 211, true, 506); + AddBlackAlpha(246, 87, 174, 156); + AddLabel(253, 67, 200, @"MALAS"); + AddLabel(253, 90, 52, @"Citadel"); + AddLabel(253, 112, 52, @"Doom"); + AddLabel(253, 133, 52, @"Labyrinth"); + AddLabel(253, 154, 52, @"North (*)"); + AddLabel(253, 174, 52, @"Orc Forts"); + AddLabel(253, 196, 52, @"South (*)"); + AddLabel(253, 217, 52, @"Vendors"); + AddCheck(394, 91, 210, 211, true, 406); + AddCheck(394, 112, 210, 211, true, 401); + AddCheck(394, 133, 210, 211, true, 407); + AddCheck(394, 154, 210, 211, true, 402); + AddCheck(394, 175, 210, 211, true, 403); + AddCheck(394, 196, 210, 211, true, 404); + AddCheck(394, 217, 210, 211, true, 405); + AddLabel(428, 91, 200, @"(*) Wild"); + AddLabel(428, 109, 200, @"Animals and"); + AddLabel(428, 129, 200, @"monsters."); + AddBlackAlpha(246, 270, 174, 117); + AddLabel(253, 250, 200, @"TER MUR"); + AddLabel(253, 273, 52, @"Abyss"); + AddLabel(253, 294, 52, @"TerMur"); + AddLabel(253, 315, 52, @"Underworld"); + AddLabel(253, 336, 52, @"Vendors"); + AddCheck(394, 274, 210, 211, true, 601); + AddCheck(394, 295, 210, 211, true, 602); + AddCheck(394, 316, 210, 211, true, 603); + AddCheck(394, 337, 210, 211, true, 604); + //END + AddLabel(381, 453, 52, @"Page: 2/2"); //Page + AddButton(361, 455, 5603, 5607, 0, GumpButtonType.Page, 1); //Change Page + AddButton(282, 452, 240, 239, 1, GumpButtonType.Reply, 0); // Apply + } + + public static void UnloadThis( Mobile from, List ListSwitches, int switche ) + { + string prefix = Server.Commands.CommandSystem.Prefix; + + if( ListSwitches.Contains( switche ) == true ) + CommandSystem.Handle( from, String.Format( "{0}Spawngen unload {1}", prefix, switche ) ); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + switch(info.ButtonID) + { + case 0: //Closed or Cancel + { + break; + } + default: + { + // Make sure that the APPLY button was pressed + if( info.ButtonID == 1 ) + { + // Get the array of switches selected + List Selections = new List( info.Switches ); + + //TRAMMEL + // DUNGEONS + UnloadThis(from, Selections, 101); + UnloadThis(from, Selections, 102); + UnloadThis(from, Selections, 103); + UnloadThis(from, Selections, 104); + UnloadThis(from, Selections, 105); + UnloadThis(from, Selections, 106); + UnloadThis(from, Selections, 107); + UnloadThis(from, Selections, 108); + UnloadThis(from, Selections, 109); + UnloadThis(from, Selections, 110); + //There is no Khaldun (118) + UnloadThis(from, Selections, 112); + UnloadThis(from, Selections, 114); + UnloadThis(from, Selections, 115); + UnloadThis(from, Selections, 116); + UnloadThis(from, Selections, 117); + UnloadThis(from, Selections, 119); + UnloadThis(from, Selections, 120); + UnloadThis(from, Selections, 121); + UnloadThis(from, Selections, 124); + UnloadThis(from, Selections, 127); + //TOWNS + UnloadThis(from, Selections, 122); + UnloadThis(from, Selections, 123); + UnloadThis(from, Selections, 125); + //OUTDOORS + UnloadThis(from, Selections, 126); + UnloadThis(from, Selections, 111); + UnloadThis(from, Selections, 113); + UnloadThis(from, Selections, 129); + UnloadThis(from, Selections, 118); + + //FELUCCA + // DUNGEONS + UnloadThis(from, Selections, 201); + UnloadThis(from, Selections, 202); + UnloadThis(from, Selections, 203); + UnloadThis(from, Selections, 204); + UnloadThis(from, Selections, 205); + UnloadThis(from, Selections, 206); + UnloadThis(from, Selections, 207); + UnloadThis(from, Selections, 208); + UnloadThis(from, Selections, 209); + UnloadThis(from, Selections, 210); + UnloadThis(from, Selections, 228); + UnloadThis(from, Selections, 212); + UnloadThis(from, Selections, 214); + UnloadThis(from, Selections, 215); + UnloadThis(from, Selections, 216); + UnloadThis(from, Selections, 217); + UnloadThis(from, Selections, 219); + UnloadThis(from, Selections, 220); + UnloadThis(from, Selections, 221); + UnloadThis(from, Selections, 224); + UnloadThis(from, Selections, 227); + //TOWNS + UnloadThis(from, Selections, 222); + UnloadThis(from, Selections, 223); + UnloadThis(from, Selections, 225); + //OUTDOORS + UnloadThis(from, Selections, 226); + UnloadThis(from, Selections, 211); + UnloadThis(from, Selections, 213); + UnloadThis(from, Selections, 229); + UnloadThis(from, Selections, 218); + + //ILSHENAR + UnloadThis(from, Selections, 301); + UnloadThis(from, Selections, 302); + UnloadThis(from, Selections, 303); + UnloadThis(from, Selections, 304); + UnloadThis(from, Selections, 305); + UnloadThis(from, Selections, 306); + UnloadThis(from, Selections, 307); + UnloadThis(from, Selections, 308); + UnloadThis(from, Selections, 309); + UnloadThis(from, Selections, 310); + UnloadThis(from, Selections, 311); + UnloadThis(from, Selections, 314); + UnloadThis(from, Selections, 312); + UnloadThis(from, Selections, 313); + + //MALAS + UnloadThis(from, Selections, 406); + UnloadThis(from, Selections, 401); + UnloadThis(from, Selections, 407); + UnloadThis(from, Selections, 402); + UnloadThis(from, Selections, 403); + UnloadThis(from, Selections, 404); + UnloadThis(from, Selections, 405); + + //TOKUNO + UnloadThis(from, Selections, 501); + UnloadThis(from, Selections, 502); + UnloadThis(from, Selections, 503); + UnloadThis(from, Selections, 504); + UnloadThis(from, Selections, 505); + UnloadThis(from, Selections, 506); + + //TER MUR + UnloadThis(from, Selections, 601); + UnloadThis(from, Selections, 602); + UnloadThis(from, Selections, 603); + UnloadThis(from, Selections, 604); + + from.Say( "SPAWN UNLOAD COMPLETED" ); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Commands/UnloadMapsUOML.cs b/Scripts/Customs/Nerun's Distro/New/Commands/UnloadMapsUOML.cs new file mode 100644 index 0000000..a275dc6 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Commands/UnloadMapsUOML.cs @@ -0,0 +1,372 @@ +// Engine r29 +#define RunUo2_0 +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class UnloadUOMLGump : Gump + { + Mobile caller; + + public static void Initialize() + { +#if(RunUo2_0) + CommandSystem.Register("UnloadUOML", AccessLevel.Administrator, new CommandEventHandler(UnloadUOML_OnCommand)); +#else + Register("UnloadUOML", AccessLevel.Administrator, new CommandEventHandler(UnloadUOML_OnCommand)); +#endif + } + + [Usage("UnloadUOML")] + [Description("Unload PremiumSpawners around the world with a gump.")] + public static void UnloadUOML_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from.HasGump(typeof(UnloadUOMLGump))) + from.CloseGump(typeof(UnloadUOMLGump)); + from.SendGump(new UnloadUOMLGump(from)); + } + + public UnloadUOMLGump(Mobile from) : this() + { + caller = from; + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public UnloadUOMLGump() : base( 30, 30 ) + { + this.Closable=true; + this.Disposable=true; + this.Dragable=true; + AddPage(1); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO UNLOAD"); + AddBlackAlpha(66, 87, 239, 447); + AddLabel(69, 67, 200, @"DUNGEONS"); + AddLabel(69, 90, 52, @"Blighted Grove"); + AddLabel(69, 112, 52, @"Britain Sewer"); + AddLabel(69, 133, 52, @"Covetous"); + AddLabel(69, 154, 52, @"Deceit"); + AddLabel(69, 174, 52, @"Despise"); + AddLabel(69, 196, 52, @"Destard"); + AddLabel(69, 217, 52, @"Fire"); + AddLabel(69, 237, 52, @"Graveyards"); + AddLabel(69, 258, 52, @"Hythloth"); + AddLabel(69, 280, 52, @"Ice"); + AddLabel(69, 301, 52, @"Khaldun"); + AddLabel(69, 322, 52, @"Orc Caves"); + AddLabel(69, 343, 52, @"Painted Caves"); + AddLabel(69, 363, 52, @"Palace of Paroxysmus"); + AddLabel(69, 384, 52, @"Prism of Light"); + AddLabel(69, 405, 52, @"Sanctuary"); + AddLabel(69, 427, 52, @"Shame"); + AddLabel(69, 448, 52, @"Solen Hive"); + AddLabel(69, 469, 52, @"Terathan Keep"); + AddLabel(69, 489, 52, @"Trinsic Passage"); + AddLabel(69, 510, 52, @"Wrong"); + AddLabel(194, 66, 200, @"Felucca"); + AddCheck(210, 91, 210, 211, true, 201); + AddCheck(210, 112, 210, 211, true, 202); + AddCheck(210, 133, 210, 211, true, 203); + AddCheck(210, 154, 210, 211, true, 204); + AddCheck(210, 175, 210, 211, true, 205); + AddCheck(210, 196, 210, 211, true, 206); + AddCheck(210, 217, 210, 211, true, 207); + AddCheck(210, 238, 210, 211, true, 208); + AddCheck(210, 259, 210, 211, true, 209); + AddCheck(210, 280, 210, 211, true, 210); + AddCheck(210, 301, 210, 211, true, 228); + AddCheck(210, 322, 210, 211, true, 212); + AddCheck(210, 343, 210, 211, true, 214); + AddCheck(210, 364, 210, 211, true, 215); + AddCheck(210, 385, 210, 211, true, 216); + AddCheck(210, 406, 210, 211, true, 217); + AddCheck(210, 427, 210, 211, true, 219); + AddCheck(210, 448, 210, 211, true, 220); + AddCheck(210, 469, 210, 211, true, 221); + AddCheck(210, 490, 210, 211, true, 224); + AddCheck(210, 511, 210, 211, true, 227); + AddLabel(250, 66, 200, @"Trammel"); + AddCheck(268, 91, 210, 211, true, 101); + AddCheck(268, 112, 210, 211, true, 102); + AddCheck(268, 133, 210, 211, true, 103); + AddCheck(268, 154, 210, 211, true, 104); + AddCheck(268, 175, 210, 211, true, 105); + AddCheck(268, 196, 210, 211, true, 106); + AddCheck(268, 217, 210, 211, true, 107); + AddCheck(268, 238, 210, 211, true, 108); + AddCheck(268, 259, 210, 211, true, 109); + AddCheck(268, 280, 210, 211, true, 110); + //There is no Khaldun in Trammel (ID 128 reserved) + AddCheck(268, 322, 210, 211, true, 112); + AddCheck(268, 343, 210, 211, true, 114); + AddCheck(268, 364, 210, 211, true, 115); + AddCheck(268, 385, 210, 211, true, 116); + AddCheck(268, 406, 210, 211, true, 117); + AddCheck(268, 427, 210, 211, true, 119); + AddCheck(268, 448, 210, 211, true, 120); + AddCheck(268, 469, 210, 211, true, 121); + AddCheck(268, 490, 210, 211, true, 124); + AddCheck(268, 511, 210, 211, true, 127); + AddBlackAlpha(311, 87, 213, 70); + AddLabel(315, 67, 200, @"TOWNS"); + AddLabel(315, 91, 52, @"Animals"); + AddLabel(315, 112, 52, @"People (*)"); + AddLabel(315, 133, 52, @"Vendors"); + AddLabel(413, 66, 200, @"Felucca"); + AddCheck(429, 91, 210, 211, true, 222); + AddCheck(429, 112, 210, 211, true, 223); + AddCheck(429, 133, 210, 211, true, 225); + AddLabel(469, 66, 200, @"Trammel"); + AddCheck(487, 91, 210, 211, true, 122); + AddCheck(487, 112, 210, 211, true, 123); + AddCheck(487, 133, 210, 211, true, 125); + AddBlackAlpha(311, 183, 213, 114); + AddLabel(315, 162, 200, @"OUTDOORS"); + AddLabel(316, 187, 52, @"Animals"); + AddLabel(316, 207, 52, @"Lost Lands"); + AddLabel(316, 229, 52, @"Monsters"); + AddLabel(316, 249, 52, @"Reagents"); + AddLabel(316, 270, 52, @"Sea Life"); + AddLabel(413, 162, 200, @"Felucca"); + AddCheck(429, 187, 210, 211, true, 226); + AddCheck(429, 208, 210, 211, true, 211); + AddCheck(429, 229, 210, 211, true, 213); + AddCheck(429, 250, 210, 211, true, 229); + AddCheck(429, 271, 210, 211, true, 218); + AddLabel(469, 162, 200, @"Trammel"); + AddCheck(487, 187, 210, 211, true, 126); + AddCheck(487, 208, 210, 211, true, 111); + AddCheck(487, 229, 210, 211, true, 113); + AddCheck(487, 250, 210, 211, true, 129); + AddCheck(487, 271, 210, 211, true, 118); + AddLabel(316, 305, 200, @"(*) Escortables, Hireables,"); + AddLabel(316, 324, 200, @"Town Criers, Order and Chaos"); + AddLabel(316, 344, 200, @"guards etc."); + // END + AddLabel(361, 453, 52, @"Page: 1/2"); //Page + AddButton(423, 455, 5601, 5605, 0, GumpButtonType.Page, 2); // Change Page + + //PAGE 2 + AddPage(2); + AddBackground(58, 22, 474, 540, 9200); + AddImage(305, 306, 1418); // Castle + AddBlackAlpha(66, 30, 458, 33); + AddLabel(213, 37, 52, @"SELECT MAPS TO SPAWN"); + AddBlackAlpha(66, 87, 174, 300); + AddLabel(74, 67, 200, @"ILSHENAR"); + AddLabel(74, 90, 52, @"Ancient Lair"); + AddLabel(74, 112, 52, @"Ankh"); + AddLabel(74, 133, 52, @"Blood"); + AddLabel(74, 154, 52, @"Exodus"); + AddLabel(74, 174, 52, @"Mushroom"); + AddLabel(74, 196, 52, @"Outdoors"); + AddLabel(74, 217, 52, @"Ratman Cave"); + AddLabel(74, 237, 52, @"Rock"); + AddLabel(74, 258, 52, @"Sorcerers"); + AddLabel(74, 280, 52, @"Spectre"); + AddLabel(74, 301, 52, @"Towns"); + AddLabel(74, 322, 52, @"Twisted Weald"); + AddLabel(74, 343, 52, @"Vendors"); + AddLabel(74, 363, 52, @"Wisp"); + AddCheck(215, 91, 210, 211, true, 301); + AddCheck(215, 112, 210, 211, true, 302); + AddCheck(215, 133, 210, 211, true, 303); + AddCheck(215, 154, 210, 211, true, 304); + AddCheck(215, 175, 210, 211, true, 305); + AddCheck(215, 196, 210, 211, true, 306); + AddCheck(215, 217, 210, 211, true, 307); + AddCheck(215, 238, 210, 211, true, 308); + AddCheck(215, 259, 210, 211, true, 309); + AddCheck(215, 280, 210, 211, true, 310); + AddCheck(215, 301, 210, 211, true, 311); + AddCheck(215, 322, 210, 211, true, 314); + AddCheck(215, 343, 210, 211, true, 312); + AddCheck(215, 364, 210, 211, true, 313); + AddBlackAlpha(66, 414, 174, 133); + AddLabel(74, 393, 200, @"TOKUNO"); + AddLabel(74, 416, 52, @"Fan Dancers Dojo"); + AddLabel(74, 438, 52, @"Outdoors"); + AddLabel(74, 459, 52, @"Towns Life"); + AddLabel(74, 480, 52, @"Vendors"); + AddLabel(74, 500, 52, @"Wild Life"); + AddLabel(74, 522, 52, @"Yomutso Mines"); + AddCheck(215, 417, 210, 211, true, 501); + AddCheck(215, 438, 210, 211, true, 502); + AddCheck(215, 459, 210, 211, true, 503); + AddCheck(215, 480, 210, 211, true, 504); + AddCheck(215, 501, 210, 211, true, 505); + AddCheck(215, 522, 210, 211, true, 506); + AddBlackAlpha(246, 87, 174, 156); + AddLabel(253, 67, 200, @"MALAS"); + AddLabel(253, 90, 52, @"Citadel"); + AddLabel(253, 112, 52, @"Doom"); + AddLabel(253, 133, 52, @"Labyrinth"); + AddLabel(253, 154, 52, @"North (*)"); + AddLabel(253, 174, 52, @"Orc Forts"); + AddLabel(253, 196, 52, @"South (*)"); + AddLabel(253, 217, 52, @"Vendors"); + AddCheck(394, 91, 210, 211, true, 406); + AddCheck(394, 112, 210, 211, true, 401); + AddCheck(394, 133, 210, 211, true, 407); + AddCheck(394, 154, 210, 211, true, 402); + AddCheck(394, 175, 210, 211, true, 403); + AddCheck(394, 196, 210, 211, true, 404); + AddCheck(394, 217, 210, 211, true, 405); + AddLabel(428, 91, 200, @"(*) Wild"); + AddLabel(428, 109, 200, @"Animals and"); + AddLabel(428, 129, 200, @"monsters."); + //END + AddLabel(381, 453, 52, @"Page: 2/2"); //Page + AddButton(361, 455, 5603, 5607, 0, GumpButtonType.Page, 1); //Change Page + AddButton(282, 452, 240, 239, 1, GumpButtonType.Reply, 0); // Apply + } + + public static void UnloadThis( Mobile from, List ListSwitches, int switche ) + { + string prefix = Server.Commands.CommandSystem.Prefix; + + if( ListSwitches.Contains( switche ) == true ) + CommandSystem.Handle( from, String.Format( "{0}Spawngen unload 2{1}", prefix, switche ) ); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + switch(info.ButtonID) + { + case 0: //Closed or Cancel + { + break; + } + default: + { + // Make sure that the APPLY button was pressed + if( info.ButtonID == 1 ) + { + // Get the array of switches selected + List Selections = new List( info.Switches ); + + //TRAMMEL + // DUNGEONS + UnloadThis(from, Selections, 101); + UnloadThis(from, Selections, 102); + UnloadThis(from, Selections, 103); + UnloadThis(from, Selections, 104); + UnloadThis(from, Selections, 105); + UnloadThis(from, Selections, 106); + UnloadThis(from, Selections, 107); + UnloadThis(from, Selections, 108); + UnloadThis(from, Selections, 109); + UnloadThis(from, Selections, 110); + //There is no Khaldun (118) + UnloadThis(from, Selections, 112); + UnloadThis(from, Selections, 114); + UnloadThis(from, Selections, 115); + UnloadThis(from, Selections, 116); + UnloadThis(from, Selections, 117); + UnloadThis(from, Selections, 119); + UnloadThis(from, Selections, 120); + UnloadThis(from, Selections, 121); + UnloadThis(from, Selections, 124); + UnloadThis(from, Selections, 127); + //TOWNS + UnloadThis(from, Selections, 122); + UnloadThis(from, Selections, 123); + UnloadThis(from, Selections, 125); + //OUTDOORS + UnloadThis(from, Selections, 126); + UnloadThis(from, Selections, 111); + UnloadThis(from, Selections, 113); + UnloadThis(from, Selections, 129); + UnloadThis(from, Selections, 118); + + //FELUCCA + // DUNGEONS + UnloadThis(from, Selections, 201); + UnloadThis(from, Selections, 202); + UnloadThis(from, Selections, 203); + UnloadThis(from, Selections, 204); + UnloadThis(from, Selections, 205); + UnloadThis(from, Selections, 206); + UnloadThis(from, Selections, 207); + UnloadThis(from, Selections, 208); + UnloadThis(from, Selections, 209); + UnloadThis(from, Selections, 210); + UnloadThis(from, Selections, 228); + UnloadThis(from, Selections, 212); + UnloadThis(from, Selections, 214); + UnloadThis(from, Selections, 215); + UnloadThis(from, Selections, 216); + UnloadThis(from, Selections, 217); + UnloadThis(from, Selections, 219); + UnloadThis(from, Selections, 220); + UnloadThis(from, Selections, 221); + UnloadThis(from, Selections, 224); + UnloadThis(from, Selections, 227); + //TOWNS + UnloadThis(from, Selections, 222); + UnloadThis(from, Selections, 223); + UnloadThis(from, Selections, 225); + //OUTDOORS + UnloadThis(from, Selections, 226); + UnloadThis(from, Selections, 211); + UnloadThis(from, Selections, 213); + UnloadThis(from, Selections, 229); + UnloadThis(from, Selections, 218); + + //ILSHENAR + UnloadThis(from, Selections, 301); + UnloadThis(from, Selections, 302); + UnloadThis(from, Selections, 303); + UnloadThis(from, Selections, 304); + UnloadThis(from, Selections, 305); + UnloadThis(from, Selections, 306); + UnloadThis(from, Selections, 307); + UnloadThis(from, Selections, 308); + UnloadThis(from, Selections, 309); + UnloadThis(from, Selections, 310); + UnloadThis(from, Selections, 311); + UnloadThis(from, Selections, 314); + UnloadThis(from, Selections, 312); + UnloadThis(from, Selections, 313); + + //MALAS + UnloadThis(from, Selections, 406); + UnloadThis(from, Selections, 401); + UnloadThis(from, Selections, 407); + UnloadThis(from, Selections, 402); + UnloadThis(from, Selections, 403); + UnloadThis(from, Selections, 404); + UnloadThis(from, Selections, 405); + + //TOKUNO + UnloadThis(from, Selections, 501); + UnloadThis(from, Selections, 502); + UnloadThis(from, Selections, 503); + UnloadThis(from, Selections, 504); + UnloadThis(from, Selections, 505); + UnloadThis(from, Selections, 506); + + from.Say( "SPAWN UNLOAD COMPLETED" ); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/ChampionSpawnController/ChampionSpawnController.cs b/Scripts/Customs/Nerun's Distro/New/Engines/ChampionSpawnController/ChampionSpawnController.cs new file mode 100644 index 0000000..8480610 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/ChampionSpawnController/ChampionSpawnController.cs @@ -0,0 +1,495 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Engines.CannedEvil; + +namespace Server.Engines.CannedEvil +{ + public class ChampionSpawnController : Item + { + bool m_Active; + + private ArrayList m_AllSpawn; + private ArrayList m_DungeonsSpawn; + private ArrayList m_LostLandsSpawn; + private ArrayList m_IlshenarSpawn; + private ArrayList m_TokunoSpawn; + + //private int m_SpawnRange; + private TimeSpan m_ExpireDelay; + private TimeSpan m_RestartDelay; + + private TimeSpan m_RandomizeDelay; + + private int m_ActiveAltars; + + private RandomizeTimer m_Timer; + + public struct SpawnRecord + { + public int type,x,y,z; + + public SpawnRecord( int type, int x, int y, int z ) + { + this.type = type; + this.x = x; + this.y = y; + this.z = z; + } + } + + private SpawnRecord[] m_Dungeons = new SpawnRecord[] + { + new SpawnRecord( (int)ChampionSpawnType.UnholyTerror, 5178, 708, 20 ), //Deceit + new SpawnRecord( (int)ChampionSpawnType.VerminHorde, 5557, 824, 65 ), // Despise + new SpawnRecord( (int)ChampionSpawnType.ColdBlood, 5259, 837, 61 ), // Destard + new SpawnRecord( (int)ChampionSpawnType.Abyss, 5814, 1350, 2 ), // Fire + new SpawnRecord( (int)ChampionSpawnType.Arachnid, 5190, 1605, 20 ), // TerathanKeep + }; + + private SpawnRecord[] m_LostLands = new SpawnRecord[] + { + new SpawnRecord( 0xff, 5636, 2916, 37 ), // Desert + new SpawnRecord( 0xff, 5724, 3991, 42 ), // Tortoise + new SpawnRecord( 0xff, 5511, 2360, 40 ), // Ice West + + new SpawnRecord( 0xff, 5549, 2640, 15 ), // Oasis + new SpawnRecord( 0xff, 6035, 2944, 52 ), // Terra Sanctum + new SpawnRecord( (int)ChampionSpawnType.ForestLord, 5559, 3757, 21 ), // Lord Oaks + + new SpawnRecord( 0xff, 5267, 3171, 104 ), // Marble + new SpawnRecord( 0xff, 5954, 3475, 25 ), // Hoppers Boog + new SpawnRecord( 0xff, 5982, 3882, 20 ), // Khaldun + + new SpawnRecord( 0xff, 6038, 2400, 46 ), // Ice East + new SpawnRecord( 0xff, 5281, 3368, 51 ), // Damwin + new SpawnRecord( 0xff, 5207, 3637, 20 ), // City of Death + }; + + private SpawnRecord[] m_Ilshenar = new SpawnRecord[] + { + new SpawnRecord( 0xff, 382, 328, -30 ), // Valor + new SpawnRecord( 0xff, 462, 926, -67 ), // Humility + new SpawnRecord( (int)ChampionSpawnType.ForestLord, 1645, 1107, 8 ), // Spirituality + }; + + private SpawnRecord[] m_Tokuno = new SpawnRecord[] + { + new SpawnRecord( (int)ChampionSpawnType.SleepingDragon, 948, 434, 29 ), // Isamu Jima + }; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get + { + return m_Active; + } + set + { + if ( value ) + Start(); + else + Stop(); + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ActiveAltars + { + get + { + return m_ActiveAltars; + } + set + { + m_ActiveAltars = value; + } + } + + /*[CommandProperty( AccessLevel.GameMaster )] + public int SpawnRange + { + get + { + return m_SpawnRange; + } + set + { + m_SpawnRange = value; + + foreach( ChampionSpawn cs in m_AllSpawn ) + { + cs.SpawnRange = m_SpawnRange; + } + } + }*/ + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan ExpireDelay + { + get + { + return m_ExpireDelay; + } + set + { + m_ExpireDelay = value; + + foreach( ChampionSpawn cs in m_AllSpawn ) + { + cs.ExpireDelay = m_ExpireDelay; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan RestartDelay + { + get + { + return m_RestartDelay; + } + set + { + m_RestartDelay = value; + + foreach( ChampionSpawn cs in m_IlshenarSpawn ) + { + cs.RestartDelay = m_RestartDelay; + } + + foreach( ChampionSpawn cs in m_TokunoSpawn ) + { + cs.RestartDelay = m_RestartDelay; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan RandomizeDelay + { + get + { + return m_RandomizeDelay; + } + set + { + m_RandomizeDelay = value; + } + } + + [Constructable] + public ChampionSpawnController() : base( 0x1B7A ) + { + if ( Check() ) + { + World.Broadcast( 0x35, true, "Another champion spawn controller exist in the world !" ); + Delete(); + return; + } + + Visible = false; + Movable = false; + Name = "champion spawn controller"; + + m_Active = false; + + m_AllSpawn = new ArrayList(); + m_DungeonsSpawn = new ArrayList(); + m_LostLandsSpawn = new ArrayList(); + m_IlshenarSpawn = new ArrayList(); + m_TokunoSpawn = new ArrayList(); + + m_ActiveAltars = 1; + + //m_SpawnRange = 24; + m_ExpireDelay = TimeSpan.FromMinutes( 10.0 ); + m_RestartDelay = TimeSpan.FromMinutes( 5.0 ); + + m_RandomizeDelay = TimeSpan.FromHours( 72.0 ); + + DeleteAll(); + Generate(); + + World.Broadcast( 0x35, true, "Champion spawn generation complete. Old spawns removed." ); + } + + private bool Check() + { + foreach ( Item item in World.Items.Values ) + { + if ( item is ChampionSpawnController && !item.Deleted && item != this ) + return true; + } + + return false; + } + + private void DeleteAll() + { + ArrayList list = new ArrayList(); + + foreach ( Item item in World.Items.Values ) + { + if ( item is ChampionSpawn && !item.Deleted ) + list.Add( item ); + } + + foreach ( ChampionSpawn cs in list ) + { + cs.Delete(); + } + } + + private ChampionSpawn CreateAltar( SpawnRecord r, Map m, bool restartdisable ) + { + ChampionSpawn cs = new ChampionSpawn(); + + Point3D loc = new Point3D( r.x, r.y, r.z ); + + if ( r.type == 0xff ) + { + cs.RandomizeType = true; + + switch ( Utility.Random( 5 ) ) + { + case 0: cs.Type = ChampionSpawnType.VerminHorde; break; + case 1: cs.Type = ChampionSpawnType.UnholyTerror; break; + case 2: cs.Type = ChampionSpawnType.ColdBlood; break; + case 3: cs.Type = ChampionSpawnType.Abyss; break; + case 4: cs.Type = ChampionSpawnType.Arachnid; break; + } + } + else + { + cs.RandomizeType = false; + cs.Type = (ChampionSpawnType)r.type; + } + +// Prevent autorestart of felucca & t2a the spawns + + if ( restartdisable ) + cs.RestartDelay = TimeSpan.FromDays( 9999 ); + + cs.MoveToWorld( loc, m ); + + return cs; + } + + private void Generate() + { + int i = 0; + + for ( i = 0; i= AccessLevel.GameMaster && !canLoot) + { + m.SendMessage("This is unlootable but you are able to open that with your Godly powers."); + return true; + } + + return canLoot; + } + + return base.OnDoubleClick(m, o); + } + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + if (m_Controller.LightLevel >= 0) + global = m_Controller.LightLevel; + else + base.AlterLightLevel(m, ref global, ref personal); + } + + /*public override bool CheckAccessibility(Item item, Mobile from) + { + + if (item is BasePotion && !m_Controller.CanUsePotions) + { + from.SendMessage("You cannot drink potions here."); + return false; + } + + if (item is Corpse) + { + Corpse c = item as Corpse; + + bool canLoot; + + if (c.Owner == from) + canLoot = m_Controller.CanLootOwnCorpse; + else if (c.Owner is PlayerMobile) + canLoot = m_Controller.CanLootPlayerCorpse; + else + canLoot = m_Controller.CanLootNPCCorpse; + + if (!canLoot) + from.SendMessage("You cannot loot that corpse here."); + + if (from.AccessLevel >= AccessLevel.GameMaster && !canLoot) + { + from.SendMessage("This is unlootable but you are able to open that with your Godly powers."); + return true; + } + + return canLoot; + } + + return base.CheckAccessibility(item, from); + }*/ + + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionBounds.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionBounds.cs new file mode 100644 index 0000000..6f9cdac --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionBounds.cs @@ -0,0 +1,152 @@ +using System; +using Server; +using System.Collections; +using Server.Regions; +using Server.Targeting; +using Server.Items; + +namespace Server.Commands +{ + public class RegionBounds + { + public static void Initialize() + { + CommandSystem.Register( "RegionBounds", AccessLevel.GameMaster, new CommandEventHandler( RegionBounds_OnCommand ) ); + } + + [Usage( "RegionBounds" )] + [Description( "Displays the bounding area of either a targeted Mobile's region or the Bounding area of a targeted RegionControl." )] + private static void RegionBounds_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new RegionBoundTarget(); + e.Mobile.SendMessage( "Target a Mobile or RegionControl" ); + e.Mobile.SendMessage( "Please note that Players will also be able to see the bounds of the Region." ); + } + + private class RegionBoundTarget : Target + { + public RegionBoundTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if( targeted is Mobile ) + { + Mobile m = (Mobile)targeted; + + Region r = m.Region; + + if( r == m.Map.DefaultRegion ) + { + from.SendMessage( "The Region is the Default region for the entire map and as such, cannot have it's bounds displayed." ); + return; + } + + from.SendMessage( String.Format( "That Mobile's region is of type {0}, with a priority of {1}.", r.GetType().FullName, r.Priority.ToString() )); + + ShowRegionBounds(r, from, false, true); + } + else if( targeted is RegionControl ) + { + RegionControl control = ((RegionControl)targeted); + Region r = control.Region; + + if (control.Active) + { + if (control.RegionArea == null || control.RegionArea.Length == 0 || r == null) + { + from.SendMessage("Region area not defined for targeted RegionControl."); + return; + } + + from.SendMessage("Displaying targeted RegionControl's ACTIVE Region..."); + + ShowRegionBounds(r, from, true, true); + } + else + { + if (control.RegionArea == null || control.RegionArea.Length == 0) + { + from.SendMessage("Region area not defined for targeted RegionControl."); + return; + } + + r = new CustomRegion(control); + + if (r == null) + { + from.SendMessage("Region area not defined for targeted RegionControl."); + return; + } + + from.SendMessage("Displaying targeted RegionControl's INACTIVE Region..."); + + ShowRegionBounds(r, from, true, false); + } + } + else + { + from.SendMessage( "That is not a Mobile or a RegionControl" ); + } + } + } + + public static void ShowRectBounds(Rectangle3D r, Map m, Mobile from, bool control, bool active) + { + if (m == Map.Internal || m == null) + return; + + int hue = 0; + if(control && active) + hue = 0x3F; + else if(control && !active) + hue = 0x26; + else if(!control) + hue = 1151; + + Point3D p1 = new Point3D(r.Start.X, r.Start.Y - 1, from.Z); //So we dont' need to create a new one each point + Point3D p2 = new Point3D(r.Start.X, r.Start.Y + r.Height - 1, from.Z); //So we dont' need to create a new one each point + + Effects.SendLocationEffect(new Point3D(r.Start.X - 1, r.Start.Y - 1, from.Z), m, 251, 75, 1, hue, 3); //Top Corner //Testing color + + for (int x = r.Start.X; x <= (r.Start.X + r.Width - 1); x++) + { + p1.X = x; + p2.X = x; + + p1.Z = from.Z; + p2.Z = from.Z; + + Effects.SendLocationEffect(p1, m, 249, 75, 1, hue, 3); //North bound + Effects.SendLocationEffect(p2, m, 249, 75, 1, hue, 3); //South bound + } + + p1 = new Point3D(r.Start.X - 1, r.Start.Y - 1, from.Z); + p2 = new Point3D(r.Start.X + r.Width - 1, r.Start.Y, from.Z); + + for (int y = r.Start.Y; y <= (r.Start.Y + r.Height - 1); y++) + { + p1.Y = y; + p2.Y = y; + + p1.Z = from.Z; + p2.Z = from.Z; + + Effects.SendLocationEffect(p1, m, 250, 75, 1, hue, 3); //West Bound + Effects.SendLocationEffect(p2, m, 250, 75, 1, hue, 3); //East Bound + } + } + + public static void ShowRegionBounds(Region r, Mobile from, bool control, bool active) + { + if (r == null) + return; + + foreach (Rectangle3D rect in r.Area) + { + ShowRectBounds(rect, r.Map, from, control, active); + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionControl.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionControl.cs new file mode 100644 index 0000000..409989a --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionControl.cs @@ -0,0 +1,1186 @@ +/* +INCLUDED AT v4.0 FOR RC2: + +@JeremyMCC +I've toyed around with the RegionControl.cs and have a fix that seems to work. +I've tested it pretty thoroughly and haven't had any crashes and the custom go location still +seems to work fine. Here's the fix, let me know how it works for everyone. +http://www.runuo.com/community/threads/runuo-2-0-rc1-custom-regions-in-a-box-v4-0.70170/page-6#post-543450 + + @oii88 + Reported JeremyMCC changes did not works. + http://www.runuo.com/community/threads/runuo-2-0-rc1-custom-regions-in-a-box-v4-0.70170/page-6#post-543461 + +@Datguy +Removed Custom Go Location +If you want no Crash/error, remove CustomGo in RegionControl.cs. +You'll not have the Region Go command for the custom regions you make but you'll not have crashes either. +http://www.runuo.com/community/threads/runuo-2-0-rc1-custom-regions-in-a-box-v4-0.70170/page-8#post-543495 + +INCLUDED AT v4.0 FOR NERUN'S DISTRO + +@Lord Dio +Custom Regions in a Box 2.0 Final: Z value fix +http://www.runuo.com/community/threads/custom-regions-in-a-box-2-0-final-z-value-fix.102663/ + +@Nerun +Lines 873-877 +RemoveAreaGump will be refreshed after added a new area +*/ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Spells; +using Server.Items; +using Server.Regions; +using System.Collections; +using Server.SkillHandlers; +using Server.Gumps; + +namespace Server.Items +{ + public enum RegionFlag : uint + { + None = 0x00000000, + AllowBenefitPlayer = 0x00000001, + AllowHarmPlayer = 0x00000002, + AllowHousing = 0x00000004, + AllowSpawn = 0x00000008, + + CanBeDamaged = 0x00000010, + CanHeal = 0x00000020, + CanRessurect = 0x00000040, + CanUseStuckMenu = 0x00000080, + ItemDecay = 0x00000100, + + ShowEnterMessage = 0x00000200, + ShowExitMessage = 0x00000400, + + AllowBenefitNPC = 0x00000800, + AllowHarmNPC = 0x00001000, + + CanMountEthereal = 0x000002000, + // ToDo: Change to "CanEnter" + CanEnter = 0x000004000, + + CanLootPlayerCorpse = 0x000008000, + CanLootNPCCorpse = 0x000010000, + // ToDo: Change to "CanLootOwnCorpse" + CanLootOwnCorpse = 0x000020000, + + CanUsePotions = 0x000040000, + + IsGuarded = 0x000080000, + + // Obsolete, needed for old versions for DeSer. + NoPlayerCorpses = 0x000100000, + NoItemDrop = 0x000200000, + // + + EmptyNPCCorpse = 0x000400000, + EmptyPlayerCorpse = 0x000800000, + DeleteNPCCorpse = 0x001000000, + DeletePlayerCorpse = 0x002000000, + ResNPCOnDeath = 0x004000000, + ResPlayerOnDeath = 0x008000000, + MoveNPCOnDeath = 0x010000000, + MovePlayerOnDeath = 0x020000000, + + NoPlayerItemDrop = 0x040000000, + NoNPCItemDrop = 0x080000000 + } + + public class RegionControl : Item + { + private static List m_AllControls = new List(); + + public static List AllControls + { + get { return m_AllControls; } + } + + + #region Region Flags + + private RegionFlag m_Flags; + + public RegionFlag Flags + { + get { return m_Flags; } + set { m_Flags = value; } + } + + public bool GetFlag(RegionFlag flag) + { + return ((m_Flags & flag) != 0); + } + + public void SetFlag(RegionFlag flag, bool value) + { + if (value) + m_Flags |= flag; + else + { + m_Flags &= ~flag; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowBenefitPlayer + { + get { return GetFlag(RegionFlag.AllowBenefitPlayer); } + set { SetFlag(RegionFlag.AllowBenefitPlayer, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowHarmPlayer + { + get { return GetFlag(RegionFlag.AllowHarmPlayer); } + set { SetFlag(RegionFlag.AllowHarmPlayer, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowHousing + { + get { return GetFlag(RegionFlag.AllowHousing); } + set { SetFlag(RegionFlag.AllowHousing, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowSpawn + { + get { return GetFlag(RegionFlag.AllowSpawn); } + set { SetFlag(RegionFlag.AllowSpawn, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanBeDamaged + { + get { return GetFlag(RegionFlag.CanBeDamaged); } + set { SetFlag(RegionFlag.CanBeDamaged, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanMountEthereal + { + get { return GetFlag(RegionFlag.CanMountEthereal); } + set { SetFlag(RegionFlag.CanMountEthereal, value); } + } + + // ToDo: Change to "CanEnter" + [CommandProperty(AccessLevel.GameMaster)] + public bool CanEnter + { + get { return GetFlag(RegionFlag.CanEnter); } + set { SetFlag(RegionFlag.CanEnter, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanHeal + { + get { return GetFlag(RegionFlag.CanHeal); } + set { SetFlag(RegionFlag.CanHeal, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanRessurect + { + get { return GetFlag(RegionFlag.CanRessurect); } + set { SetFlag(RegionFlag.CanRessurect, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanUseStuckMenu + { + get { return GetFlag(RegionFlag.CanUseStuckMenu); } + set { SetFlag(RegionFlag.CanUseStuckMenu, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ItemDecay + { + get { return GetFlag(RegionFlag.ItemDecay); } + set { SetFlag(RegionFlag.ItemDecay, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowBenefitNPC + { + get { return GetFlag(RegionFlag.AllowBenefitNPC); } + set { SetFlag(RegionFlag.AllowBenefitNPC, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowHarmNPC + { + get { return GetFlag(RegionFlag.AllowHarmNPC); } + set { SetFlag(RegionFlag.AllowHarmNPC, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowEnterMessage + { + get { return GetFlag(RegionFlag.ShowEnterMessage); } + set { SetFlag(RegionFlag.ShowEnterMessage, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowExitMessage + { + get { return GetFlag(RegionFlag.ShowExitMessage); } + set { SetFlag(RegionFlag.ShowExitMessage, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanLootPlayerCorpse + { + get { return GetFlag(RegionFlag.CanLootPlayerCorpse); } + set { SetFlag(RegionFlag.CanLootPlayerCorpse, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanLootNPCCorpse + { + get { return GetFlag(RegionFlag.CanLootNPCCorpse); } + set { SetFlag(RegionFlag.CanLootNPCCorpse, value); } + } + + // ToDo: Change to "CanLootOwnCorpse" + [CommandProperty(AccessLevel.GameMaster)] + public bool CanLootOwnCorpse + { + get { return GetFlag(RegionFlag.CanLootOwnCorpse); } + set { SetFlag(RegionFlag.CanLootOwnCorpse, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanUsePotions + { + get { return GetFlag(RegionFlag.CanUsePotions); } + set { SetFlag(RegionFlag.CanUsePotions, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsGuarded + { + get + { return GetFlag(RegionFlag.IsGuarded); } + set + { + SetFlag(RegionFlag.IsGuarded, value); + if (m_Region != null) + m_Region.Disabled = !value; + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), new TimerCallback(UpdateRegion)); + } + } + + // OBSOLETE, needed for old Deser + public bool NoPlayerCorpses + { + get { return GetFlag(RegionFlag.NoPlayerCorpses); } + set { SetFlag(RegionFlag.NoPlayerCorpses, value); } + } + + public bool NoItemDrop + { + get { return GetFlag(RegionFlag.NoItemDrop); } + set { SetFlag(RegionFlag.NoItemDrop, value); } + } + // END OBSOLETE + + [CommandProperty(AccessLevel.GameMaster)] + public bool EmptyNPCCorpse + { + get { return GetFlag(RegionFlag.EmptyNPCCorpse); } + set { SetFlag(RegionFlag.EmptyNPCCorpse, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool EmptyPlayerCorpse + { + get { return GetFlag(RegionFlag.EmptyPlayerCorpse); } + set { SetFlag(RegionFlag.EmptyPlayerCorpse, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DeleteNPCCorpse + { + get { return GetFlag(RegionFlag.DeleteNPCCorpse); } + set { SetFlag(RegionFlag.DeleteNPCCorpse, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DeletePlayerCorpse + { + get { return GetFlag(RegionFlag.DeletePlayerCorpse); } + set { SetFlag(RegionFlag.DeletePlayerCorpse, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ResNPCOnDeath + { + get { return GetFlag(RegionFlag.ResNPCOnDeath); } + set { SetFlag(RegionFlag.ResNPCOnDeath, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ResPlayerOnDeath + { + get { return GetFlag(RegionFlag.ResPlayerOnDeath); } + set { SetFlag(RegionFlag.ResPlayerOnDeath, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool MoveNPCOnDeath + { + get { return GetFlag(RegionFlag.MoveNPCOnDeath); } + set + { + if (MoveNPCToMap == null || MoveNPCToMap == Map.Internal || MoveNPCToLoc == Point3D.Zero) + SetFlag(RegionFlag.MoveNPCOnDeath, false); + else + SetFlag(RegionFlag.MoveNPCOnDeath, value); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool MovePlayerOnDeath + { + get { return GetFlag(RegionFlag.MovePlayerOnDeath); } + set + { + if (MovePlayerToMap == null || MovePlayerToMap == Map.Internal || MovePlayerToLoc == Point3D.Zero) + SetFlag(RegionFlag.MovePlayerOnDeath, false); + else + SetFlag(RegionFlag.MovePlayerOnDeath, value); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool NoPlayerItemDrop + { + get { return GetFlag(RegionFlag.NoPlayerItemDrop); } + set { SetFlag(RegionFlag.NoPlayerItemDrop, value); } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public bool NoNPCItemDrop + { + get { return GetFlag(RegionFlag.NoNPCItemDrop); } + set { SetFlag(RegionFlag.NoNPCItemDrop, value); } + } + + # endregion + + + #region Region Restrictions + + private BitArray m_RestrictedSpells; + private BitArray m_RestrictedSkills; + + public BitArray RestrictedSpells + { + get { return m_RestrictedSpells; } + } + + public BitArray RestrictedSkills + { + get { return m_RestrictedSkills; } + } + + # endregion + + + # region Region Related Objects + + private CustomRegion m_Region; + private Rectangle3D[] m_RegionArea; + + public CustomRegion Region + { + get { return m_Region; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Rectangle3D[] RegionArea + { + get { return m_RegionArea; } + set { m_RegionArea = value; } + } + + # endregion + + + # region Control Properties + + private bool m_Active = true; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Active + { + get { return m_Active; } + set + { + if (m_Active != value) + { + m_Active = value; + UpdateRegion(); + } + } + + } + + # endregion + + + # region Region Properties + + private string m_RegionName; + private int m_RegionPriority; + private MusicName m_Music; + private TimeSpan m_PlayerLogoutDelay; + private int m_LightLevel; + + private Map m_MoveNPCToMap; + private Point3D m_MoveNPCToLoc; + private Map m_MovePlayerToMap; + private Point3D m_MovePlayerToLoc; + + [CommandProperty(AccessLevel.GameMaster)] + public string RegionName + { + get { return m_RegionName; } + set + { + if (Map != null && !RegionNameTaken(value)) + m_RegionName = value; + else if (Map != null) + Console.WriteLine("RegionName not changed for {0}, {1} already has a Region with the name of {2}", this, Map, value); + else if(Map == null) + Console.WriteLine("RegionName not changed for {0} to {1}, it's Map value was null", this, value); + + UpdateRegion(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RegionPriority + { + get { return m_RegionPriority; } + set + { + m_RegionPriority = value; + UpdateRegion(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public MusicName Music + { + get { return m_Music; } + set + { + m_Music = value; + UpdateRegion(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan PlayerLogoutDelay + { + get{ return m_PlayerLogoutDelay; } + set + { + m_PlayerLogoutDelay = value; + UpdateRegion(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int LightLevel + { + get { return m_LightLevel; } + set + { + m_LightLevel = value; + UpdateRegion(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map MoveNPCToMap + { + get { return m_MoveNPCToMap; } + set + { + if (value != Map.Internal) + m_MoveNPCToMap = value; + else + SetFlag(RegionFlag.MoveNPCOnDeath, false); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D MoveNPCToLoc + { + get { return m_MoveNPCToLoc; } + set + { + if (value != Point3D.Zero) + m_MoveNPCToLoc = value; + else + SetFlag(RegionFlag.MoveNPCOnDeath, false); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map MovePlayerToMap + { + get { return m_MovePlayerToMap; } + set + { + if (value != Map.Internal) + m_MovePlayerToMap = value; + else + SetFlag(RegionFlag.MovePlayerOnDeath, false); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D MovePlayerToLoc + { + get { return m_MovePlayerToLoc; } + set + { + if (value != Point3D.Zero) + m_MovePlayerToLoc = value; + else + SetFlag(RegionFlag.MovePlayerOnDeath, false); + } + } + + // REMOVED + /* + private Point3D m_CustomGoLocation; + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D CustomGoLocation + { + get { return m_Region.GoLocation; } + set + { + m_Region.GoLocation = value; + m_CustomGoLocation = value; + UpdateRegion(); + } + } + */ + + # endregion + + + [Constructable] + public RegionControl() : base ( 5609 ) + { + Visible = false; + Movable = false; + Name = "Region Controller"; + + if (m_AllControls == null) + m_AllControls = new List(); + m_AllControls.Add(this); + + m_RegionName = FindNewName("Custom Region"); + m_RegionPriority = CustomRegion.DefaultPriority; + + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + } + + [Constructable] + public RegionControl(Rectangle2D rect): base(5609) + { + Visible = false; + Movable = false; + Name = "Region Controller"; + + if (m_AllControls == null) + m_AllControls = new List(); + m_AllControls.Add(this); + + m_RegionName = FindNewName("Custom Region"); + m_RegionPriority = CustomRegion.DefaultPriority; + + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + + Rectangle3D newrect = Server.Region.ConvertTo3D(rect); + DoChooseArea(null, this.Map, newrect.Start, newrect.End, this); + + UpdateRegion(); + } + + [Constructable] + public RegionControl(Rectangle3D rect): base(5609) + { + Visible = false; + Movable = false; + Name = "Region Controller"; + + if (m_AllControls == null) + m_AllControls = new List(); + m_AllControls.Add(this); + + m_RegionName = FindNewName("Custom Region"); + m_RegionPriority = CustomRegion.DefaultPriority; + + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + + DoChooseArea(null, this.Map, rect.Start, rect.End, this); + + UpdateRegion(); + } + + [Constructable] + public RegionControl(Rectangle2D[] rects): base(5609) + { + Visible = false; + Movable = false; + Name = "Region Controller"; + + if (m_AllControls == null) + m_AllControls = new List(); + m_AllControls.Add(this); + + m_RegionName = FindNewName("Custom Region"); + m_RegionPriority = CustomRegion.DefaultPriority; + + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + + foreach (Rectangle2D rect2d in rects) + { + Rectangle3D newrect = Server.Region.ConvertTo3D(rect2d); + DoChooseArea(null, this.Map, newrect.Start, newrect.End, this); + } + + UpdateRegion(); + } + + [Constructable] + public RegionControl(Rectangle3D[] rects): base(5609) + { + Visible = false; + Movable = false; + Name = "Region Controller"; + + if (m_AllControls == null) + m_AllControls = new List(); + m_AllControls.Add(this); + + m_RegionName = FindNewName("Custom Region"); + m_RegionPriority = CustomRegion.DefaultPriority; + + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + + foreach (Rectangle3D rect3d in rects) + { + DoChooseArea(null, this.Map, rect3d.Start, rect3d.End, this); + } + + UpdateRegion(); + } + + public RegionControl( Serial serial ) : base( serial ) + { + } + + + #region Control Special Voids + + public bool RegionNameTaken(string testName) + { + + if (m_AllControls != null) + { + foreach (RegionControl control in m_AllControls) + { + if (control.RegionName == testName && control != this) + return true; + } + } + + return false; + } + + public string FindNewName(string oldName) + { + int i = 1; + + string newName = oldName; + while( RegionNameTaken(newName) ) + { + newName = oldName; + newName += String.Format(" {0}", i); + i++; + } + + return newName; + } + + public void UpdateRegion() + { + if (m_Region != null) + m_Region.Unregister(); + + if (this.Map != null && this.Active) + { + if (this != null && this.RegionArea != null && this.RegionArea.Length > 0) + { + m_Region = new CustomRegion(this); + // m_Region.GoLocation = m_CustomGoLocation; // REMOVED + m_Region.Register(); + } + else + m_Region = null; + } + else + m_Region = null; + } + + public void RemoveArea(int index, Mobile from) + { + try + { + List rects = new List(); + foreach (Rectangle3D rect in m_RegionArea) + rects.Add(rect); + + rects.RemoveAt(index); + m_RegionArea = rects.ToArray(); + + UpdateRegion(); + from.SendMessage("Area Removed!"); + } + catch + { + from.SendMessage("Removing of Area Failed!"); + } + } + public static int GetRegistryNumber(ISpell s) + { + Type[] t = SpellRegistry.Types; + + for (int i = 0; i < t.Length; i++) + { + if (s.GetType() == t[i]) + return i; + } + + return -1; + } + + + public bool IsRestrictedSpell(ISpell s) + { + + if (m_RestrictedSpells.Length != SpellRegistry.Types.Length) + { + + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + + for (int i = 0; i < m_RestrictedSpells.Length; i++) + m_RestrictedSpells[i] = false; + + } + + int regNum = GetRegistryNumber(s); + + + if (regNum < 0) //Happens with unregistered Spells + return false; + + return m_RestrictedSpells[regNum]; + } + + public bool IsRestrictedSkill(int skill) + { + if (m_RestrictedSkills.Length != SkillInfo.Table.Length) + { + + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + + for (int i = 0; i < m_RestrictedSkills.Length; i++) + m_RestrictedSkills[i] = false; + + } + + if (skill < 0) + return false; + + + return m_RestrictedSkills[skill]; + } + + public void ChooseArea(Mobile m) + { + BoundingBoxPicker.Begin(m, new BoundingBoxCallback(CustomRegion_Callback), this); + } + + public void CustomRegion_Callback(Mobile from, Map map, Point3D start, Point3D end, object state) + { + DoChooseArea(from, map, start, end, state); + } + + public void DoChooseArea(Mobile from, Map map, Point3D start, Point3D end, object control) + { + if (this != null) + { + List areas = new List(); + + if (this.m_RegionArea != null) + { + foreach (Rectangle3D rect in this.m_RegionArea) + areas.Add(rect); + } +// Added Lord Dio's Z Value Fix + if (start.Z == end.Z || start.Z < end.Z) + { + if (start.Z != Server.Region.MinZ) + start.Z = Server.Region.MinZ; + if (end.Z != Server.Region.MaxZ) + end.Z = Server.Region.MaxZ; + } + else + { + if (start.Z != Server.Region.MaxZ) + start.Z = Server.Region.MaxZ; + if (end.Z != Server.Region.MinZ) + end.Z = Server.Region.MinZ; + } + + Rectangle3D newrect = new Rectangle3D(start, end); + areas.Add(newrect); + + this.m_RegionArea = areas.ToArray(); + + this.UpdateRegion(); +// Added by nerun, so the RemoveAreaGump will be refreshed after added a new area + from.CloseGump( typeof( RegionControlGump ) ); + from.SendGump( new RegionControlGump( this ) ); + from.CloseGump( typeof( RemoveAreaGump ) ); + from.SendGump( new RemoveAreaGump( this ) ); + } + } + + # endregion + + + #region Control Overrides + + public override void OnDoubleClick(Mobile m) + { + if (m.AccessLevel >= AccessLevel.GameMaster) + { + if (m_RestrictedSpells.Length != SpellRegistry.Types.Length) + { + m_RestrictedSpells = new BitArray(SpellRegistry.Types.Length); + + for (int i = 0; i < m_RestrictedSpells.Length; i++) + m_RestrictedSpells[i] = false; + + m.SendMessage("Resetting all restricted Spells due to Spell change"); + } + + if (m_RestrictedSkills.Length != SkillInfo.Table.Length) + { + + m_RestrictedSkills = new BitArray(SkillInfo.Table.Length); + + for (int i = 0; i < m_RestrictedSkills.Length; i++) + m_RestrictedSkills[i] = false; + + m.SendMessage("Resetting all restricted Skills due to Skill change"); + + } + + m.CloseGump(typeof(RegionControlGump)); + m.SendGump(new RegionControlGump(this)); + m.SendMessage("Don't forget to props this object for more options!"); + m.CloseGump(typeof(RemoveAreaGump)); + m.SendGump(new RemoveAreaGump(this)); + } + } + + public override void OnMapChange() + { + UpdateRegion(); + base.OnMapChange(); + } + + public override void OnDelete() + { + if (m_Region != null) + m_Region.Unregister(); + + if (m_AllControls != null) + m_AllControls.Remove(this); + + base.OnDelete(); + } + + # endregion + + + #region Ser/Deser Helpers + + public static void WriteBitArray(GenericWriter writer, BitArray ba) + { + writer.Write(ba.Length); + + for (int i = 0; i < ba.Length; i++) + { + writer.Write(ba[i]); + } + return; + } + + public static BitArray ReadBitArray(GenericReader reader) + { + int size = reader.ReadInt(); + + BitArray newBA = new BitArray(size); + + for (int i = 0; i < size; i++) + { + newBA[i] = reader.ReadBool(); + } + + return newBA; + } + + + public static void WriteRect3DArray(GenericWriter writer, Rectangle3D[] ary) + { + if (ary == null) + { + writer.Write(0); + return; + } + + writer.Write(ary.Length); + + for (int i = 0; i < ary.Length; i++) + { + Rectangle3D rect = ((Rectangle3D)ary[i]); + writer.Write((Point3D)rect.Start); + writer.Write((Point3D)rect.End); + } + return; + } + + public static List ReadRect2DArray(GenericReader reader) + { + int size = reader.ReadInt(); + List newAry = new List(); + + for (int i = 0; i < size; i++) + { + newAry.Add(reader.ReadRect2D()); + } + + return newAry; + } + + public static Rectangle3D[] ReadRect3DArray(GenericReader reader) + { + int size = reader.ReadInt(); + List newAry = new List(); + + for (int i = 0; i < size; i++) + { + Point3D start = reader.ReadPoint3D(); + Point3D end = reader.ReadPoint3D(); + newAry.Add(new Rectangle3D(start,end)); + } + + return newAry.ToArray(); + } + + # endregion + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 5 ); // version + + // writer.Write((Point3D)CustomGoLocation); // REMOVED + + WriteRect3DArray(writer, m_RegionArea); + + writer.Write((int)m_Flags); + + WriteBitArray(writer, m_RestrictedSpells); + WriteBitArray(writer, m_RestrictedSkills); + + writer.Write((bool)m_Active); + + writer.Write((string)m_RegionName); + writer.Write((int)m_RegionPriority); + writer.Write((int)m_Music); + writer.Write((TimeSpan)m_PlayerLogoutDelay); + writer.Write((int)m_LightLevel); + + writer.Write((Map)m_MoveNPCToMap); + writer.Write((Point3D)m_MoveNPCToLoc); + writer.Write((Map)m_MovePlayerToMap); + writer.Write((Point3D)m_MovePlayerToLoc); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + // Point3D customGoLoc = new Point3D(0,0,0); // REMOVED + switch (version) + { + // New RunUO 2.0 Version (case 5 and 4) + case 5: + { + // customGoLoc = reader.ReadPoint3D(); // REMOVED + goto case 4; + } + case 4: + { + m_RegionArea = ReadRect3DArray(reader); + + m_Flags = (RegionFlag)reader.ReadInt(); + + m_RestrictedSpells = ReadBitArray(reader); + m_RestrictedSkills = ReadBitArray(reader); + + m_Active = reader.ReadBool(); + + m_RegionName = reader.ReadString(); + m_RegionPriority = reader.ReadInt(); + m_Music = (MusicName)reader.ReadInt(); + m_PlayerLogoutDelay = reader.ReadTimeSpan(); + m_LightLevel = reader.ReadInt(); + + m_MoveNPCToMap = reader.ReadMap(); + m_MoveNPCToLoc = reader.ReadPoint3D(); + m_MovePlayerToMap = reader.ReadMap(); + m_MovePlayerToLoc = reader.ReadPoint3D(); + + break; + } + + // Old RunUO 1.0 Version (cases 3-0) + case 3: + { + m_LightLevel = reader.ReadInt(); + goto case 2; + } + case 2: + { + m_Music = (MusicName)reader.ReadInt(); + goto case 1; + } + case 1: + { + List rects2d = ReadRect2DArray(reader); + foreach (Rectangle2D rect in rects2d) + { + Rectangle3D newrect = Server.Region.ConvertTo3D(rect); + DoChooseArea(null, this.Map, newrect.Start, newrect.End, this); + } + + m_RegionPriority = reader.ReadInt(); + m_PlayerLogoutDelay = reader.ReadTimeSpan(); + + m_RestrictedSpells = ReadBitArray(reader); + m_RestrictedSkills = ReadBitArray(reader); + + m_Flags = (RegionFlag)reader.ReadInt(); + if (NoPlayerCorpses) + { + DeleteNPCCorpse = true; + DeletePlayerCorpse = true; + } + if (NoItemDrop) + { + NoPlayerItemDrop = true; + NoNPCItemDrop = true; + } + // Invert because of change from "Cannot" to "Can" + if (CanLootOwnCorpse) + { + CanLootOwnCorpse = false; + } + if (CanEnter) + { + CanEnter = false; + } + + m_RegionName = reader.ReadString(); + break; + } + case 0: + { + List rects2d = ReadRect2DArray(reader); + foreach (Rectangle2D rect in rects2d) + { + Rectangle3D newrect = Server.Region.ConvertTo3D(rect); + DoChooseArea(null, this.Map, newrect.Start, newrect.End, this); + } + + m_RestrictedSpells = ReadBitArray(reader); + m_RestrictedSkills = ReadBitArray(reader); + + m_Flags = (RegionFlag)reader.ReadInt(); + if (NoPlayerCorpses) + { + DeleteNPCCorpse = true; + DeletePlayerCorpse = true; + } + if (NoItemDrop) + { + NoPlayerItemDrop = true; + NoNPCItemDrop = true; + } + // Invert because of change from "Cannot" to "Can" + if (CanLootOwnCorpse) + { + CanLootOwnCorpse = false; + } + if (CanEnter) + { + CanEnter = false; + } + + m_RegionName = reader.ReadString(); + break; + } + } + + m_AllControls.Add(this); + + if(RegionNameTaken(m_RegionName)) + m_RegionName = FindNewName(m_RegionName); + + UpdateRegion(); + // m_CustomGoLocation = customGoLoc; // REMOVED + // CustomGoLocation = customGoLoc; // REMOVED + UpdateRegion(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionControlGump.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionControlGump.cs new file mode 100644 index 0000000..c535af8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RegionControlGump.cs @@ -0,0 +1,110 @@ +using System; +using Server; +using Server.Commands; +using Server.Gumps; +using Server.Items; +using Server.Network; + +namespace Server.Gumps +{ + public class RegionControlGump : Gump + { + RegionControl m_Controller; + public RegionControlGump( RegionControl r ) : base( 25, 50 ) + { + m_Controller = r; + + Closable=true; + Dragable=true; + Resizable=false; + + AddPage(0); + //x, y, width, high + AddBackground(23, 32, 412, 186, 9270); + AddAlphaRegion(19, 29, 418, 193); + + AddLabel(55, 60, 1152, "CUSTOM REGIONS IN A BOX"); + + AddLabel(75, 90, 1152, "Add Region Area"); + AddButton(55, 92, 0x845, 0x846, 3, GumpButtonType.Reply, 0); + + AddLabel(75, 110, 1152, "Edit Restricted Spells"); + AddButton(55, 112, 0x845, 0x846, 1, GumpButtonType.Reply, 0); + + AddLabel(75, 130, 1152, "Edit Restricted Skills"); + AddButton(55, 132, 0x845, 0x846, 2, GumpButtonType.Reply, 0); + + AddLabel(75, 150, 1152, "Edit Other Properties"); + AddButton(55, 152, 0x845, 0x846, 4, GumpButtonType.Reply, 0); + + AddLabel(75, 170, 1152, "See Region Bounds"); + AddButton(55, 172, 0x845, 0x846, 5, GumpButtonType.Reply, 0); + + AddImage(353, 54, 3953); + AddImage(353, 180, 3955); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if( m_Controller == null || m_Controller.Deleted ) + return; + + Mobile m = sender.Mobile; + string prefix = Server.Commands.CommandSystem.Prefix; + + switch( info.ButtonID ) + { + case 1: + { + //m_Controller.SendRestrictGump( m, RestrictType.Spells ); + m.CloseGump( typeof( SpellRestrictGump ) ); + m.SendGump( new SpellRestrictGump( m_Controller.RestrictedSpells ) ); + + m.CloseGump( typeof( RegionControlGump ) ); + m.SendGump( new RegionControlGump( m_Controller )); + break; + } + case 2: + { + //m_Controller.SendRestrictGump( m, RestrictType.Skills ); + + m.CloseGump( typeof( SkillRestrictGump ) ); + m.SendGump( new SkillRestrictGump( m_Controller.RestrictedSkills ) ); + + m.CloseGump( typeof( RegionControlGump ) ); + m.SendGump( new RegionControlGump( m_Controller )); + break; + } + case 3: + { + m.CloseGump( typeof( RegionControlGump ) ); + m.SendGump( new RegionControlGump( m_Controller ) ); + + m.CloseGump( typeof( RemoveAreaGump ) ); + m.SendGump( new RemoveAreaGump( m_Controller ) ); + + m_Controller.ChooseArea( m ); + break; + } + case 4: + { + m.SendGump( new PropertiesGump( m, m_Controller ) ); + m.CloseGump( typeof( RegionControlGump ) ); + m.SendGump( new RegionControlGump( m_Controller ) ); + m.CloseGump( typeof( RemoveAreaGump ) ); + m.SendGump( new RemoveAreaGump( m_Controller ) ); + break; + } + case 5: + { + CommandSystem.Handle( m, String.Format( "{0}RegionBounds", prefix ) ); + m.CloseGump( typeof( RegionControlGump ) ); + m.SendGump( new RegionControlGump( m_Controller ) ); + m.CloseGump( typeof( RemoveAreaGump ) ); + m.SendGump( new RemoveAreaGump( m_Controller ) ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RemoveAreaGump.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RemoveAreaGump.cs new file mode 100644 index 0000000..adaa6b8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RemoveAreaGump.cs @@ -0,0 +1,97 @@ +using System; +using Server; +using Server.Gumps; +using Server.Items; +using System.Collections; +using Server.Network; + +namespace Server.Gumps +{ + public class RemoveAreaGump : Gump + { + RegionControl m_Control; + + public RemoveAreaGump( RegionControl r ) : base( 25, 250 ) + { + m_Control = r; + + Closable=true; + Dragable=true; + Resizable=false; + + AddPage(0); + AddBackground(23, 32, 412, 256, 9270); + AddAlphaRegion(19, 29, 418, 263); + + AddLabel(186, 45, 1152, "REMOVE AREA"); + + + //+25 between 'em. + + int itemsThisPage = 0; + int nextPageNumber = 1; + + + if (r.RegionArea != null) + { + for(int i = 0; i < r.RegionArea.Length; i++) + { + Rectangle3D rect = ((Rectangle3D)r.RegionArea[i]); + + if (itemsThisPage >= 8 || itemsThisPage == 0) + { + itemsThisPage = 0; + + if (nextPageNumber != 1) + { + AddButton(393, 45, 4007, 4009, 0, GumpButtonType.Page, nextPageNumber); + //Forward button -> #0 + } + + AddPage(nextPageNumber++); + + if (nextPageNumber != 2) + { + AddButton(35, 45, 4014, 4016, 1, GumpButtonType.Page, nextPageNumber - 2); + //Back Button -> #1 + } + } + + AddButton(70, 75 + 25 * itemsThisPage, 4017, 4019, 100 + i, GumpButtonType.Reply, 0); + //Button is 100 + i + + //AddLabel(116, 77 + 25*i, 0, "(1234, 5678)"); + AddLabel(116, 77 + 25 * itemsThisPage, 1152, String.Format("({0}, {1}, {2})", rect.Start.X, rect.Start.Y, rect.Start.Z)); + + + AddLabel(232, 78 + 25 * itemsThisPage, 1152, "<-->"); + + //AddLabel(294, 77 + 25*i, 0, "(9876, 5432)"); + AddLabel(294, 77 + 25 * itemsThisPage, 1152, String.Format("({0}, {1}, {2})", rect.End.X, rect.End.Y, rect.End.Z)); + + itemsThisPage++; + + } + } + + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if (from == null) + return; + + if( info.ButtonID >= 100 ) + { + m_Control.RemoveArea( info.ButtonID - 100, from ); + + sender.Mobile.CloseGump( typeof( RemoveAreaGump ) ); + + sender.Mobile.SendGump( new RemoveAreaGump( m_Control ) ); + } + } + + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RestrictGump.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RestrictGump.cs new file mode 100644 index 0000000..a578110 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Custom Regions in a Box/RestrictGump.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Gumps; +using Server.Spells; +using Server.Network; +using System.Collections; + +public enum RestrictType +{ + Spells, + Skills +} + +namespace Server.Gumps +{ + public abstract class RestrictGump : Gump + { + BitArray m_Restricted; + + RestrictType m_type; + + public RestrictGump( BitArray ba, RestrictType t ) : base( 50, 50 ) + { + m_Restricted = ba; + m_type = t; + + Closable=true; + Dragable=true; + Resizable=false; + + AddPage(0); + + AddBackground(10, 10, 225, 425, 9380); + AddLabel(73, 15, 1152, (t == RestrictType.Spells) ? "Restrict Spells" : "Restrict Skills" ); + AddButton(91, 411, 247, 248, 1, GumpButtonType.Reply, 0); + //Okay Button -> # 1 + + + + int itemsThisPage = 0; + int nextPageNumber = 1; + + Object[] ary;// = (t == RestrictType.Skills) ? SkillInfo.Table : SpellRegistry.Types; + + if( t == RestrictType.Skills ) + ary = SkillInfo.Table; + else + ary = SpellRegistry.Types; + + + for( int i = 0; i < ary.Length; i++ ) + { + if( ary[i] != null ) + { + if( itemsThisPage >= 8 || itemsThisPage == 0) + { + itemsThisPage = 0; + + if( nextPageNumber != 1) + { + AddButton(190, 412, 4005, 4007, 2, GumpButtonType.Page, nextPageNumber); + //Forward button -> #2 + } + + AddPage( nextPageNumber++ ); + + if( nextPageNumber != 2) + { + AddButton(29, 412, 4014, 4016, 3, GumpButtonType.Page, nextPageNumber-2); + //Back Button -> #3 + } + } + + AddCheck(40, 55 + ( 45 * itemsThisPage ), 210, 211, ba[i], i + ((t == RestrictType.Spells) ? 100 : 500) ); + //checkbox -> ID = 100 + i for spells, 500 + i for skills + //Console.WriteLine( ary[i].GetType().ToString() ); + AddLabel(70, 55 + ( 45 * itemsThisPage ) , 0, ((t == RestrictType.Spells) ? ((Type)(ary[i])).Name : ((SkillInfo)(ary[i])).Name )); + + itemsThisPage++; + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if( info.ButtonID == 1 ) + { + for( int i = 0; i < m_Restricted.Length; i++ ) + { + m_Restricted[ i ] = info.IsSwitched( i + ((m_type == RestrictType.Spells) ? 100 : 500 )); + //This way is faster after looking at decompiled BitArray.SetAll( bool ) + } + } + } + } + + public class SpellRestrictGump : RestrictGump + { + public SpellRestrictGump( BitArray ba ) : base( ba, RestrictType.Spells ) + { + + } + } + + public class SkillRestrictGump : RestrictGump + { + public SkillRestrictGump( BitArray ba ) : base( ba, RestrictType.Skills ) + { + + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/PremiumSpawner.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/PremiumSpawner.cs new file mode 100644 index 0000000..58e5b87 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/PremiumSpawner.cs @@ -0,0 +1,1635 @@ +//Engine r91 +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using Server; +using Server.Commands; +using Server.Items; +using Server.Network; +using CPA = Server.CommandPropertyAttribute; + +namespace Server.Mobiles +{ + public class PremiumSpawner : Item + { + private int m_Team; + private int m_HomeRange; // = old SpawnRange + private int m_WalkingRange = -1; // = old HomeRange + private int m_SpawnID = 1; + private int m_Count; + private int m_CountA; + private int m_CountB; + private int m_CountC; + private int m_CountD; + private int m_CountE; + private TimeSpan m_MinDelay; + private TimeSpan m_MaxDelay; + private List m_CreaturesName; // creatures to be spawned + private List m_Creatures; // spawned creatures + private List m_CreaturesNameA; + private List m_CreaturesA; + private List m_CreaturesNameB; + private List m_CreaturesB; + private List m_CreaturesNameC; + private List m_CreaturesC; + private List m_CreaturesNameD; + private List m_CreaturesD; + private List m_CreaturesNameE; + private List m_CreaturesE; + private DateTime m_End; + private InternalTimer m_Timer; + private bool m_Running; + private bool m_Water; + private bool m_Group; + private WayPoint m_WayPoint; + + public bool IsFull { get { return (m_Creatures != null && m_Creatures.Count >= m_Count); } } + public bool IsFulla { get { return (m_CreaturesA != null && m_CreaturesA.Count >= m_CountA); } } + public bool IsFullb { get { return (m_CreaturesB != null && m_CreaturesB.Count >= m_CountB); } } + public bool IsFullc { get { return (m_CreaturesC != null && m_CreaturesC.Count >= m_CountC); } } + public bool IsFulld { get { return (m_CreaturesD != null && m_CreaturesD.Count >= m_CountD); } } + public bool IsFulle { get { return (m_CreaturesE != null && m_CreaturesE.Count >= m_CountE); } } + + public List CreaturesName + { + get { return m_CreaturesName; } + set + { + m_CreaturesName = value; + if (m_CreaturesName.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public List SubSpawnerA + { + get { return m_CreaturesNameA; } + set + { + m_CreaturesNameA = value; + if (m_CreaturesNameA.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public List SubSpawnerB + { + get { return m_CreaturesNameB; } + set + { + m_CreaturesNameB = value; + if (m_CreaturesNameB.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public List SubSpawnerC + { + get { return m_CreaturesNameC; } + set + { + m_CreaturesNameC = value; + if (m_CreaturesNameC.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public List SubSpawnerD + { + get { return m_CreaturesNameD; } + set + { + m_CreaturesNameD = value; + if (m_CreaturesNameD.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public List SubSpawnerE + { + get { return m_CreaturesNameE; } + set + { + m_CreaturesNameE = value; + if (m_CreaturesNameE.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public virtual int CreaturesNameCount { get { return m_CreaturesName.Count; } } + public virtual int CreaturesNameCountA { get { return m_CreaturesNameA.Count; } } + public virtual int CreaturesNameCountB { get { return m_CreaturesNameB.Count; } } + public virtual int CreaturesNameCountC { get { return m_CreaturesNameC.Count; } } + public virtual int CreaturesNameCountD { get { return m_CreaturesNameD.Count; } } + public virtual int CreaturesNameCountE { get { return m_CreaturesNameE.Count; } } + + public override void OnAfterDuped(Item newItem) + { + PremiumSpawner s = newItem as PremiumSpawner; + + if (s == null) + return; + + s.m_CreaturesName = new List(m_CreaturesName); + s.m_CreaturesNameA = new List(m_CreaturesNameA); + s.m_CreaturesNameB = new List(m_CreaturesNameB); + s.m_CreaturesNameC = new List(m_CreaturesNameC); + s.m_CreaturesNameD = new List(m_CreaturesNameD); + s.m_CreaturesNameE = new List(m_CreaturesNameE); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Count + { + get { return m_Count; } + set { m_Count = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CountA + { + get { return m_CountA; } + set { m_CountA = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CountB + { + get { return m_CountB; } + set { m_CountB = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CountC + { + get { return m_CountC; } + set { m_CountC = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CountD + { + get { return m_CountD; } + set { m_CountD = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CountE + { + get { return m_CountE; } + set { m_CountE = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint WayPoint + { + get + { + return m_WayPoint; + } + set + { + m_WayPoint = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Running + { + get { return m_Running; } + set + { + if (value) + Start(); + else + Stop(); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HomeRange + { + get { return m_HomeRange; } + set { m_HomeRange = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int WalkingRange + { + get { return m_WalkingRange; } + set { m_WalkingRange = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SpawnID + { + get { return m_SpawnID; } + set { m_SpawnID = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Team + { + get { return m_Team; } + set { m_Team = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MinDelay + { + get { return m_MinDelay; } + set { m_MinDelay = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MaxDelay + { + get { return m_MaxDelay; } + set { m_MaxDelay = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSpawn + { + get + { + if (m_Running) + return m_End - DateTime.Now; + else + return TimeSpan.FromSeconds(0); + } + set + { + Start(); + DoTimer(value); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Group + { + get { return m_Group; } + set { m_Group = value; InvalidateProperties(); } + } + + [Constructable] + public PremiumSpawner(int amount, int subamountA, int subamountB, int subamountC, int subamountD, int subamountE, int spawnid, int minDelay, int maxDelay, int team, int homeRange, int walkingRange, string creatureName, string creatureNameA, string creatureNameB, string creatureNameC, string creatureNameD, string creatureNameE) + : base(0x1f13) + { + List creaturesName = new List(); + creaturesName.Add(creatureName); + + List creatureNameAA = new List(); + creaturesName.Add(creatureNameA); + + List creatureNameBB = new List(); + creaturesName.Add(creatureNameB); + + List creatureNameCC = new List(); + creaturesName.Add(creatureNameC); + + List creatureNameDD = new List(); + creaturesName.Add(creatureNameD); + + List creatureNameEE = new List(); + creaturesName.Add(creatureNameE); + + InitSpawn(amount, subamountA, subamountB, subamountC, subamountD, subamountE, spawnid, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), team, homeRange, walkingRange, creaturesName, creatureNameAA, creatureNameBB, creatureNameCC, creatureNameDD, creatureNameEE); + } + + [Constructable] + public PremiumSpawner(string creatureName) + : base(0x1f13) + { + List creaturesName = new List(); + creaturesName.Add(creatureName); + + List creatureNameAA = new List(); + List creatureNameBB = new List(); + List creatureNameCC = new List(); + List creatureNameDD = new List(); + List creatureNameEE = new List(); + + InitSpawn(1, 0, 0, 0, 0, 0, 1, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), 0, 4, -1, creaturesName, creatureNameAA, creatureNameBB, creatureNameCC, creatureNameDD, creatureNameEE); + } + + [Constructable] + public PremiumSpawner() + : base(0x1f13) + { + List creaturesName = new List(); + + List creatureNameAA = new List(); + List creatureNameBB = new List(); + List creatureNameCC = new List(); + List creatureNameDD = new List(); + List creatureNameEE = new List(); + + InitSpawn(1, 0, 0, 0, 0, 0, 1, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), 0, 4, -1, creaturesName, creatureNameAA, creatureNameBB, creatureNameCC, creatureNameDD, creatureNameEE); + } + + public PremiumSpawner(int amount, int subamountA, int subamountB, int subamountC, int subamountD, int subamountE, int spawnid, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, int walkingRange, List creaturesName, List creatureNameAA, List creatureNameBB, List creatureNameCC, List creatureNameDD, List creatureNameEE) + : base(0x1f13) + { + InitSpawn(amount, subamountA, subamountB, subamountC, subamountD, subamountE, spawnid, minDelay, maxDelay, team, homeRange, walkingRange, creaturesName, creatureNameAA, creatureNameBB, creatureNameCC, creatureNameDD, creatureNameEE); + } + + public override string DefaultName + { + get { return "PremiumSpawner"; } + } + + public void InitSpawn(int amount, int subamountA, int subamountB, int subamountC, int subamountD, int subamountE, int SpawnID, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, int walkingRange, List creaturesName, List creatureNameAA, List creatureNameBB, List creatureNameCC, List creatureNameDD, List creatureNameEE) + { + Name = "PremiumSpawner"; + m_SpawnID = SpawnID; + Visible = false; + Movable = false; + m_Running = true; + m_Water = false; + m_Group = false; + m_MinDelay = minDelay; + m_MaxDelay = maxDelay; + m_Count = amount; + m_CountA = subamountA; + m_CountB = subamountB; + m_CountC = subamountC; + m_CountD = subamountD; + m_CountE = subamountE; + m_Team = team; + m_HomeRange = homeRange; + m_WalkingRange = walkingRange; + m_CreaturesName = creaturesName; + m_CreaturesNameA = creatureNameAA; + m_CreaturesNameB = creatureNameBB; + m_CreaturesNameC = creatureNameCC; + m_CreaturesNameD = creatureNameDD; + m_CreaturesNameE = creatureNameEE; + m_Creatures = new List(); + m_CreaturesA = new List(); + m_CreaturesB = new List(); + m_CreaturesC = new List(); + m_CreaturesD = new List(); + m_CreaturesE = new List(); + DoTimer(TimeSpan.FromSeconds(1)); + } + + public PremiumSpawner(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel < AccessLevel.GameMaster) + return; + + PremiumSpawnerGump g = new PremiumSpawnerGump(this); + from.SendGump(g); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Running) + { + list.Add(1060742); // active + + list.Add(1060656, m_Count.ToString()); + list.Add(1061169, m_HomeRange.ToString()); + list.Add(1060658, "walking range\t{0}", m_WalkingRange); + + list.Add(1060663, "SpawnID\t{0}", m_SpawnID.ToString()); + + // list.Add( 1060659, "group\t{0}", m_Group ); + // list.Add( 1060660, "team\t{0}", m_Team ); + list.Add(1060661, "speed\t{0} to {1}", m_MinDelay, m_MaxDelay); + + for (int i = 0; i < 2 && i < m_CreaturesName.Count; ++i) + list.Add(1060662 + i, "{0}\t{1}", m_CreaturesName[i], CountCreatures(m_CreaturesName[i])); + } + else + { + list.Add(1060743); // inactive + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Running) + LabelTo(from, "[Running]"); + else + LabelTo(from, "[Off]"); + } + + public void SpawnWater() + { + } + + public void Start() + { + if (!m_Running) + { + if (m_CreaturesName.Count > 0 || m_CreaturesNameA.Count > 0 || m_CreaturesNameB.Count > 0 || m_CreaturesNameC.Count > 0 || m_CreaturesNameD.Count > 0 || m_CreaturesNameE.Count > 0) + { + m_Running = true; + DoTimer(); + } + } + } + + public void Stop() + { + if (m_Running) + { + m_Timer.Stop(); + m_Running = false; + } + } + + public static string ParseType(string s) + { + return s.Split(null, 2)[0]; + } + + public void Defrag(List m_Beings) + { + bool removed = false; + + for (int i = 0; i < m_Beings.Count; ++i) + { + IEntity e = m_Beings[i]; + + if (e is Item) + { + Item item = (Item)e; + + if (item.Deleted || item.Parent != null) + { + m_Beings.RemoveAt(i); + --i; + removed = true; + } + } + else if (e is Mobile) + { + Mobile m = (Mobile)e; + + if (m.Deleted) + { + m_Beings.RemoveAt(i); + --i; + removed = true; + } + else if (m is BaseCreature) + { + BaseCreature bc = (BaseCreature)m; + if (bc.Controlled || bc.IsStabled) + { + m_Beings.RemoveAt(i); + --i; + removed = true; + } + } + } + else + { + m_Beings.RemoveAt(i); + --i; + removed = true; + } + } + + if (removed) + InvalidateProperties(); + } + + public void OnTick() + { + DoTimer(); + + if (m_Group) + { + Defrag(m_Creatures); + Defrag(m_CreaturesA); + Defrag(m_CreaturesB); + Defrag(m_CreaturesC); + Defrag(m_CreaturesD); + Defrag(m_CreaturesE); + + if (m_Creatures.Count == 0 || m_CreaturesA.Count == 0 || m_CreaturesB.Count == 0 || m_CreaturesC.Count == 0 || m_CreaturesD.Count == 0 || m_CreaturesE.Count == 0) + { + Respawn(); + } + else + { + return; + } + } + else + { + Spawn(CreaturesNameCount, m_Creatures, m_Count, m_CreaturesName); + Spawn(CreaturesNameCountA, m_CreaturesA, m_CountA, m_CreaturesNameA); + Spawn(CreaturesNameCountB, m_CreaturesB, m_CountB, m_CreaturesNameB); + Spawn(CreaturesNameCountC, m_CreaturesC, m_CountC, m_CreaturesNameC); + Spawn(CreaturesNameCountD, m_CreaturesD, m_CountD, m_CreaturesNameD); + Spawn(CreaturesNameCountE, m_CreaturesE, m_CountE, m_CreaturesNameE); + } + } + + public void Respawn() // remove all creatures and spawn all again + { + RemoveCreatures(m_Creatures); + RemoveCreatures(m_CreaturesA); + RemoveCreatures(m_CreaturesB); + RemoveCreatures(m_CreaturesC); + RemoveCreatures(m_CreaturesD); + RemoveCreatures(m_CreaturesE); + + for (int i = 0; i < m_Count; i++) + Spawn(CreaturesNameCount, m_Creatures, m_Count, m_CreaturesName); + for (int i = 0; i < m_CountA; i++) + Spawn(CreaturesNameCountA, m_CreaturesA, m_CountA, m_CreaturesNameA); + for (int i = 0; i < m_CountB; i++) + Spawn(CreaturesNameCountB, m_CreaturesB, m_CountB, m_CreaturesNameB); + for (int i = 0; i < m_CountC; i++) + Spawn(CreaturesNameCountC, m_CreaturesC, m_CountC, m_CreaturesNameC); + for (int i = 0; i < m_CountD; i++) + Spawn(CreaturesNameCountD, m_CreaturesD, m_CountD, m_CreaturesNameD); + for (int i = 0; i < m_CountE; i++) + Spawn(CreaturesNameCountE, m_CreaturesE, m_CountE, m_CreaturesNameE); + } + + public void Spawn(int CreatNameCount, List m_Creat, int m_Countt, List m_CreatName) + { + if (CreatNameCount > 0) + SpawnTwo(Utility.Random(CreatNameCount), CreatNameCount, m_Creat, m_Countt, m_CreatName); + + } + + // Spawn(string anystring) - all this works for PremiumSpawnerGump(line 422) and SpawnEditor(line 957) + // But this funcionality is broken in these scripts. + public void Spawn(string creatureName) + { + for (int i = 0; i < m_CreaturesName.Count; i++) + { + if (m_CreaturesName[i] == creatureName) + { + SpawnTwo(i, CreaturesNameCount, m_Creatures, m_Count, m_CreaturesName); + break; + } + } + } + + public void SpawnA(string creatureNameA) + { + for (int i = 0; i < m_CreaturesNameA.Count; i++) + { + if ((string)m_CreaturesNameA[i] == creatureNameA) + { + SpawnTwo(i, CreaturesNameCountA, m_CreaturesA, m_CountA, m_CreaturesNameA); + break; + } + } + } + + public void SpawnB(string creatureNameB) + { + for (int i = 0; i < m_CreaturesNameB.Count; i++) + { + if ((string)m_CreaturesNameB[i] == creatureNameB) + { + SpawnTwo(i, CreaturesNameCountB, m_CreaturesB, m_CountB, m_CreaturesNameB); + break; + } + } + } + + public void SpawnC(string creatureNameC) + { + for (int i = 0; i < m_CreaturesNameC.Count; i++) + { + if ((string)m_CreaturesNameC[i] == creatureNameC) + { + SpawnTwo(i, CreaturesNameCountC, m_CreaturesC, m_CountC, m_CreaturesNameC); + break; + } + } + } + + public void SpawnD(string creatureNameD) + { + for (int i = 0; i < m_CreaturesNameD.Count; i++) + { + if ((string)m_CreaturesNameD[i] == creatureNameD) + { + SpawnTwo(i, CreaturesNameCountD, m_CreaturesD, m_CountD, m_CreaturesNameD); + break; + } + } + } + + public void SpawnE(string creatureNameE) + { + for (int i = 0; i < m_CreaturesNameE.Count; i++) + { + if ((string)m_CreaturesNameE[i] == creatureNameE) + { + SpawnTwo(i, CreaturesNameCountE, m_CreaturesE, m_CountE, m_CreaturesNameE); + break; + } + } + } + + protected virtual IEntity CreateSpawnedObject(int index, List m_CreatName) + { + if (index >= m_CreatName.Count) + return null; + + Type type = ScriptCompiler.FindTypeByName(ParseType(m_CreatName[index])); + + if (type != null) + { + try + { + return Build(CommandSystem.Split(m_CreatName[index])); + } + catch + { + } + } + + return null; + } + + public static IEntity Build(string[] args) + { + string name = args[0]; + + Add.FixArgs(ref args); + + string[,] props = null; + + for (int i = 0; i < args.Length; ++i) + { + if (Insensitive.Equals(args[i], "set")) + { + int remains = args.Length - i - 1; + + if (remains >= 2) + { + props = new string[remains / 2, 2]; + + remains /= 2; + + for (int j = 0; j < remains; ++j) + { + props[j, 0] = args[i + (j * 2) + 1]; + props[j, 1] = args[i + (j * 2) + 2]; + } + + Add.FixSetString(ref args, i); + } + + break; + } + } + + Type type = ScriptCompiler.FindTypeByName(name); + + if (!Add.IsEntity(type)) + { + return null; + } + + PropertyInfo[] realProps = null; + + if (props != null) + { + realProps = new PropertyInfo[props.GetLength(0)]; + + PropertyInfo[] allProps = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + for (int i = 0; i < realProps.Length; ++i) + { + PropertyInfo thisProp = null; + + string propName = props[i, 0]; + + for (int j = 0; thisProp == null && j < allProps.Length; ++j) + { + if (Insensitive.Equals(propName, allProps[j].Name)) + thisProp = allProps[j]; + } + + if (thisProp != null) + { + CPA attr = Properties.GetCPA(thisProp); + + if (attr != null && AccessLevel.GameMaster >= attr.WriteLevel && thisProp.CanWrite && !attr.ReadOnly) + realProps[i] = thisProp; + } + } + } + + ConstructorInfo[] ctors = type.GetConstructors(); + + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + if (!Add.IsConstructable(ctor, AccessLevel.GameMaster)) + continue; + + ParameterInfo[] paramList = ctor.GetParameters(); + + if (args.Length == paramList.Length) + { + object[] paramValues = Add.ParseValues(paramList, args); + + if (paramValues == null) + continue; + + object built = ctor.Invoke(paramValues); + + if (built != null && realProps != null) + { + for (int j = 0; j < realProps.Length; ++j) + { + if (realProps[j] == null) + continue; + + string result = Properties.InternalSetValue(built, realProps[j], props[j, 1]); + } + } + + return (IEntity)built; + } + } + + return null; + } + + public void SpawnTwo(int index, int CreatNameCount, List m_Creat, int m_Countt, List m_CreatName) + { + Map map = Map; + + if (map == null || map == Map.Internal || CreatNameCount == 0 || index >= CreatNameCount || Parent != null) + return; + + Defrag(m_Creatures); + Defrag(m_CreaturesA); + Defrag(m_CreaturesB); + Defrag(m_CreaturesC); + Defrag(m_CreaturesD); + Defrag(m_CreaturesE); + + if (m_Creat.Count >= m_Countt) + return; + + + IEntity ent = CreateSpawnedObject(index, m_CreatName); + + if (ent is Mobile) + { + Mobile m = (Mobile)ent; + + if (m.CanSwim) + { + m_Water = true; + } + else + { + m_Water = false; + } + + m_Creat.Add(m); + + + Point3D loc = (m is BaseVendor ? this.Location : GetSpawnPosition()); + + if (m is WanderingHealer || m is EvilWanderingHealer || m is EvilHealer) + { + loc = GetSpawnPosition(); + } + + m.OnBeforeSpawn(loc, map); + InvalidateProperties(); + + + m.MoveToWorld(loc, map); + + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + + if (m_WalkingRange >= 0) + c.RangeHome = m_WalkingRange; + else + c.RangeHome = m_HomeRange; + + c.CurrentWayPoint = m_WayPoint; + + if (m_Team > 0) + c.Team = m_Team; + + c.Home = this.Location; + } + + m.OnAfterSpawn(); + } + else if (ent is Item) + { + Item item = (Item)ent; + + m_Creat.Add(item); + + Point3D loc = GetSpawnPosition(); + + item.OnBeforeSpawn(loc, map); + InvalidateProperties(); + + item.MoveToWorld(loc, map); + + item.OnAfterSpawn(); + } + } + + public Point3D GetSpawnPosition() + { + Map map = Map; + + if (map == null) + return Location; + + // Try 10 times to find a Spawnable location. + for (int i = 0; i < 10; i++) + { + int x, y; + + if (m_HomeRange > 0) + { + x = Location.X + (Utility.Random((m_HomeRange * 2) + 1) - m_HomeRange); + y = Location.Y + (Utility.Random((m_HomeRange * 2) + 1) - m_HomeRange); + } + else + { + x = Location.X; + y = Location.Y; + } + + int z = Map.GetAverageZ(x, y); + + if (m_Water) + { + TileMatrix tiles = Map.Tiles; + LandTile _tile = tiles.GetLandTile(x, y); + int id = _tile.ID; + if ((id >= 168 && id <= 171) || id == 100) + { + return new Point3D(x, y, this.Z); + } + } + + if (Map.CanSpawnMobile(new Point2D(x, y), this.Z)) + return new Point3D(x, y, this.Z); + else if (Map.CanSpawnMobile(new Point2D(x, y), z)) + return new Point3D(x, y, z); + } + + return this.Location; + } + + public void DoTimer() + { + if (!m_Running) + return; + + int minSeconds = (int)m_MinDelay.TotalSeconds; + int maxSeconds = (int)m_MaxDelay.TotalSeconds; + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)); + DoTimer(delay); + } + + public void DoTimer(TimeSpan delay) + { + if (!m_Running) + return; + + m_End = DateTime.Now + delay; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = new InternalTimer(this, delay); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + private PremiumSpawner m_PremiumSpawner; + + public InternalTimer(PremiumSpawner spawner, TimeSpan delay) + : base(delay) + { + if (spawner.IsFull || spawner.IsFulla || spawner.IsFullb || spawner.IsFullc || spawner.IsFulld || spawner.IsFulle) + Priority = TimerPriority.FiveSeconds; + else + Priority = TimerPriority.OneSecond; + + m_PremiumSpawner = spawner; + } + + protected override void OnTick() + { + if (m_PremiumSpawner != null) + if (!m_PremiumSpawner.Deleted) + m_PremiumSpawner.OnTick(); + } + } + + public int CountCreatures(string creatureName) + { + Defrag(m_Creatures); + + int count = 0; + + for (int i = 0; i < m_Creatures.Count; ++i) + if (Insensitive.Equals(creatureName, m_Creatures[i].GetType().Name)) + ++count; + + return count; + } + + public int CountCreaturesA(string creatureNameA) + { + Defrag(m_CreaturesA); + + int count = 0; + + for (int i = 0; i < m_CreaturesA.Count; ++i) + if (Insensitive.Equals(creatureNameA, m_CreaturesA[i].GetType().Name)) + ++count; + + return count; + } + + public int CountCreaturesB(string creatureNameB) + { + Defrag(m_CreaturesB); + + int count = 0; + + for (int i = 0; i < m_CreaturesB.Count; ++i) + if (Insensitive.Equals(creatureNameB, m_CreaturesB[i].GetType().Name)) + ++count; + + return count; + } + + public int CountCreaturesC(string creatureNameC) + { + Defrag(m_CreaturesC); + + int count = 0; + + for (int i = 0; i < m_CreaturesC.Count; ++i) + if (Insensitive.Equals(creatureNameC, m_CreaturesC[i].GetType().Name)) + ++count; + + return count; + } + + public int CountCreaturesD(string creatureNameD) + { + Defrag(m_CreaturesD); + + int count = 0; + + for (int i = 0; i < m_CreaturesD.Count; ++i) + if (Insensitive.Equals(creatureNameD, m_CreaturesD[i].GetType().Name)) + ++count; + + return count; + } + + public int CountCreaturesE(string creatureNameE) + { + Defrag(m_CreaturesE); + + int count = 0; + + for (int i = 0; i < m_CreaturesE.Count; ++i) + if (Insensitive.Equals(creatureNameE, m_CreaturesE[i].GetType().Name)) + ++count; + + return count; + } + + // RemoveCreatures(string anystring) - all this works for PremiumSpawnerGump(line 579) and SpawnEditor(line 957) + // But this funcionality is broken in these scripts. + public void RemoveCreatures(string creatureName) + { + Defrag(m_Creatures); + + for (int i = 0; i < m_Creatures.Count; ++i) + { + IEntity e = m_Creatures[i]; + + if (Insensitive.Equals(creatureName, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveCreaturesA(string creatureNameA) + { + Defrag(m_CreaturesA); + + for (int i = 0; i < m_CreaturesA.Count; ++i) + { + IEntity e = m_CreaturesA[i]; + + if (Insensitive.Equals(creatureNameA, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveCreaturesB(string creatureNameB) + { + Defrag(m_CreaturesB); + + for (int i = 0; i < m_CreaturesB.Count; ++i) + { + IEntity e = m_CreaturesB[i]; + + if (Insensitive.Equals(creatureNameB, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveCreaturesC(string creatureNameC) + { + Defrag(m_CreaturesC); + + for (int i = 0; i < m_CreaturesC.Count; ++i) + { + IEntity e = m_CreaturesC[i]; + + if (Insensitive.Equals(creatureNameC, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveCreaturesD(string creatureNameD) + { + Defrag(m_CreaturesD); + + for (int i = 0; i < m_CreaturesD.Count; ++i) + { + IEntity e = m_CreaturesD[i]; + + if (Insensitive.Equals(creatureNameD, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveCreaturesE(string creatureNameE) + { + Defrag(m_CreaturesE); + + for (int i = 0; i < m_CreaturesE.Count; ++i) + { + IEntity e = m_CreaturesE[i]; + + if (Insensitive.Equals(creatureNameE, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveCreatures(List m_Creatur) + { + Defrag(m_Creatur); + + for (int i = 0; i < m_Creatur.Count; ++i) + m_Creatur[i].Delete(); + + InvalidateProperties(); + } + + //Used by PremiumSpawnerGump + public void BringToHome(List m_Beings) + { + for (int i = 0; i < m_Beings.Count; ++i) + { + IEntity e = m_Beings[i]; + + if (e is Mobile) + { + Mobile m = (Mobile)e; + + m.MoveToWorld(Location, Map); + } + else if (e is Item) + { + Item item = (Item)e; + + item.MoveToWorld(Location, Map); + } + } + } + + //Used by PremiumSpawnerGump + public void BringToHome() + { + Defrag(m_Creatures); + Defrag(m_CreaturesA); + Defrag(m_CreaturesB); + Defrag(m_CreaturesC); + Defrag(m_CreaturesD); + Defrag(m_CreaturesE); + + BringToHome(m_Creatures); + BringToHome(m_CreaturesA); + BringToHome(m_CreaturesB); + BringToHome(m_CreaturesC); + BringToHome(m_CreaturesD); + BringToHome(m_CreaturesE); + } + + public override void OnDelete() + { + base.OnDelete(); + + RemoveCreatures(m_Creatures); + RemoveCreatures(m_CreaturesA); + RemoveCreatures(m_CreaturesB); + RemoveCreatures(m_CreaturesC); + RemoveCreatures(m_CreaturesD); + RemoveCreatures(m_CreaturesE); + if (m_Timer != null) + m_Timer.Stop(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)4); // version + writer.Write(m_WalkingRange); + + writer.Write(m_SpawnID); + writer.Write(m_CountA); + writer.Write(m_CountB); + writer.Write(m_CountC); + writer.Write(m_CountD); + writer.Write(m_CountE); + + writer.Write(m_WayPoint); + + writer.Write(m_Group); + + writer.Write(m_MinDelay); + writer.Write(m_MaxDelay); + writer.Write(m_Count); + writer.Write(m_Team); + writer.Write(m_HomeRange); + writer.Write(m_Running); + + if (m_Running) + writer.WriteDeltaTime(m_End); + + writer.Write(m_CreaturesName.Count); + + for (int i = 0; i < m_CreaturesName.Count; ++i) + writer.Write(m_CreaturesName[i]); + + writer.Write(m_CreaturesNameA.Count); + + for (int i = 0; i < m_CreaturesNameA.Count; ++i) + writer.Write((string)m_CreaturesNameA[i]); + + writer.Write(m_CreaturesNameB.Count); + + for (int i = 0; i < m_CreaturesNameB.Count; ++i) + writer.Write((string)m_CreaturesNameB[i]); + + writer.Write(m_CreaturesNameC.Count); + + for (int i = 0; i < m_CreaturesNameC.Count; ++i) + writer.Write((string)m_CreaturesNameC[i]); + + writer.Write(m_CreaturesNameD.Count); + + for (int i = 0; i < m_CreaturesNameD.Count; ++i) + writer.Write((string)m_CreaturesNameD[i]); + + writer.Write(m_CreaturesNameE.Count); + + for (int i = 0; i < m_CreaturesNameE.Count; ++i) + writer.Write((string)m_CreaturesNameE[i]); + + writer.Write(m_Creatures.Count); + + for (int i = 0; i < m_Creatures.Count; ++i) + { + IEntity e = m_Creatures[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + + writer.Write(m_CreaturesA.Count); + + for (int i = 0; i < m_CreaturesA.Count; ++i) + { + IEntity e = m_CreaturesA[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + + writer.Write(m_CreaturesB.Count); + + for (int i = 0; i < m_CreaturesB.Count; ++i) + { + IEntity e = m_CreaturesB[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + + writer.Write(m_CreaturesC.Count); + + for (int i = 0; i < m_CreaturesC.Count; ++i) + { + IEntity e = m_CreaturesC[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + + writer.Write(m_CreaturesD.Count); + + for (int i = 0; i < m_CreaturesD.Count; ++i) + { + IEntity e = m_CreaturesD[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + + writer.Write(m_CreaturesE.Count); + + for (int i = 0; i < m_CreaturesE.Count; ++i) + { + IEntity e = m_CreaturesE[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + + } + + private static WarnTimer m_WarnTimer; + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 4: + { + m_WalkingRange = reader.ReadInt(); + m_SpawnID = reader.ReadInt(); + m_CountA = reader.ReadInt(); + m_CountB = reader.ReadInt(); + m_CountC = reader.ReadInt(); + m_CountD = reader.ReadInt(); + m_CountE = reader.ReadInt(); + + goto case 3; + } + case 3: + case 2: + { + m_WayPoint = reader.ReadItem() as WayPoint; + + goto case 1; + } + + case 1: + { + m_Group = reader.ReadBool(); + + goto case 0; + } + + case 0: + { + m_MinDelay = reader.ReadTimeSpan(); + m_MaxDelay = reader.ReadTimeSpan(); + m_Count = reader.ReadInt(); + m_Team = reader.ReadInt(); + m_HomeRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + + TimeSpan ts = TimeSpan.Zero; + + if (m_Running) + ts = reader.ReadDeltaTime() - DateTime.Now; + + int size = reader.ReadInt(); + m_CreaturesName = new List(size); + for (int i = 0; i < size; ++i) + { + string creatureString = reader.ReadString(); + + m_CreaturesName.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int sizeA = reader.ReadInt(); + m_CreaturesNameA = new List(sizeA); + for (int i = 0; i < sizeA; ++i) + { + string creatureString = reader.ReadString(); + + m_CreaturesNameA.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int sizeB = reader.ReadInt(); + m_CreaturesNameB = new List(sizeB); + for (int i = 0; i < sizeB; ++i) + { + string creatureString = reader.ReadString(); + + m_CreaturesNameB.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int sizeC = reader.ReadInt(); + m_CreaturesNameC = new List(sizeC); + for (int i = 0; i < sizeC; ++i) + { + string creatureString = reader.ReadString(); + + m_CreaturesNameC.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int sizeD = reader.ReadInt(); + m_CreaturesNameD = new List(sizeD); + for (int i = 0; i < sizeD; ++i) + { + string creatureString = reader.ReadString(); + + m_CreaturesNameD.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int sizeE = reader.ReadInt(); + m_CreaturesNameE = new List(sizeE); + for (int i = 0; i < sizeE; ++i) + { + string creatureString = reader.ReadString(); + + m_CreaturesNameE.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int count = reader.ReadInt(); + m_Creatures = new List(count); + for (int i = 0; i < count; ++i) + { + IEntity e = World.FindEntity(reader.ReadInt()); + + if (e != null) + m_Creatures.Add(e); + } + + int countA = reader.ReadInt(); + m_CreaturesA = new List(countA); + for (int i = 0; i < countA; ++i) + { + IEntity e = World.FindEntity(reader.ReadInt()); + + if (e != null) + m_CreaturesA.Add(e); + } + + int countB = reader.ReadInt(); + m_CreaturesB = new List(countB); + for (int i = 0; i < countB; ++i) + { + IEntity e = World.FindEntity(reader.ReadInt()); + + if (e != null) + m_CreaturesB.Add(e); + } + + int countC = reader.ReadInt(); + m_CreaturesC = new List(countC); + for (int i = 0; i < countC; ++i) + { + IEntity e = World.FindEntity(reader.ReadInt()); + + if (e != null) + m_CreaturesC.Add(e); + } + + int countD = reader.ReadInt(); + m_CreaturesD = new List(countD); + for (int i = 0; i < countD; ++i) + { + IEntity e = World.FindEntity(reader.ReadInt()); + + if (e != null) + m_CreaturesD.Add(e); + } + + int countE = reader.ReadInt(); + m_CreaturesE = new List(countE); + for (int i = 0; i < countE; ++i) + { + IEntity e = World.FindEntity(reader.ReadInt()); + + if (e != null) + m_CreaturesE.Add(e); + } + + if (m_Running) + DoTimer(ts); + + break; + } + } + + if (version < 3 && Weight == 0) + Weight = -1; + } + + private class WarnTimer : Timer + { + private List m_List; + + private class WarnEntry + { + public Point3D m_Point; + public Map m_Map; + public string m_Name; + + public WarnEntry(Point3D p, Map map, string name) + { + m_Point = p; + m_Map = map; + m_Name = name; + } + } + + public WarnTimer() + : base(TimeSpan.FromSeconds(1.0)) + { + m_List = new List(); + Start(); + } + + public void Add(Point3D p, Map map, string name) + { + m_List.Add(new WarnEntry(p, map, name)); + } + + protected override void OnTick() + { + try + { + Console.WriteLine("Warning: {0} bad spawns detected, logged: 'PremiumBadspawn.log'", m_List.Count); + + using (StreamWriter op = new StreamWriter("PremiumBadspawn.log", true)) + { + op.WriteLine("# Bad spawns : {0}", DateTime.Now); + op.WriteLine("# Format: X Y Z F Name"); + op.WriteLine(); + + foreach (WarnEntry e in m_List) + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name); + + op.WriteLine(); + op.WriteLine(); + } + } + catch + { + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/PremiumSpawnerGump.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/PremiumSpawnerGump.cs new file mode 100644 index 0000000..5d02860 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/PremiumSpawnerGump.cs @@ -0,0 +1,505 @@ +//Engine r73 +using System; +using System.Collections; +using Server.Network; +using Server.Gumps; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class PremiumSpawnerGump : Gump + { + private PremiumSpawner m_Spawner; + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public PremiumSpawnerGump( PremiumSpawner spawner ) : base( 50, 50 ) + { + m_Spawner = spawner; + + AddPage( 1 ); + + AddBackground( 0, 0, 350, 360, 5054 ); + + AddLabel( 80, 1, 52, "Creatures List 1" ); + + AddLabel( 215, 3, 52, "PREMIUM SPAWNER" ); + AddBlackAlpha( 213, 23, 125, 270 ); + + AddButton( 260, 40, 0xFB7, 0xFB9, 1001, GumpButtonType.Reply, 0 ); + AddLabel( 260, 60, 52, "Okay" ); + + AddButton( 260, 90, 0xFB4, 0xFB6, 200, GumpButtonType.Reply, 0 ); + AddLabel( 232, 110, 52, "Bring to Home" ); + + AddButton( 260, 140, 0xFA8, 0xFAA, 300, GumpButtonType.Reply, 0 ); + AddLabel( 232, 160, 52, "Total Respawn" ); + + AddButton( 260, 190, 0xFAB, 0xFAD, 400, GumpButtonType.Reply, 0 ); + AddLabel( 245, 210, 52, "Properties" ); + + AddButton( 260, 240, 0xFB1, 0xFB3, 500, GumpButtonType.Reply, 0 ); + AddLabel( 256, 260, 52, "Cancel" ); + + AddButton( 230, 320, 5603, 5607, 0, GumpButtonType.Page, 6 ); + AddButton( 302, 320, 5601, 5605, 0, GumpButtonType.Page, 2 ); + AddLabel( 258, 320, 52, "- 1 -" ); + + for ( int i = 0; i < 15; i++ ) + { + // AddButton ( x, y, image, imageOnClick, ButtonID ) + AddButton( 5, ( 22 * i ) + 20, 0xFA5, 0xFA7, (1 + i), GumpButtonType.Reply, 0 ); // > (spawn this creature) + AddButton( 38, ( 22 * i ) + 20, 0xFA2, 0xFA4, (91 + i), GumpButtonType.Reply, 0 ); // X (remove this creature) + + AddImageTiled( 71, ( 22 * i ) + 20, 119, 23, 0xA40 ); + AddImageTiled( 72, ( 22 * i ) + 21, 117, 21, 0xBBC ); + + string str = ""; + + if ( i < spawner.CreaturesName.Count ) + { + str = (string)spawner.CreaturesName[i]; + int count = m_Spawner.CountCreatures( str ); + + AddLabel( 192, ( 22 * i ) + 20, 0, count.ToString() ); + } + + AddTextEntry( 75, ( 22 * i ) + 21, 114, 21, 0, 101 + i, str ); + } + + AddPage( 2 ); + + AddBackground( 0, 0, 350, 360, 5054 ); + + AddLabel( 80, 1, 52, "Creatures List 2" ); + + AddLabel( 215, 3, 52, "PREMIUM SPAWNER" ); + AddBlackAlpha( 213, 23, 125, 270 ); + + AddButton( 260, 40, 0xFB7, 0xFB9, 1002, GumpButtonType.Reply, 0 ); + AddLabel( 260, 60, 52, "Okay" ); + + AddButton( 260, 90, 0xFB4, 0xFB6, 200, GumpButtonType.Reply, 0 ); + AddLabel( 232, 110, 52, "Bring to Home" ); + + AddButton( 260, 140, 0xFA8, 0xFAA, 300, GumpButtonType.Reply, 0 ); + AddLabel( 232, 160, 52, "Total Respawn" ); + + AddButton( 260, 190, 0xFAB, 0xFAD, 400, GumpButtonType.Reply, 0 ); + AddLabel( 245, 210, 52, "Properties" ); + + AddButton( 260, 240, 0xFB1, 0xFB3, 500, GumpButtonType.Reply, 0 ); + AddLabel( 256, 260, 52, "Cancel" ); + + AddButton( 230, 320, 5603, 5607, 0, GumpButtonType.Page, 1 ); + AddButton( 302, 320, 5601, 5605, 0, GumpButtonType.Page, 3 ); + AddLabel( 258, 320, 52, "- 2 -" ); + + for ( int i = 0; i < 15; i++ ) + { + AddButton( 5, ( 22 * i ) + 20, 0xFA5, 0xFA7, (16 + i), GumpButtonType.Reply, 0 ); + AddButton( 38, ( 22 * i ) + 20, 0xFA2, 0xFA4, (106 + i), GumpButtonType.Reply, 0 ); + + AddImageTiled( 71, ( 22 * i ) + 20, 119, 23, 0xA40 ); + AddImageTiled( 72, ( 22 * i ) + 21, 117, 21, 0xBBC ); + + string str = ""; + + if ( i < spawner.SubSpawnerA.Count ) + { + str = (string)spawner.SubSpawnerA[i]; + int count = m_Spawner.CountCreaturesA( str ); + + AddLabel( 192, ( 22 * i ) + 20, 0, count.ToString() ); + } + + AddTextEntry( 75, ( 22 * i ) + 21, 114, 21, 0, 201 + i, str ); + } + + AddPage( 3 ); + + AddBackground( 0, 0, 350, 360, 5054 ); + + AddLabel( 80, 1, 52, "Creatures List 3" ); + + AddLabel( 215, 3, 52, "PREMIUM SPAWNER" ); + AddBlackAlpha( 213, 23, 125, 270 ); + + AddButton( 260, 40, 0xFB7, 0xFB9, 1003, GumpButtonType.Reply, 0 ); + AddLabel( 260, 60, 52, "Okay" ); + + AddButton( 260, 90, 0xFB4, 0xFB6, 200, GumpButtonType.Reply, 0 ); + AddLabel( 232, 110, 52, "Bring to Home" ); + + AddButton( 260, 140, 0xFA8, 0xFAA, 300, GumpButtonType.Reply, 0 ); + AddLabel( 232, 160, 52, "Total Respawn" ); + + AddButton( 260, 190, 0xFAB, 0xFAD, 400, GumpButtonType.Reply, 0 ); + AddLabel( 245, 210, 52, "Properties" ); + + AddButton( 260, 240, 0xFB1, 0xFB3, 500, GumpButtonType.Reply, 0 ); + AddLabel( 256, 260, 52, "Cancel" ); + + AddButton( 230, 320, 5603, 5607, 0, GumpButtonType.Page, 2 ); + AddButton( 302, 320, 5601, 5605, 0, GumpButtonType.Page, 4 ); + AddLabel( 258, 320, 52, "- 3 -" ); + + for ( int i = 0; i < 15; i++ ) + { + AddButton( 5, ( 22 * i ) + 20, 0xFA5, 0xFA7, (31 + i), GumpButtonType.Reply, 0 ); + AddButton( 38, ( 22 * i ) + 20, 0xFA2, 0xFA4, (121 + i), GumpButtonType.Reply, 0 ); + + AddImageTiled( 71, ( 22 * i ) + 20, 119, 23, 0xA40 ); + AddImageTiled( 72, ( 22 * i ) + 21, 117, 21, 0xBBC ); + + string str = ""; + + if ( i < spawner.SubSpawnerB.Count ) + { + str = (string)spawner.SubSpawnerB[i]; + int count = m_Spawner.CountCreaturesB( str ); + + AddLabel( 192, ( 22 * i ) + 20, 0, count.ToString() ); + } + + AddTextEntry( 75, ( 22 * i ) + 21, 114, 21, 0, 301 + i, str ); + } + + AddPage( 4 ); + + AddBackground( 0, 0, 350, 360, 5054 ); + + AddLabel( 80, 1, 52, "Creatures List 4" ); + + AddLabel( 215, 3, 52, "PREMIUM SPAWNER" ); + AddBlackAlpha( 213, 23, 125, 270 ); + + AddButton( 260, 40, 0xFB7, 0xFB9, 1004, GumpButtonType.Reply, 0 ); + AddLabel( 260, 60, 52, "Okay" ); + + AddButton( 260, 90, 0xFB4, 0xFB6, 200, GumpButtonType.Reply, 0 ); + AddLabel( 232, 110, 52, "Bring to Home" ); + + AddButton( 260, 140, 0xFA8, 0xFAA, 300, GumpButtonType.Reply, 0 ); + AddLabel( 232, 160, 52, "Total Respawn" ); + + AddButton( 260, 190, 0xFAB, 0xFAD, 400, GumpButtonType.Reply, 0 ); + AddLabel( 245, 210, 52, "Properties" ); + + AddButton( 260, 240, 0xFB1, 0xFB3, 500, GumpButtonType.Reply, 0 ); + AddLabel( 256, 260, 52, "Cancel" ); + + AddButton( 230, 320, 5603, 5607, 0, GumpButtonType.Page, 3 ); + AddButton( 302, 320, 5601, 5605, 0, GumpButtonType.Page, 5 ); + AddLabel( 258, 320, 52, "- 4 -" ); + + for ( int i = 0; i < 15; i++ ) + { + AddButton( 5, ( 22 * i ) + 20, 0xFA5, 0xFA7, (46 + i), GumpButtonType.Reply, 0 ); + AddButton( 38, ( 22 * i ) + 20, 0xFA2, 0xFA4, (136 + i), GumpButtonType.Reply, 0 ); + + AddImageTiled( 71, ( 22 * i ) + 20, 119, 23, 0xA40 ); + AddImageTiled( 72, ( 22 * i ) + 21, 117, 21, 0xBBC ); + + string str = ""; + + if ( i < spawner.SubSpawnerC.Count ) + { + str = (string)spawner.SubSpawnerC[i]; + int count = m_Spawner.CountCreaturesC( str ); + + AddLabel( 192, ( 22 * i ) + 20, 0, count.ToString() ); + } + + AddTextEntry( 75, ( 22 * i ) + 21, 114, 21, 0, 401 + i, str ); + } + + AddPage( 5 ); + + AddBackground( 0, 0, 350, 360, 5054 ); + + AddLabel( 80, 1, 52, "Creatures List 5" ); + + AddLabel( 215, 3, 52, "PREMIUM SPAWNER" ); + AddBlackAlpha( 213, 23, 125, 270 ); + + AddButton( 260, 40, 0xFB7, 0xFB9, 1005, GumpButtonType.Reply, 0 ); + AddLabel( 260, 60, 52, "Okay" ); + + AddButton( 260, 90, 0xFB4, 0xFB6, 200, GumpButtonType.Reply, 0 ); + AddLabel( 232, 110, 52, "Bring to Home" ); + + AddButton( 260, 140, 0xFA8, 0xFAA, 300, GumpButtonType.Reply, 0 ); + AddLabel( 232, 160, 52, "Total Respawn" ); + + AddButton( 260, 190, 0xFAB, 0xFAD, 400, GumpButtonType.Reply, 0 ); + AddLabel( 245, 210, 52, "Properties" ); + + AddButton( 260, 240, 0xFB1, 0xFB3, 500, GumpButtonType.Reply, 0 ); + AddLabel( 256, 260, 52, "Cancel" ); + + AddButton( 230, 320, 5603, 5607, 0, GumpButtonType.Page, 4 ); + AddButton( 302, 320, 5601, 5605, 0, GumpButtonType.Page, 6 ); + AddLabel( 258, 320, 52, "- 5 -" ); + + for ( int i = 0; i < 15; i++ ) + { + AddButton( 5, ( 22 * i ) + 20, 0xFA5, 0xFA7, (61 + i), GumpButtonType.Reply, 0 ); + AddButton( 38, ( 22 * i ) + 20, 0xFA2, 0xFA4, (151 + i), GumpButtonType.Reply, 0 ); + + AddImageTiled( 71, ( 22 * i ) + 20, 119, 23, 0xA40 ); + AddImageTiled( 72, ( 22 * i ) + 21, 117, 21, 0xBBC ); + + string str = ""; + + if ( i < spawner.SubSpawnerD.Count ) + { + str = (string)spawner.SubSpawnerD[i]; + int count = m_Spawner.CountCreaturesD( str ); + + AddLabel( 192, ( 22 * i ) + 20, 0, count.ToString() ); + } + + AddTextEntry( 75, ( 22 * i ) + 21, 114, 21, 0, 501 + i, str ); + } + + AddPage( 6 ); + + AddBackground( 0, 0, 350, 360, 5054 ); + + AddLabel( 80, 1, 52, "Creatures List 6" ); + + AddLabel( 215, 3, 52, "PREMIUM SPAWNER" ); + AddBlackAlpha( 213, 23, 125, 270 ); + + AddButton( 260, 40, 0xFB7, 0xFB9, 1006, GumpButtonType.Reply, 0 ); + AddLabel( 260, 60, 52, "Okay" ); + + AddButton( 260, 90, 0xFB4, 0xFB6, 200, GumpButtonType.Reply, 0 ); + AddLabel( 232, 110, 52, "Bring to Home" ); + + AddButton( 260, 140, 0xFA8, 0xFAA, 300, GumpButtonType.Reply, 0 ); + AddLabel( 232, 160, 52, "Total Respawn" ); + + AddButton( 260, 190, 0xFAB, 0xFAD, 400, GumpButtonType.Reply, 0 ); + AddLabel( 245, 210, 52, "Properties" ); + + AddButton( 260, 240, 0xFB1, 0xFB3, 500, GumpButtonType.Reply, 0 ); + AddLabel( 256, 260, 52, "Cancel" ); + + AddButton( 230, 320, 5603, 5607, 0, GumpButtonType.Page, 5 ); + AddButton( 302, 320, 5601, 5605, 0, GumpButtonType.Page, 1 ); + AddLabel( 258, 320, 52, "- 6 -" ); + + for ( int i = 0; i < 15; i++ ) + { + AddButton( 5, ( 22 * i ) + 20, 0xFA5, 0xFA7, (76 + i), GumpButtonType.Reply, 0 ); + AddButton( 38, ( 22 * i ) + 20, 0xFA2, 0xFA4, (166 + i), GumpButtonType.Reply, 0 ); + + AddImageTiled( 71, ( 22 * i ) + 20, 119, 23, 0xA40 ); + AddImageTiled( 72, ( 22 * i ) + 21, 117, 21, 0xBBC ); + + string str = ""; + + if ( i < spawner.SubSpawnerE.Count ) + { + str = (string)spawner.SubSpawnerE[i]; + int count = m_Spawner.CountCreaturesE( str ); + + AddLabel( 192, ( 22 * i ) + 20, 0, count.ToString() ); + } + + AddTextEntry( 75, ( 22 * i ) + 21, 114, 21, 0, 601 + i, str ); + } + + } + + public List CreateArray( RelayInfo info, Mobile from, int TextIndex ) + { + List creaturesName = new List(); + + for ( int i = 0; i < 15; i++ ) + { + TextRelay te = info.GetTextEntry( TextIndex + i ); + + if ( te != null ) + { + string str = te.Text; + + if ( str.Length > 0 ) + { + str = str.Trim(); + + string t = Spawner.ParseType( str ); + + Type type = ScriptCompiler.FindTypeByName( t ); + + if ( type != null ) + creaturesName.Add( str ); + else + from.SendMessage( "{0} is not a valid type name.", t ); + } + } + } + + return creaturesName; + } + + public string GetEntry( int Type, RelayInfo info ) + { + TextRelay entry = info.GetTextEntry( Type ); + return entry.Text; + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( m_Spawner.Deleted ) + return; + + switch ( info.ButtonID ) + { + case 0: // Cancel (mouse's right button click anywhere on the gump) + { + break; + } + case 200: // Bring everything home + { + m_Spawner.BringToHome(); + break; + } + case 300: // Complete respawn + { + m_Spawner.Respawn(); + break; + } + case 400: // Props + { + state.Mobile.SendGump( new PropertiesGump( state.Mobile, m_Spawner ) ); + state.Mobile.SendGump( new PremiumSpawnerGump( m_Spawner ) ); + break; + } + case 500: // Cancel (button "Cancel") + { + break; + } + case 1001: // Okay + { + m_Spawner.CreaturesName = CreateArray( info, state.Mobile, 100 ); + break; + } + case 1002: // Okay + { + m_Spawner.SubSpawnerA = CreateArray( info, state.Mobile, 200 ); + break; + } + case 1003: // Okay + { + m_Spawner.SubSpawnerB = CreateArray( info, state.Mobile, 300 ); + break; + } + case 1004: // Okay + { + m_Spawner.SubSpawnerC = CreateArray( info, state.Mobile, 400 ); + break; + } + case 1005: // Okay + { + m_Spawner.SubSpawnerD = CreateArray( info, state.Mobile, 500 ); + break; + } + case 1006: // Okay + { + m_Spawner.SubSpawnerE = CreateArray( info, state.Mobile, 600 ); + break; + } + default: + { //ButtonID: 1-90 spawn; 91-180 remove + int ID = info.ButtonID; + + int Type = 0; + + // Spawn creature + if ( (ID >= 1) && (ID <= 15) ) + { + Type += 100 + ID; + m_Spawner.Spawn( GetEntry(Type, info) ); + } + else if ( (ID >= 16) && (ID <= 30) ) + { + Type += 200 + ID - 15; + m_Spawner.SpawnA( GetEntry(Type, info) ); + } + else if ( (ID >= 31) && (ID <= 45) ) + { + Type += 300 + ID - 30; + m_Spawner.SpawnB( GetEntry(Type, info) ); + } + else if ( (ID >= 46) && (ID <= 60) ) + { + Type += 400 + ID - 45; + m_Spawner.SpawnC( GetEntry(Type, info) ); + } + else if ( (ID >= 61) && (ID <= 75) ) + { + Type += 500 + ID - 60; + m_Spawner.SpawnD( GetEntry(Type, info) ); + } + else if ( (ID >= 76) && (ID <= 90) ) + { + Type += 600 + ID - 75; + m_Spawner.SpawnE( GetEntry(Type, info) ); + } + // Remove creature + else if ( (ID >= 91) && (ID <= 105) ) + { + Type += 100 + ID - 90; + m_Spawner.RemoveCreatures( GetEntry(Type, info) ); + } + else if ( (ID >= 106) && (ID <= 120) ) + { + Type += 200 + ID - 105; + m_Spawner.RemoveCreaturesA( GetEntry(Type, info) ); + } + else if ( (ID >= 121) && (ID <= 135) ) + { + Type += 300 + ID - 120; + m_Spawner.RemoveCreaturesB( GetEntry(Type, info) ); + } + else if ( (ID >= 136) && (ID <= 150) ) + { + Type += 400 + ID - 135; + m_Spawner.RemoveCreaturesC( GetEntry(Type, info) ); + } + else if ( (ID >= 151) && (ID <= 165) ) + { + Type += 500 + ID - 150; + m_Spawner.RemoveCreaturesD( GetEntry(Type, info) ); + } + else if ( (ID >= 166) && (ID <= 180) ) + { + Type += 600 + ID - 165; + m_Spawner.RemoveCreaturesE( GetEntry(Type, info) ); + } + + string entry = GetEntry(Type, info); + + if ( entry != null && entry.Length > 0 ) + { + m_Spawner.CreaturesName = CreateArray( info, state.Mobile, 100 ); + m_Spawner.SubSpawnerA = CreateArray( info, state.Mobile, 200 ); + m_Spawner.SubSpawnerB = CreateArray( info, state.Mobile, 300 ); + m_Spawner.SubSpawnerC = CreateArray( info, state.Mobile, 400 ); + m_Spawner.SubSpawnerD = CreateArray( info, state.Mobile, 500 ); + m_Spawner.SubSpawnerE = CreateArray( info, state.Mobile, 600 ); + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/SpawnsOverseer.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/SpawnsOverseer.cs new file mode 100644 index 0000000..1810b99 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Spawner/SpawnsOverseer.cs @@ -0,0 +1,331 @@ +/************************* + * By Nerun * + * Engine r74 * + ************************* + */ + +using System; +using System.IO; +using Server; +using Server.Mobiles; +using System.Collections.Generic; +using Server.Network; + +namespace Server.Items +{ + public class SpawnsOverseer : Item + { + private int m_Range; + private int m_InRangeDelay; + private int m_OutRangeDelay; + private CheckTimer m_Timer; + private bool m_Enable; + private TimeSpan m_CurrentDelay; // players out dungeon + private DateTime m_End; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Enable + { + get { return m_Enable; } + set + { + if ( value ) + Begin(); + + else + End(); + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range + { + get { return m_Range; } + set { m_Range = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan CurrentDelay + { + get { return m_CurrentDelay; } + set { m_CurrentDelay = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan NextDelay + { + get + { + if ( m_Enable ) + return m_End - DateTime.Now; + else + return TimeSpan.FromSeconds( 0 ); + } + set + { + Begin(); + DoTimer( value ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int InRangeDelay + { + get { return m_InRangeDelay; } + set { m_InRangeDelay = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int OutRangeDelay + { + get { return m_OutRangeDelay; } + set { m_OutRangeDelay = value; InvalidateProperties(); } + } + + public void Begin() + { + if ( !m_Enable ) + { + m_Enable = true; + DoTimer(); + } + } + + public void End() + { + if ( m_Enable ) + { + m_Timer.Stop(); + m_Enable = false; + } + } + + public void Restart() + { + if ( m_Enable ) + { + m_Timer.Stop(); + DoTimer(); + } + } + + public void DoTimer() + { + if ( !m_Enable ) + return; + + int mSeconds = (int)m_CurrentDelay.TotalSeconds; + + TimeSpan delay = TimeSpan.FromSeconds( mSeconds ); + DoTimer( delay ); + } + + public void DoTimer( TimeSpan delay ) + { + if ( !m_Enable ) + return; + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_End = DateTime.Now + delay; + + m_Timer = new CheckTimer( this, delay ); + m_Timer.Start(); + } + + [Constructable] + public SpawnsOverseer() : this( 20, 30, 5 ) + { + } + + [Constructable] + public SpawnsOverseer( int startrange ) : this( startrange, 30, 5 ) + { + } + + [Constructable] + public SpawnsOverseer( int startrange, int startIRD, int startORD ) : base( 0x1F1E ) + { + InitSeer( startrange, startIRD, startORD ); + } + + private void InitSeer( int startrange, int startIRD, int startORD ) + { + Name = "Spawns' Overseer"; + Movable = false; + Light = LightType.Circle150; + Weight = 1; + Visible = false; + Enable = true; + Range = startrange; + CurrentDelay = TimeSpan.FromSeconds( 5 ); + InRangeDelay = startIRD; //minutes + OutRangeDelay = startORD; //seconds + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Enable ) + { + list.Add( 1060742 ); // active + + list.Add( 1060662, "Range\t{0}", Range.ToString() ); + list.Add( 1060663, "In Range Delay\t{0} min", InRangeDelay.ToString() ); + list.Add( 1060661, "Out Range Delay\t{0} sec", OutRangeDelay.ToString() ); + } + else + { + list.Add( 1060743 ); // inactive + } + } + + private class CheckTimer : Timer + { + private SpawnsOverseer m_SpawnsOverseer; + + public CheckTimer( SpawnsOverseer Crystal, TimeSpan delay ) : base( delay, delay ) + { + Priority = TimerPriority.OneSecond; + + m_SpawnsOverseer = Crystal; + } + + protected override void OnTick() + { + if ( ( m_SpawnsOverseer != null ) && ( !m_SpawnsOverseer.Deleted ) ) + { + m_SpawnsOverseer.OnTickDoThis(); + } + + else + { + Stop(); + } + } + } + + public void OnTickDoThis() + { + List ClosePremiumSpawners = new List(); + + List ClosePlayers = new List(); + + List MobsCleaning = new List(); + + List ItemsCleaning = new List(); + + foreach ( Item item in this.GetItemsInRange( Range ) ) // para cada item dentro do raio de alcance + { + if( item is PremiumSpawner ) // se for um PremiumSpawner + ClosePremiumSpawners.Add( item ); + } + + if ( ClosePremiumSpawners.Count > 0 ) + { + foreach ( Mobile m in this.GetMobilesInRange( Range ) ) // para cada mobile dentro do raio de alcance + { + if( m is PlayerMobile && m.AccessLevel == AccessLevel.Player || m is PlayerMobile && m.AccessLevel > AccessLevel.Player && m.Hidden == false ) //se f�r player ou GM n�o oculto (hidden) + ClosePlayers.Add( m ); + } + + if ( ClosePlayers.Count > 0 ) // h� pelo menos um player pr�ximo + { + this.CurrentDelay = TimeSpan.FromMinutes( InRangeDelay ); // tempo para nova checagem + Restart(); + + foreach ( Item pspawner in ClosePremiumSpawners ) // pra cada PremiumSpawner pr�ximo (na lista) + { + if ( ((PremiumSpawner)pspawner).Running == false ) // se estiver desativado + { + ((PremiumSpawner)pspawner).Running = true; // ativar! + ((PremiumSpawner)pspawner).NextSpawn = TimeSpan.FromSeconds( 1 ); // respawn total! + } + } + } + + else if ( ClosePlayers.Count <= 0 ) // n�o tem ningu�m perto + { + this.CurrentDelay = TimeSpan.FromSeconds( OutRangeDelay ); // tempo para nova checagem + Restart(); + + foreach ( Item pspawner in ClosePremiumSpawners ) // pra cada Premium PremiumSpawner pr�ximo (na lista) + { + if ( ((PremiumSpawner)pspawner).Running == true ) // se estiver ativado + { + ((PremiumSpawner)pspawner).Running = false; // desativar! + + foreach ( Mobile mobdel in this.GetMobilesInRange( Range ) ) + { + if( mobdel is BaseCreature || mobdel is TownCrier ) + MobsCleaning.Add( mobdel ); + } + + if ( MobsCleaning.Count > 0 ) + { + foreach ( Mobile mDel in MobsCleaning ) + mDel.Delete(); + } + + foreach ( Item itemdel in this.GetItemsInRange( Range ) ) + { + if( itemdel.Movable == true ) //se f�r um item m�vel (n�o decora��o) + ItemsCleaning.Add( itemdel ); + } + + if ( ItemsCleaning.Count > 0 ) + { + foreach ( Item iDel in ItemsCleaning ) + iDel.Delete(); + } + } + } + } + } + + else if ( ClosePremiumSpawners.Count <= 0 ) + { + this.Enable = false; + this.CurrentDelay = TimeSpan.FromSeconds( OutRangeDelay ); + } + } + + public SpawnsOverseer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_Range ); + writer.Write( m_InRangeDelay ); + writer.Write( m_OutRangeDelay ); + writer.Write( m_Enable ); + if ( m_Enable ) + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Range = reader.ReadInt(); + m_InRangeDelay = reader.ReadInt(); + m_OutRangeDelay = reader.ReadInt(); + m_Enable = reader.ReadBool(); + TimeSpan ts = TimeSpan.Zero; + if ( m_Enable ) + ts = reader.ReadDeltaTime() - DateTime.Now; + DoTimer( ts ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Gump.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Gump.cs new file mode 100644 index 0000000..7a47129 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Gump.cs @@ -0,0 +1,307 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Joeku.SR +{ + public class SR_Gump : Gump + { + public SR_RuneAccount RuneAcc; + + public static void Send( Mobile mob, SR_RuneAccount runeAcc ) + { + mob.CloseGump( typeof( SR_Gump ) ); + mob.SendGump( new SR_Gump( runeAcc ) ); + } + + public SR_Gump( SR_RuneAccount runeAcc ) : base( 0, 27 ) + { + RuneAcc = runeAcc; + + int count = 0; + if( RuneAcc.ChildRune == null ) + count = RuneAcc.Count; + else + count = RuneAcc.ChildRune.Count; + + int RunebooksH = 0, + RunebooksW = 0; + + int tier = -1; + if( RuneAcc.ChildRune != null ) + tier = RuneAcc.ChildRune.Tier; + + if( tier > -1 ) + { + if( tier == 0 ) + { + RunebooksH = 42; + RunebooksW = 278; + } + else + { + RunebooksH = 37 + 42; + RunebooksW = 278 + (tier*5); + } + } + + int RunesH = 10*2; + + if( count > 10 ) + count = 10; + if( count > 0 ) + RunesH += (count*22); + if( count > 1 ) + RunesH += ((count-1)*5); + + DisplayHeader(); + if( tier > -1 ) + DisplayRunebooks( 42, RunebooksH, RunebooksW, tier ); + DisplayAddNew( 42 + RunebooksH + RunesH ); + DisplayRunes( 42 + RunebooksH, RunesH ); + } + + public void DisplayHeader() + { + AddPage(0); + AddBackground(0, 0, 210, 42, 9270); + AddImageTiled(10, 10, 190, 22, 2624); + AddAlphaRegion(10, 10, 190, 22 ); + AddHtml(0, 11, 210, 20, "
Joeku's Staff Runebook", false, false); + } + + public void DisplayRunebooks( int y, int h, int w, int tiers ) + { + AddBackground(0, y, w, h, 9270); + AddImageTiled(10, y+10, w-20, h-20, 2624); + AddAlphaRegion(10, y+10, w-20, h-20 ); + for( int i = tiers, j = 1; i > 0; i--, j++ ) + { + AddBackground( j*5, y + 37, ((i-1)*5) + 278, 42, 9270 ); + if( i == 1 ) + { + AddImageTiled((j*5)+10, y+47, ((i-1)*5) + 258, 22, 2624); + AddAlphaRegion((j*5)+10, y+47, ((i-1)*5) + 258, 22 ); + } + } + + SR_Rune rune = RuneAcc.Runes[RuneAcc.PageIndex]; + + AddItem(SR_Utilities.ItemOffsetX( rune ), y + SR_Utilities.ItemOffsetY( rune ) + 12, SR_Utilities.RunebookID, SR_Utilities.ItemHue( rune ) ); + AddLabelCropped(35, y + 12, w - 108, 20, 2100, rune.Name ); + AddButton(w-70, y + 10, 4014, 4016, 5, GumpButtonType.Reply, 0); + AddButton(w-40, y + 10, 4017, 4019, 4, GumpButtonType.Reply, 0); + + if( tiers > 0 ) + { + rune = RuneAcc.ChildRune; + AddItem(SR_Utilities.ItemOffsetX( rune ) + tiers*5, y + SR_Utilities.ItemOffsetY( rune ) + 12 + 37, SR_Utilities.RunebookID, SR_Utilities.ItemHue( rune ) ); + AddLabelCropped(35 + tiers*5, y + 12 + 37, 170, 20, 2100, rune.Name ); + AddButton(w-70, y + 10 + 37, 4014, 4016, 7, GumpButtonType.Reply, 0); + AddButton(w-40, y + 10 + 37, 4017, 4019, 6, GumpButtonType.Reply, 0); + } + + // AddButton(238, 30 + bgY + 10, 4011, 4013, 0, GumpButtonType.Reply, 0); + } + + public void DisplayAddNew( int y ) + { + AddBackground(0, y, 278, 42, 9270); + AddImageTiled(10, y+10, 258, 22, 2624); + AddAlphaRegion(10, y+10, 258, 22 ); + AddLabel(15, y + 10, 2100, @"New Rune"); + AddButton(80, y + 10, 4011, 4013, 1, GumpButtonType.Reply, 0); + AddButton(110, y + 10, 4029, 4031, 2, GumpButtonType.Reply, 0); + AddLabel(150, y + 10, 2100, @"New Runebook"); + AddButton(238, y + 10, 4011, 4013, 3, GumpButtonType.Reply, 0); + } + + public void DisplayRunes( int y, int h ) + { + AddBackground(0, y, 430/*400*/, h, 9270); + AddImageTiled(10, y+10, 410, h-20, 2624); + AddAlphaRegion(10, y+10, 410, h-20 ); + + List runes = null; + int count, runebooks; + + if( RuneAcc.ChildRune == null ) + { + runes = RuneAcc.Runes; + count = RuneAcc.Count; + runebooks = RuneAcc.RunebookCount; + } + else + { + runes = RuneAcc.ChildRune.Runes; + count = RuneAcc.ChildRune.Count; + runebooks = RuneAcc.ChildRune.RunebookCount; + } + + AddPage( 1 ); + int pages = (int)Math.Ceiling( (double)count / 9.0 ), temp = 0; + for( int i = 0, loc = 0, page = 1; i < count; i++, loc++ ) + { + temp = 10 + y + (22+5)*loc; + + AddItem(SR_Utilities.ItemOffsetX( runes[i] ), 2 + SR_Utilities.ItemOffsetY( runes[i] ) + temp, runes[i].IsRunebook ? SR_Utilities.RunebookID : SR_Utilities.RuneID, SR_Utilities.ItemHue( runes[i] )); + if( runes[i].IsRunebook ) + AddLabelCropped(35, 2 + temp, 175, 20, 2100, String.Format( "{0}. {1}", i+1, runes[i].Name ) ); + else + { + AddLabelCropped(35, 2 + temp, 175, 20, 2100, String.Format( "{0}. {1} ({2})", i+1-runebooks, runes[i].Name, runes[i].TargetMap.ToString() ) ); + AddLabelCropped(215, 2 + temp, 110, 20, 2100, runes[i].TargetLoc.ToString() ); + AddButton(360, temp, 4008, 4010, i+30010, GumpButtonType.Reply, 0); + } + AddButton(330 + ( runes[i].IsRunebook ? 30 : 0 ), temp, 4005, 4007, i+10, GumpButtonType.Reply, 0); + //AddButton(340, 40 + ((22+5)*i), 4026, 4028, 0, GumpButtonType.Reply, 0); + //AddImage(340, 40 + ((22+5)*i), 4026, 1000); + AddButton(390, temp, 4017, 4019, i+60010, GumpButtonType.Reply, 0); // delete + + if( pages > 1 && ((loc == 8 && i < count-1) || i == count-1) ) + { + temp = 10 + y + (22+5)*9; + // (430(bg) - 20 (buffer) - 70 (txt/buffer) - 60(buttons)) / 2 = 140 + if( page > 1 ) + AddButton( 140, temp, 4014, 4016, 0, GumpButtonType.Page, page-1 ); + else + AddImage( 140, temp, 4014, 1000 ); + + AddHtml(170, 2 + temp, 90, 20, String.Format("
Page {0}/{1}", page, pages), false, false); + + if( page < pages ) + AddButton( 260, temp, 4005, 4007, 0, GumpButtonType.Page, page+1 ); + else + AddImage( 260, temp, 4005, 1000 ); + + page++; + AddPage( page ); + loc = -1; + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int button = info.ButtonID; + Mobile mob = sender.Mobile; + + switch( button ) + { + case 0: + break; + case 1: + mob.SendMessage("Enter a description:"); + mob.Prompt = new SR_NewRunePrompt( this.RuneAcc, mob.Location, mob.Map ); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + case 2: + mob.SendMessage("Target a location to mark:"); + mob.Target = new SR_NewRuneTarget( this.RuneAcc ); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + case 3: + mob.SendMessage("Enter a description:"); + mob.Prompt = new SR_NewRunePrompt( this.RuneAcc ); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + case 4: + RuneAcc.RemoveRune( RuneAcc.PageIndex, true ); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + case 5: + RuneAcc.ResetPageIndex(); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + case 6: + RuneAcc.ChildRune.ParentRune.RemoveRune( RuneAcc.ChildRune.ParentRune.PageIndex, true ); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + case 7: + RuneAcc.ChildRune.ParentRune.ResetPageIndex(); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + default: + bool moongate = false; + button -= 10; + if( button >= 60000 ) + { + if( RuneAcc.ChildRune == null ) + RuneAcc.RemoveRune( button-60000 ); + else + RuneAcc.ChildRune.RemoveRune( button-60000 ); + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + break; + } + + if( button >= 30000 ) + { + button -= 30000; + moongate = true; + } + SR_Rune rune = null; + if( RuneAcc.ChildRune == null ) + rune = RuneAcc.Runes[button]; + else + rune = RuneAcc.ChildRune.Runes[button]; + + if( rune.IsRunebook ) + { + if( RuneAcc.ChildRune == null ) + this.RuneAcc.PageIndex = button; + else + this.RuneAcc.ChildRune.PageIndex = button; + + Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + } + else + { + if( mob.Location == rune.TargetLoc && mob.Map == rune.TargetMap ) + mob.SendMessage( "You are already there." ); + else if( !moongate ) + { + mob.PlaySound( 0x1FC ); + mob.MoveToWorld( rune.TargetLoc, rune.TargetMap ); + mob.PlaySound( 0x1FC ); + } + else + { + if( SR_Utilities.FindItem( typeof( Moongate ), mob.Location, mob.Map ) ) + mob.SendMessage( "You are standing on top of a moongate, please move." ); + else if( SR_Utilities.FindItem( typeof( Moongate ), rune.TargetLoc, rune.TargetMap ) ) + mob.SendMessage( "There is already a moongate there, sorry." ); + else + { + mob.SendLocalizedMessage( 501024 ); // You open a magical gate to another location + + Effects.PlaySound( mob.Location, mob.Map, 0x20E ); + + SR_RuneGate firstGate = new SR_RuneGate( rune.TargetLoc, rune.TargetMap ); + firstGate.MoveToWorld( mob.Location, mob.Map ); + + Effects.PlaySound( rune.TargetLoc, rune.TargetMap, 0x20E ); + + SR_RuneGate secondGate = new SR_RuneGate( mob.Location, mob.Map ); + secondGate.MoveToWorld( rune.TargetLoc, rune.TargetMap ); + } + } + } + + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Load.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Load.cs new file mode 100644 index 0000000..2de11e4 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Load.cs @@ -0,0 +1,118 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Server; +using Server.Accounting; + +namespace Joeku.SR +{ + public class SR_Load + { + public static void ReadData( string filePath ) + { + if ( !File.Exists( filePath ) ) + return; + + Console.WriteLine(); + Console.WriteLine("Joeku's Staff Runebook: Loading..."); + + XmlDocument doc = new XmlDocument(); + doc.Load( filePath ); + + XmlElement root = doc["StaffRunebook"]; + int version = Utility.ToInt32(root.GetAttribute("Version")); + + if( root.HasChildNodes ) + { + foreach ( XmlElement a in root.GetElementsByTagName("RuneAccount") ) + { + try{ ReadAccountNode( a ); } + catch{ Console.WriteLine( " Warning: Staff Runebook load failed." ); } + } + } + Console.WriteLine(); + } + + public static void ReadAccountNode( XmlElement parent ) + { + Console.Write( " Account: {0}... ", parent.GetAttribute("Username") ); + try + { + SR_RuneAccount acc = new SR_RuneAccount(parent.GetAttribute("Username")); + if( parent.HasChildNodes ) + { + XmlElement child = parent.FirstChild as XmlElement; + acc.AddRune(ReadRuneNode(child)); + while( child.NextSibling != null ) + { + child = child.NextSibling as XmlElement; + acc.AddRune(ReadRuneNode(child)); + } + /*foreach( XmlElement child in parent.GetElementsByTagName("Runebook") ) + if( child != null ) + acc.AddRune(ReadRunebookNode(child)); + foreach( XmlElement child in parent.GetElementsByTagName("Rune") ) + if( child != null ) + acc.AddRune(ReadRuneNode(child));*/ + } + } + catch + { + Console.WriteLine( "failed." ); + } + Console.WriteLine( "done." ); + } + + public static SR_Rune ReadRuneNode( XmlElement parent ) + { + if( parent.LocalName == "Runebook" ) + { + SR_Rune runebook = new SR_Rune(parent.GetAttribute("Name"), true); + if( parent.HasChildNodes ) + { + XmlElement child = parent.FirstChild as XmlElement; + runebook.AddRune(ReadRuneNode(child)); + while( child.NextSibling != null ) + { + child = child.NextSibling as XmlElement; + runebook.AddRune(ReadRuneNode(child)); + } + } + return runebook; + } + //else if( parent.LocalName == "Rune" ) + + return new SR_Rune(parent.GetAttribute("Name"), Map.Parse(parent.GetAttribute("TargetMap")), new Point3D(Utility.ToInt32(parent.GetAttribute("X")),Utility.ToInt32(parent.GetAttribute("Y")),Utility.ToInt32(parent.GetAttribute("Z"))) ); + } + /*public static SR_Rune ReadRunebookNode( XmlElement parent ) + { + SR_Rune rune = new SR_Rune(parent.GetAttribute("Name"), true); + if( parent.HasChildNodes ) + { + foreach( XmlElement child in parent.GetElementsByTagName("Runebook") ) + if( child != null ) + rune.AddRune(ReadRunebookNode(child)); + foreach( XmlElement child in parent.GetElementsByTagName("Rune") ) + if( child != null ) + rune.AddRune(ReadRuneNode(child)); + } + return rune; + } + + public static SR_Rune ReadRuneNode( XmlElement rune ) + { + return new SR_Rune(rune.GetAttribute("Name"), Map.Parse(rune.GetAttribute("TargetMap")), new Point3D(Utility.ToInt32(rune.GetAttribute("X")),Utility.ToInt32(rune.GetAttribute("Y")),Utility.ToInt32(rune.GetAttribute("Z"))) ); + }*/ + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Main.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Main.cs new file mode 100644 index 0000000..46ad164 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Main.cs @@ -0,0 +1,78 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using Server; +using Server.Commands; + +namespace Joeku.SR +{ + public class SR_Main + { + public static int Version = 110; + public static string ReleaseDate = "February 4, 2009"; + public static string SavePath = "Saves/Staff Runebook"; // "ROOT\..." + //public static string SavePath = "Saves\\Staff Runebook"; // "ROOT\..." + public static string FileName = "Rune Accounts.xml"; + public static List Info = new List(); + public static int Count{ get{ return Info.Count; } } + + // public SR_Main(){} + + [CallPriority( 100 )] + public static void Initialize() + { + if( Info.Count == 0 ) + SR_Load.ReadData(Path.Combine( SavePath, FileName )); + + CommandHandlers.Register("StaffRunebook", AccessLevel.Counselor, new CommandEventHandler(SR_OnCommand)); + CommandHandlers.Register("SR", AccessLevel.Counselor, new CommandEventHandler(SR_OnCommand)); + CommandHandlers.Register("StaffRunebookReset", AccessLevel.Counselor, new CommandEventHandler(SR_Reset_OnCommand)); + EventSink.WorldSave += new WorldSaveEventHandler( EventSink_WorldSave ); + } + + [Usage("StaffRunebook")] + [Aliases( "SR" )] + public static void SR_OnCommand(CommandEventArgs e) + { + Mobile mob = e.Mobile; + + SR_Gump.Send( mob, SR_Utilities.FetchInfo( mob.Account ) ); + } + + [Usage("StaffRunebookReset")] + public static void SR_Reset_OnCommand(CommandEventArgs e) + { + Mobile mob = e.Mobile; + + SR_Utilities.NewRuneAcc( SR_Utilities.FetchInfo( mob.Account ) ); + + mob.SendMessage( "Your staff runebook has been reset to default." ); + } + + private static void EventSink_WorldSave( WorldSaveEventArgs e ) + { + // Args: bool e.Message + + SR_Save.WriteData(); + } + + public static void AddInfo( SR_RuneAccount runeAccount ) + { + for( int i = 0; i < Info.Count; i++ ) + if( Info[i].Username == runeAccount.Username ) + Info.RemoveAt(i); + + Info.Add( runeAccount ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/NewRunePrompt.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/NewRunePrompt.cs new file mode 100644 index 0000000..cc5f4ff --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/NewRunePrompt.cs @@ -0,0 +1,61 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using Server; +using Server.Prompts; + +namespace Joeku.SR +{ + public class SR_NewRunePrompt : Prompt + { + public SR_RuneAccount RuneAcc; + public bool IsRunebook; + public Point3D TargetLoc; + public Map TargetMap; + + public SR_NewRunePrompt( SR_RuneAccount runeAcc ) + { + RuneAcc = runeAcc; + IsRunebook = true; + } + + public SR_NewRunePrompt( SR_RuneAccount runeAcc, Point3D targetLoc, Map targetMap ) + { + RuneAcc = runeAcc; + TargetLoc = targetLoc; + TargetMap = targetMap; + } + + public override void OnResponse( Mobile mob, string text ) + { + text = text.Trim(); + + if ( text.Length > 40 ) + text = text.Substring( 0, 40 ); + + if ( text.Length > 0 ) + { + SR_Rune rune = null; + if( IsRunebook ) + rune = new SR_Rune( text, true ); + else + rune = new SR_Rune( text, TargetMap, TargetLoc ); + + if( RuneAcc.ChildRune == null ) + RuneAcc.AddRune( rune ); + else + RuneAcc.ChildRune.AddRune( rune ); + } + + SR_Gump.Send( mob, RuneAcc ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/NewRuneTarget.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/NewRuneTarget.cs new file mode 100644 index 0000000..786011b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/NewRuneTarget.cs @@ -0,0 +1,42 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using Server; +using Server.Targeting; + +namespace Joeku.SR +{ + public class SR_NewRuneTarget : Target + { + public SR_RuneAccount RuneAcc; + + public SR_NewRuneTarget( SR_RuneAccount runeAcc ) : base( 12, true, TargetFlags.None ) + { + RuneAcc = runeAcc; + } + + protected override void OnTarget( Mobile mob, object targ ) + { + Point3D loc = new Point3D( 0, 0, 0 ); + if( targ is LandTarget ) + loc = (targ as LandTarget).Location; + else if( targ is StaticTarget ) + loc = (targ as StaticTarget).Location; + else if( targ is Mobile ) + loc = (targ as Mobile).Location; + else if( targ is Item ) + loc = (targ as Item).Location; + + mob.SendMessage("Enter a description:"); + mob.Prompt = new SR_NewRunePrompt( this.RuneAcc, loc, mob.Map ); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Persistence.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Persistence.cs new file mode 100644 index 0000000..6d2bfd9 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Persistence.cs @@ -0,0 +1,44 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Joeku.SR +{ + // Legacy... binary serialization only used in v1.00, deserialization preserved to migrate data. + public class SR_Persistence : Item + { + public SR_Persistence(){} + public SR_Persistence(Serial serial) : base( serial ){} + + public override void Serialize(GenericWriter writer) + { base.Serialize(writer); } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine("Joeku's Staff Runebook: Loading..."); + Console.WriteLine(" Migrating data from version 1.00... "); + int count = reader.ReadInt(); + for( int i = 0; i < count; i++ ) + SR_RuneAccount.Deserialize( reader, version ); + Console.WriteLine(); + + this.Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Rune.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Rune.cs new file mode 100644 index 0000000..0756c9d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Rune.cs @@ -0,0 +1,144 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using Server; + +namespace Joeku.SR +{ + public class SR_Rune + { + public string Name; + public bool IsRunebook = false; + public List Runes; + public int Count{ get{ return Runes.Count; } } + public int RunebookCount, RuneCount; + public int PageIndex = -1; + public SR_Rune ParentRune; + + public int Tier + { + get + { + if( this.ParentRune != null ) + return ParentRune.Tier + 1; + + return 0; + } + } + + public Map TargetMap = Map.Felucca; + public Point3D TargetLoc = new Point3D( 0, 0, 0 ); + + public SR_Rune( string name, Map map, Point3D loc ) : this( name, false ) + { + TargetMap = map; + TargetLoc = loc; + } + public SR_Rune( string name, bool isRunebook ) : this( name, isRunebook, new List() ){} + public SR_Rune( string name, bool isRunebook, List runes ) + { + Name = name; + IsRunebook = isRunebook; + Runes = runes; + FindCounts(); + } + + public void ResetPageIndex() + { + if( !IsRunebook || PageIndex == -1 ) + return; + + if( Runes[PageIndex] != null ) + Runes[PageIndex].ResetPageIndex(); + + PageIndex = -1; + } + + public void Clear() + { + Runes.Clear(); + RunebookCount = 0; + RuneCount = 0; + PageIndex = -1; + } + + public void AddRune( SR_Rune rune ) + { + for( int i = 0; i < Count; i++ ) + if( Runes[i] == rune ) + Runes.RemoveAt(i); + + if( rune.IsRunebook ) + { + Runes.Insert( RunebookCount, rune ); + RunebookCount++; + } + else + { + Runes.Add( rune ); + RuneCount++; + } + + rune.ParentRune = this; + } + + public void RemoveRune( int index ){ RemoveRune( index, false ); } + public void RemoveRune( int index, bool pageIndex ) + { + if( Runes[index].IsRunebook ) + RunebookCount--; + else + RuneCount--; + + if( pageIndex && PageIndex == index ) + PageIndex = -1; + + Runes.RemoveAt( index ); + } + + public void FindCounts() + { + int runebookCount = 0, runeCount = 0; + for( int i = 0; i < Runes.Count; i++ ) + if( Runes[i].IsRunebook ) + runebookCount++; + else + runeCount++; + + RunebookCount = runebookCount; + RuneCount = runeCount; + } + + // Legacy... binary serialization only used in v1.00, deserialization preserved to migrate data. + public static SR_Rune Deserialize( GenericReader reader, int version ) + { + SR_Rune rune = null; + + string name = reader.ReadString(); + bool isRunebook = reader.ReadBool(); + + Map targetMap = reader.ReadMap(); + Point3D targetLoc = reader.ReadPoint3D(); + + if( isRunebook ) + rune = new SR_Rune( name, isRunebook ); + else + rune = new SR_Rune( name, targetMap, targetLoc ); + + int count = reader.ReadInt(); + for( int i = 0; i < count; i++ ) + rune.AddRune( SR_Rune.Deserialize( reader, version ) ); + + return rune; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/RuneAccount.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/RuneAccount.cs new file mode 100644 index 0000000..43a967b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/RuneAccount.cs @@ -0,0 +1,127 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using Server; + +namespace Joeku.SR +{ + public class SR_RuneAccount + { + public string Username; + public List Runes; + public int Count{ get{ return Runes.Count; } } + public int RunebookCount, RuneCount; + public int PageIndex = -1; + + public SR_Rune ChildRune + { + get + { + SR_Rune rune = null; + + if( PageIndex > -1 ) + rune = Runes[PageIndex]; + + if( rune != null ) + { + while( rune.PageIndex > -1 ) + rune = rune.Runes[rune.PageIndex]; + } + + return rune; + } + } + + public SR_RuneAccount( string username ) : this( username, new List() ){} + public SR_RuneAccount( string username, List runes ) + { + Username = username; + Runes = runes; + FindCounts(); + + SR_Main.AddInfo( this ); + } + + public void ResetPageIndex() + { + Runes[PageIndex].ResetPageIndex(); + PageIndex = -1; + } + + public void Clear() + { + Runes.Clear(); + RunebookCount = 0; + RuneCount = 0; + PageIndex = -1; + } + + public void AddRune( SR_Rune rune ) + { + for( int i = 0; i < Count; i++ ) + if( Runes[i] == rune ) + Runes.RemoveAt(i); + + if( rune.IsRunebook ) + { + Runes.Insert( RunebookCount, rune ); + RunebookCount++; + } + else + { + Runes.Add( rune ); + RuneCount++; + } + } + + public void RemoveRune( int index ){ RemoveRune( index, false ); } + public void RemoveRune( int index, bool pageIndex ) + { + if( Runes[index].IsRunebook ) + RunebookCount--; + else + RuneCount--; + + if( pageIndex && PageIndex == index ) + PageIndex = -1; + + Runes.RemoveAt( index ); + } + + public void FindCounts() + { + int runebookCount = 0, runeCount = 0; + for( int i = 0; i < Runes.Count; i++ ) + if( Runes[i].IsRunebook ) + runebookCount++; + else + runeCount++; + + RunebookCount = runebookCount; + RuneCount = runeCount; + } + + // Legacy... binary serialization only used in v1.00, deserialization preserved to migrate data. + public static void Deserialize( GenericReader reader, int version ) + { + List runes = new List(); + + string username = reader.ReadString(); + Console.Write(" Account: {0}... ", username); + int count = reader.ReadInt(); + for( int i = 0; i < count; i++ ) + runes.Add( SR_Rune.Deserialize( reader, version ) ); + new SR_RuneAccount( username, runes ); + Console.WriteLine("done."); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/RuneGate.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/RuneGate.cs new file mode 100644 index 0000000..2a38cc9 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/RuneGate.cs @@ -0,0 +1,66 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using Server; +using Server.Items; + +namespace Joeku.SR +{ + public class SR_RuneGate : Moongate + { + public override bool ShowFeluccaWarning{ get{ return false/*Core.AOS*/; } } + + public SR_RuneGate( Point3D target, Map map ) : base( target, map ) + { + Map = map; + + if ( ShowFeluccaWarning && map == Map.Felucca ) + ItemID = 0xDDA; + + Dispellable = false; + + InternalTimer t = new InternalTimer( this ); + t.Start(); + } + + public SR_RuneGate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + Delete(); + } + + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Save.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Save.cs new file mode 100644 index 0000000..02ae425 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Save.cs @@ -0,0 +1,82 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Server; +using Server.Accounting; + +namespace Joeku.SR +{ + public class SR_Save + { + public static void WriteData() + { + if ( !Directory.Exists( SR_Main.SavePath ) ) + Directory.CreateDirectory( SR_Main.SavePath ); + + string filePath = Path.Combine( SR_Main.SavePath, SR_Main.FileName ); + + using ( StreamWriter op = new StreamWriter( filePath ) ) + { + XmlTextWriter xml = new XmlTextWriter( op ); + + xml.Formatting = Formatting.Indented; + xml.IndentChar = '\t'; + xml.Indentation = 1; + + xml.WriteStartDocument( true ); + + xml.WriteStartElement( "StaffRunebook" ); + + xml.WriteAttributeString( "Version", SR_Main.Version.ToString() ); + + for( int i = 0; i < SR_Main.Count; i++ ) + WriteAccountNode( SR_Main.Info[i], xml ); + + xml.WriteEndElement(); + + xml.Close(); + } + } + + public static void WriteAccountNode( SR_RuneAccount a, XmlTextWriter xml ) + { + xml.WriteStartElement( "RuneAccount" ); + + xml.WriteAttributeString( "Username", a.Username ); + for ( int i = 0; i < a.Count; i++ ) + WriteRuneNode( a.Runes[i], xml ); + + xml.WriteEndElement(); + } + + public static void WriteRuneNode( SR_Rune r, XmlTextWriter xml ) + { + xml.WriteStartElement( r.IsRunebook ? "Runebook" : "Rune" ); + + xml.WriteAttributeString( "Name", r.Name ); + if( !r.IsRunebook ) + { + xml.WriteAttributeString( "TargetMap", r.TargetMap.ToString() ); + xml.WriteAttributeString( "X", r.TargetLoc.X.ToString() ); + xml.WriteAttributeString( "Y", r.TargetLoc.Y.ToString() ); + xml.WriteAttributeString( "Z", r.TargetLoc.Z.ToString() ); + } + else + for( int i = 0; i < r.Count; i++ ) + WriteRuneNode( r.Runes[i], xml ); + + xml.WriteEndElement(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Utilities.cs b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Utilities.cs new file mode 100644 index 0000000..e30d320 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Engines/Staff Runebook/Utilities.cs @@ -0,0 +1,186 @@ +/************************************** +*Script Name: Staff Runebook * +*Author: Joeku * +*For use with RunUO 2.0 RC2 * +*Client Tested with: 6.0.9.2 * +*Version: 1.10 * +*Initial Release: 11/25/07 * +*Revision Date: 02/04/09 * +**************************************/ + +using System; +using Server; +using Server.Accounting; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; + +namespace Joeku.SR +{ + public class SR_Utilities + { + public static bool FindItem( Type type, Point3D p, Map map ) + { return FindEntity( type, p, map, false ); } + + public static bool FindMobile( Type type, Point3D p, Map map ) + { return FindEntity( type, p, map, true ); } + + public static bool FindEntity( Type type, Point3D p, Map map, bool mob ) + { + IPooledEnumerable loc; + Rectangle2D rect = new Rectangle2D( p.X, p.Y, 1, 1 ); + if( mob ) + loc = map.GetMobilesInBounds( rect ); + else + loc = map.GetItemsInBounds( rect ); + + bool found = false; + + try + { + foreach( object o in loc ) + if( o != null && o.GetType() == type || o.GetType().IsSubclassOf( type ) ) + { + found = true; + break; + } + } + catch + { + } + + loc.Free(); + + return found; + } + + public static SR_RuneAccount FetchInfo( IAccount acc ){ return FetchInfo( acc as Account ); } + public static SR_RuneAccount FetchInfo( Account acc ){ return FetchInfo( acc.Username ); } + public static SR_RuneAccount FetchInfo( string username ) + { + SR_RuneAccount runeAcc = null; + + for( int i = 0; i < SR_Main.Count; i++ ) + if( SR_Main.Info[i].Username == username ) + { + runeAcc = SR_Main.Info[i]; + break; + } + + if( runeAcc == null ) + { + runeAcc = new SR_RuneAccount( username ); + NewRuneAcc( runeAcc ); + } + + return runeAcc; + } + + public static int RunebookID = 8901; + public static int RuneID = 7956; + + public static int ItemOffsetY( SR_Rune rune ) + { + if( rune.IsRunebook ) + return -1; + return 3; + } + + public static int ItemOffsetX( SR_Rune rune ) + { + if( rune.IsRunebook ) + return -1; + return -2; + } + + public static int ItemHue( SR_Rune rune ) + { + int hue = 0; + + if( rune.IsRunebook ) + hue = 1121; + else + hue = RuneHues[MapInt(rune.TargetMap) /*+ (rune.House != null) ? 5 : 0*/]; + + return hue; + } + private static int[] RuneHues = new int[]{ 0, 50, 1102, 1102, 1154, 0x66D, 0x47F, 0x55F, 0x55F, 0x47F }; + + // To do: check for valid Z (?) + public static bool CheckValid( Point3D loc, Map map ) + { + Point2D dim = MapDimensions[MapInt(map)]; + + if( loc.X < 0 || loc.Y < 0 || loc.X > dim.X || loc.Y > dim.Y ) + return false; + + return true; + } + private static Point2D[] MapDimensions = new Point2D[] + { + new Point2D( 7168, 4096 ), // Felucca + new Point2D( 7168, 4096 ), // Trammel + new Point2D( 2304, 1600 ), // Ilshenar + new Point2D( 1448, 1448 ), // Tokuno + new Point2D( 1280, 4096 ) // TerMur + }; + + public static int MapInt( Map map ) + { + int i = 0; + + if( map == Map.Felucca ) + i = 0; + else if( map == Map.Trammel ) + i = 1; + else if( map == Map.Ilshenar ) + i = 2; + else if( map == Map.Malas ) + i = 3; + else if( map == Map.Tokuno ) + i = 4; + else if( map == Map.TerMur ) + i = 5; + + return i; + } + + public static void NewRuneAcc( SR_RuneAccount acc ) + { + acc.Clear(); + + acc.AddRune( AddTree( GoGump.Felucca, Map.Felucca ) ); + acc.AddRune( AddTree( GoGump.Trammel, Map.Trammel ) ); + acc.AddRune( AddTree( GoGump.Ilshenar, Map.Ilshenar ) ); + acc.AddRune( AddTree( GoGump.Malas, Map.Malas ) ); + acc.AddRune( AddTree( GoGump.Tokuno, Map.Tokuno ) ); + acc.AddRune( AddTree( GoGump.TerMur, Map.TerMur ) ); + } + private static SR_Rune AddTree( LocationTree tree, Map map ) + { + SR_Rune runeBook = new SR_Rune( map.ToString(), true ); + + for( int i = 0; i < tree.Root.Children.Length; i++ ) + runeBook.AddRune( AddNode( tree.Root.Children[i], map ) ); + + return runeBook; + } + private static SR_Rune AddNode( object o, Map map ) + { + if( o is ParentNode ) + { + ParentNode parentNode = o as ParentNode; + SR_Rune runeBook = new SR_Rune( parentNode.Name, true ); + + for( int i = 0; i < parentNode.Children.Length; i++ ) + runeBook.AddRune( AddNode( parentNode.Children[i], map ) ); + + return runeBook; + } + + ChildNode childNode = o as ChildNode; + + return new SR_Rune( childNode.Name, map, childNode.Location ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Items/Containers/BaseTreasureChestMod.cs b/Scripts/Customs/Nerun's Distro/New/Items/Containers/BaseTreasureChestMod.cs new file mode 100644 index 0000000..d80374e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Items/Containers/BaseTreasureChestMod.cs @@ -0,0 +1,103 @@ +// Treasure Chest Pack - Version 0.99H +// By Nerun + +using Server; +using Server.Items; +using Server.Network; +using System; + +namespace Server.Items +{ + public abstract class BaseTreasureChestMod : LockableContainer + { + private ChestTimer m_DeleteTimer; + //public override bool Decays { get{ return true; } } + //public override TimeSpan DecayTime{ get{ return TimeSpan.FromMinutes( Utility.Random( 10, 15 ) ); } } + public override int DefaultGumpID{ get{ return 0x42; } } + public override int DefaultDropSound{ get{ return 0x42; } } + public override Rectangle2D Bounds{ get{ return new Rectangle2D( 20, 105, 150, 180 ); } } + public override bool IsDecoContainer{get{ return false; }} + + public BaseTreasureChestMod( int itemID ) : base ( itemID ) + { + Locked = true; + Movable = false; + + Key key = (Key)FindItemByType( typeof(Key) ); + + if( key != null ) + key.Delete(); + } + + public BaseTreasureChestMod( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( !Locked ) + StartDeleteTimer(); + } + + public override void OnTelekinesis( Mobile from ) + { + if ( CheckLocked( from ) ) + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5022 ); + Effects.PlaySound( Location, Map, 0x1F5 ); + return; + } + + base.OnTelekinesis( from ); + Name = "a treasure chest"; + StartDeleteTimer(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( CheckLocked( from ) ) + return; + + base.OnDoubleClick( from ); + Name = "a treasure chest"; + StartDeleteTimer(); + } + + private void StartDeleteTimer() + { + if( m_DeleteTimer == null ) + m_DeleteTimer = new ChestTimer( this ); + else + m_DeleteTimer.Delay = TimeSpan.FromSeconds( Utility.Random( 1, 2 )); + + m_DeleteTimer.Start(); + } + + private class ChestTimer : Timer + { + private BaseTreasureChestMod m_Chest; + + public ChestTimer( BaseTreasureChestMod chest ) : base ( TimeSpan.FromMinutes( Utility.Random( 2, 5 ) ) ) + { + m_Chest = chest; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Chest.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Items/Containers/TreasureChestMod.cs b/Scripts/Customs/Nerun's Distro/New/Items/Containers/TreasureChestMod.cs new file mode 100644 index 0000000..404b216 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Items/Containers/TreasureChestMod.cs @@ -0,0 +1,457 @@ +// Treasure Chest Pack - Version 1.0 +// Version 0.99I By Nerun +// Version 1.0 By Obsidian Fire (Gump Fixes) + +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; +using System; + +namespace Server.Items +{ + +//----------------------------------------------------------------------------------------------------------- [Level 1] ----------------------------- +// Large, Medium and Small Crate + [FlipableAttribute( 0xE3E, 0xE3F )] + public class TreasureLevel1 : BaseTreasureChestMod + { + public override int DefaultGumpID{ get{ return 0x44; } } + + [Constructable] + public TreasureLevel1() : base( Utility.RandomList( 0xE3C, 0xE3D, 0xE3E, 0xE3F, 0x9a9, 0xE7E ) ) + { + RequiredSkill = 52; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill; + TrapType = TrapType.MagicTrap; + TrapPower = 1 * Utility.Random( 1, 25 ); + + DropItem( new Gold( 30, 100 ) ); + DropItem( Loot.RandomWeapon() ); + DropItem( Loot.RandomArmorOrShield() ); + DropItem( Loot.RandomClothing() ); + DropItem( Loot.RandomJewelry() ); + DropItem( new Bolt( 10 ) ); + + for (int i = Utility.Random(3) + 1; i > 0; i--) // random 1 to 3 + DropItem( Loot.RandomGem() ); + } + + public TreasureLevel1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +//----------------------------------------------------------------------------------------------------------- [Level 1 Hybrid] ---------------------- +// Large, Medium and Small Crate + [FlipableAttribute( 0xe3e, 0xe3f )] + public class TreasureLevel1h : BaseTreasureChestMod + { + public override int DefaultGumpID{ get{ return 0x44; } } + + [Constructable] + public TreasureLevel1h() : base( Utility.RandomList( 0xE3C, 0xE3D, 0xE3E, 0xE3F, 0x9a9, 0xE7E ) ) + { + RequiredSkill = 56; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill; + TrapType = TrapType.MagicTrap; + TrapPower = 1 * Utility.Random( 1, 25 ); + + DropItem( new Gold( 10, 40 ) ); + DropItem( new Bolt( 5 ) ); + switch ( Utility.Random( 6 )) + { + case 0: DropItem( new Candelabra() ); break; + case 1: DropItem( new Candle() ); break; + case 2: DropItem( new CandleLarge() ); break; + case 3: DropItem( new CandleLong() ); break; + case 4: DropItem( new CandleShort() ); break; + case 5: DropItem( new CandleSkull() ); break; + } + switch ( Utility.Random( 2 )) + { + case 0: DropItem( new Shoes( Utility.Random( 1, 2 ) ) ); break; + case 1: DropItem( new Sandals( Utility.Random( 1, 2 ) ) ); break; + } + + switch ( Utility.Random( 3 )) + { + case 0: DropItem( new BeverageBottle(BeverageType.Ale) ); break; + case 1: DropItem( new BeverageBottle(BeverageType.Liquor) ); break; + case 2: DropItem( new Jug(BeverageType.Cider) ); break; + } + } + + public TreasureLevel1h( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +//----------------------------------------------------------------------------------------------------------- [Level 2] ----------------------------- +// Large, Medium and Small Crate +// Wooden, Metal and Metal Golden Chest +// Keg and Barrel + [FlipableAttribute( 0xE43, 0xE42 )] + public class TreasureLevel2 : BaseTreasureChestMod + { + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch( Utility.RandomList( 0, 1, 2, 3, 4, 5, 6, 7 ) ) + { + + case 0:// Large Crate + this.ItemID = ( UseFirstItemId ? 0xE3C : 0xE3D ); + this.GumpID = 0x44; + break; + + case 1:// Medium Crate + this.ItemID = ( UseFirstItemId ? 0xE3E : 0xE3F ); + this.GumpID = 0x44; + break; + + case 2:// Small Crate + this.ItemID = ( UseFirstItemId ? 0x9A9 : 0xE7E ); + this.GumpID = 0x44; + break; + + case 3:// Wooden Chest + this.ItemID = ( UseFirstItemId ? 0xE42 : 0xE43 ); + this.GumpID = 0x49; + break; + + case 4:// Metal Chest + this.ItemID = ( UseFirstItemId ? 0x9AB : 0xE7C ); + this.GumpID = 0x4A; + break; + + case 5:// Metal Golden Chest + this.ItemID = ( UseFirstItemId ? 0xE40 : 0xE41 ); + this.GumpID = 0x42; + break; + + case 6:// Keg + this.ItemID = ( UseFirstItemId ? 0xE7F : 0xE7F ); + this.GumpID = 0x3e; + break; + + case 7:// Barrel + this.ItemID = ( UseFirstItemId ? 0xE77 : 0xE77 ); + this.GumpID = 0x3e; + break; + } + } + + [Constructable] + public TreasureLevel2() : base ( Utility.RandomList( 0xE3C, 0xE3E, 0x9A9, 0xE42, 0x9AB, 0xE40, 0xE7F, 0xE77 )) + { + this.SetChestAppearance(); + Movable = false; + RequiredSkill = 72; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill; + TrapType = TrapType.MagicTrap; + TrapPower = 2 * Utility.Random( 1, 25 ); + + DropItem( new Gold( 70, 100 ) ); + DropItem( new Arrow( 10 ) ); + DropItem( Loot.RandomPotion() ); + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random( 1, 2 ); + DropItem( ReagentLoot ); + } + if (Utility.RandomBool()) //50% chance + for (int i = Utility.Random(8) + 1; i > 0; i--) + DropItem(Loot.RandomScroll(0, 39, SpellbookType.Regular)); + + if (Utility.RandomBool()) //50% chance + for (int i = Utility.Random(6) + 1; i > 0; i--) + DropItem( Loot.RandomGem() ); + } + + public TreasureLevel2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +//----------------------------------------------------------------------------------------------------------- [Level 3] ----------------------------- +// Wooden, Metal and Metal Golden Chest + [FlipableAttribute( 0x9AB, 0xE7C )] + public class TreasureLevel3 : BaseTreasureChestMod + { + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + switch( Utility.RandomList( 0, 1, 2 ) ) + { + case 0:// Wooden Chest + this.ItemID = ( UseFirstItemId ? 0xE42 : 0xE43 ); + this.GumpID = 0x49; + break; + + case 1:// Metal Chest + this.ItemID = ( UseFirstItemId ? 0x9AB : 0xE7C ); + this.GumpID = 0x4A; + break; + + case 2:// Metal Golden Chest + this.ItemID = ( UseFirstItemId ? 0xE40 : 0xE41 ); + this.GumpID = 0x42; + break; + } + } + + [Constructable] + public TreasureLevel3() : base( Utility.RandomList( 0xE42, 0x9AB, 0xE40 ) ) + { + this.SetChestAppearance(); + Movable = false; + RequiredSkill = 84; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill; + TrapType = TrapType.MagicTrap; + TrapPower = 3 * Utility.Random( 1, 25 ); + + DropItem( new Gold( 180, 240 ) ); + DropItem( new Arrow( 10 ) ); + + for( int i = Utility.Random( 1, 3 ); i > 1; i-- ) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random( 1, 9 ); + DropItem( ReagentLoot ); + } + + for ( int i = Utility.Random( 1, 3 ); i > 1; i-- ) + DropItem( Loot.RandomPotion() ); + + if ( 0.67 > Utility.RandomDouble() ) //67% chance = 2/3 + for (int i = Utility.Random(12) + 1; i > 0; i--) + DropItem(Loot.RandomScroll(0, 47, SpellbookType.Regular)); + + if ( 0.67 > Utility.RandomDouble() ) //67% chance = 2/3 + for (int i = Utility.Random(9) + 1; i > 0; i--) + DropItem( Loot.RandomGem() ); + + for( int i = Utility.Random( 1, 3 ); i > 1; i-- ) + DropItem( Loot.RandomWand() ); + + // Magical ArmorOrWeapon + for( int i = Utility.Random( 1, 3 ); i > 1; i-- ) + { + Item item = Loot.RandomArmorOrShieldOrWeapon(); + + if( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random( 3 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random( 3 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random( 3 ); + weapon.Quality = WeaponQuality.Regular; + } + else if( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random( 3 ); + armor.Durability = (ArmorDurabilityLevel)Utility.Random( 3 ); + armor.Quality = ArmorQuality.Regular; + } + + DropItem( item ); + } + + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomClothing() ); + + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomJewelry() ); + + // Magic clothing (not implemented) + + // Magic jewelry (not implemented) + } + + public TreasureLevel3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +//----------------------------------------------------------------------------------------------------------- [Level 4] ----------------------------- +// Wooden, Metal and Metal Golden Chest + [FlipableAttribute( 0xE41, 0xE40 )] + public class TreasureLevel4 : BaseTreasureChestMod + { + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + switch( Utility.RandomList( 0, 1, 2 ) ) + { + case 0:// Wooden Chest + this.ItemID = ( UseFirstItemId ? 0xE42 : 0xE43 ); + this.GumpID = 0x49; + break; + + case 1:// Metal Chest + this.ItemID = ( UseFirstItemId ? 0x9AB : 0xE7C ); + this.GumpID = 0x4A; + break; + + case 2:// Metal Golden Chest + this.ItemID = ( UseFirstItemId ? 0xE40 : 0xE41 ); + this.GumpID = 0x42; + break; + } + } + + [Constructable] + public TreasureLevel4() : base( Utility.RandomList( 0xE42, 0x9AB, 0xE40 ) ) + { + this.SetChestAppearance(); + Movable = false; + RequiredSkill = 92; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill; + TrapType = TrapType.MagicTrap; + TrapPower = 4 * Utility.Random( 1, 25 ); + + DropItem( new Gold( 200, 400 ) ); + DropItem( new BlankScroll( Utility.Random( 1, 4 ) ) ); + + for( int i = Utility.Random( 1, 4 ); i > 1; i-- ) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random( 6, 12 ); + DropItem( ReagentLoot ); + } + + for ( int i = Utility.Random( 1, 4 ); i > 1; i-- ) + DropItem( Loot.RandomPotion() ); + + if ( 0.75 > Utility.RandomDouble() ) //75% chance = 3/4 + for (int i = Utility.RandomMinMax(8,16); i > 0; i--) + DropItem(Loot.RandomScroll(0, 47, SpellbookType.Regular)); + + if ( 0.75 > Utility.RandomDouble() ) //75% chance = 3/4 + for (int i = Utility.RandomMinMax(6,12) + 1; i > 0; i--) + DropItem( Loot.RandomGem() ); + + for( int i = Utility.Random( 1, 4 ); i > 1; i-- ) + DropItem( Loot.RandomWand() ); + + // Magical ArmorOrWeapon + for( int i = Utility.Random( 1, 4 ); i > 1; i-- ) + { + Item item = Loot.RandomArmorOrShieldOrWeapon(); + + if( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random( 4 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random( 4 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random( 4 ); + weapon.Quality = WeaponQuality.Regular; + } + else if( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random( 4 ); + armor.Durability = (ArmorDurabilityLevel)Utility.Random( 4 ); + armor.Quality = ArmorQuality.Regular; + } + + DropItem( item ); + } + + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomClothing() ); + + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomJewelry() ); + + DropItem( new MagicCrystalBall() ); + + // Magic clothing (not implemented) + + // Magic jewelry (not implemented) + } + + public TreasureLevel4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Items/Decoration/Lever.cs b/Scripts/Customs/Nerun's Distro/New/Items/Decoration/Lever.cs new file mode 100644 index 0000000..54713b7 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Items/Decoration/Lever.cs @@ -0,0 +1,38 @@ +// By Nerun + +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class Lever : Item + { + [Constructable] + public Lever() : base( Utility.RandomList( 0x108C, 0x108D, 0x108E, 0x1093, 0x1094, 0x1095, 0x108F, 0x1090, 0x1091, 0x1092 ) ) + { + this.Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 500357 + Utility.Random( 5 )); + } + + public Lever( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Items/GMStuff/StaffCloak.cs b/Scripts/Customs/Nerun's Distro/New/Items/GMStuff/StaffCloak.cs new file mode 100644 index 0000000..14019ff --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Items/GMStuff/StaffCloak.cs @@ -0,0 +1,189 @@ +using System; +using Server.Mobiles; + +/* +** Allows staff to quickly switch between player and their assigned staff levels by equipping or removing the cloak +** Also allows instant teleportation to a specified destination when double-clicked by the staff member. +*/ + +namespace Server.Items +{ + public class StaffCloak : Cloak + { + + private AccessLevel m_StaffLevel; + private Point3D m_HomeLoc; + private Map m_HomeMap; + private AccessLevel OriginalAccessLevel; + + [CommandProperty( AccessLevel.Administrator )] + public AccessLevel StaffLevel { + get + { + return m_StaffLevel; + } + set + { + m_StaffLevel = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D HomeLoc { get { return m_HomeLoc;} set { m_HomeLoc = value;} } + + [CommandProperty( AccessLevel.GameMaster )] + public Map HomeMap { get { return m_HomeMap;} set { m_HomeMap = value;} } + + public override void GetProperties( ObjectPropertyList list ) + { + + base.GetProperties(list); + + list.Add( 1060658, "Level\t{0}", StaffLevel ); // ~1_val~: ~2_val~ + + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + // delete this if someone without the necessary access level picks it up or tries to equip it + if(RootParent is Mobile) + { + if (((Mobile) RootParent).AccessLevel < StaffLevel) + { + Delete(); + return; + } + } + + // when equipped, change access level to player + if ( parent is Mobile ) + { + Mobile m =(Mobile) parent; + + if (m.AccessLevel >= StaffLevel) + { + OriginalAccessLevel = m.AccessLevel; + m.AccessLevel = AccessLevel.Player; + // and make vuln + m.Blessed = false; + // and remove title + m.Title = null; + } + } + } + + public override void OnRemoved( object parent ) + { + base.OnRemoved( parent ); + + // restore access level to the specified level + if ( parent is Mobile && !Deleted) + { + Mobile m = (Mobile) parent; + + // restore their assigned staff level + m.AccessLevel = OriginalAccessLevel;//StaffLevel; + OriginalAccessLevel = StaffLevel; + // and make invuln + m.Blessed = true; + // make hidden + m.Hidden = true; + // restore title + if(m.AccessLevel == AccessLevel.Counselor) + { + m.Title = "[Counselor]"; + } + + if(m.AccessLevel == AccessLevel.GameMaster) + { + m.Title = "[GM]"; + } + + if(m.AccessLevel == AccessLevel.Seer) + { + m.Title = "[Seer]"; + } + + if(m.AccessLevel == AccessLevel.Administrator) + { + m.Title = "[Admin]"; + } + + if(m.AccessLevel == AccessLevel.Developer) + { + m.Title = "[Developer]"; + } + + if(m.AccessLevel == AccessLevel.Owner) + { + m.Title = "[Owner]"; + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if(from == null) return; + + if(HomeMap != Map.Internal && HomeMap != null && from.AccessLevel == StaffLevel) + { + // teleport them to the specific location + from.MoveToWorld(HomeLoc, HomeMap); + } + } + + [Constructable] + public StaffCloak() : base() + { + StaffLevel= AccessLevel.Administrator; // assign admin staff level by default + LootType = LootType.Blessed; + Name = "Staff Cloak"; + Weight = 0; + } + + public StaffCloak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + // version + writer.Write( (int) 0 ); + // version 0 + writer.Write( (int) m_StaffLevel ); + writer.Write( m_HomeLoc ); + string mapname = null; + if(m_HomeMap != null) + { + mapname = m_HomeMap.Name; + } + writer.Write( mapname ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch(version) + { + case 0: + m_StaffLevel = (AccessLevel)reader.ReadInt(); + m_HomeLoc = reader.ReadPoint3D(); + string mapname = reader.ReadString(); + + try{ + m_HomeMap = Map.Parse(mapname); + } catch{} + + break; + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Items/GMStuff/StaffRing.cs b/Scripts/Customs/Nerun's Distro/New/Items/GMStuff/StaffRing.cs new file mode 100644 index 0000000..d3ecd7e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Items/GMStuff/StaffRing.cs @@ -0,0 +1,65 @@ +// By Nerun + +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + + public class StaffRing : BaseRing + { + [Constructable] + public StaffRing() : base( 0x108a ) + { + Weight = 1.0; + Name = "The Staff Ring"; + Attributes.NightSight = 1; + Attributes.AttackChance = 20; + Attributes.LowerRegCost = 100; + Attributes.LowerManaCost = 100; + Attributes.RegenHits = 12; + Attributes.RegenStam = 24; + Attributes.RegenMana = 18; + Attributes.SpellDamage = 30; + Attributes.CastRecovery = 6; + Attributes.CastSpeed = 4; + LootType = LootType.Blessed; + } + + public StaffRing( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel < AccessLevel.Counselor ) + { + from.SendMessage ( "Your not a Staff member, you may not wear this Item..." ); + this.Delete(); + } + } + + public override bool OnEquip( Mobile from ) + { + if ( from.AccessLevel < AccessLevel.Counselor ) + { + from.SendMessage ( "Your not a Staff member, you may not wear this Item..." ); + this.Delete(); + } + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Items/Misc/CrystalBall.cs b/Scripts/Customs/Nerun's Distro/New/Items/Misc/CrystalBall.cs new file mode 100644 index 0000000..31eb0dc --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Items/Misc/CrystalBall.cs @@ -0,0 +1,43 @@ +// By Neon +// Improved By Dddie + +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class MagicCrystalBall : Item + { + [Constructable] + public MagicCrystalBall() : base( 0xE2E ) + { + this.Name = "a crystal ball"; + this.Weight = 10; + this.Stackable = false; + this.LootType = LootType.Blessed; + this.Light = LightType.Circle150; + } + + public override void OnDoubleClick( Mobile from ) + { + this.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1007000 + Utility.Random( 28 )); + } + + public MagicCrystalBall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/NinjaAI.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/NinjaAI.cs new file mode 100644 index 0000000..1e128c9 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/NinjaAI.cs @@ -0,0 +1,516 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Spells; +using Server.Spells.Ninjitsu; +using Server.Network; +using Server.Items; + +namespace Server.Mobiles +{ + public class NinjaAI : BaseAI + { + public override bool Think() + { + try + { + if( m_Mobile.Deleted ) + return false; + + if( CheckFlee() ) + return true; + + switch( Action ) + { + case ActionType.Wander: + m_Mobile.OnActionWander(); + return DoActionWander(); + + case ActionType.Combat: + m_Mobile.OnActionCombat(); + return DoActionCombat(); + + case ActionType.Guard: + m_Mobile.OnActionGuard(); + return DoActionGuard(); + + case ActionType.Flee: + m_Mobile.OnActionFlee(); + return DoActionFlee(); + + case ActionType.Interact: + m_Mobile.OnActionInteract(); + return DoActionInteract(); + + case ActionType.Backoff: + m_Mobile.OnActionBackoff(); + return DoActionBackoff(); + + default: + return false; + } + } + catch ( Exception e ) + { + Console.WriteLine( "Catched Exception from EliteNinja when " + Action.ToString() ); + Console.WriteLine( e.ToString() ); + return false; + } + } + + private static double shadowJumpChance = 0.3; + private static double mirrorChance = 0.4; + private static double kiChance = 0.5; + private static double focusChance = 0.5; + private static double hideChance = 0.1; + private static double turnOrHideChance = 0.05; + + private static double comboChance = 0.7; + + public NinjaAI( BaseCreature m ) : base( m ) + { + } + + private double MagnitudeBySkill() + { + return (m_Mobile.Skills[ SkillName.Ninjitsu ].Value/1000.0); + } + + private bool CanUseAbility( double limit, int mana, double chance ) + { + if ( m_Mobile.Skills[ SkillName.Ninjitsu ].Value >= limit && m_Mobile.Mana >= mana ) + { + if ( (chance + MagnitudeBySkill()) >= Utility.RandomDouble() ) + { + return true; + } + } + + return false; + } + + private static int[] m_Bodies = new int[] + { + 0x84, + 0x7A, + 0xF6, + 0x19, + 0xDC, + 0xDA, + 0x51, + 0x15, + 0xD9, + 0xC9, + 0xEE, + 0xCD + }; + + private static int[] m_Offsets = new int[] + { + 0, 0, + -1,-1, + 0,-1, + 1,-1, + -1, 0, + 1, 0, + -1,-1, + 0, 1, + 1, 1, + }; + + private void ChangeForm( int body ) + { + m_Mobile.FixedEffect( 0x37C4, 10, 42, 4, 3 ); + + m_Mobile.BodyMod = body; + } + + // Shadowjump + private bool PerformShadowjump( Mobile toTarget ) + { + if ( m_Mobile.Skills[ SkillName.Ninjitsu ].Value < 50.0 ) + { + return false; + } + + if ( toTarget != null ) + { + Map map = m_Mobile.Map; + + if ( map == null ) + { + return false; + } + + int px, py, ioffset = 0; + + px = toTarget.X; + py = toTarget.Y; + + if ( Action == ActionType.Flee ) + { + double outerradius = m_Mobile.Skills[ SkillName.Ninjitsu ].Value/10.0; + double radiusoffset = 2.0; + // random point for direction vector + int rpx = Utility.Random( 40 ) - 20 + toTarget.X; + int rpy = Utility.Random( 40 ) - 20 + toTarget.Y; + // get vector + int dx = rpx - toTarget.X; + int dy = rpy - toTarget.Y; + // get vector's length + double l = Math.Sqrt( (double) (dx*dx + dy*dy) ); + + if ( l == 0 ) + { + return false; + } + // normalize vector + double dpx = ((double) dx)/l; + double dpy = ((double) dy)/l; + // move + px += (int) (dpx*(outerradius - radiusoffset) + Math.Sign( dpx )*(radiusoffset + 0.5)); + py += (int) (dpy*(outerradius - radiusoffset) + Math.Sign( dpy )*(radiusoffset + 0.5)); + } + else + { + ioffset = 2; + } + + for ( int i = ioffset; i < m_Offsets.Length; i += 2 ) + { + int x = m_Offsets[ i ], y = m_Offsets[ i + 1 ]; + + Point3D p = new Point3D( px + x, py + y, 0 ); + + LandTarget lt = new LandTarget( p, map ); + + if ( m_Mobile.InLOS( lt ) && map.CanSpawnMobile( px + x, py + y, lt.Z ) && !SpellHelper.CheckMulti( p, map ) ) + { + m_Mobile.Location = new Point3D( lt.X, lt.Y, lt.Z ); + m_Mobile.ProcessDelta(); + + return true; + } + } + } + + return false; + } + + private void PerformHide() + { + Effects.SendLocationParticles( EffectItem.Create( m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + m_Mobile.PlaySound( 0x22F ); + m_Mobile.Hidden = true; + } + + private bool PerformFocusAttack() + { + if ( Utility.RandomBool() && CanUseAbility( 60.0, 20, focusChance ) ) + { + SpecialMove.SetCurrentMove( m_Mobile, new FocusAttack() ); + return true; + } + + return false; + } + + private bool PerformMirror() + { + if ( CanUseAbility( 40.0, 10, mirrorChance ) && (m_Mobile.Followers < m_Mobile.FollowersMax) ) + { + new MirrorImage( m_Mobile, null ).Cast(); + return true; + } + + return false; + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay( "I am wandering around." ); + + if ( turnOrHideChance > Utility.RandomDouble() && !m_Mobile.Hidden ) + { + if ( Utility.RandomBool() ) + { + if ( m_Mobile.BodyMod == 0 ) + { + ChangeForm( m_Bodies[ Utility.Random( m_Bodies.Length ) ] ); + } + else + { + ChangeForm( 0 ); + } + } + else + { + PerformHide(); + m_Mobile.UseSkill( SkillName.Stealth ); + } + } + + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.DebugSay( "I have detected {0}, going to try and sneak up on them!", m_Mobile.FocusMob.Name ); + + if( m_Mobile.Hidden ) // we are hidden + { + if( m_Mobile.GetDistanceToSqrt( m_Mobile.FocusMob ) <= 2 ) + { + if ( CanUseAbility( 85.0, 30, 1.0 ) ) + { + SpecialMove.SetCurrentMove( m_Mobile, new DeathStrike() ); + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + + else + { + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + + } + else if( m_Mobile.GetDistanceToSqrt( m_Mobile.FocusMob ) <= 10 ) + { + //MoveTo( m_Mobile.FocusMob, true, 1 ); + WalkMobileRange(m_Mobile.FocusMob, 10, true, 2, 1); + } + } + + else + { + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + + + } + else + return base.DoActionWander(); + + return true; + } + + public override bool DoActionCombat() + { + if ( m_Mobile.BodyMod != 0 ) + { + ChangeForm( 0 ); + } + + Mobile combatant = m_Mobile.Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet ) + { + m_Mobile.DebugSay( "My combatant is gone, so my guard is up" ); + + Action = ActionType.Guard; + + return true; + } + + /*if ( !m_Mobile.InLOS( combatant ) ) + { + if ( AquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + }*/ + + if ( MoveTo( combatant, true, m_Mobile.RangeFight ) ) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant ); + } + else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + + return true; + } + else if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 ) + { + m_Mobile.DebugSay( "I cannot find {0}, so my guard is up", combatant.Name ); + + Action = ActionType.Guard; + + return true; + } + else + { + m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name ); + } + + if ( !m_Mobile.Controlled && !m_Mobile.Summoned ) + { + if ( m_Mobile.Hits < m_Mobile.HitsMax*20/100 ) + { + // We are low on health, should we flee? + + bool flee = false; + + if ( m_Mobile.Hits < combatant.Hits ) + { + // We are more hurt than them + + int diff = combatant.Hits - m_Mobile.Hits; + + flee = (Utility.Random( 0, 100 ) < (10 + diff)); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random( 0, 100 ) < 10; // 10% chance to flee + } + + if ( flee ) + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name ); + } + + Action = ActionType.Flee; + + if ( CanUseAbility( 50.0, 15, shadowJumpChance ) ) + { + PerformHide(); + + m_Mobile.UseSkill( SkillName.Stealth ); + + if ( m_Mobile.AllowedStealthSteps != 0 ) + { + if ( PerformShadowjump( combatant ) ) + { + m_Mobile.Mana -= 15; + } + } + } + } + } + } + + if ( combatant.Hits < (Utility.Random( 10 ) + 10) ) + { + if ( CanUseAbility( 85.0, 30, 1.0 ) ) + { + SpecialMove.SetCurrentMove( m_Mobile, new DeathStrike() ); + return true; + } + } + + double dstToTarget = m_Mobile.GetDistanceToSqrt( combatant ); + + if ( dstToTarget > 2.0 && dstToTarget <= (m_Mobile.Skills[ SkillName.Ninjitsu ].Value/10.0) && m_Mobile.Mana > 45 && comboChance > (Utility.RandomDouble() + MagnitudeBySkill()) ) + { + PerformHide(); + + m_Mobile.UseSkill( SkillName.Stealth ); + + if ( m_Mobile.AllowedStealthSteps != 0 ) + { + if ( CanUseAbility( 20.0, 30, 1.0 ) ) + { + SpecialMove.SetCurrentMove( m_Mobile, new Backstab() ); + } + + if ( CanUseAbility( 30.0, 20, 1.0 ) ) + { + SpecialMove.SetCurrentMove( m_Mobile, new SurpriseAttack() ); + } + + PerformFocusAttack(); + + if ( PerformShadowjump( combatant ) ) + { + m_Mobile.Mana -= 15; + } + } + + return true; + } + + if ( PerformMirror() ) + { + return true; + } + + if ( CanUseAbility( 80.0, 25, kiChance ) && m_Mobile.GetDistanceToSqrt( combatant ) < 2.0 ) + { + SpecialMove.SetCurrentMove( m_Mobile, new KiAttack() ); + return true; + } + + PerformFocusAttack(); + + return true; + } + + public override bool DoActionGuard() + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + if ( m_Mobile.Hits > m_Mobile.HitsMax/2 ) + { + m_Mobile.DebugSay( "I am stronger now, so I will continue fighting" ); + Action = ActionType.Combat; + } + else + { + m_Mobile.FocusMob = m_Mobile.Combatant; + + if ( m_Mobile.FocusMob == null || m_Mobile.FocusMob.Deleted || m_Mobile.FocusMob.Map != m_Mobile.Map ) + { + m_Mobile.DebugSay( "I have lost im" ); + Action = ActionType.Guard; + return true; + } + + if ( !m_Mobile.Hidden ) + { + PerformMirror(); + + if ( hideChance > (Utility.RandomDouble() + MagnitudeBySkill()) ) + { + PerformHide(); + + m_Mobile.UseSkill( SkillName.Stealth ); + } + } + + if ( WalkMobileRange( m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception*2, m_Mobile.RangePerception*3 ) ) + { + m_Mobile.DebugSay( "I Have fled" ); + Action = ActionType.Guard; + return true; + } + else + { + m_Mobile.DebugSay( "I am fleeing!" ); + } + } + + return true; + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/OrcScoutAI.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/OrcScoutAI.cs new file mode 100644 index 0000000..646cf9c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/OrcScoutAI.cs @@ -0,0 +1,362 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Spells; +using Server.Items; + +namespace Server.Mobiles +{ + public class OrcScoutAI : BaseAI + { + private static double teleportChance = 0.04; + private static int[] m_Offsets = new int[] + { + 0, 0, + -1,-1, + 0,-1, + 1,-1, + -1, 0, + 1, 0, + -1,-1, + 0, 1, + 1, 1, + }; + + private Mobile FindNearestAggressor() + { + Mobile nearest = null; + + double dist = 9999.0; + + foreach ( Mobile m in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) ) + { + if ( m.Player && !m.Hidden && m.AccessLevel == AccessLevel.Player && m.Combatant == m_Mobile ) + { + if ( dist > m.GetDistanceToSqrt( m_Mobile ) ) + { + nearest = m; + } + } + } + + return nearest; + } + + private void TryToTeleport() + { + Mobile m = FindNearestAggressor(); + + if ( m == null || m.Map == null || m_Mobile.Map == null ) + { + return; + } + + if ( m_Mobile.GetDistanceToSqrt( m ) > m_Mobile.RangePerception + 1 ) + { + return; + } + + int px = m_Mobile.X; + int py = m_Mobile.Y; + + int dx = m_Mobile.X - m.X; + int dy = m_Mobile.Y - m.Y; + + // get vector's length + + double l = Math.Sqrt( (double) (dx*dx + dy*dy) ); + + if ( l == 0 ) + { + int rand = Utility.Random( 8 ) + 1; + rand *= 2; + dx = m_Offsets[ rand ]; + dy = m_Offsets[ rand + 1 ]; + l = Math.Sqrt( (double) (dx*dx + dy*dy) ); + } + + // normalize vector + double dpx = ((double) dx)/l; + double dpy = ((double) dy)/l; + // move + px += (int) (dpx*(4 + Utility.Random( 3 ))); + py += (int) (dpy*(4 + Utility.Random( 3 ))); + + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = m_Offsets[ i ], y = m_Offsets[ i + 1 ]; + + Point3D p = new Point3D( px + x, py + y, 0 ); + + LandTarget lt = new LandTarget( p, m_Mobile.Map ); + + if ( m_Mobile.InLOS( lt ) && m_Mobile.Map.CanSpawnMobile( px + x, py + y, lt.Z ) && !SpellHelper.CheckMulti( p, m_Mobile.Map ) ) + { + m_Mobile.FixedParticles( 0x376A, 9, 32, 0x13AF, EffectLayer.Waist ); + m_Mobile.PlaySound( 0x1FE ); + + m_Mobile.Location = new Point3D( lt.X, lt.Y, lt.Z ); + m_Mobile.ProcessDelta(); + + return; + } + } + + return; + } + + private void HideSelf() + { + if ( DateTime.Now >= m_Mobile.NextSkillTime ) + { + Effects.SendLocationParticles( EffectItem.Create( m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + + m_Mobile.PlaySound( 0x22F ); + m_Mobile.Hidden = true; + + m_Mobile.UseSkill( SkillName.Stealth ); + } + } + + private void PerformHide() + { + if ( !m_Mobile.Alive || m_Mobile.Deleted ) + { + return; + } + + if ( !m_Mobile.Hidden ) + { + double chance = 0.05; + + if ( m_Mobile.Hits < 20 ) + { + chance = 0.1; + } + + if ( m_Mobile.Poisoned ) + { + chance = 0.01; + } + + if ( Utility.RandomDouble() < chance ) + { + HideSelf(); + } + } + } + + public OrcScoutAI( BaseCreature m ) : base( m ) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay( "I have no combatant" ); + + PerformHide(); + + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name ); + } + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + if ( m_Mobile.Combatant != null ) + { + Action = ActionType.Combat; + return true; + } + + + + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet ) + { + m_Mobile.DebugSay( "My combatant is gone, so my guard is up" ); + + Action = ActionType.Guard; + + return true; + } + + if ( Utility.RandomDouble() < teleportChance ) + { + TryToTeleport(); + } + + if ( !m_Mobile.InRange( combatant, m_Mobile.RangePerception ) ) + { + // They are somewhat far away, can we find something else? + + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if ( !m_Mobile.InRange( combatant, m_Mobile.RangePerception*3 ) ) + { + m_Mobile.Combatant = null; + } + + combatant = m_Mobile.Combatant; + + if ( combatant == null ) + { + m_Mobile.DebugSay( "My combatant has fled, so I am on guard" ); + Action = ActionType.Guard; + + return true; + } + } + + /*if ( !m_Mobile.InLOS( combatant ) ) + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + }*/ + + if ( MoveTo( combatant, true, m_Mobile.RangeFight ) ) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant ); + } + else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name ); + } + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + + return true; + } + else if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 ) + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "I cannot find {0}, so my guard is up", combatant.Name ); + } + + Action = ActionType.Guard; + + return true; + } + else + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name ); + } + } + + if ( !m_Mobile.Controlled && !m_Mobile.Summoned ) + { + if ( m_Mobile.Hits < m_Mobile.HitsMax*20/100 ) + { + // We are low on health, should we flee? + + bool flee = false; + + if ( m_Mobile.Hits < combatant.Hits ) + { + // We are more hurt than them + + int diff = combatant.Hits - m_Mobile.Hits; + + flee = (Utility.Random( 0, 100 ) < (10 + diff)); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random( 0, 100 ) < 10; // 10% chance to flee + } + + if ( flee ) + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name ); + } + + Action = ActionType.Flee; + + if ( Utility.RandomDouble() < teleportChance + 0.1 ) + { + TryToTeleport(); + } + } + } + } + + return true; + } + + public override bool DoActionGuard() + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + { + m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name ); + } + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + if ( m_Mobile.Hits > m_Mobile.HitsMax/2 ) + { + m_Mobile.DebugSay( "I am stronger now, so I will continue fighting" ); + Action = ActionType.Combat; + } + else + { + m_Mobile.FocusMob = m_Mobile.Combatant; + + PerformHide(); + + if ( WalkMobileRange( m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception*2, m_Mobile.RangePerception*3 ) ) + { + m_Mobile.DebugSay( "I Have fled" ); + Action = ActionType.Guard; + return true; + } + else + { + m_Mobile.DebugSay( "I am fleeing!" ); + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/SpellbinderAI.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/SpellbinderAI.cs new file mode 100644 index 0000000..013cac4 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/AI/SpellbinderAI.cs @@ -0,0 +1,862 @@ +using System; +using System.Collections.Generic; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Spells; +using Server.Spells.First; +using Server.Spells.Second; +using Server.Spells.Third; +using Server.Spells.Fourth; +using Server.Spells.Fifth; +using Server.Spells.Sixth; +using Server.Spells.Seventh; +using Server.Spells.Necromancy; +using Server.Misc; +using Server.Regions; +using Server.SkillHandlers; + +namespace Server.Mobiles +{ + public class SpellbinderAI : BaseAI + { + private DateTime m_NextCastTime; + + public SpellbinderAI( BaseCreature m ) : base( m ) + { + } + + public override bool Think() + { + if ( m_Mobile.Deleted ) + return false; + + Target targ = m_Mobile.Target; + + if ( targ != null ) + { + ProcessTarget( targ ); + + return true; + } + else + { + return base.Think(); + } + } + + private const double HealChance = 0.05; // 5% chance to heal at gm necromancy, uses spirit speak healing + private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery + private const double DispelChance = 0.75; // 75% chance to dispel at gm magery + + public virtual double ScaleByNecromancy( double v ) + { + return m_Mobile.Skills[SkillName.Necromancy].Value * v * 0.01; + } + + public virtual double ScaleByMagery( double v ) + { + return m_Mobile.Skills[SkillName.Magery].Value * v * 0.01; + } + + public override bool DoActionWander() + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + m_NextCastTime = DateTime.Now; + } + else if ( m_Mobile.Mana < m_Mobile.ManaMax ) + { + m_Mobile.DebugSay( "I am going to meditate" ); + + m_Mobile.UseSkill( SkillName.Meditation ); + } + else + { + m_Mobile.DebugSay( "I am wandering" ); + + m_Mobile.Warmode = false; + + base.DoActionWander(); + + if ( m_Mobile.Poisoned ) + { + new CureSpell( m_Mobile, null ).Cast(); + } + else if ( !m_Mobile.Summoned ) + { + if ( m_Mobile.Hits < (m_Mobile.HitsMax - 50) ) + { + if ( !new GreaterHealSpell( m_Mobile, null ).Cast() ) + new HealSpell( m_Mobile, null ).Cast(); + } + else if ( m_Mobile.Hits < (m_Mobile.HitsMax - 10) ) + { + new HealSpell( m_Mobile, null ).Cast(); + } + } + } + + return true; + } + + private DateTime m_NextHealTime = DateTime.Now; + + private Spell CheckCastHealingSpell() + { + // If I'm poisoned, always attempt to cure. + if ( m_Mobile.Poisoned ) + return new CureSpell( m_Mobile, null ); + + // Summoned creatures never heal themselves. + if ( m_Mobile.Summoned ) + return null; + + if ( m_Mobile.Controlled ) + { + if ( DateTime.Now < m_NextHealTime ) + return null; + } + + if ( ScaleByMagery( HealChance ) < Utility.RandomDouble() ) + return null; + + Spell spell = null; + + if ( m_Mobile.Hits < (m_Mobile.HitsMax - 50) ) + { + spell = new GreaterHealSpell( m_Mobile, null ); + + if ( spell == null ) + spell = new HealSpell( m_Mobile, null ); + } + else if ( m_Mobile.Hits < (m_Mobile.HitsMax - 10) ) + spell = new HealSpell( m_Mobile, null ); + + double delay; + + if ( m_Mobile.Int >= 500 ) + delay = Utility.RandomMinMax( 7, 10 ); + else + delay = Math.Sqrt( 600 - m_Mobile.Int ); + + m_Mobile.UseSkill( SkillName.SpiritSpeak ); + + m_NextHealTime = DateTime.Now + TimeSpan.FromSeconds( delay ); + + return spell; + } + + public void RunTo( Mobile m ) + { + if ( m.Paralyzed || m.Frozen ) + { + if ( m_Mobile.InRange( m, 1 ) ) + RunFrom( m ); + else if ( !m_Mobile.InRange( m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2 ) && !MoveTo( m, true, 1 ) ) + OnFailedMove(); + } + else + { + if ( !m_Mobile.InRange( m, m_Mobile.RangeFight ) ) + { + if ( !MoveTo( m, true, 1 ) ) + OnFailedMove(); + } + else if ( m_Mobile.InRange( m, m_Mobile.RangeFight - 1 ) ) + { + RunFrom( m ); + } + } + } + + public void RunFrom( Mobile m ) + { + Run( (m_Mobile.GetDirectionTo( m ) - 4) & Direction.Mask ); + } + + public void OnFailedMove() + { + if ( !m_Mobile.DisallowAllMoves && ScaleByMagery( TeleportChance ) > Utility.RandomDouble() ) + { + if ( m_Mobile.Target != null ) + m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled ); + + new TeleportSpell( m_Mobile, null ).Cast(); + + m_Mobile.DebugSay( "I am stuck, I'm going to try teleporting away" ); + } + else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + m_Mobile.DebugSay( "I am stuck" ); + } + } + + public void Run( Direction d ) + { + if ( (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.Paralyzed || m_Mobile.Frozen || m_Mobile.DisallowAllMoves ) + return; + + m_Mobile.Direction = d | Direction.Running; + + if ( !DoMove( m_Mobile.Direction, true ) ) + OnFailedMove(); + } + + + public virtual Spell GetRandomCurseSpell() + { + int necro = (int)((m_Mobile.Skills[SkillName.Necromancy].Value + 50.0) / (100.0 / 7.0)); + int mage = (int)((m_Mobile.Skills[SkillName.Magery].Value + 50.0) / (100.0 / 7.0)); + + if ( mage < 1 ) + mage = 1; + + if ( necro < 1 ) + necro = 1; + + if ( m_Mobile.Skills[SkillName.Necromancy].Value > 30 && Utility.Random( necro ) > Utility.Random( mage ) ) + { + switch ( Utility.Random( necro - 5 ) ) + { + case 0: case 1: return new CorpseSkinSpell( m_Mobile, null ); + case 2: case 3: return new MindRotSpell( m_Mobile, null ); + default: return new MindRotSpell( m_Mobile, null ); + } + } + + if ( Utility.RandomBool() && mage > 3 ) + return new CurseSpell( m_Mobile, null ); + + switch ( Utility.Random( 3 ) ) + { + default: + case 0: return new WeakenSpell( m_Mobile, null ); + case 1: return new ClumsySpell( m_Mobile, null ); + case 2: return new FeeblemindSpell( m_Mobile, null ); + } + } + + public virtual Spell GetRandomManaDrainSpell() + { + if ( Utility.RandomBool() ) + { + if ( m_Mobile.Skills[SkillName.Magery].Value >= 80.0 ) + return new ManaVampireSpell( m_Mobile, null ); + } + + return new ManaDrainSpell( m_Mobile, null ); + } + + public virtual Spell DoDispel( Mobile toDispel ) + { + if ( ScaleByMagery( DispelChance ) > Utility.RandomDouble() ) + return new DispelSpell( m_Mobile, null ); + + return ChooseSpell( toDispel ); + } + + public virtual Spell ChooseSpell( Mobile c ) + { + Spell spell = CheckCastHealingSpell(); + + if ( spell != null ) + return spell; + + double damage = ((m_Mobile.Skills[SkillName.SpiritSpeak].Value - c.Skills[SkillName.MagicResist].Value) / 10) + (c.Player ? 18 : 30); + + if ( damage > c.Hits ) + spell = new ManaDrainSpell( m_Mobile, null ); + + switch ( Utility.Random( 16 ) ) + { + case 0: + case 1: + case 2: // Poison them + { + m_Mobile.DebugSay( "Attempting to BloodOath" ); + + if ( !c.Poisoned ) + spell = new BloodOathSpell( m_Mobile, null ); + + break; + } + case 3: // Bless ourselves. + { + m_Mobile.DebugSay( "Blessing myself" ); + + spell = new BlessSpell( m_Mobile, null ); + break; + } + case 4: + case 5: + case 6: // Curse them. + { + m_Mobile.DebugSay( "Attempting to curse" ); + + spell = GetRandomCurseSpell(); + break; + } + case 7: // Paralyze them. + { + m_Mobile.DebugSay( "Attempting to paralyze" ); + + if ( m_Mobile.Skills[SkillName.Magery].Value > 50.0 ) + spell = new ParalyzeSpell( m_Mobile, null ); + + break; + } + case 8: // Drain mana + { + m_Mobile.DebugSay( "Attempting to drain mana" ); + + spell = GetRandomManaDrainSpell(); + break; + } + case 9: // Blood oath them + { + m_Mobile.DebugSay( "Attempting to blood oath" ); + + if ( m_Mobile.Skills[SkillName.Necromancy].Value > 30 && BloodOathSpell.GetBloodOath( c ) != m_Mobile ) + spell = new BloodOathSpell( m_Mobile, null ); + + break; + } + + } + + return spell; + } + + + + private TimeSpan GetDelay() + { + double del = ScaleByMagery( 3.0 ); + double min = 6.0 - (del * 0.75); + double max = 6.0 - (del * 1.25); + + return TimeSpan.FromSeconds( min + ((max - min) * Utility.RandomDouble()) ); + } + + public override bool DoActionCombat() + { + Mobile c = m_Mobile.Combatant; + m_Mobile.Warmode = true; + + if ( c == null || c.Deleted || !c.Alive || c.IsDeadBondedPet || !m_Mobile.CanSee( c ) || !m_Mobile.CanBeHarmful( c, false ) || c.Map != m_Mobile.Map ) + { + // Our combatant is deleted, dead, hidden, or we cannot hurt them + // Try to find another combatant + + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = c = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else + { + m_Mobile.DebugSay( "Something happened to my combatant, and nothing is around. I am on guard." ); + Action = ActionType.Guard; + return true; + } + } + + if ( !m_Mobile.InLOS( c ) ) + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = c = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + } + + if ( !m_Mobile.StunReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.Anatomy].Value >= 80.0 ) + EventSink.InvokeStunRequest( new StunRequestEventArgs( m_Mobile ) ); + + if ( !m_Mobile.InRange( c, m_Mobile.RangePerception ) ) + { + // They are somewhat far away, can we find something else? + + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if ( !m_Mobile.InRange( c, m_Mobile.RangePerception * 3 ) ) + { + m_Mobile.Combatant = null; + } + + c = m_Mobile.Combatant; + + if ( c == null ) + { + m_Mobile.DebugSay( "My combatant has fled, so I am on guard" ); + Action = ActionType.Guard; + + return true; + } + } + + if ( !m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon ) + { + if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 ) + { + // We are low on health, should we flee? + + bool flee = false; + + if ( m_Mobile.Hits < c.Hits ) + { + // We are more hurt than them + + int diff = c.Hits - m_Mobile.Hits; + + flee = ( Utility.Random( 0, 100 ) > (10 + diff) ); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random( 0, 100 ) > 10; // 10% chance to flee + } + + if ( flee ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I am going to flee from {0}", c.Name ); + + Action = ActionType.Flee; + return true; + } + } + } + + + + if ( m_Mobile.Spell == null && DateTime.Now > m_NextCastTime && m_Mobile.InRange( c, 12 ) ) + { + // We are ready to cast a spell + + Spell spell = null; + Mobile toDispel = FindDispelTarget( true ); + + if ( m_Mobile.Poisoned ) // Top cast priority is cure + { + m_Mobile.DebugSay( "I am going to cure myself" ); + + spell = new CureSpell( m_Mobile, null ); + } + else if ( toDispel != null ) // Something dispellable is attacking us + { + m_Mobile.DebugSay( "I am going to dispel {0}", toDispel ); + + spell = DoDispel( toDispel ); + } + + else if ( (c.Spell is HealSpell || c.Spell is GreaterHealSpell) && !c.Poisoned ) // They have a heal spell out + { + spell = new BloodOathSpell( m_Mobile, null ); + } + else + { + spell = ChooseSpell( c ); + } + + // Now we have a spell picked + // Move first before casting + + if ( toDispel != null ) + { + if ( m_Mobile.InRange( toDispel, 10 ) ) + RunFrom( toDispel ); + else if ( !m_Mobile.InRange( toDispel, 12 ) ) + RunTo( toDispel ); + } + else + { + RunTo( c ); + } + + if ( spell != null ) + spell.Cast(); + + TimeSpan delay; + + if ( spell is DispelSpell ) + delay = TimeSpan.FromSeconds( m_Mobile.ActiveSpeed ); + else + delay = GetDelay(); + + m_NextCastTime = DateTime.Now + delay; + } + else if ( m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting ) + { + RunTo( c ); + } + + return true; + } + + public override bool DoActionGuard() + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + if ( m_Mobile.Poisoned ) + { + new CureSpell( m_Mobile, null ).Cast(); + } + else if ( !m_Mobile.Summoned && ((ScaleByMagery( HealChance ) > Utility.RandomDouble())) ) + { + if ( m_Mobile.Hits < (m_Mobile.HitsMax - 50) ) + { + if ( !new GreaterHealSpell( m_Mobile, null ).Cast() ) + new HealSpell( m_Mobile, null ).Cast(); + } + else if ( m_Mobile.Hits < (m_Mobile.HitsMax - 10) ) + { + new HealSpell( m_Mobile, null ).Cast(); + } + else + { + base.DoActionGuard(); + } + } + else + { + base.DoActionGuard(); + } + } + + return true; + } + + public override bool DoActionFlee() + { + Mobile c = m_Mobile.Combatant; + + if ( (m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > (m_Mobile.HitsMax / 2) ) + { + m_Mobile.DebugSay( "I am stronger now, my guard is up" ); + Action = ActionType.Guard; + } + else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I am scared of {0}", m_Mobile.FocusMob.Name ); + + RunFrom( m_Mobile.FocusMob ); + m_Mobile.FocusMob = null; + + if ( m_Mobile.Poisoned && Utility.Random( 0, 5 ) == 0 ) + new CureSpell( m_Mobile, null ).Cast(); + } + else + { + m_Mobile.DebugSay( "Area seems clear, but my guard is up" ); + + Action = ActionType.Guard; + m_Mobile.Warmode = true; + } + + return true; + } + + public Mobile FindDispelTarget( bool activeOnly ) + { + if ( m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel( m_Mobile ) || m_Mobile.AutoDispel ) + return null; + + if ( activeOnly ) + { + List aggressed = m_Mobile.Aggressed; + List aggressors = m_Mobile.Aggressors; + + Mobile active = null; + double activePrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange( comb, 12 ) && CanDispel( comb ) ) + { + active = comb; + activePrio = m_Mobile.GetDistanceToSqrt( comb ); + + if ( activePrio <= 2 ) + return active; + } + + for ( int i = 0; i < aggressed.Count; ++i ) + { + AggressorInfo info = (AggressorInfo)aggressed[i]; + Mobile m = (Mobile)info.Defender; + + if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) ) + { + double prio = m_Mobile.GetDistanceToSqrt( m ); + + if ( active == null || prio < activePrio ) + { + active = m; + activePrio = prio; + + if ( activePrio <= 2 ) + return active; + } + } + } + + for ( int i = 0; i < aggressors.Count; ++i ) + { + AggressorInfo info = (AggressorInfo)aggressors[i]; + Mobile m = (Mobile)info.Attacker; + + if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) ) + { + double prio = m_Mobile.GetDistanceToSqrt( m ); + + if ( active == null || prio < activePrio ) + { + active = m; + activePrio = prio; + + if ( activePrio <= 2 ) + return active; + } + } + } + + return active; + } + else + { + Map map = m_Mobile.Map; + + if ( map != null ) + { + Mobile active = null, inactive = null; + double actPrio = 0.0, inactPrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel( comb ) ) + { + active = inactive = comb; + actPrio = inactPrio = m_Mobile.GetDistanceToSqrt( comb ); + } + + foreach ( Mobile m in m_Mobile.GetMobilesInRange( 12 ) ) + { + if ( m != m_Mobile && CanDispel( m ) ) + { + double prio = m_Mobile.GetDistanceToSqrt( m ); + + if ( !activeOnly && (inactive == null || prio < inactPrio) ) + { + inactive = m; + inactPrio = prio; + } + + if ( (m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio) ) + { + active = m; + actPrio = prio; + } + } + } + + return active != null ? active : inactive; + } + } + + return null; + } + + public bool CanDispel( Mobile m ) + { + return ( m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful( m, false ) && !((BaseCreature)m).IsAnimatedDead ); + } + + private static int[] m_Offsets = new int[] + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1, + + -2, -2, + -2, -1, + -2, 0, + -2, 1, + -2, 2, + -1, -2, + -1, 2, + 0, -2, + 0, 2, + 1, -2, + 1, 2, + 2, -2, + 2, -1, + 2, 0, + 2, 1, + 2, 2 + }; + + private void ProcessTarget( Target targ ) + { + bool isDispel = ( targ is DispelSpell.InternalTarget ); + bool isParalyze = ( targ is ParalyzeSpell.InternalTarget ); + bool isTeleport = ( targ is TeleportSpell.InternalTarget ); + bool teleportAway = false; + + Mobile toTarget; + + if ( isDispel ) + { + toTarget = FindDispelTarget( false ); + + if ( toTarget != null && m_Mobile.InRange( toTarget, 10 ) ) + RunFrom( toTarget ); + } + else if ( isParalyze || isTeleport ) + { + toTarget = FindDispelTarget( true ); + + if ( toTarget == null ) + { + toTarget = m_Mobile.Combatant; + + if ( toTarget != null ) + RunTo( toTarget ); + } + else if ( m_Mobile.InRange( toTarget, 10 ) ) + { + RunFrom( toTarget ); + teleportAway = true; + } + else + { + teleportAway = true; + } + } + else + { + toTarget = m_Mobile.Combatant; + + if ( toTarget != null ) + RunTo( toTarget ); + } + + if ( (targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null ) + { + if ( (targ.Range == -1 || m_Mobile.InRange( toTarget, targ.Range )) && m_Mobile.CanSee( toTarget ) && m_Mobile.InLOS( toTarget ) ) + { + targ.Invoke( m_Mobile, toTarget ); + } + else if ( isDispel ) + { + targ.Cancel( m_Mobile, TargetCancelType.Canceled ); + } + } + else if ( (targ.Flags & TargetFlags.Beneficial) != 0 ) + { + targ.Invoke( m_Mobile, m_Mobile ); + } + else if ( isTeleport && toTarget != null ) + { + Map map = m_Mobile.Map; + + if ( map == null ) + { + targ.Cancel( m_Mobile, TargetCancelType.Canceled ); + return; + } + + int px, py; + + if ( teleportAway ) + { + int rx = m_Mobile.X - toTarget.X; + int ry = m_Mobile.Y - toTarget.Y; + + double d = m_Mobile.GetDistanceToSqrt( toTarget ); + + px = toTarget.X + (int)(rx * (10 / d)); + py = toTarget.Y + (int)(ry * (10 / d)); + } + else + { + px = toTarget.X; + py = toTarget.Y; + } + + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = m_Offsets[i], y = m_Offsets[i + 1]; + + Point3D p = new Point3D( px + x, py + y, 0 ); + + LandTarget lt = new LandTarget( p, map ); + + if ( (targ.Range == -1 || m_Mobile.InRange( p, targ.Range )) && m_Mobile.InLOS( lt ) && map.CanSpawnMobile( px + x, py + y, lt.Z ) && !SpellHelper.CheckMulti( p, map ) ) + { + targ.Invoke( m_Mobile, lt ); + return; + } + } + + int teleRange = targ.Range; + + if ( teleRange < 0 ) + teleRange = 12; + + for ( int i = 0; i < 10; ++i ) + { + Point3D randomPoint = new Point3D( m_Mobile.X - teleRange + Utility.Random( teleRange * 2 + 1 ), m_Mobile.Y - teleRange + Utility.Random( teleRange * 2 + 1 ), 0 ); + + LandTarget lt = new LandTarget( randomPoint, map ); + + if ( m_Mobile.InLOS( lt ) && map.CanSpawnMobile( lt.X, lt.Y, lt.Z ) && !SpellHelper.CheckMulti( randomPoint, map ) ) + { + targ.Invoke( m_Mobile, new LandTarget( randomPoint, map ) ); + return; + } + } + + targ.Cancel( m_Mobile, TargetCancelType.Canceled ); + } + else + { + targ.Cancel( m_Mobile, TargetCancelType.Canceled ); + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/BaseHire.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/BaseHire.cs new file mode 100644 index 0000000..14d6008 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/BaseHire.cs @@ -0,0 +1,348 @@ +using System; +using Server; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using System.Collections.Generic; +using System.Collections; + +namespace Server.Mobiles +{ + public class BaseHire : BaseCreature + { + private int m_Pay = 1; + private bool m_IsHired; + private int m_HoldGold = 8; + private Timer m_PayTimer; + + public BaseHire( AIType AI ): base( AI, FightMode.Aggressor, 10, 1, 0.1, 4.0 ) + { + } + + public BaseHire(): base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.1, 4.0 ) + { + } + + public BaseHire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + + writer.Write( (bool)m_IsHired ); + writer.Write( (int)m_HoldGold ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_IsHired = reader.ReadBool(); + m_HoldGold = reader.ReadInt(); + + m_PayTimer = new PayTimer( this ); + m_PayTimer.Start(); + } + + private static Hashtable m_HireTable = new Hashtable(); + + public static Hashtable HireTable + { + get{ return m_HireTable;} + } + + public override bool KeepsItemsOnDeath{ get{ return true;}} + + private int m_GoldOnDeath = 0; + + public override bool OnBeforeDeath() + { + // Stop the pay timer if its running + if( m_PayTimer != null ) + m_PayTimer.Stop(); + + m_PayTimer = null; + + // Get all of the gold on the hireling and add up the total amount + if( this.Backpack != null ) + { + Item[] AllGold = this.Backpack.FindItemsByType( typeof(Gold), true ); + if( AllGold != null ) + { + foreach( Gold g in AllGold ) + this.m_GoldOnDeath += g.Amount; + } + } + + return base.OnBeforeDeath(); + } + + public override void OnDeath( Container c ) + { + if( this.m_GoldOnDeath > 0 ) + c.DropItem( new Gold( this.m_GoldOnDeath ) ); + + base.OnDeath( c ); + } + + [CommandProperty( AccessLevel.Player )] + public bool IsHired + { + get + { + return m_IsHired; + } + set + { + if ( m_IsHired== value ) + return; + + m_IsHired= value; + Delta( MobileDelta.Noto ); + InvalidateProperties(); + } + } + + #region [ GetOwner ] + public virtual Mobile GetOwner() + { + if( !Controlled ) + return null; + Mobile Owner = ControlMaster; + + m_IsHired = true; + + if( Owner == null ) + return null; + + if( Owner.Deleted || Owner.Map != this.Map || !Owner.InRange( Location, 30 ) ) + { + Say( 1005653 );// Hmmm. I seem to have lost my master. + BaseHire.HireTable.Remove( Owner ); + SetControlMaster( null ); + return null; + } + + return Owner; + } + #endregion + + #region [ AddHire ] + public virtual bool AddHire( Mobile m ) + { + Mobile owner = GetOwner(); + + if( owner != null ) + { + m.SendLocalizedMessage( 1043283, owner.Name );// I am following ~1_NAME~. + return false; + } + + if( SetControlMaster( m ) ) + { + m_IsHired = true; + return true; + } + + return false; + } + #endregion + + #region [ Payday ] + public virtual bool Payday( BaseHire m ) + { + m_Pay = (int)m.Skills[SkillName.Anatomy].Value + (int)m.Skills[SkillName.Tactics].Value; + m_Pay += (int)m.Skills[SkillName.Macing].Value + (int)m.Skills[SkillName.Swords].Value; + m_Pay += (int)m.Skills[SkillName.Fencing].Value + (int)m.Skills[SkillName.Archery].Value; + m_Pay += (int)m.Skills[SkillName.MagicResist].Value + (int)m.Skills[SkillName.Healing].Value; + m_Pay += (int)m.Skills[SkillName.Magery].Value + (int)m.Skills[SkillName.Parry].Value; + m_Pay /= 35; + m_Pay += 1; + return true; + } + #endregion + + #region [ OnDragDrop ] + public override bool OnDragDrop( Mobile from, Item item ) + { + if( m_Pay != 0 ) + { + // Is the creature already hired + if( Controlled == false ) + { + // Is the item the payment in gold + if( item is Gold ) + { + // Is the payment in gold sufficient + if( item.Amount >= m_Pay ) + { + // Check if this mobile already has a hire + BaseHire hire = (BaseHire)m_HireTable[from]; + + if( hire != null && !hire.Deleted && hire.GetOwner() == from ) + { + SayTo( from, 500896 );// I see you already have an escort. + return false; + } + + // Try to add the hireling as a follower + if( AddHire(from) == true ) + { + SayTo( from, 1043258, string.Format( "{0}", (int)item.Amount / m_Pay ) );//"I thank thee for paying me. I will work for thee for ~1_NUMBER~ days.", (int)item.Amount / m_Pay ); + m_HireTable[from] = this; + m_HoldGold += item.Amount; + m_PayTimer = new PayTimer( this ); + m_PayTimer.Start(); + return true; + } + + else + { + return false; + } + } + + else + { + this.SayHireCost(); + } + + } + + else + { + SayTo( from, 1043268 );// Tis crass of me, but I want gold + } + } + + else + { + Say( 1042495 );// I have already been hired. + } + } + + else + { + SayTo( from, 500200 );// I have no need for that. + } + + return base.OnDragDrop( from, item ); + } + #endregion + + + #region [ OnSpeech ] + internal void SayHireCost() + { + Say( 1043256, string.Format( "{0}", m_Pay ) );// "I am available for hire for ~1_AMOUNT~ gold coins a day. If thou dost give me gold, I will work for thee." + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if( !e.Handled && e.Mobile.InRange( this, 6 ) ) + { + int[] keywords = e.Keywords; + string speech = e.Speech; + + // Check for a greeting, a 'hire', or a 'servant' + if( ( e.HasKeyword( 0x003B ) == true ) || ( e.HasKeyword( 0x0162 ) == true ) || ( e.HasKeyword( 0x000C ) == true ) ) + { + if( Controlled == false ) + { + e.Handled = Payday( this ); + this.SayHireCost(); + } + else + { + this.Say( 1042495 );// I have already been hired. + } + } + } + + base.OnSpeech( e ); + } + #endregion + + #region [ GetContextMenuEntries ] + public override void GetContextMenuEntries( Mobile from, List list ) + { + BaseAI m_AI = new MeleeAI(this); + + if ( this.Deleted ) + return; + + if ( CanPaperdollBeOpenedBy( from ) ) + list.Add( new PaperdollEntry( this ) ); + + if ( from == this && Backpack != null && CanSee( Backpack ) && CheckAlive( false ) ) + list.Add( new OpenBackpackEntry( this ) ); + + if( Controlled == false ) + list.Add( new HireEntry( from, this ) ); + + if( Controlled == true ) // OSI has a custom MenuEntries for Hireling, with Dismiss instead of Release (see BaseAI changes) + m_AI.GetContextMenuEntries( from, list ); + } + + #endregion + + #region [ Class PayTimer ] + private class PayTimer : Timer + { + private BaseHire m_Hire; + + public PayTimer( BaseHire vend ) : base( TimeSpan.FromMinutes( 30.0 ), TimeSpan.FromMinutes( 30.0 ) ) + { + m_Hire = vend; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + int m_Pay = m_Hire.m_Pay; + if( m_Hire.m_HoldGold <= m_Pay ) + { + // Get the current owner, if any (updates HireTable) + Mobile owner = m_Hire.GetOwner(); + + m_Hire.Say( 503235 );// I regret nothing!postal + m_Hire.Delete(); + } + + else + { + m_Hire.m_HoldGold -= m_Pay; + } + } + } + #endregion + + #region [ Class HireEntry ] + public class HireEntry : ContextMenuEntry + { + private Mobile m_Mobile; + private BaseHire m_Hire; + + public HireEntry( Mobile from, BaseHire hire ) : base( 6120, 3 ) + { + m_Hire = hire; + m_Mobile = from; + } + + public override void OnClick() + { + m_Hire.Payday(m_Hire); + m_Hire.SayHireCost(); + } + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBard.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBard.cs new file mode 100644 index 0000000..455ef9d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBard.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireBard : BaseHire + { + [Constructable] + public HireBard() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + + switch ( Utility.Random ( 2 ) ) + { + case 0: AddItem( new Skirt ( Utility.RandomDyedHue() ) );break; + case 1: AddItem( new Kilt ( Utility.RandomNeutralHue() ) );break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the bard"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 16, 16 ); + SetDex( 26, 26 ); + SetInt( 26, 26 ); + + SetDamage( 5, 10 ); + + SetSkill( SkillName.Tactics, 35, 57 ); + SetSkill( SkillName.Magery, 22, 22 ); + SetSkill( SkillName.Swords, 45, 67 ); + SetSkill( SkillName.Archery, 36, 67 ); + SetSkill( SkillName.Parry, 45, 60 ); + SetSkill( SkillName.Musicianship, 66.0, 97.5 ); + SetSkill( SkillName.Peacemaking, 65.0, 87.5 ); + + Fame = 100; + Karma = 100; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomDyedHue() ) );break; + case 1: AddItem( new Shirt( Utility.RandomDyedHue() ) );break; + } + switch ( Utility.Random( 4 ) ) + { + case 0: PackItem( new Harp() );break; + case 1: PackItem( new Lute() );break; + case 2: PackItem( new Drums() );break; + case 3: PackItem( new Tambourine() );break; + } + + AddItem( new Longsword() ); + PackItem( new Bow() ); + PackItem( new Arrow(100) ); + PackGold( 10, 50 ); + } + public override bool ClickTitle{get{return false;}} + public HireBard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBardArcher.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBardArcher.cs new file mode 100644 index 0000000..2e3b94e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBardArcher.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireBardArcher : BaseHire + { + [Constructable] + public HireBardArcher() : base( AIType.AI_Archer ) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + + switch ( Utility.Random ( 2 ) ) + { + case 0: AddItem( new Skirt ( Utility.RandomDyedHue() ) );break; + case 1: AddItem( new Kilt ( Utility.RandomNeutralHue() ) );break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the bard"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 16, 16 ); + SetDex( 26, 26 ); + SetInt( 26, 26 ); + + SetDamage( 5, 10 ); + + SetSkill( SkillName.Tactics, 35, 57 ); + SetSkill( SkillName.Magery, 22, 22 ); + SetSkill( SkillName.Swords, 45, 67 ); + SetSkill( SkillName.Archery, 36, 67 ); + SetSkill( SkillName.Parry, 45, 60 ); + SetSkill( SkillName.Musicianship, 66.0, 97.5 ); + SetSkill( SkillName.Peacemaking, 65.0, 87.5 ); + + Fame = 100; + Karma = 100; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomDyedHue() ) );break; + case 1: AddItem( new Shirt( Utility.RandomDyedHue() ) );break; + } + switch ( Utility.Random( 4 ) ) + { + case 0: PackItem( new Harp() );break; + case 1: PackItem( new Lute() );break; + case 2: PackItem( new Drums() );break; + case 3: PackItem( new Tambourine() );break; + } + + PackItem( new Longsword() ); + AddItem( new Bow() ); + PackItem( new Arrow(100) ); + PackGold( 10, 50 ); + } + public override bool ClickTitle{get{return false;}} + public HireBardArcher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBeggar.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBeggar.cs new file mode 100644 index 0000000..f396618 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireBeggar.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireBeggar : BaseHire + { + [Constructable] + public HireBeggar() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + + switch ( Utility.Random ( 2 ) ) + { + case 0: AddItem( new Skirt ( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Kilt ( Utility.RandomNeutralHue() ) );break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the beggar"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 26, 26 ); + SetDex( 21, 21 ); + SetInt( 36, 36 ); + + SetDamage( 1, 1 ); + + SetSkill( SkillName.Begging, 66, 97 ); + SetSkill( SkillName.Tactics, 5, 27 ); + SetSkill( SkillName.Wrestling, 5, 27 ); + SetSkill( SkillName.Magery, 2, 2 ); + + Fame = 0; + Karma = 0; + + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Shirt( Utility.RandomNeutralHue() ) );break; + } + + PackGold( 0, 25 ); + } + public override bool ClickTitle{get{return false;}} + public HireBeggar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireFighter.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireFighter.cs new file mode 100644 index 0000000..d550754 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireFighter.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireFighter : BaseHire + { + [Constructable] + public HireFighter() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the fighter"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 40, 100 ); + SetDex( 30, 99 ); + SetInt( 40, 49 ); + + SetDamage( 7, 14 ); + + SetSkill( SkillName.Tactics, 36, 67 ); + SetSkill( SkillName.Magery, 22, 22 ); + SetSkill( SkillName.Swords, 64, 100 ); + SetSkill( SkillName.Parry, 60, 82 ); + SetSkill( SkillName.Macing, 36, 67 ); + SetSkill( SkillName.Focus, 36, 67 ); + SetSkill( SkillName.Wrestling, 25, 47 ); + + Fame = 100; + Karma = 100; + + switch ( Utility.Random( 2 )) + { + case 0: AddItem( new Shoes( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Boots( Utility.RandomNeutralHue() ) );break; + } + + AddItem( new Shirt()); + + // Pick a random sword + switch ( Utility.Random( 5 )) + { + case 0: AddItem( new Longsword() );break; + case 1: AddItem( new Broadsword() );break; + case 2: AddItem( new VikingSword() );break; + case 3: AddItem( new BattleAxe() );break; + case 4: AddItem( new TwoHandedAxe() );break; + } + + // Pick a random shield + switch ( Utility.Random( 8 )) + { + case 0: AddItem( new BronzeShield() );break; + case 1: AddItem( new HeaterShield() );break; + case 2: AddItem( new MetalKiteShield() );break; + case 3: AddItem( new MetalShield() );break; + case 4: AddItem( new WoodenKiteShield() );break; + case 5: AddItem( new WoodenShield() );break; + case 6: AddItem( new OrderShield() );break; + case 7: AddItem( new ChaosShield() );break; + } + + switch( Utility.Random( 5 ) ) + { + case 0: break; + case 1: AddItem( new Bascinet() );break; + case 2: AddItem( new CloseHelm() );break; + case 3: AddItem( new NorseHelm() );break; + case 4: AddItem( new Helmet() );break; + + } + // Pick some armour + switch( Utility.Random( 4 ) ) + { + case 0: // Leather + AddItem( new LeatherChest() ); + AddItem( new LeatherArms() ); + AddItem( new LeatherGloves() ); + AddItem( new LeatherGorget() ); + AddItem( new LeatherLegs() ); + break; + + case 1: // Studded Leather + AddItem( new StuddedChest() ); + AddItem( new StuddedArms() ); + AddItem( new StuddedGloves() ); + AddItem( new StuddedGorget() ); + AddItem( new StuddedLegs() ); + break; + + case 2: // Ringmail + AddItem( new RingmailChest() ); + AddItem( new RingmailArms() ); + AddItem( new RingmailGloves() ); + AddItem( new RingmailLegs() ); + break; + + case 3: // Chain + AddItem( new ChainChest() ); + AddItem( new ChainCoif() ); + AddItem( new ChainLegs() ); + break; + } + + PackGold( 25, 100 ); + } + + public override bool ClickTitle{get{return false;}} + + public HireFighter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireMage.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireMage.cs new file mode 100644 index 0000000..d046c79 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireMage.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireMage : BaseHire + { + [Constructable] + public HireMage() : base( AIType.AI_Mage ) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + Title = "the mage"; + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 61, 75 ); + SetDex( 81, 95 ); + SetInt( 86, 100 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.EvalInt, 100.0, 125 ); + SetSkill( SkillName.Magery, 100, 125 ); + SetSkill( SkillName.Meditation, 100, 125 ); + SetSkill( SkillName.MagicResist, 100, 125 ); + SetSkill( SkillName.Tactics, 100, 125 ); + SetSkill( SkillName.Macing, 100, 125 ); + + Fame = 100; + Karma = 100; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Shirt()); + + AddItem( new Robe( Utility.RandomNeutralHue() ) ); + AddItem( new ThighBoots() ); + + + PackGold( 20, 100 ); + } + public override bool ClickTitle{get{return false;}} + public HireMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HirePaladin.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HirePaladin.cs new file mode 100644 index 0000000..6553ad8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HirePaladin.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HirePaladin : BaseHire + { + [Constructable] + public HirePaladin() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the paladin"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + switch( Utility.Random( 5 ) ) + { + case 0: break; + case 1: AddItem( new Bascinet() );break; + case 2: AddItem( new CloseHelm() );break; + case 3: AddItem( new NorseHelm() );break; + case 4: AddItem( new Helmet() );break; + } + + SetStr( 86, 100 ); + SetDex( 81, 95 ); + SetInt( 61, 75 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Swords, 66.0, 97.5 ); + SetSkill( SkillName.Anatomy, 65.0, 87.5 ); + SetSkill( SkillName.MagicResist, 25.0, 47.5 ); + SetSkill( SkillName.Healing, 65.0, 87.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 15.0, 37.5 ); + SetSkill( SkillName.Parry, 45.0, 60.5 ); + SetSkill( SkillName.Chivalry, 85, 100 ); + + Fame = 100; + Karma = 250; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Shirt()); + AddItem( new VikingSword() ); + AddItem( new MetalKiteShield () ); + + + AddItem( new PlateChest() ); + AddItem( new PlateLegs() ); + AddItem( new PlateArms() ); + AddItem( new LeatherGorget() ); + PackGold( 20, 100 ); + + } + public override bool ClickTitle{get{return false;}} + + public HirePaladin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HirePeasant.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HirePeasant.cs new file mode 100644 index 0000000..45aed87 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HirePeasant.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HirePeasant : BaseHire + { + [Constructable] + public HirePeasant() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + + switch ( Utility.Random ( 2 ) ) + { + case 0: AddItem( new Skirt ( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Kilt ( Utility.RandomNeutralHue() ) );break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the peasant"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + AddItem( new Katana() ); + + SetStr( 26, 26 ); + SetDex( 21, 21 ); + SetInt( 16, 16 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Tactics, 5, 27 ); + SetSkill( SkillName.Wrestling, 5, 5 ); + SetSkill( SkillName.Swords, 5, 27 ); + + Fame = 0; + Karma = 0; + + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Shirt( Utility.RandomNeutralHue() ) );break; + } + + PackGold( 0, 25 ); + } + public override bool ClickTitle{get{return false;}} + public HirePeasant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireRanger.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireRanger.cs new file mode 100644 index 0000000..4766a93 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireRanger.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireRanger : BaseHire + { + [Constructable] + public HireRanger() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the ranger"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 91, 91 ); + SetDex( 76, 76 ); + SetInt( 61, 61 ); + + SetDamage( 13, 24 ); + + SetSkill( SkillName.Wrestling, 15, 37 ); + SetSkill( SkillName.Parry, 45, 60 ); + SetSkill( SkillName.Archery, 66, 97 ); + SetSkill( SkillName.Magery, 62, 62 ); + SetSkill( SkillName.Swords, 35, 57 ); + SetSkill( SkillName.Fencing, 15, 37 ); + SetSkill( SkillName.Tactics, 65, 87 ); + + Fame = 100; + Karma = 125; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Shirt()); + + // Pick a random sword + switch ( Utility.Random( 3 )) + { + case 0: AddItem( new Longsword() );break; + case 1: AddItem( new VikingSword() );break; + case 2: AddItem( new Broadsword() );break; + } + + AddItem( new RangerChest() ); + AddItem( new RangerArms() ); + AddItem( new RangerGloves() ); + AddItem( new RangerGorget() ); + AddItem( new RangerLegs() ); + + PackItem ( new Arrow( 20 ) ); + PackGold( 10, 75 ); + } + public override bool ClickTitle{get{return false;}} + public HireRanger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireRangerArcher.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireRangerArcher.cs new file mode 100644 index 0000000..65eded8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireRangerArcher.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireRangerArcher : BaseHire + { + [Constructable] + public HireRangerArcher() : base( AIType.AI_Archer ) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the ranger"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 91, 91 ); + SetDex( 76, 76 ); + SetInt( 61, 61 ); + + SetDamage( 13, 24 ); + + SetSkill( SkillName.Wrestling, 15, 37 ); + SetSkill( SkillName.Parry, 45, 60 ); + SetSkill( SkillName.Archery, 66, 97 ); + SetSkill( SkillName.Magery, 62, 62 ); + SetSkill( SkillName.Swords, 35, 57 ); + SetSkill( SkillName.Fencing, 15, 37 ); + SetSkill( SkillName.Tactics, 65, 87 ); + + Fame = 100; + Karma = 125; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Shirt()); + + // Pick a random sword + switch ( Utility.Random( 2 )) + { + case 0: AddItem( new Bow() );break; + case 1: AddItem( new CompositeBow() );break; + } + + AddItem( new RangerChest() ); + AddItem( new RangerArms() ); + AddItem( new RangerGloves() ); + AddItem( new RangerGorget() ); + AddItem( new RangerLegs() ); + + PackItem ( new Arrow( 20 ) ); + PackGold( 10, 75 ); + } + public override bool ClickTitle{get{return false;}} + public HireRangerArcher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireSailor.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireSailor.cs new file mode 100644 index 0000000..149ea24 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireSailor.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireSailor : BaseHire + { + [Constructable] + public HireSailor() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the sailor"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 86 ); + SetDex( 66 ); + SetInt( 41 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Stealing, 66.0, 97.5 ); + SetSkill( SkillName.Peacemaking, 65.0, 87.5 ); + SetSkill( SkillName.MagicResist, 25.0, 47.5 ); + SetSkill( SkillName.Healing, 65.0, 87.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Fencing, 65.0, 87.5 ); + SetSkill( SkillName.Parry, 45.0, 60.5 ); + SetSkill( SkillName.Lockpicking, 65, 87 ); + SetSkill( SkillName.Hiding, 65, 87 ); + SetSkill( SkillName.Snooping, 65, 87 ); + Fame = 100; + Karma = 0; + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Cutlass() ); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomDyedHue() ) );break; + case 1: AddItem( new Shirt( Utility.RandomDyedHue() ) );break; + } + + PackGold( 0, 25 ); + } + public override bool ClickTitle{get{return false;}} + public HireSailor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireThief.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireThief.cs new file mode 100644 index 0000000..0aa33d4 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Hireables/HireThief.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class HireThief : BaseHire + { + [Constructable] + public HireThief() + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + + switch ( Utility.Random ( 2 ) ) + { + case 0: AddItem( new Skirt ( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Kilt ( Utility.RandomNeutralHue() ) );break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + Title = "the thief"; + HairItemID = Race.RandomHair( Female ); + HairHue = Race.RandomHairHue(); + Race.RandomFacialHair( this ); + + SetStr( 81, 95 ); + SetDex( 86, 100 ); + SetInt( 61, 75 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Stealing, 66.0, 97.5 ); + SetSkill( SkillName.Peacemaking, 65.0, 87.5 ); + SetSkill( SkillName.MagicResist, 25.0, 47.5 ); + SetSkill( SkillName.Healing, 65.0, 87.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Fencing, 65.0, 87.5 ); + SetSkill( SkillName.Parry, 45.0, 60.5 ); + SetSkill( SkillName.Lockpicking, 65, 87 ); + SetSkill( SkillName.Hiding, 65, 87 ); + SetSkill( SkillName.Snooping, 65, 87 ); + Fame = 100; + Karma = 0; + + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + AddItem( new Dagger() ); + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomNeutralHue() ) );break; + case 1: AddItem( new Shirt( Utility.RandomNeutralHue() ) );break; + } + + PackGold( 0, 25 ); + } + public override bool ClickTitle{get{return false;}} + public HireThief( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );// version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Monsters/AOS/Sphynx.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Monsters/AOS/Sphynx.cs new file mode 100644 index 0000000..bd1f670 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Monsters/AOS/Sphynx.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.ContextMenus; +using Server.Gumps; + +namespace Server.Mobiles +{ + [CorpseName( "a sphynx corpse" )] + public class Sphynx : BaseCreature + { + [Constructable] + public Sphynx() : base( AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Body = 788; + Name = "Sphynx"; + + SetStr( 1001, 1200 ); + SetDex( 176, 195 ); + SetInt( 301, 400 ); + SetHits( 1001, 1200 ); + SetDamage( 10, 15 ); + SetMana( 301, 400 ); + + SetDamageType( ResistanceType.Physical, 85 ); + SetDamageType( ResistanceType.Energy, 15 ); + + SetResistance( ResistanceType.Physical, 60, 80 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Wrestling, 90.1, 100 ); + SetSkill( SkillName.Tactics, 90.1, 100 ); + SetSkill( SkillName.MagicResist, 100.5, 150 ); + SetSkill( SkillName.Anatomy, 25.1, 50 ); + SetSkill( SkillName.Magery, 95.5, 100 ); + SetSkill( SkillName.EvalInt, 90.1, 100 ); + SetSkill( SkillName.Meditation, 95.1, 120 ); + + VirtualArmor = 78; + Fame = 15000; + Karma = 0; + + PackGold( 845, 1250 ); + } + + public override void GenerateLoot() + { + //AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Regular; } } +/* + public override void GetContextMenuEntries( Mobile from, List list ) + { + list.Add( new FortuneEntry( from ) ); + } + + public class FortuneEntry : ContextMenuEntry + { + private Mobile m_Mobile; + + public FortuneEntry( Mobile from ) : base( 6199, 8 ) + { + m_Mobile = from; + } + + public override void OnClick() + { + m_Mobile.SendGump( new FortuneGump( m_Mobile ) ); + } + } +*/ + public Sphynx( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Monsters/Humanoid/Magic/Spellbinder.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Monsters/Humanoid/Magic/Spellbinder.cs new file mode 100644 index 0000000..00b0acd --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Monsters/Humanoid/Magic/Spellbinder.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class Spellbinder : BaseCreature + { + [Constructable] + public Spellbinder() : base( AIType.AI_Spellbinder, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Spectral Spellbinder"; + Body = 153; + BaseSoundID = 0x482; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + SetMana(100 ); + + SetDamage( 0, 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + SetSkill( SkillName.Magery, 70.0, 80.0 ); + SetSkill( SkillName.Meditation, 100.0, 120.0 ); + SetSkill( SkillName.Necromancy, 100.0, 120.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 28; + + PackItem( Loot.RandomWeapon() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + + public Spellbinder( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/New/Mobiles/Townfolk/EscortableWanderingHealer.cs b/Scripts/Customs/Nerun's Distro/New/Mobiles/Townfolk/EscortableWanderingHealer.cs new file mode 100644 index 0000000..9f00706 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/New/Mobiles/Townfolk/EscortableWanderingHealer.cs @@ -0,0 +1,61 @@ +//By Nerun +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class EscortableWanderingHealer : BaseEscortable + { + [Constructable] + public EscortableWanderingHealer() + { + Title = "the wandering healer"; + + AddItem( new GnarledStaff() ); + + SetSkill( SkillName.Tactics, 82.0, 100.0 ); + SetSkill( SkillName.MagicResist, 82.0, 100.0 ); + SetSkill( SkillName.Anatomy, 75.0, 97.5 ); + SetSkill( SkillName.Magery, 82.0, 100.0 ); + SetSkill( SkillName.EvalInt, 82.0, 100.0 ); + } + + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display title in OnSingleClick + + public virtual int GetRobeColor() + { + return Utility.RandomYellowHue(); + } + + public override void InitOutfit() + { + AddItem( new Robe( GetRobeColor() ) ); + AddItem( new Sandals() ); + + Utility.AssignRandomHair( this ); + + PackGold( 50, 100 ); + } + + public EscortableWanderingHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Commands/DecorateSA.cs b/Scripts/Customs/Nerun's Distro/SA/Commands/DecorateSA.cs new file mode 100644 index 0000000..b85cb19 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Commands/DecorateSA.cs @@ -0,0 +1,31 @@ +using System; +using Server; +using System.IO; +using Server.Commands; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server +{ + public static class StygianAbyss + { + public static void Initialize() + { + CommandSystem.Register( "DecorateSA", AccessLevel.Administrator, new CommandEventHandler( DecorateSA_OnCommand ) ); + } + + [Usage( "DecorateSA" )] + [Description( "Generates Stygian Abyss world decoration." )] + private static void DecorateSA_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Generating Stygian Abyss world decoration, please wait." ); + + Decorate.Generate( "Data/Decoration/Stygian Abyss/Ter Mur", Map.TerMur ); + Decorate.Generate( "Data/Decoration/Stygian Abyss/Trammel", Map.Trammel ); + Decorate.Generate( "Data/Decoration/Stygian Abyss/Felucca", Map.Felucca ); + + e.Mobile.SendMessage( "Stygian Abyss world generation complete." ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/AcidSac.cs b/Scripts/Customs/Nerun's Distro/SA/Items/AcidSac.cs new file mode 100644 index 0000000..1d81d51 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/AcidSac.cs @@ -0,0 +1,110 @@ +using System; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class AcidSac : Item + { + public override int LabelNumber{ get{ return 1111654; } } // acid sac + + [Constructable] + public AcidSac() : base(0x0C67) + { + Stackable = true; + Weight = 1.0; + Hue = 648; + } + + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(1111656); // What do you wish to use the acid on? + + from.Target = new InternalTarget(this); + } + + private class InternalTarget : Target + { + private Item m_Item; + private Item wall; + private Item wallandvine; + + public InternalTarget(Item item) : base(2, false, TargetFlags.None) + { + m_Item = item; + } + + protected override void OnTarget(Mobile from, object targeted) + { + PlayerMobile pm = from as PlayerMobile; + + if (m_Item.Deleted) + return; + + if(targeted is AddonComponent) + { + AddonComponent addoncomponent = (AddonComponent)targeted; + + if ( addoncomponent is MagicVinesComponent || addoncomponent is StoneWallComponent || addoncomponent is DungeonWallComponent ) + { + int Xs = addoncomponent.X; + + if ( addoncomponent is MagicVinesComponent ) + Xs += -1; + + if ( addoncomponent.Addon is StoneWallAndVineAddon ) + { + wall = new SecretStoneWallNS(); + wallandvine = new StoneWallAndVineAddon(); + } + else if ( addoncomponent.Addon is DungeonWallAndVineAddon ) + { + wall = new SecretDungeonWallNS(); + wallandvine = new DungeonWallAndVineAddon(); + } + + wall.MoveToWorld( new Point3D( Xs, addoncomponent.Y, addoncomponent.Z ), addoncomponent.Map); + + addoncomponent.Delete(); + + m_Item.Consume(); + + wall.PublicOverheadMessage(0, 1358, 1111662); // The acid quickly burns through the writhing wallvines, revealing the strange wall. + + Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), delegate() + { + wallandvine.MoveToWorld( wall.Location, wall.Map); + + wall.Delete(); + wallandvine.PublicOverheadMessage(0, 1358, 1111663); // The vines recover from the acid and, spreading like tentacles, reclaim their grip over the wall. + } ); + } + } + else + { + from.SendLocalizedMessage(1111657); // The acid swiftly burn through it. + m_Item.Consume(); + return; // Exit the method, because addoncomponent is null + } + } + } + + public AcidSac( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/Addons/DungeonWallAndVineAddon.cs b/Scripts/Customs/Nerun's Distro/SA/Items/Addons/DungeonWallAndVineAddon.cs new file mode 100644 index 0000000..ef95cd6 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/Addons/DungeonWallAndVineAddon.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class DungeonWallAndVineAddon : BaseAddon + { + [ Constructable ] + public DungeonWallAndVineAddon() + { + AddComponent( new MagicVinesComponent(), 1, 0, 0 ); + AddComponent( new DungeonWallComponent(), 0, 0, 0 ); + } + + public DungeonWallAndVineAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class DungeonWallComponent : AddonComponent + { + [Constructable] + public DungeonWallComponent() : base( 0x0242 ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if( from.X > this.X ) + { + from.SendLocalizedMessage(1111659); // You try to examine the strange wall but the vines get in your way. + } + else + { + this.Z += -22; + Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), delegate() + { + this.Z += 22; + } ); + } + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Parent == null && Utility.InRange( Location, m.Location, 3 ) && !Utility.InRange( Location, oldLocation, 3 ) && m is PlayerMobile ) + { + if ( m.X > this.X ) + m.SendLocalizedMessage(1111665); // You notice something odd about the vines covering the wall. + } + } + + public DungeonWallComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/Addons/StoneWallAndVineAddon.cs b/Scripts/Customs/Nerun's Distro/SA/Items/Addons/StoneWallAndVineAddon.cs new file mode 100644 index 0000000..3271875 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/Addons/StoneWallAndVineAddon.cs @@ -0,0 +1,116 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class StoneWallAndVineAddon : BaseAddon + { + [ Constructable ] + public StoneWallAndVineAddon() + { + AddComponent( new MagicVinesComponent(), 1, 0, 0 ); + AddComponent( new StoneWallComponent(), 0, 0, 0 ); + } + + public StoneWallAndVineAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class StoneWallComponent : AddonComponent + { + [Constructable] + public StoneWallComponent() : base( 0x03C9 ) + { + Hue = 744; + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if( from.X > this.X ) + { + from.SendLocalizedMessage(1111659); // You try to examine the strange wall but the vines get in your way. + } + else + { + this.Z += -22; + Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), delegate() + { + this.Z += 22; + } ); + } + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Parent == null && Utility.InRange( Location, m.Location, 3 ) && !Utility.InRange( Location, oldLocation, 3 ) && m is PlayerMobile ) + { + if ( m.X > this.X ) + m.SendLocalizedMessage(1111665); // You notice something odd about the vines covering the wall. + } + } + + public StoneWallComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MagicVinesComponent : AddonComponent + { + [Constructable] + public MagicVinesComponent() : base( 0x0CF1 ) + { + Name = "magic vines"; + Movable = false; + } + + public MagicVinesComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/Construction/BaseSwitch.cs b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/BaseSwitch.cs new file mode 100644 index 0000000..86545b8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/BaseSwitch.cs @@ -0,0 +1,143 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class BaseSwitch : Item + { + private int m_TurnOn; + private int m_TurnOff; + private int m_LocMessageA; + private int m_LocMessageB; + private bool m_Used; + private bool m_Working; + + [Constructable] + public BaseSwitch( int TurnOff, int TurnOn, int LocMessageA, int LocMessageB, bool Working ) : base( TurnOff ) + { + Movable = false; + m_TurnOn = TurnOn; + m_TurnOff = TurnOff; + m_LocMessageA = LocMessageA; + m_LocMessageB = LocMessageB; + m_Used = false; + m_Working = Working; + } + + [Constructable] + public BaseSwitch( int TurnOff, int TurnOn ) : base( TurnOff ) + { + Movable = false; + m_TurnOn = TurnOn; + m_TurnOff = TurnOff; + m_LocMessageA = 0; + m_LocMessageB = 0; + m_Used = false; + m_Working = false; + } + + public override void OnDoubleClick( Mobile m ) + { + if ( !m.InRange( this, 2 ) ) + { + m.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + else + { + + int MessageA = 0; + + if ( this.m_LocMessageA == 0 ) + MessageA = 500357 + Utility.Random( 5 ); + else + MessageA = this.m_LocMessageA; + + int MessageB = 0; + + if ( this.m_LocMessageB == 0 ) + MessageB = 500357 + Utility.Random( 5 ); + else + MessageB = this.m_LocMessageB; + + /* + 500357 - If this lever ever did anything, it doesn't do it anymore. + 500358 - The lever feels loose, and you realize it no longer controls anything. + 500359 - You flip the lever and think you hear something, but realize it was just your imagination. + 500360 - The lever flips without effort, doing nothing. + */ + + if ( this.ItemID == this.m_TurnOff && this.m_Used == false ) + { + this.ItemID = this.m_TurnOn; + this.m_Used = true; + Effects.PlaySound( this.Location, this.Map, 0x3E8 ); + + m.LocalOverheadMessage( MessageType.Regular, 0, MessageA ); //Message received when it is turned on by first time. + + //This call to another method to do something special, so you don't need + //to override OnDoubleClick and rewrite this section again. + if ( this.m_Working == true ) + { + DoSomethingSpecial(m); + } + + //Refresh time of two minutes, equal to RunUO's RaiseSwith + Timer.DelayCall( TimeSpan.FromMinutes( 2.0 ), delegate() + { + this.ItemID = this.m_TurnOff; + this.m_Used = false; + } ); + } + else if ( this.ItemID == this.m_TurnOff && this.m_Used == true ) + { + this.ItemID = this.m_TurnOn; + Effects.PlaySound( this.Location, this.Map, 0x3E8 ); + m.LocalOverheadMessage( MessageType.Regular, 0, MessageB); //Message received after click it again until the refresh. + } + else //TurnOn and m_Used true + { + this.ItemID = this.m_TurnOff; + Effects.PlaySound( this.Location, this.Map, 0x3E8 ); + m.LocalOverheadMessage( MessageType.Regular, 0, MessageB); //Message received after click it again until the refresh. + } + } + } + + public virtual void DoSomethingSpecial( Mobile from ) + { + from.LocalOverheadMessage( MessageType.Regular, 0, 1116629 ); //It does Nothing! + } + + public BaseSwitch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( m_TurnOn ); + writer.Write( m_TurnOff ); + writer.Write( m_LocMessageA ); + writer.Write( m_LocMessageB ); + writer.Write( m_Working ); + writer.Write( m_Used ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_TurnOn = reader.ReadInt(); + m_TurnOff = reader.ReadInt(); + m_LocMessageA = reader.ReadInt(); + m_LocMessageB = reader.ReadInt(); + m_Working = reader.ReadBool(); + m_Used = reader.ReadBool(); + this.m_Used = false; + this.ItemID = this.m_TurnOff; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Switches.cs b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Switches.cs new file mode 100644 index 0000000..496e252 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Switches.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class UnderworldSwitchWE : BaseSwitch + { + [Constructable] + public UnderworldSwitchWE() : base( 0x1091, 0x1092, 1042901, 1042900, true ) + { + //1042901 = You hear a deep rumbling as something seems to happen. + //1042900 = There seems to be no further effect right now. + //true = It do something, it is not useless or broken switch. + } + + public override void DoSomethingSpecial( Mobile from ) + { + foreach ( Item item in GetItemsInRange( 8 ) ) + { + if ( item.ItemID == 0x3660 && item.Hue == 1000 ) //Dark Globe of Sosaria + { + Timer m_timerA = new MoveTimer( item, 1 ); + m_timerA.Start(); + } + } + } + + private class MoveTimer : Timer + { + private Item item; + private int num; + private int m_Stage; + private int m_Cicle; + + public MoveTimer( Item sphere, int coord ) : base( TimeSpan.FromSeconds( 0.0 ), TimeSpan.FromSeconds( 1.5 ) ) + { + item = sphere; + num = coord; + } + + protected override void OnTick() + { + if ( item.Deleted ) + { + Stop(); + return; + } + + m_Stage++; + + if ( m_Cicle == 0 ) + item.Z += 1; + else if ( m_Cicle == 1 ) + item.Z += 0; + else + item.Z += -1; + + if ( m_Stage == 8 ) + m_Cicle++; + else if ( m_Stage == 14 ) + m_Cicle++; + else if ( m_Stage == 22 ) + Stop(); + } + } + + public UnderworldSwitchWE( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Walls/BaseSliding.cs b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Walls/BaseSliding.cs new file mode 100644 index 0000000..b6b685e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Walls/BaseSliding.cs @@ -0,0 +1,54 @@ +using System; + +namespace Server.Items +{ + public class BaseSliding : Item + { + private int m_OpenedID; + private int m_ClosedID; + + [Constructable] + public BaseSliding( int closedID, int openedID ) : base( closedID ) + { + Movable = false; + m_OpenedID = openedID; + m_ClosedID = closedID; + } + + public override void OnDoubleClick( Mobile from ) + { + this.ItemID = this.m_OpenedID; + Timer.DelayCall( TimeSpan.FromSeconds( 1.6 ), delegate() + { + this.Z += -22; + this.Visible = false; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), delegate() + { + this.ItemID = this.m_ClosedID; + this.Visible = true; + this.Z += 22; + } ); + } ); + } + + public BaseSliding( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( m_OpenedID ); + writer.Write( m_ClosedID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_OpenedID = reader.ReadInt(); + m_ClosedID = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Walls/SecretSlidingWalls.cs b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Walls/SecretSlidingWalls.cs new file mode 100644 index 0000000..fb7ef0b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/Construction/Walls/SecretSlidingWalls.cs @@ -0,0 +1,86 @@ +using System; + +namespace Server.Items +{ + public class SecretShadowWallNS : BaseSliding + { + [Constructable] + public SecretShadowWallNS() : base( 0x363A, 0x3619 ) + { + Name = "secret door"; + } + + public SecretShadowWallNS( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretDungeonWallNS : BaseSliding + { + [Constructable] + public SecretDungeonWallNS() : base( 0x0242, 0x0244 ) + { + Name = "secret door"; + } + + public SecretDungeonWallNS( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretStoneWallNS : BaseSliding + { + [Constructable] + public SecretStoneWallNS() : base( 0x3C9, 0x3CA ) + { + Name = "secret door"; + Hue = 744; + } + + public SecretStoneWallNS( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Items/VialOfVitriol.cs b/Scripts/Customs/Nerun's Distro/SA/Items/VialOfVitriol.cs new file mode 100644 index 0000000..f35d7db --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Items/VialOfVitriol.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Items +{ + public class VialOfVitriol : Item + { + public override int LabelNumber{ get{ return 1113331; } } // vial of vitriol + + [Constructable] + public VialOfVitriol() : base(0x5722) + { + } + + public VialOfVitriol( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Coral Snake.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Coral Snake.cs new file mode 100644 index 0000000..e8eee61 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Coral Snake.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a snake corpse" )] + public class CoralSnake : BaseCreature + { + [Constructable] + public CoralSnake() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a coral snake"; + Body = 52; + Hue = 41; + BaseSoundID = 0xDB; + + SetStr( 205 ); + SetDex( 248 ); + SetInt( 28 ); + + SetHits( 132 ); + SetMana( 28 ); + + SetDamage( 5, 21 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 42 ); + SetResistance( ResistanceType.Fire, 5 ); + SetResistance( ResistanceType.Cold, 5 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 5 ); + + SetSkill( SkillName.Poisoning, 99.7 ); + SetSkill( SkillName.MagicResist, 98.1 ); + SetSkill( SkillName.Tactics, 82.0 ); + SetSkill( SkillName.Wrestling, 90.3 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 16; + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Eggs; } } + + public CoralSnake(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Daemons/FireDaemon.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Daemons/FireDaemon.cs new file mode 100644 index 0000000..56437c6 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Daemons/FireDaemon.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an fire daemon corpse" )] + public class FireDaemon : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ConcussionBlow; + } + + [Constructable] + public FireDaemon() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an fire daemon"; + Body = 0x310; + BaseSoundID = 0x47D; + + SetStr( 549, 1199 ); + SetDex( 136, 206 ); + SetInt( 202, 336 ); + + SetHits( 1111, 1478 ); + + SetDamage( 22, 29 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 48, 93 ); + SetResistance( ResistanceType.Fire, 60, 100 ); + SetResistance( ResistanceType.Cold, -8, 57 ); + SetResistance( ResistanceType.Poison, 30, 100 ); + SetResistance( ResistanceType.Energy, 37, 50 ); + + SetSkill( SkillName.MagicResist, 98.1, 132.6 ); + SetSkill( SkillName.Tactics, 86.9, 95.5 ); + SetSkill( SkillName.Wrestling, 42.2, 98.8 ); + SetSkill( SkillName.Magery, 97.1, 100.8 ); + SetSkill( SkillName.EvalInt, 91.1, 91.8 ); + SetSkill( SkillName.Meditation, 45.4, 94.1 ); + + Fame = 7000; + Karma = -10000; + + VirtualArmor = 55; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + + public FireDaemon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Daemons/Pit Fiend.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Daemons/Pit Fiend.cs new file mode 100644 index 0000000..7bc698d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Daemons/Pit Fiend.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a PitFiend corpse" )] + public class PitFiend : BaseCreature + { + [Constructable] + public PitFiend () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a pit fiend"; + Body = 40; + Hue = 1136; + BaseSoundID = 357; + + SetStr( 382 ); + SetDex( 178 ); + SetInt( 212 ); + + SetHits( 237 ); + + SetDamage( 8, 19 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 65 ); + SetResistance( ResistanceType.Fire, 10 ); + SetResistance( ResistanceType.Cold, 69 ); + SetResistance( ResistanceType.Poison, 24 ); + SetResistance( ResistanceType.Energy, 38 ); + + SetSkill( SkillName.Anatomy, 25.1, 50.0 ); + SetSkill( SkillName.EvalInt, 112.2 ); + SetSkill( SkillName.Magery, 105.5 ); + SetSkill( SkillName.Meditation, 8.5 ); + SetSkill( SkillName.MagicResist, 107.0 ); + SetSkill( SkillName.Tactics, 108.9 ); + SetSkill( SkillName.Wrestling, 105.2 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 90; + + PackItem( new Longsword() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 5; } } + public override int Meat{ get{ return 1; } } + + public PitFiend( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/FireAnt.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/FireAnt.cs new file mode 100644 index 0000000..43d9533 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/FireAnt.cs @@ -0,0 +1,67 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a fire ant corpse" )] + public class FireAnt : BaseCreature + { + [Constructable] + public FireAnt() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fire ant"; + Body = 738; + + SetStr( 225 ); + SetDex( 108 ); + SetInt( 25 ); + + SetHits( 299 ); + + SetDamage( 15, 18 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Fire, 60 ); + + SetResistance( ResistanceType.Physical, 52 ); + SetResistance( ResistanceType.Fire, 96 ); + SetResistance( ResistanceType.Cold, 36 ); + SetResistance( ResistanceType.Poison, 40 ); + SetResistance( ResistanceType.Energy, 36 ); + + SetSkill( SkillName.Anatomy, 8.7 ); + SetSkill( SkillName.MagicResist, 53.1 ); + SetSkill( SkillName.Tactics, 77.2 ); + SetSkill( SkillName.Wrestling, 75.4 ); + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override int GetIdleSound() { return 846; } + public override int GetAngerSound() { return 849; } + public override int GetHurtSound() { return 852; } + public override int GetDeathSound() { return 850; } + + public FireAnt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/LavaElemental.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/LavaElemental.cs new file mode 100644 index 0000000..773c311 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/LavaElemental.cs @@ -0,0 +1,77 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a lava elemental corpse" )] + public class LavaElemental : BaseCreature + { + [Constructable] + public LavaElemental() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a lava elemental"; + Body = 720; + + SetStr( 446, 510 ); + SetDex( 173, 191 ); + SetInt( 369, 397 ); + + SetHits( 260, 266 ); + + SetDamage( 12, 18 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Fire, 90 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 0.0, 12.8 ); + SetSkill( SkillName.EvalInt, 84.8, 92.6 ); + SetSkill( SkillName.Magery, 90.1, 92.7 ); + SetSkill( SkillName.Meditation, 97.8, 102.8 ); + SetSkill( SkillName.MagicResist, 101.9, 106.2 ); + SetSkill( SkillName.Tactics, 80.3, 94.0 ); + SetSkill( SkillName.Wrestling, 71.7, 85.4 ); + + PackItem( new LesserPoisonPotion() ); + PackReg( 9 ); + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + AddLoot( LootPack.Gems, 2 ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + + public override int GetIdleSound() { return 1549; } + public override int GetAngerSound() { return 1546; } + public override int GetHurtSound() { return 1548; } + public override int GetDeathSound() { return 1547; } + + public LavaElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Leather Wolf.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Leather Wolf.cs new file mode 100644 index 0000000..5b8b2ed --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Leather Wolf.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a leather wolf corpse" )] + public class LeatherWolf : BaseCreature + { + [Constructable] + public LeatherWolf() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a leather wolf"; + Body = 739; + Hue = 2213;//guessing + BaseSoundID = 0xE5; + + SetStr( 102 ); + SetDex( 120 ); + SetInt( 34 ); + + SetHits( 180 ); + SetMana( 20 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 20.1, 35.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = false; + ControlSlots = 1; + MinTameSkill = 0.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public LeatherWolf(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/MaddeningHorror.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/MaddeningHorror.cs new file mode 100644 index 0000000..211b879 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/MaddeningHorror.cs @@ -0,0 +1,65 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a maddening horror corpse" )] + public class MaddeningHorror : BaseCreature + { + [Constructable] + public MaddeningHorror() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a maddening horror"; + Body = 721; + + SetStr( 285 ); + SetDex( 80 ); + SetInt( 17 ); + + SetHits( 330 ); + + SetDamage( 15, 27 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 40 ); + SetDamageType( ResistanceType.Energy, 40 ); + + SetResistance( ResistanceType.Physical, 55 ); + SetResistance( ResistanceType.Fire, 29 ); + SetResistance( ResistanceType.Cold, 50 ); + SetResistance( ResistanceType.Poison, 41 ); + SetResistance( ResistanceType.Energy, 57 ); + + SetSkill( SkillName.EvalInt, 125.9 ); + SetSkill( SkillName.Magery, 120.4 ); + SetSkill( SkillName.Meditation, 100.8 ); + SetSkill( SkillName.MagicResist, 185.5 ); + SetSkill( SkillName.Tactics, 94.0 ); + SetSkill( SkillName.Wrestling, 87.4 ); + + } + + public override int GetIdleSound() { return 1553; } + public override int GetAngerSound() { return 1550; } + public override int GetHurtSound() { return 1552; } + public override int GetDeathSound() { return 1551; } + + public MaddeningHorror( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Raptor.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Raptor.cs new file mode 100644 index 0000000..2d003f6 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Raptor.cs @@ -0,0 +1,72 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a raptor corpse" )] + public class Raptor : BaseCreature + { + [Constructable] + public Raptor() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a raptor"; + Body = 730; + + SetStr( 407, 455 ); + SetDex( 139, 153 ); + SetInt( 104, 135 ); + + SetHits( 347, 392 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 50 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 75.5, 89.0 ); + SetSkill( SkillName.Tactics, 80.3, 93.8 ); + SetSkill( SkillName.Wrestling, 66.9, 81.5 ); + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 65.1; + } + + public override int Meat{ get{ return 7; } } + public override int Hides{ get{ return 11; } } + public override HideType HideType{ get{ return HideType.Horned; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + } + + public override int GetIdleSound() { return 1573; } + public override int GetAngerSound() { return 1570; } + public override int GetHurtSound() { return 1572; } + public override int GetDeathSound() { return 1571; } + + public Raptor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanChitterAssistant.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanChitterAssistant.cs new file mode 100644 index 0000000..c0793a4 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanChitterAssistant.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman archer corpse" )] + public class ClanChitterAssistant : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public ClanChitterAssistant() : base( AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = ( "Clan Chitter Assistant" ); + Body = 0x8E; + BaseSoundID = 437; + + SetStr( 146, 180 ); + SetDex( 101, 130 ); + SetInt( 116, 140 ); + + SetHits( 120, 150 ); + SetMana( 120, 140 ); + SetStam( 100, 130 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 60.2, 100.0 ); + SetSkill( SkillName.Archery, 80.1, 90.0 ); + SetSkill( SkillName.MagicResist, 65.1, 90.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 56; + + AddItem( new Bow() ); + PackItem( new Arrow( Utility.RandomMinMax( 50, 70 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 9; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public ClanChitterAssistant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Body == 42 ) + { + Body = 0x8E; + Hue = 0; + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanChitterTinkerer.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanChitterTinkerer.cs new file mode 100644 index 0000000..bda3c23 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanChitterTinkerer.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman archer corpse" )] + public class ClanChitterTinkerer : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public ClanChitterTinkerer() : base( AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = ( "Clan Chitter Tinkerer" ); + Body = 0x8E; + BaseSoundID = 437; + + SetStr( 300, 330 ); + SetDex( 220, 240 ); + SetInt( 240, 280 ); + + SetHits( 2000, 2100 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 30 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 35, 50 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 60.2, 100.0 ); + SetSkill( SkillName.Archery, 80.1, 90.0 ); + SetSkill( SkillName.MagicResist, 65.1, 90.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 56; + + AddItem( new Bow() ); + PackItem( new Arrow( Utility.RandomMinMax( 50, 70 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 9; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public ClanChitterTinkerer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Body == 42 ) + { + Body = 0x8E; + Hue = 0; + } + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonCourtier.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonCourtier.cs new file mode 100644 index 0000000..0ccc35c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonCourtier.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman's corpse" )] + public class ClanRibbonCourtier : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public ClanRibbonCourtier() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = ( "Clan Ribbon Courtier" ); + Body = 42; + BaseSoundID = 437; + + SetStr( 220, 250 ); + SetDex( 240, 260 ); + SetInt( 100, 150 ); + + SetHits( 2000, 2100 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 100.1, 120.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 1500; + Karma = -1500; + + Hue = 258; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon, misc + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 9; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public ClanRibbonCourtier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonPlagueRat.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonPlagueRat.cs new file mode 100644 index 0000000..4f8f18a --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonPlagueRat.cs @@ -0,0 +1,75 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a rat corpse" )] + public class ClanRibbonPlagueRat : BaseCreature + { + [Constructable] + public ClanRibbonPlagueRat() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Clan Ribbon Plague Rat"; + Body = 238; + BaseSoundID = 0xCC; + + SetStr( 59 ); + SetDex( 51 ); + SetInt( 17 ); + + SetHits( 92 ); + SetStam( 51 ); + + SetDamage( 4, 8 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 30.0 ); + SetSkill( SkillName.Tactics, 34.0 ); + SetSkill( SkillName.Wrestling, 40.0 ); + + Fame = 150; + Karma = -150; + + VirtualArmor = 6; + + Hue = 52; + + Tamable = false; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.GrainsAndHay; } } + + public ClanRibbonPlagueRat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonSupplicant.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonSupplicant.cs new file mode 100644 index 0000000..ff4cc49 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanRibbonSupplicant.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman's corpse" )] + public class ClanRibbonSupplicant : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public ClanRibbonSupplicant() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = ( "Clan Ribbon Supplicant" ); + Body = 42; + BaseSoundID = 437; + + SetStr( 170, 180 ); + SetDex( 100, 120 ); + SetInt( 200, 210 ); + + SetHits( 120, 140 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Cold, 20 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 20, 35 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 50.1, 80.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 1500; + Karma = -1500; + + Hue = 558; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon, misc + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public ClanRibbonSupplicant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchHenchrat.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchHenchrat.cs new file mode 100644 index 0000000..c102b3f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchHenchrat.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman's corpse" )] + public class ClanScratchHenchrat : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public ClanScratchHenchrat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = ( "Clan Scratch Henchrat" ); + Body = 42; + BaseSoundID = 437; + + SetStr( 200, 230 ); + SetDex( 181, 191 ); + SetInt( 80, 100 ); + + SetHits( 2000, 2100 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 35.1, 60.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + SetSkill( SkillName.Anatomy, 50.1, 75.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon, misc + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public ClanScratchHenchrat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchSavageWolf.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchSavageWolf.cs new file mode 100644 index 0000000..7743bcc --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchSavageWolf.cs @@ -0,0 +1,78 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a wolf corpse" )] + [TypeAlias( "Server.Mobiles.ClanScratchSavageWolf" )] + public class ClanScratchSavageWolf : BaseCreature + { + [Constructable] + public ClanScratchSavageWolf() : base( AIType.AI_Melee,FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Clan Scratch Savage Wolf"; + Body = 23; + BaseSoundID = 0xE5; + + SetStr( 150, 180 ); + SetDex( 230, 250 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + SetStam( 230, 250 ); + SetMana( 35, 60 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 35 ); + SetResistance( ResistanceType.Fire, 30, 45 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 25 ); + + SetSkill( SkillName.MagicResist, 40.6, 60.0 ); + SetSkill( SkillName.Tactics, 40.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 22; + + Hue = 1172; + + Tamable = false; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 7; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public ClanScratchSavageWolf(Serial serial) : base(serial) + { + } + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchScrounger.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchScrounger.cs new file mode 100644 index 0000000..a1710f4 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/ClanScratchScrounger.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman's corpse" )] + public class ClanScratchScrounger : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public ClanScratchScrounger() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = ( "Clan Scratch Scrounger" ); + Body = 42; + BaseSoundID = 437; + + SetStr( 120, 140 ); + SetDex( 81, 100 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + SetStam( 81, 100 ); + SetMana( 36, 60 ); + + SetDamage( 4, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 35.1, 60.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + SetSkill( SkillName.Anatomy, 50.1, 75.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon, misc + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public ClanScratchScrounger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/Clockwork Scorpion.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/Clockwork Scorpion.cs new file mode 100644 index 0000000..442dec2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/RatMan Clan/Clockwork Scorpion.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a clockwork scorpion corpse" )] + public class ClockworkScorpion : BaseCreature + { + [Constructable] + public ClockworkScorpion() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a clockwork scorpion"; + Body = 717; + BaseSoundID = 397; + + SetStr( 233 ); + SetDex( 90 ); + SetInt( 31 ); + + SetHits( 78 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 83 ); + SetResistance( ResistanceType.Fire, 24 ); + SetResistance( ResistanceType.Cold, 66 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 13 ); + + SetSkill( SkillName.Poisoning, 99.1 ); + SetSkill( SkillName.MagicResist, 31.6 ); + SetSkill( SkillName.Tactics, 70.1 ); + SetSkill( SkillName.Wrestling, 57.4 ); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 28; + + Tamable = false; + ControlSlots = 1; + MinTameSkill = 47.1; + + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Arachnid; } } + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override Poison HitPoison{ get{ return (0.8 >= Utility.RandomDouble() ? Poison.Greater : Poison.Deadly); } } + + public ClockworkScorpion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/SAPixie.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/SAPixie.cs new file mode 100644 index 0000000..5acf53a --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/SAPixie.cs @@ -0,0 +1,93 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a pixie corpse" )] + public class SAPixie : BaseCreature + { + public override bool InitialInnocent{ get{ return true; } } + + [Constructable] + public SAPixie() : base( AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "pixie" ); + Body = 128; + BaseSoundID = 0x467; + + SetStr( 21, 30 ); + SetDex( 301, 400 ); + SetInt( 201, 250 ); + + SetHits( 13, 18 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 10.1, 20.0 ); + SetSkill( SkillName.Wrestling, 10.1, 12.5 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 100; + if ( 0.02 > Utility.RandomDouble() ) + PackStatue(); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + #region Mondain's Legacy +// if ( Utility.RandomDouble() < 0.3 ) +// c.DropItem( new PixieLeg() ); + #endregion + } + + public override void GenerateLoot() + { + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Gems, 2 ); + } + + public override HideType HideType{ get{ return HideType.Spined; } } + public override int Hides{ get{ return 5; } } + public override int Meat{ get{ return 1; } } + + public SAPixie( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Skeletal Lich.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Skeletal Lich.cs new file mode 100644 index 0000000..07e6051 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Skeletal Lich.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal corpse" )] + public class SkeletalLich : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public SkeletalLich() : base( AIType.AI_Spellbinder, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a skeletal lich"; + Body = 309; + Hue = 1345; + BaseSoundID = 0x48D; + + SetStr( 301, 350 ); + SetDex( 75 ); + SetInt( 151, 200 ); + + SetHits( 1200 ); + SetStam( 150 ); + SetMana( 0 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 70 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.EvalInt, 127.2 ); + SetSkill( SkillName.Magery, 127.2 ); + SetSkill( SkillName.Necromancy, 100.0, 120.0 ); + SetSkill( SkillName.MagicResist, 187.1 ); + SetSkill( SkillName.Tactics, 91.7 ); + SetSkill( SkillName.Wrestling, 98.5 ); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public SkeletalLich( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Skree.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Skree.cs new file mode 100644 index 0000000..7b36577 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Skree.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a skree corpse" )] + public class Skree : BaseCreature + { + [Constructable] + public Skree() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a skree"; + Body = 733; + + SetStr( 305, 330 ); + SetDex( 114, 119 ); + SetInt( 191, 260 ); + + SetHits( 228, 310 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 45, 55 ); + SetResistance( ResistanceType.Cold, 25, 40 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 26, 40 ); + + SetSkill( SkillName.EvalInt, 90.8, 99.7 ); + SetSkill( SkillName.Magery, 100.0, 115.0 ); + SetSkill( SkillName.Meditation, 69.7, 73.7 ); + SetSkill( SkillName.MagicResist, 75.3, 82.6 ); + SetSkill( SkillName.Tactics, 20.1, 24.2 ); + SetSkill( SkillName.Wrestling, 22.9, 32.7 ); + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 95.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override int Meat{ get{ return 3; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override int Hides{ get{ return 6; } } + + public override int GetIdleSound() { return 1585; } + public override int GetAngerSound() { return 1582; } + public override int GetHurtSound() { return 1584; } + public override int GetDeathSound() { return 1583; } + + public Skree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Slith.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Slith.cs new file mode 100644 index 0000000..c41cb45 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Slith.cs @@ -0,0 +1,66 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a slith corpse" )] + public class Slith : BaseCreature + { + [Constructable] + public Slith() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a slith"; + Body = 734; + + SetStr( 129, 136 ); + SetDex( 72, 75 ); + SetInt( 12, 13 ); + + SetHits( 84, 85 ); + + SetDamage( 6, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 59.1, 63.5 ); + SetSkill( SkillName.Tactics, 74.6, 76.4 ); + SetSkill( SkillName.Wrestling, 62.0, 77.1 ); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 80.7; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 6; } } + public override int Hides{ get{ return 10; } } + + public Slith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Stone Slith.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Stone Slith.cs new file mode 100644 index 0000000..d2ae9ca --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Stone Slith.cs @@ -0,0 +1,67 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a stone slith corpse" )] + public class StoneSlith : BaseCreature + { + [Constructable] + public StoneSlith() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Stone Slith"; + Body = 734; + Hue = 2500;//guessing here + + SetStr( 273 ); + SetDex( 72, 75 ); + SetInt( 80 ); + + SetHits( 161 ); + + SetDamage( 6, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 59.1, 63.5 ); + SetSkill( SkillName.Tactics, 74.6, 76.4 ); + SetSkill( SkillName.Wrestling, 62.0, 77.1 ); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 65.7; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 6; } } + public override int Hides{ get{ return 10; } } + + public StoneSlith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Toxic Slith.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Toxic Slith.cs new file mode 100644 index 0000000..59c699e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Abyss/Toxic Slith.cs @@ -0,0 +1,64 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a toxic slith corpse" )] + public class ToxicSlith : BaseCreature + { + [Constructable] + public ToxicSlith() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a toxic slith"; + Body = 734; + Hue = 81; + + SetStr( 223, 306 ); + SetDex( 231, 258 ); + SetInt( 30, 35 ); + + SetHits( 197, 215 ); + + SetDamage( 6, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 5, 9 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 5, 7 ); + + SetSkill( SkillName.MagicResist, 95.4, 98.3 ); + SetSkill( SkillName.Tactics, 85.5, 90.9 ); + SetSkill( SkillName.Wrestling, 90.4, 95.1 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override int Meat{ get{ return 6; } } + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Horned; } } + + public ToxicSlith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/Medusa.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/Medusa.cs new file mode 100644 index 0000000..0645f22 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/Medusa.cs @@ -0,0 +1,74 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a medusa corpse" )] + public class Medusa : BaseCreature + { + [Constructable] + public Medusa() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Medusa"; + Body = 728; + + SetStr( 1378, 1442 ); + SetDex( 129, 143 ); + SetInt( 575, 671 ); + + SetHits( 50000, 55000 ); + SetStam( 129, 143 ); + SetMana( 575, 671 ); + + SetDamage( 21, 28 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 55, 65 ); + SetResistance( ResistanceType.Cold, 55, 65 ); + SetResistance( ResistanceType.Poison, 70, 90 ); + SetResistance( ResistanceType.Energy, 65, 75 ); + + SetSkill( SkillName.Anatomy, 111.5, 117.9 ); + SetSkill( SkillName.EvalInt, 103.1, 128.5 ); + SetSkill( SkillName.Magery, 114.7, 120.8 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Tactics, 124.8, 130.5 ); + SetSkill( SkillName.Wrestling, 119.7, 122.9 ); + } + + public override int GetIdleSound() { return 1557; } + public override int GetAngerSound() { return 1554; } + public override int GetHurtSound() { return 1556; } + public override int GetDeathSound() { return 1555; } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 2 ); + AddLoot( LootPack.UltraRich, 2 ); + AddLoot( LootPack.FilthyRich, 3 ); + } + + public Medusa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/SlasherOfVeils.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/SlasherOfVeils.cs new file mode 100644 index 0000000..865819b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/SlasherOfVeils.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a slasher of veils corpse" )] + public class SlasherOfVeils : BaseCreature + { + [Constructable] + public SlasherOfVeils() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "The Slasher of Veils"; + Body = 741; + + SetStr( 949, 1039 ); + SetDex( 133, 142 ); + SetInt( 1041, 1256 ); + + SetHits( 100000, 150000 ); + SetStam( 133, 142 ); + SetMana( 480, 500 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 66, 77 ); + SetResistance( ResistanceType.Fire, 70, 78 ); + SetResistance( ResistanceType.Cold, 77, 80 ); + SetResistance( ResistanceType.Poison, 72, 75 ); + SetResistance( ResistanceType.Energy, 76, 78 ); + + SetSkill( SkillName.Anatomy, 113.9, 125.0 ); + SetSkill( SkillName.EvalInt, 111.1, 123.5 ); + SetSkill( SkillName.Magery, 115.3, 119 ); + SetSkill( SkillName.Meditation, 118.2, 127.8 ); + SetSkill( SkillName.MagicResist, 125.7, 188.7 ); + SetSkill( SkillName.Tactics, 124.0, 126.8 ); + SetSkill( SkillName.Wrestling, 118.2, 124.0 ); + } + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 1 ); + AddLoot( LootPack.UltraRich, 2 ); + AddLoot( LootPack.FilthyRich, 3 ); + } + + public override int GetIdleSound() { return 1589; } + public override int GetAngerSound() { return 1586; } + public override int GetHurtSound() { return 1588; } + public override int GetDeathSound() { return 1587; } + + public SlasherOfVeils( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/StygianDragon.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/StygianDragon.cs new file mode 100644 index 0000000..4faa2d2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/Peerless/StygianDragon.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.Spells; +using Server.Spells.Fourth; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class StygianDragon : BaseCreature + { + public override bool AlwaysMurderer { get { return true; } } + + [Constructable] + public StygianDragon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5 ) + { + Name = "a stygian dragon"; + Body = 826; + BaseSoundID = 362; + + SetStr( 494, 595 ); + SetDex( 239, 345 ); + SetInt( 108, 230 ); + + SetHits( 150000, 200000 ); + SetStam( 468, 486 ); + SetMana( 108, 236 ); + + SetDamage( 33, 55 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 35 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 84, 90 ); + SetResistance( ResistanceType.Fire, 81, 88 ); + SetResistance( ResistanceType.Cold, 66, 69 ); + SetResistance( ResistanceType.Poison, 89, 88 ); + SetResistance( ResistanceType.Energy, 80, 84 ); + + + SetSkill( SkillName.Anatomy, 114.3, 123.8 ); + SetSkill( SkillName.MagicResist, 122.2, 126.8 ); + SetSkill( SkillName.Tactics, 113.9, 116.1 ); + SetSkill( SkillName.Wrestling, 113.4, 117.2 ); + + Fame = 55000; + Karma = -55000; + + VirtualArmor = 60; + + Tamable = false; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 4 ); + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Meager ); + } + + public override bool Unprovokable { get { return true; } } + public override bool BardImmune { get { return true; } } + //public override bool GivesMinorArtifact { get { return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override bool AutoDispel{ get{ return !Controlled; } } + public override int TreasureMapLevel{ get{ return 5; } } + //public override int DragonBlood{ get{ return 48; } } + public override int Meat{ get{ return 19; } } + public override int Hides{ get{ return 44; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override int Scales{ get{ return 7; } } + public override ScaleType ScaleType{ get{ return ( Body == 12 ? ScaleType.Yellow : ScaleType.Red ); } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public override WeaponAbility GetWeaponAbility() + { + if (50.0 >= Utility.RandomDouble()) + return WeaponAbility.Bladeweave; + else + return WeaponAbility.TalonStrike; + + } + /* + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + if (0.2 >= Utility.RandomDouble()) + CrimsonMeteor(Mobile from, int damage); + } + + public static void CrimsonMeteor( Mobile from, int damage ) + { + if ( !CanUse( from ) ) + return; + + new CrimsonMeteorTimer( from, damage ).Start(); + } + + public class CrimsonMeteorTimer : Timer + { + private Mobile m_From; + private int m_Damage; + private int m_Count; + private int m_MaxCount; + private Point3D m_LastTarget; + private Point3D m_ShowerLocation; + + public CrimsonMeteorTimer( Mobile from, int damage ) : base( TimeSpan.FromMilliseconds( 500.0 ), TimeSpan.FromMilliseconds( 500.0 ) ) + { + m_From = from; + m_Damage = damage; + m_Count = 0; + m_MaxCount = 30; + m_LastTarget = new Point3D( 0, 0, 0 ); + m_ShowerLocation = new Point3D( from.Location ); + } + + protected override void OnTick() + { + if ( m_From == null ) + { + Stop(); + return; + } + + new FireField( m_From, 30, m_Damage, m_Damage, Utility.RandomBool(), m_LastTarget, m_From.Map ); + + if ( m_Count >= m_MaxCount ) + { + Stop(); + return; + } + + Point3D point = new Point3D(); + int tries = 0; + + while ( tries < 5 ) + { + point.X = m_ShowerLocation.X += Utility.RandomMinMax( -5, 5 ); + point.Y = m_ShowerLocation.Y += Utility.RandomMinMax( -5, 5 ); + + if ( m_From.CanSee( point ) ) + break; + + tries++; + } + + Effects.SendMovingParticles( + new Entity( Serial.Zero, new Point3D( point.X, point.Y, point.Z + 30 ), m_From.Map ), + new Entity( Serial.Zero, point, m_From.Map ), + 0x36D4, 5, 0, false, false, 0, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + + m_LastTarget = point; + m_Count++; + } + }*/ + + public StygianDragon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + } + } + /* + #region FireField + public class FireField : Item + { + private Mobile m_Owner; + private int m_MinDamage; + private int m_MaxDamage; + private DateTime m_Destroy; + private Point3D m_MoveToPoint; + private Map m_MoveToMap; + private Timer m_Timer; + private List m_List; + + [Constructable] + public FireField( int duration, int min, int max, bool south, Point3D point, Map map ) : this( null, duration, min, max, south, point, map ) + { + } + + [Constructable] + public FireField( Mobile owner, int duration, int min, int max, bool south, Point3D point, Map map ) : base( GetItemID( south ) ) + { + Movable = false; + + m_Owner = owner; + m_MinDamage = min; + m_MaxDamage = max; + m_Destroy = DateTime.Now + TimeSpan.FromSeconds( (double)duration + 1.5 ); + m_MoveToPoint = point; + m_MoveToMap = map; + m_List = new List(); + m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1 ), new TimerCallback( OnTick ) ); + Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1.5 ), new TimerCallback( Move ) ); + } + + private static int GetItemID( bool south ) + { + if ( south ) + return 0x398C; + else + return 0x3996; + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private void Move() + { + if ( !Visible ) + ItemID = 0x36FE; + + MoveToWorld( m_MoveToPoint, m_MoveToMap ); + } + + private void OnTick() + { + if ( DateTime.Now > m_Destroy ) + Delete(); + else if ( m_MinDamage != 0 ) + { + foreach( Mobile m in GetMobilesInRange( 0 ) ) + { + if ( m == null ) + continue; + else if ( m_Owner != null ) + { + if ( Ability.CanTarget( m_Owner, m, true, true, false ) ) + m_List.Add( m ); + } + else + m_List.Add( m ); + } + + for ( int i = 0; i < m_List.Count; i++ ) + { + if ( m_List[i] != null ) + DealDamage( m_List[i] ); + } + + m_List.Clear(); + m_List = new List(); + } + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m_MinDamage != 0 ) + DealDamage( m ); + + return true; + } + + public void DealDamage( Mobile m ) + { + if ( m != m_Owner ) + AOS.Damage( m, (m_Owner == null) ? m : m_Owner, Utility.RandomMinMax( m_MinDamage, m_MaxDamage ), 0, 100, 0, 0, 0 ); + } + + public FireField( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + // Unsaved. + } + + public override void Deserialize( GenericReader reader ) + { + } + }*/ + + //#endregion +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Anlorvaglem.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Anlorvaglem.cs new file mode 100644 index 0000000..8e5181f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Anlorvaglem.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a plant corpse" )] + public class Anlorvaglem : BaseCreature + { + [Constructable] + public Anlorvaglem() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.6, 1.2 ) + { + Name = "Anlorvaglem"; + Body = 780; + + SetStr( 1104, 1104 ); + SetDex( 1076, 1076 ); + SetInt( 1107, 1107 ); + + SetHits( 3205, 3205 ); + SetMana( 1107, 1107 ); + SetStam( 1076, 1076 ); + + SetDamage( 11, 13 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 30, 36 ); + SetResistance( ResistanceType.Fire, 40, 43 ); + SetResistance( ResistanceType.Cold, 50, 58 ); + SetResistance( ResistanceType.Poison, 100, 100 ); + SetResistance( ResistanceType.Energy, 35, 40 ); + + SetSkill( SkillName.MagicResist, 62.8, 66.8 ); + SetSkill( SkillName.Tactics, 90.7, 94.1 ); + SetSkill( SkillName.Anatomy, 20.5, 27.2 ); + SetSkill( SkillName.Wrestling, 53.6, 58.8 ); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 28; + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( new Board( 10 ) ); + else + PackItem( new Log( 10 ) ); + PackItem( new DaemonBone( 30 ) ); + + PackReg( 3 ); + PackItem( new Engines.Plants.Seed() ); + PackItem( new Engines.Plants.Seed() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Anlorvaglem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + + /*public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( this.Hits > (this.HitsMax / 4) ) + { + if ( 0.25 >= Utility.RandomDouble() ) + //SpawnBogling( attacker ); + } + else if ( 0.25 >= Utility.RandomDouble() ) + { + //EatBoglings(); + } + }*/ + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/BattleChickenLizard.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/BattleChickenLizard.cs new file mode 100644 index 0000000..cb43219 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/BattleChickenLizard.cs @@ -0,0 +1,64 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a chicken lizard corpse" )] + public class BattleChickenLizard : BaseCreature + { + [Constructable] + public BattleChickenLizard() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a battle chicken lizard"; + Body = 716; + + SetStr( 94, 177 ); + SetDex( 78, 124 ); + SetInt( 6, 13 ); + + SetHits( 94, 177 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 15 ); + + SetSkill( SkillName.MagicResist, 30.0, 53.0 ); + SetSkill( SkillName.Tactics, 50.0, 62.0 ); + SetSkill( SkillName.Wrestling, 50.0, 62.0 ); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 0.0; + } + + public override int Meat{ get{ return 3; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay; } } + + public override int GetIdleSound() { return 1511; } + public override int GetAngerSound() { return 1508; } + public override int GetHurtSound() { return 1510; } + public override int GetDeathSound() { return 1509; } + + public BattleChickenLizard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/High Plains Boura.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/High Plains Boura.cs new file mode 100644 index 0000000..7068ffe --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/High Plains Boura.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Targeting; +using System.Collections; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a boura corpse" )] + public class HighPlainsBoura: BaseCreature + { + private bool m_Stunning; + + [Constructable] + public HighPlainsBoura() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a high plains boura"; + Body = 715; + + SetStr( 337, 518 ); + SetDex( 87, 107 ); + SetInt( 25, 30 ); + + SetHits( 575, 666 ); + + SetDamage( 20, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 35, 40 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 81.2, 84.4 ); + SetSkill( SkillName.MagicResist, 70.7, 75.0 ); + SetSkill( SkillName.Tactics, 83.4, 86.7 ); + SetSkill( SkillName.Wrestling, 95.1, 97.3 ); + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 47.1; + } + + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override int GetIdleSound() { return 1507; } + public override int GetAngerSound() { return 1504; } + public override int GetHurtSound() { return 1506; } + public override int GetDeathSound() { return 1505; } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !m_Stunning && 0.3 > Utility.RandomDouble() ) + { + m_Stunning = true; + + defender.Animate( 21, 6, 1, true, false, 0 ); + this.PlaySound( 0xEE ); + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You have been stunned by a colossal blow!" ); + + BaseWeapon weapon = this.Weapon as BaseWeapon; + if ( weapon != null ) + weapon.OnHit( this, defender ); + + if ( defender.Alive ) + { + defender.Frozen = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( Recover_Callback ), defender ); + } + } + } + + private void Recover_Callback( object state ) + { + Mobile defender = state as Mobile; + + if ( defender != null ) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You recover your senses." ); + } + + m_Stunning = false; + } + + public HighPlainsBoura( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/LowlandBoura.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/LowlandBoura.cs new file mode 100644 index 0000000..6f04576 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/LowlandBoura.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Targeting; +using System.Collections; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a boura corpse" )] + public class LowlandBoura: BaseCreature + { + private bool m_Stunning; + + [Constructable] + public LowlandBoura() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a lowland boura"; + Body = 715; + + SetStr( 337, 411 ); + SetDex( 82, 93 ); + SetInt( 23, 25 ); + + SetHits( 438, 553 ); + + SetDamage( 18, 23 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 35, 40 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 81.2, 84.4 ); + SetSkill( SkillName.MagicResist, 70.7, 75.0 ); + SetSkill( SkillName.Tactics, 83.4, 86.7 ); + SetSkill( SkillName.Wrestling, 95.1, 97.3 ); + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 29.1; + } + + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override int GetIdleSound() { return 1507; } + public override int GetAngerSound() { return 1504; } + public override int GetHurtSound() { return 1506; } + public override int GetDeathSound() { return 1505; } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !m_Stunning && 0.3 > Utility.RandomDouble() ) + { + m_Stunning = true; + + defender.Animate( 21, 6, 1, true, false, 0 ); + this.PlaySound( 0xEE ); + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You have been stunned by a colossal blow!" ); + + BaseWeapon weapon = this.Weapon as BaseWeapon; + if ( weapon != null ) + weapon.OnHit( this, defender ); + + if ( defender.Alive ) + { + defender.Frozen = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( Recover_Callback ), defender ); + } + } + } + + private void Recover_Callback( object state ) + { + Mobile defender = state as Mobile; + + if ( defender != null ) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You recover your senses." ); + } + + m_Stunning = false; + } + + public LowlandBoura( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/Ruddy Boura.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/Ruddy Boura.cs new file mode 100644 index 0000000..0c39fa5 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Boura/Ruddy Boura.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Targeting; +using System.Collections; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a boura corpse" )] + public class RuddyBoura: BaseCreature + { + private bool m_Stunning; + + [Constructable] + public RuddyBoura() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a ruddy boura"; + Body = 715; + + SetStr( 383 ); + SetDex( 80 ); + SetInt( 17 ); + + SetHits( 471 ); + + SetDamage( 16, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 49 ); + SetResistance( ResistanceType.Fire, 30 ); + SetResistance( ResistanceType.Cold, 33 ); + SetResistance( ResistanceType.Poison, 38 ); + SetResistance( ResistanceType.Energy, 31 ); + + SetSkill( SkillName.Anatomy, 84.7 ); + SetSkill( SkillName.MagicResist, 68.6 ); + SetSkill( SkillName.Tactics, 83.9 ); + SetSkill( SkillName.Wrestling, 94.5 ); + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 25.1; + } + + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override int GetIdleSound() { return 1507; } + public override int GetAngerSound() { return 1504; } + public override int GetHurtSound() { return 1506; } + public override int GetDeathSound() { return 1505; } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !m_Stunning && 0.3 > Utility.RandomDouble() ) + { + m_Stunning = true; + + defender.Animate( 21, 6, 1, true, false, 0 ); + this.PlaySound( 0xEE ); + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You have been stunned by a colossal blow!" ); + + BaseWeapon weapon = this.Weapon as BaseWeapon; + if ( weapon != null ) + weapon.OnHit( this, defender ); + + if ( defender.Alive ) + { + defender.Frozen = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( Recover_Callback ), defender ); + } + } + } + + private void Recover_Callback( object state ) + { + Mobile defender = state as Mobile; + + if ( defender != null ) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You recover your senses." ); + } + + m_Stunning = false; + } + + public RuddyBoura( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/ChickenLizard.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/ChickenLizard.cs new file mode 100644 index 0000000..4a4da0b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/ChickenLizard.cs @@ -0,0 +1,64 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a chicken lizard corpse" )] + public class ChickenLizard : BaseCreature + { + [Constructable] + public ChickenLizard() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a chicken lizard"; + Body = 716; + + SetStr( 78, 87 ); + SetDex( 87, 92 ); + SetInt( 8 ); + + SetHits( 77, 82 ); + + SetDamage( 2, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 18, 20 ); + SetResistance( ResistanceType.Fire, 7, 14 ); + + SetSkill( SkillName.MagicResist, 0.0, 28.5 ); + SetSkill( SkillName.Tactics, 0.0, 41.3 ); + SetSkill( SkillName.Wrestling, 0.0, 35.8 ); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 0.0; + } + + public override int Meat{ get{ return 3; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public override int GetIdleSound() { return 1511; } + public override int GetAngerSound() { return 1508; } + public override int GetHurtSound() { return 1510; } + public override int GetDeathSound() { return 1509; } + + public ChickenLizard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Dread War Horse.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Dread War Horse.cs new file mode 100644 index 0000000..809b69b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Dread War Horse.cs @@ -0,0 +1,102 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a dread war horse corpse" )] + public class DreadWarHorse : BaseMount + { + [Constructable] + public DreadWarHorse() : this( "a Dread War Horse" ) + { + } + + [Constructable] + public DreadWarHorse( string name ) : base( name, 0x74, 0x3EA7, AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 179; + BaseSoundID = 0xA8; + + SetStr( 500, 555 ); + SetDex( 89, 123 ); + SetInt( 100, 159 ); + + SetHits( 555, 650 ); + + SetDamage( 20, 26 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 40 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 20, 40 ); + SetResistance( ResistanceType.Cold, 20, 40 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 15.2, 19.3 ); + SetSkill( SkillName.Magery, 39.5, 49.5 ); + SetSkill( SkillName.MagicResist, 91.4, 93.4 ); + SetSkill( SkillName.Tactics, 108.1, 110.0 ); + SetSkill( SkillName.Wrestling, 97.3, 98.2 ); + + Fame = 14000; + Karma = -14000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 107.1; + + PackItem( new SulfurousAsh( Utility.RandomMinMax( 3, 5 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Potions ); + } + + public override int GetAngerSound() + { + if ( !Controlled ) + return 0x16A; + + return base.GetAngerSound(); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 5; } } + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public DreadWarHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( BaseSoundID == 0x16A ) + BaseSoundID = 0xA8; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Fire Ant Queen.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Fire Ant Queen.cs new file mode 100644 index 0000000..cce8bfd --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Fire Ant Queen.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a fire ant corpse" )] + public class FireAntQueen : BaseCreature + { + [Constructable] + public FireAntQueen() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fire ant queen"; + Body = 787; + Hue = 1161; + + SetStr( 1200 ); + SetDex( 300 ); + SetInt( 200 ); + + SetHits( 900 ); + + SetDamage( 15, 18 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Fire, 60 ); + + SetResistance( ResistanceType.Physical, 52 ); + SetResistance( ResistanceType.Fire, 96 ); + SetResistance( ResistanceType.Cold, 36 ); + SetResistance( ResistanceType.Poison, 40 ); + SetResistance( ResistanceType.Energy, 36 ); + + SetSkill( SkillName.Anatomy, 8.7 ); + SetSkill( SkillName.MagicResist, 53.1 ); + SetSkill( SkillName.Tactics, 77.2 ); + SetSkill( SkillName.Wrestling, 75.4 ); + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 1 ); + } + + public override int GetIdleSound() { return 846; } + public override int GetAngerSound() { return 849; } + public override int GetHurtSound() { return 852; } + public override int GetDeathSound() { return 850; } + + public FireAntQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/ForgottenServant.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/ForgottenServant.cs new file mode 100644 index 0000000..d9f6e72 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/ForgottenServant.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class ForgottenServant : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public ForgottenServant() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "Forgotten Servant"; + Hue = 768; + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + AddItem( new Skirt( Utility.RandomNeutralHue() ) ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + + SetStr( 147, 215 ); + SetDex( 91, 115 ); + SetInt( 61, 85 ); + + SetHits( 95, 123 ); + + SetDamage( 4, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Swords, 60.1, 85.0 ); + SetSkill( SkillName.Tactics, 75.1, 90.0 ); + SetSkill( SkillName.Wrestling, 60.1, 85.0 ); + + Fame = 2500; + Karma = -2500; + + AddItem( new Boots( Utility.RandomNeutralHue() ) ); + AddItem( new FancyShirt()); + AddItem( new Bandana()); + + switch ( Utility.Random( 7 )) + { + case 0: AddItem( new Longsword() ); break; + case 1: AddItem( new Cutlass() ); break; + case 2: AddItem( new Broadsword() ); break; + case 3: AddItem( new Axe() ); break; + case 4: AddItem( new Club() ); break; + case 5: AddItem( new Dagger() ); break; + case 6: AddItem( new Spear() ); break; + } + + Utility.AssignRandomHair( this ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public ForgottenServant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/GargoylePet.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/GargoylePet.cs new file mode 100644 index 0000000..cf1fab3 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/GargoylePet.cs @@ -0,0 +1,72 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a gargoyle corpse" )] + public class GargoylePet : BaseCreature + { + [Constructable] + public GargoylePet() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gargoyle pet"; + Body = 730; + + SetStr( 500, 512 ); + SetDex( 90, 94 ); + SetInt( 100, 107 ); + + SetHits( 300, 313 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60 ); + SetResistance( ResistanceType.Fire, 40 ); + SetResistance( ResistanceType.Cold, 40 ); + SetResistance( ResistanceType.Poison, 40 ); + SetResistance( ResistanceType.Energy, 40 ); + + SetSkill( SkillName.MagicResist, 75.5, 89.0 ); + SetSkill( SkillName.Tactics, 80.3, 93.8 ); + SetSkill( SkillName.Wrestling, 66.9, 81.5 ); + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 65.1; + } + + public override int Meat{ get{ return 7; } } + public override int Hides{ get{ return 11; } } + public override HideType HideType{ get{ return HideType.Horned; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + } + + public override int GetIdleSound() { return 1573; } + public override int GetAngerSound() { return 1570; } + public override int GetHurtSound() { return 1572; } + public override int GetDeathSound() { return 1571; } + + public GargoylePet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Kepetch/Kepetch.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Kepetch/Kepetch.cs new file mode 100644 index 0000000..6ee38bd --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Kepetch/Kepetch.cs @@ -0,0 +1,116 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a kepetch corpse" )] + public class Kepetch : BaseCreature, ICarvable + { + private DateTime m_NextWoolTime; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextWoolTime + { + get{ return m_NextWoolTime; } + set{ m_NextWoolTime = value; Body = ( DateTime.Now >= m_NextWoolTime ) ? 0xCF : 0xDF; } + } + + public void Carve( Mobile from, Item item ) + { + if ( DateTime.Now < m_NextWoolTime ) + { + // This sheep is not yet ready to be shorn. + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 500449, from.NetState ); + return; + } + + from.SendLocalizedMessage( 500452 ); // You place the gathered wool into your backpack. + from.AddToBackpack( new Wool( Map == Map.Felucca ? 2 : 1 ) ); + + NextWoolTime = DateTime.Now + TimeSpan.FromHours( 3.0 ); // TODO: Proper time delay + } + + public override void OnThink() + { + base.OnThink(); + Body = ( DateTime.Now >= m_NextWoolTime ) ? 726 : 727; + } + + [Constructable] + public Kepetch() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a kepetch"; + Body = 726; + + SetStr( 337, 354 ); + SetDex( 184, 194 ); + SetInt( 32, 37 ); + + SetHits( 308, 366 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 40, 45 ); + SetResistance( ResistanceType.Cold, 45, 55 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 65, 75 ); + + SetSkill( SkillName.Anatomy, 119.7, 124.1 ); + SetSkill( SkillName.MagicResist, 89.9, 97.4 ); + SetSkill( SkillName.Tactics, 117.4, 123.5 ); + SetSkill( SkillName.Wrestling, 107.7, 113.9 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override int Meat{ get{ return 5; } } + public override int Hides{ get{ return 14; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override int Wool{ get{ return (Body == 726 ? 3 : 0); } } + + public override int GetIdleSound() { return 1545; } + public override int GetAngerSound() { return 1542; } + public override int GetHurtSound() { return 1544; } + public override int GetDeathSound() { return 1543; } + + public Kepetch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.WriteDeltaTime( m_NextWoolTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + NextWoolTime = reader.ReadDeltaTime(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Kepetch/KepetchAmbusher.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Kepetch/KepetchAmbusher.cs new file mode 100644 index 0000000..dcfd2dc --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Kepetch/KepetchAmbusher.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a kepetch corpse" )] + public class KepetchAmbusher : BaseCreature + { + [Constructable] + public KepetchAmbusher() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a kepetch ambusher"; + Body = 726; + + SetStr( 440, 446 ); + SetDex( 229, 254 ); + SetInt( 46, 46 ); + + SetHits( 533, 544 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 73, 95 ); + SetResistance( ResistanceType.Fire, 57, 70 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 70, 95 ); + + SetSkill( SkillName.Anatomy, 104.3, 114.1 ); + SetSkill( SkillName.MagicResist, 94.6, 97.4 ); + SetSkill( SkillName.Tactics, 110.4, 123.5 ); + SetSkill( SkillName.Wrestling, 107.3, 113.9 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override int Meat{ get{ return 7; } } + public override int Hides{ get{ return 14; } } + public override HideType HideType{ get{ return HideType.Horned; } } + // add fur drop + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override int GetIdleSound() { return 1545; } + public override int GetAngerSound() { return 1542; } + public override int GetHurtSound() { return 1544; } + public override int GetDeathSound() { return 1543; } + + public KepetchAmbusher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre.cs new file mode 100644 index 0000000..1813057 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a slimey corpse" )] + public class Korpre : BaseCreature + { + [Constructable] + public Korpre() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Korpre"; + Body = 51; + BaseSoundID = 456; + + Hue = Utility.RandomSlimeHue(); + + SetStr( 22, 34 ); + SetDex( 16, 21 ); + SetInt( 16, 20 ); + + SetHits( 15, 19 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Poison, 15, 20 ); + + SetSkill( SkillName.Poisoning, 36.0, 49.1 ); + SetSkill(SkillName.Anatomy, 0); + SetSkill( SkillName.MagicResist, 15.9, 18.9 ); + SetSkill( SkillName.Tactics, 24.6, 26.1 ); + SetSkill( SkillName.Wrestling, 24.9, 26.1 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 8; + + Tamable = false; + ControlSlots = 1; + MinTameSkill = 23.1; + } + +/* public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + DodeSpawn(attacker); + } + + public void DodeSpawn(Mobile attacker) + { + if (attacker is BaseCreature && ((BaseCreature)atacker) == 6) + { + DeSpawn.Mobile(Korpre); + Spawn.Mobile(Anlorzen); + } + else if (attacker == killed.BaseCreature && ((BaseCreature)Isweaker) + { + DeSpawn.Mobile(Korpre); + Spawn.Mobile(new Betballem); + } + else if (attacker is BaseCreature && ((BaseCreature)IsAlive) > Time.Span(100) + { + DeSpawn.Mobile(Korpre); + Spawn.Mobile(new Anzuanords); + } + else + { + Math.Rnd(0,100); + Math.Rnd = 50; + + DeSpawn.Mobile(Korpre); + Spawn.Mobile(new Ortanord); + } + }*/ + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + AddLoot( LootPack.Gems ); + } + + public override Poison PoisonImmune { get { return Poison.Regular; } } + public override Poison HitPoison { get { return Poison.Regular; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + //TODO: Damage weapon via acid + + public Korpre( Serial serial ) : base( serial ) + { + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + +// if ( Utility.RandomDouble() < 0.05 ) +// { +// switch ( Utility.Random( 1 ) ) +// { +// case 0: c.DropItem( new CoagulatedLegs() ); break;/*Void Orb*/ +// } +// } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/Evolution Korpre.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/Evolution Korpre.cs new file mode 100644 index 0000000..415fa7d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/Evolution Korpre.cs @@ -0,0 +1,532 @@ +using System; +using System.Collections; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Mobiles +{ + [CorpseName( "a korpre corpse" )] + public class EvolutionKorpre : BaseCreature + { + private Timer m_KorpreMatingTimer; + private DateTime m_EndMating; + + public int m_Stage; + public int m_KPKorpre; + + public DateTime EndMating{ get{ return m_EndMating; } set{ m_EndMating = value; } } + + public bool m_AllowMating; + public bool m_HasEgg; + public bool m_Pregnant; + + public bool m_S1; + public bool m_S2; + + public bool S1 + { + get{ return m_S1; } + set{ m_S1 = value; } + } + public bool S2 + { + get{ return m_S2; } + set{ m_S2 = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowMating + { + get{ return m_AllowMating; } + set{ m_AllowMating = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasEgg + { + get{ return m_HasEgg; } + set{ m_HasEgg = value; } + } + [CommandProperty( AccessLevel.GameMaster )] + public bool Pregnant + { + get{ return m_Pregnant; } + set{ m_Pregnant = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int KPKorpre + { + get{ return m_KPKorpre; } + set{ m_KPKorpre = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Stage + { + get{ return m_Stage; } + set{ m_Stage = value; } + } + + [Constructable] + public EvolutionKorpre() : this( "a Korpre" ) + { + } + + [Constructable] + public EvolutionKorpre( string name ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a korpre"; + Body = 51; + Hue = 1759; + BaseSoundID = 456; + Stage = 1; + + S1 = true; + S2 = true; + + SetStr( 26 ); + SetDex( 19 ); + SetInt( 17 ); + + SetHits( 58 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 45 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 45 ); + SetResistance( ResistanceType.Fire, 25 ); + SetResistance( ResistanceType.Cold, 5 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 1 ); + + SetSkill( SkillName.Wrestling, 16.0, 16.5 ); + + Fame = 9000; + Karma = -10000; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 80.0; + + PackItem( new KorpreDust( 1 ) ); + } + + public EvolutionKorpre(Serial serial) : base(serial) + { + } + + public override void Damage( int amount, Mobile defender ) + + { + + int KPKorpregainmin, KPKorpregainmax; + + if ( this.Stage == 1 ) + { + if ( defender is BaseCreature ) + { + BaseCreature bc = (BaseCreature)defender; + + if ( bc.Controlled != true ) + { + KPKorpregainmin = 5 + ( bc.HitsMax ) / 10; + KPKorpregainmax = 5 + ( bc.HitsMax ) / 5; + + this.KPKorpre += Utility.RandomList( KPKorpregainmin, KPKorpregainmax ); + } + } + + if ( this.KPKorpre >= 50000 ) + { + if ( this.S1 == true ) + { + this.S1 = false; + int va; + + va = ( this.VirtualArmor + 10 ); + + this.AI = AIType.AI_Mage; + this.Warmode = false; + this.Say( "*"+ this.Name +" is now a ballem*"); + this.Title = "a ballem"; + + this.BodyValue = 792; + this.BaseSoundID = 0x3E9; + this.VirtualArmor = va; + this.Stage = 2; + + this.SetDamageType( ResistanceType.Physical, 20 ); + this.SetDamageType( ResistanceType.Fire, 20 ); + this.SetDamageType( ResistanceType.Cold, 20 ); + this.SetDamageType( ResistanceType.Poison, 20 ); + this.SetDamageType( ResistanceType.Energy, 20 ); + + this.SetResistance( ResistanceType.Physical, 39 ); + this.SetResistance( ResistanceType.Fire, 46 ); + this.SetResistance( ResistanceType.Cold, 24 ); + this.SetResistance( ResistanceType.Poison, 100 ); + this.SetResistance( ResistanceType.Energy, 30 ); + + this.SetSkill( SkillName.Magery, 70.0 ); + this.SetSkill( SkillName.MagicResist, 70.0 ); + this.SetSkill( SkillName.Tactics, 70.0 ); + this.SetSkill( SkillName.Wrestling, 70.0 ); + + this.SetStr( 991 ); + this.SetDex( 1001 ); + this.SetInt( 243 ); + this.SetHits( 521 ); + + this.SetDamage( 10, 15 ); + } + } + } + + else if ( this.Stage == 2 ) + { + if ( defender is BaseCreature ) + { + BaseCreature bc = (BaseCreature)defender; + + if ( bc.Controlled != true ) + { + KPKorpregainmin = 5 + ( bc.HitsMax ) / 30; + KPKorpregainmax = 5 + ( bc.HitsMax ) / 20; + + this.KPKorpre += Utility.RandomList( KPKorpregainmin, KPKorpregainmax ); + } + } + + if ( this.KPKorpre >= 250000 ) + { + if ( this.S2 == true ) + { + this.S2 = false; + int va; + + va = ( this.VirtualArmor + 10 ); + + this.AllowMating = true; + this.Warmode = false; + this.Say( "*"+ this.Name +" is now a Usagralem Ballem*"); + this.Title = "a Usagralem Ballem"; + this.BodyValue = 318; + this.BaseSoundID = 0x165; + this.VirtualArmor = va; + this.Stage = 3; + + this.SetDamageType( ResistanceType.Physical, 30 ); + this.SetDamageType( ResistanceType.Fire, 30 ); + this.SetDamageType( ResistanceType.Cold, 30 ); + this.SetDamageType( ResistanceType.Poison, 30 ); + this.SetDamageType( ResistanceType.Energy, 30 ); + + this.SetResistance( ResistanceType.Physical, 50 ); + this.SetResistance( ResistanceType.Fire, 60 ); + this.SetResistance( ResistanceType.Cold, 54 ); + this.SetResistance( ResistanceType.Poison, 100 ); + this.SetResistance( ResistanceType.Energy, 47 ); + + this.SetSkill( SkillName.Magery, 100.0 ); + this.SetSkill( SkillName.MagicResist, 100.0 ); + this.SetSkill( SkillName.Tactics, 70.0 ); + this.SetSkill( SkillName.Wrestling, 80.0 ); + + this.SetStr( 1000 ); + this.SetDex( 1028 ); + this.SetInt( 1014 ); + this.SetHits( 2125 ); + + this.SetDamage( 17, 21 ); + } + } + } + base.Damage( amount, defender ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + if ( dropped is KorpreDust ) + { + KorpreDust dust = ( KorpreDust )dropped; + + int amount = ( dust.Amount * 1000 ); + + this.PlaySound( 665 ); + this.KPKorpre += amount; + + dust.Delete(); + + this.Say( "*"+ this.Name +" absorbs the Korpre dust*" ); + + return false; + } + } + return base.OnDragDrop( from, dropped ); + } + + private void MatingTarget_Callback( Mobile from, object obj ) + { + if ( obj is EvolutionKorpre && obj is BaseCreature ) + { + BaseCreature bc = (BaseCreature)obj; + EvolutionKorpre ed = (EvolutionKorpre)obj; + + if ( ed.Controlled == true && ed.ControlMaster == from ) + { + if ( ed.Female == false ) + { + if ( ed.AllowMating == true ) + { + this.Blessed = true; + this.Pregnant = true; + + m_KorpreMatingTimer = new KorpreMatingTimer( this, TimeSpan.FromDays( 0.0 ) ); + m_KorpreMatingTimer.Start(); + + m_EndMating = DateTime.Now + TimeSpan.FromDays( 0.0 ); + } + else + { + from.SendMessage( "This male Korpre is not old enough to mate!" ); + } + } + else + { + from.SendMessage( "This Korpre is not male!" ); + } + } + else if ( ed.Controlled == true ) + { + if ( ed.Female == false ) + { + if ( ed.AllowMating == true ) + { + if ( ed.ControlMaster != null ) + { + ed.ControlMaster.SendGump( new KorpreMatingGump( from, ed.ControlMaster, this, ed ) ); + from.SendMessage( "You ask the owner of the Korpre if they will let your female mate with their male." ); + } + else + { + from.SendMessage( "This Korpre is wild." ); + } + } + else + { + from.SendMessage( "This male Korpre is not old enough to mate!" ); + } + } + else + { + from.SendMessage( "This Korpre is not male!" ); + } + } + else + { + from.SendMessage( "This Korpre is wild." ); + } + } + else + { + from.SendMessage( "That is not a Korpre!" ); + } + } + + /*public override bool HandlesOnSpeech( Mobile from ) + { + if (from.InRange(this, 1)) + return true; + else + return false; + }*/ + + public override void OnSpeech(SpeechEventArgs args) + { + base.OnSpeech (args); + if (args.Speech.ToLower() == "mate Korpre") + { + if (this.Controlled == true && this.ControlMaster == args.Mobile) + { + //if (this is EvolutionDragon) // Always true ;) + //{ + if (this.Female == true) + { + if (this.AllowMating == true) + { + if (this.Pregnant == false) + { + if (this.HasEgg == true) + { + this.HasEgg = false; + this.Pregnant = false; + this.Blessed = false; + + if (args.Mobile.Backpack != null) + { + args.Mobile.AddToBackpack(new KorpreEgg()); + args.Mobile.SendMessage("A Korpre's egg has been placed in your backpack"); + } + else + args.Mobile.SendMessage("You broke the egg."); // If the Mobile has no backpack, the Egg is lost. + } + else + { + args.Mobile.SendMessage("Target a male Korpre to mate with this female."); + args.Mobile.BeginTarget(-1, false, TargetFlags.Harmful, new TargetCallback(MatingTarget_Callback)); + } + } + } + else + { + args.Mobile.SendMessage("This female Korpre is not old enough to mate!"); + } + } + //} + } + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 1); + + writer.Write( m_AllowMating ); + writer.Write( m_HasEgg ); + writer.Write( m_Pregnant ); + writer.Write( m_S1 ); + writer.Write( m_S2 ); + writer.Write( (int) m_KPKorpre ); + writer.Write( (int) m_Stage ); + writer.WriteDeltaTime( m_EndMating ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_AllowMating = reader.ReadBool(); + m_HasEgg = reader.ReadBool(); + m_Pregnant = reader.ReadBool(); + m_S1 = reader.ReadBool(); + m_S2 = reader.ReadBool(); + m_KPKorpre = reader.ReadInt(); + m_Stage = reader.ReadInt(); + m_EndMating = reader.ReadDeltaTime(); + m_KorpreMatingTimer = new KorpreMatingTimer( this, m_EndMating - DateTime.Now ); + m_KorpreMatingTimer.Start(); + + break; + } + case 0: + { + TimeSpan durationmating = TimeSpan.FromDays( 0.0 ); + + m_KorpreMatingTimer = new KorpreMatingTimer( this, durationmating ); + m_KorpreMatingTimer.Start(); + m_EndMating = DateTime.Now + durationmating; + + break; + } + } + } + } + + public class KorpreMatingTimer : Timer + { + private EvolutionKorpre ed; + + public KorpreMatingTimer( EvolutionKorpre owner, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + ed = owner; + } + + protected override void OnTick() + { + ed.Blessed = false; + ed.HasEgg = true; + ed.Pregnant = false; + Stop(); + } + } + public class KorpreMatingGump : Gump + { + private Mobile m_From; + private Mobile m_Mobile; + private EvolutionKorpre m_ED1; + private EvolutionKorpre m_ED2; + + public KorpreMatingGump( Mobile from, Mobile mobile, EvolutionKorpre ed1, EvolutionKorpre ed2 ) : base( 25, 50 ) + { + Closable = false; + Dragable = false; + + m_From = from; + m_Mobile = mobile; + m_ED1 = ed1; + m_ED2 = ed2; + + AddPage( 0 ); + + AddBackground( 25, 10, 420, 200, 5054 ); + + AddImageTiled( 33, 20, 401, 181, 2624 ); + AddAlphaRegion( 33, 20, 401, 181 ); + + AddLabel( 125, 148, 1152, m_From.Name +" would like to mate "+ m_ED1.Name +" with" ); + AddLabel( 125, 158, 1152, m_ED2.Name +"." ); + + AddButton( 100, 50, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddLabel( 130, 50, 1152, "Allow them to mate." ); + AddButton( 100, 75, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddLabel( 130, 75, 1152, "Do not allow them to mate." ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( from == null ) + return; + + if ( info.ButtonID == 0 ) + { + m_From.SendMessage( m_Mobile.Name +" declines your request to mate the two Korpres." ); + m_Mobile.SendMessage( "You decline "+ m_From.Name +"'s request to mate the two Korpres." ); + } + if ( info.ButtonID == 1 ) + { + m_ED1.Blessed = true; + m_ED1.Pregnant = true; + + KorpreMatingTimer mt = new KorpreMatingTimer( m_ED1, TimeSpan.FromDays( 0.0 ) ); + mt.Start(); + m_ED1.EndMating = DateTime.Now + TimeSpan.FromDays( 0.0 ); + + m_From.SendMessage( m_Mobile.Name +" accepts your request to mate the two Korpres." ); + m_Mobile.SendMessage( "You accept "+ m_From.Name +"'s request to mate the two Korpres." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/KPKorpre.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/KPKorpre.cs new file mode 100644 index 0000000..7a26c42 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/KPKorpre.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Targeting; + + +namespace Server.Commands +{ + public class KPKorpreSystem + { + + public static void Initialize() + { + CommandSystem.Register( "KPKorpre", AccessLevel.Player, new CommandEventHandler( KPKorpre_OnCommand ) ); + } + + public static void KPKorpre_OnCommand( CommandEventArgs e ) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if( from != null ) + { + from.Target = new InternalTarget( from ); + } + } + + private class InternalTarget : Target + { + public InternalTarget( Mobile from ) : base( 8, false, TargetFlags.None ) + { + from.SendMessage ( "Target an animal that you own to check their level." ); + } + + protected override void OnTarget( Mobile from, object obj ) + { + if ( !from.Alive ) + { + from.SendMessage( "You may not do that while dead." ); + } + else if ( obj is EvolutionKorpre && obj is BaseCreature )//Korpre + { + BaseCreature bc = (BaseCreature)obj; + EvolutionKorpre ed = (EvolutionKorpre)obj; + + if ( ed.Controlled == true && ed.ControlMaster == from ) + { + ed.PublicOverheadMessage( MessageType.Regular, ed.SpeechHue, true, ed.Name +" has "+ ed.KPKorpre +" kill points.", false ); + } + else + { + from.SendMessage( "You do not control this Korpre!" ); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/Korpre Egg.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/Korpre Egg.cs new file mode 100644 index 0000000..40f8f8d --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/Korpre Egg.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Mobiles; +using Server.Misc; +using Server.Network; + +namespace Server.Items +{ + public class KorpreEgg: Item + { + public bool m_AllowEvolution; + public Timer m_EvolutionTimer; + private DateTime m_End; + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowEvolution + { + get{ return m_AllowEvolution; } + set{ m_AllowEvolution = value; } + } + + [Constructable] + public KorpreEgg() : base( 0x09B5 ) + { + Weight = 0.0; + Name = "a Korpres egg"; + Hue = 1759; + AllowEvolution = false; + + m_EvolutionTimer = new EvolutionTimer( this, TimeSpan.FromDays( 0.0 ) ); + m_EvolutionTimer.Start(); + m_End = DateTime.Now + TimeSpan.FromDays( 0.0 ); + } + + public KorpreEgg( Serial serial ) : base ( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendMessage( "You must have the egg in your backpack." ); + } + else if ( this.AllowEvolution == true ) + { + this.Delete(); + from.SendMessage( "You are now the proud owner of a baby Korpre!!" ); + + EvolutionKorpre Korpre = new EvolutionKorpre(); + + Korpre.Map = from.Map; + Korpre.Location = from.Location; + + Korpre.Controlled = true; + + Korpre.ControlMaster = from; + + Korpre.IsBonded = true; + } + else + { + from.SendMessage( "This Korpre is not ready." ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_End = reader.ReadDeltaTime(); + m_EvolutionTimer = new EvolutionTimer( this, m_End - DateTime.Now ); + m_EvolutionTimer.Start(); + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromDays( 1.0 ); + + m_EvolutionTimer = new EvolutionTimer( this, duration ); + m_EvolutionTimer.Start(); + m_End = DateTime.Now + duration; + + break; + } + } + } + + private class EvolutionTimer : Timer + { + private KorpreEgg de; + + private int cnt = 0; + + public EvolutionTimer( KorpreEgg owner, TimeSpan duration ) : base( duration ) + { + de = owner; + } + + protected override void OnTick() + { + cnt += 1; + + if ( cnt == 1 ) + { + de.AllowEvolution = true; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/KorpreDust.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/KorpreDust.cs new file mode 100644 index 0000000..601748c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 1/KorpreDust.cs @@ -0,0 +1,39 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class KorpreDust: Item + { + [Constructable] + public KorpreDust() : this( 1 ) + { + } + + [Constructable] + public KorpreDust( int amount ) : base( 0x26B8 ) + { + Stackable = true; + Weight = 0.0; + Amount = amount; + Name = "korpre dust"; + Hue = 1759; + } + + public KorpreDust( Serial serial ) : base ( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Evolution Korpre 2.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Evolution Korpre 2.cs new file mode 100644 index 0000000..2325fc8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Evolution Korpre 2.cs @@ -0,0 +1,534 @@ +using System; +using System.Collections; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Mobiles +{ + [CorpseName( "a Korpre corpse" )] + public class EvolutionKorpre2 : BaseCreature + { + private Timer m_Korpre2MatingTimer; + private DateTime m_EndMating; + + public int m_Stage; + public int m_KPKorpre2; + + public DateTime EndMating{ get{ return m_EndMating; } set{ m_EndMating = value; } } + + public bool m_AllowMating; + public bool m_HasEgg; + public bool m_Pregnant; + + public bool m_S1; + public bool m_S2; + + public bool S1 + { + get{ return m_S1; } + set{ m_S1 = value; } + } + public bool S2 + { + get{ return m_S2; } + set{ m_S2 = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowMating + { + get{ return m_AllowMating; } + set{ m_AllowMating = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasEgg + { + get{ return m_HasEgg; } + set{ m_HasEgg = value; } + } + [CommandProperty( AccessLevel.GameMaster )] + public bool Pregnant + { + get{ return m_Pregnant; } + set{ m_Pregnant = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int KPKorpre2 + { + get{ return m_KPKorpre2; } + set{ m_KPKorpre2 = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Stage + { + get{ return m_Stage; } + set{ m_Stage = value; } + } + + [Constructable] + public EvolutionKorpre2() : this( "a Korpre" ) + { + } + + [Constructable] + public EvolutionKorpre2( string name ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Korpre"; + Body = 51; + Hue = 1759; + BaseSoundID = 456; + Stage = 1; + + S1 = true; + S2 = true; + + SetStr( 26 ); + SetDex( 19 ); + SetInt( 17 ); + + SetHits( 58 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 45 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 45 ); + SetResistance( ResistanceType.Fire, 25 ); + SetResistance( ResistanceType.Cold, 5 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 1 ); + + SetSkill( SkillName.Wrestling, 16.0, 16.5 ); + + Fame = 9000; + Karma = -10000; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 80.0; + + PackItem( new Korpre2Dust( 1 ) ); + } + + public EvolutionKorpre2(Serial serial) : base(serial) + { + } + + public override void Damage( int amount, Mobile defender ) + + { + + int KPKorpre2gainmin, KPKorpre2gainmax; + + if ( this.Stage == 1 ) + { + if ( defender is BaseCreature ) + { + BaseCreature bc = (BaseCreature)defender; + + if ( bc.Controlled != true ) + { + KPKorpre2gainmin = 5 + ( bc.HitsMax ) / 10; + KPKorpre2gainmax = 5 + ( bc.HitsMax ) / 5; + + this.KPKorpre2 += Utility.RandomList( KPKorpre2gainmin, KPKorpre2gainmax ); + } + } + + if ( this.KPKorpre2 >= 50000 ) + { + if ( this.S1 == true ) + { + this.S1 = false; + int va; + + va = ( this.VirtualArmor + 10 ); + + //this.AI = AIType.AI_Mage; + this.Warmode = false; + this.Say( "*"+ this.Name +" is now a anlorzen*"); + this.Title = "a anlorzen"; + + this.BodyValue = 0x9D; + this.BaseSoundID = 0x388; + this.VirtualArmor = va; + this.Stage = 2; + + this.SetDamageType( ResistanceType.Physical, 20 ); + this.SetDamageType( ResistanceType.Fire, 20 ); + this.SetDamageType( ResistanceType.Cold, 20 ); + this.SetDamageType( ResistanceType.Poison, 20 ); + this.SetDamageType( ResistanceType.Energy, 20 ); + + this.SetResistance( ResistanceType.Physical, 47, 49 ); + this.SetResistance( ResistanceType.Fire, 43, 45 ); + this.SetResistance( ResistanceType.Cold, 36, 40 ); + this.SetResistance( ResistanceType.Poison, 100 ); + this.SetResistance( ResistanceType.Energy, 41, 45 ); + + this.SetSkill( SkillName.Anatomy, 30.3, 75.0 ); + this.SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + this.SetSkill( SkillName.MagicResist, 34.7, 48.3 ); + this.SetSkill( SkillName.Tactics, 37.0, 50.5 ); + this.SetSkill( SkillName.Wrestling, 50.7, 61.0 ); + + this.SetStr( 612, 622 ); + this.SetDex( 702, 758 ); + this.SetInt( 876, 964 ); + this.SetHits( 349, 370 ); + + this.SetDamage( 15, 18 ); + } + } + } + + else if ( this.Stage == 2 ) + { + if ( defender is BaseCreature ) + { + BaseCreature bc = (BaseCreature)defender; + + if ( bc.Controlled != true ) + { + KPKorpre2gainmin = 5 + ( bc.HitsMax ) / 30; + KPKorpre2gainmax = 5 + ( bc.HitsMax ) / 20; + + this.KPKorpre2 += Utility.RandomList( KPKorpre2gainmin, KPKorpre2gainmax ); + } + } + + if ( this.KPKorpre2 >= 250000 ) + { + if ( this.S2 == true ) + { + this.S2 = false; + int va; + + va = ( this.VirtualArmor + 10 ); + + this.AllowMating = true; + this.Warmode = false; + this.Say( "*"+ this.Name +" is now a Anlorzaglem*"); + this.Title = "a anlorzaglem"; + this.BodyValue = 71; + this.BaseSoundID = 594; + this.VirtualArmor = va; + this.Stage = 3; + + this.SetDamageType( ResistanceType.Physical, 30 ); + this.SetDamageType( ResistanceType.Fire, 30 ); + this.SetDamageType( ResistanceType.Cold, 30 ); + this.SetDamageType( ResistanceType.Poison, 30 ); + this.SetDamageType( ResistanceType.Energy, 30 ); + + this.SetResistance( ResistanceType.Physical, 49 ); + this.SetResistance( ResistanceType.Fire, 41 ); + this.SetResistance( ResistanceType.Cold, 45 ); + this.SetResistance( ResistanceType.Poison, 100 ); + this.SetResistance( ResistanceType.Energy, 38 ); + + this.SetSkill( SkillName.Anatomy, 65.3, 95.0 ); + this.SetSkill( SkillName.Poisoning, 100.0 ); + this.SetSkill( SkillName.MagicResist, 84.5 ); + this.SetSkill( SkillName.Tactics, 97.2 ); + this.SetSkill( SkillName.Wrestling, 82.5 ); + + this.SetStr( 1036 ); + this.SetDex( 1177 ); + this.SetInt( 1049 ); + this.SetHits( 3134 ); + + this.SetDamage( 11, 13 ); + } + } + } + base.Damage( amount, defender ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + if ( dropped is Korpre2Dust ) + { + Korpre2Dust dust = ( Korpre2Dust )dropped; + + int amount = ( dust.Amount * 1000 ); + + this.PlaySound( 665 ); + this.KPKorpre2 += amount; + + dust.Delete(); + + this.Say( "*"+ this.Name +" absorbs the Korpre2 dust*" ); + + return false; + } + } + return base.OnDragDrop( from, dropped ); + } + + private void MatingTarget_Callback( Mobile from, object obj ) + { + if ( obj is EvolutionKorpre2 && obj is BaseCreature ) + { + BaseCreature bc = (BaseCreature)obj; + EvolutionKorpre2 ed = (EvolutionKorpre2)obj; + + if ( ed.Controlled == true && ed.ControlMaster == from ) + { + if ( ed.Female == false ) + { + if ( ed.AllowMating == true ) + { + this.Blessed = true; + this.Pregnant = true; + + m_Korpre2MatingTimer = new Korpre2MatingTimer( this, TimeSpan.FromDays( 0.0 ) ); + m_Korpre2MatingTimer.Start(); + + m_EndMating = DateTime.Now + TimeSpan.FromDays( 0.0 ); + } + else + { + from.SendMessage( "This male Korpre is not old enough to mate!" ); + } + } + else + { + from.SendMessage( "This Korpre is not male!" ); + } + } + else if ( ed.Controlled == true ) + { + if ( ed.Female == false ) + { + if ( ed.AllowMating == true ) + { + if ( ed.ControlMaster != null ) + { + ed.ControlMaster.SendGump( new Korpre2MatingGump( from, ed.ControlMaster, this, ed ) ); + from.SendMessage( "You ask the owner of the Korpre if they will let your female mate with their male." ); + } + else + { + from.SendMessage( "This Korpre is wild." ); + } + } + else + { + from.SendMessage( "This male Korpre is not old enough to mate!" ); + } + } + else + { + from.SendMessage( "This Korpre is not male!" ); + } + } + else + { + from.SendMessage( "This Korpre is wild." ); + } + } + else + { + from.SendMessage( "That is not a Korpre!" ); + } + } + + /*public override bool HandlesOnSpeech( Mobile from ) + { + if (from.InRange(this, 1)) + return true; + else + return false; + }*/ + + public override void OnSpeech(SpeechEventArgs args) + { + base.OnSpeech (args); + if (args.Speech.ToLower() == "mate Korpre2") + { + if (this.Controlled == true && this.ControlMaster == args.Mobile) + { + //if (this is EvolutionDragon) // Always true ;) + //{ + if (this.Female == true) + { + if (this.AllowMating == true) + { + if (this.Pregnant == false) + { + if (this.HasEgg == true) + { + this.HasEgg = false; + this.Pregnant = false; + this.Blessed = false; + + if (args.Mobile.Backpack != null) + { + args.Mobile.AddToBackpack(new Korpre2Egg()); + args.Mobile.SendMessage("A Korpre's egg has been placed in your backpack"); + } + else + args.Mobile.SendMessage("You broke the egg."); // If the Mobile has no backpack, the Egg is lost. + } + else + { + args.Mobile.SendMessage("Target a male Korpre to mate with this female."); + args.Mobile.BeginTarget(-1, false, TargetFlags.Harmful, new TargetCallback(MatingTarget_Callback)); + } + } + } + else + { + args.Mobile.SendMessage("This female Korpre is not old enough to mate!"); + } + } + //} + } + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 1); + + writer.Write( m_AllowMating ); + writer.Write( m_HasEgg ); + writer.Write( m_Pregnant ); + writer.Write( m_S1 ); + writer.Write( m_S2 ); + writer.Write( (int) m_KPKorpre2 ); + writer.Write( (int) m_Stage ); + writer.WriteDeltaTime( m_EndMating ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_AllowMating = reader.ReadBool(); + m_HasEgg = reader.ReadBool(); + m_Pregnant = reader.ReadBool(); + m_S1 = reader.ReadBool(); + m_S2 = reader.ReadBool(); + m_KPKorpre2 = reader.ReadInt(); + m_Stage = reader.ReadInt(); + m_EndMating = reader.ReadDeltaTime(); + m_Korpre2MatingTimer = new Korpre2MatingTimer( this, m_EndMating - DateTime.Now ); + m_Korpre2MatingTimer.Start(); + + break; + } + case 0: + { + TimeSpan durationmating = TimeSpan.FromDays( 0.0 ); + + m_Korpre2MatingTimer = new Korpre2MatingTimer( this, durationmating ); + m_Korpre2MatingTimer.Start(); + m_EndMating = DateTime.Now + durationmating; + + break; + } + } + } + } + + public class Korpre2MatingTimer : Timer + { + private EvolutionKorpre2 ed; + + public Korpre2MatingTimer( EvolutionKorpre2 owner, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + ed = owner; + } + + protected override void OnTick() + { + ed.Blessed = false; + ed.HasEgg = true; + ed.Pregnant = false; + Stop(); + } + } + public class Korpre2MatingGump : Gump + { + private Mobile m_From; + private Mobile m_Mobile; + private EvolutionKorpre2 m_ED1; + private EvolutionKorpre2 m_ED2; + + public Korpre2MatingGump( Mobile from, Mobile mobile, EvolutionKorpre2 ed1, EvolutionKorpre2 ed2 ) : base( 25, 50 ) + { + Closable = false; + Dragable = false; + + m_From = from; + m_Mobile = mobile; + m_ED1 = ed1; + m_ED2 = ed2; + + AddPage( 0 ); + + AddBackground( 25, 10, 420, 200, 5054 ); + + AddImageTiled( 33, 20, 401, 181, 2624 ); + AddAlphaRegion( 33, 20, 401, 181 ); + + AddLabel( 125, 148, 1152, m_From.Name +" would like to mate "+ m_ED1.Name +" with" ); + AddLabel( 125, 158, 1152, m_ED2.Name +"." ); + + AddButton( 100, 50, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddLabel( 130, 50, 1152, "Allow them to mate." ); + AddButton( 100, 75, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddLabel( 130, 75, 1152, "Do not allow them to mate." ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( from == null ) + return; + + if ( info.ButtonID == 0 ) + { + m_From.SendMessage( m_Mobile.Name +" declines your request to mate the two Korpres." ); + m_Mobile.SendMessage( "You decline "+ m_From.Name +"'s request to mate the two Korpres." ); + } + if ( info.ButtonID == 1 ) + { + m_ED1.Blessed = true; + m_ED1.Pregnant = true; + + Korpre2MatingTimer mt = new Korpre2MatingTimer( m_ED1, TimeSpan.FromDays( 0.0 ) ); + mt.Start(); + m_ED1.EndMating = DateTime.Now + TimeSpan.FromDays( 0.0 ); + + m_From.SendMessage( m_Mobile.Name +" accepts your request to mate the two Korpres." ); + m_Mobile.SendMessage( "You accept "+ m_From.Name +"'s request to mate the two Korpres." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/KPKorpre2.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/KPKorpre2.cs new file mode 100644 index 0000000..d385235 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/KPKorpre2.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Targeting; + + +namespace Server.Commands +{ + public class KPKorpre2System + { + + public static void Initialize() + { + CommandSystem.Register( "KPKorpre2", AccessLevel.Player, new CommandEventHandler( KPKorpre2_OnCommand ) ); + } + + public static void KPKorpre2_OnCommand( CommandEventArgs e ) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if( from != null ) + { + from.Target = new InternalTarget( from ); + } + } + + private class InternalTarget : Target + { + public InternalTarget( Mobile from ) : base( 8, false, TargetFlags.None ) + { + from.SendMessage ( "Target an animal that you own to check their level." ); + } + + protected override void OnTarget( Mobile from, object obj ) + { + if ( !from.Alive ) + { + from.SendMessage( "You may not do that while dead." ); + } + else if ( obj is EvolutionKorpre2 && obj is BaseCreature )//Korpre + { + BaseCreature bc = (BaseCreature)obj; + EvolutionKorpre2 ed = (EvolutionKorpre2)obj; + + if ( ed.Controlled == true && ed.ControlMaster == from ) + { + ed.PublicOverheadMessage( MessageType.Regular, ed.SpeechHue, true, ed.Name +" has "+ ed.KPKorpre2 +" kill points.", false ); + } + else + { + from.SendMessage( "You do not control this Korpre!" ); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Korpre 2 Dust.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Korpre 2 Dust.cs new file mode 100644 index 0000000..0b7376f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Korpre 2 Dust.cs @@ -0,0 +1,39 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class Korpre2Dust: Item + { + [Constructable] + public Korpre2Dust() : this( 1 ) + { + } + + [Constructable] + public Korpre2Dust( int amount ) : base( 0x26B8 ) + { + Stackable = true; + Weight = 0.0; + Amount = amount; + Name = "korpre 2 dust"; + Hue = 1759; + } + + public Korpre2Dust( Serial serial ) : base ( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Korpre 2 Egg.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Korpre 2 Egg.cs new file mode 100644 index 0000000..dd75103 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 2/Korpre 2 Egg.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Mobiles; +using Server.Misc; +using Server.Network; + +namespace Server.Items +{ + public class Korpre2Egg: Item + { + public bool m_AllowEvolution; + public Timer m_EvolutionTimer; + private DateTime m_End; + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowEvolution + { + get{ return m_AllowEvolution; } + set{ m_AllowEvolution = value; } + } + + [Constructable] + public Korpre2Egg() : base( 0x09B5 ) + { + Weight = 0.0; + Name = "a Korpre 2 egg"; + Hue = 1759; + AllowEvolution = false; + + m_EvolutionTimer = new EvolutionTimer( this, TimeSpan.FromDays( 0.0 ) ); + m_EvolutionTimer.Start(); + m_End = DateTime.Now + TimeSpan.FromDays( 0.0 ); + } + + public Korpre2Egg( Serial serial ) : base ( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendMessage( "You must have the egg in your backpack." ); + } + else if ( this.AllowEvolution == true ) + { + this.Delete(); + from.SendMessage( "You are now the proud owner of a baby Korpre!!" ); + + EvolutionKorpre2 Korpre2 = new EvolutionKorpre2(); + + Korpre2.Map = from.Map; + Korpre2.Location = from.Location; + + Korpre2.Controlled = true; + + Korpre2.ControlMaster = from; + + Korpre2.IsBonded = true; + } + else + { + from.SendMessage( "This Korpre is not ready." ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_End = reader.ReadDeltaTime(); + m_EvolutionTimer = new EvolutionTimer( this, m_End - DateTime.Now ); + m_EvolutionTimer.Start(); + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromDays( 1.0 ); + + m_EvolutionTimer = new EvolutionTimer( this, duration ); + m_EvolutionTimer.Start(); + m_End = DateTime.Now + duration; + + break; + } + } + } + + private class EvolutionTimer : Timer + { + private Korpre2Egg de; + + private int cnt = 0; + + public EvolutionTimer( Korpre2Egg owner, TimeSpan duration ) : base( duration ) + { + de = owner; + } + + protected override void OnTick() + { + cnt += 1; + + if ( cnt == 1 ) + { + de.AllowEvolution = true; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Evolution Korpre 3.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Evolution Korpre 3.cs new file mode 100644 index 0000000..c442a6a --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Evolution Korpre 3.cs @@ -0,0 +1,533 @@ +using System; +using System.Collections; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Mobiles +{ + [CorpseName( "a Korpre corpse" )] + public class EvolutionKorpre3 : BaseCreature + { + private Timer m_Korpre3MatingTimer; + private DateTime m_EndMating; + + public int m_Stage; + public int m_KPKorpre3; + + public DateTime EndMating{ get{ return m_EndMating; } set{ m_EndMating = value; } } + + public bool m_AllowMating; + public bool m_HasEgg; + public bool m_Pregnant; + + public bool m_S1; + public bool m_S2; + + public bool S1 + { + get{ return m_S1; } + set{ m_S1 = value; } + } + public bool S2 + { + get{ return m_S2; } + set{ m_S2 = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowMating + { + get{ return m_AllowMating; } + set{ m_AllowMating = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasEgg + { + get{ return m_HasEgg; } + set{ m_HasEgg = value; } + } + [CommandProperty( AccessLevel.GameMaster )] + public bool Pregnant + { + get{ return m_Pregnant; } + set{ m_Pregnant = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int KPKorpre3 + { + get{ return m_KPKorpre3; } + set{ m_KPKorpre3 = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Stage + { + get{ return m_Stage; } + set{ m_Stage = value; } + } + + [Constructable] + public EvolutionKorpre3() : this( "a Korpre" ) + { + } + + [Constructable] + public EvolutionKorpre3( string name ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Korpre"; + Body = 51; + Hue = 1759; + BaseSoundID = 456; + Stage = 1; + + S1 = true; + S2 = true; + + SetStr( 26 ); + SetDex( 19 ); + SetInt( 17 ); + + SetHits( 58 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 45 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 45 ); + SetResistance( ResistanceType.Fire, 25 ); + SetResistance( ResistanceType.Cold, 5 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 1 ); + + SetSkill( SkillName.Wrestling, 16.0, 16.5 ); + + Fame = 9000; + Karma = -10000; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 80.0; + + PackItem( new Korpre3Dust( 1 ) ); + } + + public EvolutionKorpre3(Serial serial) : base(serial) + { + } + + public override void Damage( int amount, Mobile defender ) + + { + + int KPKorpre3gainmin, KPKorpre3gainmax; + + if ( this.Stage == 1 ) + { + if ( defender is BaseCreature ) + { + BaseCreature bc = (BaseCreature)defender; + + if ( bc.Controlled != true ) + { + KPKorpre3gainmin = 5 + ( bc.HitsMax ) / 10; + KPKorpre3gainmax = 5 + ( bc.HitsMax ) / 5; + + this.KPKorpre3 += Utility.RandomList( KPKorpre3gainmin, KPKorpre3gainmax ); + } + } + + if ( this.KPKorpre3 >= 50000 ) + { + if ( this.S1 == true ) + { + this.S1 = false; + int va; + + va = ( this.VirtualArmor + 10 ); + + this.AI = AIType.AI_Mage; + this.Warmode = false; + this.Say( "*"+ this.Name +" is now a Anzuanord*"); + this.Title = "a anzuanord "; + + this.BodyValue = 22; + this.BaseSoundID = 377; + this.VirtualArmor = va; + this.Stage = 2; + + this.SetDamageType( ResistanceType.Physical, 20 ); + this.SetDamageType( ResistanceType.Fire, 20 ); + this.SetDamageType( ResistanceType.Cold, 20 ); + this.SetDamageType( ResistanceType.Poison, 20 ); + this.SetDamageType( ResistanceType.Energy, 20 ); + + this.SetResistance( ResistanceType.Physical, 39 ); + this.SetResistance( ResistanceType.Fire, 15 ); + this.SetResistance( ResistanceType.Cold, 15 ); + this.SetResistance( ResistanceType.Poison, 10 ); + this.SetResistance( ResistanceType.Energy, 100 ); + + this.SetSkill( SkillName.EvalInt, 85.6 ); + this.SetSkill( SkillName.Magery, 76.9 ); + this.SetSkill( SkillName.MagicResist, 47.5 ); + this.SetSkill( SkillName.Tactics, 85.6 ); + this.SetSkill( SkillName.Wrestling, 41.9 ); + + this.SetStr( 705 ); + this.SetDex( 909 ); + this.SetInt( 983 ); + this.SetHits( 180 ); + + this.SetDamage( 8, 10 ); + } + } + } + + else if ( this.Stage == 2 ) + { + if ( defender is BaseCreature ) + { + BaseCreature bc = (BaseCreature)defender; + + if ( bc.Controlled != true ) + { + KPKorpre3gainmin = 5 + ( bc.HitsMax ) / 30; + KPKorpre3gainmax = 5 + ( bc.HitsMax ) / 20; + + this.KPKorpre3 += Utility.RandomList( KPKorpre3gainmin, KPKorpre3gainmax ); + } + } + + if ( this.KPKorpre3 >= 250000 ) + { + if ( this.S2 == true ) + { + this.S2 = false; + int va; + + va = ( this.VirtualArmor + 10 ); + + this.AllowMating = true; + this.Warmode = false; + this.Say( "*"+ this.Name +" is now a Vasanord*"); + this.Title = "a vasanord"; + this.BodyValue = 780; + this.BaseSoundID = 0x482; + this.VirtualArmor = va; + this.Stage = 3; + + this.SetDamageType( ResistanceType.Physical, 30 ); + this.SetDamageType( ResistanceType.Fire, 30 ); + this.SetDamageType( ResistanceType.Cold, 30 ); + this.SetDamageType( ResistanceType.Poison, 30 ); + this.SetDamageType( ResistanceType.Energy, 30 ); + + this.SetResistance( ResistanceType.Physical, 20, 47 ); + this.SetResistance( ResistanceType.Fire, 20, 35 ); + this.SetResistance( ResistanceType.Cold, 20, 33 ); + this.SetResistance( ResistanceType.Poison, 100 ); + this.SetResistance( ResistanceType.Energy, 20, 29 ); + + this.SetSkill( SkillName.Magery, 100.0 ); + this.SetSkill( SkillName.MagicResist, 100.0 ); + this.SetSkill( SkillName.Tactics, 70.0 ); + this.SetSkill( SkillName.Wrestling, 80.0 ); + + this.SetStr( 880 ); + this.SetDex( 49 ); + this.SetInt( 40 ); + this.SetHits( 5079 ); + + this.SetDamage( 10, 23 ); + } + } + } + base.Damage( amount, defender ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + if ( dropped is Korpre3Dust ) + { + Korpre3Dust dust = ( Korpre3Dust )dropped; + + int amount = ( dust.Amount * 1000 ); + + this.PlaySound( 665 ); + this.KPKorpre3 += amount; + + dust.Delete(); + + this.Say( "*"+ this.Name +" absorbs the Korpre3 dust*" ); + + return false; + } + } + return base.OnDragDrop( from, dropped ); + } + + private void MatingTarget_Callback( Mobile from, object obj ) + { + if ( obj is EvolutionKorpre3 && obj is BaseCreature ) + { + BaseCreature bc = (BaseCreature)obj; + EvolutionKorpre3 ed = (EvolutionKorpre3)obj; + + if ( ed.Controlled == true && ed.ControlMaster == from ) + { + if ( ed.Female == false ) + { + if ( ed.AllowMating == true ) + { + this.Blessed = true; + this.Pregnant = true; + + m_Korpre3MatingTimer = new Korpre3MatingTimer( this, TimeSpan.FromDays( 0.0 ) ); + m_Korpre3MatingTimer.Start(); + + m_EndMating = DateTime.Now + TimeSpan.FromDays( 0.0 ); + } + else + { + from.SendMessage( "This male Korpre3 is not old enough to mate!" ); + } + } + else + { + from.SendMessage( "This Korpre3 is not male!" ); + } + } + else if ( ed.Controlled == true ) + { + if ( ed.Female == false ) + { + if ( ed.AllowMating == true ) + { + if ( ed.ControlMaster != null ) + { + ed.ControlMaster.SendGump( new Korpre3MatingGump( from, ed.ControlMaster, this, ed ) ); + from.SendMessage( "You ask the owner of the Korpre if they will let your female mate with their male." ); + } + else + { + from.SendMessage( "This Korpre is wild." ); + } + } + else + { + from.SendMessage( "This male Korpre is not old enough to mate!" ); + } + } + else + { + from.SendMessage( "This Korpre is not male!" ); + } + } + else + { + from.SendMessage( "This Korpre is wild." ); + } + } + else + { + from.SendMessage( "That is not a Korpre!" ); + } + } + + /*public override bool HandlesOnSpeech( Mobile from ) + { + if (from.InRange(this, 1)) + return true; + else + return false; + }*/ + + public override void OnSpeech(SpeechEventArgs args) + { + base.OnSpeech (args); + if (args.Speech.ToLower() == "mate Korpre3") + { + if (this.Controlled == true && this.ControlMaster == args.Mobile) + { + //if (this is EvolutionDragon) // Always true ;) + //{ + if (this.Female == true) + { + if (this.AllowMating == true) + { + if (this.Pregnant == false) + { + if (this.HasEgg == true) + { + this.HasEgg = false; + this.Pregnant = false; + this.Blessed = false; + + if (args.Mobile.Backpack != null) + { + args.Mobile.AddToBackpack(new Korpre3Egg()); + args.Mobile.SendMessage("A Korpre's egg has been placed in your backpack"); + } + else + args.Mobile.SendMessage("You broke the egg."); // If the Mobile has no backpack, the Egg is lost. + } + else + { + args.Mobile.SendMessage("Target a male Korpre to mate with this female."); + args.Mobile.BeginTarget(-1, false, TargetFlags.Harmful, new TargetCallback(MatingTarget_Callback)); + } + } + } + else + { + args.Mobile.SendMessage("This female Hen is not old enough to mate!"); + } + } + //} + } + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 1); + + writer.Write( m_AllowMating ); + writer.Write( m_HasEgg ); + writer.Write( m_Pregnant ); + writer.Write( m_S1 ); + writer.Write( m_S2 ); + writer.Write( (int) m_KPKorpre3 ); + writer.Write( (int) m_Stage ); + writer.WriteDeltaTime( m_EndMating ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_AllowMating = reader.ReadBool(); + m_HasEgg = reader.ReadBool(); + m_Pregnant = reader.ReadBool(); + m_S1 = reader.ReadBool(); + m_S2 = reader.ReadBool(); + m_KPKorpre3 = reader.ReadInt(); + m_Stage = reader.ReadInt(); + m_EndMating = reader.ReadDeltaTime(); + m_Korpre3MatingTimer = new Korpre3MatingTimer( this, m_EndMating - DateTime.Now ); + m_Korpre3MatingTimer.Start(); + + break; + } + case 0: + { + TimeSpan durationmating = TimeSpan.FromDays( 0.0 ); + + m_Korpre3MatingTimer = new Korpre3MatingTimer( this, durationmating ); + m_Korpre3MatingTimer.Start(); + m_EndMating = DateTime.Now + durationmating; + + break; + } + } + } + } + + public class Korpre3MatingTimer : Timer + { + private EvolutionKorpre3 ed; + + public Korpre3MatingTimer( EvolutionKorpre3 owner, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + ed = owner; + } + + protected override void OnTick() + { + ed.Blessed = false; + ed.HasEgg = true; + ed.Pregnant = false; + Stop(); + } + } + public class Korpre3MatingGump : Gump + { + private Mobile m_From; + private Mobile m_Mobile; + private EvolutionKorpre3 m_ED1; + private EvolutionKorpre3 m_ED2; + + public Korpre3MatingGump( Mobile from, Mobile mobile, EvolutionKorpre3 ed1, EvolutionKorpre3 ed2 ) : base( 25, 50 ) + { + Closable = false; + Dragable = false; + + m_From = from; + m_Mobile = mobile; + m_ED1 = ed1; + m_ED2 = ed2; + + AddPage( 0 ); + + AddBackground( 25, 10, 420, 200, 5054 ); + + AddImageTiled( 33, 20, 401, 181, 2624 ); + AddAlphaRegion( 33, 20, 401, 181 ); + + AddLabel( 125, 148, 1152, m_From.Name +" would like to mate "+ m_ED1.Name +" with" ); + AddLabel( 125, 158, 1152, m_ED2.Name +"." ); + + AddButton( 100, 50, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddLabel( 130, 50, 1152, "Allow them to mate." ); + AddButton( 100, 75, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddLabel( 130, 75, 1152, "Do not allow them to mate." ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( from == null ) + return; + + if ( info.ButtonID == 0 ) + { + m_From.SendMessage( m_Mobile.Name +" declines your request to mate the two Korpres." ); + m_Mobile.SendMessage( "You decline "+ m_From.Name +"'s request to mate the two Korpres." ); + } + if ( info.ButtonID == 1 ) + { + m_ED1.Blessed = true; + m_ED1.Pregnant = true; + + Korpre3MatingTimer mt = new Korpre3MatingTimer( m_ED1, TimeSpan.FromDays( 0.0 ) ); + mt.Start(); + m_ED1.EndMating = DateTime.Now + TimeSpan.FromDays( 0.0 ); + + m_From.SendMessage( m_Mobile.Name +" accepts your request to mate the two Korpres." ); + m_Mobile.SendMessage( "You accept "+ m_From.Name +"'s request to mate the two Korpres." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/KPKorpre3.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/KPKorpre3.cs new file mode 100644 index 0000000..5fd60ed --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/KPKorpre3.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Targeting; + + +namespace Server.Commands +{ + public class KPKorpre3System + { + + public static void Initialize() + { + CommandSystem.Register( "KPKorpre3", AccessLevel.Player, new CommandEventHandler( KPKorpre3_OnCommand ) ); + } + + public static void KPKorpre3_OnCommand( CommandEventArgs e ) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if( from != null ) + { + from.Target = new InternalTarget( from ); + } + } + + private class InternalTarget : Target + { + public InternalTarget( Mobile from ) : base( 8, false, TargetFlags.None ) + { + from.SendMessage ( "Target an animal that you own to check their level." ); + } + + protected override void OnTarget( Mobile from, object obj ) + { + if ( !from.Alive ) + { + from.SendMessage( "You may not do that while dead." ); + } + else if ( obj is EvolutionKorpre3 && obj is BaseCreature )//Korpre + { + BaseCreature bc = (BaseCreature)obj; + EvolutionKorpre3 ed = (EvolutionKorpre3)obj; + + if ( ed.Controlled == true && ed.ControlMaster == from ) + { + ed.PublicOverheadMessage( MessageType.Regular, ed.SpeechHue, true, ed.Name +" has "+ ed.KPKorpre3 +" kill points.", false ); + } + else + { + from.SendMessage( "You do not control this Korpre!" ); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Korpre 3 Dust.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Korpre 3 Dust.cs new file mode 100644 index 0000000..96db890 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Korpre 3 Dust.cs @@ -0,0 +1,39 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class Korpre3Dust: Item + { + [Constructable] + public Korpre3Dust() : this( 1 ) + { + } + + [Constructable] + public Korpre3Dust( int amount ) : base( 0x26B8 ) + { + Stackable = true; + Weight = 0.0; + Amount = amount; + Name = "korpre 3 dust"; + Hue = 1759; + } + + public Korpre3Dust( Serial serial ) : base ( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Korpre 3 Egg.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Korpre 3 Egg.cs new file mode 100644 index 0000000..7973bf8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Korpre/Korpre 3/Korpre 3 Egg.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Mobiles; +using Server.Misc; +using Server.Network; + +namespace Server.Items +{ + public class Korpre3Egg: Item + { + public bool m_AllowEvolution; + public Timer m_EvolutionTimer; + private DateTime m_End; + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowEvolution + { + get{ return m_AllowEvolution; } + set{ m_AllowEvolution = value; } + } + + [Constructable] + public Korpre3Egg() : base( 0x09B5 ) + { + Weight = 0.0; + Name = "a Korpre egg"; + Hue = 1759; + AllowEvolution = false; + + m_EvolutionTimer = new EvolutionTimer( this, TimeSpan.FromDays( 0.0 ) ); + m_EvolutionTimer.Start(); + m_End = DateTime.Now + TimeSpan.FromDays( 0.0 ); + } + + public Korpre3Egg( Serial serial ) : base ( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendMessage( "You must have the egg in your backpack." ); + } + else if ( this.AllowEvolution == true ) + { + this.Delete(); + from.SendMessage( "You are now the proud owner of a baby Korpre3!!" ); + + EvolutionKorpre3 Korpre3 = new EvolutionKorpre3(); + + Korpre3.Map = from.Map; + Korpre3.Location = from.Location; + + Korpre3.Controlled = true; + + Korpre3.ControlMaster = from; + + Korpre3.IsBonded = true; + } + else + { + from.SendMessage( "This Korpre3 is not ready." ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_End = reader.ReadDeltaTime(); + m_EvolutionTimer = new EvolutionTimer( this, m_End - DateTime.Now ); + m_EvolutionTimer.Start(); + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromDays( 1.0 ); + + m_EvolutionTimer = new EvolutionTimer( this, duration ); + m_EvolutionTimer.Start(); + m_End = DateTime.Now + duration; + + break; + } + } + } + + private class EvolutionTimer : Timer + { + private Korpre3Egg de; + + private int cnt = 0; + + public EvolutionTimer( Korpre3Egg owner, TimeSpan duration ) : base( duration ) + { + de = owner; + } + + protected override void OnTick() + { + cnt += 1; + + if ( cnt == 1 ) + { + de.AllowEvolution = true; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Ortanord.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Ortanord.cs new file mode 100644 index 0000000..55d4fd8 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Ortanord.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Factions; + +namespace Server.Mobiles +{ + [CorpseName( "a Wisp corpse" )] + public class Ortanord : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Wisp; } } + + [Constructable] + public Ortanord() : base( AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a ortanord"; + Body = 58; + Hue = 1766; + BaseSoundID = 466; + + SetStr( 50 ); + SetDex( 50 ); + SetInt( 50 ); + + SetHits( 100 ); + + SetDamage( 5, 8 ); + + SetDamageType( ResistanceType.Physical, 90 ); + SetDamageType( ResistanceType.Energy, 90 ); + + SetResistance( ResistanceType.Physical, 90 ); + SetResistance( ResistanceType.Fire, 90 ); + SetResistance( ResistanceType.Cold, 90 ); + SetResistance( ResistanceType.Poison, 90 ); + SetResistance( ResistanceType.Energy, 90 ); + + SetSkill( SkillName.EvalInt, 80.0 ); + SetSkill( SkillName.Magery, 80.0 ); + SetSkill( SkillName.MagicResist, 80.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 4000; + Karma = -10000; + + VirtualArmor = 40; + + AddItem( new LightSource() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public Ortanord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Vasanord.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Vasanord.cs new file mode 100644 index 0000000..cf8a561 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TerMur/Vasanord.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a plant corpse" )] + public class Vasanord : BaseCreature + { + [Constructable] + public Vasanord() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.6, 1.2 ) + { + Name = "Vasanord"; + Body = 780; + + SetStr( 805, 869 ); + SetDex( 51, 64 ); + SetInt( 38, 48 ); + + SetHits( 553, 626 ); + SetMana( 0 ); + SetStam( 51, 64 ); + + SetDamage( 10, 23 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 30, 50 ); + SetResistance( ResistanceType.Fire, 20, 40 ); + SetResistance( ResistanceType.Cold, 20, 50 ); + SetResistance( ResistanceType.Poison, 100, 100 ); + SetResistance( ResistanceType.Energy, 20, 50 ); + + SetSkill( SkillName.MagicResist, 72.8, 77.7 ); + SetSkill( SkillName.Tactics, 50.7, 99.6 ); + SetSkill( SkillName.Anatomy, 6.5, 17.1 ); + SetSkill( SkillName.EvalInt, 92.5, 106.2 ); + SetSkill( SkillName.Magery, 95.5, 106.9 ); + SetSkill( SkillName.Wrestling, 53.6, 98.6 ); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 28; + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( new Board( 10 ) ); + else + PackItem( new Log( 10 ) ); + PackItem( new DaemonBone( 30 ) ); + + PackReg( 3 ); + PackItem( new Engines.Plants.Seed() ); + PackItem( new Engines.Plants.Seed() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Vasanord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + + /*public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( this.Hits > (this.HitsMax / 4) ) + { + if ( 0.25 >= Utility.RandomDouble() ) + //SpawnBogling( attacker ); + } + else if ( 0.25 >= Utility.RandomDouble() ) + { + //EatBoglings(); + } + }*/ + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/GargoyleShade.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/GargoyleShade.cs new file mode 100644 index 0000000..f5f9a5f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/GargoyleShade.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class GargoyleShade : BaseCreature + { + [Constructable] + public GargoyleShade() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gargoyle shade"; + Body = 722; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr( 76, 78 ); + SetDex( 76, 81 ); + SetInt( 36, 48 ); + + SetHits( 60, 64 ); + SetStam( 80, 81 ); + SetMana( 75, 78 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 41 ); + SetResistance( ResistanceType.Fire, 40, 44 ); + SetResistance( ResistanceType.Cold, 10, 16 ); + SetResistance( ResistanceType.Poison, 20, 35 ); + + SetSkill( SkillName.EvalInt, 57.1, 65.5 ); + SetSkill( SkillName.Magery, 60.6, 70.1 ); + SetSkill( SkillName.MagicResist, 52.6, 70.0 ); + SetSkill( SkillName.Tactics, 52.7, 60.0 ); + SetSkill( SkillName.Wrestling, 47.7, 55.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg( 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public GargoyleShade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/Niporailem/FoolishGold.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/Niporailem/FoolishGold.cs new file mode 100644 index 0000000..4a4a182 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/Niporailem/FoolishGold.cs @@ -0,0 +1,105 @@ +using System; +using Server; + + +namespace Server.Items +{ + + public class NiporailemsTreasure : Item + { + + public override int LabelNumber{ get{ return 1112113; } } // Niporailem's Treasure + + + + [Constructable] + public NiporailemsTreasure() : base(0xEEF) + { + Weight = 100.0; + } + + public NiporailemsTreasure(Serial serial) : base(serial) + { + + } + + public override bool DropToWorld( Mobile from, Point3D p ) + { + bool convert = base.DropToWorld( from, p ); + + if ( convert ) + ConvertItem( from ); + + return convert; + } + + public override bool DropToMobile( Mobile from, Mobile target, Point3D p ) + { + bool convert = base.DropToMobile( from, target, p ); + + if ( convert ) + ConvertItem( from ); + + return convert; + } + + public override bool DropToItem( Mobile from, Item target, Point3D p ) + { + bool convert = base.DropToItem( from, target, p ); + + if ( convert && Parent != from.Backpack ) + ConvertItem( from ); + + return convert; + } + + public virtual void ConvertItem( Mobile from ) + { + from.SendLocalizedMessage( 1112112 ); // To carry the burden of greed! + Delete(); + from.AddToBackpack( new TreasureSand() ); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class TreasureSand : Item + { + + public override int LabelNumber{ get{ return 1112115; } } // Treasure Sand + + + + [Constructable] + public TreasureSand() : base(0x11EA) + { + Weight = 25.0; + } + + public TreasureSand(Serial serial) : base(serial) + { + + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/Niporailem/Niporailem.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/Niporailem/Niporailem.cs new file mode 100644 index 0000000..2ceff0f --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/Niporailem/Niporailem.cs @@ -0,0 +1,176 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "the corpse of niporailem" )] + public class Niporailem : BaseCreature + { + [Constructable] + public Niporailem() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "niporailem"; + Title = "the thief"; + + Body = 722; + + SetStr( 1000, 1200 ); + SetDex( 1200 ); + SetInt( 1200 ); + + SetHits( 2654, 3988 ); + + SetDamage( 15, 27 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 42 ); + SetResistance( ResistanceType.Fire, 29 ); + SetResistance( ResistanceType.Cold, 53, 56 ); + SetResistance( ResistanceType.Poison, 23, 24 ); + SetResistance( ResistanceType.Energy, 34, 39 ); + + SetSkill( SkillName.MagicResist, 87.7, 93.5 ); + SetSkill( SkillName.Tactics, 56.1, 65.0 ); + SetSkill( SkillName.Wrestling, 68.8, 76.2 ); + + PackNecroReg( 12, 24 ); /// Stratics didn't specify + + Fame = 15000; + Karma = -15000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 6 ); + AddLoot(LootPack.Gems, 6); + } + + public override int Meat{ get{ return 1; } } + public override bool AlwaysMurderer{ get{ return true; } } + + public override int GetIdleSound() { return 1609; } + public override int GetAngerSound() { return 1606; } + public override int GetHurtSound() { return 1608; } + public override int GetDeathSound() { return 1607; } + + + + + public Niporailem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public void SpawnSpectralArmour( Mobile m ) + { + Map map = this.Map; + + if ( map == null ) + return; + + SpectralArmour spawned = new SpectralArmour(); + + spawned.Team = this.Team; + + bool validLocation = false; + Point3D loc = this.Location; + + for ( int j = 0; !validLocation && j < 10; ++j ) + { + int x = X + Utility.Random( 3 ) - 1; + int y = Y + Utility.Random( 3 ) - 1; + int z = map.GetAverageZ( x, y ); + + if ( validLocation = map.CanFit( x, y, this.Z, 16, false, false ) ) + loc = new Point3D( x, y, Z ); + else if ( validLocation = map.CanFit( x, y, z, 16, false, false ) ) + loc = new Point3D( x, y, z ); + } + + spawned.MoveToWorld( loc, map ); + spawned.Combatant = m; + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( this.Hits > (this.HitsMax / 4) ) + { + if ( 0.25 >= Utility.RandomDouble() ) + SpawnSpectralArmour( attacker ); + } + else if ( 0.10 >= Utility.RandomDouble() ) + { + SpawnSpectralArmour( attacker ); + } + } + + private DateTime m_NextTreasure; + private int m_Thrown; + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != Map || !InRange( combatant, 12 ) || !CanBeHarmful( combatant ) || !InLOS( combatant ) ) + return; + + if ( DateTime.Now >= m_NextTreasure ) + { + ThrowTreasure( combatant ); + + m_Thrown++; + + if ( 0.75 >= Utility.RandomDouble() && (m_Thrown % 2) == 1 ) // 75% chance to toss a second one + m_NextTreasure = DateTime.Now + TimeSpan.FromSeconds( 3.0 ); + else + m_NextTreasure = DateTime.Now + TimeSpan.FromSeconds( 5.0 + (10.0 * Utility.RandomDouble()) ); // 5-15 seconds + } + } + + public void ThrowTreasure( Mobile m ) + { + DoHarmful( m ); + + this.MovingParticles( m, 0xEEF, 1, 0, false, true, 0, 0, 9502, 6014, 0x11D, EffectLayer.Waist, 0 ); + + new InternalTimer( m, this ).Start(); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile, m_From; + + public InternalTimer( Mobile m, Mobile from ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound( 0x033 ); + m_Mobile.AddToBackpack( new NiporailemsTreasure() ); + m_Mobile.SendLocalizedMessage( 1112111 ); // To steal my gold? To give it freely! + } + } + + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/PutridUndeadGuardian.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/PutridUndeadGuardian.cs new file mode 100644 index 0000000..207def9 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/PutridUndeadGuardian.cs @@ -0,0 +1,69 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "an putrid undead guardian corpse" )] + public class PutridUndeadGuardian : BaseCreature + { + [Constructable] + public PutridUndeadGuardian() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an putrid undead guardian"; + Body = 722; + + SetStr( 79 ); + SetDex( 63 ); + SetInt( 187 ); + + SetHits( 553 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40 ); + SetResistance( ResistanceType.Fire, 23 ); + SetResistance( ResistanceType.Cold, 57 ); + SetResistance( ResistanceType.Poison, 29 ); + SetResistance( ResistanceType.Energy, 39 ); + + SetSkill( SkillName.MagicResist, 62.7 ); + SetSkill( SkillName.Tactics, 45.4 ); + SetSkill( SkillName.Wrestling, 50.7 ); + + PackNecroReg( 10, 15 ); /// Stratics didn't specify + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + } + + public override int Meat{ get{ return 1; } } + + public override int GetIdleSound() { return 1609; } + public override int GetAngerSound() { return 1606; } + public override int GetHurtSound() { return 1608; } + public override int GetDeathSound() { return 1607; } + + public PutridUndeadGuardian( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/UndeadGuardian.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/UndeadGuardian.cs new file mode 100644 index 0000000..b5ab4b9 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/TombofKings/UndeadGuardian.cs @@ -0,0 +1,70 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "an undead guardian corpse" )] + public class UndeadGuardian : BaseCreature + { + [Constructable] + public UndeadGuardian() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an undead guardian"; + Body = 722; + + SetStr( 212 ); + SetDex( 76 ); + SetInt( 56 ); + + SetHits( 138 ); + + SetDamage( 8, 18 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 38 ); + SetResistance( ResistanceType.Fire, 24 ); + SetResistance( ResistanceType.Cold, 58 ); + SetResistance( ResistanceType.Poison, 28 ); + SetResistance( ResistanceType.Energy, 38 ); + + SetSkill( SkillName.MagicResist, 66.6 ); + SetSkill( SkillName.Tactics, 86.2 ); + SetSkill( SkillName.Wrestling, 86.9 ); + + PackNecroReg( 10, 15 ); /// Stratics didn't specify + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + } + + public override int Meat{ get{ return 1; } } + + public override int GetIdleSound() { return 1609; } + public override int GetAngerSound() { return 1606; } + public override int GetHurtSound() { return 1608; } + public override int GetDeathSound() { return 1607; } + + public UndeadGuardian( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/AcidElemental.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/AcidElemental.cs new file mode 100644 index 0000000..06efb1b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/AcidElemental.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public interface IAcidCreature + { + } + + [CorpseName( "an acid elementals corpse" )] + public class SAAcidElemental : BaseCreature, IAcidCreature + { + [Constructable] + public SAAcidElemental() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "an acid elemental"; + Body = 162; + BaseSoundID = 263; + + SetStr( 326, 355 ); + SetDex( 66, 85 ); + SetInt( 271, 295 ); + + SetHits( 196, 213 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Poison, 90 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 30.3, 60.0 ); + SetSkill( SkillName.EvalInt, 80.1, 95.0 ); + SetSkill( SkillName.Magery, 70.1, 85.0 ); + SetSkill( SkillName.Meditation, 0.0, 0.0 ); + SetSkill( SkillName.MagicResist, 60.1, 85.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 70.1, 90.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 70; + + PackItem( new Nightshade( 4 ) ); +// PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.75; } } + + public override int TreasureMapLevel{ get{ return 2; } } + + public SAAcidElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/AcidSlug.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/AcidSlug.cs new file mode 100644 index 0000000..623af0b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/AcidSlug.cs @@ -0,0 +1,80 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "an acid slug corpse" )] + public class AcidSlug : BaseCreature, IAcidCreature + { + [Constructable] + public AcidSlug() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an acid slug"; + Body = 51; + Hue = 44; + + SetStr( 213, 294 ); + SetDex( 80, 82 ); + SetInt( 18, 22 ); + + SetHits( 333, 370 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 0 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 25.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + if ( 0.1 > Utility.RandomDouble() ) + PackItem( new VialOfVitriol() ); + + if ( 0.75 > Utility.RandomDouble() ) + PackItem( new AcidSac() ); + + //PackItem( new CongealedSlugAcid() ); + + Fame = 1000; + Karma = -1000; + + Tamable = false; + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int GetIdleSound() { return 1499; } + public override int GetAngerSound() { return 1496; } + public override int GetHurtSound() { return 1498; } + public override int GetDeathSound() { return 1497; } + + public AcidSlug( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/BloodWorm.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/BloodWorm.cs new file mode 100644 index 0000000..3a772bb --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/BloodWorm.cs @@ -0,0 +1,66 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a bloodworm corpse" )] + public class BloodWorm : BaseCreature + { + [Constructable] + public BloodWorm() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bloodworm"; + Body = 287; + + SetStr( 420 ); + SetDex( 80 ); + SetInt( 18 ); + + SetHits( 365 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 49 ); + SetResistance( ResistanceType.Fire, 50 ); + SetResistance( ResistanceType.Cold, 35 ); + SetResistance( ResistanceType.Poison, 69 ); + SetResistance( ResistanceType.Energy, 26 ); + + SetSkill( SkillName.MagicResist, 35.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override int GetIdleSound() { return 1503; } + public override int GetAngerSound() { return 1500; } + public override int GetHurtSound() { return 1502; } + public override int GetDeathSound() { return 1501; } + + public BloodWorm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/EnragedEarthElemental.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/EnragedEarthElemental.cs new file mode 100644 index 0000000..d531f72 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/EnragedEarthElemental.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an earth elemental corpse" )] + public class EnragedEarthElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public EnragedEarthElemental() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enraged earth elemental"; + Body = 14; + BaseSoundID = 268; + + SetStr( 125, 129 ); + SetDex( 66, 86 ); + SetInt( 71, 92 ); + + SetHits( 500,505 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60, 62 ); + SetResistance( ResistanceType.Fire, 20, 24 ); + SetResistance( ResistanceType.Cold, 20, 29 ); + SetResistance( ResistanceType.Poison, 45, 50 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 100.1, 120.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 34; + ControlSlots = 2; + + PackItem( new FertileDirt( Utility.RandomMinMax( 1, 4 ) ) ); + PackItem( new MandrakeRoot() ); + + Item ore = new IronOre( 5 ); + ore.ItemID = 0x19B7; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Gems ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public EnragedEarthElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblin Mage.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblin Mage.cs new file mode 100644 index 0000000..ce6c360 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblin Mage.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class EnslavedGoblinMage : BaseCreature + { + [Constructable] + public EnslavedGoblinMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved goblin mage"; + Body = 723; + Hue = 2500; + BaseSoundID = 0x45A; + + SetStr( 294 ); + SetDex( 79 ); + SetInt( 488 ); + + SetHits( 154 ); + SetStam( 79 ); + SetMana( 488 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 29 ); + SetResistance( ResistanceType.Fire, 36 ); + SetResistance( ResistanceType.Cold, 34 ); + SetResistance( ResistanceType.Poison, 41 ); + SetResistance( ResistanceType.Energy, 20 ); + + SetSkill( SkillName.EvalInt, 107.7 ); + SetSkill( SkillName.Magery, 104.4 ); + SetSkill( SkillName.MagicResist, 145.2 ); + SetSkill( SkillName.Tactics, 89.2 ); + SetSkill( SkillName.Anatomy, 87.0 ); + SetSkill( SkillName.Wrestling, 93.4 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public EnslavedGoblinMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblin.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblin.cs new file mode 100644 index 0000000..bb3935e --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblin.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class EnslavedGrayGoblin : BaseCreature + { + [Constructable] + public EnslavedGrayGoblin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved gray goblin"; + Body = 723; + Hue = 2500; + BaseSoundID = 0x45A; + + SetStr( 331 ); + SetDex( 69 ); + SetInt( 114 ); + + SetHits( 200 ); + SetStam( 69 ); + SetMana( 114 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 43 ); + SetResistance( ResistanceType.Fire, 36 ); + SetResistance( ResistanceType.Cold, 33 ); + SetResistance( ResistanceType.Poison, 15 ); + SetResistance( ResistanceType.Energy, 12 ); + + SetSkill( SkillName.MagicResist, 123.7, 123.9 ); + SetSkill( SkillName.Tactics, 82.0 ); + SetSkill( SkillName.Anatomy, 88.9 ); + SetSkill( SkillName.Wrestling, 96.1 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public EnslavedGrayGoblin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblinKeeper.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblinKeeper.cs new file mode 100644 index 0000000..69dd3b2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayEnslavedGoblinKeeper.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class EnslavedGoblinKeeper : BaseCreature + { + [Constructable] + public EnslavedGoblinKeeper() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved goblin keeper"; + Body = 723; + Hue = 2500; + BaseSoundID = 0x45A; + + SetStr( 326 ); + SetDex( 79 ); + SetInt( 114 ); + + SetHits( 186 ); + SetStam( 79 ); + SetMana( 114 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45 ); + SetResistance( ResistanceType.Fire, 33 ); + SetResistance( ResistanceType.Cold, 25 ); + SetResistance( ResistanceType.Poison, 20 ); + SetResistance( ResistanceType.Energy, 10 ); + + SetSkill( SkillName.MagicResist, 129.9 ); + SetSkill( SkillName.Tactics, 86.7 ); + SetSkill( SkillName.Anatomy, 86.6 ); + SetSkill( SkillName.Wrestling, 103.6 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public EnslavedGoblinKeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblin.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblin.cs new file mode 100644 index 0000000..da68345 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblin.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class GrayGoblin : BaseCreature + { + [Constructable] + public GrayGoblin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gray goblin"; + Body = 334; + BaseSoundID = 0x45A; + + SetStr( 258, 327 ); + SetDex( 62, 80 ); + SetInt( 103, 150 ); + + SetHits( 159, 194 ); + SetStam( 62, 80 ); + SetMana( 103, 150 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 25, 32 ); + SetResistance( ResistanceType.Poison, 10, 19 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 120.9, 129.1 ); + SetSkill( SkillName.Tactics, 80.6, 89.4 ); + SetSkill( SkillName.Anatomy, 80.3, 89.4 ); + SetSkill( SkillName.Wrestling, 96.1, 105.5 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public GrayGoblin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblinKeeper.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblinKeeper.cs new file mode 100644 index 0000000..b347d3a --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblinKeeper.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin keeper corpse" )] + public class GrayGoblinKeeper : BaseCreature + { + [Constructable] + public GrayGoblinKeeper() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gray goblin keeper"; + Body = 334; + BaseSoundID = 0x45A; + + SetStr( 326 ); + SetDex( 79 ); + SetInt( 114 ); + + SetHits( 186 ); + SetStam( 79 ); + SetMana( 114 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45 ); + SetResistance( ResistanceType.Fire, 33 ); + SetResistance( ResistanceType.Cold, 25 ); + SetResistance( ResistanceType.Poison, 20 ); + SetResistance( ResistanceType.Energy, 10 ); + + SetSkill( SkillName.MagicResist, 129.9 ); + SetSkill( SkillName.Tactics, 86.7 ); + SetSkill( SkillName.Anatomy, 86.6 ); + SetSkill( SkillName.Wrestling, 103.6 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public GrayGoblinKeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblinMage.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblinMage.cs new file mode 100644 index 0000000..3dbf7bd --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GrayGoblinMage.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin mage corpse" )] + public class GrayGoblinMage : BaseCreature + { + [Constructable] + public GrayGoblinMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gray goblin mage"; + Body = 334; + BaseSoundID = 0x45A; + + SetStr( 227, 285 ); + SetDex( 70, 88 ); + SetInt( 451, 499 ); + + SetHits( 129, 151 ); + SetStam( 70, 88 ); + SetMana( 451, 499 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 25, 32 ); + SetResistance( ResistanceType.Poison, 10, 19 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 141.9, 147.1 ); + SetSkill( SkillName.Tactics, 80.7, 86.9 ); + SetSkill( SkillName.Anatomy, 81.9, 89.4 ); + SetSkill( SkillName.Wrestling, 90.5, 104.2 ); + SetSkill( SkillName.Magery, 105.5, 119.1 ); + SetSkill( SkillName.EvalInt, 94.9, 107.7 ); + + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public GrayGoblinMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblin.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblin.cs new file mode 100644 index 0000000..30efec3 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblin.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class EnslavedGreenGoblin : BaseCreature + { + [Constructable] + public EnslavedGreenGoblin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved green goblin"; + Body = 723; + BaseSoundID = 0x45A; + + SetStr( 275 ); + SetDex( 77 ); + SetInt( 113 ); + + SetHits( 200 ); + SetStam( 77 ); + SetMana( 113 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 42 ); + SetResistance( ResistanceType.Fire, 38 ); + SetResistance( ResistanceType.Cold, 26 ); + SetResistance( ResistanceType.Poison, 12 ); + SetResistance( ResistanceType.Energy, 18 ); + + SetSkill( SkillName.MagicResist, 120.2 ); + SetSkill( SkillName.Tactics, 89.5 ); + SetSkill( SkillName.Anatomy, 81.4 ); + SetSkill( SkillName.Wrestling, 106.8 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + // loot 60 gold, magic item, gem, bola ball, liquar,gob blood + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 1 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + //public override bool IsEnemy( Mobile m ) + //{ + // if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + // return false; + + // return base.IsEnemy( m ); + //} + + //public override void AggressiveAction( Mobile aggressor, bool criminal ) + //{ + //base.AggressiveAction( aggressor, criminal ); + + //Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + //if ( item is OrcishKinMask ) + //{ + // AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + // item.Delete(); + // aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + // aggressor.PlaySound( 0x307 ); + //} + //} + + public EnslavedGreenGoblin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblinAlchemist.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblinAlchemist.cs new file mode 100644 index 0000000..3b883bd --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblinAlchemist.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class EnslavedGreenGoblinAlchemist : BaseCreature + { + [Constructable] + public EnslavedGreenGoblinAlchemist() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved goblin alchemist"; + Body = 723; + BaseSoundID = 0x45A; + + SetStr( 316 ); + SetDex( 61 ); + SetInt( 316 ); + + SetHits( 179 ); + SetStam( 61 ); + SetMana( 316 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 42 ); + SetResistance( ResistanceType.Fire, 50 ); + SetResistance( ResistanceType.Cold, 34 ); + SetResistance( ResistanceType.Poison, 37 ); + SetResistance( ResistanceType.Energy, 15 ); + + SetSkill( SkillName.MagicResist, 128.9 ); + SetSkill( SkillName.Tactics, 80.3 ); + SetSkill( SkillName.Wrestling, 98.2 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + // loot 60 gold, magic item, gem, bola ball, liquar,gob blood + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 1 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + //public override bool IsEnemy( Mobile m ) + //{ + // if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + // return false; + + // return base.IsEnemy( m ); + //} + + //public override void AggressiveAction( Mobile aggressor, bool criminal ) + //{ + //base.AggressiveAction( aggressor, criminal ); + + //Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + //if ( item is OrcishKinMask ) + //{ + // AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + // item.Delete(); + // aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + // aggressor.PlaySound( 0x307 ); + //} + //} + + public EnslavedGreenGoblinAlchemist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblinScout.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblinScout.cs new file mode 100644 index 0000000..e74b3c2 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenEnslavedGoblinScout.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class EnslavedGoblinScout : BaseCreature + { + [Constructable] + public EnslavedGoblinScout() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved goblin scout"; + Body = 723; + BaseSoundID = 0x45A; + + SetStr( 336 ); + SetDex( 75 ); + SetInt( 138 ); + + SetHits( 174 ); + SetStam( 75 ); + SetMana( 138 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 41 ); + SetResistance( ResistanceType.Fire, 30 ); + SetResistance( ResistanceType.Cold, 30 ); + SetResistance( ResistanceType.Poison, 20 ); + SetResistance( ResistanceType.Energy, 14 ); + + SetSkill( SkillName.MagicResist, 98.6 ); + SetSkill( SkillName.Tactics, 84.1 ); + SetSkill( SkillName.Anatomy, 86.2 ); + SetSkill( SkillName.Wrestling, 109.1 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + // loot 60 gold, magic item, gem, bola ball, liquar,gob blood + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 1 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + //public override bool IsEnemy( Mobile m ) + //{ + // if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + // return false; + + // return base.IsEnemy( m ); + //} + + //public override void AggressiveAction( Mobile aggressor, bool criminal ) + //{ + //base.AggressiveAction( aggressor, criminal ); + + //Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + //if ( item is OrcishKinMask ) + //{ + // AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + // item.Delete(); + // aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + // aggressor.PlaySound( 0x307 ); + //} + //} + + public EnslavedGoblinScout( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblin.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblin.cs new file mode 100644 index 0000000..2dc35b4 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblin.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class GreenGoblin : BaseCreature + { + //public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public GreenGoblin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a green goblin"; + Body = 723; + BaseSoundID = 0x45A; + + SetStr( 329, 329 ); + SetDex( 67, 67 ); + SetInt( 137, 137 ); + + SetHits( 191, 191 ); + SetStam( 67, 67 ); + SetMana( 137, 137 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 49, 49 ); + SetResistance( ResistanceType.Fire, 37, 37 ); + SetResistance( ResistanceType.Cold, 35, 35 ); + SetResistance( ResistanceType.Poison, 17, 17 ); + SetResistance( ResistanceType.Energy, 15, 15 ); + + SetSkill( SkillName.MagicResist, 123.9, 123.9 ); + SetSkill( SkillName.Tactics, 87.3, 87.3 ); + SetSkill( SkillName.Anatomy, 81.3, 81.3 ); + SetSkill( SkillName.Wrestling, 101.0, 101.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + //public override bool IsEnemy( Mobile m ) + //{ + // if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + // return false; + + // return base.IsEnemy( m ); + //} + + //public override void AggressiveAction( Mobile aggressor, bool criminal ) + //{ + //base.AggressiveAction( aggressor, criminal ); + + //Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + //if ( item is OrcishKinMask ) + //{ + // AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + // item.Delete(); + // aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + // aggressor.PlaySound( 0x307 ); + //} + //} + + public GreenGoblin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblinAlchemist.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblinAlchemist.cs new file mode 100644 index 0000000..4dafadb --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblinAlchemist.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a goblin corpse" )] + public class GreenGoblinAlchemist : BaseCreature + { + //public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public GreenGoblinAlchemist() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a green goblin alchemist"; + Body = 723; + BaseSoundID = 0x45A; + + SetStr( 410, 420 ); + SetDex( 75, 80 ); + SetInt( 15, 18 ); + + SetHits( 350, 365 ); + SetStam( 75, 80 ); + SetMana( 15, 18 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 45 ); + SetResistance( ResistanceType.Fire, 45, 47 ); + SetResistance( ResistanceType.Cold, 35, 36 ); + SetResistance( ResistanceType.Poison, 35, 37 ); + SetResistance( ResistanceType.Energy, 15, 20 ); + + SetSkill( SkillName.MagicResist, 124.1, 124.2 ); + SetSkill( SkillName.Tactics, 75.3, 80.1 ); + SetSkill( SkillName.Anatomy, 0.0, 0.0 ); + SetSkill( SkillName.Wrestling, 105.4, 107.4 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + // loot 60 gold, magic item, gem, bola ball, liquar,gob blood + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib ); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + //public override bool IsEnemy( Mobile m ) + //{ + // if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + // return false; + + // return base.IsEnemy( m ); + //} + + //public override void AggressiveAction( Mobile aggressor, bool criminal ) + //{ + //base.AggressiveAction( aggressor, criminal ); + + //Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + //if ( item is OrcishKinMask ) + //{ + // AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + // item.Delete(); + // aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + // aggressor.PlaySound( 0x307 ); + //} + //} + + public GreenGoblinAlchemist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblinScout.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblinScout.cs new file mode 100644 index 0000000..5aa121b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Goblin/GreenGoblinScout.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName("a goblin corpse")] + public class GreenGoblinScout : BaseCreature + { + //public override InhumanSpeech SpeechType { get { return InhumanSpeech.Orc; } } + + [Constructable] + public GreenGoblinScout() + : base(AIType.AI_OrcScout, FightMode.Closest, 10, 7, 0.2, 0.4) + { + Name = "a green goblin scout"; + Body = 723; + BaseSoundID = 0x45A; + + SetStr(250, 261); + SetDex(65, 70); + SetInt(105, 108); + + SetHits(200, 204); + SetMana(100, 108); + + SetDamage(5, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 35, 45); + SetResistance(ResistanceType.Fire, 30, 33); + SetResistance(ResistanceType.Cold, 25, 28); + SetResistance(ResistanceType.Poison, 10, 13); + SetResistance(ResistanceType.Energy, 10, 11); + + SetSkill(SkillName.MagicResist, 105.1, 110.2); + SetSkill(SkillName.Tactics, 85.1, 89.1); + + SetSkill(SkillName.Wrestling, 90.1, 92.9); + SetSkill(SkillName.Anatomy, 70.1, 80.3); + + + Fame = 1500; + Karma = -1500; + + + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.SavagesAndOrcs; } + } + + + private Mobile FindTarget() + { + foreach (Mobile m in this.GetMobilesInRange(10)) + { + if (m.Player && m.Hidden && m.AccessLevel == AccessLevel.Player) + { + return m; + } + } + + return null; + } + + private void TryToDetectHidden() + { + Mobile m = FindTarget(); + + if (m != null) + { + if (DateTime.Now >= this.NextSkillTime && UseSkill(SkillName.DetectHidden)) + { + Target targ = this.Target; + + if (targ != null) + targ.Invoke(this, this); + + Effects.PlaySound(this.Location, this.Map, 0x340); + } + } + } + + public override void OnThink() + { + if (Utility.RandomDouble() < 0.2) + TryToDetectHidden(); + } + + public override bool CanRummageCorpses { get { return true; } } + public override int Meat { get { return 1; } } + + public GreenGoblinScout(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/GreaterPoisonElemental.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/GreaterPoisonElemental.cs new file mode 100644 index 0000000..53d8ba7 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/GreaterPoisonElemental.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a poison elementals corpse" )] + public class GreaterPoisonElemental : BaseCreature + { + [Constructable] + public GreaterPoisonElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Greater Poison Elemental"; + Body = 162; + BaseSoundID = 263; + + SetStr( 700, 771 ); + SetDex( 195, 203 ); + SetInt( 650, 691 ); + + SetHits( 650, 702 ); + SetStam( 300, 322 ); + SetMana( 500, 530 ); + + SetDamage( 12, 18 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Poison, 90 ); + + SetResistance( ResistanceType.Physical, 60, 61 ); + SetResistance( ResistanceType.Fire, 20, 24 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 49 ); + + SetSkill( SkillName.EvalInt, 80.1, 88.3 ); + SetSkill( SkillName.Magery, 80.1, 97.0 ); + SetSkill( SkillName.Meditation, 80.2, 105.8 ); + SetSkill( SkillName.Poisoning, 100.1, 114.9 ); + SetSkill( SkillName.MagicResist, 85.2, 93.2 ); + SetSkill( SkillName.Tactics, 80.1, 87.3 ); + SetSkill( SkillName.Wrestling, 80.1, 88.3 ); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 70; + + PackItem( new Nightshade( 4 ) ); + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.75; } } + + public override int TreasureMapLevel{ get{ return 5; } } + + public GreaterPoisonElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Gremlin.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Gremlin.cs new file mode 100644 index 0000000..6e0569b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Gremlin.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a gremlin corpse" )] + public class Gremlin : BaseCreature + { + [Constructable] + public Gremlin() : base( AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gremlin"; + Body = 724; + + SetStr( 106 ); + SetDex( 130 ); + SetInt( 36 ); + + SetHits( 70 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 26 ); + SetResistance( ResistanceType.Fire, 36 ); + SetResistance( ResistanceType.Cold, 22 ); + SetResistance( ResistanceType.Poison, 17 ); + SetResistance( ResistanceType.Energy, 30 ); + + SetSkill( SkillName.Anatomy, 78.5 ); + SetSkill( SkillName.MagicResist, 82.5 ); + SetSkill( SkillName.Tactics, 65.3 ); + + AddItem( new Bow() ); + PackItem( new Arrow( Utility.RandomMinMax( 60, 80 ) ) ); + + Apple fruit = new Apple(5); + if (Utility.RandomDouble() <= 0.15) + fruit.Poison = Poison.Regular; + PackItem( fruit); + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public Gremlin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IBShovel.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IBShovel.cs new file mode 100644 index 0000000..0c9479c --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IBShovel.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class IBShovel : BaseHarvestTool + { + public override HarvestSystem HarvestSystem{ get{ return Mining.System; } } + + [Constructable] + public IBShovel() : this( 1000 ) + { + } + + [Constructable] + public IBShovel( int uses ) : base( uses, 0xF39 ) + { + Name = "Iron Beetle Mining Shovel"; + Weight = 5.0; + Hue = 1150; + } + + public IBShovel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IronBeetle.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IronBeetle.cs new file mode 100644 index 0000000..bed8ff0 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IronBeetle.cs @@ -0,0 +1,1002 @@ +using System; +using Server; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Gumps; +using Server.Network; +using Server.Menus; +using Server.ContextMenus; +using Server.Menus.Questions; +using Server.Targeting; +using Server.Engines.Harvest; +using Server.Regions; +using Server.Mobiles; +using System.Runtime.Serialization; +using System.IO; +using System.Diagnostics; +using System.Text; +using Server.Misc; +using System.Text.RegularExpressions; +using Server.Commands; + +namespace Server.Mobiles +{ + [CorpseName("an Iron beetle corpse")] + public class IronBeetle : BaseCreature + { + private static int[] m_MountainAndCaveTiles = new int[] + { + 113, 114, 115, 116, 117, 118, 119, 120, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 296, 296, 297, + 321, 322, 323, 324, 467, 468, 469, 470, 471, 472, + 473, 474, 476, 477, 478, 479, 480, 481, 482, 483, + 484, 485, 486, 487, 492, 493, 494, 495, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, + 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, + 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 577, 578, 579, 581, 582, 583, 584, 585, + 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, + 596, 597, 598, 599, 600, 601, 610, 611, 612, 613, + + 1010, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, + 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1771, 1772, + 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, + 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1801, 1802, + 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1811, 1812, 1813, + 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, + 1824, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, + 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, + 1850, 1851, 1852, 1853, 1854, 1861, 1862, 1863, 1864, 1865, + 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, + 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1981, + 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, + 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2028, 2029, 2030, 2031, 2032, 2033, 2100, + 2101, 2102, 2103, 2104, 2105, + + 0x453B, 0x453C, 0x453D, 0x453E, 0x453F, 0x4540, 0x4541, + 0x4542, 0x4543, 0x4544, 0x4545, 0x4546, 0x4547, 0x4548, + 0x4549, 0x454A, 0x454B, 0x454C, 0x454D, 0x454E, 0x454F + }; + + public bool m_Mine; + private DateTime m_NextUse; + private bool m_Crafted; + private double m_SummonScalar; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextUse { get { return m_NextUse; } set { m_NextUse = value; } } + + public bool Crafted + { + get { return m_Crafted;} + set + { + if (m_Crafted == value) + return; + else if (value) + ScaleProps(); + + InvalidateProperties(); + } + } + + public double SummonScalar + { + get { return m_SummonScalar; } + set { m_SummonScalar = value; } + } + + public override bool SubdueBeforeTame { get { return true; } } + + [Constructable] + public IronBeetle() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "an Iron beetle"; + Body = 714; + BaseSoundID = 397; + + SetStr(760, 886 ); + SetDex(66, 75); + SetInt(36, 51); + + SetHits(765, 880); + SetMana(36, 51); + + SetDamage(15, 20); + + SetDamageType(ResistanceType.Physical, 90); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 20, 40); + SetResistance(ResistanceType.Energy, 45, 55); + + SetSkill(SkillName.Anatomy, 80, 89); + SetSkill(SkillName.MagicResist, 120, 129); + SetSkill(SkillName.Tactics, 82.6, 97); + SetSkill(SkillName.Wrestling, 94.8, 108); + SetSkill(SkillName.Blacksmith, 120.0); + SetSkill(SkillName.Mining, 70); + Skills.Mining.Cap = 105; + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 38; + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 98; + + Container pack = Backpack; + //if (pack != null) pack.Delete(); + pack = new StrongBackpack(); + pack.Movable = false; + pack.DropItem(new Pickaxe()); + } + + public void ScaleProps() + { + Str = (int)(Str*SummonScalar); + HitsMaxSeed = (int)(HitsMaxSeed * SummonScalar); + for (int i = 0; i < this.Skills.Length; i++) + { + Skill skill = (Skill)this.Skills[i]; + + if (skill.Base > 0.0) + skill.Base *= SummonScalar; + } + } + + public override double GetControlChance(Mobile m, bool useBaseSkill) +{ + if(Controlled) + return 0.9; + else + return base.GetControlChance(m, useBaseSkill); +} + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Gems); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + +// if (Utility.RandomDouble() < 0.1) +// c.DropItem(new UndamagedIronBeetleScale()); + + if (Utility.RandomDouble() < 0.15) + c.DropItem(new IBShovel()); + + } + + + + public override bool IsBondable + { + get + { + return false; + } + } + public override bool CanRummageCorpses { get { return true; } } + public override int Meat { get { return 1; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + public override DeathMoveResult GetInventoryMoveResultFor(Item item) { return DeathMoveResult.MoveToCorpse; } + public override bool AllowEquipFrom(Mobile from) { return (ControlMaster != null && ControlMaster == from); } + public override bool CanBeRenamedBy(Mobile from) { return (ControlMaster != null && ControlMaster == from); } + public override bool CanPaperdollBeOpenedBy(Mobile from) { return false; } + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) { return PackAnimal.CheckAccess(this, from); } + public override bool CheckNonlocalLift(Mobile from, Item item) { return PackAnimal.CheckAccess(this, from); } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) return false; + PackAnimal.CombineBackpacks(this); + return base.OnBeforeDeath(); + } + + + public override bool IsSnoop(Mobile from) + { + if (PackAnimal.CheckAccess(this, from)) return false; + return base.IsSnoop(from); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + this.Skills.Mining.Cap = 100; + if (CheckFeed(from, item)) return true; + if (PackAnimal.CheckAccess(this, from)) + { + if (item is BaseOre) + { + BaseOre m_Ore = item as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + from.SendLocalizedMessage(501989); // You burn away the impurities but are left with no useable metal. + m_Ore.Delete(); + return true; + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.Hue = m_Ore.Hue; + + from.PlaySound(0x57); + + AddToBackpack(item); + AddToBackpack(ingot); + + + return true; + } + } + + return base.OnDragDrop(from, item); + } + + public override void OnSpeech(SpeechEventArgs args) + { + string said = args.Speech.ToLower(); + Mobile from = args.Mobile; + string bmine = this.Name + " " + "mine"; + string bmine2 = bmine.ToLower(); + string bbreak = this.Name + " " + "takebreak"; + string bbreak2 = bbreak.ToLower(); + string bbreak3 = this.Name + " " + "take break"; + string bbreak4 = bbreak3.ToLower(); + if (said == this.Name.ToLower()) + { + if (from == this.ControlMaster) + { + this.Say("Yes?"); + } + else + { + + this.Say("You are not my master."); + + } + } + + else if ((said == "mine" || said == bmine2) && from == this.ControlMaster) { m_Mine = true; ControlOrder = OrderType.Stay; } + else if ((said == "takebreak" || said == "take break" || said == bbreak2 || said == bbreak4) && from == this.ControlMaster) { m_Mine = false; ControlOrder = OrderType.Follow; this.Hue = 0; } + base.OnSpeech(args); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + PackAnimal.GetContextMenuEntries(this, from, list); + } + + public override void OnThink() + { + if (this.Alive && this.m_Mine && this.m_NextUse <= DateTime.Now) + { + Container backpack = this.Backpack; + + if ( backpack == null) { m_NextUse = DateTime.Now + TimeSpan.FromSeconds(2.5); base.OnThink(); return; } + if ( backpack.TotalWeight > (backpack.MaxWeight - 100) ) { this.Say("I'm full !! I'm AutoConverting Ore in Ingot !"); m_Mine = true; this.Hue = 0; ControlOrder = OrderType.Stay; ConvertOretoIngot( this ); base.OnThink(); return; } + + Shovel shovel1 = (Shovel)backpack.FindItemByType(typeof(Shovel)); + Pickaxe shovel2 = (Pickaxe)backpack.FindItemByType(typeof(Pickaxe)); + IBShovel shovel3 = (IBShovel)backpack.FindItemByType(typeof(IBShovel)); + + + if (shovel1 != null) + { + if (this.DoDisposeOre(this.X, this.Y, this.Z, this.Map, this)) + { + + shovel1.UsesRemaining -= 1; + if (shovel1 != null && !shovel1.Deleted && shovel1.UsesRemaining <= 0) shovel1.Delete(); + } + } + + if (shovel2 != null) + { + if (this.DoDisposeOre(this.X, this.Y, this.Z, this.Map, this)) + { + + shovel2.UsesRemaining -= 1; + if (shovel2 != null && !shovel2.Deleted && shovel2.UsesRemaining <= 0) shovel2.Delete(); + } + } + + if (shovel3 != null) + { + if (this.DoDisposeOre(this.X, this.Y, this.Z, this.Map, this)) + { + + shovel3.UsesRemaining -= 1; + if (shovel3 != null && !shovel3.Deleted && shovel3.UsesRemaining <= 0) shovel3.Delete(); + } + } + + m_NextUse = DateTime.Now + TimeSpan.FromSeconds(2.5); + + if ( (shovel1 == null) && (shovel2 == null) && (shovel3 == null) ) + { + this.Say("I require a tool to dig"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + } + + IronIngot iron1 = (IronIngot)backpack.FindItemByType(typeof(IronIngot)); + if( iron1 is BaseIngot ) + { + BaseIngot m_Ore1 = iron1 as BaseIngot; + + if (m_Ore1.Amount > 1000) + { + SendIronIngot( this ); + } + } + + DullcopperIngot dull1 = (DullcopperIngot)backpack.FindItemByType(typeof(DullcopperIngot)); + if( dull1 is BaseIngot ) + { + BaseIngot m_Ore2 = dull1 as BaseIngot; + + if (m_Ore2.Amount > 1000) + { + SendDullCopperIngot( this ); + } + } + + ShadowIngot shad1 = (ShadowIngot)backpack.FindItemByType(typeof(ShadowIngot)); + if( shad1 is BaseIngot ) + { + BaseIngot m_Ore3 = shad1 as BaseIngot; + + if (m_Ore3.Amount > 1000) + { + SendShadowIronIngot( this ); + } + } + + BronzeIngot bron1 = (BronzeIngot)backpack.FindItemByType(typeof(BronzeIngot)); + if( bron1 is BaseIngot ) + { + BaseIngot m_Ore4 = bron1 as BaseIngot; + + if (m_Ore4.Amount > 1000) + { + SendBronzeIngot( this ); + } + } + + GoldIngot gold1 = (GoldIngot)backpack.FindItemByType(typeof(GoldIngot)); + if( gold1 is BaseIngot ) + { + BaseIngot m_Ore5 = gold1 as BaseIngot; + + if (m_Ore5.Amount > 1000) + { + SendGoldIngot( this ); + } + } + + CopperIngot copp1 = (CopperIngot)backpack.FindItemByType(typeof(CopperIngot)); + if( copp1 is BaseIngot ) + { + BaseIngot m_Ore6 = copp1 as BaseIngot; + + if (m_Ore6.Amount > 1000) + { + SendCopperIngot( this ); + } + } + + AgapiteIngot agap1 = (AgapiteIngot)backpack.FindItemByType(typeof(AgapiteIngot)); + if( agap1 is BaseIngot ) + { + BaseIngot m_Ore7 = agap1 as BaseIngot; + + if (m_Ore7.Amount > 1000) + { + SendAgapiteIngot( this ); + } + } + + VeriteIngot veri1 = (VeriteIngot)backpack.FindItemByType(typeof(VeriteIngot)); + if( veri1 is BaseIngot ) + { + BaseIngot m_Ore8 = veri1 as BaseIngot; + + if (m_Ore8.Amount > 1000) + { + SendVeriteIngot( this ); + } + } + + ValoriteIngot valo1 = (ValoriteIngot)backpack.FindItemByType(typeof(ValoriteIngot)); + if( valo1 is BaseIngot ) + { + BaseIngot m_Ore9 = valo1 as BaseIngot; + + if (m_Ore9.Amount > 1000) + { + SendValoriteIngot( this ); + } + } + + + } + base.OnThink(); + } + + public bool DoDisposeOre(int x, int y, int z, Map map, Mobile from) + { + if (!IsMiningTile(x, y, map)) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + + HarvestBank bank = Mining.System.OreAndStone.GetBank(map, x, y); + + if (bank == null) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + + if (bank.Current <= 0) + { + this.Say("No Ore remains !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + + HarvestVein vein = bank.DefaultVein; + + if (vein == null) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + + HarvestDefinition def = Mining.System.OreAndStone; + HarvestResource res = vein.PrimaryResource; + BaseOre ore = Mining.System.Construct(res.Types[0], null) as BaseOre; + + if (ore == null) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + + if (ore.Resource > CraftResource.MIron) + { + double minskill = 0.0; + double minskill2 = 0.0; + double maxskill = 0.0; + double skillbase = this.Skills.Mining.Base; + + switch (ore.Resource) + { + case CraftResource.MIron: { minskill = 00.0; minskill2 = 00.0; maxskill = 100.0; } break; + case CraftResource.MDullcopper: { minskill = 60.0; minskill2 = 25.0; maxskill = 105.0; } break; + case CraftResource.MShadow: { minskill = 65.0; minskill2 = 30.0; maxskill = 110.0; } break; + case CraftResource.MCopper: { minskill = 70.0; minskill2 = 35.0; maxskill = 115.0; } break; + case CraftResource.MGold: { minskill = 75.0; minskill2 = 40.0; maxskill = 120.0; } break; + case CraftResource.MAgapite: { minskill = 80.0; minskill2 = 45.0; maxskill = 120.0; } break; + case CraftResource.MVerite: { minskill = 85.0; minskill2 = 50.0; maxskill = 120.0; } break; + case CraftResource.MValorite: { minskill = 90.0; minskill2 = 55.0; maxskill = 120.0; } break; + } + + if (Utility.RandomDouble() <= 0.30 || skillbase < minskill) { ore = new IronOre(); minskill = 00.0; minskill2 = 00.0; maxskill = 100.0; } + if (!(from.CheckSkill(SkillName.Mining, minskill2, maxskill))) + { + ore.Delete(); + return false; + } + } + + ore.Amount = (map == Map.Felucca ? 2 : 1); + if (from != null) from.AddToBackpack(ore); + else ore.Delete(); + bank.Consume( ore.Amount, this); + this.Hue = ore.Hue; + return true; + + } + + public void SendIronIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + IronIngot iron = (IronIngot)backpack.FindItemByType(typeof(IronIngot)); + if( iron is BaseIngot ) + { + BaseIngot m_Ore1 = iron as BaseIngot; + + if (m_Ore1.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, iron ); + } + } + } + + public void SendDullCopperIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + DullcopperIngot dull = (DullcopperIngot)backpack.FindItemByType(typeof(DullcopperIngot)); + if( dull is BaseIngot ) + { + BaseIngot m_Ore2 = dull as BaseIngot; + + if (m_Ore2.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, dull); + } + } + } + + public void SendShadowIronIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + ShadowIngot shad = (ShadowIngot)backpack.FindItemByType(typeof(ShadowIngot)); + if( shad is BaseIngot ) + { + BaseIngot m_Ore3 = shad as BaseIngot; + + if (m_Ore3.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, shad); + } + } + } + + public void SendCopperIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + CopperIngot copp = (CopperIngot)backpack.FindItemByType(typeof(CopperIngot)); + if( copp is BaseIngot ) + { + BaseIngot m_Ore4 = copp as BaseIngot; + + if (m_Ore4.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, copp ); + } + } + } + + public void SendGoldIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + GoldIngot gold = (GoldIngot)backpack.FindItemByType(typeof(GoldIngot)); + if( gold is BaseIngot ) + { + BaseIngot m_Ore5 = gold as BaseIngot; + + if (m_Ore5.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, gold); + } + } + } + + public void SendBronzeIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + BronzeIngot bron = (BronzeIngot)backpack.FindItemByType(typeof(BronzeIngot)); + if( bron is BaseIngot ) + { + BaseIngot m_Ore6 = bron as BaseIngot; + + if (m_Ore6.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, bron); + } + } + } + + public void SendAgapiteIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + AgapiteIngot agap = (AgapiteIngot)backpack.FindItemByType(typeof(AgapiteIngot)); + if( agap is BaseIngot ) + { + BaseIngot m_Ore7 = agap as BaseIngot; + + if (m_Ore7.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, agap); + } + } + } + + public void SendVeriteIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + VeriteIngot veri = (VeriteIngot)backpack.FindItemByType(typeof(VeriteIngot)); + if( veri is BaseIngot ) + { + BaseIngot m_Ore8 = veri as BaseIngot; + + if (m_Ore8.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, veri); + } + } + } + + public void SendValoriteIngot( Mobile from ) + { + Container backpack = this.Backpack; + from = this.ControlMaster; + BankBox bank1 = from.BankBox; + ValoriteIngot valo = (ValoriteIngot)backpack.FindItemByType(typeof(ValoriteIngot)); + if( valo is BaseIngot ) + { + BaseIngot m_Ore9 = valo as BaseIngot; + + if (m_Ore9.Amount > 1000) + { + + PlaceItemIn( bank1, 18, 169, valo); + } + } + } + + public void ConvertOretoIngot( Mobile from ) + { + this.Skills.Mining.Cap = 120; + Container backpack = this.Backpack; + BankBox bank = from.BankBox; + IronOre item = (IronOre)backpack.FindItemByType(typeof(IronOre)); + + if( item is BaseOre ) + { + BaseOre m_Ore = item as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + + } + + ShadowOre item1 = (ShadowOre)backpack.FindItemByType(typeof(ShadowOre)); + + if( item1 is BaseOre ) + { + BaseOre m_Ore = item1 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + BronzeOre item2 = (BronzeOre)backpack.FindItemByType(typeof(BronzeOre)); + + if( item2 is BaseOre ) + { + BaseOre m_Ore = item2 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + CopperOre item3 = (CopperOre)backpack.FindItemByType(typeof(CopperOre)); + + if( item3 is BaseOre ) + { + BaseOre m_Ore = item3 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + GoldOre item4 = (GoldOre)backpack.FindItemByType(typeof(GoldOre)); + + if( item4 is BaseOre ) + { + BaseOre m_Ore = item4 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + DullcopperOre item5 = (DullcopperOre)backpack.FindItemByType(typeof(DullcopperOre)); + + if( item5 is BaseOre ) + { + BaseOre m_Ore = item5 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + AgapiteOre item6 = (AgapiteOre)backpack.FindItemByType(typeof(AgapiteOre)); + + if( item6 is BaseOre ) + { + BaseOre m_Ore = item6 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + VeriteOre item7 = (VeriteOre)backpack.FindItemByType(typeof(VeriteOre)); + + if( item7 is BaseOre ) + { + BaseOre m_Ore = item7 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + + ValoriteOre item8 = (ValoriteOre)backpack.FindItemByType(typeof(ValoriteOre)); + + if( item8 is BaseOre ) + { + BaseOre m_Ore = item8 as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + m_Ore.Delete(); + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.PlaySound(0x57); + + this.AddToBackpack(item); + this.AddToBackpack(ingot); + } + } + + private bool IsMiningTile(int X, int Y, Map map) + { + LandTile list = map.Tiles.GetLandTile( X, Y ); + + for (int l = 0; l < m_MountainAndCaveTiles.Length; l++) + { + if (m_MountainAndCaveTiles[l] == list.ID) return true; + } + return false; + } + + private static void PlaceItemIn( Container bank1, int x, int y, Item item ) + { + + bank1.AddItem( item ); + item.Location = new Point3D( x, y, 0 ); + } + + public IronBeetle(Serial serial): base(serial) + { + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write((double)m_SummonScalar); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_SummonScalar = reader.ReadDouble(); + } + } + } \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IronBeetle.cs.off b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IronBeetle.cs.off new file mode 100644 index 0000000..1797886 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/IronBeetle/IronBeetle.cs.off @@ -0,0 +1,397 @@ +using System; +using Server; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Gumps; +using Server.Network; +using Server.Menus; +using Server.ContextMenus; +using Server.Menus.Questions; +using Server.Targeting; +using Server.Engines.Harvest; +using Server.Regions; +using Server.Mobiles; +using System.Runtime.Serialization; + +namespace Server.Mobiles +{ + [CorpseName("an Iron beetle corpse")] + public class IronBeetle : BaseCreature + { + private static int[] m_MountainAndCaveTiles = new int[] + { + 113, 114, 115, 116, 117, 118, 119, 120, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 296, 296, 297, + 321, 322, 323, 324, 467, 468, 469, 470, 471, 472, + 473, 474, 476, 477, 478, 479, 480, 481, 482, 483, + 484, 485, 486, 487, 492, 493, 494, 495, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, + 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, + 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 577, 578, 579, 581, 582, 583, 584, 585, + 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, + 596, 597, 598, 599, 600, 601, 610, 611, 612, 613, + + 1010, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, + 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1771, 1772, + 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, + 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1801, 1802, + 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1811, 1812, 1813, + 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, + 1824, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, + 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, + 1850, 1851, 1852, 1853, 1854, 1861, 1862, 1863, 1864, 1865, + 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, + 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1981, + 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, + 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2028, 2029, 2030, 2031, 2032, 2033, 2100, + 2101, 2102, 2103, 2104, 2105, + + 0x453B, 0x453C, 0x453D, 0x453E, 0x453F, 0x4540, 0x4541, + 0x4542, 0x4543, 0x4544, 0x4545, 0x4546, 0x4547, 0x4548, + 0x4549, 0x454A, 0x454B, 0x454C, 0x454D, 0x454E, 0x454F + }; + + public bool m_Mine; + private DateTime m_NextUse; + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextUse { get { return m_NextUse; } set { m_NextUse = value; } } + + public override bool SubdueBeforeTame { get { return true; } } + + [Constructable] + public IronBeetle() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "an Iron beetle"; + Body = 714; + BaseSoundID = 397; + + SetStr (779, 831); + SetDex (66, 75); + SetInt (38, 50); + + SetHits(764, 877); + SetMana(38, 50); + + SetDamage(15, 20); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 20, 30); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 45, 55); + + SetSkill(SkillName.Anatomy, 80, 89.5); + SetSkill(SkillName.MagicResist, 120.6, 128.8); + SetSkill(SkillName.Tactics, 82.5, 96.6); + SetSkill(SkillName.Wrestling, 92.4, 108.2); + SetSkill(SkillName.Blacksmith, 120.0); + SetSkill(SkillName.Mining, 90); + Skills.Mining.Cap = 120; + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 38; + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 71.1; + + Container pack = Backpack; + if (pack != null) pack.Delete(); + pack = new StrongBackpack(); + pack.Movable = false; + AddItem(pack); + + AddItem(new Gold(600)); + PackItem(new IronOre(5)); + PackItem(new IronOre(5)); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + AddLoot(LootPack.Gems); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.1) + c.DropItem(new UndamagedIronBeetleScale()); + + if (Utility.RandomDouble() < 0.15) + c.DropItem(new IBShovel()); + } + + public override bool CanRummageCorpses { get { return true; } } + public override int Meat { get { return 1; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + public override DeathMoveResult GetInventoryMoveResultFor(Item item) { return DeathMoveResult.MoveToCorpse; } + public override bool AllowEquipFrom(Mobile from) { return (ControlMaster != null && ControlMaster == from); } + public override bool CanBeRenamedBy(Mobile from) { return (ControlMaster != null && ControlMaster == from); } + public override bool CanPaperdollBeOpenedBy(Mobile from) { return false; } + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) { return PackAnimal.CheckAccess(this, from); } + public override bool CheckNonlocalLift(Mobile from, Item item) { return PackAnimal.CheckAccess(this, from); } + + public override bool OnBeforeDeath() + { + if (!base.OnBeforeDeath()) return false; + PackAnimal.CombineBackpacks(this); + return base.OnBeforeDeath(); + } + + public override bool IsSnoop(Mobile from) + { + if (PackAnimal.CheckAccess(this, from)) return false; + return base.IsSnoop(from); + } + + public override bool OnDragDrop(Mobile from, Item item) + { + this.Skills.Mining.Cap = 120; + if (CheckFeed(from, item)) return true; + if (PackAnimal.CheckAccess(this, from)) + { + if (item is BaseOre) + { + BaseOre m_Ore = item as BaseOre; + + int toConsume = m_Ore.Amount; + + if (toConsume > 30000) + { + toConsume = 30000; + } + else if (m_Ore.Amount < 2) + { + from.SendLocalizedMessage(501989); // You burn away the impurities but are left with no useable metal. + m_Ore.Delete(); + return true; + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = toConsume * 2; + + m_Ore.Consume(toConsume); + + this.Hue = m_Ore.Hue; + + from.PlaySound(0x57); + + AddToBackpack(item); + AddToBackpack(ingot); + return true; + } + } + + return base.OnDragDrop(from, item); + } + + public override void OnSpeech(SpeechEventArgs args) + { + string said = args.Speech.ToLower(); + Mobile from = args.Mobile; + string bmine = this.Name + " " + "mine"; + string bmine2 = bmine.ToLower(); + string bbreak = this.Name + " " + "takebreak"; + string bbreak2 = bbreak.ToLower(); + string bbreak3 = this.Name + " " + "take break"; + string bbreak4 = bbreak3.ToLower(); + if (said == this.Name.ToLower()) + { + if (from == this.ControlMaster) + { + this.Say("Yes?"); + } + else + { + + this.Say("You are not my master."); + + } + } + + else if ((said == "mine" || said == bmine2) && from == this.ControlMaster) { m_Mine = true; ControlOrder = OrderType.Stay; } + else if ((said == "takebreak" || said == "take break" || said == bbreak2 || said == bbreak4) && from == this.ControlMaster) { m_Mine = false; ControlOrder = OrderType.Follow; this.Hue = 0; } + base.OnSpeech(args); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + PackAnimal.GetContextMenuEntries(this, from, list); + } + + public override void OnThink() + { + if (this.Alive && this.m_Mine && this.m_NextUse <= DateTime.Now) + { + Container backpack = this.Backpack; + if (backpack == null) { m_NextUse = DateTime.Now + TimeSpan.FromSeconds(1.5); base.OnThink(); return; } + + if ( ( backpack.TotalWeight >= backpack.MaxWeight ) || ( backpack.TotalItems >= backpack.MaxItems ) ) + { + this.Say("I'm full !! Please Empty Me !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + } + Pickaxe pickaxe = (Pickaxe)backpack.FindItemByType(typeof(Pickaxe)); + + if (pickaxe != null) + { + if (this.DoDisposeOre(this.X, this.Y, this.Z, this.Map, this)) + { + pickaxe.UsesRemaining -= 1; + if (pickaxe != null && !pickaxe.Deleted && pickaxe.UsesRemaining <= 0) pickaxe.Delete(); + } + } + m_NextUse = DateTime.Now + TimeSpan.FromSeconds(1.5); + if (pickaxe == null) + { + this.Say("I require a tool, to dig"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + } + + Shovel shovel = (Shovel)backpack.FindItemByType(typeof(Shovel)); + + if (shovel != null) + { + if (this.DoDisposeOre(this.X, this.Y, this.Z, this.Map, this)) + { + shovel.UsesRemaining -= 1; + if (shovel != null && !shovel.Deleted && shovel.UsesRemaining <= 0) shovel.Delete(); + } + } + m_NextUse = DateTime.Now + TimeSpan.FromSeconds(1.5); + if (shovel == null) + { + this.Say("I require a tool, to dig"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + } + + } + base.OnThink(); + } + + public bool DoDisposeOre(int x, int y, int z, Map map, Mobile from) + { + if (!IsMiningTile(x, y, map)) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + HarvestBank bank = Mining.System.OreAndStone.GetBank(map, x, y); + if (bank == null) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + if (bank.Current <= 0) + { + this.Say("No Ore remains !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + HarvestVein vein = bank.DefaultVein; + if (vein == null) + { + this.Say("I can not mine here !"); + m_Mine = false; + this.Hue = 0; + ControlOrder = OrderType.Follow; + return false; + } + HarvestDefinition def = Mining.System.OreAndStone; + HarvestResource res = vein.PrimaryResource; + BaseOre ore = Mining.System.Construct(res.Types[0], null) as BaseOre; + if (ore == null) return false; + if (ore.Resource > CraftResource.Iron) + { + double minskill = 0.0; + double minskill2 = 0.0; + double maxskill = 0.0; + double skillbase = this.Skills.Mining.Base; + + switch (ore.Resource) + { + case CraftResource.Iron: { minskill = 00.0; minskill2 = 00.0; maxskill = 100.0; } break; + case CraftResource.DullCopper: { minskill = 60.0; minskill2 = 25.0; maxskill = 105.0; } break; + case CraftResource.ShadowIron: { minskill = 65.0; minskill2 = 30.0; maxskill = 110.0; } break; + case CraftResource.Copper: { minskill = 70.0; minskill2 = 35.0; maxskill = 115.0; } break; + case CraftResource.Gold: { minskill = 75.0; minskill2 = 40.0; maxskill = 120.0; } break; + case CraftResource.Agapite: { minskill = 80.0; minskill2 = 45.0; maxskill = 120.0; } break; + case CraftResource.Verite: { minskill = 85.0; minskill2 = 50.0; maxskill = 120.0; } break; + case CraftResource.Valorite: { minskill = 90.0; minskill2 = 55.0; maxskill = 120.0; } break; + } + + if (Utility.RandomDouble() <= 0.30 || skillbase < minskill) { ore = new IronOre(); minskill = 00.0; minskill2 = 00.0; maxskill = 100.0; } + if (!(from.CheckSkill(SkillName.Mining, minskill2, maxskill))) + { + ore.Delete(); + return false; + } + } + + ore.Amount = (map == Map.Felucca ? 2 : 1); + if (from != null) from.AddToBackpack(ore); + else ore.Delete(); + bank.Consume( ore.Amount, this); + this.Hue = ore.Hue; + return true; + + } + + private bool IsMiningTile(int X, int Y, Map map) + { + LandTile list = map.Tiles.GetLandTile( X, Y ); + + for (int l = 0; l < m_MountainAndCaveTiles.Length; l++) + { + if (m_MountainAndCaveTiles[l] == list.ID) return true; + } + return false; + } + + + public IronBeetle(Serial serial): base(serial) + { + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + } diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Mimic.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Mimic.cs new file mode 100644 index 0000000..dd1c2b3 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Mimic.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a mimic corpse" )] + public class Mimic : BaseCreature + { + [Constructable] + public Mimic() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a mimic"; + Body = 729; + + SetStr( 281 ); + SetDex( 140 ); + SetInt( 261 ); + + SetHits( 543 ); + + SetDamage( 13, 20 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 63 ); + SetResistance( ResistanceType.Fire, 43 ); + SetResistance( ResistanceType.Cold, 36 ); + SetResistance( ResistanceType.Poison, 37 ); + SetResistance( ResistanceType.Energy, 42 ); + + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Magery, 107.5 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 126.5 ); + SetSkill( SkillName.Tactics, 98.5 ); + SetSkill( SkillName.Wrestling, 92.2 ); + + PackReg( 20 ); + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 4 ); + AddLoot( LootPack.MedScrolls ); + } + + public override int GetIdleSound() { return 1561; } + public override int GetAngerSound() { return 1558; } + public override int GetHurtSound() { return 1560; } + public override int GetDeathSound() { return 1559; } + + public Mimic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/NavreyNightEyes.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/NavreyNightEyes.cs new file mode 100644 index 0000000..eb90109 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/NavreyNightEyes.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a spider corpse" )] + public class NavreyNightEyes : BaseCreature + { + [Constructable] + public NavreyNightEyes () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Navrey Night-Eyes"; + Body = 735; + BaseSoundID = 1170; + + SetStr( 1000, 1500 ); + SetDex( 190, 250 ); + SetInt( 170, 200 ); + + SetHits( 30000, 30000 ); + SetStam( 200, 250 ); + SetMana( 150, 200 ); + + SetDamage( 22, 29 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 60, 80 ); + + SetSkill( SkillName.Wrestling, 90.0, 100.7 ); + SetSkill( SkillName.Tactics, 90.0, 100.0 ); + SetSkill( SkillName.MagicResist, 100.0, 130.0 ); + SetSkill( SkillName.Poisoning, 100.0 ); + SetSkill( SkillName.Magery, 90.0, 100.0 ); + SetSkill( SkillName.EvalInt, 90.0, 100.0 ); + SetSkill( SkillName.Meditation, 80.0, 100.0 ); + SetSkill( SkillName.Anatomy, 50.0, 80.0 ); + + PackItem( new SpidersSilk( 8 ) ); + + Fame = 24000; + Karma = -24000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 4 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + public NavreyNightEyes( Serial serial ) : base( serial ) + { + } + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/People/GenericGuard.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/People/GenericGuard.cs new file mode 100644 index 0000000..f070276 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/People/GenericGuard.cs @@ -0,0 +1,56 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class GenericGuard : BaseCreature + { + [Constructable] + public GenericGuard () : base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + InitStats( 100, 100, 25 ); + + Hue = Utility.RandomSkinHue(); + + Female = false; + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + Title = "the guard"; + + HairItemID = 0x203B; + HairHue = Utility.RandomNeutralHue(); + FacialHairItemID = 0; + + AddItem( new PlateChest() ); + AddItem( new PlateArms() ); + AddItem( new PlateGloves() ); + AddItem( new PlateLegs() ); + + //Longsword weapon = new Longsword(); + //weapon.Movable = false; + //AddItem( weapon ); + } + + public override bool ClickTitle{ get{ return false; } } + + public GenericGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/RotWorm.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/RotWorm.cs new file mode 100644 index 0000000..d3e14eb --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/RotWorm.cs @@ -0,0 +1,65 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a rotworm corpse" )] + public class RotWorm : BaseCreature + { + [Constructable] + public RotWorm() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a rotworm"; + Body = 732; + + SetStr( 244 ); + SetDex( 80 ); + SetInt( 17 ); + + SetHits( 215 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + //SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 37 ); + SetResistance( ResistanceType.Fire, 30 ); + SetResistance( ResistanceType.Cold, 35 ); + SetResistance( ResistanceType.Poison, 73 ); + SetResistance( ResistanceType.Energy, 26 ); + + SetSkill( SkillName.MagicResist, 25.0 ); + SetSkill( SkillName.Tactics, 25.0 ); + SetSkill( SkillName.Wrestling, 50.0 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int GetIdleSound() { return 1503; } + public override int GetAngerSound() { return 1500; } + public override int GetHurtSound() { return 1502; } + public override int GetDeathSound() { return 1501; } + + public RotWorm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/SentinelSpider.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/SentinelSpider.cs new file mode 100644 index 0000000..70a71b5 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/SentinelSpider.cs @@ -0,0 +1,76 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a sentinel spider spider corpse" )] + public class SentinelSpider : BaseCreature + { + [Constructable] + public SentinelSpider() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a sentinel spider"; + Body = 0x9D; + BaseSoundID = 0x388; // TODO: validate + + SetStr( 113, 118 ); + SetDex( 150, 155 ); + SetInt( 88, 90 ); + + SetHits( 336, 336 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 47, 50 ); + SetResistance( ResistanceType.Fire, 36, 40 ); + SetResistance( ResistanceType.Cold, 33, 35 ); + SetResistance( ResistanceType.Poison, 76, 80 ); + SetResistance( ResistanceType.Energy, 34, 40 ); + + SetSkill( SkillName.Anatomy, 96.7, 97.0 ); + SetSkill( SkillName.Poisoning, 107.8, 108.0 ); + SetSkill( SkillName.MagicResist, 89.5, 90.0 ); + SetSkill( SkillName.Tactics, 107.7, 108.0 ); + SetSkill( SkillName.Wrestling, 109.8, 110.0 ); + SetSkill( SkillName.DetectHidden, 120.4, 139.6); + + Fame = 18900; + Karma = -3500; + + VirtualArmor = 24; + + PackItem( new SpidersSilk( 10 ) ); + PackItem( new LesserPoisonPotion() ); + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + + public SentinelSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/TrapdoorSpider.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/TrapdoorSpider.cs new file mode 100644 index 0000000..8fdc655 --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/TrapdoorSpider.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a trapdoor spider corpse" )] + public class TrapdoorSpider : BaseCreature + { + [Constructable] + public TrapdoorSpider() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a trapdoor spider"; + Body = 737; + + SetStr( 100, 104 ); + SetDex( 162, 165 ); + SetInt( 29, 50 ); + + SetHits( 125, 144 ); + + SetDamage( 15, 18 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Poison, 80 ); + + SetResistance( ResistanceType.Physical, 0 ); + SetResistance( ResistanceType.Fire, 30, 35 ); + SetResistance( ResistanceType.Cold, 30, 35 ); + SetResistance( ResistanceType.Poison, 40, 45 ); + SetResistance( ResistanceType.Energy, 95, 100 ); + + SetSkill( SkillName.Anatomy, 2.0, 3.8 ); + SetSkill( SkillName.MagicResist, 47.5, 57.9 ); + SetSkill( SkillName.Poisoning, 70.5, 73.5 ); + SetSkill( SkillName.Tactics, 73.3, 78.9 ); + SetSkill( SkillName.Wrestling, 92.5, 94.6 ); + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override int GetIdleSound() { return 1605; } + public override int GetAngerSound() { return 1602; } + public override int GetHurtSound() { return 1604; } + public override int GetDeathSound() { return 1603; } + + public TrapdoorSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/WolfSpider.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/WolfSpider.cs new file mode 100644 index 0000000..d5c43ba --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/Spiders/WolfSpider.cs @@ -0,0 +1,82 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a wolf spider corpse" )] + public class WolfSpider : BaseCreature + { + [Constructable] + public WolfSpider() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + ActiveSpeed = 0.1; + PassiveSpeed = 0.2; + + Name = "a wolf spider"; + Body = 736; + BaseSoundID = 0x388; + + SetStr( 230, 263 ); + SetDex( 145, 152 ); + SetInt( 285, 310 ); + + SetHits( 150, 200 ); + SetMana( 285, 310 ); + + SetDamage( 15, 18 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 100, 100 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Poisoning, 65.0, 80.0 ); + SetSkill( SkillName.MagicResist, 60.0, 90.0 ); + SetSkill( SkillName.Tactics, 84.0, 96.0); + SetSkill( SkillName.Wrestling, 80.0, 90.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 59.1; + + PackItem( new SpidersSilk( 8 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Arachnid; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Greater; } } + + public WolfSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/TanglingRoots.cs b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/TanglingRoots.cs new file mode 100644 index 0000000..0f2800b --- /dev/null +++ b/Scripts/Customs/Nerun's Distro/SA/Mobiles/UnderWorld/TanglingRoots.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a tangling root corpse" )] + public class TanglingRoots : BaseCreature + { + [Constructable] + public TanglingRoots() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a tangling root"; + Body = 129; + BaseSoundID = 684; + + SetStr( 150, 157 ); + SetDex( 55, 60 ); + SetInt( 30, 35 ); + + SetHits( 200, 232 ); + SetStam( 55, 60 ); + + SetDamage( 10, 23 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + + SetSkill( SkillName.MagicResist, 15.1, 18.5 ); + SetSkill( SkillName.Tactics, 45.1, 59.5 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 18; + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( new Board( 10 ) ); + else + PackItem( new Log( 10 ) ); + + PackItem( new MandrakeRoot( 3 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + public override bool DisallowAllMoves{ get{ return true; } } + + public TanglingRoots( Serial serial ) : base( serial ) + { + } + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 352 ) + BaseSoundID = 684; + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/ExportMobiles.txt b/Scripts/Customs/OrbRemoteServer/ExportMobiles.txt new file mode 100644 index 0000000..3718954 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/ExportMobiles.txt @@ -0,0 +1,45 @@ +// Created by Peoharen +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class ExportMobiles : Item + { + [Constructable] + public ExportMobiles() : base( 0x108A ) + { + Name = "Export Mobiles"; + Layer = Layer.Ring; + } + + public override void GetProperties( ObjectPropertyList list ) + { + list.Add( 1114057, "" + this.Name ); // ~1_VAL~ + + if ( IsSecure ) + AddSecureProperty( list ); + else if ( IsLockedDown ) + AddLockedDownProperty( list ); + + list.Add( 1042971, "[Saves Mobiles while using UOAR to Export]" ); // ~1_NOTHING~ + } + + public ExportMobiles( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/OrbRemoteServer/MetalDoors.cs b/Scripts/Customs/OrbRemoteServer/MetalDoors.cs new file mode 100644 index 0000000..3f380b2 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/MetalDoors.cs @@ -0,0 +1,223 @@ +//Created by Peoharen +using System; + +namespace Server.Items +{ + public class NorthWestDoor : BaseDoor + { + [Constructable] + public NorthWestDoor() : base( 0x679, 0x67A, 0xEC, 0xF3, new Point3D( -1, 0, 0 ) ) + { + } + + public NorthWestDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class NorthEastDoor : BaseDoor + { + [Constructable] + public NorthEastDoor() : base( 0x67B, 0x67C, 0xEC, 0xF3, new Point3D( 1, -1, 0 ) ) + { + } + + public NorthEastDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class SouthWestDoor : BaseDoor + { + [Constructable] + public SouthWestDoor() : base( 0x675, 0x676, 0xEC, 0xF3, new Point3D( -1, 1, 0 ) ) + { + } + + public SouthWestDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class SouthEastDoor : BaseDoor + { + [Constructable] + public SouthEastDoor() : base( 0x677, 0x678, 0xEC, 0xF3, new Point3D( 1, 1, 0 ) ) + { + } + + public SouthEastDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class WestNorthDoor : BaseDoor + { + [Constructable] + public WestNorthDoor() : base( 0x683, 1, 0xEC, 0xF3, new Point3D( -1, -1, 0 ) ) + { + } + + public WestNorthDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class WestSouthDoor : BaseDoor + { + [Constructable] + public WestSouthDoor() : base( 0x681, 1, 0xEC, 0xF3, new Point3D( -1, 1, 0 ) ) + { + } + + public WestSouthDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class EastNorthDoor : BaseDoor + { + [Constructable] + public EastNorthDoor() : base( 0x67F, 1, 0xEC, 0xF3, new Point3D( 1, -1, 0 ) ) + { + } + + public EastNorthDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class EastSouthDoor : BaseDoor + { + [Constructable] + public EastSouthDoor() : base( 0x67D, 0x67E, 0xEC, 0xF3, new Point3D( 0, 1, 0 ) ) + { + } + + public EastSouthDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + +} +/* + public class Door : BaseDoor + { + [Constructable] + public Door() : base( , , 0xEC, 0xF3, new Point3D( 0, 0, 0 ) ) + { + } + + public Door( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +*/ \ No newline at end of file diff --git a/Scripts/Customs/OrbRemoteServer/OrbServer.cs b/Scripts/Customs/OrbRemoteServer/OrbServer.cs new file mode 100644 index 0000000..29cb606 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/OrbServer.cs @@ -0,0 +1,416 @@ +using System; +using System.Collections; +using OrbServerSDK; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Channels; +using System.Runtime.Remoting.Channels.Tcp; +using Server.Accounting; +using Server; +using Server.Network; +using System.Threading; + +namespace Server.Engines.OrbRemoteServer +{ + class OrbServer + { + private static readonly int SERVER_PORT = 2594; + private static readonly AccessLevel REQUIRED_ACCESS_LEVEL = AccessLevel.GameMaster; + private static readonly string SERVER_VERSION = ""; + private static readonly string SERVER_NAME = "UO Architect Server for RunUO 2.0"; + + private static Hashtable m_Registry = System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable(0); + private static Hashtable m_Clients = new Hashtable(); + + private static bool m_IsRunning = false; + + public static bool IsRunning + { + get{ return m_IsRunning; } + } + + public static void Initialize() + { + } + + static OrbServer() + { + StartServer(); + + OrbConnection.OnLogin += new OrbConnection.LoginEvent(OnLogin); + OrbConnection.OnExecuteCommand += new OrbConnection.ExecuteCommandEvent(OnExecuteCommand); + OrbConnection.OnExecuteRequest += new OrbConnection.ExecuteRequestEvent(OnExecuteRequest); + } + + private static void OnExecuteCommand(string alias, OrbClientInfo clientInfo, OrbCommandArgs args) + { + OrbClientState client = GetClientState(clientInfo); + + if(client == null) + return; + + try + { + OrbCommand command = GetCommand(alias, client); + + if(command != null) + { + new CommandSyncTimer(client, command, args).Start(); + } + } + catch(Exception e) + { + Console.WriteLine("Exception occurred for OrbServer command {0}\nMessage: {1}", alias, e.Message); + } + } + + private static OrbClientState GetClientState(OrbClientInfo clientInfo) + { + return (OrbClientState)m_Clients[clientInfo.ClientID]; + } + + private static OrbResponse OnExecuteRequest(string alias, OrbClientInfo clientInfo, OrbRequestArgs args) + { + OrbClientState client = GetClientState(clientInfo); + + if(client == null) + return null; + + OrbResponse response = null; + + try + { + OrbRequest request = GetRequest(alias, client); + + if(request != null) + { + ManualResetEvent reset = new ManualResetEvent(false); + request.ResetEvent = reset; + + new RequestSyncTimer(client, request, args).Start(); + reset.WaitOne(); + + response = request.Response; + } + } + catch(Exception e) + { + Console.WriteLine("Exception occurred for OrbServer request {0}\nMessage: {1}", alias, e.Message); + } + + return response; + } + + private static OrbRequest GetRequest(string alias, OrbClientState client) + { + OrbRegistryEntry entry = (OrbRegistryEntry)m_Registry[alias]; + OrbRequest request = null; + + if(entry != null) + { + if(CanConnectionAccess(client, entry)) + { + try + { + request = (OrbRequest)Activator.CreateInstance(entry.Type); + } + catch(Exception e) + { + Console.WriteLine("OrbServer Exception: " + e.Message); + } + } + } + + return request; + } + + private static OrbCommand GetCommand(string alias, OrbClientState client) + { + OrbRegistryEntry entry = (OrbRegistryEntry)m_Registry[alias]; + OrbCommand command = null; + + if(entry != null) + { + if(CanConnectionAccess(client, entry)) + { + try + { + command = (OrbCommand)Activator.CreateInstance(entry.Type); + } + catch(Exception e) + { + Console.WriteLine("OrbServer Exception: " + e.Message); + } + } + } + + return command; + } + + private static bool CanConnectionAccess(OrbClientState client, OrbRegistryEntry entry) + { + bool authorized = false; + + if(entry.RequiresLogin) + { + if(client.OnlineMobile != null) + { + authorized = IsAccessAllowed(client.OnlineMobile, entry.RequiredLevel); + } + } + else + { + authorized = IsAccessAllowed(client.Account, entry.RequiredLevel); + } + + return authorized; + } + + private static void StartServer() + { + // Run the OrbServer in a worked thread + ThreadPool.QueueUserWorkItem(new WaitCallback(OrbServer.Run), null); + } + + public static void Register(string alias, Type type, AccessLevel requiredLevel, bool requiresLogin) + { + if(!type.IsSubclassOf(typeof(OrbRequest)) && !type.IsSubclassOf(typeof(OrbCommand)) ) + { + Console.WriteLine("OrbRemoteServer Error: The type {0} isn't a subclass of the OrbCommand or OrbRequest classes.", type.FullName); + } + else if(m_Registry.ContainsKey(alias)) + { + Console.WriteLine("OrbRemoteServer Error: The type {0} has been assigned a duplicate alias.", type.FullName); + } + else + { + m_Registry.Add(alias, new OrbRegistryEntry(alias, type, requiredLevel, requiresLogin)); + } + + } + + ////////////////////////////////////////////////////////////////////////////// + // main method - this method registers the TCP/IP channel and the OrbConnection Type + // for remote instanciation. + public static void Run(object o) + { + try{ + Console.WriteLine("\n{0} {1} is listening on port {2}", SERVER_NAME, SERVER_VERSION, SERVER_PORT); + // Create Tcp channel using the selected Port number + TcpChannel chan = new TcpChannel(SERVER_PORT); + ChannelServices.RegisterChannel(chan); //register channel + + // register the remote object + RemotingConfiguration.RegisterWellKnownServiceType( + typeof(OrbConnection), + "OrbConnection", + WellKnownObjectMode.Singleton); + + while(true) + { + // Keep sleeping in order to keep this tread alive without hogging cpu cycles + Thread.Sleep(30000); + } + + }catch{} + } + + // This function callback validates an account and returns true if it has access + // rights to use this tool. + private static LoginCodes OnLogin(OrbClientInfo clientInfo, string password) + { + LoginCodes code = LoginCodes.Success; + + //Console.WriteLine("OnValidateAccount"); + IAccount account = Accounts.GetAccount(clientInfo.UserName); + + if(account == null || account.CheckPassword(password) == false) + { + code = LoginCodes.InvalidAccount; + } + else + { + if(!IsAccessAllowed(account, REQUIRED_ACCESS_LEVEL)) + { + Mobile player = GetOnlineMobile(account); + + if(player == null || !IsAccessAllowed(player, REQUIRED_ACCESS_LEVEL)) + { + // Neither the account or the char the account is logged in with has + // the required accesslevel to make this connection. + code = LoginCodes.NotAuthorized; + } + } + + Console.WriteLine("{0} connected to the Orb Script Server", account.Username); + } + + if(code == LoginCodes.Success) + { + if(m_Clients.ContainsKey(clientInfo.ClientID)) + m_Clients.Remove(clientInfo.ClientID); + + m_Clients.Add(clientInfo.ClientID, new OrbClientState(clientInfo, account, DateTime.Now)); + } + + return code; + } + + private static bool IsAccessAllowed(IAccount acct, AccessLevel accessLevel) + { + bool AccessAllowed = false; + + if(acct != null) + { + if((int)acct.AccessLevel >= (int)accessLevel) + { + AccessAllowed = true; + } + } + + return AccessAllowed; + } + + private static bool IsAccessAllowed(Mobile mobile, AccessLevel accessLevel) + { + bool AccessAllowed = false; + + if(mobile != null) + { + if((int)mobile.AccessLevel >= (int)accessLevel) + { + AccessAllowed = true; + } + } + + return AccessAllowed; + } + + // get logged in char for an account + internal static Mobile GetOnlineMobile(IAccount acct) + { + if(acct == null) + return null; + + Mobile mobile = null; + + // syncronize the account object to keep this access thread safe + lock(acct) + { + for(int i=0; i < 5; ++i) + { + Mobile mob = acct[i]; + + if(mob == null) + continue; + + if(mob.NetState != null) + { + mobile = mob; + break; + } + } + } + + return mobile; + } + + // Stores info regarding the registered OrbCommand or OrbRequest + class OrbRegistryEntry + { + public string Alias; + public Type Type; + public AccessLevel RequiredLevel; + public bool RequiresLogin; + + public OrbRegistryEntry(string alias, Type type, AccessLevel requiredLevel, bool requiresLogin) + { + Alias = alias; + Type = type; + RequiredLevel = requiredLevel; + RequiresLogin = requiresLogin; + } + + public bool IsCommand + { + get{ return Type.IsSubclassOf(typeof(OrbCommand)); } + } + + public bool IsRequest + { + get{ return Type.IsSubclassOf(typeof(OrbRequest)); } + } + } + + class RequestSyncTimer : Timer + { + private OrbClientState m_Client; + private OrbRequest m_Request; + private OrbRequestArgs m_Args; + + public RequestSyncTimer(OrbClientState client, OrbRequest request, OrbRequestArgs args) : base(TimeSpan.FromMilliseconds(20.0), TimeSpan.FromMilliseconds(20.0)) + { + m_Client = client; + m_Request = request; + m_Args = args; + } + + protected override void OnTick() + { + if(m_Request != null) + m_Request.OnRequest(m_Client, m_Args); + + Stop(); + } + } + + class CommandSyncTimer : Timer + { + private OrbClientState m_Client; + private OrbCommand m_Command; + private OrbCommandArgs m_Args; + + public CommandSyncTimer(OrbClientState client, OrbCommand command, OrbCommandArgs args) : base(TimeSpan.FromMilliseconds(20.0), TimeSpan.FromMilliseconds(20.0)) + { + m_Client = client; + m_Command = command; + m_Args = args; + } + + protected override void OnTick() + { + if(m_Command != null) + m_Command.OnCommand(m_Client, m_Args); + + Stop(); + } + } + } + + internal class OrbClientState : OrbClientInfo + { + private IAccount m_Account = null; + private DateTime m_LoginTime; + + internal OrbClientState(OrbClientInfo clientInfo, IAccount account, DateTime loginTime) + : base(clientInfo.ClientID, clientInfo.UserName) + { + m_Account = account; + m_LoginTime = loginTime; + } + + internal IAccount Account + { + get{ return m_Account; } + } + + internal Mobile OnlineMobile + { + get{ return OrbServer.GetOnlineMobile(m_Account); } + } + + internal DateTime LoginTime + { + get{ return m_LoginTime; } + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/SEDoors.cs b/Scripts/Customs/OrbRemoteServer/SEDoors.cs new file mode 100644 index 0000000..7f8416f --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/SEDoors.cs @@ -0,0 +1,317 @@ +//Created by Peoharen +using System; + +namespace Server.Items +{ + public class SWPaperSEDoor : BaseDoor + { + [Constructable] + public SWPaperSEDoor() : base( 0x2A05, 0x2A06, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public SWPaperSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SEPaperSEDoor : BaseDoor + { + [Constructable] + public SEPaperSEDoor() : base( 0x2A07, 0x2A08, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public SEPaperSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ESPaperSEDoor : BaseDoor + { + [Constructable] + public ESPaperSEDoor() : base( 0x2A09, 0x2A0A, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public ESPaperSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ENPaperSEDoor : BaseDoor + { + [Constructable] + public ENPaperSEDoor() : base( 0x2A0B, 0x2A0C, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public ENPaperSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SWClothSEDoor : BaseDoor + { + [Constructable] + public SWClothSEDoor() : base( 0x2A0D, 0x2A0E, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public SWClothSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SEClothSEDoor : BaseDoor + { + [Constructable] + public SEClothSEDoor() : base( 0x2A0F, 0x2A10, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public SEClothSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ESClothSEDoor : BaseDoor + { + [Constructable] + public ESClothSEDoor() : base( 0x2A11, 0x2A12, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public ESClothSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ENClothSEDoor : BaseDoor + { + [Constructable] + public ENClothSEDoor() : base( 0x2A13, 0x2A14, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public ENClothSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SWWoodenSEDoor : BaseDoor + { + [Constructable] + public SWWoodenSEDoor() : base( 0x2A16, 0x2A17, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public SWWoodenSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SEWoodenSEDoor : BaseDoor + { + [Constructable] + public SEWoodenSEDoor() : base( 0x2A17, 0x2A18, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public SEWoodenSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ESWoodenSEDoor : BaseDoor + { + [Constructable] + public ESWoodenSEDoor() : base( 0x2A19, 0x2A1A, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public ESWoodenSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ENWoodenSEDoor : BaseDoor + { + [Constructable] + public ENWoodenSEDoor() : base( 0x2A1B, 0x2A1C, 0x539, 0x539, new Point3D( 0, 0, 0 ) ) + { + } + + public ENWoodenSEDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/BaseOrbToolRequest.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/BaseOrbToolRequest.cs new file mode 100644 index 0000000..873ce58 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/BaseOrbToolRequest.cs @@ -0,0 +1,37 @@ +using System; +using Server; +using Server.Accounting; +using OrbServerSDK; +using Server.Engines.OrbRemoteServer; + +namespace Server.Engines.UOArchitect +{ + public abstract class BaseOrbToolRequest : OrbRequest + { + private Mobile m_OnlineMobile; + + public Mobile Mobile + { + get{ return m_OnlineMobile; } + } + + public bool IsOnline + { + get + { + if(m_OnlineMobile == null) + return false; + else if(m_OnlineMobile.NetState == null) + return false; + else + return true; + } + } + + public void FindOnlineMobile(OrbClientInfo client) + { + m_OnlineMobile = ((OrbClientState)client).OnlineMobile; + } + + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/BoundingBoxEx.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/BoundingBoxEx.cs new file mode 100644 index 0000000..a22034b --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/BoundingBoxEx.cs @@ -0,0 +1,97 @@ +using System; +using Server; +using Server.Targeting; +using Server.Commands; + +namespace Server.Engines.UOArchitect +{ + public delegate void BoundingBoxExCancelled(); + + public class BoundingBoxPickerEx + { + public BoundingBoxExCancelled OnCancelled; + + public void Begin( Mobile from, BoundingBoxCallback callback, object state ) + { + from.SendMessage( "Target the first location of the bounding box." ); + + PickTarget target = new PickTarget(callback, state); + target.OnCancelled += new BoundingBoxExCancelled(OnTargetCancelled); + from.Target = target; + } + + private void OnTargetCancelled() + { + if(OnCancelled != null) + OnCancelled(); + } + + private class PickTarget : Target + { + public BoundingBoxExCancelled OnCancelled; + private Point3D m_Store; + private bool m_First; + private Map m_Map; + private BoundingBoxCallback m_Callback; + private object m_State; + + public PickTarget( BoundingBoxCallback callback, object state ) : this( Point3D.Zero, true, null, callback, state ) + { + } + + public PickTarget( Point3D store, bool first, Map map, BoundingBoxCallback callback, object state ) : base( -1, true, TargetFlags.None ) + { + m_Store = store; + m_First = first; + m_Map = map; + m_Callback = callback; + m_State = state; + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + base.OnTargetCancel (from, cancelType); + + if(OnCancelled != null) + OnCancelled(); + } + + private void OnTargetCancelled() + { + if(OnCancelled != null) + OnCancelled(); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + else if ( p is Item ) + p = ((Item)p).GetWorldTop(); + + if ( m_First ) + { + from.SendMessage( "Target another location to complete the bounding box." ); + PickTarget target = new PickTarget( new Point3D( p ), false, from.Map, m_Callback, m_State ); + target.OnCancelled += new BoundingBoxExCancelled(OnTargetCancelled); + from.Target = target; + } + else if ( from.Map != m_Map ) + { + from.SendMessage( "Both locations must reside on the same map." ); + } + else if ( m_Map != null && m_Map != Map.Internal && m_Callback != null ) + { + Point3D start = m_Store; + Point3D end = new Point3D( p ); + + Utility.FixPoints( ref start, ref end ); + + m_Callback( from, m_Map, start, end, m_State ); + } + } + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignRequest.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignRequest.cs new file mode 100644 index 0000000..f03532c --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignRequest.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using OrbServerSDK; +using Server.Engines.OrbRemoteServer; +using UOArchitectInterface; + +namespace Server.Engines.UOArchitect +{ + public class BuildDesignRequest : BaseOrbToolRequest + { + private DesignItemCol m_Items; + + public DesignItemCol Items + { + get{ return m_Items; } + } + + public static void Initialize() + { + OrbServer.Register("UOAR_BuildDesign", typeof(BuildDesignRequest), AccessLevel.GameMaster, true); + } + + public override void OnRequest(OrbClientInfo clientInfo, OrbRequestArgs args) + { + FindOnlineMobile(clientInfo); + + if(args == null) + SendResponse(null); + else if(!(args is BuildRequestArgs)) + SendResponse(null); + else if(!this.IsOnline) + SendResponse(null); + + m_Items = ((BuildRequestArgs)args).Items; + + Mobile.SendMessage("Target the ground where you want to place the building"); + this.Mobile.Target = new BuildDesignTarget(this); + } + + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignTarget Backup.txt b/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignTarget Backup.txt new file mode 100644 index 0000000..e7b51a8 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignTarget Backup.txt @@ -0,0 +1,229 @@ +using System; +using Server.Targeting; +using Server.Items; +using UOArchitectInterface; +using System.Collections; + +namespace Server.Engines.UOArchitect +{ + public class BuildDesignTarget : Target + { + private BuildDesignRequest m_Request; + + public BuildDesignTarget(BuildDesignRequest request) : base( -1, true, TargetFlags.None ) + { + m_Request = request; + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + base.OnTargetCancel(from, cancelType); + m_Request.SendResponse(null); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if(m_Request.Items.Count == 0) + m_Request.SendResponse(null); + + // Used to store the serials of the created items + ArrayList itemSerials = new ArrayList(m_Request.Items.Count); + + IPoint3D p = targeted as IPoint3D; + + if ( p != null ) + { + if ( p is Item ) + p = ((Item)p).GetWorldLocation(); + + for(int i=0; i < m_Request.Items.Count; ++i) + { + DesignItem designItem = m_Request.Items[i]; + + try + { + Point3D location = new Point3D(p.X + designItem.X, p.Y + designItem.Y, p.Z + designItem.Z); + + Item item = CreateItem(designItem.ItemID); + item.MoveToWorld(location, from.Map); + item.Hue = designItem.Hue; + itemSerials.Add(item.Serial.Value); + } + catch(Exception e) + { + Console.WriteLine("Unable to import item: " + e.Message); + } + } + + } + + int[] serials = (int[])itemSerials.ToArray(typeof(int)); + + // send the serial list back to the client + m_Request.SendResponse(new BuildResponse(serials)); + } + + // Create the appropriate item class - Defaults to a Static Item + private Item CreateItem(int ItemID) + { + Item item = null; + + switch(ItemID) + { + // Don't import nodraw, node crystals, odd items, etc. + // Add any unwanted items here. + // TODO: Boat parts: planks, tillerman, etc. + case 0x0001: + case 0x1F19: + case 0x0FB7: + break; + /* + * Put all usable items here, for example, forges, anvils, + * training dummies, lights, containers, messageboards, etc. + * We'll need to wait until some of them are scripted. + * + * The following are some examples, I intend to finish things + * up as quickly as I can. + */ + case 0x0FB1: //forge + item = new SmallForgeAddon(); + break; + case 0x0FAF: //anvil east + item = new AnvilEastAddon(); + break; + case 0x0FB0: //anvil south + item = new AnvilSouthAddon(); + break; + + // TODO: Gates + + /* + * Now create all of the doors according to graphic. + * NOTE: Some doors seem to open the wrong way, but + * there's no way to determine correct CCW/CW + * from the POL file. + */ + + // Metal Doors 2 + case 0x0675: + item = new MetalDoor2( DoorFacing.WestCW ); + break; + case 0x0677: + item = new MetalDoor2( DoorFacing.EastCCW ); + break; + case 0x067D: + item = new MetalDoor2( DoorFacing.SouthCW ); + break; + case 0x067F: + item = new MetalDoor2( DoorFacing.NorthCCW ); + break; + + // Barred Metal Doors + case 0x0685: + item = new BarredMetalDoor( DoorFacing.WestCW ); + break; + case 0x0687: + item = new BarredMetalDoor( DoorFacing.EastCCW ); + break; + case 0x068D: + item = new BarredMetalDoor( DoorFacing.SouthCW ); + break; + case 0x068F: + item = new BarredMetalDoor( DoorFacing.NorthCCW ); + break; + + // Rattan Doors + case 0x0695: + item = new RattanDoor( DoorFacing.WestCW ); + break; + case 0x0697: + item = new RattanDoor( DoorFacing.EastCCW ); + break; + case 0x069D: + item = new RattanDoor( DoorFacing.SouthCW ); + break; + case 0x069F: + item = new RattanDoor( DoorFacing.NorthCCW ); + break; + + // Dark Wood Doors + case 0x06A5: + item = new DarkWoodDoor( DoorFacing.WestCW ); + break; + case 0x06A7: + item = new DarkWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06AD: + item = new DarkWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06AF: + item = new DarkWoodDoor( DoorFacing.NorthCCW ); + break; + + // Medium Wood Doors + case 0x06B5: + item = new MediumWoodDoor( DoorFacing.WestCW ); + break; + case 0x06B7: + item = new MediumWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06BD: + item = new MediumWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06BF: + item = new MediumWoodDoor( DoorFacing.NorthCCW ); + break; + + // Metal Doors + case 0x06C5: + item = new MetalDoor( DoorFacing.WestCW ); + break; + case 0x06C7: + item = new MetalDoor( DoorFacing.EastCCW ); + break; + case 0x06CD: + item = new MetalDoor( DoorFacing.SouthCW ); + break; + case 0x06CF: + item = new MetalDoor( DoorFacing.NorthCCW ); + break; + + // Light Wood Doors + case 0x06D5: + item = new LightWoodDoor( DoorFacing.WestCW ); + break; + case 0x06D7: + item = new LightWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06DD: + item = new LightWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06DF: + item = new LightWoodDoor( DoorFacing.NorthCCW ); + break; + + // Strong Wood Doors + case 0x06E5: + item = new StrongWoodDoor( DoorFacing.WestCW ); + break; + case 0x06E7: + item = new StrongWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06ED: + item = new StrongWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06EF: + item = new StrongWoodDoor( DoorFacing.NorthCCW ); + break; + + default: + item = new Static(ItemID); + item.Movable = false; + break; + + } + + return item; + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignTarget.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignTarget.cs new file mode 100644 index 0000000..b4e8ebe --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/BuildDesignTarget.cs @@ -0,0 +1,636 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Mobiles; +using UOArchitectInterface; +using System.Collections; + +namespace Server.Engines.UOArchitect +{ + public class BuildDesignTarget : Target + { + private BuildDesignRequest m_Request; + + public BuildDesignTarget(BuildDesignRequest request) : base( -1, true, TargetFlags.None ) + { + m_Request = request; + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + base.OnTargetCancel(from, cancelType); + m_Request.SendResponse(null); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if(m_Request.Items.Count == 0) + m_Request.SendResponse(null); + + ArrayList itemSerials = new ArrayList(m_Request.Items.Count); // Used to store the serials of the created items + + IPoint3D p = targeted as IPoint3D; + + if ( p != null ) + { + if ( p is Item ) + p = ((Item)p).GetWorldLocation(); + + for(int i=0; i < m_Request.Items.Count; ++i) + { + DesignItem designItem = m_Request.Items[i]; + + try + { + Point3D location = new Point3D(p.X + designItem.X, p.Y + designItem.Y, p.Z + designItem.Z); + + Item item = CreateItem(designItem.ItemID); + + #region MobileSaver + if ( item.ItemID == 0x1 ) + { + Spawner spawner = MobileSaver.LoadMobile( item ); + + if ( spawner != null ) + itemSerials.Add( spawner.Serial.Value ); + + item.Delete(); + continue; + } + #endregion + + item.MoveToWorld(location, from.Map); + item.Hue = designItem.Hue; + itemSerials.Add(item.Serial.Value); + } + catch(Exception e) + { + Console.WriteLine("Unable to import item: " + e.Message); + } + } + } + + int[] serials = (int[])itemSerials.ToArray(typeof(int)); + + m_Request.SendResponse(new BuildResponse(serials)); // send the serial list back to the client + } + + private Item CreateItem(int ItemID) // Create the appropriate item class - Defaults to a Static Item + { + Item item = null; + + switch(ItemID) + { + #region MobileSaver + case 0x0001: // Now used for Mobile Importing. + { + item = new Static( 0x1 ); + break; + } + #endregion + case 0x1F19: // Add any unwanted items here. + case 0x0FB7: // TODO: Boat parts: planks, tillerman, etc. + break; + + + + case 0x0FB1: //forge + item = new SmallForgeAddon(); + break; + case 0x0FAF: //anvil east + item = new AnvilEastAddon(); + break; + case 0x0FB0: //anvil south + item = new AnvilSouthAddon(); + break; + + case 0x2DD8: //Elven Forge + item = new ElvenForgeAddon(); + break; + + case 0x1922: //FlourMill East + item = new FlourMillEastAddon(); + break; + case 0x1920: case 0x1924: break; //Don't add those items since the addon has them. + case 0x192E: //FlourMill South + item = new FlourMillSouthAddon(); + break; + case 0x192C: case 0x1930: break; //Don't add those items since the addon has them. + + case 0x1060: //Loom East + item = new LoomEastAddon(); + break; + case 0x105F: break; //Don't add those items since the addon has them. + case 0x1061: //Loom South + item = new LoomSouthAddon(); + break; + case 0x1062: break; //Don't add those items since the addon has them. + + case 0x1019: //Spinningwheel East + item = new SpinningwheelEastAddon(); + break; + case 0x1015: //Spinningwheel South + item = new SpinningwheelSouthAddon(); + break; + + + // Housing Metal Doors + case 0x679: + item = new NorthWestDoor(); + break; + case 0x67B: + item = new NorthEastDoor(); + break; + case 0x675: + item = new SouthWestDoor(); + break; + case 0x677: + item = new SouthEastDoor(); + break; + case 0x683: + item = new WestNorthDoor(); + break; + case 0x681: + item = new WestSouthDoor(); + break; + case 0x67F: + item = new EastNorthDoor(); + break; + case 0x67D: + item = new EastSouthDoor(); + break; + + /* + case 0x0675: // Metal Doors 2 NOTE: Some doors seem to open the wrong way, but there's no way to determine correct CCW/CW from the POL file. + item = new MetalDoor2( DoorFacing.WestCW ); + break; + case 0x0677: + item = new MetalDoor2( DoorFacing.EastCCW ); + break; + case 0x067D: + item = new MetalDoor2( DoorFacing.SouthCW ); + break; + case 0x067F: + item = new MetalDoor2( DoorFacing.NorthCCW ); + break; + */ + + case 0x0685: // Barred Metal Doors + item = new BarredMetalDoor( DoorFacing.WestCW ); + break; + case 0x0687: + item = new BarredMetalDoor( DoorFacing.EastCCW ); + break; + case 0x068D: + item = new BarredMetalDoor( DoorFacing.SouthCW ); + break; + case 0x068F: + item = new BarredMetalDoor( DoorFacing.NorthCCW ); + break; + + case 0x0695: // Rattan Doors + item = new RattanDoor( DoorFacing.WestCW ); + break; + case 0x0697: + item = new RattanDoor( DoorFacing.EastCCW ); + break; + case 0x069D: + item = new RattanDoor( DoorFacing.SouthCW ); + break; + case 0x069F: + item = new RattanDoor( DoorFacing.NorthCCW ); + break; + + case 0x06A5: // Dark Wood Doors + item = new DarkWoodDoor( DoorFacing.WestCW ); + break; + case 0x06A7: + item = new DarkWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06AD: + item = new DarkWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06AF: + item = new DarkWoodDoor( DoorFacing.NorthCCW ); + break; + + case 0x06B5: // Medium Wood Doors + item = new MediumWoodDoor( DoorFacing.WestCW ); + break; + case 0x06B7: + item = new MediumWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06BD: + item = new MediumWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06BF: + item = new MediumWoodDoor( DoorFacing.NorthCCW ); + break; + + /* + case 0x06C5: // Metal Doors + item = new MetalDoor( DoorFacing.WestCW ); + break; + case 0x06C7: + item = new MetalDoor( DoorFacing.EastCCW ); + break; + case 0x06CD: + item = new MetalDoor( DoorFacing.SouthCW ); + break; + case 0x06CF: + item = new MetalDoor( DoorFacing.NorthCCW ); + break; + */ + + case 0x06D5: // Light Wood Doors + item = new LightWoodDoor( DoorFacing.WestCW ); + break; + case 0x06D7: + item = new LightWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06DD: + item = new LightWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06DF: + item = new LightWoodDoor( DoorFacing.NorthCCW ); + break; + + case 0x06E5: // Strong Wood Doors + item = new StrongWoodDoor( DoorFacing.WestCW ); + break; + case 0x06E7: + item = new StrongWoodDoor( DoorFacing.EastCCW ); + break; + case 0x06ED: + item = new StrongWoodDoor( DoorFacing.SouthCW ); + break; + case 0x06EF: + item = new StrongWoodDoor( DoorFacing.NorthCCW ); + break; + + case 0x2A05: //South facing West half Paper door (SE) + item = new SWPaperSEDoor(); + break; + case 0x2A07: //South facing East half Paper door (SE) + item = new SEPaperSEDoor(); + break; + case 0x2A09: //East facing South half Paper door (SE) + item = new ESPaperSEDoor(); + break; + case 0x2A0B: //East facing North half Paper door (SE) + item = new ENPaperSEDoor(); + break; + + case 0x2A0D: //South facing West half Cloth door (SE) + item = new SWClothSEDoor(); + break; + case 0x2A0F: //South facing East half Cloth door (SE) + item = new SEClothSEDoor(); + break; + case 0x2A11: //East facing South half Cloth door (SE) + item = new ESClothSEDoor(); + break; + case 0x2A13: //East facing North half Cloth door (SE) + item = new ENClothSEDoor(); + break; + + case 0x2A16: //South facing West half Wooden door (SE) + item = new SWWoodenSEDoor(); + break; + case 0x2A17: //South facing East half Wooden door (SE) + item = new SEWoodenSEDoor(); + break; + case 0x2A19: //East facing South half Wooden door (SE) + item = new ESWoodenSEDoor(); + break; + case 0x2A1B: //East facing North half Wooden door (SE) + item = new ENWoodenSEDoor(); + break; + + + + case 0xE77: //Barrel + item = new Barrel(); + item.Movable = false; + break; + case 0xE7F: //Keg + item = new Keg(); + item.Movable = false; + break; + case 0xE7A: //PicnicBasket + item = new PicnicBasket(); + item.Movable = false; + break; + case 0x990: //Basket + item = new Basket(); + item.Movable = false; + break; + case 0x9AA: //WoodenBox (0xE7D) + item = new WoodenBox(); + item.Movable = false; + break; + case 0xE7D: //WoodenBox (0xE7D) + item = new WoodenBox(); + item.Movable = false; + item.ItemID = 0xE7D; + break; + case 0x9A9: //SmallCrate (0xE7E) + item = new SmallCrate(); + item.Movable = false; + break; + case 0xE7E: //SmallCrate (0xE7E) + item = new SmallCrate(); + item.Movable = false; + item.ItemID = 0xE7E; + break; + case 0xE3F: //MediumCrate (0xE3E) + item = new MediumCrate(); + item.Movable = false; + break; + case 0xE3E: //MediumCrate (0xE3E) + item = new MediumCrate(); + item.Movable = false; + item.ItemID = 0xE3E; + break; + case 0xE3D: //LargeCrate (0xE3C) + item = new LargeCrate(); + item.Movable = false; + break; + case 0xE3C: //LargeCrate (0xE3C) + item = new LargeCrate(); + item.Movable = false; + item.ItemID = 0xE3C; + break; + case 0x9A8: //MetalBox (0xE80) + item = new MetalBox(); + item.Movable = false; + break; + case 0xE80: //MetalBox (0xE80) + item = new MetalBox(); + item.Movable = false; + item.ItemID = 0xE80; + break; + case 0x9AB: //MetalChest (0xE7C) + item = new MetalChest(); + item.Movable = false; + break; + case 0xE7C: //MetalChest (0xE7C) + item = new MetalChest(); + item.Movable = false; + item.ItemID = 0xE7C; + break; + case 0xE41: //MetalGoldenChest (0xE40) + item = new MetalGoldenChest(); + item.Movable = false; + break; + case 0xE40: //MetalGoldenChest (0xE40) + item = new MetalGoldenChest(); + item.Movable = false; + item.ItemID = 0xE40; + break; + case 0xe43: //WoodenChest (0xe42) + item = new WoodenChest(); + item.Movable = false; + break; + case 0xe42: //WoodenChest (0xe42) + item = new WoodenChest(); + item.Movable = false; + item.ItemID = 0xe42; + break; + case 0x280B: //PlainWoodenChest (0x280C) + item = new PlainWoodenChest(); + item.Movable = false; + break; + case 0x280C: //PlainWoodenChest (0x280C) + item = new PlainWoodenChest(); + item.Movable = false; + item.ItemID = 0x280C; + break; + case 0x280D: //OrnateWoodenChest (0x280E) + item = new OrnateWoodenChest(); + item.Movable = false; + break; + case 0x280E: //OrnateWoodenChest (0x280E) + item = new OrnateWoodenChest(); + item.Movable = false; + item.ItemID = 0x280E; + break; + case 0x280F: //GildedWoodenChest (0x2810) + item = new GildedWoodenChest(); + item.Movable = false; + break; + case 0x2810: //GildedWoodenChest (0x2810) + item = new GildedWoodenChest(); + item.Movable = false; + item.ItemID = 0x2810; + break; + case 0x2811: //WoodenFootLocker (0x2812) + item = new WoodenFootLocker(); + item.Movable = false; + break; + case 0x2812: //WoodenFootLocker (0x2812) + item = new WoodenFootLocker(); + item.Movable = false; + item.ItemID = 0x2812; + break; + case 0x2813: //FinishedWoodenChest (0x2814) + item = new FinishedWoodenChest(); + item.Movable = false; + break; + case 0x2814: //FinishedWoodenChest (0x2814) + item = new FinishedWoodenChest(); + item.Movable = false; + item.ItemID = 0x2814; + break; + + case 0x2815: //TallCabinet (0x2816) + item = new TallCabinet(); + item.Movable = false; + break; + case 0x2816: //TallCabinet (0x2816) + item = new TallCabinet(); + item.Movable = false; + item.ItemID = 0x2816; + break; + case 0x2817: //ShortCabinet (0x2818) + item = new ShortCabinet(); + item.Movable = false; + break; + case 0x2818: //ShortCabinet (0x2818) + item = new ShortCabinet(); + item.Movable = false; + item.ItemID = 0x2818; + break; + case 0x2857: //RedArmoire (0x2858) + item = new RedArmoire(); + item.Movable = false; + break; + case 0x2858: //RedArmoire (0x2858) + item = new RedArmoire(); + item.Movable = false; + item.ItemID = 0x2858; + break; + case 0x285D: //CherryArmoire (0x285E) + item = new CherryArmoire(); + item.Movable = false; + break; + case 0x285E: //CherryArmoire (0x285E) + item = new CherryArmoire(); + item.Movable = false; + item.ItemID = 0x285E; + break; + case 0x285B: //MapleArmoire (0x285C) + item = new MapleArmoire(); + item.Movable = false; + break; + case 0x285C: //MapleArmoire (0x285C) + item = new MapleArmoire(); + item.Movable = false; + item.ItemID = 0x285C; + break; + case 0x2859: //ElegantArmoire (0x285A) + item = new ElegantArmoire(); + item.Movable = false; + break; + case 0x285A: //ElegantArmoire (0x285A) + item = new ElegantArmoire(); + item.Movable = false; + item.ItemID = 0x285A; + break; + case 0xA97: //FullBookcase (0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c) + item = new FullBookcase(); + item.Movable = false; + break; + case 0xA99: //FullBookcase (0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c) + item = new FullBookcase(); + item.Movable = false; + item.ItemID = 0xa99; + break; + case 0xA98: //FullBookcase (0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c) + item = new FullBookcase(); + item.Movable = false; + item.ItemID = 0xa98; + break; + case 0xA9a: //FullBookcase (0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c) + item = new FullBookcase(); + item.Movable = false; + item.ItemID = 0xa9a; + break; + case 0xA9b: //FullBookcase (0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c) + item = new FullBookcase(); + item.Movable = false; + item.ItemID = 0xa9b; + break; + case 0xA9c: //FullBookcase (0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c) + item = new FullBookcase(); + item.Movable = false; + item.ItemID = 0xa9c; + break; + case 0xA9D: //EmptyBookcase (0xa9e) + item = new EmptyBookcase(); + item.Movable = false; + break; + case 0xa9e: //EmptyBookcase (0xa9e) + item = new EmptyBookcase (); + item.Movable = false; + item.ItemID = 0xa9e; + break; + case 0xA2C: //Drawer (0xa34) + item = new Drawer(); + item.Movable = false; + break; + case 0xa34: //Drawer (0xa34) + item = new Drawer(); + item.Movable = false; + item.ItemID = 0xa34; + break; + case 0xA30: //FancyDrawer (0xa38) + item = new FancyDrawer(); + item.Movable = false; + break; + case 0xa38: //FancyDrawer (0xa38) + item = new FancyDrawer(); + item.Movable = false; + item.ItemID = 0xa38; + break; + case 0xA4F: //Armoire (0xa53) + item = new Armoire(); + item.Movable = false; + break; + case 0xa53: //Armoire (0xa53) + item = new Armoire(); + item.Movable = false; + item.ItemID = 0xa53; + break; + case 0xA4D: //FancyArmoire (0xa51) + item = new FancyArmoire(); + item.Movable = false; + break; + case 0xa51: //FancyArmoire (0xa51) + item = new FancyArmoire(); + item.Movable = false; + item.ItemID = 0xa51; + break; + + + + default: + item = new Static(ItemID); + item.Movable = false; + break; + + } + + return item; + } + } +} +/* +Added. + +Misc +-ElvenForge +-FlourMill(East/South) +-Loom(East/South)Addon + +Doors +-Paper sliding doors +-Cloth sliding doors +-Wooden sliding doors + +Containers +-Barrel +-Keg +-PicnicBasket +-Basket +-WoodenBox +-SmallCrate +-MediumCrate +-LargeCrate +-MetalBox +-MetalChest +-MetalGoldenChest +-WoodenChest +-PlainWoodenChest +-OrnateWoodenChest +-OrnateWoodenChest +-GildedWoodenChest +-GildedWoodenChest +-WoodenFootLocker +-WoodenFootLocker +-FinishedWoodenChest +-FinishedWoodenChest +-TallCabinet +-ShortCabinet +-RedArmoire +-CherryArmoire +-MapleArmoire +-ElegantArmoire +-FullBookcase +-EmptyBookcase +-Drawer +-FancyDrawer +-Armoire +-FancyArmoire + +*/ \ No newline at end of file diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/ClientCommands.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/ClientCommands.cs new file mode 100644 index 0000000..5dcf68f --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/ClientCommands.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Multis; +using Server.Engines.UOArchitect; +using Server.Commands; + +namespace System.Scripts.Commands +{ + public class ClientCommands + { + public static void Initialize() + { + CommandSystem.Register("NudgeSelfDown", AccessLevel.GameMaster, new CommandEventHandler(NudgeSelfDown_OnCommand)); + CommandSystem.Register("NudgeSelfUp", AccessLevel.GameMaster, new CommandEventHandler(NudgeSelfUp_OnCommand)); + } + + [Usage( "NudgeSelfDown ")] + [Description( "Decreases your z by the specified amount." )] + private static void NudgeSelfDown_OnCommand( CommandEventArgs e ) + { + if(e.Arguments.Length > 0) + { + int zoffset = e.GetInt32(0); + e.Mobile.Location = new Point3D(e.Mobile.Location, e.Mobile.Location.Z - zoffset); + } + } + + [Usage( "NudgeSelfUp ")] + [Description( "Increases your z by the specified amount." )] + private static void NudgeSelfUp_OnCommand( CommandEventArgs e ) + { + if(e.Arguments.Length > 0) + { + int zoffset = e.GetInt32(0); + e.Mobile.Location = new Point3D(e.Mobile.Location, e.Mobile.Location.Z + zoffset); + } + } + + } + + public class MultiDeleteCommand + { + private static Mobile _mobile = null; + + public static void Initialize() + { + CommandSystem.Register("MRemove", AccessLevel.GameMaster, new CommandEventHandler(MultiRemove_OnCommand)); + } + + [Usage( "MRemove")] + [Description( "Allows you to delete items until you press ESC." )] + private static void MultiRemove_OnCommand( CommandEventArgs e ) + { + UOAR_ObjectTarget target = new UOAR_ObjectTarget(); + target.OnTargetObject += new UOAR_ObjectTarget.TargetObjectEvent(OnTargetObject); + + _mobile = e.Mobile; + + e.Mobile.SendMessage("Target items to delete them. Press ESC to stop."); + // send the target to the char + e.Mobile.Target = target; + + } + + private static void OnTargetObject(object obj) + { + if( (obj is Item) && !((obj is BaseMulti) || (obj is HouseSign)) ) + { + (obj as Item).Delete(); + } + else + { + _mobile.SendMessage("You can't delete this object."); + } + + UOAR_ObjectTarget target = new UOAR_ObjectTarget(); + target.OnTargetObject += new UOAR_ObjectTarget.TargetObjectEvent(OnTargetObject); + + // send the target to the char + _mobile.Target = target; + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/DeleteItemsCommand.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/DeleteItemsCommand.cs new file mode 100644 index 0000000..042155c --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/DeleteItemsCommand.cs @@ -0,0 +1,38 @@ +using System; +using OrbServerSDK; +using UOArchitectInterface; +using Server.Engines.OrbRemoteServer; + +namespace Server.Scripts.UOArchitect +{ + public class DeleteItems : OrbCommand + { + public static void Initialize() + { + OrbServer.Register("UOAR_DeleteItems", typeof(DeleteItems), AccessLevel.GameMaster, true); + } + + public override void OnCommand(OrbClientInfo clientInfo, OrbCommandArgs cmdArgs) + { + if(cmdArgs == null || !(cmdArgs is DeleteCommandArgs) ) + return; + + DeleteCommandArgs args = (DeleteCommandArgs)cmdArgs; + + if(args.Count > 0) + { + int[] serials = args.ItemSerials; + + for(int i=0; i < serials.Length; ++i) + { + Item item = World.FindItem(serials[i]); + + if(item == null || item.Deleted) + continue; + + item.Delete(); + } + } + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/ExtractItemsRequest.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/ExtractItemsRequest.cs new file mode 100644 index 0000000..08fddca --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/ExtractItemsRequest.cs @@ -0,0 +1,365 @@ +using System; +using System.IO; +using UOArchitectInterface; +using Server.Targeting; +using System.Collections; +using Server.Items; +using Server.Mobiles; +using Server.Multis; +using System.Threading; +using OrbServerSDK; +using Server.Commands; + +namespace Server.Engines.UOArchitect +{ + public class ExtractItemsRequest : BaseOrbToolRequest + { + private BoundingBoxPickerEx _picker; + private Rect2DCol _rects = new Rect2DCol(); + private Map _map = null; + private DesignItemCol _items = new DesignItemCol(); + private ExtractRequestArgs _args; + private ArrayList _extractedMultiIds = new ArrayList(); + + public static void Initialize() + { + OrbRemoteServer.OrbServer.Register("UOAR_ExtractDesign", typeof(ExtractItemsRequest), AccessLevel.GameMaster, true); + } + + public override void OnRequest(OrbClientInfo client, OrbRequestArgs args) + { + FindOnlineMobile(client); + + if(args == null) + SendResponse(null); + else if(!(args is ExtractRequestArgs)) + SendResponse(null); + else if(!this.IsOnline) + SendResponse(null); + + _args = args as ExtractRequestArgs; + + if(_args.ItemSerials == null) + { + _picker = new BoundingBoxPickerEx(); + _picker.OnCancelled += new BoundingBoxExCancelled(OnTargetCancelled); + _picker.Begin( this.Mobile, new BoundingBoxCallback( BoundingBox_Callback ), null ); + } + else + { + ExtractItems(_args.ItemSerials); + } + } + + private void BoundingBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state ) + { + Utility.FixPoints( ref start, ref end ); + Rectangle2D rect = new Rectangle2D(start, end); + _map = map; + + _rects.Add(new Rect2D(rect.Start.X, rect.Start.Y, rect.Width, rect.Height)); + + if(_args.MultipleRects) + { + _picker.Begin( this.Mobile, new BoundingBoxCallback( BoundingBox_Callback ), null ); + } + else + { + ExtractItems(); + } + } + + private void ExtractItems(int[] itemSerials) + { + for(int i=0; i < itemSerials.Length; ++i) + { + Item item = World.FindItem(itemSerials[i]); + + if ( item != null && !(item is BaseMulti) ) + { + DesignItem designItem = new DesignItem(); + designItem.ItemID = (short)item.ItemID; + designItem.X = item.X; + designItem.Y = item.Y; + designItem.Z = item.Z; + designItem.Hue = (short)item.Hue; + + _items.Add(designItem); + } + } + + ExtractResponse resp = null; + + if(_items.Count > 0) + resp = new ExtractResponse(_items); + else + resp = null; + + SendResponse(resp); + } + + private void ExtractItems() + { + foreach(Rect2D rect in _rects) + { + #region MobileSaver + Rectangle2D realrectangle = new Rectangle2D( rect.TopX, rect.TopY, rect.Width, rect.Height ); + + foreach ( Mobile m in _map.GetMobilesInBounds( realrectangle ) ) + { + if ( m != null && m is BaseCreature ) + { + int saveflag = MobileSaver.GetSaveFlag( m ); + + if ( saveflag > 0 ) + { + DesignItem designItem = new DesignItem(); + designItem.ItemID = (short)0x1; + designItem.X = m.X; + designItem.Y = m.Y; + designItem.Z = m.Z + saveflag; + designItem.Hue = (short)m.Hue; + } + } + } + #endregion + + for ( int x = 0; x <= rect.Width; ++x ) + { + for ( int y = 0; y <= rect.Height; ++y ) + { + int tileX = rect.TopX + x; + int tileY = rect.TopY + y; + + Sector sector = _map.GetSector( tileX, tileY ); + + if (_args.NonStatic || _args.Static) + { + for ( int i = 0; i < sector.Items.Count; ++i ) + { + Item item = (Item)sector.Items[i]; + + if(!item.Visible) + continue; + else if( (!_args.NonStatic) && !(item is Static) ) + continue; + else if( (!_args.Static) && (item is Static) ) + continue; + else if( _args.MinZSet && item.Z < _args.MinZ) + continue; + else if( _args.MaxZSet && item.Z > _args.MaxZ) + continue; + + int hue = 0; + + if(_args.ExtractHues) + hue = item.Hue; + + if ( item.X == tileX && item.Y == tileY && !((item is BaseMulti) || (item is HouseSign))) + { + DesignItem designItem = new DesignItem(); + designItem.ItemID = (short)item.ItemID; + designItem.X = item.X; + designItem.Y = item.Y; + designItem.Z = item.Z; + designItem.Hue = (short)hue; + + _items.Add(designItem); + } + + // extract multi + if(item is HouseFoundation) + { + HouseFoundation house = (HouseFoundation)item; + + if(_extractedMultiIds.IndexOf(house.Serial.Value) == -1) + ExtractCustomMulti(house); + } + } + } + + } + } + } + + ExtractResponse response = new ExtractResponse(_items); + + if(_args.Frozen) + { + response.Rects = _rects; + response.Map = _map.Name; + } + + // send response back to the UOAR tool + SendResponse(response); + } + + private void ExtractCustomMulti(HouseFoundation house) + { + _extractedMultiIds.Add(house.Serial.Value); + + for(int x=0; x < house.Components.Width; ++x) + { + for(int y=0; y < house.Components.Height; ++y) + { + StaticTile[] tiles = house.Components.Tiles[x][y]; + + for ( int i = 0; i < tiles.Length; ++i ) + { + DesignItem designItem = new DesignItem(); + designItem.ItemID = (short)tiles[i].ID; + + designItem.X = x + house.Sign.Location.X; + designItem.Y = (y + house.Sign.Location.Y) - (house.Components.Height - 1); + designItem.Z = house.Location.Z + tiles[i].Z; + + _items.Add(designItem); + } + + } + } + + DesignItem sign = new DesignItem(); + sign.ItemID = (short)(house.Sign.ItemID); + + sign.X = house.Sign.Location.X; + sign.Y = house.Sign.Location.Y; + sign.Z = house.Sign.Location.Z; + + _items.Add(sign); + } + + private void OnTargetCancelled() + { + if(_rects.Count > 0) + ExtractItems(); + else + SendResponse(null); + } + +// private void GetFrozenItems( Map map, IPoint2D start, IPoint2D end, ref ArrayList designItems) +// { +// start = map.Bound( new Point2D(start) ); +// end = map.Bound( new Point2D(end) ); +// +// int xStartBlock = start.X >> 3; +// int yStartBlock = start.Y >> 3; +// int xEndBlock = end.X >> 3; +// int yEndBlock = end.Y >> 3; +// +// int xTileStart = start.X, yTileStart = start.Y; +// int xTileWidth = end.X - start.X + 1, yTileHeight = end.Y - start.Y + 1; +// +// TileMatrix matrix = map.Tiles; +// +// using ( FileStream idxStream = OpenFile(matrix.IndexStream) ) +// { +// using ( FileStream mulStream = OpenFile(matrix.DataStream) ) +// { +// if ( idxStream == null || mulStream == null ) +// { +// return; +// } +// +// BinaryReader idxReader = new BinaryReader( idxStream ); +// +// //for ( int x = xStartBlock; x <= xEndBlock; ++x ) +// for ( int x = xTileStart; x <= xTileWidth; ++x ) +// { +// //for ( int y = yStartBlock; y <= yEndBlock; ++y ) +// for ( int y = yTileStart; y <= yTileHeight; ++y ) +// { +// int tileCount; +// StaticTile[] staticTiles = ReadStaticBlock( idxReader, mulStream, x, y, matrix.BlockWidth, matrix.BlockHeight, out tileCount ); +// +// if ( tileCount < 0 ) +// continue; +// +// for(int i = 0; i < tileCount; ++i) +// { +// StaticTile tile = staticTiles[i]; +// DesignItem item = new DesignItem(); +// +// item.X = x; +// item.Y = y; +// item.Z = tile.m_Z; +// item.Hue = _args.ExtractHues ? (short)tile.m_Hue : (short)0; +// +// designItems.Add(item); +// } +// } +// } +// } +// } +// } + +// private byte[] m_Buffer; +// private StaticTile[] m_TileBuffer = new StaticTile[128]; +// +// private StaticTile[] ReadStaticBlock( BinaryReader idxReader, FileStream mulStream, int x, int y, int width, int height, out int count ) +// { +// try +// { +// if ( x < 0 || x >= width || y < 0 || y >= height ) +// { +// count = -1; +// return m_TileBuffer; +// } +// +// idxReader.BaseStream.Seek( ((x * height) + y) * 12, SeekOrigin.Begin ); +// +// int lookup = idxReader.ReadInt32(); +// int length = idxReader.ReadInt32(); +// +// if ( lookup < 0 || length <= 0 ) +// { +// count = 0; +// } +// else +// { +// count = length / 7; +// +// mulStream.Seek( lookup, SeekOrigin.Begin ); +// +// if ( m_TileBuffer.Length < count ) +// m_TileBuffer = new StaticTile[count]; +// +// StaticTile[] staTiles = m_TileBuffer; +// +// if ( m_Buffer == null || length > m_Buffer.Length ) +// m_Buffer = new byte[length]; +// +// mulStream.Read( m_Buffer, 0, length ); +// +// int index = 0; +// +// for ( int i = 0; i < count; ++i ) +// { +// staTiles[i].m_ID = (short)(m_Buffer[index++] | (m_Buffer[index++] << 8)); +// staTiles[i].m_X = m_Buffer[index++]; +// staTiles[i].m_Y = m_Buffer[index++]; +// staTiles[i].m_Z = (sbyte)m_Buffer[index++]; +// staTiles[i].m_Hue = (short)(m_Buffer[index++] | (m_Buffer[index++] << 8)); +// } +// } +// } +// catch +// { +// count = -1; +// } +// +// return m_TileBuffer; +// } +// +// private FileStream OpenFile( FileStream orig ) +// { +// if ( orig == null ) +// return null; +// +// try{ return new FileStream( orig.Name, FileMode.Open, FileAccess.Read, FileShare.Read ); } +// catch{ return null; } +// } + + } + +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/GetLocationRequest.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/GetLocationRequest.cs new file mode 100644 index 0000000..5020929 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/GetLocationRequest.cs @@ -0,0 +1,52 @@ +using System; +using OrbServerSDK; +using UOArchitectInterface; +using Server.Engines.OrbRemoteServer; + +namespace Server.Engines.UOArchitect +{ + public class GetLocationRequest : BaseOrbToolRequest + { + public static void Initialize() + { + OrbServer.Register("UOAR_GetLocation", typeof(GetLocationRequest), AccessLevel.GameMaster, true); + } + + public override void OnRequest(OrbClientInfo clientInfo, OrbRequestArgs args) + { + FindOnlineMobile(clientInfo); + + if(!this.IsOnline) + { + SendResponse(null); + return; + } + + UOAR_ObjectTarget target = new UOAR_ObjectTarget(); + target.OnTargetObject += new UOAR_ObjectTarget.TargetObjectEvent(OnTarget); + target.OnCancelled += new UOAR_ObjectTarget.TargetCancelEvent(OnCancelTarget); + + this.Mobile.SendMessage("Target an object"); + this.Mobile.Target = target; + } + + private void OnTarget(object targeted) + { + if(targeted != null) + { + IPoint3D location = (IPoint3D)targeted; + SendResponse(new GetLocationResp(location.X, location.Y, location.Z)); + } + else + { + SendResponse(null); + } + } + + private void OnCancelTarget() + { + SendResponse(null); + } + + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/MobileSaver.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/MobileSaver.cs new file mode 100644 index 0000000..1af0b52 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/MobileSaver.cs @@ -0,0 +1,366 @@ +// Created by Peoharen +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server +{ + public class MobileSaver + { + public static List ConversionTable = new List(); + public const int Offset = 1000; + + public static void Configure() + { + #region NPCS + // Vendors NPC + ConversionTable.Add( typeof( Alchemist ) ); + ConversionTable.Add( typeof( AnimalTrainer ) ); + ConversionTable.Add( typeof( Architect ) ); + ConversionTable.Add( typeof( Armorer ) ); + ConversionTable.Add( typeof( Baker ) ); + ConversionTable.Add( typeof( Bard ) ); + ConversionTable.Add( typeof( Barkeeper ) ); + ConversionTable.Add( typeof( Beekeeper ) ); + ConversionTable.Add( typeof( Blacksmith ) ); + ConversionTable.Add( typeof( Bowyer ) ); + ConversionTable.Add( typeof( Butcher ) ); + ConversionTable.Add( typeof( Carpenter ) ); + ConversionTable.Add( typeof( Cobbler ) ); + ConversionTable.Add( typeof( Cook ) ); + ConversionTable.Add( typeof( CustomHairstylist ) ); + ConversionTable.Add( typeof( Farmer ) ); + ConversionTable.Add( typeof( Fisherman ) ); + ConversionTable.Add( typeof( Furtrader ) ); + ConversionTable.Add( typeof( Glassblower ) ); + ConversionTable.Add( typeof( GolemCrafter ) ); + ConversionTable.Add( typeof( GypsyAnimalTrainer ) ); + ConversionTable.Add( typeof( GypsyBanker ) ); + ConversionTable.Add( typeof( GypsyMaiden ) ); + ConversionTable.Add( typeof( HairStylist ) ); + ConversionTable.Add( typeof( Herbalist ) ); + ConversionTable.Add( typeof( HolyMage ) ); + ConversionTable.Add( typeof( InnKeeper ) ); + ConversionTable.Add( typeof( IronWorker ) ); + ConversionTable.Add( typeof( Jeweler ) ); + ConversionTable.Add( typeof( KeeperOfChivalry ) ); + ConversionTable.Add( typeof( LeatherWorker ) ); + ConversionTable.Add( typeof( Mage ) ); + ConversionTable.Add( typeof( Mapmaker ) ); + ConversionTable.Add( typeof( Miller ) ); + ConversionTable.Add( typeof( Miner ) ); + ConversionTable.Add( typeof( Monk ) ); + ConversionTable.Add( typeof( Provisioner ) ); + ConversionTable.Add( typeof( Rancher ) ); + ConversionTable.Add( typeof( Ranger ) ); + ConversionTable.Add( typeof( RealEstateBroker ) ); + ConversionTable.Add( typeof( Scribe ) ); + ConversionTable.Add( typeof( Shipwright ) ); + ConversionTable.Add( typeof( StoneCrafter ) ); + ConversionTable.Add( typeof( Tailor ) ); + ConversionTable.Add( typeof( Tanner ) ); + ConversionTable.Add( typeof( TavernKeeper ) ); + ConversionTable.Add( typeof( Thief ) ); + ConversionTable.Add( typeof( Tinker ) ); + ConversionTable.Add( typeof( Vagabond ) ); + ConversionTable.Add( typeof( VarietyDealer ) ); + ConversionTable.Add( typeof( Veterinarian ) ); + ConversionTable.Add( typeof( Waiter ) ); + ConversionTable.Add( typeof( Weaponsmith ) ); + ConversionTable.Add( typeof( Weaver ) ); + // Vendors Guildmasters + ConversionTable.Add( typeof( BardGuildmaster ) ); + ConversionTable.Add( typeof( BlacksmithGuildmaster ) ); + ConversionTable.Add( typeof( FisherGuildmaster ) ); + ConversionTable.Add( typeof( HealerGuildmaster ) ); + ConversionTable.Add( typeof( MageGuildmaster ) ); + ConversionTable.Add( typeof( MerchantGuildmaster ) ); + ConversionTable.Add( typeof( MinerGuildmaster ) ); + ConversionTable.Add( typeof( RangerGuildmaster ) ); + ConversionTable.Add( typeof( TailorGuildmaster ) ); + ConversionTable.Add( typeof( ThiefGuildmaster ) ); + ConversionTable.Add( typeof( TinkerGuildmaster ) ); + ConversionTable.Add( typeof( WarriorGuildmaster ) ); + // Townfolk + ConversionTable.Add( typeof( Actor ) ); + ConversionTable.Add( typeof( Artist ) ); + ConversionTable.Add( typeof( Banker ) ); + ConversionTable.Add( typeof( BrideGroom ) ); + ConversionTable.Add( typeof( EscortableMage ) ); + ConversionTable.Add( typeof( Gypsy ) ); + ConversionTable.Add( typeof( HarborMaster ) ); + ConversionTable.Add( typeof( Merchant ) ); + ConversionTable.Add( typeof( Messenger ) ); + ConversionTable.Add( typeof( Minter ) ); + ConversionTable.Add( typeof( Ninja ) ); + ConversionTable.Add( typeof( Noble ) ); + ConversionTable.Add( typeof( Peasant ) ); + ConversionTable.Add( typeof( Samurai ) ); + ConversionTable.Add( typeof( Sculptor ) ); + ConversionTable.Add( typeof( SeekerOfAdventure ) ); + ConversionTable.Add( typeof( TownCrier ) ); + // Guards + ConversionTable.Add( typeof( ArcherGuard ) ); + ConversionTable.Add( typeof( WarriorGuard ) ); + // Healers + ConversionTable.Add( typeof( EvilHealer ) ); + ConversionTable.Add( typeof( EvilWanderingHealer ) ); + ConversionTable.Add( typeof( FortuneTeller ) ); + ConversionTable.Add( typeof( Healer ) ); + ConversionTable.Add( typeof( PricedHealer ) ); + ConversionTable.Add( typeof( WanderingHealer ) ); + #endregion + + #region Animals + // Animals Bears + ConversionTable.Add( typeof( BlackBear ) ); + ConversionTable.Add( typeof( BrownBear ) ); + ConversionTable.Add( typeof( GrizzlyBear ) ); + ConversionTable.Add( typeof( PolarBear ) ); + // Animals Birds + ConversionTable.Add( typeof( Chicken ) ); + ConversionTable.Add( typeof( Crane ) ); + ConversionTable.Add( typeof( Eagle ) ); + ConversionTable.Add( typeof( Phoenix ) ); + // Animals Canines + ConversionTable.Add( typeof( DireWolf ) ); + ConversionTable.Add( typeof( GreyWolf ) ); + ConversionTable.Add( typeof( TimberWolf ) ); + ConversionTable.Add( typeof( WhiteWolf ) ); + // Animals Cows + ConversionTable.Add( typeof( Bull ) ); + ConversionTable.Add( typeof( Cow ) ); + // Animals Felines + ConversionTable.Add( typeof( Cougar ) ); + ConversionTable.Add( typeof( HellCat ) ); + ConversionTable.Add( typeof( Panther ) ); + ConversionTable.Add( typeof( PredatorHellCat ) ); + ConversionTable.Add( typeof( SnowLeopard ) ); + // Animals Misc + ConversionTable.Add( typeof( Boar ) ); + ConversionTable.Add( typeof( BullFrog ) ); + ConversionTable.Add( typeof( Dolphin ) ); + ConversionTable.Add( typeof( Gaman ) ); + ConversionTable.Add( typeof( GiantToad ) ); + ConversionTable.Add( typeof( Goat ) ); + ConversionTable.Add( typeof( Gorilla ) ); + ConversionTable.Add( typeof( GreatHart ) ); + ConversionTable.Add( typeof( Hind ) ); + ConversionTable.Add( typeof( Llama ) ); + ConversionTable.Add( typeof( MountainGoat ) ); + ConversionTable.Add( typeof( PackHorse ) ); + ConversionTable.Add( typeof( PackLlama ) ); + ConversionTable.Add( typeof( Pig ) ); + ConversionTable.Add( typeof( Sheep ) ); + ConversionTable.Add( typeof( Walrus ) ); + // Animals Mounts + ConversionTable.Add( typeof( Beetle ) ); + ConversionTable.Add( typeof( DesertOstard ) ); + ConversionTable.Add( typeof( FireSteed ) ); + ConversionTable.Add( typeof( ForestOstard ) ); + ConversionTable.Add( typeof( HellSteed ) ); + ConversionTable.Add( typeof( Hiryu ) ); + ConversionTable.Add( typeof( Horse ) ); + ConversionTable.Add( typeof( Kirin ) ); + ConversionTable.Add( typeof( LesserHiryu ) ); + ConversionTable.Add( typeof( RidableLlama ) ); + ConversionTable.Add( typeof( Ridgeback ) ); + ConversionTable.Add( typeof( SavageRidgeback ) ); + ConversionTable.Add( typeof( ScaledSwampDragon ) ); + ConversionTable.Add( typeof( SeaHorse ) ); + ConversionTable.Add( typeof( SilverSteed ) ); + ConversionTable.Add( typeof( SkeletalMount ) ); + ConversionTable.Add( typeof( SwampDragon ) ); + ConversionTable.Add( typeof( Unicorn ) ); + // Animals Mounts War Horses + ConversionTable.Add( typeof( CoMWarHorse ) ); + ConversionTable.Add( typeof( MinaxWarHorse ) ); + ConversionTable.Add( typeof( SLWarHorse ) ); + ConversionTable.Add( typeof( TBWarHorse ) ); + // Animals Reptiles + ConversionTable.Add( typeof( Alligator ) ); + ConversionTable.Add( typeof( GiantSerpent ) ); + ConversionTable.Add( typeof( IceSerpent ) ); + ConversionTable.Add( typeof( IceSnake ) ); + ConversionTable.Add( typeof( LavaLizard ) ); + ConversionTable.Add( typeof( LavaSerpent ) ); + ConversionTable.Add( typeof( LavaSnake ) ); + ConversionTable.Add( typeof( SilverSerpent ) ); + ConversionTable.Add( typeof( Snake ) ); + // Animals Rodents + ConversionTable.Add( typeof( GiantRat ) ); + ConversionTable.Add( typeof( JackRabbit ) ); + ConversionTable.Add( typeof( Rabbit ) ); + ConversionTable.Add( typeof( Sewerrat ) ); + // Animals Slimes + ConversionTable.Add( typeof( Jwilson ) ); + // Animals Town Critters + ConversionTable.Add( typeof( Bird ) ); + ConversionTable.Add( typeof( Cat ) ); + ConversionTable.Add( typeof( Dog ) ); + ConversionTable.Add( typeof( Rat ) ); + #endregion + + #region Special + ConversionTable.Add( typeof( Barracoon ) ); + ConversionTable.Add( typeof( ChaosGuard ) ); + ConversionTable.Add( typeof( Harrower ) ); + ConversionTable.Add( typeof( HarrowerTentacles ) ); + ConversionTable.Add( typeof( LordOaks ) ); + ConversionTable.Add( typeof( Mephitis ) ); + ConversionTable.Add( typeof( Neira ) ); + ConversionTable.Add( typeof( OrderGuard ) ); + ConversionTable.Add( typeof( Rikktor ) ); + ConversionTable.Add( typeof( Semidar ) ); + ConversionTable.Add( typeof( Serado ) ); + ConversionTable.Add( typeof( ServantOfSemidar ) ); + ConversionTable.Add( typeof( Silvani ) ); + #endregion + + #region Monsters + // Monsters Ants + ConversionTable.Add( typeof( AntLion ) ); + ConversionTable.Add( typeof( BlackSolenInfiltratorQueen ) ); + ConversionTable.Add( typeof( BlackSolenInfiltratorWarrior ) ); + ConversionTable.Add( typeof( BlackSolenQueen ) ); + ConversionTable.Add( typeof( BlackSolenWarrior ) ); + ConversionTable.Add( typeof( BlackSolenWorker ) ); + ConversionTable.Add( typeof( RedSolenInfiltratorQueen ) ); + ConversionTable.Add( typeof( RedSolenInfiltratorWarrior ) ); + ConversionTable.Add( typeof( RedSolenQueen ) ); + ConversionTable.Add( typeof( RedSolenWarrior ) ); + ConversionTable.Add( typeof( RedSolenWorker ) ); + // Monsters AOS + ConversionTable.Add( typeof( AbysmalHorror ) ); + ConversionTable.Add( typeof( BoneDemon ) ); + ConversionTable.Add( typeof( CrystalElemental ) ); + ConversionTable.Add( typeof( DarknightCreeper ) ); + ConversionTable.Add( typeof( DemonKnight ) ); + ConversionTable.Add( typeof( Devourer ) ); + ConversionTable.Add( typeof( FleshGolem ) ); + ConversionTable.Add( typeof( FleshRenderer ) ); + ConversionTable.Add( typeof( Gibberling ) ); + ConversionTable.Add( typeof( GoreFiend ) ); + ConversionTable.Add( typeof( Impaler ) ); + ConversionTable.Add( typeof( MoundOfMaggots ) ); + ConversionTable.Add( typeof( PatchworkSkeleton ) ); + ConversionTable.Add( typeof( Ravager ) ); + ConversionTable.Add( typeof( Revenant ) ); + ConversionTable.Add( typeof( ShadowKnight ) ); + ConversionTable.Add( typeof( SkitteringHopper ) ); + ConversionTable.Add( typeof( Treefellow ) ); + ConversionTable.Add( typeof( VampireBat ) ); + ConversionTable.Add( typeof( WailingBanshee ) ); + ConversionTable.Add( typeof( WandererOfTheVoid ) ); + // Monsters Arachnid Magic + ConversionTable.Add( typeof( DreadSpider ) ); + ConversionTable.Add( typeof( TerathanAvenger ) ); + ConversionTable.Add( typeof( TerathanMatriarch ) ); + // Monsters Arachnid Melee + ConversionTable.Add( typeof( FrostSpider ) ); + ConversionTable.Add( typeof( GiantBlackWidow ) ); + ConversionTable.Add( typeof( GiantSpider ) ); + ConversionTable.Add( typeof( TerathanDrone ) ); + ConversionTable.Add( typeof( TerathanWarrior ) ); + // Monsters Elemental Magic + ConversionTable.Add( typeof( AirElemental ) ); + ConversionTable.Add( typeof( BloodElemental ) ); + ConversionTable.Add( typeof( Efreet ) ); + ConversionTable.Add( typeof( FireElemental ) ); + ConversionTable.Add( typeof( IceElemental ) ); + ConversionTable.Add( typeof( PoisonElemental ) ); + ConversionTable.Add( typeof( AcidElemental ) ); + ConversionTable.Add( typeof( WaterElemental ) ); + // Monsters Elemental Melee + ConversionTable.Add( typeof( EarthElemental ) ); + ConversionTable.Add( typeof( SnowElemental ) ); + // Monsters Humanoid Magic + ConversionTable.Add( typeof( AncientLich ) ); + ConversionTable.Add( typeof( ArcaneDaemon ) ); + ConversionTable.Add( typeof( Balron ) ); + ConversionTable.Add( typeof( Betrayer ) ); + ConversionTable.Add( typeof( Bogle ) ); + ConversionTable.Add( typeof( BoneMagi ) ); + ConversionTable.Add( typeof( Daemon ) ); + ConversionTable.Add( typeof( ElderGazer ) ); + ConversionTable.Add( typeof( EvilMage ) ); + ConversionTable.Add( typeof( EvilMageLord ) ); + ConversionTable.Add( typeof( FireGargoyle ) ); + ConversionTable.Add( typeof( Gargoyle ) ); + ConversionTable.Add( typeof( GargoyleDestroyer ) ); + ConversionTable.Add( typeof( GargoyleEnforcer ) ); + ConversionTable.Add( typeof( Gazer ) ); + ConversionTable.Add( typeof( GolemController ) ); + ConversionTable.Add( typeof( IceFiend ) ); + ConversionTable.Add( typeof( Imp ) ); + ConversionTable.Add( typeof( Lich ) ); + ConversionTable.Add( typeof( LichLord ) ); + ConversionTable.Add( typeof( OrcishMage ) ); + ConversionTable.Add( typeof( RatmanMage ) ); + ConversionTable.Add( typeof( SavageShaman ) ); + ConversionTable.Add( typeof( Shade ) ); + ConversionTable.Add( typeof( SkeletalMage ) ); + ConversionTable.Add( typeof( Spectre ) ); + ConversionTable.Add( typeof( Spellbinder ) ); + ConversionTable.Add( typeof( Succubus ) ); + ConversionTable.Add( typeof( Titan ) ); + ConversionTable.Add( typeof( Wraith ) ); + // Monsters Humanoid Melee + // LBR Exodus + // LBR Jukas + // LBR Meers + // Mammel Melee + // Misc Magic + // Misc Melee + // ML Animal + // ML Humanoid Magic + // ML Humanoid Melee + // ML Misc Magic + // ML Misc Melee + // ML Special + // Ore Elementals + // Plant Magic + // Plant Melee + // Reptile Magic + // Reptile Melee + // SE + // Summons + #endregion + + + //ConversionTable.Add( typeof( ) ); + + } + + public static Spawner LoadMobile( Item item ) + { + Type t = GetType( item.Z - Offset ); + + if ( t == null ) + return null; + + Spawner spawner = new Spawner(); + spawner.SpawnNames.Add( t.ToString() ); + spawner.Running = true; + spawner.HomeRange = 0; + spawner.WalkingRange = 4; + //spawner.Respawn(); + return spawner; + } + + public static int GetSaveFlag( Mobile m ) + { + return ConversionTable.IndexOf( m.GetType() ) + Offset; + } + + public static Type GetType( int saveflag ) + { + if ( saveflag > 0 && saveflag < ConversionTable.Count ) + return ConversionTable[saveflag]; + else + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/MoveItemsCommand.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/MoveItemsCommand.cs new file mode 100644 index 0000000..fb6cdf7 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/MoveItemsCommand.cs @@ -0,0 +1,46 @@ +using System; +using OrbServerSDK; +using UOArchitectInterface; +using Server.Engines.OrbRemoteServer; + +namespace Server.Scripts.UOArchitect +{ + public class MoveItemsCommand : OrbCommand + { + public static void Initialize() + { + OrbServer.Register("UOAR_MoveItems", typeof(MoveItemsCommand), AccessLevel.GameMaster, true); + } + + public override void OnCommand(OrbClientInfo client, OrbCommandArgs cmdArgs) + { + if(cmdArgs == null || !(cmdArgs is MoveItemsArgs) ) + return; + + MoveItemsArgs args = (MoveItemsArgs)cmdArgs; + + if(args.Count > 0) + { + int xoffset = args.Xoffset; + int yoffset = args.Yoffset; + int zoffset = args.Zoffset; + + int[] serials = args.ItemSerials; + + for(int i=0; i < serials.Length; ++i) + { + Item item = World.FindItem(serials[i]); + + if(item == null) + continue; + + int newX = item.X + xoffset; + int newY = item.Y + yoffset; + int newZ = item.Z + zoffset; + + item.Location = new Point3D(newX, newY, newZ); + } + } + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/SelectItemsRequest.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/SelectItemsRequest.cs new file mode 100644 index 0000000..3455ff7 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/SelectItemsRequest.cs @@ -0,0 +1,155 @@ +using System; +using OrbServerSDK; +using Server.Engines.OrbRemoteServer; +using UOArchitectInterface; +using Server; +using Server.Mobiles; +using Server.Multis; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Engines.UOArchitect +{ + public class SelectItemsRequest : BaseOrbToolRequest + { + private ArrayList _itemSerials = new ArrayList(); + private SelectItemsRequestArgs _args = null; + + public static void Initialize() + { + OrbServer.Register("UOAR_SelectItems", typeof(SelectItemsRequest), AccessLevel.GameMaster, true); + } + + public override void OnRequest(OrbClientInfo clientInfo, OrbRequestArgs reqArgs) + { + FindOnlineMobile(clientInfo); + + if(reqArgs == null || !(reqArgs is SelectItemsRequestArgs) || !this.IsOnline) + SendResponse(null); + + _args = (SelectItemsRequestArgs)reqArgs; + + if(_args.SelectType == SelectTypes.Area) + { + BoundingBoxPickerEx picker = new BoundingBoxPickerEx(); + picker.OnCancelled += new BoundingBoxExCancelled(OnTargetCancelled); + picker.Begin( this.Mobile, new BoundingBoxCallback( BoundingBox_Callback ), null ); + } + else + { + UOAR_ObjectTarget target = new UOAR_ObjectTarget(); + target.OnCancelled += new UOAR_ObjectTarget.TargetCancelEvent(OnTargetCancelled); + target.OnTargetObject += new UOAR_ObjectTarget.TargetObjectEvent(OnTargetObject); + + this.Mobile.SendMessage("Target the first item you want to select."); + // send the target to the char + this.Mobile.Target = target; + } + } + + private void BoundingBox_Callback( Mobile from, Map map, Point3D start, Point3D end, object state ) + { + Utility.FixPoints( ref start, ref end ); + Rectangle2D rect = new Rectangle2D(start, end); + + #region MobileSaver + from.SendMessage( "Extracting Mobiles" ); + + foreach ( Mobile m in map.GetMobilesInBounds( rect ) ) + { + if ( m != null && m is BaseCreature ) + { + int saveflag = MobileSaver.GetSaveFlag( m ); + + if ( saveflag > 0 ) + { + DesignItem designItem = new DesignItem(); + designItem.ItemID = (short)0x1; + designItem.X = m.X; + designItem.Y = m.Y; + designItem.Z = m.Z + saveflag; + designItem.Hue = (short)m.Hue; + } + } + } + #endregion + + for ( int x = 0; x <= rect.Width; ++x ) + { + for ( int y = 0; y <= rect.Height; ++y ) + { + int tileX = rect.Start.X + x; + int tileY = rect.Start.Y + y; + + Sector sector = map.GetSector( tileX, tileY ); + + for ( int i = 0; i < sector.Items.Count; ++i ) + { + Item item = (Item)sector.Items[i]; + + if(_args.UseMinZ && item.Z < _args.MinZ) + continue; + else if(_args.UseMaxZ && item.Z > _args.MaxZ) + continue; + + if ( item.Visible && item.X == tileX && item.Y == tileY && !((item is BaseMulti) || (item is HouseSign)) ) + { + _itemSerials.Add(item.Serial.Value); + } + } + } + } + + if(_itemSerials.Count > 0) + SendResponse(new SelectItemsResponse((int[])_itemSerials.ToArray(typeof(int)))); + else + SendResponse(null); + } + + private void OnTargetCancelled() + { + if(_itemSerials.Count > 0) + { + SendResponse(new SelectItemsResponse((int[])_itemSerials.ToArray(typeof(int)))); + } + else + { + SendResponse(null); + } + } + + private void OnTargetObject(object obj) + { + if( (obj is Item) && !((obj is BaseMulti) || (obj is HouseSign)) ) + { + int serial = (obj as Item).Serial.Value; + + if(_itemSerials.IndexOf(serial) == -1) + { + // add the item's serial # to the ArrayList + _itemSerials.Add( ((Item)obj).Serial.Value ); + } + } + else + { + this.Mobile.SendMessage("That object is not valid for this selection."); + } + + if(_args.Multiple) + { + UOAR_ObjectTarget target = new UOAR_ObjectTarget(); + target.OnCancelled += new UOAR_ObjectTarget.TargetCancelEvent(OnTargetCancelled); + target.OnTargetObject += new UOAR_ObjectTarget.TargetObjectEvent(OnTargetObject); + + this.Mobile.SendMessage("Select another item to add it to your selection or press ESC to finish."); + // send the target to the char + this.Mobile.Target = target; + } + else + { + OnTargetCancelled(); + } + } + } +} diff --git a/Scripts/Customs/OrbRemoteServer/UOArchitect/UOAR_ObjectTarget.cs b/Scripts/Customs/OrbRemoteServer/UOArchitect/UOAR_ObjectTarget.cs new file mode 100644 index 0000000..796b584 --- /dev/null +++ b/Scripts/Customs/OrbRemoteServer/UOArchitect/UOAR_ObjectTarget.cs @@ -0,0 +1,37 @@ +using System; +using Server; +using Server.Multis; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Engines.UOArchitect +{ + public class UOAR_ObjectTarget : Target + { + public delegate void TargetCancelEvent(); + public delegate void TargetObjectEvent(object targeted); + + public TargetObjectEvent OnTargetObject; + public TargetCancelEvent OnCancelled; + + public UOAR_ObjectTarget() : base( -1, true, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if(OnTargetObject != null) + OnTargetObject(targeted); + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + if(OnCancelled != null) + OnCancelled(); + + base.OnTargetCancel (from, cancelType); + } + + } +} diff --git a/Scripts/Customs/RazorNegotiator.cs b/Scripts/Customs/RazorNegotiator.cs new file mode 100644 index 0000000..80d8a2e --- /dev/null +++ b/Scripts/Customs/RazorNegotiator.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Gumps; + +namespace Server.Misc +{ + public class RazorFeatureControl + { + public const bool Enabled = true; // Is the "Feature Enforced" turned on? + public const bool KickOnFailure = false; // When true, this will cause anyone who does not negotiate (include those not running Razor at all) to be disconnected from the server. + public static readonly TimeSpan HandshakeTimeout = TimeSpan.FromSeconds(30.0); // How long to wait for a handshake response before showing warning and disconnecting + public static readonly TimeSpan DisconnectDelay = TimeSpan.FromSeconds(15.0); // How long to show warning message before they are disconnected + public const string WarningMessage = "The server was unable to negotiate features with Razor on your system.
You must be running the latest version of Razor to play on this server.
Once you have Razor installed and running, go to the Options tab and check the box in the lower right-hand corner marked Negotiate features with server. Once you have this box checked, you may log in and play normally.
You will be disconnected shortly."; + + public static void Configure() + { + DisallowFeature(RazorFeatures.LoopedMacros); + DisallowFeature(RazorFeatures.FilterWeather); + DisallowFeature(RazorFeatures.FilterLight); + DisallowFeature(RazorFeatures.PoisonedChecks); + DisallowFeature(RazorFeatures.AutoOpenDoors); + DisallowFeature(RazorFeatures.AutoPotionEquip); + // TODO: Add your server's feature allowances here + // For example, the following line will disallow all looping macros on your server + //DisallowFeature( RazorFeatures.LoopedMacros ); + } + + [Flags] + public enum RazorFeatures : ulong + { + None = 0, + + FilterWeather = 1 << 0, // Weather Filter + FilterLight = 1 << 1, // Light Filter + SmartTarget = 1 << 2, // Smart Last Target + RangedTarget = 1 << 3, // Range Check Last Target + AutoOpenDoors = 1 << 4, // Automatically Open Doors + DequipOnCast = 1 << 5, // Unequip Weapon on spell cast + AutoPotionEquip = 1 << 6, // Un/Re-equip weapon on potion use + PoisonedChecks = 1 << 7, // Block heal If poisoned/Macro IIf Poisoned condition/Heal or Cure self + LoopedMacros = 1 << 8, // Disallow Looping macros, For loops, and macros that call other macros + UseOnceAgent = 1 << 9, // The use once agent + RestockAgent = 1 << 10,// The restock agent + SellAgent = 1 << 11,// The sell agent + BuyAgent = 1 << 12,// The buy agent + PotionHotkeys = 1 << 13,// All potion hotkeys + RandomTargets = 1 << 14,// All random target hotkeys (Not target next, last target, target self) + ClosestTargets = 1 << 15,// All closest target hotkeys + OverheadHealth = 1 << 16,// Health and Mana/Stam messages shown over player's heads + + All = 0xFFFFFFFFFFFFFFFF // Every feature possible + } + + private static RazorFeatures m_DisallowedFeatures = RazorFeatures.None; + + public static void DisallowFeature(RazorFeatures feature) + { + SetDisallowed(feature, true); + } + + public static void AllowFeature(RazorFeatures feature) + { + SetDisallowed(feature, false); + } + + public static void SetDisallowed(RazorFeatures feature, bool value) + { + if (value) + m_DisallowedFeatures |= feature; + else + m_DisallowedFeatures &= ~feature; + } + + public static RazorFeatures DisallowedFeatures { get { return m_DisallowedFeatures; } } + } + + public class RazorFeatureEnforcer + { + private static Hashtable m_Table = new Hashtable(); + private static TimerStateCallback OnHandshakeTimeout_Callback = new TimerStateCallback(OnHandshakeTimeout); + private static TimerStateCallback OnForceDisconnect_Callback = new TimerStateCallback(OnForceDisconnect); + + public static void Initialize() + { + if (RazorFeatureControl.Enabled) + { + EventSink.Login += new LoginEventHandler(EventSink_Login); + + ProtocolExtensions.Register(0xFF, true, new OnPacketReceive(OnHandshakeResponse)); + } + } + + private static void EventSink_Login(LoginEventArgs e) + { + Mobile m = e.Mobile; + if (m != null && m.NetState != null && m.NetState.Running) + { + Timer t; + + m.Send(new BeginRazorHandshake()); + + if (m_Table.ContainsKey(m)) + { + t = m_Table[m] as Timer; + if (t != null && t.Running) + t.Stop(); + } + + m_Table[m] = t = Timer.DelayCall(RazorFeatureControl.HandshakeTimeout, OnHandshakeTimeout_Callback, m); + t.Start(); + } + } + + private static void OnHandshakeResponse(NetState state, PacketReader pvSrc) + { + pvSrc.Trace(state); + + if (state == null || state.Mobile == null || !state.Running) + return; + + Mobile m = state.Mobile; + Timer t = null; + if (m_Table.Contains(m)) + { + t = m_Table[m] as Timer; + + if (t != null) + t.Stop(); + + m_Table.Remove(m); + } + } + + private static void OnHandshakeTimeout(object state) + { + Timer t = null; + Mobile m = state as Mobile; + if (m == null) + return; + + m_Table.Remove(m); + + // Plume : Retrait : on sait d�j� que certains clients n'utiliseront pas Razor. + if (!RazorFeatureControl.KickOnFailure) + { + //Console.WriteLine("Player '{0}' failed to negotiate Razor features.", m); + } + else if (m.NetState != null && m.NetState.Running) + { + m.SendGump(new Gumps.WarningGump(1060635, 30720, RazorFeatureControl.WarningMessage, 0xFFC000, 420, 250, null, null)); + + if (m.AccessLevel <= AccessLevel.Player) + { + m_Table[m] = t = Timer.DelayCall(RazorFeatureControl.DisconnectDelay, OnForceDisconnect_Callback, m); + t.Start(); + } + } + } + + private static void OnForceDisconnect(object state) + { + if (state is Mobile) + { + Mobile m = (Mobile)state; + + if (m.NetState != null && m.NetState.Running) + m.NetState.Dispose(); + m_Table.Remove(m); + + Console.WriteLine("Player {0} kicked (Failed Razor handshake)", m); + } + } + + private sealed class BeginRazorHandshake : ProtocolExtension + { + public BeginRazorHandshake() + : base(0xFE, 8) + { + m_Stream.Write((uint)((ulong)RazorFeatureControl.DisallowedFeatures >> 32)); + m_Stream.Write((uint)((ulong)RazorFeatureControl.DisallowedFeatures & 0xFFFFFFFF)); + } + } + } +} diff --git a/Scripts/Customs/Town Houses/Gumps/Error Reporting/Errors.cs b/Scripts/Customs/Town Houses/Gumps/Error Reporting/Errors.cs new file mode 100644 index 0000000..2446d78 --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Error Reporting/Errors.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections; +using Server; +using Server.Network; + +namespace Knives.TownHouses +{ + public class Errors + { + private static ArrayList s_ErrorLog = new ArrayList(); + private static ArrayList s_Checked = new ArrayList(); + + public static ArrayList ErrorLog{ get{ return s_ErrorLog; } } + public static ArrayList Checked{ get{ return s_Checked; } } + + public static void Initialize() + { + RUOVersion.AddCommand("Erreure TownHouse", AccessLevel.Counselor, new TownHouseCommandHandler(OnErrors)); + RUOVersion.AddCommand("le", AccessLevel.Counselor, new TownHouseCommandHandler(OnErrors)); + + EventSink.Login += new LoginEventHandler( OnLogin ); + } + + private static void OnErrors( CommandInfo e ) + { + if ( e.ArgString == null || e.ArgString == "" ) + new ErrorsGump( e.Mobile ); + else + Report( e.ArgString + " - " + e.Mobile.Name ); + } + + private static void OnLogin( LoginEventArgs e ) + { + if ( e.Mobile.AccessLevel != AccessLevel.Player + && s_ErrorLog.Count != 0 + && !s_Checked.Contains( e.Mobile ) ) + new ErrorsNotifyGump( e.Mobile ); + } + + public static void Report( string error ) + { + s_ErrorLog.Add( String.Format( "{0}
{1}
", DateTime.Now, error ) ); + + s_Checked.Clear(); + + Notify(); + } + + private static void Notify() + { + foreach( NetState state in NetState.Instances ) + { + if ( state.Mobile == null ) + continue; + + if ( state.Mobile.AccessLevel != AccessLevel.Player ) + Notify( state.Mobile ); + } + } + + public static void Notify( Mobile m ) + { + if ( m.HasGump( typeof( ErrorsGump ) ) ) + new ErrorsGump( m ); + else + new ErrorsNotifyGump( m ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Error Reporting/ErrorsGump.cs b/Scripts/Customs/Town Houses/Gumps/Error Reporting/ErrorsGump.cs new file mode 100644 index 0000000..b744539 --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Error Reporting/ErrorsGump.cs @@ -0,0 +1,55 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public class ErrorsGump : GumpPlusLight + { + public ErrorsGump( Mobile m ) : base( m, 100, 100 ) + { + Errors.Checked.Add(m); + + m.CloseGump( typeof( ErrorsGump ) ); + } + + protected override void BuildGump() + { + int width = 400; + int y = 10; + + AddHtml(0, y, width, "
Erreur TownHouse"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddButton(width - 20, y, 0x5689, 0x5689, "Aide", new GumpCallback(Help)); + + string str = HTML.Black; + foreach( string text in Errors.ErrorLog ) + str += text; + + AddHtml( 20, y+=25, width-40, 200, str, true, true ); + + y += 200; + + if ( Owner.AccessLevel >= AccessLevel.Administrator ) + { + AddButton( width/2-30, y+=10, 0x98B, 0x98B, "Clear", new GumpCallback( ClearLog ) ); + AddHtml( width/2-23, y+3, 51, "
Clear"); + } + + AddBackgroundZero(0, 0, width, y + 40, 0x1400); + } + + private void Help() + { + NewGump(); + new InfoGump( Owner, 300, 300, HTML.White + " Erreurs signal�es soit par le syst�me maison de ville ou autres membres du personnel! Les admin ont le pouvoir d'effacer cette liste. Tous les membres du staff peuvent signaler une erreur en utilisant la commande .TownHouseErrors.", true ); + } + + private void ClearLog() + { + Errors.ErrorLog.Clear(); + NewGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Error Reporting/ErrorsNotifyGump.cs b/Scripts/Customs/Town Houses/Gumps/Error Reporting/ErrorsNotifyGump.cs new file mode 100644 index 0000000..70c7ed1 --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Error Reporting/ErrorsNotifyGump.cs @@ -0,0 +1,24 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public class ErrorsNotifyGump : GumpPlusLight + { + public ErrorsNotifyGump( Mobile m ) : base( m, 250, 100 ) + { + m.CloseGump( typeof( ErrorsNotifyGump ) ); + } + + protected override void BuildGump() + { + AddButton( 0, 0, 0x1590, 0x1590, "Erreurs", new GumpCallback( Errors ) ); + AddItem(20, 20, 0x22C4); + } + + private void Errors() + { + new ErrorsGump( Owner ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/BackgroundPlus.cs b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/BackgroundPlus.cs new file mode 100644 index 0000000..99fdc3b --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/BackgroundPlus.cs @@ -0,0 +1,23 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.TownHouses +{ + public class BackgroundPlus : GumpBackground + { + private bool c_Override; + + public bool Override{ get{ return c_Override; } set{ c_Override = value; } } + + public BackgroundPlus( int x, int y, int width, int height, int back ) : base( x, y, width, height, back ) + { + c_Override = true; + } + + public BackgroundPlus( int x, int y, int width, int height, int back, bool over ) : base( x, y, width, height, back ) + { + c_Override = over; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/ButtonPlus.cs b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/ButtonPlus.cs new file mode 100644 index 0000000..ca1fbcc --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/ButtonPlus.cs @@ -0,0 +1,37 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.TownHouses +{ + public class ButtonPlus : GumpButton + { + private string c_Name; + private object c_Callback; + private object c_Param; + + public string Name{ get{ return c_Name; } } + + public ButtonPlus( int x, int y, int normalID, int pressedID, int buttonID, string name, GumpCallback back ) : base( x, y, normalID, pressedID, buttonID, GumpButtonType.Reply, 0 ) + { + c_Name = name; + c_Callback = back; + c_Param = ""; + } + + public ButtonPlus( int x, int y, int normalID, int pressedID, int buttonID, string name, GumpStateCallback back, object param ) : base( x, y, normalID, pressedID, buttonID, GumpButtonType.Reply, 0 ) + { + c_Name = name; + c_Callback = back; + c_Param = param; + } + + public void Invoke() + { + if ( c_Callback is GumpCallback ) + ((GumpCallback)c_Callback)(); + else if ( c_Callback is GumpStateCallback ) + ((GumpStateCallback)c_Callback)( c_Param ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/GumpPlusLight.cs b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/GumpPlusLight.cs new file mode 100644 index 0000000..947be35 --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/GumpPlusLight.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Knives.TownHouses +{ + public delegate void GumpStateCallback(object obj); + public delegate void GumpCallback(); + + public abstract class GumpPlusLight : Gump + { + public static void RefreshGump(Mobile m, Type type) + { + if (m.NetState == null) + return; + + foreach (Gump g in m.NetState.Gumps) + if (g is GumpPlusLight && g.GetType() == type) + { + m.CloseGump(type); + ((GumpPlusLight)g).NewGump(); + return; + } + } + + private Mobile c_Owner; + private Hashtable c_Buttons, c_Fields; + + public Mobile Owner{ get{ return c_Owner; } } + + public GumpPlusLight( Mobile m, int x, int y ) : base( x, y ) + { + c_Owner = m; + + c_Buttons = new Hashtable(); + c_Fields = new Hashtable(); + + Timer.DelayCall(TimeSpan.FromSeconds(0), new TimerCallback(NewGump)); + } + + public void Clear() + { + Entries.Clear(); + c_Buttons.Clear(); + c_Fields.Clear(); + } + + public virtual void NewGump() + { + NewGump( true ); + } + + public void NewGump( bool clear ) + { + if ( clear ) + Clear(); + + BuildGump(); + + c_Owner.SendGump( this ); + } + + public void SameGump() + { + c_Owner.SendGump( this ); + } + + protected abstract void BuildGump(); + + private int UniqueButton() + { + int random = 0; + + do + { + random = Utility.Random( 20000 ); + + }while( c_Buttons[random] != null ); + + return random; + } + + private int UniqueTextId() + { + int random = 0; + + do + { + random = Utility.Random(20000); + + } while (c_Buttons[random] != null); + + return random; + } + + public void AddBackgroundZero(int x, int y, int width, int height, int back) + { + AddBackgroundZero(x, y, width, height, back, true); + } + + public void AddBackgroundZero(int x, int y, int width, int height, int back, bool over) + { + BackgroundPlus plus = new BackgroundPlus(x, y, width, height, back, over); + + Entries.Insert(0, plus); + } + + public new void AddBackground(int x, int y, int width, int height, int back) + { + AddBackground(x, y, width, height, back, true); + } + + public void AddBackground(int x, int y, int width, int height, int back, bool over) + { + BackgroundPlus plus = new BackgroundPlus(x, y, width, height, back, over); + + Add(plus); + } + + public void AddButton(int x, int y, int id, GumpCallback callback) + { + AddButton(x, y, id, id, "None", callback); + } + + public void AddButton(int x, int y, int id, GumpStateCallback callback, object arg) + { + AddButton(x, y, id, id, "None", callback, arg); + } + + public void AddButton(int x, int y, int id, string name, GumpCallback callback) + { + AddButton(x, y, id, id, name, callback); + } + + public void AddButton(int x, int y, int id, string name, GumpStateCallback callback, object arg) + { + AddButton(x, y, id, id, name, callback, arg); + } + + public void AddButton(int x, int y, int up, int down, GumpCallback callback) + { + AddButton(x, y, up, down, "None", callback); + } + + public void AddButton(int x, int y, int up, int down, string name, GumpCallback callback) + { + int id = UniqueButton(); + + ButtonPlus button = new ButtonPlus( x, y, up, down, id, name, callback ); + + Add( button ); + + c_Buttons[id] = button; + } + + public void AddButton( int x, int y, int up, int down, GumpStateCallback callback, object arg ) + { + AddButton( x, y, up, down, "None", callback, arg ); + } + + public void AddButton( int x, int y, int up, int down, string name, GumpStateCallback callback, object arg ) + { + int id = UniqueButton(); + + ButtonPlus button = new ButtonPlus( x, y, up, down, id, name, callback, arg ); + + Add( button ); + + c_Buttons[id] = button; + } + + public void AddHtml(int x, int y, int width, string text) + { + AddHtml(x, y, width, 21, HTML.White + text, false, false, true); + } + + public void AddHtml(int x, int y, int width, string text, bool over) + { + AddHtml(x, y, width, 21, HTML.White + text, false, false, over); + } + + public new void AddHtml(int x, int y, int width, int height, string text, bool back, bool scroll) + { + AddHtml(x, y, width, height, HTML.White + text, back, scroll, true); + } + + public void AddHtml(int x, int y, int width, int height, string text, bool back, bool scroll, bool over) + { + HtmlPlus html = new HtmlPlus(x, y, width, height, HTML.White + text, back, scroll, over); + + Add(html); + } + + public void AddTextField(int x, int y, int width, int height, int color, int back, string name, string text) + { + int id = UniqueTextId(); + + AddImageTiled(x, y, width, height, back); + base.AddTextEntry(x, y, width, height, color, id, text); + + c_Fields[id] = name; + c_Fields[name] = text; + } + + public string GetTextField( string name ) + { + if ( c_Fields[name] == null ) + return ""; + + return c_Fields[name].ToString(); + } + + public int GetTextFieldInt(string name) + { + return Utility.ToInt32(GetTextField(name)); + } + + protected virtual void OnClose() + { + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + string name = ""; + + try + { + if (info.ButtonID == -5) + { + NewGump(); + return; + } + + foreach (TextRelay t in info.TextEntries) + c_Fields[c_Fields[t.EntryID].ToString()] = t.Text; + + if (info.ButtonID == 0) + OnClose(); + + if (c_Buttons[info.ButtonID] == null || !(c_Buttons[info.ButtonID] is ButtonPlus)) + return; + + name = ((ButtonPlus)c_Buttons[info.ButtonID]).Name; + + ((ButtonPlus)c_Buttons[info.ButtonID]).Invoke(); + + } + catch (Exception e) + { + Errors.Report("An error occured during a gump response. More information can be found on the console."); + if (name != "") + Console.WriteLine("{0} gump name triggered an error.", name); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/HTML.cs b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/HTML.cs new file mode 100644 index 0000000..bf52ced --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/HTML.cs @@ -0,0 +1,20 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public class HTML + { + public static string White{ get { return ""; } } + public static string Red{ get { return ""; } } + public static string AshRed{ get { return ""; } } + public static string Green{ get { return ""; } } + public static string Blue{ get { return ""; } } + public static string Gray{ get { return ""; } } + public static string DarkGray{ get { return ""; } } + public static string Black{ get { return ""; } } + public static string Yellow{ get { return ""; } } + public static string Purple{ get { return ""; } } + public static string LightPurple{ get { return ""; } } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/HtmlPlus.cs b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/HtmlPlus.cs new file mode 100644 index 0000000..52ba38b --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/HtmlPlus.cs @@ -0,0 +1,23 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.TownHouses +{ + public class HtmlPlus : GumpHtml + { + private bool c_Override; + + public bool Override{ get{ return c_Override; } set{ c_Override = value; } } + + public HtmlPlus( int x, int y, int width, int height, string text, bool back, bool scroll ) : base( x, y, width, height, text, back, scroll ) + { + c_Override = true; + } + + public HtmlPlus( int x, int y, int width, int height, string text, bool back, bool scroll, bool over ) : base( x, y, width, height, text, back, scroll ) + { + c_Override = over; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/InfoGump.cs b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/InfoGump.cs new file mode 100644 index 0000000..9fb2a5a --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/Gumps Plus Light/InfoGump.cs @@ -0,0 +1,30 @@ +using System; +using Server; +using Server.Gumps; + +namespace Knives.TownHouses +{ + public class InfoGump : GumpPlusLight + { + private int c_Width, c_Height; + private string c_Text; + private bool c_Scroll; + + public InfoGump( Mobile m, int width, int height, string text, bool scroll ) : base( m, 100, 100 ) + { + c_Width = width; + c_Height = height; + c_Text= text; + c_Scroll = scroll; + + NewGump(); + } + + protected override void BuildGump() + { + AddBackground( 0, 0, c_Width, c_Height, 0x13BE ); + + AddHtml( 20, 20, c_Width-40, c_Height-40, HTML.White + c_Text, false, c_Scroll ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/ContractConfirmGump.cs b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/ContractConfirmGump.cs new file mode 100644 index 0000000..2b820a8 --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/ContractConfirmGump.cs @@ -0,0 +1,117 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public class ContractConfirmGump : GumpPlusLight + { + private RentalContract c_Contract; + + public ContractConfirmGump( Mobile m, RentalContract rc ) : base( m, 100, 100 ) + { + m.CloseGump( typeof( ContractConfirmGump ) ); + + c_Contract = rc; + } + + protected override void BuildGump() + { + int width = 300; + int y = 0; + + if ( c_Contract.RentalClient == null ) + AddHtml( 0, y+5, width, HTML.Black + "
Louer cette maison?"); + else + AddHtml( 0, y+5, width, HTML.Black + "
Contrat de location"); + + string text = String.Format( " Moi, {0}, accepte de louer ce bien appartenant a {1} pour la somme de {2} tous les {3}. "+ + "Les versements pour ce paiement seront effectu�s directement � partir de ma banque. Dans le cas o�" + + "Je ne peux pas payer cette taxe, la propri�t� revient � {1}. Je peux annuler cet accord � tout moment par" + + "d�molir la propri�t�. {1} peut �galement r�silier ce contrat � tout moment soit en d�molissant son" + + "biens ou en annulant le contrat, auquel cas votre d�p�t de garantie vous sera retourn�.", + c_Contract.RentalClient == null ? "_____" : c_Contract.RentalClient.Name, + c_Contract.RentalMaster.Name, + c_Contract.Free ? 0 : c_Contract.Price, + c_Contract.PriceTypeShort.ToLower() ); + + text += "
Voici quelques infos au sujet de cette propri�t�:
"; + + text += String.Format( "
Lockdowns: {0}
", c_Contract.Locks ); + text += String.Format( "Secures: {0}
", c_Contract.Secures ); + text += String.Format( "Floors: {0}
", (c_Contract.MaxZ-c_Contract.MinZ < 200) ? (c_Contract.MaxZ-c_Contract.MinZ)/20+1 : 1 ); + text += String.Format( "Space: {0} cubic units", c_Contract.CalcVolume() ); + + AddHtml( 40, y+=30, width-60, 200, HTML.Black + text, false, true ); + + y += 200; + + if ( c_Contract.RentalClient == null ) + { + AddHtml( 60, y+=20, 60, HTML.Black + "Preview"); + AddButton( 40, y+3, 0x837, 0x838, "Preview", new GumpCallback( Preview ) ); + + bool locsec = c_Contract.ValidateLocSec(); + + if ( Owner != c_Contract.RentalMaster && locsec ) + { + AddHtml( width-100, y, 60, HTML.Black + "Accepter"); + AddButton( width-60, y+3, 0x232C, 0x232D, "Accepter", new GumpCallback( Accept ) ); + } + else + AddImage( width-60, y-10, 0x232C ); + + if ( !locsec ) + Owner.SendMessage((Owner == c_Contract.RentalMaster ? "Vous n'avez pas de Lockdown ou Secures disponible pour ce contrat." : "Le propri�taire de ce contrat ne peut actuellement pas louer cette propri�t�.")); + } + else + { + if ( Owner == c_Contract.RentalMaster ) + { + AddHtml( 60, y+=20, 100, HTML.Black + "Annuler Contrat"); + AddButton( 40, y+3, 0x837, 0x838, "Annuler Contrat", new GumpCallback( CancelContract ) ); + } + else + AddImage( width-60, y+=20, 0x232C ); + } + + AddBackgroundZero( 0, 0, width, y+23, 0x24A4 ); + } + + protected override void OnClose() + { + c_Contract.ClearPreview(); + } + + private void Preview() + { + c_Contract.ShowAreaPreview(Owner); + NewGump(); + } + + private void CancelContract() + { + if ( Owner == c_Contract.RentalClient ) + c_Contract.House.Delete(); + else + c_Contract.Delete(); + } + + private void Accept() + { + if ( !c_Contract.ValidateLocSec() ) + { + Owner.SendMessage("Le propri�taire de ce contrat ne peut actuellement pas louer cette propri�t�."); + return; + } + + c_Contract.Purchase( Owner ); + + if ( !c_Contract.Owned ) + return; + + c_Contract.Visible = true; + c_Contract.RentalClient = Owner; + c_Contract.RentalClient.AddToBackpack( new RentalContractCopy( c_Contract ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/ContractSetupGump.cs b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/ContractSetupGump.cs new file mode 100644 index 0000000..31f729b --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/ContractSetupGump.cs @@ -0,0 +1,561 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Knives.TownHouses +{ + public class ContractSetupGump : GumpPlusLight + { + public enum Page { Blocks, Floors, Sign, LocSec, Length, Price } + public enum TargetType { SignLoc, MinZ, MaxZ, BlockOne, BlockTwo } + + private RentalContract c_Contract; + private Page c_Page; + + public ContractSetupGump( Mobile m, RentalContract contract ) : base( m, 50, 50 ) + { + m.CloseGump( typeof( ContractSetupGump ) ); + + c_Contract = contract; + } + + protected override void BuildGump() + { + int width = 300; + int y = 0; + + switch( c_Page ) + { + case Page.Blocks: BlocksPage(width, ref y); break; + case Page.Floors: FloorsPage(width, ref y); break; + case Page.Sign: SignPage(width, ref y); break; + case Page.LocSec: LocSecPage(width, ref y); break; + case Page.Length: LengthPage(width, ref y); break; + case Page.Price: PricePage(width, ref y); break; + } + + AddBackgroundZero(0, 0, width, y+40, 0x13BE); + } + + private void BlocksPage(int width, ref int y) + { + if ( c_Contract == null ) + return; + + c_Contract.ShowAreaPreview( Owner ); + + AddHtml( 0, y+=10, width, "
Creer la zone"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + y+=25; + + if ( !General.HasOtherContract( c_Contract.ParentHouse, c_Contract ) ) + { + AddHtml( 60, y, 90, "Maison entiere"); + AddButton(30, y, c_Contract.EntireHouse ? 0xD3 : 0xD2, "Maison entiere", new GumpCallback(EntireHouse)); + } + + if ( !c_Contract.EntireHouse ) + { + AddHtml( 170, y, 70, "Ajouter zone"); + AddButton(240, y, 0x15E1, 0x15E5, "Ajouter zone", new GumpCallback(AddBlock)); + + AddHtml( 170, y+=20, 70, "Clear All"); + AddButton( 240, y, 0x15E1, 0x15E5, "Clear All", new GumpCallback( ClearBlocks ) ); + } + + string helptext = String.Format("Bienvenue sur le menu de configuration contrat de location! Pour commencer, vous devez" + + " d'abord cr�er la zone que vous souhaitez vendre. Comme on le voit ci-dessus, il ya deux fa�ons de le faire:" + + "louer toute la maison, ou de parties de celle-ci. Lorsque vous cr�ez la zone, un aper�u simple va vous montrer exactement" + + "quelle zone vous avez s�lectionn� . Vous pouvez faire toutes sortes de formes bizarres en utilisant de multiples zones!"); + + AddHtml( 10, y+=35, width-20, 170, helptext, false, false ); + + y += 170; + + if ( c_Contract.EntireHouse || c_Contract.Blocks.Count != 0 ) + { + AddHtml( width-60, y+=20, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page + ( c_Contract.EntireHouse ? 4 : 1 ) ); + } + } + + private void FloorsPage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Sols"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 40, y+=25, 80, "Etage de Base"); + AddButton(110, y, 0x15E1, 0x15E5, "Etage de Base", new GumpCallback(MinZSelect)); + + AddHtml( 160, y, 80, "Top Floor"); + AddButton( 230, y, 0x15E1, 0x15E5, "Etage superieur", new GumpCallback( MaxZSelect ) ); + + AddHtml( 100, y+=25, 100, String.Format( "{0} total etages{1}", c_Contract.Floors > 10 ? "1" : "" + c_Contract.Floors, c_Contract.Floors == 1 || c_Contract.Floors > 10 ? "" : "s" )); + + string helptext = String.Format( "Maintenantque vous aurez besoin de cibler les �tagesque vous souhaitez louer" + + "Si vous voulez seulement un �tage, vous pouvez ne pas cible l'�tage sup�rieur Toutes choses entre la base" + + "et le dernier �tage sera inclue dans la location, avec consequences sur le prix" ); + + AddHtml( 10, y+=35, width-20, 120, helptext, false, false ); + + y += 120; + + AddHtml( 30, y+=20, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Contract.MinZ != short.MinValue ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void SignPage(int width, ref int y) + { + if ( c_Contract == null ) + return; + + c_Contract.ShowSignPreview(); + + AddHtml( 0, y+=10, width, "
Their Sign Location"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 100, y+=25, 80, "Def. Emplacement"); + AddButton( 180, y, 0x15E1, 0x15E5, "Sign Loc", new GumpCallback( SignLocSelect ) ); + + string helptext = String.Format( "Avec ce panneau, le locataire aura tous les pouvoirs d'un propri�taire" + +"sur toute sa surface. Si il exercent ce pouvoir de d�molir le logement locatif, il rompu le" + +"contrat et ne recevra pas son d�p�t de garantie. Il peut aussi vous banir de sa maison de location!" ); + + AddHtml( 10, y+=35, width-20, 110, helptext, false, false ); + + y += 110; + + AddHtml( 30, y+=20, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Contract.SignLoc != Point3D.Zero ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void LocSecPage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Lockdowns and Secures"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
Suggest Secures"); + AddButton(width / 2 - 70, y + 3, 0x2716, "Suggest LocSec", new GumpCallback(SuggestLocSec)); + AddButton(width / 2 + 60, y + 3, 0x2716, "Suggest LocSec", new GumpCallback(SuggestLocSec)); + + AddHtml(30, y += 25, width / 2 - 20, "
Secures (Max: " + (General.RemainingSecures(c_Contract.ParentHouse) + c_Contract.Secures) + ")"); + AddTextField( width/2+50, y, 50, 20, 0x480, 0xBBC, "Secures", c_Contract.Secures.ToString() ); + AddButton(width / 2 + 25, y + 3, 0x2716, "Secures", new GumpCallback(Secures)); + + AddHtml(30, y += 20, width / 2 - 20, "
Lockdowns (Max: " + (General.RemainingLocks(c_Contract.ParentHouse) + c_Contract.Locks) + ")"); + AddTextField( width/2+50, y, 50, 20, 0x480, 0xBBC, "Lockdowns", c_Contract.Locks.ToString() ); + AddButton(width / 2 + 25, y + 3, 0x2716, "Lockdowns", new GumpCallback(Lockdowns)); + + string helptext = String.Format( "Sans donner d'espace, ce ne serait pas vraiment une maison, ici, vous assignez les lockdowns" + +"et secures de votre propre maison. Utilisez le bouton sugg�rer pour une id�e de combien vous devriez alouer. Soyez tr�s prudent lorsque vous" + +"louez votre bien: si vous utilisez trop de stockage vous commencerez � utiliser du stockage que vous avez r�serv� a vos clients" + +"Vous recevrez un avertissement de 48 heures lorsque cela se produit, apr�s quoi le contrat dispara�tra!" ); + + AddHtml( 10, y+=35, width-20, 180, helptext, false, false ); + + y += 180; + + AddHtml( 30, y+=20, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Contract.Locks != 0 && c_Contract.Secures != 0 ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void LengthPage(int width, ref int y) + { + AddHtml(0, y += 10, width, "
P�riodes"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 120, y+=25, 50, c_Contract.PriceType); + AddButton( 170, y+8, 0x985, "LengthUp", new GumpCallback( LengthUp ) ); + AddButton( 170, y-2, 0x983, "LengthDown", new GumpCallback( LengthDown ) ); + + string helptext = String.Format("Tous les {0}, la banque vous transf�re automatiquement le co�t de location" + +"En utilisant les fl�ches, vous pouvez definir d'autres p�riodes, mieux adapt�es � vos besoins", c_Contract.PriceTypeShort.ToLower()); + + AddHtml( 10, y+=35, width-20, 100, helptext, false, false ); + + y += 100; + + AddHtml( 30, y+=20, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page - ( c_Contract.EntireHouse ? 4 : 1 ) ); + + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + + private void PricePage(int width, ref int y) + { + AddHtml(0, y += 10, width, "
Loyer par p�riodes"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
Gratuit"); + AddButton(width / 2 - 80, y, c_Contract.Free ? 0xD3 : 0xD2, "Gratuit", new GumpCallback(Free)); + AddButton(width / 2 + 60, y, c_Contract.Free ? 0xD3 : 0xD2, "Gratuit", new GumpCallback(Free)); + + if ( !c_Contract.Free ) + { + AddHtml( 0, y+=25, width/2-20, "
Par " + c_Contract.PriceTypeShort); + AddTextField( width/2+20, y, 70, 20, 0x480, 0xBBC, "Prix", c_Contract.Price.ToString() ); + AddButton(width / 2 - 5, y + 3, 0x2716, "Prix", new GumpCallback(Price)); + + AddHtml(0, y += 20, width, "
Sugg�rer"); + AddButton(width / 2 - 70, y + 3, 0x2716, "Sugg�rer", new GumpCallback(SuggestPrice)); + AddButton(width / 2 + 60, y + 3, 0x2716, "Sugg�rer", new GumpCallback(SuggestPrice)); + } + + string helptext = String.Format(" Maintenant, vous pouvez finaliser le contrat en incluant votre prix par {0}" + +"Une fois que vous avez finalis�, la seule fa�on vous pouvez le modifier est de l'annuler et de commencer un nouveau contrat! En" + +"utilisant le bouton sugg�rer, un prix sera automatiquement choisi sur les bases suivantes:
", c_Contract.PriceTypeShort); + + helptext += String.Format( "
Volume: {0}
", c_Contract.CalcVolume() ); + helptext += String.Format( "Cout par unite: {0} Or
", General.SuggestionFactor ); + helptext += "
Avec l'option ci-dessous, vous pouvez offrir cet espace entre trop."; + + AddHtml( 10, y+=35, width-20, 150, helptext, false, true ); + + y += 150; + + AddHtml( 30, y+=20, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Contract.Price != 0 ) + { + AddHtml( width-70, y, 60, "Finaliser"); + AddButton(width - 30, y, 0x15E1, 0x15E5, "Finaliser", new GumpCallback(FinalizeSetup)); + } + } + + protected override void OnClose() + { + c_Contract.ClearPreview(); + } + + private void SuggestPrice() + { + if ( c_Contract == null ) + return; + + c_Contract.Price = c_Contract.CalcVolume()*General.SuggestionFactor; + + if ( c_Contract.RentByTime == TimeSpan.FromDays( 1 ) ) + c_Contract.Price /= 60; + if ( c_Contract.RentByTime == TimeSpan.FromDays( 7 ) ) + c_Contract.Price = (int)((double)c_Contract.Price/8.57); + if ( c_Contract.RentByTime == TimeSpan.FromDays( 30 ) ) + c_Contract.Price /= 2; + + NewGump(); + } + + private void SuggestLocSec() + { + int price = c_Contract.CalcVolume()*General.SuggestionFactor; + c_Contract.Secures = price/75; + c_Contract.Locks = c_Contract.Secures/2; + + c_Contract.FixLocSec(); + + NewGump(); + } + + private void Price() + { + c_Contract.Price = GetTextFieldInt("Prix"); + Owner.SendMessage("Prix choisi!"); + NewGump(); + } + + private void Secures() + { + c_Contract.Secures = GetTextFieldInt("Secures"); + Owner.SendMessage("Secures choisi!"); + NewGump(); + } + + private void Lockdowns() + { + c_Contract.Locks = GetTextFieldInt("Lockdowns"); + Owner.SendMessage("Lockdowns choisi!"); + NewGump(); + } + + private void ChangePage(object obj) + { + if ( c_Contract == null || !(obj is int) ) + return; + + c_Contract.ClearPreview(); + + c_Page = (Page)(int)obj; + + NewGump(); + } + + private void EntireHouse() + { + if ( c_Contract == null || c_Contract.ParentHouse == null ) + return; + + c_Contract.EntireHouse = !c_Contract.EntireHouse; + + c_Contract.ClearPreview(); + + if ( c_Contract.EntireHouse ) + { + ArrayList list = new ArrayList(); + + bool once = false; + foreach (Rectangle3D rect in RUOVersion.RegionArea(c_Contract.ParentHouse.Region)) + { + list.Add(new Rectangle2D(new Point2D(rect.Start.X, rect.Start.Y), new Point2D(rect.End.X, rect.End.Y))); + + if (once) + continue; + + if (rect.Start.Z >= rect.End.Z) + { + c_Contract.MinZ = rect.End.Z; + c_Contract.MaxZ = rect.Start.Z; + } + else + { + c_Contract.MinZ = rect.Start.Z; + c_Contract.MaxZ = rect.End.Z; + } + + once = true; + } + + c_Contract.Blocks = list; + } + else + { + c_Contract.Blocks.Clear(); + c_Contract.MinZ = short.MinValue; + c_Contract.MaxZ = short.MinValue; + } + + NewGump(); + } + + private void SignLocSelect() + { + Owner.Target = new InternalTarget( this, c_Contract, TargetType.SignLoc ); + } + + private void MinZSelect() + { + Owner.SendMessage("Cibler l'�tage de base de votre r�gion de location."); + Owner.Target = new InternalTarget( this, c_Contract, TargetType.MinZ ); + } + + + private void MaxZSelect() + { + Owner.SendMessage("Cibler l'�tage sup�rieur de votre r�gion de location."); + Owner.Target = new InternalTarget( this, c_Contract, TargetType.MaxZ ); + } + + private void LengthUp() + { + if ( c_Contract == null ) + return; + + c_Contract.NextPriceType(); + + if ( c_Contract.RentByTime == TimeSpan.FromDays( 0 ) ) + c_Contract.RentByTime = TimeSpan.FromDays( 1 ); + + NewGump(); + } + + private void LengthDown() + { + if ( c_Contract == null ) + return; + + c_Contract.PrevPriceType(); + + if ( c_Contract.RentByTime == TimeSpan.FromDays( 0 ) ) + c_Contract.RentByTime = TimeSpan.FromDays( 30 ); + + NewGump(); + } + + private void Free() + { + c_Contract.Free = !c_Contract.Free; + + NewGump(); + } + + private void AddBlock() + { + Owner.SendMessage("Cibler le coin nord-ouest."); + Owner.Target = new InternalTarget( this, c_Contract, TargetType.BlockOne ); + } + + private void ClearBlocks() + { + if ( c_Contract == null ) + return; + + c_Contract.Blocks.Clear(); + + c_Contract.ClearPreview(); + + NewGump(); + } + + private void FinalizeSetup() + { + if ( c_Contract == null ) + return; + + if ( c_Contract.Price == 0 ) + { + Owner.SendMessage("Vous ne pouvez pas louer la zone pour 0 or!"); + NewGump(); + return; + } + + c_Contract.Completed = true; + c_Contract.BanLoc = c_Contract.ParentHouse.Region.GoLocation; + + if ( c_Contract.EntireHouse ) + { + Point3D point = c_Contract.ParentHouse.Sign.Location; + c_Contract.SignLoc = new Point3D( point.X, point.Y, point.Z-5 ); + c_Contract.Secures = Core.AOS ? c_Contract.ParentHouse.GetAosMaxSecures() : c_Contract.ParentHouse.MaxSecures; + c_Contract.Locks = Core.AOS ? c_Contract.ParentHouse.GetAosMaxLockdowns() : c_Contract.ParentHouse.MaxLockDowns; + } + + Owner.SendMessage("Vous avez finalis� ce contrat de location. Maintenant trouvez quelqu'un pour le signer!"); + } + + private class InternalTarget : Target + { + private ContractSetupGump c_Gump; + private RentalContract c_Contract; + private TargetType c_Type; + private Point3D c_BoundOne; + + public InternalTarget( ContractSetupGump gump, RentalContract contract, TargetType type ) : this( gump, contract, type, Point3D.Zero ){} + + public InternalTarget( ContractSetupGump gump, RentalContract contract, TargetType type, Point3D point ) : base( 20, true, TargetFlags.None ) + { + c_Gump = gump; + c_Contract = contract; + c_Type = type; + c_BoundOne = point; + } + + protected override void OnTarget( Mobile m, object o ) + { + IPoint3D point = (IPoint3D)o; + + if ( c_Contract == null || c_Contract.ParentHouse == null ) + return; + + if ( !c_Contract.ParentHouse.Region.Contains( new Point3D( point.X, point.Y, point.Z ) ) ) + { + m.SendMessage("Vous devez cibler dans la maison"); + m.Target = new InternalTarget( c_Gump, c_Contract, c_Type, c_BoundOne ); + return; + } + + switch( c_Type ) + { + case TargetType.SignLoc: + c_Contract.SignLoc = new Point3D( point.X, point.Y, point.Z ); + c_Contract.ShowSignPreview(); + c_Gump.NewGump(); + break; + + case TargetType.MinZ: + if (!c_Contract.ParentHouse.Region.Contains(new Point3D(point.X, point.Y, point.Z))) + m.SendMessage( "Ce n'est pas dans votre maison" ); + else if ( c_Contract.HasContractedArea( point.Z ) ) + m.SendMessage("Cette zone est d�j� prise par un autre contrat de location"); + else + { + c_Contract.MinZ = point.Z; + + if ( c_Contract.MaxZ < c_Contract.MinZ+19 ) + c_Contract.MaxZ = point.Z+19; + } + + c_Contract.ShowFloorsPreview(m); + c_Gump.NewGump(); + break; + + case TargetType.MaxZ: + if ( !c_Contract.ParentHouse.Region.Contains(new Point3D(point.X, point.Y, point.Z)) ) + m.SendMessage("Ce n'est pas dans votre maison"); + else if ( c_Contract.HasContractedArea( point.Z ) ) + m.SendMessage( "Cette zone est d�j� prise par un autre contrat de location." ); + else + { + c_Contract.MaxZ = point.Z+19; + + if ( c_Contract.MinZ > c_Contract.MaxZ ) + c_Contract.MinZ = point.Z; + } + + c_Contract.ShowFloorsPreview(m); + c_Gump.NewGump(); + break; + + case TargetType.BlockOne: + m.SendMessage("Maintenant, ciblez le coin sud-est"); + m.Target = new InternalTarget( c_Gump, c_Contract, TargetType.BlockTwo, new Point3D( point.X, point.Y, point.Z ) ); + break; + + case TargetType.BlockTwo: + Rectangle2D rect = TownHouseSetupGump.FixRect( new Rectangle2D( c_BoundOne, new Point3D( point.X+1, point.Y+1, point.Z ) ) ); + + if ( c_Contract.HasContractedArea( rect, point.Z ) ) + m.SendMessage("Cette zone est d�j� prise par un autre contrat de location"); + else + { + c_Contract.Blocks.Add( rect ); + c_Contract.ShowAreaPreview( m ); + } + + c_Gump.NewGump(); + break; + } + } + + protected override void OnTargetCancel( Mobile m, TargetCancelType cancelType ) + { + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHouseConfirmGump.cs b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHouseConfirmGump.cs new file mode 100644 index 0000000..e96f8fa --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHouseConfirmGump.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public class TownHouseConfirmGump : GumpPlusLight + { + private TownHouseSign c_Sign; + private bool c_Items; + + public TownHouseConfirmGump( Mobile m, TownHouseSign sign ) : base( m, 100, 100 ) + { + c_Sign = sign; + } + + protected override void BuildGump() + { + int width = 200; + int y = 0; + + AddHtml( 0, y+=10, width, String.Format( "
{0} cette maison?", c_Sign.RentByTime == TimeSpan.Zero ? "Acheter" : "Louer" )); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + if ( c_Sign.RentByTime == TimeSpan.Zero ) + AddHtml( 0, y+=25, width, String.Format( "
{0}: {1}", "Prix", c_Sign.Free ? "Gratuit" : "" + c_Sign.Price )); + else if ( c_Sign.RecurRent ) + AddHtml(0, y += 25, width, String.Format("
{0}: {1}", "R�current " + c_Sign.PriceType, c_Sign.Price)); + else + AddHtml( 0, y+=25, width, String.Format( "
{0}: {1}", "Un " + c_Sign.PriceTypeShort, c_Sign.Price )); + + if ( c_Sign.KeepItems ) + { + AddHtml( 0, y+=20, width, "
Cout des objets: " + c_Sign.ItemsPrice); + AddButton( 20, y, c_Items ? 0xD3 : 0xD2, "Objets", new GumpCallback( Items ) ); + } + + AddHtml(0, y += 20, width, "
Lockdowns: " + c_Sign.Locks); + AddHtml( 0, y+=20, width, "
Secures: " + c_Sign.Secures); + + AddButton( 10, y+=25, 0xFB1, 0xFB3, "Cancel", new GumpCallback( Cancel ) ); + AddButton( width-40, y, 0xFB7, 0xFB9, "Confirm", new GumpCallback( Confirm ) ); + + AddBackgroundZero(0, 0, width, y+40, 0x13BE); + } + + private void Items() + { + c_Items = !c_Items; + + NewGump(); + } + + private void Cancel() + { + } + + private void Confirm() + { + c_Sign.Purchase( Owner, c_Items ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHouseSetupGump.cs b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHouseSetupGump.cs new file mode 100644 index 0000000..51419f8 --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHouseSetupGump.cs @@ -0,0 +1,1050 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; + +namespace Knives.TownHouses +{ + public class TownHouseSetupGump : GumpPlusLight + { + public static Rectangle2D FixRect( Rectangle2D rect ) + { + Point3D pointOne = Point3D.Zero; + Point3D pointTwo = Point3D.Zero; + + if ( rect.Start.X < rect.End.X ) + { + pointOne.X = rect.Start.X; + pointTwo.X = rect.End.X; + } + else + { + pointOne.X = rect.End.X; + pointTwo.X = rect.Start.X; + } + + if ( rect.Start.Y < rect.End.Y ) + { + pointOne.Y = rect.Start.Y; + pointTwo.Y = rect.End.Y; + } + else + { + pointOne.Y = rect.End.Y; + pointTwo.Y = rect.Start.Y; + } + + return new Rectangle2D( pointOne, pointTwo ); + } + + public enum Page { Welcome, Blocks, Floors, Sign, Ban, LocSec, Items, Length, Price, Skills, Other, Other2 } + public enum TargetType { BanLoc, SignLoc, MinZ, MaxZ, BlockOne, BlockTwo } + + private TownHouseSign c_Sign; + private Page c_Page; + private bool c_Quick; + + public TownHouseSetupGump( Mobile m, TownHouseSign sign ) : base( m, 50, 50 ) + { + m.CloseGump( typeof( TownHouseSetupGump ) ); + + c_Sign = sign; + } + + protected override void BuildGump() + { + if ( c_Sign == null ) + return; + + int width = 300; + int y = 0; + + if (c_Quick) + { + QuickPage(width, ref y); + } + else + { + switch (c_Page) + { + case Page.Welcome: WelcomePage(width, ref y); break; + case Page.Blocks: BlocksPage(width, ref y); break; + case Page.Floors: FloorsPage(width, ref y); break; + case Page.Sign: SignPage(width, ref y); break; + case Page.Ban: BanPage(width, ref y); break; + case Page.LocSec: LocSecPage(width, ref y); break; + case Page.Items: ItemsPage(width, ref y); break; + case Page.Length: LengthPage(width, ref y); break; + case Page.Price: PricePage(width, ref y); break; + case Page.Skills: SkillsPage(width, ref y); break; + case Page.Other: OtherPage(width, ref y); break; + case Page.Other2: OtherPage2(width, ref y); break; + } + + BuildTabs(width, ref y); + } + + AddBackgroundZero(0, 0, width, y+=30, 0x13BE); + + if (c_Sign.PriceReady && !c_Sign.Owned) + { + AddBackground(width / 2 - 50, y, 100, 30, 0x13BE); + AddHtml(width / 2 - 50 + 25, y + 5, 100, "Revendiquer Maison"); + AddButton(width / 2 - 50 + 5, y + 10, 0x837, 0x838, "Revendiquer", new GumpCallback(Claim)); + } + } + + private void BuildTabs(int width, ref int y) + { + int x = 20; + + y += 30; + + AddButton(x-5, y - 3, 0x768, "Rapide", new GumpCallback(Quick)); + AddLabel(x, y - 3, c_Quick ? 0x34 : 0x47E, "Q"); + + AddButton(x+=20, y, c_Page == Page.Welcome ? 0x939 : 0x93A, "Accueil", new GumpStateCallback(ChangePage), 0); + AddButton(x += 20, y, c_Page == Page.Blocks ? 0x939 : 0x93A, "Page Blocks", new GumpStateCallback(ChangePage), 1); + + if ( c_Sign.BlocksReady ) + AddButton( x+=20, y, c_Page == Page.Floors ? 0x939 : 0x93A, "Page Etages", new GumpStateCallback( ChangePage ), 2 ); + + if ( c_Sign.FloorsReady ) + AddButton( x+=20, y, c_Page == Page.Sign ? 0x939 : 0x93A, "Page Panneau", new GumpStateCallback( ChangePage ), 3 ); + + if ( c_Sign.SignReady ) + AddButton(x += 20, y, c_Page == Page.Ban ? 0x939 : 0x93A, "Page Bans", new GumpStateCallback(ChangePage), 4); + + if ( c_Sign.BanReady ) + AddButton(x += 20, y, c_Page == Page.LocSec ? 0x939 : 0x93A, "Page LocSec", new GumpStateCallback(ChangePage), 5); + + if ( c_Sign.LocSecReady ) + { + AddButton(x += 20, y, c_Page == Page.Items ? 0x939 : 0x93A, "Page Objets", new GumpStateCallback(ChangePage), 6); + + if ( !c_Sign.Owned ) + AddButton(x += 20, y, c_Page == Page.Length ? 0x939 : 0x93A, "Page Duree", new GumpStateCallback(ChangePage), 7); + else + x+=20; + + AddButton( x+=20, y, c_Page == Page.Price ? 0x939 : 0x93A, "Page Prix", new GumpStateCallback( ChangePage ), 8 ); + } + + if ( c_Sign.PriceReady ) + { + AddButton(x += 20, y, c_Page == Page.Skills ? 0x939 : 0x93A, "Page Skills", new GumpStateCallback(ChangePage), 9); + AddButton(x += 20, y, c_Page == Page.Other ? 0x939 : 0x93A, "Autre Page", new GumpStateCallback(ChangePage), 10); + AddButton(x += 20, y, c_Page == Page.Other2 ? 0x939 : 0x93A, "Autre Page 2", new GumpStateCallback(ChangePage), 11); + } + } + + private void QuickPage(int width, ref int y) + { + c_Sign.ClearPreview(); + + AddHtml(0, y += 10, width, "
Installation rapide"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddButton(5, 5, 0x768, "Rapide", new GumpCallback(Quick)); + AddLabel(10, 5, c_Quick ? 0x34 : 0x47E, "Q"); + + AddHtml(0, y += 25, width / 2 - 55, "
Nom"); + AddTextField(width / 2 - 15, y, 100, 20, 0x480, 0xBBC, "Nom", c_Sign.Name); + AddButton(width / 2 - 40, y + 3, 0x2716, "Name", new GumpCallback(Name)); + + AddHtml(0, y += 25, width/2, "
Ajouter zone"); + AddButton(width / 4 - 50, y + 3, 0x2716, "Ajouter zone", new GumpCallback(AddBlock)); + AddButton(width / 4 + 40, y + 3, 0x2716, "Ajouter zone", new GumpCallback(AddBlock)); + + AddHtml(width/2, y, width/2, "
Clear All"); + AddButton(width / 4 * 3 - 50, y + 3, 0x2716, "ClearAll", new GumpCallback(ClearAll)); + AddButton(width / 4 * 3 + 40, y + 3, 0x2716, "ClearAll", new GumpCallback(ClearAll)); + + AddHtml(0, y += 25, width, "
Etage Base: " + c_Sign.MinZ.ToString()); + AddButton(width / 2 - 80, y + 3, 0x2716, "Etage Base", new GumpCallback(MinZSelect)); + AddButton(width / 2 + 70, y + 3, 0x2716, "Etage Base", new GumpCallback(MinZSelect)); + + AddHtml(0, y += 17, width, "
Etage superieur: " + c_Sign.MaxZ.ToString()); + AddButton(width / 2 - 80, y + 3, 0x2716, "Etage superieur", new GumpCallback(MaxZSelect)); + AddButton(width / 2 + 70, y + 3, 0x2716, "Etage superieur", new GumpCallback(MaxZSelect)); + + AddHtml(0, y += 25, width / 2, "
Panneau Loc"); + AddButton(width / 4 - 50, y + 3, 0x2716, "Panneau Loc", new GumpCallback(SignLocSelect)); + AddButton(width / 4 + 40, y + 3, 0x2716, "Panneau Loc", new GumpCallback(SignLocSelect)); + + AddHtml(width/2, y, width/2, "
Ban Loc"); + AddButton(width / 4 * 3 - 50, y + 3, 0x2716, "Ban Loc", new GumpCallback(BanLocSelect)); + AddButton(width / 4 * 3 + 40, y + 3, 0x2716, "Ban Loc", new GumpCallback(BanLocSelect)); + + AddHtml(0, y += 25, width, "
Suggest Secures"); + AddButton(width / 2 - 70, y + 3, 0x2716, "Suggest LocSec", new GumpCallback(SuggestLocSec)); + AddButton(width / 2 + 60, y + 3, 0x2716, "Suggest LocSec", new GumpCallback(SuggestLocSec)); + + AddHtml(0, y += 20, width / 2 - 20, "
Secures"); + AddTextField(width / 2 + 20, y, 50, 20, 0x480, 0xBBC, "Secures", c_Sign.Secures.ToString()); + AddButton(width / 2 - 5, y + 3, 0x2716, "Secures", new GumpCallback(Secures)); + + AddHtml(0, y += 22, width / 2 - 20, "
Lockdowns"); + AddTextField(width / 2 + 20, y, 50, 20, 0x480, 0xBBC, "Lockdowns", c_Sign.Locks.ToString()); + AddButton(width / 2 - 5, y + 3, 0x2716, "Lockdowns", new GumpCallback(Lockdowns)); + + AddHtml(0, y += 25, width, "
Donner les objets a l'acheteur de la maison"); + AddButton(width / 2 - 110, y, c_Sign.KeepItems ? 0xD3 : 0xD2, "Garder objets", new GumpCallback(KeepItems)); + AddButton(width / 2 + 90, y, c_Sign.KeepItems ? 0xD3 : 0xD2, "Garder objets", new GumpCallback(KeepItems)); + + if (c_Sign.KeepItems) + { + AddHtml(0, y += 25, width / 2 - 25, "
Au Prix"); + AddTextField(width / 2 + 15, y, 70, 20, 0x480, 0xBBC, "PrixObjet", c_Sign.ItemsPrice.ToString()); + AddButton(width / 2 - 10, y + 5, 0x2716, "Prix Objet", new GumpCallback(ItemsPrice)); + } + else + { + AddHtml(0, y += 25, width, "
Ne pas supprimer les objets"); + AddButton(width / 2 - 110, y, c_Sign.LeaveItems ? 0xD3 : 0xD2, "LaisserObjets", new GumpCallback(LeaveItems)); + AddButton(width / 2 + 90, y, c_Sign.LeaveItems ? 0xD3 : 0xD2, "LaisserObjets", new GumpCallback(LeaveItems)); + } + + if (!c_Sign.Owned) + { + AddHtml(120, y += 25, 50, c_Sign.PriceType); + AddButton(170, y + 8, 0x985, 0x985, "DureeUp", new GumpCallback(PriceUp)); + AddButton(170, y - 2, 0x983, 0x983, "DureeDown", new GumpCallback(PriceDown)); + } + + if (c_Sign.RentByTime != TimeSpan.Zero) + { + AddHtml(0, y += 25, width, "
Location Recurente"); + AddButton(width / 2 - 80, y, c_Sign.RecurRent ? 0xD3 : 0xD2, "RecurLoc", new GumpCallback(RecurRent)); + AddButton(width / 2 + 60, y, c_Sign.RecurRent ? 0xD3 : 0xD2, "RecurLoc", new GumpCallback(RecurRent)); + + if (c_Sign.RecurRent) + { + AddHtml(0, y += 20, width, "
Location-vente"); + AddButton(width / 2 - 80, y, c_Sign.RentToOwn ? 0xD3 : 0xD2, "Location-vente", new GumpCallback(RentToOwn)); + AddButton(width / 2 + 60, y, c_Sign.RentToOwn ? 0xD3 : 0xD2, "Location-vente", new GumpCallback(RentToOwn)); + } + } + + AddHtml(0, y += 25, width, "
Gratuit"); + AddButton(width / 2 - 80, y, c_Sign.Free ? 0xD3 : 0xD2, "Gratuit", new GumpCallback(Free)); + AddButton(width / 2 + 60, y, c_Sign.Free ? 0xD3 : 0xD2, "Gratuit", new GumpCallback(Free)); + + if (!c_Sign.Free) + { + AddHtml(0, y += 25, width / 2 - 20, "
" + c_Sign.PriceType + " Prix"); + AddTextField(width / 2 + 20, y, 70, 20, 0x480, 0xBBC, "Prix", c_Sign.Price.ToString()); + AddButton(width / 2 - 5, y + 5, 0x2716, "Prix", new GumpCallback(Price)); + + AddHtml(0, y += 25, width, "
Suggerer Prix"); + AddButton(width / 2 - 70, y + 3, 0x2716, "Suggerer", new GumpCallback(SuggestPrice)); + AddButton(width / 2 + 50, y + 3, 0x2716, "Suggerer", new GumpCallback(SuggestPrice)); + } + } + + private void WelcomePage(int width, ref int y) + { + AddHtml(0, y += 10, width, "
Bienvenue !"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + string helptext = ""; + + AddHtml(0, y += 25, width / 2 - 55, "
Nom"); + AddTextField(width / 2 - 15, y, 100, 20, 0x480, 0xBBC, "Nom", c_Sign.Name); + AddButton(width / 2 - 40, y + 3, 0x2716, "Nom", new GumpCallback(Name)); + + if (c_Sign != null && c_Sign.Map != Map.Internal && c_Sign.RootParent == null) + { + AddHtml(0, y += 25, width, "
AllerA"); + AddButton(width / 2 - 50, y + 3, 0x2716, "AllerA", new GumpCallback(Goto)); + AddButton(width / 2 + 40, y + 3, 0x2716, "AllerA", new GumpCallback(Goto)); + } + + if (c_Sign.Owned) + { + helptext = String.Format("Cette maison appartient � {0}, donc soyez conscient que changer quoi que ce soit"+ + "gr�ce � ce menu va changer la maison elle-m�me! Vous pouvez ajouter plus d'espace, modifier la propri�t�" + + "les r�gles, presque tout! Vous ne pouvez pas, toutefois, changer le statut de location de la maison, beaucoup trop de" + + "possibilites de bugs. Si vous changez les restrictions et le propri�taire n'y correspond plus," + + "ils recevront l'avertissement de demolition normal de 24 heures ", c_Sign.House.Owner.Name); + + AddHtml(10, y += 25, width - 20, 180, helptext, false, false); + + y += 180; + } + else + { + helptext = String.Format("Bienvenue dans le menu de configuration TownHouse! Ce menu vous guidera � travers" + + "chaque �tape du processus d'installation. Vous pouvez configurer n'importe quelle zone d'une maison, ainsi que tout les d�tails de" + + "lockdowns, le prix, et si que vous souhaitez vendre ou louer la maison. Commen�ons ici par le nom de" + + "cette nouvelle Maison de Ville!"); + + AddHtml(10, y += 25, width - 20, 130, helptext, false, false); + + y += 130; + } + + AddHtml(width - 60, y+=15, 60, "Next"); + AddButton(width - 30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback(ChangePage), (int)c_Page + 1); + } + + private void BlocksPage(int width, ref int y) + { + if ( c_Sign == null ) + return; + + c_Sign.ShowAreaPreview(Owner); + + AddHtml( 0, y+=10, width, "
Creer la zone"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 0, y+=25, width, "
Ajouter zone"); + AddButton(width / 2 - 50, y + 3, 0x2716, "Ajouterzone", new GumpCallback(AddBlock)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Ajouterzone", new GumpCallback(AddBlock)); + + AddHtml( 0, y+=20, width, "
Clear All"); + AddButton(width / 2 - 50, y + 3, 0x2716, "ClearAll", new GumpCallback(ClearAll)); + AddButton(width / 2 + 40, y + 3, 0x2716, "ClearAll", new GumpCallback(ClearAll)); + + string helptext = String.Format(" Le programme d'installation commence par d�finir la zone que vous souhaitez vendre ou louer " + +"Vous pouvez ajouter autant de blocs que vous le souhaitez, � chaque fois un aper�u montrera ce que" + +" vous avez s�lectionn�. Si vous avez envie de recommencer, il suffit de les faire dispara�tre! Vous devez avoir" + +"au moins un bloc d�fini avant de passer � l'�tape suivante."); + + AddHtml( 10, y+=35, width-20, 140, helptext, false, false ); + + y += 140; + + AddHtml(30, y += 15, 80, "Prec."); + AddButton(10, y, 0x15E3, 0x15E7, "Prec.", new GumpStateCallback(ChangePage), (int)c_Page - 1); + + if (c_Sign.BlocksReady) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void FloorsPage(int width, ref int y) + { + c_Sign.ShowFloorsPreview(Owner); + + AddHtml(0, y += 10, width, "
Etages"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
Etage de base: " + c_Sign.MinZ.ToString()); + AddButton(width / 2 - 80, y + 3, 0x2716, "Etagedebase", new GumpCallback(MinZSelect)); + AddButton(width / 2 + 70, y + 3, 0x2716, "Etagedebase", new GumpCallback(MinZSelect)); + + AddHtml(0, y += 20, width, "
Etage superieur: " + c_Sign.MaxZ.ToString()); + AddButton(width / 2 - 80, y + 3, 0x2716, "EtageSuperieur", new GumpCallback(MaxZSelect)); + AddButton(width / 2 + 70, y + 3, 0x2716, "EtageSuperieur", new GumpCallback(MaxZSelect)); + + string helptext = String.Format( "Maintenant, il vous faut cibler les �tages que vous souhaitez vendre "+ + "Si vous voulez seulement un �tage, vous pouvez ne pas cibler l'�tage sup�rieur. Toutes choses entre la base" + + "et le dernier �tage sera inclue dans la maison, avec repercussions sur le prix."); + + AddHtml( 10, y+=35, width-20, 110, helptext, false, false); + + y += 110; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.FloorsReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void SignPage(int width, ref int y) + { + if ( c_Sign == null ) + return; + + c_Sign.ShowSignPreview(); + + AddHtml( 0, y+=10, width, "
Emplacement Panneau"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 0, y+=25, width, "
Definir Emplacement"); + AddButton(width / 2 - 60, y + 3, 0x2716, "EmplacementPanneau", new GumpCallback(SignLocSelect)); + AddButton(width / 2 + 50, y + 3, 0x2716, "EmplacementPanneau", new GumpCallback(SignLocSelect)); + + string helptext = String.Format( "Avec ce panneau, le propri�taire aura les memes droits de possession "+ +"que sur une autre maison. Si il utilisent le panneau de d�molition de la maison, il retournera automatiquement" + +"a la vente ou � location. Le panneau joueurs � utiliser pour acheter la maison appara�t dans le m�me" + +"endroit, l�g�rement en dessous de la plaque de maison normale" ); + + AddHtml( 10, y+=35, width-20, 130, helptext, false, false); + + y += 130; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.SignReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void BanPage(int width, ref int y) + { + if ( c_Sign == null ) + return; + + c_Sign.ShowBanPreview(); + + AddHtml( 0, y+=10, width, "
Emplacement de Ban"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 0, y+=25, width, "
Definir emplacement"); + AddButton(width / 2 - 60, y + 3, 0x2716, "EmplacementdeBan", new GumpCallback(BanLocSelect)); + AddButton(width / 2 + 50, y + 3, 0x2716, "EmplacementdeBan", new GumpCallback(BanLocSelect)); + + string helptext = String.Format( "L'emplacement de Ban d�termine o� un joueur est envoy� quand il est �ject� ou " + +"banni d'une maison. Si vous n'avez jamais defini cela, il ira dans le coin sud-ouest a l'ext�rieur" + + "de la maison"); + + AddHtml( 10, y+=35, width-20, 100, helptext, false, false ); + + y += 100; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.BanReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void LocSecPage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Lockdowns et Secures"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y+=25, width, "
Suggerer"); + AddButton(width / 2 - 50, y + 3, 0x2716, "SuggererLocSec", new GumpCallback(SuggestLocSec)); + AddButton(width / 2 + 40, y + 3, 0x2716, "SuggererLocSec", new GumpCallback(SuggestLocSec)); + + AddHtml(0, y += 25, width / 2 - 20, "
Secures"); + AddTextField( width/2+20, y, 50, 20, 0x480, 0xBBC, "Secures", c_Sign.Secures.ToString() ); + AddButton(width / 2 - 5, y + 3, 0x2716, "Secures", new GumpCallback(Secures)); + + AddHtml( 0, y+=25, width/2-20, "
Lockdowns"); + AddTextField( width/2+20, y, 50, 20, 0x480, 0xBBC, "Lockdowns", c_Sign.Locks.ToString() ); + AddButton(width / 2 - 5, y + 3, 0x2716, "Lockdowns", new GumpCallback(Lockdowns)); + + string helptext = String.Format("Avec cette �tape vous d�finissez la quantit� de stockage pour la maison, ou emplacement " + +"le syst�me peut le faire pour que vous en utilisant le bouton Sugg�rer. En g�n�ral, les joueurs obtiennent la moiti� du nombre de lockdowns" + +"en secure."); + + AddHtml( 10, y+=35, width-20, 90, helptext, false, false ); + + y += 90; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.LocSecReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void ItemsPage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Objet de Decoration"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 0, y+=25, width, "
Donner a l'acheteur les objets dans la maison"); + AddButton(width / 2 - 110, y, c_Sign.KeepItems ? 0xD3 : 0xD2, "Garderobjets", new GumpCallback(KeepItems)); + AddButton(width / 2 + 90, y, c_Sign.KeepItems ? 0xD3 : 0xD2, "Garderobjets", new GumpCallback(KeepItems)); + + if ( c_Sign.KeepItems ) + { + AddHtml( 0, y+=25, width/2-25, "
aux prix de"); + AddTextField( width/2+15, y, 70, 20, 0x480, 0xBBC, "coutObjet", c_Sign.ItemsPrice.ToString()); + AddButton(width / 2 - 10, y + 5, 0x2716, "coutObjet", new GumpCallback(ItemsPrice)); + } + else + { + AddHtml( 0, y+=25, width, "
Ne pas supprimer les objets"); + AddButton(width / 2 - 110, y, c_Sign.LeaveItems ? 0xD3 : 0xD2, "LaisserObjets", new GumpCallback(LeaveItems)); + AddButton(width / 2 + 90, y, c_Sign.LeaveItems ? 0xD3 : 0xD2, "LaisserObjets", new GumpCallback(LeaveItems)); + } + + string helptext = String.Format("Par d�faut, le syst�me permet de supprimer tous les objets non-statique d�j� " + +"presents dans la maison au moment de l'achat. Ces �l�ments sont commun�ment appel�s Objets de d�coration." + +"Ils ne comprennent pas les addons de maison, comme les forges, etc. Ils comprennent les conteneurs. Vous pouvez ici" + +"permettre aux joueurs de garder ces objets, et vous pouvez �galement les charger de le faire!"); + + AddHtml( 10, y+=35, width-20, 160, helptext, false, false ); + + y+=160; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.ItemsReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page + ( c_Sign.Owned ? 2: 1 ) ); + } + } + + private void LengthPage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Acheter ou Louer" ); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 120, y+=25, 50, c_Sign.PriceType); + AddButton( 170, y+8, 0x985, 0x985, "DureeUp", new GumpCallback( PriceUp ) ); + AddButton( 170, y-2, 0x983, 0x983, "DureeDown", new GumpCallback( PriceDown ) ); + + if ( c_Sign.RentByTime != TimeSpan.Zero ) + { + AddHtml( 0, y+=25, width, "
Location recurente"); + AddButton(width / 2 - 80, y, c_Sign.RecurRent ? 0xD3 : 0xD2, "RecurLoc", new GumpCallback(RecurRent)); + AddButton(width / 2 + 60, y, c_Sign.RecurRent ? 0xD3 : 0xD2, "RecurLoc", new GumpCallback(RecurRent)); + + if ( c_Sign.RecurRent ) + { + AddHtml(0, y += 20, width, "
Location-vente"); + AddButton(width / 2 - 80, y, c_Sign.RentToOwn ? 0xD3 : 0xD2, "Location-vente", new GumpCallback(RentToOwn)); + AddButton(width / 2 + 60, y, c_Sign.RentToOwn ? 0xD3 : 0xD2, "Location-vente", new GumpCallback(RentToOwn)); + } + } + + string helptext = String.Format( "On s'approche de la fin du programme d'installation! Maintenant vous pouvez sp�cifier si "+ +"ceci est une propri�t� en achat ou en location. Il suffit d'utiliser les fl�ches jusqu'� ce que que vous ayez le r�glage que vous d�sirez. Pour" + +"la location, vous pouvez �galement proc�der � l'achat non-recuit, ce qui signifie qu'apr�s que le temps soit �coul� le joueur" + +"est a la rue! Avec r�currents, s'il a de l'argent disponible, il peut continuer � louer. Vous pouvez" + +"�galement faire de la Location-Vente, permettant au joueur de poss�der le bien, apr�s deux mois de paiements"); + + AddHtml( 10, y+=35, width-20, 160, helptext, false, true ); + + y += 160; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.LengthReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void PricePage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Prix"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 0, y+=25, width, "
Gratuit"); + AddButton(width / 2 - 80, y, c_Sign.Free ? 0xD3 : 0xD2, "Gratuit", new GumpCallback(Free)); + AddButton(width / 2 + 60, y, c_Sign.Free ? 0xD3 : 0xD2, "Gratuit", new GumpCallback(Free)); + + if ( !c_Sign.Free ) + { + AddHtml( 0, y+=25, width/2-20, "
" + c_Sign.PriceType + " Prix"); + AddTextField( width/2+20, y, 70, 20, 0x480, 0xBBC, "Prix", c_Sign.Price.ToString()); + AddButton(width / 2 - 5, y + 5, 0x2716, "Prix", new GumpCallback(Price)); + + AddHtml( 0, y+=20, width, "
Suggest"); + AddButton(width / 2 - 50, y + 3, 0x2716, "Suggerer", new GumpCallback(SuggestPrice)); + AddButton(width / 2 + 40, y + 3, 0x2716, "Suggerer", new GumpCallback(SuggestPrice)); + } + + string helptext = String.Format(" Maintenant vous pouvez definir le prix de la maison. Rappelez-vous, s'il s'agit d'une " + +"location, le syst�me debitera ce montant au joueur pour chaque p�riode! Heureusement, la suggestion" + +"le prend en compte. Si que vous n'avez pas envie de chercher, laissez le syst�me propose un prix pour vous." + +"Vous pouvez aussi offrir la maison avec l'option gratuit"); + + AddHtml( 10, y+=35, width-20, 130, helptext, false, false ); + + y += 130; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page - ( c_Sign.Owned ? 2 : 1 ) ); + + if ( c_Sign.PriceReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void SkillsPage(int width, ref int y) + { + AddHtml( 0, y+=10, width, "
Restictions de competencess"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml( 0, y+=25, width/2-20, "
Competence"); + AddTextField(width / 2 + 20, y, 100, 20, 0x480, 0xBBC, "Competence", c_Sign.Skill.ToString()); + AddButton(width / 2 - 5, y + 5, 0x2716, "Competence", new GumpCallback(Skill)); + + AddHtml(0, y+=25, width / 2 - 20, "
Amount"); + AddTextField(width / 2 + 20, y, 50, 20, 0x480, 0xBBC, "SkillReq", c_Sign.SkillReq.ToString()); + AddButton(width / 2 - 5, y + 5, 0x2716, "Skill", new GumpCallback(Skill)); + + AddHtml(0, y += 25, width/2-20, "
Min Total"); + AddTextField(width / 2 + 20, y, 60, 20, 0x480, 0xBBC, "MinTotalSkill", c_Sign.MinTotalSkill.ToString()); + AddButton(width / 2 - 5, y + 5, 0x2716, "Skill", new GumpCallback(Skill)); + + AddHtml( 0, y+=25, width/2-20, "
Max Total"); + AddTextField(width / 2 + 20, y, 60, 20, 0x480, 0xBBC, "MaxTotalSkill", c_Sign.MaxTotalSkill.ToString()); + AddButton(width / 2 - 5, y + 5, 0x2716, "Skill", new GumpCallback(Skill)); + + string helptext = String.Format(" Ces param�tres sont tous facultatifs. Si vous souhaitez restreindre qui peut �tre propri�taire " + +"de cette maison par les comp�tences, c'est ici. Vous pouvez sp�cifier le nom et la valeur des comp�tences, ou par" + +"niveau de comp�tence totale"); + + AddHtml( 10, y+=35, width-20, 90, helptext, false, false ); + + y += 90; + + AddHtml( 30, y+=15, 80, "Previous"); + AddButton( 10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback( ChangePage ), (int)c_Page-1 ); + + if ( c_Sign.PriceReady ) + { + AddHtml( width-60, y, 60, "Next"); + AddButton( width-30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback( ChangePage ), (int)c_Page+1 ); + } + } + + private void OtherPage(int width, ref int y) + { + AddHtml(0, y += 10, width, "
Autres Options"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
Young"); + AddButton(width / 2 - 80, y, c_Sign.YoungOnly ? 0xD3 : 0xD2, "Young Only", new GumpCallback(Young)); + AddButton(width / 2 + 60, y, c_Sign.YoungOnly ? 0xD3 : 0xD2, "Young Only", new GumpCallback(Young)); + + if (!c_Sign.YoungOnly) + { + AddHtml(0, y += 25, width, "
Innocents"); + AddButton(width / 2 - 80, y, c_Sign.Murderers == Intu.No ? 0xD3 : 0xD2, "Pas d'Assassins", new GumpStateCallback(Murderers), Intu.No); + AddButton(width / 2 + 60, y, c_Sign.Murderers == Intu.No ? 0xD3 : 0xD2, "Pas d'Assassins", new GumpStateCallback(Murderers), Intu.No); + AddHtml(0, y += 20, width, "
Assassins"); + AddButton(width / 2 - 80, y, c_Sign.Murderers == Intu.Yes ? 0xD3 : 0xD2, "Assassins", new GumpStateCallback(Murderers), Intu.Yes); + AddButton(width / 2 + 60, y, c_Sign.Murderers == Intu.Yes ? 0xD3 : 0xD2, "Assassins", new GumpStateCallback(Murderers), Intu.Yes); + AddHtml(0, y += 20, width, "
Tous"); + AddButton(width / 2 - 80, y, c_Sign.Murderers == Intu.Neither ? 0xD3 : 0xD2, "Ni Assassins", new GumpStateCallback(Murderers), Intu.Neither); + AddButton(width / 2 + 60, y, c_Sign.Murderers == Intu.Neither ? 0xD3 : 0xD2, "Ni Assassins", new GumpStateCallback(Murderers), Intu.Neither); + } + + AddHtml(0, y += 25, width, "
Verrouiller et Demolir"); + AddButton(width / 2 - 110, y, c_Sign.Relock ? 0xD3 : 0xD2, "Reverouiller", new GumpCallback(Relock)); + AddButton(width / 2 + 90, y, c_Sign.Relock ? 0xD3 : 0xD2, "Reverouiller", new GumpCallback(Relock)); + + string helptext = String.Format(" Ces options sont �galement facultatives. Avec l'option Young, vous pouvez restreindre "+ + "l'achat de la maison aux Youngs uniquement. De m�me, vous pouvez sp�cifier si des assassins ou des innocents sont" + + "autoristes a etre propri�taires de la maison. Vous pouvez �galement sp�cifier si les portes au sein de " + + "la maison sont verrouill�es lorsque le propri�taire d�molit ses biens"); + + AddHtml(10, y += 35, width - 20, 180, helptext, false, false); + + y += 180; + + AddHtml(30, y += 15, 80, "Previous"); + AddButton(10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback(ChangePage), (int)c_Page - 1); + + AddHtml(width - 60, y, 60, "Next"); + AddButton(width - 30, y, 0x15E1, 0x15E5, "Next", new GumpStateCallback(ChangePage), (int)c_Page + 1); + } + + private void OtherPage2(int width, ref int y) + { + AddHtml(0, y += 10, width, "
Other Options 2"); + AddImage(width / 2 - 100, y + 2, 0x39); + AddImage(width / 2 + 70, y + 2, 0x3B); + + AddHtml(0, y += 25, width, "
Force Public"); + AddButton(width / 2 - 110, y, c_Sign.ForcePublic ? 0xD3 : 0xD2, "Public", new GumpCallback(ForcePublic)); + AddButton(width / 2 + 90, y, c_Sign.ForcePublic ? 0xD3 : 0xD2, "Public", new GumpCallback(ForcePublic)); + + AddHtml(0, y += 25, width, "
Force Private"); + AddButton(width / 2 - 110, y, c_Sign.ForcePrivate ? 0xD3 : 0xD2, "Private", new GumpCallback(ForcePrivate)); + AddButton(width / 2 + 90, y, c_Sign.ForcePrivate ? 0xD3 : 0xD2, "Private", new GumpCallback(ForcePrivate)); + + AddHtml(0, y += 25, width, "
No Trading"); + AddButton(width / 2 - 110, y, c_Sign.NoTrade ? 0xD3 : 0xD2, "NoTrade", new GumpCallback(NoTrade)); + AddButton(width / 2 + 90, y, c_Sign.NoTrade ? 0xD3 : 0xD2, "NoTrade", new GumpCallback(NoTrade)); + + AddHtml(0, y += 25, width, "
No Banning"); + AddButton(width / 2 - 110, y, c_Sign.NoBanning ? 0xD3 : 0xD2, "NoBan", new GumpCallback(NoBan)); + AddButton(width / 2 + 90, y, c_Sign.NoBanning ? 0xD3 : 0xD2, "NoBan", new GumpCallback(NoBan)); + + string helptext = String.Format("Une autre page d'options en option! Parfois, des maisons ont des caract�ristiques a soustraire aux joueurs " + + "Vous pouvez forcer les maisons en mode priv� ou publique. Vous pouvez aussi �viter que la session de la maison. Enfin, vous pouvez supprimer leur capacit� � bannir les joueurs"); + + AddHtml(10, y += 35, width - 20, 180, helptext, false, false); + + y += 180; + + AddHtml(30, y += 15, 80, "Previous"); + AddButton(10, y, 0x15E3, 0x15E7, "Previous", new GumpStateCallback(ChangePage), (int)c_Page - 1); + } + + private bool SkillNameExists(string text) + { + try + { + SkillName index = (SkillName)Enum.Parse( typeof( SkillName ), text, true ); + return true; + } + catch + { + Owner.SendMessage("Vous avez fourni un nom de comp�tence invalide."); + return false; + } + } + + private void ChangePage( object obj ) + { + if ( c_Sign == null ) + return; + + if ( !(obj is int) ) + return; + + c_Page = (Page)(int)obj; + + c_Sign.ClearPreview(); + + NewGump(); + } + + private void Name() + { + c_Sign.Name = GetTextField("Nom"); + Owner.SendMessage("Nom defini!"); + NewGump(); + } + + private void Goto() + { + Owner.Location = c_Sign.Location; + Owner.Z += 5; + Owner.Map = c_Sign.Map; + + NewGump(); + } + + private void Quick() + { + c_Quick = !c_Quick; + NewGump(); + } + + private void BanLocSelect() + { + Owner.SendMessage( "Ciblez l'emplacement des bannis." ); + Owner.Target = new InternalTarget( this, c_Sign, TargetType.BanLoc ); + } + + private void SignLocSelect() + { + Owner.SendMessage("Ciblez de l'emplacement pour le panneau d'accueil."); + Owner.Target = new InternalTarget( this, c_Sign, TargetType.SignLoc ); + } + + private void MinZSelect() + { + Owner.SendMessage( "Ciblez le plancher de base." ); + Owner.Target = new InternalTarget( this, c_Sign, TargetType.MinZ ); + } + + private void MaxZSelect() + { + Owner.SendMessage( "Ciblez le plancher le plus haut." ); + Owner.Target = new InternalTarget( this, c_Sign, TargetType.MaxZ ); + } + + private void Young() + { + c_Sign.YoungOnly = !c_Sign.YoungOnly; + NewGump(); + } + + private void Murderers( object obj ) + { + if ( !(obj is Intu) ) + return; + + c_Sign.Murderers = (Intu)obj; + + NewGump(); + } + + private void Relock() + { + c_Sign.Relock = !c_Sign.Relock; + NewGump(); + } + + private void ForcePrivate() + { + c_Sign.ForcePrivate = !c_Sign.ForcePrivate; + NewGump(); + } + + private void ForcePublic() + { + c_Sign.ForcePublic = !c_Sign.ForcePublic; + NewGump(); + } + + private void NoTrade() + { + c_Sign.NoTrade = !c_Sign.NoTrade; + NewGump(); + } + + private void NoBan() + { + c_Sign.NoBanning = !c_Sign.NoBanning; + NewGump(); + } + + private void KeepItems() + { + c_Sign.KeepItems = !c_Sign.KeepItems; + NewGump(); + } + + private void LeaveItems() + { + c_Sign.LeaveItems = !c_Sign.LeaveItems; + NewGump(); + } + + private void ItemsPrice() + { + c_Sign.ItemsPrice = GetTextFieldInt("PrixObjet"); + Owner.SendMessage("Prix objet defini!"); + NewGump(); + } + + private void RecurRent() + { + c_Sign.RecurRent = !c_Sign.RecurRent; + NewGump(); + } + + private void RentToOwn() + { + c_Sign.RentToOwn = !c_Sign.RentToOwn; + NewGump(); + } + + private void Skill() + { + if (GetTextField("Competence") != "" && SkillNameExists(GetTextField("Competence"))) + c_Sign.Skill = GetTextField("Competence"); + else + c_Sign.Skill = ""; + + c_Sign.SkillReq = GetTextFieldInt("SkillReq"); + c_Sign.MinTotalSkill = GetTextFieldInt("MinTotalSkill"); + c_Sign.MaxTotalSkill = GetTextFieldInt("MaxTotalSkill"); + + Owner.SendMessage("Infos competences definies!"); + + NewGump(); + } + + private void Claim() + { + new TownHouseConfirmGump( Owner, c_Sign ); + OnClose(); + } + + private void SuggestLocSec() + { + int price = c_Sign.CalcVolume()*General.SuggestionFactor; + c_Sign.Secures = price/75; + c_Sign.Locks = c_Sign.Secures/2; + + NewGump(); + } + + private void Secures() + { + c_Sign.Secures = GetTextFieldInt("Secures"); + Owner.SendMessage("Secures set!"); + NewGump(); + } + + private void Lockdowns() + { + c_Sign.Locks = GetTextFieldInt("Lockdowns"); + Owner.SendMessage("Lockdowns set!"); + NewGump(); + } + + private void SuggestPrice() + { + c_Sign.Price = c_Sign.CalcVolume()*General.SuggestionFactor; + + if ( c_Sign.RentByTime == TimeSpan.FromDays( 1 ) ) + c_Sign.Price /= 60; + if ( c_Sign.RentByTime == TimeSpan.FromDays( 7 ) ) + c_Sign.Price = (int)((double)c_Sign.Price/8.57); + if ( c_Sign.RentByTime == TimeSpan.FromDays( 30 ) ) + c_Sign.Price /= 2; + + NewGump(); + } + + private void Price() + { + c_Sign.Price = GetTextFieldInt("Prix"); + Owner.SendMessage("Prix defini!"); + NewGump(); + } + + private void Free() + { + c_Sign.Free = !c_Sign.Free; + NewGump(); + } + + private void AddBlock() + { + if ( c_Sign == null ) + return; + + Owner.SendMessage("Cibler le coin nord-ouest."); + Owner.Target = new InternalTarget( this, c_Sign, TargetType.BlockOne ); + } + + private void ClearAll() + { + if ( c_Sign == null ) + return; + + c_Sign.Blocks.Clear(); + c_Sign.ClearPreview(); + c_Sign.UpdateBlocks(); + + NewGump(); + } + + private void PriceUp() + { + c_Sign.NextPriceType(); + NewGump(); + } + + private void PriceDown() + { + c_Sign.PrevPriceType(); + NewGump(); + } + + protected override void OnClose() + { + c_Sign.ClearPreview(); + } + + + private class InternalTarget : Target + { + private TownHouseSetupGump c_Gump; + private TownHouseSign c_Sign; + private TargetType c_Type; + private Point3D c_BoundOne; + + public InternalTarget( TownHouseSetupGump gump, TownHouseSign sign, TargetType type ) : this( gump, sign, type, Point3D.Zero ){} + + public InternalTarget( TownHouseSetupGump gump, TownHouseSign sign, TargetType type, Point3D point ) : base( 20, true, TargetFlags.None ) + { + c_Gump = gump; + c_Sign = sign; + c_Type = type; + c_BoundOne = point; + } + + protected override void OnTarget( Mobile m, object o ) + { + IPoint3D point = (IPoint3D)o; + + switch( c_Type ) + { + case TargetType.BanLoc: + c_Sign.BanLoc = new Point3D( point.X, point.Y, point.Z ); + c_Gump.NewGump(); + break; + + case TargetType.SignLoc: + c_Sign.SignLoc = new Point3D( point.X, point.Y, point.Z ); + c_Sign.MoveToWorld(c_Sign.SignLoc, c_Sign.Map); + c_Sign.Z -= 5; + c_Sign.ShowSignPreview(); + c_Gump.NewGump(); + break; + + case TargetType.MinZ: + c_Sign.MinZ = point.Z; + + if ( c_Sign.MaxZ < c_Sign.MinZ+19 ) + c_Sign.MaxZ = point.Z+19; + + if ( c_Sign.MaxZ == short.MaxValue ) + c_Sign.MaxZ = point.Z+19; + + c_Gump.NewGump(); + break; + + case TargetType.MaxZ: + c_Sign.MaxZ = point.Z+19; + + if ( c_Sign.MinZ > c_Sign.MaxZ ) + c_Sign.MinZ = point.Z; + + c_Gump.NewGump(); + break; + + case TargetType.BlockOne: + m.SendMessage("Maintenant cibler le coin sud-est."); + m.Target = new InternalTarget( c_Gump, c_Sign, TargetType.BlockTwo, new Point3D( point.X, point.Y, point.Z ) ); + break; + + case TargetType.BlockTwo: + c_Sign.Blocks.Add( FixRect( new Rectangle2D( c_BoundOne, new Point3D( point.X+1, point.Y+1, point.Z ) ) ) ); + c_Sign.UpdateBlocks(); + c_Sign.ShowAreaPreview(m); + c_Gump.NewGump(); + break; + } + } + + protected override void OnTargetCancel( Mobile m, TargetCancelType cancelType ) + { + c_Gump.NewGump(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHousesGump.cs b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHousesGump.cs new file mode 100644 index 0000000..13e072d --- /dev/null +++ b/Scripts/Customs/Town Houses/Gumps/TownHouse Gumps/TownHousesGump.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Gumps; + +namespace Knives.TownHouses +{ + public class TownHousesGump : GumpPlusLight + { + public enum ListPage { Town, House } + + public static void Initialize() + { + RUOVersion.AddCommand("TownHouses", AccessLevel.Counselor, new TownHouseCommandHandler(OnHouses)); + } + + private static void OnHouses(CommandInfo info) + { + new TownHousesGump(info.Mobile); + } + + private ListPage c_ListPage; + private int c_Page; + + public TownHousesGump(Mobile m) + : base(m, 100, 100) + { + m.CloseGump(typeof(TownHousesGump)); + } + + protected override void BuildGump() + { + int width = 400; + int y = 0; + + AddHtml(0, y += 10, width, "
TownHouses Main Menu"); + AddImage(width / 2 - 120, y + 2, 0x39); + AddImage(width / 2 + 90, y + 2, 0x3B); + + int pp = 10; + + if (c_Page != 0) + AddButton(width / 2 - 10, y += 25, 0x25E4, 0x25E5, "Page Down", new GumpCallback(PageDown)); + + ArrayList list = new ArrayList(); + if(c_ListPage == ListPage.Town) + list = new ArrayList(TownHouseSign.AllSigns); + else + foreach(Item item in World.Items.Values) + if(item is BaseHouse) + list.Add(item); + + list.Sort(new InternalSort()); + + AddHtml(0, y += 20, width, "
" + (c_ListPage == ListPage.Town ? "TownHouses" : "Houses") + " Count: " + list.Count); + AddHtml(0, y += 25, width, "
TownHouses / Houses"); + AddButton(width / 2 - 100, y + 3, c_ListPage == ListPage.Town ? 0x939 : 0x2716, "Page", new GumpStateCallback(Page), ListPage.Town); + AddButton(width / 2 + 90, y + 3, c_ListPage == ListPage.House ? 0x939 : 0x2716, "Page", new GumpStateCallback(Page), ListPage.House); + + TownHouseSign sign = null; + BaseHouse house = null; + + y += 5; + + for (int i = c_Page * pp; i < (c_Page + 1) * pp && i < list.Count; ++i) + { + if (c_ListPage == ListPage.Town) + { + sign = (TownHouseSign)list[i]; + + AddHtml(30, y += 20, width / 2 - 20, "
" + sign.Name); + AddButton(15, y + 3, 0x2716, "TownHouse Menu", new GumpStateCallback(TownHouseMenu), sign); + + if (sign.House != null && sign.House.Owner != null) + { + AddHtml(width / 2, y, width / 2 - 40, "
" + sign.House.Owner.RawName); + AddButton(width - 30, y + 3, 0x2716, "House Menu", new GumpStateCallback(HouseMenu), sign.House); + } + } + else + { + house = (BaseHouse)list[i]; + + AddHtml(30, y += 20, width / 2 - 20, "
" + house.Name); + AddButton(15, y + 3, 0x2716, "Goto", new GumpStateCallback(Goto), house); + + if (house.Owner != null) + { + AddHtml(width / 2, y, width / 2 - 40, "
" + house.Owner.RawName); + AddButton(width - 30, y + 3, 0x2716, "House Menu", new GumpStateCallback(HouseMenu), house); + } + } + } + + if (pp * (c_Page + 1) < list.Count) + AddButton(width / 2 - 10, y += 25, 0x25E8, 0x25E9, "Page Up", new GumpCallback(PageUp)); + + if (c_ListPage == ListPage.Town) + { + AddHtml(0, y += 35, width, "
Add New TownHouse"); + AddButton(width / 2 - 80, y + 3, 0x2716, "New", new GumpCallback(New)); + AddButton(width / 2 + 70, y + 3, 0x2716, "New", new GumpCallback(New)); + } + + AddBackgroundZero(0, 0, width, y + 40, 0x13BE); + } + + private void TownHouseMenu(object obj) + { + if (!(obj is TownHouseSign)) + return; + + NewGump(); + + new TownHouseSetupGump(Owner, (TownHouseSign)obj); + } + + private void Page(object obj) + { + c_ListPage = (ListPage)obj; + NewGump(); + } + + private void Goto(object obj) + { + if (!(obj is BaseHouse)) + return; + + Owner.Location = ((BaseHouse)obj).BanLocation; + Owner.Map = ((BaseHouse)obj).Map; + + NewGump(); + } + + private void HouseMenu(object obj) + { + if (!(obj is BaseHouse)) + return; + + NewGump(); + + Owner.SendGump(new HouseGumpAOS((HouseGumpPageAOS)0, Owner, (BaseHouse)obj)); + } + + private void New() + { + TownHouseSign sign = new TownHouseSign(); + Owner.AddToBackpack(sign); + Owner.SendMessage("Une nouvelle enseigne est maintenant dans votre sac � do.s Il se d�place par lui-m�me lors de l'installation, mais si que vous ne terminez pas l'installation, vous pouvez le supprimer"); + + NewGump(); + + new TownHouseSetupGump(Owner, sign); + } + + private void PageUp() + { + c_Page++; + NewGump(); + } + + private void PageDown() + { + c_Page--; + NewGump(); + } + + + private class InternalSort : IComparer + { + public InternalSort() + { + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + return 0; + + if (x is TownHouseSign) + { + TownHouseSign a = (TownHouseSign)x; + TownHouseSign b = (TownHouseSign)y; + + return Insensitive.Compare(a.Name, b.Name); + } + else + { + BaseHouse a = (BaseHouse)x; + BaseHouse b = (BaseHouse)y; + + if (a.Owner == null && b.Owner != null) + return -1; + if (a.Owner != null && b.Owner == null) + return 1; + + return Insensitive.Compare(a.Owner.RawName, b.Owner.RawName); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Items/RentalContract.cs b/Scripts/Customs/Town Houses/Items/RentalContract.cs new file mode 100644 index 0000000..8e77be4 --- /dev/null +++ b/Scripts/Customs/Town Houses/Items/RentalContract.cs @@ -0,0 +1,316 @@ +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Items; + +namespace Knives.TownHouses +{ + public class RentalContract : TownHouseSign + { + private Mobile c_RentalMaster; + private Mobile c_RentalClient; + private BaseHouse c_ParentHouse; + private bool c_Completed, c_EntireHouse; + + public BaseHouse ParentHouse{ get{ return c_ParentHouse; } } + public Mobile RentalClient{ get{ return c_RentalClient; } set{ c_RentalClient = value; InvalidateProperties(); } } + public Mobile RentalMaster{ get{ return c_RentalMaster; } } + public bool Completed{ get{ return c_Completed; } set{ c_Completed = value; } } + public bool EntireHouse{ get{ return c_EntireHouse; } set{ c_EntireHouse = value; } } + + public RentalContract() : base() + { + ItemID = 0x14F0; + Movable = true; + RentByTime = TimeSpan.FromDays( 1 ); + RecurRent = true; + MaxZ = MinZ; + } + + public bool HasContractedArea( Rectangle2D rect, int z ) + { + foreach( Item item in TownHouseSign.AllSigns ) + if ( item is RentalContract && item != this && item.Map == Map && c_ParentHouse == ((RentalContract)item).ParentHouse ) + foreach( Rectangle2D rect2 in ((RentalContract)item).Blocks ) + for( int x = rect.Start.X; x < rect.End.X; ++x ) + for( int y = rect.Start.Y; y < rect.End.Y; ++y ) + if ( rect2.Contains( new Point2D( x, y ) ) ) + if ( ((RentalContract)item).MinZ <= z && ((RentalContract)item).MaxZ >= z ) + return true; + + return false; + } + + public bool HasContractedArea( int z ) + { + foreach( Item item in TownHouseSign.AllSigns ) + if ( item is RentalContract && item != this && item.Map == Map && c_ParentHouse == ((RentalContract)item).ParentHouse ) + if ( ((RentalContract)item).MinZ <= z && ((RentalContract)item).MaxZ >= z ) + return true; + + return false; + } + + public void DepositTo( Mobile m ) + { + if ( m == null ) + return; + + if ( Free ) + { + m.SendMessage( "Since this home is free, you do not receive the deposit." ); + return; + } + + m.BankBox.DropItem( new Gold( Price ) ); + m.SendMessage( "You have received a {0} gold deposit from your town house.", Price ); + } + + public override void ValidateOwnership() + { + if ( c_Completed && c_RentalMaster == null ) + { + Delete(); + return; + } + + if ( c_RentalClient != null && ( c_ParentHouse == null || c_ParentHouse.Deleted ) ) + { + Delete(); + return; + } + + if ( c_RentalClient != null && !Owned ) + { + Delete(); + return; + } + + if ( ParentHouse == null ) + return; + + if ( !ValidateLocSec() ) + { + if ( DemolishTimer == null ) + BeginDemolishTimer( TimeSpan.FromHours( 48 ) ); + } + else + ClearDemolishTimer(); + } + + protected override void DemolishAlert() + { + if ( ParentHouse == null || c_RentalMaster == null || c_RentalClient == null ) + return; + + c_RentalMaster.SendMessage( "You have begun to use lockdowns reserved for {0}, and their rental unit will collapse in {1}.", c_RentalClient.Name, Math.Round( (DemolishTime-DateTime.Now).TotalHours, 2 ) ); + c_RentalClient.SendMessage( "Alert your land lord, {0}, they are using storage reserved for you. They have violated the rental agreement, which will end in {1} if nothing is done.", c_RentalMaster.Name, Math.Round( (DemolishTime-DateTime.Now).TotalHours, 2 ) ); + } + + public void FixLocSec() + { + int count = 0; + + if ( (count = General.RemainingSecures( c_ParentHouse )+Secures) < Secures ) + Secures = count; + + if ( (count = General.RemainingLocks( c_ParentHouse )+Locks) < Locks ) + Locks = count; + } + + public bool ValidateLocSec() + { + if ( General.RemainingSecures( c_ParentHouse )+Secures < Secures ) + return false; + + if ( General.RemainingLocks( c_ParentHouse )+Locks < Locks ) + return false; + + return true; + } + + public override void ConvertItems( bool keep ) + { + if ( House == null || c_ParentHouse == null || c_RentalMaster == null ) + return; + + foreach( BaseDoor door in new ArrayList( c_ParentHouse.Doors ) ) + if ( door.Map == House.Map && House.Region.Contains( door.Location ) ) + ConvertDoor( door ); + + foreach( SecureInfo info in new ArrayList( c_ParentHouse.Secures ) ) + if ( info.Item.Map == House.Map && House.Region.Contains( info.Item.Location ) ) + c_ParentHouse.Release( c_RentalMaster, info.Item ); + + foreach( Item item in new ArrayList( c_ParentHouse.LockDowns ) ) + if ( item.Map == House.Map && House.Region.Contains( item.Location ) ) + c_ParentHouse.Release( c_RentalMaster, item ); + } + + public override void UnconvertDoors( ) + { + if ( House == null || c_ParentHouse == null ) + return; + + foreach( BaseDoor door in new ArrayList( House.Doors ) ) + House.Doors.Remove( door ); + } + + protected override void OnRentPaid() + { + if ( c_RentalMaster == null || c_RentalClient == null ) + return; + + if ( Free ) + return; + + c_RentalMaster.BankBox.DropItem( new Gold( Price ) ); + c_RentalMaster.SendMessage( "The bank has transfered your rent from {0}.", c_RentalClient.Name ); + } + + public override void ClearHouse() + { + if ( !Deleted ) + Delete(); + + base.ClearHouse(); + } + + public override void OnDoubleClick( Mobile m ) + { + ValidateOwnership(); + + if ( Deleted ) + return; + + if ( c_RentalMaster == null ) + c_RentalMaster = m; + + BaseHouse house = BaseHouse.FindHouseAt( m ); + + if ( c_ParentHouse == null ) + c_ParentHouse = house; + + if ( house == null || ( house != c_ParentHouse && house != House ) ) + { + m.SendMessage( "You must be in the home to view this contract." ); + return; + } + + if ( m == c_RentalMaster + && !c_Completed + && house is TownHouse + && ((TownHouse)house).ForSaleSign.PriceType != "Sale" ) + { + c_ParentHouse = null; + m.SendMessage( "You can only rent property you own." ); + return; + } + + if ( m == c_RentalMaster && !c_Completed && General.EntireHouseContracted( c_ParentHouse ) ) + { + m.SendMessage( "This entire house already has a rental contract." ); + return; + } + + if ( c_Completed ) + new ContractConfirmGump( m, this ); + else if ( m == c_RentalMaster ) + new ContractSetupGump( m, this ); + else + m.SendMessage( "This rental contract has not yet been completed." ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + if ( c_RentalClient != null ) + list.Add( "a house rental contract with " + c_RentalClient.Name ); + else if ( c_Completed ) + list.Add( "a completed house rental contract" ); + else + list.Add( "an uncompleted house rental contract" ); + } + + public override void Delete() + { + if ( c_ParentHouse == null ) + { + base.Delete(); + return; + } + + if ( !Owned && !c_ParentHouse.IsFriend( c_RentalClient ) ) + { + if ( c_RentalClient != null && c_RentalMaster != null ) + { + c_RentalMaster.SendMessage( "{0} has ended your rental agreement. Because you revoked their access, their last payment will be refunded.", c_RentalMaster.Name ); + c_RentalClient.SendMessage( "You have ended your rental agreement with {0}. Because your access was revoked, your last payment is refunded.", c_RentalClient.Name ); + } + + DepositTo( c_RentalClient ); + } + else if ( Owned ) + { + if ( c_RentalClient != null && c_RentalMaster != null ) + { + c_RentalClient.SendMessage( "{0} has ended your rental agreement. Since they broke the contract, your are refunded the last payment.", c_RentalMaster.Name ); + c_RentalMaster.SendMessage( "You have ended your rental agreement with {0}. They will be refunded their last payment.", c_RentalClient.Name ); + } + + DepositTo( c_RentalClient ); + + PackUpHouse(); + } + else + { + if ( c_RentalClient != null && c_RentalMaster != null ) + { + c_RentalMaster.SendMessage( "{0} has ended your rental agreement.", c_RentalClient.Name ); + c_RentalClient.SendMessage( "You have ended your rental agreement with {0}.", c_RentalMaster.Name ); + } + + DepositTo( c_RentalMaster ); + } + + ClearRentTimer(); + base.Delete(); + } + + public RentalContract( Serial serial ) : base( serial ) + { + RecurRent = true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + // Version 1 + + writer.Write( c_EntireHouse ); + + writer.Write( c_RentalMaster ); + writer.Write( c_RentalClient ); + writer.Write( c_ParentHouse ); + writer.Write( c_Completed ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version >= 1 ) + c_EntireHouse = reader.ReadBool(); + + c_RentalMaster = reader.ReadMobile(); + c_RentalClient = reader.ReadMobile(); + c_ParentHouse = reader.ReadItem() as BaseHouse; + c_Completed = reader.ReadBool(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Items/RentalContractCopy.cs b/Scripts/Customs/Town Houses/Items/RentalContractCopy.cs new file mode 100644 index 0000000..f8dccb4 --- /dev/null +++ b/Scripts/Customs/Town Houses/Items/RentalContractCopy.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Items; + +namespace Knives.TownHouses +{ + public class RentalContractCopy : Item + { + private RentalContract c_Contract; + + public RentalContractCopy( RentalContract contract ) + { + Name = "rental contract copy"; + ItemID = 0x14F0; + c_Contract = contract; + } + + public override void OnDoubleClick( Mobile m ) + { + if ( c_Contract == null || c_Contract.Deleted ) + { + Delete(); + return; + } + + c_Contract.OnDoubleClick( m ); + } + + public RentalContractCopy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Items/RentalLicense.cs b/Scripts/Customs/Town Houses/Items/RentalLicense.cs new file mode 100644 index 0000000..ede2fa7 --- /dev/null +++ b/Scripts/Customs/Town Houses/Items/RentalLicense.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Knives.TownHouses +{ + public class RentalLicense : Item + { + private Mobile c_Owner; + + public Mobile Owner{ get{ return c_Owner; } set{ c_Owner = value; InvalidateProperties(); } } + + public RentalLicense() : base( 0x14F0 ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + if ( c_Owner != null ) + list.Add( "a renter's license belonging to " + c_Owner.Name ); + else + list.Add( "a renter's license" ); + } + + public override void OnDoubleClick( Mobile m ) + { + if ( c_Owner == null ) + c_Owner = m; + } + + public RentalLicense( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( c_Owner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + c_Owner = reader.ReadMobile(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Items/SignHammer.cs b/Scripts/Customs/Town Houses/Items/SignHammer.cs new file mode 100644 index 0000000..dc1b053 --- /dev/null +++ b/Scripts/Customs/Town Houses/Items/SignHammer.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Multis; +using Server.Targeting; + +namespace Knives.TownHouses +{ + public enum HammerJob{ Flip, Swap } + + public class SignHammer : Item + { + private static Hashtable s_Table = new Hashtable(); + private static ArrayList s_List = new ArrayList(); + + public static void Initialize() + { + // Signs + s_Table[0xB95] = 0xB96; + s_Table[0xB96] = 0xB95; + s_Table[0xBA3] = 0xBA4; + s_Table[0xBA4] = 0xBA3; + s_Table[0xBA5] = 0xBA6; + s_Table[0xBA6] = 0xBA5; + s_Table[0xBA7] = 0xBA8; + s_Table[0xBA8] = 0xBA7; + s_Table[0xBA9] = 0xBAA; + s_Table[0xBAA] = 0xBA9; + s_Table[0xBAB] = 0xBAC; + s_Table[0xBAC] = 0xBAB; + s_Table[0xBAD] = 0xBAE; + s_Table[0xBAE] = 0xBAD; + s_Table[0xBAF] = 0xBB0; + s_Table[0xBB0] = 0xBAF; + s_Table[0xBB1] = 0xBB2; + s_Table[0xBB2] = 0xBB1; + s_Table[0xBB3] = 0xBB4; + s_Table[0xBB4] = 0xBB3; + s_Table[0xBB5] = 0xBB6; + s_Table[0xBB6] = 0xBB5; + s_Table[0xBB7] = 0xBB8; + s_Table[0xBB8] = 0xBB7; + s_Table[0xBB9] = 0xBBA; + s_Table[0xBBA] = 0xBB9; + s_Table[0xBBB] = 0xBBC; + s_Table[0xBBC] = 0xBBB; + s_Table[0xBBD] = 0xBBE; + s_Table[0xBBE] = 0xBBD; + s_Table[0xBBF] = 0xBC0; + s_Table[0xBC0] = 0xBBF; + s_Table[0xBC1] = 0xBC2; + s_Table[0xBC2] = 0xBC1; + s_Table[0xBC3] = 0xBC4; + s_Table[0xBC4] = 0xBC3; + s_Table[0xBC5] = 0xBC6; + s_Table[0xBC6] = 0xBC5; + s_Table[0xBC7] = 0xBC8; + s_Table[0xBC8] = 0xBC7; + s_Table[0xBC9] = 0xBCA; + s_Table[0xBCA] = 0xBC9; + s_Table[0xBCB] = 0xBCC; + s_Table[0xBCC] = 0xBCB; + s_Table[0xBCD] = 0xBCE; + s_Table[0xBCE] = 0xBCD; + s_Table[0xBCF] = 0xBD0; + s_Table[0xBD0] = 0xBCF; + s_Table[0xBD1] = 0xBD2; + s_Table[0xBD2] = 0xBD1; + s_Table[0xBD3] = 0xBD4; + s_Table[0xBD4] = 0xBD3; + s_Table[0xBD5] = 0xBD6; + s_Table[0xBD6] = 0xBD5; + s_Table[0xBD7] = 0xBD8; + s_Table[0xBD8] = 0xBD7; + s_Table[0xBD9] = 0xBDA; + s_Table[0xBDA] = 0xBD9; + s_Table[0xBDB] = 0xBDC; + s_Table[0xBDC] = 0xBDB; + s_Table[0xBDD] = 0xBDE; + s_Table[0xBDE] = 0xBDD; + s_Table[0xBDF] = 0xBE0; + s_Table[0xBE0] = 0xBDF; + s_Table[0xBE1] = 0xBE2; + s_Table[0xBE2] = 0xBE1; + s_Table[0xBE3] = 0xBE4; + s_Table[0xBE4] = 0xBE3; + s_Table[0xBE5] = 0xBE6; + s_Table[0xBE6] = 0xBE5; + s_Table[0xBE7] = 0xBE8; + s_Table[0xBE8] = 0xBE7; + s_Table[0xBE9] = 0xBEA; + s_Table[0xBEA] = 0xBE9; + s_Table[0xBEB] = 0xBEC; + s_Table[0xBEC] = 0xBEB; + s_Table[0xBED] = 0xBEE; + s_Table[0xBEE] = 0xBED; + s_Table[0xBEF] = 0xBF0; + s_Table[0xBF0] = 0xBEF; + s_Table[0xBF1] = 0xBF2; + s_Table[0xBF2] = 0xBF1; + s_Table[0xBF3] = 0xBF4; + s_Table[0xBF4] = 0xBF3; + s_Table[0xBF5] = 0xBF6; + s_Table[0xBF6] = 0xBF5; + s_Table[0xBF7] = 0xBF8; + s_Table[0xBF8] = 0xBF7; + s_Table[0xBF9] = 0xBFA; + s_Table[0xBFA] = 0xBF9; + s_Table[0xBFB] = 0xBFC; + s_Table[0xBFC] = 0xBFB; + s_Table[0xBFD] = 0xBFE; + s_Table[0xBFE] = 0xBFD; + s_Table[0xBFF] = 0xC00; + s_Table[0xC00] = 0xBFF; + s_Table[0xC01] = 0xC02; + s_Table[0xC02] = 0xC01; + s_Table[0xC03] = 0xC04; + s_Table[0xC04] = 0xC03; + s_Table[0xC05] = 0xC06; + s_Table[0xC06] = 0xC05; + s_Table[0xC07] = 0xC08; + s_Table[0xC08] = 0xC07; + s_Table[0xC09] = 0xC0A; + s_Table[0xC0A] = 0xC09; + s_Table[0xC0B] = 0xC0C; + s_Table[0xC0C] = 0xC0B; + s_Table[0xC0D] = 0xC0E; + s_Table[0xC0E] = 0xC0D; + + // Hangers + s_Table[0xB97] = 0xB98; + s_Table[0xB98] = 0xB97; + s_Table[0xB99] = 0xB9A; + s_Table[0xB9A] = 0xB99; + s_Table[0xB9B] = 0xB9C; + s_Table[0xB9C] = 0xB9B; + s_Table[0xB9D] = 0xB9E; + s_Table[0xB9E] = 0xB9D; + s_Table[0xB9F] = 0xBA0; + s_Table[0xBA0] = 0xB9F; + s_Table[0xBA1] = 0xBA2; + s_Table[0xBA2] = 0xBA1; + + // Hangers for swapping + s_List.Add(0xB97); + s_List.Add(0xB98); + s_List.Add(0xB99); + s_List.Add(0xB9A); + s_List.Add(0xB9B); + s_List.Add(0xB9C); + s_List.Add(0xB9D); + s_List.Add(0xB9E); + s_List.Add(0xB9F); + s_List.Add(0xBA0); + s_List.Add(0xBA1); + s_List.Add(0xBA2); + } + + private HammerJob c_Job; + + public HammerJob Job { get { return c_Job; } set { c_Job = value; } } + + [Constructable] + public SignHammer() + : base(0x13E3) + { + Name = "Sign Hammer"; + } + + public int GetFlipFor(int id) + { + return (s_Table[id] == null ? id : (int)s_Table[id]); + } + + public int GetNextSign(int id) + { + if (!s_List.Contains(id)) + return id; + + int idx = s_List.IndexOf(id); + + if (idx + 2 < s_List.Count) + return (int)s_List[idx + 2]; + + if (idx % 2 == 0) + return (int)s_List[0]; + + return (int)s_List[1]; + } + + public override void OnDoubleClick(Mobile m) + { + if (RootParent != m) + { + m.SendMessage("That item must be in your backpack to use."); + return; + } + + BaseHouse house = BaseHouse.FindHouseAt(m); + + if (m.AccessLevel == AccessLevel.Player && (house == null || house.Owner != m)) + { + m.SendMessage("You have to be inside your house to use this."); + return; + } + + m.BeginTarget(3, false, TargetFlags.None, new TargetCallback(OnTarget)); + } + + protected void OnTarget(Mobile m, object obj) + { + Item item = obj as Item; + + if (item == null) + { + m.SendMessage("You cannot change that with this."); + return; + } + + if (item == this) + { + new SignHammerGump(m, this); + return; + } + + if (c_Job == HammerJob.Flip) + { + int id = GetFlipFor(item.ItemID); + + if (id == item.ItemID) + m.SendMessage("You cannot change that with this."); + else + item.ItemID = id; + } + else + { + int id = GetNextSign(item.ItemID); + + if (id == item.ItemID) + m.SendMessage("You cannot change that with this."); + else + item.ItemID = id; + } + } + + public SignHammer(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SignHammerGump : GumpPlusLight + { + private SignHammer c_Hammer; + + public SignHammerGump( Mobile m, SignHammer hammer ) : base( m, 100, 100 ) + { + c_Hammer = hammer; + + NewGump(); + } + + protected override void BuildGump() + { + AddBackground(0, 0, 200, 200, 2600); + + AddButton(50, 45, 2152, 2154, "Swap", new GumpCallback(Swap)); + AddHtml( 90, 50, 70, "Swap Hanger"); + + AddButton( 50, 95, 2152, 2154, "Flip", new GumpCallback( Flip ) ); + AddHtml( 90, 100, 70, "Flip Sign or Hanger"); + } + + private void Swap() + { + c_Hammer.Job = HammerJob.Swap; + } + + private void Flip() + { + c_Hammer.Job = HammerJob.Flip; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Items/TownHouse.cs b/Scripts/Customs/Town Houses/Items/TownHouse.cs new file mode 100644 index 0000000..8c0ec7e --- /dev/null +++ b/Scripts/Customs/Town Houses/Items/TownHouse.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Multis; +using Server.Targeting; + +namespace Knives.TownHouses +{ + public class TownHouse : VersionHouse + { + private static ArrayList s_TownHouses = new ArrayList(); + public static ArrayList AllTownHouses{ get{ return s_TownHouses; } } + + private TownHouseSign c_Sign; + private Item c_Hanger; + private ArrayList c_Sectors = new ArrayList(); + + public TownHouseSign ForSaleSign { get { return c_Sign; } } + + public Item Hanger + { + get + { + if ( c_Hanger == null ) + { + c_Hanger = new Item( 0xB98 ); + c_Hanger.Movable = false; + c_Hanger.Location = Sign.Location; + c_Hanger.Map = Sign.Map; + } + + return c_Hanger; + } + set{ c_Hanger = value; } + } + + public TownHouse( Mobile m, TownHouseSign sign, int locks, int secures ) : base( 0x1DD6 | 0x4000, m, locks, secures ) + { + c_Sign = sign; + + SetSign( 0, 0, 0 ); + + s_TownHouses.Add( this ); + } + + public void InitSectorDefinition() + { + if (c_Sign == null || c_Sign.Blocks.Count == 0) + return; + + int minX = ((Rectangle2D)c_Sign.Blocks[0]).Start.X; + int minY = ((Rectangle2D)c_Sign.Blocks[0]).Start.Y; + int maxX = ((Rectangle2D)c_Sign.Blocks[0]).End.X; + int maxY = ((Rectangle2D)c_Sign.Blocks[0]).End.Y; + + foreach( Rectangle2D rect in c_Sign.Blocks ) + { + if ( rect.Start.X < minX ) + minX = rect.Start.X; + if ( rect.Start.Y < minY ) + minY = rect.Start.Y; + if ( rect.End.X > maxX ) + maxX = rect.End.X; + if ( rect.End.Y > maxY ) + maxY = rect.End.Y; + } + + foreach (Sector sector in c_Sectors) + sector.OnMultiLeave(this); + + c_Sectors.Clear(); + for (int x = minX; x < maxX; ++x) + for (int y = minY; y < maxY; ++y) + if(!c_Sectors.Contains(Map.GetSector(new Point2D(x, y)))) + c_Sectors.Add(Map.GetSector(new Point2D(x, y))); + + foreach (Sector sector in c_Sectors) + sector.OnMultiEnter(this); + + Components.Resize(maxX - minX, maxY - minY); + Components.Add(0x520, Components.Width - 1, Components.Height - 1, -5); + } + + public override Rectangle2D[] Area + { + get + { + if (c_Sign == null) + return new Rectangle2D[100]; + + Rectangle2D[] rects = new Rectangle2D[c_Sign.Blocks.Count]; + + for (int i = 0; i < c_Sign.Blocks.Count && i < rects.Length; ++i) + rects[i] = (Rectangle2D)c_Sign.Blocks[i]; + + return rects; + } + } + + public override bool IsInside( Point3D p, int height ) + { + if (c_Sign == null) + return false; + + if ( Map == null || Region == null ) + { + Delete(); + return false; + } + + Sector sector = null; + + try + { + if (c_Sign is RentalContract && Region.Contains(p)) + return true; + + sector = Map.GetSector(p); + + foreach (BaseMulti m in sector.Multis) + { + if (m != this + && m is TownHouse + && ((TownHouse)m).ForSaleSign is RentalContract + && ((TownHouse)m).IsInside(p, height)) + return false; + } + + return Region.Contains(p); + } + catch(Exception e) + { + Errors.Report("Error occured in IsInside(). More information on the console."); + Console.WriteLine("Info:{0}, {1}, {2}", Map, sector, Region, sector != null ? "" + sector.Multis : "**"); + Console.WriteLine(e.Source); + Console.WriteLine(e.Message); + Console.WriteLine(e.StackTrace); + return false; + } + } + + public override int GetNewVendorSystemMaxVendors() + { + return 50; + } + + public override int GetAosMaxSecures() + { + return MaxSecures; + } + + public override int GetAosMaxLockdowns() + { + return MaxLockDowns; + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if ( c_Hanger != null ) + c_Hanger.Map = Map; + } + + public override void OnLocationChange( Point3D oldLocation ) + { + base.OnLocationChange( oldLocation ); + + if ( c_Hanger != null ) + c_Hanger.Location = Sign.Location; + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( e.Mobile != Owner || !IsInside( e.Mobile ) ) + return; + + if (e.Speech.ToLower() == "check house rent") + c_Sign.CheckRentTimer(); + + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(AfterSpeech), e.Mobile); + } + + private void AfterSpeech(object o) + { + if (!(o is Mobile)) + return; + + if (((Mobile)o).Target is HouseBanTarget && ForSaleSign != null && ForSaleSign.NoBanning) + { + ((Mobile)o).Target.Cancel((Mobile)o, TargetCancelType.Canceled); + ((Mobile)o).SendMessage(0x161, "You cannot ban people from this house."); + } + } + + public override void OnDelete() + { + if (c_Hanger != null) + c_Hanger.Delete(); + + foreach (Item item in Sign.GetItemsInRange(0)) + if (item != Sign) + item.Visible = true; + + c_Sign.ClearHouse(); + Doors.Clear(); + + s_TownHouses.Remove(this); + + base.OnDelete(); + } + + public TownHouse(Serial serial) + : base(serial) + { + s_TownHouses.Add(this); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( 3 ); + + // Version 2 + + writer.Write( c_Hanger ); + + // Version 1 + + writer.Write( c_Sign ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version >= 2 ) + c_Hanger = reader.ReadItem(); + + c_Sign = (TownHouseSign)reader.ReadItem(); + + if (version <= 2) + { + int count = reader.ReadInt(); + for (int i = 0; i < count; ++i) + reader.ReadRect2D(); + } + + if( Price == 0 ) + Price = 1; + + ItemID = 0x1DD6 | 0x4000; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Items/TownHouseSign.cs b/Scripts/Customs/Town Houses/Items/TownHouseSign.cs new file mode 100644 index 0000000..afa3f89 --- /dev/null +++ b/Scripts/Customs/Town Houses/Items/TownHouseSign.cs @@ -0,0 +1,1305 @@ +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Items; +using Server.Mobiles; + +namespace Knives.TownHouses +{ + public enum Intu{ Neither, No, Yes } + + [Flipable( 0xC0B, 0xC0C )] + public class TownHouseSign : Item + { + private static ArrayList s_TownHouseSigns = new ArrayList(); + public static ArrayList AllSigns{ get{ return s_TownHouseSigns; } } + + private Point3D c_BanLoc, c_SignLoc; + private int c_Locks, c_Secures, c_Price, c_MinZ, c_MaxZ, c_MinTotalSkill, c_MaxTotalSkill, c_ItemsPrice, c_RTOPayments; + private bool c_YoungOnly, c_RecurRent, c_Relock, c_KeepItems, c_LeaveItems, c_RentToOwn, c_Free, c_ForcePrivate, c_ForcePublic, c_NoTrade, c_NoBanning; + private string c_Skill; + private double c_SkillReq; + private ArrayList c_Blocks, c_DecoreItemInfos, c_PreviewItems; + private TownHouse c_House; + private Timer c_DemolishTimer, c_RentTimer, c_PreviewTimer; + private DateTime c_DemolishTime, c_RentTime; + private TimeSpan c_RentByTime, c_OriginalRentTime; + private Intu c_Murderers; + + public Point3D BanLoc + { + get{ return c_BanLoc; } + set + { + c_BanLoc = value; + InvalidateProperties(); + if ( Owned ) + c_House.Region.GoLocation = value; + } + } + + public Point3D SignLoc + { + get{ return c_SignLoc; } + set + { + c_SignLoc = value; + InvalidateProperties(); + + if ( Owned ) + { + c_House.Sign.Location = value; + c_House.Hanger.Location = value; + } + } + } + + public int Locks + { + get{ return c_Locks; } + set + { + c_Locks = value; + InvalidateProperties(); + if ( Owned ) + c_House.MaxLockDowns = value; + } + } + + public int Secures + { + get{ return c_Secures; } + set + { + c_Secures = value; + InvalidateProperties(); + if ( Owned ) + c_House.MaxSecures = value; + } + } + + public int Price + { + get{ return c_Price; } + set + { + c_Price = value; + InvalidateProperties(); + } + } + + public int MinZ + { + get{ return c_MinZ; } + set + { + if ( value > c_MaxZ ) + c_MaxZ = value+1; + + c_MinZ = value; + if (Owned) + RUOVersion.UpdateRegion(this); + } + } + + public int MaxZ + { + get{ return c_MaxZ; } + set + { + if ( value < c_MinZ ) + value = c_MinZ; + + c_MaxZ = value; + if (Owned) + RUOVersion.UpdateRegion(this); + } + } + + public int MinTotalSkill + { + get{ return c_MinTotalSkill; } + set + { + if ( value > c_MaxTotalSkill ) + value = c_MaxTotalSkill; + + c_MinTotalSkill = value; + ValidateOwnership(); + InvalidateProperties(); + } + } + + public int MaxTotalSkill + { + get{ return c_MaxTotalSkill; } + set + { + if ( value < c_MinTotalSkill ) + value = c_MinTotalSkill; + + c_MaxTotalSkill = value; + ValidateOwnership(); + InvalidateProperties(); + } + } + + public bool YoungOnly + { + get{ return c_YoungOnly; } + set + { + c_YoungOnly = value; + + if ( c_YoungOnly ) + c_Murderers = Intu.Neither; + + ValidateOwnership(); + InvalidateProperties(); + } + } + + public TimeSpan RentByTime + { + get{ return c_RentByTime; } + set + { + c_RentByTime = value; + c_OriginalRentTime = value; + + if ( value == TimeSpan.Zero ) + ClearRentTimer(); + else + { + ClearRentTimer(); + BeginRentTimer( value ); + } + + InvalidateProperties(); + } + } + + public bool RecurRent + { + get{ return c_RecurRent; } + set + { + c_RecurRent = value; + + if ( !value ) + c_RentToOwn = value; + + InvalidateProperties(); + } + } + + public bool KeepItems + { + get{ return c_KeepItems; } + set + { + c_LeaveItems = false; + c_KeepItems = value; + InvalidateProperties(); + } + } + + public bool Free + { + get{ return c_Free; } + set + { + c_Free = value; + c_Price = 1; + InvalidateProperties(); + } + } + + public Intu Murderers + { + get{ return c_Murderers; } + set + { + c_Murderers = value; + + ValidateOwnership(); + InvalidateProperties(); + } + } + + public bool ForcePrivate + { + get { return c_ForcePrivate; } + set + { + c_ForcePrivate = value; + + if (value) + { + c_ForcePublic = false; + + if (c_House != null) + c_House.Public = false; + } + } + } + + public bool ForcePublic + { + get { return c_ForcePublic; } + set + { + c_ForcePublic = value; + + if (value) + { + c_ForcePrivate = false; + + if (c_House != null) + c_House.Public = true; + } + } + } + + public bool NoBanning + { + get { return c_NoBanning; } + set + { + c_NoBanning = value; + + if (value && c_House != null) + c_House.Bans.Clear(); + } + } + + public ArrayList Blocks { get { return c_Blocks; } set { c_Blocks = value; } } + public string Skill { get { return c_Skill; } set { c_Skill = value; ValidateOwnership(); InvalidateProperties(); } } + public double SkillReq { get { return c_SkillReq; } set { c_SkillReq = value; ValidateOwnership(); InvalidateProperties(); } } + public bool LeaveItems{ get{ return c_LeaveItems; } set{ c_LeaveItems = value; InvalidateProperties(); } } + public bool RentToOwn{ get{ return c_RentToOwn; } set{ c_RentToOwn = value; InvalidateProperties(); } } + public bool Relock { get { return c_Relock; } set { c_Relock = value; } } + public bool NoTrade { get { return c_NoTrade; } set { c_NoTrade = value; } } + public int ItemsPrice { get { return c_ItemsPrice; } set { c_ItemsPrice = value; InvalidateProperties(); } } + public TownHouse House{ get{ return c_House; } set{ c_House = value; } } + public Timer DemolishTimer{ get{ return c_DemolishTimer; } } + public DateTime DemolishTime{ get{ return c_DemolishTime; } } + + public bool Owned{ get{ return c_House != null && !c_House.Deleted; } } + public int Floors{ get{ return (c_MaxZ-c_MinZ)/20+1; } } + + public bool BlocksReady{ get{ return Blocks.Count != 0; } } + public bool FloorsReady{ get{ return ( BlocksReady && MinZ != short.MinValue ); } } + public bool SignReady{ get{ return ( FloorsReady && SignLoc != Point3D.Zero ); } } + public bool BanReady{ get{ return ( SignReady && BanLoc != Point3D.Zero ); } } + public bool LocSecReady{ get{ return ( BanReady && Locks != 0 && Secures != 0 ); } } + public bool ItemsReady{ get{ return LocSecReady; } } + public bool LengthReady{ get{ return ItemsReady; } } + public bool PriceReady{ get{ return ( LengthReady && Price != 0 ); } } + + public string PriceType + { + get + { + if ( c_RentByTime == TimeSpan.Zero ) + return "Sale"; + if ( c_RentByTime == TimeSpan.FromDays( 1 ) ) + return "Daily"; + if ( c_RentByTime == TimeSpan.FromDays( 7 ) ) + return "Weekly"; + if ( c_RentByTime == TimeSpan.FromDays( 30 ) ) + return "Monthly"; + + return "Sale"; + } + } + + public string PriceTypeShort + { + get + { + if ( c_RentByTime == TimeSpan.Zero ) + return "Sale"; + if ( c_RentByTime == TimeSpan.FromDays( 1 ) ) + return "Day"; + if ( c_RentByTime == TimeSpan.FromDays( 7 ) ) + return "Week"; + if ( c_RentByTime == TimeSpan.FromDays( 30 ) ) + return "Month"; + + return "Sale"; + } + } + + [Constructable] + public TownHouseSign() : base( 0xC0B ) + { + Name = "This building is for sale or rent!"; + Movable = false; + + c_BanLoc = Point3D.Zero; + c_SignLoc = Point3D.Zero; + c_Skill = ""; + c_Blocks = new ArrayList(); + c_DecoreItemInfos = new ArrayList(); + c_PreviewItems = new ArrayList(); + c_DemolishTime = DateTime.Now; + c_RentTime = DateTime.Now; + c_RentByTime = TimeSpan.Zero; + c_RecurRent = true; + + c_MinZ = short.MinValue; + c_MaxZ = short.MaxValue; + + s_TownHouseSigns.Add( this ); + } + + private void SearchForHouse() + { + foreach( TownHouse house in TownHouse.AllTownHouses ) + if (house.ForSaleSign == this ) + c_House = house; + } + + public void UpdateBlocks() + { + if ( !Owned ) + return; + + if (c_Blocks.Count == 0) + UnconvertDoors(); + + RUOVersion.UpdateRegion(this); + ConvertItems(false); + c_House.InitSectorDefinition(); + } + + public void ShowAreaPreview( Mobile m ) + { + ClearPreview(); + + Point2D point = Point2D.Zero; + ArrayList blocks = new ArrayList(); + + foreach( Rectangle2D rect in c_Blocks ) + for( int x = rect.Start.X; x < rect.End.X; ++x ) + for( int y = rect.Start.Y; y < rect.End.Y; ++y ) + { + point = new Point2D( x, y ); + if ( !blocks.Contains( point ) ) + blocks.Add( point ); + } + + if (blocks.Count > 500) + { + m.SendMessage("Due to size of the area, skipping the preview."); + return; + } + + Item item = null; + int avgz = 0; + foreach( Point2D p in blocks ) + { + avgz = Map.GetAverageZ(p.X, p.Y); + + item = new Item( 0x1766 ); + item.Name = "Area Preview"; + item.Movable = false; + item.Location = new Point3D( p.X, p.Y, (avgz <= m.Z ? m.Z+2 : avgz+2 ) ); + item.Map = Map; + + c_PreviewItems.Add( item ); + } + + c_PreviewTimer = Timer.DelayCall( TimeSpan.FromSeconds( 100 ), new TimerCallback( ClearPreview ) ); + } + + public void ShowSignPreview() + { + ClearPreview(); + + Item sign = new Item( 0xBD2 ); + sign.Name = "Sign Preview"; + sign.Movable = false; + sign.Location = SignLoc; + sign.Map = Map; + + c_PreviewItems.Add( sign ); + + sign = new Item( 0xB98 ); + sign.Name = "Sign Preview"; + sign.Movable = false; + sign.Location = SignLoc; + sign.Map = Map; + + c_PreviewItems.Add( sign ); + + c_PreviewTimer = Timer.DelayCall( TimeSpan.FromSeconds( 100 ), new TimerCallback( ClearPreview ) ); + } + + public void ShowBanPreview() + { + ClearPreview(); + + Item ban = new Item( 0x17EE ); + ban.Name = "Ban Loc Preview"; + ban.Movable = false; + ban.Location = BanLoc; + ban.Map = Map; + + c_PreviewItems.Add( ban ); + + c_PreviewTimer = Timer.DelayCall( TimeSpan.FromSeconds( 100 ), new TimerCallback( ClearPreview ) ); + } + + public void ShowFloorsPreview(Mobile m) + { + ClearPreview(); + + Item item = new Item(0x7BD); + item.Name = "Bottom Floor Preview"; + item.Movable = false; + item.Location = m.Location; + item.Z = c_MinZ; + item.Map = Map; + + c_PreviewItems.Add(item); + + item = new Item(0x7BD); + item.Name = "Top Floor Preview"; + item.Movable = false; + item.Location = m.Location; + item.Z = c_MaxZ; + item.Map = Map; + + c_PreviewItems.Add(item); + + c_PreviewTimer = Timer.DelayCall(TimeSpan.FromSeconds(100), new TimerCallback(ClearPreview)); + } + + public void ClearPreview() + { + foreach( Item item in new ArrayList( c_PreviewItems ) ) + { + c_PreviewItems.Remove( item ); + item.Delete(); + } + + if ( c_PreviewTimer != null ) + c_PreviewTimer.Stop(); + + c_PreviewTimer = null; + } + + public void Purchase( Mobile m ) + { + Purchase( m, false ); + } + + public void Purchase( Mobile m, bool sellitems ) + { + try + { + if (Owned) + { + m.SendMessage("Someone already owns this house!"); + return; + } + + if (!PriceReady) + { + m.SendMessage("The setup for this house is not yet complete."); + return; + } + + int price = c_Price + (sellitems ? c_ItemsPrice : 0); + + if (c_Free) + price = 0; + + if (m.AccessLevel == AccessLevel.Player && !Server.Mobiles.Banker.Withdraw(m, price)) + { + m.SendMessage("You cannot afford this house."); + return; + } + + if (m.AccessLevel == AccessLevel.Player) + m.SendLocalizedMessage(1060398, price.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + + Visible = false; + + int minX = ((Rectangle2D)c_Blocks[0]).Start.X; + int minY = ((Rectangle2D)c_Blocks[0]).Start.Y; + int maxX = ((Rectangle2D)c_Blocks[0]).End.X; + int maxY = ((Rectangle2D)c_Blocks[0]).End.Y; + + foreach (Rectangle2D rect in c_Blocks) + { + if (rect.Start.X < minX) + minX = rect.Start.X; + if (rect.Start.Y < minY) + minY = rect.Start.Y; + if (rect.End.X > maxX) + maxX = rect.End.X; + if (rect.End.Y > maxY) + maxY = rect.End.Y; + } + + c_House = new TownHouse(m, this, c_Locks, c_Secures); + + c_House.Components.Resize( maxX-minX, maxY-minY ); + c_House.Components.Add( 0x520, c_House.Components.Width-1, c_House.Components.Height-1, -5 ); + + c_House.Location = new Point3D(minX, minY, Map.GetAverageZ(minX, minY)); + c_House.Map = Map; + c_House.Region.GoLocation = c_BanLoc; + c_House.Sign.Location = c_SignLoc; + c_House.Hanger = new Item(0xB98); + c_House.Hanger.Location = c_SignLoc; + c_House.Hanger.Map = Map; + c_House.Hanger.Movable = false; + + if (c_ForcePublic) + c_House.Public = true; + + c_House.Price = (RentByTime == TimeSpan.FromDays(0) ? c_Price : 1); + + RUOVersion.UpdateRegion(this); + + if (c_House.Price == 0) + c_House.Price = 1; + + if (c_RentByTime != TimeSpan.Zero) + BeginRentTimer(c_RentByTime); + + c_RTOPayments = 1; + + HideOtherSigns(); + + c_DecoreItemInfos = new ArrayList(); + + ConvertItems(sellitems); + } + catch(Exception e) + { + Errors.Report(String.Format("An error occurred during home purchasing. More information available on the console.")); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source); + Console.WriteLine(e.StackTrace); + } + } + + private void HideOtherSigns() + { + foreach( Item item in c_House.Sign.GetItemsInRange( 0 ) ) + if ( !(item is HouseSign) ) + if ( item.ItemID == 0xB95 + || item.ItemID == 0xB96 + || item.ItemID == 0xC43 + || item.ItemID == 0xC44 + || ( item.ItemID > 0xBA3 && item.ItemID < 0xC0E ) ) + item.Visible = false; + } + + public virtual void ConvertItems( bool keep ) + { + if ( c_House == null ) + return; + + ArrayList items = new ArrayList(); + foreach(Rectangle2D rect in c_Blocks) + foreach (Item item in Map.GetItemsInBounds(rect)) + if (c_House.Region.Contains(item.Location) && item.RootParent == null && !items.Contains(item)) + items.Add(item); + + foreach (Item item in new ArrayList(items)) + { + if (item is HouseSign + || item is BaseMulti + || item is BaseAddon + || item is AddonComponent + || item == c_House.Hanger + || !item.Visible + || item.IsLockedDown + || item.IsSecure + || item.Movable + || c_PreviewItems.Contains(item)) + continue; + + if (item is BaseDoor) + ConvertDoor((BaseDoor)item); + else if (!c_LeaveItems) + { + c_DecoreItemInfos.Add(new DecoreItemInfo(item.GetType().ToString(), item.Name, item.ItemID, item.Hue, item.Location, item.Map)); + + if (!c_KeepItems || !keep) + item.Delete(); + else + { + item.Movable = true; + c_House.LockDown(c_House.Owner, item, false); + } + } + } + } + + protected void ConvertDoor( BaseDoor door ) + { + if ( !Owned ) + return; + + if ( door is Server.Gumps.ISecurable ) + { + door.Locked = false; + c_House.Doors.Add( door ); + return; + } + + door.Open = false; + + GenericHouseDoor newdoor = new GenericHouseDoor( (DoorFacing)0, door.ClosedID, door.OpenedSound, door.ClosedSound ); + newdoor.Offset = door.Offset; + newdoor.ClosedID = door.ClosedID; + newdoor.OpenedID = door.OpenedID; + newdoor.Location = door.Location; + newdoor.Map = door.Map; + + door.Delete(); + + foreach( Item inneritem in newdoor.GetItemsInRange( 1 ) ) + if ( inneritem is BaseDoor && inneritem != newdoor && inneritem.Z == newdoor.Z ) + { + ((BaseDoor)inneritem).Link = newdoor; + newdoor.Link = (BaseDoor)inneritem; + } + + c_House.Doors.Add(newdoor); + } + + public virtual void UnconvertDoors() + { + if ( c_House == null ) + return; + + BaseDoor newdoor = null; + + foreach (BaseDoor door in new ArrayList(c_House.Doors)) + { + door.Open = false; + + if ( c_Relock ) + door.Locked = true; + + newdoor = new StrongWoodDoor( (DoorFacing)0 ); + newdoor.ItemID = door.ItemID; + newdoor.ClosedID = door.ClosedID; + newdoor.OpenedID = door.OpenedID; + newdoor.OpenedSound = door.OpenedSound; + newdoor.ClosedSound = door.ClosedSound; + newdoor.Offset = door.Offset; + newdoor.Location = door.Location; + newdoor.Map = door.Map; + + door.Delete(); + + foreach( Item inneritem in newdoor.GetItemsInRange( 1 ) ) + if ( inneritem is BaseDoor && inneritem != newdoor && inneritem.Z == newdoor.Z ) + { + ( (BaseDoor)inneritem ).Link = newdoor; + newdoor.Link = (BaseDoor)inneritem; + } + + c_House.Doors.Remove( door ); + } + } + + public void RecreateItems() + { + Item item = null; + foreach( DecoreItemInfo info in c_DecoreItemInfos ) + { + item = null; + + if ( info.TypeString.ToLower().IndexOf( "static" ) != -1 ) + item = new Static( info.ItemID ); + else + { + try{ + item = Activator.CreateInstance( ScriptCompiler.FindTypeByFullName( info.TypeString ) ) as Item; + }catch{ continue; } + } + + if ( item == null ) + continue; + + item.ItemID = info.ItemID; + item.Name = info.Name; + item.Hue = info.Hue; + item.Location = info.Location; + item.Map = info.Map; + item.Movable = false; + } + } + + public virtual void ClearHouse() + { + UnconvertDoors(); + ClearDemolishTimer(); + ClearRentTimer(); + PackUpItems(); + RecreateItems(); + c_House = null; + Visible = true; + + if ( c_RentToOwn ) + c_RentByTime = c_OriginalRentTime; + } + + public virtual void ValidateOwnership() + { + if ( !Owned ) + return; + + if ( c_House.Owner == null ) + { + c_House.Delete(); + return; + } + + if ( c_House.Owner.AccessLevel != AccessLevel.Player ) + return; + + if ( !CanBuyHouse( c_House.Owner ) && c_DemolishTimer == null ) + BeginDemolishTimer(); + else + ClearDemolishTimer(); + } + + public int CalcVolume() + { + int floors = 1; + if ( c_MaxZ - c_MinZ < 100 ) + floors = 1 + Math.Abs( (c_MaxZ - c_MinZ)/20 ); + + Point3D point = Point3D.Zero; + ArrayList blocks = new ArrayList(); + + foreach( Rectangle2D rect in c_Blocks ) + for( int x = rect.Start.X; x < rect.End.X; ++x ) + for( int y = rect.Start.Y; y < rect.End.Y; ++y ) + for( int z = 0; z < floors; z++ ) + { + point = new Point3D( x, y, z ); + if ( !blocks.Contains( point ) ) + blocks.Add( point ); + } + return blocks.Count; + } + + private void StartTimers() + { + if (c_DemolishTime > DateTime.Now) + BeginDemolishTimer(c_DemolishTime - DateTime.Now); + else if (c_RentByTime != TimeSpan.Zero) + BeginRentTimer(c_RentByTime); + } + + #region Demolish + + public void ClearDemolishTimer() + { + if ( c_DemolishTimer == null ) + return; + + c_DemolishTimer.Stop(); + c_DemolishTimer = null; + c_DemolishTime = DateTime.Now; + + if ( !c_House.Deleted && Owned ) + c_House.Owner.SendMessage( "Demolition canceled." ); + } + + public void CheckDemolishTimer() + { + if ( c_DemolishTimer == null || !Owned ) + return; + + DemolishAlert(); + } + + protected void BeginDemolishTimer() + { + BeginDemolishTimer( TimeSpan.FromHours( 24 ) ); + } + + protected void BeginDemolishTimer( TimeSpan time ) + { + if ( !Owned ) + return; + + c_DemolishTime = DateTime.Now + time; + c_DemolishTimer = Timer.DelayCall( time, new TimerCallback( PackUpHouse ) ); + + DemolishAlert(); + } + + protected virtual void DemolishAlert() + { + c_House.Owner.SendMessage( "You no longer meet the requirements for your town house, which will be demolished automatically in {0}:{1}:{2}.", (c_DemolishTime-DateTime.Now).Hours, (c_DemolishTime-DateTime.Now).Minutes, (c_DemolishTime-DateTime.Now).Seconds ); + } + + protected void PackUpHouse() + { + if ( !Owned || c_House.Deleted ) + return; + + PackUpItems(); + + c_House.Owner.BankBox.DropItem( new BankCheck( c_House.Price ) ); + + c_House.Delete(); + } + + protected void PackUpItems() + { + if ( c_House == null ) + return; + + Container bag = new Bag(); + bag.Name = "Town House Belongings"; + + foreach( Item item in new ArrayList( c_House.LockDowns ) ) + { + item.IsLockedDown = false; + item.Movable = true; + c_House.LockDowns.Remove( item ); + bag.DropItem( item ); + } + + foreach( SecureInfo info in new ArrayList( c_House.Secures ) ) + { + info.Item.IsLockedDown = false; + info.Item.IsSecure = false; + info.Item.Movable = true; + info.Item.SetLastMoved(); + c_House.Secures.Remove( info ); + bag.DropItem( info.Item ); + } + + foreach(Rectangle2D rect in c_Blocks) + foreach (Item item in Map.GetItemsInBounds(rect)) + { + if (item is HouseSign + || item is BaseDoor + || item is BaseMulti + || item is BaseAddon + || item is AddonComponent + || !item.Visible + || item.IsLockedDown + || item.IsSecure + || !item.Movable + || item.Map != c_House.Map + || !c_House.Region.Contains(item.Location)) + continue; + + bag.DropItem(item); + } + + if ( bag.Items.Count == 0 ) + { + bag.Delete(); + return; + } + + c_House.Owner.BankBox.DropItem( bag ); + } + + #endregion + + #region Rent + + public void ClearRentTimer() + { + if ( c_RentTimer != null ) + { + c_RentTimer.Stop(); + c_RentTimer = null; + } + + c_RentTime = DateTime.Now; + } + + private void BeginRentTimer() + { + BeginRentTimer( TimeSpan.FromDays( 1 ) ); + } + + private void BeginRentTimer( TimeSpan time ) + { + if ( !Owned ) + return; + + c_RentTimer = Timer.DelayCall( time, new TimerCallback( RentDue ) ); + c_RentTime = DateTime.Now + time; + } + + public void CheckRentTimer() + { + if ( c_RentTimer == null || !Owned ) + return; + + c_House.Owner.SendMessage( "This rent cycle ends in {0} days, {1}:{2}:{3}.", (c_RentTime-DateTime.Now).Days, (c_RentTime-DateTime.Now).Hours, (c_RentTime-DateTime.Now).Minutes, (c_RentTime-DateTime.Now).Seconds ); + } + + private void RentDue() + { + if ( !Owned || c_House.Owner == null ) + return; + + if ( !c_RecurRent ) + { + c_House.Owner.SendMessage( "Your town house rental contract has expired, and the bank has once again taken possession." ); + PackUpHouse(); + return; + } + + if ( !c_Free && c_House.Owner.AccessLevel == AccessLevel.Player && !Server.Mobiles.Banker.Withdraw( c_House.Owner, c_Price ) ) + { + c_House.Owner.SendMessage( "Since you can not afford the rent, the bank has reclaimed your town house." ); + PackUpHouse(); + return; + } + + if ( !c_Free ) + c_House.Owner.SendMessage( "The bank has withdrawn {0} gold rent for your town house.", c_Price ); + + OnRentPaid(); + + if ( c_RentToOwn ) + { + c_RTOPayments++; + + bool complete = false; + + if ( c_RentByTime == TimeSpan.FromDays( 1 ) && c_RTOPayments >= 60 ) + { + complete = true; + c_House.Price = c_Price*60; + } + + if ( c_RentByTime == TimeSpan.FromDays( 7 ) && c_RTOPayments >= 9 ) + { + complete = true; + c_House.Price = c_Price*9; + } + + if ( c_RentByTime == TimeSpan.FromDays( 30 ) && c_RTOPayments >= 2 ) + { + complete = true; + c_House.Price = c_Price*2; + } + + if ( complete ) + { + c_House.Owner.SendMessage( "You now own your rental home." ); + c_RentByTime = TimeSpan.FromDays( 0 ); + return; + } + } + + BeginRentTimer( c_RentByTime ); + } + + protected virtual void OnRentPaid() + { + } + + public void NextPriceType() + { + if ( c_RentByTime == TimeSpan.Zero ) + RentByTime = TimeSpan.FromDays( 1 ); + else if ( c_RentByTime == TimeSpan.FromDays( 1 ) ) + RentByTime = TimeSpan.FromDays( 7 ); + else if ( c_RentByTime == TimeSpan.FromDays( 7 ) ) + RentByTime = TimeSpan.FromDays( 30 ); + else + RentByTime = TimeSpan.Zero; + } + + public void PrevPriceType() + { + if ( c_RentByTime == TimeSpan.Zero ) + RentByTime = TimeSpan.FromDays( 30 ); + else if ( c_RentByTime == TimeSpan.FromDays( 30 ) ) + RentByTime = TimeSpan.FromDays( 7 ); + else if ( c_RentByTime == TimeSpan.FromDays( 7 ) ) + RentByTime = TimeSpan.FromDays( 1 ); + else + RentByTime = TimeSpan.Zero; + } + + #endregion + + public bool CanBuyHouse( Mobile m ) + { + if ( c_Skill != "" ) + { + try + { + SkillName index = (SkillName)Enum.Parse( typeof( SkillName ), c_Skill, true ); + if ( m.Skills[index].Value < c_SkillReq ) + return false; + } + catch + { + return false; + } + } + + if ( c_MinTotalSkill != 0 && m.SkillsTotal/10 < c_MinTotalSkill ) + return false; + + if ( c_MaxTotalSkill != 0 && m.SkillsTotal/10 > c_MaxTotalSkill ) + return false; + + if ( c_YoungOnly && m.Player && !((PlayerMobile)m).Young ) + return false; + + if ( c_Murderers == Intu.Yes && m.Kills < 5 ) + return false; + + if ( c_Murderers == Intu.No && m.Kills >= 5 ) + return false; + + return true; + } + + public override void OnDoubleClick( Mobile m ) + { + if ( m.AccessLevel != AccessLevel.Player ) + new TownHouseSetupGump( m, this ); + else if ( !Visible ) + return; + else if ( CanBuyHouse( m ))// && !BaseHouse.HasAccountHouse( m ) ) + new TownHouseConfirmGump( m, this ); + else + m.SendMessage( "You cannot purchase this house." ); + } + + public override void Delete() + { + if ( c_House == null || c_House.Deleted ) + base.Delete(); + else + PublicOverheadMessage( Server.Network.MessageType.Regular, 0x0, true, "You cannot delete this while the home is owned." ); + + if ( this.Deleted ) + s_TownHouseSigns.Remove( this ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( c_Free ) + list.Add( 1060658, "Price\tFree" ); + else if ( c_RentByTime == TimeSpan.Zero ) + list.Add( 1060658, "Price\t{0}{1}", c_Price, c_KeepItems ? " (+" + c_ItemsPrice + " for the items)" : "" ); + else if ( c_RecurRent ) + list.Add( 1060658, "{0}\t{1}\r{2}", PriceType + (c_RentToOwn ? " Rent-to-Own" : " Recurring"), c_Price, c_KeepItems ? " (+" + c_ItemsPrice + " for the items)" : "" ); + else + list.Add( 1060658, "One {0}\t{1}{2}", PriceTypeShort, c_Price, c_KeepItems ? " (+" + c_ItemsPrice + " for the items)" : "" ); + + list.Add( 1060659, "Lockdowns\t{0}", c_Locks ); + list.Add( 1060660, "Secures\t{0}", c_Secures ); + + if ( c_SkillReq != 0.0 ) + list.Add( 1060661, "Requires\t{0}", c_SkillReq + " in " + c_Skill ); + if ( c_MinTotalSkill != 0 ) + list.Add( 1060662, "Requires more than\t{0} total skills", c_MinTotalSkill ); + if ( c_MaxTotalSkill != 0 ) + list.Add( 1060663, "Requires less than\t{0} total skills", c_MaxTotalSkill ); + + if ( c_YoungOnly ) + list.Add( 1063483, "Must be\tYoung" ); + else if ( c_Murderers == Intu.Yes ) + list.Add( 1063483, "Must be\ta murderer" ); + else if ( c_Murderers == Intu.No ) + list.Add( 1063483, "Must be\tinnocent" ); + } + + public TownHouseSign( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( 13 ); + + // Version 13 + + writer.Write(c_ForcePrivate); + writer.Write(c_ForcePublic); + writer.Write(c_NoTrade); + + // Version 12 + + writer.Write( c_Free ); + + // Version 11 + + writer.Write( (int)c_Murderers ); + + // Version 10 + + writer.Write( c_LeaveItems ); + + // Version 9 + writer.Write( c_RentToOwn ); + writer.Write( c_OriginalRentTime ); + writer.Write( c_RTOPayments ); + + // Version 7 + writer.WriteItemList( c_PreviewItems, true ); + + // Version 6 + writer.Write( c_ItemsPrice ); + writer.Write( c_KeepItems ); + + // Version 5 + writer.Write( c_DecoreItemInfos.Count ); + foreach( DecoreItemInfo info in c_DecoreItemInfos ) + info.Save( writer ); + + writer.Write( c_Relock ); + + // Version 4 + writer.Write( c_RecurRent ); + writer.Write( c_RentByTime ); + writer.Write( c_RentTime ); + writer.Write( c_DemolishTime ); + writer.Write( c_YoungOnly ); + writer.Write( c_MinTotalSkill ); + writer.Write( c_MaxTotalSkill ); + + // Version 3 + writer.Write( c_MinZ ); + writer.Write( c_MaxZ ); + + // Version 2 + writer.Write( c_House ); + + // Version 1 + writer.Write( c_Price ); + writer.Write( c_Locks ); + writer.Write( c_Secures ); + writer.Write( c_BanLoc ); + writer.Write( c_SignLoc ); + writer.Write( c_Skill ); + writer.Write( c_SkillReq ); + writer.Write( c_Blocks.Count ); + foreach( Rectangle2D rect in c_Blocks ) + writer.Write( rect ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if (version >= 13) + { + c_ForcePrivate = reader.ReadBool(); + c_ForcePublic = reader.ReadBool(); + c_NoTrade = reader.ReadBool(); + } + + if (version >= 12) + c_Free = reader.ReadBool(); + + if ( version >= 11 ) + c_Murderers = (Intu)reader.ReadInt(); + + if ( version >= 10 ) + c_LeaveItems = reader.ReadBool(); + + if ( version >= 9 ) + { + c_RentToOwn = reader.ReadBool(); + c_OriginalRentTime = reader.ReadTimeSpan(); + c_RTOPayments = reader.ReadInt(); + } + + c_PreviewItems = new ArrayList(); + if ( version >= 7 ) + c_PreviewItems = reader.ReadItemList(); + + if ( version >= 6 ) + { + c_ItemsPrice = reader.ReadInt(); + c_KeepItems = reader.ReadBool(); + } + + c_DecoreItemInfos = new ArrayList(); + if ( version >= 5 ) + { + int decorecount = reader.ReadInt(); + DecoreItemInfo info; + for( int i = 0; i < decorecount; ++i ) + { + info = new DecoreItemInfo(); + info.Load( reader ); + c_DecoreItemInfos.Add( info ); + } + + c_Relock = reader.ReadBool(); + } + + if ( version >= 4 ) + { + c_RecurRent = reader.ReadBool(); + c_RentByTime = reader.ReadTimeSpan(); + c_RentTime = reader.ReadDateTime(); + c_DemolishTime = reader.ReadDateTime(); + c_YoungOnly = reader.ReadBool(); + c_MinTotalSkill = reader.ReadInt(); + c_MaxTotalSkill = reader.ReadInt(); + } + + if ( version >= 3 ) + { + c_MinZ = reader.ReadInt(); + c_MaxZ = reader.ReadInt(); + } + + if ( version >= 2 ) + c_House = (TownHouse)reader.ReadItem(); + + c_Price = reader.ReadInt(); + c_Locks = reader.ReadInt(); + c_Secures = reader.ReadInt(); + c_BanLoc = reader.ReadPoint3D(); + c_SignLoc = reader.ReadPoint3D(); + c_Skill = reader.ReadString(); + c_SkillReq = reader.ReadDouble(); + + c_Blocks = new ArrayList(); + int count = reader.ReadInt(); + for ( int i = 0; i < count; ++i ) + c_Blocks.Add( reader.ReadRect2D() ); + + if ( c_RentTime > DateTime.Now ) + BeginRentTimer( c_RentTime-DateTime.Now ); + + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(StartTimers)); + + ClearPreview(); + + s_TownHouseSigns.Add( this ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Misc/CommandInfo.cs b/Scripts/Customs/Town Houses/Misc/CommandInfo.cs new file mode 100644 index 0000000..93a59ac --- /dev/null +++ b/Scripts/Customs/Town Houses/Misc/CommandInfo.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public delegate void TownHouseCommandHandler(CommandInfo info); + + public class CommandInfo + { + private Mobile c_Mobile; + private string c_Command; + private string c_ArgString; + private string[] c_Arguments; + + public Mobile Mobile { get { return c_Mobile; } } + public string Command { get { return c_Command; } } + public string ArgString { get { return c_ArgString; } } + public string[] Arguments { get { return c_Arguments; } } + + public CommandInfo(Mobile m, string com, string args, string[] arglist) + { + c_Mobile = m; + c_Command = com; + c_ArgString = args; + c_Arguments = arglist; + } + + public string GetString(int num) + { + if (c_Arguments.Length > num) + return c_Arguments[num]; + + return ""; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Misc/DecoreItemInfo.cs b/Scripts/Customs/Town Houses/Misc/DecoreItemInfo.cs new file mode 100644 index 0000000..b5aae3c --- /dev/null +++ b/Scripts/Customs/Town Houses/Misc/DecoreItemInfo.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Knives.TownHouses +{ + public class DecoreItemInfo + { + private string c_TypeString; + private string c_Name; + private int c_ItemID; + private int c_Hue; + private Point3D c_Location; + private Map c_Map; + + public string TypeString{ get{ return c_TypeString; } } + public string Name{ get{ return c_Name; } } + public int ItemID{ get{ return c_ItemID; } } + public int Hue{ get{ return c_Hue; } } + public Point3D Location{ get{ return c_Location; } } + public Map Map{ get{ return c_Map; } } + + public DecoreItemInfo() + { + } + + public DecoreItemInfo( string typestring, string name, int itemid, int hue, Point3D loc, Map map ) + { + c_TypeString = typestring; + c_ItemID = itemid; + c_Location = loc; + c_Map = map; + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int)1 ); // Version + + // Version 1 + writer.Write( c_Hue ); + writer.Write( c_Name ); + + writer.Write( c_TypeString ); + writer.Write( c_ItemID ); + writer.Write( c_Location ); + writer.Write( c_Map ); + } + + public void Load( GenericReader reader ) + { + int version = reader.ReadInt(); + + if ( version >= 1 ) + { + c_Hue = reader.ReadInt(); + c_Name = reader.ReadString(); + } + + c_TypeString = reader.ReadString(); + c_ItemID = reader.ReadInt(); + c_Location = reader.ReadPoint3D(); + c_Map = reader.ReadMap(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Misc/General.cs b/Scripts/Customs/Town Houses/Misc/General.cs new file mode 100644 index 0000000..cd17bf2 --- /dev/null +++ b/Scripts/Customs/Town Houses/Misc/General.cs @@ -0,0 +1,217 @@ +// Check PackUpHouse() for that crash on item delete. It causes a crash in RemoveMulti (Core) + +using System; +using System.Collections; +using Server; +using Server.Multis; + +namespace Knives.TownHouses +{ + public class General + { + public static string Version{ get { return "2.01"; } } + + // This setting determines the suggested gold value for a single square of a home + // which then derives price, lockdowns and secures. + public static int SuggestionFactor { get{ return 600; } } + + // This setting determines if players need License in order to rent out their property + public static bool RequireRenterLicense{ get{ return false; } } + + public static void Configure() + { + EventSink.WorldSave += new WorldSaveEventHandler( OnSave ); + } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( OnLogin ); + EventSink.Speech += new SpeechEventHandler( HandleSpeech ); + EventSink.ServerStarted += new ServerStartedEventHandler( OnStarted ); + } + + private static void OnStarted() + { + foreach (TownHouse house in TownHouse.AllTownHouses) + { + house.InitSectorDefinition(); + RUOVersion.UpdateRegion(house.ForSaleSign); + } + } + + public static void OnSave( WorldSaveEventArgs e ) + { + foreach( TownHouseSign sign in new ArrayList( TownHouseSign.AllSigns ) ) + sign.ValidateOwnership(); + + foreach( TownHouse house in new ArrayList( TownHouse.AllTownHouses ) ) + if ( house.Deleted ) + { + TownHouse.AllTownHouses.Remove( house ); + continue; + } + } + + private static void OnLogin( LoginEventArgs e ) + { + foreach( BaseHouse house in BaseHouse.GetHouses( e.Mobile ) ) + if ( house is TownHouse ) + ((TownHouse)house).ForSaleSign.CheckDemolishTimer(); + } + + private static void HandleSpeech( SpeechEventArgs e ) + { + ArrayList houses = new ArrayList(BaseHouse.GetHouses( e.Mobile )); + + if ( houses == null ) + return; + + foreach( BaseHouse house in houses ) + { + if (!RUOVersion.RegionContains(house.Region, e.Mobile)) + continue; + + if ( house is TownHouse ) + house.OnSpeech( e ); + + if ( house.Owner == e.Mobile + && e.Speech.ToLower() == "create rental contract" + && CanRent( e.Mobile, house, true ) ) + { + e.Mobile.AddToBackpack( new RentalContract() ); + e.Mobile.SendMessage( "A rental contract has been placed in your bag." ); + } + + if ( house.Owner == e.Mobile + && e.Speech.ToLower() == "check storage" ) + { + int count = 0; + + e.Mobile.SendMessage( "You have {0} lockdowns and {1} secures available.", RemainingSecures( house ), RemainingLocks( house ) ); + + if ( (count = AllRentalLocks( house )) != 0 ) + e.Mobile.SendMessage( "Current rentals are using {0} of your lockdowns.", count ); + if ( (count = AllRentalSecures( house )) != 0 ) + e.Mobile.SendMessage( "Current rentals are using {0} of your secures.", count ); + } + } + } + + private static bool CanRent( Mobile m, BaseHouse house, bool say ) + { + if ( house is TownHouse && ((TownHouse)house).ForSaleSign.PriceType != "Sale" ) + { + if ( say ) + m.SendMessage( "You must own your property to rent it." ); + + return false; + } + + if ( RequireRenterLicense ) + { + RentalLicense lic = m.Backpack.FindItemByType( typeof( RentalLicense ) ) as RentalLicense; + + if ( lic != null && lic.Owner == null ) + lic.Owner = m; + + if ( lic == null || lic.Owner != m ) + { + if ( say ) + m.SendMessage( "You must have a renter's license to rent your property." ); + + return false; + } + } + + if ( EntireHouseContracted( house ) ) + { + if ( say ) + m.SendMessage( "This entire house already has a rental contract." ); + + return false; + } + + if ( RemainingSecures( house ) < 0 || RemainingLocks( house ) < 0 ) + { + if ( say ) + m.SendMessage( "You don't have the storage available to rent property." ); + + return false; + } + + return true; + } + + #region Rental Info + + public static bool EntireHouseContracted( BaseHouse house ) + { + foreach( Item item in TownHouseSign.AllSigns ) + if ( item is RentalContract && house == ((RentalContract)item).ParentHouse ) + if ( ((RentalContract)item).EntireHouse ) + return true; + + return false; + } + + public static bool HasContract( BaseHouse house ) + { + foreach( Item item in TownHouseSign.AllSigns ) + if ( item is RentalContract && house == ((RentalContract)item).ParentHouse ) + return true; + + return false; + } + + public static bool HasOtherContract( BaseHouse house, RentalContract contract ) + { + foreach( Item item in TownHouseSign.AllSigns ) + if ( item is RentalContract && item != contract && house == ((RentalContract)item).ParentHouse ) + return true; + + return false; + } + + public static int RemainingSecures( BaseHouse house ) + { + if ( house == null ) + return 0; + + int a, b, c, d; + + return (Core.AOS ? house.GetAosMaxSecures() - house.GetAosCurSecures( out a, out b, out c, out d ) : house.MaxSecures - house.SecureCount) - AllRentalSecures( house ); + } + + public static int RemainingLocks( BaseHouse house ) + { + if ( house == null ) + return 0; + + return (Core.AOS ? house.GetAosMaxLockdowns() - house.GetAosCurLockdowns() : house.MaxLockDowns - house.LockDownCount) - AllRentalLocks( house ); + } + + public static int AllRentalSecures( BaseHouse house ) + { + int count = 0; + + foreach( TownHouseSign sign in TownHouseSign.AllSigns ) + if ( sign is RentalContract && ((RentalContract)sign).ParentHouse == house ) + count+=sign.Secures; + + return count; + } + + public static int AllRentalLocks( BaseHouse house ) + { + int count = 0; + + foreach( TownHouseSign sign in TownHouseSign.AllSigns ) + if ( sign is RentalContract && ((RentalContract)sign).ParentHouse == house ) + count+=sign.Locks; + + return count; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Misc/GumpResponse.cs b/Scripts/Customs/Town Houses/Misc/GumpResponse.cs new file mode 100644 index 0000000..cfb4396 --- /dev/null +++ b/Scripts/Customs/Town Houses/Misc/GumpResponse.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Gumps; + +namespace Knives.TownHouses +{ + public class GumpResponse + { + public static void Initialize() + { + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(AfterInit)); + } + + private static void AfterInit() + { + PacketHandlers.Register(0xB1, 0, true, new OnPacketReceive(DisplayGumpResponse)); + } + + public static void DisplayGumpResponse(NetState state, PacketReader pvSrc) + { + int serial = pvSrc.ReadInt32(); + int typeID = pvSrc.ReadInt32(); + int buttonID = pvSrc.ReadInt32(); + + List gumps = (List)state.Gumps; + + for (int i = 0; i < gumps.Count; ++i) + { + Gump gump = gumps[i]; + + if (gump.Serial == serial && gump.TypeID == typeID) + { + int switchCount = pvSrc.ReadInt32(); + + if (switchCount < 0) + { + Console.WriteLine("Client: {0}: Invalid gump response, disconnecting...", state); + state.Dispose(); + return; + } + + int[] switches = new int[switchCount]; + + for (int j = 0; j < switches.Length; ++j) + switches[j] = pvSrc.ReadInt32(); + + int textCount = pvSrc.ReadInt32(); + + if (textCount < 0) + { + Console.WriteLine("Client: {0}: Invalid gump response, disconnecting...", state); + state.Dispose(); + return; + } + + TextRelay[] textEntries = new TextRelay[textCount]; + + for (int j = 0; j < textEntries.Length; ++j) + { + int entryID = pvSrc.ReadUInt16(); + int textLength = pvSrc.ReadUInt16(); + + if (textLength > 239) + return; + + string text = pvSrc.ReadUnicodeStringSafe(textLength); + textEntries[j] = new TextRelay(entryID, text); + } + + state.RemoveGump(i); + + if (!CheckResponse(gump, state.Mobile, buttonID)) + return; + + gump.OnResponse(state, new RelayInfo(buttonID, switches, textEntries)); + + return; + } + } + + if (typeID == 461) // Virtue gump + { + int switchCount = pvSrc.ReadInt32(); + + if (buttonID == 1 && switchCount > 0) + { + Mobile beheld = World.FindMobile(pvSrc.ReadInt32()); + + if (beheld != null) + EventSink.InvokeVirtueGumpRequest(new VirtueGumpRequestEventArgs(state.Mobile, beheld)); + } + else + { + Mobile beheld = World.FindMobile(serial); + + if (beheld != null) + EventSink.InvokeVirtueItemRequest(new VirtueItemRequestEventArgs(state.Mobile, beheld, buttonID)); + } + } + } + + private static bool CheckResponse(Gump gump, Mobile m, int id) + { + if (m == null || !m.Player) + return true; + + TownHouse th = null; + + ArrayList list = new ArrayList(); + foreach (Item item in m.GetItemsInRange(20)) + if (item is TownHouse) + list.Add(item); + + foreach (TownHouse t in list) + if (t.Owner == m) + { + th = t; + break; + } + + if (th == null || th.ForSaleSign == null) + return true; + + if (gump is HouseGumpAOS) + { + int val = id - 1; + + if (val < 0) + return true; + + int type = val % 15; + int index = val / 15; + + if (th.ForSaleSign.ForcePublic && type == 3 && index == 12 && th.Public) + { + m.SendMessage("This house cannot be private."); + m.SendGump(gump); + return false; + } + + if (th.ForSaleSign.ForcePrivate && type == 3 && index == 13 && !th.Public) + { + m.SendMessage("This house cannot be public."); + m.SendGump(gump); + return false; + } + + if (th.ForSaleSign.NoTrade && type == 6 && index == 1) + { + m.SendMessage("This house cannot be traded."); + m.SendGump(gump); + return false; + } + } + else if (gump is HouseGump) + { + if (th.ForSaleSign.ForcePublic && id == 17 && th.Public) + { + m.SendMessage("This house cannot be private."); + m.SendGump(gump); + return false; + } + + if (th.ForSaleSign.ForcePrivate && id == 17 && !th.Public) + { + m.SendMessage("This house cannot be public."); + m.SendGump(gump); + return false; + } + + if (th.ForSaleSign.NoTrade && id == 14) + { + m.SendMessage("This house cannot be traded."); + m.SendGump(gump); + return false; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Optional Patches/BaseHousePatch.txt b/Scripts/Customs/Town Houses/Optional Patches/BaseHousePatch.txt new file mode 100644 index 0000000..d69ea5a --- /dev/null +++ b/Scripts/Customs/Town Houses/Optional Patches/BaseHousePatch.txt @@ -0,0 +1,27 @@ +This patch adjusts how RunUO finds items in houses, switching from searching sectors and MultiComponentLists to simply seeing if the house region contains the location. Since players cannot go underground, or stand 10 feet above the roof of their house, this will negatively affect nothing. What it corrects is being able to see houses within houses, which is what renting out classic and custom homes creates. This patch will determine whether a home has a TownHouse within it, and whether the point in question is actually within the TownHouse. + +~ + +To patch, replace the following method within Scripts/Multis/BaseHouse.cs with this updated code: + +[code] + + public virtual bool IsInside( Point3D p, int height ) + { + Sector sector = Map.GetSector( p ); + + foreach( BaseMulti m in sector.Multis ) + { + if ( m != this + && m is Knives.TownHouses.TownHouse + && ((Knives.TownHouses.TownHouse)m).ForSaleSign is Knives.TownHouses.RentalContract + && ((Knives.TownHouses.TownHouse)m).IsInside( p, height ) ) + return false; + } + + return Region.Contains( p ); + } + +[/code] + +Be sure you make a backup of the default BaseHouse.cs file, just in case TownHouses needs to be removed or other problems occur. You can also comment out the old method instead of completely replacing it. \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Optional Patches/InteriorDecoratorPatch.txt b/Scripts/Customs/Town Houses/Optional Patches/InteriorDecoratorPatch.txt new file mode 100644 index 0000000..cace503 --- /dev/null +++ b/Scripts/Customs/Town Houses/Optional Patches/InteriorDecoratorPatch.txt @@ -0,0 +1,39 @@ +This patch slightly modifies how InteriorDecorators find the floor, which determines how far an item can be lowered or raised. Before TownHouses, homes always had a foundation underneith, that square block. InteriorDecorator used that foundation as the bottom floor. With this patch, when no bottom floor is found it will find the bottom floor off the map itself. + +~ + +To patch, replace the following method within Scripts/Items/Misc/InteriorDecorator.cs with this updated code: + +[code] + + private static int GetFloorZ( Item item ) + { + Map map = item.Map; + + if ( map == null ) + return int.MinValue; + + Tile[] tiles = map.Tiles.GetStaticTiles( item.X, item.Y, true ); + + int z = int.MinValue; + + for ( int i = 0; i < tiles.Length; ++i ) + { + Tile tile = tiles[i]; + ItemData id = TileData.ItemTable[tile.ID & 0x3FFF]; + + int top = tile.Z; // Confirmed : no height checks here + + if ( id.Surface && !id.Impassable && top > z && top <= item.Z ) + z = top; + } + + if ( z == int.MinValue ) + z = map.Tiles.GetLandTile( item.X, item.Y ).Z; + + return z; + } + +[/code] + +Be sure you make a backup of the default IntoeriorDecorator.cs file. Although removing TownHouses won't cause any problems with this patch, backups are always a great idea! You can also comment out the old method instead of completely replacing it. \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Optional Patches/READ.txt b/Scripts/Customs/Town Houses/Optional Patches/READ.txt new file mode 100644 index 0000000..1c86833 --- /dev/null +++ b/Scripts/Customs/Town Houses/Optional Patches/READ.txt @@ -0,0 +1,3 @@ +These patches are optional, meaning TownHouses will function without including them. However, they do correct minor issues with TownHouses that could not otherwise be corrected. These patches require modifying default RunUO source code, and you should have some knowledge of how to do this before attempting to patch. Finaly, be sure to make a backup copy of the original files, just in case. + +Good luck! \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/RUOVersion.cs b/Scripts/Customs/Town Houses/RUOVersion.cs new file mode 100644 index 0000000..92fda88 --- /dev/null +++ b/Scripts/Customs/Town Houses/RUOVersion.cs @@ -0,0 +1,137 @@ +/* + * The two lines following this entry specify what RunUO version you are running. + * In order to switch to RunUO 1.0 Final, remove the '//' in front of that setting + * and add '//' in front of '#define RunUO_2_RC1'. Warning: If you comment both + * out, many commands in this system will not work. Enjoy! + */ + +#define RunUO_2_RC1 +//#define RunUO_1_Final + +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Network; + +#if (RunUO_2_RC1) + using Server.Commands; +#endif + +namespace Knives.TownHouses +{ + public class RUOVersion + { + private static Hashtable s_Commands = new Hashtable(); + + public static void AddCommand(string com, AccessLevel acc, TownHouseCommandHandler cch) + { + s_Commands[com.ToLower()] = cch; + + #if(RunUO_1_Final) + Server.Commands.Register(com, acc, new CommandEventHandler(OnCommand)); + #elif(RunUO_2_RC1) + Server.Commands.CommandSystem.Register(com, acc, new CommandEventHandler(OnCommand)); + #endif + } + + public static void OnCommand(CommandEventArgs e) + { + if (s_Commands[e.Command.ToLower()] == null) + return; + + ((TownHouseCommandHandler)s_Commands[e.Command.ToLower()])(new CommandInfo(e.Mobile, e.Command, e.ArgString, e.Arguments)); + } + + public static void UpdateRegion(TownHouseSign sign) + { + if (sign.House == null) + return; + + #if(RunUO_1_Final) + sign.House.Region.Coords = new ArrayList(sign.Blocks); + sign.House.Region.MinZ = sign.MinZ; + sign.House.Region.MaxZ = sign.MaxZ; + sign.House.Region.Unregister(); + sign.House.Region.Register(); + sign.House.Region.GoLocation = sign.BanLoc; + #elif(RunUO_2_RC1) + sign.House.UpdateRegion(); + + Rectangle3D rect = new Rectangle3D(Point3D.Zero, Point3D.Zero); + + for (int i = 0; i < sign.House.Region.Area.Length; ++i) + { + rect = sign.House.Region.Area[i]; + rect = new Rectangle3D(new Point3D(rect.Start.X - sign.House.X, rect.Start.Y - sign.House.Y, sign.MinZ), new Point3D(rect.End.X - sign.House.X, rect.End.Y - sign.House.Y, sign.MaxZ)); + sign.House.Region.Area[i] = rect; + } + + sign.House.Region.Unregister(); + sign.House.Region.Register(); + sign.House.Region.GoLocation = sign.BanLoc; + + #endif + } + + public static bool RegionContains(Region region, Mobile m) + { + #if(RunUO_1_Final) + return region.Mobiles.Contains(m); + #elif(RunUO_2_RC1) + return region.GetMobiles().Contains(m); + #endif + } + + public static Rectangle3D[] RegionArea(Region region) + { + #if(RunUO_1_Final) + + Rectangle3D[] rects = new Rectangle3D[region.Coords.Count]; + Rectangle2D rect = new Rectangle2D(Point2D.Zero, Point2D.Zero); + + for (int i = 0; i < rects.Length && i < region.Coords.Count; ++i) + { + rect = (Rectangle2D)region.Coords[i]; + rects[i] = new Rectangle3D(new Point3D(rect.Start.X, rect.Start.Y, region.MinZ), new Point3D(rect.End.X, rect.End.Y, region.MaxZ)); + } + + return rects; + + #elif(RunUO_2_RC1) + return region.Area; + #endif + } + } + + public class VersionHouse : BaseHouse + { + public VersionHouse(int id, Mobile m, int locks, int secures) + : base(id, m, locks, secures) + { + } + + public override Rectangle2D[] Area { get { return new Rectangle2D[5]; } } + + #if(RunUO_2_RC1) + + public override Point3D BaseBanLocation { get { return Point3D.Zero; } } + + #endif + + public VersionHouse(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Town Houses/Read.doc b/Scripts/Customs/Town Houses/Read.doc new file mode 100644 index 0000000..5ee9e36 --- /dev/null +++ b/Scripts/Customs/Town Houses/Read.doc @@ -0,0 +1,127 @@ +{\rtf1\ansi\ansicpg1252\uc1\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} +{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f10\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;} +{\f36\froman\fcharset238\fprq2 Times New Roman CE;}{\f37\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f39\froman\fcharset161\fprq2 Times New Roman Greek;}{\f40\froman\fcharset162\fprq2 Times New Roman Tur;} +{\f41\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f42\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f43\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f44\froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\f46\fswiss\fcharset238\fprq2 Arial CE;}{\f47\fswiss\fcharset204\fprq2 Arial Cyr;}{\f49\fswiss\fcharset161\fprq2 Arial Greek;}{\f50\fswiss\fcharset162\fprq2 Arial Tur;}{\f51\fswiss\fcharset177\fprq2 Arial (Hebrew);} +{\f52\fswiss\fcharset178\fprq2 Arial (Arabic);}{\f53\fswiss\fcharset186\fprq2 Arial Baltic;}{\f54\fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f56\fmodern\fcharset238\fprq1 Courier New CE;}{\f57\fmodern\fcharset204\fprq1 Courier New Cyr;} +{\f59\fmodern\fcharset161\fprq1 Courier New Greek;}{\f60\fmodern\fcharset162\fprq1 Courier New Tur;}{\f61\fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f62\fmodern\fcharset178\fprq1 Courier New (Arabic);} +{\f63\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f64\fmodern\fcharset163\fprq1 Courier New (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0; +\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{ +\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\* +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv +\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\listtable{\list\listtemplateid1659899392 +\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid521150660\'01-;}{\levelnumbers;}\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480 +\jclisttab\tx6480\lin6480 }{\listname ;}\listid928544353}{\list\listtemplateid-410366494\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid1470935610 +\'01-;}{\levelnumbers;}\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691 +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1800\jclisttab\tx1800\lin1800 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} +\f10\fbias0 \fi-360\li2520\jclisttab\tx2520\lin2520 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li3240 +\jclisttab\tx3240\lin3240 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3960\jclisttab\tx3960\lin3960 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4680\jclisttab\tx4680\lin4680 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5400\jclisttab\tx5400\lin5400 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li6120\jclisttab\tx6120\lin6120 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6840\jclisttab\tx6840\lin6840 }{\listname ;}\listid953288573}{\list\listtemplateid-881454316\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat0\levelspace0\levelindent0{\leveltext\leveltemplateid-1037564862\'01-;}{\levelnumbers;}\loch\af1\hich\af1\dbch\af0\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 +{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691 +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;} +\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 +\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid1136679256}} +{\*\listoverridetable{\listoverride\listid1136679256\listoverridecount0\ls1}{\listoverride\listid953288573\listoverridecount0\ls2}{\listoverride\listid928544353\listoverridecount0\ls3}}{\*\rsidtbl \rsid673505\rsid939626\rsid1928404\rsid3087438\rsid3374933 +\rsid4403757\rsid5720789\rsid6097433\rsid7694856\rsid9571899\rsid10444852\rsid10580262\rsid11010391\rsid11032522\rsid11150156\rsid11536214\rsid12322751\rsid14176111\rsid14746673\rsid15479477\rsid15728713\rsid16011839\rsid16464944}{\*\generator Microsoft W +ord 11.0.5604;}{\info{\author Kevin}{\operator Kevin}{\creatim\yr2006\mo6\dy16\hr19\min10}{\revtim\yr2007\mo5\dy13\hr20\min27}{\version23}{\edmins40}{\nofpages2}{\nofwords722}{\nofchars4116}{\*\company }{\nofcharsws4829}{\vern24689}} +\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind4\viewscale100\nolnhtadjtbl\rsidroot5720789 \fet0\sectd +\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4 +\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (} +{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\b\f1\fs20\insrsid939626 Summary:}{\f1\fs20\insrsid939626 +\par +\par }{\f1\fs20\insrsid14746673 Version 2.0}{\f1\fs20\insrsid3374933 1}{\f1\fs20\insrsid939626 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid14746673 {\f1\fs20\insrsid14746673 Supports RunUO 2.0 RC1, RunUO 1.0 Final}{\f1\fs20\insrsid14746673\charrsid9571899 +\par +\par ***}{\f1\fs20\insrsid14746673 This version may work with the current RunUO 2.0 SVN, and this may change as the SVN changes. Please report this to me, as I can add patches to allow functionality. +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\f1\fs20\insrsid939626 +\par }{\b\f1\fs20\insrsid15728713 Version 2.0}{\b\f1\fs20\insrsid3374933 1}{\b\f1\fs20\insrsid15728713 News}{\f1\fs20\insrsid15728713\charrsid15728713 +\par }{\f1\fs20\insrsid15728713 +\par }{\f1\fs20\insrsid3374933 \tab Only about 15 days late, here is my latest TownHouses release! Since it is a build on top of the current 2.0 system, I just adjusted a little itty bitty .01! +There have been many recent feature requests, and this only touches a few. One of them, however, is quite important, that being a major RAM usage overhaul. For most of you this will be transparent but the large shards will see an improvement. +\par }{\f1\fs20\insrsid15728713 +\par }{\f1\fs20\insrsid3374933 \tab Here\rquote s the list of changes! +\par +\par {\listtext\pard\plain\f1\fs20\insrsid11032522 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li1080\ri0\nowidctlpar\jclisttab\tx1080\faauto\ls2\rin0\lin1080\itap0\pararsid15728713 {\f1\fs20\insrsid11032522 RAM reduction on home purchase}{ +\f1\fs20\insrsid15728713 +\par {\listtext\pard\plain\f1\fs20\insrsid11032522 \hich\af1\dbch\af0\loch\f1 -\tab}}{\f1\fs20\insrsid11032522 A new setup options: You can prevent banning in homes and force a home to be public or private. +\par {\listtext\pard\plain\f1\fs20\insrsid11032522 \hich\af1\dbch\af0\loch\f1 -\tab}The [TownHouses menu now has a tab for showing all houses. +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid10580262 {\f1\fs20\insrsid10580262 +\par }\pard \ql \li720\ri0\nowidctlpar\faauto\rin0\lin720\itap0\pararsid10580262 {\f1\fs20\insrsid10580262 That\rquote s it! Next time I update, I am planning to enhance the rental features. I can\rquote t predict when that update will come however + =) Until then, I will continue support as always! +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid11032522 {\f1\fs20\insrsid11032522 +\par }\pard \ql \fi720\li0\ri0\nowidctlpar\tx0\faauto\rin0\lin0\itap0\pararsid4403757 {\f1\fs20\insrsid1928404 For this package to work under RunUO 1.0 Final, follow the directions below after the Installation directions. +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\f1\fs20\insrsid15728713 +\par }{\f1\fs20\insrsid939626 \tab This package }{\b\f1\fs20\insrsid939626 doesn't require any existing script modifications.}{\f1\fs20\insrsid939626 (The patches are optional!) +\par +\par \tab I am soliciting any and all feedback: suggestions, coding style suggestions, bugs, and anything else! Don't be }{\f1\fs20\insrsid10444852 shy;}{\f1\fs20\insrsid939626 I can take well formed }{\f1\fs20\insrsid10444852 criticis}{ +\f1\fs20\insrsid939626 m. +\par +\par }{\b\f1\fs20\insrsid939626 Commands: +\par }{\b\f1\fs20\insrsid673505 +\par \tab [TownHouses}{\f1\fs20\insrsid673505 : View a list of all TownHouses and access their menus here. You can also create new TownHouses from this menu. +\par +\par \tab }{\b\f1\fs20\insrsid673505 [TownHouseErrors, [the}{\f1\fs20\insrsid673505 : View or report errors in the TownHouse system. Very similar to previous Error systems in Chat and TownHouses.}{\f1\fs20\insrsid673505\charrsid673505 +\par }{\f1\fs20\insrsid939626 +\par \tab }{\b\f1\fs20\insrsid939626\charrsid673505 "Create rental contract"}{\f1\fs20\insrsid939626 : If allowed, players can use this spoken command in their home to begin the setup for renting portions of their home. +\par +\par \tab "}{\b\f1\fs20\insrsid939626\charrsid673505 Check house rent"}{\f1\fs20\insrsid939626 : Players can check to see how long before their rental cycle expires by speaking these words while in their home. At the end of the cycle, if the rent is }{ +\f1\fs20\insrsid10444852 reoccurring}{\f1\fs20\insrsid939626 , the bank will attempt to take gold automatically. If not }{\f1\fs20\insrsid10444852 reoccurring}{\f1\fs20\insrsid939626 , the bank will pack up the pla +yer's belongings and put the home back up for rent. +\par +\par \tab }{\b\f1\fs20\insrsid939626\charrsid673505 "Check storage"}{\f1\fs20\insrsid939626 +: While usable by all home owners, this command is especially useful for renters. It will detail how many lockdowns and secures are used by their rental property, and include those figures in how much storage they have available. +\par }{\b\f1\fs20\insrsid939626 +\par Features included in this system:}{\f1\fs20\insrsid939626 Turn static buildings into homes, turn anything into a home, supports odd shaped homes, allows players to rent out their homes, easy to install, easy to use, and much more! +\par +\par }{\b\f1\fs20\insrsid939626 Details:}{\f1\fs20\insrsid939626 +\par +\par \tab With this system you can not only sell static buildings to players, you can sell or rent any portion of land in any shape and size! Nothing like owning Blackthorn's Castle, or the center of the Hedge Maze! Good way to give many of the never-used + areas of the game some life. +\par +\par \tab These houses come with all the housing features we've come to love: lock downs, secures, private, public, vendors. In fact, it's derived from RunUO's own housing system! Setup is fairly simple, with a step-by-step menu to +guide you through the process. +\par +\par \tab Players can also rent out their property, as long as they own it! By speaking the "Create rental contract" command in their home, players can rent out unused rooms and make a little bit of cash on the side. This also work +s with classic and custom houses! You can also require players to have a renter's license to rent property, which you will have to add for sale. You can find that option in Misc/General.cs right near the top. +\par +\par \tab To begin}{\f1\fs20\insrsid11010391 as a staff member, use the command [TownHouses}{\f1\fs20\insrsid939626 . }{\f1\fs20\insrsid11010391 Here you can create a new TownHouse through the setup menu. This menu }{\f1\fs20\insrsid939626 +takes you step-by-step through the many different features you can apply to the home, with detailed explanations at every level. +\par +\par \tab In brief, here's all the neat things yo +u can customize with the home: lockdowns, secures, the area and floors, the sign location, ban location, whether or not to include items in the area with the purchase, restrictions on who can purchase the home, how much to charge, whether it is a purchase + or rent, automated price suggestion. +\par +\par \tab While the home is owned, you can change its price, lockdowns, secures, its area, and ownership requirements through the now invisible TownHouseSign. Just in case you need to adjust the home! +\par +\par }{\b\f1\fs20\insrsid939626 Installing:}{\f1\fs20\insrsid939626 +\par {\listtext\pard\plain\f1\fs20\insrsid939626 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls1\rin0\lin720\itap0\pararsid939626 {\f1\fs20\insrsid939626 Remove any older versions of TownHouses. +\par {\listtext\pard\plain\f1\fs20\insrsid939626 \hich\af1\dbch\af0\loch\f1 -\tab}Remove any older version of Utilities}{\f1\fs20\insrsid3087438 (Now obsolete)}{\f1\fs20\insrsid939626 +\par {\listtext\pard\plain\f1\fs20\insrsid939626 \hich\af1\dbch\af0\loch\f1 -\tab}Place the T}{\f1\fs20\insrsid3087438 ownHouses }{\f1\fs20\insrsid939626 into a custom folder! +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\b\f1\fs20\insrsid939626 +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid11150156 {\b\f1\fs20\insrsid11150156 Enabling RunUO 1.0 Final:}{\f1\fs20\insrsid11150156 +\par +\par {\listtext\pard\plain\f1\fs20\insrsid11536214 \hich\af1\dbch\af0\loch\f1 -\tab}}\pard \ql \fi-360\li720\ri0\nowidctlpar\jclisttab\tx720\faauto\ls3\rin0\lin720\itap0\pararsid11150156 {\f1\fs20\insrsid11536214 In the main TownHouses}{ +\f1\fs20\insrsid11150156 directory, open up RUOVersion.cs +\par {\listtext\pard\plain\f1\fs20\insrsid11150156 \hich\af1\dbch\af0\loch\f1 -\tab}Follow the directions at the top of this file. +\par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\b\f1\fs20\insrsid11150156 +\par }{\b\f1\fs20\insrsid939626 Planned Features:}{\f1\fs20\insrsid939626 +\par +\par }{\b\f1\fs20\insrsid939626 Bugs Reported:}{\f1\fs20\insrsid939626 +\par }{\b\f1\fs20\insrsid939626 +\par Contact Info:}{\f1\fs20\insrsid939626 Send me an email day or night (Though I will likely be sleeping at night)! kmwill23@hotmail.com}{\b\f1\fs20\insrsid939626 +\par }} \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/BaseXmlSpawner.cs b/Scripts/Customs/XML Spawner/BaseXmlSpawner.cs new file mode 100644 index 0000000..0b7f559 --- /dev/null +++ b/Scripts/Customs/XML Spawner/BaseXmlSpawner.cs @@ -0,0 +1,10782 @@ + +using System; +using System.Data; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using System.Globalization; +using Server.Accounting; +using Server.Engines.XmlSpawner2; + +namespace Server.Mobiles +{ + public delegate void XmlGumpCallback(Mobile from, object invoker, string response); + + public class BaseXmlSpawner + { + #region Initialization + + private static ArrayList ProtectedPropertiesList = new ArrayList(); + + private class ProtectedProperty + { + public Type ObjectType; + public string Name; + + public ProtectedProperty(Type type, string name) + { + ObjectType = type; + Name = name; + } + } + + public static bool IsProtected(Type type, string property) + { + if (type == null || property == null) return false; + + // search through the protected list for a matching entry + foreach (ProtectedProperty p in ProtectedPropertiesList) + { + if ((p.ObjectType == type || type.IsSubclassOf(p.ObjectType)) && (property.ToLower() == p.Name.ToLower())) + { + return true; + } + } + + return false; + } + + public static void Initialize() + { + // register restricted properties that cannot be set by the spawner + ProtectedPropertiesList.Add(new ProtectedProperty(typeof(Mobile), "accesslevel")); + ProtectedPropertiesList.Add(new ProtectedProperty(typeof(Item), "stafflevel")); + } + + #endregion + + #region Type support + + [Flags] + public enum KeywordFlags + { + HoldSpawn = 0x01, + HoldSequence = 0x02, + Serialize = 0x04, + Defrag = 0x08, + + } + + public class TypeInfo + { + public ArrayList plist = new ArrayList(); // hold propertyinfo list + public Type t; + } + + // ------------------------------------------------------------- + // Modified from Beta-36 Properties.cs code + // ------------------------------------------------------------- + + private static Type typeofTimeSpan = typeof(TimeSpan); + private static Type typeofParsable = typeof(ParsableAttribute); + private static Type typeofCustomEnum = typeof(CustomEnumAttribute); + + private static bool IsParsable(Type t) + { + return (t == typeofTimeSpan || t.IsDefined(typeofParsable, false)); + } + + private static Type[] m_ParseTypes = new Type[] { typeof(string) }; + private static object[] m_ParseParams = new object[1]; + + private static object Parse(object o, Type t, string value) + { + MethodInfo method = t.GetMethod("Parse", m_ParseTypes); + + m_ParseParams[0] = value; + + return method.Invoke(o, m_ParseParams); + } + + private static Type[] m_NumericTypes = new Type[] + { + typeof( Byte ), typeof( SByte ), + typeof( Int16 ), typeof( UInt16 ), + typeof( Int32 ), typeof( UInt32 ), + typeof( Int64 ), typeof( UInt64 ), typeof( Server.Serial ) + }; + + public static bool IsNumeric(Type t) + { + return (Array.IndexOf(m_NumericTypes, t) >= 0); + } + + private static Type typeofType = typeof(Type); + + private static bool IsType(Type t) + { + return (t == typeofType); + } + + private static Type typeofChar = typeof(Char); + + private static bool IsChar(Type t) + { + return (t == typeofChar); + } + + private static Type typeofString = typeof(String); + + private static bool IsString(Type t) + { + return (t == typeofString); + } + + private static bool IsEnum(Type t) + { + return t.IsEnum; + } + + private static bool IsCustomEnum(Type t) + { + return t.IsDefined(typeofCustomEnum, false); + } + + // ------------------------------------------------------------- + // End modified Beta-36 Properties.cs code + // ------------------------------------------------------------- + + public static string ParsedType(Type type) + { + if (type == null) return null; + + string s = type.ToString(); + + if (s == null) return null; + + string[] args = s.Split(Type.Delimiter); + + if (args != null && args.Length > 0) + { + return args[args.Length - 1]; + } + else + { + return null; + } + } + + public static bool CheckType(object o, string typename) + { + if (typename == null || o == null) return false; + + // test the type + Type objecttype = o.GetType(); + + Type targettype = null; + + try + { + targettype = SpawnerType.GetType(typename); + } + catch { } + + if (objecttype != null && targettype != null && (objecttype.Equals(targettype) || objecttype.IsSubclassOf(targettype))) + { + return true; + + } + + return false; + + } + + private enum typeKeyword + { + SET, + SETVAR, + SETONTRIGMOB, + SETONCARRIED, + SETONSPAWN, + SETONSPAWNENTRY, + SETONNEARBY, + SETONPETS, + SETONMOB, + SETONTHIS, + SETONPARENT, + SETACCOUNTTAG, + GIVE, + TAKE, + GUMP, + TAKEBYTYPE, + BROWSER, + SENDMSG, + SENDASCIIMSG, + MUSIC, + RESURRECT, + POISON, + DAMAGE, + EFFECT, + MEFFECT, + SOUND, + WAITUNTIL, + WHILE, + IF, + GOTO, + CAST, + BCAST, + BSOUND, + COMMAND, + SPAWN, + DESPAWN + } + + private enum typemodKeyword + { + MUSIC, + POISON, + DAMAGE, + EFFECT, + BOLTEFFECT, + MEFFECT, + PEFFECT, + SOUND, + SAY, + SPEECH, + ANIMATE, + OFFSET, + ADD, + MSG, + ASCIIMSG, + SENDMSG, + SENDASCIIMSG, + BCAST, + EQUIP, + UNEQUIP, + DELETE, + KILL, + ATTACH + } + + private enum itemKeyword + { + ARMOR, + WEAPON, + JARMOR, + JWEAPON, + SHIELD, + SARMOR, + LOOT, + JEWELRY, + POTION, + SCROLL, + NECROSCROLL, + LOOTPACK, + TAKEN, + GIVEN, + ITEM, + MULTIADDON + } + + private enum valueKeyword + { + GET, + GETVAR, + GETONMOB, + GETONCARRIED, + GETONTRIGMOB, + GETONNEARBY, + GETONSPAWN, + GETONPARENT, + GETONTHIS, + GETONTAKEN, + GETONGIVEN, + GETFROMFILE, + GETACCOUNTTAG, + AMOUNTCARRIED, + RND, + RNDBOOL, + RNDLIST, + RNDSTRLIST, + TRIGSKILL, + PLAYERSINRANGE, + MY, + RANDNAME + } + + private enum valuemodKeyword + { + GET, + GETONMOB, + GETVAR, + GETONCARRIED, + GETONTRIGMOB, + GETONNEARBY, + GETONSPAWN, + GETONPARENT, + GETONTHIS, + GETONTAKEN, + GETONGIVEN, + GETFROMFILE, + GETACCOUNTTAG, + AMOUNTCARRIED, + RND, + RNDBOOL, + RNDLIST, + RNDSTRLIST, + MUL, + INC, + MOB, + TRIGMOB, + MY, + TRIGSKILL, + PLAYERSINRANGE, + RANDNAME + } + + #endregion + + #region Static variable declarations + + // name of mobile used to issue commands via the COMMAND keyword. The accesslevel of the mobile will determine + // the accesslevel of commands that can be issued. + // if this is null, then COMMANDS can only be issued when triggered by players of the appropriate accesslevel + private static string CommandMobileName = null; + + private static Hashtable typeKeywordHash; + private static Hashtable typemodKeywordHash; + private static Hashtable valueKeywordHash; + private static Hashtable valuemodKeywordHash; + private static Hashtable itemKeywordHash; + + private static char[] slashdelim = new char[1] { '/' }; + private static char[] commadelim = new char[1] { ',' }; + private static char[] spacedelim = new char[1] { ' ' }; + private static char[] semicolondelim = new char[1] { ';' }; + + #endregion + + #region Keywords + + public static bool IsValueKeyword(string str) + { + if (str == null) return false; + + if (valueKeywordHash == null) InitializeHash(); + + return valueKeywordHash.Contains(str); + } + + public static bool IsValuemodKeyword(string str) + { + if (str == null) return false; + + if (valuemodKeywordHash == null) InitializeHash(); + + return valuemodKeywordHash.Contains(str); + } + + public static bool IsSpecialItemKeyword(string typeName) + { + if (typeName == null || typeName.Length < 1 || !Char.IsUpper(typeName[0])) return false; + + if (itemKeywordHash == null) InitializeHash(); + + return itemKeywordHash.Contains(typeName); + } + + public static bool IsTypeKeyword(string typeName) + { + if (typeName == null || typeName.Length < 1 || !Char.IsUpper(typeName[0])) return false; + + if (typeKeywordHash == null) InitializeHash(); + + return (typeKeywordHash.Contains(typeName)); + } + + public static bool IsTypemodKeyword(string typeName) + { + if (typeName == null || typeName.Length < 1 || !Char.IsUpper(typeName[0])) return false; + + if (typemodKeywordHash == null) InitializeHash(); + + return (typemodKeywordHash.Contains(typeName)); + } + + public static bool IsTypeOrItemKeyword(string typeName) + { + if (typeName == null || typeName.Length < 1 || !Char.IsUpper(typeName[0])) return false; + + if (typeKeywordHash == null || itemKeywordHash == null) InitializeHash(); + + return (typeKeywordHash.Contains(typeName) || itemKeywordHash.Contains(typeName)); + } + + private static void AddTypeKeyword(string name) + { + typeKeywordHash.Add(name, (typeKeyword)Enum.Parse(typeof(typeKeyword), name)); + } + + private static void AddTypemodKeyword(string name) + { + typemodKeywordHash.Add(name, (typemodKeyword)Enum.Parse(typeof(typemodKeyword), name)); + } + + private static void AddValueKeyword(string name) + { + valueKeywordHash.Add(name, (valueKeyword)Enum.Parse(typeof(valueKeyword), name)); + } + + private static void AddValuemodKeyword(string name) + { + valuemodKeywordHash.Add(name, (valuemodKeyword)Enum.Parse(typeof(valuemodKeyword), name)); + } + + private static void AddItemKeyword(string name) + { + itemKeywordHash.Add(name, (itemKeyword)Enum.Parse(typeof(itemKeyword), name)); + } + + public static void RemoveKeyword(string name) + { + if (name == null) return; + + name = name.Trim().ToUpper(); + + if (IsTypeKeyword(name)) + { + typeKeywordHash.Remove(name); + } + if (IsTypemodKeyword(name)) + { + typemodKeywordHash.Remove(name); + } + if (IsValueKeyword(name)) + { + valueKeywordHash.Remove(name); + } + if (IsValuemodKeyword(name)) + { + valuemodKeywordHash.Remove(name); + } + if (IsSpecialItemKeyword(name)) + { + itemKeywordHash.Remove(name); + } + } + + + public static void InitializeHash() + { + // set up the keyword hash tables + typeKeywordHash = new Hashtable(); + typemodKeywordHash = new Hashtable(); + itemKeywordHash = new Hashtable(); + valueKeywordHash = new Hashtable(); + valuemodKeywordHash = new Hashtable(); + + // Type keywords + // spawned as primary objects + AddTypeKeyword("SET"); + AddTypeKeyword("SETVAR"); + AddTypeKeyword("SETONTRIGMOB"); + AddTypeKeyword("SETONCARRIED"); + AddTypeKeyword("SETONNEARBY"); + AddTypeKeyword("SETONPETS"); + AddTypeKeyword("SETONSPAWN"); + AddTypeKeyword("SETONSPAWNENTRY"); + AddTypeKeyword("SETONMOB"); + AddTypeKeyword("SETONTHIS"); + AddTypeKeyword("SETONPARENT"); + AddTypeKeyword("SETACCOUNTTAG"); + AddTypeKeyword("GIVE"); + AddTypeKeyword("TAKE"); + AddTypeKeyword("GUMP"); + AddTypeKeyword("TAKEBYTYPE"); + AddTypeKeyword("BROWSER"); + AddTypeKeyword("SENDMSG"); + AddTypeKeyword("SENDASCIIMSG"); + AddTypeKeyword("RESURRECT"); + AddTypeKeyword("POISON"); + AddTypeKeyword("DAMAGE"); + AddTypeKeyword("SOUND"); + AddTypeKeyword("EFFECT"); + AddTypeKeyword("MEFFECT"); + AddTypeKeyword("MUSIC"); + AddTypeKeyword("WAITUNTIL"); + AddTypeKeyword("WHILE"); + AddTypeKeyword("IF"); + AddTypeKeyword("GOTO"); + AddTypeKeyword("CAST"); + AddTypeKeyword("BCAST"); + AddTypeKeyword("BSOUND"); + AddTypeKeyword("COMMAND"); + AddTypeKeyword("SPAWN"); + AddTypeKeyword("DESPAWN"); + + // Typemod keywords + // used in place of properties as modifiers of the primary object type + AddTypemodKeyword("MUSIC"); + AddTypemodKeyword("SOUND"); + AddTypemodKeyword("POISON"); + AddTypemodKeyword("DAMAGE"); + AddTypemodKeyword("EFFECT"); + AddTypemodKeyword("BOLTEFFECT"); + AddTypemodKeyword("MEFFECT"); + AddTypemodKeyword("PEFFECT"); + AddTypemodKeyword("SAY"); + AddTypemodKeyword("SPEECH"); + AddTypemodKeyword("ANIMATE"); + AddTypemodKeyword("OFFSET"); + AddTypemodKeyword("MSG"); + AddTypemodKeyword("ASCIIMSG"); + AddTypemodKeyword("SENDMSG"); + AddTypemodKeyword("SENDASCIIMSG"); + AddTypemodKeyword("BCAST"); + AddTypemodKeyword("ADD"); + AddTypemodKeyword("EQUIP"); + AddTypemodKeyword("UNEQUIP"); + AddTypemodKeyword("DELETE"); + AddTypemodKeyword("KILL"); + AddTypemodKeyword("ATTACH"); + + // Value keywords + // used in property tests + AddValueKeyword("RND"); + AddValueKeyword("RNDBOOL"); + AddValueKeyword("RNDLIST"); + AddValueKeyword("RNDSTRLIST"); + AddValueKeyword("MY"); + AddValueKeyword("GET"); + AddValueKeyword("GETVAR"); + AddValueKeyword("GETONMOB"); + AddValueKeyword("GETONCARRIED"); + AddValueKeyword("AMOUNTCARRIED"); + AddValueKeyword("GETONTRIGMOB"); + AddValueKeyword("GETONNEARBY"); + AddValueKeyword("GETONSPAWN"); + AddValueKeyword("GETONPARENT"); + AddValueKeyword("GETONTHIS"); + AddValueKeyword("GETONTAKEN"); + AddValueKeyword("GETONGIVEN"); + AddValueKeyword("GETFROMFILE"); + AddValueKeyword("GETACCOUNTTAG"); + AddValueKeyword("RANDNAME"); + AddValueKeyword("TRIGSKILL"); + AddValueKeyword("PLAYERSINRANGE"); + + // Valuemod keywords + // used as values in property assignments + AddValuemodKeyword("RND"); + AddValuemodKeyword("RNDBOOL"); + AddValuemodKeyword("RNDLIST"); + AddValuemodKeyword("RNDSTRLIST"); + AddValuemodKeyword("MY"); + AddValuemodKeyword("GET"); + AddValuemodKeyword("GETVAR"); + AddValuemodKeyword("GETONMOB"); + AddValuemodKeyword("GETONCARRIED"); + AddValuemodKeyword("AMOUNTCARRIED"); + AddValuemodKeyword("GETONTRIGMOB"); + AddValuemodKeyword("GETONNEARBY"); + AddValuemodKeyword("GETONSPAWN"); + AddValuemodKeyword("GETONPARENT"); + AddValuemodKeyword("GETONTHIS"); + AddValuemodKeyword("GETONTAKEN"); + AddValuemodKeyword("GETONGIVEN"); + AddValuemodKeyword("GETFROMFILE"); + AddValuemodKeyword("GETACCOUNTTAG"); + AddValuemodKeyword("MUL"); + AddValuemodKeyword("INC"); + AddValuemodKeyword("MOB"); + AddValuemodKeyword("TRIGMOB"); + AddValuemodKeyword("RANDNAME"); + AddValuemodKeyword("TRIGSKILL"); + AddValuemodKeyword("PLAYERSINRANGE"); + + // Item keywords + // these can be spawned like type keywords, or added to containers like items + AddItemKeyword("ARMOR"); + AddItemKeyword("WEAPON"); + AddItemKeyword("JARMOR"); + AddItemKeyword("LOOT"); + AddItemKeyword("JWEAPON"); + AddItemKeyword("SARMOR"); + AddItemKeyword("SHIELD"); + AddItemKeyword("JEWELRY"); + AddItemKeyword("POTION"); + AddItemKeyword("SCROLL"); + AddItemKeyword("NECROSCROLL"); + AddItemKeyword("LOOTPACK"); + AddItemKeyword("TAKEN"); + AddItemKeyword("GIVEN"); + AddItemKeyword("ITEM"); + AddItemKeyword("MULTIADDON"); + + } + + #endregion + + #region KeywordTag + + public class KeywordTag + { + + public KeywordFlags Flags; + public int Type; + private Timer m_Timer; + public DateTime m_End; + public DateTime m_TimeoutEnd; + public TimeSpan m_Delay; + public TimeSpan m_Timeout; + private XmlSpawner m_Spawner; + public string m_Condition; + public int m_Goto; + public bool Deleted = false; + public int Serial = -1; + public Mobile m_TrigMob; + public string Typename; + + public KeywordTag(string typename, XmlSpawner spawner) + : this(typename, spawner, -1) + { + } + + public KeywordTag(string typename, XmlSpawner spawner, int type) + : this(typename, spawner, type, TimeSpan.Zero, TimeSpan.Zero, null, -1) + { + } + + public KeywordTag(string typename, XmlSpawner spawner, TimeSpan delay, string condition, int gotogroup) + : this(typename, spawner, 0, delay, TimeSpan.Zero, condition, gotogroup) + { + } + + public KeywordTag(string typename, XmlSpawner spawner, TimeSpan delay, TimeSpan timeout, string condition, int gotogroup) + : this(typename, spawner, 0, delay, timeout, condition, gotogroup) + { + } + + public KeywordTag(string typename, XmlSpawner spawner, int type, TimeSpan delay, TimeSpan timeout, string condition, int gotogroup) + { + Type = type; + m_Delay = delay; + m_Timeout = timeout; + m_TimeoutEnd = DateTime.Now + timeout; + m_Spawner = spawner; + m_Condition = condition; + m_Goto = gotogroup; + + Typename = typename; + // add the tag to the list + if (spawner != null && !spawner.Deleted) + { + m_TrigMob = spawner.TriggerMob; + if (spawner.m_KeywordTagList == null) + { + spawner.m_KeywordTagList = new ArrayList(); + } + // calculate the serial index of the new tag by adding one to the last one if there is one, otherwise just reset to 0 + if (spawner.m_KeywordTagList.Count > 0) + Serial = ((KeywordTag)(spawner.m_KeywordTagList[spawner.m_KeywordTagList.Count - 1])).Serial + 1; + else + Serial = 0; + + spawner.m_KeywordTagList.Add(this); + + switch (type) + { + case 0: // WAIT timer type + // start up the timer + DoTimer(delay, m_Delay, condition, gotogroup); + // and put spawning on hold until it is done + //spawner.OnHold = true; + Flags |= KeywordFlags.HoldSpawn; + Flags |= KeywordFlags.Serialize; + + break; + case 1: // GUMP type + + break; + case 2: // GOTO type + Flags |= KeywordFlags.HoldSequence; + Flags |= KeywordFlags.Serialize; + + break; + default: + // dont do anything for other types + Flags |= KeywordFlags.Defrag; + break; + } + } + } + + + public void Delete() + { + + // release any hold on spawning that might have been in place + //if(m_Spawner != null && !m_Spawner.Deleted && Type == 0) + //{ + //m_Spawner.OnHold = false; + //m_Spawner.HoldSequence = false; + //} + + // and stop all timers + if (m_Timer != null && Type == 0) + { + m_Timer.Stop(); + } + + this.Deleted = true; + + // and remove it from the list + RemoveFromTagList(m_Spawner, this); + + } + + + private void DoTimer(TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) + { + m_End = DateTime.Now + delay; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = new KeywordTimer(m_Spawner, this, delay, repeatdelay, condition, gotogroup); + m_Timer.Start(); + } + + public void Serialize(GenericWriter writer) + { + writer.Write((int)1); // version + // Version 1 + writer.Write((int)Flags); + // Version 0 + writer.Write(m_Spawner); + writer.Write(Type); + writer.Write(Serial); + if (Type == 0) + { + // save any timer information + writer.Write(m_End - DateTime.Now); + writer.Write(m_Delay); + writer.Write(m_Condition); + writer.Write(m_Goto); + writer.Write(m_TimeoutEnd - DateTime.Now); + writer.Write(m_Timeout); + writer.Write(m_TrigMob); + } + } + public void Deserialize(GenericReader reader) + { + + int version = reader.ReadInt(); + switch (version) + { + case 1: + Flags = (KeywordFlags)reader.ReadInt(); + goto case 0; + case 0: + m_Spawner = (XmlSpawner)reader.ReadItem(); + Type = reader.ReadInt(); + Serial = reader.ReadInt(); + if (Type == 0) + { + // get any timer info + TimeSpan delay = reader.ReadTimeSpan(); + m_Delay = reader.ReadTimeSpan(); + m_Condition = reader.ReadString(); + m_Goto = reader.ReadInt(); + + TimeSpan timeoutdelay = reader.ReadTimeSpan(); + m_TimeoutEnd = DateTime.Now + timeoutdelay; + m_Timeout = reader.ReadTimeSpan(); + m_TrigMob = reader.ReadMobile(); + + this.DoTimer(delay, m_Delay, m_Condition, m_Goto); + } + break; + } + } + + // added the timer that begins on spawning tmp keywords + private class KeywordTimer : Timer + { + private KeywordTag m_Tag; + private XmlSpawner m_Spawner; + private string m_Condition; + private int m_Goto; + private TimeSpan m_Repeatdelay; + + public KeywordTimer(XmlSpawner spawner, KeywordTag tag, TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) + : base(delay) + { + Priority = TimerPriority.OneSecond; + m_Tag = tag; + m_Spawner = spawner; + m_Condition = condition; + m_Goto = gotogroup; + m_Repeatdelay = repeatdelay; + } + + protected override void OnTick() + { + + // if a condition is available then test it + if (m_Condition != null && m_Condition.Length > 0 && m_Spawner != null && m_Spawner.Running) + { + // if the test is valid then terminate the timer + string status_str; + Mobile trigmob = null; + + if (m_Spawner != null && !m_Spawner.Deleted) + { + trigmob = m_Spawner.TriggerMob; + } + + if (TestItemProperty(m_Spawner, m_Spawner, m_Condition, trigmob, out status_str)) + { + + // release the hold on spawning + //m_Spawner.OnHold = false; + + // spawn the designated subgroup if specified + if (m_Goto >= 0 && m_Spawner != null && !m_Spawner.Deleted) + { + // set the trigmob to the mob that originally triggered the wait keyword + if (m_Tag != null) + m_Spawner.TriggerMob = m_Tag.m_TrigMob; + + // spawn the subgroup + m_Spawner.SpawnSubGroup(m_Goto); + + // advance sequential spawning to that group + //m_Spawner.SequentialSpawn = m_Goto; + } + + // get rid of the temporary tag + if (m_Tag != null && !m_Tag.Deleted) + { + m_Tag.Delete(); + } + + } + else + { + + // otherwise restart it and keep on holding + if (m_Tag != null && !m_Tag.Deleted) + { + //if(m_Tag.m_Timeout > TimeSpan.Zero) + // check the timeout if applicable + if (m_Tag.m_Timeout > TimeSpan.Zero && m_Tag.m_TimeoutEnd < DateTime.Now) + { + // release the hold on spawning and delete the tag + m_Tag.Delete(); + + //m_Spawner.OnHold = false; + + } + else + { + m_Tag.DoTimer(m_Repeatdelay, m_Repeatdelay, m_Condition, m_Goto); + } + } + } + } + else + { + + // and terminate the timer + if (m_Tag != null && !m_Tag.Deleted) + { + m_Tag.Delete(); + } + + // release the hold on spawning + //m_Spawner.OnHold = false; + + } + } + } + } + + public static string TagInfo(KeywordTag tag) + { + if (tag != null) + return (String.Format("{0} : type={1} cond={2} go={3} del={4} end={5}", tag.Typename, tag.Type, tag.m_Condition, tag.m_Goto, tag.m_Delay, tag.m_End)); + else + return null; + } + + public static void RemoveFromTagList(XmlSpawner spawner, KeywordTag tag) + { + for (int i = 0; i < spawner.m_KeywordTagList.Count; i++) + { + if (tag == spawner.m_KeywordTagList[i]) + { + spawner.m_KeywordTagList.RemoveAt(i); + break; + } + } + } + + public static KeywordTag GetFromTagList(XmlSpawner spawner, int serial) + { + for (int i = 0; i < spawner.m_KeywordTagList.Count; i++) + { + if (serial == ((KeywordTag)spawner.m_KeywordTagList[i]).Serial) + { + return ((KeywordTag)spawner.m_KeywordTagList[i]); + } + } + return (null); + } + + #endregion + + #region Property parsing methods + + // ------------------------------------------------------------- + // Begin modified code from Beta-36 Properties.cs + // Added support for nested attribute and array access + // ------------------------------------------------------------- + private static string InternalGetValue(object o, PropertyInfo p, int index) + { + Type type = p.PropertyType; + object value = null; + + if (type.IsPrimitive) + { + value = p.GetValue(o, null); + } + else if ((type.GetInterface("IList") != null) && index >= 0) + { + try + { + object arrayvalue = p.GetValue(o, null); + value = ((IList)arrayvalue)[index]; + } + catch { } + } + else + { + value = p.GetValue(o, null); + } + + string toString; + + if (value == null) + toString = "(-null-)"; + else if (IsNumeric(type)) + toString = String.Format("{0} (0x{0:X})", value); + else if (IsChar(type)) + toString = String.Format("'{0}' ({1} [0x{1:X}])", value, (int)value); + else if (IsString(type)) + toString = String.Format("\"{0}\"", value); + else + toString = value.ToString(); + + return String.Format("{0} = {1}", p.Name, toString); + } + + public static bool IsItem(Type type) + { + return (type != null && (type == typeof(Item) || type.IsSubclassOf(typeof(Item)))); + } + + public static bool IsMobile(Type type) + { + return (type != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile)))); + } + + + public static string ConstructFromString(PropertyInfo p, Type type, object obj, string value, ref object constructed) + { + object toSet; + + if (value == "(-null-)" && !type.IsValueType) + value = null; + + if (IsEnum(type)) + { + + try + { + toSet = Enum.Parse(type, value, true); + } + catch + { + return "That is not a valid enumeration member."; + } + } + else if (IsCustomEnum(type)) + { + + try + { + + MethodInfo info = p.PropertyType.GetMethod("Parse", new Type[] { typeof(string) }); + + if (info != null) + toSet = info.Invoke(null, new object[] { value }); + else if (p.PropertyType == typeof(Enum) || p.PropertyType.IsSubclassOf(typeof(Enum))) + toSet = Enum.Parse(p.PropertyType, value, false); + else + toSet = null; + + if (toSet == null) + return "That is not a valid custom enumeration member."; + + } + catch + { + return "That is not a valid custom enumeration member."; + } + } + else if (IsType(type)) + { + + try + { + toSet = ScriptCompiler.FindTypeByName(value); + + if (toSet == null) + return "No type with that name was found."; + } + catch + { + return "No type with that name was found."; + } + } + else if (IsParsable(type)) + { + + try + { + toSet = Parse(obj, type, value); + } + catch + { + return "That is not properly formatted."; + } + } + else if (value == null) + { + toSet = null; + } + else if (value.StartsWith("0x") && IsNumeric(type)) + { + try + { + toSet = Convert.ChangeType(Convert.ToUInt64(value.Substring(2), 16), type); + } + catch + { + return "That is not properly formatted. not convertible."; + } + } + else if (value.StartsWith("0x") && (IsItem(type) || IsMobile(type))) + { + try + { + // parse out the mobile or item name from the value string + int ispace = value.IndexOf(' '); + string valstr = value.Substring(2); + if (ispace > 0) + { + valstr = value.Substring(2, ispace - 2); + } + + toSet = World.FindEntity(Convert.ToInt32(valstr, 16)); + + // now check to make sure the object returned is consistent with the type + if (!((toSet is Mobile && IsMobile(type)) || (toSet is Item && IsItem(type)))) + { + return "Item/Mobile type mismatch. cannot assign."; + } + } + catch + { + return "That is not properly formatted. not convertible."; + } + } + else if ((type.GetInterface("IList") != null)) + { + try + { + object arrayvalue = p.GetValue(obj, null); + + object po = ((IList)arrayvalue)[0]; + + Type atype = po.GetType(); + + toSet = Parse(obj, atype, value); + } + catch + { + return "That is not properly formatted."; + } + } + else + { + try + { + toSet = Convert.ChangeType(value, type); + } + catch + { + return "That is not properly formatted."; + } + } + + constructed = toSet; + + return null; + } + + + public static string InternalSetValue(Mobile from, object o, PropertyInfo p, string value, bool shouldLog, int index) + { + object toSet = null; + Type ptype = p.PropertyType; + + string result = ConstructFromString(p, p.PropertyType, o, value, ref toSet); + + if (result != null) + return result; + + try + { + if (shouldLog) + CommandLogging.LogChangeProperty(from, o, p.Name, value); + + if (ptype.IsPrimitive) + { + p.SetValue(o, toSet, null); + } + else if ((ptype.GetInterface("IList") != null) && index >= 0) + { + try + { + object arrayvalue = p.GetValue(o, null); + ((IList)arrayvalue)[index] = toSet; + } + catch { } + } + else + { + p.SetValue(o, toSet, null); + } + + return "Property has been set."; + } + catch + { + return "An exception was caught, the property may not be set."; + } + } + + // set property values with support for nested attributes + public static string SetPropertyValue(XmlSpawner spawner, object o, string name, string value) + { + if (o == null) + { + return "Null object"; + } + + Type ptype = null; + object po = null; + Type type = o.GetType(); + + PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + // parse the strings of the form property.attribute into two parts + // first get the property + string[] arglist = ParseString(name, 2, "."); + + + string propname = arglist[0]; + + string[] keywordargs = ParseString(propname, 4, ","); + + // check for special keywords + if (keywordargs[0] == "ATTACHMENT") + { + if (keywordargs.Length < 4) + { + return "Invalid ATTACHMENT format"; + } + // syntax is ATTACHMENT,type,name,propname + + string apropname = keywordargs[3]; + string aname = keywordargs[2]; + Type attachtype = SpawnerType.GetType(keywordargs[1]); + + // allow empty string specifications to be used to indicate a null string which will match any name + if (aname == "") aname = null; + + ArrayList attachments = XmlAttach.FindAttachments(o, attachtype, aname); + + if (attachments != null && attachments.Count > 0) + { + // change the object, object type, and propname to refer to the attachment + o = attachments[0]; + propname = apropname; + + if (o == null) + { + return "Null object"; + } + + type = o.GetType(); + props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + } + else + return "Attachment not found"; + + } + else if (keywordargs[0] == "SKILL") + { + if (keywordargs.Length < 2) + { + return "Invalid SKILL format"; + } + bool found = true; + try + { + SkillName skillname = (SkillName)Enum.Parse(typeof(SkillName), keywordargs[1], true); + if (o is Mobile) + { + + Skill skill = ((Mobile)o).Skills[skillname]; + + skill.Base = double.Parse(value); + + return "Property has been set."; + } + else + return "Object is not mobile"; + } + catch { found = false; } + + if (!found) + return "Invalid SKILL reference."; + } + else if (keywordargs[0] == "STEALABLE") + { + + bool found = true; + try + { + if (o is Item) + { + + ItemFlags.SetStealable(o as Item, bool.Parse(value)); + + return "Property has been set."; + } + else + return "Object is not an item"; + } + catch { found = false; } + + if (!found) + return "Invalid Stealable assignment."; + } + + + // do a bit of parsing to handle array references + string[] arraystring = propname.Split('['); + int index = 0; + if (arraystring.Length > 1) + { + // parse the property name from the indexing + propname = arraystring[0]; + + // then parse to get the index value + string[] arrayvalue = arraystring[1].Split(']'); + + if (arrayvalue.Length > 0) + { + try + { + index = int.Parse(arrayvalue[0]); + } + catch { } + } + } + + if (arglist.Length == 2) + { + PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + + if (plookup != null) + { + + //if ( !plookup.CanWrite ) + //return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, propname)) + return "Property is protected."; + + ptype = plookup.PropertyType; + po = plookup.GetValue(o, null); + + // now set the nested attribute using the new property list + return (SetPropertyValue(spawner, po, arglist[1], value)); + } + else + { + // is a nested property with attributes so first get the property + foreach (PropertyInfo p in props) + { + if (Insensitive.Equals(p.Name, propname)) + { + //CPA pattr = Properties.GetCPA( p ); + + //if ( pattr == null ) + //return "Property not found."; + + //if ( !p.CanWrite ) + //return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, propname)) + return "Property is protected."; + + ptype = p.PropertyType; + + po = p.GetValue(o, null); + + // now set the nested attribute using the new property list + return (SetPropertyValue(spawner, po, arglist[1], value)); + + } + } + } + } + else + { + + // its just a simple single property + + PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + + if (plookup != null) + { + if (!plookup.CanWrite) + return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, propname)) + return "Property is protected."; + + string returnvalue = InternalSetValue(null, o, plookup, value, false, index); + + return returnvalue; + + } + else + { + // note, looping through all of the props turns out to be a significant performance bottleneck + // good place for optimization + + foreach (PropertyInfo p in props) + { + if (Insensitive.Equals(p.Name, propname)) + { + + if (!p.CanWrite) + return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, propname)) + return "Property is protected."; + + string returnvalue = InternalSetValue(null, o, p, value, false, index); + + return returnvalue; + + } + } + } + } + + return "Property not found."; + } + + public static string SetPropertyObject(XmlSpawner spawner, object o, string name, object value) + { + if (o == null) + { + return "Null object"; + } + + Type ptype = null; + object po = null; + Type type = o.GetType(); + + PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + // parse the strings of the form property.attribute into two parts + // first get the property + string[] arglist = ParseString(name, 2, "."); + + + if (arglist.Length == 2) + { + // is a nested property with attributes so first get the property + + // use the lookup table for optimization if possible + PropertyInfo plookup = LookupPropertyInfo(spawner, type, arglist[0]); + + if (plookup != null) + { + + //if ( !plookup.CanWrite ) + //return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, arglist[0])) + return "Property is protected."; + + ptype = plookup.PropertyType; + + po = plookup.GetValue(o, null); + + // now set the nested attribute using the new property list + return (SetPropertyObject(spawner, po, arglist[1], value)); + } + else + { + + foreach (PropertyInfo p in props) + { + if (Insensitive.Equals(p.Name, arglist[0])) + { + + //if ( !p.CanWrite ) + //return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, arglist[0])) + return "Property is protected."; + + ptype = p.PropertyType; + + po = p.GetValue(o, null); + + // now set the nested attribute using the new property list + return (SetPropertyObject(spawner, po, arglist[1], value)); + + } + } + } + } + else + { + // its just a simple single property + + // use the lookup table for optimization if possible + PropertyInfo plookup = LookupPropertyInfo(spawner, type, name); + + if (plookup != null) + { + + if (!plookup.CanWrite) + return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, name)) + return "Property is protected."; + + if (plookup.PropertyType == typeof(Server.Mobile)) + { + plookup.SetValue(o, value, null); + + return "Property has been set."; + } + else + { + return "Property is not of type Mobile."; + } + } + else + { + foreach (PropertyInfo p in props) + { + if (Insensitive.Equals(p.Name, name)) + { + + if (!p.CanWrite) + return "Property is read only."; + + if (BaseXmlSpawner.IsProtected(type, name)) + return "Property is protected."; + + if (p.PropertyType == typeof(Server.Mobile)) + { + p.SetValue(o, value, null); + + return "Property has been set."; + } + else + { + return "Property is not of type Mobile."; + } + } + } + } + } + + return "Property not found."; + } + + + public static string GetBasicPropertyValue(object o, string propname, out Type ptype) + { + ptype = null; + + if (o == null || propname == null) return null; + + Type type = o.GetType(); + + PropertyInfo[] props = type.GetProperties(); + + foreach (PropertyInfo p in props) + { + + if (Insensitive.Equals(p.Name, propname)) + { + if (!p.CanRead) + return null; + + ptype = p.PropertyType; + + string value = InternalGetValue(o, p, -1); + + return ParseGetValue(value, ptype); + } + } + return null; + } + + public static string GetPropertyValue(XmlSpawner spawner, object o, string name, out Type ptype) + { + ptype = null; + if (o == null || name == null) return null; + + Type type = o.GetType(); + object po = null; + + PropertyInfo[] props = null; + + try + { + props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + } + catch + { + Console.WriteLine("GetProperties error with type {0}", type); + return null; + } + + // parse the strings of the form property.attribute into two parts + // first get the property + string[] arglist = ParseString(name, 2, "."); + string propname = arglist[0]; + // parse up to 4 comma separated args for special keyword properties + string[] keywordargs = ParseString(propname, 4, ","); + + // check for special keywords + if (keywordargs[0] == "ATTACHMENT") + { + // syntax is ATTACHMENT,type,name,property + if (keywordargs.Length < 4) + { + return "Invalid ATTACHMENT format"; + } + + string apropname = keywordargs[3]; + string aname = keywordargs[2]; + Type attachtype = SpawnerType.GetType(keywordargs[1]); + + // allow empty string specifications to be used to indicate a null string which will match any name + if (aname == "") aname = null; + + ArrayList attachments = XmlAttach.FindAttachments(o, attachtype, aname); + + if (attachments != null && attachments.Count > 0) + { + string getvalue = GetPropertyValue(spawner, attachments[0], apropname, out ptype); + + return getvalue; + } + else + return "Attachment not found"; + } + else + if (keywordargs[0] == "SKILL") + { + // syntax is SKILL,skillname + if (keywordargs.Length < 2) + { + return "Invalid SKILL format"; + } + bool found = true; + try + { + SkillName skillname = (SkillName)Enum.Parse(typeof(SkillName), keywordargs[1], true); + + if (o is Mobile) + { + Skill skill = ((Mobile)o).Skills[skillname]; + ptype = skill.Value.GetType(); + + return String.Format("{0} = {1}", skillname, skill.Value); + } + else + return "Object is not mobile"; + } + catch { found = false; } + + if (!found) + return "Skill not found."; + } + else + if (keywordargs[0] == "SERIAL") + { + + bool found = true; + try + { + if (o is Mobile) + { + ptype = ((Mobile)o).Serial.GetType(); + + return String.Format("Serial = {0}", ((Mobile)o).Serial); + } + else + if (o is Item) + { + ptype = ((Item)o).Serial.GetType(); + + return String.Format("Serial = {0}", ((Item)o).Serial); + } + else + return "Object is not item/mobile"; + } + catch { found = false; } + + if (!found) + return "Serial not found."; + } + else + if (keywordargs[0] == "TYPE") + { + ptype = typeof(Type); + + return String.Format("Type = {0}", o.GetType().Name); + + } + else + if (keywordargs[0] == "STEALABLE") + { + + bool found = true; + try + { + + if (o is Item) + { + ptype = typeof(bool); + + return String.Format("Stealable = {0}", ItemFlags.GetStealable(o as Item)); + } + else + return "Object is not an item"; + } + catch { found = false; } + + if (!found) + return "Stealable flag not found."; + } + + + + // do a bit of parsing to handle array references + string[] arraystring = arglist[0].Split('['); + int index = -1; + if (arraystring.Length > 1) + { + // parse the property name from the indexing + propname = arraystring[0]; + + // then parse to get the index value + string[] arrayvalue = arraystring[1].Split(']'); + + if (arrayvalue.Length > 0) + { + try + { + index = int.Parse(arrayvalue[0]); + } + catch { } + } + } + + if (arglist.Length == 2) + { + // use the lookup table for optimization if possible + PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + + if (plookup != null) + { + + if (!plookup.CanRead) + return "Property is write only."; + + //if ( BaseXmlSpawner.IsProtected(type, propname) ) + //return "Property is protected."; + + ptype = plookup.PropertyType; + if (ptype.IsPrimitive) + { + po = plookup.GetValue(o, null); + } + else if ((ptype.GetInterface("IList") != null) && index >= 0) + { + try + { + object arrayvalue = plookup.GetValue(o, null); + po = ((IList)arrayvalue)[index]; + } + catch { } + } + else + { + po = plookup.GetValue(o, null); + } + // now set the nested attribute using the new property list + return (GetPropertyValue(spawner, po, arglist[1], out ptype)); + } + else + { + // is a nested property with attributes so first get the property + foreach (PropertyInfo p in props) + { + //if ( Insensitive.Equals( p.Name, arglist[0] ) ) + if (Insensitive.Equals(p.Name, propname)) + { + + if (!p.CanRead) + return "Property is write only."; + + //if ( BaseXmlSpawner.IsProtected(type, propname) ) + //return "Property is protected."; + + ptype = p.PropertyType; + if (ptype.IsPrimitive) + { + po = p.GetValue(o, null); + } + else if ((ptype.GetInterface("IList") != null) && index >= 0) + { + try + { + object arrayvalue = p.GetValue(o, null); + po = ((IList)arrayvalue)[index]; + } + catch { } + } + else + { + po = p.GetValue(o, null); + } + // now set the nested attribute using the new property list + return (GetPropertyValue(spawner, po, arglist[1], out ptype)); + + } + } + } + } + else + { + // use the lookup table for optimization if possible + PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + + if (plookup != null) + { + + + if (!plookup.CanRead) + return "Property is write only."; + + ptype = plookup.PropertyType; + + return InternalGetValue(o, plookup, index); + } + else + { + // its just a simple single property + foreach (PropertyInfo p in props) + { + + //if ( Insensitive.Equals( p.Name, name ) ) + if (Insensitive.Equals(p.Name, propname)) + { + + + if (!p.CanRead) + return "Property is write only."; + + ptype = p.PropertyType; + + return InternalGetValue(o, p, index); + } + } + } + } + + return "Property not found."; + } + // ------------------------------------------------------------- + // End modified Beta-36 Properties.cs code + // ------------------------------------------------------------- + + public static string ApplyToProperty(XmlSpawner spawner, object getobject, object setobject, string getpropertystring, string setpropertystring) + { + Type ptype; + + string getvalue = GetPropertyValue(spawner, getobject, getpropertystring, out ptype); + + if (getvalue == null) + { + return "Null object or property"; + } + + if (ptype == null) + { + return getvalue; + } + + string value2 = ParseGetValue(getvalue, ptype); + + if (value2 != null) + { + // set the property value using returned get value as the the value + string result = SetPropertyValue(spawner, setobject, setpropertystring, value2); + + // see if it was successful + if (result != "Property has been set.") + { + return setpropertystring + " : " + result; + } + } + + return null; + } + + + + // added in arg parsing to handle object property setting + public static bool ApplyObjectStringProperties(XmlSpawner spawner, string str, object o, Mobile trigmob, object refobject, out string status_str) + { + status_str = null; + + if (str == null || str.Length <= 0 || o == null) return false; + + // object strings will be of the form "object/modifier" where the modifier string is of the form "propname/value/propname/value/..." + // some keywords do not have value arguments so the modifier could take the form "propname/propname/value/..." + // this is handled by parsing into both forms + + // make sure the string is properly terminated to assure proper parsing of any final keywords + bool terminated = false; + str = str.Trim(); + + if (str[str.Length - 1] != '/') + { + str += "/"; + terminated = true; + } + + string[] arglist; + + arglist = ParseSlashArgs(str, 2); + + string remainder = null; + + // place the modifier section of the string in remainder + if (arglist.Length > 1) + remainder = arglist[1]; + + bool no_error = true; + + // process the modifier string if there is anything + while (arglist.Length > 1) + { + // place into arglist the parsed modifier up to this point + // arglist[0] will contain the propname + // arglist[1] will contain the value + // arglist[2] will contain the reset of the modifier + arglist = ParseSlashArgs(remainder, 3); + + // singlearglist will contain the propname and the remainder + // for those keywords that do not have value args + string[] singlearglist = ParseSlashArgs(remainder, 2); + + if (arglist.Length > 1) + { + // handle value keywords that may take comma args + + // itemarglist[1] will contain arg2/arg3/arg4>/arg5 + // additemstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 + // it will just have arg2 + string[] groupedarglist = ParseString(arglist[1], 2, "["); + + // take that argument list that should like like arg2/ag3/arg4>/arg5 + // need to find the matching ">" + + string[] groupargs = null; + string groupargstring = null; + if (groupedarglist.Length > 1) + { + groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']'); + + // and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4 + groupargstring = groupargs[0]; + } + + // need to handle comma args that may be grouped with the () such as the (ATTACHMENT,args) arg + + //string[] value_keywordargs = ParseString(groupedarglist[0],10,","); + string[] value_keywordargs = groupedarglist[0].Trim().Split(','); + if (groupargstring != null && groupargstring.Length > 0) + { + + if (value_keywordargs != null && value_keywordargs.Length > 0) + value_keywordargs[value_keywordargs.Length - 1] = groupargstring; + } + + // handle propname keywords that may take comma args + //string[] keywordargs = ParseString(arglist[0],10,","); + string[] keywordargs = arglist[0].Trim().Split(','); + + + // this quick optimization can determine whether this is a regular prop/value assignment + // since most prop modification strings will use regular propnames and not keywords, it makes sense to check for that first + if (value_keywordargs[0].Length > 0 && !Char.IsUpper(value_keywordargs[0][0]) && + arglist[0].Length > 0 && !Char.IsUpper(arglist[0][0])) + { + // all of this code is also included in the keyword candidate tests + // this is because regular props can also be entered with uppercase so the lowercase test is not definitive + + // restricted properties + //if(arglist[0].ToLower() == "accesslevel") + //{ + // status_str = "accesslevel is a protected property"; + // if(arglist.Length < 3) break; + // remainder = arglist[2]; + //} + //else + { + // check for the literal char + if (singlearglist[1] != null && singlearglist[1].Length > 0 && singlearglist[1][0] == '@') + { + string lstr = singlearglist[1]; + + if (terminated && lstr[lstr.Length - 1] == '/') + lstr = lstr.Remove(lstr.Length - 1, 1); + + string result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1)); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + remainder = null; + break; + } + else + { + + string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + } + } + else + { + if (IsValuemodKeyword(value_keywordargs[0])) + { + valuemodKeyword kw = (valuemodKeyword)valuemodKeywordHash[value_keywordargs[0]]; + + if (kw == valuemodKeyword.RND) + { + // generate a random number and use it as the property value. Use the format /RND,min,max/ + if (value_keywordargs.Length > 2) + { + // get a random number + string randvalue = "0"; + try + { + randvalue = String.Format("{0}", Utility.RandomMinMax(int.Parse(value_keywordargs[1]), int.Parse(value_keywordargs[2]))); + } + catch { status_str = "Invalid RND args : " + arglist[1]; no_error = false; } + // set the property value using the random number as the value + string result = SetPropertyValue(spawner, o, arglist[0], randvalue); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + else + { + status_str = "Invalid RND args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.RNDBOOL) + { + // generate a random bool and use it as the property value. Use the format /RNDBOOL/ + + string randvalue = Utility.RandomBool().ToString(); + + // set the property value using the random number as the value + string result = SetPropertyValue(spawner, o, arglist[0], randvalue); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.RNDLIST || kw == valuemodKeyword.RNDSTRLIST) + { + // generate a random number and use it as the property value. Use the format /RNDLIST,val1,val2,.../ + if (value_keywordargs.Length > 1) + { + + // compute a random index into the arglist + + int randindex = Utility.Random(1, value_keywordargs.Length - 1); + + // assign the list entry as the value + + string randvalue = value_keywordargs[randindex]; + + // set the property value + string result = SetPropertyValue(spawner, o, arglist[0], randvalue); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + else + { + status_str = "Invalid " + arglist[0] + " args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.MY) + { + // syntax is MY,property + // note this will be an arg to some property + if (value_keywordargs.Length > 1) + { + string resultstr = ApplyToProperty(spawner, o, o, value_keywordargs[1], arglist[0]); + if (resultstr != null) + { + status_str = "MY error: " + resultstr; + no_error = false; + } + + } + else + { + status_str = "Invalid MY args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GET) + { + // syntax is GET,itemname[,itemtype],property + // or GET,itemname[,itemtype], + // note this will be an arg to some property + if (value_keywordargs.Length > 2) + { + string propname = value_keywordargs[2]; + string typestr = null; + + if (value_keywordargs.Length > 3) + { + propname = value_keywordargs[3]; + typestr = value_keywordargs[2]; + } + // get the current property value + //Type ptype; + // get target item + // is the itemname a serialno? + object testitem = null; + if (value_keywordargs[1].StartsWith("0x")) + { + int serial = -1; + try + { + serial = Convert.ToInt32(value_keywordargs[1], 16); + } + catch { } + if (serial >= 0) + testitem = World.FindEntity(serial); + } + else + { + + testitem = FindItemByName(spawner, value_keywordargs[1], typestr); + } + + string resultstr = ApplyToProperty(spawner, testitem, o, propname, arglist[0]); + + if (resultstr != null) + { + status_str = "GET error: " + resultstr; + no_error = false; + } + + } + else + { + status_str = "Invalid GET args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETVAR) + { + // syntax is GETVAR,varname + if (value_keywordargs.Length > 1) + { + + + string varname = value_keywordargs[1]; + + // look for the xmllocalvariable attachment with the given name + XmlLocalVariable var = (XmlLocalVariable)XmlAttach.FindAttachment(refobject, typeof(XmlLocalVariable), varname); + + if (var != null) + { + + string result = SetPropertyValue(spawner, o, arglist[0], var.Data); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + else + { + status_str = arglist[0] + " : No such var"; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + + } + else + { + status_str = "Invalid GETVAR args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONMOB) + { + // syntax is GETONMOB,mobname[,mobtype],property + // or GETONMOB,mobname[,mobtype], + // note this will be an arg to some property + if (value_keywordargs.Length > 2) + { + //if(trigmob != null && !trigmob.Deleted){ + // get the current property value + //Type ptype; + // get target item + + string propname = value_keywordargs[2]; + string typestr = null; + if (value_keywordargs.Length > 3) + { + propname = value_keywordargs[3]; + typestr = value_keywordargs[2]; + } + + Mobile testmobile = FindMobileByName(spawner, value_keywordargs[1], typestr); + string resultstr = ApplyToProperty(spawner, testmobile, o, propname, arglist[0]); + if (resultstr != null) + { + status_str = "GETONMOB error: " + resultstr; + no_error = false; + } + + } + else + { + status_str = "Invalid GETONMOB args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONCARRIED) + { + // syntax is GETONCARRIED,itemname[,itemtype][,equippedonly],property + // or GETONCARRIED,itemname[,itemtype][,equippedonly], + // note this will be an arg to some property + if (value_keywordargs.Length > 2) + { + bool equippedonly = false; + + if (trigmob != null && !trigmob.Deleted) + { + string itemname = value_keywordargs[1]; + string propname = value_keywordargs[2]; + string typestr = null; + if (value_keywordargs.Length > 3) + { + propname = value_keywordargs[3]; + typestr = value_keywordargs[2]; + } + if (value_keywordargs.Length > 4) + { + propname = value_keywordargs[4]; + if (value_keywordargs[3].ToLower() == "equippedonly") + { + equippedonly = true; + } + else + { + try + { + equippedonly = bool.Parse(value_keywordargs[3]); + } + catch + { + status_str = "GETONCARRIED error parsing equippedonly"; + no_error = false; + } + } + } + // get the current property value + //Type ptype; + // get target item + Item testitem = SearchMobileForItem(trigmob, ParseObjectType(itemname), typestr, false, equippedonly); + + string resultstr = ApplyToProperty(spawner, testitem, o, propname, arglist[0]); + + if (resultstr != null) + { + status_str = "GETONCARRIED error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + else + { + status_str = "Invalid GETONCARRIED args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONTRIGMOB) + { + // syntax is GETONTRIGMOB,property + // or GETONTRIGMOB, + // note this will be an arg to some property + if (value_keywordargs.Length > 1) + { + if (trigmob != null && !trigmob.Deleted) + { + string resultstr = ApplyToProperty(spawner, trigmob, o, value_keywordargs[1], arglist[0]); + if (resultstr != null) + { + status_str = "GETONTRIGMOB error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + else + { + status_str = "Invalid GETONTRIGMOB args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONNEARBY) + { + // syntax is GETONNEARBY,range,name[,type][,searchcontainers],property + // or GETONNEARBY,range,name[,type][,searchcontainers],[ATTACHMENT,type,name,property] + // note this will be an arg to some property + if (value_keywordargs.Length > 3) + { + string targetname = value_keywordargs[2]; + string propname = value_keywordargs[3]; + string typestr = null; + bool searchcontainers = false; + int range = -1; + try + { + range = int.Parse(value_keywordargs[1]); + } + catch { } + + if (range < 0) + { + status_str = "invalid range in GETONNEARBY"; + no_error = false; + } + + if (value_keywordargs.Length > 4) + { + typestr = value_keywordargs[3]; + propname = value_keywordargs[4]; + } + + if (value_keywordargs.Length > 5) + { + try + { + searchcontainers = bool.Parse(value_keywordargs[3]); + } + catch + { + status_str = "invalid searchcontainer bool in GETONNEARBY"; + no_error = false; + } + typestr = value_keywordargs[4]; + propname = value_keywordargs[5]; + } + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + if (no_error) + { + // get all of the nearby objects + object relativeto = spawner; + if (o is XmlAttachment) + { + relativeto = ((XmlAttachment)o).AttachedTo; + } + ArrayList nearbylist = GetNearbyObjects(relativeto, targetname, targettype, typestr, range, searchcontainers, null); + + string resultstr = null; + + // apply the properties from the first valid thing on the list + foreach (object nearbyobj in nearbylist) + { + resultstr = ApplyToProperty(spawner, nearbyobj, o, propname, arglist[0]); + if (resultstr == null) + break; + } + if (resultstr != null) + { + status_str = "GETONNEARBY error: " + resultstr; + no_error = false; + } + } + } + else + { + status_str = "Invalid GETONNEARBY args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONPARENT) + { + // syntax is GETONPARENT,property + // or GETONPARENT, + // note this will be an arg to some property + if (value_keywordargs.Length > 1) + { + object parent = null; + if (refobject is Item) + { + parent = ((Item)refobject).Parent; + } + else + if (refobject is XmlAttachment) + { + parent = ((XmlAttachment)refobject).AttachedTo; + } + + if (parent != null) + { + string resultstr = ApplyToProperty(spawner, parent, o, value_keywordargs[1], arglist[0]); + if (resultstr != null) + { + status_str = "GETONPARENT error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + else + { + status_str = "Invalid GETONPARENT args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONTHIS) + { + // syntax is GETONTHIS,property + // or GETONTHIS, + // note this will be an arg to some property + if (value_keywordargs.Length > 1) + { + + if (refobject != null) + { + string resultstr = ApplyToProperty(spawner, refobject, o, value_keywordargs[1], arglist[0]); + if (resultstr != null) + { + status_str = "GETONTHIS error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + else + { + status_str = "Invalid GETONTHIS args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONTAKEN) + { + // syntax is GETONTAKEN,property + // or GETONTAKEN, + // note this will be an arg to some property + if (value_keywordargs.Length > 1) + { + + // find the taken object + + Item taken = GetTaken(refobject); + + if (taken != null) + { + string resultstr = ApplyToProperty(spawner, taken, o, value_keywordargs[1], arglist[0]); + if (resultstr != null) + { + status_str = "GETONTAKEN error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + else + { + status_str = "Invalid GETONTAKEN args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONGIVEN) + { + // syntax is GETONGIVEN,property + // or GETONGIVEN, + // note this will be an arg to some property + if (value_keywordargs.Length > 1) + { + + // find the taken object + + Item taken = GetGiven(refobject); + + if (taken != null) + { + string resultstr = ApplyToProperty(spawner, taken, o, value_keywordargs[1], arglist[0]); + if (resultstr != null) + { + status_str = "GETONGIVEN error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + else + { + status_str = "Invalid GETONGIVEN args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETONSPAWN) + { + // syntax is GETONSPAWN[,spawername],subgroup,property + // or GETONSPAWN[,spawername],subgroup, + // note this will be an arg to some property + + if (value_keywordargs.Length > 2) + { + string subgroupstr = value_keywordargs[1]; + string propstr = value_keywordargs[2]; + string spawnerstr = null; + if (value_keywordargs.Length > 3) + { + spawnerstr = value_keywordargs[1]; + subgroupstr = value_keywordargs[2]; + propstr = value_keywordargs[3]; + } + // get the current property value + //Type ptype; + // get target object + int subgroup = -1; + try { subgroup = int.Parse(subgroupstr); } + catch { } + if (subgroup == -1) + { + status_str = "Invalid subgroup in GETONSPAWN"; + no_error = false; + } + else + { + if (spawnerstr != null) + { + spawner = FindSpawnerByName(spawner, spawnerstr); + if (spawner == null) + { + status_str = "Invalid spawnername in GETONSPAWN"; + no_error = false; + } + } + object targetobj = XmlSpawner.GetSpawned(spawner, subgroup); + if (targetobj != null) + { + string resultstr = ApplyToProperty(spawner, targetobj, o, propstr, arglist[0]); + if (resultstr != null) + { + status_str = "GETONSPAWN error: " + resultstr; + no_error = false; + } + + } + else + { + no_error = false; + } + } + } + else + { + status_str = "Invalid GETONSPAWN args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETFROMFILE) + { + // syntax is GETFROMFILE,filename + + if (value_keywordargs.Length > 1) + { + + string filename = value_keywordargs[1]; + string filestring = null; + + // read in the string from the file + if (System.IO.File.Exists(filename) == true) + { + + try + { + // Create an instance of StreamReader to read from a file. + // The using statement also closes the StreamReader. + using (StreamReader sr = new StreamReader(filename)) + { + string line; + // Read and display lines from the file until the end of + // the file is reached. + while ((line = sr.ReadLine()) != null) + { + filestring += line; + } + + sr.Close(); + } + } + catch + { + status_str = "GETFROMFILE error: " + filename; + no_error = false; + } + // set the property value + string result = SetPropertyValue(spawner, o, arglist[0], filestring); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + + } + else + { + status_str = "Invalid GETFROMFILE args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.GETACCOUNTTAG) + { + // syntax is GETACCOUNTTAG,tagname + + if (value_keywordargs.Length > 1) + { + + string tagname = value_keywordargs[1]; + string tagvalue = null; + + // get the value of the account tag from the triggering mob + if (trigmob != null && !trigmob.Deleted) + { + Account acct = trigmob.Account as Account; + if (acct != null) + { + tagvalue = acct.GetTag(tagname); + } + } + else + { + no_error = false; + } + + if (tagvalue != null) + { + // set the property value + string result = SetPropertyValue(spawner, o, arglist[0], tagvalue); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + else + { + status_str = "Invalid GETACCOUNTTAG tagname : " + tagname; + no_error = false; + } + } + else + { + status_str = "Invalid GETACCOUNTTAG args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.MUL) + { + // increment the property value by the amount. Use the format propname/MUL,min,max/ or propname/MUL,value + if (value_keywordargs.Length > 1) + { + // get a random number + string incvalue = "0"; + if (value_keywordargs.Length > 2) + { + try + { + int incarg0 = (int)(10000 * double.Parse(value_keywordargs[1])); + int incarg1 = (int)(10000 * double.Parse(value_keywordargs[2])); + incvalue = String.Format("{0}", Utility.RandomMinMax(incarg0, incarg1) / 10000.0); + } + catch { status_str = "Invalid MUL args : " + arglist[1]; no_error = false; } + } + else + { + incvalue = value_keywordargs[1]; + } + // get the current property value + Type ptype; + string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype); + + // see if it was successful + if (ptype == null) + { + status_str = String.Format("Cant find {0}", arglist[0]); + no_error = false; + } + else + { + string currentvalue = "0"; + try + { + string[] arglist2 = ParseString(tmpvalue, 2, "="); + string[] arglist3 = ParseString(arglist2[1], 2, " "); + currentvalue = arglist3[0].Trim(); + } + catch { } + string tmpstr = currentvalue; + // should use the actual ptype info to do the multiplication. Maybe later. + try + { + int tmpval = (int)(double.Parse(currentvalue) * double.Parse(incvalue)); + tmpstr = tmpval.ToString(); + } + catch { status_str = "Invalid MUL args : " + arglist[1]; no_error = false; } + + // set the property value using the incremented value + string result = SetPropertyValue(spawner, o, arglist[0], tmpstr); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + } + else + { + status_str = "Invalid MUL args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.INC) + { + // increment the property value by the amount. Use the format propname/INC,min,max/ or propname/INC,value + if (value_keywordargs.Length > 1) + { + // get a random number + string incvalue = "0"; + if (value_keywordargs.Length > 2) + { + try + { + incvalue = String.Format("{0}", Utility.RandomMinMax(int.Parse(value_keywordargs[1]), int.Parse(value_keywordargs[2]))); + } + catch { status_str = "Invalid INC args : " + arglist[1]; no_error = false; } + } + else + { + incvalue = value_keywordargs[1]; + } + // get the current property value + Type ptype; + string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype); + + + // see if it was successful + if (ptype == null) + { + status_str = String.Format("Cant find {0}", arglist[0]); + no_error = false; + } + else + { + string currentvalue = "0"; + try + { + string[] arglist2 = ParseString(tmpvalue, 2, "="); + string[] arglist3 = ParseString(arglist2[1], 2, " "); + currentvalue = arglist3[0].Trim(); + } + catch { } + string tmpstr = currentvalue; + + // should use the actual ptype info to do the addition. Maybe later. + try + { + int tmpval = (int)(double.Parse(currentvalue) + double.Parse(incvalue)); + tmpstr = tmpval.ToString(); + } + catch { status_str = "Invalid INC args : " + arglist[1]; no_error = false; } + + // set the property value using the incremented value + string result = SetPropertyValue(spawner, o, arglist[0], tmpstr); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + } + else + { + status_str = "Invalid INC args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.MOB) + { + // lookup the mob id based on the name. format is /MOB,name[,type]/ + if (value_keywordargs.Length > 1) + { + string typestr = null; + if (value_keywordargs.Length > 2) + { + typestr = value_keywordargs[2]; + } + // lookup the name + Mobile mob_id = null; + try + { + mob_id = FindMobileByName(spawner, value_keywordargs[1], typestr); // the format of this will be 0xvalue "name" + } + catch { status_str = "Invalid MOB args : " + arglist[1]; no_error = false; } + // set the property value using this format (M) id name + + string result = SetPropertyObject(spawner, o, arglist[0], mob_id); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + + } + else + { + + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.TRIGMOB) + { + string result = SetPropertyObject(spawner, o, arglist[0], trigmob); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.AMOUNTCARRIED) + { + // syntax is AMOUNTCARRIED,itemtype + int amount = 0; + + if (value_keywordargs.Length > 1) + { + string typestr = value_keywordargs[1]; + + // get the list of items being carried of the specified type + Type targetType = SpawnerType.GetType(typestr); + + if (targetType != null && trigmob != null && trigmob.Backpack != null) + { + amount = trigmob.Backpack.GetAmount(targetType); + } + + string result = SetPropertyValue(spawner, o, arglist[0], amount.ToString()); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + else + { + status_str = "Invalid AMOUNTCARRIED args : " + arglist[1]; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.PLAYERSINRANGE) + { + // syntax is PLAYERSINRANGE,range + int nplayers = 0; + int range = 0; + // get the number of players in range + if (value_keywordargs.Length > 1) + { + try + { + range = int.Parse(value_keywordargs[1]); + } + catch { } + } + + // count nearby players + if (refobject is Item) + { + + foreach (Mobile p in ((Item)refobject).GetMobilesInRange(range)) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; + } + + } + else + if (refobject is Mobile) + { + + foreach (Mobile p in ((Mobile)refobject).GetMobilesInRange(range)) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; + } + } + + + string result = SetPropertyValue(spawner, o, arglist[0], nplayers.ToString()); + + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.TRIGSKILL) + { + if (value_keywordargs.Length > 1) + { + if (spawner != null && spawner.TriggerSkill != null) + { + string skillstr = null; + // syntax is TRIGSKILL,name|value|cap|base + if (value_keywordargs[1].ToLower() == "name") + { + skillstr = spawner.TriggerSkill.Name; + } + else + if (value_keywordargs[1].ToLower() == "value") + { + skillstr = spawner.TriggerSkill.Value.ToString(); + } + else + if (value_keywordargs[1].ToLower() == "cap") + { + skillstr = spawner.TriggerSkill.Cap.ToString(); + } + else + if (value_keywordargs[1].ToLower() == "base") + { + skillstr = spawner.TriggerSkill.Base.ToString(); + } + + string result = SetPropertyValue(spawner, o, arglist[0], skillstr); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == valuemodKeyword.RANDNAME) + { + if (value_keywordargs.Length > 1) + { + + string result = SetPropertyValue(spawner, o, arglist[0], NameList.RandomName(value_keywordargs[1])); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + } + else + { + + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + } + else if (IsTypemodKeyword(keywordargs[0])) + { + typemodKeyword kw = (typemodKeyword)typemodKeywordHash[keywordargs[0]]; + + if (kw == typemodKeyword.MUSIC) + { + SendMusicToPlayers(arglist[0], trigmob, refobject, out status_str); + if (status_str != null) + { + no_error = false; + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + // + // SOUND keyword + // + else if (kw == typemodKeyword.SOUND) + { + int sound = -1; + // try to get the soundnumber argument + if (keywordargs.Length < 2) + { + status_str = "Missing sound number"; + no_error = false; + } + else + { + try + { + sound = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper sound number format"; no_error = false; } + } + try + { + if (sound >= 0 && o is IEntity) + { + Effects.PlaySound(((IEntity)o).Location, ((IEntity)o).Map, sound); + } + } + catch { } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + // + // EFFECT keyword + // + else if (kw == typemodKeyword.EFFECT) + { + int effect = -1; + int duration = 1; + // syntax is EFFECT,itemid,duration,[x,y,z] + // try to get the effect argument + if (keywordargs.Length < 2) + { + status_str = "Missing effect number"; + no_error = false; + } + else + { + try + { + effect = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper effect number format"; no_error = false; } + } + if (keywordargs.Length > 2) + { + try + { + duration = int.Parse(keywordargs[2]); + } + catch { status_str = "Improper effect duration format"; no_error = false; } + } + // by default just use the spawn location + Point3D eloc; + Map emap = Map.Internal; + if (o is Mobile) + { + eloc = ((Mobile)o).Location; + emap = ((Mobile)o).Map; + } + else + if (o is Item) + { + eloc = ((Item)o).Location; + emap = ((Item)o).Map; + } + else + { + // should never get here + eloc = new Point3D(0, 0, 0); + } + + if (keywordargs.Length > 3) + { + // is this applied to the trig mob or to a location? + if (keywordargs.Length > 5) + { + int x = 0; + int y = 0; + int z = 0; + try + { + x = int.Parse(keywordargs[3]); + y = int.Parse(keywordargs[4]); + z = int.Parse(keywordargs[5]); + } + catch { status_str = "Improper effect location format"; } + eloc = new Point3D(x, y, z); + } + } + if (effect >= 0 && emap != Map.Internal) + { + Effects.SendLocationEffect(eloc, emap, effect, duration); + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + // + // BOLTEFFECT keyword + // + else if (kw == typemodKeyword.BOLTEFFECT) + { + int sound = 0x29; + int hue = 0; + // syntax is BOLTEFFECT[,sound[,hue]] + + + // try to get the effect argument + if (keywordargs.Length > 1) + { + + try + { + sound = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper sound id"; no_error = false; } + } + if (keywordargs.Length > 2) + { + try + { + hue = int.Parse(keywordargs[2]); + } + catch { status_str = "Improper hue"; no_error = false; } + } + if (o is IEntity) + { + SendBoltEffect((IEntity)o, sound, hue); + } + + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + // + // MEFFECT keyword + // + else if (kw == typemodKeyword.MEFFECT) + { + int effect = -1; + int duration = 0; + int speed = 1; + Point3D eloc1 = new Point3D(0, 0, 0); + Point3D eloc2 = new Point3D(0, 0, 0); + Map emap = Map.Internal; + bool hasloc = false; + // syntax is MEFFECT,itemid[,speed][,x,y,z][,x2,y2,z2] + + + // try to get the effect argument + if (keywordargs.Length < 2) + { + status_str = "Missing effect number"; + no_error = false; + } + else + { + try + { + effect = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper effect number format"; no_error = false; } + } + if (keywordargs.Length > 2) + { + try + { + speed = int.Parse(keywordargs[2]); + } + catch { status_str = "Improper effect speed format"; no_error = false; } + } + + // by default just use the spawn location + + if (o is Mobile) + { + eloc2 = ((Mobile)o).Location; + emap = ((Mobile)o).Map; + } + else if (o is Item) + { + eloc2 = ((Item)o).Location; + emap = ((Item)o).Map; + } + + if (keywordargs.Length > 8) + { + + int x = 0; + int y = 0; + int z = 0; + try + { + x = int.Parse(keywordargs[3]); + y = int.Parse(keywordargs[4]); + z = int.Parse(keywordargs[5]); + } + catch { status_str = "Improper effect location format"; } + eloc1 = new Point3D(x, y, z); + + try + { + x = int.Parse(keywordargs[6]); + y = int.Parse(keywordargs[7]); + z = int.Parse(keywordargs[8]); + } + catch { status_str = "Improper effect location format"; } + eloc2 = new Point3D(x, y, z); + hasloc = true; + + } + else + if (keywordargs.Length > 5) + { + + int x = 0; + int y = 0; + int z = 0; + try + { + x = int.Parse(keywordargs[3]); + y = int.Parse(keywordargs[4]); + z = int.Parse(keywordargs[5]); + } + catch { status_str = "Improper effect location format"; } + eloc1 = new Point3D(x, y, z); + hasloc = true; + + } + + if (effect >= 0 && hasloc && emap != Map.Internal) + { + Effects.SendPacket(eloc1, emap, new HuedEffect(EffectType.Moving, -1, -1, effect, eloc1, eloc2, speed, duration, false, false, 0, 0)); + } + else + if (effect >= 0 && refobject is IEntity && o is IEntity) + { + //Effects.SendLocationEffect(eloc, emap, effect, duration); + //public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes ) + Effects.SendMovingEffect((IEntity)refobject, (IEntity)o, effect, speed, duration, false, false); + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + // + // PEFFECT keyword + // + else if (kw == typemodKeyword.PEFFECT) + { + int effect = -1; + int duration = 1; + // syntax is PEFFECT,itemid,duration,[x,y,z] + // try to get the effect argument + if (keywordargs.Length < 2) + { + status_str = "Missing effect number"; + no_error = false; + } + else + { + try + { + effect = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper effect number format"; no_error = false; } + } + if (keywordargs.Length > 2) + { + try + { + duration = int.Parse(keywordargs[2]); + } + catch { status_str = "Improper effect duration format"; no_error = false; } + } + // by default just use the spawn location + Point3D eloc; + Map emap = Map.Internal; + if (o is Mobile) + { + eloc = ((Mobile)o).Location; + emap = ((Mobile)o).Map; + } + else if (o is Item) + { + eloc = ((Item)o).Location; + emap = ((Item)o).Map; + } + else + { + // should never get here + eloc = new Point3D(0, 0, 0); + } + + if (keywordargs.Length > 3) + { + // is this applied to the trig mob or to a location? + if (keywordargs.Length > 5) + { + int x = 0; + int y = 0; + int z = 0; + try + { + x = int.Parse(keywordargs[3]); + y = int.Parse(keywordargs[4]); + z = int.Parse(keywordargs[5]); + } + catch { status_str = "Improper effect location format"; } + eloc = new Point3D(x, y, z); + } + } + if (effect >= 0 && emap != Map.Internal) + { + Effects.SendLocationEffect(eloc, emap, effect, duration); + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + // + // POISON keyword + // + else if (kw == typemodKeyword.POISON) + { + + ApplyPoisonToPlayers(arglist[0], o as Mobile, o, out status_str); + + + //ApplyPoisonToPlayers(arglist[0], trigmob, refobject, out status_str); + + if (status_str != null) + { + no_error = false; + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + else if (kw == typemodKeyword.DAMAGE) + { + + ApplyDamageToPlayers(arglist[0], o as Mobile, o, out status_str); + + //ApplyDamageToPlayers(arglist[0], trigmob, refobject, out status_str); + if (status_str != null) + { + no_error = false; + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + else if (kw == typemodKeyword.ADD) + { + + no_error = AddItemToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, false, out remainder, out status_str); + + } + else if (kw == typemodKeyword.EQUIP) + { + no_error = AddItemToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, true, out remainder, out status_str); + + } + else if (kw == typemodKeyword.DELETE) + { + + if (o is Item) + { + ((Item)o).Delete(); + } + else if (o is Mobile) + { + if (!((Mobile)o).Player) + { + ((Mobile)o).Delete(); + } + } + else if (o is XmlAttachment) + { + ((XmlAttachment)o).Delete(); + } + + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + + } + else if (kw == typemodKeyword.KILL) + { + if (o is Mobile) + { + ((Mobile)o).Kill(); + } + + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + } + else if (kw == typemodKeyword.UNEQUIP) + { + // syntax is UNEQUIP,layer[,delete] + + Layer layer = Layer.Invalid; + bool remove = false; + + if (keywordargs.Length > 1) + { + try + { + layer = (Layer)Enum.Parse(typeof(Layer), keywordargs[1], true); + } + catch { status_str = "Invalid layer"; } + } + + if (keywordargs.Length > 2) + { + if (keywordargs[2] == "delete") + { + remove = true; + } + } + + if (o is Mobile && layer != Layer.Invalid) + { + Mobile m = (Mobile)o; + // go through all of the items on the mobile + List packlist = m.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + // check the layer + // if it matches then unequip it + if (item.Layer == layer) + { + if (remove) + { + item.Delete(); + } + else + { + m.AddToBackpack(item); + } + } + } + } + + if (status_str != null) + { + no_error = false; + } + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + + } + else if (kw == typemodKeyword.ATTACH) + { + no_error = AddAttachmentToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, out remainder, out status_str); + + } + else if (kw == typemodKeyword.MSG) + { + // syntax is MSG[,probability][,hue] + + // if the object is a mobile then display a msg over the mob or item + double drop_probability = 1; + int hue = 0x3b2; + + if (keywordargs.Length > 1) + { + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } + + } + if (keywordargs.Length > 2) + { + try { hue = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } + + } + + if (hue < 0) hue = 0; + + if (o is Mobile || o is Item) + { + string msgstr = arglist[1]; + + // test the drop probability + if (Utility.RandomDouble() < drop_probability) + { + if (o is Mobile) + ((Mobile)o).PublicOverheadMessage(MessageType.Regular, hue, false, msgstr); + else + if (o is Item) + ((Item)o).PublicOverheadMessage(MessageType.Regular, hue, false, msgstr); + + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + + else if (kw == typemodKeyword.ASCIIMSG) + { + // syntax is ASCIIMSG[,probability][,hue][,font] + + // if the object is a mobile then display a msg over the mob or item + double drop_probability = 1; + int hue = 0x3b2; + int font = 3; + if (keywordargs.Length > 1) + { + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } + + } + if (keywordargs.Length > 2) + { + try { hue = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } + + } + if (keywordargs.Length > 3) + { + try { font = int.Parse(keywordargs[3]); } + catch { status_str = "Invalid MSG font : " + arglist[1]; no_error = false; } + + } + if (hue < 0) hue = 0; + if (font < 0) font = 0; + + if (o is Mobile || o is Item) + { + string msgstr = arglist[1]; + + // test the drop probability + if (Utility.RandomDouble() < drop_probability) + { + if (o is Mobile) + PublicOverheadMobileMessage((Mobile)o, MessageType.Regular, hue, font, msgstr, true); + else + if (o is Item) + PublicOverheadItemMessage((Item)o, MessageType.Regular, hue, font, msgstr); + + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == typemodKeyword.SENDMSG) + { + // syntax is SENDMSG[,probability][,hue]/msg + + // if the object is a mobile then display a msg over the mob or item + double drop_probability = 1; + int hue = 0x3b2; + int font = 3; + if (keywordargs.Length > 1) + { + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } + + } + if (keywordargs.Length > 2) + { + try { hue = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid SENDMSG hue : " + arglist[1]; no_error = false; } + + } + + if (hue < 0) hue = 0; + + if (o is Mobile) + { + string msgstr = arglist[1]; + + // test the drop probability + if (Utility.RandomDouble() < drop_probability) + { + ((Mobile)o).Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "ENU", "System", msgstr)); + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == typemodKeyword.SENDASCIIMSG) + { + // syntax is SENDASCIIMSG[,probability][,hue][,font] + + // if the object is a mobile then display a msg over the mob or item + double drop_probability = 1; + int hue = 0x3b2; + int font = 3; + if (keywordargs.Length > 1) + { + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } + + } + if (keywordargs.Length > 2) + { + try { hue = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } + + } + if (keywordargs.Length > 3) + { + try { font = int.Parse(keywordargs[3]); } + catch { status_str = "Invalid MSG font : " + arglist[1]; no_error = false; } + + } + if (hue < 0) hue = 0; + if (font < 0) font = 0; + + if (o is Mobile) + { + string msgstr = arglist[1]; + + // test the drop probability + if (Utility.RandomDouble() < drop_probability) + { + ((Mobile)o).Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", msgstr)); + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + else if (kw == typemodKeyword.SAY) + { + // if the object is a mobile then display a msg over the mob + double drop_probability = 1; + if (keywordargs.Length > 1) + { + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid say probability : " + arglist[1]; no_error = false; } + } + if (o is Mobile) + { + string msgstr = arglist[1]; + + // test the drop probability + if (Utility.RandomDouble() < drop_probability) + { + ((Mobile)o).Say(msgstr); + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + + } + else if (kw == typemodKeyword.SPEECH) + { + // syntax is SPEECH[,probability][,keywordnumber] + // if the object is a mobile then have it speak with optional keyword arg + double drop_probability = 1; + if (keywordargs.Length > 1) + { + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid speech probability : " + arglist[1]; no_error = false; } + } + int keyword_number = -1; + if (keywordargs.Length > 2) + { + try { keyword_number = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid keyword number : " + arglist[1]; no_error = false; } + } + if (o is Mobile) + { + string msgstr = arglist[1]; + + // test the drop probability + if (Utility.RandomDouble() < drop_probability) + { + int[] keywordarray = new int[] { }; + if (keyword_number >= 0) + { + keywordarray = new int[] { keyword_number }; + } + ((Mobile)o).DoSpeech(msgstr, keywordarray, MessageType.Regular, 0x3B2); + } + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + + } + else if (kw == typemodKeyword.OFFSET) + { + // syntax is OFFSET,x,y[,z] + // shift the location of the object by the specified amount + + int xoffset = 0; + int yoffset = 0; + int zoffset = 0; + + if (keywordargs.Length > 2) + { + try + { + xoffset = int.Parse(keywordargs[1]); + yoffset = int.Parse(keywordargs[2]); + } + catch { status_str = "Invalid xy offset : " + arglist[1]; no_error = false; } + } + + if (keywordargs.Length > 3) + { + try + { + zoffset = int.Parse(keywordargs[3]); + } + catch { status_str = "Invalid zoffset : " + arglist[1]; no_error = false; } + } + + if (o is Mobile) + { + Point3D loc = ((Mobile)o).Location; + ((Mobile)o).Location = new Point3D(loc.X + xoffset, loc.Y + yoffset, loc.Z + zoffset); + } + else if (o is Item) + { + Point3D loc = ((Item)o).Location; + ((Item)o).Location = new Point3D(loc.X + xoffset, loc.Y + yoffset, loc.Z + zoffset); + } + + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + + } + else if (kw == typemodKeyword.ANIMATE) + { + // syntax is ANIMATE,action[,framecount][,repeatcount][,forward true/false][,repeat true/false][delay] + // Animate( int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay ) + int action = -1; + int framecount = 7; + int repeatcount = 1; + bool forward = true; + bool repeat = false; + int delay = 0; + if (keywordargs.Length > 1) + { + try { action = int.Parse(keywordargs[1]); } + catch { status_str = "Invalid action : " + arglist[1]; no_error = false; } + } + + if (keywordargs.Length > 2) + { + try { framecount = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid framecount : " + arglist[1]; no_error = false; } + } + + if (keywordargs.Length > 3) + { + try { repeatcount = int.Parse(keywordargs[3]); } + catch { status_str = "Invalid repeatcount : " + arglist[1]; no_error = false; } + } + + if (keywordargs.Length > 4) + { + try { forward = bool.Parse(keywordargs[4]); } + catch { status_str = "Invalid forward : " + arglist[1]; no_error = false; } + } + + if (keywordargs.Length > 5) + { + try { repeat = bool.Parse(keywordargs[5]); } + catch { status_str = "Invalid repeat : " + arglist[1]; no_error = false; } + } + + + if (keywordargs.Length > 6) + { + try { delay = int.Parse(keywordargs[6]); } + catch { status_str = "Invalid delay : " + arglist[1]; no_error = false; } + } + + if (o is Mobile && action >= 0) + { + ((Mobile)o).Animate(action, framecount, repeatcount, forward, repeat, delay); + } + + if (arglist.Length < 2) break; + remainder = singlearglist[1]; + + } + else if (kw == typemodKeyword.BCAST) + { + // syntax is BCAST[,hue][,font]/message + + int hue = 0x482; + int font = -1; // default unicode messages + + if (keywordargs.Length > 1) + { + try { hue = int.Parse(keywordargs[1]); } + catch { status_str = "Invalid hue : " + arglist[1]; no_error = false; } + } + + if (keywordargs.Length > 2) + { + try { font = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid font : " + arglist[1]; no_error = false; } + } + + if (font >= 0) + { + // broadcast an ascii message to all players + BroadcastAsciiMessage(AccessLevel.Player, hue, font, arglist[1]); + } + else + { + // broadcast a message to all players + CommandHandlers.BroadcastMessage(AccessLevel.Player, hue, arglist[1]); + } + + if (arglist.Length < 3) break; + remainder = arglist[2]; + + } + } + //else // check for protected properties + // if(arglist[0].ToLower() == "accesslevel") + //{ + // status_str = "accesslevel is a protected property"; + // if(arglist.Length < 3) break; + // remainder = arglist[2]; + //} + else + { + // check for the literal char + if (singlearglist[1] != null && singlearglist[1].Length > 0 && singlearglist[1][0] == '@') + { + + string lstr = singlearglist[1]; + if (terminated && lstr[lstr.Length - 1] == '/') + lstr = lstr.Remove(lstr.Length - 1, 1); + + string result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1)); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + remainder = null; + break; + } + else + { + string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); + // see if it was successful + if (result != "Property has been set.") + { + status_str = arglist[0] + " : " + result; + no_error = false; + } + if (arglist.Length < 3) break; + remainder = arglist[2]; + } + } + } + } + } + return (no_error); + } + + #endregion + + #region Property testing + + public static bool TestMobProperty(XmlSpawner spawner, Mobile mobile, string testString, Mobile trigmob, out string status_str) + { + status_str = null; + // now make sure the mobile itself is there + if (mobile == null || mobile.Deleted) + { + return false; + } + + bool testreturn = CheckPropertyString(spawner, mobile, testString, trigmob, out status_str); + + return testreturn; + } + + public static bool TestItemProperty(XmlSpawner spawner, Item ObjectPropertyItem, string testString, Mobile trigmob, out string status_str) + { + status_str = null; + // now make sure the item itself is there + if (ObjectPropertyItem == null || ObjectPropertyItem.Deleted) + { + status_str = "Trigger Object not found"; + return false; + } + + bool testreturn = CheckPropertyString(spawner, ObjectPropertyItem, testString, trigmob, out status_str); + + return testreturn; + } + + + + public static PropertyInfo LookupPropertyInfo(XmlSpawner spawner, Type type, string propname) + { + if (spawner == null || type == null || propname == null) return null; + + // look up the info in the current list + + if (spawner.PropertyInfoList == null) spawner.PropertyInfoList = new ArrayList(); + + PropertyInfo pinfo = null; + TypeInfo tinfo = null; + + foreach (TypeInfo to in spawner.PropertyInfoList) + { + // check the type + if (to.t == type) + { + // found it + tinfo = to; + + // now search the property list + foreach (PropertyInfo p in to.plist) + { + if (Insensitive.Equals(p.Name, propname)) + { + pinfo = p; + } + } + } + } + + // did we find the property? + if (pinfo != null) + { + return pinfo; + } + else + { + // if it cant be found, then do the full search and add it to the list + + PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + foreach (PropertyInfo p in props) + { + if (Insensitive.Equals(p.Name, propname)) + { + // did we find the type at least? + if (tinfo == null) + { + // if not then add the type to the list + tinfo = new TypeInfo(); + tinfo.t = type; + + spawner.PropertyInfoList.Add(tinfo); + } + + // and add the property to the tinfo property list + tinfo.plist.Add(p); + return p; + } + } + } + + return null; + } + + public static string ParseForKeywords(XmlSpawner spawner, object o, string valstr, Mobile trigmob, bool literal, out Type ptype) + { + ptype = null; + + if (valstr == null || valstr.Length <= 0) return null; + + string str = valstr.Trim(); + + // look for keywords + // need to handle the case of nested arglists like arg,arg, + // handle value keywords that may take comma args + + // itemarglist[1] will contain arg2/arg3/arg4>/arg5 + // additemstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 + // it will just have arg2 + string[] groupedarglist = ParseString(str, 2, "["); + + // take that argument list that should like like arg2/ag3/arg4>/arg5 + // need to find the matching ">" + + string[] groupargs = null; + string groupargstring = null; + if (groupedarglist.Length > 1) + { + groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']'); + + // and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4 + groupargstring = groupargs[0]; + } + + // need to handle comma args that may be grouped with the () such as the (ATTACHMENT,args) arg + + //string[] arglist = ParseString(groupedarglist[0],4,","); + string[] arglist = groupedarglist[0].Trim().Split(','); + if (groupargstring != null && groupargstring.Length > 0) + { + if (arglist != null && arglist.Length > 0) + arglist[arglist.Length - 1] = groupargstring; + } + + + string pname = arglist[0].Trim(); + char startc = str[0]; + + // first see whether it is a standard numeric value + if ((startc == '.') || (startc == '-') || (startc == '+') || (startc >= '0' && startc <= '9')) + { + // determine the type + if (str.IndexOf(".") >= 0) + { + ptype = typeof(Double); + } + else + { + ptype = typeof(Int32); + } + return str; + } + else + // or a string + if (startc == '"' || startc == '(') + { + ptype = typeof(String); + return str; + } + else + // or an enum + if (startc == '#') + { + ptype = typeof(String); + return str.Substring(1); + } + // or a bool + else if ((str.ToLower()) == "true" || (str.ToLower() == "false")) + { + ptype = typeof(Boolean); + return str; + } + // then look for a keyword + else if (IsValueKeyword(pname)) + { + valueKeyword kw = (valueKeyword)valueKeywordHash[pname]; + + //if(pname == "GETONMOB" && arglist.Length > 2) + if ((kw == valueKeyword.GETONMOB) && arglist.Length > 2) + { + // syntax is GETONMOB,mobname[,mobtype],property + + string propname = arglist[2]; + string typestr = null; + + if (arglist.Length > 3) + { + typestr = arglist[2]; + propname = arglist[3]; + } + + Mobile testmobile = FindMobileByName(spawner, arglist[1], typestr); + + string getvalue = GetPropertyValue(spawner, testmobile, propname, out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GET) && arglist.Length > 2) + { + // syntax is GET,itemname[,itemtype],property + + string propname = arglist[2]; + string typestr = null; + + if (arglist.Length > 3) + { + typestr = arglist[2]; + propname = arglist[3]; + } + + // is the itemname a serialno? + object testitem = null; + if (arglist[1].StartsWith("0x")) + { + int serial = -1; + try + { + serial = Convert.ToInt32(arglist[1], 16); + } + catch { } + if (serial >= 0) + testitem = World.FindEntity(serial); + } + else + { + testitem = FindItemByName(spawner, arglist[1], typestr); + } + + + string getvalue = GetPropertyValue(spawner, testitem, propname, out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETONCARRIED) && arglist.Length > 2) + { + // syntax is GETONCARRIED,itemname[,itemtype][,equippedonly],property + + string propname = arglist[2]; + string typestr = null; + bool equippedonly = false; + + // if the itemtype arg has been specified then check it + if (arglist.Length > 3) + { + propname = arglist[3]; + typestr = arglist[2]; + } + if (arglist.Length > 4) + { + propname = arglist[4]; + if (arglist[3].ToLower() == "equippedonly") + { + equippedonly = true; + } + else + { + try + { + equippedonly = bool.Parse(arglist[3]); + } + catch + { + } + } + } + + Item testitem = SearchMobileForItem(trigmob, ParseObjectType(arglist[1]), typestr, false, equippedonly); + + string getvalue = GetPropertyValue(spawner, testitem, propname, out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETONNEARBY) && arglist.Length > 3) + { + // syntax is GETONNEARBY,range,name[,type][,searchcontainers],property + // or GETONNEARBY,range,name[,type][,searchcontainers],[ATTACHMENT,type,name,property] + + string targetname = arglist[2]; + string propname = arglist[3]; + string typestr = null; + bool searchcontainers = false; + int range = -1; + try + { + range = int.Parse(arglist[1]); + } + catch { } + + if (arglist.Length > 4) + { + typestr = arglist[3]; + propname = arglist[4]; + } + + if (arglist.Length > 5) + { + try + { + searchcontainers = bool.Parse(arglist[4]); + } + catch + { + } + propname = arglist[5]; + } + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + if (range >= 0) + { + // get all of the nearby objects + object relativeto = spawner; + if (o is XmlAttachment) + { + relativeto = ((XmlAttachment)o).AttachedTo; + } + ArrayList nearbylist = GetNearbyObjects(relativeto, targetname, targettype, typestr, range, searchcontainers, null); + + // apply the properties from the first valid thing on the list + foreach (object nearbyobj in nearbylist) + { + string getvalue = GetPropertyValue(spawner, nearbyobj, propname, out ptype); + return ParseGetValue(getvalue, ptype); + } + } + else + return null; + } + else if ((kw == valueKeyword.GETONTRIGMOB) && arglist.Length > 1) + { + // syntax is GETONTRIGMOB,property + string getvalue = GetPropertyValue(spawner, trigmob, arglist[1], out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETVAR) && arglist.Length > 1) + { + // syntax is GETVAR,varname + string varname = arglist[1]; + + if (o is XmlAttachment) + o = ((XmlAttachment)o).AttachedTo; + + // look for the xmllocalvariable attachment with the given name + XmlLocalVariable var = (XmlLocalVariable)XmlAttach.FindAttachment(o, typeof(XmlLocalVariable), varname); + + if (var != null) + { + + return var.Data; + } + else + { + return null; + } + } + else if ((kw == valueKeyword.GETONPARENT) && arglist.Length > 1) + { + // syntax is GETONPARENT,property + + string getvalue = null; + + if (o is Item) + { + getvalue = GetPropertyValue(spawner, ((Item)o).Parent, arglist[1], out ptype); + } + else + if (o is XmlAttachment) + { + + getvalue = GetPropertyValue(spawner, ((XmlAttachment)o).AttachedTo, arglist[1], out ptype); + } + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETONGIVEN) && arglist.Length > 1) + { + // syntax is GETONGIVEN,property + + + Item taken = null; + if (o is XmlAttachment) + { + taken = GetGiven(((XmlAttachment)o).AttachedTo); + } + else + { + taken = GetGiven(o); + } + + string getvalue = GetPropertyValue(spawner, taken, arglist[1], out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETONTAKEN) && arglist.Length > 1) + { + // syntax is GETONTAKEN,property + + + Item taken = null; + if (o is XmlAttachment) + { + taken = GetTaken(((XmlAttachment)o).AttachedTo); + } + else + { + taken = GetTaken(o); + } + + string getvalue = GetPropertyValue(spawner, taken, arglist[1], out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETONTHIS) && arglist.Length > 1) + { + // syntax is GETONTHIS,property + + string getvalue = GetPropertyValue(spawner, o, arglist[1], out ptype); + + return ParseGetValue(getvalue, ptype); + } + else if ((kw == valueKeyword.GETONSPAWN) && arglist.Length > 2) + { + // syntax is GETONSPAWN[,spawnername],subgroup,property + // get the target from the spawn list + string subgroupstr = arglist[1]; + string propstr = arglist[2]; + string spawnerstr = null; + + if (arglist.Length > 3) + { + spawnerstr = arglist[1]; + subgroupstr = arglist[2]; + propstr = arglist[3]; + } + + int subgroup = -1; + try { subgroup = int.Parse(subgroupstr); } + catch { } + + if (subgroup == -1) return null; + + if (spawnerstr != null) + { + spawner = FindSpawnerByName(spawner, spawnerstr); + } + + // check for the special COUNT property keyword + if (propstr == "COUNT") + { + ptype = typeof(int); + + // get all of the currently active spawns with the specified subgroup + ArrayList so = XmlSpawner.GetSpawnedList(spawner, subgroup); + + if (so == null) return "0"; + + // and return the count + return so.Count.ToString(); + } + else + { + + object targetobj = XmlSpawner.GetSpawned(spawner, subgroup); + if (targetobj == null) return null; + + string getvalue = GetPropertyValue(spawner, targetobj, propstr, out ptype); + + return ParseGetValue(getvalue, ptype); + } + } + else if ((kw == valueKeyword.GETFROMFILE) && arglist.Length > 1) + { + // syntax is GETFROMFILE,filename + ptype = typeof(string); + + string filename = arglist[1]; + string filestring = null; + + // read in the string from the file + if (System.IO.File.Exists(filename) == true) + { + + try + { + // Create an instance of StreamReader to read from a file. + // The using statement also closes the StreamReader. + using (StreamReader sr = new StreamReader(filename)) + { + string line; + // Read and display lines from the file until the end of + // the file is reached. + while ((line = sr.ReadLine()) != null) + { + filestring += line; + } + + sr.Close(); + } + } + catch { } + } + + return filestring; + } + else if ((kw == valueKeyword.GETACCOUNTTAG) && arglist.Length > 1) + { + // syntax is GETACCOUNTTAG,tagname + ptype = typeof(string); + + string tagname = arglist[1]; + string tagvalue = null; + + // get the value of the account tag from the triggering mob + if (trigmob != null && !trigmob.Deleted) + { + Account acct = trigmob.Account as Account; + if (acct != null) + { + tagvalue = '"' + acct.GetTag(tagname) + '"'; + } + } + + return tagvalue; + } + else if ((kw == valueKeyword.RND) && arglist.Length > 2) + { + // syntax is RND,min,max + string randvalue = "0"; + ptype = typeof(Int32); + + try + { + randvalue = String.Format("{0}", Utility.RandomMinMax(int.Parse(arglist[1]), int.Parse(arglist[2]))); + } + catch { } + + // return the random number as the value + return randvalue; + } + else if ((kw == valueKeyword.RNDBOOL)) + { + // syntax is RNDBOOL + + ptype = typeof(bool); + + // return the random number as the value + return Utility.RandomBool().ToString(); + } + else if ((kw == valueKeyword.RNDLIST) && arglist.Length > 1) + { + // syntax is RNDLIST,val1,val2,... + + ptype = typeof(Int32); + + // compute a random index into the arglist + + int randindex = Utility.Random(1, arglist.Length - 1); + + // return the list entry as the value + + return arglist[randindex]; + + } + else if ((kw == valueKeyword.RNDSTRLIST) && arglist.Length > 1) + { + // syntax is RNDSTRLIST,val1,val2,... + + ptype = typeof(string); + + // compute a random index into the arglist + + int randindex = Utility.Random(1, arglist.Length - 1); + + // return the list entry as the value + + return arglist[randindex]; + + } + else if ((kw == valueKeyword.AMOUNTCARRIED) && arglist.Length > 1) + { + // syntax is AMOUNTCARRIED,itemtype + + ptype = typeof(Int32); + + int amount = 0; + + string typestr = arglist[1]; + + if (typestr != null) + { + // get the list of items being carried of the specified type + Type targetType = SpawnerType.GetType(typestr); + + if (targetType != null && trigmob != null && trigmob.Backpack != null) + { + amount = trigmob.Backpack.GetAmount(targetType); + } + } + + return amount.ToString(); + + } + else if ((kw == valueKeyword.PLAYERSINRANGE) && arglist.Length > 1) + { + // syntax is PLAYERSINRANGE,range + + ptype = typeof(Int32); + + int nplayers = 0; + int range = 0; + // get the number of players in range + try + { + range = int.Parse(arglist[1]); + } + catch { } + + // count nearby players + + if (o is Item) + { + foreach (Mobile p in ((Item)o).GetMobilesInRange(range)) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; + } + + } + else if (o is Mobile) + { + foreach (Mobile p in ((Mobile)o).GetMobilesInRange(range)) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; + } + } + + return nplayers.ToString(); + + } + else if ((kw == valueKeyword.TRIGSKILL) && arglist.Length > 1) + { + if (spawner != null && spawner.TriggerSkill != null) + { + // syntax is TRIGSKILL,name|value|cap|base + if (arglist[1].ToLower() == "name") + { + ptype = typeof(string); + return spawner.TriggerSkill.Name; + } + else if (arglist[1].ToLower() == "value") + { + ptype = typeof(double); + return spawner.TriggerSkill.Value.ToString(); + } + else if (arglist[1].ToLower() == "cap") + { + ptype = typeof(double); + return spawner.TriggerSkill.Cap.ToString(); + } + else if (arglist[1].ToLower() == "base") + { + ptype = typeof(double); + return spawner.TriggerSkill.Base.ToString(); + } + } + + return null; + } + if ((kw == valueKeyword.RANDNAME) && arglist.Length > 1) + { + // syntax is RANDNAME,nametype + return NameList.RandomName(arglist[1]); + } + else + { + // an invalid keyword format will be passed as literal + return str; + } + } + else if (literal) + { + ptype = typeof(String); + return str; + } + else + { + // otherwise treat it as a property name + string result = GetPropertyValue(spawner, o, pname, out ptype); + + return ParseGetValue(result, ptype); + } + } + + public static string ParseGetValue(string str, Type ptype) + { + // the results of getPropertyValue takes the form + // propname = value + // or + // propname = value (hexvalue) + + if (str == null) return null; + + // find the separator + string[] arglist = str.Split("=".ToCharArray(), 2); + + if (arglist.Length > 1) + { + if (IsNumeric(ptype)) + { + // parse the value portion and get rid of the possible (hexvalue) portion of the string + string[] arglist2 = arglist[1].Trim().Split(" ".ToCharArray(), 2); + + return arglist2[0]; + + } + else + { + // for everything else + // pass on as is + return arglist[1].Trim(); + + } + } + else + { + return null; + } + } + + public static bool CheckSubstitutedPropertyString(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str) + { + string substitutedtest = ApplySubstitution(spawner, o, trigmob, testString); + + return CheckPropertyString(spawner, o, substitutedtest, trigmob, out status_str); + } + + public static bool CheckPropertyString(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str) + { + status_str = null; + + if (o == null) return false; + + if (testString == null || testString.Length < 1) + { + status_str = "Null property test string"; + return false; + } + // parse the property test string for and(&)/or(|) operators + string[] arglist = ParseString(testString, 2, "&|"); + if (arglist.Length < 2) + { + bool returnval = CheckSingleProperty(spawner, o, testString, trigmob, out status_str); + + // simple conditional test with no and/or operators + return returnval; + } + else + { + // test each half independently and combine the results + bool first = CheckSingleProperty(spawner, o, arglist[0], trigmob, out status_str); + + // this will recursively parse the property test string with implicit nesting for multiple logical tests of the + // form A * B * C * D being grouped as A * (B * (C * D)) + bool second = CheckPropertyString(spawner, o, arglist[1], trigmob, out status_str); + + int andposition = testString.IndexOf("&"); + int orposition = testString.IndexOf("|"); + + // combine them based upon the operator + if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition)) + { + // and operator + return (first && second); + } + else + if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition)) + { + // or operator + return (first || second); + } + else + { + // should never get here + return false; + } + } + + + } + + public static bool CheckSingleProperty(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str) + { + + status_str = null; + + if (o == null || testString == null || testString.Length == 0) return false; + + //get the prop name and test value + // format will be prop=prop, or prop>prop, prop 0 && testString[0] == '~') + { + invertreturn = true; + testString = testString.Substring(1, testString.Length - 1); + } + + string[] arglist = ParseString(testString, 2, "=> 0) + { + hasequal = true; + } + else + if (testString.IndexOf("!") > 0) + { + hasnotequals = true; + } + else + if (testString.IndexOf(">") > 0) + { + hasgreaterthan = true; + } + else + if (testString.IndexOf("<") > 0) + { + haslessthan = true; + } + + // does it have a valid operator? + if (!hasequal && !hasgreaterthan && !haslessthan && !hasnotequals) + return false; + + Type ptype1; + Type ptype2; + + string value1 = ParseForKeywords(spawner, o, arglist[0].Trim(), trigmob, false, out ptype1); + + // see if it was successful + if (ptype1 == null) + { + status_str = arglist[0] + " : " + value1; + + return invertreturn; + //return false; + } + + string value2 = ParseForKeywords(spawner, o, arglist[1].Trim(), trigmob, false, out ptype2); + + // see if it was successful + if (ptype2 == null) + { + status_str = arglist[1] + " : " + value2; + + return invertreturn; + //return false; + } + + // look for hex numeric specifications + int base1 = 10; + int base2 = 10; + if (IsNumeric(ptype1) && value1.StartsWith("0x")) + { + base1 = 16; + } + + if (IsNumeric(ptype2) && value2.StartsWith("0x")) + { + base2 = 16; + } + + // and do the type dependent comparisons + if (ptype2 == typeof(TimeSpan) || ptype1 == typeof(TimeSpan)) + { + if (hasequal) + { + try + { + if (TimeSpan.Parse(value1) == TimeSpan.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid timespan comparison : {0}" + testString; + } + } + else + if (hasnotequals) + { + try + { + if (TimeSpan.Parse(value1) != TimeSpan.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid timespan comparison : {0}" + testString; + } + } + else + if (hasgreaterthan) + { + try + { + if (TimeSpan.Parse(value1) > TimeSpan.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid timespan comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (TimeSpan.Parse(value1) < TimeSpan.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid timespan comparison : {0}" + testString; } + } + } + else + // and do the type dependent comparisons + if (ptype2 == typeof(DateTime) || ptype1 == typeof(DateTime)) + { + if (hasequal) + { + try + { + if (DateTime.Parse(value1) == DateTime.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid DateTime comparison : {0}" + testString; + } + } + else + if (hasnotequals) + { + try + { + if (DateTime.Parse(value1) != DateTime.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid DateTime comparison : {0}" + testString; + } + } + else + if (hasgreaterthan) + { + try + { + if (DateTime.Parse(value1) > DateTime.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid DateTime comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (DateTime.Parse(value1) < DateTime.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid DateTime comparison : {0}" + testString; } + } + } + else + // and do the type dependent comparisons + if (IsNumeric(ptype2) && IsNumeric(ptype1)) + { + if (hasequal) + { + try + { + if (Convert.ToInt64(value1, base1) == Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasnotequals) + { + try + { + if (Convert.ToInt64(value1, base1) != Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasgreaterthan) + { + try + { + if (Convert.ToInt64(value1, base1) > Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (Convert.ToInt64(value1, base1) < Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + } + else + if ((ptype2 == typeof(double)) && IsNumeric(ptype1)) + { + if (hasequal) + { + try + { + if (Convert.ToInt64(value1, base1) == double.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasnotequals) + { + try + { + if (Convert.ToInt64(value1, base1) != double.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasgreaterthan) + { + try + { + if (Convert.ToInt64(value1, base1) > double.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (Convert.ToInt64(value1, base1) < double.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + } + else + if ((ptype1 == typeof(double)) && IsNumeric(ptype2)) + { + if (hasequal) + { + try + { + if (double.Parse(value1) == Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasnotequals) + { + try + { + if (double.Parse(value1) != Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasgreaterthan) + { + try + { + if (double.Parse(value1) > Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (double.Parse(value1) < Convert.ToInt64(value2, base2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + } + else + if ((ptype1 == typeof(double)) && (ptype2 == typeof(double))) + { + if (hasequal) + { + try + { + if (double.Parse(value1) == double.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasnotequals) + { + try + { + if (double.Parse(value1) != double.Parse(value2)) return !invertreturn; + } + catch + { + status_str = "invalid int comparison : {0}" + testString; + } + } + else + if (hasgreaterthan) + { + try + { + if (double.Parse(value1) > double.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (double.Parse(value1) < double.Parse(value2)) return !invertreturn; + } + catch { status_str = "invalid int comparison : {0}" + testString; } + } + } + else + if (ptype2 == typeof(Boolean) && ptype1 == typeof(Boolean)) + { + if (hasequal) + { + try + { + if (Convert.ToBoolean(value1) == Convert.ToBoolean(value2)) return !invertreturn; + } + catch (Exception se) { status_str = "invalid bool comparison : {0}" + testString + se.Message; } + } + else + if (hasnotequals) + { + try + { + if (Convert.ToBoolean(value1) != Convert.ToBoolean(value2)) return !invertreturn; + } + catch (Exception se) { status_str = "invalid bool comparison : {0}" + testString + se.Message; } + } + } + else + if (ptype2 == typeof(Double) || ptype2 == typeof(Double)) + { + if (hasequal) + { + try + { + if (Convert.ToDouble(value1) == Convert.ToDouble(value2)) return !invertreturn; + } + catch { status_str = "invalid double comparison : {0}" + testString; } + } + else + if (hasnotequals) + { + try + { + if (Convert.ToDouble(value1) != Convert.ToDouble(value2)) return !invertreturn; + } + catch { status_str = "invalid double comparison : {0}" + testString; } + } + else + if (hasgreaterthan) + { + try + { + if (Convert.ToDouble(value1) > Convert.ToDouble(value2)) return !invertreturn; + } + catch { status_str = "invalid double comparison : {0}" + testString; } + } + else + if (haslessthan) + { + try + { + if (Convert.ToDouble(value1) < Convert.ToDouble(value2)) return !invertreturn; + } + catch { status_str = "invalid double comparison : {0}" + testString; } + } + } + else + { + // by default just do a string comparison + if (hasequal) + { + if (value1 == value2) return !invertreturn; + } + else + if (hasnotequals) + { + if (value1 != value2) return !invertreturn; + } + } + return invertreturn; + } + + #endregion + + #region Search object methods + + private static bool CheckNameMatch(string targetname, string name) + { + // a "*" targetname will match anything + // a null or empty targetname will match a null name + // otherwise the strings must match + return (targetname == "*") || (name == targetname) || (targetname != null && targetname.Length == 0 && name == null); + } + + private static void GetItemsIn(Item source, string targetname, Type targettype, string typestr, ref ArrayList nearbylist, string proptest) + { + string status_str; + if (source != null && source.Items != null && nearbylist != null) + { + foreach (Item i in source.Items) + { + // check the type and name + + Type itemtype = i.GetType(); + + if (!i.Deleted && CheckNameMatch(targetname, i.Name) && (typestr == null || + (itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype))))) + { + if (proptest == null || CheckPropertyString(null, i, proptest, null, out status_str)) + nearbylist.Add(i); + } + + if (i is Container) + { + GetItemsIn(i, targetname, targettype, typestr, ref nearbylist, proptest); + } + } + + } + } + + private static ArrayList GetNearbyObjects(object invoker, string targetname, Type targettype, string typestr, int range, bool searchcontainers, string proptest) + { + IPooledEnumerable itemlist = null; + IPooledEnumerable mobilelist = null; + ArrayList nearbylist = new ArrayList(); + string status_str; + + // get nearby items + if (targettype == null || targettype == typeof(Item) || targettype.IsSubclassOf(typeof(Item))) + { + if (invoker is Item) + { + itemlist = ((Item)invoker).GetItemsInRange(range); + } + else + if (invoker is Mobile) + { + itemlist = ((Mobile)invoker).GetItemsInRange(range); + } + + + if (itemlist != null) + { + foreach (Item i in itemlist) + { + // check the type and name + + Type itemtype = i.GetType(); + + if (searchcontainers) + { + if (i is Container) + GetItemsIn(i, targetname, targettype, typestr, ref nearbylist, proptest); + } + else + if (!i.Deleted && CheckNameMatch(targetname, i.Name) && (typestr == null || + (itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype))))) + { + if (proptest == null || CheckPropertyString(null, i, proptest, null, out status_str)) + nearbylist.Add(i); + } + + + } + + } + } + + // get nearby mobiles + if (targettype == null || targettype == typeof(Mobile) || targettype.IsSubclassOf(typeof(Mobile))) + { + if (invoker is Item) + { + mobilelist = ((Item)invoker).GetMobilesInRange(range); + } + else + if (invoker is Mobile) + { + mobilelist = ((Mobile)invoker).GetMobilesInRange(range); + } + + if (mobilelist != null) + { + + foreach (Mobile m in mobilelist) + { + + + // check the type and name + Type mobtype = m.GetType(); + + if (!m.Deleted && CheckNameMatch(targetname, m.Name) && (typestr == null || + (mobtype != null && targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype))))) + { + if (proptest == null || CheckPropertyString(null, m, proptest, null, out status_str)) + nearbylist.Add(m); + } + } + } + } + return nearbylist; + } + + public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank) + { + return SearchMobileForItem(m, targetName, typeStr, searchbank, false); + } + + + public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank, bool equippedonly) + { + + if (m != null && !m.Deleted) + { + // go through all of the items in the pack + List packlist = m.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + // dont search bank boxes + if (item is BankBox && !searchbank && !equippedonly) continue; + + // recursively search containers + if (item != null && !item.Deleted) + { + if (item is Container && !equippedonly) + { + Item itemTarget = SearchPackForItem((Container)item, targetName, typeStr); + + if (itemTarget != null) return itemTarget; + } + // test the item name against the trigger string + // if a typestring has been specified then check against that as well + if (CheckNameMatch(targetName, item.Name)) + { + + if ((typeStr == null || CheckType(item, typeStr))) + { + //found it + return item; + } + } + } + } + // now check any item that might be held + Item held = m.Holding; + + if (held != null && !held.Deleted && !equippedonly) + { + if (held is Container) + { + Item itemTarget = SearchPackForItem((Container)held, targetName, typeStr); + + if (itemTarget != null) return itemTarget; + } + // test the item name against the trigger string + if (CheckNameMatch(targetName, held.Name)) + { + if (typeStr == null || CheckType(held, typeStr)) + { + //found it + return held; + } + } + } + } + return null; + } + + public static Item SearchPackForItemType(Container pack, string targetName) + { + if (pack != null && !pack.Deleted && targetName != null && targetName.Length > 0) + { + Type targetType = SpawnerType.GetType(targetName); + + // go through all of the items in the pack + List packlist = pack.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + if (item != null && !item.Deleted) + { + if (item is Container) + { + Item itemTarget = SearchPackForItemType((Container)item, targetName); + + if (itemTarget != null) return itemTarget; + } + // test the item name against the trigger string + if (item.GetType() == targetType) + { + //found it + return item; + } + } + } + } + return null; + } + + public static Item SearchMobileForItemType(Mobile m, string targetName, bool searchbank) + { + if (m != null && !m.Deleted && targetName != null && targetName.Length > 0) + { + Type targetType = SpawnerType.GetType(targetName); + + // go through all of the items in the pack + List packlist = m.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + // dont search bank boxes + if (item is BankBox && !searchbank) continue; + + // recursively search containers + if (item != null && !item.Deleted) + { + if (item is Container) + { + Item itemTarget = SearchPackForItemType((Container)item, targetName); + + if (itemTarget != null) return itemTarget; + } + // test the item type against the trigger string + if ((item.GetType() == targetType)) + { + //found it + return item; + } + } + } + // now check any item that might be held + Item held = m.Holding; + + if (held != null && !held.Deleted) + { + if (held is Container) + { + Item itemTarget = SearchPackForItemType((Container)held, targetName); + + if (itemTarget != null) return itemTarget; + } + // test the item name against the trigger string + if (held.GetType() == targetType) + { + //found it + return held; + } + } + } + return null; + } + + public static Item SearchPackForItem(Container pack, string targetName, string typestr) + { + if (pack != null && !pack.Deleted) + { + Type targettype = null; + + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + // go through all of the items in the pack + List packlist = pack.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + if (item != null && !item.Deleted) + { + + if (item is Container) + { + Item itemTarget = SearchPackForItem((Container)item, targetName, typestr); + + if (itemTarget != null) return itemTarget; + } + // test the item name against the trigger string + if (CheckNameMatch(targetName, item.Name)) + { + if (targettype == null || (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype))) + { + //found it + return item; + } + } + } + } + } + return null; + } + + public static ArrayList SearchPackListForItemType(Container pack, string targetName, ArrayList itemlist) + { + if (pack != null && !pack.Deleted && targetName != null && targetName.Length > 0) + { + Type targetType = null; + try + { + targetType = SpawnerType.GetType(targetName); + } + catch { } + + if (targetType == null) return null; + + // go through all of the items in the pack + List packlist = pack.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + if (item != null && !item.Deleted && item is Container) + { + itemlist = SearchPackListForItemType((Container)item, targetName, itemlist); + } + // test the item name against the trigger string + if (item != null && !item.Deleted && (item.GetType().IsSubclassOf(targetType) || item.GetType().Equals(targetType))) + { + //found it + itemlist.Add(item); + } + } + } + return itemlist; + } + + public static ArrayList FindItemListByType(Mobile m, string targetName, bool searchbank) + { + ArrayList itemlist = new ArrayList(); + + if (m != null && !m.Deleted && targetName != null && targetName.Length > 0) + { + Type targetType = SpawnerType.GetType(targetName); + + // go through all of the items on the mobile + List packlist = m.Items; + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + // dont search bank boxes + if (item is BankBox && !searchbank) continue; + + // recursively search containers + if (item != null && !item.Deleted) + { + if (item is Container) + { + itemlist = SearchPackListForItemType((Container)item, targetName, itemlist); + } + // test the item name against the trigger string + if (item.GetType().IsSubclassOf(targetType) || item.GetType().Equals(targetType)) + { + //found it + // add the item to the list + itemlist.Add(item); + } + } + } + // now check any item that might be held + Item held = m.Holding; + + if (held != null && !held.Deleted) + { + if (held is Container) + { + itemlist = SearchPackListForItemType((Container)held, targetName, itemlist); + } + // test the item name against the trigger string + if (held.GetType().IsSubclassOf(targetType) || held.GetType().Equals(targetType)) + { + //found it + // add the item to the list + itemlist.Add(held); + } + } + } + return itemlist; + } + + public static bool CheckForNotCarried(Mobile m, string objectivestr) + { + if (m == null || objectivestr == null) return true; + + // parse the objective string that might be of the form 'obj &| obj &| obj ...' + string[] arglist = ParseString(objectivestr, 2, "&|"); + if (arglist.Length < 2) + { + // simple test with no and/or operators + return SingleCheckForNotCarried(m, objectivestr); + } + else + { + // test each half independently and combine the results + bool first = SingleCheckForNotCarried(m, arglist[0]); + + // this will recursively parse the property test string with implicit nesting for multiple logical tests of the + // form A * B * C * D being grouped as A * (B * (C * D)) + bool second = CheckForNotCarried(m, arglist[1]); + + int andposition = objectivestr.IndexOf("&"); + int orposition = objectivestr.IndexOf("|"); + + // for the & operator + // notrigger if + // notcarrying A | notcarrying B + // people will actually think of it as not(carrying A | carrying B) + // which is + // notrigger if + // notcarrying A && notcarrying B + // similarly for the & operator + + // combine them based upon the operator + if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition)) + { + // and operator (see explanation above) + return (first || second); + } + else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition)) + { + // or operator (see explanation above) + return (first && second); + } + else + { + // should never get here + return false; + } + } + } + + public static bool SingleCheckForNotCarried(Mobile m, string objectivestr) + { + + if (m == null || objectivestr == null) return true; + + bool has_no_such_item = true; + + // check to see whether there is an objective specification as well. The format is name[,type][,EQUIPPED][,objective,objective,...] + string[] objstr = ParseString(objectivestr, 8, ","); + string itemname = objstr[0]; + + // check for attachment keyword + if (itemname == "ATTACHMENT") + { + // syntax is ATTACHMENT,name,type + if (objstr.Length > 1) + { + string aname = objstr[1]; + Type atype = null; + if (objstr.Length > 2) + { + try + { + atype = SpawnerType.GetType(objstr[2]); + } + catch { } + } + + // try to find the attachment on the mob + if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) + return false; + else + return true; + } + else + return true; + } + + bool equippedonly = false; + string typestr = null; + int objoffset = 1; + // is there a type specification? + + + while (objoffset < objstr.Length) + { + if (objstr[objoffset] != null && objstr[objoffset].Length > 0) + { + + char startc = objstr[objoffset][0]; + + if (startc >= '0' && startc <= '9') + { + // this is the start of the numeric objective specifications + break; + } + else + if (objstr[objoffset] == "EQUIPPED") + { + equippedonly = true; + } + else + { + // treat as a type specification if it does not begin with a numeric char + // and is not the EQUIPPED keyword + typestr = objstr[objoffset]; + } + } + objoffset++; + } + + // look for the item + Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); + + // found the item + if (testitem != null) + { + // check to see if it is a quest token item. If so, then check validity, otherwise just finding it is enough + if (testitem is IXmlQuest && ((IXmlQuest)testitem).IsValid) + { + IXmlQuest token = (IXmlQuest)testitem; + + if (objstr.Length > objoffset) + { + has_no_such_item = true; + // get any objectives and test for them. If any of the required conditions are true, then block trigger + for (int n = objoffset; n < objstr.Length; n++) + { + try + { + switch (int.Parse(objstr[n]) - objoffset + 1) + { + case 1: + if (token.Completed1) has_no_such_item = false; + break; + case 2: + if (token.Completed2) has_no_such_item = false; + break; + case 3: + if (token.Completed3) has_no_such_item = false; + break; + case 4: + if (token.Completed4) has_no_such_item = false; + break; + case 5: + if (token.Completed5) has_no_such_item = false; + break; + } + } + catch { } + } + } + else + has_no_such_item = false; + } + else + { + // is the equippedonly flag set? If so then see if the item is equipped + if ((equippedonly && testitem.Parent == m) || !equippedonly) + has_no_such_item = false; + } + } + return has_no_such_item; + } + + public static bool CheckForCarried(Mobile m, string objectivestr) + { + if (m == null || objectivestr == null) return true; + + // parse the objective string that might be of the form 'obj &| obj &| obj ...' + string[] arglist = ParseString(objectivestr, 2, "&|"); + if (arglist.Length < 2) + { + // simple test with no and/or operators + return SingleCheckForCarried(m, objectivestr); + } + else + { + // test each half independently and combine the results + bool first = SingleCheckForCarried(m, arglist[0]); + + // this will recursively parse the property test string with implicit nesting for multiple logical tests of the + // form A * B * C * D being grouped as A * (B * (C * D)) + bool second = CheckForCarried(m, arglist[1]); + + int andposition = objectivestr.IndexOf("&"); + int orposition = objectivestr.IndexOf("|"); + + // combine them based upon the operator + if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition)) + { + // and operator + return (first && second); + } + else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition)) + { + // or operator + return (first || second); + } + else + { + // should never get here + return false; + } + } + } + + + public static bool SingleCheckForCarried(Mobile m, string objectivestr) + { + + if (m == null || objectivestr == null) return false; + + bool has_valid_item = false; + + // check to see whether there is an objective specification as well. The format is name[,type][,EQUIPPED][,objective,objective,...] + string[] objstr = ParseString(objectivestr, 8, ","); + + string itemname = objstr[0]; + + // check for attachment keyword + if (itemname == "ATTACHMENT") + { + // syntax is ATTACHMENT,name,type + if (objstr.Length > 1) + { + string aname = objstr[1]; + Type atype = null; + if (objstr.Length > 2) + { + try + { + atype = SpawnerType.GetType(objstr[2]); + } + catch { } + } + // try to find the attachment on the mob + if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) + return true; + else + return false; + } + else + return false; + } + + bool equippedonly = false; + string typestr = null; + int objoffset = 1; + // is there a type specification? + + while (objoffset < objstr.Length) + { + if (objstr[objoffset] != null && objstr[objoffset].Length > 0) + { + + char startc = objstr[objoffset][0]; + + if (startc >= '0' && startc <= '9') + { + // this is the start of the numeric objective specifications + break; + } + else if (objstr[objoffset] == "EQUIPPED") + { + equippedonly = true; + } + else + { + // treat as a type specification if it does not begin with a numeric char + // and is not the EQUIPPED keyword + typestr = objstr[objoffset]; + } + } + objoffset++; + } + + + Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); + + // found the item + if (testitem != null) + { + // check to see if it is a quest token item. If so, then check validity, otherwise just finding it is enough + if (testitem is IXmlQuest) + { + IXmlQuest token = (IXmlQuest)testitem; + + if (token.IsValid) + { + if (objstr.Length > objoffset) + { + has_valid_item = true; + // get any objectives and test for them. If any of the required conditions are false, then dont trigger + for (int n = objoffset; n < objstr.Length; n++) + { + try + { + switch (int.Parse(objstr[n]) - objoffset + 1) + { + case 1: + if (!token.Completed1) has_valid_item = false; + break; + case 2: + if (!token.Completed2) has_valid_item = false; + break; + case 3: + if (!token.Completed3) has_valid_item = false; + break; + case 4: + if (!token.Completed4) has_valid_item = false; + break; + case 5: + if (!token.Completed5) has_valid_item = false; + break; + } + } + catch { } + } + } + else + // if an objective list has not been specified then just a valid item is enough + has_valid_item = true; + } + } + else + { + // is the equippedonly flag set? If so then see if the item is equipped + if ((equippedonly && testitem.Parent == m) || !equippedonly) + has_valid_item = true; + } + } + return has_valid_item; + } + + public static Item FindItemByName(XmlSpawner fromspawner, string name, string typestr) + { + if (name == null) return (Item)null; + + int count = 0; + + + Item founditem = FindInRecentItemSearchList(fromspawner, name, typestr); + + if (founditem != null) + { + return founditem; + } + + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + // search through all items in the world and find the first one with a matching name + foreach (Item item in World.Items.Values) + { + Type itemtype = item.GetType(); + + if (!item.Deleted && (name.Length == 0 || String.Compare(item.Name, name, true) == 0)) + { + + if (typestr == null || + (itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype)))) + { + founditem = item; + count++; + // added the break in to return the first match instead of forcing uniqueness (overrides the count test) + break; + } + } + //if(count > 1) break; + } + + // if a unique item is found then success + if (count == 1) + { + // add this to the recent search list + AddToRecentItemSearchList(fromspawner, founditem); + + return (founditem); + } + else + return (Item)null; + } + + public static Mobile FindMobileByName(XmlSpawner fromspawner, string name, string typestr) + { + if (name == null) return (Mobile)null; + + int count = 0; + + Mobile foundmobile = FindInRecentMobileSearchList(fromspawner, name, typestr); + + if (foundmobile != null) return foundmobile; + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + // search through all mobiles in the world and find one with a matching name + foreach (Mobile mobile in World.Mobiles.Values) + { + Type mobtype = mobile.GetType(); + if (!mobile.Deleted && ((name.Length == 0 || String.Compare(mobile.Name, name, true) == 0)) && (typestr == null || + (mobtype != null && targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype))))) + { + + foundmobile = mobile; + count++; + // added the break in to return the first match instead of forcing uniqueness (overrides the count test) + break; + } + //if(count > 1) break; + } + + // if a unique item is found then success + if (count == 1) + { + // add this to the recent search list + AddToRecentMobileSearchList(fromspawner, foundmobile); + + return (foundmobile); + } + else + return (Mobile)null; + } + + public static XmlSpawner FindSpawnerByName(XmlSpawner fromspawner, string name) + { + if (name == null) return (XmlSpawner)null; + + int count = 0; + + // do a quick search through the recent search list to see if it is there + XmlSpawner foundspawner = FindInRecentSpawnerSearchList(fromspawner, name); + + if (foundspawner != null) return foundspawner; + + // search through all xmlspawners in the world and find one with a matching name + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + XmlSpawner spawner = (XmlSpawner)item; + if (!spawner.Deleted && (String.Compare(spawner.Name, name, true) == 0)) + { + foundspawner = spawner; + + count++; + // added the break in to return the first match instead of forcing uniqueness (overrides the count test) + break; + } + //if(count > 1) break; + } + } + + // if a unique item is found then success + if (count == 1) + { + // add this to the recent search list + AddToRecentSpawnerSearchList(fromspawner, foundspawner); + + return (foundspawner); + } + else + return (XmlSpawner)null; + + } + + public static void AddToRecentSpawnerSearchList(XmlSpawner spawner, XmlSpawner target) + { + if (spawner == null || target == null) return; + + if (spawner.RecentSpawnerSearchList == null) + { + spawner.RecentSpawnerSearchList = new ArrayList(); + } + spawner.RecentSpawnerSearchList.Add(target); + + // check the length and truncate if it gets too long + if (spawner.RecentSpawnerSearchList.Count > 100) + { + spawner.RecentSpawnerSearchList.RemoveAt(0); + } + } + + public static XmlSpawner FindInRecentSpawnerSearchList(XmlSpawner spawner, string name) + { + if (spawner == null || name == null || spawner.RecentSpawnerSearchList == null) return null; + + ArrayList deletelist = null; + XmlSpawner foundspawner = null; + + foreach (XmlSpawner s in spawner.RecentSpawnerSearchList) + { + if (s.Deleted) + { + // clean it up + if (deletelist == null) + deletelist = new ArrayList(); + deletelist.Add(s); + } + else + if (String.Compare(s.Name, name, true) == 0) + { + foundspawner = s; + break; + } + } + + if (deletelist != null) + { + foreach (XmlSpawner i in deletelist) + spawner.RecentSpawnerSearchList.Remove(i); + } + + return (foundspawner); + } + + public static void AddToRecentItemSearchList(XmlSpawner spawner, Item target) + { + if (spawner == null || target == null) return; + + if (spawner.RecentItemSearchList == null) + { + spawner.RecentItemSearchList = new ArrayList(); + } + + spawner.RecentItemSearchList.Add(target); + + // check the length and truncate if it gets too long + if (spawner.RecentItemSearchList.Count > 100) + { + spawner.RecentItemSearchList.RemoveAt(0); + } + } + + public static Item FindInRecentItemSearchList(XmlSpawner spawner, string name, string typestr) + { + if (spawner == null || name == null || spawner.RecentItemSearchList == null) return null; + + ArrayList deletelist = null; + Item founditem = null; + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + foreach (Item item in spawner.RecentItemSearchList) + { + if (item.Deleted) + { + // clean it up + if (deletelist == null) + deletelist = new ArrayList(); + deletelist.Add(item); + } + else + if (name.Length == 0 || String.Compare(item.Name, name, true) == 0) + { + if (typestr == null || + (item.GetType() != null && targettype != null && (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype)))) + { + founditem = item; + break; + } + } + } + + if (deletelist != null) + { + foreach (Item i in deletelist) + spawner.RecentItemSearchList.Remove(i); + } + + return (founditem); + } + + public static void AddToRecentMobileSearchList(XmlSpawner spawner, Mobile target) + { + if (spawner == null || target == null) return; + + if (spawner.RecentMobileSearchList == null) + { + spawner.RecentMobileSearchList = new ArrayList(); + } + + spawner.RecentMobileSearchList.Add(target); + + // check the length and truncate if it gets too long + if (spawner.RecentMobileSearchList.Count > 100) + { + spawner.RecentMobileSearchList.RemoveAt(0); + } + } + + public static Mobile FindInRecentMobileSearchList(XmlSpawner spawner, string name, string typestr) + { + if (spawner == null || name == null || spawner.RecentMobileSearchList == null) return null; + + ArrayList deletelist = null; + Mobile foundmobile = null; + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + foreach (Mobile m in spawner.RecentMobileSearchList) + { + if (m.Deleted) + { + // clean it up + if (deletelist == null) + deletelist = new ArrayList(); + deletelist.Add(m); + } + else + if (name.Length == 0 || String.Compare(m.Name, name, true) == 0) + { + + if (typestr == null || + (m.GetType() != null && targettype != null && (m.GetType().Equals(targettype) || m.GetType().IsSubclassOf(targettype)))) + { + foundmobile = m; + break; + } + } + } + + if (deletelist != null) + { + foreach (Mobile i in deletelist) + spawner.RecentMobileSearchList.Remove(i); + } + + return (foundmobile); + } + + #endregion + + #region Add object methods + + public static bool AddAttachmentToTarget(XmlSpawner spawner, object o, string[] keywordargs, string[] arglist, Mobile trigmob, + object refobject, out string remainder, out string status_str) + { + remainder = ""; + status_str = null; + + if (o == null || keywordargs == null || arglist == null) return false; + + // Use the format /ATTACH,drop_probability/attachmenttype,name[,args]/ + // or /ATTACH,drop_probability// + double drop_probability = 1; + + if (keywordargs.Length > 1) + { + bool converterror = false; + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid drop probability : " + arglist[1]; converterror = true; } + + if (converterror) return false; + } + + // o is the object to which the attachment will be attached + + // handle the nested item property specification using <> + string attachargstring = null; + + // attachtypestr will be the actual attachment type to be created. In the simple form it will be arglist[1] + // for the string /arg1/ATTACH/arg2/arg3/arg4/arg5 arglist [0] will contain ATTACH , arglist[1] will be arg2, + // and arglist[2] will be arg3/arg4/arg5 + // if nested property specs + // arglist[1] will be /arg5 + // the drop probability will be in probargs + string[] probargs = ParseString(arglist[0], 2, ","); + + string attachtypestr = arglist[1]; + + // get the argument list after the < if any , note for the string /arg1/ATTACH//arg5 arglist [0] will contain ATTACH + // arglist[1] will be /arg5 + // but note arglist[1] could also be + // remainder will have ATTACH//arg5 + // + // can also deal with nested cases of ATTACH/> and ATTACH//ADD/> although there is no clear + // reason why this syntax should be used at this time + string addattachstr = arglist[1]; + + + if (arglist.Length > 2) + addattachstr = arglist[1] + "/" + arglist[2]; + + // check to see if the first char is a "<" + if (addattachstr.IndexOf("<") == 0) + { + // attacharglist[1] will contain arg2/arg3/arg4>/arg5 + // addattachstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 + // it will just have arg2 + string[] attacharglist = ParseString(addattachstr, 2, "<"); + + // take that argument list that should like like arg2/ag3/arg4>/arg5 + // need to find the matching ">" + //string[] attachargs = ParseString(attacharglist[1],2,">"); + + string[] attachargs = ParseToMatchingParen(attacharglist[1], '<', '>'); + + // and get the first part of the string without the > so attachargs[0] should be arg2/ag3/arg4 + attachargstring = attachargs[0]; + + // and attachargs[1] should be the remainder + if (attachargs.Length > 1) + { + // but have to get rid of any trailing / that might be after the > + string[] trailstr = ParseSlashArgs(attachargs[1], 2); + if (trailstr.Length > 1) + remainder = trailstr[1]; + else + remainder = attachargs[1]; + } + else + remainder = ""; + + // get the type info by pulling out the first arg in attachargstring + string[] tempattacharg = ParseSlashArgs(attachargstring, 2); + + // and get the type info from it + attachtypestr = tempattacharg[0]; + + + } + else + { + // otherwise its just a regular case with arglist[2] containing the rest of the arguments + if (arglist.Length > 2) + remainder = arglist[2]; + else + remainder = ""; + } + + // test the drop probability + if (Utility.RandomDouble() >= drop_probability) return true; + + Type type = null; + if (attachtypestr != null) + { + try + { + type = SpawnerType.GetType(ParseObjectType(attachtypestr)); + } + catch { } + } + // if so then create it + if (type != null && type.IsSubclassOf(typeof(XmlAttachment))) + { + object newo = XmlSpawner.CreateObject(type, attachtypestr, false, true); + if (newo is XmlAttachment) + { + XmlAttachment attachment = newo as XmlAttachment; + + // could call applyobjectstringproperties on a nested propertylist here to set attachment attributes + if (attachargstring != null) + { + ApplyObjectStringProperties(spawner, attachargstring, attachment, trigmob, refobject, out status_str); + } + + // add the attachment to the target + if (!XmlAttach.AttachTo(spawner, o, attachment)) + { + status_str = String.Format("Attachment {0} not added", attachtypestr); + return false; + } + + } + else + { + status_str = "Invalid ATTACH. No such attachment : " + attachtypestr; + + return false; + } + + } + else + { + status_str = "Invalid ATTACH. No such attachment : " + attachtypestr; + return false; + } + + return true; + } + + public static bool AddItemToTarget(XmlSpawner spawner, object o, string[] keywordargs, string[] arglist, Mobile trigmob, + object refobject, bool equip, out string remainder, out string status_str) + { + remainder = ""; + status_str = null; + + if (o == null || keywordargs == null || arglist == null) return false; + + // if the object is a mobile then add the item in the next arg to its pack. Use the format /ADD,drop_probability/itemtype/ + // or /ADD,drop_probability// + double drop_probability = 1; + + if (keywordargs.Length > 1) + { + bool converterror = false; + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid drop probability : " + arglist[1]; converterror = true; } + + if (converterror) return false; + } + + Mobile m = null; + if (o is Mobile || (o is Container)) + { + Container pack = null; + + if (o is Mobile) + { + m = (Mobile)o; + + if (!m.Deleted) + { + pack = m.Backpack; + + // auto add a pack if the mob doesnt have one + if (pack == null) + { + pack = new Backpack(); + m.AddItem(pack); + } + } + } + else + { + pack = o as Container; + + } + + if (pack != null) + { + // handle the nested item property specification using <> + string itemargstring = null; + + // itemtypestr will be the actual item type to be created. In the simple form it will be arglist[1] + // for the string /arg1/ADD/arg2/arg3/arg4/arg5 arglist [0] will contain ADD , arglist[1] will be arg2, + // and arglist[2] will be arg3/arg4/arg5 + // if nested property specs + // arglist[1] will be /arg5 + // the drop probability will be in probargs + string[] probargs = ParseCommaArgs(arglist[0], 2); + + string itemtypestr = arglist[1]; + + // get the argument list after the < if any , note for the string /arg1/ADD//arg5 arglist [0] will contain ADD + // arglist[1] will be /arg5 + // but note arglist[1] could also be + // remainder will have ADD//arg5 + // + // also need to deal with nested cases of ADD/> and ADD//ADD> + string additemstr = arglist[1]; + + + if (arglist.Length > 2) + additemstr = arglist[1] + "/" + arglist[2]; + + // check to see if the first char is a "<" + if (additemstr.IndexOf("<") == 0) + { + // itemarglist[1] will contain arg2/arg3/arg4>/arg5 + // additemstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 + // it will just have arg2 + string[] itemarglist = ParseString(additemstr, 2, "<"); + + // take that argument list that should like like arg2/ag3/arg4>/arg5 + // need to find the matching ">" + //string[] itemargs = ParseString(itemarglist[1],2,">"); + + string[] itemargs = ParseToMatchingParen(itemarglist[1], '<', '>'); + + // and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4 + itemargstring = itemargs[0]; + + // and itemargs[1] should be the remainder + if (itemargs.Length > 1) + { + // but have to get rid of any trailing / that might be after the > + string[] trailstr = ParseSlashArgs(itemargs[1], 2); + if (trailstr.Length > 1) + remainder = trailstr[1]; + else + remainder = itemargs[1]; + } + else + remainder = ""; + + // get the type info by pulling out the first arg in itemargstring + string[] tempitemarg = ParseSlashArgs(itemargstring, 2); + + // and get the type info from it + itemtypestr = tempitemarg[0]; + + + } + else + { + // otherwise its just a regular case with arglist[2] containing the rest of the arguments + if (arglist.Length > 2) + remainder = arglist[2]; + else + remainder = ""; + } + + // test the drop probability + if (Utility.RandomDouble() >= drop_probability) return true; + + // is it a valid item specification? + string baseitemtype = ParseObjectType(itemtypestr); + + if (IsSpecialItemKeyword(baseitemtype)) + { + + // itemtypestr will have the form keyword[,x[,y]] + string[] itemkeywordargs = ParseCommaArgs(itemtypestr, 3); + + itemKeyword kw = (itemKeyword)itemKeywordHash[baseitemtype]; + + switch (kw) + { + // deal with the special keywords + + case itemKeyword.ARMOR: + { + // syntax is ARMOR,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid ARMOR args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid ARMOR args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicArmor(min, max, false, false); + + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + { + + pack.DropItem(item); + } + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "ARMOR takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.WEAPON: + { + // syntax is WEAPON,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid WEAPON args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid WEAPON args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicWeapon(min, max, false); + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "WEAPON takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.JEWELRY: + { + // syntax is JEWELRY,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid JEWELRY args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid JEWELRY args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicJewelry(min, max); + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "JEWELRY takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.SHIELD: + { + // syntax is SHIELD,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid SHIELD args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid SHIELD args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicShield(min, max); + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "SHIELD takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.JARMOR: + { + // syntax is JARMOR,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid JARMOR args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid JARMOR args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicArmor(min, max, true, true); + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "JARMOR takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.SARMOR: + { + // syntax is SARMOR,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid SARMOR args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid SARMOR args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicArmor(min, max, false, true); + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "SARMOR takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.JWEAPON: + { + // syntax is JWEAPON,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid JWEAPON args : " + itemtypestr; converterror = true; } + + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid JWEAPON args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + Item item = MagicWeapon(min, max, true); + if (item != null) + { + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "JWEAPON takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.SCROLL: + { + // syntax is SCROLL,mincircle,maxcircle + //get the min,max + if (itemkeywordargs.Length == 3) + { + int minCircle = 0; + int maxCircle = 0; + bool converterror = false; + try { minCircle = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid SCROLL args : " + itemtypestr; converterror = true; } + + try { maxCircle = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid SCROLL args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + int circle = Utility.RandomMinMax(minCircle, maxCircle); + int min = (circle - 1) * 8; + Item item = Loot.RandomScroll(min, min + 7, SpellbookType.Regular); + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "SCROLL takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.POTION: + { + // syntax is POTION + Item item = Loot.RandomPotion(); + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + break; + } + case itemKeyword.TAKEN: + { + // syntax is TAKEN + + Item item = GetTaken(refobject); + + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + break; + } + case itemKeyword.GIVEN: + { + // syntax is GIVEN + + Item item = GetGiven(refobject); + + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + break; + } + case itemKeyword.ITEM: + { + // syntax is ITEM,serial + if (itemkeywordargs.Length == 2) + { + int serial = -1; + bool converterror = false; + try { serial = Convert.ToInt32(itemkeywordargs[1], 16); } + catch { status_str = "Invalid ITEM args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + + Item item = World.FindItem(serial); + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "ITEM takes 1 arg : " + itemtypestr; + return false; + } + + break; + } + case itemKeyword.LOOT: + { + // syntax is LOOT,methodname + if (itemkeywordargs.Length == 2) + { + + Item item = null; + + // look up the method + Type ltype = typeof(Loot); + if (ltype != null) + { + MethodInfo method = null; + + try + { + // get the zero-arg method with the specified name + method = ltype.GetMethod(itemkeywordargs[1], new Type[0]); + + } + catch { } + + if (method != null && method.IsStatic) + { + ParameterInfo[] pinfo = method.GetParameters(); + // check to make sure the method for this object has the right args + if (pinfo.Length == 0) + { + // method must be public static with no arguments returning an Item class object + try + { + item = method.Invoke(null, null) as Item; + } + catch { } + } + else + { + status_str = "LOOT method must be zero arg : " + itemtypestr; + return false; + } + } + else + { + status_str = "LOOT no valid method found : " + itemtypestr; + return false; + } + } + + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + else + { + status_str = "LOOT takes 1 arg : " + itemtypestr; + return false; + } + break; + } + /* case itemKeyword.NECROSCROLL: + { + // syntax is NECROSCROLL,index + if (itemkeywordargs.Length == 2) + { + int index = 0; + bool converterror = false; + try + { + index = int.Parse(itemkeywordargs[1]); + } + catch + { + status_str = "Invalid NECROSCROLL args : " + itemtypestr; + converterror = true; + } + + if (converterror) return false; + + if (Core.AOS) + { + Item item = Loot.Construct(Loot.NecromancyScrollTypes, index); + if (item != null) + { + pack.DropItem(item); + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + } + } + else + { + status_str = "NECROSCROLL takes 1 arg : " + itemtypestr; + return false; + } + break; + }*/ + case itemKeyword.LOOTPACK: + { + // syntax is LOOTPACK,type + if (itemkeywordargs.Length == 2) + { + LootPack lootpack = null; + string loottype = itemkeywordargs[1]; + + if (loottype.ToLower() == "poor") + { + lootpack = LootPack.Poor; + } + else if (loottype.ToLower() == "meager") + { + lootpack = LootPack.Meager; + } + else if (loottype.ToLower() == "average") + { + lootpack = LootPack.Average; + } + else if (loottype.ToLower() == "rich") + { + lootpack = LootPack.Rich; + } + else if (loottype.ToLower() == "filthyrich") + { + lootpack = LootPack.FilthyRich; + } + else if (loottype.ToLower() == "ultrarich") + { + lootpack = LootPack.UltraRich; + } + else if (loottype.ToLower() == "superboss") + { + lootpack = LootPack.SuperBoss; + } + else + { + status_str = "Invalid LOOTPACK type: " + loottype; + return false; + } + + int m_KillersLuck = 0; + if (trigmob != null) + { + m_KillersLuck = LootPack.GetLuckChanceForKiller(trigmob); + } + + bool converterror = false; + try + { + // generate the nospawn component of the lootpack + lootpack.Generate(m, pack, false, m_KillersLuck); + + // generate the spawn component (basically gold) requires a mobile and wont work in containers + // because Generate does a test for TryDropItem for stackables which requires a valid mob argument, + // any stackable generated in a container will fail + // so just test for a valid mobile and only do the atspawn generate for them. + if (m != null) + lootpack.Generate(m, pack, true, m_KillersLuck); + } + catch + { + status_str = "Unable to add LOOTPACK"; + converterror = true; + } + + if (converterror) return false; + + } + else + { + status_str = "LOOTPACK takes 1 arg : " + itemtypestr; + return false; + } + break; + } + } + + } + else + { + Type type = null; + try + { + type = SpawnerType.GetType(ParseObjectType(itemtypestr)); + } + catch { } + + // if so then create it + if (type != null) + { + object newo = XmlSpawner.CreateObject(type, itemtypestr); + if (newo is Item) + { + Item item = newo as Item; + + if (equip && m != null) + { + if (!m.EquipItem(item)) pack.DropItem(item); + } + else + pack.DropItem(item); + + // could call applyobjectstringproperties on a nested propertylist here to set item attributes + if (itemargstring != null) + { + ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); + } + } + else + { + status_str = "Invalid ADD. No such item : " + itemtypestr; + + if (newo is BaseCreature) + ((BaseCreature)newo).Delete(); + + return false; + } + + } + else + { + status_str = "Invalid ADD. No such item : " + itemtypestr; + return false; + } + } + } + else + { + status_str = "Invalid ADD. mobile has no pack."; + + if (arglist.Length < 3) return false; + + remainder = arglist[2]; + return false; + } + } + else + { + status_str = "Invalid ADD. must be mobile or container."; + + if (arglist.Length < 3) return false; + + remainder = arglist[2]; + return false; + } + return true; + } + + #endregion + + #region String parsing methods + + public static string ApplySubstitution(XmlSpawner spawner, object o, Mobile trigmob, string typeName) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + // go through the string looking for instances of {keyword} + string remaining = typeName; + + while (remaining != null && remaining.Length > 0) + { + + int startindex = remaining.IndexOf('{'); + + if (startindex == -1 || startindex + 1 >= remaining.Length) + { + // if there are no more delimiters then append the remainder and finish + sb.Append(remaining); + break; + } + + + // might be a substitution, check for keywords + int endindex = remaining.Substring(startindex + 1).IndexOf("}"); + + // if the ending delimiter cannot be found then just append and finish + if (endindex == -1) + { + sb.Append(remaining); + break; + } + + // get the string up to the delimiter + string firstpart = remaining.Substring(0, startindex); + sb.Append(firstpart); + + string keypart = remaining.Substring(startindex + 1, endindex); + + // try to evaluate and then substitute the arg + Type ptype; + + string value = ParseForKeywords(spawner, o, keypart.Trim(), trigmob, true, out ptype); + + // trim off the " from strings + if (value != null) + { + value = value.Trim('"'); + } + + // replace the parsed value for the keyword + sb.Append(value); + + // continue processing the rest of the string + if (endindex + startindex + 2 >= remaining.Length) break; + + remaining = remaining.Substring(endindex + startindex + 2, remaining.Length - endindex - startindex - 2); + } + return sb.ToString(); + } + + public static string ParseObjectType(string str) + { + string[] arglist = ParseSlashArgs(str, 2); + if (arglist.Length > 0) + { + // parse out any arguments of the form typename,arg,arg,.. + string[] typeargs = ParseCommaArgs(arglist[0], 2); + if (typeargs.Length > 1) + { + return (typeargs[0]); + } + return arglist[0]; + } + else + return null; + } + + public static string[] ParseObjectArgs(string str) + { + string[] arglist = ParseSlashArgs(str, 2); + if (arglist.Length > 0) + { + string itemtypestring = arglist[0]; + // parse out any arguments of the form typename,arg,arg,.. + // find the first arg if it is there + string[] typeargs = null; + int argstart = 0; + if (itemtypestring != null && itemtypestring.Length > 0) + argstart = itemtypestring.IndexOf(",") + 1; + + if (argstart > 1 && argstart < itemtypestring.Length) + { + typeargs = ParseCommaArgs(itemtypestring.Substring(argstart), 10); + } + return (typeargs); + + } + else + return null; + } + + // take a string of the form str-opendelim-str-closedelim-str-closedelimstr + public static string[] ParseToMatchingParen(string str, char opendelim, char closedelim) + { + + int nopen = 1; + int nclose = 0; + int splitpoint = str.Length; + for (int i = 0; i < str.Length; i++) + { + // walk through the string until a matching close delimstr is found + if (str[i] == opendelim) nopen++; + if (str[i] == closedelim) nclose++; + + if (nopen == nclose) + { + splitpoint = i; + break; + } + } + + string[] args = new string[2]; + + // allow missing closing delimiters at the end of the line, basically just treat eol as a closing delim + + args[0] = str.Substring(0, splitpoint); + args[1] = ""; + if (splitpoint + 1 < str.Length) + { + args[1] = str.Substring(splitpoint + 1, str.Length - splitpoint - 1); + } + + return args; + } + + public static string[] ParseString(string str, int nitems, string delimstr) + { + if (str == null || delimstr == null) return null; + + char[] delims = delimstr.ToCharArray(); + string[] args = null; + str = str.Trim(); + args = str.Split(delims, nitems); + + return args; + } + + + public static string[] ParseSlashArgs(string str, int nitems) + { + if (str == null) return null; + + string[] args = null; + + str = str.Trim(); + + // this supports strings that may have special html formatting in them that use the / + if (str.IndexOf("= 0 || str.IndexOf("/>") >= 0) + { + // or use indexof to do it with more context control + ArrayList tmparray = new ArrayList(); + // find the next slash char + int index = 0; + int preindex = 0; + int searchindex = 0; + int length = str.Length; + while (index >= 0 && searchindex < length && tmparray.Count < nitems - 1) + { + index = str.IndexOf('/', searchindex); + + if (index >= 0) + { + // check the char before it and after it to ignore + if ((index > 0 && str[index - 1] == '<') || (index < length - 1 && str[index + 1] == '>')) + { + // skip it + searchindex = index + 1; + } + else + { + // split it + tmparray.Add(str.Substring(preindex, index - preindex)); + + preindex = index + 1; + searchindex = preindex; + } + } + + } + + // is there still room for more args? + if (tmparray.Count <= nitems - 1 && preindex < length) + { + // searched past the end and didnt find anything + tmparray.Add(str.Substring(preindex, length - preindex)); + } + + // turn tmparray into a string[] + + args = new string[tmparray.Count]; + tmparray.CopyTo(args); + } + else + { + // just use split to do it with no context control + args = str.Split(slashdelim, nitems); + + } + + + + return args; + } + + public static string[] ParseSpaceArgs(string str, int nitems) + { + + if (str == null) return null; + + string[] args = null; + + str = str.Trim(); + + args = str.Split(spacedelim, nitems); + + return args; + } + + + public static string[] ParseCommaArgs(string str, int nitems) + { + + if (str == null) return null; + + string[] args = null; + + str = str.Trim(); + + args = str.Split(commadelim, nitems); + + return args; + } + + + public static string[] ParseSemicolonArgs(string str, int nitems) + { + + if (str == null) return null; + + string[] args = null; + + str = str.Trim(); + + args = str.Split(semicolondelim, nitems); + + return args; + } + + + public static string[] SplitString(string str, string separator) + { + if (str == null || separator == null) return null; + + int lastindex = 0; + int index = 0; + ArrayList strargs = new ArrayList(); + while (index >= 0) + { + // go through the string and find the first instance of the separator + index = str.IndexOf(separator); + if (index < 0) + { + // no separator so its the end of the string + strargs.Add(str); + break; + } + + string arg = str.Substring(lastindex, index); + + strargs.Add(arg); + + str = str.Substring(index + separator.Length, str.Length - (index + separator.Length)); + } + + // now make the string args + string[] args = new string[strargs.Count]; + for (int i = 0; i < strargs.Count; i++) + { + args[i] = (string)strargs[i]; + } + + return args; + } + + #endregion + + #region Keyword support methods + + public static void BroadcastAsciiMessage(AccessLevel ac, int hue, int font, string message) + { + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + + if (m != null && m.AccessLevel >= ac) + //m.SendMessage(hue, message); + m.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", message)); + } + } + + public static void BroadcastSound(AccessLevel ac, int soundid) + { + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + + if (m != null && m.AccessLevel >= ac) + { + m.ProcessDelta(); + + state.Send(new PlaySound(soundid, m.Location)); + } + } + } + + public static void PublicOverheadMobileMessage(Mobile mob, MessageType type, int hue, int font, string text, bool noLineOfSight) + { + if (mob != null && mob.Map != null) + { + Packet p = null; + + IPooledEnumerable eable = mob.Map.GetClientsInRange(mob.Location); + + foreach (NetState state in eable) + { + if (state.Mobile.CanSee(mob) && (noLineOfSight || state.Mobile.InLOS(mob))) + { + if (p == null) + { + p = new AsciiMessage(mob.Serial, mob.Body, type, hue, font, mob.Name, text); + + p.Acquire(); + + } + + state.Send(p); + } + } + + Packet.Release(p); + + eable.Free(); + } + } + + public static void PublicOverheadItemMessage(Item item, MessageType type, int hue, int font, string text) + { + if (item != null && item.Map != null) + { + Packet p = null; + Point3D worldLoc = item.GetWorldLocation(); + + IPooledEnumerable eable = item.Map.GetClientsInRange(worldLoc, item.GetMaxUpdateRange()); + + foreach (NetState state in eable) + { + Mobile m = state.Mobile; + + if (m.CanSee(item) && m.InRange(worldLoc, item.GetUpdateRange(m))) + { + if (p == null) + { + p = new AsciiMessage(item.Serial, item.ItemID, type, hue, font, item.Name, text); + + p.Acquire(); + } + + state.Send(p); + } + } + + Packet.Release(p); + + eable.Free(); + } + } + + public static Item GetTaken(object o) + { + // find the XmlSaveItem attachment + XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(o, typeof(XmlSaveItem), "Taken"); + + if (si != null) + { + return si.SavedItem; + } + + return null; + } + public static Item GetGiven(object o) + { + // find the XmlSaveItem attachment + XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(o, typeof(XmlSaveItem), "Given"); + + if (si != null) + { + return si.SavedItem; + } + + return null; + } + + // modified from 1.0.0 core packet.cs + public sealed class XmlPlayMusic : Packet + { + public XmlPlayMusic(short number) + : base(0x6D, 3) + { + UnderlyingStream.Write(number); + } + } + + // ------------------------------------------------------------- + // Begin modified code from Beta-36 Basecreature.cs + // ------------------------------------------------------------- + + public static Item MagicJewelry(int minLevel, int maxLevel) + { + BaseCreature.Cap(ref minLevel, 0, 5); + BaseCreature.Cap(ref maxLevel, 0, 5); + if (Core.AOS) + { + Item item = Loot.RandomJewelry(); + + if (item == null) + return null; + + int attributeCount, min, max; + BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); + + if (item is BaseJewel) + BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); + + return item; + } + else + { + Item jewel = Loot.RandomJewelry(); + + return jewel; + } + } + + public static Item MagicArmor(int minLevel, int maxLevel, bool jewel, bool shield) + { + BaseCreature.Cap(ref minLevel, 0, 5); + BaseCreature.Cap(ref maxLevel, 0, 5); + if (Core.AOS) + { + Item item = null; + if (jewel) + item = Loot.RandomArmorOrShieldOrJewelry(); + else + if (shield) + item = Loot.RandomArmorOrShield(); + else + item = Loot.RandomArmor(); + + if (item == null) + return null; + + int attributeCount, min, max; + + BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); + + if (item is BaseArmor) + BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max); + else if (item is BaseJewel) + BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); + + return item; + } + else + { + BaseArmor armor = Loot.RandomArmorOrShield(); + + if (armor == null) + return null; + + armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + + return armor; + } + } + + public static Item MagicShield(int minLevel, int maxLevel) + { + BaseCreature.Cap(ref minLevel, 0, 5); + BaseCreature.Cap(ref maxLevel, 0, 5); + if (Core.AOS) + { + Item item = Loot.RandomShield(); + + if (item == null) + return null; + + int attributeCount, min, max; + + BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); + + if (item is BaseArmor) + BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max); + + return item; + } + else + { + BaseArmor armor = Loot.RandomShield(); + + if (armor == null) + return null; + + armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + + return armor; + } + } + + public static Item MagicWeapon(int minLevel, int maxLevel, bool jewel) + { + BaseCreature.Cap(ref minLevel, 0, 5); + BaseCreature.Cap(ref maxLevel, 0, 5); + if (Core.AOS) + { + Item item = null; + if (jewel) + item = Loot.RandomWeaponOrJewelry(); + else + item = Loot.RandomWeapon(); + + if (item == null) + return null; + + int attributeCount, min, max; + + BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); + + if (item is BaseWeapon) + BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, attributeCount, min, max); + else if (item is BaseJewel) + BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); + + return item; + } + else + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if (weapon == null) + return null; + + if (0.05 > Utility.RandomDouble()) + weapon.Slayer = SlayerName.Silver; + + weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); + + return weapon; + } + } + + + // ------------------------------------------------------------- + // End modified code from Beta-36 Basecreature.cs + // ------------------------------------------------------------- + + public static void SendMusicToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) + { + status_str = null; + Item refitem = null; + Mobile refmob = null; + + if (refobject is Item) + { + refitem = (Item)refobject; + } + else + if (refobject is Mobile) + { + refmob = (Mobile)refobject; + } + // look for the other args + string[] musicstr = ParseString(arglist, 3, ","); + int range = 0; + if (musicstr.Length < 2) + { + status_str = "missing musicname in MUSIC"; + } + if (musicstr.Length > 2) + { + // get the range arg + try + { + range = int.Parse(musicstr[2]); + } + catch { status_str = "bad range arg in MUSIC"; } + } + + try + { + if ((range > 0) || (triggermob != null && !triggermob.Deleted)) + { + // send the music to all players within range if range is > 0 + if (range > 0) + { + IPooledEnumerable rangelist = null; + if (refitem != null && !refitem.Deleted) + { + rangelist = refitem.GetMobilesInRange(range); + } + else + if (refmob != null && !refmob.Deleted) + { + rangelist = refmob.GetMobilesInRange(range); + } + if (rangelist != null) + { + foreach (Mobile p in rangelist) + { + if (p is PlayerMobile) + { + + // stop any ongoing music + p.Send(PlayMusic.InvalidInstance); + // and play the new music + short musicnumber = -1; + try + { + musicnumber = short.Parse(musicstr[1]); + } + catch { } + + if (musicnumber == -1) + p.Send(PlayMusic.GetInstance((MusicName)Enum.Parse(typeof(MusicName), musicstr[1], true))); + else + p.Send(new XmlPlayMusic(musicnumber)); + } + } + rangelist.Free(); + } + } + else + { + // just send it to the mob who triggered + // stop any ongoing music + + triggermob.Send(PlayMusic.InvalidInstance); + // and play the new music + //triggermob.Send(PlayMusic.GetInstance((MusicName)Enum.Parse(typeof(MusicName), musicstr[1], true))); + //m_mob_who_triggered.Region.Music = (MusicName)Enum.Parse(typeof(MusicName), musicstr[1]); + // and play the new music + short musicnumber = -1; + try + { + musicnumber = short.Parse(musicstr[1]); + } + catch { } + + if (musicnumber == -1) + triggermob.Send(PlayMusic.GetInstance((MusicName)Enum.Parse(typeof(MusicName), musicstr[1], true))); + else + triggermob.Send(new XmlPlayMusic(musicnumber)); + } + } + } + catch { } + } + + public static void ResurrectPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) + { + status_str = null; + Item refitem = null; + Mobile refmob = null; + if (refobject is Item) + { + refitem = (Item)refobject; + } + else + if (refobject is Mobile) + { + refmob = (Mobile)refobject; + } + // syntax is RESURRECT[,range][,PETS] + // look for the range arg + string[] str = ParseString(arglist, 3, ","); + int range = 0; + bool petres = false; + + if (str.Length > 1) + { + + try + { + range = int.Parse(str[1]); + } + catch { status_str = "bad range arg in RESURRECT"; } + + } + if (str.Length > 2) + { + // get the range arg + if (str[2] == "PETS") + { + petres = true; + } + } + + try + { + if ((range > 0) || (triggermob != null && !triggermob.Deleted)) + { + // resurrect all players within range if range is > 0 + if (range > 0) + { + IPooledEnumerable rangelist = null; + if (refitem != null && !refitem.Deleted) + { + rangelist = refitem.GetMobilesInRange(range); + } + else if (refmob != null && !refmob.Deleted) + { + rangelist = refmob.GetMobilesInRange(range); + } + + if (rangelist != null) + { + foreach (Mobile p in rangelist) + { + if (!petres && p is PlayerMobile && p.Body.IsGhost) + { + p.Resurrect(); + } + else if (petres && p is BaseCreature && ((BaseCreature)p).ControlMaster == triggermob && ((BaseCreature)p).Controlled && ((BaseCreature)p).IsDeadPet) + { + ((BaseCreature)p).ResurrectPet(); + } + } + rangelist.Free(); + } + } + else + { + // just send it to the mob who triggered + if (triggermob.Body.IsGhost) + triggermob.Resurrect(); + + } + } + } + catch { } + } + + public static void ApplyPoisonToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) + { + status_str = null; + Item refitem = null; + Mobile refmob = null; + + if (refobject is Item) + { + refitem = (Item)refobject; + } + else if (refobject is Mobile) + { + refmob = (Mobile)refobject; + } + + // look for the other args + string[] str = ParseString(arglist, 4, ","); + bool playeronly = false; + int range = 0; + if (str.Length < 2) + { + status_str = "missing poisontype in POISON"; + } + if (str.Length > 2) + { + // get the range arg + try + { + range = int.Parse(str[2]); + } + catch { status_str = "bad range arg in POISON"; } + } + if (str.Length > 3) + { + if (str[3].ToLower() == "playeronly") playeronly = true; + } + try + { + if ((range > 0) || (triggermob != null && !triggermob.Deleted)) + { + // apply the poison to all players within range if range is > 0 + if (range > 0) + { + + IPooledEnumerable rangelist = null; + if (refitem != null && !refitem.Deleted) + { + rangelist = refitem.GetMobilesInRange(range); + + } + else if (refmob != null && !refmob.Deleted) + { + + rangelist = refmob.GetMobilesInRange(range); + + } + + if (rangelist != null) + { + foreach (Mobile p in rangelist) + { + + if (p is PlayerMobile || !playeronly) + p.ApplyPoison(p, Poison.Parse(str[1])); + } + rangelist.Free(); + } + } + else + { + // just apply it to the mob who triggered + triggermob.ApplyPoison(triggermob, Poison.Parse(str[1])); + + } + } + } + catch { } + } + + public static void ApplyDamageToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) + { + status_str = null; + Item refitem = null; + Mobile refmob = null; + if (refobject is Item) + { + refitem = (Item)refobject; + } + else if (refobject is Mobile) + { + refmob = (Mobile)refobject; + } + // look for the other args. Syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range][,playeronly] + string[] str = ParseString(arglist, 9, ","); + bool playeronly = false; + int range = -1; + if (str.Length < 7) + { + status_str = "missing damage args in DAMAGE"; + } + if (str.Length > 7) + { + // get the range arg + try + { + range = int.Parse(str[7]); + } + catch { status_str = "bad range arg in DAMAGE"; } + } + if (str.Length > 8) + { + if (str[8].ToLower() == "playeronly") playeronly = true; + } + // get the damage arguments + int damage = 0; + int phys = 0; + int fire = 0; + int cold = 0; + int pois = 0; + int ener = 0; + try + { + damage = int.Parse(str[1]); + phys = int.Parse(str[2]); + fire = int.Parse(str[3]); + cold = int.Parse(str[4]); + pois = int.Parse(str[5]); + ener = int.Parse(str[6]); + } + catch { status_str = "bad damage args in DAMAGE"; } + + try + { + if (range >= 0 || (triggermob != null && !triggermob.Deleted)) + { + // apply the poison to all players within range if range is > 0 + if (range >= 0) + { + IPooledEnumerable rangelist = null; + if (refitem != null && !refitem.Deleted) + { + rangelist = refitem.GetMobilesInRange(range); + } + else if (refmob != null && !refmob.Deleted) + { + rangelist = refmob.GetMobilesInRange(range); + } + + if (rangelist != null) + { + foreach (Mobile p in rangelist) + { + + if (p is PlayerMobile || !playeronly) + AOS.Damage(p, damage, phys, fire, cold, pois, ener); + } + rangelist.Free(); + } + } + else + { + // just apply it to the mob who triggered + AOS.Damage(triggermob, damage, phys, fire, cold, pois, ener); + + } + } + } + catch { } + } + + public static void SendBoltEffect(IEntity e, int sound, int hue) + { + Map map = e.Map; + + if (map == null) + return; + + if (e is Item) + ((Item)e).ProcessDelta(); + else if (e is Mobile) + ((Mobile)e).ProcessDelta(); + + Packet preEffect = null, boltEffect = null, playSound = null; + + IPooledEnumerable eable = map.GetClientsInRange(e.Location); + + foreach (NetState state in eable) + { + + if (Effects.SendParticlesTo(state)) + { + if (preEffect == null) + preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0)); + + state.Send(preEffect); + } + + if (boltEffect == null) + boltEffect = Packet.Acquire(new BoltEffect(e, hue)); + + state.Send(boltEffect); + + if (sound > 0) + { + if (playSound == null) + playSound = Packet.Acquire(new PlaySound(sound, e)); + + state.Send(playSound); + } + } + + Packet.Release(preEffect); + Packet.Release(boltEffect); + Packet.Release(playSound); + + eable.Free(); + } + + #endregion + + #region Spawn methods + + + public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + string propertyString, out string status_str) + { + AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, false, out status_str); + } + + public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + string propertyString, out string status_str) + { + AddSpawnItem(spawner, invoker, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, false, out status_str); + } + + public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + string propertyString, bool smartspawn, out string status_str) + { + AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, smartspawn, out status_str); + } + + public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + List spawnpositioning, string propertyString, out string status_str) + { + AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, false, out status_str); + } + + public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + List spawnpositioning, string propertyString, out string status_str) + { + AddSpawnItem(spawner, invoker, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, false, out status_str); + } + + public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + List spawnpositioning, string propertyString, bool smartspawn, out string status_str) + { + AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, smartspawn, out status_str); + } + + + public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, + List spawnpositioning, string propertyString, bool smartspawn, out string status_str) + { + + status_str = null; + if (item == null || theSpawn == null) return; + + // add the item to the spawned list + theSpawn.SpawnedObjects.Add(item); + + item.Spawner = spawner; + + if (spawner != null) + { + // this is being called by a spawner so use spawner information for placement + if (!spawner.Deleted) + { + // set the item amount + if (spawner.StackAmount > 1 && item.Stackable) + { + item.Amount = spawner.StackAmount; + } + // if this is in any container such as a pack then add to the container. + if (spawner.Parent is Container) + { + Container c = (Container)spawner.Parent; + + Point3D loc = spawner.Location; + + if (!smartspawn) + { + item.OnBeforeSpawn(loc, map); + } + + item.Location = loc; + + // check to see whether we drop or add the item based on the spawnrange + // this will distribute multiple items around the spawn point, and allow precise + // placement of single spawns at the spawn point + if (spawner.SpawnRange > 0) + c.DropItem(item); + else + c.AddItem(item); + + } + else + { + // if the spawn entry is in a subgroup and has a packrange, then get the packcoord + + Point3D packcoord = Point3D.Zero; + if (theSpawn.PackRange >= 0 && theSpawn.SubGroup > 0) + { + packcoord = spawner.GetPackCoord(theSpawn.SubGroup); + } + Point3D loc = spawner.GetSpawnPosition(requiresurface, theSpawn.PackRange, packcoord, spawnpositioning); + + if (!smartspawn) + { + item.OnBeforeSpawn(loc, map); + } + + // standard placement for all items in the world + item.MoveToWorld(loc, map); + } + } + else + { + // if the spawner has already been deleted then delete the item since it cannot be cleaned up by spawner deletion any longer + item.Delete(); + return; + } + } + else + { + if (!smartspawn) + { + item.OnBeforeSpawn(location, map); + } + // use the location and map info passed in + // this allows AddSpawnItem to be called by objects other than spawners as long as they pass in a valid SpawnObject + item.MoveToWorld(location, map); + } + + // clear the taken flag on all newly spawned items + ItemFlags.SetTaken(item, false); + + if (!smartspawn) + { + item.OnAfterSpawn(); + } + + // apply the parsed arguments from the typestring using setcommand + // be sure to do this after setting map and location so that errors dont place the mob on the internal map + BaseXmlSpawner.ApplyObjectStringProperties(spawner, propertyString, item, trigmob, spawner, out status_str); + + // if the object has an OnAfterSpawnAndModify method, then invoke it + //InvokeOnAfterSpawnAndModify(item); + + } + + /* + // hash table for optimizing OnAfterSpawnAndModify method invocation + private static Hashtable OnAfterSpawnAndModifyMethodHash; + + public static void InvokeOnAfterSpawnAndModify(object o) + { + if(o == null) return; + // try looking this up in the lookup table + if(OnAfterSpawnAndModifyMethodHash == null) + { + OnAfterSpawnAndModifyMethodHash = new Hashtable(); + } + MethodInfo minfo = null; + + if(!OnAfterSpawnAndModifyMethodHash.Contains(o.GetType())) + { + // not found so look it up the long way + minfo = o.GetType().GetMethod("OnAfterSpawnAndModify"); + + if(minfo != null) + { + ParameterInfo [] pinfo = minfo.GetParameters(); + // check to make sure the OnSpawned method for this object has the right args + if(pinfo.Length != 0) + { + minfo = null; + } + } + OnAfterSpawnAndModifyMethodHash.Add(o.GetType(),minfo); + } else + { + // look it up in the hash table + minfo = (MethodInfo) OnAfterSpawnAndModifyMethodHash[o.GetType()]; + } + try{ + if(minfo != null) + { + minfo.Invoke(o, null); + } + } catch {} + } + */ + + + public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, + Mobile triggermob, Point3D location, Map map, out string status_str) + { + return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, null, + triggermob, location, map, null, out status_str); + } + + public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, + Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str) + { + return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, null, + triggermob, location, map, gumpcallback, out status_str); + } + + public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, + List spawnpositioning, Mobile triggermob, Point3D location, Map map, out string status_str) + { + return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, spawnpositioning, + triggermob, location, map, null, out status_str); + } + + public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, + List spawnpositioning, Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str) + { + status_str = null; + + if (typeName == null || TheSpawn == null || substitutedtypeName == null) return false; + + XmlSpawner spawner = invoker as XmlSpawner; + + // check for any special keywords that might appear in the type such as SET, GIVE, or TAKE + + if (IsTypeKeyword(typeName)) + { + typeKeyword kw = (typeKeyword)typeKeywordHash[typeName]; + + switch (kw) + { + case typeKeyword.SET: + { + + // the syntax is SET/prop/value/prop2/value... + // check for the SET,itemname[,itemtype]/prop/value form is used + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string[] keywordargs = ParseString(arglist[0], 3, ","); + + if (keywordargs.Length > 1) + { + string typestr = null; + if (keywordargs.Length > 2) + { + typestr = keywordargs[2]; + } + + // is the itemname a serialno? + object setitem = null; + if (keywordargs[1].StartsWith("0x")) + { + int serial = -1; + try + { + serial = Convert.ToInt32(keywordargs[1], 16); + } + catch { } + if (serial >= 0) + setitem = World.FindEntity(serial); + } + else + { + // just look it up by name + setitem = FindItemByName(spawner, keywordargs[1], typestr); + } + + if (setitem == null) + { + status_str = "cant find unique item :" + keywordargs[1]; + return false; + } + else + { + ApplyObjectStringProperties(spawner, substitutedtypeName, setitem, triggermob, invoker, out status_str); + } + } + else if (spawner != null) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, spawner.SetItem, triggermob, invoker, out status_str); + } + + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONMOB: + { + // the syntax is SETONMOB,mobname[,mobtype]/prop/value/prop2/value... + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + Mobile mob = null; + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length > 1) + { + string typestr = null; + if (keywordargs.Length > 2) + { + typestr = keywordargs[2]; + } + + mob = FindMobileByName(spawner, keywordargs[1], typestr); + + if (mob == null) + { + status_str = String.Format("named mob '{0}' not found", keywordargs[1]); + } + } + else + { + status_str = "missing mob name in SETONMOB"; + } + } + if (mob != null) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, mob, triggermob, invoker, out status_str); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONTHIS: + { + // the syntax is SETONTHIS/prop/value/prop2/value... + //string [] arglist = ParseString(substitutedtypeName,3,"/"); + + if (invoker != null) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, invoker, triggermob, invoker, out status_str); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONTRIGMOB: + { + // the syntax is SETONTRIGMOB/prop/value/prop2/value... + ApplyObjectStringProperties(spawner, substitutedtypeName, triggermob, triggermob, invoker, out status_str); + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETACCOUNTTAG: + { + // the syntax is SETACCOUNTTAG,tagname/value + string[] arglist = ParseSlashArgs(substitutedtypeName, 2); + + if (arglist.Length > 1) + { + string[] objstr = ParseString(arglist[0], 2, ","); + + if (objstr.Length < 2) + { + status_str = "missing tagname in SETACCOUNTTAG"; + return false; + } + + string tagname = objstr[1]; + string tagval = arglist[1]; + + // set the tag value + // get the value of the account tag from the triggering mob + if (triggermob != null && !triggermob.Deleted) + { + Account acct = triggermob.Account as Account; + if (acct != null) + { + acct.SetTag(tagname, tagval); + } + } + } + else + { + status_str = "no value assigned to SETACCOUNTTAG"; + return false; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETVAR: + { + // the syntax is SETVAR,varname/value + + string[] arglist = ParseSlashArgs(substitutedtypeName, 2); + + if (arglist.Length > 1) + { + string[] objstr = ParseString(arglist[0], 2, ","); + + if (objstr.Length < 2) + { + status_str = "missing varname in SETVAR"; + return false; + } + + string varname = objstr[1]; + string varval = arglist[1]; + + // find the xmllocalvariable attachment with that name + XmlLocalVariable a = (XmlLocalVariable)XmlAttach.FindAttachment(invoker, typeof(XmlLocalVariable), varname); + + if (a == null) + { + // doesnt already exist so add it + XmlAttach.AttachTo(invoker, new XmlLocalVariable(varname, varval)); + + } + else + { + a.Data = varval; + } + } + else + { + status_str = "no value assigned to SETVAR"; + return false; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONNEARBY: + { + // the syntax is SETONNEARBY,range,name[,type][,searchcontainers][,proptest]/prop/value/prop/value... + + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string typestr = null; + string targetname = null; + string proptest = null; + int range = -1; + bool searchcontainers = false; + + if (arglist.Length > 0) + { + string[] objstr = ParseString(arglist[0], 6, ","); + if (objstr.Length < 3) + { + status_str = "missing range or name in SETONNEARBY"; + return false; + } + + try + { + range = int.Parse(objstr[1]); + } + catch { } + + if (range < 0) + { + status_str = "invalid range in SETONNEARBY"; + return false; + } + + targetname = objstr[2]; + + if (objstr.Length > 3) + { + typestr = objstr[3]; + } + + if (objstr.Length > 4) + { + try + { + searchcontainers = bool.Parse(objstr[4]); + } + catch { } + } + + if (objstr.Length > 5) + { + proptest = objstr[5]; + } + } + else + { + status_str = "missing args to SETONNEARBY"; + return false; + } + + Type targettype = null; + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + ArrayList nearbylist = GetNearbyObjects(invoker, targetname, targettype, typestr, range, searchcontainers, proptest); + + // apply the properties to everything on the list + foreach (object nearbyobj in nearbylist) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, nearbyobj, triggermob, invoker, out status_str); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONPETS: + { + // the syntax is SETONPETS,range/prop/value/prop/value... + + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string typestr = "BaseCreature"; + string targetname = null; + int range = -1; + bool searchcontainers = false; + + if (arglist.Length > 0) + { + string[] objstr = ParseString(arglist[0], 2, ","); + if (objstr.Length < 2) + { + status_str = "missing range or name in SETONPETS"; + return false; + } + + try + { + range = int.Parse(objstr[1]); + } + catch { } + + if (range < 0) + { + status_str = "invalid range in SETONPETS"; + return false; + } + + + } + else + { + status_str = "missing args to SETONPETS"; + return false; + } + + Type targettype = null; + + if (typestr != null) + { + targettype = SpawnerType.GetType(typestr); + } + + // get all of the nearby pets + ArrayList nearbylist = GetNearbyObjects(triggermob, targetname, targettype, typestr, range, searchcontainers, null); + + // apply the properties to everything on the list + foreach (object nearbyobj in nearbylist) + { + // is this a pet of the triggering mob + BaseCreature pet = nearbyobj as BaseCreature; + + if (pet != null && pet.Controlled && pet.ControlMaster == triggermob) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, nearbyobj, triggermob, invoker, out status_str); + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + + case typeKeyword.SETONCARRIED: + { + // the syntax is SETONCARRIED,itemname[,itemtype][,equippedonly]/prop/value/prop2/value... + // or SETONCARRIED,itemname[,itemtype]/prop/value + + // first find the carried item + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string typestr = null; + string itemname = null; + bool equippedonly = false; + + if (arglist.Length > 0) + { + string[] objstr = ParseString(arglist[0], 4, ","); + if (objstr.Length < 2) + { + status_str = "missing itemname in SETONCARRIED"; + return false; + } + + itemname = objstr[1]; + + if (objstr.Length > 2) + { + typestr = objstr[2]; + } + + if (objstr.Length > 3) + { + if (objstr[3].ToLower() == "equippedonly") + { + equippedonly = true; + } + else + { + try + { + equippedonly = bool.Parse(objstr[3]); + } + catch { } + } + } + } + else + { + status_str = "missing args to SETONCARRIED"; + return false; + } + + Item testitem = SearchMobileForItem(triggermob, ParseObjectType(itemname), typestr, false, equippedonly); + + ApplyObjectStringProperties(spawner, substitutedtypeName, testitem, triggermob, invoker, out status_str); + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONSPAWN: + { + // the syntax is SETONSPAWN[,spawnername],subgroup/prop/value/prop2/value... + // or SETONSPAWN[,spawnername],subgroup/prop/value + + // first find the spawn + int subgroup = -1; + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + XmlSpawner targetspawner = spawner; + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length < 2) + { + status_str = "missing subgroup in SETONSPAWN"; + return false; + } + else + { + string subgroupstr = keywordargs[1]; + string spawnerstr = null; + if (keywordargs.Length > 2) + { + spawnerstr = keywordargs[1]; + subgroupstr = keywordargs[2]; + } + if (spawnerstr != null) + { + targetspawner = FindSpawnerByName(spawner, spawnerstr); + } + try { subgroup = int.Parse(subgroupstr); } + catch { } + } + } + if (subgroup == -1) + { + status_str = "invalid subgroup in SETONSPAWN"; + return false; + } + + ArrayList spawnedlist = XmlSpawner.GetSpawnedList(targetspawner, subgroup); + if (spawnedlist == null) return true; + foreach (object targetobj in spawnedlist) + { + if (targetobj == null) return true; + + // dont apply it to keyword tags + if (targetobj is KeywordTag) continue; + + // set the properties on the target object + ApplyObjectStringProperties(spawner, substitutedtypeName, targetobj, triggermob, spawner, out status_str); + } + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONSPAWNENTRY: + { + // the syntax is SETONSPAWNENTRY[,spawnername],entrystring/prop/value/prop2/value... + + // find the spawn entry + string entrystring = null; + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + XmlSpawner targetspawner = spawner; + + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length < 2) + { + status_str = "missing entrystring in SETONSPAWNENTRY"; + return false; + } + else + { + entrystring = keywordargs[1]; + string spawnerstr = null; + if (keywordargs.Length > 2) + { + spawnerstr = keywordargs[1]; + entrystring = keywordargs[2]; + } + if (spawnerstr != null) + { + targetspawner = FindSpawnerByName(spawner, spawnerstr); + } + } + } + if (entrystring == null || entrystring.Length == 0) + { + status_str = "invalid entrystring in SETONSPAWNENTRY"; + return false; + } + + int entryindex = -1; + // is the entrystring a number? + if (entrystring[0] >= '0' && entrystring[0] <= '9') + { + try + { + entryindex = int.Parse(entrystring); + } + catch { } + + } + + if (targetspawner == null || targetspawner.SpawnObjects == null) return true; + + for (int i = 0; i < targetspawner.SpawnObjects.Length; i++) + { + XmlSpawner.SpawnObject targetobj = targetspawner.SpawnObjects[i]; + + // is this references by entrystring or entryindex? + if ((entryindex == i) + || (entryindex == -1 && targetobj != null && targetobj.TypeName != null && targetobj.TypeName.IndexOf(entrystring) >= 0)) + { + // set the properties on the spawn entry object + ApplyObjectStringProperties(spawner, substitutedtypeName, targetobj, triggermob, spawner, out status_str); + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SETONPARENT: + { + // the syntax is SETONPARENT/prop/value/prop2/value... + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + + if (invoker != null && (invoker is Item)) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, ((Item)invoker).Parent, triggermob, invoker, out status_str); + } + else if (invoker != null && (invoker is XmlAttachment)) + { + ApplyObjectStringProperties(spawner, substitutedtypeName, ((XmlAttachment)invoker).Attached, triggermob, invoker, out status_str); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.GIVE: + { + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + + string remainder; + if (arglist.Length > 1) + { + // check for any special keywords such as the additem option or the subproperty specification + // note this will be an arg to some property + string[] keywordargs = ParseString(arglist[0], 2, ","); + AddItemToTarget(spawner, triggermob, keywordargs, arglist, triggermob, invoker, false, out remainder, out status_str); + + } + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.TAKE: + { + // syntax TAKE[,prob[,quantity[,true,[type]]]]/itemname + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string targetName; + string typestr = null; + if (arglist.Length > 1) + { + targetName = arglist[1]; + } + else + { + status_str = "invalid TAKE specification"; + return false; + } + string[] keywordargs = ParseString(arglist[0], 5, ","); + double drop_probability = 1; + int quantity = 0; + bool banksearch = false; + Item savedItem = null; + if (keywordargs.Length > 1) + { + bool converterror = false; + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid TAKE probability : " + arglist[1]; converterror = true; } + if (converterror) return false; + } + if (keywordargs.Length > 2) + { + bool converterror = false; + try { quantity = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid TAKE quantity : " + arglist[1]; converterror = true; } + if (converterror) return false; + } + if (keywordargs.Length > 3) + { + bool converterror = false; + try { banksearch = bool.Parse(keywordargs[3]); } + catch { status_str = "Invalid TAKE bankflag : " + arglist[1]; converterror = true; } + if (converterror) return false; + } + if (keywordargs.Length > 4) + { + typestr = keywordargs[4]; + } + if (drop_probability == 1 || Utility.RandomDouble() < drop_probability) + { + // search the trigger mob for the named item + Item itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch); + + // found the item so get rid of it + if (itemTarget != null) + { + // if a quantity was specified and the item is stackable, then try to take the quantity + if (quantity > 0 && itemTarget.Stackable) + { + // create a copy of the stacked item to be saved + //savedItem = itemTarget.Dupe(0); + savedItem = Mobile.LiftItemDupe(itemTarget, itemTarget.Amount); + if (savedItem != null) + { + savedItem.Internalize(); + } + + int totaltaken = 0; + + int remaining = itemTarget.Amount - quantity; + if (remaining <= 0) + { + int taken = itemTarget.Amount; + totaltaken += taken; + + itemTarget.Delete(); + while (remaining < 0) + { + quantity -= taken; + // if didnt get the full amount then keep looking for other stacks + itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch); + if (itemTarget == null) break; + + remaining = itemTarget.Amount - quantity; + + if (remaining <= 0) + { + taken = itemTarget.Amount; + totaltaken += taken; + + itemTarget.Delete(); + } + else + { + totaltaken += quantity; + itemTarget.Amount = remaining; + } + } + } + else + { + totaltaken = quantity; + itemTarget.Amount = remaining; + } + + if (savedItem != null) + { + savedItem.Amount = totaltaken; + } + } + else + { + // dont save quest holders + if (itemTarget is XmlQuestBook || itemTarget is IXmlQuest) + { + itemTarget.Delete(); + } + else + savedItem = itemTarget; + } + + + // if the saved item was being held then release it otherwise the player can take it back + if (triggermob != null && triggermob.Holding == savedItem) + { + triggermob.Holding = null; + } + + XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(invoker, typeof(XmlSaveItem), "Taken"); + + if (si == null) + { + XmlAttach.AttachTo(invoker, new XmlSaveItem("Taken", savedItem, triggermob)); + } + else + { + si.SavedItem = savedItem; + si.WasOwnedBy = triggermob; + } + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.TAKEBYTYPE: + { + // syntax TAKEBYTYPE[,prob[,quantity[,true]]]/itemtype + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string targetName; + if (arglist.Length > 1) + { + targetName = arglist[1]; + } + else + { + status_str = "invalid TAKEBYTYPE specification"; + return false; + } + string[] keywordargs = ParseString(arglist[0], 4, ","); + double drop_probability = 1; + int quantity = 0; + bool banksearch = false; + Item savedItem = null; + + if (keywordargs.Length > 1) + { + bool converterror = false; + try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } + catch { status_str = "Invalid TAKEBYTYPE probability : " + arglist[1]; converterror = true; } + if (converterror) return false; + } + if (keywordargs.Length > 2) + { + bool converterror = false; + try { quantity = int.Parse(keywordargs[2]); } + catch { status_str = "Invalid TAKEBYTYPE quantity : " + arglist[1]; converterror = true; } + if (converterror) return false; + } + if (keywordargs.Length > 3) + { + bool converterror = false; + try { banksearch = bool.Parse(keywordargs[3]); } + catch { status_str = "Invalid TAKEBYTYPE bankflag : " + arglist[1]; converterror = true; } + if (converterror) return false; + } + if (drop_probability == 1 || Utility.RandomDouble() < drop_probability) + { + // search the trigger mob for the named item + Item itemTarget = SearchMobileForItemType(triggermob, targetName, banksearch); + + // found the item so get rid of it + if (itemTarget != null) + { + // if a quantity was specified and the item is stackable, then try to take the quantity + if (quantity > 0 && itemTarget.Stackable) + { + + // create a copy of the stacked item to be saved + //savedItem = itemTarget.Dupe(0); + savedItem = Mobile.LiftItemDupe(itemTarget, itemTarget.Amount); + if (savedItem != null) + { + savedItem.Internalize(); + } + + int totaltaken = 0; + + int remaining = itemTarget.Amount - quantity; + if (remaining <= 0) + { + int taken = itemTarget.Amount; + totaltaken += taken; + + itemTarget.Delete(); + + while (remaining < 0) + { + quantity -= taken; + // if didnt get the full amount then keep looking for other stacks + itemTarget = SearchMobileForItemType(triggermob, targetName, banksearch); + + if (itemTarget == null) break; + + remaining = itemTarget.Amount - quantity; + if (remaining <= 0) + { + taken = itemTarget.Amount; + totaltaken += taken; + + itemTarget.Delete(); + + } + else + { + totaltaken += quantity; + itemTarget.Amount = remaining; + } + } + } + else + { + + totaltaken = quantity; + itemTarget.Amount = remaining; + } + + if (savedItem != null) + { + savedItem.Amount = totaltaken; + } + } + else + { + // dont save quest holders + if (itemTarget is XmlQuestBook || itemTarget is XmlQuestHolder || itemTarget is XmlQuestToken) + { + itemTarget.Delete(); + } + else + savedItem = itemTarget; + } + } + + // is there an existing xmlsaveitem attachment + + XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(invoker, typeof(XmlSaveItem), "Taken"); + + if (si == null) + { + XmlAttach.AttachTo(invoker, new XmlSaveItem("Taken", savedItem, triggermob)); + } + else + { + si.SavedItem = savedItem; + si.WasOwnedBy = triggermob; + } + } + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.GUMP: + { + // the syntax is GUMP,title,type/string + // can alternatively accept a gump constructor name + // GUMP,title,type,constructorname/string + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + string gumpText; + if (arglist.Length > 1) + { + gumpText = arglist[1]; + } + else + { + status_str = "invalid GUMP specification"; + return false; + } + + string[] gumpkeywordargs = ParseString(arglist[0], 4, ","); + string gumpTitle = ""; + int gumpNumber = 0; // 0=simple text gump, 1=yes/no gump, 2=reply gump, 3=quest gump + + if (gumpkeywordargs.Length > 2) + { + gumpTitle = gumpkeywordargs[1]; + bool converterror = false; + try { gumpNumber = int.Parse(gumpkeywordargs[2]); } + catch { status_str = "Invalid GUMP args"; converterror = true; } + if (converterror) return false; + } + else + { + status_str = "invalid GUMP specification"; + return false; + } + string gumptypestr = "XmlSimpleGump"; // default gump constructor + + if (gumpkeywordargs.Length > 3) + { + // get the gump constructor type + gumptypestr = gumpkeywordargs[3].Trim(); + } + Type type = null; + if (gumptypestr != null) + { + try + { + type = SpawnerType.GetType(gumptypestr); + } + catch { } + } + if (type == null) + { + status_str = "invalid GUMP constructor : " + gumptypestr; + return false; + } + + // prepare the keyword tag for the gump + KeywordTag newtag = new KeywordTag(substitutedtypeName, spawner, 1); + if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile)) + { + object newgump = null; + object[] gumpargs = new object[7]; + gumpargs[0] = invoker; + gumpargs[1] = gumpText; + gumpargs[2] = gumpTitle; + gumpargs[3] = gumpNumber; + gumpargs[4] = newtag; + gumpargs[5] = triggermob; + gumpargs[6] = gumpcallback; + + //spawner.TriggerMob.SendGump( new XmlSimpleGump(this, gumpText,gumpTitle, gumpType )); + try + { + newgump = Activator.CreateInstance(type, gumpargs); + } + catch { status_str = "Error in creating gump type : " + gumptypestr; newtag.Delete(); return false; } + if (newgump != null) + { + if (newgump is Gump) + { + triggermob.SendGump((Gump)newgump); + } + else if (newgump is Item) + { + ((Item)newgump).Delete(); + status_str = gumptypestr + " is not a Gump type"; + newtag.Delete(); + return false; + } + else if (newgump is Mobile) + { + ((Mobile)newgump).Delete(); + status_str = gumptypestr + " is not a Gump type"; + newtag.Delete(); + return false; + } + else + { + status_str = gumptypestr + " is not a Gump type"; + newtag.Delete(); + return false; + } + } + } + TheSpawn.SpawnedObjects.Add(newtag); + + break; + } + case typeKeyword.BROWSER: + { + // the syntax is BROWSER/url + string[] arglist = ParseSlashArgs(substitutedtypeName, 2); + string url; + + if (arglist.Length > 1) + { + if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@') + { + url = arglist[1].Substring(1); + } + else + url = arglist[1]; + } + else + { + status_str = "invalid BROWSER specification"; + return false; + } + + if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile)) + { + triggermob.LaunchBrowser(url); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SENDMSG: + { + // the syntax is SENDMSG[,hue]/string + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + // check for literal + string msgText; + int hue = 0x3B2; + int font = 3; + + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 2, ","); + if (keywordargs.Length > 1) + { + try + { + hue = int.Parse(keywordargs[1]); + } + catch { status_str = "invalid hue arg to SENDMSG"; } + } + } + if (arglist.Length > 1) + { + if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@') + { + arglist = ParseSlashArgs(substitutedtypeName, 2); + msgText = arglist[1].Substring(1); + } + else + msgText = arglist[1]; + } + else + { + status_str = "invalid SENDMSG specification"; + return false; + } + if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile)) + { + //triggermob.SendMessage(msgText); + triggermob.Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "ENU", "System", msgText)); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SENDASCIIMSG: + { + // the syntax is SENDASCIIMSG[,hue][,font#]/string + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + // check for literal + string msgText; + int hue = 0x3B2; + int font = 3; + + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length > 1) + { + try + { + hue = int.Parse(keywordargs[1]); + } + catch { status_str = "invalid hue arg to SENDASCIIMSG"; } + } + if (keywordargs.Length > 2) + { + try + { + font = int.Parse(keywordargs[2]); + } + catch { status_str = "invalid font arg to SENDASCIIMSG"; } + } + } + if (arglist.Length > 1) + { + if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@') + { + arglist = ParseSlashArgs(substitutedtypeName, 2); + msgText = arglist[1].Substring(1); + } + else + msgText = arglist[1]; + } + else + { + status_str = "invalid SENDASCIIMSG specification"; + return false; + } + if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile)) + { + triggermob.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", msgText)); + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.WAITUNTIL: + { + // the syntax is WAITUNTIL[,delay][,timeout][/condition][/thendogroup] + string[] arglist = ParseSlashArgs(substitutedtypeName, 4); + double delay = 0; + double timeout = 0; + string condition = null; + int gotogroup = -1; + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length > 1) + { + try + { + delay = double.Parse(keywordargs[1]); + } + catch { status_str = "invalid delay arg to WAITUNTIL"; } + } + if (keywordargs.Length > 2) + { + try + { + timeout = double.Parse(keywordargs[2]); + } + catch { status_str = "invalid timeout arg to WAITUNTIL"; } + } + } + if (arglist.Length > 1) + { + condition = arglist[1]; + } + if (arglist.Length > 2) + { + try + { + gotogroup = int.Parse(arglist[2]); + } + catch { status_str = "invalid goto arg to WAITUNTIL"; } + } + if (status_str != null) + { + return false; + } + // suppress sequential advancement + //spawner.HoldSequence = true; + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner, TimeSpan.FromMinutes(delay), TimeSpan.FromMinutes(timeout), condition, gotogroup)); + + break; + } + case typeKeyword.WHILE: + { + // the syntax is WHILE/condition/dogroup + string[] arglist = ParseSlashArgs(substitutedtypeName, 4); + string condition = null; + int gotogroup = -1; + if (arglist.Length < 3) + { + status_str = "insufficient args to WHILE"; + } + else + { + condition = arglist[1]; + try + { + gotogroup = int.Parse(arglist[2]); + } + catch { status_str = "invalid dogroup arg to WHILE"; } + } + if (status_str != null) + { + return false; + } + // test the condition + if (TestItemProperty(spawner, spawner, condition, triggermob, out status_str)) + { + // try to spawn the dogroup + if (spawner != null && !spawner.Deleted) + { + if (gotogroup >= 0) + { + // spawn the subgroup + spawner.SpawnSubGroup(gotogroup); + + // advance the sequence to that group + //spawner.SequentialSpawn = gotogroup; + } + // and suppress sequential advancement + spawner.HoldSequence = true; + + } + + } + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.IF: + { + + // the syntax is IF/condition/thengroup [/elsegroup] + string[] arglist = ParseSlashArgs(substitutedtypeName, 5); + string condition = null; + int thengroup = -1; + int elsegroup = -1; + if (arglist.Length < 3) + { + status_str = "insufficient args to IF"; + } + else + { + condition = arglist[1]; + try + { + thengroup = int.Parse(arglist[2]); + } + catch { status_str = "invalid thengroup arg to IF"; } + } + if (arglist.Length > 3) + { + try + { + elsegroup = int.Parse(arglist[3]); + } + catch { status_str = "invalid elsegroup arg to IF"; } + } + + if (status_str != null) + { + return false; + } + + // test the condition + if (TestItemProperty(spawner, spawner, condition, triggermob, out status_str)) + { + // try to spawn the thengroup + if (thengroup >= 0 && spawner != null && !spawner.Deleted) + { + + // spawn the subgroup + spawner.SpawnSubGroup(thengroup); + + // advance the sequence to that group + //spawner.SequentialSpawn = thengroup; + } + // and suppress sequential advancement + //spawner.HoldSequence = true; + } + else + { + + // try to spawn the elsegroup + if (elsegroup >= 0 && spawner != null && !spawner.Deleted) + { + + // spawn the subgroup + spawner.SpawnSubGroup(elsegroup); + + // advance the sequence to that group + //spawner.SequentialSpawn = elsegroup; + } + // and suppress sequential advancement + //spawner.HoldSequence = true; + } + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.DESPAWN: + { + // the syntax is DESPAWN[,spawnername],subgroup + + // first find the spawner and group + int subgroup = -1; + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + XmlSpawner targetspawner = spawner; + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length < 2) + { + status_str = "missing subgroup in DESPAWN"; + return false; + } + else + { + string subgroupstr = keywordargs[1]; + string spawnerstr = null; + if (keywordargs.Length > 2) + { + spawnerstr = keywordargs[1]; + subgroupstr = keywordargs[2]; + } + if (spawnerstr != null) + { + targetspawner = FindSpawnerByName(spawner, spawnerstr); + } + try { subgroup = int.Parse(subgroupstr); } + catch { } + } + } + if (subgroup == -1) + { + status_str = "invalid subgroup in DESPAWN"; + return false; + } + + if (targetspawner != null) + { + targetspawner.ClearSubgroup(subgroup); + } + else + { + status_str = "invalid spawner in DESPAWN"; + return false; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SPAWN: + { + // the syntax is SPAWN[,spawnername],subgroup + + // first find the spawner and group + int subgroup = -1; + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + XmlSpawner targetspawner = spawner; + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length < 2) + { + status_str = "missing subgroup in SPAWN"; + return false; + } + else + { + string subgroupstr = keywordargs[1]; + string spawnerstr = null; + if (keywordargs.Length > 2) + { + spawnerstr = keywordargs[1]; + subgroupstr = keywordargs[2]; + } + if (spawnerstr != null) + { + targetspawner = FindSpawnerByName(spawner, spawnerstr); + } + try { subgroup = int.Parse(subgroupstr); } + catch { } + } + } + if (subgroup == -1) + { + status_str = "invalid subgroup in SPAWN"; + return false; + } + + if (targetspawner != null) + { + if (spawner != targetspawner) + { + // allow spawning of other spawners to be forced and ignore the normal loop protection + targetspawner.SpawnSubGroup(subgroup, false, true); + } + else + { + targetspawner.SpawnSubGroup(subgroup); + } + } + else + { + status_str = "invalid spawner in SPAWN"; + return false; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.GOTO: + { + // the syntax is GOTO/subgroup + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + int group = -1; + if (arglist.Length < 2) + { + status_str = "insufficient args to GOTO"; + } + else + { + try + { + group = int.Parse(arglist[1]); + } + catch { status_str = "invalid subgroup arg to GOTO"; } + } + if (status_str != null) + { + return false; + } + + // move the sequence to the specified subgroup + if (group >= 0 && spawner != null && !spawner.Deleted) + { + // note, this will activate sequential spawning if it wasnt already set + spawner.SequentialSpawn = group; + + // and suppress sequential advancement so that the specified group is the next to spawn + spawner.HoldSequence = true; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner, 2)); + + break; + } + case typeKeyword.COMMAND: + { + // the syntax is COMMAND/commandstring + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + // mod to use a dummy char to issue commands + if (CommandMobileName != null) + { + Mobile dummy = FindMobileByName(spawner, CommandMobileName, "Mobile"); + if (dummy != null) + { + CommandSystem.Handle(dummy, String.Format("{0}{1}", CommandSystem.Prefix, arglist[1])); + } + } + else + if (triggermob != null && !triggermob.Deleted) + { + CommandSystem.Handle(triggermob, String.Format("{0}{1}", CommandSystem.Prefix, arglist[1])); + } + + } + else + { + status_str = "insufficient args to COMMAND"; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.MUSIC: + { + // the syntax is MUSIC,name,range + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + SendMusicToPlayers(arglist[0], triggermob, invoker, out status_str); + if (status_str != null) + { + return false; + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.SOUND: + { + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + + if (arglist.Length > 0) + { + // Syntax is SOUND,soundnumber + string[] keywordargs = ParseString(arglist[0], 3, ","); + int sound = -1; + // try to get the soundnumber argument + if (keywordargs.Length < 2) + { + status_str = "Missing sound number"; + } + else + { + try + { + sound = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper sound number format"; } + } + if (sound >= 0 && invoker is IEntity) + { + Effects.PlaySound(((IEntity)invoker).Location, ((IEntity)invoker).Map, sound); + } + if (status_str != null) + { + return false; + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + // + // MEFFECT keyword + // + case typeKeyword.MEFFECT: + { + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 9, ","); + + if (keywordargs.Length < 9) + { + status_str = "Missing args"; + } + else + { + int effect = -1; + int duration = 0; + int speed = 1; + Point3D eloc1 = new Point3D(0, 0, 0); + Point3D eloc2 = new Point3D(0, 0, 0); + Map emap = Map.Internal; + + // syntax is MEFFECT,itemid,speed,x,y,z,x2,y2,z2 + + // try to get the effect argument + + try + { + effect = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper effect number format"; } + + try + { + speed = int.Parse(keywordargs[2]); + } + catch { status_str = "Improper effect speed format"; } + + + int x = 0; + int y = 0; + int z = 0; + try + { + x = int.Parse(keywordargs[3]); + y = int.Parse(keywordargs[4]); + z = int.Parse(keywordargs[5]); + } + catch { status_str = "Improper effect location format"; } + eloc1 = new Point3D(x, y, z); + + try + { + x = int.Parse(keywordargs[6]); + y = int.Parse(keywordargs[7]); + z = int.Parse(keywordargs[8]); + } + catch { status_str = "Improper effect location format"; } + eloc2 = new Point3D(x, y, z); + + + if (effect >= 0 && emap != Map.Internal) + { + Effects.SendPacket(eloc1, emap, new HuedEffect(EffectType.Moving, -1, -1, effect, eloc1, eloc2, speed, duration, false, false, 0, 0)); + } + } + if (status_str != null) + { + return false; + } + } + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + break; + } + case typeKeyword.EFFECT: + { + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (spawner == null || spawner.Deleted) return false; + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 6, ","); + int effect = -1; + int duration = 1; + // syntax is EFFECT,itemid,duration[,x,y,z] or EFFECT,itemid,duration[,trigmob] + // try to get the effect argument + // some interesting effects are explosion(14013,15), sparkle(14155,15), explosion2(14000,13) + if (keywordargs.Length < 3) + { + status_str = "Missing effect number and duration"; + } + else + { + try + { + effect = int.Parse(keywordargs[1]); + } + catch { status_str = "Improper effect number format"; } + try + { + duration = int.Parse(keywordargs[2]); + } + catch { status_str = "Improper effect duration format"; } + } + // by default just use the spawner location + Point3D eloc = spawner.Location; + Map emap = spawner.Map; + if (keywordargs.Length > 3) + { + // is this applied to the trig mob or to a location? + if (keywordargs.Length > 5) + { + int x = spawner.Location.X; + int y = spawner.Location.Y; + int z = spawner.Location.Z; + try + { + x = int.Parse(keywordargs[3]); + y = int.Parse(keywordargs[4]); + z = int.Parse(keywordargs[5]); + } + catch { status_str = "Improper effect location format"; } + eloc = new Point3D(x, y, z); + } + } + if (status_str != null) + { + return false; + } + if (effect >= 0) + { + Effects.SendLocationEffect(eloc, emap, effect, duration); + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.POISON: + { + // the syntax is POISON,name,range + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + ApplyPoisonToPlayers(arglist[0], triggermob, invoker, out status_str); + if (status_str != null) + { + return false; + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.DAMAGE: + { + // the syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range] + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + ApplyDamageToPlayers(arglist[0], triggermob, invoker, out status_str); + if (status_str != null) + { + return false; + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.RESURRECT: + { + // the syntax is RESURRECT[,range][,PETS] + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + ResurrectPlayers(arglist[0], triggermob, invoker, out status_str); + if (status_str != null) + { + return false; + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.CAST: + { + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + // Syntax is CAST,spellnumber[,arg] or CAST,spellname[,arg] + string[] keywordargs = ParseString(arglist[0], 3, ","); + int spellnumber = 0; + bool hasnumber = true; + // try it as spellnumber + if (keywordargs.Length > 1) + { + try { spellnumber = int.Parse(keywordargs[1]); } + catch { hasnumber = false; } + } + else + { + status_str = "invalid CAST specification"; + // note that returning true means that Spawn will assume that it worked and will not try to recast + return true; + } + // call this with the 3 argument version that includes the bodytype arg + int keywordarg2 = 0; + if (keywordargs.Length > 2) + { + try { keywordarg2 = int.Parse(keywordargs[2]); } + catch { } + } + + Spell spell = null; + + // the trigger mob will cast the spells + + Mobile caster = triggermob; + if (caster == null) + { + // note that returning true means that Spawn will assume that it worked and will not try to recast + return true; + } + + // make the placeholder wand to avoid reagent and mana use + BaseWand cwand = new ClumsyWand(); + cwand.Parent = caster; + + if (hasnumber) + { + spell = SpellRegistry.NewSpell(spellnumber, caster, cwand); + } + else + { + spell = SpellRegistry.NewSpell(keywordargs[1], caster, cwand); + } + if (spell != null) + { + bool casterror = false; + try + { + // deal with the 3 types of spells, mob targeted, location targeted, and self targeted + + // dont go through all of the warm up stuff, get right to the casting + spell.State = SpellState.Sequencing; + + Type spelltype = spell.GetType(); + // deal with any special cases here + if (spelltype == typeof(Server.Spells.Seventh.PolymorphSpell)) + { + if (keywordarg2 == 0) + { + // this is invalid so dont cast + throw (new ArgumentNullException()); + } + object[] polyargs = new object[3]; + polyargs[0] = caster; + polyargs[1] = cwand; + polyargs[2] = keywordarg2; + spell = (Spell)Activator.CreateInstance(spelltype, polyargs); + + if (spell == null) + { + throw (new ArgumentNullException()); + } + spell.State = SpellState.Sequencing; + } + MethodInfo spelltargetmethod = null; + + // get the targeting method from the spell + // note, the precedence is important as the target call should override oncast if it is present + if (spelltype != null && (spelltargetmethod = spelltype.GetMethod("Target")) != null) + { + + } + // if it doesnt have it then check for self targeted types + else if (spelltype != null && (spelltargetmethod = spelltype.GetMethod("OnCast")) != null) + { + + } + else + { + + throw (new ArgumentNullException()); + } + // Get the parameters for the target method. + ParameterInfo[] spelltargetparms = spelltargetmethod.GetParameters(); + // target will have one parm + // selftarg will have none + object[] targetargs = null; + // check the parameters + if (spelltargetparms != null && spelltargetparms.Length > 0) + { + if (spelltargetparms[0].ParameterType == typeof(Server.Mobile)) + { + // set the target parameter + targetargs = new object[1]; + targetargs[0] = triggermob; + } + else if (spelltargetparms[0].ParameterType == typeof(Server.IPoint3D)) + { + // set the target parameter + targetargs = new object[1]; + // pick a random point around the caster + int range = keywordarg2; + if (range == 0) range = 1; + int randx = Utility.RandomMinMax(-range, range); + int randy = Utility.RandomMinMax(-range, range); + if (randx == 0 && randy == 0) randx = 1; + targetargs[0] = new Point3D(triggermob.Location.X + randx, + triggermob.Location.Y + randy, + triggermob.Location.Z); + } + else + { + // dont handle any other types of args + throw (new ArgumentNullException()); + } + } + // set the spell on the caster + caster.Spell = spell; + // invoke the spell method with the appropriate args + spelltargetmethod.Invoke(spell, targetargs); + + // get rid of the placeholder wand + if (cwand != null && !cwand.Deleted) + cwand.Delete(); + } + catch + { + status_str = "bad spell call : " + spell.Name; + casterror = true; + // get rid of the placeholder wand + if (cwand != null && !cwand.Deleted) + cwand.Delete(); + } + + if (casterror) return true; + } + else + { + status_str = "spell invalid or disabled : " + keywordargs[1]; + + //return true; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + // note that returning true means that Spawn assume that it worked and will not try to recast + break; + } + case typeKeyword.BCAST: + { + // syntax is BCAST[,hue][,font]/message + + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + + int hue = 0x482; + int font = -1; + + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length > 1) + { + try + { + hue = int.Parse(keywordargs[1]); + } + catch { status_str = "invalid hue arg to BCAST"; } + } + if (keywordargs.Length > 2) + { + try + { + font = int.Parse(keywordargs[2]); + } + catch { status_str = "invalid font arg to BCAST"; } + } + } + + if (arglist.Length > 1) + { + string msg = arglist[1]; + if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@') + { + arglist = ParseSlashArgs(substitutedtypeName, 2); + msg = arglist[1].Substring(1); + } + if (font >= 0) + { + // broadcast an ascii message to all players + BroadcastAsciiMessage(AccessLevel.Player, hue, font, msg); + } + else + { + // standard unicode message format + CommandHandlers.BroadcastMessage(AccessLevel.Player, hue, msg); + } + + } + else + { + status_str = "missing msg arg in BCAST"; + return false; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case typeKeyword.BSOUND: + { + // syntax is BSOUND,soundid + + string[] arglist = ParseSlashArgs(substitutedtypeName, 3); + + int soundid = -1; + + if (arglist.Length > 0) + { + string[] keywordargs = ParseString(arglist[0], 2, ","); + if (keywordargs.Length > 1) + { + try + { + soundid = int.Parse(keywordargs[1]); + } + catch { status_str = "invalid soundid arg to BSOUND"; } + } + + if (soundid >= 0) + { + // broadcast a sound to all players + BroadcastSound(AccessLevel.Player, soundid); + } + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + default: + { + status_str = "unrecognized keyword"; + // should never get here + break; + } + } + // indicate successful keyword spawn + return true; + } + else + if (IsSpecialItemKeyword(typeName)) + { + // these are special keyword item drops + string[] arglist = ParseSlashArgs(substitutedtypeName, 2); + string itemtypestr = arglist[0]; + string baseitemtype = typeName; + + // itemtypestr will have the form keyword[,x[,y]] + string[] itemkeywordargs = ParseString(itemtypestr, 3, ","); + + // deal with the special keywords + itemKeyword kw = (itemKeyword)itemKeywordHash[baseitemtype]; + + switch (kw) + { + case itemKeyword.ARMOR: + { + // syntax is ARMOR,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid ARMOR args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid ARMOR args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicArmor(min, max, false, false); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "ARMOR takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.WEAPON: + { + // syntax is WEAPON,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid WEAPON args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid WEAPON args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicWeapon(min, max, false); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "WEAPON takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.JARMOR: + { + // syntax is JARMOR,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid JARMOR args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid JARMOR args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicArmor(min, max, true, true); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "JARMOR takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.JWEAPON: + { + // syntax is JWEAPON,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid JWEAPON args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid JWEAPON args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicWeapon(min, max, true); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "JWEAPON takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.SARMOR: + { + // syntax is SARMOR,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid SARMOR args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid SARMOR args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicArmor(min, max, false, true); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "SARMOR takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.SHIELD: + { + // syntax is SHIELD,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid SHIELD args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid SHIELD args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicShield(min, max); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "SHIELD takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.JEWELRY: + { + // syntax is JEWELRY,min,max + //get the min,max + if (itemkeywordargs.Length == 3) + { + int min = 0; + int max = 0; + bool converterror = false; + try { min = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid JEWELRY args : " + itemtypestr; converterror = true; } + try { max = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid JEWELRY args : " + itemtypestr; converterror = true; } + if (converterror) return false; + Item item = MagicJewelry(min, max); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "JEWELRY takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.ITEM: + { + // syntax is ITEM,serial + if (itemkeywordargs.Length == 2) + { + int serial = -1; + bool converterror = false; + try { serial = Convert.ToInt32(itemkeywordargs[1], 16); } + catch { status_str = "Invalid ITEM args : " + itemtypestr; converterror = true; } + + if (converterror) return false; + + Item item = World.FindItem(serial); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "ITEM takes 1 arg : " + itemtypestr; + return false; + } + + break; + } + case itemKeyword.SCROLL: + { + // syntax is SCROLL,mincircle,maxcircle + //get the min,max + if (itemkeywordargs.Length == 3) + { + int minCircle = 0; + int maxCircle = 0; + bool converterror = false; + try { minCircle = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid SCROLL args : " + itemtypestr; converterror = true; } + try { maxCircle = int.Parse(itemkeywordargs[2]); } + catch { status_str = "Invalid SCROLL args : " + itemtypestr; converterror = true; } + if (converterror) return false; + int circle = Utility.RandomMinMax(minCircle, maxCircle); + int min = (circle - 1) * 8; + Item item = Loot.RandomScroll(min, min + 7, SpellbookType.Regular); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "SCROLL takes 2 args : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.LOOT: + { + // syntax is LOOT,methodname + if (itemkeywordargs.Length == 2) + { + Item item = null; + + // look up the method + Type ltype = typeof(Loot); + if (ltype != null) + { + MethodInfo method = null; + + try + { + // get the zero arg method with the specified name + method = ltype.GetMethod(itemkeywordargs[1], new Type[0]); + } + catch { } + + if (method != null && method.IsStatic) + { + ParameterInfo[] pinfo = method.GetParameters(); + // check to make sure the method for this object has the right args + if (pinfo.Length == 0) + { + // method must be public static with no arguments returning an Item class object + try + { + item = method.Invoke(null, null) as Item; + } + catch { } + } + else + { + status_str = "LOOT method must be zero arg : " + itemtypestr; + return false; + } + } + else + { + status_str = "LOOT no valid method found : " + itemtypestr; + return false; + } + } + + + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "LOOT takes 1 arg : " + itemtypestr; + return false; + } + break; + } + case itemKeyword.POTION: + { + // syntax is POTION + Item item = Loot.RandomPotion(); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + break; + } + case itemKeyword.TAKEN: + { + // syntax is TAKEN + // find the XmlSaveItem attachment + + Item item = GetTaken(invoker); + + if (item != null) + { + AddSpawnItem(spawner, invoker, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + break; + } + case itemKeyword.GIVEN: + { + // syntax is GIVEN + // find the XmlSaveItem attachment + + Item item = GetGiven(invoker); + + if (item != null) + { + AddSpawnItem(spawner, invoker, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + break; + } + + /* case itemKeyword.NECROSCROLL: + { + // syntax is NECROSCROLL,index + if (itemkeywordargs.Length == 2) + { + int necroindex = 0; + bool converterror = false; + try { necroindex = int.Parse(itemkeywordargs[1]); } + catch { status_str = "Invalid NECROSCROLL args : " + itemtypestr; converterror = true; } + if (converterror) return false; + if (Core.AOS) + { + Item item = Loot.Construct(Loot.NecromancyScrollTypes, necroindex); + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + } + else + { + status_str = "NECROSCROLL takes 1 arg : " + itemtypestr; + return false; + } + break; + + }*/ + case itemKeyword.MULTIADDON: + { + // syntax is MULTIADDON,filename + if (itemkeywordargs.Length == 2) + { + string filename = itemkeywordargs[1]; + + // read in the multi.txt file + + Item item = XmlSpawnerAddon.ReadMultiFile(filename, out status_str); + + if (item != null) + { + AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); + } + } + else + { + status_str = "MULTIADDON takes 1 arg : " + itemtypestr; + return false; + } + break; + } + default: + { + status_str = "unrecognized keyword"; + // should never get here + break; + } + } + + return true; + } + else + { + // should never get here + status_str = "unrecognized keyword"; + return false; + } + } + + #endregion + } +} + diff --git a/Scripts/Customs/XML Spawner/Instructions for importing maps.txt b/Scripts/Customs/XML Spawner/Instructions for importing maps.txt new file mode 100644 index 0000000..cd6a042 --- /dev/null +++ b/Scripts/Customs/XML Spawner/Instructions for importing maps.txt @@ -0,0 +1,24 @@ +If you would like to import maps that have been saved in either the .map or .msf file formats, here are some step-by-step instructions + +1) unzip the package like Neruns +2) find the directory containing the .map files (e.g. Data/Monsters) +3) while ingame, type the command "[xmlimportmap Data/Monsters" + +that will instantly read all of the spawner definitions in all .map files under the Data/Monsters directory and load them as xmlspawners. + +For cwards .msf maps, do exactly the same thing except use the [xmlimportmsf command instead of [xmlimportmap + + +note that you can also use SpawnEditor2 to import maps. + +1) open the Files menu, and select "Import .map file" +2) select a .map file from the file browser +3) repeat for other .map files that you want to import + +(same procedure for .msf, just use the "Import .msf file" option) + +4) Once you have loaded in your converted .map or .msf files, you can save them out to XML by hitting the 'Save' button in the spawner selection panel in the main editor window. +5) You can then load this XML file while ingame by using the "[xmlload filename" command. + +You can also send the converted spawners directly to a live server if you have the TransferServer installed by just hitting the 'Send to Server' button while in SpawnEditor2 +Also note, if you sent them and then decided that you wanted to 'unsend' them, you can just right click that button and select 'Unload spawners from server' instead. \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/ItemFlags.cs b/Scripts/Customs/XML Spawner/ItemFlags.cs new file mode 100644 index 0000000..647058e --- /dev/null +++ b/Scripts/Customs/XML Spawner/ItemFlags.cs @@ -0,0 +1,156 @@ +using System; +using System.Text; +using Server; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Items +{ + public class ItemFlags + { + public const int StealableFlag = 0x00200000; + public const int TakenFlag = 0x00100000; + + public static void Initialize() + { + CommandSystem.Register( "Stealable", AccessLevel.GameMaster, new CommandEventHandler( SetStealable_OnCommand ) ); + CommandSystem.Register( "Flag", AccessLevel.GameMaster, new CommandEventHandler( GetFlag_OnCommand ) ); + } + + public static void SetStealable(Item target, bool value) + { + if(target != null) + target.SetSavedFlag( StealableFlag, value); + } + + public static bool GetStealable(Item target) + { + if(target != null) + return target.GetSavedFlag(StealableFlag); + else + return false; + } + + public static void SetTaken(Item target, bool value) + { + if(target != null) + { + target.SetSavedFlag( TakenFlag, value); + } + } + + public static bool GetTaken(Item target) + { + if(target != null) + return target.GetSavedFlag(TakenFlag); + else + return false; + } + + [Usage( "Flag flagfield" )] + [Description( "Gets the state of the specified SavedFlag on any item" )] + public static void GetFlag_OnCommand( CommandEventArgs e ) + { + int flag=0; + bool error = false; + if( e.Arguments.Length > 0 ) + { + if(e.Arguments[0].StartsWith( "0x" )) + { + try{flag = Convert.ToInt32( e.Arguments[0].Substring( 2 ), 16 ); } catch { error = true;} + } else + { + try{flag = int.Parse(e.Arguments[0]); } catch { error = true;} + } + + } + if(!error) + { + e.Mobile.Target = new GetFlagTarget(e,flag); + } else + { + try{ + e.Mobile.SendMessage(33,"Flag: Bad flagfield argument"); + } catch {} + } + } + + private class GetFlagTarget : Target + { + private CommandEventArgs m_e; + private int m_flag; + + public GetFlagTarget( CommandEventArgs e, int flag) : base ( 30, false, TargetFlags.None ) + { + m_e = e; + m_flag = flag; + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(targeted is Item) + { + bool state = ((Item)targeted).GetSavedFlag(m_flag); + + from.SendMessage("Flag (0x{0:X}) = {1}",m_flag,state); + } else + { + from.SendMessage("Must target an Item"); + } + } + } + + + [Usage( "Stealable [true/false]" )] + [Description( "Sets/gets the stealable flag on any item" )] + public static void SetStealable_OnCommand( CommandEventArgs e ) + { + bool state = false; + bool error = false; + if( e.Arguments.Length > 0 ){ + try{state = bool.Parse(e.Arguments[0]); } catch { error = true;} + + } + if(!error) + { + e.Mobile.Target = new SetStealableTarget(e, state); + } + + } + + private class SetStealableTarget : Target + { + private CommandEventArgs m_e; + private bool m_state; + private bool set = false; + + public SetStealableTarget( CommandEventArgs e, bool state) : base ( 30, false, TargetFlags.None ) + { + m_e = e; + m_state = state; + if( e.Arguments.Length > 0 ) + { + set = true; + } + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(targeted is Item) + { + if(set) + { + SetStealable(((Item)targeted), m_state); + } + + bool state = GetStealable((Item)targeted); + + from.SendMessage("Stealable = {0}",state); + + } else + { + from.SendMessage("Must target an Item"); + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/PacketHandlerOverrides.cs b/Scripts/Customs/XML Spawner/PacketHandlerOverrides.cs new file mode 100644 index 0000000..d087747 --- /dev/null +++ b/Scripts/Customs/XML Spawner/PacketHandlerOverrides.cs @@ -0,0 +1,65 @@ +#define CLIENT6017 + +using System; +using System.IO; +using System.Text; +using Server; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; + + +namespace Server.Engines.XmlSpawner2 +{ + + public class PacketHandlerOverrides + { + public static void Initialize() + { + // + // this will replace the default packet handlers with XmlSpawner2 versions. + // The delay call is to make sure they are assigned after the core default assignments. + // + // If you dont want these packet handler overrides to be applied, just comment them out here. + // + + // This will replace the default packet handler for basebooks content change. This allows the + // use of the text entry book interface for editing spawner entries. + // Regular BaseBooks will still call their default handlers for ContentChange and HeaderChange + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(ContentChangeOverride)); + + // this replaces the default packet handler for Use requests. Items and Mobiles will still + // behave exactly the same way, it simply adds a hook in to call the OnUse method for attachments + // they might have. + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( UseReqOverride ) ); + + // This will REPLACE the default packet handler called when the quest button on the paperdoll is pressed with the xmlquest gump. + //Timer.DelayCall(TimeSpan.Zero, new TimerCallback(QuestButtonOverride)); + // This will ADD the xmlquest gump to the default packet handler called when the quest button on the paperdoll is pressed. + EventSink.QuestGumpRequest += new QuestGumpRequestHandler(XmlQuest.QuestButton); + + } + + public static void ContentChangeOverride() + { + PacketHandlers.Register(0x66, 0, true, new OnPacketReceive(XmlTextEntryBook.ContentChange)); +#if(CLIENT6017) + PacketHandlers.Register6017(0x66, 0, true, new OnPacketReceive(XmlTextEntryBook.ContentChange)); +#endif + } + + public static void UseReqOverride() + { + PacketHandlers.Register(0x06, 5, true, new OnPacketReceive(XmlAttach.UseReq)); +#if(CLIENT6017) + PacketHandlers.Register6017(0x06, 5, true, new OnPacketReceive(XmlAttach.UseReq)); +#endif + } + + public static void QuestButtonOverride() + { + PacketHandlers.RegisterEncoded( 0x32, true, new OnEncodedPacketReceive( XmlQuest.QuestButton ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/XmlAttach/XmlAttach.cs b/Scripts/Customs/XML Spawner/XmlAttach/XmlAttach.cs new file mode 100644 index 0000000..47332ef --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttach/XmlAttach.cs @@ -0,0 +1,2529 @@ +using System; +using System.Text; +using Server; +using Server.Commands; +using Server.Commands.Generic; +using Server.Network; +using System.Collections; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Targeting; +using CPA = Server.CommandPropertyAttribute; +using System.Reflection; +using Server.Gumps; +using Server.Items; +using System.IO; +using System.Diagnostics; +using Server.Accounting; +using System.Net.Mail; +using Server.Misc; +using Server.ContextMenus; + +namespace Server.Engines.XmlSpawner2 +{ + + [AttributeUsage(AttributeTargets.Constructor)] + public class Attachable : Attribute + { + public Attachable() + { + } + } + + public class ASerial + { + + private int m_SerialValue; + + public int Value { get { return m_SerialValue; } } + + public ASerial(int serial) + { + m_SerialValue = serial; + } + + private static int m_GlobalSerialValue; + + public static bool serialInitialized = false; + + public static ASerial NewSerial() + { + // it is possible for new attachments to be constructed before existing attachments are deserialized and the current m_globalserialvalue + // restored. This creates a possible serial conflict, so dont allow assignment of valid serials until proper deser of m_globalserialvalue + // Resolve unassigned serials in initialization + if (!serialInitialized) return new ASerial(0); + + if (m_GlobalSerialValue == int.MaxValue || m_GlobalSerialValue < 0) m_GlobalSerialValue = 0; + + // try the next serial number in the series + int newserialno = m_GlobalSerialValue + 1; + + // check to make sure that it is not in use + while (XmlAttach.AllAttachments.Contains(newserialno)) + { + newserialno++; + if (newserialno == int.MaxValue || newserialno < 0) newserialno = 1; + } + + m_GlobalSerialValue = newserialno; + + return new ASerial(m_GlobalSerialValue); + } + + internal static void GlobalSerialize(GenericWriter writer) + { + writer.Write(m_GlobalSerialValue); + } + + internal static void GlobalDeserialize(GenericReader reader) + { + m_GlobalSerialValue = reader.ReadInt(); + } + } + + public class XmlAttach + { + + private static Type m_AttachableType = typeof(Attachable); + + public static bool IsAttachable(ConstructorInfo ctor) + { + return ctor.IsDefined(m_AttachableType, false); + } + + + public static void HashSerial(ASerial key, object o) + { + if (key.Value != 0) + { + AllAttachments.Add(key.Value, o); + } + else + { + UnassignedAttachments.Add(o); + } + } + + // each entry in the hashtable is an array of XmlAttachments that is keyed by an object. + public static Hashtable ItemAttachments = new Hashtable(); // keyed by item + public static Hashtable MobileAttachments = new Hashtable(); // keyed by mobile + public static Hashtable AllAttachments = new Hashtable(); // keyed by attachment serial + private static ArrayList UnassignedAttachments = new ArrayList(); + + public static bool HasAttachments(object o) + { + if (o == null) return false; + + if (o is Item && ItemAttachments.Contains(o)) + { + ArrayList alist = (ArrayList)ItemAttachments[o]; + // see if the attachment list is empty + if (alist == null || alist.Count == 0) return false; + + // check to see if there are any valid attachments in the list + foreach (XmlAttachment a in alist) + { + if (!a.Deleted) return true; + } + + return false; + } + + if (o is Mobile && MobileAttachments.Contains(o)) + { + ArrayList alist = (ArrayList)MobileAttachments[o]; + // see if the attachment list is empty + if (alist == null || alist.Count == 0) return false; + + // check to see if there are any valid attachments in the list + foreach (XmlAttachment a in alist) + { + if (!a.Deleted) return true; + } + + return false; + } + + return false; + } + + public static object[] Values + { + get + { + object[] valuearray = new object[XmlAttach.AllAttachments.Count]; + XmlAttach.AllAttachments.Values.CopyTo(valuearray, 0); + return valuearray; + } + } + + public static void Configure() + { + EventSink.WorldLoad += new WorldLoadEventHandler(Load); + EventSink.WorldSave += new WorldSaveEventHandler(Save); + } + + public static void Initialize() + { + ASerial.serialInitialized = true; + + // resolve unassigned serials + foreach (XmlAttachment a in UnassignedAttachments) + { + // get the next unique serial id + ASerial serial = ASerial.NewSerial(); + a.Serial = serial; + + // register the attachment in the serial keyed hashtable + XmlAttach.HashSerial(serial, a); + } + + // Register our speech handler + EventSink.Speech += new SpeechEventHandler(EventSink_Speech); + + // Register our movement handler + EventSink.Movement += new MovementEventHandler(EventSink_Movement); + + //CommandSystem.Register( "ItemAtt", AccessLevel.GameMaster, new CommandEventHandler( ListItemAttachments_OnCommand ) ); + //CommandSystem.Register( "MobAtt", AccessLevel.GameMaster, new CommandEventHandler( ListMobileAttachments_OnCommand ) ); + CommandSystem.Register("GetAtt", AccessLevel.GameMaster, new CommandEventHandler(GetAttachments_OnCommand)); + //CommandSystem.Register( "DelAtt", AccessLevel.GameMaster, new CommandEventHandler( DeleteAttachments_OnCommand ) ); + //CommandSystem.Register( "TrigAtt", AccessLevel.GameMaster, new CommandEventHandler( ActivateAttachments_OnCommand ) ); + //CommandSystem.Register( "AddAtt", AccessLevel.GameMaster, new CommandEventHandler( AddAttachment_OnCommand ) ); + TargetCommands.Register(new AddAttCommand()); + TargetCommands.Register(new DelAttCommand()); + CommandSystem.Register("AvailAtt", AccessLevel.GameMaster, new CommandEventHandler(ListAvailableAttachments_OnCommand)); + } + + public class AddAttCommand : BaseCommand + { + public AddAttCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.All; + Commands = new string[] { "AddAtt" }; + ObjectTypes = ObjectTypes.Both; + Usage = "AddAtt type [args]"; + Description = "Adds an attachment to the targeted object."; + ListOptimized = true; + } + + public override bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + return true; + + e.Mobile.SendMessage("Usage: " + Usage); + return false; + } + + public override void ExecuteList(CommandEventArgs e, ArrayList list) + { + if (e != null && list != null && e.Length >= 1) + { + + // create a new attachment and add it to the item + int nargs = e.Arguments.Length - 1; + + string[] args = new string[nargs]; + + for (int j = 0; j < nargs; j++) + { + args[j] = (string)e.Arguments[j + 1]; + } + + Type attachtype = SpawnerType.GetType(e.Arguments[0]); + + if (attachtype != null && attachtype.IsSubclassOf(typeof(XmlAttachment))) + { + + // go through all of the objects in the list + int count = 0; + + for (int i = 0; i < list.Count; ++i) + { + + XmlAttachment o = (XmlAttachment)XmlSpawner.CreateObject(attachtype, args, false, true); + + if (o == null) + { + AddResponse(String.Format("Unable to construct {0} with specified args", attachtype.Name)); + break; + } + + if (XmlAttach.AttachTo(null, list[i], o, true)) + { + if (list.Count < 10) + { + AddResponse(String.Format("Added {0} to {1}", attachtype.Name, list[i])); + } + count++; + } + else + LogFailure(String.Format("Attachment {0} not added to {1}", attachtype.Name, list[i])); + + } + if (count > 0) + { + AddResponse(String.Format("Attachment {0} has been added [{1}]", attachtype.Name, count)); + } + else + { + AddResponse(String.Format("Attachment {0} not added", attachtype.Name)); + } + } + else + { + AddResponse(String.Format("Invalid attachment type {0}", e.Arguments[0])); + } + } + } + } + + public class DelAttCommand : BaseCommand + { + public DelAttCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.All; + Commands = new string[] { "DelAtt" }; + ObjectTypes = ObjectTypes.Both; + Usage = "DelAtt type"; + Description = "Deletes an attachment on the targeted object."; + ListOptimized = true; + } + + public override bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + return true; + + e.Mobile.SendMessage("Usage: " + Usage); + return false; + } + + public override void ExecuteList(CommandEventArgs e, ArrayList list) + { + if (e != null && list != null && e.Length >= 1) + { + + Type attachtype = SpawnerType.GetType(e.Arguments[0]); + + if (attachtype != null && attachtype.IsSubclassOf(typeof(XmlAttachment))) + { + + // go through all of the objects in the list + int count = 0; + + for (int i = 0; i < list.Count; ++i) + { + ArrayList alist = XmlAttach.FindAttachments(list[i], attachtype); + + if (alist != null) + { + // delete the attachments + foreach (XmlAttachment a in alist) + { + a.Delete(); + if (list.Count < 10) + { + AddResponse(String.Format("Deleted {0} from {1}", attachtype.Name, list[i])); + } + count++; + } + } + } + + if (count > 0) + { + AddResponse(String.Format("Attachment {0} has been deleted [{1}]", attachtype.Name, count)); + } + else + { + AddResponse(String.Format("Attachment {0} not deleted", attachtype.Name)); + } + } + else + { + AddResponse(String.Format("Invalid attachment type {0}", e.Arguments[0])); + } + } + } + } + + public static void CleanUp() + { + // clean up any unowned attachments + foreach (XmlAttachment a in XmlAttach.Values) + { + if (a.OwnedBy == null || (a.OwnedBy is Mobile && ((Mobile)a.OwnedBy).Deleted) || (a.OwnedBy is Item && ((Item)a.OwnedBy).Deleted)) + { + a.Delete(); + } + } + } + + public static void Save(WorldSaveEventArgs e) + { + if (XmlAttach.MobileAttachments == null && XmlAttach.ItemAttachments == null) return; + + CleanUp(); + + if (!Directory.Exists("Saves/Attachments")) + Directory.CreateDirectory("Saves/Attachments"); + + string filePath = Path.Combine("Saves/Attachments", "Attachments.bin"); // the attachment serializations + string imaPath = Path.Combine("Saves/Attachments", "Attachments.ima"); // the item/mob attachment tables + string fpiPath = Path.Combine("Saves/Attachments", "Attachments.fpi"); // the file position indices + + BinaryFileWriter writer = null; + BinaryFileWriter imawriter = null; + BinaryFileWriter fpiwriter = null; + + try + { + writer = new BinaryFileWriter(filePath, true); + imawriter = new BinaryFileWriter(imaPath, true); + fpiwriter = new BinaryFileWriter(fpiPath, true); + + } + catch (Exception err) + { + ErrorReporter.GenerateErrorReport(err.ToString()); + return; + } + + if (writer != null && imawriter != null && fpiwriter != null) + { + // save the current global attachment serial state + ASerial.GlobalSerialize(writer); + + // remove all deleted attachments + XmlAttach.FullDefrag(); + + // save the attachments themselves + if (XmlAttach.AllAttachments != null) + { + writer.Write(XmlAttach.AllAttachments.Count); + + object[] valuearray = new object[XmlAttach.AllAttachments.Count]; + XmlAttach.AllAttachments.Values.CopyTo(valuearray, 0); + + object[] keyarray = new object[XmlAttach.AllAttachments.Count]; + XmlAttach.AllAttachments.Keys.CopyTo(keyarray, 0); + + for (int i = 0; i < keyarray.Length; i++) + { + // write the key + writer.Write((int)keyarray[i]); + + XmlAttachment a = valuearray[i] as XmlAttachment; + + // write the value type + writer.Write((string)a.GetType().ToString()); + + // serialize the attachment itself + a.Serialize(writer); + + // save the fileposition index + fpiwriter.Write((long)writer.Position); + } + } + else + { + writer.Write((int)0); + } + + writer.Close(); + + // save the hash table info for items and mobiles + // mobile attachments + if (XmlAttach.MobileAttachments != null) + { + imawriter.Write(XmlAttach.MobileAttachments.Count); + + object[] valuearray = new object[XmlAttach.MobileAttachments.Count]; + XmlAttach.MobileAttachments.Values.CopyTo(valuearray, 0); + + object[] keyarray = new object[XmlAttach.MobileAttachments.Count]; + XmlAttach.MobileAttachments.Keys.CopyTo(keyarray, 0); + + for (int i = 0; i < keyarray.Length; i++) + { + // write the key + imawriter.Write((Mobile)keyarray[i]); + + // write out the attachments + ArrayList alist = (ArrayList)valuearray[i]; + + imawriter.Write((int)alist.Count); + foreach (XmlAttachment a in alist) + { + // write the attachment serial + imawriter.Write((int)a.Serial.Value); + + // write the value type + imawriter.Write((string)a.GetType().ToString()); + + // save the fileposition index + fpiwriter.Write((long)imawriter.Position); + } + } + } + else + { + // no mobile attachments + imawriter.Write((int)0); + } + + // item attachments + if (XmlAttach.ItemAttachments != null) + { + imawriter.Write(XmlAttach.ItemAttachments.Count); + + object[] valuearray = new object[XmlAttach.ItemAttachments.Count]; + XmlAttach.ItemAttachments.Values.CopyTo(valuearray, 0); + + object[] keyarray = new object[XmlAttach.ItemAttachments.Count]; + XmlAttach.ItemAttachments.Keys.CopyTo(keyarray, 0); + + for (int i = 0; i < keyarray.Length; i++) + { + // write the key + imawriter.Write((Item)keyarray[i]); + + // write out the attachments + ArrayList alist = (ArrayList)valuearray[i]; + + imawriter.Write((int)alist.Count); + foreach (XmlAttachment a in alist) + { + // write the attachment serial + imawriter.Write((int)a.Serial.Value); + + // write the value type + imawriter.Write((string)a.GetType().ToString()); + + // save the fileposition index + fpiwriter.Write((long)imawriter.Position); + } + } + } + else + { + // no item attachments + imawriter.Write((int)0); + } + + imawriter.Close(); + fpiwriter.Close(); + } + } + + public static void Load() + { + string filePath = Path.Combine("Saves/Attachments", "Attachments.bin"); // the attachment serializations + string imaPath = Path.Combine("Saves/Attachments", "Attachments.ima"); // the item/mob attachment tables + string fpiPath = Path.Combine("Saves/Attachments", "Attachments.fpi"); // the file position indices + + if (!File.Exists(filePath)) + { + return; + } + + + FileStream fs = null; + BinaryFileReader reader = null; + FileStream imafs = null; + BinaryFileReader imareader = null; + FileStream fpifs = null; + BinaryFileReader fpireader = null; + + try + { + fs = new FileStream(filePath, (FileMode)3, (FileAccess)1, (FileShare)1); + reader = new BinaryFileReader(new BinaryReader(fs)); + imafs = new FileStream(imaPath, (FileMode)3, (FileAccess)1, (FileShare)1); + imareader = new BinaryFileReader(new BinaryReader(imafs)); + fpifs = new FileStream(fpiPath, (FileMode)3, (FileAccess)1, (FileShare)1); + fpireader = new BinaryFileReader(new BinaryReader(fpifs)); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + if (reader != null && imareader != null && fpireader != null) + { + // restore the current global attachment serial state + try + { + ASerial.GlobalDeserialize(reader); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + ASerial.serialInitialized = true; + + // read in the serial attachment hash table information + int count = 0; + try + { + count = reader.ReadInt(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + for (int i = 0; i < count; i++) + { + // read the serial + ASerial serialno = null; + try + { + serialno = new ASerial(reader.ReadInt()); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + // read the attachment type + string valuetype = null; + try + { + valuetype = reader.ReadString(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + // read the position of the beginning of the next attachment deser within the .bin file + long position = 0; + try + { + position = fpireader.ReadLong(); + + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + bool skip = false; + + XmlAttachment o = null; + try + { + o = (XmlAttachment)Activator.CreateInstance(Type.GetType(valuetype), new object[] { serialno }); + } + catch + { + skip = true; + } + + if (skip) + { + if (!AlreadyReported(valuetype)) + { + Console.WriteLine("\nError deserializing attachments {0}.\nMissing a serial constructor?\n", valuetype); + ReportDeserError(valuetype, "Missing a serial constructor?"); + } + // position the .ima file at the next deser point + try + { + reader.Seek(position, SeekOrigin.Begin); + } + catch + { + ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); + return; + } + continue; + } + + try + { + o.Deserialize(reader); + } + catch + { + skip = true; + } + + // confirm the read position + if (reader.Position != position || skip) + { + if (!AlreadyReported(valuetype)) + { + Console.WriteLine("\nError deserializing attachments {0}\n", valuetype); + ReportDeserError(valuetype, "save file corruption or incorrect Serialize/Deserialize methods?"); + } + // position the .ima file at the next deser point + try + { + reader.Seek(position, SeekOrigin.Begin); + } + catch + { + ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); + return; + } + continue; + } + + // add it to the hash table + try + { + AllAttachments.Add(serialno.Value, o); + } + catch + { + ErrorReporter.GenerateErrorReport(String.Format("\nError deserializing {0} serialno {1}. Attachments save file corrupted. Attachment load aborted.\n", + valuetype, serialno.Value)); + return; + } + } + + // read in the mobile attachment hash table information + try + { + count = imareader.ReadInt(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + for (int i = 0; i < count; i++) + { + + Mobile key = null; + try + { + key = imareader.ReadMobile(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + int nattach = 0; + try + { + nattach = imareader.ReadInt(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + for (int j = 0; j < nattach; j++) + { + // and serial + ASerial serialno = null; + try + { + serialno = new ASerial(imareader.ReadInt()); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + // read the attachment type + string valuetype = null; + try + { + valuetype = imareader.ReadString(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + // read the position of the beginning of the next attachment deser within the .bin file + long position = 0; + try + { + position = fpireader.ReadLong(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + XmlAttachment o = FindAttachmentBySerial(serialno.Value); + + if (o == null || imareader.Position != position) + { + if (!AlreadyReported(valuetype)) + { + Console.WriteLine("\nError deserializing attachments of type {0}.\n", valuetype); + ReportDeserError(valuetype, "save file corruption or incorrect Serialize/Deserialize methods?"); + } + // position the .ima file at the next deser point + try + { + imareader.Seek(position, SeekOrigin.Begin); + } + catch + { + ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); + return; + } + continue; + } + + // attachment successfully deserialized so attach it + AttachTo(key, o, false); + } + } + + // read in the item attachment hash table information + try + { + count = imareader.ReadInt(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + for (int i = 0; i < count; i++) + { + Item key = null; + try + { + key = imareader.ReadItem(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + int nattach = 0; + try + { + nattach = imareader.ReadInt(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + for (int j = 0; j < nattach; j++) + { + // and serial + ASerial serialno = null; + try + { + serialno = new ASerial(imareader.ReadInt()); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + // read the attachment type + string valuetype = null; + try + { + valuetype = imareader.ReadString(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + // read the position of the beginning of the next attachment deser within the .bin file + long position = 0; + try + { + position = fpireader.ReadLong(); + } + catch (Exception e) + { + ErrorReporter.GenerateErrorReport(e.ToString()); + return; + } + + XmlAttachment o = FindAttachmentBySerial(serialno.Value); + + if (o == null || imareader.Position != position) + { + if (!AlreadyReported(valuetype)) + { + Console.WriteLine("\nError deserializing attachments of type {0}.\n", valuetype); + ReportDeserError(valuetype, "save file corruption or incorrect Serialize/Deserialize methods?"); + } + // position the .ima file at the next deser point + try + { + imareader.Seek(position, SeekOrigin.Begin); + } + catch + { + ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); + return; + } + continue; + } + + // attachment successfully deserialized so attach it + AttachTo(key, o, false); + } + } + if (fs != null) + fs.Close(); + if (imafs != null) + imafs.Close(); + if (fpifs != null) + fpifs.Close(); + + if (desererror != null) + { + ErrorReporter.GenerateErrorReport("Error deserializing particular attachments."); + } + } + + } + + private class DeserErrorDetails + { + public string Type; + public string Details; + + public DeserErrorDetails(string type, string details) + { + Type = type; + Details = details; + } + + } + private static ArrayList desererror = null; + private static void ReportDeserError(string typestr, string detailstr) + { + if (desererror == null) + desererror = new ArrayList(); + + desererror.Add(new DeserErrorDetails(typestr, detailstr)); + } + private static bool AlreadyReported(string typestr) + { + if (desererror == null) return false; + foreach (DeserErrorDetails s in desererror) + { + if (s.Type == typestr) return true; + } + return false; + } + + public static void CheckOnBeforeKill(Mobile m_killed, Mobile m_killer) + { + + // do not register creature vs creature kills, nor any kills involving staff + // if (m_killer == null || m_killed == null || !(m_killer.Player || m_killed.Player) /*|| (m_killer.AccessLevel > AccessLevel.Player) || (m_killed.AccessLevel > AccessLevel.Player) */) + // return; + + if (m_killer != null) + { + // check the killer + ArrayList alist = XmlAttach.FindAttachments(m_killer); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnKill) + { + a.OnBeforeKill(m_killed, m_killer); + } + } + } + + // check any equipped items + List equiplist = m_killer.Items; + if (equiplist != null) + { + foreach (Item i in equiplist) + { + if (i == null || i.Deleted) continue; + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.CanActivateEquipped && a.HandlesOnKill) + { + a.OnBeforeKill(m_killed, m_killer); + } + } + } + } + } + } + + if (m_killed != null) + { + // check the killed + ArrayList alist = XmlAttach.FindAttachments(m_killed); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnKilled) + { + a.OnBeforeKilled(m_killed, m_killer); + } + } + } + } + } + + + public static void CheckOnKill(Mobile m_killed, Mobile m_killer) + { + + // do not register creature vs creature kills, nor any kills involving staff + // if (m_killer == null || m_killed == null || !(m_killer.Player || m_killed.Player) /*|| (m_killer.AccessLevel > AccessLevel.Player) || (m_killed.AccessLevel > AccessLevel.Player) */) + // return; + + if (m_killer != null) + { + // check the killer + ArrayList alist = XmlAttach.FindAttachments(m_killer); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnKill) + { + a.OnKill(m_killed, m_killer); + } + } + } + + // check any equipped items + List equiplist = m_killer.Items; + if (equiplist != null) + { + foreach (Item i in equiplist) + { + if (i == null || i.Deleted) continue; + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.CanActivateEquipped && a.HandlesOnKill) + { + a.OnKill(m_killed, m_killer); + } + } + } + } + } + } + + if (m_killed != null) + { + // check the killed + ArrayList alist = XmlAttach.FindAttachments(m_killed); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnKilled) + { + a.OnKilled(m_killed, m_killer); + } + } + } + } + } + + public static void EventSink_Movement(MovementEventArgs args) + { + Mobile from = args.Mobile; + + if (!from.Player /* || from.AccessLevel > AccessLevel.Player */) + return; + + // check for any items in the same sector + if (from.Map != null) + { + IPooledEnumerable itemlist = from.Map.GetItemsInRange(from.Location, Map.SectorSize); + if (itemlist != null) + { + foreach (Item i in itemlist) + { + if (i == null || i.Deleted) continue; + + ArrayList alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnMovement) + { + a.OnMovement(args); + } + } + } + } + itemlist.Free(); + } + + + // check for mobiles + IPooledEnumerable moblist = from.Map.GetMobilesInRange(from.Location, Map.SectorSize); + if (moblist != null) + { + foreach (Mobile i in moblist) + { + // dont respond to self motion + if (i == null || i.Deleted || i == from) continue; + + ArrayList alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnMovement) + { + a.OnMovement(args); + } + } + } + } + moblist.Free(); + } + } + } + + public static void EventSink_Speech(SpeechEventArgs args) + { + Mobile from = args.Mobile; + + if (from == null || from.Map == null /*|| from.AccessLevel > AccessLevel.Player */) return; + + // check the mob for any attachments that might handle speech + ArrayList alist = XmlAttach.FindAttachments(from); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnSpeech) + { + a.OnSpeech(args); + } + } + } + + // check for any nearby items + IPooledEnumerable itemlist = from.Map.GetItemsInRange(from.Location, Map.SectorSize); + if (itemlist != null) + { + foreach (Item i in itemlist) + { + if (i == null || i.Deleted) continue; + + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.CanActivateInWorld && a.HandlesOnSpeech) + { + a.OnSpeech(args); + } + } + } + } + itemlist.Free(); + } + + + // check for any nearby mobs + IPooledEnumerable moblist = from.Map.GetMobilesInRange(from.Location, Map.SectorSize); + if (moblist != null) + { + foreach (Mobile i in moblist) + { + if (i == null || i.Deleted) continue; + + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.HandlesOnSpeech) + { + a.OnSpeech(args); + } + } + } + } + moblist.Free(); + } + + + + // also check for any items in the mobs toplevel backpack + if (from.Backpack != null) + { + List packlist = from.Backpack.Items; + if (packlist != null) + { + foreach (Item i in packlist) + { + if (i == null || i.Deleted) continue; + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.CanActivateInBackpack && a.HandlesOnSpeech) + { + a.OnSpeech(args); + } + } + } + } + } + } + + // check any equipped items + List equiplist = from.Items; + if (equiplist != null) + { + foreach (Item i in equiplist) + { + if (i == null || i.Deleted) continue; + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && a.CanActivateEquipped && a.HandlesOnSpeech) + { + a.OnSpeech(args); + } + } + } + } + } + } + + public static XmlAttachment FindAttachmentOnMobile(Mobile from, Type type, string name) + { + if (from == null) return null; + // check the mob for any attachments + ArrayList alist = XmlAttach.FindAttachments(from); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && (type == null || (a.GetType() == type || a.GetType().IsSubclassOf(type))) && (name == null || name == a.Name)) + { + return a; + } + } + } + + + // also check for any items in the mobs toplevel backpack + if (from.Backpack != null) + { + List itemlist = from.Backpack.Items; + if (itemlist != null) + { + foreach (Item i in itemlist) + { + if (i == null || i.Deleted) continue; + alist = XmlAttach.FindAttachments(i); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && (type == null || (a.GetType() == type || a.GetType().IsSubclassOf(type))) && (name == null || name == a.Name)) + { + return a; + } + } + } + } + } + } + + // check any equipped items + List equiplist = from.Items; + if (equiplist != null) + { + foreach (Item i in equiplist) + { + if (i == null || i.Deleted) continue; + + alist = XmlAttach.FindAttachments(i); + + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted && (type == null || (a.GetType() == type || a.GetType().IsSubclassOf(type))) && (name == null || name == a.Name)) + { + return a; + } + } + } + } + } + return null; + } + + private class AttachTarget : Target + { + private CommandEventArgs m_e; + private string m_set = null; + + public AttachTarget(CommandEventArgs e, string set) + : base(30, false, TargetFlags.None) + { + m_e = e; + m_set = set; + } + protected override void OnTarget(Mobile from, object targeted) + { + if (from == null || targeted == null) return; + + Type type = null; + string name = null; + + if (m_e.Arguments.Length > 0) + { + + type = SpawnerType.GetType(m_e.Arguments[0]); + + } + if (m_e.Arguments.Length > 1) + { + name = m_e.Arguments[1]; + } + + XmlAttach.Defrag(targeted); + + ArrayList plist = XmlAttach.FindAttachments(targeted, type); + + if (plist == null && m_set != "add") + { + from.SendMessage("No attachments"); + return; + } + + switch (m_set) + { + case "add": + + if (m_e.Arguments.Length < 1) + { + from.SendMessage("Must specify an attachment type."); + return; + } + + // create a new attachment and add it to the item + int nargs = m_e.Arguments.Length - 1; + + string[] args = new string[nargs]; + + for (int j = 0; j < nargs; j++) + { + args[j] = (string)m_e.Arguments[j + 1]; + } + + + XmlAttachment o = null; + + Type attachtype = SpawnerType.GetType(m_e.Arguments[0]); + + if (attachtype != null && attachtype.IsSubclassOf(typeof(XmlAttachment))) + { + + o = (XmlAttachment)XmlSpawner.CreateObject(attachtype, args, false, true); + } + + if (o != null) + { + //o.Name = aname; + if (XmlAttach.AttachTo(from, targeted, o, true)) + from.SendMessage("Added attachment {2} : {0} to {1}", m_e.Arguments[0], targeted, o.Serial.Value); + else + from.SendMessage("Attachment not added: {0}", m_e.Arguments[0]); + } + else + { + from.SendMessage("Unable to construct attachment {0}", m_e.Arguments[0]); + } + + break; + case "get": + /* + foreach(XmlAttachment p in plist) + { + if(p == null || p.Deleted || (name != null && name != p.Name) || (type != null && type != p.GetType())) continue; + + from.SendMessage("Found attachment {3} : {0} : {1} : {2}",p.GetType().Name,p.Name,p.OnIdentify(from), p.Serial.Value); + + } + */ + from.SendGump(new XmlGetAttGump(from, targeted, 0, 0)); + + break; + case "delete": + /* + foreach(XmlAttachment p in plist) + { + if(p == null || p.Deleted || (name != null && name != p.Name) || (type != null && type != p.GetType())) continue; + + from.SendMessage("Deleting attachment {3} : {0} : {1} : {2}",p.GetType().Name,p.Name,p.OnIdentify(from), p.Serial.Value); + p.Delete(); + } + */ + from.SendGump(new XmlGetAttGump(from, targeted, 0, 0)); + + break; + case "activate": + foreach (XmlAttachment p in plist) + { + if (p == null || p.Deleted || (name != null && name != p.Name) || (type != null && type != p.GetType())) continue; + + from.SendMessage("Activating attachment {3} : {0} : {1} : {2}", p.GetType().Name, p.Name, p.OnIdentify(from), p.Serial.Value); + p.OnTrigger(null, from); + } + + break; + } + } + } + + [Usage("GetAtt [type/serialno [name]]")] + [Description("Returns descriptions of the attachments on the targeted object.")] + public static void GetAttachments_OnCommand(CommandEventArgs e) + { + int ser = -1; + if (e.Arguments.Length > 0) + { + // is this a numeric arg? + char c = e.Arguments[0][0]; + if (c >= '0' && c <= '9') + { + try + { + ser = int.Parse(e.Arguments[0]); + } + catch { } + XmlAttachment a = FindAttachmentBySerial(ser); + if (a != null) + { + // open up the props gump on the attachment + e.Mobile.SendGump(new PropertiesGump(e.Mobile, a)); + + } + else + { + e.Mobile.SendMessage("Attachment {0} does not exist", ser); + } + } + } + + if (ser == -1) + e.Mobile.Target = new AttachTarget(e, "get"); + } + + [Usage("AddAtt type [args]")] + [Description("Adds an attachment to the targeted object.")] + public static void AddAttachment_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new AttachTarget(e, "add"); + } + + [Usage("DelAtt [type/serialno [name]]")] + [Description("Deletes attachments on the targeted object.")] + public static void DeleteAttachments_OnCommand(CommandEventArgs e) + { + int ser = -1; + if (e.Arguments.Length > 0) + { + // is this a numeric arg? + char c = e.Arguments[0][0]; + if (c >= '0' && c <= '9') + { + try + { + ser = int.Parse(e.Arguments[0]); + } + catch { } + XmlAttachment a = FindAttachmentBySerial(ser); + if (a != null) + { + e.Mobile.SendMessage("Deleting attachment {0} : {1}", ser, a); + a.Delete(); + } + else + { + e.Mobile.SendMessage("Attachment {0} does not exist", ser); + } + } + } + + if (ser == -1) + e.Mobile.Target = new AttachTarget(e, "delete"); + } + + [Usage("TrigAtt [type [name]]")] + [Description("Triggers attachments on the targeted object.")] + public static void ActivateAttachments_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new AttachTarget(e, "activate"); + } + + [Usage("ItemAtt")] + [Description("Lists all item attachments.")] + public static void ListItemAttachments_OnCommand(CommandEventArgs e) + { + if (ItemAttachments == null) return; + + XmlAttach.FullDefrag(ItemAttachments); + + Item[] itemarray = new Item[ItemAttachments.Count]; + + ItemAttachments.Keys.CopyTo(itemarray, 0); + + e.Mobile.SendMessage("{0} items with attachments", ItemAttachments.Count); + + for (int i = 0; i < itemarray.Length; i++) + { + e.Mobile.SendMessage("Attachments for {0} :", itemarray[i]); + ArrayList list = FindAttachments(itemarray[i]); + + if (list != null) + { + foreach (XmlAttachment a in list) + { + if (a != null && !a.Deleted) + e.Mobile.SendMessage("\t{0} : {1} : {2}", a.GetType().Name, a.Name, a.OnIdentify(e.Mobile)); + } + } + } + } + [Usage("MobAtt")] + [Description("Lists all mobile attachments.")] + public static void ListMobileAttachments_OnCommand(CommandEventArgs e) + { + if (MobileAttachments == null) return; + + XmlAttach.FullDefrag(MobileAttachments); + + Mobile[] mobilearray = new Mobile[MobileAttachments.Count]; + + MobileAttachments.Keys.CopyTo(mobilearray, 0); + + e.Mobile.SendMessage("{0} mobiles with attachments", MobileAttachments.Count); + + for (int i = 0; i < mobilearray.Length; i++) + { + e.Mobile.SendMessage("Attachments for {0} :", mobilearray[i]); + ArrayList list = FindAttachments(mobilearray[i]); + + if (list != null) + { + foreach (XmlAttachment a in list) + { + if (a != null && !a.Deleted) + e.Mobile.SendMessage("\t{0} : {1} : {2}", a.GetType().Name, a.Name, a.OnIdentify(e.Mobile)); + } + } + } + } + + private static void Match(Type matchtype, Type[] types, ArrayList results) + { + if (matchtype == null) + return; + + for (int i = 0; i < types.Length; ++i) + { + Type t = types[i]; + + if (t.IsSubclassOf(matchtype)) + { + results.Add(t); + } + } + } + + + private static ArrayList Match(Type matchtype) + { + ArrayList results = new ArrayList(); + Type[] types; + + Assembly[] asms = ScriptCompiler.Assemblies; + + for (int i = 0; i < asms.Length; ++i) + { + types = ScriptCompiler.GetTypeCache(asms[i]).Types; + Match(matchtype, types, results); + } + + types = ScriptCompiler.GetTypeCache(Core.Assembly).Types; + Match(matchtype, types, results); + + results.Sort(new TypeNameComparer()); + + return results; + } + + private class TypeNameComparer : IComparer + { + public int Compare(object x, object y) + { + Type a = x as Type; + Type b = y as Type; + + return a.Name.CompareTo(b.Name); + } + } + + + [Usage("AvailAtt")] + [Description("Lists all available attachments.")] + public static void ListAvailableAttachments_OnCommand(CommandEventArgs e) + { + + ArrayList attachtypes = Match(typeof(XmlAttachment)); + + string parmliststr = null; + + foreach (Type attachtype in attachtypes) + { + // get all constructors derived from the XmlAttachment class + ConstructorInfo[] ctors = attachtype.GetConstructors(); + + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + if (!IsAttachable(ctor)) + { + continue; + } + + ParameterInfo[] paramList = ctor.GetParameters(); + + if (paramList != null) + { + string parms = attachtype.Name; + + + for (int j = 0; j < paramList.Length; j++) + { + parms += ", " + paramList[j].Name; + } + + parmliststr += parms + "\n"; + } + } + } + e.Mobile.SendGump(new ListAttachmentsGump(parmliststr, 20, 20)); + + } + + private class ListAttachmentsGump : Gump + { + + public ListAttachmentsGump(string attachmentlist, int X, int Y) + : base(X, Y) + { + AddPage(0); + + AddBackground(20, 0, 330, 480, 5054); + + AddPage(1); + + AddImageTiled(20, 0, 330, 480, 0x52); + + AddLabel(27, 2, 0x384, "Available Attachments"); + AddHtml(25, 22, 320, 458, attachmentlist, false, true); + } + } + + private class DisplayAttachmentGump : Gump + { + public DisplayAttachmentGump(Mobile from, string text, int X, int Y) + : base(X, Y) + { + // prepare the page + AddPage(0); + + AddBackground(0, 0, 400, 150, 5054); + AddAlphaRegion(0, 0, 400, 150); + AddLabel(20, 2, 55, "Attachment Description(s)"); + + AddHtml(20, 20, 360, 110, text, true, true); + } + } + + public static void RevealAttachments(Mobile from, object o) + { + if (from == null || o == null) return; + + ArrayList plist = XmlAttach.FindAttachments(o); + + if (plist == null) return; + + string msg = null; + + foreach (XmlAttachment p in plist) + { + if (p != null && !p.Deleted) + { + string pmsg = p.OnIdentify(from); + if (pmsg != null) + msg += String.Format("\n{0}\n", pmsg); + } + } + if (msg != null) + { + from.CloseGump(typeof(DisplayAttachmentGump)); + from.SendMessage("Hidden attributes revealed!"); + + from.SendGump(new DisplayAttachmentGump(from, msg, 0, 0)); + } + } + + public static bool AttachTo(object o, XmlAttachment attachment) + { + return AttachTo(null, o, attachment, true); + } + + public static bool AttachTo(object from, object o, XmlAttachment attachment) + { + return AttachTo(from, o, attachment, true); + } + + public static bool AttachTo(object o, XmlAttachment attachment, bool first) + { + return AttachTo(null, o, attachment, first); + } + + private static bool AttachTo(object from, object o, XmlAttachment attachment, bool first) + { + if (!(o is Item || o is Mobile) || attachment == null) return false; + + Hashtable attachments = null; + if (o is Item) + { + if (ItemAttachments == null) + { + ItemAttachments = new Hashtable(); + } + attachments = ItemAttachments; + + } + else + if (o is Mobile) + { + if (MobileAttachments == null) + { + MobileAttachments = new Hashtable(); + } + + attachments = MobileAttachments; + } + + XmlAttach.Defrag(o); + + // see if there is already an attachment list for the object + ArrayList attachmententry = FindAttachments(attachments, o, true); + + if (attachmententry != null) + { + // if an existing entry list was found then just add the attachment to that list after making sure there is not a duplicate + foreach (XmlAttachment i in attachmententry) + { + // and attachment is considered a duplicate if both the type and name match + if (i != null && !i.Deleted && i.GetType() == attachment.GetType() && i.Name == attachment.Name) + { + // duplicate found so replace it + i.Delete(); + } + } + + attachmententry.Add(attachment); + } + else + { + // otherwise make a new entry list + attachmententry = new ArrayList(1); + + // containing the attachment + attachmententry.Add(attachment); + + // and add it to the hash table + attachments.Add(o, attachmententry); + + } + + attachment.AttachedTo = o; + attachment.OwnedBy = o; + + if (from is Mobile) + { + attachment.SetAttachedBy(((Mobile)from).Name); + } + else + if (from is Item) + { + attachment.SetAttachedBy(((Item)from).Name); + } + + // if this is being attached for the first time, then call the OnAttach method + // if it is being reattached due to deserialization then dont + if (first) + { + attachment.OnAttach(); + } + else + { + attachment.OnReattach(); + } + + return !attachment.Deleted; + } + + public static ArrayList FindAttachments(object o) + { + return FindAttachments(o, null, null); + } + + public static ArrayList FindAttachments(object o, Type type) + { + return FindAttachments(o, type, null); + } + + public static ArrayList FindAttachments(object o, Type type, string name) + { + Hashtable attachments = null; + if (o is Item) + { + attachments = ItemAttachments; + } + else + if (o is Mobile) + { + attachments = MobileAttachments; + } + return FindAttachments(attachments, o, type, name); + } + + public static ArrayList FindAttachments(Hashtable attachments, object o) + { + return FindAttachments(attachments, o, null, null, false); + } + + public static ArrayList FindAttachments(Hashtable attachments, object o, bool original) + { + return FindAttachments(attachments, o, null, null, original); + } + + public static ArrayList FindAttachments(Hashtable attachments, object o, Type type) + { + return FindAttachments(attachments, o, type, null, false); + } + + public static ArrayList FindAttachments(Hashtable attachments, object o, Type type, string name) + { + return FindAttachments(attachments, o, type, name, false); + } + + + public static ArrayList FindAttachments(Hashtable attachments, object o, Type type, string name, bool original) + { + if (o == null || attachments == null) return null; + + if ((o is Item && ((Item)o).Deleted) || (o is Mobile && ((Mobile)o).Deleted)) return null; + + if (type == null && name == null) + { + if (attachments[o] != null) + { + if (original) + return (ArrayList)attachments[o]; + else + return (ArrayList)(((ArrayList)attachments[o]).Clone()); + + + } + else + return null; + + } + else + { + // just get those of a particular type and/or name + ArrayList list = (ArrayList)attachments[o]; + + if (list != null) + { + ArrayList newlist = new ArrayList(); + + foreach (XmlAttachment i in list) + { + // see if it is deleted + if (i == null || i.Deleted) + continue; + + Type itype = i.GetType(); + + if ((type == null || (itype != null && (itype == type || itype.IsSubclassOf(type)))) && (name == null || (name == i.Name))) + { + newlist.Add(i); + } + } + + return newlist; + } + + return null; + } + } + + public static XmlAttachment FindAttachment(object o) + { + return FindAttachment(o, null, null); + } + + public static XmlAttachment FindAttachment(object o, Type type) + { + return FindAttachment(o, type, null); + } + + public static XmlAttachment FindAttachment(object o, Type type, string name) + { + Hashtable attachments = null; + if (o is Item) + { + attachments = ItemAttachments; + } + else + if (o is Mobile) + { + attachments = MobileAttachments; + } + return FindAttachment(attachments, o, type, name); + } + + public static XmlAttachment FindAttachment(Hashtable attachments, object o) + { + return FindAttachment(attachments, o, null, null); + } + + public static XmlAttachment FindAttachment(Hashtable attachments, object o, Type type) + { + return FindAttachment(attachments, o, type, null); + } + + public static XmlAttachment FindAttachment(Hashtable attachments, object o, Type type, string name) + { + if (o == null || attachments == null) return null; + + if ((o is Item && ((Item)o).Deleted) || (o is Mobile && ((Mobile)o).Deleted)) return null; + + ArrayList list = attachments[o] as ArrayList; + if (type == null && name == null) + { + if (list != null && list.Count > 0) + { + // return the first valid attachment + foreach (XmlAttachment i in list) + { + if (i != null && !i.Deleted) + return i; + } + } + } + else + { + // just get those of a particular type and/or name + if (list != null) + { + + foreach (XmlAttachment i in list) + { + // see if it is deleted + if (i == null || i.Deleted) + continue; + + Type itype = i.GetType(); + + if ((type == null || (itype != null && (itype == type || itype.IsSubclassOf(type)))) && (name == null || (name == i.Name))) + { + return i; + } + } + } + } + return null; + } + + public static XmlAttachment FindAttachmentBySerial(int serialno) + { + if (serialno <= 0) return null; + XmlAttachment a = AllAttachments[serialno] as XmlAttachment; + + return a; + } + + + private static void FullDefrag() + { + // defrag the mobile/item tables + FullDefrag(ItemAttachments); + FullDefrag(MobileAttachments); + // defrag the serial table + FullSerialDefrag(AllAttachments); + } + + private static void FullDefrag(Hashtable attachments) + { + // go through the item attachments + object[] keyarray = new object[attachments.Count]; + + attachments.Keys.CopyTo(keyarray, 0); + for (int i = 0; i < keyarray.Length; i++) + { + Defrag(attachments, keyarray[i]); + } + } + + private static void FullSerialDefrag(Hashtable attachments) + { + // go through the item attachments + object[] keyarray = new object[attachments.Count]; + + attachments.Keys.CopyTo(keyarray, 0); + for (int i = 0; i < keyarray.Length; i++) + { + object o = attachments[keyarray[i]]; + if (o is XmlAttachment) + { + XmlAttachment a = o as XmlAttachment; + + if (a == null || a.Deleted) + { + attachments.Remove(keyarray[i]); + } + } + } + } + + + private static void SerialDefrag(XmlAttachment a) + { + if (a != null && a.Deleted) + AllAttachments.Remove(a.Serial.Value); + } + + public static void Defrag(object o) + { + Hashtable attachments = null; + if (o is Item) + { + attachments = ItemAttachments; + } + else + if (o is Mobile) + { + attachments = MobileAttachments; + } + + Defrag(attachments, o); + } + + private static void Defrag(Hashtable attachments, object o) + { + if (o == null || attachments == null) return; + + bool removeall = false; + + if ((o is Item && ((Item)o).Deleted) || (o is Mobile && ((Mobile)o).Deleted)) + { + removeall = true; + } + + // lookup the attachments for the given object + ArrayList list = (ArrayList)attachments[o]; + + ArrayList defraglist = null; + + if (list != null) + { + foreach (XmlAttachment i in list) + { + // see if it is deleted + if (i == null || i.Deleted || removeall) + { + // then flag for removal from the original list + if (defraglist == null) + defraglist = new ArrayList(); + + defraglist.Add(i); + } + } + + if (defraglist != null) + { + foreach (XmlAttachment i in defraglist) + { + list.Remove(i); + } + // if the list is empty then remove the hashtable entry for the given object + if (list.Count == 0 || removeall) + { + attachments.Remove(o); + } + } + } + else + attachments.Remove(o); + + } + + public static bool CheckCanEquip(Item item, Mobile from) + { + // call the CanEquip method on any attachments on the item + // look for attachments on the item + ArrayList attachments = FindAttachments(ItemAttachments, item); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted) + if (!a.CanEquip(from)) return false; + } + } + return true; + } + + public static void CheckOnEquip(Item item, Mobile from) + { + // look for attachments on the item + ArrayList attachments = FindAttachments(ItemAttachments, item); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted) + a.OnEquip(from); + } + } + } + + public static void CheckOnRemoved(Item item, object parent) + { + // look for attachments on the item + ArrayList attachments = FindAttachments(ItemAttachments, item); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted) + a.OnRemoved(parent); + } + } + } + + public static void OnWeaponHit(BaseWeapon weapon, Mobile attacker, Mobile defender, int damage) + { + // look for attachments on the weapon + ArrayList attachments = FindAttachments(ItemAttachments, weapon); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted) + a.OnWeaponHit(attacker, defender, weapon, damage); + } + } + + // also support OnWeaponHit for the mobile owner + attachments = FindAttachments(MobileAttachments, attacker); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted) + a.OnWeaponHit(attacker, defender, weapon, damage); + } + } + } + + public static int OnArmorHit(Mobile attacker, Mobile defender, Item armor, BaseWeapon weapon, int damage) + { + int damageTaken = 0; + + // figure out who the attacker and defender are based upon who is carrying the armor/weapon + + // look for attachments on the armor + if (armor != null) + { + ArrayList attachments = FindAttachments(ItemAttachments, armor); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted) + damageTaken += a.OnArmorHit(attacker, defender, armor, weapon, damage); + } + } + } + + return damageTaken; + } + + public static void AddAttachmentProperties(object parent, ObjectPropertyList list) + { + if (parent == null) return; + + string propstr = null; + + ArrayList plist = XmlAttach.FindAttachments(parent); + if (plist != null && plist.Count > 0) + { + for (int i = 0; i < plist.Count; i++) + { + XmlAttachment a = plist[i] as XmlAttachment; + + if (a != null && !a.Deleted) + { + // give the attachment an opportunity to modify the properties list of the parent + a.AddProperties(list); + + // get any displayed properties on the attachment + string str = a.DisplayedProperties(null); + + if (str != null) + { + propstr += str; + + if (i < plist.Count - 1) propstr += "\n"; + } + + } + } + } + + if (propstr != null && list != null) + list.Add(1062613, propstr); + } + + public static void UseReq(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + + if (from.AccessLevel >= AccessLevel.GameMaster || DateTime.Now >= from.NextActionTime) + { + int value = pvSrc.ReadInt32(); + + if ((value & ~0x7FFFFFFF) != 0) + { + from.OnPaperdollRequest(); + } + else + { + Serial s = value; + + bool blockdefaultonuse = false; + + if (s.IsMobile) + { + Mobile m = World.FindMobile(s); + + if (m != null && !m.Deleted) + { + // get attachments on the mobile doing the using + ArrayList fromlist = FindAttachments(MobileAttachments, from); + if (fromlist != null) + { + foreach (XmlAttachment a in fromlist) + { + if (a != null && !a.Deleted) + { + if (a.BlockDefaultOnUse(from, m)) + blockdefaultonuse = true; + a.OnUser(m); + } + } + } + + // get attachments on the mob + ArrayList alist = FindAttachments(MobileAttachments, m); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted) + { + if (a.BlockDefaultOnUse(from, m)) + blockdefaultonuse = true; + a.OnUse(from); + } + } + } + + if (!blockdefaultonuse && m != null && !m.Deleted) + from.Use(m); + } + } + else if (s.IsItem) + { + Item item = World.FindItem(s); + + if (item != null && !item.Deleted) + { + // get attachments on the mobile doing the using + ArrayList fromlist = FindAttachments(MobileAttachments, from); + if (fromlist != null) + { + foreach (XmlAttachment a in fromlist) + { + if (a != null && !a.Deleted) + { + if (a.BlockDefaultOnUse(from, item)) + blockdefaultonuse = true; + a.OnUser(item); + } + } + } + + // get attachments on the mob + ArrayList alist = FindAttachments(ItemAttachments, item); + if (alist != null) + { + foreach (XmlAttachment a in alist) + { + if (a != null && !a.Deleted) + { + if (a.BlockDefaultOnUse(from, item)) + blockdefaultonuse = true; + a.OnUse(from); + } + } + } + // need to check the item again in case it was modified in the OnUse or OnUser method + if (!blockdefaultonuse && item != null && !item.Deleted) + from.Use(item); + } + } + } + + } + else + { + from.SendActionMessage(); + } + + } + + public static bool OnDragLift(Mobile from, Item item) + { + // look for attachments on the item + if (item != null) + { + ArrayList attachments = FindAttachments(ItemAttachments, item); + + if (attachments != null) + { + foreach (XmlAttachment a in attachments) + { + if (a != null && !a.Deleted && !a.OnDragLift(from, item)) + return false; + } + } + } + + // allow lifts by default + return true; + } + + public class ErrorReporter + { + + + private static void SendEmail(string filePath) + { + Console.Write("XmlSpawner2 Attachment error: Sending email..."); + + MailMessage message = null; + try + { + message = new MailMessage(Email.FromAddress, Email.CrashAddresses); + } + catch { } + + if (message == null) + { + Console.Write("Unable to send email. Possible invalid email address."); + return; + } + message.Subject = "Automated XmlSpawner2 Attachment Error Report"; + + message.Body = "Automated XmlSpawner2 Attachment Report. See attachment for details."; + + message.Attachments.Add(new Attachment(filePath)); + + if (Email.Send(message)) + Console.WriteLine("done"); + else + Console.WriteLine("failed"); + } + + private static string GetRoot() + { + try + { + return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]); + } + catch + { + return ""; + } + } + + private static string Combine(string path1, string path2) + { + if (path1 == "") + return path2; + + return Path.Combine(path1, path2); + } + + + private static void CreateDirectory(string path) + { + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + } + + private static void CreateDirectory(string path1, string path2) + { + CreateDirectory(Combine(path1, path2)); + } + + private static void CopyFile(string rootOrigin, string rootBackup, string path) + { + string originPath = Combine(rootOrigin, path); + string backupPath = Combine(rootBackup, path); + + try + { + if (File.Exists(originPath)) + File.Copy(originPath, backupPath); + } + catch + { + } + } + + public static void GenerateErrorReport(string error) + { + Console.Write("\nXmlSpawner2 Attachment Error:\n{0}\nGenerating report...", error); + + try + { + string timeStamp = GetTimeStamp(); + string fileName = String.Format("Attachment Error {0}.log", timeStamp); + + string root = GetRoot(); + string filePath = Combine(root, fileName); + + using (StreamWriter op = new StreamWriter(filePath)) + { + Version ver = Core.Assembly.GetName().Version; + + op.WriteLine("XmlSpawner2 Attachment Error Report"); + op.WriteLine("==================="); + op.WriteLine(); + op.WriteLine("RunUO Version {0}.{1}.{3}, Build {2}", ver.Major, ver.Minor, ver.Revision, ver.Build); + op.WriteLine("Operating System: {0}", Environment.OSVersion); + op.WriteLine(".NET Framework: {0}", Environment.Version); + op.WriteLine("XmlSpawner2: {0}", XmlSpawner.Version); + op.WriteLine("Time: {0}", DateTime.Now); + + op.WriteLine(); + + op.WriteLine("Error:"); + op.WriteLine(error); + + op.WriteLine(); + op.WriteLine("Specific Attachment Errors:"); + foreach (DeserErrorDetails s in XmlAttach.desererror) + { + op.WriteLine("{0} - {1}", s.Type, s.Details); + } + } + + Console.WriteLine("done"); + + if (Email.CrashAddresses != null) + SendEmail(filePath); + } + catch + { + Console.WriteLine("failed"); + } + } + + private static string GetTimeStamp() + { + DateTime now = DateTime.Now; + + return String.Format("{0}-{1}-{2}-{3}-{4}-{5}", + now.Day, + now.Month, + now.Year, + now.Hour, + now.Minute, + now.Second + ); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttach/XmlAttachment.cs b/Scripts/Customs/XML Spawner/XmlAttach/XmlAttachment.cs new file mode 100644 index 0000000..f19fae7 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttach/XmlAttachment.cs @@ -0,0 +1,530 @@ +using System; +using System.Text; +using Server; +using Server.Commands; +using Server.Network; +using System.Collections; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Engines.XmlSpawner2 +{ + public interface IXmlAttachment + { + ASerial Serial { get; } + + string Name { get; set; } + + TimeSpan Expiration { get; set; } + + DateTime ExpirationEnd { get; } + + DateTime CreationTime { get; } + + bool Deleted { get; } + + bool DoDelete { get; set; } + + bool CanActivateInBackpack { get; } + + bool CanActivateEquipped { get; } + + bool CanActivateInWorld { get; } + + bool HandlesOnSpeech { get; } + + void OnSpeech(SpeechEventArgs args); + + bool HandlesOnMovement { get; } + + void OnMovement(MovementEventArgs args); + + bool HandlesOnKill { get; } + + void OnKill(Mobile killed, Mobile killer); + + void OnBeforeKill(Mobile killed, Mobile killer); + + bool HandlesOnKilled { get; } + + void OnKilled(Mobile killed, Mobile killer); + + void OnBeforeKilled(Mobile killed, Mobile killer); + + /* + bool HandlesOnSkillUse { get; } + + void OnSkillUse( Mobile m, Skill skill, bool success); + */ + + object AttachedTo { get; set; } + + object OwnedBy { get; set; } + + bool CanEquip(Mobile from); + + void OnEquip(Mobile from); + + void OnRemoved(object parent); + + void OnAttach(); + + void OnReattach(); + + void OnUse(Mobile from); + + void OnUser(object target); + + bool BlockDefaultOnUse(Mobile from, object target); + + bool OnDragLift(Mobile from, Item item); + + string OnIdentify(Mobile from); + + string DisplayedProperties(Mobile from); + + void AddProperties(ObjectPropertyList list); + + string AttachedBy { get; } + + void OnDelete(); + + void Delete(); + + void InvalidateParentProperties(); + + void SetAttachedBy(string name); + + void OnTrigger(object activator, Mobile from); + + void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven); + + int OnArmorHit(Mobile attacker, Mobile defender, Item armor, BaseWeapon weapon, int damageGiven); + + void Serialize(GenericWriter writer); + + void Deserialize(GenericReader reader); + + } + + public abstract class XmlAttachment : IXmlAttachment + { + // ---------------------------------------------- + // Private fields + // ---------------------------------------------- + private ASerial m_Serial; + + private string m_Name; + + private object m_AttachedTo; + + private object m_OwnedBy; + + private string m_AttachedBy; + + private bool m_Deleted; + + private AttachmentTimer m_ExpirationTimer; + + private TimeSpan m_Expiration = TimeSpan.Zero; // no expiration by default + + private DateTime m_ExpirationEnd; + + private DateTime m_CreationTime; // when the attachment was made + + // ---------------------------------------------- + // Public properties + // ---------------------------------------------- + [CommandProperty(AccessLevel.GameMaster)] + public DateTime CreationTime { get { return m_CreationTime; } } + + public bool Deleted { get { return m_Deleted; } } + + public bool DoDelete { get { return false; } set { if (value == true) Delete(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int SerialValue { get { return m_Serial.Value; } } + + public ASerial Serial { get { return m_Serial; } set { m_Serial = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan Expiration + { + get + { + // if the expiration timer is running then return the remaining time + if (m_ExpirationTimer != null) + { + return m_ExpirationEnd - DateTime.Now; + } + else + return m_Expiration; + } + set + { + m_Expiration = value; + // if it is already attached to something then set the expiration timer + if (m_AttachedTo != null) + { + DoTimer(m_Expiration); + } + } + } + + public DateTime ExpirationEnd + { + get { return m_ExpirationEnd; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool CanActivateInBackpack { get { return true; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool CanActivateEquipped { get { return true; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool CanActivateInWorld { get { return true; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool HandlesOnSpeech { get { return false; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool HandlesOnMovement { get { return false; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool HandlesOnKill { get { return false; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool HandlesOnKilled { get { return false; } } + + /* + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool HandlesOnSkillUse { get{return false; } } + */ + + [CommandProperty(AccessLevel.GameMaster)] + public virtual string Name { get { return m_Name; } set { m_Name = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual object Attached { get { return m_AttachedTo; } } + + public virtual object AttachedTo { get { return m_AttachedTo; } set { m_AttachedTo = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual string AttachedBy { get { return m_AttachedBy; } } + + public virtual object OwnedBy { get { return m_OwnedBy; } set { m_OwnedBy = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual object Owner { get { return m_OwnedBy; } } + + // ---------------------------------------------- + // Private methods + // ---------------------------------------------- + private void DoTimer(TimeSpan delay) + { + m_ExpirationEnd = DateTime.Now + delay; + + if (m_ExpirationTimer != null) + m_ExpirationTimer.Stop(); + + m_ExpirationTimer = new AttachmentTimer(this, delay); + m_ExpirationTimer.Start(); + } + + // a timer that can be implement limited lifetime attachments + private class AttachmentTimer : Timer + { + private XmlAttachment m_Attachment; + + public AttachmentTimer(XmlAttachment attachment, TimeSpan delay) + : base(delay) + { + Priority = TimerPriority.OneSecond; + + m_Attachment = attachment; + } + + protected override void OnTick() + { + m_Attachment.Delete(); + } + } + + // ---------------------------------------------- + // Constructors + // ---------------------------------------------- + public XmlAttachment() + { + m_CreationTime = DateTime.Now; + + // get the next unique serial id + m_Serial = ASerial.NewSerial(); + + // register the attachment in the serial keyed hashtable + XmlAttach.HashSerial(m_Serial, this); + } + + // needed for deserialization + public XmlAttachment(ASerial serial) + { + m_Serial = serial; + } + + // ---------------------------------------------- + // Public methods + // ---------------------------------------------- + + public static void Initialize() + { + XmlAttach.CleanUp(); + } + + public virtual bool CanEquip(Mobile from) + { + return true; + } + + public virtual void OnEquip(Mobile from) + { + } + + + + public virtual void OnRemoved(object parent) + { + } + + public virtual void OnAttach() + { + // start up the expiration timer on attachment + if (m_Expiration > TimeSpan.Zero) + DoTimer(m_Expiration); + } + + public virtual void OnReattach() + { + } + + public virtual void OnUse(Mobile from) + { + } + + public virtual void OnUser(object target) + { + } + + public virtual bool BlockDefaultOnUse(Mobile from, object target) + { + return false; + } + + public virtual bool OnDragLift(Mobile from, Item item) + { + return true; + } + + public void SetAttachedBy(string name) + { + m_AttachedBy = name; + } + + public virtual void OnSpeech(SpeechEventArgs args) + { + } + + public virtual void OnMovement(MovementEventArgs args) + { + } + + public virtual void OnKill(Mobile killed, Mobile killer) + { + } + + public virtual void OnBeforeKill(Mobile killed, Mobile killer) + { + } + + public virtual void OnKilled(Mobile killed, Mobile killer) + { + } + + public virtual void OnBeforeKilled(Mobile killed, Mobile killer) + { + } + + /* + public virtual void OnSkillUse( Mobile m, Skill skill, bool success) + { + } + */ + + public virtual void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + } + + public virtual int OnArmorHit(Mobile attacker, Mobile defender, Item armor, BaseWeapon weapon, int damageGiven) + { + return 0; + } + + public virtual string OnIdentify(Mobile from) + { + return null; + } + + public virtual string DisplayedProperties(Mobile from) + { + return OnIdentify(from); + } + + + public virtual void AddProperties(ObjectPropertyList list) + { + } + + public void InvalidateParentProperties() + { + if (AttachedTo is Item) + { + ((Item)AttachedTo).InvalidateProperties(); + } + } + + public void SafeItemDelete(Item item) + { + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(DeleteItemCallback), new object[] { item }); + + } + + public void DeleteItemCallback(object state) + { + object[] args = (object[])state; + + Item item = args[0] as Item; + + if (item != null) + { + // delete the item + item.Delete(); + } + } + + public void SafeMobileDelete(Mobile mob) + { + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(DeleteMobileCallback), new object[] { mob }); + + } + + public void DeleteMobileCallback(object state) + { + object[] args = (object[])state; + + Mobile mob = args[0] as Mobile; + + if (mob != null) + { + // delete the mobile + mob.Delete(); + } + } + + public void Delete() + { + if (m_Deleted) return; + + m_Deleted = true; + + if (m_ExpirationTimer != null) + m_ExpirationTimer.Stop(); + + OnDelete(); + + // dereference the attachment object + AttachedTo = null; + OwnedBy = null; + } + + public virtual void OnDelete() + { + } + + public virtual void OnTrigger(object activator, Mobile from) + { + } + + public virtual void Serialize(GenericWriter writer) + { + writer.Write((int)2); + // version 2 + writer.Write(m_AttachedBy); + // version 1 + if (OwnedBy is Item) + { + writer.Write((int)0); + writer.Write((Item)OwnedBy); + } + else + if (OwnedBy is Mobile) + { + writer.Write((int)1); + writer.Write((Mobile)OwnedBy); + } + else + writer.Write((int)-1); + + // version 0 + writer.Write(Name); + // if there are any active timers, then serialize + writer.Write(m_Expiration); + if (m_ExpirationTimer != null) + { + writer.Write(m_ExpirationEnd - DateTime.Now); + } + else + { + writer.Write(TimeSpan.Zero); + } + writer.Write(m_CreationTime); + } + + public virtual void Deserialize(GenericReader reader) + { + int version = reader.ReadInt(); + + switch (version) + { + case 2: + m_AttachedBy = reader.ReadString(); + goto case 1; + case 1: + int owned = reader.ReadInt(); + if (owned == 0) + { + OwnedBy = reader.ReadItem(); + } + else + if (owned == 1) + { + OwnedBy = reader.ReadMobile(); + } + else + OwnedBy = null; + + goto case 0; + case 0: + // version 0 + Name = (string)reader.ReadString(); + m_Expiration = reader.ReadTimeSpan(); + TimeSpan remaining = (TimeSpan)reader.ReadTimeSpan(); + + if (remaining > TimeSpan.Zero) + DoTimer(remaining); + + m_CreationTime = reader.ReadDateTime(); + break; + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttach/XmlGetAttachGump.cs b/Scripts/Customs/XML Spawner/XmlAttach/XmlGetAttachGump.cs new file mode 100644 index 0000000..c909dd9 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttach/XmlGetAttachGump.cs @@ -0,0 +1,729 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using Server.Engines.XmlSpawner2; + +/* +** XmlGetAtt +** Version 1.00 +** updated 10/24/04 +** ArteGordon +** +*/ + +namespace Server.Mobiles +{ + public class XmlGetAttGump : Gump + { + private const int MaxEntries = 18; + private const int MaxEntriesPerPage = 18; + + private object m_TargetObject; + + private bool Dosearchtype; + private bool Dosearchname; + + private bool Dosearchage; + + private bool Searchagedirection; + private double Searchage; + + private string Searchtype; + private string Searchname; + + private bool Sorttype; + + private bool Sortname; + + private Mobile m_From; + + private bool Descendingsort; + private int Selected; + private int DisplayFrom; + private bool [] m_SelectionList; + + private bool SelectAll = false; + + private ArrayList m_SearchList; + + public static void Initialize() + { + CommandSystem.Register( "XmlGetAtt", AccessLevel.GameMaster, new CommandEventHandler( XmlGetAtt_OnCommand ) ); + } + + + private bool TestAge(object o) + { + if(Searchage <= 0) return true; + + if(o is XmlAttachment){ + XmlAttachment a = (XmlAttachment)o; + + if(Searchagedirection) + { + // true means allow only mobs greater than the age + if((DateTime.Now - a.CreationTime) > TimeSpan.FromHours(Searchage)) return true; + } + else + { + // false means allow only mobs less than the age + if((DateTime.Now - a.CreationTime) < TimeSpan.FromHours(Searchage)) return true; + } + + } + return false; + } + + + private ArrayList Search(object target, out string status_str) + { + status_str = null; + ArrayList newarray = new ArrayList(); + Type targetType = null; + // if the type is specified then get the search type + if(Dosearchtype && Searchtype != null){ + targetType = SpawnerType.GetType( Searchtype ); + if(targetType == null){ + status_str = "Invalid type: " + Searchtype; + return newarray; + } + } + + ArrayList attachments = XmlAttach.FindAttachments(target); + + // do the search through attachments + if(attachments != null) + foreach(XmlAttachment i in attachments) + { + bool hastype = false; + bool hasname = false; + + if(i == null || i.Deleted ) continue; + + + // check for type + if(Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType().Equals(targetType))) + { + hastype = true; + } + if(Dosearchtype && !hastype) continue; + + // check for name + if (Dosearchname && (i.Name != null) && (Searchname != null) && (i.Name.ToLower().IndexOf(Searchname.ToLower()) >= 0)) + { + hasname = true; + } + if(Dosearchname && !hasname) continue; + + + // satisfied all conditions so add it + newarray.Add(i); + } + + return newarray; + } + + private class GetAttachTarget : Target + { + private CommandEventArgs m_e; + + public GetAttachTarget( CommandEventArgs e) : base ( 30, false, TargetFlags.None ) + { + m_e = e; + + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(from == null || targeted == null) return; + + + from.SendGump( new XmlGetAttGump(from, targeted, 0,0)); + } + } + + [Usage( "XmlGetAtt" )] + [Description( "Gets attachments on an object" )] + public static void XmlGetAtt_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new GetAttachTarget(e); + } + + public XmlGetAttGump(Mobile from, object targeted, int x, int y) : this(from, targeted, true, false, + false, false, false, + null,null, false, 0, + null, -1, 0, + false,false, + false, null, x, y) + { + + } + + public XmlGetAttGump( Mobile from, object targeted, bool firststart, bool descend, + bool dosearchtype, bool dosearchname, bool dosearchage, + string searchtype, string searchname, bool searchagedirection, double searchage, + ArrayList searchlist, int selected, int displayfrom, + bool sorttype, bool sortname, + bool selectall, bool [] selectionlist, int X, int Y ) : base( X,Y ) + { + + m_TargetObject = targeted; + m_From = from; + m_SelectionList = selectionlist; + if(m_SelectionList == null){ + m_SelectionList = new bool[MaxEntries]; + } + SelectAll = selectall; + Sorttype = sorttype; + Sortname = sortname; + + DisplayFrom = displayfrom; + Selected = selected; + + Descendingsort = descend; + Dosearchtype = dosearchtype; + Dosearchname = dosearchname; + Dosearchage = dosearchage; + + Searchagedirection = searchagedirection; + + Searchage = searchage; + Searchtype = searchtype; + Searchname = searchname; + + m_SearchList = searchlist; + + if(firststart) + { + string status_str; + m_SearchList = Search(m_TargetObject,out status_str); + } + + // prepare the page + + AddPage( 0 ); + + AddBackground( 0, 0, 640, 474, 5054 ); + AddAlphaRegion( 0, 0, 640, 474 ); + + string tnamestr = null; + if(targeted is Item) + { + tnamestr = ((Item)targeted).Name; + } else + if(targeted is Mobile) + { + tnamestr = ((Mobile)targeted).Name; + } + AddLabel( 2, 0, 0x33, String.Format( "Attachments on {0} : {1}", targeted.GetType().Name, tnamestr ) ); + + // add the Sort button + AddButton( 5, 450, 0xFAB, 0xFAD, 700, GumpButtonType.Reply, 0 ); + AddLabel( 38, 450, 0x384, "Sort" ); + + // add the sort direction button + if(Descendingsort){ + AddButton( 75, 453, 0x15E2, 0x15E6, 701, GumpButtonType.Reply, 0 ); + AddLabel( 100, 450, 0x384, "descend" ); + } else { + AddButton( 75, 453, 0x15E0, 0x15E4, 701, GumpButtonType.Reply, 0 ); + AddLabel( 100, 450, 0x384, "ascend" ); + } + + // add the Sort on type toggle + AddRadio( 155, 450, 0xD2,0xD3, Sorttype, 0 ); + AddLabel( 155, 425, 0x384, "type" ); + + // add the Sort on name toggle + AddRadio( 200, 450, 0xD2,0xD3, Sortname, 1 ); + AddLabel( 200, 425, 0x384, "name" ); + + + AddLabel( 42, 13, 0x384, "Name" ); + AddLabel( 145, 13, 0x384, "Type" ); + AddLabel( 285, 13, 0x384, "Created" ); + AddLabel( 425, 13, 0x384, "Expires In" ); + AddLabel( 505, 13, 0x384, "Attached By" ); + + // add the Delete button + AddButton( 250, 450, 0xFB1, 0xFB3, 156, GumpButtonType.Reply, 0 ); + AddLabel( 283, 450, 0x384, "Delete" ); + + + // add the page buttons + for(int i = 0;i<(int)(MaxEntries/MaxEntriesPerPage);i++){ + //AddButton( 38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i ); + AddButton( 418+i*25, 450, 0x8B1+i, 0x8B1+i, 0, GumpButtonType.Page, 1+i ); + } + + // add the advance pageblock buttons + AddButton( 415+25*(int)(MaxEntries/MaxEntriesPerPage), 450, 0x15E1, 0x15E5, 201, GumpButtonType.Reply, 0 ); // block forward + AddButton( 395, 450, 0x15E3, 0x15E7, 202, GumpButtonType.Reply, 0 ); // block backward + + // add the displayfrom entry + AddLabel( 460, 450, 0x384, "Display" ); + AddImageTiled( 500, 450, 60, 21, 0xBBC ); + AddTextEntry( 501, 450, 60, 21, 0, 400, DisplayFrom.ToString() ); + AddButton( 560, 450, 0xFAB, 0xFAD, 9998, GumpButtonType.Reply, 0 ); + + // display the item list + if(m_SearchList != null){ + AddLabel( 320, 425, 68, String.Format("Found {0} attachments",m_SearchList.Count) ); + AddLabel( 500, 425, 68, String.Format("Displaying {0}-{1}",DisplayFrom, + (DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count)) ); + } + + // display the select-all-displayed toggle + AddButton( 620, 5, 0xD2, 0xD3, 3999, GumpButtonType.Reply, 0 ); + + // display the select-all toggle + AddButton( 600, 5, (SelectAll? 0xD3:0xD2), (SelectAll? 0xD2:0xD3), 3998, GumpButtonType.Reply, 0 ); + + for ( int i = 0; i < MaxEntries; i++ ) + { + int index = i + DisplayFrom; + if(m_SearchList == null || index >= m_SearchList.Count) break; + int page = (int)(i/MaxEntriesPerPage); + if(i%MaxEntriesPerPage == 0){ + AddPage(page+1); + } + + // background for search results area + //AddImageTiled( 235, 22 * (i%MaxEntriesPerPage) + 30, 386, 23, 0x52 ); + //AddImageTiled( 236, 22 * (i%MaxEntriesPerPage) + 31, 384, 21, 0xBBC ); + + // add the Props button for each entry + AddButton( 5, 22 * (i%MaxEntriesPerPage) + 30, 0xFAB, 0xFAD, 3000+i, GumpButtonType.Reply, 0 ); + + string namestr = null; + string typestr = null; + string expirestr = null; + //string description = null; + string attachedby = null; + string created = null; + + int texthue = 0; + + object o = (object)m_SearchList[index]; + + if(o is XmlAttachment){ + XmlAttachment a = (XmlAttachment)m_SearchList[index]; + + namestr = a.Name; + typestr = a.GetType().Name; + expirestr = a.Expiration.ToString(); + //description = a.OnIdentify(m_From); + created = a.CreationTime.ToString(); + attachedby = a.AttachedBy; + } + + bool sel=false; + if(m_SelectionList != null && i < m_SelectionList.Length){ + sel = m_SelectionList[i]; + } + if(sel) texthue = 33; + + if(i == Selected) texthue = 68; + + // display the name + AddImageTiled( 36, 22 * (i%MaxEntriesPerPage) + 31, 102, 21, 0xBBC ); + AddLabelCropped( 38, 22 * (i%MaxEntriesPerPage) + 31, 100, 21, texthue, namestr ); + + // display the type + AddImageTiled( 140, 22 * (i%MaxEntriesPerPage) + 31, 133, 21, 0xBBC ); + AddLabelCropped( 140, 22 * (i%MaxEntriesPerPage) + 31, 133, 21, texthue, typestr ); + + // display the creation time + AddImageTiled( 275, 22 * (i%MaxEntriesPerPage) + 31, 138, 21, 0xBBC ); + AddLabelCropped( 275, 22 * (i%MaxEntriesPerPage) + 31, 138, 21, texthue, created ); + + // display the expiration + AddImageTiled( 415, 22 * (i%MaxEntriesPerPage) + 31, 78, 21, 0xBBC ); + AddLabelCropped( 415, 22 * (i%MaxEntriesPerPage) + 31, 78, 21, texthue, expirestr ); + + // display the attachedby + AddImageTiled( 495, 22 * (i%MaxEntriesPerPage) + 31, 125, 21, 0xBBC ); + AddLabelCropped( 495, 22 * (i%MaxEntriesPerPage) + 31,105, 21, texthue, attachedby ); + + // display the descriptio button + AddButton( 600, 22 * (i%MaxEntriesPerPage) + 32, 0x5689, 0x568A, 5000+i, GumpButtonType.Reply, 0 ); + + // display the selection button + AddButton( 620, 22 * (i%MaxEntriesPerPage) + 32, (sel? 0xD3:0xD2), (sel? 0xD2:0xD3), 4000+i, GumpButtonType.Reply, 0 ); + } + } + + + private void DoShowProps(int index) + { + if(m_From == null || m_From.Deleted) return; + + if(index < m_SearchList.Count){ + object o = m_SearchList[index]; + if(o is XmlAttachment){ + XmlAttachment x = (XmlAttachment)o; + if(x == null || x.Deleted ) return; + + m_From.SendGump( new PropertiesGump( m_From, o ) ); + } + + } + } + + private void SortFindList() + { + if(m_SearchList != null && m_SearchList.Count > 0){ + if(Sorttype){ + this.m_SearchList.Sort( new ListTypeSorter(Descendingsort) ); + } else + if(Sortname){ + this.m_SearchList.Sort( new ListNameSorter(Descendingsort) ); + } + } + } + + private class ListTypeSorter : IComparer + { + private bool Dsort; + public ListTypeSorter(bool descend) : base () + { + Dsort = descend; + } + public int Compare( object x, object y ) + { + string xstr=null; + string ystr=null; + string str=null; + if(x is XmlAttachment){ + str = ((XmlAttachment)x).GetType().ToString(); + } + if(str != null){ + string [] arglist = str.Split('.'); + xstr = arglist[arglist.Length-1]; + } + + str = null; + if(y is XmlAttachment){ + str = ((XmlAttachment)y).GetType().ToString(); + } + if(str != null){ + string [] arglist = str.Split('.'); + ystr = arglist[arglist.Length-1]; + } + if(Dsort) + return String.Compare(ystr, xstr, true); + else + return String.Compare(xstr, ystr, true); + } + } + + private class ListNameSorter : IComparer + { + private bool Dsort; + + public ListNameSorter(bool descend) : base () + { + Dsort = descend; + } + public int Compare( object x, object y ) + { + string xstr=null; + string ystr=null; + + if(x is XmlAttachment){ + xstr = ((XmlAttachment)x).Name; + } + + if(y is XmlAttachment){ + ystr = ((XmlAttachment)y).Name; + } + if(Dsort) + return String.Compare(ystr, xstr, true); + else + return String.Compare(xstr, ystr, true); + } + } + + + private void Refresh(NetState state) + { + state.Mobile.SendGump( new XmlGetAttGump(this.m_From, this.m_TargetObject, false, this.Descendingsort, + this.Dosearchtype, this.Dosearchname, this.Dosearchage, + this.Searchtype, this.Searchname, this.Searchagedirection, this.Searchage, + this.m_SearchList, this.Selected, this.DisplayFrom, + this.Sorttype, this.Sortname, + this.SelectAll, this.m_SelectionList, this.X, this.Y)); + } + + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if(info.Switches.Length > 0){ + radiostate = info.Switches[0]; + } + + // read the text entries for the search criteria + + Searchage = 0; + + TextRelay tr = info.GetTextEntry( 400 ); // displayfrom info + try{ + DisplayFrom = int.Parse(tr.Text); + } catch{} + + switch ( info.ButtonID ) + { + + case 0: // Close + { + return; + } + + case 156: // Delete selected items + { + Refresh(state); + int allcount = 0; + if(m_SearchList != null) + allcount = m_SearchList.Count; + state.Mobile.SendGump( new XmlConfirmDeleteGump(state.Mobile, m_TargetObject, m_SearchList, m_SelectionList, DisplayFrom, SelectAll, allcount) ); + return; + } + + case 201: // forward block + { + // clear the selections + if(m_SelectionList != null && !SelectAll) Array.Clear(m_SelectionList,0,m_SelectionList.Length); + if(m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) { + DisplayFrom += MaxEntries; + // clear any selection + Selected = -1; + } + break; + } + case 202: // backward block + { + // clear the selections + if(m_SelectionList != null && !SelectAll) Array.Clear(m_SelectionList,0,m_SelectionList.Length); + DisplayFrom -= MaxEntries; + if(DisplayFrom < 0) DisplayFrom = 0; + // clear any selection + Selected = -1; + break; + } + + case 700: // Sort + { + // clear any selection + Selected = -1; + // clear the selections + if(m_SelectionList != null && !SelectAll) Array.Clear(m_SelectionList,0,m_SelectionList.Length); + Sorttype = false; + Sortname = false; + + // read the toggle switches that determine the sort + if ( radiostate == 0 ) // sort by type + { + Sorttype = true; + } + if ( radiostate == 1 ) // sort by name + { + Sortname = true; + } + SortFindList(); + break; + } + case 701: // descending sort + { + Descendingsort = !Descendingsort; + break; + } + case 9998: // refresh the gump + { + // clear any selection + Selected = -1; + break; + } + default: + { + + + if(info.ButtonID >= 3000 && info.ButtonID < 3000+ MaxEntries){ + + Selected = info.ButtonID - 3000; + // Show the props window + Refresh(state); + + DoShowProps(info.ButtonID - 3000 + DisplayFrom); + return; + } + + if(info.ButtonID == 3998){ + + SelectAll = !SelectAll; + + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null) + { + for(int i = 0; i < MaxEntries;i++) + { + if(i < m_SelectionList.Length){ + // only toggle the selection list entries for things that actually have entries + m_SelectionList[i] = SelectAll; + } else + { + break; + } + } + } + } + if(info.ButtonID == 3999){ + + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null && m_SearchList != null && !SelectAll) + { + for(int i = 0; i < MaxEntries;i++) + { + if(i < m_SelectionList.Length){ + // only toggle the selection list entries for things that actually have entries + if((m_SearchList.Count - DisplayFrom > i)) { + m_SelectionList[i] = !m_SelectionList[i]; + } + } else + { + break; + } + } + } + } + if(info.ButtonID >= 4000 && info.ButtonID < 4000+ MaxEntries){ + int i = info.ButtonID - 4000; + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null && i >= 0 && i < m_SelectionList.Length && !SelectAll){ + // only toggle the selection list entries for things that actually have entries + if(m_SearchList != null && (m_SearchList.Count - DisplayFrom > i)) { + m_SelectionList[i] = !m_SelectionList[i]; + } + } + } + if(info.ButtonID >= 5000 && info.ButtonID < 5000+ MaxEntries){ + int i = info.ButtonID - 5000; + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null && i >= 0 && i < m_SelectionList.Length && !SelectAll){ + // only toggle the selection list entries for things that actually have entries + if(m_SearchList != null && (m_SearchList.Count - DisplayFrom > i)) { + XmlAttachment a = m_SearchList[i+DisplayFrom] as XmlAttachment; + if(a != null) + { + state.Mobile.SendMessage(a.OnIdentify(state.Mobile)); + } + } + } + } + break; + } + } + // Create a new gump + //m_Spawner.OnDoubleClick( state.Mobile); + Refresh(state); + } + + + public class XmlConfirmDeleteGump : Gump + { + private ArrayList SearchList; + private bool [] SelectedList; + private Mobile From; + private int DisplayFrom; + private bool selectAll; + private object m_target; + + public XmlConfirmDeleteGump(Mobile from, object target, ArrayList searchlist, bool [] selectedlist, int displayfrom, bool selectall, int allcount) : base ( 0, 0 ) + { + SearchList = searchlist; + SelectedList = selectedlist; + DisplayFrom = displayfrom; + selectAll = selectall; + m_target = target; + From = from; + Closable = false; + Dragable = true; + AddPage( 0 ); + AddBackground( 10, 200, 200, 130, 5054 ); + int count = 0; + if(selectall) + { + count = allcount; + } else + { + for(int i =0;i 0){ + radiostate = info.Switches[0]; + } + switch(info.ButtonID) + { + + default: + { + if(radiostate == 1 && SearchList != null && SelectedList != null) + { // accept + for(int i = 0;i < SearchList.Count;i++){ + int index = i-DisplayFrom; + if((index >= 0 && index < SelectedList.Length && SelectedList[index] == true) || selectAll){ + object o = SearchList[i]; + if(o is XmlAttachment) + { + // some objects may not delete gracefully (null map items are particularly error prone) so trap them + try { + ((XmlAttachment)o).Delete(); + } catch {} + } + } + } + // refresh the gump + state.Mobile.CloseGump(typeof(XmlGetAttGump)); + state.Mobile.SendGump(new XmlGetAttGump(state.Mobile,m_target,0,0)); + } + break; + } + } + } + } + + } + + +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/TemporaryQuestObject.cs b/Scripts/Customs/XML Spawner/XmlAttachments/TemporaryQuestObject.cs new file mode 100644 index 0000000..87f65e4 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/TemporaryQuestObject.cs @@ -0,0 +1,115 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + // When this attachment is deleted, the object that it is attached to will be deleted as well. + // The quest system will automatically delete these attachments after a quest is completed. + // Specifying an expiration time will also allow you to give objects limited lifetimes. + public class TemporaryQuestObject : XmlAttachment, ITemporaryQuestAttachment + { + + private Mobile m_QuestOwner; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile QuestOwner + { + get {return m_QuestOwner;} + set {m_QuestOwner = value;} + } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public TemporaryQuestObject(ASerial serial) : base(serial) + { + } + + [Attachable] + public TemporaryQuestObject(string questname) + { + Name = questname; + } + + [Attachable] + public TemporaryQuestObject(string questname, double expiresin) + { + Name = questname; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + [Attachable] + public TemporaryQuestObject(string questname, double expiresin, Mobile questowner) + { + Name = questname; + Expiration = TimeSpan.FromMinutes(expiresin); + QuestOwner = questowner; + + } + + public override void OnDelete() + { + base.OnDelete(); + + // delete the object that it is attached to + if(AttachedTo is Mobile) + { + // dont allow deletion of players + if(!((Mobile)AttachedTo).Player) + { + SafeMobileDelete((Mobile)AttachedTo); + //((Mobile)AttachedTo).Delete(); + } + } + else + if(AttachedTo is Item) + { + SafeItemDelete((Item)AttachedTo); + //((Item)AttachedTo).Delete(); + } + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + + // version 0 + writer.Write(m_QuestOwner); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + // version 0 + m_QuestOwner = reader.ReadMobile(); + + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("{1} expires in {0} mins",Expiration.TotalMinutes, Name); + } else + { + return String.Format("{1}: QuestOwner {0}",QuestOwner, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddFame.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddFame.cs new file mode 100644 index 0000000..5323c35 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddFame.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlAddFame : XmlAttachment + { + private int m_DataValue; // default data + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get{ return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlAddFame(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlAddFame( int value) + { + Value = value; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadInt(); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is PlayerMobile) + { + // for players just add it immediately + ((Mobile)AttachedTo).Fame += Value; + + ((Mobile)AttachedTo).SendMessage("Receive {0}",OnIdentify((Mobile)AttachedTo)); + + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } + else + if(AttachedTo is Item) + { + // dont allow item attachments + Delete(); + } + + } + + public override bool HandlesOnKilled { get { return true; } } + + public override void OnKilled(Mobile killed, Mobile killer ) + { + base.OnKilled(killed, killer); + + if(killer == null) return; + + killer.Fame += Value; + + killer.SendMessage("Receive {0}",OnIdentify(killer)); + } + + + public override string OnIdentify(Mobile from) + { + + return String.Format("{0} Fame", Value); + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddKarma.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddKarma.cs new file mode 100644 index 0000000..cbd1ba7 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddKarma.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlAddKarma : XmlAttachment + { + private int m_DataValue; // default data + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get{ return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlAddKarma(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlAddKarma( int value) + { + Value = value; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadInt(); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is PlayerMobile) + { + // for players just add it immediately + ((Mobile)AttachedTo).Karma += Value; + + ((Mobile)AttachedTo).SendMessage("Receive {0}",OnIdentify((Mobile)AttachedTo)); + + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } + else + if(AttachedTo is Item) + { + // dont allow item attachments + Delete(); + } + + } + + public override bool HandlesOnKilled { get { return true; } } + + public override void OnKilled(Mobile killed, Mobile killer ) + { + base.OnKilled(killed, killer); + + if(killer == null) return; + + killer.Karma += Value; + + killer.SendMessage("Receive {0}",OnIdentify(killer)); + } + + + public override string OnIdentify(Mobile from) + { + + return String.Format("{0} Karma", Value); + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddTithing.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddTithing.cs new file mode 100644 index 0000000..c2d4be2 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddTithing.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlAddTithing : XmlAttachment + { + private int m_DataValue; // default data + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get{ return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlAddTithing(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlAddTithing( int value) + { + Value = value; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadInt(); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is PlayerMobile) + { + // for players just add it immediately + ((Mobile)AttachedTo).TithingPoints += Value; + + ((Mobile)AttachedTo).SendMessage("Receive {0}",OnIdentify((Mobile)AttachedTo)); + + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } + else + if(AttachedTo is Item) + { + // dont allow item attachments + Delete(); + } + + } + + public override bool HandlesOnKilled { get { return true; } } + + public override void OnKilled(Mobile killed, Mobile killer ) + { + base.OnKilled(killed, killer); + + if(killer == null) return; + + killer.TithingPoints += Value; + + killer.SendMessage("Receive {0}",OnIdentify(killer)); + } + + + public override string OnIdentify(Mobile from) + { + + return String.Format("{0} TithingPoints", Value); + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddVirtue.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddVirtue.cs new file mode 100644 index 0000000..a74d36e --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlAddVirtue.cs @@ -0,0 +1,138 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlAddVirtue : XmlAttachment + { + private int m_DataValue; // default data + private string m_Virtue; + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get{ return m_DataValue; } set { m_DataValue = value; } } + public string Virtue { get{ return m_Virtue; } set { m_Virtue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlAddVirtue(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlAddVirtue(string virtue, int value) + { + Value = value; + Virtue = virtue; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_DataValue); + writer.Write(m_Virtue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadInt(); + m_Virtue = reader.ReadString(); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is PlayerMobile) + { + // for players just add it immediately + // lookup the virtue type + VirtueName g = (VirtueName)0; + bool valid = true; + bool gainedPath = false; + try{ + g = (VirtueName)Enum.Parse(typeof(VirtueName),Virtue, true); + } catch{valid = false;} + + if(valid) + { + + VirtueHelper.Award( (Mobile)AttachedTo, g, Value, ref gainedPath ); + + ((Mobile)AttachedTo).SendMessage("Receive {0}",OnIdentify((Mobile)AttachedTo)); + + if(gainedPath) + { + ((Mobile)AttachedTo).SendMessage("You have gained a path in {0}",Virtue); + } + } else + { + ((Mobile)AttachedTo).SendMessage("{0}: no such Virtue", Virtue); + } + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } else + if(AttachedTo is Item) + { + // dont allow item attachments + Delete(); + } + + } + + public override bool HandlesOnKilled { get { return true; } } + + public override void OnKilled(Mobile killed, Mobile killer ) + { + base.OnKilled(killed, killer); + + if(killer == null) return; + + VirtueName g = (VirtueName)0; + bool valid = true; + bool gainedPath = false; + try{ + g = (VirtueName)Enum.Parse(typeof(VirtueName),Virtue, true); + } catch{valid = false;} + + if(valid) + { + // give the killer the Virtue + + VirtueHelper.Award( killer, g, Value, ref gainedPath ); + + if(gainedPath) + { + killer.SendMessage("You have gained a path in {0}",Virtue); + } + + killer.SendMessage("Receive {0}",OnIdentify(killer)); + } + } + + + public override string OnIdentify(Mobile from) + { + + return String.Format("{0} {1} Virtue points", Value, Virtue); + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlCustomAttacks.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlCustomAttacks.cs new file mode 100644 index 0000000..34f5b60 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlCustomAttacks.cs @@ -0,0 +1,1108 @@ +using System; +using System.Data; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using Server.Gumps; +using System.Text; + +/* +** XmlCustomAttacks +** 11/16/04 +** ArteGordon +** +** This attachment will allow you to create a system for adding special attacks to weapons including combo attacks that require +** a series of specific special attacks to be executed in a timed sequence +** +** Version 1.01 +** updated 11/26/04 +** - restricted attachment to weapons only. +** - added a few more example custom attacks +*/ +namespace Server.Engines.XmlSpawner2 +{ + public class XmlCustomAttacks : XmlAttachment + { + + // ------------------------------------------------------------------------------ + // BEGINNING of user-defined special attacks and combos information + // ------------------------------------------------------------------------------ + + // + // define the Combo and special attack enums + // + // you must first add entries here if you wish to add new attacks + // + + // ATTACKS + public enum ComboAttacks + { + ThunderStrike, + LightningRain, + SqueezingFist + } + + public enum SpecialAttacks + { + TripleSlash, + MindDrain, + StamDrain, + ParalyzingFear, + GiftOfHealth, + VortexStrike, + PuffOfSmoke + } + + public static new void Initialize() + { + // + // define the special attacks and their use requirements + // + // ideally, you have a definition for every SpecialAttacks enum. Although it isnt absolutely necessary, + // if it isnt defined here, it will not be available for use + + AddSpecialAttack("Triple Slash", "Deals triple the max damage of the weapon", // attack name, and description + SpecialAttacks.TripleSlash, 0x520C, TimeSpan.FromSeconds(3.5), // attack id, id of gump icon, and chaining time + 30, 20, 5, 0, // mana, stam, hits, karma usage + 70,30,0, // str, dex, int requirements + new SkillName [] { SkillName.ArmsLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(MandrakeRoot)}, // reagent list + new int [] { 1 } // reagent quantities + ); + + AddSpecialAttack("Mind Drain", "Drains mana from the target", + SpecialAttacks.MindDrain, 0x5007, IconTypes.GumpID, TimeSpan.FromSeconds(3.5), // explicitly specifying the gump icon as a gumpid + 10, 5, 5, 0, + 0,0,40, + new SkillName [] { SkillName.Magery }, + new int [] { 50 }, + null, + null + ); + AddSpecialAttack("Vortex Strike", "Calls an energy vortex to aid you in battle", + SpecialAttacks.VortexStrike, 0x20b9, IconTypes.ItemID,TimeSpan.FromSeconds(3.5), // example of using an itemid for the gump icon + 40, 20, 0, 0, + 0,0,30, + new SkillName [] { SkillName.Magery }, + new int [] { 60 }, + new Type [] {typeof(Diamond)}, + new int [] { 3 } + ); + + + AddSpecialAttack("Stam Drain", "Drains stamina from the target", + SpecialAttacks.StamDrain, 0x500e, TimeSpan.FromSeconds(3.5), // if the icon type is not specified, gump icons use gumpids + 30, 5, 0, 0, + 40, 40, 0, + null, + null, + new Type [] {typeof(Ginseng), typeof(Garlic)}, + new int [] { 1, 2 } + ); + + AddSpecialAttack("Paralyzing Fear", "Paralyzes the target and causes it to flee", + SpecialAttacks.ParalyzingFear, 0x500d, TimeSpan.FromSeconds(3.5), + 10, 10, 5, 10, + 0, 0, 40, + new SkillName [] { SkillName.Necromancy }, + new int [] { 30 }, + new Type [] {typeof(Head)}, + new int [] { 1 } + ); + + AddSpecialAttack("Gift of Health", "Restores attacker to full health", + SpecialAttacks.GiftOfHealth, 0x500c, TimeSpan.FromSeconds(3.5), + 40, 20, 0, 0, + 0, 0, 30, + new SkillName [] { SkillName.Healing }, + new int [] { 60 }, + new Type [] {typeof(Ginseng), typeof(MandrakeRoot), typeof(Gold)}, + new int [] { 2, 2, 50 } + ); + + AddSpecialAttack("Puff of Smoke", "Makes the attacker invisible", + SpecialAttacks.PuffOfSmoke, 0x520b, TimeSpan.FromSeconds(3.5), + 20, 40, 0, 0, + 0, 40, 0, + new SkillName [] { SkillName.Stealth, SkillName.Hiding }, + new int [] { 50, 50 }, + new Type [] {typeof(SpidersSilk)}, + new int [] { 2 } + ); + + + // + // define combos and the sequence of special attacks needed to activate them + // + AddComboAttack( "Thunder Strike", ComboAttacks.ThunderStrike, // combo name, and id + new SpecialAttacks [] // list of special attacks needed to complete the combo + { + SpecialAttacks.TripleSlash, + SpecialAttacks.MindDrain, + SpecialAttacks.ParalyzingFear, + SpecialAttacks.TripleSlash, + SpecialAttacks.StamDrain + } + ); + + AddComboAttack( "Lightning Rain", ComboAttacks.LightningRain, + new SpecialAttacks [] + { + SpecialAttacks.TripleSlash, + SpecialAttacks.MindDrain, + SpecialAttacks.MindDrain, + SpecialAttacks.StamDrain + } + ); + + AddComboAttack( "Squeezing Fist", ComboAttacks.SqueezingFist, + new SpecialAttacks [] + { + SpecialAttacks.MindDrain, + SpecialAttacks.StamDrain + } + ); + + // after deser, restore combo and specials lists to all existing CustomAttacks attachments based on these definitions + foreach(XmlAttachment x in XmlAttach.AllAttachments.Values) + { + if(x is XmlCustomAttacks) + { + ((XmlCustomAttacks)x).FillComboList(); + ((XmlCustomAttacks)x).FillSpecialsList(); + } + } + } + + // + // carry out the special attacks + // + // If you add a new attack, you must add the code here to define what it actually does when it hits + // + public void DoSpecialAttack(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven, SpecialAttack special) + { + + if(attacker == null || defender == null || weapon == null || special == null) return; + + attacker.SendMessage("you strike with {0}!", special.Name); + + // apply the special attack + switch(special.AttackID) + { + case SpecialAttacks.TripleSlash: + { + defender.Damage( weapon.MaxDamage*3, attacker ); + break; + } + case SpecialAttacks.MindDrain: + { + defender.Mana -= weapon.MaxDamage; + attacker.Mana += weapon.MaxDamage; + break; + } + case SpecialAttacks.VortexStrike: + { + attacker.PlaySound( 0x217 ); + BaseCreature m = new EnergyVortex(); + m.Summoned = true; + m.SummonMaster = attacker; + m.Combatant = defender; + m.MoveToWorld(defender.Location, defender.Map); + break; + } + case SpecialAttacks.StamDrain: + { + defender.Stam -= weapon.MaxDamage; + attacker.Stam += weapon.MaxDamage; + break; + } + case SpecialAttacks.PuffOfSmoke: + { + attacker.Hidden = true; + break; + } + case SpecialAttacks.GiftOfHealth: + { + attacker.FixedEffect( 0x376A, 9, 32 ); + attacker.PlaySound( 0x202 ); + attacker.Hits = attacker.HitsMax; + break; + } + case SpecialAttacks.ParalyzingFear: + { + // lose target focus + defender.Combatant = null; + // flee + if(defender is BaseCreature) + { + ((BaseCreature)defender).BeginFlee(TimeSpan.FromSeconds(6)); + } + // and become paralyzed + defender.Freeze( TimeSpan.FromSeconds(3) ); + defender.FixedEffect( 0x376A, 9, 32 ); + defender.PlaySound( 0x204 ); + break; + } + default: + attacker.SendMessage("no effect"); + break; + } + } + + // + // carry out the combo attacks + // + // If you add a new combo, you must add the code here to define what it actually does when it is activated + // + public void DoComboAttack(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven, ComboAttack combo) + { + if(attacker == null || defender == null || weapon == null || combo == null) return; + + attacker.SendMessage("You unleash the combo attack {0}!",combo.Name); + + // apply the combo attack + switch(combo.AttackID) + { + case ComboAttacks.ThunderStrike: + { + defender.FixedEffect( 0x376A, 9, 32 ); + defender.PlaySound( 0x28 ); + // 5x damage + defender.Damage( weapon.MaxDamage*5, attacker ); + // mana and stam drain + defender.Mana -= weapon.MaxDamage*3; + defender.Stam -= weapon.MaxDamage*3; + // full self heal + attacker.FixedEffect( 0x376A, 9, 32 ); + attacker.Hits = attacker.HitsMax; + break; + } + case ComboAttacks.LightningRain: + { + defender.Damage( weapon.MaxDamage*3, attacker ); + defender.Mana -= weapon.MaxDamage*7; + defender.Stam -= weapon.MaxDamage*4; + break; + } + case ComboAttacks.SqueezingFist: + { + // 5 sec paralyze + defender.FixedEffect( 0x376A, 9, 32 ); + defender.PlaySound( 0x204 ); + defender.Freeze( TimeSpan.FromSeconds(5) ); + // 7x stam drain + defender.Stam -= weapon.MaxDamage*7; + break; + } + } + } + + + [Attachable] + public XmlCustomAttacks(string name, int nspecials) + { + + FillComboList(); + + // + // you can put any named specials configurations that you want in here + // + if(String.Compare("tartan", name, true) == 0) + { + AddSpecial(SpecialAttacks.TripleSlash); + AddSpecial(SpecialAttacks.MindDrain); + AddSpecial(SpecialAttacks.StamDrain); + AddSpecial(SpecialAttacks.ParalyzingFear); + } else + if(String.Compare("balzog", name, true) == 0) + { + AddSpecial(SpecialAttacks.StamDrain); + AddSpecial(SpecialAttacks.ParalyzingFear); + } else + if(String.Compare("klamath", name, true) == 0) + { + AddSpecial(SpecialAttacks.TripleSlash); + AddSpecial(SpecialAttacks.MindDrain); + } else + if(String.Compare("random", name, true) == 0) + { + // assign the requested number of random special attacks + SetRandomSpecials(nspecials); + } + } + + + // this constructor is intended to be called from within scripts that wish to define custom attack configurations + // by passing it a list of SpecialAttacks + public XmlCustomAttacks(SpecialAttacks [] attacklist) + { + if(attacklist != null) + { + foreach(SpecialAttacks sid in attacklist) + { + AddSpecial(sid); + } + } + } + + public XmlCustomAttacks(SpecialAttacks attack) + { + AddSpecial(attack); + } + + [Attachable] + public XmlCustomAttacks(string name) : this(name, 1) + { + } + + [Attachable] + public XmlCustomAttacks() : this("random", 1) + { + } + + // ------------------------------------------------------------------------------ + // END of user-defined special attacks and combos information + // ------------------------------------------------------------------------------ + + private static Hashtable AllSpecials = new Hashtable(); + private static Hashtable AllCombos = new Hashtable(); + + public enum IconTypes + { + GumpID, + ItemID + } + + public class SpecialAttack + { + public string Name; // attack name + public string Description; // attack description + public SpecialAttacks AttackID; // attack id + public TimeSpan ChainTime; // time available until next attack in the chain must be performed + public int Icon; // button icon for this attack + public IconTypes IconType; // what type of art to use for button icon + public int ManaReq; // mana usage for this attack + public int StamReq; // stamina usage for this attack + public int HitsReq; // hits usage for this attack + public int KarmaReq; // karma usage for this attack + public int StrReq; // str requirements for this attack + public int DexReq; // dex requirements for this attack + public int IntReq; // int requirements for this attack + public Type [] Reagents; // reagent list used for this attack + public int [] Quantity; // reagent quantity list + public SkillName [] Skills; // list of skill requirements for this attack + public int [] MinSkillLevel; // minimum skill levels + + public SpecialAttack( string name, string description, SpecialAttacks id, int icon, IconTypes itype, TimeSpan duration, + int mana, int stam, int hits, int karma, int minstr, int mindex, int minint, + SkillName [] skills, int [] minlevel, Type [] reagents, int [] quantity) + { + Name = name; + Description = description; + AttackID = id; + ChainTime = duration; + Icon = icon; + IconType = itype; + ManaReq = mana; + StamReq = stam; + HitsReq = hits; + KarmaReq = karma; + StrReq = minstr; + DexReq = mindex; + IntReq = minint; + Reagents = reagents; + Quantity = quantity; + Skills = skills; + MinSkillLevel = minlevel; + } + } + + public class ComboAttack + { + public string Name; + public ComboAttacks AttackID; + public SpecialAttacks [] AttackSequence; + + public ComboAttack( string name, ComboAttacks id, SpecialAttacks [] sequence) + { + Name = name; + AttackID = id; + AttackSequence = sequence; + } + } + + public class ActiveCombo + { + public ComboAttack Combo; + public int PositionInSequence; + + public ActiveCombo(ComboAttack c) + { + Combo = c; + PositionInSequence = 0; + } + } + + private ComboTimer m_ComboTimer; + public SpecialAttack m_SelectedAttack; + + // these are the lists of special moves and combo status for each instance + private ArrayList Specials = new ArrayList(); + private ArrayList Combos = new ArrayList(); + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlCustomAttacks(ASerial serial) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + + // version 0 + // save the specials for this instance + writer.Write( Specials.Count); + + foreach(SpecialAttack s in Specials) + { + writer.Write(s.AttackID.ToString()); + } + } + + private ArrayList tmpSpecialsList = new ArrayList(); + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + + case 0: + // version 0 + int count = reader.ReadInt(); + + for(int i = 0; i 0) + { + int ntries = 0; + int total = 0; + ArrayList tmplist = new ArrayList(); + while(total < count) + { + int rand = Utility.Random(nspecials); + int nrtries = 0; + while(tmplist.Contains(rand)) + { + rand = Utility.Random(nspecials); + // add some sanity checking + if(nrtries++ > 100) break; + } + + tmplist.Add(rand); + + SpecialAttack s = GetSpecialAttack((SpecialAttacks)rand); + if(s != null) + { + Specials.Add(s); + total++; + } + + // add some sanity checking + if(tmplist.Count >= nspecials) break; + if(ntries++ > 100) break; + } + } + } + + private void ResetCombos() + { + foreach(ActiveCombo c in Combos) + { + c.PositionInSequence = 0; + } + } + + private bool HasActiveCombos + { + get{ + if(Combos == null) return false; + + foreach(ActiveCombo c in Combos) + { + if(c.PositionInSequence > 0) return true; + } + + return false; + } + } + + private void CheckCombos(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven, SpecialAttack s) + { + if(s == null) return; + + foreach(ActiveCombo c in Combos) + { + if(c != null && c.Combo != null && c.Combo.AttackSequence != null && c.PositionInSequence < c.Combo.AttackSequence.Length) + { + if(c.Combo.AttackSequence[c.PositionInSequence] == s.AttackID) + { + if(++c.PositionInSequence >= c.Combo.AttackSequence.Length) + { + // combo is complete so execute it + DoComboAttack(attacker, defender, weapon, damageGiven, c.Combo); + + // and reset it + c.PositionInSequence = 0; + } + } else + { + // out of sequence so reset the combo + c.PositionInSequence = 0; + } + } + } + } + + public static bool CheckRequirements(Mobile from, SpecialAttack s) + { + if(from == null || s == null) return false; + + // test for str, dex, int requirements + if(from.Str < s.StrReq) + { + from.SendMessage("Need {0} Str to perform {1}", s.StrReq, s.Name); + return false; + } + if(from.Dex < s.DexReq) + { + from.SendMessage("Need {0} Dex to perform {1}", s.DexReq, s.Name); + return false; + } + if(from.Int < s.IntReq) + { + from.SendMessage("Need {0} Int to perform {1}", s.IntReq, s.Name); + return false; + } + + // test for skill requirements + if(s.Skills != null && s.MinSkillLevel != null) + { + if(from.Skills == null) return false; + + for(int i = 0; i < s.Skills.Length; i++) + { + // and check level + if(i < s.MinSkillLevel.Length) + { + Skill skill = from.Skills[s.Skills[i]]; + if(skill != null && s.MinSkillLevel[i] > skill.Base) + { + from.SendMessage("Need {0} {1} to perform {2}", s.MinSkillLevel[i], s.Skills[i].ToString(), s.Name); + return false; + } + } else + { + from.SendMessage(33,"Error in skill level specification for {0}", s.Name); + return false; + } + } + } + + + // test for mana, stam, and hits requirements + if(from.Mana < s.ManaReq) + { + from.SendMessage("Need {0} Mana to perform {1}", s.ManaReq, s.Name); + return false; + } + if(from.Stam < s.StamReq) + { + from.SendMessage("Need {0} Stamina to perform {1}", s.StamReq, s.Name); + return false; + } + if(from.Hits < s.HitsReq) + { + // clear the selected attack + from.SendMessage("Need {0} Hits to perform {1}", s.HitsReq, s.Name); + return false; + } + + + // check for any reagents that are specified + if(s.Reagents != null && s.Quantity != null) + { + if(from.Backpack == null) return false; + + for(int i = 0; i < s.Reagents.Length; i++) + { + // go through each reagent + Item ret = from.Backpack.FindItemByType(s.Reagents[i], true); + + // and check quantity + if(i < s.Quantity.Length) + { + if(ret == null || s.Quantity[i] > ret.Amount) + { + from.SendMessage("Need {1} {0} to perform {2}", s.Reagents[i].Name, s.Quantity[i], s.Name); + return false; + } + } else + { + from.SendMessage(33,"Error in quantity specification for {0}", s.Name); + return false; + } + } + } + return true; + } + + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + if(attacker == null || defender == null || weapon == null || m_SelectedAttack == null) return; + + if(!CheckRequirements(attacker, m_SelectedAttack)) return; + + // take the requirements + if(attacker.Backpack != null && m_SelectedAttack.Reagents != null && m_SelectedAttack.Quantity != null) + { + attacker.Backpack.ConsumeTotal( m_SelectedAttack.Reagents, m_SelectedAttack.Quantity, true); + } + + attacker.Mana -= m_SelectedAttack.ManaReq; + attacker.Stam -= m_SelectedAttack.StamReq; + attacker.Hits -= m_SelectedAttack.HitsReq; + attacker.Karma -= m_SelectedAttack.KarmaReq; + + // apply the attack + DoSpecialAttack( attacker, defender, weapon, damageGiven, m_SelectedAttack); + + if(m_SelectedAttack.KarmaReq > 0) + { + attacker.SendMessage("and lose a little karma."); + } + + // after applying a special attack activate the specials timer for combo chaining + DoComboTimer(attacker, m_SelectedAttack.ChainTime); + + // check all combos to see which have this attack as the next in sequence, and which might be complete + CheckCombos(attacker, defender, weapon, damageGiven, m_SelectedAttack); + + // clear the selected attack + m_SelectedAttack = null; + + // redisplay the gump + attacker.SendGump(new CustomAttacksGump(attacker, this)); + } + + public override void OnEquip( Mobile from ) + { + // open the specials gump + if(from == null || !from.Player) return; + + from.SendGump(new CustomAttacksGump(from, this)); + + } + + public override void OnRemoved( object parent ) + { + // open the specials gump + if(parent != null && parent is Mobile && ((Mobile)parent).Player) + { + ((Mobile)parent).CloseGump(typeof( CustomAttacksGump )); + } + } + + public override string OnIdentify(Mobile from) + { + + string msg = "Special Attacks:"; + + foreach(SpecialAttack s in Specials) + { + msg += String.Format("\n{0}", s.Name); + } + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("{0}\nexpires in {0} mins ", msg, Expiration.TotalMinutes); + } + + return msg; + } + + public override void OnAttach() + { + base.OnAttach(); + + // only allow attachment to weapons and shields + if(!(AttachedTo is BaseWeapon)) + { + Delete(); + } + } + + public void DoComboTimer(Mobile from, TimeSpan delay) + { + if ( m_ComboTimer != null ) + m_ComboTimer.Stop(); + + m_ComboTimer = new ComboTimer(from, this, delay); + + m_ComboTimer.Start(); + } + + private class ComboTimer : Timer + { + private XmlCustomAttacks m_attachment; + private Mobile m_from; + + public ComboTimer( Mobile from, XmlCustomAttacks a, TimeSpan delay ) : base( delay ) + { + Priority = TimerPriority.OneSecond; + m_attachment = a; + m_from = from; + } + + protected override void OnTick() + { + if(m_attachment == null || m_attachment.Deleted) return; + + // the combo has expired + m_attachment.ResetCombos(); + + // refresh the gump + if(m_from != null) + { + m_from.SendGump(new CustomAttacksGump(m_from, m_attachment)); + } + } + } + + private class CustomAttacksInfoGump : Gump + { + private XmlCustomAttacks m_attachment; + private SpecialAttack m_special; + + public CustomAttacksInfoGump( Mobile from, XmlCustomAttacks a, SpecialAttack s) : base( 0,0) + { + + m_attachment = a; + m_special = s; + + // prepare the page + AddPage( 0 ); + + AddBackground( 0, 0, 400, 300, 5054 ); + AddAlphaRegion( 0, 0, 400, 300 ); + AddLabel( 20, 2, 55, String.Format("{0}",s.Name) ); + + StringBuilder text = new StringBuilder(); + + text.AppendFormat("\n{0}", s.Description ); + + + text.AppendFormat("\n\nMinimum Stats/Skills:" ); + if(s.StrReq > 0) + { + text.AppendFormat("\n {0} Str", s.StrReq ); + } + if(s.DexReq > 0) + { + text.AppendFormat("\n {0} Dex", s.DexReq ); + } + if(s.IntReq > 0) + { + text.AppendFormat("\n {0} Int", s.IntReq ); + } + + if(s.Skills != null) + for(int i = 0;i < s.Skills.Length;i++) + { + if(i < s.MinSkillLevel.Length) + { + text.AppendFormat("\n {1} {0}", s.Skills[i].ToString(), s.MinSkillLevel[i] ); + } else + { + text.AppendFormat("\n {1} {0}", s.Skills[i].ToString(), "???" ); + } + } + + text.AppendFormat("\n\nConsumes:" ); + + // generate the text requirements + if(s.ManaReq > 0) + { + text.AppendFormat("\n {0} Mana", s.ManaReq ); + } + if(s.StamReq > 0) + { + text.AppendFormat("\n {0} Stamina", s.StamReq ); + } + if(s.HitsReq > 0) + { + text.AppendFormat("\n {0} Hits", s.HitsReq ); + } + if(s.KarmaReq > 0) + { + text.AppendFormat("\n {0} Karma", s.KarmaReq ); + } + + if(s.Reagents != null) + for(int i = 0;i < s.Reagents.Length;i++) + { + if(i < s.Quantity.Length) + { + text.AppendFormat("\n {1} {0}", s.Reagents[i].Name, s.Quantity[i] ); + } else + { + text.AppendFormat("\n {1} {0}", s.Reagents[i].Name, "???" ); + } + } + + AddHtml( 20,20, 360, 260, text.ToString(), true , true ); + } + } + + private class CustomAttacksGump : Gump + { + private XmlCustomAttacks m_attachment; + private const int vertspacing = 47; + + public CustomAttacksGump( Mobile from, XmlCustomAttacks a) : base( 0,0) + { + if(a == null) + { + return; + } + if(from != null) + from.CloseGump(typeof( CustomAttacksGump)); + + m_attachment = a; + + int specialcount = a.Specials.Count; + + // prepare the page + AddPage( 0 ); + + AddBackground( 0, 0, 70, 75 + specialcount*vertspacing, 5054 ); + AddLabel( 15, 2, 55, "Attack" ); + // if combos are still active then give it the green light + if(m_attachment != null && m_attachment.HasActiveCombos) + { + // green button + //AddImage( 20, 10, 0x2a4e ); + AddImage( 15, 25, 0x0a53 ); + } else + { + // red button + //AddImage( 20, 10, 0x2a62 ); + AddImage( 15, 25, 0x0a52 ); + } + // go through the list of enabled moves and add buttons for them + int y = 70; + for(int i = 0;i 0) + { + int ntries = 0; + int total = 0; + ArrayList tmplist = new ArrayList(); + while(total < count) + { + int rand = Utility.Random(nspecials); + int nrtries = 0; + while(tmplist.Contains(rand)) + { + rand = Utility.Random(nspecials); + // add some sanity checking + if(nrtries++ > 100) break; + } + + tmplist.Add(rand); + + SpecialDefense s = GetSpecialDefense((SpecialDefenses)rand); + if(s != null) + { + Specials.Add(s); + total++; + } + + // add some sanity checking + if(tmplist.Count >= nspecials) break; + if(ntries++ > 100) break; + } + } + } + + private void ResetCombos() + { + foreach(ActiveCombo c in Combos) + { + c.PositionInSequence = 0; + } + } + + private bool HasActiveCombos + { + get{ + if(Combos == null) return false; + + foreach(ActiveCombo c in Combos) + { + if(c.PositionInSequence > 0) return true; + } + + return false; + } + } + + private void CheckCombos(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven, SpecialDefense s) + { + if(s == null) return; + + foreach(ActiveCombo c in Combos) + { + if(c != null && c.Combo != null && c.Combo.DefenseSequence != null && c.PositionInSequence < c.Combo.DefenseSequence.Length) + { + if(c.Combo.DefenseSequence[c.PositionInSequence] == s.DefenseID) + { + if(++c.PositionInSequence >= c.Combo.DefenseSequence.Length) + { + // combo is complete so execute it + DoComboDefense(attacker, defender, weapon, damageGiven, c.Combo); + + // and reset it + c.PositionInSequence = 0; + } + } else + { + // out of sequence so reset the combo + c.PositionInSequence = 0; + } + } + } + } + + public static bool CheckRequirements(Mobile from, SpecialDefense s) + { + if(from == null || s == null) return false; + + // test for str, dex, int requirements + if(from.Str < s.StrReq) + { + from.SendMessage("Need {0} Str to perform {1}", s.StrReq, s.Name); + return false; + } + if(from.Dex < s.DexReq) + { + from.SendMessage("Need {0} Dex to perform {1}", s.DexReq, s.Name); + return false; + } + if(from.Int < s.IntReq) + { + from.SendMessage("Need {0} Int to perform {1}", s.IntReq, s.Name); + return false; + } + + // test for skill requirements + if(s.Skills != null && s.MinSkillLevel != null) + { + if(from.Skills == null) return false; + + for(int i = 0; i < s.Skills.Length; i++) + { + // and check level + if(i < s.MinSkillLevel.Length) + { + Skill skill = from.Skills[s.Skills[i]]; + if(skill != null && s.MinSkillLevel[i] > skill.Base) + { + from.SendMessage("Need {0} {1} to perform {2}", s.MinSkillLevel[i], s.Skills[i].ToString(), s.Name); + return false; + } + } else + { + from.SendMessage(33,"Error in skill level specification for {0}", s.Name); + return false; + } + } + } + + + // test for mana, stam, and hits requirements + if(from.Mana < s.ManaReq) + { + from.SendMessage("Need {0} Mana to perform {1}", s.ManaReq, s.Name); + return false; + } + if(from.Stam < s.StamReq) + { + from.SendMessage("Need {0} Stamina to perform {1}", s.StamReq, s.Name); + return false; + } + if(from.Hits < s.HitsReq) + { + // clear the selected defense + from.SendMessage("Need {0} Hits to perform {1}", s.HitsReq, s.Name); + return false; + } + + + // check for any reagents that are specified + if(s.Reagents != null && s.Quantity != null) + { + if(from.Backpack == null) return false; + + for(int i = 0; i < s.Reagents.Length; i++) + { + // go through each reagent + Item ret = from.Backpack.FindItemByType(s.Reagents[i], true); + + // and check quantity + if(i < s.Quantity.Length) + { + if(ret == null || s.Quantity[i] > ret.Amount) + { + from.SendMessage("Need {1} {0} to perform {2}", s.Reagents[i].Name, s.Quantity[i], s.Name); + return false; + } + } else + { + from.SendMessage(33,"Error in quantity specification for {0}", s.Name); + return false; + } + } + } + return true; + } + + public override int OnArmorHit(Mobile attacker, Mobile defender, Item armor, BaseWeapon weapon, int damageGiven) + { + if(attacker == null || defender == null || weapon == null || armor == null || m_SelectedDefense == null) return 0; + + if(!CheckRequirements(defender, m_SelectedDefense)) return 0; + + // take the requirements + if(defender.Backpack != null && m_SelectedDefense.Reagents != null && m_SelectedDefense.Quantity != null) + { + defender.Backpack.ConsumeTotal( m_SelectedDefense.Reagents, m_SelectedDefense.Quantity, true); + } + + defender.Mana -= m_SelectedDefense.ManaReq; + defender.Stam -= m_SelectedDefense.StamReq; + defender.Hits -= m_SelectedDefense.HitsReq; + defender.Karma -= m_SelectedDefense.KarmaReq; + + // apply the attack + int damage = DoSpecialDefense( attacker, defender, weapon, damageGiven, m_SelectedDefense); + + if(m_SelectedDefense.KarmaReq > 0) + { + defender.SendMessage("and lose a little karma."); + } + + // after applying a special defense activate the specials timer for combo chaining + DoComboTimer(defender, m_SelectedDefense.ChainTime); + + // check all combos to see which have this defense as the next in sequence, and which might be complete + CheckCombos( attacker, defender, weapon, damageGiven, m_SelectedDefense); + + // clear the selected defense + m_SelectedDefense = null; + + // redisplay the gump + defender.SendGump(new CustomDefenseGump(defender, this)); + + return damage; + } + + public override void OnEquip( Mobile from ) + { + // open the specials gump + if(from == null || !from.Player) return; + + from.SendGump(new CustomDefenseGump(from, this)); + } + + public override void OnRemoved( object parent ) + { + // open the specials gump + if(parent != null && parent is Mobile && ((Mobile)parent).Player) + { + ((Mobile)parent).CloseGump(typeof( CustomDefenseGump )); + } + } + + public override string OnIdentify(Mobile from) + { + + string msg = "Special Defenses:"; + + foreach(SpecialDefense s in Specials) + { + msg += String.Format("\n{0}", s.Name); + } + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("{0}\nexpires in {0} mins ", msg, Expiration.TotalMinutes); + } + + return msg; + } + + public override void OnAttach() + { + base.OnAttach(); + + // only allow attachment to shields (for now) + if(!(AttachedTo is BaseShield)) + { + Delete(); + } + } + + public void DoComboTimer(Mobile from, TimeSpan delay) + { + if ( m_ComboTimer != null ) + m_ComboTimer.Stop(); + + m_ComboTimer = new ComboTimer(from, this, delay); + + m_ComboTimer.Start(); + } + + private class ComboTimer : Timer + { + private XmlCustomDefenses m_attachment; + private Mobile m_from; + + public ComboTimer( Mobile from, XmlCustomDefenses a, TimeSpan delay ) : base( delay ) + { + Priority = TimerPriority.OneSecond; + m_attachment = a; + m_from = from; + } + + protected override void OnTick() + { + if(m_attachment == null || m_attachment.Deleted) return; + + // the combo has expired + m_attachment.ResetCombos(); + + // refresh the gump + if(m_from != null) + { + m_from.SendGump(new CustomDefenseGump(m_from, m_attachment)); + } + } + } + + private class CustomDefenseInfoGump : Gump + { + private XmlCustomDefenses m_attachment; + private SpecialDefense m_special; + + public CustomDefenseInfoGump( Mobile from, XmlCustomDefenses a, SpecialDefense s) : base( 0,0) + { + + m_attachment = a; + m_special = s; + + // prepare the page + AddPage( 0 ); + + AddBackground( 0, 0, 400, 300, 5054 ); + AddAlphaRegion( 0, 0, 400, 300 ); + AddLabel( 20, 2, 55, String.Format("{0}",s.Name) ); + + StringBuilder text = new StringBuilder(); + + text.AppendFormat("\n{0}", s.Description ); + + + text.AppendFormat("\n\nMinimum Stats/Skills:" ); + if(s.StrReq > 0) + { + text.AppendFormat("\n {0} Str", s.StrReq ); + } + if(s.DexReq > 0) + { + text.AppendFormat("\n {0} Dex", s.DexReq ); + } + if(s.IntReq > 0) + { + text.AppendFormat("\n {0} Int", s.IntReq ); + } + + if(s.Skills != null) + for(int i = 0;i < s.Skills.Length;i++) + { + if(i < s.MinSkillLevel.Length) + { + text.AppendFormat("\n {1} {0}", s.Skills[i].ToString(), s.MinSkillLevel[i] ); + } else + { + text.AppendFormat("\n {1} {0}", s.Skills[i].ToString(), "???" ); + } + } + + text.AppendFormat("\n\nConsumes:" ); + + // generate the text requirements + if(s.ManaReq > 0) + { + text.AppendFormat("\n {0} Mana", s.ManaReq ); + } + if(s.StamReq > 0) + { + text.AppendFormat("\n {0} Stamina", s.StamReq ); + } + if(s.HitsReq > 0) + { + text.AppendFormat("\n {0} Hits", s.HitsReq ); + } + if(s.KarmaReq > 0) + { + text.AppendFormat("\n {0} Karma", s.KarmaReq ); + } + + if(s.Reagents != null) + for(int i = 0;i < s.Reagents.Length;i++) + { + if(i < s.Quantity.Length) + { + text.AppendFormat("\n {1} {0}", s.Reagents[i].Name, s.Quantity[i] ); + } else + { + text.AppendFormat("\n {1} {0}", s.Reagents[i].Name, "???" ); + } + } + + AddHtml( 20,20, 360, 260, text.ToString(), true , true ); + } + } + + private class CustomDefenseGump : Gump + { + private XmlCustomDefenses m_attachment; + private const int vertspacing = 47; + + public CustomDefenseGump( Mobile from, XmlCustomDefenses a) : base( 0,0) + { + if(a == null) + { + return; + } + if(from != null) + from.CloseGump(typeof( CustomDefenseGump)); + + m_attachment = a; + + int specialcount = a.Specials.Count; + + // prepare the page + AddPage( 0 ); + + AddBackground( 0, 0, 70, 75 + specialcount*vertspacing, 5054 ); + AddLabel( 13, 2, 55, "Defense" ); + // if combos are still active then give it the green light + if(m_attachment != null && m_attachment.HasActiveCombos) + { + // green button + //AddImage( 20, 10, 0x2a4e ); + AddImage( 15, 25, 0x0a53 ); + } else + { + // red button + //AddImage( 20, 10, 0x2a62 ); + AddImage( 15, 25, 0x0a52 ); + } + // go through the list of enabled moves and add buttons for them + int y = 70; + for(int i = 0;i TimeSpan.Zero) + { + return String.Format("{2}: Data {0} expires in {1} mins",Data,Expiration.TotalMinutes, Name); + } + else + { + return String.Format("{1}: Data {0}",Data, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlDate.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDate.cs new file mode 100644 index 0000000..9888397 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDate.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlDate : XmlAttachment + { + private DateTime m_DataValue; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime Date { get{ return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlDate(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlDate(string name) + { + Name = name; + Date = DateTime.Now; + } + + [Attachable] + public XmlDate(string name, double expiresin) + { + Name = name; + Date = DateTime.Now; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + [Attachable] + public XmlDate(string name, DateTime value, double expiresin) + { + Name = name; + Date = value; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadDateTime(); + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("{2}: Date {0} expires in {1} mins",Date,Expiration.TotalMinutes, Name); + } + else + { + return String.Format("{1}: Date {0}",Date, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlDeathAction.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDeathAction.cs new file mode 100644 index 0000000..08c96f3 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDeathAction.cs @@ -0,0 +1,180 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlDeathAction : XmlAttachment + { + private string m_Action; // action string + private string m_Condition; // condition string + + [CommandProperty(AccessLevel.GameMaster)] + public string Action { get { return m_Action; } set { m_Action = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string Condition { get { return m_Condition; } set { m_Condition = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlDeathAction(ASerial serial) + : base(serial) + { + } + + [Attachable] + public XmlDeathAction(string action) + { + Action = action; + } + + [Attachable] + public XmlDeathAction() + { + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); + // version 1 + writer.Write(m_Condition); + // version 0 + writer.Write(m_Action); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 1: + m_Condition = reader.ReadString(); + goto case 0; + case 0: + m_Action = reader.ReadString(); + break; + } + + } + + public override void OnAttach() + { + base.OnAttach(); + + if (AttachedTo is Item) + { + // dont allow item attachments + Delete(); + } + + } + + public override bool HandlesOnKilled { get { return true; } } + + public override void OnKilled(Mobile killed, Mobile killer) + { + base.OnKilled(killed, killer); + + if (killed == null) return; + + // now check for any conditions as well + // check for any condition that must be met for this entry to be processed + if (Condition != null) + { + string status_str; + + if (!BaseXmlSpawner.CheckPropertyString(null, killed, Condition, killer, out status_str)) + { + return; + } + } + + ExecuteDeathActions(killed.Corpse, killer, Action); + } + + private void ExecuteDeathActions(Item corpse, Mobile killer, string actions) + { + if (actions == null || actions.Length <= 0) return; + // execute any action associated with it + // allow for multiple action strings on a single line separated by a semicolon + + string[] args = actions.Split(';'); + + for (int j = 0; j < args.Length; j++) + { + ExecuteDeathAction(corpse, killer, args[j]); + } + + } + + private static void ExecuteDeathAction(Item corpse, Mobile killer, string action) + { + if (action == null || action.Length <= 0 || corpse == null) return; + + string status_str = null; + Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0); + + TheSpawn.TypeName = action; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, corpse, killer, action); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + Point3D loc = corpse.Location; + Map map = corpse.Map; + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + BaseXmlSpawner.SpawnTypeKeyword(corpse, TheSpawn, typeName, substitutedtypeName, true, killer, loc, map, out status_str); + } + else + { + // its a regular type descriptor so find out what it is + Type type = SpawnerType.GetType(typeName); + try + { + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]); + + if (o == null) + { + status_str = "invalid type specification: " + arglist[0]; + } + else + if (o is Mobile) + { + Mobile m = (Mobile)o; + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + c.Home = loc; // Spawners location is the home point + } + + m.Location = loc; + m.Map = map; + + BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, killer, corpse, out status_str); + } + else + if (o is Item) + { + Item item = (Item)o; + BaseXmlSpawner.AddSpawnItem(null, corpse, TheSpawn, item, loc, map, killer, false, substitutedtypeName, out status_str); + } + } + catch { } + } + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlDex.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDex.cs new file mode 100644 index 0000000..11fd5fe --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDex.cs @@ -0,0 +1,59 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlDex : XmlAttachment + { + private TimeSpan m_Duration = TimeSpan.FromSeconds(30.0); // default 30 sec duration + private int m_Value = 10; // default value of 10 + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get { return m_Value; } set { m_Value = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlDex(ASerial serial) : base(serial) + { + } + + + [Attachable] + public XmlDex() + { + } + + [Attachable] + public XmlDex(int value) + { + m_Value = value; + } + + [Attachable] + public XmlDex(int value, double duration) + { + m_Value = value; + m_Duration = TimeSpan.FromSeconds(duration); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).AddStatMod( new StatMod( StatType.Dex, "XmlDex"+Name, m_Value, m_Duration ) ); + } + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlDialog.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDialog.cs new file mode 100644 index 0000000..a343f5a --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlDialog.cs @@ -0,0 +1,2228 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using System.Diagnostics; +using System.Text.RegularExpressions; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlDialog : XmlAttachment + { + + + // speech entry + public class SpeechEntry + { + public int EntryNumber; + private int m_ID; + public string Text; // text displayed when the entry is activated + public string Keywords; // comma separated list of keywords that can be matched to activate the entry. If no keywords are present then it is automatically activated + public string Action; // action string + public string Condition; // condition test string + public string DependsOn; // the previous entrynumber required to activate this entry + public int Pause = 1; // pause in seconds before advancing to the next entry + public int PrePause = -1; // pause in seconds before saying the speech for this entry. -1 indicates the use of auto pause calculation based on triggering speech length. + public bool LockConversation = true; // flag to determine if the conversation locks to one player + public bool AllowNPCTrigger = false; // flag to determine if npc speech can trigger it + public MessageType SpeechStyle = MessageType.Regular; + public string Gump; // GUMP specification string + public int m_SpeechHue = -1; // speech hue + public bool IgnoreCarried = false; // ignore the TriggerOnCarried/NoTriggerOnCarried settings for the dialog when activating this entry + + public int SpeechHue + { + get { return m_SpeechHue; } + set + { + // dont allow invalid hues + m_SpeechHue = value; + if (m_SpeechHue > 37852) m_SpeechHue = 37852; + } + } + + public int ID + { + get { return m_ID; } + set + { + // dont allow ID modification of entry 0 + if (EntryNumber == 0) return; + m_ID = value; + } + } + } + + public static int defProximityRange = 3; + public static int defResetRange = 16; + public static TimeSpan defResetTime = TimeSpan.FromSeconds(60); + public static int defSpeechPace = 10; + + private const string NPCDataSetName = "XmlQuestNPC"; + private const string NPCPointName = "NPC"; + private const string SpeechPointName = "SpeechEntry"; + public static string DefsDir = "XmlQuestNPC"; + + private ArrayList m_SpeechEntries = new ArrayList(); // contains the list of speech entries + private int m_CurrentEntryNumber = -1; // used to determine which entry will be subject to modification by various entry editing calls + private SpeechEntry m_CurrentEntry; + private bool m_Running = true; + private int m_ProximityRange = defProximityRange; + private bool m_AllowGhostTriggering = false; + private AccessLevel m_TriggerAccessLevel = AccessLevel.Player; + private DateTime m_LastInteraction; + private TimeSpan m_ResetTime = defResetTime; + private int m_ResetRange = defResetRange; + private bool m_IsActive = false; + private InternalTimer m_Timer; + private string m_ConfigFile; + private Mobile m_ActivePlayer; // keep track of the player that is currently engaged in conversation so that other players speech can be ignored. + private int m_SpeechPace = defSpeechPace; // used for automatic prepause delay calculation. delayinsecs = speechlength/speechpace + 1 + bool m_HoldProcessing; + private string m_ItemTriggerName; + private string m_NoItemTriggerName; + public ArrayList m_TextEntryBook; + private string m_ResponseString; + + public string ResponseString + { + get { return m_ResponseString; } + set { m_ResponseString = value; } + } + + public ArrayList SpeechEntries + { + get + { + return m_SpeechEntries; + } + set + { + m_SpeechEntries = value; + } + } + + public Mobile ActivePlayer + { + get { return m_ActivePlayer; } + set { m_ActivePlayer = value; } + } + + + + // a serial constructor is REQUIRED + public XmlDialog(ASerial serial) + : base(serial) + { + } + + [Attachable] + public XmlDialog(string ConfigFile) + { + DoLoadNPC(null, ConfigFile); + } + + [Attachable] + public XmlDialog() + { + EntryNumber = 0; + } + + public void DeleteTextEntryBook() + { + if (m_TextEntryBook != null) + { + foreach (Item s in m_TextEntryBook) + s.Delete(); + + m_TextEntryBook = null; + } + } + + private SpeechEntry GetEntry(int entryid) + { + if (entryid < 0) return null; + if (m_SpeechEntries == null) + { + m_SpeechEntries = new ArrayList(); + } + // find the speech entry that matches the current entry number + foreach (SpeechEntry s in m_SpeechEntries) + { + if (s.EntryNumber == entryid) + return s; + } + // didnt find it so make a new entry + SpeechEntry newentry = new SpeechEntry(); + newentry.EntryNumber = entryid; + newentry.ID = entryid; + m_SpeechEntries.Add(newentry); + return newentry; + } + + private bool ValidMovementTrig(Mobile m) + { + if (m == null || m.Deleted) return false; + + return ( + ((m is PlayerMobile && (m.AccessLevel <= TriggerAccessLevel))) && + ((!m.Body.IsGhost && !m_AllowGhostTriggering) || (m.Body.IsGhost && m_AllowGhostTriggering))); + } + + private bool ValidSpeechTrig(Mobile m) + { + if (m == null || m.Deleted) return false; + + bool allownpctrigger = false; + if (CurrentEntry != null) + { + allownpctrigger = CurrentEntry.AllowNPCTrigger; + } + + return ( + ((m is PlayerMobile && (m.AccessLevel <= TriggerAccessLevel)) || (allownpctrigger && !(m is PlayerMobile))) && + ((!m.Body.IsGhost && !m_AllowGhostTriggering) || (m.Body.IsGhost && m_AllowGhostTriggering))); + } + + + [CommandProperty(AccessLevel.GameMaster)] + public AccessLevel TriggerAccessLevel + { + get + { + return m_TriggerAccessLevel; + } + set + { + m_TriggerAccessLevel = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastInteraction + { + get + { + return m_LastInteraction; + } + set + { + m_LastInteraction = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DoReset + { + get { return false; } + set + { + if (value) Reset(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsActive + { + get + { + return m_IsActive; + } + set + { + m_IsActive = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan GameTOD + { + get + { + int hours; + int minutes; + Map map = null; + int x = 0; + int y = 0; + if (AttachedTo is Item) + { + map = ((Item)AttachedTo).Map; + x = ((Item)AttachedTo).Location.X; + y = ((Item)AttachedTo).Location.Y; + + } + else + if (AttachedTo is Mobile) + { + map = ((Mobile)AttachedTo).Map; + x = ((Mobile)AttachedTo).Location.X; + y = ((Mobile)AttachedTo).Location.Y; + } + + Server.Items.Clock.GetTime(map, x, y, out hours, out minutes); + return (new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, hours, minutes, 0).TimeOfDay); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RealTOD + { + get + { + return DateTime.Now.TimeOfDay; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RealDay + { + get + { + return DateTime.Now.Day; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RealMonth + { + get + { + return DateTime.Now.Month; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DayOfWeek RealDayOfWeek + { + get + { + return DateTime.Now.DayOfWeek; + } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public MoonPhase MoonPhase + { + get + { + Map map = null; + int x = 0; + int y = 0; + if (AttachedTo is Item) + { + map = ((Item)AttachedTo).Map; + x = ((Item)AttachedTo).Location.X; + y = ((Item)AttachedTo).Location.Y; + + } + else + if (AttachedTo is Mobile) + { + map = ((Mobile)AttachedTo).Map; + x = ((Mobile)AttachedTo).Location.X; + y = ((Mobile)AttachedTo).Location.Y; + } + return Clock.GetMoonPhase(map, x, y); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowGhostTrig + { + get { return m_AllowGhostTriggering; } + set + { + m_AllowGhostTriggering = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Running + { + get { return m_Running; } + set { m_Running = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan ResetTime + { + get { return m_ResetTime; } + set { m_ResetTime = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SpeechPace + { + get { return m_SpeechPace; } + set { m_SpeechPace = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Keywords + { + get + { + // return the keyword string for the current entry + if (m_CurrentEntry == null) + { + return null; + } + return m_CurrentEntry.Keywords; + } + set + { + // set the keyword string for the current entry + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.Keywords = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Action + { + get + { + if (m_CurrentEntry == null) + { + return null; + } + return m_CurrentEntry.Action; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.Action = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Gump + { + get + { + if (m_CurrentEntry == null) + { + return null; + } + return m_CurrentEntry.Gump; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.Gump = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SpeechHue + { + get + { + if (m_CurrentEntry == null) + { + return 0; + } + return m_CurrentEntry.SpeechHue; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.SpeechHue = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Condition + { + get + { + if (m_CurrentEntry == null) + { + return null; + } + return m_CurrentEntry.Condition; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.Condition = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Text + { + get + { + if (m_CurrentEntry == null) + { + return null; + } + return m_CurrentEntry.Text; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.Text = value; + } + } + + + + [CommandProperty(AccessLevel.GameMaster)] + public string DependsOn + { + get + { + // return the keyword string for the current entry + if (m_CurrentEntry == null) + { + return "-1"; + } + return m_CurrentEntry.DependsOn; + } + set + { + // set the keyword string for the current entry + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.DependsOn = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool LockConversation + { + get + { + if (m_CurrentEntry == null) + { + return true; + } + return m_CurrentEntry.LockConversation; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.LockConversation = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IgnoreCarried + { + get + { + if (m_CurrentEntry == null) + { + return true; + } + return m_CurrentEntry.IgnoreCarried; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.IgnoreCarried = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public MessageType SpeechStyle + { + get + { + if (m_CurrentEntry == null) + { + return MessageType.Regular; + } + return m_CurrentEntry.SpeechStyle; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.SpeechStyle = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowNPCTrigger + { + get + { + if (m_CurrentEntry == null) + { + return false; + } + return m_CurrentEntry.AllowNPCTrigger; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.AllowNPCTrigger = value; + } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public int Pause + { + get + { + if (m_CurrentEntry == null) + { + return -1; + } + return m_CurrentEntry.Pause; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.Pause = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PrePause + { + get + { + if (m_CurrentEntry == null) + { + return -1; + } + return m_CurrentEntry.PrePause; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + m_CurrentEntry.PrePause = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ID + { + get + { + if (m_CurrentEntry == null) + { + return -1; + } + return m_CurrentEntry.ID; + } + set + { + if (m_CurrentEntry == null) + { + return; + } + + + m_CurrentEntry.ID = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int EntryNumber + { + get { return m_CurrentEntryNumber; } + set + { + m_CurrentEntryNumber = value; + // get the entry corresponding to the number + m_CurrentEntry = GetEntry(m_CurrentEntryNumber); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ProximityRange + { + get { return m_ProximityRange; } + set + { + m_ProximityRange = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ResetRange + { + get { return m_ResetRange; } + set + { + m_ResetRange = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string ConfigFile + { + get { return m_ConfigFile; } + set + { + m_ConfigFile = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool LoadConfig + { + get { return false; } + set { if (value == true) DoLoadNPC(null, ConfigFile); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string TriggerOnCarried + { + get { return m_ItemTriggerName; } + set + { + m_ItemTriggerName = value; + } + + } + [CommandProperty(AccessLevel.GameMaster)] + public string NoTriggerOnCarried + { + get { return m_NoItemTriggerName; } + set + { + m_NoItemTriggerName = value; + } + + } + + public SpeechEntry CurrentEntry + { + get { return m_CurrentEntry; } + set + { + + // get the entry corresponding to the number + m_CurrentEntry = value; + if (m_CurrentEntry != null) + m_CurrentEntryNumber = m_CurrentEntry.EntryNumber; + else + m_CurrentEntryNumber = -1; + } + } + + // see if the DependsOn property contains the specified id + public bool CheckDependsOn(SpeechEntry s, int id) + { + if (s == null || s.DependsOn == null) return false; + + // parse the DependsOn string + string[] args = s.DependsOn.Split(','); + for (int i = 0; i < args.Length; i++) + { + try + { + if (int.Parse(args[i].Trim()) == id) return true; + } + catch { } + } + return false; + } + + private SpeechEntry FindMatchingKeyword(Mobile from, string keyword, int currententryid) + { + if (m_SpeechEntries == null) return null; + ArrayList matchlist = new ArrayList(); + + // go through all of the speech entries and find those that depend on the current entry + foreach (SpeechEntry s in m_SpeechEntries) + { + // ignore self-referencing entries + if (CheckDependsOn(s, s.ID)) continue; + + // start processing if set for spontaneous activation (banter), already active, or waiting in the default state + if (((CheckDependsOn(s, -1) || CheckDependsOn(s, -2)) && !IsActive) || (CheckDependsOn(s, currententryid) && (IsActive || currententryid == 0))) + { + // now check for any conditions as well + // check for any condition that must be met for this entry to be processed + if (s.Condition != null) + { + string status_str; + + if (!BaseXmlSpawner.CheckPropertyString(null, this, s.Condition, from, out status_str)) + { + continue; + } + } + + // testing for keyword = null will handle calls from the OnTick + if ((keyword == null && s.Keywords == null)) + { + // add it to the list of match candidates + matchlist.Add(s); + } + else + // parse the keyword string + if (keyword != null && s.Keywords != null) + { + + string[] arglist = s.Keywords.Split(",".ToCharArray()); + for (int i = 0; i < arglist.Length; i++) + { + if (arglist[i] == "*") + { + // special match anything expression (regex doesnt parse this well) + matchlist.Add(s); + break; + } + else + { + bool error = false; + Regex r = null; + string status_str = null; + try + { + r = new Regex(arglist[i], RegexOptions.IgnoreCase); + } + catch (Exception e) { error = true; status_str = e.Message; } + + if (!error && r != null) + { + + Match m = r.Match(keyword); + if (m.Success) + { + // add it to the list of match candidates + matchlist.Add(s); + break; + } + } + else + { + ReportError(from, String.Format("Bad regular expression: {0} ", status_str)); + } + } + } + } + } + } + if (matchlist.Count > 0) + { + // found at least one match + // if there is more than one, then randomly pick one + int select = Utility.Random(matchlist.Count); + + return (SpeechEntry)matchlist[select]; + } + else + { + // didnt find a match + return null; + } + } + + public static void DialogGumpCallback(Mobile from, object invoker, string response) + { + // insert the response into the triggering speech of the invoking attachment + if (invoker is XmlDialog) + { + XmlDialog xd = (XmlDialog)invoker; + xd.m_HoldProcessing = false; + + xd.ProcessSpeech(from, response); + } + } + + private void ExecuteGump(Mobile mob, string gumpstring) + { + if (gumpstring == null || gumpstring.Length <= 0) return; + + string status_str = null; + + Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0); + + TheSpawn.TypeName = gumpstring; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, this, mob, gumpstring); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + Point3D loc = new Point3D(0, 0, 0); + Map map = null; + + if (AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + loc = m.Location; + map = m.Map; + } + else + if (AttachedTo is Item && ((Item)AttachedTo).Parent == null) + { + Item i = AttachedTo as Item; + loc = i.Location; + map = i.Map; + } + + if (typeName == "GUMP") + { + BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, true, mob, loc, map, new XmlGumpCallback(DialogGumpCallback), out status_str); + // hold processing until the gump response is completed + + m_HoldProcessing = true; + } + else + { + status_str = "not a GUMP specification"; + } + + ReportError(mob, status_str); + } + + private void ExecuteAction(Mobile mob, string action) + { + if (action == null || action.Length <= 0) return; + string status_str = null; + Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0); + + TheSpawn.TypeName = action; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, this, mob, action); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + Point3D loc = new Point3D(0, 0, 0); + Map map = null; + + if (AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + loc = m.Location; + map = m.Map; + } + else + if (AttachedTo is Item && ((Item)AttachedTo).Parent == null) + { + Item i = AttachedTo as Item; + loc = i.Location; + map = i.Map; + } + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + BaseXmlSpawner.SpawnTypeKeyword(AttachedTo, TheSpawn, typeName, substitutedtypeName, true, mob, loc, map, out status_str); + } + else + { + // its a regular type descriptor so find out what it is + Type type = SpawnerType.GetType(typeName); + try + { + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]); + + if (o == null) + { + status_str = "invalid type specification: " + arglist[0]; + } + else + if (o is Mobile) + { + Mobile m = (Mobile)o; + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + c.Home = loc; // Spawners location is the home point + } + + m.Location = loc; + m.Map = map; + + BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, mob, AttachedTo, out status_str); + } + else + if (o is Item) + { + Item item = (Item)o; + BaseXmlSpawner.AddSpawnItem(null, AttachedTo, TheSpawn, item, loc, map, mob, false, substitutedtypeName, out status_str); + } + } + catch { } + } + + ReportError(mob, status_str); + } + + private void ReportError(Mobile mob, string status_str) + { + if (status_str != null && mob != null && !mob.Deleted && mob is PlayerMobile && mob.AccessLevel > AccessLevel.Player) + { + mob.SendMessage(33, String.Format("{0}:{1}", AttachedTo.GetType().Name, status_str)); + } + } + + public override bool HandlesOnSpeech + { + get { return (m_Running); } + } + + + public override void OnSpeech(SpeechEventArgs e) + { + + if (e.Mobile == null) return; + + // dont handle your own speech + if (e.Mobile == AttachedTo as Mobile || e.Mobile.AccessLevel > TriggerAccessLevel) + { + e.Handled = false; + return; + } + + if (m_HoldProcessing) return; + + bool lockconversation = true; + bool ishandled = false; + + Point3D loc = new Point3D(0, 0, 0); + Map map; + + if (AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + loc = m.Location; + map = m.Map; + } + else + if (AttachedTo is Item && ((Item)AttachedTo).Parent == null) + { + Item i = AttachedTo as Item; + loc = i.Location; + map = i.Map; + } + + if (CurrentEntry != null) + { + lockconversation = CurrentEntry.LockConversation; + } + + if (!e.Handled && m_Running && m_ProximityRange >= 0 && ValidSpeechTrig(e.Mobile) && ((e.Mobile == m_ActivePlayer) || !lockconversation || m_ActivePlayer == null)) + { + + if (!Utility.InRange(e.Mobile.Location, loc, m_ProximityRange)) + return; + + CheckForReset(); + + // process the current speech entry + ishandled = ProcessSpeech(e.Mobile, e.Speech); + + // check to make sure the timer is running + DoTimer(TimeSpan.FromSeconds(1), m_ActivePlayer); + + } + + if (!ishandled) + { + base.OnSpeech(e); + } + } + + public override bool HandlesOnMovement { get { return (m_Running); } } + + public override void OnMovement(MovementEventArgs e) + { + Mobile m = e.Mobile; + + if (m == null || m.AccessLevel > TriggerAccessLevel) return; + + Point3D loc = new Point3D(0, 0, 0); + Map map; + + if (AttachedTo is Mobile) + { + Mobile mob = AttachedTo as Mobile; + loc = mob.Location; + map = mob.Map; + } + else + if (AttachedTo is Item && ((Item)AttachedTo).Parent == null) + { + Item i = AttachedTo as Item; + loc = i.Location; + map = i.Map; + } + + // if proximity sensing is off, a speech entry has been activated, or player is an admin then ignore + if (m_Running && m_ProximityRange >= 0 && ValidMovementTrig(m) && !IsActive && !m_HoldProcessing) + { + // check to see if player is within range of the npc + if (Utility.InRange(m.Location, loc, m_ProximityRange)) + { + + TimeSpan pause = TimeSpan.FromSeconds(0); + if (CurrentEntry != null && CurrentEntry.Pause > 0) + { + pause = TimeSpan.FromSeconds(CurrentEntry.Pause); + } + // check to see if the current pause interval has elapsed + if (DateTime.Now - pause > m_LastInteraction) + { + // process speech that is not keyword dependent + CheckForReset(); + + ProcessSpeech(m, null); + } + // turn on the timer that will run until the speech list is reset + // it will control paused speech and will allow the speech entry to be reset after ResetTime timeout + DoTimer(TimeSpan.FromSeconds(1), m); + } + } + else + { + CheckForReset(); + } + base.OnMovement(e); + } + + private bool IsInRange(IEntity e1, IEntity e2, int range) + { + if (e1 == null || e2 == null) return false; + + if (e1.Map != e2.Map) return false; + + return Utility.InRange(e1.Location, e2.Location, range); + } + + + private void CheckForReset() + { + // check to see if the interaction time has elapsed or player has gone out of range. If so then reset to entry zero + if (!m_HoldProcessing && + ((DateTime.Now - ResetTime > m_LastInteraction) || + (AttachedTo is IEntity && m_ActivePlayer != null && !IsInRange(m_ActivePlayer, (IEntity)AttachedTo, ResetRange)))) + { + Reset(); + } + + } + + private void Reset() + { + EntryNumber = 0; + IsActive = false; + m_ActivePlayer = null; + // turn off the timer + if (m_Timer != null) + m_Timer.Stop(); + } + + private void DelayedSpeech(object state) + { + object[] states = (object[])state; + + SpeechEntry matchentry = (SpeechEntry)states[0]; + Mobile m = (Mobile)states[1]; + + if (matchentry != null) + { + CurrentEntry = matchentry; + + string text = BaseXmlSpawner.ApplySubstitution(null, this, m, CurrentEntry.Text); + + if (text != null) + { + // dont know why emote doesnt work, but we'll just do it manually + if (CurrentEntry.SpeechStyle == MessageType.Emote) + { + text = String.Format("*{0}*", text); + } + + // items cannot produce actual speech + // display a message over the item it was attached to + if (AttachedTo is Item) + { + int speechhue = 0x3B2; + if (CurrentEntry.SpeechHue >= 0) + { + speechhue = CurrentEntry.SpeechHue; + } + ((Item)AttachedTo).PublicOverheadMessage(MessageType.Regular, speechhue, true, text); + } + else + if (AttachedTo is Mobile) + { + // mobiles can produce actual speech + // so let them. This allows mobiles to talk with one another + int speechhue = ((Mobile)AttachedTo).SpeechHue; + if (CurrentEntry.SpeechHue >= 0) + { + speechhue = CurrentEntry.SpeechHue; + } + + ((Mobile)AttachedTo).DoSpeech(text, new int[] { }, CurrentEntry.SpeechStyle, speechhue); + //((Mobile)AttachedTo).PublicOverheadMessage( MessageType.Regular, 0x3B2, true, text ); + } + } + + IsActive = true; + m_LastInteraction = DateTime.Now; + + // execute any action associated with it + // allow for multiple action strings on a single line separated by a semicolon + if (CurrentEntry.Action != null && CurrentEntry.Action.Length > 0) + { + string[] args = CurrentEntry.Action.Split(';'); + + for (int j = 0; j < args.Length; j++) + { + ExecuteAction(m, args[j]); + } + } + + // execute any GUMP associated with it + ExecuteGump(m, CurrentEntry.Gump); + + + + } + + m_HoldProcessing = false; + } + + public bool ProcessSpeech(Mobile m, string speech) + { + + if (m_HoldProcessing) return true; + + // check the speech against the entries that depend on the present entry + SpeechEntry matchentry = FindMatchingKeyword(m, speech, ID); + + if (matchentry == null) return false; + + // when attempting to process speech-triggered speech, check for oncarried dependencies + // This will not apply to movement-triggered speech (banter with -1 dependson) which will continue to be activated + // regardless of oncarried status + // dependson of -2 will allow non-speech triggering but will still apply oncarried dependencies + + // if player-carried item triggering is set then test for the presence of an item on the player an in their pack + if ((speech != null || CheckDependsOn(matchentry, -2)) && TriggerOnCarried != null && TriggerOnCarried.Length > 0) + { + bool found = BaseXmlSpawner.CheckForCarried(m, TriggerOnCarried) || matchentry.IgnoreCarried; + + // is the player carrying the right item, if not then dont process + if (!found) return false; + } + + // if player-carried noitem triggering is set then test for the presence of an item in the players pack that should block triggering + if ((speech != null || CheckDependsOn(matchentry, -2)) && NoTriggerOnCarried != null && NoTriggerOnCarried.Length > 0) + { + bool notfound = BaseXmlSpawner.CheckForNotCarried(m, NoTriggerOnCarried) || matchentry.IgnoreCarried; + + // is the player carrying the right item, if so then dont process + if (!notfound) return false; + } + + ResponseString = speech; + + // the player that successfully activates a conversation by speech becomes the exclusive conversationalist until the npc resets + if (speech != null && m != null) + m_ActivePlayer = m; + + // calculate the delay before activating the entry + int prepause = 1; // 1 sec by default + if (matchentry.PrePause < 0) + { + if (SpeechPace > 0 && speech != null) + { + // do the auto delay calculation based on the length of the triggering speech + prepause = (speech.Length / SpeechPace) + 1; // make 1 sec the min pause + + } + } + else + { + prepause = matchentry.PrePause; + } + + // and switch to the one that matches + + m_HoldProcessing = true; + Timer.DelayCall(TimeSpan.FromSeconds(prepause), new TimerStateCallback(DelayedSpeech), new object[] { matchentry, m }); + + return true; + } + + public void DoTimer(TimeSpan delay, Mobile trigmob) + { + if (!m_Running) + return; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = new InternalTimer(this, delay, trigmob); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + private XmlDialog m_npc; + public Mobile m_trigmob; + public TimeSpan m_delay; + + public InternalTimer(XmlDialog npc, TimeSpan delay, Mobile trigmob) + : base(delay, delay) + { + + Priority = TimerPriority.OneSecond; + + m_npc = npc; + m_trigmob = trigmob; + m_delay = delay; + } + + protected override void OnTick() + { + + if (m_npc != null && !m_npc.Deleted) + { + // check to see if any speech needs to be processed + TimeSpan pause = TimeSpan.FromSeconds(0); + if (m_npc.CurrentEntry != null && m_npc.CurrentEntry.Pause > 0) + { + pause = TimeSpan.FromSeconds(m_npc.CurrentEntry.Pause); + } + // check to see if the current pause interval has elapsed + if (DateTime.Now - pause > m_npc.LastInteraction) + { + // process speech that is not keyword dependent + + m_npc.ProcessSpeech(m_trigmob, null); + m_npc.CheckForReset(); + } + } + else + { + Stop(); + } + } + } + + public void DoLoadNPC(Mobile from, string filename) + { + if (filename == null || filename.Length <= 0) return; + + string dirname; + if (System.IO.Directory.Exists(DefsDir) == true) + { + // look for it in the defaults directory + dirname = String.Format("{0}/{1}.npc", DefsDir, filename); + + // Check if the file exists + if (System.IO.File.Exists(dirname) == false) + { + // didnt find it so just look in the main install dir + dirname = String.Format("{0}.npc", filename); + } + } + else + { + // look in the main installation dir + dirname = String.Format("{0}.npc", filename); + } + + // Check if the file exists + if (System.IO.File.Exists(dirname) == true) + { + FileStream fs = null; + try + { + fs = File.Open(dirname, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + from.SendMessage("Unable to open {0} for loading", dirname); + return; + } + + // Create the data set + DataSet ds = new DataSet(NPCDataSetName); + + // Read in the file + bool fileerror = false; + + try + { + ds.ReadXml(fs); + } + catch { fileerror = true; } + + // close the file + fs.Close(); + + if (fileerror) + { + if (from != null && !from.Deleted) + from.SendMessage(33, "Error reading npc file {0}", dirname); + return; + } + + // Check that at least a single table was loaded + if (ds.Tables != null && ds.Tables.Count > 0) + { + // get the npc info + if (ds.Tables[NPCPointName] != null && ds.Tables[NPCPointName].Rows.Count > 0) + { + DataRow dr = ds.Tables[NPCPointName].Rows[0]; + + try + { + if (AttachedTo is Item) + { + ((Item)AttachedTo).Name = (string)dr["Name"]; + } + else + if (AttachedTo is Mobile) + { + ((Mobile)AttachedTo).Name = (string)dr["Name"]; + } + + } + catch { } + try { this.ProximityRange = int.Parse((string)dr["ProximityRange"]); } + catch { } + try { this.ResetRange = int.Parse((string)dr["ResetRange"]); } + catch { } + try { this.TriggerOnCarried = (string)dr["TriggerOnCarried"]; } + catch { } + try { this.NoTriggerOnCarried = (string)dr["NoTriggerOnCarried"]; } + catch { } + try { this.m_AllowGhostTriggering = bool.Parse((string)dr["AllowGhost"]); } + catch { } + try { this.m_SpeechPace = int.Parse((string)dr["SpeechPace"]); } + catch { } + try { this.Running = bool.Parse((string)dr["Running"]); } + catch { } + try { this.ResetTime = TimeSpan.FromMinutes(double.Parse((string)dr["ResetTime"])); } + catch { } + try { this.ConfigFile = (string)dr["ConfigFile"]; } + catch { } + + int entrycount = 0; + try { entrycount = int.Parse((string)dr["SpeechEntries"]); } + catch { } + } + + // get the speech entry info + if (ds.Tables[NPCPointName] != null && ds.Tables[NPCPointName].Rows.Count > 0) + { + m_SpeechEntries = new ArrayList(); + foreach (DataRow dr in ds.Tables[SpeechPointName].Rows) + { + SpeechEntry s = new SpeechEntry(); + // Populate the speech entry data + try { s.EntryNumber = int.Parse((string)dr["EntryNumber"]); } + catch { } + try { s.ID = int.Parse((string)dr["ID"]); } + catch { } + try { s.Text = (string)dr["Text"]; } + catch { } + try { s.Keywords = (string)dr["Keywords"]; } + catch { } + try { s.Action = (string)dr["Action"]; } + catch { } + try { s.Condition = (string)dr["Condition"]; } + catch { } + try { s.DependsOn = (string)dr["DependsOn"]; } + catch { } + try { s.Pause = int.Parse((string)dr["Pause"]); } + catch { } + try { s.PrePause = int.Parse((string)dr["PrePause"]); } + catch { } + try { s.LockConversation = bool.Parse((string)dr["LockConversation"]); } + catch { } + try { s.IgnoreCarried = bool.Parse((string)dr["IgnoreCarried"]); } + catch { } + try { s.AllowNPCTrigger = bool.Parse((string)dr["AllowNPCTrigger"]); } + catch { } + try { s.SpeechStyle = (MessageType)Enum.Parse(typeof(MessageType), (string)dr["SpeechStyle"]); } + catch { } + try { s.SpeechHue = int.Parse((string)dr["SpeechHue"]); } + catch { } + try { s.Gump = (string)dr["Gump"]; } + catch { } + + m_SpeechEntries.Add(s); + } + } + + Reset(); + + if (from != null && !from.Deleted) + from.SendMessage("Loaded npc from file {0}", dirname); + } + else + { + if (from != null && !from.Deleted) + from.SendMessage(33, "No npc data found in: {0}", dirname); + } + } + else + { + if (from != null && !from.Deleted) + from.SendMessage(33, "File not found: {0}", dirname); + } + } + + public void DoSaveNPC(Mobile from, string filename, bool updateconfig) + { + if (filename == null || filename.Length <= 0) return; + + // Create the data set + DataSet ds = new DataSet(NPCDataSetName); + + // Load the data set up + ds.Tables.Add(NPCPointName); + ds.Tables.Add(SpeechPointName); + + // Create a schema for the npc + ds.Tables[NPCPointName].Columns.Add("Name"); + ds.Tables[NPCPointName].Columns.Add("Running"); + ds.Tables[NPCPointName].Columns.Add("ProximityRange"); + ds.Tables[NPCPointName].Columns.Add("ResetRange"); + ds.Tables[NPCPointName].Columns.Add("TriggerOnCarried"); + ds.Tables[NPCPointName].Columns.Add("NoTriggerOnCarried"); + ds.Tables[NPCPointName].Columns.Add("AllowGhost"); + ds.Tables[NPCPointName].Columns.Add("SpeechPace"); + ds.Tables[NPCPointName].Columns.Add("ResetTime"); + ds.Tables[NPCPointName].Columns.Add("ConfigFile"); + ds.Tables[NPCPointName].Columns.Add("SpeechEntries"); + + // Create a schema for the speech entries + ds.Tables[SpeechPointName].Columns.Add("EntryNumber"); + ds.Tables[SpeechPointName].Columns.Add("ID"); + ds.Tables[SpeechPointName].Columns.Add("Text"); + ds.Tables[SpeechPointName].Columns.Add("Keywords"); + ds.Tables[SpeechPointName].Columns.Add("Action"); + ds.Tables[SpeechPointName].Columns.Add("Condition"); + ds.Tables[SpeechPointName].Columns.Add("DependsOn"); + ds.Tables[SpeechPointName].Columns.Add("Pause"); + ds.Tables[SpeechPointName].Columns.Add("PrePause"); + ds.Tables[SpeechPointName].Columns.Add("LockConversation"); + ds.Tables[SpeechPointName].Columns.Add("IgnoreCarried"); + ds.Tables[SpeechPointName].Columns.Add("AllowNPCTrigger"); + ds.Tables[SpeechPointName].Columns.Add("SpeechStyle"); + ds.Tables[SpeechPointName].Columns.Add("SpeechHue"); + ds.Tables[SpeechPointName].Columns.Add("Gump"); + + // Create a new data row + DataRow dr = ds.Tables[NPCPointName].NewRow(); + + // Populate the npc data + if (AttachedTo is Item) + { + dr["Name"] = (string)((Item)AttachedTo).Name; + } + else + if (AttachedTo is Mobile) + { + dr["Name"] = (string)((Mobile)AttachedTo).Name; + } + + dr["Running"] = (bool)this.Running; + dr["ProximityRange"] = (int)this.m_ProximityRange; + dr["ResetRange"] = (int)this.m_ResetRange; + dr["TriggerOnCarried"] = (string)this.TriggerOnCarried; + dr["NoTriggerOnCarried"] = (string)this.NoTriggerOnCarried; + dr["AllowGhost"] = (bool)this.m_AllowGhostTriggering; + dr["SpeechPace"] = (int)this.SpeechPace; + dr["ResetTime"] = (double)this.ResetTime.TotalMinutes; + dr["ConfigFile"] = (string)this.ConfigFile; + int entrycount = 0; + if (SpeechEntries != null) + { + entrycount = SpeechEntries.Count; + } + dr["SpeechEntries"] = (int)entrycount; + + // Add the row the the table + ds.Tables[NPCPointName].Rows.Add(dr); + + for (int i = 0; i < entrycount; i++) + { + SpeechEntry s = (SpeechEntry)SpeechEntries[i]; + + // Create a new data row + dr = ds.Tables[SpeechPointName].NewRow(); + + // Populate the speech entry data + dr["EntryNumber"] = (int)s.EntryNumber; + dr["ID"] = (int)s.ID; + dr["Text"] = (string)s.Text; + dr["Keywords"] = (string)s.Keywords; + dr["Action"] = (string)s.Action; + dr["Condition"] = (string)s.Condition; + dr["DependsOn"] = (string)s.DependsOn; + dr["Pause"] = (int)s.Pause; + dr["PrePause"] = (int)s.PrePause; + dr["LockConversation"] = (bool)s.LockConversation; + dr["IgnoreCarried"] = (bool)s.IgnoreCarried; + dr["AllowNPCTrigger"] = (bool)s.AllowNPCTrigger; + dr["SpeechStyle"] = (MessageType)s.SpeechStyle; + dr["SpeechHue"] = (int)s.SpeechHue; + dr["Gump"] = (string)s.Gump; + + // Add the row the the table + ds.Tables[SpeechPointName].Rows.Add(dr); + } + + // Write out the file + + string dirname; + + if (System.IO.Directory.Exists(DefsDir) == true) + { + // put it in the defaults directory if it exists + dirname = String.Format("{0}/{1}.npc", DefsDir, filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = String.Format("{0}.npc", filename); + } + + // check to see if the file already exists + + if (System.IO.File.Exists(dirname) == true) + { + // prompt the user to save over it + if (from != null) + { + from.SendGump(new ConfirmSaveGump(this, ds, dirname, filename, updateconfig)); + } + } + else + { + + SaveFile(from, ds, dirname, filename, updateconfig); + } + } + + public bool SaveFile(Mobile from, DataSet ds, string dirname, string configname, bool updateconfig) + { + if (ds == null) + { + if (from != null && !from.Deleted) + from.SendMessage("Empty dataset. File {0} not saved.", dirname); + return false; + } + + bool file_error = false; + + try + { + ds.WriteXml(dirname); + } + catch { file_error = true; } + + if (file_error) + { + if (from != null && !from.Deleted) + from.SendMessage("Error trying to save to file {0}", dirname); + return false; + } + else + { + if (from != null && !from.Deleted) + from.SendMessage("Saved npc to file {0}", dirname); + if (updateconfig) + ConfigFile = configname; + } + + return true; + } + + public class ConfirmSaveGump : Gump + { + private XmlDialog m_dialog; + private DataSet m_ds; + private string m_filename; + private string m_configname; + private bool m_updateconfig; + + + public ConfirmSaveGump(XmlDialog dialog, DataSet ds, string filename, string configname, bool updateconfig) + : base(0, 0) + { + m_dialog = dialog; + m_ds = ds; + m_filename = filename; + m_configname = configname; + m_updateconfig = updateconfig; + + Closable = false; + Dragable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + + AddLabel(20, 210, 33, String.Format("{0} exists.", filename)); + AddLabel(20, 230, 33, String.Format("Overwrite?", filename)); + AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff, false, false); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff, false, false); // No + AddButton(80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0); // Okay button + + } + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + + default: + { + if (radiostate == 1) + { // accept + if (m_dialog != null) + m_dialog.SaveFile(state.Mobile, m_ds, m_filename, m_configname, m_updateconfig); + } + else + { + state.Mobile.SendMessage("File {0} not saved.", m_filename); + } + break; + } + } + } + } + + + + [Usage("XmlSaveNPC filename")] + [Description("Saves the targeted Talking NPC to an xml file.")] + public static void SaveNPC_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new SaveNPCTarget(e); + } + + private class SaveNPCTarget : Target + { + private CommandEventArgs m_e; + public SaveNPCTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) + { + m_e = e; + } + protected override void OnTarget(Mobile from, object targeted) + { + string filename = m_e.GetString(0); + + if (filename == null || filename.Length <= 0) + { + from.SendMessage("must specify a save filename"); + return; + } + + // save the XmlDialog attachment info to xml + XmlDialog xa = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog; + + if (xa != null) + { + xa.DoSaveNPC(from, filename, false); + + } + else + { + from.SendMessage("Must target a Talking NPC"); + } + } + } + + [Usage("XmlLoadNPC filename")] + [Description("Loads the targeted Talking NPC to an xml file.")] + public static void LoadNPC_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new LoadNPCTarget(e); + } + + private class LoadNPCTarget : Target + { + private CommandEventArgs m_e; + public LoadNPCTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) + { + m_e = e; + } + protected override void OnTarget(Mobile from, object targeted) + { + string filename = m_e.GetString(0); + + if (filename == null || filename.Length <= 0) + { + from.SendMessage("must specify a load filename"); + return; + } + + // load the XmlDialog attachment + XmlDialog xa = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog; + + if (xa != null) + { + xa.DoLoadNPC(from, filename); + + } + else + { + // doesnt have a dialog attachment, so add and load + xa = new XmlDialog(filename); + XmlAttach.AttachTo(targeted, xa); + } + } + } + + public static bool AssignSettings(string argname, string value) + { + switch (argname) + { + case "XmlQuestNPCDir": + DefsDir = value; + break; + case "defResetTime": + defResetTime = TimeSpan.FromSeconds(XmlSpawner.ConvertToInt(value)); + break; + case "defProximityRange": + defProximityRange = XmlSpawner.ConvertToInt(value); + break; + case "defResetRange": + defResetRange = XmlSpawner.ConvertToInt(value); + break; + case "defSpeechPace": + defSpeechPace = XmlSpawner.ConvertToInt(value); + break; + default: + return false; + } + + return true; + } + + public new static void Initialize() + { + XmlSpawner.LoadSettings(new XmlSpawner.AssignSettingsHandler(AssignSettings), "XmlDialog"); + + CommandSystem.Register("SaveNPC", AccessLevel.Administrator, new CommandEventHandler(SaveNPC_OnCommand)); + CommandSystem.Register("LoadNPC", AccessLevel.Administrator, new CommandEventHandler(LoadNPC_OnCommand)); + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)9); // version + // Version 9 added the ResetRange property + writer.Write(m_ResetRange); + // Version 8 added the IgnoreCarried property + if (m_SpeechEntries != null) + { + writer.Write((int)m_SpeechEntries.Count); + foreach (SpeechEntry s in m_SpeechEntries) + { + writer.Write(s.IgnoreCarried); + } + } + else + { + writer.Write((int)0); + } + + // Version 7 + // changed DependsOn to a string + // Version 6 + // write out the additional speech entry fields + if (m_SpeechEntries != null) + { + writer.Write((int)m_SpeechEntries.Count); + foreach (SpeechEntry s in m_SpeechEntries) + { + writer.Write(s.SpeechHue); + } + } + else + { + writer.Write((int)0); + } + // Version 5 + // write out the additional speech entry fields + if (m_SpeechEntries != null) + { + writer.Write((int)m_SpeechEntries.Count); + foreach (SpeechEntry s in m_SpeechEntries) + { + writer.Write(s.Gump); + } + } + else + { + writer.Write((int)0); + } + // Version 4 + // write out the additional speech entry fields + if (m_SpeechEntries != null) + { + writer.Write((int)m_SpeechEntries.Count); + foreach (SpeechEntry s in m_SpeechEntries) + { + writer.Write(s.Condition); + } + } + else + { + writer.Write((int)0); + } + // Version 3 + writer.Write(TriggerOnCarried); + writer.Write(NoTriggerOnCarried); + // Version 2 + writer.Write(m_SpeechPace); + // write out the additional speech entry fields + if (m_SpeechEntries != null) + { + writer.Write((int)m_SpeechEntries.Count); + foreach (SpeechEntry s in m_SpeechEntries) + { + writer.Write(s.PrePause); + writer.Write(s.LockConversation); + writer.Write(s.AllowNPCTrigger); + writer.Write((int)s.SpeechStyle); + } + } + else + { + writer.Write((int)0); + } + + // Version 1 + writer.Write(m_ActivePlayer); + + // Version 0 + writer.Write(m_IsActive); + writer.Write(m_ResetTime); + writer.Write(m_LastInteraction); + writer.Write(m_AllowGhostTriggering); + writer.Write(m_ProximityRange); + writer.Write(m_Running); + writer.Write(m_ConfigFile); + // write out the speech entries + if (m_SpeechEntries != null) + { + writer.Write((int)m_SpeechEntries.Count); + foreach (SpeechEntry s in m_SpeechEntries) + { + writer.Write(s.EntryNumber); + writer.Write(s.ID); + writer.Write(s.Text); + writer.Write(s.Keywords); + writer.Write(s.Action); + writer.Write(s.DependsOn); + writer.Write(s.Pause); + } + } + else + { + writer.Write((int)0); + } + writer.Write(m_CurrentEntryNumber); + // check to see if the timer is running + if (m_Timer != null && m_Timer.Running) + { + writer.Write(true); + writer.Write(m_Timer.m_trigmob); + writer.Write(m_Timer.m_delay); + } + else + { + writer.Write(false); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 9: + { + m_ResetRange = reader.ReadInt(); + goto case 8; + } + case 8: + { + int count = reader.ReadInt(); + m_SpeechEntries = new ArrayList(); + for (int i = 0; i < count; i++) + { + SpeechEntry newentry = new SpeechEntry(); + + newentry.IgnoreCarried = reader.ReadBool(); + + m_SpeechEntries.Add(newentry); + } + + goto case 7; + } + case 7: + { + goto case 6; + } + case 6: + { + int count = reader.ReadInt(); + if (version < 8) + { + m_SpeechEntries = new ArrayList(); + } + for (int i = 0; i < count; i++) + { + if (version < 8) + { + SpeechEntry newentry = new SpeechEntry(); + + newentry.SpeechHue = reader.ReadInt(); + + m_SpeechEntries.Add(newentry); + } + else + { + SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i]; + + newentry.SpeechHue = reader.ReadInt(); + } + } + + goto case 5; + } + case 5: + { + int count = reader.ReadInt(); + if (version < 6) + { + m_SpeechEntries = new ArrayList(); + } + for (int i = 0; i < count; i++) + { + if (version < 6) + { + SpeechEntry newentry = new SpeechEntry(); + + newentry.Gump = reader.ReadString(); + + m_SpeechEntries.Add(newentry); + } + else + { + SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i]; + + newentry.Gump = reader.ReadString(); + } + } + + goto case 4; + } + case 4: + { + int count = reader.ReadInt(); + if (version < 5) + { + m_SpeechEntries = new ArrayList(); + } + for (int i = 0; i < count; i++) + { + if (version < 5) + { + SpeechEntry newentry = new SpeechEntry(); + + newentry.Condition = reader.ReadString(); + + m_SpeechEntries.Add(newentry); + } + else + { + SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i]; + + newentry.Condition = reader.ReadString(); + } + } + + goto case 3; + } + case 3: + { + TriggerOnCarried = reader.ReadString(); + NoTriggerOnCarried = reader.ReadString(); + goto case 2; + } + case 2: + { + m_SpeechPace = reader.ReadInt(); + + int count = reader.ReadInt(); + if (version < 4) + { + m_SpeechEntries = new ArrayList(); + } + for (int i = 0; i < count; i++) + { + if (version < 4) + { + SpeechEntry newentry = new SpeechEntry(); + + newentry.PrePause = reader.ReadInt(); + newentry.LockConversation = reader.ReadBool(); + newentry.AllowNPCTrigger = reader.ReadBool(); + newentry.SpeechStyle = (MessageType)reader.ReadInt(); + + m_SpeechEntries.Add(newentry); + } + else + { + SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i]; + + newentry.PrePause = reader.ReadInt(); + newentry.LockConversation = reader.ReadBool(); + newentry.AllowNPCTrigger = reader.ReadBool(); + newentry.SpeechStyle = (MessageType)reader.ReadInt(); + } + } + goto case 1; + } + case 1: + { + m_ActivePlayer = reader.ReadMobile(); + goto case 0; + } + case 0: + { + m_IsActive = reader.ReadBool(); + m_ResetTime = reader.ReadTimeSpan(); + m_LastInteraction = reader.ReadDateTime(); + m_AllowGhostTriggering = reader.ReadBool(); + m_ProximityRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + m_ConfigFile = reader.ReadString(); + int count = reader.ReadInt(); + if (version < 2) + { + m_SpeechEntries = new ArrayList(); + } + for (int i = 0; i < count; i++) + { + + if (version < 2) + { + SpeechEntry newentry = new SpeechEntry(); + + newentry.EntryNumber = reader.ReadInt(); + newentry.ID = reader.ReadInt(); + newentry.Text = reader.ReadString(); + newentry.Keywords = reader.ReadString(); + newentry.Action = reader.ReadString(); + newentry.DependsOn = reader.ReadInt().ToString(); + newentry.Pause = reader.ReadInt(); + + m_SpeechEntries.Add(newentry); + } + else + { + SpeechEntry newentry = (SpeechEntry)m_SpeechEntries[i]; + + newentry.EntryNumber = reader.ReadInt(); + newentry.ID = reader.ReadInt(); + newentry.Text = reader.ReadString(); + newentry.Keywords = reader.ReadString(); + newentry.Action = reader.ReadString(); + if (version < 7) + { + newentry.DependsOn = reader.ReadInt().ToString(); + } + else + { + newentry.DependsOn = reader.ReadString(); + } + newentry.Pause = reader.ReadInt(); + } + } + // read in the current entry number. Note this will also set the current entry + EntryNumber = reader.ReadInt(); + // restart the timer if it was active + bool isrunning = reader.ReadBool(); + if (isrunning) + { + Mobile trigmob = reader.ReadMobile(); + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer(delay, trigmob); + } + break; + } + } + } + } +} + diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlEnemyMastery.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlEnemyMastery.cs new file mode 100644 index 0000000..d01c662 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlEnemyMastery.cs @@ -0,0 +1,161 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlEnemyMastery : XmlAttachment + { + private int m_Chance = 20; // 20% chance by default + private int m_PercentIncrease = 50; + private string m_Enemy; + private Type m_EnemyType; + + [CommandProperty( AccessLevel.GameMaster )] + public int Chance { get{ return m_Chance; } set { m_Chance = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int PercentIncrease { get{ return m_PercentIncrease; } set { m_PercentIncrease = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string Enemy + { + get { return m_Enemy; } + set + { + m_Enemy = value; + // look up the type + m_EnemyType = SpawnerType.GetType(m_Enemy); + } + } + + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlEnemyMastery(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlEnemyMastery(string enemy) + { + Enemy = enemy; + } + + [Attachable] + public XmlEnemyMastery(string enemy,int increase ) + { + m_PercentIncrease = increase; + Enemy = enemy; + } + + [Attachable] + public XmlEnemyMastery(string enemy,int chance, int increase ) + { + m_Chance = chance; + m_PercentIncrease = increase; + Enemy = enemy; + } + + [Attachable] + public XmlEnemyMastery(string enemy, int chance, int increase, double expiresin) + { + m_Chance = chance; + m_PercentIncrease = increase; + Expiration = TimeSpan.FromMinutes(expiresin); + Enemy = enemy; + } + + public override void OnAttach() + { + base.OnAttach(); + + if(AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + Effects.PlaySound( m, m.Map, 516 ); + m.SendMessage(String.Format("You gain the power of Enemy Mastery over {0}",Enemy)); + } + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + if(m_Chance <= 0 || Utility.Random(100) > m_Chance) + return; + + if(defender != null && attacker != null && m_EnemyType != null) + { + + // is the defender the correct type? + if(defender.GetType() == m_EnemyType || defender.GetType().IsSubclassOf(m_EnemyType)) + { + defender.Damage( (int) (damageGiven*PercentIncrease/100), attacker ); + } + } + } + + public override void OnDelete() + { + base.OnDelete(); + + if(AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + if(!m.Deleted) + { + Effects.PlaySound( m, m.Map, 958 ); + m.SendMessage(String.Format("Your power of Enemy Mastery over {0} fades..",Enemy)); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_PercentIncrease); + writer.Write(m_Chance); + writer.Write(m_Enemy); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_PercentIncrease = reader.ReadInt(); + m_Chance = reader.ReadInt(); + Enemy = reader.ReadString(); + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Enemy Mastery : +{3}% damage vs {0}, {1}%, hitchance expires in {2} mins", m_Enemy, Chance, Expiration.TotalMinutes, PercentIncrease); + } + else + { + msg = String.Format("Enemy Mastery : +{2}% damage vs {0}, {1}% hitchance",m_Enemy, Chance, PercentIncrease); + } + + return msg; + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlFire.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlFire.cs new file mode 100644 index 0000000..7b6f762 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlFire.cs @@ -0,0 +1,176 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlFire : XmlAttachment + { + private int m_Damage = 0; + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public int Damage { get{ return m_Damage; } set { m_Damage = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlFire(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlFire(int damage) + { + m_Damage = damage; + } + + [Attachable] + public XmlFire(int damage, double refractory) + { + m_Damage = damage; + Refractory = TimeSpan.FromSeconds(refractory); + + } + + [Attachable] + public XmlFire(int damage, double refractory, double expiresin) + { + m_Damage = damage; + Expiration = TimeSpan.FromMinutes(expiresin); + Refractory = TimeSpan.FromSeconds(refractory); + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int damage = 0; + + if(m_Damage > 0) + damage = Utility.Random(m_Damage); + + if(defender != null && attacker != null && damage > 0) + { + attacker.MovingParticles( defender, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160 ); + attacker.PlaySound( 0x15E ); + + SpellHelper.Damage( TimeSpan.Zero, defender, attacker, damage, 0, 100, 0, 0, 0 ); + + m_EndTime = DateTime.Now + Refractory; + } + } + + public override bool HandlesOnMovement { get { return true; } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_Damage); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + Range = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + m_Damage = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Fire Damage {0} expires in {1} mins", m_Damage, Expiration.TotalMinutes); + } + else + { + msg = String.Format("Fire Damage {0}",m_Damage); + } + + if(Refractory > TimeSpan.Zero) + { + return String.Format("{0} : {1} secs between uses",msg, Refractory.TotalSeconds); + } + else + return msg; + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int damage = 0; + + if(m_Damage > 0) + damage = Utility.Random(m_Damage); + + if(damage > 0) + { + m.MovingParticles( m, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160 ); + m.PlaySound( 0x15E ); + SpellHelper.Damage( TimeSpan.Zero, m, damage, 0, 100, 0, 0, 0 ); + } + + m_EndTime = DateTime.Now + Refractory; + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlFreeze.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlFreeze.cs new file mode 100644 index 0000000..48e65bb --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlFreeze.cs @@ -0,0 +1,88 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlFreeze : XmlAttachment + { + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlFreeze(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlFreeze() + { + } + + [Attachable] + public XmlFreeze(double seconds) + { + Expiration = TimeSpan.FromSeconds(seconds); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override string OnIdentify(Mobile from) + { + base.OnIdentify(from); + + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("Freeze expires in {1} secs",Expiration.TotalSeconds); + } + else + { + return String.Format("Frozen"); + } + } + + public override void OnDelete() + { + base.OnDelete(); + + // remove the mod + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).Frozen = false; + } + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).Frozen = true; + ((Mobile)AttachedTo).ProcessDelta(); + } + else + Delete(); + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlHue.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlHue.cs new file mode 100644 index 0000000..e0045bb --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlHue.cs @@ -0,0 +1,117 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlHue : XmlAttachment + { + private int m_Originalhue; + private int m_Hue; + + [CommandProperty( AccessLevel.GameMaster )] + public int Hue { get{ return m_Hue; } set { m_Hue = value; } } + + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlHue(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlHue(int value) + { + m_Hue = value; + Expiration = TimeSpan.FromSeconds(30.0); // default 30 second duration + } + + [Attachable] + public XmlHue(int value, double duration) + { + m_Hue = value; + Expiration = TimeSpan.FromMinutes(duration); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_Originalhue); + writer.Write(m_Hue); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + + m_Originalhue = reader.ReadInt(); + m_Hue = reader.ReadInt(); + } + + public override string OnIdentify(Mobile from) + { + base.OnIdentify(from); + + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("Hue {0} expires in {1} mins",m_Hue,Expiration.TotalMinutes); + } + else + { + return String.Format("Hue {0}",m_Hue); + } + } + + public override void OnDelete() + { + base.OnDelete(); + + // remove the mod + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).Hue = m_Originalhue; + } + else + if(AttachedTo is Item) + { + ((Item)AttachedTo).Hue = m_Originalhue; + } + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + m_Originalhue = m.Hue; + m.Hue = m_Hue; + } + else + if(AttachedTo is Item) + { + Item i = AttachedTo as Item; + m_Originalhue = i.Hue; + i.Hue = m_Hue; + } + else + Delete(); + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlInt.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlInt.cs new file mode 100644 index 0000000..8add698 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlInt.cs @@ -0,0 +1,59 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlInt : XmlAttachment + { + private TimeSpan m_Duration = TimeSpan.FromSeconds(30.0); // default 30 sec duration + private int m_Value = 10; // default value of 10 + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get { return m_Value; } set { m_Value = value; } } + + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlInt(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlInt() + { + } + + [Attachable] + public XmlInt(int value) + { + m_Value = value; + } + + [Attachable] + public XmlInt(int value, double duration) + { + m_Value = value; + m_Duration = TimeSpan.FromSeconds(duration); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).AddStatMod( new StatMod( StatType.Int, "XmlInt"+Name, m_Value, m_Duration ) ); + } + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlLifeDrain.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlLifeDrain.cs new file mode 100644 index 0000000..ffd322f --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlLifeDrain.cs @@ -0,0 +1,205 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlLifeDrain : XmlAttachment + { + private int m_Drain = 0; + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public int Drain { get{ return m_Drain; } set { m_Drain = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlLifeDrain(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlLifeDrain(int drain) + { + m_Drain = drain; + } + + [Attachable] + public XmlLifeDrain(int drain, double refractory) + { + m_Drain = drain; + Refractory = TimeSpan.FromSeconds(refractory); + + } + + [Attachable] + public XmlLifeDrain(int drain, double refractory, double expiresin) + { + m_Drain = drain; + Expiration = TimeSpan.FromMinutes(expiresin); + Refractory = TimeSpan.FromSeconds(refractory); + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int drain = 0; + + if(m_Drain > 0) + drain = Utility.Random(m_Drain); + + if(defender != null && attacker != null && drain > 0) + { + defender.Hits -= drain; + if(defender.Hits < 0) defender.Hits = 0; + attacker.Hits += drain; + if(attacker.Hits < 0) attacker.Hits = 0; + + DrainEffect(defender); + + m_EndTime = DateTime.Now + Refractory; + } + } + + public void DrainEffect(Mobile m) + { + if (m == null) return; + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist ); + m.PlaySound( 0x231 ); + + m.SendMessage( "You feel the life drain out of you!" ); + } + + public override bool HandlesOnMovement { get { return true; } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_Drain); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + // version 1 + Range = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + m_Drain = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Life drain {0} expires in {1} mins", m_Drain, Expiration.TotalMinutes); + } + else + { + msg = String.Format("Life drain {0}",m_Drain); + } + + if(Refractory > TimeSpan.Zero) + { + return String.Format("{0} : {1} secs between uses",msg, Refractory.TotalSeconds); + } + else + return msg; + } + + public override void OnAttach() + { + base.OnAttach(); + + // announce it to the mob + if(AttachedTo is Mobile) + { + if(m_Drain > 0) + ((Mobile)AttachedTo).SendMessage("You have been granted the power of Life Drain!"); + else + ((Mobile)AttachedTo).SendMessage("You have been cursed with Life Drain!"); + } + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int drain = 0; + + if(m_Drain > 0) + drain = Utility.Random(m_Drain); + + if(drain > 0) + { + m.Hits -= drain; + if(m.Hits < 0) m.Hits = 0; + + DrainEffect(m); + + } + + m_EndTime = DateTime.Now + Refractory; + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlLightning.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlLightning.cs new file mode 100644 index 0000000..efae1f4 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlLightning.cs @@ -0,0 +1,190 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlLightning : XmlAttachment + { + private int m_Damage = 0; + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public int Damage { get{ return m_Damage; } set { m_Damage = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlLightning(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlLightning(int damage) + { + m_Damage = damage; + } + + [Attachable] + public XmlLightning(int damage, double refractory) + { + m_Damage = damage; + Refractory = TimeSpan.FromSeconds(refractory); + + } + + [Attachable] + public XmlLightning(int damage, double refractory, double expiresin) + { + m_Damage = damage; + Expiration = TimeSpan.FromMinutes(expiresin); + Refractory = TimeSpan.FromSeconds(refractory); + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int damage = 0; + + if(m_Damage > 0) + damage = Utility.Random(m_Damage); + + if(defender != null && attacker != null && damage > 0) + { + defender.BoltEffect( 0 ); + + SpellHelper.Damage( TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100 ); + + m_EndTime = DateTime.Now + Refractory; + } + } + + //public override bool HandlesOnMovement { get { return true; } } + + // restrict the movement detection feature to non-movable items + + public override bool HandlesOnMovement + { + get + { + if(AttachedTo is Item && !((Item)AttachedTo).Movable) + return true; + else + return false; + } + } + + + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_Damage); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + proximityrange = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + m_Damage = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Lightning Damage {0} expires in {1} mins", m_Damage, Expiration.TotalMinutes); + } + else + { + msg = String.Format("Lightning Damage {0}",m_Damage); + } + + if(Refractory > TimeSpan.Zero) + { + return String.Format("{0} - {1} secs between uses",msg, Refractory.TotalSeconds); + } + else + return msg; + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int damage = 0; + + if(m_Damage > 0) + damage = Utility.Random(m_Damage); + + if(damage > 0) + { + m.BoltEffect( 0 ); + + SpellHelper.Damage( TimeSpan.Zero, m, damage, 0, 0, 0, 0, 100 ); + } + + m_EndTime = DateTime.Now + Refractory; + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlLocalVariable.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlLocalVariable.cs new file mode 100644 index 0000000..7c93fc1 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlLocalVariable.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlLocalVariable : XmlAttachment + { + private string m_DataValue = null; // default data + + [CommandProperty( AccessLevel.GameMaster )] + public string Data { get{ return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlLocalVariable(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlLocalVariable(string name) + { + Name = name; + Data = String.Empty; + } + + [Attachable] + public XmlLocalVariable(string name, string data) + { + Name = name; + Data = data; + } + + [Attachable] + public XmlLocalVariable(string name, string data, double expiresin) + { + Name = name; + Data = data; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write((string)m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadString(); + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("{2} = {0} : expires in {1} mins",Data,Expiration.TotalMinutes, Name); + } + else + { + return String.Format("{1} = {0}",Data, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlMagicWord.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMagicWord.cs new file mode 100644 index 0000000..8e2e09d --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMagicWord.cs @@ -0,0 +1,267 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlMagicWord : XmlAttachment + { + private string Word; + private TimeSpan Duration = TimeSpan.FromSeconds(30.0); // 30 sec default duration for effects + private int Charges = 1; // single use by default, note a value of zero or less means unlimited use + private TimeSpan Refractory = TimeSpan.Zero; // no refractory period + private DateTime m_EndTime = DateTime.MinValue; + + // static list used for random word assignment + private static string [] keywordlist = new string[] { "Shoda", "Malik", "Lepto" , "Velas", "Tarda", "Marda", "Vas Malik", "Nartor", "Santor"}; + + // note that support for player identification requires modification of the identification skill (see the installation notes for details) + private bool m_Identified = false; // optional identification flag that can suppress application of the mod until identified when applied to items + + private bool m_RequireIdentification = false; // by default no identification is required for the mod to be activatable + + // this property can be set allowing individual items to determine whether they must be identified for the mod to be activatable + public bool RequireIdentification { get { return m_RequireIdentification; } set {m_RequireIdentification = value; } } + + // a serial constructor is REQUIRED + public XmlMagicWord(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlMagicWord() + { + Word = keywordlist[Utility.Random(keywordlist.Length)]; + Name = Word; + } + + [Attachable] + public XmlMagicWord(string word) + { + Word = word; + Name = word; + } + + [Attachable] + public XmlMagicWord(string word, double duration) + { + Name = word; + Word = word; + Duration = TimeSpan.FromSeconds(duration); + } + + [Attachable] + public XmlMagicWord(string word, double duration, double refractory) + { + Name = word; + Word = word; + Duration = TimeSpan.FromSeconds(duration); + Refractory = TimeSpan.FromSeconds(refractory); + } + + [Attachable] + public XmlMagicWord(string word, double duration, double refractory, int charges) + { + Name = word; + Word = word; + Duration = TimeSpan.FromSeconds(duration); + Refractory = TimeSpan.FromSeconds(refractory); + Charges = charges; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(Word); + writer.Write(Charges); + writer.Write(Duration); + writer.Write(Refractory); + writer.Write(m_EndTime - DateTime.Now); + writer.Write(m_RequireIdentification); + writer.Write(m_Identified); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + Word = reader.ReadString(); + Charges = reader.ReadInt(); + Duration = reader.ReadTimeSpan(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + m_RequireIdentification = reader.ReadBool(); + m_Identified = reader.ReadBool(); + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + // can force identification before the skill mods can be applied + if(from != null && from.AccessLevel == AccessLevel.Player) + { + m_Identified = true; + } + + if(RequireIdentification && !m_Identified) return null; + + if(Refractory > TimeSpan.Zero) + { + msg = String.Format("{0} lasting {1} secs : {2} secs between uses",Word,Duration.TotalSeconds, Refractory.TotalSeconds); + } + else + { + msg = String.Format("{0} lasting {1} secs",Word,Duration.TotalSeconds); + } + + if(Charges > 0) + { + return String.Format("{0} : {1} charge(s) remaining",msg, Charges); + } + else + { + return msg; + } + } + + // by overriding these properties armor and weapons can be restricted to trigger on speech only when equipped and not when in the pack or in the world + public override bool CanActivateInBackpack + { + get + { + if(AttachedTo is BaseWeapon || AttachedTo is BaseArmor) + return false; + else + return true; + } + } + + public override bool CanActivateInWorld + { + get + { + if(AttachedTo is BaseWeapon || AttachedTo is BaseArmor) + return false; + else + return true; + } + } + + public override bool HandlesOnSpeech { get { return true; } } + + public override void OnSpeech(SpeechEventArgs e ) + { + base.OnSpeech(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + // dont respond to other players speech if this is attached to a mob + if(AttachedTo is Mobile && (Mobile)AttachedTo != e.Mobile) return; + + if(e.Speech == Word) + { + OnTrigger(null, e.Mobile); + } + } + + public void Hide_Callback(object state) + { + object[] args = (object[])state; + Mobile m = (Mobile)args[0]; + + m.Hidden = true; + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null || Word == null || (RequireIdentification && !m_Identified)) return; + + if(DateTime.Now < m_EndTime) return; + + string msgstr = "Activating the power of " + Word; + + // assign powers to certain words + switch ( Word ) + { + case "Shoda": + m.AddStatMod( new StatMod( StatType.Int, "Shoda", 20, Duration ) ); + m.SendMessage("Your mind expands!"); + break; + case "Malik": + m.AddStatMod( new StatMod( StatType.Str, "Malik", 20, Duration ) ); + m.SendMessage("Your strength surges!"); + break; + case "Lepto": + m.AddStatMod( new StatMod( StatType.Dex, "Lepto", 20, Duration ) ); + m.SendMessage("You are more nimble!"); + break; + case "Velas": + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( Hide_Callback ), new object[]{ m } ); + m.SendMessage("You disappear!"); + break; + case "Tarda": + m.AddSkillMod( new TimedSkillMod( SkillName.Tactics, true, 20, Duration ) ); + m.SendMessage("You are more skillful warrior!"); + break; + case "Marda": + m.AddSkillMod( new TimedSkillMod( SkillName.Magery, true, 20, Duration ) ); + m.SendMessage("You are more skillful mage!"); + break; + case "Vas Malik": + m.AddStatMod( new StatMod( StatType.Str, "Vas Malik", 40, Duration ) ); + m.SendMessage("You are exceptionally strong!"); + break; + case "Nartor": + BaseCreature b = new Drake(); + b.MoveToWorld(m.Location, m.Map); + b.Owners.Add( m ); + b.SetControlMaster( m ); + if(b.Controlled) + m.SendMessage("You master the beast!"); + break; + case "Santor": + b = new Horse(); + b.MoveToWorld(m.Location, m.Map); + b.Owners.Add( m ); + b.SetControlMaster( m ); + if(b.Controlled) + m.SendMessage("You master the beast!"); + break; + default: + m.SendMessage("There is no effect."); + break; + } + + // display activation effects + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 ); + Effects.PlaySound( m, m.Map, 0x201 ); + + // display a message over the item it was attached to + if(AttachedTo is Item ) + { + ((Item)AttachedTo).PublicOverheadMessage( MessageType.Regular, 0x3B2, true, msgstr ); + } + + Charges--; + + // remove the attachment after the charges run out + if(Charges == 0) + { + Delete(); + } + else + { + m_EndTime = DateTime.Now + Refractory; + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlManaDrain.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlManaDrain.cs new file mode 100644 index 0000000..6b765d9 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlManaDrain.cs @@ -0,0 +1,191 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlManaDrain : XmlAttachment + { + private int m_Drain = 0; + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public int Drain { get{ return m_Drain; } set { m_Drain = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlManaDrain(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlManaDrain(int drain) + { + m_Drain = drain; + } + + [Attachable] + public XmlManaDrain(int drain, double refractory) + { + m_Drain = drain; + Refractory = TimeSpan.FromSeconds(refractory); + + } + + [Attachable] + public XmlManaDrain(int drain, double refractory, double expiresin) + { + m_Drain = drain; + Expiration = TimeSpan.FromMinutes(expiresin); + Refractory = TimeSpan.FromSeconds(refractory); + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int drain = 0; + + if(m_Drain > 0) + drain = Utility.Random(m_Drain); + + if(defender != null && attacker != null && drain > 0) + { + defender.Mana -= drain; + if(defender.Mana < 0) defender.Mana = 0; + attacker.Mana += drain; + if(attacker.Mana < 0) attacker.Mana = 0; + + m_EndTime = DateTime.Now + Refractory; + } + } + + public override bool HandlesOnMovement { get { return true; } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_Drain); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + // version 1 + Range = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + m_Drain = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Mana drain {0} expires in {1} mins", m_Drain, Expiration.TotalMinutes); + } + else + { + msg = String.Format("Mana drain {0}",m_Drain); + } + + if(Refractory > TimeSpan.Zero) + { + return String.Format("{0} : {1} secs between uses",msg, Refractory.TotalSeconds); + } + else + return msg; + } + + public override void OnAttach() + { + base.OnAttach(); + + // announce it to the mob + if(AttachedTo is Mobile) + { + if(m_Drain > 0) + ((Mobile)AttachedTo).SendMessage("You have been granted the power of Mana Drain!"); + else + ((Mobile)AttachedTo).SendMessage("You have been cursed with Mana Drain!"); + } + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int drain = 0; + + if(m_Drain > 0) + drain = Utility.Random(m_Drain); + + if(drain > 0) + { + m.Mana -= drain; + if(m.Mana < 0) m.Mana = 0; + + } + + m_EndTime = DateTime.Now + Refractory; + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlMessage.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMessage.cs new file mode 100644 index 0000000..c1e7198 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMessage.cs @@ -0,0 +1,203 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlMessage : XmlAttachment + { + private string m_MessageStr; + private string m_Word = null; // no word activation by default + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int m_Charges = 0; // no charge limit + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public string Message { get { return m_MessageStr; } set { m_MessageStr = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string ActivationWord { get { return m_Word; } set { m_Word = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges { get { return m_Charges; } set { m_Charges = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlMessage(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlMessage(string msg) + { + Message = msg; + } + + [Attachable] + public XmlMessage(string msg, double refractory) + { + Message = msg; + Refractory = TimeSpan.FromSeconds(refractory); + } + + [Attachable] + public XmlMessage(string msg, double refractory, string word ) + { + ActivationWord = word; + Message = msg; + Refractory = TimeSpan.FromSeconds(refractory); + } + + [Attachable] + public XmlMessage(string msg, double refractory, string word, int charges ) + { + ActivationWord = word; + Message = msg; + Refractory = TimeSpan.FromSeconds(refractory); + Charges = charges; + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_MessageStr); + writer.Write(m_Word); + writer.Write(m_Charges); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + Range = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + Message = reader.ReadString(); + ActivationWord = reader.ReadString(); + Charges = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + string msg = null; + + if(Charges > 0) + { + msg = String.Format("{0} : {1} secs between uses, {2} charges left",Message,Refractory.TotalSeconds, Charges); + } + else + { + msg = String.Format("{0} : {1} secs between uses",Message,Refractory.TotalSeconds); + } + + if(ActivationWord == null) + { + return msg; + } + else + { + return String.Format("{0} : trigger on '{1}'",msg,ActivationWord); + } + + } + + public override bool HandlesOnSpeech { get { return (ActivationWord != null); } } + + public override void OnSpeech(SpeechEventArgs e ) + { + base.OnSpeech(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(e.Speech == ActivationWord) + { + OnTrigger(null, e.Mobile); + } + } + + public override bool HandlesOnMovement { get { return (ActivationWord == null); } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + if(AttachedTo is Mobile && Utility.InRange( e.Mobile.Location, ((Mobile)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + if(DateTime.Now < m_EndTime) return; + + + // display a message over the item it was attached to + if(AttachedTo is Item ) + { + ((Item)AttachedTo).PublicOverheadMessage( MessageType.Regular, 0x3B2, true, Message ); + } + else + if(AttachedTo is Mobile ) + { + ((Mobile)AttachedTo).PublicOverheadMessage( MessageType.Regular, 0x3B2, true, Message ); + } + + Charges--; + + // remove the attachment either after the charges run out or if refractory is zero, then it is one use only + if(Refractory == TimeSpan.Zero || Charges == 0) + { + Delete(); + } + else + { + m_EndTime = DateTime.Now + Refractory; + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlMinionStrike.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMinionStrike.cs new file mode 100644 index 0000000..9522c7b --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMinionStrike.cs @@ -0,0 +1,214 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlMinionStrike : XmlAttachment + { + private int m_Chance = 5; // 5% chance by default + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private string m_Minion = "Drake"; + private ArrayList MinionList = new ArrayList(); + + [CommandProperty( AccessLevel.GameMaster )] + public int Chance { get{ return m_Chance; } set { m_Chance = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string Minion { get { return m_Minion; } set { m_Minion = value; } } + + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlMinionStrike(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlMinionStrike(string minion) + { + m_Minion = minion; + Expiration = TimeSpan.FromMinutes(30); + } + + [Attachable] + public XmlMinionStrike(string minion,int chance ) + { + m_Chance = chance; + m_Minion = minion; + Expiration = TimeSpan.FromMinutes(30); + } + + [Attachable] + public XmlMinionStrike(string minion, int chance, double refractory) + { + m_Chance = chance; + Refractory = TimeSpan.FromSeconds(refractory); + Expiration = TimeSpan.FromMinutes(30); + m_Minion = minion; + + } + + [Attachable] + public XmlMinionStrike(string minion, int chance, double refractory, double expiresin) + { + m_Chance = chance; + Expiration = TimeSpan.FromMinutes(expiresin); + Refractory = TimeSpan.FromSeconds(refractory); + m_Minion = minion; + } + + public override void OnAttach() + { + base.OnAttach(); + + if(AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + Effects.PlaySound( m, m.Map, 516 ); + } + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + if(m_Chance <= 0 || Utility.Random(100) > m_Chance) + return; + + if(defender != null && attacker != null) + { + + // spawn a minion + object o = null; + try + { + o = Activator.CreateInstance( SpawnerType.GetType(m_Minion) ); + } + catch{} + + if(o is BaseCreature) + { + BaseCreature b = o as BaseCreature; + b.MoveToWorld(attacker.Location, attacker.Map); + + if(attacker is PlayerMobile) + { + b.Controlled = true; + b.ControlMaster = attacker; + } + + b.Combatant = defender; + + // add it to the list of controlled mobs + MinionList.Add(b); + } + else + { + if(o is Item) + ((Item)o).Delete(); + if(o is Mobile) + ((Mobile)o).Delete(); + // bad minion specification so delete the attachment + Delete(); + } + + m_EndTime = DateTime.Now + Refractory; + } + } + + public override void OnDelete() + { + base.OnDelete(); + + if(AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + if(!m.Deleted) + { + Effects.PlaySound( m, m.Map, 958 ); + } + } + + // delete the minions + foreach(BaseCreature b in MinionList) + { + if(b != null && !b.Deleted) + b.Delete(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_Chance); + writer.Write(m_Minion); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + writer.Write(MinionList.Count); + foreach(BaseCreature b in MinionList) + writer.Write(b); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_Chance = reader.ReadInt(); + m_Minion = reader.ReadString(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + int nminions = reader.ReadInt(); + for(int i = 0;i TimeSpan.Zero) + { + msg = String.Format("Minion : {0} {1}% chance expires in {2} mins", m_Minion, Chance, Expiration.TotalMinutes); + } + else + { + msg = String.Format("Minion : {0}",m_Minion); + } + + if(Refractory > TimeSpan.Zero) + { + return String.Format("{0} : {1} secs between uses",msg, Refractory.TotalSeconds); + } + else + return msg; + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlMorph.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMorph.cs new file mode 100644 index 0000000..2b6fb27 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlMorph.cs @@ -0,0 +1,267 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlMorph : XmlAttachment + { + private string m_Word = null; // no word activation by default + private int m_OriginalID = -1; // default value indicating that it has not been morphed + private int m_MorphID; + private int proximityrange = 2; // default movement activation from 5 tiles away + private TimeSpan m_Duration = TimeSpan.FromSeconds(30.0); // default 30 second duration + private MorphTimer m_MorphTimer; + private DateTime m_MorphEnd; + + [CommandProperty( AccessLevel.GameMaster )] + public int MorphID { get { return m_MorphID; } set { m_MorphID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Duration { get { return m_Duration; } set { m_Duration = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime MorphEnd { get { return m_MorphEnd; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string ActivationWord { get { return m_Word; } set { m_Word = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlMorph(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlMorph(int morphID) + { + m_MorphID = morphID; + } + + [Attachable] + public XmlMorph(int morphID, double duration) + { + m_MorphID = morphID; + m_Duration = TimeSpan.FromMinutes(duration); + } + + [Attachable] + public XmlMorph(int morphID, double duration, string word) + { + m_MorphID = morphID; + m_Duration = TimeSpan.FromMinutes(duration); + ActivationWord = word; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_OriginalID); + writer.Write(m_MorphID); + writer.Write(m_Duration); + writer.Write(m_Word); + if(m_MorphTimer != null) + { + writer.Write(m_MorphEnd - DateTime.Now); + } + else + { + writer.Write(TimeSpan.Zero); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + Range = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + + m_OriginalID = reader.ReadInt(); + m_MorphID = reader.ReadInt(); + m_Duration = reader.ReadTimeSpan(); + ActivationWord = reader.ReadString(); + TimeSpan remaining = (TimeSpan)reader.ReadTimeSpan(); + + if(remaining > TimeSpan.Zero) + DoTimer(remaining); + break; + } + } + + public override string OnIdentify(Mobile from) + { + base.OnIdentify(from); + + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Morph to {0} expires in {1} mins",m_MorphID,Expiration.TotalMinutes); + } + else + { + msg = String.Format("Morph to {0} duration {1} mins",m_MorphID, m_Duration.TotalMinutes); + } + + if(ActivationWord != null) + { + return String.Format("{0} activated by '{1}'",msg, ActivationWord); + } + else + { + return msg; + } + } + + public override void OnDelete() + { + base.OnDelete(); + + // remove the mod + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).BodyMod = m_OriginalID; + } + else + if(AttachedTo is Item) + { + ((Item)AttachedTo).ItemID = m_OriginalID; + } + } + + public override bool HandlesOnSpeech { get { return (ActivationWord != null); } } + + public override void OnSpeech(SpeechEventArgs e ) + { + base.OnSpeech(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + // dont respond to other players speech if this is attached to a mob + if(AttachedTo is Mobile && (Mobile)AttachedTo != e.Mobile) return; + + if(e.Speech == ActivationWord) + { + OnTrigger(null, e.Mobile); + } + } + + public override bool HandlesOnMovement { get { return (ActivationWord == null); } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod immediately if attached to a mob + if(AttachedTo is Mobile) + { + Mobile m = AttachedTo as Mobile; + m_OriginalID = m.BodyMod; + m.BodyMod = m_MorphID; + Expiration = m_Duration; + } + } + + public override void OnReattach() + { + base.OnReattach(); + + // reapply the mod if attached to a mob + if(AttachedTo is Mobile) + { + ((Mobile)AttachedTo).BodyMod = m_MorphID; + } + } + + // ---------------------------------------------- + // Private methods + // ---------------------------------------------- + private void DoTimer(TimeSpan delay) + { + m_MorphEnd = DateTime.Now + delay; + + if ( m_MorphTimer != null ) + m_MorphTimer.Stop(); + + m_MorphTimer = new MorphTimer( this, delay); + m_MorphTimer.Start(); + } + + // a timer that can be implement limited lifetime morph + private class MorphTimer : Timer + { + private XmlMorph m_Attachment; + + public MorphTimer( XmlMorph attachment, TimeSpan delay) : base( delay ) + { + Priority = TimerPriority.OneSecond; + + m_Attachment = attachment; + } + + protected override void OnTick() + { + if(m_Attachment != null && !m_Attachment.Deleted && m_Attachment.AttachedTo is Item && !((Item)m_Attachment.AttachedTo).Deleted) + { + Item i = m_Attachment.AttachedTo as Item; + i.ItemID = m_Attachment.m_OriginalID; + m_Attachment.m_OriginalID = -1; + } + } + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + // if attached to an item then morph and then reset after duration + // note that OriginalID will be -1 if the target is not already morphed + if(AttachedTo is Item && m_OriginalID == -1) + { + Item i = AttachedTo as Item; + m_OriginalID = i.ItemID; + i.ItemID = m_MorphID; + + // start the timer to reset the ID + DoTimer(m_Duration); + } + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlSaveItem.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlSaveItem.cs new file mode 100644 index 0000000..21c7d2c --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlSaveItem.cs @@ -0,0 +1,246 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlSaveItem : XmlAttachment + { + private class SaveItemPack : Container + { + public override int MaxWeight { get { return 0; }} + + public SaveItemPack() : base( 0x9B2 ) + { + } + + public SaveItemPack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + private Item m_SavedItem; + private Container m_Container; + private Mobile m_WasOwnedBy; + + [CommandProperty( AccessLevel.GameMaster )] + public Container Container + { + get { return m_Container; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Item SavedItem + { + get + { + // if the item has been moved off of the internal map, then forget about it + if(m_SavedItem != null && (m_SavedItem.Parent != m_Container || m_SavedItem.Deleted)) + { + m_WasOwnedBy = null; + m_SavedItem = null; + } + + return m_SavedItem; + } + set + { + // delete any existing item before assigning a new value + if(SavedItem != null) + { + SafeItemDelete(m_SavedItem); + //m_SavedItem.Delete(); + m_SavedItem = null; + } + + // dont allow saving the item if it is attached to it + if(value != AttachedTo) + { + m_SavedItem = value; + } + + // automatically internalize any saved item + if(m_SavedItem != null) + { + AddToContainer(m_SavedItem); + + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RestoreItem + { + get{ return false; } + set + { + if(value == true && SavedItem != null && AttachedTo is IEntity && ((IEntity)AttachedTo).Map != Map.Internal && ((IEntity)AttachedTo).Map != null) + { + + // move the item to the location of the object the attachment is attached to + if(AttachedTo is Item) + { + m_SavedItem.Map = ((Item)AttachedTo).Map; + m_SavedItem.Location = ((Item)AttachedTo).Location; + m_SavedItem.Parent = ((Item)AttachedTo).Parent; + } else + if(AttachedTo is Mobile) + { + m_SavedItem.Map = ((Mobile)AttachedTo).Map; + m_SavedItem.Location = ((Mobile)AttachedTo).Location; + m_SavedItem.Parent = null; + } + + + m_SavedItem = null; + m_WasOwnedBy = null; + + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile WasOwnedBy { get{ return m_WasOwnedBy; } set { m_WasOwnedBy = value; } } + + private void AddToContainer(Item item) + { + if(item == null) return; + + if(m_Container == null) + { + m_Container = new SaveItemPack(); + } + + // need to place in a container to prevent internal map cleanup of the item + m_Container.DropItem(item); + m_Container.Internalize(); + } + + public Item GetItem() + { + Item returneditem = SavedItem; + + m_SavedItem = null; + m_WasOwnedBy = null; + + return returneditem; + } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlSaveItem(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlSaveItem() + { + m_Container = new SaveItemPack(); + } + + [Attachable] + public XmlSaveItem(string name) + { + Name = name; + } + + + public XmlSaveItem(string name, Item saveditem) + { + Name = name; + SavedItem = saveditem; + + } + + public XmlSaveItem(string name, Item saveditem, Mobile wasownedby) + { + Name = name; + SavedItem = saveditem; + WasOwnedBy = wasownedby; + } + + public override void OnDelete() + { + base.OnDelete(); + + // delete the item + if(SavedItem != null) + { + //SavedItem.Delete(); + SafeItemDelete(SavedItem); + } + + if(m_Container != null) + { + SafeItemDelete(m_Container); + //m_Container.Delete(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + if(SavedItem != null) + { + writer.Write(m_SavedItem); + } + else + { + writer.Write((Item)null); + } + writer.Write(m_WasOwnedBy); + writer.Write(m_Container); + + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_SavedItem = reader.ReadItem(); + m_WasOwnedBy = reader.ReadMobile(); + m_Container = (Container)reader.ReadItem(); + + AddToContainer(m_SavedItem); + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("{2}: Item {0} expires in {1} mins",SavedItem, Expiration.TotalMinutes, Name); + } + else + { + return String.Format("{1}: Item {0}",SavedItem, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlSkill.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlSkill.cs new file mode 100644 index 0000000..7785699 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlSkill.cs @@ -0,0 +1,202 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlSkill : XmlAttachment + { + private string m_Word = null; // not speech activated by default + private TimeSpan m_Duration = TimeSpan.FromMinutes(30.0); // 30 min default duration for effects + private int m_Value = 10; // default value of 10 + private SkillName m_Skill; + + // note that support for player identification requires modification of the identification skill (see the installation notes for details) + private bool m_Identified = false; // optional identification flag that can suppress application of the mod until identified when applied to items + + private bool m_RequireIdentification = false; // by default no identification is required for the mod to be activatable + + [CommandProperty( AccessLevel.GameMaster )] + // this property can be set allowing individual items to determine whether they must be identified for the mod to be activatable + public bool RequireIdentification { get { return m_RequireIdentification; } set {m_RequireIdentification = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get { return m_Value; } set { m_Value = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill { get { return m_Skill; } set { m_Skill = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Duration { get { return m_Duration; } set { m_Duration = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string ActivationWord { get { return m_Word; } set { m_Word = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlSkill(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlSkill(string name, string skill) + { + Name = name; + try + { + m_Skill = (SkillName)Enum.Parse( typeof( SkillName ), skill, true ); + } + catch {} + } + + [Attachable] + public XmlSkill(string name, string skill, int value) + { + Name = name; + try + { + m_Skill = (SkillName)Enum.Parse( typeof( SkillName ), skill, true ); + } + catch {} + m_Value = value; + } + + [Attachable] + public XmlSkill(string name, string skill, int value, double duration) + { + Name = name; + try + { + m_Skill = (SkillName)Enum.Parse( typeof( SkillName ), skill, true ); + } + catch {} + m_Value = value; + m_Duration = TimeSpan.FromMinutes(duration); + + } + + [Attachable] + public XmlSkill(string name, string skill, int value, double duration, string word) + { + Name = name; + try + { + m_Skill = (SkillName)Enum.Parse( typeof( SkillName ), skill, true ); + } + catch {} + m_Value = value; + m_Duration = TimeSpan.FromMinutes(duration); + m_Word = word; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_Word); + writer.Write((int)m_Skill); + writer.Write(m_Value); + writer.Write(m_Duration); + writer.Write(m_RequireIdentification); + writer.Write(m_Identified); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_Word = reader.ReadString(); + m_Skill = (SkillName) reader.ReadInt(); + m_Value = reader.ReadInt(); + m_Duration = reader.ReadTimeSpan(); + m_RequireIdentification = reader.ReadBool(); + m_Identified = reader.ReadBool(); + } + + public override string OnIdentify(Mobile from) + { + if(AttachedTo is BaseArmor || AttachedTo is BaseWeapon) + { + // can force identification before the skill mods can be applied + if(from != null && from.AccessLevel == AccessLevel.Player) + { + m_Identified = true; + } + return String.Format("activated by {0} : skill {1} mod of {2} when equipped",m_Word, m_Skill, m_Value); + } + else + { + return String.Format("activated by {0} : skill {1} mod of {2} lasting {3} mins",m_Word, m_Skill, m_Value, m_Duration.TotalMinutes); + } + } + + + public override bool HandlesOnSpeech { get { return true; } } + + public override void OnSpeech(SpeechEventArgs e ) + { + base.OnSpeech(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + // dont respond to other players speech if this is attached to a mob + if(AttachedTo is Mobile && (Mobile)AttachedTo != e.Mobile) return; + + if(e.Speech == m_Word) + { + OnTrigger(null, e.Mobile); + } + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod immediately + if(AttachedTo is Mobile && m_Word == null) + { + OnTrigger(null, (Mobile)AttachedTo); + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + //Delete(); + } + else + if(AttachedTo is Item && m_Word == null) + { + // no way to activate if it is on an item and is not speech activated so just delete it + Delete(); + } + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null || (RequireIdentification && !m_Identified)) return; + + if((AttachedTo is BaseArmor || AttachedTo is BaseWeapon) && (((Item)AttachedTo).Layer != Layer.Invalid)) + { + // when activated via speech will apply mod when equipped by the speaker + SkillMod sm = new EquipedSkillMod( m_Skill, true, m_Value, (Item)AttachedTo, m ); + m.AddSkillMod( sm ); + // and then remove the attachment + Delete(); + } + else + { + // when activated it will apply the skill mod that will last for the specified duration + SkillMod sm = new TimedSkillMod( m_Skill, true, m_Value, m_Duration ); + m.AddSkillMod( sm ); + // and then remove the attachment + Delete(); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlSound.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlSound.cs new file mode 100644 index 0000000..07ab23e --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlSound.cs @@ -0,0 +1,233 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlSound : XmlAttachment + { + private int m_SoundValue = 500; // default sound + private string m_Word = null; // no word activation by default + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int m_Charges = 0; // no charge limit + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SoundValue { get { return m_SoundValue; } set { m_SoundValue = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string ActivationWord { get { return m_Word; } set { m_Word = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges { get { return m_Charges; } set { m_Charges = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlSound(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlSound() + { + } + + [Attachable] + public XmlSound(int sound) + { + SoundValue = sound; + } + + [Attachable] + public XmlSound(int sound, double refractory) + { + SoundValue = sound; + Refractory = TimeSpan.FromSeconds(refractory); + } + + [Attachable] + public XmlSound(int sound, double refractory, string word ) + { + ActivationWord = word; + SoundValue = sound; + Refractory = TimeSpan.FromSeconds(refractory); + } + + [Attachable] + public XmlSound(int sound, double refractory, string word, int charges ) + { + ActivationWord = word; + SoundValue = sound; + Refractory = TimeSpan.FromSeconds(refractory); + Charges = charges; + } + + [Attachable] + public XmlSound(int sound, double refractory, int charges ) + { + SoundValue = sound; + Refractory = TimeSpan.FromSeconds(refractory); + Charges = charges; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_SoundValue); + writer.Write(m_Word); + writer.Write(m_Charges); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + // version 1 + proximityrange = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + SoundValue = reader.ReadInt(); + ActivationWord = reader.ReadString(); + Charges = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + string msg = null; + + if(Charges > 0) + { + msg = String.Format("Sound #{0} : {1} secs between uses - {2} charges left",SoundValue,Refractory.TotalSeconds, Charges); + } + else + { + msg = String.Format("Sound #{0} : {1} secs between uses",SoundValue,Refractory.TotalSeconds); + } + + if(ActivationWord == null) + { + return msg; + } + else + { + return String.Format("{0} : trigger on '{1}'",msg, ActivationWord); + } + + } + + public override bool HandlesOnSpeech { get { return (ActivationWord != null); } } + + public override void OnSpeech(SpeechEventArgs e ) + { + base.OnSpeech(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(e.Speech == ActivationWord) + { + OnTrigger(null, e.Mobile); + } + } + + public override bool HandlesOnMovement { get { return (ActivationWord == null); } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + if(DateTime.Now < m_EndTime) return; + + + // play a sound + if(AttachedTo is Mobile ) + { + try + { + Effects.PlaySound(((Mobile)AttachedTo).Location, ((IEntity)AttachedTo).Map, SoundValue); + } + catch{} + } + else + if(AttachedTo is Item ) + { + Item i = AttachedTo as Item; + + if(i.Parent == null) + { + try + { + Effects.PlaySound(i.Location, i.Map, SoundValue); + } + catch{} + } + else + if(i.RootParent is IEntity) + { + try + { + Effects.PlaySound(((IEntity)i.RootParent).Location, ((IEntity)i.RootParent).Map, SoundValue); + } + catch{} + } + } + + Charges--; + + // remove the attachment either after the charges run out or if refractory is zero, then it is one use only + if(Refractory == TimeSpan.Zero || Charges == 0) + { + Delete(); + } + else + { + m_EndTime = DateTime.Now + Refractory; + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlStamDrain.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlStamDrain.cs new file mode 100644 index 0000000..ff89e6b --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlStamDrain.cs @@ -0,0 +1,192 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlStamDrain : XmlAttachment + { + private int m_Drain = 0; + private TimeSpan m_Refractory = TimeSpan.FromSeconds(5); // 5 seconds default time between activations + private DateTime m_EndTime; + private int proximityrange = 5; // default movement activation from 5 tiles away + + [CommandProperty( AccessLevel.GameMaster )] + public int Drain { get{ return m_Drain; } set { m_Drain = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range { get { return proximityrange; } set { proximityrange = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlStamDrain(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlStamDrain(int drain) + { + m_Drain = drain; + } + + [Attachable] + public XmlStamDrain(int drain, double refractory) + { + m_Drain = drain; + Refractory = TimeSpan.FromSeconds(refractory); + + } + + [Attachable] + public XmlStamDrain(int drain, double refractory, double expiresin) + { + m_Drain = drain; + Expiration = TimeSpan.FromMinutes(expiresin); + Refractory = TimeSpan.FromSeconds(refractory); + } + + + // note that this method will be called when attached to either a mobile or a weapon + // when attached to a weapon, only that weapon will do additional damage + // when attached to a mobile, any weapon the mobile wields will do additional damage + public override void OnWeaponHit(Mobile attacker, Mobile defender, BaseWeapon weapon, int damageGiven) + { + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int drain = 0; + + if(m_Drain > 0) + drain = Utility.Random(m_Drain); + + if(defender != null && attacker != null && drain > 0) + { + defender.Stam -= drain; + if(defender.Stam < 0) defender.Stam = 0; + + attacker.Stam += drain; + if(attacker.Stam < 0) attacker.Stam = 0; + + m_EndTime = DateTime.Now + Refractory; + } + } + + public override bool HandlesOnMovement { get { return true; } } + + public override void OnMovement(MovementEventArgs e ) + { + base.OnMovement(e); + + if(e.Mobile == null || e.Mobile.AccessLevel > AccessLevel.Player) return; + + if(AttachedTo is Item && (((Item)AttachedTo).Parent == null) && Utility.InRange( e.Mobile.Location, ((Item)AttachedTo).Location, proximityrange )) + { + OnTrigger(null, e.Mobile); + } + else + return; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(proximityrange); + // version 0 + writer.Write(m_Drain); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + // version 1 + Range = reader.ReadInt(); + goto case 0; + case 0: + // version 0 + m_Drain = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + break; + } + } + + public override string OnIdentify(Mobile from) + { + string msg = null; + + if(Expiration > TimeSpan.Zero) + { + msg = String.Format("Stamina drain {0} expires in {1} mins", m_Drain, Expiration.TotalMinutes); + } + else + { + msg = String.Format("Stamina drain {0}",m_Drain); + } + + if(Refractory > TimeSpan.Zero) + { + return String.Format("{0} : {1} secs between uses",msg, Refractory.TotalSeconds); + } + else + return msg; + } + + public override void OnAttach() + { + base.OnAttach(); + + // announce it to the mob + if(AttachedTo is Mobile) + { + if(m_Drain > 0) + ((Mobile)AttachedTo).SendMessage("You have been granted the power of Stamina Drain!"); + else + ((Mobile)AttachedTo).SendMessage("You have been cursed with Stamina Drain!"); + } + } + + public override void OnTrigger(object activator, Mobile m) + { + if(m == null ) return; + + // if it is still refractory then return + if(DateTime.Now < m_EndTime) return; + + int drain = 0; + + if(m_Drain > 0) + drain = Utility.Random(m_Drain); + + if(drain > 0) + { + m.Stam -= drain; + if(m.Stam < 0) m.Stam = 0; + + } + + m_EndTime = DateTime.Now + Refractory; + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlStr.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlStr.cs new file mode 100644 index 0000000..fc3363f --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlStr.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlStr : XmlAttachment + { + private TimeSpan m_Duration = TimeSpan.FromSeconds(30.0); // default 30 sec duration + private int m_Value = 10; // default value of 10 + + [CommandProperty(AccessLevel.GameMaster)] + public int Value { get { return m_Value; } set { m_Value = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlStr(ASerial serial) + : base(serial) + { + } + + [Attachable] + public XmlStr() + { + } + + [Attachable] + public XmlStr(int value) + { + m_Value = value; + } + + [Attachable] + public XmlStr(int value, double duration) + { + m_Value = value; + m_Duration = TimeSpan.FromSeconds(duration); + } + + public override void OnAttach() + { + base.OnAttach(); + + // apply the mod + if (AttachedTo is Mobile) + { + ((Mobile)AttachedTo).AddStatMod(new StatMod(StatType.Str, "XmlStr" + Name, m_Value, m_Duration)); + } + // and then remove the attachment + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + + //Delete(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlUse.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlUse.cs new file mode 100644 index 0000000..a1b74cc --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlUse.cs @@ -0,0 +1,491 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlUse : XmlAttachment + { + private bool m_BlockDefaultUse; + private string m_Condition; // additional condition required for use + private string m_TargetingAction; // action performed when the target cursor is brought up + private string m_TargetCondition; // condition test applied when target is selected to determine whether it is appropriate + private string m_TargetFailureAction; // action performed if target condition is not met + private string m_SuccessAction; // action performed on successful use or targeting + private string m_FailureAction; // action performed if the player cannot use the object for reasons other than range, refractory, or maxuses + private string m_RefractoryAction; // action performed if the object is used before the refractory interval expires + private string m_MaxUsesAction; // action performed if the object is used when the maxuses are exceeded + private int m_NUses = 0; + private int m_MaxRange = 3; // must be within 3 tiles to use by default + private int m_MaxTargetRange = 30; // must be within 30 tiles to target by default + private int m_MaxUses = 0; + private TimeSpan m_Refractory = TimeSpan.Zero; + public DateTime m_EndTime; + private bool m_RequireLOS = false; + private bool m_AllowCarried = true; + private bool m_TargetingEnabled = false; + + + [CommandProperty(AccessLevel.GameMaster)] + public bool TargetingEnabled { get { return m_TargetingEnabled; } set { m_TargetingEnabled = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowCarried { get { return m_AllowCarried; } set { m_AllowCarried = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RequireLOS { get { return m_RequireLOS; } set { m_RequireLOS = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxRange { get { return m_MaxRange; } set { m_MaxRange = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxTargetRange { get { return m_MaxTargetRange; } set { m_MaxTargetRange = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int NUses { get { return m_NUses; } set { m_NUses = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxUses { get { return m_MaxUses; } set { m_MaxUses = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan Refractory { get { return m_Refractory; } set { m_Refractory = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public bool BlockDefaultUse { get { return m_BlockDefaultUse; } set { m_BlockDefaultUse = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string Condition { get { return m_Condition; } set { m_Condition = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string TargetCondition { get { return m_TargetCondition; } set { m_TargetCondition = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string TargetingAction { get { return m_TargetingAction; } set { m_TargetingAction = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string TargetFailureAction { get { return m_TargetFailureAction; } set { m_TargetFailureAction = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string SuccessAction { get { return m_SuccessAction; } set { m_SuccessAction = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string FailureAction { get { return m_FailureAction; } set { m_FailureAction = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string RefractoryAction { get { return m_RefractoryAction; } set { m_RefractoryAction = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public string MaxUsesAction { get { return m_MaxUsesAction; } set { m_MaxUsesAction = value; } } + + public XmlUse(ASerial serial) + : base(serial) + { + } + [Attachable] + public XmlUse() + { + } + + [Attachable] + public XmlUse(int maxuses) + { + MaxUses = maxuses; + } + + [Attachable] + public XmlUse(int maxuses, double refractory) + { + MaxUses = maxuses; + Refractory = TimeSpan.FromSeconds(refractory); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)3); + // version 3 + writer.Write(m_MaxTargetRange); + // version 2 + writer.Write(m_TargetingEnabled); + writer.Write(m_TargetingAction); + writer.Write(m_TargetCondition); + writer.Write(m_TargetFailureAction); + // version 1 + writer.Write(m_AllowCarried); + // version 0 + writer.Write(m_RequireLOS); + writer.Write(m_MaxRange); + writer.Write(m_Refractory); + writer.Write(m_EndTime - DateTime.Now); + writer.Write(m_MaxUses); + writer.Write(m_NUses); + writer.Write(m_BlockDefaultUse); + writer.Write(m_Condition); + writer.Write(m_SuccessAction); + writer.Write(m_FailureAction); + writer.Write(m_RefractoryAction); + writer.Write(m_MaxUsesAction); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 3: + m_MaxTargetRange = reader.ReadInt(); + goto case 2; + case 2: + m_TargetingEnabled = reader.ReadBool(); + m_TargetingAction = reader.ReadString(); + m_TargetCondition = reader.ReadString(); + m_TargetFailureAction = reader.ReadString(); + goto case 1; + case 1: + m_AllowCarried = reader.ReadBool(); + goto case 0; + case 0: + // version 0 + m_RequireLOS = reader.ReadBool(); + m_MaxRange = reader.ReadInt(); + Refractory = reader.ReadTimeSpan(); + TimeSpan remaining = reader.ReadTimeSpan(); + m_EndTime = DateTime.Now + remaining; + m_MaxUses = reader.ReadInt(); + m_NUses = reader.ReadInt(); + m_BlockDefaultUse = reader.ReadBool(); + m_Condition = reader.ReadString(); + m_SuccessAction = reader.ReadString(); + m_FailureAction = reader.ReadString(); + m_RefractoryAction = reader.ReadString(); + m_MaxUsesAction = reader.ReadString(); + break; + } + } + + public void ExecuteActions(Mobile mob, object target, string actions) + { + if (actions == null || actions.Length <= 0) return; + // execute any action associated with it + // allow for multiple action strings on a single line separated by a semicolon + + string[] args = actions.Split(';'); + + for (int j = 0; j < args.Length; j++) + { + ExecuteAction(mob, target, args[j]); + } + + } + + private void ExecuteAction(Mobile mob, object target, string action) + { + if (action == null || action.Length <= 0) return; + + string status_str = null; + Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0); + + TheSpawn.TypeName = action; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, target, mob, action); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + Point3D loc = new Point3D(0, 0, 0); + Map map = null; + + + if (target is Item) + { + Item ti = target as Item; + if (ti.Parent == null) + { + loc = ti.Location; + map = ti.Map; + } + else if (ti.RootParent is Item) + { + loc = ((Item)ti.RootParent).Location; + map = ((Item)ti.RootParent).Map; + } + else if (ti.RootParent is Mobile) + { + loc = ((Mobile)ti.RootParent).Location; + map = ((Mobile)ti.RootParent).Map; + } + + } + else if (target is Mobile) + { + Mobile ti = target as Mobile; + + loc = ti.Location; + map = ti.Map; + + } + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + BaseXmlSpawner.SpawnTypeKeyword(target, TheSpawn, typeName, substitutedtypeName, true, mob, loc, map, out status_str); + } + else + { + // its a regular type descriptor so find out what it is + Type type = SpawnerType.GetType(typeName); + try + { + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]); + + if (o == null) + { + status_str = "invalid type specification: " + arglist[0]; + } + else + if (o is Mobile) + { + Mobile m = (Mobile)o; + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + c.Home = loc; // Spawners location is the home point + } + + m.Location = loc; + m.Map = map; + + BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, mob, target, out status_str); + } + else + if (o is Item) + { + Item item = (Item)o; + BaseXmlSpawner.AddSpawnItem(null, target, TheSpawn, item, loc, map, mob, false, substitutedtypeName, out status_str); + } + } + catch { } + } + + ReportError(mob, status_str); + } + + private void ReportError(Mobile mob, string status_str) + { + if (status_str != null && mob != null && !mob.Deleted && mob is PlayerMobile && mob.AccessLevel > AccessLevel.Player) + { + mob.SendMessage(33, String.Format("{0}:{1}", Name, status_str)); + } + } + + // return true to allow use + private bool CheckCondition(Mobile from, object target) + { + // test the condition if there is one + if (Condition != null && Condition.Length > 0) + { + string status_str; + + return BaseXmlSpawner.CheckPropertyString(null, target, Condition, from, out status_str); + } + + return true; + } + + // return true to allow use + private bool CheckTargetCondition(Mobile from, object target) + { + // test the condition if there is one + if (TargetCondition != null && TargetCondition.Length > 0) + { + string status_str; + + return BaseXmlSpawner.CheckPropertyString(null, target, TargetCondition, from, out status_str); + } + + return true; + } + + // return true to allow use + private bool CheckRange(Mobile from, object target) + { + if (from == null || !(target is IEntity) || MaxRange < 0) return false; + + Map map = ((IEntity)target).Map; + Point3D loc = ((IEntity)target).Location; + + if (map != from.Map) return false; + + // check for allowed use in pack + if (target is Item) + { + Item targetitem = (Item)target; + // is it carried by the user? + if (targetitem.RootParent == from) + { + return AllowCarried; + } + else + // block use in other containers or on other mobiles + if (targetitem.Parent != null) + { + return false; + } + } + + bool haslos = true; + if (RequireLOS) + { + // check los as well + haslos = from.InLOS(target); + } + + return from.InRange(loc, MaxRange) && haslos; + } + + public bool CheckMaxUses + { + get + { + // is there a use limit? + if (MaxUses > 0 && NUses >= MaxUses) return false; + + return true; + } + } + + public bool CheckRefractory + { + get + { + // is there a refractory limit? + // if it is still refractory then return + if (Refractory > TimeSpan.Zero && DateTime.Now < m_EndTime) return false; + + return true; + } + } + + public void OutOfRange(Mobile from) + { + if (from == null) return; + + from.SendLocalizedMessage(500446); // That is too far away. + } + + public class XmlUseTarget : Target + { + private object m_objectused; + private XmlUse m_xa; + + public XmlUseTarget(int range, object objectused, XmlUse xa) + : base(range, true, TargetFlags.None) + { + m_objectused = objectused; + m_xa = xa; + CheckLOS = false; + } + protected override void OnTarget(Mobile from, object targeted) + { + if (from == null || targeted == null || m_xa == null) return; + + // success + if (m_xa.CheckTargetCondition(from, targeted)) + { + m_xa.ExecuteActions(from, targeted, m_xa.SuccessAction); + + m_xa.m_EndTime = DateTime.Now + m_xa.Refractory; + m_xa.NUses++; + } + else + { + m_xa.ExecuteActions(from, targeted, m_xa.TargetFailureAction); + } + + } + } + + private void TryToTarget(Mobile from, object target, XmlUse xa) + { + if (from == null) return; + + ExecuteActions(from, target, TargetingAction); + + if (xa != null) + { + from.Target = new XmlUseTarget(xa.MaxTargetRange, target, xa); + } + } + + private void TryToUse(Mobile from, object target) + { + if (CheckRange(from, target) && CheckCondition(from, target) && CheckMaxUses && CheckRefractory) + { + // check for targeting + if (TargetingEnabled) + { + TryToTarget(from, target, this); + } + else + { + // success + ExecuteActions(from, target, SuccessAction); + + m_EndTime = DateTime.Now + Refractory; + NUses++; + } + } + else + { + // failure + if (!CheckRange(from, target)) + { + OutOfRange(from); + } + else if (!CheckRefractory) + { + ExecuteActions(from, target, RefractoryAction); + } + else if (!CheckMaxUses) + { + ExecuteActions(from, target, MaxUsesAction); + } + + else + { + ExecuteActions(from, target, FailureAction); + } + } + } + + // disable the default use of the target + public override bool BlockDefaultOnUse(Mobile from, object target) + { + return (BlockDefaultUse || !(CheckRange(from, target) && CheckCondition(from, target) && CheckMaxUses && CheckRefractory)); + } + + // this is called when the attachment is on the user + public override void OnUser(object target) + { + Mobile from = AttachedTo as Mobile; + + TryToUse(from, target); + + } + + + // this is called when the attachment is on the target being used + public override void OnUse(Mobile from) + { + object target = AttachedTo; + + // if a target tries to use itself, then ignore it, it will be handled by OnUser + if (target == from) return; + + TryToUse(from, target); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlValue.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlValue.cs new file mode 100644 index 0000000..608b21a --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlValue.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlValue : XmlAttachment + { + private int m_DataValue; + + [CommandProperty( AccessLevel.GameMaster )] + public int Value { get{ return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlValue(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlValue(string name, int value) + { + Name = name; + Value = value; + } + + [Attachable] + public XmlValue(string name, int value, double expiresin) + { + Name = name; + Value = value; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadInt(); + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("{2}: Value {0} expires in {1} mins",Value,Expiration.TotalMinutes, Name); + } + else + { + return String.Format("{1}: Value {0}",Value, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlAttachments/XmlWeaponAbility.cs b/Scripts/Customs/XML Spawner/XmlAttachments/XmlWeaponAbility.cs new file mode 100644 index 0000000..55f3315 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlAttachments/XmlWeaponAbility.cs @@ -0,0 +1,119 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Reflection; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlWeaponAbility : XmlAttachment + { + private WeaponAbility m_Ability = null; // default data + + public WeaponAbility WeaponAbility + { + get { return m_Ability; } + set { m_Ability = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Ability + { + get + { + if (m_Ability != null) + { + return m_Ability.GetType().Name; + } + else + { + return null; + } + } + set + { + if (value != null) + { + FieldInfo finfo = typeof(WeaponAbility).GetField(value); + if (finfo != null && finfo.IsStatic && finfo.FieldType == typeof(WeaponAbility)) + { + try + { + m_Ability = (WeaponAbility)finfo.GetValue(null); + } + catch { } + } + } + else + { + m_Ability = null; + } + } + } + + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlWeaponAbility(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlWeaponAbility(string weaponability) + { + Ability = weaponability; + } + + [Attachable] + public XmlWeaponAbility(string name, string weaponability) + { + Name = name; + Ability = weaponability; + } + + [Attachable] + public XmlWeaponAbility(string name, string weaponability, double expiresin) + { + Name = name; + Ability = weaponability; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(Ability); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + Ability = reader.ReadString(); + } + + public override string OnIdentify(Mobile from) + { + if(from == null || from.AccessLevel == AccessLevel.Player) return null; + + if(Expiration > TimeSpan.Zero) + { + return String.Format("{2}: Weapon ability {0} expires in {1} mins", Ability, Expiration.TotalMinutes, Name); + } + else + { + return String.Format("{1}: Weapon ability {0}", Ability, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/QuestHolder.cs b/Scripts/Customs/XML Spawner/XmlItems/QuestHolder.cs new file mode 100644 index 0000000..fb1c594 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/QuestHolder.cs @@ -0,0 +1,64 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +/* +** QuestNote +** ArteGordon +** +*/ +namespace Server.Items +{ + public class QuestHolder : XmlQuestHolder + { + + [Constructable] + public QuestHolder() + : base() + { + Name = "A quest"; + TitleString = "A quest"; + } + + public QuestHolder(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + + public override void OnDoubleClick(Mobile from) + { + base.OnDoubleClick(from); + from.CloseGump(typeof(XmlQuestStatusGump)); + + from.SendGump(new XmlQuestStatusGump(this, this.TitleString)); + } + + public override void OnSnoop(Mobile from) + { + if (from.AccessLevel > AccessLevel.Player) + { + from.CloseGump(typeof(XmlQuestStatusGump)); + + from.SendGump(new XmlQuestStatusGump(this, this.TitleString)); + } + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/QuestNote.cs b/Scripts/Customs/XML Spawner/XmlItems/QuestNote.cs new file mode 100644 index 0000000..0657de3 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/QuestNote.cs @@ -0,0 +1,252 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +/* +** QuestNote +** ArteGordon +** +** Version 1.02 +** updated 9/14/04 +** - changed the QuestNote to open the status gump directly, and removed the serialized properties related to the scroll gump +** - added the OriginalQuestNote that has the scroll gump and behaves like the old QuestNote +** +** Version 1.01 +** updated 3/25/04 +** - Moved the TitleString and NoteString properties from the QuestNote class to the XmlQuestToken class. +** +** Version 1.0 +** updated 1/07/04 +** adds a item that displays text messages in a scroll gump and maintains quest state information. The size can be varied and the note text and text-color can be specified. +** The title of the note and its color can also be set. +*/ +namespace Server.Items +{ + public class QuestNote : XmlQuestToken + { + + [Constructable] + public QuestNote() : base( 0x14EE ) + { + Name = "A quest note"; + TitleString = "A quest note"; + } + + public QuestNote( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + // Version 2 has no serialized variables + + // Version 0 + //writer.Write( this.m_NoteString ); // moved to the XmlQuestToken class in version 1 + //writer.Write( this.m_TitleString ); // moved to the XmlQuestToken class in version 1 + // Version 1 + //writer.Write( this.m_TextColor ); // no longer used + //writer.Write( this.m_TitleColor ); // no longer used + //writer.Write( this.m_size ); // no longer used + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + reader.ReadInt(); + reader.ReadInt(); + reader.ReadInt(); + //this.m_TextColor = reader.ReadInt(); + //this.m_TitleColor = reader.ReadInt(); + //this.m_size = reader.ReadInt(); + } + break; + case 0: + { + reader.ReadString(); + reader.ReadString(); + reader.ReadInt(); + reader.ReadInt(); + reader.ReadInt(); + //this.NoteString = reader.ReadString(); + //this.TitleString = reader.ReadString(); + //this.m_TextColor = reader.ReadInt(); + //this.m_TitleColor = reader.ReadInt(); + //this.m_size = reader.ReadInt(); + } + break; + } + } + + public override void OnDoubleClick( Mobile from ) + { + base.OnDoubleClick(from); + from.CloseGump( typeof( XmlQuestStatusGump ) ); + + from.SendGump( new XmlQuestStatusGump(this, this.TitleString) ); + } + } + + + public class OriginalQuestNote : XmlQuestToken + { + private int m_size = 1; + + private int m_TextColor = 0x3e8; + private int m_TitleColor = 0xef0000; // cyan 0xf70000, black 0x3e8, brown 0xef0000 darkblue 0x7fff + + [Constructable] + public OriginalQuestNote() : base( 0x14EE ) + { + Name = "A quest note"; + TitleString = "A quest note"; + } + + public OriginalQuestNote( Serial serial ) : base( serial ) + { + } + + + [CommandProperty( AccessLevel.GameMaster )] + public int Size + { + get{ return m_size; } + set + { + m_size = value; + if(m_size < 1) m_size = 1; + //InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TextColor + { + get{ return m_TextColor; } + set + { + m_TextColor = value; + //InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TitleColor + { + get{ return m_TitleColor; } + set + { + m_TitleColor = value; + //InvalidateProperties(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + // Version 1 + writer.Write( this.m_TextColor ); + writer.Write( this.m_TitleColor ); + writer.Write( this.m_size ); + // Version 0 + //writer.Write( this.m_NoteString ); // moved to the XmlQuestToken class in version 1 + //writer.Write( this.m_TitleString ); // moved to the XmlQuestToken class in version 1 + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 1: + { + this.m_TextColor = reader.ReadInt(); + this.m_TitleColor = reader.ReadInt(); + this.m_size = reader.ReadInt(); + } + break; + case 0: + { + this.NoteString = reader.ReadString(); + this.TitleString = reader.ReadString(); + this.m_TextColor = reader.ReadInt(); + this.m_TitleColor = reader.ReadInt(); + this.m_size = reader.ReadInt(); + } + break; + } + } + + public override void OnDoubleClick( Mobile from ) + { + base.OnDoubleClick(from); + from.CloseGump( typeof( QuestNoteGump ) ); + from.SendGump( new QuestNoteGump( this ) ); + } + } + + public class QuestNoteGump : Gump + { + private OriginalQuestNote m_Note; + + public static string HtmlFormat( string text, int color ) + { + return String.Format( "{1}", color, text); + } + + public QuestNoteGump( OriginalQuestNote note ) : base( 0, 0 ) + { + m_Note = note; + + AddPage( 0 ); + AddAlphaRegion( 40, 41, 225, /*371*/70*note.Size ); + // scroll top + AddImageTiled( 3, 5, 300, 37, 0x820 ); + // scroll middle, upper portion + AddImageTiled( 19, 41, 263, 70, 0x821 ); + for(int i=1;i 0 && CurrentPin <=Pins.Count) + { + int mapx, mapy; + ConvertToMap(value.X, value.Y, out mapx, out mapy); + Pins[CurrentPin -1] = new Point2D(mapx, mapy); + } + } + get + { + // get the coordinates of the current pin + if(Pins != null && CurrentPin > 0 && CurrentPin <=Pins.Count) + { + int mapx, mapy; + ConvertToWorld(((Point2D)Pins[CurrentPin -1]).X, ((Point2D)Pins[CurrentPin -1]).Y, out mapx, out mapy); + return new Point2D(mapx, mapy); + } + else + { + return Point2D.Zero; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point2D NewPin + { + set + { + // add a new pin at the specified world coordinate + AddWorldPin(value.X, value.Y); + CurrentPin = NPins; + } + get + { + // return the last pin added to the Pins arraylist + if(Pins != null && NPins > 0) + { + int mapx, mapy; + ConvertToWorld(((Point2D)Pins[NPins -1]).X, ((Point2D)Pins[NPins -1]).Y, out mapx, out mapy); + return new Point2D(mapx, mapy); + } + else + { + return Point2D.Zero; + } + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public bool ClearAllPins + { + get { return false; } + set { if(value == true) ClearPins(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PinRemove + { + set { RemovePin(value); } + get { return 0; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile ShowTo + { + set + { + if(value != null) + { + //DisplayTo(value); + OnDoubleClick(value); + } + } + get { return null; } + } + + + [Constructable] + public SimpleMap() + { + SetDisplay( 0, 0, 5119, 4095, 400, 400 ); + } + + public override int LabelNumber{ get{ return 1025355; } } // map + + public SimpleMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/XmlItems/SimpleNote.cs b/Scripts/Customs/XML Spawner/XmlItems/SimpleNote.cs new file mode 100644 index 0000000..a271643 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/SimpleNote.cs @@ -0,0 +1,143 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +/* +** SimpleNote +** updated 1/3/04 +** ArteGordon +** adds a simple item that displays text messages in a scroll gump. The size can be varied and the note text and text-color can be specified. +** The title of the note and its color can also be set. +*/ +namespace Server.Items +{ + public class SimpleNote : Item + { + private int m_size = 1; + private string m_NoteString; + private string m_TitleString; + private int m_TextColor = 0x3e8; + private int m_TitleColor = 0xef0000; // cyan 0xf70000, black 0x3e8, brown 0xef0000 darkblue 0x7fff + + [Constructable] + public SimpleNote() : base( 0x14EE ) + { + Name = "A note"; + TitleString = "A note"; + } + + public SimpleNote( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public string NoteString + { + get{ return m_NoteString; } + set { m_NoteString = value; InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public string TitleString + { + get{ return m_TitleString; } + set { m_TitleString = value; InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Size + { + get{ return m_size; } + set + { + m_size = value; + if(m_size < 1) m_size = 1; + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TextColor + { + get{ return m_TextColor; } + set { m_TextColor = value; InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TitleColor + { + get{ return m_TitleColor; } + set { m_TitleColor = value; InvalidateProperties();} + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( this.m_NoteString ); + writer.Write( this.m_TitleString ); + writer.Write( this.m_TextColor ); + writer.Write( this.m_TitleColor ); + writer.Write( this.m_size ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 0: + { + this.m_NoteString = reader.ReadString(); + this.m_TitleString = reader.ReadString(); + this.m_TextColor = reader.ReadInt(); + this.m_TitleColor = reader.ReadInt(); + this.m_size = reader.ReadInt(); + } + break; + } + } + + public override void OnDoubleClick( Mobile from ) + { + SimpleNoteGump g = new SimpleNoteGump( this ); + from.SendGump( g ); + } + } + + public class SimpleNoteGump : Gump + { + private SimpleNote m_Note; + + public static string HtmlFormat( string text, int color ) + { + return String.Format( "{1}", color, text); + } + + public SimpleNoteGump( SimpleNote note ) : base( 0, 0 ) + { + m_Note = note; + + AddPage( 0 ); + AddAlphaRegion( 40, 41, 225, /*371*/70*note.Size ); + // scroll top + AddImageTiled( 3, 5, 300, 37, 0x820 ); + // scroll middle, upper portion + AddImageTiled( 19, 41, 263, 70, 0x821 ); + for(int i=1;i 1 && m_LeverType == leverType.Two_State) m_LeverState = 1; + if (m_LeverState > 2) m_LeverState = 2; + + // update the graphic + SetLeverStatic(); + + // play the switching sound if possible + //if (from != null) + //{ + // from.PlaySound(m_LeverSound); + //} + try + { + Effects.PlaySound(Location, Map, m_LeverSound); + } + catch { } + + // if a target object has been specified then apply the property modification + if (m_LeverState == 0 && m_TargetItem0 != null && !m_TargetItem0.Deleted && m_TargetProperty0 != null && m_TargetProperty0.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, from, this, out status_str); + } + if (m_LeverState == 1 && m_TargetItem1 != null && !m_TargetItem1.Deleted && m_TargetProperty1 != null && m_TargetProperty1.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, from, this, out status_str); + } + if (m_LeverState == 2 && m_TargetItem2 != null && !m_TargetItem2.Deleted && m_TargetProperty2 != null && m_TargetProperty2.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty2, m_TargetItem2, from, this, out status_str); + } + + // if the switch is linked, then activate the link as well + if (Link != null && Link is ILinkable) + { + if (links == null) + { + links = new ArrayList(); + } + // activate other linked objects if they have not already been activated + if (!links.Contains(this)) + { + links.Add(this); + + ((ILinkable)Link).Activate(from, state, links); + } + } + + // report any problems to staff + if (status_str != null && from != null && from.AccessLevel > AccessLevel.Player) + { + from.SendMessage("{0}", status_str); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null || Disabled) return; + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } + + // change the switch state + m_LeverState = m_LeverState + 1; + + if (m_LeverState > 1 && m_LeverType == leverType.Two_State) m_LeverState = 0; + if (m_LeverState > 2) m_LeverState = 0; + + // carry out the switch actions + Activate(from, m_LeverState, null); + + } + } + + public class SimpleSwitch : Item, ILinkable + { + private int m_SwitchState = 0; + private int m_SwitchSound = 939; + private Item m_TargetItem0 = null; + private string m_TargetProperty0 = null; + private Item m_TargetItem1 = null; + private string m_TargetProperty1 = null; + + private Item m_LinkedItem = null; + private bool already_being_activated = false; + + private bool m_Disabled = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Disabled + { + set { m_Disabled = value; } + get { return m_Disabled; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Link + { + set { m_LinkedItem = value; } + get { return m_LinkedItem; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SwitchState + { + set + { + // prevent infinite recursion + if (!already_being_activated) + { + already_being_activated = true; + Activate(null, value, null); + already_being_activated = false; + } + + InvalidateProperties(); + } + get { return m_SwitchState; } + } + + [Constructable] + public SimpleSwitch() + : base(0x108F) + { + Name = "A switch"; + Movable = false; + } + + public SimpleSwitch(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SwitchSound + { + get { return m_SwitchSound; } + set + { + m_SwitchSound = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + new public virtual Direction Direction + { + get { return base.Direction; } + set + { + base.Direction = value; + SetSwitchStatic(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Target0Item + { + get { return m_TargetItem0; } + set + { + m_TargetItem0 = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Target0Property + { + get { return m_TargetProperty0; } + set + { + m_TargetProperty0 = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Target0ItemName + { + get + { + if (m_TargetItem0 != null && !m_TargetItem0.Deleted) + return m_TargetItem0.Name; + else + return null; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Target1Item + { + get { return m_TargetItem1; } + set { m_TargetItem1 = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Target1Property + { + get { return m_TargetProperty1; } + set + { + m_TargetProperty1 = value; + InvalidateProperties(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Target1ItemName + { + get + { + if (m_TargetItem1 != null && !m_TargetItem1.Deleted) + return m_TargetItem1.Name; + else + return null; + } + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)2); // version + // version 2 + writer.Write(this.m_Disabled); + // version 1 + writer.Write(this.m_LinkedItem); + // version 0 + writer.Write(this.m_SwitchState); + writer.Write(this.m_SwitchSound); + writer.Write(this.m_TargetItem0); + writer.Write(this.m_TargetProperty0); + writer.Write(this.m_TargetItem1); + writer.Write(this.m_TargetProperty1); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 2: + { + m_Disabled = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_LinkedItem = reader.ReadItem(); + goto case 0; + } + case 0: + { + this.m_SwitchState = reader.ReadInt(); + this.m_SwitchSound = reader.ReadInt(); + this.m_TargetItem0 = reader.ReadItem(); + this.m_TargetProperty0 = reader.ReadString(); + this.m_TargetItem1 = reader.ReadItem(); + this.m_TargetProperty1 = reader.ReadString(); + } + break; + } + } + + public void SetSwitchStatic() + { + + switch (this.Direction) + { + case Direction.North: + case Direction.South: + case Direction.Right: + case Direction.Up: + this.ItemID = 0x108f + m_SwitchState; + break; + case Direction.East: + case Direction.West: + case Direction.Left: + case Direction.Down: + this.ItemID = 0x1091 + m_SwitchState; + break; + default: + this.ItemID = 0x108f + m_SwitchState; + break; + } + } + + public void Activate(Mobile from, int state, ArrayList links) + { + if (Disabled) return; + + string status_str = null; + + // assign the switch state + m_SwitchState = state; + + if (m_SwitchState < 0) m_SwitchState = 0; + if (m_SwitchState > 1) m_SwitchState = 1; + + // update the graphic + SetSwitchStatic(); + + //if (from != null) + //{ + // from.PlaySound(m_SwitchSound); + //} + try + { + Effects.PlaySound(Location, Map, m_SwitchSound); + } + catch { } + + // if a target object has been specified then apply the property modification + if (m_SwitchState == 0 && m_TargetItem0 != null && !m_TargetItem0.Deleted && m_TargetProperty0 != null && m_TargetProperty0.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, from, this, out status_str); + } + + if (m_SwitchState == 1 && m_TargetItem1 != null && !m_TargetItem1.Deleted && m_TargetProperty1 != null && m_TargetProperty1.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, from, this, out status_str); + } + + // if the switch is linked, then activate the link as well + if (Link != null && Link is ILinkable) + { + if (links == null) + { + links = new ArrayList(); + } + // activate other linked objects if they have not already been activated + if (!links.Contains(this)) + { + links.Add(this); + + ((ILinkable)Link).Activate(from, state, links); + } + } + + // report any problems to staff + if (status_str != null && from != null && from.AccessLevel > AccessLevel.Player) + { + from.SendMessage("{0}", status_str); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null || Disabled) return; + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } + + // change the switch state + m_SwitchState = m_SwitchState + 1; + + if (m_SwitchState > 1) m_SwitchState = 0; + + // activate the switch + Activate(from, m_SwitchState, null); + } + } + + public class CombinationLock : Item + { + private int m_Combination = 0; + private Item m_Digit0Object = null; + private string m_Digit0Property = null; + private Item m_Digit1Object = null; + private string m_Digit1Property = null; + private Item m_Digit2Object = null; + private string m_Digit2Property = null; + private Item m_Digit3Object = null; + private string m_Digit3Property = null; + private Item m_Digit4Object = null; + private string m_Digit4Property = null; + private Item m_Digit5Object = null; + private string m_Digit5Property = null; + private Item m_Digit6Object = null; + private string m_Digit6Property = null; + private Item m_Digit7Object = null; + private string m_Digit7Property = null; + private Item m_TargetItem = null; + private string m_TargetProperty = null; + private int m_CombinationSound = 940; + + [Constructable] + public CombinationLock() + : base(0x1BBF) + { + Name = "A combination lock"; + Movable = false; + } + + public CombinationLock(Serial serial) + : base(serial) + { + } + + public int SetDigit(int value) + { + if (value < 0) return 0; + if (value > 9) return 9; + return value; + } + + public int CheckDigit(object o, string property) + { + if (o == null) return 0; + if (property == null || property.Length <= 0) return (0); + Type ptype; + int ival = -1; + string testvalue; + // check to see whether this is a direct value request, or a test + string[] argtest = BaseXmlSpawner.ParseString(property, 2, "<>!="); + if (argtest.Length > 1) + { + // ok, its a test, so test it + string status_str; + if (BaseXmlSpawner.CheckPropertyString(null, o, property, null, out status_str)) + { + return 1; // true + } + else + return 0; // false + } + // otherwise get the value of the property requested + string result = BaseXmlSpawner.GetPropertyValue(null, o, property, out ptype); + + string[] arglist = BaseXmlSpawner.ParseString(result, 2, "="); + if (arglist.Length < 2) return -1; + string[] arglist2 = BaseXmlSpawner.ParseString(arglist[1], 2, " "); + if (arglist2.Length > 0) + { + testvalue = arglist2[0].Trim(); + } + else + { + return -1; + } + + if (BaseXmlSpawner.IsNumeric(ptype)) + { + try + { + ival = Convert.ToInt32(testvalue, 10); + } + catch { } + } + return ival; + } + + + + [CommandProperty(AccessLevel.GameMaster)] + public int Combination + { + get { return m_Combination; } + set + { + m_Combination = value; + if (m_Combination < 0) m_Combination = 0; + if (m_Combination > 99999999) m_Combination = 99999999; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit0Object + { + get { return m_Digit0Object; } + set { m_Digit0Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit0Property + { + get { return m_Digit0Property; } + set { m_Digit0Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit0 + { get { return (CheckDigit(m_Digit0Object, m_Digit0Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit1Object + { + get { return m_Digit1Object; } + set { m_Digit1Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit1Property + { + get { return m_Digit1Property; } + set { m_Digit1Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit1 + { get { return (CheckDigit(m_Digit1Object, m_Digit1Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit2Object + { + get { return m_Digit2Object; } + set { m_Digit2Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit2Property + { + get { return m_Digit2Property; } + set { m_Digit2Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit2 + { get { return (CheckDigit(m_Digit2Object, m_Digit2Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit3Object + { + get { return m_Digit3Object; } + set { m_Digit3Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit3Property + { + get { return m_Digit3Property; } + set { m_Digit3Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit3 + { get { return (CheckDigit(m_Digit3Object, m_Digit3Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit4Object + { + get { return m_Digit4Object; } + set { m_Digit4Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit4Property + { + get { return m_Digit4Property; } + set { m_Digit4Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit4 + { get { return (CheckDigit(m_Digit4Object, m_Digit4Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit5Object + { + get { return m_Digit5Object; } + set { m_Digit5Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit5Property + { + get { return m_Digit5Property; } + set { m_Digit5Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit5 + { get { return (CheckDigit(m_Digit5Object, m_Digit5Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit6Object + { + get { return m_Digit6Object; } + set { m_Digit6Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit6Property + { + get { return m_Digit6Property; } + set { m_Digit6Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit6 + { get { return (CheckDigit(m_Digit6Object, m_Digit6Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Digit7Object + { + get { return m_Digit7Object; } + set { m_Digit7Object = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Digit7Property + { + get { return m_Digit7Property; } + set { m_Digit7Property = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int Digit7 + { get { return (CheckDigit(m_Digit7Object, m_Digit7Property)); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Item TargetItem + { + get { return m_TargetItem; } + set { m_TargetItem = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string TargetProperty + { + get { return m_TargetProperty; } + set { m_TargetProperty = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public string TargetItemName + { get { if (m_TargetItem != null && !m_TargetItem.Deleted) return m_TargetItem.Name; else return null; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int CombinationSound + { + get { return m_CombinationSound; } + set + { + m_CombinationSound = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Matched + { + get { return (m_Combination == CurrentValue); } + } + [CommandProperty(AccessLevel.GameMaster)] + + public int CurrentValue + { + get + { + int value = Digit0 + Digit1 * 10 + Digit2 * 100 + Digit3 * 1000 + Digit4 * 10000 + Digit5 * 100000 + Digit6 * 1000000 + Digit7 * 10000000; + return value; + } + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(this.m_Combination); + writer.Write(this.m_CombinationSound); + writer.Write(this.m_Digit0Object); + writer.Write(this.m_Digit0Property); + writer.Write(this.m_Digit1Object); + writer.Write(this.m_Digit1Property); + writer.Write(this.m_Digit2Object); + writer.Write(this.m_Digit2Property); + writer.Write(this.m_Digit3Object); + writer.Write(this.m_Digit3Property); + writer.Write(this.m_Digit4Object); + writer.Write(this.m_Digit4Property); + writer.Write(this.m_Digit5Object); + writer.Write(this.m_Digit5Property); + writer.Write(this.m_Digit6Object); + writer.Write(this.m_Digit6Property); + writer.Write(this.m_Digit7Object); + writer.Write(this.m_Digit7Property); + writer.Write(this.m_TargetItem); + writer.Write(this.m_TargetProperty); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 0: + { + this.m_Combination = reader.ReadInt(); + this.m_CombinationSound = reader.ReadInt(); + this.m_Digit0Object = reader.ReadItem(); + this.m_Digit0Property = reader.ReadString(); + this.m_Digit1Object = reader.ReadItem(); + this.m_Digit1Property = reader.ReadString(); + this.m_Digit2Object = reader.ReadItem(); + this.m_Digit2Property = reader.ReadString(); + this.m_Digit3Object = reader.ReadItem(); + this.m_Digit3Property = reader.ReadString(); + this.m_Digit4Object = reader.ReadItem(); + this.m_Digit4Property = reader.ReadString(); + this.m_Digit5Object = reader.ReadItem(); + this.m_Digit5Property = reader.ReadString(); + this.m_Digit6Object = reader.ReadItem(); + this.m_Digit6Property = reader.ReadString(); + this.m_Digit7Object = reader.ReadItem(); + this.m_Digit7Property = reader.ReadString(); + this.m_TargetItem = reader.ReadItem(); + this.m_TargetProperty = reader.ReadString(); + + } + break; + } + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null) return; + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } + string status_str; + // test the combination and apply the property to the target item + if (Matched) + { + //from.PlaySound(m_CombinationSound); + try + { + Effects.PlaySound(Location, Map, m_CombinationSound); + } + catch { } + + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty, m_TargetItem, from, this, out status_str); + + } + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/SimpleTileTrap.cs b/Scripts/Customs/XML Spawner/XmlItems/SimpleTileTrap.cs new file mode 100644 index 0000000..283062c --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/SimpleTileTrap.cs @@ -0,0 +1,167 @@ +using System; +using Server; +using Server.Mobiles; + + /* + SimpleTileTrap + Written by Alari + + based off SimpleSwitch. (did a search and replace on simpleswitch->simpletiletrap + and then modified the code as appropriate.) + +For this tile trap, 0 is the state when the player moves off or is not standing, and 1 is what is triggered when the player moves directly over the tile trap. + */ + + +namespace Server.Items +{ + + public class SimpleTileTrap : Item + { + + private int m_SwitchSound = 939; + private Item m_TargetItem0 = null; + private string m_TargetProperty0 = null; + private Item m_TargetItem1 = null; + private string m_TargetProperty1 = null; + + [Constructable] + public SimpleTileTrap() : base( 7107 ) + { + Name = "A tile trap"; + Movable = false; + Visible = false; + } + + public SimpleTileTrap( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SwitchSound + { + get{ return m_SwitchSound; } + set + { + m_SwitchSound = value; + InvalidateProperties(); + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target0Item + { + get{ return m_TargetItem0; } + set { m_TargetItem0 = value;InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Target0Property + { + get{ return m_TargetProperty0; } + set { m_TargetProperty0 = value;InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Target0ItemName + { get{ if(m_TargetItem0 != null && !m_TargetItem0.Deleted) return m_TargetItem0.Name; else return null;} } + + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target1Item + { + get{ return m_TargetItem1; } + set { m_TargetItem1 = value;InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Target1Property + { + get{ return m_TargetProperty1; } + set { m_TargetProperty1 = value;InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Target1ItemName + { get{ if(m_TargetItem1 != null && !m_TargetItem1.Deleted) return m_TargetItem1.Name; else return null;} } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( this.m_SwitchSound ); + writer.Write( this.m_TargetItem0 ); + writer.Write( this.m_TargetProperty0 ); + writer.Write( this.m_TargetItem1 ); + writer.Write( this.m_TargetProperty1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 0: + { + + this.m_SwitchSound = reader.ReadInt(); + this.m_TargetItem0 = reader.ReadItem(); + this.m_TargetProperty0 = reader.ReadString(); + this.m_TargetItem1 = reader.ReadItem(); + this.m_TargetProperty1 = reader.ReadString(); + } + break; + } + } + + public bool CheckRange( Point3D loc, Point3D oldLoc, int range ) + { + return CheckRange( loc, range ) && !CheckRange( oldLoc, range ); + } + + public bool CheckRange( Point3D loc, int range ) + { + return ( (this.Z + 8) >= loc.Z && (loc.Z + 16) > this.Z ) + && Utility.InRange( GetWorldLocation(), loc, range ); + } + + + public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m.Location == oldLocation ) + return; + + + if( ( m.Player && m.AccessLevel == AccessLevel.Player ) ) + { + if ( CheckRange( m.Location, oldLocation, 0 ) ) + OnEnter( m ); + else if ( oldLocation == this.Location ) + OnExit( m ); + } + } + + public virtual void OnEnter( Mobile m ) + { + string status_str; + m.PlaySound(SwitchSound); + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, m, this, out status_str); + } + + public virtual void OnExit( Mobile m ) + { + string status_str; + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, m, this, out status_str); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/SingleUseSwitch.cs b/Scripts/Customs/XML Spawner/XmlItems/SingleUseSwitch.cs new file mode 100644 index 0000000..ddcb668 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/SingleUseSwitch.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SingleUseSwitch : SimpleSwitch + { + + [Constructable] + public SingleUseSwitch() + { + } + + public SingleUseSwitch(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null || Disabled) return; + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } + + base.OnDoubleClick(from); + + // delete after use + Delete(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/TimedSwitches.cs b/Scripts/Customs/XML Spawner/XmlItems/TimedSwitches.cs new file mode 100644 index 0000000..011cf40 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/TimedSwitches.cs @@ -0,0 +1,1094 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; + +/* +** TimedLever, TimedSwitch, and XmlLatch class and TimedSwitchableItem +** Version 1.01 +** updated 5/06/04 +** ArteGordon +*/ +namespace Server.Items +{ + + public class XmlLatch : Item + { + + private TimeSpan m_MinDelay; + private TimeSpan m_MaxDelay; + private DateTime m_End; + private InternalTimer m_Timer; + private int m_State = 0; + private int m_ResetState = 0; + + + + [Constructable] + public XmlLatch() : base( 0x1BBF ) + { + Movable = false; + } + + public XmlLatch(int itemID) : base( itemID ) + { + } + + public XmlLatch( Serial serial ) : base( serial ) + { + } + + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan MinDelay + { + get { return m_MinDelay; } + set + { + m_MinDelay = value; + InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan MaxDelay + { + get { return m_MaxDelay; } + set + { + m_MaxDelay = value; + InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan TimeUntilReset + { + get + { + if ( m_Timer != null && m_Timer.Running ) + return m_End - DateTime.Now; + else + return TimeSpan.FromSeconds( 0 ); + } + set + { + DoTimer( value ); + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int ResetState + { + get{ return m_ResetState; } + set + { + m_ResetState = value; + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int State + { + get{ return m_State; } + set + { + m_State = value; + StartTimer(); + InvalidateProperties();} + } + + public void StartTimer() + { + if(m_State != m_ResetState && (m_MinDelay > TimeSpan.Zero || m_MaxDelay > TimeSpan.Zero)) + DoTimer(); + else + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + public virtual void OnReset() + { + State = ResetState; + } + + + public void DoTimer() + { + + int minSeconds = (int)m_MinDelay.TotalSeconds; + int maxSeconds = (int)m_MaxDelay.TotalSeconds; + + TimeSpan delay = TimeSpan.FromSeconds( Utility.RandomMinMax( minSeconds, maxSeconds ) ); + DoTimer( delay ); + } + + public void DoTimer( TimeSpan delay ) + { + + + m_End = DateTime.Now + delay; + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = new InternalTimer( this, delay ); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + private XmlLatch m_latch; + + public InternalTimer( XmlLatch xmllatch, TimeSpan delay ) : base( delay ) + { + Priority = TimerPriority.OneSecond; + m_latch = xmllatch; + } + + protected override void OnTick() + { + if(m_latch != null && !m_latch.Deleted) + { + Stop(); + m_latch.OnReset(); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + // version 0 + writer.Write( this.m_State ); + writer.Write( this.m_ResetState ); + writer.Write( this.m_MinDelay ); + writer.Write( this.m_MaxDelay ); + bool running = (m_Timer != null && m_Timer.Running); + writer.Write( running ); + if ( m_Timer != null && m_Timer.Running ) + writer.Write( this.m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 0: + { + // note this is redundant with the base class serialization, but it is there for older (pre 1.02) version compatibility + // not needed + this.m_State = reader.ReadInt(); + this.m_ResetState = reader.ReadInt(); + this.m_MinDelay = reader.ReadTimeSpan(); + this.m_MaxDelay = reader.ReadTimeSpan(); + bool running = reader.ReadBool(); + if(running) + { + TimeSpan delay = reader.ReadTimeSpan(); + this.DoTimer( delay ); + } + } + break; + } + } + + } + + public class TimedLever : XmlLatch, ILinkable + { + public enum leverType { Two_State, Three_State} + private leverType m_LeverType = leverType.Two_State; + private int m_LeverSound = 936; + private Item m_TargetItem0 = null; + private string m_TargetProperty0 = null; + private Item m_TargetItem1 = null; + private string m_TargetProperty1 = null; + private Item m_TargetItem2 = null; + private string m_TargetProperty2 = null; + + private Item m_LinkedItem = null; + private bool already_being_activated = false; + + private bool m_Disabled = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Disabled + { + set { m_Disabled = value; } + get { return m_Disabled; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Link + { + set { m_LinkedItem = value; } + get { return m_LinkedItem; } + } + + [Constructable] + public TimedLever() : base( 0x108C ) + { + Name = "A lever"; + Movable = false; + } + + public TimedLever( Serial serial ) : base( serial ) + { + } + + + [CommandProperty(AccessLevel.GameMaster)] + public override int State + { + get { return base.State; } + set + { + // prevent infinite recursion + if (!already_being_activated) + { + already_being_activated = true; + Activate(null, value, null); + already_being_activated = false; + } + + InvalidateProperties(); + } + } + + public void Activate(Mobile from, int state, ArrayList links) + { + if (Disabled) return; + + string status_str = null; + + if (state < 0) state = 0; + if (state > 1 && m_LeverType == leverType.Two_State) state = 1; + if (state > 2) state = 2; + + // assign the latch state and start the timer + base.State = state; + + // update the graphic + SetLeverStatic(); + + // play the switching sound + //if (from != null) + //{ + // from.PlaySound(m_LeverSound); + //} + try + { + Effects.PlaySound(Location, Map, m_LeverSound); + } + catch { } + + // if a target object has been specified then apply the property modification + if (state == 0 && m_TargetItem0 != null && !m_TargetItem0.Deleted && m_TargetProperty0 != null && m_TargetProperty0.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, null, this, out status_str); + } + if (state == 1 && m_TargetItem1 != null && !m_TargetItem1.Deleted && m_TargetProperty1 != null && m_TargetProperty1.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, null, this, out status_str); + } + if (state == 2 && m_TargetItem2 != null && !m_TargetItem2.Deleted && m_TargetProperty2 != null && m_TargetProperty2.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty2, m_TargetItem2, null, this, out status_str); + } + + // if the switch is linked, then activate the link as well + if (Link != null && Link is ILinkable) + { + if (links == null) + { + links = new ArrayList(); + } + // activate other linked objects if they have not already been activated + if (!links.Contains(this)) + { + links.Add(this); + + ((ILinkable)Link).Activate(from, state, links); + } + } + + // report any problems to staff + if (status_str != null && from != null && from.AccessLevel > AccessLevel.Player) + { + from.SendMessage("{0}", status_str); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int LeverSound + { + get{ return m_LeverSound; } + set + { + m_LeverSound = value; + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public leverType LeverType + { + get{ return m_LeverType; } + set + { + m_LeverType = value; State = 0; + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + new public virtual Direction Direction + { + get{ return base.Direction; } + set { base.Direction = value; SetLeverStatic();InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target0Item + { + get{ return m_TargetItem0; } + set { m_TargetItem0 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target0Property + { + get{ return m_TargetProperty0; } + set { m_TargetProperty0 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target0ItemName + { get{ if(m_TargetItem0 != null && !m_TargetItem0.Deleted) return m_TargetItem0.Name; else return null;} } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target1Item + { + get{ return m_TargetItem1; } + set { m_TargetItem1 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target1Property + { + get{ return m_TargetProperty1; } + set { m_TargetProperty1 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target1ItemName + { get{ if(m_TargetItem1 != null && !m_TargetItem1.Deleted) return m_TargetItem1.Name; else return null;} } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target2Item + { + get{ return m_TargetItem2; } + set { m_TargetItem2 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target2Property + { + get{ return m_TargetProperty2; } + set { m_TargetProperty2 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target2ItemName + { get{ if(m_TargetItem2 != null && !m_TargetItem2.Deleted) return m_TargetItem2.Name; else return null;} } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + // version 2 + writer.Write(this.m_Disabled); + // version 1 + writer.Write(this.m_LinkedItem); + // version 0 + writer.Write( this.m_LeverSound ); + writer.Write( (int)this.m_LeverType ); + writer.Write( this.m_TargetItem0 ); + writer.Write( this.m_TargetProperty0 ); + writer.Write( this.m_TargetItem1 ); + writer.Write( this.m_TargetProperty1 ); + writer.Write( this.m_TargetItem2 ); + writer.Write( this.m_TargetProperty2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 2: + { + m_Disabled = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_LinkedItem = reader.ReadItem(); + goto case 0; + } + case 0: + { + this.m_LeverSound = reader.ReadInt(); + int ltype = reader.ReadInt(); + switch( ltype ) + { + case (int)leverType.Two_State: this.m_LeverType = leverType.Two_State; break; + case (int)leverType.Three_State: this.m_LeverType = leverType.Three_State; break; + + } + this.m_TargetItem0 = reader.ReadItem(); + this.m_TargetProperty0 = reader.ReadString(); + this.m_TargetItem1 = reader.ReadItem(); + this.m_TargetProperty1 = reader.ReadString(); + this.m_TargetItem2 = reader.ReadItem(); + this.m_TargetProperty2 = reader.ReadString(); + } + break; + } + // refresh the lever static to reflect the state + SetLeverStatic(); + } + + public void SetLeverStatic() + { + + switch(this.Direction) + { + case Direction.North: + case Direction.South: + case Direction.Right: + case Direction.Up: + if(m_LeverType == leverType.Two_State) + this.ItemID = 0x108c+ State*2; + else + this.ItemID = 0x108c+ State; + break; + case Direction.East: + case Direction.West: + case Direction.Left: + case Direction.Down: + if(m_LeverType == leverType.Two_State) + this.ItemID = 0x1093+ State*2; + else + this.ItemID = 0x1093+ State; + break; + default: + break; + } + } + + + public override void OnDoubleClick( Mobile from ) + { + if(from == null || Disabled) return; + + if ( !from.InRange( GetWorldLocation(), 2 ) || !from.InLOS(this)) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + // animate and change state + int newstate = State+1; + if(newstate > 1 && m_LeverType == leverType.Two_State) newstate = 0; + if(newstate > 2) newstate = 0; + + // carry out the switch actions + Activate(from, newstate, null); + } + } + + public class TimedSwitch : XmlLatch, ILinkable + { + private int m_SwitchSound = 939; + private Item m_TargetItem0 = null; + private string m_TargetProperty0 = null; + private Item m_TargetItem1 = null; + private string m_TargetProperty1 = null; + + private Item m_LinkedItem = null; + private bool already_being_activated = false; + + private bool m_Disabled = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Disabled + { + set { m_Disabled = value; } + get { return m_Disabled; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Link + { + set { m_LinkedItem = value; } + get { return m_LinkedItem; } + } + + [Constructable] + public TimedSwitch() : base( 0x108F ) + { + Name = "A switch"; + Movable = false; + } + + public TimedSwitch( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int State + { + get { return base.State; } + set + { + // prevent infinite recursion + if (!already_being_activated) + { + already_being_activated = true; + Activate(null, value, null); + already_being_activated = false; + } + + InvalidateProperties(); + } + } + + public void Activate(Mobile from, int state, ArrayList links) + { + if (Disabled) return; + + string status_str = null; + + if (state < 0) state = 0; + if (state > 1) state = 1; + + // assign the latch state and start the timer + base.State = state; + + // update the graphic + SetSwitchStatic(); + + // play the switching sound + //if (from != null) + //{ + // from.PlaySound(m_SwitchSound); + //} + try + { + Effects.PlaySound(Location, Map, m_SwitchSound); + } + catch { } + + // if a target object has been specified then apply the property modification + if (state == 0 && m_TargetItem0 != null && !m_TargetItem0.Deleted && m_TargetProperty0 != null && m_TargetProperty0.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, null, this, out status_str); + } + if (state == 1 && m_TargetItem1 != null && !m_TargetItem1.Deleted && m_TargetProperty1 != null && m_TargetProperty1.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, null, this, out status_str); + } + + // if the switch is linked, then activate the link as well + if (Link != null && Link is ILinkable) + { + if (links == null) + { + links = new ArrayList(); + } + // activate other linked objects if they have not already been activated + if (!links.Contains(this)) + { + links.Add(this); + + ((ILinkable)Link).Activate(from, state, links); + } + } + + // report any problems to staff + if (status_str != null && from != null && from.AccessLevel > AccessLevel.Player) + { + from.SendMessage("{0}", status_str); + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public int SwitchSound + { + get{ return m_SwitchSound; } + set + { + m_SwitchSound = value; + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + new public virtual Direction Direction + { + get{ return base.Direction; } + set { base.Direction = value; SetSwitchStatic();InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target0Item + { + get{ return m_TargetItem0; } + set { m_TargetItem0 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target0Property + { + get{ return m_TargetProperty0; } + set { m_TargetProperty0 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target0ItemName + { get{ if(m_TargetItem0 != null && !m_TargetItem0.Deleted) return m_TargetItem0.Name; else return null;} } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target1Item + { + get{ return m_TargetItem1; } + set { m_TargetItem1 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target1Property + { + get{ return m_TargetProperty1; } + set { m_TargetProperty1 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target1ItemName + { get{ if(m_TargetItem1 != null && !m_TargetItem1.Deleted) return m_TargetItem1.Name; else return null;} } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + // version 2 + writer.Write(this.m_Disabled); + // version 1 + writer.Write(this.m_LinkedItem); + // version 0 + writer.Write( this.m_SwitchSound ); + writer.Write( this.m_TargetItem0 ); + writer.Write( this.m_TargetProperty0 ); + writer.Write( this.m_TargetItem1 ); + writer.Write( this.m_TargetProperty1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 2: + { + m_Disabled = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_LinkedItem = reader.ReadItem(); + goto case 0; + } + case 0: + { + + this.m_SwitchSound = reader.ReadInt(); + this.m_TargetItem0 = reader.ReadItem(); + this.m_TargetProperty0 = reader.ReadString(); + this.m_TargetItem1 = reader.ReadItem(); + this.m_TargetProperty1 = reader.ReadString(); + } + break; + } + // refresh the lever static to reflect the state + SetSwitchStatic(); + } + + public void SetSwitchStatic() + { + + switch(this.Direction) + { + case Direction.North: + case Direction.South: + case Direction.Right: + case Direction.Up: + this.ItemID = 0x108f+ State; + break; + case Direction.East: + case Direction.West: + case Direction.Left: + case Direction.Down: + this.ItemID = 0x1091+ State; + break; + default: + this.ItemID = 0x108f+ State; + break; + } + } + + + public override void OnDoubleClick( Mobile from ) + { + if(from == null || Disabled) return; + + if ( !from.InRange( GetWorldLocation(), 2 ) || !from.InLOS(this)) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + // animate and change state + int newstate = State+1; + if(newstate > 1) newstate = 0; + + // carry out the switch actions + Activate(from, newstate, null); + + } + } + + public class TimedSwitchableItem : XmlLatch, ILinkable + { + private int m_SwitchSound = 939; + private Item m_TargetItem0 = null; + private string m_TargetProperty0 = null; + private Item m_TargetItem1 = null; + private string m_TargetProperty1 = null; + private int m_ItemID0 = 0x108F; + private int m_ItemID1 = 0x1090; + + private Item m_LinkedItem = null; + private bool already_being_activated = false; + + private Point3D m_Offset = Point3D.Zero; + + private bool m_Disabled = false; + private bool m_NoDoubleClick = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Disabled + { + set { m_Disabled = value; } + get { return m_Disabled; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool NoDoubleClick + { + set { m_NoDoubleClick = value; } + get { return m_NoDoubleClick; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Offset + { + set { m_Offset = value; } + get { return m_Offset; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Link + { + set { m_LinkedItem = value; } + get { return m_LinkedItem; } + } + + [Constructable] + public TimedSwitchableItem() : base( 0x108F ) + { + Name = "A switchable item"; + Movable = false; + } + + public TimedSwitchableItem( Serial serial ) : base( serial ) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int State + { + get { return base.State; } + set + { + // prevent infinite recursion + if (!already_being_activated) + { + already_being_activated = true; + Activate(null, value, null); + already_being_activated = false; + } + + InvalidateProperties(); + } + } + + + public void Activate(Mobile from, int state, ArrayList links) + { + if (Disabled) return; + + string status_str = null; + + if (state < 0) state = 0; + if (state > 1) state = 1; + + if (base.State != state) + { + // apply the offset + SetSwitchOffset(); + } + // assign the latch state and start the timer + base.State = state; + + // update the graphic + SetSwitchStatic(); + + // play the switching sound + //if (from != null) + //{ + // from.PlaySound(m_SwitchSound); + //} + try + { + Effects.PlaySound(Location, Map, m_SwitchSound); + } + catch { } + + // if a target object has been specified then apply the property modification + if (state == 0 && m_TargetItem0 != null && !m_TargetItem0.Deleted && m_TargetProperty0 != null && m_TargetProperty0.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty0, m_TargetItem0, null, this, out status_str); + } + if (state == 1 && m_TargetItem1 != null && !m_TargetItem1.Deleted && m_TargetProperty1 != null && m_TargetProperty1.Length > 0) + { + BaseXmlSpawner.ApplyObjectStringProperties(null, m_TargetProperty1, m_TargetItem1, null, this, out status_str); + } + + // if the switch is linked, then activate the link as well + if (Link != null && Link is ILinkable) + { + if (links == null) + { + links = new ArrayList(); + } + // activate other linked objects if they have not already been activated + if (!links.Contains(this)) + { + links.Add(this); + + ((ILinkable)Link).Activate(from, state, links); + } + } + + // report any problems to staff + if (status_str != null && from != null && from.AccessLevel > AccessLevel.Player) + { + from.SendMessage("{0}", status_str); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ItemID0 + { + get{ return m_ItemID0; } + set + { + m_ItemID0 = value; + // refresh the lever static to reflect the state + SetSwitchStatic(); + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ItemID1 + { + get{ return m_ItemID1; } + set + { + m_ItemID1 = value; + // refresh the lever static to reflect the state + SetSwitchStatic(); + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SwitchSound + { + get{ return m_SwitchSound; } + set + { + m_SwitchSound = value; + InvalidateProperties();} + } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target0Item + { + get{ return m_TargetItem0; } + set { m_TargetItem0 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target0Property + { + get{ return m_TargetProperty0; } + set { m_TargetProperty0 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target0ItemName + { get{ if(m_TargetItem0 != null && !m_TargetItem0.Deleted) return m_TargetItem0.Name; else return null;} } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target1Item + { + get{ return m_TargetItem1; } + set { m_TargetItem1 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target1Property + { + get{ return m_TargetProperty1; } + set { m_TargetProperty1 = value;InvalidateProperties();} + } + [CommandProperty( AccessLevel.GameMaster )] + public string Target1ItemName + { get{ if(m_TargetItem1 != null && !m_TargetItem1.Deleted) return m_TargetItem1.Name; else return null;} } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 4 ); // version + // version 4 + writer.Write(this.m_NoDoubleClick); + // version 3 + writer.Write(this.m_Disabled); + writer.Write(this.m_Offset); + // version 2 + writer.Write(this.m_LinkedItem); + // version 1 + writer.Write( this.m_ItemID0 ); + writer.Write( this.m_ItemID1 ); + // version 0 + writer.Write( this.m_SwitchSound ); + writer.Write( this.m_TargetItem0 ); + writer.Write( this.m_TargetProperty0 ); + writer.Write( this.m_TargetItem1 ); + writer.Write( this.m_TargetProperty1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 4: + { + m_NoDoubleClick = reader.ReadBool(); + goto case 3; + } + case 3: + { + m_Disabled = reader.ReadBool(); + m_Offset = reader.ReadPoint3D(); + goto case 2; + } + case 2: + { + m_LinkedItem = reader.ReadItem(); + goto case 1; + } + case 1: + { + m_ItemID0 = reader.ReadInt(); + m_ItemID1 = reader.ReadInt(); + goto case 0; + } + case 0: + { + + m_SwitchSound = reader.ReadInt(); + m_TargetItem0 = reader.ReadItem(); + m_TargetProperty0 = reader.ReadString(); + m_TargetItem1 = reader.ReadItem(); + m_TargetProperty1 = reader.ReadString(); + } + break; + } + // refresh the lever static to reflect the state + SetSwitchStatic(); + } + + public void SetSwitchStatic() + { + + switch(State) + { + case 0: + this.ItemID = ItemID0; + break; + case 1: + this.ItemID = ItemID1; + break; + } + } + + public void SetSwitchOffset() + { + + switch (State) + { + case 0: + Location = new Point3D(X - m_Offset.X, Y - m_Offset.Y, Z - m_Offset.Z); + break; + case 1: + Location = new Point3D(X + m_Offset.X, Y + m_Offset.Y, Z + m_Offset.Z); + break; + } + } + + + public override void OnDoubleClick( Mobile from ) + { + if(from == null || Disabled || NoDoubleClick) return; + + if ( !from.InRange( GetWorldLocation(), 2 ) || !from.InLOS(this)) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + // animate and change state + int newstate = State+1; + if(newstate > 1) newstate = 0; + + // carry out the switch actions + Activate(from, newstate, null); + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/XmlQuestMaker.cs b/Scripts/Customs/XML Spawner/XmlItems/XmlQuestMaker.cs new file mode 100644 index 0000000..ae968dd --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/XmlQuestMaker.cs @@ -0,0 +1,73 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.IO; +using System.Collections; +using Server.Targeting; +using Server.Engines.PartySystem; +using System.Data; +using System.Xml; + +/* +** XmlQuestMaker +** +** Version 1.00 +** updated 9/03/04 +** ArteGordon +** +*/ +namespace Server.Items +{ + + public class XmlQuestMaker : Item + { + + public XmlQuestMaker( Serial serial ) : base( serial ) + { + } + + + [Constructable] + public XmlQuestMaker() : base(0xED4) + { + Name = "XmlQuestMaker"; + Movable = false; + Visible = true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + } + + public override void OnDoubleClick( Mobile from ) + { + base.OnDoubleClick(from); + + if(!(from is PlayerMobile)) return; + + // make a quest note + QuestHolder newquest = new QuestHolder(); + newquest.PlayerMade = true; + newquest.Creator = from as PlayerMobile; + newquest.Hue = 500; + from.AddToBackpack(newquest); + from.SendMessage("A blank quest has been added to your pack!"); + + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlItems/XmlSpawnerAddon.cs b/Scripts/Customs/XML Spawner/XmlItems/XmlSpawnerAddon.cs new file mode 100644 index 0000000..e0c6ab7 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlItems/XmlSpawnerAddon.cs @@ -0,0 +1,279 @@ +using System; +using Server; +using System.IO; +using System.Collections; +using Server.Multis; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlSpawnerAddon : BaseAddon + { + + public override bool ShareHue { get { return false; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int PartialVisibility + { + get + { + int nvisible = 0; + // figure out what percentage of components is visible and return that value + // go through the components + for (int i = 0; i < Components.Count; i++) + { + if (Components[i].Visible) nvisible++; + } + + return (int)(100.0 * nvisible / Components.Count + 0.5); + } + set + { + if (Components == null || Components.Count < 1) return; + + // assign visibility to the components based upon the percentage value + int nvisible = value * (Components.Count - 1) / 100; + + // go through the components and assign visibility to the specified percentage + // starting at the beginning of the component list + for (int i = 0; i < Components.Count; i++) + { + Components[i].Visible = (i < nvisible); + } + } + } + + // create an addon with the static components described in the multi.txt file + public static XmlSpawnerAddon ReadMultiFile(string filename, out string status_str) + { + status_str = null; + + if (filename == null) return null; + + XmlSpawnerAddon newaddon = null; + + // look for the file in the default spawner locations + string dirname = XmlSpawner.LocateFile(filename); + + if (System.IO.File.Exists(dirname)) + { + int ncomponents = 0; + + newaddon = new XmlSpawnerAddon(); + + try + { + ncomponents = LoadAddonFromMulti(newaddon, dirname, out status_str); + } + catch + { + newaddon.Delete(); + status_str = "Bad Multi file : " + filename; + return null; + } + + if (ncomponents == 0) + { + newaddon.Delete(); + status_str += " : " + filename; + return null; + } + + } + else + { + status_str = "No such file : " + filename; + } + + return newaddon; + } + + // adds components from a multi.txt file to an existing addon + public static int LoadAddonFromMulti(XmlSpawnerAddon newaddon, string filename, out string status_str) + { + status_str = null; + + if (filename == null) + { + status_str = "Invalid filename"; + return 0; + } + + if (newaddon == null) + { + status_str = "Invalid addon"; + return 0; + } + + bool badformat = false; + int ncomponents = 0; + + if (System.IO.File.Exists(filename)) + { + + using (StreamReader sr = new StreamReader(filename)) + { + string line; + int linenumber = 0; + + // Read and process lines from the file until the end of the file is reached. + // Individual lines have the format of + // itemid x y z visible [hue] ; attachment[,args] + // where visible is a 0/1 and hue can be optionally specified for individual itemid entries. + while ((line = sr.ReadLine()) != null) + { + linenumber++; + + // process the line + if (line.Length == 0) continue; + + // first parse out the component specification from any optional attachment specifications + + string[] specs = line.Split(';'); + + // the component spec will always be first + + if (specs == null || specs.Length < 1) continue; + + string[] args = specs[0].Trim().Split(' '); + + AddonComponent newcomponent = null; + + if (args != null && args.Length >= 5) + { + + int itemid = -1; + int x = 0; + int y = 0; + int z = 0; + int visible = 0; + int hue = -1; + + try + { + itemid = int.Parse(args[0]); + x = int.Parse(args[1]); + y = int.Parse(args[2]); + z = int.Parse(args[3]); + visible = int.Parse(args[4]); + + // handle the optional fields that are not part of the original multi.txt specification + if (args.Length > 5) + { + hue = int.Parse(args[5]); + } + } + catch { badformat = true; } + + if (itemid < 0 || badformat) + { + status_str = String.Format("Error line {0}", linenumber); + break; + } + + // create the new component + newcomponent = new AddonComponent(itemid); + + // set the properties according to the specification + newcomponent.Visible = (visible == 1); + + if (hue >= 0) + newcomponent.Hue = hue; + + // add it to the addon + newaddon.AddComponent(newcomponent, x, y, z); + + ncomponents++; + + } + + // if a valid component was added, then check to see if any additional attachment specifications need to be processed + if (newcomponent != null && specs.Length > 1) + { + for (int j = 1; j < specs.Length; j++) + { + + if (specs[j] == null) continue; + + string attachstring = specs[j].Trim(); + + Type type = null; + try + { + type = SpawnerType.GetType(BaseXmlSpawner.ParseObjectType(attachstring)); + } + catch { } + + // if so then create it + if (type != null && type.IsSubclassOf(typeof(XmlAttachment))) + { + object newo = XmlSpawner.CreateObject(type, attachstring, false, true); + if (newo is XmlAttachment) + { + // add the attachment to the target + XmlAttach.AttachTo(newcomponent, (XmlAttachment)newo); + + } + } + } + } + } + + sr.Close(); + } + } + else + { + status_str = "No such file : " + filename; + } + + if (badformat) + { + return 0; + } + else + { + return ncomponents; + } + } + + public override BaseAddonDeed Deed + { + get + { + return null; + } + } + + public XmlSpawnerAddon() + { + } + + public XmlSpawnerAddon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write(1); // Version + // version 1 + writer.Write(PartialVisibility); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 1: + PartialVisibility = reader.ReadInt(); + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/XmlMobiles/TalkingBaseCreature.cs b/Scripts/Customs/XML Spawner/XmlMobiles/TalkingBaseCreature.cs new file mode 100644 index 0000000..2f4c316 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlMobiles/TalkingBaseCreature.cs @@ -0,0 +1,963 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using System.Diagnostics; +using System.Text.RegularExpressions; +using Server.Engines.XmlSpawner2; + +/* +** TalkingBaseCreature +** A mobile that can be programmed with branching conversational sequences that are advanced by keywords at each sequence point. +** +** 2/10/05 +** modified to use the XmlDialog attachment +*/ +namespace Server.Mobiles +{ + public class TalkingBaseCreature : BaseCreature + { + + private XmlDialog m_DialogAttachment; + + + public XmlDialog DialogAttachment {get { return m_DialogAttachment; } set {m_DialogAttachment = value; }} + + private DateTime lasteffect; + private int m_EItemID = 0; // 0 = disable, 14202 = sparkle, 6251 = round stone, 7885 = light pyramid + private int m_Duration = 70; + private Point3D m_Offset = new Point3D(0,0,20); // overhead + private int m_EHue = 68; // green + + [CommandProperty( AccessLevel.GameMaster )] + public int EItemID { + get{ return m_EItemID; } + set { + m_EItemID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D EOffset + { + get{ return m_Offset; } + set + { + m_Offset = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EDuration + { + get{ return m_Duration; } + set + { + m_Duration = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EHue + { + get{ return m_EHue; } + set + { + m_EHue = value; + } + } + public void DisplayHighlight() + { + if(EItemID > 0) + { + //SendOffsetTargetEffect(this, new Point3D(Location.X + EOffset.X, Location.Y + EOffset.Y, Location.Z + EOffset.Z), EItemID, 10, EDuration, EHue, 0); + Effects.SendLocationEffect(new Point3D(Location.X + EOffset.X, Location.Y + EOffset.Y, Location.Z + EOffset.Z), Map, EItemID, EDuration, EHue, 0); + + lasteffect = DateTime.Now; + + } + } + + public static void SendOffsetTargetEffect( IEntity target, Point3D loc, int itemID, int speed, int duration, int hue, int renderMode ) + { + if ( target is Mobile ) + ((Mobile)target).ProcessDelta(); + + Effects.SendPacket( loc, target.Map, new OffsetTargetEffect( target, loc, itemID, speed, duration, hue, renderMode ) ); + } + + public sealed class OffsetTargetEffect : HuedEffect + { + public OffsetTargetEffect(IEntity e, Point3D loc, int itemID, int speed, int duration, int hue, int renderMode) + : base(EffectType.FixedFrom, e.Serial, Serial.Zero, itemID, loc, loc, speed, duration, true, false, hue, renderMode) + { + } + } + + public override void OnThink() + { + base.OnThink(); + + if(lasteffect + TimeSpan.FromSeconds(1) < DateTime.Now) + { + DisplayHighlight(); + } + } + + public override bool Move( Direction d ) + { + bool didmove = base.Move( d ); + + DisplayHighlight(); + + return didmove; + } + + private string m_TalkText; + + [CommandProperty( AccessLevel.GameMaster )] + public string TalkText {get{ return m_TalkText; } set { m_TalkText = value; }} + + // properties below are modified to access the equivalent XmlDialog properties + // this is largely for backward compatibility, but it does also add some convenience + + public Mobile ActivePlayer + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ActivePlayer; + else + return null; + } + set + { + if(DialogAttachment != null) + DialogAttachment.ActivePlayer = value; + } + } + + public ArrayList SpeechEntries + { + get + { + if(DialogAttachment != null) + return DialogAttachment.SpeechEntries; + else + return null; + } + set + { + if(DialogAttachment != null) + DialogAttachment.SpeechEntries = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan GameTOD + { + get + { + int hours; + int minutes; + + Server.Items.Clock.GetTime(this.Map, this.Location.X, this.Location.Y, out hours, out minutes); + return (new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,hours, minutes,0).TimeOfDay); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan RealTOD + { + get + { + return DateTime.Now.TimeOfDay; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RealDay + { + get + { + return DateTime.Now.Day; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RealMonth + { + get + { + return DateTime.Now.Month; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DayOfWeek RealDayOfWeek + { + get + { + return DateTime.Now.DayOfWeek; + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public MoonPhase MoonPhase + { + get + { + return Clock.GetMoonPhase( this.Map, this.Location.X, this.Location.Y ); + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public AccessLevel TriggerAccessLevel + { + get + { + if(DialogAttachment != null) + return DialogAttachment.TriggerAccessLevel; + else + return AccessLevel.Player; + } + set + { + if(DialogAttachment != null) + DialogAttachment.TriggerAccessLevel = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastInteraction + { + get + { + if(DialogAttachment != null) + return DialogAttachment.LastInteraction; + else + return DateTime.MinValue; + } + set + { + if(DialogAttachment != null) + DialogAttachment.LastInteraction = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool DoReset + { + get + { + return false; + } + set + { + if(DialogAttachment != null) + DialogAttachment.DoReset = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsActive + { + get + { + if(DialogAttachment != null) + return DialogAttachment.IsActive; + else + return false; + } + set + { + if(DialogAttachment != null) + DialogAttachment.IsActive = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowGhostTrig + { + get + { + if(DialogAttachment != null) + return DialogAttachment.AllowGhostTrig; + else + return false; + } + set + { + if(DialogAttachment != null) + DialogAttachment.AllowGhostTrig = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Running + { + get + { + if(DialogAttachment != null) + return DialogAttachment.Running; + else + return false; + + } + set + { + if(DialogAttachment != null) + DialogAttachment.Running = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan ResetTime + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ResetTime; + else + return TimeSpan.Zero; + } + set + { + if(DialogAttachment != null) + DialogAttachment.ResetTime = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpeechPace + { + get + { + if(DialogAttachment != null) + return DialogAttachment.SpeechPace; + else + return 0; + } + set + { + if(DialogAttachment != null) + DialogAttachment.SpeechPace = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Keywords + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Keywords; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Keywords = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Action + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Action; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Action = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Condition + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Condition; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Condition = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Text + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Text; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Text = value; + } + } + + + + [CommandProperty( AccessLevel.GameMaster )] + public string DependsOn + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.DependsOn; + } + else + return "-1"; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.DependsOn = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LockConversation + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.LockConversation; + } + else + return false; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.LockConversation = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public MessageType SpeechStyle + { + + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.SpeechStyle; + } + else + return MessageType.Regular; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.SpeechStyle = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowNPCTrigger + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.AllowNPCTrigger; + } + else + return false; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.AllowNPCTrigger = value; + } + + } + + + [CommandProperty( AccessLevel.GameMaster )] + public int Pause + { + + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Pause; + } + else + return -1; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Pause = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PrePause + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.PrePause; + } + else + return -1; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.PrePause = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ID + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.ID; + } + else + return -1; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.ID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EntryNumber + { + get + { + if(DialogAttachment != null) + return DialogAttachment.EntryNumber; + else + return -1; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.EntryNumber = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ProximityRange + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ProximityRange; + else + return -1; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.ProximityRange = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string ConfigFile + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ConfigFile; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.ConfigFile = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LoadConfig + { + get{return false;} + set{ if(value == true && DialogAttachment != null) DialogAttachment.DoLoadNPC(null,ConfigFile);} + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SaveConfig + { + get{return false;} + set + { + if(value == true && DialogAttachment != null) + DialogAttachment.DoSaveNPC(null,ConfigFile, false); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string TriggerOnCarried + { + get + { + if(DialogAttachment != null) + return DialogAttachment.TriggerOnCarried; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.TriggerOnCarried = value; + } + } + + } + [CommandProperty( AccessLevel.GameMaster )] + public string NoTriggerOnCarried + { + get + { + if(DialogAttachment != null) + return DialogAttachment.NoTriggerOnCarried; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.NoTriggerOnCarried = value; + } + } + + } + + public XmlDialog.SpeechEntry CurrentEntry + { + get + { + if(DialogAttachment != null) + return DialogAttachment.CurrentEntry; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.CurrentEntry = value; + } + } + + } + + public override bool OnDragDrop( Mobile from, Item item) + { + + return XmlQuest.RegisterGive(from, this, item); + + //return base.OnDragDrop(from, item); + } + + private class TalkEntry : ContextMenuEntry + { + private TalkingBaseCreature m_NPC; + + public TalkEntry( TalkingBaseCreature npc ) : base( 6146 ) + { + m_NPC = npc; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( m_NPC == null || m_NPC.Deleted || !from.CheckAlive() || m_NPC.DialogAttachment == null ) + return; + + // process the talk text + //m_NPC.DialogAttachment.ProcessSpeech(from, m_NPC.TalkText); + from.DoSpeech(m_NPC.TalkText,new int[] {},MessageType.Regular,from.SpeechHue); + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + if ( from.Alive ) + { + if ( TalkText != null && TalkText.Length > 0 && DialogAttachment != null) + { + list.Add( new TalkEntry( this ) ); + } + } + + base.GetContextMenuEntries( from, list ); + } + + + + public TalkingBaseCreature(AIType ai, + FightMode mode, + int iRangePerception, + int iRangeFight, + double dActiveSpeed, + double dPassiveSpeed): base( ai, mode, iRangePerception, iRangeFight, dActiveSpeed, dPassiveSpeed ) + { + // add the XmlDialog attachment + m_DialogAttachment = new XmlDialog((string)null); + XmlAttach.AttachTo(this, m_DialogAttachment); + + } + + public TalkingBaseCreature( Serial serial ) : base( serial ) + { + } + + public static void Initialize() + { + // reestablish the DialogAttachment assignment + foreach(Mobile m in World.Mobiles.Values) + { + if(m is TalkingBaseCreature) + { + XmlDialog xa = XmlAttach.FindAttachment(m, typeof(XmlDialog)) as XmlDialog; + ((TalkingBaseCreature)m).DialogAttachment = xa; + } + } + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 7 ); // version + + // version 7 + writer.Write( m_EItemID); + writer.Write( m_Duration); + writer.Write( m_Offset); + writer.Write( m_EHue); + + // version 6 + writer.Write( m_TalkText); + + // Version 5 + // all serialized data now handled by the XmlDialog attachment + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if(version < 5) + { + // have to add the XmlDialog attachment + m_DialogAttachment = new XmlDialog((string)null); + XmlAttach.AttachTo(this, m_DialogAttachment); + } + + switch ( version ) + { + case 7: + m_EItemID = reader.ReadInt(); + m_Duration = reader.ReadInt(); + m_Offset = reader.ReadPoint3D(); + m_EHue = reader.ReadInt(); + goto case 6; + case 6: + TalkText = reader.ReadString(); + break; + case 5: + { + break; + } + case 4: + { + int count = reader.ReadInt(); + + SpeechEntries = new ArrayList(); + for(int i = 0; i= DateTime.Now ) + { + int minutes = (int)Math.Ceiling( ((((PlayerMobile)m).LastEscortTime + m_EscortDelay) - DateTime.Now).TotalMinutes ); + + Say( "You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s" ); + return false; + } + else if ( SetControlMaster( m ) ) + { + m_LastSeenEscorter = DateTime.Now; + + if ( m is PlayerMobile ) + ((PlayerMobile)m).LastEscortTime = DateTime.Now; + + Say( "Lead on! Payment will be made when we arrive in {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name ); + m_EscortTable[m] = this; + StartFollow(); + return true; + } + + return false; + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.InRange( this.Location, 3 ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + base.OnSpeech( e ); + + EDI dest = GetDestination(); + + if ( dest != null && !e.Handled && e.Mobile.InRange( this.Location, 3 ) ) + { + if ( e.HasKeyword( 0x1D ) ) // *destination* + e.Handled = SayDestinationTo( e.Mobile ); + else if ( e.HasKeyword( 0x1E ) ) // *i will take thee* + e.Handled = AcceptEscorter( e.Mobile ); + } + } + + public override void OnAfterDelete() + { + if ( m_DeleteTimer != null ) + m_DeleteTimer.Stop(); + + m_DeleteTimer = null; + + base.OnAfterDelete(); + } + + public override void OnThink() + { + base.OnThink(); + CheckAtDestination(); + } + + protected override bool OnMove( Direction d ) + { + if ( !base.OnMove( d ) ) + return false; + + CheckAtDestination(); + + return true; + } + + public virtual void StartFollow() + { + StartFollow( GetEscorter() ); + } + + public virtual void StartFollow( Mobile escorter ) + { + if ( escorter == null ) + return; + + ActiveSpeed = 0.1; + PassiveSpeed = 0.2; + + ControlOrder = OrderType.Follow; + ControlTarget = escorter; + + CurrentSpeed = 0.1; + } + + public virtual void StopFollow() + { + ActiveSpeed = 0.2; + PassiveSpeed = 1.0; + + ControlOrder = OrderType.None; + ControlTarget = null; + + CurrentSpeed = 1.0; + } + + private DateTime m_LastSeenEscorter; + + public virtual Mobile GetEscorter() + { + if ( !Controlled ) + return null; + + Mobile master = ControlMaster; + + if ( master == null ) + return null; + + if ( master.Deleted || master.Map != this.Map || !master.InRange( Location, 30 ) || !master.Alive ) + { + StopFollow(); + + TimeSpan lastSeenDelay = DateTime.Now - m_LastSeenEscorter; + + if ( lastSeenDelay >= TimeSpan.FromMinutes( 2.0 ) ) + { + master.SendLocalizedMessage( 1042473 ); // You have lost the person you were escorting. + Say( 1005653 ); // Hmmm. I seem to have lost my master. + + SetControlMaster( null ); + m_EscortTable.Remove( master ); + + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( Delete ) ); + return null; + } + else + { + ControlOrder = OrderType.Stay; + return master; + } + } + + if ( ControlOrder != OrderType.Follow ) + StartFollow( master ); + + m_LastSeenEscorter = DateTime.Now; + return master; + } + + public virtual void BeginDelete() + { + if ( m_DeleteTimer != null ) + m_DeleteTimer.Stop(); + + m_DeleteTime = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + + m_DeleteTimer = new DeleteTimer( this, m_DeleteTime - DateTime.Now ); + m_DeleteTimer.Start(); + } + + public virtual bool CheckAtDestination() + { + EDI dest = GetDestination(); + + if ( dest == null ) + return false; + + Mobile escorter = GetEscorter(); + + if ( escorter == null ) + return false; + + if ( dest.Contains( Location ) ) + { + Say( 1042809, escorter.Name ); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay. + + + // not going anywhere + m_Destination = null; + m_DestinationString = null; + + Container cont = escorter.Backpack; + + if ( cont == null ) + cont = escorter.BankBox; + + Gold gold = new Gold( 500, 1000 ); + + if ( cont == null || !cont.TryDropItem( escorter, gold, false ) ) + gold.MoveToWorld( escorter.Location, escorter.Map ); + + Misc.Titles.AwardFame( escorter, 10, true ); + + bool gainedPath = false; + + PlayerMobile pm = escorter as PlayerMobile; + + if ( pm != null ) + { + if ( pm.CompassionGains > 0 && DateTime.Now > pm.NextCompassionDay ) + { + pm.NextCompassionDay = DateTime.MinValue; + pm.CompassionGains = 0; + } + + if ( pm.CompassionGains >= 5 ) // have already gained 5 points in one day, can gain no more + { + pm.SendLocalizedMessage( 1053004 ); // You must wait about a day before you can gain in compassion again. + } + else if ( VirtueHelper.Award( pm, VirtueName.Compassion, 1, ref gainedPath ) ) + { + if ( gainedPath ) + pm.SendLocalizedMessage( 1053005 ); // You have achieved a path in compassion! + else + pm.SendLocalizedMessage( 1053002 ); // You have gained in compassion. + + pm.NextCompassionDay = DateTime.Now + TimeSpan.FromDays( 1.0 ); // in one day CompassionGains gets reset to 0 + ++pm.CompassionGains; + } + else + { + pm.SendLocalizedMessage( 1053003 ); // You have achieved the highest path of compassion and can no longer gain any further. + } + } + + XmlQuest.RegisterEscort(this, escorter); + + StopFollow(); + SetControlMaster(null); + m_EscortTable.Remove(escorter); + BeginDelete(); + + return true; + } + + return false; + } + + public TalkingBaseEscortable( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + EDI dest = GetDestination(); + + writer.Write( dest != null ); + + if ( dest != null ) + writer.Write( dest.Name ); + + writer.Write( m_DeleteTimer != null ); + + if ( m_DeleteTimer != null ) + writer.WriteDeltaTime( m_DeleteTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( reader.ReadBool() ) + m_DestinationString = reader.ReadString(); // NOTE: We cannot EDI.Find here, regions have not yet been loaded :-( + + if ( reader.ReadBool() ) + { + m_DeleteTime = reader.ReadDeltaTime(); + m_DeleteTimer = new DeleteTimer( this, m_DeleteTime - DateTime.Now ); + m_DeleteTimer.Start(); + } + } + + public override bool CanBeRenamedBy( Mobile from ) + { + return ( from.AccessLevel >= AccessLevel.GameMaster ); + } + + public override void AddCustomContextEntries(Mobile from, List list) + { + EDI dest = GetDestination(); + + if ( dest != null && from.Alive ) + { + Mobile escorter = GetEscorter(); + + if ( escorter == null || escorter == from ) + list.Add( new AskTalkingDestinationEntry( this, from ) ); + + if ( escorter == null ) + list.Add( new AcceptTalkingEscortEntry( this, from ) ); + else if ( escorter == from ) + list.Add( new AbandonTalkingEscortEntry( this, from ) ); + } + + base.AddCustomContextEntries( from, list ); + } + + public virtual string[] GetPossibleDestinations() + { + return m_TownNames; + } + + public virtual string PickRandomDestination() + { + if ( Map.Felucca.Regions.Count == 0 || Map == null || Map == Map.Internal || Location == Point3D.Zero ) + return null; // Not yet fully initialized + + string[] possible = GetPossibleDestinations(); + string picked = null; + + while ( picked == null ) + { + picked = possible[Utility.Random( possible.Length )]; + EDI test = EDI.Find( picked ); + + if ( test != null && test.Contains( Location ) ) + picked = null; + } + + return picked; + } + + public EDI GetDestination() + { + if ( m_DestinationString == null && m_DeleteTimer == null ) + m_DestinationString = PickRandomDestination(); + + if ( m_Destination != null && m_Destination.Name == m_DestinationString ) + return m_Destination; + + if ( Map.Felucca.Regions.Count > 0 ) + return ( m_Destination = EDI.Find( m_DestinationString ) ); + + return ( m_Destination = null ); + } + + private class DeleteTimer : Timer + { + private Mobile m_Mobile; + + public DeleteTimer( Mobile m, TimeSpan delay ) : base( delay ) + { + m_Mobile = m; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Mobile.Delete(); + } + } + } + + + public class AskTalkingDestinationEntry : ContextMenuEntry + { + private TalkingBaseEscortable m_Mobile; + private Mobile m_From; + + public AskTalkingDestinationEntry( TalkingBaseEscortable m, Mobile from ) : base( 6100, 3 ) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.SayDestinationTo( m_From ); + } + } + + public class AcceptTalkingEscortEntry : ContextMenuEntry + { + private TalkingBaseEscortable m_Mobile; + private Mobile m_From; + + public AcceptTalkingEscortEntry( TalkingBaseEscortable m, Mobile from ) : base( 6101, 3 ) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.AcceptEscorter( m_From ); + } + } + + public class AbandonTalkingEscortEntry : ContextMenuEntry + { + private TalkingBaseEscortable m_Mobile; + private Mobile m_From; + + public AbandonTalkingEscortEntry( TalkingBaseEscortable m, Mobile from ) : base( 6102, 3 ) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.Delete(); // OSI just seems to delete instantly + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlMobiles/TalkingBaseVendor.cs b/Scripts/Customs/XML Spawner/XmlMobiles/TalkingBaseVendor.cs new file mode 100644 index 0000000..83b522c --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlMobiles/TalkingBaseVendor.cs @@ -0,0 +1,938 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.ContextMenus; +using Server.Commands; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using System.Diagnostics; +using System.Text.RegularExpressions; +using Server.Engines.XmlSpawner2; + +/* +** mirrors the TalkingBaseCreature only for vendors +*/ + +namespace Server.Mobiles +{ + public abstract class TalkingBaseVendor : BaseVendor + { + + public TalkingBaseVendor( string title ) : base( title ) + { + // add the XmlDialog attachment + m_DialogAttachment = new XmlDialog((string)null); + XmlAttach.AttachTo(this, m_DialogAttachment); + + } + + public TalkingBaseVendor( Serial serial ) : base( serial ) + { + } + + public static void Initialize() + { + // reestablish the DialogAttachment assignment + foreach(Mobile m in World.Mobiles.Values) + { + if(m is TalkingBaseVendor) + { + XmlDialog xa = XmlAttach.FindAttachment(m, typeof(XmlDialog)) as XmlDialog; + ((TalkingBaseVendor)m).DialogAttachment = xa; + } + } + } + + + private XmlDialog m_DialogAttachment; + + public XmlDialog DialogAttachment {get { return m_DialogAttachment; } set {m_DialogAttachment = value; }} + + private DateTime lasteffect; + private int m_EItemID = 0; // 0 = disable, 14202 = sparkle, 6251 = round stone, 7885 = light pyramid + private int m_Duration = 70; + private Point3D m_Offset = new Point3D(0,0,20); // overhead + private int m_EHue = 68; // green + + [CommandProperty( AccessLevel.GameMaster )] + public int EItemID + { + get{ return m_EItemID; } + set + { + m_EItemID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D EOffset + { + get{ return m_Offset; } + set + { + m_Offset = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EDuration + { + get{ return m_Duration; } + set + { + m_Duration = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EHue + { + get{ return m_EHue; } + set + { + m_EHue = value; + } + } + + private void DisplayHighlight() + { + if(EItemID > 0) + { + Effects.SendLocationEffect(new Point3D(Location.X + EOffset.X, Location.Y + EOffset.Y, Location.Z + EOffset.Z), Map, EItemID, EDuration, EHue, 0); + lasteffect = DateTime.Now; + } + } + + public override void OnThink() + { + base.OnThink(); + + if(lasteffect + TimeSpan.FromSeconds(1) < DateTime.Now) + { + DisplayHighlight(); + } + } + + public override bool Move( Direction d ) + { + bool didmove = base.Move( d ); + + DisplayHighlight(); + + return didmove; + } + + private string m_TalkText; + + [CommandProperty( AccessLevel.GameMaster )] + public string TalkText {get{ return m_TalkText; } set { m_TalkText = value; }} + + // properties below are modified to access the equivalent XmlDialog properties + // this is largely for backward compatibility, but it does also add some convenience + + public Mobile ActivePlayer + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ActivePlayer; + else + return null; + } + set + { + if(DialogAttachment != null) + DialogAttachment.ActivePlayer = value; + } + } + + public ArrayList SpeechEntries + { + get + { + if(DialogAttachment != null) + return DialogAttachment.SpeechEntries; + else + return null; + } + set + { + if(DialogAttachment != null) + DialogAttachment.SpeechEntries = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan GameTOD + { + get + { + int hours; + int minutes; + + Server.Items.Clock.GetTime(this.Map, this.Location.X, this.Location.Y, out hours, out minutes); + return (new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,hours, minutes,0).TimeOfDay); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan RealTOD + { + get + { + return DateTime.Now.TimeOfDay; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RealDay + { + get + { + return DateTime.Now.Day; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RealMonth + { + get + { + return DateTime.Now.Month; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DayOfWeek RealDayOfWeek + { + get + { + return DateTime.Now.DayOfWeek; + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public MoonPhase MoonPhase + { + get + { + return Clock.GetMoonPhase( this.Map, this.Location.X, this.Location.Y ); + } + + } + + + [CommandProperty( AccessLevel.GameMaster )] + public AccessLevel TriggerAccessLevel + { + get + { + if(DialogAttachment != null) + return DialogAttachment.TriggerAccessLevel; + else + return AccessLevel.Player; + } + set + { + if(DialogAttachment != null) + DialogAttachment.TriggerAccessLevel = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastInteraction + { + get + { + if(DialogAttachment != null) + return DialogAttachment.LastInteraction; + else + return DateTime.MinValue; + } + set + { + if(DialogAttachment != null) + DialogAttachment.LastInteraction = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool DoReset + { + get + { + return false; + } + set + { + if(DialogAttachment != null) + DialogAttachment.DoReset = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsActive + { + get + { + if(DialogAttachment != null) + return DialogAttachment.IsActive; + else + return false; + } + set + { + if(DialogAttachment != null) + DialogAttachment.IsActive = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowGhostTrig + { + get + { + if(DialogAttachment != null) + return DialogAttachment.AllowGhostTrig; + else + return false; + } + set + { + if(DialogAttachment != null) + DialogAttachment.AllowGhostTrig = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Running + { + get + { + if(DialogAttachment != null) + return DialogAttachment.Running; + else + return false; + + } + set + { + if(DialogAttachment != null) + DialogAttachment.Running = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan ResetTime + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ResetTime; + else + return TimeSpan.Zero; + } + set + { + if(DialogAttachment != null) + DialogAttachment.ResetTime = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpeechPace + { + get + { + if(DialogAttachment != null) + return DialogAttachment.SpeechPace; + else + return 0; + } + set + { + if(DialogAttachment != null) + DialogAttachment.SpeechPace = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Keywords + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Keywords; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Keywords = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Action + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Action; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Action = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Condition + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Condition; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Condition = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Text + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Text; + } + else + return null; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Text = value; + } + } + + + + [CommandProperty( AccessLevel.GameMaster )] + public string DependsOn + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.DependsOn; + } + else + return "-1"; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.DependsOn = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LockConversation + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.LockConversation; + } + else + return false; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.LockConversation = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public MessageType SpeechStyle + { + + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.SpeechStyle; + } + else + return MessageType.Regular; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.SpeechStyle = value; + } + + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AllowNPCTrigger + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.AllowNPCTrigger; + } + else + return false; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.AllowNPCTrigger = value; + } + + } + + + [CommandProperty( AccessLevel.GameMaster )] + public int Pause + { + + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.Pause; + } + else + return -1; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.Pause = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PrePause + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.PrePause; + } + else + return -1; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.PrePause = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ID + { + get + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + { + return DialogAttachment.CurrentEntry.ID; + } + else + return -1; + } + set + { + if(DialogAttachment != null && DialogAttachment.CurrentEntry != null) + DialogAttachment.CurrentEntry.ID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EntryNumber + { + get + { + if(DialogAttachment != null) + return DialogAttachment.EntryNumber; + else + return -1; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.EntryNumber = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ProximityRange + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ProximityRange; + else + return -1; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.ProximityRange = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string ConfigFile + { + get + { + if(DialogAttachment != null) + return DialogAttachment.ConfigFile; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.ConfigFile = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LoadConfig + { + get{return false;} + set{ if(value == true && DialogAttachment != null) DialogAttachment.DoLoadNPC(null,ConfigFile);} + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SaveConfig + { + get{return false;} + set + { + if(value == true && DialogAttachment != null) + DialogAttachment.DoSaveNPC(null,ConfigFile, false); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string TriggerOnCarried + { + get + { + if(DialogAttachment != null) + return DialogAttachment.TriggerOnCarried; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.TriggerOnCarried = value; + } + } + + } + [CommandProperty( AccessLevel.GameMaster )] + public string NoTriggerOnCarried + { + get + { + if(DialogAttachment != null) + return DialogAttachment.NoTriggerOnCarried; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.NoTriggerOnCarried = value; + } + } + + } + + public XmlDialog.SpeechEntry CurrentEntry + { + get + { + if(DialogAttachment != null) + return DialogAttachment.CurrentEntry; + else + return null; + } + set + { + if(DialogAttachment != null) + { + DialogAttachment.CurrentEntry = value; + } + } + + } + + public override bool OnDragDrop( Mobile from, Item item) + { + + return XmlQuest.RegisterGive(from, this, item); + + //return base.OnDragDrop(from, item); + } + + private class TalkEntry : ContextMenuEntry + { + private TalkingBaseVendor m_NPC; + + public TalkEntry( TalkingBaseVendor npc ) : base( 6146 ) + { + m_NPC = npc; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( m_NPC == null || m_NPC.Deleted || !from.CheckAlive() || m_NPC.DialogAttachment == null ) + return; + + // process the talk text + //m_NPC.DialogAttachment.ProcessSpeech(from, m_NPC.TalkText); + from.DoSpeech(m_NPC.TalkText,new int[] {},MessageType.Regular,from.SpeechHue); + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + if ( from.Alive ) + { + if ( TalkText != null && TalkText.Length > 0 && DialogAttachment != null) + { + list.Add( new TalkEntry( this ) ); + } + } + + base.GetContextMenuEntries( from, list ); + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 7 ); // version + + // version 7 + writer.Write( m_EItemID); + writer.Write( m_Duration); + writer.Write( m_Offset); + writer.Write( m_EHue); + + // version 6 + writer.Write( m_TalkText); + + // Version 5 + // all serialized data now handled by the XmlDialog attachment + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if(version < 5) + { + // have to add the XmlDialog attachment + m_DialogAttachment = new XmlDialog((string)null); + XmlAttach.AttachTo(this, m_DialogAttachment); + } + + switch ( version ) + { + case 7: + m_EItemID = reader.ReadInt(); + m_Duration = reader.ReadInt(); + m_Offset = reader.ReadPoint3D(); + m_EHue = reader.ReadInt(); + goto case 6; + case 6: + TalkText = reader.ReadString(); + break; + case 5: + { + break; + } + case 4: + { + int count = reader.ReadInt(); + + SpeechEntries = new ArrayList(); + for(int i = 0; i m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + [Constructable] + public TalkingJeweler() : base( "the jeweler" ) + { + SetSkill( SkillName.ItemID, 64.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBJewel() ); + } + + public TalkingJeweler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlMobiles/TalkingSeekerOfAdventure.cs b/Scripts/Customs/XML Spawner/XmlMobiles/TalkingSeekerOfAdventure.cs new file mode 100644 index 0000000..0a2e7b9 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlMobiles/TalkingSeekerOfAdventure.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class TalkingSeekerOfAdventure : TalkingBaseEscortable + { + private static string[] m_Dungeons = new string[] + { + "Covetous", "Deceit", "Despise", + "Destard", "Hythloth", "Shame", + "Wrong" + }; + + public override string[] GetPossibleDestinations() + { + return m_Dungeons; + } + + [Constructable] + public TalkingSeekerOfAdventure() + { + Title = "the seeker of adventure"; + } + + public override bool ClickTitle{ get{ return false; } } // Do not display 'the seeker of adventure' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + if ( Female ) + AddItem( new FancyDress( GetRandomHue() ) ); + else + AddItem( new FancyShirt( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ShortPants( lowHue ) ); + + if ( Female ) + AddItem( new ThighBoots( lowHue ) ); + else + AddItem( new Boots( lowHue ) ); + + if ( !Female ) + AddItem( new BodySash( lowHue ) ); + + AddItem( new Cloak( GetRandomHue() ) ); + + AddItem( new Longsword() ); + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new ShortHair( Utility.RandomHairHue() ) ); break; + case 1: AddItem( new TwoPigTails( Utility.RandomHairHue() ) ); break; + case 2: AddItem( new ReceedingHair( Utility.RandomHairHue() ) ); break; + case 3: AddItem( new KrisnaHair( Utility.RandomHairHue() ) ); break; + } + + PackGold( 100, 150 ); + } + + public TalkingSeekerOfAdventure( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlMobiles/XmlQuestNPC.cs b/Scripts/Customs/XML Spawner/XmlMobiles/XmlQuestNPC.cs new file mode 100644 index 0000000..706a814 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlMobiles/XmlQuestNPC.cs @@ -0,0 +1,191 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using System.Diagnostics; + + + +namespace Server.Mobiles +{ + public class XmlQuestNPC : TalkingBaseCreature + { + + [Constructable] + public XmlQuestNPC() : this(-1) + { + } + + [Constructable] + public XmlQuestNPC(int gender) : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.8, 3.0 ) + { + SetStr( 10, 30 ); + SetDex( 10, 30 ); + SetInt( 10, 30 ); + + Fame = 50; + Karma = 50; + + CanHearGhosts = true; + + SpeechHue = Utility.RandomDyedHue(); + Title = string.Empty; + Hue = Utility.RandomSkinHue(); + + switch(gender) + { + case -1: this.Female = Utility.RandomBool(); break; + case 0: this.Female = false; break; + case 1: this.Female = true; break; + } + + if ( this.Female) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + Item hair = new Item( Utility.RandomList( 0x203B, 0x203C, 0x203D, 0x2045, 0x204A, 0x2046 , 0x2049 ) ); + hair.Hue = Utility.RandomHairHue(); + hair.Layer = Layer.Hair; + hair.Movable = false; + AddItem( hair ); + Item hat = null; + switch ( Utility.Random( 5 ) )//4 hats, one empty, for no hat + { + case 0: hat = new FloppyHat( Utility.RandomNeutralHue() ); break; + case 1: hat = new FeatheredHat( Utility.RandomNeutralHue() ); break; + case 2: hat = new Bonnet(); break; + case 3: hat = new Cap( Utility.RandomNeutralHue() ); break; + } + AddItem( hat ); + Item pants = null; + switch ( Utility.Random( 3 ) ) + { + case 0: pants = new ShortPants( GetRandomHue() ); break; + case 1: pants = new LongPants( GetRandomHue() ); break; + case 2: pants = new Skirt( GetRandomHue() ); break; + } + AddItem( pants ); + Item shirt = null; + switch ( Utility.Random( 7 ) ) + { + case 0: shirt = new Doublet( GetRandomHue() ); break; + case 1: shirt = new Surcoat( GetRandomHue() ); break; + case 2: shirt = new Tunic( GetRandomHue() ); break; + case 3: shirt = new FancyDress( GetRandomHue() ); break; + case 4: shirt = new PlainDress( GetRandomHue() ); break; + case 5: shirt = new FancyShirt( GetRandomHue() ); break; + case 6: shirt = new Shirt( GetRandomHue() ); break; + } + AddItem( shirt ); + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + Item hair = new Item( Utility.RandomList( 0x203B, 0x203C, 0x203D, 0x2044, 0x2045, 0x2047, 0x2048 ) ); + hair.Hue = Utility.RandomHairHue(); + hair.Layer = Layer.Hair; + hair.Movable = false; + AddItem( hair ); + Item beard = new Item( Utility.RandomList( 0x0000, 0x203E, 0x203F, 0x2040, 0x2041, 0x2067, 0x2068, 0x2069 ) ); + beard.Hue = hair.Hue; + beard.Layer = Layer.FacialHair; + beard.Movable = false; + AddItem( beard ); + Item hat = null; + switch ( Utility.Random( 7 ) ) //6 hats, one empty, for no hat + { + case 0: hat = new SkullCap( GetRandomHue() ); break; + case 1: hat = new Bandana( GetRandomHue() ); break; + case 2: hat = new WideBrimHat(); break; + case 3: hat = new TallStrawHat( Utility.RandomNeutralHue() ); break; + case 4: hat = new StrawHat( Utility.RandomNeutralHue() ); break; + case 5: hat = new TricorneHat( Utility.RandomNeutralHue() ); break; + } + AddItem( hat ); + Item pants = null; + switch ( Utility.Random( 2 ) ) + { + case 0: pants = new ShortPants( GetRandomHue() ); break; + case 1: pants = new LongPants( GetRandomHue() ); break; + } + AddItem( pants ); + Item shirt = null; + switch ( Utility.Random( 5 ) ) + { + case 0: shirt = new Doublet( GetRandomHue() ); break; + case 1: shirt = new Surcoat( GetRandomHue() ); break; + case 2: shirt = new Tunic( GetRandomHue() ); break; + case 3: shirt = new FancyShirt( GetRandomHue() ); break; + case 4: shirt = new Shirt( GetRandomHue() ); break; + } + AddItem( shirt ); + } + + Item feet = null; + switch ( Utility.Random( 3 ) ) + { + case 0: feet = new Boots( Utility.RandomNeutralHue() ); break; + case 1: feet = new Shoes( Utility.RandomNeutralHue() ); break; + case 2: feet = new Sandals( Utility.RandomNeutralHue() ); break; + } + AddItem( feet ); + Container pack = new Backpack(); + + pack.DropItem( new Gold( 0, 50 ) ); + + pack.Movable = false; + + AddItem( pack ); + } + + public XmlQuestNPC( Serial serial ) : base( serial ) + { + } + + + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlPropsGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlPropsGump.cs new file mode 100644 index 0000000..f0f6e20 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlPropsGump.cs @@ -0,0 +1,738 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Menus; +using Server.Menus.Questions; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +/* +** modified properties gumps taken from RC0 properties gump scripts to support the special XmlSpawner properties gump +*/ + +namespace Server.Gumps +{ + public class XmlPropertiesGump : Gump + { + private ArrayList m_List; + private int m_Page; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static bool PrevLabel = OldStyle, NextLabel = OldStyle; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int NameWidth = 103; + private static readonly int ValueWidth = 82; + + private static readonly int EntryCount = 66; + private static readonly int ColumnEntryCount = 22; + + private static readonly int TypeWidth = NameWidth + OffsetSize + ValueWidth; + + private static readonly int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlPropertiesGump( Mobile mobile, object o ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Mobile = mobile; + m_Object = o; + m_List = BuildList(); + + Initialize( 0 ); + } + + public XmlPropertiesGump( Mobile mobile, object o, Stack stack, object parent ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_List = BuildList(); + + if ( parent != null ) + { + if ( m_Stack == null ) + m_Stack = new Stack(); + + m_Stack.Push( parent ); + } + + Initialize( 0 ); + } + + public XmlPropertiesGump( Mobile mobile, object o, Stack stack, ArrayList list, int page ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Mobile = mobile; + m_Object = o; + m_List = list; + m_Stack = stack; + + Initialize( page ); + } + + private void Initialize( int page ) + { + m_Page = page; + + int count = m_List.Count - (page * EntryCount); + + if ( count < 0 ) + count = 0; + else if ( count > EntryCount ) + count = EntryCount; + + int lastIndex = (page * EntryCount) + count - 1; + + if ( lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null ) + --count; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (ColumnEntryCount + 1)); + + AddPage( 0 ); + + AddBackground( 0, 0, TotalWidth*3 + BorderSize*2, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize + EntryHeight, (TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0))*3, totalHeight-EntryHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize /*+ OffsetSize*/; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0); + + if(m_Object is Item) + AddLabelCropped( x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, ((Item)m_Object).Name ); + int propcount = 0; + for ( int i = 0, index = page * EntryCount; i < count && index < m_List.Count; ++i, ++index ) + { + // do the multi column display + int column = propcount/ColumnEntryCount; + if(propcount%ColumnEntryCount == 0) + y = BorderSize; + x = BorderSize + OffsetSize + column*(ValueWidth + NameWidth +OffsetSize*2 + SetOffsetX + SetWidth); + y += EntryHeight + OffsetSize; + + + + object o = m_List[index]; + + if ( o == null ) + { + AddImageTiled( x - OffsetSize, y, TotalWidth, EntryHeight, BackGumpID + 4 ); + propcount++; + } + else + /*if ( o is Type ) + { + Type type = (Type)o; + + AddImageTiled( x, y, TypeWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, type.Name ); + x += TypeWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + } + else + */ + if ( o is PropertyInfo ) + { + propcount++; + + PropertyInfo prop = (PropertyInfo)o; + + // look for the default value of the equivalent property in the XmlSpawnerDefaults.DefaultEntry class + + int huemodifier = TextHue; + FieldInfo finfo = null; + Server.Mobiles.XmlSpawnerDefaults.DefaultEntry de = new Server.Mobiles.XmlSpawnerDefaults.DefaultEntry(); + Type ftype = de.GetType(); + if(ftype != null) + finfo = ftype.GetField(prop.Name); + // is there an equivalent default field? + if(finfo != null){ + // see if the value is different from the default + if(ValueToString(finfo.GetValue(de)) != ValueToString(prop)) + { + huemodifier = 68; + } + } + + AddImageTiled( x, y, NameWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, NameWidth - TextOffsetX, EntryHeight, huemodifier, prop.Name ); + x += NameWidth + OffsetSize; + AddImageTiled( x, y, ValueWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, huemodifier, ValueToString( prop ) ); + x += ValueWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + CPA cpa = GetCPA( prop ); + + if ( prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel ) + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3, GumpButtonType.Reply, 0 ); + } + } + } + + public static string[] m_BoolNames = new string[]{ "True", "False" }; + public static object[] m_BoolValues = new object[]{ true, false }; + + public static string[] m_PoisonNames = new string[]{ "None", "Lesser", "Regular", "Greater", "Deadly", "Lethal" }; + public static object[] m_PoisonValues = new object[]{ null, Poison.Lesser, Poison.Regular, Poison.Greater, Poison.Deadly, Poison.Lethal }; + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( !BaseCommand.IsAccessible( from, m_Object ) ) + { + from.SendMessage( "You may no longer access their properties." ); + return; + } + + switch ( info.ButtonID ) + { + case 0: // Closed + { + if ( m_Stack != null && m_Stack.Count > 0 ) + { + object obj = m_Stack.Pop(); + + from.SendGump( new XmlPropertiesGump( from, obj, m_Stack, null ) ); + } + + break; + } + case 1: // Previous + { + if ( m_Page > 0 ) + from.SendGump( new XmlPropertiesGump( from, m_Object, m_Stack, m_List, m_Page - 1 ) ); + + break; + } + case 2: // Next + { + if ( (m_Page + 1) * EntryCount < m_List.Count ) + from.SendGump( new XmlPropertiesGump( from, m_Object, m_Stack, m_List, m_Page + 1 ) ); + + break; + } + default: + { + int index = (m_Page * EntryCount) + (info.ButtonID - 3); + + if ( index >= 0 && index < m_List.Count ) + { + PropertyInfo prop = m_List[index] as PropertyInfo; + + if ( prop == null ) + return; + + CPA attr = GetCPA( prop ); + + if ( !prop.CanWrite || attr == null || from.AccessLevel < attr.WriteLevel ) + return; + + Type type = prop.PropertyType; + + if ( IsType( type, typeofMobile ) || IsType( type, typeofItem ) ) + from.SendGump( new XmlSetObjectGump( prop, from, m_Object, m_Stack, type, m_Page, m_List ) ); + else if ( IsType( type, typeofType ) ) + from.Target = new XmlSetObjectTarget( prop, from, m_Object, m_Stack, type, m_Page, m_List ); + else if ( IsType( type, typeofPoint3D ) ) + from.SendGump( new XmlSetPoint3DGump( prop, from, m_Object, m_Stack, m_Page, m_List ) ); + else if ( IsType( type, typeofPoint2D ) ) + from.SendGump( new XmlSetPoint2DGump( prop, from, m_Object, m_Stack, m_Page, m_List ) ); + else if ( IsType( type, typeofTimeSpan ) ) + from.SendGump( new XmlSetTimeSpanGump( prop, from, m_Object, m_Stack, m_Page, m_List ) ); + else if ( IsCustomEnum( type ) ) + from.SendGump( new XmlSetCustomEnumGump( prop, from, m_Object, m_Stack, m_Page, m_List, GetCustomEnumNames( type ) ) ); + else if ( IsType( type, typeofEnum ) ) + from.SendGump( new XmlSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, Enum.GetNames( type ), GetObjects( Enum.GetValues( type ) ) ) ); + else if ( IsType( type, typeofBool ) ) + from.SendGump( new XmlSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, m_BoolNames, m_BoolValues ) ); + else if ( IsType( type, typeofString ) || IsType( type, typeofReal ) || IsType( type, typeofNumeric ) ) + from.SendGump( new XmlSetGump( prop, from, m_Object, m_Stack, m_Page, m_List ) ); + else if ( IsType( type, typeofPoison ) ) + from.SendGump( new XmlSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, m_PoisonNames, m_PoisonValues ) ); + else if ( IsType( type, typeofMap ) ) + from.SendGump( new XmlSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, Map.GetMapNames(), Map.GetMapValues() ) ); + else if ( IsType( type, typeofSkills ) && m_Object is Mobile ) + { + from.SendGump( new XmlPropertiesGump( from, m_Object, m_Stack, m_List, m_Page ) ); + from.SendGump( new SkillsGump( from, (Mobile)m_Object ) ); + } + else if ( HasAttribute( type, typeofPropertyObject, true ) ) + from.SendGump( new XmlPropertiesGump( from, prop.GetValue( m_Object, null ), m_Stack, m_Object ) ); + } + + break; + } + } + } + + private static object[] GetObjects( Array a ) + { + object[] list = new object[a.Length]; + + for ( int i = 0; i < list.Length; ++i ) + list[i] = a.GetValue( i ); + + return list; + } + + private static bool IsCustomEnum( Type type ) + { + return type.IsDefined( typeofCustomEnum, false ); + } + + private static string[] GetCustomEnumNames( Type type ) + { + object[] attrs = type.GetCustomAttributes( typeofCustomEnum, false ); + + if ( attrs.Length == 0 ) + return new string[0]; + + CustomEnumAttribute ce = attrs[0] as CustomEnumAttribute; + + if ( ce == null ) + return new string[0]; + + return ce.Names; + } + + private static bool HasAttribute( Type type, Type check, bool inherit ) + { + object[] objs = type.GetCustomAttributes( check, inherit ); + + return ( objs != null && objs.Length > 0 ); + } + + private static bool IsType( Type type, Type check ) + { + return type == check || type.IsSubclassOf( check ); + } + + private static bool IsType( Type type, Type[] check ) + { + for ( int i = 0; i < check.Length; ++i ) + if ( IsType( type, check[i] ) ) + return true; + + return false; + } + + private static Type typeofMobile = typeof( Mobile ); + private static Type typeofItem = typeof( Item ); + private static Type typeofType = typeof( Type ); + private static Type typeofPoint3D = typeof( Point3D ); + private static Type typeofPoint2D = typeof( Point2D ); + private static Type typeofTimeSpan = typeof( TimeSpan ); + private static Type typeofCustomEnum = typeof( CustomEnumAttribute ); + private static Type typeofEnum = typeof( Enum ); + private static Type typeofBool = typeof( Boolean ); + private static Type typeofString = typeof( String ); + private static Type typeofPoison = typeof( Poison ); + private static Type typeofMap = typeof( Map ); + private static Type typeofSkills = typeof( Skills ); + private static Type typeofPropertyObject = typeof( PropertyObjectAttribute ); + private static Type typeofNoSort = typeof( NoSortAttribute ); + + private static Type[] typeofReal = new Type[] + { + typeof( Single ), + typeof( Double ) + }; + + private static Type[] typeofNumeric = new Type[] + { + typeof( Byte ), + typeof( Int16 ), + typeof( Int32 ), + typeof( Int64 ), + typeof( SByte ), + typeof( UInt16 ), + typeof( UInt32 ), + typeof( UInt64 ) + }; + + private string ValueToString( PropertyInfo prop ) + { + return ValueToString( m_Object, prop ); + } + + public static string ValueToString( object obj, PropertyInfo prop ) + { + try + { + return ValueToString( prop.GetValue( obj, null ) ); + } + catch ( Exception e ) + { + return String.Format( "!{0}!", e.GetType() ); + } + } + + public static string ValueToString( object o ) + { + if ( o == null ) + { + return "-null-"; + } + else if ( o is string ) + { + return String.Format( "\"{0}\"", (string)o ); + } + else if ( o is bool ) + { + return o.ToString(); + } + else if ( o is char ) + { + return String.Format( "0x{0:X} '{1}'", (int)(char)o, (char)o ); + } + else if ( o is Serial ) + { + Serial s = (Serial)o; + + if ( s.IsValid ) + { + if ( s.IsItem ) + { + return String.Format( "(I) 0x{0:X}", s.Value ); + } + else if ( s.IsMobile ) + { + return String.Format( "(M) 0x{0:X}", s.Value ); + } + } + + return String.Format( "(?) 0x{0:X}", s.Value ); + } + else if ( o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong ) + { + return String.Format( "{0} (0x{0:X})", o ); + } + else if ( o is double ) + { + return o.ToString(); + } + else if ( o is Mobile ) + { + return String.Format( "(M) 0x{0:X} \"{1}\"", ((Mobile)o).Serial.Value, ((Mobile)o).Name ); + } + else if ( o is Item ) + { + return String.Format( "(I) 0x{0:X}", ((Item)o).Serial ); + } + else if ( o is Type ) + { + return ((Type)o).Name; + } + else + { + return o.ToString(); + } + } + + private ArrayList BuildList() + { + Type type = m_Object.GetType(); + + PropertyInfo[] props = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public ); + + ArrayList groups = GetGroups( type, props ); + ArrayList list = new ArrayList(); + + for ( int i = 0; i < groups.Count; ++i ) + { + DictionaryEntry de = (DictionaryEntry)groups[i]; + ArrayList groupList = (ArrayList)de.Value; + + if ( !HasAttribute( (Type)de.Key, typeofNoSort, false ) ) + groupList.Sort( PropertySorter.Instance ); + + if ( i != 0 ) + list.Add( null ); + + list.Add( de.Key ); + list.AddRange( groupList ); + } + + return list; + } + + private static Type typeofCPA = typeof( CPA ); + private static Type typeofObject = typeof( object ); + + private static CPA GetCPA( PropertyInfo prop ) + { + object[] attrs = prop.GetCustomAttributes( typeofCPA, false ); + + if ( attrs.Length > 0 ) + return attrs[0] as CPA; + else + return null; + } + + private ArrayList GetGroups( Type objectType, PropertyInfo[] props ) + { + Hashtable groups = new Hashtable(); + + for ( int i = 0; i < props.Length; ++i ) + { + PropertyInfo prop = props[i]; + + if ( prop.CanRead ) + { + CPA attr = GetCPA( prop ); + + if ( attr != null && m_Mobile.AccessLevel >= attr.ReadLevel ) + { + Type type = prop.DeclaringType; + + while ( true ) + { + Type baseType = type.BaseType; + + if ( baseType == null || baseType == typeofObject ) + break; + + if ( baseType.GetProperty( prop.Name, prop.PropertyType ) != null ) + type = baseType; + else + break; + } + + ArrayList list = (ArrayList)groups[type]; + + if ( list == null ) + groups[type] = list = new ArrayList(); + + list.Add( prop ); + } + } + } + + ArrayList sorted = new ArrayList( groups ); + + sorted.Sort( new GroupComparer( objectType ) ); + + return sorted; + } + + public static object GetObjectFromString( Type t, string s ) + { + if ( t == typeof( string ) ) + { + return s; + } + else if ( t == typeof( byte ) || t == typeof( sbyte ) || t == typeof( short ) || t == typeof( ushort ) || t == typeof( int ) || t == typeof( uint ) || t == typeof( long ) || t == typeof( ulong ) ) + { + if ( s.StartsWith( "0x" ) ) + { + if ( t == typeof( ulong ) || t == typeof( uint ) || t == typeof( ushort ) || t == typeof( byte ) ) + { + return Convert.ChangeType( Convert.ToUInt64( s.Substring( 2 ), 16 ), t ); + } + else + { + return Convert.ChangeType( Convert.ToInt64( s.Substring( 2 ), 16 ), t ); + } + } + else + { + return Convert.ChangeType( s, t ); + } + } + else if ( t == typeof( double ) || t == typeof( float ) ) + { + return Convert.ChangeType( s, t ); + } + else if ( t.IsDefined( typeof( ParsableAttribute ), false ) ) + { + MethodInfo parseMethod = t.GetMethod( "Parse", new Type[]{ typeof( string ) } ); + + return parseMethod.Invoke( null, new object[]{ s } ); + } + + throw new Exception( "bad" ); + } + + private static string GetStringFromObject( object o ) + { + if ( o == null ) + { + return "-null-"; + } + else if ( o is string ) + { + return String.Format( "\"{0}\"", (string)o ); + } + else if ( o is bool ) + { + return o.ToString(); + } + else if ( o is char ) + { + return String.Format( "0x{0:X} '{1}'", (int)(char)o, (char)o ); + } + else if ( o is Serial ) + { + Serial s = (Serial)o; + + if ( s.IsValid ) + { + if ( s.IsItem ) + { + return String.Format( "(I) 0x{0:X}", s.Value ); + } + else if ( s.IsMobile ) + { + return String.Format( "(M) 0x{0:X}", s.Value ); + } + } + + return String.Format( "(?) 0x{0:X}", s.Value ); + } + else if ( o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong ) + { + return String.Format( "{0} (0x{0:X})", o ); + } + else if ( o is Mobile ) + { + return String.Format( "(M) 0x{0:X} \"{1}\"", ((Mobile)o).Serial.Value, ((Mobile)o).Name ); + } + else if ( o is Item ) + { + return String.Format( "(I) 0x{0:X}", ((Item)o).Serial ); + } + else if ( o is Type ) + { + return ((Type)o).Name; + } + else + { + return o.ToString(); + } + } + + private class PropertySorter : IComparer + { + public static readonly PropertySorter Instance = new PropertySorter(); + + private PropertySorter() + { + } + + public int Compare( object x, object y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + PropertyInfo a = x as PropertyInfo; + PropertyInfo b = y as PropertyInfo; + + if ( a == null || b == null ) + throw new ArgumentException(); + + return a.Name.CompareTo( b.Name ); + } + } + + private class GroupComparer : IComparer + { + private Type m_Start; + + public GroupComparer( Type start ) + { + m_Start = start; + } + + private static Type typeofObject = typeof( Object ); + + private int GetDistance( Type type ) + { + Type current = m_Start; + + int dist; + + for ( dist = 0; current != null && current != typeofObject && current != type; ++dist ) + current = current.BaseType; + + return dist; + } + + public int Compare( object x, object y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + if ( !(x is DictionaryEntry) || !(y is DictionaryEntry) ) + throw new ArgumentException(); + + DictionaryEntry de1 = (DictionaryEntry)x; + DictionaryEntry de2 = (DictionaryEntry)y; + + Type a = (Type)de1.Key; + Type b = (Type)de2.Key; + + return GetDistance( a ).CompareTo( GetDistance( b ) ); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetCustomEnumGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetCustomEnumGump.cs new file mode 100644 index 0000000..b75de0c --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetCustomEnumGump.cs @@ -0,0 +1,46 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetCustomEnumGump : XmlSetListOptionGump + { + private string[] m_Names; + + public XmlSetCustomEnumGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int propspage, ArrayList list, string[] names ) : base( prop, mobile, o, stack, propspage, list, names, null ) + { + m_Names = names; + } + + public override void OnResponse( NetState sender, RelayInfo relayInfo ) + { + int index = relayInfo.ButtonID - 1; + + if ( index >= 0 && index < m_Names.Length ) + { + try + { + MethodInfo info = m_Property.PropertyType.GetMethod( "Parse", new Type[]{ typeof( string ) } ); + + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, m_Names[index] ); + + if ( info != null ) + m_Property.SetValue( m_Object, info.Invoke( null, new object[]{ m_Names[index] } ), null ); + else if ( m_Property.PropertyType == typeof( Enum ) || m_Property.PropertyType.IsSubclassOf( typeof( Enum ) ) ) + m_Property.SetValue( m_Object, Enum.Parse( m_Property.PropertyType, m_Names[index], false ), null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetGump.cs new file mode 100644 index 0000000..021a394 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetGump.cs @@ -0,0 +1,284 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.HuePickers; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (2 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + bool canNull = !prop.PropertyType.IsValueType; + bool canDye = prop.IsDefined( typeof( HueAttribute ), false ); + bool isBody = prop.IsDefined( typeof( BodyAttribute ), false ); + + int xextend = 0; + if(prop.PropertyType == typeof(string)) + { + xextend = 300; + } + + object val = prop.GetValue( m_Object, null ); + string initialText; + + if ( val == null ) + initialText = ""; + else + initialText = val.ToString(); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth+xextend, BackHeight + (canNull ? (EntryHeight + OffsetSize) : 0) + (canDye ? (EntryHeight + OffsetSize) : 0) + (isBody ? (EntryHeight + OffsetSize) : 0), BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth+xextend - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight + (canNull ? (EntryHeight + OffsetSize) : 0) + (canDye ? (EntryHeight + OffsetSize) : 0) + (isBody ? (EntryHeight + OffsetSize) : 0), OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth+xextend, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth+xextend - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth+xextend + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth+xextend, EntryHeight, EntryGumpID ); + AddTextEntry( x + TextOffsetX, y, EntryWidth+xextend - TextOffsetX, EntryHeight, TextHue, 0, initialText ); + x += EntryWidth+xextend + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( canNull ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth+xextend, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth+xextend - TextOffsetX, EntryHeight, TextHue, "Null" ); + x += EntryWidth+xextend + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + } + + if ( canDye ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth+xextend, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth+xextend - TextOffsetX, EntryHeight, TextHue, "Hue Picker" ); + x += EntryWidth+xextend + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + } + + if ( isBody ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth+xextend, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth+xextend - TextOffsetX, EntryHeight, TextHue, "Body Picker" ); + x += EntryWidth+xextend + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 4, GumpButtonType.Reply, 0 ); + } + } + + private class InternalPicker : HuePicker + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public InternalPicker( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( ((IHued)o).HuedItemID ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + public override void OnResponse( int hue ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, hue.ToString() ); + m_Property.SetValue( m_Object, hue, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + object toSet; + bool shouldSet, shouldSend = true; + + switch ( info.ButtonID ) + { + case 1: + { + TextRelay text = info.GetTextEntry( 0 ); + + if ( text != null ) + { + try + { + toSet = XmlPropertiesGump.GetObjectFromString( m_Property.PropertyType, text.Text ); + shouldSet = true; + } + catch + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage( "Bad format" ); + } + } + else + { + toSet = null; + shouldSet = false; + } + + break; + } + case 2: // Null + { + toSet = null; + shouldSet = true; + + break; + } + case 3: // Hue Picker + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendHuePicker( new InternalPicker( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ) ); + + break; + } + case 4: // Body Picker + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendGump( new SetBodyGump( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ) ); + + break; + } + default: + { + toSet = null; + shouldSet = false; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet==null?"(null)":toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetListOptionGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetListOptionGump.cs new file mode 100644 index 0000000..ca7976d --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetListOptionGump.cs @@ -0,0 +1,183 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetListOptionGump : Gump + { + protected PropertyInfo m_Property; + protected Mobile m_Mobile; + protected object m_Object; + protected Stack m_Stack; + protected int m_Page; + protected ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + private static readonly int EntryCount = 13; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + + private static bool PrevLabel = OldStyle, NextLabel = OldStyle; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + protected object[] m_Values; + + public XmlSetListOptionGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int propspage, ArrayList list, string[] names, object[] values ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = propspage; + m_List = list; + + m_Values = values; + + int pages = (names.Length + EntryCount - 1) / EntryCount; + int index = 0; + + for ( int page = 1; page <= pages; ++page ) + { + AddPage( page ); + + int start = (page - 1) * EntryCount; + int count = names.Length - start; + + if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((count + 2) * (EntryHeight + OffsetSize)); + int backHeight = BorderSize + totalHeight + BorderSize; + + AddBackground( 0, 0, BackWidth, backHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0); + + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 1 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 0, GumpButtonType.Page, page - 1 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, HeaderGumpID ); + + x += emptyWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( page < pages ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 0, GumpButtonType.Page, page + 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + + + AddRect( 0, prop.Name, 0 ); + + for ( int i = 0; i < count; ++i ) + AddRect( i + 1, names[index], ++index ); + } + } + + private void AddRect( int index, string str, int button ) + { + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize + ((index + 1) * (EntryHeight + OffsetSize)); + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( button != 0 ) + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, button, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_Values.Length ) + { + try + { + object toSet = m_Values[index]; + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, (toSet == null ? "(-null-)" : toSet.ToString()) ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetObjectGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetObjectGump.cs new file mode 100644 index 0000000..6980961 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetObjectGump.cs @@ -0,0 +1,307 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Prompts; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetObjectGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private Type m_Type; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (5 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + + public XmlSetObjectGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + + string initialText = XmlPropertiesGump.ValueToString( o, prop ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, initialText ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Change by Serial" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Nullify" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "View Properties" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 4, GumpButtonType.Reply, 0 ); + } + + private class InternalPrompt : Prompt + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private Type m_Type; + private int m_Page; + private ArrayList m_List; + + public InternalPrompt( PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + } + + public override void OnCancel( Mobile from ) + { + m_Mobile.SendGump( new XmlSetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + object toSet; + bool shouldSet; + + try + { + int serial = Utility.ToInt32( text ); + + toSet = World.FindEntity( serial ); + + if ( toSet == null ) + { + shouldSet = false; + m_Mobile.SendMessage( "No object with that serial was found." ); + } + else if ( !m_Type.IsAssignableFrom( toSet.GetType() ) ) + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage( "The object with that serial could not be assigned to a property of type : {0}", m_Type.Name ); + } + else + { + shouldSet = true; + } + } + catch + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage( "Bad format" ); + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet==null?"(null)":toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + m_Mobile.SendGump( new XmlSetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + object toSet; + bool shouldSet, shouldSend = true; + object viewProps = null; + + switch ( info.ButtonID ) + { + case 0: // closed + { + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + + toSet = null; + shouldSet = false; + shouldSend = false; + + break; + } + case 1: // Change by Target + { + m_Mobile.Target = new XmlSetObjectTarget( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ); + toSet = null; + shouldSet = false; + shouldSend = false; + break; + } + case 2: // Change by Serial + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendMessage( "Enter the serial you wish to find:" ); + m_Mobile.Prompt = new InternalPrompt( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ); + + break; + } + case 3: // Nullify + { + toSet = null; + shouldSet = true; + + break; + } + case 4: // View Properties + { + toSet = null; + shouldSet = false; + + object obj = m_Property.GetValue( m_Object, null ); + + if ( obj == null ) + m_Mobile.SendMessage( "The property is null and so you cannot view its properties." ); + else if ( !BaseCommand.IsAccessible( m_Mobile, obj ) ) + m_Mobile.SendMessage( "You may not view their properties." ); + else + viewProps = obj; + + break; + } + default: + { + toSet = null; + shouldSet = false; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet==null?"(null)":toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new XmlSetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + + if ( viewProps != null ) + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, viewProps ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetObjectTarget.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetObjectTarget.cs new file mode 100644 index 0000000..f014c23 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetObjectTarget.cs @@ -0,0 +1,66 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetObjectTarget : Target + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private Type m_Type; + private int m_Page; + private ArrayList m_List; + + public XmlSetObjectTarget( PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list ) : base( -1, false, TargetFlags.None ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + try + { + if ( m_Type == typeof( Type ) ) + targeted = targeted.GetType(); + else if ( (m_Type == typeof( BaseAddon ) || m_Type.IsAssignableFrom( typeof( BaseAddon ) )) && targeted is AddonComponent ) + targeted = ((AddonComponent)targeted).Addon; + + if ( m_Type.IsAssignableFrom( targeted.GetType() ) ) + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, targeted.ToString() ); + m_Property.SetValue( m_Object, targeted, null ); + } + else + { + m_Mobile.SendMessage( "That cannot be assigned to a property of type : {0}", m_Type.Name ); + } + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_Type == typeof( Type ) ) + from.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + else + from.SendGump( new XmlSetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetPoint2DGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetPoint2DGump.cs new file mode 100644 index 0000000..2eb1a34 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetPoint2DGump.cs @@ -0,0 +1,236 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetPoint2DGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int CoordWidth = 105; + private static readonly int EntryWidth = CoordWidth + OffsetSize + CoordWidth; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (4 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetPoint2DGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + Point2D p = (Point2D)prop.GetValue( o, null ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 0, p.X.ToString() ); + x += CoordWidth + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Y:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 1, p.Y.ToString() ); + x += CoordWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + } + + private class InternalTarget : Target + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public InternalTarget( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( -1, true, TargetFlags.None ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p != null ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, new Point2D( p ).ToString() ); + m_Property.SetValue( m_Object, new Point2D( p ), null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Point2D toSet; + bool shouldSet, shouldSend; + + switch ( info.ButtonID ) + { + case 1: // Current location + { + toSet = new Point2D( m_Mobile.Location ); + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // Pick location + { + m_Mobile.Target = new InternalTarget( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ); + + toSet = Point2D.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // Use values + { + TextRelay x = info.GetTextEntry( 0 ); + TextRelay y = info.GetTextEntry( 1 ); + + toSet = new Point2D( x == null ? 0 : Utility.ToInt32( x.Text ), y == null ? 0 : Utility.ToInt32( y.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + default: + { + toSet = Point2D.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetPoint3DGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetPoint3DGump.cs new file mode 100644 index 0000000..4632af2 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetPoint3DGump.cs @@ -0,0 +1,242 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetPoint3DGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int CoordWidth = 70; + private static readonly int EntryWidth = CoordWidth + OffsetSize + CoordWidth + OffsetSize + CoordWidth; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (4 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetPoint3DGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + Point3D p = (Point3D)prop.GetValue( o, null ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 0, p.X.ToString() ); + x += CoordWidth + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Y:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 1, p.Y.ToString() ); + x += CoordWidth + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Z:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 2, p.Z.ToString() ); + x += CoordWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + } + + private class InternalTarget : Target + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public InternalTarget( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( -1, true, TargetFlags.None ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p != null ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, new Point3D( p ).ToString() ); + m_Property.SetValue( m_Object, new Point3D( p ), null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Point3D toSet; + bool shouldSet, shouldSend; + + switch ( info.ButtonID ) + { + case 1: // Current location + { + toSet = m_Mobile.Location; + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // Pick location + { + m_Mobile.Target = new InternalTarget( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ); + + toSet = Point3D.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // Use values + { + TextRelay x = info.GetTextEntry( 0 ); + TextRelay y = info.GetTextEntry( 1 ); + TextRelay z = info.GetTextEntry( 2 ); + + toSet = new Point3D( x == null ? 0 : Utility.ToInt32( x.Text ), y == null ? 0 : Utility.ToInt32( y.Text ), z == null ? 0 : Utility.ToInt32( z.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + default: + { + toSet = Point3D.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetTimeSpanGump.cs b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetTimeSpanGump.cs new file mode 100644 index 0000000..241c811 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlPropsGumps/XmlSetTimeSpanGump.cs @@ -0,0 +1,246 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class XmlSetTimeSpanGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (7 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + + public XmlSetTimeSpanGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + TimeSpan ts = (TimeSpan)prop.GetValue( o, null ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + AddRect( 0, prop.Name, 0, -1 ); + AddRect( 1, ts.ToString(), 0, -1 ); + AddRect( 2, "Zero", 1, -1 ); + AddRect( 3, "From H:M:S", 2, -1 ); + AddRect( 4, "H:", 3, 0 ); + AddRect( 5, "M:", 4, 1 ); + AddRect( 6, "S:", 5, 2 ); + } + + private void AddRect( int index, string str, int button, int text ) + { + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize + (index * (EntryHeight + OffsetSize)); + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str ); + + if ( text != -1 ) + AddTextEntry( x + 16 + TextOffsetX, y, EntryWidth - TextOffsetX - 16, EntryHeight, TextHue, text, "" ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( button != 0 ) + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, button, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + TimeSpan toSet; + bool shouldSet, shouldSend; + + TextRelay h = info.GetTextEntry( 0 ); + TextRelay m = info.GetTextEntry( 1 ); + TextRelay s = info.GetTextEntry( 2 ); + + switch ( info.ButtonID ) + { + case 1: // Zero + { + toSet = TimeSpan.Zero; + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // From H:M:S + { + if ( h != null && m != null && s != null ) + { + try + { + toSet = TimeSpan.Parse( h.Text + ":" + m.Text + ":" + s.Text ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // From H + { + if ( h != null ) + { + try + { + toSet = TimeSpan.FromHours( Utility.ToDouble( h.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 4: // From M + { + if ( m != null ) + { + try + { + toSet = TimeSpan.FromMinutes( Utility.ToDouble( m.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 5: // From S + { + if ( s != null ) + { + try + { + toSet = TimeSpan.FromSeconds( Utility.ToDouble( s.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + default: + { + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new XmlPropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/QuestLeadersBoard.cs b/Scripts/Customs/XML Spawner/XmlQuest/QuestLeadersBoard.cs new file mode 100644 index 0000000..af48159 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/QuestLeadersBoard.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Gumps; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + [Flipable( 0x1E5E, 0x1E5F )] + public class QuestLeadersBoard : Item + { + + public QuestLeadersBoard( Serial serial ) : base( serial ) + { + } + + [Constructable] + public QuestLeadersBoard() : base( 0x1e5e ) + { + Movable = false; + Name = "Quest Leaders Board"; + } + + public override void OnDoubleClick( Mobile from ) + { + + from.SendGump( new XmlQuestLeaders.TopQuestPlayersGump( XmlAttach.FindAttachment(from,typeof(XmlQuestPoints)) as XmlQuestPoints) ); + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + } + } +} + diff --git a/Scripts/Customs/XML Spawner/XmlQuest/QuestLeadersStone.cs b/Scripts/Customs/XML Spawner/XmlQuest/QuestLeadersStone.cs new file mode 100644 index 0000000..58e6ceb --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/QuestLeadersStone.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using System.Collections; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Engines.XmlSpawner2 +{ + public class QuestLeadersStone: Item + { + + [Constructable] + public QuestLeadersStone() : base( 0xED4) + { + Movable = false; + Visible = false; + Name = "Quest LeaderboardSave Stone"; + + // is there already another? + ArrayList dlist = new ArrayList(); + foreach( Item i in World.Items.Values) + { + if(i is QuestLeadersStone && i != this) + { + dlist.Add(i); + } + } + foreach(Item d in dlist) + { + d.Delete(); + } + } + + public QuestLeadersStone( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile m ) + { + if( m != null && m.AccessLevel >= AccessLevel.Administrator) + { + CommandEventArgs e = new CommandEventArgs(m, "", "", new string[0]); + XmlQuestLeaders.QuestLeaderboardSave_OnCommand(e); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + XmlQuestLeaders.QuestLBSSerialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + XmlQuestLeaders.QuestLBSDeserialize( reader ); + + int version = reader.ReadInt(); + + // version 0 + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/QuestLogGump.cs b/Scripts/Customs/XML Spawner/XmlQuest/QuestLogGump.cs new file mode 100644 index 0000000..50f4f59 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/QuestLogGump.cs @@ -0,0 +1,418 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Prompts; +using Server.Engines.XmlSpawner2; + +// +// XmlLogGump +// modified from RC0 BOBGump.cs +// +namespace Server.Gumps +{ + public class XMLQuestLogGump : Gump + { + private Mobile m_From; + + private ArrayList m_List; + + private int m_Page; + + private const int LabelColor = 0x7FFF; + + public int GetIndexForPage( int page ) + { + int index = 0; + + while ( page-- > 0 ) + index += GetCountForIndex( index ); + + return index; + } + + public int GetCountForIndex( int index ) + { + int slots = 0; + int count = 0; + + ArrayList list = m_List; + + for ( int i = index; i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + int add; + + add = 1; + + if ( (slots + add) > 10 ) + break; + + slots += add; + + ++count; + } + + return count; + } + + + public XMLQuestLogGump(Mobile from) + : this(from, 0, null) + { + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if(info == null || m_From == null) return; + + switch ( info.ButtonID ) + { + case 0: // EXIT + { + break; + } + + case 2: // Previous page + { + if ( m_Page > 0 ) + m_From.SendGump(new XMLQuestLogGump(m_From, m_Page - 1, m_List)); + + return; + } + case 3: // Next page + { + if ( GetIndexForPage( m_Page + 1 ) < m_List.Count ) + m_From.SendGump(new XMLQuestLogGump(m_From, m_Page + 1, m_List)); + + break; + } + case 10: // Top players + { + // if this player has an XmlQuestPoints attachment, find it + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(m_From,typeof(XmlQuestPoints)); + + m_From.CloseGump(typeof(XmlQuestLeaders.TopQuestPlayersGump)); + m_From.SendGump(new XmlQuestLeaders.TopQuestPlayersGump(p)); + + break; + } + + + default: + { + if ( info.ButtonID >= 2000 ) + { + int index = info.ButtonID - 2000; + + if ( index < 0 || index >= m_List.Count ) + break; + + if(m_List[index] is IXmlQuest) + { + IXmlQuest o = m_List[index] as IXmlQuest; + + if(o != null && !o.Deleted){ + m_From.SendGump( new XMLQuestLogGump( m_From, m_Page, null ) ); + m_From.CloseGump( typeof( XmlQuestStatusGump ) ); + m_From.SendGump( new XmlQuestStatusGump(o, o.TitleString, 320, 0, true) ); + } + } + } + + break; + } + } + } + + + public XMLQuestLogGump( Mobile from, int page, ArrayList list ) : base( 12, 24 ) + { + if(from == null) return; + + from.CloseGump( typeof( XMLQuestLogGump ) ); + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(from, typeof(XmlQuestPoints)); + + m_From = from; + m_Page = page; + + if ( list == null ) + { + // make a new list based on the number of items in the book + int nquests = 0; + list = new ArrayList( ); + + // find all quest items in the players pack + if(from.Backpack != null) + { + Item [] packquestitems = from.Backpack.FindItemsByType(typeof(IXmlQuest)); + + if (packquestitems != null) + { + nquests += packquestitems.Length; + for ( int i = 0; i < packquestitems.Length; ++i ) + { + if(packquestitems[i] != null && !packquestitems[i].Deleted && !(packquestitems[i].Parent is XmlQuestBook)) + list.Add( packquestitems[i] ); + } + } + + // find any questbooks they might have + Item [] questbookitems = from.Backpack.FindItemsByType(typeof(XmlQuestBook)); + + if(questbookitems != null) + { + + for ( int j = 0; j < questbookitems.Length; ++j ) + { + Item [] questitems = ((XmlQuestBook)questbookitems[j]).FindItemsByType(typeof(IXmlQuest)); + + if(questitems != null) + { + nquests += questitems.Length; + + for ( int i = 0; i < questitems.Length; ++i ) + { + list.Add( questitems[i] ); + } + } + } + } + + // find any completed quests on the XmlQuestPoints attachment + + if(p != null && p.QuestList != null) + { + // add all completed quests + foreach(XmlQuestPoints.QuestEntry q in p.QuestList) + { + list.Add(q); + } + } + } + + } + + m_List = list; + + int index = GetIndexForPage( page ); + int count = GetCountForIndex( index ); + + int tableIndex = 0; + + int width = 600; + + width = 766; + + X = (824 - width) / 2; + + int xoffset = 20; + + AddPage( 0 ); + + AddBackground( 10, 10, width, 439, 5054 ); + AddImageTiled( 18, 20, width - 17, 420, 2624 ); + + AddImageTiled( 58 - xoffset, 64, 36, 352, 200 ); // open + AddImageTiled( 96 - xoffset, 64, 163, 352, 1416 ); // name + AddImageTiled( 261 - xoffset, 64, 55, 352, 200 ); // type + AddImageTiled( 308 - xoffset, 64, 85, 352, 1416 ); // status + AddImageTiled( 395 - xoffset, 64, 116, 352, 200 ); // expires + + AddImageTiled( 511 - xoffset, 64, 42, 352, 1416 ); // points + AddImageTiled( 555 - xoffset, 64, 175, 352, 200 ); // completed + AddImageTiled( 734 - xoffset, 64, 42, 352, 1416 ); // repeated + + for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + AddImageTiled( 24, 94 + (tableIndex * 32), 489, 2, 2624 ); + + ++tableIndex; + } + + AddAlphaRegion( 18, 20, width - 17, 420 ); + AddImage( 5, 5, 10460 ); + AddImage( width - 15, 5, 10460 ); + AddImage( 5, 424, 10460 ); + AddImage( width - 15, 424, 10460 ); + + AddHtmlLocalized( 375, 25, 200, 30, 1046026, LabelColor, false, false ); // Quest Log + + AddHtmlLocalized( 63 - xoffset, 45, 200, 32, 1072837, LabelColor, false, false ); // Current Points: + + AddHtml( 243 - xoffset, 45, 200, 32, XmlSimpleGump.Color("Available Credits:","FFFFFF"), false, false ); // Your Reward Points: + + AddHtml( 453 - xoffset, 45, 200, 32, XmlSimpleGump.Color("Rank:","FFFFFF"), false, false ); // Rank + + AddHtml( 600 - xoffset, 45, 200, 32, XmlSimpleGump.Color("Quests Completed:","FFFFFF"), false, false ); // Quests completed + + if(p != null) + { + + int pcolor = 53; + AddLabel(170 - xoffset, 45, pcolor, p.Points.ToString()); + AddLabel(350 - xoffset, 45, pcolor, p.Credits.ToString()); + AddLabel(500 - xoffset, 45, pcolor, p.Rank.ToString()); + AddLabel(720 - xoffset, 45, pcolor, p.QuestsCompleted.ToString()); + } + + AddHtmlLocalized( 63 - xoffset, 64, 200, 32, 3000362, LabelColor, false, false ); // Open + AddHtmlLocalized( 147 - xoffset, 64, 200, 32, 3005104, LabelColor, false, false ); // Name + AddHtmlLocalized( 270 - xoffset, 64, 200, 32, 1062213, LabelColor, false, false ); // Type + AddHtmlLocalized( 326 - xoffset, 64, 200, 32, 3000132, LabelColor, false, false ); // Status + AddHtmlLocalized( 429 - xoffset, 64, 200, 32, 1062465, LabelColor, false, false ); // Expires + + AddHtml( 514 - xoffset, 64, 200, 32, XmlSimpleGump.Color("Points","FFFFFF"), false, false ); // Points + AddHtml( 610 - xoffset, 64, 200, 32, XmlSimpleGump.Color("Next Available","FFFFFF"), false, false ); // Next Available + //AddHtmlLocalized( 610 - xoffset, 64, 200, 32, 1046033, LabelColor, false, false ); // Completed + AddHtmlLocalized( 738 - xoffset, 64, 200, 32, 3005020, LabelColor, false, false ); // Repeat + + AddButton( 675 - xoffset, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 710 - xoffset, 416, 120, 20, 1011441, LabelColor, false, false ); // EXIT + + AddButton( 113 - xoffset, 416, 0xFA8, 0xFAA, 10, GumpButtonType.Reply, 0 ); + AddHtml( 150 - xoffset, 416, 200, 32, XmlSimpleGump.Color("Top Players","FFFFFF"), false, false ); // Top players gump + + + tableIndex = 0; + + if ( page > 0 ) + { + AddButton( 225, 416, 4014, 4016, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 260, 416, 150, 20, 1011067, LabelColor, false, false ); // Previous page + } + + if ( GetIndexForPage( page + 1 ) < list.Count ) + { + AddButton( 375, 416, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 410, 416, 150, 20, 1011066, LabelColor, false, false ); // Next page + } + + for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + + if ( obj is IXmlQuest ) + { + IXmlQuest e = (IXmlQuest)obj; + + int y = 96 + (tableIndex++ * 32); + + + AddButton( 60 - xoffset, y + 2, 0xFAB, 0xFAD, 2000 + i, GumpButtonType.Reply, 0 ); // open gump + + + int color; + + if(!e.IsValid) + { + color = 33; + } + else + if(e.IsCompleted) + { + color = 67; + } + else + { + color = 5; + } + + + AddLabel( 100 - xoffset, y, color, (string)e.Name ); + + //AddHtmlLocalized( 315, y, 200, 32, e.IsCompleted ? 1049071 : 1049072, htmlcolor, false, false ); // Completed/Incomplete + AddLabel( 315 - xoffset, y, color, e.IsCompleted ? "Completed" : "In Progress" ); + + // indicate the expiration time + if(e.IsValid) + { + + // do a little parsing of the expiration string to fit it in the space + string substring = e.ExpirationString; + if(e.ExpirationString.IndexOf("Expires in") >= 0) + { + substring = e.ExpirationString.Substring(11); + } + AddLabel( 400 - xoffset, y, color, (string)substring ); + } + else + { + AddLabel( 400 - xoffset, y, color, "No longer valid" ); + } + + if(e.PartyEnabled) + { + + AddLabel( 270 - xoffset, y, color, "Party" ); + //AddHtmlLocalized( 250, y, 200, 32, 3000332, htmlcolor, false, false ); // Party + } + else + { + + AddLabel( 270 - xoffset, y, color, "Solo" ); + } + + AddLabel( 515 - xoffset, y, color, e.Difficulty.ToString() ); + + } + else + if(obj is XmlQuestPoints.QuestEntry) + { + XmlQuestPoints.QuestEntry e = (XmlQuestPoints.QuestEntry)obj; + + int y = 96 + (tableIndex++ * 32); + int color = 67; + + AddLabel( 100 - xoffset, y, color, (string)e.Name ); + + AddLabel( 315 - xoffset, y, color, "Completed" ); + + if(e.PartyEnabled) + { + + AddLabel( 270 - xoffset, y, color, "Party" ); + //AddHtmlLocalized( 250, y, 200, 32, 3000332, htmlcolor, false, false ); // Party + } + else + { + + AddLabel( 270 - xoffset, y, color, "Solo" ); + } + + AddLabel( 515 - xoffset, y, color, e.Difficulty.ToString() ); + + //AddLabel( 560 - xoffset, y, color, e.WhenCompleted.ToString() ); + // determine when the quest can be done again by looking for an xmlquestattachment with the same name + XmlQuestAttachment qa = (XmlQuestAttachment)XmlAttach.FindAttachment(from, typeof(XmlQuestAttachment), e.Name); + if(qa != null) + { + if(qa.Expiration == TimeSpan.Zero) + { + AddLabel( 560 - xoffset, y, color, "Not Repeatable" ); + } + else + { + DateTime nexttime = DateTime.Now + qa.Expiration; + AddLabel( 560 - xoffset, y, color, nexttime.ToString() ); + } + } + else + { + // didnt find one so it can be done again + AddLabel( 560 - xoffset, y, color, "Available Now" ); + } + + AddLabel( 741 - xoffset, y, color, e.TimesCompleted.ToString() ); + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/QuestRewardGump.cs b/Scripts/Customs/XML Spawner/XmlQuest/QuestRewardGump.cs new file mode 100644 index 0000000..f4fa55b --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/QuestRewardGump.cs @@ -0,0 +1,220 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using System.Collections; +using Server.Engines.XmlSpawner2; + +/* +** QuestRewardGump +** ArteGordon +** updated 9/18/05 +** +** Gives out rewards based on the XmlQuestReward reward list entries and the players Credits that are accumulated through quests with the XmlQuestPoints attachment. +** The Gump supports Item, Mobile, and Attachment type rewards. +*/ + +namespace Server.Gumps +{ + public class QuestRewardGump : Gump + { + private ArrayList Rewards; + + private int y_inc = 35; + private int x_creditoffset = 350; + private int x_pointsoffset = 480; + private int maxItemsPerPage = 9; + private int viewpage; + + public QuestRewardGump( Mobile from, int page ) : base( 20, 30 ) + { + + from.CloseGump(typeof(QuestRewardGump)); + + // determine the gump size based on the number of rewards + Rewards = XmlQuestPointsRewards.RewardsList; + + viewpage = page; + + int height = maxItemsPerPage*y_inc + 120; + int width = x_pointsoffset+110; + + /* + if(Rewards != null && Rewards.Count > 0) + { + height = Rewards.Count*y_inc + 120; + } + */ + + AddBackground( 0, 0, width, height, 0xDAC ); + + AddHtml( 40, 20, 350, 50, "Rewards Available for Purchase with QuestPoints Credits", false, false ); + + AddLabel( 400, 20, 0, String.Format("Available Credits: {0}", XmlQuestPoints.GetCredits(from) )); + + //AddButton( 30, height - 35, 0xFB7, 0xFB9, 0, GumpButtonType.Reply, 0 ); + //AddLabel( 70, height - 35, 0, "Close" ); + + // put the page buttons in the lower right corner + if(Rewards != null && Rewards.Count > 0) + { + AddLabel( width - 165, height - 35, 0, String.Format("Page: {0}/{1}", viewpage+1, (int)(Rewards.Count/maxItemsPerPage)+1)); + + // page up and down buttons + AddButton( width - 55, height - 35, 0x15E0, 0x15E4, 13, GumpButtonType.Reply, 0 ); + AddButton( width - 35, height - 35, 0x15E2, 0x15E6, 12, GumpButtonType.Reply, 0 ); + } + + AddLabel( 70, 50, 40, "Reward" ); + AddLabel( x_creditoffset, 50, 40, "Credits" ); + AddLabel( x_pointsoffset, 50, 40, "Min Points" ); + + // display the items with their selection buttons + if(Rewards != null) + { + int y = 50; + for(int i = 0; i < Rewards.Count; i++) + { + if((int)(i/maxItemsPerPage) != viewpage) continue; + + XmlQuestPointsRewards r = Rewards[i] as XmlQuestPointsRewards; + if(r == null) continue; + + y += y_inc; + + int texthue = 0; + + // display the item + if(r.MinPoints > XmlQuestPoints.GetPoints(from)) + { + texthue = 33; + } else + { + // add the selection button + AddButton( 30, y, 0xFA5, 0xFA7, 1000+i, GumpButtonType.Reply, 0 ); + } + + // display the name + AddLabel( 70, y+3, texthue, r.Name); + + // display the cost + AddLabel( x_creditoffset, y+3, texthue, r.Cost.ToString() ); + + + + // display the item + if(r.ItemID > 0) + AddItem(x_creditoffset+60, y, r.ItemID); + + // display the min points requirement + AddLabel( x_pointsoffset, y+3, texthue, r.MinPoints.ToString() ); + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null || Rewards == null) return; + + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 12: + // page up + int nitems = 0; + if(Rewards != null) + nitems = Rewards.Count; + + int page = viewpage+1; + if(page > (int)(nitems/maxItemsPerPage)) + { + page = (int)(nitems/maxItemsPerPage); + } + state.Mobile.SendGump( new QuestRewardGump( state.Mobile, page)); + break; + case 13: + // page down + page = viewpage-1; + if(page < 0) + { + page = 0; + } + state.Mobile.SendGump( new QuestRewardGump( state.Mobile, page)); + break; + default: + { + if(info.ButtonID >= 1000) + { + int selection = info.ButtonID - 1000; + if(selection < Rewards.Count) + { + XmlQuestPointsRewards r = Rewards[selection] as XmlQuestPointsRewards; + + // check the price + if(XmlQuestPoints.HasCredits(from,r.Cost)) + { + // create an instance of the reward type + object o = null; + + try{ + o = Activator.CreateInstance( r.RewardType , r.RewardArgs); + } catch {} + + bool received = true; + + if(o is Item) + { + + // and give them the item + from.AddToBackpack((Item)o); + + } else + if(o is Mobile) + { + + // if it is controllable then set the buyer as master. Note this does not check for control slot limits. + if(o is BaseCreature) + { + BaseCreature b = o as BaseCreature; + b.Controlled = true; + b.ControlMaster = from; + } + + ((Mobile)o).MoveToWorld(from.Location, from.Map); + + } else + if(o is XmlAttachment) + { + XmlAttachment a = o as XmlAttachment; + + XmlAttach.AttachTo(from, a); + + } else + { + from.SendMessage(33, "unable to create {0}.", r.RewardType.Name); + received = false; + } + + // complete the transaction + if(received) + { + // charge them + XmlQuestPoints.TakeCredits(from, r.Cost); + from.SendMessage("You have purchased {0} for {1} credits.", r.Name, r.Cost); + } + } else + { + from.SendMessage("Insufficient Credits for {0}.", r.Name); + } + from.SendGump(new QuestRewardGump(from, viewpage)); + } + } + break; + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/QuestRewardStone.cs b/Scripts/Customs/XML Spawner/XmlQuest/QuestRewardStone.cs new file mode 100644 index 0000000..f54e4e1 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/QuestRewardStone.cs @@ -0,0 +1,50 @@ +using System; +using Server.Gumps; + +/* +** QuestRewardStone +** used to open the QuestPointsRewardGump that allows players to purchase rewards with their XmlQuestPoints Credits. +*/ + +namespace Server.Items +{ + public class QuestRewardStone : Item + { + [Constructable] + public QuestRewardStone() : base( 0xED4 ) + { + Movable = false; + Name = "a Quest Points Reward Stone"; + } + + public QuestRewardStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + { + from.SendGump( new QuestRewardGump( from, 0 ) ); + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlPlayerQuestGump.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlPlayerQuestGump.cs new file mode 100644 index 0000000..4479fe2 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlPlayerQuestGump.cs @@ -0,0 +1,342 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Prompts; +using Server.Targeting; +using Server.Engines.XmlSpawner2; + +// +// XmlPlayerQuestGump +// + +namespace Server.Gumps +{ + public class XmlPlayerQuestGump : Gump + { + private PlayerMobile m_From; + private IXmlQuest m_QuestItem; + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if(info == null || sender == null || sender.Mobile == null) return; + + // read the text entries for the search criteria + TextRelay tr = info.GetTextEntry( 100 ); // quest name + if(tr != null) + m_QuestItem.Name = tr.Text.Trim(); + + tr = info.GetTextEntry( 102 ); // title + if(tr != null) + m_QuestItem.TitleString = tr.Text.Trim(); + + tr = info.GetTextEntry( 103 ); // notestring + if(tr != null) + m_QuestItem.NoteString = tr.Text; + + tr = info.GetTextEntry( 200 ); // objectives + if(tr != null) + m_QuestItem.Objective1 = tr.Text.Trim(); + + tr = info.GetTextEntry( 201 ); + if(tr != null) + m_QuestItem.Objective2 = tr.Text.Trim(); + + tr = info.GetTextEntry( 202 ); + if(tr != null) + m_QuestItem.Objective3 = tr.Text.Trim(); + + tr = info.GetTextEntry( 203 ); + if (tr != null) + m_QuestItem.Objective4 = tr.Text.Trim(); + + tr = info.GetTextEntry( 204 ); + if(tr != null) + m_QuestItem.Objective5 = tr.Text.Trim(); + + tr = info.GetTextEntry( 205 ); + if(tr != null && tr.Text != null && tr.Text.Length > 0) // descriptions + m_QuestItem.Description1 = tr.Text.Trim(); + else + m_QuestItem.Description1 = null; + + tr = info.GetTextEntry( 206 ); + if(tr != null && tr.Text != null && tr.Text.Length > 0) + m_QuestItem.Description2 = tr.Text.Trim(); + else + m_QuestItem.Description2 = null; + + tr = info.GetTextEntry( 207 ); + if(tr != null && tr.Text != null && tr.Text.Length > 0) + m_QuestItem.Description3 = tr.Text.Trim(); + else + m_QuestItem.Description3 = null; + + tr = info.GetTextEntry( 208 ); + if(tr != null && tr.Text != null && tr.Text.Length > 0) + m_QuestItem.Description4 = tr.Text.Trim(); + else + m_QuestItem.Description4 = null; + + tr = info.GetTextEntry( 209 ); + if(tr != null && tr.Text != null && tr.Text.Length > 0) + m_QuestItem.Description5 = tr.Text.Trim(); + else + m_QuestItem.Description5 = null; + + tr = info.GetTextEntry( 210 ); // expiration + if(tr != null && tr.Text != null && tr.Text.Length > 0){ + try{m_QuestItem.Expiration = double.Parse(tr.Text.Trim());} catch{} + } + + // check all of the check boxes + m_QuestItem.PartyEnabled = info.IsSwitched(300); + m_QuestItem.CanSeeReward = info.IsSwitched(301); + + // refresh the time created + m_QuestItem.TimeCreated = DateTime.Now; + + + switch ( info.ButtonID ) + { + case 0: // Okay + { + + break; + } + case 1: // Select Reward + { + sender.Mobile.Target = new RewardTarget(m_QuestItem); + break; + } + case 2: // Select Reward Return + { + sender.Mobile.Target = new ReturnTarget(m_QuestItem); + break; + } + + } + } + + + public XmlPlayerQuestGump( PlayerMobile from, IXmlQuest questitem ) : base( 12, 140 ) + { + + from.CloseGump( typeof( XmlPlayerQuestGump ) ); + + if(from == null || from.Deleted || questitem == null || questitem.Deleted) return; + + m_From = from; + m_QuestItem = questitem; + + int width = 600; + + //width = 516; + + X = (624 - width) / 2; + + AddPage( 0 ); + + AddBackground( 10, 10, width, 439, 5054 ); + AddImageTiled( 18, 20, width - 17, 420, 2624 ); + + AddAlphaRegion( 18, 20, width - 17, 420 ); + AddImage( 5, 5, 10460 ); + AddImage( width - 15, 5, 10460 ); + AddImage( 5, 424, 10460 ); + AddImage( width - 15, 424, 10460 ); + + // add the Quest Title + AddLabel( width/2 - 50, 15, 0x384, "Player Quest Maker" ); + + int y = 35; + + // add the Quest Name + AddLabel( 28, y, 0x384, "Quest Name" ); + string name = questitem.Name; + if(name != null) + { + name = name.Substring(4); + } + AddImageTiled( 26, y + 20, 232, 20, 0xBBC ); + AddTextEntry( 26, y + 20, 250, 20, 0, 100, name ); + + // add the Quest Title + AddLabel( 328, y, 0x384, "Quest Title" ); + AddImageTiled( 306, y + 20, 232, 20, 0xBBC ); + AddTextEntry( 306, y + 20, 230, 20, 0, 102, questitem.TitleString ); + + y += 50; + // add the Quest Text + AddLabel( 28, y, 0x384, "Quest Text" ); + AddImageTiled( 26, y + 20, 532, 80, 0xBBC ); + AddTextEntry( 26, y + 20, 530, 80, 0, 103, questitem.NoteString ); + + y += 110; + // add the Quest Expiration + AddLabel( 28, y, 0x384, "Expiration" ); + AddLabel( 98, y + 20, 0x384, "Hours" ); + AddImageTiled( 26, y + 20, 52, 20, 0xBBC ); + AddTextEntry( 26, y + 20, 50, 20, 0, 210, questitem.Expiration.ToString() ); + + y += 50; + // add the Quest Objectives + AddLabel( 28, y, 0x384, "Quest Objectives" ); + + AddImageTiled( 26, y + 20, 252, 19, 0xBBC ); + AddTextEntry( 26, y + 20, 250, 19, 0, 200, questitem.Objective1 ); + + AddImageTiled( 26, y + 40, 252, 19, 0xBBC ); + AddTextEntry( 26, y + 40, 250, 19, 0, 201, questitem.Objective2 ); + + AddImageTiled( 26, y + 60, 252, 19, 0xBBC ); + AddTextEntry( 26, y + 60, 250, 19, 0, 202, questitem.Objective3 ); + + AddImageTiled( 26, y + 80, 252, 19, 0xBBC ); + AddTextEntry( 26, y + 80, 250, 19, 0, 203, questitem.Objective4 ); + + AddImageTiled( 26, y + 100, 252, 19, 0xBBC ); + AddTextEntry( 26, y + 100, 250, 19, 0, 204, questitem.Objective5 ); + + // add the Quest Objectives + AddLabel( 328, y, 0x384, "Objective Descriptions" ); + AddImageTiled( 306, y + 20, 252, 19, 0xBBC ); + AddTextEntry( 306, y + 20, 250, 19, 0, 205, questitem.Description1 ); + + AddImageTiled( 306, y + 40, 252, 19, 0xBBC ); + AddTextEntry( 306, y + 40, 250, 19, 0, 206, questitem.Description2 ); + + AddImageTiled( 306, y + 60, 252, 19, 0xBBC ); + AddTextEntry( 306, y + 60, 250, 19, 0, 207, questitem.Description3 ); + + AddImageTiled( 306, y + 80, 252, 19, 0xBBC ); + AddTextEntry( 306, y + 80, 250, 19, 0, 208, questitem.Description4 ); + + AddImageTiled( 306, y + 100, 252, 19, 0xBBC ); + AddTextEntry( 306, y + 100, 250, 19, 0, 209, questitem.Description5 ); + + y += 130; + // party enable toggle + AddCheck( 25, y, 0xD2, 0xD3, questitem.PartyEnabled, 300); + AddLabel( 48, y, 0x384, "PartyEnabled" ); + y += 20; + // can see toggle + AddCheck( 25, y, 0xD2, 0xD3, questitem.CanSeeReward, 301); + AddLabel( 48, y, 0x384, "CanSeeReward" ); + + // select reward button + AddButton( 225, y+3, 2103, 2103, 1, GumpButtonType.Reply, 0 ); + AddLabel( 245, y, 0x384, "Select Reward" ); + + // select reward button + AddButton( 375, y+3, 2103, 2103, 2, GumpButtonType.Reply, 0 ); + AddLabel( 395, y, 0x384, "Select Return Container" ); + + + AddButton( 45, 416, 2130, 2129, 0, GumpButtonType.Reply, 0 ); // Okay button + + //AddButton( 375 - xoffset, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 ); + + //AddHtmlLocalized( 410 - xoffset, 416, 120, 20, 1011441, LabelColor, false, false ); // EXIT + + } + + private class RewardTarget : Target + { + IXmlQuest m_QuestItem; + + public RewardTarget(IXmlQuest questitem) : base ( 30, true, TargetFlags.None ) + { + m_QuestItem = questitem; + + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if(m_QuestItem == null || m_QuestItem.Deleted) return; + + // first check to see if you are too far from the return container. This is to avoid exploits involving targeting a container + // then using the return reward feature as a free transport of items back to that container + if(m_QuestItem.ReturnContainer != null && !m_QuestItem.ReturnContainer.Deleted) + { + Point3D returnloc; + + if(m_QuestItem.ReturnContainer.Parent == null) + { + returnloc = m_QuestItem.ReturnContainer.Location; + } else + if(m_QuestItem.ReturnContainer.RootParent != null) + { + + returnloc = ((IEntity)m_QuestItem.ReturnContainer.RootParent).Location; + } else + { + from.SendMessage("Invalid container location"); + return; + } + + if(!Utility.InRange( returnloc, from.Location, 10)) + { + // out of range + from.SendMessage("Too far away from the reward return container"); + return; + } + } + // try to add the item as the reward item + if(m_QuestItem.PlayerMade && (from != null) && !from.Deleted && (from is PlayerMobile) && + (from == m_QuestItem.Creator) && (from == m_QuestItem.Owner) && (targeted is Item) && + !(targeted is IXmlQuest)) + { + Item i = targeted as Item; + + // make sure the target item is in the oweners backpack + if(i != null && !i.Deleted && i.RootParent == m_QuestItem.Owner) + { + m_QuestItem.RewardItem = i; + m_QuestItem.AutoReward = true; + } else + { + from.SendMessage("Targeted item must be in the owners pack"); + } + } + } + } + + private class ReturnTarget : Target + { + IXmlQuest m_QuestItem; + + public ReturnTarget(IXmlQuest questitem) : base ( 30, true, TargetFlags.None ) + { + m_QuestItem = questitem; + + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if(m_QuestItem == null || m_QuestItem.Deleted) return; + + // try to add the item as the reward item + if(m_QuestItem.PlayerMade && (from != null) && !from.Deleted && (from is PlayerMobile) && + (from == m_QuestItem.Creator) && (from == m_QuestItem.Owner) && targeted is Container) + { + Container i = targeted as Container; + + // make sure the target item is in the oweners backpack + if(i != null && !i.Deleted ) + { + m_QuestItem.ReturnContainer = i; + from.SendMessage("Reward return container set"); + + } else + { + from.SendMessage("Targeted item must be a valid container"); + } + } + } + } + } +} + diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuest.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuest.cs new file mode 100644 index 0000000..d49bd2e --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuest.cs @@ -0,0 +1,1593 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server.Targeting; +using Server.Engines.PartySystem; +using System.Data; +using System.Xml; +using Server.Engines.XmlSpawner2; + + +namespace Server.Items +{ + public interface IXmlQuest + { + string Name { get; set; } + + string NoteString { get; set; } + + string TitleString { get; set; } + + string Objective1 { get; set; } + + string Objective2 { get; set; } + + string Objective3 { get; set; } + + string Objective4 { get; set; } + + string Objective5 { get; set; } + + string Description1 { get; set; } + + string Description2 { get; set; } + + string Description3 { get; set; } + + string Description4 { get; set; } + + string Description5 { get; set; } + + bool Completed1 { get; set; } + + bool Completed2 { get; set; } + + bool Completed3 { get; set; } + + bool Completed4 { get; set; } + + bool Completed5 { get; set; } + + string State1 { get; set; } + + string State2 { get; set; } + + string State3 { get; set; } + + string State4 { get; set; } + + string State5 { get; set; } + + bool PlayerMade { get; set; } + + bool PartyEnabled { get; set; } + + int PartyRange { get; set; } + + int Difficulty { get; set; } + + PlayerMobile Owner { get; set; } + + PlayerMobile Creator { get; set; } + + Container ReturnContainer { get; set; } + + Item RewardItem { get; set; } + + XmlAttachment RewardAttachment { get; set; } + + string Status { get; set; } + + string ExpirationString { get; } + + bool CanSeeReward { get; set; } + + bool AutoReward { get; set; } + + bool Repeatable { get; set; } + + bool IsValid { get; } + + bool AlreadyDone { get; } + + bool IsCompleted { get; } + + bool Deleted { get; } + + Container Pack { get; } + + bool HandlesOnSkillUse { get; } + + double Expiration { get; set; } + + DateTime TimeCreated { get; set; } + + void CheckAutoReward(); + + void CheckRewardItem(); + + void Invalidate(); + + void OnSkillUse(Mobile m, Skill skill, bool success); + + ArrayList Journal { get; set; } + + string AddJournalEntry { set;} + + } + + public interface ITemporaryQuestAttachment + { + Mobile QuestOwner { get; set; } + } + + + public abstract class XmlQuest + { + public const PlayerFlag CarriedXmlQuestFlag = (PlayerFlag)0x00100000; + + public const bool QuestPointsEnabled = true; + + public class JournalEntry + { + private string m_EntryID; + private string m_EntryText; + + public string EntryID { get { return m_EntryID; } set { m_EntryID = value; } } + public string EntryText { get { return m_EntryText; } set { m_EntryText = value; } } + + public JournalEntry(string ID, string text) + { + EntryID = ID; + EntryText = text; + } + } + + public class GetCollectTarget : Target + { + IXmlQuest m_quest; + + public GetCollectTarget(IXmlQuest quest) + : base(30, false, TargetFlags.None) + { + m_quest = quest; + } + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item && m_quest != null && !m_quest.Deleted) + { + XmlQuest.Collect(from, (Item)targeted, m_quest); + from.CloseGump(typeof(XmlQuestStatusGump)); + from.SendGump(new XmlQuestStatusGump(m_quest, m_quest.TitleString)); + } + } + } + + public static void QuestButton(QuestGumpRequestArgs e) + { + if (e == null || e.Mobile == null) return; + Mobile from = e.Mobile; + + from.CloseGump(typeof(XMLQuestLogGump)); + // bring up the quest status gump + from.SendGump(new XMLQuestLogGump(from)); + + // bring up the normal quest objectives gump + //NormalQuestButton(from as PlayerMobile); + } + + + public static void QuestButton(NetState state, IEntity e, EncodedReader reader) + { + if (state == null || state.Mobile == null) return; + Mobile from = state.Mobile; + + from.CloseGump(typeof(XMLQuestLogGump)); + // bring up the quest status gump + from.SendGump(new XMLQuestLogGump(from)); + + // bring up the normal quest objectives gump + //NormalQuestButton(from as PlayerMobile); + } + + // this just brings up the normal quest objectives gump + public static void NormalQuestButton(PlayerMobile from) + { + if (from == null || from.Quest == null) return; + + from.Quest.ShowQuestLog(); + } + + public static void RemoveTemporaryQuestObjects(Mobile questowner, string questname) + { + // find all TemporaryQuestObject attachments associated with the owner with the given name, and delete them + + ArrayList list = new ArrayList(); + + foreach (XmlAttachment i in XmlAttach.Values) + { + // check for type + if (i != null && !i.Deleted && i is ITemporaryQuestAttachment && ((ITemporaryQuestAttachment)i).QuestOwner == questowner && i.Name == questname) + { + list.Add(i); + } + } + + foreach (XmlAttachment i in list) + { + i.Delete(); + } + } + + private static void ReturnCollected(IXmlQuest quest, Item item) + { + if (item == null) return; + + // if this was player made, then return the item to the creator + // dont allow players to return items to themselves. This prevents possible exploits where quests are used as + // item transporters + if (quest != null && quest.PlayerMade && (quest.Creator != null) && !quest.Creator.Deleted && (quest.Creator != quest.Owner)) + { + bool returned = false; + if ((quest.ReturnContainer != null) && !quest.ReturnContainer.Deleted) + { + returned = quest.ReturnContainer.TryDropItem(quest.Creator, item, false); + + //ReturnContainer.DropItem(m_RewardItem); + } + if (!returned) + { + quest.Creator.AddToBackpack(item); + } + + quest.Creator.SendMessage("You receive {0} from quest {1}", item.GetType().Name, quest.Name); + } + else + { + // just delete it + item.Delete(); + } + } + + private static void TakeGiven(Mobile to, IXmlQuest quest, Item item) + { + if (item == null) return; + + XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(to, typeof(XmlSaveItem), "Given"); + + if (si == null) + { + XmlAttach.AttachTo(to, new XmlSaveItem("Given", item, quest.Owner)); + } + else + { + si.SavedItem = item; + si.WasOwnedBy = quest.Owner; + } + + // just delete it + //item.Delete(); + } + + + public static object CreateItem(IEntity from, string action, out string status_str, Type typerestrict) + { + status_str = null; + + if (action == null || action.Length <= 0 || from == null) return null; + + XmlSpawner.SpawnObject TheSpawn = new XmlSpawner.SpawnObject(null, 0); + + //BaseXmlSpawner.ApplyObjectStringProperties(null, action, m_TargetItem, m, m_TargetItem, out status_str); + + TheSpawn.TypeName = action; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, null, null, action); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + BaseXmlSpawner.SpawnTypeKeyword(null, TheSpawn, typeName, substitutedtypeName, true, null, from.Location, Map.Internal, out status_str); + } + else + { + // its a regular type descriptor so find out what it is + Type type = SpawnerType.GetType(typeName); + + // if a type restriction has been specified then test it + if (typerestrict != null && type != null && type != typerestrict && !type.IsSubclassOf(typerestrict)) + { + return null; + } + + + try + { + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + object o = XmlSpawner.CreateObject(type, arglist[0], true, true); + + if (o == null) + { + status_str = "invalid type specification: " + arglist[0]; + } + else if (o is Mobile) + { + Mobile m = (Mobile)o; + + // dont do mobiles as rewards at this point + m.Delete(); + } + else if (o is Item) + { + Item item = (Item)o; + BaseXmlSpawner.AddSpawnItem(null, from, TheSpawn, item, from.Location, Map.Internal, null, false, substitutedtypeName, out status_str); + } + else if (o is XmlAttachment) + { + return o; + } + } + catch { } + } + if (TheSpawn.SpawnedObjects.Count > 0) + { + if (TheSpawn.SpawnedObjects[0] is Item) + { + return ((Item)TheSpawn.SpawnedObjects[0]); + } + else if (TheSpawn.SpawnedObjects[0] is Mobile) + { + // dont do mobiles as rewards at this point + ((Mobile)(TheSpawn.SpawnedObjects[0])).Delete(); + } + } + + return null; + } + + public static ArrayList FindXmlQuest(PlayerMobile from) + { + + if (from == null || from.Deleted) return null; + + if (from.Backpack == null) return null; + + List packlist = from.Backpack.Items; + + if (packlist == null) return null; + + ArrayList itemlist = new ArrayList(); + + for (int i = 0; i < packlist.Count; ++i) + { + Item item = (Item)packlist[i]; + + if (item != null && !item.Deleted && item is IXmlQuest) + { + //found it + // add the item to the list + itemlist.Add(item); + + } + // is it an XmlQuestBook? + if (item is XmlQuestBook) + { + XmlQuestBook book = item as XmlQuestBook; + // search the book + foreach (Item xi in book.Items) + { + if (xi != null && !xi.Deleted && xi is IXmlQuest) + { + itemlist.Add(xi); + } + } + } + } + // now check any item that might be held + Item held = from.Holding; + if (held != null && !held.Deleted && held is IXmlQuest) + { + //found it + // add the item to the list + itemlist.Add(held); + } + return itemlist; + } + + public static void CheckArgList(string[] arglist, int argstart, object propobj, out string typestr, out int targetcount, out bool checkprop, out string status_str) + { + targetcount = 1; + checkprop = true; + status_str = null; + typestr = null; + + if (arglist.Length > argstart) + { + // go through the remaining args and determine what they are + for (int i = argstart; i < arglist.Length; i++) + { + // is it a count arg or a prop arg + string[] propargs = BaseXmlSpawner.ParseString(arglist[i], 2, "<>=!"); + if (propargs.Length > 1) + { + // its a prop arg + checkprop = BaseXmlSpawner.CheckPropertyString(null, propobj, arglist[i], null, out status_str); + } + else if (arglist[i] != null && arglist[i].Length > 0 && arglist[i][0] >= '0' && arglist[i][0] <= '9') + { + // its a count arg + try + { + targetcount = int.Parse(arglist[i]); + } + catch { } + + } + else + { + // its a type arg + typestr = arglist[i]; + } + + } + } + } + + + public static void ApplyCollected(Item target, IXmlQuest quest) + { + // check the quest objectives for special COLLECT keywords + string newstatestr; + bool collectstatus = false; + + if (!quest.Completed1 && CheckCollectObjective(quest, target, quest.Objective1, quest.State1, out newstatestr, out collectstatus)) + { + quest.State1 = newstatestr; + quest.Completed1 = collectstatus; + } + else if (!quest.Completed2 && CheckCollectObjective(quest, target, quest.Objective2, quest.State2, out newstatestr, out collectstatus)) + { + quest.State2 = newstatestr; + quest.Completed2 = collectstatus; + } + else if (!quest.Completed3 && CheckCollectObjective(quest, target, quest.Objective3, quest.State3, out newstatestr, out collectstatus)) + { + quest.State3 = newstatestr; + quest.Completed3 = collectstatus; + } + else if (!quest.Completed4 && CheckCollectObjective(quest, target, quest.Objective4, quest.State4, out newstatestr, out collectstatus)) + { + quest.State4 = newstatestr; + quest.Completed4 = collectstatus; + } + else if (!quest.Completed5 && CheckCollectObjective(quest, target, quest.Objective5, quest.State5, out newstatestr, out collectstatus)) + { + quest.State5 = newstatestr; + quest.Completed5 = collectstatus; + + } + if (!quest.Deleted && quest.Owner != null && collectstatus) + { + quest.Owner.SendMessage("Quest objective completed."); + + // check to see if the quest has been completed and there is a reward to be automatically handed out + quest.CheckAutoReward(); + + } + } + + public static void Collect(Mobile m, Item target, IXmlQuest quest) + { + if (quest == null || !quest.IsValid || m != quest.Owner) return; + + // check to see what was dropped onto this + if (target != null && !target.Deleted) + { + // check for party collection + Party p = null; + if (m != null && !m.Deleted && m is PlayerMobile) + { + p = Party.Get(m); + } + + if (quest.PartyEnabled && p != null) + { + // go through all of the party members to find the equivalent quest items and apply the collected target item + // make a randomized order list + ArrayList startlist = new ArrayList(); + ArrayList randlist = new ArrayList(); + + foreach (PartyMemberInfo mi in p.Members) + { + startlist.Add(mi); + } + + while (randlist.Count < p.Members.Count) + { + // pick a random member from the start list + // then take them off the list + int randindex = Utility.Random(startlist.Count); + + randlist.Add(startlist[randindex]); + + startlist.RemoveAt(randindex); + } + + foreach (PartyMemberInfo mi in randlist) + { + Mobile member = mi.Mobile; + + // see if the member is in range + if (quest.PartyRange < 0 || Utility.InRange(m.Location, member.Location, quest.PartyRange)) + { + // find the quest item in their packs + Item questitem = BaseXmlSpawner.SearchMobileForItem(member, quest.Name, "IXmlQuest", false); + + if (questitem != null && !questitem.Deleted && questitem is IXmlQuest) + { + ApplyCollected(target, (IXmlQuest)questitem); + } + } + } + } + else + { + ApplyCollected(target, quest); + } + } + } + + public static bool CheckCollectObjective(IXmlQuest quest, Item item, string objectivestr, string statestr, out string newstatestr, out bool collectstatus) + { + // format for the objective string will be COLLECT,itemtype[,count][,proptest] or COLLECTNAMED,itemname[,itemtype][,count][,proptest] + newstatestr = statestr; + collectstatus = false; + if (objectivestr == null) return false; + + string[] arglist = BaseXmlSpawner.ParseString(objectivestr, 5, ","); + int targetcount = 1; + bool found = false; + bool checkprop = true; + string status_str = null; + + string typestr = null; + + CheckArgList(arglist, 2, item, out typestr, out targetcount, out checkprop, out status_str); + + if (status_str != null) quest.Status = status_str; + + if (arglist.Length > 1) + { + // collect task objective + if (arglist[0] == "COLLECT") + { + //Type targettype = SpawnerType.GetType( arglist[1] ); + // test the collect requirements against the the collected item + if (item != null && !item.Deleted && BaseXmlSpawner.CheckType(item, arglist[1])/*(item.GetType() == targettype)*/ && checkprop) + { + // found a match + found = true; + } + } + else if (arglist[0] == "COLLECTNAMED") + { + if (item != null && !item.Deleted && (arglist[1] == item.Name) && checkprop && + (typestr == null || BaseXmlSpawner.CheckType(item, typestr)) + ) + { + // found a match + found = true; + } + } + } + // update the objective state + if (found) + { + + int current = 0; + try + { + current = int.Parse(statestr); + } + catch { } + // get the current collect count and update it + int added = 0; + if (item.Stackable) + { + if (targetcount - current < item.Amount) + { + added = targetcount - current; + + if (quest != null && quest.PlayerMade) + { + + Item newitem = Mobile.LiftItemDupe(item, item.Amount - added); + //Item newitem = item.Dupe(added); + //if(newitem != null) + //newitem.Amount = added; + ReturnCollected(quest, newitem); + } + else + { + + item.Amount -= added; + } + } + else + { + added = item.Amount; + // if it is a playermade quest then give the item to the creator, otherwise just delete it + ReturnCollected(quest, item); + //item.Delete(); + } + } + else + { + if (targetcount - current > 0) + { + added = 1; + ReturnCollected(quest, item); + //item.Delete(); + } + } + + int collected = current + added; + + newstatestr = String.Format("{0}", collected); + + if (collected >= targetcount) + { + // collecttask completed + collectstatus = true; + } + return true; + } + else + // not a collect task + return false; + } + + public static bool ApplyGiven(Mobile mob, Item target, IXmlQuest quest) + { + + if (mob == null) return false; + + // check the quest objectives for special GIVE keywords + string newstatestr; + bool givestatus = false; + bool found = false; + + if (!quest.Completed1 && CheckGiveObjective(quest, mob, target, quest.Objective1, quest.State1, out newstatestr, out givestatus)) + { + quest.State1 = newstatestr; + quest.Completed1 = givestatus; + found = true; + } + else if (!quest.Completed2 && CheckGiveObjective(quest, mob, target, quest.Objective2, quest.State2, out newstatestr, out givestatus)) + { + quest.State2 = newstatestr; + quest.Completed2 = givestatus; + found = true; + } + else if (!quest.Completed3 && CheckGiveObjective(quest, mob, target, quest.Objective3, quest.State3, out newstatestr, out givestatus)) + { + quest.State3 = newstatestr; + quest.Completed3 = givestatus; + found = true; + } + else if (!quest.Completed4 && CheckGiveObjective(quest, mob, target, quest.Objective4, quest.State4, out newstatestr, out givestatus)) + { + quest.State4 = newstatestr; + quest.Completed4 = givestatus; + found = true; + } + else if (!quest.Completed5 && CheckGiveObjective(quest, mob, target, quest.Objective5, quest.State5, out newstatestr, out givestatus)) + { + quest.State5 = newstatestr; + quest.Completed5 = givestatus; + found = true; + } + + /* + if(found) + { + mob.Say("Thank you."); + } else + { + mob.Say("I have no use for this."); + } + */ + + if (quest.Owner != null && found) + { + quest.Owner.SendMessage("Quest item accepted."); + } + + if (!quest.Deleted && quest.Owner != null && givestatus) + { + quest.Owner.SendMessage("Quest objective completed."); + // check to see if the quest has been completed and there is a reward to be automatically handed out + quest.CheckAutoReward(); + } + + return found; + } + + public static bool Give(Mobile from, Mobile to, Item target, IXmlQuest quest) + { + + if (quest == null || !quest.IsValid) return false; + + bool found = false; + + // check to see what was dropped onto this + if (target != null && !target.Deleted) + { + // check for party collection + Party p = null; + if (from != null && !from.Deleted && from is PlayerMobile) + { + p = Party.Get(from); + } + + if (quest.PartyEnabled && p != null) + { + // go through all of the party members to find the equivalent quest items and apply the collected target item + // make a randomized order list + ArrayList startlist = new ArrayList(); + ArrayList randlist = new ArrayList(); + + foreach (PartyMemberInfo mi in p.Members) + { + startlist.Add(mi); + } + + while (randlist.Count < p.Members.Count) + { + // pick a random member from the start list + // then take them off the list + int randindex = Utility.Random(startlist.Count); + + randlist.Add(startlist[randindex]); + + startlist.RemoveAt(randindex); + } + + foreach (PartyMemberInfo mi in randlist) + { + Mobile member = mi.Mobile; + // see if the member is in range + if (quest.PartyRange < 0 || Utility.InRange(from.Location, member.Location, quest.PartyRange)) + { + // find the quest item in their packs + Item questitem = BaseXmlSpawner.SearchMobileForItem(member, quest.Name, "IXmlQuest", false); + + if (questitem != null && !questitem.Deleted && questitem is IXmlQuest) + { + if (ApplyGiven(to, target, (IXmlQuest)questitem)) + { + found = true; + } + } + } + } + } + else + { + found = ApplyGiven(to, target, quest); + } + } + + return found; + } + + public static bool RegisterGive(Mobile from, Mobile to, Item item) + { + // check to see if this is a quest item that is to be collected + // who is dropping it? + + bool found = false; + + if (item != null && !item.Deleted && from is PlayerMobile) + { + + ArrayList questlist = FindXmlQuest(from as PlayerMobile); + if (questlist != null) + { + // now go through the list and try to apply the dropped item + for (int i = 0; i < questlist.Count; i++) + { + if (questlist[i] is IXmlQuest) + { + if (Give(from, to, item, questlist[i] as IXmlQuest)) + { + found = true; + } + } + } + } + } + + return found; + } + + + public static bool CheckGiveObjective(IXmlQuest quest, Mobile mob, Item item, string objectivestr, string statestr, out string newstatestr, out bool givestatus) + { + // format for the objective string will be GIVE,mobname,itemtype[,count][,proptest] or GIVENAMED,mobname,itemname[,type][,count][,proptest] + newstatestr = statestr; + givestatus = false; + if (objectivestr == null) return false; + + if (mob == null || mob.Name == null) return false; + + string[] arglist = BaseXmlSpawner.ParseString(objectivestr, 6, ","); + int targetcount = 1; + bool found = false; + bool checkprop = true; + string status_str = null; + string typestr = null; + + CheckArgList(arglist, 3, item, out typestr, out targetcount, out checkprop, out status_str); + + if (status_str != null) quest.Status = status_str; + + if (arglist.Length > 1) + { + // the name of the mob must match the specified mobname + if (mob.Name != arglist[1]) return false; + } + + + if (arglist.Length > 2) + { + // collect task objective + if (arglist[0] == "GIVE") + { + //Type targettype = SpawnerType.GetType( arglist[2] ); + + // test the requirements against the the given item + if (item != null && !item.Deleted && BaseXmlSpawner.CheckType(item, arglist[2]) /*(item.GetType() == targettype)*/ && checkprop) + { + // found a match + found = true; + } + } + else if (arglist[0] == "GIVENAMED") + { + if (item != null && !item.Deleted && (arglist[2] == item.Name) && checkprop && + (typestr == null || BaseXmlSpawner.CheckType(item, typestr)) + ) + { + // found a match + found = true; + } + } + } + // update the objective state + if (found) + { + + int current = 0; + try + { + current = int.Parse(statestr); + } + catch { } + // get the current given count and update it + int added = 0; + + if (item.Stackable) + { + if (targetcount - current < item.Amount) + { + added = targetcount - current; + + if (quest != null && quest.PlayerMade) + { + //Item newitem = item.Dupe(added); + Item newitem = Mobile.LiftItemDupe(item, added); + //if(newitem != null) + //newitem.Amount = added; + TakeGiven(mob, quest, newitem); + } + else + { + item.Amount -= added; + } + } + else + { + added = item.Amount; + TakeGiven(mob, quest, item); + //item.Delete(); + } + } + else + { + if (targetcount - current > 0) + { + added = 1; + TakeGiven(mob, quest, item); + //item.Delete(); + } + } + + int collected = current + added; + + newstatestr = String.Format("{0}", collected); + + if (collected >= targetcount) + { + // givetask completed + givestatus = true; + } + + return (added > 0); + + } + else + { + // not a give task + return false; + } + } + + public static bool CheckKillObjective(IXmlQuest quest, Mobile m_killed, Mobile m_killer, string objectivestr, string statestr, out string newstatestr, out bool killstatus) + { + newstatestr = statestr; + killstatus = false; + if (objectivestr == null) return false; + + // format for the objective string will be KILL,mobtype[,count][,proptest] or KILLNAMED,mobname[,type][,count][,proptest] + string[] arglist = BaseXmlSpawner.ParseString(objectivestr, 5, ","); + int targetcount = 1; + bool found = false; + bool checkprop = true; + string status_str = null; + + string typestr = null; + + CheckArgList(arglist, 2, m_killed, out typestr, out targetcount, out checkprop, out status_str); + + if (status_str != null) quest.Status = status_str; + + if (arglist.Length > 1) + { + // kill task objective + if (arglist[0] == "KILL") + { + //Type targettype = SpawnerType.GetType( arglist[1] ); + + // test the kill requirements against the the killed mobile + if (m_killed != null && !m_killed.Deleted && BaseXmlSpawner.CheckType(m_killed, arglist[1])/*(m_killed.GetType() == targettype)*/ && checkprop) + { + // found a match + found = true; + } + } + else if (arglist[0] == "KILLNAMED") + { + if (m_killed != null && !m_killed.Deleted && (arglist[1] == m_killed.Name) && checkprop && + (typestr == null || BaseXmlSpawner.CheckType(m_killed, typestr)) + ) + { + // found a match + found = true; + } + } + } + // update the objective state + if (found) + { + // get the current kill count and update it + int current = 0; + try + { + current = int.Parse(statestr); + } + catch { } + + int killed = current + 1; + newstatestr = String.Format("{0}", killed); + + if (killed >= targetcount) + { + // killtask completed + killstatus = true; ; + } + return true; + } + else + // not a kill task + return false; + } + + public static void ApplyKilled(Mobile m_killed, Mobile m_killer, IXmlQuest quest) + { + if (quest == null || !quest.IsValid) return; + + string newstatestr; + bool killstatus = false; + if (!quest.Completed1 && CheckKillObjective(quest, m_killed, m_killer, quest.Objective1, quest.State1, out newstatestr, out killstatus)) + { + quest.State1 = newstatestr; + quest.Completed1 = killstatus; + } + else if (!quest.Completed2 && CheckKillObjective(quest, m_killed, m_killer, quest.Objective2, quest.State2, out newstatestr, out killstatus)) + { + quest.State2 = newstatestr; + quest.Completed2 = killstatus; + } + else if (!quest.Completed3 && CheckKillObjective(quest, m_killed, m_killer, quest.Objective3, quest.State3, out newstatestr, out killstatus)) + { + quest.State3 = newstatestr; + quest.Completed3 = killstatus; + } + else if (!quest.Completed4 && CheckKillObjective(quest, m_killed, m_killer, quest.Objective4, quest.State4, out newstatestr, out killstatus)) + { + quest.State4 = newstatestr; + quest.Completed4 = killstatus; + } + else if (!quest.Completed5 && CheckKillObjective(quest, m_killed, m_killer, quest.Objective5, quest.State5, out newstatestr, out killstatus)) + { + quest.State5 = newstatestr; + quest.Completed5 = killstatus; + } + if (!quest.Deleted && quest.Owner != null && killstatus) + { + quest.Owner.SendMessage("Quest objective completed."); + // check to see if the quest has been completed and there is a reward to be automatically handed out + quest.CheckAutoReward(); + } + } + + public static void CheckKilled(Mobile m_killed, Mobile m_killer, Mobile member) + { + if (!(member is PlayerMobile)) return; + + // search the player for IXmlQuest objects + ArrayList mobitems = FindXmlQuest(member as PlayerMobile); + + if (mobitems == null) return; + + for (int i = 0; i < mobitems.Count; i++) + { + // search the objects for kill requirements + if (mobitems[i] is IXmlQuest) + { + IXmlQuest quest = (IXmlQuest)(mobitems[i]); + + if (quest != null && !quest.Deleted && quest.PartyEnabled) + { + if (member != null && !member.Deleted) + { + if (quest.PartyRange < 0 || Utility.InRange(m_killer.Location, member.Location, quest.PartyRange)) + ApplyKilled(m_killed, member, quest); + } + } + else if (member != null && !member.Deleted && member == m_killer && quest != null && !quest.Deleted) + { + ApplyKilled(m_killed, m_killer, quest); + } + } + } + } + + + + + public static void RegisterKill(Mobile m_killed, Mobile m_killer) + { + + // check for any attachments that might support the OnBeforeKill method + XmlAttach.CheckOnBeforeKill(m_killed, m_killer); + + // check for any attachments that might support the OnKill method + XmlAttach.CheckOnKill(m_killed, m_killer); + + // go through all of the party members to to try to fill killquest objectives + Party p = Party.Get(m_killer); + if (p != null) + { + foreach (PartyMemberInfo mi in p.Members) + { + Mobile member = mi.Mobile; + if (member != null && member is PlayerMobile && ((PlayerMobile)member).GetFlag(CarriedXmlQuestFlag)) + { + + CheckKilled(m_killed, m_killer, member); + + } + + } + } + else + { + if (m_killer != null && m_killer is PlayerMobile && ((PlayerMobile)m_killer).GetFlag(CarriedXmlQuestFlag)) + { + CheckKilled(m_killed, m_killer, m_killer); + + } + + } + } + + public static bool CheckEscortObjective(IXmlQuest quest, Mobile m_escorted, Mobile m_escorter, string objectivestr, string statestr, out string newstatestr, out bool escortstatus) + { + newstatestr = statestr; + escortstatus = false; + if (objectivestr == null) return false; + // format for the objective string will be ESCORT[,mobname][,proptest] + string[] arglist = BaseXmlSpawner.ParseString(objectivestr, 3, ","); + + if (arglist.Length > 0) + { + // is it an escort task? + if (arglist[0] != "ESCORT") + return false; + } + else + { + return false; + } + + bool found = false; + + int targetcount = 1; + + bool checkprop = true; + string status_str = null; + + if (arglist.Length > 2) + { + checkprop = BaseXmlSpawner.CheckPropertyString(null, m_escorted, arglist[2], null, out status_str); + } + + if (status_str != null) quest.Status = status_str; + + if (arglist.Length > 1) + { + // check the mobname, allow for empty names to match any escort + + if (m_escorted != null && !m_escorted.Deleted && (arglist[1] == m_escorted.Name || (arglist[1] == null || arglist[1] == String.Empty)) && checkprop) + { + // found a match + found = true; + } + + } + else + { + // no mobname so any escort will do + if (m_escorted != null && !m_escorted.Deleted && checkprop) + { + // found a match + found = true; + } + } + + // update the objective state + if (found) + { + // get the current escort count and update it + int current = 0; + try + { + current = int.Parse(statestr); + } + catch { } + + int escorted = current + 1; + + newstatestr = String.Format("{0}", escorted); + + if (escorted >= targetcount) + { + // escort completed + escortstatus = true; ; + } + return true; + } + else + // not an escort task + return false; + } + + public static void ApplyEscorted(Mobile m_escorted, Mobile m_escorter, IXmlQuest quest) + { + if (quest == null || !quest.IsValid) return; + + string newstatestr; + bool escortstatus = false; + if (!quest.Completed1 && CheckEscortObjective(quest, m_escorted, m_escorter, quest.Objective1, quest.State1, out newstatestr, out escortstatus)) + { + quest.State1 = newstatestr; + quest.Completed1 = escortstatus; + } + else if (!quest.Completed2 && CheckEscortObjective(quest, m_escorted, m_escorter, quest.Objective2, quest.State2, out newstatestr, out escortstatus)) + { + quest.State2 = newstatestr; + quest.Completed2 = escortstatus; + } + else if (!quest.Completed3 && CheckEscortObjective(quest, m_escorted, m_escorter, quest.Objective3, quest.State3, out newstatestr, out escortstatus)) + { + quest.State3 = newstatestr; + quest.Completed3 = escortstatus; + } + else if (!quest.Completed4 && CheckEscortObjective(quest, m_escorted, m_escorter, quest.Objective4, quest.State4, out newstatestr, out escortstatus)) + { + quest.State4 = newstatestr; + quest.Completed4 = escortstatus; + } + else if (!quest.Completed5 && CheckEscortObjective(quest, m_escorted, m_escorter, quest.Objective5, quest.State5, out newstatestr, out escortstatus)) + { + quest.State5 = newstatestr; + quest.Completed5 = escortstatus; + } + if (!quest.Deleted && quest.Owner != null && escortstatus) + { + quest.Owner.SendMessage("Quest objective completed."); + // check to see if the quest has been completed and there is a reward to be automatically handed out + quest.CheckAutoReward(); + } + } + + public static void CheckEscorted(Mobile m_escorted, Mobile m_escorter, Mobile member) + { + if (!(member is PlayerMobile)) return; + + // search the player for IXmlQuest objects + ArrayList mobitems = FindXmlQuest(member as PlayerMobile); + + if (mobitems == null) return; + + for (int i = 0; i < mobitems.Count; i++) + { + + if (mobitems[i] is IXmlQuest) + { + // search the objects for escort requirements + IXmlQuest quest = (IXmlQuest)(mobitems[i]); + + + if (quest != null && !quest.Deleted && quest.PartyEnabled) + { + if (member != null && !member.Deleted) + { + if (quest.PartyRange < 0 || Utility.InRange(m_escorter.Location, member.Location, quest.PartyRange)) + { + ApplyEscorted(m_escorted, member, quest); + } + } + } + else if (member != null && !member.Deleted && member == m_escorter && quest != null && !quest.Deleted) + { + ApplyEscorted(m_escorted, m_escorter, quest); + } + } + } + } + + public static void RegisterEscort(Mobile m_escorted, Mobile m_escorter) + { + + // go through all of the party members to to try to fill escort objectives + Party p = Party.Get(m_escorter); + if (p != null) + { + foreach (PartyMemberInfo mi in p.Members) + { + Mobile member = mi.Mobile; + if (member != null && member is PlayerMobile && ((PlayerMobile)member).GetFlag(CarriedXmlQuestFlag)) + { + + CheckEscorted(m_escorted, m_escorter, member); + } + + } + } + else + { + if (m_escorter != null && m_escorter is PlayerMobile && ((PlayerMobile)m_escorter).GetFlag(CarriedXmlQuestFlag)) + { + CheckEscorted(m_escorted, m_escorter, m_escorter); + } + + } + } + + public static Hashtable VisitSectorList = new Hashtable(); + + public static void RegisterMove(PlayerMobile m_player) + { + + if (m_player == null || m_player.Map == null) return; + + // check for any attachments that might support the OnMove method + //XmlAttach.CheckOnMove(m_player); + + // check to see if the current sector that the player is in, is registered in the VISIT sector list + Sector newSector = m_player.Map.GetSector(m_player.Location); + + if (VisitSectorList != null && VisitSectorList.Contains(newSector)) + { + // check to see if the player has a quest with a VISIT type objective + if (m_player.GetFlag(CarriedXmlQuestFlag)) + { + CheckVisited(m_player); + } + } + } + + public static bool CheckVisitObjective(IXmlQuest quest, PlayerMobile m_player, string objectivestr, string statestr, out string newstatestr, out bool visitstatus) + { + newstatestr = statestr; + visitstatus = false; + + if (objectivestr == null) return false; + + // format for the objective string will be VISIT,x,y,range[,duration] + string[] arglist = BaseXmlSpawner.ParseString(objectivestr, 5, ","); + + bool found = false; + + int targetcount = 1; + + string status_str = null; + + if (status_str != null) quest.Status = status_str; + + if (arglist.Length > 3) + { + // escort task objective + if (arglist[0] == "VISIT") + { + + double duration = 0; // duration in minutes + + // get the coords + int x = 0; + try + { + x = int.Parse(arglist[1]); + } + catch { status_str = "invalid VISIT x"; } + + int y = 0; + try + { + y = int.Parse(arglist[2]); + } + catch { status_str = "invalid VISIT y"; } + + int range = 0; + try + { + range = int.Parse(arglist[2]); + } + catch { status_str = "invalid VISIT range"; } + + + + if (arglist.Length > 4) + { + try + { + duration = double.Parse(arglist[4]); + } + catch { status_str = "invalid VISIT duration"; } + } + + // check them against the players current location + + if (m_player != null && m_player.InRange(new Point2D(x, y), range)) + { + if (duration > 0) + { + // is there already a timer started on the quest object? + } + else + { + found = true; + } + // if it is in range, then start the timer + } + } + } + + // update the objective state + if (found) + { + // get the current visitation count and update it + int current = 0; + try + { + current = int.Parse(statestr); + } + catch { } + + int visited = current + 1; + + newstatestr = String.Format("{0}", visited); + + if (visited >= targetcount) + { + // visitation completed + visitstatus = true; ; + } + return true; + } + else + // not a visitation task + return false; + } + + public static void ApplyVisited(PlayerMobile m_player, IXmlQuest quest) + { + if (quest == null || !quest.IsValid) return; + + string newstatestr; + bool visitstatus = false; + if (!quest.Completed1 && CheckVisitObjective(quest, m_player, quest.Objective1, quest.State1, out newstatestr, out visitstatus)) + { + quest.State1 = newstatestr; + quest.Completed1 = visitstatus; + } + else if (!quest.Completed2 && CheckVisitObjective(quest, m_player, quest.Objective2, quest.State2, out newstatestr, out visitstatus)) + { + quest.State2 = newstatestr; + quest.Completed2 = visitstatus; + } + else if (!quest.Completed3 && CheckVisitObjective(quest, m_player, quest.Objective2, quest.State2, out newstatestr, out visitstatus)) + { + quest.State3 = newstatestr; + quest.Completed3 = visitstatus; + } + else if (!quest.Completed4 && CheckVisitObjective(quest, m_player, quest.Objective4, quest.State4, out newstatestr, out visitstatus)) + { + quest.State4 = newstatestr; + quest.Completed4 = visitstatus; + } + else if (!quest.Completed5 && CheckVisitObjective(quest, m_player, quest.Objective5, quest.State5, out newstatestr, out visitstatus)) + { + quest.State5 = newstatestr; + quest.Completed5 = visitstatus; + } + if (!quest.Deleted && quest.Owner != null && visitstatus) + { + quest.Owner.SendMessage("Quest objective completed."); + // check to see if the quest has been completed and there is a reward to be automatically handed out + quest.CheckAutoReward(); + } + } + + public static void CheckVisited(PlayerMobile m_player) + { + + // search the player for IXmlQuest objects + ArrayList mobitems = FindXmlQuest(m_player); + + if (mobitems == null) return; + + for (int i = 0; i < mobitems.Count; i++) + { + + if (mobitems[i] is IXmlQuest) + { + // search the objects for visitation requirements + IXmlQuest quest = (IXmlQuest)(mobitems[i]); + + if (quest != null && !quest.Deleted) + { + ApplyVisited(m_player, quest); + } + } + } + } + + + public static bool VerifyObjective(string[] arglist, out string status_str) + { + status_str = null; + + if (arglist == null || arglist.Length < 1) + { + return true; + } + + bool checkprop; + int targetcount; + string typestr = null; + + switch (arglist[0]) + { + case "COLLECT": + case "KILL": + XmlQuest.CheckArgList(arglist, 2, null, out typestr, out targetcount, out checkprop, out status_str); + if (arglist.Length > 1) + { + if (SpawnerType.GetType(arglist[1]) == null) + { + status_str = "Invalid type: " + arglist[1]; + return false; + } + } + else + { + status_str = arglist[0] + "missing args"; + return false; + } + break; + case "COLLECTNAMED": + case "KILLNAMED": + XmlQuest.CheckArgList(arglist, 2, null, out typestr, out targetcount, out checkprop, out status_str); + if (arglist.Length < 1) + { + status_str = arglist[0] + "missing args"; + return false; + } + break; + case "GIVENAMED": + XmlQuest.CheckArgList(arglist, 3, null, out typestr, out targetcount, out checkprop, out status_str); + if (arglist.Length < 1) + { + status_str = arglist[0] + "missing args"; + return false; + } + break; + case "GIVE": + XmlQuest.CheckArgList(arglist, 3, null, out typestr, out targetcount, out checkprop, out status_str); + if (arglist.Length > 2) + { + if (SpawnerType.GetType(arglist[2]) == null) + { + status_str = "Invalid type: " + arglist[2]; + return false; + } + } + else + { + status_str = arglist[0] + "missing args"; + return false; + } + break; + } + + + // check the validity of the typestr + if (typestr != null) + { + if (SpawnerType.GetType(typestr) == null) + { + status_str = "Invalid type: " + typestr; + return false; + } + } + + return true; + } + + public static void VerifyObjectives(IXmlQuest quest) + { + string status_str; + + // go through each objective and test the args + VerifyObjective(BaseXmlSpawner.ParseString(quest.Objective1, 6, ","), out status_str); + if (status_str != null) quest.Status = status_str; + VerifyObjective(BaseXmlSpawner.ParseString(quest.Objective2, 6, ","), out status_str); + if (status_str != null) quest.Status = status_str; + VerifyObjective(BaseXmlSpawner.ParseString(quest.Objective3, 6, ","), out status_str); + if (status_str != null) quest.Status = status_str; + VerifyObjective(BaseXmlSpawner.ParseString(quest.Objective4, 6, ","), out status_str); + if (status_str != null) quest.Status = status_str; + VerifyObjective(BaseXmlSpawner.ParseString(quest.Objective5, 6, ","), out status_str); + if (status_str != null) quest.Status = status_str; + + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestAttachment.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestAttachment.cs new file mode 100644 index 0000000..6bb95ee --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestAttachment.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.IO; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlQuestAttachment : XmlAttachment + { + private DateTime m_DataValue; + + + public DateTime Date { get { return m_DataValue; } set { m_DataValue = value; } } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlQuestAttachment(ASerial serial) + : base(serial) + { + } + + [Attachable] + public XmlQuestAttachment(string name) + { + Name = name; + Date = DateTime.Now; + } + + [Attachable] + public XmlQuestAttachment(string name, double expiresin) + { + Name = name; + Date = DateTime.Now; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + [Attachable] + public XmlQuestAttachment(string name, DateTime value, double expiresin) + { + Name = name; + Date = value; + Expiration = TimeSpan.FromMinutes(expiresin); + + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + // version 0 + writer.Write(m_DataValue); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + // version 0 + m_DataValue = reader.ReadDateTime(); + } + + public override string OnIdentify(Mobile from) + { + if (from.AccessLevel == AccessLevel.Player) return null; + + if (Expiration > TimeSpan.Zero) + { + return String.Format("Quest '{2}' Completed {0} expires in {1} mins", Date, Expiration.TotalMinutes, Name); + } + else + { + return String.Format("Quest '{1}' Completed {0}", Date, Name); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestBook.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestBook.cs new file mode 100644 index 0000000..65ed155 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestBook.cs @@ -0,0 +1,275 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.IO; +using System.Collections; +using Server.Targeting; +using Server.Engines.PartySystem; +using System.Data; +using System.Xml; + + +/* +** XmlQuestBook class +** +*/ +namespace Server.Items +{ + [Flipable( 0x1E5E, 0x1E5F )] + public class PlayerQuestBoard : XmlQuestBook + { + + public override bool IsDecoContainer + { + get { return false; } + } + + public PlayerQuestBoard( Serial serial ) : base( serial ) + { + } + + [Constructable] + public PlayerQuestBoard() : base( 0x1e5e ) + { + Movable = false; + Name = "Player Quest Board"; + LiftOverride = true; // allow players to store books in it + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + } + } + + + public class XmlQuestBook : Container + { + + private PlayerMobile m_Owner; + private bool m_Locked; + + [CommandProperty( AccessLevel.GameMaster )] + public PlayerMobile Owner + { get{ return m_Owner; } + set { m_Owner = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Locked + { get{ return m_Locked; } + set { m_Locked = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsCompleted + { get{ + Item [] questitems = this.FindItemsByType(typeof(IXmlQuest)); + + if(questitems == null || questitems.Length <= 0) + return false; + + for ( int i = 0; i < questitems.Length; ++i ) + { + IXmlQuest q = questitems[i] as IXmlQuest; + + // check completion and validity status of all quests held in the book + if(q == null || q.Deleted || !q.IsValid || !q.IsCompleted) return false; + + } + + return true; + } + } + + + public XmlQuestBook( Serial serial ) : base( serial ) + { + } + + [Constructable] + public XmlQuestBook(int itemid) : this( ) + { + ItemID = itemid; + } + + [Constructable] + public XmlQuestBook() : base( 0x2259 ) + { + //LootType = LootType.Blessed; + Name = "QuestBook"; + Hue = 100; + } + + public override void OnDoubleClick( Mobile from ) + { + if(!(from is PlayerMobile)) return; + + if(from.AccessLevel >= AccessLevel.GameMaster) + { + base.OnDoubleClick(from); + } + + from.SendGump( new XmlQuestBookGump( (PlayerMobile)from, this ) ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if(dropped is IXmlQuest && !Locked) + { + return base.OnDragDrop(from,dropped); + } else + { + return false; + } + } + + private void CheckOwnerFlag() + { + if(Owner != null && !Owner.Deleted) + { + // need to check to see if any other questtoken items are owned + // search the Owners top level pack for an xmlquest + ArrayList list = XmlQuest.FindXmlQuest(Owner); + + if(list == null || list.Count == 0) + { + // if none remain then flag the ower as having none + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag,false); + } + + } + } + + public virtual void Invalidate() + { + + if(Owner != null) + { + Owner.SendMessage(String.Format("{0} Quests invalidated - '{1}' removed", TotalItems,Name)); + } + this.Delete(); + } + + public override void OnItemLifted(Mobile from, Item item) + { + base.OnItemLifted(from,item); + + if(from is PlayerMobile && Owner == null) + { + Owner = from as PlayerMobile; + LootType = LootType.Blessed; + // flag the owner as carrying a questtoken assuming the book contains quests and then confirm it with CheckOwnerFlag + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag,true); + CheckOwnerFlag(); + } + } + + + public override void OnAdded(object parent) + { + base.OnAdded(parent); + + if(parent != null && parent is Container) + { + // find the parent of the container + // note, the only valid additions are to the player pack. Anything else is invalid. This is to avoid exploits involving storage or transfer of questtokens + object from = ((Container)parent).Parent; + + // check to see if it can be added + if(from != null && from is PlayerMobile) + { + // if it was not owned then allow it to go anywhere + if(Owner == null) + { + Owner = from as PlayerMobile; + + LootType = LootType.Blessed; + // could also bless all of the quests inside as well but not actually necessary since blessed containers retain their + // contents whether blessed or not, and when dropped the questtokens will be blessed + + // flag the owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag,true); + CheckOwnerFlag(); + } else + if(from as PlayerMobile != Owner || parent is BankBox) + { + // tried to give it to another player or placed it in the players bankbox. try to return it to the owners pack + Owner.AddToBackpack(this); + } + } else + { + if(Owner != null) + { + // try to return it to the owners pack + Owner.AddToBackpack(this); + } + // allow placement into npcs or drop on their corpses when owner is null + else + if(!(from is Mobile) && !(parent is Corpse)) + { + // in principle this should never be reached + + // invalidate the token + + CheckOwnerFlag(); + + Invalidate(); + } + } + } + } + + public override void OnDelete() + { + base.OnDelete(); + + CheckOwnerFlag(); + } + + public override bool OnDroppedToWorld(Mobile from,Point3D point) + { + + bool returnvalue = base.OnDroppedToWorld(from,point); + + from.SendGump( new XmlConfirmDeleteGump(from,this)); + + //CheckOwnerFlag(); + + //Invalidate(); + return false; + //return returnvalue; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + + writer.Write( m_Owner); + writer.Write( m_Locked); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + this.m_Owner = reader.ReadMobile() as PlayerMobile; + this.m_Locked = reader.ReadBool(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestBookGump.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestBookGump.cs new file mode 100644 index 0000000..7409fb2 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestBookGump.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Prompts; +using Server.Engines.XmlSpawner2; + +// +// XmlQuestBookGump +// modified from RC0 BOBGump.cs +// +namespace Server.Gumps +{ + public class XmlQuestBookGump : Gump + { + private PlayerMobile m_From; + private XmlQuestBook m_Book; + private ArrayList m_List; + + private int m_Page; + + private const int LabelColor = 0x7FFF; + + public int GetIndexForPage( int page ) + { + int index = 0; + + while ( page-- > 0 ) + index += GetCountForIndex( index ); + + return index; + } + + public int GetCountForIndex( int index ) + { + int slots = 0; + int count = 0; + + ArrayList list = m_List; + + for ( int i = index; i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + int add; + + add = 1; + + if ( (slots + add) > 10 ) + break; + + slots += add; + + ++count; + } + + return count; + } + + + public XmlQuestBookGump( PlayerMobile from, XmlQuestBook book ) : this( from, book, 0, null ) + { + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if(info == null || m_From == null) return; + + switch ( info.ButtonID ) + { + case 0: // EXIT + { + break; + } + + case 2: // Previous page + { + if ( m_Page > 0 ) + m_From.SendGump( new XmlQuestBookGump( m_From, m_Book, m_Page - 1, m_List ) ); + + return; + } + case 3: // Next page + { + if ( GetIndexForPage( m_Page + 1 ) < m_List.Count ) + m_From.SendGump( new XmlQuestBookGump( m_From, m_Book, m_Page + 1, m_List ) ); + + break; + } + + + default: + { + if ( info.ButtonID >= 2000 ) + { + int index = info.ButtonID - 2000; + + if ( index < 0 || index >= m_List.Count ) + break; + + if(m_List[index] is IXmlQuest) + { + IXmlQuest o = m_List[index] as IXmlQuest; + + if(o != null && !o.Deleted){ + m_From.SendGump( new XmlQuestBookGump( m_From, m_Book, m_Page, null ) ); + m_From.CloseGump( typeof( XmlQuestStatusGump ) ); + m_From.SendGump( new XmlQuestStatusGump(o, o.TitleString, 320, 0, true) ); + } + } + } else + if ( info.ButtonID >= 1000 ) + { + + int index = info.ButtonID - 1000; + + if ( index < 0 || index >= m_List.Count ) + break; + + // allow quests to be dropped from books that are either in the world or in the players backpack + if ( m_Book.IsChildOf( m_From.Backpack ) || (m_Book.Parent == null)) + { + // move the item from the book to the players backpack + Item item = m_List[index] as Item; + + if ( item != null && !item.Deleted) + { + m_From.AddToBackpack( item ); + + m_From.SendGump( new XmlQuestBookGump( m_From, m_Book, m_Page, null ) ); + + } + else + { + m_From.SendMessage( "Internal error. The quest could not be retrieved." ); + } + } + } + + break; + } + } + } + + + public XmlQuestBookGump( PlayerMobile from, XmlQuestBook book, int page, ArrayList list ) : base( 12, 24 ) + { + from.CloseGump( typeof( XmlQuestBookGump ) ); + + m_From = from; + m_Book = book; + m_Page = page; + + if ( list == null ) + { + // make a new list based on the number of items in the book + int nquests = 0; + + Item [] questitems = book.FindItemsByType(typeof(IXmlQuest)); + + if(questitems != null) + nquests = questitems.Length; + + list = new ArrayList( nquests ); + + for ( int i = 0; i < nquests; ++i ) + { + list.Add( questitems[i] ); + } + } + + m_List = list; + + int index = GetIndexForPage( page ); + int count = GetCountForIndex( index ); + + int tableIndex = 0; + + int width = 600; + + width = 516; + + X = (624 - width) / 2; + + int xoffset = 0; + if(m_Book.Locked) + xoffset = 20; + + AddPage( 0 ); + + AddBackground( 10, 10, width, 439, 5054 ); + AddImageTiled( 18, 20, width - 17, 420, 2624 ); + + AddImageTiled( 58 - xoffset, 64, 36, 352, 200 ); // open + AddImageTiled( 96 - xoffset, 64, 163, 352, 1416 ); // name + AddImageTiled( 261 - xoffset, 64, 55, 352, 200 ); // type + AddImageTiled( 308 - xoffset, 64, 85, 352, 1416 ); // status + AddImageTiled( 395 - xoffset, 64, 116, 352, 200 ); // expires + + for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + AddImageTiled( 24, 94 + (tableIndex * 32), 489, 2, 2624 ); + + ++tableIndex; + } + + AddAlphaRegion( 18, 20, width - 17, 420 ); + AddImage( 5, 5, 10460 ); + AddImage( width - 15, 5, 10460 ); + AddImage( 5, 424, 10460 ); + AddImage( width - 15, 424, 10460 ); + + AddHtmlLocalized( 224, 32, 200, 32, 1046026, LabelColor, false, false ); // Quest Log + AddHtmlLocalized( 63 - xoffset, 64, 200, 32, 3000362, LabelColor, false, false ); // Open + AddHtmlLocalized( 147 - xoffset, 64, 200, 32, 3005104, LabelColor, false, false ); // Name + AddHtmlLocalized( 270 - xoffset, 64, 200, 32, 1062213, LabelColor, false, false ); // Type + AddHtmlLocalized( 326 - xoffset, 64, 200, 32, 3000132, LabelColor, false, false ); // Status + AddHtmlLocalized( 429 - xoffset, 64, 200, 32, 1062465, LabelColor, false, false ); // Expires + + AddButton( 375 - xoffset, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 410 - xoffset, 416, 120, 20, 1011441, LabelColor, false, false ); // EXIT + if(!m_Book.Locked) + AddHtmlLocalized( 26, 64, 50, 32, 1062212, LabelColor, false, false ); // Drop + + tableIndex = 0; + + if ( page > 0 ) + { + AddButton( 75, 416, 4014, 4016, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 110, 416, 150, 20, 1011067, LabelColor, false, false ); // Previous page + } + + if ( GetIndexForPage( page + 1 ) < list.Count ) + { + AddButton( 225, 416, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 260, 416, 150, 20, 1011066, LabelColor, false, false ); // Next page + } + + for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + + if ( obj is IXmlQuest ) + { + IXmlQuest e = (IXmlQuest)obj; + + int y = 96 + (tableIndex++ * 32); + + if(!m_Book.Locked) + AddButton( 35, y + 2, 5602, 5606, 1000 + i, GumpButtonType.Reply, 0 ); // drop + + AddButton( 60 - xoffset, y + 2, 0xFAB, 0xFAD, 2000 + i, GumpButtonType.Reply, 0 ); // open gump + + + int color; + + if(!e.IsValid) + { + color = 33; + } else + if(e.IsCompleted) + { + color = 67; + } else + { + color = 5; + } + + + AddLabel( 100 - xoffset, y, color, (string)e.Name ); + + //AddHtmlLocalized( 315, y, 200, 32, e.IsCompleted ? 1049071 : 1049072, htmlcolor, false, false ); // Completed/Incomplete + AddLabel( 315 - xoffset, y, color, e.IsCompleted ? "Completed" : "In Progress" ); + + // indicate the expiration time + if(e.IsValid){ + + // do a little parsing of the expiration string to fit it in the space + string substring = e.ExpirationString; + if(e.ExpirationString.IndexOf("Expires in") >= 0) + { + substring = e.ExpirationString.Substring(11); + } + AddLabel( 400 - xoffset, y, color, (string)substring ); + } else + { + AddLabel( 400 - xoffset, y, color, "No longer valid" ); + } + + if(e.PartyEnabled){ + + AddLabel( 270 - xoffset, y, color, "Party" ); + //AddHtmlLocalized( 250, y, 200, 32, 3000332, htmlcolor, false, false ); // Party + } else { + + AddLabel( 270 - xoffset, y, color, "Solo" ); + } + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestGumps.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestGumps.cs new file mode 100644 index 0000000..8a28f6a --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestGumps.cs @@ -0,0 +1,748 @@ +using System; +using System.Data; +using System.IO; +using Server.Mobiles; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using System.Collections; +using Server.Targeting; +using Server.Engines.XmlSpawner2; + +/* +** Changelog +** +** 3/25/04 +** added party status information +** 3/23/04 +** changed bottom border location in the quest status gump for 3dclient compatibility +*/ +namespace Server.Gumps +{ + + public class XmlConfirmDeleteGump : Gump + { + Item m_Item; + Mobile m_From; + + public XmlConfirmDeleteGump(Mobile from, Item item) : base ( 0, 0 ) + { + m_Item = item; + m_From = from; + + Closable = false; + Dragable = true; + AddPage( 0 ); + AddBackground( 10, 180, 200, 130, 5054 ); + + if(item is XmlQuestBook) + { + AddLabel( 20, 185, 33, String.Format("Delete this questbook?") ); + AddLabel( 20, 205, 33, String.Format("{0} quest(s) will be lost.", item.TotalItems) ); + AddLabel( 20, 225, 53, item.Name ); + } + else + if(item is IXmlQuest) + { + AddLabel( 20, 205, 33, String.Format("Delete this quest?") ); + AddLabel( 20, 225, 53, item.Name ); + } + else + { + AddLabel( 20, 225, 33, String.Format("Delete this item?") ); + } + AddRadio( 35, 255, 9721, 9724, false, 1 ); // accept/yes radio + AddRadio( 135, 255, 9721, 9724, true, 2 ); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff , false , false ); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff , false , false ); // No + AddButton( 80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0 ); // Okay button + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if(info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch(info.ButtonID) + { + default: + { + if(radiostate == 1 && m_Item != null ) + { // accept + if(m_Item is IXmlQuest) + { + ((IXmlQuest)m_Item).Invalidate(); + } + else + if(m_Item is XmlQuestBook) + { + ((XmlQuestBook)m_Item).Invalidate(); + } + else + { + m_Item.Delete(); + } + } + else + if(m_From != null && m_Item != null && !m_Item.Deleted) + { + m_From.AddToBackpack(m_Item); + } + break; + } + } + } + } + + + public class XmlSimpleGump : Gump + { + public static string Color( string text, string color ) + { + return String.Format( "{1}", color, text ); + } + private int m_gumptype; + private object m_invoker; + private BaseXmlSpawner.KeywordTag m_keywordtag; + private XmlGumpCallback m_gumpcallback; + private ArrayList gumpSelections = new ArrayList(); + + private class GumpSelection + { + public string Selection; + public string Response; + public int GumpItemType; // 1=textentry + + public GumpSelection(string s, string r) + { + Selection = s; + Response = r; + } + } + + void LocalAddHtml(string text, int x, int y, int width, int height, int color, bool background, bool scrollbar) + { + if (text == null) return; + + // check for cliloc specification + if (text.StartsWith("#")) + { + try + { + int cliloc = int.Parse(text.Substring(1, text.Length - 1)); + AddHtmlLocalized(x, y, width, height, cliloc, color, background, scrollbar); + } + catch { } + } + else + { + try + { + string colorstring = String.Format("{0:X}",color); + AddHtml(x, y, width, height, XmlSimpleGump.Color(text, colorstring), background, scrollbar); + } + catch { } + } + } + + private string ParseGumpText(string text) + { + + string maintext = text; + + // format for multiple selection specifications is + // maintext ; selection0 ; response0 ; selection1 ; response1 .... + + string [] args = text.Split(';'); + + // the first arg is the maintext + if(args.Length > 0) + { + maintext = args[0]; + // fill the selection and responses with the remaining args + for(int i = 1;i 0 && gumptype != 5) + { // display the title if it is there + AddImage( 156, 126, 2103 ); // bullet + LocalAddHtml(gumptitle, 174, 121, 200, 40, 0x00FF42, false, false); + } + + if(gumptype == 0) + { // simple message gump + + LocalAddHtml(maintext, 105, 159, 299, 182, 0xEFEF5A, false, true); + + } else + if(gumptype == 1) + { // Yes/no type gump + AddRadio( 101, height - 45, 9721, 9724, true, 1 ); // accept/yes radio + AddRadio( 101, height - 11, 9721, 9724, false, 2 ); // decline/no radio + AddHtmlLocalized(137, height - 41, 200, 30, 1049016, 0x7fff , false , false ); // Yes + AddHtmlLocalized(137, height - 7, 200, 30, 1049017, 0x7fff , false , false ); // No + + LocalAddHtml(maintext, 105, 159, 299, 182, 0xEFEF5A, false, true); + } + else + if(gumptype == 2) + { // reply type gump + AddImageTiled( 134, height - 7, 159, 23, 0x52 ); + AddImageTiled( 135, height - 6, 157, 21, 0xBBC ); + AddHtmlLocalized(105, height - 7, 200, 30, 3002006, 0x7fff , false , false ); // Say: + AddTextEntry( 135, height - 7, 150, 21, 0, 99, null ); + + LocalAddHtml(maintext, 105, 159, 299, 182, 0xEFEF5A, false, true); + } + else + if(gumptype == 3) + { // Quest type gump + AddImage( 97, 49, 9005 ); // quest ribbon + AddRadio( 101, height - 45, 9721, 9724, true, 1 ); // accept/yes radio + AddRadio( 101, height - 11, 9721, 9724, false, 2 ); // decline/no radio + AddHtmlLocalized( 139, 59, 200, 30, 1046013, 0x7fff, false , false ); // Quest Offer + AddHtmlLocalized(137, height - 41, 200, 30, 1049011, 0x7fff , false , false ); // I accept! + AddHtmlLocalized(137, height - 7, 200, 30, 1049012, 0x7fff , false , false ); // No thanks, I decline. + + LocalAddHtml(maintext, 105, 159, 299, 182, 0xEFEF5A, false, true); + } + else + if(gumptype == 4) + { // multiple selection type gump + // parse the gump text to get the selections and responses + + for(int i=0;i < gumpSelections.Count; i++) + { + int y = 360 + i*40; + AddRadio( 101, y, 9721, 9724, i==0 ? true: false, i ); // accept/yes radio + AddHtml( 137, y+4, 250, 40, XmlSimpleGump.Color( ((GumpSelection)gumpSelections[i]).Selection, "FFFFFF" ), false, false ); + } + + LocalAddHtml(maintext, 105, 159, 299, 182, 0xEFEF5A, false, true); + + } + else + if(gumptype == 5) + { + // parse the gump text to get the selections and responses + + for(int i=0;i < gumpSelections.Count; i++) + { + string selection = ((GumpSelection)gumpSelections[i]).Selection; + string response = ((GumpSelection)gumpSelections[i]).Response; + + int gx = 0; + int gy = 0; + int gwidth = 0; + int gheight = 0; + string label = null; + string [] args = null; + int gumpid = 0; + int color = 0; + + if(selection != null) + { + args = selection.Split(','); + } + + // process the gumpitem specifications + if(args != null && args.Length > 1) + { + for(int j=0;j 3) + { + try + { + if(args[1].StartsWith("0x")) + { + gumpid = Convert.ToInt32(args[1],16); + } + else + { + gumpid = int.Parse(args[1]); + } + gx = int.Parse(args[2]); + gy = int.Parse(args[3]); + } + catch{} + + int buttonid = 1000 + i; + + // add the button + AddButton( gx, gy, gumpid, gumpid, buttonid, GumpButtonType.Reply, 0 ); + } + } + else + if(args[0].ToLower() == "label") + { + // syntax is label,x,y,label[,color] + if(args.Length > 3) + { + try + { + gx = int.Parse(args[1]); + gy = int.Parse(args[2]); + } + catch{} + + label = args[3]; + } + // set the default label color + color = 0x384; + if(args.Length > 4) + { + try + { + color = int.Parse(args[4]); + } + catch{} + } + + // add the label + AddLabel( gx, gy, color, label ); + } + else + if(args[0].ToLower() == "html") + { + // reparse the specification to allow for the possibility of commas in the html text + args = selection.Split(new char[] {','},6); + + // syntax is html,x,y,width,height,text + if(args.Length > 5) + { + try + { + gx = int.Parse(args[1].Trim()); + gy = int.Parse(args[2].Trim()); + gwidth = int.Parse(args[3].Trim()); + gheight = int.Parse(args[4].Trim()); + } + catch{} + + label = args[5]; + } + + // add the html area + //AddHtml( gx, gy, gwidth, gheight, label, false, true ); + LocalAddHtml(label, gx, gy, gwidth, gheight, 0xEFEF5A, false, true); + } + else + if(args[0].ToLower() == "textentry") + { + ((GumpSelection)gumpSelections[i]).GumpItemType = 1; + + // syntax is textentry,x,y,width,height[,textcolor][,text] + if(args.Length > 4) + { + try + { + gx = int.Parse(args[1].Trim()); + gy = int.Parse(args[2].Trim()); + gwidth = int.Parse(args[3].Trim()); + gheight = int.Parse(args[4].Trim()); + } + catch{} + } + + if(args.Length > 5) + { + label = args[5]; + } + + // set the default textentry color + color = 0x384; + if(args.Length > 6) + { + try + { + color = int.Parse(args[6]); + } + catch{} + } + + + AddTextEntry( gx, gy, gwidth, gheight, color, i, label ); + } + else + if(args[0].ToLower() == "radio") + { + int gumpid1 = 0; + int gumpid2 = 0; + + // syntax is radio,gumpid1,gumpid2,x,y[,initialstate] + if(args.Length > 4) + { + + try + { + gumpid1 = int.Parse(args[1].Trim()); + gumpid2 = int.Parse(args[2].Trim()); + gx = int.Parse(args[3].Trim()); + gy = int.Parse(args[4].Trim()); + } + catch{} + } + + bool initial = false; + if(args.Length > 5) + { + try + { + initial = bool.Parse(args[5]); + } + catch{} + } + + AddRadio( gx, gy, gumpid1, gumpid2, initial, i); + + } + else + if(args[0].ToLower() == "image") + { + // syntax is image,gumpid,x,y[,hue] + if(args.Length > 3) + { + try + { + if(args[1].StartsWith("0x")) + { + gumpid = Convert.ToInt32(args[1],16); + } + else + { + gumpid = int.Parse(args[1]); + } + gx = int.Parse(args[2]); + gy = int.Parse(args[3]); + } + catch{} + + if(args.Length > 4) + { + try + { + color = int.Parse(args[4]); + } + catch{} + } + + // add the image + AddImage( gx, gy, gumpid, color ); + } + + } + else + if(args[0].ToLower() == "imagetiled") + { + // syntax is imagetiled,gumpid,x,y,width,height + if(args.Length > 5) + { + try + { + if(args[1].StartsWith("0x")) + { + gumpid = Convert.ToInt32(args[1],16); + } + else + { + gumpid = int.Parse(args[1]); + } + gx = int.Parse(args[2]); + gy = int.Parse(args[3]); + gwidth = int.Parse(args[4]); + gheight = int.Parse(args[5]); + } + catch{} + + // add the image + AddImageTiled( gx, gy, gwidth, gheight, gumpid ); + } + } + else + if(args[0].ToLower() == "item") + { + // syntax is item,itemid,x,y[,hue] + if(args.Length > 3) + { + try + { + if(args[1].StartsWith("0x")) + { + gumpid = Convert.ToInt32(args[1],16); + } + else + { + gumpid = int.Parse(args[1]); + } + gx = int.Parse(args[2]); + gy = int.Parse(args[3]); + } + catch{} + + if(args.Length > 4) + { + try + { + color = int.Parse(args[4]); + } + catch{} + } + + // add the image + AddItem( gx, gy, gumpid, color ); + } + + } + } + } + } + } + + public override void OnResponse( Server.Network.NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + Mobile from = state.Mobile; + + + + if(m_gumpcallback != null) + { + + if(info.ButtonID == 0) + { + m_gumpcallback( from, m_invoker, String.Empty); + + } else + + switch(m_gumptype) + { + case 0: // simple acknowledgement gump + m_gumpcallback( from, m_invoker, "done"); + break; + case 1: // yes/no gump + if(info.Switches != null && info.Switches.Length > 0) + { + if ( info.Switches[0] == 1 ) + { + m_gumpcallback( from, m_invoker, "yes"); + } + else + { + m_gumpcallback( from, m_invoker, "no"); + } + } + break; + case 2: // text entry gump + TextRelay entry = info.GetTextEntry( 99 ); + if ( entry != null && entry.Text.Length > 0 ) + { + // return the response string + m_gumpcallback( from, m_invoker, entry.Text); + } + break; + case 3: // accept/decline gump + if(info.Switches != null && info.Switches.Length > 0) + { + if ( info.Switches[0] == 1 ) + { + from.SendLocalizedMessage( 1049019 ); // You have accepted the Quest. + + m_gumpcallback( from, m_invoker, "accept"); + } + else + { + from.SendLocalizedMessage( 1049018 ); // You have declined the Quest. + + m_gumpcallback( from, m_invoker, "decline"); + + } + } + break; + case 4: // multiple option gump + if(info.Switches != null && info.Switches.Length > 0) + { + int select = info.Switches[0]; + + if(select >= 0 && select < gumpSelections.Count) + { + // return the response string for that selection + m_gumpcallback( from, m_invoker, ((GumpSelection)gumpSelections[select]).Response); + } + } + break; + case 5: + + string buttonresponse = String.Empty; + string radioresponse = String.Empty; + string textresponse = String.Empty; + + if(info.ButtonID >= 1000) + { + int select = info.ButtonID - 1000; + // get the gump response associated with the button + if(select >= 0 && select < gumpSelections.Count) + { + // return the response string for that selection + buttonresponse = ((GumpSelection)gumpSelections[select]).Response; + } + } + + if(info.Switches != null && info.Switches.Length > 0) + { + int radiostate = info.Switches[0]; + + if(radiostate >= 0 && radiostate < gumpSelections.Count) + { + radioresponse = ((GumpSelection)gumpSelections[radiostate]).Response; + } + } + + // check for any textentries + for(int j=0;j 0 ) + { + textresponse += te.Text + " "; + } + } + catch {} + } + } + + // build the composite reponse string + string responsestring = null; + if(buttonresponse != null && buttonresponse.Length > 0) + { + responsestring = buttonresponse; + } + if(radioresponse != null && radioresponse.Length > 0) + { + responsestring += " " + radioresponse; + } + if(textresponse != null && textresponse.Length > 0) + { + responsestring += " " + textresponse; + } + + m_gumpcallback( from, m_invoker, responsestring); + break; + } + } + // get rid of any temporary gump keyword tokens + if(m_invoker is XmlSpawner) + ((XmlSpawner)m_invoker).DeleteTag(m_keywordtag); + } + } +} + diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestHolder.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestHolder.cs new file mode 100644 index 0000000..1cb0e5f --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestHolder.cs @@ -0,0 +1,1849 @@ +#define CLIENT6017 + +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server.Targeting; +using Server.Engines.PartySystem; +using System.Data; +using System.Xml; +using Server.Engines.XmlSpawner2; + +/* +** XmlQuestHolder class +** +** +** Version 1.0 +** updated 9/17/04 +** - based on the XmlQuestToken class, but derived from the Container instead of Item class in order to support reward holding and display +*/ +namespace Server.Items +{ + public abstract class XmlQuestHolder : Container, IXmlQuest + { + // public const PlayerFlag CarriedXmlQuestFlag = (PlayerFlag)0x00100000; + + private double m_ExpirationDuration; + private DateTime m_TimeCreated; + private string m_Objective1; + private string m_Objective2; + private string m_Objective3; + private string m_Objective4; + private string m_Objective5; + private string m_Description1; + private string m_Description2; + private string m_Description3; + private string m_Description4; + private string m_Description5; + private bool m_Completed1 = false; + private bool m_Completed2 = false; + private bool m_Completed3 = false; + private bool m_Completed4 = false; + private bool m_Completed5 = false; + private string m_State1; + private string m_State2; + private string m_State3; + private string m_State4; + private string m_State5; + private bool m_PartyEnabled = false; + private int m_PartyRange = -1; + private string m_ConfigFile; + private string m_NoteString; + private string m_TitleString; + private string m_RewardString; + private string m_AttachmentString; + private PlayerMobile m_Owner; + private string m_SkillTrigger = null; + private bool m_Repeatable = true; + private TimeSpan m_NextRepeatable; + + private Item m_RewardItem; + private XmlAttachment m_RewardAttachment; + private int m_RewardAttachmentSerialNumber; + private bool m_AutoReward = false; + + private bool m_CanSeeReward = true; + private bool m_PlayerMade = false; + private PlayerMobile m_Creator; + private Container m_ReturnContainer; + private string m_status_str; + private int m_QuestDifficulty = 1; + + public static int JournalNotifyColor = 0; + public static int JournalEchoColor = 6; + + public XmlQuestHolder(Serial serial) + : base(serial) + { + } + + public XmlQuestHolder() + : this(3643) + { + } + + public XmlQuestHolder(int itemID) + : base(itemID) + { + Weight = 0; + Hue = 500; + //LootType = LootType.Blessed; + TimeCreated = DateTime.Now; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)6); // version + // version 6 + if (m_Journal == null || m_Journal.Count == 0) + { + writer.Write((int)0); + } + else + { + writer.Write((int)m_Journal.Count); + foreach (XmlQuest.JournalEntry e in m_Journal) + { + writer.Write(e.EntryID); + writer.Write(e.EntryText); + } + } + // version 5 + writer.Write(m_Repeatable); + // version 4 + writer.Write(m_QuestDifficulty); + // version 3 + writer.Write(m_AttachmentString); + // version 2 + writer.Write(m_NextRepeatable); + // version 1 + if (m_RewardAttachment != null) + writer.Write(m_RewardAttachment.Serial.Value); + else + writer.Write((int)0); + // version 0 + writer.Write(m_ReturnContainer); + writer.Write(m_RewardItem); + writer.Write(m_AutoReward); + writer.Write(m_CanSeeReward); + writer.Write(m_PlayerMade); + writer.Write(m_Creator); + writer.Write(m_Description1); + writer.Write(m_Description2); + writer.Write(m_Description3); + writer.Write(m_Description4); + writer.Write(m_Description5); + writer.Write(m_Owner); + writer.Write(m_RewardString); + writer.Write(m_ConfigFile); + writer.Write(m_NoteString); // moved from the QuestNote class + writer.Write(m_TitleString); // moved from the QuestNote class + writer.Write(m_PartyEnabled); + writer.Write(m_PartyRange); + writer.Write(m_State1); + writer.Write(m_State2); + writer.Write(m_State3); + writer.Write(m_State4); + writer.Write(m_State5); + writer.Write(m_ExpirationDuration); + writer.Write(m_TimeCreated); + writer.Write(m_Objective1); + writer.Write(m_Objective2); + writer.Write(m_Objective3); + writer.Write(m_Objective4); + writer.Write(m_Objective5); + writer.Write(m_Completed1); + writer.Write(m_Completed2); + writer.Write(m_Completed3); + writer.Write(m_Completed4); + writer.Write(m_Completed5); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 6: + { + int nentries = reader.ReadInt(); + + if (nentries > 0) + { + m_Journal = new ArrayList(); + for (int i = 0; i < nentries; i++) + { + string entryID = reader.ReadString(); + string entryText = reader.ReadString(); + m_Journal.Add(new XmlQuest.JournalEntry(entryID, entryText)); + } + } + + goto case 5; + } + case 5: + { + m_Repeatable = reader.ReadBool(); + + goto case 4; + } + case 4: + { + m_QuestDifficulty = reader.ReadInt(); + + goto case 3; + } + case 3: + { + m_AttachmentString = reader.ReadString(); + + goto case 2; + } + case 2: + { + m_NextRepeatable = reader.ReadTimeSpan(); + + goto case 1; + } + case 1: + { + m_RewardAttachmentSerialNumber = reader.ReadInt(); + + goto case 0; + } + case 0: + { + this.m_ReturnContainer = (Container)reader.ReadItem(); + this.m_RewardItem = reader.ReadItem(); + this.m_AutoReward = reader.ReadBool(); + this.m_CanSeeReward = reader.ReadBool(); + this.m_PlayerMade = reader.ReadBool(); + this.m_Creator = reader.ReadMobile() as PlayerMobile; + this.m_Description1 = reader.ReadString(); + this.m_Description2 = reader.ReadString(); + this.m_Description3 = reader.ReadString(); + this.m_Description4 = reader.ReadString(); + this.m_Description5 = reader.ReadString(); + this.m_Owner = reader.ReadMobile() as PlayerMobile; + this.m_RewardString = reader.ReadString(); + this.m_ConfigFile = reader.ReadString(); + this.m_NoteString = reader.ReadString(); + this.m_TitleString = reader.ReadString(); + this.m_PartyEnabled = reader.ReadBool(); + this.m_PartyRange = reader.ReadInt(); + this.m_State1 = reader.ReadString(); + this.m_State2 = reader.ReadString(); + this.m_State3 = reader.ReadString(); + this.m_State4 = reader.ReadString(); + this.m_State5 = reader.ReadString(); + this.Expiration = reader.ReadDouble(); + this.m_TimeCreated = reader.ReadDateTime(); + this.m_Objective1 = reader.ReadString(); + this.m_Objective2 = reader.ReadString(); + this.m_Objective3 = reader.ReadString(); + this.m_Objective4 = reader.ReadString(); + this.m_Objective5 = reader.ReadString(); + this.m_Completed1 = reader.ReadBool(); + this.m_Completed2 = reader.ReadBool(); + this.m_Completed3 = reader.ReadBool(); + this.m_Completed4 = reader.ReadBool(); + this.m_Completed5 = reader.ReadBool(); + } + break; + } + } + + private static Item PlaceHolderItem = null; + + public static void Initialize() + { + // create a temporary placeholder item used to force allocation empty Items lists used to hold hidden rewards. + PlaceHolderItem = new Item(1); + + foreach (Item item in World.Items.Values) + { + if (item is XmlQuestHolder) + { + XmlQuestHolder t = item as XmlQuestHolder; + + t.UpdateWeight(); + + t.RestoreRewardAttachment(); + } + } + + // remove the temporary placeholder item + PlaceHolderItem.Delete(); + } + + private void HideRewards() + { + if (m_RewardItem != null) + { + // remove the item from the containers item list + if (Items.Contains(m_RewardItem)) + { + Items.Remove(m_RewardItem); + } + } + } + + private void UnHideRewards() + { + if (m_RewardItem == null) return; + + Item tmpitem = null; + + if (Items == Item.EmptyItems) + { + tmpitem = PlaceHolderItem; + + if (tmpitem == null || tmpitem.Deleted) + { + tmpitem = new Item(1); + } + + // need to get it to allocate a new list by adding an item + DropItem(tmpitem); + } + + if (!Items.Contains(m_RewardItem)) + { + m_RewardItem.Parent = this; + m_RewardItem.Map = Map; + + // restore the item to the containers item list + Items.Add(m_RewardItem); + + } + + // remove the placeholder + if (tmpitem != null && Items.Contains(tmpitem)) + { + Items.Remove(tmpitem); + tmpitem.Map = Map.Internal; + } + + if (tmpitem != null && tmpitem != PlaceHolderItem) + { + tmpitem.Delete(); + } + } + + public override bool CheckItemUse(Mobile from, Item item) + { + if (!(item is Container)) + return false; + else + return base.CheckItemUse(from, item); + } + + public override void DisplayTo(Mobile to) + { + if (to == null) return; + + // add the reward item back into the container list for display + UnHideRewards(); + + to.Send(new ContainerDisplay(this)); + +#if(CLIENT6017) + // add support for new client container packets + if (to.NetState != null && to.NetState.ContainerGridLines) + to.Send(new ContainerContent6017(to, this)); + else +#endif + to.Send(new ContainerContent(to, this)); ; + + if (ObjectPropertyList.Enabled) + { + List items = this.Items; + + for (int i = 0; i < items.Count; ++i) + to.Send(((Item)items[i]).OPLPacket); + } + // move the reward item out of container to protect it from use + HideRewards(); + } + + public override void GetProperties(ObjectPropertyList list) + { + + list.Add(Name); + if (LootType == LootType.Blessed) + { + list.Add(1038021); + } + if (PlayerMade && Owner != null && !(RootParent is PlayerVendor)) + { + list.Add(1050044, "{0}\t{1}", this.TotalItems, this.TotalWeight); // ~1_COUNT~items,~2_WEIGHT~stones + } + + // add any playervendor price/description information + if (RootParent is PlayerVendor) + { + ((PlayerVendor)RootParent).GetChildProperties(list, this); + } + } + + public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + { + if (m.AccessLevel == AccessLevel.Player) return false; + + return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight); + } + + public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage) + { + if (from.AccessLevel == AccessLevel.Player) return false; + + return base.TryDropItem(from, dropped, sendFullMessage); + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + return false; + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + return false; + } + + public override bool CheckTarget(Mobile from, Server.Targeting.Target targ, object targeted) + { + if (from.AccessLevel == AccessLevel.Player) return false; + + return true; + } + + + public override void OnDoubleClick(Mobile from) + { + //base.OnDoubleClick(from); + + if (!(from is PlayerMobile)) return; + + if (PlayerMade && (from == Creator) && (from == Owner)) + { + from.SendGump(new XmlPlayerQuestGump((PlayerMobile)from, this)); + } + } + + public override bool OnDroppedToWorld(Mobile from, Point3D point) + { + + bool returnvalue = base.OnDroppedToWorld(from, point); + + from.SendGump(new XmlConfirmDeleteGump(from, this)); + + return false; + } + + + public override void OnDelete() + { + + // remove any temporary quest attachments associated with this quest and quest owner + XmlQuest.RemoveTemporaryQuestObjects(Owner, Name); + + base.OnDelete(); + + // remove any reward items that might be attached to this + ReturnReward(); + + // determine whether the owner needs to be flagged with a quest attachment indicating completion of this quest + QuestCompletionAttachment(); + + + CheckOwnerFlag(); + + + } + + public override void OnItemLifted(Mobile from, Item item) + { + base.OnItemLifted(from, item); + + if (from is PlayerMobile && PlayerMade && (Owner != null) && (Owner == Creator)) + { + LootType = LootType.Regular; + } + else + if (from is PlayerMobile && Owner == null) + { + Owner = from as PlayerMobile; + + LootType = LootType.Blessed; + // flag the owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); + } + } + + public override void OnAdded(object target) + { + base.OnAdded(target); + + if ((target != null) && target is Container) + { + // find the parent of the container + // note, the only valid additions are to the player pack or a questbook. Anything else is invalid. + // This is to avoid exploits involving storage or transfer of questtokens + // make an exception for playermade quests that can be put on playervendors + object parentOfTarget = ((Container)target).Parent; + + // if this is a QuestBook then allow additions if it is in a players pack or it is a player quest + if ((parentOfTarget != null) && parentOfTarget is Container && target is XmlQuestBook) + { + parentOfTarget = ((Container)parentOfTarget).Parent; + } + + // check to see if it can be added. + // allow playermade quests to be placed in playervendors or in xmlquestbooks that are in the world (supports the playerquestboards) + if (PlayerMade && (((parentOfTarget != null) && parentOfTarget is PlayerVendor) || + ((parentOfTarget == null) && target is XmlQuestBook))) + { + CheckOwnerFlag(); + + Owner = null; + + LootType = LootType.Regular; + } + else + if ((parentOfTarget != null) && (parentOfTarget is PlayerMobile) && PlayerMade && (Owner != null) && ((Owner == Creator) || (Creator == null))) + { + // check the old owner + CheckOwnerFlag(); + + Owner = parentOfTarget as PlayerMobile; + + // first owner will become creator by default + if (Creator == null) + Creator = Owner; + + LootType = LootType.Blessed; + + // flag the new owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); + + } + else + if ((parentOfTarget != null) && (parentOfTarget is PlayerMobile)) + { + if (Owner == null) + { + Owner = parentOfTarget as PlayerMobile; + + LootType = LootType.Blessed; + + // flag the owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); + } + else + if ((parentOfTarget as PlayerMobile != Owner) || (target is BankBox)) + { + // tried to give it to another player or placed it in the players bankbox. try to return it to the owners pack + Owner.AddToBackpack(this); + + } + } + else + { + + if (Owner != null) + { + // try to return it to the owners pack + Owner.AddToBackpack(this); + } + // allow placement into containers in the world, npcs or drop on their corpses when owner is null + else + if (!(parentOfTarget is Mobile) && !(target is Corpse) && parentOfTarget != null) + { + + // invalidate the token + + CheckOwnerFlag(); + + Invalidate(); + } + } + } + } + + private ArrayList m_Journal; + public ArrayList Journal { get { return m_Journal; } set { m_Journal = value; } } + private static char[] colondelim = new char[1] { ':' }; + + public string EchoAddJournalEntry + { + set + { + // notify and echo journal text + VerboseAddJournalEntry(value, true, true); + } + } + + public string NotifyAddJournalEntry + { + set + { + // notify + VerboseAddJournalEntry(value, true, false); + } + } + + public string AddJournalEntry + { + set + { + // silent + VerboseAddJournalEntry(value, false, false); + } + } + + private void VerboseAddJournalEntry(string entrystring, bool notify, bool echo) + { + if (entrystring == null) return; + + // parse the value + string[] args = entrystring.Split(colondelim, 2); + + if (args == null) return; + + string entryID = null; + string entryText = null; + if (args.Length > 0) + { + entryID = args[0].Trim(); + } + + if (entryID == null || entryID.Length == 0) return; + + if (args.Length > 1) + { + entryText = args[1].Trim(); + } + + // allocate a new journal if none exists + if (m_Journal == null) m_Journal = new ArrayList(); + + // go through the existing journal to find a matching ID + XmlQuest.JournalEntry foundEntry = null; + + foreach (XmlQuest.JournalEntry e in m_Journal) + { + if (e.EntryID == entryID) + { + foundEntry = e; + break; + } + } + + if (foundEntry != null) + { + // modify an existing entry + if (entryText == null || entryText.Length == 0) + { + // delete the entry + m_Journal.Remove(foundEntry); + } + else + { + // just replace the text + foundEntry.EntryText = entryText; + + Mobile holder = RootParent as Mobile; + + if (holder != null) + { + if (notify) + { + // notify the player holding the questholder + holder.SendMessage(JournalNotifyColor, "Journal entry '{0}' of quest '{1}' has been modified.", entryID, Name); + } + if (echo) + { + // echo the journal text to the player holding the questholder + holder.SendMessage(JournalEchoColor, "{0}", entryText); + } + } + } + } + else + { + // add a new entry + if (entryText != null && entryText.Length != 0) + { + // add the new entry + m_Journal.Add(new XmlQuest.JournalEntry(entryID, entryText)); + + Mobile holder = RootParent as Mobile; + + if (holder != null) + { + if (notify) + { + // notify the player holding the questholder + holder.SendMessage(JournalNotifyColor, "Journal entry '{0}' has been added to quest '{1}'.", entryID, Name); + } + if (echo) + { + // echo the journal text to the player holding the questholder + holder.SendMessage(JournalEchoColor, "{0}", entryText); + } + } + } + } + } + + + + private void QuestCompletionAttachment() + { + bool complete = IsCompleted; + + // is this quest repeatable + if ((!Repeatable || NextRepeatable > TimeSpan.Zero) && complete) + { + double expiresin = Repeatable ? NextRepeatable.TotalMinutes : 0; + + // then add an attachment indicating that it has already been done + XmlAttach.AttachTo(Owner, new XmlQuestAttachment(this.Name, expiresin)); + } + + // have quest points been enabled? + if (XmlQuest.QuestPointsEnabled && complete && !PlayerMade) + { + XmlQuestPoints.GiveQuestPoints(Owner, this); + } + } + + private void PackItem(Item item) + { + if (item != null) + { + DropItem(item); + } + + PackItemsMovable(this, false); + + // make sure the weight and gold of the questtoken is updated to reflect the weight of added rewards in playermade quests to avoid + // exploits where quests are used as zero weight containers + + UpdateWeight(); + } + + + private void CalculateWeight(Item target) + { + if (target is Container) + { + int gold = 0; + int weight = 0; + int nitems = 0; + + foreach (Item i in ((Container)target).Items) + { + // make sure gold amount is consistent with totalgold + if (i is Gold) + { + UpdateTotal(i, TotalType.Gold, i.Amount); + } + + if (i is Container) + { + CalculateWeight(i); + weight += i.TotalWeight + (int)i.Weight; + gold += i.TotalGold; + nitems += i.TotalItems + 1; + } + else + { + weight += (int)(i.Weight * i.Amount); + gold += i.TotalGold; + nitems += 1; + } + } + + UpdateTotal((Container)target, TotalType.Weight, weight); + UpdateTotal((Container)target, TotalType.Gold, gold); + UpdateTotal((Container)target, TotalType.Items, nitems); + } + } + + + private void UpdateWeight() + { + + + // decide whether to hide the weight, gold, and number of the reward from the totals calculation + + if (PlayerMade) + { + UnHideRewards(); + } + else + { + HideRewards(); + } + + // update the container totals + UpdateTotals(); + + // and the parent totals + if (RootParent is Mobile) + { + ((Mobile)RootParent).UpdateTotals(); + } + + // hide the reward item + HideRewards(); + + } + + private void ReturnReward() + { + if (m_RewardItem != null) + { + + CheckRewardItem(); + + // if this was player made, then return the item to the creator + if (PlayerMade && (Creator != null) && !Creator.Deleted) + { + m_RewardItem.Movable = true; + + // make sure all of the items in the pack are movable as well + PackItemsMovable(this, true); + + bool returned = false; + + if ((ReturnContainer != null) && !ReturnContainer.Deleted) + { + returned = ReturnContainer.TryDropItem(Creator, m_RewardItem, false); + //ReturnContainer.DropItem(m_RewardItem); + } + if (!returned) + { + + returned = Creator.AddToBackpack(m_RewardItem); + + } + if (returned) + { + Creator.SendMessage("Your reward {0} was returned from quest {1}", m_RewardItem.GetType().Name, Name); + //AddMobileWeight(Creator, m_RewardItem); + } + else + { + Creator.SendMessage("Attempted to return reward {0} from quest {1} : containers full.", m_RewardItem.GetType().Name, Name); + } + } + else + { + // just delete it + m_RewardItem.Delete(); + + } + m_RewardItem = null; + UpdateWeight(); + } + if (m_RewardAttachment != null) + { + // delete any remaining attachments + m_RewardAttachment.Delete(); + } + + } + + [CommandProperty(AccessLevel.GameMaster)] + public PlayerMobile Owner + { + get { return m_Owner; } + set { m_Owner = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public new string Name + { + get + { + if (PlayerMade) + { + return "PQ: " + base.Name; + } + else + { + return base.Name; + } + } + set + { + base.Name = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public PlayerMobile Creator + { + get { return m_Creator; } + set { m_Creator = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Difficulty + { + get { return m_QuestDifficulty; } + set { m_QuestDifficulty = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Status + { + get { return m_status_str; } + set { m_status_str = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string NoteString + { + get { return m_NoteString; } + set { m_NoteString = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AutoReward + { + get { return m_AutoReward; } + set { m_AutoReward = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanSeeReward + { + get { return m_CanSeeReward; } + set { m_CanSeeReward = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PlayerMade + { + get { return m_PlayerMade; } + set { m_PlayerMade = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Container ReturnContainer + { + get { return m_ReturnContainer; } + set { m_ReturnContainer = value; } + } + + private void PackItemsMovable(Container pack, bool canmove) + { + if (pack == null) return; + UnHideRewards(); + Item[] itemlist = pack.FindItemsByType(typeof(Item), true); + if (itemlist != null) + { + for (int i = 0; i < itemlist.Length; i++) + { + itemlist[i].Movable = canmove; + } + } + + } + + private void RestoreRewardAttachment() + { + m_RewardAttachment = XmlAttach.FindAttachmentBySerial(m_RewardAttachmentSerialNumber); + } + + public XmlAttachment RewardAttachment + { + get + { + // if the reward item is not set, and the reward string is specified, then use the reward string to construct and assign the + // reward item + // dont allow player made quests to use the rewardstring creation feature + if (m_RewardAttachment != null && m_RewardAttachment.Deleted) m_RewardAttachment = null; + + if ((m_RewardAttachment == null || m_RewardAttachment.Deleted) && + (m_AttachmentString != null) && !PlayerMade) + { + object o = XmlQuest.CreateItem(this, m_AttachmentString, out m_status_str, typeof(XmlAttachment)); + if (o is Item) + { + ((Item)o).Delete(); + } + else + if (o is XmlAttachment) + { + m_RewardAttachment = o as XmlAttachment; + m_RewardAttachment.OwnedBy = this; + } + } + + return m_RewardAttachment; + } + set + { + // get rid of any existing attachment + if (m_RewardAttachment != null && !m_RewardAttachment.Deleted) + { + m_RewardAttachment.Delete(); + } + + m_RewardAttachment = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item RewardItem + { + get + { + // if the reward item is not set, and the reward string is specified, then use the reward string to construct and assign the + // reward item + // dont allow player made quests to use the rewardstring creation feature + if ((m_RewardItem == null || m_RewardItem.Deleted) && + (m_RewardString != null) && !PlayerMade) + { + object o = XmlQuest.CreateItem(this, m_RewardString, out m_status_str, typeof(Item)); + if (o is Item) + { + m_RewardItem = o as Item; + PackItem(m_RewardItem); + } + else + if (o is XmlAttachment) + { + ((XmlAttachment)o).Delete(); + } + } + + return m_RewardItem; + } + set + { + // get rid of any existing reward item if it has been assigned + if (m_RewardItem != null && !m_RewardItem.Deleted) + { + + ReturnReward(); + } + + // and assign the new item + m_RewardItem = value; + + /* + // is this currently carried by a mobile? + if(m_RewardItem.RootParent != null && m_RewardItem.RootParent is Mobile) + { + // if so then remove it + ((Mobile)(m_RewardItem.RootParent)).RemoveItem(m_RewardItem); + + } + */ + + // and put it in the pack + if (m_RewardItem != null && !m_RewardItem.Deleted) + { + PackItem(m_RewardItem); + } + + + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string TitleString + { + get { return m_TitleString; } + set { m_TitleString = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string RewardString + { + get { return m_RewardString; } + set { m_RewardString = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string AttachmentString + { + get { return m_AttachmentString; } + set { m_AttachmentString = value; } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public string ConfigFile + { + get { return m_ConfigFile; } + set { m_ConfigFile = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool LoadConfig + { + get { return false; } + set { if (value == true) LoadXmlConfig(ConfigFile); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PartyEnabled + { + get { return m_PartyEnabled; } + set { m_PartyEnabled = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public int PartyRange + { + get { return m_PartyRange; } + set { m_PartyRange = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State1 + { + get { return m_State1; } + set { m_State1 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State2 + { + get { return m_State2; } + set { m_State2 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State3 + { + get { return m_State3; } + set { m_State3 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State4 + { + get { return m_State4; } + set { m_State4 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State5 + { + get { return m_State5; } + set { m_State5 = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Description1 + { + get { return m_Description1; } + set { m_Description1 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description2 + { + get { return m_Description2; } + set { m_Description2 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description3 + { + get { return m_Description3; } + set { m_Description3 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description4 + { + get { return m_Description4; } + set { m_Description4 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description5 + { + get { return m_Description5; } + set { m_Description5 = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Objective1 + { + get { return m_Objective1; } + set { m_Objective1 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective2 + { + get { return m_Objective2; } + set { m_Objective2 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective3 + { + get { return m_Objective3; } + set { m_Objective3 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective4 + { + get { return m_Objective4; } + set { m_Objective4 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective5 + { + get { return m_Objective5; } + set { m_Objective5 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed1 + { + get { return m_Completed1; } + set + { + m_Completed1 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed2 + { + get { return m_Completed2; } + set + { + m_Completed2 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed3 + { + get { return m_Completed3; } + set + { + m_Completed3 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed4 + { + get { return m_Completed4; } + set + { + m_Completed4 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed5 + { + get { return m_Completed5; } + set + { + m_Completed5 = value; + CheckAutoReward(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime TimeCreated + { + get { return m_TimeCreated; } + set { m_TimeCreated = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Expiration + { + get + { + return m_ExpirationDuration; + } + set + { + // cap the max value at 100 years + if (value > 876000) + { + m_ExpirationDuration = 876000; + } + else + { + m_ExpirationDuration = value; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan ExpiresIn + { + get + { + if (m_ExpirationDuration > 0) + { + // if this is a player created quest, then refresh the expiration time until it is in someone elses possession + /* + if(PlayerMade && ((Owner == Creator) || (Owner == null))) + { + m_TimeCreated = DateTime.Now; + } + */ + return (m_TimeCreated + TimeSpan.FromHours(m_ExpirationDuration) - DateTime.Now); + } + else + { + return TimeSpan.FromHours(0); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsExpired + { + get + { + if (((m_ExpirationDuration > 0) && (ExpiresIn <= TimeSpan.FromHours(0)))) + { + + return true; + } + else + return false; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool Repeatable + { + get + { + return m_Repeatable; + } + set + { + m_Repeatable = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual TimeSpan NextRepeatable + { + get + { + return m_NextRepeatable; + } + set + { + m_NextRepeatable = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool AlreadyDone + { + get + { + // look for a quest attachment with the current quest name + if (XmlAttach.FindAttachment(Owner, typeof(XmlQuestAttachment), Name) == null) + return false; + + return true; + + } + } + + public virtual string ExpirationString + { + get + { + if (AlreadyDone) + { + return "Already done"; + } + else + if (m_ExpirationDuration <= 0) + { + return "Never expires"; + } + else + if (IsExpired) + { + return "Expired"; + } + else + { + TimeSpan ts = ExpiresIn; + + int days = (int)ts.TotalDays; + int hours = (int)(ts - TimeSpan.FromDays(days)).TotalHours; + int minutes = (int)(ts - TimeSpan.FromHours(hours)).TotalMinutes; + int seconds = (int)(ts - TimeSpan.FromMinutes(minutes)).TotalSeconds; + + if (days > 0) + { + return String.Format("Expires in {0} days {1} hrs", days, hours); + } + else + if (hours > 0) + { + return String.Format("Expires in {0} hrs {1} mins", hours, minutes); + } + else + { + return String.Format("Expires in {0} mins {1} secs", minutes, seconds); + } + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsValid + { + get + { + if (IsExpired) + { + // eliminate reward definitions + RewardString = null; + AttachmentString = null; + + // return any reward items + ReturnReward(); + + return false; + } + else + if (AlreadyDone) + { + return false; + } + else + return true; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsCompleted + { + get + { + if (IsValid && + (Completed1 || Objective1 == null || (Objective1.Length == 0)) && + (Completed2 || Objective2 == null || (Objective2.Length == 0)) && + (Completed3 || Objective3 == null || (Objective3.Length == 0)) && + (Completed4 || Objective4 == null || (Objective4.Length == 0)) && + (Completed5 || Objective5 == null || (Objective5.Length == 0)) + ) + return true; + else + return false; + } + } + + public Container Pack + { + get { return this; } + } + + // this is the handler for skill use + // not yet implemented, just a hook for now + public void OnSkillUse(Mobile m, Skill skill, bool success) + { + + if (m == m_Owner && IsValid) + { + //m_skillTriggerActivated = false; + + // do a location test for the skill use + /* + if ( !Utility.InRange( m.Location, this.Location, m_ProximityRange ) ) + return; + */ + int testskill = -1; + + // check the skill trigger conditions, Skillname,min,max + try + { + testskill = (int)Enum.Parse(typeof(SkillName), m_SkillTrigger); + } + catch { } + + if (m_SkillTrigger != null && (int)skill.SkillName == testskill) + { + // have a skill trigger so flag it and test it + //m_skillTriggerActivated = true; + } + + } + + } + + public bool HandlesOnSkillUse { get { return (IsValid && m_SkillTrigger != null && m_SkillTrigger.Length > 0); } } + + + + private void CheckOwnerFlag() + { + if (Owner != null && !Owner.Deleted) + { + // need to check to see if any other questtoken items are owned + // search the Owners top level pack for an xmlquest + ArrayList list = XmlQuest.FindXmlQuest(Owner); + + if (list == null || list.Count == 0) + { + + // if none remain then flag the ower as having none + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, false); + } + } + + + } + + public virtual void Invalidate() + { + //Hue = 32; + //LootType = LootType.Regular; + if (Owner != null) + { + Owner.SendMessage(String.Format("Quest invalidated - '{0}' removed", Name)); + } + this.Delete(); + } + + public void CheckRewardItem() + { + // go through all reward items and delete anything that is movable. This blocks any exploits where players might + // try to add items themselves + if (m_RewardItem != null && !m_RewardItem.Deleted && m_RewardItem is Container) + { + foreach (Item i in ((Container)m_RewardItem).FindItemsByType(typeof(Item), true)) + { + if (i.Movable) + { + i.Delete(); + } + } + } + + } + + public void CheckAutoReward() + { + if (!this.Deleted && AutoReward && IsCompleted && Owner != null && + ((RewardItem != null && !m_RewardItem.Deleted) || (RewardAttachment != null && !m_RewardAttachment.Deleted))) + { + if (RewardItem != null) + { + // make sure nothing has been added to the pack other than the original reward items + CheckRewardItem(); + + m_RewardItem.Movable = true; + + // make sure all of the items in the pack are movable as well + PackItemsMovable(this, true); + + Owner.AddToBackpack(m_RewardItem); + //AddMobileWeight(Owner,m_RewardItem); + + m_RewardItem = null; + } + if (RewardAttachment != null) + { + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(AttachToCallback), new object[] { Owner, m_RewardAttachment }); + + m_RewardAttachment = null; + } + + Owner.SendMessage(String.Format("{0} completed. You receive the quest reward!", Name)); + this.Delete(); + } + } + + public void AttachToCallback(object state) + { + object[] args = (object[])state; + + XmlAttach.AttachTo(args[0], (XmlAttachment)args[1]); + } + + + + + private const string XmlTableName = "Properties"; + private const string XmlDataSetName = "XmlQuestHolder"; + + public void LoadXmlConfig(string filename) + { + if (filename == null || filename.Length <= 0) return; + // Check if the file exists + if (System.IO.File.Exists(filename) == true) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + Status = String.Format("Unable to open {0} for loading", filename); + return; + } + + // Create the data set + DataSet ds = new DataSet(XmlDataSetName); + + // Read in the file + //ds.ReadXml( e.Arguments[0].ToString() ); + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch { fileerror = true; } + + // close the file + fs.Close(); + if (fileerror) + { + Console.WriteLine("XmlQuestHolder: Error in XML config file '{0}'", filename); + return; + } + // Check that at least a single table was loaded + if (ds.Tables != null && ds.Tables.Count > 0) + { + if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[XmlTableName].Rows) + { + bool valid_entry; + string strEntry = null; + bool boolEntry = true; + double doubleEntry = 0; + int intEntry = 0; + TimeSpan timespanEntry = TimeSpan.Zero; + + valid_entry = true; + try { strEntry = (string)dr["Name"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Name = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Title"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.TitleString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Note"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.NoteString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Reward"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.RewardString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Attachment"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.AttachmentString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective1"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective1 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective2"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective2 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective3"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective3 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective4"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective4 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective5"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective5 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description1"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description1 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description2"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description2 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description3"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description3 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description4"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description4 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description5"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description5 = strEntry; + } + + valid_entry = true; + boolEntry = false; + try { boolEntry = bool.Parse((string)dr["PartyEnabled"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.PartyEnabled = boolEntry; + } + + valid_entry = true; + boolEntry = false; + try { boolEntry = bool.Parse((string)dr["AutoReward"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.AutoReward = boolEntry; + } + + valid_entry = true; + boolEntry = true; + try { boolEntry = bool.Parse((string)dr["CanSeeReward"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.CanSeeReward = boolEntry; + } + + valid_entry = true; + boolEntry = true; + try { boolEntry = bool.Parse((string)dr["Repeatable"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.m_Repeatable = boolEntry; + } + + valid_entry = true; + timespanEntry = TimeSpan.Zero; + try { timespanEntry = TimeSpan.Parse((string)dr["NextRepeatable"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.m_NextRepeatable = timespanEntry; + } + + valid_entry = true; + boolEntry = false; + try { boolEntry = bool.Parse((string)dr["PlayerMade"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.PlayerMade = boolEntry; + } + + valid_entry = true; + intEntry = 0; + try { intEntry = int.Parse((string)dr["PartyRange"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.PartyRange = intEntry; + } + + valid_entry = true; + doubleEntry = 0; + try { doubleEntry = double.Parse((string)dr["Expiration"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.Expiration = doubleEntry; + } + } + } + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestHolderGumps.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestHolderGumps.cs new file mode 100644 index 0000000..4a2f448 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestHolderGumps.cs @@ -0,0 +1,689 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Prompts; +using Server.Targeting; +using Server.Engines.XmlSpawner2; + + +namespace Server.Gumps +{ + + public class XmlQuestStatusGump : Gump + { + public static string Color(string text, string color) + { + return String.Format("{1}", color, text); + } + + + public void DisplayQuestStatus(int x, int y, string objectivestr, string statestr, bool status, string descriptionstr) + { + if (objectivestr != null && objectivestr.Length > 0) + { + // look for special keywords + string[] arglist = BaseXmlSpawner.ParseString(objectivestr, 5, ","); + int targetcount = 1; + bool foundkill = false; + bool foundcollect = false; + bool foundgive = false; + bool foundescort = false; + string name = null; + string mobname = null; + string type = null; + + string status_str; + string text = null; + string typestr; + bool checkprop; + + if (arglist.Length > 0) + switch (arglist[0]) + { + case "GIVE": + // format for the objective string will be GIVE,mobname,itemtype[,count][,proptest] + if (arglist.Length > 2) + { + mobname = arglist[1]; + //name = arglist[2]; + type = arglist[2]; + } + + XmlQuest.CheckArgList(arglist, 3, null, out typestr, out targetcount, out checkprop, out status_str); + + foundgive = true; + break; + case "GIVENAMED": + // format for the objective string will be GIVENAMED,mobname,itemname[,type][,count][,proptest] + if (arglist.Length > 2) + { + mobname = arglist[1]; + name = arglist[2]; + } + + XmlQuest.CheckArgList(arglist, 3, null, out typestr, out targetcount, out checkprop, out status_str); + + if (typestr != null) type = typestr; + + foundgive = true; + break; + case "KILL": + // format for the objective string will be KILL,mobtype[,count][,proptest] + + if (arglist.Length > 1) + { + //name = arglist[1]; + type = arglist[1]; + } + + XmlQuest.CheckArgList(arglist, 2, null, out typestr, out targetcount, out checkprop, out status_str); + + foundkill = true; + break; + + case "KILLNAMED": + // format for the objective string KILLNAMED,mobname[,type][,count][,proptest] + if (arglist.Length > 1) + { + name = arglist[1]; + } + + XmlQuest.CheckArgList(arglist, 2, null, out typestr, out targetcount, out checkprop, out status_str); + + if (typestr != null) type = typestr; + + foundkill = true; + break; + case "COLLECT": + // format for the objective string will be COLLECT,itemtype[,count][,proptest] + if (arglist.Length > 1) + { + //name = arglist[1]; + type = arglist[1]; + } + + XmlQuest.CheckArgList(arglist, 2, null, out typestr, out targetcount, out checkprop, out status_str); + + + + foundcollect = true; + break; + case "COLLECTNAMED": + // format for the objective string will be COLLECTNAMED,itemname[,itemtype][,count][,proptest] + if (arglist.Length > 1) + { + name = arglist[1]; + } + + XmlQuest.CheckArgList(arglist, 2, null, out typestr, out targetcount, out checkprop, out status_str); + + if (typestr != null) type = typestr; + + foundcollect = true; + break; + case "ESCORT": + // format for the objective string will be ESCORT,mobname[,proptest] + if (arglist.Length > 1) + { + name = arglist[1]; + } + foundescort = true; + break; + } + + if (foundkill) + { + // get the current kill status + int killed = 0; + try + { + killed = int.Parse(statestr); + } + catch { } + + int remaining = targetcount - killed; + + if (remaining < 0) remaining = 0; + + // report the kill task objective status + if (descriptionstr != null) + text = String.Format("{0} ({1} left)", descriptionstr, remaining); + else + { + if (name != null) + { + if (type == null) type = "mob"; + + text = String.Format("Kill {0} {1}(s) named {2} ({3} left)", targetcount, type, name, remaining); + } + else + text = String.Format("Kill {0} {1}(s) ({2} left)", targetcount, type, remaining); + } + } + else + if (foundescort) + { + // get the current escort status + int escorted = 0; + try + { + escorted = int.Parse(statestr); + } + catch { } + + int remaining = targetcount - escorted; + + if (remaining < 0) remaining = 0; + + // report the escort task objective status + if (descriptionstr != null) + text = descriptionstr; + else + text = String.Format("Escort {0}", name); + } + else + if (foundcollect) + { + // get the current collection status + int collected = 0; + try + { + collected = int.Parse(statestr); + } + catch { } + + int remaining = targetcount - collected; + + if (remaining < 0) remaining = 0; + + // report the collect task objective status + if (descriptionstr != null) + text = String.Format("{0} ({1} left)", descriptionstr, remaining); + else + { + if (name != null) + { + if (type == null) type = "mob"; + + text = String.Format("Collect {0} {1}(s) named {2} ({3} left)", targetcount, type, name, remaining); + } + else + text = String.Format("Collect {0} {1}(s) ({2} left)", targetcount, type, remaining); + } + } + else + if (foundgive) + { + // get the current give status + int collected = 0; + + try + { + collected = int.Parse(statestr); + } + catch { } + + int remaining = targetcount - collected; + + if (remaining < 0) remaining = 0; + + // report the collect task objective status + if (descriptionstr != null) + text = String.Format("{0} ({1} left)", descriptionstr, remaining); + else + { + if (name != null) + { + if (type == null) type = "item"; + + text = String.Format("Give {0} {1}(s) named {2} to {3} ({4} left)", targetcount, type, name, mobname, remaining); + } + else + text = String.Format("Give {0} {1}(s) to {2} ({3} left)", targetcount, type, mobname, remaining); + } + } + else + { + // just report the objectivestring + text = objectivestr; + } + + AddHtml(x, y, 223, 35, XmlSimpleGump.Color(text, "EFEF5A"), false, false); + + if (status) + { + AddImage(x - 20, y + 3, 0x939); // bullet + AddHtmlLocalized(x + 222, y, 225, 37, 1046033, 0xff42, false, false); // Complete + } + else + { + AddImage(x - 20, y + 3, 0x938); // bullet + AddHtmlLocalized(x + 222, y, 225, 37, 1046034, 0x7fff, false, false); // Incomplete + } + } + } + + private IXmlQuest m_questitem; + private string m_gumptitle; + private int m_X; + private int m_Y; + private bool m_solid; + private int m_screen; + + public XmlQuestStatusGump(IXmlQuest questitem, string gumptitle) + : this(questitem, gumptitle, 0, 0, false, 0) + { + } + + public XmlQuestStatusGump(IXmlQuest questitem, string gumptitle, int X, int Y, bool solid) + : this(questitem, gumptitle, X, Y, solid, 0) + { + } + + + public XmlQuestStatusGump(IXmlQuest questitem, string gumptitle, int X, int Y, bool solid, int screen) + : base(X, Y) + { + Closable = true; + Dragable = true; + m_X = X; + m_Y = Y; + m_solid = solid; + m_questitem = questitem; + m_gumptitle = gumptitle; + m_screen = screen; + + AddPage(0); + + if (!solid) + { + AddImageTiled(54, 33, 369, 400, 2624); + AddAlphaRegion(54, 33, 369, 400); + } + else + { + AddBackground(54, 33, 369, 400, 5054); + } + + AddImageTiled(416, 39, 44, 389, 203); + + // AddButton( 338, 392, 2130, 2129, 3, GumpButtonType.Reply, 0 ); // Okay button + + AddHtmlLocalized(139, 59, 200, 30, 1046026, 0x7fff, false, false); // Quest Log + AddImage(97, 49, 9005); // quest ribbon + + AddImageTiled(58, 39, 29, 390, 10460); // left hand border + AddImageTiled(412, 37, 31, 389, 10460); // right hand border + AddImage(430, 9, 10441); + AddImageTiled(40, 38, 17, 391, 9263); + AddImage(6, 25, 10421); + AddImage(34, 12, 10420); + AddImageTiled(94, 25, 342, 15, 10304); // top border + AddImageTiled(40, 414, 415, 16, 10304); // bottom border + AddImage(-10, 314, 10402); + AddImage(56, 150, 10411); + + AddImage(136, 84, 96); + AddImage(372, 57, 1417); + AddImage(381, 66, 5576); + + // add the status and journal tabs + AddImageTiled(90, 34, 322, 5, 0x145E); // top border + int tab1 = 0x138F; + int tab2 = 0x138E; + if (screen == 1) + { + tab1 = 0x138E; + tab2 = 0x138F; + } + AddButton(100, 18, tab1, tab2, 900, GumpButtonType.Reply, 0); + AddLabel(115, 17, 0, "Status"); + AddButton(189, 18, tab2, tab1, 901, GumpButtonType.Reply, 0); + AddLabel(205, 17, 0, "Journal"); + + if (screen == 1) + { + // display the journal + if (questitem.Journal != null && questitem.Journal.Count > 0) + { + string journaltext = null; + for (int i = 0; i < questitem.Journal.Count; i++) + { + journaltext += ""; + journaltext += ((XmlQuest.JournalEntry)questitem.Journal[i]).EntryID; + journaltext += ":
"; + journaltext += ((XmlQuest.JournalEntry)questitem.Journal[i]).EntryText; + journaltext += "

"; + } + AddHtml(100, 90, 270, 300, journaltext, true, true); + + } + + // add the add journal entry button + AddButton(300, 49, 0x99C, 0x99D, 952, GumpButtonType.Reply, 0); + //AddButton(300, 49, 0x159E, 0x159D, 952, GumpButtonType.Reply, 0); + } + else + { + if (gumptitle != null && gumptitle.Length > 0) + { // display the title if it is there + AddImage(146, 91, 2103); // bullet + AddHtml(164, 86, 200, 30, XmlSimpleGump.Color(gumptitle, "00FF42"), false, false); + } + + if (questitem.NoteString != null && questitem.NoteString.Length > 0) + { // display the note string if it is there + AddHtml(100, 106, 270, 80, questitem.NoteString, true, true); + } + + DisplayQuestStatus(130, 192, questitem.Objective1, questitem.State1, questitem.Completed1, questitem.Description1); + DisplayQuestStatus(130, 224, questitem.Objective2, questitem.State2, questitem.Completed2, questitem.Description2); + DisplayQuestStatus(130, 256, questitem.Objective3, questitem.State3, questitem.Completed3, questitem.Description3); + DisplayQuestStatus(130, 288, questitem.Objective4, questitem.State4, questitem.Completed4, questitem.Description4); + DisplayQuestStatus(130, 320, questitem.Objective5, questitem.State5, questitem.Completed5, questitem.Description5); + + //if(questitem.HasCollect){ + AddButton(100, 350, 0x2A4E, 0x2A3A, 700, GumpButtonType.Reply, 0); + AddLabel(135, 356, 0x384, "Collect"); + //} + + if ((questitem.RewardItem != null && !questitem.RewardItem.Deleted)) + { + m_questitem.CheckRewardItem(); + + if (questitem.RewardItem.Amount > 1) + { + AddLabel(230, 356, 55, String.Format("Reward: {0} ({1})", questitem.RewardItem.GetType().Name, + questitem.RewardItem.Amount)); + AddLabel(230, 373, 55, String.Format("Weight: {0}", questitem.RewardItem.Weight * questitem.RewardItem.Amount)); + } + else + if (questitem.RewardItem is Container) + { + AddLabel(230, 356, 55, String.Format("Reward: {0} ({1} items)", questitem.RewardItem.GetType().Name, + questitem.RewardItem.TotalItems)); + AddLabel(230, 373, 55, String.Format("Weight: {0}", questitem.RewardItem.TotalWeight + questitem.RewardItem.Weight)); + } + else + { + AddLabel(230, 356, 55, String.Format("Reward: {0}", questitem.RewardItem.GetType().Name)); + AddLabel(230, 373, 55, String.Format("Weight: {0}", questitem.RewardItem.Weight)); + } + AddImageTiled(330, 373, 81, 40, 200); + AddItem(340, 376, questitem.RewardItem.ItemID); + + } + if (questitem.RewardAttachment != null && !questitem.RewardAttachment.Deleted) + { + AddLabel(230, 339, 55, String.Format("Bonus: {0}", questitem.RewardAttachment.GetType().Name)); + } + + if ((questitem.RewardItem != null && !questitem.RewardItem.Deleted) || (questitem.RewardAttachment != null && !questitem.RewardAttachment.Deleted)) + { + if (questitem.CanSeeReward) + { + AddButton(400, 380, 2103, 2103, 800, GumpButtonType.Reply, 0); + } + } + + // indicate any status info + XmlQuest.VerifyObjectives(questitem); + if (questitem.Status != null) + { + AddLabel(100, 392, 33, questitem.Status); + } + else + // indicate the expiration time + if (questitem.IsValid) + { + //AddHtmlLocalized(150, 400, 50, 37, 1046033, 0xf0000 , false , false ); // Expires + AddHtml(130, 392, 200, 37, XmlSimpleGump.Color(questitem.ExpirationString, "00FF42"), false, false); + } + else + if (questitem.AlreadyDone) + { + if (!questitem.Repeatable) + { + AddLabel(100, 392, 33, "Already done - cannot be repeated"); + } + else + { + ArrayList a = XmlAttach.FindAttachments(questitem.Owner, typeof(XmlQuestAttachment), questitem.Name); + if (a != null && a.Count > 0) + { + AddLabel(100, 392, 33, String.Format("Repeatable in {0}", ((XmlQuestAttachment)a[0]).Expiration)); + } + else + { + AddLabel(150, 392, 33, "Already done - ???"); + } + } + } + else + { + //AddHtml( 150, 384, 200, 37, XmlSimpleGump.Color( "No longer valid", "00FF42" ), false, false ); + AddLabel(150, 392, 33, "No longer valid"); + } + if (XmlQuest.QuestPointsEnabled) + { + AddHtml(250, 40, 200, 30, XmlSimpleGump.Color(String.Format("Difficulty Level {0}", questitem.Difficulty), "00FF42"), false, false); + } + if (questitem.PartyEnabled) + { + AddHtml(250, 55, 200, 30, XmlSimpleGump.Color("Party Quest", "00FF42"), false, false); + if (questitem.PartyRange >= 0) + { + AddHtml(250, 70, 200, 30, XmlSimpleGump.Color(String.Format("Party Range {0}", questitem.PartyRange), "00FF42"), false, false); + } + else + { + AddHtml(250, 70, 200, 30, XmlSimpleGump.Color("No Range Limit", "00FF42"), false, false); + } + } + else + { + AddHtml(250, 55, 200, 30, XmlSimpleGump.Color("Solo Quest", "00FF42"), false, false); + } + } + + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null || state.Mobile.Deleted || m_questitem == null || m_questitem.Deleted) + return; + switch (info.ButtonID) + { + case 700: + state.Mobile.Target = new XmlQuest.GetCollectTarget(m_questitem); + state.Mobile.SendGump(new XmlQuestStatusGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid, m_screen)); + break; + case 800: + if (m_questitem.RewardItem != null || m_questitem.RewardAttachment != null) + { + // open a new status gump + state.Mobile.SendGump(new XmlQuestStatusGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid, m_screen)); + } + // display the reward item + if (m_questitem.RewardItem != null) + { + // show the contents of the xmlquest pack + if (m_questitem.Pack != null) + m_questitem.Pack.DisplayTo(state.Mobile); + } + // identify the reward attachment + if (m_questitem.RewardAttachment != null) + { + //state.Mobile.SendMessage("{0}",m_questitem.RewardAttachment.OnIdentify(state.Mobile)); + state.Mobile.CloseGump(typeof(DisplayAttachmentGump)); + state.Mobile.SendGump(new DisplayAttachmentGump(state.Mobile, m_questitem.RewardAttachment.OnIdentify(state.Mobile))); + } + break; + case 900: + // open a new status gump with status display + state.Mobile.SendGump(new XmlQuestStatusGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid, 0)); + break; + case 901: + // open a new status gump with journal display + state.Mobile.SendGump(new XmlQuestStatusGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid, 1)); + break; + case 952: + // open a new status gump with journal display + state.Mobile.SendGump(new XmlQuestStatusGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid, 1)); + // and open the journal entry editing gump + // only allow this to be used if the questholder is theirs + if (m_questitem.Owner == state.Mobile) + { + state.Mobile.SendGump(new JournalEntryGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid)); + } + break; + } + } + + public class JournalEntryGump : Gump + { + private IXmlQuest m_questitem; + private string m_gumptitle; + private int m_X, m_Y; + private bool m_solid; + + public JournalEntryGump(IXmlQuest questitem, string gumptitle, int X, int Y, bool solid) + : base(X, Y) + { + if (questitem == null || questitem.Deleted) + return; + + m_questitem = questitem; + m_gumptitle = gumptitle; + m_X = X; + m_Y = Y; + m_solid = solid; + + AddPage(0); + + //AddBackground(0, 0, 260, 354, 5054); + //AddAlphaRegion(20, 0, 220, 354); + AddImage(0, 0, 0x24AE); // left top scroll + AddImage(114, 0, 0x24AF); // middle top scroll + AddImage(170, 0, 0x24B0); // right top scroll + AddImageTiled(0, 140, 114, 100, 0x24B1); // left middle scroll + AddImageTiled(114, 140, 114, 100, 0x24B2); // middle middle scroll + AddImageTiled(170, 140, 114, 100, 0x24B3); // right middle scroll + AddImage(0, 210, 0x24B4); // left bottom scroll + AddImage(114, 210, 0x24B5); // middle bottom scroll + AddImage(170, 210, 0x24B6); // right bottom scroll + //AddImageTiled(23, 40, 214, 290, 0x52); + //AddImageTiled(24, 41, 213, 281, 0xBBC); + + + // OK button + AddButton(25, 327, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0); + // Close button + AddButton(230, 327, 0xFB1, 0xFB3, 0, GumpButtonType.Reply, 0); + // Edit button + //AddButton(100, 325, 0xEF, 0xEE, 2, GumpButtonType.Reply, 0); + string str = null; + + int entrynumber = 0; + if (questitem.Journal != null && questitem.Journal.Count > 0) + { + entrynumber = questitem.Journal.Count; + } + string m_entryid = "Personal entry #" + entrynumber; + + // entryid text entry area + //AddImageTiled(23, 0, 214, 23, 0x52); + //AddImageTiled(24, 1, 213, 21, 0xBBC); + AddTextEntry(35, 5, 200, 21, 0, 1, m_entryid); + + // main text entry area + AddTextEntry(35, 40, 200, 271, 0, 0, str); + + // editing text entry areas + // background for text entry area + /* + AddImageTiled(23, 275, 214, 23, 0x52); + AddImageTiled(24, 276, 213, 21, 0xBBC); + AddImageTiled(23, 300, 214, 23, 0x52); + AddImageTiled(24, 301, 213, 21, 0xBBC); + + AddTextEntry(35, 275, 200, 21, 0, 1, null); + AddTextEntry(35, 300, 200, 21, 0, 2, null); + */ + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null) return; + + if (m_questitem == null || m_questitem.Deleted) + return; + bool update_entry = false; + //bool edit_entry = false; + switch (info.ButtonID) + { + case 0: // Close + { + update_entry = false; + break; + } + case 1: // Okay + { + update_entry = true; + break; + } + case 2: // Edit + { + //edit_entry = true; + break; + } + default: + update_entry = true; + break; + } + + if (update_entry) + { + string entrytext = null; + string entryid = null; + + TextRelay entry = info.GetTextEntry(0); + if (entry != null) + { + entrytext = entry.Text; + } + + entry = info.GetTextEntry(1); + if (entry != null) + { + entryid = entry.Text; + } + + m_questitem.AddJournalEntry = entryid + ":" + entrytext; + } + // open a new journal gump + state.Mobile.CloseGump(typeof(XmlQuestStatusGump)); + state.Mobile.SendGump(new XmlQuestStatusGump(m_questitem, m_gumptitle, m_X, m_Y, m_solid, 1)); + } + } + + private class DisplayAttachmentGump : Gump + { + public DisplayAttachmentGump(Mobile from, string text) + : base(0, 0) + { + // prepare the page + AddPage(0); + + AddBackground(0, 0, 400, 150, 5054); + AddAlphaRegion(0, 0, 400, 150); + AddLabel(20, 2, 55, "Quest Attachment Description"); + + AddHtml(20, 20, 360, 110, text, true, true); + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestLeaders.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestLeaders.cs new file mode 100644 index 0000000..b9f41dc --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestLeaders.cs @@ -0,0 +1,763 @@ +#define FACTIONS +using System; +using System.IO; +using System.Xml; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Targeting; +using Server.Gumps; +using System.Text; +using Server.Commands; +using Server.Commands.Generic; + + +namespace Server.Engines.XmlSpawner2 +{ + + public class XmlQuestLeaders + { + + private static TimeSpan m_QuestLeaderboardSaveInterval = TimeSpan.FromMinutes(15); // default time interval between quest leaderboard saves + private static string m_QuestLeaderboardSaveDirectory = "Leaderboard"; // default directory for saving quest leaderboard xml information + private static int m_QuestLeaderboardSaveRanks = 20; // number of ranked players to save to the quest leaderboard. 0 means save all players. + + private static QuestLeaderboardTimer m_QuestLeaderboardTimer; + private static string m_QuestLeaderboardFile; + private static ArrayList QuestRankList = new ArrayList(); + private static bool needsupdate = true; + + + + public class QuestRankEntry : IComparable + { + public Mobile Quester; + public int Rank; + public XmlQuestPoints QuestPointsAttachment; + + public QuestRankEntry(Mobile m, XmlQuestPoints attachment) + { + Quester = m; + QuestPointsAttachment = attachment; + } + + public int CompareTo( object obj ) + { + QuestRankEntry p = (QuestRankEntry)obj; + + if(p.QuestPointsAttachment == null || QuestPointsAttachment == null) return 0; + + // break points ties with quests completed (more quests means higher rank) + if(p.QuestPointsAttachment.Points - QuestPointsAttachment.Points == 0) + { + // if kills are the same then compare previous rank + if(p.QuestPointsAttachment.QuestsCompleted - QuestPointsAttachment.QuestsCompleted == 0) + { + return p.QuestPointsAttachment.Rank - QuestPointsAttachment.Rank; + } + + return p.QuestPointsAttachment.QuestsCompleted - QuestPointsAttachment.QuestsCompleted; + } + + return p.QuestPointsAttachment.Points - QuestPointsAttachment.Points; + } + } + + private static void RefreshQuestRankList() + { + if(needsupdate && QuestRankList != null) + { + QuestRankList.Sort(); + + int rank = 0; + //int prevpoints = 0; + for(int i= 0; i 0) + xf.WriteAttributeString( "nentries", nranks.ToString() ); + else + xf.WriteAttributeString( "nentries", QuestRankList.Count.ToString() ); + + // go through the sorted list and display the top ranked players + + for(int i= 0; i 0 && i >= nranks) break; + + QuestRankEntry r = QuestRankList[i] as QuestRankEntry; + XmlQuestPoints a = r.QuestPointsAttachment; + + + if(r.Quester != null && !r.Quester.Deleted && r.Rank > 0 && a != null && !a.Deleted) + { + string guildname = null; + + if(r.Quester.Guild != null) + guildname = r.Quester.Guild.Abbreviation; +#if(FACTIONS) + string factionname = null; + + if(r.Quester is PlayerMobile && ((PlayerMobile)r.Quester).FactionPlayerState != null) + factionname = ((PlayerMobile)r.Quester).FactionPlayerState.Faction.ToString(); +#endif + // check for any ranking change and update rank date + if(r.Rank != a.Rank) + { + a.WhenRanked = DateTime.Now; + if(a.Rank > 0) + a.DeltaRank = a.Rank - r.Rank; + a.Rank = r.Rank; + + } + + TimeSpan timeranked = DateTime.Now - a.WhenRanked; + + // write out the entry information + + xf.WriteStartElement( "Entry" ); + xf.WriteAttributeString( "number", i.ToString() ); + + xf.WriteStartElement( "Player" ); + xf.WriteString( r.Quester.Name ); + xf.WriteEndElement(); + + xf.WriteStartElement( "Guild" ); + xf.WriteString( guildname ); + xf.WriteEndElement(); +#if(FACTIONS) + xf.WriteStartElement( "Faction" ); + xf.WriteString( factionname ); + xf.WriteEndElement(); +#endif + xf.WriteStartElement( "Points" ); + xf.WriteString( a.Points.ToString() ); + xf.WriteEndElement(); + + string quests = "???"; + try + { + quests = a.QuestsCompleted.ToString(); + } + catch{} + xf.WriteStartElement( "Quests" ); + xf.WriteString( quests ); + xf.WriteEndElement(); + + xf.WriteStartElement( "Rank" ); + xf.WriteString( a.Rank.ToString() ); + xf.WriteEndElement(); + + xf.WriteStartElement( "Change" ); + xf.WriteString( a.DeltaRank.ToString() ); + xf.WriteEndElement(); + + xf.WriteStartElement( "Duration" ); + xf.WriteString( timeranked.ToString() ); + xf.WriteEndElement(); + + // end the entry + xf.WriteEndElement(); + + } + } + + xf.WriteEndElement(); + + xf.Close(); + } + + public static void WriteQuestLeaderboardHtml(string filename, int nranks) + { + string dirname = Path.Combine( m_QuestLeaderboardSaveDirectory, filename ); + + StreamWriter sw = new StreamWriter( dirname ); + + if(sw == null) + { + Console.WriteLine("Error: unable to save HTML quest leaderboard to {0}", dirname); + return; + } + sw.WriteLine(" "); + sw.WriteLine( ""); +#if(FACTIONS) + sw.WriteLine( "
Quest Leaderboard
Player NameGuildFactionPointsQuestsRankChangeTime at current rank"); +#else + sw.WriteLine( "
Player NameGuildPointsQuestsRankChangeTime at current rank"); +#endif + // go through the sorted list and display the top ranked players + + for(int i= 0; i 0 && i >= nranks) break; + + QuestRankEntry r = QuestRankList[i] as QuestRankEntry; + XmlQuestPoints a = r.QuestPointsAttachment; + + if(r.Quester != null && !r.Quester.Deleted && r.Rank > 0 && a != null && !a.Deleted) + { + string guildname = null; + + if(r.Quester.Guild != null) + guildname = r.Quester.Guild.Abbreviation; +#if(FACTIONS) + string factionname = null; + + if(r.Quester is PlayerMobile && ((PlayerMobile)r.Quester).FactionPlayerState != null) + factionname = ((PlayerMobile)r.Quester).FactionPlayerState.Faction.ToString(); +#endif + // check for any ranking change and update rank date + if(r.Rank != a.Rank) + { + a.WhenRanked = DateTime.Now; + if(a.Rank > 0) + a.DeltaRank = a.Rank - r.Rank; + a.Rank = r.Rank; + + } + + TimeSpan timeranked = DateTime.Now - a.WhenRanked; + + string quests = "???"; + try + { + quests = a.QuestsCompleted.ToString(); + } + catch{} + +#if(FACTIONS) + // write out the entry information + sw.WriteLine( "
{0}{1}{2}{3}{4}{5}{6}{7}", + r.Quester.Name, + guildname, + factionname, + a.Points, + quests, + a.Rank, + a.DeltaRank, + timeranked + ); +#else + // write out the entry information + sw.WriteLine( "
{0}{1}{2}{3}{4}{5}{6}", + r.Quester.Name, + guildname, + a.Points, + quests, + a.Rank, + a.DeltaRank, + timeranked + ); + +#endif + + } + } + sw.WriteLine( "
"); + sw.Close(); + } + + + public static void WriteQuestLeaderboard(string filename, int nranks) + { + if(QuestRankList == null) return; + + // force an update of the quest leaderboard rankings + needsupdate = true; + RefreshQuestRankList(); + + if ( !Directory.Exists( m_QuestLeaderboardSaveDirectory ) ) + Directory.CreateDirectory( m_QuestLeaderboardSaveDirectory ); + + WriteQuestLeaderboardXml(filename + ".xml", nranks); + + WriteQuestLeaderboardHtml(filename + ".html", nranks); + + } + + + [Usage( "QuestLeaderboardSave [filename [minutes[nentries]]][off]" )] + [Description( "Periodically save .xml quest leaderboard information to the specified file" )] + public static void QuestLeaderboardSave_OnCommand( CommandEventArgs e ) + { + if(e.Arguments.Length > 0) + { + if(m_QuestLeaderboardTimer != null) m_QuestLeaderboardTimer.Stop(); + + if(e.Arguments[0].ToLower() != "off") + { + m_QuestLeaderboardFile = e.Arguments[0]; + + if(e.Arguments.Length > 1) + { + try + { + m_QuestLeaderboardSaveInterval = TimeSpan.FromMinutes(double.Parse(e.Arguments[1])); + } + catch{} + } + + if(e.Arguments.Length > 2) + { + try + { + m_QuestLeaderboardSaveRanks = int.Parse(e.Arguments[2]); + } + catch{} + } + + + m_QuestLeaderboardTimer = new QuestLeaderboardTimer(m_QuestLeaderboardFile, m_QuestLeaderboardSaveInterval, m_QuestLeaderboardSaveRanks); + m_QuestLeaderboardTimer.Start(); + } + } + + + if(m_QuestLeaderboardTimer != null && m_QuestLeaderboardTimer.Running) + { + e.Mobile.SendMessage("Quest Leaderboard is saving to {0} every {1} minutes. Nranks = {2}", + m_QuestLeaderboardFile, m_QuestLeaderboardSaveInterval.TotalMinutes, m_QuestLeaderboardSaveRanks); + } + else + { + e.Mobile.SendMessage("Quest Leaderboard saving is off."); + } + } + + public static void QuestLBSSerialize( GenericWriter writer ) + { + // version + writer.Write( (int) 0 ); + + // version 0 + if(m_QuestLeaderboardTimer != null && m_QuestLeaderboardTimer.Running) + { + writer.Write((bool)true); + } + else + writer.Write((bool)false); + writer.Write(m_QuestLeaderboardSaveInterval); + writer.Write(m_QuestLeaderboardSaveRanks); + writer.Write(m_QuestLeaderboardFile); + } + + public static void QuestLBSDeserialize(GenericReader reader) + { + int version = reader.ReadInt(); + + switch(version) + { + + case 0: + bool running = reader.ReadBool(); + m_QuestLeaderboardSaveInterval = reader.ReadTimeSpan(); + m_QuestLeaderboardSaveRanks = reader.ReadInt(); + m_QuestLeaderboardFile = reader.ReadString(); + + if(running) + { + if(m_QuestLeaderboardTimer != null) m_QuestLeaderboardTimer.Stop(); + m_QuestLeaderboardTimer = new QuestLeaderboardTimer(m_QuestLeaderboardFile, m_QuestLeaderboardSaveInterval, m_QuestLeaderboardSaveRanks); + m_QuestLeaderboardTimer.Start(); + } + break; + } + + } + + // added the duration timer that begins on spawning + private class QuestLeaderboardTimer : Timer + { + private string m_filename; + private int m_nranks; + + public QuestLeaderboardTimer( string filename, TimeSpan delay, int nranks ) : base( delay, delay ) + { + m_filename = filename; + m_nranks = nranks; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + WriteQuestLeaderboard(m_filename, m_nranks); + } + } + + + private string guildFilter = null; + private string nameFilter = null; + + public class TopQuestPlayersGump : Gump + { + private XmlQuestPoints m_attachment; + + public TopQuestPlayersGump(XmlQuestPoints attachment) : base( 0,0) + { + + if(QuestRankList == null || attachment == null) return; + + m_attachment = attachment; + + int numberToDisplay = 20; + int height = numberToDisplay*20 + 65; + + // prepare the page + AddPage( 0 ); + + int width = 740; +#if(FACTIONS) + width = 790; +#endif + + AddBackground( 0, 0, width, height, 5054 ); + AddAlphaRegion( 0, 0, width, height ); + AddImageTiled( 20, 20, width - 40, height - 45, 0xBBC ); + AddLabel( 20, 2, 55, "Top Quest Player Rankings" ); + + // guild filter + AddLabel( 40, height - 20, 55, "Filter by Guild" ); + string filter = null; + if(m_attachment != null) + filter = m_attachment.guildFilter; + + AddImageTiled( 140, height - 20, 160, 19, 0xBBC ); + AddTextEntry( 140, height - 20, 160, 19, 0, 200, filter ); + + AddButton( 20, height - 20, 0x15E1, 0x15E5, 200, GumpButtonType.Reply, 0 ); + + // name filter + AddLabel( 340, height - 20, 55, "Filter by Name" ); // + string nfilter = null; + if(m_attachment != null) + nfilter = m_attachment.nameFilter; + + AddImageTiled( 440, height - 20, 160, 19, 0xBBC ); + AddTextEntry( 440, height - 20, 160, 19, 0, 100, nfilter ); + + AddButton( 320, height - 20, 0x15E1, 0x15E5, 100, GumpButtonType.Reply, 0 ); + + RefreshQuestRankList(); + + int xloc = 23; + AddLabel( xloc, 20, 0, "Name" ); + xloc += 177; + AddLabel( xloc, 20, 0, "Guild" ); +#if(FACTIONS) + xloc += 35; + AddLabel( xloc, 20, 0, "Faction" ); + xloc += 15; +#endif + xloc += 50; + AddLabel( xloc, 20, 0, "Points" ); + xloc += 50; + AddLabel( xloc, 20, 0, "Quests" ); + xloc += 50; + //AddLabel( xloc, 20, 0, "" ); + xloc += 70; + AddLabel( xloc, 20, 0, "Rank" ); + xloc += 45; + AddLabel( xloc, 20, 0, "Change" ); + xloc += 45; + AddLabel( xloc, 20, 0, "Time at Rank" ); + + // go through the sorted list and display the top ranked players + + int y = 40; + int count = 0; + for(int i= 0; i= numberToDisplay) break; + + QuestRankEntry r = QuestRankList[i] as QuestRankEntry; + + if(r == null) continue; + + XmlQuestPoints a = r.QuestPointsAttachment; + + if(a == null) continue; + + if(r.Quester != null && !r.Quester.Deleted && r.Rank > 0 && a != null && !a.Deleted) + { + string guildname = null; + + if(r.Quester.Guild != null) guildname = r.Quester.Guild.Abbreviation; + +#if(FACTIONS) + string factionname = null; + + if(r.Quester is PlayerMobile && ((PlayerMobile)r.Quester).FactionPlayerState != null) + factionname = ((PlayerMobile)r.Quester).FactionPlayerState.Faction.ToString(); +#endif + // check for any ranking change and update rank date + if(r.Rank != a.Rank) + { + a.WhenRanked = DateTime.Now; + if(a.Rank > 0) + a.DeltaRank = a.Rank - r.Rank; + a.Rank = r.Rank; + + } + + // check for guild filter + if(m_attachment != null && m_attachment.guildFilter != null && m_attachment.guildFilter.Length > 0) + { + // parse the comma separated list + string [] args = m_attachment.guildFilter.Split(','); + if(args != null) + { + bool found = false; + foreach(string arg in args) + { + if(arg != null && guildname == arg.Trim()) + { + found = true; + break; + } + } + if(!found) continue; + } + } + + // check for name filter + if(m_attachment != null && m_attachment.nameFilter != null && m_attachment.nameFilter.Length > 0) + { + // parse the comma separated list + string [] args = m_attachment.nameFilter.Split(','); + + if(args != null) + { + bool found = false; + foreach(string arg in args) + { + if(arg != null && r.Quester.Name != null && (r.Quester.Name.ToLower().IndexOf(arg.Trim().ToLower()) >= 0)) + { + found = true; + break; + } + } + if(!found) continue; + } + } + + count++; + + TimeSpan timeranked = DateTime.Now - a.WhenRanked; + + int days = (int)timeranked.TotalDays; + int hours = (int)(timeranked.TotalHours - days*24); + int mins = (int)(timeranked.TotalMinutes - ((int)timeranked.TotalHours)*60); + + string quests = "???"; + try + { + quests = a.QuestsCompleted.ToString(); + } + catch{} + + xloc = 23; + AddLabel( xloc, y, 0, r.Quester.Name ); + xloc += 177; + AddLabel( xloc, y, 0, guildname ); +#if(FACTIONS) + xloc += 35; + AddLabelCropped( xloc, y, 60, 21, 0, factionname ); + xloc += 15; +#endif + xloc += 50; + AddLabel( xloc, y, 0, a.Points.ToString() ); + xloc += 50; + AddLabel( xloc, y, 0, quests ); + xloc += 50; + //AddLabel( xloc, y, 0, "" ); + xloc += 70; + AddLabel( xloc, y, 0, a.Rank.ToString() ); + + string label=null; + + if(days > 0) + label += String.Format("{0} days ",days); + if(hours > 0) + label += String.Format("{0} hours ",hours); + if(mins > 0) + label += String.Format("{0} mins",mins); + + if(label == null) + { + label = "just changed"; + } + + string deltalabel = a.DeltaRank.ToString(); + int deltahue = 0; + if(a.DeltaRank > 0) + { + deltalabel = String.Format("+{0}",a.DeltaRank); + deltahue = 68; + } + else + if(a.DeltaRank < 0) + { + deltahue = 33; + } + xloc += 50; + AddLabel( xloc, y, deltahue, deltalabel ); + xloc += 40; + AddLabel( xloc, y, 0, label); + + y += 20; + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(state == null || state.Mobile == null || info == null) return; + // Get the current name + if(m_attachment != null) + { + TextRelay entry = info.GetTextEntry( 200 ); + if(entry != null) + m_attachment.guildFilter = entry.Text; + + entry = info.GetTextEntry( 100 ); + if(entry != null) + m_attachment.nameFilter = entry.Text; + } + + switch(info.ButtonID) + { + case 100: + case 200: + { + // redisplay the gump + state.Mobile.SendGump(new TopQuestPlayersGump(m_attachment)); + break; + } + } + } + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestPoints.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestPoints.cs new file mode 100644 index 0000000..0acc855 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestPoints.cs @@ -0,0 +1,382 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Gumps; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlQuestPoints : XmlAttachment + { + private int m_Points; + private int m_Completed; + private int m_Credits; + + private ArrayList m_QuestList = new ArrayList(); + + private DateTime m_WhenRanked; + private int m_Rank; + private int m_DeltaRank; + + public string guildFilter; + public string nameFilter; + + + public ArrayList QuestList { get{ return m_QuestList; } set { m_QuestList = value; }} + + [CommandProperty( AccessLevel.GameMaster )] + public int Rank { get{ return m_Rank; } set { m_Rank = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DeltaRank { get{ return m_DeltaRank; } set { m_DeltaRank = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime WhenRanked { get{ return m_WhenRanked; } set { m_WhenRanked = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Points { get{ return m_Points; } set { m_Points = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Credits { get{ return m_Credits; } set { m_Credits = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int QuestsCompleted { get{ return m_Completed; } set { m_Completed = value; } } + + public class QuestEntry + { + public Mobile Quester; + public string Name; + public DateTime WhenCompleted; + public DateTime WhenStarted; + public int Difficulty; + public bool PartyEnabled; + public int TimesCompleted = 1; + + public QuestEntry() + { + } + + public QuestEntry(Mobile m, IXmlQuest quest) + { + Quester = m; + if(quest != null) + { + WhenStarted = quest.TimeCreated; + WhenCompleted = DateTime.Now; + Difficulty = quest.Difficulty; + Name = quest.Name; + } + } + + public virtual void Serialize( GenericWriter writer ) + { + + writer.Write( (int) 0 ); // version + + writer.Write(Quester); + writer.Write(Name); + writer.Write(WhenCompleted); + writer.Write(WhenStarted); + writer.Write(Difficulty); + writer.Write(TimesCompleted); + writer.Write(PartyEnabled); + + + } + + public virtual void Deserialize( GenericReader reader ) + { + + int version = reader.ReadInt(); + + switch(version) + { + case 0: + Quester = reader.ReadMobile(); + Name = reader.ReadString(); + WhenCompleted = reader.ReadDateTime(); + WhenStarted = reader.ReadDateTime(); + Difficulty = reader.ReadInt(); + TimesCompleted = reader.ReadInt(); + PartyEnabled = reader.ReadBool(); + break; + } + + } + + public static void AddQuestEntry(Mobile m, IXmlQuest quest) + { + if(m == null || quest == null) return; + + // get the XmlQuestPoints attachment from the mobile + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(m, typeof(XmlQuestPoints)); + + if(p == null) return; + + // look through the list of quests and see if it is one that has already been done + if(p.QuestList == null) p.QuestList = new ArrayList(); + + bool found = false; + foreach(QuestEntry e in p.QuestList) + { + if(e.Name == quest.Name) + { + // found a match, so just change the number and dates + e.TimesCompleted++; + e.WhenStarted = quest.TimeCreated; + e.WhenCompleted = DateTime.Now; + // and update the difficulty and party status + e.Difficulty = quest.Difficulty; + e.PartyEnabled = quest.PartyEnabled; + found = true; + break; + } + } + + if(!found) + { + // add a new entry + p.QuestList.Add(new QuestEntry(m, quest)); + + } + } + } + + + public XmlQuestPoints(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlQuestPoints() + { + } + + public static new void Initialize() + { + CommandSystem.Register( "QuestPoints", AccessLevel.Player, new CommandEventHandler( CheckQuestPoints_OnCommand ) ); + + CommandSystem.Register( "QuestLog", AccessLevel.Player, new CommandEventHandler( QuestLog_OnCommand ) ); + + } + + [Usage( "QuestPoints" )] + [Description( "Displays the players quest points and ranking" )] + public static void CheckQuestPoints_OnCommand( CommandEventArgs e ) + { + if(e == null || e.Mobile == null) return; + + string msg = null; + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(e.Mobile, typeof(XmlQuestPoints)); + if(p != null) + { + msg = p.OnIdentify(e.Mobile); + } + + if(msg != null) + e.Mobile.SendMessage(msg); + } + + + + [Usage( "QuestLog" )] + [Description( "Displays players quest history" )] + public static void QuestLog_OnCommand( CommandEventArgs e ) + { + if(e == null || e.Mobile == null) return; + + e.Mobile.CloseGump(typeof(XMLQuestLogGump)); + e.Mobile.SendGump(new XMLQuestLogGump(e.Mobile)); + } + + + public static void GiveQuestPoints(Mobile from, IXmlQuest quest) + { + if(from == null || quest == null) return; + + // find the XmlQuestPoints attachment + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(from, typeof(XmlQuestPoints)); + + // if doesnt have one yet, then add it + if(p == null) + { + p = new XmlQuestPoints(); + XmlAttach.AttachTo(from, p); + } + + // if you wanted to scale the points given based on party size, karma, fame, etc. + // this would be the place to do it + int points = quest.Difficulty; + + // update the questpoints attachment information + p.Points += points; + p.Credits += points; + p.QuestsCompleted++; + + if(from != null) + { + from.SendMessage("You have received {0} quest points!",points); + } + + // add the completed quest to the quest list + QuestEntry.AddQuestEntry(from, quest); + + // update the overall ranking list + XmlQuestLeaders.UpdateQuestRanking(from, p); + } + + public static int GetCredits(Mobile m) + { + int val = 0; + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(m, typeof(XmlQuestPoints)); + if(p != null) + { + val = p.Credits; + } + + return val; + } + + public static int GetPoints(Mobile m) + { + int val = 0; + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(m, typeof(XmlQuestPoints)); + if(p != null) + { + val = p.Points; + } + + return val; + } + + public static bool HasCredits(Mobile m, int credits) + { + if(m == null || m.Deleted) return false; + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(m, typeof(XmlQuestPoints)); + + if(p != null) + { + if(p.Credits >= credits) + { + return true; + } + } + + return false; + } + + public static bool TakeCredits(Mobile m, int credits) + { + if(m == null || m.Deleted) return false; + + XmlQuestPoints p = (XmlQuestPoints)XmlAttach.FindAttachment(m, typeof(XmlQuestPoints)); + + if(p != null) + { + if(p.Credits >= credits) + { + p.Credits -= credits; + return true; + } + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + // version 0 + writer.Write(m_Points); + writer.Write(m_Credits); + writer.Write(m_Completed); + writer.Write(m_Rank); + writer.Write(m_DeltaRank); + writer.Write(m_WhenRanked); + + // save the quest history + if(QuestList != null) + { + writer.Write((int)QuestList.Count); + + foreach(QuestEntry e in QuestList) + { + e.Serialize(writer); + } + } + else + { + writer.Write((int)0); + } + + // need this in order to rebuild the rankings on deser + if(AttachedTo is Mobile) + writer.Write(AttachedTo as Mobile); + else + writer.Write((Mobile)null); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch(version) + { + case 0: + + m_Points = reader.ReadInt(); + m_Credits = reader.ReadInt(); + m_Completed = reader.ReadInt(); + m_Rank = reader.ReadInt(); + m_DeltaRank = reader.ReadInt(); + m_WhenRanked = reader.ReadDateTime(); + + int nquests = reader.ReadInt(); + + if(nquests > 0) + { + QuestList = new ArrayList(nquests); + for(int i = 0; i< nquests;i++) + { + QuestEntry e = new QuestEntry(); + e.Deserialize(reader); + + QuestList.Add(e); + } + } + + + + // get the owner of this in order to rebuild the rankings + Mobile quester = reader.ReadMobile(); + + // rebuild the ranking list + // if they have never made a kill, then dont rank + if(quester != null && QuestsCompleted > 0) + { + XmlQuestLeaders.UpdateQuestRanking(quester, this); + } + break; + } + } + + public override string OnIdentify(Mobile from) + { + return String.Format("Quest Points Status:\nTotal Quest Points = {0}\nTotal Quests Completed = {1}\nQuest Credits Available = {2}",Points, QuestsCompleted, Credits); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestPointsRewards.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestPointsRewards.cs new file mode 100644 index 0000000..dec66ab --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestPointsRewards.cs @@ -0,0 +1,61 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using System.Collections; + +/* +** XmlQuestPointsRewards +** ArteGordon +** updated 9/18/05 +** +** this class lets you specify rewards that can be purchased for XmlQuestPoints quest Credits. +** The items will be displayed in the QuestPointsRewardGump that is opened by the QuestPointsRewardStone +*/ + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlQuestPointsRewards + { + public int Cost; // cost of the reward in credits + public Type RewardType; // this will be used to create an instance of the reward + public string Name; // used to describe the reward in the gump + public int ItemID; // used for display purposes + public object [] RewardArgs; // arguments passed to the reward constructor + public int MinPoints; // the minimum points requirement for the reward + + private static ArrayList PointsRewardList = new ArrayList(); + + public static ArrayList RewardsList { get { return PointsRewardList; } } + + public XmlQuestPointsRewards(int minpoints, Type reward, string name, int cost, int id, object[] args) + { + RewardType = reward; + Cost = cost; + ItemID = id; + Name = name; + RewardArgs = args; + MinPoints = minpoints; + } + + public static void Initialize() + { + // these are items as rewards. Note that the args list must match a constructor for the reward type specified. + //PointsRewardList.Add( new XmlQuestPointsRewards( 1000, typeof(PowerScroll), "105 Smithing powerscroll", 1000, 0x14F0, new object[] { SkillName.Blacksmith, 105 })); + //PointsRewardList.Add( new XmlQuestPointsRewards( 2000, typeof(PowerScroll), "110 Smithing powerscroll", 2000, 0x14F0, new object[] { SkillName.Blacksmith, 110 })); + //PointsRewardList.Add( new XmlQuestPointsRewards( 4000, typeof(PowerScroll), "115 Smithing powerscroll", 4000, 0x14F0, new object[] { SkillName.Blacksmith, 115 })); + PointsRewardList.Add( new XmlQuestPointsRewards( 500, typeof(AncientSmithyHammer), "+20 Ancient Smithy Hammer, 50 uses", 500, 0x13E4, new object[] { 20, 50 })); + PointsRewardList.Add( new XmlQuestPointsRewards( 200, typeof(ColoredAnvil), "Colored Anvil", 400, 0xFAF, null )); + PointsRewardList.Add( new XmlQuestPointsRewards( 100, typeof(PowderOfTemperament), "Powder Of Temperament, 10 uses", 300, 4102, new object[] { 10 })); + PointsRewardList.Add( new XmlQuestPointsRewards( 100, typeof(LeatherGlovesOfMining), "+20 Leather Gloves Of Mining", 200, 0x13c6, new object[] { 20 })); + + // this is an example of adding a mobile as a reward + PointsRewardList.Add( new XmlQuestPointsRewards( 0, typeof(RidableLlama),"Ridable Llama", 1, 0x20f6, null)); + + // this is an example of adding an attachment as a reward + //PointsRewardList.Add( new XmlQuestPointsRewards( 0, typeof(XmlEnemyMastery), "+200% Balron Mastery for 1 day", 2, 0, new object[] { "Balron", 50, 200, 1440.0 })); + //PointsRewardList.Add( new XmlQuestPointsRewards( 0, typeof(XmlStr), "+20 Strength for 1 day", 10, 0, new object[] { 20, 86400.0 })); + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestToken.cs b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestToken.cs new file mode 100644 index 0000000..aecd535 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlQuest/XmlQuestToken.cs @@ -0,0 +1,1887 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server.Targeting; +using Server.Engines.PartySystem; +using System.Data; +using System.Xml; +using Server.Engines.XmlSpawner2; + +/* +** XmlQuestToken class +** +** Version 1.10 +** updated 10/26/04 +** ArteGordon +** +** Version 1.10 +** updated 10/26/04 +** - modified RewardString to only support item rewards and added the new AttachmentString property for specifying attachment rewards. +** +** Version 1.09 +** updated 9/03/04 +** - added the autoreward and rewarditem properties that allow rewards to be automatically created and given upon quest completion +** +** Version 1.08 +** updated 7/31/04 +** - added the Description1-5 property to allow the quest objective descriptions to be explicitly specified. When this string is defined it will override the default +** description provided for the different types of quest objectives. +** +** Version 1.07 +** updated 7/28/04 +** - add support for an additional property test argument to the quest keywords +** - mobs no longer say "Thank you", or "I have no need for that." when given items for GIVE type quests. +** +** Version 1.06 +** updated 7/07/04 +** - Added the GIVE type quest objective. Using an objective string of the type "GIVE,mobname,item[,count]" or "GIVENAMED,mobname,itemname[,count]" will produce an objective +** that is satisfied when the specified item(s) are dragged and dropped onto the named mob. +** - Added the ESCORT type quest objective. Using an objective string of the type "ESCORT,mobname" will produce an objective +** that is satisfied when the specified TalkingBaseEscortable class mob is successfully escorted to its destination. +** Note, the destination is specified by setting the Destination property on the escort to a region name. +** - changed the rules for invalid XmlQuestTokens to eliminate hording or trading so that they can no longer be placed in containers and will automatically +** return to the player's pack if the player attempts to place them in any invalid location (such as another container, a bankbox, or another player). +** If they are placed on ground they will be automatically deleted. +** - added optimizations for KILL type quests in which only players that are flagged as carrying XmlQuestTokens are checked on kills. +** +** Version 1.05 +** updated 4/30/04 +** - Added the RewardString property +** +** Version 1.04 +** updated 3/25/04 +** - Added the LoadConfig and ConfigFile properties that allow XmlQuestTokens to read their configuration information from an XML file. +** - Moved the TitleString and NoteString properties from the QuestNote class to the XmlQuestToken class. +** +** Version 1.03 +** updated 3/25/04 +** - Added the PartyEnabled and PartyRange properties that allow party members to benefit from KILL and COLLECT keywords. +** +** Version 1.02 +** updated 3/20/04 +** - fixed the COLLECT and COLLECTNAMED keywords to remove non-stackable items after collecting. Thanks to nix4 for pointing this out. +** +* Version 1.01 +** updated 2/26/04 +** - modified expiration time reporting format +** - added State properties to support more complex objective status information +** - added killtask support with special objective specification keywords KILL,mobtype,count and KILLNAMED,mobname,count +** - added collecttask support with special objective specification keywords COLLECT,itemtype,count and COLLECTNAMED,itemname,count +** +** Version 1.0 +** updated 1/07/04 +*/ +namespace Server.Items +{ + + public class XmlQuestTokenPack : Container + { + public override bool OnDragDrop(Mobile from, Item dropped) + { + return false; + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + return false; + } + + public override void OnAdded(object target) + { + base.OnAdded(target); + + UpdateTotal(this, TotalType.Weight, 0); + UpdateTotal(this, TotalType.Gold, 0); + UpdateTotal(this, TotalType.Items, 0); + } + + public sealed class ForcedContainerContent : Packet + { + public ForcedContainerContent(Mobile beholder, Item beheld) + : base(0x3C) + { + List items = beheld.Items; + int count = items.Count; + + this.EnsureCapacity(5 + (count * 19)); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write((ushort)0); + + for (int i = 0; i < count; ++i) + { + Item child = items[i]; + + if (!child.Deleted ) + { + Point3D loc = child.Location; + + ushort cid = (ushort)child.ItemID; + + if (cid > 0x3FFF) + cid = 0x9D7; + + m_Stream.Write((int)child.Serial); + m_Stream.Write((ushort)cid); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)child.Amount); + m_Stream.Write((short)loc.X); + m_Stream.Write((short)loc.Y); + m_Stream.Write((int)beheld.Serial); + m_Stream.Write((ushort)child.Hue); + + ++written; + } + } + + m_Stream.Seek(pos, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } + + public override void DisplayTo(Mobile to) + { + if (to == null) return; + + to.Send(new ContainerDisplay(this)); + to.Send(new ForcedContainerContent(to, this)); + + if (ObjectPropertyList.Enabled) + { + List items = this.Items; + + for (int i = 0; i < items.Count; ++i) + to.Send(((Item)items[i]).OPLPacket); + } + } + + public XmlQuestTokenPack() + : base(0x9B2) + { + Weight = 0; + } + + public XmlQuestTokenPack(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public abstract class XmlQuestToken : Item, IXmlQuest + { + //public const PlayerFlag CarriedXmlQuestFlag = (PlayerFlag)0x00100000; + + private bool m_wasMoved = false; + private double m_ExpirationDuration; + private DateTime m_TimeCreated; + private string m_Objective1; + private string m_Objective2; + private string m_Objective3; + private string m_Objective4; + private string m_Objective5; + private string m_Description1; + private string m_Description2; + private string m_Description3; + private string m_Description4; + private string m_Description5; + private bool m_Completed1 = false; + private bool m_Completed2 = false; + private bool m_Completed3 = false; + private bool m_Completed4 = false; + private bool m_Completed5 = false; + private string m_State1; + private string m_State2; + private string m_State3; + private string m_State4; + private string m_State5; + private bool m_PartyEnabled = false; + private int m_PartyRange = -1; + private string m_ConfigFile; + private string m_NoteString; + private string m_TitleString; + private string m_RewardString; + private string m_AttachmentString; + private PlayerMobile m_Owner; + private string m_SkillTrigger = null; + private bool m_Repeatable = true; + private TimeSpan m_NextRepeatable; + + private Item m_RewardItem; + private XmlAttachment m_RewardAttachment; + private int m_RewardAttachmentSerialNumber; + private bool m_AutoReward = false; + private Container m_Pack; + private bool m_CanSeeReward = false; + private bool m_PlayerMade = false; + private PlayerMobile m_Creator; + private Container m_ReturnContainer; + private string m_status_str; + private int m_QuestDifficulty = 1; + + public XmlQuestToken(Serial serial) + : base(serial) + { + } + + public XmlQuestToken() + { + //LootType = LootType.Blessed; + TimeCreated = DateTime.Now; + } + + public XmlQuestToken(int itemID) + { + ItemID = itemID; + //LootType = LootType.Blessed; + TimeCreated = DateTime.Now; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)14); // version + // version 14 + if (m_Journal == null || m_Journal.Count == 0) + { + writer.Write((int)0); + } + else + { + writer.Write((int)m_Journal.Count); + foreach (XmlQuest.JournalEntry e in m_Journal) + { + writer.Write(e.EntryID); + writer.Write(e.EntryText); + } + } + // version 13 + writer.Write(m_Repeatable); + // version 12 + writer.Write(m_QuestDifficulty); + // version 11 + writer.Write(m_AttachmentString); + // version 10 + writer.Write(m_NextRepeatable); + // version 9 + if (m_RewardAttachment != null) + writer.Write(m_RewardAttachment.Serial.Value); + else + writer.Write((int)0); + // version 8 + writer.Write(m_ReturnContainer); + // version 7 + writer.Write(m_Pack); + writer.Write(m_RewardItem); + writer.Write(m_AutoReward); + writer.Write(m_CanSeeReward); + writer.Write(m_PlayerMade); + writer.Write(m_Creator); + // version 6 + writer.Write(m_Description1); + writer.Write(m_Description2); + writer.Write(m_Description3); + writer.Write(m_Description4); + writer.Write(m_Description5); + // version 5 + writer.Write(m_Owner); + // version 4 + writer.Write(m_RewardString); + // version 3 + writer.Write(m_ConfigFile); + writer.Write(m_NoteString); // moved from the QuestNote class + writer.Write(m_TitleString); // moved from the QuestNote class + + // version 2 + writer.Write(m_PartyEnabled); + writer.Write(m_PartyRange); + // version 1 + writer.Write(m_State1); + writer.Write(m_State2); + writer.Write(m_State3); + writer.Write(m_State4); + writer.Write(m_State5); + + // version 0 + writer.Write(m_wasMoved); + writer.Write(m_ExpirationDuration); + writer.Write(m_TimeCreated); + writer.Write(m_Objective1); + writer.Write(m_Objective2); + writer.Write(m_Objective3); + writer.Write(m_Objective4); + writer.Write(m_Objective5); + writer.Write(m_Completed1); + writer.Write(m_Completed2); + writer.Write(m_Completed3); + writer.Write(m_Completed4); + writer.Write(m_Completed5); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch (version) + { + case 14: + { + int nentries = reader.ReadInt(); + + if (nentries > 0) + { + m_Journal = new ArrayList(); + for (int i = 0; i < nentries; i++) + { + string entryID = reader.ReadString(); + string entryText = reader.ReadString(); + m_Journal.Add(new XmlQuest.JournalEntry(entryID, entryText)); + } + } + + goto case 13; + } + case 13: + { + m_Repeatable = reader.ReadBool(); + goto case 12; + } + case 12: + { + m_QuestDifficulty = reader.ReadInt(); + goto case 11; + } + case 11: + { + m_AttachmentString = reader.ReadString(); + goto case 10; + } + case 10: + { + m_NextRepeatable = reader.ReadTimeSpan(); + goto case 9; + } + case 9: + { + m_RewardAttachmentSerialNumber = reader.ReadInt(); + goto case 8; + } + case 8: + { + this.m_ReturnContainer = (Container)reader.ReadItem(); + goto case 7; + } + case 7: + { + this.m_Pack = (Container)reader.ReadItem(); + this.m_RewardItem = reader.ReadItem(); + this.m_AutoReward = reader.ReadBool(); + this.m_CanSeeReward = reader.ReadBool(); + this.m_PlayerMade = reader.ReadBool(); + this.m_Creator = reader.ReadMobile() as PlayerMobile; + goto case 6; + } + case 6: + { + this.m_Description1 = reader.ReadString(); + this.m_Description2 = reader.ReadString(); + this.m_Description3 = reader.ReadString(); + this.m_Description4 = reader.ReadString(); + this.m_Description5 = reader.ReadString(); + goto case 5; + } + case 5: + { + this.m_Owner = reader.ReadMobile() as PlayerMobile; + goto case 4; + } + case 4: + { + this.m_RewardString = reader.ReadString(); + goto case 3; + } + case 3: + { + this.m_ConfigFile = reader.ReadString(); + this.m_NoteString = reader.ReadString(); + this.m_TitleString = reader.ReadString(); + goto case 2; + } + case 2: + { + this.m_PartyEnabled = reader.ReadBool(); + this.m_PartyRange = reader.ReadInt(); + goto case 1; + } + case 1: + { + this.m_State1 = reader.ReadString(); + this.m_State2 = reader.ReadString(); + this.m_State3 = reader.ReadString(); + this.m_State4 = reader.ReadString(); + this.m_State5 = reader.ReadString(); + goto case 0; + } + case 0: + { + this.m_wasMoved = reader.ReadBool(); + this.Expiration = reader.ReadDouble(); + this.m_TimeCreated = reader.ReadDateTime(); + this.m_Objective1 = reader.ReadString(); + this.m_Objective2 = reader.ReadString(); + this.m_Objective3 = reader.ReadString(); + this.m_Objective4 = reader.ReadString(); + this.m_Objective5 = reader.ReadString(); + this.m_Completed1 = reader.ReadBool(); + this.m_Completed2 = reader.ReadBool(); + this.m_Completed3 = reader.ReadBool(); + this.m_Completed4 = reader.ReadBool(); + this.m_Completed5 = reader.ReadBool(); + } + break; + } + } + + public static void Initialize() + { + foreach (Item item in World.Items.Values) + { + if (item is XmlQuestToken) + { + XmlQuestToken t = item as XmlQuestToken; + + if (t.Pack != null && !t.Pack.Deleted) + { + + t.UpdateWeight(); + + t.UpdateTotal(t.Pack, TotalType.Weight, 0); + t.UpdateTotal(t.Pack, TotalType.Gold, 0); + + t.RestoreRewardAttachment(); + + } + } + } + } + + public override void OnDoubleClick(Mobile from) + { + base.OnDoubleClick(from); + + if (!(from is PlayerMobile)) return; + + if (PlayerMade && (from == Creator) && (from == Owner)) + { + from.SendGump(new XmlPlayerQuestGump((PlayerMobile)from, this)); + } + } + + public override bool OnDroppedToWorld(Mobile from, Point3D point) + { + + bool returnvalue = base.OnDroppedToWorld(from, point); + + from.SendGump(new XmlConfirmDeleteGump(from, this)); + + //m_wasMoved = true; + + //CheckOwnerFlag(); + + //Invalidate(); + return false; + //return returnvalue; + } + + + public override void OnDelete() + { + // remove any temporary quest attachments associated with this quest and quest owner + XmlQuest.RemoveTemporaryQuestObjects(Owner, Name); + + base.OnDelete(); + + // remove any reward items that might be attached to this + ReturnReward(); + + // and remove any pack + if (Pack != null) + { + Pack.Delete(); + } + CheckOwnerFlag(); + } + + public override void OnItemLifted(Mobile from, Item item) + { + base.OnItemLifted(from, item); + + if (from is PlayerMobile && PlayerMade && (Owner != null) && (Owner == Creator)) + { + LootType = LootType.Regular; + } + else + if (from is PlayerMobile && Owner == null) + { + Owner = from as PlayerMobile; + + LootType = LootType.Blessed; + // flag the owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); + } + } + + public override void OnAdded(object target) + { + base.OnAdded(target); + + if ((target != null) && target is Container) + { + // find the parent of the container + // note, the only valid additions are to the player pack or a questbook. Anything else is invalid. This is to avoid exploits involving storage or transfer of questtokens + // make an exception for playermade quests that can be put on playervendors + object parentOfTarget = ((Container)target).Parent; + + // if this is a QuestBook then allow additions if it is in a players pack or it is a player quest + if ((parentOfTarget != null) && parentOfTarget is Container && target is XmlQuestBook) + { + parentOfTarget = ((Container)parentOfTarget).Parent; + } + + + + // check to see if it can be added. + // allow playermade quests to be placed in playervendors or in xmlquestbooks that are in the world (supports the playerquestboards) + if (PlayerMade && (((parentOfTarget != null) && parentOfTarget is PlayerVendor) || + ((parentOfTarget == null) && target is XmlQuestBook))) + { + CheckOwnerFlag(); + + Owner = null; + + LootType = LootType.Regular; + } + else + if ((parentOfTarget != null) && (parentOfTarget is PlayerMobile) && PlayerMade && (Owner != null) && ((Owner == Creator) || (Creator == null))) + { + // check the old owner + CheckOwnerFlag(); + + Owner = parentOfTarget as PlayerMobile; + + // first owner will become creator by default + if (Creator == null) + Creator = Owner; + + LootType = LootType.Blessed; + + // flag the new owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); + + } + else + if ((parentOfTarget != null) && (parentOfTarget is PlayerMobile)) + { + if (Owner == null) + { + Owner = parentOfTarget as PlayerMobile; + + LootType = LootType.Blessed; + + // flag the owner as carrying a questtoken + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, true); + } + else + if ((parentOfTarget as PlayerMobile != Owner) || (target is BankBox)) + { + // tried to give it to another player or placed it in the players bankbox. try to return it to the owners pack + Owner.AddToBackpack(this); + /* + // this has been added to a player who is not the owner so invalidate it + WasMoved = true; + + CheckOwnerFlag(); + + Invalidate(); + */ + + } + } + else + { + if (Owner != null) + { + // try to return it to the owners pack + Owner.AddToBackpack(this); + } + // allow placement into npcs or drop on their corpses when owner is null + else + if (!(parentOfTarget is Mobile) && !(target is Corpse) && parentOfTarget != null) + { + + // in principle this should never be reached + + // invalidate the token + + WasMoved = true; + + CheckOwnerFlag(); + + Invalidate(); + } + } + } + } + + private ArrayList m_Journal; + public ArrayList Journal { get { return m_Journal; } set { m_Journal = value; } } + private static char[] colondelim = new char[1] { ':' }; + + public string AddJournalEntry + { + set + { + if (value == null) return; + + // parse the value + string[] args = value.Split(colondelim, 2); + + if (args == null) return; + + string entryID = null; + string entryText = null; + if (args.Length > 0) + { + entryID = args[0].Trim(); + } + + if (entryID == null || entryID.Length == 0) return; + + if (args.Length > 1) + { + entryText = args[1].Trim(); + } + + + // allocate a new journal if none exists + if (m_Journal == null) m_Journal = new ArrayList(); + + // go through the existing journal to find a matching ID + XmlQuest.JournalEntry foundEntry = null; + + foreach (XmlQuest.JournalEntry e in m_Journal) + { + if (e.EntryID == entryID) + { + foundEntry = e; + break; + } + } + + if (foundEntry != null) + { + + if (entryText == null || entryText.Length == 0) + { + // delete the entry + m_Journal.Remove(foundEntry); + } + else + { + // just replace the text + foundEntry.EntryText = entryText; + } + } + else + { + if (entryText != null && entryText.Length != 0) + { + // add the new entry + m_Journal.Add(new XmlQuest.JournalEntry(entryID, entryText)); + } + } + } + } + + + private void QuestCompletionAttachment() + { + bool complete = IsCompleted; + + // is this quest repeatable + if ((!Repeatable || NextRepeatable > TimeSpan.Zero) && complete) + { + double expiresin = Repeatable ? NextRepeatable.TotalMinutes : 0; + + // then add an attachment indicating that it has already been done + XmlAttach.AttachTo(Owner, new XmlQuestAttachment(this.Name, expiresin)); + } + + // have quest points been enabled? + if (XmlQuest.QuestPointsEnabled && complete && !PlayerMade) + { + XmlQuestPoints.GiveQuestPoints(Owner, this); + } + } + + private void PackItem(Item item) + { + if ((m_Pack == null || m_Pack.Deleted) && (Owner != null) /* && (this.RootParent is Mobile) */) + { + m_Pack = new XmlQuestTokenPack(); + + m_Pack.Layer = Layer.Invalid; + + //m_Pack.Parent = Owner; + m_Pack.Parent = this; + //m_Pack.Map = Owner.Map; + m_Pack.Map = this.Map; + m_Pack.Location = this.Location; + + } + + if ((m_Pack != null) && !m_Pack.Deleted) + { + + m_Pack.DropItem(item); + PackItemsMovable(m_Pack, false); + + UpdateTotal(m_Pack, TotalType.Weight, 0); + UpdateTotal(m_Pack, TotalType.Gold, 0); + + } + // make sure the weight and gold of the questtoken is updated to reflect the weight of added rewards in playermade quests to avoid + // exploits where quests are used as zero weight containers + + UpdateWeight(); + } + + + private void CalculateWeight(Item target) + { + if (target is Container) + { + int gold = 0; + int weight = 0; + int nitems = 0; + foreach (Item i in ((Container)target).FindItemsByType(typeof(Item), false)) + { + // make sure gold amount is consistent with totalgold + if (i is Gold) + { + UpdateTotal(i, TotalType.Gold, i.Amount); + } + + if (i is Container) + { + CalculateWeight(i); + weight += i.TotalWeight + (int)i.Weight; + gold += i.TotalGold; + nitems += i.TotalItems + 1; + } + else + { + weight += (int)(i.Weight * i.Amount); + gold += i.TotalGold; + nitems += 1; + } + } + + UpdateTotal((Container)target, TotalType.Weight, weight); + UpdateTotal((Container)target, TotalType.Gold, gold); + UpdateTotal((Container)target, TotalType.Items, nitems); + } + } + + + private void UpdateWeight() + { + + + // update the weight of the reward item itself + CalculateWeight(m_RewardItem); + + // make sure the weight and gold of the questtoken is updated to reflect the weight of added rewards + if (m_RewardItem != null && !m_RewardItem.Deleted && PlayerMade) + { + if (m_RewardItem is Container) + { + UpdateTotal(this, TotalType.Weight, m_RewardItem.TotalWeight + (int)m_RewardItem.Weight); + UpdateTotal(this, TotalType.Gold, m_RewardItem.TotalGold); + } + else + { + UpdateTotal(this, TotalType.Weight, (int)(m_RewardItem.Weight * m_RewardItem.Amount)); + UpdateTotal(this, TotalType.Gold, m_RewardItem.TotalGold); + + } + + } + else + { + UpdateTotal(this, TotalType.Weight, 0); + UpdateTotal(this, TotalType.Gold, 0); + } + + } + + private void ReturnReward() + { + if (m_RewardItem != null) + { + + CheckRewardItem(); + + // if this was player made, then return the item to the creator + if (PlayerMade && (Creator != null) && !Creator.Deleted) + { + m_RewardItem.Movable = true; + if (m_Pack != null && !m_Pack.Deleted) + { + // make sure all of the items in the pack are movable as well + PackItemsMovable(m_Pack, true); + } + bool returned = false; + + //RefreshPackLocation(Creator, false); + + if ((ReturnContainer != null) && !ReturnContainer.Deleted) + { + returned = ReturnContainer.TryDropItem(Creator, m_RewardItem, false); + //ReturnContainer.DropItem(m_RewardItem); + } + if (!returned) + { + + returned = Creator.AddToBackpack(m_RewardItem); + + } + if (returned) + { + Creator.SendMessage("Your reward {0} was returned from quest {1}", m_RewardItem.GetType().Name, Name); + //AddMobileWeight(Creator, m_RewardItem); + } + else + { + Creator.SendMessage("Attempted to return reward {0} from quest {1} : containers full.", m_RewardItem.GetType().Name, Name); + } + } + else + { + // just delete it + m_RewardItem.Delete(); + + } + m_RewardItem = null; + UpdateWeight(); + } + if (m_RewardAttachment != null) + { + // delete any remaining attachments + m_RewardAttachment.Delete(); + } + + } + + [CommandProperty(AccessLevel.GameMaster)] + public PlayerMobile Owner + { + get { return m_Owner; } + set { m_Owner = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public new string Name + { + get + { + if (PlayerMade) + { + return "PQ: " + base.Name; + } + else + { + return base.Name; + } + } + set + { + base.Name = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public PlayerMobile Creator + { + get { return m_Creator; } + set { m_Creator = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Difficulty + { + get { return m_QuestDifficulty; } + set { m_QuestDifficulty = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string NoteString + { + get { return m_NoteString; } + set { m_NoteString = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AutoReward + { + get { return m_AutoReward; } + set { m_AutoReward = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanSeeReward + { + // dont allow rewards to be seen on xmlquesttokens + get { return false; } + set { } + } + /* + [CommandProperty( AccessLevel.GameMaster )] + public bool CanSeeReward + { + get{ return m_CanSeeReward; } + set { m_CanSeeReward = value; } + } + */ + [CommandProperty(AccessLevel.GameMaster)] + public bool PlayerMade + { + get { return m_PlayerMade; } + set { m_PlayerMade = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Container ReturnContainer + { + get { return m_ReturnContainer; } + set { m_ReturnContainer = value; } + } + + public Container Pack + { + get { return m_Pack; } + } + + private void PackItemsMovable(Container pack, bool canmove) + { + if (pack == null) return; + + Item[] itemlist = pack.FindItemsByType(typeof(Item), true); + if (itemlist != null) + { + for (int i = 0; i < itemlist.Length; i++) + { + itemlist[i].Movable = canmove; + } + } + + } + + private void RestoreRewardAttachment() + { + m_RewardAttachment = XmlAttach.FindAttachmentBySerial(m_RewardAttachmentSerialNumber); + } + + public XmlAttachment RewardAttachment + { + get + { + // if the reward item is not set, and the reward string is specified, then use the reward string to construct and assign the + // reward item + // dont allow player made quests to use the rewardstring creation feature + if (m_RewardAttachment != null && m_RewardAttachment.Deleted) m_RewardAttachment = null; + + if ((m_RewardAttachment == null || m_RewardAttachment.Deleted) && + (m_AttachmentString != null) && !PlayerMade) + { + object o = XmlQuest.CreateItem(this, m_AttachmentString, out m_status_str, typeof(XmlAttachment)); + if (o is Item) + { + // should never get here + ((Item)o).Delete(); + } + else + if (o is XmlAttachment) + { + m_RewardAttachment = o as XmlAttachment; + m_RewardAttachment.OwnedBy = this; + } + } + + return m_RewardAttachment; + } + set + { + // get rid of any existing attachment + if (m_RewardAttachment != null && !m_RewardAttachment.Deleted) + { + m_RewardAttachment.Delete(); + } + + m_RewardAttachment = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item RewardItem + { + get + { + // if the reward item is not set, and the reward string is specified, then use the reward string to construct and assign the + // reward item + // dont allow player made quests to use the rewardstring creation feature + if ((m_RewardItem == null || m_RewardItem.Deleted) && + (m_RewardString != null) && !PlayerMade) + { + string status_str; + object o = XmlQuest.CreateItem(this, m_RewardString, out status_str, typeof(Item)); + if (o is Item) + { + m_RewardItem = o as Item; + } + else + if (o is XmlAttachment) + { + // should never get here + ((XmlAttachment)o).Delete(); + } + } + + // place it in the xmlquesttoken pack if it isnt already there + if ((m_RewardItem != null && !m_RewardItem.Deleted) && ((Pack == null) || Pack.Deleted || (m_RewardItem.Parent != Pack))) + { + PackItem(m_RewardItem); + } + + return m_RewardItem; + } + set + { + // get rid of any existing reward item if it has been assigned + if (m_RewardItem != null && !m_RewardItem.Deleted) + { + + ReturnReward(); + } + + // and assign the new item + m_RewardItem = value; + + // and put it in the xmlquesttoken pack + if (m_RewardItem != null && !m_RewardItem.Deleted) + { + PackItem(m_RewardItem); + } + + // is this currently carried by a mobile? + if (m_RewardItem.RootParent != null && m_RewardItem.RootParent is Mobile) + { + // if so then remove it + ((Mobile)(m_RewardItem.RootParent)).RemoveItem(m_RewardItem); + + } + + + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string TitleString + { + get { return m_TitleString; } + set { m_TitleString = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string RewardString + { + get { return m_RewardString; } + set { m_RewardString = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string AttachmentString + { + get { return m_AttachmentString; } + set { m_AttachmentString = value; } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public string ConfigFile + { + get { return m_ConfigFile; } + set { m_ConfigFile = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool LoadConfig + { + get { return false; } + set { if (value == true) LoadXmlConfig(ConfigFile); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PartyEnabled + { + get { return m_PartyEnabled; } + set { m_PartyEnabled = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public int PartyRange + { + get { return m_PartyRange; } + set { m_PartyRange = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State1 + { + get { return m_State1; } + set { m_State1 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State2 + { + get { return m_State2; } + set { m_State2 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State3 + { + get { return m_State3; } + set { m_State3 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State4 + { + get { return m_State4; } + set { m_State4 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string State5 + { + get { return m_State5; } + set { m_State5 = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Description1 + { + get { return m_Description1; } + set { m_Description1 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description2 + { + get { return m_Description2; } + set { m_Description2 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description3 + { + get { return m_Description3; } + set { m_Description3 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description4 + { + get { return m_Description4; } + set { m_Description4 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Description5 + { + get { return m_Description5; } + set { m_Description5 = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Objective1 + { + get { return m_Objective1; } + set { m_Objective1 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective2 + { + get { return m_Objective2; } + set { m_Objective2 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective3 + { + get { return m_Objective3; } + set { m_Objective3 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective4 + { + get { return m_Objective4; } + set { m_Objective4 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public string Objective5 + { + get { return m_Objective5; } + set { m_Objective5 = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed1 + { + get { return m_Completed1; } + set + { + m_Completed1 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed2 + { + get { return m_Completed2; } + set + { + m_Completed2 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed3 + { + get { return m_Completed3; } + set + { + m_Completed3 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed4 + { + get { return m_Completed4; } + set + { + m_Completed4 = value; + CheckAutoReward(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Completed5 + { + get { return m_Completed5; } + set + { + m_Completed5 = value; + CheckAutoReward(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Status + { + get { return m_status_str; } + set { m_status_str = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool WasMoved + { + get { return m_wasMoved; } + set { m_wasMoved = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime TimeCreated + { + get { return m_TimeCreated; } + set { m_TimeCreated = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Expiration + { + get + { + return m_ExpirationDuration; + } + set + { + // cap the max value at 100 years + if (value > 876000) + { + m_ExpirationDuration = 876000; + } + else + { + m_ExpirationDuration = value; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan ExpiresIn + { + get + { + if (m_ExpirationDuration > 0) + { + // if this is a player created quest, then refresh the expiration time until it is in someone elses possession + /* + if(PlayerMade && ((Owner == Creator) || (Owner == null))) + { + m_TimeCreated = DateTime.Now; + } + */ + return (m_TimeCreated + TimeSpan.FromHours(m_ExpirationDuration) - DateTime.Now); + } + else + { + return TimeSpan.FromHours(0); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsExpired + { + get + { + if (((m_ExpirationDuration > 0) && (ExpiresIn <= TimeSpan.FromHours(0)))) + { + + return true; + } + else + return false; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool Repeatable + { + get + { + return m_Repeatable; + } + set + { + m_Repeatable = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual TimeSpan NextRepeatable + { + get + { + return m_NextRepeatable; + } + set + { + m_NextRepeatable = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool AlreadyDone + { + get + { + // look for a quest attachment with the current quest name + if (XmlAttach.FindAttachment(Owner, typeof(XmlQuestAttachment), Name) == null) + return false; + + return true; + + } + } + + public virtual string ExpirationString + { + get + { + if (AlreadyDone) + { + return "Already done"; + } + else + if (m_ExpirationDuration <= 0) + { + return "Never expires"; + } + else + if (IsExpired) + { + return "Expired"; + } + else + { + TimeSpan ts = ExpiresIn; + + int days = (int)ts.TotalDays; + int hours = (int)(ts - TimeSpan.FromDays(days)).TotalHours; + int minutes = (int)(ts - TimeSpan.FromHours(hours)).TotalMinutes; + int seconds = (int)(ts - TimeSpan.FromMinutes(minutes)).TotalSeconds; + + if (days > 0) + { + return String.Format("Expires in {0} days {1} hrs", days, hours); + } + else + if (hours > 0) + { + return String.Format("Expires in {0} hrs {1} mins", hours, minutes); + } + else + { + return String.Format("Expires in {0} mins {1} secs", minutes, seconds); + } + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsValid + { + get + { + if (WasMoved || IsExpired) + { + // eliminate reward definitions + RewardString = null; + AttachmentString = null; + + // return any reward items + ReturnReward(); + + // and get rid of the pack + if (Pack != null) + Pack.Delete(); + + return false; + } + else + if (AlreadyDone) + { + return false; + } + else + return true; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsCompleted + { + get + { + if (IsValid && + (Completed1 || Objective1 == null || (Objective1.Length == 0)) && + (Completed2 || Objective2 == null || (Objective2.Length == 0)) && + (Completed3 || Objective3 == null || (Objective3.Length == 0)) && + (Completed4 || Objective4 == null || (Objective4.Length == 0)) && + (Completed5 || Objective5 == null || (Objective5.Length == 0)) + ) + return true; + else + return false; + } + } + + + public bool HandlesOnSkillUse { get { return (IsValid && m_SkillTrigger != null && m_SkillTrigger.Length > 0); } } + + public void OnSkillUse(Mobile m, Skill skill, bool success) + { + } + + private void CheckOwnerFlag() + { + if (Owner != null && !Owner.Deleted) + { + // need to check to see if any other questtoken items are owned + // search the Owners top level pack for an xmlquesttoken + ArrayList list = XmlQuest.FindXmlQuest(Owner); + + if (list == null || list.Count == 0) + { + + // if none remain then flag the ower as having none + Owner.SetFlag(XmlQuest.CarriedXmlQuestFlag, false); + } + } + + + } + + public virtual void Invalidate() + { + //Hue = 32; + //LootType = LootType.Regular; + if (Owner != null) + { + Owner.SendMessage(String.Format("Quest invalidated - '{0}' removed", Name)); + } + this.Delete(); + } + + + public void CheckRewardItem() + { + // go through all reward items and delete anything that is movable. This blocks any exploits where players might + // try to add items themselves + if (m_RewardItem != null && !m_RewardItem.Deleted && m_RewardItem is Container) + { + foreach (Item i in ((Container)m_RewardItem).FindItemsByType(typeof(Item), true)) + { + if (i.Movable) + { + i.Delete(); + } + } + } + + } + + public void CheckAutoReward() + { + if (!this.Deleted && AutoReward && IsCompleted && Owner != null && + ((RewardItem != null && !m_RewardItem.Deleted) || (RewardAttachment != null && !m_RewardAttachment.Deleted))) + { + if (RewardItem != null) + { + // make sure nothing has been added to the pack other than the original reward items + CheckRewardItem(); + + m_RewardItem.Movable = true; + if (m_Pack != null) + { + // make sure all of the items in the pack are movable as well + PackItemsMovable(m_Pack, true); + } + //RefreshPackLocation(Owner, false); + + + Owner.AddToBackpack(m_RewardItem); + //AddMobileWeight(Owner,m_RewardItem); + + m_RewardItem = null; + } + + if (RewardAttachment != null) + { + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(AttachToCallback), new object[] { Owner, m_RewardAttachment }); + + m_RewardAttachment = null; + } + + Owner.SendMessage(String.Format("{0} completed. You receive the quest reward!", Name)); + this.Delete(); + } + } + + public void AttachToCallback(object state) + { + object[] args = (object[])state; + + XmlAttach.AttachTo(args[0], (XmlAttachment)args[1]); + } + + private const string XmlTableName = "Properties"; + private const string XmlDataSetName = "XmlQuestToken"; + + public void LoadXmlConfig(string filename) + { + if (filename == null || filename.Length <= 0) return; + + // Check if the file exists + if (System.IO.File.Exists(filename) == true) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + Status = String.Format("Unable to open {0} for loading", filename); + return; + } + // Create the data set + DataSet ds = new DataSet(XmlDataSetName); + + // Read in the file + //ds.ReadXml( e.Arguments[0].ToString() ); + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch { fileerror = true; } + // close the file + fs.Close(); + if (fileerror) + { + Console.WriteLine("XmlQuestToken: Error in XML config file '{0}'", filename); + return; + } + // Check that at least a single table was loaded + if (ds.Tables != null && ds.Tables.Count > 0) + { + if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[XmlTableName].Rows) + { + bool valid_entry; + string strEntry = null; + bool boolEntry = true; + double doubleEntry = 0; + int intEntry = 0; + TimeSpan timespanEntry = TimeSpan.Zero; + + valid_entry = true; + try { strEntry = (string)dr["Name"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Name = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Title"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.TitleString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Note"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.NoteString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Reward"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.RewardString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Attachment"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.AttachmentString = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective1"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective1 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective2"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective2 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective3"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective3 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective4"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective4 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Objective5"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Objective5 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description1"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description1 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description2"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description2 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description3"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description3 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description4"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description4 = strEntry; + } + + valid_entry = true; + strEntry = null; + try { strEntry = (string)dr["Description5"]; } + catch { valid_entry = false; } + if (valid_entry) + { + this.Description5 = strEntry; + } + + valid_entry = true; + boolEntry = false; + try { boolEntry = bool.Parse((string)dr["PartyEnabled"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.PartyEnabled = boolEntry; + } + + valid_entry = true; + boolEntry = false; + try { boolEntry = bool.Parse((string)dr["AutoReward"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.AutoReward = boolEntry; + } + + valid_entry = true; + boolEntry = true; + try { boolEntry = bool.Parse((string)dr["CanSeeReward"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.CanSeeReward = boolEntry; + } + + valid_entry = true; + boolEntry = true; + try { boolEntry = bool.Parse((string)dr["Repeatable"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.m_Repeatable = boolEntry; + } + + valid_entry = true; + timespanEntry = TimeSpan.Zero; + try { timespanEntry = TimeSpan.Parse((string)dr["NextRepeatable"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.m_NextRepeatable = timespanEntry; + } + + valid_entry = true; + boolEntry = false; + try { boolEntry = bool.Parse((string)dr["PlayerMade"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.PlayerMade = boolEntry; + } + + valid_entry = true; + intEntry = 0; + try { intEntry = int.Parse((string)dr["PartyRange"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.PartyRange = intEntry; + } + + valid_entry = true; + doubleEntry = 0; + try { doubleEntry = double.Parse((string)dr["Expiration"]); } + catch { valid_entry = false; } + if (valid_entry) + { + this.Expiration = doubleEntry; + } + } + } + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlSpawner2.cs b/Scripts/Customs/XML Spawner/XmlSpawner2.cs new file mode 100644 index 0000000..83502b0 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlSpawner2.cs @@ -0,0 +1,12555 @@ +//#define TRACE +//#define RUNUO2RC1 +//#define RESTRICTCONSTRUCTABLE + +using System; +using System.Data; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using System.Diagnostics; +using Server.Misc; +using Server.Engines.XmlSpawner2; + +/* +** XmlSpawner2 +** version 3.24 +** updated 2/11/08 +** ArteGordon +** Modification of the original XmlSpawner written by bobsmart +*/ + +namespace Server.Mobiles +{ + + public class XmlSpawner : Item, ISpawner + { + + #region Type declarations + + public enum TODModeType { Realtime, Gametime } + + public enum SpawnPositionType { Random, RowFill, ColFill, Perimeter, Player, Waypoint, RelXY, DeltaLocation, Location, Wet, Tiles, NoTiles } + + public class SpawnPositionInfo + { + public SpawnPositionType positionType; + public Mobile trigMob; + public string[] positionArgs; + + public SpawnPositionInfo(SpawnPositionType positiontype, Mobile trigmob, string[] positionargs) + { + positionType = positiontype; + trigMob = trigmob; + positionArgs = positionargs; + } + } + + public class MovementInfo + { + public Mobile trigMob; + public Point3D trigLocation = Point3D.Zero; + + public MovementInfo(Mobile m) + { + trigMob = m; + if (m != null) + trigLocation = m.Location; + } + } + + #endregion + + #region Constant declarations + + public const string Version = "3.24"; + //private const double SpawnIdleTime = 72.0; // time in hours after which idle spawns will be relocated. A value < 0 disables this feature. This does not work properly under RunUO 2.0 + private const int ShowBoundsItemId = 14089; // 14089 Fire Column // 3555 Campfire // 8708 Skull Pole + private const string SpawnDataSetName = "Spawns"; + private const string SpawnTablePointName = "Points"; + private const int SpawnFitSize = 16; // Normal wall/door height for a mobile is 20 to walk through + private static int BaseItemId = 0x1F1C; // Purple Magic Crystal + private static int ShowItemId = 0x3E57; // ships mast + private static int defaultTriggerSound = 0x1F4; // click and sparkle sound by default (0x1F4) , click sound (0x3A4) + public static string XmlSpawnDir = "Spawns"; // default directory for saving/loading .xml files with [xmlload [xmlsave + private static string XmlConfigsDir = "SpawnerConfigs"; // default directory for loading .xml config files with LoadConfig + private const int MaxSmartSectorListSize = 1024; // maximum sector list size for use in smart spawning. This gives a 512x512 tile range. + + private static string defwaypointname = null; // default waypoint name will get assigned in Initialize + private const string XmlTableName = "Properties"; + private const string XmlDataSetName = "XmlSpawner"; + public static AccessLevel DiskAccessLevel = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit +#if(RESTRICTCONSTRUCTABLE) + public static AccessLevel ConstructableAccessLevel = AccessLevel.GameMaster; // only allow spawning of objects that have Constructable access restrictions at this level or lower. Must define RESTRICTCONSTRUCTABLE to enable this. +#endif + private static int MaxMoveCheck = 10; // limit number of players that can be checked for triggering in a single OnMovement tick + + #endregion + + #region Static variable declarations + + // specifies the level at which smartspawning will be triggered. Players with AccessLevel above this will not trigger smartspawning unless unhidden. + public static AccessLevel SmartSpawnAccessLevel = AccessLevel.Owner; + + // define the default values used in making spawners + private static TimeSpan defMinDelay = TimeSpan.FromMinutes(5); + private static TimeSpan defMaxDelay = TimeSpan.FromMinutes(10); + private static TimeSpan defMinRefractory = TimeSpan.FromMinutes(0); + private static TimeSpan defMaxRefractory = TimeSpan.FromMinutes(0); + private static TimeSpan defTODStart = TimeSpan.FromMinutes(0); + private static TimeSpan defTODEnd = TimeSpan.FromMinutes(0); + private static TimeSpan defDuration = TimeSpan.FromMinutes(0); + private static TimeSpan defDespawnTime = TimeSpan.FromHours(0); + private static bool defIsGroup = false; + private static int defTeam = 0; + private static int defProximityTriggerSound = defaultTriggerSound; + private static int defAmount = 1; + private static bool defRelativeHome = true; + private static int defSpawnRange = 5; + private static int defHomeRange = 5; + private static double defTriggerProbability = 1; + private static int defProximityRange = -1; + private static int defKillReset = 1; + private static TODModeType defTODMode = TODModeType.Realtime; + + private static Timer m_GlobalSectorTimer; + private static bool SmartSpawningSystemEnabled = false; + + private static WarnTimer2 m_WarnTimer; + + // hash table for optimizing HoldSmartSpawning method invocation + private static Hashtable holdSmartSpawningHash; + + public static int seccount; + + // sector hashtable for each map + private static Hashtable[] GlobalSectorTable = new Hashtable[5]; + + #endregion + + #region Variable declarations + + private string m_Name = string.Empty; + private string m_UniqueId = string.Empty; + private bool m_PlayerCreated = false; + private bool m_HomeRangeIsRelative = false; + private int m_Team; + private int m_HomeRange; + // added a amount parameter for stacked item spawns + private int m_StackAmount; + // this is actually redundant with the width height spec for spawning area + // just an easier way of specifying it + private int m_SpawnRange; + private int m_Count; + private TimeSpan m_MinDelay; + private TimeSpan m_MaxDelay; + // added a duration parameter for time-limited spawns + private TimeSpan m_Duration; + public ArrayList m_SpawnObjects = new ArrayList(); // List of objects to spawn + private DateTime m_End; + private DateTime m_RefractEnd; + private DateTime m_DurEnd; + private SpawnerTimer m_Timer; + private InternalTimer m_DurTimer; + private InternalTimer3 m_RefractoryTimer; + private bool m_Running; + private bool m_Group; + private int m_X; + private int m_Y; + private int m_Width; + private int m_Height; + private WayPoint m_WayPoint; + + private Static m_ShowContainerStatic; + private bool m_proximityActivated; + private bool m_refractActivated; + private bool m_durActivated; + private TimeSpan m_TODStart; + private TimeSpan m_TODEnd; + // time after proximity activation when the spawn cannot be reactivated + private TimeSpan m_MinRefractory; + private TimeSpan m_MaxRefractory; + private string m_ItemTriggerName; + private string m_NoItemTriggerName; + private Item m_ObjectPropertyItem; + private string m_ObjectPropertyName; + public string status_str; + public int m_killcount; + // added proximity range sensor + private int m_ProximityRange; + // sound played when a proximity triggered spawner is tripped by a player + // set this to zero if you dont want to hear anything + private int m_ProximityTriggerSound; + private string m_ProximityTriggerMessage; + private string m_SpeechTrigger; + private bool m_speechTriggerActivated; + private string m_MobPropertyName; + private string m_MobTriggerName; + private string m_PlayerPropertyName; + private double m_TriggerProbability = defTriggerProbability; + private Mobile m_mob_who_triggered; + private Item m_SetPropertyItem; + + private bool m_skipped = false; + private int m_KillReset = defKillReset; // number of spawn ticks that pass without kills before killcount gets reset to zero + private int m_spawncheck = 0; + private TODModeType m_TODMode = TODModeType.Realtime; + private string m_GumpState; + private bool m_ExternalTriggering; + private bool m_ExternalTrigger; + private int m_SequentialSpawning = -1; // off by default + private DateTime m_SeqEnd; + private Region m_Region; // 2004.02.08 :: Omega Red + private string m_RegionName = string.Empty; // 2004.02.08 :: Omega Red + private AccessLevel m_TriggerAccessLevel = AccessLevel.Player; + + public ArrayList m_TextEntryBook; + private XmlSpawnerGump m_SpawnerGump; + + private bool m_AllowGhostTriggering = false; + private bool m_AllowNPCTriggering = false; + private string m_ConfigFile; + private bool m_OnHold = false; + private bool m_HoldSequence = false; + private bool m_SpawnOnTrigger = false; + + private DateTime m_FirstModified; + private DateTime m_LastModified; + + private ArrayList m_MovementList; + private MovementTimer m_MovementTimer; + internal ArrayList m_KeywordTagList = new ArrayList(); + private string m_FirstModifiedBy = null; + private string m_LastModifiedBy = null; + + public ArrayList RecentSpawnerSearchList = null; + public ArrayList RecentItemSearchList = null; + public ArrayList RecentMobileSearchList = null; + private TimeSpan m_DespawnTime; + + private string m_SkillTrigger; + private bool m_skillTriggerActivated; + private SkillName m_skill_that_triggered; + private bool m_FreeRun = false; // override for all other triggering modes + private SkillName m_SkillTriggerName; + private double m_SkillTriggerMin; + private double m_SkillTriggerMax; + private int m_SkillTriggerSuccess; + private Map currentmap; + + public bool m_IsInactivated = false; + private bool m_SmartSpawning = false; + private SectorTimer m_SectorTimer; + + private ArrayList m_ShowBoundsItems = new ArrayList(); + + public ArrayList PropertyInfoList = null; // used to optimize property info lookup used by set and get property methods. + + private Hashtable spawnPositionWayTable = null; // used to optimize #waypoint lookup + + private bool inrespawn = false; + + private ArrayList sectorList = null; + + private bool m_Debug; + + private Point3D mostRecentSpawnPosition = Point3D.Zero; + + private int m_MovingPlayerCount = 0; + private int m_FastestPlayerSpeed = 0; + + private bool m_DebugThis = false; + + private TimerPriority m_BasePriority = TimerPriority.OneSecond; + + + #endregion + + #region Property Overrides + + // does not decay + public override bool Decays { get { return false; } } + // is not counted in the normal item count + public override bool IsVirtualItem { get { return true; } } + + #endregion + + #region Properties + + public TimerPriority BasePriority { get { return m_BasePriority; } set { m_BasePriority = value; } } + + public bool DebugThis { get { return m_DebugThis; } set { m_DebugThis = value; } } + + public int MovingPlayerCount { get { return m_MovingPlayerCount; } set { m_MovingPlayerCount = value; } } + + public int FastestPlayerSpeed { get { return m_FastestPlayerSpeed; } set { m_FastestPlayerSpeed = value; } } + + public int NearbyPlayerCount + { + get + { + int count = 0; + if (ProximityRange >= 0) + { + foreach (Mobile m in GetMobilesInRange(ProximityRange)) + { + if (m != null && m.Player) count++; + } + } + return count; + } + } + + public Point3D MostRecentSpawnPosition + { + get { return mostRecentSpawnPosition; } + set { mostRecentSpawnPosition = value; } + } + + public TimeSpan GameTOD + { + get + { + int hours; + int minutes; + + Server.Items.Clock.GetTime(this.Map, this.Location.X, this.Location.Y, out hours, out minutes); + return (new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, hours, minutes, 0).TimeOfDay); + } + } + + public TimeSpan RealTOD { get { return DateTime.Now.TimeOfDay; } } + + public int RealDay { get { return DateTime.Now.Day; } } + + public int RealMonth { get { return DateTime.Now.Month; } } + + public DayOfWeek RealDayOfWeek { get { return DateTime.Now.DayOfWeek; } } + + public MoonPhase MoonPhase + { + get + { + return Clock.GetMoonPhase(this.Map, this.Location.X, this.Location.Y); + } + + } + + public XmlSpawnerGump SpawnerGump + { + get { return m_SpawnerGump; } + set + { + m_SpawnerGump = value; + } + } + + public bool Debug { get { return m_Debug; } set { m_Debug = value; } } + + public bool DoDefrag + { + get { return false; } + set + { + if (value == true) + { + Defrag(true); + } + } + } + + private bool sectorIsActive = false; + private bool UseSectorActivate = false; + + public bool SingleSector { get { return UseSectorActivate; } } + + /* + public override void OnSectorDeactivate() + { + sectorIsActive = false; + base.OnSectorDeactivate(); + } + + public override void OnSectorActivate() + { + sectorIsActive = true; + + base.OnSectorActivate(); + + // perform the smart respawning + if(SmartSpawning && IsInactivated && UseSectorActivate) + { + SmartRespawn(); + } + + } + */ + + public bool InActivationRange(Sector s1, Sector s2) + { + // check to see if the sectors are within +- 2 of one another + if (s1 == null || s2 == null) return false; + + return (Math.Abs(s1.X - s2.X) < 3 && Math.Abs(s1.Y - s2.Y) < 3); + } + + public bool HasDamagedOrDistantSpawns + { + get + { + Sector ssec = Map.GetSector(Location); + // go through the spawn lists + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + + if (o is BaseCreature) + { + BaseCreature b = (BaseCreature)o; + + // if the mob is damaged or outside of smartspawning detection range then return true + if ((b.Hits < b.HitsMax) || (b.Mana < b.ManaMax) || (b.Stam < b.StamMax) || (b.Map != this.Map)) + { + return true; + } + + // if the spawn moves into a sector that is not activatable from a sector on the sector list then dont smartspawn + if (b.Map != null && b.Map != Map.Internal) + { + Sector bsec = b.Map.GetSector(b.Location); + + if (UseSectorActivate) + { + // is it in activatable range of the sector the spawner is in + if (!InActivationRange(bsec, ssec)) + { + return true; + } + } + else + { + bool outofsec = true; + + if (sectorList != null) + { + foreach (Sector s in sectorList) + { + // is the creatures sector within activation range of any of the sectors in the list + if (InActivationRange(bsec, s)) + { + outofsec = false; + break; + } + } + } + + if (outofsec) + { + return true; + } + } + } + } + } + } + + return false; + } + } + + private static int totalSectorsMonitored = 0; + + + public bool HasActiveSectors + { + get + { + if (!SmartSpawning || Map == null || Map == Map.Internal) return false; + + // is this a region spawner? + if (m_Region != null) + { + List players = m_Region.GetPlayers(); + + if (players == null || players.Count == 0) return false; + + // confirm that players with the proper access level are present + foreach (Mobile m in players) + { + if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) + { + return true; + } + } + return false; + } + // is this a single sector spawner? + if (UseSectorActivate) + { + return sectorIsActive; + } + + // if there is no sector list made for this spawner then create one. + if (sectorList == null) + { + Point3D loc = this.Location; + sectorList = new ArrayList(); + + // is this container held? + if (Parent != null) + { + if (RootParent is Mobile) + loc = ((Mobile)(RootParent)).Location; + else + if (RootParent is Item) + loc = ((Item)(RootParent)).Location; + } + + // find the max detection range by examining both spawnrange + // note, sectors will activate when within +-2 sectors + int bufferzone = 2 * Server.Map.SectorSize; + int x1 = m_X - bufferzone; + int width = m_Width + 2 * bufferzone; + int y1 = m_Y - bufferzone; + int height = m_Height + 2 * bufferzone; + + // go through all of the sectors within the SpawnRange of the spawner to see if any are active + for (int x = x1; x <= x1 + width; x += Server.Map.SectorSize) + { + for (int y = y1; y <= y1 + height; y += Server.Map.SectorSize) + { + Sector s = Map.GetSector(new Point3D(x, y, loc.Z)); + + if (s == null) continue; + + // dont add any redundant sectors + bool duplicate = false; + foreach (Sector olds in sectorList) + { + if (olds == s) + { + duplicate = true; + break; + } + } + if (!duplicate) + { + sectorList.Add(s); + + if (GlobalSectorTable[Map.MapID] == null) + { + GlobalSectorTable[Map.MapID] = new Hashtable(); + } + + // add this sector and the spawner associated with it to the global sector table + if (GlobalSectorTable[Map.MapID].Contains(s)) + { + ArrayList spawnerlist = (ArrayList)GlobalSectorTable[Map.MapID][s]; + if (spawnerlist == null) + { + //GlobalSectorTable[Map.MapID].Remove(s); + spawnerlist = new ArrayList(); + //GlobalSectorTable[Map.MapID].Add(s, spawnerlist); + GlobalSectorTable[Map.MapID][s] = spawnerlist; + } + + if (!spawnerlist.Contains(this)) + { + spawnerlist.Add(this); + + } + } + else + { + ArrayList spawnerlist = new ArrayList(); + spawnerlist.Add(this); + // add a new entry to the table + GlobalSectorTable[Map.MapID].Add(s, spawnerlist); + + } + + totalSectorsMonitored++; + + // add some sanity checking here + if (sectorList.Count > MaxSmartSectorListSize) + { + SmartSpawning = false; + + // log it + try + { + Console.WriteLine("SmartSpawning disabled at {0} {1} : Range too large.", loc, Map); + + using (StreamWriter op = new StreamWriter("badspawn.log", true)) + { + op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", DateTime.Now, loc, Map); + op.WriteLine(); + } + } + catch + { } + + return true; + } + } + + } + } + + // if the spawner is in a single sector, then we can use the OnSectorActivation method to test for activity + // note, sectors will activate when within +-2 sectors + /* + if((sectorList.Count == 1) && (Location.X >= m_X) && (Location.X <= m_X + m_Width) && + (Location.Y >= m_Y) && (Location.Y <= m_Y + m_Height)) + { + + UseSectorActivate = true; + } + else + { + UseSectorActivate = false; + } + */ + UseSectorActivate = false; + } + _TraceStart(2); + // go through the sectorlist and see if any of the sectors are active + + foreach (Sector s in sectorList) + { + + if (s != null && s.Active && s.Players != null && s.Players.Count > 0) + { + + // confirm that players with the proper access level are present + foreach (Mobile m in s.Players) + { + if (m != null && m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden) + { + return true; + } + } + _TraceEnd(2); + } + seccount++; + } + _TraceEnd(2); + return false; + } + } + + public int SecCount { get { return seccount; } } + + + public bool IsInactivated + { + get { return m_IsInactivated; } + set + { + m_IsInactivated = value; + } + } + + + public int ActiveSectorCount + { + get + { + if (sectorList != null) return sectorList.Count; + return 0; + } + } + + public DateTime FirstModified + { + get { return m_FirstModified; } + } + + public DateTime LastModified + { + get { return m_LastModified; } + } + + public bool PlayerCreated + { + get { return m_PlayerCreated; } + set { m_PlayerCreated = value; } + } + + public bool OnHold + { + get + { + if (m_OnHold) return true; + + // determine whether there are any keywordtags with the hold flag + if (m_KeywordTagList == null || m_KeywordTagList.Count == 0) return false; + + foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList) + { + // check for any keyword tag with the holdspawn flag + if (sot != null && !sot.Deleted && ((sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSpawn) != 0)) + { + return true; + } + } + // no hold flags were set + return false; + } + set { m_OnHold = value; } + } + + + public string AddSpawn + { + get { return null; } + set + { + if (value.Length > 0) + { + string str = value.Trim(); + string typestr = BaseXmlSpawner.ParseObjectType(str); + + Type type = null; + + if (typestr != null) + type = SpawnerType.GetType(typestr); + + if (type != null) + m_SpawnObjects.Add(new XmlSpawner.SpawnObject(str, 1)); + else + { + // check for special keywords + if (typestr != null && (BaseXmlSpawner.IsTypeOrItemKeyword(typestr) || typestr.IndexOf("{") != -1 || typestr.StartsWith("*") || typestr.StartsWith("#"))) + { + m_SpawnObjects.Add(new XmlSpawner.SpawnObject(str, 1)); + } + else + this.status_str = String.Format("{0} is not a valid type name.", str); + } + InvalidateProperties(); + } + } + } + + + public Skill TriggerSkill + { + get + { + if (TriggerMob != null && (int)m_skill_that_triggered >= 0) + { + return TriggerMob.Skills[m_skill_that_triggered]; + } + else + { + return null; + } + } + set + { + if (value != null) + { + m_skill_that_triggered = value.SkillName; + } + else + { + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + } + } + } + + public string UniqueId + { + get { return m_UniqueId; } + } + + // does not perform a defrag, so less accurate but can be used while looping through world object enums + public int SafeCurrentCount + { + get { return SafeTotalSpawnedObjects; } + } + + + public bool FreeRun + { + get { return m_FreeRun; } + set { m_FreeRun = value; } + } + + public bool CanFreeSpawn + { + get + { + // allow free spawning if proximity sensing is off and if all of the potential free-spawning triggers are disabled + if (Running && m_ProximityRange == -1 && + (m_ObjectPropertyName == null || m_ObjectPropertyName.Length == 0) && + (m_MobPropertyName == null || m_MobPropertyName.Length == 0 || + m_MobTriggerName == null || m_MobTriggerName.Length == 0) && + !m_ExternalTriggering) + return true; + else + return false; + } + } + + + public SpawnObject[] SpawnObjects + { + get { return (SpawnObject[])m_SpawnObjects.ToArray(typeof(SpawnObject)); } + set + { + if ((value != null) && (value.Length > 0)) + { + + foreach (SpawnObject so in value) + { + if (so == null) continue; + bool AlreadyInList = false; + + // Check if the new array has an existing spawn object + foreach (SpawnObject TheSpawn in m_SpawnObjects) + { + if (TheSpawn.TypeName.ToUpper() == so.TypeName.ToUpper()) + { + AlreadyInList = true; + break; + } + } + + // Does this item need to be added + if (AlreadyInList == false) + { + // This is a new spawn object so add it to the array (deep copy) + m_SpawnObjects.Add(new SpawnObject(so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded, + so.RestrictKillsToSubgroup, so.ClearOnAdvance, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange)); + } + } + + if (SpawnObjects.Length < 1) + Stop(); + + InvalidateProperties(); + } + } + } + + public bool HoldSequence + { + get + { + // check to see if any keyword tags have the holdsequence flag set, or whether the spawner holdsequence flag is set + if (m_HoldSequence) return true; + + // determine whether there are any keywordtags with the hold flag + if (m_KeywordTagList == null || m_KeywordTagList.Count == 0) return false; + + foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList) + { + + // check for any keyword tag with the holdsequence flag + if (sot != null && !sot.Deleted && ((sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSequence) != 0)) + { + return true; + } + } + + // no hold flags were set + return false; + + } + set { m_HoldSequence = value; } + } + + public bool CanSpawn + { + get + { + if (OnHold) return false; + + + + if (m_Group == true) + { + if (TotalSpawnedObjects <= 0) + return true; + else + return false; + } + else + { + if (IsFull) + return false; + else + return true; + } + } + } + + // test for a full spawner + public bool IsFull + { + get + { + int nobj = TotalSpawnedObjects; + + return ((nobj >= m_Count) || (nobj >= TotalSpawnObjectCount)); + } + } + + // this can be used in loops over world objects since it will not defrag and potentially modify the world object lists + public int SafeTotalSpawnedObjects + { + get + { + if (m_SpawnObjects == null) return 0; + + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + count += so.SpawnedObjects.Count; + + return count; + } + } + + public int TotalSpawnedObjects + { + get + { + if (m_SpawnObjects == null) return 0; + + // defrag so that accurately reflects currently active spawns + Defrag(true); + + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + count += so.SpawnedObjects.Count; + + return count; + } + } + + + public int TotalSpawnObjectCount + { + get + { + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + count += so.MaxCount; + + return count; + } + } + + #endregion + + #region Command Properties + + [CommandProperty(AccessLevel.GameMaster)] + public bool GumpReset + { + + set + { + if (value == true) + { + m_SpawnerGump = null; + } + } + } + + public Region SpawnRegion + { + get { return m_Region; } + set + { + // force a re-update of the smart spawning sector list the next time it is accessed + ResetSectorList(); + + m_Region = value; + + if (m_Region != null) + { + m_RegionName = m_Region.Name; + } + else + { + m_RegionName = null; + } + } + } + + // 2004.02.08 :: Omega Red + [CommandProperty(AccessLevel.GameMaster)] + public string RegionName + { + get + { + return m_RegionName; + } + set + { + // force a re-update of the smart spawning sector list the next time it is accessed + ResetSectorList(); + + m_RegionName = value; + + if (value == null || value.Length <= 0) + { + m_Region = null; + return; + } + + if (Region.Regions.Count == 0) // after world load, before region load + return; + + foreach (Region region in Region.Regions) + { + if (string.Compare(region.Name, m_RegionName, true) == 0) + { + m_Region = region; + m_RegionName = region.Name; + //InvalidateProperties(); + return; + } + } + status_str = "invalid region: " + value; + m_Region = null; + } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D X1_Y1 + { + get { return new Point3D(m_X, m_Y, Z); } + set + { + // X1 and Y1 will initiate region specification + m_Width = 0; + m_Height = 0; + m_X = value.X; + m_Y = value.Y; + + // reset the sector list + ResetSectorList(); + + m_SpawnRange = 0; + + // Check if the spawner is showing its bounds + if (ShowBounds == true) + { + ShowBounds = false; + ShowBounds = true; + } + } + } + + // added the spawnrange property. It sets both the XY and width/height parameters automatically. + // also doesnt mess with homerange like XY does + [CommandProperty(AccessLevel.GameMaster)] + public int SpawnRange + { + get { return (m_SpawnRange); } + set + { + if (value < 0) return; + + // reset the sector list + ResetSectorList(); + + m_SpawnRange = value; + m_Width = m_SpawnRange * 2; + m_Height = m_SpawnRange * 2; + + // dont set the bounding box locations if the initial location is 0,0 since this occurs when the item is just being made + // because m_X and m_Y are restored on loading, it creates problems with OnLocationChange which has to avoid applying translational + // adjustments to newly placed spawners (because the actual m_X and m_Y is associated with the original location, not the 0,0 location) + // basically, before placement, dont set m_X or m_Y to anything that needs to be adjusted later on + + if (Location.X == 0 && Location.Y == 0) return; + + m_X = Location.X - m_SpawnRange; + m_Y = Location.Y - m_SpawnRange; + + //InvalidateProperties(); + + // Check if the spawner is showing its bounds + if (ShowBounds == true) + { + ShowBounds = false; + ShowBounds = true; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowBounds + { + get { return (m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0); } + set + { + if ((value == true) && (ShowBounds == false)) + { + if (m_ShowBoundsItems == null) m_ShowBoundsItems = new ArrayList(); + + // Boundary lines + int ValidX1 = m_X; + int ValidX2 = m_X + m_Width; + int ValidY1 = m_Y; + int ValidY2 = m_Y + m_Height; + + for (int x = 0; x <= m_Width; x++) + { + int NewX = m_X + x; + for (int y = 0; y <= m_Height; y++) + { + int NewY = m_Y + y; + + if (NewX == ValidX1 || NewX == ValidX2 || NewX == ValidY1 || NewX == ValidY2 || NewY == ValidX1 || NewY == ValidX2 || NewY == ValidY1 || NewY == ValidY2) + { + // Add an object to show the spawn area + Static s = new Static(ShowBoundsItemId); + s.Visible = false; + s.MoveToWorld(new Point3D(NewX, NewY, Z), this.Map); + m_ShowBoundsItems.Add(s); + } + } + } + } + + if (value == false && m_ShowBoundsItems != null) + { + // Remove all of the items from the array + foreach (Static s in m_ShowBoundsItems) + s.Delete(); + + m_ShowBoundsItems.Clear(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D X2_Y2 + { + get { return new Point3D((m_X + m_Width), (m_Y + m_Height), Z); } + set + { + int X2; + int Y2; + + int OriginalX2 = m_X + m_Width; + int OriginalY2 = m_Y + m_Height; + + // reset the sector list + ResetSectorList(); + + // now determine based upon the entered coordinate values what the lower left corner is + // lower left will be the min x and min y + // upper right will be max x max y + if (value.X < OriginalX2) + { + // ok, this is the proper x value for the lower left + m_X = value.X; + X2 = OriginalX2; + } + else + { + m_X = OriginalX2; + X2 = value.X; + } + + if (value.Y < OriginalY2) + { + // ok, this is the proper y value for the lower left + m_Y = value.Y; + Y2 = OriginalY2; + } + else + { + m_Y = OriginalY2; + Y2 = value.Y; + } + + m_Width = X2 - m_X; + m_Height = Y2 - m_Y; + + if (m_Width == m_Height) + m_SpawnRange = m_Width / 2; + else + m_SpawnRange = -1; + + if (m_HomeRangeIsRelative == false) + { + int NewHomeRange = (m_Width > m_Height ? m_Height : m_Width); + m_HomeRange = (NewHomeRange > 0 ? NewHomeRange : 0); + } + + //original test was for less than 1, changed it to less than zero (zero is a valid width, its the default in fact) + // Stop the spawner if the width or height is less than 1 + if ((m_Width < 0) || (m_Height < 0)) + Running = false; + + InvalidateProperties(); + + // Check if the spawner is showing its bounds + if (ShowBounds == true) + { + ShowBounds = false; + ShowBounds = true; + } + } + } + /* + [CommandProperty(AccessLevel.GameMaster)] + public override string Name + { + get { return m_Name; } + set + { + m_Name = value; + InvalidateProperties(); + } + } + */ + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCount + { + get { return m_Count; } + set + { + m_Count = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CurrentCount + { + get { return TotalSpawnedObjects; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint WayPoint + { + get { return m_WayPoint; } + set { m_WayPoint = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ExternalTriggering + { + get { return m_ExternalTriggering; } + set { m_ExternalTriggering = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ExtTrigState + { + get { return m_ExternalTrigger; } + set { m_ExternalTrigger = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Running + { + get { return m_Running; } + set + { + // Don't start the spawner unless the height and width are valid + if ((value == true) && (m_Width >= 0) && (m_Height >= 0)) + { + Start(); + } + else + Stop(); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HomeRange + { + get { return m_HomeRange; } + set { m_HomeRange = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool HomeRangeIsRelative + { + get { return m_HomeRangeIsRelative; } + set { m_HomeRangeIsRelative = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Team + { + get { return m_Team; } + set { m_Team = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int StackAmount + { + get { return m_StackAmount; } + set { m_StackAmount = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MinDelay + { + get { return m_MinDelay; } + set + { + m_MinDelay = value; + // reset the spawn timer + DoTimer(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MaxDelay + { + get { return m_MaxDelay; } + set + { + m_MaxDelay = value; + // reset the spawn timer + DoTimer(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int KillCount + { + get { return m_killcount; } + set { m_killcount = value; } + } + [CommandProperty(AccessLevel.GameMaster)] + public int KillReset + { + get { return m_KillReset; } + set { m_KillReset = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double TriggerProbability + { + get { return m_TriggerProbability; } + set { m_TriggerProbability = value; } + } + + //added refractory period support + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RefractMin + { + get { return m_MinRefractory; } + set { m_MinRefractory = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RefractMax + { + get { return m_MaxRefractory; } + set { m_MaxRefractory = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RefractoryOver + { + get + { + if (m_refractActivated) + return m_RefractEnd - DateTime.Now; + else + return TimeSpan.FromSeconds(0); + } + set + { + DoTimer3(value); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public string TriggerOnCarried + { + get { return m_ItemTriggerName; } + set { m_ItemTriggerName = value; } + + } + [CommandProperty(AccessLevel.GameMaster)] + public string NoTriggerOnCarried + { + get { return m_NoItemTriggerName; } + set { m_NoItemTriggerName = value; } + + } + + + [CommandProperty(AccessLevel.GameMaster)] + public string TriggerObjectProp + { + get { return m_ObjectPropertyName; } + set { m_ObjectPropertyName = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string TriggerObjectName + { + get + { + if (m_ObjectPropertyItem == null || m_ObjectPropertyItem.Deleted) return null; + return m_ObjectPropertyItem.Name; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item TriggerObject + { + get { return m_ObjectPropertyItem; } + set { m_ObjectPropertyItem = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string SetItemName + { + get + { + if (m_SetPropertyItem == null || m_SetPropertyItem.Deleted) return null; + return m_SetPropertyItem.Name; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item SetItem + { + get + { + return m_SetPropertyItem; + } + set { m_SetPropertyItem = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string MobTriggerProp + { + get { return m_MobPropertyName; } + set { m_MobPropertyName = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string MobTriggerName + { + get { return m_MobTriggerName; } + set { m_MobTriggerName = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile MobTriggerId + { + get + { + if (m_MobTriggerName == null) return null; + + // try to parse out the type information if it has also been saved + string[] typeargs = m_MobTriggerName.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = m_MobTriggerName; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + return BaseXmlSpawner.FindMobileByName(this, namestr, typestr); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string PlayerTriggerProp + { + get { return m_PlayerPropertyName; } + set { m_PlayerPropertyName = value; } + } + + // time of day activation + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TODStart + { + get { return m_TODStart; } + set { m_TODStart = value; } + + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TODEnd + { + get { return m_TODEnd; } + set { m_TODEnd = value; } + + } + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TOD + { + get + { + if (m_TODMode == TODModeType.Gametime) + { + int hours; + int minutes; + Server.Items.Clock.GetTime(this.Map, Location.X, this.Location.Y, out hours, out minutes); + return (new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, hours, minutes, 0).TimeOfDay); + + } + else + return DateTime.Now.TimeOfDay; + + } + + } + + [CommandProperty(AccessLevel.GameMaster)] + public TODModeType TODMode + { + get { return m_TODMode; } + set { m_TODMode = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool TODInRange + { + get + { + if (m_TODStart == m_TODEnd) return true; + DateTime now; + DateTime TOD_start; + DateTime TOD_end; + DateTime day_start; + + if (m_TODMode == TODModeType.Gametime) + { + int hours; + int minutes; + Server.Items.Clock.GetTime(this.Map, Location.X, this.Location.Y, out hours, out minutes); + now = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, hours, minutes, 0); + } + else + { + // calculate the time window + now = DateTime.Now; + } + day_start = new DateTime(now.Year, now.Month, now.Day); + // calculate the starting TOD window by adding the TODStart to day_start + TOD_start = day_start + m_TODStart; + TOD_end = day_start + m_TODEnd; + + + // handle the case when TODstart is before midnight and end is after + + if (TOD_start > TOD_end) + { + if (now > TOD_start || now < TOD_end) + return true; + else + return false; + } + else + { + if (now > TOD_start && now < TOD_end) + return true; + else + return false; + } + + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DespawnTime + { + get { return m_DespawnTime; } + set { m_DespawnTime = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan Duration + { + get { return m_Duration; } + set + { + m_Duration = value; + InvalidateProperties(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DurationOver + { + get + { + if (m_durActivated) + return m_DurEnd - DateTime.Now; + else + return TimeSpan.FromSeconds(0); + } + set + { + DoTimer2(value); + } + } + // proximity range parameter + [CommandProperty(AccessLevel.GameMaster)] + public int ProximityRange + { + get { return m_ProximityRange; } + set + { + m_ProximityRange = value; + InvalidateProperties(); + } + } + + + // proximity range activated? + [CommandProperty(AccessLevel.GameMaster)] + public bool ProximityActivated + { + get { return m_proximityActivated; } + set + { + + if (AllowTriggering) + { + ActivateTrigger(); + } + + m_proximityActivated = value; + + } + } + + // proximity trigger sound parameter + [CommandProperty(AccessLevel.GameMaster)] + public int ProximitySound + { + get { return m_ProximityTriggerSound; } + set { m_ProximityTriggerSound = value; } + } + + // proximity trigger message parameter + [CommandProperty(AccessLevel.GameMaster)] + public string ProximityMsg + { + get { return m_ProximityTriggerMessage; } + set { m_ProximityTriggerMessage = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string SpeechTrigger + { + get { return m_SpeechTrigger; } + set { m_SpeechTrigger = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string SkillTrigger + { + get { return m_SkillTrigger; } + set + { + + SkillName news = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + double minval = -1; + double maxval = -1; + int successval = 3; // either success or failure will trigger + + if (value != null) + { + // try parsing the skill trigger string for min and maxval + // the string can take the form "skill,[+/-][,minval,maxval]" + + string[] arglist = BaseXmlSpawner.ParseString(value, 4, ","); + + if (arglist.Length == 2 || arglist.Length == 4) + { + if (arglist[1] == "+") + { + successval = 1; // trigger on success only + } + else + if (arglist[1] == "-") + { + successval = 2; // trigger on failure only + } + } + + if (arglist.Length == 3) + { + successval = 3; + try + { + minval = double.Parse(arglist[1]); + maxval = double.Parse(arglist[2]); + } + catch { } + } + else + if (arglist.Length == 4) + { + try + { + minval = double.Parse(arglist[2]); + maxval = double.Parse(arglist[3]); + } + catch { } + } + try + { + news = (SkillName)Enum.Parse(typeof(SkillName), arglist[0], true); + } + catch { } + } + + // unregister the previous skill if it was assigned + if (m_SkillTrigger != null) + { + XmlSpawnerSkillCheck.UnRegisterSkillTrigger(this, m_SkillTriggerName, this.Map, false); + } + + // if the skill trigger was valid then register it + if (news != XmlSpawnerSkillCheck.RegisteredSkill.Invalid) + { + XmlSpawnerSkillCheck.RegisterSkillTrigger(this, news, this.Map); + m_SkillTrigger = value; + m_SkillTriggerName = news; + m_SkillTriggerMin = minval; + m_SkillTriggerMax = maxval; + m_SkillTriggerSuccess = successval; + } + else + { + m_SkillTrigger = null; + m_SkillTriggerName = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + m_SkillTriggerMin = -1; + m_SkillTriggerMax = -1; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSpawn + { + get + { + if (m_Running) + return m_End - DateTime.Now; + else + return TimeSpan.FromSeconds(0); + } + set + { + Start(); + DoTimer(value); + //InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool SpawnOnTrigger + { + get { return m_SpawnOnTrigger; } + set { m_SpawnOnTrigger = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Group + { + get { return m_Group; } + set { m_Group = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string GumpState + { + get { return m_GumpState; } + set { m_GumpState = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SequentialSpawn + { + get { return m_SequentialSpawning; } + set { m_SequentialSpawning = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSeqReset + { + get + { + if (m_Running && ((m_SeqEnd - DateTime.Now) > TimeSpan.Zero)) + return m_SeqEnd - DateTime.Now; + else + return TimeSpan.FromSeconds(0); + } + set + { + m_SeqEnd = DateTime.Now + value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public AccessLevel TriggerAccessLevel + { + get { return m_TriggerAccessLevel; } + set { m_TriggerAccessLevel = value; } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public bool DoRespawn + { + get { return false; } + set + { + // need to determine whether this is being set by the spawner during processing of a respawn entry + // if so then dont do it, otherwise you will infinitely recurse and crash with a stack overflow + if (value == true && !inrespawn) + { + Respawn(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DoReset + { + get { return false; } + set { if (value == true) Reset(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowGhostTrig + { + get { return m_AllowGhostTriggering; } + set { m_AllowGhostTriggering = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowNPCTrig + { + get { return m_AllowNPCTriggering; } + set { m_AllowNPCTriggering = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string ConfigFile + { + get { return m_ConfigFile; } + set { m_ConfigFile = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool LoadConfig + { + get { return false; } + set { if (value == true) LoadXmlConfig(ConfigFile); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile TriggerMob + { + get { return m_mob_who_triggered; } + set { m_mob_who_triggered = value; } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public string FirstModifiedBy + { + get { return m_FirstModifiedBy; } + set + { + m_FirstModifiedBy = value; + m_FirstModified = DateTime.Now; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string LastModifiedBy + { + get { return m_LastModifiedBy; } + set + { + m_LastModifiedBy = value; + m_LastModified = DateTime.Now; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool SmartSpawning + { + get { return m_SmartSpawning; } + set + { + m_SmartSpawning = value; + + if (m_SmartSpawning) + { + // if any spawner is smartspawning, then the smartspawning system is enabled + SmartSpawningSystemEnabled = true; + // check to see if the global sector timer is running + if (m_GlobalSectorTimer == null || !m_GlobalSectorTimer.Running) + { + // start the global smartspawning timer + DoGlobalSectorTimer(TimeSpan.FromSeconds(1)); + } + } + + //IsInactivated = false; + } + } + + #endregion + + #region ISpawner interface support + + public bool UnlinkOnTaming { get { return true; } } + public Point3D HomeLocation { get { return this.Location; } } + public int Range { get { return HomeRange; } } + + public void Remove(ISpawnable spawn) + { + if (m_SpawnObjects == null) return; + + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + if (so.SpawnedObjects[i] == spawn) + { + so.SpawnedObjects.Remove(spawn); + m_killcount++; + return; + } + } + } + } + + public void RestoreISpawner() + { + // restore the Spawner assignments to all spawned objects + if (m_SpawnObjects == null) return; + + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + if (o is Item) + { + ((Item)o).Spawner = this; + } + else if (o is Mobile) + { + ((Mobile)o).Spawner = this; + } + } + } + } + + #endregion + #region Method Overrides + + public override void OnAfterDuped(Item newItem) + { + // automatically turn off duped spawners + ((XmlSpawner)newItem).Running = false; + } + + public override void OnMapChange() + { + base.OnMapChange(); + + // unregister the skill trigger on the previous map + XmlSpawnerSkillCheck.UnRegisterSkillTrigger(this, m_SkillTriggerName, currentmap, false); + + // register the skill trigger on the new current map + XmlSpawnerSkillCheck.RegisterSkillTrigger(this, m_SkillTriggerName, this.Map); + + currentmap = this.Map; + + // reset the sector list for smart spawning + ResetSectorList(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null || from.Deleted || from.AccessLevel < AccessLevel.GameMaster || (m_SpawnerGump != null && SomeOneHasGumpOpen)) return; + + // flag the first person to open the spawner as the placer + if (FirstModifiedBy == null) FirstModifiedBy = from.Name; + + LastModifiedBy = from.Name; + + // clear any text entry books that might still be around + DeleteTextEntryBook(); + + int x = 0; + int y = 0; + // read the text entries for default values + Account acct = from.Account as Account; + if (acct != null) + { + XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + if (defs != null) + { + x = defs.SpawnerGumpX; + y = defs.SpawnerGumpY; + } + } + + XmlSpawnerGump g = new XmlSpawnerGump(this, x, y, 0, 0, 0); + from.SendGump(g); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Running) + { + list.Add(1060742); // active + } + else + { + list.Add(1060743); // inactive + } + + // add whitespace to the beginning to avoid any problem with names that begin with # and are interpreted as cliloc ids + list.Add(1042971, " " + Name); // ~1_val~ + list.Add(1060656, m_Count.ToString()); // amount to make: ~1_val~ + list.Add(1061169, m_HomeRange.ToString()); // range ~1_val~ + + int nlist_items = 6; + + if (m_Group) + { + list.Add(1060658 + 6 - nlist_items, "group\t{0}", m_Group); // ~1_val~: ~2_val~ + nlist_items--; + } + + if (m_Team != 0) + { + list.Add(1060658 + 6 - nlist_items, "team\t{0}", m_Team); // ~1_val~: ~2_val~ + nlist_items--; + } + + list.Add(1060658 + 6 - nlist_items, "speed\t{0} to {1}", m_MinDelay, m_MaxDelay); // ~1_val~: ~2_val~ + nlist_items--; + + // display the duration parameter in the prop gump if it is non-zero + if (m_Duration > TimeSpan.FromMinutes(0)) + { + list.Add(1060658 + 6 - nlist_items, "Duration\t{0}", m_Duration); + nlist_items--; + } + + // display the proximity range parameter in the prop gump if it is active + if (m_ProximityRange != -1) + { + list.Add(1060658 + 6 - nlist_items, "ProximityRange\t{0}", m_ProximityRange); + nlist_items--; + } + + if (m_SpawnObjects != null) + for (int i = 0; i < nlist_items && i < m_SpawnObjects.Count; ++i) + { + string typename = ((SpawnObject)m_SpawnObjects[i]).TypeName; + if (typename != null && typename.Length > 20) + { + typename = typename.Substring(0, 20); + } + + list.Add(1060658 + (6 - nlist_items) + i, " {0}\t{1}", typename, ((SpawnObject)m_SpawnObjects[i]).SpawnedObjects.Count); + } + + + } + + public override void OnSingleClick(Mobile from) + { + LabelTo(from, "XmlSpawner"); + LabelTo(from, Name + (m_Running == true ? " [On]" : " [Off]")); + } + + + public override void OnDelete() + { + base.OnDelete(); + + if (ShowBounds == true) + ShowBounds = false; + + RemoveSpawnObjects(); + + // remove any text entry books that might still be attached to the spawner + DeleteTextEntryBook(); + + if (m_Timer != null) + m_Timer.Stop(); + + if (m_DurTimer != null) + m_DurTimer.Stop(); + + if (m_RefractoryTimer != null) + m_RefractoryTimer.Stop(); + + // if statics were added for marking container held spawners, delete them + if (m_ShowContainerStatic != null && !m_ShowContainerStatic.Deleted) + m_ShowContainerStatic.Delete(); + + // unregister all triggerskills that might have been added + XmlSpawnerSkillCheck.UnRegisterSkillTrigger(this, SkillName.Alchemy, this.Map, true); + } + + static bool IgnoreLocationChange = false; + public override void OnLocationChange(Point3D oldLocation) + { + if (IgnoreLocationChange) + { + IgnoreLocationChange = false; + return; + } + + + // calculate the positional shift + if (oldLocation.X > 0 && oldLocation.Y > 0) + { + int diffx = this.X - oldLocation.X; + int diffy = this.Y - oldLocation.Y; + m_X += diffx; + m_Y += diffy; + } + else + { + // Keep the original dimensions the same (Width, Height), + // just recalculate the new top left corner + m_X = this.X - (m_Width / 2); + m_Y = this.Y - (m_Height / 2); + } + + // reset the sector list for smart spawning + ResetSectorList(); + + // Check if the spawner is showing its bounds + if (ShowBounds == true) + { + ShowBounds = false; + ShowBounds = true; + } + } + #endregion + + #region Gump support + + public bool SomeOneHasGumpOpen + { + get + { + // go through all online mobiles and see if any have xmlspawner gumps open + List states = NetState.Instances; + + for (int i = 0; i < states.Count; ++i) + { + Mobile m = ((NetState)states[i]).Mobile; + + if (m != null && m.HasGump(typeof(XmlSpawnerGump))) + { + return true; + } + } + + return false; + } + } + + + public static void SpawnerGumpCallback(Mobile from, object invoker, string response) + { + // assign the response to the gumpstate + if (invoker is XmlSpawner) + { + XmlSpawner xs = (XmlSpawner)invoker; + xs.GumpState = response; + } + } + + public void DeleteTextEntryBook() + { + if (m_TextEntryBook != null) + { + foreach (Item s in m_TextEntryBook) + s.Delete(); + + m_TextEntryBook = null; + } + } + + #endregion + + #region Utility Methods + + private static bool IsConstructable(ConstructorInfo ctor) + { + return ctor.IsDefined(typeof(ConstructableAttribute), false); + } + + public static int ConvertToInt(string value) + { + if (value.StartsWith("0x")) + { + return Convert.ToInt32(value.Substring(2), 16); + } + else + { + return Convert.ToInt32(value); + } + } + + public static void ExecuteAction(object attachedto, Mobile trigmob, string action) + { + Point3D loc = Point3D.Zero; + Map map = null; + if (attachedto is IEntity) + { + loc = ((IEntity)attachedto).Location; + map = ((IEntity)attachedto).Map; + } + + if (action == null || action.Length <= 0 || attachedto == null || map == null) return; + + string status_str = null; + Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0); + + TheSpawn.TypeName = action; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, attachedto, trigmob, action); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, true, trigmob, loc, map, out status_str); + } + else + { + // its a regular type descriptor so find out what it is + Type type = SpawnerType.GetType(typeName); + try + { + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]); + + if (o == null) + { + status_str = "invalid type specification: " + arglist[0]; + } + else + if (o is Mobile) + { + Mobile m = (Mobile)o; + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + c.Home = loc; // Spawners location is the home point + } + + m.Location = loc; + m.Map = map; + + BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, trigmob, attachedto, out status_str); + } + else + if (o is Item) + { + Item item = (Item)o; + BaseXmlSpawner.AddSpawnItem(null, attachedto, TheSpawn, item, loc, map, trigmob, false, substitutedtypeName, out status_str); + } + } + catch { } + } + } + + private static void RemoveFromSectorTable(Sector s, XmlSpawner spawner) + { + if (s == null || s.Owner == null || s.Owner == Map.Internal || GlobalSectorTable[s.Owner.MapID] == null) return; + + // find the sector + if (GlobalSectorTable[s.Owner.MapID].Contains(s)) + { + ArrayList spawnerlist = (ArrayList)GlobalSectorTable[s.Owner.MapID][s]; + if (spawnerlist.Contains(spawner)) + { + spawnerlist.Remove(spawner); + } + } + } + + private void ResetSectorList() + { + // remove the global sector entries + if (sectorList != null) + { + foreach (Sector s in sectorList) + { + RemoveFromSectorTable(s, this); + + } + } + sectorList = null; + UseSectorActivate = false; + + //IsInactivated = false; + + // force an update of the sector list + bool sectorrefresh = HasActiveSectors; + } + + public void LoadXmlConfig(string filename) + { + if (filename == null || filename.Length <= 0) return; + // Check if the file exists + if (System.IO.File.Exists(filename) == true) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + status_str = String.Format("Unable to open {0} for loading", filename); + return; + } + + // Create the data set + DataSet ds = new DataSet(XmlDataSetName); + + // Read in the file + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch { fileerror = true; } + // close the file + fs.Close(); + if (fileerror) + { + Console.WriteLine("XmlSpawner: Error in XML config file '{0}'", filename); + return; + } + + // Check that at least a single table was loaded + if (ds.Tables != null && ds.Tables.Count > 0) + { + if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[XmlTableName].Rows) + { + bool valid_entry; + string strEntry = null; + bool boolEntry = true; + double doubleEntry = 0; + int intEntry = 0; + + valid_entry = true; + try { strEntry = (string)dr["Name"]; } + catch { valid_entry = false; } + if (valid_entry) { Name = strEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["X"]); } + catch { valid_entry = false; } + if (valid_entry) { m_X = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Y"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Y = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Width"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Width = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Height"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Height = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["CentreX"]); } + catch { valid_entry = false; } + if (valid_entry) { X = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["CentreY"]); } + catch { valid_entry = false; } + if (valid_entry) { Y = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["CentreZ"]); } + catch { valid_entry = false; } + if (valid_entry) { Z = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["SequentialSpawning"]); } + catch { valid_entry = false; } + if (valid_entry) { m_SequentialSpawning = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["ProximityRange"]); } + catch { valid_entry = false; } + if (valid_entry) { m_ProximityRange = intEntry; } + + valid_entry = true; + try { strEntry = (string)dr["ProximityTriggerMessage"]; } + catch { valid_entry = false; } + if (valid_entry) { m_ProximityTriggerMessage = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["SpeechTrigger"]; } + catch { valid_entry = false; } + if (valid_entry) { m_SpeechTrigger = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["SkillTrigger"]; } + catch { valid_entry = false; } + if (valid_entry) { m_SkillTrigger = strEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["ProximityTriggerSound"]); } + catch { valid_entry = false; } + if (valid_entry) { m_ProximityTriggerSound = intEntry; } + + valid_entry = true; + try { strEntry = (string)dr["ItemTriggerName"]; } + catch { valid_entry = false; } + if (valid_entry) { m_ItemTriggerName = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["NoItemTriggerName"]; } + catch { valid_entry = false; } + if (valid_entry) { m_NoItemTriggerName = strEntry; } + + // check for the delayinsec entry + bool delayinsec = false; + try { delayinsec = bool.Parse((string)dr["DelayInSec"]); } + catch { } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MinDelay"]); } + catch { valid_entry = false; } + if (valid_entry) { if (delayinsec) m_MinDelay = TimeSpan.FromSeconds(doubleEntry); else m_MinDelay = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MaxDelay"]); } + catch { valid_entry = false; } + if (valid_entry) { if (delayinsec) m_MaxDelay = TimeSpan.FromSeconds(doubleEntry); else m_MaxDelay = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["Duration"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Duration = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["DespawnTime"]); } + catch { valid_entry = false; } + if (valid_entry) { m_DespawnTime = TimeSpan.FromHours(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MinRefractory"]); } + catch { valid_entry = false; } + if (valid_entry) { m_MinRefractory = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MaxRefractory"]); } + catch { valid_entry = false; } + if (valid_entry) { m_MaxRefractory = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["TODStart"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TODStart = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["TODEnd"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TODEnd = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["TODMode"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TODMode = (TODModeType)intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Amount"]); } + catch { valid_entry = false; } + if (valid_entry) { m_StackAmount = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["MaxCount"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Count = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Range"]); } + catch { valid_entry = false; } + if (valid_entry) { m_HomeRange = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Team"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Team = intEntry; } + + valid_entry = true; + try { strEntry = (string)dr["WayPoint"]; } + catch { valid_entry = false; } + if (valid_entry) { m_WayPoint = GetWaypoint(strEntry); } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["KillReset"]); } + catch { valid_entry = false; } + if (valid_entry) { m_KillReset = intEntry; } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["TriggerProbability"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TriggerProbability = doubleEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["ExternalTriggering"]); } + catch { valid_entry = false; } + if (valid_entry) { m_ExternalTriggering = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["IsGroup"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Group = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["IsHomeRangeRelative"]); } + catch { valid_entry = false; } + if (valid_entry) { m_HomeRangeIsRelative = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["AllowGhostTriggering"]); } + catch { valid_entry = false; } + if (valid_entry) { m_AllowGhostTriggering = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["AllowNPCTriggering"]); } + catch { valid_entry = false; } + if (valid_entry) { m_AllowNPCTriggering = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["SpawnOnTrigger"]); } + catch { valid_entry = false; } + if (valid_entry) { m_SpawnOnTrigger = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["SmartSpawning"]); } + catch { valid_entry = false; } + if (valid_entry) { m_SmartSpawning = boolEntry; } + + valid_entry = true; + try { strEntry = (string)dr["RegionName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + RegionName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["PlayerPropertyName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_PlayerPropertyName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["MobPropertyName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_MobPropertyName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["MobTriggerName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_MobTriggerName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["ObjectPropertyName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_ObjectPropertyName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["ObjectPropertyItemName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + string[] typeargs = strEntry.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = strEntry; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr); + } + + valid_entry = true; + try { strEntry = (string)dr["SetPropertyItemName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + string[] typeargs = strEntry.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = strEntry; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + m_SetPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr); + } + + valid_entry = true; + try { strEntry = (string)dr["Name"]; } + catch { valid_entry = false; } + if (valid_entry) { Name = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["Map"]; } + catch { valid_entry = false; } + if (valid_entry) + { + // Convert the xml map value to a real map object + try + { + Map = Map.Parse(strEntry); + } + catch { } + } + + // try loading the new spawn specifications first + SpawnObject[] Spawns = new SpawnObject[0]; + bool havenew = true; + valid_entry = true; + try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } + catch { havenew = false; } + if (!havenew) + { + // try loading the new spawn specifications + try { Spawns = SpawnObject.LoadSpawnObjectsFromString((string)dr["Objects"]); } + catch { valid_entry = false; } + // can only have one of these defined + } + if (valid_entry) + { + + // clear existing spawns + RemoveSpawnObjects(); + + // Create the new array of spawned objects + m_SpawnObjects = new ArrayList(); + + // Assign the list of objects to spawn + SpawnObjects = Spawns; + } + } + } + } + } + } + + public void ReportStatus() + { + if (PropertyInfoList != null) + { + Console.WriteLine("PropertyInfoList: {0}", PropertyInfoList.Count); + foreach (BaseXmlSpawner.TypeInfo to in PropertyInfoList) + { + Console.WriteLine("\t{0}", to.t); + foreach (PropertyInfo p in to.plist) + { + Console.WriteLine("\t\t{0}", p); + } + } + } + ShowTagList(this); + int count = 0; + Console.WriteLine("Registered Skills"); + Console.WriteLine("Felucca"); + for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++) + { + + if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Felucca).Count > 0) + Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Felucca).Count); + + count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Felucca).Count; + } + Console.WriteLine("Trammel"); + for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++) + { + + if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Trammel).Count > 0) + Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Trammel).Count); + + count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Trammel).Count; + } + Console.WriteLine("Ilshenar"); + for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++) + { + + if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Ilshenar).Count > 0) + Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Ilshenar).Count); + + count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Ilshenar).Count; + } + Console.WriteLine("Malas"); + for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++) + { + + if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Malas).Count > 0) + Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Malas).Count); + + count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Malas).Count; + } + + Console.WriteLine("Tokuno"); + for (int i = 0; i < XmlSpawnerSkillCheck.RegisteredSkill.MaxSkills + 1; i++) + { + + if (XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Tokuno).Count > 0) + Console.WriteLine("\t{0} : {1}", (SkillName)i, XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Tokuno).Count); + + count += XmlSpawnerSkillCheck.RegisteredSkill.TriggerList((SkillName)i, Map.Tokuno).Count; + } + + Console.WriteLine("Total = {0}", count); + } + + #endregion + + #region Trace support + +#if(TRACE) + +string setname1 = _traceName[1] = "XmlFind"; +string setname2 = _traceName[2] = "HasSector"; + +string setname4 = _traceName[4] = "AttachSpeech"; +string setname5 = _traceName[5] = "HasHold"; + + +string setname8 = _traceName[8] = "OnTick"; +string setname9 = _traceName[9] = "Defrag"; +string setname10 = _traceName[10] = "Respawn"; +string setname11 = _traceName[11] = "SetProp"; +string setname12 = _traceName[12] = "AttachMovement"; +string setname13 = _traceName[13] = "ActiveSector"; + +string setname15 = _traceName[15] = "DistroTick"; +string setname16 = _traceName[16] = "GetScaledFaction"; +string setname17 = _traceName[17] = "FactionOnKill"; +string setname18 = _traceName[18] = "CheckAcquire"; + + + +private const int MaxTraces = 20; +private static DateTime[] _traceStart = new DateTime[MaxTraces]; +public static TimeSpan[] _traceTotal = new TimeSpan[MaxTraces]; +public static string[] _traceName = new string[MaxTraces]; +public static int[] _traceCount = new int[MaxTraces]; +private static DateTime _traceStartTime = DateTime.Now; +private static double _startProcessTime = 0; + +public static void _TraceStart(int index) +{ + if(index < MaxTraces){ + _traceStart[index] = DateTime.Now; + //_traceStart[index] = Process.GetCurrentProcess().UserProcessorTime; + } +} +public static void _TraceEnd(int index) +{ + if(index < MaxTraces){ + XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(DateTime.Now - _traceStart[index]); + //XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(Process.GetCurrentProcess().UserProcessorTime - _traceStart[index]); + XmlSpawner._traceCount[index]++; + } +} +#else + public static void _TraceStart(int index) { } + public static void _TraceEnd(int index) { } +#endif + + #endregion + + #region Trigger Methods + + private bool ValidPlayerTrig(Mobile m) + { + if (m == null || m.Deleted) return false; + return ((m.Player || m_AllowNPCTriggering) && (m.AccessLevel <= TriggerAccessLevel) && ((!m.Body.IsGhost && !m_AllowGhostTriggering) || (m.Body.IsGhost && m_AllowGhostTriggering))); + } + + private bool AllowTriggering + { + get + { + return m_Running && !m_refractActivated && TODInRange && CanSpawn; + } + } + + private void ActivateTrigger() + { + + // reset the timer + DoTimer(); + + // start the refractory timer to set proximity activated to false, thus enabling another activation + if (m_MaxRefractory > TimeSpan.FromMinutes(0)) + { + int minSeconds = (int)m_MinRefractory.TotalSeconds; + int maxSeconds = (int)m_MaxRefractory.TotalSeconds; + + DoTimer3(TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds))); + } + + // if the spawnontrigger flag is set, then spawn immediately + if (m_SpawnOnTrigger) + { + NextSpawn = TimeSpan.Zero; + ResetNextSpawnTimes(); + } + + // reset speech triggering if it was set + m_speechTriggerActivated = false; + + // reset skill triggering if it was set + m_skillTriggerActivated = false; + + // reset external triggering if it was set + //this.m_ExternalTrigger = false; + } + + public void CheckTriggers(Mobile m, Skill s, bool hasproximity) + { + + // only proximity trigger when no spawns have already been triggered + if (AllowTriggering && !m_proximityActivated) + { + bool needs_item_trigger = false; + bool needs_speech_trigger = false; + bool needs_skill_trigger = false; + bool needs_object_trigger = false; + bool needs_mob_trigger = false; + bool needs_player_trigger = false; + bool needs_noitem_trigger = false; + bool has_object_trigger = false; + bool has_mob_trigger = false; + bool has_player_trigger = false; + bool has_item_trigger = false; + bool has_noitem_trigger = true; // assume the player doesnt have the trigger-blocking item until it is found by search + + m_skipped = false; + + // test for the various triggering options in the order of increasing computational demand. No point checking a high demand test + // if a low demand one has already failed. + + // check for external triggering + if (m_ExternalTriggering && !m_ExternalTrigger) return; + + // if speech triggering is set then test for successful activation + if (m_SpeechTrigger != null && m_SpeechTrigger.Length > 0) + { + needs_speech_trigger = true; + } + // check to see if we have to continue + if (needs_speech_trigger && !m_speechTriggerActivated) return; + + // if skill triggering is set then test for successful activation + if (m_SkillTrigger != null && m_SkillTrigger.Length > 0) + { + needs_skill_trigger = true; + } + // check to see if we have to continue + if (needs_skill_trigger && !m_skillTriggerActivated) return; + + // if item property triggering is set then test for the property value + // + if (m_ObjectPropertyName != null && m_ObjectPropertyName.Length > 0) + { + needs_object_trigger = true; + string status_str; + + if (BaseXmlSpawner.TestItemProperty(this, m_ObjectPropertyItem, m_ObjectPropertyName, null, out status_str)) + { + has_object_trigger = true; + } + else + has_object_trigger = false; + if (status_str != null && status_str.Length > 0) + { + this.status_str = status_str; + } + } + + // check to see if we have to continue + if (needs_object_trigger && !has_object_trigger) return; + + // if player property triggering is set then look for the mob and test properties + if (m_PlayerPropertyName != null && m_PlayerPropertyName.Length > 0) + { + needs_player_trigger = true; + string status_str; + + if (BaseXmlSpawner.TestMobProperty(this, m, m_PlayerPropertyName, null, out status_str)) + { + has_player_trigger = true; + } + else + has_player_trigger = false; + if (status_str != null && status_str.Length > 0) + { + this.status_str = status_str; + } + } + + // check to see if we have to continue + if (needs_player_trigger && !has_player_trigger) return; + + // if mob property triggering is set then look for the mob and test properties + if (m_MobPropertyName != null && m_MobPropertyName.Length > 0 && + m_MobTriggerName != null && m_MobTriggerName.Length > 0) + { + needs_mob_trigger = true; + + string status_str; + + if (BaseXmlSpawner.TestMobProperty(this, MobTriggerId, m_MobPropertyName, null, out status_str)) + { + has_mob_trigger = true; + } + else + has_mob_trigger = false; + + if (status_str != null && status_str.Length > 0) + { + this.status_str = status_str; + } + } + + // check to see if we have to continue + if (needs_mob_trigger && !has_mob_trigger) return; + + // if player-carried item triggering is set then test for the presence of an item on the player an in their pack + if (m_ItemTriggerName != null && m_ItemTriggerName.Length > 0) + { + //enable_triggering = false; + needs_item_trigger = true; + + has_item_trigger = BaseXmlSpawner.CheckForCarried(m, m_ItemTriggerName); + } + // check to see if we have to continue + if (needs_item_trigger && !has_item_trigger) return; + + // if player-carried noitem triggering is set then test for the presence of an item in the players pack that should block triggering + if (m_NoItemTriggerName != null && m_NoItemTriggerName.Length > 0) + { + needs_noitem_trigger = true; + + has_noitem_trigger = BaseXmlSpawner.CheckForNotCarried(m, m_NoItemTriggerName); + } + // check to see if we have to continue + if (needs_noitem_trigger && !has_noitem_trigger) return; + + // if this was called without being proximity triggered then check to see that the non-movement triggers were enabled. + if (!hasproximity && !needs_object_trigger && !needs_mob_trigger && !m_ExternalTriggering) return; + + // all of the necessary trigger conditions have been met so go ahead and trigger + // after you make the probability check + + if (Utility.RandomDouble() < m_TriggerProbability) + { + + // play a sound indicating the spawner has been triggered + if (m_ProximityTriggerSound > 0 && m != null && !m.Deleted) + m.PlaySound(m_ProximityTriggerSound); + + // display the trigger message + if (m_ProximityTriggerMessage != null && m_ProximityTriggerMessage.Length > 0 && m != null && !m.Deleted) + m.PublicOverheadMessage(MessageType.Regular, 0x3B2, true, m_ProximityTriggerMessage); + + // enable spawning at the next ontick + // this will also start the refractory timer and send the triggering indicators + ProximityActivated = true; + + // keep track of who triggered this + m_mob_who_triggered = m; + + // keep track of the skill that triggered this + if (s != null) + { + m_skill_that_triggered = s.SkillName; + } + else + { + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + } + + + } + else + { + m_skipped = true; + // reset speech triggering if it was set + + m_speechTriggerActivated = false; + + // reset skill triggering if it was set + m_skillTriggerActivated = false; + // reset external triggering if it was set + //this.m_ExternalTrigger = false; + } + } + } + + public bool HandlesOnSkillUse { get { return (m_Running && m_SkillTrigger != null && m_SkillTrigger.Length > 0); } } + + // this is the handler for skill use + public void OnSkillUse(Mobile m, Skill skill, bool success) + { + + if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn && !m_refractActivated && TODInRange) + { + + if (!Utility.InRange(m.Location, this.Location, m_ProximityRange)) + return; + + m_skillTriggerActivated = false; + + // check the skill trigger conditions, Skillname[+/-][,min,max] + if (m_SkillTrigger != null && (skill.SkillName == m_SkillTriggerName) && + ((m_SkillTriggerMin < 0) || (skill.Value >= m_SkillTriggerMin)) && + ((m_SkillTriggerMax < 0) || (skill.Value <= m_SkillTriggerMax)) && + ((m_SkillTriggerSuccess == 3) || ((m_SkillTriggerSuccess == 1) && success) || ((m_SkillTriggerSuccess == 2) && !success))) + { + // have a skill trigger so flag it and test it + m_skillTriggerActivated = true; + + CheckTriggers(m, skill, true); + } + } + } + + + public override bool HandlesOnSpeech { get { return (m_Running && m_SpeechTrigger != null && m_SpeechTrigger.Length > 0); } } + + public override void OnSpeech(SpeechEventArgs e) + { + if ( /*!e.Handled && */m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(e.Mobile) && CanSpawn && !m_refractActivated && TODInRange) + { + m_speechTriggerActivated = false; + + if (!Utility.InRange(e.Mobile.Location, this.Location, m_ProximityRange)) + return; + + if (m_SpeechTrigger != null && e.Speech.ToLower().IndexOf(m_SpeechTrigger.ToLower()) >= 0) + { + e.Handled = true; + + // found the speech trigger so flag it for testing in the onmovement handler where the other proximity features are tested + m_speechTriggerActivated = true; + + CheckTriggers(e.Mobile, null, true); + } + } + } + + + public override bool HandlesOnMovement + { + get + { + return (m_Running && m_ProximityRange >= 0); + } + } + + + public void AddToMovementList(Mobile m) + { + // go through the list and check for redundancy + if (m_MovementList == null) + { + m_MovementList = new ArrayList(); + } + + // check to see if the movement timer is running + if (m_MovementTimer == null || !m_MovementTimer.Running) + { + DoMovementTimer(TimeSpan.FromSeconds(1)); + } + + bool add = true; + + foreach (MovementInfo moveinfo in m_MovementList) + { + Mobile mtrig = moveinfo.trigMob; + if (mtrig == m) + { + add = false; + break; + } + } + + // wasnt on the list so add it + if (add) + { + + // is the list at max throttling length? + if (m_MovementList.Count > MaxMoveCheck) + { + // replace a random entry in the current list with this one + m_MovementList[Utility.Random(m_MovementList.Count)] = new MovementInfo(m); + } + else + { + + m_MovementList.Add(new MovementInfo(m)); + } + } + } + + public void DoMovementTimer(TimeSpan delay) + { + if (m_MovementTimer != null) + m_MovementTimer.Stop(); + + m_MovementTimer = new MovementTimer(this, delay); + + m_MovementTimer.Start(); + } + + private class MovementTimer : Timer + { + private XmlSpawner m_Spawner; + + public MovementTimer(XmlSpawner spawner, TimeSpan delay) + : base(delay) + { + Priority = TimerPriority.OneSecond; + m_Spawner = spawner; + } + + protected override void OnTick() + { + // check everyone on the movement list then clear the list + + if (m_Spawner != null && !m_Spawner.Deleted) + { + if (m_Spawner.m_Running && !m_Spawner.m_proximityActivated && !m_Spawner.m_refractActivated && m_Spawner.TODInRange && m_Spawner.CanSpawn) + { + int count = 0; + int maxspeed = 0; + int speed = 0; + foreach (MovementInfo moveinfo in m_Spawner.m_MovementList) + { + Mobile m = moveinfo.trigMob; + if (m == null) continue; + + // additional throttling in here by limiting number of mobs that can be checked in a single ontick + count++; + if (count > MaxMoveCheck) break; + + speed = (int)GetDistance(m.Location, moveinfo.trigLocation); + if (speed > maxspeed) maxspeed = speed; + m_Spawner.CheckTriggers(m, null, true); + } + + m_Spawner.MovingPlayerCount = m_Spawner.m_MovementList.Count; + m_Spawner.FastestPlayerSpeed = maxspeed; + + } + m_Spawner.m_MovementList.Clear(); + } + } + } + + public static double GetDistance(Point3D p1, Point3D p2) + { + int xDelta = p1.X - p2.X; + int yDelta = p1.Y - p2.Y; + + return Math.Sqrt((xDelta * xDelta) + (yDelta * yDelta)); + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + + if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn) + { + // check to see if player is within range of the spawner + if ((this.Parent == null) && Utility.InRange(m.Location, this.Location, m_ProximityRange)) + { + // add some throttling code here. + // add the player to a list that gets cleared every few seconds, checking for redundancy then trigger off of the list instead of off of + // the actual movement stream + + AddToMovementList(m); + + // check the triggers in the OnTick for the list handler instead of here + } + else + { + // clear any speech triggering + m_speechTriggerActivated = false; + + // clear any skill triggering + m_skillTriggerActivated = false; + } + } + base.OnMovement(m, oldLocation); + } + #endregion + + #region Initialization + + public static bool AssignSettings(string argname, string value) + { + switch (argname) + { + case "XmlSpawnDir": + XmlSpawnDir = value; + break; + case "DiskAccessLevel": + DiskAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); + break; + case "SmartSpawnAccessLevel": + SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); + break; + case "XmlConfigsDir": + XmlConfigsDir = value; + break; + case "defaultTriggerSound": + defaultTriggerSound = ConvertToInt(value); + defProximityTriggerSound = defaultTriggerSound; + break; + case "BaseItemId": + BaseItemId = ConvertToInt(value); + break; + case "ShowItemId": + ShowItemId = ConvertToInt(value); + break; + case "MaxMoveCheck": + MaxMoveCheck = ConvertToInt(value); + break; + case "defMinDelay": + defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + case "defMaxDelay": + defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + case "defRelativeHome": + defRelativeHome = bool.Parse(value); + break; + case "defSpawnRange": + defSpawnRange = ConvertToInt(value); + break; + case "defHomeRange": + defHomeRange = ConvertToInt(value); + break; + case "JournalNotifyColor": + XmlQuestHolder.JournalNotifyColor = ConvertToInt(value); + break; + case "JournalEchoColor": + XmlQuestHolder.JournalEchoColor = ConvertToInt(value); + break; + case "BlockKeyword": + { + // parse the keyword list and remove them from the keyword hashtables + string[] keywordlist = value.Split(','); + + if (keywordlist != null && keywordlist.Length > 0) + { + for (int i = 0; i < keywordlist.Length; i++) + { + BaseXmlSpawner.RemoveKeyword(keywordlist[i]); + } + } + break; + } + case "BlockCommand": + case "ChangeCommand": + // delay processing of these settings until after all commands have been registered in their Initialize methods + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(DelayedAssignSettings), new object[] { argname, value }); + break; + default: + return false; + } + + return true; + } + + private static void DelayedAssignSettings(object state) + { + object[] args = (object[])state; + string argname = (string)args[0]; + string value = (string)args[1]; + switch (argname) + { + case "BlockCommand": + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and remove them from the command hashtables + // the syntax is "commandname, commandname, etc." + string[] keywordlist = value.Split(','); + + if (keywordlist != null && keywordlist.Length > 0) + { + for (int i = 0; i < keywordlist.Length; i++) + { + string commandname = keywordlist[i].Trim().ToLower(); + try + { + CommandSystem.Entries.Remove(commandname); + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, commandname); + } + } + } + break; + } + case "ChangeCommand": + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and rehash them into the command hashtables + // the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc." + string[] keywordlist = value.Split(','); + + if (keywordlist != null && keywordlist.Length > 0) + { + for (int i = 0; i < keywordlist.Length; i++) + { + string[] namelist = keywordlist[i].Split(':'); + if (namelist != null && namelist.Length > 1) + { + string oldname = namelist[0].Trim().ToLower(); + string newname = namelist[1].Trim(); + + if (newname.Length == 0) newname = oldname; + + AccessLevel access = AccessLevel.Player; + bool validaccess = false; + if (namelist.Length > 2) + { + // get the new accesslevel + try + { + access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true); + validaccess = true; + } + catch + { + Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname); + } + } + // find the command entry for the old name + CommandEntry e = null; + try + { + e = CommandSystem.Entries[oldname]; + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, oldname); + } + if (e != null) + { + if (!validaccess) + { + // use the old accesslevel + access = e.AccessLevel; + } + // remove the old command entry + CommandSystem.Entries.Remove(oldname); + // register the new command using the old handler + CommandSystem.Register(newname, access, e.Handler); + } + + // also look in the targetcommands list and adjust name and accesslevel there + foreach (BaseCommand b in TargetCommands.AllCommands) + { + if (b.Commands != null) + { + for (int j = 0; j < b.Commands.Length; j++) + { + string commandname = b.Commands[j]; + if (commandname.ToLower() == oldname) + { + // modify the basecommand with the new name and access + b.Commands[j] = newname; + if (validaccess) + { + b.AccessLevel = access; + } + + // re-register it in the implementors hashtable + List impls = BaseCommandImplementor.Implementors; + + for (int k = 0; k < impls.Count; ++k) + { + BaseCommandImplementor impl = impls[k]; + + if ((b.Supports & impl.SupportRequirement) != 0) + { + try + { + impl.Commands.Remove(commandname); + } + catch { } + impl.Register(b); + } + } + + break; + } + } + } + } + } + } + } + break; + } + } + } + + public delegate bool AssignSettingsHandler(string argname, string value); + + // load in settings from the xmlspawner2.cfg file in the Data directory + public static void LoadSettings(AssignSettingsHandler settingshandler, string section) + { + // Check if the file exists + string path = Path.Combine(Core.BaseDirectory, "Data/xmlspawner.cfg"); + + if (!File.Exists(path)) + { + return; + } + + Console.WriteLine("Loading {0} configuration", section); + using (StreamReader ip = new StreamReader(path)) + { + string line; + string currentsection = null; + int nsettings = 0; + + while ((line = ip.ReadLine()) != null) + { + line = line.Trim(); + + // skip comments + if (line.Length == 0 || line.StartsWith("#")) + continue; + + if (line.StartsWith("[")) + { + // parse the section name + string[] args = line.Split("[]".ToCharArray(), 3); + if (args.Length > 2) + { + currentsection = args[1].Trim(); + } + } + + // only process the matching classname section + if (currentsection != section) + continue; + + string[] split = line.Split('='); + + if (split.Length >= 2) + { + string argname = split[0].Trim(); + string value = split[1].Trim(); + + if (argname.Length == 0 || value.Length == 0) + continue; + + try + { + if (settingshandler(argname, value)) + nsettings++; + else + Console.WriteLine("'{0}' setting is invalid in section [{1}]", argname, currentsection); + + } + catch (Exception e) + { + Console.WriteLine("Config error '{0}'='{1}'", argname, value); + Console.WriteLine("Error: {0}", e.Message); + } + } + + } + if (nsettings > 0) + { + Console.WriteLine("{0} settings processed", nsettings); + } + } + } + + public static void Initialize() + { + XmlSpawner.LoadSettings(new XmlSpawner.AssignSettingsHandler(AssignSettings), "XmlSpawner"); + + // initialize the default waypoint name + WayPoint tmpwaypoint = new WayPoint(); + if (tmpwaypoint != null) + { + defwaypointname = tmpwaypoint.Name; + tmpwaypoint.Delete(); + } + // 2004.02.08 :: Omega Red + // initialize m_Region fields after world load (now, regions are loaded) + // Now this gets handled in OnTick + + int count = 0; + int regional = 0; + //int timercount=0; + + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + count++; + XmlSpawner spawner = ((XmlSpawner)item); + + if (spawner.RegionName != null && spawner.RegionName != string.Empty) + { + spawner.RegionName = spawner.RegionName; // invoke set(RegionName) + regional++; + } + + // check for smart spawning and restart timers after deser if needed + // note, HasActiveSectors will recalculate the sector list and UseSectorActivate property + bool recalc_sectors = spawner.HasActiveSectors; + /* + if(spawner.SmartSpawning && spawner.IsInactivated && !spawner.UseSectorActivate) + { + spawner.DoSectorTimer(TimeSpan.FromSeconds(1)); + timercount++; + } + */ + // add in the totalitem mod to keep them from adding to container counts + //spawner.TotalItems = -1; + //spawner.UpdateTotal(spawner, TotalType.Items, -1); + + spawner.RestoreISpawner(); + } + } + + // start the global smartspawning timer + if (SmartSpawningSystemEnabled) + { + DoGlobalSectorTimer(TimeSpan.FromSeconds(1)); + } + + // standard commands + CommandSystem.Register("XmlSpawnerShowAll", AccessLevel.Administrator, new CommandEventHandler(ShowSpawnPoints_OnCommand)); + CommandSystem.Register("XmlSpawnerHideAll", AccessLevel.Administrator, new CommandEventHandler(HideSpawnPoints_OnCommand)); + CommandSystem.Register("XmlSpawnerWipe", AccessLevel.Administrator, new CommandEventHandler(Wipe_OnCommand)); + CommandSystem.Register("XmlSpawnerWipeAll", AccessLevel.Administrator, new CommandEventHandler(WipeAll_OnCommand)); + CommandSystem.Register("XmlSpawnerLoad", DiskAccessLevel, new CommandEventHandler(Load_OnCommand)); + CommandSystem.Register("XmlSpawnerSave", DiskAccessLevel, new CommandEventHandler(Save_OnCommand)); + CommandSystem.Register("XmlSpawnerSaveAll", DiskAccessLevel, new CommandEventHandler(SaveAll_OnCommand)); + //added respawn commands + CommandSystem.Register("XmlSpawnerRespawn", AccessLevel.GameMaster, new CommandEventHandler(Respawn_OnCommand)); + CommandSystem.Register("XmlSpawnerRespawnAll", AccessLevel.GameMaster, new CommandEventHandler(RespawnAll_OnCommand)); + + // ok, I'm lazy. I dont like all that typing, so these are two aliases for the longer commands + CommandSystem.Register("XmlShow", AccessLevel.Administrator, new CommandEventHandler(ShowSpawnPoints_OnCommand)); + CommandSystem.Register("XmlHide", AccessLevel.Administrator, new CommandEventHandler(HideSpawnPoints_OnCommand)); + + CommandSystem.Register("XmlHome", AccessLevel.GameMaster, new CommandEventHandler(XmlHome_OnCommand)); + CommandSystem.Register("XmlUnLoad", DiskAccessLevel, new CommandEventHandler(UnLoad_OnCommand)); + CommandSystem.Register("XmlSpawnerUnLoad", DiskAccessLevel, new CommandEventHandler(UnLoad_OnCommand)); + CommandSystem.Register("XmlLoad", DiskAccessLevel, new CommandEventHandler(Load_OnCommand)); + CommandSystem.Register("XmlLoadHere", DiskAccessLevel, new CommandEventHandler(LoadHere_OnCommand)); + CommandSystem.Register("XmlNewLoad", DiskAccessLevel, new CommandEventHandler(NewLoad_OnCommand)); + CommandSystem.Register("XmlNewLoadHere", DiskAccessLevel, new CommandEventHandler(NewLoadHere_OnCommand)); + CommandSystem.Register("XmlSave", DiskAccessLevel, new CommandEventHandler(Save_OnCommand)); + CommandSystem.Register("XmlSaveAll", DiskAccessLevel, new CommandEventHandler(SaveAll_OnCommand)); + CommandSystem.Register("XmlSaveOld", DiskAccessLevel, new CommandEventHandler(SaveOld_OnCommand)); + CommandSystem.Register("XmlImportSpawners", DiskAccessLevel, new CommandEventHandler(XmlImportSpawners_OnCommand)); + CommandSystem.Register("XmlImportMSF", DiskAccessLevel, new CommandEventHandler(XmlImportMSF_OnCommand)); + CommandSystem.Register("XmlImportMap", DiskAccessLevel, new CommandEventHandler(XmlImportMap_OnCommand)); + CommandSystem.Register("XmlDefaults", AccessLevel.Administrator, new CommandEventHandler(XmlDefaults_OnCommand)); + CommandSystem.Register("XmlGet", AccessLevel.GameMaster, new CommandEventHandler(XmlGetValue_OnCommand)); + TargetCommands.Register(new XmlSetCommand()); + //CommandSystem.Register( "XmlSet", AccessLevel.GameMaster, new CommandEventHandler( XmlSetValue_OnCommand ) ); + CommandSystem.Register("OptimalSmartSpawning", AccessLevel.Administrator, new CommandEventHandler(OptimalSmartSpawning_OnCommand)); + CommandSystem.Register("SmartStat", AccessLevel.GameMaster, new CommandEventHandler(SmartStat_OnCommand)); + CommandSystem.Register("XmlGo", AccessLevel.GameMaster, new CommandEventHandler(SpawnEditorGo_OnCommand)); + //CommandSystem.Register( "TagList", AccessLevel.Administrator, new CommandEventHandler( ShowTagList_OnCommand ) ); + +#if(TRACE) + CommandSystem.Register( "XmlMake", AccessLevel.Administrator, new CommandEventHandler( XmlMake_OnCommand ) ); + CommandSystem.Register( "XmlTrace", AccessLevel.Administrator, new CommandEventHandler( XmlTrace_OnCommand ) ); + CommandSystem.Register( "XmlResetTrace", AccessLevel.Administrator, new CommandEventHandler( XmlResetTrace_OnCommand ) ); +#endif + + } + + #endregion + + #region Commands + + [Usage("XmlGet property")] + [Description("Returns value of the property on the targeted object.")] + public static void XmlGetValue_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new GetValueTarget(e); + } + private class GetValueTarget : Target + { + private CommandEventArgs m_e; + public GetValueTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) + { + m_e = e; + } + protected override void OnTarget(Mobile from, object targeted) + { + string pname = m_e.GetString(0); + Type ptype; + string result = BaseXmlSpawner.GetPropertyValue(null, targeted, pname, out ptype); + + // see if it was successful + if (ptype == null) + { + return; + } + from.SendMessage("{0}", result); + + } + } + + public class XmlSetCommand : BaseCommand + { + public XmlSetCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.All; + Commands = new string[] { "XmlSet" }; + ObjectTypes = ObjectTypes.Both; + Usage = "XmlSet "; + Description = "Sets a property value by name of a targeted object. Provides access to all public properties."; + } + + public override void Execute(CommandEventArgs e, object obj) + { + if (e.Length >= 2) + { + string result = BaseXmlSpawner.SetPropertyValue(null, obj, e.GetString(0), e.GetString(1)); + + if (result == "Property has been set.") + AddResponse(result); + else + LogFailure(result); + } + else + { + LogFailure("Format: XmlSet "); + } + } + } + + + [Usage("TagList property")] + [Description("Lists the keyword taglist for a spawner")] + public static void ShowTagList_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new TagListTarget(e); + } + + private class TagListTarget : Target + { + private CommandEventArgs m_e; + + public TagListTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) + { + m_e = e; + } + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is XmlSpawner) + ((XmlSpawner)targeted).ShowTagList((XmlSpawner)targeted); + + } + } + + public void ShowTagList(XmlSpawner spawner) + { + int count = 0; + Console.WriteLine("{0} tags", spawner.m_KeywordTagList.Count); + foreach (BaseXmlSpawner.KeywordTag tag in spawner.m_KeywordTagList) + { + count++; + Console.WriteLine("tag {0} : {1}", count, BaseXmlSpawner.TagInfo(tag)); + } + } + + + // added in targeting for the [xmlhome command + private class XmlHomeTarget : Target + { + private CommandEventArgs m_e; + public XmlHomeTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) + { + m_e = e; + } + + protected override void OnTarget(Mobile from, object targeted) + { + XmlSpawner spawner = null; + + if (targeted is XmlSpawner) + { + if (m_e.GetString(0) == "status") + { + ((XmlSpawner)targeted).ReportStatus(); + return; + } + } + + + if (targeted is Mobile) + { + spawner = ((Mobile)targeted).Spawner as XmlSpawner; + } + else + if (targeted is Item) + { + spawner = ((Item)targeted).Spawner as XmlSpawner; + } + + if (spawner == null) + { + from.SendMessage("Unable to find spawner for this object"); + return; + } + + // check to make sure it is still on the spawner + foreach (SpawnObject so in spawner.m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + + if (o == targeted) + { + from.SendMessage("{0}, {1}, {2}", spawner.X, spawner.Y, spawner.Z); + + if (m_e.GetString(0) == "go") + { + // make sure the spawner is not in a container. + if (spawner.Parent == null) + { + from.Location = new Point3D(spawner.Location); + from.Map = spawner.Map; + } + else + { + from.SendMessage("Spawner is in a container"); + } + } + else + if (m_e.GetString(0) == "send") + { + // make sure the spawner is not in a container. + if (spawner.Parent == null) + { + if (o is Item) + { + ((Item)o).Location = new Point3D(spawner.Location); + ((Item)o).Map = spawner.Map; + } + if (o is Mobile) + { + ((Mobile)o).Location = new Point3D(spawner.Location); + ((Mobile)o).Map = spawner.Map; + } + } + else + { + from.SendMessage("Spawner is in a container"); + } + } + else + if (m_e.GetString(0) == "gump") + { + spawner.OnDoubleClick(from); + } + + return; + } + } + } + } + } + + [Usage("XmlHome [go][gump][send]")] + [Description("Returns the coordinates of the spawner for the targeted object. Args: 'go' teleports to spawner, 'gump' opens spawner gump, 'send' sends mob home")] + public static void XmlHome_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new XmlHomeTarget(e); + } + + private static void XmlSaveDefaults(string filePath, Mobile m) + { + + if (filePath == null || filePath.Length < 1) return; + + using (StreamWriter op = new StreamWriter(filePath)) + { + if (op == null) + { + m.SendMessage("unable to open file {0}", filePath); + } + XmlTextWriter xml = new XmlTextWriter(op); + + xml.Formatting = Formatting.Indented; + xml.IndentChar = '\t'; + xml.Indentation = 1; + + xml.WriteStartDocument(true); + + xml.WriteStartElement("XmlDefaults"); + + xml.WriteStartElement("defProximityRange"); + xml.WriteString(XmlSpawner.defProximityRange.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTriggerProbability"); + xml.WriteString(XmlSpawner.defTriggerProbability.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defProximityTriggerSound"); + xml.WriteString(XmlSpawner.defProximityTriggerSound.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMinRefractory"); + xml.WriteString(XmlSpawner.defMinRefractory.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMaxRefractory"); + xml.WriteString(XmlSpawner.defMaxRefractory.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTODStart"); + xml.WriteString(XmlSpawner.defTODStart.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTODEnd"); + xml.WriteString(XmlSpawner.defTODEnd.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defStackAmount"); + xml.WriteString(XmlSpawner.defAmount.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defDuration"); + xml.WriteString(XmlSpawner.defDuration.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defIsGroup"); + xml.WriteString(XmlSpawner.defIsGroup.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTeam"); + xml.WriteString(XmlSpawner.defTeam.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defRelativeHome"); + xml.WriteString(XmlSpawner.defRelativeHome.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defSpawnRange"); + xml.WriteString(XmlSpawner.defSpawnRange.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defHomeRange"); + xml.WriteString(XmlSpawner.defHomeRange.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMinDelay"); + xml.WriteString(XmlSpawner.defMinDelay.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMaxDelay"); + xml.WriteString(XmlSpawner.defMaxDelay.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTODMode"); + xml.WriteString(XmlSpawner.defTODMode.ToString()); + xml.WriteEndElement(); + + xml.WriteEndElement(); + + xml.Close(); + } + m.SendMessage("defaults saved to {0}", filePath); + } + + public static void XmlLoadDefaults(string filePath, Mobile m) + { + if (m == null || m.Deleted) return; + if (filePath != null && filePath.Length >= 1) + { + + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + doc.Load(filePath); + + XmlElement root = doc["XmlDefaults"]; + LoadDefaults(root); + m.SendMessage("defaults loaded successfully from {0}", filePath); + } + else + { + m.SendMessage("File {0} does not exist.", filePath); + } + } + } + + private static void LoadDefaults(XmlElement node) + { + + try { XmlSpawner.defProximityRange = int.Parse(node["defProximityRange"].InnerText); } + catch { } + try { XmlSpawner.defTriggerProbability = double.Parse(node["defTriggerProbability"].InnerText); } + catch { } + try { XmlSpawner.defProximityTriggerSound = int.Parse(node["defProximityTriggerSound"].InnerText); } + catch { } + try { XmlSpawner.defMinRefractory = TimeSpan.Parse(node["defMinRefractory"].InnerText); } + catch { } + try { XmlSpawner.defMaxRefractory = TimeSpan.Parse(node["defMaxRefractory"].InnerText); } + catch { } + try { XmlSpawner.defTODStart = TimeSpan.Parse(node["defTODStart"].InnerText); } + catch { } + try { XmlSpawner.defTODEnd = TimeSpan.Parse(node["defTODEnd"].InnerText); } + catch { } + try { XmlSpawner.defAmount = int.Parse(node["defStackAmount"].InnerText); } + catch { } + try { XmlSpawner.defDuration = TimeSpan.Parse(node["defDuration"].InnerText); } + catch { } + try { XmlSpawner.defIsGroup = bool.Parse(node["defIsGroup"].InnerText); } + catch { } + try { XmlSpawner.defTeam = int.Parse(node["defTeam"].InnerText); } + catch { } + try { XmlSpawner.defRelativeHome = bool.Parse(node["defRelativeHome"].InnerText); } + catch { } + try { XmlSpawner.defSpawnRange = int.Parse(node["defSpawnRange"].InnerText); } + catch { } + try { XmlSpawner.defHomeRange = int.Parse(node["defHomeRange"].InnerText); } + catch { } + try { XmlSpawner.defMinDelay = TimeSpan.Parse(node["defMinDelay"].InnerText); } + catch { } + try { XmlSpawner.defMaxDelay = TimeSpan.Parse(node["defMaxDelay"].InnerText); } + catch { } + int todmode = 0; + try { todmode = int.Parse(node["defTODMode"].InnerText); } + catch { } + switch (todmode) + { + case (int)TODModeType.Realtime: + XmlSpawner.defTODMode = TODModeType.Realtime; + break; + case (int)TODModeType.Gametime: + XmlSpawner.defTODMode = TODModeType.Gametime; + break; + } + } + + [Usage("XmlDefaults [defaultpropertyname value]")] + [Description("Returns or changes the default settings of the spawner.")] + public static void XmlDefaults_OnCommand(CommandEventArgs e) + { + Mobile m = e.Mobile; + if (m == null || m.Deleted) return; + if (e.Arguments.Length >= 1) + { + // leave open the possibility of just requesting display of a single property + if (e.Arguments.Length == 2) + { + if (e.Arguments[0].ToLower() == "save") + { + XmlSaveDefaults(e.Arguments[1], m); + } + else + if (e.Arguments[0].ToLower() == "load") + { + XmlLoadDefaults(e.Arguments[1], m); + } + else + // try to set the property + if (e.Arguments[0].ToLower() == "maxdelay") + { + try + { + XmlSpawner.defMaxDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MaxDelay = {0}", XmlSpawner.defMaxDelay); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "mindelay") + { + try + { + XmlSpawner.defMinDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MinDelay = {0}", XmlSpawner.defMinDelay); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "spawnrange") + { + try + { + XmlSpawner.defSpawnRange = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("SpawnRange = {0}", XmlSpawner.defSpawnRange); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "homerange") + { + try + { + XmlSpawner.defHomeRange = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("HomeRange = {0}", XmlSpawner.defHomeRange); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "relativehome") + { + try + { + XmlSpawner.defRelativeHome = Convert.ToBoolean(e.Arguments[1]); + m.SendMessage("RelativeHome = {0}", XmlSpawner.defRelativeHome); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "proximitytriggersound") + { + try + { + XmlSpawner.defProximityTriggerSound = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("ProximityTriggerSound = {0}", XmlSpawner.defProximityTriggerSound); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "proximityrange") + { + try + { + XmlSpawner.defProximityRange = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("ProximityRange = {0}", XmlSpawner.defProximityRange); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "triggerprobability") + { + try + { + XmlSpawner.defTriggerProbability = Convert.ToDouble(e.Arguments[1]); + m.SendMessage("TriggerProbability = {0}", XmlSpawner.defTriggerProbability); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "todstart") + { + try + { + XmlSpawner.defTODStart = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("TODStart = {0}", XmlSpawner.defTODStart); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "todend") + { + try + { + XmlSpawner.defTODEnd = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("TODEnd = {0}", XmlSpawner.defTODEnd); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "stackamount") + { + try + { + XmlSpawner.defAmount = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("StackAmount = {0}", XmlSpawner.defAmount); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "duration") + { + try + { + XmlSpawner.defDuration = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("Duration = {0}", XmlSpawner.defDuration); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "group") + { + try + { + XmlSpawner.defIsGroup = Convert.ToBoolean(e.Arguments[1]); + m.SendMessage("Group = {0}", XmlSpawner.defIsGroup); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "team") + { + try + { + XmlSpawner.defTeam = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("Team = {0}", XmlSpawner.defTeam); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "todmode") + { + int todmode = (int)TODModeType.Realtime; + try + { + todmode = Convert.ToInt32(e.Arguments[1]); + switch (todmode) + { + case (int)TODModeType.Gametime: + XmlSpawner.defTODMode = TODModeType.Gametime; + break; + case (int)TODModeType.Realtime: + XmlSpawner.defTODMode = TODModeType.Realtime; + break; + } + m.SendMessage("TODMode = {0}", XmlSpawner.defTODMode); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "maxrefractory") + { + try + { + XmlSpawner.defMaxRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MaxRefractory = {0}", XmlSpawner.defMaxRefractory); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + if (e.Arguments[0].ToLower() == "minrefractory") + { + try + { + XmlSpawner.defMinRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MinRefractory = {0}", XmlSpawner.defMinRefractory); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + { + m.SendMessage("{0} : no such default value.", e.Arguments[0]); + } + } + + } + else + { + // just display the values + m.SendMessage("TriggerProbability = {0}", XmlSpawner.defTriggerProbability); + m.SendMessage("ProximityRange = {0}", XmlSpawner.defProximityRange); + m.SendMessage("ProximityTriggerSound = {0}", XmlSpawner.defProximityTriggerSound); + m.SendMessage("MinRefractory = {0}", XmlSpawner.defMinRefractory); + m.SendMessage("MaxRefractory = {0}", XmlSpawner.defMaxRefractory); + m.SendMessage("TODStart = {0}", XmlSpawner.defTODStart); + m.SendMessage("TODEnd = {0}", XmlSpawner.defTODEnd); + m.SendMessage("TODMode = {0}", XmlSpawner.defTODMode); + m.SendMessage("StackAmount = {0}", XmlSpawner.defAmount); + m.SendMessage("Duration = {0}", XmlSpawner.defDuration); + m.SendMessage("Group = {0}", XmlSpawner.defIsGroup); + m.SendMessage("Team = {0}", XmlSpawner.defTeam); + m.SendMessage("RelativeHome = {0}", XmlSpawner.defRelativeHome); + m.SendMessage("SpawnRange = {0}", XmlSpawner.defSpawnRange); + m.SendMessage("HomeRange = {0}", XmlSpawner.defHomeRange); + m.SendMessage("MinDelay = {0}", XmlSpawner.defMinDelay); + m.SendMessage("MaxDelay = {0}", XmlSpawner.defMaxDelay); + } + } + + + [Usage("XmlSpawnerShowAll")] + [Aliases("XmlShow")] + [Description("Makes all XmlSpawner objects movable and also changes the item id to a blue ships mast for easy identification.")] + public static void ShowSpawnPoints_OnCommand(CommandEventArgs e) + { + ArrayList ToShow = new ArrayList(); + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + //turned off visibility. Admins will still see masts but players will not. + item.Visible = false; // set the spawn item visibility + item.Movable = false; // Make the spawn item movable + item.Hue = 88; // Bright blue colour so its easy to spot + item.ItemID = ShowItemId; // Ship Mast (Very tall, easy to see if beneath other objects) + + // find container-held spawners to be marked with an external static + if ((item.Parent != null) && (item.RootParent is Container)) + { + ToShow.Add(item); + } + } + } + + // place the statics + foreach (Item i in ToShow) + { + + XmlSpawner xml_item = (XmlSpawner)i; + // does the spawner already have a static attached to it? could happen if two showall commands are issued in a row. + // if so then dont add another + if ((xml_item.m_ShowContainerStatic == null || xml_item.m_ShowContainerStatic.Deleted) && xml_item.RootParent is Container) + { + Container root_item = xml_item.RootParent as Container; + // calculate a world location for the static. Position it just above the container + int x = root_item.Location.X; + int y = root_item.Location.Y; + int z = root_item.Location.Z + 10; + + Static s = new Static(ShowItemId); + s.Visible = false; + s.MoveToWorld(new Point3D(x, y, z), root_item.Map); + + xml_item.m_ShowContainerStatic = s; + } + + } + } + + [Usage("XmlSpawnerHideAll")] + [Aliases("XmlHide")] + [Description("Makes all XmlSpawner objects invisible and unmovable returns the object id to the default.")] + public static void HideSpawnPoints_OnCommand(CommandEventArgs e) + { + ArrayList ToDelete = new ArrayList(); + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + item.Visible = false; + item.Movable = false; + item.Hue = 0; + item.ItemID = BaseItemId; + + // get rid of the external static marker for container-held spawners + // check anything that might have been tagged with a container static + XmlSpawner xml_item = (XmlSpawner)item; + if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted) + { + ToDelete.Add(item); + } + } + } + foreach (Item i in ToDelete) + { + XmlSpawner xml_item = (XmlSpawner)i; + if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted) + { + xml_item.m_ShowContainerStatic.Delete(); + } + } + } + + [Usage("XmlGo | [z]")] + [Description("Go command used with spawn editor, takes the name of the map as the first parameter.")] + private static void SpawnEditorGo_OnCommand(CommandEventArgs e) + { + if (e == null) return; + + Mobile from = e.Mobile; + + // Make sure a map name was given at least + if (from != null && e.Length >= 1) + { + // Get the map + Map NewMap = null; + string MapName = e.Arguments[0]; + + // Convert the xml map value to a real map object + if (string.Compare(MapName, Map.Trammel.Name, true) == 0) + NewMap = Map.Trammel; + else if (string.Compare(MapName, Map.Felucca.Name, true) == 0) + NewMap = Map.Felucca; + else if (string.Compare(MapName, Map.Ilshenar.Name, true) == 0) + NewMap = Map.Ilshenar; + else if (string.Compare(MapName, Map.Malas.Name, true) == 0) + NewMap = Map.Malas; + else if (string.Compare(MapName, Map.Tokuno.Name, true) == 0) + NewMap = Map.Tokuno; + else + { + from.SendMessage("Map '{0}' does not exist!", MapName); + return; + } + + // Now that the map has been determined, continue + // Check if the request is to simply change maps + if (e.Length == 1) + { + // Map Change ONLY + from.Map = NewMap; + } + else if (e.Length == 3) + { + // Map & X Y ONLY + if (NewMap != null) + { + int x = e.GetInt32(1); + int y = e.GetInt32(2); + int z = NewMap.GetAverageZ(x, y); + from.Map = NewMap; + from.Location = new Point3D(x, y, z); + } + } + else if (e.Length == 4) + { + // Map & X Y Z + from.Map = NewMap; + from.Location = new Point3D(e.GetInt32(1), e.GetInt32(2), e.GetInt32(3)); + } + else + { + from.SendMessage("Format: XmlGo | [z]"); + } + } + } + + [Usage("SmartStat [accesslevel Player/Counselor/GameMaster/Seer/Administrator]")] + + [Description("Returns the spawn reduction due to SmartSpawning.")] + public static void SmartStat_OnCommand(CommandEventArgs e) + { + if (e == null || e.Mobile == null) return; + + if (e.Arguments.Length > 1 && e.Arguments[0].ToLower() == "accesslevel" && e.Mobile.AccessLevel >= AccessLevel.Administrator) + { + try + { + SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), e.Arguments[1], true); + } + catch { } + } + // handle the + // number of spawners + int count = 0; + // number of actual spawns + int currentcount = 0; + int smartcount = 0; + int inactivecount = 0; + // maximum possible spawns + int totalcount = 0; + int maxcount = 0; + // maximum possible of spawns that are currently inactivated + int savings = 0; + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + + XmlSpawner spawner = (XmlSpawner)item; + + if (spawner.Deleted) continue; + + totalcount += spawner.MaxCount; + // get the current count without defragging + currentcount += spawner.SafeCurrentCount; + count++; + + // check to see if smartspawning is set + if (spawner.SmartSpawning) + { + smartcount++; + maxcount += spawner.MaxCount; + } + + if (spawner.IsInactivated) + { + inactivecount++; + savings += spawner.MaxCount; + } + } + } + + int percent = 0; + //if((currentcount + savings) > 0) + //{ + // percent = 100*savings/(currentcount + savings); + //} + + int maxpercent = 0; + if (totalcount > 0) + { + percent = 100 * savings / totalcount; + maxpercent = 100 * maxcount / totalcount; + } + + e.Mobile.SendMessage( + "Running XmlSpawner version {9}\n" + + "Smartspawning access level is {11}\n" + + "--------------------------------\n" + + "{0} XmlSpawners\n" + + "{1} are configured for SmartSpawning\n" + + "{2} are currently inactivated\n" + + "{10} sectors being monitored\n" + + "Maximum possible spawn count is {3}\n" + + "Maximum possible spawn reduction is {4}\n" + + "Current spawn count is {5}\n" + + "Current spawn reduction is {6}\n" + + "Maximum possible savings is {7}%\n" + + "Current savings is {8}%", + count, smartcount, inactivecount, totalcount, maxcount, currentcount, savings, maxpercent, + percent, Version, totalSectorsMonitored, SmartSpawnAccessLevel); + } + + [Usage("OptimalSmartSpawning [max spawn/homerange diff]")] + + [Description("Activates SmartSpawning on XmlSpawners that are well-suited for use of this feature.")] + public static void OptimalSmartSpawning_OnCommand(CommandEventArgs e) + { + + int maxdiff = 1; + if (e.Arguments.Length > 0) + { + try + { + maxdiff = int.Parse(e.Arguments[0]); + } + catch { } + } + int count = 0; + int maxcount = 0; + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + + XmlSpawner spawner = (XmlSpawner)item; + + // determine whether this spawner is a good candidate + + if (spawner.Deleted) continue; + + // ignore spawners in towns + //if (Region.Find(spawner.Location, spawner.Map) is Regions.TownRegion) continue; + + // dont bother setting it on triggered spawners + if (spawner.ProximityRange >= 0) continue; + + // check the relative spawnrange and homerange. Dont set it on spawners with a larger homerange than spawnrange + int width = spawner.m_Width; + int height = spawner.m_Height; + + if (spawner.HomeRange * 2 > width + maxdiff * 2 || spawner.HomeRange * 2 > height + maxdiff * 2 && spawner.m_Region != null) continue; + + int nso = 0; + + if (spawner.m_SpawnObjects != null) nso = spawner.m_SpawnObjects.Count; + + // empty spawner so skip it + if (nso == 0) continue; + + bool skipit = false; + + // check the spawn types + for (int i = 0; i < nso; ++i) + { + SpawnObject so = spawner.m_SpawnObjects[i] as SpawnObject; + + if (so == null) continue; + + string typestr = so.TypeName; + + Type type = null; + + if (typestr != null) + type = SpawnerType.GetType(typestr); + + // if it has basevendors on it or invalid types, then skip it + if (typestr == null || (type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor)))) || + ((type == null) && (!BaseXmlSpawner.IsTypeOrItemKeyword(typestr) && typestr.IndexOf('{') == -1 && !typestr.StartsWith("*") && !typestr.StartsWith("#")))) + { + skipit = true; + break; + } + } + + if (!skipit) + { + count++; + spawner.SmartSpawning = true; + maxcount += spawner.MaxCount; + } + } + } + e.Mobile.SendMessage("Configured {0} XmlSpawners for SmartSpawning using maxdiff of {1}", count, maxdiff); + e.Mobile.SendMessage("Estimated item/mob reduction is {0}", maxcount); + + } + + + [Usage("XmlSpawnerWipe [SpawnerPrefixFilter]")] + [Description("Removes all XmlSpawner objects from the current map.")] + public static void Wipe_OnCommand(CommandEventArgs e) + { + WipeSpawners(e, false); + } + + [Usage("XmlSpawnerWipeAll [SpawnerPrefixFilter]")] + [Description("Removes all XmlSpawner objects from the entire world.")] + public static void WipeAll_OnCommand(CommandEventArgs e) + { + WipeSpawners(e, true); + } + + public static void XmlUnLoadFromFile(string filename, string SpawnerPrefix, Mobile from, out int processedmaps, out int processedspawners) + { + + processedmaps = 0; + processedspawners = 0; + if (filename == null || filename.Length <= 0) return; + + int total_processed_maps = 0; + int total_processed_spawners = 0; + + // Check if the file exists + if (System.IO.File.Exists(filename) == true) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + if (from != null) + from.SendMessage("Unable to open {0} for unloading", filename); + return; + } + + XmlUnLoadFromStream(fs, filename, SpawnerPrefix, from, out processedmaps, out processedspawners); + + } + else + // check to see if it is a directory + if (System.IO.Directory.Exists(filename) == true) + { + // if so then import all of the .xml files in the directory + string[] files = null; + try + { + files = Directory.GetFiles(filename, "*.xml"); + } + catch { } + if (files != null && files.Length > 0) + { + if (from != null) + from.SendMessage("UnLoading {0} .xml files from directory {1}", files.Length, filename); + foreach (string file in files) + { + XmlUnLoadFromFile(file, SpawnerPrefix, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + // recursively search subdirectories for more .xml files + string[] dirs = null; + try + { + dirs = Directory.GetDirectories(filename); + } + catch { } + if (dirs != null && dirs.Length > 0) + { + foreach (string dir in dirs) + { + XmlUnLoadFromFile(dir, SpawnerPrefix, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + if (from != null) + from.SendMessage("UnLoaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + processedmaps = total_processed_maps; + processedspawners = total_processed_spawners; + } + else + { + if (from != null) + from.SendMessage("{0} does not exist", filename); + } + + } + + public static void XmlUnLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + + if (fs == null) return; + + + + int TotalCount = 0; + int TrammelCount = 0; + int FeluccaCount = 0; + int IlshenarCount = 0; + int MalasCount = 0; + int TokunoCount = 0; + int OtherCount = 0; + int bad_spawner_count = 0; + int spawners_deleted = 0; + + + + if (from != null) + from.SendMessage(string.Format("UnLoading {0} objects{1} from file {2}.", + "XmlSpawner", ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), filename)); + + // Create the data set + DataSet ds = new DataSet(SpawnDataSetName); + + // Read in the file + //ds.ReadXml( e.Arguments[0].ToString() ); + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch + { + if (from != null) + from.SendMessage(33, "Error reading xml file {0}", filename); fileerror = true; + } + // close the file + fs.Close(); + if (fileerror) return; + + // Check that at least a single table was loaded + if (ds.Tables != null && ds.Tables.Count > 0) + { + // Add each spawn point to the current map + if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) + { + // load in the spawner info. Certain fields are required and therefore cannot be ignored + // the exception handler for those will flag bad_spawner and the result will be logged + + // Each row makes up a single spawner + string SpawnName = "Spawner"; + try { SpawnName = (string)dr["Name"]; } + catch { } + + // Check if there is any spawner name criteria specified on the unload + if (SpawnerPrefix == null || (SpawnerPrefix.Length == 0) || (SpawnName.StartsWith(SpawnerPrefix) == true)) + { + bool bad_spawner = false; + // Try load the GUID (might not work so create a new GUID) + Guid SpawnId = Guid.NewGuid(); + try { SpawnId = new Guid((string)dr["UniqueId"]); } + catch { bad_spawner = true; } + // have to have a GUID or no point in continuing + if (bad_spawner) + { + bad_spawner_count++; + continue; + } + // Get the map (default to the mobiles map) + Map SpawnMap = Map.Internal; + string XmlMapName = SpawnMap.Name; + + // Try to get the "map" field, but in case it doesn't exist, catch and discard the exception + try { XmlMapName = (string)dr["Map"]; } + catch { } + + // Convert the xml map value to a real map object + if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel") + { + SpawnMap = Map.Trammel; + TrammelCount++; + } + else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca") + { + SpawnMap = Map.Felucca; + FeluccaCount++; + } + else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar") + { + SpawnMap = Map.Ilshenar; + IlshenarCount++; + } + else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas") + { + SpawnMap = Map.Malas; + MalasCount++; + } + else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno") + { + SpawnMap = Map.Tokuno; + TokunoCount++; + } + else + { + try + { + SpawnMap = Map.Parse(XmlMapName); + } + catch { } + OtherCount++; + } + // Check if this spawner already exists + XmlSpawner OldSpawner = null; + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner) + { + XmlSpawner CheckXmlSpawner = (XmlSpawner)i; + // Check if the spawners GUID is the same as the one being unloaded + // and that the spawners map is the same as the one being unloaded + if ((CheckXmlSpawner.UniqueId == SpawnId.ToString()) + /*&& ( CheckXmlSpawner.Map == SpawnMap )*/ ) + { + OldSpawner = (XmlSpawner)i; + if (OldSpawner != null) + { + spawners_deleted++; + OldSpawner.Delete(); + } + + break; + } + } + } + + } + TotalCount++; + } + } + } + + try + { + fs.Close(); + } + catch { } + + if (from != null) + from.SendMessage("{0}/{8} spawner(s) were unloaded using file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].", + spawners_deleted, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount, TotalCount); + if (bad_spawner_count > 0) + { + if (from != null) + from.SendMessage(33, "{0} bad spawners detected.", bad_spawner_count); + } + processedmaps = 1; + processedspawners = TotalCount; + + } + + [Usage("XmlSpawnerUnLoad [SpawnerPrefixFilter]")] + [Aliases("XmlUnload")] + [Description("UnLoads XmlSpawner objects from the proper map as defined in the file supplied.")] + public static void UnLoad_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + // Spawner unload criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (load criteria) + if (e.Arguments.Length > 1) + SpawnerPrefix = e.Arguments[1]; + + string filename = LocateFile(e.Arguments[0].ToString()); + int processedmaps; + int processedspawners; + XmlUnLoadFromFile(filename, SpawnerPrefix, e.Mobile, out processedmaps, out processedspawners); + } + else + e.Mobile.SendMessage("Usage: {0} ", e.Command); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + [Usage("XmlImportMap ")] + [Description("Loads spawner definitions from a .map file")] + public static void XmlImportMap_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = e.Arguments[0].ToString(); + + int processedmaps; + int processedspawners; + XmlImportMap(filename, e.Mobile, out processedmaps, out processedspawners); + } + else + e.Mobile.SendMessage("Usage: {0} ", e.Command); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + public static void XmlImportMap(string filename, Mobile from, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + int total_processed_maps = 0; + int total_processed_spawners = 0; + if (filename == null || filename.Length <= 0 || from == null || from.Deleted) return; + // Check if the file exists + if (System.IO.File.Exists(filename) == true) + { + int spawnercount = 0; + int badspawnercount = 0; + int linenumber = 0; + // default is no map override, use the map spec from each spawn line + int overridemap = -1; + double overridemintime = -1; + double overridemaxtime = -1; + bool newformat = false; + try + { + // Create an instance of StreamReader to read from a file. + // The using statement also closes the StreamReader. + using (StreamReader sr = new StreamReader(filename)) + { + string line; + // Read and display lines from the file until the end of + // the file is reached. + while ((line = sr.ReadLine()) != null) + { + // the old format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // * | typename:typename:... |s1 |s2 |s3 |s4 |s5 | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount1 | maxcount2 | maxcount3 | maxcount4 | maxcount5 + // where s1-5 are additional spawn type entries with their own maxcounts + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + linenumber++; + // is this the new format? + string[] args; + if (line.IndexOf('|') >= 0) + { + args = line.Trim().Split('|'); + newformat = true; + } + else + { + args = line.Trim().Split(' '); + } + + // determine the format of this line and parse accordingly + if (newformat) + { + ParseNewMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); + } + else + { + ParseOldMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); + } + + } + sr.Close(); + } + } + catch (Exception e) + { + // Let the user know what went wrong. + from.SendMessage("The file could not be read: {0}", e.Message); + } + from.SendMessage("Imported {0} spawners from {1}", spawnercount, filename); + from.SendMessage("{0} bad spawners detected", badspawnercount); + processedmaps = 1; + processedspawners = spawnercount; + } + else + // check to see if it is a directory + if (System.IO.Directory.Exists(filename) == true) + { + // if so then import all of the .map files in the directory + string[] files = null; + try + { + files = Directory.GetFiles(filename, "*.map"); + } + catch { } + if (files != null && files.Length > 0) + { + from.SendMessage("Importing {0} .map files from directory {1}", files.Length, filename); + foreach (string file in files) + { + XmlImportMap(file, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + // recursively search subdirectories for more .map files + string[] dirs = null; + try + { + dirs = Directory.GetDirectories(filename); + } + catch { } + if (dirs != null && dirs.Length > 0) + { + foreach (string dir in dirs) + { + XmlImportMap(dir, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + from.SendMessage("Imported a total of {0} .map files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + processedmaps = total_processed_maps; + processedspawners = total_processed_spawners; + } + else + { + from.SendMessage("{0} does not exist", filename); + } + } + + private static void ParseNewMapFormat(Mobile from, string filename, string line, string[] args, int linenumber, ref int spawnercount, ref int badspawnercount, ref int overridemap, ref double overridemintime, ref double overridemaxtime) + { + // format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // or + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange spawnid maxcount + // ## are comments + // overridemap mapnumber + // map 0 is tram+fel + // map 1 is fel + // map 2 is tram + // map 3 is ilsh + // map 4 is mal + // map 5 is tokuno + // + // * | typename:typename:... | | | | | | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount1 | maxcount2 | maxcount2 | maxcount3 | maxcount4 | maxcount5 | maxcount6 + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + if (args == null || from == null) return; + + // look for the override keyword + if (args.Length == 2 && (args[0].ToLower() == "overridemap")) + { + try + { + overridemap = int.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && (args[0].ToLower() == "overridemintime")) + { + try + { + overridemintime = double.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && (args[0].ToLower() == "overridemaxtime")) + { + try + { + overridemaxtime = double.Parse(args[1]); + } + catch { } + } + else + // look for a spawn spec line + if (args.Length > 0 && (args[0] == "*")) + { + + bool badspawn = false; + int x = 0; + int y = 0; + int z = 0; + int map = 0; + double mindelay = 0; + double maxdelay = 0; + int homerange = 0; + int spawnrange = 0; + + int spawnid = 0; + string[][] typenames = new string[6][]; + + int[] maxcount = new int[6]; + + // parse the main args + + try + { + // get the list of spawns + for (int k = 0; k < 6; k++) + typenames[k] = args[k + 1].Split(':'); + + x = int.Parse(args[7]); + y = int.Parse(args[8]); + z = int.Parse(args[9]); + map = int.Parse(args[10]); + mindelay = double.Parse(args[11]); + maxdelay = double.Parse(args[12]); + homerange = int.Parse(args[13]); + spawnrange = int.Parse(args[14]); + spawnid = int.Parse(args[15]); + + for (int k = 0; k < 6; k++) + maxcount[k] = int.Parse(args[k + 16]); + + } + catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + + // compute the total number of spawns + int totalspawns = 0; + int totalmaxcount = 0; + + for (int k = 0; k < 6; k++) + { + if (typenames[k] == null) continue; + + for (int i = 0; i < typenames[k].Length; i++) + { + if (typenames[k][i] == null || typenames[k][i].Length == 0) continue; + + totalspawns++; + } + + totalmaxcount += maxcount[k]; + } + + // apply min/maxdelay overrides + if (overridemintime != -1) + { + mindelay = overridemintime; + } + if (overridemaxtime != -1) + { + maxdelay = overridemaxtime; + } + if (mindelay > maxdelay) maxdelay = mindelay; + + if (!badspawn && totalspawns > 0) + { + // everything seems ok so go ahead and make the spawner + // check for map override + if (overridemap >= 0) map = overridemap; + Map spawnmap = Map.Internal; + switch (map) + { + case 0: + spawnmap = Map.Felucca; + // note it also does trammel + break; + case 1: + spawnmap = Map.Felucca; + break; + case 2: + spawnmap = Map.Trammel; + break; + case 3: + spawnmap = Map.Ilshenar; + break; + case 4: + spawnmap = Map.Malas; + break; + case 5: + spawnmap = Map.Tokuno; + break; + } + + if (!IsValidMapLocation(x, y, spawnmap)) + { + // invalid so dont spawn it + badspawnercount++; + from.SendMessage("Invalid map/location at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + + // allow it to make an xmlspawner instead + // first add all of the creatures on the list + SpawnObject[] so = new SpawnObject[totalspawns]; + int count = 0; + bool hasvendor = true; + for (int k = 0; k < 6; k++) + { + if (typenames[k] == null) continue; + + for (int i = 0; i < typenames[k].Length; i++) + { + if (typenames[k][i] == null || typenames[k][i].Length == 0 || count > totalspawns) continue; + + so[count++] = new SpawnObject(typenames[k][i], maxcount[k]); + + // check the type to see if there are vendors on it + Type type = SpawnerType.GetType(typenames[k][i]); + + // check for vendor-only spawners which get special spawnrange treatment + if (type != null && (type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor)))) + { + hasvendor = false; + } + + } + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + + // and give it a name based on the spawner count and file + string spawnername = String.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount); + + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null); + + if (hasvendor) + { + // force vendor spawners to behave like the distro + spawner.SpawnRange = 0; + } + else + { + spawner.SpawnRange = spawnrange; + } + + spawner.m_PlayerCreated = true; + string fromname = null; + if (from != null) fromname = from.Name; + spawner.LastModifiedBy = fromname; + spawner.FirstModifiedBy = fromname; + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Invalid map at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + // handle the special case of map 0 that also needs to do trammel + if (map == 0) + { + spawnmap = Map.Trammel; + // assign it a unique id + SpawnId = Guid.NewGuid(); + // Create the new xml spawner + spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null); + + spawner.SpawnRange = spawnrange; + spawner.m_PlayerCreated = true; + + spawner.LastModifiedBy = fromname; + spawner.FirstModifiedBy = fromname; + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + } + } + else + { + badspawnercount++; + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + } + } + } + + private static void ParseOldMapFormat(Mobile from, string filename, string line, string[] args, int linenumber, ref int spawnercount, ref int badspawnercount, ref int overridemap, ref double overridemintime, ref double overridemaxtime) + { + // format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // or + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange spawnid maxcount + // ## are comments + // overridemap mapnumber + // map 0 is tram+fel + // map 1 is fel + // map 2 is tram + // map 3 is ilsh + // map 4 is mal + // map 5 is tokuno + // + // * | typename:typename:... | | | | | | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount2 | maxcount2 | maxcount3 | maxcount4 | maxcount5 + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + if (args == null || from == null) return; + + // look for the override keyword + if (args.Length == 2 && (args[0].ToLower() == "overridemap")) + { + try + { + overridemap = int.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && (args[0].ToLower() == "overridemintime")) + { + try + { + overridemintime = double.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && (args[0].ToLower() == "overridemaxtime")) + { + try + { + overridemaxtime = double.Parse(args[1]); + } + catch { } + } + else + // look for a spawn spec line + if (args.Length > 0 && (args[0] == "*")) + { + bool badspawn = false; + int x = 0; + int y = 0; + int z = 0; + int map = 0; + double mindelay = 0; + double maxdelay = 0; + int homerange = 0; + int spawnrange = 0; + int maxcount = 0; + int spawnid = 0; + string[] typenames = null; + if (args.Length != 11 && args.Length != 12) + { + badspawn = true; + from.SendMessage("Invalid arg count {1} at line {0}", linenumber, args.Length); + } + else + { + // get the list of spawns + typenames = args[1].Split(':'); + // parse the rest of the args + + if (args.Length == 11) + { + + try + { + x = int.Parse(args[2]); + y = int.Parse(args[3]); + z = int.Parse(args[4]); + map = int.Parse(args[5]); + mindelay = double.Parse(args[6]); + maxdelay = double.Parse(args[7]); + homerange = int.Parse(args[8]); + spawnrange = int.Parse(args[9]); + maxcount = int.Parse(args[10]); + + } + catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + } + else + if (args.Length == 12) + { + + try + { + x = int.Parse(args[2]); + y = int.Parse(args[3]); + z = int.Parse(args[4]); + map = int.Parse(args[5]); + mindelay = double.Parse(args[6]); + maxdelay = double.Parse(args[7]); + homerange = int.Parse(args[8]); + spawnrange = int.Parse(args[9]); + spawnid = int.Parse(args[10]); + maxcount = int.Parse(args[11]); + + } + catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + } + } + + + // apply mi/maxdelay overrides + if (overridemintime != -1) + { + mindelay = overridemintime; + } + if (overridemaxtime != -1) + { + maxdelay = overridemaxtime; + } + if (mindelay > maxdelay) maxdelay = mindelay; + + if (!badspawn && typenames != null && typenames.Length > 0) + { + // everything seems ok so go ahead and make the spawner + // check for map override + if (overridemap >= 0) map = overridemap; + Map spawnmap = Map.Internal; + switch (map) + { + case 0: + spawnmap = Map.Felucca; + // note it also does trammel + break; + case 1: + spawnmap = Map.Felucca; + break; + case 2: + spawnmap = Map.Trammel; + break; + case 3: + spawnmap = Map.Ilshenar; + break; + case 4: + spawnmap = Map.Malas; + break; + case 5: + spawnmap = Map.Tokuno; + break; + } + + if (!IsValidMapLocation(x, y, spawnmap)) + { + // invalid so dont spawn it + badspawnercount++; + from.SendMessage("Invalid map/location at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + + // allow it to make an xmlspawner instead + // first add all of the creatures on the list + SpawnObject[] so = new SpawnObject[typenames.Length]; + + bool hasvendor = true; + for (int i = 0; i < typenames.Length; i++) + { + so[i] = new SpawnObject(typenames[i], maxcount); + + // check the type to see if there are vendors on it + Type type = SpawnerType.GetType(typenames[i]); + + // check for vendor-only spawners which get special spawnrange treatment + if (type != null && (type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor)))) + { + hasvendor = false; + } + + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + + // and give it a name based on the spawner count and file + string spawnername = String.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount); + + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null); + + if (hasvendor) + { + // force vendor spawners to behave like the distro + spawner.SpawnRange = 0; + } + else + { + spawner.SpawnRange = spawnrange; + } + + spawner.m_PlayerCreated = true; + string fromname = null; + if (from != null) fromname = from.Name; + spawner.LastModifiedBy = fromname; + spawner.FirstModifiedBy = fromname; + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Invalid map at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + // handle the special case of map 0 that also needs to do trammel + if (map == 0) + { + spawnmap = Map.Trammel; + // assign it a unique id + SpawnId = Guid.NewGuid(); + // Create the new xml spawner + spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null); + + spawner.SpawnRange = spawnrange; + spawner.m_PlayerCreated = true; + + spawner.LastModifiedBy = fromname; + spawner.FirstModifiedBy = fromname; + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + } + } + else + { + badspawnercount++; + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + } + } + } + + + + //------------------------------------------------------------------------------------------------------------------------------------ + // The following code was taken from Sno's xml exporter package and slightly modified to create xmlspawners instead of regular spawners + //------------------------------------------------------------------------------------------------------------------------------------ + [Usage("XmlImportSpawners filename")] + [Description("Loads xml files created by Sno's xml exporter as xmlspawners.")] + public static void XmlImportSpawners_OnCommand(CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + { + string filename = e.GetString(0); + string filePath = Path.Combine("Saves/Spawners", filename); + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + try + { + doc.Load(filePath); + } + catch + { + e.Mobile.SendMessage("unable to load file {0}.", filePath); + return; + } + + XmlElement root = doc["spawners"]; + int successes = 0, failures = 0; + if (root != null && root.GetElementsByTagName("spawner") != null) + { + foreach (XmlElement spawner in root.GetElementsByTagName("spawner")) + { + try + { + ImportSpawner(spawner, e.Mobile); + successes++; + } + catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; } + } + } + e.Mobile.SendMessage("{0} spawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + } + else + e.Mobile.SendMessage("File {0} does not exist.", filePath); + } + else + e.Mobile.SendMessage("Usage: [XmlImportSpawners "); + } + + private static string GetText(XmlElement node, string defaultValue) + { + if (node == null) + return defaultValue; + return node.InnerText; + } + + private static void ImportSpawner(XmlElement node, Mobile from) + { + int count = int.Parse(GetText(node["count"], "1")); + int homeRange = int.Parse(GetText(node["homerange"], "4")); + int walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); + // width of the spawning area + int spawnwidth = homeRange * 2; + if (walkingRange >= 0) spawnwidth = walkingRange * 2; + + int team = int.Parse(GetText(node["team"], "0")); + bool group = bool.Parse(GetText(node["group"], "False")); + TimeSpan maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); + TimeSpan minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); + ArrayList creaturesName = LoadCreaturesName(node["creaturesname"]); + string name = GetText(node["name"], "Spawner"); + Point3D location = Point3D.Parse(GetText(node["location"], "Error")); + Map map = Map.Parse(GetText(node["map"], "Error")); + + // allow it to make an xmlspawner instead + // first add all of the creatures on the list + SpawnObject[] so = new SpawnObject[creaturesName.Count]; + + bool hasvendor = false; + + for (int i = 0; i < creaturesName.Count; i++) + { + so[i] = new SpawnObject((string)creaturesName[i], count); + // check the type to see if there are vendors on it + Type type = SpawnerType.GetType((string)creaturesName[i]); + + // if it has basevendors on it or invalid types, then skip it + if (type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor)))) + { + hasvendor = true; + } + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, spawnwidth, spawnwidth, name, count, + minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + + if (hasvendor) + { + spawner.SpawnRange = 0; + } + else + { + spawner.SpawnRange = homeRange; + } + spawner.m_PlayerCreated = true; + string fromname = null; + if (from != null) fromname = from.Name; + spawner.LastModifiedBy = fromname; + spawner.FirstModifiedBy = fromname; + + spawner.MoveToWorld(location, map); + if (!IsValidMapLocation(location, spawner.Map)) + { + spawner.Delete(); + throw new Exception("Invalid spawner location."); + } + } + + private static ArrayList LoadCreaturesName(XmlElement node) + { + ArrayList names = new ArrayList(); + + if (node != null) + { + foreach (XmlElement ele in node.GetElementsByTagName("creaturename")) + { + if (ele != null) + names.Add(ele.InnerText); + } + } + return names; + } + //------------------------------------------------------------------------------------------------------------------------------------ + // end of modified xml importer by Sno + //------------------------------------------------------------------------------------------------------------------------------------ + + + [Usage("XmlImportMSF filename")] + [Description("Loads msf files created by Morxeton's megaspawner as xmlspawners.")] + public static void XmlImportMSF_OnCommand(CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + { + /* + // I'm not sure what the default location for .msf files is + string filename = e.GetString( 0 ); + string filePath = Path.Combine( "Data/Megaspawner", filename ); + */ + string filePath = e.GetString(0); + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + doc.Load(filePath); + XmlElement root = doc["MegaSpawners"]; + if (root != null) + { + int successes = 0, failures = 0; + foreach (XmlElement spawner in root.GetElementsByTagName("MegaSpawner")) + { + + try + { + ImportMegaSpawner(e.Mobile, spawner); + successes++; + } + catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; } + } + e.Mobile.SendMessage("{0} megaspawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + } + else + { + e.Mobile.SendMessage("Invalid .msf file. No MegaSpawners node found"); + } + } + else + e.Mobile.SendMessage("File {0} does not exist.", filePath); + } + else + e.Mobile.SendMessage("Usage: [XmlImportMSF "); + } + + private static void ImportMegaSpawner(Mobile from, XmlElement node) + { + string name = GetText(node["Name"], "MegaSpawner"); + bool running = bool.Parse(GetText(node["Active"], "True")); + Point3D location = Point3D.Parse(GetText(node["Location"], "Error")); + Map map = Map.Parse(GetText(node["Map"], "Error")); + + + int team = 0; + bool group = false; + int maxcount = 0; // default maxcount of the spawner + int homeRange = 4; // default homerange + int spawnRange = 4; // default homerange + TimeSpan maxDelay = TimeSpan.FromMinutes(10); + TimeSpan minDelay = TimeSpan.FromMinutes(5); + + XmlElement listnode = node["EntryLists"]; + + int nentries = 0; + SpawnObject[] so = null; + + + if (listnode != null) + { + // get the number of entries + if (listnode.HasAttributes) + { + XmlAttributeCollection attr = listnode.Attributes; + + nentries = int.Parse(attr.GetNamedItem("count").Value); + } + if (nentries > 0) + { + so = new SpawnObject[nentries]; + + int entrycount = 0; + bool diff = false; + foreach (XmlElement entrynode in listnode.GetElementsByTagName("EntryList")) + { + // go through each entry and add a spawn object for it + if (entrynode != null) + { + if (entrycount == 0) + { + // get the spawner defaults from the first entry + // dont handle the individually specified entry attributes + group = bool.Parse(GetText(entrynode["GroupSpawn"], "False")); + maxDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00"))); + minDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00"))); + homeRange = int.Parse(GetText(entrynode["WalkRange"], "10")); + spawnRange = int.Parse(GetText(entrynode["SpawnRange"], "4")); + } + else + { + // just check for consistency with other entries and report discrepancies + if (group != bool.Parse(GetText(entrynode["GroupSpawn"], "False"))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual group entry difference: {0} vs {1}", + GetText(entrynode["GroupSpawn"], "False"), group); + + } + } + catch { } + } + if (minDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00")))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual mindelay entry difference: {0} vs {1}", + GetText(entrynode["MinDelay"], "05:00"), minDelay); + + } + } + catch { } + } + if (maxDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00")))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual maxdelay entry difference: {0} vs {1}", + GetText(entrynode["MaxDelay"], "10:00"), maxDelay); + + } + } + catch { } + } + if (homeRange != int.Parse(GetText(entrynode["WalkRange"], "10"))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual homerange entry difference: {0} vs {1}", + GetText(entrynode["WalkRange"], "10"), homeRange); + + } + } + catch { } + } + if (spawnRange != int.Parse(GetText(entrynode["SpawnRange"], "4"))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual spawnrange entry difference: {0} vs {1}", + GetText(entrynode["SpawnRange"], "4"), spawnRange); + + } + } + catch { } + } + } + + // these apply to individual entries + int amount = int.Parse(GetText(entrynode["Amount"], "1")); + string entryname = GetText(entrynode["EntryType"], ""); + + // keep track of the maxcount for the spawner by adding the individual amounts + maxcount += amount; + + // add the creature entry + so[entrycount] = new SpawnObject(entryname, amount); + + entrycount++; + if (entrycount > nentries) + { + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("{0} MSFImport Error; inconsistent entry count {1} {2}", DateTime.Now, location, map); + op.WriteLine(); + } + } + catch { } + from.SendMessage("Inconsistent entry count detected at {0} {1}.", location, map); + break; + } + + } + } + if (diff) + { + from.SendMessage("Individual entry setting detected at {0} {1}.", location, map); + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("{0} MSFImport: Individual entry setting differences listed above from spawner at {1} {2}", DateTime.Now, location, map); + op.WriteLine(); + } + } + catch { } + } + } + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, 0, 0, name, maxcount, + minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + + spawner.SpawnRange = spawnRange; + spawner.m_PlayerCreated = true; + string fromname = null; + if (from != null) fromname = from.Name; + spawner.LastModifiedBy = fromname; + spawner.FirstModifiedBy = fromname; + + // Try to find a valid Z height if required (Z == -999) + + if (location.Z == -999) + { + int NewZ = map.GetAverageZ(location.X, location.Y); + + if (map.CanFit(location.X, location.Y, NewZ, SpawnFitSize) == false) + { + for (int x = 1; x <= 39; x++) + { + if (map.CanFit(location.X, location.Y, NewZ + x, SpawnFitSize)) + { + NewZ += x; + break; + } + } + } + location.Z = NewZ; + } + + spawner.MoveToWorld(location, map); + + if (!IsValidMapLocation(location, spawner.Map)) + { + spawner.Delete(); + throw new Exception("Invalid spawner location."); + } + } + + + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + int total_processed_maps = 0; + int total_processed_spawners = 0; + + if (filename == null || filename.Length <= 0) return; + + + // Check if the file exists + if (System.IO.File.Exists(filename) == true) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + if (from != null) + from.SendMessage("Unable to open {0} for loading", filename); + return; + } + + // load the file + XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + + } + else + // check to see if it is a directory + if (System.IO.Directory.Exists(filename) == true) + { + // if so then load all of the .xml files in the directory + string[] files = null; + try + { + files = Directory.GetFiles(filename, "*.xml"); + } + catch { } + if (files != null && files.Length > 0) + { + if (from != null) + from.SendMessage("Loading {0} .xml files from directory {1}", files.Length, filename); + foreach (string file in files) + { + XmlLoadFromFile(file, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + // recursively search subdirectories for more .xml files + string[] dirs = null; + try + { + dirs = Directory.GetDirectories(filename); + } + catch { } + if (dirs != null && dirs.Length > 0) + { + foreach (string dir in dirs) + { + XmlLoadFromFile(dir, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + if (from != null) + from.SendMessage("Loaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + processedmaps = total_processed_maps; + processedspawners = total_processed_spawners; + } + else + { + if (from != null) + from.SendMessage("{0} does not exist", filename); + } + + } + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + + if (from == null) return; + + XmlLoadFromFile(filename, SpawnerPrefix, from, from.Location, from.Map, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + } + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + + XmlLoadFromFile(filename, SpawnerPrefix, null, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + + } + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, bool loadnew, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + + XmlLoadFromFile(filename, SpawnerPrefix, null, Point3D.Zero, Map.Internal, false, 0, loadnew, out processedmaps, out processedspawners); + + } + + + public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners, true); + } + + public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners, bool verbose) + { + + processedmaps = 0; + processedspawners = 0; + + if (fs == null) return; + + // assign an id that will be used to distinguish the newly loaded spawners by appending it to their name + Guid newloadid = Guid.NewGuid(); + + + int TotalCount = 0; + int TrammelCount = 0; + int FeluccaCount = 0; + int IlshenarCount = 0; + int MalasCount = 0; + int TokunoCount = 0; + int OtherCount = 0; + bool questionable_spawner = false; + bool bad_spawner = false; + int badcount = 0; + int questionablecount = 0; + + int failedobjectitemcount = 0; + int failedsetitemcount = 0; + int relativex = -1; + int relativey = -1; + int relativez = 0; + Map relativemap = null; + + if (from != null) + from.SendMessage(string.Format("Loading {0} objects{1} from file {2}.", "XmlSpawner", + ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), filename)); + + // Create the data set + DataSet ds = new DataSet(SpawnDataSetName); + + // Read in the file + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch + { + if (from != null) + from.SendMessage(33, "Error reading xml file {0}", filename); + fileerror = true; + } + // close the file + fs.Close(); + if (fileerror) return; + + // Check that at least a single table was loaded + if (ds.Tables != null && ds.Tables.Count > 0) + { + // Add each spawn point to the current map + if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) + { + // load in the spawner info. Certain fields are required and therefore cannot be ignored + // the exception handler for those will flag bad_spawner and the result will be logged + + // Each row makes up a single spawner + string SpawnName = "Spawner"; + try { SpawnName = (string)dr["Name"]; } + catch { questionable_spawner = true; } + + if (loadnew) + { + // append the new id to the name + SpawnName = String.Format("{0}-{1}", SpawnName, newloadid); + } + + // Check if there is any spawner name criteria specified on the load + if ((SpawnerPrefix == null) || (SpawnerPrefix.Length == 0) || (SpawnName.StartsWith(SpawnerPrefix) == true)) + { + // Try load the GUID (might not work so create a new GUID) + Guid SpawnId = Guid.NewGuid(); + if (!loadnew) + { + try { SpawnId = new Guid((string)dr["UniqueId"]); } + catch { } + } + else + { + // change the dataset guid to the newly created one when new loading + try + { + dr["UniqueId"] = SpawnId; + } + catch { Console.WriteLine("unable to set UniqueId"); } + } + + int SpawnCentreX = fromloc.X; + int SpawnCentreY = fromloc.Y; + int SpawnCentreZ = fromloc.Z; + + try { SpawnCentreX = int.Parse((string)dr["CentreX"]); } + catch { bad_spawner = true; } + try { SpawnCentreY = int.Parse((string)dr["CentreY"]); } + catch { bad_spawner = true; } + try { SpawnCentreZ = int.Parse((string)dr["CentreZ"]); } + catch { bad_spawner = true; } + + int SpawnX = SpawnCentreX; + int SpawnY = SpawnCentreY; + int SpawnWidth = 0; + int SpawnHeight = 0; + try { SpawnX = int.Parse((string)dr["X"]); } + catch { questionable_spawner = true; } + try { SpawnY = int.Parse((string)dr["Y"]); } + catch { questionable_spawner = true; } + try { SpawnWidth = int.Parse((string)dr["Width"]); } + catch { questionable_spawner = true; } + try { SpawnHeight = int.Parse((string)dr["Height"]); } + catch { questionable_spawner = true; } + + // Try load the InContainer (default to false) + bool InContainer = false; + int ContainerX = 0; + int ContainerY = 0; + int ContainerZ = 0; + try { InContainer = bool.Parse((string)dr["InContainer"]); } + catch { } + if (InContainer) + { + try { ContainerX = int.Parse((string)dr["ContainerX"]); } + catch { } + try { ContainerY = int.Parse((string)dr["ContainerY"]); } + catch { } + try { ContainerZ = int.Parse((string)dr["ContainerZ"]); } + catch { } + } + + // Get the map (default to the mobiles map) if the relative distance is too great, then use the defined map + + Map SpawnMap = frommap; + + string XmlMapName = frommap.Name; + + //if(!loadrelative && !loadnew) + { + // Try to get the "map" field, but in case it doesn't exist, catch and discard the exception + try { XmlMapName = (string)dr["Map"]; } + catch { questionable_spawner = true; } + + // Convert the xml map value to a real map object + if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel") + { + SpawnMap = Map.Trammel; + TrammelCount++; + } + else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca") + { + SpawnMap = Map.Felucca; + FeluccaCount++; + } + else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar") + { + SpawnMap = Map.Ilshenar; + IlshenarCount++; + } + else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas") + { + SpawnMap = Map.Malas; + MalasCount++; + } + else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno") + { + SpawnMap = Map.Tokuno; + TokunoCount++; + } + else + { + try + { + SpawnMap = Map.Parse(XmlMapName); + } + catch { } + OtherCount++; + } + } + + // test to see whether the distance between the relative center point and the spawner is too great. If so then dont do relative + if (relativex == -1 && relativey == -1) + { + // the first xml entry in the file will determine the origin + relativex = SpawnCentreX; + relativey = SpawnCentreY; + relativez = SpawnCentreZ; + + // and also the relative map to relocate from + relativemap = SpawnMap; + } + + int SpawnRelZ = 0; + int OrigZ = SpawnCentreZ; + if (loadrelative && (Math.Abs(relativex - SpawnCentreX) <= maxrange) && (Math.Abs(relativey - SpawnCentreY) <= maxrange) + && (SpawnMap == relativemap)) + { + // its within range so shift it + SpawnCentreX -= relativex - fromloc.X; + SpawnCentreY -= relativey - fromloc.Y; + SpawnX -= relativex - fromloc.X; + SpawnY -= relativey - fromloc.Y; + // force it to autosearch for Z when it places it but hold onto relative Z info just in case it can be placed there + SpawnRelZ = relativez - fromloc.Z; + SpawnCentreZ = short.MinValue; + } + + // if relative loading has been specified, see if the loaded map is the same as the relativemap and relocate. + // if it doesnt match then just leave it + if (loadrelative && (relativemap == SpawnMap)) + { + SpawnMap = frommap; + } + + + if (SpawnMap == Map.Internal) bad_spawner = true; + + // Try load the IsRelativeHomeRange (default to true) + bool SpawnIsRelativeHomeRange = true; + try { SpawnIsRelativeHomeRange = bool.Parse((string)dr["IsHomeRangeRelative"]); } + catch { } + + + int SpawnHomeRange = 5; + try { SpawnHomeRange = int.Parse((string)dr["Range"]); } + catch { questionable_spawner = true; } + int SpawnMaxCount = 1; + try { SpawnMaxCount = int.Parse((string)dr["MaxCount"]); } + catch { questionable_spawner = true; } + + //deal with double format for delay. default is the old minute format + bool delay_in_sec = false; + try { delay_in_sec = bool.Parse((string)dr["DelayInSec"]); } + catch { } + TimeSpan SpawnMinDelay = TimeSpan.FromMinutes(5); + TimeSpan SpawnMaxDelay = TimeSpan.FromMinutes(10); + + + if (delay_in_sec) + { + try { SpawnMinDelay = TimeSpan.FromSeconds(int.Parse((string)dr["MinDelay"])); } + catch { } + try { SpawnMaxDelay = TimeSpan.FromSeconds(int.Parse((string)dr["MaxDelay"])); } + catch { } + } + else + { + try { SpawnMinDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MinDelay"])); } + catch { } + try { SpawnMaxDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MaxDelay"])); } + catch { } + } + TimeSpan SpawnMinRefractory = TimeSpan.FromMinutes(0); + try { SpawnMinRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MinRefractory"])); } + catch { } + + TimeSpan SpawnMaxRefractory = TimeSpan.FromMinutes(0); + try { SpawnMaxRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MaxRefractory"])); } + catch { } + + TimeSpan SpawnTODStart = TimeSpan.FromMinutes(0); + try { SpawnTODStart = TimeSpan.FromMinutes(double.Parse((string)dr["TODStart"])); } + catch { } + + TimeSpan SpawnTODEnd = TimeSpan.FromMinutes(0); + try { SpawnTODEnd = TimeSpan.FromMinutes(double.Parse((string)dr["TODEnd"])); } + catch { } + + int todmode = (int)TODModeType.Realtime; + TODModeType SpawnTODMode = TODModeType.Realtime; + try { todmode = int.Parse((string)dr["TODMode"]); } + catch { } + switch ((int)todmode) + { + case (int)TODModeType.Gametime: + SpawnTODMode = TODModeType.Gametime; + break; + case (int)TODModeType.Realtime: + SpawnTODMode = TODModeType.Realtime; + break; + } + + int SpawnKillReset = defKillReset; + try { SpawnKillReset = int.Parse((string)dr["KillReset"]); } + catch { } + + string SpawnProximityMessage = null; + // proximity message + try { SpawnProximityMessage = (string)dr["ProximityTriggerMessage"]; } + catch { } + + string SpawnItemTriggerName = null; + try { SpawnItemTriggerName = (string)dr["ItemTriggerName"]; } + catch { } + + string SpawnNoItemTriggerName = null; + try { SpawnNoItemTriggerName = (string)dr["NoItemTriggerName"]; } + catch { } + + string SpawnSpeechTrigger = null; + try { SpawnSpeechTrigger = (string)dr["SpeechTrigger"]; } + catch { } + + string SpawnSkillTrigger = null; + try { SpawnSkillTrigger = (string)dr["SkillTrigger"]; } + catch { } + + string SpawnMobTriggerName = null; + try { SpawnMobTriggerName = (string)dr["MobTriggerName"]; } + catch { } + string SpawnMobPropertyName = null; + try { SpawnMobPropertyName = (string)dr["MobPropertyName"]; } + catch { } + string SpawnPlayerPropertyName = null; + try { SpawnPlayerPropertyName = (string)dr["PlayerPropertyName"]; } + catch { } + + double SpawnTriggerProbability = 1; + try { SpawnTriggerProbability = double.Parse((string)dr["TriggerProbability"]); } + catch { } + + int SpawnSequentialSpawning = -1; + try { SpawnSequentialSpawning = int.Parse((string)dr["SequentialSpawning"]); } + catch { } + + string SpawnRegionName = null; + try { SpawnRegionName = (string)dr["RegionName"]; } + catch { } + + string SpawnConfigFile = null; + try { SpawnConfigFile = (string)dr["ConfigFile"]; } + catch { } + + bool SpawnAllowGhost = false; + try { SpawnAllowGhost = bool.Parse((string)dr["AllowGhostTriggering"]); } + catch { } + + bool SpawnAllowNPC = false; + try { SpawnAllowNPC = bool.Parse((string)dr["AllowNPCTriggering"]); } + catch { } + + bool SpawnSpawnOnTrigger = false; + try { SpawnSpawnOnTrigger = bool.Parse((string)dr["SpawnOnTrigger"]); } + catch { } + + bool SpawnSmartSpawning = false; + try { SpawnSmartSpawning = bool.Parse((string)dr["SmartSpawning"]); } + catch { } + + string SpawnObjectPropertyName = null; + try { SpawnObjectPropertyName = (string)dr["ObjectPropertyName"]; } + catch { } + + // read in the object proximity target, this will be an object name, so have to do a search + // to find the item in the world. Also have to test for redundancy + string triggerObjectName = null; + try { triggerObjectName = (string)dr["ObjectPropertyItemName"]; } + catch { } + + // read in the target for the set command, this will be an object name, so have to do a search + // to find the item in the world. Also have to test for redundancy + string setObjectName = null; + try { setObjectName = (string)dr["SetPropertyItemName"]; } + catch { } + + // we will assign this during the self-reference resolution pass + Item SpawnSetPropertyItem = null; + + // we will assign this during the self-reference resolution pass + Item SpawnObjectPropertyItem = null; + + // read the duration parameter from the xml file + // but older files wont have it so deal with that condition and set it to the default of "0", i.e. infinite duration + // Try to get the "Duration" field, but in case it doesn't exist, catch and discard the exception + TimeSpan SpawnDuration = TimeSpan.FromMinutes(0); + try { SpawnDuration = TimeSpan.FromMinutes(double.Parse((string)dr["Duration"])); } + catch { } + + TimeSpan SpawnDespawnTime = TimeSpan.FromHours(0); + try { SpawnDespawnTime = TimeSpan.FromHours(double.Parse((string)dr["DespawnTime"])); } + catch { } + int SpawnProximityRange = -1; + // Try to get the "ProximityRange" field, but in case it doesn't exist, catch and discard the exception + try { SpawnProximityRange = int.Parse((string)dr["ProximityRange"]); } + catch { } + + int SpawnProximityTriggerSound = 0; + // Try to get the "ProximityTriggerSound" field, but in case it doesn't exist, catch and discard the exception + try { SpawnProximityTriggerSound = int.Parse((string)dr["ProximityTriggerSound"]); } + catch { } + + int SpawnAmount = 1; + try { SpawnAmount = int.Parse((string)dr["Amount"]); } + catch { } + + bool SpawnExternalTriggering = false; + try { SpawnExternalTriggering = bool.Parse((string)dr["ExternalTriggering"]); } + catch { } + + string waypointstr = null; + try { waypointstr = (string)dr["Waypoint"]; } + catch { } + + WayPoint SpawnWaypoint = GetWaypoint(waypointstr); + + int SpawnTeam = 0; + try { SpawnTeam = int.Parse((string)dr["Team"]); } + catch { questionable_spawner = true; } + bool SpawnIsGroup = false; + try { SpawnIsGroup = bool.Parse((string)dr["IsGroup"]); } + catch { questionable_spawner = true; } + bool SpawnIsRunning = false; + try { SpawnIsRunning = bool.Parse((string)dr["IsRunning"]); } + catch { questionable_spawner = true; } + // try loading the new spawn specifications first + SpawnObject[] Spawns = new SpawnObject[0]; + bool havenew = true; + try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } + catch { havenew = false; } + if (!havenew) + { + // try loading the new spawn specifications + try { Spawns = SpawnObject.LoadSpawnObjectsFromString((string)dr["Objects"]); } + catch { questionable_spawner = true; } + // can only have one of these defined + } + + // do a check on the location of the spawner + if (!IsValidMapLocation(SpawnCentreX, SpawnCentreY, SpawnMap)) + { + if (from != null) + from.SendMessage(33, "Invalid location '{0}' at [{1} {2}] in {3}", + SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName); + bad_spawner = true; + } + + // Check if this spawner already exists + XmlSpawner OldSpawner = null; + bool found_container = false; + bool found_spawner = false; + Container spawn_container = null; + if (!bad_spawner) + { + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner) + { + XmlSpawner CheckXmlSpawner = (XmlSpawner)i; + + // Check if the spawners GUID is the same as the one being loaded + // and that the spawners map is the same as the one being loaded + if ((CheckXmlSpawner.UniqueId == SpawnId.ToString()) + /* && ( CheckXmlSpawner.Map == SpawnMap || loadrelative)*/ ) + { + OldSpawner = (XmlSpawner)i; + found_spawner = true; + } + } + + //look for containers with the spawn coordinates if the incontainer flag is set + if (InContainer && !found_container && (i is Container) && (SpawnCentreX == i.Location.X) && (SpawnCentreY == i.Location.Y) && + (SpawnCentreZ == i.Location.Z || SpawnCentreZ == short.MinValue)) + { + // assume this is the container that the spawner was in + found_container = true; + spawn_container = i as Container; + } + // ok we can break if we have handled both the spawner and any containers + if (found_spawner && (found_container || !InContainer)) + break; + } + } + + // test to see whether the spawner specification was valid, bad, or questionable + if (bad_spawner) + { + badcount++; + if (from != null) + from.SendMessage(33, "Invalid spawner"); + // log it + long fileposition = -1; + try { fileposition = fs.Position; } + catch { } + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", DateTime.Now, fileposition, filename); + op.WriteLine(); + } + } + catch { } + } + else + if (questionable_spawner) + { + questionablecount++; + if (from != null) + from.SendMessage(33, "Questionable spawner '{0}' at [{1} {2}] in {3}", + SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName); + // log it + long fileposition = -1; + try { fileposition = fs.Position; } + catch { } + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", DateTime.Now); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", SpawnCentreX, SpawnCentreY, SpawnCentreZ, XmlMapName, SpawnName, fileposition, filename); + op.WriteLine(); + } + } + catch { } + } + if (!bad_spawner) + { + // Delete the old spawner if it exists + if (OldSpawner != null) + OldSpawner.Delete(); + + // Create the new spawner + XmlSpawner TheSpawn = new XmlSpawner(SpawnId, SpawnX, SpawnY, SpawnWidth, SpawnHeight, SpawnName, SpawnMaxCount, + SpawnMinDelay, SpawnMaxDelay, SpawnDuration, SpawnProximityRange, SpawnProximityTriggerSound, SpawnAmount, + SpawnTeam, SpawnHomeRange, SpawnIsRelativeHomeRange, Spawns, SpawnMinRefractory, SpawnMaxRefractory, SpawnTODStart, + SpawnTODEnd, SpawnObjectPropertyItem, SpawnObjectPropertyName, SpawnProximityMessage, SpawnItemTriggerName, SpawnNoItemTriggerName, + SpawnSpeechTrigger, SpawnMobTriggerName, SpawnMobPropertyName, SpawnPlayerPropertyName, SpawnTriggerProbability, + SpawnSetPropertyItem, SpawnIsGroup, SpawnTODMode, SpawnKillReset, SpawnExternalTriggering, SpawnSequentialSpawning, + SpawnRegionName, SpawnAllowGhost, SpawnAllowNPC, SpawnSpawnOnTrigger, SpawnConfigFile, SpawnDespawnTime, SpawnSkillTrigger, SpawnSmartSpawning, SpawnWaypoint); + //TheSpawn.Group = SpawnIsGroup;\ + + string fromname = null; + if (from != null) fromname = from.Name; + TheSpawn.LastModifiedBy = fromname; + TheSpawn.FirstModifiedBy = fromname; + + // Try to find a valid Z height if required (SpawnCentreZ = short.MinValue) + int NewZ = 0; + + + // Check if relative loading is set. If so then try loading at the z-offset position first with no surface requirement, then try auto + /*if(loadrelative && SpawnMap.CanFit( SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ, SpawnFitSize,true, false,false )) */ + + if (loadrelative && HasTileSurface(SpawnMap, SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ)) + { + + NewZ = OrigZ - SpawnRelZ; + + } + else + + if (SpawnCentreZ == short.MinValue) + { + NewZ = SpawnMap.GetAverageZ(SpawnCentreX, SpawnCentreY); + + + if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ, SpawnFitSize) == false) + { + for (int x = 1; x <= 39; x++) + { + if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ + x, SpawnFitSize)) + { + NewZ += x; + break; + } + } + } + } + else + { + // This spawn point already has a defined Z location, so use it + NewZ = SpawnCentreZ; + } + + // if this is a container held spawner, drop it in the container + if (found_container && (spawn_container != null) && !spawn_container.Deleted) + { + TheSpawn.Location = (new Point3D(ContainerX, ContainerY, ContainerZ)); + spawn_container.AddItem(TheSpawn); + } + else + { + // disable the X_Y adjustments in OnLocationChange + IgnoreLocationChange = true; + TheSpawn.MoveToWorld(new Point3D(SpawnCentreX, SpawnCentreY, NewZ), SpawnMap); + } + + // reset the spawner + TheSpawn.Reset(); + TheSpawn.Running = SpawnIsRunning; + + // update subgroup-specific next spawn times + TheSpawn.NextSpawn = TimeSpan.Zero; + TheSpawn.ResetNextSpawnTimes(); + + + // Send a message to the client that the spawner is created + if (from != null && verbose) + from.SendMessage(188, "Created '{0}' in {1} at {2}", TheSpawn.Name, TheSpawn.Map.Name, TheSpawn.Location.ToString()); + + // Do a total respawn + //TheSpawn.Respawn(); + + // Increment the count + TotalCount++; + } + bad_spawner = false; + questionable_spawner = false; + } + } + + if (from != null) + from.SendMessage("Resolving spawner self references"); + + if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) + { + // Try load the GUID + bool badid = false; + Guid SpawnId = Guid.NewGuid(); + try { SpawnId = new Guid((string)dr["UniqueId"]); } + catch { badid = true; } + if (badid) continue; + // Get the map + Map SpawnMap = frommap; + string XmlMapName = frommap.Name; + + if (!loadrelative) + { + try { XmlMapName = (string)dr["Map"]; } + catch { } + + // Convert the xml map value to a real map object + try + { + SpawnMap = Map.Parse(XmlMapName); + } + catch { } + } + + bool found_spawner = false; + XmlSpawner OldSpawner = null; + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner) + { + XmlSpawner CheckXmlSpawner = (XmlSpawner)i; + + // Check if the spawners GUID is the same as the one being loaded + // and that the spawners map is the same as the one being loaded + if ((CheckXmlSpawner.UniqueId == SpawnId.ToString()) + /* && ( CheckXmlSpawner.Map == SpawnMap || loadrelative) */) + { + OldSpawner = (XmlSpawner)i; + found_spawner = true; + } + } + + if (found_spawner) + break; + } + + if (found_spawner && OldSpawner != null && !OldSpawner.Deleted) + { + // resolve item name references since they may have referred to spawners that were just created + string setObjectName = null; + try { setObjectName = (string)dr["SetPropertyItemName"]; } + catch { } + if (setObjectName != null && setObjectName.Length > 0) + { + // try to parse out the type information if it has also been saved + string[] typeargs = setObjectName.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = setObjectName; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + + // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid + if (loadnew) + { + string tmpsetObjectName = String.Format("{0}-{1}", namestr, newloadid); + OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, tmpsetObjectName, typestr); + } + // if this fails then try the original + if (OldSpawner.m_SetPropertyItem == null) + { + OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr); + } + if (OldSpawner.m_SetPropertyItem == null) + { + failedsetitemcount++; + if (from != null) + from.SendMessage(33, "Failed to initialize SetItemProperty Object '{0}' on ' '{1}' at [{2} {3}] in {4}", + setObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map); + // log it + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Failed SetItemProperty Object initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", + DateTime.Now); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", + setObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); + op.WriteLine(); + } + } + catch { } + } + } + string triggerObjectName = null; + try { triggerObjectName = (string)dr["ObjectPropertyItemName"]; } + catch { } + if (triggerObjectName != null && triggerObjectName.Length > 0) + { + string[] typeargs = triggerObjectName.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = triggerObjectName; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + + // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid + if (loadnew) + { + string tmptriggerObjectName = String.Format("{0}-{1}", namestr, newloadid); + OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, tmptriggerObjectName, typestr); + } + // if this fails then try the original + if (OldSpawner.m_ObjectPropertyItem == null) + { + OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr); + } + if (OldSpawner.m_ObjectPropertyItem == null) + { + failedobjectitemcount++; + if (from != null) + from.SendMessage(33, "Failed to initialize TriggerObject '{0}' on ' '{1}' at [{2} {3}] in {4}", + triggerObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map); + // log it + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Failed TriggerObject initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", + DateTime.Now); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", + triggerObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); + op.WriteLine(); + } + } + catch { } + } + } + } + } + } + + // close the file + try + { + fs.Close(); + } + catch { } + + if (from != null) + from.SendMessage("{0} spawner(s) were created from file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6} Other={7}].", + TotalCount, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount); + if (failedobjectitemcount > 0) + { + if (from != null) + from.SendMessage(33, "Failed to initialize TriggerObjects in {0} spawners. Saved to 'badxml.log'", failedobjectitemcount); + } + if (failedsetitemcount > 0) + { + if (from != null) + from.SendMessage(33, "Failed to initialize SetItemProperty Objects in {0} spawners. Saved to 'badxml.log'", failedsetitemcount); + } + if (badcount > 0) + { + if (from != null) + from.SendMessage(33, "{0} bad spawners detected. Saved to 'badxml.log'", badcount); + } + if (questionablecount > 0) + { + if (from != null) + from.SendMessage(33, "{0} questionable spawners detected. Saved to 'badxml.log'", questionablecount); + } + processedmaps = 1; + processedspawners = TotalCount; + + } + + public static string LocateFile(string filename) + { + bool found = false; + + string dirname = null; + + if (System.IO.Directory.Exists(XmlSpawnDir) == true) + { + // get it from the defaults directory if it exists + dirname = String.Format("{0}/{1}", XmlSpawnDir, filename); + found = System.IO.File.Exists(dirname) || System.IO.Directory.Exists(dirname); + } + + if (!found) + { + // otherwise just get it from the main installation dir + dirname = filename; + } + + return dirname; + } + + [Usage("XmlNewLoad [SpawnerPrefixFilter]")] + [Description("Loads new XmlSpawner objects with new GUIDs (no replacement) into the current map of the player.")] + public static void NewLoad_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0].ToString()); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (load criteria) + if (e.Arguments.Length > 1) + SpawnerPrefix = e.Arguments[1]; + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, true, out processedmaps, out processedspawners); + } + else + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + [Usage("XmlLoad [SpawnerPrefixFilter]")] + [Description("Loads XmlSpawner objects (replacing existing spawners with matching GUIDs) into the proper map as defined in the file supplied.")] + public static void Load_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0].ToString()); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (load criteria) + if (e.Arguments.Length > 1) + SpawnerPrefix = e.Arguments[1]; + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, false, out processedmaps, out processedspawners); + } + else + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + [Usage("XmlNewLoadHere [SpawnerPrefixFilter][-maxrange range]")] + [Description("Loads new XmlSpawner objects with new GUIDs (no replacement) to the current map and location of the player. Spawners beyond maxrange (default=48 tiles) are not moved relative to the player")] + public static void NewLoadHere_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0].ToString()); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + bool badargs = false; + int maxrange = 48; + + // Check if there is an argument provided (load criteria) + try + { + // Check if there is an argument provided (load criteria) + for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) + { + // is it a maxrange option? + if (e.Arguments[nxtarg].ToLower() == "-maxrange") + { + maxrange = int.Parse(e.Arguments[++nxtarg]); + } + else + { + SpawnerPrefix = e.Arguments[nxtarg]; + } + } + } + catch { e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; } + + if (!badargs) + { + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, true, out processedmaps, out processedspawners); + } + } + else + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + [Usage("XmlLoadHere [SpawnerPrefixFilter][-maxrange range]")] + [Description("Loads XmlSpawner objects to the current map and location of the player. Spawners beyond maxrange (default=48 tiles) are not moved relative to the player")] + public static void LoadHere_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0].ToString()); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + bool badargs = false; + int maxrange = 48; + + try + { + // Check if there is an argument provided (load criteria) + for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) + { + // is it a maxrange option? + if (e.Arguments[nxtarg].ToLower() == "-maxrange") + { + maxrange = int.Parse(e.Arguments[++nxtarg]); + } + else + { + SpawnerPrefix = e.Arguments[nxtarg]; + } + } + } + catch { e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; } + + if (!badargs) + { + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, false, out processedmaps, out processedspawners); + } + } + else + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + [Usage("XmlSaveOld [SpawnerPrefixFilter]")] + [Description("Saves all XmlSpawner objects from the current map into the file supplied in the old xmlspawner format.")] + public static void SaveOld_OnCommand(CommandEventArgs e) + { + SaveSpawns(e, false, true); + } + + [Usage("XmlSpawnerSave [SpawnerPrefixFilter]")] + [Description("Saves all XmlSpawner objects from the current map into the file supplied.")] + public static void Save_OnCommand(CommandEventArgs e) + { + SaveSpawns(e, false, false); + } + + [Usage("XmlSpawnerSaveAll [SpawnerPrefixFilter]")] + [Description("Saves ALL XmlSpawner objects from the entire world into the file supplied.")] + public static void SaveAll_OnCommand(CommandEventArgs e) + { + SaveSpawns(e, true, false); + } + + private static void SaveSpawns(CommandEventArgs e, bool SaveAllMaps, bool oldformat) + { + if (e == null || e.Mobile == null || e.Arguments == null || e.Arguments.Length < 1) return; + + if (e.Mobile.AccessLevel < DiskAccessLevel) + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + return; + } + + if (e.Arguments != null && e.Arguments.Length < 1) + { + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + return; + } + + + // Spawner save criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (save criteria) + if (e.Arguments.Length > 1) + SpawnerPrefix = e.Arguments[1]; + + string filename = e.Arguments[0].ToString(); + + string dirname; + if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = String.Format("{0}/{1}", XmlSpawnDir, filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + if (SaveAllMaps == true) + e.Mobile.SendMessage(string.Format("Saving {0} objects{1} to file {2} from {3}.", "XmlSpawner", + ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), dirname, e.Mobile.Map)); + else + e.Mobile.SendMessage(string.Format("Saving {0} obejcts{1} to file {2} from the entire world.", "XmlSpawner", + ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty), dirname)); + + + ArrayList saveslist = new ArrayList(); + + // Add each spawn point to the list + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner && !i.Deleted && ((SaveAllMaps == true) || (i.Map == e.Mobile.Map)) + //check for mob carried spawners and ignore them + && !(i.RootParent is Mobile) + && (SpawnerPrefix == null || (SpawnerPrefix.Length == 0) || (i.Name != null && i.Name.StartsWith(SpawnerPrefix)))) + { + saveslist.Add(i); + } + } + + // save the list + SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, true); + } + + public static bool SaveSpawnList(ArrayList savelist, Stream stream) + { + return SaveSpawnList(null, savelist, null, stream, false, false); + } + + public static bool SaveSpawnList(Mobile from, ArrayList savelist, string dirname, bool oldformat, bool verbose) + { + if (dirname == null || dirname.Length == 0) return false; + + + bool save_ok = true; + System.IO.FileStream fs = null; + + try + { + // Create the FileStream to write with. + fs = new System.IO.FileStream(dirname, System.IO.FileMode.Create); + } + catch + { + if (from != null) + from.SendMessage("Error creating file {0}", dirname); + save_ok = false; + } + + // so far so good + if (save_ok) + { + save_ok = SaveSpawnList(from, savelist, dirname, fs, oldformat, verbose); + } + + if (!save_ok && from != null) + { + from.SendMessage("Unable to complete save operation."); + } + + return save_ok; + } + + + public static bool SaveSpawnList(Mobile from, ArrayList savelist, string dirname, Stream stream, bool oldformat, bool verbose) + { + if (savelist == null || stream == null) return false; + + int TotalCount = 0; + int TrammelCount = 0; + int FeluccaCount = 0; + int IlshenarCount = 0; + int MalasCount = 0; + int TokunoCount = 0; + int OtherCount = 0; + + + // Create the data set + DataSet ds = new DataSet(SpawnDataSetName); + + // Load the data set up + ds.Tables.Add(SpawnTablePointName); + + // Create spawn point schema + ds.Tables[SpawnTablePointName].Columns.Add("Name"); + ds.Tables[SpawnTablePointName].Columns.Add("UniqueId"); + ds.Tables[SpawnTablePointName].Columns.Add("Map"); + ds.Tables[SpawnTablePointName].Columns.Add("X"); + ds.Tables[SpawnTablePointName].Columns.Add("Y"); + ds.Tables[SpawnTablePointName].Columns.Add("Width"); + ds.Tables[SpawnTablePointName].Columns.Add("Height"); + ds.Tables[SpawnTablePointName].Columns.Add("CentreX"); + ds.Tables[SpawnTablePointName].Columns.Add("CentreY"); + ds.Tables[SpawnTablePointName].Columns.Add("CentreZ"); + ds.Tables[SpawnTablePointName].Columns.Add("Range"); + ds.Tables[SpawnTablePointName].Columns.Add("MaxCount"); + ds.Tables[SpawnTablePointName].Columns.Add("MinDelay"); + ds.Tables[SpawnTablePointName].Columns.Add("MaxDelay"); + // deal with the double format for delay. old format stored them as minutes in int format. that meant that short delays were lost + // proper solution would simply be to store as doubles, but older progs still assume int format (like spawneditor) + // so this is the solution. add a flag and do it both ways. + ds.Tables[SpawnTablePointName].Columns.Add("DelayInSec"); + + // add the duration and proximity range and sound parameters, and in container flag and coords inside the container + ds.Tables[SpawnTablePointName].Columns.Add("Duration"); + ds.Tables[SpawnTablePointName].Columns.Add("DespawnTime"); + ds.Tables[SpawnTablePointName].Columns.Add("ProximityRange"); + ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerSound"); + ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerMessage"); + ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyName"); + ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyItemName"); + ds.Tables[SpawnTablePointName].Columns.Add("SetPropertyItemName"); + ds.Tables[SpawnTablePointName].Columns.Add("ItemTriggerName"); + ds.Tables[SpawnTablePointName].Columns.Add("NoItemTriggerName"); + ds.Tables[SpawnTablePointName].Columns.Add("MobTriggerName"); + ds.Tables[SpawnTablePointName].Columns.Add("MobPropertyName"); + ds.Tables[SpawnTablePointName].Columns.Add("PlayerPropertyName"); + ds.Tables[SpawnTablePointName].Columns.Add("TriggerProbability"); + ds.Tables[SpawnTablePointName].Columns.Add("SpeechTrigger"); + ds.Tables[SpawnTablePointName].Columns.Add("SkillTrigger"); + ds.Tables[SpawnTablePointName].Columns.Add("InContainer"); + ds.Tables[SpawnTablePointName].Columns.Add("ContainerX"); + ds.Tables[SpawnTablePointName].Columns.Add("ContainerY"); + ds.Tables[SpawnTablePointName].Columns.Add("ContainerZ"); + ds.Tables[SpawnTablePointName].Columns.Add("MinRefractory"); + ds.Tables[SpawnTablePointName].Columns.Add("MaxRefractory"); + ds.Tables[SpawnTablePointName].Columns.Add("TODStart"); + ds.Tables[SpawnTablePointName].Columns.Add("TODEnd"); + ds.Tables[SpawnTablePointName].Columns.Add("TODMode"); + ds.Tables[SpawnTablePointName].Columns.Add("KillReset"); + ds.Tables[SpawnTablePointName].Columns.Add("ExternalTriggering"); + ds.Tables[SpawnTablePointName].Columns.Add("SequentialSpawning"); + ds.Tables[SpawnTablePointName].Columns.Add("RegionName"); + ds.Tables[SpawnTablePointName].Columns.Add("AllowGhostTriggering"); + ds.Tables[SpawnTablePointName].Columns.Add("AllowNPCTriggering"); + ds.Tables[SpawnTablePointName].Columns.Add("SpawnOnTrigger"); + ds.Tables[SpawnTablePointName].Columns.Add("ConfigFile"); + ds.Tables[SpawnTablePointName].Columns.Add("SmartSpawning"); + + ds.Tables[SpawnTablePointName].Columns.Add("WayPoint"); + ds.Tables[SpawnTablePointName].Columns.Add("Team"); + // amount for stacked item spawns + ds.Tables[SpawnTablePointName].Columns.Add("Amount"); + ds.Tables[SpawnTablePointName].Columns.Add("IsGroup"); + ds.Tables[SpawnTablePointName].Columns.Add("IsRunning"); + ds.Tables[SpawnTablePointName].Columns.Add("IsHomeRangeRelative"); + if (oldformat) + { + ds.Tables[SpawnTablePointName].Columns.Add("Objects"); + } + else + { + ds.Tables[SpawnTablePointName].Columns.Add("Objects2"); + } + + // Add each spawn point to the new table + foreach (XmlSpawner sp in savelist) + { + if (sp == null || sp.Map == null || sp.Deleted) + continue; + + if (verbose && from != null) + // Send a message to the client that the spawner is being saved + from.SendMessage(68, "Saving '{0}' in {1} at {2}", sp.Name, sp.Map.Name, sp.Location.ToString()); + + // Create a new data row + DataRow dr = ds.Tables[SpawnTablePointName].NewRow(); + + // Populate the data + dr["Name"] = (string)sp.Name; + + // Set the unqiue id + dr["UniqueId"] = (string)sp.m_UniqueId; + + // Get the map name + dr["Map"] = (string)sp.Map.Name; + + // Convert the xml map value to a real map object + if (string.Compare(sp.Map.Name, Map.Trammel.Name, true) == 0) + TrammelCount++; + else if (string.Compare(sp.Map.Name, Map.Felucca.Name, true) == 0) + FeluccaCount++; + else if (string.Compare(sp.Map.Name, Map.Ilshenar.Name, true) == 0) + IlshenarCount++; + else if (string.Compare(sp.Map.Name, Map.Malas.Name, true) == 0) + MalasCount++; + else if (string.Compare(sp.Map.Name, Map.Tokuno.Name, true) == 0) + TokunoCount++; + else + OtherCount++; + + dr["X"] = (int)sp.m_X; + dr["Y"] = (int)sp.m_Y; + dr["Width"] = (int)sp.m_Width; + dr["Height"] = (int)sp.m_Height; + + // check to see if this is in a container + if (sp.RootParent is Container) + { + dr["CentreX"] = (int)(((Container)(sp.RootParent)).Location.X); + dr["CentreY"] = (int)(((Container)(sp.RootParent)).Location.Y); + dr["CentreZ"] = (int)(((Container)(sp.RootParent)).Location.Z); + dr["ContainerX"] = (int)(sp.Location.X); + dr["ContainerY"] = (int)(sp.Location.Y); + dr["ContainerZ"] = (int)(sp.Location.Z); + dr["InContainer"] = true; + } + else + { + dr["CentreX"] = (int)sp.Location.X; + dr["CentreY"] = (int)sp.Location.Y; + dr["CentreZ"] = (int)sp.Location.Z; + //dr["ContainerX"] = 0; + //dr["ContainerY"] = 0; + //dr["ContainerZ"] = 0; + dr["InContainer"] = false; + } + dr["Range"] = (int)sp.m_HomeRange; + dr["MaxCount"] = (int)sp.m_Count; + + // need to deal with the fact that the old xmlspawner xml format only saved delays in minutes as ints, so shorter spawn times + // are lost + // flag it then on reading it can be properly handled and still + // maintain backward compatibility with older xml files + if (((int)sp.m_MinDelay.TotalSeconds - 60 * (int)sp.m_MinDelay.TotalMinutes) > 0 || + ((int)sp.m_MaxDelay.TotalSeconds - 60 * (int)sp.m_MaxDelay.TotalMinutes) > 0) + { + dr["DelayInSec"] = true; + dr["MinDelay"] = (int)sp.m_MinDelay.TotalSeconds; + dr["MaxDelay"] = (int)sp.m_MaxDelay.TotalSeconds; + } + else + { + dr["DelayInSec"] = false; + dr["MinDelay"] = (int)sp.m_MinDelay.TotalMinutes; + dr["MaxDelay"] = (int)sp.m_MaxDelay.TotalMinutes; + } + + // additional parameters + dr["TODStart"] = (double)sp.m_TODStart.TotalMinutes; + dr["TODEnd"] = (double)sp.m_TODEnd.TotalMinutes; + dr["TODMode"] = (int)sp.m_TODMode; + dr["KillReset"] = (int)sp.m_KillReset; + dr["MinRefractory"] = (double)sp.m_MinRefractory.TotalMinutes; + dr["MaxRefractory"] = (double)sp.m_MaxRefractory.TotalMinutes; + dr["Duration"] = (double)sp.m_Duration.TotalMinutes; + dr["DespawnTime"] = (double)sp.m_DespawnTime.TotalHours; + dr["ExternalTriggering"] = (bool)sp.m_ExternalTriggering; + + dr["ProximityRange"] = (int)sp.m_ProximityRange; + dr["ProximityTriggerSound"] = (int)sp.m_ProximityTriggerSound; + dr["ProximityTriggerMessage"] = sp.m_ProximityTriggerMessage; + if (sp.m_ObjectPropertyItem != null && !sp.m_ObjectPropertyItem.Deleted) + dr["ObjectPropertyItemName"] = String.Format("{0},{1}", sp.m_ObjectPropertyItem.Name, + sp.m_ObjectPropertyItem.GetType().Name); + else + dr["ObjectPropertyItemName"] = null; + dr["ObjectPropertyName"] = sp.m_ObjectPropertyName; + if (sp.m_SetPropertyItem != null && !sp.m_SetPropertyItem.Deleted) + dr["SetPropertyItemName"] = String.Format("{0},{1}", sp.m_SetPropertyItem.Name, + sp.m_SetPropertyItem.GetType().Name); + else + dr["SetPropertyItemName"] = null; + dr["ItemTriggerName"] = sp.m_ItemTriggerName; + dr["NoItemTriggerName"] = sp.m_NoItemTriggerName; + dr["MobTriggerName"] = sp.m_MobTriggerName; + dr["MobPropertyName"] = sp.m_MobPropertyName; + dr["PlayerPropertyName"] = sp.m_PlayerPropertyName; + dr["TriggerProbability"] = sp.m_TriggerProbability; + dr["SequentialSpawning"] = sp.m_SequentialSpawning; + dr["RegionName"] = sp.m_RegionName; + dr["AllowGhostTriggering"] = sp.m_AllowGhostTriggering; + dr["AllowNPCTriggering"] = sp.m_AllowNPCTriggering; + dr["SpawnOnTrigger"] = sp.m_SpawnOnTrigger; + dr["ConfigFile"] = sp.m_ConfigFile; + dr["SmartSpawning"] = sp.m_SmartSpawning; + + dr["SpeechTrigger"] = sp.m_SpeechTrigger; + dr["SkillTrigger"] = sp.m_SkillTrigger; + dr["Amount"] = (int)sp.m_StackAmount; + dr["Team"] = (int)sp.m_Team; + + // assign the waypoint based on the waypoint name if it deviates from the default waypoint name, otherwise do it by serial + string waystr = null; + if (sp.m_WayPoint != null) + { + if ((sp.m_WayPoint.Name != defwaypointname) && (sp.m_WayPoint.Name != null) && (sp.m_WayPoint.Name.Length > 0)) + { + waystr = sp.m_WayPoint.Name; + } + else + { + waystr = String.Format("SERIAL,{0}", sp.m_WayPoint.Serial); + } + } + dr["WayPoint"] = waystr; + + dr["IsGroup"] = (bool)sp.m_Group; + dr["IsRunning"] = (bool)sp.m_Running; + dr["IsHomeRangeRelative"] = (bool)sp.m_HomeRangeIsRelative; + if (oldformat) + { + dr["Objects"] = (string)sp.GetSerializedObjectList(); + } + else + { + dr["Objects2"] = (string)sp.GetSerializedObjectList2(); + } + + // Add the row the the table + ds.Tables[SpawnTablePointName].Rows.Add(dr); + + // Increment the count + TotalCount++; + } + + + // Write out the file + bool file_error = false; + if (TotalCount > 0) + { + try + { + ds.WriteXml(stream); + } + catch { file_error = true; } + + if (file_error) + { + return false; + } + } + + try + { + stream.Close(); + } + catch { } + // Indicate how many spawners were written + if (from != null) + { + from.SendMessage("{0} spawner(s) were saved to file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].", + TotalCount, dirname, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount); + } + return true; + + } + + private static void WipeSpawners(CommandEventArgs e, bool WipeAll) + { + if (e == null || e.Mobile == null) return; + + if (e.Mobile.AccessLevel >= AccessLevel.Administrator) + { + // Spawner delete criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (delete criteria) + if (e.Arguments != null && e.Arguments.Length > 0) + SpawnerPrefix = e.Arguments[0]; + + if (WipeAll == true) + e.Mobile.SendMessage("Removing ALL XmlSpawner objects from the world{0}.", ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty)); + else + e.Mobile.SendMessage("Removing ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty)); + + // Delete Xml spawner's in the world based on the mobiles current map + int Count = 0; + ArrayList ToDelete = new ArrayList(); + foreach (Item i in World.Items.Values) + { + if ((i is XmlSpawner) && (WipeAll == true || i.Map == e.Mobile.Map) && (i.Deleted == false)) + { + // Check if there is a delete condition + if (SpawnerPrefix == null || (SpawnerPrefix.Length == 0) || (i.Name.StartsWith(SpawnerPrefix))) + { + // Send a message to the client that the spawner is being deleted + e.Mobile.SendMessage(33, "Removing '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString()); + + ToDelete.Add(i); + Count++; + } + } + } + + // Delete the items in the array list + foreach (Item i in ToDelete) + i.Delete(); + + if (WipeAll == true) + e.Mobile.SendMessage("Removed {0} XmlSpawner objects from the world.", Count); + else + e.Mobile.SendMessage("Removed {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + + + [Usage("XmlSpawnerRespawn [SpawnerPrefixFilter]")] + [Description("Respawns all XmlSpawner objects from the current map.")] + public static void Respawn_OnCommand(CommandEventArgs e) + { + RespawnSpawners(e, false); + } + + [Usage("XmlSpawnerRespawnAll [SpawnerPrefixFilter]")] + [Description("Respawns all XmlSpawner objects from the entire world.")] + public static void RespawnAll_OnCommand(CommandEventArgs e) + { + RespawnSpawners(e, true); + } + + private static void RespawnSpawners(CommandEventArgs e, bool RespawnAll) + { + if (e == null || e.Mobile == null) return; + + if (e.Mobile.AccessLevel >= AccessLevel.Administrator) + { + // Spawner Respawn criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (respawn criteria) + if (e.Arguments != null && e.Arguments.Length > 0) + SpawnerPrefix = e.Arguments[0]; + + if (RespawnAll == true) + e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from the world{0}.", ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty)); + else + e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, ((SpawnerPrefix != null && SpawnerPrefix.Length > 0) ? " beginning with " + SpawnerPrefix : string.Empty)); + + // Respawn Xml spawner's in the world based on the mobiles current map + int Count = 0; + ArrayList ToRespawn = new ArrayList(); + foreach (Item i in World.Items.Values) + { + try + { + + if ((i is XmlSpawner) && (RespawnAll == true || i.Map == e.Mobile.Map) && (i.Deleted == false)) + { + // Check if there is a respawn condition + if ((SpawnerPrefix == null) || (SpawnerPrefix.Length == 0) || (i.Name != null && i.Name.StartsWith(SpawnerPrefix))) + { + ToRespawn.Add(i); + Count++; + } + } + } + catch (Exception ex) { Console.WriteLine("Error attempting to add {0}, {1}", i, ex.Message); } + } + // Respawn the items in the array list + foreach (Item i in ToRespawn) + { + + // Send a message to the client that the spawner is being respawned + e.Mobile.SendMessage(33, "Respawning '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString()); + XmlSpawner CheckXmlSpawner = (XmlSpawner)i; + CheckXmlSpawner.Respawn(); + } + + if (RespawnAll == true) + e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from the world.", Count); + else + e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map); + } + else + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + +#if(TRACE) + public static void XmlMake_OnCommand( CommandEventArgs e ) + { + + if( e.Arguments.Length > 0 ){ + int count = 0; + try{ + count = Convert.ToInt32( e.Arguments[0],10); + } catch{} + + for(int i=0;i 2) + { + Spawner x = new Spawner(10,1,1,0,2,e.Arguments[1]); + x.Location = new Point3D(5400+Utility.Random(700),1090+Utility.Random(180),0); + x.Map = Map.Trammel; + } else + if( e.Arguments.Length > 1) + { + XmlSpawner x = new XmlSpawner(10,1,1,0,2,e.Arguments[1]); + x.Location = new Point3D(5400+Utility.Random(700),1090+Utility.Random(180),0); + x.Map = Map.Trammel; + //x.MinDelay = TimeSpan.FromSeconds(1); + //x.MaxDelay = TimeSpan.FromSeconds(1); + //x.ProximityRange = 0; + } + } + if( e.Arguments.Length > 2) + { + e.Mobile.SendMessage( "Created {0} Spawner objects.", count ); + } else { + e.Mobile.SendMessage( "Created {0} XmlSpawner objects.", count ); + } + + + } + } + + public static void XmlTrace_OnCommand( ) + { + XmlTrace_OnCommand( null ); + } + + public static void XmlTrace_OnCommand( CommandEventArgs e ) + { + Process currentprocess = Process.GetCurrentProcess(); + TimeSpan runningtime = DateTime.Now - XmlSpawner._traceStartTime; + double processtime = currentprocess.UserProcessorTime.TotalMilliseconds - _startProcessTime; + double sysload = 0; + + if(runningtime.TotalMilliseconds > 0) + { + sysload = processtime/runningtime.TotalMilliseconds; + } + + Console.WriteLine( "______________"); + Console.WriteLine( "Active Traces:"); + Console.WriteLine( "Running Time = {0}",runningtime); + Console.WriteLine( "Adjusted Process Time = {0:####.####} secs",processtime/1000); + Console.WriteLine( "Processor Time = {0} ({1:p3} avg sys load)",currentprocess.UserProcessorTime,sysload); + + for(int i=0;i 0) + { + double load = 0; + if(processtime > 0) + { + load = ((double)XmlSpawner._traceTotal[i].TotalMilliseconds)/processtime; + } + Console.WriteLine( "{0} ({4}) {1,21} / {2} calls = {3:####.####} ms/call, {5:p3}", + i,XmlSpawner._traceTotal[i], XmlSpawner._traceCount[i],((double)XmlSpawner._traceTotal[i].TotalMilliseconds)/XmlSpawner._traceCount[i], + XmlSpawner._traceName[i], load); + } + } + } + + public static void XmlResetTrace_OnCommand( CommandEventArgs e ) + { + + if( e.Arguments.Length >= 0 ) + { + for(int i=0;i 0)) + Name = name; + else + Name = "Spawner"; + + m_MinDelay = minDelay; + m_MaxDelay = maxDelay; + + // duration and proximity range parameter + m_MinRefractory = minRefractory; + m_MaxRefractory = maxRefractory; + m_TODStart = todstart; + m_TODEnd = todend; + m_TODMode = todMode; + m_KillReset = killReset; + m_Duration = duration; + m_DespawnTime = despawnTime; + m_ProximityRange = proximityRange; + m_ProximityTriggerSound = proximityTriggerSound; + m_proximityActivated = false; + m_durActivated = false; + m_refractActivated = false; + m_Count = maxCount; + m_Team = team; + m_StackAmount = amount; + m_HomeRange = homeRange; + m_HomeRangeIsRelative = isRelativeHomeRange; + m_ObjectPropertyItem = objectPropertyItem; + m_ObjectPropertyName = objectPropertyName; + m_ProximityTriggerMessage = proximityMessage; + m_ItemTriggerName = itemTriggerName; + m_NoItemTriggerName = noitemTriggerName; + m_SpeechTrigger = speechTrigger; + SkillTrigger = skillTrigger; // note this will register the skill as well + m_MobTriggerName = mobTriggerName; + m_MobPropertyName = mobPropertyName; + m_PlayerPropertyName = playerPropertyName; + m_TriggerProbability = triggerProbability; + m_SetPropertyItem = setPropertyItem; + m_ExternalTriggering = externalTriggering; + m_ExternalTrigger = false; + m_SequentialSpawning = sequentialSpawning; + RegionName = regionName; + m_AllowGhostTriggering = allowghost; + m_AllowNPCTriggering = allownpc; + m_SpawnOnTrigger = spawnontrigger; + m_SmartSpawning = smartSpawning; + ConfigFile = configfile; + m_WayPoint = wayPoint; + + // set the totalitem property to -1 so that it doesnt show up in the item count of containers + //TotalItems = -1; + //UpdateTotal(this, TotalType.Items, -1); + + // Create the array of spawned objects + m_SpawnObjects = new ArrayList(); + + // Assign the list of objects to spawn + SpawnObjects = objectsToSpawn; + + // Kick off the process + DoTimer(TimeSpan.FromSeconds(1)); + } + + public XmlSpawner(Serial serial) + : base(serial) + { + } + + #endregion + + #region Defrag methods + + public void Defrag(bool killtest) + { + + if (m_SpawnObjects == null) return; + + bool removed = false; + int total_removed = 0; + + ArrayList deletelist = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + + + if (o is Item) + { + Item item = (Item)o; + bool despawned = false; + // check to see if the despawn time has elapsed. If so, then delete it if it hasnt been picked up or stolen. + if (DespawnTime.TotalHours > 0 && !item.Deleted && (item.LastMoved < DateTime.Now - DespawnTime) && (item.Parent == this.Parent) + && (!ItemFlags.GetTaken(item) || (item.Parent != null && (item.Parent == this.Parent)))) // can despawn if just moved within the same container + { + //item.Delete(); + deletelist.Add(item); + despawned = true; + } + + // Check if the items has been deleted or + // if something else now owns the item (picked it up for example) + // also check the stolen/placed in container flag. If any of those are true then the spawner doesnt own it any more so take it off the list. + // the stolen/container flag prevents spawns from being left on the list when players take them and lock them back down on the ground. + // If you have made the changes to stealing.cs and container.cs described in xmlspawner2.txt then just uncomment the line below to + // enable this check + if (item.Deleted || despawned || (item.Parent != this.Parent) // different container + || (ItemFlags.GetTaken(item) && (item.Parent == null || (item.Parent != this.Parent)))) // taken and in the world, or a different container + { + so.SpawnedObjects.Remove(o); + x--; + removed = true; + // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if + // the object is in the current subgroup before adding to the total + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + total_removed++; + } + else + { + // just add it + total_removed++; + } + } + } + else if (o is Mobile) + { + Mobile m = (Mobile)o; + + // check to see if the spawn has been idle for a long time + // if it has then reposition it because it might be in an inaccessible location + // note, vendors and special cases of positioning from the Spawn method will not get relocated + // i'm not saying I like those special cases, but they should be treated consistently + // doesnt work properly under RunUO 2.0 and also doesnt properly take spawn control keywords into consideration + // when repositioning, so disable this for now + /* + if (SpawnIdleTime > 0 && !m.Deleted && !(m is BaseVendor) && (m.CreationTime < DateTime.Now - TimeSpan.FromHours(SpawnIdleTime)) + && m.Map != null && m.Map != Map.Internal && !m.Map.GetSector(m.Location).Active) + { + // determine whether the requiresurface flag is set + m.Location = GetSpawnPosition(so.RequireSurface, m); + + // and reset the creation time (simulates respawning the identical mob at a new location) + //m.CreationTime = DateTime.Now; + } + * */ + bool despawned = false; + // check to see if the despawn time has elapsed. If so, and the sector is not active then delete it. + if (DespawnTime.TotalHours > 0 && !m.Deleted && (m.CreationTime < DateTime.Now - DespawnTime) + && m.Map != null && m.Map != Map.Internal && !m.Map.GetSector(m.Location).Active) + { + //m.Delete(); + deletelist.Add(m); + despawned = true; + } + + if (m.Deleted || despawned) + { + // Remove the delete mobile from the list + so.SpawnedObjects.Remove(o); + x--; + removed = true; + // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if + // the object is in the current subgroup before adding to the total + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + total_removed++; + } + else + { + // just add it + total_removed++; + } + } + else if (m is BaseCreature) + { + BaseCreature b = (BaseCreature)m; + // Check if the creature has been tamed or previously tamed and released + // and if it is, remove it from the list of spawns + if (b.Controlled || b.IsStabled || (b.Owners != null && b.Owners.Count > 0)) + { + so.SpawnedObjects.Remove(o); + x--; + removed = true; + // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if + // the object is in the current subgroup before adding to the total + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + total_removed++; + } + else + { + // just add it + total_removed++; + } + } + } + } + else + if (o is BaseXmlSpawner.KeywordTag) + { + BaseXmlSpawner.KeywordTag tag = (BaseXmlSpawner.KeywordTag)o; + if (tag.Deleted) + { + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + } + else + { + // Don't know what this is, so remove it + Console.WriteLine("removing unknown {0} from spawnlist", so); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + } + } + + DeleteFromList(deletelist); + + // Check if anything has been removed + if (removed == true) + InvalidateProperties(); + + // increment the killcount based upon the number of items that were removed from the spawnlist (i.e. were spawned but now are gone, presumed killed) + if (killtest) m_killcount += total_removed; + + } + + // special defrag pass to remove GOTO keyword tags + public void ClearGOTOTags() + { + if (m_SpawnObjects == null) return; + + ArrayList ToDelete = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag) + { + BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o; + // clear the tags except for gump and delay tags + if (sot != null && sot.Type == 2) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + } + + } + } + } + + foreach (BaseXmlSpawner.KeywordTag i in ToDelete) + { + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + } + + // special defrag pass to remove spawn object tags, which are placeholders for the special keyword spawn spec entries + public void ClearTags(bool all) + { + if (m_SpawnObjects == null) return; + bool removed = false; + ArrayList ToDelete = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag) + { + BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o; + // clear the tags except for gump and delay tags + if (sot != null && (all || ((sot.Flags & BaseXmlSpawner.KeywordFlags.Defrag) != 0))) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + + } + } + } + + foreach (BaseXmlSpawner.KeywordTag i in ToDelete) + { + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + + // full clear of the taglist + if (all) m_KeywordTagList.Clear(); + + // Check if anything has been removed + if (removed == true) + InvalidateProperties(); + } + + public void DeleteGumpTags() + { + if (m_SpawnObjects == null) return; + bool removed = false; + ArrayList ToDelete = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag) + { + BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o; + // clear the gump tags + if (sot != null && sot.Type == 1) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + + } + } + } + + foreach (BaseXmlSpawner.KeywordTag i in ToDelete) + { + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + + // Check if anything has been removed + if (removed == true) + InvalidateProperties(); + } + + public void DeleteTag(BaseXmlSpawner.KeywordTag tag) + { + if (m_SpawnObjects == null) return; + bool removed = false; + ArrayList ToDelete = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag) + { + BaseXmlSpawner.KeywordTag sot = (BaseXmlSpawner.KeywordTag)o; + // clear the matching tags + if (sot != null && sot == tag) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + + } + } + } + + foreach (BaseXmlSpawner.KeywordTag i in ToDelete) + { + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + + // Check if anything has been removed + if (removed == true) + InvalidateProperties(); + } + + #endregion + + #region SequentialSpawning methods + + private int SubGroupCount(int sgroup) + { + if (m_SpawnObjects == null) return (0); + + int nsub = 0; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[i]; + + if (s.SubGroup == sgroup) + nsub++; + } + + return nsub; + } + + private int RandomAvailableSpawnIndex() + { + // get spawn indices randomly from all available spawns independent of group + return (RandomAvailableSpawnIndex(-1)); + } + + // get spawn indices randomly from all available spawns of a group + private int RandomAvailableSpawnIndex(int sgroup) + { + if (m_SpawnObjects == null) return (-1); + + int maxrange = 0; + List sgrouplist = null; + int totalcount = 0; + // make a pass to determine which subgroups are available for spawning + // by finding any subgroups that do not have available spawns + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[i]; + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue; + + totalcount += s.SpawnedObjects.Count; + if (s.SubGroup > 0 && s.SpawnedObjects.Count >= s.MaxCount) + { + // this subgroup is not available so add it to the list + if (sgrouplist == null) + { + sgrouplist = new List(); + } + sgrouplist.Add(s.SubGroup); + } + } + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[i]; + + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue; + + if ((s.MaxCount > s.SpawnedObjects.Count) && (sgroup < 0 || sgroup == s.SubGroup) + && (sgrouplist == null || !sgrouplist.Contains(s.SubGroup)) && (s.SubGroup <= 0 || SubGroupCount(s.SubGroup) + totalcount <= MaxCount)) + { + // keep track of the number of spawn objects that are not at max (hence available for spawning) + // this will be used to compute the probabilistic weighting function based on the relative + // maxcounts of each entry + maxrange += s.MaxCount; + s.Available = true; + } + else + { + s.Available = false; + } + } + // now generate a random number over the available spawnobjects + // but only if the entire subgroup is available for spawning + // note, subgroup zero is exempt from this check. + if (maxrange > 0) + { + int randindex = Utility.Random(maxrange); + + // and map it into the avail spawns + int currentrange = 0; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[i]; + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue; + + // keep track of the number of spawn objects that are not at max (hence available for spawning) + if (s.Available) + { + // check to see if the random value maps into the range of the current index + if (randindex >= currentrange && randindex < currentrange + s.MaxCount) + { + return (i); + } + + currentrange += s.MaxCount; + } + } + // should never get here + return (-1); + } + else + { + // no spawns are available + return (-1); + } + } + + + // get spawn indices randomly from all available spawns of a group + private int RandomSpawnIndex(int sgroup) + { + if (m_SpawnObjects == null) return (-1); + + int avail = 0; + int maxrange = 0; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[i]; + + // keep track of the number of spawn objects that are not at max (hence available for spawning) + if (sgroup < 0 || (sgroup == s.SubGroup)) + { + avail++; + maxrange += s.MaxCount; + } + } + // now generate a random number over the available spawnobjects + if (avail > 0 && maxrange > 0) + { + int randindex = Utility.Random(maxrange); + + // and map it into the avail spawns + int currentrange = 0; + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[i]; + + // keep track of the number of spawn objects that are not at max (hence available for spawning) + if (sgroup < 0 || (sgroup == s.SubGroup)) + { + if (randindex >= currentrange && randindex < currentrange + s.MaxCount) + return (i); + + currentrange += s.MaxCount; + } + } + // should never get here + return (-1); + } + else + { + // no spawns are available + return (-1); + } + } + + // return the next subgroup in the sequence. + public int NextSequentialIndex(int sgroup) + { + if (m_SpawnObjects == null || m_SpawnObjects.Count == 0) return (0); + + int finddirection = 1; + int largergroup = -1; + + //find the next subgroup that is greater than the current one + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[j]; + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) continue; + + int thisgroup = s.SubGroup; + + // start off by finding a subgroup that is larger + if (finddirection == 1) + { + if (thisgroup > sgroup) + { + largergroup = thisgroup; + + // then work backward to find the group that is less than this but still larger than the current + finddirection = -1; + } + } + else + { + if ((thisgroup > sgroup) && (thisgroup < largergroup)) + { + largergroup = thisgroup; + + finddirection = -1; + } + } + } + + // if couldnt find one larger, then it is time to wraparound + if (largergroup < 0 && sgroup >= 0) + return (NextSequentialIndex(-1)); + else + return (largergroup); + } + + // returns the spawn index of a spawn entry in the current sequential subgroup + public int GetCurrentAvailableSequentialSpawnIndex(int sgroup) + { + if (sgroup < 0) return (-1); + + if (m_SpawnObjects == null) return (-1); + + if (sgroup == 0) return (RandomAvailableSpawnIndex(0)); + + //return the first instance of a spawn object that is an available member of the requested subgroup + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[j]; + + if (s.SubGroup == sgroup && s.MaxCount > s.SpawnedObjects.Count) + { + return (j); + } + } + // failed to find any spawn entry of the requested subgroup + return (-1); + } + + // returns the spawn index of a spawn entry in the current sequential subgroup + public int GetCurrentSequentialSpawnIndex(int sgroup) + { + if (sgroup < 0) return (-1); + + if (m_SpawnObjects == null) return (-1); + + if (sgroup == 0) return (RandomSpawnIndex(0)); + + //return the first instance of a spawn object that is an available member of the requested subgroup + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + if (((SpawnObject)m_SpawnObjects[j]).SubGroup == sgroup) + { + return (j); + } + } + // failed to find any spawn entry of the requested subgroup + return (-1); + } + + private void SeqResetTo(int sgroup) + { + // check the SequentialResetTo on the subgroup + // cant do resets on subgroup 0 + if (sgroup == 0) return; + + // this will get the index of the first spawn entry in the subgroup + // it will have the subgroup timer settings + int spawnindex = GetCurrentSequentialSpawnIndex(sgroup); + + if (spawnindex >= 0) + { + // if it is greater than zero then initiate reset + SpawnObject s = (SpawnObject)m_SpawnObjects[spawnindex]; + m_SequentialSpawning = s.SequentialResetTo; + + InitiateSequentialReset(sgroup); + + // clear the spawns + //RemoveSpawnObjects(); + ClearSubgroup(s.SubGroup); + + // and reset the kill count + KillCount = 0; + } + } + + private bool CheckForSequentialReset() + { + // check the SequentialResetTime on the subgroup + // cant do resets on subgroup 0 + if (m_SequentialSpawning == 0) return false; + + // this will get the index of the first spawn entry in the subgroup + // it will have the subgroup timer settings + int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning); + + if (spawnindex >= 0) + { + // check the reset time on it + SpawnObject s = (SpawnObject)m_SpawnObjects[spawnindex]; + // if it is greater than zero then resetting is possible + if (s.SequentialResetTime > 0) + { + // so check the reset timer + if (NextSeqReset <= TimeSpan.Zero) + { + // it has expired so time to reset + return true; + } + } + } + return false; + } + + private void InitiateSequentialReset(int sgroup) + { + // check the SequentialResetTime on the subgroup + // cant do resets on subgroup 0 + if (sgroup == 0) return; + + // this will get the index of the first spawn entry in the subgroup + // it will have the subgroup timer settings + int spawnindex = GetCurrentSequentialSpawnIndex(sgroup); + + if (spawnindex >= 0) + { + // if it is greater than zero then initiate reset + SpawnObject s = (SpawnObject)m_SpawnObjects[spawnindex]; + NextSeqReset = TimeSpan.FromMinutes(s.SequentialResetTime); + } + } + + + public void ResetSequential() + { + // go back to the lowest level + if (m_SequentialSpawning >= 0) + { + m_SequentialSpawning = NextSequentialIndex(-1); + } + + // reset the nextspawn times + ResetNextSpawnTimes(); + + // and reset the kill count + KillCount = 0; + } + + public bool AdvanceSequential() + { + // check for a sequence hold + + if (HoldSequence) return false; + + // check for triggering + if (!((m_proximityActivated || CanFreeSpawn) && TODInRange)) return false; + + // if kills needed is greater than zero then check the killcount as well + int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning); + + int killsneeded = 0; + int subgroup = -1; + bool clearedobjects = false; + + if (spawnindex >= 0) + { + SpawnObject s = (SpawnObject)m_SpawnObjects[spawnindex]; + subgroup = s.SubGroup; + killsneeded = s.KillsNeeded; + } + + // advance the sequential spawn index if it is enabled and kills needed have been satisfied + if (m_SequentialSpawning >= 0 && (killsneeded == 0 || KillCount >= killsneeded)) + { + m_SequentialSpawning = NextSequentialIndex(m_SequentialSpawning); + + // set the sequential reset based on the current sequence state + // this will be checked in the spawner OnTick to determine whether to Reset the sequential state + InitiateSequentialReset(m_SequentialSpawning); + + // clear the spawns if there is a killcount on the level + if (killsneeded >= 0) + { + ClearSubgroup(subgroup); + clearedobjects = true; + } + + // and reset the kill count + KillCount = 0; + } + + // returning true will indicate that all spawns have been cleared and therefore a new spawn can be initiated in the same OnTick + return (clearedobjects); + } + #endregion + + #region Spawn methods + + int killcount_held = 0; + + public void OnTick() + { + _TraceStart(8); + // start up the timer again for the next Ontick + DoTimer(); + + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + + // if regional spawning is enabled, update the region in case new regions were added after the initialization pass + CheckRegionAssignment = true; + + // reset the killcount whenever a spawntick goes by in which it could have spawned, ie the spawner is full, or proximity triggered + // spawns were not activated. Note that killcount gets incremented within Defrag whenever a spawn is that had been generated is removed from the active list. + // Check the count before and then after the spawn passes. + // if the spawner is still refractory then dont do a reset of the killcount. + //int startcount = this.m_killcount; + int startcount = killcount_held; + if (!m_skipped) + { + killcount_held = m_killcount; + } + + // killcount will be updated in Defrag + Defrag(true); + + // remove any keyword tags that were made + // note, tags only last a single ontick except for WAIT type + ClearTags(false); + + if (startcount == m_killcount && !m_refractActivated && !m_skipped) + { + m_spawncheck--; + } + m_skipped = false; + + // allow for some slack in the killcount reset by resetting after a certain number of spawn ticks without kills pass + if (m_spawncheck <= 0) + { + m_killcount = 0; + m_spawncheck = m_KillReset; // wait for 1 spawn ticks to pass before resetting. This can be set to anything you like + } + + // check for smart spawning + if (SmartSpawning && IsFull && !HasActiveSectors && !HasDamagedOrDistantSpawns /*&& !HasHoldSmartSpawning */ ) + { + IsInactivated = true; + // for multiple sector spawning ranges use the sector timer, otherwise just rely on OnSectorActivate to detect sector activation + //if(!UseSectorActivate) + //DoSectorTimer(TimeSpan.FromSeconds(1)); + + SmartRemoveSpawnObjects(); + + } + + // dont process spawn ticks while inactivated if smart spawning is enabled + if (SmartSpawning && IsInactivated) + { + _TraceEnd(8); + return; + } + + IsInactivated = false; + + // check to see if spawning is on hold due to a WAIT keyword + if (!OnHold) + { + // look for triggers that are not player activated. + if (m_ProximityRange == -1 && CanSpawn) + { + CheckTriggers((Mobile)null, null, false); + } + + // check for proximity triggers without movement activation + if (m_ProximityRange >= 0 && CanSpawn) + { + // check all nearby players + foreach (Mobile p in GetMobilesInRange(m_ProximityRange)) + { + if (ValidPlayerTrig(p)) + CheckTriggers(p, null, true); + } + } + + if (m_Group == true) + { + // check the seq reset time on the current subgroup + // if the reset time is greater than zero then check the timer + // if it has expired then reset the sequential subgroup + // only do this if it can actually spawn + if (CheckForSequentialReset()) + { + // it has expired so reset the sequential spawn level + SeqResetTo(m_SequentialSpawning); + + bool triedtospawn = Respawn(); + + if (triedtospawn) ClearGOTOTags(); + + // dont advance if the spawn isnt triggered after resetting + if (!triedtospawn) HoldSequence = true; + + + } + else + if (TotalSpawnedObjects <= 0) + { + + // advance the sequential spawn index if it is enabled + AdvanceSequential(); + + //bool hadhold = HoldSequence; + + //HoldSequence = false; + + bool triedtospawn = Respawn(); + + if (triedtospawn) ClearGOTOTags(); + + //if(!triedtospawn) HoldSequence = hadhold; + } + } + else + { + + if (CheckForSequentialReset()) + { + // it has expired so reset the sequential spawn level + SeqResetTo(m_SequentialSpawning); + + // dont advance if the spawn isnt triggered after resetting + HoldSequence = true; + } + else + { + // advance the sequence before spawning + AdvanceSequential(); + } + + // keep track of the hold flag before trying to spawn in case no spawn attempt is made + //bool hadhold = HoldSequence; + + // clear the hold flag to see if any of the spawned entries try to set it + //HoldSequence = false; + + // try to spawn. If spawning conditions such as triggering or TOD are not met, then it returns false + bool triedtospawn = Spawn(false); + + if (triedtospawn) ClearGOTOTags(); + // this will maintain any sequential holds if spawning was suppressed due to triggering + // if nothing was spawned or triggered, then restore the hold status to previous state + //if(!triedtospawn) HoldSequence = hadhold; + + if (!FreeRun) + { + m_mob_who_triggered = null; + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + } + + } + + // remove any keyword tags that were made except for WAIT type + ClearTags(false); + + + // and clear triggering flags + if (!OnHold && !FreeRun) + { + m_proximityActivated = false; + } + } + + if (FreeRun && SpawnOnTrigger && m_proximityActivated) + { + // if it is in free run and was triggered, then just keep spawning as though it was triggered immediately + NextSpawn = TimeSpan.Zero; + ResetNextSpawnTimes(); + } + + + //this.m_ExternalTrigger = false; + // if it is out of the TOD range then delete the spawns + if (!TODInRange) + { + RemoveSpawnObjects(); + + ResetAllFlags(); + } + _TraceEnd(8); + + } + + public bool ClearSpawnedThisTick + { + set + { + if (m_SpawnObjects == null || value == false) return; + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject sobj = (SpawnObject)m_SpawnObjects[i]; + if (sobj != null) + { + sobj.SpawnedThisTick = false; + } + } + } + + } + + // select and spawn something + // return false if it cannot spawn, e.g. there is nothing to spawn or it is a triggerable spawner and has not been triggered + public bool Spawn(bool smartspawn) + { + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0 && (m_proximityActivated || CanFreeSpawn) && TODInRange) + { + + m_HoldSequence = false; + + // if the spawner is full then dont bother + if (IsFull) + { + ResetProximityActivated(); + return (true); + } + + // Pick a spawn object to spawn + int SpawnIndex = 0; + + // see if sequential spawning has been selected + if (m_SequentialSpawning >= 0) + { + // if so then use its value to get the index of the first available spawn entry in the next subgroup to be spawned + // note, if the current sequence finds a zero group then the spawn will be picked at random from it + SpawnIndex = GetCurrentAvailableSequentialSpawnIndex(m_SequentialSpawning); + } + else + { + // if sequential spawning is not set then select the next spawn at random + SpawnIndex = RandomAvailableSpawnIndex(); + } + + // no spawns are available so no point in continuing + if (SpawnIndex < 0) + { + ResetProximityActivated(); + return (true); + } + + SpawnObject sobj = (SpawnObject)m_SpawnObjects[SpawnIndex]; + int sgroup = sobj.SubGroup; + + // if this is part of a non-zero group, then spawn all of the group members as well + if (sgroup != 0) + { + SpawnSubGroup(sgroup, smartspawn); + + /* + for( int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[j]; + + if(so.SubGroup == sgroup) + { + // get the SpawnsPerTick count and spawn up to that number + bool success = Spawn( j, smartspawn, so.SpawnsPerTick ); + + if(success && !smartspawn) + RefreshNextSpawnTime(so); + } + } + */ + } + else + { + // Found a valid spawn object so spawn it and see if it successful + if (Spawn(SpawnIndex, smartspawn, sobj.SpawnsPerTick) == true) + { + if (!smartspawn) + RefreshNextSpawnTime(sobj); + } + } + + ResetProximityActivated(); + return (true); + } + ResetProximityActivated(); + return (false); + } + + // spawn an individual entry by index up to count times + public bool Spawn(int index, bool smartspawn, int count, int packrange, Point3D packcoord, bool ignoreloopprotection) + { + if (m_SpawnObjects == null || index >= m_SpawnObjects.Count) return false; + + bool didspawn = false; + + SpawnObject so = (SpawnObject)m_SpawnObjects[index]; + + if (so == null) return false; + + Defrag(false); + + // make sure you dont go over the individual entry maxcount + int somax = so.MaxCount; + int socnt = so.SpawnedObjects.Count; + int nspawn = so.SpawnsPerTick; + int scnt = SafeCurrentCount; + + for (int k = 0; (k < nspawn) && (k + socnt < somax) && (k + scnt < MaxCount); k++) + { + if (packrange >= 0 && so.SubGroup > 0 && packcoord == Point3D.Zero) + { + packcoord = GetPackCoord(so.SubGroup); + } + if (Spawn(index, smartspawn, packrange, packcoord, ignoreloopprotection)) + { + // if any of the attempts were successful then flag it as having spawned + didspawn = true; + } + } + + return didspawn; + } + + // spawn an individual entry by index up to count times + public bool Spawn(int index, bool smartspawn, int count) + { + return Spawn(index, smartspawn, count, false); + } + + // spawn an individual entry by index up to count times + public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection) + { + return Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection); + } + + // spawn an individual entry by spawn object + public void Spawn(string SpawnObjectTypeName, bool smartspawn, int packrange, Point3D packcoord) + { + if (m_SpawnObjects == null) return; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + if (((SpawnObject)m_SpawnObjects[i]).TypeName.ToUpper() == SpawnObjectTypeName.ToUpper()) + { + + if (Spawn(i, smartspawn, packrange, packcoord)) + { + RefreshNextSpawnTime((SpawnObject)m_SpawnObjects[i]); + } + break; + } + else + { + + } + } + } + + // spawn an individual entry by index + public void Spawn(string SpawnObjectTypeName, bool smartspawn) + { + Spawn(SpawnObjectTypeName, smartspawn, -1, Point3D.Zero); + } + + // spawn an individual entry by index + public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord) + { + return Spawn(index, smartspawn, packrange, packcoord, false); + } + + // spawn an individual entry by index + public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, bool ignoreloopprotection) + { + + Map map = this.Map; + + // Make sure everything is ok to spawn an object + if ((map == null) || + (map == Map.Internal) || + (m_SpawnObjects == null) || + (m_SpawnObjects.Count == 0) || + (index < 0) || + (index >= m_SpawnObjects.Count) + ) + return false; + + // Remove any spawns that don't belong to the spawner any more. + Defrag(false); + + // Get the spawn object at the required index + SpawnObject TheSpawn = m_SpawnObjects[index] as SpawnObject; + + // Check if the object retrieved is a valid SpawnObject + if (TheSpawn != null) + { + // dont allow an entry to be spawned more than once per tick + // this protects against runaway recursive looping + if (TheSpawn.SpawnedThisTick && !ignoreloopprotection) return false; + + // check the nextspawn time to see if it is available + if (TheSpawn.NextSpawn > DateTime.Now) + return false; + + int CurrentCreatureMax = TheSpawn.MaxCount; + int CurrentCreatureCount = TheSpawn.SpawnedObjects.Count; + + // Check that the current object to be spawned has not reached its maximum allowed + // and make sure that the maximum spawner count has not been exceeded as well + if ((CurrentCreatureCount >= CurrentCreatureMax) || + (TotalSpawnedObjects >= m_Count)) + { + return false; + } + + // check for string substitions + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(this, this, m_mob_who_triggered, TheSpawn.TypeName); + + // random positioning is the default + List spawnpositioning = null; + + // require valid surfaces by default + bool requiresurface = true; + + // parse the # function specification for the entry + while (substitutedtypeName.StartsWith("#")) + { + string[] args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2); + + if (args.Length > 0) + { + if (spawnpositioning == null) + { + spawnpositioning = new List(); + } + // parse any comma args + string[] keyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 10); + + if (keyvalueargs.Length > 0) + { + + switch (keyvalueargs[0]) + { + case "#NOTILES": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, m_mob_who_triggered, keyvalueargs)); + break; + case "#TILES": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, m_mob_who_triggered, keyvalueargs)); + break; + case "#WET": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, m_mob_who_triggered, keyvalueargs)); + break; + case "#XFILL": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, m_mob_who_triggered, keyvalueargs)); + break; + case "#YFILL": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, m_mob_who_triggered, keyvalueargs)); + break; + case "#EDGE": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, m_mob_who_triggered, keyvalueargs)); + break; + case "#PLAYER": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, m_mob_who_triggered, keyvalueargs)); + break; + case "#WAYPOINT": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, m_mob_who_triggered, keyvalueargs)); + break; + case "#RELXY": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, m_mob_who_triggered, keyvalueargs)); + break; + case "#DXY": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, m_mob_who_triggered, keyvalueargs)); + break; + case "#XY": + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, m_mob_who_triggered, keyvalueargs)); + break; + case "#CONDITION": + // test the specified condition string + // syntax is #CONDITION,proptest + // reparse with only one arg after the comma, this allows property tests that use commas as well + string[] ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2); + if (ckeyvalueargs.Length > 1) + { + // dont spawn if it fails the test + if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], m_mob_who_triggered, out this.status_str)) return false; + + } + else + { + this.status_str = "invalid #CONDITION specification: " + args[0]; + } + break; + default: + this.status_str = "invalid # specification: " + args[0]; + break; + } + } + } + + // get the rest of the spawn entry + if (args.Length > 1) + { + substitutedtypeName = args[1].Trim(); + } + else + { + substitutedtypeName = String.Empty; + } + } + + + if (substitutedtypeName.StartsWith("*")) + { + requiresurface = false; + substitutedtypeName = substitutedtypeName.TrimStart('*'); + } + + TheSpawn.RequireSurface = requiresurface; + + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + string status_str = null; + + bool completedtypespawn = BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, requiresurface, spawnpositioning, + m_mob_who_triggered, this.Location, this.Map, new XmlGumpCallback(SpawnerGumpCallback), out status_str); + + if (status_str != null) + { + this.status_str = status_str; + } + + if (completedtypespawn) + { + // successfully spawned the keyword + // note that returning true means that Spawn will assume that it worked and will not try to respawn something else + // added the duration timer that begins on spawning + DoTimer2(m_Duration); + + InvalidateProperties(); + + return true; + } + else + { + return false; + } + } + else + { + + // its a regular type descriptor so find out what it is + Type type = null; + if (typeName != null) + { + type = SpawnerType.GetType(typeName); + } + + // dont try to spawn invalid types, or Mobile type spawns in containers + if (type != null && !(this.Parent != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile))))) + { + + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + + object o = CreateObject(type, arglist[0]); + + if (o == null) + { + this.status_str = "invalid type specification: " + arglist[0]; + return true; + } + try + { + if (o is Mobile) + { + // if this is in any container such as a pack the xyz values are invalid as map coords so dont spawn the mob + if (this.Parent is Container) + { + ((Mobile)o).Delete(); + + return true; + } + + Mobile m = (Mobile)o; + + // add the mobile to the spawned list + TheSpawn.SpawnedObjects.Add(m); + + m.Spawner = this; + + Point3D loc; + + /* + if( ( m is BaseVendor ) && + ( this.Map.CanFit( this.Location, SpawnFitSize, true, false ) == true ) ) + { + loc = this.Location; + } + else + { + loc = GetSpawnPosition(requiresurface); + } + */ + loc = GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, m); + + if (!smartspawn) + { + m.OnBeforeSpawn(loc, map); + } + + m.MoveToWorld(loc, map); + + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + c.RangeHome = m_HomeRange; + c.CurrentWayPoint = m_WayPoint; + + if (m_Team > 0) + c.Team = m_Team; + + // Check if this spawner uses absolute (from spawnER location) + // or relative (from spawnED location) as the mobiles home point + if (m_HomeRangeIsRelative == true) + c.Home = m.Location; // Mobiles spawned location is the home point + else + c.Home = this.Location; // Spawners location is the home point + } + + // if the object has an OnSpawned method, then invoke it + if (!smartspawn) + { + m.OnAfterSpawn(); + } + + // apply the parsed arguments from the typestring using setcommand + // be sure to do this after setting map and location so that errors dont place the mob on the internal map + string status_str; + + BaseXmlSpawner.ApplyObjectStringProperties(this, substitutedtypeName, m, m_mob_who_triggered, this, out status_str); + + // if the object has an OnAfterSpawnAndModify method, then invoke it + //BaseXmlSpawner.InvokeOnAfterSpawnAndModify(o); + + if (status_str != null) + { + this.status_str = status_str; + } + + InvalidateProperties(); + + // added the duration timer that begins on spawning + DoTimer2(m_Duration); + + return true; + } + else if (o is Item) + { + Item item = (Item)o; + + string status_str; + + BaseXmlSpawner.AddSpawnItem(this, TheSpawn, item, this.Location, map, m_mob_who_triggered, requiresurface, spawnpositioning, substitutedtypeName, smartspawn, out status_str); + + if (status_str != null) + { + this.status_str = status_str; + } + + InvalidateProperties(); + + // added the duration timer that begins on spawning + DoTimer2(m_Duration); + + return true; + } + } + catch (Exception ex) { Console.WriteLine("When spawning {0}, {1}", o, ex); } + } + else + { + this.status_str = "invalid type specification: " + typeName; + return true; + } + } + } + return false; + } + + public bool SpawnSubGroup(int sgroup) + { + return SpawnSubGroup(sgroup, false); + } + + public bool SpawnSubGroup(int sgroup, bool smartspawn) + { + return SpawnSubGroup(sgroup, false, false); + } + + public bool SpawnSubGroup(int sgroup, bool smartspawn, bool ignoreloopprotection) + { + if (m_SpawnObjects == null) return false; + + if (sgroup >= 0) + { + bool didspawn = false; + Point3D packcoord = Point3D.Zero; + + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[j]; + + if (so != null && so.SubGroup == sgroup) + { + + // find the first subgroup spawn to determine the packspawning reference coordinates + if (so.PackRange >= 0 && packcoord == Point3D.Zero) + { + packcoord = GetPackCoord(sgroup); + } + + // get the SpawnsPerTick count and spawn up to that number + bool success = Spawn(j, smartspawn, so.SpawnsPerTick, so.PackRange, packcoord, ignoreloopprotection); + + if (success) didspawn = true; + + if (success && !smartspawn) + RefreshNextSpawnTime(so); + + } + } + + // success if any of the subgroup spawned + if (didspawn) + { + return (true); + } + } + return (false); + } + + #endregion + + #region Spawn support methods + + public Point3D GetPackCoord(int sgroup) + { + Point3D packcoord = Point3D.Zero; + + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[j]; + + if (so != null && so.SubGroup == sgroup && so.SpawnedObjects.Count > 0 && so.PackRange >= 0) + { + // if pack spawning is enabled for this subgroup, then get the + // the origin for pack spawning using the first existing pack spawn + // in the subgroup + + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + if (o is Item) + { + return ((Item)o).Location; + } + else + if (o is Mobile) + { + return ((Mobile)o).Location; + } + } + } + } + + return Point3D.Zero; + } + + + //used by the reset button in the gump + public void ResetAllFlags() + { + m_proximityActivated = false; + m_ExternalTrigger = false; + m_durActivated = false; + m_refractActivated = false; + m_mob_who_triggered = null; + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + m_killcount = 0; + m_GumpState = null; + FreeRun = false; + } + + public bool BringHome + { + set { if (value) BringToHome(); } + } + + public void BringToHome() + { + if (m_SpawnObjects == null) return; + Defrag(false); + + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Mobile) + { + Mobile m = (Mobile)o; + + m.Map = Map; + m.Location = new Point3D(Location); + } + else if (o is Item) + { + Item item = (Item)o; + + item.MoveToWorld(Location, Map); + } + } + } + } + + public bool CheckRegionAssignment + { + get { return false; } + set + { + if (value == true) + { + // see if a region definition needs updating + if (m_Region == null && m_RegionName != null && RegionName != string.Empty) + { + RegionName = RegionName; + + if (SpawnRegion != null) + { + // clear the status if successful + status_str = null; + } + } + } + } + } + + public void Start() + { + + if (m_Running == false) + { + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + m_Running = true; + DoTimer(); + } + } + } + + + public void Stop() + { + + if (m_Running == true) + { + // turn off all timers + if (m_Timer != null) + m_Timer.Stop(); + if (m_DurTimer != null) + m_DurTimer.Stop(); + if (m_RefractoryTimer != null) + m_RefractoryTimer.Stop(); + m_Running = false; + m_proximityActivated = false; + m_ExternalTrigger = false; + m_mob_who_triggered = null; + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + } + } + + public void Reset() + { + Stop(); + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + RemoveSpawnObjects(); + ClearTags(true); + ResetAllFlags(); + status_str = ""; + m_killcount = 0; + OnHold = false; + mostRecentSpawnPosition = Point3D.Zero; + spawnPositionWayTable = null; + // dont advance before the next spawn + HoldSequence = true; + IsInactivated = false; + ResetSequential(); + } + + public bool Respawn() + { + inrespawn = true; + IsInactivated = false; + + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + + // Delete all currently spawned objects + RemoveSpawnObjects(); + + // added the explicit start. Previously it relied on the automatic start that occurred when the spawnobject list was updated. + Start(); + + ResetNextSpawnTimes(); + + // Respawn all objects up to the spawners current maximum allowed + // note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all + bool keepProximityActivated = m_proximityActivated; + + bool triedtospawn = false; + + // attempt to spawn up to the MaxCount of the spawner + for (int x = 0; x < m_Count; x++) + { + if (Spawn(false)) triedtospawn = true; + + if (x < m_Count - 1 || OnHold) m_proximityActivated = keepProximityActivated; + } + if (!FreeRun) + { + m_mob_who_triggered = null; + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + } + + ClearTags(true); + + + inrespawn = false; + + return triedtospawn; + } + + // used to optimize smartspawning use of hasholdsmartspawning + public void SmartRespawn() + { + + inrespawn = true; + IsInactivated = false; + + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + + // Delete all currently spawned objects + SmartRemoveSpawnObjects(); + + // added the explicit start. Previously it relied on the automatic start that occurred when the spawnobject list was updated. + Start(); + + ResetNextSpawnTimes(); + + // Respawn all objects up to the spawners current maximum allowed + // note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all + bool keepProximityActivated = m_proximityActivated; + + // attempt to spawn up to the MaxCount of the spawner + for (int x = 0; x < m_Count; x++) + { + Spawn(true); + + if (x < m_Count - 1 || OnHold) m_proximityActivated = keepProximityActivated; + } + + if (!FreeRun) + { + m_mob_who_triggered = null; + m_skill_that_triggered = XmlSpawnerSkillCheck.RegisteredSkill.Invalid; + } + + ClearTags(true); + + inrespawn = false; + } + + + public void SortSpawns() + { + if (m_SpawnObjects == null) return; + + // establish the entry order + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + { + so.EntryOrder = count++; + } + + m_SpawnObjects.Sort(new SubgroupSorter()); + } + + private class SubgroupSorter : IComparer + { + public int Compare(object x, object y) + { + SpawnObject a = x as SpawnObject; + SpawnObject b = y as SpawnObject; + if (a.SubGroup == b.SubGroup) + { + // use the entry order as the secondary sort factor + return a.EntryOrder - b.EntryOrder; + } + else + return a.SubGroup - b.SubGroup; + } + } + + + public static SpawnObject GetSpawnObject(XmlSpawner spawner, int sgroup) + { + if (spawner == null || spawner.m_SpawnObjects == null) return (null); + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + // find the first entry with matching subgroup id + if (((SpawnObject)spawner.m_SpawnObjects[i]).SubGroup == sgroup) + { + return (SpawnObject)spawner.m_SpawnObjects[i]; + } + } + return null; + } + + + public static object GetSpawned(XmlSpawner spawner, int sgroup) + { + if (spawner == null || spawner.m_SpawnObjects == null) return (null); + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + // find the first entry with matching subgroup id + if (((SpawnObject)spawner.m_SpawnObjects[i]).SubGroup == sgroup) + { + // find the first spawned object in the entry + if (((SpawnObject)spawner.m_SpawnObjects[i]).SpawnedObjects.Count > 0) + { + return ((SpawnObject)spawner.m_SpawnObjects[i]).SpawnedObjects[0]; + } + } + } + return null; + } + + public static ArrayList GetSpawnedList(XmlSpawner spawner, int sgroup) + { + ArrayList newlist = new ArrayList(); + + if (spawner == null || spawner.m_SpawnObjects == null) return (null); + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + // find the first entry with matching subgroup id + if (((SpawnObject)spawner.m_SpawnObjects[i]).SubGroup == sgroup) + { + // find the first spawned object in the entry + + if (((SpawnObject)spawner.m_SpawnObjects[i]).SpawnedObjects.Count > 0) + { + for (int j = 0; j < ((SpawnObject)spawner.m_SpawnObjects[i]).SpawnedObjects.Count; j++) + newlist.Add(((SpawnObject)spawner.m_SpawnObjects[i]).SpawnedObjects[j]); + } + } + } + return newlist; + } + + + public bool HasSubGroups() + { + if (m_SpawnObjects == null) return (false); + + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + if (((SpawnObject)m_SpawnObjects[j]).SubGroup > 0) return true; + } + + return false; + } + + private void ResetProximityActivated() + { + // dont reset triggering if free run mode has been selected + if (!FreeRun) + { + m_proximityActivated = false; + } + } + + private void RefreshNextSpawnTimes() + { + + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject so = m_SpawnObjects[i] as SpawnObject; + + RefreshNextSpawnTime(so); + } + } + } + + public bool HasIndividualSpawnTimes() + { + + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject so = m_SpawnObjects[i] as SpawnObject; + + if (so.MinDelay != -1 || so.MaxDelay != -1) return true; + } + } + return false; + } + + private void ResetNextSpawnTimes() + { + + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject so = m_SpawnObjects[i] as SpawnObject; + + so.NextSpawn = DateTime.Now; + } + } + } + + public void RefreshNextSpawnTime(SpawnObject so) + { + if (so == null) return; + + int mind = (int)(so.MinDelay * 60); + int maxd = (int)(so.MaxDelay * 60); + if (mind < 0 || maxd < 0) + { + so.NextSpawn = DateTime.Now; + } + else + { + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(mind, maxd)); + + so.NextSpawn = DateTime.Now + delay; + } + + } + + + public static bool IsValidMapLocation(int X, int Y, Map map) + { + if (map == null || map == Map.Internal) return false; + // check the location relative to the current map to make sure it is valid + if (X < 0 || X > map.Width || Y < 0 || Y > map.Height) + { + return false; + } + return true; + } + public static bool IsValidMapLocation(Point3D location, Map map) + { + if (map == null || map == Map.Internal) return false; + // check the location relative to the current map to make sure it is valid + if (location.X < 0 || location.X > map.Width || location.Y < 0 || location.Y > map.Height) + { + return false; + } + return true; + } + public static bool IsValidMapLocation(Point2D location, Map map) + { + if (map == null || map == Map.Internal) return false; + // check the location relative to the current map to make sure it is valid + if (location.X < 0 || location.X > map.Width || location.Y < 0 || location.Y > map.Height) + { + return false; + } + return true; + } + + private static WayPoint GetWaypoint(string waypointstr) + { + WayPoint waypoint = null; + + // try parsing the waypoint name to determine the waypoint. object syntax is "SERIAL,sernumber" or "waypointname" + if (waypointstr != null && waypointstr.Length > 0) + { + string[] wayargs = BaseXmlSpawner.ParseString(waypointstr, 2, ","); + if (wayargs != null && wayargs.Length > 0) + { + // is this a SERIAL specification? + if (wayargs[0] == "SERIAL") + { + + // look it up by serial + if (wayargs.Length > 1) + { + int sernum = -1; + try { sernum = (int)Convert.ToUInt64(wayargs[1].Substring(2), 16); } + catch { } + + if (sernum > -1) + { + IEntity e = World.FindEntity(sernum); + + if (e is WayPoint) + waypoint = e as WayPoint; + + } + } + else + { + // improper serial format + } + } + else + { + // just look it up by name + Item wayitem = BaseXmlSpawner.FindItemByName(null, wayargs[0], "WayPoint"); + if (wayitem is WayPoint) + { + waypoint = wayitem as WayPoint; + } + } + } + } + + return waypoint; + } + + private static bool HasTileSurface(Map map, int X, int Y, int Z) + { + if (map == null) return false; +#if(RUNUO2RC1) + ArrayList tiles = map.GetTilesAt(new Point2D(X, Y), true, true, true); +#else + StaticTile[] tiles = map.Tiles.GetStaticTiles(X, Y, true); + //List tiles = map.GetTilesAt(new Point2D(X, Y), true, true, true); +#endif + if (tiles == null) return false; + + // go through the tiles and see if any are at the Z location + foreach (object o in tiles) + { + + if (o is StaticTile) + { + StaticTile i = (StaticTile)o; + + if ((i.Z + i.Height) == Z) + { + return true; + } + } + } + + return false; + } + + private bool CheckHoldSmartSpawning(object o) + { + if (o == null) return false; + + // try looking this up in the lookup table + if (holdSmartSpawningHash == null) + { + holdSmartSpawningHash = new Hashtable(); + } + PropertyInfo prop = null; + + if (!holdSmartSpawningHash.Contains(o.GetType())) + { + + prop = o.GetType().GetProperty("HoldSmartSpawning"); + // check to make sure the HoldSmartSpawning property for this object has the right type + if (prop != null && (!prop.CanRead || prop.PropertyType != typeof(bool))) + { + prop = null; + } + + holdSmartSpawningHash.Add(o.GetType(), prop); + } + else + { + // look it up in the hash table + prop = (PropertyInfo)holdSmartSpawningHash[o.GetType()]; + } + + if (prop != null) + { + try + { + return (bool)(prop.GetValue(o, null)); + } + catch { } + } + + return false; + } + + public bool HasHoldSmartSpawning + { + get + { + + // go through the spawn lists + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (CheckHoldSmartSpawning(o)) + { + return true; + } + } + } + + return false; + } + } + + // if a non-null mob argument is passed, then check the canswim and cantwalk props to determine valid placement + public bool CanFit(int x, int y, int z, int height, bool checkBlocksFit, bool checkMobiles, bool requireSurface, Mobile mob) + { + + Map map = this.Map; + + if (DebugThis) + { + Console.WriteLine("CanFit mob {0}, map={1}", mob, map); + } + if (map == null || map == Map.Internal) + return false; + + if (x < 0 || y < 0 || x >= map.Width || y >= map.Height) + return false; + + bool hasSurface = false; + bool checkmob = false; + bool canswim = false; + bool cantwalk = false; + + if (mob != null) + { + checkmob = true; + canswim = mob.CanSwim; + cantwalk = mob.CantWalk; + } + if (DebugThis) + { + Console.WriteLine("fitting mob {0} checkmob={1} swim={2} walk={3}", mob, checkmob, canswim, cantwalk); + } + LandTile lt = map.Tiles.GetLandTile(x, y); + int lowZ = 0, avgZ = 0, topZ = 0; + + bool surface, impassable; + bool wet = false; + + map.GetAverageZ(x, y, ref lowZ, ref avgZ, ref topZ); + TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + + if (DebugThis) + { + Console.WriteLine("landtile at {0},{1},{2} lowZ={3} avgZ={4} topZ={5}", x, y, z, lowZ, avgZ, topZ); + } + + impassable = (landFlags & TileFlag.Impassable) != 0; + if (checkmob) + { + wet = (landFlags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + impassable = true; + // allow water creatures on water + if (canswim && wet) + { + impassable = false; + } + } + + + if (impassable && avgZ > z && (z + height) > lowZ) + return false; + else if (!impassable && z == avgZ && !lt.Ignored) + hasSurface = true; + + if (DebugThis) + { + Console.WriteLine("landtile at {0},{1},{2} wet={3} impassable={4} hassurface={5}", x, y, z, wet, impassable, hasSurface); + } + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y, true); + + + for (int i = 0; i < staticTiles.Length; ++i) + { + ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + surface = id.Surface; + impassable = id.Impassable; + if (checkmob) + { + wet = (id.Flags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + impassable = true; + // allow water creatures on water + if (canswim && wet) + { + surface = true; + impassable = false; + } + } + + if ((surface || impassable) && (staticTiles[i].Z + id.CalcHeight) > z && (z + height) > staticTiles[i].Z) + return false; + else if (surface && !impassable && z == (staticTiles[i].Z + id.CalcHeight)) + hasSurface = true; + + + } + if (DebugThis) + { + Console.WriteLine("statics hassurface={0}", hasSurface); + } + + Sector sector = map.GetSector(x, y); + List items = sector.Items; + List mobs = sector.Mobiles; + + for (int i = 0; i < items.Count; ++i) + { + Item item = items[i]; + + if (item.ItemID < 0x4000 && item.AtWorldPoint(x, y)) + { + ItemData id = item.ItemData; + surface = id.Surface; + impassable = id.Impassable; + if (checkmob) + { + wet = (id.Flags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + impassable = true; + // allow water creatures on water + if (canswim && wet) + { + surface = true; + impassable = false; + } + } + + if ((surface || impassable || (checkBlocksFit && item.BlocksFit)) && (item.Z + id.CalcHeight) > z && (z + height) > item.Z) + return false; + else if (surface && !impassable && !item.Movable && z == (item.Z + id.CalcHeight)) + hasSurface = true; + } + } + + if (DebugThis) + { + Console.WriteLine("items hassurface={0}", hasSurface); + } + + if (checkMobiles) + { + for (int i = 0; i < mobs.Count; ++i) + { + Mobile m = mobs[i]; + + if (m.Location.X == x && m.Location.Y == y && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + if ((m.Z + 16) > z && (z + height) > m.Z) + return false; + } + } + + if (DebugThis) + { + Console.WriteLine("return requiresurface={0} hassurface={1}", requireSurface, hasSurface); + } + + return !requireSurface || hasSurface; + } + + public bool CanSpawnMobile(int x, int y, int z, Mobile mob) + { + if (DebugThis) + { + Console.WriteLine("CanSpawnMobile mob {0}", mob); + } + if (!Region.Find(new Point3D(x, y, z), this.Map).AllowSpawn()) + return false; + + return CanFit(x, y, z, 16, false, true, true, mob); + } + + public bool HasRegionPoints(Region r) + { + if (r != null && r.Area.Length > 0) return true; + else + return false; + } + + private void FindTileLocations(ref List locations, Map map, int startx, int starty, int width, int height, List includetilelist, List excludetilelist, TileFlag tileflag) + { + if (width < 0 || height < 0 || map == null) return; + + if (locations == null) locations = new List(); + + bool includetile; + bool excludetile; + for (int x = startx; x <= startx + width; x++) + { + for (int y = starty; y <= starty + height; y++) + { + // go through all of the tiles at the location and find those that are in the allowed tiles list + LandTile ltile = map.Tiles.GetLandTile(x, y); + TileFlag lflags = TileData.LandTable[ltile.ID & TileData.MaxLandValue].Flags; + + // check the land tile + if (includetilelist != null && includetilelist.Count > 0) + { + includetile = includetilelist.Contains(ltile.ID & TileData.MaxItemValue); + } + else + { + includetile = true; + } + + // non-excluded tiles must also be passable + if (excludetilelist != null && excludetilelist.Count > 0) + { + // also require the tile to be passable + excludetile = ((lflags & TileFlag.Impassable) != 0) || excludetilelist.Contains(ltile.ID & TileData.MaxLandValue); + } + else + { + excludetile = false; + } + + if (includetile && !excludetile && ((lflags & tileflag) == tileflag)) + { + //Console.WriteLine("found landtile {0}/{1} at {2},{3},{4}", ltile.ID, ltile.ID & 0x3fff, x, y, ltile.Z + ltile.Height); + locations.Add(new Point3D(x, y, ltile.Z + ltile.Height)); + continue; + } + + StaticTile[] statictiles = map.Tiles.GetStaticTiles(x, y, true); + + // check the static tiles + for (int i = 0; i < statictiles.Length; ++i) + { + StaticTile stile = statictiles[i]; + TileFlag sflags = TileData.ItemTable[stile.ID & TileData.MaxItemValue].Flags; + + if (includetilelist != null && includetilelist.Count > 0) + { + includetile = includetilelist.Contains(stile.ID & TileData.MaxItemValue); + } + else + { + includetile = true; + } + + // non-excluded tiles must also be passable + if (excludetilelist != null && excludetilelist.Count > 0) + { + excludetile = ((sflags & TileFlag.Impassable) != 0) || excludetilelist.Contains(stile.ID & TileData.MaxItemValue); + } + else + { + excludetile = false; + } + + if (includetile && !excludetile && ((sflags & tileflag) == tileflag)) + { + //Console.WriteLine("found statictile {0}/{1} at {2},{3},{4}", stile.ID, stile.ID & 0x3fff, x, y, stile.Z + stile.Height); + locations.Add(new Point3D(x, y, stile.Z + stile.Height)); + break; + } + } + } + } + } + + private void FindRegionTileLocations(ref List locations, Region r, List includetilelist, List excludetilelist, TileFlag tileflag) + { + if (r == null || r.Area == null) return; + + int count = r.Area.Length; + + if (locations == null) locations = new List(); + + // calculate fields of all rectangles (for probability calculating) + for (int n = 0; n < count; n++) + { + object o = r.Area[n]; + int sx = 0; + int sy = 0; + int w = -1; + int h = -1; + if (o is Rectangle2D) + { + sx = ((Rectangle2D)o).X; + sy = ((Rectangle2D)o).Y; + w = ((Rectangle2D)o).X + ((Rectangle2D)o).Width; + h = ((Rectangle2D)o).Y + ((Rectangle2D)o).Height; + } + else + if (o is Rectangle3D) + { + sx = ((Rectangle3D)o).Start.X; + sy = ((Rectangle3D)o).Start.Y; + w = ((Rectangle3D)o).Width; + h = ((Rectangle3D)o).Height; + } + + // find all of the valid tile locations in the area + FindTileLocations(ref locations, r.Map, sx, sy, w, h, includetilelist, excludetilelist, tileflag); + } + + + } + + // 2004.02.08 :: Omega Red + public Point2D GetRandomRegionPoint(Region r) + { + int count = r.Area.Length; + + int[] FieldArray = new int[count]; + int total = 0; + + // calculate fields of all rectangles (for probability calculating) + for (int i = 0; i < count; i++) + { + object o = r.Area[i]; + if (o is Rectangle2D) + { + total += (FieldArray[i] = ((Rectangle2D)o).Width * ((Rectangle2D)o).Height); + } + else + if (o is Rectangle3D) + { + total += (FieldArray[i] = ((Rectangle3D)o).Width * ((Rectangle3D)o).Height); + } + } + + int sum = 0; + int rnd = 0; + if (total > 0) + rnd = Utility.Random(total); + int x = 0; + int y = 0; + for (int i = 0; i < count; i++) + { + sum += FieldArray[i]; + if (sum > rnd) + { + object o = r.Area[i]; + + if (o is Rectangle2D) + { + Rectangle2D r2d = (Rectangle2D)o; + if (r2d.Width >= 0) + x = r2d.X + Utility.Random(r2d.Width + 1); + + if (r2d.Height >= 0) + y = r2d.Y + Utility.Random(r2d.Height + 1); + + break; + } + else + if (o is Rectangle3D) + { + Rectangle3D r3d = (Rectangle3D)o; + if (r3d.Width >= 0) + x = r3d.Start.X + Utility.Random(r3d.Width + 1); + if (r3d.Height >= 0) + y = r3d.Start.Y + Utility.Random(r3d.Height + 1); + break; + } + } + } + + return new Point2D(x, y); + } + + // used for getting non-mobile spawn positions + public Point3D GetSpawnPosition(bool requiresurface) + { + // no pack spawning + return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null); + } + + // used for getting mobile spawn positions + public Point3D GetSpawnPosition(bool requiresurface, Mobile mob) + { + // no pack spawning + return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob); + } + + // used for getting non-mobile spawn positions + public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List spawnpositioning) + { + return GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null); + } + + public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List spawnpositioning, Mobile mob) + { + Map map = Map; + + if (map == null) + return Location; + + // random positioning by default + SpawnPositionType positioning = SpawnPositionType.Random; + Mobile trigmob = null; + string[] positionargs = null; + List includetilelist = null; + List excludetilelist = null; + // restrictions on tile flags + TileFlag tileflag = TileFlag.None; + List locations = null; + + int fillinc = 1; + int positionrange = 0; + string prefix = null; + ArrayList WayList = null; + int xinc = 0; + int yinc = 0; + int zinc = 0; + if (spawnpositioning != null) + { + foreach (SpawnPositionInfo s in spawnpositioning) + { + if (s == null) continue; + + trigmob = s.trigMob; + positionargs = s.positionArgs; + + // parse the possible args to the spawn position control keywords + switch (s.positionType) + { + case SpawnPositionType.Wet: + // syntax Wet + // find all of the wet tiles + tileflag |= TileFlag.Wet; + requiresurface = false; + break; + case SpawnPositionType.Tiles: + { + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + int start = -1; + int end = -1; + if (positionargs != null && positionargs.Length > 1) + { + try + { + start = int.Parse(positionargs[1]); + } + catch { } + } + if (positionargs != null && positionargs.Length > 2) + { + try + { + end = int.Parse(positionargs[2]); + } + catch { } + } + if (includetilelist == null) + { + includetilelist = new List(); + } + + // add the tiles to the list + if (start > -1 && end < 0) + { + includetilelist.Add(start); + } + else + if (start > -1 && end > -1) + { + for (int j = start; j <= end; j++) + { + includetilelist.Add(j); + } + } + break; + } + case SpawnPositionType.NoTiles: + { + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + int start = -1; + int end = -1; + if (positionargs != null && positionargs.Length > 1) + { + try + { + start = int.Parse(positionargs[1]); + } + catch { } + } + if (positionargs != null && positionargs.Length > 2) + { + try + { + end = int.Parse(positionargs[2]); + } + catch { } + } + if (excludetilelist == null) + { + excludetilelist = new List(); + } + + // add the tiles to the list + if (start > -1 && end < 0) + { + excludetilelist.Add(start); + } + else + if (start > -1 && end > -1) + { + for (int j = start; j <= end; j++) + { + excludetilelist.Add(j); + } + } + break; + } + case SpawnPositionType.RowFill: + case SpawnPositionType.ColFill: + case SpawnPositionType.Perimeter: + // syntax XFILL[,inc] + // syntax YFILL[,inc] + // syntax EDGE[,inc] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) + { + try + { + fillinc = int.Parse(positionargs[1]); + } + catch { } + } + break; + case SpawnPositionType.RelXY: + case SpawnPositionType.DeltaLocation: + case SpawnPositionType.Location: + // syntax RELXY,xinc,yinc[,zinc] + // syntax XY,x,y[,z] + // syntax DXY,dx,dy[,dz] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 2) + { + try + { + xinc = int.Parse(positionargs[1]); + yinc = int.Parse(positionargs[2]); + } + catch { } + } + if (positionargs != null && positionargs.Length > 3) + { + try + { + zinc = int.Parse(positionargs[3]); + } + catch { } + } + break; + case SpawnPositionType.Waypoint: + // syntax WAYPOINT,prefix[,range] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) + { + prefix = positionargs[1]; + } + + if (positionargs != null && positionargs.Length > 2) + { + try + { + positionrange = int.Parse(positionargs[2]); + } + catch { } + } + + // find a list of items that match the waypoint prefix + if (prefix != null) + { + // see if there is an existing hashtable for the waypoint lists + if (spawnPositionWayTable == null) + { + spawnPositionWayTable = new Hashtable(); + } + + // try to find the waypoint list in the local table + WayList = (ArrayList)spawnPositionWayTable[prefix]; + + // no existing list so create a new one + if (WayList == null) + { + WayList = new ArrayList(); + + foreach (Item i in World.Items.Values) + { + if (i is WayPoint && i.Name != null && i.Map == Map && i.Name.StartsWith(prefix)) + { + // add it to the list of items + WayList.Add(i); + } + } + // add the new list to the local table + spawnPositionWayTable.Add(prefix, WayList); + } + } + break; + case SpawnPositionType.Player: + // syntax PLAYER[,range] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) + { + try + { + positionrange = int.Parse(positionargs[1]); + } + catch { } + } + break; + } + } + } + + // precalculate tile locations if they have been specified + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + { + if (m_Region != null && HasRegionPoints(m_Region)) + { + + FindRegionTileLocations(ref locations, m_Region, includetilelist, excludetilelist, tileflag); + } + else + if (positioning == SpawnPositionType.Random) + { + FindTileLocations(ref locations, this.Map, m_X, m_Y, m_Width, m_Height, includetilelist, excludetilelist, tileflag); + } + } + + + // Try 10 times to find a Spawnable location. + // trace profiling indicates that this is a major bottleneck + for (int i = 0; i < 10; i++) + { + int x = this.X; + int y = this.Y; + int z = Z; + + int defaultZ = this.Z; + if (packrange >= 0 && packcoord != Point3D.Zero) + { + defaultZ = packcoord.Z; + } + + if (packrange >= 0 && packcoord != Point3D.Zero) + { + // find a random coord relative to the packcoord + x = packcoord.X - packrange + Utility.Random(packrange * 2 + 1); + y = packcoord.Y - packrange + Utility.Random(packrange * 2 + 1); + } + else + if (m_Region != null && HasRegionPoints(m_Region)) // 2004.02.08 :: Omega Red + { + // if region spawning is selected then use that to find an x,y loc instead of the spawn box + + + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + { + // use the precalculated tile locations + if (locations != null && locations.Count > 0) + { + Point3D p = locations[Utility.Random(locations.Count)]; + x = p.X; + y = p.Y; + defaultZ = p.Z; + } + } + else + { + Point2D p = GetRandomRegionPoint(m_Region); + x = p.X; + y = p.Y; + } + + + } + else + { + switch (positioning) + { + case SpawnPositionType.Random: + + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + { + + if (locations != null && locations.Count > 0) + { + Point3D p = locations[Utility.Random(locations.Count)]; + x = p.X; + y = p.Y; + defaultZ = p.Z; + } + } + else + { + + if (m_Width > 0) + x = m_X + Utility.Random(m_Width + 1); + if (m_Height > 0) + y = m_Y + Utility.Random(m_Height + 1); + } + break; + case SpawnPositionType.RelXY: + + x = mostRecentSpawnPosition.X + xinc; + y = mostRecentSpawnPosition.Y + yinc; + defaultZ = mostRecentSpawnPosition.Z + zinc; + break; + case SpawnPositionType.DeltaLocation: + + x = this.X + xinc; + y = this.Y + yinc; + defaultZ = this.Z + zinc; + break; + case SpawnPositionType.Location: + + x = xinc; + y = yinc; + defaultZ = zinc; + break; + case SpawnPositionType.RowFill: + + x = mostRecentSpawnPosition.X + fillinc; + y = mostRecentSpawnPosition.Y; + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + if (x > m_X + m_Width) + { + x = m_X + (x - m_X - m_Width - 1); + y++; + } + + if (y > m_Y + m_Height) + { + y = m_Y; + } + + break; + case SpawnPositionType.ColFill: + + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y + fillinc; + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + if (y > m_Y + m_Height) + { + y = m_Y + (y - m_Y - m_Height - 1); + x++; + } + + if (x > m_X + m_Width) + { + x = m_X; + } + + break; + case SpawnPositionType.Perimeter: + + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y; + + // if the point is not on the perimeter, reset it to the corner + if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height) + { + x = m_X; + y = m_Y; + } + + if (y == m_Y && x < m_X + m_Width) x += fillinc; + else + if (y == m_Y + m_Height && x > m_X) x -= fillinc; + else + if (x == m_X && y > m_Y) y -= fillinc; + else + if (x == m_X + m_Width && y < m_Y + m_Height) y += fillinc; + + if (x > m_X + m_Width) + { + x = m_X + m_Width; + } + + if (y > m_Y + m_Height) + { + y = m_Y + m_Height; + } + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + break; + case SpawnPositionType.Player: + + if (trigmob != null) + { + x = trigmob.Location.X; + y = trigmob.Location.Y; + if (positionrange > 0) + { + x += Utility.Random(positionrange * 2 + 1) - positionrange; + y += Utility.Random(positionrange * 2 + 1) - positionrange; + } + } + break; + case SpawnPositionType.Waypoint: + + // pick an item randomly from the waylist + if (WayList != null && WayList.Count > 0) + { + int index = Utility.Random(WayList.Count); + Item waypoint = (Item)WayList[index]; + if (waypoint != null) + { + x = waypoint.Location.X; + y = waypoint.Location.Y; + defaultZ = waypoint.Location.Z; + if (positionrange > 0) + { + x += Utility.Random(positionrange * 2 + 1) - positionrange; + y += Utility.Random(positionrange * 2 + 1) - positionrange; + } + } + } + break; + } + + mostRecentSpawnPosition = new Point3D(x, y, defaultZ); + } + + // skip invalid points + if (x < 0 || y < 0 || (x == 0 && y == 0)) continue; + + // try to find a valid spawn location using the z coord of the spawner + // relax the normal surface requirement for mobiles if the flag is set + bool fit = false; + if (requiresurface) + { + fit = CanSpawnMobile(x, y, defaultZ, mob); + } + else + { + fit = Map.CanFit(x, y, defaultZ, SpawnFitSize, true, false, false); + } + + // if that fails then try to find a valid z coord + if (fit) + { + return new Point3D(x, y, defaultZ); + } + else + { + + z = Map.GetAverageZ(x, y); + + if (requiresurface) + { + fit = CanSpawnMobile(x, y, z, mob); + } + else + { + fit = Map.CanFit(x, y, z, SpawnFitSize, true, false, false); + } + + if (fit) + { + return new Point3D(x, y, z); + } + } + } + + if (packrange >= 0 && packcoord != Point3D.Zero) + { + return packcoord; + } + else + { + return this.Location; + } + } + + public int GetCreatureMax(int index) + { + Defrag(false); + + if (m_SpawnObjects == null) return 0; + + return ((SpawnObject)m_SpawnObjects[index]).MaxCount; + } + + private void DeleteFromList(ArrayList list) + { + if (list == null) return; + + foreach (object o in list) + { + if (o is Item) + ((Item)o).Delete(); + else if (o is Mobile) + ((Mobile)o).Delete(); + } + } + + public void RemoveSpawnObjects() + { + if (m_SpawnObjects == null) return; + + Defrag(false); + + ClearTags(true); + ArrayList deletelist = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Item || o is Mobile) deletelist.Add(o); + + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + + public void RemoveSpawnObjects(SpawnObject so) + { + if (so == null) return; + + Defrag(false); + + ArrayList deletelist = new ArrayList(); + + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Item || o is Mobile) deletelist.Add(o); + + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + public void ClearSubgroup(int subgroup) + { + if (m_SpawnObjects == null) return; + + Defrag(false); + + ClearTags(true); + ArrayList deletelist = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.SubGroup != subgroup || !so.ClearOnAdvance) continue; + + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Item || o is Mobile) deletelist.Add(o); + + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + + // used to optimize smart spawning by removing all objects except those that have hold smartspawning + public void SmartRemoveSpawnObjects() + { + if (m_SpawnObjects == null) return; + + Defrag(false); + + ClearTags(true); + ArrayList deletelist = new ArrayList(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + // new optimization for smart spawning to remove all objects except those with hold smartspawning enabled + if (CheckHoldSmartSpawning(o)) + { + continue; + } + + if (o is Item || o is Mobile) deletelist.Add(o); + + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + public void AddSpawnObject(string SpawnObjectName) + { + if (m_SpawnObjects == null) return; + + Defrag(false); + + // Find the spawn object and increment its count by one + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) + { + + // Add one to the total count + m_Count++; + + // Increment the max count for the current creature + so.ActualMaxCount++; + + //only spawn them immediately if the spawner is running + if (Running) + Spawn(SpawnObjectName, false); + + } + } + + InvalidateProperties(); + } + + public void DeleteSpawnObject(Mobile from, string SpawnObjectName) + { + bool WasRunning = m_Running; + + try + { + // Stop spawning for a moment + Stop(); + + // Clean up any spawns marked as deleted + Defrag(false); + + // Keep a reference to the spawn object + SpawnObject TheSpawn = null; + + // Find the spawn object and increment its count by one + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) + { + // Set the spawn + TheSpawn = so; + break; + } + } + + // Was the spawn object found + if (TheSpawn != null) + { + bool delete_this_entry = false; + + // Decrement the max count for the current creature + TheSpawn.ActualMaxCount--; + + // Make sure the spawn count does not go negative + if (TheSpawn.MaxCount < 0) + { + TheSpawn.MaxCount = 0; + delete_this_entry = true; + } + + if (!delete_this_entry) + { + // Subtract one to the total count + m_Count--; + } + + // Make sure the count does not go negative + if (m_Count < 0) + { + m_Count = 0; + + } + + ArrayList deletelist = new ArrayList(); + + // Remove any spawns over the count + while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount) + { + object o = TheSpawn.SpawnedObjects[0]; + + // Delete the object + if (o is Item || o is Mobile) deletelist.Add(o); + + TheSpawn.SpawnedObjects.Remove(o); + } + + DeleteFromList(deletelist); + + // Check if the spawn object should be removed + //if( TheSpawn.MaxCount < 1 ) + if (delete_this_entry) + { + m_SpawnObjects.Remove(TheSpawn); + if (from != null) + CommandLogging.WriteLine(from, "{0} {1} removed from XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), Serial, Name, GetWorldLocation().X, GetWorldLocation().Y, Map, SpawnObjectName); + } + } + + InvalidateProperties(); + } + finally + { + if (WasRunning) + Start(); + } + } + + #endregion + + #region Object Creation + + public static object CreateObject(Type type, string itemtypestring) + { + return CreateObject(type, itemtypestring, true); + } + + public static object CreateObject(Type type, string itemtypestring, bool requireconstructable) + { + // look for constructor arguments to be passed to it with the syntax type,arg1,arg2,.../ + string[] typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring); + + return CreateObject(type, typewordargs, requireconstructable, false); + } + + public static object CreateObject(Type type, string itemtypestring, bool requireconstructable, bool requireattachable) + { + // look for constructor arguments to be passed to it with the syntax type,arg1,arg2,.../ + string[] typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring); + + return CreateObject(type, typewordargs, requireconstructable, requireattachable); + } + + public static object CreateObject(Type type, string[] typewordargs, bool requireconstructable, bool requireattachable) + { + if (type == null) return null; + + object o = null; + + int typearglen = 0; + if (typewordargs != null) + typearglen = typewordargs.Length; + + // ok, there are args in the typename, so we need to invoke the proper constructor + ConstructorInfo[] ctors = type.GetConstructors(); + + if (ctors == null) return null; + + // go through all the constructors for this type + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + if (ctor == null) continue; + + // if both requireconstructable and requireattachable are true, then allow either condition +#if(RESTRICTCONSTRUCTABLE) + if (!(requireconstructable && Add.IsConstructable(ctor,ConstructableAccessLevel)) && !(requireattachable && XmlAttach.IsAttachable(ctor))) + continue; +#else + if (!(requireconstructable && IsConstructable(ctor)) && !(requireattachable && XmlAttach.IsAttachable(ctor))) + continue; +#endif + + // check the parameter list of the constructor + ParameterInfo[] paramList = ctor.GetParameters(); + + // and compare with the argument list provided + if (paramList != null && typearglen == paramList.Length) + { + // this is a constructor that takes args and matches the number of args passed in to CreateObject + if (paramList.Length > 0) + { + object[] paramValues = null; + + try + { + paramValues = Add.ParseValues(paramList, typewordargs); + } + catch { } + + if (paramValues == null) + continue; + + // ok, have a match on args, so try to construct it + try + { + o = Activator.CreateInstance(type, paramValues); + } + catch { } + } + else + { + // zero argument constructor + try + { + o = Activator.CreateInstance(type); + } + catch { } + } + + // successfully constructed the object, otherwise try another matching constructor + if (o != null) break; + } + } + + return o; + } + + #endregion + + #region Timers + + + private static void DoGlobalSectorTimer(TimeSpan delay) + { + if (m_GlobalSectorTimer != null) + m_GlobalSectorTimer.Stop(); + + m_GlobalSectorTimer = new GlobalSectorTimer(delay); + + m_GlobalSectorTimer.Start(); + } + + private class GlobalSectorTimer : Timer + { + + public GlobalSectorTimer(TimeSpan delay) + : base(delay, delay) + { + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + // check the sectors + + // check all active players + if (NetState.Instances == null) return; + + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + + if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) + { + // activate any spawner in the sector they are in + if (m.Map != null && m.Map != Map.Internal) + { + Sector s = m.Map.GetSector(m.Location); + + // Scriptiz : voyons voir ce qui cloche + if (m.Map.MapID >= GlobalSectorTable.Length) + { + using (StreamWriter sw = new StreamWriter("debug_scriptiz.txt", true)) + { + string error = String.Format("{0} : MapID ({1}:{2}) > GlobalSectorTable.Length ({3})", DateTime.Now, m.Map.Name, m.Map.MapID, GlobalSectorTable.Length); + sw.WriteLine(error); + Console.WriteLine(error); + } + return; + } + + if (s != null && GlobalSectorTable[m.Map.MapID] != null) + { + // Scriptiz : voyons voir ce qui cloche + if (!GlobalSectorTable[m.Map.MapID].Contains(s)) + { + using (StreamWriter sw = new StreamWriter("debug_scriptiz.txt", true)) + { + string error = String.Format("{0} : GlobalSectorTable doesn't contains sector {1}:{2} ({3},{4})", DateTime.Now, m.Map.Name, m.Map.MapID, s.X, s.Y); + sw.WriteLine(error); + Console.WriteLine(error); + } + return; + } + + ArrayList spawnerlist = (ArrayList)GlobalSectorTable[m.Map.MapID][s]; + if (spawnerlist != null) + { + foreach (XmlSpawner spawner in spawnerlist) + { + + if (spawner != null && !spawner.Deleted && spawner.Running && spawner.SmartSpawning && spawner.IsInactivated) + { + spawner.SmartRespawn(); + } + } + } + } + } + } + } + } + } + + public void DoSectorTimer(TimeSpan delay) + { + if (m_SectorTimer != null) + m_SectorTimer.Stop(); + + m_SectorTimer = new SectorTimer(this, delay); + + m_SectorTimer.Start(); + } + + private class SectorTimer : Timer + { + private XmlSpawner m_Spawner; + + public SectorTimer(XmlSpawner spawner, TimeSpan delay) + : base(delay, delay) + { + Priority = TimerPriority.OneSecond; + m_Spawner = spawner; + } + + protected override void OnTick() + { + // check the sectors + + if (m_Spawner != null && !m_Spawner.Deleted && m_Spawner.Running && m_Spawner.IsInactivated) + { + if (m_Spawner.SmartSpawning) + { + if (m_Spawner.HasActiveSectors) + { + Stop(); + + m_Spawner.SmartRespawn(); + } + } + else + { + Stop(); + + m_Spawner.IsInactivated = false; + } + } + else + { + Stop(); + + } + } + } + + private class WarnTimer2 : Timer + { + private ArrayList m_List; + + private class WarnEntry2 + { + public Point3D m_Point; + public Map m_Map; + public string m_Name; + + public WarnEntry2(Point3D p, Map map, string name) + { + m_Point = p; + m_Map = map; + m_Name = name; + } + } + + public WarnTimer2() + : base(TimeSpan.FromSeconds(1.0)) + { + m_List = new ArrayList(); + Start(); + } + + public void Add(Point3D p, Map map, string name) + { + m_List.Add(new WarnEntry2(p, map, name)); + } + + protected override void OnTick() + { + try + { + Console.WriteLine("Warning: {0} bad spawns detected, logged: 'badspawn.log'", m_List.Count); + + using (StreamWriter op = new StreamWriter("badspawn.log", true)) + { + op.WriteLine("# Bad spawns : {0}", DateTime.Now); + op.WriteLine("# Format: X Y Z F Name"); + op.WriteLine(); + + foreach (WarnEntry2 e in m_List) + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name); + + op.WriteLine(); + op.WriteLine(); + } + } + catch + { } + } + } + + public void DoTimer() + { + if (!m_Running) + return; + + + int minSeconds = (int)m_MinDelay.TotalSeconds; + int maxSeconds = (int)m_MaxDelay.TotalSeconds; + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)); + DoTimer(delay); + } + + public void DoTimer(TimeSpan delay) + { + if (!m_Running) + return; + + m_End = DateTime.Now + delay; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = new SpawnerTimer(this, delay); + m_Timer.Start(); + } + + public void DoTimer2(TimeSpan delay) + { + m_DurEnd = DateTime.Now + delay; + if (m_Duration > TimeSpan.FromMinutes(0) || (m_durActivated == true)) + { + if (m_DurTimer != null) + m_DurTimer.Stop(); + m_DurTimer = new InternalTimer(this, delay); + m_DurTimer.Start(); + m_durActivated = true; + } + } + + public void DoTimer3(TimeSpan delay) + { + // if ( !m_proximityActivated ) + // return; + + m_RefractEnd = DateTime.Now + delay; + m_refractActivated = true; + + if (m_RefractoryTimer != null) + m_RefractoryTimer.Stop(); + + m_RefractoryTimer = new InternalTimer3(this, delay); + m_RefractoryTimer.Start(); + } + + // added the duration timer that begins on spawning + private class InternalTimer : Timer + { + private XmlSpawner m_spawner; + + public InternalTimer(XmlSpawner spawner, TimeSpan delay) + : base(delay) + { + Priority = TimerPriority.OneSecond; + m_spawner = spawner; + } + + protected override void OnTick() + { + if (m_spawner != null && !m_spawner.Deleted) + { + m_spawner.RemoveSpawnObjects(); + m_spawner.m_durActivated = false; + } + + } + } + + private class SpawnerTimer : Timer + { + private XmlSpawner m_Spawner; + + public SpawnerTimer(XmlSpawner spawner, TimeSpan delay) + : base(delay) + { + + // reduce timer priority if spawner is inactivated + if (spawner.IsInactivated) + { + Priority = TimerPriority.FiveSeconds; + } + else + { + Priority = spawner.BasePriority; + } + + + m_Spawner = spawner; + } + + protected override void OnTick() + { + if (m_Spawner != null && !m_Spawner.Deleted) + { + m_Spawner.OnTick(); + } + } + } + + // added the refractory timer that begins on proximity triggering + private class InternalTimer3 : Timer + { + private XmlSpawner m_spawner; + + public InternalTimer3(XmlSpawner spawner, TimeSpan delay) + : base(delay) + { + Priority = TimerPriority.OneSecond; + m_spawner = spawner; + } + + protected override void OnTick() + { + if (m_spawner != null && !m_spawner.Deleted) + { + // reenable triggering + m_spawner.m_refractActivated = false; + } + } + } + #endregion + + #region Serialization + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)30); // version + // Version 30 + writer.Write(m_AllowNPCTriggering); + + // Version 29 + if (m_SpawnObjects != null) + { + writer.Write(m_SpawnObjects.Count); + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the spawns per tick value + writer.Write(((SpawnObject)m_SpawnObjects[i]).SpawnsPerTick); + } + } + else + { + // empty spawner + writer.Write((int)0); + } + + // Version 28 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the pack range value + writer.Write(((SpawnObject)m_SpawnObjects[i]).PackRange); + } + } + + + // Version 27 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the disable spawn flag + writer.Write(((SpawnObject)m_SpawnObjects[i]).Disabled); + } + } + + // Version 26 + writer.Write(m_SpawnOnTrigger); + writer.Write(m_FirstModified); + writer.Write(m_LastModified); + + // Version 25 + // eliminated the textentrybook serialization (they autodelete on deser now) + + // Version 24 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[i]; + // Write the restrict kills flag + writer.Write(so.RestrictKillsToSubgroup); + // Write the clear on advance flag + writer.Write(so.ClearOnAdvance); + // Write the mindelay + writer.Write(so.MinDelay); + // Write the maxdelay + writer.Write(so.MaxDelay); + // write the next spawn time for the subgrop + writer.WriteDeltaTime(so.NextSpawn); + + } + } + + if (m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0) + { + writer.Write(true); + writer.WriteItemList(m_ShowBoundsItems); + } + else + { + // empty showbounds item list + writer.Write(false); + } + + // Version 23 + writer.Write(IsInactivated); + writer.Write(m_SmartSpawning); + // Version 22 + writer.Write(m_SkillTrigger); + writer.Write((int)m_skill_that_triggered); + writer.Write(m_FreeRun); + writer.Write(m_mob_who_triggered); + // Version 21 + writer.Write(m_DespawnTime); + // Version 20 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the requiresurface flag + writer.Write(((SpawnObject)m_SpawnObjects[i]).RequireSurface); + } + } + // Version 19 + writer.Write(m_ConfigFile); + writer.Write(m_OnHold); + writer.Write(m_HoldSequence); + writer.Write(m_FirstModifiedBy); + writer.Write(m_LastModifiedBy); + // compute the number of tags to save + int tagcount = 0; + for (int i = 0; i < m_KeywordTagList.Count; i++) + { + // only save WAIT type keywords or other keywords that have the save flag set + if ((((BaseXmlSpawner.KeywordTag)(m_KeywordTagList[i])).Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0) + tagcount++; + } + writer.Write(tagcount); + // and write them out + for (int i = 0; i < m_KeywordTagList.Count; i++) + { + if ((((BaseXmlSpawner.KeywordTag)(m_KeywordTagList[i])).Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0) + { + ((BaseXmlSpawner.KeywordTag)(m_KeywordTagList[i])).Serialize(writer); + } + } + // Version 18 + writer.Write(m_AllowGhostTriggering); + // Version 17 + // removed in version 25 + //writer.Write( m_TextEntryBook); + // Version 16 + writer.Write(m_SequentialSpawning); + // write out the remaining time until sequential reset + writer.Write(NextSeqReset); + // Write the spawn object list + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[i]; + // Write the subgroup and sequential reset time + writer.Write(so.SubGroup); + writer.Write(so.SequentialResetTime); + writer.Write(so.SequentialResetTo); + writer.Write(so.KillsNeeded); + } + } + writer.Write(m_RegionName); // 2004.02.08 :: Omega Red + + + // Version 15 + writer.Write(m_ExternalTriggering); + writer.Write(m_ExternalTrigger); + + // Version 14 + writer.Write(m_NoItemTriggerName); + + // Version 13 + writer.Write(m_GumpState); + + // Version 12 + int todtype = (int)m_TODMode; + writer.Write(todtype); + + // Version 11 + writer.Write(m_KillReset); + writer.Write(m_skipped); + writer.Write(m_spawncheck); + + // Version 10 + writer.Write(m_SetPropertyItem); + + // Version 9 + writer.Write(m_TriggerProbability); + + // Version 8 + writer.Write(m_MobPropertyName); + writer.Write(m_MobTriggerName); + writer.Write(m_PlayerPropertyName); + + // Version 7 + writer.Write(m_SpeechTrigger); + + // Version 6 + writer.Write(m_ItemTriggerName); + + // Version 5 + writer.Write(m_ProximityTriggerMessage); + writer.Write(m_ObjectPropertyItem); + writer.Write(m_ObjectPropertyName); + writer.Write(m_killcount); + + // Version 4 + writer.Write(m_ProximityRange); + writer.Write(m_ProximityTriggerSound); + writer.Write(m_proximityActivated); + writer.Write(m_durActivated); + writer.Write(m_refractActivated); + writer.Write(m_StackAmount); + writer.Write(m_TODStart); + writer.Write(m_TODEnd); + writer.Write(m_MinRefractory); + writer.Write(m_MaxRefractory); + if (m_refractActivated) + writer.Write(m_RefractEnd - DateTime.Now); + if (m_durActivated) + writer.Write(m_DurEnd - DateTime.Now); + // Version 3 + writer.Write(m_ShowContainerStatic); + // Version 2 + writer.Write(m_Duration); + + // Version 1 + writer.Write(m_UniqueId); + writer.Write(m_HomeRangeIsRelative); + + // Version 0 + writer.Write(m_Name); + writer.Write(m_X); + writer.Write(m_Y); + writer.Write(m_Width); + writer.Write(m_Height); + writer.Write(m_WayPoint); + writer.Write(m_Group); + writer.Write(m_MinDelay); + writer.Write(m_MaxDelay); + writer.Write(m_Count); + writer.Write(m_Team); + writer.Write(m_HomeRange); + writer.Write(m_Running); + + if (m_Running) + writer.Write(m_End - DateTime.Now); + + // Write the spawn object list + int nso = 0; + if (m_SpawnObjects != null) nso = m_SpawnObjects.Count; + writer.Write(nso); + for (int i = 0; i < nso; ++i) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[i]; + + // Write the type and maximum count + writer.Write((string)so.TypeName); + writer.Write((int)so.ActualMaxCount); + + // Write the spawned object information + writer.Write(so.SpawnedObjects.Count); + for (int x = 0; x < so.SpawnedObjects.Count; ++x) + { + object o = so.SpawnedObjects[x]; + + if (o is Item) + writer.Write((Item)o); + else if (o is Mobile) + writer.Write((Mobile)o); + else + { + + // if this is a keyword tag then add some more info + if (o is BaseXmlSpawner.KeywordTag) + { + writer.Write(-1 * ((BaseXmlSpawner.KeywordTag)o).Serial - 2); + } + else + { + writer.Write(Serial.MinusOne); + } + } + } + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + bool haveproximityrange = false; + bool hasnewobjectinfo = false; + int tmpSpawnListSize = 0; + ArrayList tmpSubGroup = null; + ArrayList tmpSequentialResetTime = null; + ArrayList tmpSequentialResetTo = null; + ArrayList tmpKillsNeeded = null; + ArrayList tmpRequireSurface = null; + ArrayList tmpRestrictKillsToSubgroup = null; + ArrayList tmpClearOnAdvance = null; + ArrayList tmpMinDelay = null; + ArrayList tmpMaxDelay = null; + ArrayList tmpNextSpawn = null; + ArrayList tmpDisableSpawn = null; + ArrayList tmpPackRange = null; + ArrayList tmpSpawnsPer = null; + + switch (version) + { + case 30: + { + m_AllowNPCTriggering = reader.ReadBool(); + goto case 29; + } + case 29: + { + tmpSpawnListSize = reader.ReadInt(); + tmpSpawnsPer = new ArrayList(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + int spawnsper = reader.ReadInt(); + + tmpSpawnsPer.Add(spawnsper); + + } + goto case 28; + } + case 28: + { + if (version < 29) + tmpSpawnListSize = reader.ReadInt(); + + tmpPackRange = new ArrayList(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + int packrange = reader.ReadInt(); + + tmpPackRange.Add(packrange); + + } + goto case 27; + } + case 27: + { + if (version < 28) + tmpSpawnListSize = reader.ReadInt(); + + tmpDisableSpawn = new ArrayList(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + bool disablespawn = reader.ReadBool(); + + tmpDisableSpawn.Add(disablespawn); + + } + goto case 26; + } + case 26: + { + m_SpawnOnTrigger = reader.ReadBool(); + m_FirstModified = reader.ReadDateTime(); + m_LastModified = reader.ReadDateTime(); + goto case 25; + } + case 25: + { + goto case 24; + } + case 24: + { + if (version < 27) + tmpSpawnListSize = reader.ReadInt(); + tmpRestrictKillsToSubgroup = new ArrayList(tmpSpawnListSize); + tmpClearOnAdvance = new ArrayList(tmpSpawnListSize); + tmpMinDelay = new ArrayList(tmpSpawnListSize); + tmpMaxDelay = new ArrayList(tmpSpawnListSize); + tmpNextSpawn = new ArrayList(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + bool restrictkills = reader.ReadBool(); + bool clearadvance = reader.ReadBool(); + double mind = reader.ReadDouble(); + double maxd = reader.ReadDouble(); + DateTime nextspawn = reader.ReadDeltaTime(); + + tmpRestrictKillsToSubgroup.Add(restrictkills); + tmpClearOnAdvance.Add(clearadvance); + tmpMinDelay.Add(mind); + tmpMaxDelay.Add(maxd); + tmpNextSpawn.Add(nextspawn); + } + + bool hasitems = reader.ReadBool(); + + if (hasitems) + { + m_ShowBoundsItems = reader.ReadItemList(); + } + goto case 23; + } + case 23: + { + IsInactivated = reader.ReadBool(); + SmartSpawning = reader.ReadBool(); + + goto case 22; + } + case 22: + { + SkillTrigger = reader.ReadString(); // note this will also register the skill + m_skill_that_triggered = (SkillName)reader.ReadInt(); + m_FreeRun = reader.ReadBool(); + m_mob_who_triggered = reader.ReadMobile(); + goto case 21; + } + case 21: + { + m_DespawnTime = reader.ReadTimeSpan(); + goto case 20; + } + case 20: + { + if (version < 24) + tmpSpawnListSize = reader.ReadInt(); + tmpRequireSurface = new ArrayList(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + bool requiresurface = reader.ReadBool(); + tmpRequireSurface.Add(requiresurface); + } + goto case 19; + } + case 19: + { + m_ConfigFile = reader.ReadString(); + m_OnHold = reader.ReadBool(); + m_HoldSequence = reader.ReadBool(); + m_FirstModifiedBy = reader.ReadString(); + m_LastModifiedBy = reader.ReadString(); + // deserialize the keyword tag list + int tagcount = reader.ReadInt(); + m_KeywordTagList = new ArrayList(tagcount); + for (int i = 0; i < tagcount; i++) + { + BaseXmlSpawner.KeywordTag tag = new BaseXmlSpawner.KeywordTag(null, this); + tag.Deserialize(reader); + } + goto case 18; + } + case 18: + { + m_AllowGhostTriggering = reader.ReadBool(); + goto case 17; + } + case 17: + { + if (version < 25) + { + // the textentrybooks are deleted on deserialization so no need to track them + reader.ReadItem(); + } + goto case 16; + } + case 16: + { + hasnewobjectinfo = true; + m_SequentialSpawning = reader.ReadInt(); + TimeSpan seqdelay = reader.ReadTimeSpan(); + m_SeqEnd = DateTime.Now + seqdelay; + if (version < 20) + { + tmpSpawnListSize = reader.ReadInt(); + } + tmpSubGroup = new ArrayList(tmpSpawnListSize); + tmpSequentialResetTime = new ArrayList(tmpSpawnListSize); + tmpSequentialResetTo = new ArrayList(tmpSpawnListSize); + tmpKillsNeeded = new ArrayList(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + int subgroup = reader.ReadInt(); + double resettime = reader.ReadDouble(); + int resetto = reader.ReadInt(); + int killsneeded = reader.ReadInt(); + tmpSubGroup.Add(subgroup); + tmpSequentialResetTime.Add(resettime); + tmpSequentialResetTo.Add(resetto); + tmpKillsNeeded.Add(killsneeded); + } + m_RegionName = reader.ReadString(); // 2004.02.08 :: Omega Red + goto case 15; + } + case 15: + { + m_ExternalTriggering = reader.ReadBool(); + m_ExternalTrigger = reader.ReadBool(); + goto case 14; + } + case 14: + { + m_NoItemTriggerName = reader.ReadString(); + goto case 13; + } + case 13: + { + m_GumpState = reader.ReadString(); + goto case 12; + } + case 12: + { + int todtype = reader.ReadInt(); + switch (todtype) + { + case (int)TODModeType.Gametime: + m_TODMode = TODModeType.Gametime; + break; + case (int)TODModeType.Realtime: + m_TODMode = TODModeType.Realtime; + break; + } + goto case 11; + } + case 11: + { + m_KillReset = reader.ReadInt(); + m_skipped = reader.ReadBool(); + m_spawncheck = reader.ReadInt(); + goto case 10; + } + case 10: + { + m_SetPropertyItem = reader.ReadItem(); + goto case 9; + } + case 9: + { + m_TriggerProbability = reader.ReadDouble(); + goto case 8; + } + case 8: + { + m_MobPropertyName = reader.ReadString(); + m_MobTriggerName = reader.ReadString(); + m_PlayerPropertyName = reader.ReadString(); + goto case 7; + } + case 7: + { + m_SpeechTrigger = reader.ReadString(); + goto case 6; + } + case 6: + { + m_ItemTriggerName = reader.ReadString(); + goto case 5; + } + case 5: + { + m_ProximityTriggerMessage = reader.ReadString(); + m_ObjectPropertyItem = reader.ReadItem(); + m_ObjectPropertyName = reader.ReadString(); + m_killcount = reader.ReadInt(); + goto case 4; + } + case 4: + { + haveproximityrange = true; + m_ProximityRange = reader.ReadInt(); + m_ProximityTriggerSound = reader.ReadInt(); + m_proximityActivated = reader.ReadBool(); + m_durActivated = reader.ReadBool(); + m_refractActivated = reader.ReadBool(); + m_StackAmount = reader.ReadInt(); + m_TODStart = reader.ReadTimeSpan(); + m_TODEnd = reader.ReadTimeSpan(); + m_MinRefractory = reader.ReadTimeSpan(); + m_MaxRefractory = reader.ReadTimeSpan(); + if (m_refractActivated == true) + { + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer3(delay); + } + if (m_durActivated == true) + { + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer2(delay); + } + goto case 3; + } + case 3: + { + m_ShowContainerStatic = reader.ReadItem() as Static; + goto case 2; + } + case 2: + { + m_Duration = reader.ReadTimeSpan(); + goto case 1; + } + case 1: + { + m_UniqueId = reader.ReadString(); + m_HomeRangeIsRelative = reader.ReadBool(); + goto case 0; + } + case 0: + { + m_Name = reader.ReadString(); + // backward compatibility with old name storage + if (m_Name != null && m_Name != String.Empty) Name = m_Name; + m_X = reader.ReadInt(); + m_Y = reader.ReadInt(); + m_Width = reader.ReadInt(); + m_Height = reader.ReadInt(); + if (m_Width == m_Height) + m_SpawnRange = m_Width / 2; + else + m_SpawnRange = -1; + if (!haveproximityrange) + { + m_ProximityRange = -1; + } + m_WayPoint = reader.ReadItem() as WayPoint; + m_Group = reader.ReadBool(); + m_MinDelay = reader.ReadTimeSpan(); + m_MaxDelay = reader.ReadTimeSpan(); + m_Count = reader.ReadInt(); + m_Team = reader.ReadInt(); + m_HomeRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + + if (m_Running == true) + { + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer(delay); + } + + // Read in the size of the spawn object list + int SpawnListSize = reader.ReadInt(); + m_SpawnObjects = new ArrayList(SpawnListSize); + for (int i = 0; i < SpawnListSize; ++i) + { + string TypeName = reader.ReadString(); + int TypeMaxCount = reader.ReadInt(); + + SpawnObject TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount); + + m_SpawnObjects.Add(TheSpawnObject); + + string typeName = BaseXmlSpawner.ParseObjectType(TypeName); + // does it have a substitution that might change its validity? + // if so then let it go + + if (typeName == null || ((SpawnerType.GetType(typeName) == null) && + (!BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#")))) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer2(); + + m_WarnTimer.Add(Location, Map, TypeName); + + this.status_str = "invalid type: " + typeName; + } + + // Read in the number of spawns already + int SpawnedCount = reader.ReadInt(); + + TheSpawnObject.SpawnedObjects = new ArrayList(SpawnedCount); + + for (int x = 0; x < SpawnedCount; ++x) + { + int serial = reader.ReadInt(); + if (serial < -1) + { + // minusone is reserved for unknown types by default + // minustwo on is used for referencing keyword tags + int tagserial = -1 * (serial + 2); + // get the tag with that serial and add it + BaseXmlSpawner.KeywordTag t = BaseXmlSpawner.GetFromTagList(this, tagserial); + if (t != null) + { + TheSpawnObject.SpawnedObjects.Add(t); + } + } + else + { + IEntity e = World.FindEntity(serial); + + if (e != null) + TheSpawnObject.SpawnedObjects.Add(e); + } + } + } + // now have to reintegrate the later version spawnobject information into the earlier version desered objects + if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize) + { + for (int i = 0; i < SpawnListSize; ++i) + { + SpawnObject so = (SpawnObject)m_SpawnObjects[i]; + + so.SubGroup = (int)tmpSubGroup[i]; + so.SequentialResetTime = (double)tmpSequentialResetTime[i]; + so.SequentialResetTo = (int)tmpSequentialResetTo[i]; + so.KillsNeeded = (int)tmpKillsNeeded[i]; + if (version > 19) + so.RequireSurface = (bool)tmpRequireSurface[i]; + bool restrictkills = false; + bool clearadvance = true; + double mind = -1; + double maxd = -1; + DateTime nextspawn = DateTime.MinValue; + if (version > 23) + { + restrictkills = (bool)tmpRestrictKillsToSubgroup[i]; + clearadvance = (bool)tmpClearOnAdvance[i]; + mind = (double)tmpMinDelay[i]; + maxd = (double)tmpMaxDelay[i]; + nextspawn = (DateTime)tmpNextSpawn[i]; + } + so.RestrictKillsToSubgroup = restrictkills; + so.ClearOnAdvance = clearadvance; + so.MinDelay = mind; + so.MaxDelay = maxd; + so.NextSpawn = nextspawn; + + bool disablespawn = false; + if (version > 26) + { + disablespawn = (bool)tmpDisableSpawn[i]; + } + so.Disabled = disablespawn; + + int packrange = -1; + if (version > 27) + { + packrange = (int)tmpPackRange[i]; + } + so.PackRange = packrange; + + int spawnsper = 1; + if (version > 28) + { + spawnsper = (int)tmpSpawnsPer[i]; + } + so.SpawnsPerTick = spawnsper; + + } + } + + break; + } + } + } + + internal string GetSerializedObjectList() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + foreach (SpawnObject so in m_SpawnObjects) + { + if (sb.Length > 0) + sb.Append(':'); // ':' Separates multiple object types + + sb.AppendFormat("{0}={1}", so.TypeName, so.ActualMaxCount); // '=' separates object name from maximum amount + } + + return sb.ToString(); + } + + internal string GetSerializedObjectList2() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + foreach (SpawnObject so in m_SpawnObjects) + { + if (sb.Length > 0) + sb.Append(":OBJ="); // Separates multiple object types + + sb.AppendFormat("{0}:MX={1}:SB={2}:RT={3}:TO={4}:KL={5}:RK={6}:CA={7}:DN={8}:DX={9}:SP={10}:PR={11}", + so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded, + so.RestrictKillsToSubgroup ? 1 : 0, so.ClearOnAdvance ? 1 : 0, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange); + } + + return sb.ToString(); + } + + #endregion + + #region Spawn classes + + public class SpawnObject + { + private string m_TypeName; + private int m_MaxCount; + private int m_SubGroup; + private int m_SequentialResetTo; + private int m_KillsNeeded; + private bool m_RestrictKillsToSubgroup = false; + private bool m_ClearOnAdvance = true; + private double m_MinDelay = -1; + private double m_MaxDelay = -1; + private int m_SpawnsPerTick = 1; + private bool m_Disabled = false; + private int m_PackRange = -1; + private bool m_Ignore = false; + // temporary variable used to calculate weighted spawn probabilities + public bool Available; + + + public ArrayList SpawnedObjects; + public string[] PropertyArgs; + public double SequentialResetTime; + public int EntryOrder; // used for sorting + public bool RequireSurface = true; + public DateTime NextSpawn; + public bool SpawnedThisTick; + + // these are externally accessible to the SETONSPAWNENTRY keyword + public string TypeName { get { return m_TypeName; } set { m_TypeName = value; } } + public int MaxCount + { + get + { + if (Disabled) + { + return 0; + } + else + { + return m_MaxCount; + } + } + set + { + m_MaxCount = value; + } + } + public int ActualMaxCount { get { return m_MaxCount; } set { m_MaxCount = value; } } + public int SubGroup { get { return m_SubGroup; } set { m_SubGroup = value; } } + public int SpawnsPerTick { get { return m_SpawnsPerTick; } set { m_SpawnsPerTick = value; } } + public int SequentialResetTo { get { return m_SequentialResetTo; } set { m_SequentialResetTo = value; } } + public int KillsNeeded { get { return m_KillsNeeded; } set { m_KillsNeeded = value; } } + public bool RestrictKillsToSubgroup { get { return m_RestrictKillsToSubgroup; } set { m_RestrictKillsToSubgroup = value; } } + public bool ClearOnAdvance { get { return m_ClearOnAdvance; } set { m_ClearOnAdvance = value; } } + public double MinDelay { get { return m_MinDelay; } set { m_MinDelay = value; } } + public double MaxDelay { get { return m_MaxDelay; } set { m_MaxDelay = value; } } + public bool Disabled { get { return m_Disabled; } set { m_Disabled = value; } } + public bool Ignore { get { return m_Ignore; } set { m_Ignore = value; } } + public int PackRange { get { return m_PackRange; } set { m_PackRange = value; } } + + + // command loggable constructor + public SpawnObject(Mobile from, XmlSpawner spawner, string name, int maxamount) + { + + if (from != null && spawner != null) + { + bool found = false; + // go through the current spawner objects and see if this is a new entry + if (spawner.m_SpawnObjects != null) + { + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + SpawnObject s = spawner.m_SpawnObjects[i] as SpawnObject; + if (s != null && s.TypeName == name) + { + found = true; + break; + } + } + } + + if (!found) + { + CommandLogging.WriteLine(from, "{0} {1} added to XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), spawner.Serial, spawner.Name, spawner.GetWorldLocation().X, spawner.GetWorldLocation().Y, spawner.Map, name); + + } + } + + TypeName = name; + MaxCount = maxamount; + SubGroup = 0; + SequentialResetTime = 0; + SequentialResetTo = 0; + KillsNeeded = 0; + RestrictKillsToSubgroup = false; + ClearOnAdvance = true; + SpawnedObjects = new ArrayList(); + } + + public SpawnObject(string name, int maxamount) + { + TypeName = name; + MaxCount = maxamount; + SubGroup = 0; + SequentialResetTime = 0; + SequentialResetTo = 0; + KillsNeeded = 0; + RestrictKillsToSubgroup = false; + ClearOnAdvance = true; + SpawnedObjects = new ArrayList(); + } + + public SpawnObject(string name, int maxamount, int subgroup, double sequentialresettime, int sequentialresetto, int killsneeded, + bool restrictkills, bool clearadvance, double mindelay, double maxdelay, int spawnsper, int packrange) + { + TypeName = name; + MaxCount = maxamount; + SubGroup = subgroup; + SequentialResetTime = sequentialresettime; + SequentialResetTo = sequentialresetto; + KillsNeeded = killsneeded; + RestrictKillsToSubgroup = restrictkills; + ClearOnAdvance = clearadvance; + MinDelay = mindelay; + MaxDelay = maxdelay; + SpawnsPerTick = spawnsper; + PackRange = packrange; + SpawnedObjects = new ArrayList(); + } + + internal static string GetParm(string str, string separator) + { + // find the parm separator in the string + // then look for the termination at the ':' or end of string + // and return the stuff between + string[] arg = BaseXmlSpawner.SplitString(str, separator); + //should be 2 args + if (arg.Length > 1) + { + // look for the end of parm terminator (could also be eol) + string[] parm = arg[1].Split(':'); + if (parm.Length > 0) + { + return (parm[0]); + } + } + return (null); + } + + + internal static SpawnObject[] LoadSpawnObjectsFromString(string ObjectList) + { + // Clear the spawn object list + ArrayList NewSpawnObjects = new ArrayList(); + + if (ObjectList != null && ObjectList.Length > 0) + { + // Split the string based on the object separator first ':' + string[] SpawnObjectList = ObjectList.Split(':'); + + // Parse each item in the array + foreach (string s in SpawnObjectList) + { + // Split the single spawn object item by the max count '=' + string[] SpawnObjectDetails = s.Split('='); + + // Should be two entries + if (SpawnObjectDetails.Length == 2) + { + // Validate the information + + // Make sure the spawn object name part has a valid length + if (SpawnObjectDetails[0].Length > 0) + { + // Make sure the max count part has a valid length + if (SpawnObjectDetails[1].Length > 0) + { + int maxCount = 1; + + try + { + maxCount = int.Parse(SpawnObjectDetails[1]); + } + catch (System.Exception) + { // Something went wrong, leave the default amount } + } + + // Create the spawn object and store it in the array list + SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount); + NewSpawnObjects.Add(so); + } + } + } + } + } + + return (SpawnObject[])NewSpawnObjects.ToArray(typeof(SpawnObject)); + } + + + + internal static SpawnObject[] LoadSpawnObjectsFromString2(string ObjectList) + { + // Clear the spawn object list + ArrayList NewSpawnObjects = new ArrayList(); + + // spawn object definitions will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int + // or typestring:MX=int:SB=int:RT=double:TO=int:KL=int:OBJ=typestring... + if (ObjectList != null && ObjectList.Length > 0) + { + string[] SpawnObjectList = BaseXmlSpawner.SplitString(ObjectList, ":OBJ="); + + // Parse each item in the array + foreach (string s in SpawnObjectList) + { + // at this point each spawn string will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int + // Split the single spawn object item by the max count to get the typename and the remaining parms + string[] SpawnObjectDetails = BaseXmlSpawner.SplitString(s, ":MX="); + + // Should be two entries + if (SpawnObjectDetails.Length == 2) + { + // Validate the information + + // Make sure the spawn object name part has a valid length + if (SpawnObjectDetails[0].Length > 0) + { + // Make sure the parm part has a valid length + if (SpawnObjectDetails[1].Length > 0) + { + // now parse out the parms + // MaxCount + string parmstr = GetParm(s, ":MX="); + int maxCount = 1; + try { maxCount = int.Parse(parmstr); } + catch { } + + // SubGroup + parmstr = GetParm(s, ":SB="); + + int subGroup = 0; + try { subGroup = int.Parse(parmstr); } + catch { } + + // SequentialSpawnResetTime + parmstr = GetParm(s, ":RT="); + double resetTime = 0; + try { resetTime = double.Parse(parmstr); } + catch { } + + // SequentialSpawnResetTo + parmstr = GetParm(s, ":TO="); + int resetTo = 0; + try { resetTo = int.Parse(parmstr); } + catch { } + + // KillsNeeded + parmstr = GetParm(s, ":KL="); + int killsNeeded = 0; + try { killsNeeded = int.Parse(parmstr); } + catch { } + + // RestrictKills + parmstr = GetParm(s, ":RK="); + bool restrictKills = false; + if (parmstr != null) + try { restrictKills = (int.Parse(parmstr) == 1); } + catch { } + + // ClearOnAdvance + parmstr = GetParm(s, ":CA="); + bool clearAdvance = true; + // if kills needed is zero, then set CA to false by default. This maintains consistency with the + // previous default behavior for old spawn specs that havent specified CA + if (killsNeeded == 0) + clearAdvance = false; + if (parmstr != null) + try { clearAdvance = (int.Parse(parmstr) == 1); } + catch { } + + // MinDelay + parmstr = GetParm(s, ":DN="); + double minD = -1; + try { minD = double.Parse(parmstr); } + catch { } + + // MaxDelay + parmstr = GetParm(s, ":DX="); + double maxD = -1; + try { maxD = double.Parse(parmstr); } + catch { } + + // SpawnsPerTick + parmstr = GetParm(s, ":SP="); + int spawnsPer = 1; + try { spawnsPer = int.Parse(parmstr); } + catch { } + + // PackRange + parmstr = GetParm(s, ":PR="); + int packRange = -1; + try { packRange = int.Parse(parmstr); } + catch { } + + // Create the spawn object and store it in the array list + SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount, subGroup, resetTime, resetTo, killsNeeded, + restrictKills, clearAdvance, minD, maxD, spawnsPer, packRange); + + NewSpawnObjects.Add(so); + } + } + } + } + } + + return (SpawnObject[])NewSpawnObjects.ToArray(typeof(SpawnObject)); + } + } + + + #endregion + + } +} + diff --git a/Scripts/Customs/XML Spawner/XmlSpawnerGumps.cs b/Scripts/Customs/XML Spawner/XmlSpawnerGumps.cs new file mode 100644 index 0000000..6cb4847 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlSpawnerGumps.cs @@ -0,0 +1,1613 @@ +#define NEWPROPSGUMP +#define BOOKTEXTENTRY + +using System; +using System.Data; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; + +/* +** Changelog +** +** 8/15/04 +** - fixed a crash bug when using the goto spawn button on an empty spawn entry +** +** 8/10/04 +** - added a goto-spawn button in the spawner gump (to the right of the text entry area, next to the text entry gump button) that will take you to the location of +** currently spawned objects for a given spawner entry. If there are multiple spawned objects for an entry, it will cycle through them with repeated clicks. +** Useful for tracking down spawns. +** 3/23/04 +** changed spawner name font color for 3dclient compatibility +*/ + +namespace Server.Mobiles +{ + public class HelpGump : Gump + { + public XmlSpawner m_Spawner; + private XmlSpawnerGump m_SpawnerGump; + + public HelpGump(XmlSpawner spawner, XmlSpawnerGump spawnergump, int X, int Y) + : base(X, Y) + { + if (spawner == null || spawner.Deleted) + return; + m_Spawner = spawner; + m_SpawnerGump = spawnergump; + + AddPage(0); + + int width = 370; + + AddBackground(20, 0, width, 480, 5054); + + AddPage(1); + //AddAlphaRegion( 20, 0, 220, 554 ); + AddImageTiled(20, 0, width, 480, 0x52); + //AddImageTiled( 24, 6, 213, 261, 0xBBC ); + + AddLabel(27, 2, 0x384, "Standalone Keywords"); + AddHtml(25, 20, width - 10, 440, + "spawntype[,arg1,arg2,...]\n" + + "SET[,itemname or serialno][,itemtype]/property/value/...\n" + + "SETVAR,varname/value\n" + + "SETONMOB,mobname[,mobtype]/property/value/...\n" + + "SETONTRIGMOB/property/value/...\n" + + "SETONTHIS/property/value/...\n" + + "SETONPARENT/property/value/...\n" + + "SETONNEARBY,range,name[,type][,searchcontainers]/prop/value/prop/value...\n" + + "SETONPETS,range/prop/value/prop/value...\n" + + "SETONCARRIED,itemname[,itemtype][,equippedonly]/property/value/...\n" + + "SETONSPAWN[,spawnername],subgroup/property/value/...\n" + + "SETONSPAWNENTRY[,spawnername],entrystring/property/value/...\n" + + "SPAWN[,spawnername],subgroup\n" + + "DESPAWN[,spawnername],subgroup\n" + + "{GET or RND keywords}\n" + + "GIVE[,prob]/itemtype\n" + + "GIVE[,prob]/<itemtype/property/value...>\n" + + "TAKE[,prob[,quantity[,true[,itemtype]]]]/itemname\n" + + "TAKEBYTYPE[,prob[,quantity[,true]]]/itemtype\n" + + "IF/condition/thenspawn[/elsespawn]\n" + + "WAITUNTIL[,duration][,timeout][/condition][/spawngroup]\n" + + "WHILE/condition/spawngroup\n" + + "GOTO/subgroup\n" + + "BROWSER/url\n" + + "MUSIC,musicname[,range]\n" + + "SOUND,value\n" + + "EFFECT,itemid,duration[,x,y,z]\n" + + "MEFFECT,itemid[,speed][,x,y,z][,x2,y2,z2]" + + "RESURRECT[,range][,PETS]\n" + + "POISON,level[,range][,playeronly]\n" + + "DAMAGE,dmg,phys,fire,cold,pois,energy[,range][,playeronly]\n" + + "CAST,spellname[,arg] or CAST,spellnumber[,arg]\n" + + "SENDMSG/text\n" + + "BCAST[,hue][,font]/text\n" + + "GUMP,title,number[,gumpconstructor]/text", + false, true); + AddButton(width - 30, 5, 0x15E1, 0x15E5, 200, GumpButtonType.Page, 2); + AddLabel(width - 38, 2, 0x384, "1"); + AddButton(width - 60, 5, 0x15E3, 0x15E7, 200, GumpButtonType.Page, 4); + + AddPage(2); + AddLabel(27, 2, 0x384, "Value and Itemtype Keywords"); + AddHtml(25, 20, width - 10, 440, + "property/@value\n" + + "ARMOR,minlevel,maxlevel\n" + + "WEAPON,minlevel,maxlevel\n" + + "JARMOR,minlevel,maxlevel\n" + + "JWEAPON,minlevel,maxlevel\n" + + "JEWELRY,minlevel,maxlevel\n" + + "SARMOR,minlevel,maxlevel\n" + + "SHIELD,minlevel,maxlevel\n" + + "POTION\n" + + "SCROLL,mincircle,maxcircle\n" + + "NECROSCROLL,index\n" + + "LOOT,methodname\n" + + "LOOTPACK,loottype\n" + + "MOB,name[,mobtype]\n" + + "TRIGMOB\n" + + "TAKEN\n" + + "GIVEN\n" + + "GET,itemname or serialno[,itemtype],property\n" + + "GETVAR,varname\n" + + "GETONCARRIED,itemname[,itemtype][,equippedonly],property\n" + + "GETONNEARBY,range,name[,type][,searchcontainers],property\n" + + "GETONMOB,mobname[,mobtype],property\n" + + "GETONGIVEN,property\n" + + "GETONTAKEN,property\n" + + "GETONPARENT,property\n" + + "GETONSPAWN[,spawnername],subgroup,property\n" + + "GETONSPAWN[,spawnername],subgroup,COUNT\n" + + "GETONTHIS,property\n" + + "GETONTRIGMOB,property\n" + + "GETONATTACH,type[,name],property\n" + + "...<ATTACHMENT,type,name,property> as GET property\n" + + "{GET or RND keywords}\n" + + "RND,min,max\n" + + "RNDLIST,int1[,int2,...]\n" + + "RNDSTRLIST,str1[,str2,...]\n" + + "RNDBOOL\n" + + "RANDNAME,nametype\n" + + "PLAYERSINRANGE,range\n" + + "AMOUNTCARRIED,itemtype\n" + + "OFFSET,x,y,[,z]\n" + + "ANIMATE,action[,nframes][,nrepeat][,forward][,repeat][delay]\n" + + "MSG[,prob]/text\n" + + "SENDASCIIMSG[,probability][,hue][,font/text\n" + + "SENDMSG[,probability][,hue]/text\n" + + "SAY[,prob]/text\n" + + "SKILL,skillname\n" + + "TRIGSKILL,name|value|base|cap\n" + + "MUSIC,musicname[,range]\n" + + "SOUND,value\n" + + "EFFECT,itemid,duration[,x,y,z]\n" + + "MEFFECT,itemid[,speed][,x,y,z]" + + "POISON,level[,range][,playeronly]\n" + + "DAMAGE,dmg,phys,fire,cold,pois,energy[,range][,playeronly]\n" + + "INC,value or INC,min,max\n" + + "MUL,value or MUL,min,max\n" + + "ATTACH[,prob]/attachmenttype[,args]\n" + + "ATTACH[,prob]/<attachmenttype[,args]/property/value...>\n" + + "ADD[,prob]/itemtype[,args]\n" + + "ADD[,prob]/<itemtype[,args]/property/value...>\n" + + "DELETE\n" + + "KILL\n" + + "UNEQUIP,layer[,delete]\n" + + "EQUIP[,prob]/itemtype[,args]\n" + + "EQUIP[,prob]/<itemtype[,args]/property/value...>", + false, true); + AddButton(width - 30, 5, 0x15E1, 0x15E5, 200, GumpButtonType.Page, 3); + AddLabel(width - 41, 2, 0x384, "2"); + AddButton(width - 60, 5, 0x15E3, 0x15E7, 200, GumpButtonType.Page, 1); + + AddPage(3); + AddLabel(27, 2, 0x384, "[ Commands"); + + AddHtml(25, 20, width - 10, 440, + "XmlAdd [-defaults]\n" + + "XmlShow\n" + + "XmlHide\n" + + "XmlFind\n" + + "AddAtt type [args]\n" + + "GetAtt [type]\n" + + "DelAtt [type][serialno]\n" + + "AvailAtt\n" + + "SmartStat [accesslevel AccessLevel]\n" + + "OptimalSmartSpawning [maxdiff]\n" + + "XmlSpawnerWipe [prefix]\n" + + "XmlSpawnerWipeAll [prefix]\n" + + "XmlSpawnerRespawn [prefix]\n" + + "XmlSpawnerRespawnAll [prefix]\n" + + "XmlHome [go][gump][send]\n" + + "XmlUnLoad filename [prefix]\n" + + "XmlLoad filename [prefix]\n" + + "XmlLoadHere filename [prefix][-maxrange range]\n" + + "XmlNewLoad filename [prefix]\n" + + "XmlNewLoadHere filename [prefix][-maxrange range]\n" + + "XmlSave filename [prefix]\n" + + "XmlSaveAll filename [prefix]\n" + + "XmlSaveOld filename [prefix]\n" + + "XmlSpawnerSaveAll filename [prefix]\n" + + "XmlImportSpawners filename\n" + + "XmlImportMap filename\n" + + "XmlImportMSF filename\n" + + "XmlDefaults [defaultpropertyname value]\n" + + "XmlGet property\n" + + "XmlSet property value", + false, true); + + AddButton(width - 30, 5, 0x15E1, 0x15E5, 200, GumpButtonType.Page, 4); + AddLabel(width - 41, 2, 0x384, "3"); + AddButton(width - 60, 5, 0x15E3, 0x15E7, 200, GumpButtonType.Page, 2); + + AddPage(4); + AddLabel(27, 2, 0x384, "Quest types"); + AddHtml(25, 20, width - 10, 180, + "KILL,mobtype[,count][,proptest]\n" + + "KILLNAMED,mobname[,type][,count][,proptest]\n" + + "GIVE,mobname,itemtype[,count][,proptest]\n" + + "GIVENAMED,mobname,itemname[,type][,count][,proptest]\n" + + "COLLECT,itemtype[,count][,proptest]\n" + + "COLLECTNAMED,itemname[,itemtype][,count][,proptest]\n" + + "ESCORT[,mobname][,proptest]\n", + false, true); + + AddLabel(27, 200, 0x384, "Trigger/NoTriggerOnCarried"); + AddHtml(25, 220, width - 10, 50, + "ATTACHMENT,name,type\n" + + "itemname[,type][,EQUIPPED][,objective#,objective#,...]\n", + false, true); + + AddLabel(27, 300, 0x384, "GUMPITEMS"); + AddHtml(25, 320, width - 10, 150, + "BUTTON,gumpid,x,y\n" + + "HTML,x,y,width,height,text\n" + + "IMAGE,gumpid,x,y[,hue]\n" + + "IMAGETILED,gumpid,x,y,width,height\n" + + "ITEM,itemid,x,y[,hue]\n" + + "LABEL,x,y,labelstring[,labelcolor]\n" + + "RADIO,gumpid1,gumpid2,x,y[,initialstate]\n" + + "TEXTENTRY,x,y,width,height[,text][,textcolor]\n", + false, true); + + AddButton(width - 30, 5, 0x15E1, 0x15E5, 200, GumpButtonType.Page, 1); + AddLabel(width - 41, 2, 0x384, "4"); + AddButton(width - 60, 5, 0x15E3, 0x15E7, 200, GumpButtonType.Page, 3); + } + } + public class TextEntryGump : Gump + { + private XmlSpawner m_Spawner; + private int m_index; + private XmlSpawnerGump m_SpawnerGump; + + public TextEntryGump(XmlSpawner spawner, XmlSpawnerGump spawnergump, int index, int X, int Y) + : base(X, Y) + { + if (spawner == null || spawner.Deleted) + return; + m_Spawner = spawner; + m_index = index; + m_SpawnerGump = spawnergump; + + AddPage(0); + + AddBackground(20, 0, 220, 354, 5054); + AddAlphaRegion(20, 0, 220, 354); + AddImageTiled(23, 5, 214, 270, 0x52); + AddImageTiled(24, 6, 213, 261, 0xBBC); + + string label = spawner.Name + " entry " + index; + AddLabel(28, 10, 0x384, label); + + // OK button + AddButton(25, 325, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0); + // Close button + AddButton(205, 325, 0xFB1, 0xFB3, 0, GumpButtonType.Reply, 0); + // Edit button + AddButton(100, 325, 0xEF, 0xEE, 2, GumpButtonType.Reply, 0); + string str = null; + if (index < m_Spawner.SpawnObjects.Length) + { + str = (string)m_Spawner.SpawnObjects[index].TypeName; + } + // main text entry area + AddTextEntry(35, 30, 200, 251, 0, 0, str); + + // editing text entry areas + // background for text entry area + AddImageTiled(23, 275, 214, 23, 0x52); + AddImageTiled(24, 276, 213, 21, 0xBBC); + AddImageTiled(23, 300, 214, 23, 0x52); + AddImageTiled(24, 301, 213, 21, 0xBBC); + + AddTextEntry(35, 275, 200, 21, 0, 1, null); + AddTextEntry(35, 300, 200, 21, 0, 2, null); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null) return; + + if (m_Spawner == null || m_Spawner.Deleted) + return; + bool update_entry = false; + bool edit_entry = false; + switch (info.ButtonID) + { + case 0: // Close + { + update_entry = false; + break; + } + case 1: // Okay + { + update_entry = true; + break; + } + case 2: // Edit + { + edit_entry = true; + break; + } + default: + update_entry = true; + break; + } + if (edit_entry) + { + // get the old text + TextRelay entry = info.GetTextEntry(1); + string oldtext = entry.Text; + // get the new text + entry = info.GetTextEntry(2); + string newtext = entry.Text; + // make the substitution + entry = info.GetTextEntry(0); + string origtext = entry.Text; + if (origtext != null && oldtext != null && newtext != null) + { + try + { + int firstindex = origtext.IndexOf(oldtext); + if (firstindex >= 0) + { + + + int secondindex = firstindex + oldtext.Length; + + int lastindex = origtext.Length - 1; + + string editedtext; + if (firstindex > 0) + { + editedtext = origtext.Substring(0, firstindex) + newtext + origtext.Substring(secondindex, lastindex - secondindex + 1); + } + else + { + editedtext = newtext + origtext.Substring(secondindex, lastindex - secondindex + 1); + } + + if (m_index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[m_index].TypeName = editedtext; + } + else + { + // Update the creature list + m_Spawner.SpawnObjects = m_SpawnerGump.CreateArray(info, state.Mobile); + } + } + } + catch { } + + } + // open a new text entry gump + state.Mobile.SendGump(new TextEntryGump(m_Spawner, m_SpawnerGump, m_index, this.X, this.Y)); + return; + } + if (update_entry) + { + TextRelay entry = info.GetTextEntry(0); + if (m_index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[m_index].TypeName = entry.Text; + } + else + { + // Update the creature list + m_Spawner.SpawnObjects = m_SpawnerGump.CreateArray(info, state.Mobile); + } + } + // Create a new gump + + //m_Spawner.OnDoubleClick( state.Mobile); + // open a new spawner gump + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, m_SpawnerGump.m_ShowGump, m_SpawnerGump.xoffset, m_SpawnerGump.page)); + } + } + + + + public class XmlSpawnerGump : Gump + { + private static int nclicks = 0; + public XmlSpawner m_Spawner; + public const int MaxSpawnEntries = 60; + private const int MaxEntriesPerPage = 15; + public int m_ShowGump = 0; + public bool AllowGumpUpdate = true; + public int xoffset = 0; + public int initial_maxcount; + public int page; + public ReplacementEntry Rentry; + + public class ReplacementEntry + { + public string Typename; + public int Index; + public int Color; + + public ReplacementEntry() + { + } + } + + public XmlSpawnerGump(XmlSpawner spawner, int X, int Y, int extension, int textextension, int newpage) + : this(spawner, X, Y, extension, textextension, newpage, null) + { + } + + public XmlSpawnerGump(XmlSpawner spawner, int X, int Y, int extension, int textextension, int newpage, ReplacementEntry rentry) + : base(X, Y) + { + if (spawner == null || spawner.Deleted) + return; + + m_Spawner = spawner; + spawner.SpawnerGump = this; + xoffset = textextension; + initial_maxcount = spawner.MaxCount; + page = newpage; + Rentry = rentry; + + AddPage(0); + + // automatically change the gump depending on whether sequential spawning and/or subgroups are activated + + if (spawner.SequentialSpawn >= 0 || spawner.HasSubGroups() || spawner.HasIndividualSpawnTimes()) + { + // show the fully extended gump with subgroups and reset timer info + m_ShowGump = 2; + } + /* + else + if(spawner.HasSubGroups() || spawner.SequentialSpawn >= 0) + { + // show partially extended gump with subgroups + m_ShowGump = 1; + } + */ + + if (extension > 0) + { + m_ShowGump = extension; + } + if (extension < 0) + { + m_ShowGump = 0; + } + + // if the expanded gump toggle has been activated then override the auto settings. + + + if (m_ShowGump > 1) + { + AddBackground(0, 0, 670 + xoffset + 30, 474, 5054); + AddAlphaRegion(0, 0, 670 + xoffset + 30, 474); + } + else + if (m_ShowGump > 0) + { + AddBackground(0, 0, 335 + xoffset, 474, 5054); + AddAlphaRegion(0, 0, 335 + xoffset, 474); + } + else + { + AddBackground(0, 0, 305 + xoffset, 474, 5054); + AddAlphaRegion(0, 0, 305 + xoffset, 474); + } + + // spawner name area + AddImageTiled(3, 5, 227, 23, 0x52); + AddImageTiled(4, 6, 225, 21, 0xBBC); + AddTextEntry(6, 5, 222, 21, 0, 999, spawner.Name); // changed from color 50 + + AddButton(5, 450, 0xFAE, 0xFAF, 4, GumpButtonType.Reply, 0); + AddLabel(38, 450, 0x384, "Goto"); + + //AddButton( 5, 428, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0 ); + AddButton(5, 428, 0xFAE, 0xFAF, 1, GumpButtonType.Reply, 0); + AddLabel(38, 428, 0x384, "Help"); + + AddButton(80, 428, 0xFB4, 0xFB6, 2, GumpButtonType.Reply, 0); + AddLabel(113, 428, 0x384, "Bring Home"); + + AddButton(80, 450, 0xFA8, 0xFAA, 3, GumpButtonType.Reply, 0); + AddLabel(113, 450, 0x384, "Respawn"); + + // Props button + AddButton(200, 428, 0xFAB, 0xFAD, 9999, GumpButtonType.Reply, 0); + AddLabel(233, 428, 0x384, "Props"); + + // Sort button + AddButton(200, 450, 0xFAB, 0xFAD, 702, GumpButtonType.Reply, 0); + AddLabel(233, 450, 0x384, "Sort"); + + // Reset button + AddButton(80, 406, 0xFA2, 0xFA3, 701, GumpButtonType.Reply, 0); + AddLabel(113, 406, 0x384, "Reset"); + + // Refresh button + AddButton(200, 406, 0xFBD, 0xFBE, 9998, GumpButtonType.Reply, 0); + AddLabel(233, 406, 0x384, "Refresh"); + + // add run status display + if (m_Spawner.Running) + { + AddButton(5, 399, 0x2A4E, 0x2A3A, 700, GumpButtonType.Reply, 0); + AddLabel(38, 406, 0x384, "On"); + } + else + { + AddButton(5, 399, 0x2A62, 0x2A3A, 700, GumpButtonType.Reply, 0); + AddLabel(38, 406, 0x384, "Off"); + } + + // Add sequential spawn state + if (m_Spawner.SequentialSpawn >= 0) + { + AddLabel(15, 365, 33, String.Format("{0}", m_Spawner.SequentialSpawn)); + } + + // Add Current / Max count labels + AddLabel(231 + xoffset, 9, 68, "Count"); + AddLabel(270 + xoffset, 9, 33, "Max"); + + if (m_ShowGump > 0) + { + // Add subgroup label + AddLabel(334 + xoffset, 9, 68, "Sub"); + } + if (m_ShowGump > 1) + { + // Add entry field labels + AddLabel(303 + xoffset, 9, 68, "Per"); + AddLabel(329 + xoffset + 30, 9, 68, "Reset"); + AddLabel(368 + xoffset + 30, 9, 68, "To"); + AddLabel(392 + xoffset + 30, 9, 68, "Kills"); + AddLabel(432 + xoffset + 30, 9, 68, "MinD"); + AddLabel(472 + xoffset + 30, 9, 68, "MaxD"); + AddLabel(515 + xoffset + 30, 9, 68, "Rng"); + AddLabel(545 + xoffset + 30, 9, 68, "RK"); + AddLabel(565 + xoffset + 30, 9, 68, "Clr"); + AddLabel(590 + xoffset + 30, 9, 68, "NextSpawn"); + } + + // add area for spawner max + AddLabel(180 + xoffset, 365, 50, "Spawner"); + AddImageTiled(267 + xoffset, 365, 35, 23, 0x52); + AddImageTiled(268 + xoffset, 365, 32, 21, 0xBBC); + AddTextEntry(273 + xoffset, 365, 33, 33, 33, 300, m_Spawner.MaxCount.ToString()); + + // add area for spawner count + AddImageTiled(231 + xoffset, 365, 35, 23, 0x52); + AddImageTiled(232 + xoffset, 365, 32, 21, 0xBBC); + AddLabel(233 + xoffset, 365, 68, m_Spawner.CurrentCount.ToString()); + + // add the status string + AddTextEntry(38, 384, 235, 33, 33, 900, m_Spawner.status_str); + // add the page buttons + for (int i = 0; i < (int)(MaxSpawnEntries / MaxEntriesPerPage); i++) + { + //AddButton( 38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i ); + AddButton(38 + i * 25, 365, 0x8B1 + i, 0x8B1 + i, 4000 + i, GumpButtonType.Reply, 0); + } + + // add gump extension button + if (m_ShowGump > 1) + AddButton(645 + xoffset + 30, 450, 0x15E3, 0x15E7, 200, GumpButtonType.Reply, 0); + else + if (m_ShowGump > 0) + AddButton(315 + xoffset, 450, 0x15E1, 0x15E5, 200, GumpButtonType.Reply, 0); + else + AddButton(285 + xoffset, 450, 0x15E1, 0x15E5, 200, GumpButtonType.Reply, 0); + + // add the textentry extender button + if (xoffset > 0) + { + AddButton(160, 365, 0x15E3, 0x15E7, 201, GumpButtonType.Reply, 0); + } + else + { + AddButton(160, 365, 0x15E1, 0x15E5, 201, GumpButtonType.Reply, 0); + } + + + for (int i = 0; i < MaxSpawnEntries; i++) + { + if (page != (int)(i / MaxEntriesPerPage)) continue; + + string str = String.Empty; + int texthue = 0; + int background = 0xBBC; + + if (i % MaxEntriesPerPage == 0) + { + //AddPage(page+1); + // add highlighted page button + AddImageTiled(35 + page * 25, 363, 25, 25, 0xBBC); + AddImage(38 + page * 25, 365, 0x8B1 + page); + } + + if (i < m_Spawner.SpawnObjects.Length) + { + // disable button + + if (m_Spawner.SpawnObjects[i].Disabled) + { + // change the background for the spawn text entry if disabled + background = 0x23F4; + AddButton(2, 22 * (i % MaxEntriesPerPage) + 34, 0x82C, 0x82C, 6000 + i, GumpButtonType.Reply, 0); + } + else + { + AddButton(2, 22 * (i % MaxEntriesPerPage) + 36, 0x837, 0x837, 6000 + i, GumpButtonType.Reply, 0); + } + + + } + + bool hasreplacement = false; + + // check for replacement entries + if (Rentry != null && Rentry.Index == i) + { + hasreplacement = true; + str = Rentry.Typename; + background = Rentry.Color; + // replacement is one time only. + Rentry = null; + + } + + + // increment/decrement buttons + AddButton(15, 22 * (i % MaxEntriesPerPage) + 34, 0x15E0, 0x15E4, 6 + (i * 2), GumpButtonType.Reply, 0); + AddButton(30, 22 * (i % MaxEntriesPerPage) + 34, 0x15E2, 0x15E6, 7 + (i * 2), GumpButtonType.Reply, 0); + + // categorization gump button + AddButton(171 + xoffset - 18, 22 * (i % MaxEntriesPerPage) + 34, 0x15E1, 0x15E5, 5000 + i, GumpButtonType.Reply, 0); + + // goto spawn button + AddButton(171 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1300 + i, GumpButtonType.Reply, 0); + + // text entry gump button + AddButton(200 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 0xFAB, 0xFAD, 800 + i, GumpButtonType.Reply, 0); + + // background for text entry area + AddImageTiled(48, 22 * (i % MaxEntriesPerPage) + 30, 133 + xoffset - 25, 23, 0x52); + AddImageTiled(49, 22 * (i % MaxEntriesPerPage) + 31, 131 + xoffset - 25, 21, background); + + // Add page number + //AddLabel( 15, 365, 33, String.Format("{0}",(int)(i/MaxEntriesPerPage + 1)) ); + //AddButton( 38+page*25, 365, 0x8B1+i, 0x8B1+i, 0, GumpButtonType.Page, 1+i ); + + + + if (i < m_Spawner.SpawnObjects.Length) + { + if (!hasreplacement) + { + str = (string)m_Spawner.SpawnObjects[i].TypeName; + } + + int count = m_Spawner.SpawnObjects[i].SpawnedObjects.Count; + int max = m_Spawner.SpawnObjects[i].ActualMaxCount; + int subgrp = m_Spawner.SpawnObjects[i].SubGroup; + int spawnsper = m_Spawner.SpawnObjects[i].SpawnsPerTick; + + texthue = subgrp * 11; + if (texthue < 0) texthue = 0; + + // Add current count + AddImageTiled(231 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 35, 23, 0x52); + AddImageTiled(232 + xoffset, 22 * (i % MaxEntriesPerPage) + 31, 32, 21, 0xBBC); + AddLabel(233 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 68, count.ToString()); + + // Add maximum count + AddImageTiled(267 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 35, 23, 0x52); + AddImageTiled(268 + xoffset, 22 * (i % MaxEntriesPerPage) + 31, 32, 21, 0xBBC); + // AddTextEntry(x,y,w,ht,color,id,str) + AddTextEntry(270 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 30, 30, 33, 500 + i, max.ToString()); + + + if (m_ShowGump > 0) + { + // Add subgroup + AddImageTiled(334 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 25, 23, 0x52); + AddImageTiled(335 + xoffset, 22 * (i % MaxEntriesPerPage) + 31, 22, 21, 0xBBC); + AddTextEntry(338 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 17, 33, texthue, 600 + i, subgrp.ToString()); + } + if (m_ShowGump > 1) + { + // Add subgroup timer fields + + string strrst = null; + string strto = null; + string strkill = null; + string strmind = null; + string strmaxd = null; + string strnext = null; + string strpackrange = null; + string strspawnsper = spawnsper.ToString(); + + if (m_Spawner.SpawnObjects[i].SequentialResetTime > 0 && m_Spawner.SpawnObjects[i].SubGroup > 0) + { + strrst = m_Spawner.SpawnObjects[i].SequentialResetTime.ToString(); + strto = m_Spawner.SpawnObjects[i].SequentialResetTo.ToString(); + } + if (m_Spawner.SpawnObjects[i].KillsNeeded > 0) + { + strkill = m_Spawner.SpawnObjects[i].KillsNeeded.ToString(); + } + + if (m_Spawner.SpawnObjects[i].MinDelay >= 0) + { + strmind = m_Spawner.SpawnObjects[i].MinDelay.ToString(); + } + + if (m_Spawner.SpawnObjects[i].MaxDelay >= 0) + { + strmaxd = m_Spawner.SpawnObjects[i].MaxDelay.ToString(); + } + + if (m_Spawner.SpawnObjects[i].PackRange >= 0) + { + strpackrange = m_Spawner.SpawnObjects[i].PackRange.ToString(); + } + + if (m_Spawner.SpawnObjects[i].NextSpawn > DateTime.Now) + { + // if the next spawn tick of the spawner will occur after the subgroup is available for spawning + // then report the next spawn tick since that is the earliest that the subgroup can actually be spawned + if ((DateTime.Now + m_Spawner.NextSpawn) > m_Spawner.SpawnObjects[i].NextSpawn) + { + strnext = m_Spawner.NextSpawn.ToString(); + } + else + { + // estimate the earliest the next spawn could occur as the first spawn tick after reaching the subgroup nextspawn + strnext = (m_Spawner.SpawnObjects[i].NextSpawn - DateTime.Now + m_Spawner.NextSpawn).ToString(); + } + } + else + { + strnext = m_Spawner.NextSpawn.ToString(); + } + + int yoff = 22 * (i % MaxEntriesPerPage) + 30; + + // spawns per tick + AddImageTiled(303 + xoffset, yoff, 30, 23, 0x52); + AddImageTiled(304 + xoffset, yoff + 1, 27, 21, 0xBBC); + AddTextEntry(307 + xoffset, yoff, 22, 33, texthue, 1500 + i, strspawnsper); + // reset time + AddImageTiled(329 + xoffset + 30, yoff, 35, 23, 0x52); + AddImageTiled(330 + xoffset + 30, yoff + 1, 32, 21, 0xBBC); + AddTextEntry(333 + xoffset + 30, yoff, 27, 33, texthue, 1000 + i, strrst); + // reset to + AddImageTiled(365 + xoffset + 30, yoff, 26, 23, 0x52); + AddImageTiled(366 + xoffset + 30, yoff + 1, 23, 21, 0xBBC); + AddTextEntry(369 + xoffset + 30, yoff, 18, 33, texthue, 1100 + i, strto); + // kills needed + AddImageTiled(392 + xoffset + 30, yoff, 35, 23, 0x52); + AddImageTiled(393 + xoffset + 30, yoff + 1, 32, 21, 0xBBC); + AddTextEntry(396 + xoffset + 30, yoff, 27, 33, texthue, 1200 + i, strkill); + + // mindelay + AddImageTiled(428 + xoffset + 30, yoff, 41, 23, 0x52); + AddImageTiled(429 + xoffset + 30, yoff + 1, 38, 21, 0xBBC); + AddTextEntry(432 + xoffset + 30, yoff, 33, 33, texthue, 1300 + i, strmind); + + // maxdelay + AddImageTiled(470 + xoffset + 30, yoff, 41, 23, 0x52); + AddImageTiled(471 + xoffset + 30, yoff + 1, 38, 21, 0xBBC); + AddTextEntry(474 + xoffset + 30, yoff, 33, 33, texthue, 1400 + i, strmaxd); + + // packrange + AddImageTiled(512 + xoffset + 30, yoff, 33, 23, 0x52); + AddImageTiled(513 + xoffset + 30, yoff + 1, 30, 21, 0xBBC); + AddTextEntry(516 + xoffset + 30, yoff, 25, 33, texthue, 1600 + i, strpackrange); + + if (m_Spawner.SequentialSpawn >= 0) + { + // restrict kills button + AddButton(545 + xoffset + 30, yoff, m_Spawner.SpawnObjects[i].RestrictKillsToSubgroup ? 0xD3 : 0xD2, + m_Spawner.SpawnObjects[i].RestrictKillsToSubgroup ? 0xD2 : 0xD3, 300 + i, GumpButtonType.Reply, 0); + + //clear on advance button for spawn entries in subgroups that require kills + AddButton(565 + xoffset + 30, yoff, m_Spawner.SpawnObjects[i].ClearOnAdvance ? 0xD3 : 0xD2, + m_Spawner.SpawnObjects[i].ClearOnAdvance ? 0xD2 : 0xD3, 400 + i, GumpButtonType.Reply, 0); + } + + // add the next spawn time + AddLabelCropped(590 + xoffset + 30, yoff, 70, 20, 55, strnext); + + } + + //AddButton( 20, 22 * (i%MaxEntriesPerPage) + 34, 0x15E3, 0x15E7, 5 + (i * 2), GumpButtonType.Reply, 0 ); + } + // the spawn specification text + //if(str != null) + AddTextEntry(52, 22 * (i % MaxEntriesPerPage) + 31, 119 + xoffset - 25, 21, texthue, i, str); + } + } + + public XmlSpawner.SpawnObject[] CreateArray(RelayInfo info, Mobile from) + { + ArrayList SpawnObjects = new ArrayList(); + + for (int i = 0; i < MaxSpawnEntries; i++) + { + TextRelay te = info.GetTextEntry(i); + + if (te != null) + { + string str = te.Text; + + if (str.Length > 0) + { + str = str.Trim(); +#if(BOOKTEXTENTRY) + if (i < m_Spawner.SpawnObjects.Length) + { + string currenttext = m_Spawner.SpawnObjects[i].TypeName; + if (currenttext != null && currenttext.Length >= 230) + { + str = currenttext; + } + } +#endif + string typestr = BaseXmlSpawner.ParseObjectType(str); + + Type type = null; + if (typestr != null) + { + try + { + type = SpawnerType.GetType(typestr); + } + catch { } + } + + if (type != null) + SpawnObjects.Add(new XmlSpawner.SpawnObject(from, m_Spawner, str, 0)); + else + { + // check for special keywords + if (typestr != null && (BaseXmlSpawner.IsTypeOrItemKeyword(typestr) || typestr.IndexOf("{") != -1 || typestr.StartsWith("*") || typestr.StartsWith("#"))) + { + SpawnObjects.Add(new XmlSpawner.SpawnObject(from, m_Spawner, str, 0)); + } + else + m_Spawner.status_str = String.Format("{0} is not a valid type name.", str); + //from.SendMessage( "{0} is not a valid type name.", str ); + } + + } + } + } + + return (XmlSpawner.SpawnObject[])SpawnObjects.ToArray(typeof(XmlSpawner.SpawnObject)); + } + + public void UpdateTypeNames(Mobile from, RelayInfo info) + { + for (int i = 0; i < MaxSpawnEntries; i++) + { + TextRelay te = info.GetTextEntry(i); + + if (te != null) + { + string str = te.Text; + + if (str.Length > 0) + { + str = str.Trim(); + if (i < m_Spawner.SpawnObjects.Length) + { + // check to see if the existing typename is longer than the max textentry buffer + // if it is then dont update it since we will assume that the textentry has truncated the actual string + // that could be longer than the buffer if booktextentry is used + +#if(BOOKTEXTENTRY) + string currentstr = m_Spawner.SpawnObjects[i].TypeName; + if (currentstr != null && currentstr.Length < 230) +#endif + { + if (m_Spawner.SpawnObjects[i].TypeName != str) + { + CommandLogging.WriteLine(from, "{0} {1} changed XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7} to {8}", from.AccessLevel, CommandLogging.Format(from), m_Spawner.Serial, m_Spawner.Name, m_Spawner.GetWorldLocation().X, m_Spawner.GetWorldLocation().Y, m_Spawner.Map, m_Spawner.SpawnObjects[i].TypeName, str); + + } + + m_Spawner.SpawnObjects[i].TypeName = str; + } + } + + } + } + } + } + + +#if(BOOKTEXTENTRY) + + public static void ProcessSpawnerBookEntry(Mobile from, object[] args, string entry) + { + if (from == null || args == null || args.Length < 6) return; + + XmlSpawner m_Spawner = (XmlSpawner)args[0]; + int m_Index = (int)args[1]; + int m_X = (int)args[2]; + int m_Y = (int)args[3]; + int m_Extension = (int)args[4]; + int m_page = (int)args[5]; + if (m_Spawner == null || m_Spawner.SpawnObjects == null) return; + + // place the book text into the spawn entry + if (m_Index < m_Spawner.SpawnObjects.Length) + { + XmlSpawner.SpawnObject so = m_Spawner.SpawnObjects[m_Index]; + + if (so.TypeName != entry) + { + CommandLogging.WriteLine(from, "{0} {1} changed XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7} to {8}", from.AccessLevel, CommandLogging.Format(from), m_Spawner.Serial, m_Spawner.Name, m_Spawner.GetWorldLocation().X, m_Spawner.GetWorldLocation().Y, m_Spawner.Map, so.TypeName, entry); + + } + + so.TypeName = entry; + } + else + { + + // add a new spawn entry + m_Spawner.m_SpawnObjects.Add(new XmlSpawner.SpawnObject(from, m_Spawner, entry, 1)); + + m_Index = m_Spawner.SpawnObjects.Length - 1; + + // and bump the maxcount of the spawner + m_Spawner.MaxCount++; + } + + // refresh the spawner gumps + RefreshSpawnerGumps(from); + + // and refresh the current one + //from.SendGump( new XmlSpawnerGump(m_Spawner, m_X, m_Y, m_Extension,0, m_page) ); + + // return the text entry focus to the book. Havent figured out how to do that yet. + } + + +#endif + + public static void Refresh_Callback(object state) + { + object[] args = (object[])state; + Mobile m = (Mobile)args[0]; + // refresh the spawner gumps + RefreshSpawnerGumps(m); + } + + public static void RefreshSpawnerGumps(Mobile from) + { + if (from == null) return; + + NetState ns = from.NetState; + + if (ns != null && ns.Gumps != null) + { + + ArrayList refresh = new ArrayList(); + + foreach (Gump g in ns.Gumps) + { + + if (g is XmlSpawnerGump) + { + XmlSpawnerGump xg = (XmlSpawnerGump)g; + + // clear the gump status on the spawner associated with the gump + if (xg.m_Spawner != null) + { + // and add the old gump to the removal list + refresh.Add(xg); + } + } + } + + // close all of the currently opened spawner gumps + from.CloseGump(typeof(XmlSpawnerGump)); + + + // reopen the closed gumps from the gump collection + foreach (XmlSpawnerGump g in refresh) + { + // reopen a new gump for the spawner + if (g.m_Spawner != null /*&& g.m_Spawner.SpawnerGump == g */) + { + // flag the current gump on the spawner as closed + g.m_Spawner.GumpReset = true; + + XmlSpawnerGump xg = new XmlSpawnerGump(g.m_Spawner, g.X, g.Y, g.m_ShowGump, g.xoffset, g.page, g.Rentry); + + from.SendGump(xg); + } + } + } + } + + + private bool ValidGotoObject(Mobile from, object o) + { + if (o is Item) + { + Item i = o as Item; + if (!i.Deleted && (i.Map != null) && (i.Map != Map.Internal)) + return true; + + if (from != null && !from.Deleted) + { + from.SendMessage("{0} is not available", i); + } + } + else + if (o is Mobile) + { + Mobile m = o as Mobile; + if (!m.Deleted && (m.Map != null) && (m.Map != Map.Internal)) + return true; + + if (from != null && !from.Deleted) + { + from.SendMessage("{0} is not available", m); + } + } + + return false; + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Spawner == null || m_Spawner.Deleted || state == null || info == null) + { + if (m_Spawner != null) m_Spawner.SpawnerGump = null; + return; + } + + // restrict access to the original creator or someone of higher access level + //if (m_Spawner.FirstModifiedBy != null && m_Spawner.FirstModifiedBy != state.Mobile && state.Mobile.AccessLevel <= m_Spawner.FirstModifiedBy.AccessLevel) + //return; + + + // Get the current name + TextRelay tr = info.GetTextEntry(999); + if (tr != null) + { + m_Spawner.Name = tr.Text; + } + + // update typenames of the spawn objects based upon the current text entry strings + UpdateTypeNames(state.Mobile, info); + + // Update the creature list + m_Spawner.SpawnObjects = CreateArray(info, state.Mobile); + + if (m_Spawner.SpawnObjects == null) + { + m_Spawner.SpawnerGump = null; + return; + } + + AllowGumpUpdate = true; + + for (int i = 0; i < m_Spawner.SpawnObjects.Length; i++) + { + if (page != (int)(i / MaxEntriesPerPage)) continue; + + // check the max count entry + TextRelay temcnt = info.GetTextEntry(500 + i); + if (temcnt != null) + { + int maxval = 0; + try { maxval = Convert.ToInt32(temcnt.Text, 10); } + catch { } + if (maxval < 0) maxval = 0; + + m_Spawner.SpawnObjects[i].MaxCount = maxval; + } + + if (m_ShowGump > 0) + { + // check the subgroup entry + TextRelay tegrp = info.GetTextEntry(600 + i); + if (tegrp != null) + { + int grpval = 0; + try { grpval = Convert.ToInt32(tegrp.Text, 10); } + catch { } + if (grpval < 0) grpval = 0; + + m_Spawner.SpawnObjects[i].SubGroup = grpval; + } + } + + if (m_ShowGump > 1) + { + // note, while these values can be entered in any spawn entry, they will only be assigned to the subgroup leader + int subgroupindex = m_Spawner.GetCurrentSequentialSpawnIndex(m_Spawner.SpawnObjects[i].SubGroup); + TextRelay tegrp; + + if (subgroupindex >= 0 && subgroupindex < m_Spawner.SpawnObjects.Length) + { + // check the reset time entry + tegrp = info.GetTextEntry(1000 + i); + if (tegrp != null && tegrp.Text != null && tegrp.Text.Length > 0) + { + double grpval = 0; + try { grpval = Convert.ToDouble(tegrp.Text); } + catch { } + if (grpval < 0) grpval = 0; + + m_Spawner.SpawnObjects[i].SequentialResetTime = 0; + + m_Spawner.SpawnObjects[subgroupindex].SequentialResetTime = grpval; + } + // check the reset to entry + tegrp = info.GetTextEntry(1100 + i); + if (tegrp != null && tegrp.Text != null && tegrp.Text.Length > 0) + { + int grpval = 0; + try { grpval = Convert.ToInt32(tegrp.Text, 10); } + catch { } + if (grpval < 0) grpval = 0; + + m_Spawner.SpawnObjects[subgroupindex].SequentialResetTo = grpval; + } + // check the kills entry + tegrp = info.GetTextEntry(1200 + i); + if (tegrp != null && tegrp.Text != null && tegrp.Text.Length > 0) + { + int grpval = 0; + try { grpval = Convert.ToInt32(tegrp.Text, 10); } + catch { } + if (grpval < 0) grpval = 0; + + m_Spawner.SpawnObjects[subgroupindex].KillsNeeded = grpval; + } + + } + + // check the mindelay + tegrp = info.GetTextEntry(1300 + i); + if (tegrp != null) + { + if (tegrp.Text != null && tegrp.Text.Length > 0) + { + double grpval = -1; + try { grpval = Convert.ToDouble(tegrp.Text); } + catch { } + if (grpval < 0) grpval = -1; + + // if this value has changed, then update the next spawn time + if (grpval != m_Spawner.SpawnObjects[i].MinDelay) + { + m_Spawner.SpawnObjects[i].MinDelay = grpval; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + else + { + m_Spawner.SpawnObjects[i].MinDelay = -1; + m_Spawner.SpawnObjects[i].MaxDelay = -1; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + + // check the maxdelay + tegrp = info.GetTextEntry(1400 + i); + if (tegrp != null) + { + if (tegrp.Text != null && tegrp.Text.Length > 0) + { + double grpval = -1; + try { grpval = Convert.ToDouble(tegrp.Text); } + catch { } + if (grpval < 0) grpval = -1; + + // if this value has changed, then update the next spawn time + if (grpval != m_Spawner.SpawnObjects[i].MaxDelay) + { + m_Spawner.SpawnObjects[i].MaxDelay = grpval; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + else + { + m_Spawner.SpawnObjects[i].MinDelay = -1; + m_Spawner.SpawnObjects[i].MaxDelay = -1; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + + // check the spawns per tick + tegrp = info.GetTextEntry(1500 + i); + if (tegrp != null) + { + if (tegrp.Text != null && tegrp.Text.Length > 0) + { + int grpval = 1; + try { grpval = int.Parse(tegrp.Text); } + catch { } + if (grpval < 0) grpval = 1; + + // if this value has changed, then update the next spawn time + if (grpval != m_Spawner.SpawnObjects[i].SpawnsPerTick) + { + m_Spawner.SpawnObjects[i].SpawnsPerTick = grpval; + } + } + else + { + m_Spawner.SpawnObjects[i].SpawnsPerTick = 1; + } + } + + // check the packrange + tegrp = info.GetTextEntry(1600 + i); + if (tegrp != null) + { + if (tegrp.Text != null && tegrp.Text.Length > 0) + { + int grpval = 1; + try { grpval = int.Parse(tegrp.Text); } + catch { } + if (grpval < 0) grpval = 1; + + // if this value has changed, then update + if (grpval != m_Spawner.SpawnObjects[i].PackRange) + { + m_Spawner.SpawnObjects[i].PackRange = grpval; + } + } + else + { + m_Spawner.SpawnObjects[i].PackRange = -1; + } + } + } + } + + // Update the maxcount + TextRelay temax = info.GetTextEntry(300); + if (temax != null) + { + int maxval = 0; + try { maxval = Convert.ToInt32(temax.Text, 10); } + catch { } + if (maxval < 0) maxval = 0; + // if the maxcount of the spawner has been altered external to the interface (e.g. via props, or by the running spawner itself + // then that change will override the text entry + if (m_Spawner.MaxCount == this.initial_maxcount) + { + m_Spawner.MaxCount = maxval; + } + } + + switch (info.ButtonID) + { + case 0: // Close + { + // clear any text entry books + m_Spawner.DeleteTextEntryBook(); + // and reset the gump status + m_Spawner.GumpReset = true; + + return; + } + case 1: // Help + { + //state.Mobile.SendGump( new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump)); + state.Mobile.SendGump(new HelpGump(m_Spawner, this, this.X + 290, this.Y)); + break; + } + case 2: // Bring everything home + { + m_Spawner.BringToHome(); + break; + } + case 3: // Complete respawn + { + m_Spawner.Respawn(); + //m_Spawner.AdvanceSequential(); + m_Spawner.m_killcount = 0; + break; + } + case 4: // Goto + { + state.Mobile.Location = m_Spawner.Location; + state.Mobile.Map = m_Spawner.Map; + break; + } + case 200: // gump extension + { + if (this.m_ShowGump > 1) + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, -1, this.xoffset, this.page)); + else + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump + 2, this.xoffset, this.page)); + return; + } + case 201: // gump text extension + { + if (this.xoffset > 0) + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, 0, this.page)); + else + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, 250, this.page)); + return; + } + case 700: // Start/stop spawner + { + if (m_Spawner.Running) + m_Spawner.Running = false; + else + m_Spawner.Running = true; + break; + } + case 701: // Complete reset + { + m_Spawner.Reset(); + break; + } + case 702: // Sort spawns + { + m_Spawner.SortSpawns(); + break; + } + case 900: // empty the status string + { + m_Spawner.status_str = ""; + break; + } + case 9998: // refresh the gump + { + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, this.xoffset, this.page)); + return; + } + case 9999: + { + // Show the props window for the spawner, as well as a new gump + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, this.xoffset, this.page)); +#if(NEWPROPSGUMP) + state.Mobile.SendGump(new XmlPropertiesGump(state.Mobile, m_Spawner)); +#else + state.Mobile.SendGump( new PropertiesGump( state.Mobile, m_Spawner ) ); +#endif + return; + } + default: + { + // check the restrict kills flag + if (info.ButtonID >= 300 && info.ButtonID < 300 + MaxSpawnEntries) + { + int index = info.ButtonID - 300; + if (index < m_Spawner.SpawnObjects.Length) + m_Spawner.SpawnObjects[index].RestrictKillsToSubgroup = !m_Spawner.SpawnObjects[index].RestrictKillsToSubgroup; + + } + else + // check the clear on advance flag + if (info.ButtonID >= 400 && info.ButtonID < 400 + MaxSpawnEntries) + { + int index = info.ButtonID - 400; + if (index < m_Spawner.SpawnObjects.Length) + m_Spawner.SpawnObjects[index].ClearOnAdvance = !m_Spawner.SpawnObjects[index].ClearOnAdvance; + } + else + // text entry gump scroll buttons + if (info.ButtonID >= 800 && info.ButtonID < 800 + MaxSpawnEntries) + { + // open the text entry gump + int index = info.ButtonID - 800; + // open a text entry gump +#if(BOOKTEXTENTRY) + // display a new gump + XmlSpawnerGump newgump = new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, this.xoffset, this.page); + state.Mobile.SendGump(newgump); + + // is there an existing book associated with the gump? + if (m_Spawner.m_TextEntryBook == null) + { + m_Spawner.m_TextEntryBook = new ArrayList(); + } + + object[] args = new object[6]; + + args[0] = m_Spawner; + args[1] = index; + args[2] = X; + args[3] = Y; + args[4] = m_ShowGump; + args[5] = page; + + XmlTextEntryBook book = new XmlTextEntryBook(0, String.Empty, m_Spawner.Name, 20, true, new XmlTextEntryBookCallback(ProcessSpawnerBookEntry), args); + + m_Spawner.m_TextEntryBook.Add(book); + + book.Title = String.Format("Entry {0}", index); + book.Author = m_Spawner.Name; + + // fill the contents of the book with the current text entry data + string text = String.Empty; + if (m_Spawner.SpawnObjects != null && index < m_Spawner.SpawnObjects.Length) + { + text = m_Spawner.SpawnObjects[index].TypeName; + } + book.FillTextEntryBook(text); + + // put the book at the location of the player so that it can be opened, but drop it below visible range + book.Visible = false; + book.Movable = false; + book.MoveToWorld(new Point3D(state.Mobile.Location.X, state.Mobile.Location.Y, state.Mobile.Location.Z - 100), state.Mobile.Map); + + // and open it + book.OnDoubleClick(state.Mobile); + + +#else + state.Mobile.SendGump( new TextEntryGump(m_Spawner,this, index, this.X, this.Y)); +#endif + return; + } + else + // goto spawn buttons + if (info.ButtonID >= 1300 && info.ButtonID < 1300 + MaxSpawnEntries) + { + nclicks++; + // find the location of the spawn at the specified index + int index = info.ButtonID - 1300; + if (index < m_Spawner.SpawnObjects.Length) + { + int scount = m_Spawner.SpawnObjects[index].SpawnedObjects.Count; + if (scount > 0) + { + object so = m_Spawner.SpawnObjects[index].SpawnedObjects[nclicks % scount]; + if (ValidGotoObject(state.Mobile, so)) + { + IPoint3D o = so as IPoint3D; + if (o != null) + { + Map m = m_Spawner.Map; + if (o is Item) + m = ((Item)o).Map; + if (o is Mobile) + m = ((Mobile)o).Map; + + state.Mobile.Location = new Point3D(o); + state.Mobile.Map = m; + } + } + } + } + } + else + // page buttons + if (info.ButtonID >= 4000 && info.ButtonID < 4001 + (int)(MaxSpawnEntries / MaxEntriesPerPage)) + { + // which page + this.page = info.ButtonID - 4000; + + } + else + // toggle the disabled state of the entry + if (info.ButtonID >= 6000 && info.ButtonID < 6000 + MaxSpawnEntries) + { + int index = info.ButtonID - 6000; + + if (index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[index].Disabled = !m_Spawner.SpawnObjects[index].Disabled; + + // clear any current spawns on the disabled entry + if (m_Spawner.SpawnObjects[index].Disabled) + m_Spawner.RemoveSpawnObjects(m_Spawner.SpawnObjects[index]); + } + } + else + if (info.ButtonID >= 5000 && info.ButtonID < 5000 + MaxSpawnEntries) + { + int i = info.ButtonID - 5000; + + + + + string categorystring = null; + string entrystring = null; + + TextRelay te = info.GetTextEntry(i); + + if (te != null && te.Text != null) + { + // get the string + + string[] cargs = te.Text.Split(','); + + // parse out any comma separated args + categorystring = cargs[0]; + + entrystring = te.Text; + } + + + if (categorystring == null || categorystring.Length == 0) + { + + XmlSpawnerGump newg = new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, this.xoffset, this.page); + state.Mobile.SendGump(newg); + + // if no string has been entered then just use the full categorized add gump + state.Mobile.CloseGump(typeof(Server.Gumps.XmlCategorizedAddGump)); + state.Mobile.SendGump(new Server.Gumps.XmlCategorizedAddGump(state.Mobile, i, newg)); + } + else + { + // use the XmlPartialCategorizedAddGump + state.Mobile.CloseGump(typeof(Server.Gumps.XmlPartialCategorizedAddGump)); + + //Type [] types = (Type[])XmlPartialCategorizedAddGump.Match( categorystring ).ToArray( typeof( Type ) ); + ArrayList types = XmlPartialCategorizedAddGump.Match(categorystring); + + + XmlSpawnerGump.ReplacementEntry re = new XmlSpawnerGump.ReplacementEntry(); + re.Typename = entrystring; + re.Index = i; + re.Color = 0x1436; + + XmlSpawnerGump newg = new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, this.xoffset, this.page, re); + + state.Mobile.SendGump(new XmlPartialCategorizedAddGump(state.Mobile, categorystring, 0, types, true, i, newg)); + + state.Mobile.SendGump(newg); + } + + return; + + + } + else + { + // up and down arrows + int buttonID = info.ButtonID - 6; + int index = buttonID / 2; + int type = buttonID % 2; + + TextRelay entry = info.GetTextEntry(index); + + if (entry != null && entry.Text.Length > 0) + { + string entrystr = entry.Text; + +#if(BOOKTEXTENTRY) + if (index < m_Spawner.SpawnObjects.Length) + { + string str = m_Spawner.SpawnObjects[index].TypeName; + + if (str != null && str.Length >= 230) + entrystr = str; + } +#endif + + if (type == 0) // Add creature + { + m_Spawner.AddSpawnObject(entrystr); + } + else // Remove creatures + { + m_Spawner.DeleteSpawnObject(state.Mobile, entrystr); + + + } + } + } + break; + } + } + // Create a new gump + //m_Spawner.OnDoubleClick( state.Mobile); + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, this.X, this.Y, this.m_ShowGump, this.xoffset, this.page, this.Rentry)); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlSpawnerSkillCheck.cs b/Scripts/Customs/XML Spawner/XmlSpawnerSkillCheck.cs new file mode 100644 index 0000000..82e6ac9 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlSpawnerSkillCheck.cs @@ -0,0 +1,283 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using System.Diagnostics; +using Server.Misc; +using Server.Engines.XmlSpawner2; + +namespace Server.Mobiles +{ + public class XmlSpawnerSkillCheck + { + // alternate skillcheck hooks to replace those in SkillCheck.cs + public static bool Mobile_SkillCheckLocation( Mobile from, SkillName skillName, double minSkill, double maxSkill ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckLocation( from, skillName, minSkill, maxSkill ); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + public static bool Mobile_SkillCheckDirectLocation( Mobile from, SkillName skillName, double chance ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckDirectLocation( from, skillName, chance ); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + public static bool Mobile_SkillCheckTarget( Mobile from, SkillName skillName, object target, double minSkill, double maxSkill ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckTarget( from, skillName, target, minSkill, maxSkill ); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + public static bool Mobile_SkillCheckDirectTarget( Mobile from, SkillName skillName, object target, double chance ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckDirectTarget( from, skillName, target, chance ); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + + public class RegisteredSkill + { + public const int MaxSkills = 52; + public const SkillName Invalid = (SkillName)(-1); + + public object target; + public SkillName sid; + + // note the extra skill MaxSkills +1 is used for any unknown skill that falls outside of the known 52 + private static ArrayList[] m_FeluccaSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_TrammelSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_MalasSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_IlshenarSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_TokunoSkillList = new ArrayList[MaxSkills+1]; + + // primary function that returns the list of objects (spawners) that are associated with a given skillname by map + public static ArrayList TriggerList(SkillName index, Map map) + { + if(map == null || map == Map.Internal) return null; + + ArrayList[] maplist; + + // get the list for the specified map + + if(map == Map.Felucca) + maplist = m_FeluccaSkillList; + else + if(map == Map.Ilshenar) + maplist = m_IlshenarSkillList; + else + if(map == Map.Malas) + maplist = m_MalasSkillList; + else + if(map == Map.Trammel) + maplist = m_TrammelSkillList; + else + if(map == Map.Tokuno) + maplist = m_TokunoSkillList; + else + return null; + + // is it one of the standard 52 skills + if((int)index >= 0 && (int)index < MaxSkills) + { + if(maplist[(int)index] == null) + maplist[(int)index] = new ArrayList(); + + return maplist[(int)index]; + } + else + // otherwise pull it out of the final slot for unknown skills. I dont know of a condition that would lead to + // additional skills being registered but it will support them if they are + { + if(maplist[MaxSkills] == null) + maplist[MaxSkills] = new ArrayList(); + + return maplist[MaxSkills]; + } + + } + } + + public static void RegisterSkillTrigger( object o, SkillName s, Map map) + { + if(o == null || s == RegisteredSkill.Invalid) return; + + // go through the list and if the spawner is not on it yet, then add it + bool found = false; + + ArrayList skilllist = RegisteredSkill.TriggerList(s, map); + + if(skilllist == null) return; + + foreach(RegisteredSkill rs in skilllist) + { + if(rs.target == o && rs.sid == s) + { + found = true; + // dont register a skill if it is already on the list for this spawner + break; + } + } + + // if it hasnt already been added to the list, then add it + if(!found) + { + RegisteredSkill newrs = new RegisteredSkill(); + newrs.target = o; + newrs.sid = s; + + skilllist.Add(newrs); + + } + } + + public static void UnRegisterSkillTrigger( object o, SkillName s, Map map, bool all) + { + if(o == null || s == RegisteredSkill.Invalid) return; + + // go through the list and if the spawner is on it regardless of the skill registered, then remove it + if(all) + { + for(int i = 0;i 0) + { + foreach(XmlAttachment a in list) + { + if(a != null && !a.Deleted && a.HandlesOnSkillUse) + { + a.OnSkillUse(m, skill, success); + } + } + } + */ + + // then check for registered skills + ArrayList skilllist = RegisteredSkill.TriggerList(skill.SkillName, m.Map); + + if(skilllist == null) return; + + // determine whether there are any registered objects for this skill + foreach(RegisteredSkill rs in skilllist) + { + if(rs.sid == skill.SkillName) + { + // if so then invoke their skill handlers + if(rs.target is XmlSpawner) + { + XmlSpawner spawner = (XmlSpawner)rs.target; + + if ( spawner.HandlesOnSkillUse ) + { + // call the spawner handler + spawner.OnSkillUse(m, skill, success); + } + } else + if(rs.target is IXmlQuest) + { + IXmlQuest quest = (IXmlQuest)rs.target; + if ( quest.HandlesOnSkillUse ) + { + // call the xmlquest handler + quest.OnSkillUse(m, skill, success); + } + } + } + } + } + + } +} diff --git a/Scripts/Customs/XML Spawner/XmlTextEntryBook.cs b/Scripts/Customs/XML Spawner/XmlTextEntryBook.cs new file mode 100644 index 0000000..58c5014 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlTextEntryBook.cs @@ -0,0 +1,364 @@ +#define BOOKTEXTENTRY + +using System; +using System.IO; +using System.Text; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Items +{ + + public delegate void XmlTextEntryBookCallback( Mobile from, object [] args, string response ); + + public class XmlTextEntryBook : BaseEntryBook + { + public XmlTextEntryBookCallback m_bookcallback; + public object [] m_args; + + public XmlTextEntryBook( int itemID, string title, string author, int pageCount, bool writable, + XmlTextEntryBookCallback callback, object [] args) : base( itemID, title, author, pageCount, writable ) + { + m_args = args; + m_bookcallback = callback; + } + + public XmlTextEntryBook( Serial serial ) : base( serial ) + { + } + + public void FillTextEntryBook(string text) + { + + int pagenum = 0; + BookPageInfo [] pages = Pages; + int current = 0; + + // break up the text into single line length pieces + while(text != null && current < text.Length) + { + int lineCount = 8; + string[] lines = new string[lineCount]; + + // place the line on the page + for(int i=0;i 20) length = 20; + lines[i] = text.Substring(current,length); + current += length; + } + else + { + // fill up the remaining lines + lines[i] = String.Empty; + } + } + + if ( pagenum >= PagesCount ) + return; + Pages[pagenum].Lines = lines; + pagenum++; + } + // empty the remaining contents + for(int j=pagenum;j < PagesCount; j++) + { + if(Pages[j].Lines.Length > 0) + for(int i=0;i book.PagesCount ) + return; + + for ( int i = 0; i < pageCount; ++i ) + { + // get the current page number being read + int index = pvSrc.ReadUInt16(); + + if ( index >= 1 && index <= book.PagesCount ) + { + --index; + + int lineCount = pvSrc.ReadUInt16(); + + if ( lineCount <= 8 ) + { + string[] lines = new string[lineCount]; + + for ( int j = 0; j < lineCount; ++j ) + { + if ( (lines[j] = pvSrc.ReadUTF8StringSafe()).Length >= 80 ) + return; + + } + + book.Pages[index].Lines = lines; + + } + else + { + return; + } + } + else + { + return; + } + } + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + // add the book lines to the entry string + for ( int i = 0; i < book.PagesCount; ++i ) + { + for(int j=0;j book.PagesCount ) + return; + + for ( int i = 0; i < pageCount; ++i ) + { + int index = pvSrc.ReadUInt16(); + + if ( index >= 1 && index <= book.PagesCount ) + { + --index; + + int lineCount = pvSrc.ReadUInt16(); + + if ( lineCount <= 8 ) + { + string[] lines = new string[lineCount]; + + for ( int j = 0; j < lineCount; ++j ) + if ( (lines[j] = pvSrc.ReadUTF8StringSafe()).Length >= 80 ) + return; + + book.Pages[index].Lines = lines; + } + else + { + return; + } + } + else + { + return; + } + } + } +#endif + } + +#if(BOOKTEXTENTRY) + public sealed class EntryBookPageDetails : Packet + { + public EntryBookPageDetails( BaseEntryBook book ) : base( 0x66 ) + { + EnsureCapacity( 256 ); + + m_Stream.Write( (int) book.Serial ); + m_Stream.Write( (ushort) book.PagesCount ); + + for ( int i = 0; i < book.PagesCount; ++i ) + { + BookPageInfo page = book.Pages[i]; + + m_Stream.Write( (ushort) (i + 1) ); + m_Stream.Write( (ushort) page.Lines.Length ); + + for ( int j = 0; j < page.Lines.Length; ++j ) + { + byte[] buffer = Utility.UTF8.GetBytes( page.Lines[j] ); + + m_Stream.Write( buffer, 0, buffer.Length ); + m_Stream.Write( (byte) 0 ); + } + } + } + } + + public sealed class EntryBookHeader : Packet + { + public EntryBookHeader( Mobile from, BaseEntryBook book ) : base ( 0xD4 ) + { + string title = book.Title == null ? "" : book.Title; + string author = book.Author == null ? "" : book.Author; + + byte[] titleBuffer = Utility.UTF8.GetBytes( title ); + byte[] authorBuffer = Utility.UTF8.GetBytes( author ); + + EnsureCapacity( 15 + titleBuffer.Length + authorBuffer.Length ); + + m_Stream.Write( (int) book.Serial ); + m_Stream.Write( (bool) true ); + m_Stream.Write( (bool) book.Writable && from.InRange( book.GetWorldLocation(), 1 ) ); + m_Stream.Write( (ushort) book.PagesCount ); + + m_Stream.Write( (ushort) (titleBuffer.Length + 1) ); + m_Stream.Write( titleBuffer, 0, titleBuffer.Length ); + m_Stream.Write( (byte) 0 ); // terminate + + m_Stream.Write( (ushort) (authorBuffer.Length + 1) ); + m_Stream.Write( authorBuffer, 0, authorBuffer.Length ); + m_Stream.Write( (byte) 0 ); // terminate + } + } +#endif +} + diff --git a/Scripts/Customs/XML Spawner/XmlUtils/WhatIsIt.cs b/Scripts/Customs/XML Spawner/XmlUtils/WhatIsIt.cs new file mode 100644 index 0000000..e224fee --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/WhatIsIt.cs @@ -0,0 +1,69 @@ +using System; +using System.Text; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Commands +{ + public class WhatIsIt + { + + public static void Initialize() + { + CommandSystem.Register("WhatIsIt", AccessLevel.Player, new CommandEventHandler(GenericCommand_OnCommand)); + } + + public class WhatIsItTarget : Target + { + + public WhatIsItTarget() + : base(30, true, TargetFlags.None) + { + CheckLOS = false; + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(from == null || targeted == null) return; + + string name = String.Empty; + string typename = targeted.GetType().Name; + string article = "a"; + + if (typename != null && typename.Length > 0) + { + if ("aeiouy".IndexOf(typename.ToLower()[0]) >= 0) + { + article = "an"; + } + } + + if(targeted is Item) + { + name = ((Item)targeted).Name; + } else + if(targeted is Mobile) + { + name = ((Mobile)targeted).Name; + } + if (name != String.Empty && name != null) + { + from.SendMessage("That is {0} {1} named '{2}'", article, typename, name); + } + else + { + from.SendMessage("That is {0} {1} with no name", article, typename); + } + } + } + + [Usage( "WhatIsIt" )] + public static void GenericCommand_OnCommand( CommandEventArgs e ) + { + if(e == null || e.Mobile == null) return; + + e.Mobile.Target = new WhatIsItTarget(); + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlUtils/WriteMulti.cs b/Scripts/Customs/XML Spawner/XmlUtils/WriteMulti.cs new file mode 100644 index 0000000..929abd4 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/WriteMulti.cs @@ -0,0 +1,466 @@ +using System; +using Server; +using System.IO; +using System.Collections; +using Server.Multis; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using System.Runtime.Serialization; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Engines.XmlSpawner2 +{ + public class WriteMulti + { + private class TileEntry + { + public int ID; + public int X; + public int Y; + public int Z; + + public TileEntry(int id, int x, int y, int z) + { + ID = id; + X = x; + Y = y; + Z = z; + } + } + + public static void Initialize() + { + + CommandSystem.Register("WriteMulti", XmlSpawner.DiskAccessLevel, new CommandEventHandler(WriteMulti_OnCommand)); + } + + [Usage("WriteMulti [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]")] + [Description("Creates a multi text file from the objects within the targeted area. The min/max z range can also be specified.")] + public static void WriteMulti_OnCommand(CommandEventArgs e) + { + if (e == null || e.Mobile == null) return; + + if (e.Mobile.AccessLevel < XmlSpawner.DiskAccessLevel) + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + return; + } + + if (e.Arguments != null && e.Arguments.Length < 1) + { + e.Mobile.SendMessage("Usage: {0} [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]", e.Command); + return; + } + + string filename = e.Arguments[0].ToString(); + + int zmin = int.MinValue; + int zmax = int.MinValue; + bool includeitems = true; + bool includestatics = true; + bool includemultis = true; + bool includeaddons = true; + bool includeinvisible = false; + + if (e.Arguments.Length > 1) + { + int index = 1; + while (index < e.Arguments.Length) + { + if (e.Arguments[index] == "-noitems") + { + includeitems = false; + index++; + } + else if (e.Arguments[index] == "-nostatics") + { + includestatics = false; + index++; + } + else if (e.Arguments[index] == "-nomultis") + { + includemultis = false; + index++; + } + else if (e.Arguments[index] == "-noaddons") + { + includeaddons = false; + index++; + } + else if (e.Arguments[index] == "-invisible") + { + includeinvisible = true; + index++; + } + else + { + try + { + zmin = int.Parse(e.Arguments[index++]); + zmax = int.Parse(e.Arguments[index++]); + } + catch + { + e.Mobile.SendMessage("{0} : Invalid zmin zmax arguments", e.Command); + return; + } + } + } + } + + string dirname; + if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = String.Format("{0}/{1}", XmlSpawner.XmlSpawnDir, filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + // check to see if the file already exists and can be written to by the owner + if (System.IO.File.Exists(dirname)) + { + + // check the file + try + { + StreamReader op = new StreamReader(dirname, false); + + if (op == null) + { + e.Mobile.SendMessage("Cannot access file {0}", dirname); + return; + } + + string line = op.ReadLine(); + + op.Close(); + + // check the first line + if (line != null && line.Length > 0) + { + + string[] args = line.Split(" ".ToCharArray(), 3); + if (args == null || args.Length < 3) + { + e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + return; + } + + if (args[2] != e.Mobile.Name) + { + e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + return; + } + } + else + { + e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + return; + } + + } + catch + { + e.Mobile.SendMessage("Cannot overwrite file {0}", dirname); + return; + } + + } + + DefineMultiArea(e.Mobile, dirname, zmin, zmax, includeitems, includestatics, includemultis, includeinvisible, includeaddons); + } + + public static void DefineMultiArea(Mobile m, string dirname, int zmin, int zmax, bool includeitems, bool includestatics, + bool includemultis, bool includeinvisible, bool includeaddons) + { + object[] multiargs = new object[8]; + multiargs[0] = dirname; + multiargs[1] = zmin; + multiargs[2] = zmax; + multiargs[3] = includeitems; + multiargs[4] = includestatics; + multiargs[5] = includemultis; + multiargs[6] = includeinvisible; + multiargs[7] = includeaddons; + + BoundingBoxPicker.Begin(m, new BoundingBoxCallback(DefineMultiArea_Callback), multiargs); + } + + private static void DefineMultiArea_Callback(Mobile from, Map map, Point3D start, Point3D end, object state) + { + object[] multiargs = (object[])state; + + if (from != null && multiargs != null && map != null) + { + string dirname = (string)multiargs[0]; + int zmin = (int)multiargs[1]; + int zmax = (int)multiargs[2]; + bool includeitems = (bool)multiargs[3]; + bool includestatics = (bool)multiargs[4]; + bool includemultis = (bool)multiargs[5]; + bool includeinvisible = (bool)multiargs[6]; + bool includeaddons = (bool)multiargs[7]; + + ArrayList itemlist = new ArrayList(); + ArrayList staticlist = new ArrayList(); + ArrayList tilelist = new ArrayList(); + + int sx = (start.X > end.X) ? end.X : start.X; + int sy = (start.Y > end.Y) ? end.Y : start.Y; + int ex = (start.X < end.X) ? end.X : start.X; + int ey = (start.Y < end.Y) ? end.Y : start.Y; + + // find all of the world-placed items within the specified area + if (includeitems) + { + // make the first pass for items only + IPooledEnumerable eable = map.GetItemsInBounds(new Rectangle2D(sx, sy, ex - sx + 1, ey - sy + 1)); + + foreach (Item item in eable) + { + // is it within the bounding area + if (item.Parent == null && (zmin == int.MinValue || (item.Location.Z >= zmin && item.Location.Z <= zmax))) + { + // add the item + if ((includeinvisible || item.Visible) && (item.ItemID <= 16383)) + { + itemlist.Add(item); + } + } + } + + eable.Free(); + + int searchrange = 100; + + // make the second expanded pass to pick up addon components and multi components + eable = map.GetItemsInBounds(new Rectangle2D(sx - searchrange, sy - searchrange, ex - sy + searchrange * 2 + 1, + ey - sy + searchrange * 2 + 1)); + + foreach (Item item in eable) + { + // is it within the bounding area + if (item.Parent == null) + { + + if (item is BaseAddon && includeaddons) + { + // go through all of the addon components + foreach (AddonComponent c in ((BaseAddon)item).Components) + { + int x = c.X; + int y = c.Y; + int z = c.Z; + + if ((includeinvisible || item.Visible) && (item.ItemID <= 16383 || includemultis) && + (x >= sx && x <= ex && y >= sy && y <= ey && (zmin == int.MinValue || (z >= zmin && z <= zmax)))) + { + itemlist.Add(c); + } + } + } + + if (item is BaseMulti && includemultis) + { + // go through all of the multi components + MultiComponentList mcl = ((BaseMulti)item).Components; + if (mcl != null && mcl.List != null) + { + for (int i = 0; i < mcl.List.Length; i++) + { + MultiTileEntry t = mcl.List[i]; + + int x = t.m_OffsetX + item.X; + int y = t.m_OffsetY + item.Y; + int z = t.m_OffsetZ + item.Z; + int itemID = t.m_ItemID & 0x3FFF; + + if (x >= sx && x <= ex && y >= sy && y <= ey && (zmin == int.MinValue || (z >= zmin && z <= zmax))) + { + tilelist.Add(new TileEntry(itemID, x, y, z)); + } + } + + } + } + } + } + + eable.Free(); + } + + // find all of the static tiles within the specified area + if (includestatics) + { + // count the statics + for (int x = sx; x < ex; x++) + { + for (int y = sy; y < ey; y++) + { + StaticTile[] statics = map.Tiles.GetStaticTiles(x, y, false); + + for (int j = 0; j < statics.Length; j++) + { + if ((zmin == int.MinValue || (statics[j].Z >= zmin && statics[j].Z <= zmax))) + { + staticlist.Add(new TileEntry(statics[j].ID & 0x3FFF, x, y, statics[j].Z)); + } + } + } + } + } + + int nstatics = staticlist.Count; + int nitems = itemlist.Count; + int ntiles = tilelist.Count; + + int ntotal = nitems + nstatics + ntiles; + + int ninvisible = 0; + int nmultis = ntiles; + int naddons = 0; + + foreach (Item item in itemlist) + { + int x = item.X - from.X; + int y = item.Y - from.Y; + int z = item.Z - from.Z; + + if (item.ItemID > 16383) + { + nmultis++; + } + if (!item.Visible) + { + ninvisible++; + } + if (item is BaseAddon || item is AddonComponent) + { + naddons++; + } + } + + try + { + // open the file, overwrite any previous contents + StreamWriter op = new StreamWriter(dirname, false); + + if (op != null) + { + // write the header + op.WriteLine("1 version {0}", from.Name); + op.WriteLine("{0} num components", ntotal); + + // write out the items + foreach (Item item in itemlist) + { + + int x = item.X - from.X; + int y = item.Y - from.Y; + int z = item.Z - from.Z; + + if (item.Hue > 0) + { + // format is x y z visible hue + op.WriteLine("{0} {1} {2} {3} {4} {5}", item.ItemID, x, y, z, item.Visible ? 1 : 0, item.Hue); + } + else + { + // format is x y z visible + op.WriteLine("{0} {1} {2} {3} {4}", item.ItemID, x, y, z, item.Visible ? 1 : 0); + } + } + + if (includestatics) + { + foreach (TileEntry s in staticlist) + { + int x = s.X - from.X; + int y = s.Y - from.Y; + int z = s.Z - from.Z; + int ID = s.ID; + op.WriteLine("{0} {1} {2} {3} {4}", ID, x, y, z, 1); + } + } + + if (includemultis) + { + foreach (TileEntry s in tilelist) + { + int x = s.X - from.X; + int y = s.Y - from.Y; + int z = s.Z - from.Z; + int ID = s.ID; + op.WriteLine("{0} {1} {2} {3} {4}", ID, x, y, z, 1); + } + } + } + + op.Close(); + } + catch + { + from.SendMessage("Error writing multi file {0}", dirname); + return; + } + + from.SendMessage(66, "WriteMulti results:"); + + if (includeitems) + { + from.SendMessage(66, "Included {0} items", nitems); + + if (includemultis) + { + from.SendMessage("{0} multis", nmultis); + } + else + { + from.SendMessage(33, "Ignored multis"); + } + + if (includeinvisible) + { + from.SendMessage("{0} invisible", ninvisible); + } + else + { + from.SendMessage(33, "Ignored invisible"); + } + + if (includeaddons) + { + from.SendMessage("{0} addons", naddons); + } + else + { + from.SendMessage(33, "Ignored addons"); + } + + } + else + { + from.SendMessage(33, "Ignored items"); + } + + if (includestatics) + { + from.SendMessage(66, "Included {0} statics", nstatics); + } + else + { + from.SendMessage(33, "Ignored statics"); + } + + from.SendMessage(66, "Saved {0} components to {1}", ntotal, dirname); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/XmlUtils/XmlAdd.cs b/Scripts/Customs/XML Spawner/XmlUtils/XmlAdd.cs new file mode 100644 index 0000000..36c448d --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/XmlAdd.cs @@ -0,0 +1,1719 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; + +/* +** XmlAdd +** Version 1.00 +** updated 4/19/04 +** ArteGordon +** +** version 1.04 +** update 8/08/04 +** - the add button now uses targeting to place spawners rather than just putting them at the location of the placer. +** +** version 1.03 +** update 8/07/04 +** +** - changed the selection buttons to checkboxes, and changed their gump art for space reasons. +** - added the smartspawning option +** +** Changelog +** version 1.02 +** update 7/14/04 +** - the duration entry was not being applied to added spawners (Thanks to BlackNova for pointing this out). +** +** version 1.02 +** update 7/14/04 +** - added the SkillTrigger entry +** +** version 1.01 +** update 4/22/04 +** - added a spawn entry selection list +** - added named save and load defaults options +** +*/ + +namespace Server.Mobiles +{ + public class XmlSpawnerDefaults + { + public class DefaultEntry + { + public string AccountName; + public string PlayerName; + public TimeSpan MinDelay = TimeSpan.FromMinutes(5); + public TimeSpan MaxDelay = TimeSpan.FromMinutes(10); + public TimeSpan RefractMin = TimeSpan.FromMinutes(0); + public TimeSpan RefractMax = TimeSpan.FromMinutes(0); + public TimeSpan TODStart = TimeSpan.FromMinutes(0); + public TimeSpan TODEnd = TimeSpan.FromMinutes(0); + public TimeSpan Duration = TimeSpan.FromMinutes(0); + public TimeSpan DespawnTime = TimeSpan.FromHours(0); + public bool Group = false; + public int Team = 0; + public int ProximitySound = 0x1F4; + public string SpeechTrigger = null; + public string SkillTrigger = null; + public int SequentialSpawn = -1; + public bool HomeRangeIsRelative = true; + public int SpawnRange = 5; + public int HomeRange = 5; + public int ProximityRange = -1; + public XmlSpawner.TODModeType TODMode = XmlSpawner.TODModeType.Realtime; + public int KillReset = 1; + public string SpawnerName = "Spawner"; + public bool AllowGhostTrig = false; + public bool AllowNPCTrig = false; + public bool SpawnOnTrigger = false; + public bool SmartSpawning = false; + public bool ExternalTriggering = false; + public string TriggerOnCarried = null; + public string NoTriggerOnCarried = null; + public string ProximityMsg = null; + public double TriggerProbability = 1; + public string PlayerTriggerProp = null; + public string TriggerObjectProp = null; + public string DefsExt; + public string [] NameList; + public bool [] SelectionList; + public int AddGumpX = 440; + public int AddGumpY = 0; + public int SpawnerGumpX = 0; + public int SpawnerGumpY = 0; + public int FindGumpX = 0; + public int FindGumpY = 0; + + // these are additional defaults that are not set by XmlAdd but can be used by other routines such as the custom properties gump to determine + // whether properties have been changed from spawner default values + public string ConfigFile = null; + public int StackAmount = 1; + public string MobTriggerName = null; + public string MobTriggerProp = null; + public string RegionName = null; + public bool Running = true; + public Item SetItem = null; + public AccessLevel TriggerAccessLevel = AccessLevel.Player; + public Item TriggerObject = null; + public WayPoint WayPoint = null; + public bool ShowBounds = false; + + public bool AutoNumber = false; + public int AutoNumberValue = 0; + + public XmlAddCAGCategory CurrentCategory; + public int CurrentCategoryPage; + public int CategorySelectionIndex = -1; + + public XmlSpawner LastSpawner; + public Map StartingMap; + public Point3D StartingLoc; + public bool ShowExtension; + + public bool IgnoreUpdate; + + + public DefaultEntry() + { + } + } + public static ArrayList DefaultEntryList; + + public static DefaultEntry GetDefaults(string account, string name) + { + // find the default entry corresponding to the account and username + if(DefaultEntryList != null) + { + for(int i = 0;i < DefaultEntryList.Count;i++) + { + DefaultEntry entry = (DefaultEntry)DefaultEntryList[i]; + if( entry != null && string.Compare( entry.PlayerName, name, true ) == 0 && string.Compare( entry.AccountName, account, true ) == 0) + { + return entry; + } + } + } + // if not found then add one + DefaultEntry newentry = new DefaultEntry(); + newentry.PlayerName = name; + newentry.AccountName = account; + if(DefaultEntryList == null) + DefaultEntryList = new ArrayList(); + DefaultEntryList.Add(newentry); + return newentry; + } + + public static void RestoreDefs(DefaultEntry defs) + { + if(defs == null) return; + defs.MinDelay = TimeSpan.FromMinutes(5); + defs.MaxDelay = TimeSpan.FromMinutes(10); + defs.RefractMin = TimeSpan.FromMinutes(0); + defs.RefractMax = TimeSpan.FromMinutes(0); + defs.TODStart = TimeSpan.FromMinutes(0); + defs.TODEnd = TimeSpan.FromMinutes(0); + defs.Duration = TimeSpan.FromMinutes(0); + defs.DespawnTime = TimeSpan.FromHours(0); + defs.Group = false; + defs.Team = 0; + defs.ProximitySound = 0x1F4; + defs.SpeechTrigger = null; + defs.SkillTrigger = null; + defs.SequentialSpawn = -1; + defs.HomeRangeIsRelative = true; + defs.SpawnRange = 5; + defs.HomeRange = 5; + defs.ProximityRange = -1; + defs.TODMode = XmlSpawner.TODModeType.Realtime; + defs.KillReset = 1; + defs.SpawnerName = "Spawner"; + defs.AllowGhostTrig = false; + defs.AllowNPCTrig = false; + defs.SpawnOnTrigger = false; + defs.SmartSpawning = false; + defs.ExternalTriggering = false; + defs.TriggerOnCarried = null; + defs.NoTriggerOnCarried = null; + defs.ProximityMsg = null; + defs.TriggerProbability = 1; + defs.PlayerTriggerProp = null; + defs.TriggerObjectProp = null; + defs.DefsExt = null; + defs.AddGumpX = 440; + defs.AddGumpY = 0; + defs.SpawnerGumpX = 0; + defs.SpawnerGumpY = 0; + defs.FindGumpX = 0; + defs.FindGumpY = 0; + defs.AutoNumber = false; + defs.AutoNumberValue = 0; + + + if(defs.SelectionList != null) Array.Clear(defs.SelectionList,0,defs.SelectionList.Length); + if(defs.NameList != null) Array.Clear(defs.NameList,0,defs.NameList.Length); + } + + } + + + + public class XmlAddGump : Gump + { + private const int MaxEntries = 40; + private const int MaxEntriesPerColumn = 20; + private const string DefsDataSetName = "Defs"; + private const string DefsTablePointName = "Values"; + private const string DefsDir = "SpawnerDefs"; + + private static int StartingXoffset = 440; + private Mobile m_From; + + public XmlSpawnerDefaults.DefaultEntry defs; + + + private string NameListToString() + { + if(defs.NameList == null || defs.NameList.Length == 0) + return "0"; + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.AppendFormat( "{0}", defs.NameList.Length); + for(int i = 0; i < defs.NameList.Length;i++) + { + sb.AppendFormat( ":{0}", defs.NameList[i] ); + } + return sb.ToString(); + } + + private string SelectionListToString() + { + if(defs.SelectionList == null || defs.SelectionList.Length == 0) + return "0"; + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.AppendFormat( "{0}", defs.SelectionList.Length); + for(int i = 0; i < defs.SelectionList.Length;i++) + { + sb.AppendFormat( ":{0}", (defs.SelectionList[i] ? 1:0) ); + } + return sb.ToString(); + } + + private string [] StringToNameList(string namelist) + { + string [] newlist = new string[MaxEntries]; + string [] tmplist = namelist.Split(':'); + for(int i = 1;i= newlist.Length) break; + newlist[i-1] = tmplist[i]; + } + return newlist; + } + + private bool [] StringToSelectionList(string selectionlist) + { + bool [] newlist = new bool[MaxEntries]; + string [] tmplist = selectionlist.Split(':'); + for(int i = 1;i= newlist.Length) break; + if(tmplist[i] == "1") + newlist[i-1] = true; + else + newlist[i-1] = false; + } + return newlist; + } + + + private void DoSaveDefs(Mobile from, string filename) + { + if(filename == null || filename.Length <= 0 ) return; + + // Create the data set + DataSet ds = new DataSet( DefsDataSetName ); + + // Load the data set up + ds.Tables.Add( DefsTablePointName ); + + // Create spawn point schema + //ds.Tables[DefsTablePointName].Columns.Add( "AccountName" ); + //ds.Tables[DefsTablePointName].Columns.Add( "PlayerName" ); + ds.Tables[DefsTablePointName].Columns.Add( "MinDelay" ); + ds.Tables[DefsTablePointName].Columns.Add( "MaxDelay" ); + ds.Tables[DefsTablePointName].Columns.Add( "SpawnRange" ); + ds.Tables[DefsTablePointName].Columns.Add( "HomeRange" ); + ds.Tables[DefsTablePointName].Columns.Add( "MinRefractory" ); + ds.Tables[DefsTablePointName].Columns.Add( "MaxRefractory" ); + ds.Tables[DefsTablePointName].Columns.Add( "TODStart" ); + ds.Tables[DefsTablePointName].Columns.Add( "TODEnd" ); + ds.Tables[DefsTablePointName].Columns.Add( "Duration" ); + ds.Tables[DefsTablePointName].Columns.Add( "DespawnTime" ); + ds.Tables[DefsTablePointName].Columns.Add( "RelativeHome" ); + ds.Tables[DefsTablePointName].Columns.Add( "IsGroup" ); + ds.Tables[DefsTablePointName].Columns.Add( "Team" ); + ds.Tables[DefsTablePointName].Columns.Add( "ProximityTriggerSound" ); + ds.Tables[DefsTablePointName].Columns.Add( "SpeechTrigger" ); + ds.Tables[DefsTablePointName].Columns.Add( "SkillTrigger" ); + ds.Tables[DefsTablePointName].Columns.Add( "SequentialSpawn" ); + ds.Tables[DefsTablePointName].Columns.Add( "ProximityRange" ); + ds.Tables[DefsTablePointName].Columns.Add( "TODMode" ); + ds.Tables[DefsTablePointName].Columns.Add( "KillReset" ); + ds.Tables[DefsTablePointName].Columns.Add( "SpawnerName" ); + ds.Tables[DefsTablePointName].Columns.Add( "AllowGhost" ); + ds.Tables[DefsTablePointName].Columns.Add("AllowNPC"); + ds.Tables[DefsTablePointName].Columns.Add( "SpawnOnTrigger" ); + ds.Tables[DefsTablePointName].Columns.Add( "SmartSpawn" ); + ds.Tables[DefsTablePointName].Columns.Add( "ExtTrig" ); + ds.Tables[DefsTablePointName].Columns.Add( "TrigOnCarried" ); + ds.Tables[DefsTablePointName].Columns.Add( "NoTrigOnCarried" ); + ds.Tables[DefsTablePointName].Columns.Add( "ProximityMessage" ); + ds.Tables[DefsTablePointName].Columns.Add( "TrigProb" ); + ds.Tables[DefsTablePointName].Columns.Add( "PlayerTrigProp" ); + ds.Tables[DefsTablePointName].Columns.Add( "TrigObjectProp" ); + //ds.Tables[DefsTablePointName].Columns.Add( "DefsExt" ); + ds.Tables[DefsTablePointName].Columns.Add( "NameList" ); + ds.Tables[DefsTablePointName].Columns.Add( "SelectionList" ); + ds.Tables[DefsTablePointName].Columns.Add( "AddGumpX" ); + ds.Tables[DefsTablePointName].Columns.Add( "AddGumpY" ); + ds.Tables[DefsTablePointName].Columns.Add( "SpawnerGumpX" ); + ds.Tables[DefsTablePointName].Columns.Add( "SpawnerGumpY" ); + ds.Tables[DefsTablePointName].Columns.Add( "FindGumpX" ); + ds.Tables[DefsTablePointName].Columns.Add( "FindGumpY" ); + ds.Tables[DefsTablePointName].Columns.Add( "AutoNumber" ); + ds.Tables[DefsTablePointName].Columns.Add( "AutoNumberValue" ); + + // Create a new data row + DataRow dr = ds.Tables[DefsTablePointName].NewRow(); + + // Populate the data + //dr["AccountName"] = (string)defs.AccountName; + //dr["PlayerName"] = (string)defs.PlayerName; + dr["SpawnerName"] = (string)defs.SpawnerName; + dr["MinDelay"] = (double)defs.MinDelay.TotalMinutes; + dr["MaxDelay"] = (double)defs.MaxDelay.TotalMinutes; + dr["SpawnRange"] = (int)defs.SpawnRange; + dr["HomeRange"] = (int)defs.HomeRange; + dr["RelativeHome"] = (bool)defs.HomeRangeIsRelative; + dr["IsGroup"] = (bool)defs.Group; + dr["Team"] = (int)defs.Team; + dr["MinRefractory"] = (double)defs.RefractMin.TotalMinutes; + dr["MaxRefractory"] = (double)defs.RefractMax.TotalMinutes; + dr["TODStart"] = (double)defs.TODStart.TotalMinutes; + dr["TODEnd"] = (double)defs.TODEnd.TotalMinutes; + dr["TODMode"] = (XmlSpawner.TODModeType)defs.TODMode; + dr["Duration"] = (double)defs.Duration.TotalMinutes; + dr["DespawnTime"] = (double)defs.Duration.TotalHours; + dr["ProximityRange"] = (int)defs.ProximityRange; + dr["ProximityTriggerSound"] = (int)defs.ProximitySound; + dr["ProximityMessage"] = (string)defs.ProximityMsg; + dr["SpeechTrigger"] = (string)defs.SpeechTrigger; + dr["SkillTrigger"] = (string)defs.SkillTrigger; + dr["SequentialSpawn"] = (int)defs.SequentialSpawn; + dr["KillReset"] = (int)defs.KillReset; + dr["TrigProb"] = (double)defs.TriggerProbability; + dr["AllowGhost"] = (bool)defs.AllowGhostTrig; + dr["AllowNPC"] = (bool)defs.AllowNPCTrig; + dr["SpawnOnTrigger"] = (bool)defs.SpawnOnTrigger; + dr["SmartSpawn"] = (bool)defs.SmartSpawning; + dr["ExtTrig"] = (bool)defs.ExternalTriggering; + dr["TrigOnCarried"] = (string)defs.TriggerOnCarried; + dr["NoTrigOnCarried"] = (string)defs.NoTriggerOnCarried; + dr["PlayerTrigProp"] = (string)defs.PlayerTriggerProp; + dr["TrigObjectProp"] = (string)defs.TriggerObjectProp; + dr["NameList"] = NameListToString(); + dr["SelectionList"] = SelectionListToString(); + dr["AddGumpX"] = (int)defs.AddGumpX; + dr["AddGumpY"] = (int)defs.AddGumpY; + dr["SpawnerGumpX"] = (int)defs.SpawnerGumpX; + dr["SpawnerGumpY"] = (int)defs.SpawnerGumpY; + dr["FindGumpX"] = (int)defs.FindGumpX; + dr["FindGumpY"] = (int)defs.FindGumpY; + dr["AutoNumber"] = (bool)defs.AutoNumber; + dr["AutoNumberValue"] = (int)defs.AutoNumberValue; + + // Add the row the the table + ds.Tables[DefsTablePointName].Rows.Add( dr ); + + // Write out the file + bool file_error = false; + string dirname; + if( System.IO.Directory.Exists( DefsDir ) == true ) + { + // put it in the defaults directory if it exists + dirname = String.Format("{0}/{1}.defs",DefsDir,filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = String.Format("{0}.defs",filename); + } + try + { + ds.WriteXml( dirname ); + } + catch { file_error = true;} + + if(file_error) + { + if(from != null && !from.Deleted) + from.SendMessage( "Error trying to save to file {0}", dirname); + return; + } + else + { + if(from != null && !from.Deleted) + from.SendMessage( "Saved defs to file {0}", dirname); + } + + } + + private void DoLoadDefs(Mobile from, string filename) + { + if(filename == null || filename.Length <= 0) return; + string dirname; + if( System.IO.Directory.Exists( DefsDir ) == true ) + { + // look for it in the defaults directory + dirname = String.Format("{0}/{1}.defs",DefsDir,filename); + // Check if the file exists + if( System.IO.File.Exists( dirname ) == false ) + { + // didnt find it so just look in the main install dir + dirname = String.Format("{0}.defs",filename); + } + } + else + { + // look in the main installation dir + dirname = String.Format("{0}.defs",filename); + } + // Check if the file exists + if( System.IO.File.Exists( dirname ) == true ) + { + FileStream fs = null; + try + { + fs = File.Open(dirname, FileMode.Open, FileAccess.Read); + } + catch {} + + if(fs == null) + { + from.SendMessage("Unable to open {0} for loading", dirname); + return; + } + + // Create the data set + DataSet ds = new DataSet( DefsDataSetName ); + + // Read in the file + //ds.ReadXml( e.Arguments[0].ToString() ); + bool fileerror = false; + try + { + ds.ReadXml( fs); + } + catch{fileerror = true;} + // close the file + fs.Close(); + if(fileerror) + { + if(from != null && !from.Deleted) + from.SendMessage( 33, "Error reading defs file {0}", dirname); + return; + } + + // Check that at least a single table was loaded + if( ds.Tables != null && ds.Tables.Count > 0 ) + { + // Add each spawn point to the current map + if(ds.Tables[DefsTablePointName] != null && ds.Tables[DefsTablePointName].Rows.Count > 0) + { + //foreach( DataRow dr in ds.Tables[DefsTablePointName].Rows ){ + DataRow dr = ds.Tables[DefsTablePointName].Rows[0]; + + try{defs.SpawnerName = (string)dr["SpawnerName"];} + catch{} + + double mindelay = defs.MinDelay.TotalMinutes; + try{mindelay = double.Parse((string)dr["MinDelay"]);} + catch{} + defs.MinDelay = TimeSpan.FromMinutes(mindelay); + + double maxdelay = defs.MaxDelay.TotalMinutes; + try{maxdelay = double.Parse((string)dr["MaxDelay"]);} + catch{} + defs.MaxDelay = TimeSpan.FromMinutes(maxdelay); + + try{defs.SpawnRange = int.Parse((string)dr["SpawnRange"]);} + catch{} + try{defs.HomeRange = int.Parse((string)dr["HomeRange"]);} + catch{} + try{defs.HomeRangeIsRelative = bool.Parse((string)dr["RelativeHome"]);} + catch{} + try{defs.Group = bool.Parse((string)dr["IsGroup"]);} + catch{} + try{defs.Team = int.Parse((string)dr["Team"]);} + catch{} + + double minrefract = defs.RefractMin.TotalMinutes; + try{minrefract = double.Parse((string)dr["MinRefractory"]);} + catch{} + defs.RefractMin = TimeSpan.FromMinutes(minrefract); + + double maxrefract = defs.RefractMax.TotalMinutes; + try{maxrefract = double.Parse((string)dr["MaxRefractory"]);} + catch{} + defs.RefractMax = TimeSpan.FromMinutes(maxrefract); + + double todstart = defs.TODStart.TotalMinutes; + try{todstart = double.Parse((string)dr["TODStart"]);} + catch{} + defs.TODStart = TimeSpan.FromMinutes(todstart); + + double todend = defs.TODEnd.TotalMinutes; + try{todend = double.Parse((string)dr["TODEnd"]);} + catch{} + defs.TODEnd = TimeSpan.FromMinutes(todend); + + string todmode = null; + try{todmode = (string)dr["TODMode"];} + catch{} + if(todmode != null) + { + if(todmode == "Realtime") defs.TODMode = XmlSpawner.TODModeType.Realtime; + else + if(todmode == "Gametime") defs.TODMode = XmlSpawner.TODModeType.Gametime; + } + + double duration = defs.Duration.TotalMinutes; + try{duration = double.Parse((string)dr["Duration"]);} + catch{} + defs.Duration = TimeSpan.FromMinutes(duration); + + double despawnTime = defs.DespawnTime.TotalHours; + try{despawnTime = double.Parse((string)dr["DespawnTime"]);} + catch{} + defs.DespawnTime = TimeSpan.FromHours(despawnTime); + + try{defs.ProximityRange = int.Parse((string)dr["ProximityRange"]);} + catch{} + try{defs.ProximitySound = int.Parse((string)dr["ProximityTriggerSound"]);} + catch{} + try{defs.ProximityMsg = (string)dr["ProximityMessage"];} + catch{} + try{defs.SpeechTrigger = (string)dr["SpeechTrigger"];} + catch{} + try{defs.SkillTrigger = (string)dr["SkillTrigger"];} + catch{} + try{defs.SequentialSpawn = int.Parse((string)dr["SequentialSpawn"]);} + catch{} + try{defs.KillReset = int.Parse((string)dr["KillReset"]);} + catch{} + try{defs.TriggerProbability = double.Parse((string)dr["TrigProb"]);} + catch{} + try{defs.AllowGhostTrig = bool.Parse((string)dr["AllowGhost"]);} + catch{} + try { defs.AllowNPCTrig = bool.Parse((string)dr["AllowNPC"]); } + catch { } + try{defs.SpawnOnTrigger = bool.Parse((string)dr["SpawnOnTrigger"]);} + catch{} + try{defs.SmartSpawning = bool.Parse((string)dr["SmartSpawn"]);} + catch{} + try{defs.ExternalTriggering = bool.Parse((string)dr["ExtTrig"]);} + catch{} + try{defs.TriggerOnCarried = (string)dr["TrigOnCarried"];} + catch{} + try{defs.NoTriggerOnCarried = (string)dr["NoTrigOnCarried"];} + catch{} + try{defs.PlayerTriggerProp = (string)dr["PlayerTrigProp"];} + catch{} + try{defs.TriggerObjectProp = (string)dr["TrigObjectProp"];} + catch{} + + try{defs.NameList = StringToNameList((string)dr["NameList"]);} + catch{} + try{defs.SelectionList = StringToSelectionList((string)dr["SelectionList"]);} + catch{} + try{defs.AddGumpX = int.Parse((string)dr["AddGumpX"]);} + catch{} + try{defs.AddGumpY = int.Parse((string)dr["AddGumpY"]);} + catch{} + try{defs.SpawnerGumpX = int.Parse((string)dr["SpawnerGumpX"]);} + catch{} + try{defs.SpawnerGumpY = int.Parse((string)dr["SpawnerGumpY"]);} + catch{} + try{defs.FindGumpX = int.Parse((string)dr["FindGumpX"]);} + catch{} + try{defs.FindGumpY = int.Parse((string)dr["FindGumpY"]);} + catch{} + try{defs.AutoNumber = bool.Parse((string)dr["AutoNumber"]);} + catch{} + try{defs.AutoNumberValue = int.Parse((string)dr["AutoNumberValue"]);} + catch{} + + if(from != null && !from.Deleted) + from.SendMessage("Loaded defs from file {0}", dirname); + } + } + } + else + { + if(from != null && !from.Deleted) + from.SendMessage( 33, "File not found: {0}", dirname); + } + } + + public static void Initialize() + { + CommandSystem.Register( "XmlAdd", AccessLevel.GameMaster, new CommandEventHandler( XmlAdd_OnCommand ) ); + } + + [Usage( "XmlAdd [-defaults]" )] + [Description( "Opens a gump that can add Xmlspawners with specified default settings" )] + public static void XmlAdd_OnCommand( CommandEventArgs e ) + { + Account acct = e.Mobile.Account as Account; + int x = 440; + int y = 0; + XmlSpawnerDefaults.DefaultEntry defs = null; + if(acct != null) + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), e.Mobile.Name); + if(defs != null) + { + x = defs.AddGumpX; + y = defs.AddGumpY; + } + // Check if there is an argument provided (load criteria) + try + { + // Check if there is an argument provided (load criteria) + for(int nxtarg = 0;nxtarg 0) + { + maxcount++; + } + } + + // if autonumbering is enabled, name the spawner with the name+number + string sname = defs.SpawnerName; + if(defs.AutoNumber) + { + sname = String.Format("{0}#{1}",defs.SpawnerName, defs.AutoNumberValue); + } + + XmlSpawner spawner = new XmlSpawner( SpawnId, from.Location.X, from.Location.Y, 0, 0, sname, maxcount, + defs.MinDelay, defs.MaxDelay, defs.Duration, defs.ProximityRange, defs.ProximitySound, 1, + defs.Team, defs.HomeRange, defs.HomeRangeIsRelative, new XmlSpawner.SpawnObject[0], defs.RefractMin, defs.RefractMax, + defs.TODStart, defs.TODEnd, null, defs.TriggerObjectProp, defs.ProximityMsg, defs.TriggerOnCarried, defs.NoTriggerOnCarried, + defs.SpeechTrigger, null, null, defs.PlayerTriggerProp, defs.TriggerProbability , null, defs.Group, defs.TODMode, defs.KillReset, defs.ExternalTriggering, + defs.SequentialSpawn, null, defs.AllowGhostTrig, defs.AllowNPCTrig, defs.SpawnOnTrigger, null, defs.DespawnTime, defs.SkillTrigger, defs.SmartSpawning, null); + + spawner.PlayerCreated = true; + + // if the object is a container, then place it in the container + if(targeted is Container) + { + ((Container)targeted).DropItem(spawner); + } + else + { + // place the spawner at the targeted location + IPoint3D p = targeted as IPoint3D; + if(p == null) + { + spawner.Delete(); + return; + } + if ( p is Item ) + p = ((Item)p).GetWorldTop(); + + spawner.MoveToWorld( new Point3D(p), from.Map ); + + } + + spawner.SpawnRange = defs.SpawnRange; + // add entries from the name list + for(int i = 0; i 0) + { + spawner.AddSpawn = defs.NameList[i]; + } + } + + defs.LastSpawner = spawner; + + if(defs.AutoNumber) + // bump the autonumber + defs.AutoNumberValue++; + + //from.CloseGump(typeof(XmlAddGump)); + XmlAddGump.Refresh(m_state.Mobile, true); + + // open the spawner gump + DoShowGump(from, spawner); + + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if(info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + // read the text entries for default values + XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); + if (defs.IgnoreUpdate) + { + return; + } + + TextRelay tr = info.GetTextEntry( 100 ); // mindelay + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.MinDelay = TimeSpan.FromMinutes(double.Parse(tr.Text));} + catch{} + } + tr = info.GetTextEntry( 101 ); // maxdelay info + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.MaxDelay = TimeSpan.FromMinutes(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 102 ); // min refractory + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.RefractMin = TimeSpan.FromMinutes(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 103 ); // max refractory + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.RefractMax = TimeSpan.FromMinutes(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 104 ); // TOD start + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.TODStart = TimeSpan.FromHours(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 105 ); // TOD end + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.TODEnd = TimeSpan.FromHours(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 106 ); // Speech trigger + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.SpeechTrigger = txt; + } + + + + tr = info.GetTextEntry( 107 ); // HomeRange + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.HomeRange = int.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 108 ); // SpawnRange + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.SpawnRange = int.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 109 ); // ProximityRange + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.ProximityRange = int.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 110 ); // Team + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.Team = int.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 111 ); // Duration + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.Duration = TimeSpan.FromMinutes(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 112 ); // ProximitySound + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.ProximitySound = int.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 113 ); // Kill reset + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.KillReset = int.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 114 ); // Spawner name + if(tr != null) + defs.SpawnerName = tr.Text; + + // DefsExt entry + tr = info.GetTextEntry( 115 ); // save def str + if(tr != null) + defs.DefsExt = tr.Text; + + tr = info.GetTextEntry( 117 ); // trigger on carried + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.TriggerOnCarried = txt; + } + + tr = info.GetTextEntry( 118 ); // no trigger on carried + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.NoTriggerOnCarried = txt; + } + + tr = info.GetTextEntry( 119 ); // proximity message + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.ProximityMsg = txt; + } + + tr = info.GetTextEntry( 120 ); // player trig prop + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.PlayerTriggerProp = txt; + } + + tr = info.GetTextEntry( 121 ); // Trigger probability + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.TriggerProbability = double.Parse(tr.Text);} + catch{} + } + + tr = info.GetTextEntry( 122 ); // trig object prop + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.TriggerObjectProp = txt; + } + + tr = info.GetTextEntry( 123 ); // DespawnTime + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.DespawnTime = TimeSpan.FromHours(double.Parse(tr.Text));} + catch{} + } + + tr = info.GetTextEntry( 124 ); // Skill trigger + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) txt = null; + defs.SkillTrigger = txt; + } + + tr = info.GetTextEntry( 125 ); // AutoNumberValue + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.AutoNumberValue = int.Parse(tr.Text);} + catch{} + } + + + // fill the NameList from the text entries + if(defs.ShowExtension) + for(int i=0;i 0) + { + filename = String.Format("{0}-{1}-{2}",defs.AccountName, defs.PlayerName, defs.DefsExt); + } + else + { + filename = String.Format("{0}-{1}",defs.AccountName, defs.PlayerName); + } + DoSaveDefs(state.Mobile,filename); + break; + } + case 116: // LoadDefs + { + string filename; + if(defs.DefsExt != null && defs.DefsExt.Length > 0) + { + filename = String.Format("{0}-{1}-{2}",defs.AccountName, defs.PlayerName, defs.DefsExt); + } + else + { + filename = String.Format("{0}-{1}",defs.AccountName, defs.PlayerName); + } + DoLoadDefs(state.Mobile,filename); + break; + } + case 117: // Restore Defaults + { + state.Mobile.SendMessage(String.Format("Restoring defaults")); + XmlSpawnerDefaults.RestoreDefs(defs); + break; + } + case 155: // Return the player to the starting loc + { + m_From.Location = defs.StartingLoc; + m_From.Map = defs.StartingMap; + break; + } + case 156: // Delete last spawner + { + if(defs.LastSpawner == null || defs.LastSpawner.Deleted) break; + Refresh(state.Mobile); + state.Mobile.SendGump( new XmlAddConfirmDeleteGump(state.Mobile, defs.LastSpawner) ); + return; + } + case 157: // Reset last spawner + { + if(defs.LastSpawner != null && !defs.LastSpawner.Deleted) + defs.LastSpawner.DoReset = true; + break; + } + case 158: // Respawn last spawner + { + if(defs.LastSpawner != null && !defs.LastSpawner.Deleted) + defs.LastSpawner.DoRespawn = true; + break; + } + case 180: // Set Options + { + Refresh(state.Mobile); + state.Mobile.SendGump( new XmlAddOptionsGump(state.Mobile, defs.LastSpawner) ); + return; + } + case 200: // gump extension + { + defs.ShowExtension = !defs.ShowExtension; + break; + } + case 306: // TOD mode + { + if(defs.TODMode == XmlSpawner.TODModeType.Realtime) + defs.TODMode = XmlSpawner.TODModeType.Gametime; + else + defs.TODMode = XmlSpawner.TODModeType.Realtime; + break; + } + case 1000: // GoTo + { + // then go to it + DoGoTo(defs.LastSpawner); + break; + } + case 1001: // Show Gump + { + Refresh(state.Mobile); + DoShowGump(state.Mobile, defs.LastSpawner); + break; + } + case 1002: // Show Props + { + Refresh(state.Mobile); + DoShowProps(defs.LastSpawner); + break; + } + case 3999: // clear selections + { + // clear the selections + if(defs.SelectionList != null) Array.Clear(defs.SelectionList,0,defs.SelectionList.Length); + break; + } + case 9998: // refresh the gump + { + break; + } + default: + { + if(info.ButtonID >= 4000 && info.ButtonID < 4000+ MaxEntries) + { + int i = info.ButtonID - 4000; + if(defs.SelectionList != null && i >= 0 && i < defs.SelectionList.Length) + { + defs.SelectionList[i] = !defs.SelectionList[i]; + } + } + if(info.ButtonID >= 5000 && info.ButtonID < 5000+ MaxEntries) + { + int i = info.ButtonID - 5000; + /* + string match = null; + if(defs.NameList[i] != null) + { + match = defs.NameList[i].Trim(); + } + */ + + defs.CategorySelectionIndex = i; + XmlAddGump newg = new XmlAddGump(state.Mobile, defs.StartingLoc, defs.StartingMap, false, defs.ShowExtension, 0,0); + + state.Mobile.SendGump( newg ); + + if(defs.NameList[i] == null || defs.NameList[i].Length == 0) + { + + // if no string has been entered then just use the full categorized add gump + state.Mobile.CloseGump( typeof(Server.Gumps.XmlCategorizedAddGump)); + state.Mobile.SendGump( new Server.Gumps.XmlCategorizedAddGump( state.Mobile, defs.CurrentCategory, defs.CurrentCategoryPage,i, newg ) ); + } + else + { + // use the XmlPartialCategorizedAddGump + state.Mobile.CloseGump( typeof(Server.Gumps.XmlPartialCategorizedAddGump)); + + //Type [] types = (Type[])XmlPartialCategorizedAddGump.Match( defs.NameList[i] ).ToArray( typeof( Type ) ); + ArrayList types = XmlPartialCategorizedAddGump.Match( defs.NameList[i] ); + state.Mobile.SendGump( new XmlPartialCategorizedAddGump( state.Mobile, defs.NameList[i], 0, types, true, i, newg ) ); + } + return; + /* + if(match == null || match.Length == 0) + { + state.Mobile.SendGump( new Server.Gumps.XmlCategorizedAddGump( state.Mobile, i, this ) ); + } else + { + state.Mobile.SendGump( new Server.Gumps.XmlLookupCategorizedAddGump( state.Mobile, match, 0, + (Type[])Server.Gumps.AddGump.Match( match ).ToArray( typeof( Type ) ), true ) ); + } + */ + + + } + break; + } + } + // Create a new gump + //m_Spawner.OnDoubleClick( state.Mobile); + Refresh(state.Mobile); + } + + private class XmlAddOptionsGump : Gump + { + private Mobile From; + private XmlSpawner LastSpawner; + + public XmlAddOptionsGump(Mobile from, XmlSpawner lastSpawner) : base ( 0, 0 ) + { + + // read the text entries for default values + // read the text entries for default values + Account acct = from.Account as Account; + XmlSpawnerDefaults.DefaultEntry defs = null; + if(acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + } + + if(defs == null) return; + + From = from; + LastSpawner = lastSpawner; + Closable = true; + Dragable = true; + AddPage( 0 ); + AddBackground( 0, 0, 300, 130, 5054 ); + + + AddLabel( 20, 5, 0, String.Format("Options") ); + // add the AddGumpX/Y entries + AddImageTiled( 5, 30, 40, 21, 0xBBC ); + AddTextEntry( 5, 30, 40, 21, 0, 100, defs.AddGumpX.ToString() ); + AddLabel( 45, 30, 0x384, "AddGumpX" ); + + AddImageTiled( 135, 30, 40, 21, 0xBBC ); + AddTextEntry( 135, 30, 40, 21, 0, 101, defs.AddGumpY.ToString() ); + AddLabel( 175, 30, 0x384, "AddGumpY" ); + + // add the SpawnerGumpX/Y entries + AddImageTiled( 5, 55, 40, 21, 0xBBC ); + AddTextEntry( 5, 55, 40, 21, 0, 102, defs.SpawnerGumpX.ToString() ); + AddLabel( 45, 55, 0x384, "SpawnerGumpX" ); + + AddImageTiled( 135, 55, 40, 21, 0xBBC ); + AddTextEntry( 135, 55, 40, 21, 0, 103, defs.SpawnerGumpY.ToString() ); + AddLabel( 175, 55, 0x384, "SpawnerGumpY" ); + + // add the FindGumpX/Y entries + AddImageTiled( 5, 80, 40, 21, 0xBBC ); + AddTextEntry( 5, 80, 40, 21, 0, 104, defs.FindGumpX.ToString() ); + AddLabel( 45, 80, 0x384, "FindGumpX" ); + + AddImageTiled( 135, 80, 40, 21, 0xBBC ); + AddTextEntry( 135, 80, 40, 21, 0, 105, defs.FindGumpY.ToString() ); + AddLabel( 175, 80, 0x384, "FindGumpY" ); + + + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + // read the text entries for default values + XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); + if(defs == null) return; + + TextRelay tr = info.GetTextEntry( 100 ); // AddGumpX + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.AddGumpX = int.Parse(tr.Text);} + catch{} + } + tr = info.GetTextEntry( 101 ); // AddGumpY info + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.AddGumpY = int.Parse(tr.Text);} + catch{} + } + tr = info.GetTextEntry( 102 ); // SpawnerGumpX info + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.SpawnerGumpX = int.Parse(tr.Text);} + catch{} + } + tr = info.GetTextEntry( 103 ); // SpawnerGumpY info + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.SpawnerGumpY = int.Parse(tr.Text);} + catch{} + } + tr = info.GetTextEntry( 104 ); // FindGumpX info + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.FindGumpX = int.Parse(tr.Text);} + catch{} + } + tr = info.GetTextEntry( 105 ); // FindGumpY info + if(tr != null && tr.Text != null && tr.Text.Length > 0) + { + try{defs.FindGumpY = int.Parse(tr.Text);} + catch{} + } + } + + } + + private class XmlAddConfirmDeleteGump : Gump + { + private Mobile From; + private XmlSpawner LastSpawner; + + public XmlAddConfirmDeleteGump(Mobile from, XmlSpawner lastSpawner) : base ( 0, 0 ) + { + + From = from; + LastSpawner = lastSpawner; + Closable = false; + Dragable = true; + AddPage( 0 ); + AddBackground( 10, 200, 200, 130, 5054 ); + + + AddLabel( 20, 225, 33, String.Format("Delete Last Spawner?") ); + AddRadio( 35, 255, 9721, 0x86A, false, 1 ); // accept/yes radio + AddRadio( 135, 255, 9721, 0x86A, true, 2 ); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff , false , false ); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff , false , false ); // No + AddButton( 80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0 ); // Okay button + + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if(info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch(info.ButtonID) + { + default: + { + if(radiostate == 1 && LastSpawner != null && !LastSpawner.Deleted) + { // accept + // delete it + LastSpawner.Delete(); + } + break; + } + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlUtils/XmlCategorizedAddGump.cs b/Scripts/Customs/XML Spawner/XmlUtils/XmlCategorizedAddGump.cs new file mode 100644 index 0000000..ceca7ef --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/XmlCategorizedAddGump.cs @@ -0,0 +1,476 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; +using Server.Network; +using Server.Mobiles; + +/* +** Modified from RunUO 1.0.0 CategorizedAddGump.cs +** by ArteGordon +** 2/5/05 +*/ +namespace Server.Gumps +{ + + public abstract class XmlAddCAGNode + { + public abstract string Caption{ get; } + public abstract void OnClick( Mobile from, int page, int index, Gump gump ); + } + + public class XmlAddCAGObject : XmlAddCAGNode + { + private Type m_Type; + private int m_ItemID; + private int m_Hue; + private XmlAddCAGCategory m_Parent; + + public Type Type{ get{ return m_Type; } } + public int ItemID{ get{ return m_ItemID; } } + public int Hue{ get{ return m_Hue; } } + public XmlAddCAGCategory Parent{ get{ return m_Parent; } } + + public override string Caption{ get{ return ( m_Type == null ? "bad type" : m_Type.Name ); } } + + public override void OnClick( Mobile from, int page, int index, Gump gump ) + { + if ( m_Type == null ) + { + from.SendMessage( "That is an invalid type name." ); + } + else + { + if(gump is XmlAddGump) + { + XmlAddGump xmladdgump = (XmlAddGump)gump; + + //Commands.Handle( from, String.Format( "{0}Add {1}", Commands.CommandPrefix, m_Type.Name ) ); + if(xmladdgump != null && xmladdgump.defs != null && xmladdgump.defs.NameList != null && + index >= 0 && index < xmladdgump.defs.NameList.Length) + { + + xmladdgump.defs.NameList[index] = m_Type.Name; + XmlAddGump.Refresh(from, true); + } + from.SendGump( new XmlCategorizedAddGump( from, m_Parent, page, index, xmladdgump ) ); + } + else + if(gump is XmlSpawnerGump) + { + XmlSpawner m_Spawner = ((XmlSpawnerGump)gump).m_Spawner; + + if(m_Spawner != null) + { + XmlSpawnerGump xg = m_Spawner.SpawnerGump; + + if(xg != null) + { + + xg.Rentry = new XmlSpawnerGump.ReplacementEntry(); + xg.Rentry.Typename = m_Type.Name; + xg.Rentry.Index = index; + xg.Rentry.Color = 0x1436; + + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( XmlSpawnerGump.Refresh_Callback ), new object[]{ from } ); + //from.CloseGump(typeof(XmlSpawnerGump)); + //from.SendGump( new XmlSpawnerGump(xg.m_Spawner, xg.X, xg.Y, xg.m_ShowGump, xg.xoffset, xg.page, xg.Rentry) ); + } + } + } + } + } + + public XmlAddCAGObject( XmlAddCAGCategory parent, XmlTextReader xml ) + { + m_Parent = parent; + + if ( xml.MoveToAttribute( "type" ) ) + m_Type = ScriptCompiler.FindTypeByFullName( xml.Value, false ); + + if ( xml.MoveToAttribute( "gfx" ) ) + m_ItemID = XmlConvert.ToInt32( xml.Value ); + + if ( xml.MoveToAttribute( "hue" ) ) + m_Hue = XmlConvert.ToInt32( xml.Value ); + } + } + + public class XmlAddCAGCategory : XmlAddCAGNode + { + private string m_Title; + private XmlAddCAGNode[] m_Nodes; + private XmlAddCAGCategory m_Parent; + + public string Title{ get{ return m_Title; } } + public XmlAddCAGNode[] Nodes{ get{ return m_Nodes; } } + public XmlAddCAGCategory Parent{ get{ return m_Parent; } } + + public override string Caption{ get{ return m_Title; } } + + public override void OnClick( Mobile from, int page, int index, Gump gump ) + { + from.SendGump( new XmlCategorizedAddGump( from, this, 0, index, gump ) ); + } + + private XmlAddCAGCategory() + { + m_Title = "no data"; + m_Nodes = new XmlAddCAGNode[0]; + } + + public XmlAddCAGCategory( XmlAddCAGCategory parent, XmlTextReader xml ) + { + m_Parent = parent; + + if ( xml.MoveToAttribute( "title" ) ) + { + if(xml.Value == "Add Menu") + m_Title = "XmlAdd Menu"; + else + m_Title = xml.Value; + + } + else + m_Title = "empty"; + + if ( m_Title == "Docked" ) + m_Title = "Docked 2"; + + if ( xml.IsEmptyElement ) + { + m_Nodes = new XmlAddCAGNode[0]; + } + else + { + ArrayList nodes = new ArrayList(); + + try{ + while ( xml.Read() && xml.NodeType != XmlNodeType.EndElement ) + { + + if ( xml.NodeType == XmlNodeType.Element && xml.Name == "object" ) + nodes.Add( new XmlAddCAGObject( this, xml ) ); + else if (xml.NodeType == XmlNodeType.Element && xml.Name == "category") + { + if (!xml.IsEmptyElement) + { + + nodes.Add(new XmlAddCAGCategory(this, xml)); + } + } + else + xml.Skip(); + + } + } catch (Exception ex){ + Console.WriteLine("XmlCategorizedAddGump: Corrupted Data/objects.xml file detected. Not all XmlCAG objects loaded. {0}", ex); + } + + + m_Nodes = (XmlAddCAGNode[])nodes.ToArray( typeof( XmlAddCAGNode ) ); + + } + } + + private static XmlAddCAGCategory m_Root; + + public static XmlAddCAGCategory Root + { + get + { + if ( m_Root == null ) + m_Root = Load( "Data/objects.xml" ); + + return m_Root; + } + } + + public static XmlAddCAGCategory Load( string path ) + { + if ( File.Exists( path ) ) + { + XmlTextReader xml = new XmlTextReader( path ); + + xml.WhitespaceHandling = WhitespaceHandling.None; + + while ( xml.Read() ) + { + if ( xml.Name == "category" && xml.NodeType == XmlNodeType.Element ) + { + XmlAddCAGCategory cat = new XmlAddCAGCategory( null, xml ); + + xml.Close(); + + return cat; + } + } + } + + return new XmlAddCAGCategory(); + } + } + + + + public class XmlCategorizedAddGump : Gump + { + public static bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = 24;//PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static bool PrevLabel = false, NextLabel = false; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int EntryWidth = 180; + private static readonly int EntryCount = 15; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + private Mobile m_Owner; + private XmlAddCAGCategory m_Category; + private int m_Page; + + private int m_Index = -1; + private Gump m_Gump; + private XmlSpawner m_Spawner; + + public XmlCategorizedAddGump( Mobile owner, int index, Gump gump ) : this( owner, XmlAddCAGCategory.Root, 0, index, gump ) + { + } + + public XmlCategorizedAddGump( Mobile owner, XmlAddCAGCategory category, int page, int index, Gump gump ) : base( GumpOffsetX, GumpOffsetY ) + { + if (category == null) + { + category = XmlAddCAGCategory.Root; + page = 0; + } + + owner.CloseGump( typeof( WhoGump ) ); + + m_Owner = owner; + m_Category = category; + + m_Index = index; + m_Gump = gump; + if(gump is XmlAddGump) + { + XmlAddGump xmladdgump = (XmlAddGump)gump; + + if(xmladdgump != null && xmladdgump.defs != null) + { + xmladdgump.defs.CurrentCategory = category; + xmladdgump.defs.CurrentCategoryPage = page; + } + } + else + if(gump is XmlSpawnerGump) + { + m_Spawner = ((XmlSpawnerGump)gump).m_Spawner; + + + } + + Initialize( page ); + } + + public void Initialize( int page ) + { + m_Page = page; + + XmlAddCAGNode[] nodes = m_Category.Nodes; + + int count = nodes.Length - (page * EntryCount); + + if ( count < 0 ) + count = 0; + else if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1)); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( m_Category.Parent != null ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + int emptyWidth = TotalWidth - (PrevWidth * 2) - NextWidth - (OffsetSize * 5) - (OldStyle ? SetWidth + OffsetSize : 0); + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID ); + + AddHtml( x + TextOffsetX, y + ((EntryHeight - 20) / 2), emptyWidth - TextOffsetX, EntryHeight, String.Format( "
{0}
", m_Category.Caption ), false, false ); + + x += emptyWidth + OffsetSize; + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 0 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 2, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( (page + 1) * EntryCount < nodes.Length ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + for ( int i = 0, index = page * EntryCount; i < EntryCount && index < nodes.Length; ++i, ++index ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + XmlAddCAGNode node = nodes[index]; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y + ((EntryHeight - 20) / 2), EntryWidth - TextOffsetX, EntryHeight, TextHue, node.Caption ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 4, GumpButtonType.Reply, 0 ); + + if ( node is XmlAddCAGObject ) + { + XmlAddCAGObject obj = (XmlAddCAGObject)node; + int itemID = obj.ItemID; + + Rectangle2D bounds = ItemBounds.Table[itemID]; + + if ( itemID != 1 && bounds.Height < (EntryHeight * 2) ) + { + if ( bounds.Height < EntryHeight ) + AddItem( x - OffsetSize - 22 - ((i % 2) * 44) - (bounds.Width / 2) - bounds.X, y + (EntryHeight / 2) - (bounds.Height / 2) - bounds.Y, itemID ); + else + AddItem( x - OffsetSize - 22 - ((i % 2) * 44) - (bounds.Width / 2) - bounds.X, y + EntryHeight - 1 - bounds.Height - bounds.Y, itemID ); + } + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = m_Owner; + + switch ( info.ButtonID ) + { + case 0: // Closed + { + return; + } + case 1: // Up + { + if ( m_Category.Parent != null ) + { + int index = Array.IndexOf( m_Category.Parent.Nodes, m_Category ) / EntryCount; + + if ( index < 0 ) + index = 0; + + from.SendGump( new XmlCategorizedAddGump( from, m_Category.Parent, index, m_Index, m_Gump ) ); + } + + break; + } + case 2: // Previous + { + if ( m_Page > 0 ) + from.SendGump( new XmlCategorizedAddGump( from, m_Category, m_Page - 1, m_Index, m_Gump ) ); + + break; + } + case 3: // Next + { + if ( (m_Page + 1) * EntryCount < m_Category.Nodes.Length ) + from.SendGump( new XmlCategorizedAddGump( from, m_Category, m_Page + 1, m_Index, m_Gump ) ); + + break; + } + default: + { + int index = (m_Page * EntryCount) + (info.ButtonID - 4); + + if ( index >= 0 && index < m_Category.Nodes.Length ) + { + m_Category.Nodes[index].OnClick( from, m_Page, m_Index, m_Gump ); + } + + break; + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlUtils/XmlEdit.cs b/Scripts/Customs/XML Spawner/XmlUtils/XmlEdit.cs new file mode 100644 index 0000000..e3b021a --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/XmlEdit.cs @@ -0,0 +1,1299 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using System.Text; +using Server.Accounting; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +/* +** XmlEditNPC +** Version 1.00 +** updated 5/24/05 +** ArteGordon +** +** +*/ + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlEditDialogGump : Gump + { + private const int MaxEntries = 8; + private const int MaxEntriesPerPage = 8; + + private Mobile m_From; + private string Name; + private int Selected; + private int DisplayFrom; + private string SaveFilename; + private bool [] m_SelectionList; + private XmlDialog m_Dialog; + + private bool SelectAll = false; + + private ArrayList m_SearchList; + + public static void Initialize() + { + CommandSystem.Register( "XmlEdit", AccessLevel.GameMaster, new CommandEventHandler( XmlEditDialog_OnCommand ) ); + } + + [Usage( "XmlEdit" )] + [Description( "Edits XmlDialog entries on an object" )] + public static void XmlEditDialog_OnCommand( CommandEventArgs e ) + { + if(e == null || e.Mobile == null) return; + + // target an object with the xmldialog attachment + e.Mobile.Target = new EditDialogTarget(); + + + } + + private class EditDialogTarget : Target + { + + public EditDialogTarget() : base ( 30, true, TargetFlags.None ) + { + + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if(from == null) return; + + // does it have an xmldialog attachment? + XmlDialog xd = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog; + + if(xd == null) + { + from.SendMessage("Target has no XmlDialog attachment"); + + // TODO: ask whether they would like to add one + from.SendGump( new XmlConfirmAddGump(from, targeted)); + + return; + } + + from.SendGump( new XmlEditDialogGump(from, true, xd, -1, 0, null, false, null, 0, 0)); + } + } + + public class XmlConfirmAddGump : Gump + { + private Mobile m_From; + private object m_Targeted; + + public XmlConfirmAddGump(Mobile from, object targeted) : base ( 0, 0 ) + { + if(from == null || targeted == null) return; + + m_Targeted = targeted; + m_From = from; + + Closable = false; + Dragable = true; + AddPage( 0 ); + AddBackground( 10, 200, 200, 130, 5054 ); + + AddLabel( 20, 210, 68, String.Format("Add an XmlDialog to target?") ); + + string name = null; + if(targeted is Item) + { + name = ((Item)targeted).Name; + } + else + if(targeted is Mobile) + { + name = ((Mobile)targeted).Name; + } + + if(name == null) + { + name = targeted.GetType().Name; + } + AddLabel( 20, 230, 0, String.Format("{0}", name) ); + + AddRadio( 35, 255, 9721, 9724, false, 1 ); // accept/yes radio + AddRadio( 135, 255, 9721, 9724, true, 2 ); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff , false , false ); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff , false , false ); // No + AddButton( 80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0 ); // Okay button + + } + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if(info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch(info.ButtonID) + { + + default: + { + if(radiostate == 1) + { // accept + + // add the attachment + XmlDialog xd = new XmlDialog(); + XmlAttach.AttachTo(state.Mobile, m_Targeted, xd); + + // open the editing gump + state.Mobile.SendGump( new XmlEditDialogGump(state.Mobile, true, xd, -1, 0, null, false, null, 0, 0)); + } + break; + } + } + } + } + + public const int MaxLabelLength = 200; + public string TruncateLabel(string s) + { + if (s == null || s.Length < MaxLabelLength) return s; + + return s.Substring(0,MaxLabelLength); + } + + public XmlEditDialogGump( Mobile from, bool firststart, + XmlDialog dialog, int selected, int displayfrom, string savefilename, + bool selectall, bool [] selectionlist, int X, int Y ) : base( X,Y ) + { + + if(from == null || dialog == null) return; + + m_Dialog = dialog; + m_From = from; + + m_SelectionList = selectionlist; + if(m_SelectionList == null) + { + m_SelectionList = new bool[MaxEntries]; + } + SaveFilename = savefilename; + + DisplayFrom = displayfrom; + Selected = selected; + + // fill the list with the XmlDialog entries + m_SearchList = dialog.SpeechEntries; + + // prepare the page + int height = 500; + + + AddPage( 0 ); + + AddBackground( 0, 0, 755, height, 5054 ); + AddAlphaRegion( 0, 0, 755, height ); + + // add the separators + AddImageTiled( 10, 80, 735, 4, 0xBB9 ); + AddImageTiled( 10, height -212, 735, 4, 0xBB9 ); + AddImageTiled( 10, height -60, 735, 4, 0xBB9 ); + + // add the xmldialog properties + int y = 5; + int w = 140; + int x = 5; + int lw = 0; + // the dialog name + AddImageTiled( x, y, w, 21, 0x23F4 ); + // get the name of the object this is attached to + + if(m_Dialog.AttachedTo is Item) + { + Name = ((Item)m_Dialog.AttachedTo).Name; + } + else + if(m_Dialog.AttachedTo is Mobile) + { + Name = ((Mobile)m_Dialog.AttachedTo).Name; + } + if(Name == null && m_Dialog.AttachedTo != null) + { + Name = m_Dialog.AttachedTo.GetType().Name; + } + AddLabelCropped( x, y, w, 21, 0, Name ); + + + x += w + lw + 20; + w = 40; + lw = 90; + // add the proximity range + AddLabel( x, y, 0x384, "ProximityRange" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 140, m_Dialog.ProximityRange.ToString() ); + + x += w + lw + 20; + w = 100; + lw = 60; + // reset time + AddLabel( x, y, 0x384, "ResetTime" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 141, m_Dialog.ResetTime.ToString() ); + + x += w + lw + 20; + w = 40; + lw = 65; + // speech pace + AddLabel( x, y, 0x384, "SpeechPace" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 142, m_Dialog.SpeechPace.ToString() ); + + x += w + lw + 20; + w = 30; + lw = 55; + // allow ghost triggering + AddLabel( x, y, 0x384, "GhostTrig" ); + AddCheck( x+lw, y, 0xD2, 0xD3, m_Dialog.AllowGhostTrig, 260); + + // add the triggeroncarried + y += 27; + w = 600; + x = 10; + lw = 100; + AddLabel( 10, y, 0x384, "TrigOnCarried" ); + AddImageTiled( x + lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 150, TruncateLabel(m_Dialog.TriggerOnCarried) ); + AddButton( 720, y, 0xFAB, 0xFAD, 5005, GumpButtonType.Reply, 0 ); + + // add the notriggeroncarried + y += 22; + w = 600; + x = 10; + lw = 100; + AddLabel( x, y, 0x384, "NoTrigOnCarried" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry(x + lw, y, w, 21, 0, 151, TruncateLabel(m_Dialog.NoTriggerOnCarried)); + AddButton( 720, y, 0xFAB, 0xFAD, 5006, GumpButtonType.Reply, 0 ); + + y = 88; + // column labels + AddLabel( 10, y, 0x384, "Edit" ); + AddLabel( 45, y, 0x384, "#" ); + AddLabel( 95, y, 0x384, "ID" ); + AddLabel( 145, y, 0x384, "Depends" ); + AddLabel( 195, y, 0x384, "Keywords" ); + AddLabel( 295, y, 0x384, "Text" ); + AddLabel( 540, y, 0x384, "Action" ); + AddLabel( 602, y, 0x384, "Condition" ); + AddLabel( 664, y, 0x384, "Gump" ); + + // display the select-all-displayed toggle + AddButton( 730, y, 0xD2, 0xD3, 3999, GumpButtonType.Reply, 0 ); + + y -= 10; + for ( int i = 0; i < MaxEntries; i++ ) + { + int index = i + DisplayFrom; + if(m_SearchList == null || index >= m_SearchList.Count) break; + int page = (int)(i/MaxEntriesPerPage); + if(i%MaxEntriesPerPage == 0) + { + AddPage(page+1); + // add highlighted page button + //AddImageTiled( 235+page*25, 448, 25, 25, 0xBBC ); + //AddImage( 238+page*25, 450, 0x8B1+page ); + } + + // background for search results area + AddImageTiled( 235, y + 22 * (i%MaxEntriesPerPage) + 30, 386, 23, 0x52 ); + AddImageTiled( 236, y + 22 * (i%MaxEntriesPerPage) + 31, 384, 21, 0xBBC ); + + + XmlDialog.SpeechEntry s = (XmlDialog.SpeechEntry)m_SearchList[index]; + + if(s == null) continue; + + int texthue = 0; + + bool sel=false; + + if(m_SelectionList != null && i < m_SelectionList.Length) + { + sel = m_SelectionList[i]; + } + + // entries with the selection box checked are highlighted in red + if(sel) texthue = 33; + + // the selected entry is highlighted in green + if(i == Selected) texthue = 68; + + x = 10; + w = 35; + // add the Edit button for each entry + AddButton( 10, y + 22 * (i%MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1000+i, GumpButtonType.Reply, 0 ); + + x += w; + w = 50; + // display the entry number + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC ); + AddLabel( x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.EntryNumber.ToString() ); + + x += w; + w = 50; + // display the entry ID + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4 ); + AddLabel( x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.ID.ToString() ); + + x += w; + w = 50; + // display the entry dependson + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC ); + AddLabel( x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.DependsOn ); + + x += w; + w = 100; + // display the entry keywords + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4 ); + AddLabelCropped( x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Keywords) ); + + x += w; + w = 245; + // display the entry text + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC ); + AddLabelCropped( x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Text) ); + + x += w; + w = 62; + // display the action text + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4 ); + AddLabelCropped( x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Action) ); + + x += w; + w = 62; + // display the condition text + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC ); + AddLabelCropped( x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Condition) ); + + x += w; + w = 62; + // display the gump text + AddImageTiled( x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4 ); + AddLabelCropped( x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Gump) ); + + // display the selection button + AddButton( 730, y + 22 * (i%MaxEntriesPerPage) + 32, (sel? 0xD3:0xD2), (sel? 0xD2:0xD3), 4000+i, GumpButtonType.Reply, 0 ); + + } + + + // display the selected entry information for editing + XmlDialog.SpeechEntry sentry = null; + if(Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) + { + sentry = (XmlDialog.SpeechEntry)m_SearchList[Selected+ DisplayFrom]; + } + + if(sentry != null) + { + + y = height - 200; + + // add the entry parameters + lw = 15; + w = 40; + x = 10; + int spacing = 11; + + // entry number + AddLabel( x, y, 0x384, "#" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 200, sentry.EntryNumber.ToString() ); + + x += w + lw + spacing; + w = 40; + lw = 17; + // ID number + AddLabel( x, y, 0x384, "ID" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 201, sentry.ID.ToString() ); + + x += w + lw + spacing; + w = 40; + lw = 65; + // depends on + AddLabel( x, y, 0x384, "DependsOn" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 202, sentry.DependsOn ); + + x += w + lw + spacing; + w = 35; + lw = 57; + // prepause + AddLabel( x, y, 0x384, "PrePause" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 203, sentry.PrePause.ToString() ); + + x += w + lw + spacing; + w = 35; + lw = 37; + // pause + AddLabel( x, y, 0x384, "Pause" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 204, sentry.Pause.ToString() ); + + x += w + lw + spacing; + w = 37; + lw = 26; + // speech hue + AddLabel( x, y, 0x384, "Hue" ); + AddImageTiled( x+lw, y, w, 21, 0xBBC ); + AddTextEntry( x+lw, y, w, 21, 0, 205, sentry.SpeechHue.ToString() ); + + x += w + lw + spacing; + w = 20; + lw = 52; + // lock conversation + AddLabel(x, y, 0x384, "IgnoreCar"); + AddCheck(x + lw, y, 0xD2, 0xD3, sentry.IgnoreCarried, 252); + + x += w + lw + spacing; + w = 20; + lw = 42; + // lock conversation + AddLabel( x, y, 0x384, "LockOn" ); + AddCheck( x+lw, y, 0xD2, 0xD3, sentry.LockConversation, 250); + + x += w + lw + spacing; + w = 20; + lw = 54; + // npctrigger + AddLabel( x, y, 0x384, "AllowNPC" ); + AddCheck( x+lw, y, 0xD2, 0xD3, sentry.AllowNPCTrigger, 251); + + + w = 650; + x = 70; + + y += 27; + // add the keyword entry + AddLabel( 10, y, 0x384, "Keywords" ); + AddImageTiled( x, y, w, 21, 0xBBC ); + AddTextEntry( x+1, y, w, 21, 0, 101, sentry.Keywords ); + AddButton( 720, y, 0xFAB, 0xFAD, 5001, GumpButtonType.Reply, 0 ); + + y += 22; + // add the text entry + AddLabel( 10, y, 0x384, "Text" ); + AddImageTiled( x, y, w, 21, 0xBBC ); + AddTextEntry( x+1, y, w, 21, 0, 100, sentry.Text ); + AddButton( 720, y, 0xFAB, 0xFAD, 5000, GumpButtonType.Reply, 0 ); + + + y += 22; + // add the condition string entry + AddLabel( 10, y, 0x384, "Condition" ); + AddImageTiled( x, y, w, 21, 0xBBC ); + AddTextEntry( x+1, y, w, 21, 0, 102, sentry.Condition ); + AddButton( 720, y, 0xFAB, 0xFAD, 5002, GumpButtonType.Reply, 0 ); + + y += 22; + // add the action string entry + AddLabel( 10, y, 0x384, "Action" ); + AddImageTiled( x, y, w, 21, 0xBBC ); + AddTextEntry( x+1, y, w, 21, 0, 103, sentry.Action ); + AddButton( 720, y, 0xFAB, 0xFAD, 5003, GumpButtonType.Reply, 0 ); + + y += 22; + // add the gump string entry + AddLabel( 10, y, 0x384, "Gump" ); + AddImageTiled( x, y, w, 21, 0xBBC ); + AddTextEntry( x+1, y, w, 21, 0, 104, sentry.Gump ); + AddButton( 720, y, 0xFAB, 0xFAD, 5004, GumpButtonType.Reply, 0 ); + } + + y = height - 50; + + AddLabel( 10, y, 0x384, "Config:" ); + AddImageTiled( 50, y , 120, 19, 0x23F4 ); + AddLabel( 50, y, 0, m_Dialog.ConfigFile ); + + if(from.AccessLevel >= XmlSpawner.DiskAccessLevel) + { + + // add the save entry + AddButton( 185, y , 0xFA8, 0xFAA, 159, GumpButtonType.Reply, 0 ); + AddLabel( 218, y , 0x384, "Save to file:" ); + AddImageTiled( 300, y , 180, 19, 0xBBC ); + AddTextEntry( 300, y, 180, 19, 0, 300, SaveFilename ); + } + + // display the item list + if(m_SearchList != null) + { + AddLabel( 495, y, 68, String.Format("{0} Entries",m_SearchList.Count) ); + int last = DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count; + if(last > 0) + AddLabel( 595, y, 68, String.Format("Displaying {0}-{1}",DisplayFrom, last -1) ); + } + + y = height - 25; + + // add run status display + if(m_Dialog.Running) + { + AddButton( 10, y-5, 0x2A4E, 0x2A3A, 100, GumpButtonType.Reply, 0 ); + AddLabel( 43, y, 0x384, "On" ); + } + else + { + AddButton( 10, y-5, 0x2A62, 0x2A3A, 100, GumpButtonType.Reply, 0 ); + AddLabel( 43, y, 0x384, "Off" ); + } + + // add the Refresh/Sort button + AddButton( 80, y, 0xFAB, 0xFAD, 700, GumpButtonType.Reply, 0 ); + AddLabel( 113, y, 0x384, "Refresh" ); + + // add the Add button + AddButton( 185, y, 0xFAB, 0xFAD, 155, GumpButtonType.Reply, 0 ); + AddLabel( 218, y, 0x384, "Add" ); + + // add the Delete button + AddButton( 255, y, 0xFB1, 0xFB3, 156, GumpButtonType.Reply, 0 ); + AddLabel( 283, y, 0x384, "Delete" ); + + // add the page buttons + for(int i = 0;i<(int)(MaxEntries/MaxEntriesPerPage);i++) + { + AddButton( 513+i*25, y, 0x8B1+i, 0x8B1+i, 0, GumpButtonType.Page, 1+i ); + } + + // add the advance pageblock buttons + AddButton( 510+25*(int)(MaxEntries/MaxEntriesPerPage), y, 0x15E1, 0x15E5, 201, GumpButtonType.Reply, 0 ); // block forward + AddButton( 490, y, 0x15E3, 0x15E7, 202, GumpButtonType.Reply, 0 ); // block backward + + // add the displayfrom entry + AddLabel( 555, y, 0x384, "Display" ); + AddImageTiled( 595, y, 60, 21, 0xBBC ); + AddTextEntry( 595, y, 60, 21, 0, 400, DisplayFrom.ToString() ); + AddButton( 655, y, 0xFAB, 0xFAD, 9998, GumpButtonType.Reply, 0 ); + + //AddLabel( 610, y, 0x384, "Select All" ); + // display the select-all toggle + //AddButton( 670, y, (SelectAll? 0xD3:0xD2), (SelectAll? 0xD2:0xD3), 3998, GumpButtonType.Reply, 0 ); + + } + + + + private void SortFindList() + { + if(m_SearchList != null && m_SearchList.Count > 0) + { + + this.m_SearchList.Sort( new ListSorter(false) ); + + } + } + + private class ListSorter : IComparer + { + private bool Dsort; + public ListSorter(bool descend) : base () + { + Dsort = descend; + } + public int Compare( object x, object y ) + { + int xn = 0; + int yn = 0; + + + xn = ((XmlDialog.SpeechEntry)x).EntryNumber; + + yn = ((XmlDialog.SpeechEntry)y).EntryNumber; + + + if(Dsort) + return yn - xn; + else + return xn- yn; + } + } + + + + private void SaveList(Mobile from, string filename) + { + if(m_SearchList == null || m_SelectionList == null) return; + + string dirname; + if( System.IO.Directory.Exists( XmlDialog.DefsDir ) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = String.Format("{0}/{1}",XmlDialog.DefsDir,filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + // save it to the file + } + + private XmlEditDialogGump Refresh(NetState state) + { + XmlEditDialogGump g = new XmlEditDialogGump(this.m_From, false, this.m_Dialog, this.Selected, + this.DisplayFrom, this.SaveFilename, this.SelectAll, this.m_SelectionList, this.X, this.Y); + state.Mobile.SendGump(g); + return g; + } + + public static void ProcessXmlEditBookEntry(Mobile from, object[] args, string text) + { + + if(from == null || args == null || args.Length < 6) return; + + XmlDialog dialog = (XmlDialog)args[0]; + XmlDialog.SpeechEntry entry = (XmlDialog.SpeechEntry)args[1]; + int textid = (int)args[2]; + int selected = (int)args[3]; + int displayfrom = (int)args[4]; + string savefile = (string)args[5]; + + // place the book text into the entry by type + switch(textid) + { + case 0: // text + if(entry != null) + entry.Text = text; + break; + case 1: // keywords + if(entry != null) + entry.Keywords = text; + break; + case 2: // condition + if(entry != null) + entry.Condition = text; + break; + case 3: // action + if(entry != null) + entry.Action = text; + break; + case 4: // gump + if(entry != null) + entry.Gump = text; + break; + case 5: // trigoncarried + if(dialog != null) + dialog.TriggerOnCarried = text; + break; + case 6: // notrigoncarried + if(dialog != null) + dialog.NoTriggerOnCarried = text; + break; + } + + + from.CloseGump(typeof(XmlEditDialogGump)); + + //from.SendGump( new XmlEditDialogGump(from, false, m_Dialog, selected, displayfrom, savefilename, false, null, X, Y) ); + from.SendGump( new XmlEditDialogGump(from, true, dialog, selected, displayfrom, savefile, false, null, 0, 0)); + } + + + public override void OnResponse( NetState state, RelayInfo info ) + { + if(info == null || state == null || state.Mobile == null || m_Dialog == null) return; + + int radiostate = -1; + if(info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + + + + TextRelay tr = info.GetTextEntry( 400 ); // displayfrom info + try + { + DisplayFrom = int.Parse(tr.Text); + } + catch{} + + + tr = info.GetTextEntry( 300 ); // savefilename info + if(tr != null) + SaveFilename = tr.Text; + + if(m_Dialog != null) + { + tr = info.GetTextEntry( 140 ); // proximity range + if(tr != null) + { + try + { + m_Dialog.ProximityRange = int.Parse(tr.Text); + } + catch{} + } + tr = info.GetTextEntry( 141 ); // reset time + if(tr != null) + { + try + { + m_Dialog.ResetTime = TimeSpan.Parse(tr.Text); + } + catch{} + } + tr = info.GetTextEntry( 142 ); // speech pace + if(tr != null) + { + try + { + m_Dialog.SpeechPace = int.Parse(tr.Text); + } + catch{} + } + + tr = info.GetTextEntry( 150 ); // trig on carried + if(tr != null && (m_Dialog.TriggerOnCarried == null || m_Dialog.TriggerOnCarried.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + m_Dialog.TriggerOnCarried = tr.Text; + } + else + { + m_Dialog.TriggerOnCarried = null; + } + } + + tr = info.GetTextEntry( 151 ); // notrig on carried + if(tr != null && (m_Dialog.NoTriggerOnCarried == null || m_Dialog.NoTriggerOnCarried.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + m_Dialog.NoTriggerOnCarried = tr.Text; + } + else + { + m_Dialog.NoTriggerOnCarried = null; + } + } + + m_Dialog.AllowGhostTrig = info.IsSwitched(260); // allow ghost triggering + } + + if(m_SearchList != null && Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) + { + // entry information + XmlDialog.SpeechEntry entry = (XmlDialog.SpeechEntry)m_SearchList[Selected + DisplayFrom]; + + tr = info.GetTextEntry( 200 ); // entry number + if(tr != null) + { + try + { + entry.EntryNumber = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry( 201 ); // entry id + if(tr != null) + { + try + { + entry.ID = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry( 202 ); // depends on + if(tr != null) + { + try + { + entry.DependsOn = tr.Text; + } + catch {} + } + + tr = info.GetTextEntry( 203 ); // prepause + if(tr != null) + { + try + { + entry.PrePause = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry( 204 ); // pause + if(tr != null) + { + try + { + entry.Pause = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry( 205 ); // hue + if(tr != null) + { + try + { + entry.SpeechHue = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry( 101 ); // keywords + if(tr != null && (entry.Keywords == null || entry.Keywords.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Keywords = tr.Text; + } + else + { + entry.Keywords = null; + } + + } + + tr = info.GetTextEntry( 100 ); // text + if(tr != null && (entry.Text == null || entry.Text.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Text = tr.Text; + } + else + { + entry.Text = null; + } + } + + tr = info.GetTextEntry( 102 ); // condition + if(tr != null && (entry.Condition == null || entry.Condition.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Condition = tr.Text; + } + else + { + entry.Condition = null; + } + } + + tr = info.GetTextEntry( 103 ); // action + if(tr != null && (entry.Action == null || entry.Action.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Action = tr.Text; + } + else + { + entry.Action = null; + } + } + + tr = info.GetTextEntry( 104 ); // gump + if(tr != null && (entry.Gump == null || entry.Gump.Length < 230)) + { + if(tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Gump = tr.Text; + } + else + { + entry.Gump = null; + } + } + + entry.LockConversation = info.IsSwitched(250); // lock conversation + entry.AllowNPCTrigger = info.IsSwitched(251); // allow npc + entry.IgnoreCarried = info.IsSwitched(252); // ignorecarried + } + + + + switch ( info.ButtonID ) + { + + case 0: // Close + { + + m_Dialog.DeleteTextEntryBook(); + + return; + } + case 100: // toggle running status + { + + m_Dialog.Running = !m_Dialog.Running; + + break; + } + case 155: // add new entry + { + + if(m_SearchList != null) + { + // find the last entry + int lastentry = 0; + foreach(XmlDialog.SpeechEntry e in m_SearchList) + { + if(e.EntryNumber > lastentry) + lastentry = e.EntryNumber; + } + lastentry += 10; + XmlDialog.SpeechEntry se = new XmlDialog.SpeechEntry(); + se.EntryNumber = lastentry; + se.ID = lastentry; + m_SearchList.Add(se); + Selected = m_SearchList.Count -1; + } + break; + } + + case 156: // Delete selected entries + { + XmlEditDialogGump g = Refresh(state); + int allcount = 0; + if(m_SearchList != null) + allcount = m_SearchList.Count; + state.Mobile.SendGump( new XmlConfirmDeleteGump(state.Mobile, g, m_SearchList, m_SelectionList, DisplayFrom, SelectAll, allcount) ); + return; + } + + case 159: // save to a .npc file + { + + // Create a new gump + Refresh(state); + // try to save + m_Dialog.DoSaveNPC(state.Mobile, SaveFilename, true); + + return; + } + + case 201: // forward block + { + // clear the selections + if(m_SelectionList != null && !SelectAll) Array.Clear(m_SelectionList,0,m_SelectionList.Length); + if(m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) + { + DisplayFrom += MaxEntries; + // clear any selection + Selected = -1; + } + break; + } + case 202: // backward block + { + // clear the selections + if(m_SelectionList != null && !SelectAll) Array.Clear(m_SelectionList,0,m_SelectionList.Length); + DisplayFrom -= MaxEntries; + if(DisplayFrom < 0) DisplayFrom = 0; + // clear any selection + Selected = -1; + break; + } + + case 700: // Sort + { + // clear any selection + Selected = -1; + // clear the selections + if(m_SelectionList != null && !SelectAll) Array.Clear(m_SelectionList,0,m_SelectionList.Length); + + SortFindList(); + break; + } + + case 9998: // refresh the gump + { + // clear any selection + Selected = -1; + break; + } + default: + { + + if(info.ButtonID >= 1000 && info.ButtonID < 1000+ MaxEntries) + { + // flag the entry selected + Selected = info.ButtonID - 1000; + } + else + if(info.ButtonID == 3998) + { + + SelectAll = !SelectAll; + + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null) + { + for(int i = 0; i < MaxEntries;i++) + { + if(i < m_SelectionList.Length) + { + // only toggle the selection list entries for things that actually have entries + m_SelectionList[i] = SelectAll; + } + else + { + break; + } + } + } + } + else + if(info.ButtonID == 3999) + { + + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null && m_SearchList != null && !SelectAll) + { + for(int i = 0; i < MaxEntries;i++) + { + if(i < m_SelectionList.Length) + { + // only toggle the selection list entries for things that actually have entries + if((m_SearchList.Count - DisplayFrom > i)) + { + m_SelectionList[i] = !m_SelectionList[i]; + } + } + else + { + break; + } + } + } + } + else + if(info.ButtonID >= 4000 && info.ButtonID < 4000+ MaxEntries) + { + int i = info.ButtonID - 4000; + // dont allow individual selection with the selectall button selected + if(m_SelectionList != null && i >= 0 && i < m_SelectionList.Length && !SelectAll) + { + // only toggle the selection list entries for things that actually have entries + if(m_SearchList != null && (m_SearchList.Count - DisplayFrom > i)) + { + m_SelectionList[i] = !m_SelectionList[i]; + } + } + } + else + if(info.ButtonID >= 5000 && info.ButtonID < 5100) + { + + + // text entry book buttons + int textid = info.ButtonID - 5000; + + // entry information + XmlDialog.SpeechEntry entry = null; + + if(m_SearchList != null && Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) + { + entry = (XmlDialog.SpeechEntry)m_SearchList[Selected + DisplayFrom]; + } + + string text = String.Empty; + string title = String.Empty; + switch(textid) + { + case 0: // text + if(entry != null) + text = entry.Text; + title = "Text"; + break; + case 1: // keywords + if(entry != null) + text = entry.Keywords; + title = "Keywords"; + break; + case 2: // condition + if(entry != null) + text = entry.Condition; + title = "Condition"; + break; + case 3: // action + if(entry != null) + text = entry.Action; + title = "Action"; + break; + case 4: // gump + if(entry != null) + text = entry.Gump; + title = "Gump"; + break; + case 5: // trigoncarried + text = m_Dialog.TriggerOnCarried; + title = "TrigOnCarried"; + break; + case 6: // notrigoncarried + text = m_Dialog.NoTriggerOnCarried; + title = "NoTrigOnCarried"; + break; + } + + object [] args = new object[6]; + + args[0] = m_Dialog; + args[1] = entry; + args[2] = textid; + args[3] = Selected; + args[4] = DisplayFrom; + args[5] = SaveFilename; + + XmlTextEntryBook book = new XmlTextEntryBook(0, String.Empty, m_Dialog.Name, 20, true, new XmlTextEntryBookCallback(ProcessXmlEditBookEntry), args); + + if(m_Dialog.m_TextEntryBook == null) + { + m_Dialog.m_TextEntryBook = new ArrayList(); + } + m_Dialog.m_TextEntryBook.Add(book); + + book.Title = title; + book.Author = Name; + + // fill the contents of the book with the current text entry data + book.FillTextEntryBook(text); + + // put the book at the location of the player so that it can be opened, but drop it below visible range + book.Visible = false; + book.Movable = false; + book.MoveToWorld(new Point3D(state.Mobile.Location.X,state.Mobile.Location.Y,state.Mobile.Location.Z-100), state.Mobile.Map); + + // Create a new gump + Refresh(state); + + // and open it + book.OnDoubleClick(state.Mobile); + + return; + + } + break; + } + } + // Create a new gump + Refresh(state); + } + + + public class XmlConfirmDeleteGump : Gump + { + private ArrayList SearchList; + private bool [] SelectedList; + private Mobile From; + private int DisplayFrom; + private bool selectAll; + XmlEditDialogGump m_Gump; + + public XmlConfirmDeleteGump(Mobile from, XmlEditDialogGump gump, ArrayList searchlist, bool [] selectedlist, int displayfrom, bool selectall, int allcount) : base ( 0, 0 ) + { + SearchList = searchlist; + SelectedList = selectedlist; + DisplayFrom = displayfrom; + selectAll = selectall; + m_Gump = gump; + From = from; + Closable = false; + Dragable = true; + AddPage( 0 ); + AddBackground( 10, 200, 200, 130, 5054 ); + int count = 0; + if(selectall) + { + count = allcount; + } + else + { + for(int i =0;i 0) + { + radiostate = info.Switches[0]; + } + switch(info.ButtonID) + { + + default: + { + if(radiostate == 1 && SearchList != null && SelectedList != null) + { // accept + ArrayList dlist = new ArrayList(); + for(int i = 0;i < SearchList.Count;i++) + { + int index = i-DisplayFrom; + if((index >= 0 && index < SelectedList.Length && SelectedList[index] == true) || selectAll) + { + object o = SearchList[i]; + // delete the entry; + dlist.Add(o); + } + } + + foreach(object o in dlist) + { + SearchList.Remove(o); + } + + // clear the selections + Array.Clear(SelectedList,0,SelectedList.Length); + + if(m_Gump != null) + { + state.Mobile.CloseGump(typeof(XmlEditDialogGump)); + m_Gump.Refresh(state); + } + } + break; + } + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlUtils/XmlFind.cs b/Scripts/Customs/XML Spawner/XmlUtils/XmlFind.cs new file mode 100644 index 0000000..538cb88 --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/XmlFind.cs @@ -0,0 +1,2622 @@ +using System; +using System.Data; +using System.IO; +using System.Collections; +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using System.Reflection; +using Server.Commands; +using Server.Commands.Generic; +using CPA = Server.CommandPropertyAttribute; +using System.Xml; +using Server.Spells; +using Server.Regions; +using System.Text; +using Server.Accounting; +using System.Threading; +using Server.Engines.XmlSpawner2; + +/* +** XmlFind +** utility for locating objects in the world. +** ArteGordon +** original version 1.0 +** 4/13/04 +** +*/ + +namespace Server.Mobiles +{ + public class XmlFindGump : Gump + { + + public class XmlFindThread + { + SearchCriteria m_SearchCriteria; + Mobile m_From; + string m_commandstring; + + public XmlFindThread(Mobile from, SearchCriteria criteria, string commandstring) + { + m_SearchCriteria = criteria; + m_From = from; + m_commandstring = commandstring; + } + + + public void XmlFindThreadMain() + { + + if (m_From == null) return; + + string status_str; + + ArrayList results = XmlFindGump.Search(m_SearchCriteria, out status_str); + + XmlFindGump gump = new XmlFindGump(m_From, m_From.Location, m_From.Map, true, true, false, + + m_SearchCriteria, + + results, -1, 0, null, m_commandstring, + false, false, false, false, false, false, 0, 0); + + // display the updated gump synched with the main server thread + Timer.DelayCall(TimeSpan.Zero, new TimerStateCallback(GumpDisplayCallback), new object[] { m_From, gump, status_str }); + + } + + public void GumpDisplayCallback(object state) + { + object[] args = (object[])state; + + Mobile from = (Mobile)args[0]; + XmlFindGump gump = (XmlFindGump)args[1]; + string status_str = (string)args[2]; + + if (from != null && !from.Deleted) + { + from.SendGump(gump); + if (status_str != null) + { + from.SendMessage(33, "XmlFind: {0}", status_str); + } + } + } + + + } + + private const int MaxEntries = 18; + private const int MaxEntriesPerPage = 18; + + public class SearchEntry + { + public bool Selected; + public object Object; + + public SearchEntry(object o) + { + Object = o; + } + } + + public class SearchCriteria + { + public bool Dosearchtype; + public bool Dosearchname; + public bool Dosearchrange; + public bool Dosearchregion; + public bool Dosearchspawnentry; + public bool Dosearchspawntype; + public bool Dosearchcondition; + public bool Dosearchfel; + public bool Dosearchtram; + public bool Dosearchmal; + public bool Dosearchilsh; + public bool Dosearchtok; + public bool Dosearchint; + public bool Dosearchnull; + public bool Dosearcherr; + public bool Dosearchage; + public bool Dosearchwithattach; + public bool Dosearchattach; + public bool Dohidevalidint = false; + public bool Searchagedirection; + public double Searchage; + public int Searchrange; + public string Searchregion; + public string Searchcondition; + public string Searchtype; + public string Searchattachtype; + public string Searchname; + public string Searchspawnentry; + + public Map Currentmap; + public Point3D Currentloc; + + public SearchCriteria(bool dotype, bool doname, bool dorange, bool doregion, bool doentry, bool doentrytype, bool docondition, bool dofel, bool dotram, + bool domal, bool doilsh, bool dotok, bool doint, bool donull, bool doerr, bool doage, bool dowithattach, bool doattach, bool dohidevalid, + bool agedirection, double age, int range, string region, string condition, string type, string attachtype, string name, string entry + ) + { + Dosearchtype = dotype; + Dosearchname = doname; + Dosearchrange = dorange; + Dosearchregion = doregion; + Dosearchspawnentry = doentry; + Dosearchspawntype = doentrytype; + Dosearchcondition = docondition; + Dosearchfel = dofel; + Dosearchtram = dotram; + Dosearchmal = domal; + Dosearchilsh = doilsh; + Dosearchtok = dotok; + Dosearchint = doint; + Dosearchnull = donull; + Dosearcherr = doerr; + Dosearchage = doage; + Dosearchwithattach = dowithattach; + Dosearchattach = doattach; + Dohidevalidint = dohidevalid; + Searchagedirection = agedirection; + Searchage = age; + Searchrange = range; + Searchregion = region; + Searchcondition = condition; + Searchtype = type; + Searchattachtype = attachtype; + Searchname = name; + Searchspawnentry = entry; + + } + + public SearchCriteria() + { + } + } + + private SearchCriteria m_SearchCriteria; + private bool Sorttype; + private bool Sortrange; + private bool Sortname; + private bool Sortmap; + private bool Sortselect; + private Mobile m_From; + private Point3D StartingLoc; + private Map StartingMap; + private bool m_ShowExtension; + private bool Descendingsort; + private int Selected; + private int DisplayFrom; + private string SaveFilename; + private string CommandString; + + private bool SelectAll = false; + + private ArrayList m_SearchList; + + public static void Initialize() + { + CommandSystem.Register("XmlFind", AccessLevel.GameMaster, new CommandEventHandler(XmlFind_OnCommand)); + } + + private static bool TestRange(object o, int range, Map currentmap, Point3D currentloc) + { + if (range < 0) return true; + if (o is Item) + { + Item item = (Item)o; + + if (item.Map != currentmap) return false; + + // is the item in a container? + // if so, then check the range of the parent rather than the item + Point3D loc = item.Location; + if (item.Parent != null && item.RootParent != null) + { + if (item.RootParent is Mobile) + { + loc = ((Mobile)item.RootParent).Location; + } + else + if (item.RootParent is Container) + { + loc = ((Container)item.RootParent).Location; + } + + } + return (Utility.InRange(currentloc, loc, range)); + + } + else + if (o is Mobile) + { + Mobile mob = (Mobile)o; + + if (mob.Map != currentmap) return false; + return (Utility.InRange(currentloc, mob.Location, range)); + + } + return false; + } + + private static bool TestRegion(object o, string regionname) + { + if (regionname == null) return false; + if (o is Item) + { + Item item = (Item)o; + // is the item in a container? + // if so, then check the region of the parent rather than the item + Point3D loc = item.Location; + if (item.Parent != null && item.RootParent != null) + { + if (item.RootParent is Mobile) + { + loc = ((Mobile)item.RootParent).Location; + } + else + if (item.RootParent is Container) + { + loc = ((Container)item.RootParent).Location; + } + + } + //Region r = Region.GetByName(regionname, item.Map); + + Region r = null; + + try + { + r = item.Map.Regions[regionname]; + } + catch { } + + if (r == null) return false; + return (r.Contains(loc)); + + } + else + if (o is Mobile) + { + Mobile mob = (Mobile)o; + + Region r = null; + try + { + r = mob.Map.Regions[regionname]; + } + catch { } + + //Region r = Region.GetByName(regionname, mob.Map); + if (r == null) return false; + return (r.Contains(mob.Location)); + + } + return false; + } + + private static bool TestAttach(object o) + { + if (XmlAttach.FindAttachments(o) != null) return true; + + return false; + } + + private static bool TestAge(object o, double age, bool direction) + { + if (age <= 0) return true; + + if (o is Mobile) + { + Mobile mob = (Mobile)o; + + if (direction) + { + // true means allow only mobs greater than the age + if ((DateTime.Now - mob.CreationTime) > TimeSpan.FromHours(age)) return true; + } + else + { + // false means allow only mobs less than the age + if ((DateTime.Now - mob.CreationTime) < TimeSpan.FromHours(age)) return true; + } + + } + return false; + } + + private static void IgnoreManagedInternal(object i, ref ArrayList ignoreList) + { + + // ignore valid internalized commodity deed items + if (i is CommodityDeed) + { + CommodityDeed deed = (CommodityDeed)i; + + if (deed.Commodity != null && deed.Commodity.Map == Map.Internal) + ignoreList.Add(deed.Commodity); + } + + // ignore valid internalized keyring keys + if (i is KeyRing) + { + KeyRing keyring = (KeyRing)i; + + if (keyring.Keys != null) + { + foreach (Key k in keyring.Keys) + { + ignoreList.Add(k); + } + } + } + + // ignore valid internalized relocatable house items + if (i is BaseHouse) + { + BaseHouse house = (BaseHouse)i; + + foreach (RelocatedEntity relEntity in house.RelocatedEntities) + { + if (relEntity.Entity is Item) + ignoreList.Add(relEntity.Entity); + } + + foreach (VendorInventory inventory in house.VendorInventories) + { + foreach (Item subItem in inventory.Items) + ignoreList.Add(subItem); + } + } + } + + // test for valid items/mobs on the internal map + private static bool TestValidInternal(object o) + { + if (o is Mobile) + { + Mobile m = (Mobile)o; + + if (m.Map != Map.Internal || m.Account != null || + (m is IMount && ((IMount)m).Rider != null) || + (m is BaseCreature && ((BaseCreature)m).IsStabled)) + return true; + + } + else + if (o is Item) + { + Item i = (Item)o; + + // note, in order to test for a vendors display container that contains valid internal map items + // we need to see if we have a DisplayCache type container. Unfortunately, DisplayCache + // is a private class declared in GenericBuyInfo and so cannot be tested for here. + // To get around that we just check the declaring type. + if (i.Map != Map.Internal || i.Parent != null || i is Fists || i is MountItem || i is EffectItem || i.HeldBy != null || + i is MovingCrate || i is SpawnPersistence || (i.GetType().DeclaringType == typeof(GenericBuyInfo))) + return true; + } + + return false; + } + + public static ArrayList Search(SearchCriteria criteria, out string status_str) + { + status_str = null; + ArrayList newarray = new ArrayList(); + ArrayList ignoreList = new ArrayList(); + + if (criteria == null) + { + status_str = "Empty search criteria"; + return newarray; + } + + Type targetType = null; + Type targetattachType = null; + + Map tokunomap = null; + try + { + tokunomap = Map.Parse("Tokuno"); + } + catch { } + + // if the type is specified then get the search type + if (criteria.Dosearchtype && criteria.Searchtype != null) + { + targetType = SpawnerType.GetType(criteria.Searchtype); + if (targetType == null) + { + status_str = "Invalid type: " + criteria.Searchtype; + return newarray; + } + } + + // if the attachment type is specified then get the search type + if (criteria.Dosearchattach && criteria.Searchattachtype != null && criteria.Searchattachtype.Length > 0) + { + targetattachType = SpawnerType.GetType(criteria.Searchattachtype); + if (targetattachType == null) + { + status_str = "Invalid type: " + criteria.Searchattachtype; + return newarray; + } + } + + // do the search through items + + if (!criteria.Dosearchattach) + { + // make a copy so that we dont get enumeration errors if World.Items.Values changes while searching + ArrayList itemarray = null; + + ICollection itemvalues = World.Items.Values; + + lock (itemvalues.SyncRoot) + { + try + { + itemarray = new ArrayList(itemvalues); + } + catch (SystemException e) { status_str = "Unable to search World.Items: " + e.Message; } + } + + if (itemarray != null) + { + foreach (Item i in itemarray) + { + bool hastype = false; + bool hasname = false; + bool hasentry = false; + bool hascondition = false; + bool hasrange = false; + bool hasregion = false; + bool hasmap = false; + bool hasattach = false; + bool hasspawnerr = false; + bool hasvalidhidden = false; + + + if (i == null || i.Deleted) continue; + + // this will deal with items that are not on the internal map but hold valid internal items + if (criteria.Dohidevalidint && i.Map != Map.Internal && i.Map != null) + { + IgnoreManagedInternal(i, ref ignoreList); + } + + // check for map + if ((i.Map == Map.Felucca && criteria.Dosearchfel) || (i.Map == Map.Trammel && criteria.Dosearchtram) || + (i.Map == Map.Malas && criteria.Dosearchmal) || (i.Map == Map.Ilshenar && criteria.Dosearchilsh) || (i.Map == Map.Internal && criteria.Dosearchint) || + (i.Map == null && criteria.Dosearchnull)) + { + hasmap = true; + } + + if (tokunomap != null && i.Map == tokunomap && criteria.Dosearchtok) + { + hasmap = true; + } + + + if (!hasmap) continue; + + // check for type + if (criteria.Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType().Equals(targetType))) + { + hastype = true; + } + if (criteria.Dosearchtype && !hastype) continue; + + // check for name + if (criteria.Dosearchname && (i.Name != null) && (criteria.Searchname != null) && (i.Name.ToLower().IndexOf(criteria.Searchname.ToLower()) >= 0)) + { + hasname = true; + } + if (criteria.Dosearchname && !hasname) continue; + + // check for valid internal map items + if (criteria.Dohidevalidint && TestValidInternal(i)) + { + hasvalidhidden = true; + + // this will deal with items that are on the internal map and hold valid internal items + IgnoreManagedInternal(i, ref ignoreList); + } + if (criteria.Dohidevalidint && hasvalidhidden) continue; + + // check for range + if (criteria.Dosearchrange && TestRange(i, criteria.Searchrange, criteria.Currentmap, criteria.Currentloc)) + { + hasrange = true; + } + if (criteria.Dosearchrange && !hasrange) continue; + + // check for region + if (criteria.Dosearchregion && TestRegion(i, criteria.Searchregion)) + { + hasregion = true; + } + if (criteria.Dosearchregion && !hasregion) continue; + + // check for attachments + if (criteria.Dosearchwithattach && TestAttach(i)) + { + hasattach = true; + } + if (criteria.Dosearchwithattach && !hasattach) continue; + + // check for condition + if (criteria.Dosearchcondition && (criteria.Searchcondition != null)) + { + // check the property test + hascondition = BaseXmlSpawner.CheckPropertyString(null, i, criteria.Searchcondition, null, out status_str); + } + if (criteria.Dosearchcondition && !hascondition) continue; + + // check for entry + if (criteria.Dosearchspawnentry) + { + Type targetentrytype = null; + + if (criteria.Dosearchspawntype) + { + targetentrytype = SpawnerType.GetType(criteria.Searchspawnentry.ToLower()); + } + + if (criteria.Searchspawnentry == null || (targetentrytype == null && criteria.Dosearchspawntype)) + { + hasentry = false; + } + else + { + // see what kind of spawner it is + if (i is XmlSpawner) + { + + // search the entries of the spawner + foreach (XmlSpawner.SpawnObject so in ((XmlSpawner)i).m_SpawnObjects) + { + if (criteria.Dosearchspawntype) + { + // search by entry type + Type type = null; + + if (so.TypeName != null) + { + string[] args = so.TypeName.Split('/'); + string typestr = null; + if (args != null && args.Length > 0) + { + typestr = args[0]; + } + + type = SpawnerType.GetType(typestr); + } + + if (type != null && (type == targetentrytype || type.IsSubclassOf(targetentrytype))) + { + hasentry = true; + break; + } + } + else + { + // search by entry string + if (so.TypeName != null && so.TypeName.ToLower().IndexOf(criteria.Searchspawnentry.ToLower()) >= 0) + { + hasentry = true; + break; + } + } + } + } + else if (i is Spawner) + { + // search the entries of the spawner + foreach (string so in ((Spawner)i).SpawnNames) + { + if (criteria.Dosearchspawntype) + { + // search by entry type + Type type = null; + + if (so != null) + { + type = SpawnerType.GetType(so); + } + + if (type != null && (type == targetentrytype || type.IsSubclassOf(targetentrytype))) + { + hasentry = true; + break; + } + } + else + { + if (so != null && so.ToLower().IndexOf(criteria.Searchspawnentry.ToLower()) >= 0) + { + hasentry = true; + break; + } + } + } + } + else + { + hasentry = false; + } + } + } + if (criteria.Dosearchspawnentry && !hasentry) continue; + + // check for err + if (criteria.Dosearcherr) + { + // see what kind of spawner it is + if (i is XmlSpawner) + { + // check the status of the spawner + if (((XmlSpawner)i).status_str != null) + { + hasspawnerr = true; + } + } + } + if (criteria.Dosearcherr && !hasspawnerr) continue; + + + // satisfied all conditions so add it + newarray.Add(new SearchEntry(i)); + } + } + } + + // do the search through mobiles + if (!criteria.Dosearcherr && !criteria.Dosearchattach) + { + // make a copy so that we dont get enumeration errors if World.Mobiles.Values changes while searching + ArrayList mobilearray = null; + ICollection mobilevalues = World.Mobiles.Values; + lock (mobilevalues.SyncRoot) + { + try + { + mobilearray = new ArrayList(mobilevalues); + } + catch (SystemException e) { status_str = "Unable to search World.Mobiles: " + e.Message; } + } + + if (mobilearray != null) + { + foreach (Mobile i in mobilearray) + { + bool hastype = false; + bool hasname = false; + bool hascondition = false; + bool hasrange = false; + bool hasregion = false; + bool hasmap = false; + bool hasage = false; + bool hasattach = false; + bool hasvalidhidden = false; + + if (i == null || i.Deleted) continue; + + // check for map + if ((i.Map == Map.Felucca && criteria.Dosearchfel) || (i.Map == Map.Trammel && criteria.Dosearchtram) || + (i.Map == Map.Malas && criteria.Dosearchmal) || (i.Map == Map.Ilshenar && criteria.Dosearchilsh) || (i.Map == Map.Internal && criteria.Dosearchint) || + (i.Map == null && criteria.Dosearchnull)) + { + hasmap = true; + } + + if (tokunomap != null && i.Map == tokunomap && criteria.Dosearchtok) + { + hasmap = true; + } + + if (!hasmap) continue; + + // check for range + if (criteria.Dosearchrange && TestRange(i, criteria.Searchrange, criteria.Currentmap, criteria.Currentloc)) + { + hasrange = true; + } + if (criteria.Dosearchrange && !hasrange) continue; + + // check for region + if (criteria.Dosearchregion && TestRegion(i, criteria.Searchregion)) + { + hasregion = true; + } + if (criteria.Dosearchregion && !hasregion) continue; + + // check for valid internal map mobiles + if (criteria.Dohidevalidint && TestValidInternal(i)) + { + hasvalidhidden = true; + } + if (criteria.Dohidevalidint && hasvalidhidden) continue; + + // check for age + if (criteria.Dosearchage && TestAge(i, criteria.Searchage, criteria.Searchagedirection)) + { + hasage = true; + } + if (criteria.Dosearchage && !hasage) continue; + + // check for type + if (criteria.Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType().Equals(targetType))) + { + hastype = true; + } + if (criteria.Dosearchtype && !hastype) continue; + + // check for name + if (criteria.Dosearchname && (i.Name != null) && (criteria.Searchname != null) && (i.Name.ToLower().IndexOf(criteria.Searchname.ToLower()) >= 0)) + { + hasname = true; + } + if (criteria.Dosearchname && !hasname) continue; + + // check for attachments + if (criteria.Dosearchwithattach && TestAttach(i)) + { + hasattach = true; + } + if (criteria.Dosearchwithattach && !hasattach) continue; + + // check for condition + if (criteria.Dosearchcondition && (criteria.Searchcondition != null)) + { + // check the property test + hascondition = BaseXmlSpawner.CheckPropertyString(null, i, criteria.Searchcondition, null, out status_str); + } + if (criteria.Dosearchcondition && !hascondition) continue; + + // passed all conditions so add it to the list + + newarray.Add(new SearchEntry(i)); + } + } + + } + + // need to keep track of valid internalized XmlSaveItem items + if (criteria.Dohidevalidint) + { + foreach (XmlAttachment i in XmlAttach.Values) + { + if (i is XmlSaveItem) + { + XmlSaveItem s = (XmlSaveItem)i; + if (s.Container != null) + { + ignoreList.Add(s.Container); + } + } + } + } + + if (criteria.Dosearchattach) + { + + foreach (XmlAttachment i in XmlAttach.Values) + { + // check for type + if (i != null && !i.Deleted && (targetattachType == null || i.GetType().IsSubclassOf(targetattachType) || i.GetType().Equals(targetattachType))) + { + newarray.Add(new SearchEntry(i)); + } + } + } + + ArrayList removelist = new ArrayList(); + for (int i = 0; i < ignoreList.Count; ++i) + { + foreach (SearchEntry se in newarray) + { + if (se.Object == ignoreList[i]) + { + removelist.Add(se); + break; + } + } + } + + foreach (SearchEntry se in removelist) + { + newarray.Remove(se); + } + + return newarray; + } + + [Usage("XmlFind [objecttype] [range]")] + [Description("Finds objects in the world")] + public static void XmlFind_OnCommand(CommandEventArgs e) + { + if (e == null || e.Mobile == null) return; + + Account acct = e.Mobile.Account as Account; + int x = 0; + int y = 0; + XmlSpawnerDefaults.DefaultEntry defs = null; + if (acct != null) + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), e.Mobile.Name); + + if (defs != null) + { + x = defs.FindGumpX; + y = defs.FindGumpY; + } + + string typename = "Xmlspawner"; + int range = -1; + bool dorange = false; + + if (e.Arguments.Length > 0) + { + typename = e.Arguments[0]; + } + + if (e.Arguments.Length > 1) + { + dorange = true; + try + { + range = int.Parse(e.Arguments[1]); + } + catch + { + dorange = false; + e.Mobile.SendMessage("Invalid range argument {0}", e.Arguments[1]); + } + } + + e.Mobile.SendGump(new XmlFindGump(e.Mobile, e.Mobile.Location, e.Mobile.Map, typename, range, dorange, x, y)); + } + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, int x, int y) + : this(from, startloc, startmap, null, x, y) + { + } + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, string type, int x, int y) + : this(from, startloc, startmap, type, -1, false, x, y) + { + } + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, string type, int range, bool dorange, int x, int y) + : this(from, startloc, startmap, true, false, false, + + new SearchCriteria( + true, // dotype + false, // doname + dorange, // dorange + false, // doregion + false, // doentry + false, // doentrytype + false, // docondition + true, // dofel + true, // dotram + true, // domal + true, // doilsh + true, // dotok + false, // doint + false, // donull + false, // doerr + false, // doage + false, // dowithattach + false, // doattach + false, // dohidevalid + true, // agedirection + 0, // age + range, // range + null, // region + null, // condition + type, // type + null, // attachtype + null, // name + null // entry + ), + + null, -1, 0, null, null, + false, false, false, false, false, false, x, y) + { + } + + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, bool firststart, bool extension, bool descend, SearchCriteria criteria, ArrayList searchlist, int selected, int displayfrom, string savefilename, + string commandstring, bool sorttype, bool sortname, bool sortrange, bool sortmap, bool sortselect, bool selectall, int X, int Y) + : base(X, Y) + { + + StartingMap = startmap; + StartingLoc = startloc; + if (from != null && !from.Deleted) + { + m_From = from; + if (firststart) + { + StartingMap = from.Map; + StartingLoc = from.Location; + } + } + + SaveFilename = savefilename; + CommandString = commandstring; + SelectAll = selectall; + Sorttype = sorttype; + Sortname = sortname; + Sortrange = sortrange; + Sortmap = sortmap; + Sortselect = sortselect; + DisplayFrom = displayfrom; + Selected = selected; + m_ShowExtension = extension; + Descendingsort = descend; + + m_SearchCriteria = criteria; + + if (m_SearchCriteria == null) m_SearchCriteria = new SearchCriteria(); + + m_SearchList = searchlist; + + // prepare the page + int height = 500; + int y = 0; + + AddPage(0); + if (m_ShowExtension) + { + AddBackground(0, 0, 755, height, 5054); + AddAlphaRegion(0, 0, 755, height); + } + else + { + AddBackground(0, 0, 170, height, 5054); + AddAlphaRegion(0, 0, 170, height); + } + + + // Close button + //AddButton( 5, 450, 0xFB1, 0xFB3, 0, GumpButtonType.Reply, 0 ); + //AddLabel( 38, 450, 0x384, "Close" ); + + // add the SubSearch button + //AddButton( 90, 160, 0xFA8, 0xFAA, 4, GumpButtonType.Reply, 0 ); + //AddLabel( 128, 160, 0x384, "SubSearch" ); + + // ---------------- + // SORT section + // ---------------- + y = 5; + // add the Sort button + AddButton(5, y, 0xFAB, 0xFAD, 700, GumpButtonType.Reply, 0); + AddLabel(38, y, 0x384, "Sort"); + + // add the sort direction button + if (Descendingsort) + { + AddButton(75, y + 3, 0x15E2, 0x15E6, 701, GumpButtonType.Reply, 0); + AddLabel(95, y, 0x384, "descend"); + } + else + { + AddButton(75, y + 3, 0x15E0, 0x15E4, 701, GumpButtonType.Reply, 0); + AddLabel(95, y, 0x384, "ascend"); + } + y += 22; + // add the Sort on type toggle + AddRadio(5, y, 0xD2, 0xD3, Sorttype, 0); + AddLabel(28, y, 0x384, "type"); + + // add the Sort on name toggle + AddRadio(75, y, 0xD2, 0xD3, Sortname, 1); + AddLabel(98, y, 0x384, "name"); + + y += 20; + // add the Sort on range toggle + AddRadio(5, y, 0xD2, 0xD3, Sortrange, 2); + AddLabel(28, y, 0x384, "range"); + + // add the Sort on map toggle + AddRadio(75, y, 0xD2, 0xD3, Sortmap, 4); + AddLabel(98, y, 0x384, "map"); + + y += 20; + // add the Sort on selected toggle + AddRadio(5, y, 0xD2, 0xD3, Sortselect, 5); + AddLabel(28, y, 0x384, "select"); + + // ---------------- + // SEARCH section + // ---------------- + y = 85; + // add the Search button + AddButton(5, y, 0xFA8, 0xFAA, 3, GumpButtonType.Reply, 0); + AddLabel(38, y, 0x384, "Search"); + + y += 20; + // add the map buttons + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchint, 312); + AddLabel(28, y, 0x384, "Int"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchnull, 314); + AddLabel(98, y, 0x384, "Null"); + + y += 20; + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchfel, 308); + AddLabel(28, y, 0x384, "Fel"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtram, 309); + AddLabel(98, y, 0x384, "Tram"); + + y += 20; + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchmal, 310); + AddLabel(28, y, 0x384, "Mal"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchilsh, 311); + AddLabel(98, y, 0x384, "Ilsh"); + + y += 20; + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtok, 318); + AddLabel(28, y, 0x384, "Tok"); + + y += 20; + // add the hide valid internal map button + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dohidevalidint, 316); + AddLabel(28, y, 0x384, "Hide valid internal"); + + // ---------------- + // FILTER section + // ---------------- + y = height - 295; + + // add the search region entry + AddLabel(28, y, 0x384, "region"); + AddImageTiled(70, y, 68, 19, 0xBBC); + AddTextEntry(70, y, 250, 19, 0, 106, m_SearchCriteria.Searchregion); + // add the toggle to enable search region + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchregion, 319); + + y += 20; + // add the search age entry + AddLabel(28, y, 0x384, "age"); + //AddImageTiled( 80, 220, 50, 23, 0x52 ); + AddImageTiled(70, y, 45, 19, 0xBBC); + AddTextEntry(70, y, 45, 19, 0, 105, m_SearchCriteria.Searchage.ToString()); + AddLabel(117, y, 0x384, "Hrs"); + // add the toggle to enable search age + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchage, 303); + // add the toggle to set the search age test direction + AddCheck(50, y + 2, 0x1467, 0x1468, m_SearchCriteria.Searchagedirection, 302); + + y += 20; + // add the search range entry + AddLabel(28, y, 0x384, "range"); + AddImageTiled(70, y, 45, 19, 0xBBC); + AddTextEntry(70, y, 45, 19, 0, 100, m_SearchCriteria.Searchrange.ToString()); + // add the toggle to enable search range + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchrange, 304); + + y += 20; + // add the search type entry + AddLabel(28, y, 0x384, "type"); + // add the toggle to enable search by type + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtype, 305); + //AddImageTiled( 5, 285, 135, 23, 0x52 ); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 101, m_SearchCriteria.Searchtype); + + // add the search for attachments button + AddLabel(100, y, 0x384, "attach"); + // add the toggle to enable search by attachment + AddCheck(77, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchwithattach, 317); + + y += 41; + // add the search condition entry + AddLabel(28, y, 0x384, "property test"); + // add the toggle to enable search by condition + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchcondition, 315); + //AddImageTiled( 5, 285, 135, 23, 0x52 ); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 500, 19, 0, 104, m_SearchCriteria.Searchcondition); + + y += 41; + // add the search name entry + AddLabel(28, y, 0x384, "name"); + // add the toggle to enable search by name + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchname, 306); + //AddImageTiled( 5, 350, 135, 23, 0x52 ); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 102, m_SearchCriteria.Searchname); + + y += 41; + // add the search attachment type entry + AddLabel(28, y, 0x384, "attachment type"); + // add the toggle to enable search by attachment type + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchattach, 325); + //AddImageTiled( 5, 285, 135, 23, 0x52 ); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 125, m_SearchCriteria.Searchattachtype); + + y += 41; + // add the search spawner entries + AddLabel(28, y, 0x384, "entry"); + // add the toggle to enable search spawner entries + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchspawnentry, 307); + + // add the search spawner entries by type + AddLabel(88, y, 0x384, "type"); + // add the toggle to enable search spawner entry types + AddCheck(65, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchspawntype, 326); + + //AddImageTiled( 5, 415, 135, 23, 0x52 ); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 103, m_SearchCriteria.Searchspawnentry); + + // add the search spawner errors + AddLabel(140, y, 0x384, "err"); + // add the toggle to enable search spawner entries + AddCheck(117, y, 0xD2, 0xD3, m_SearchCriteria.Dosearcherr, 313); + + // add the Show Map button + //AddButton( 5, 450, 0xFAB, 0xFAD, 150, GumpButtonType.Reply, 0 ); + //AddLabel( 38, 450, 0x384, "Map" ); + + // ---------------- + // CONTROL section + // ---------------- + + y = height - 25; + // add the Return button + AddButton(72, y, 0xFAE, 0xFAF, 155, GumpButtonType.Reply, 0); + AddLabel(105, y, 0x384, "Return"); + + y = height - 25; + // add the Bring button + AddButton(5, y, 0xFAE, 0xFAF, 154, GumpButtonType.Reply, 0); + AddLabel(38, y, 0x384, "Bring"); + + + // add gump extension button + if (m_ShowExtension) + { + AddButton(720, y + 5, 0x15E3, 0x15E7, 200, GumpButtonType.Reply, 0); + } + else + { + AddButton(150, y + 5, 0x15E1, 0x15E5, 200, GumpButtonType.Reply, 0); + } + + if (m_ShowExtension) + { + AddLabel(143, 5, 0x384, "Gump"); + AddLabel(178, 5, 0x384, "Prop"); + AddLabel(210, 5, 0x384, "Goto"); + AddLabel(250, 5, 0x384, "Name"); + AddLabel(365, 5, 0x384, "Type"); + AddLabel(460, 5, 0x384, "Location"); + AddLabel(578, 5, 0x384, "Map"); + AddLabel(650, 5, 0x384, "Owner"); + + // add the Delete button + AddButton(150, y, 0xFB1, 0xFB3, 156, GumpButtonType.Reply, 0); + AddLabel(183, height - 25, 0x384, "Delete"); + + // add the Reset button + AddButton(230, y, 0xFA2, 0xFA3, 157, GumpButtonType.Reply, 0); + AddLabel(263, y, 0x384, "Reset"); + + // add the Respawn button + AddButton(310, y, 0xFA8, 0xFAA, 158, GumpButtonType.Reply, 0); + AddLabel(343, y, 0x384, "Respawn"); + + // add the xmlsave entry + AddButton(150, y - 25, 0xFA8, 0xFAA, 159, GumpButtonType.Reply, 0); + AddLabel(183, y - 25, 0x384, "Save to file:"); + + AddImageTiled(270, y - 25, 180, 19, 0xBBC); + AddTextEntry(270, y - 25, 180, 19, 0, 300, SaveFilename); + + // add the commandstring entry + AddButton(470, y - 25, 0xFA8, 0xFAA, 160, GumpButtonType.Reply, 0); + AddLabel(503, y - 25, 0x384, "Command:"); + + AddImageTiled(560, y - 25, 180, 19, 0xBBC); + AddTextEntry(560, y - 25, 180, 19, 0, 301, CommandString); + + + // add the page buttons + for (int i = 0; i < (int)(MaxEntries / MaxEntriesPerPage); i++) + { + //AddButton( 38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i ); + AddButton(418 + i * 25, height - 25, 0x8B1 + i, 0x8B1 + i, 0, GumpButtonType.Page, 1 + i); + } + + // add the advance pageblock buttons + AddButton(415 + 25 * (int)(MaxEntries / MaxEntriesPerPage), height - 25, 0x15E1, 0x15E5, 201, GumpButtonType.Reply, 0); // block forward + AddButton(395, height - 25, 0x15E3, 0x15E7, 202, GumpButtonType.Reply, 0); // block backward + + // add the displayfrom entry + AddLabel(460, y, 0x384, "Display"); + AddImageTiled(500, y, 60, 21, 0xBBC); + AddTextEntry(501, y, 60, 21, 0, 400, DisplayFrom.ToString()); + AddButton(560, y, 0xFAB, 0xFAD, 9998, GumpButtonType.Reply, 0); + + // display the item list + if (m_SearchList != null) + { + AddLabel(180, y - 50, 68, String.Format("Found {0} items/mobiles", m_SearchList.Count)); + AddLabel(400, y - 50, 68, String.Format("Displaying {0}-{1}", DisplayFrom, + (DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count))); + // count the number of selected objects + int count = 0; + foreach (SearchEntry e in m_SearchList) + { + if (e.Selected) count++; + } + AddLabel(600, y - 50, 33, String.Format("Selected {0}", count)); + } + + // display the select-all-displayed toggle + AddButton(730, 5, 0xD2, 0xD3, 3999, GumpButtonType.Reply, 0); + + AddLabel(610, y, 0x384, "Select All"); + // display the select-all toggle + AddButton(670, y, (SelectAll ? 0xD3 : 0xD2), (SelectAll ? 0xD2 : 0xD3), 3998, GumpButtonType.Reply, 0); + + for (int i = 0; i < MaxEntries; i++) + { + int index = i + DisplayFrom; + if (m_SearchList == null || index >= m_SearchList.Count) break; + + SearchEntry e = (SearchEntry)m_SearchList[index]; + + int page = (int)(i / MaxEntriesPerPage); + + if (i % MaxEntriesPerPage == 0) + { + AddPage(page + 1); + // add highlighted page button + //AddImageTiled( 235+page*25, 448, 25, 25, 0xBBC ); + //AddImage( 238+page*25, 450, 0x8B1+page ); + } + + // background for search results area + AddImageTiled(235, 22 * (i % MaxEntriesPerPage) + 30, 386, 23, 0x52); + AddImageTiled(236, 22 * (i % MaxEntriesPerPage) + 31, 384, 21, 0xBBC); + + // add the Goto button for each entry + AddButton(205, 22 * (i % MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1000 + i, GumpButtonType.Reply, 0); + + object o = e.Object; + + // add the Gump button for spawner entries + if (o is XmlSpawner || o is Spawner) + { + AddButton(145, 22 * (i % MaxEntriesPerPage) + 30, 0xFBD, 0xFBE, 2000 + i, GumpButtonType.Reply, 0); + } + + // add the Props button for each entry + AddButton(175, 22 * (i % MaxEntriesPerPage) + 30, 0xFAB, 0xFAD, 3000 + i, GumpButtonType.Reply, 0); + + string namestr = null; + string typestr = null; + string locstr = null; + string mapstr = null; + string ownstr = null; + int texthue = 0; + + if (o is Item) + { + Item item = (Item)e.Object; + // change the color if it is in a container + namestr = item.Name; + string str = item.GetType().ToString(); + if (str != null) + { + string[] arglist = str.Split('.'); + typestr = arglist[arglist.Length - 1]; + } + // check for in container + // if so then display parent loc + // change the color for container held items + if (item.Parent != null) + { + + if (item.RootParent is Mobile) + { + + Mobile m = item.RootParent as Mobile; + if (m.Player) + texthue = 44; + else + texthue = 24; + locstr = m.Location.ToString(); + ownstr = m.Name; + } + else + if (item.RootParent is Container) + { + texthue = 5; + Container c = item.RootParent as Container; + locstr = c.Location.ToString(); + if (c.Name != null) + { + ownstr = c.Name; + } + else + { + ownstr = c.ItemData.Name; + } + } + + } + else + { + locstr = item.Location.ToString(); + } + + if (item.Deleted) + mapstr = "Deleted"; + else + if (item.Map != null) + mapstr = item.Map.ToString(); + + } + else + if (o is Mobile) + { + Mobile mob = (Mobile)e.Object; + // change the color if it is in a container + namestr = mob.Name; + string str = mob.GetType().ToString(); + if (str != null) + { + string[] arglist = str.Split('.'); + typestr = arglist[arglist.Length - 1]; + } + locstr = mob.Location.ToString(); + if (mob.Deleted) + mapstr = "Deleted"; + else + if (mob.Map != null) + mapstr = mob.Map.ToString(); + + } + else + if (o is XmlAttachment) + { + XmlAttachment a = (XmlAttachment)e.Object; + // change the color + namestr = a.Name; + + string str = a.GetType().ToString(); + if (a.Owner is Mobile) + { + Mobile m = a.Owner as Mobile; + + ownstr = m.Name; + if (m.Player) + texthue = 44; + else + texthue = 24; + } + else + if (a.Owner is Item) + { + Item item = a.Owner as Item; + + texthue = 50; + if (item.Name != null) + { + ownstr = item.Name; + } + else + { + ownstr = item.ItemData.Name; + } + } + if (str != null) + { + string[] arglist = str.Split('.'); + typestr = arglist[arglist.Length - 1]; + } + if (a.AttachedTo is Mobile) + { + Mobile m = (Mobile)a.AttachedTo; + locstr = m.Location.ToString(); + if (m.Map != null) + mapstr = m.Map.ToString(); + } + if (a.AttachedTo is Item) + { + Item item = (Item)a.AttachedTo; + if (item.Map != null) + mapstr = item.Map.ToString(); + if (item.Parent != null) + { + if (item.RootParent is Mobile) + { + locstr = ((Mobile)item.RootParent).Location.ToString(); + + } + else + if (item.RootParent is Item) + { + locstr = ((Item)item.RootParent).Location.ToString(); + } + } + else + locstr = item.Location.ToString(); + } + if (a.Deleted) + { + mapstr = "Deleted"; + } + + } + + if (e.Selected) texthue = 33; + + if (i == Selected) texthue = 68; + + // display the name + AddLabelCropped(248, 22 * (i % MaxEntriesPerPage) + 31, 110, 21, texthue, namestr); + + // display the attachment button if it has attachments + if (XmlAttach.HasAttachments(o)) + { + AddButton(238, 22 * (i % MaxEntriesPerPage) + 35, 2103, 2103, 5000 + i, GumpButtonType.Reply, 0); + } + + // display the type + AddImageTiled(360, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, 0xBBC); + AddLabelCropped(360, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, texthue, typestr); + // display the loc + AddImageTiled(450, 22 * (i % MaxEntriesPerPage) + 31, 137, 21, 0xBBC); + AddLabel(450, 22 * (i % MaxEntriesPerPage) + 31, texthue, locstr); + // display the map + AddImageTiled(571, 22 * (i % MaxEntriesPerPage) + 31, 70, 21, 0xBBC); + AddLabel(571, 22 * (i % MaxEntriesPerPage) + 31, texthue, mapstr); + // display the owner + AddImageTiled(640, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, 0xBBC); + AddLabelCropped(640, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, texthue, ownstr); + + // display the selection button + + AddButton(730, 22 * (i % MaxEntriesPerPage) + 32, (e.Selected ? 0xD3 : 0xD2), (e.Selected ? 0xD2 : 0xD3), 4000 + i, GumpButtonType.Reply, 0); + + } + } + } + + private void DoGoTo(int index) + { + if (m_From == null || m_From.Deleted) return; + + if (m_SearchList != null && index < m_SearchList.Count) + { + object o = ((SearchEntry)m_SearchList[index]).Object; + if (o is Item) + { + Item item = (Item)o; + Point3D itemloc; + if (item.Parent != null) + { + if (item.RootParent is Mobile) + { + itemloc = ((Mobile)(item.RootParent)).Location; + } + else + if (item.RootParent is Container) + { + itemloc = ((Container)(item.RootParent)).Location; + } + else + { + return; + } + } + else + { + itemloc = item.Location; + } + if (item == null || item.Deleted || item.Map == null || item.Map == Map.Internal) return; + m_From.Location = itemloc; + m_From.Map = item.Map; + + } + else + if (o is Mobile) + { + Mobile mob = (Mobile)o; + if (mob == null || mob.Deleted || mob.Map == null || mob.Map == Map.Internal) return; + m_From.Location = mob.Location; + m_From.Map = mob.Map; + } + else + if (o is XmlAttachment) + { + XmlAttachment a = (XmlAttachment)o; + if (a == null || a.Deleted) return; + if (a.AttachedTo is Mobile) + { + Mobile mob = (Mobile)a.AttachedTo; + if (mob == null || mob.Deleted || mob.Map == null || mob.Map == Map.Internal) return; + m_From.Location = mob.Location; + m_From.Map = mob.Map; + } + else + if (a.AttachedTo is Item) + { + Item item = (Item)a.AttachedTo; + Point3D itemloc; + if (item.Parent != null) + { + if (item.RootParent is Mobile) + { + itemloc = ((Mobile)(item.RootParent)).Location; + } + else + if (item.RootParent is Container) + { + itemloc = ((Container)(item.RootParent)).Location; + } + else + { + return; + } + } + else + { + itemloc = item.Location; + } + if (item == null || item.Deleted || item.Map == null || item.Map == Map.Internal) return; + m_From.Location = itemloc; + m_From.Map = item.Map; + } + } + } + } + + private void DoShowGump(int index) + { + if (m_From == null || m_From.Deleted) return; + + if (m_SearchList != null && index < m_SearchList.Count) + { + object o = ((SearchEntry)m_SearchList[index]).Object; + if (o is XmlSpawner) + { + // dont open anything with a null map null item or deleted + XmlSpawner x = (XmlSpawner)o; + if (x == null || x.Deleted || x.Map == null || x.Map == Map.Internal) return; + x.OnDoubleClick(m_From); + } + else + if (o is Spawner) + { + Spawner x = (Spawner)o; + if (x == null || x.Deleted || x.Map == null || x.Map == Map.Internal) return; + x.OnDoubleClick(m_From); + } + } + } + + private void DoShowProps(int index) + { + if (m_From == null || m_From.Deleted) return; + + if (m_SearchList != null && index < m_SearchList.Count) + { + object o = ((SearchEntry)m_SearchList[index]).Object; + if (o is Item) + { + Item x = (Item)o; + if (x == null || x.Deleted /*|| x.Map == null*/) return; + m_From.SendGump(new PropertiesGump(m_From, o)); + } + else + if (o is Mobile) + { + Mobile x = (Mobile)o; + if (x == null || x.Deleted /*|| x.Map == null*/) return; + m_From.SendGump(new PropertiesGump(m_From, o)); + } + else + if (o is XmlAttachment) + { + XmlAttachment x = (XmlAttachment)o; + if (x == null || x.Deleted /*|| x.Map == null*/) return; + m_From.SendGump(new PropertiesGump(m_From, o)); + } + + } + } + + private void SortFindList() + { + if (m_SearchList != null && m_SearchList.Count > 0) + { + if (Sorttype) + { + this.m_SearchList.Sort(new ListTypeSorter(Descendingsort)); + } + else + if (Sortname) + { + this.m_SearchList.Sort(new ListNameSorter(Descendingsort)); + } + else + if (Sortmap) + { + this.m_SearchList.Sort(new ListMapSorter(Descendingsort)); + } + else + if (Sortrange) + { + this.m_SearchList.Sort(new ListRangeSorter(m_From, Descendingsort)); + } + else + if (Sortselect) + { + this.m_SearchList.Sort(new ListSelectSorter(m_From, Descendingsort)); + } + } + } + + private class ListTypeSorter : IComparer + { + private bool Dsort; + + public ListTypeSorter(bool descend) + : base() + { + Dsort = descend; + } + + public int Compare(object e1, object e2) + { + object x = null; + object y = null; + if (e1 is SearchEntry) + x = ((SearchEntry)e1).Object; + if (e2 is SearchEntry) + y = ((SearchEntry)e2).Object; + + string xstr = null; + string ystr = null; + string str = null; + if (x is Item) + { + str = ((Item)x).GetType().ToString(); + } + else + if (x is Mobile) + { + str = ((Mobile)x).GetType().ToString(); + } + if (str != null) + { + string[] arglist = str.Split('.'); + xstr = arglist[arglist.Length - 1]; + } + + str = null; + if (y is Item) + { + str = ((Item)y).GetType().ToString(); + } + else + if (y is Mobile) + { + str = ((Mobile)y).GetType().ToString(); + } + if (str != null) + { + string[] arglist = str.Split('.'); + ystr = arglist[arglist.Length - 1]; + } + if (Dsort) + return String.Compare(ystr, xstr, true); + else + return String.Compare(xstr, ystr, true); + } + } + + private class ListNameSorter : IComparer + { + private bool Dsort; + + public ListNameSorter(bool descend) + : base() + { + Dsort = descend; + } + + public int Compare(object e1, object e2) + { + object x = null; + object y = null; + if (e1 is SearchEntry) + x = ((SearchEntry)e1).Object; + if (e2 is SearchEntry) + y = ((SearchEntry)e2).Object; + + string xstr = null; + string ystr = null; + + if (x is Item) + { + xstr = ((Item)x).Name; + } + else + if (x is Mobile) + { + xstr = ((Mobile)x).Name; + } + + if (y is Item) + { + ystr = ((Item)y).Name; + } + else + if (y is Mobile) + { + ystr = ((Mobile)y).Name; + } + if (Dsort) + return String.Compare(ystr, xstr, true); + else + return String.Compare(xstr, ystr, true); + } + } + + private class ListMapSorter : IComparer + { + private bool Dsort; + + public ListMapSorter(bool descend) + : base() + { + Dsort = descend; + } + + public int Compare(object e1, object e2) + { + object x = null; + object y = null; + if (e1 is SearchEntry) + x = ((SearchEntry)e1).Object; + if (e2 is SearchEntry) + y = ((SearchEntry)e2).Object; + + string xstr = null; + string ystr = null; + + if (x is Item) + { + if (((Item)x).Map != null) + xstr = ((Item)x).Map.ToString(); + } + else + if (x is Mobile) + { + if (((Mobile)x).Map != null) + xstr = ((Mobile)x).Map.ToString(); + } + + if (y is Item) + { + if (((Item)y).Map != null) + ystr = ((Item)y).Map.ToString(); + } + else + if (y is Mobile) + { + if (((Mobile)y).Map != null) + ystr = ((Mobile)y).Map.ToString(); + } + if (Dsort) + return String.Compare(ystr, xstr, true); + else + return String.Compare(xstr, ystr, true); + } + } + + private class ListEntrySorter : IComparer + { + private bool Dsort; + + public ListEntrySorter(bool descend) + : base() + { + Dsort = descend; + } + + public int Compare(object x, object y) + { + return 0; + } + } + + private class ListRangeSorter : IComparer + { + private Mobile From; + private bool Dsort; + + public ListRangeSorter(Mobile from, bool descend) + : base() + { + From = from; + Dsort = descend; + } + + public int Compare(object e1, object e2) + { + object x = null; + object y = null; + if (e1 is SearchEntry) + x = ((SearchEntry)e1).Object; + if (e2 is SearchEntry) + y = ((SearchEntry)e2).Object; + + Map xmap = null; + Map ymap = null; + Point3D xloc = new Point3D(0, 0, 0); + Point3D yloc = new Point3D(0, 0, 0); + + if (From == null || From.Deleted) return 0; + if (x is Item) + { + xmap = ((Item)x).Map; + xloc = ((Item)x).Location; + } + else + if (x is Mobile) + { + xmap = ((Mobile)x).Map; + xloc = ((Mobile)x).Location; + } + + if (y is Item) + { + ymap = ((Item)y).Map; + yloc = ((Item)y).Location; + } + else + if (y is Mobile) + { + ymap = ((Mobile)y).Map; + yloc = ((Mobile)y).Location; + } + + if (xmap != From.Map && ymap != From.Map) return 0; + + + if (Dsort) + { + if (xmap == From.Map && ymap != From.Map) return 1; + if (xmap != From.Map && ymap == From.Map) return -1; + return From.GetDistanceToSqrt(yloc).CompareTo(From.GetDistanceToSqrt(xloc)); + } + else + { + if (xmap == From.Map && ymap != From.Map) return -1; + if (xmap != From.Map && ymap == From.Map) return 1; + return From.GetDistanceToSqrt(xloc).CompareTo(From.GetDistanceToSqrt(yloc)); + } + } + } + + private class ListSelectSorter : IComparer + { + private Mobile From; + private bool Dsort; + + public ListSelectSorter(Mobile from, bool descend) + : base() + { + From = from; + Dsort = descend; + } + + public int Compare(object e1, object e2) + { + int x = 0; + int y = 0; + if (e1 is SearchEntry) + x = ((SearchEntry)e1).Selected ? 1 : 0; + if (e2 is SearchEntry) + y = ((SearchEntry)e2).Selected ? 1 : 0; + + + if (Dsort) + { + return x - y; + } + else + { + return y - x; + } + } + } + + private void Refresh(NetState state) + { + state.Mobile.SendGump(new XmlFindGump(this.m_From, this.StartingLoc, this.StartingMap, false, this.m_ShowExtension, this.Descendingsort, this.m_SearchCriteria, this.m_SearchList, this.Selected, this.DisplayFrom, this.SaveFilename, + this.CommandString, this.Sorttype, this.Sortname, this.Sortrange, + this.Sortmap, this.Sortselect, this.SelectAll, this.X, this.Y)); + } + + private void ResetList() + { + if (m_SearchList == null) return; + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is XmlSpawner) + { + ((XmlSpawner)o).DoReset = true; + } + } + } + } + + private void RespawnList() + { + if (m_SearchList == null) return; + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is XmlSpawner) + { + ((XmlSpawner)o).DoRespawn = true; + } + } + } + } + + private void SaveList(Mobile from, string filename) + { + if (m_SearchList == null) return; + + string dirname; + if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = String.Format("{0}/{1}", XmlSpawner.XmlSpawnDir, filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + + ArrayList savelist = new ArrayList(); + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is XmlSpawner) + { + // add it to the saves list + savelist.Add(o); + } + } + } + + // write out the spawners to a file + XmlSpawner.SaveSpawnList(from, savelist, dirname, false, true); + } + + private void ExecuteCommand(Mobile from, string command) + { + if (m_SearchList == null) return; + + ArrayList executelist = new ArrayList(); + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + // add it to the execute list + executelist.Add(o); + + } + } + + // lookup the command + // and execute it + if (command != null && command.Length > 0) + { + string[] args = command.Split(' '); + + if (args != null && args.Length > 1) + { + string[] cargs = new string[args.Length - 1]; + for (int i = 0; i < args.Length - 1; i++) + cargs[i] = args[i + 1]; + + CommandEventArgs e = new CommandEventArgs(from, args[0], command, cargs); + + foreach (BaseCommand c in TargetCommands.AllCommands) + { + // find the matching command + if (c.Commands[0].ToLower() == args[0].ToLower()) + { + bool flushToLog = false; + + // execute the command on the objects in the list + + if (executelist.Count > 20) + CommandLogging.Enabled = false; + + c.ExecuteList(e, executelist); + + if (executelist.Count > 20) + { + flushToLog = true; + CommandLogging.Enabled = true; + } + + c.Flush(from, flushToLog); + return; + } + } + from.SendMessage("Invalid command: {0}", args[0]); + } + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null || m_SearchCriteria == null) return; + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + + // read the text entries for the search criteria + TextRelay tr = info.GetTextEntry(105); // range info + m_SearchCriteria.Searchage = 0; + if (tr != null && tr.Text != null && tr.Text.Length > 0) + { + try { m_SearchCriteria.Searchage = double.Parse(tr.Text); } + catch { } + } + + // read the text entries for the search criteria + tr = info.GetTextEntry(100); // range info + m_SearchCriteria.Searchrange = -1; + if (tr != null && tr.Text != null && tr.Text.Length > 0) + { + try { m_SearchCriteria.Searchrange = int.Parse(tr.Text); } + catch { } + } + + tr = info.GetTextEntry(101); // type info + if (tr != null) + m_SearchCriteria.Searchtype = tr.Text; + + tr = info.GetTextEntry(102); // name info + if (tr != null) + m_SearchCriteria.Searchname = tr.Text; + + tr = info.GetTextEntry(125); // attachment type info + m_SearchCriteria.Searchattachtype = tr.Text; + + tr = info.GetTextEntry(103); // entry info + if (tr != null) + m_SearchCriteria.Searchspawnentry = tr.Text; + + tr = info.GetTextEntry(104); // condition info + if (tr != null) + m_SearchCriteria.Searchcondition = tr.Text; + + tr = info.GetTextEntry(106); // region info + if (tr != null) + m_SearchCriteria.Searchregion = tr.Text; + + + tr = info.GetTextEntry(400); // displayfrom info + try + { + DisplayFrom = int.Parse(tr.Text); + } + catch { } + + + tr = info.GetTextEntry(300); // savefilename info + if (tr != null) + SaveFilename = tr.Text; + + tr = info.GetTextEntry(301); // commandstring info + if (tr != null) + CommandString = tr.Text; + + + // check all of the check boxes + m_SearchCriteria.Searchagedirection = info.IsSwitched(302); + m_SearchCriteria.Dosearchage = info.IsSwitched(303); + m_SearchCriteria.Dosearchrange = info.IsSwitched(304); + m_SearchCriteria.Dosearchtype = info.IsSwitched(305); + m_SearchCriteria.Dosearchname = info.IsSwitched(306); + m_SearchCriteria.Dosearchspawnentry = info.IsSwitched(307); + m_SearchCriteria.Dosearchspawntype = info.IsSwitched(326); + m_SearchCriteria.Dosearcherr = info.IsSwitched(313); + m_SearchCriteria.Dosearchcondition = info.IsSwitched(315); + + m_SearchCriteria.Dosearchint = info.IsSwitched(312); + m_SearchCriteria.Dosearchfel = info.IsSwitched(308); + m_SearchCriteria.Dosearchtram = info.IsSwitched(309); + m_SearchCriteria.Dosearchmal = info.IsSwitched(310); + m_SearchCriteria.Dosearchilsh = info.IsSwitched(311); + m_SearchCriteria.Dosearchtok = info.IsSwitched(318); + m_SearchCriteria.Dosearchnull = info.IsSwitched(314); + + m_SearchCriteria.Dohidevalidint = info.IsSwitched(316); + m_SearchCriteria.Dosearchwithattach = info.IsSwitched(317); + m_SearchCriteria.Dosearchattach = info.IsSwitched(325); + m_SearchCriteria.Dosearchregion = info.IsSwitched(319); + + switch (info.ButtonID) + { + + case 0: // Close + { + return; + } + case 3: // Search + { + // clear any selection + Selected = -1; + + // reset displayfrom + DisplayFrom = 0; + + // do the search + m_SearchCriteria.Currentloc = state.Mobile.Location; + m_SearchCriteria.Currentmap = state.Mobile.Map; + + //m_SearchList = Search(m_SearchCriteria, out status_str); + XmlFindThread tobj = new XmlFindThread(state.Mobile, m_SearchCriteria, CommandString); + Thread find = new Thread(new ThreadStart(tobj.XmlFindThreadMain)); + find.Name = "XmlFind Thread"; + find.Start(); + + // turn on gump extension + m_ShowExtension = true; + return; + } + case 4: // SubSearch + { + // do the search + string status_str; + m_SearchList = Search(m_SearchCriteria, out status_str); + break; + } + case 150: // Open the map gump + { + break; + } + case 154: // Bring all selected objects to the current location + { + Refresh(state); + + state.Mobile.SendGump(new XmlConfirmBringGump(state.Mobile, m_SearchList)); + return; + } + case 155: // Return the player to the starting loc + { + m_From.Location = StartingLoc; + m_From.Map = StartingMap; + break; + } + case 156: // Delete selected items + { + Refresh(state); + + state.Mobile.SendGump(new XmlConfirmDeleteGump(state.Mobile, m_SearchList)); + return; + } + case 157: // Reset selected items + { + ResetList(); + break; + } + case 158: // Respawn selected items + { + RespawnList(); + break; + } + case 159: // xmlsave selected spawners + { + SaveList(state.Mobile, SaveFilename); + break; + } + case 160: // execute the command on the selected items + { + ExecuteCommand(state.Mobile, CommandString); + break; + } + case 200: // gump extension + { + m_ShowExtension = !m_ShowExtension; + break; + } + case 201: // forward block + { + if (m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) + { + DisplayFrom += MaxEntries; + // clear any selection + Selected = -1; + } + break; + } + case 202: // backward block + { + + DisplayFrom -= MaxEntries; + if (DisplayFrom < 0) DisplayFrom = 0; + // clear any selection + Selected = -1; + break; + } + + case 700: // Sort + { + // clear any selection + Selected = -1; + + Sorttype = false; + Sortname = false; + Sortrange = false; + Sortmap = false; + Sortselect = false; + // read the toggle switches that determine the sort + if (radiostate == 0) // sort by type + { + Sorttype = true; + } + else + if (radiostate == 1) // sort by name + { + Sortname = true; + } + else + if (radiostate == 2) // sort by range + { + Sortrange = true; + } + else + if (radiostate == 4) // sort by entry + { + Sortmap = true; + } + else + if (radiostate == 5) // sort by selected + { + Sortselect = true; + } + + SortFindList(); + break; + } + case 701: // descending sort + { + Descendingsort = !Descendingsort; + break; + } + case 9998: // refresh the gump + { + // clear any selection + Selected = -1; + break; + } + default: + { + + if (info.ButtonID >= 1000 && info.ButtonID < 1000 + MaxEntries) + { + // flag the entry selected + Selected = info.ButtonID - 1000; + // then go to it + DoGoTo(info.ButtonID - 1000 + DisplayFrom); + } + if (info.ButtonID >= 2000 && info.ButtonID < 2000 + MaxEntries) + { + // flag the entry selected + Selected = info.ButtonID - 2000; + // then open the gump + Refresh(state); + DoShowGump(info.ButtonID - 2000 + DisplayFrom); + return; + } + if (info.ButtonID >= 3000 && info.ButtonID < 3000 + MaxEntries) + { + Selected = info.ButtonID - 3000; + // Show the props window + Refresh(state); + DoShowProps(info.ButtonID - 3000 + DisplayFrom); + return; + } + else + if (info.ButtonID == 3998) + { + SelectAll = !SelectAll; + + if (m_SearchList != null) + { + foreach (SearchEntry e in m_SearchList) + { + e.Selected = SelectAll; + } + } + } + if (info.ButtonID == 3999) + { + + // toggle selection of everything currently displayed + if (m_SearchList != null) + { + for (int i = 0; i < MaxEntries; i++) + { + if (i + DisplayFrom < m_SearchList.Count) + { + SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; + + e.Selected = !e.Selected; + } + else + { + break; + } + } + } + } + if (info.ButtonID >= 4000 && info.ButtonID < 4000 + MaxEntries) + { + int i = info.ButtonID - 4000; + + if (m_SearchList != null && i >= 0 && m_SearchList.Count > i + DisplayFrom) + { + SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; + + e.Selected = !e.Selected; + } + } + if (info.ButtonID >= 5000 && info.ButtonID < 5000 + MaxEntries) + { + int i = info.ButtonID - 5000; + + if (m_SearchList != null && i >= 0 && m_SearchList.Count > i + DisplayFrom) + { + SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; + + state.Mobile.CloseGump(typeof(XmlGetAttGump)); + state.Mobile.SendGump(new XmlGetAttGump(state.Mobile, e.Object, 10, 10)); + } + } + break; + } + } + // Create a new gump + //m_Spawner.OnDoubleClick( state.Mobile); + Refresh(state); + } + + public class XmlConfirmBringGump : Gump + { + private ArrayList SearchList; + + private Mobile From; + + public XmlConfirmBringGump(Mobile from, ArrayList searchlist) + : base(0, 0) + { + SearchList = searchlist; + + From = from; + Closable = false; + Dragable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + int count = 0; + + if (SearchList != null) + { + for (int i = 0; i < SearchList.Count; i++) + { + if (((SearchEntry)SearchList[i]).Selected) count++; + } + } + + AddLabel(20, 225, 33, String.Format("Bring {0} objects to you?", count)); + AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff, false, false); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff, false, false); // No + AddButton(80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0); // Okay button + + } + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + + Point3D myloc = state.Mobile.Location; + Map mymap = state.Mobile.Map; + + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + + default: + { + if (radiostate == 1 && SearchList != null) + { // accept + for (int i = 0; i < SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is Item) + { + + ((Item)o).MoveToWorld(myloc, mymap); + + } + else + if (o is Mobile) + { + + ((Mobile)o).MoveToWorld(myloc, mymap); + + } + } + } + } + break; + } + } + } + } + + public class XmlConfirmDeleteGump : Gump + { + private ArrayList SearchList; + + private Mobile From; + + public XmlConfirmDeleteGump(Mobile from, ArrayList searchlist) + : base(0, 0) + { + SearchList = searchlist; + + From = from; + Closable = false; + Dragable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + int count = 0; + + if (SearchList != null) + { + for (int i = 0; i < SearchList.Count; i++) + { + if (((SearchEntry)SearchList[i]).Selected) count++; + } + } + + AddLabel(20, 225, 33, String.Format("Delete {0} objects?", count)); + AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff, false, false); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff, false, false); // No + AddButton(80, 289, 2130, 2129, 3, GumpButtonType.Reply, 0); // Okay button + + } + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null) return; + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + + default: + { + if (radiostate == 1 && SearchList != null) + { // accept + for (int i = 0; i < SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is Item) + { + // some objects may not delete gracefully (null map items are particularly error prone) so trap them + try + { + ((Item)o).Delete(); + } + catch { } + } + else + // block player deletion + if ((o is Mobile) && !(((Mobile)o).Player)) + { + try + { + ((Mobile)o).Delete(); + } + catch { } + } + else + if (o is XmlAttachment) + { + try + { + ((XmlAttachment)o).Delete(); + } + catch { } + } + } + + } + } + break; + } + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/XmlUtils/XmlPartialCategorizedAddGump.cs b/Scripts/Customs/XML Spawner/XmlUtils/XmlPartialCategorizedAddGump.cs new file mode 100644 index 0000000..70e458a --- /dev/null +++ b/Scripts/Customs/XML Spawner/XmlUtils/XmlPartialCategorizedAddGump.cs @@ -0,0 +1,267 @@ + +using System; +using System.Collections; +using System.Reflection; +using Server; +using Server.Targeting; +using Server.Engines.XmlSpawner2; +using Server.Mobiles; + +/* +** Modified from RunUO 1.0.0 AddGump.cs +** by ArteGordon +** 3/13/05 +*/ + +namespace Server.Gumps +{ + public class XmlPartialCategorizedAddGump : Gump + { + private string m_SearchString; + private ArrayList m_SearchResults; + private int m_Page; + private Gump m_Gump; + private int m_EntryIndex = -1; + private XmlSpawner m_Spawner; + + public XmlPartialCategorizedAddGump( Mobile from, string searchString, int page, ArrayList searchResults, bool explicitSearch, int entryindex, Gump gump ) : base( 50, 50 ) + { + + if(gump is XmlSpawnerGump) + { + // keep track of the spawner for xmlspawnergumps + m_Spawner = ((XmlSpawnerGump)gump).m_Spawner; + } + + // keep track of the gump + m_Gump = gump; + + + m_SearchString = searchString; + m_SearchResults = searchResults; + m_Page = page; + + m_EntryIndex = entryindex; + + from.CloseGump( typeof( XmlPartialCategorizedAddGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 280, 5054 ); + + AddImageTiled( 10, 10, 400, 20, 2624 ); + AddAlphaRegion( 10, 10, 400, 20 ); + AddImageTiled( 41, 11, 184, 18, 0xBBC ); + AddImageTiled( 42, 12, 182, 16, 2624 ); + AddAlphaRegion( 42, 12, 182, 16 ); + + AddButton( 10, 9, 4011, 4013, 1, GumpButtonType.Reply, 0 ); + AddTextEntry( 44, 10, 180, 20, 0x480, 0, searchString ); + + AddHtmlLocalized( 230, 10, 100, 20, 3010005, 0x7FFF, false, false ); + + AddImageTiled( 10, 40, 400, 200, 2624 ); + AddAlphaRegion( 10, 40, 400, 200 ); + + if ( searchResults.Count > 0 ) + { + for ( int i = (page * 10); i < ((page + 1) * 10) && i < searchResults.Count; ++i ) + { + int index = i % 10; + + SearchEntry se = (SearchEntry)searchResults[i]; + + string labelstr = se.EntryType.Name; + + if(se.Parameters.Length > 0) + { + for(int j = 0; j < se.Parameters.Length;j++) + { + labelstr += ", " + se.Parameters[j].Name; + } + } + + AddLabel( 44, 39 + (index * 20), 0x480, labelstr ); + AddButton( 10, 39 + (index * 20), 4023, 4025, 4 + i, GumpButtonType.Reply, 0 ); + } + } + else + { + AddLabel( 15, 44, 0x480, explicitSearch ? "Nothing matched your search terms." : "No results to display." ); + } + + AddImageTiled( 10, 250, 400, 20, 2624 ); + AddAlphaRegion( 10, 250, 400, 20 ); + + if ( m_Page > 0 ) + AddButton( 10, 249, 4014, 4016, 2, GumpButtonType.Reply, 0 ); + else + AddImage( 10, 249, 4014 ); + + AddHtmlLocalized( 44, 250, 170, 20, 1061028, m_Page > 0 ? 0x7FFF : 0x5EF7, false, false ); // Previous page + + if ( ((m_Page + 1) * 10) < searchResults.Count ) + AddButton( 210, 249, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + else + AddImage( 210, 249, 4005 ); + + AddHtmlLocalized( 244, 250, 170, 20, 1061027, ((m_Page + 1) * 10) < searchResults.Count ? 0x7FFF : 0x5EF7, false, false ); // Next page + } + + private static Type typeofItem = typeof( Item ), typeofMobile = typeof( Mobile ); + + private class SearchEntry + { + public Type EntryType; + public ParameterInfo [] Parameters; + + public SearchEntry() + { + } + } + private static void Match( string match, Type[] types, ArrayList results ) + { + if ( match.Length == 0 ) + return; + + match = match.ToLower(); + + for ( int i = 0; i < types.Length; ++i ) + { + Type t = types[i]; + + if ( (typeofMobile.IsAssignableFrom( t ) || typeofItem.IsAssignableFrom( t )) && t.Name.ToLower().IndexOf( match ) >= 0 && !results.Contains( t ) ) + { + ConstructorInfo[] ctors = t.GetConstructors(); + + for ( int j = 0; j < ctors.Length; ++j ) + { + if ( /*ctors[j].GetParameters().Length == 0 && */ ctors[j].IsDefined( typeof( ConstructableAttribute ), false ) ) + { + SearchEntry s = new SearchEntry(); + s.EntryType = t; + s.Parameters = ctors[j].GetParameters(); + //results.Add( t ); + results.Add( s ); + //break; + } + } + } + } + } + + public static ArrayList Match( string match ) + { + ArrayList results = new ArrayList(); + Type[] types; + + Assembly[] asms = ScriptCompiler.Assemblies; + + for ( int i = 0; i < asms.Length; ++i ) + { + types = ScriptCompiler.GetTypeCache( asms[i] ).Types; + Match( match, types, results ); + } + + types = ScriptCompiler.GetTypeCache( Core.Assembly ).Types; + Match( match, types, results ); + + results.Sort( new TypeNameComparer() ); + + return results; + } + + private class TypeNameComparer : IComparer + { + public int Compare( object x, object y ) + { + SearchEntry a = x as SearchEntry; + SearchEntry b = y as SearchEntry; + + return a.EntryType.Name.CompareTo( b.EntryType.Name ); + } + } + + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + switch ( info.ButtonID ) + { + case 1: // Search + { + TextRelay te = info.GetTextEntry( 0 ); + string match = ( te == null ? "" : te.Text.Trim() ); + + if ( match.Length < 3 ) + { + from.SendMessage( "Invalid search string." ); + from.SendGump( new XmlPartialCategorizedAddGump( from, match, m_Page, m_SearchResults, false, m_EntryIndex, m_Gump ) ); + } + else + { + from.SendGump( new XmlPartialCategorizedAddGump( from, match, 0, Match( match ) , true, m_EntryIndex, m_Gump ) ); + } + + break; + } + case 2: // Previous page + { + if ( m_Page > 0 ) + from.SendGump( new XmlPartialCategorizedAddGump( from, m_SearchString, m_Page - 1, m_SearchResults, true, m_EntryIndex, m_Gump ) ); + + break; + } + case 3: // Next page + { + if ( (m_Page + 1) * 10 < m_SearchResults.Count ) + from.SendGump( new XmlPartialCategorizedAddGump( from, m_SearchString, m_Page + 1, m_SearchResults, true, m_EntryIndex, m_Gump ) ); + + break; + } + default: + { + int index = info.ButtonID - 4; + + if ( index >= 0 && index < m_SearchResults.Count ) + { + + Type type = ((SearchEntry)m_SearchResults[index]).EntryType; + + if(m_Gump is XmlAddGump && type != null) + { + XmlAddGump m_XmlAddGump = (XmlAddGump)m_Gump; + if(type != null && m_XmlAddGump.defs != null && m_XmlAddGump.defs.NameList != null && + m_EntryIndex >= 0 && m_EntryIndex < m_XmlAddGump.defs.NameList.Length) + { + m_XmlAddGump.defs.NameList[m_EntryIndex] = type.Name; + XmlAddGump.Refresh(from, true); + } + } + else + if(m_Spawner != null && type != null) + { + XmlSpawnerGump xg = m_Spawner.SpawnerGump; + + if(xg != null) + { + + xg.Rentry = new XmlSpawnerGump.ReplacementEntry(); + xg.Rentry.Typename = type.Name; + xg.Rentry.Index = m_EntryIndex; + xg.Rentry.Color = 0x1436; + + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( XmlSpawnerGump.Refresh_Callback ), new object[]{ from } ); + //from.CloseGump(typeof(XmlSpawnerGump)); + //from.SendGump( new XmlSpawnerGump(xg.m_Spawner, xg.X, xg.Y, xg.m_ShowGump, xg.xoffset, xg.page, xg.Rentry) ); + } + } + } + + break; + } + } + } + } +} diff --git a/Scripts/Customs/XML Spawner/customattacks.xml b/Scripts/Customs/XML Spawner/customattacks.xml new file mode 100644 index 0000000..83a81b0 --- /dev/null +++ b/Scripts/Customs/XML Spawner/customattacks.xml @@ -0,0 +1,45 @@ + + + + CustomAttacks#1 + cd117f6c-e958-4080-89b8-80e9a4d21c4b + Felucca + 5438 + 1151 + 10 + 10 + 5443 + 1156 + 0 + 5 + 2 + 5 + 10 + False + 0 + 0 + -1 + 500 + 1 + False + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + False + -1 + False + False + 0 + 1 + False + True + True + katana/name/Custom Weapon/ATTACH/xmlcustomattacks,random,3:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=orc/ADD/<buckler/hue/500/name/Master of Defense/ATTACH/xmlcustomdefenses,random,4>:MX=1:SB=0:RT=0:TO=0:KL=0 + + \ No newline at end of file diff --git a/Scripts/Customs/XML Spawner/installation 2.0.txt b/Scripts/Customs/XML Spawner/installation 2.0.txt new file mode 100644 index 0000000..3e3a03b --- /dev/null +++ b/Scripts/Customs/XML Spawner/installation 2.0.txt @@ -0,0 +1,458 @@ +INSTALLATION: +for RunUO 2.0 + +BASIC INSTALLATION +------------------ +If you just wish to the standard spawning features of xmlspawner, and are not interested in support of quests, advanced spawn triggering, or additional addon systems, then this single basic installation step is enough. + +STEP 1: +With a fresh 2.0 install, simply unzip the contents of the three required packages into your custom scripts directory. + +The xmlspawner2-20-vxxx-1of3.zip file is a necessary part of the installation. +The xmlspawner2-20-vxxx-2of3.zip file is a necessary part of the installation. +The xmlspawner2-20-vxxx-3of3.zip file is a necessary part of the installation. + + +Note, XmlSpawner2 is fully compatible with all existing xml spawn file descriptions and can also co-exist with the standard distribution spawners and other spawners. +You can use xmlspawners and other spawners at the same time if you like. + + +ADVANCED INSTALLATION +--------------------- +If you plan to use the xmlspawner quest system or other advanced features, then there are additional installation steps that provide additional functionality to the XmlSpawner2 system. None of the additional steps are absolutely required for basic spawner functioning, but they do add additional features that will enhance the use of the system. +Feel free to go through the steps and select the ones that seem like they would be of use to you, or select none if you decide you would rather not make additional modifications. + + +The xmlspawner2-support.zip file is a recommended part of the installation. +The xmlspawner2-xmlextras.zip is completely optional containing .xml file examples of some of the spawner capabilities as well as other spawn files. Make a folder called Spawns in the main RunUO installation directory (where your server.exe is) and place the .xml files in there. Then make a folder named XmlQuestNPC in the main RunUO installation directory and place the .npc files there. +Test them out by using the [xmlload command on the example .xml files. Most of these will load up in Green Acres. You can also use the [xmlloadhere command to force them to load at your current location. + + +If you plan on spawning rares or any items with long spawn cycles I would strongly recommend that you follow installation step 4. You can find the reason for this described at the end of xmlspawner2.txt in the section "FIX FOR STOLEN/TAKEN ITEM SPAWNS THAT REMAIN UNDER SPAWNER CONTROL" + + +Additional Recommended Steps: + +STEP 2: (recommended but not required) +-------------------------------------- +To take advantage of the XmlQuest killtask keywords KILL and KILLNAMED, one line must be added to the OnDeath method in BaseCreature.cs as described below (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, the KILL and KILLNAMED features simply wont do anything) + +around line 4172 of basecreature.cs change + +Titles.AwardKarma( ds.m_Mobile, totalKarma, true ); + +to + +Titles.AwardKarma( ds.m_Mobile, totalKarma, true ); +// modification to support XmlQuest Killtasks +XmlQuest.RegisterKill( this, ds.m_Mobile); + + +STEP 3: (NOT recommended but allowed) +------------------------------------- +In order to provide the book extended text entry interface, xmlspawner replaces the default packet handler for basebooks. While this does not affect the behavior of standard books in any way, if you DONT want this mod, comment out the following line at line 26 in PacketHandlerOverrides.cs +If you comment out this line then you will NOT be able to edit spawner entries using the book interface. + +// Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ContentChangeOverride ) ); + + +STEP 4: (recommended but not required) +-------------------------------------- +To take advantage of the stealable rares/artifacts system and the support for eliminating issues of maintained spawner control over items, either replace the default distribution files container.cs (Scripts/Items/Containers/Container.cs) and stealing.cs (Scripts/Skills/Stealing.cs) with the versions found in xmlspawner2-support.zip. Select the appropriate RC1 or RC2 versions and change the extension back to .cs (always keep backups of the originals). Or the simpler way is to just change the extension of the distro files to something other than .cs + + +STEP 5: (recommended but not required) +-------------------------------------- +To take advantage of spawner triggering on skill use you must change 4 lines in Scripts/Misc/SkillCheck.cs (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, the SkillTriggering features simply wont do anything). Near the beginning of the file at line 73 change these lines. + +public static void Initialize() +{ +Mobile.SkillCheckLocationHandler = new SkillCheckLocationHandler( Mobile_SkillCheckLocation ); +Mobile.SkillCheckDirectLocationHandler = new SkillCheckDirectLocationHandler( Mobile_SkillCheckDirectLocation ); + +Mobile.SkillCheckTargetHandler = new SkillCheckTargetHandler( Mobile_SkillCheckTarget ); +Mobile.SkillCheckDirectTargetHandler = new SkillCheckDirectTargetHandler( Mobile_SkillCheckDirectTarget ); +} + +to this + +public static void Initialize() +{ +// Begin mod to enable XmlSpawner skill triggering +Mobile.SkillCheckLocationHandler = new SkillCheckLocationHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckLocation ); +Mobile.SkillCheckDirectLocationHandler = new SkillCheckDirectLocationHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckDirectLocation ); + +Mobile.SkillCheckTargetHandler = new SkillCheckTargetHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckTarget ); +Mobile.SkillCheckDirectTargetHandler = new SkillCheckDirectTargetHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckDirectTarget ); +// End mod to enable XmlSpawner skill triggering +} + + +STEP 6: (recommended but not required) +-------------------------------------- +To allow the XmlQuest killtask keywords KILL and KILLNAMED to be applied to players providing a contract kill system, one line must be added to ReportMurderer.cs (Scripts/Gumps/ReportMurderer.cs) as described below (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, the KILL and KILLNAMED features simply wont work when specifying players as the targets). +This is also required to allow the attachment system to register kills (through the OnKill or OnKilled methods). Some addons such as XmlPoints require this. + +around line 64 of ReportMurderer.cs change + +Titles.AwardKarma( g, karmaAward, true ); + +to + +Titles.AwardKarma( g, karmaAward, true ); +// modification to support XmlQuest Killtasks of players +Server.Items.XmlQuest.RegisterKill( m, g); + + + +STEP 7: (recommended but not required) +-------------------------------------- +To allow attachments to be triggered on weapon hits, one line must be added to BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs) as described below (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, the attachment OnWeaponHit method simply wont be called so attachments such as XmlMinionStrike will not work) + +around line 1644 of BaseWeapon.cs at the end of the OnHit method, change + + if ( AnimalForm.UnderTransformation( defender, typeof( BullFrog ) ) ) + attacker.ApplyPoison( defender, Poison.Regular ); + } + } + +to + + if ( AnimalForm.UnderTransformation( defender, typeof( BullFrog ) ) ) + attacker.ApplyPoison( defender, Poison.Regular ); + } + // hook for attachment OnWeaponHit method + Server.Engines.XmlSpawner2.XmlAttach.OnWeaponHit(this, attacker, defender, damageGiven); + } + + +STEP 8: (recommended but not required) +-------------------------------------- +To allow the ItemIdentification skill to be used to reveal attachments on items/mobs, one line must be added to ItemIdentification.cs (Scripts/Skills/ItemIdentification.cs) as described below. (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, players just wont be able to see what attachments are on an item/mob using this skill). + +around line 50 of ItemIdentification.cs change + +else if ( o is Mobile ) +{ + ((Mobile)o).OnSingleClick( from ); +} + else +{ + from.SendLocalizedMessage( 500353 ); // You are not certain... +} + +to + +else if ( o is Mobile ) +{ + ((Mobile)o).OnSingleClick( from ); +} + else +{ + from.SendLocalizedMessage( 500353 ); // You are not certain... +} +//allows the identify skill to reveal attachments +Server.Engines.XmlSpawner2.XmlAttach.RevealAttachments(from,o); + + +STEP 9: (recommended but not required) +-------------------------------------- +To allow attachments to make use of the OnEquip and OnRemoved methods, the following 8 changes must be made in three files, BaseArmor.cs, BaseWeapon.cs, and BaseJewel.cs. (note, you dont have to make this mod if you dont want to, the spawner and other items/attachments will work just fine without it, you just wont be able to use certain attachments that make use of this feature such as XmlFactionEquip). + +around line 1202 of BaseArmor.cs (Scripts/Items/Armor/BaseArmor.cs) at the end of the CanEquip method change + + return base.CanEquip( from ); + +to + + // XmlAttachment check for CanEquip + if(!Server.Engines.XmlSpawner2.XmlAttach.CheckCanEquip(this, from)) + { + return false; + } else + { + + return base.CanEquip( from ); + } + + +around line 1241 of BaseArmor.cs (Scripts/Items/Armor/BaseArmor.cs) at the end of the OnEquip method change + + + return base.OnEquip( from ); + +to + + + // XmlAttachment check for OnEquip + Server.Engines.XmlSpawner2.XmlAttach.CheckOnEquip(this, from); + + return base.OnEquip( from ); + + +around line 1273 of BaseArmor.cs (Scripts/Items/Armor/BaseArmor.cs) at the end of the OnRemoved method change + + + base.OnRemoved( parent ); + +to + + // XmlAttachment check for OnRemoved + Server.Engines.XmlSpawner2.XmlAttach.CheckOnRemoved(this, parent); + + base.OnRemoved( parent ); + + +around line 569 of BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs) at the end of the CanEquip method change + + else if ( !from.CanBeginAction( typeof( BaseWeapon ) ) ) + { + return false; + } + else + { + return base.CanEquip( from ); + } + +to + + else if ( !from.CanBeginAction( typeof( BaseWeapon ) ) ) + { + return false; + } + else + // XmlAttachment check for CanEquip + if (!Server.Engines.XmlSpawner2.XmlAttach.CheckCanEquip(this, from)) + { + return false; + } + else + { + return base.CanEquip(from); + } + + +around line 628 of BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs) at the end of the OnEquip method change + + return true; + +to + + // XmlAttachment check for OnEquip + Server.Engines.XmlSpawner2.XmlAttach.CheckOnEquip(this, from); + + return true; + + +around line 686 of BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs) at the end of the OnRemoved method change + + m.Delta( MobileDelta.WeaponDamage ); + } + } + +to + + m.Delta( MobileDelta.WeaponDamage ); + } + // XmlAttachment check for OnRemoved + Server.Engines.XmlSpawner2.XmlAttach.CheckOnRemoved(this, parent); + } + + +around line 138 of BaseJewel.cs (Scripts/Items/Jewels/BaseJewel.cs) at the end of the OnAdded method change + + from.CheckStatTimers(); + } + } + +to + + + from.CheckStatTimers(); + } + + // XmlAttachment check for OnEquip and CanEquip + if(parent is Mobile) + { + if(Server.Engines.XmlSpawner2.XmlAttach.CheckCanEquip(this, (Mobile)parent)) + { + Server.Engines.XmlSpawner2.XmlAttach.CheckOnEquip(this, (Mobile)parent); + } else + { + ((Mobile)parent).AddToBackpack(this); + } + } + } + + +around line 151 of BaseJewel.cs (Scripts/Items/Jewels/BaseJewel.cs) at the end of the OnRemoved method change + + from.CheckStatTimers(); + } + } + +to + + from.CheckStatTimers(); + } + + // XmlAttachment check for OnRemoved + Server.Engines.XmlSpawner2.XmlAttach.CheckOnRemoved(this, parent); + } + +STEP 10: (recommended but not required) +--------------------------------------- +To allow attachments to make use of the OnArmorHit methods, the following changes must be made in BaseWeapon.cs.(note, you dont have to make this mod if you dont want to, the spawner and other items/attachments will work just fine without it, you just wont be able to use features of certain attachments that require this such as XmlCustomAttacks). + + +at the beginning of the AbsorbDamageAOS method around line 1103 of BaseWeapon.cs change + + public virtual int AbsorbDamageAOS( Mobile attacker, Mobile defender, int damage ) + { + bool blocked = false; + +to + + public virtual int AbsorbDamageAOS( Mobile attacker, Mobile defender, int damage ) + { + bool blocked = false; + int originaldamage = damage; + + +in the AbsorbDamageAOS method around line 1142 of BaseWeapon.cs change + + if ( shield != null ) + { + shield.OnHit( this, damage ); + + } + +to + if ( shield != null ) + { + shield.OnHit( this, damage ); + + // XmlAttachment check for OnArmorHit + Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, shield, this, originaldamage); + } + + +in the AbsorbDamageAOS method around line 1173 of BaseWeapon.cs change + + if (armor != null) + { + armor.OnHit(this, damage); // call OnHit to lose durability + } + } + + return damage; + } + + +to + + if (armor != null) + { + armor.OnHit(this, damage); // call OnHit to lose durability + + // XmlAttachment check for OnArmorHit + damage -= Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, armorItem, this, originaldamage); + } + } + + return damage; + } + + + +in the AbsorbDamage method around line 1210 of BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs) change + + + int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod; + + +to + + // XmlAttachment check for OnArmorHit + damage -= Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, armorItem, this, damage); + damage -= Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, shield, this, damage); + + int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod; + + + +STEP 11: (recommended but not required) +--------------------------------------- +To allow attachment properties on weapons/armor to be automatically displayed in the properties list on mouseover/click, these changes must be made to BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs), BaseArmor.cs (Scripts/Items/Armor/BaseArmor.cs) and BaseJewel.cs (Scripts/Items/Jewels/BaseJewel.cs) described below. (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, players just wont automatically see attachment properties on items with attachments). + +at the end of the GetProperties method around line 3246 of BaseWeapon.cs change + + if ( m_Hits > 0 && m_MaxHits > 0 ) + list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~ + +to + + if ( m_Hits > 0 && m_MaxHits > 0 ) + list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~ + + // mod to display attachment properties + Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list); + + +at the end of the GetProperties method around line 1518 of BaseArmor.cs change + + if ( m_HitPoints > 0 && m_MaxHitPoints > 0 ) + list.Add( 1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints ); // durability ~1_val~ / ~2_val~ + +to + + if ( m_HitPoints > 0 && m_MaxHitPoints > 0 ) + list.Add( 1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints ); // durability ~1_val~ / ~2_val~ + + // mod to display attachment properties + Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list); + +at the end of the GetProperties method around line 226 of BaseJewel.cs change + + + base.AddResistanceProperties( list ); +to + + base.AddResistanceProperties( list ); + + // mod to display attachment properties + Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list); + + +STEP 12: (recommended but not required) +--------------------------------------- +To prevent Paragons from being despawned due to smartspawning, add this property to BaseCreature.cs anywhere within the BaseCreature class. Paragons should be excluded because the OnBeforeSpawn and OnAfterSpawn methods are not called when smartspawning, so if they despawn, they will not come back as paragons. + +public virtual bool HoldSmartSpawning + { + get{ + // dont smartspawn paragons + if(IsParagon) return true; + + return false; + } + } + +STEP 13: (recommended but not required) +--------------------------------------- +To fix a problem with lootpack generation under RunUO 2.0 using the LOOTPACK keyword, make this mod in Misc/LootPack.cs around line 571. If you dont make this mod, you will not be able to use the LOOTPACK keyword. + + private static bool IsInTokuno(Mobile m) + { + // ARTEGORDONMOD + // allow lootpack construction without a mobile + if (m == null) return false; + + if (m.Region.IsPartOf("Fan Dancer's Dojo")) + return true; + + if (m.Region.IsPartOf("Yomotsu Mines")) + return true; + + return (m.Map == Map.Tokuno); + } \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Shrink System/HitchingPost.cs b/Scripts/Customs/Xanthos/Shrink System/HitchingPost.cs new file mode 100644 index 0000000..5062b6b --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/HitchingPost.cs @@ -0,0 +1,192 @@ +#region AuthorHeader +// +// Shrink System version 2.1, by Xanthos +// +// +#endregion AuthorHeader +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Xanthos.Interfaces; + +namespace Xanthos.ShrinkSystem +{ + [Flipable( 0x14E8, 0x14E7 )] + public class HitchingPost : AddonComponent, IShrinkTool + { + private int m_Charges = ShrinkConfig.ShrinkCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int ShrinkCharges + { + get { return m_Charges; } + set + { + if ( 0 == m_Charges || 0 == (m_Charges = value )) + Delete(); + else + InvalidateProperties(); + } + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; }} + + [Constructable] + public HitchingPost() : this( 0x14E7 ) + { + } + + [Constructable] + public HitchingPost( int itemID ) : base( itemID ) + { + } + + public HitchingPost( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( m_Charges >= 0 ) + list.Add( 1060658, "Charges\t{0}", m_Charges.ToString() ); + } + + public override void OnDoubleClick( Mobile from ) + { + if( from.InRange( this.GetWorldLocation(), 2 ) == false ) + from.SendLocalizedMessage( 500486 ); //That is too far away. + + else if ( from.Skills[SkillName.AnimalTaming].Value >= ShrinkConfig.TamingRequired ) + from.Target = new ShrinkTarget( from, this, false ); + + else + from.SendMessage( "You must have at least " + ShrinkConfig.TamingRequired + " animal taming to use a hitching post." ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( m_Charges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Charges = reader.ReadInt(); + } + } + + public class HitchingPostEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new HitchingPostEastDeed(); }} + + [Constructable] + public HitchingPostEastAddon() + { + AddComponent( new HitchingPost( 0x14E7 ), 0, 0, 0); + } + + public HitchingPostEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class HitchingPostEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new HitchingPostEastAddon(); }} + + [Constructable] + public HitchingPostEastDeed() + { + Name = "Hitching Post (east)"; + } + + public HitchingPostEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + + public class HitchingPostSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new HitchingPostSouthDeed(); }} + + [Constructable] + public HitchingPostSouthAddon() + { + AddComponent( new HitchingPost( 0x14E8 ), 0, 0, 0); + } + + public HitchingPostSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class HitchingPostSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new HitchingPostSouthAddon(); }} + + [Constructable] + public HitchingPostSouthDeed() + { + Name = "Hitching Post (south)"; + } + + public HitchingPostSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Xanthos/Shrink System/PetLeash.cs b/Scripts/Customs/Xanthos/Shrink System/PetLeash.cs new file mode 100644 index 0000000..f5e81af --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/PetLeash.cs @@ -0,0 +1,80 @@ +#region AuthorHeader +// +// Shrink System version 2.1, by Xanthos +// +// +#endregion AuthorHeader +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Xanthos.Interfaces; + +namespace Xanthos.ShrinkSystem +{ + public class PetLeash : Item, IShrinkTool + { + private int m_Charges = ShrinkConfig.ShrinkCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int ShrinkCharges + { + get { return m_Charges; } + set + { + if ( 0 == m_Charges || 0 == (m_Charges = value )) + Delete(); + else + InvalidateProperties(); + } + } + + [Constructable] + public PetLeash() : base( 0x1374 ) + { + Weight = 1.0; + Movable = true; + Name = "Pet Leash"; + LootType = ( ShrinkConfig.BlessedLeash ? LootType.Blessed : LootType.Regular ); + } + + public PetLeash( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( m_Charges >= 0 ) + list.Add( 1060658, "Charges\t{0}", m_Charges.ToString() ); + } + + public override void OnDoubleClick( Mobile from ) + { + bool isStaff = from.AccessLevel != AccessLevel.Player; + + if ( !IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + + else if ( isStaff || from.Skills[ SkillName.AnimalTaming ].Value >= ShrinkConfig.TamingRequired ) + from.Target = new ShrinkTarget( from, this, isStaff ); + else + from.SendMessage( "You must have at least " + ShrinkConfig.TamingRequired + " animal taming to use a pet leash." ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + writer.Write( m_Charges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Charges = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/Xanthos/Shrink System/ReadMe.htm b/Scripts/Customs/Xanthos/Shrink System/ReadMe.htm new file mode 100644 index 0000000..7a80654 --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/ReadMe.htm @@ -0,0 +1,20 @@ + + +

Shrink System version 2.1, by Xanthos

+

Introduction

+

The Shrink System allows pets to be shrunken to small statuettes that can be carried in a player's backpack. Many options are provided to control the system and the properties of the shrunken pets. Two items are provided to allow players to access the shrink function as well as a staff command. Staff may shrink wild animals and other people's pets for safe keeping. The shrink algorithm is fast and simple and works with any pet or pet system.

+

Commands:

+
    +
  • [Shrink
  • +
  • [ShrinkLockDown
  • +
  • [ShrinkRelease
  • +
+

Installation

+

Unzip the Xanthos folder into your customs folder. Copy ShrinkConfig.xml to your RunUO\Data folder if you wish to modify configuration parameters.

+

Requirements

+

Requires the Xanthos Utilities package.

+

Caveats

+

You may use or modify this system in any way you desire, however I ask that you leave the original headers in the source files if you re-write or redistribute the sources in any way.

+

- Xanthos

+ + \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Shrink System/ShrinkCommand.cs b/Scripts/Customs/Xanthos/Shrink System/ShrinkCommand.cs new file mode 100644 index 0000000..17778c4 --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/ShrinkCommand.cs @@ -0,0 +1,167 @@ +#region AuthorHeader +// +// Shrink System version 2.1, by Xanthos +// +// +#endregion AuthorHeader +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Commands; +using Server.Targeting; +using Server.Regions; +using Xanthos.Interfaces; + +namespace Xanthos.ShrinkSystem +{ + public class ShrinkCommands + { + private static bool m_LockDown; // TODO: need to persist this. + + public static void Initialize() + { + CommandHandlers.Register("Shrink", AccessLevel.GameMaster, new CommandEventHandler(Shrink_OnCommand)); + CommandHandlers.Register("ShrinkLockDown", AccessLevel.Administrator, new CommandEventHandler(ShrinkLockDown_OnCommand)); + CommandHandlers.Register("ShrinkRelease", AccessLevel.Administrator, new CommandEventHandler(ShrinkRelease_OnCommand)); + } + + public static bool LockDown + { + get { return m_LockDown; } + } + + [Usage("Shrink")] + [Description("Shrinks a creature.")] + private static void Shrink_OnCommand(CommandEventArgs e) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if (null != from) + from.Target = new ShrinkTarget(from, null, true); + } + + [Usage("ShrinkLockDown")] + [Description("Disables all shrinkitems in the world.")] + private static void ShrinkLockDown_OnCommand(CommandEventArgs e) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if (null != from) + SetLockDown(from, true); + } + + [Usage("ShrinkRelease")] + [Description("Re-enables all disabled shrink items in the world.")] + private static void ShrinkRelease_OnCommand(CommandEventArgs e) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if (null != from) + SetLockDown(from, false); + } + + static private void SetLockDown(Mobile from, bool lockDown) + { + if (m_LockDown = lockDown) + { + World.Broadcast(0x35, true, "A server wide shrinkitem lockout has initiated."); + World.Broadcast(0x35, true, "All shrunken pets have will remain shruken until further notice."); + } + else + { + World.Broadcast(0x35, true, "The server wide shrinkitem lockout has been lifted."); + World.Broadcast(0x35, true, "You may once again unshrink shrunken pets."); + } + } + } + + public class ShrinkTarget : Target + { + private IShrinkTool m_ShrinkTool; + private bool m_StaffCommand; + + public ShrinkTarget(Mobile from, IShrinkTool shrinkTool, bool staffCommand) + : base(10, false, TargetFlags.None) + { + m_ShrinkTool = shrinkTool; + m_StaffCommand = staffCommand; + from.SendMessage("Target the pet you wish to shrink."); + } + + protected override void OnTarget(Mobile from, object target) + { + BaseCreature pet = target as BaseCreature; + + if (target == from) + from.SendMessage("You cannot shrink yourself!"); + + else if (target is Item) + from.SendMessage("You cannot shrink that!"); + + else if (target is PlayerMobile) + from.SendMessage("That person gives you a dirty look!"); + + else if (Server.Spells.SpellHelper.CheckCombat(from)) + from.SendMessage("You cannot shrink your pet while you are fighting."); + + else if (null == pet) + from.SendMessage("That is not a pet!"); + + else if ((pet.BodyValue == 400 || pet.BodyValue == 401) && pet.Controlled == false) + from.SendMessage("That person gives you a dirty look!"); + + else if (pet.IsDeadPet) + from.SendMessage("You cannot shrink the dead!"); + + else if (pet.Summoned) + from.SendMessage("You cannot shrink a summoned creature!"); + + else if (!m_StaffCommand && pet.Combatant != null && pet.InRange(pet.Combatant, 12) && pet.Map == pet.Combatant.Map) + from.SendMessage("Your pet is fighting; you cannot shrink it yet."); + + else if (pet.BodyMod != 0) + from.SendMessage("You cannot shrink your pet while it is polymorphed."); + + else if (!m_StaffCommand && pet.Controlled == false) + from.SendMessage("You cannot not shrink wild creatures."); + + else if (!m_StaffCommand && pet.ControlMaster != from) + from.SendMessage("That is not your pet."); + + else if (!m_StaffCommand && ShrinkItem.IsPackAnimal(pet) && (null != pet.Backpack && pet.Backpack.Items.Count > 0)) + from.SendMessage("You must unload this pet's pack before it can be shrunk."); + + else + { + if (pet.ControlMaster != from && !pet.Controlled) + { + SpawnEntry se = pet.Spawner as SpawnEntry; + if (se != null && se.UnlinkOnTaming) + { + pet.Spawner.Remove((ISpawnable)this); + pet.Spawner = null; + } + + pet.CurrentWayPoint = null; + pet.ControlMaster = from; + pet.Controlled = true; + pet.ControlTarget = null; + pet.ControlOrder = OrderType.Come; + pet.Guild = null; + pet.Delta(MobileDelta.Noto); + } + + IEntity p1 = new Entity(Serial.Zero, new Point3D(from.X, from.Y, from.Z), from.Map); + IEntity p2 = new Entity(Serial.Zero, new Point3D(from.X, from.Y, from.Z + 50), from.Map); + + Effects.SendMovingParticles(p2, p1, ShrinkTable.Lookup(pet), 1, 0, true, false, 0, 3, 1153, 1, 0, EffectLayer.Head, 0x100); + from.PlaySound(492); + from.AddToBackpack(new ShrinkItem(pet)); + + if (!m_StaffCommand && null != m_ShrinkTool && m_ShrinkTool.ShrinkCharges > 0) + m_ShrinkTool.ShrinkCharges--; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Shrink System/ShrinkConfig.cs b/Scripts/Customs/Xanthos/Shrink System/ShrinkConfig.cs new file mode 100644 index 0000000..6bd4827 --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/ShrinkConfig.cs @@ -0,0 +1,100 @@ +#region AuthorHeader +// +// Shrink System version 2.1, by Xanthos +// +// +#endregion AuthorHeader +using System; +using System.IO; +using System.Xml; +using System.Text; +using System.Collections; +using System.Collections.Specialized; +using Xanthos.Utilities; + +namespace Xanthos.ShrinkSystem +{ + // This file is for configuration of the Shrink System. It is advised + // that you DO NOT edit this file, instead place ShrinkConfig.xml in the + // RunUO/Data directory and modify the values there to configure the system + // without changing code. This allows you to take updates to the system + // without losing your specific configuration settings. + + public class ShrinkConfig + { + public enum BlessStatus + { + All, // All shrink items are blessed + BondedOnly, // Only shrink items for bonded pets are blessed + None // No shrink items are blessed + } + + public static bool PetAsStatuette = true; // Deed or statuette form + public static bool AllowLocking = false; // Allow players to lock the shrunken pet or not + public static bool ShowPetDetails = true; // Show stats and skills on the properties of the shrunken pet + public static double ShrunkenWeight = 10.0; + public static bool BlessedLeash = true; + public static BlessStatus LootStatus = BlessStatus.None; // How the shruken pet should be as loot + public static double TamingRequired = 0; // set to zero for no skill requirement to use shrink tools + public static int ShrinkCharges = -1; // set to -1 for infinite uses + + public static Type[] PackAnimals = new Type [] + { + typeof(Server.Mobiles.PackHorse), + typeof(Server.Mobiles.PackLlama), + typeof(Server.Mobiles.Beetle), + }; + + private const string kConfigFile = @"Data/ShrinkConfig.xml"; + private const string kConfigName = "ShrinkSystem"; + + public static void Initialize() + { + Element element = ConfigParser.GetConfig( kConfigFile, kConfigName ); + + if ( null == element || element.ChildElements.Count <= 0 ) + return; + + double tempDouble; + bool tempBool; + int tempInt; + Type[] tempTypeArray; + + foreach( Element child in element.ChildElements ) + { + if ( child.TagName == "PetAsStatuette" && child.GetBoolValue( out tempBool )) + PetAsStatuette = tempBool; + + else if ( child.TagName == "AllowLocking" && child.GetBoolValue( out tempBool )) + AllowLocking = tempBool; + + else if ( child.TagName == "ShowPetDetails" && child.GetBoolValue( out tempBool )) + ShowPetDetails = tempBool; + + else if ( child.TagName == "ShrunkenWeight" && child.GetDoubleValue( out tempDouble )) + ShrunkenWeight = tempDouble; + + else if ( child.TagName == "BlessedLeash" && child.GetBoolValue( out tempBool )) + BlessedLeash = tempBool; + + else if ( child.TagName == "LootStatus" && null != child.Text && "" != child.Text ) + { + if ( "BlessStatus.All" == child.Text ) + LootStatus = BlessStatus.All; + else if ( "BlessStatus.BondedOnly" == child.Text ) + LootStatus = BlessStatus.BondedOnly; + else if ( "BlessStatus.None" == child.Text ) + LootStatus = BlessStatus.None; + } + else if ( child.TagName == "TamingRequired" && child.GetIntValue( out tempInt )) + TamingRequired = tempInt; + + else if ( child.TagName == "ShrinkCharges" && child.GetIntValue( out tempInt )) + ShrinkCharges = tempInt; + + else if ( child.TagName == "PackAnimals" && child.GetArray( out tempTypeArray )) + PackAnimals = tempTypeArray; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Shrink System/ShrinkConfig.xml b/Scripts/Customs/Xanthos/Shrink System/ShrinkConfig.xml new file mode 100644 index 0000000..a2c75a4 --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/ShrinkConfig.xml @@ -0,0 +1,39 @@ + + + + + true + false + true + 10 + false + + + BlessStatus.None + + 0 + 50 + + + Server.Mobiles.PackHorse + Server.Mobiles.PackLlama + Server.Mobiles.Beetle + + + diff --git a/Scripts/Customs/Xanthos/Shrink System/ShrinkItem.cs b/Scripts/Customs/Xanthos/Shrink System/ShrinkItem.cs new file mode 100644 index 0000000..92d9f09 --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/ShrinkItem.cs @@ -0,0 +1,376 @@ +#region AuthorHeader +// +// Shrink System version 2.1, by Xanthos +// +// +#endregion AuthorHeader +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Xanthos.Utilities; +using Xanthos.Interfaces; +using Server.Regions; + +namespace Xanthos.ShrinkSystem +{ + public class ShrinkItem : Item, IShrinkItem + { + // Persisted + private bool m_IsStatuette; + private bool m_Locked; + private Mobile m_Owner; + private BaseCreature m_Pet; + + // Not persisted; lazy loaded. + private bool m_PropsLoaded; + private string m_Breed; + private string m_Gender; + private bool m_IsBonded; + private string m_Name; + private int m_RawStr; + private int m_RawDex; + private int m_RawInt; + private double m_Wrestling; + private double m_Tactics; + private double m_Anatomy; + private double m_Poisoning; + private double m_Magery; + private double m_EvalInt; + private double m_MagicResist; + private double m_Meditation; + private double m_Archery; + private double m_Fencing; + private double m_Macing; + private double m_Swords; + private double m_Parry; + private int m_EvoEp; + private int m_EvoStage; + + private bool m_IgnoreLockDown; // Is only ever changed by staff + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsStatuette + { + get { return m_IsStatuette; } + set + { + if ( null == ShrunkenPet ) + { + ItemID = 0xFAA; + Name = "unlinked shrink item!"; + } + else if ( m_IsStatuette = value ) + { + ItemID = ShrinkTable.Lookup( m_Pet ); + Name = "a shrunken pet"; + } + else + { + ItemID = 0x14EF; + Name = "a pet deed"; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IgnoreLockDown + { + get { return m_IgnoreLockDown; } + set { m_IgnoreLockDown = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Locked + { + get { return m_Locked; } + set { m_Locked = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get { return m_Owner; } + set { m_Owner = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseCreature ShrunkenPet + { + get { return m_Pet; } + set { m_Pet = value; InvalidateProperties(); } + } + + public ShrinkItem() : base() + { + } + + public ShrinkItem( Serial serial ) : base( serial ) + { + } + + public ShrinkItem( BaseCreature pet ) : this() + { + ShrinkPet( pet ); + IsStatuette = ShrinkConfig.PetAsStatuette; + m_IgnoreLockDown = false; // This is only used to allow GMs to bypass the lockdown, one pet at a time. + + // Scriptiz : le poids varie en fonction de la force du pet + Weight = (int)Math.Round(pet.Str / 5.0); //ShrinkConfig.ShrunkenWeight; + + if ( !(m_Pet is IEvoCreature) || ((IEvoCreature)m_Pet).CanHue ) + Hue = m_Pet.Hue; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !m_PropsLoaded ) + PreloadProperties(); + + if ( !IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + + else if ( m_Pet == null || m_Pet.Deleted || ItemID == 0xFAA ) + from.SendMessage( "Due to unforseen circumstances your pet is lost forever." ); + + else if ( m_Locked && m_Owner != from ) + { + from.SendMessage( "This is locked and only the owner can claim this pet while locked." ); + from.SendMessage( "This item is now being returned to its owner." ); + m_Owner.AddToBackpack( this ); + m_Owner.SendMessage( "Your pet {0} has been returned to you because it was locked and {1} was trying to claim it.", m_Breed, from.Name ); + } + else if ( from.Followers + m_Pet.ControlSlots > from.FollowersMax ) + from.SendMessage( "You have to many followers to claim this pet." ); + + else if ( Server.Spells.SpellHelper.CheckCombat( from ) ) + from.SendMessage( "You cannot reclaim your pet while your fighting." ); + + else if ( ShrinkCommands.LockDown == true && !m_IgnoreLockDown ) + from.SendMessage( 54, "The server is on a shrinkitem lockdown. You cannot unshrink your pet at this time." ); + + else if ( !m_Pet.CanBeControlledBy( from )) + from.SendMessage( "You do not have the required skills to control this pet."); + + else + UnshrinkPet( from ); + } + + private void ShrinkPet( BaseCreature pet ) + { + m_Pet = pet; + m_Owner = pet.ControlMaster; + + if ( ShrinkConfig.LootStatus == ShrinkConfig.BlessStatus.All + || ( m_Pet.IsBonded && ShrinkConfig.LootStatus == ShrinkConfig.BlessStatus.BondedOnly )) + LootType = LootType.Blessed; + else + LootType = LootType.Regular; + + m_Pet.Internalize(); + m_Pet.SetControlMaster( null ); + m_Pet.ControlOrder = OrderType.Stay; + m_Pet.SummonMaster = null; + m_Pet.IsStabled = true; + + if ( pet is IEvoCreature ) + ((IEvoCreature)m_Pet).OnShrink( this ); + } + + private void UnshrinkPet( Mobile from ) + { + m_Pet.SetControlMaster( from ); + m_Pet.IsStabled = false; + m_Pet.MoveToWorld( from.Location, from.Map ); + if ( from != m_Owner ) + m_Pet.IsBonded = false; + + m_Pet = null; + this.Delete(); + } + + // Summoning ball was used so dispose of the shrink item + public void OnPetSummoned() + { + m_Pet = null; + Delete(); + } + + public override void Delete() + { + if ( m_Pet != null ) // Don't orphan pets on the internal map + m_Pet.Delete(); + + base.Delete(); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if (( ShrinkConfig.AllowLocking || m_Locked == true ) && from.Alive && m_Owner == from ) + { + if ( m_Locked == false ) + list.Add( new LockShrinkItem( from, this ) ); + else + list.Add( new UnLockShrinkItem( from, this ) ); + } + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( null == m_Pet || m_Pet.Deleted ) + return; + + if ( !m_PropsLoaded ) + PreloadProperties(); + + if ( m_IsBonded && ShrinkConfig.BlessStatus.None == ShrinkConfig.LootStatus ) // Only show bonded when the item is not blessed + list.Add( 1049608 ); + + if ( ShrinkConfig.AllowLocking || m_Locked ) // Only show lock status when locking enabled or already locked + list.Add( 1049644, ( m_Locked == true ) ? "Locked" : "Unlocked" ); + + if ( ShrinkConfig.ShowPetDetails ) + { + list.Add( 1060663, "Name\t{0} Breed: {1} Gender: {2}", m_Name, m_Breed, m_Gender ); + list.Add( 1061640, ( null == m_Owner ) ? "nobody (WILD)" : m_Owner.Name ); // Owner: ~1_OWNER~ + list.Add( 1060659, "Stats\tStrength {0}, Dexterity {1}, Intelligence {2}", m_RawStr, m_RawDex, m_RawInt ); + list.Add( 1060660, "Combat Skills\tWrestling {0}, Tactics {1}, Anatomy {2}, Poisoning {3}", m_Wrestling, m_Tactics, m_Anatomy, m_Poisoning ); + list.Add( 1060661, "Magic Skills\tMagery {0}, Eval Intel {1}, Magic Resist {2}, Meditation {3}", m_Magery, m_EvalInt, m_MagicResist, m_Meditation ); + if ( !( 0 == m_Parry && 0 == m_Archery )) + list.Add( 1060661, "Weapon Skills\tArchery {0}, Fencing {1}, Macing {2}, Parry {3}, Swords {4}", m_Archery, m_Fencing, m_Macing, m_Parry, m_Swords ); + if ( m_EvoEp > 0 ) + list.Add( 1060662, "EP\t{0}, Stage: {1}", m_EvoEp, m_EvoStage + 1 ); + } + else + list.Add( 1060663, "Name\t{0}", m_Name ); + } + + private void PreloadProperties() + { + if ( null == m_Pet ) + return; + + m_IsBonded = m_Pet.IsBonded; + m_Name = m_Pet.Name; + + m_Gender = (m_Pet.Female ? "Female" : "Male"); + m_Breed = Xanthos.Utilities.Misc.GetFriendlyClassName( m_Pet.GetType().Name ); + m_RawStr = m_Pet.RawStr; + m_RawDex = m_Pet.RawDex; + m_RawInt = m_Pet.RawInt; + m_Wrestling = m_Pet.Skills[SkillName.Wrestling].Base; + m_Tactics = m_Pet.Skills[SkillName.Tactics].Base; + m_Anatomy = m_Pet.Skills[SkillName.Anatomy].Base; + m_Poisoning = m_Pet.Skills[SkillName.Poisoning].Base; + m_Magery = m_Pet.Skills[SkillName.Magery].Base; + m_EvalInt = m_Pet.Skills[SkillName.EvalInt].Base; + m_MagicResist = m_Pet.Skills[SkillName.MagicResist].Base; + m_Meditation = m_Pet.Skills[SkillName.Meditation].Base; + m_Parry = m_Pet.Skills[SkillName.Parry].Base; + m_Archery = m_Pet.Skills[SkillName.Archery].Base; + m_Fencing = m_Pet.Skills[SkillName.Fencing].Base; + m_Swords = m_Pet.Skills[SkillName.Swords].Base; + m_Macing = m_Pet.Skills[SkillName.Macing].Base; + + IEvoCreature evo = m_Pet as IEvoCreature; + + if ( null != evo ) + { + m_EvoEp = evo.Ep; + m_EvoStage = evo.Stage; + } + + m_PropsLoaded = true; + } + + public static bool IsPackAnimal( BaseCreature pet ) + { + if ( null == pet || pet.Deleted ) + return false; + + Type breed = pet.GetType(); + + foreach ( Type packBreed in ShrinkConfig.PackAnimals ) + if ( packBreed == breed ) + return true; + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + writer.Write( m_IsStatuette ); + writer.Write( m_Locked ); + writer.Write( (Mobile)m_Owner ); + writer.Write( (Mobile)m_Pet ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + switch ( reader.ReadInt() ) + { + case 0: + { + m_IsStatuette = reader.ReadBool(); + m_Locked = reader.ReadBool(); + m_Owner = (PlayerMobile)reader.ReadMobile(); + m_Pet = (BaseCreature)reader.ReadMobile(); + + if (null != m_Pet ) + m_Pet.IsStabled = true; + + break; + } + } + } + } + + public class LockShrinkItem : ContextMenuEntry + { + private Mobile m_From; + private ShrinkItem m_ShrinkItem; + + public LockShrinkItem( Mobile from, ShrinkItem shrink ) : base( 2029, 5 ) + { + m_From = from; + m_ShrinkItem = shrink; + } + + public override void OnClick() + { + m_ShrinkItem.Locked = true; + m_From.SendMessage( 38, "You have locked this shrunken pet so only you can reclaim it." ); + } + } + + public class UnLockShrinkItem : ContextMenuEntry + { + private Mobile m_From; + private ShrinkItem m_ShrinkItem; + + public UnLockShrinkItem( Mobile from, ShrinkItem shrink ) : base( 2033, 5 ) + { + m_From = from; + m_ShrinkItem = shrink; + } + + public override void OnClick() + { + m_ShrinkItem.Locked = false; + m_From.SendMessage( 38, "You have unlocked this shrunken pet, now anyone can reclaim it as theirs." ); + } + } +} diff --git a/Scripts/Customs/Xanthos/Shrink System/ShrinkPotion.cs b/Scripts/Customs/Xanthos/Shrink System/ShrinkPotion.cs new file mode 100644 index 0000000..63b0ee7 --- /dev/null +++ b/Scripts/Customs/Xanthos/Shrink System/ShrinkPotion.cs @@ -0,0 +1,92 @@ +using Server; +using Server.Items; +using Server.Targeting; +using Xanthos.Interfaces; + +namespace Xanthos.ShrinkSystem +{ + public class ShrinkPotion : Item, IShrinkTool + { + private int m_Charges = 3; + + [CommandProperty(AccessLevel.GameMaster)] + public int ShrinkCharges + { + get { return m_Charges; } + set + { + if (0 == m_Charges || 0 == (m_Charges = value)) + Delete(); + else + InvalidateProperties(); + } + } + + #region Constructors + public ShrinkPotion(Serial serial) + : base(serial) + { + } + + [Constructable] + public ShrinkPotion() + : base(0xF04) + { + Name = "a Shrink potion"; + } + #endregion + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + list.Add(1060658, "Charges\t{0}", m_Charges.ToString()); + } + + public override void OnDoubleClick(Mobile from) + { + if (!Movable) + return; + else if (from.InRange(this.GetWorldLocation(), 2) == false) + { + from.SendLocalizedMessage(500486); //That is too far away. + return; + } + + Container pack = from.Backpack; + + if (!(Parent == from || (pack != null && Parent == pack))) //If not in pack. + { + from.SendLocalizedMessage(1042001); //That must be in your pack to use it. + return; + } + + if (from.Skills[SkillName.AnimalTaming].Value < ShrinkConfig.TamingRequired) + { + from.SendMessage("You must have at least " + ShrinkConfig.TamingRequired + " animal taming to use a hitching post."); + return; + } + + from.Target = new ShrinkTarget(from, this, false); + } + + #region Serialization + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Charges); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Charges = reader.ReadInt(); + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Utilities/ConfigParser.cs b/Scripts/Customs/Xanthos/Utilities/ConfigParser.cs new file mode 100644 index 0000000..5ce96f2 --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/ConfigParser.cs @@ -0,0 +1,485 @@ +#region AuthorHeader +// +// ConfigParser version 1.2 - utilities version 2.0, by Xanthos +// +// Provides for parsing of xml files containing values to be used to set C# variables during +// initialization of a module. This code will throw exceptions if the data does not match +// the expected type or number of elements (in the case of arrays) so that the problem can +// be corrected to avoid potentially catastrophic runtime errors. +// If the config file does not exist or cannot be read it will simply output an error to the +// console and continue. In other words - it's ok not to provide a config file. +// +#endregion AuthorHeader +#undef HALT_ON_ERRORS +using System; +using System.IO; +using System.Xml; +using System.Text; +using System.Collections; +using System.Collections.Specialized; +using Server; + +namespace Xanthos.Utilities +{ + public class ConfigParser + { + public static Element GetConfig( string filename, string tag ) + { + Element element = GetConfig( filename ); + + if ( element != null ) + element = GetConfig( element, tag ); + + return element; + } + + public static Element GetConfig( string filename ) + { + XmlTextReader reader = null; + Element element = null; + DOMParser parser; + + try + { + Console.WriteLine( "Xanthos.Utilities.ConfigParser attempting to load {0}...", filename ); + reader = new XmlTextReader( filename ); + parser = new DOMParser(); + element = parser.Parse( reader ); + Console.WriteLine( "Xanthos.Utilities.ConfigParser success!" ); + + } + catch ( Exception exc ) + { + // Fail gracefully only on errors reading the file + if ( !( exc is System.IO.IOException )) + throw exc; + + Console.WriteLine( "Xanthos.Utilities.ConfigParser failed." ); + } + + if ( null != reader ) + reader.Close(); + + return element; + } + + public static Element GetConfig( Element element, string tag ) + { + if ( element.ChildElements.Count > 0 ) + { + foreach( Element child in element.ChildElements ) + { + if ( child.TagName == tag ) + return child; + } + } + return null; + } + } + + public class DOMParser + { + private Stack m_Elements; + private Element m_CurrentElement; + private Element m_RootElement; + + public DOMParser() + { + m_Elements = new Stack(); + m_CurrentElement = null; + m_RootElement = null; + } + + public Element Parse( XmlTextReader reader ) + { + Element element = null; + + while ( !reader.EOF ) + { + reader.Read(); + switch ( reader.NodeType ) + { + case XmlNodeType.Element : + element = new Element( reader.LocalName ); + m_CurrentElement = element; + if ( m_Elements.Count == 0 ) + { + m_RootElement = element; + m_Elements.Push( element ); + } + else + { + Element parent = (Element)m_Elements.Peek(); + parent.ChildElements.Add( element ); + + if ( reader.IsEmptyElement ) + break; + else + m_Elements.Push( element ); + } + if ( reader.HasAttributes ) + { + while( reader.MoveToNextAttribute() ) + { + m_CurrentElement.setAttribute( reader.Name, reader.Value ); + } + } + break; + case XmlNodeType.Attribute : + element.setAttribute( reader.Name, reader.Value ); + break; + case XmlNodeType.EndElement : + m_Elements.Pop(); + break; + case XmlNodeType.Text : + m_CurrentElement.Text = reader.Value; + break; + case XmlNodeType.CDATA : + m_CurrentElement.Text = reader.Value; + break; + default : + // ignore + break; + } + } + return m_RootElement; + } + } + + public class Elements : CollectionBase + { + public Elements() + { + } + + public void Add( Element element ) + { + List.Add( element ); + } + + public Element this[ int index ] + { + get { return (Element)List[index]; } + } + } + + public class Element + { + private String m_TagName; + private String m_Text; + private StringDictionary m_Attributes; + private Elements m_ChildElements; + + public Element( String tagName ) + { + m_TagName = tagName; + m_Attributes = new StringDictionary(); + m_ChildElements = new Elements(); + m_Text = ""; + } + + public String TagName + { + get { return m_TagName; } + set { m_TagName = value; } + } + + public string Text + { + get { return m_Text; } + set { m_Text = value; } + } + + public Elements ChildElements + { + get { return m_ChildElements; } + } + + public StringDictionary Attributes + { + get { return m_Attributes; } + } + + public String Attribute( String name ) + { + return (String)m_Attributes[name]; + } + + public void setAttribute( String name, String value ) + { + m_Attributes.Add( name, value ); + } + + #region Xml to data type conversions + + public bool GetBoolValue( out bool val ) + { + val = false; + + try + { + if ( null != m_Text && "" != m_Text ) + { + val = bool.Parse( m_Text ); + return true; + } + } + catch ( Exception exc ) { HandleError( exc ); } + + return false; + } + + public bool GetDoubleValue( out double val ) + { + val = 0; + + try + { + if ( null != m_Text && "" != m_Text ) + { + val = double.Parse( m_Text ); + return true; + } + } + catch ( Exception exc ) { HandleError( exc ); } + + return false; + } + + public bool GetIntValue( out int val ) + { + val = 0; + + try + { + if ( null != m_Text && "" != m_Text ) + { + val = Int32.Parse( m_Text ); + return true; + } + } + catch ( Exception exc ) { HandleError( exc ); } + + return false; + } + + public bool GetAccessLevelValue( out AccessLevel val ) + { + val = AccessLevel.Player; + try + { + val = (AccessLevel)AccessLevel.Parse( typeof(Server.AccessLevel), m_Text, true ); + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + public bool GetMapValue( out Map val ) + { + val = null; + try + { + val = Map.Parse( m_Text ); + + if ( null == val ) + throw new ArgumentException( "Map expected" ); + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + public bool GetTypeValue( out Type val ) + { + val = null; + try + { + val = Type.GetType( m_Text ); + + if ( null == val ) + throw new ArgumentException( "Type expected" ); + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + public bool GetPoint3DValue( out Point3D val ) + { + val = new Point3D(); + int elementsExpected = 3; + + try + { + if ( null == ChildElements ) + return false; + + if ( elementsExpected != ChildElements.Count ) + throw new System.IndexOutOfRangeException( elementsExpected + " elements were expected" ); + + int temp; + + if ( ChildElements[ 0 ].GetIntValue( out temp )) + val.X = temp; + else + throw new System.ArrayTypeMismatchException( "Int expected" ); + + if ( ChildElements[ 1 ].GetIntValue( out temp )) + val.Y = temp; + else + throw new System.ArrayTypeMismatchException( "Int expected" ); + + if ( ChildElements[ 2 ].GetIntValue( out temp )) + val.Z = temp; + else + throw new System.ArrayTypeMismatchException( "Int expected" ); + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + + public bool GetArray( out bool[] val ) + { + return GetArray( 0, out val ); + } + + public bool GetArray( int elementsExpected, out bool[] val ) + { + val = null; + + if ( null == ChildElements ) + return false; + + try + { + if ( elementsExpected > 0 && elementsExpected != ChildElements.Count ) + throw new System.IndexOutOfRangeException( elementsExpected + " elements were expected" ); + + bool[] array = new bool[ ChildElements.Count ]; + bool temp; + + for ( int i = 0; i < ChildElements.Count; i++ ) + { + if ( ChildElements[ i ].GetBoolValue( out temp )) + array[ i ] = temp; + else + throw new System.ArrayTypeMismatchException( "Bool expected" ); + } + val = array; + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + public bool GetArray( out int[] val ) + { + return GetArray( 0, out val ); + } + + public bool GetArray( int elementsExpected, out int[] val ) + { + val = null; + + if ( null == ChildElements ) + return false; + + try + { + if ( elementsExpected > 0 && elementsExpected != ChildElements.Count ) + throw new System.IndexOutOfRangeException( elementsExpected + " elements were expected" ); + + int[] array = new int[ ChildElements.Count ]; + int temp; + + for ( int i = 0; i < ChildElements.Count; i++ ) + { + if ( ChildElements[ i ].GetIntValue( out temp )) + array[ i ] = temp; + else + throw new System.ArrayTypeMismatchException( "Int expected" ); + } + val = array; + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + public bool GetArray( out Type[] val ) + { + return GetArray( 0, out val ); + } + + public bool GetArray( int elementsExpected, out Type[] val ) + { + val = null; + + if ( null == ChildElements ) + return false; + + try + { + if ( elementsExpected > 0 && elementsExpected != ChildElements.Count ) + throw new System.IndexOutOfRangeException( elementsExpected + " elements were expected" ); + + Type[] array = new Type[ ChildElements.Count ]; + + for ( int i = 0; i < ChildElements.Count; i++ ) + { + array[ i ] = Type.GetType( ChildElements[ i ].Text ); + } + val = array; + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + public bool GetArray( out string[] val ) + { + return GetArray( 0, out val ); + } + + public bool GetArray( int elementsExpected, out string[] val ) + { + val = null; + + if ( null == ChildElements ) + return false; + + try + { + if ( elementsExpected > 0 && elementsExpected != ChildElements.Count ) + throw new System.IndexOutOfRangeException( elementsExpected + " elements were expected" ); + + string[] array = new string[ ChildElements.Count ]; + + for ( int i = 0; i < ChildElements.Count; i++ ) + { + if ( null != ChildElements[ i ].Text ) + array[ i ] = ChildElements[ i ].Text; + else + throw new System.ArrayTypeMismatchException( "String expected" ); + } + val = array; + } + catch ( Exception exc ) { HandleError( exc ); } + + return true; + } + + #endregion + + private void HandleError( Exception exc ) + { + Console.WriteLine( "\nXanthos.Utilities.ConfigParser error:\n{0}\nElement: <{1}>{2}\n", exc.Message, TagName, Text ); +#if HALT_ON_ERRORS + throw exc; +#endif + } + } +} diff --git a/Scripts/Customs/Xanthos/Utilities/Interfaces.cs b/Scripts/Customs/Xanthos/Utilities/Interfaces.cs new file mode 100644 index 0000000..b089ed9 --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/Interfaces.cs @@ -0,0 +1,58 @@ +#region AuthorHeader +// +// Interfaces version 1.0 - utilities version 2.0, by Xanthos +// +// +#endregion AuthorHeader +using System; +using Server; +using Server.Mobiles; +using Xanthos.Interfaces; + +namespace Xanthos.Interfaces +{ + // + // This interface is implemented by clients of ShrinkTarget allowing the + // ShrinkTarget to adjust the charges of tools without requiring they have the same base class. + // + + public interface IShrinkTool + { + int ShrinkCharges { get; set; } + } + + // + // Used by the auction system to validate the pet referred to by a shrink item. + // + + public interface IShrinkItem + { + BaseCreature ShrunkenPet{ get; } + } + + // + // Allows BaseEvo and BaseEvoMount to be handled without special-casing. + // + + public interface IEvoCreature + { + TimeSpan RemainingTerm { get; } + string Breed { get; } + bool Pregnant { get; set; } + bool HasEgg { get; set; } + bool CanHue { get; } + Type GetEvoDustType(); + int Ep { get; } + int Stage { get; } + void OnShrink( IShrinkItem shrinkItem ); + } + + // + // For simple testing of whether an Evo is a standard evo or a guardian. + // + + public interface IEvoGuardian + { + } + +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Utilities/Misc.cs b/Scripts/Customs/Xanthos/Utilities/Misc.cs new file mode 100644 index 0000000..492954a --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/Misc.cs @@ -0,0 +1,143 @@ +#region AuthorHeader +// +// Misc version 2.0 - utilities version 2.0, by Xanthos +// +// +#endregion AuthorHeader +using System; +using System.Reflection; +using System.Security; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.Commands; + +namespace Xanthos.Utilities +{ + public class Misc + { + /// + /// The hues used for gumps in the systems + /// + public static int kLabelHue = 0x480; + public static int kGreenHue = 0x40; + public static int kRedHue = 0x20; + + public static bool IsArtifact( Item item ) + { + if ( null == item ) + return false; + + Type t = item.GetType(); + PropertyInfo prop = null; + + try { prop = t.GetProperty( "ArtifactRarity" ); } + catch {} + + if ( null == prop || (int)(prop.GetValue( item, null )) <= 0 ) + return false; + + return true; + } + + public static bool IsPlayerConstructed( Item item ) + { + if ( null == item ) + return false; + + Type t = item.GetType(); + PropertyInfo prop = null; + + try { prop = t.GetProperty( "PlayerConstructed" ); } + catch {} + + if ( null == prop || true != (bool)(prop.GetValue( item, null ))) + return false; + + return true; + } + + // + // Puts spaces before type name inner-caps + // + public static string GetFriendlyClassName( string typeName ) + { + for ( int index = 1; index < typeName.Length; index++ ) + { + if ( char.IsUpper( typeName, index ) ) + { + typeName.Insert( index++, " " ); + } + } + + return typeName; + } + + public static object InvokeParameterlessMethod( object target, string method ) + { + object result = null; + + try + { + Type objectType = target.GetType(); + MethodInfo methodInfo = objectType.GetMethod( method ); + + result = methodInfo.Invoke( target, null ); + } + catch ( SecurityException exc ) + { + Console.WriteLine( "SecurityException: " + exc.Message ); + } + return result; + } + + public static void SendCommandDetails( Mobile player, string command ) + { + SendCommandDescription( player, command ); + SendCommandUsage( player, command ); + } + + public static void SendCommandUsage( Mobile player, string command ) + { + string message; + CommandEntry entry = CommandSystem.Entries[ command ]; + + if ( null != entry ) + { + MethodInfo mi = entry.Handler.Method; + + object[] attrs = mi.GetCustomAttributes( typeof( UsageAttribute ), false ); + + UsageAttribute usage = attrs.Length > 0 ? attrs[ 0 ] as UsageAttribute : null; + + message = "Format: " + ( null == usage ? " - no usage" : usage.Usage ); + } + else + message = command + " - unknown command"; + + player.SendMessage( kRedHue, message ); + } + + public static void SendCommandDescription( Mobile player, string command ) + { + string message; + CommandEntry entry = CommandSystem.Entries[ command ]; + + if ( null != entry ) + { + MethodInfo mi = entry.Handler.Method; + + object[] attrs = mi.GetCustomAttributes( typeof( DescriptionAttribute ), false ); + + DescriptionAttribute desc = attrs.Length > 0 ? attrs[ 0 ] as DescriptionAttribute : null; + + message = command + ": " + ( null == desc ? " - no description" : desc.Description ); + } + else + message = command + " - unknown command"; + + player.SendMessage( kRedHue, message ); + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Utilities/Replace.cs b/Scripts/Customs/Xanthos/Utilities/Replace.cs new file mode 100644 index 0000000..38ca1e4 --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/Replace.cs @@ -0,0 +1,223 @@ +#region AuthorHeader +// +// Replace version 1.0 - utilities version 2.0, by Xanthos +// +// +#endregion AuthorHeader +using System; +using System.Collections; +using System.Reflection; +using Server; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using System.IO; +using System.Xml; +using Server.Commands; +using Server.Commands.Generic; + +namespace Xanthos.Utilities +{ + public class PickReplacementTarget : Target + { + private Item m_ItemToReplace; + private bool m_CopyDeep; + + public static void Initialize() + { + CommandHandlers.Register( "ReplaceItem", AccessLevel.GameMaster, new CommandEventHandler( ReplaceItem_OnCommand ) ); +// CommandHandlers.Register( "UpgradeShrinkSystem", AccessLevel.GameMaster, new CommandEventHandler( UpgradeShrinkSystem ) ); + } + + public PickReplacementTarget( object o, bool copyDeep ) : base( -1, false, TargetFlags.None ) + { + m_ItemToReplace = o as Item; + m_CopyDeep = copyDeep; + } + + [Usage( "ReplaceItem [-d]" )] + [Description( "Replaces an item with another copying properties of the replaced to the replacement." )] + private static void ReplaceItem_OnCommand( CommandEventArgs e ) + { + bool copyDeep = false; + + if ( e.Length == 1 && e.GetString( 0 ).Equals( "-d" )) + copyDeep = true; + + e.Mobile.Target = new ReplaceItemTarget( copyDeep ); + e.Mobile.SendMessage( "Choose an Item to replace." ); + } + + [Usage( "UpdateShrinkSystem" )] + [Description( "Updates the Items in the shrink system." )] + public static void UpgradeShrinkSystem( CommandEventArgs e ) + { +// ReplaceType( "Xanthos.ShrinkSystem.PetLeash", "Xanthos.Evo.PetLeash", false ); +// ReplaceType( "Xanthos.ShrinkSystem.HitchingPost", "Xanthos.Evo.HitchingPost", false ); +// ReplaceType( "Xanthos.ShrinkSystem.ShrinkItem", "Xanthos.Evo.ShrinkItem", true ); + } + + protected override void OnTarget( Mobile from, object replacement ) + { + if ( !( replacement is Item )) + from.SendMessage( "You cannot use that as a replacement!" ); + else + ReplaceItem( replacement as Item, m_ItemToReplace, m_CopyDeep ); + } + + private static void CopyPropertiesShallow( Item dest, Item src ) + { + dest.IsLockedDown = src.IsLockedDown; + dest.IsSecure = src.IsSecure; + dest.Movable = src.Movable; + dest.Insured = src.Insured; + dest.LootType = src.LootType; + dest.BlessedFor = src.BlessedFor; + dest.Name = src.Name; + } + + private static void CopyProperties( Item dest, Item src ) + { + PropertyInfo[] props = src.GetType().GetProperties(); + + //Console.WriteLine( "Copying properties..." ); + for ( int i = 0; i < props.Length; i++ ) + { + try + { + if ( props[i].CanRead && props[i].CanWrite ) + { + //Console.WriteLine( "Setting {0} = {1}", props[i].Name, props[i].GetValue( src, null ) ); + props[i].SetValue( dest, props[i].GetValue( src, null ), null ); + } + } + catch + { + Console.WriteLine( "Exception copying properties for {0}", props[i].Name ); + } + } + // Must do this due to a bug in impl of Newbied, which comes after loottype + // in the props list, overwriting loottype. + dest.LootType = src.LootType; + } + + // + // Search through all of the Items for those with Type oldTypeName + // and create Items of newTypeName passing the two Items to ReplaceItem() + // + private static void ReplaceType( string newTypeName, string oldTypeName, bool copyDeep ) + { + Type oldType = null; + Type newType = null; + + try + { + oldType = Type.GetType( oldTypeName ); + newType = Type.GetType( newTypeName ); + } + catch ( Exception e ) + { + Console.WriteLine( "Exception getting types {0}", e.Message ); + } + + if ( oldType == null ) + Console.WriteLine( "No class {0} installed", oldTypeName ); + else if ( newType == null ) + Console.WriteLine( "No class {0} installed", newTypeName ); + else + { + Type[] types = new Type[0]; + ConstructorInfo ci = newType.GetConstructor( types ); + + if ( ci != null ) + { + ArrayList array = new ArrayList(); + + Console.WriteLine( "Looking for {0}s", oldTypeName ); + foreach( Item item in World.Items.Values ) + { + if ( item.GetType() == oldType ) + array.Add( item ); + } + + Console.WriteLine( "Found {0} {1}s - replacing with {2}s", array.Count, oldTypeName, newTypeName ); + + for ( int j = 0; j < array.Count; j++ ) + { + Item item = array[j] as Item; + + if ( item != null && item.GetType() == oldType ) + { + Object obj = ci.Invoke( null ); + + if ( obj == null ) + continue; + + ReplaceItem( (Item)obj, item, copyDeep ); // This does the actual work of replacement + } + } + Console.WriteLine( "Replaced {0} {1} with {2}", array.Count, oldTypeName, newTypeName ); + } + } + } + + // + // Given two Items, copies the properties of the first to the second + // then places the second one where the first is and deletes the first. + // + public static void ReplaceItem( Item replacement, Item itemToReplace, bool copyDeep ) + { + Container pack; + + if ( null != itemToReplace && !itemToReplace.Deleted ) + { + if ( copyDeep ) + CopyProperties( replacement, itemToReplace ); + else + CopyPropertiesShallow( replacement, itemToReplace ); + + if ( itemToReplace.Parent is Container ) + pack = (Container)itemToReplace.Parent; + else if ( itemToReplace.Parent is Mobile ) + pack = ((Mobile)itemToReplace.Parent).Backpack; + else + pack = null; + + replacement.Parent = null; + + if ( pack != null ) + pack.DropItem( replacement ); + else + replacement.MoveToWorld( itemToReplace.Location, itemToReplace.Map ); + + itemToReplace.Delete(); + } + } + } + + public class ReplaceItemTarget : Target + { + bool m_CopyDeep; + + public ReplaceItemTarget( bool copyDeep ) : base( -1, false, TargetFlags.None ) + { + m_CopyDeep = copyDeep; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Item ) + { + from.Target = new PickReplacementTarget( o, m_CopyDeep ); + from.SendMessage( "Choose a replacement." ); + } + else + from.SendMessage( "You cannot replace that!" ); + } + } +} + + + diff --git a/Scripts/Customs/Xanthos/Utilities/findMobs.cs b/Scripts/Customs/Xanthos/Utilities/findMobs.cs new file mode 100644 index 0000000..b44a815 --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/findMobs.cs @@ -0,0 +1,368 @@ +#region AuthorHeader +// +// FindMobs version 1.5 - utilities version 2.0, by Xanthos +// based on the GoByName utility by unknown +// +#endregion AuthorHeaderusing System; +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Accounting; +using Server.Gumps; +using Server.Commands; + +namespace Xanthos.Utilities +{ + public class FindMobsGump : Gump + { + public const string kCommandName = "FindMobs"; + public const int kGumpOffsetX = 30; + public const int kGumpOffsetY = 30; + + public const int kTextHue = 0; + public const int kTextOffsetX = 2; + public const int kButtonWidth = 20; + public const int kOffsetSize = 1; + public const int kEntryHeight = 20; + public const int kBorderSize = 10; + + public const int kOffsetGumpID = 0x0052; // Pure black + public const int kHeaderGumpID = 0x0E14; // Dark navy blue, textured + public const int kEntryGumpID = 0x0BBC; // Light offwhite, textured + public const int kBackGumpID = 0x13BE; // Gray slate/stoney + public const int kButtonGumpID = 0x0E14; // Dark navy blue, textured + + public const int kGoOffsetX = 2; + public const int kGoOffsetY = 2; + public const int kGoButtonID1 = 0x15E1; // Arrow pointing right + public const int kGoButtonID2 = 0x15E5; // " pressed + + public const int kBringOffsetX = 1; + public const int kBringOffsetY = 1; + public const int kBringButtonID1 = 0x15E3; // 'X' Button + public const int kBringButtonID2 = 0x15E7; // " pressed + + public const int kPrevWidth = 20; + public const int kPrevOffsetX = 2; + public const int kPrevOffsetY = 2; + public const int kPrevButtonID1 = 0x15E3; // Arrow pointing left + public const int kPrevButtonID2 = 0x15E7; // " pressed + + public const int kNextWidth = 20; + public const int kNextOffsetX = 2; + public const int kNextOffsetY = 2; + public const int kNextButtonID1 = 0x15E1; // Arrow pointing right + public const int kNextButtonID2 = 0x15E5; // " pressed + + private const int kMiniGumpButtonID = 7107; + private const int kGreenHue = 0x40; + private const int kRedHue = 0x20; + + private const int kPrevLabelOffsetX = kPrevWidth + 1; + private const int kPrevLabelOffsetY = 0; + + private const int kNextLabelOffsetX = -29; + private const int kNextLabelOffsetY = 0; + + private const int kEntryWidth = 500; + private const int kEntryCount = 15; + + private const int kTotalWidth = kOffsetSize + kEntryWidth + kOffsetSize + (kButtonWidth * 2) + kOffsetSize; + private const int kTotalHeight = kOffsetSize + ((kEntryHeight + kOffsetSize) * (kEntryCount + 2)); + + private const int kBackWidth = kBorderSize + kTotalWidth + kBorderSize; + private const int kBackHeight = kBorderSize + kTotalHeight + kBorderSize; + + private static bool s_PrevLabel = false; + private static bool s_NextLabel = false; + + private string m_SearchValue; + private int m_Options; + private Mobile m_Owner; + private ArrayList m_Names; + private int m_Page; + private string m_Args; + private bool m_MiniGump; + + public static void Initialize() + { + CommandSystem.Register( kCommandName, AccessLevel.GameMaster, new CommandEventHandler( Find_OnCommand ) ); + } + + [Usage( kCommandName + " [-i] [-p|-t] " )] + [Description( "Finds all mobiles by name, -p for players, -t searches by mobiles type name, -i specifies the internal map" )] + private static void Find_OnCommand( CommandEventArgs e ) + { + string str; + + try + { + int options = GetOptions( e, out str ); + e.Mobile.SendGump( new FindMobsGump( e.Mobile, str, options ) ); + } + catch + { + Misc.SendCommandDetails( e.Mobile, kCommandName ); + } + } + + public enum FindOptions + { + None = 0x00, + Player = 0x01, + Internal = 0x02, + Type = 0x04, + } + + private static int GetOptions( CommandEventArgs e, out string searchValue ) + { + int options = (int)FindOptions.None; + + searchValue = ""; + + for ( int i = 0; i < e.Length; i++ ) + { + string str = e.GetString( i ).ToLower(); + + if ( str.Equals( "-?" ) ) + throw new Exception(); + + else if ( str.Equals( "-i" ) ) + options |= (int)FindOptions.Internal; + + else if ( str.Equals( "-p" ) ) + { + options |= (int)FindOptions.Player; + options &= ~( (int)FindOptions.Type ); // mutually exclusive, turn off the bit + } + else if ( str.Equals( "-t" ) ) + { + options |= (int)FindOptions.Type; + options &= ~( (int)FindOptions.Player ); // mutually exclusive, turn off the bit + } + else + searchValue = str; + } + + return options; + } + + public FindMobsGump( Mobile owner, string searchValue, int options ) : this( owner, BuildList( owner, searchValue, options ), 0, searchValue, options, false ) + { + m_SearchValue = searchValue; + m_Options = options; + m_MiniGump = false; + GenerateArgString(); + } + + public FindMobsGump( Mobile owner, ArrayList list, int page, string searchValue, int options, bool miniGump ) : base( kGumpOffsetX, kGumpOffsetY ) + { + m_Owner = owner; + m_Names = list; + m_SearchValue = searchValue; + m_Options = options; + m_MiniGump = miniGump; + owner.CloseGump( typeof( FindMobsGump ) ); + GenerateArgString(); + Initialize( page ); + } + + public static ArrayList BuildList( Mobile owner, string searchValue, int options ) + { + ArrayList list = new ArrayList(); + + bool searchInternal = ((options & (int)FindOptions.Internal) == (int)FindOptions.Internal); + bool findPlayers = ((options & (int)FindOptions.Player) == (int)FindOptions.Player); + bool findTypes = ((options & (int)FindOptions.Type) == (int)FindOptions.Type); + + foreach ( Mobile mob in World.Mobiles.Values ) + { + if ( searchInternal != (Map.Internal == mob.Map) ) + continue; + else if ( findPlayers && !(mob is PlayerMobile) ) + continue; + + if ( findTypes && searchValue != "" && mob.GetType().Name.ToLower().StartsWith( searchValue ) ) + list.Add( mob ); + if ( !findTypes && (searchValue == "" || mob.Name.ToLower().StartsWith( searchValue )) ) + list.Add( mob ); + } + return list; + } + + private void GenerateArgString() + { + bool m_SearchInternal = ( ( m_Options & (int)FindOptions.Internal ) == (int)FindOptions.Internal ); + bool m_FindPlayers = ( ( m_Options & (int)FindOptions.Player ) == (int)FindOptions.Player ); + bool m_FindTypes = ( ( m_Options & (int)FindOptions.Type ) == (int)FindOptions.Type ); + + if ( m_SearchValue == "" ) + m_Args = "all "; + + m_Args += m_FindPlayers ? "players" : "mobiles"; + m_Args += m_SearchInternal ? " (internal)" : ""; + + if ( m_SearchValue != "" ) + { + m_Args += m_FindTypes ? " of type " : " named "; + m_Args += m_SearchValue; + } + } + + public void Initialize( int page ) + { + m_Page = page; + + int count = m_Names.Count - ( page * kEntryCount ); + + if ( count < 0 ) + count = 0; + else if ( count > kEntryCount ) + count = kEntryCount; + + if ( m_MiniGump ) + { + AddPage( 0 ); + AddBackground( 0, 0, 40, 40, kBackGumpID ); + AddItem( 10, 10, kMiniGumpButtonID, kGreenHue ); + } + else + { + int kTotalHeight = kOffsetSize + ( ( kEntryHeight + kOffsetSize ) * ( count + 2 ) ); + int x = kBorderSize + kOffsetSize; + int y = kBorderSize + kOffsetSize; + int emptyWidth = kEntryWidth; + + AddPage( 0 ); + + AddBackground( 0, 0, kBackWidth, kBorderSize + kTotalHeight + kBorderSize, kBackGumpID ); + AddImageTiled( kBorderSize, kBorderSize, kTotalWidth, kTotalHeight, kOffsetGumpID ); + AddImageTiled( x, y, emptyWidth, kEntryHeight, kEntryGumpID ); + AddLabel( x + kTextOffsetX, y, kTextHue, string.Format( "Page {0} of {1} ({2}) - Matches for: {3}", page + 1, ( m_Names.Count + kEntryCount - 1 ) / kEntryCount, m_Names.Count, m_Args ) ); + + x += emptyWidth + kOffsetSize; + + AddImageTiled( x, y, kPrevWidth, kEntryHeight, kHeaderGumpID ); + + if ( page > 0 ) + { + AddButton( x + kPrevOffsetX, y + kPrevOffsetY, kPrevButtonID1, kPrevButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( s_PrevLabel ) + AddLabel( x + kPrevLabelOffsetX, y + kPrevLabelOffsetY, kTextHue, "Previous" ); + } + + x += kPrevWidth + kOffsetSize; + + AddImageTiled( x, y, kNextWidth, kEntryHeight, kHeaderGumpID ); + + if ( ( page + 1 ) * kEntryCount < m_Names.Count ) + { + AddButton( x + kNextOffsetX, y + kNextOffsetY, kNextButtonID1, kNextButtonID2, 2, GumpButtonType.Reply, 1 ); + + if ( s_NextLabel ) + AddLabel( x + kNextLabelOffsetX, y + kNextLabelOffsetY, kTextHue, "Next" ); + } + + for ( int i = 0, index = page * kEntryCount; i < kEntryCount && index < m_Names.Count; ++i, ++index ) + { + x = kBorderSize + kOffsetSize; + y += kEntryHeight + kOffsetSize; + + Mobile item = (Mobile)m_Names[ index ]; + + AddImageTiled( x, y, kEntryWidth, kEntryHeight, kEntryGumpID ); + AddLabelCropped( x + kTextOffsetX, y, kEntryWidth - kTextOffsetX, kEntryHeight, 0x58, + item.Deleted ? "(deleted)" : ( string.Format( "{0} : {1} : {2} {3}", item.Name, item is PlayerMobile ? ( (Account)item.Account ).Username : "Null", item.Map, item.Location ) ) ); + + if ( !item.Deleted ) + { + x += kEntryWidth + kOffsetSize; + AddImageTiled( x, y, kButtonWidth, kEntryHeight, kButtonGumpID ); + AddButton( x + kBringOffsetX, y + kBringOffsetY, kBringButtonID1, kBringButtonID2, i + 4, GumpButtonType.Reply, 0 ); + + x += kButtonWidth + kOffsetSize; + AddImageTiled( x, y, kButtonWidth, kEntryHeight, kButtonGumpID ); + AddButton( x + kGoOffsetX, y + kGoOffsetY, kGoButtonID1, kGoButtonID2, i + 1004, GumpButtonType.Reply, 0 ); + } + } +// AddItem( kBackWidth - 55, ((kEntryHeight + kOffsetSize) * (count + 1)) + 15, kMiniGumpButtonID, kRedHue ); +// AddButton( kBackWidth - 55, ( ( kEntryHeight + kOffsetSize ) * ( count + 1 ) ) + 15, 0, 0, 3, GumpButtonType.Reply, 0 ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // Close + { + return; + } + case 1: // Previous + { + if ( m_Page > 0 ) + from.SendGump( new FindMobsGump( from, m_Names, m_Page - 1, m_SearchValue, m_Options, false ) ); + + break; + } + case 2: // Next + { + if ( ( m_Page + 1 ) * kEntryCount < m_Names.Count ) + from.SendGump( new FindMobsGump( from, m_Names, m_Page + 1, m_SearchValue, m_Options, false ) ); + + break; + } + case 3: // MiniGump toggle + { + from.SendGump( new FindMobsGump( from, m_Names, m_Page, m_SearchValue, m_Options, !m_MiniGump ) ); + break; + } + default: + { + int index = (m_Page * kEntryCount) + (info.ButtonID - 4); + bool bringing = index < 1000; + if ( !bringing ) + index -= 1000; + + if ( index >= 0 && index < m_Names.Count ) + { + Mobile sought = (Mobile)m_Names[index]; + + if ( sought.Deleted ) + { + from.SendMessage( "That mobile no longer exists." ); + from.SendGump( new FindMobsGump( from, m_Names, m_Page, m_SearchValue, m_Options, false ) ); + } + else if ( bringing ) + { + from.SendMessage( "Bringing {0} to you.", sought.Name ); + sought.Map = from.Map; + sought.SetLocation( from.Location, true ); + from.SendGump( new FindMobsGump( from, m_Names, m_Page, m_SearchValue, m_Options, false ) ); + } + else + { + from.SendMessage( "Going to {0}.", sought.Name ); + if ( sought.Map == Map.Internal) + { + from.Map = sought.LogoutMap; + } + else + { + from.Map = sought.Map; + } + from.SetLocation( sought.Location, true ); + from.SendGump( new FindMobsGump( from, m_Names, m_Page, m_SearchValue, m_Options, false ) ); + } + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Utilities/motd.cs b/Scripts/Customs/Xanthos/Utilities/motd.cs new file mode 100644 index 0000000..aec1779 --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/motd.cs @@ -0,0 +1,513 @@ +#region AuthorHeader +// +// Motd.cs version 2.0, by Xanthos +// +// This is a RunUO assembly to display a message of the day (motd) gump +// at login. It supports archiving and display of previous motd content. +// You may use this code as you please as long as you leave this AuthorHeader +// in place. +// +#endregion AuthorHeader +#region Header +// +// Using this is pretty simple. Place this file in your custom directory. +// It will create a Motd subdirectory in your data directory and an Archive +// directory beneath that. Place a file named motd.txt in the Motd sub- +// directory, enter the game as an admin and type [motd. Select the reload +// button and all players will see the new motd on login. Once the motd is +// presented to a player, their account is tagged so they will not see it +// again on login unless the Reload button is used as described above. +// Players may, at any time, see the motd by typing motd. The Reload +// option allows an admin to make small changes to the motd and then get +// them brought into the motd cache without a restart of the server. +// +// The [motd admin command also allows archiving of the current motd.txt +// into the Archive directory and replacing the existing motd file with one +// named new.txt. This action will also tag all accounts so that the motd +// will be displayed at login. The archives are given names in sequence +// starting at 1.txt. The current motd, when archived is always given the +// name 1.txt after any older files are propagated to higher numbered names. +// By default, a maximum of nine archives will be shown in the gump. The +// number of archives maintained in the Archive directory is limited only +// by the file system. Archiving may take longer as the number of files +// increases however. If an motd.txt file is not present when the Reload +// or Archive functions are used, all accounts are tagged so that the motd +// will not be displayed. +// +// There are a number of static variables that can be used to customize +// aspects of this program. In most cases no modifications are needed. +// +// This work was done by Xanthos, based on code written by Viago and others, +// see the credits page for more details. +// - Xanthos. +// +// editor tabs = 4 +// +#endregion Header +using System; +using System.IO; +using System.Text; +using System.Threading; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Accounting; +using Server.Commands; + +namespace Xanthos.Utilities +{ + public class NewsGump : Gump + { + // Modify these constants to suit your needs + private const string kNewFile = "new"; + private const string kMotdFile = "motd"; + private const string kFileSuffix = ".txt"; + private const string kPathMotd = "Data/Motd/"; + private const string kPathArchive = kPathMotd + "Archive/"; + private const string kGreeting = "Greetings And Welcome To ShardName"; + private const string kDefaultBody = "There is no current news."; + private const string kDefaultTitle = "Current News"; + private const string kNewMotdMessage= "The message of the day has been updated. To see it, type motd."; + private static int kMaximumArchives = 9; // should be const, used static to get avoid compiler warning + private static bool kAlwaysShowMotdOnLogin = false;// should be const, used static to get avoid compiler warning + private static bool kTextInsteadOfGumpOnLogin = true; // should be const, used static to get avoid compiler warning + + internal const int kDataColor = 50; + internal const int kLabelColor = 88; + internal const string kLabelHtmlColor = "66CCFF"; + + //----- Edting below this line is not recommended ----- + + #region Static Methods + + private static volatile string [] s_ArchiveFilenameCache; + private static volatile string s_MotdCache; + private static volatile Mutex s_Mutex = new Mutex(); + + public static void Initialize() + { + try + { + // Make sure we have a message store + if ( !Directory.Exists( kPathArchive ) ) + Directory.CreateDirectory( kPathArchive ); + + LoadMotd(); + } + catch + { + World.Broadcast( kLabelColor, true, "Motd: no motd file found"); + } + + try { GetArchiveList(); } + catch { World.Broadcast( kLabelColor, true, "Motd: no archive files found"); } + + EventSink.Login += new LoginEventHandler( MOTD_Login ); + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + CommandHandlers.Register( "MOTD", AccessLevel.Administrator, new CommandEventHandler( MOTD_OnCommand ) ); + } + + private static bool LoadMotd() // Not thread safe, call only from a locked block + { + string Filename = kPathMotd + kMotdFile + kFileSuffix; + string str = ""; + + try + { + StreamReader reader = new StreamReader( Filename ); + str = reader.ReadToEnd(); + reader.Close(); + } + finally + { + s_MotdCache = ( str == "" ? kDefaultBody : str ); + } + + return !( s_MotdCache == kDefaultBody ); + } + + private static void ArchiveMotd( PlayerMobile mobile ) // Not thread safe, call only from a locked block + { + string [] list = Directory.GetFiles( kPathArchive, "*" + kFileSuffix ); + int totalFiles = list.Length; + string source; + + // Rename all files to make room for the new #1 + for ( int i = totalFiles, j = i + 1; i > 0; i--, j-- ) + { + if ( File.Exists( source = kPathArchive + i + kFileSuffix ) ) + File.Move( source, kPathArchive + j + kFileSuffix ); + } + + // Copy the motd file to the #1 slot in the archive, and replace old motd with the new motd file + if ( File.Exists( source = kPathMotd + kMotdFile + kFileSuffix ) ) + File.Move( source, kPathArchive + "1" + kFileSuffix ); + + if ( File.Exists( source = kPathMotd + kNewFile + kFileSuffix ) ) + File.Move( kPathMotd + kNewFile + kFileSuffix, kPathMotd + kMotdFile + kFileSuffix ); + } + + private static void GetArchiveList() // Not thread safe, call only from a locked block + { + s_ArchiveFilenameCache = null; + + // This method may be set to not get all of the files so don't use when archiving. + // One of these will be unreachable - I chose to live with it rather than use defines. + // Also Directory.GetFiles has really poor regular expression support + // so this is about the best you can do without more work. + + if ( kMaximumArchives < 10 ) + s_ArchiveFilenameCache = Directory.GetFiles( kPathArchive, "?" + kFileSuffix ); + else + s_ArchiveFilenameCache = Directory.GetFiles( kPathArchive, "*" + kFileSuffix ); + } + + // + // All thread unsafe methods are bottlenecked in the next three methods. + // + + private static void PreformArchive( PlayerMobile mobile ) + { + bool showMotd; + + s_Mutex.WaitOne(); + try + { + ArchiveMotd( mobile ); + showMotd = LoadMotd(); + GetArchiveList( ); + } + catch (Exception exc) + { + s_Mutex.ReleaseMutex(); + throw exc; + } + s_Mutex.ReleaseMutex(); + SetAllTags( mobile, showMotd ); // no need to block for this + } + + private static void PerformReload( PlayerMobile mobile ) + { + bool showMotd; + + s_Mutex.WaitOne(); + try + { + showMotd = LoadMotd(); + GetArchiveList( ); + } + catch (Exception exc) + { + s_Mutex.ReleaseMutex(); + throw exc; + } + s_Mutex.ReleaseMutex(); + SetAllTags( mobile, showMotd ); // no need to block for this + } + + internal static void SafelySendGumpTo( Mobile mobile, bool admin ) + { + NewsGump gump; + + s_Mutex.WaitOne(); + try + { + int length = s_ArchiveFilenameCache.Length >= kMaximumArchives + ? kMaximumArchives : s_ArchiveFilenameCache.Length; + + // Get the caches copied onto the stack of the gump thread. + gump = new NewsGump( mobile, s_MotdCache, s_ArchiveFilenameCache, length, admin ); + } + finally + { + s_Mutex.ReleaseMutex(); + } + + gump.DrawGump( mobile, admin ); + mobile.SendGump( gump ); + ((Account)(((PlayerMobile)mobile).Account)).SetTag( "motd", "false" ); + } + + private static void SetAllTags( Mobile from, bool toTrue ) + { + if ( kAlwaysShowMotdOnLogin ) // No need to tag if we are always showing + return; + + string boolValue = toTrue.ToString(); + Account account; + + foreach ( Mobile mobile in World.Mobiles.Values ) + { + if ( null == mobile || !( mobile is PlayerMobile ) ) + continue; + + if( null == ( account = (Account)from.Account ) ) + continue; + + account.SetTag( "motd", boolValue ); + } + from.SendMessage( kLabelColor, "All players" + ( true == toTrue ? " will " : " will not ") + "see the MOTD Message at next login." ); + } + + #region In-game commands and events + + [Usage( "MOTD" )] + [Description( "Show MOTD admin menu." )] + private static void MOTD_OnCommand( CommandEventArgs args ) + { + Mobile mobile = args.Mobile; + mobile.CloseGump( typeof(NewsGump) ); + SafelySendGumpTo( mobile, true ); + } + + private static void EventSink_Speech( SpeechEventArgs args ) + { + Mobile mobile = args.Mobile; + if ( args.Speech.ToLower().IndexOf( "motd" ) >= 0 ) + { + SafelySendGumpTo( mobile, false ); + } + } + + private static void MOTD_Login( LoginEventArgs args ) + { + Mobile mobile = args.Mobile; + Account account = (Account)mobile.Account; + + if ( kAlwaysShowMotdOnLogin || Convert.ToBoolean( account.GetTag( "motd" ) ) ) + { + // One of these will be unreachable - I chose to live with it rather than use defines. + if ( kTextInsteadOfGumpOnLogin ) + mobile.SendMessage( kLabelColor, kNewMotdMessage ); + else + SafelySendGumpTo( mobile, false ); + } + } + + #endregion In-game commands and events + #endregion Static Methods + #region News Gump Methods + + private PlayerMobile m_Player; + private string m_UserCount; + private string m_ItemCount; + private string m_MobileCount; + private string m_Body; + private string [] m_ArchiveList; + private int m_TotalPages; + private int m_ArchiveCount; + private int m_ArchivesLoaded; + + private string LoadNextArchive() + { + string Filename; + string text = ""; + + if ( m_ArchiveList != null && m_ArchivesLoaded < m_ArchiveCount + && (( Filename = m_ArchiveList[ m_ArchivesLoaded ].ToString() ) != null ) + && File.Exists( Filename ) ) + { + StreamReader reader = new StreamReader( Filename ); + + text = reader.ReadToEnd(); + reader.Close(); + + m_ArchivesLoaded++; + } + return text == "" ? kDefaultBody : text; + } + + private NewsGump( Mobile mobile, string body, string [] archiveList, int archiveCount, bool admin ) : base( 100, 100 ) + { + mobile.CloseGump( typeof(NewsGump) ); + m_Body = body; + m_Player = (PlayerMobile)mobile; + m_UserCount = NetState.Instances.Count.ToString(); + m_ItemCount = World.Items.Count.ToString(); + m_MobileCount = World.Mobiles.Count.ToString(); + m_ArchiveList = archiveList; + m_ArchiveCount = ( null == archiveList ? 0 : archiveCount ); + m_ArchivesLoaded = 0; + m_TotalPages = 0; + } + + private void DrawGump( Mobile mobile, bool admin ) + { + if ( admin ) + { + int colOne = 10; + int colTwo = colOne + 35; + int rowOne = 10; + int rowHeight = 25; + int row = rowOne; + + AddPage( 1 ); + AddBackground( 0, 0, 205, 180, 5054 ); + AddButton( colOne, rowOne, 0xFB7, 0xFB9, 100, GumpButtonType.Reply, 0 ); // Archive + AddLabel( colTwo, rowOne, kLabelColor, "Archive motd File" ); + AddButton( colOne, (row += rowHeight), 0xFB7, 0xFB9, 101, GumpButtonType.Reply, 0 ); // Reload + AddLabel( colTwo, row, kLabelColor, "Reload motd File" ); + AddButton( colOne, (row += rowHeight + 10), 0xFB7, 0xFB9, 0, GumpButtonType.Reply, 0 ); // Cancel + AddLabel( colTwo, row, kLabelColor, "Cancel" ); + AddLabel( colOne, (row += rowHeight + 10), kDataColor, "Warning, admins have both" ); + AddLabel( colOne, (row += rowHeight - 10), kDataColor, "the [motd and motd commands." ); + AddLabel( colOne, (row += rowHeight - 10), kDataColor, "Press Cancel unless you know" ); + AddLabel( colOne, (row += rowHeight - 10), kDataColor, "what these options do." ); + } + else + { + AddNewPage( m_Body ); + + while ( m_ArchivesLoaded < m_ArchiveCount ) + { + AddNewPage( LoadNextArchive() ); + } + } + } + + private void AddNewPage( string bodyText ) + { + AddPage( ++m_TotalPages ); + + AddBackground( 50, 0, 514, 280, 9270 ); + AddBackground( 50, 80, 514, 400, 9270 ); + + AddLabel( 170, 15, kDataColor, kGreeting ); + AddLabel( 80, 33, kDataColor, m_Player.Name ); + AddLabel( 205, 33, kLabelColor, "Online Users" ); + AddLabel( 205, 47, kDataColor, m_UserCount ); + AddLabel( 315, 33, kLabelColor, "Total Items" ); + AddLabel( 315, 47, kDataColor, m_ItemCount ); + AddLabel( 425, 33, kLabelColor, "Total Mobiles" ); + AddLabel( 425, 47, kDataColor, m_MobileCount); + + AddHtml( 65, 95, 485, 25, CenterAndColor( 1 == m_TotalPages ? kDefaultTitle : "Previous News" ), false, false ); + AddHtml( 65, 120, 485, 330, bodyText, true, true ); + AddHtml( 65, 450, 485, 25, CenterAndColor( "Page " + ( m_TotalPages ) + " of " + ( m_ArchiveCount + 1 ) ), false, false ); + + AddButton( 525, 15, 25, 26, 102, GumpButtonType.Reply, 0 ); // Close button + AddButton( 60, 55, 5522, 5523, 103, GumpButtonType.Reply, 0 ); // Account button + AddButton( 65, 12, 22153, 22154, 104, GumpButtonType.Reply, 0 );// About button + AddButton( 500, 95, 5537, 5538, 0, GumpButtonType.Page, m_TotalPages - 1 ); // Navigation left button + AddButton( 525, 95, 5540, 5541, 0, GumpButtonType.Page, m_TotalPages + 1 ); // Navigation right button + } + + private static string CenterAndColor( string text ) + { + return String.Format( "
{0}
", text ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + switch ( info.ButtonID ) + { + case 100: // Archive + try + { + PreformArchive( (PlayerMobile)from ); + SafelySendGumpTo( from, false ); + World.Broadcast( kLabelColor, true, kNewMotdMessage ); + } + catch (Exception exc) { from.SendMessage( kLabelColor, "Archive: exception encountered - " + exc.Message); } + break; + case 101: // Reload + try + { + PerformReload( (PlayerMobile)from ); + SafelySendGumpTo( from, false ); + World.Broadcast( kLabelColor, true, kNewMotdMessage ); + } + catch (Exception exc) { from.SendMessage( kLabelColor, "Archive: exception encountered - " + exc.Message); } + break; + case 102: // Close Account Gump + from.CloseGump( typeof(AccountGump) ); + break; + case 103: // Account Gump + from.SendGump( new AccountGump( from, sender, false ) ); + break; + case 104: // Credits + from.SendGump( new AccountGump( from, sender, true ) ); + break; + case 105: // Motd from credits only page - $$$ not tested, may not work + from.CloseGump( typeof(AccountGump) ); + SafelySendGumpTo( from, false ); + break; + } + } + + #endregion News Gump Methods + #region AccountGump + + internal class AccountGump : Gump + { + public AccountGump( Mobile from, NetState state, bool showOnlyCredits ) : base( 30, 20 ) + { + if ( null == state ) + return; + + PlayerMobile mobile = (PlayerMobile)from; + + AddPage( 1 ); + + if ( !showOnlyCredits ) + { + AddBackground( 50, 0, 479, 309, 9270 ); + AddImage( 0, 0, 10400 ); + AddImage( 0, 225, 10402 ); + AddImage( 495, 0, 10410 ); + AddImage( 495, 225, 10412 ); + AddImage( 60, 15, 5536 ); + AddImage( 275, 15, 1025 ); + AddLabel( 205, 43, NewsGump.kLabelColor, "Account Name" ); + AddLabel( 205, 57, 0x480, mobile.Account.ToString() ); + AddLabel( 205, 80, NewsGump.kLabelColor, "Account Password" ); + AddLabel( 205, 98, NewsGump.kDataColor, "-(Protected)-" ); + AddLabel( 355, 43, NewsGump.kLabelColor, "Online Character" ); + AddLabel( 355, 57, NewsGump.kDataColor, mobile.Name ); + AddLabel( 355, 80, NewsGump.kLabelColor, "Character Age" ); + AddLabel( 355, 100, NewsGump.kDataColor, mobile.GameTime.Days.ToString() + " Days" ); + AddLabel( 355, 115, NewsGump.kDataColor, mobile.GameTime.Hours.ToString() + " Hours" ); + AddLabel( 355, 130, NewsGump.kDataColor, mobile.GameTime.Minutes.ToString() + " Minutes" ); + AddLabel( 355, 144, NewsGump.kDataColor, mobile.GameTime.Seconds.ToString() + " Seconds" ); + AddLabel( 205, 120, NewsGump.kLabelColor, "Account Access Level" ); + AddLabel( 205, 135, NewsGump.kDataColor, from.AccessLevel.ToString() ); + AddButton( 470, 15, 25, 26, 0, GumpButtonType.Reply, 0 ); // Close + AddLabel( 355, 165, NewsGump.kLabelColor, "IP Address" ); + AddLabel( 355, 180, NewsGump.kDataColor, state.ToString()); + AddLabel( 205, 165, NewsGump.kLabelColor, "Client Version" ); + //AddLabel( 205, 180, NewsGump.kDataColor, (( state.Flags & 0x10 ) != 0 ) ? "Samurai Empire" : (( state.Flags & 0x08 ) != 0) ? "Age of Shadows" : (( state.Flags & 0x04 ) != 0) ? "Blackthorn's Revenge" : (( state.Flags & 0x02 ) != 0 ) ? "Third Dawn" : (( state.Flags & 0x01 ) != 0 ) ? "Renaissance" : "The Second Age" ); + AddLabel(205, 180, NewsGump.kDataColor, "Not supported"); // Scriptiz : bug ! + AddLabel( 205, 200, NewsGump.kLabelColor, "Client Patch" ); + AddLabel( 205, 215, NewsGump.kDataColor, null == state.Version ? "(null)" : state.Version.ToString() ); + AddButton( 445, 15, 22153, 22154, 0, GumpButtonType.Page, 2 ); // About + + AddPage( 2 ); + } + + // Credits page + AddBackground( 50, 0, 479, 309, 9270 ); + AddImage( 0, 0, 10400 ); + AddImage( 0, 225, 10402 ); + AddImage( 495, 0, 10410 ); + AddImage( 495, 225, 10412 ); + AddImage( 60, 15, 5536 ); + AddLabel( 205, 45, NewsGump.kLabelColor, "Code By" ); + AddLabel( 205, 60, NewsGump.kDataColor, "Xanthos" ); + AddLabel( 205, 80, NewsGump.kLabelColor, "Inspiration By" ); + AddLabel( 205, 95, NewsGump.kDataColor, "Princess Monika" ); + AddLabel( 205, 110, NewsGump.kLabelColor, "Gumps By" ); + AddLabel( 205, 125, NewsGump.kDataColor, "Viago" ); + AddLabel( 355, 45, NewsGump.kLabelColor, "Credit To" ); + AddLabel( 355, 60, NewsGump.kDataColor, "Xuse" ); + AddLabel( 355, 75, NewsGump.kDataColor, "The RunUO Comunity" ); + AddLabel( 355, 90, NewsGump.kDataColor, "Lady Rouge" ); + AddLabel( 355, 105, NewsGump.kDataColor, "RoninGT" ); + AddButton( 470, 15, 25, 26, 0, GumpButtonType.Reply, 0 ); // Close + } + #endregion AccountGump + } + } +} \ No newline at end of file diff --git a/Scripts/Customs/Xanthos/Utilities/wipemobs.cs b/Scripts/Customs/Xanthos/Utilities/wipemobs.cs new file mode 100644 index 0000000..08570f9 --- /dev/null +++ b/Scripts/Customs/Xanthos/Utilities/wipemobs.cs @@ -0,0 +1,367 @@ +#region AuthorHeader +// +// wipemobs version 1.1 - utilities version 2.0, by Xanthos +// +// +#endregion AuthorHeader +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Accounting; +using Server.Commands; + +namespace Xanthos.Utilities +{ + public class WipeMobsGump : Gump + { + public const string kCommandName = "WipeMobs"; + + public static void Initialize() + { + CommandHandlers.Register( kCommandName, AccessLevel.Administrator, new CommandEventHandler( WipeMobs_OnCommand ) ); + } + public static string m_args; + [Usage( kCommandName + " " )] + [Description( "Finds and wipes mobiles by name" )] + private static void WipeMobs_OnCommand( CommandEventArgs e ) + { + m_args = e.ArgString; + + if ( 1 != e.Length ) + Misc.SendCommandDetails( e.Mobile, kCommandName ); + else + e.Mobile.SendGump( new WipeMobsGump( e.Mobile, e.ArgString ) ); + } + public const int GumpOffsetX = 30; + public const int GumpOffsetY = 30; + + public const int TextHue = 0; + public const int TextOffsetX = 2; + + public const int OffsetGumpID = 0x0052; // Pure black + public const int HeaderGumpID = 0x0E14; // Dark navy blue, textured + public const int EntryGumpID = 0x0BBC; // Light offwhite, textured + public const int BackGumpID = 0x13BE; // Gray slate/stoney + public const int ButtonGumpID = 0x0E14; // Dark navy blue, textured + + public const int ButtonWidth = 20; + + public const int GoOffsetX = 2, GoOffsetY = 2; + public const int GoButtonID1 = 0x15E1; // Arrow pointing right + public const int GoButtonID2 = 0x15E5; // " pressed + + public const int DeleteOffsetX = 1, DeleteOffsetY = 1; + public const int DeleteButtonID1 = 0x0A94; // 'X' Button + public const int DeleteButtonID2 = 0x0A95; // " pressed + + public const int PrevWidth = 20; + public const int PrevOffsetX = 2, PrevOffsetY = 2; + public const int PrevButtonID1 = 0x15E3; // Arrow pointing left + public const int PrevButtonID2 = 0x15E7; // " pressed + + public const int NextWidth = 20; + public const int NextOffsetX = 2, NextOffsetY = 2; + public const int NextButtonID1 = 0x15E1; // Arrow pointing right + public const int NextButtonID2 = 0x15E5; // " pressed + + public const int WipeWidth = 20; + public const int WipeOffsetX = 0, WipeOffsetY = 1; + public const int WipeButtonID1 = 0x0A94; // 'X' Button + public const int WipeButtonID2 = 0x0A95; // " pressed + + public const int OffsetSize = 1; + + public const int EntryHeight = 20; + public const int BorderSize = 10; + + private static bool PrevLabel = false, NextLabel = false, WipeLabel = true; + + private const int PrevLabelOffsetX = PrevWidth + 1; + private const int PrevLabelOffsetY = 0; + + private const int NextLabelOffsetX = -29; + private const int NextLabelOffsetY = 0; + + private const int WipeLabelOffsetX = WipeWidth + 1; + private const int WipeLabelOffsetY = 0; + + private const int EntryWidth = 500; + private const int EntryCount = 15; + + private const int TotalWidth = OffsetSize + EntryWidth + OffsetSize + (ButtonWidth * 2) + OffsetSize; + private const int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 2)); + + private const int BackWidth = BorderSize + TotalWidth + BorderSize; + private const int BackHeight = BorderSize + TotalHeight + BorderSize; + + private Mobile m_Owner; + private ArrayList m_Names; + private int m_Page; + public WipeMobsGump( Mobile owner, string args ) : this( owner, BuildList( owner, args ), 0 ) + { + } + + public WipeMobsGump( Mobile owner, ArrayList list, int page ) : base( GumpOffsetX, GumpOffsetY ) + { + owner.CloseGump( typeof( WipeMobsGump ) ); + + m_Owner = owner; + m_Names = list; + + Initialize( page ); + } + + public static ArrayList BuildList( Mobile owner, string args ) + { + ArrayList list = new ArrayList(); + foreach ( Mobile i in World.Mobiles.Values ) + { + if (args.Length == 0) + break; + else if (i.Name == null) + continue; + else if (i.Name.ToLower().IndexOf( args.ToLower() ) >= 0) + list.Add(i); + } + return list; + } + + public void Initialize( int page ) + { + m_Page = page; + + int count = m_Names.Count - (page * EntryCount); + + if ( count < 0 ) + count = 0; + else if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 2)); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth, totalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + //int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4); + int emptyWidth = EntryWidth; + + AddImageTiled( x, y, emptyWidth, EntryHeight, EntryGumpID ); + + AddLabel( x + TextOffsetX, y, TextHue, string.Format( "Page {0} of {1} ({2}) - Matches for: {3}", page+1, (m_Names.Count + EntryCount - 1) / EntryCount, m_Names.Count, m_args) ); + + x += emptyWidth + OffsetSize; + + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 0 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( (page + 1) * EntryCount < m_Names.Count ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + for ( int i = 0, index = page * EntryCount; i < EntryCount && index < m_Names.Count; ++i, ++index ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + Mobile item = (Mobile)m_Names[index]; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, 0x58 /*hue*/, + item.Deleted ? "(deleted)" : (string.Format("{0} : {1} : {2} {3}", item.Name, item is PlayerMobile? ((Account)item.Account).Username : "Null", item.Map, item.Location)) ); + + if ( !item.Deleted ) + { + x += EntryWidth + OffsetSize; + AddImageTiled( x, y, ButtonWidth, EntryHeight, ButtonGumpID ); + AddButton( x + DeleteOffsetX, y + DeleteOffsetY, DeleteButtonID1, DeleteButtonID2, i + 4, GumpButtonType.Reply, 0 ); + + x += ButtonWidth + OffsetSize; + AddImageTiled( x, y, ButtonWidth, EntryHeight, ButtonGumpID ); + AddButton( x + GoOffsetX, y + GoOffsetY, GoButtonID1, GoButtonID2, i + 1004, GumpButtonType.Reply, 0 ); + } + } + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, TotalWidth, EntryHeight, EntryGumpID ); + + AddImageTiled( x, y, WipeWidth, EntryHeight, HeaderGumpID ); + + AddButton( x + WipeOffsetX, y + WipeOffsetY, WipeButtonID1, WipeButtonID2, 3, GumpButtonType.Reply, 1 ); + + if ( WipeLabel ) + AddLabel( x + WipeLabelOffsetX, y + WipeLabelOffsetY, TextHue, "Wipe All Listed" ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // Closed + { + return; + } + case 1: // Previous + { + if ( m_Page > 0 ) + from.SendGump( new WipeMobsGump( from, m_Names, m_Page - 1 ) ); + + break; + } + case 2: // Next + { + if ( (m_Page + 1) * EntryCount < m_Names.Count ) + from.SendGump( new WipeMobsGump( from, m_Names, m_Page + 1 ) ); + + break; + } + case 3: // Wipe All Listed + { + from.SendGump( new WipeAllGump(from, m_Names) ); + break; + } + default: + { + int index = (m_Page * EntryCount) + (info.ButtonID - 4); + bool deleting = index < 1000; + if (!deleting) + index -= 1000; + + if ( index >= 0 && index < m_Names.Count ) + { + Mobile s = (Mobile)m_Names[index]; + + if ( s.Deleted ) + { + from.SendMessage( "That Mobile no longer exists." ); + from.SendGump( new WipeMobsGump( from, m_Names, m_Page ) ); + } + else + { + if (deleting) + from.SendGump( new DeleteGump(from, m_Names, index) ); + else + { + from.SendMessage( "Going to {0}.", s.Name ); + if ( s.Map == Map.Internal ) + { + from.Map = s.LogoutMap; + } + else + { + from.Map = s.Map; + } + from.SetLocation( s.Location, true ); + from.SendGump( new WipeMobsGump( from, m_Names, m_Page ) ); + } + } + } + + break; + } + } + } + + private class DeleteGump : Gump + { + private Mobile m_From; + private ArrayList m_Names; + private int m_Index; + + public DeleteGump( Mobile from, ArrayList spawners, int index ) : base( 50, 50 ) + { + m_From = from; + m_Names = spawners; + m_Index = index; + + AddPage( 0 ); + + AddBackground( 0, 0, 270, 120, 5054 ); + AddBackground( 10, 10, 250, 100, 3000 ); + + AddHtml( 20, 15, 230, 60, "Are you sure you wish to delete this Mobile?", true, true ); + + AddButton( 20, 80, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 80, 75, 20, 1011011, false, false ); // CONTINUE + + AddButton( 135, 80, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 170, 80, 75, 20, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 2 ) + { + ((Mobile)m_Names[m_Index]).Delete(); + m_Names.RemoveAt(m_Index); + m_From.SendLocalizedMessage( 1010303 ); // deleted object + } + m_From.SendGump( new WipeMobsGump( m_From, m_Names, 0 ) ); + } + } + + private class WipeAllGump : Gump + { + private Mobile m_From; + private ArrayList m_Names; + + public WipeAllGump( Mobile from, ArrayList spawners ) : base( 50, 50 ) + { + m_From = from; + m_Names = spawners; + + AddPage( 0 ); + + AddBackground( 0, 0, 270, 120, 5054 ); + AddBackground( 10, 10, 250, 100, 3000 ); + + AddHtml( 20, 15, 230, 60, "Are you sure you wish to delete all " + m_Names.Count + " of the listed Mobiles?", true, true ); + + AddButton( 20, 80, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 80, 75, 20, 1011011, false, false ); // CONTINUE + + AddButton( 135, 80, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 170, 80, 75, 20, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 2 ) + { + foreach (Mobile item in m_Names) + { + item.Delete(); + } + + m_From.SendMessage( "Deleted {0} Mobiles.", m_Names.Count ); + } + } + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/IAugments.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/IAugments.cs new file mode 100644 index 0000000..a003c97 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/IAugments.cs @@ -0,0 +1,22 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2 +{ + public interface IAncientAugment + { + } + + public interface ILegendaryAugment + { + } + + public interface IMythicAugment + { + } + + public interface ICrystalAugment + { + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/amethysts.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/amethysts.cs new file mode 100644 index 0000000..082bf62 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/amethysts.cs @@ -0,0 +1,356 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // -------------------------------------------------- + // Legendary Amethyst + // -------------------------------------------------- + + public class MythicAmethyst : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicAmethyst() : base(0xf26) + { + Name = "Mythic Amethyst"; + Hue = 11; + } + + public MythicAmethyst( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +17 Damage\nShields: +9 Str\nArmor: +16 Defend Chance\nCreature: +5 Max Damage"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponDamage += 17; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.Attributes.BonusStr += 9; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.DefendChance += 16; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).DamageMax += 5; + } else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponDamage -= 17; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.Attributes.BonusStr -= 9; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.DefendChance -= 16; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).DamageMax -= 5; + } else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Legendary Amethyst + // -------------------------------------------------- + + public class LegendaryAmethyst : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendaryAmethyst() : base(0xf26) + { + Name = "Legendary Amethyst"; + Hue = 12; + } + + public LegendaryAmethyst( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +10 Damage\nShields: +5 Str\nArmor: +10 Defend Chance\nCreature: +3 Max Damage"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponDamage += 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.Attributes.BonusStr += 5; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.DefendChance += 10; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).DamageMax += 3; + } else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponDamage -= 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.Attributes.BonusStr -= 5; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.DefendChance -= 10; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).DamageMax -= 3; + } else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ancient Amethyst + // -------------------------------------------------- + + public class AncientAmethyst : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientAmethyst() : base(0xf26) + { + Name = "Ancient Amethyst"; + Hue = 15; + } + + public AncientAmethyst( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +4 Damage\nShields: +2 Str\nArmor: +4 Defend Chance\nCreature: +1 Max Damage"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponDamage += 4; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.Attributes.BonusStr += 2; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.DefendChance += 4; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).DamageMax += 1; + } else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponDamage -= 4; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.Attributes.BonusStr -= 2; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.DefendChance -= 4; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).DamageMax -= 1; + } else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/crystals.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/crystals.cs new file mode 100644 index 0000000..6ef1c14 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/crystals.cs @@ -0,0 +1,1650 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + // -------------------------------------------------- + // Fen Crystal + // -------------------------------------------------- + + public class FenCrystal : BaseSocketAugmentation + { + + [Constructable] + public FenCrystal() : base(0xF8E) + { + Name = "Fen Crystal"; + Hue = 8; + } + + public FenCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +Spell Channeling\nShields: +Spell Channeling\nArmor: Mage armor"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.SpellChanneling = 1; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.SpellChanneling = 1; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.MageArmor = 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.SpellChanneling = 0; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.SpellChanneling = 0; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.MageArmor = 0; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Rho Crystal + // -------------------------------------------------- + + public class RhoCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public RhoCrystal() : base(0xF8E) + { + Name = "Rho Crystal"; + Hue = 13; + } + + public RhoCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +1 Faster Casting"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastSpeed += 1; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastSpeed += 1; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastSpeed += 1; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastSpeed += 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastSpeed -= 1; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastSpeed -= 1; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastSpeed -= 1; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastSpeed -= 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Rys Crystal + // -------------------------------------------------- + + public class RysCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public RysCrystal() : base(0xF8E) + { + Name = "Rys Crystal"; + Hue = 18; + } + + public RysCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +1 Faster Cast Recovery"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastRecovery += 1; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastRecovery += 1; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastRecovery += 1; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastRecovery += 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastRecovery -= 1; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastRecovery -= 1; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastRecovery -= 1; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastRecovery -= 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Wyr Crystal + // -------------------------------------------------- + + public class WyrCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public WyrCrystal() : base(0xF8E) + { + Name = "Wyr Crystal"; + Hue = 23; + } + + public WyrCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +80 Luck"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.Luck += 80; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.Luck += 80; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.Luck += 80; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.Luck += 80; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.Luck -= 80; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.Luck -= 80; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.Luck -= 80; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.Luck -= 80; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Fre Crystal + // -------------------------------------------------- + + public class FreCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public FreCrystal() : base(0xF8E) + { + Name = "Fre Crystal"; + Hue = 28; + } + + public FreCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Enhance potions"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.EnhancePotions += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.EnhancePotions += 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.EnhancePotions += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.EnhancePotions += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.EnhancePotions -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.EnhancePotions -= 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.EnhancePotions -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.EnhancePotions -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Tor Crystal + // -------------------------------------------------- + + public class TorCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public TorCrystal() : base(0xF8E) + { + Name = "Tor Crystal"; + Hue = 33; + } + + public TorCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Lower reagent cost"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerRegCost += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerRegCost += 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerRegCost += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.LowerRegCost += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerRegCost -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerRegCost -= 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerRegCost -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.LowerRegCost -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Vel Crystal + // -------------------------------------------------- + + public class VelCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public VelCrystal() : base(0xF8E) + { + Name = "Vel Crystal"; + Hue = 38; + } + + public VelCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +4 Lower mana cost"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerManaCost += 4; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerManaCost += 4; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerManaCost += 4; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.LowerManaCost += 4; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerManaCost -= 4; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerManaCost -= 4; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerManaCost -= 4; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.LowerManaCost -= 4; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Xen Crystal + // -------------------------------------------------- + + public class XenCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public XenCrystal() : base(0xF8E) + { + Name = "Xen Crystal"; + Hue = 43; + } + + public XenCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +5 Spell damage"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.SpellDamage += 5; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.SpellDamage += 5; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.SpellDamage += 5; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.SpellDamage += 5; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.SpellDamage -= 5; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.SpellDamage -= 5; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.SpellDamage -= 5; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.SpellDamage -= 5; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Pol Crystal + // -------------------------------------------------- + + public class PolCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public PolCrystal() : base(0xF8E) + { + Name = "Pol Crystal"; + Hue = 48; + } + + public PolCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor: +50 Durability\nJewelry: +6 Attack Chance"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.DurabilityBonus += 50; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.DurabilityBonus += 50; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.DurabilityBonus += 50; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.AttackChance += 6; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.DurabilityBonus -= 50; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.DurabilityBonus -= 50; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.DurabilityBonus -= 50; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.AttackChance -= 6; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Wol Crystal + // -------------------------------------------------- + + public class WolCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public WolCrystal() : base(0xF8E) + { + Name = "Wol Crystal"; + Hue = 53; + } + + public WolCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor: +2 Self-repair\nJewelry: +6 Defend Chance"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.SelfRepair += 2; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.SelfRepair += 2; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.SelfRepair += 2; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.DefendChance += 6; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.SelfRepair -= 2; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.SelfRepair -= 2; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.SelfRepair -= 2; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.DefendChance -= 6; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Bal Crystal + // -------------------------------------------------- + + public class BalCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public BalCrystal() : base(0xF8E) + { + Name = "Bal Crystal"; + Hue = 133; + } + + public BalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Resist fire"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistFireBonus += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).FireBonus += 10; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).FireBonus += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Fire += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistFireBonus -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).FireBonus -= 10; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).FireBonus -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Fire -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Tal Crystal + // -------------------------------------------------- + + public class TalCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public TalCrystal() : base(0xF8E) + { + Name = "Tal Crystal"; + Hue = 88; + } + + public TalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Resist cold"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistColdBonus += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).ColdBonus += 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ColdBonus += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Cold += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistColdBonus -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).ColdBonus -= 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ColdBonus -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Cold -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Jal Crystal + // -------------------------------------------------- + + public class JalCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public JalCrystal() : base(0xF8E) + { + Name = "Jal Crystal"; + Hue = 70; + } + + public JalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Resist poison"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPoisonBonus += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).PoisonBonus += 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PoisonBonus += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Poison += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPoisonBonus -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).PoisonBonus -= 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PoisonBonus -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Poison -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ral Crystal + // -------------------------------------------------- + + public class RalCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public RalCrystal() : base(0xF8E) + { + Name = "Ral Crystal"; + Hue = 75; + } + + public RalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Resist energy"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistEnergyBonus += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).EnergyBonus += 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).EnergyBonus += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Energy += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistEnergyBonus -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).EnergyBonus -= 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).EnergyBonus -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Energy -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Kal Crystal + // -------------------------------------------------- + + public class KalCrystal : BaseSocketAugmentation, ICrystalAugment + { + + [Constructable] + public KalCrystal() : base(0xF8E) + { + Name = "Kal Crystal"; + Hue = 46; + } + + public KalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Resist physical"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPhysicalBonus += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).PhysicalBonus += 10; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PhysicalBonus += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Physical += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPhysicalBonus -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).PhysicalBonus -= 10; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PhysicalBonus -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Physical -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/diamonds.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/diamonds.cs new file mode 100644 index 0000000..0a899ee --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/diamonds.cs @@ -0,0 +1,380 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // -------------------------------------------------- + // Mythic Diamond + // -------------------------------------------------- + + public class MythicDiamond : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicDiamond() : base(0xf26) + { + Name = "Mythic Diamond"; + Hue = 1153; + } + + public MythicDiamond( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +40 Hit Physical Area\nShields: +5 all resists\nArmor: +32 Attack Chance\nCreature: +32 Str"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPhysicalArea += 40; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.EnergyBonus += 5; + s.FireBonus += 5; + s.PoisonBonus += 5; + s.PhysicalBonus += 5; + s.ColdBonus += 5; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.AttackChance += 32; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawStr += 32; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPhysicalArea -= 40; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.EnergyBonus -= 5; + s.FireBonus -= 5; + s.PoisonBonus -= 5; + s.PhysicalBonus -= 5; + s.ColdBonus -= 5; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.AttackChance -= 32; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawStr -= 32; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Legendary Diamond + // -------------------------------------------------- + + public class LegendaryDiamond : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendaryDiamond() : base(0xf26) + { + Name = "Legendary Diamond"; + Hue = 1150; + } + + public LegendaryDiamond( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +25 Hit Physical Area\nShields: +3 all resists\nArmor: +20 Attack Chance\nCreature: +20 Str"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPhysicalArea += 25; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.EnergyBonus += 3; + s.FireBonus += 3; + s.PoisonBonus += 3; + s.PhysicalBonus += 3; + s.ColdBonus += 3; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.AttackChance += 20; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawStr += 20; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPhysicalArea -= 25; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.EnergyBonus -= 3; + s.FireBonus -= 3; + s.PoisonBonus -= 3; + s.PhysicalBonus -= 3; + s.ColdBonus -= 3; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.AttackChance -= 20; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawStr -= 20; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ancient Diamond + // -------------------------------------------------- + + public class AncientDiamond : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientDiamond() : base(0xf26) + { + Name = "Ancient Diamond"; + Hue = 1151; + } + + public AncientDiamond( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +10 Hit Physical Area\nShields: +1 all resists\nArmor: +8 Attack Chance\nCreature: +8 str"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPhysicalArea += 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.EnergyBonus += 1; + s.FireBonus += 1; + s.PoisonBonus += 1; + s.PhysicalBonus += 1; + s.ColdBonus += 1; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.AttackChance += 8; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawStr += 8; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPhysicalArea -= 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.EnergyBonus -= 1; + s.FireBonus -= 1; + s.PoisonBonus -= 1; + s.PhysicalBonus -= 1; + s.ColdBonus -= 1; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.AttackChance -= 8; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawStr -= 8; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/emeralds.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/emeralds.cs new file mode 100644 index 0000000..2a0cf64 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/emeralds.cs @@ -0,0 +1,359 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + // -------------------------------------------------- + // Mythic Emerald + // -------------------------------------------------- + + public class MythicEmerald : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicEmerald() : base(0xf26) + { + Name = "Mythic Emerald"; + Hue = 1267; + } + + public MythicEmerald( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +40 Hit Poison Area\nShields: +25 poison resist\nArmor: +25 Dex\nCreature: +32 Dex"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPoisonArea += 40; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.PoisonBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusDex += 25; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawDex += 32; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPoisonArea -= 40; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.PoisonBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusDex -= 25; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawDex -= 32; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Legendary Emerald + // -------------------------------------------------- + + public class LegendaryEmerald : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendaryEmerald() : base(0xf26) + { + Name = "Legendary Emerald"; + Hue = 1268; + } + + public LegendaryEmerald( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +25 Hit Poison Area\nShields: +15 poison resist\nArmor: +15 Dex\nCreature: +20 Dex"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPoisonArea += 25; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.PoisonBonus += 15; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusDex += 15; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawDex += 20; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPoisonArea -= 25; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.PoisonBonus -= 15; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusDex -= 15; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawDex -= 20; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ancient Emerald + // -------------------------------------------------- + + public class AncientEmerald : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientEmerald() : base(0xf26) + { + Name = "Ancient Emerald"; + Hue = 76; + } + + public AncientEmerald( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +10 Hit Poison Area\nShields: +6 poison resist\nArmor: +6 Dex\nCreature: +8 Dex"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPoisonArea += 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.PoisonBonus += 6; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusDex += 6; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawDex += 8; + } else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitPoisonArea -= 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.PoisonBonus -= 6; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusDex -= 6; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawDex -= 8; + } else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/keyaugment.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/keyaugment.cs new file mode 100644 index 0000000..17d6b10 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/keyaugment.cs @@ -0,0 +1,188 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // --------------------------------------------------- + // Key augment to open doors and locked containers + // --------------------------------------------------- + + public class KeyAugment : BaseSocketAugmentation + { + + private SkillName m_RequiredSkill = SkillName.Lockpicking; // default skill required to use this augment + private int m_RequiredSkillLevel = 100; // default skill level required to use this augment + private int m_OpenSound = 0x1F4; // default opening sound + private int m_KeyValue; // matched against the keyvalue of the door or container it is intended to open + private int m_UsesRemaining = 1; // can only use once by default + + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName RequiredSkill { get{ return m_RequiredSkill; } set { m_RequiredSkill = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int RequiredSkillLevel { get{ return m_RequiredSkillLevel; } set { m_RequiredSkillLevel = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int OpenSound { get{ return m_OpenSound; } set { m_OpenSound = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int KeyValue { get{ return m_KeyValue; } set { m_KeyValue = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining { get{ return m_UsesRemaining; } set { m_UsesRemaining = value; InvalidateProperties(); } } + + + [Constructable] + public KeyAugment(string name, int keyvalue, string skillname, int minlevel) : base(0x1f14) + { + Hue = 20; + Name = name; + KeyValue = keyvalue; + try{ + RequiredSkill = (SkillName)Enum.Parse(typeof(SkillName),skillname); + } catch{} + RequiredSkillLevel = minlevel; + } + + [Constructable] + public KeyAugment(string name, int keyvalue) : base(0x1f14) + { + Hue = 20; + Name = name; + KeyValue = keyvalue; + } + + [Constructable] + public KeyAugment(string name) : base(0x1f14) + { + Hue = 20; + Name = name; + } + + [Constructable] + public KeyAugment() : base(0x1f14) + { + Hue = 20; + } + + public override bool DestroyAfterUse { get { return (UsesRemaining == 0); } } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public KeyAugment( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if(m_UsesRemaining >= 0) + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + public override string OnIdentify(Mobile from) + { + return String.Format("Key to {0}", Name); + } + + public override bool OnAugment(Mobile from, object target) + { + if(from == null || target == null || UsesRemaining == 0) return false; + + if(target is BaseDoor) + { + BaseDoor d = target as BaseDoor; + + // open the door + d.Open = true; + + if(OpenSound > 0) + from.PlaySound( OpenSound ); + + // and add a fresh socket attachment to the door + XmlAttach.AttachTo(d,new XmlSockets(1,false)); + + // decrement the uses + if(UsesRemaining > 0) + UsesRemaining--; + + return true; + } else + if(target is LockableContainer) + { + LockableContainer d = target as LockableContainer; + + // open the container + d.Locked = false; + + if(OpenSound > 0) + from.PlaySound( OpenSound ); + + // decrement the uses + if(UsesRemaining > 0) + UsesRemaining--; + + return true; + } + + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(from == null) return false; + + if(target is BaseDoor || target is LockableContainer) + { + Item d = target as Item; + + if(RequiredSkillLevel > 0 && from.Skills[RequiredSkill].Value < RequiredSkillLevel) + { + from.SendMessage("You lack the {0} skill to use this", RequiredSkill.ToString()); + return false; + } + + if((d is BaseDoor && ((BaseDoor)d).KeyValue == KeyValue) || (d is LockableContainer && ((LockableContainer)d).KeyValue == KeyValue)) + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (int)m_RequiredSkill); + writer.Write( (int)m_RequiredSkillLevel); + writer.Write( (int)m_OpenSound); + writer.Write( (int)m_KeyValue); + writer.Write( (int)m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_RequiredSkill = (SkillName)reader.ReadInt(); + m_RequiredSkillLevel = reader.ReadInt(); + m_OpenSound = reader.ReadInt(); + m_KeyValue = reader.ReadInt(); + m_UsesRemaining = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/radiantcrystals.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/radiantcrystals.cs new file mode 100644 index 0000000..b924100 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/radiantcrystals.cs @@ -0,0 +1,1544 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + + // -------------------------------------------------- + // Radiant Rho Crystal + // -------------------------------------------------- + + public class RadiantRhoCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantRhoCrystal() : base(0xF8E) + { + Name = "Radiant Rho Crystal"; + Hue = 13; + } + + public RadiantRhoCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +3 Faster Casting"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastSpeed += 3; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastSpeed += 3; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastSpeed += 3; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastSpeed += 3; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastSpeed -= 3; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastSpeed -= 3; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastSpeed -= 3; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastSpeed -= 3; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Rys Crystal + // -------------------------------------------------- + + public class RadiantRysCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantRysCrystal() : base(0xF8E) + { + Name = "Radiant Rys Crystal"; + Hue = 18; + } + + public RadiantRysCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +3 Faster Cast Recovery"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastRecovery += 3; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastRecovery += 3; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastRecovery += 3; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastRecovery += 3; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.CastRecovery -= 3; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.CastRecovery -= 3; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.CastRecovery -= 3; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.CastRecovery -= 3; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Wyr Crystal + // -------------------------------------------------- + + public class RadiantWyrCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantWyrCrystal() : base(0xF8E) + { + Name = "Radiant Wyr Crystal"; + Hue = 23; + } + + public RadiantWyrCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +200 Luck"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.Luck += 200; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.Luck += 200; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.Luck += 200; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.Luck += 200; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.Luck -= 200; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.Luck -= 200; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.Luck -= 200; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.Luck -= 200; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Fre Crystal + // -------------------------------------------------- + + public class RadiantFreCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantFreCrystal() : base(0xF8E) + { + Name = "Radiant Fre Crystal"; + Hue = 28; + } + + public RadiantFreCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +25 Enhance potions"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.EnhancePotions += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.EnhancePotions += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.EnhancePotions += 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.EnhancePotions += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.EnhancePotions -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.EnhancePotions -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.EnhancePotions -= 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.EnhancePotions -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Tor Crystal + // -------------------------------------------------- + + public class RadiantTorCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantTorCrystal() : base(0xF8E) + { + Name = "Radiant Tor Crystal"; + Hue = 33; + } + + public RadiantTorCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor: +25 Lower reagent cost"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerRegCost += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerRegCost += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerRegCost += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerRegCost -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerRegCost -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerRegCost -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Vel Crystal + // -------------------------------------------------- + + public class RadiantVelCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantVelCrystal() : base(0xF8E) + { + Name = "Radiant Vel Crystal"; + Hue = 38; + } + + public RadiantVelCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +10 Lower mana cost"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerManaCost += 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerManaCost += 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerManaCost += 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.LowerManaCost += 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.LowerManaCost -= 10; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.LowerManaCost -= 10; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.LowerManaCost -= 10; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.LowerManaCost -= 10; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Xen Crystal + // -------------------------------------------------- + + public class RadiantXenCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantXenCrystal() : base(0xF8E) + { + Name = "Radiant Xen Crystal"; + Hue = 43; + } + + public RadiantXenCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +12 Spell damage"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.SpellDamage += 12; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.SpellDamage += 12; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.SpellDamage += 12; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.SpellDamage += 12; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.SpellDamage -= 12; + } else + if(target is BaseShield) + { + ((BaseShield)target).Attributes.SpellDamage -= 12; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.SpellDamage -= 12; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.SpellDamage -= 12; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Pol Crystal + // -------------------------------------------------- + + public class RadiantPolCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantPolCrystal() : base(0xF8E) + { + Name = "Radiant Pol Crystal"; + Hue = 48; + } + + public RadiantPolCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor: +125 Durability\nJewelry: +15 Attack Chance"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.DurabilityBonus += 125; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.DurabilityBonus += 125; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.DurabilityBonus += 125; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.AttackChance += 15; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.DurabilityBonus -= 125; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.DurabilityBonus -= 125; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.DurabilityBonus -= 125; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.AttackChance -= 15; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Wol Crystal + // -------------------------------------------------- + + public class RadiantWolCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantWolCrystal() : base(0xF8E) + { + Name = "Radiant Wol Crystal"; + Hue = 53; + } + + public RadiantWolCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor: +5 Self-repair\nJewelry: +15 Defend Chance"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.SelfRepair += 5; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.SelfRepair += 5; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.SelfRepair += 5; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.DefendChance += 15; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.SelfRepair -= 5; + } else + if(target is BaseShield) + { + ((BaseShield)target).ArmorAttributes.SelfRepair -= 5; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ArmorAttributes.SelfRepair -= 5; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Attributes.DefendChance -= 15; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Bal Crystal + // -------------------------------------------------- + + public class RadiantBalCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantBalCrystal() : base(0xF8E) + { + Name = "Radiant Bal Crystal"; + Hue = 133; + } + + public RadiantBalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +25 Resist fire"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistFireBonus += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).FireBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).FireBonus += 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Fire += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistFireBonus -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).FireBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).FireBonus -= 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Fire -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Tal Crystal + // -------------------------------------------------- + + public class RadiantTalCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantTalCrystal() : base(0xF8E) + { + Name = "Radiant Tal Crystal"; + Hue = 88; + } + + public RadiantTalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +25 Resist cold"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistColdBonus += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).ColdBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ColdBonus += 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Cold += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistColdBonus -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).ColdBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).ColdBonus -= 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Cold -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Jal Crystal + // -------------------------------------------------- + + public class RadiantJalCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantJalCrystal() : base(0xF8E) + { + Name = "Radiant Jal Crystal"; + Hue = 70; + } + + public RadiantJalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +25 Resist poison"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPoisonBonus += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).PoisonBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PoisonBonus += 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Poison += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPoisonBonus -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).PoisonBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PoisonBonus -= 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Poison -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Ral Crystal + // -------------------------------------------------- + + public class RadiantRalCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantRalCrystal() : base(0xF8E) + { + Name = "Radiant Ral Crystal"; + Hue = 75; + } + + public RadiantRalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +25 Resist energy"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistEnergyBonus += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).EnergyBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).EnergyBonus += 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Energy += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistEnergyBonus -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).EnergyBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).EnergyBonus -= 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Energy -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Radiant Kal Crystal + // -------------------------------------------------- + + public class RadiantKalCrystal : BaseSocketAugmentation + { + + [Constructable] + public RadiantKalCrystal() : base(0xF8E) + { + Name = "Kal Crystal"; + Hue = 46; + } + + public RadiantKalCrystal( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 4; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon, Shield, Armor, Jewelry: +25 Resist physical"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPhysicalBonus += 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).PhysicalBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PhysicalBonus += 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Physical += 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseJewel); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.ResistPhysicalBonus -= 25; + } else + if(target is BaseShield) + { + ((BaseShield)target).PhysicalBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).PhysicalBonus -= 25; + } else + if(target is BaseJewel) + { + ((BaseJewel)target).Resistances.Physical -= 25; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/rubies.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/rubies.cs new file mode 100644 index 0000000..2e38009 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/rubies.cs @@ -0,0 +1,453 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + public class MythicRuby : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicRuby() : base(0xF13) + { + Name = "Mythic Ruby"; + Hue = 32; + } + + public MythicRuby( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + public override int Version { get { return 0;} } + + public override string OnIdentify(Mobile from) + { + switch(Version) + { + case 0: + return "Weapon: +40 Hit Fire Area\nShields: +25 Fire Resist\nArmor: +32 Hits\nCreature: +32 Armor"; + case 1: + return "Weapon: +30 Hit Fire Area\nShields: +20 Fire Resist\nArmor: +25 Hits\nCreature: +28 Armor"; + } + + return null; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnAugment(Mobile from, object target) + { + switch(Version) + { + case 0: + // stronger version + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea += 40; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus += 25; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits += 32; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor += 32; + } + else + { + return false; + } + break; + case 1: + // weaker version + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea += 30; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus += 20; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits += 25; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor += 28; + } + else + { + return false; + } + break; + + } + + return true; + } + + public override bool OnRecover(Mobile from, object target, int version) + { + switch(version) + { + case 0: + // stronger version + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea -= 40; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus -= 25; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits -= 32; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor -= 32; + } + else + { + return false; + } + break; + case 1: + // weaker version + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea -= 30; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus -= 20; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits -= 25; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor -= 28; + } + else + { + return false; + } + break; + + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Legendary Ruby + // -------------------------------------------------- + + public class LegendaryRuby : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendaryRuby() : base(0xF13) + { + Name = "Legendary Ruby"; + Hue = 33; + } + + public LegendaryRuby( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +25 Hit Fire Area\nShields: +15 fire resist\nArmor: +20 Hits\nCreature: +20 Armor"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea += 25; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus += 15; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits += 20; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor += 20; + } + else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea -= 25; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus -= 15; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits -= 20; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor -= 20; + } + else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ancient Ruby + // -------------------------------------------------- + + public class AncientRuby : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientRuby() : base(0xF13) + { + Name = "Ancient Ruby"; + Hue = 30; + } + + public AncientRuby( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +10 Hit Fire Area\nShields: +6 fire resist\nArmor: +8 Hits\nCreature: +8 Armor"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea += 10; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus += 6; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits += 8; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor += 8; + } + else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitFireArea -= 10; + } + else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.FireBonus -= 6; + } + else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusHits -= 8; + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).VirtualArmor -= 8; + } + else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/runeaugments.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/runeaugments.cs new file mode 100644 index 0000000..9a38cd3 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/runeaugments.cs @@ -0,0 +1,517 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // --------------------------------------------------- + // Tyr rune + // --------------------------------------------------- + + public class TyrRune : BaseSocketAugmentation + { + + [Constructable] + public TyrRune() : base(0x1f14) + { + Name = "Tyr Rune"; + Hue = 289; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public TyrRune( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Weapons: +Special attack Stamina Drain\nShields: +Special defense Stamina Drain"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + // adds the custom attack attachment + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.StamDrain); + + from.SendMessage("The target has gained the special attack Stamina Drain"); + return true; + } else + if(target is BaseShield) + { + // adds the custom defense attachment + XmlCustomDefenses.AddDefense(target, XmlCustomDefenses.SpecialDefenses.StamDrain); + + from.SendMessage("The target has gained the special defense Stamina Drain"); + return true; + } + + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon || target is BaseArmor) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Ahm rune + // --------------------------------------------------- + + public class AhmRune : BaseSocketAugmentation + { + + [Constructable] + public AhmRune() : base(0x1f14) + { + Name = "Ahm Rune"; + Hue = 289; + } + + public AhmRune( Serial serial ) : base( serial ) + { + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public override string OnIdentify(Mobile from) + { + return "Weapons: +Special attack Puff Of Smoke\nShields: +Special defense Puff Of Smoke"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.PuffOfSmoke); + + from.SendMessage("The target has gained the special attack Puff Of Smoke"); + return true; + } else + if(target is BaseShield) + { + XmlCustomDefenses.AddDefense(target, XmlCustomDefenses.SpecialDefenses.PuffOfSmoke); + + from.SendMessage("The target has gained the special defense Puff Of Smoke"); + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon || target is BaseShield) + { + return true; + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Mor rune + // --------------------------------------------------- + + public class MorRune : BaseSocketAugmentation + { + + [Constructable] + public MorRune() : base(0x1f14) + { + Name = "Mor Rune"; + Hue = 289; + } + + public MorRune( Serial serial ) : base( serial ) + { + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public override string OnIdentify(Mobile from) + { + return "Weapons: +Special attack Mind Drain\nShields: +Special defense Mind Drain"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.MindDrain); + + from.SendMessage("The target has gained the special attack Mind Drain"); + return true; + } else + if(target is BaseShield) + { + XmlCustomDefenses.AddDefense(target, XmlCustomDefenses.SpecialDefenses.MindDrain); + + from.SendMessage("The target has gained the special defense Mind Drain"); + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon || target is BaseShield) + { + return true; + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Mef rune + // --------------------------------------------------- + + public class MefRune : BaseSocketAugmentation + { + + [Constructable] + public MefRune() : base(0x1f14) + { + Name = "Mef Rune"; + Hue = 289; + } + + public MefRune( Serial serial ) : base( serial ) + { + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public override string OnIdentify(Mobile from) + { + return "Weapons: +Special attack Gift of Health\nShields: +Special defense Gift of Health"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.GiftOfHealth); + + from.SendMessage("The target has gained the special attack Gift of Health"); + return true; + } else + if(target is BaseShield) + { + XmlCustomDefenses.AddDefense(target, XmlCustomDefenses.SpecialDefenses.GiftOfHealth); + + from.SendMessage("The target has gained the special defense Gift of Health"); + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon || target is BaseShield) + { + return true; + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Ylm rune + // --------------------------------------------------- + + public class YlmRune : BaseSocketAugmentation + { + + [Constructable] + public YlmRune() : base(0x1f14) + { + Name = "Ylm Rune"; + Hue = 289; + } + + public YlmRune( Serial serial ) : base( serial ) + { + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public override string OnIdentify(Mobile from) + { + return "Weapons: +Special attack Vortex Strike\nShields: +Special defense Spike Shield"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.VortexStrike); + + from.SendMessage("The target has gained the special attack Vortex Strike"); + return true; + } else + if(target is BaseShield) + { + XmlCustomDefenses.AddDefense(target, XmlCustomDefenses.SpecialDefenses.SpikeShield); + + from.SendMessage("The target has gained the special defense Spike Shield"); + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon || target is BaseShield) + { + return true; + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Kot rune + // --------------------------------------------------- + + public class KotRune : BaseSocketAugmentation + { + + [Constructable] + public KotRune() : base(0x1f14) + { + Name = "Kot Rune"; + Hue = 289; + } + + public KotRune( Serial serial ) : base( serial ) + { + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public override string OnIdentify(Mobile from) + { + return "Weapons: +Special attack Paralyzing Fear\nShields: +Special defense Paralyzing Fear"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.ParalyzingFear); + + from.SendMessage("The target has gained the special attack Paralyzing Fear"); + return true; + } else + if(target is BaseShield) + { + XmlCustomDefenses.AddDefense(target, XmlCustomDefenses.SpecialDefenses.ParalyzingFear); + + from.SendMessage("The target has gained the special defense Paralyzing Fear"); + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon || target is BaseShield) + { + return true; + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Jor rune + // --------------------------------------------------- + + public class JorRune : BaseSocketAugmentation + { + + [Constructable] + public JorRune() : base(0x1f14) + { + Name = "Jor Rune"; + Hue = 289; + } + + public JorRune( Serial serial ) : base( serial ) + { + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public override string OnIdentify(Mobile from) + { + return "Weapons: +Special attack Triple Slash"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + XmlCustomAttacks.AddAttack(target, XmlCustomAttacks.SpecialAttacks.TripleSlash); + + from.SendMessage("The target has gained the special attack Triple Slash"); + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + return true; + } + + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/sapphires.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/sapphires.cs new file mode 100644 index 0000000..a813587 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/sapphires.cs @@ -0,0 +1,360 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + // -------------------------------------------------- + // Mythic Sapphire + // -------------------------------------------------- + + public class MythicSapphire : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicSapphire() : base(0xF19) + { + Name = "Mythic Sapphire"; + Hue = 190; + } + + public MythicSapphire( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +40 Hit Cold Area\nShields: +25 Cold Resist\nArmor: +15 Int\nCreature: +32 Int"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitColdArea += 40; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.ColdBonus += 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusInt += 15; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawInt += 32; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitColdArea -= 40; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.ColdBonus -= 25; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusInt -= 15; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawInt -= 32; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Legendary Sapphire + // -------------------------------------------------- + + public class LegendarySapphire : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendarySapphire() : base(0xF19) + { + Name = "Legendary Sapphire"; + Hue = 100; + } + + public LegendarySapphire( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +25 Hit Cold Area\nShields: +15 Cold Resist\nArmor: +8 Int\nCreature: +20 Int"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitColdArea += 25; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.ColdBonus += 15; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusInt += 8; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawInt += 20; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitColdArea -= 25; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.ColdBonus -= 15; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusInt -= 8; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawInt -= 20; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ancient Sapphire + // -------------------------------------------------- + + public class AncientSapphire : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientSapphire() : base(0xF19) + { + Name = "Ancient Sapphire"; + Hue = 94; + } + + public AncientSapphire( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +10 Hit Cold Area\nShields: +6 Cold Resist\nArmor: +3 Int\nCreature: +5 Int"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitColdArea += 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.ColdBonus += 6; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusInt += 3; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawInt += 3; + } else + { + return false; + } + + return true; + } + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).WeaponAttributes.HitColdArea -= 10; + } else + if(target is BaseShield) + { + BaseShield s = target as BaseShield; + + s.ColdBonus -= 6; + + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.BonusInt -= 3; + } else + if(target is BaseCreature) + { + ((BaseCreature)target).RawInt -= 3; + } else + { + return false; + } + + return true; + } + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/skulls.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/skulls.cs new file mode 100644 index 0000000..00bade6 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/skulls.cs @@ -0,0 +1,361 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // --------------------------------------------------- + // Mythic skull + // --------------------------------------------------- + + public class MythicSkull : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicSkull() : base(0x1ae4) + { + Name = "Mythic skull"; + Hue = 1154; + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon { get { return 0x2203;} } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + public MythicSkull( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Weapon: +9 Leech Mana, +9 Leech Life\nArmor: +5 Mana Regen, +5 Hits Regen\nCreature: +85 Hits"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + a.Attributes.RegenHits += 5; + a.Attributes.RegenMana += 5; + return true; + } else + if(target is BaseWeapon) + { + BaseWeapon a = target as BaseWeapon; + a.WeaponAttributes.HitLeechHits += 9; + a.WeaponAttributes.HitLeechMana += 9; + return true; + } else + if(target is BaseCreature) + { + BaseCreature a = target as BaseCreature; + a.HitsMaxSeed += 85; + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseWeapon || target is BaseCreature) + { + return true; + } + + return false; + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + a.Attributes.RegenHits -= 5; + a.Attributes.RegenMana -= 5; + return true; + } else + if(target is BaseWeapon) + { + BaseWeapon a = target as BaseWeapon; + a.WeaponAttributes.HitLeechHits -= 9; + a.WeaponAttributes.HitLeechMana -= 9; + return true; + } else + if(target is BaseCreature) + { + BaseCreature a = target as BaseCreature; + a.HitsMaxSeed -= 85; + return true; + } + + return false; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + // --------------------------------------------------- + // Ancient skull + // --------------------------------------------------- + + public class AncientSkull : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientSkull() : base(0x1ae4) + { + Name = "Ancient skull"; + Hue = 1150; + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon { get { return 0x2203;} } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + public AncientSkull( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Weapon: +2 Leech Mana, +2 Leech Life\nArmor: +1 Mana Regen, +1 Hits Regen\nCreature: +20 Hits"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + a.Attributes.RegenHits += 1; + a.Attributes.RegenMana += 1; + return true; + } else + if(target is BaseWeapon) + { + BaseWeapon a = target as BaseWeapon; + a.WeaponAttributes.HitLeechHits += 2; + a.WeaponAttributes.HitLeechMana += 2; + return true; + } else + if(target is BaseCreature) + { + BaseCreature a = target as BaseCreature; + a.HitsMaxSeed += 20; + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseWeapon || target is BaseCreature) + { + return true; + } + + return false; + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + a.Attributes.RegenHits -= 1; + a.Attributes.RegenMana -= 1; + return true; + } else + if(target is BaseWeapon) + { + BaseWeapon a = target as BaseWeapon; + a.WeaponAttributes.HitLeechHits -= 2; + a.WeaponAttributes.HitLeechMana -= 2; + return true; + } else + if(target is BaseCreature) + { + BaseCreature a = target as BaseCreature; + a.HitsMaxSeed -= 20; + return true; + } + + return false; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + // --------------------------------------------------- + // Legendary skull + // --------------------------------------------------- + + public class LegendarySkull : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendarySkull() : base(0x1ae4) + { + Name = "Legendary skull"; + Hue = 1153; + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon { get { return 0x2203;} } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + public LegendarySkull( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Weapon: +5 Leech Mana, +5 Leech Life\nArmor: +3 Mana Regen, +3 Hits Regen\nCreature: +50 Hits"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + a.Attributes.RegenHits += 3; + a.Attributes.RegenMana += 3; + return true; + } else + if(target is BaseWeapon) + { + BaseWeapon a = target as BaseWeapon; + a.WeaponAttributes.HitLeechHits += 5; + a.WeaponAttributes.HitLeechMana += 5; + return true; + } else + if(target is BaseCreature) + { + BaseCreature a = target as BaseCreature; + a.HitsMaxSeed += 50; + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseWeapon || target is BaseCreature) + { + return true; + } + + return false; + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + a.Attributes.RegenHits -= 3; + a.Attributes.RegenMana -= 3; + return true; + } else + if(target is BaseWeapon) + { + BaseWeapon a = target as BaseWeapon; + a.WeaponAttributes.HitLeechHits -= 5; + a.WeaponAttributes.HitLeechMana -= 5; + return true; + } else + if(target is BaseCreature) + { + BaseCreature a = target as BaseCreature; + a.HitsMaxSeed -= 50; + return true; + } + + return false; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/stones.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/stones.cs new file mode 100644 index 0000000..433fd08 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/stones.cs @@ -0,0 +1,858 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + public class GlimmeringGranite : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringGranite() : base(0x1779) + { + Name = "Glimmering Granite"; + Hue = 15; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringGranite( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Alchemy"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Alchemy, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Alchemy, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringClay : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringClay() : base(0x1779) + { + Name = "Glimmering Clay"; + Hue = 25; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringClay( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Anatomy"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Anatomy, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Anatomy, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringHeartstone : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringHeartstone() : base(0x1779) + { + Name = "Glimmering Heartstone"; + Hue = 35; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringHeartstone( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 AnimalLore"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.AnimalLore, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.AnimalLore, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringGypsum : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringGypsum() : base(0x1779) + { + Name = "Glimmering Gypsum"; + Hue = 45; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringGypsum( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 ItemID"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.ItemID, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.ItemID, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringIronOre : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringIronOre() : base(0x1779) + { + Name = "Glimmering Iron Ore"; + Hue = 55; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringIronOre( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 ArmsLore"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.ArmsLore, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.ArmsLore, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringOnyx : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringOnyx() : base(0x1779) + { + Name = "Glimmering Onyx"; + Hue = 2; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringOnyx( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Parry"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Parry, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Parry, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringMarble : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringMarble() : base(0x1779) + { + Name = "Glimmering Marble"; + Hue = 85; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringMarble( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Blacksmith"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Blacksmith, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Blacksmith, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringPetrifiedWood : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringPetrifiedWood() : base(0x1779) + { + Name = "Glimmering Petrified wood"; + Hue = 85; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringPetrifiedWood( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Fletching"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Fletching, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Fletching, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringLimestone : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringLimestone() : base(0x1779) + { + Name = "Glimmering Limestone"; + Hue = 85; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringLimestone( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Peacemaking"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Peacemaking, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Peacemaking, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlimmeringBloodrock : BaseSocketAugmentation + { + + [Constructable] + public GlimmeringBloodrock() : base(0x1779) + { + Name = "Glimmering Bloodrock"; + Hue = 85; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public GlimmeringBloodrock( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor, Jewelry: +5 Healing"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Healing, 5.0 ); + break; + } + } + return true; + } else + if(target is BaseJewel) + { + BaseJewel a = target as BaseJewel; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Healing, 5.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor || target is BaseJewel) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/tourmalines.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/tourmalines.cs new file mode 100644 index 0000000..99d4f04 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/tourmalines.cs @@ -0,0 +1,359 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // -------------------------------------------------- + // Mythic Tourmaline + // -------------------------------------------------- + + public class MythicTourmaline : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicTourmaline() : base(0xF2D) + { + Name = "Mythic Tourmaline"; + Hue = 1161; + } + + public MythicTourmaline( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 3; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +25 Weapon speed\nShields,Armor: +15 Reflect physical\nCreature: +5 All resists"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponSpeed += 25; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.ReflectPhysical += 15; + } else + if(target is BaseCreature) + { + BaseCreature b = target as BaseCreature; + + b.PhysicalResistanceSeed += 5; + b.FireResistSeed += 5; + b.ColdResistSeed += 5; + b.PoisonResistSeed += 5; + b.EnergyResistSeed += 5; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponSpeed -= 25; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.ReflectPhysical -= 15; + } else + if(target is BaseCreature) + { + BaseCreature b = target as BaseCreature; + + b.PhysicalResistanceSeed -= 5; + b.FireResistSeed -= 5; + b.ColdResistSeed -= 5; + b.PoisonResistSeed -= 5; + b.EnergyResistSeed -= 5; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Legendary Tourmaline + // -------------------------------------------------- + + public class LegendaryTourmaline : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendaryTourmaline() : base(0xf26) + { + Name = "Legendary Tourmaline"; + Hue = 53; + } + + public LegendaryTourmaline( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 2; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +15 Weapon speed\nShields,Armor: +8 Reflect physical\nCreature: +3 All resists"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponSpeed += 15; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.ReflectPhysical += 8; + } else + if(target is BaseCreature) + { + BaseCreature b = target as BaseCreature; + + b.PhysicalResistanceSeed += 3; + b.FireResistSeed += 3; + b.ColdResistSeed += 3; + b.PoisonResistSeed += 3; + b.EnergyResistSeed += 3; + } else + { + return false; + } + + return true; + } + + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponSpeed -= 15; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.ReflectPhysical -= 8; + } else + if(target is BaseCreature) + { + BaseCreature b = target as BaseCreature; + + b.PhysicalResistanceSeed -= 3; + b.FireResistSeed -= 3; + b.ColdResistSeed -= 3; + b.PoisonResistSeed -= 3; + b.EnergyResistSeed -= 3; + } else + { + return false; + } + + return true; + } + + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // -------------------------------------------------- + // Ancient Tourmaline + // -------------------------------------------------- + + public class AncientTourmaline : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientTourmaline() : base(0xf26) + { + Name = "Ancient Tourmaline"; + Hue = 56; + } + + public AncientTourmaline( Serial serial ) : base( serial ) + { + } + + public override int SocketsRequired {get { return 1; } } + + public override int Icon {get { return 0x9a8; } } + + public override bool UseGumpArt {get { return true; } } + + public override int IconXOffset { get { return 15;} } + + public override int IconYOffset { get { return 15;} } + + + public override string OnIdentify(Mobile from) + { + return "Weapon: +5 Weapon speed\nShields,Armor: +3 Reflect physical\nCreature: +1 All resists"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponSpeed += 5; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.ReflectPhysical += 3; + } else + if(target is BaseCreature) + { + BaseCreature b = target as BaseCreature; + + b.PhysicalResistanceSeed += 1; + b.FireResistSeed += 1; + b.ColdResistSeed += 1; + b.PoisonResistSeed += 1; + b.EnergyResistSeed += 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanAugment(Mobile from, object target) + { + return (target is BaseWeapon || target is BaseArmor || target is BaseCreature); + } + + public override bool OnRecover(Mobile from, object target, int version) + { + if(target is BaseWeapon) + { + ((BaseWeapon)target).Attributes.WeaponSpeed -= 5; + } else + if(target is BaseArmor) + { + ((BaseArmor)target).Attributes.ReflectPhysical -= 3; + } else + if(target is BaseCreature) + { + BaseCreature b = target as BaseCreature; + + b.PhysicalResistanceSeed -= 1; + b.FireResistSeed -= 1; + b.ColdResistSeed -= 1; + b.PoisonResistSeed -= 1; + b.EnergyResistSeed -= 1; + } else + { + return false; + } + + return true; + } + + + public override bool CanRecover(Mobile from, object target, int version) + { + return true; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/Augments/woods.cs b/Scripts/Customs/XmlSockets_20_v108a/Augments/woods.cs new file mode 100644 index 0000000..efe731a --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/Augments/woods.cs @@ -0,0 +1,238 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + // --------------------------------------------------- + // Mythic wood + // --------------------------------------------------- + + public class MythicWood : BaseSocketAugmentation, IMythicAugment + { + + [Constructable] + public MythicWood() : base(0x1bdd) + { + Name = "Mythic wood"; + Hue = 11; + } + + public override int SocketsRequired {get { return 3; } } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public MythicWood( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor: +40 Lumberjacking"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Lumberjacking, 40.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // --------------------------------------------------- + // Legendary wood + // --------------------------------------------------- + + public class LegendaryWood : BaseSocketAugmentation, ILegendaryAugment + { + + [Constructable] + public LegendaryWood() : base(0x1bdd) + { + Name = "Legendary wood"; + Hue = 12; + } + + public override int SocketsRequired {get { return 2; } } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public LegendaryWood( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor: +25 Lumberjacking"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Lumberjacking, 25.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + // --------------------------------------------------- + // Ancient wood + // --------------------------------------------------- + + public class AncientWood : BaseSocketAugmentation, IAncientAugment + { + + [Constructable] + public AncientWood() : base(0x1bdd) + { + Name = "Ancient wood"; + Hue = 15; + } + + public override int IconXOffset { get { return 5;} } + + public override int IconYOffset { get { return 20;} } + + public AncientWood( Serial serial ) : base( serial ) + { + } + + public override string OnIdentify(Mobile from) + { + + return "Armor: +10 Lumberjacking"; + } + + public override bool OnAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + BaseArmor a = target as BaseArmor; + // find a free slot + for(int i =0; i < 5; i++) + { + if(a.SkillBonuses.GetBonus(i) == 0) + { + a.SkillBonuses.SetValues( i, SkillName.Lumberjacking, 10.0 ); + break; + } + } + return true; + } + + return false; + } + + + public override bool CanAugment(Mobile from, object target) + { + if(target is BaseArmor) + { + return true; + } + + return false; + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/BagOfResources.cs b/Scripts/Customs/XmlSockets_20_v108a/BagOfResources.cs new file mode 100644 index 0000000..8a21123 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/BagOfResources.cs @@ -0,0 +1,163 @@ +using System; +using System.Data; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using Server.Gumps; +using System.Text; +using Server.ContextMenus; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + public class BagOfResources : BaseTransmutationContainer + { + + public enum Recipes + { + BoltsToArrows, + ArrowsToBolts, + HidesToBandages + } + + public static void Initialize() + { + + // + // define the recipes and their use requirements + // + // ideally, you have a definition for every Recipes enum. Although it isnt absolutely necessary, + // if it isnt defined here, it will not be available for use + + AddRecipe( + (int)Recipes.BoltsToArrows, // transform any quantity of bolts into half the quantity of arrows + 70,30,0, // str, dex, int requirements + new SkillName [] { SkillName.ArmsLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(Bolt)}, // ingredient list + new int [] { 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.ArrowsToBolts, // transform any quantity of arrows into half the quantity of bolts + 70,30,0, // str, dex, int requirements + new SkillName [] { SkillName.ArmsLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(Arrow)}, // ingredient list + new int [] { 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.HidesToBandages, // transform any quantity of hides into bandages + 50,30,0, // str, dex, int requirements + null, // no skill requirements + null, // minimum skill levels + new Type [] {typeof(Hides)}, // ingredient list + new int [] { 0 } // zero indicates any quantity + ); + + } + + public override void DoTransmute(Mobile from, Recipe r) + { + if(r == null || from == null) return; + + Recipes rid = (Recipes) r.RecipeID; + switch(rid) + { + case Recipes.BoltsToArrows: + { + int totalamount = 0; + foreach(Item i in Items) + { + totalamount += i.Amount; + } + // turn into half the amount + totalamount /= 2; + + // take the ingredients + ConsumeAll(); + + // add the new + if(totalamount > 0) + DropItem(new Arrow(totalamount)); + break; + } + case Recipes.ArrowsToBolts: + { + int totalamount = 0; + foreach(Item i in Items) + { + totalamount += i.Amount; + } + // turn into half the amount + totalamount /= 2; + + // take the ingredients + ConsumeAll(); + + // add the new + if(totalamount > 0) + DropItem(new Bolt(totalamount)); + break; + } + case Recipes.HidesToBandages: + { + int totalamount = 0; + foreach(Item i in Items) + { + totalamount += i.Amount; + } + + // take the ingredients + ConsumeAll(); + + // add the new + if(totalamount > 0) + DropItem(new Bandage(totalamount)); + break; + } + + } + + // give effects for successful transmutation + from.PlaySound(503); + + base.DoTransmute(from, r); + } + + [Constructable] + public BagOfResources() : this(-1) + { + } + + [Constructable] + public BagOfResources(int nuses) : base(0xE76) + { + Name = "Bag Of Resources"; + GumpID = 0x3D; + Hue = 25; + UsesRemaining = nuses; + } + + public BagOfResources( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/BaseSocketAugmentation.cs b/Scripts/Customs/XmlSockets_20_v108a/BaseSocketAugmentation.cs new file mode 100644 index 0000000..b044b33 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/BaseSocketAugmentation.cs @@ -0,0 +1,156 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Gumps; +using System.Text; +using Server.Targeting; + +namespace Server.Engines.XmlSpawner2 +{ + // this is the interface for objects that can be used in sockets + public interface IXmlSocketAugmentation + { + string OnIdentify(Mobile from); + + bool OnAugment(Mobile from, object target); + + bool CanAugment(Mobile from, object target); + + bool CanAugment(Mobile from, object target, int socketnumber); + + bool OnRecover(Mobile from, object target, int version); + + bool CanRecover(Mobile from, object target, int version); + + int RecoverableSockets(int version); + + bool ConsumeOnAugment(Mobile from); + + int SocketsRequired {get; } + + bool DestroyAfterUse {get; } + + int Version { get; } + + void Delete(); + + string Name {get; set; } + + int Icon {get; } + + bool UseGumpArt {get; } + + int IconXOffset { get; } + + int IconYOffset { get; } + + int IconHue { get; } + } + + public abstract class BaseSocketAugmentation : Item, IXmlSocketAugmentation + { + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + string msg = null; + + if(SocketsRequired > 1) + { + msg = String.Format("\nRequires {0} sockets",SocketsRequired); + } + + list.Add( 1062613, OnIdentify(null) + msg); + } + + public virtual string OnIdentify(Mobile from) + { + return null; + } + + public virtual bool OnAugment(Mobile from, object target) + { + return true; + } + + public virtual bool CanAugment(Mobile from, object target) + { + return true; + } + + public virtual bool CanAugment(Mobile from, object target, int socketnumber) + { + return CanAugment(from, target); + } + + public virtual bool OnRecover(Mobile from, object target, int version) + { + return false; + } + + public virtual bool CanRecover(Mobile from, object target, int version) + { + return false; + } + + public virtual int RecoverableSockets(int version) + { + return SocketsRequired; + } + + public virtual bool ConsumeOnAugment(Mobile from) + { + return true; + } + + public virtual bool DestroyAfterUse + { + get { return true;} + } + + public virtual int Icon {get { return ItemID; } } + + public virtual int SocketsRequired {get { return 1; } } + + public virtual int Version { get { return 0; } } + + public virtual bool UseGumpArt {get { return false; } } + + public virtual int IconXOffset { get { return 0; } } + + public virtual int IconYOffset { get { return 0; } } + + public virtual int IconHue { get { return (Hue > 0 ? Hue - 1 : Hue); } } + + + public BaseSocketAugmentation(int itemid) : base(itemid) + { + } + + public BaseSocketAugmentation() : base() + { + } + + public BaseSocketAugmentation( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/BaseTransmutationContainer.cs b/Scripts/Customs/XmlSockets_20_v108a/BaseTransmutationContainer.cs new file mode 100644 index 0000000..dceb234 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/BaseTransmutationContainer.cs @@ -0,0 +1,444 @@ +using System; +using System.Data; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using System.Collections.Generic; +using Server.Gumps; +using System.Text; +using Server.ContextMenus; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + public class BaseTransmutationContainer : Container + { + + public virtual void DoTransmute(Mobile from, Recipe r) + { + if(UsesRemaining > 0) + { + UsesRemaining--; + } + } + + + public void ConsumeAll() + { + ArrayList dlist = new ArrayList(); + foreach(Item i in Items) + { + dlist.Add(i); + } + foreach(Item i in dlist) + { + i.Delete(); + } + + } + + public class Recipe + { + public int RecipeID; // recipe id + public int StrReq; // str requirements for this recipe + public int DexReq; // dex requirements for this recipe + public int IntReq; // int requirements for this recipe + public Type [] Ingredients; // ingredient list used for this recipe + public int [] Quantity; // ingredients quantity list + public SkillName [] Skills; // list of skill requirements for this recipe + public int [] MinSkillLevel; // minimum skill levels + public string [] PropertyTests; // additional property tests on the ingredients + + public Recipe( int id, int minstr, int mindex, int minint, + SkillName [] skills, int [] minlevel, Type [] ingredients, int [] quantity, string [] proptests) + { + RecipeID = id; + StrReq = minstr; + DexReq = mindex; + IntReq = minint; + Ingredients = ingredients; + Quantity = quantity; + Skills = skills; + MinSkillLevel = minlevel; + PropertyTests = proptests; + } + } + + private int m_UsesRemaining; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining { get { return m_UsesRemaining; } set { m_UsesRemaining = value; InvalidateProperties(); } } + + private static ArrayList AllRecipes = new ArrayList(); + + public static void AddRecipe( int id, int minstr, int mindex, int minint, + SkillName [] skills, int [] minlevel, Type [] ingredients, int [] quantity) + { + AllRecipes.Add(new Recipe( id, + minstr, mindex, minint, skills, minlevel, ingredients, quantity, null) ); + } + + public static void AddRecipe( int id, int minstr, int mindex, int minint, + SkillName [] skills, int [] minlevel, Type [] ingredients, int [] quantity, string [] proptests) + { + AllRecipes.Add(new Recipe( id, + minstr, mindex, minint, skills, minlevel, ingredients, quantity, proptests) ); + } + + public override int DefaultGumpID{ get{ return 0x4B; } } + public override int DefaultDropSound{ get{ return 0x42; } } + + public override Rectangle2D Bounds + { + get{ return new Rectangle2D( 16, 51, 168, 73 ); } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if(m_UsesRemaining >= 0) + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + + private class TransmuteEntry : ContextMenuEntry + { + Mobile m_From; + BaseTransmutationContainer m_Box; + + public TransmuteEntry(Mobile from, BaseTransmutationContainer box ) : base( 6190, 2 ) + { + m_From = from; + m_Box = box; + } + + public override void OnClick() + { + if(m_From == null || m_Box == null || m_Box.Deleted) return; + + // open the transmutation gump + m_From.CloseGump( typeof(TransmuteGump) ); + m_From.SendGump( new TransmuteGump( m_From, m_Box, null) ); + + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries( from, list ); + + list.Add( new TransmuteEntry(from, this) ); + } + + public override void OnItemLifted( Mobile from, Item item ) + { + if(from != null) + { + from.CloseGump( typeof(TransmuteGump) ); + from.SendGump( new TransmuteGump( from, this, item) ); + } + } + + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + bool diddrop = base.OnDragDrop( from, dropped); + + if(from != null && diddrop) + { + from.CloseGump( typeof(TransmuteGump) ); + from.SendGump( new TransmuteGump( from, this, null) ); + } + + return diddrop; + + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + bool diddrop = base.OnDragDropInto( from, item, p); + + if(from != null && diddrop) + { + from.CloseGump( typeof(TransmuteGump) ); + from.SendGump( new TransmuteGump( from, this, null) ); + } + + return diddrop; + } + + + public static bool CheckRequirements(Mobile from, Recipe s) + { + if(from == null || s == null) return false; + + // test for str, dex, int requirements + if(from.Str < s.StrReq) + { + from.SendMessage("Need {0} Str to transmute this", s.StrReq); + return false; + } + if(from.Dex < s.DexReq) + { + from.SendMessage("Need {0} Dex to transmute this", s.DexReq); + return false; + } + if(from.Int < s.IntReq) + { + from.SendMessage("Need {0} Int to transmute this", s.IntReq); + return false; + } + + // test for skill requirements + if(s.Skills != null && s.MinSkillLevel != null) + { + if(from.Skills == null) return false; + + for(int i = 0; i < s.Skills.Length; i++) + { + // and check level + if(i < s.MinSkillLevel.Length) + { + Skill skill = from.Skills[s.Skills[i]]; + if(skill != null && s.MinSkillLevel[i] > skill.Base) + { + from.SendMessage("Need {0} {1} to transmute this", s.MinSkillLevel[i], s.Skills[i].ToString()); + return false; + } + } else + { + from.SendMessage(33,"Error in skill level specification for {0}", s.RecipeID); + return false; + } + } + } + + return true; + } + + private bool ContainsInterface(Type [] typearray, Type type) + { + if(typearray == null || type == null) return false; + + foreach(Type t in typearray) + { + if(t == type) return true; + } + + return false; + } + + public void Transmute(Mobile from) + { + if(from == null) return; + + if(UsesRemaining == 0) + { + from.SendMessage("{0} is exhausted", Name); + return; + } + // go through each recipe and determine if the conditions are met + foreach(Recipe r in AllRecipes) + { + if(r.Ingredients == null || r.Ingredients.Length == 0 || r.Quantity == null || r.Ingredients.Length != r.Quantity.Length) continue; + + // go through all of the items in the container + bool validrecipe = true; + int [] quantity = new int[r.Quantity.Length]; + + foreach(Item i in Items) + { + // is this in the recipe? + bool hasingredient = false; + string status_str; + for(int j = 0; j< r.Ingredients.Length; j++) + { + Type rt = r.Ingredients[j]; + Type it = i.GetType(); + if(it != null && rt != null && (it.Equals(rt) || it.IsSubclassOf( rt ) || + (rt.IsInterface && ContainsInterface(it.GetInterfaces(), rt)))) + { + // check any additional property requirements + if(r.PropertyTests != null && r.PropertyTests[j] != null && !BaseXmlSpawner.CheckPropertyString(null, i, r.PropertyTests[j], null, out status_str)) + { + // failed to meet the requirement so skip it + continue; + } + + // found it, so add the quantity + quantity[j] += i.Amount; + + hasingredient = true; + break; + } + } + + // an item is present that is not an ingredient + // that means an invalid recipe + if(!hasingredient) + { + validrecipe = false; + break; + } + } + + // check to see if all of the ingredient quantities have been satisfied + for(int j = 0; j< r.Ingredients.Length; j++) + { + if((quantity[j] == 0) || (r.Quantity[j] != 0 && quantity[j] != r.Quantity[j])) + { + validrecipe = false; + break; + } + } + + + if(validrecipe) + { + // check on stat and skill requirements + if(CheckRequirements(from,r)) + { + // all recipe conditions are satisfied, so carry out the transmutation + DoTransmute(from, r); + break; + } + } + } + + } + + public BaseTransmutationContainer(int itemid) : base(itemid) + { + Name = "Transmutation Container"; + } + + public BaseTransmutationContainer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + // version 0 + writer.Write( m_UsesRemaining ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch(version) + { + case 0: + m_UsesRemaining = reader.ReadInt(); + break; + } + } + + private class TransmuteGump : Gump + { + private Mobile m_From; + private BaseTransmutationContainer m_Target; + + private const int LineSpacing = 20; + private const int ContentColor = 0x384; + private const int TitleColor = 53; + private const int ContentTitleColor = 2101; + + public TransmuteGump(Mobile from, BaseTransmutationContainer target, Item lifted) : base ( 0, 0 ) + { + + if(target == null || from == null) return; + + m_From = from; + m_Target = target; + + Closable = true; + Dragable = true; + + int count = 0; + // figure out how many items are in the box + if(target.Items != null) + { + count = target.Items.Count; + } + + int displayeditems = count; + if(lifted != null && count > 0) + { + displayeditems = count - 1; + } + + int height = 160 + LineSpacing*displayeditems; + int width = 350; + + AddPage( 0 ); + //AddBackground( 0, 0, width, height, 0x242C ); + AddBackground( 0, 0, width, height, 0xA28 ); + //AddAlphaRegion( 2, 2, width - 4, height - 4 ); + + AddLabel( width/2 - 55, 15, TitleColor, target.Name ); + + AddLabel( 20, 45, ContentTitleColor, String.Format("Contents:") ); + + AddImageTiled( 15, 65, width - 30, 20, 0x242D ); + AddImageTiled( 15, height - 70, width - 30, 20, 0x242D ); + + + // go through and list all of the items in the box + int y = 85; + for(int i = 0;i < count; i++) + { + if(target.Items[i] is Item) + { + Item item = target.Items[i] as Item; + + if(item == lifted) continue; + + string name = null; + if(item.Name != null) + { + name = item.Name; + } else + { + name = item.GetType().Name; + } + AddLabel( 80, y, ContentColor, name ); + AddLabel( 20, y, ContentColor, item.Amount.ToString() ); + y += LineSpacing; + } + } + + //AddButton( width/2 - 20, height - 35, 2130, 2129, 1, GumpButtonType.Reply, 0 ); // Okay button + AddButton( width/2 - 43, height - 45, 0x1454, 0x1455, 1, GumpButtonType.Reply, 0 ); // Apply button + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + + if(info == null || state == null || state.Mobile == null || m_From == null || m_Target == null) return; + + + switch(info.ButtonID) + { + case 1: + { + // transmute + m_Target.Transmute(state.Mobile); + state.Mobile.SendGump( new TransmuteGump( state.Mobile, m_Target, null) ); + break; + } + } + } + } + + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/BoxOfTransmutation.cs b/Scripts/Customs/XmlSockets_20_v108a/BoxOfTransmutation.cs new file mode 100644 index 0000000..f3bfef7 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/BoxOfTransmutation.cs @@ -0,0 +1,809 @@ +// Uncomment the following line if you have XmlMobFactions installed and you would like to allow faction gain through recipes +//#define XMLMOBFACTIONS + +using System; +using System.Data; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using Server.Gumps; +using System.Text; +using Server.ContextMenus; +using Server.Engines.BulkOrders; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + public class BoxOfTransmutation : BaseTransmutationContainer + { + + public enum Recipes + { + UpgradeAncientAugment, + UpgradeLegendaryAugment, + UpgradeCrystalAugment, + UndeadFaction, + AbyssFaction, + ReptilianFaction, + ElementalFaction, + HumanoidFaction, + ArachnidFaction, + UnderworldFaction, + SocketWeapon, + SocketArmor, + RecoverAugmentation, + HammerOfRecovery, + PowerScrollSkillChange, + SmallBODChange, + LargeBODChange, + ExceptionalSocketHammer + } + + public override int DefaultMaxWeight + { + get + { + return 420; + } + } + + public static void Initialize() + { + + // + // define the recipes and their use requirements + // + // ideally, you have a definition for every Recipes enum. Although it isnt absolutely necessary, + // if it isnt defined here, it will not be available for use + + AddRecipe( + (int)Recipes.PowerScrollSkillChange, // combines 3 powerscrolls of the same level to produce a new random ps of the same level + 50,20,50, // str, dex, int requirements + new SkillName [] { SkillName.Alchemy }, // skill requirement list + new int [] { 100 }, // minimum skill levels + new Type [] {typeof(LegendaryDiamond), typeof(LegendaryRuby), typeof(LegendaryEmerald), typeof(PowerScroll)}, // ingredient list + new int [] { 1, 1, 1, 3, } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.SmallBODChange, // a small bod and gold to yield a new random small bod + 50,20,50, // str, dex, int requirements + new SkillName [] { SkillName.Alchemy }, // skill requirement list + new int [] { 100 }, // minimum skill levels + new Type [] {typeof(Gold), typeof(SmallBOD)}, // ingredient list + new int [] { 2000, 1 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.LargeBODChange, // a large bod and gold to yield a new random large bod + 50,20,50, // str, dex, int requirements + new SkillName [] { SkillName.Alchemy }, // skill requirement list + new int [] { 100 }, // minimum skill levels + new Type [] {typeof(Gold), typeof(LargeBOD)}, // ingredient list + new int [] { 20000, 1 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.HammerOfRecovery, // removes an augmentation from an item + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Blacksmith }, // skill requirement list + new int [] { 105 }, // minimum skill levels + new Type [] {typeof(AncientRuby), typeof(Hammer)}, // ingredient list + new int [] { 1, 1, } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.RecoverAugmentation, // removes an augmentation from an item + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Blacksmith }, // skill requirement list + new int [] { 100 }, // minimum skill levels + new Type [] {typeof(AncientRuby), typeof(Item)}, // ingredient list + new int [] { 1, 1, } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.UpgradeAncientAugment, // change 6 ancient augments into one legendary + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Alchemy }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(IAncientAugment)}, // ingredient list + new int [] { 6 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.UpgradeLegendaryAugment, // change 3 legendary augments into one mythic + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Alchemy }, // skill requirement list + new int [] { 70 }, // minimum skill levels + new Type [] {typeof(ILegendaryAugment)}, // ingredient list + new int [] { 3 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.UpgradeCrystalAugment, // change 3 crystal augments into one radiant + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Alchemy }, // skill requirement list + new int [] { 70 }, // minimum skill levels + new Type [] {typeof(ICrystalAugment)}, // ingredient list + new int [] { 3 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.UndeadFaction, // gain undead faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringGranite), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.AbyssFaction, // gain abyss faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringBloodrock), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.ReptilianFaction, // gain reptilian faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringHeartstone), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.HumanoidFaction, // gain humanoid faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringClay), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.ArachnidFaction, // gain arachnid faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringIronOre), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.ElementalFaction, // gain elemental faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringGypsum), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.UnderworldFaction, // gain underworld faction + 20,20,40, // str, dex, int requirements + new SkillName [] { SkillName.AnimalLore }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(GlimmeringMarble), typeof( Gold) }, // ingredient list + new int [] { 1 , 0 } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.SocketWeapon, // add a socket to any unsocketed weapon + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Blacksmith }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(RadiantRhoCrystal), typeof(BaseWeapon)}, // ingredient list + new int [] { 1, 1, } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.SocketArmor, // add a socket to any unsocketed armor + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Blacksmith }, // skill requirement list + new int [] { 50 }, // minimum skill levels + new Type [] {typeof(RadiantRhoCrystal), typeof(BaseArmor)}, // ingredient list + new int [] { 1, 1, } // zero indicates any quantity + ); + AddRecipe( + (int)Recipes.ExceptionalSocketHammer, // create a single use Exceptionalsockethammer + 70,30,40, // str, dex, int requirements + new SkillName [] { SkillName.Blacksmith }, // skill requirement list + new int [] { 105 }, // minimum skill levels + new Type [] {typeof(RadiantRysCrystal), typeof(Hammer)}, // ingredient list + new int [] { 1, 1, } // zero indicates any quantity + ); + } + + public override void DoTransmute(Mobile from, Recipe r) + { + if(r == null || from == null) return; + + Recipes rid = (Recipes) r.RecipeID; + switch(rid) + { + case Recipes.PowerScrollSkillChange: + { + // get the target value from one of the powerscrolls + Item [] slist = FindItemsByType(typeof(PowerScroll), true); + + double value = 0; + // make sure they are all of the same value + foreach(Item s in slist) + { + if(value == 0) + { + value = ((PowerScroll)s).Value; + } else + { + if(value != ((PowerScroll)s).Value) + { + from.SendMessage("All powerscrolls must be of the same level"); + return; + } + } + } + + PowerScroll newps = PowerScroll.CreateRandom( (int)(value - 100), (int)(value - 100) ); + + // consume ingredients + ConsumeAll(); + + // add the new powerscroll + DropItem(newps); + + break; + } + case Recipes.SmallBODChange: + { + // get the target value from one of the powerscrolls + Item [] slist = FindItemsByType(typeof(SmallBOD), true); + + Type t = null; + // make sure they are all of the same type + foreach(Item s in slist) + { + if(t == null) + { + t = ((SmallBOD)s).GetType(); + } else + { + if(t != ((SmallBOD)s).GetType()) + { + from.SendMessage("All BODs must be of the same type"); + return; + } + } + } + + SmallBOD newbod = null; + + if(t == typeof(SmallTailorBOD)) + { + newbod = new SmallTailorBOD(); + } else + if(t == typeof(SmallSmithBOD)) + { + newbod = new SmallSmithBOD(); + } else + { + from.SendMessage("Cannot transmute those BODs"); + return; + } + + if(newbod == null) return; + + // consume ingredients + ConsumeAll(); + + // add the new powerscroll + DropItem(newbod); + + break; + } + case Recipes.LargeBODChange: + { + // get the target value from one of the powerscrolls + Item [] slist = FindItemsByType(typeof(LargeBOD), true); + + Type t = null; + // make sure they are all of the same type + foreach(Item s in slist) + { + if(t == null) + { + t = ((LargeBOD)s).GetType(); + } else + { + if(t != ((LargeBOD)s).GetType()) + { + from.SendMessage("All BODs must be of the same type"); + return; + } + } + } + + LargeBOD newbod = null; + + if(t == typeof(LargeTailorBOD)) + { + newbod = new LargeTailorBOD(); + } else + if(t == typeof(LargeSmithBOD)) + { + newbod = new LargeSmithBOD(); + } else + { + from.SendMessage("Cannot transmute those BODs"); + return; + } + + if(newbod == null) return; + + // consume ingredients + ConsumeAll(); + + // add the new powerscroll + DropItem(newbod); + + break; + } + case Recipes.UpgradeAncientAugment: + { + // check what type of augment is being upgraded + BaseSocketAugmentation augment = null; + if(Items.Count > 0) + { + augment = Items[0] as BaseSocketAugmentation; + } + + if(augment == null) return; + + // make sure they are all the same + foreach(Item i in Items) + { + if(augment.GetType() != i.GetType()) return; + } + + // take the ingredients + ConsumeAll(); + // and add the result + if(augment is AncientDiamond) + { + DropItem(new LegendaryDiamond() ); + } else + if(augment is AncientSapphire) + { + DropItem(new LegendarySapphire() ); + } else + if(augment is AncientSkull) + { + DropItem(new LegendarySkull() ); + } else + if(augment is AncientTourmaline) + { + DropItem(new LegendaryTourmaline() ); + } else + if(augment is AncientWood) + { + DropItem(new LegendaryWood() ); + } else + if(augment is AncientRuby) + { + DropItem(new LegendaryRuby() ); + } else + if(augment is AncientEmerald) + { + DropItem(new LegendaryEmerald() ); + } + else + if(augment is AncientAmethyst) + { + DropItem(new LegendaryAmethyst() ); + } + + break; + } + case Recipes.UpgradeLegendaryAugment: + { + // check what type of augment is being upgraded + BaseSocketAugmentation augment = null; + if(Items.Count > 0) + { + augment = Items[0] as BaseSocketAugmentation; + } + + if(augment == null) return; + + // make sure they are all the same + foreach(Item i in Items) + { + if(augment.GetType() != i.GetType()) return; + } + + // take the ingredients + ConsumeAll(); + + // and add the result + if(augment is LegendaryDiamond) + { + DropItem(new MythicDiamond() ); + } else + if(augment is LegendarySapphire) + { + DropItem(new MythicSapphire() ); + } else + if(augment is LegendarySkull) + { + DropItem(new MythicSkull() ); + } else + if(augment is LegendaryTourmaline) + { + DropItem(new MythicTourmaline() ); + } else + if(augment is LegendaryWood) + { + DropItem(new MythicWood() ); + } else + if(augment is LegendaryRuby) + { + DropItem(new MythicRuby() ); + } else + if(augment is LegendaryEmerald) + { + DropItem(new MythicEmerald() ); + } + else + if(augment is LegendaryAmethyst) + { + DropItem(new MythicAmethyst() ); + } + + break; + } + case Recipes.UpgradeCrystalAugment: + { + // check what type of augment is being upgraded + BaseSocketAugmentation augment = null; + if(Items.Count > 0) + { + augment = Items[0] as BaseSocketAugmentation; + } + + if(augment == null) return; + + // make sure they are all the same + foreach(Item i in Items) + { + if(augment.GetType() != i.GetType()) return; + } + + // take the ingredients + ConsumeAll(); + + // and add the result + if(augment is RhoCrystal) + { + DropItem(new RadiantRhoCrystal() ); + } else + if(augment is RysCrystal) + { + DropItem(new RadiantRysCrystal() ); + } else + if(augment is WyrCrystal) + { + DropItem(new RadiantWyrCrystal() ); + } else + if(augment is FreCrystal) + { + DropItem(new RadiantFreCrystal() ); + } else + if(augment is TorCrystal) + { + DropItem(new RadiantTorCrystal() ); + } else + if(augment is VelCrystal) + { + DropItem(new RadiantVelCrystal() ); + } else + if(augment is XenCrystal) + { + DropItem(new RadiantXenCrystal() ); + } else + if(augment is PolCrystal) + { + DropItem(new RadiantPolCrystal() ); + } else + if(augment is WolCrystal) + { + DropItem(new RadiantWolCrystal() ); + } else + if(augment is BalCrystal) + { + DropItem(new RadiantBalCrystal() ); + } else + if(augment is TalCrystal) + { + DropItem(new RadiantTalCrystal() ); + } else + if(augment is JalCrystal) + { + DropItem(new RadiantJalCrystal() ); + } else + if(augment is RalCrystal) + { + DropItem(new RadiantRalCrystal() ); + } else + if(augment is KalCrystal) + { + DropItem(new RadiantKalCrystal() ); + } + + break; + + } + case Recipes.RecoverAugmentation: + { + // does item have any sockets on it? + Item b = FindItemByType(typeof(BaseArmor), true); + if(b == null) + b = FindItemByType(typeof(BaseWeapon), true); + if(b == null) + b = FindItemByType(typeof(BaseJewel), true); + + XmlSockets a = XmlAttach.FindAttachment(b, typeof(XmlSockets)) as XmlSockets; + if(a == null) + { + // if so then forget it + from.SendMessage("This item is not socketed."); + return; + } + + + if(a.NSockets == 0) + { + from.SendMessage("This item is has no sockets."); + return; + } + + BaseSocketAugmentation augment = a.RecoverRandomAugmentation(from, b); + + if(augment != null) + { + // consume the crystal + ConsumeTotal(typeof(AncientRuby), 1, true); + + // put the recovered augment in the container + DropItem(augment); + + from.SendMessage("Recovered a {0} augmentation.", augment.Name); + + // update the sockets gump + a.OnIdentify(from); + + } else + { + from.SendMessage("Failed to recover augmentation."); + } + + + break; + } + case Recipes.HammerOfRecovery: + { + // consume ingredients + ConsumeAll(); + + // add the hammer + DropItem(new HammerOfRecovery(1)); + + break; + } + + case Recipes.ExceptionalSocketHammer: + { + // consume ingredients + ConsumeAll(); + + // add the hammer + DropItem(new ExceptionalSocketHammer(1)); + + break; + } + + case Recipes.SocketWeapon: + { + // does the weapon already have any sockets on it? + Item b = FindItemByType(typeof(BaseWeapon), true); + XmlAttachment a = XmlAttach.FindAttachment(b, typeof(XmlSockets)); + if(a != null) + { + // if so then forget it + from.SendMessage("Weapon already socketed."); + return; + } + // otherwise add the socket + XmlAttach.AttachTo(b, new XmlSockets(1)); + // consume the crystal + ConsumeTotal(typeof(RadiantRhoCrystal), 1, true); + break; + } + case Recipes.SocketArmor: + { + // does the armor already have any sockets on it? + Item b = FindItemByType(typeof(BaseArmor), true); + XmlAttachment a = XmlAttach.FindAttachment(b, typeof(XmlSockets)); + if(a != null) + { + // if so then forget it + from.SendMessage("Armor already socketed."); + return; + } + // otherwise add the socket + XmlAttach.AttachTo(b, new XmlSockets(1)); + // consume the crystal + ConsumeTotal(typeof(RadiantRhoCrystal), 1, true); + break; + } +// Uncomment the follow recipes if you have XmlMobFactions installed and you would like to allow faction gain through these recipes + +#if(XMLMOBFACTIONS) + case Recipes.UndeadFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Undead", value)); + break; + } + case Recipes.AbyssFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Abyss", value)); + break; + } + case Recipes.HumanoidFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Humanoid", value)); + break; + } + case Recipes.ReptilianFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Reptilian", value)); + break; + } + case Recipes.ArachnidFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Arachnid", value)); + break; + } + case Recipes.ElementalFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Elemental", value)); + break; + } + case Recipes.UnderworldFaction: + { + // how much gold is being offered + Item b = FindItemByType(typeof(Gold), true); + + int value = 0; + if(b != null) + { + value = b.Amount/10; + } + + // take the ingredients + ConsumeAll(); + + // add the faction + XmlAttach.AttachTo(from, new XmlAddFaction("Underworld", value)); + break; + } + +// end of commented-out XmlMobFactions recipes +#endif + } + + // give effects for successful transmutation + from.PlaySound(503); + + base.DoTransmute(from, r); + } + + [Constructable] + public BoxOfTransmutation() : this(-1) + { + } + + [Constructable] + public BoxOfTransmutation(int nuses) : base(0xE80) + { + Name = "Box of Transmutation"; + UsesRemaining = nuses; + } + + public BoxOfTransmutation( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/ExceptionalSocketHammer.cs b/Scripts/Customs/XmlSockets_20_v108a/ExceptionalSocketHammer.cs new file mode 100644 index 0000000..d715d2b --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/ExceptionalSocketHammer.cs @@ -0,0 +1,127 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + [FlipableAttribute( 0x13E4, 0x13E3 )] + public class ExceptionalSocketHammer : Item + { + private int m_UsesRemaining; // if set to less than zero, becomes unlimited uses + private int m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Level + { + get { return m_Level; } + set { m_Level = value; InvalidateProperties(); } + } + + [Constructable] + public ExceptionalSocketHammer() : this(50) + { + } + + [Constructable] + public ExceptionalSocketHammer(int nuses) : base(0x13E4) + { + Name = "An Exceptional Socket Hammer"; + Hue = 5; + UsesRemaining = nuses; + int rand = Utility.Random(100); + if(rand < 5) + { + m_Level = Utility.Random(4) + 1; + } + else + if(rand < 10) + { + m_Level = Utility.Random(3) + 1; + } + else + if(rand < 20) + { + m_Level = Utility.Random(2) + 1; + } + else + if(rand < 40) + { + m_Level = Utility.Random(1) + 1; + } + else + { + m_Level = 1; + } + } + + public ExceptionalSocketHammer( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if(m_UsesRemaining >= 0) + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + list.Add( 1060658, "Level\t{0}", m_Level ); // ~1_val~: ~2_val~ + } + + public override void OnDoubleClick( Mobile from) + { + if(UsesRemaining == 0) + { + from.SendMessage("This hammer is now useless"); + return; + } + if ( IsChildOf( from.Backpack ) || Parent == from ) + { + from.Target = new XmlSockets.AddSocketToTarget(m_Level); + if(UsesRemaining > 0) + UsesRemaining--; + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + // version 1 + writer.Write(m_Level); + // version 0 + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch(version) + { + case 1: + m_Level = reader.ReadInt(); + goto case 0; + case 0: + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/HammerOfRecovery.cs b/Scripts/Customs/XmlSockets_20_v108a/HammerOfRecovery.cs new file mode 100644 index 0000000..ec6a820 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/HammerOfRecovery.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + [FlipableAttribute( 0x13E4, 0x13E3 )] + public class HammerOfRecovery : Item + { + private int m_UsesRemaining; // if set to less than zero, becomes unlimited uses + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [Constructable] + public HammerOfRecovery() : this(50) + { + } + + [Constructable] + public HammerOfRecovery(int nuses) : base(0x13E4) + { + Name = "A Hammer of Augmentation Recovery"; + Hue = 5; + UsesRemaining = nuses; + } + + public HammerOfRecovery( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if(m_UsesRemaining >= 0) + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + public override void OnDoubleClick( Mobile from) + { + if(UsesRemaining == 0) + { + from.SendMessage("This hammer is now useless"); + return; + } + if ( IsChildOf( from.Backpack ) || Parent == from ) + { + from.Target = new XmlSockets.RecoverAugmentationFromTarget(); + if(UsesRemaining > 0) + UsesRemaining--; + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_UsesRemaining = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/MagicBasket.cs b/Scripts/Customs/XmlSockets_20_v108a/MagicBasket.cs new file mode 100644 index 0000000..9170623 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/MagicBasket.cs @@ -0,0 +1,99 @@ +using System; +using System.Data; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using Server.Gumps; +using System.Text; +using Server.ContextMenus; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + public class MagicBasket : BaseTransmutationContainer + { + + public enum Recipes + { + UnbakedMeatPie + } + + public static void Initialize() + { + + // + // define the recipes and their use requirements + // + // ideally, you have a definition for every Recipes enum. Although it isnt absolutely necessary, + // if it isnt defined here, it will not be available for use + AddRecipe( + (int)Recipes.UnbakedMeatPie, // makes an uncooked meat pie + 0,30,20, // str, dex, int requirements + new SkillName [] { SkillName.Cooking }, // skill requirement list + new int [] { 30 }, // minimum skill levels + new Type [] {typeof(BowlFlour), typeof(Pitcher), typeof(RawRibs), typeof(Garlic), typeof(Carrot) }, // ingredient list // ingredient list + new int [] { 1, 1, 2, 1, 4 }, // quantities + new string [] { null, "IsFull=true & Content=#Milk", null, null, null } // additional property tests + ); + } + + public override void DoTransmute(Mobile from, Recipe r) + { + if(r == null || from == null) return; + + Recipes rid = (Recipes) r.RecipeID; + switch(rid) + { + case Recipes.UnbakedMeatPie: + { + // take the ingredients + ConsumeAll(); + + // add the pie + DropItem(new UnbakedMeatPie()); + break; + } + } + + // give effects for successful transmutation + from.PlaySound(503); + + base.DoTransmute(from, r); + } + + [Constructable] + public MagicBasket() : this(-1) + { + } + + [Constructable] + public MagicBasket(int nuses) : base(0xE7A) + { + Name = "Magical Basket"; + GumpID = 63; + UsesRemaining = nuses; + } + + public MagicBasket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/SocketHammer.cs b/Scripts/Customs/XmlSockets_20_v108a/SocketHammer.cs new file mode 100644 index 0000000..baa8902 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/SocketHammer.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + + [FlipableAttribute( 0x13E4, 0x13E3 )] + public class SocketHammer : Item + { + private int m_UsesRemaining; // if set to less than zero, becomes unlimited uses + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [Constructable] + public SocketHammer() : this(50) + { + } + + [Constructable] + public SocketHammer(int nuses) : base(0x13E4) + { + Name = "A Socket Hammer"; + Hue = 5; + UsesRemaining = nuses; + } + + public SocketHammer( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if(m_UsesRemaining >= 0) + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + public override void OnDoubleClick( Mobile from) + { + if(UsesRemaining == 0) + { + from.SendMessage("This hammer is now useless"); + return; + } + if ( IsChildOf( from.Backpack ) || Parent == from ) + { + from.Target = new XmlSockets.AddSocketToTarget(); + if(UsesRemaining > 0) + UsesRemaining--; + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + writer.Write(m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_UsesRemaining = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/TestSocketedWeapon.cs b/Scripts/Customs/XmlSockets_20_v108a/TestSocketedWeapon.cs new file mode 100644 index 0000000..0566f30 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/TestSocketedWeapon.cs @@ -0,0 +1,69 @@ +using System; +using Server; +using Server.Engines.XmlSpawner2; + +namespace Server.Items +{ + public class TestSocketedWeapon : Katana + { + + [Constructable] + public TestSocketedWeapon() + { + Name = "Test socketed weapon"; + + switch(Utility.Random(4)) + { + case 0: + // make the weapon socketable up to 4 sockets using the default blacksmithing requirements + // and add 2 sockets to start + XmlAttach.AttachTo(this, new XmlSocketable(4)); + XmlAttach.AttachTo(this, new XmlSockets(2)); + break; + case 1: + // make the weapon socketable up to 4 sockets, and set specific socketing requirements + // minimum of 100 skill in Tinkering required to socket it, and it uses 50 Agapipe ingots + XmlAttach.AttachTo(this, new XmlSocketable(4, SkillName.Tinkering, 100.0, typeof(AgapiteIngot), 50)); + break; + case 2: + // give it 2 sockets and dont allow it to be further socketed + XmlAttach.AttachTo(this, new XmlSocketable(0)); + XmlAttach.AttachTo(this, new XmlSockets(2)); + break; + case 3: + // give it 2 sockets, fill one of them with an augment, nd dont allow it to be further socketed + + // create 2 sockets + XmlSockets s = new XmlSockets(2); + // fill the sockets (starting at 0) with an ancient diamond augment (which only takes up 1 slot) + // the augment call has this form: public static bool Augment( Mobile from, object parent, XmlSockets sock, int socketnum, IXmlSocketAugmentation a) + // Note that the new augment will be automatically deleted after augmenting + XmlSockets.Augment(null, this, s, 0, new AncientDiamond()); + // and put the sockets onto the katana + XmlAttach.AttachTo(this, s); + // and dont allow it to be further socketed + XmlAttach.AttachTo(this, new XmlSocketable(0)); + break; + } + + } + + public TestSocketedWeapon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/XmlAttachments/XmlSocketable.cs b/Scripts/Customs/XmlSockets_20_v108a/XmlAttachments/XmlSocketable.cs new file mode 100644 index 0000000..276ad3c --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/XmlAttachments/XmlSocketable.cs @@ -0,0 +1,241 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Engines.XmlSpawner2 +{ + public class XmlSocketable : XmlAttachment + { + private int m_MaxSockets; + private SkillName m_RequiredSkill = XmlSockets.DefaultSocketSkill; + private double m_MinSkillLevel = XmlSockets.DefaultSocketDifficulty; + private SkillName m_RequiredSkill2 = XmlSockets.DefaultSocketSkill; + private double m_MinSkillLevel2 = 0; // second skill requirement turned off by default + private Type m_RequiredResource = XmlSockets.DefaultSocketResource; + private int m_ResourceQuantity = XmlSockets.DefaultSocketResourceQuantity; + + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxSockets { get{ return m_MaxSockets; } set { m_MaxSockets = value; InvalidateParentProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName RequiredSkill { get{ return m_RequiredSkill; } set { m_RequiredSkill = value; InvalidateParentProperties();} } + + [CommandProperty( AccessLevel.GameMaster )] + public double MinSkillLevel { get{ return m_MinSkillLevel; } set { m_MinSkillLevel = value; InvalidateParentProperties();} } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName RequiredSkill2 { get{ return m_RequiredSkill2; } set { m_RequiredSkill2 = value; InvalidateParentProperties();} } + + [CommandProperty( AccessLevel.GameMaster )] + public double MinSkillLevel2 { get{ return m_MinSkillLevel2; } set { m_MinSkillLevel2 = value; InvalidateParentProperties();} } + + [CommandProperty( AccessLevel.GameMaster )] + public int ResourceQuantity { get{ return m_ResourceQuantity; } set { m_ResourceQuantity = value; InvalidateParentProperties();} } + + [CommandProperty( AccessLevel.GameMaster )] + public Type RequiredResource { get{ return m_RequiredResource; } set { m_RequiredResource = value; InvalidateParentProperties();} } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlSocketable(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlSocketable(int maxsockets, string skillname, double minskilllevel, string skillname2, double minskilllevel2, string resource, int quantity) + { + MaxSockets = maxsockets; + + try{ + RequiredResource = SpawnerType.GetType(resource); + } catch{} + + try{ + RequiredSkill = (SkillName)Enum.Parse(typeof(SkillName),skillname); + } catch{} + + MinSkillLevel = minskilllevel; + + try{ + RequiredSkill2 = (SkillName)Enum.Parse(typeof(SkillName),skillname2); + } catch{} + + MinSkillLevel2 = minskilllevel2; + + ResourceQuantity = quantity; + InvalidateParentProperties(); + } + + [Attachable] + public XmlSocketable(int maxsockets, string skillname, double minskilllevel, string resource, int quantity) + { + MaxSockets = maxsockets; + + try{ + RequiredResource = SpawnerType.GetType(resource); + } catch{} + + try{ + RequiredSkill = (SkillName)Enum.Parse(typeof(SkillName),skillname); + } catch{} + + MinSkillLevel = minskilllevel; + ResourceQuantity = quantity; + InvalidateParentProperties(); + } + + [Attachable] + public XmlSocketable(int maxsockets) + { + MaxSockets = maxsockets; + InvalidateParentProperties(); + } + + [Attachable] + public XmlSocketable() + { + MaxSockets = -1; + InvalidateParentProperties(); + } + + public XmlSocketable(int maxsockets, SkillName skillname, double minskilllevel, Type resource, int quantity) + { + MaxSockets = maxsockets; + RequiredResource = resource; + ResourceQuantity = quantity; + RequiredSkill = skillname; + MinSkillLevel = minskilllevel; + InvalidateParentProperties(); + } + + public XmlSocketable(int maxsockets, SkillName skillname, double minskilllevel, SkillName skillname2, double minskilllevel2, Type resource, int quantity) + { + MaxSockets = maxsockets; + RequiredResource = resource; + ResourceQuantity = quantity; + RequiredSkill = skillname; + MinSkillLevel = minskilllevel; + RequiredSkill2 = skillname2; + MinSkillLevel2 = minskilllevel2; + InvalidateParentProperties(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 1 ); + // version 1 + writer.Write((int)m_RequiredSkill2); + writer.Write(m_MinSkillLevel2); + // version 0 + writer.Write(m_MaxSockets); + if(m_RequiredResource != null) + writer.Write(m_RequiredResource.ToString()); + else + writer.Write((string) null); + writer.Write(m_ResourceQuantity); + writer.Write((int)m_RequiredSkill); + writer.Write(m_MinSkillLevel); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + switch(version) + { + case 1: + // version 1 + m_RequiredSkill2 = (SkillName)reader.ReadInt(); + m_MinSkillLevel2 = reader.ReadDouble(); + goto case 0; + case 0: + // version 0 + m_MaxSockets = reader.ReadInt(); + string resourcetype = reader.ReadString(); + try{ + m_RequiredResource = Type.GetType(resourcetype); + } catch{} + m_ResourceQuantity = reader.ReadInt(); + m_RequiredSkill = (SkillName)reader.ReadInt(); + m_MinSkillLevel = reader.ReadDouble(); + break; + } + } + + public override void OnAttach() + { + base.OnAttach(); + + InvalidateParentProperties(); + } + + public override string OnIdentify(Mobile from) + { + + string msg = null; + int nSockets = 0; + + // first see if the target has any existing sockets + + XmlSockets s = XmlAttach.FindAttachment(AttachedTo,typeof(XmlSockets)) as XmlSockets; + + if(s != null) + { + // find out how many sockets it has + nSockets = s.NSockets; + } + + if(nSockets > MaxSockets) m_MaxSockets = nSockets; + + if(MaxSockets == nSockets) + { + // already full so no chance of socketing + return "Cannot be socketed any further."; + } + + if(MaxSockets > 0) + { + msg = String.Format("Maximum sockets allowed is {0}.",MaxSockets); + } else + if(MaxSockets == 0) + { + return "You cannot add sockets to this."; + } else + if(MaxSockets == -1) + { + msg = String.Format("Can be socketed."); + } + + // compute difficulty based upon existing sockets + + if(from != null) + { + if(MinSkillLevel > 0) + msg += String.Format("\nRequires {0} skill in {1} to socket.", MinSkillLevel, RequiredSkill); + + if(MinSkillLevel2 > 0) + msg += String.Format("\nas well as {0} skill in {1} to socket.", MinSkillLevel2, RequiredSkill2); + + if(RequiredResource != null && ResourceQuantity > 0) + msg += String.Format("\nSocketing consumes {0} {1}.", ResourceQuantity, RequiredResource.Name); + + int success = XmlSockets.ComputeSuccessChance(from, nSockets, MinSkillLevel, RequiredSkill, MinSkillLevel2, RequiredSkill2); + + msg += String.Format("\n{0}% chance of socketing\n",success); + } + + return msg; + } + } +} diff --git a/Scripts/Customs/XmlSockets_20_v108a/XmlAttachments/XmlSockets.cs b/Scripts/Customs/XmlSockets_20_v108a/XmlAttachments/XmlSockets.cs new file mode 100644 index 0000000..827d21b --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/XmlAttachments/XmlSockets.cs @@ -0,0 +1,1384 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Gumps; +using System.Text; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Engines.XmlSpawner2 +{ + + public class XmlSockets : XmlAttachment + { + // if CanSocketByDefault is set to true, then any object can be socketed using the default settings. If the XmlSocketable attachment is present, it + // will override these defaults regardless of the CanSocketByDefault setting. + // If this is set to false, then ONLY objects with the XmlSocketable attachment can be socketed. + public static bool CanSocketByDefault = false; + + // The following default settings will be applied when CanSocketByDefault is true + // + // DefaultMaxSockets determines the default maximum number of sockets and item can have. + // A value of -1 means that any item can have an unlimited number of sockets. + // To set it up so that items by default cannot have sockets added to them set this to zero. + // That way, only items that have the XmlSocketLimit attachment will be allowed to be socketed. This is the same as setting CanSocketByDefault to false. + // You can also assign any other value here to set the default number of sockets allowed when no XmlSocketLimit attachment is present. + public static int DefaultMaxSockets = -1; + + // DefaultSocketDifficulty is the default minimum skill required to socket. + // This can be overridden with the XmlSocketLimit attachment on specific items (100 by default) + public static double DefaultSocketDifficulty = 100.0; + + public static SkillName DefaultSocketSkill = SkillName.Blacksmith; + + public static Type DefaultSocketResource = typeof(ValoriteIngot); + + public static int DefaultSocketResourceQuantity = 50; + + // DefaultDestructionProbability is the percent chance that failure to socket will result in destruction of the the item (10% by default) + public static double DefaultDestructionProbability = 0.1; + + public static int MaxAugmentDistance = 2; // if socketed object isnt in pack, then this is the max distance away from it you can be and still augment + + public static int MaxSocketDistance = 2; // if socketable object isnt in pack, then this is the max distance away from it you can be and still socket + + private ArrayList m_SocketOccupants; + + private bool m_MustAugmentInPack = true; // determines whether the socketed object must be in the players pack in order to augment + + public class SocketOccupant + { + public Type OccupantType; + public int OccupantID; + public int AugmentationVersion; + public string Description; + public int IconXOffset; + public int IconYOffset; + public int IconHue; + public bool UseGumpArt; + + public SocketOccupant(Type t, int version, int id, int xoffset, int yoffset, int hue, bool usegumpart, string description) + { + OccupantType = t; + AugmentationVersion = version; + OccupantID = id; + IconXOffset = xoffset; + IconYOffset = yoffset; + IconHue = hue; + UseGumpArt = usegumpart; + Description = description; + } + + public SocketOccupant(Type t, int nsockets, int version, int id) + { + OccupantType = t; + AugmentationVersion = version; + OccupantID = id; + } + } + + public ArrayList SocketOccupants { get{ return m_SocketOccupants; } set { m_SocketOccupants = value;} } + + [CommandProperty( AccessLevel.GameMaster )] + public bool MustAugmentInPack + { + get + { + return m_MustAugmentInPack; + } + set + { + m_MustAugmentInPack = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int NSockets + { + get + { + if(m_SocketOccupants == null) + { + return 0; + } + else + { + return m_SocketOccupants.Count; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int NFree + { + get + { + if(m_SocketOccupants == null) + { + return 0; + } + else + { + int count = 0; + for(int i = 0; i < m_SocketOccupants.Count; i++) + { + if(m_SocketOccupants[i] != null) count++; + } + return m_SocketOccupants.Count - count; + } + } + } + + public static new void Initialize() + { + CommandSystem.Register( "AddSocket", AccessLevel.Player, new CommandEventHandler( AddSocket_OnCommand ) ); + TargetCommands.Register( new UpgradeAugmentCommand() ); + TargetCommands.Register( new LimitSocketsCommand() ); + } + + public class LimitSocketsCommand : BaseCommand + { + int m_maxsockets; + + public LimitSocketsCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.Area | CommandSupport.Region | CommandSupport.Global | CommandSupport.Multi | CommandSupport.Single; + Commands = new string[]{ "LimitSockets" }; + ObjectTypes = ObjectTypes.All; + Usage = "LimitSockets "; + Description = "Finds XmlSocket attachments with more than maxsockets, recovers their augmentations and reduces the socket number"; + ListOptimized = true; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + + + int nobjects = 0; + + for ( int i = 0; i < list.Count; ++i ) + { + + object targetobject = list[i]; + + // get any socket attachments + // first see if the target has any existing sockets + XmlSockets s = XmlAttach.FindAttachment(targetobject,typeof(XmlSockets)) as XmlSockets; + + bool found = true; + + if(s != null && s.SocketOccupants != null && s.SocketOccupants.Count > m_maxsockets) + { + int maxsock = s.NSockets; + int nchange = 0; + while(found && nchange <= maxsock) + { + found = false; + + // recover all of the augments + for(int j = 0; j < s.SocketOccupants.Count; j++) + { + SocketOccupant so =s.SocketOccupants[j] as SocketOccupant; + if(so != null ) + { + nchange++; + + // recover the old version of the augment + BaseSocketAugmentation augment = s.RecoverAugmentation(null, targetobject, j); + + if(augment != null) + { + + // give it back to the owner + if(targetobject is Item) + { + // is the parent a container? + if(((Item)targetobject).Parent is Container) + { + // add the augment to the container + ((Container)((Item)targetobject).Parent).DropItem(augment); + + } + else + if(((Item)targetobject).Parent is Mobile) + { + // drop it on the ground + augment.MoveToWorld(((Mobile)((Item)targetobject).Parent).Location); + } + else + if(((Item)targetobject).Parent == null) + { + // drop it on the ground + augment.MoveToWorld(((Item)targetobject).Location); + } + } + else + if(targetobject is Mobile) + { + // drop it on the ground + augment.MoveToWorld(((Mobile)targetobject).Location); + } + + found = true; + + break; + } + } + } + } + if(nchange > 0) + nobjects ++; + + e.Mobile.SendMessage("Modified object {0}",targetobject); + + // limit the sockets + s.SocketOccupants = new ArrayList(m_maxsockets); + + for(int k =0;k= 1 ) + { + try + { + m_maxsockets = int.Parse(e.GetString( 0 )); + } + catch { e.Mobile.SendMessage( "Usage: " + Usage ); return false; } + + return true; + + + } + + e.Mobile.SendMessage( "Usage: " + Usage ); + return false; + } + } + + public class UpgradeAugmentCommand : BaseCommand + { + int m_oldversion; + Type m_augmenttype; + + public UpgradeAugmentCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.Area | CommandSupport.Region | CommandSupport.Global | CommandSupport.Multi | CommandSupport.Single; + Commands = new string[]{ "UpgradeAugment" }; + ObjectTypes = ObjectTypes.All; + Usage = "UpgradeAugment "; + Description = "Upgrades the specified augmentation on objects from the oldversion number to the newversion number."; + ListOptimized = true; + } + + public override void ExecuteList( CommandEventArgs e, ArrayList list ) + { + + + int naugments = 0; + int nobjects = 0; + int nfailures = 0; + + for ( int i = 0; i < list.Count; ++i ) + { + + object targetobject = list[i]; + + // get any socket attachments + // first see if the target has any existing sockets + XmlSockets s = XmlAttach.FindAttachment(targetobject,typeof(XmlSockets)) as XmlSockets; + + bool found = true; + + if(s != null && s.SocketOccupants != null) + { + int maxsock = s.NSockets; + int nchange = 0; + while(found && nchange <= maxsock) + { + found = false; + + // find the specified augment type + for(int j = 0; j < s.SocketOccupants.Count; j++) + { + SocketOccupant so =s.SocketOccupants[j] as SocketOccupant; + if(so != null && so.OccupantType == m_augmenttype && so.AugmentationVersion == m_oldversion) + { + + // recover the old version of the augment + BaseSocketAugmentation augment = s.RecoverAugmentation(null, targetobject, j); + + if(augment != null) + { + + // augment with the new version + if(!Augment( null, targetobject, s, j, augment)) + { + e.Mobile.SendMessage("failed to replace augment on {0}",targetobject); + nfailures++; + } + else + { + + naugments++; + } + + nchange++; + + found = true; + + break; + } + } + } + } + if(nchange > 0) + nobjects ++; + } + } + + AddResponse( String.Format( "{0} {1} augmentations upgraded on {2} objects. {3} failures.", naugments, m_augmenttype.Name, nobjects, nfailures ) ); + + } + + public override bool ValidateArgs( BaseCommandImplementor impl, CommandEventArgs e ) + { + if ( e.Arguments.Length >= 2 ) + { + m_augmenttype = SpawnerType.GetType(e.GetString( 0 )); + + if(m_augmenttype == null) + { + e.Mobile.SendMessage( "Unknown augment type: " + e.GetString( 0 )); + return false; + } + + m_oldversion = -1; + try + { + m_oldversion = int.Parse(e.GetString( 1 )); + } + catch{} + + if(m_oldversion != -1) + { + return true; + } + } + + e.Mobile.SendMessage( "Usage: " + Usage ); + return false; + } + } + + // These are the various ways in which the message attachment can be constructed. + // These can be called via the [addatt interface, via scripts, via the spawner ATTACH keyword. + // Other overloads could be defined to handle other types of arguments + + // a serial constructor is REQUIRED + public XmlSockets(ASerial serial) : base(serial) + { + } + + [Attachable] + public XmlSockets(int nsockets) + { + m_SocketOccupants = new ArrayList(nsockets); + + for(int i =0;i 0) + { + // version 1 + m_MustAugmentInPack = reader.ReadBool(); + } + + // version 0 + int count = reader.ReadInt(); + + m_SocketOccupants = new ArrayList(count); + + for(int i = 0;i< count;i++) + { + Type t = null; + + string typename = reader.ReadString(); + + if(typename != null) + { + try + { + t = Type.GetType(typename); + } + catch{} + + int augmentversion = 0; + if(version > 1) + { + // version 2 + augmentversion = reader.ReadInt(); + } + int id = reader.ReadInt(); + string desc = reader.ReadString(); + int xoff = reader.ReadInt(); + int yoff = reader.ReadInt(); + int hue = reader.ReadInt(); + bool use = reader.ReadBool(); + + if(t != null) + m_SocketOccupants.Add(new SocketOccupant(t, augmentversion, id, xoff, yoff, hue, use, desc)); + else + m_SocketOccupants.Add(null); + } + else + { + m_SocketOccupants.Add(null); + } + } + } + + public override void OnAttach() + { + base.OnAttach(); + + InvalidateParentProperties(); + } + + public override string OnIdentify(Mobile from) + { + + // open up the socket gump + if(from != null) + { + from.SendGump(new SocketsGump(from, this)); + } + else + { + return String.Format("{0} Sockets. {1} available.",NSockets, NFree); + } + + return null; + } + + + // this is a utility method that will set up a target item with random socket configurations + public static void ConfigureRandom(object target, double dropchance, double chance5, double chance4, double chance3, double chance2, double chance1) + { + ConfigureRandom( target, dropchance, chance5, chance4, chance3, chance2, chance1, + DefaultSocketSkill, DefaultSocketDifficulty, DefaultSocketResource, DefaultSocketResourceQuantity); + } + + public static void ConfigureRandom(object target, double dropchance, double chance5, double chance4, double chance3, + double chance2, double chance1, SkillName skillname, double minskill, Type resource, int quantity) + { + + if(Utility.Random(1000) < (int)(dropchance*10)) + { + // compute chance of having sockets + int level = Utility.Random(1000); + + if(level < (int)(chance5*10)) + XmlAttach.AttachTo(target, new XmlSockets(5)); + else + if(level < (int)(chance4 + chance5)*10) + XmlAttach.AttachTo(target, new XmlSockets(4)); + else + if(level < (int)(chance3 + chance4)*10) + XmlAttach.AttachTo(target, new XmlSockets(3)); + else + if(level < (int)(chance2 + chance3)*10) + XmlAttach.AttachTo(target, new XmlSockets(2)); + else + if(level < (int)(chance1 + chance2)*10) + XmlAttach.AttachTo(target, new XmlSockets(1)); + + + // compute chance of being socketable + int socklevel = Utility.Random(1000); + + if(socklevel < (int)(chance5*10)) + XmlAttach.AttachTo(target, new XmlSocketable(5, skillname, minskill, resource, quantity)); + else + if(socklevel < (int)(chance4 + chance5)*10) + XmlAttach.AttachTo(target, new XmlSocketable(4, skillname, minskill, resource, quantity)); + else + if(socklevel < (int)(chance3 + chance4)*10) + XmlAttach.AttachTo(target, new XmlSocketable(3, skillname, minskill, resource, quantity)); + else + if(socklevel < (int)(chance2 + chance3)*10) + XmlAttach.AttachTo(target, new XmlSocketable(2, skillname, minskill, resource, quantity)); + else + XmlAttach.AttachTo(target, new XmlSocketable(1, skillname, minskill, resource, quantity)); + } + } + + public static void ConfigureRandom(object target, double dropchance, double chance5, double chance4, double chance3, + double chance2, double chance1, SkillName skillname, double minskill, SkillName skillname2, double minskill2, Type resource, int quantity) + { + + if(Utility.Random(1000) < (int)(dropchance*10)) + { + // compute chance of having sockets + int level = Utility.Random(1000); + + if(level < (int)(chance5*10)) + XmlAttach.AttachTo(target, new XmlSockets(5)); + else + if(level < (int)(chance4 + chance5)*10) + XmlAttach.AttachTo(target, new XmlSockets(4)); + else + if(level < (int)(chance3 + chance4)*10) + XmlAttach.AttachTo(target, new XmlSockets(3)); + else + if(level < (int)(chance2 + chance3)*10) + XmlAttach.AttachTo(target, new XmlSockets(2)); + else + if(level < (int)(chance1 + chance2)*10) + XmlAttach.AttachTo(target, new XmlSockets(1)); + + + // compute chance of being socketable + int socklevel = Utility.Random(1000); + + if(socklevel < (int)(chance5*10)) + XmlAttach.AttachTo(target, new XmlSocketable(5, skillname, minskill, skillname2, minskill2, resource, quantity)); + else + if(socklevel < (int)(chance4 + chance5)*10) + XmlAttach.AttachTo(target, new XmlSocketable(4, skillname, minskill, skillname2, minskill2, resource, quantity)); + else + if(socklevel < (int)(chance3 + chance4)*10) + XmlAttach.AttachTo(target, new XmlSocketable(3, skillname, minskill, skillname2, minskill2, resource, quantity)); + else + if(socklevel < (int)(chance2 + chance3)*10) + XmlAttach.AttachTo(target, new XmlSocketable(2, skillname, minskill, skillname2, minskill2, resource, quantity)); + else + XmlAttach.AttachTo(target, new XmlSocketable(1, skillname, minskill, skillname2, minskill2, resource, quantity)); + } + } + + public static int ComputeSuccessChance(Mobile from, int nsockets, double difficulty, SkillName requiredSkill) + { + if(from == null) return 0; + + double skill = 0; + + // with a difficulty of 120 + // at 120, chance of adding 1 socket is 15%, 2 sockets is 2%, 3 is 0% + // + // with a difficulty of 100 + // at skill level of 100, adding 1 socket has a probability of success of 15%, 2 sockets is 0% + // at 120, chance of adding 1 socket is 55%, 2 sockets is 42%, 3 is 29%, 4 is 16% , 5 is 3%, 6 is 0% + // + // with a difficulty of 70 + // at skill level of 100, adding 1 socket has a probability of success of 75%, 2 sockets is 60%, 3 sockets is 45%, etc. + // at 120, chance of adding 1 socket is 100%, 2 sockets is 100%, 3 sockets is 85%, etc. + // + try + { + skill = from.Skills[requiredSkill].Value; + } + catch{} + + if((int)(skill - difficulty) < 0) return 0; + + int successchance = (int)(2*(skill - difficulty) + 15 - (nsockets-1)*13); + + if(successchance < 0 ) successchance = 0; + + return successchance; + } + + public static int ComputeSuccessChance(Mobile from, int nsockets, double difficulty, SkillName requiredSkill, double difficulty2, SkillName requiredSkill2) + { + if(from == null) return 0; + + double skill = 0; + + // with a difficulty of 120 + // at 120, chance of adding 1 socket is 15%, 2 sockets is 2%, 3 is 0% + // + // with a difficulty of 100 + // at skill level of 100, adding 1 socket has a probability of success of 15%, 2 sockets is 0% + // at 120, chance of adding 1 socket is 55%, 2 sockets is 42%, 3 is 29%, 4 is 16% , 5 is 3%, 6 is 0% + // + // with a difficulty of 70 + // at skill level of 100, adding 1 socket has a probability of success of 75%, 2 sockets is 60%, 3 sockets is 45%, etc. + // at 120, chance of adding 1 socket is 100%, 2 sockets is 100%, 3 sockets is 85%, etc. + // + try + { + skill = from.Skills[requiredSkill].Value; + } + catch{} + + if((int)(skill - difficulty) < 0) return 0; + + int successchance = (int)(2*(skill - difficulty) + 15 - (nsockets-1)*13); + + // if a second skill check has been specified then test it + if(difficulty2 > 0) + { + double skill2 = 0; + try + { + skill2 = from.Skills[requiredSkill2].Value; + } + catch{} + + if((int)(skill2 - difficulty2) < 0) return 0; + + successchance = (int)((skill - difficulty) + (skill2 - difficulty2) + 15 - (nsockets-1)*13); + } + + if(successchance < 0 ) successchance = 0; + + return successchance; + } + + public static bool AddSocket(Mobile from, object target, int maxSockets, double difficulty, SkillName requiredSkill, Type resource, int quantity) + { + return AddSocket(from, target, maxSockets, difficulty, requiredSkill, 0, requiredSkill, resource, quantity); + } + + public static bool AddSocket(Mobile from, object target, int maxSockets, double difficulty, SkillName requiredSkill, + double difficulty2, SkillName requiredSkill2, Type resource, int quantity) + { + + if(maxSockets == 0 || target == null || from == null) return false; + + + // is it in the pack + if ( target is Item && !((Item)target).IsChildOf( from.Backpack )) + { + from.SendMessage("Must be in your backpack."); + return false; + } + else + if ( target is BaseCreature && ((BaseCreature)target).ControlMaster != from) + { + from.SendMessage("Must be under your control."); + return false; + } + + // check the target range + if ( target is Mobile && !Utility.InRange( ((Mobile)target).Location, from.Location, MaxSocketDistance )) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return false; + } + + + int nSockets = 0; + + // first see if the target has any existing sockets + + ArrayList plist = XmlAttach.FindAttachments(target,typeof(XmlSockets)); + + XmlSockets s = null; + + if(plist != null && plist.Count > 0) + { + s = plist[0] as XmlSockets; + + // find out how many sockets it has + nSockets = s.NSockets; + } + + // already full, no more sockets allowed + if(nSockets >= maxSockets && maxSockets >= 0) + { + from.SendMessage("This cannot be socketed any further."); + return false; + } + + // try to add a socket to the target + + // determine the difficulty based upon the required skill and the current number of sockets + + int successchance = ComputeSuccessChance( from, nSockets, difficulty, requiredSkill, difficulty2, requiredSkill2); + + if(successchance <= 0) + { + from.SendMessage("You have no chance of socketing this."); + return false; + } + + // consume the resources + + if(from.Backpack != null && resource != null && quantity > 0) + { + if(!from.Backpack.ConsumeTotal( resource, quantity, true)) + { + from.SendMessage("Socketing this requires {0} {1}",quantity, resource.Name); + return false; + } + } + + from.PlaySound( 0x2A ); // play anvil sound + + if(Utility.Random(1000) < successchance*10) + { + from.SendMessage("You have successfully added a socket the target!"); + if(s != null) + { + // add an empty socket + s.SocketOccupants.Add(null ); + + } + else + { + // add an xmlsockets attachment with the new socket + s = new XmlSockets(1); + XmlAttach.AttachTo(target, s); + } + + if(s != null) + s.InvalidateParentProperties(); + + from.SendGump(new SocketsGump(from, s)); + + } + else + { + from.SendMessage("Your attempt to add a socket to the target was unsuccessful."); + // if it fails then there is also a chance of destroying it + if(DefaultDestructionProbability > 0 && Utility.RandomDouble() < DefaultDestructionProbability) + { + + from.SendMessage("You destroy the target while attempting to add a socket to it."); + + if(target is Item) + { + ((Item)target).Delete(); + + } + else + if(target is BaseCreature) + { + ((BaseCreature)target).Delete(); + } + + from.CloseGump(typeof(SocketsGump)); + + return false; + } + } + + return true; + } + + public static bool Augment( Mobile from, object parent, XmlSockets sock, int socketnum, IXmlSocketAugmentation a) + { + if(parent == null || a == null || sock == null || socketnum < 0) + { + if(a != null && from == null) a.Delete(); + + return false; + } + + if(sock.SocketOccupants != null && sock.NFree >= a.SocketsRequired && sock.SocketOccupants.Count > socketnum && a.OnAugment(from, parent)) + { + SocketOccupant occ = new SocketOccupant(a.GetType(), a.Version, a.Icon, a.IconXOffset, a.IconYOffset, a.IconHue, a.UseGumpArt, + String.Format("{0}\n{1}\n{2} Socket(s)",a.Name,a.OnIdentify(null),a.SocketsRequired)); + + int remaining = a.SocketsRequired; + + // make sure the requested socket is unoccupied + if(sock.SocketOccupants[socketnum] == null) + { + sock.SocketOccupants[socketnum] = occ; + remaining--; + } + + // if this augmentation requires more than 1 socket, then fill the rest + if(remaining > 0) + { + // find a free socket + for(int i = 0;i 0) + { + + // recover the augment + augment.OnRecover(from, o, s.AugmentationVersion); + + // clear all of the sockets that it occupied + int count = augment.RecoverableSockets(s.AugmentationVersion); + for(int i = 0; i < SocketOccupants.Count; i++) + { + if(SocketOccupants[i] != null && ((SocketOccupant)SocketOccupants[i]).OccupantType == t && ((SocketOccupant)SocketOccupants[i]).AugmentationVersion == s.AugmentationVersion) + { + SocketOccupants[i] = null; + count--; + if(count <= 0) break; + } + } + + } + else + { + augment.Delete(); + return null; + } + } + + return augment; + } + + public BaseSocketAugmentation RecoverRandomAugmentation(Mobile from, object o) + { + int nfilled = NSockets - NFree; + + if(nfilled > 0) + { + // pick a random augmentation from a filled socket + int rindex = Utility.Random(nfilled); + int count = 0; + for(int i = 0; i < SocketOccupants.Count; i++) + { + if(SocketOccupants[i] != null) + { + if(count == rindex) + { + // reconstruct the augment + BaseSocketAugmentation augment = RecoverAugmentation(from, o, i); + + return augment; + } + count++; + } + } + } + + return null; + } + + + private class AddAugmentationToSocket : Target + { + private object m_parent; + private XmlSockets m_s; + private int m_socketnum; + + public AddAugmentationToSocket(object parent, XmlSockets s, int socketnum) : base ( 30, false, TargetFlags.None ) + { + m_parent = parent; + m_socketnum = socketnum; + m_s = s; + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(from == null || targeted == null) return; + + // is this a valid augmentation + if(targeted is IXmlSocketAugmentation) + { + IXmlSocketAugmentation a = targeted as IXmlSocketAugmentation; + + // check the augment + if ( a is Item && !((Item)a).IsChildOf( from.Backpack )) + { + from.SendMessage("Augmentation must be in your backpack."); + return; + } + else + if ( a is BaseCreature && ((BaseCreature)a).ControlMaster != from) + { + from.SendMessage("Augmentation must be under your control."); + return; + } + + // check the parent + if ( m_parent is Item && !((Item)m_parent).IsChildOf( from.Backpack ) && m_s != null && m_s.MustAugmentInPack) + { + from.SendMessage("Socketable item be in your backpack."); + return; + } + else + if ( m_parent is BaseCreature && ((BaseCreature)m_parent).ControlMaster != from) + { + from.SendMessage("Socketable creature must be under your control."); + return; + } + + // check the parent range + if ( ( m_parent is Item && ((Item)m_parent).Parent == null) || m_parent is Mobile) + { + Point3D loc = from.Location; + + if(m_parent is Item) + { + loc = ((Item)m_parent).Location; + } + else + if(m_parent is Mobile) + { + loc = ((Mobile)m_parent).Location; + } + + + if ( !Utility.InRange( loc, from.Location, MaxAugmentDistance ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + } + + if (a.CanAugment(from, m_parent, m_socketnum)) + { + + // check for sufficient available sockets + if( m_s == null || m_s.NFree < a.SocketsRequired) + { + from.SendMessage("Not enough available sockets for that augmentation."); + return; + } + + if(!a.ConsumeOnAugment(from)) + { + from.SendMessage("You are lacking the resources needed to use that augmentation."); + return; + } + + from.PlaySound( 0x2A ); // play anvil sound + + // add the augmentation to the socket + if(Augment(from, m_parent, m_s, m_socketnum, a)) + { + // refresh the gump + from.CloseGump(typeof(SocketsGump)); + from.SendGump(new SocketsGump(from, m_s)); + from.SendMessage("You successfully augment the target."); + + m_s.InvalidateParentProperties(); + + + + } + else + { + from.SendMessage("The augmentation fails."); + } + } + else + { + from.SendMessage("That cannot be used in this socket."); + + } + } + else + { + from.SendMessage("That is not a valid augmentation."); + } + } + } + + + public class AddSocketToTarget : Target + { + //private CommandEventArgs m_e; + private int m_extrasockets; + + public AddSocketToTarget( ) : this ( 0 ) + { + } + + public AddSocketToTarget( int extrasockets) : base ( 30, false, TargetFlags.None ) + { + m_extrasockets = extrasockets; + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(from == null || targeted == null) return; + + + int maxSockets = DefaultMaxSockets; + double difficulty = DefaultSocketDifficulty; + SkillName skillname = DefaultSocketSkill; + double difficulty2 = DefaultSocketDifficulty; + SkillName skillname2 = DefaultSocketSkill; + Type resource = DefaultSocketResource; + int quantity = DefaultSocketResourceQuantity; + + // see if this has an XmlSocketable attachment that might impose socketing restrictions + ArrayList plist = XmlAttach.FindAttachments(targeted,typeof(XmlSocketable)); + + if(plist != null && plist.Count > 0) + { + XmlSocketable s = plist[0] as XmlSocketable; + // get the socketing restrictions + maxSockets = s.MaxSockets; + // and any difficulty restrictions + difficulty = s.MinSkillLevel; + skillname = s.RequiredSkill; + difficulty2 = s.MinSkillLevel2; + skillname2 = s.RequiredSkill2; + resource = s.RequiredResource; + quantity = s.ResourceQuantity; + } + else + if(!CanSocketByDefault && m_extrasockets <= 0) + { + from.SendMessage("This cannot be socketed."); + return; + } + + if(maxSockets < 0 && m_extrasockets > 0) + { + maxSockets = 0; + } + + + // override maximum socket restrictions + maxSockets += m_extrasockets; + + AddSocket(from, targeted, maxSockets, difficulty, skillname, difficulty2, skillname2, resource, quantity); + } + } + + public class RecoverAugmentationFromTarget : Target + { + //private CommandEventArgs m_e; + + public RecoverAugmentationFromTarget( /*CommandEventArgs e*/) : base ( 30, false, TargetFlags.None ) + { + //m_e = e; + } + protected override void OnTarget( Mobile from, object targeted ) + { + if(from == null || targeted == null) return; + + // see if the target has an XmlSockets attachment + XmlSockets s = XmlAttach.FindAttachment(targeted,typeof(XmlSockets)) as XmlSockets; + + if(s == null) + { + from.SendMessage("This is not socketed."); + return; + } + + BaseSocketAugmentation augment = s.RecoverRandomAugmentation(from, targeted); + + if(augment != null) + { + from.SendMessage("Recovered a {0} augmentation.", augment.Name); + from.AddToBackpack(augment); + + // update the sockets gump + s.OnIdentify(from); + } + else + { + from.SendMessage("Failed to recover augmentation."); + } + } + } + + [Usage( "AddSocket" )] + [Description( "Attempts to add a socket to the targeted item." )] + public static void AddSocket_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new AddSocketToTarget(); + } + + private class SocketsGump : Gump + { + private XmlSockets m_attachment; + private const int vertspacing = 65; + + public SocketsGump( Mobile from, XmlSockets a) : base( 0,0) + { + if(a == null) + { + return; + } + if(from != null) + from.CloseGump(typeof( SocketsGump)); + + m_attachment = a; + + int socketcount = 0; + + if(a.SocketOccupants != null) + { + socketcount = a.SocketOccupants.Count; + } + + // prepare the page + AddPage( 0 ); + + AddBackground( 0, 0, 185, 137 + socketcount*vertspacing, 5054 ); + + AddImage( 2 , 2 , 0x28d4); // garg top center + + AddImageTiled( 2 , 52 , 30, 50 + socketcount*vertspacing, 0x28e0); // left edge + + AddImageTiled( 151 , 52 , 30, 50 + socketcount*vertspacing, 0x28e0); // right edge + + AddImageTiled( 40 , 104 + socketcount*vertspacing , 121, 30, 0x28de); // bottom edge + AddImage( 143 , 84 + socketcount*vertspacing , 0x28d2); // garg bottom right + AddImage( 2 , 84 + socketcount*vertspacing , 0x28d2); // garg bottom left + + string label = null; + + if(m_attachment.AttachedTo is Item) + { + Item item = m_attachment.AttachedTo as Item; + + label = item.Name; + + if(item.Name == null) + { + label = item.ItemData.Name; + } + + } + else + if(m_attachment.AttachedTo is Mobile) + { + Mobile m = m_attachment.AttachedTo as Mobile; + + label = m.Name; + } + + int xadjust = 50; + if(label != null) + xadjust -= label.Length*5/2; + + if(xadjust < 0) xadjust = 0; + + AddLabelCropped( 34 + xadjust, 60, 110-xadjust, 20, 55, label ); + + // go through the list of sockets and add buttons for them + int xoffset = 62; + int y = 98; + for(int i = 0;i + + + KeyAugment#1 + 8add4ae9-61eb-491b-9b6a-cbf1f09ddfac + Felucca + 5441 + 1159 + 10 + 10 + 5446 + 1164 + 0 + 5 + 4 + 5 + 10 + False + 0 + 0 + -1 + 500 + 1 + False + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + False + -1 + False + False + 0 + 1 + True + True + True + metaldoor,0/name/Sesame/locked/true/keyvalue/12345/ATTACH/xmlsockets,1,false:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=keyaugment/name/Sesame/keyvalue/12345/usesremaining/-1:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=metaltreasurechest/name/Sesame's treasure/locked/true/keyvalue/2345/ATTACH/xmlsockets,1,false:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=keyaugment/name/Sesame's treasure/itemid/6884/keyvalue/2345:MX=1:SB=0:RT=0:TO=0:KL=0 + + \ No newline at end of file diff --git a/Scripts/Customs/XmlSockets_20_v108a/socket1.xml b/Scripts/Customs/XmlSockets_20_v108a/socket1.xml new file mode 100644 index 0000000..706f78b --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/socket1.xml @@ -0,0 +1,45 @@ + + + + Socket#1 + 0a389f1d-ce76-4f87-a0a0-ba47d2721cbc + Felucca + 5443 + 1155 + 8 + 8 + 5447 + 1159 + 0 + 5 + 11 + 5 + 10 + False + 0 + 0 + -1 + 500 + 1 + False + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + False + -1 + False + False + 0 + 1 + True + True + True + kryss/ATTACH/xmlsocketable,3:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=orc/ADD/<warhammer/ATTACH/xmlsocketable>:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=bow/ATTACH/xmlsockets,2/ATTACH/xmlsocketable,4,Fletching,100,emerald,30:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=platelegs/ATTACH/xmlsocketable,4/ATTACH/xmlsockets,1:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=dragon/ATTACH/xmlsocketable,2,Veterinary,100,goldingot,100:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=testsocketedweapon:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=bag/hue/50/name/Gem Augmentations/ADD/legendarydiamond/ADD/ancientdiamond/ADD/ancientruby/ADD/ancientsapphire/ADD/legendaryruby/ADD/ancientemerald/ADD/legendaryemerald/ADD/ancientamethyst/ADD/legendaryamethyst/ADD/legendarysapphire/ADD/mythicdiamond/ADD/mythicemerald/ADD/mythicsapphire/ADD/mythicamethyst/ADD/mythicruby:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=bag/hue/40/name/Other Augmentations/ADD/ancientwood/ADD/legendarywood/ADD/ancientskull/ADD/legendaryskull/ADD/mythicskull/ADD/mythicwood:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=bag/hue/11/name/Rune Augmentations/ADD/ahmrune/ADD/tyrrune/ADD/morrune/ADD/mefrune/ADD/ylmrune/ADD/kotrune/ADD/jorrune:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=bag/hue/8/name/Crystal Augmentations/ADD/fencrystal/ADD/rhocrystal/ADD/ryscrystal/ADD/wyrcrystal/ADD/frecrystal/ADD/torcrystal/ADD/velcrystal/ADD/xencrystal/ADD/polcrystal/ADD/wolcrystal/ADD/balcrystal/ADD/talcrystal/ADD/jalcrystal/ADD/jalcrystal/ADD/ralcrystal/ADD/kalcrystal:MX=1:SB=0:RT=0:TO=0:KL=0:OBJ=bag/hue/33/name/Radiant Augmentations/ADD/radiantrhocrystal/ADD/radiantryscrystal/ADD/radiantwyrcrystal/ADD/radiantfrecrystal/ADD/radianttorcrystal/ADD/radiantvelcrystal/ADD/radiantxencrystal/ADD/radiantpolcrystal/ADD/radiantwolcrystal/ADD/radiantbalcrystal/ADD/radianttalcrystal/ADD/radiantjalcrystal/ADD/radiantjalcrystal/ADD/radiantralcrystal/ADD/radiantkalcrystal:MX=1:SB=0:RT=0:TO=0:KL=0 + + \ No newline at end of file diff --git a/Scripts/Customs/XmlSockets_20_v108a/xmlsockets.txt b/Scripts/Customs/XmlSockets_20_v108a/xmlsockets.txt new file mode 100644 index 0000000..c9a0173 --- /dev/null +++ b/Scripts/Customs/XmlSockets_20_v108a/xmlsockets.txt @@ -0,0 +1,400 @@ +XmlSockets v1.08a +updated 4/13/05 +ArteGordon + +[b]SUMMARY[/b] +This set of attachments provides a system for adding sockets and socket augmentations to items and mobs. The XmlSockets attachment adds sockets that can be filled with augmentations that will enhance specific abilities. The XmlSocketable attachment enables player-addable sockets that can be added to the target object by players meeting customizable skill and resources requirements. + +[b]New to v1.08a[/b] +updated 4/13/05 +- added a new powerscroll transmutation recipe to the BoxOfTransmutation that takes any 3 powerscrolls of the same level, along with a legendary diamond, legendary ruby, and legendary emerald, and creates a new random powerscroll of the same level. + +- added some recipes for transmuting large and small BODs. Transmuting a small BOD and 2000 gp will give you a new random small BOD of the same type. Transmuting 20000 gp and a large BOD will give you a random large BOD of the same type. + +- the XmlMobFactions recipes are now properly commented out. + +[b]New to v1.08[/b] +updated 3/10/05 +[b]- slightly modified the transmutation rules so that a recipe that specifies an ingredient in any quantity (quantity requirement of 0) still requires at least one of that ingredient.[/b] + +[b]- added the option to specify a second skill requirement for socketing[/b] (thanks to Greystar for the suggestion). The XmlSocketable attachment now has 2 additional properties, RequiredSkill2 and MinSkillLevel2. By default MinSkillLevel2 is 0 so there is no second skill requirement. +To support the requirement for a second skill, several new methods and constructors have been added. You can spawn an object with a second socketable skill requirement like this + +buckler/ATTACH/xmlsocketable,2,Tinkering,115,ArmsLore,70,gold,2000 + +You can also randomly configure a socketed/socketable object with two skill requirements in scripts using the new ConfigureRandom overload method, like this + +XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0, SkillName.Veterinary, 100.0, SkillName.AnimalLore, 90.0, typeof(Emerald), 30); + +which will add a random socketable/socketed configuration to the target with a minimum 100 veterinary skill as well as a minimum 90 animal lore skill on socketing. + +There is also a new XmlSocketable constructor that accepts the additional skill requirements if you wish to add socketing to items in your own scripts. + +public XmlSocketable(int maxsockets, SkillName skillname, double minskilllevel, SkillName skillname2, double minskilllevel2, Type resource, int quantity) + +[b]- added the ability to recover augmentations from sockets.[/b] Specific augmentations must have the ability to be recovered enabled by defining the CanRecover and OnRecover override methods in their scripts. If these are not defined for a particular augmentation, then they will not be recoverable. +Augmentations that can be recovered and are already socketed into an item will be identified as such by clicking on their socket in the socket display gump. If the augmentation can be recovered you will see "Can be recovered" at the end of the description. +Note that it is possible for an augmentation to be recoverable in certain items and not others if you wish, or even dependent on the individual trying to do the recovery (based on karma, fame, etc.). Just put the desired conditions in the CanRecover override method for the given augmentation. +A version argument has been added to the CanRecover and OnRecover calls to allow you to make changes to augmentations but still control how older versions are handled. +If you do make changes to existing augmentations you should override the Version property for that augmentation and return an updated value (the default is zero). +If you make changes to the number of sockets used by an augmentation and previous versions of the augmentation been used, and you make the augmentation recoverable, then you should override the RecoverableSockets method and return the proper value based on the version number. + +[b]- added a new recipe to the BoxOfTransmutation for recovering augmentations from items.[/b] Transmuting an augmented item and an AncientRuby will allow a random augmentation from the item to be recovered. + +[b]- added the new HammerOfRecovery item that can be used to recover augmentations from a target.[/b] This can be used to recover augmentations from items or creatures. + +[b]- added a new recipe to the BoxofTransmutation for creating a single use HammerOfRecovery from a regular hammer and an AncientRuby [/b] This allows players with the proper skills and resources to create a hammer that could be given to other players to allow them to remove augmentations. + +[b]- updated the crystal, radiant crystal, gem, and skull augments to support recovery.[/b] + + +[b]New to v1.07[/b] +updated 2/13/05 +- fixed a possible crash bug involving the display of Socket properties on items that are on the generic vendor buy lists. + +- added a new transmutation container item, the BagOfResources that takes the arrow/bolt recipes and the hides/bandage recipe out of the BoxOfTransmutation. The BoxOfTransmutation now just contains augmentation related recipes. + +[b]New to v1.06[/b] +updated 1/31/05 + +[b]- added an interface specification to some of the existing augments to facilitate their use in the new transmutation system.[/b] + +[b]- added the new items BoxOfTransmutation and MagicBasket.[/b] They can be made with limited or unlimited uses (setting the UsesRemaining property to a value less than zero gives unlimited use). + +[b]- added the new BaseTransmutationContainer class that allows you to make containers that can magically create objects based upon specifiable recipes.[/b] The recipes are made up of lists of ingredients that when placed into the container in exactly the right quantity and with the correct properties, can be transformed into other objects. +Each recipe can also optionally have multiple minimum skill and stat requirements. + +Two examples of transmutation devices are included. To test them out just [add magicbasket, or [add boxoftransmutation. They can also be made with limited uses with e.g. [add magicbasket 50 for a 50 use basket. + +The transmutation gump can be opened either by placing objects into the container, or by selecting the 'Use this device' context menu option. + +[b]The MagicBasket[/b] has one recipe defined that requires cooking skill and makes a meat pie out when the following ingredients are used: 2 raw ribs, 1 garlic, 1 bowl of flour, 1 full pitcher of milk, 4 carrots. It requires 30 cooking skill, 30 dex, and 20 int. + +[b]The BoxOfTransmutation[/b] has recipes for manipulating augments, and socketed weapons/armor, and a few other things. +Here are the recipes that it has defined: + +[b]HidesToBandages:[/b] will change any amount of hides into bandages +Req - 50 str, 30 dex + +[b]BoltsToArrows:[/b] will change any amount of bolts into half the quantity of arrows +Req - 50 ArmsLore, 70 str, 30 dex + +[b]ArrowsToBolts:[/b] will change any amount of arrows into half the quantity of bolts +Req - 50 ArmsLore, 70 str, 30 dex + +[b]UpgradeAncientAugment:[/b] will take 6 Ancient augments and convert them to a Legendary augment of the same type. +Req - 50 Alchemy, 70 str, 30 dex, 40 int + +[b]UpgradeLegendaryAugment:[/b] will take 3 Legendary augments and convert them to a Mythic augment of the same type. +Req - 70 Alchemy, 70 str, 30 dex, 40 int + +[b]UpgradeCrystalAugment: will take 3 Crystal augments and convert them to a Radiant augment of the same type.[/b] +Req - 70 Alchemy, 70 str, 30 dex, 40 int + +[b]SocketWeapon:[/b] will take any unsocketed weapon and a Rho rune augment and add a single socket to the weapon. +Req - 50 Blacksmith, 70 str, 30 dex, 40 int + +[b]SocketArmor:[/b] will take any unsocketed armor and a Rho rune augment and add a single socket to the armor. +Req - 50 Blacksmith, 70 str, 30 dex, 40 int + +some additional recipes that allow various mob faction bonuses to be granted with recipes that use a combination of glimmering stone augments and gold are included. These require the XmlMobFactions system to be installed. +These are commented out by default. If you have XmlMobFactions installed and you wish to use these, just uncomment them. + +An arbitrary number of additional recipes can be specified. You could also construct different transmutation container classes (derived from the BaseTransmutationContainer class) that implemented different recipe sets. + + +[b]New to v1.05[/b] +updated 1/22/05 +[b]- made an adjustment to the default gump art hues for augments so that they match the item hues.[/b] + +[b]- added another gem augment (tourmaline) and updated the optional Loot.cs to reflect this.[/b] + +[b]- added a set of glimmering stone augments that grant various skill bonuses.[/b] + +[b]- updated installation instructions for 1.0.0[/b] + +[b]- updated the optional modified lootpack.cs/loot.cs files to 1.0.0[/b] + + +[b]INSTALLATION:[/b] +for RC0. + +[u]STEP 1:[/u] +Install the latest XmlSpawner2 package (must be at least version 2.70. You can find it here [URL=http://www.runuo.com/forum/showthread.php?t=30848]XmlSpawner2[/URL]). Make sure that you perform installation step 8 from that thread. I would also strongly suggest performing step 11 from that thread to allow socket properties to be automatically displayed. + +[u]STEP 2: [/u] +Place the scripts from this package into your custom scripts directory, or into the XmlAttachments area of your XmlSpawner2 installation. (anywhere in your Scripts folder is fine, these locations are suggested for organizational purposes only). +Place the optional .xml example in the top level of your RunUO installation directory if you would like to try it out. +If you have also installed the custom attacks/defenses system ([URL=http://www.runuo.com/forum/showthread.php?t=46761]XmlCustomAttacks[/URL]) then you can extract the runeaugments.cs file. If you do not have that system, then do not extract that file. + +[u]STEP 3: (optional)[/u] +To automatically add sockets and socketability to dropped weapons and armor and tamable creatures with some probability, you can make these changes to BaseArmor.cs, BaseWeapon.cs, BaseJewel.cs, and BaseCreature.cs. If you make this modification, all weapons/armor/tamable creatures will have some chance of having sockets when they are made. If you would rather put the modifications somewhere else, such as in LootPack.cs, that would work as well. + +First, place the following line at the beginning of the files BaseArmor.cs, BaseWeapon.cs, BaseJewel.cs, and BaseCreature.cs + +using Server.Engines.XmlSpawner2; + +then, at the end of the BaseArmor constructor around line 1121 in Scripts/Items/Armor/BaseArmor.cs +change this + + m_AosSkillBonuses = new AosSkillBonuses( this ); + +to this + + m_AosSkillBonuses = new AosSkillBonuses( this ); + + // mod to randomly add sockets and socketability features to armor. These settings will yield + // 2% drop rate of socketed/socketable items + // 0.1% chance of 5 sockets + // 0.5% of 4 sockets + // 3% chance of 3 sockets + // 15% chance of 2 sockets + // 50% chance of 1 socket + // the remainder will be 0 socket (31.4% in this case) + // uncomment the next line to prevent artifacts from being socketed + // if(ArtifactRarity == 0) + XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0); + +at the end of the BaseWeapon constructor around line 2525 in Scripts/Items/Weapons/BaseWeapon.cs +change this + + m_AosSkillBonuses = new AosSkillBonuses( this ); + +to this + + m_AosSkillBonuses = new AosSkillBonuses( this ); + + // mod to randomly add sockets and socketability features to weapons. These settings will yield + // 2% drop rate of socketed/socketable items + // 0.1% chance of 5 sockets + // 0.5% of 4 sockets + // 3% chance of 3 sockets + // 15% chance of 2 sockets + // 50% chance of 1 socket + // the remainder will be 0 socket (31.4% in this case) + // uncomment the next line to prevent artifacts from being socketed + // if(ArtifactRarity == 0) + XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0); + +at the end of the BaseJewel constructor around line 93 in Scripts/Items/Jewels/BaseJewel.cs +change this + + Layer = layer; + +to this + + Layer = layer; + + // mod to randomly add sockets and socketability features to weapons. These settings will yield + // 2% drop rate of socketed/socketable items + // 0.1% chance of 5 sockets + // 0.5% of 4 sockets + // 3% chance of 3 sockets + // 15% chance of 2 sockets + // 50% chance of 1 socket + // the remainder will be 0 socket (31.4% in this case) + // uncomment the next line to prevent artifacts from being socketed + // if(ArtifactRarity == 0) + XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0); + +make this change in the BaseCreature class around line 743 in Scripts/Engines/AI/Creature/BaseCreature.cs change + + +public override void OnBeforeSpawn( Point3D location, Map m ) + { + if ( Paragon.CheckConvert( this, location, m ) ) + IsParagon = true; + + base.OnBeforeSpawn( location, m ); + } +to this + +public override void OnBeforeSpawn( Point3D location, Map m ) + { + if ( Paragon.CheckConvert( this, location, m ) ) + IsParagon = true; + + + // mod to randomly add socket features to tamable creatures. These settings will yield + // 2% drop rate of socketed/socketable items + // 0.1% chance of 5 sockets + // 0.5% of 4 sockets + // 3% chance of 3 sockets + // 15% chance of 2 sockets + // 50% chance of 1 socket + // the remainder will be 0 socket (31.4% in this case) + // Adding new sockets will require a minimum of 100 Veterinary skill and 30 emeralds + if(Tamable) + XmlSockets.ConfigureRandom(this, 2.0, 0.1, 0.5, 3.0, 15.0, 50.0, SkillName.Veterinary, 100.0, typeof(Emerald), 30); + + base.OnBeforeSpawn( location, m ); + } + +STEP 4: (optional) +I have added modified distro 1.0.0 versions of Loot.cs and LootPack.cs that will give random lootpack drops of augmentations. The frequency of drop is low (about the same as instruments), and the definitions include the rune augmentations (if you dont have runeaugments.cs installed then comment out the sections referring to the runes). To use them, either replace the distro Scripts/Misc/LootPack.cs and Scripts/Misc/Loot.cs with the versions in the SocketsLootMod.zip file (always make backups of your original scripts), or just look in those files for the changes marked "ARTEGORDONMOD", and incorporate them into your existing lootpack.cs and loot.cs files. +Note, I intentionally renamed the files with ._cs extensions so that they wouldnt cause problems if you extracted them into your scripts area. The extensions need to be changed to .cs if you wish to use them as replacements for the distro loot.cs and lootpack.cs scripts. + + +[b]DESCRIPTION:[/b] + +This system makes use of the XmlSpawner2 attachment system and the XmlSpawner2 package must be installed to support it. You dont need to use the xmlspawners themselves, and it doesnt matter whether you use the standard distribution spawners or any other spawning system but you do need the XmlSpawner2 package installed. + +Because the attachment system neither requires nor makes any changes to serialization/deserializations of any item or mobile, it can be safely added and removed at any time now or in the future without interfering with any other systems that you might have installed. + +Note, this is intended as more of a development system for people to add custom content to their shards than just a drop-and-play system with a full complement of socket augmentations. While I have included a number of augmentations in the package that can be used as-is, they are intended to illustrate its features so that users can extend them with additional content. + +[b][u]Features:[/u][/b] + +Note that ANY object can in principle be socketed - weapons, armor, jewelry, clothing, tools, trees, doors, fruit, creatures, players, gems - anything. You just have to tag them with the sockets/socketable attachments using one of the methods described below. It is then the responsibility of the augment to determine what it can affect and what effect it has on the socketed object. + +[u]Sockets[/u] +Sockets allow target objects to be enhanced by providing slots in which specially designed augmentations can be placed. Different augmentations will confer different abilities to the target. +Sockets can either come pre-existing on a target, or can be added by an individual with sufficient skill and resources. + +[u]Socketability[/u] +Individual objects can be flagged as being "socketable", by adding the XmlSocketable attachment which allows the maximum number of sockets, the type of skill and minimum skill level required to socket, and the resources used in socketing, to be specified. By default 100 Blacksmithing and 50 Valorite ingots are required to add a socket to a target. + +[u]Augmenting[/u] +To add an augmentation to a socket, both the augmentation and the item to be augmented must be in the players pack. To bring up the socket gump you must use the item identification skill on the item. In the gump, click on the socket and target the augmentation. By default, augmenting requires no resources and will always succeed. This behavior can be changed in the ConsumeOnAugment and OnAugment override methods for individual augmentations. +After a socket has been filled with an augmentation, clicking on the socket will display the augmentation properties. + +[u]Item Identification.[/u] This skill is used to display the sockets and socketability of target objects. Just use the skill and target an object (either items or creatures). + +[u]Examples.[/u] Examples of socketed/socketable objects including tamable creatures such as a socketable dragon are included in the example .xml file socket1.xml. To try this out, place the file "socket1.xml" in your top level RunUO directory and execute the command "[xmlloadhere socket1.xml" +It creates several bags of augmentations and various socketed and socketable items. The dragon can be socketed after it is tamed. + + +[b][u]Commands/Control Items:[/u][/b] + +[u][addsocket[/u] - To add a socket to a socketable object the player issues the "[addsocket" command and targets an object. If the target is an item, then the item must be in the players backpack. If the target is a creature, then the creature must be under the players control. If socketing is successful, you will see the new socket in the socket gump. On each failure resources will still be consumed and there is a 10% chance that the target will be destroyed (this probability can be set by the static DefaultDestructionProbability variable in XmlSocket.cs). +The difficulty of adding a socket depends on the minimum skill required by the object, the skill level of the player, and the existing number of sockets. +The chance of succeeding in adding a socket can be displayed by using the Item Identification skill on a socketable object. + +[u]SocketHammer[/u] - an item that provides the same functionality as the [addsocket command. Just double-click to use and target the object to be socketed. It can be given either limited (set UsesRemaining to a value > 0) or unlimited number of uses (set UsesRemaining to a value < 0). + + +[b][u]Adding sockets to items/mobs[/u][/b] + +[u]Manually to individual item/mobs [/u] + +- the xmlSockets attachment can be added to objects in several ways. It can be manually attached to any existing object with the "[addatt" command. + +For example + +"[addatt xmlsockets 4" + +will add 4 sockets to a targeted object. + + +[u]To scripts[/u] + +- Sockets can also be added to scripted objects. See the included script TestSocketedWeapon.cs for an example of this. + +[u]To spawned objects[/u] + +- To add sockets to spawned objects use the ATTACH keyword in spawn entries such as this + +katana/ATTACH/xmlsockets,4 + +which would spawn a katana with 4 sockets. + +or + +orc/ADD/ + +would spawn an orc carrying the socketd katana. + +To try out the included example spawner .xml file, place the file "socket1.xml" in your top level RunUO directory and execute the command + +"[xmlloadhere socket1.xml" + + +[b][u]Making items/mobs socketable by players[/u][/b] + +[u]Manually to individual item/mobs [/u] + +- the xmlSocketable attachment can be added to objects in several ways. It can be manually attached to any existing object with the "[addatt" command. + +For example + +"[addatt xmlsocketable 4" + +will flag the target object as socketable and supporting a maximum of 4 player-added sockets. + + +[u]To scripts[/u] + +- Socketability can also be added to scripted objects. See the included script TestSocketedWeapon.cs for an example of this. + +[u]To spawned objects[/u] + +- To add sockets to spawned objects use the ATTACH keyword in spawn entries such as this + +katana/ATTACH/xmlsocketable,4 + +which would spawn a katana supporting a maximum of 4 player-added sockets. + +buckler/ATTACH/xmlsocketable,2,Tinkering,115,gold,2000 + +which would spawn a buckler supporting a maximum of 2 player-added sockets that require a minimum of 115 Tinkering and 2000 gold to add. + + +Changelog + +Version 1.04 +updated 12/26/04 + +- added support for adding augments via scripts instead of just via player targeting (thanks to sUpplier1 for the suggestion). + +- added a new example of this feature in testsocketedweapon.cs (case 3) + +- minor change in reporting of objects that have already reached their maximum number of allowed sockets. It no longer describes the requirements and socketing chance for such objects. + +- minor change in property list display of socketable objects. The resource and skill requirements will no longer be displayed on mouseover. That info can still be obtained by using the Item Identification skill on the object. + +- the random socket/socketable configuration method "ConfigureRandom" will no longer create 0-socketable configurations (thanks to sUpplier1 for pointing this out). + +- added jewelry support to the crystal and radiant crystal augments. + +- modified installation step 3 to support randomly socketed jewelry drops and to allow you to exclude the possibility of socketed artifacts if you like. + + + +Version 1.03 +updated 12/07/04 + +- added 29 new augmentations in two sets, Crystals (2 socket) and RadiantCrystals (4 socket). + +- modified the optional Loot.cs file to support lootpack drops of these augments. + +- updated the socket1.xml example to include a bags of the new augments. + +Version 1.02 +updated 12/03/04 + +- added an additional XmlSockets constructor that allows the default requirement for socketed items to be in the players pack when augmenting to be overridden. "[addatt xmlsockets 1 false" for example would allow you to attach a single socket that did not require the socketed item to be in the players pack when augmenting. +This can be useful for allowing items in the world such as doors to be augmented. + +- added a new augmentation called a "keyaugment". This can be used to open doors and chests by assigning it a KeyValue that matches the KeyValue of the door/chest, and then using it to augment a socket on the door/chest. A skill requirement can also be assigned to it as can the number of uses. This is an example of placing additional constraints on the use of augmentations in the OnAugment method. + +- added an example of a socketed door and socketed chest that open when a master thief places the proper keyaugment into the socket. This can be tested by loading the keyaugment.xml example. Use item identify on the door named "Sesame" to bring up the socket gump, and then augment it with the special "Sesame" rune (you must have at least 100 lockpicking). After opening, the door resockets itself so that it has to be augmented again to be opened. The chest can be opened in the same way with the "Sesame's treasure" keyaugment that has the form of a skull. That one requires 100 Stealing to use. Notice how the keyaugment to open the door does not get destroyed after it is used, while the one to the chest does. This is due to the UsesRemaining property that has been set on it. Setting this to a value < 0, gives it unlimited uses. Setting it to a value > 0 gives it the specified number of uses (a value of 1 would be the default single-use case). + +- shifted the SocketAugmentations entries in the optional LootPack.cs mods to the ends of each lootpack list to reduce luck-enhanced chance of dropping augments. The way lootpacks work, entries near the top of the list have the greatest chance of being added due to luck, and the luck-computed drop probability is generally much higher than the drop chance specified for each entry (particularly if the entry chance is supposed to be low which is why you get so many luck-related magic item drops on poor lootpack mobs). + +- added a range check for socketing creatures (maximum distance 2) + +version 1.01 +updated 12/1/04 + +- added a set of Mythic augments that are 3 socket augmentations in addition to the Ancient (1 socket) and Legendary (2 socket) types. Loot.cs was modified to reflect the change. + +- the augments have been organized into a separate folder replacing the previous files otheraugments.cs, gemaugments.cs (you should get rid of those if you had them from an earlier installation or your will get errors about things being already defined). + +- added the SocketHammer item as an alternative to the [addsocket command to add sockets to target objects. Just double click the hammer and target the object to be socketed. Setting the number of uses to a value greater than zero will give it limited uses. Setting it less than zero makes it unlimited. + +- having an item with an existing socket number that exceeds the maxsockets indicated in its XmlSocketable attachment will now automatically have that max adjusted to match the current number of existing sockets. It is basically just a cosmetic change to avoid confusion in the way the available sockets are reported. Some players were getting confused by items that indicated the maxsockets allowed as 1, and the available sockets as 2 for example. This just meant that the item already had 2 sockets, but that you could not add any additional sockets beyond 1. + + + + + diff --git a/Scripts/Engines/BulkOrders/Books/BOBFilter.cs b/Scripts/Engines/BulkOrders/Books/BOBFilter.cs new file mode 100644 index 0000000..fc73a42 --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BOBFilter.cs @@ -0,0 +1,88 @@ +using System; + +namespace Server.Engines.BulkOrders +{ + public class BOBFilter + { + private int m_Type; + private int m_Quality; + private int m_Material; + private int m_Quantity; + + public bool IsDefault + { + get{ return ( m_Type == 0 && m_Quality == 0 && m_Material == 0 && m_Quantity == 0 ); } + } + + public void Clear() + { + m_Type = 0; + m_Quality = 0; + m_Material = 0; + m_Quantity = 0; + } + + public int Type + { + get{ return m_Type; } + set{ m_Type = value; } + } + + public int Quality + { + get{ return m_Quality; } + set{ m_Quality = value; } + } + + public int Material + { + get{ return m_Material; } + set{ m_Material = value; } + } + + public int Quantity + { + get{ return m_Quantity; } + set{ m_Quantity = value; } + } + + public BOBFilter() + { + } + + public BOBFilter( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_Type = reader.ReadEncodedInt(); + m_Quality = reader.ReadEncodedInt(); + m_Material = reader.ReadEncodedInt(); + m_Quantity = reader.ReadEncodedInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + if ( IsDefault ) + { + writer.WriteEncodedInt( 0 ); // version + } + else + { + writer.WriteEncodedInt( 1 ); // version + + writer.WriteEncodedInt( m_Type ); + writer.WriteEncodedInt( m_Quality ); + writer.WriteEncodedInt( m_Material ); + writer.WriteEncodedInt( m_Quantity ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BOBFilterGump.cs b/Scripts/Engines/BulkOrders/Books/BOBFilterGump.cs new file mode 100644 index 0000000..76f2e11 --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BOBFilterGump.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.BulkOrders +{ + public class BOBFilterGump : Gump + { + private PlayerMobile m_From; + private BulkOrderBook m_Book; + + private const int LabelColor = 0x7FFF; + + private static int[,] m_MaterialFilters = new int[,] + { + { 1044067, 1 }, // Blacksmithy + { 1062226, 3 }, // Iron + { 1018332, 4 }, // Dull Copper + { 1018333, 5 }, // Shadow Iron + { 1018334, 6 }, // Copper + { 1018335, 7 }, // Bronze + + { 0, 0 }, // --Blank-- + { 1018336, 8 }, // Golden + { 1018337, 9 }, // Agapite + { 1018338, 10 }, // Verite + { 1018339, 11 }, // Valorite + { 0, 0 }, // --Blank-- + + { 1044094, 2 }, // Tailoring + { 1044286, 12 }, // Cloth + { 1062235, 13 }, // Leather + { 1062236, 14 }, // Spined + { 1062237, 15 }, // Horned + { 1062238, 16 } // Barbed + }; + + private static int[,] m_TypeFilters = new int[,] + { + { 1062229, 0 }, // All + { 1062224, 1 }, // Small + { 1062225, 2 } // Large + }; + + private static int[,] m_QualityFilters = new int[,] + { + { 1062229, 0 }, // All + { 1011542, 1 }, // Normal + { 1060636, 2 } // Exceptional + }; + + private static int[,] m_AmountFilters = new int[,] + { + { 1062229, 0 }, // All + { 1049706, 1 }, // 10 + { 1016007, 2 }, // 15 + { 1062239, 3 } // 20 + }; + + private static int[][,] m_Filters = new int[][,] + { + m_TypeFilters, + m_QualityFilters, + m_MaterialFilters, + m_AmountFilters + }; + + private static int[] m_XOffsets_Type = new int[]{ 0, 75, 170 }; + private static int[] m_XOffsets_Quality = new int[]{ 0, 75, 170 }; + private static int[] m_XOffsets_Amount = new int[]{ 0, 75, 180, 275 }; + private static int[] m_XOffsets_Material = new int[]{ 0, 105, 210, 305, 390, 485 }; + + private static int[] m_XWidths_Small = new int[]{ 50, 50, 70, 50 }; + private static int[] m_XWidths_Large = new int[]{ 80, 50, 50, 50, 50, 50 }; + + private void AddFilterList( int x, int y, int[] xOffsets, int yOffset, int[,] filters, int[] xWidths, int filterValue, int filterIndex ) + { + for ( int i = 0; i < filters.GetLength( 0 ); ++i ) + { + int number = filters[i, 0]; + + if ( number == 0 ) + continue; + + bool isSelected = ( filters[i, 1] == filterValue ); + + if ( !isSelected && (i % xOffsets.Length) == 0 ) + isSelected = ( filterValue == 0 ); + + AddHtmlLocalized( x + 35 + xOffsets[i % xOffsets.Length], y + ((i / xOffsets.Length) * yOffset), xWidths[i % xOffsets.Length], 32, number, isSelected ? 16927 : LabelColor, false, false ); + AddButton( x + xOffsets[i % xOffsets.Length], y + ((i / xOffsets.Length) * yOffset), 4005, 4007, 4 + filterIndex + (i * 4), GumpButtonType.Reply, 0 ); + } + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + BOBFilter f = ( m_From.UseOwnFilter ? m_From.BOBFilter : m_Book.Filter ); + + int index = info.ButtonID; + + switch ( index ) + { + case 0: // Apply + { + m_From.SendGump( new BOBGump( m_From, m_Book ) ); + + break; + } + case 1: // Set Book Filter + { + m_From.UseOwnFilter = false; + m_From.SendGump( new BOBFilterGump( m_From, m_Book ) ); + + break; + } + case 2: // Set Your Filter + { + m_From.UseOwnFilter = true; + m_From.SendGump( new BOBFilterGump( m_From, m_Book ) ); + + break; + } + case 3: // Clear Filter + { + f.Clear(); + m_From.SendGump( new BOBFilterGump( m_From, m_Book ) ); + + break; + } + default: + { + index -= 4; + + int type = index % 4; + index /= 4; + + if ( type >= 0 && type < m_Filters.Length ) + { + int[,] filters = m_Filters[type]; + + if ( index >= 0 && index < filters.GetLength( 0 ) ) + { + if ( filters[index, 0] == 0 ) + break; + + switch ( type ) + { + case 0: f.Type = filters[index, 1]; break; + case 1: f.Quality = filters[index, 1]; break; + case 2: f.Material = filters[index, 1]; break; + case 3: f.Quantity = filters[index, 1]; break; + } + + m_From.SendGump( new BOBFilterGump( m_From, m_Book ) ); + } + } + + break; + } + } + } + + public BOBFilterGump( PlayerMobile from, BulkOrderBook book ) : base( 12, 24 ) + { + from.CloseGump( typeof( BOBGump ) ); + from.CloseGump( typeof( BOBFilterGump ) ); + + m_From = from; + m_Book = book; + + BOBFilter f = ( from.UseOwnFilter ? from.BOBFilter : book.Filter ); + + AddPage( 0 ); + + AddBackground( 10, 10, 600, 439, 5054 ); + + AddImageTiled( 18, 20, 583, 420, 2624 ); + AddAlphaRegion( 18, 20, 583, 420 ); + + AddImage( 5, 5, 10460 ); + AddImage( 585, 5, 10460 ); + AddImage( 5, 424, 10460 ); + AddImage( 585, 424, 10460 ); + + AddHtmlLocalized( 270, 32, 200, 32, 1062223, LabelColor, false, false ); // Filter Preference + + AddHtmlLocalized( 26, 64, 120, 32, 1062228, LabelColor, false, false ); // Bulk Order Type + AddFilterList( 25, 96, m_XOffsets_Type, 40, m_TypeFilters, m_XWidths_Small, f.Type, 0 ); + + AddHtmlLocalized( 320, 64, 50, 32, 1062215, LabelColor, false, false ); // Quality + AddFilterList( 320, 96, m_XOffsets_Quality, 40, m_QualityFilters, m_XWidths_Small, f.Quality, 1 ); + + AddHtmlLocalized( 26, 160, 120, 32, 1062232, LabelColor, false, false ); // Material Type + AddFilterList( 25, 192, m_XOffsets_Material, 40, m_MaterialFilters, m_XWidths_Large, f.Material, 2 ); + + AddHtmlLocalized( 26, 320, 120, 32, 1062217, LabelColor, false, false ); // Amount + AddFilterList( 25, 352, m_XOffsets_Amount, 40, m_AmountFilters, m_XWidths_Small, f.Quantity, 3 ); + + AddHtmlLocalized( 75, 416, 120, 32, 1062477, ( from.UseOwnFilter ? LabelColor : 16927 ), false, false ); // Set Book Filter + AddButton( 40, 416, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 235, 416, 120, 32, 1062478, ( from.UseOwnFilter ? 16927 : LabelColor ), false, false ); // Set Your Filter + AddButton( 200, 416, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 405, 416, 120, 32, 1062231, LabelColor, false, false ); // Clear Filter + AddButton( 370, 416, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 540, 416, 50, 32, 1011046, LabelColor, false, false ); // APPLY + AddButton( 505, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BOBGump.cs b/Scripts/Engines/BulkOrders/Books/BOBGump.cs new file mode 100644 index 0000000..105b080 --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BOBGump.cs @@ -0,0 +1,708 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Prompts; + +namespace Server.Engines.BulkOrders +{ + public class BOBGump : Gump + { + private PlayerMobile m_From; + private BulkOrderBook m_Book; + private ArrayList m_List; + + private int m_Page; + + private const int LabelColor = 0x7FFF; + + public Item Reconstruct( object obj ) + { + Item item = null; + + if ( obj is BOBLargeEntry ) + item = ((BOBLargeEntry)obj).Reconstruct(); + else if ( obj is BOBSmallEntry ) + item = ((BOBSmallEntry)obj).Reconstruct(); + + return item; + } + + public bool CheckFilter( object obj ) + { + if ( obj is BOBLargeEntry ) + { + BOBLargeEntry e = (BOBLargeEntry)obj; + + return CheckFilter( e.Material, e.AmountMax, true, e.RequireExceptional, e.DeedType, ( e.Entries.Length > 0 ? e.Entries[0].ItemType : null ) ); + } + else if ( obj is BOBSmallEntry ) + { + BOBSmallEntry e = (BOBSmallEntry)obj; + + return CheckFilter( e.Material, e.AmountMax, false, e.RequireExceptional, e.DeedType, e.ItemType ); + } + + return false; + } + + public bool CheckFilter( BulkMaterialType mat, int amountMax, bool isLarge, bool reqExc, BODType deedType, Type itemType ) + { + BOBFilter f = ( m_From.UseOwnFilter ? m_From.BOBFilter : m_Book.Filter ); + + if ( f.IsDefault ) + return true; + + if ( f.Quality == 1 && reqExc ) + return false; + else if ( f.Quality == 2 && !reqExc ) + return false; + + if ( f.Quantity == 1 && amountMax != 10 ) + return false; + else if ( f.Quantity == 2 && amountMax != 15 ) + return false; + else if ( f.Quantity == 3 && amountMax != 20 ) + return false; + + if ( f.Type == 1 && isLarge ) + return false; + else if ( f.Type == 2 && !isLarge ) + return false; + + switch ( f.Material ) + { + default: + case 0: return true; + case 1: return ( deedType == BODType.Smith ); + case 2: return ( deedType == BODType.Tailor ); + + case 3: return ( mat == BulkMaterialType.None && BGTClassifier.Classify( deedType, itemType ) == BulkGenericType.Iron ); + case 4: return ( mat == BulkMaterialType.DullCopper ); + case 5: return ( mat == BulkMaterialType.ShadowIron ); + case 6: return ( mat == BulkMaterialType.Copper ); + case 7: return ( mat == BulkMaterialType.Bronze ); + case 8: return ( mat == BulkMaterialType.Gold ); + case 9: return ( mat == BulkMaterialType.Agapite ); + case 10: return ( mat == BulkMaterialType.Verite ); + case 11: return ( mat == BulkMaterialType.Valorite ); + + case 12: return ( mat == BulkMaterialType.None && BGTClassifier.Classify( deedType, itemType ) == BulkGenericType.Cloth ); + case 13: return ( mat == BulkMaterialType.None && BGTClassifier.Classify( deedType, itemType ) == BulkGenericType.Leather ); + case 14: return ( mat == BulkMaterialType.Spined ); + case 15: return ( mat == BulkMaterialType.Horned ); + case 16: return ( mat == BulkMaterialType.Barbed ); + } + } + + public int GetIndexForPage( int page ) + { + int index = 0; + + while ( page-- > 0 ) + index += GetCountForIndex( index ); + + return index; + } + + public int GetCountForIndex( int index ) + { + int slots = 0; + int count = 0; + + ArrayList list = m_List; + + for ( int i = index; i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + if ( CheckFilter( obj ) ) + { + int add; + + if ( obj is BOBLargeEntry ) + add = ((BOBLargeEntry)obj).Entries.Length; + else + add = 1; + + if ( (slots + add) > 10 ) + break; + + slots += add; + } + + ++count; + } + + return count; + } + + public int GetPageForIndex(int index, int sizeDropped) + { + if (index <= 0) + return 0; + + int count = 0; + int add = 0; + int page = 0; + ArrayList list = m_List; + int i; + object obj; + + for (i=0; (i < index) && (i < list.Count); i++) + { + obj = list[i]; + if (CheckFilter(obj)) + { + if (obj is BOBLargeEntry) + add = ((BOBLargeEntry)obj).Entries.Length; + else + add = 1; + count += add; + if (count > 10) + { + page++; + count = add; + } + } + } + /* now we are on the page of the bod preceeding the dropped one. + * next step: checking whether we have to remain where we are. + * The counter i needs to be incremented as the bod to this very moment + * has not yet been removed from m_List */ + i++; + + /* if, for instance, a big bod of size 6 has been removed, smaller bods + * might fall back into this page. Depending on their sizes, the page eeds + * to be adjusted accordingly. This is done now. + */ + if (count + sizeDropped > 10) + { + while ((i < list.Count) && (count <= 10)) + { + obj = list[i]; + if (CheckFilter(obj)) + { + if (obj is BOBLargeEntry) + count += ((BOBLargeEntry)obj).Entries.Length; + else + count += 1; + } + i++; + } + if (count > 10) + page++; + } + return page; + } + + + public object GetMaterialName( BulkMaterialType mat, BODType type, Type itemType ) + { + switch ( type ) + { + case BODType.Smith: + { + switch ( mat ) + { + case BulkMaterialType.None: return 1062226; + case BulkMaterialType.DullCopper: return 1018332; + case BulkMaterialType.ShadowIron: return 1018333; + case BulkMaterialType.Copper: return 1018334; + case BulkMaterialType.Bronze: return 1018335; + case BulkMaterialType.Gold: return 1018336; + case BulkMaterialType.Agapite: return 1018337; + case BulkMaterialType.Verite: return 1018338; + case BulkMaterialType.Valorite: return 1018339; + } + + break; + } + case BODType.Tailor: + { + switch ( mat ) + { + case BulkMaterialType.None: + { + if ( itemType.IsSubclassOf( typeof( BaseArmor ) ) || itemType.IsSubclassOf( typeof( BaseShoes ) ) ) + return 1062235; + + return 1044286; + } + case BulkMaterialType.Spined: return 1062236; + case BulkMaterialType.Horned: return 1062237; + case BulkMaterialType.Barbed: return 1062238; + } + + break; + } + } + + return "Invalid"; + } + + public BOBGump( PlayerMobile from, BulkOrderBook book ) : this( from, book, 0, null ) + { + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + int index = info.ButtonID; + + switch ( index ) + { + case 0: // EXIT + { + break; + } + case 1: // Set Filter + { + m_From.SendGump( new BOBFilterGump( m_From, m_Book ) ); + + break; + } + case 2: // Previous page + { + if ( m_Page > 0 ) + m_From.SendGump( new BOBGump( m_From, m_Book, m_Page - 1, m_List ) ); + + return; + } + case 3: // Next page + { + if ( GetIndexForPage( m_Page + 1 ) < m_List.Count ) + m_From.SendGump( new BOBGump( m_From, m_Book, m_Page + 1, m_List ) ); + + break; + } + case 4: // Price all + { + if ( m_Book.IsChildOf( m_From.Backpack ) ) + { + m_From.Prompt = new SetPricePrompt( m_Book, null, m_Page, m_List ); + m_From.SendMessage( "Type in a price for all deeds in the book:" ); + } + + break; + } + default: + { + bool canDrop = m_Book.IsChildOf( m_From.Backpack ); + bool canPrice = canDrop || (m_Book.RootParent is PlayerVendor); + + index -= 5; + + int type = index % 2; + index /= 2; + + if ( index < 0 || index >= m_List.Count ) + break; + + object obj = m_List[index]; + + if ( !m_Book.Entries.Contains( obj ) ) + { + m_From.SendLocalizedMessage( 1062382 ); // The deed selected is not available. + break; + } + + if ( type == 0 ) // Drop + { + if ( m_Book.IsChildOf( m_From.Backpack ) ) + { + Item item = Reconstruct( obj ); + + if ( item != null ) + { + Container pack = m_From.Backpack; + if ((pack == null) || ((pack != null) && (!pack.CheckHold(m_From, item, true, true, 0, item.PileWeight + item.TotalWeight)))) + { + m_From.SendLocalizedMessage(503204); // You do not have room in your backpack for this + m_From.SendGump(new BOBGump(m_From, m_Book, m_Page, null)); + } + else + { + if (m_Book.IsChildOf(m_From.Backpack)) + { + int sizeOfDroppedBod; + if (obj is BOBLargeEntry) + sizeOfDroppedBod = ((BOBLargeEntry)obj).Entries.Length; + else + sizeOfDroppedBod = 1; + + m_From.AddToBackpack(item); + m_From.SendLocalizedMessage(1045152); // The bulk order deed has been placed in your backpack. + m_Book.Entries.Remove(obj); + m_Book.InvalidateProperties(); + + if ( m_Book.Entries.Count / 5 < m_Book.ItemCount ) + { + m_Book.ItemCount--; + m_Book.InvalidateItems(); + } + + if (m_Book.Entries.Count > 0) + { + m_Page = GetPageForIndex(index, sizeOfDroppedBod); + m_From.SendGump(new BOBGump(m_From, m_Book, m_Page, null)); + } + else + m_From.SendLocalizedMessage(1062381); // The book is empty. + } + } + } + else + { + m_From.SendMessage( "Internal error. The bulk order deed could not be reconstructed." ); + } + } + } + else // Set Price | Buy + { + if ( m_Book.IsChildOf( m_From.Backpack ) ) + { + m_From.Prompt = new SetPricePrompt( m_Book, obj, m_Page, m_List ); + m_From.SendLocalizedMessage( 1062383 ); // Type in a price for the deed: + } + else if ( m_Book.RootParent is PlayerVendor ) + { + PlayerVendor pv = (PlayerVendor)m_Book.RootParent; + VendorItem vi = pv.GetVendorItem( m_Book ); + + if (vi != null && !vi.IsForSale) + { + int sizeOfDroppedBod; + int price = 0; + if (obj is BOBLargeEntry) + { + price = ((BOBLargeEntry)obj).Price; + sizeOfDroppedBod = ((BOBLargeEntry)obj).Entries.Length; + } + else + { + price = ((BOBSmallEntry)obj).Price; + sizeOfDroppedBod = 1; + } + if (price == 0) + m_From.SendLocalizedMessage(1062382); // The deed selected is not available. + else + { + if (m_Book.Entries.Count > 0) + { + m_Page = GetPageForIndex(index, sizeOfDroppedBod); + m_From.SendGump(new BODBuyGump(m_From, m_Book, obj, m_Page, price)); + } + else + m_From.SendLocalizedMessage(1062381); // The book is emptz + } + } + } + } + break; + } + } + } + + private class SetPricePrompt : Prompt + { + private BulkOrderBook m_Book; + private object m_Object; + private int m_Page; + private ArrayList m_List; + + public SetPricePrompt( BulkOrderBook book, object obj, int page, ArrayList list ) + { + m_Book = book; + m_Object = obj; + m_Page = page; + m_List = list; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Object != null && !m_Book.Entries.Contains( m_Object ) ) + { + from.SendLocalizedMessage( 1062382 ); // The deed selected is not available. + return; + } + + int price = Utility.ToInt32( text ); + + if ( price < 0 || price > 250000000 ) + { + from.SendLocalizedMessage( 1062390 ); // The price you requested is outrageous! + } + else if ( m_Object == null ) + { + for ( int i = 0; i < m_List.Count; ++i ) + { + object obj = m_List[i]; + + if ( !m_Book.Entries.Contains( obj ) ) + continue; + + if ( obj is BOBLargeEntry ) + ((BOBLargeEntry)obj).Price = price; + else if ( obj is BOBSmallEntry ) + ((BOBSmallEntry)obj).Price = price; + } + + from.SendMessage( "Deed prices set." ); + + if ( from is PlayerMobile ) + from.SendGump( new BOBGump( (PlayerMobile)from, m_Book, m_Page, m_List ) ); + } + else if ( m_Object is BOBLargeEntry ) + { + ((BOBLargeEntry)m_Object).Price = price; + + from.SendLocalizedMessage( 1062384 ); // Deed price set. + + if ( from is PlayerMobile ) + from.SendGump( new BOBGump( (PlayerMobile)from, m_Book, m_Page, m_List ) ); + } + else if ( m_Object is BOBSmallEntry ) + { + ((BOBSmallEntry)m_Object).Price = price; + + from.SendLocalizedMessage( 1062384 ); // Deed price set. + + if ( from is PlayerMobile ) + from.SendGump( new BOBGump( (PlayerMobile)from, m_Book, m_Page, m_List ) ); + } + } + } + + public BOBGump( PlayerMobile from, BulkOrderBook book, int page, ArrayList list ) : base( 12, 24 ) + { + from.CloseGump( typeof( BOBGump ) ); + from.CloseGump( typeof( BOBFilterGump ) ); + + m_From = from; + m_Book = book; + m_Page = page; + + if ( list == null ) + { + list = new ArrayList( book.Entries.Count ); + + for ( int i = 0; i < book.Entries.Count; ++i ) + { + object obj = book.Entries[i]; + + if ( CheckFilter( obj ) ) + list.Add( obj ); + } + } + + m_List = list; + + int index = GetIndexForPage( page ); + int count = GetCountForIndex( index ); + + int tableIndex = 0; + + PlayerVendor pv = book.RootParent as PlayerVendor; + + bool canDrop = book.IsChildOf( from.Backpack ); + bool canBuy = ( pv != null ); + bool canPrice = ( canDrop || canBuy ); + + if ( canBuy ) + { + VendorItem vi = pv.GetVendorItem( book ); + + canBuy = ( vi != null && !vi.IsForSale ); + } + + int width = 600; + + if ( !canPrice ) + width = 516; + + X = (624 - width) / 2; + + AddPage( 0 ); + + AddBackground( 10, 10, width, 439, 5054 ); + AddImageTiled( 18, 20, width - 17, 420, 2624 ); + + if ( canPrice ) + { + AddImageTiled( 573, 64, 24, 352, 200 ); + AddImageTiled( 493, 64, 78, 352, 1416 ); + } + + if ( canDrop ) + AddImageTiled( 24, 64, 32, 352, 1416 ); + + AddImageTiled( 58, 64, 36, 352, 200 ); + AddImageTiled( 96, 64, 133, 352, 1416 ); + AddImageTiled( 231, 64, 80, 352, 200 ); + AddImageTiled( 313, 64, 100, 352, 1416 ); + AddImageTiled( 415, 64, 76, 352, 200 ); + + for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + if ( !CheckFilter( obj ) ) + continue; + + AddImageTiled( 24, 94 + (tableIndex * 32), canPrice ? 573 : 489, 2, 2624 ); + + if ( obj is BOBLargeEntry ) + tableIndex += ((BOBLargeEntry)obj).Entries.Length; + else if ( obj is BOBSmallEntry ) + ++tableIndex; + } + + AddAlphaRegion( 18, 20, width - 17, 420 ); + AddImage( 5, 5, 10460 ); + AddImage( width - 15, 5, 10460 ); + AddImage( 5, 424, 10460 ); + AddImage( width - 15, 424, 10460 ); + + AddHtmlLocalized( canPrice ? 266 : 224, 32, 200, 32, 1062220, LabelColor, false, false ); // Bulk Order Book + AddHtmlLocalized( 63, 64, 200, 32, 1062213, LabelColor, false, false ); // Type + AddHtmlLocalized( 147, 64, 200, 32, 1062214, LabelColor, false, false ); // Item + AddHtmlLocalized( 246, 64, 200, 32, 1062215, LabelColor, false, false ); // Quality + AddHtmlLocalized( 336, 64, 200, 32, 1062216, LabelColor, false, false ); // Material + AddHtmlLocalized( 429, 64, 200, 32, 1062217, LabelColor, false, false ); // Amount + + AddButton( 35, 32, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 70, 32, 200, 32, 1062476, LabelColor, false, false ); // Set Filter + + BOBFilter f = ( from.UseOwnFilter ? from.BOBFilter : book.Filter ); + + if ( f.IsDefault ) + AddHtmlLocalized( canPrice ? 470 : 386, 32, 120, 32, 1062475, 16927, false, false ); // Using No Filter + else if ( from.UseOwnFilter ) + AddHtmlLocalized( canPrice ? 470 : 386, 32, 120, 32, 1062451, 16927, false, false ); // Using Your Filter + else + AddHtmlLocalized( canPrice ? 470 : 386, 32, 120, 32, 1062230, 16927, false, false ); // Using Book Filter + + AddButton( 375, 416, 4017, 4018, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 410, 416, 120, 20, 1011441, LabelColor, false, false ); // EXIT + + if ( canDrop ) + AddHtmlLocalized( 26, 64, 50, 32, 1062212, LabelColor, false, false ); // Drop + + if ( canPrice ) + { + AddHtmlLocalized( 516, 64, 200, 32, 1062218, LabelColor, false, false ); // Price + + if ( canBuy ) + { + AddHtmlLocalized( 576, 64, 200, 32, 1062219, LabelColor, false, false ); // Buy + } + else + { + AddHtmlLocalized( 576, 64, 200, 32, 1062227, LabelColor, false, false ); // Set + + AddButton( 450, 416, 4005, 4007, 4, GumpButtonType.Reply, 0 ); + AddHtml( 485, 416, 120, 20, "Price all", false, false ); + } + } + + tableIndex = 0; + + if ( page > 0 ) + { + AddButton( 75, 416, 4014, 4016, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 110, 416, 150, 20, 1011067, LabelColor, false, false ); // Previous page + } + + if ( GetIndexForPage( page + 1 ) < list.Count ) + { + AddButton( 225, 416, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 260, 416, 150, 20, 1011066, LabelColor, false, false ); // Next page + } + + for ( int i = index; i < (index + count) && i >= 0 && i < list.Count; ++i ) + { + object obj = list[i]; + + if ( !CheckFilter( obj ) ) + continue; + + if ( obj is BOBLargeEntry ) + { + BOBLargeEntry e = (BOBLargeEntry)obj; + + int y = 96 + (tableIndex * 32); + + if ( canDrop ) + AddButton( 35, y + 2, 5602, 5606, 5 + (i * 2), GumpButtonType.Reply, 0 ); + + if ( canDrop || (canBuy && e.Price > 0) ) + { + AddButton( 579, y + 2, 2117, 2118, 6 + (i * 2), GumpButtonType.Reply, 0 ); + AddLabel( 495, y, 1152, e.Price.ToString() ); + } + + AddHtmlLocalized( 61, y, 50, 32, 1062225, LabelColor, false, false ); // Large + + for ( int j = 0; j < e.Entries.Length; ++j ) + { + BOBLargeSubEntry sub = e.Entries[j]; + + AddHtmlLocalized( 103, y, 130, 32, sub.Number, LabelColor, false, false ); + + if ( e.RequireExceptional ) + AddHtmlLocalized( 235, y, 80, 20, 1060636, LabelColor, false, false ); // exceptional + else + AddHtmlLocalized( 235, y, 80, 20, 1011542, LabelColor, false, false ); // normal + + object name = GetMaterialName( e.Material, e.DeedType, sub.ItemType ); + + if ( name is int ) + AddHtmlLocalized( 316, y, 100, 20, (int)name, LabelColor, false, false ); + else if ( name is string ) + AddLabel( 316, y, 1152, (string)name ); + + AddLabel( 421, y, 1152, String.Format( "{0} / {1}", sub.AmountCur, e.AmountMax ) ); + + ++tableIndex; + y += 32; + } + } + else if ( obj is BOBSmallEntry ) + { + BOBSmallEntry e = (BOBSmallEntry)obj; + + int y = 96 + (tableIndex++ * 32); + + if ( canDrop ) + AddButton( 35, y + 2, 5602, 5606, 5 + (i * 2), GumpButtonType.Reply, 0 ); + + if ( canDrop || (canBuy && e.Price > 0) ) + { + AddButton( 579, y + 2, 2117, 2118, 6 + (i * 2), GumpButtonType.Reply, 0 ); + AddLabel( 495, y, 1152, e.Price.ToString() ); + } + + AddHtmlLocalized( 61, y, 50, 32, 1062224, LabelColor, false, false ); // Small + + AddHtmlLocalized( 103, y, 130, 32, e.Number, LabelColor, false, false ); + + if ( e.RequireExceptional ) + AddHtmlLocalized( 235, y, 80, 20, 1060636, LabelColor, false, false ); // exceptional + else + AddHtmlLocalized( 235, y, 80, 20, 1011542, LabelColor, false, false ); // normal + + object name = GetMaterialName( e.Material, e.DeedType, e.ItemType ); + + if ( name is int ) + AddHtmlLocalized( 316, y, 100, 20, (int)name, LabelColor, false, false ); + else if ( name is string ) + AddLabel( 316, y, 1152, (string)name ); + + AddLabel( 421, y, 1152, String.Format( "{0} / {1}", e.AmountCur, e.AmountMax ) ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BOBLargeEntry.cs b/Scripts/Engines/BulkOrders/Books/BOBLargeEntry.cs new file mode 100644 index 0000000..71a029a --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BOBLargeEntry.cs @@ -0,0 +1,110 @@ +using System; + +namespace Server.Engines.BulkOrders +{ + public class BOBLargeEntry + { + private bool m_RequireExceptional; + private BODType m_DeedType; + private BulkMaterialType m_Material; + private int m_AmountMax; + private int m_Price; + private BOBLargeSubEntry[] m_Entries; + + public bool RequireExceptional{ get{ return m_RequireExceptional; } } + public BODType DeedType{ get{ return m_DeedType; } } + public BulkMaterialType Material{ get{ return m_Material; } } + public int AmountMax{ get{ return m_AmountMax; } } + public int Price{ get{ return m_Price; } set{ m_Price = value; } } + public BOBLargeSubEntry[] Entries{ get{ return m_Entries; } } + + public Item Reconstruct() + { + LargeBOD bod = null; + + if ( m_DeedType == BODType.Smith ) + bod = new LargeSmithBOD( m_AmountMax, m_RequireExceptional, m_Material, ReconstructEntries() ); + else if ( m_DeedType == BODType.Tailor ) + bod = new LargeTailorBOD( m_AmountMax, m_RequireExceptional, m_Material, ReconstructEntries() ); + + for ( int i = 0; bod != null && i < bod.Entries.Length; ++i ) + bod.Entries[i].Owner = bod; + + return bod; + } + + private LargeBulkEntry[] ReconstructEntries() + { + LargeBulkEntry[] entries = new LargeBulkEntry[m_Entries.Length]; + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + entries[i] = new LargeBulkEntry( null, new SmallBulkEntry( m_Entries[i].ItemType, m_Entries[i].Number, m_Entries[i].Graphic ) ); + entries[i].Amount = m_Entries[i].AmountCur; + } + + return entries; + } + + public BOBLargeEntry( LargeBOD bod ) + { + m_RequireExceptional = bod.RequireExceptional; + + if ( bod is LargeTailorBOD ) + m_DeedType = BODType.Tailor; + else if ( bod is LargeSmithBOD ) + m_DeedType = BODType.Smith; + + m_Material = bod.Material; + m_AmountMax = bod.AmountMax; + + m_Entries = new BOBLargeSubEntry[bod.Entries.Length]; + + for ( int i = 0; i < m_Entries.Length; ++i ) + m_Entries[i] = new BOBLargeSubEntry( bod.Entries[i] ); + } + + public BOBLargeEntry( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_RequireExceptional = reader.ReadBool(); + + m_DeedType = (BODType)reader.ReadEncodedInt(); + + m_Material = (BulkMaterialType)reader.ReadEncodedInt(); + m_AmountMax = reader.ReadEncodedInt(); + m_Price = reader.ReadEncodedInt(); + + m_Entries = new BOBLargeSubEntry[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_Entries.Length; ++i ) + m_Entries[i] = new BOBLargeSubEntry( reader ); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_RequireExceptional ); + + writer.WriteEncodedInt( (int) m_DeedType ); + writer.WriteEncodedInt( (int) m_Material ); + writer.WriteEncodedInt( (int) m_AmountMax ); + writer.WriteEncodedInt( (int) m_Price ); + + writer.WriteEncodedInt( (int) m_Entries.Length ); + + for ( int i = 0; i < m_Entries.Length; ++i ) + m_Entries[i].Serialize( writer ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BOBLargeSubEntry.cs b/Scripts/Engines/BulkOrders/Books/BOBLargeSubEntry.cs new file mode 100644 index 0000000..42f89f7 --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BOBLargeSubEntry.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Engines.BulkOrders +{ + public class BOBLargeSubEntry + { + private Type m_ItemType; + private int m_AmountCur; + private int m_Number; + private int m_Graphic; + + public Type ItemType{ get{ return m_ItemType; } } + public int AmountCur{ get{ return m_AmountCur; } } + public int Number{ get{ return m_Number; } } + public int Graphic{ get{ return m_Graphic; } } + + public BOBLargeSubEntry( LargeBulkEntry lbe ) + { + m_ItemType = lbe.Details.Type; + m_AmountCur = lbe.Amount; + m_Number = lbe.Details.Number; + m_Graphic = lbe.Details.Graphic; + } + + public BOBLargeSubEntry( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + string type = reader.ReadString(); + + if ( type != null ) + m_ItemType = ScriptCompiler.FindTypeByFullName( type ); + + m_AmountCur = reader.ReadEncodedInt(); + m_Number = reader.ReadEncodedInt(); + m_Graphic = reader.ReadEncodedInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_ItemType == null ? null : m_ItemType.FullName ); + + writer.WriteEncodedInt( (int) m_AmountCur ); + writer.WriteEncodedInt( (int) m_Number ); + writer.WriteEncodedInt( (int) m_Graphic ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BOBSmallEntry.cs b/Scripts/Engines/BulkOrders/Books/BOBSmallEntry.cs new file mode 100644 index 0000000..4a77c6a --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BOBSmallEntry.cs @@ -0,0 +1,101 @@ +using System; + +namespace Server.Engines.BulkOrders +{ + public class BOBSmallEntry + { + private Type m_ItemType; + private bool m_RequireExceptional; + private BODType m_DeedType; + private BulkMaterialType m_Material; + private int m_AmountCur, m_AmountMax; + private int m_Number; + private int m_Graphic; + private int m_Price; + + public Type ItemType{ get{ return m_ItemType; } } + public bool RequireExceptional{ get{ return m_RequireExceptional; } } + public BODType DeedType{ get{ return m_DeedType; } } + public BulkMaterialType Material{ get{ return m_Material; } } + public int AmountCur{ get{ return m_AmountCur; } } + public int AmountMax{ get{ return m_AmountMax; } } + public int Number{ get{ return m_Number; } } + public int Graphic{ get{ return m_Graphic; } } + public int Price{ get{ return m_Price; } set{ m_Price = value; } } + + public Item Reconstruct() + { + SmallBOD bod = null; + + if ( m_DeedType == BODType.Smith ) + bod = new SmallSmithBOD( m_AmountCur, m_AmountMax, m_ItemType, m_Number, m_Graphic, m_RequireExceptional, m_Material ); + else if ( m_DeedType == BODType.Tailor ) + bod = new SmallTailorBOD( m_AmountCur, m_AmountMax, m_ItemType, m_Number, m_Graphic, m_RequireExceptional, m_Material ); + + return bod; + } + + public BOBSmallEntry( SmallBOD bod ) + { + m_ItemType = bod.Type; + m_RequireExceptional = bod.RequireExceptional; + + if ( bod is SmallTailorBOD ) + m_DeedType = BODType.Tailor; + else if ( bod is SmallSmithBOD ) + m_DeedType = BODType.Smith; + + m_Material = bod.Material; + m_AmountCur = bod.AmountCur; + m_AmountMax = bod.AmountMax; + m_Number = bod.Number; + m_Graphic = bod.Graphic; + } + + public BOBSmallEntry( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + string type = reader.ReadString(); + + if ( type != null ) + m_ItemType = ScriptCompiler.FindTypeByFullName( type ); + + m_RequireExceptional = reader.ReadBool(); + + m_DeedType = (BODType)reader.ReadEncodedInt(); + + m_Material = (BulkMaterialType)reader.ReadEncodedInt(); + m_AmountCur = reader.ReadEncodedInt(); + m_AmountMax = reader.ReadEncodedInt(); + m_Number = reader.ReadEncodedInt(); + m_Graphic = reader.ReadEncodedInt(); + m_Price = reader.ReadEncodedInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_ItemType == null ? null : m_ItemType.FullName ); + + writer.Write( (bool) m_RequireExceptional ); + + writer.WriteEncodedInt( (int) m_DeedType ); + writer.WriteEncodedInt( (int) m_Material ); + writer.WriteEncodedInt( (int) m_AmountCur ); + writer.WriteEncodedInt( (int) m_AmountMax ); + writer.WriteEncodedInt( (int) m_Number ); + writer.WriteEncodedInt( (int) m_Graphic ); + writer.WriteEncodedInt( (int) m_Price ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BODBuyGump.cs b/Scripts/Engines/BulkOrders/Books/BODBuyGump.cs new file mode 100644 index 0000000..88916ff --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BODBuyGump.cs @@ -0,0 +1,138 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; + +namespace Server.Engines.BulkOrders +{ + public class BODBuyGump : Gump + { + private PlayerMobile m_From; + private BulkOrderBook m_Book; + private object m_Object; + private int m_Price; + private int m_Page; + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 2 ) + { + PlayerVendor pv = m_Book.RootParent as PlayerVendor; + + if ( m_Book.Entries.Contains( m_Object ) && pv != null ) + { + int price = 0; + + VendorItem vi = pv.GetVendorItem( m_Book ); + + if ( vi != null && !vi.IsForSale ) + { + if ( m_Object is BOBLargeEntry ) + price = ((BOBLargeEntry)m_Object).Price; + else if ( m_Object is BOBSmallEntry ) + price = ((BOBSmallEntry)m_Object).Price; + } + + if ( price != m_Price ) + { + pv.SayTo( m_From, "The price has been been changed. If you like, you may offer to purchase the item again." ); + } + else if ( price == 0 ) + { + pv.SayTo( m_From, 1062382 ); // The deed selected is not available. + } + else + { + Item item = null; + + if ( m_Object is BOBLargeEntry ) + item = ((BOBLargeEntry)m_Object).Reconstruct(); + else if ( m_Object is BOBSmallEntry ) + item = ((BOBSmallEntry)m_Object).Reconstruct(); + + if ( item == null ) + { + m_From.SendMessage( "Internal error. The bulk order deed could not be reconstructed." ); + } + else + { + pv.Say( m_From.Name ); + + Container pack = m_From.Backpack; + + if ( (pack == null) || ((pack != null) && (!pack.CheckHold(m_From, item, true, true, 0, item.PileWeight + item.TotalWeight)) ) ) + { + pv.SayTo(m_From, 503204); // You do not have room in your backpack for this + m_From.SendGump(new BOBGump(m_From, m_Book, m_Page, null)); + } + else + { + if ((pack != null && pack.ConsumeTotal( typeof( Gold ), price )) || Banker.Withdraw( m_From, price ) ) + { + m_Book.Entries.Remove( m_Object ); + m_Book.InvalidateProperties(); + pv.HoldGold += price; + m_From.AddToBackpack( item ); + m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack. + + if ( m_Book.Entries.Count / 5 < m_Book.ItemCount ) + { + m_Book.ItemCount--; + m_Book.InvalidateItems(); + } + + if ( m_Book.Entries.Count > 0 ) + m_From.SendGump( new BOBGump( m_From, m_Book, m_Page, null ) ); + else + m_From.SendLocalizedMessage( 1062381 ); // The book is empty. + } + else + { + pv.SayTo( m_From, 503205 ); // You cannot afford this item. + item.Delete(); + } + } + } + } + } + else + { + if ( pv == null ) + m_From.SendLocalizedMessage( 1062382 ); // The deed selected is not available. + else + pv.SayTo( m_From, 1062382 ); // The deed selected is not available. + } + } + else + { + m_From.SendLocalizedMessage( 503207 ); // Cancelled purchase. + } + } + + public BODBuyGump( PlayerMobile from, BulkOrderBook book, object obj, int page, int price ) : base( 100, 200 ) + { + m_From = from; + m_Book = book; + m_Object = obj; + m_Price = price; + m_Page = page; + + AddPage( 0 ); + + AddBackground( 100, 10, 300, 150, 5054 ); + + AddHtmlLocalized( 125, 20, 250, 24, 1019070, false, false ); // You have agreed to purchase: + AddHtmlLocalized( 125, 45, 250, 24, 1045151, false, false ); // a bulk order deed + + AddHtmlLocalized( 125, 70, 250, 24, 1019071, false, false ); // for the amount of: + AddLabel( 125, 95, 0, price.ToString() ); + + AddButton( 250, 130, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 282, 130, 100, 24, 1011012, false, false ); // CANCEL + + AddButton( 120, 130, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 152, 130, 100, 24, 1011036, false, false ); // OKAY + } + } +} diff --git a/Scripts/Engines/BulkOrders/Books/BODType.cs b/Scripts/Engines/BulkOrders/Books/BODType.cs new file mode 100644 index 0000000..633cc9e --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BODType.cs @@ -0,0 +1,10 @@ +using System; + +namespace Server.Engines.BulkOrders +{ + public enum BODType + { + Smith, + Tailor + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs b/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs new file mode 100644 index 0000000..04a74ba --- /dev/null +++ b/Scripts/Engines/BulkOrders/Books/BulkOrderBook.cs @@ -0,0 +1,334 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Prompts; +using Server.Mobiles; +using Server.ContextMenus; +using Server.Items; + +namespace Server.Engines.BulkOrders +{ + public class BulkOrderBook : Item, ISecurable + { + private ArrayList m_Entries; + private BOBFilter m_Filter; + private string m_BookName; + private SecureLevel m_Level; + private int m_ItemCount; + + [CommandProperty( AccessLevel.GameMaster )] + public string BookName + { + get{ return m_BookName; } + set{ m_BookName = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + public ArrayList Entries + { + get{ return m_Entries; } + } + + public BOBFilter Filter + { + get{ return m_Filter; } + } + + public int ItemCount + { + get{ return m_ItemCount; } + set{ m_ItemCount = value; } + } + + [Constructable] + public BulkOrderBook() : base( 0x2259 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + + m_Entries = new ArrayList(); + m_Filter = new BOBFilter(); + + m_Level = SecureLevel.CoOwners; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( m_Entries.Count == 0 ) + from.SendLocalizedMessage( 1062381 ); // The book is empty. + else if ( from is PlayerMobile ) + from.SendGump( new BOBGump( (PlayerMobile)from, this ) ); + } + + public override void OnDoubleClickSecureTrade( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( m_Entries.Count == 0 ) + { + from.SendLocalizedMessage( 1062381 ); // The book is empty. + } + else + { + from.SendGump( new BOBGump( (PlayerMobile)from, this ) ); + + SecureTradeContainer cont = GetSecureTradeCont(); + + if ( cont != null ) + { + SecureTrade trade = cont.Trade; + + if ( trade != null && trade.From.Mobile == from ) + trade.To.Mobile.SendGump( new BOBGump( (PlayerMobile)(trade.To.Mobile), this ) ); + else if ( trade != null && trade.To.Mobile == from ) + trade.From.Mobile.SendGump( new BOBGump( (PlayerMobile)(trade.From.Mobile), this ) ); + } + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is LargeBOD || dropped is SmallBOD ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062385 ); // You must have the book in your backpack to add deeds to it. + return false; + } + else if ( !from.Backpack.CheckHold( from, dropped, true, true ) ) + return false; + else if ( m_Entries.Count < 500 ) + { + if ( dropped is LargeBOD ) + m_Entries.Add( new BOBLargeEntry( (LargeBOD)dropped ) ); + else if ( dropped is SmallBOD ) // Sanity + m_Entries.Add( new BOBSmallEntry( (SmallBOD)dropped ) ); + + InvalidateProperties(); + + if ( m_Entries.Count / 5 > m_ItemCount ) + { + m_ItemCount++; + InvalidateItems(); + } + + from.SendSound(0x42, GetWorldLocation()); + from.SendLocalizedMessage( 1062386 ); // Deed added to book. + + if ( from is PlayerMobile ) + from.SendGump( new BOBGump( (PlayerMobile)from, this ) ); + + dropped.Delete(); + + return true; + } + else + { + from.SendLocalizedMessage( 1062387 ); // The book is full of deeds. + return false; + } + } + + from.SendLocalizedMessage( 1062388 ); // That is not a bulk order deed. + return false; + } + + public override int GetTotal( TotalType type ) + { + int total = base.GetTotal( type ); + + if ( type == TotalType.Items ) + total = m_ItemCount; + + return total; + } + + public void InvalidateItems() + { + if ( RootParent is Mobile ) + { + Mobile m = (Mobile) RootParent; + + m.UpdateTotals(); + InvalidateContainers( Parent ); + } + } + + public void InvalidateContainers( object parent ) + { + if ( parent != null && parent is Container ) + { + Container c = (Container)parent; + + c.InvalidateProperties(); + InvalidateContainers( c.Parent ); + } + } + + public BulkOrderBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (int) m_ItemCount ); + + writer.Write( (int) m_Level ); + + writer.Write( m_BookName ); + + m_Filter.Serialize( writer ); + + writer.WriteEncodedInt( (int) m_Entries.Count ); + + for ( int i = 0; i < m_Entries.Count; ++i ) + { + object obj = m_Entries[i]; + + if ( obj is BOBLargeEntry ) + { + writer.WriteEncodedInt( 0 ); + ((BOBLargeEntry)obj).Serialize( writer ); + } + else if ( obj is BOBSmallEntry ) + { + writer.WriteEncodedInt( 1 ); + ((BOBSmallEntry)obj).Serialize( writer ); + } + else + { + writer.WriteEncodedInt( -1 ); + } + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_ItemCount = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_BookName = reader.ReadString(); + + m_Filter = new BOBFilter( reader ); + + int count = reader.ReadEncodedInt(); + + m_Entries = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + int v = reader.ReadEncodedInt(); + + switch ( v ) + { + case 0: m_Entries.Add( new BOBLargeEntry( reader ) ); break; + case 1: m_Entries.Add( new BOBSmallEntry( reader ) ); break; + } + } + + break; + } + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1062344, m_Entries.Count.ToString() ); // Deeds in book: ~1_val~ + + if ( m_BookName != null && m_BookName.Length > 0 ) + list.Add( 1062481, m_BookName ); // Book Name: ~1_val~ + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.CheckAlive() && IsChildOf( from.Backpack ) ) + list.Add( new NameBookEntry( from, this ) ); + + SetSecureLevelEntry.AddTo( from, this, list ); + } + + private class NameBookEntry : ContextMenuEntry + { + private Mobile m_From; + private BulkOrderBook m_Book; + + public NameBookEntry( Mobile from, BulkOrderBook book ) : base( 6216 ) + { + m_From = from; + m_Book = book; + } + + public override void OnClick() + { + if ( m_From.CheckAlive() && m_Book.IsChildOf( m_From.Backpack ) ) + { + m_From.Prompt = new NameBookPrompt( m_Book ); + m_From.SendLocalizedMessage( 1062479 ); // Type in the new name of the book: + } + } + } + + private class NameBookPrompt : Prompt + { + private BulkOrderBook m_Book; + + public NameBookPrompt( BulkOrderBook book ) + { + m_Book = book; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( text.Length > 40 ) + text = text.Substring( 0, 40 ); + + if ( from.CheckAlive() && m_Book.IsChildOf( from.Backpack ) ) + { + m_Book.BookName = Utility.FixHtml( text.Trim() ); + + from.SendLocalizedMessage( 1062480 ); // The bulk order book's name has been changed. + } + } + + public override void OnCancel( Mobile from ) + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/BulkMaterialType.cs b/Scripts/Engines/BulkOrders/BulkMaterialType.cs new file mode 100644 index 0000000..a12bd49 --- /dev/null +++ b/Scripts/Engines/BulkOrders/BulkMaterialType.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.BulkOrders +{ + public enum BulkMaterialType + { + None, + DullCopper, + ShadowIron, + Copper, + Bronze, + Gold, + Agapite, + Verite, + Valorite, + Spined, + Horned, + Barbed, + Daemon + } + + public enum BulkGenericType + { + Iron, + Cloth, + Leather + } + + public class BGTClassifier + { + public static BulkGenericType Classify( BODType deedType, Type itemType ) + { + if ( deedType == BODType.Tailor ) + { + if ( itemType == null || itemType.IsSubclassOf( typeof( BaseArmor ) ) || itemType.IsSubclassOf( typeof( BaseShoes ) ) ) + return BulkGenericType.Leather; + + return BulkGenericType.Cloth; + } + + return BulkGenericType.Iron; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeBOD.cs b/Scripts/Engines/BulkOrders/LargeBOD.cs new file mode 100644 index 0000000..5630ea4 --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeBOD.cs @@ -0,0 +1,268 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Engines.BulkOrders +{ + [TypeAlias( "Scripts.Engines.BulkOrders.LargeBOD" )] + public abstract class LargeBOD : Item + { + private int m_AmountMax; + private bool m_RequireExceptional; + private BulkMaterialType m_Material; + private LargeBulkEntry[] m_Entries; + + [CommandProperty( AccessLevel.GameMaster )] + public int AmountMax{ get{ return m_AmountMax; } set{ m_AmountMax = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RequireExceptional{ get{ return m_RequireExceptional; } set{ m_RequireExceptional = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public BulkMaterialType Material{ get{ return m_Material; } set{ m_Material = value; InvalidateProperties(); } } + + public LargeBulkEntry[] Entries{ get{ return m_Entries; } set{ m_Entries = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Complete + { + get + { + for ( int i = 0; i < m_Entries.Length; ++i ) + { + if ( m_Entries[i].Amount < m_AmountMax ) + return false; + } + + return true; + } + } + + public abstract List ComputeRewards( bool full ); + public abstract int ComputeGold(); + public abstract int ComputeFame(); + + public virtual void GetRewards( out Item reward, out int gold, out int fame ) + { + reward = null; + gold = ComputeGold(); + fame = ComputeFame(); + + List rewards = ComputeRewards( false ); + + if ( rewards.Count > 0 ) + { + reward = rewards[Utility.Random( rewards.Count )]; + + for ( int i = 0; i < rewards.Count; ++i ) + { + if ( rewards[i] != reward ) + rewards[i].Delete(); + } + } + } + + public static BulkMaterialType GetRandomMaterial( BulkMaterialType start, double[] chances ) + { + double random = Utility.RandomDouble(); + + for ( int i = 0; i < chances.Length; ++i ) + { + if ( random < chances[i] ) + return ( i == 0 ? BulkMaterialType.None : start + (i - 1) ); + + random -= chances[i]; + } + + return BulkMaterialType.None; + } + + public override int LabelNumber{ get{ return 1045151; } } // a bulk order deed + + public LargeBOD( int hue, int amountMax, bool requireExeptional, BulkMaterialType material, LargeBulkEntry[] entries ) : base( Core.AOS ? 0x2258 : 0x14EF ) + { + Weight = 1.0; + Hue = hue; // Blacksmith: 0x44E; Tailoring: 0x483 + LootType = LootType.Blessed; + + m_AmountMax = amountMax; + m_RequireExceptional = requireExeptional; + m_Material = material; + m_Entries = entries; + } + + public LargeBOD() : base( Core.AOS ? 0x2258 : 0x14EF ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060655 ); // large bulk order + + if ( m_RequireExceptional ) + list.Add( 1045141 ); // All items must be exceptional. + + if ( m_Material != BulkMaterialType.None ) + list.Add( LargeBODGump.GetMaterialNumberFor( m_Material ) ); // All items must be made with x material. + + list.Add( 1060656, m_AmountMax.ToString() ); // amount to make: ~1_val~ + + for ( int i = 0; i < m_Entries.Length; ++i ) + list.Add( 1060658 + i, "#{0}\t{1}", m_Entries[i].Details.Number, m_Entries[i].Amount ); // ~1_val~: ~2_val~ + } + + public override void OnDoubleClickNotAccessible(Mobile from) + { + OnDoubleClick(from); + } + + public override void OnDoubleClickSecureTrade(Mobile from) + { + OnDoubleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack) || InSecureTrade || RootParent is PlayerVendor) + from.SendGump(new LargeBODGump(from, this)); + else + from.SendLocalizedMessage(1045156); // You must have the deed in your backpack to use it. + } + + public void BeginCombine( Mobile from ) + { + if ( !Complete ) + from.Target = new LargeBODTarget( this ); + else + from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed. + } + + public void EndCombine( Mobile from, object o ) + { + if ( o is Item && ((Item)o).IsChildOf( from.Backpack ) ) + { + if ( o is SmallBOD ) + { + SmallBOD small = (SmallBOD)o; + + LargeBulkEntry entry = null; + + for ( int i = 0; entry == null && i < m_Entries.Length; ++i ) + { + if ( m_Entries[i].Details.Type == small.Type ) + entry = m_Entries[i]; + } + + if ( entry == null ) + { + from.SendLocalizedMessage( 1045160 ); // That is not a bulk order for this large request. + } + else if ( m_RequireExceptional && !small.RequireExceptional ) + { + from.SendLocalizedMessage( 1045161 ); // Both orders must be of exceptional quality. + } + else if ( m_Material >= BulkMaterialType.DullCopper && m_Material <= BulkMaterialType.Valorite && small.Material != m_Material ) + { + from.SendLocalizedMessage( 1045162 ); // Both orders must use the same ore type. + } + else if ( m_Material >= BulkMaterialType.Spined && m_Material <= BulkMaterialType.Barbed && small.Material != m_Material ) + { + from.SendLocalizedMessage( 1049351 ); // Both orders must use the same leather type. + } + else if ( m_AmountMax != small.AmountMax ) + { + from.SendLocalizedMessage( 1045163 ); // The two orders have different requested amounts and cannot be combined. + } + else if ( small.AmountCur < small.AmountMax ) + { + from.SendLocalizedMessage( 1045164 ); // The order to combine with is not completed. + } + else if ( entry.Amount >= m_AmountMax ) + { + from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed. + } + else + { + entry.Amount += small.AmountCur; + small.Delete(); + + from.SendLocalizedMessage( 1045165 ); // The orders have been combined. + + from.SendGump( new LargeBODGump( from, this ) ); + + if ( !Complete ) + BeginCombine( from ); + } + } + else + { + from.SendLocalizedMessage( 1045159 ); // That is not a bulk order. + } + } + else + { + from.SendLocalizedMessage( 1045158 ); // You must have the item in your backpack to target it. + } + } + + public LargeBOD( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_AmountMax ); + writer.Write( m_RequireExceptional ); + writer.Write( (int) m_Material ); + + writer.Write( (int) m_Entries.Length ); + + for ( int i = 0; i < m_Entries.Length; ++i ) + m_Entries[i].Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_AmountMax = reader.ReadInt(); + m_RequireExceptional = reader.ReadBool(); + m_Material = (BulkMaterialType)reader.ReadInt(); + + m_Entries = new LargeBulkEntry[reader.ReadInt()]; + + for ( int i = 0; i < m_Entries.Length; ++i ) + m_Entries[i] = new LargeBulkEntry( this, reader ); + + break; + } + } + + if ( Weight == 0.0 ) + Weight = 1.0; + + if ( Core.AOS && ItemID == 0x14EF ) + ItemID = 0x2258; + + if ( Parent == null && Map == Map.Internal && Location == Point3D.Zero ) + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeBODAcceptGump.cs b/Scripts/Engines/BulkOrders/LargeBODAcceptGump.cs new file mode 100644 index 0000000..6d691d0 --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeBODAcceptGump.cs @@ -0,0 +1,106 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.BulkOrders +{ + public class LargeBODAcceptGump : Gump + { + private LargeBOD m_Deed; + private Mobile m_From; + + public LargeBODAcceptGump( Mobile from, LargeBOD deed ) : base( 50, 50 ) + { + m_From = from; + m_Deed = deed; + + m_From.CloseGump( typeof( LargeBODAcceptGump ) ); + m_From.CloseGump( typeof( SmallBODAcceptGump ) ); + + LargeBulkEntry[] entries = deed.Entries; + + AddPage( 0 ); + + AddBackground( 25, 10, 430, 240 + (entries.Length * 24), 5054 ); + + AddImageTiled( 33, 20, 413, 221 + (entries.Length * 24), 2624 ); + AddAlphaRegion( 33, 20, 413, 221 + (entries.Length * 24) ); + + AddImage( 20, 5, 10460 ); + AddImage( 430, 5, 10460 ); + AddImage( 20, 225 + (entries.Length * 24), 10460 ); + AddImage( 430, 225 + (entries.Length * 24), 10460 ); + + AddHtmlLocalized( 180, 25, 120, 20, 1045134, 0x7FFF, false, false ); // A large bulk order + + AddHtmlLocalized( 40, 48, 350, 20, 1045135, 0x7FFF, false, false ); // Ah! Thanks for the goods! Would you help me out? + + AddHtmlLocalized( 40, 72, 210, 20, 1045138, 0x7FFF, false, false ); // Amount to make: + AddLabel( 250, 72, 1152, deed.AmountMax.ToString() ); + + AddHtmlLocalized( 40, 96, 120, 20, 1045137, 0x7FFF, false, false ); // Items requested: + + int y = 120; + + for ( int i = 0; i < entries.Length; ++i, y += 24 ) + AddHtmlLocalized( 40, y, 210, 20, entries[i].Details.Number, 0x7FFF, false, false ); + + if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None ) + { + AddHtmlLocalized( 40, y, 210, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet: + y += 24; + + if ( deed.RequireExceptional ) + { + AddHtmlLocalized( 40, y, 350, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional. + y += 24; + } + + if ( deed.Material != BulkMaterialType.None ) + { + AddHtmlLocalized( 40, y, 350, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material. + y += 24; + } + } + + AddHtmlLocalized( 40, 192 + (entries.Length * 24), 350, 20, 1045139, 0x7FFF, false, false ); // Do you want to accept this order? + + AddButton( 100, 216 + (entries.Length * 24), 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 135, 216 + (entries.Length * 24), 120, 20, 1006044, 0x7FFF, false, false ); // Ok + + AddButton( 275, 216 + (entries.Length * 24), 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 310, 216 + (entries.Length * 24), 120, 20, 1011012, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) // Ok + { + if ( m_From.PlaceInBackpack( m_Deed ) ) + { + m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack. + } + else + { + m_From.SendLocalizedMessage( 1045150 ); // There is not enough room in your backpack for the deed. + m_Deed.Delete(); + } + } + else + { + m_Deed.Delete(); + } + } + + public static int GetMaterialNumberFor( BulkMaterialType material ) + { + if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) + return 1045142 + (int)(material - BulkMaterialType.DullCopper); + else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed ) + return 1049348 + (int)(material - BulkMaterialType.Spined); + + return 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeBODGump.cs b/Scripts/Engines/BulkOrders/LargeBODGump.cs new file mode 100644 index 0000000..8e85a5d --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeBODGump.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.BulkOrders +{ + public class LargeBODGump : Gump + { + private LargeBOD m_Deed; + private Mobile m_From; + + public LargeBODGump( Mobile from, LargeBOD deed ) : base( 25, 25 ) + { + m_From = from; + m_Deed = deed; + + m_From.CloseGump( typeof( LargeBODGump ) ); + m_From.CloseGump( typeof( SmallBODGump ) ); + + LargeBulkEntry[] entries = deed.Entries; + + AddPage( 0 ); + + AddBackground( 50, 10, 455, 236 + (entries.Length * 24), 5054 ); + + AddImageTiled( 58, 20, 438, 217 + (entries.Length * 24), 2624 ); + AddAlphaRegion( 58, 20, 438, 217 + (entries.Length * 24) ); + + AddImage( 45, 5, 10460 ); + AddImage( 480, 5, 10460 ); + AddImage( 45, 221 + (entries.Length * 24), 10460 ); + AddImage( 480, 221 + (entries.Length * 24), 10460 ); + + AddHtmlLocalized( 225, 25, 120, 20, 1045134, 0x7FFF, false, false ); // A large bulk order + + AddHtmlLocalized( 75, 48, 250, 20, 1045138, 0x7FFF, false, false ); // Amount to make: + AddLabel( 275, 48, 1152, deed.AmountMax.ToString() ); + + AddHtmlLocalized( 75, 72, 120, 20, 1045137, 0x7FFF, false, false ); // Items requested: + AddHtmlLocalized( 275, 76, 200, 20, 1045153, 0x7FFF, false, false ); // Amount finished: + + int y = 96; + + for ( int i = 0; i < entries.Length; ++i ) + { + LargeBulkEntry entry = entries[i]; + SmallBulkEntry details = entry.Details; + + AddHtmlLocalized( 75, y, 210, 20, details.Number, 0x7FFF, false, false ); + AddLabel( 275, y, 0x480, entry.Amount.ToString() ); + + y += 24; + } + + if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None ) + { + AddHtmlLocalized( 75, y, 200, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet: + y += 24; + } + + if ( deed.RequireExceptional ) + { + AddHtmlLocalized( 75, y, 300, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional. + y += 24; + } + + if ( deed.Material != BulkMaterialType.None ) + AddHtmlLocalized( 75, y, 300, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material. + + AddButton( 125, 168 + (entries.Length * 24), 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 160, 168 + (entries.Length * 24), 300, 20, 1045155, 0x7FFF, false, false ); // Combine this deed with another deed. + + AddButton( 125, 192 + (entries.Length * 24), 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 160, 192 + (entries.Length * 24), 120, 20, 1011441, 0x7FFF, false, false ); // EXIT + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed.Deleted || !m_Deed.IsChildOf( m_From.Backpack ) ) + return; + + if ( info.ButtonID == 2 ) // Combine + { + m_From.SendGump( new LargeBODGump( m_From, m_Deed ) ); + m_Deed.BeginCombine( m_From ); + } + } + + public static int GetMaterialNumberFor( BulkMaterialType material ) + { + if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) + return 1045142 + (int)(material - BulkMaterialType.DullCopper); + else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed ) + return 1049348 + (int)(material - BulkMaterialType.Spined); + + return 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeBODTarget.cs b/Scripts/Engines/BulkOrders/LargeBODTarget.cs new file mode 100644 index 0000000..e010221 --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeBODTarget.cs @@ -0,0 +1,25 @@ +using System; +using Server; +using Server.Targeting; +using Server.Network; + +namespace Server.Engines.BulkOrders +{ + public class LargeBODTarget : Target + { + private LargeBOD m_Deed; + + public LargeBODTarget( LargeBOD deed ) : base( 18, false, TargetFlags.None ) + { + m_Deed = deed; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Deed.Deleted || !m_Deed.IsChildOf( from.Backpack ) ) + return; + + m_Deed.EndCombine( from, targeted ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeBulkEntry.cs b/Scripts/Engines/BulkOrders/LargeBulkEntry.cs new file mode 100644 index 0000000..403de76 --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeBulkEntry.cs @@ -0,0 +1,189 @@ +using System; +using System.IO; +using System.Collections; +using Server; + +namespace Server.Engines.BulkOrders +{ + public class LargeBulkEntry + { + private LargeBOD m_Owner; + private int m_Amount; + private SmallBulkEntry m_Details; + + public LargeBOD Owner{ get{ return m_Owner; } set{ m_Owner = value; } } + public int Amount{ get{ return m_Amount; } set{ m_Amount = value; if ( m_Owner != null ) m_Owner.InvalidateProperties(); } } + public SmallBulkEntry Details{ get{ return m_Details; } } + + public static SmallBulkEntry[] LargeRing + { + get{ return GetEntries( "Blacksmith", "largering" ); } + } + + public static SmallBulkEntry[] LargePlate + { + get{ return GetEntries( "Blacksmith", "largeplate" ); } + } + + public static SmallBulkEntry[] LargeChain + { + get{ return GetEntries( "Blacksmith", "largechain" ); } + } + + public static SmallBulkEntry[] LargeAxes + { + get{ return GetEntries( "Blacksmith", "largeaxes" ); } + } + + public static SmallBulkEntry[] LargeFencing + { + get{ return GetEntries( "Blacksmith", "largefencing" ); } + } + + public static SmallBulkEntry[] LargeMaces + { + get{ return GetEntries( "Blacksmith", "largemaces" ); } + } + + public static SmallBulkEntry[] LargePolearms + { + get{ return GetEntries( "Blacksmith", "largepolearms" ); } + } + + public static SmallBulkEntry[] LargeSwords + { + get{ return GetEntries( "Blacksmith", "largeswords" ); } + } + + + public static SmallBulkEntry[] BoneSet + { + get{ return GetEntries( "Tailoring", "boneset" ); } + } + + public static SmallBulkEntry[] Farmer + { + get{ return GetEntries( "Tailoring", "farmer" ); } + } + + public static SmallBulkEntry[] FemaleLeatherSet + { + get{ return GetEntries( "Tailoring", "femaleleatherset" ); } + } + + public static SmallBulkEntry[] FisherGirl + { + get{ return GetEntries( "Tailoring", "fishergirl" ); } + } + + public static SmallBulkEntry[] Gypsy + { + get{ return GetEntries( "Tailoring", "gypsy" ); } + } + + public static SmallBulkEntry[] HatSet + { + get{ return GetEntries( "Tailoring", "hatset" ); } + } + + public static SmallBulkEntry[] Jester + { + get{ return GetEntries( "Tailoring", "jester" ); } + } + + public static SmallBulkEntry[] Lady + { + get{ return GetEntries( "Tailoring", "lady" ); } + } + + public static SmallBulkEntry[] MaleLeatherSet + { + get{ return GetEntries( "Tailoring", "maleleatherset" ); } + } + + public static SmallBulkEntry[] Pirate + { + get{ return GetEntries( "Tailoring", "pirate" ); } + } + + public static SmallBulkEntry[] ShoeSet + { + get{ return GetEntries( "Tailoring", "shoeset" ); } + } + + public static SmallBulkEntry[] StuddedSet + { + get{ return GetEntries( "Tailoring", "studdedset" ); } + } + + public static SmallBulkEntry[] TownCrier + { + get{ return GetEntries( "Tailoring", "towncrier" ); } + } + + public static SmallBulkEntry[] Wizard + { + get{ return GetEntries( "Tailoring", "wizard" ); } + } + + + private static Hashtable m_Cache; + + public static SmallBulkEntry[] GetEntries( string type, string name ) + { + if ( m_Cache == null ) + m_Cache = new Hashtable(); + + Hashtable table = (Hashtable)m_Cache[type]; + + if ( table == null ) + m_Cache[type] = table = new Hashtable(); + + SmallBulkEntry[] entries = (SmallBulkEntry[])table[name]; + + if ( entries == null ) + table[name] = entries = SmallBulkEntry.LoadEntries( type, name ); + + return entries; + } + + public static LargeBulkEntry[] ConvertEntries( LargeBOD owner, SmallBulkEntry[] small ) + { + LargeBulkEntry[] large = new LargeBulkEntry[small.Length]; + + for ( int i = 0; i < small.Length; ++i ) + large[i] = new LargeBulkEntry( owner, small[i] ); + + return large; + } + + public LargeBulkEntry( LargeBOD owner, SmallBulkEntry details ) + { + m_Owner = owner; + m_Details = details; + } + + public LargeBulkEntry( LargeBOD owner, GenericReader reader ) + { + m_Owner = owner; + m_Amount = reader.ReadInt(); + + Type realType = null; + + string type = reader.ReadString(); + + if ( type != null ) + realType = ScriptCompiler.FindTypeByFullName( type ); + + m_Details = new SmallBulkEntry( realType, reader.ReadInt(), reader.ReadInt() ); + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( m_Amount ); + writer.Write( m_Details.Type == null ? null : m_Details.Type.FullName ); + writer.Write( m_Details.Number ); + writer.Write( m_Details.Graphic ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeSmithBOD.cs b/Scripts/Engines/BulkOrders/LargeSmithBOD.cs new file mode 100644 index 0000000..b1d2635 --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeSmithBOD.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Mat = Server.Engines.BulkOrders.BulkMaterialType; +using System.Collections.Generic; + +namespace Server.Engines.BulkOrders +{ + [TypeAlias( "Scripts.Engines.BulkOrders.LargeSmithBOD" )] + public class LargeSmithBOD : LargeBOD + { + public static double[] m_BlacksmithMaterialChances = new double[] + { + 0.501953125, // None + 0.250000000, // Dull Copper + 0.125000000, // Shadow Iron + 0.062500000, // Copper + 0.031250000, // Bronze + 0.015625000, // Gold + 0.007812500, // Agapite + 0.003906250, // Verite + 0.001953125 // Valorite + }; + + public override int ComputeFame() + { + return SmithRewardCalculator.Instance.ComputeFame( this ); + } + + public override int ComputeGold() + { + return SmithRewardCalculator.Instance.ComputeGold( this ); + } + + [Constructable] + public LargeSmithBOD() + { + LargeBulkEntry[] entries; + bool useMaterials = true; + + int rand = Utility.Random( 8 ); + + switch ( rand ) + { + default: + case 0: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeRing ); break; + case 1: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargePlate ); break; + case 2: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeChain ); break; + case 3: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeAxes ); break; + case 4: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeFencing ); break; + case 5: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeMaces ); break; + case 6: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargePolearms ); break; + case 7: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.LargeSwords ); break; + } + + if( rand > 2 && rand < 8 ) + useMaterials = false; + + int hue = 0x44E; + int amountMax = Utility.RandomList( 10, 15, 20, 20 ); + bool reqExceptional = ( 0.825 > Utility.RandomDouble() ); + + BulkMaterialType material; + + if ( useMaterials ) + material = GetRandomMaterial( BulkMaterialType.DullCopper, m_BlacksmithMaterialChances ); + else + material = BulkMaterialType.None; + + this.Hue = hue; + this.AmountMax = amountMax; + this.Entries = entries; + this.RequireExceptional = reqExceptional; + this.Material = material; + } + + public LargeSmithBOD( int amountMax, bool reqExceptional, BulkMaterialType mat, LargeBulkEntry[] entries ) + { + this.Hue = 0x44E; + this.AmountMax = amountMax; + this.Entries = entries; + this.RequireExceptional = reqExceptional; + this.Material = mat; + } + + public override List ComputeRewards( bool full ) + { + List list = new List(); + + RewardGroup rewardGroup = SmithRewardCalculator.Instance.LookupRewards( SmithRewardCalculator.Instance.ComputePoints( this ) ); + + if ( rewardGroup != null ) + { + if ( full ) + { + for ( int i = 0; i < rewardGroup.Items.Length; ++i ) + { + Item item = rewardGroup.Items[i].Construct(); + + if ( item != null ) + list.Add( item ); + } + } + else + { + RewardItem rewardItem = rewardGroup.AcquireItem(); + + if ( rewardItem != null ) + { + Item item = rewardItem.Construct(); + + if ( item != null ) + list.Add( item ); + } + } + } + + return list; + } + + public LargeSmithBOD( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/LargeTailorBOD.cs b/Scripts/Engines/BulkOrders/LargeTailorBOD.cs new file mode 100644 index 0000000..8db9279 --- /dev/null +++ b/Scripts/Engines/BulkOrders/LargeTailorBOD.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Mat = Server.Engines.BulkOrders.BulkMaterialType; +using System.Collections.Generic; + +namespace Server.Engines.BulkOrders +{ + public class LargeTailorBOD : LargeBOD + { + public static double[] m_TailoringMaterialChances = new double[] + { + 0.857421875, // None + 0.125000000, // Spined + 0.015625000, // Horned + 0.001953125 // Barbed + }; + + public override int ComputeFame() + { + return TailorRewardCalculator.Instance.ComputeFame( this ); + } + + public override int ComputeGold() + { + return TailorRewardCalculator.Instance.ComputeGold( this ); + } + + [Constructable] + public LargeTailorBOD() + { + LargeBulkEntry[] entries; + bool useMaterials = false; + + switch ( Utility.Random( 14 ) ) + { + default: + case 0: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Farmer ); break; + case 1: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.FemaleLeatherSet ); useMaterials = true; break; + case 2: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.FisherGirl ); break; + case 3: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Gypsy ); break; + case 4: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.HatSet ); break; + case 5: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Jester ); break; + case 6: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Lady ); break; + case 7: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.MaleLeatherSet ); useMaterials = true; break; + case 8: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Pirate ); break; + case 9: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.ShoeSet ); useMaterials = Core.ML; break; + case 10: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.StuddedSet ); useMaterials = true; break; + case 11: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.TownCrier ); break; + case 12: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.Wizard ); break; + case 13: entries = LargeBulkEntry.ConvertEntries( this, LargeBulkEntry.BoneSet ); useMaterials = true; break; + } + + int hue = 0x483; + int amountMax = Utility.RandomList( 10, 15, 20, 20 ); + bool reqExceptional = ( 0.825 > Utility.RandomDouble() ); + + BulkMaterialType material; + + if ( useMaterials ) + material = GetRandomMaterial( BulkMaterialType.Spined, m_TailoringMaterialChances ); + else + material = BulkMaterialType.None; + + this.Hue = hue; + this.AmountMax = amountMax; + this.Entries = entries; + this.RequireExceptional = reqExceptional; + this.Material = material; + } + + public LargeTailorBOD( int amountMax, bool reqExceptional, BulkMaterialType mat, LargeBulkEntry[] entries ) + { + this.Hue = 0x483; + this.AmountMax = amountMax; + this.Entries = entries; + this.RequireExceptional = reqExceptional; + this.Material = mat; + } + + public override List ComputeRewards( bool full ) + { + List list = new List(); + + RewardGroup rewardGroup = TailorRewardCalculator.Instance.LookupRewards( TailorRewardCalculator.Instance.ComputePoints( this ) ); + + if ( rewardGroup != null ) + { + if ( full ) + { + for ( int i = 0; i < rewardGroup.Items.Length; ++i ) + { + Item item = rewardGroup.Items[i].Construct(); + + if ( item != null ) + list.Add( item ); + } + } + else + { + RewardItem rewardItem = rewardGroup.AcquireItem(); + + if ( rewardItem != null ) + { + Item item = rewardItem.Construct(); + + if ( item != null ) + list.Add( item ); + } + } + } + + return list; + } + + public LargeTailorBOD( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/Rewards.cs b/Scripts/Engines/BulkOrders/Rewards.cs new file mode 100644 index 0000000..ea43c7d --- /dev/null +++ b/Scripts/Engines/BulkOrders/Rewards.cs @@ -0,0 +1,740 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.BulkOrders +{ + public delegate Item ConstructCallback( int type ); + + public sealed class RewardType + { + private int m_Points; + private Type[] m_Types; + + public int Points{ get{ return m_Points; } } + public Type[] Types{ get{ return m_Types; } } + + public RewardType( int points, params Type[] types ) + { + m_Points = points; + m_Types = types; + } + + public bool Contains( Type type ) + { + for ( int i = 0; i < m_Types.Length; ++i ) + { + if ( m_Types[i] == type ) + return true; + } + + return false; + } + } + + public sealed class RewardItem + { + private int m_Weight; + private ConstructCallback m_Constructor; + private int m_Type; + + public int Weight{ get{ return m_Weight; } } + public ConstructCallback Constructor{ get{ return m_Constructor; } } + public int Type{ get{ return m_Type; } } + + public RewardItem( int weight, ConstructCallback constructor ) : this( weight, constructor, 0 ) + { + } + + public RewardItem( int weight, ConstructCallback constructor, int type ) + { + m_Weight = weight; + m_Constructor = constructor; + m_Type = type; + } + + public Item Construct() + { + try{ return m_Constructor( m_Type ); } + catch{ return null; } + } + } + + public sealed class RewardGroup + { + private int m_Points; + private RewardItem[] m_Items; + + public int Points{ get{ return m_Points; } } + public RewardItem[] Items{ get{ return m_Items; } } + + public RewardGroup( int points, params RewardItem[] items ) + { + m_Points = points; + m_Items = items; + } + + public RewardItem AcquireItem() + { + if ( m_Items.Length == 0 ) + return null; + else if ( m_Items.Length == 1 ) + return m_Items[0]; + + int totalWeight = 0; + + for ( int i = 0; i < m_Items.Length; ++i ) + totalWeight += m_Items[i].Weight; + + int randomWeight = Utility.Random( totalWeight ); + + for ( int i = 0; i < m_Items.Length; ++i ) + { + RewardItem item = m_Items[i]; + + if ( randomWeight < item.Weight ) + return item; + + randomWeight -= item.Weight; + } + + return null; + } + } + + public abstract class RewardCalculator + { + private RewardGroup[] m_Groups; + + public RewardGroup[] Groups{ get{ return m_Groups; } set{ m_Groups = value; } } + + public abstract int ComputePoints( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type ); + public abstract int ComputeGold( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type ); + + public virtual int ComputeFame( SmallBOD bod ) + { + int points = ComputePoints( bod ) / 50; + + return points * points; + } + + public virtual int ComputeFame( LargeBOD bod ) + { + int points = ComputePoints( bod ) / 50; + + return points * points; + } + + public virtual int ComputePoints( SmallBOD bod ) + { + return ComputePoints( bod.AmountMax, bod.RequireExceptional, bod.Material, 1, bod.Type ); + } + + public virtual int ComputePoints( LargeBOD bod ) + { + return ComputePoints( bod.AmountMax, bod.RequireExceptional, bod.Material, bod.Entries.Length, bod.Entries[0].Details.Type ); + } + + public virtual int ComputeGold( SmallBOD bod ) + { + return ComputeGold( bod.AmountMax, bod.RequireExceptional, bod.Material, 1, bod.Type ); + } + + public virtual int ComputeGold( LargeBOD bod ) + { + return ComputeGold( bod.AmountMax, bod.RequireExceptional, bod.Material, bod.Entries.Length, bod.Entries[0].Details.Type ); + } + + public virtual RewardGroup LookupRewards( int points ) + { + for ( int i = m_Groups.Length - 1; i >= 1; --i ) + { + RewardGroup group = m_Groups[i]; + + if ( points >= group.Points ) + return group; + } + + return m_Groups[0]; + } + + public virtual int LookupTypePoints( RewardType[] types, Type type ) + { + for ( int i = 0; i < types.Length; ++i ) + { + if ( types[i].Contains( type ) ) + return types[i].Points; + } + + return 0; + } + + public RewardCalculator() + { + } + } + + public sealed class SmithRewardCalculator : RewardCalculator + { + #region Constructors + private static readonly ConstructCallback SturdyShovel = new ConstructCallback( CreateSturdyShovel ); + private static readonly ConstructCallback SturdyPickaxe = new ConstructCallback( CreateSturdyPickaxe ); + private static readonly ConstructCallback MiningGloves = new ConstructCallback( CreateMiningGloves ); + private static readonly ConstructCallback GargoylesPickaxe = new ConstructCallback( CreateGargoylesPickaxe ); + private static readonly ConstructCallback ProspectorsTool = new ConstructCallback( CreateProspectorsTool ); + private static readonly ConstructCallback PowderOfTemperament = new ConstructCallback( CreatePowderOfTemperament ); + private static readonly ConstructCallback RunicHammer = new ConstructCallback( CreateRunicHammer ); + private static readonly ConstructCallback PowerScroll = new ConstructCallback( CreatePowerScroll ); + private static readonly ConstructCallback ColoredAnvil = new ConstructCallback( CreateColoredAnvil ); + private static readonly ConstructCallback AncientHammer = new ConstructCallback( CreateAncientHammer ); + + private static Item CreateSturdyShovel( int type ) + { + return new SturdyShovel(); + } + + private static Item CreateSturdyPickaxe( int type ) + { + return new SturdyPickaxe(); + } + + private static Item CreateMiningGloves( int type ) + { + if ( type == 1 ) + return new LeatherGlovesOfMining( 1 ); + else if ( type == 3 ) + return new StuddedGlovesOfMining( 3 ); + else if ( type == 5 ) + return new RingmailGlovesOfMining( 5 ); + + throw new InvalidOperationException(); + } + + private static Item CreateGargoylesPickaxe( int type ) + { + return new GargoylesPickaxe(); + } + + private static Item CreateProspectorsTool( int type ) + { + return new ProspectorsTool(); + } + + private static Item CreatePowderOfTemperament( int type ) + { + return new PowderOfTemperament(); + } + + private static Item CreateRunicHammer( int type ) + { + if ( type >= 1 && type <= 8 ) + return new RunicHammer( CraftResource.MIron + type, Core.AOS ? ( 55 - (type*5) ) : 50 ); + + throw new InvalidOperationException(); + } + + private static Item CreatePowerScroll( int type ) + { + if ( type == 5 || type == 10 || type == 15 || type == 20 ) + return new PowerScroll( SkillName.Blacksmith, 100 + type ); + + throw new InvalidOperationException(); + } + + private static Item CreateColoredAnvil( int type ) + { + // Generate an anvil deed, not an actual anvil. + //return new ColoredAnvilDeed(); + + return new ColoredAnvil(); + } + + private static Item CreateAncientHammer( int type ) + { + if ( type == 10 || type == 15 || type == 30 || type == 60 ) + return new AncientSmithyHammer( type ); + + throw new InvalidOperationException(); + } + #endregion + + public static readonly SmithRewardCalculator Instance = new SmithRewardCalculator(); + + private RewardType[] m_Types = new RewardType[] + { + // Armors + new RewardType( 200, typeof( RingmailGloves ), typeof( RingmailChest ), typeof( RingmailArms ), typeof( RingmailLegs ) ), + new RewardType( 300, typeof( ChainCoif ), typeof( ChainLegs ), typeof( ChainChest ) ), + new RewardType( 400, typeof( PlateArms ), typeof( PlateLegs ), typeof( PlateHelm ), typeof( PlateGorget ), typeof( PlateGloves ), typeof( PlateChest ) ), + + // Weapons + new RewardType( 200, typeof( Bardiche ), typeof( Halberd ) ), + new RewardType( 300, typeof( Dagger ), typeof( ShortSpear ), typeof( Spear ), typeof( WarFork ), typeof( Kryss ) ), //OSI put the dagger in there. Odd, ain't it. + new RewardType( 350, typeof( Axe ), typeof( BattleAxe ), typeof( DoubleAxe ), typeof( ExecutionersAxe ), typeof( LargeBattleAxe ), typeof( TwoHandedAxe ) ), + new RewardType( 350, typeof( Broadsword ), typeof( Cutlass ), typeof( Katana ), typeof( Longsword ), typeof( Scimitar ), /*typeof( ThinLongsword ),*/ typeof( VikingSword ) ), + new RewardType( 350, typeof( WarAxe ), typeof( HammerPick ), typeof( Mace ), typeof( Maul ), typeof( WarHammer ), typeof( WarMace ) ) + }; + + public override int ComputePoints( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type ) + { + int points = 0; + + if ( quantity == 10 ) + points += 10; + else if ( quantity == 15 ) + points += 25; + else if ( quantity == 20 ) + points += 50; + + if ( exceptional ) + points += 200; + + if ( itemCount > 1 ) + points += LookupTypePoints( m_Types, type ); + + if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) + points += 200 + (50 * (material - BulkMaterialType.DullCopper)); + + return points; + } + + private static int[][][] m_GoldTable = new int[][][] + { + new int[][] // 1-part (regular) + { + new int[]{ 150, 250, 250, 400, 400, 750, 750, 1200, 1200 }, + new int[]{ 225, 375, 375, 600, 600, 1125, 1125, 1800, 1800 }, + new int[]{ 300, 500, 750, 800, 1050, 1500, 2250, 2400, 4000 } + }, + new int[][] // 1-part (exceptional) + { + new int[]{ 250, 400, 400, 750, 750, 1500, 1500, 3000, 3000 }, + new int[]{ 375, 600, 600, 1125, 1125, 2250, 2250, 4500, 4500 }, + new int[]{ 500, 800, 1200, 1500, 2500, 3000, 6000, 6000, 12000 } + }, + new int[][] // Ringmail (regular) + { + new int[]{ 3000, 5000, 5000, 7500, 7500, 10000, 10000, 15000, 15000 }, + new int[]{ 4500, 7500, 7500, 11250, 11500, 15000, 15000, 22500, 22500 }, + new int[]{ 6000, 10000, 15000, 15000, 20000, 20000, 30000, 30000, 50000 } + }, + new int[][] // Ringmail (exceptional) + { + new int[]{ 5000, 10000, 10000, 15000, 15000, 25000, 25000, 50000, 50000 }, + new int[]{ 7500, 15000, 15000, 22500, 22500, 37500, 37500, 75000, 75000 }, + new int[]{ 10000, 20000, 30000, 30000, 50000, 50000, 100000, 100000, 200000 } + }, + new int[][] // Chainmail (regular) + { + new int[]{ 4000, 7500, 7500, 10000, 10000, 15000, 15000, 25000, 25000 }, + new int[]{ 6000, 11250, 11250, 15000, 15000, 22500, 22500, 37500, 37500 }, + new int[]{ 8000, 15000, 20000, 20000, 30000, 30000, 50000, 50000, 100000 } + }, + new int[][] // Chainmail (exceptional) + { + new int[]{ 7500, 15000, 15000, 25000, 25000, 50000, 50000, 100000, 100000 }, + new int[]{ 11250, 22500, 22500, 37500, 37500, 75000, 75000, 150000, 150000 }, + new int[]{ 15000, 30000, 50000, 50000, 100000, 100000, 200000, 200000, 200000 } + }, + new int[][] // Platemail (regular) + { + new int[]{ 5000, 10000, 10000, 15000, 15000, 25000, 25000, 50000, 50000 }, + new int[]{ 7500, 15000, 15000, 22500, 22500, 37500, 37500, 75000, 75000 }, + new int[]{ 10000, 20000, 30000, 30000, 50000, 50000, 100000, 100000, 200000 } + }, + new int[][] // Platemail (exceptional) + { + new int[]{ 10000, 25000, 25000, 50000, 50000, 100000, 100000, 100000, 100000 }, + new int[]{ 15000, 37500, 37500, 75000, 75000, 150000, 150000, 150000, 150000 }, + new int[]{ 20000, 50000, 100000, 100000, 200000, 200000, 200000, 200000, 200000 } + }, + new int[][] // 2-part weapons (regular) + { + new int[]{ 3000, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 4500, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 6000, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + new int[][] // 2-part weapons (exceptional) + { + new int[]{ 5000, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 7500, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 10000, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + new int[][] // 5-part weapons (regular) + { + new int[]{ 4000, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 6000, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 8000, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + new int[][] // 5-part weapons (exceptional) + { + new int[]{ 7500, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 11250, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 15000, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + new int[][] // 6-part weapons (regular) + { + new int[]{ 4000, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 6000, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 10000, 0, 0, 0, 0, 0, 0, 0, 0 } + }, + new int[][] // 6-part weapons (exceptional) + { + new int[]{ 7500, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 11250, 0, 0, 0, 0, 0, 0, 0, 0 }, + new int[]{ 15000, 0, 0, 0, 0, 0, 0, 0, 0 } + } + }; + + private int ComputeType( Type type, int itemCount ) + { + // Item count of 1 means it's a small BOD. + if ( itemCount == 1 ) + return 0; + + int typeIdx; + + // Loop through the RewardTypes defined earlier and find the correct one. + for ( typeIdx = 0; typeIdx < 7; ++typeIdx ) + { + if ( m_Types[typeIdx].Contains( type ) ) + break; + } + + // Types 5, 6 and 7 are Large Weapon BODs with the same rewards. + if ( typeIdx > 5 ) + typeIdx = 5; + + return ( typeIdx + 1 ) * 2; + } + + public override int ComputeGold( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type ) + { + int[][][] goldTable = m_GoldTable; + + int typeIndex = ComputeType( type, itemCount ); + int quanIndex = ( quantity == 20 ? 2 : quantity == 15 ? 1 : 0 ); + int mtrlIndex = ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) ? 1 + (int)(material - BulkMaterialType.DullCopper) : 0; + + if ( exceptional ) + typeIndex++; + + int gold = goldTable[typeIndex][quanIndex][mtrlIndex]; + + int min = (gold * 9) / 10; + int max = (gold * 10) / 9; + + return Utility.RandomMinMax( min, max ); + } + + public SmithRewardCalculator() + { + Groups = new RewardGroup[] + { + new RewardGroup( 0, new RewardItem( 1, SturdyShovel ) ), + new RewardGroup( 25, new RewardItem( 1, SturdyPickaxe ) ), + new RewardGroup( 50, new RewardItem( 45, SturdyShovel ), new RewardItem( 45, SturdyPickaxe ), new RewardItem( 10, MiningGloves, 1 ) ), + new RewardGroup( 200, new RewardItem( 45, GargoylesPickaxe ), new RewardItem( 45, ProspectorsTool ), new RewardItem( 10, MiningGloves, 3 ) ), + new RewardGroup( 400, new RewardItem( 2, GargoylesPickaxe ), new RewardItem( 2, ProspectorsTool ), new RewardItem( 1, PowderOfTemperament ) ), + new RewardGroup( 450, new RewardItem( 9, PowderOfTemperament ), new RewardItem( 1, MiningGloves, 5 ) ), + new RewardGroup( 500, new RewardItem( 1, RunicHammer, 1 ) ), + new RewardGroup( 550, new RewardItem( 3, RunicHammer, 1 ), new RewardItem( 2, RunicHammer, 2 ) ), + new RewardGroup( 600, new RewardItem( 1, RunicHammer, 2 ) ), + new RewardGroup( 625, new RewardItem( 3, RunicHammer, 2 ), /*new RewardItem( 6, PowerScroll, 5 ),*/ new RewardItem( 1, ColoredAnvil ) ), + new RewardGroup( 650, new RewardItem( 1, RunicHammer, 3 ) ), + new RewardGroup( 675, new RewardItem( 1, ColoredAnvil ),/* new RewardItem( 6, PowerScroll, 10 ),*/ new RewardItem( 3, RunicHammer, 3 ) ), + new RewardGroup( 700, new RewardItem( 1, RunicHammer, 4 ) ), + new RewardGroup( 750, new RewardItem( 1, AncientHammer, 10 ) ), + //new RewardGroup( 800, new RewardItem( 1, PowerScroll, 15 ) ), + new RewardGroup( 850, new RewardItem( 1, AncientHammer, 15 ) ), + //new RewardGroup( 900, new RewardItem( 1, PowerScroll, 20 ) ), + new RewardGroup( 950, new RewardItem( 1, RunicHammer, 5 ) ), + new RewardGroup( 1000, new RewardItem( 1, AncientHammer, 30 ) ), + new RewardGroup( 1050, new RewardItem( 1, RunicHammer, 6 ) ), + new RewardGroup( 1100, new RewardItem( 1, AncientHammer, 60 ) ), + new RewardGroup( 1150, new RewardItem( 1, RunicHammer, 7 ) ), + new RewardGroup( 1200, new RewardItem( 1, RunicHammer, 8 ) ) + }; + } + } + + public sealed class TailorRewardCalculator : RewardCalculator + { + #region Constructors + private static readonly ConstructCallback Cloth = new ConstructCallback( CreateCloth ); + private static readonly ConstructCallback Sandals = new ConstructCallback( CreateSandals ); + private static readonly ConstructCallback StretchedHide = new ConstructCallback( CreateStretchedHide ); + private static readonly ConstructCallback RunicKit = new ConstructCallback( CreateRunicKit ); + private static readonly ConstructCallback Tapestry = new ConstructCallback( CreateTapestry ); + private static readonly ConstructCallback PowerScroll = new ConstructCallback( CreatePowerScroll ); + private static readonly ConstructCallback BearRug = new ConstructCallback( CreateBearRug ); + private static readonly ConstructCallback ClothingBlessDeed = new ConstructCallback( CreateCBD ); + + private static int[][] m_ClothHues = new int[][] + { + new int[]{ 0x483, 0x48C, 0x488, 0x48A }, + new int[]{ 0x495, 0x48B, 0x486, 0x485 }, + new int[]{ 0x48D, 0x490, 0x48E, 0x491 }, + new int[]{ 0x48F, 0x494, 0x484, 0x497 }, + new int[]{ 0x489, 0x47F, 0x482, 0x47E } + }; + + private static Item CreateCloth( int type ) + { + if ( type >= 0 && type < m_ClothHues.Length ) + { + UncutCloth cloth = new UncutCloth( 100 ); + // Scriptiz : les pigments seront trouv�s via un autre syst�me + //cloth.Hue = m_ClothHues[type][Utility.Random( m_ClothHues[type].Length )]; + return cloth; + } + + throw new InvalidOperationException(); + } + + private static int[] m_SandalHues = new int[] + { + 0x489, 0x47F, 0x482, + 0x47E, 0x48F, 0x494, + 0x484, 0x497 + }; + + private static Item CreateSandals( int type ) + { + return new Sandals( m_SandalHues[Utility.Random( m_SandalHues.Length )] ); + } + + private static Item CreateStretchedHide( int type ) + { + switch ( Utility.Random( 4 ) ) + { + default: + case 0: return new SmallStretchedHideEastDeed(); + case 1: return new SmallStretchedHideSouthDeed(); + case 2: return new MediumStretchedHideEastDeed(); + case 3: return new MediumStretchedHideSouthDeed(); + } + } + + private static Item CreateTapestry( int type ) + { + switch ( Utility.Random( 4 ) ) + { + default: + case 0: return new LightFlowerTapestryEastDeed(); + case 1: return new LightFlowerTapestrySouthDeed(); + case 2: return new DarkFlowerTapestryEastDeed(); + case 3: return new DarkFlowerTapestrySouthDeed(); + } + } + + private static Item CreateBearRug( int type ) + { + switch ( Utility.Random( 4 ) ) + { + default: + case 0: return new BrownBearRugEastDeed(); + case 1: return new BrownBearRugSouthDeed(); + case 2: return new PolarBearRugEastDeed(); + case 3: return new PolarBearRugSouthDeed(); + } + } + + private static Item CreateRunicKit( int type ) + { + if ( type >= 1 && type <= 3 ) + return new RunicSewingKit( CraftResource.RegularLeather + type, 60 - (type*15) ); + + throw new InvalidOperationException(); + } + + private static Item CreatePowerScroll( int type ) + { + if ( type == 5 || type == 10 || type == 15 || type == 20 ) + return new PowerScroll( SkillName.Tailoring, 100 + type ); + + throw new InvalidOperationException(); + } + + private static Item CreateCBD( int type ) + { + return new ClothingBlessDeed(); + } + #endregion + + public static readonly TailorRewardCalculator Instance = new TailorRewardCalculator(); + + public override int ComputePoints( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type ) + { + int points = 0; + + if ( quantity == 10 ) + points += 10; + else if ( quantity == 15 ) + points += 25; + else if ( quantity == 20 ) + points += 50; + + if ( exceptional ) + points += 100; + + if ( itemCount == 4 ) + points += 300; + else if ( itemCount == 5 ) + points += 400; + else if ( itemCount == 6 ) + points += 500; + + if ( material == BulkMaterialType.Spined ) + points += 50; + else if ( material == BulkMaterialType.Horned ) + points += 100; + else if ( material == BulkMaterialType.Barbed ) + points += 150; + + return points; + } + + private static int[][][] m_AosGoldTable = new int[][][] + { + new int[][] // 1-part (regular) + { + new int[]{ 150, 150, 300, 300 }, + new int[]{ 225, 225, 450, 450 }, + new int[]{ 300, 400, 600, 750 } + }, + new int[][] // 1-part (exceptional) + { + new int[]{ 300, 300, 600, 600 }, + new int[]{ 450, 450, 900, 900 }, + new int[]{ 600, 750, 1200, 1800 } + }, + new int[][] // 4-part (regular) + { + new int[]{ 4000, 4000, 5000, 5000 }, + new int[]{ 6000, 6000, 7500, 7500 }, + new int[]{ 8000, 10000, 10000, 15000 } + }, + new int[][] // 4-part (exceptional) + { + new int[]{ 5000, 5000, 7500, 7500 }, + new int[]{ 7500, 7500, 11250, 11250 }, + new int[]{ 10000, 15000, 15000, 20000 } + }, + new int[][] // 5-part (regular) + { + new int[]{ 5000, 5000, 7500, 7500 }, + new int[]{ 7500, 7500, 11250, 11250 }, + new int[]{ 10000, 15000, 15000, 20000 } + }, + new int[][] // 5-part (exceptional) + { + new int[]{ 7500, 7500, 10000, 10000 }, + new int[]{ 11250, 11250, 15000, 15000 }, + new int[]{ 15000, 20000, 20000, 30000 } + }, + new int[][] // 6-part (regular) + { + new int[]{ 7500, 7500, 10000, 10000 }, + new int[]{ 11250, 11250, 15000, 15000 }, + new int[]{ 15000, 20000, 20000, 30000 } + }, + new int[][] // 6-part (exceptional) + { + new int[]{ 10000, 10000, 15000, 15000 }, + new int[]{ 15000, 15000, 22500, 22500 }, + new int[]{ 20000, 30000, 30000, 50000 } + } + }; + + private static int[][][] m_OldGoldTable = new int[][][] + { + new int[][] // 1-part (regular) + { + new int[]{ 150, 150, 300, 300 }, + new int[]{ 225, 225, 450, 450 }, + new int[]{ 300, 400, 600, 750 } + }, + new int[][] // 1-part (exceptional) + { + new int[]{ 300, 300, 600, 600 }, + new int[]{ 450, 450, 900, 900 }, + new int[]{ 600, 750, 1200, 1800 } + }, + new int[][] // 4-part (regular) + { + new int[]{ 3000, 3000, 4000, 4000 }, + new int[]{ 4500, 4500, 6000, 6000 }, + new int[]{ 6000, 8000, 8000, 10000 } + }, + new int[][] // 4-part (exceptional) + { + new int[]{ 4000, 4000, 5000, 5000 }, + new int[]{ 6000, 6000, 7500, 7500 }, + new int[]{ 8000, 10000, 10000, 15000 } + }, + new int[][] // 5-part (regular) + { + new int[]{ 4000, 4000, 5000, 5000 }, + new int[]{ 6000, 6000, 7500, 7500 }, + new int[]{ 8000, 10000, 10000, 15000 } + }, + new int[][] // 5-part (exceptional) + { + new int[]{ 5000, 5000, 7500, 7500 }, + new int[]{ 7500, 7500, 11250, 11250 }, + new int[]{ 10000, 15000, 15000, 20000 } + }, + new int[][] // 6-part (regular) + { + new int[]{ 5000, 5000, 7500, 7500 }, + new int[]{ 7500, 7500, 11250, 11250 }, + new int[]{ 10000, 15000, 15000, 20000 } + }, + new int[][] // 6-part (exceptional) + { + new int[]{ 7500, 7500, 10000, 10000 }, + new int[]{ 11250, 11250, 15000, 15000 }, + new int[]{ 15000, 20000, 20000, 30000 } + } + }; + + public override int ComputeGold( int quantity, bool exceptional, BulkMaterialType material, int itemCount, Type type ) + { + int[][][] goldTable = ( Core.AOS ? m_AosGoldTable : m_OldGoldTable ); + + int typeIndex = (( itemCount == 6 ? 3 : itemCount == 5 ? 2 : itemCount == 4 ? 1 : 0 ) * 2) + (exceptional ? 1 : 0); + int quanIndex = ( quantity == 20 ? 2 : quantity == 15 ? 1 : 0 ); + int mtrlIndex = ( material == BulkMaterialType.Barbed ? 3 : material == BulkMaterialType.Horned ? 2 : material == BulkMaterialType.Spined ? 1 : 0 ); + + int gold = goldTable[typeIndex][quanIndex][mtrlIndex]; + + int min = (gold * 9) / 10; + int max = (gold * 10) / 9; + + return Utility.RandomMinMax( min, max ); + } + + public TailorRewardCalculator() + { + Groups = new RewardGroup[] + { + new RewardGroup( 0, new RewardItem( 1, Cloth, 0 ) ), + new RewardGroup( 50, new RewardItem( 1, Cloth, 1 ) ), + new RewardGroup( 100, new RewardItem( 1, Cloth, 2 ) ), + new RewardGroup( 150, new RewardItem( 9, Cloth, 3 ), new RewardItem( 1, Sandals ) ), + new RewardGroup( 200, new RewardItem( 4, Cloth, 4 ), new RewardItem( 1, Sandals ) ), + new RewardGroup( 300, new RewardItem( 1, StretchedHide ) ), + //new RewardGroup( 350, new RewardItem( 1, RunicKit, 1 ) ), + new RewardGroup( 400, /*new RewardItem( 2, PowerScroll, 5 ), */new RewardItem( 3, Tapestry ) ), + new RewardGroup( 500, new RewardItem( 1, BearRug ) ), // Scriptiz : passe de 450 � 500 + //new RewardGroup( 500, new RewardItem( 1, PowerScroll, 10 ) ), + new RewardGroup( 650, new RewardItem( 1, ClothingBlessDeed ) ), // Scriptiz : passe de 550 � 650 + //new RewardGroup( 575, new RewardItem( 1, PowerScroll, 15 ) ), + //new RewardGroup( 600, new RewardItem( 1, RunicKit, 2 ) ), + //new RewardGroup( 650, new RewardItem( 1, PowerScroll, 20 ) ), + //new RewardGroup( 700, new RewardItem( 1, RunicKit, 3 ) ) + }; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallBOD.cs b/Scripts/Engines/BulkOrders/SmallBOD.cs new file mode 100644 index 0000000..54068e9 --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallBOD.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Engines.BulkOrders +{ + [TypeAlias( "Scripts.Engines.BulkOrders.SmallBOD" )] + public abstract class SmallBOD : Item + { + private int m_AmountCur, m_AmountMax; + private Type m_Type; + private int m_Number; + private int m_Graphic; + private bool m_RequireExceptional; + private BulkMaterialType m_Material; + + [CommandProperty( AccessLevel.GameMaster )] + public int AmountCur{ get{ return m_AmountCur; } set{ m_AmountCur = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int AmountMax{ get{ return m_AmountMax; } set{ m_AmountMax = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Type Type{ get{ return m_Type; } set{ m_Type = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Number{ get{ return m_Number; } set{ m_Number = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Graphic{ get{ return m_Graphic; } set{ m_Graphic = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RequireExceptional{ get{ return m_RequireExceptional; } set{ m_RequireExceptional = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public BulkMaterialType Material{ get{ return m_Material; } set{ m_Material = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Complete{ get{ return ( m_AmountCur == m_AmountMax ); } } + + public override int LabelNumber{ get{ return 1045151; } } // a bulk order deed + + [Constructable] + public SmallBOD( int hue, int amountMax, Type type, int number, int graphic, bool requireExeptional, BulkMaterialType material ) : base( Core.AOS ? 0x2258 : 0x14EF ) + { + Weight = 1.0; + Hue = hue; // Blacksmith: 0x44E; Tailoring: 0x483 + LootType = LootType.Blessed; + + m_AmountMax = amountMax; + m_Type = type; + m_Number = number; + m_Graphic = graphic; + m_RequireExceptional = requireExeptional; + m_Material = material; + } + + public SmallBOD() : base( Core.AOS ? 0x2258 : 0x14EF ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public static BulkMaterialType GetRandomMaterial( BulkMaterialType start, double[] chances ) + { + double random = Utility.RandomDouble(); + + for ( int i = 0; i < chances.Length; ++i ) + { + if ( random < chances[i] ) + return ( i == 0 ? BulkMaterialType.None : start + (i - 1) ); + + random -= chances[i]; + } + + return BulkMaterialType.None; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060654 ); // small bulk order + + if ( m_RequireExceptional ) + list.Add( 1045141 ); // All items must be exceptional. + + if ( m_Material != BulkMaterialType.None ) + list.Add( SmallBODGump.GetMaterialNumberFor( m_Material ) ); // All items must be made with x material. + + list.Add( 1060656, m_AmountMax.ToString() ); // amount to make: ~1_val~ + list.Add( 1060658, "#{0}\t{1}", m_Number, m_AmountCur ); // ~1_val~: ~2_val~ + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack) || InSecureTrade || RootParent is PlayerVendor) + from.SendGump(new SmallBODGump(from, this)); + else + from.SendLocalizedMessage(1045156); // You must have the deed in your backpack to use it. + } + + public override void OnDoubleClickNotAccessible(Mobile from) + { + OnDoubleClick(from); + } + + public override void OnDoubleClickSecureTrade(Mobile from) + { + OnDoubleClick(from); + } + + public void BeginCombine( Mobile from ) + { + if ( m_AmountCur < m_AmountMax ) + from.Target = new SmallBODTarget( this ); + else + from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed. + } + + public abstract List ComputeRewards( bool full ); + public abstract int ComputeGold(); + public abstract int ComputeFame(); + + public virtual void GetRewards( out Item reward, out int gold, out int fame ) + { + reward = null; + gold = ComputeGold(); + fame = ComputeFame(); + + List rewards = ComputeRewards( false ); + + if ( rewards.Count > 0 ) + { + reward = rewards[Utility.Random( rewards.Count )]; + + for ( int i = 0; i < rewards.Count; ++i ) + { + if ( rewards[i] != reward ) + rewards[i].Delete(); + } + } + } + + public static BulkMaterialType GetMaterial( CraftResource resource ) + { + switch ( resource ) + { + case CraftResource.MDullcopper: return BulkMaterialType.DullCopper; + case CraftResource.MShadow: return BulkMaterialType.ShadowIron; + case CraftResource.MCopper: return BulkMaterialType.Copper; + case CraftResource.MBronze: return BulkMaterialType.Bronze; + case CraftResource.MGold: return BulkMaterialType.Gold; + case CraftResource.MAgapite: return BulkMaterialType.Agapite; + case CraftResource.MVerite: return BulkMaterialType.Verite; + case CraftResource.MValorite: return BulkMaterialType.Valorite; + case CraftResource.SpinedLeather: return BulkMaterialType.Spined; + case CraftResource.HornedLeather: return BulkMaterialType.Horned; + case CraftResource.BarbedLeather: return BulkMaterialType.Barbed; + } + + return BulkMaterialType.None; + } + + public void EndCombine( Mobile from, object o ) + { + if ( o is Item && ((Item)o).IsChildOf( from.Backpack ) ) + { + Type objectType = o.GetType(); + + if ( m_AmountCur >= m_AmountMax ) + { + from.SendLocalizedMessage( 1045166 ); // The maximum amount of requested items have already been combined to this deed. + } + else if ( m_Type == null || (objectType != m_Type && !objectType.IsSubclassOf( m_Type )) || (!(o is BaseWeapon) && !(o is BaseArmor) && !(o is BaseClothing)) ) + { + from.SendLocalizedMessage( 1045169 ); // The item is not in the request. + } + else + { + BulkMaterialType material = BulkMaterialType.None; + + if ( o is BaseArmor ) + material = GetMaterial( ((BaseArmor)o).Resource ); + else if ( o is BaseClothing ) + material = GetMaterial( ((BaseClothing)o).Resource ); + + if ( m_Material >= BulkMaterialType.DullCopper && m_Material <= BulkMaterialType.Valorite && material != m_Material ) + { + from.SendLocalizedMessage( 1045168 ); // The item is not made from the requested ore. + } + else if ( m_Material >= BulkMaterialType.Spined && m_Material <= BulkMaterialType.Barbed && material != m_Material ) + { + from.SendLocalizedMessage( 1049352 ); // The item is not made from the requested leather type. + } + else + { + bool isExceptional = false; + + if ( o is BaseWeapon ) + isExceptional = ( ((BaseWeapon)o).Quality == WeaponQuality.Exceptional ); + else if ( o is BaseArmor ) + isExceptional = ( ((BaseArmor)o).Quality == ArmorQuality.Exceptional ); + else if ( o is BaseClothing ) + isExceptional = ( ((BaseClothing)o).Quality == ClothingQuality.Exceptional ); + + if ( m_RequireExceptional && !isExceptional ) + { + from.SendLocalizedMessage( 1045167 ); // The item must be exceptional. + } + else + { + ((Item)o).Delete(); + ++AmountCur; + + from.SendLocalizedMessage( 1045170 ); // The item has been combined with the deed. + + from.SendGump( new SmallBODGump( from, this ) ); + + if ( m_AmountCur < m_AmountMax ) + BeginCombine( from ); + } + } + } + } + else + { + from.SendLocalizedMessage( 1045158 ); // You must have the item in your backpack to target it. + } + } + + public SmallBOD( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_AmountCur ); + writer.Write( m_AmountMax ); + writer.Write( m_Type == null ? null : m_Type.FullName ); + writer.Write( m_Number ); + writer.Write( m_Graphic ); + writer.Write( m_RequireExceptional ); + writer.Write( (int) m_Material ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_AmountCur = reader.ReadInt(); + m_AmountMax = reader.ReadInt(); + + string type = reader.ReadString(); + + if ( type != null ) + m_Type = ScriptCompiler.FindTypeByFullName( type ); + + m_Number = reader.ReadInt(); + m_Graphic = reader.ReadInt(); + m_RequireExceptional = reader.ReadBool(); + m_Material = (BulkMaterialType)reader.ReadInt(); + + break; + } + } + + if ( Weight == 0.0 ) + Weight = 1.0; + + if ( Core.AOS && ItemID == 0x14EF ) + ItemID = 0x2258; + + if ( Parent == null && Map == Map.Internal && Location == Point3D.Zero ) + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallBODAcceptGump.cs b/Scripts/Engines/BulkOrders/SmallBODAcceptGump.cs new file mode 100644 index 0000000..7f6e55e --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallBODAcceptGump.cs @@ -0,0 +1,93 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.BulkOrders +{ + public class SmallBODAcceptGump : Gump + { + private SmallBOD m_Deed; + private Mobile m_From; + + public SmallBODAcceptGump( Mobile from, SmallBOD deed ) : base( 50, 50 ) + { + m_From = from; + m_Deed = deed; + + m_From.CloseGump( typeof( LargeBODAcceptGump ) ); + m_From.CloseGump( typeof( SmallBODAcceptGump ) ); + + AddPage( 0 ); + + AddBackground( 25, 10, 430, 264, 5054 ); + + AddImageTiled( 33, 20, 413, 245, 2624 ); + AddAlphaRegion( 33, 20, 413, 245 ); + + AddImage( 20, 5, 10460 ); + AddImage( 430, 5, 10460 ); + AddImage( 20, 249, 10460 ); + AddImage( 430, 249, 10460 ); + + AddHtmlLocalized( 190, 25, 120, 20, 1045133, 0x7FFF, false, false ); // A bulk order + AddHtmlLocalized( 40, 48, 350, 20, 1045135, 0x7FFF, false, false ); // Ah! Thanks for the goods! Would you help me out? + + AddHtmlLocalized( 40, 72, 210, 20, 1045138, 0x7FFF, false, false ); // Amount to make: + AddLabel( 250, 72, 1152, deed.AmountMax.ToString() ); + + AddHtmlLocalized( 40, 96, 120, 20, 1045136, 0x7FFF, false, false ); // Item requested: + AddItem( 385, 96, deed.Graphic ); + AddHtmlLocalized( 40, 120, 210, 20, deed.Number, 0xFFFFFF, false, false ); + + if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None ) + { + AddHtmlLocalized( 40, 144, 210, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet: + + if ( deed.RequireExceptional ) + AddHtmlLocalized( 40, 168, 350, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional. + + if ( deed.Material != BulkMaterialType.None ) + AddHtmlLocalized( 40, deed.RequireExceptional ? 192 : 168, 350, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material. + } + + AddHtmlLocalized( 40, 216, 350, 20, 1045139, 0x7FFF, false, false ); // Do you want to accept this order? + + AddButton( 100, 240, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 135, 240, 120, 20, 1006044, 0x7FFF, false, false ); // Ok + + AddButton( 275, 240, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 310, 240, 120, 20, 1011012, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) // Ok + { + if ( m_From.PlaceInBackpack( m_Deed ) ) + { + m_From.SendLocalizedMessage( 1045152 ); // The bulk order deed has been placed in your backpack. + } + else + { + m_From.SendLocalizedMessage( 1045150 ); // There is not enough room in your backpack for the deed. + m_Deed.Delete(); + } + } + else + { + m_Deed.Delete(); + } + } + + public static int GetMaterialNumberFor( BulkMaterialType material ) + { + if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) + return 1045142 + (int)(material - BulkMaterialType.DullCopper); + else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed ) + return 1049348 + (int)(material - BulkMaterialType.Spined); + + return 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallBODGump.cs b/Scripts/Engines/BulkOrders/SmallBODGump.cs new file mode 100644 index 0000000..034469b --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallBODGump.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.BulkOrders +{ + public class SmallBODGump : Gump + { + private SmallBOD m_Deed; + private Mobile m_From; + + public SmallBODGump( Mobile from, SmallBOD deed ) : base( 25, 25 ) + { + m_From = from; + m_Deed = deed; + + m_From.CloseGump( typeof( LargeBODGump ) ); + m_From.CloseGump( typeof( SmallBODGump ) ); + + AddPage( 0 ); + + AddBackground( 50, 10, 455, 260, 5054 ); + AddImageTiled( 58, 20, 438, 241, 2624 ); + AddAlphaRegion( 58, 20, 438, 241 ); + + AddImage( 45, 5, 10460 ); + AddImage( 480, 5, 10460 ); + AddImage( 45, 245, 10460 ); + AddImage( 480, 245, 10460 ); + + AddHtmlLocalized( 225, 25, 120, 20, 1045133, 0x7FFF, false, false ); // A bulk order + + AddHtmlLocalized( 75, 48, 250, 20, 1045138, 0x7FFF, false, false ); // Amount to make: + AddLabel( 275, 48, 1152, deed.AmountMax.ToString() ); + + AddHtmlLocalized( 275, 76, 200, 20, 1045153, 0x7FFF, false, false ); // Amount finished: + AddHtmlLocalized( 75, 72, 120, 20, 1045136, 0x7FFF, false, false ); // Item requested: + + AddItem( 410, 72, deed.Graphic ); + + AddHtmlLocalized( 75, 96, 210, 20, deed.Number, 0x7FFF, false, false ); + AddLabel( 275, 96, 0x480, deed.AmountCur.ToString() ); + + if ( deed.RequireExceptional || deed.Material != BulkMaterialType.None ) + AddHtmlLocalized( 75, 120, 200, 20, 1045140, 0x7FFF, false, false ); // Special requirements to meet: + + if ( deed.RequireExceptional ) + AddHtmlLocalized( 75, 144, 300, 20, 1045141, 0x7FFF, false, false ); // All items must be exceptional. + + if ( deed.Material != BulkMaterialType.None ) + AddHtmlLocalized( 75, deed.RequireExceptional ? 168 : 144, 300, 20, GetMaterialNumberFor( deed.Material ), 0x7FFF, false, false ); // All items must be made with x material. + + AddButton( 125, 192, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 160, 192, 300, 20, 1045154, 0x7FFF, false, false ); // Combine this deed with the item requested. + + AddButton( 125, 216, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 160, 216, 120, 20, 1011441, 0x7FFF, false, false ); // EXIT + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed.Deleted || !m_Deed.IsChildOf( m_From.Backpack ) ) + return; + + if ( info.ButtonID == 2 ) // Combine + { + m_From.SendGump( new SmallBODGump( m_From, m_Deed ) ); + m_Deed.BeginCombine( m_From ); + } + } + + public static int GetMaterialNumberFor( BulkMaterialType material ) + { + if ( material >= BulkMaterialType.DullCopper && material <= BulkMaterialType.Valorite ) + return 1045142 + (int)(material - BulkMaterialType.DullCopper); + else if ( material >= BulkMaterialType.Spined && material <= BulkMaterialType.Barbed ) + return 1049348 + (int)(material - BulkMaterialType.Spined); + + return 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallBODTarget.cs b/Scripts/Engines/BulkOrders/SmallBODTarget.cs new file mode 100644 index 0000000..94f1220 --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallBODTarget.cs @@ -0,0 +1,25 @@ +using System; +using Server; +using Server.Targeting; +using Server.Network; + +namespace Server.Engines.BulkOrders +{ + public class SmallBODTarget : Target + { + private SmallBOD m_Deed; + + public SmallBODTarget( SmallBOD deed ) : base( 18, false, TargetFlags.None ) + { + m_Deed = deed; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Deed.Deleted || !m_Deed.IsChildOf( from.Backpack ) ) + return; + + m_Deed.EndCombine( from, targeted ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallBulkEntry.cs b/Scripts/Engines/BulkOrders/SmallBulkEntry.cs new file mode 100644 index 0000000..8c4cf01 --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallBulkEntry.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server; + +namespace Server.Engines.BulkOrders +{ + public class SmallBulkEntry + { + private Type m_Type; + private int m_Number; + private int m_Graphic; + + public Type Type{ get{ return m_Type; } } + public int Number{ get{ return m_Number; } } + public int Graphic{ get{ return m_Graphic; } } + + public SmallBulkEntry( Type type, int number, int graphic ) + { + m_Type = type; + m_Number = number; + m_Graphic = graphic; + } + + public static SmallBulkEntry[] BlacksmithWeapons + { + get{ return GetEntries( "Blacksmith", "weapons" ); } + } + + public static SmallBulkEntry[] BlacksmithArmor + { + get{ return GetEntries( "Blacksmith", "armor" ); } + } + + public static SmallBulkEntry[] TailorCloth + { + get{ return GetEntries( "Tailoring", "cloth" ); } + } + + public static SmallBulkEntry[] TailorLeather + { + get{ return GetEntries( "Tailoring", "leather" ); } + } + + private static Hashtable m_Cache; + + public static SmallBulkEntry[] GetEntries( string type, string name ) + { + if ( m_Cache == null ) + m_Cache = new Hashtable(); + + Hashtable table = (Hashtable)m_Cache[type]; + + if ( table == null ) + m_Cache[type] = table = new Hashtable(); + + SmallBulkEntry[] entries = (SmallBulkEntry[])table[name]; + + if ( entries == null ) + table[name] = entries = LoadEntries( type, name ); + + return entries; + } + + public static SmallBulkEntry[] LoadEntries( string type, string name ) + { + return LoadEntries( String.Format( "Data/Bulk Orders/{0}/{1}.cfg", type, name ) ); + } + + public static SmallBulkEntry[] LoadEntries( string path ) + { + path = Path.Combine( Core.BaseDirectory, path ); + + List list = new List(); + + if ( File.Exists( path ) ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + if ( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + try + { + string[] split = line.Split( '\t' ); + + if ( split.Length >= 2 ) + { + Type type = ScriptCompiler.FindTypeByName( split[0] ); + int graphic = Utility.ToInt32( split[split.Length - 1] ); + + if ( type != null && graphic > 0 ) + list.Add( new SmallBulkEntry( type, graphic < 0x4000 ? 1020000 + graphic : 1078872 + graphic, graphic ) ); + } + } + catch + { + } + } + } + } + + return list.ToArray(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallSmithBOD.cs b/Scripts/Engines/BulkOrders/SmallSmithBOD.cs new file mode 100644 index 0000000..50e30b0 --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallSmithBOD.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.Craft; +using Server.Items; +using Mat = Server.Engines.BulkOrders.BulkMaterialType; + +namespace Server.Engines.BulkOrders +{ + [TypeAlias( "Scripts.Engines.BulkOrders.SmallSmithBOD" )] + public class SmallSmithBOD : SmallBOD + { + public static double[] m_BlacksmithMaterialChances = new double[] + { + 0.501953125, // None + 0.250000000, // Dull Copper + 0.125000000, // Shadow Iron + 0.062500000, // Copper + 0.031250000, // Bronze + 0.015625000, // Gold + 0.007812500, // Agapite + 0.003906250, // Verite + 0.001953125 // Valorite + }; + + public override int ComputeFame() + { + return SmithRewardCalculator.Instance.ComputeFame( this ); + } + + public override int ComputeGold() + { + return SmithRewardCalculator.Instance.ComputeGold( this ); + } + + public override List ComputeRewards( bool full ) + { + List list = new List(); + + RewardGroup rewardGroup = SmithRewardCalculator.Instance.LookupRewards( SmithRewardCalculator.Instance.ComputePoints( this ) ); + + if ( rewardGroup != null ) + { + if ( full ) + { + for ( int i = 0; i < rewardGroup.Items.Length; ++i ) + { + Item item = rewardGroup.Items[i].Construct(); + + if ( item != null ) + list.Add( item ); + } + } + else + { + RewardItem rewardItem = rewardGroup.AcquireItem(); + + if ( rewardItem != null ) + { + Item item = rewardItem.Construct(); + + if ( item != null ) + list.Add( item ); + } + } + } + + return list; + } + + public static SmallSmithBOD CreateRandomFor( Mobile m ) + { + SmallBulkEntry[] entries; + bool useMaterials; + + if ( useMaterials = Utility.RandomBool() ) + entries = SmallBulkEntry.BlacksmithArmor; + else + entries = SmallBulkEntry.BlacksmithWeapons; + + if ( entries.Length > 0 ) + { + double theirSkill = m.Skills[SkillName.Blacksmith].Base; + int amountMax; + + if ( theirSkill >= 70.1 ) + amountMax = Utility.RandomList( 10, 15, 20, 20 ); + else if ( theirSkill >= 50.1 ) + amountMax = Utility.RandomList( 10, 15, 15, 20 ); + else + amountMax = Utility.RandomList( 10, 10, 15, 20 ); + + BulkMaterialType material = BulkMaterialType.None; + + if ( useMaterials && theirSkill >= 70.1 ) + { + for ( int i = 0; i < 20; ++i ) + { + BulkMaterialType check = GetRandomMaterial( BulkMaterialType.DullCopper, m_BlacksmithMaterialChances ); + double skillReq = 0.0; + + switch ( check ) + { + case BulkMaterialType.DullCopper: skillReq = 65.0; break; + case BulkMaterialType.ShadowIron: skillReq = 70.0; break; + case BulkMaterialType.Copper: skillReq = 75.0; break; + case BulkMaterialType.Bronze: skillReq = 80.0; break; + case BulkMaterialType.Gold: skillReq = 85.0; break; + case BulkMaterialType.Agapite: skillReq = 90.0; break; + case BulkMaterialType.Verite: skillReq = 95.0; break; + case BulkMaterialType.Valorite: skillReq = 100.0; break; + case BulkMaterialType.Spined: skillReq = 65.0; break; + case BulkMaterialType.Horned: skillReq = 80.0; break; + case BulkMaterialType.Barbed: skillReq = 99.0; break; + } + + if ( theirSkill >= skillReq ) + { + material = check; + break; + } + } + } + + double excChance = 0.0; + + if ( theirSkill >= 70.1 ) + excChance = (theirSkill + 80.0) / 200.0; + + bool reqExceptional = ( excChance > Utility.RandomDouble() ); + + CraftSystem system = DefBlacksmithy.CraftSystem; + + List validEntries = new List(); + + for ( int i = 0; i < entries.Length; ++i ) + { + CraftItem item = system.CraftItems.SearchFor( entries[i].Type ); + + if ( item != null ) + { + bool allRequiredSkills = true; + double chance = item.GetSuccessChance( m, null, system, false, ref allRequiredSkills ); + + if ( allRequiredSkills && chance >= 0.0 ) + { + if ( reqExceptional ) + chance = item.GetExceptionalChance( system, chance, m ); + + if ( chance > 0.0 ) + validEntries.Add( entries[i] ); + } + } + } + + if ( validEntries.Count > 0 ) + { + SmallBulkEntry entry = validEntries[Utility.Random( validEntries.Count )]; + return new SmallSmithBOD( entry, material, amountMax, reqExceptional ); + } + } + + return null; + } + + private SmallSmithBOD( SmallBulkEntry entry, BulkMaterialType material, int amountMax, bool reqExceptional ) + { + this.Hue = 0x44E; + this.AmountMax = amountMax; + this.Type = entry.Type; + this.Number = entry.Number; + this.Graphic = entry.Graphic; + this.RequireExceptional = reqExceptional; + this.Material = material; + } + + [Constructable] + public SmallSmithBOD() + { + SmallBulkEntry[] entries; + bool useMaterials; + + if ( useMaterials = Utility.RandomBool() ) + entries = SmallBulkEntry.BlacksmithArmor; + else + entries = SmallBulkEntry.BlacksmithWeapons; + + if ( entries.Length > 0 ) + { + int hue = 0x44E; + int amountMax = Utility.RandomList( 10, 15, 20 ); + + BulkMaterialType material; + + if ( useMaterials ) + material = GetRandomMaterial( BulkMaterialType.DullCopper, m_BlacksmithMaterialChances ); + else + material = BulkMaterialType.None; + + bool reqExceptional = Utility.RandomBool() || (material == BulkMaterialType.None); + + SmallBulkEntry entry = entries[Utility.Random( entries.Length )]; + + this.Hue = hue; + this.AmountMax = amountMax; + this.Type = entry.Type; + this.Number = entry.Number; + this.Graphic = entry.Graphic; + this.RequireExceptional = reqExceptional; + this.Material = material; + } + } + + public SmallSmithBOD( int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional, BulkMaterialType mat ) + { + this.Hue = 0x44E; + this.AmountMax = amountMax; + this.AmountCur = amountCur; + this.Type = type; + this.Number = number; + this.Graphic = graphic; + this.RequireExceptional = reqExceptional; + this.Material = mat; + } + + public SmallSmithBOD( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/BulkOrders/SmallTailorBOD.cs b/Scripts/Engines/BulkOrders/SmallTailorBOD.cs new file mode 100644 index 0000000..9286272 --- /dev/null +++ b/Scripts/Engines/BulkOrders/SmallTailorBOD.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.Craft; +using Server.Items; + +namespace Server.Engines.BulkOrders +{ + public class SmallTailorBOD : SmallBOD + { + public static double[] m_TailoringMaterialChances = new double[] + { + 0.857421875, // None + 0.125000000, // Spined + 0.015625000, // Horned + 0.001953125 // Barbed + }; + + public override int ComputeFame() + { + return TailorRewardCalculator.Instance.ComputeFame( this ); + } + + public override int ComputeGold() + { + return TailorRewardCalculator.Instance.ComputeGold( this ); + } + + public override List ComputeRewards( bool full ) + { + List list = new List(); + + RewardGroup rewardGroup = TailorRewardCalculator.Instance.LookupRewards( TailorRewardCalculator.Instance.ComputePoints( this ) ); + + if ( rewardGroup != null ) + { + if ( full ) + { + for ( int i = 0; i < rewardGroup.Items.Length; ++i ) + { + Item item = rewardGroup.Items[i].Construct(); + + if ( item != null ) + list.Add( item ); + } + } + else + { + RewardItem rewardItem = rewardGroup.AcquireItem(); + + if ( rewardItem != null ) + { + Item item = rewardItem.Construct(); + + if ( item != null ) + list.Add( item ); + } + } + } + + return list; + } + + public static SmallTailorBOD CreateRandomFor( Mobile m ) + { + SmallBulkEntry[] entries; + bool useMaterials; + + double theirSkill = m.Skills[SkillName.Tailoring].Base; + if ( useMaterials = Utility.RandomBool() && theirSkill >= 6.2 ) // Ugly, but the easiest leather BOD is Leather Cap which requires at least 6.2 skill. + entries = SmallBulkEntry.TailorLeather; + else + entries = SmallBulkEntry.TailorCloth; + + if ( entries.Length > 0 ) + { + int amountMax; + + if ( theirSkill >= 70.1 ) + amountMax = Utility.RandomList( 10, 15, 20, 20 ); + else if ( theirSkill >= 50.1 ) + amountMax = Utility.RandomList( 10, 15, 15, 20 ); + else + amountMax = Utility.RandomList( 10, 10, 15, 20 ); + + BulkMaterialType material = BulkMaterialType.None; + + if ( useMaterials && theirSkill >= 70.1 ) + { + for ( int i = 0; i < 20; ++i ) + { + BulkMaterialType check = GetRandomMaterial( BulkMaterialType.Spined, m_TailoringMaterialChances ); + double skillReq = 0.0; + + switch ( check ) + { + case BulkMaterialType.DullCopper: skillReq = 65.0; break; + case BulkMaterialType.Bronze: skillReq = 80.0; break; + case BulkMaterialType.Gold: skillReq = 85.0; break; + case BulkMaterialType.Agapite: skillReq = 90.0; break; + case BulkMaterialType.Verite: skillReq = 95.0; break; + case BulkMaterialType.Valorite: skillReq = 100.0; break; + case BulkMaterialType.Spined: skillReq = 65.0; break; + case BulkMaterialType.Horned: skillReq = 80.0; break; + case BulkMaterialType.Barbed: skillReq = 99.0; break; + } + + if ( theirSkill >= skillReq ) + { + material = check; + break; + } + } + } + + double excChance = 0.0; + + if ( theirSkill >= 70.1 ) + excChance = (theirSkill + 80.0) / 200.0; + + bool reqExceptional = ( excChance > Utility.RandomDouble() ); + + + CraftSystem system = DefTailoring.CraftSystem; + + List validEntries = new List(); + + for ( int i = 0; i < entries.Length; ++i ) + { + CraftItem item = system.CraftItems.SearchFor( entries[i].Type ); + + if ( item != null ) + { + bool allRequiredSkills = true; + double chance = item.GetSuccessChance( m, null, system, false, ref allRequiredSkills ); + + if ( allRequiredSkills && chance >= 0.0 ) + { + if ( reqExceptional ) + chance = item.GetExceptionalChance( system, chance, m ); + + if ( chance > 0.0 ) + validEntries.Add( entries[i] ); + } + } + } + + if ( validEntries.Count > 0 ) + { + SmallBulkEntry entry = validEntries[Utility.Random( validEntries.Count )]; + return new SmallTailorBOD( entry, material, amountMax, reqExceptional ); + } + } + + return null; + } + + private SmallTailorBOD( SmallBulkEntry entry, BulkMaterialType material, int amountMax, bool reqExceptional ) + { + this.Hue = 0x483; + this.AmountMax = amountMax; + this.Type = entry.Type; + this.Number = entry.Number; + this.Graphic = entry.Graphic; + this.RequireExceptional = reqExceptional; + this.Material = material; + } + + [Constructable] + public SmallTailorBOD() + { + SmallBulkEntry[] entries; + bool useMaterials; + + if ( useMaterials = Utility.RandomBool() ) + entries = SmallBulkEntry.TailorLeather; + else + entries = SmallBulkEntry.TailorCloth; + + if ( entries.Length > 0 ) + { + int hue = 0x483; + int amountMax = Utility.RandomList( 10, 15, 20 ); + + BulkMaterialType material; + + if ( useMaterials ) + material = GetRandomMaterial( BulkMaterialType.Spined, m_TailoringMaterialChances ); + else + material = BulkMaterialType.None; + + bool reqExceptional = Utility.RandomBool() || (material == BulkMaterialType.None); + + SmallBulkEntry entry = entries[Utility.Random( entries.Length )]; + + this.Hue = hue; + this.AmountMax = amountMax; + this.Type = entry.Type; + this.Number = entry.Number; + this.Graphic = entry.Graphic; + this.RequireExceptional = reqExceptional; + this.Material = material; + } + } + + public SmallTailorBOD( int amountCur, int amountMax, Type type, int number, int graphic, bool reqExceptional, BulkMaterialType mat ) + { + this.Hue = 0x483; + this.AmountMax = amountMax; + this.AmountCur = amountCur; + this.Type = type; + this.Number = number; + this.Graphic = graphic; + this.RequireExceptional = reqExceptional; + this.Material = mat; + } + + public SmallTailorBOD( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionAltar.cs b/Scripts/Engines/CannedEvil/ChampionAltar.cs new file mode 100644 index 0000000..431231d --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionAltar.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Engines.CannedEvil +{ + public class ChampionAltar : PentagramAddon + { + private ChampionSpawn m_Spawn; + + public ChampionAltar( ChampionSpawn spawn ) + { + m_Spawn = spawn; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Spawn != null ) + m_Spawn.Delete(); + } + + public ChampionAltar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Spawn ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Spawn = reader.ReadItem() as ChampionSpawn; + + if ( m_Spawn == null ) + Delete(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionPlatform.cs b/Scripts/Engines/CannedEvil/ChampionPlatform.cs new file mode 100644 index 0000000..e04bab9 --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionPlatform.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Engines.CannedEvil +{ + public class ChampionPlatform : BaseAddon + { + private ChampionSpawn m_Spawn; + + public ChampionPlatform(ChampionSpawn spawn) + { + m_Spawn = spawn; + + for (int x = -2; x <= 2; ++x) + for (int y = -2; y <= 2; ++y) + AddComponent(0x750, x, y, -5); + + for (int x = -1; x <= 1; ++x) + for (int y = -1; y <= 1; ++y) + AddComponent(0x750, x, y, 0); + + for (int i = -1; i <= 1; ++i) + { + AddComponent(0x751, i, 2, 0); + AddComponent(0x752, 2, i, 0); + + AddComponent(0x753, i, -2, 0); + AddComponent(0x754, -2, i, 0); + } + + AddComponent(0x759, -2, -2, 0); + AddComponent(0x75A, 2, 2, 0); + AddComponent(0x75B, -2, 2, 0); + AddComponent(0x75C, 2, -2, 0); + } + + public void AddComponent(int id, int x, int y, int z) + { + AddonComponent ac = new AddonComponent(id); + + ac.Hue = 0x497; + + AddComponent(ac, x, y, z); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Spawn != null) + m_Spawn.Delete(); + } + + public ChampionPlatform(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Spawn); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Spawn = reader.ReadItem() as ChampionSpawn; + + if (m_Spawn == null) + Delete(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionSkull.cs b/Scripts/Engines/CannedEvil/ChampionSkull.cs new file mode 100644 index 0000000..0e6a653 --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionSkull.cs @@ -0,0 +1,73 @@ +using System; +using Server; +using Server.Engines.CannedEvil; + +namespace Server.Items +{ + public class ChampionSkull : Item + { + private ChampionSkullType m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public ChampionSkullType Type{ get{ return m_Type; } set{ m_Type = value; InvalidateProperties(); } } + + public override int LabelNumber{ get{ return 1049479 + (int)m_Type; } } + + [Constructable] + public ChampionSkull( ChampionSkullType type ) : base( 0x1AE1 ) + { + m_Type = type; + LootType = LootType.Cursed; + + // TODO: All hue values + switch ( type ) + { + case ChampionSkullType.Power: Hue = 0x159; break; + case ChampionSkullType.Venom: Hue = 0x172; break; + case ChampionSkullType.Greed: Hue = 0x1EE; break; + case ChampionSkullType.Death: Hue = 0x025; break; + case ChampionSkullType.Pain: Hue = 0x035; break; + } + } + + public ChampionSkull( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Type = (ChampionSkullType)reader.ReadInt(); + + break; + } + } + + if( version == 0 ) + { + if ( LootType != LootType.Cursed ) + LootType = LootType.Cursed; + + if ( Insured ) + Insured = false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs b/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs new file mode 100644 index 0000000..153e7c4 --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionSkullBrazier.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Engines.CannedEvil +{ + public class ChampionSkullBrazier : AddonComponent + { + private ChampionSkullPlatform m_Platform; + private ChampionSkullType m_Type; + private Item m_Skull; + + [CommandProperty( AccessLevel.GameMaster )] + public ChampionSkullPlatform Platform{ get{ return m_Platform; } } + + [CommandProperty( AccessLevel.GameMaster )] + public ChampionSkullType Type{ get{ return m_Type; } set{ m_Type = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Skull{ get{ return m_Skull; } set{ m_Skull = value; if ( m_Platform != null ) m_Platform.Validate(); } } + + public override int LabelNumber{ get{ return 1049489 + (int)m_Type; } } + + public ChampionSkullBrazier( ChampionSkullPlatform platform, ChampionSkullType type ) : base( 0x19BB ) + { + Hue = 0x455; + Light = LightType.Circle300; + + m_Platform = platform; + m_Type = type; + } + + public ChampionSkullBrazier( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Platform != null ) + m_Platform.Validate(); + + BeginSacrifice( from ); + } + + public void BeginSacrifice( Mobile from ) + { + if ( Deleted ) + return; + + if ( m_Skull != null && m_Skull.Deleted ) + Skull = null; + + if ( from.Map != this.Map || !from.InRange( GetWorldLocation(), 3 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( !Harrower.CanSpawn ) + { + from.SendMessage( "The harrower has already been spawned." ); + } + else if ( m_Skull == null ) + { + from.SendLocalizedMessage( 1049485 ); // What would you like to sacrifice? + from.Target = new SacrificeTarget( this ); + } + else + { + SendLocalizedMessageTo( from, 1049487, "" ); // I already have my champions awakening skull! + } + } + + public void EndSacrifice( Mobile from, ChampionSkull skull ) + { + if ( Deleted ) + return; + + if ( m_Skull != null && m_Skull.Deleted ) + Skull = null; + + if ( from.Map != this.Map || !from.InRange( GetWorldLocation(), 3 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( !Harrower.CanSpawn ) + { + from.SendMessage( "The harrower has already been spawned." ); + } + else if ( skull == null ) + { + SendLocalizedMessageTo( from, 1049488, "" ); // That is not my champions awakening skull! + } + else if ( m_Skull != null ) + { + SendLocalizedMessageTo( from, 1049487, "" ); // I already have my champions awakening skull! + } + else if ( !skull.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1049486 ); // You can only sacrifice items that are in your backpack! + } + else + { + if ( skull.Type == this.Type ) + { + skull.Movable = false; + skull.MoveToWorld( GetWorldTop(), this.Map ); + + this.Skull = skull; + } + else + { + SendLocalizedMessageTo( from, 1049488, "" ); // That is not my champions awakening skull! + } + } + } + + private class SacrificeTarget : Target + { + private ChampionSkullBrazier m_Brazier; + + public SacrificeTarget( ChampionSkullBrazier brazier ) : base( 12, false, TargetFlags.None ) + { + m_Brazier = brazier; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + m_Brazier.EndSacrifice( from, targeted as ChampionSkull ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Type ); + writer.Write( m_Platform ); + writer.Write( m_Skull ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (ChampionSkullType)reader.ReadInt(); + m_Platform = reader.ReadItem() as ChampionSkullPlatform; + m_Skull = reader.ReadItem(); + + if ( m_Platform == null ) + Delete(); + + break; + } + } + + if ( Hue == 0x497 ) + Hue = 0x455; + + if ( Light != LightType.Circle300 ) + Light = LightType.Circle300; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionSkullPlatform.cs b/Scripts/Engines/CannedEvil/ChampionSkullPlatform.cs new file mode 100644 index 0000000..37e5b21 --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionSkullPlatform.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.CannedEvil +{ + public class ChampionSkullPlatform : BaseAddon + { + private ChampionSkullBrazier m_Power, m_Enlightenment, m_Venom, m_Pain, m_Greed, m_Death; + + [Constructable] + public ChampionSkullPlatform() + { + AddComponent( new AddonComponent( 0x71A ), -1, -1, -1 ); + AddComponent( new AddonComponent( 0x709 ), 0, -1, -1 ); + AddComponent( new AddonComponent( 0x709 ), 1, -1, -1 ); + AddComponent( new AddonComponent( 0x709 ), -1, 0, -1 ); + AddComponent( new AddonComponent( 0x709 ), 0, 0, -1 ); + AddComponent( new AddonComponent( 0x709 ), 1, 0, -1 ); + AddComponent( new AddonComponent( 0x709 ), -1, 1, -1 ); + AddComponent( new AddonComponent( 0x709 ), 0, 1, -1 ); + AddComponent( new AddonComponent( 0x71B ), 1, 1, -1 ); + + AddComponent( new AddonComponent( 0x50F ), 0, -1, 4 ); + AddComponent( m_Power = new ChampionSkullBrazier( this, ChampionSkullType.Power ), 0, -1, 5 ); + + AddComponent( new AddonComponent( 0x50F ), 1, -1, 4 ); + AddComponent( m_Enlightenment = new ChampionSkullBrazier( this, ChampionSkullType.Enlightenment ), 1, -1, 5 ); + + AddComponent( new AddonComponent( 0x50F ), -1, 0, 4 ); + AddComponent( m_Venom = new ChampionSkullBrazier( this, ChampionSkullType.Venom ), -1, 0, 5 ); + + AddComponent( new AddonComponent( 0x50F ), 1, 0, 4 ); + AddComponent( m_Pain = new ChampionSkullBrazier( this, ChampionSkullType.Pain ), 1, 0, 5 ); + + AddComponent( new AddonComponent( 0x50F ), -1, 1, 4 ); + AddComponent( m_Greed = new ChampionSkullBrazier( this, ChampionSkullType.Greed ), -1, 1, 5 ); + + AddComponent( new AddonComponent( 0x50F ), 0, 1, 4 ); + AddComponent( m_Death = new ChampionSkullBrazier( this, ChampionSkullType.Death ), 0, 1, 5 ); + + AddonComponent comp = new LocalizedAddonComponent( 0x20D2, 1049495 ); + comp.Hue = 0x482; + AddComponent( comp, 0, 0, 5 ); + + comp = new LocalizedAddonComponent( 0x0BCF, 1049496 ); + comp.Hue = 0x482; + AddComponent( comp, 0, 2, -7 ); + + comp = new LocalizedAddonComponent( 0x0BD0, 1049497 ); + comp.Hue = 0x482; + AddComponent( comp, 2, 0, -7 ); + } + + public void Validate() + { + if ( Validate( m_Power ) && Validate( m_Enlightenment ) && Validate( m_Venom ) && Validate( m_Pain ) && Validate( m_Greed ) && Validate( m_Death ) ) + { + Mobile harrower = Harrower.Spawn( new Point3D( X, Y, Z + 6 ), this.Map ); + + if ( harrower == null ) + return; + + Clear( m_Power ); + Clear( m_Enlightenment ); + Clear( m_Venom ); + Clear( m_Pain ); + Clear( m_Greed ); + Clear( m_Death ); + } + } + + public void Clear( ChampionSkullBrazier brazier ) + { + if ( brazier != null ) + { + Effects.SendBoltEffect( brazier ); + + if ( brazier.Skull != null ) + brazier.Skull.Delete(); + } + } + + public bool Validate( ChampionSkullBrazier brazier ) + { + return ( brazier != null && brazier.Skull != null && !brazier.Skull.Deleted ); + } + + public ChampionSkullPlatform( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Power ); + writer.Write( m_Enlightenment ); + writer.Write( m_Venom ); + writer.Write( m_Pain ); + writer.Write( m_Greed ); + writer.Write( m_Death ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Power = reader.ReadItem() as ChampionSkullBrazier; + m_Enlightenment = reader.ReadItem() as ChampionSkullBrazier; + m_Venom = reader.ReadItem() as ChampionSkullBrazier; + m_Pain = reader.ReadItem() as ChampionSkullBrazier; + m_Greed = reader.ReadItem() as ChampionSkullBrazier; + m_Death = reader.ReadItem() as ChampionSkullBrazier; + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionSkullType.cs b/Scripts/Engines/CannedEvil/ChampionSkullType.cs new file mode 100644 index 0000000..165874a --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionSkullType.cs @@ -0,0 +1,15 @@ +using System; +using Server; + +namespace Server.Engines.CannedEvil +{ + public enum ChampionSkullType + { + Power, + Enlightenment, + Venom, + Pain, + Greed, + Death + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionSpawn.cs b/Scripts/Engines/CannedEvil/ChampionSpawn.cs new file mode 100644 index 0000000..f817567 --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionSpawn.cs @@ -0,0 +1,1350 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Regions; +using System.Collections.Generic; + +namespace Server.Engines.CannedEvil +{ + public class ChampionSpawn : Item + { + [CommandProperty(AccessLevel.GameMaster)] + public int SpawnSzMod + { + get + { + return (m_SPawnSzMod < 1 || m_SPawnSzMod > 12) ? 12 : m_SPawnSzMod; + } + set + { + m_SPawnSzMod = (value < 1 || value > 12) ? 12 : value; + } + } + private int m_SPawnSzMod; + private bool m_Active; + private bool m_RandomizeType; + private ChampionSpawnType m_Type; + private List m_Creatures; + private List m_RedSkulls; + private List m_WhiteSkulls; + private ChampionPlatform m_Platform; + private ChampionAltar m_Altar; + private int m_Kills; + private Mobile m_Champion; + + //private int m_SpawnRange; + private Rectangle2D m_SpawnArea; + private ChampionSpawnRegion m_Region; + + private TimeSpan m_ExpireDelay; + private DateTime m_ExpireTime; + + private TimeSpan m_RestartDelay; + private DateTime m_RestartTime; + + private Timer m_Timer, m_RestartTimer; + + private IdolOfTheChampion m_Idol; + + private bool m_HasBeenAdvanced; + private bool m_ConfinedRoaming; + + private Dictionary m_DamageEntries; + + [CommandProperty(AccessLevel.GameMaster)] + public bool ConfinedRoaming + { + get { return m_ConfinedRoaming; } + set { m_ConfinedRoaming = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool HasBeenAdvanced + { + get { return m_HasBeenAdvanced; } + set { m_HasBeenAdvanced = value; } + } + + [Constructable] + public ChampionSpawn() + : base(0xBD2) + { + Movable = false; + Visible = false; + + m_Creatures = new List(); + m_RedSkulls = new List(); + m_WhiteSkulls = new List(); + + m_Platform = new ChampionPlatform(this); + m_Altar = new ChampionAltar(this); + m_Idol = new IdolOfTheChampion(this); + + m_ExpireDelay = TimeSpan.FromMinutes(10.0); + m_RestartDelay = TimeSpan.FromMinutes(10.0); + + m_DamageEntries = new Dictionary(); + + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(SetInitialSpawnArea)); + } + + public void SetInitialSpawnArea() + { + //Previous default used to be 24; + SpawnArea = new Rectangle2D(new Point2D(X - 24, Y - 24), new Point2D(X + 24, Y + 24)); + } + + public void UpdateRegion() + { + if (m_Region != null) + m_Region.Unregister(); + + if (!Deleted && this.Map != Map.Internal) + { + m_Region = new ChampionSpawnRegion(this); + m_Region.Register(); + } + + /* + if( m_Region == null ) + { + m_Region = new ChampionSpawnRegion( this ); + } + else + { + m_Region.Unregister(); + //Why doesn't Region allow me to set it's map/Area meself? >< + m_Region = new ChampionSpawnRegion( this ); + } + */ + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RandomizeType + { + get { return m_RandomizeType; } + set { m_RandomizeType = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Kills + { + get + { + return m_Kills; + } + set + { + m_Kills = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Rectangle2D SpawnArea + { + get + { + return m_SpawnArea; + } + set + { + m_SpawnArea = value; + InvalidateProperties(); + UpdateRegion(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RestartDelay + { + get + { + return m_RestartDelay; + } + set + { + m_RestartDelay = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime RestartTime + { + get + { + return m_RestartTime; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan ExpireDelay + { + get + { + return m_ExpireDelay; + } + set + { + m_ExpireDelay = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime ExpireTime + { + get + { + return m_ExpireTime; + } + set + { + m_ExpireTime = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public ChampionSpawnType Type + { + get + { + return m_Type; + } + set + { + m_Type = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Active + { + get + { + return m_Active; + } + set + { + if (value) + Start(); + else + Stop(); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Champion + { + get + { + return m_Champion; + } + set + { + m_Champion = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Level + { + get + { + return m_RedSkulls.Count; + } + set + { + for (int i = m_RedSkulls.Count - 1; i >= value; --i) + { + m_RedSkulls[i].Delete(); + m_RedSkulls.RemoveAt(i); + } + + for (int i = m_RedSkulls.Count; i < value; ++i) + { + Item skull = new Item(0x1854); + + skull.Hue = 0x26; + skull.Movable = false; + skull.Light = LightType.Circle150; + + skull.MoveToWorld(GetRedSkullLocation(i), Map); + + m_RedSkulls.Add(skull); + } + + InvalidateProperties(); + } + } + + public int MaxKills + { + get + { + return (m_SPawnSzMod * (250 / 12)) - (Level * m_SPawnSzMod); + } + } + + public bool IsChampionSpawn(Mobile m) + { + return m_Creatures.Contains(m); + } + + public void SetWhiteSkullCount(int val) + { + for (int i = m_WhiteSkulls.Count - 1; i >= val; --i) + { + m_WhiteSkulls[i].Delete(); + m_WhiteSkulls.RemoveAt(i); + } + + for (int i = m_WhiteSkulls.Count; i < val; ++i) + { + Item skull = new Item(0x1854); + + skull.Movable = false; + skull.Light = LightType.Circle150; + + skull.MoveToWorld(GetWhiteSkullLocation(i), Map); + + m_WhiteSkulls.Add(skull); + + Effects.PlaySound(skull.Location, skull.Map, 0x29); + Effects.SendLocationEffect(new Point3D(skull.X + 1, skull.Y + 1, skull.Z), skull.Map, 0x3728, 10); + } + } + + public void Start() + { + if (m_Active || Deleted) + return; + + m_Active = true; + m_HasBeenAdvanced = false; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = new SliceTimer(this); + m_Timer.Start(); + + if (m_RestartTimer != null) + m_RestartTimer.Stop(); + + m_RestartTimer = null; + + if (m_Altar != null) + { + if (m_Champion != null) + m_Altar.Hue = 0x26; + else + m_Altar.Hue = 0; + } + + if (m_Platform != null) + m_Platform.Hue = 0x452; + } + + public void Stop() + { + if (!m_Active || Deleted) + return; + + m_Active = false; + m_HasBeenAdvanced = false; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = null; + + if (m_RestartTimer != null) + m_RestartTimer.Stop(); + + m_RestartTimer = null; + + if (m_Altar != null) + m_Altar.Hue = 0; + + if (m_Platform != null) + m_Platform.Hue = 0x497; + } + + public void BeginRestart(TimeSpan ts) + { + if (m_RestartTimer != null) + m_RestartTimer.Stop(); + + m_RestartTime = DateTime.Now + ts; + + m_RestartTimer = new RestartTimer(this, ts); + m_RestartTimer.Start(); + } + + public void EndRestart() + { + if (RandomizeType) + { + switch (Utility.Random(5)) + { + case 0: Type = ChampionSpawnType.VerminHorde; break; + case 1: Type = ChampionSpawnType.UnholyTerror; break; + case 2: Type = ChampionSpawnType.ColdBlood; break; + case 3: Type = ChampionSpawnType.Abyss; break; + case 4: Type = ChampionSpawnType.Arachnid; break; + } + } + + m_HasBeenAdvanced = false; + + Start(); + } + + #region Scroll of Transcendence + private ScrollofTranscendence CreateRandomSoT(bool felucca) + { + int level = Utility.RandomMinMax(1, 5); + + if (felucca) + level += 5; + + return ScrollofTranscendence.CreateRandom(level, level); + } + #endregion + + public static void GiveScrollTo(Mobile killer, SpecialScroll scroll) + { + if (scroll == null || killer == null) //sanity + return; + + if (scroll is ScrollofTranscendence) + killer.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence! + else + killer.SendLocalizedMessage(1049524); // You have received a scroll of power! + + if (killer.Alive) + killer.AddToBackpack(scroll); + else + { + if (killer.Corpse != null && !killer.Corpse.Deleted) + killer.Corpse.DropItem(scroll); + else + killer.AddToBackpack(scroll); + } + + // Justice reward + PlayerMobile pm = (PlayerMobile)killer; + for (int j = 0; j < pm.JusticeProtectors.Count; ++j) + { + Mobile prot = (Mobile)pm.JusticeProtectors[j]; + + if (prot.Map != killer.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(killer, prot)) + continue; + + int chance = 0; + + switch (VirtueHelper.GetLevel(prot, VirtueName.Justice)) + { + case VirtueLevel.Seeker: chance = 60; break; + case VirtueLevel.Follower: chance = 80; break; + case VirtueLevel.Knight: chance = 100; break; + } + + if (chance > Utility.Random(100)) + { + try + { + prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice! + + SpecialScroll scrollDupe = Activator.CreateInstance(scroll.GetType()) as SpecialScroll; + + if (scrollDupe != null) + { + scrollDupe.Skill = scroll.Skill; + scrollDupe.Value = scroll.Value; + prot.AddToBackpack(scrollDupe); + } + } + catch { } + } + } + } + + public void OnSlice() + { + if (!m_Active || Deleted) + return; + + if (m_Champion != null) + { + if (m_Champion.Deleted) + { + RegisterDamageTo(m_Champion); + + if (m_Champion is BaseChampion) + AwardArtifact(((BaseChampion)m_Champion).GetArtifact()); + + m_DamageEntries.Clear(); + + if (m_Platform != null) + m_Platform.Hue = 0x497; + + if (m_Altar != null) + { + m_Altar.Hue = 0; + + if (!Core.ML || Map == Map.Felucca) + { + new StarRoomGate(true, m_Altar.Location, m_Altar.Map); + } + } + + m_Champion = null; + Stop(); + + BeginRestart(m_RestartDelay); + } + } + else + { + int kills = m_Kills; + + for (int i = 0; i < m_Creatures.Count; ++i) + { + Mobile m = m_Creatures[i]; + + if (m.Deleted) + { + if (m.Corpse != null && !m.Corpse.Deleted) + { + ((Corpse)m.Corpse).BeginDecay(TimeSpan.FromMinutes(1)); + } + m_Creatures.RemoveAt(i); + --i; + ++m_Kills; + + Mobile killer = m.FindMostRecentDamager(false); + + RegisterDamageTo(m); + + if (killer is BaseCreature) + killer = ((BaseCreature)killer).GetMaster(); + + if (killer is PlayerMobile) + { + #region Scroll of Transcendence + if (Core.ML) + { + if (Map == Map.Felucca) + { + if (Utility.RandomDouble() < 0.001) + { + PlayerMobile pm = (PlayerMobile)killer; + double random = Utility.Random(49); + + if (random <= 24) + { + ScrollofTranscendence SoTF = CreateRandomSoT(true); + GiveScrollTo(pm, (SpecialScroll)SoTF); + } + else + { + PowerScroll PS = PowerScroll.CreateRandomNoCraft(5, 5); + GiveScrollTo(pm, (SpecialScroll)PS); + } + } + } + + if (Map == Map.Ilshenar || Map == Map.Tokuno || Map == Map.Malas) + { + if (Utility.RandomDouble() < 0.0015) + { + killer.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence! + ScrollofTranscendence SoTT = CreateRandomSoT(false); + killer.AddToBackpack(SoTT); + } + } + } + #endregion + + int mobSubLevel = GetSubLevelFor(m) + 1; + + if (mobSubLevel >= 0) + { + bool gainedPath = false; + + int pointsToGain = mobSubLevel * 40; + + if (VirtueHelper.Award(killer, VirtueName.Valor, pointsToGain, ref gainedPath)) + { + if (gainedPath) + m.SendLocalizedMessage(1054032); // You have gained a path in Valor! + else + m.SendLocalizedMessage(1054030); // You have gained in Valor! + + //No delay on Valor gains + } + + PlayerMobile.ChampionTitleInfo info = ((PlayerMobile)killer).ChampionTitles; + + info.Award(m_Type, mobSubLevel); + } + } + } + } + + // Only really needed once. + if (m_Kills > kills) + InvalidateProperties(); + + double n = m_Kills / (double)MaxKills; + int p = (int)(n * 100); + + if (p >= 90) + AdvanceLevel(); + else if (p > 0) + SetWhiteSkullCount(p / 20); + + if (DateTime.Now >= m_ExpireTime) + Expire(); + + Respawn(); + } + } + + public void AdvanceLevel() + { + m_ExpireTime = DateTime.Now + m_ExpireDelay; + + if (Level < 16) + { + m_Kills = 0; + ++Level; + InvalidateProperties(); + SetWhiteSkullCount(0); + + if (m_Altar != null) + { + Effects.PlaySound(m_Altar.Location, m_Altar.Map, 0x29); + Effects.SendLocationEffect(new Point3D(m_Altar.X + 1, m_Altar.Y + 1, m_Altar.Z), m_Altar.Map, 0x3728, 10); + } + } + else + { + SpawnChampion(); + } + } + + public void SpawnChampion() + { + if (m_Altar != null) + m_Altar.Hue = 0x26; + + if (m_Platform != null) + m_Platform.Hue = 0x452; + + m_Kills = 0; + Level = 0; + InvalidateProperties(); + SetWhiteSkullCount(0); + + try + { + m_Champion = Activator.CreateInstance(ChampionSpawnInfo.GetInfo(m_Type).Champion) as Mobile; + } + catch { } + + if (m_Champion != null) + m_Champion.MoveToWorld(new Point3D(X, Y, Z - 15), Map); + } + + public void Respawn() + { + if (!m_Active || Deleted || m_Champion != null) + return; + + while (m_Creatures.Count < ((m_SPawnSzMod * (200 / 12))) - (GetSubLevel() * (m_SPawnSzMod * (40 / 12)))) + { + Mobile m = Spawn(); + + if (m == null) + return; + + Point3D loc = GetSpawnLocation(); + + // Allow creatures to turn into Paragons at Ilshenar champions. + m.OnBeforeSpawn(loc, Map); + + m_Creatures.Add(m); + m.MoveToWorld(loc, Map); + + if (m is BaseCreature) + { + BaseCreature bc = m as BaseCreature; + bc.Tamable = false; + + if (!m_ConfinedRoaming) + { + bc.Home = this.Location; + bc.RangeHome = (int)(Math.Sqrt(m_SpawnArea.Width * m_SpawnArea.Width + m_SpawnArea.Height * m_SpawnArea.Height) / 2); + } + else + { + bc.Home = bc.Location; + + Point2D xWall1 = new Point2D(m_SpawnArea.X, bc.Y); + Point2D xWall2 = new Point2D(m_SpawnArea.X + m_SpawnArea.Width, bc.Y); + Point2D yWall1 = new Point2D(bc.X, m_SpawnArea.Y); + Point2D yWall2 = new Point2D(bc.X, m_SpawnArea.Y + m_SpawnArea.Height); + + double minXDist = Math.Min(bc.GetDistanceToSqrt(xWall1), bc.GetDistanceToSqrt(xWall2)); + double minYDist = Math.Min(bc.GetDistanceToSqrt(yWall1), bc.GetDistanceToSqrt(yWall2)); + + bc.RangeHome = (int)Math.Min(minXDist, minYDist); + } + } + } + } + + public Point3D GetSpawnLocation() + { + Map map = Map; + + if (map == null) + return Location; + + // Try 20 times to find a spawnable location. + for (int i = 0; i < 20; i++) + { + /* + int x = Location.X + (Utility.Random( (m_SpawnRange * 2) + 1 ) - m_SpawnRange); + int y = Location.Y + (Utility.Random( (m_SpawnRange * 2) + 1 ) - m_SpawnRange); + */ + + int x = Utility.Random(m_SpawnArea.X, m_SpawnArea.Width); + int y = Utility.Random(m_SpawnArea.Y, m_SpawnArea.Height); + + int z = Map.GetAverageZ(x, y); + + if (Map.CanSpawnMobile(new Point2D(x, y), z)) + return new Point3D(x, y, z); + + /* try @ platform Z if map z fails */ + else if (Map.CanSpawnMobile(new Point2D(x, y), m_Platform.Location.Z)) + return new Point3D(x, y, m_Platform.Location.Z); + } + + return Location; + } + + private const int Level1 = 4; // First spawn level from 0-4 red skulls + private const int Level2 = 8; // Second spawn level from 5-8 red skulls + private const int Level3 = 12; // Third spawn level from 9-12 red skulls + + public int GetSubLevel() + { + int level = this.Level; + + if (level <= Level1) + return 0; + else if (level <= Level2) + return 1; + else if (level <= Level3) + return 2; + + return 3; + } + + public int GetSubLevelFor(Mobile m) + { + Type[][] types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes; + Type t = m.GetType(); + + for (int i = 0; i < types.GetLength(0); i++) + { + Type[] individualTypes = types[i]; + + for (int j = 0; j < individualTypes.Length; j++) + { + if (t == individualTypes[j]) + return i; + } + } + + return -1; + } + + public Mobile Spawn() + { + Type[][] types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes; + + int v = GetSubLevel(); + + if (v >= 0 && v < types.Length) + return Spawn(types[v]); + + return null; + } + + public Mobile Spawn(params Type[] types) + { + try + { + return Activator.CreateInstance(types[Utility.Random(types.Length)]) as Mobile; + } + catch + { + return null; + } + } + + public void Expire() + { + m_Kills = 0; + + if (m_WhiteSkulls.Count == 0) + { + // They didn't even get 20%, go back a level + + if (Level > 0) + --Level; + + InvalidateProperties(); + } + else + { + SetWhiteSkullCount(0); + } + + m_ExpireTime = DateTime.Now + m_ExpireDelay; + } + + public Point3D GetRedSkullLocation(int index) + { + int x, y; + + if (index < 5) + { + x = index - 2; + y = -2; + } + else if (index < 9) + { + x = 2; + y = index - 6; + } + else if (index < 13) + { + x = 10 - index; + y = 2; + } + else + { + x = -2; + y = 14 - index; + } + + return new Point3D(X + x, Y + y, Z - 15); + } + + public Point3D GetWhiteSkullLocation(int index) + { + int x, y; + + switch (index) + { + default: + case 0: x = -1; y = -1; break; + case 1: x = 1; y = -1; break; + case 2: x = 1; y = 1; break; + case 3: x = -1; y = 1; break; + } + + return new Point3D(X + x, Y + y, Z - 15); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add("champion spawn"); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Active) + { + list.Add(1060742); // active + list.Add(1060658, "Type\t{0}", m_Type); // ~1_val~: ~2_val~ + list.Add(1060659, "Level\t{0}", Level); // ~1_val~: ~2_val~ + list.Add(1060660, "Kills\t{0} of {1} ({2:F1}%)", m_Kills, MaxKills, 100.0 * ((double)m_Kills / MaxKills)); // ~1_val~: ~2_val~ + //list.Add( 1060661, "Spawn Range\t{0}", m_SpawnRange ); // ~1_val~: ~2_val~ + } + else + { + list.Add(1060743); // inactive + } + } + + public override void OnSingleClick(Mobile from) + { + if (m_Active) + LabelTo(from, "{0} (Active; Level: {1}; Kills: {2}/{3})", m_Type, Level, m_Kills, MaxKills); + else + LabelTo(from, "{0} (Inactive)", m_Type); + } + + public override void OnDoubleClick(Mobile from) + { + from.SendGump(new PropertiesGump(from, this)); + } + + public override void OnLocationChange(Point3D oldLoc) + { + if (Deleted) + return; + + if (m_Platform != null) + m_Platform.Location = new Point3D(X, Y, Z - 20); + + if (m_Altar != null) + m_Altar.Location = new Point3D(X, Y, Z - 15); + + if (m_Idol != null) + m_Idol.Location = new Point3D(X, Y, Z - 15); + + if (m_RedSkulls != null) + { + for (int i = 0; i < m_RedSkulls.Count; ++i) + m_RedSkulls[i].Location = GetRedSkullLocation(i); + } + + if (m_WhiteSkulls != null) + { + for (int i = 0; i < m_WhiteSkulls.Count; ++i) + m_WhiteSkulls[i].Location = GetWhiteSkullLocation(i); + } + + m_SpawnArea.X += Location.X - oldLoc.X; + m_SpawnArea.Y += Location.Y - oldLoc.Y; + + UpdateRegion(); + } + + public override void OnMapChange() + { + if (Deleted) + return; + + if (m_Platform != null) + m_Platform.Map = Map; + + if (m_Altar != null) + m_Altar.Map = Map; + + if (m_Idol != null) + m_Idol.Map = Map; + + if (m_RedSkulls != null) + { + for (int i = 0; i < m_RedSkulls.Count; ++i) + m_RedSkulls[i].Map = Map; + } + + if (m_WhiteSkulls != null) + { + for (int i = 0; i < m_WhiteSkulls.Count; ++i) + m_WhiteSkulls[i].Map = Map; + } + + UpdateRegion(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Platform != null) + m_Platform.Delete(); + + if (m_Altar != null) + m_Altar.Delete(); + + if (m_Idol != null) + m_Idol.Delete(); + + if (m_RedSkulls != null) + { + for (int i = 0; i < m_RedSkulls.Count; ++i) + m_RedSkulls[i].Delete(); + + m_RedSkulls.Clear(); + } + + if (m_WhiteSkulls != null) + { + for (int i = 0; i < m_WhiteSkulls.Count; ++i) + m_WhiteSkulls[i].Delete(); + + m_WhiteSkulls.Clear(); + } + + if (m_Creatures != null) + { + for (int i = 0; i < m_Creatures.Count; ++i) + { + Mobile mob = m_Creatures[i]; + + if (!mob.Player) + mob.Delete(); + } + + m_Creatures.Clear(); + } + + if (m_Champion != null && !m_Champion.Player) + m_Champion.Delete(); + + Stop(); + + UpdateRegion(); + } + + public ChampionSpawn(Serial serial) + : base(serial) + { + } + + public virtual void RegisterDamageTo(Mobile m) + { + if (m == null) + return; + + foreach (DamageEntry de in m.DamageEntries) + { + if (de.HasExpired) + continue; + + Mobile damager = de.Damager; + + Mobile master = damager.GetDamageMaster(m); + + if (master != null) + damager = master; + + RegisterDamage(damager, de.DamageGiven); + } + } + + public void RegisterDamage(Mobile from, int amount) + { + if (from == null || !from.Player) + return; + + if (m_DamageEntries.ContainsKey(from)) + m_DamageEntries[from] += amount; + else + m_DamageEntries.Add(from, amount); + } + + public void AwardArtifact(Item artifact) + { + if (artifact == null) + return; + + int totalDamage = 0; + + Dictionary validEntries = new Dictionary(); + + foreach (KeyValuePair kvp in m_DamageEntries) + { + if (IsEligible(kvp.Key, artifact)) + { + validEntries.Add(kvp.Key, kvp.Value); + totalDamage += kvp.Value; + } + } + + int randomDamage = Utility.RandomMinMax(1, totalDamage); + + totalDamage = 0; + + foreach (KeyValuePair kvp in validEntries) + { + totalDamage += kvp.Value; + + if (totalDamage >= randomDamage) + { + GiveArtifact(kvp.Key, artifact); + return; + } + } + + artifact.Delete(); + } + + public void GiveArtifact(Mobile to, Item artifact) + { + if (to == null || artifact == null) + return; + + Container pack = to.Backpack; + + if (pack == null || !pack.TryDropItem(to, artifact, false)) + artifact.Delete(); + else + to.SendLocalizedMessage(1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + + public bool IsEligible(Mobile m, Item Artifact) + { + return m.Player && m.Alive && m.Region != null && m.Region == m_Region && m.Backpack != null && m.Backpack.CheckHold(m, Artifact, false); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)6); // version + + writer.Write((int)m_SPawnSzMod); + writer.Write(m_DamageEntries.Count); + foreach (KeyValuePair kvp in m_DamageEntries) + { + writer.Write(kvp.Key); + writer.Write(kvp.Value); + } + + writer.Write(m_ConfinedRoaming); + writer.WriteItem(m_Idol); + writer.Write(m_HasBeenAdvanced); + writer.Write(m_SpawnArea); + + writer.Write(m_RandomizeType); + + // writer.Write( m_SpawnRange ); + writer.Write(m_Kills); + + writer.Write((bool)m_Active); + writer.Write((int)m_Type); + writer.Write(m_Creatures, true); + writer.Write(m_RedSkulls, true); + writer.Write(m_WhiteSkulls, true); + writer.WriteItem(m_Platform); + writer.WriteItem(m_Altar); + writer.Write(m_ExpireDelay); + writer.WriteDeltaTime(m_ExpireTime); + writer.Write(m_Champion); + writer.Write(m_RestartDelay); + + writer.Write(m_RestartTimer != null); + + if (m_RestartTimer != null) + writer.WriteDeltaTime(m_RestartTime); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + m_DamageEntries = new Dictionary(); + + int version = reader.ReadInt(); + + switch (version) + { + case 6: + { + m_SPawnSzMod = reader.ReadInt(); + goto case 5; + } + case 5: + { + int entries = reader.ReadInt(); + Mobile m; + int damage; + for (int i = 0; i < entries; ++i) + { + m = reader.ReadMobile(); + damage = reader.ReadInt(); + + if (m == null) + continue; + + m_DamageEntries.Add(m, damage); + } + + goto case 4; + } + case 4: + { + m_ConfinedRoaming = reader.ReadBool(); + m_Idol = reader.ReadItem(); + m_HasBeenAdvanced = reader.ReadBool(); + + goto case 3; + } + case 3: + { + m_SpawnArea = reader.ReadRect2D(); + + goto case 2; + } + case 2: + { + m_RandomizeType = reader.ReadBool(); + + goto case 1; + } + case 1: + { + if (version < 3) + { + int oldRange = reader.ReadInt(); + + m_SpawnArea = new Rectangle2D(new Point2D(X - oldRange, Y - oldRange), new Point2D(X + oldRange, Y + oldRange)); + } + + m_Kills = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if (version < 1) + m_SpawnArea = new Rectangle2D(new Point2D(X - 24, Y - 24), new Point2D(X + 24, Y + 24)); //Default was 24 + + bool active = reader.ReadBool(); + m_Type = (ChampionSpawnType)reader.ReadInt(); + m_Creatures = reader.ReadStrongMobileList(); + m_RedSkulls = reader.ReadStrongItemList(); + m_WhiteSkulls = reader.ReadStrongItemList(); + m_Platform = reader.ReadItem(); + m_Altar = reader.ReadItem(); + m_ExpireDelay = reader.ReadTimeSpan(); + m_ExpireTime = reader.ReadDeltaTime(); + m_Champion = reader.ReadMobile(); + m_RestartDelay = reader.ReadTimeSpan(); + + if (reader.ReadBool()) + { + m_RestartTime = reader.ReadDeltaTime(); + BeginRestart(m_RestartTime - DateTime.Now); + } + + if (version < 4) + { + m_Idol = new IdolOfTheChampion(this); + m_Idol.MoveToWorld(new Point3D(X, Y, Z - 15), Map); + } + + if (m_Platform == null || m_Altar == null || m_Idol == null) + Delete(); + else if (active) + Start(); + + break; + } + } + + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(UpdateRegion)); + } + } + + public class ChampionSpawnRegion : BaseRegion + { + public override bool YoungProtected { get { return false; } } + + private ChampionSpawn m_Spawn; + + public ChampionSpawn ChampionSpawn + { + get { return m_Spawn; } + } + + public ChampionSpawnRegion(ChampionSpawn spawn) + : base(null, spawn.Map, Region.Find(spawn.Location, spawn.Map), spawn.SpawnArea) + { + m_Spawn = spawn; + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + base.AlterLightLevel(m, ref global, ref personal); + global = Math.Max(global, 1 + m_Spawn.Level); //This is a guesstimate. TODO: Verify & get exact values // OSI testing: at 2 red skulls, light = 0x3 ; 1 red = 0x3.; 3 = 8; 9 = 0xD 8 = 0xD 12 = 0x12 10 = 0xD + } + } + + public class IdolOfTheChampion : Item + { + private ChampionSpawn m_Spawn; + + public ChampionSpawn Spawn { get { return m_Spawn; } } + + public override string DefaultName + { + get { return "Idol of the Champion"; } + } + + + public IdolOfTheChampion(ChampionSpawn spawn) + : base(0x1F18) + { + m_Spawn = spawn; + Movable = false; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Spawn != null) + m_Spawn.Delete(); + } + + public IdolOfTheChampion(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Spawn); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Spawn = reader.ReadItem() as ChampionSpawn; + + if (m_Spawn == null) + Delete(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/ChampionSpawnType.cs b/Scripts/Engines/CannedEvil/ChampionSpawnType.cs new file mode 100644 index 0000000..f15eb11 --- /dev/null +++ b/Scripts/Engines/CannedEvil/ChampionSpawnType.cs @@ -0,0 +1,122 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.CannedEvil +{ + public enum ChampionSpawnType + { + Abyss, + Arachnid, + ColdBlood, + ForestLord, + VerminHorde, + UnholyTerror, + SleepingDragon, + Glade, + Pestilence + } + + public class ChampionSpawnInfo + { + private string m_Name; + private Type m_Champion; + private Type[][] m_SpawnTypes; + private string[] m_LevelNames; + + public string Name { get { return m_Name; } } + public Type Champion { get { return m_Champion; } } + public Type[][] SpawnTypes { get { return m_SpawnTypes; } } + public string[] LevelNames { get { return m_LevelNames; } } + + public ChampionSpawnInfo(string name, Type champion, string[] levelNames, Type[][] spawnTypes) + { + m_Name = name; + m_Champion = champion; + m_LevelNames = levelNames; + m_SpawnTypes = spawnTypes; + } + + public static ChampionSpawnInfo[] Table { get { return m_Table; } } + + private static readonly ChampionSpawnInfo[] m_Table = new ChampionSpawnInfo[] + { + new ChampionSpawnInfo( "Abyss", typeof( Semidar ), new string[]{ "Foe", "Assassin", "Conqueror" }, new Type[][] // Abyss + { // Abyss + new Type[]{ typeof( GreaterMongbat ), typeof( Imp ) }, // Level 1 + new Type[]{ typeof( Gargoyle ), typeof( Harpy ) }, // Level 2 + new Type[]{ typeof( FireGargoyle ), typeof( StoneGargoyle ) }, // Level 3 + new Type[]{ typeof( Daemon ), typeof( Succubus ) } // Level 4 + } ), + new ChampionSpawnInfo( "Arachnid", typeof( Mephitis ), new string[]{ "Bane", "Killer", "Vanquisher" }, new Type[][] // Arachnid + { // Arachnid + new Type[]{ typeof( Scorpion ), typeof( GiantSpider ) }, // Level 1 + new Type[]{ typeof( TerathanDrone ), typeof( TerathanWarrior ) }, // Level 2 + new Type[]{ typeof( DreadSpider ), typeof( TerathanMatriarch ) }, // Level 3 + new Type[]{ typeof( PoisonElemental ), typeof( TerathanAvenger ) } // Level 4 + } ), + new ChampionSpawnInfo( "Cold Blood", typeof( Rikktor ), new string[]{ "Blight", "Slayer", "Destroyer" }, new Type[][] // Cold Blood + { // Cold Blood + new Type[]{ typeof( Lizardman ), typeof( Snake ) }, // Level 1 + new Type[]{ typeof( LavaLizard ), typeof( OphidianWarrior ) }, // Level 2 + new Type[]{ typeof( Drake ), typeof( OphidianArchmage ) }, // Level 3 + new Type[]{ typeof( Dragon ), typeof( OphidianKnight ) } // Level 4 + } ), + new ChampionSpawnInfo( "Forest Lord", typeof( LordOaks ), new string[]{ "Enemy", "Curse", "Slaughterer" }, new Type[][] // Forest Lord + { // Forest Lord + new Type[]{ typeof( Pixie ), typeof( ShadowWisp ) }, // Level 1 + new Type[]{ typeof( Kirin ), typeof( Wisp ) }, // Level 2 + new Type[]{ typeof( Centaur ), typeof( Unicorn ) }, // Level 3 + new Type[]{ typeof( EtherealWarrior ), typeof( SerpentineDragon ) } // Level 4 + } ), + new ChampionSpawnInfo( "Vermin Horde", typeof( Barracoon ), new string[]{ "Adversary", "Subjugator", "Eradicator" }, new Type[][] // Vermin Horde + { // Vermin Horde + new Type[]{ typeof( GiantRat ), typeof( Slime ) }, // Level 1 + new Type[]{ typeof( DireWolf ), typeof( Ratman ) }, // Level 2 + new Type[]{ typeof( HellHound ), typeof( RatmanMage ) }, // Level 3 + new Type[]{ typeof( RatmanArcher ), typeof( SilverSerpent ) } // Level 4 + } ), + new ChampionSpawnInfo( "Unholy Terror", typeof( Neira ), new string[]{ "Scourge", "Punisher", "Nemesis" }, new Type[][] // Unholy Terror + { // Unholy Terror + (Core.AOS ? + new Type[]{ typeof( Bogle ), typeof( Ghoul ), typeof( Shade ), typeof( Spectre ), typeof( Wraith ) } // Level 1 (Pre-AoS) + : new Type[]{ typeof( Ghoul ), typeof( Shade ), typeof( Spectre ), typeof( Wraith ) } ), // Level 1 + + new Type[]{ typeof( BoneMagi ), typeof( Mummy ), typeof( SkeletalMage ) }, // Level 2 + new Type[]{ typeof( BoneKnight ), typeof( Lich ), typeof( SkeletalKnight ) }, // Level 3 + new Type[]{ typeof( LichLord ), typeof( RottingCorpse ) } // Level 4 + } ), + new ChampionSpawnInfo( "Sleeping Dragon", typeof( Serado ), new string[]{ "Rival", "Challenger", "Antagonist" } , new Type[][] + { // Unholy Terror + new Type[]{ typeof( DeathwatchBeetleHatchling ), typeof( Lizardman ) }, + new Type[]{ typeof( DeathwatchBeetle ), typeof( Kappa ) }, + new Type[]{ typeof( LesserHiryu ), typeof( RevenantLion ) }, + new Type[]{ typeof( Hiryu ), typeof( Oni ) } + } ), + new ChampionSpawnInfo( "Glade", typeof( Twaulo ), new string[]{ "Banisher", "Enforcer", "Eradicator" } , new Type[][] + { // Glade + new Type[]{ typeof( Pixie ), typeof( ShadowWisp ) }, + new Type[]{ typeof( Centaur ), typeof( MLDryad ) }, + new Type[]{ typeof( Satyr ), typeof( CuSidhe ) }, + new Type[]{ typeof( FerelTreefellow ), typeof( RagingGrizzlyBear ) } + } ), + new ChampionSpawnInfo( "The Corrupt", typeof( Ilhenir ), new string[]{ "Cleanser", "Expunger", "Depurator" } , new Type[][] + { // Unholy Terror + new Type[]{ typeof( PlagueSpawn ), typeof( Bogling ) }, + new Type[]{ typeof( PlagueBeast ), typeof( BogThing ) }, + new Type[]{ typeof( PlagueBeastLord ), typeof( InterredGrizzle ) }, + new Type[]{ typeof( FetidEssence ), typeof( PestilentBandage ) } + } ) + }; + + public static ChampionSpawnInfo GetInfo(ChampionSpawnType type) + { + int v = (int)type; + + if (v < 0 || v >= m_Table.Length) + v = 0; + + return m_Table[v]; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/HarrowerGate.cs b/Scripts/Engines/CannedEvil/HarrowerGate.cs new file mode 100644 index 0000000..0331c55 --- /dev/null +++ b/Scripts/Engines/CannedEvil/HarrowerGate.cs @@ -0,0 +1,59 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HarrowerGate : Moongate + { + private Mobile m_Harrower; + + public override int LabelNumber{ get{ return 1049498; } } // dark moongate + + public HarrowerGate( Mobile harrower, Point3D loc, Map map, Point3D targLoc, Map targMap ) : base( targLoc, targMap ) + { + m_Harrower = harrower; + + Dispellable = false; + ItemID = 0x1FD4; + Light = LightType.Circle300; + + MoveToWorld( loc, map ); + } + + public HarrowerGate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Harrower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Harrower = reader.ReadMobile(); + + if ( m_Harrower == null ) + Delete(); + + break; + } + } + + if ( Light != LightType.Circle300 ) + Light = LightType.Circle300; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/RestartTimer.cs b/Scripts/Engines/CannedEvil/RestartTimer.cs new file mode 100644 index 0000000..dd4257c --- /dev/null +++ b/Scripts/Engines/CannedEvil/RestartTimer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Engines.CannedEvil +{ + public class RestartTimer : Timer + { + private ChampionSpawn m_Spawn; + + public RestartTimer( ChampionSpawn spawn, TimeSpan delay ) : base( delay ) + { + m_Spawn = spawn; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Spawn.EndRestart(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/SliceTimer.cs b/Scripts/Engines/CannedEvil/SliceTimer.cs new file mode 100644 index 0000000..7323bd9 --- /dev/null +++ b/Scripts/Engines/CannedEvil/SliceTimer.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Engines.CannedEvil +{ + public class SliceTimer : Timer + { + private ChampionSpawn m_Spawn; + + public SliceTimer( ChampionSpawn spawn ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Spawn = spawn; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Spawn.OnSlice(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/CannedEvil/StarRoomGate.cs b/Scripts/Engines/CannedEvil/StarRoomGate.cs new file mode 100644 index 0000000..3d3688e --- /dev/null +++ b/Scripts/Engines/CannedEvil/StarRoomGate.cs @@ -0,0 +1,106 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StarRoomGate : Moongate + { + private bool m_Decays; + private DateTime m_DecayTime; + private Timer m_Timer; + + public override int LabelNumber{ get{ return 1049498; } } // dark moongate + + [Constructable] + public StarRoomGate() : this( false ) + { + } + + [Constructable] + public StarRoomGate( bool decays, Point3D loc, Map map ) : this( decays ) + { + MoveToWorld( loc, map ); + Effects.PlaySound( loc, map, 0x20E ); + } + + [Constructable] + public StarRoomGate( bool decays ) : base( new Point3D( 5143, 1774, 0 ), Map.Felucca ) + { + Dispellable = false; + ItemID = 0x1FD4; + + if ( decays ) + { + m_Decays = true; + m_DecayTime = DateTime.Now + TimeSpan.FromMinutes( 2.0 ); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + } + } + + public StarRoomGate( Serial serial ) : base( serial ) + { + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + base.OnAfterDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Decays ); + + if ( m_Decays ) + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Decays = reader.ReadBool(); + + if ( m_Decays ) + { + m_DecayTime = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_DecayTime ); + m_Timer.Start(); + } + + break; + } + } + } + + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item, DateTime end ) : base( end - DateTime.Now ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/Channel.cs b/Scripts/Engines/Chat/Channel.cs new file mode 100644 index 0000000..aea4328 --- /dev/null +++ b/Scripts/Engines/Chat/Channel.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Engines.Chat +{ + public class Channel + { + private string m_Name; + private string m_Password; + private List m_Users, m_Banned, m_Moderators, m_Voices; + private bool m_VoiceRestricted; + private bool m_AlwaysAvailable; + + public Channel( string name ) + { + m_Name = name; + + m_Users = new List(); + m_Banned = new List(); + m_Moderators = new List(); + m_Voices = new List(); + } + + public Channel( string name, string password ) : this( name ) + { + m_Password = password; + } + + public string Name + { + get + { + return m_Name; + } + set + { + SendCommand( ChatCommand.RemoveChannel, m_Name ); + m_Name = value; + SendCommand( ChatCommand.AddChannel, m_Name ); + SendCommand( ChatCommand.JoinedChannel, m_Name ); + } + } + + public string Password + { + get + { + return m_Password; + } + set + { + string newValue = null; + + if ( value != null ) + { + newValue = value.Trim(); + + if ( String.IsNullOrEmpty( newValue ) ) + newValue = null; + } + + m_Password = newValue; + } + } + + public bool Contains( ChatUser user ) + { + return m_Users.Contains( user ); + } + + public bool IsBanned( ChatUser user ) + { + return m_Banned.Contains( user ); + } + + public bool CanTalk( ChatUser user ) + { + return ( !m_VoiceRestricted || m_Voices.Contains( user ) || m_Moderators.Contains( user ) ); + } + + public bool IsModerator( ChatUser user ) + { + return m_Moderators.Contains( user ); + } + + public bool IsVoiced( ChatUser user ) + { + return m_Voices.Contains( user ); + } + + public bool ValidatePassword( string password ) + { + return ( m_Password == null || Insensitive.Equals( m_Password, password ) ); + } + + public bool ValidateModerator( ChatUser user ) + { + if ( user != null && !IsModerator( user ) ) + { + user.SendMessage( 29 ); // You must have operator status to do this. + return false; + } + + return true; + } + + public bool ValidateAccess( ChatUser from, ChatUser target ) + { + if ( from != null && target != null && from.Mobile.AccessLevel < target.Mobile.AccessLevel ) + { + from.Mobile.SendMessage( "Your access level is too low to do this." ); + return false; + } + + return true; + } + + public bool AddUser( ChatUser user ) + { + return AddUser( user, null ); + } + + public bool AddUser( ChatUser user, string password ) + { + if ( Contains( user ) ) + { + user.SendMessage( 46, m_Name ); // You are already in the conference '%1'. + return true; + } + else if ( IsBanned( user ) ) + { + user.SendMessage( 64 ); // You have been banned from this conference. + return false; + } + else if ( !ValidatePassword( password ) ) + { + user.SendMessage( 34 ); // That is not the correct password. + return false; + } + else + { + if ( user.CurrentChannel != null ) + user.CurrentChannel.RemoveUser( user ); // Remove them from their current channel first + + ChatSystem.SendCommandTo( user.Mobile, ChatCommand.JoinedChannel, m_Name ); + + SendCommand( ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username ); + + m_Users.Add( user ); + user.CurrentChannel = this; + + if ( user.Mobile.AccessLevel >= AccessLevel.GameMaster || (!m_AlwaysAvailable && m_Users.Count == 1) ) + AddModerator( user ); + + SendUsersTo( user ); + + return true; + } + } + + public void RemoveUser( ChatUser user ) + { + if ( Contains( user ) ) + { + m_Users.Remove( user ); + user.CurrentChannel = null; + + if ( m_Moderators.Contains( user ) ) + m_Moderators.Remove( user ); + + if ( m_Voices.Contains( user ) ) + m_Voices.Remove( user ); + + SendCommand( ChatCommand.RemoveUserFromChannel, user, user.Username ); + ChatSystem.SendCommandTo( user.Mobile, ChatCommand.LeaveChannel ); + + if ( m_Users.Count == 0 && !m_AlwaysAvailable ) + RemoveChannel( this ); + } + } + + public void AdBan( ChatUser user ) + { + AddBan( user, null ); + } + + public void AddBan( ChatUser user, ChatUser moderator ) + { + if ( !ValidateModerator( moderator ) || !ValidateAccess( moderator, user ) ) + return; + + if ( !m_Banned.Contains( user ) ) + m_Banned.Add( user ); + + Kick( user, moderator, true ); + } + + public void RemoveBan( ChatUser user ) + { + if ( m_Banned.Contains( user ) ) + m_Banned.Remove( user ); + } + + public void Kick( ChatUser user ) + { + Kick( user, null ); + } + + public void Kick( ChatUser user, ChatUser moderator ) + { + Kick( user, moderator, false ); + } + + public void Kick( ChatUser user, ChatUser moderator, bool wasBanned ) + { + if ( !ValidateModerator( moderator ) || !ValidateAccess( moderator, user ) ) + return; + + if ( Contains( user ) ) + { + if ( moderator != null ) + { + if ( wasBanned ) + user.SendMessage( 63, moderator.Username ); // %1, a conference moderator, has banned you from the conference. + else + user.SendMessage( 45, moderator.Username ); // %1, a conference moderator, has kicked you out of the conference. + } + + RemoveUser( user ); + ChatSystem.SendCommandTo( user.Mobile, ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username ); + + SendMessage( 44, user.Username ) ; // %1 has been kicked out of the conference. + } + + if ( wasBanned && moderator != null ) + moderator.SendMessage( 62, user.Username ); // You are banning %1 from this conference. + } + + public bool VoiceRestricted + { + get + { + return m_VoiceRestricted; + } + set + { + m_VoiceRestricted = value; + + if ( value ) + SendMessage( 56 ); // From now on, only moderators will have speaking privileges in this conference by default. + else + SendMessage( 55 ); // From now on, everyone in the conference will have speaking privileges by default. + } + } + + public bool AlwaysAvailable + { + get + { + return m_AlwaysAvailable; + } + set + { + m_AlwaysAvailable = value; + } + } + + public void AddVoiced( ChatUser user ) + { + AddVoiced( user, null ); + } + + public void AddVoiced( ChatUser user, ChatUser moderator ) + { + if ( !ValidateModerator( moderator ) ) + return; + + if ( !IsBanned( user ) && !IsModerator( user ) && !IsVoiced( user ) ) + { + m_Voices.Add( user ); + + if ( moderator != null ) + user.SendMessage( 54, moderator.Username ); // %1, a conference moderator, has granted you speaking priviledges in this conference. + + SendMessage( 52, user, user.Username ); // %1 now has speaking privileges in this conference. + SendCommand( ChatCommand.AddUserToChannel, user, user.GetColorCharacter() + user.Username ); + } + } + + public void RemoveVoiced( ChatUser user, ChatUser moderator ) + { + if ( !ValidateModerator( moderator ) || !ValidateAccess( moderator, user ) ) + return; + + if ( !IsModerator( user ) && IsVoiced( user ) ) + { + m_Voices.Remove( user ); + + if ( moderator != null ) + user.SendMessage( 53, moderator.Username ); // %1, a conference moderator, has removed your speaking priviledges for this conference. + + SendMessage( 51, user, user.Username ); // %1 no longer has speaking privileges in this conference. + SendCommand( ChatCommand.AddUserToChannel, user, user.GetColorCharacter() + user.Username ); + } + } + + public void AddModerator( ChatUser user ) + { + AddModerator( user, null ); + } + + public void AddModerator( ChatUser user, ChatUser moderator ) + { + if ( !ValidateModerator( moderator ) ) + return; + + if ( IsBanned( user ) || IsModerator( user ) ) + return; + + if ( IsVoiced( user ) ) + m_Voices.Remove( user ); + + m_Moderators.Add( user ); + + if ( moderator != null ) + user.SendMessage( 50, moderator.Username ); // %1 has made you a conference moderator. + + SendMessage( 48, user, user.Username ); // %1 is now a conference moderator. + SendCommand( ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username ); + } + + public void RemoveModerator( ChatUser user ) + { + RemoveModerator( user, null ); + } + + public void RemoveModerator( ChatUser user, ChatUser moderator ) + { + if ( !ValidateModerator( moderator ) || !ValidateAccess( moderator, user ) ) + return; + + if ( IsModerator( user ) ) + { + m_Moderators.Remove( user ); + + if ( moderator != null ) + user.SendMessage( 49, moderator.Username ); // %1 has removed you from the list of conference moderators. + + SendMessage( 47, user, user.Username ); // %1 is no longer a conference moderator. + SendCommand( ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username ); + } + } + + public void SendMessage( int number ) + { + SendMessage( number, null, null, null ); + } + + public void SendMessage( int number, string param1 ) + { + SendMessage( number, null, param1, null ); + } + + public void SendMessage( int number, string param1, string param2 ) + { + SendMessage( number, null, param1, param2 ); + } + + public void SendMessage( int number, ChatUser initiator ) + { + SendMessage( number, initiator, null, null ); + } + + public void SendMessage( int number, ChatUser initiator, string param1 ) + { + SendMessage( number, initiator, param1, null ); + } + + public void SendMessage( int number, ChatUser initiator, string param1, string param2 ) + { + for ( int i = 0; i < m_Users.Count; ++i ) + { + ChatUser user = m_Users[i]; + + if ( user == initiator ) + continue; + + if ( user.CheckOnline() ) + user.SendMessage( number, param1, param2 ); + else if ( !Contains( user ) ) + --i; + } + } + + public void SendIgnorableMessage( int number, ChatUser from, string param1, string param2 ) + { + for ( int i = 0; i < m_Users.Count; ++i ) + { + ChatUser user = m_Users[i]; + + if ( user.IsIgnored( from ) ) + continue; + + if ( user.CheckOnline() ) + user.SendMessage( number, from.Mobile, param1, param2 ); + else if ( !Contains( user ) ) + --i; + } + } + + public void SendCommand( ChatCommand command ) + { + SendCommand( command, null, null, null ); + } + + public void SendCommand( ChatCommand command, string param1 ) + { + SendCommand( command, null, param1, null ); + } + + public void SendCommand( ChatCommand command, string param1, string param2 ) + { + SendCommand( command, null, param1, param2 ); + } + + public void SendCommand( ChatCommand command, ChatUser initiator ) + { + SendCommand( command, initiator, null, null ); + } + + public void SendCommand( ChatCommand command, ChatUser initiator, string param1 ) + { + SendCommand( command, initiator, param1, null ); + } + + public void SendCommand( ChatCommand command, ChatUser initiator, string param1, string param2 ) + { + for ( int i = 0; i < m_Users.Count; ++i ) + { + ChatUser user = m_Users[i]; + + if ( user == initiator ) + continue; + + if ( user.CheckOnline() ) + ChatSystem.SendCommandTo( user.Mobile, command, param1, param2 ); + else if ( !Contains( user ) ) + --i; + } + } + + public void SendUsersTo( ChatUser to ) + { + for ( int i = 0; i < m_Users.Count; ++i ) + { + ChatUser user = m_Users[i]; + + ChatSystem.SendCommandTo( to.Mobile, ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username ); + } + } + + private static List m_Channels = new List(); + + public static List Channels + { + get + { + return m_Channels; + } + } + + public static void SendChannelsTo( ChatUser user ) + { + for ( int i = 0; i < m_Channels.Count; ++i ) + { + Channel channel = m_Channels[i]; + + if ( !channel.IsBanned( user ) ) + ChatSystem.SendCommandTo( user.Mobile, ChatCommand.AddChannel, channel.Name, "0" ); + } + } + + public static Channel AddChannel( string name ) + { + return AddChannel( name, null ); + } + + public static Channel AddChannel( string name, string password ) + { + Channel channel = FindChannelByName( name ); + + if ( channel == null ) + { + channel = new Channel( name, password ); + m_Channels.Add( channel ); + } + + ChatUser.GlobalSendCommand( ChatCommand.AddChannel, name, "0" ) ; + + return channel; + } + + public static void RemoveChannel( string name ) + { + RemoveChannel( FindChannelByName( name ) ); + } + + public static void RemoveChannel( Channel channel ) + { + if ( channel == null ) + return; + + if ( m_Channels.Contains( channel ) && channel.m_Users.Count == 0 ) + { + ChatUser.GlobalSendCommand( ChatCommand.RemoveChannel, channel.Name ) ; + + channel.m_Moderators.Clear(); + channel.m_Voices.Clear(); + + m_Channels.Remove( channel ); + } + } + + public static Channel FindChannelByName( string name ) + { + for ( int i = 0; i < m_Channels.Count; ++i ) + { + Channel channel = m_Channels[i]; + + if ( channel.m_Name == name ) + return channel; + } + + return null; + } + + public static void Initialize() + { + AddStaticChannel( "Newbie Help" ); + } + + public static void AddStaticChannel( string name ) + { + AddChannel( name ).AlwaysAvailable = true; + } + } +} diff --git a/Scripts/Engines/Chat/Chat.cs b/Scripts/Engines/Chat/Chat.cs new file mode 100644 index 0000000..1d77c83 --- /dev/null +++ b/Scripts/Engines/Chat/Chat.cs @@ -0,0 +1,174 @@ +using System; +using Server; +using Server.Misc; +using Server.Network; +using Server.Accounting; + +namespace Server.Engines.Chat +{ + public class ChatSystem + { + private static bool m_Enabled = true; + + public static bool Enabled + { + get{ return m_Enabled; } + set{ m_Enabled = value; } + } + + public static void Initialize() + { + PacketHandlers.Register( 0xB5, 0x40, true, new OnPacketReceive( OpenChatWindowRequest ) ); + PacketHandlers.Register( 0xB3, 0, true, new OnPacketReceive( ChatAction ) ); + } + + public static void SendCommandTo( Mobile to, ChatCommand type ) + { + SendCommandTo( to, type, null, null ); + } + + public static void SendCommandTo( Mobile to, ChatCommand type, string param1 ) + { + SendCommandTo( to, type, param1, null ); + } + + public static void SendCommandTo( Mobile to, ChatCommand type, string param1, string param2 ) + { + if ( to != null ) + to.Send( new ChatMessagePacket( null, (int)type + 20, param1, param2 ) ); + } + + public static void OpenChatWindowRequest( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + if ( !m_Enabled ) + { + from.SendMessage( "The chat system has been disabled." ); + return; + } + + pvSrc.Seek( 2, System.IO.SeekOrigin.Begin ); + string chatName = pvSrc.ReadUnicodeStringSafe( ( 0x40 - 2 ) >> 1 ).Trim(); + + Account acct = state.Account as Account; + + string accountChatName = null; + + if ( acct != null ) + accountChatName = acct.GetTag( "ChatName" ); + + if ( accountChatName != null ) + accountChatName = accountChatName.Trim(); + + if ( accountChatName != null && accountChatName.Length > 0 ) + { + if ( chatName.Length > 0 && chatName != accountChatName ) + from.SendMessage( "You cannot change chat nickname once it has been set." ); + } + else + { + if ( chatName == null || chatName.Length == 0 ) + { + SendCommandTo( from, ChatCommand.AskNewNickname ); + return; + } + + if ( NameVerification.Validate( chatName, 2, 31, true, true, true, 0, NameVerification.SpaceDashPeriodQuote ) && chatName.ToLower().IndexOf( "system" ) == -1 ) + { + // TODO: Optimize this search + + foreach ( Account checkAccount in Accounts.GetAccounts() ) + { + string existingName = checkAccount.GetTag( "ChatName" ); + + if ( existingName != null ) + { + existingName = existingName.Trim(); + + if ( Insensitive.Equals( existingName, chatName ) ) + { + from.SendMessage( "Nickname already in use." ); + SendCommandTo( from, ChatCommand.AskNewNickname ); + return; + } + } + } + + accountChatName = chatName; + + if ( acct != null ) + acct.AddTag( "ChatName", chatName ); + } + else + { + from.SendLocalizedMessage( 501173 ); // That name is disallowed. + SendCommandTo( from, ChatCommand.AskNewNickname ); + return; + } + } + + SendCommandTo( from, ChatCommand.OpenChatWindow, accountChatName ); + ChatUser.AddChatUser( from ); + } + + public static ChatUser SearchForUser( ChatUser from, string name ) + { + ChatUser user = ChatUser.GetChatUser( name ); + + if ( user == null ) + from.SendMessage( 32, name ); // There is no player named '%1'. + + return user; + } + + public static void ChatAction( NetState state, PacketReader pvSrc ) + { + if ( !m_Enabled ) + return; + + try + { + Mobile from = state.Mobile; + ChatUser user = ChatUser.GetChatUser( from ); + + if ( user == null ) + return; + + string lang = pvSrc.ReadStringSafe( 4 ); + int actionID = pvSrc.ReadInt16(); + string param = pvSrc.ReadUnicodeString(); + + ChatActionHandler handler = ChatActionHandlers.GetHandler( actionID ); + + if ( handler != null ) + { + Channel channel = user.CurrentChannel; + + if ( handler.RequireConference && channel == null ) + { + user.SendMessage( 31 ); /* You must be in a conference to do this. + * To join a conference, select one from the Conference menu. + */ + } + else if ( handler.RequireModerator && !user.IsModerator ) + { + user.SendMessage( 29 ); // You must have operator status to do this. + } + else + { + handler.Callback( user, channel, param ); + } + } + else + { + Console.WriteLine( "Client: {0}: Unknown chat action 0x{1:X}: {2}", state, actionID, param ); + } + } + catch ( Exception e ) + { + Console.WriteLine( e ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/ChatActionHandler.cs b/Scripts/Engines/Chat/ChatActionHandler.cs new file mode 100644 index 0000000..8ff9326 --- /dev/null +++ b/Scripts/Engines/Chat/ChatActionHandler.cs @@ -0,0 +1,24 @@ +using System; + +namespace Server.Engines.Chat +{ + public delegate void OnChatAction( ChatUser from, Channel channel, string param ); + + public class ChatActionHandler + { + private bool m_RequireModerator; + private bool m_RequireConference; + private OnChatAction m_Callback; + + public bool RequireModerator{ get{ return m_RequireModerator; } } + public bool RequireConference{ get{ return m_RequireConference; } } + public OnChatAction Callback{ get{ return m_Callback; } } + + public ChatActionHandler( bool requireModerator, bool requireConference, OnChatAction callback ) + { + m_RequireModerator = requireModerator; + m_RequireConference = requireConference; + m_Callback = callback; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/ChatActionHandlers.cs b/Scripts/Engines/Chat/ChatActionHandlers.cs new file mode 100644 index 0000000..2b1d1e0 --- /dev/null +++ b/Scripts/Engines/Chat/ChatActionHandlers.cs @@ -0,0 +1,359 @@ +using System; + +namespace Server.Engines.Chat +{ + public class ChatActionHandlers + { + private static ChatActionHandler[] m_Handlers; + + static ChatActionHandlers() + { + m_Handlers = new ChatActionHandler[0x100]; + + Register( 0x41, true, true, new OnChatAction( ChangeChannelPassword ) ); + + Register( 0x58, false, false, new OnChatAction( LeaveChat ) ); + + Register( 0x61, false, true, new OnChatAction( ChannelMessage ) ); + Register( 0x62, false, false, new OnChatAction( JoinChannel ) ); + Register( 0x63, false, false, new OnChatAction( JoinNewChannel ) ); + Register( 0x64, true, true, new OnChatAction( RenameChannel ) ); + Register( 0x65, false, false, new OnChatAction( PrivateMessage ) ); + Register( 0x66, false, false, new OnChatAction( AddIgnore ) ); + Register( 0x67, false, false, new OnChatAction( RemoveIgnore ) ); + Register( 0x68, false, false, new OnChatAction( ToggleIgnore ) ); + Register( 0x69, true, true, new OnChatAction( AddVoice ) ); + Register( 0x6A, true, true, new OnChatAction( RemoveVoice ) ); + Register( 0x6B, true, true, new OnChatAction( ToggleVoice ) ); + Register( 0x6C, true, true, new OnChatAction( AddModerator ) ); + Register( 0x6D, true, true, new OnChatAction( RemoveModerator ) ); + Register( 0x6E, true, true, new OnChatAction( ToggleModerator ) ); + Register( 0x6F, false, false, new OnChatAction( AllowPrivateMessages ) ); + Register( 0x70, false, false, new OnChatAction( DisallowPrivateMessages ) ); + Register( 0x71, false, false, new OnChatAction( TogglePrivateMessages ) ); + Register( 0x72, false, false, new OnChatAction( ShowCharacterName ) ); + Register( 0x73, false, false, new OnChatAction( HideCharacterName ) ); + Register( 0x74, false, false, new OnChatAction( ToggleCharacterName ) ); + Register( 0x75, false, false, new OnChatAction( QueryWhoIs ) ); + Register( 0x76, true, true, new OnChatAction( Kick ) ); + Register( 0x77, true, true, new OnChatAction( EnableDefaultVoice ) ); + Register( 0x78, true, true, new OnChatAction( DisableDefaultVoice ) ); + Register( 0x79, true, true, new OnChatAction( ToggleDefaultVoice ) ); + Register( 0x7A, false, true, new OnChatAction( EmoteMessage ) ); + } + + public static void Register( int actionID, bool requireModerator, bool requireConference, OnChatAction callback ) + { + if ( actionID >= 0 && actionID < m_Handlers.Length ) + m_Handlers[actionID] = new ChatActionHandler( requireModerator, requireConference, callback ); + } + + public static ChatActionHandler GetHandler( int actionID ) + { + if ( actionID >= 0 && actionID < m_Handlers.Length ) + return m_Handlers[actionID]; + + return null; + } + + public static void ChannelMessage( ChatUser from, Channel channel, string param ) + { + if ( channel.CanTalk( from ) ) + channel.SendIgnorableMessage( 57, from, from.GetColorCharacter() + from.Username, param ); // %1: %2 + else + from.SendMessage( 36 ); // The moderator of this conference has not given you speaking priviledges. + } + + public static void EmoteMessage( ChatUser from, Channel channel, string param ) + { + if ( channel.CanTalk( from ) ) + channel.SendIgnorableMessage( 58, from, from.GetColorCharacter() + from.Username, param ); // %1 %2 + else + from.SendMessage( 36 ); // The moderator of this conference has not given you speaking priviledges. + } + + public static void PrivateMessage( ChatUser from, Channel channel, string param ) + { + int indexOf = param.IndexOf( ' ' ); + + string name = param.Substring( 0, indexOf ); + string text = param.Substring( indexOf + 1 ); + + ChatUser target = ChatSystem.SearchForUser( from, name ); + + if ( target == null ) + return; + + if ( target.IsIgnored( from ) ) + from.SendMessage( 35, target.Username ); // %1 has chosen to ignore you. None of your messages to them will get through. + else if ( target.IgnorePrivateMessage ) + from.SendMessage( 42, target.Username ); // %1 has chosen to not receive private messages at the moment. + else + target.SendMessage( 59, from.Mobile, from.GetColorCharacter() + from.Username, text ); // [%1]: %2 + } + + public static void LeaveChat( ChatUser from, Channel channel, string param ) + { + ChatUser.RemoveChatUser( from ); + } + + public static void ChangeChannelPassword( ChatUser from, Channel channel, string param ) + { + channel.Password = param; + from.SendMessage( 60 ); // The password to the conference has been changed. + } + + public static void AllowPrivateMessages( ChatUser from, Channel channel, string param ) + { + from.IgnorePrivateMessage = false; + from.SendMessage( 37 ); // You can now receive private messages. + } + + public static void DisallowPrivateMessages( ChatUser from, Channel channel, string param ) + { + from.IgnorePrivateMessage = true; + from.SendMessage( 38 ); /* You will no longer receive private messages. + * Those who send you a message will be notified that you are blocking incoming messages. + */ + } + + public static void TogglePrivateMessages( ChatUser from, Channel channel, string param ) + { + from.IgnorePrivateMessage = !from.IgnorePrivateMessage; + from.SendMessage( from.IgnorePrivateMessage ? 38 : 37 ); // See above for messages + } + + public static void ShowCharacterName( ChatUser from, Channel channel, string param ) + { + from.Anonymous = false; + from.SendMessage( 39 ); // You are now showing your character name to any players who inquire with the whois command. + } + + public static void HideCharacterName( ChatUser from, Channel channel, string param ) + { + from.Anonymous = true; + from.SendMessage( 40 ); // You are no longer showing your character name to any players who inquire with the whois command. + } + + public static void ToggleCharacterName( ChatUser from, Channel channel, string param ) + { + from.Anonymous = !from.Anonymous; + from.SendMessage( from.Anonymous ? 40 : 39 ); // See above for messages + } + + public static void JoinChannel( ChatUser from, Channel channel, string param ) + { + string name; + string password = null; + + int start = param.IndexOf( '\"' ); + + if ( start >= 0 ) + { + int end = param.IndexOf( '\"', ++start ); + + if ( end >= 0 ) + { + name = param.Substring( start, end - start ); + password = param.Substring( ++end ); + } + else + { + name = param.Substring( start ); + } + } + else + { + int indexOf = param.IndexOf( ' ' ); + + if ( indexOf >= 0 ) + { + name = param.Substring( 0, indexOf++ ); + password = param.Substring( indexOf ); + } + else + { + name = param; + } + } + + if ( password != null ) + password = password.Trim(); + + if ( password != null && password.Length == 0 ) + password = null; + + Channel joined = Channel.FindChannelByName( name ); + + if ( joined == null ) + from.SendMessage( 33, name ); // There is no conference named '%1'. + else + joined.AddUser( from, password ); + } + + public static void JoinNewChannel( ChatUser from, Channel channel, string param ) + { + if ( (param = param.Trim()).Length == 0 ) + return; + + string name; + string password = null; + + int start = param.IndexOf( '{' ); + + if ( start >= 0 ) + { + name = param.Substring( 0, start++ ); + + int end = param.IndexOf( '}', start ); + + if ( end >= start ) + password = param.Substring( start, end - start ); + } + else + { + name = param; + } + + if ( password != null ) + password = password.Trim(); + + if ( password != null && password.Length == 0 ) + password = null; + + Channel.AddChannel( name, password ).AddUser( from, password ); + } + + public static void AddIgnore( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target == null ) + return; + + from.AddIgnored( target ); + } + + public static void RemoveIgnore( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target == null ) + return; + + from.RemoveIgnored( target ); + } + + public static void ToggleIgnore( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target == null ) + return; + + if ( from.IsIgnored( target ) ) + from.RemoveIgnored( target ); + else + from.AddIgnored( target ); + } + + public static void AddVoice( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target != null ) + channel.AddVoiced( target, from ); + } + + public static void RemoveVoice( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target != null ) + channel.RemoveVoiced( target, from ); + } + + public static void ToggleVoice( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target == null ) + return; + + if ( channel.IsVoiced( target ) ) + channel.RemoveVoiced( target, from ); + else + channel.AddVoiced( target, from ); + } + + public static void AddModerator( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target != null ) + channel.AddModerator( target, from ); + } + + public static void RemoveModerator( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target != null ) + channel.RemoveModerator( target, from ); + } + + public static void ToggleModerator( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target == null ) + return; + + if ( channel.IsModerator( target ) ) + channel.RemoveModerator( target, from ); + else + channel.AddModerator( target, from ); + } + + public static void RenameChannel( ChatUser from, Channel channel, string param ) + { + channel.Name = param; + } + + public static void QueryWhoIs( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target == null ) + return; + + if ( target.Anonymous ) + from.SendMessage( 41, target.Username ); // %1 is remaining anonymous. + else + from.SendMessage( 43, target.Username, target.Mobile.Name ); // %2 is known in the lands of Britannia as %2. + } + + public static void Kick( ChatUser from, Channel channel, string param ) + { + ChatUser target = ChatSystem.SearchForUser( from, param ); + + if ( target != null ) + channel.Kick( target, from ); + } + + public static void EnableDefaultVoice( ChatUser from, Channel channel, string param ) + { + channel.VoiceRestricted = false; + } + + public static void DisableDefaultVoice( ChatUser from, Channel channel, string param ) + { + channel.VoiceRestricted = true; + } + + public static void ToggleDefaultVoice( ChatUser from, Channel channel, string param ) + { + channel.VoiceRestricted = !channel.VoiceRestricted; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/ChatCommand.cs b/Scripts/Engines/Chat/ChatCommand.cs new file mode 100644 index 0000000..ab03746 --- /dev/null +++ b/Scripts/Engines/Chat/ChatCommand.cs @@ -0,0 +1,44 @@ +using System; + +namespace Server.Engines.Chat +{ + public enum ChatCommand + { + /// + /// Add a channel to top list. + /// + AddChannel = 0x3E8, + /// + /// Remove channel from top list. + /// + RemoveChannel = 0x3E9, + /// + /// Queries for a new chat nickname. + /// + AskNewNickname = 0x3EB, + /// + /// Closes the chat window. + /// + CloseChatWindow = 0x3EC, + /// + /// Opens the chat window. + /// + OpenChatWindow = 0x3ED, + /// + /// Add a user to current channel. + /// + AddUserToChannel = 0x3EE, + /// + /// Remove a user from current channel. + /// + RemoveUserFromChannel = 0x3EF, + /// + /// Send a message putting generic conference name at top when player leaves a channel. + /// + LeaveChannel = 0x3F0, + /// + /// Send a message putting Channel name at top and telling player he joined the channel. + /// + JoinedChannel = 0x3F1 + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/ChatUser.cs b/Scripts/Engines/Chat/ChatUser.cs new file mode 100644 index 0000000..a5d4496 --- /dev/null +++ b/Scripts/Engines/Chat/ChatUser.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Accounting; + +namespace Server.Engines.Chat +{ + public class ChatUser + { + private Mobile m_Mobile; + private Channel m_Channel; + private bool m_Anonymous; + private bool m_IgnorePrivateMessage; + private List m_Ignored, m_Ignoring; + + public ChatUser( Mobile m ) + { + m_Mobile = m; + m_Ignored = new List(); + m_Ignoring = new List(); + } + + public Mobile Mobile + { + get + { + return m_Mobile; + } + } + + public List Ignored + { + get + { + return m_Ignored; + } + } + + public List Ignoring + { + get + { + return m_Ignoring; + } + } + + public string Username + { + get + { + Account acct = m_Mobile.Account as Account; + + if ( acct != null ) + return acct.GetTag( "ChatName" ); + + return null; + } + set + { + Account acct = m_Mobile.Account as Account; + + if ( acct != null ) + acct.SetTag( "ChatName", value ); + } + } + + public Channel CurrentChannel + { + get + { + return m_Channel; + } + set + { + m_Channel = value; + } + } + + public bool IsOnline + { + get + { + return ( m_Mobile.NetState != null ); + } + } + + public bool Anonymous + { + get + { + return m_Anonymous; + } + set + { + m_Anonymous = value; + } + } + + public bool IgnorePrivateMessage + { + get + { + return m_IgnorePrivateMessage; + } + set + { + m_IgnorePrivateMessage = value; + } + } + + public const char NormalColorCharacter = '0'; + public const char ModeratorColorCharacter = '1'; + public const char VoicedColorCharacter = '2'; + + public char GetColorCharacter() + { + if ( m_Channel != null && m_Channel.IsModerator( this ) ) + return ModeratorColorCharacter; + + if ( m_Channel != null && m_Channel.IsVoiced( this ) ) + return VoicedColorCharacter; + + return NormalColorCharacter; + } + + public bool CheckOnline() + { + if ( IsOnline ) + return true; + + RemoveChatUser( this ); + return false; + } + + public void SendMessage( int number ) + { + SendMessage( number, null, null ); + } + + public void SendMessage( int number, string param1 ) + { + SendMessage( number, param1, null ); + } + + public void SendMessage( int number, string param1, string param2 ) + { + if ( m_Mobile.NetState != null ) + m_Mobile.Send( new ChatMessagePacket( m_Mobile, number, param1, param2 ) ); + } + + public void SendMessage( int number, Mobile from, string param1, string param2 ) + { + if ( m_Mobile.NetState != null ) + m_Mobile.Send( new ChatMessagePacket( from, number, param1, param2 ) ); + } + + public bool IsIgnored( ChatUser check ) + { + return m_Ignored.Contains( check ); + } + + public bool IsModerator + { + get + { + return ( m_Channel != null && m_Channel.IsModerator( this ) ); + } + } + + public void AddIgnored( ChatUser user ) + { + if ( IsIgnored( user ) ) + { + SendMessage( 22, user.Username ); // You are already ignoring %1. + } + else + { + m_Ignored.Add( user ); + user.m_Ignoring.Add( this ); + + SendMessage( 23, user.Username ); // You are now ignoring %1. + } + } + + public void RemoveIgnored( ChatUser user ) + { + if ( IsIgnored( user ) ) + { + m_Ignored.Remove( user ); + user.m_Ignoring.Remove( this ); + + SendMessage( 24, user.Username ); // You are no longer ignoring %1. + + if ( m_Ignored.Count == 0 ) + SendMessage( 26 ); // You are no longer ignoring anyone. + } + else + { + SendMessage( 25, user.Username ); // You are not ignoring %1. + } + } + + private static List m_Users = new List(); + private static Dictionary m_Table = new Dictionary(); + + public static ChatUser AddChatUser( Mobile from ) + { + ChatUser user = GetChatUser( from ); + + if ( user == null ) + { + user = new ChatUser( from ); + + m_Users.Add( user ); + m_Table[from] = user; + + Channel.SendChannelsTo( user ); + + List list = Channel.Channels; + + for ( int i = 0; i < list.Count; ++i ) + { + Channel c = list[i]; + + if ( c.AddUser( user ) ) + break; + } + + //ChatSystem.SendCommandTo( user.m_Mobile, ChatCommand.AddUserToChannel, user.GetColorCharacter() + user.Username ); + } + + return user; + } + + public static void RemoveChatUser( ChatUser user ) + { + if ( user == null ) + return; + + for ( int i = 0; i < user.m_Ignoring.Count; ++i ) + user.m_Ignoring[i].RemoveIgnored( user ); + + if ( m_Users.Contains( user ) ) + { + ChatSystem.SendCommandTo( user.Mobile, ChatCommand.CloseChatWindow ); + + if ( user.m_Channel != null ) + user.m_Channel.RemoveUser( user ); + + m_Users.Remove( user ); + m_Table.Remove( user.m_Mobile ); + } + } + + public static void RemoveChatUser( Mobile from ) + { + ChatUser user = GetChatUser( from ); + + RemoveChatUser( user ); + } + + public static ChatUser GetChatUser( Mobile from ) + { + ChatUser c; + m_Table.TryGetValue( from, out c ); + return c; + } + + public static ChatUser GetChatUser( string username ) + { + for ( int i = 0; i < m_Users.Count; ++i ) + { + ChatUser user = m_Users[i]; + + if ( user.Username == username ) + return user; + } + + return null; + } + + public static void GlobalSendCommand( ChatCommand command ) + { + GlobalSendCommand( command, null, null, null ); + } + + public static void GlobalSendCommand( ChatCommand command, string param1 ) + { + GlobalSendCommand( command, null, param1, null ); + } + + public static void GlobalSendCommand( ChatCommand command, string param1, string param2 ) + { + GlobalSendCommand( command, null, param1, param2 ); + } + + public static void GlobalSendCommand( ChatCommand command, ChatUser initiator ) + { + GlobalSendCommand( command, initiator, null, null ); + } + + public static void GlobalSendCommand( ChatCommand command, ChatUser initiator, string param1 ) + { + GlobalSendCommand( command, initiator, param1, null ); + } + + public static void GlobalSendCommand( ChatCommand command, ChatUser initiator, string param1, string param2 ) + { + for ( int i = 0; i < m_Users.Count; ++i ) + { + ChatUser user = m_Users[i]; + + if ( user == initiator ) + continue; + + if ( user.CheckOnline() ) + ChatSystem.SendCommandTo( user.m_Mobile, command, param1, param2 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/Chatold.cs b/Scripts/Engines/Chat/Chatold.cs new file mode 100644 index 0000000..55cbbcd --- /dev/null +++ b/Scripts/Engines/Chat/Chatold.cs @@ -0,0 +1,20 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Chat +{ + public class ChatSystem + { + public static void Initialize() + { + EventSink.ChatRequest += new ChatRequestEventHandler( EventSink_ChatRequest ); + } + + private static void EventSink_ChatRequest( ChatRequestEventArgs e ) + { + e.Mobile.SendMessage( "Chat is not currently supported." ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Chat/Packets.cs b/Scripts/Engines/Chat/Packets.cs new file mode 100644 index 0000000..f172ae1 --- /dev/null +++ b/Scripts/Engines/Chat/Packets.cs @@ -0,0 +1,30 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Engines.Chat +{ + public sealed class ChatMessagePacket : Packet + { + public ChatMessagePacket( Mobile who, int number, string param1, string param2 ) : base( 0xB2 ) + { + if ( param1 == null ) + param1 = String.Empty; + + if ( param2 == null ) + param2 = String.Empty; + + EnsureCapacity( 13 + ((param1.Length + param2.Length) * 2) ); + + m_Stream.Write( (ushort) (number - 20) ); + + if ( who != null ) + m_Stream.WriteAsciiFixed( who.Language, 4 ); + else + m_Stream.Write( (int) 0 ); + + m_Stream.WriteBigUniNull( param1 ); + m_Stream.WriteBigUniNull( param2 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/AcceptDuelGump.cs b/Scripts/Engines/ConPVP/AcceptDuelGump.cs new file mode 100644 index 0000000..d5eaf04 --- /dev/null +++ b/Scripts/Engines/ConPVP/AcceptDuelGump.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Engines.ConPVP +{ + public class AcceptDuelGump : Gump + { + private Mobile m_Challenger, m_Challenged; + private DuelContext m_Context; + private Participant m_Participant; + private int m_Slot; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private const int LabelColor32 = 0xFFFFFF; + private const int BlackColor32 = 0x000008; + + private bool m_Active = true; + + public AcceptDuelGump( Mobile challenger, Mobile challenged, DuelContext context, Participant p, int slot ) : base( 50, 50 ) + { + m_Challenger = challenger; + m_Challenged = challenged; + m_Context = context; + m_Participant = p; + m_Slot = slot; + + challenged.CloseGump( typeof( AcceptDuelGump ) ); + + Closable = false; + + AddPage( 0 ); + + //AddBackground( 0, 0, 400, 220, 9150 ); + AddBackground( 1, 1, 398, 218, 3600 ); + //AddBackground( 16, 15, 369, 189, 9100 ); + + AddImageTiled( 16, 15, 369, 189, 3604 ); + AddAlphaRegion( 16, 15, 369, 189 ); + + AddImage( 215, -43, 0xEE40 ); + //AddImage( 330, 141, 0x8BA ); + + AddHtml( 22-1, 22, 294, 20, Color( Center( "Duel Challenge" ), BlackColor32 ), false, false ); + AddHtml( 22+1, 22, 294, 20, Color( Center( "Duel Challenge" ), BlackColor32 ), false, false ); + AddHtml( 22, 22-1, 294, 20, Color( Center( "Duel Challenge" ), BlackColor32 ), false, false ); + AddHtml( 22, 22+1, 294, 20, Color( Center( "Duel Challenge" ), BlackColor32 ), false, false ); + AddHtml( 22, 22, 294, 20, Color( Center( "Duel Challenge" ), LabelColor32 ), false, false ); + + string fmt; + + if ( p.Contains( challenger ) ) + fmt = "You have been asked to join sides with {0} in a duel. Do you accept?"; + else + fmt = "You have been challenged to a duel from {0}. Do you accept?"; + + AddHtml( 22-1, 50, 294, 40, Color( String.Format( fmt, challenger.Name ), BlackColor32 ), false, false ); + AddHtml( 22+1, 50, 294, 40, Color( String.Format( fmt, challenger.Name ), BlackColor32 ), false, false ); + AddHtml( 22, 50-1, 294, 40, Color( String.Format( fmt, challenger.Name ), BlackColor32 ), false, false ); + AddHtml( 22, 50+1, 294, 40, Color( String.Format( fmt, challenger.Name ), BlackColor32 ), false, false ); + AddHtml( 22, 50, 294, 40, Color( String.Format( fmt, challenger.Name ), 0xB0C868 ), false, false ); + + AddImageTiled( 32, 88, 264, 1, 9107 ); + AddImageTiled( 42, 90, 264, 1, 9157 ); + + AddRadio( 24, 100, 9727, 9730, true, 1 ); + AddHtml( 60-1, 105, 250, 20, Color( "Yes, I will fight this duel.", BlackColor32 ), false, false ); + AddHtml( 60+1, 105, 250, 20, Color( "Yes, I will fight this duel.", BlackColor32 ), false, false ); + AddHtml( 60, 105-1, 250, 20, Color( "Yes, I will fight this duel.", BlackColor32 ), false, false ); + AddHtml( 60, 105+1, 250, 20, Color( "Yes, I will fight this duel.", BlackColor32 ), false, false ); + AddHtml( 60, 105, 250, 20, Color( "Yes, I will fight this duel.", LabelColor32 ), false, false ); + + AddRadio( 24, 135, 9727, 9730, false, 2 ); + AddHtml( 60-1, 140, 250, 20, Color( "No, I do not wish to fight.", BlackColor32 ), false, false ); + AddHtml( 60+1, 140, 250, 20, Color( "No, I do not wish to fight.", BlackColor32 ), false, false ); + AddHtml( 60, 140-1, 250, 20, Color( "No, I do not wish to fight.", BlackColor32 ), false, false ); + AddHtml( 60, 140+1, 250, 20, Color( "No, I do not wish to fight.", BlackColor32 ), false, false ); + AddHtml( 60, 140, 250, 20, Color( "No, I do not wish to fight.", LabelColor32 ), false, false ); + + AddRadio( 24, 170, 9727, 9730, false, 3 ); + AddHtml( 60-1, 175, 250, 20, Color( "No, knave. Do not ask again.", BlackColor32 ), false, false ); + AddHtml( 60+1, 175, 250, 20, Color( "No, knave. Do not ask again.", BlackColor32 ), false, false ); + AddHtml( 60, 175-1, 250, 20, Color( "No, knave. Do not ask again.", BlackColor32 ), false, false ); + AddHtml( 60, 175+1, 250, 20, Color( "No, knave. Do not ask again.", BlackColor32 ), false, false ); + AddHtml( 60, 175, 250, 20, Color( "No, knave. Do not ask again.", LabelColor32 ), false, false ); + + AddButton( 314, 173, 247, 248, 1, GumpButtonType.Reply, 0 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), new TimerCallback( AutoReject ) ); + } + + public void AutoReject() + { + if ( !m_Active ) + return; + + m_Active = false; + + m_Challenged.CloseGump( typeof( AcceptDuelGump ) ); + + m_Challenger.SendMessage( "{0} seems unresponsive.", m_Challenged.Name ); + m_Challenged.SendMessage( "You decline the challenge." ); + } + + private static Hashtable m_IgnoreLists = new Hashtable(); + + private class IgnoreEntry + { + public Mobile m_Ignored; + public DateTime m_Expire; + + public Mobile Ignored{ get{ return m_Ignored; } } + public bool Expired{ get{ return ( DateTime.Now >= m_Expire ); } } + + private static TimeSpan ExpireDelay = TimeSpan.FromMinutes( 15.0 ); + + public void Refresh() + { + m_Expire = DateTime.Now + ExpireDelay; + } + + public IgnoreEntry( Mobile ignored ) + { + m_Ignored = ignored; + Refresh(); + } + } + + public static void BeginIgnore( Mobile source, Mobile toIgnore ) + { + ArrayList list = (ArrayList)m_IgnoreLists[source]; + + if ( list == null ) + m_IgnoreLists[source] = list = new ArrayList(); + + for ( int i = 0; i < list.Count; ++i ) + { + IgnoreEntry ie = (IgnoreEntry)list[i]; + + if ( ie.Ignored == toIgnore ) + { + ie.Refresh(); + return; + } + else if ( ie.Expired ) + { + list.RemoveAt( i-- ); + } + } + + list.Add( new IgnoreEntry( toIgnore ) ); + } + + public static bool IsIgnored( Mobile source, Mobile check ) + { + ArrayList list = (ArrayList)m_IgnoreLists[source]; + + if ( list == null ) + return false; + + for ( int i = 0; i < list.Count; ++i ) + { + IgnoreEntry ie = (IgnoreEntry)list[i]; + + if ( ie.Expired ) + list.RemoveAt( i-- ); + else if ( ie.Ignored == check ) + return true; + } + + return false; + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID != 1 || !m_Active || !m_Context.Registered ) + return; + + m_Active = false; + + if ( !m_Context.Participants.Contains( m_Participant ) ) + return; + + if ( info.IsSwitched( 1 ) ) + { + PlayerMobile pm = m_Challenged as PlayerMobile; + + if ( pm == null ) + return; + + if ( pm.DuelContext != null ) + { + if ( pm.DuelContext.Initiator == pm ) + pm.SendMessage( 0x22, "You have already started a duel." ); + else + pm.SendMessage( 0x22, "You have already been challenged in a duel." ); + + m_Challenger.SendMessage( "{0} cannot fight because they are already assigned to another duel.", pm.Name ); + } + else if ( DuelContext.CheckCombat( pm ) ) + { + pm.SendMessage( 0x22, "You have recently been in combat with another player and must wait before starting a duel." ); + m_Challenger.SendMessage( "{0} cannot fight because they have recently been in combat with another player.", pm.Name ); + } + else if ( TournamentController.IsActive ) + { + pm.SendMessage( 0x22, "A tournament is currently active and you may not duel." ); + m_Challenger.SendMessage( 0x22, "A tournament is currently active and you may not duel." ); + } + else + { + bool added = false; + + if ( m_Slot >= 0 && m_Slot < m_Participant.Players.Length && m_Participant.Players[m_Slot] == null ) + { + added = true; + m_Participant.Players[m_Slot] = new DuelPlayer( m_Challenged, m_Participant ); + } + else + { + for ( int i = 0; i < m_Participant.Players.Length; ++i ) + { + if ( m_Participant.Players[i] == null ) + { + added = true; + m_Participant.Players[i] = new DuelPlayer( m_Challenged, m_Participant ); + break; + } + } + } + + if ( added ) + { + m_Challenger.SendMessage( "{0} has accepted the request.", m_Challenged.Name ); + m_Challenged.SendMessage( "You have accepted the request from {0}.", m_Challenger.Name ); + + NetState ns = m_Challenger.NetState; + + if ( ns != null ) + { + foreach ( Gump g in ns.Gumps ) + { + if ( g is ParticipantGump ) + { + ParticipantGump pg = (ParticipantGump)g; + + if ( pg.Participant == m_Participant ) + { + m_Challenger.SendGump( new ParticipantGump( m_Challenger, m_Context, m_Participant ) ); + break; + } + } + else if ( g is DuelContextGump ) + { + DuelContextGump dcg = (DuelContextGump)g; + + if ( dcg.Context == m_Context ) + { + m_Challenger.SendGump( new DuelContextGump( m_Challenger, m_Context ) ); + break; + } + } + } + } + } + else + { + m_Challenger.SendMessage( "The participant list was full and so {0} could not join.", m_Challenged.Name ); + m_Challenged.SendMessage( "The participant list was full and so you could not join the fight {1} {0}.", m_Challenger.Name, m_Participant.Contains( m_Challenger ) ? "with" : "against" ); + } + } + } + else + { + if ( info.IsSwitched( 3 ) ) + BeginIgnore( m_Challenged, m_Challenger ); + + m_Challenger.SendMessage( "{0} does not wish to fight.", m_Challenged.Name ); + m_Challenged.SendMessage( "You chose not to fight {1} {0}.", m_Challenger.Name, m_Participant.Contains( m_Challenger ) ? "with" : "against" ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Arena.cs b/Scripts/Engines/ConPVP/Arena.cs new file mode 100644 index 0000000..3ead0e0 --- /dev/null +++ b/Scripts/Engines/ConPVP/Arena.cs @@ -0,0 +1,829 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Engines.ConPVP +{ + public class ArenaController : Item + { + private Arena m_Arena; + private bool m_IsPrivate; + + [CommandProperty( AccessLevel.GameMaster )] + public Arena Arena{ get{ return m_Arena; } set{} } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsPrivate{ get{ return m_IsPrivate; } set{ m_IsPrivate = value; } } + + public override string DefaultName + { + get { return "arena controller"; } + } + + [Constructable] + public ArenaController() : base( 0x1B7A ) + { + Visible = false; + Movable = false; + + m_Arena = new Arena(); + + m_Instances.Add( this ); + } + + public override void OnDelete() + { + base.OnDelete(); + + m_Instances.Remove( this ); + m_Arena.Delete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + from.SendGump( new Gumps.PropertiesGump( from, m_Arena ) ); + } + + public ArenaController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.Write( (bool) m_IsPrivate ); + + m_Arena.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsPrivate = reader.ReadBool(); + + goto case 0; + } + case 0: + { + m_Arena = new Arena( reader ); + break; + } + } + + m_Instances.Add( this ); + } + + private static List m_Instances = new List(); + + public static List Instances{ get{ return m_Instances; } set{ m_Instances = value; } } + } + + [PropertyObject] + public class ArenaStartPoints + { + private Point3D[] m_Points; + + public Point3D[] Points{ get{ return m_Points; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D EdgeWest{ get{ return m_Points[0]; } set{ m_Points[0] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D EdgeEast{ get{ return m_Points[1]; } set{ m_Points[1] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D EdgeNorth{ get{ return m_Points[2]; } set{ m_Points[2] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D EdgeSouth{ get{ return m_Points[3]; } set{ m_Points[3] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D CornerNW{ get{ return m_Points[4]; } set{ m_Points[4] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D CornerSE{ get{ return m_Points[5]; } set{ m_Points[5] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D CornerSW{ get{ return m_Points[6]; } set{ m_Points[6] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D CornerNE{ get{ return m_Points[7]; } set{ m_Points[7] = value; } } + + public override string ToString() + { + return "..."; + } + + public ArenaStartPoints() : this( new Point3D[8] ) + { + } + + public ArenaStartPoints( Point3D[] points ) + { + m_Points = points; + } + + public ArenaStartPoints( GenericReader reader ) + { + m_Points = new Point3D[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_Points.Length; ++i ) + m_Points[i] = reader.ReadPoint3D(); + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) m_Points.Length ); + + for ( int i = 0; i < m_Points.Length; ++i ) + writer.Write( (Point3D) m_Points[i] ); + } + } + + [PropertyObject] + public class Arena : IComparable + { + private Map m_Facet; + private Rectangle2D m_Bounds; + private Rectangle2D m_Zone; + private Point3D m_Outside; + private Point3D m_Wall; + private Point3D m_GateIn; + private Point3D m_GateOut; + private ArenaStartPoints m_Points; + private bool m_Active; + private string m_Name; + + private bool m_IsGuarded; + + private Item m_Teleporter; + + private List m_Players; + + private TournamentController m_Tournament; + private Mobile m_Announcer; + + private LadderController m_Ladder; + + [CommandProperty( AccessLevel.GameMaster )] + public LadderController Ladder + { + get{ return m_Ladder; } + set{ m_Ladder = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsGuarded + { + get{ return m_IsGuarded; } + set + { + m_IsGuarded = value; + + if ( m_Region != null ) + m_Region.Disabled = !m_IsGuarded; + } + } + + public Ladder AcquireLadder() + { + if ( m_Ladder != null ) + return m_Ladder.Ladder; + + return Server.Engines.ConPVP.Ladder.Instance; + } + + [CommandProperty( AccessLevel.GameMaster )] + public TournamentController Tournament + { + get{ return m_Tournament; } + set + { + if ( m_Tournament != null ) + m_Tournament.Tournament.Arenas.Remove( this ); + + m_Tournament = value; + + if ( m_Tournament != null ) + m_Tournament.Tournament.Arenas.Add( this ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Announcer + { + get{ return m_Announcer; } + set{ m_Announcer = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Name + { + get{ return m_Name; } + set{ m_Name = value; if ( m_Active ) m_Arenas.Sort(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Map Facet + { + get{ return m_Facet; } + set + { + m_Facet = value; + + if ( m_Teleporter != null ) + m_Teleporter.Map = value; + + if ( m_Region != null ) + m_Region.Unregister(); + + if ( m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null ) + m_Region = new SafeZone( m_Zone, m_Outside, m_Facet, m_IsGuarded ); + else + m_Region = null; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Rectangle2D Bounds{ get{ return m_Bounds; } set{ m_Bounds = value; } } + + private SafeZone m_Region; + + public int Spectators + { + get + { + if ( m_Region == null ) + return 0; + + int specs = m_Region.GetPlayerCount() - m_Players.Count; + + if ( specs < 0 ) + specs = 0; + + return specs; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Rectangle2D Zone + { + get{ return m_Zone; } + set + { + m_Zone = value; + + if ( m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null ) + { + if ( m_Region != null ) + m_Region.Unregister(); + + m_Region = new SafeZone( m_Zone, m_Outside, m_Facet, m_IsGuarded ); + } + else + { + if ( m_Region != null ) + m_Region.Unregister(); + + m_Region = null; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Outside{ get{ return m_Outside; } set{ m_Outside = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D GateIn{ get{ return m_GateIn; } set{ m_GateIn = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D GateOut{ get{ return m_GateOut; } set{ m_GateOut = value; if ( m_Teleporter != null ) m_Teleporter.Location = m_GateOut; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Wall{ get{ return m_Wall; } set{ m_Wall = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsOccupied{ get{ return ( m_Players.Count > 0 ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public ArenaStartPoints Points{ get{ return m_Points; } set{} } + + public Item Teleporter{ get{ return m_Teleporter; } set{ m_Teleporter = value; } } + + public List Players{ get{ return m_Players; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get{ return m_Active; } + set + { + if ( m_Active == value ) + return; + + m_Active = value; + + if ( m_Active ) + { + m_Arenas.Add( this ); + m_Arenas.Sort(); + } + else + { + m_Arenas.Remove( this ); + } + } + } + + public void Delete() + { + Active = false; + + if ( m_Region != null ) + m_Region.Unregister(); + + m_Region = null; + } + + public override string ToString() + { + return "..."; + } + + public Point3D GetBaseStartPoint( int index ) + { + if ( index < 0 ) + index = 0; + + return m_Points.Points[index % m_Points.Points.Length]; + } + + #region Offsets & Rotation + private static Point2D[] m_EdgeOffsets = new Point2D[] + { + /* + * /\ + * /\/\ + * /\/\/\ + * \/\/\/ + * \/\/\ + * \/\/ + */ + new Point2D( 0, 0 ), + new Point2D( 0, -1 ), + new Point2D( 0, +1 ), + new Point2D( 1, 0 ), + new Point2D( 1, -1 ), + new Point2D( 1, +1 ), + new Point2D( 2, 0 ), + new Point2D( 2, -1 ), + new Point2D( 2, +1 ), + new Point2D( 3, 0 ) + }; + + // nw corner + private static Point2D[] m_CornerOffsets = new Point2D[] + { + /* + * /\ + * /\/\ + * /\/\/\ + * /\/\/\/\ + * \/\/\/\/ + */ + new Point2D( 0, 0 ), + new Point2D( 0, 1 ), + new Point2D( 1, 0 ), + new Point2D( 1, 1 ), + new Point2D( 0, 2 ), + new Point2D( 2, 0 ), + new Point2D( 2, 1 ), + new Point2D( 1, 2 ), + new Point2D( 0, 3 ), + new Point2D( 3, 0 ) + }; + + private static int[][,] m_Rotate = new int[][,] + { + new int[,]{ { +1, 0 }, { 0, +1 } }, // west + new int[,]{ { -1, 0 }, { 0, -1 } }, // east + new int[,]{ { 0, +1 }, { +1, 0 } }, // north + new int[,]{ { 0, -1 }, { -1, 0 } }, // south + new int[,]{ { +1, 0 }, { 0, +1 } }, // nw + new int[,]{ { -1, 0 }, { 0, -1 } }, // se + new int[,]{ { 0, +1 }, { +1, 0 } }, // sw + new int[,]{ { 0, -1 }, { -1, 0 } }, // ne + }; + #endregion + + public void MoveInside( DuelPlayer[] players, int index ) + { + if ( index < 0 ) + index = 0; + else + index %= m_Points.Points.Length; + + Point3D start = GetBaseStartPoint( index ); + + int offset = 0; + + Point2D[] offsets = ( index < 4 ) ? m_EdgeOffsets : m_CornerOffsets; + int[,] matrix = m_Rotate[index]; + + for ( int i = 0; i < players.Length; ++i ) + { + DuelPlayer pl = players[i]; + + if ( pl == null ) + continue; + + Mobile mob = pl.Mobile; + + Point2D p; + + if ( offset < offsets.Length ) + p = offsets[offset++]; + else + p = offsets[offsets.Length - 1]; + + p.X = (p.X * matrix[0, 0]) + (p.Y * matrix[0, 1]); + p.Y = (p.X * matrix[1, 0]) + (p.Y * matrix[1, 1]); + + mob.MoveToWorld( new Point3D( start.X + p.X, start.Y + p.Y, start.Z ), m_Facet ); + mob.Direction = mob.GetDirectionTo( m_Wall ); + + m_Players.Add( mob ); + } + } + + public Arena() + { + m_Points = new ArenaStartPoints(); + m_Players = new List(); + } + + public Arena( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 7: + { + m_IsGuarded = reader.ReadBool(); + + goto case 6; + } + case 6: + { + m_Ladder = reader.ReadItem() as LadderController; + + goto case 5; + } + case 5: + { + m_Tournament = reader.ReadItem() as TournamentController; + m_Announcer = reader.ReadMobile(); + + goto case 4; + } + case 4: + { + m_Name = reader.ReadString(); + + goto case 3; + } + case 3: + { + m_Zone = reader.ReadRect2D(); + + goto case 2; + } + case 2: + { + m_GateIn = reader.ReadPoint3D(); + m_GateOut = reader.ReadPoint3D(); + m_Teleporter = reader.ReadItem(); + + goto case 1; + } + case 1: + { + m_Players = reader.ReadStrongMobileList(); + + goto case 0; + } + case 0: + { + m_Facet = reader.ReadMap(); + m_Bounds = reader.ReadRect2D(); + m_Outside = reader.ReadPoint3D(); + m_Wall = reader.ReadPoint3D(); + + if ( version == 0 ) + { + reader.ReadBool(); + m_Players = new List(); + } + + m_Active = reader.ReadBool(); + m_Points = new ArenaStartPoints( reader ); + + if ( m_Active ) + { + m_Arenas.Add( this ); + m_Arenas.Sort(); + } + + break; + } + } + + if ( m_Zone.Start != Point2D.Zero && m_Zone.End != Point2D.Zero && m_Facet != null ) + m_Region = new SafeZone( m_Zone, m_Outside, m_Facet, m_IsGuarded ); + + if ( IsOccupied ) + Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerCallback( Evict ) ); + + if ( m_Tournament != null ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( AttachToTournament_Sandbox ) ); + } + + private void AttachToTournament_Sandbox() + { + if ( m_Tournament != null ) + m_Tournament.Tournament.Arenas.Add( this ); + } + + [CommandProperty( AccessLevel.Administrator, AccessLevel.Administrator )] + public bool ForceEvict{ get{ return false; } set{ if ( value ) Evict(); } } + + public void Evict() + { + Point3D loc; + Map facet; + + if ( m_Facet == null ) + { + loc = new Point3D( 2715, 2165, 0 ); + facet = Map.Felucca; + } + else + { + loc = m_Outside; + facet = m_Facet; + } + + bool hasBounds = ( m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero ); + + for ( int i = 0; i < m_Players.Count; ++i ) + { + Mobile mob = m_Players[i]; + + if ( mob == null ) + continue; + + if ( mob.Map == Map.Internal ) + { + if ( (m_Facet == null || mob.LogoutMap == m_Facet) && (!hasBounds || m_Bounds.Contains( mob.LogoutLocation )) ) + mob.LogoutLocation = loc; + } + else if ( (m_Facet == null || mob.Map == m_Facet) && (!hasBounds || m_Bounds.Contains( mob.Location )) ) + { + mob.MoveToWorld( loc, facet ); + } + + mob.Combatant = null; + mob.Frozen = false; + DuelContext.Debuff( mob ); + DuelContext.CancelSpell( mob ); + } + + if ( hasBounds ) { + List pets = new List(); + + foreach ( Mobile mob in facet.GetMobilesInBounds( m_Bounds ) ) { + BaseCreature pet = mob as BaseCreature; + + if ( pet != null && pet.Controlled && pet.ControlMaster != null ) { + if ( m_Players.Contains( pet.ControlMaster ) ) { + pets.Add( pet ); + } + } + } + + foreach ( Mobile pet in pets ) { + pet.Combatant = null; + pet.Frozen = false; + + pet.MoveToWorld( loc, facet ); + } + } + + m_Players.Clear(); + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 7 ); + + writer.Write( (bool) m_IsGuarded ); + + writer.Write( (Item) m_Ladder ); + + writer.Write( (Item) m_Tournament ); + writer.Write( (Mobile) m_Announcer ); + + writer.Write( (string) m_Name ); + + writer.Write( (Rectangle2D) m_Zone ); + + writer.Write( (Point3D) m_GateIn ); + writer.Write( (Point3D) m_GateOut ); + writer.Write( (Item) m_Teleporter ); + + writer.Write( m_Players ); + + writer.Write( (Map) m_Facet ); + writer.Write( (Rectangle2D) m_Bounds ); + writer.Write( (Point3D) m_Outside ); + writer.Write( (Point3D) m_Wall ); + writer.Write( (bool) m_Active ); + + m_Points.Serialize( writer ); + } + + private static List m_Arenas = new List(); + + public static List Arenas{ get{ return m_Arenas; } } + + public static Arena FindArena( List players ) + { + Preferences prefs = Preferences.Instance; + + if ( prefs == null ) + return FindArena(); + + if ( m_Arenas.Count == 0 ) + return null; + + if ( players.Count > 0 ) + { + Mobile first = players[0]; + + List allControllers = ArenaController.Instances; + + for ( int i = 0; i < allControllers.Count; ++i ) + { + ArenaController controller = allControllers[i]; + + if ( controller != null && !controller.Deleted && controller.Arena != null && controller.IsPrivate && controller.Map == first.Map && first.InRange( controller, 24 ) ) + { + Multis.BaseHouse house = Multis.BaseHouse.FindHouseAt( controller ); + bool allNear = true; + + for ( int j = 0; j < players.Count; ++j ) + { + Mobile check = players[j]; + bool isNear; + + if ( house == null ) + isNear = ( controller.Map == check.Map && check.InRange( controller, 24 ) ); + else + isNear = ( Multis.BaseHouse.FindHouseAt( check ) == house ); + + if ( !isNear ) + { + allNear = false; + break; + } + } + + if ( allNear ) + return controller.Arena; + } + } + } + + List arenas = new List(); + + for ( int i = 0; i < m_Arenas.Count; ++i ) + { + Arena arena = m_Arenas[i]; + + if ( !arena.IsOccupied ) + arenas.Add( new ArenaEntry( arena ) ); + } + + if ( arenas.Count == 0 ) + return m_Arenas[0]; + + int tc = 0; + + for ( int i = 0; i < arenas.Count; ++i ) + { + ArenaEntry ae = arenas[i]; + + for ( int j = 0; j < players.Count; ++j ) + { + PreferencesEntry pe = prefs.Find( players[j] ); + + if ( pe.Disliked.Contains( ae.m_Arena.Name ) ) + ++ae.m_VotesAgainst; + else + ++ae.m_VotesFor; + } + + tc += ae.Value; + } + + int rn = Utility.Random( tc ); + + for ( int i = 0; i < arenas.Count; ++i ) + { + ArenaEntry ae = arenas[i]; + + if ( rn < ae.Value ) + return ae.m_Arena; + + rn -= ae.Value; + } + + return arenas[Utility.Random( arenas.Count )].m_Arena; + } + + private class ArenaEntry + { + public Arena m_Arena; + public int m_VotesFor; + public int m_VotesAgainst; + + public int Value + { + get + { + return m_VotesFor; + + /*if ( m_VotesFor > m_VotesAgainst ) + return m_VotesFor - m_VotesAgainst; + else if ( m_VotesFor > 0 ) + return 1; + else + return 0;*/ + } + } + + public ArenaEntry( Arena arena ) + { + m_Arena = arena; + } + } + + public static Arena FindArena() + { + if ( m_Arenas.Count == 0 ) + return null; + + int offset = Utility.Random( m_Arenas.Count ); + + for ( int i = 0; i < m_Arenas.Count; ++i ) + { + Arena arena = m_Arenas[(i + offset) % m_Arenas.Count]; + + if ( !arena.IsOccupied ) + return arena; + } + + return m_Arenas[offset]; + } + + public int CompareTo(object obj) + { + Arena c = (Arena)obj; + + string a = m_Name; + string b = c.m_Name; + + if ( a == null && b == null ) + return 0; + else if ( a == null ) + return -1; + else if ( b == null ) + return +1; + + return a.CompareTo( b ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/ArenaGump.cs b/Scripts/Engines/ConPVP/ArenaGump.cs new file mode 100644 index 0000000..33660a6 --- /dev/null +++ b/Scripts/Engines/ConPVP/ArenaGump.cs @@ -0,0 +1,296 @@ +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.ConPVP +{ + public class ArenasMoongate : Item + { + public override string DefaultName + { + get { return "arena moongate"; } + } + + [Constructable] + public ArenasMoongate() : base( 0x1FD4 ) + { + Movable = false; + Light = LightType.Circle300; + } + + public ArenasMoongate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + Light = LightType.Circle300; + } + + public bool UseGate( Mobile from ) + { + if ( DuelContext.CheckCombat( from ) ) + { + from.SendMessage( 0x22, "You have recently been in combat with another player and cannot use this moongate." ); + return false; + } + else if ( from.Spell != null ) + { + from.SendLocalizedMessage( 1049616 ); // You are too busy to do that at the moment. + return false; + } + else + { + from.CloseGump( typeof( ArenaGump ) ); + from.SendGump( new ArenaGump( from, this ) ); + + if ( !from.Hidden || from.AccessLevel == AccessLevel.Player ) + Effects.PlaySound( from.Location, from.Map, 0x20E ); + + return true; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 1 ) ) + UseGate( from ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that + } + + public override bool OnMoveOver( Mobile m ) + { + return ( !m.Player || UseGate( m ) ); + } + } + + public class ArenaGump : Gump + { + private Mobile m_From; + private ArenasMoongate m_Gate; + private List m_Arenas; + + private void Append( StringBuilder sb, LadderEntry le ) + { + if ( le == null ) + return; + + if ( sb.Length > 0 ) + sb.Append( ", " ); + + sb.Append( le.Mobile.Name ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID != 1 ) + return; + + int[] switches = info.Switches; + + if ( switches.Length == 0 ) + return; + + int opt = switches[0]; + + if ( opt < 0 || opt >= m_Arenas.Count ) + return; + + Arena arena = m_Arenas[opt]; + + if ( !m_From.InRange( m_Gate.GetWorldLocation(), 1 ) || m_From.Map != m_Gate.Map ) + { + m_From.SendLocalizedMessage( 1019002 ); // You are too far away to use the gate. + } + else if ( DuelContext.CheckCombat( m_From ) ) + { + m_From.SendMessage( 0x22, "You have recently been in combat with another player and cannot use this moongate." ); + } + else if ( m_From.Spell != null ) + { + m_From.SendLocalizedMessage( 1049616 ); // You are too busy to do that at the moment. + } + else if ( m_From.Map == arena.Facet && arena.Zone.Contains( m_From ) ) + { + m_From.SendLocalizedMessage( 1019003 ); // You are already there. + } + else + { + BaseCreature.TeleportPets( m_From, arena.GateIn, arena.Facet ); + + m_From.Combatant = null; + m_From.Warmode = false; + m_From.Hidden = true; + + m_From.MoveToWorld( arena.GateIn, arena.Facet ); + + Effects.PlaySound( arena.GateIn, arena.Facet, 0x1FE ); + } + } + + public ArenaGump( Mobile from, ArenasMoongate gate ) : base( 50, 50 ) + { + m_From = from; + m_Gate = gate; + m_Arenas = Arena.Arenas; + + AddPage( 0 ); + + int height = 12 + 20 + (m_Arenas.Count * 31) + 24 + 12; + + AddBackground( 0, 0, 499+40, height, 0x2436 ); + + List list = m_Arenas; + + for ( int i = 1; i < list.Count; i += 2 ) + AddImageTiled( 12, 32 + (i * 31), 475+40, 30, 0x2430 ); + + AddAlphaRegion( 10, 10, 479+40, height - 20 ); + + AddColumnHeader( 35, null ); + AddColumnHeader( 115, "Arena" ); + AddColumnHeader( 325, "Participants" ); + AddColumnHeader( 40, "Obs" ); + + AddButton( 499+40 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1, GumpButtonType.Reply, 0 ); + AddButton( 499+40 - 12 - 63, height - 12 - 24, 241, 242, 2, GumpButtonType.Reply, 0 ); + + for ( int i = 0; i < list.Count; ++i ) + { + Arena ar = list[i]; + + string name = ar.Name; + + if ( name == null ) + name = "(no name)"; + + int x = 12; + int y = 32 + (i * 31); + + int color = ( ar.Players.Count > 0 ? 0xCCFFCC : 0xCCCCCC ); + + AddRadio( x + 3, y + 1, 9727, 9730, false, i ); + x += 35; + + AddBorderedText( x + 5, y + 5, 115 - 5, name, color, 0 ); + x += 115; + + StringBuilder sb = new StringBuilder(); + + if ( ar.Players.Count > 0 ) + { + Ladder ladder = Ladder.Instance; + + if ( ladder == null ) + continue; + + LadderEntry p1 = null, p2 = null, p3 = null, p4 = null; + + for ( int j = 0; j < ar.Players.Count; ++j ) + { + Mobile mob = (Mobile)ar.Players[j]; + LadderEntry c = ladder.Find( mob ); + + if ( p1 == null || c.Index < p1.Index ) + { + p4 = p3; + p3 = p2; + p2 = p1; + p1 = c; + } + else if ( p2 == null || c.Index < p2.Index ) + { + p4 = p3; + p3 = p2; + p2 = c; + } + else if ( p3 == null || c.Index < p3.Index ) + { + p4 = p3; + p3 = c; + } + else if ( p4 == null || c.Index < p4.Index ) + { + p4 = c; + } + } + + Append( sb, p1 ); + Append( sb, p2 ); + Append( sb, p3 ); + Append( sb, p4 ); + + if ( ar.Players.Count > 4 ) + sb.Append( ", ..." ); + } + else + { + sb.Append( "Empty" ); + } + + AddBorderedText( x + 5, y + 5, 325 - 5, sb.ToString(), color, 0 ); + x += 325; + + AddBorderedText( x, y + 5, 40, Center( ar.Spectators.ToString() ), color, 0 ); + } + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private void AddBorderedText( int x, int y, int width, string text, int color, int borderColor ) + { + /*AddColoredText( x - 1, y, width, text, borderColor ); + AddColoredText( x + 1, y, width, text, borderColor ); + AddColoredText( x, y - 1, width, text, borderColor ); + AddColoredText( x, y + 1, width, text, borderColor );*/ + /*AddColoredText( x - 1, y - 1, width, text, borderColor ); + AddColoredText( x + 1, y + 1, width, text, borderColor );*/ + AddColoredText( x, y, width, text, color ); + } + + private void AddColoredText( int x, int y, int width, string text, int color ) + { + if ( color == 0 ) + AddHtml( x, y, width, 20, text, false, false ); + else + AddHtml( x, y, width, 20, Color( text, color ), false, false ); + } + + private int m_ColumnX = 12; + + private void AddColumnHeader( int width, string name ) + { + AddBackground( m_ColumnX, 12, width, 20, 0x242C ); + AddImageTiled( m_ColumnX + 2, 14, width - 4, 16, 0x2430 ); + + if ( name != null ) + AddBorderedText( m_ColumnX, 13, width, Center( name ), 0xFFFFFF, 0 ); + + m_ColumnX += width; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/BeginGump.cs b/Scripts/Engines/ConPVP/BeginGump.cs new file mode 100644 index 0000000..6b80151 --- /dev/null +++ b/Scripts/Engines/ConPVP/BeginGump.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class BeginGump : Gump + { + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private const int LabelColor32 = 0xFFFFFF; + private const int BlackColor32 = 0x000008; + + public BeginGump( int count ) : base( 50, 50 ) + { + AddPage( 0 ); + + const int offset = 50; + + AddBackground( 1, 1, 398, 202-offset, 3600 ); + + AddImageTiled( 16, 15, 369, 173-offset, 3604 ); + AddAlphaRegion( 16, 15, 369, 173-offset ); + + AddImage( 215, -43, 0xEE40 ); + + AddHtml( 22-1, 22, 294, 20, Color( Center( "Duel Countdown" ), BlackColor32 ), false, false ); + AddHtml( 22+1, 22, 294, 20, Color( Center( "Duel Countdown" ), BlackColor32 ), false, false ); + AddHtml( 22, 22-1, 294, 20, Color( Center( "Duel Countdown" ), BlackColor32 ), false, false ); + AddHtml( 22, 22+1, 294, 20, Color( Center( "Duel Countdown" ), BlackColor32 ), false, false ); + AddHtml( 22, 22, 294, 20, Color( Center( "Duel Countdown" ), LabelColor32 ), false, false ); + + AddHtml( 22-1, 50, 294, 80, Color( "The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.", BlackColor32 ), false, false ); + AddHtml( 22+1, 50, 294, 80, Color( "The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.", BlackColor32 ), false, false ); + AddHtml( 22, 50-1, 294, 80, Color( "The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.", BlackColor32 ), false, false ); + AddHtml( 22, 50+1, 294, 80, Color( "The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.", BlackColor32 ), false, false ); + AddHtml( 22, 50, 294, 80, Color( "The arranged duel is about to begin. During this countdown period you may not cast spells and you may not move. This message will close automatically when the period ends.", 0xFFCC66 ), false, false ); + + /*AddImageTiled( 32, 128, 264, 1, 9107 ); + AddImageTiled( 42, 130, 264, 1, 9157 ); + + AddHtml( 60-1, 140, 250, 20, Color( String.Format( "Duel will begin in {0} second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false ); + AddHtml( 60+1, 140, 250, 20, Color( String.Format( "Duel will begin in {0} second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false ); + AddHtml( 60, 140-1, 250, 20, Color( String.Format( "Duel will begin in {0} second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false ); + AddHtml( 60, 140+1, 250, 20, Color( String.Format( "Duel will begin in {0} second{1}.", count, count==1?"":"s", BlackColor32 ), BlackColor32 ), false, false ); + AddHtml( 60, 140, 250, 20, Color( String.Format( "Duel will begin in {0} second{1}.", count, count==1?"":"s", 0x66AACC ), 0x66AACC ), false, false );*/ + + AddButton( 314-50, 157-offset, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/DuelContext.cs b/Scripts/Engines/ConPVP/DuelContext.cs new file mode 100644 index 0000000..026bc31 --- /dev/null +++ b/Scripts/Engines/ConPVP/DuelContext.cs @@ -0,0 +1,2652 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using Server; +using Server.Commands; +using Server.Engines.PartySystem; +using Server.Factions; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Bushido; +using Server.Spells.Chivalry; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; +using Server.Spells.Spellweaving; + +namespace Server.Engines.ConPVP +{ + public delegate void CountdownCallback( int count ); + + public class DuelContext + { + private Mobile m_Initiator; + private ArrayList m_Participants; + private Ruleset m_Ruleset; + private Arena m_Arena; + private bool m_Registered = true; + private bool m_Finished, m_Started; + + private bool m_ReadyWait; + private int m_ReadyCount; + + private bool m_Rematch; + + public bool Rematch{ get{ return m_Rematch; } } + + public bool ReadyWait{ get{ return m_ReadyWait; } } + public int ReadyCount{ get{ return m_ReadyCount; } } + + public bool Registered{ get{ return m_Registered; } } + public bool Finished{ get{ return m_Finished; } } + public bool Started{ get{ return m_Started; } } + + public Mobile Initiator{ get{ return m_Initiator; } } + public ArrayList Participants{ get{ return m_Participants; } } + public Ruleset Ruleset{ get{ return m_Ruleset; } } + public Arena Arena{ get{ return m_Arena; } } + + private bool CantDoAnything( Mobile mob ) + { + if ( m_EventGame != null ) + return m_EventGame.CantDoAnything( mob ); + else + return false; + } + + public static bool IsFreeConsume( Mobile mob ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null || pm.DuelContext == null || pm.DuelContext.m_EventGame == null ) + return false; + + return pm.DuelContext.m_EventGame.FreeConsume; + } + + public void DelayBounce( TimeSpan ts, Mobile mob, Container corpse ) + { + Timer.DelayCall( ts, new TimerStateCallback( DelayBounce_Callback ), new object[]{ mob, corpse } ); + } + + public static bool AllowSpecialMove( Mobile from, string name, SpecialMove move ) + { + PlayerMobile pm = from as PlayerMobile; + + if( pm == null ) + return true; + + DuelContext dc = pm.DuelContext; + + return (dc == null || dc.InstAllowSpecialMove( from, name, move )); + } + + public bool InstAllowSpecialMove( Mobile from, string name, SpecialMove move ) + { + + if ( !m_StartedBeginCountdown ) + return true; + + DuelPlayer pl = Find( from ); + + if ( pl == null || pl.Eliminated ) + return true; + + if ( CantDoAnything( from ) ) + return false; + + string title = null; + + if( move is NinjaMove ) + title = "Bushido"; + else if( move is SamuraiMove ) + title = "Ninjitsu"; + + + if ( title == null || name == null || m_Ruleset.GetOption( title, name ) ) + return true; + + from.SendMessage( "The dueling ruleset prevents you from using this move." ); + return false; + } + + public bool AllowSpellCast( Mobile from, Spell spell ) + { + if ( !m_StartedBeginCountdown ) + return true; + + DuelPlayer pl = Find( from ); + + if ( pl == null || pl.Eliminated ) + return true; + + if ( CantDoAnything( from ) ) + return false; + + if (spell is Server.Spells.Fourth.RecallSpell) + from.SendMessage("You may not cast this spell."); + + string title = null, option = null; + + if( spell is ArcanistSpell ) + { + title = "Spellweaving"; + option = spell.Name; + } + else if ( spell is PaladinSpell ) + { + title = "Chivalry"; + option = spell.Name; + } + else if ( spell is NecromancerSpell ) + { + title = "Necromancy"; + option = spell.Name; + } + else if ( spell is NinjaSpell ) + { + title = "Ninjitsu"; + option = spell.Name; + } + else if ( spell is SamuraiSpell ) + { + title = "Bushido"; + option = spell.Name; + } + else if( spell is MagerySpell ) + { + switch( ((MagerySpell)spell).Circle ) + { + case SpellCircle.First: title = "1st Circle"; break; + case SpellCircle.Second: title = "2nd Circle"; break; + case SpellCircle.Third: title = "3rd Circle"; break; + case SpellCircle.Fourth: title = "4th Circle"; break; + case SpellCircle.Fifth: title = "5th Circle"; break; + case SpellCircle.Sixth: title = "6th Circle"; break; + case SpellCircle.Seventh: title = "7th Circle"; break; + case SpellCircle.Eighth: title = "8th Circle"; break; + } + + option = spell.Name; + } + else + { + title = "Other Spell"; + option = spell.Name; + } + + if ( title == null || option == null || m_Ruleset.GetOption( title, option ) ) + return true; + + from.SendMessage( "The dueling ruleset prevents you from casting this spell." ); + return false; + } + + public bool AllowItemEquip( Mobile from, Item item ) + { + if ( !m_StartedBeginCountdown ) + return true; + + DuelPlayer pl = Find( from ); + + if ( pl == null || pl.Eliminated ) + return true; + + if ( item is Dagger || CheckItemEquip( from, item ) ) + return true; + + from.SendMessage( "The dueling ruleset prevents you from equiping this item." ); + return false; + } + + public static bool AllowSpecialAbility( Mobile from, string name, bool message ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return true; + + DuelContext dc = pm.DuelContext; + + return ( dc == null || dc.InstAllowSpecialAbility( from, name, message ) ); + } + + public bool InstAllowSpecialAbility( Mobile from, string name, bool message ) + { + if ( !m_StartedBeginCountdown ) + return true; + + DuelPlayer pl = Find( from ); + + if ( pl == null || pl.Eliminated ) + return true; + + if ( CantDoAnything( from ) ) + return false; + + if ( m_Ruleset.GetOption( "Combat Abilities", name ) ) + return true; + + if ( message ) + from.SendMessage( "The dueling ruleset prevents you from using this combat ability." ); + + return false; + } + + public bool CheckItemEquip( Mobile from, Item item ) + { + if ( item is Fists ) + { + if ( !m_Ruleset.GetOption( "Weapons", "Wrestling" ) ) + return false; + } + else if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if ( armor.ProtectionLevel > ArmorProtectionLevel.Regular && !m_Ruleset.GetOption( "Armor", "Magical" ) ) + return false; + + if ( !Core.AOS && armor.Resource != armor.DefaultResource && !m_Ruleset.GetOption( "Armor", "Colored" ) ) + return false; + + if ( armor is BaseShield && !m_Ruleset.GetOption( "Armor", "Shields" ) ) + return false; + } + else if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( (weapon.DamageLevel > WeaponDamageLevel.Regular || weapon.AccuracyLevel > WeaponAccuracyLevel.Regular) && !m_Ruleset.GetOption( "Weapons", "Magical" ) ) + return false; + + if ( !Core.AOS && weapon.Resource != CraftResource.MIron && weapon.Resource != CraftResource.None && !m_Ruleset.GetOption( "Weapons", "Runics" ) ) + return false; + + if ( weapon is BaseRanged && !m_Ruleset.GetOption( "Weapons", "Ranged" ) ) + return false; + + if ( !(weapon is BaseRanged) && !m_Ruleset.GetOption( "Weapons", "Melee" ) ) + return false; + + if ( weapon.PoisonCharges > 0 && weapon.Poison != null && !m_Ruleset.GetOption( "Weapons", "Poisoned" ) ) + return false; + + if (weapon is BaseWand && !m_Ruleset.GetOption("Items", "Wands")) + return false; + } + + return true; + } + + public bool AllowSkillUse( Mobile from, SkillName skill ) + { + if ( !m_StartedBeginCountdown ) + return true; + + DuelPlayer pl = Find( from ); + + if ( pl == null || pl.Eliminated ) + return true; + + if ( CantDoAnything( from ) ) + return false; + + int id = (int)skill; + + if ( id >= 0 && id < SkillInfo.Table.Length ) + { + if ( m_Ruleset.GetOption( "Skills", SkillInfo.Table[id].Name ) ) + return true; + } + + from.SendMessage( "The dueling ruleset prevents you from using this skill." ); + return false; + } + + public bool AllowItemUse( Mobile from, Item item ) + { + if ( !m_StartedBeginCountdown ) + return true; + + DuelPlayer pl = Find( from ); + + if ( pl == null || pl.Eliminated ) + return true; + + if (!(item is BaseRefreshPotion)) + { + if (CantDoAnything(from)) + return false; + } + + string title = null, option = null; + + if ( item is BasePotion ) + { + title = "Potions"; + + if ( item is BaseAgilityPotion ) + option = "Agility"; + else if ( item is BaseCurePotion ) + option = "Cure"; + else if ( item is BaseHealPotion ) + option = "Heal"; + else if ( item is NightSightPotion ) + option = "Nightsight"; + else if ( item is BasePoisonPotion ) + option = "Poison"; + else if ( item is BaseStrengthPotion ) + option = "Strength"; + else if ( item is BaseExplosionPotion ) + option = "Explosion"; + else if ( item is BaseRefreshPotion ) + option = "Refresh"; + } + else if ( item is Bandage ) + { + title = "Items"; + option = "Bandages"; + } + else if ( item is TrapableContainer ) + { + if ( ((TrapableContainer)item).TrapType != TrapType.None ) + { + title = "Items"; + option = "Trapped Containers"; + } + } + else if ( item is Bola ) + { + title = "Items"; + option = "Bolas"; + } + else if ( item is OrangePetals ) + { + title = "Items"; + option = "Orange Petals"; + } + else if (item is EtherealMount || item.Layer == Layer.Mount) + { + title = "Items"; + option = "Mounts"; + } + else if ( item is LeatherNinjaBelt ) + { + title = "Items"; + option = "Shurikens"; + } + else if ( item is Fukiya ) + { + title = "Items"; + option = "Fukiya Darts"; + } + else if ( item is FireHorn ) + { + title = "Items"; + option = "Fire Horns"; + } + else if (item is BaseWand) + { + title = "Items"; + option = "Wands"; + } + + if ( title != null && option != null && m_StartedBeginCountdown && !m_Started ) + { + from.SendMessage( "You may not use this item before the duel begins." ); + return false; + } + else if ( item is BasePotion && !(item is BaseExplosionPotion) && !(item is BaseRefreshPotion) && IsSuddenDeath ) + { + from.SendMessage( 0x22, "You may not drink potions in sudden death." ); + return false; + } + else if ( item is Bandage && IsSuddenDeath ) + { + from.SendMessage( 0x22, "You may not use bandages in sudden death." ); + return false; + } + + if ( title == null || option == null || m_Ruleset.GetOption( title, option ) ) + return true; + + from.SendMessage( "The dueling ruleset prevents you from using this item." ); + return false; + } + + private void DelayBounce_Callback( object state ) + { + object[] states = (object[])state; + Mobile mob = (Mobile) states[0]; + Container corpse = (Container) states[1]; + + RemoveAggressions( mob ); + SendOutside( mob ); + Refresh( mob, corpse ); + Debuff( mob ); + CancelSpell( mob ); + mob.Frozen = false; + } + + public void OnMapChanged( Mobile mob ) + { + OnLocationChanged( mob ); + } + + public void OnLocationChanged( Mobile mob ) + { + if ( !m_Registered || !m_StartedBeginCountdown || m_Finished ) + return; + + Arena arena = m_Arena; + + if ( arena == null ) + return; + + if ( mob.Map == arena.Facet && arena.Bounds.Contains( mob.Location ) ) + return; + + DuelPlayer pl = Find( mob ); + + if ( pl == null || pl.Eliminated ) + return; + + if ( mob.Map == Map.Internal ) { + // they've logged out + + if ( mob.LogoutMap == arena.Facet && arena.Bounds.Contains( mob.LogoutLocation ) ) { + // they logged out inside the arena.. set them to eject on login + + mob.LogoutLocation = arena.Outside; + } + } + + pl.Eliminated = true; + + mob.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have forfeited your position in the duel." ); + mob.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has forfeited by leaving the dueling arena.", mob.Name ) ); + + Participant winner = CheckCompletion(); + + if ( winner != null ) + Finish( winner ); + } + + private bool m_Yielding; + + public void OnDeath( Mobile mob, Container corpse ) + { + if ( !m_Registered || !m_Started ) + return; + + DuelPlayer pl = Find( mob ); + + if ( pl != null && !pl.Eliminated ) + { + if ( m_EventGame != null && !m_EventGame.OnDeath( mob, corpse ) ) + return; + + pl.Eliminated = true; + + Requip( mob, corpse ); + DelayBounce( TimeSpan.FromSeconds( 4.0 ), mob, corpse ); + + Participant winner = CheckCompletion(); + + if ( winner != null ) + { + Finish( winner ); + } + else if ( !m_Yielding ) + { + mob.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have been defeated." ); + mob.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has been defeated.", mob.Name ) ); + } + } + } + + public bool CheckFull() + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + if ( p.HasOpenSlot ) + return false; + } + + return true; + } + + public void Requip( Mobile from, Container cont ) + { + Corpse corpse = cont as Corpse; + + if ( corpse == null ) + return; + + List items = new List( corpse.Items ); + + bool gathered = false; + bool didntFit = false; + + Container pack = from.Backpack; + + for ( int i = 0; !didntFit && i < items.Count; ++i ) + { + Item item = items[i]; + Point3D loc = item.Location; + + if ( (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) || !item.Movable ) + continue; + + if ( pack != null ) + { + pack.DropItem( item ); + gathered = true; + } + else + { + didntFit = true; + } + } + + corpse.Carved = true; + + if ( corpse.ItemID == 0x2006 ) + { + corpse.ProcessDelta(); + corpse.SendRemovePacket(); + corpse.ItemID = Utility.Random( 0xECA, 9 ); // bone graphic + corpse.Hue = 0; + corpse.ProcessDelta(); + + Mobile killer = from.FindMostRecentDamager( false ); + + if ( killer != null && killer.Player ) + killer.AddToBackpack( new Head( m_Tournament == null ? HeadType.Duel : HeadType.Tournament, from.Name ) ); + } + + from.PlaySound( 0x3E3 ); + + if ( gathered && !didntFit ) + from.SendLocalizedMessage( 1062471 ); // You quickly gather all of your belongings. + else if ( gathered && didntFit ) + from.SendLocalizedMessage( 1062472 ); // You gather some of your belongings. The rest remain on the corpse. + } + + public void Refresh( Mobile mob, Container cont ) + { + if ( !mob.Alive ) + { + mob.Resurrect(); + + DeathRobe robe = mob.FindItemOnLayer( Layer.OuterTorso ) as DeathRobe; + + if ( robe != null ) + robe.Delete(); + + if ( cont is Corpse ) + { + Corpse corpse = (Corpse) cont; + + for ( int i = 0; i < corpse.EquipItems.Count; ++i ) + { + Item item = corpse.EquipItems[i]; + + if ( item.Movable && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair && item.IsChildOf( mob.Backpack ) ) + mob.EquipItem( item ); + } + } + } + + mob.Hits = mob.HitsMax; + mob.Stam = mob.StamMax; + mob.Mana = mob.ManaMax; + + mob.Poison = null; + } + + public void SendOutside( Mobile mob ) + { + if ( m_Arena == null ) + return; + + mob.Combatant = null; + mob.MoveToWorld( m_Arena.Outside, m_Arena.Facet ); + } + + private Point3D m_GatePoint; + private Map m_GateFacet; + + public void Finish( Participant winner ) + { + if ( m_Finished ) + return; + + EndAutoTie(); + StopSDTimers(); + + m_Finished = true; + + for ( int i = 0; i < winner.Players.Length; ++i ) + { + DuelPlayer pl = winner.Players[i]; + + if ( pl != null && !pl.Eliminated ) + DelayBounce( TimeSpan.FromSeconds( 8.0 ), pl.Mobile, null ); + } + + winner.Broadcast( 0x59, null, winner.Players.Length == 1 ? "{0} has won the duel." : "{0} and {1} team have won the duel.", winner.Players.Length == 1 ? "You have won the duel." : "Your team has won the duel." ); + + if ( m_Tournament != null && winner.TournyPart != null ) + { + m_Match.Winner = winner.TournyPart; + winner.TournyPart.WonMatch( m_Match ); + m_Tournament.HandleWon( m_Arena, m_Match, winner.TournyPart ); + } + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant loser = (Participant)m_Participants[i]; + + if ( loser != winner ) + { + loser.Broadcast( 0x22, null, loser.Players.Length == 1 ? "{0} has lost the duel." : "{0} and {1} team have lost the duel.", loser.Players.Length == 1 ? "You have lost the duel." : "Your team has lost the duel." ); + + if ( m_Tournament != null && loser.TournyPart != null ) + loser.TournyPart.LostMatch( m_Match ); + } + + for ( int j = 0; j < loser.Players.Length; ++j ) + { + if ( loser.Players[j] != null ) + { + RemoveAggressions( loser.Players[j].Mobile ); + loser.Players[j].Mobile.Delta( MobileDelta.Noto ); + loser.Players[j].Mobile.CloseGump( typeof( BeginGump ) ); + + if ( m_Tournament != null ) + loser.Players[j].Mobile.SendEverything(); + } + } + } + + if ( IsOneVsOne ) + { + DuelPlayer dp1 = ((Participant)m_Participants[0]).Players[0]; + DuelPlayer dp2 = ((Participant)m_Participants[1]).Players[0]; + + if ( dp1 != null && dp2 != null ) + { + Award( dp1.Mobile, dp2.Mobile, dp1.Participant == winner ); + Award( dp2.Mobile, dp1.Mobile, dp2.Participant == winner ); + } + } + + if ( m_EventGame != null ) + m_EventGame.OnStop(); + + Timer.DelayCall( TimeSpan.FromSeconds( 9.0 ), new TimerCallback( UnregisterRematch ) ); + } + + public void Award( Mobile us, Mobile them, bool won ) + { + Ladder ladder = ( m_Arena == null ? Ladder.Instance : m_Arena.AcquireLadder() ); + + if ( ladder == null ) + return; + + LadderEntry ourEntry = ladder.Find( us ); + LadderEntry theirEntry = ladder.Find( them ); + + if ( ourEntry == null || theirEntry == null ) + return; + + int xpGain = Ladder.GetExperienceGain( ourEntry, theirEntry, won ); + + if ( xpGain == 0 ) + return; + + if ( m_Tournament != null ) + xpGain *= ( xpGain > 0 ? 5 : 2 ); + + if ( won ) + ++ourEntry.Wins; + else + ++ourEntry.Losses; + + int oldLevel = Ladder.GetLevel( ourEntry.Experience ); + + ourEntry.Experience += xpGain; + + if ( ourEntry.Experience < 0 ) + ourEntry.Experience = 0; + + ladder.UpdateEntry( ourEntry ); + + int newLevel = Ladder.GetLevel( ourEntry.Experience ); + + if ( newLevel > oldLevel ) + us.SendMessage( 0x59, "You have achieved level {0}!", newLevel ); + else if ( newLevel < oldLevel ) + us.SendMessage( 0x22, "You have lost a level. You are now at {0}.", newLevel ); + } + + public void UnregisterRematch() + { + Unregister(true); + } + + public void Unregister() + { + Unregister(false); + } + + public void Unregister( bool queryRematch ) + { + DestroyWall(); + + if ( !m_Registered ) + return; + + m_Registered = false; + + if ( m_Arena != null ) + m_Arena.Evict(); + + StopSDTimers(); + + Type[] types = new Type[]{ typeof( BeginGump ), typeof( DuelContextGump ), typeof( ParticipantGump ), typeof( PickRulesetGump ), typeof( ReadyGump ), typeof( ReadyUpGump ), typeof( RulesetGump ) }; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = (DuelPlayer)p.Players[j]; + + if ( pl == null ) + continue; + + if ( pl.Mobile is PlayerMobile ) + ((PlayerMobile)pl.Mobile).DuelPlayer = null; + + for ( int k = 0; k < types.Length; ++k ) + pl.Mobile.CloseGump( types[k] ); + } + } + + if ( queryRematch && m_Tournament == null ) + QueryRematch(); + } + + public void QueryRematch() + { + DuelContext dc = new DuelContext( m_Initiator, m_Ruleset.Layout, false ); + + dc.m_Ruleset = m_Ruleset; + dc.m_Rematch = true; + + dc.m_Participants.Clear(); + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant oldPart = (Participant)m_Participants[i]; + Participant newPart = new Participant( dc, oldPart.Players.Length ); + + for ( int j = 0; j < oldPart.Players.Length; ++j ) + { + DuelPlayer oldPlayer = oldPart.Players[j]; + + if ( oldPlayer != null ) + newPart.Players[j] = new DuelPlayer( oldPlayer.Mobile, newPart ); + } + + dc.m_Participants.Add( newPart ); + } + + dc.CloseAllGumps(); + dc.SendReadyUpGump(); + } + + public DuelPlayer Find( Mobile mob ) + { + if ( mob is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)mob; + + if ( pm.DuelContext == this ) + return pm.DuelPlayer; + + return null; + } + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + DuelPlayer pl = p.Find( mob ); + + if ( pl != null ) + return pl; + } + + return null; + } + + public bool IsAlly( Mobile m1, Mobile m2 ) + { + DuelPlayer pl1 = Find( m1 ); + DuelPlayer pl2 = Find( m2 ); + + return ( pl1 != null && pl2 != null && pl1.Participant == pl2.Participant ); + } + + public Participant CheckCompletion() + { + Participant winner = null; + + bool hasWinner = false; + int eliminated = 0; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + if ( p.Eliminated ) + { + ++eliminated; + + if ( eliminated == (m_Participants.Count - 1) ) + hasWinner = true; + } + else + { + winner = p; + } + } + + if ( hasWinner ) + return winner == null ? (Participant) m_Participants[0] : winner; + + return null; + } + + private Timer m_Countdown; + + public void StartCountdown( int count, CountdownCallback cb ) + { + cb(count); + m_Countdown=Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), count, new TimerStateCallback( Countdown_Callback ), new object[]{ count-1, cb } ); + } + + public void StopCountdown() + { + if ( m_Countdown != null ) + m_Countdown.Stop(); + + m_Countdown = null; + } + + private void Countdown_Callback( object state ) + { + object[] states = (object[])state; + + int count = (int)states[0]; + CountdownCallback cb = (CountdownCallback)states[1]; + + if ( count==0 ) + { + if ( m_Countdown != null ) + m_Countdown.Stop(); + + m_Countdown=null; + } + + cb( count ); + + states[0] = count - 1; + } + + private Timer m_AutoTieTimer; + private bool m_Tied; + + public bool Tied{ get{ return m_Tied; } } + + private bool m_IsSuddenDeath; + + public bool IsSuddenDeath{ get{ return m_IsSuddenDeath; } set{ m_IsSuddenDeath = value; } } + + private Timer m_SDWarnTimer, m_SDActivateTimer; + + public void StopSDTimers() + { + if ( m_SDWarnTimer != null ) + m_SDWarnTimer.Stop(); + + m_SDWarnTimer = null; + + if ( m_SDActivateTimer != null ) + m_SDActivateTimer.Stop(); + + m_SDActivateTimer = null; + } + + public void StartSuddenDeath( TimeSpan timeUntilActive ) + { + if ( m_SDWarnTimer != null ) + m_SDWarnTimer.Stop(); + + m_SDWarnTimer = Timer.DelayCall( TimeSpan.FromMinutes( timeUntilActive.TotalMinutes * 0.9 ), new TimerCallback( WarnSuddenDeath ) ); + + if ( m_SDActivateTimer != null ) + m_SDActivateTimer.Stop(); + + m_SDActivateTimer = Timer.DelayCall( timeUntilActive, new TimerCallback( ActivateSuddenDeath ) ); + } + + public void WarnSuddenDeath() + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null || pl.Eliminated ) + continue; + + pl.Mobile.SendSound( 0x1E1 ); + pl.Mobile.SendMessage( 0x22, "Warning! Warning! Warning!" ); + pl.Mobile.SendMessage( 0x22, "Sudden death will be active soon!" ); + } + } + + if ( m_Tournament != null ) + m_Tournament.Alert( m_Arena, "Sudden death will be active soon!" ); + + if ( m_SDWarnTimer != null ) + m_SDWarnTimer.Stop(); + + m_SDWarnTimer = null; + } + + public static bool CheckSuddenDeath( Mobile mob ) + { + if ( mob is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)mob; + + if ( pm.DuelPlayer != null && !pm.DuelPlayer.Eliminated && pm.DuelContext != null && pm.DuelContext.IsSuddenDeath ) + return true; + } + + return false; + } + + public void ActivateSuddenDeath() + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null || pl.Eliminated ) + continue; + + pl.Mobile.SendSound( 0x1E1 ); + pl.Mobile.SendMessage( 0x22, "Warning! Warning! Warning!" ); + pl.Mobile.SendMessage( 0x22, "Sudden death has ACTIVATED. You are now unable to perform any beneficial actions." ); + } + } + + if ( m_Tournament != null ) + m_Tournament.Alert( m_Arena, "Sudden death has been activated!" ); + + m_IsSuddenDeath = true; + + if ( m_SDActivateTimer != null ) + m_SDActivateTimer.Stop(); + + m_SDActivateTimer = null; + } + + public void BeginAutoTie() + { + if ( m_AutoTieTimer != null ) + m_AutoTieTimer.Stop(); + + TimeSpan ts = ( m_Tournament == null || m_Tournament.TournyType == TournyType.Standard ) + ? AutoTieDelay + : TimeSpan.FromMinutes( 90.0 ); + + m_AutoTieTimer = Timer.DelayCall( ts, new TimerCallback( InvokeAutoTie ) ); + } + + public void EndAutoTie() + { + if ( m_AutoTieTimer != null ) + m_AutoTieTimer.Stop(); + + m_AutoTieTimer = null; + } + + public void InvokeAutoTie() + { + m_AutoTieTimer = null; + + if ( !m_Started || m_Finished ) + return; + + m_Tied = true; + m_Finished = true; + + StopSDTimers(); + + ArrayList remaining = new ArrayList(); + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + if ( p.Eliminated ) + { + p.Broadcast( 0x22, null, p.Players.Length == 1 ? "{0} has lost the duel." : "{0} and {1} team have lost the duel.", p.Players.Length == 1 ? "You have lost the duel." : "Your team has lost the duel." ); + } + else + { + p.Broadcast( 0x59, null, p.Players.Length == 1 ? "{0} has tied the duel due to time expiration." : "{0} and {1} team have tied the duel due to time expiration.", p.Players.Length == 1 ? "You have tied the duel due to time expiration." : "Your team has tied the duel due to time expiration." ); + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl != null && !pl.Eliminated ) + DelayBounce( TimeSpan.FromSeconds( 8.0 ), pl.Mobile, null ); + } + + if ( p.TournyPart != null ) + remaining.Add( p.TournyPart ); + } + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl != null ) + { + pl.Mobile.Delta( MobileDelta.Noto ); + pl.Mobile.SendEverything(); + } + } + } + + if ( m_Tournament != null ) + m_Tournament.HandleTie( m_Arena, m_Match, remaining ); + + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Unregister ) ); + } + + public bool IsOneVsOne + { + get + { + if ( m_Participants.Count != 2 ) + return false; + + if ( ((Participant)m_Participants[0]).Players.Length != 1 ) + return false; + + if ( ((Participant)m_Participants[1]).Players.Length != 1 ) + return false; + + return true; + } + } + + public static void Initialize() + { + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + EventSink.Login += new LoginEventHandler( EventSink_Login ); + + CommandSystem.Register( "vli", AccessLevel.GameMaster, new CommandEventHandler( vli_oc ) ); + } + + private static void vli_oc( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, Targeting.TargetFlags.None, new TargetCallback( vli_ot ) ); + } + + private static void vli_ot( Mobile from, object obj ) + { + if ( obj is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)obj; + + Ladder ladder = Ladder.Instance; + + if ( ladder == null ) + return; + + LadderEntry entry = ladder.Find( pm ); + + if ( entry != null ) + from.SendGump( new PropertiesGump( from, entry ) ); + } + } + + private static TimeSpan CombatDelay = TimeSpan.FromSeconds( 30.0 ); + private static TimeSpan AutoTieDelay = TimeSpan.FromMinutes( 15.0 ); + + public static bool CheckCombat( Mobile m ) + { + for ( int i = 0; i < m.Aggressed.Count; ++i ) + { + AggressorInfo info = m.Aggressed[i]; + + if ( info.Defender.Player && (DateTime.Now - info.LastCombatTime) < CombatDelay ) + return true; + } + + for ( int i = 0; i < m.Aggressors.Count; ++i ) + { + AggressorInfo info = m.Aggressors[i]; + + if ( info.Attacker.Player && (DateTime.Now - info.LastCombatTime) < CombatDelay ) + return true; + } + + return false; + } + + private static void EventSink_Login( LoginEventArgs e ) + { + PlayerMobile pm = e.Mobile as PlayerMobile; + + if ( pm == null ) + return; + + DuelContext dc = pm.DuelContext; + + if ( dc == null ) + return; + + if ( dc.ReadyWait && pm.DuelPlayer.Ready && !dc.Started && !dc.StartedBeginCountdown && !dc.Finished ) + { + if ( dc.m_Tournament == null ) + pm.SendGump( new ReadyGump( pm, dc, dc.m_ReadyCount ) ); + } + else if ( dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished ) + { + if ( dc.m_Tournament == null ) + pm.SendGump( new ReadyUpGump( pm, dc ) ); + } + else if ( dc.Initiator == pm && !dc.ReadyWait && !dc.StartedBeginCountdown && !dc.Started && !dc.Finished ) + pm.SendGump( new DuelContextGump( pm, dc ) ); + } + + private static void ViewLadder_OnTarget( Mobile from, object obj, object state ) + { + if ( obj is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)obj; + Ladder ladder = (Ladder)state; + + LadderEntry entry = ladder.Find( pm ); + + if ( entry == null ) + return; // sanity + + string text = String.Format( "{{0}} are ranked {0} at level {1}.", LadderGump.Rank( entry.Index + 1 ), Ladder.GetLevel( entry.Experience ) ); + + pm.PrivateOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, from==pm?"You":"They" ), from.NetState ); + } + else if ( obj is Mobile ) + { + Mobile mob = (Mobile)obj; + + if ( mob.Body.IsHuman ) + mob.PrivateOverheadMessage( MessageType.Regular, mob.SpeechHue, false, "I'm not a duelist, and quite frankly, I resent the implication.", from.NetState ); + else + mob.PrivateOverheadMessage( MessageType.Regular, 0x3B2, true, "It's probably better than you.", from.NetState ); + } + else + { + from.SendMessage( "That's not a player." ); + } + } + + private static void EventSink_Speech( SpeechEventArgs e ) + { + if ( e.Handled ) + return; + + PlayerMobile pm = e.Mobile as PlayerMobile; + + if ( pm == null ) + return; + + if ( Insensitive.Contains( e.Speech, "i wish to duel" ) ) + { + if ( !pm.CheckAlive() ) + { + } + else if ( pm.Region.IsPartOf( typeof( Regions.Jail ) ) ) + { + } + else if ( CheckCombat( pm ) ) + { + e.Mobile.SendMessage( 0x22, "You have recently been in combat with another player and must wait before starting a duel." ); + } + else if ( pm.DuelContext != null ) + { + if ( pm.DuelContext.Initiator == pm ) + e.Mobile.SendMessage( 0x22, "You have already started a duel." ); + else + e.Mobile.SendMessage( 0x22, "You have already been challenged in a duel." ); + } + else if ( TournamentController.IsActive ) + { + e.Mobile.SendMessage( 0x22, "You may not start a duel while a tournament is active." ); + } + else + { + pm.SendGump( new DuelContextGump( pm, new DuelContext( pm, RulesetLayout.Root ) ) ); + e.Handled = true; + } + } + else if ( Insensitive.Equals( e.Speech, "change arena preferences" ) ) + { + if ( !pm.CheckAlive() ) + { + } + else + { + Preferences prefs = Preferences.Instance; + + if ( prefs != null ) + { + e.Mobile.CloseGump( typeof( PreferencesGump ) ); + e.Mobile.SendGump( new PreferencesGump( e.Mobile, prefs ) ); + } + } + } + else if ( Insensitive.Equals( e.Speech, "showladder" ) ) + { + e.Blocked=true; + if ( !pm.CheckAlive() ) + { + } + else + { + Ladder instance = Ladder.Instance; + + if ( instance == null ) + { + //pm.SendMessage( "Ladder not yet initialized." ); + } + else + { + LadderEntry entry = instance.Find( pm ); + + if ( entry == null ) + return; // sanity + + string text = String.Format( "{{0}} {{1}} ranked {0} at level {1}.", LadderGump.Rank( entry.Index + 1 ), Ladder.GetLevel( entry.Experience ) ); + + pm.LocalOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, "You", "are" ) ); + pm.NonlocalOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( text, pm.Name, "is" ) ); + + //pm.PublicOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( "Level {0} with {1} win{2} and {3} loss{4}.", Ladder.GetLevel( entry.Experience ), entry.Wins, entry.Wins==1?"":"s", entry.Losses, entry.Losses==1?"":"es" ) ); + //pm.PublicOverheadMessage( MessageType.Regular, pm.SpeechHue, true, String.Format( "Level {0} with {1} win{2} and {3} loss{4}.", Ladder.GetLevel( entry.Experience ), entry.Wins, entry.Wins==1?"":"s", entry.Losses, entry.Losses==1?"":"es" ) ); + } + } + } + else if ( Insensitive.Equals( e.Speech, "viewladder" ) ) + { + e.Blocked=true; + + if ( !pm.CheckAlive() ) + { + } + else + { + Ladder instance = Ladder.Instance; + + if ( instance == null ) + { + //pm.SendMessage( "Ladder not yet initialized." ); + } + else + { + pm.SendMessage( "Target a player to view their ranking and level." ); + pm.BeginTarget( 16, false, Targeting.TargetFlags.None, new TargetStateCallback( ViewLadder_OnTarget ), instance ); + } + } + } + else if ( Insensitive.Contains( e.Speech, "i yield" ) ) + { + if ( !pm.CheckAlive() ) + { + } + else if ( pm.DuelContext == null ) + { + } + else if ( pm.DuelContext.Finished ) + { + e.Mobile.SendMessage( 0x22, "The duel is already finished." ); + } + else if ( !pm.DuelContext.Started ) + { + DuelContext dc = pm.DuelContext; + Mobile init = dc.Initiator; + + if ( pm.DuelContext.StartedBeginCountdown ) + { + e.Mobile.SendMessage( 0x22, "The duel has not yet started." ); + } + else + { + DuelPlayer pl = pm.DuelContext.Find( pm ); + + if ( pl == null ) + return; + + Participant p = pl.Participant; + + if ( !pm.DuelContext.ReadyWait ) // still setting stuff up + { + p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." ); + + if ( init == pm ) + { + dc.Unregister(); + } + else + { + p.Nullify( pl ); + pm.DuelPlayer=null; + + NetState ns = init.NetState; + + if ( ns != null ) + { + foreach ( Gump g in ns.Gumps ) + { + if ( g is ParticipantGump ) + { + ParticipantGump pg = (ParticipantGump)g; + + if ( pg.Participant == p ) + { + init.SendGump( new ParticipantGump( init, dc, p ) ); + break; + } + } + else if ( g is DuelContextGump ) + { + DuelContextGump dcg = (DuelContextGump)g; + + if ( dcg.Context == dc ) + { + init.SendGump( new DuelContextGump( init, dc ) ); + break; + } + } + } + } + } + } + else if ( !pm.DuelContext.StartedReadyCountdown ) // at ready stage + { + p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." ); + + dc.m_Yielding=true; + dc.RejectReady( pm, null ); + dc.m_Yielding=false; + + if ( init == pm ) + { + dc.Unregister(); + } + else if ( dc.m_Registered ) + { + p.Nullify( pl ); + pm.DuelPlayer=null; + + NetState ns = init.NetState; + + if ( ns != null ) + { + bool send=true; + + foreach ( Gump g in ns.Gumps ) + { + if ( g is ParticipantGump ) + { + ParticipantGump pg = (ParticipantGump)g; + + if ( pg.Participant == p ) + { + init.SendGump( new ParticipantGump( init, dc, p ) ); + send=false; + break; + } + } + else if ( g is DuelContextGump ) + { + DuelContextGump dcg = (DuelContextGump)g; + + if ( dcg.Context == dc ) + { + init.SendGump( new DuelContextGump( init, dc ) ); + send=false; + break; + } + } + } + + if ( send ) + init.SendGump( new DuelContextGump( init, dc ) ); + } + } + } + else + { + if ( pm.DuelContext.m_Countdown != null ) + pm.DuelContext.m_Countdown.Stop(); + pm.DuelContext.m_Countdown= null; + + pm.DuelContext.m_StartedReadyCountdown=false; + p.Broadcast( 0x22, null, "{0} has yielded.", "You have yielded." ); + + dc.m_Yielding=true; + dc.RejectReady( pm, null ); + dc.m_Yielding=false; + + if ( init == pm ) + { + dc.Unregister(); + } + else if ( dc.m_Registered ) + { + p.Nullify( pl ); + pm.DuelPlayer=null; + + NetState ns = init.NetState; + + if ( ns != null ) + { + bool send=true; + + foreach ( Gump g in ns.Gumps ) + { + if ( g is ParticipantGump ) + { + ParticipantGump pg = (ParticipantGump)g; + + if ( pg.Participant == p ) + { + init.SendGump( new ParticipantGump( init, dc, p ) ); + send=false; + break; + } + } + else if ( g is DuelContextGump ) + { + DuelContextGump dcg = (DuelContextGump)g; + + if ( dcg.Context == dc ) + { + init.SendGump( new DuelContextGump( init, dc ) ); + send=false; + break; + } + } + } + + if ( send ) + init.SendGump( new DuelContextGump( init, dc ) ); + } + } + } + } + } + else + { + DuelPlayer pl = pm.DuelContext.Find( pm ); + + if ( pl != null ) + { + if ( pm.DuelContext.IsOneVsOne ) + { + e.Mobile.SendMessage( 0x22, "You may not yield a 1 on 1 match." ); + } + else if ( pl.Eliminated ) + { + e.Mobile.SendMessage( 0x22, "You have already been eliminated." ); + } + else + { + pm.LocalOverheadMessage( MessageType.Regular, 0x22, false, "You have yielded." ); + pm.NonlocalOverheadMessage( MessageType.Regular, 0x22, false, String.Format( "{0} has yielded.", pm.Name ) ); + + pm.DuelContext.m_Yielding=true; + pm.Kill(); + pm.DuelContext.m_Yielding=false; + + if ( pm.Alive ) // invul, ... + { + pl.Eliminated = true; + + pm.DuelContext.RemoveAggressions( pm ); + pm.DuelContext.SendOutside( pm ); + pm.DuelContext.Refresh( pm, null ); + Debuff( pm ); + CancelSpell( pm ); + pm.Frozen = false; + + Participant winner = pm.DuelContext.CheckCompletion(); + + if ( winner != null ) + pm.DuelContext.Finish( winner ); + } + } + } + else + { + e.Mobile.SendMessage( 0x22, "BUG: Unable to find duel context." ); + } + } + } + } + + public DuelContext( Mobile initiator, RulesetLayout layout ) : this( initiator, layout, true ) + { + } + + public DuelContext( Mobile initiator, RulesetLayout layout, bool addNew ) + { + m_Initiator = initiator; + m_Participants = new ArrayList(); + m_Ruleset = new Ruleset( layout ); + m_Ruleset.ApplyDefault( layout.Defaults[0] ); + + if ( addNew ) + { + m_Participants.Add( new Participant( this, 1 ) ); + m_Participants.Add( new Participant( this, 1 ) ); + + ((Participant)m_Participants[0]).Add( initiator ); + } + } + + public void CloseAllGumps() + { + Type[] types = new Type[]{ typeof( DuelContextGump ), typeof( ParticipantGump ), typeof( RulesetGump ) }; + int[] defs = new int[]{ -1, -1, -1 }; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + Mobile mob = pl.Mobile; + + for ( int k = 0; k < types.Length; ++k ) + mob.CloseGump( types[k] ); + //mob.CloseGump( types[k], defs[k] ); + } + } + } + + public void RejectReady( Mobile rejector, string page ) + { + if ( m_StartedReadyCountdown ) + return; // sanity + + Type[] types = new Type[]{ typeof( DuelContextGump ), typeof( ReadyUpGump ), typeof( ReadyGump ) }; + int[] defs = new int[]{ -1, -1, -1 }; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + pl.Ready = false; + + Mobile mob = pl.Mobile; + + if ( page == null ) // yield + { + if ( mob != rejector ) + mob.SendMessage( 0x22, "{0} has yielded.", rejector.Name ); + } + else + { + if ( mob == rejector ) + mob.SendMessage( 0x22, "You have rejected the {0}.", m_Rematch ? "rematch" : page ); + else + mob.SendMessage( 0x22, "{0} has rejected the {1}.", rejector.Name, m_Rematch ? "rematch" : page ); + } + + for ( int k = 0; k < types.Length; ++k ) + mob.CloseGump( types[k] ); + //mob.CloseGump( types[k], defs[k] ); + } + } + + if ( m_Rematch ) + Unregister(); + else if ( !m_Yielding ) + m_Initiator.SendGump( new DuelContextGump( m_Initiator, this ) ); + + m_ReadyWait = false; + m_ReadyCount = 0; + } + + public void SendReadyGump() + { + SendReadyGump( -1 ); + } + + public static void Debuff( Mobile mob ) + { + mob.RemoveStatMod( "[Magic] Str Offset" ); + mob.RemoveStatMod( "[Magic] Dex Offset" ); + mob.RemoveStatMod( "[Magic] Int Offset" ); + mob.RemoveStatMod( "Concussion" ); + + OrangePetals.RemoveContext( mob ); + + mob.Paralyzed = false; + mob.Hidden = false; + + if ( !Core.AOS ) + { + mob.MagicDamageAbsorb = 0; + mob.MeleeDamageAbsorb = 0; + Spells.Second.ProtectionSpell.Registry.Remove( mob ); + Spells.Fourth.ArchProtectionSpell.RemoveEntry(mob); + + mob.EndAction( typeof( DefensiveSpell ) ); + } + + TransformationSpellHelper.RemoveContext( mob, true ); + AnimalForm.RemoveContext( mob, true ); + + if( DisguiseTimers.IsDisguised( mob ) ) + DisguiseTimers.StopTimer( mob ); + + if( !mob.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + mob.BodyMod = 0; + mob.HueMod = -1; + mob.EndAction( typeof( PolymorphSpell ) ); + } + + BaseArmor.ValidateMobile( mob ); + BaseClothing.ValidateMobile( mob ); + + mob.Hits = mob.HitsMax; + mob.Stam = mob.StamMax; + mob.Mana = mob.ManaMax; + + mob.Poison = null; + } + + public static void CancelSpell( Mobile mob ) + { + if ( mob.Spell is Spells.Spell ) + ((Spells.Spell)mob.Spell).Disturb( Spells.DisturbType.Kill ); + + Targeting.Target.Cancel( mob ); + } + + private bool m_StartedBeginCountdown; + private bool m_StartedReadyCountdown; + + public bool StartedBeginCountdown{ get{ return m_StartedBeginCountdown; } } + public bool StartedReadyCountdown{ get{ return m_StartedReadyCountdown; } } + + private class InternalWall : Item + { + public InternalWall() : base( 0x80 ) + { + Movable = false; + } + + public void Appear( Point3D loc, Map map ) + { + MoveToWorld( loc, map ); + + Effects.SendLocationParticles( this, 0x376A, 9, 10, 5025 ); + } + + public InternalWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } + + private ArrayList m_Walls = new ArrayList(); + + public void DestroyWall() + { + for ( int i = 0; i < m_Walls.Count; ++i ) + ((Item)m_Walls[i]).Delete(); + + m_Walls.Clear(); + } + + public void CreateWall() + { + if ( m_Arena == null ) + return; + + Point3D start = m_Arena.Points.EdgeWest; + Point3D wall = m_Arena.Wall; + + int dx = start.X - wall.X; + int dy = start.Y - wall.Y; + int rx = dx - dy; + int ry = dx + dy; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + eastToWest = false; + else if ( rx >= 0 ) + eastToWest = true; + else if ( ry >= 0 ) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound( wall, m_Arena.Facet, 0x1F6 ); + + for ( int i = -1; i <= 1; ++i ) + { + Point3D loc = new Point3D( eastToWest ? wall.X + i : wall.X, eastToWest ? wall.Y : wall.Y + i, wall.Z ); + + InternalWall created = new InternalWall(); + + created.Appear( loc, m_Arena.Facet ); + + m_Walls.Add( created ); + } + } + + public void BuildParties() + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + if ( p.Players.Length > 1 ) + { + ArrayList players = new ArrayList(); + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp == null ) + continue; + + players.Add( dp.Mobile ); + } + + if ( players.Count > 1 ) + { + for ( int leaderIndex = 0; (leaderIndex+1) < players.Count; leaderIndex += Party.Capacity ) + { + Mobile leader = (Mobile) players[leaderIndex]; + Party party = Party.Get( leader ); + + if ( party == null ) + { + leader.Party = party = new Party( leader ); + } + else if ( party.Leader != leader ) + { + party.SendPublicMessage( leader, "I leave this party to fight in a duel." ); + party.Remove( leader ); + leader.Party = party = new Party( leader ); + } + + for ( int j = leaderIndex+1; j < players.Count && j < leaderIndex+Party.Capacity; ++j ) + { + Mobile player = (Mobile)players[j]; + Party existing = Party.Get( player ); + + if ( existing == party ) + continue; + + if ( (party.Members.Count + party.Candidates.Count) >= Party.Capacity ) + { + player.SendMessage( "You could not be added to the team party because it is at full capacity." ); + leader.SendMessage( "{0} could not be added to the team party because it is at full capacity." ); + } + else + { + if ( existing != null ) + { + existing.SendPublicMessage( player, "I leave this party to fight in a duel." ); + existing.Remove( player ); + } + + party.OnAccept( player, true ); + } + } + } + } + } + } + } + + public void ClearIllegalItems() + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + ClearIllegalItems( pl.Mobile ); + } + } + } + + public void ClearIllegalItems( Mobile mob ) + { + if ( mob.StunReady && !AllowSpecialAbility( mob, "Stun", false ) ) + mob.StunReady = false; + + if ( mob.DisarmReady && !AllowSpecialAbility( mob, "Disarm", false ) ) + mob.DisarmReady = false; + + Container pack = mob.Backpack; + + if ( pack == null ) + return; + + for ( int i = mob.Items.Count - 1; i >= 0; --i ) + { + if ( i >= mob.Items.Count ) + continue; // sanity + + Item item = mob.Items[i]; + + if ( !CheckItemEquip( mob, item ) ) + { + pack.DropItem( item ); + + if ( item is BaseWeapon ) + mob.SendLocalizedMessage( 1062001, item.Name == null ? "#" + item.LabelNumber.ToString() : item.Name ); // You can no longer wield your ~1_WEAPON~ + else if ( item is BaseArmor && !(item is BaseShield) ) + mob.SendLocalizedMessage( 1062002, item.Name == null ? "#" + item.LabelNumber.ToString() : item.Name ); // You can no longer wear your ~1_ARMOR~ + else + mob.SendLocalizedMessage( 1062003, item.Name == null ? "#" + item.LabelNumber.ToString() : item.Name ); // You can no longer equip your ~1_SHIELD~ + } + } + + Item inHand = mob.Holding; + + if ( inHand != null && !CheckItemEquip( mob, inHand ) ) + { + mob.Holding = null; + + BounceInfo bi = inHand.GetBounce(); + + if ( bi.m_Parent == mob ) + pack.DropItem( inHand ); + else + inHand.Bounce( mob ); + + inHand.ClearBounce(); + } + } + + public void SendBeginGump( int count ) + { + if ( !m_Registered || m_Finished ) + return; + + if ( count == 10 ) + { + CreateWall(); + BuildParties(); + ClearIllegalItems(); + } + else if ( count == 0 ) + { + DestroyWall(); + } + + m_StartedBeginCountdown = true; + + if ( count == 0 ) + { + m_Started = true; + BeginAutoTie(); + } + + Type[] types = new Type[]{ typeof( ReadyGump ), typeof( ReadyUpGump ), typeof( BeginGump ) }; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + Mobile mob = pl.Mobile; + + if ( count > 0 ) + { + if ( count == 10 ) + CloseAndSendGump( mob, new BeginGump( count ), types ); + + mob.Frozen = true; + } + else + { + mob.CloseGump( typeof( BeginGump ) ); + mob.Frozen = false; + } + } + } + } + + private ArrayList m_Entered = new ArrayList(); + + private class ReturnEntry + { + private Mobile m_Mobile; + private Point3D m_Location; + private Map m_Facet; + private DateTime m_Expire; + + public Mobile Mobile{ get{ return m_Mobile; } } + public Point3D Location{ get{ return m_Location; } } + public Map Facet{ get{ return m_Facet; } } + + public void Return() + { + if ( m_Facet == Map.Internal || m_Facet == null ) + return; + + if ( m_Mobile.Map == Map.Internal ) + { + m_Mobile.LogoutLocation = m_Location; + m_Mobile.LogoutMap = m_Facet; + } + else + { + m_Mobile.Location = m_Location; + m_Mobile.Map = m_Facet; + } + } + + public ReturnEntry( Mobile mob ) + { + m_Mobile = mob; + + Update(); + } + + public ReturnEntry( Mobile mob, Point3D loc, Map facet ) + { + m_Mobile = mob; + m_Location = loc; + m_Facet = facet; + m_Expire = DateTime.Now + TimeSpan.FromMinutes( 30.0 ); + } + + public bool Expired{ get{ return ( DateTime.Now >= m_Expire ); } } + + public void Update() + { + m_Expire = DateTime.Now + TimeSpan.FromMinutes( 30.0 ); + + if ( m_Mobile.Map == Map.Internal ) + { + m_Facet = m_Mobile.LogoutMap; + m_Location = m_Mobile.LogoutLocation; + } + else + { + m_Facet = m_Mobile.Map; + m_Location = m_Mobile.Location; + } + } + } + + private class ExitTeleporter : Item + { + private ArrayList m_Entries; + + public override string DefaultName + { + get { return "return teleporter"; } + } + + public ExitTeleporter() : base( 0x1822 ) + { + m_Entries = new ArrayList(); + + Hue = 0x482; + Movable = false; + } + + public void Register( Mobile mob ) + { + ReturnEntry entry = Find( mob ); + + if ( entry != null ) + { + entry.Update(); + return; + } + + m_Entries.Add( new ReturnEntry( mob ) ); + } + + private ReturnEntry Find( Mobile mob ) + { + for ( int i = 0; i < m_Entries.Count; ++i ) + { + ReturnEntry entry = (ReturnEntry)m_Entries[i]; + + if ( entry.Mobile == mob ) + return entry; + else if ( entry.Expired ) + m_Entries.RemoveAt( i-- ); + } + + return null; + } + + public override bool OnMoveOver( Mobile m ) + { + if ( !base.OnMoveOver( m ) ) + return false; + + ReturnEntry entry = Find( m ); + + if ( entry != null ) + { + entry.Return(); + + Effects.PlaySound( GetWorldLocation(), Map, 0x1FE ); + Effects.PlaySound( m.Location, m.Map, 0x1FE ); + + m_Entries.Remove( entry ); + + return false; + } + else + { + m.SendLocalizedMessage( 1049383 ); // The teleporter doesn't seem to work for you. + return true; + } + } + + public ExitTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.WriteEncodedInt( (int) m_Entries.Count ); + + for ( int i = 0; i < m_Entries.Count; ++i ) + { + ReturnEntry entry = (ReturnEntry)m_Entries[i]; + + writer.Write( (Mobile) entry.Mobile ); + writer.Write( (Point3D) entry.Location ); + writer.Write( (Map) entry.Facet ); + + if ( entry.Expired ) + m_Entries.RemoveAt( i-- ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + int count = reader.ReadEncodedInt(); + + m_Entries = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + Mobile mob = reader.ReadMobile(); + Point3D loc = reader.ReadPoint3D(); + Map map = reader.ReadMap(); + + m_Entries.Add( new ReturnEntry( mob, loc, map ) ); + } + + break; + } + } + } + } + + private class ArenaMoongate : ConfirmationMoongate + { + private ExitTeleporter m_Teleporter; + + public override string DefaultName + { + get { return "spectator moongate"; } + } + + public ArenaMoongate( Point3D target, Map map, ExitTeleporter tp ) : base( target, map ) + { + m_Teleporter = tp; + + ItemID = 0x1FD4; + Dispellable = false; + + GumpWidth = 300; + GumpHeight = 150; + MessageColor = 0xFFC000; + MessageString = "Are you sure you wish to spectate this duel?"; + TitleColor = 0x7800; + TitleNumber = 1062051; // Gate Warning + + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Delete ) ); + } + + public override void CheckGate(Mobile m, int range) + { + if ( DuelContext.CheckCombat( m ) ) + { + m.SendMessage( 0x22, "You have recently been in combat with another player and cannot use this moongate." ); + } + else + { + base.CheckGate( m, range ); + } + } + + public override void UseGate( Mobile m ) + { + if ( DuelContext.CheckCombat( m ) ) + { + m.SendMessage( 0x22, "You have recently been in combat with another player and cannot use this moongate." ); + } + else + { + if ( m_Teleporter != null && !m_Teleporter.Deleted ) + m_Teleporter.Register( m ); + + base.UseGate( m ); + } + } + + public void Appear( Point3D loc, Map map ) + { + Effects.PlaySound( loc, map, 0x20E ); + MoveToWorld( loc, map ); + } + + public ArenaMoongate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } + + public void RemoveAggressions( Mobile mob ) + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = (DuelPlayer)p.Players[j]; + + if ( dp == null || dp.Mobile == mob ) + continue; + + mob.RemoveAggressed( dp.Mobile ); + mob.RemoveAggressor( dp.Mobile ); + dp.Mobile.RemoveAggressed( mob ); + dp.Mobile.RemoveAggressor( mob ); + } + } + } + + public void SendReadyUpGump() + { + if ( !m_Registered ) + return; + + m_ReadyWait = true; + m_ReadyCount = -1; + + Type[] types = new Type[]{ typeof( ReadyUpGump ) }; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + Mobile mob = pl.Mobile; + + if ( mob != null ) + { + if ( m_Tournament == null ) + CloseAndSendGump( mob, new ReadyUpGump( mob, this ), types ); + } + } + } + } + + public string ValidateStart() + { + if ( m_Tournament == null && TournamentController.IsActive ) + return "a tournament is active"; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp == null ) + return "a slot is empty"; + + if ( dp.Mobile.Region.IsPartOf( typeof( Regions.Jail ) ) ) + return String.Format( "{0} is in jail", dp.Mobile.Name ); + + if ( Sigil.ExistsOn( dp.Mobile ) ) + return String.Format( "{0} is holding a sigil", dp.Mobile.Name ); + + if ( !dp.Mobile.Alive ) + { + if ( m_Tournament == null ) + return String.Format( "{0} is dead", dp.Mobile.Name ); + else + dp.Mobile.Resurrect(); + } + + if ( m_Tournament == null && CheckCombat( dp.Mobile ) ) + return String.Format( "{0} is in combat", dp.Mobile.Name ); + + if ( dp.Mobile.Mounted ) + { + IMount mount = dp.Mobile.Mount; + + if ( m_Tournament != null && mount != null ) + mount.Rider = null; + else + return String.Format( "{0} is mounted", dp.Mobile.Name ); + } + } + } + + return null; + } + + public Arena m_OverrideArena; + public Tournament m_Tournament; + public TournyMatch m_Match; + public EventGame m_EventGame; + + public Tournament Tournament { get { return m_Tournament; } } + + + public void SendReadyGump( int count ) + { + if ( !m_Registered ) + return; + + if ( count != -1 ) + m_StartedReadyCountdown = true; + + m_ReadyCount = count; + + if ( count == 0 ) + { + string error = ValidateStart(); + + if ( error != null ) + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null ) + dp.Mobile.SendMessage( "The duel could not be started because {0}.", error ); + } + } + + StartCountdown( 10, new CountdownCallback( SendReadyGump ) ); + + return; + } + + m_ReadyWait = false; + + List players = new List(); + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null ) + players.Add( dp.Mobile ); + } + } + + Arena arena = m_OverrideArena; + + if ( arena == null ) + arena = Arena.FindArena( players ); + + if ( arena == null ) + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null ) + dp.Mobile.SendMessage( "The duel could not be started because there are no arenas. If you want to stop waiting for a free arena, yield the duel." ); + } + } + + StartCountdown( 10, new CountdownCallback( SendReadyGump ) ); + return; + } + + if ( !arena.IsOccupied ) + { + m_Arena = arena; + + if ( m_Initiator.Map == Map.Internal ) + { + m_GatePoint = m_Initiator.LogoutLocation; + m_GateFacet = m_Initiator.LogoutMap; + } + else + { + m_GatePoint = m_Initiator.Location; + m_GateFacet = m_Initiator.Map; + } + + ExitTeleporter tp = arena.Teleporter as ExitTeleporter; + + if ( tp == null ) + { + arena.Teleporter = tp = new ExitTeleporter(); + tp.MoveToWorld( arena.GateOut == Point3D.Zero ? arena.Outside : arena.GateOut, arena.Facet ); + } + + ArenaMoongate mg = new ArenaMoongate( arena.GateIn == Point3D.Zero ? arena.Outside : arena.GateIn, arena.Facet, tp ); + + m_StartedBeginCountdown = true; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + tp.Register( pl.Mobile ); + + pl.Mobile.Frozen = false; // reset timer just in case + pl.Mobile.Frozen = true; + + Debuff( pl.Mobile ); + CancelSpell( pl.Mobile ); + + pl.Mobile.Delta( MobileDelta.Noto ); + } + + arena.MoveInside( p.Players, i ); + } + + if ( m_EventGame != null ) + m_EventGame.OnStart(); + + StartCountdown( 10, new CountdownCallback( SendBeginGump ) ); + + mg.Appear( m_GatePoint, m_GateFacet ); + } + else + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer dp = p.Players[j]; + + if ( dp != null ) + dp.Mobile.SendMessage( "The duel could not be started because all arenas are full. If you want to stop waiting for a free arena, yield the duel." ); + } + } + + StartCountdown( 10, new CountdownCallback( SendReadyGump ) ); + } + + return; + } + + m_ReadyWait = true; + + bool isAllReady = true; + + Type[] types = new Type[]{ typeof( ReadyGump ) }; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + Participant p = (Participant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl == null ) + continue; + + Mobile mob = pl.Mobile; + + if ( pl.Ready ) + { + if ( m_Tournament == null ) + CloseAndSendGump( mob, new ReadyGump( mob, this, count ), types ); + } + else + { + isAllReady = false; + } + } + } + + if ( count == -1 && isAllReady ) + StartCountdown( 3, new CountdownCallback( SendReadyGump ) ); + } + + public static void CloseAndSendGump( Mobile mob, Gump g, params Type[] types ) + { + CloseAndSendGump( mob.NetState, g, types ); + } + + public static void CloseAndSendGump(NetState ns, Gump g, params Type[] types) + { + if (ns != null) + { + Mobile mob = ns.Mobile; + + if (mob != null) + { + foreach (Type type in types) + { + mob.CloseGump(type); + } + + mob.SendGump(g); + } + } + + /*if ( ns == null ) + return; + + for ( int i = 0; i < types.Length; ++i ) + ns.Send( new CloseGump( Gump.GetTypeID( types[i] ), 0 ) ); + + g.SendTo( ns ); + + ns.AddGump( g ); + + Packet[] packets = new Packet[types.Length + 1]; + + for ( int i = 0; i < types.Length; ++i ) + packets[i] = new CloseGump( Gump.GetTypeID( types[i] ), 0 ); + + packets[types.Length] = (Packet) typeof( Gump ).InvokeMember( "Compile", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, g, null, null ); + + bool compress = ns.CompressionEnabled; + ns.CompressionEnabled = false; + ns.Send( BindPackets( compress, packets ) ); + ns.CompressionEnabled = compress;*/ + } + + /*public static Packet BindPackets( bool compress, params Packet[] packets ) + { + if ( packets.Length == 0 ) + throw new ArgumentException( "No packets to bind", "packets" ); + + byte[][] compiled = new byte[packets.Length][]; + int[] lengths = new int[packets.Length]; + + int length = 0; + + for ( int i = 0; i < packets.Length; ++i ) + { + compiled[i] = packets[i].Compile( compress, out lengths[i] ); + length += lengths[i]; + } + + return new BoundPackets( length, compiled, lengths ); + } + + private class BoundPackets : Packet + { + public BoundPackets( int length, byte[][] compiled, int[] lengths ) : base( 0, length ) + { + m_Stream.Seek( 0, System.IO.SeekOrigin.Begin ); + + for ( int i = 0; i < compiled.Length; ++i ) + m_Stream.Write( compiled[i], 0, lengths[i] ); + } + }*/ + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/DuelContextGump.cs b/Scripts/Engines/ConPVP/DuelContextGump.cs new file mode 100644 index 0000000..012d91d --- /dev/null +++ b/Scripts/Engines/ConPVP/DuelContextGump.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class DuelContextGump : Gump + { + private Mobile m_From; + private DuelContext m_Context; + + public Mobile From{ get{ return m_From; } } + public DuelContext Context{ get{ return m_Context; } } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public void AddGoldenButton( int x, int y, int bid ) + { + AddButton( x , y , 0xD2, 0xD2, bid, GumpButtonType.Reply, 0 ); + AddButton( x+3, y+3, 0xD8, 0xD8, bid, GumpButtonType.Reply, 0 ); + } + + public void AddGoldenButtonLabeled( int x, int y, int bid, string text ) + { + AddGoldenButton( x, y, bid ); + AddHtml( x + 25, y, 200, 20, text, false, false ); + } + + public DuelContextGump( Mobile from, DuelContext context ) : base( 50, 50 ) + { + m_From = from; + m_Context = context; + + from.CloseGump( typeof( RulesetGump ) ); + from.CloseGump( typeof( DuelContextGump ) ); + from.CloseGump( typeof( ParticipantGump ) ); + + int count = context.Participants.Count; + + if ( count < 3 ) + count = 3; + + int height = 35 + 10 + 22 + 30 + 22 + 22 + 2 + (count * 22) + 2 + 30; + + AddPage( 0 ); + + AddBackground( 0, 0, 300, height, 9250 ); + AddBackground( 10, 10, 280, height - 20, 0xDAC ); + + AddHtml( 35, 25, 230, 20, Center( "Duel Setup" ), false, false ); + + int x = 35; + int y = 47; + + AddGoldenButtonLabeled( x, y, 1, "Rules" ); y += 22; + AddGoldenButtonLabeled( x, y, 2, "Start" ); y += 22; + AddGoldenButtonLabeled( x, y, 3, "Add Participant" ); y += 30; + + AddHtml( 35, y, 230, 20, Center( "Participants" ), false, false ); y += 22; + + for ( int i = 0; i < context.Participants.Count; ++i ) + { + Participant p = (Participant)context.Participants[i]; + + AddGoldenButtonLabeled( x, y, 4 + i, String.Format( p.Count == 1 ? "Player {0}: {3}" : "Team {0}: {1}/{2}: {3}", 1 + i, p.FilledSlots, p.Count, p.NameList ) ); y += 22; + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( !m_Context.Registered ) + return; + + int index = info.ButtonID; + + switch ( index ) + { + case -1: // CloseGump + { + break; + } + case 0: // closed + { + m_Context.Unregister(); + break; + } + case 1: // Rules + { + //m_From.SendGump( new RulesetGump( m_From, m_Context.Ruleset, m_Context.Ruleset.Layout, m_Context ) ); + m_From.SendGump( new PickRulesetGump( m_From, m_Context, m_Context.Ruleset ) ); + break; + } + case 2: // Start + { + if ( m_Context.CheckFull() ) + { + m_Context.CloseAllGumps(); + m_Context.SendReadyUpGump(); + //m_Context.SendReadyGump(); + } + else + { + m_From.SendMessage( "You cannot start the duel before all participating players have been assigned." ); + m_From.SendGump( new DuelContextGump( m_From, m_Context ) ); + } + + break; + } + case 3: // New Participant + { + if ( m_Context.Participants.Count < 10 ) + m_Context.Participants.Add( new Participant( m_Context, 1 ) ); + else + m_From.SendMessage( "The number of participating parties may not be increased further." ); + + m_From.SendGump( new DuelContextGump( m_From, m_Context ) ); + + break; + } + default: // Participant + { + index -= 4; + + if ( index >= 0 && index < m_Context.Participants.Count ) + m_From.SendGump( new ParticipantGump( m_From, m_Context, (Participant)m_Context.Participants[index] ) ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs b/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs new file mode 100644 index 0000000..891bedb --- /dev/null +++ b/Scripts/Engines/ConPVP/DuelTeleporterAddon.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.ConPVP +{ + public enum DuelTeleporterType + { + Squares = 6095, + Buds = 6104, + Flowers = 6113, + Spikes = 6122, + Arrows = 6140, + Links = 6149 + } + + public class DuelTeleporterAddon : BaseAddon + { + [CommandProperty( AccessLevel.GameMaster )] + public DuelTeleporterType Type + { + get + { + if ( Components.Count > 0 ) + return (DuelTeleporterType)(((Item)Components[0]).ItemID); + + return DuelTeleporterType.Squares; + } + set + { + for ( int i = 0; i < Components.Count && i < 9; ++i ) + ((Item)Components[i]).ItemID = i + (int)value; + } + } + + [Constructable] + public DuelTeleporterAddon() : this( DuelTeleporterType.Squares ) + { + } + + [Constructable] + public DuelTeleporterAddon( DuelTeleporterType type ) + { + int itemID = (int)type; + + AddComponent( new AddonComponent( itemID + 0 ), -1, -1, 5 ); + AddComponent( new AddonComponent( itemID + 1 ), -1, 0, 5 ); + AddComponent( new AddonComponent( itemID + 2 ), 0, -1, 5 ); + AddComponent( new AddonComponent( itemID + 3 ), -1, +1, 5 ); + AddComponent( new AddonComponent( itemID + 4 ), 0, 0, 5 ); + AddComponent( new AddonComponent( itemID + 5 ), +1, -1, 5 ); + AddComponent( new AddonComponent( itemID + 6 ), 0, +1, 5 ); + AddComponent( new AddonComponent( itemID + 7 ), +1, 0, 5 ); + AddComponent( new AddonComponent( itemID + 8 ), +1, +1, 5 ); + + AddComponent( new AddonComponent( 0x759 ), -2, -2, 0 ); + AddComponent( new AddonComponent( 0x75A ), +2, +2, 0 ); + AddComponent( new AddonComponent( 0x75B ), -2, +2, 0 ); + AddComponent( new AddonComponent( 0x75C ), +2, -2, 0 ); + + AddComponent( new AddonComponent( 0x751 ), -1, +2, 0 ); + AddComponent( new AddonComponent( 0x751 ), 0, +2, 0 ); + AddComponent( new AddonComponent( 0x751 ), +1, +2, 0 ); + + AddComponent( new AddonComponent( 0x752 ), +2, -1, 0 ); + AddComponent( new AddonComponent( 0x752 ), +2, 0, 0 ); + AddComponent( new AddonComponent( 0x752 ), +2, +1, 0 ); + + AddComponent( new AddonComponent( 0x753 ), -1, -2, 0 ); + AddComponent( new AddonComponent( 0x753 ), 0, -2, 0 ); + AddComponent( new AddonComponent( 0x753 ), +1, -2, 0 ); + + AddComponent( new AddonComponent( 0x754 ), -2, -1, 0 ); + AddComponent( new AddonComponent( 0x754 ), -2, 0, 0 ); + AddComponent( new AddonComponent( 0x754 ), -2, +1, 0 ); + } + + public DuelTeleporterAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Games/EventGame.cs b/Scripts/Engines/ConPVP/Games/EventGame.cs new file mode 100644 index 0000000..8acc77a --- /dev/null +++ b/Scripts/Engines/ConPVP/Games/EventGame.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Items; + +namespace Server.Engines.ConPVP +{ + public abstract class EventController : Item + { + public abstract EventGame Construct( DuelContext dc ); + + public abstract string Title { get; } + + public abstract string GetTeamName( int teamID ); + + public EventController() + : base( 0x1B7A ) + { + Visible = false; + Movable = false; + } + + public EventController( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + from.SendGump( new Gumps.PropertiesGump( from, this ) ); + } + } + + public abstract class EventGame + { + protected DuelContext m_Context; + + public DuelContext Context { get { return m_Context; } } + + public virtual bool FreeConsume { get { return true; } } + + public EventGame( DuelContext context ) + { + m_Context = context; + } + + public virtual bool OnDeath( Mobile mob, Container corpse ) + { + return true; + } + + public virtual bool CantDoAnything( Mobile mob ) + { + return false; + } + + public virtual void OnStart() + { + } + + public virtual void OnStop() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Ladder.cs b/Scripts/Engines/ConPVP/Ladder.cs new file mode 100644 index 0000000..d6a97d0 --- /dev/null +++ b/Scripts/Engines/ConPVP/Ladder.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Engines.ConPVP +{ + public class LadderController : Item + { + private Ladder m_Ladder; + + //[CommandProperty( AccessLevel.GameMaster )] + public Ladder Ladder{ get{ return m_Ladder; } set{} } + + public override string DefaultName + { + get { return "ladder controller"; } + } + + [Constructable] + public LadderController() : base( 0x1B7A ) + { + Visible = false; + Movable = false; + + m_Ladder = new Ladder(); + + if ( Ladder.Instance == null ) + Ladder.Instance = m_Ladder; + } + + public override void Delete() + { + if ( Ladder.Instance != m_Ladder ) + base.Delete(); + } + + public LadderController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + m_Ladder.Serialize( writer ); + + writer.Write( (bool) ( Server.Engines.ConPVP.Ladder.Instance == m_Ladder ) ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Ladder = new Ladder( reader ); + + if ( version < 1 || reader.ReadBool() ) + Server.Engines.ConPVP.Ladder.Instance = m_Ladder; + + break; + } + } + } + } + + public class Ladder + { + private static int[] m_ShortLevels = new int[] + { + 1, + 2, + 3, 3, + 4, 4, + 5, 5, 5, + 6, 6, 6, + 7, 7, 7, 7, + 8, 8, 8, 8, + 9, 9, 9, 9, 9 + }; + + public static int GetLevel( int xp ) + { + if ( xp >= 22500 ) + return 50; + else if ( xp >= 2500 ) + return (10 + ((xp - 2500) / 500)); + else if ( xp < 0 ) + xp = 0; + + return m_ShortLevels[xp / 100]; + } + + private static int[] m_BaseXP = new int[] + { + 0, 100, 200, 400, 600, 900, 1200, 1600, 2000, 2500 + }; + + public static void GetLevelInfo( int level, out int xpBase, out int xpAdvance ) + { + if ( level >= 10 ) + { + xpBase = 2500 + ((level-10)*500); + xpAdvance = 500; + } + else + { + xpBase = m_BaseXP[level-1]; + xpAdvance = m_BaseXP[level] - xpBase; + } + } + + private static int[] m_LossFactors = new int[] + { + 10, + 11, 11, + 25, 25, + 43, 43, + 67, 67 + }; + + public static int GetLossFactor( int level ) + { + if ( level >= 10 ) + return 100; + + return m_LossFactors[level - 1]; + } + + private static int[,] m_OffsetScalar = new int[,] + { + /* { win, los } */ + /* -6 */ { 175, 25 }, + /* -5 */ { 165, 35 }, + /* -4 */ { 155, 45 }, + /* -3 */ { 145, 55 }, + /* -2 */ { 130, 70 }, + /* -1 */ { 115, 85 }, + /* 0 */ { 100, 100 }, + /* +1 */ { 90, 110 }, + /* +2 */ { 80, 120 }, + /* +3 */ { 70, 130 }, + /* +4 */ { 60, 140 }, + /* +5 */ { 50, 150 }, + /* +6 */ { 40, 160 } + }; + + public static int GetOffsetScalar( int ourLevel, int theirLevel, bool win ) + { + int x = ourLevel - theirLevel; + + if ( x < -6 || x > +6 ) + return 0; + + int y = win ? 0 : 1; + + return m_OffsetScalar[x+6, y]; + } + + public static int GetExperienceGain( LadderEntry us, LadderEntry them, bool weWon ) + { + if ( us == null || them == null ) + return 0; + + int ourLevel = GetLevel( us.Experience ); + int theirLevel = GetLevel( them.Experience ); + + int scalar = GetOffsetScalar( ourLevel, theirLevel, weWon ); + + if ( scalar == 0 ) + return 0; + + int xp = 25 * scalar; + + if ( !weWon ) + xp = (xp * GetLossFactor( ourLevel )) / 100; + + xp /= 100; + + if ( xp <= 0 ) + xp = 1; + + return xp * (weWon ? 1 : -1); + } + + private Hashtable m_Table; + private ArrayList m_Entries; + + public ArrayList ToArrayList() + { + return m_Entries; + } + + private int Swap( int idx, int newIdx ) + { + object hold = m_Entries[idx]; + + m_Entries[idx] = m_Entries[newIdx]; + m_Entries[newIdx] = hold; + + ((LadderEntry)m_Entries[idx]).Index = idx; + ((LadderEntry)m_Entries[newIdx]).Index = newIdx; + + return newIdx; + } + + public void UpdateEntry( LadderEntry entry ) + { + int index = entry.Index; + + if ( index >= 0 && index < m_Entries.Count ) + { + // sanity + + int c; + + while ( (index - 1) >= 0 && (c = entry.CompareTo( m_Entries[index - 1] )) < 0 ) + index = Swap( index, index - 1 ); + + while ( (index + 1) < m_Entries.Count && (c = entry.CompareTo( m_Entries[index + 1] )) > 0 ) + index = Swap( index, index + 1 ); + } + } + + public LadderEntry Find( Mobile mob ) + { + LadderEntry entry = (LadderEntry) m_Table[mob]; + + if ( entry == null ) + { + m_Table[mob] = entry = new LadderEntry( mob, this ); + entry.Index = m_Entries.Count; + m_Entries.Add( entry ); + } + + return entry; + } + + public LadderEntry FindNoCreate( Mobile mob ) + { + return m_Table[mob] as LadderEntry; + } + + private static Ladder m_Instance; + + public static Ladder Instance{ get{ return m_Instance; } set{ m_Instance = value; } } + + public Ladder() + { + m_Table = new Hashtable(); + m_Entries = new ArrayList(); + } + + public Ladder( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + case 0: + { + int count = reader.ReadEncodedInt(); + + m_Table = new Hashtable( count ); + m_Entries = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + LadderEntry entry = new LadderEntry( reader, this, version ); + + if ( entry.Mobile != null ) + { + m_Table[entry.Mobile] = entry; + entry.Index = m_Entries.Count; + m_Entries.Add( entry ); + } + } + + if ( version == 0 ) + { + m_Entries.Sort(); + + for ( int i = 0; i < m_Entries.Count; ++i ) + { + LadderEntry entry = (LadderEntry)m_Entries[i]; + + entry.Index = i; + } + } + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 1 ); // version; + + writer.WriteEncodedInt( (int) m_Entries.Count ); + + for ( int i = 0; i < m_Entries.Count; ++i ) + ((LadderEntry)m_Entries[i]).Serialize( writer ); + } + } + + public class LadderEntry : IComparable + { + private Mobile m_Mobile; + private int m_Experience; + private int m_Wins; + private int m_Losses; + private int m_Index; + private Ladder m_Ladder; + + public Mobile Mobile{ get{ return m_Mobile; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public int Experience{ get{ return m_Experience; } set{ m_Experience = value; m_Ladder.UpdateEntry(this); } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public int Wins{ get{ return m_Wins; } set{ m_Wins = value; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public int Losses{ get{ return m_Losses; } set{ m_Losses = value; } } + + public int Index{ get{ return m_Index; } set{ m_Index = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Rank{ get{ return m_Index; } } + + public LadderEntry( Mobile mob, Ladder ladder ) + { + m_Ladder = ladder; + m_Mobile = mob; + } + + public LadderEntry( GenericReader reader, Ladder ladder, int version ) + { + m_Ladder = ladder; + + switch ( version ) + { + case 1: + case 0: + { + m_Mobile = reader.ReadMobile(); + m_Experience = reader.ReadEncodedInt(); + m_Wins = reader.ReadEncodedInt(); + m_Losses = reader.ReadEncodedInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (Mobile) m_Mobile ); + writer.WriteEncodedInt( (int) m_Experience ); + writer.WriteEncodedInt( (int) m_Wins ); + writer.WriteEncodedInt( (int) m_Losses ); + } + + public int CompareTo( object obj ) + { + return ((LadderEntry)obj).m_Experience - m_Experience; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/LadderGump.cs b/Scripts/Engines/ConPVP/LadderGump.cs new file mode 100644 index 0000000..ab0d526 --- /dev/null +++ b/Scripts/Engines/ConPVP/LadderGump.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class LadderItem : Item + { + private LadderController m_Ladder; + + [CommandProperty( AccessLevel.GameMaster )] + public LadderController Ladder + { + get{ return m_Ladder; } + set{ m_Ladder = value; } + } + + public override string DefaultName + { + get { return "1v1 leaderboard"; } + } + + [Constructable] + public LadderItem() : base( 0x117F ) + { + Movable = false; + } + + public LadderItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.Write( (Item) m_Ladder ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Ladder = reader.ReadItem() as LadderController; + break; + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + { + Ladder ladder = Server.Engines.ConPVP.Ladder.Instance; + + if ( m_Ladder != null ) + ladder = m_Ladder.Ladder; + + if ( ladder != null ) + { + from.CloseGump( typeof( LadderGump ) ); + from.SendGump( new LadderGump( ladder, 0 ) ); + } + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that + } + } + + public class LadderGump : Gump + { + private Ladder m_Ladder; + private int m_Page; + + public LadderGump( Ladder ladder ) : this( ladder, 0 ) + { + } + + public static string Rank( int num ) + { + string numStr = num.ToString( "N0" ); + + if ( (num%100) > 10 && (num%100) < 20 ) + return numStr + "th"; + + switch ( num % 10 ) + { + case 1: return numStr + "st"; + case 2: return numStr + "nd"; + case 3: return numStr + "rd"; + default: return numStr + "th"; + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 1 && m_Page > 0 ) + from.SendGump( new LadderGump( m_Ladder, m_Page - 1 ) ); + else if ( info.ButtonID == 2 && ((m_Page+1)*15) lc ) + end = lc; + + int ct = end-start; + + int height = 12 + 20 + (ct*20) + 23 + 12; + + AddBackground( 0, 0, 499, height, 0x2436 ); + + for ( int i = start + 1; i < end; i += 2 ) + AddImageTiled( 12, 32 + ((i - start) * 20), 475, 20, 0x2430 ); + + AddAlphaRegion( 10, 10, 479, height - 20 ); + + if ( page > 0 ) + AddButton( 446, height-12-2-16, 0x15E3, 0x15E7, 1, GumpButtonType.Reply, 0 ); + else + AddImage( 446, height-12-2-16, 0x2626 ); + + if ( ((page+1)*15)= xpAdvance ) + width = 109; // level 50 + else + width = ((109 * xpOffset) + (xpAdvance / 2)) / (xpAdvance - 1); + + //AddImageTiled( 21, y + 6, width, 8, 0x2617 ); + AddImageTiled( x + 3, y + 4, width, 11, 0x806 ); + AddBorderedText( x, y, 115, Center( level.ToString() ), 0xFFFFFF, 0 ); + x += 115; + + Mobile mob = entry.Mobile; + + if ( mob.Guild != null ) + AddBorderedText( x, y, 50, Center( mob.Guild.Abbreviation ), 0xFFFFFF, 0 ); + + x += 50; + + AddBorderedText( x + 5, y, 115 - 5, ( mob.Name ), 0xFFFFFF, 0 ); + x += 115; + + AddBorderedText( x, y, 60, Center( entry.Wins.ToString() ), 0xFFFFFF, 0 ); + x += 60; + + AddBorderedText( x, y, 60, Center( entry.Losses.ToString() ), 0xFFFFFF, 0 ); + x += 60; + + //AddBorderedText( 292 + 15, y, 115 - 30, String.Format( "{0}
/
{1}
", entry.Wins, entry.Losses ), 0xFFC000, 0 ); + } + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private void AddBorderedText( int x, int y, int width, string text, int color, int borderColor ) + { + /*AddColoredText( x - 1, y, width, text, borderColor ); + AddColoredText( x + 1, y, width, text, borderColor ); + AddColoredText( x, y - 1, width, text, borderColor ); + AddColoredText( x, y + 1, width, text, borderColor );*/ + /*AddColoredText( x - 1, y - 1, width, text, borderColor ); + AddColoredText( x + 1, y + 1, width, text, borderColor );*/ + AddColoredText( x, y, width, text, color ); + } + + private void AddColoredText( int x, int y, int width, string text, int color ) + { + if ( color == 0 ) + AddHtml( x, y, width, 20, text, false, false ); + else + AddHtml( x, y, width, 20, Color( text, color ), false, false ); + } + + private int m_ColumnX = 12; + + private void AddColumnHeader( int width, string name ) + { + AddBackground( m_ColumnX, 12, width, 20, 0x242C ); + AddImageTiled( m_ColumnX + 2, 14, width - 4, 16, 0x2430 ); + AddBorderedText( m_ColumnX, 13, width, Center( name ), 0xFFFFFF, 0 ); + + m_ColumnX += width; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Participant.cs b/Scripts/Engines/ConPVP/Participant.cs new file mode 100644 index 0000000..ef5755b --- /dev/null +++ b/Scripts/Engines/ConPVP/Participant.cs @@ -0,0 +1,236 @@ +using System; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.ConPVP +{ + public class Participant + { + private DuelContext m_Context; + private DuelPlayer[] m_Players; + private TournyParticipant m_TournyPart; + + public int Count{ get{ return m_Players.Length; } } + public DuelPlayer[] Players{ get{ return m_Players; } } + public DuelContext Context{ get{ return m_Context; } } + public TournyParticipant TournyPart{ get{ return m_TournyPart; } set{ m_TournyPart = value; } } + + public DuelPlayer Find( Mobile mob ) + { + if ( mob is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)mob; + + if ( pm.DuelContext == m_Context && pm.DuelPlayer.Participant == this ) + return pm.DuelPlayer; + + return null; + } + + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] != null && m_Players[i].Mobile == mob ) + return m_Players[i]; + } + + return null; + } + + public bool Contains( Mobile mob ) + { + return ( Find( mob ) != null ); + } + + public void Broadcast( int hue, string message, string nonLocalOverhead, string localOverhead ) + { + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] != null ) + { + if ( message != null ) + m_Players[i].Mobile.SendMessage( hue, message ); + + if ( nonLocalOverhead != null ) + m_Players[i].Mobile.NonlocalOverheadMessage( Network.MessageType.Regular, hue, false, String.Format( nonLocalOverhead, m_Players[i].Mobile.Name, m_Players[i].Mobile.Female ? "her" : "his" ) ); + + if ( localOverhead != null ) + m_Players[i].Mobile.LocalOverheadMessage( Network.MessageType.Regular, hue, false, localOverhead ); + } + } + } + + public int FilledSlots + { + get + { + int count = 0; + + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] != null ) + ++count; + } + + return count; + } + } + + public bool HasOpenSlot + { + get + { + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] == null ) + return true; + } + + return false; + } + } + + public bool Eliminated + { + get + { + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] != null && !m_Players[i].Eliminated ) + return false; + } + + return true; + } + } + + public string NameList + { + get + { + StringBuilder sb = new StringBuilder(); + + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] == null ) + continue; + + Mobile mob = m_Players[i].Mobile; + + if ( sb.Length > 0 ) + sb.Append( ", " ); + + sb.Append( mob.Name ); + } + + if ( sb.Length == 0 ) + return "Empty"; + + return sb.ToString(); + } + } + + public void Nullify( DuelPlayer player ) + { + if ( player == null ) + return; + + int index = Array.IndexOf( m_Players, player ); + + if ( index == -1 ) + return; + + m_Players[index] = null; + } + + public void Remove( DuelPlayer player ) + { + if ( player == null ) + return; + + int index = Array.IndexOf( m_Players, player ); + + if ( index == -1 ) + return; + + DuelPlayer[] old = m_Players; + m_Players = new DuelPlayer[old.Length - 1]; + + for ( int i = 0; i < index; ++i ) + m_Players[i] = old[i]; + + for ( int i = index + 1; i < old.Length; ++i ) + m_Players[i - 1] = old[i]; + } + + public void Remove( Mobile player ) + { + Remove( Find( player ) ); + } + + public void Add( Mobile player ) + { + if ( Contains( player ) ) + return; + + for ( int i = 0; i < m_Players.Length; ++i ) + { + if ( m_Players[i] == null ) + { + m_Players[i] = new DuelPlayer( player, this ); + return; + } + } + + Resize( m_Players.Length + 1 ); + m_Players[m_Players.Length - 1] = new DuelPlayer( player, this ); + } + + public void Resize( int count ) + { + DuelPlayer[] old = m_Players; + m_Players = new DuelPlayer[count]; + + if ( old != null ) + { + int ct = 0; + + for ( int i = 0; i < old.Length; ++i ) + { + if ( old[i] != null && ct < count ) + m_Players[ct++] = old[i]; + } + } + } + + public Participant( DuelContext context, int count ) + { + m_Context = context; + //m_Stakes = new StakesContainer( context, this ); + Resize( count ); + } + } + + public class DuelPlayer + { + private Mobile m_Mobile; + private bool m_Eliminated; + private bool m_Ready; + private Participant m_Participant; + + public Mobile Mobile{ get{ return m_Mobile; } } + public bool Ready{ get{ return m_Ready; } set{ m_Ready = value; } } + public bool Eliminated{ get{ return m_Eliminated; } set{ m_Eliminated = value; if ( m_Participant.Context.m_Tournament != null && m_Eliminated ){ m_Participant.Context.m_Tournament.OnEliminated( this ); m_Mobile.SendEverything(); } } } + public Participant Participant{ get{ return m_Participant; } set{ m_Participant = value; } } + + public DuelPlayer( Mobile mob, Participant p ) + { + m_Mobile = mob; + m_Participant = p; + + if ( mob is PlayerMobile ) + ((PlayerMobile)mob).DuelPlayer = this; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/ParticipantGump.cs b/Scripts/Engines/ConPVP/ParticipantGump.cs new file mode 100644 index 0000000..8000ffd --- /dev/null +++ b/Scripts/Engines/ConPVP/ParticipantGump.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Engines.ConPVP +{ + public class ParticipantGump : Gump + { + private Mobile m_From; + private DuelContext m_Context; + private Participant m_Participant; + + public Mobile From{ get{ return m_From; } } + public DuelContext Context{ get{ return m_Context; } } + public Participant Participant{ get{ return m_Participant; } } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public void AddGoldenButton( int x, int y, int bid ) + { + AddButton( x , y , 0xD2, 0xD2, bid, GumpButtonType.Reply, 0 ); + AddButton( x+3, y+3, 0xD8, 0xD8, bid, GumpButtonType.Reply, 0 ); + } + + public void AddGoldenButtonLabeled( int x, int y, int bid, string text ) + { + AddGoldenButton( x, y, bid ); + AddHtml( x + 25, y, 200, 20, text, false, false ); + } + + public ParticipantGump( Mobile from, DuelContext context, Participant p ) : base( 50, 50 ) + { + m_From = from; + m_Context = context; + m_Participant = p; + + from.CloseGump( typeof( RulesetGump ) ); + from.CloseGump( typeof( DuelContextGump ) ); + from.CloseGump( typeof( ParticipantGump ) ); + + int count = p.Players.Length; + + if ( count < 4 ) + count = 4; + + AddPage( 0 ); + + int height = 35 + 10 + 22 + 22 + 30 + 22 + 2 + (count * 22) + 2 + 30; + + AddBackground( 0, 0, 300, height, 9250 ); + AddBackground( 10, 10, 280, height - 20, 0xDAC ); + + AddButton( 240, 25, 0xFB1, 0xFB3, 3, GumpButtonType.Reply, 0 ); + + //AddButton( 223, 54, 0x265A, 0x265A, 4, GumpButtonType.Reply, 0 ); + + AddHtml( 35, 25, 230, 20, Center( "Participant Setup" ), false, false ); + + int x = 35; + int y = 47; + + AddHtml( x, y, 200, 20, String.Format( "Team Size: {0}", p.Players.Length ), false, false ); y += 22; + + AddGoldenButtonLabeled( x + 20, y, 1, "Increase" ); y += 22; + AddGoldenButtonLabeled( x + 20, y, 2, "Decrease" ); y += 30; + + AddHtml( 35, y, 230, 20, Center( "Players" ), false, false ); y += 22; + + for ( int i = 0; i < p.Players.Length; ++i ) + { + DuelPlayer pl = p.Players[i]; + + AddGoldenButtonLabeled( x, y, 5 + i, String.Format( "{0}: {1}", 1 + i, pl == null ? "Empty" : pl.Mobile.Name ) ); y += 22; + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( !m_Context.Registered ) + return; + + int bid = info.ButtonID; + + if ( bid == 0 ) + { + m_From.SendGump( new DuelContextGump( m_From, m_Context ) ); + } + else if ( bid == 1 ) + { + if ( m_Participant.Count < 8 ) + m_Participant.Resize( m_Participant.Count + 1 ); + else + m_From.SendMessage( "You may not raise the team size any further." ); + + m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) ); + } + else if ( bid == 2 ) + { + if ( m_Participant.Count > 1 && m_Participant.Count > m_Participant.FilledSlots ) + m_Participant.Resize( m_Participant.Count - 1 ); + else + m_From.SendMessage( "You may not lower the team size any further." ); + + m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) ); + } + else if ( bid == 3 ) + { + if ( m_Participant.FilledSlots > 0 ) + { + m_From.SendMessage( "There is at least one currently active player. You must remove them first." ); + m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) ); + } + else if ( m_Context.Participants.Count > 2 ) + { + /*Container cont = m_Participant.Stakes; + + if ( cont != null ) + cont.Delete();*/ + + m_Context.Participants.Remove( m_Participant ); + m_From.SendGump( new DuelContextGump( m_From, m_Context ) ); + } + else + { + m_From.SendMessage( "Duels must have at least two participating parties." ); + m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) ); + } + } + /*else if ( bid == 4 ) + { + m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) ); + + Container cont = m_Participant.Stakes; + + if ( cont != null && !cont.Deleted ) + { + cont.DisplayTo( m_From ); + + Item[] checks = cont.FindItemsByType( typeof( BankCheck ) ); + + int gold = cont.TotalGold; + + for ( int i = 0; i < checks.Length; ++i ) + gold += ((BankCheck)checks[i]).Worth; + + m_From.SendMessage( "This container has {0} item{1} and {2} stone{3}. In gold or check form there is a total of {4:D}gp.", cont.TotalItems, cont.TotalItems==1?"":"s", cont.TotalWeight, cont.TotalWeight==1?"":"s", gold ); + } + }*/ + else + { + bid -= 5; + + if ( bid >= 0 && bid < m_Participant.Players.Length ) + { + if ( m_Participant.Players[bid] == null ) + { + m_From.Target = new ParticipantTarget( m_Context, m_Participant, bid ); + m_From.SendMessage( "Target a player." ); + } + else + { + m_Participant.Players[bid].Mobile.SendMessage( "You have been removed from the duel." ); + + if ( m_Participant.Players[bid].Mobile is PlayerMobile ) + ((PlayerMobile)(m_Participant.Players[bid].Mobile)).DuelPlayer = null; + + m_Participant.Players[bid] = null; + m_From.SendMessage( "They have been removed from the duel." ); + m_From.SendGump( new ParticipantGump( m_From, m_Context, m_Participant ) ); + } + } + } + } + + private class ParticipantTarget : Target + { + private DuelContext m_Context; + private Participant m_Participant; + private int m_Index; + + public ParticipantTarget( DuelContext context, Participant p, int index ) : base( 12, false, TargetFlags.None ) + { + m_Context = context; + m_Participant = p; + m_Index = index; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Context.Registered ) + return; + + int index = m_Index; + + if ( index < 0 || index >= m_Participant.Players.Length ) + return; + + Mobile mob = targeted as Mobile; + + if ( mob == null ) + { + from.SendMessage( "That is not a player." ); + } + else if ( !mob.Player ) + { + if ( mob.Body.IsHuman ) + mob.SayTo( from, 1005443 ); // Nay, I would rather stay here and watch a nail rust. + else + mob.SayTo( from, 1005444 ); // The creature ignores your offer. + } + else if ( AcceptDuelGump.IsIgnored( mob, from ) || mob.Blessed ) + { + from.SendMessage( "They ignore your offer." ); + } + else + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + return; + + if ( pm.DuelContext != null ) + from.SendMessage( "{0} cannot fight because they are already assigned to another duel.", pm.Name ); + else if ( DuelContext.CheckCombat( pm ) ) + from.SendMessage( "{0} cannot fight because they have recently been in combat with another player.", pm.Name ); + else if ( mob.HasGump( typeof( AcceptDuelGump ) ) ) + from.SendMessage( "{0} has already been offered a duel." ); + else + { + from.SendMessage( "You send {0} to {1}.", m_Participant.Find( from ) == null ? "a challenge" : "an invitation", mob.Name ); + mob.SendGump( new AcceptDuelGump( from, mob, m_Context, m_Participant, m_Index ) ); + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + from.SendGump( new ParticipantGump( from, m_Context, m_Participant ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/PickRulesetGump.cs b/Scripts/Engines/ConPVP/PickRulesetGump.cs new file mode 100644 index 0000000..978d23b --- /dev/null +++ b/Scripts/Engines/ConPVP/PickRulesetGump.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class PickRulesetGump : Gump + { + private Mobile m_From; + private DuelContext m_Context; + private Ruleset m_Ruleset; + private Ruleset[] m_Defaults; + private Ruleset[] m_Flavors; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public PickRulesetGump( Mobile from, DuelContext context, Ruleset ruleset ) : base( 50, 50 ) + { + m_From = from; + m_Context = context; + m_Ruleset = ruleset; + m_Defaults = ruleset.Layout.Defaults; + m_Flavors = ruleset.Layout.Flavors; + + int height = 25 + 20 + ((m_Defaults.Length + 1) * 22) + 6 + 20 + (m_Flavors.Length * 22) + 25; + + AddPage( 0 ); + + AddBackground( 0, 0, 260, height, 9250 ); + AddBackground( 10, 10, 240, height - 20, 0xDAC ); + + AddHtml( 35, 25, 190, 20, Center( "Rules" ), false, false ); + + int y = 25 + 20; + + for ( int i = 0; i < m_Defaults.Length; ++i ) + { + Ruleset cur = m_Defaults[i]; + + AddHtml( 35 + 14, y, 176, 20, cur.Title, false, false ); + + if ( ruleset.Base == cur && !ruleset.Changed ) + AddImage( 35, y + 4, 0x939 ); + else if ( ruleset.Base == cur ) + AddButton( 35, y + 4, 0x93A, 0x939, 2 + i, GumpButtonType.Reply, 0 ); + else + AddButton( 35, y + 4, 0x938, 0x939, 2 + i, GumpButtonType.Reply, 0 ); + + y += 22; + } + + AddHtml( 35 + 14, y, 176, 20, "Custom", false, false ); + AddButton( 35, y + 4, ruleset.Changed ? 0x939 : 0x938, 0x939, 1, GumpButtonType.Reply, 0 ); + + y += 22; + y += 6; + + AddHtml( 35, y, 190, 20, Center( "Flavors" ), false, false ); + y += 20; + + for ( int i = 0; i < m_Flavors.Length; ++i ) + { + Ruleset cur = m_Flavors[i]; + + AddHtml( 35 + 14, y, 176, 20, cur.Title, false, false ); + + if ( ruleset.Flavors.Contains( cur ) ) + AddButton( 35, y + 4, 0x939, 0x938, 2 + m_Defaults.Length + i, GumpButtonType.Reply, 0 ); + else + AddButton( 35, y + 4, 0x938, 0x939, 2 + m_Defaults.Length + i, GumpButtonType.Reply, 0 ); + + y += 22; + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Context != null && !m_Context.Registered ) + return; + + switch ( info.ButtonID ) + { + case 0: // closed + { + if ( m_Context != null ) + m_From.SendGump( new DuelContextGump( m_From, m_Context ) ); + + break; + } + case 1: // customize + { + m_From.SendGump( new RulesetGump( m_From, m_Ruleset, m_Ruleset.Layout, m_Context ) ); + break; + } + default: + { + int idx = info.ButtonID - 2; + + if ( idx >= 0 && idx < m_Defaults.Length ) + { + m_Ruleset.ApplyDefault( m_Defaults[idx] ); + m_From.SendGump( new PickRulesetGump( m_From, m_Context, m_Ruleset ) ); + } + else + { + idx -= m_Defaults.Length; + + if ( idx >= 0 && idx < m_Flavors.Length ) + { + if ( m_Ruleset.Flavors.Contains( m_Flavors[idx] ) ) + m_Ruleset.RemoveFlavor( m_Flavors[idx] ); + else + m_Ruleset.AddFlavor( m_Flavors[idx] ); + + m_From.SendGump( new PickRulesetGump( m_From, m_Context, m_Ruleset ) ); + } + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Preferences.cs b/Scripts/Engines/ConPVP/Preferences.cs new file mode 100644 index 0000000..26e830a --- /dev/null +++ b/Scripts/Engines/ConPVP/Preferences.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class PreferencesController : Item + { + private Preferences m_Preferences; + + //[CommandProperty( AccessLevel.GameMaster )] + public Preferences Preferences{ get{ return m_Preferences; } set{} } + + public override string DefaultName + { + get { return "preferences controller"; } + } + + [Constructable] + public PreferencesController() : base( 0x1B7A ) + { + Visible = false; + Movable = false; + + m_Preferences = new Preferences(); + + if ( Preferences.Instance == null ) + Preferences.Instance = m_Preferences; + else + Delete(); + } + + public override void Delete() + { + if ( Preferences.Instance != m_Preferences ) + base.Delete(); + } + + public PreferencesController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + m_Preferences.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Preferences = new Preferences( reader ); + Preferences.Instance = m_Preferences; + break; + } + } + } + } + + public class Preferences + { + private ArrayList m_Entries; + private Hashtable m_Table; + + public ArrayList Entries{ get{ return m_Entries; } } + + public PreferencesEntry Find( Mobile mob ) + { + PreferencesEntry entry = (PreferencesEntry) m_Table[mob]; + + if ( entry == null ) + { + m_Table[mob] = entry = new PreferencesEntry( mob, this ); + m_Entries.Add( entry ); + } + + return entry; + } + + private static Preferences m_Instance; + + public static Preferences Instance{ get{ return m_Instance; } set{ m_Instance = value; } } + + public Preferences() + { + m_Table = new Hashtable(); + m_Entries = new ArrayList(); + } + + public Preferences( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + int count = reader.ReadEncodedInt(); + + m_Table = new Hashtable( count ); + m_Entries = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + PreferencesEntry entry = new PreferencesEntry( reader, this, version ); + + if ( entry.Mobile != null ) + { + m_Table[entry.Mobile] = entry; + m_Entries.Add( entry ); + } + } + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version; + + writer.WriteEncodedInt( (int) m_Entries.Count ); + + for ( int i = 0; i < m_Entries.Count; ++i ) + ((PreferencesEntry)m_Entries[i]).Serialize( writer ); + } + } + + public class PreferencesEntry + { + private Mobile m_Mobile; + private ArrayList m_Disliked; + private Preferences m_Preferences; + + public Mobile Mobile{ get{ return m_Mobile; } } + public ArrayList Disliked{ get{ return m_Disliked; } } + + public PreferencesEntry( Mobile mob, Preferences prefs ) + { + m_Preferences = prefs; + m_Mobile = mob; + m_Disliked = new ArrayList(); + } + + public PreferencesEntry( GenericReader reader, Preferences prefs, int version ) + { + m_Preferences = prefs; + + switch ( version ) + { + case 0: + { + m_Mobile = reader.ReadMobile(); + + int count = reader.ReadEncodedInt(); + + m_Disliked = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + m_Disliked.Add( reader.ReadString() ); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (Mobile) m_Mobile ); + + writer.WriteEncodedInt( (int) m_Disliked.Count ); + + for ( int i = 0; i < m_Disliked.Count; ++i ) + writer.Write( (string) m_Disliked[i] ); + } + } + + public class PreferencesGump : Gump + { + private Mobile m_From; + private PreferencesEntry m_Entry; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Entry == null ) + return; + + if ( info.ButtonID != 1 ) + return; + + m_Entry.Disliked.Clear(); + + List arenas = Arena.Arenas; + + for ( int i = 0; i < info.Switches.Length; ++i ) + { + int idx = info.Switches[i]; + + if ( idx >= 0 && idx < arenas.Count ) + m_Entry.Disliked.Add( arenas[idx].Name ); + } + } + + public PreferencesGump( Mobile from, Preferences prefs ) : base( 50, 50 ) + { + m_From = from; + m_Entry = prefs.Find( from ); + + if ( m_Entry == null ) + return; + + List arenas = Arena.Arenas; + + AddPage( 0 ); + + int height = 12 + 20 + (arenas.Count * 31) + 24 + 12; + + AddBackground( 0, 0, 499+40-365, height, 0x2436 ); + + for ( int i = 1; i < arenas.Count; i += 2 ) + AddImageTiled( 12, 32 + (i * 31), 475+40-365, 30, 0x2430 ); + + AddAlphaRegion( 10, 10, 479+40-365, height - 20 ); + + AddColumnHeader( 35, null ); + AddColumnHeader( 115, "Arena" ); + + AddButton( 499+40-365 - 12 - 63 - 4 - 63, height - 12 - 24, 247, 248, 1, GumpButtonType.Reply, 0 ); + AddButton( 499+40-365 - 12 - 63, height - 12 - 24, 241, 242, 2, GumpButtonType.Reply, 0 ); + + for ( int i = 0; i < arenas.Count; ++i ) + { + Arena ar = arenas[i]; + + string name = ar.Name; + + if ( name == null ) + name = "(no name)"; + + int x = 12; + int y = 32 + (i * 31); + + int color = 0xCCFFCC; + + AddCheck( x + 3, y + 1, 9730, 9727, m_Entry.Disliked.Contains(name), i ); + x += 35; + + AddBorderedText( x + 5, y + 5, 115 - 5, name, color, 0 ); + x += 115; + } + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private void AddBorderedText( int x, int y, int width, string text, int color, int borderColor ) + { + /*AddColoredText( x - 1, y, width, text, borderColor ); + AddColoredText( x + 1, y, width, text, borderColor ); + AddColoredText( x, y - 1, width, text, borderColor ); + AddColoredText( x, y + 1, width, text, borderColor );*/ + /*AddColoredText( x - 1, y - 1, width, text, borderColor ); + AddColoredText( x + 1, y + 1, width, text, borderColor );*/ + AddColoredText( x, y, width, text, color ); + } + + private void AddColoredText( int x, int y, int width, string text, int color ) + { + if ( color == 0 ) + AddHtml( x, y, width, 20, text, false, false ); + else + AddHtml( x, y, width, 20, Color( text, color ), false, false ); + } + + private int m_ColumnX = 12; + + private void AddColumnHeader( int width, string name ) + { + AddBackground( m_ColumnX, 12, width, 20, 0x242C ); + AddImageTiled( m_ColumnX + 2, 14, width - 4, 16, 0x2430 ); + + if ( name != null ) + AddBorderedText( m_ColumnX, 13, width, Center( name ), 0xFFFFFF, 0 ); + + m_ColumnX += width; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/ReadyGump.cs b/Scripts/Engines/ConPVP/ReadyGump.cs new file mode 100644 index 0000000..04e27cc --- /dev/null +++ b/Scripts/Engines/ConPVP/ReadyGump.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class ReadyGump : Gump + { + private Mobile m_From; + private DuelContext m_Context; + private int m_Count; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public ReadyGump( Mobile from, DuelContext context, int count ) : base( 50, 50 ) + { + m_From = from; + m_Context = context; + m_Count = count; + + ArrayList parts = context.Participants; + + int height = 25 + 20; + + for ( int i = 0; i < parts.Count; ++i ) + { + Participant p = (Participant)parts[i]; + + height += 4; + + if ( p.Players.Length > 1 ) + height += 22; + + height += (p.Players.Length * 22); + } + + height += 25; + + Closable = false; + Dragable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 260, height, 9250 ); + AddBackground( 10, 10, 240, height - 20, 0xDAC ); + + if ( count == -1 ) + { + AddHtml( 35, 25, 190, 20, Center( "Ready" ), false, false ); + } + else + { + AddHtml( 35, 25, 190, 20, Center( "Starting" ), false, false ); + AddHtml( 35, 25, 190, 20, "
" + count.ToString(), false, false ); + } + + int y = 25 + 20; + + for ( int i = 0; i < parts.Count; ++i ) + { + Participant p = (Participant)parts[i]; + + y += 4; + + bool isAllReady = true; + int yStore = y; + int offset = 0; + + if ( p.Players.Length > 1 ) + { + AddHtml( 35 + 14, y, 176, 20, String.Format( "Participant #{0}", i + 1 ), false, false ); + y += 22; + offset = 10; + } + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + if ( pl != null && pl.Ready ) + { + AddImage( 35 + offset, y + 4, 0x939 ); + } + else + { + AddImage( 35 + offset, y + 4, 0x938 ); + isAllReady = false; + } + + string name = ( pl == null ? "(Empty)" : pl.Mobile.Name ); + + AddHtml( 35 + offset + 14, y, 166, 20, name, false, false ); + + y += 22; + } + + if ( p.Players.Length > 1 ) + AddImage( 35, yStore + 4, isAllReady ? 0x939 : 0x938 ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/ReadyUpGump.cs b/Scripts/Engines/ConPVP/ReadyUpGump.cs new file mode 100644 index 0000000..1481698 --- /dev/null +++ b/Scripts/Engines/ConPVP/ReadyUpGump.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; + +namespace Server.Engines.ConPVP +{ + public class ReadyUpGump : Gump + { + private Mobile m_From; + private DuelContext m_Context; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public void AddGoldenButton( int x, int y, int bid ) + { + AddButton( x , y , 0xD2, 0xD2, bid, GumpButtonType.Reply, 0 ); + AddButton( x+3, y+3, 0xD8, 0xD8, bid, GumpButtonType.Reply, 0 ); + } + + public ReadyUpGump( Mobile from, DuelContext context ) : base( 50, 50 ) + { + m_From = from; + m_Context = context; + + Closable = false; + AddPage( 0 ); + + if ( context.Rematch ) + { + int height = 25 + 20 + 10 + 22 + 25; + + AddBackground( 0, 0, 210, height, 9250 ); + AddBackground( 10, 10, 190, height - 20, 0xDAC ); + + AddHtml( 35, 25, 140, 20, Center( "Rematch?" ), false, false ); + + AddButton( 35, 55, 247, 248, 1, GumpButtonType.Reply, 0 ); + AddButton( 115, 55, 242, 241, 2, GumpButtonType.Reply, 0 ); + } + else + { + #region Participants + AddPage( 1 ); + + ArrayList parts = context.Participants; + + int height = 25 + 20; + + for ( int i = 0; i < parts.Count; ++i ) + { + Participant p = (Participant)parts[i]; + + height += 4; + + if ( p.Players.Length > 1 ) + height += 22; + + height += (p.Players.Length * 22); + } + + height += 10 + 22 + 25; + + AddBackground( 0, 0, 260, height, 9250 ); + AddBackground( 10, 10, 240, height - 20, 0xDAC ); + + AddHtml( 35, 25, 190, 20, Center( "Participants" ), false, false ); + + int y = 20 + 25; + + for ( int i = 0; i < parts.Count; ++i ) + { + Participant p = (Participant)parts[i]; + + y += 4; + + int offset = 0; + + if ( p.Players.Length > 1 ) + { + AddHtml( 35, y, 176, 20, String.Format( "Team #{0}", i + 1 ), false, false ); + y += 22; + offset = 10; + } + + for ( int j = 0; j < p.Players.Length; ++j ) + { + DuelPlayer pl = p.Players[j]; + + string name = ( pl == null ? "(Empty)" : pl.Mobile.Name ); + + AddHtml( 35 + offset, y, 166, 20, name, false, false ); + + y += 22; + } + } + + y += 8; + + AddHtml( 35, y, 176, 20, "Continue?", false, false ); + + y -= 2; + + AddButton( 102, y, 247, 248, 0, GumpButtonType.Page, 2 ); + AddButton( 169, y, 242, 241, 2, GumpButtonType.Reply, 0 ); + #endregion + + #region Rules + AddPage( 2 ); + + Ruleset ruleset = context.Ruleset; + Ruleset basedef = ruleset.Base; + + height = 25 + 20 + 5 + 20 + 20 + 4; + + int changes = 0; + + BitArray defs; + + if ( ruleset.Flavors.Count > 0 ) + { + defs = new BitArray( basedef.Options ); + + for ( int i = 0; i < ruleset.Flavors.Count; ++i ) + defs.Or( ((Ruleset)ruleset.Flavors[i]).Options ); + + height += ruleset.Flavors.Count * 18; + } + else + { + defs = basedef.Options; + } + + BitArray opts = ruleset.Options; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + ++changes; + } + + height += (changes * 22); + + height += 10 + 22 + 25; + + AddBackground( 0, 0, 260, height, 9250 ); + AddBackground( 10, 10, 240, height - 20, 0xDAC ); + + AddHtml( 35, 25, 190, 20, Center( "Rules" ), false, false ); + + AddHtml( 35, 50, 190, 20, String.Format( "Set: {0}", basedef.Title ), false, false ); + + y = 70; + + for ( int i = 0; i < ruleset.Flavors.Count; ++i, y += 18 ) + AddHtml( 35, y, 190, 20, String.Format( " + {0}", ((Ruleset)ruleset.Flavors[i]).Title ), false, false ); + + y += 4; + + if ( changes > 0 ) + { + AddHtml( 35, y, 190, 20, "Modifications:", false, false ); + y += 20; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + { + string name = ruleset.Layout.FindByIndex( i ); + + if ( name != null ) // sanity + { + AddImage( 35, y, opts[i] ? 0xD3 : 0xD2 ); + AddHtml( 60, y, 165, 22, name, false, false ); + } + + y += 22; + } + } + } + else + { + AddHtml( 35, y, 190, 20, "Modifications: None", false, false ); + y += 20; + } + + y += 8; + + AddHtml( 35, y, 176, 20, "Continue?", false, false ); + + y -= 2; + + AddButton( 102, y, 247, 248, 1, GumpButtonType.Reply, 0 ); + AddButton( 169, y, 242, 241, 3, GumpButtonType.Reply, 0 ); + #endregion + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( !m_Context.Registered || !m_Context.ReadyWait ) + return; + + switch ( info.ButtonID ) + { + case 1: // okay + { + PlayerMobile pm = m_From as PlayerMobile; + + if ( pm == null ) + break; + + pm.DuelPlayer.Ready = true; + m_Context.SendReadyGump(); + + break; + } + case 2: // reject participants + { + m_Context.RejectReady( m_From, "participants" ); + break; + } + case 3: // reject rules + { + m_Context.RejectReady( m_From, "rules" ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Ruleset.cs b/Scripts/Engines/ConPVP/Ruleset.cs new file mode 100644 index 0000000..856077f --- /dev/null +++ b/Scripts/Engines/ConPVP/Ruleset.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; + +namespace Server.Engines.ConPVP +{ + public class Ruleset + { + private RulesetLayout m_Layout; + private BitArray m_Options; + private string m_Title; + + private Ruleset m_Base; + private ArrayList m_Flavors = new ArrayList(); + private bool m_Changed; + + public RulesetLayout Layout{ get{ return m_Layout; } } + public BitArray Options{ get{ return m_Options; } } + public string Title{ get{ return m_Title; } set{ m_Title = value; } } + + public Ruleset Base{ get{ return m_Base; } } + public ArrayList Flavors{ get{ return m_Flavors; } } + public bool Changed{ get{ return m_Changed; } set{ m_Changed = value; } } + + public void ApplyDefault( Ruleset newDefault ) + { + m_Base = newDefault; + m_Changed = false; + + m_Options = new BitArray( newDefault.m_Options ); + + ApplyFlavorsTo( this ); + } + + public void ApplyFlavorsTo( Ruleset ruleset ) + { + for ( int i = 0; i < m_Flavors.Count; ++i ) + { + Ruleset flavor = (Ruleset)m_Flavors[i]; + + m_Options.Or( flavor.m_Options ); + } + } + + public void AddFlavor( Ruleset flavor ) + { + if ( m_Flavors.Contains( flavor ) ) + return; + + m_Flavors.Add( flavor ); + m_Options.Or( flavor.m_Options ); + } + + public void RemoveFlavor( Ruleset flavor ) + { + if ( !m_Flavors.Contains( flavor ) ) + return; + + m_Flavors.Remove( flavor ); + m_Options.And( flavor.m_Options.Not() ); + flavor.m_Options.Not(); + } + + public void SetOptionRange( string title, bool value ) + { + RulesetLayout layout = m_Layout.FindByTitle( title ); + + if ( layout == null ) + return; + + for ( int i = 0; i < layout.TotalLength; ++i ) + m_Options[i + layout.Offset] = value; + + m_Changed = true; + } + + public bool GetOption( string title, string option ) + { + int index = 0; + RulesetLayout layout = m_Layout.FindByOption( title, option, ref index ); + + if ( layout == null ) + return true; + + return m_Options[layout.Offset + index]; + } + + public void SetOption( string title, string option, bool value ) + { + int index = 0; + RulesetLayout layout = m_Layout.FindByOption( title, option, ref index ); + + if ( layout == null ) + return; + + m_Options[layout.Offset + index] = value; + + m_Changed = true; + } + + public Ruleset( RulesetLayout layout ) + { + m_Layout = layout; + m_Options = new BitArray( layout.TotalLength ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/RulesetGump.cs b/Scripts/Engines/ConPVP/RulesetGump.cs new file mode 100644 index 0000000..9895847 --- /dev/null +++ b/Scripts/Engines/ConPVP/RulesetGump.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.ConPVP +{ + public class RulesetGump : Gump + { + private Mobile m_From; + private Ruleset m_Ruleset; + private RulesetLayout m_Page; + private DuelContext m_DuelContext; + private bool m_ReadOnly; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public void AddGoldenButton( int x, int y, int bid ) + { + AddButton( x , y , 0xD2, 0xD2, bid, GumpButtonType.Reply, 0 ); + AddButton( x+3, y+3, 0xD8, 0xD8, bid, GumpButtonType.Reply, 0 ); + } + + public RulesetGump( Mobile from, Ruleset ruleset, RulesetLayout page, DuelContext duelContext ) : this( from, ruleset, page, duelContext, false ) + { + } + + public RulesetGump( Mobile from, Ruleset ruleset, RulesetLayout page, DuelContext duelContext, bool readOnly ) : base( readOnly ? 310 : 50, 50 ) + { + m_From = from; + m_Ruleset = ruleset; + m_Page = page; + m_DuelContext = duelContext; + m_ReadOnly = readOnly; + + Dragable = !readOnly; + + from.CloseGump( typeof( RulesetGump ) ); + from.CloseGump( typeof( DuelContextGump ) ); + from.CloseGump( typeof( ParticipantGump ) ); + + RulesetLayout depthCounter = page; + int depth = 0; + + while ( depthCounter != null ) + { + ++depth; + depthCounter = depthCounter.Parent; + } + + int count = page.Children.Length + page.Options.Length; + + AddPage( 0 ); + + int height = 35 + 10 + 2 + (count * 22) + 2 + 30; + + AddBackground( 0, 0, 260, height, 9250 ); + AddBackground( 10, 10, 240, height - 20, 0xDAC ); + + AddHtml( 35, 25, 190, 20, Center( page.Title ), false, false ); + + int x = 35; + int y = 47; + + for ( int i = 0; i < page.Children.Length; ++i ) + { + AddGoldenButton( x, y, 1 + i ); + AddHtml( x + 25, y, 250, 22, page.Children[i].Title, false, false ); + + y += 22; + } + + for ( int i = 0; i < page.Options.Length; ++i ) + { + bool enabled = ruleset.Options[page.Offset + i]; + + if ( readOnly ) + AddImage( x, y, enabled ? 0xD3 : 0xD2 ); + else + AddCheck( x, y, 0xD2, 0xD3, enabled, i ); + + AddHtml( x + 25, y, 250, 22, page.Options[i], false, false ); + + y += 22; + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_DuelContext != null && !m_DuelContext.Registered ) + return; + + if ( !m_ReadOnly ) + { + BitArray opts = new BitArray( m_Page.Options.Length ); + + for ( int i = 0; i < info.Switches.Length; ++i ) + { + int sid = info.Switches[i]; + + if ( sid >= 0 && sid < m_Page.Options.Length ) + opts[sid] = true; + } + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( m_Ruleset.Options[m_Page.Offset + i] != opts[i] ) + { + m_Ruleset.Options[m_Page.Offset + i] = opts[i]; + m_Ruleset.Changed = true; + } + } + } + + int bid = info.ButtonID; + + if ( bid == 0 ) + { + if ( m_Page.Parent != null ) + m_From.SendGump( new RulesetGump( m_From, m_Ruleset, m_Page.Parent, m_DuelContext, m_ReadOnly ) ); + else if ( !m_ReadOnly ) + m_From.SendGump( new PickRulesetGump( m_From, m_DuelContext, m_Ruleset ) ); + } + else + { + bid -= 1; + + if ( bid >= 0 && bid < m_Page.Children.Length ) + m_From.SendGump( new RulesetGump( m_From, m_Ruleset, m_Page.Children[bid], m_DuelContext, m_ReadOnly ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/RulesetLayout.cs b/Scripts/Engines/ConPVP/RulesetLayout.cs new file mode 100644 index 0000000..c6bf10d --- /dev/null +++ b/Scripts/Engines/ConPVP/RulesetLayout.cs @@ -0,0 +1,789 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Engines.ConPVP +{ + public class RulesetLayout + { + private static RulesetLayout m_Root; + + public static RulesetLayout Root + { + get + { + if ( m_Root == null ) + { + ArrayList entries = new ArrayList(); + + entries.Add( new RulesetLayout( "Spells", new RulesetLayout[] + { + new RulesetLayout( "1st Circle", "Spells", new string[] + { + "Reactive Armor", "Clumsy", + "Create Food", "Feeblemind", + "Heal", "Magic Arrow", + "Night Sight", "Weaken" + } ), + new RulesetLayout( "2nd Circle", "Spells", new string[] + { + "Agility", "Cunning", + "Cure", "Harm", + "Magic Trap", "Untrap", + "Protection", "Strength" + } ), + new RulesetLayout( "3rd Circle", "Spells", new string[] + { + "Bless", "Fireball", + "Magic Lock", "Poison", + "Telekinesis", "Teleport", + "Unlock Spell", "Wall of Stone" + } ), + new RulesetLayout( "4th Circle", "Spells", new string[] + { + "Arch Cure", "Arch Protection", + "Curse", "Fire Field", + "Greater Heal", "Lightning", + "Mana Drain", "Recall" + } ), + new RulesetLayout( "5th Circle", "Spells", new string[] + { + "Blade Spirits", "Dispel Field", + "Incognito", "Magic Reflection", + "Mind Blast", "Paralyze", + "Poison Field", "Summon Creature" + } ), + new RulesetLayout( "6th Circle", "Spells", new string[] + { + "Dispel", "Energy Bolt", + "Explosion", "Invisibility", + "Mark", "Mass Curse", + "Paralyze Field", "Reveal" + } ), + new RulesetLayout( "7th Circle", "Spells", new string[] + { + "Chain Lightning", "Energy Field", + "Flame Strike", "Gate Travel", + "Mana Vampire", "Mass Dispel", + "Meteor Swarm", "Polymorph" + } ), + new RulesetLayout( "8th Circle", "Spells", new string[] + { + "Earthquake", "Energy Vortex", + "Resurrection", "Air Elemental", + "Summon Daemon", "Earth Elemental", + "Fire Elemental", "Water Elemental" + } ) + } ) ); + + if ( Core.AOS ) + { + entries.Add( new RulesetLayout( "Chivalry", new string[] + { + "Cleanse by Fire", + "Close Wounds", + "Consecrate Weapon", + "Dispel Evil", + "Divine Fury", + "Enemy of One", + "Holy Light", + "Noble Sacrifice", + "Remove Curse", + "Sacred Journey" + } ) ); + + entries.Add( new RulesetLayout( "Necromancy", new string[] + { + "Animate Dead", + "Blood Oath", + "Corpse Skin", + "Curse Weapon", + "Evil Omen", + "Horrific Beast", + "Lich Form", + "Mind Rot", + "Pain Spike", + "Poison Strike", + "Strangle", + "Summon Familiar", + "Vampiric Embrace", + "Vengeful Spirit", + "Wither", + "Wraith Form" + } ) ); + + if ( Core.SE ) + { + entries.Add( new RulesetLayout( "Bushido", new string[] + { + "Confidence", + "Counter Attack", + "Evasion", + "Honorable Execution", + "Lightning Strike", + "Momentum Strike" + } ) ); + + entries.Add( new RulesetLayout( "Ninjitsu", new string[] + { + "Animal Form", + "Backstab", + "Death Strike", + "Focus Attack", + "Ki Attack", + "Mirror Image", + "Shadow Jump", + "Suprise Attack" + } ) ); + + if( Core.ML ) + { + entries.Add( new RulesetLayout( "Spellweaving", new string[] + { + "Arcane Circle", + "Arcane Empowerment", + "Attune Weapon", + "Dryad Allure", + "Essence of Wind", + "Ethereal Voyage", + "Gift of Life", + "Gift of Renewal", + "Immolating Weapon", + "Nature's Fury", + "Reaper Form", + "Summon Fey", + "Summon Fiend", + "Thunderstorm", + "Wildfire", + "Word of Death" + } ) ); + } + } + } + + if ( Core.AOS ) + { + if ( Core.SE ) + { + entries.Add( new RulesetLayout( "Combat Abilities", new string[] + { + "Stun", + "Disarm", + "Armor Ignore", + "Bleed Attack", + "Concussion Blow", + "Crushing Blow", + "Disarm", + "Dismount", + "Double Strike", + "Infectious Strike", + "Mortal Strike", + "Moving Shot", + "Paralyzing Blow", + "Shadow Strike", + "Whirlwind Attack", + "Riding Swipe", + "Frenzied Whirlwind", + "Block", + "Defense Mastery", + "Nerve Strike", + "Talon Strike", + "Feint", + "Dual Wield", + "Double Shot", + "Armor Pierce" + } ) ); + + //TODO: ADD ML ABILITIES + } + else + { + entries.Add( new RulesetLayout( "Combat Abilities", new string[] + { + "Stun", + "Disarm", + "Armor Ignore", + "Bleed Attack", + "Concussion Blow", + "Crushing Blow", + "Disarm", + "Dismount", + "Double Strike", + "Infectious Strike", + "Mortal Strike", + "Moving Shot", + "Paralyzing Blow", + "Shadow Strike", + "Whirlwind Attack" + } ) ); + } + } + else + { + entries.Add( new RulesetLayout( "Combat Abilities", new string[] + { + "Stun", + "Disarm", + "Concussion Blow", + "Crushing Blow", + "Paralyzing Blow" + } ) ); + } + + entries.Add( new RulesetLayout( "Skills", new string[] + { + "Anatomy", + "Detect Hidden", + "Evaluating Intelligence", + "Hiding", + "Poisoning", + "Snooping", + "Stealing", + "Spirit Speak", + "Stealth" + } ) ); + + if ( Core.AOS ) + { + entries.Add( new RulesetLayout( "Weapons", new string[] + { + "Magical", + "Melee", + "Ranged", + "Poisoned", + "Wrestling" + } ) ); + + entries.Add( new RulesetLayout( "Armor", new string[] + { + "Magical", + "Shields" + } ) ); + } + else + { + entries.Add( new RulesetLayout( "Weapons", new string[] + { + "Magical", + "Melee", + "Ranged", + "Poisoned", + "Wrestling", + "Runics" + } ) ); + + entries.Add( new RulesetLayout( "Armor", new string[] + { + "Magical", + "Shields", + "Colored" + } ) ); + } + + if( Core.SE ) + { + entries.Add( new RulesetLayout( "Items", new RulesetLayout[] + { + new RulesetLayout( "Potions", new string[] + { + "Agility", + "Cure", + "Explosion", + "Heal", + "Nightsight", + "Poison", + "Refresh", + "Strength" + } ) + }, + new string[] + { + "Bandages", + "Wands", + "Trapped Containers", + "Bolas", + "Mounts", + "Orange Petals", + "Shurikens", + "Fukiya Darts", + "Fire Horns" + })); + } + else + { + entries.Add( new RulesetLayout( "Items", new RulesetLayout[] + { + new RulesetLayout( "Potions", new string[] + { + "Agility", + "Cure", + "Explosion", + "Heal", + "Nightsight", + "Poison", + "Refresh", + "Strength" + } ) + }, + new string[] + { + "Bandages", + "Wands", + "Trapped Containers", + "Bolas", + "Mounts", + "Orange Petals", + "Fire Horns" + })); + } + + m_Root = new RulesetLayout( "Rules", (RulesetLayout[])entries.ToArray( typeof( RulesetLayout ) ) ); + m_Root.ComputeOffsets(); + + // Set up default rulesets + + if( !Core.AOS ) + { + + #region Mage 5x + Ruleset m5x = new Ruleset( m_Root ); + + m5x.Title = "Mage 5x"; + + m5x.SetOptionRange( "Spells", true ); + + m5x.SetOption( "Spells", "Wall of Stone", false ); + m5x.SetOption( "Spells", "Fire Field", false ); + m5x.SetOption( "Spells", "Poison Field", false ); + m5x.SetOption( "Spells", "Energy Field", false ); + m5x.SetOption( "Spells", "Reactive Armor", false ); + m5x.SetOption( "Spells", "Protection", false ); + m5x.SetOption( "Spells", "Teleport", false ); + m5x.SetOption( "Spells", "Wall of Stone", false ); + m5x.SetOption( "Spells", "Arch Protection", false ); + m5x.SetOption( "Spells", "Recall", false ); + m5x.SetOption( "Spells", "Blade Spirits", false ); + m5x.SetOption( "Spells", "Incognito", false ); + m5x.SetOption( "Spells", "Magic Reflection", false ); + m5x.SetOption( "Spells", "Paralyze", false ); + m5x.SetOption( "Spells", "Summon Creature", false ); + m5x.SetOption( "Spells", "Invisibility", false ); + m5x.SetOption( "Spells", "Mark", false ); + m5x.SetOption( "Spells", "Paralyze Field", false ); + m5x.SetOption( "Spells", "Energy Field", false ); + m5x.SetOption( "Spells", "Gate Travel", false ); + m5x.SetOption( "Spells", "Polymorph", false ); + m5x.SetOption( "Spells", "Energy Vortex", false ); + m5x.SetOption( "Spells", "Air Elemental", false ); + m5x.SetOption( "Spells", "Summon Daemon", false ); + m5x.SetOption( "Spells", "Earth Elemental", false ); + m5x.SetOption( "Spells", "Fire Elemental", false ); + m5x.SetOption( "Spells", "Water Elemental", false ); + m5x.SetOption( "Spells", "Earthquake", false ); + m5x.SetOption( "Spells", "Meteor Swarm", false ); + m5x.SetOption( "Spells", "Chain Lightning", false ); + m5x.SetOption( "Spells", "Resurrection", false ); + + m5x.SetOption( "Weapons", "Wrestling", true ); + + m5x.SetOption( "Skills", "Anatomy", true ); + m5x.SetOption( "Skills", "Detect Hidden", true ); + m5x.SetOption( "Skills", "Evaluating Intelligence", true ); + + m5x.SetOption( "Items", "Trapped Containers", true ); + #endregion + + #region Mage 7x + Ruleset m7x = new Ruleset( m_Root ); + + m7x.Title = "Mage 7x"; + + m7x.SetOptionRange( "Spells", true ); + + m7x.SetOption( "Spells", "Wall of Stone", false ); + m7x.SetOption( "Spells", "Fire Field", false ); + m7x.SetOption( "Spells", "Poison Field", false ); + m7x.SetOption( "Spells", "Energy Field", false ); + m7x.SetOption( "Spells", "Reactive Armor", false ); + m7x.SetOption( "Spells", "Protection", false ); + m7x.SetOption( "Spells", "Teleport", false ); + m7x.SetOption( "Spells", "Wall of Stone", false ); + m7x.SetOption( "Spells", "Arch Protection", false ); + m7x.SetOption( "Spells", "Recall", false ); + m7x.SetOption( "Spells", "Blade Spirits", false ); + m7x.SetOption( "Spells", "Incognito", false ); + m7x.SetOption( "Spells", "Magic Reflection", false ); + m7x.SetOption( "Spells", "Paralyze", false ); + m7x.SetOption( "Spells", "Summon Creature", false ); + m7x.SetOption( "Spells", "Invisibility", false ); + m7x.SetOption( "Spells", "Mark", false ); + m7x.SetOption( "Spells", "Paralyze Field", false ); + m7x.SetOption( "Spells", "Energy Field", false ); + m7x.SetOption( "Spells", "Gate Travel", false ); + m7x.SetOption( "Spells", "Polymorph", false ); + m7x.SetOption( "Spells", "Energy Vortex", false ); + m7x.SetOption( "Spells", "Air Elemental", false ); + m7x.SetOption( "Spells", "Summon Daemon", false ); + m7x.SetOption( "Spells", "Earth Elemental", false ); + m7x.SetOption( "Spells", "Fire Elemental", false ); + m7x.SetOption( "Spells", "Water Elemental", false ); + m7x.SetOption( "Spells", "Earthquake", false ); + m7x.SetOption( "Spells", "Meteor Swarm", false ); + m7x.SetOption( "Spells", "Chain Lightning", false ); + m7x.SetOption( "Spells", "Resurrection", false ); + + m7x.SetOption( "Combat Abilities", "Stun", true ); + + m7x.SetOption( "Skills", "Anatomy", true ); + m7x.SetOption( "Skills", "Detect Hidden", true ); + m7x.SetOption( "Skills", "Poisoning", true ); + m7x.SetOption( "Skills", "Evaluating Intelligence", true ); + + m7x.SetOption( "Weapons", "Wrestling", true ); + + m7x.SetOption( "Potions", "Refresh", true ); + m7x.SetOption( "Items", "Trapped Containers", true ); + m7x.SetOption( "Items", "Bandages", true ); + #endregion + + #region Standard 7x + Ruleset s7x = new Ruleset( m_Root ); + + s7x.Title = "Standard 7x"; + + s7x.SetOptionRange( "Spells", true ); + + s7x.SetOption( "Spells", "Wall of Stone", false ); + s7x.SetOption( "Spells", "Fire Field", false ); + s7x.SetOption( "Spells", "Poison Field", false ); + s7x.SetOption( "Spells", "Energy Field", false ); + s7x.SetOption( "Spells", "Teleport", false ); + s7x.SetOption( "Spells", "Wall of Stone", false ); + s7x.SetOption( "Spells", "Arch Protection", false ); + s7x.SetOption( "Spells", "Recall", false ); + s7x.SetOption( "Spells", "Blade Spirits", false ); + s7x.SetOption( "Spells", "Incognito", false ); + s7x.SetOption( "Spells", "Magic Reflection", false ); + s7x.SetOption( "Spells", "Paralyze", false ); + s7x.SetOption( "Spells", "Summon Creature", false ); + s7x.SetOption( "Spells", "Invisibility", false ); + s7x.SetOption( "Spells", "Mark", false ); + s7x.SetOption( "Spells", "Paralyze Field", false ); + s7x.SetOption( "Spells", "Energy Field", false ); + s7x.SetOption( "Spells", "Gate Travel", false ); + s7x.SetOption( "Spells", "Polymorph", false ); + s7x.SetOption( "Spells", "Energy Vortex", false ); + s7x.SetOption( "Spells", "Air Elemental", false ); + s7x.SetOption( "Spells", "Summon Daemon", false ); + s7x.SetOption( "Spells", "Earth Elemental", false ); + s7x.SetOption( "Spells", "Fire Elemental", false ); + s7x.SetOption( "Spells", "Water Elemental", false ); + s7x.SetOption( "Spells", "Earthquake", false ); + s7x.SetOption( "Spells", "Meteor Swarm", false ); + s7x.SetOption( "Spells", "Chain Lightning", false ); + s7x.SetOption( "Spells", "Resurrection", false ); + + s7x.SetOptionRange( "Combat Abilities", true ); + + s7x.SetOption( "Skills", "Anatomy", true ); + s7x.SetOption( "Skills", "Detect Hidden", true ); + s7x.SetOption( "Skills", "Poisoning", true ); + s7x.SetOption( "Skills", "Evaluating Intelligence", true ); + + s7x.SetOptionRange( "Weapons", true ); + s7x.SetOption( "Weapons", "Runics", false ); + s7x.SetOptionRange( "Armor", true ); + + s7x.SetOption( "Potions", "Refresh", true ); + s7x.SetOption( "Items", "Bandages", true ); + s7x.SetOption( "Items", "Trapped Containers", true ); + #endregion + + m_Root.Defaults = new Ruleset[] { m5x, m7x, s7x }; + } + else + { + #region Standard All Skills + + Ruleset all = new Ruleset( m_Root ); + + all.Title = "Standard All Skills"; + + + all.SetOptionRange( "Spells", true ); + + all.SetOption( "Spells", "Wall of Stone", false ); + all.SetOption( "Spells", "Fire Field", false ); + all.SetOption( "Spells", "Poison Field", false ); + all.SetOption( "Spells", "Energy Field", false ); + all.SetOption( "Spells", "Teleport", false ); + all.SetOption( "Spells", "Wall of Stone", false ); + all.SetOption( "Spells", "Arch Protection", false ); + all.SetOption( "Spells", "Recall", false ); + all.SetOption( "Spells", "Blade Spirits", false ); + all.SetOption( "Spells", "Incognito", false ); + all.SetOption( "Spells", "Magic Reflection", false ); + all.SetOption( "Spells", "Paralyze", false ); + all.SetOption( "Spells", "Summon Creature", false ); + all.SetOption( "Spells", "Invisibility", false ); + all.SetOption( "Spells", "Mark", false ); + all.SetOption( "Spells", "Paralyze Field", false ); + all.SetOption( "Spells", "Energy Field", false ); + all.SetOption( "Spells", "Gate Travel", false ); + all.SetOption( "Spells", "Polymorph", false ); + all.SetOption( "Spells", "Energy Vortex", false ); + all.SetOption( "Spells", "Air Elemental", false ); + all.SetOption( "Spells", "Summon Daemon", false ); + all.SetOption( "Spells", "Earth Elemental", false ); + all.SetOption( "Spells", "Fire Elemental", false ); + all.SetOption( "Spells", "Water Elemental", false ); + all.SetOption( "Spells", "Earthquake", false ); + all.SetOption( "Spells", "Meteor Swarm", false ); + all.SetOption( "Spells", "Chain Lightning", false ); + all.SetOption( "Spells", "Resurrection", false ); + + all.SetOptionRange( "Necromancy", true ); + all.SetOption( "Necromancy", "Summon Familiar", false ); + all.SetOption( "Necromancy", "Vengeful Spirit", false ); + all.SetOption( "Necromancy", "Animate Dead", false ); + all.SetOption( "Necromancy", "Wither", false ); + all.SetOption( "Necromancy", "Poison Strike", false ); + + all.SetOptionRange( "Chivalry", true ); + all.SetOption( "Chivalry", "Sacred Journey", false ); + all.SetOption( "Chivalry", "Enemy of One", false ); + all.SetOption( "Chivalry", "Noble Sacrifice", false ); + + all.SetOptionRange( "Combat Abilities", true ); + all.SetOption( "Combat Abilities", "Paralyzing Blow", false ); + all.SetOption( "Combat Abilities", "Shadow Strike", false ); + + all.SetOption( "Skills", "Anatomy", true ); + all.SetOption( "Skills", "Detect Hidden", true ); + all.SetOption( "Skills", "Poisoning", true ); + all.SetOption( "Skills", "Spirit Speak", true ); + all.SetOption( "Skills", "Evaluating Intelligence", true ); + + all.SetOptionRange( "Weapons", true ); + all.SetOption( "Weapons", "Poisoned", false ); + + all.SetOptionRange( "Armor", true ); + + all.SetOptionRange( "Ninjitsu", true ); + all.SetOption( "Ninjitsu", "Animal Form", false ); + all.SetOption( "Ninjitsu", "Mirror Image", false ); + all.SetOption( "Ninjitsu", "Backstab", false ); + all.SetOption( "Ninjitsu", "Suprise Attack", false ); + all.SetOption( "Ninjitsu", "Shadow Jump", false ); + + all.SetOptionRange( "Bushido", true ); + + all.SetOptionRange( "Spellweaving", true ); + all.SetOption( "Spellweaving", "Gift of Life", false ); + all.SetOption( "Spellweaving", "Summon Fey", false ); + all.SetOption( "Spellweaving", "Summon Fiend", false ); + all.SetOption( "Spellweaving", "Nature's Fury", false ); + + all.SetOption( "Potions", "Refresh", true ); + all.SetOption( "Items", "Bandages", true ); + all.SetOption( "Items", "Trapped Containers", true ); + + m_Root.Defaults = new Ruleset[] { all }; + #endregion + } + + // Set up flavors + + Ruleset pots = new Ruleset( m_Root ); + + pots.Title = "Potions"; + + pots.SetOptionRange( "Potions", true ); + pots.SetOption( "Potions", "Explosion", false ); + + Ruleset para = new Ruleset( m_Root ); + + para.Title = "Paralyze"; + para.SetOption( "Spells", "Paralyze", true ); + para.SetOption( "Spells", "Paralyze Field", true ); + para.SetOption( "Combat Abilities", "Paralyzing Blow", true ); + + Ruleset fields = new Ruleset( m_Root ); + + fields.Title = "Fields"; + fields.SetOption( "Spells", "Wall of Stone", true ); + fields.SetOption( "Spells", "Fire Field", true ); + fields.SetOption( "Spells", "Poison Field", true ); + fields.SetOption( "Spells", "Energy Field", true ); + fields.SetOption( "Spells", "Wildfire", true ); + + Ruleset area = new Ruleset( m_Root ); + + area.Title = "Area Effect"; + area.SetOption( "Spells", "Earthquake", true ); + area.SetOption( "Spells", "Meteor Swarm", true ); + area.SetOption( "Spells", "Chain Lightning", true ); + area.SetOption( "Necromancy", "Wither", true ); + area.SetOption( "Necromancy", "Poison Strike", true ); + + Ruleset summons = new Ruleset( m_Root ); + + summons.Title = "Summons"; + summons.SetOption( "Spells", "Blade Spirits", true ); + summons.SetOption( "Spells", "Energy Vortex", true ); + summons.SetOption( "Spells", "Air Elemental", true ); + summons.SetOption( "Spells", "Summon Daemon", true ); + summons.SetOption( "Spells", "Earth Elemental", true ); + summons.SetOption( "Spells", "Fire Elemental", true ); + summons.SetOption( "Spells", "Water Elemental", true ); + summons.SetOption( "Necromancy", "Summon Familiar", true ); + summons.SetOption( "Necromancy", "Vengeful Spirit", true ); + summons.SetOption( "Necromancy", "Animate Dead", true ); + summons.SetOption( "Ninjitsu", "Mirror Image", true ); + summons.SetOption( "Spellweaving", "Summon Fey", true ); + summons.SetOption( "Spellweaving", "Summon Fiend", true ); + summons.SetOption( "Spellweaving", "Nature's Fury", true ); + + m_Root.Flavors = new Ruleset[]{ pots, para, fields, area, summons }; + } + + return m_Root; + } + } + + private string m_Title, m_Description; + private string[] m_Options; + + private int m_Offset, m_TotalLength; + + private Ruleset[] m_Defaults; + private Ruleset[] m_Flavors; + + private RulesetLayout m_Parent; + private RulesetLayout[] m_Children; + + public string Title{ get{ return m_Title; } } + public string Description{ get{ return m_Description; } } + public string[] Options{ get{ return m_Options; } } + + public int Offset{ get{ return m_Offset; } } + public int TotalLength{ get{ return m_TotalLength; } } + + public RulesetLayout Parent{ get{ return m_Parent; } } + public RulesetLayout[] Children{ get{ return m_Children; } } + + public Ruleset[] Defaults{ get{ return m_Defaults; } set{ m_Defaults = value; } } + public Ruleset[] Flavors{ get{ return m_Flavors; } set{ m_Flavors = value; } } + + public RulesetLayout FindByTitle( string title ) + { + if ( m_Title == title ) + return this; + + for ( int i = 0; i < m_Children.Length; ++i ) + { + RulesetLayout layout = m_Children[i].FindByTitle( title ); + + if ( layout != null ) + return layout; + } + + return null; + } + + public string FindByIndex( int index ) + { + if ( index >= m_Offset && index < (m_Offset + m_Options.Length) ) + return m_Description + ": " + m_Options[index - m_Offset]; + + for ( int i = 0; i < m_Children.Length; ++i ) + { + string opt = m_Children[i].FindByIndex( index ); + + if ( opt != null ) + return opt; + } + + return null; + } + + public RulesetLayout FindByOption( string title, string option, ref int index ) + { + if ( title == null || m_Title == title ) + { + index = GetOptionIndex( option ); + + if ( index >= 0 ) + return this; + + title = null; + } + + for ( int i = 0; i < m_Children.Length; ++i ) + { + RulesetLayout layout = m_Children[i].FindByOption( title, option, ref index ); + + if ( layout != null ) + return layout; + } + + return null; + } + + public int GetOptionIndex( string option ) + { + return Array.IndexOf( m_Options, option ); + } + + public void ComputeOffsets() + { + int offset = 0; + + RecurseComputeOffsets( ref offset ); + } + + private int RecurseComputeOffsets( ref int offset ) + { + m_Offset = offset; + + offset += m_Options.Length; + m_TotalLength += m_Options.Length; + + for ( int i = 0; i < m_Children.Length; ++i ) + m_TotalLength += m_Children[i].RecurseComputeOffsets( ref offset ); + + return m_TotalLength; + } + + public RulesetLayout( string title, string[] options ) : this( title, title, new RulesetLayout[0], options ) + { + } + + public RulesetLayout( string title, string description, string[] options ) : this( title, description, new RulesetLayout[0], options ) + { + } + + public RulesetLayout( string title, RulesetLayout[] children ) : this( title, title, children, new string[0] ) + { + } + + public RulesetLayout( string title, string description, RulesetLayout[] children ) : this( title, description, children, new string[0] ) + { + } + + public RulesetLayout( string title, RulesetLayout[] children, string[] options ) : this( title, title, children, options ) + { + } + + public RulesetLayout( string title, string description, RulesetLayout[] children, string[] options ) + { + m_Title = title; + m_Description = description; + m_Children = children; + m_Options = options; + + for ( int i = 0; i < children.Length; ++i ) + children[i].m_Parent = this; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/SafeZone.cs b/Scripts/Engines/ConPVP/SafeZone.cs new file mode 100644 index 0000000..c95edf0 --- /dev/null +++ b/Scripts/Engines/ConPVP/SafeZone.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Engines.ConPVP +{ + public class SafeZone : GuardedRegion + { + public static readonly int SafeZonePriority = HouseRegion.HousePriority + 1; + + /*public override bool AllowReds{ get{ return true; } }*/ + + public SafeZone( Rectangle2D area, Point3D goloc, Map map, bool isGuarded ) : base( null, map, SafeZonePriority, area ) + { + GoLocation = goloc; + + this.Disabled = !isGuarded; + + Register(); + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + if ( from.AccessLevel < AccessLevel.GameMaster ) + return false; + + return base.AllowHousing( from, p ); + } + + public override bool OnMoveInto( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation ) + { + if ( m.Player && Factions.Sigil.ExistsOn( m ) ) + { + m.SendMessage( 0x22, "You are holding a sigil and cannot enter this zone." ); + return false; + } + + PlayerMobile pm = m as PlayerMobile; + + if ( pm == null && m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( bc.Summoned ) + pm = bc.SummonMaster as PlayerMobile; + } + + if ( pm != null && pm.DuelContext != null && pm.DuelContext.StartedBeginCountdown ) + return true; + + if ( DuelContext.CheckCombat( m ) ) + { + m.SendMessage( 0x22, "You have recently been in combat and cannot enter this zone." ); + return false; + } + + return base.OnMoveInto( m, d, newLocation, oldLocation ); + } + + public override void OnEnter( Mobile m ) + { + m.SendMessage( "You have entered a dueling safezone. No combat other than duels are allowed in this zone." ); + } + + public override void OnExit( Mobile m ) + { + m.SendMessage( "You have left a dueling safezone. Combat is now unrestricted." ); + } + + public override bool CanUseStuckMenu( Mobile m ) + { + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/StakesContainer.cs b/Scripts/Engines/ConPVP/StakesContainer.cs new file mode 100644 index 0000000..0743bc2 --- /dev/null +++ b/Scripts/Engines/ConPVP/StakesContainer.cs @@ -0,0 +1,127 @@ +using System; +using System.Text; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Engines.ConPVP +{ +#if false + [Flipable( 0x9A8, 0xE80 )] + public class StakesContainer : LockableContainer + { + private Mobile m_Initiator; + private Participant m_Participant; + private Hashtable m_Owners; + + public override bool CheckItemUse( Mobile from, Item item ) + { + Mobile owner = (Mobile)m_Owners[item]; + + if ( owner != null && owner != from ) + return false; + + return base.CheckItemUse( from, item ); + } + + public override bool CheckTarget( Mobile from, Server.Targeting.Target targ, object targeted ) + { + Mobile owner = (Mobile)m_Owners[targeted]; + + if ( owner != null && owner != from ) + return false; + + return base.CheckTarget( from, targ, targeted ); + } + + public override bool CheckLift(Mobile from, Item item) + { + Mobile owner = (Mobile)m_Owners[item]; + + if ( owner != null && owner != from ) + return false; + + return base.CheckLift( from, item ); + } + + public void ReturnItems() + { + ArrayList items = new ArrayList( this.Items ); + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = (Item)items[i]; + Mobile owner = (Mobile)m_Owners[item]; + + if ( owner == null || owner.Deleted ) + owner = m_Initiator; + + if ( owner == null || owner.Deleted ) + return; + + if ( item.LootType != LootType.Blessed || !owner.PlaceInBackpack( item ) ) + owner.BankBox.DropItem( item ); + } + } + + public override bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + if ( m_Participant == null || !m_Participant.Contains( from ) ) + { + if ( sendFullMessage ) + from.SendMessage( "You are not allowed to place items here." ); + + return false; + } + + if ( dropped is Container || dropped.Stackable ) + { + if ( sendFullMessage ) + from.SendMessage( "That item cannot be used as stakes." ); + + return false; + } + + if ( !base.TryDropItem( from, dropped, sendFullMessage ) ) + return false; + + if ( from != null ) + m_Owners[dropped] = from; + + return true; + } + + public override void RemoveItem( Item item ) + { + base.RemoveItem( item ); + m_Owners.Remove( item ); + } + + public StakesContainer( DuelContext context, Participant participant ) : base( 0x9A8 ) + { + Movable = false; + m_Initiator = context.Initiator; + m_Participant = participant; + m_Owners = new Hashtable(); + } + + public StakesContainer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +#endif +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Tournament.cs b/Scripts/Engines/ConPVP/Tournament.cs new file mode 100644 index 0000000..40fe851 --- /dev/null +++ b/Scripts/Engines/ConPVP/Tournament.cs @@ -0,0 +1,3377 @@ +using System; +using System.Text; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; +using Server.ContextMenus; +using Server.Mobiles; +using Server.Targeting; +using System.Collections.Generic; + +namespace Server.Engines.ConPVP +{ + public enum TournamentStage + { + Inactive, + Signup, + Fighting + } + + public enum GroupingType + { + HighVsLow, + Nearest, + Random + } + + public enum TieType + { + Random, + Highest, + Lowest, + FullElimination, + FullAdvancement + } + + public class TournamentRegistrar : Banker + { + private TournamentController m_Tournament; + + [CommandProperty( AccessLevel.GameMaster )] + public TournamentController Tournament{ get{ return m_Tournament; } set{ m_Tournament = value; } } + + [Constructable] + public TournamentRegistrar() + { + Timer.DelayCall( TimeSpan.FromSeconds( 30.0 ), TimeSpan.FromSeconds( 30.0 ), new TimerCallback( Announce_Callback ) ); + } + + private void Announce_Callback() + { + Tournament tourny = null; + + if ( m_Tournament != null ) + tourny = m_Tournament.Tournament; + + if ( tourny != null && tourny.Stage == TournamentStage.Signup ) + PublicOverheadMessage( MessageType.Regular, 0x35, false, "Come one, come all! Do you aspire to be a fighter of great renown? Join this tournament and show the world your abilities." ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + Tournament tourny = null; + + if ( m_Tournament != null ) + tourny = m_Tournament.Tournament; + + if ( InRange( m, 4 ) && !InRange( oldLocation, 4 ) && tourny != null && tourny.Stage == TournamentStage.Signup && m.CanBeginAction( this ) ) + { + Ladder ladder = Ladder.Instance; + + if ( ladder != null ) + { + LadderEntry entry = ladder.Find( m ); + + if ( entry != null && Ladder.GetLevel( entry.Experience ) < tourny.LevelRequirement ) + return; + } + + if ( tourny.HasParticipant( m ) ) + return; + + PrivateOverheadMessage( MessageType.Regular, 0x35, false, String.Format( "Hello m'{0}. Dost thou wish to enter this tournament? You need only to write your name in this book.", m.Female ? "Lady" : "Lord" ), m.NetState ); + m.BeginAction( this ); + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerStateCallback( ReleaseLock_Callback ), m ); + } + } + + private void ReleaseLock_Callback( object obj ) + { + ((Mobile)obj).EndAction( this ); + } + + public TournamentRegistrar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (Item) m_Tournament ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Tournament = reader.ReadItem() as TournamentController; + break; + } + } + + Timer.DelayCall( TimeSpan.FromSeconds( 30.0 ), TimeSpan.FromSeconds( 30.0 ), new TimerCallback( Announce_Callback ) ); + } + } + + public class TournamentSignupItem : Item + { + private TournamentController m_Tournament; + private Mobile m_Registrar; + + [CommandProperty( AccessLevel.GameMaster )] + public TournamentController Tournament{ get{ return m_Tournament; } set{ m_Tournament = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Registrar{ get{ return m_Registrar; } set{ m_Registrar = value; } } + + public override string DefaultName + { + get { return "tournament signup book"; } + } + + [Constructable] + public TournamentSignupItem() : base( 4029 ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that + } + else if ( m_Tournament != null ) + { + Tournament tourny = m_Tournament.Tournament; + + if ( tourny != null ) + { + if ( m_Registrar != null ) + m_Registrar.Direction = m_Registrar.GetDirectionTo( this ); + + switch ( tourny.Stage ) + { + case TournamentStage.Fighting: + { + if ( m_Registrar != null ) + { + if ( tourny.HasParticipant( from ) ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "Excuse me? You are already signed up.", from.NetState ); + } + else + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "The tournament has already begun. You are too late to signup now.", from.NetState ); + } + } + + break; + } + case TournamentStage.Inactive: + { + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "The tournament is closed.", from.NetState ); + + break; + } + case TournamentStage.Signup: + { + Ladder ladder = Ladder.Instance; + + if ( ladder != null ) + { + LadderEntry entry = ladder.Find( from ); + + if ( entry != null && Ladder.GetLevel( entry.Experience ) < tourny.LevelRequirement ) + { + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "You have not yet proven yourself a worthy dueler.", from.NetState ); + } + + break; + } + } + + if ( from.HasGump( typeof( AcceptTeamGump ) ) ) + { + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "You must first respond to the offer I've given you.", from.NetState ); + } + else if ( from.HasGump( typeof( AcceptDuelGump ) ) ) + { + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "You must first cancel your duel offer.", from.NetState ); + } + else if ( from is PlayerMobile && ((PlayerMobile)from).DuelContext != null ) + { + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "You are already participating in a duel.", from.NetState ); + } + else if ( !tourny.HasParticipant( from ) ) + { + ArrayList players = new ArrayList(); + players.Add(from); + from.CloseGump( typeof( ConfirmSignupGump ) ); + from.SendGump( new ConfirmSignupGump( from, m_Registrar, tourny, players ) ); + } + else if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "You have already entered this tournament.", from.NetState ); + } + + break; + } + } + } + } + } + + public TournamentSignupItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (Item) m_Tournament ); + writer.Write( (Mobile) m_Registrar ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Tournament = reader.ReadItem() as TournamentController; + m_Registrar = reader.ReadMobile(); + break; + } + } + } + } + + public class ConfirmSignupGump : Gump + { + private Mobile m_From; + private Tournament m_Tournament; + private ArrayList m_Players; + private Mobile m_Registrar; + + private const int BlackColor32 = 0x000008; + private const int LabelColor32 = 0xFFFFFF; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private void AddBorderedText( int x, int y, int width, int height, string text, int color, int borderColor ) + { + AddColoredText( x - 1, y - 1, width, height, text, borderColor ); + AddColoredText( x - 1, y + 1, width, height, text, borderColor ); + AddColoredText( x + 1, y - 1, width, height, text, borderColor ); + AddColoredText( x + 1, y + 1, width, height, text, borderColor ); + AddColoredText( x, y, width, height, text, color ); + } + + private void AddColoredText( int x, int y, int width, int height, string text, int color ) + { + if ( color == 0 ) + AddHtml( x, y, width, height, text, false, false ); + else + AddHtml( x, y, width, height, Color( text, color ), false, false ); + } + + public void AddGoldenButton( int x, int y, int bid ) + { + AddButton( x , y , 0xD2, 0xD2, bid, GumpButtonType.Reply, 0 ); + AddButton( x+3, y+3, 0xD8, 0xD8, bid, GumpButtonType.Reply, 0 ); + } + + public ConfirmSignupGump( Mobile from, Mobile registrar, Tournament tourny, ArrayList players ) : base( 50, 50 ) + { + m_From = from; + m_Registrar = registrar; + m_Tournament = tourny; + m_Players = players; + + m_From.CloseGump( typeof( AcceptTeamGump ) ); + m_From.CloseGump( typeof( AcceptDuelGump ) ); + m_From.CloseGump( typeof( DuelContextGump ) ); + m_From.CloseGump( typeof( ConfirmSignupGump ) ); + + #region Rules + Ruleset ruleset = tourny.Ruleset; + Ruleset basedef = ruleset.Base; + + int height = 185 + 60 + 12; + + int changes = 0; + + BitArray defs; + + if ( ruleset.Flavors.Count > 0 ) + { + defs = new BitArray( basedef.Options ); + + for ( int i = 0; i < ruleset.Flavors.Count; ++i ) + defs.Or( ((Ruleset)ruleset.Flavors[i]).Options ); + + height += ruleset.Flavors.Count * 18; + } + else + { + defs = basedef.Options; + } + + BitArray opts = ruleset.Options; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + ++changes; + } + + height += (changes * 22); + + height += 10 + 22 + 25 + 25; + + if ( tourny.PlayersPerParticipant > 1 ) + height += 36 + (tourny.PlayersPerParticipant * 20); + #endregion + + Closable = false; + + AddPage( 0 ); + + //AddBackground( 0, 0, 400, 220, 9150 ); + AddBackground( 1, 1, 398, height, 3600 ); + //AddBackground( 16, 15, 369, 189, 9100 ); + + AddImageTiled( 16, 15, 369, height - 29, 3604 ); + AddAlphaRegion( 16, 15, 369, height - 29 ); + + AddImage( 215, -43, 0xEE40 ); + //AddImage( 330, 141, 0x8BA ); + + StringBuilder sb = new StringBuilder(); + + if ( tourny.TournyType == TournyType.FreeForAll ) + { + sb.Append( "FFA" ); + } + else if ( tourny.TournyType == TournyType.RandomTeam ) + { + sb.Append( "Team" ); + } + else if ( tourny.TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else + { + for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( tourny.PlayersPerParticipant ); + } + } + + if ( tourny.EventController != null ) + sb.Append( ' ' ).Append( tourny.EventController.Title ); + + sb.Append( " Tournament Signup" ); + + AddBorderedText( 22, 22, 294, 20, Center( sb.ToString() ), LabelColor32, BlackColor32 ); + AddBorderedText( 22, 50, 294, 40, "You have requested to join the tournament. Do you accept the rules?", 0xB0C868, BlackColor32 ); + + AddImageTiled( 32, 88, 264, 1, 9107 ); + AddImageTiled( 42, 90, 264, 1, 9157 ); + + #region Rules + int y = 100; + + string groupText = null; + + switch ( tourny.GroupType ) + { + case GroupingType.HighVsLow: groupText = "High vs Low"; break; + case GroupingType.Nearest: groupText = "Closest opponent"; break; + case GroupingType.Random: groupText = "Random"; break; + } + + AddBorderedText( 35, y, 190, 20, String.Format( "Grouping: {0}", groupText ), LabelColor32, BlackColor32 ); + y += 20; + + string tieText = null; + + switch ( tourny.TieType ) + { + case TieType.Random: tieText = "Random"; break; + case TieType.Highest: tieText = "Highest advances"; break; + case TieType.Lowest: tieText = "Lowest advances"; break; + case TieType.FullAdvancement: tieText = ( tourny.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances" ); break; + case TieType.FullElimination: tieText = ( tourny.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated" ); break; + } + + AddBorderedText( 35, y, 190, 20, String.Format( "Tiebreaker: {0}", tieText ), LabelColor32, BlackColor32 ); + y += 20; + + string sdText = "Off"; + + if ( tourny.SuddenDeath > TimeSpan.Zero ) + { + sdText = String.Format( "{0}:{1:D2}", (int) tourny.SuddenDeath.TotalMinutes, tourny.SuddenDeath.Seconds ); + + if ( tourny.SuddenDeathRounds > 0 ) + sdText = String.Format( "{0} (first {1} rounds)", sdText, tourny.SuddenDeathRounds ); + else + sdText = String.Format( "{0} (all rounds)", sdText ); + } + + AddBorderedText( 35, y, 240, 20, String.Format( "Sudden Death: {0}", sdText ), LabelColor32, BlackColor32 ); + y += 20; + + y += 6; + AddImageTiled( 32, y-1, 264, 1, 9107 ); + AddImageTiled( 42, y+1, 264, 1, 9157 ); + y += 6; + + AddBorderedText( 35, y, 190, 20, String.Format( "Ruleset: {0}", basedef.Title ), LabelColor32, BlackColor32 ); + y += 20; + + for ( int i = 0; i < ruleset.Flavors.Count; ++i, y += 18 ) + AddBorderedText( 35, y, 190, 20, String.Format( " + {0}", ((Ruleset)ruleset.Flavors[i]).Title ), LabelColor32, BlackColor32 ); + + y += 4; + + if ( changes > 0 ) + { + AddBorderedText( 35, y, 190, 20, "Modifications:", LabelColor32, BlackColor32 ); + y += 20; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + { + string name = ruleset.Layout.FindByIndex( i ); + + if ( name != null ) // sanity + { + AddImage( 35, y, opts[i] ? 0xD3 : 0xD2 ); + AddBorderedText( 60, y, 165, 22, name, LabelColor32, BlackColor32 ); + } + + y += 22; + } + } + } + else + { + AddBorderedText( 35, y, 190, 20, "Modifications: None", LabelColor32, BlackColor32 ); + y += 20; + } + #endregion + + #region Team + if ( tourny.PlayersPerParticipant > 1 ) + { + y += 8; + AddImageTiled( 32, y-1, 264, 1, 9107 ); + AddImageTiled( 42, y+1, 264, 1, 9157 ); + y += 8; + + AddBorderedText( 35, y, 190, 20, "Your Team", LabelColor32, BlackColor32 ); + y += 20; + + for ( int i = 0; i < players.Count; ++i, y += 20 ) + { + if ( i == 0 ) + AddImage( 35, y, 0xD2 ); + else + AddGoldenButton( 35, y, 1 + i ); + + AddBorderedText( 60, y, 200, 20, ((Mobile)players[i]).Name, LabelColor32, BlackColor32 ); + } + + for ( int i = players.Count; i < tourny.PlayersPerParticipant; ++i, y += 20 ) + { + if ( i == 0 ) + AddImage( 35, y, 0xD2 ); + else + AddGoldenButton( 35, y, 1 + i ); + + AddBorderedText( 60, y, 200, 20, "(Empty)", LabelColor32, BlackColor32 ); + } + } + #endregion + + y += 8; + AddImageTiled( 32, y-1, 264, 1, 9107 ); + AddImageTiled( 42, y+1, 264, 1, 9157 ); + y += 8; + + AddRadio( 24, y, 9727, 9730, true, 1 ); + AddBorderedText( 60, y+5, 250, 20, "Yes, I wish to join the tournament.", LabelColor32, BlackColor32 ); + y += 35; + + AddRadio( 24, y, 9727, 9730, false, 2 ); + AddBorderedText( 60, y+5, 250, 20, "No, I do not wish to join.", LabelColor32, BlackColor32 ); + y += 35; + + y -= 3; + AddButton( 314, y, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 && info.IsSwitched( 1 ) ) + { + Tournament tourny = m_Tournament; + Mobile from = m_From; + + switch ( tourny.Stage ) + { + case TournamentStage.Fighting: + { + if ( m_Registrar != null ) + { + if ( m_Tournament.HasParticipant( from ) ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "Excuse me? You are already signed up.", from.NetState ); + } + else + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "The tournament has already begun. You are too late to signup now.", from.NetState ); + } + } + + break; + } + case TournamentStage.Inactive: + { + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "The tournament is closed.", from.NetState ); + + break; + } + case TournamentStage.Signup: + { + if ( m_Players.Count != tourny.PlayersPerParticipant ) + { + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "You have not yet chosen your team.", from.NetState ); + } + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + break; + } + + Ladder ladder = Ladder.Instance; + + for ( int i = 0; i < m_Players.Count; ++i ) + { + Mobile mob = (Mobile)m_Players[i]; + + LadderEntry entry = ( ladder == null ? null : ladder.Find( mob ) ); + + if ( entry != null && Ladder.GetLevel( entry.Experience ) < tourny.LevelRequirement ) + { + if ( m_Registrar != null ) + { + if ( mob == from ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "You have not yet proven yourself a worthy dueler.", from.NetState ); + } + else + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, String.Format( "{0} has not yet proven themselves a worthy dueler.", mob.Name ), from.NetState ); + } + } + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + return; + } + else if ( tourny.HasParticipant( mob ) ) + { + if ( m_Registrar != null ) + { + if ( mob == from ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "You have already entered this tournament.", from.NetState ); + } + else + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, String.Format( "{0} has already entered this tournament.", mob.Name ), from.NetState ); + } + } + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + return; + } + else if ( mob is PlayerMobile && ((PlayerMobile)mob).DuelContext != null ) + { + if ( m_Registrar != null ) + { + if ( mob == from ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, "You are already assigned to a duel. You must yield it before joining this tournament.", from.NetState ); + } + else + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, String.Format( "{0} is already assigned to a duel. They must yield it before joining this tournament.", mob.Name ), from.NetState ); + } + } + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + return; + } + } + + if ( m_Registrar != null ) + { + string fmt; + + if ( tourny.PlayersPerParticipant == 1 ) + fmt = "As you say m'{0}. I've written your name to the bracket. The tournament will begin {1}."; + else if ( tourny.PlayersPerParticipant == 2 ) + fmt = "As you wish m'{0}. The tournament will begin {1}, but first you must name your partner."; + else + fmt = "As you wish m'{0}. The tournament will begin {1}, but first you must name your team."; + + string timeUntil; + int minutesUntil = (int)Math.Round( ( (tourny.SignupStart + tourny.SignupPeriod) - DateTime.Now ).TotalMinutes ); + + if ( minutesUntil == 0 ) + timeUntil = "momentarily"; + else + timeUntil = String.Format( "in {0} minute{1}", minutesUntil, minutesUntil == 1 ? "" : "s" ); + + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x35, false, String.Format( fmt, from.Female ? "Lady" : "Lord", timeUntil ), from.NetState ); + } + + TournyParticipant part = new TournyParticipant( from ); + part.Players.Clear(); + part.Players.AddRange( m_Players ); + + tourny.Participants.Add( part ); + + break; + } + } + } + else if ( info.ButtonID > 1 ) + { + int index = info.ButtonID-1; + + if ( index > 0 && index < m_Players.Count ) + { + m_Players.RemoveAt( index ); + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + } + else if ( m_Players.Count < m_Tournament.PlayersPerParticipant ) + { + m_From.BeginTarget( 12, false, TargetFlags.None, new TargetCallback( AddPlayer_OnTarget ) ); + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + } + } + } + + private void AddPlayer_OnTarget( Mobile from, object obj ) + { + Mobile mob = obj as Mobile; + + if ( mob == null || mob == from ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "Excuse me?", from.NetState ); + } + else if ( !mob.Player ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( mob.Body.IsHuman ) + mob.SayTo( from, 1005443 ); // Nay, I would rather stay here and watch a nail rust. + else + mob.SayTo( from, 1005444 ); // The creature ignores your offer. + } + else if ( AcceptDuelGump.IsIgnored( mob, from ) || mob.Blessed ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They ignore your invitation.", from.NetState ); + } + else + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + return; + + if ( pm.DuelContext != null ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They are already assigned to another duel.", from.NetState ); + } + else if ( mob.HasGump( typeof( AcceptTeamGump ) ) ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They have already been offered a partnership.", from.NetState ); + } + else if ( mob.HasGump( typeof( ConfirmSignupGump ) ) ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They are already trying to join this tournament.", from.NetState ); + } + else if ( m_Players.Contains( mob ) ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "You have already named them as a team member.", from.NetState ); + } + else if ( m_Tournament.HasParticipant( mob ) ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They have already entered this tournament.", from.NetState ); + } + else if ( m_Players.Count >= m_Tournament.PlayersPerParticipant ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "Your team is full.", from.NetState ); + } + else + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + mob.SendGump( new AcceptTeamGump( from, mob, m_Tournament, m_Registrar, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x59, false, String.Format( "As you command m'{0}. I've given your offer to {1}.", from.Female ? "Lady" : "Lord", mob.Name ), from.NetState ); + } + } + } + } + + public class AcceptTeamGump : Gump + { + private bool m_Active; + + private Mobile m_From; + private Mobile m_Requested; + private Tournament m_Tournament; + private Mobile m_Registrar; + private ArrayList m_Players; + + private const int BlackColor32 = 0x000008; + private const int LabelColor32 = 0xFFFFFF; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private void AddBorderedText( int x, int y, int width, int height, string text, int color, int borderColor ) + { + AddColoredText( x - 1, y - 1, width, height, text, borderColor ); + AddColoredText( x - 1, y + 1, width, height, text, borderColor ); + AddColoredText( x + 1, y - 1, width, height, text, borderColor ); + AddColoredText( x + 1, y + 1, width, height, text, borderColor ); + AddColoredText( x, y, width, height, text, color ); + } + + private void AddColoredText( int x, int y, int width, int height, string text, int color ) + { + if ( color == 0 ) + AddHtml( x, y, width, height, text, false, false ); + else + AddHtml( x, y, width, height, Color( text, color ), false, false ); + } + + public AcceptTeamGump( Mobile from, Mobile requested, Tournament tourny, Mobile registrar, ArrayList players ) : base( 50, 50 ) + { + m_From = from; + m_Requested = requested; + m_Tournament = tourny; + m_Registrar = registrar; + m_Players = players; + + m_Active = true; + + #region Rules + Ruleset ruleset = tourny.Ruleset; + Ruleset basedef = ruleset.Base; + + int height = 185 + 35 + 60 + 12; + + int changes = 0; + + BitArray defs; + + if ( ruleset.Flavors.Count > 0 ) + { + defs = new BitArray( basedef.Options ); + + for ( int i = 0; i < ruleset.Flavors.Count; ++i ) + defs.Or( ((Ruleset)ruleset.Flavors[i]).Options ); + + height += ruleset.Flavors.Count * 18; + } + else + { + defs = basedef.Options; + } + + BitArray opts = ruleset.Options; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + ++changes; + } + + height += (changes * 22); + + height += 10 + 22 + 25 + 25; + #endregion + + Closable = false; + + AddPage( 0 ); + + AddBackground( 1, 1, 398, height, 3600 ); + + AddImageTiled( 16, 15, 369, height - 29, 3604 ); + AddAlphaRegion( 16, 15, 369, height - 29 ); + + AddImage( 215, -43, 0xEE40 ); + + StringBuilder sb = new StringBuilder(); + + if ( tourny.TournyType == TournyType.FreeForAll ) + { + sb.Append( "FFA" ); + } + else if ( tourny.TournyType == TournyType.RandomTeam ) + { + sb.Append( tourny.ParticipantsPerMatch ); + sb.Append( "-Team" ); + } + else if ( tourny.TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else + { + for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( tourny.PlayersPerParticipant ); + } + } + + if ( tourny.EventController != null ) + sb.Append( ' ' ).Append( tourny.EventController.Title ); + + sb.Append( " Tournament Invitation" ); + + AddBorderedText( 22, 22, 294, 20, Center( sb.ToString() ), LabelColor32, BlackColor32 ); + + AddBorderedText( 22, 50, 294, 40, + String.Format( "You have been asked to partner with {0} in a tournament. Do you accept?", from.Name ), + 0xB0C868, BlackColor32 ); + + AddImageTiled( 32, 88, 264, 1, 9107 ); + AddImageTiled( 42, 90, 264, 1, 9157 ); + + #region Rules + int y = 100; + + string groupText = null; + + switch ( tourny.GroupType ) + { + case GroupingType.HighVsLow: groupText = "High vs Low"; break; + case GroupingType.Nearest: groupText = "Closest opponent"; break; + case GroupingType.Random: groupText = "Random"; break; + } + + AddBorderedText( 35, y, 190, 20, String.Format( "Grouping: {0}", groupText ), LabelColor32, BlackColor32 ); + y += 20; + + string tieText = null; + + switch ( tourny.TieType ) + { + case TieType.Random: tieText = "Random"; break; + case TieType.Highest: tieText = "Highest advances"; break; + case TieType.Lowest: tieText = "Lowest advances"; break; + case TieType.FullAdvancement: tieText = ( tourny.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances" ); break; + case TieType.FullElimination: tieText = ( tourny.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated" ); break; + } + + AddBorderedText( 35, y, 190, 20, String.Format( "Tiebreaker: {0}", tieText ), LabelColor32, BlackColor32 ); + y += 20; + + string sdText = "Off"; + + if ( tourny.SuddenDeath > TimeSpan.Zero ) + { + sdText = String.Format( "{0}:{1:D2}", (int) tourny.SuddenDeath.TotalMinutes, tourny.SuddenDeath.Seconds ); + + if ( tourny.SuddenDeathRounds > 0 ) + sdText = String.Format( "{0} (first {1} rounds)", sdText, tourny.SuddenDeathRounds ); + else + sdText = String.Format( "{0} (all rounds)", sdText ); + } + + AddBorderedText( 35, y, 240, 20, String.Format( "Sudden Death: {0}", sdText ), LabelColor32, BlackColor32 ); + y += 20; + + y += 6; + AddImageTiled( 32, y-1, 264, 1, 9107 ); + AddImageTiled( 42, y+1, 264, 1, 9157 ); + y += 6; + + AddBorderedText( 35, y, 190, 20, String.Format( "Ruleset: {0}", basedef.Title ), LabelColor32, BlackColor32 ); + y += 20; + + for ( int i = 0; i < ruleset.Flavors.Count; ++i, y += 18 ) + AddBorderedText( 35, y, 190, 20, String.Format( " + {0}", ((Ruleset)ruleset.Flavors[i]).Title ), LabelColor32, BlackColor32 ); + + y += 4; + + if ( changes > 0 ) + { + AddBorderedText( 35, y, 190, 20, "Modifications:", LabelColor32, BlackColor32 ); + y += 20; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + { + string name = ruleset.Layout.FindByIndex( i ); + + if ( name != null ) // sanity + { + AddImage( 35, y, opts[i] ? 0xD3 : 0xD2 ); + AddBorderedText( 60, y, 165, 22, name, LabelColor32, BlackColor32 ); + } + + y += 22; + } + } + } + else + { + AddBorderedText( 35, y, 190, 20, "Modifications: None", LabelColor32, BlackColor32 ); + y += 20; + } + #endregion + + y += 8; + AddImageTiled( 32, y-1, 264, 1, 9107 ); + AddImageTiled( 42, y+1, 264, 1, 9157 ); + y += 8; + + AddRadio( 24, y, 9727, 9730, true, 1 ); + AddBorderedText( 60, y+5, 250, 20, "Yes, I will join them.", LabelColor32, BlackColor32 ); + y += 35; + + AddRadio( 24, y, 9727, 9730, false, 2 ); + AddBorderedText( 60, y+5, 250, 20, "No, I do not wish to fight.", LabelColor32, BlackColor32 ); + y += 35; + + AddRadio( 24, y, 9727, 9730, false, 3 ); + AddBorderedText( 60, y+5, 270, 20, "No, most certainly not. Do not ask again.", LabelColor32, BlackColor32 ); + y += 35; + + y -= 3; + AddButton( 314, y, 247, 248, 1, GumpButtonType.Reply, 0 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 15.0 ), new TimerCallback( AutoReject ) ); + } + + public void AutoReject() + { + if ( !m_Active ) + return; + + m_Active = false; + + m_Requested.CloseGump( typeof( AcceptTeamGump ) ); + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, String.Format( "{0} seems unresponsive.", m_Requested.Name ), m_From.NetState ); + + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, String.Format( "You have declined the partnership with {0}.", m_From.Name ), m_Requested.NetState ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = m_From; + Mobile mob = m_Requested; + + if ( info.ButtonID != 1 || !m_Active ) + return; + + m_Active = false; + + if ( info.IsSwitched( 1 ) ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + return; + + if ( AcceptDuelGump.IsIgnored( mob, from ) || mob.Blessed ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They ignore your invitation.", from.NetState ); + } + else if ( pm.DuelContext != null ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They are already assigned to another duel.", from.NetState ); + } + else if ( m_Players.Contains( mob ) ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "You have already named them as a team member.", from.NetState ); + } + else if ( m_Tournament.HasParticipant( mob ) ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "They have already entered this tournament.", from.NetState ); + } + else if ( m_Players.Count >= m_Tournament.PlayersPerParticipant ) + { + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, "Your team is full.", from.NetState ); + } + else + { + m_Players.Add( mob ); + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x59, false, String.Format( "{0} has accepted your offer of partnership.", mob.Name ), from.NetState ); + + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x59, false, String.Format( "You have accepted the partnership with {0}.", from.Name ), mob.NetState ); + } + } + } + else + { + if ( info.IsSwitched( 3 ) ) + AcceptDuelGump.BeginIgnore( m_Requested, m_From ); + + m_From.SendGump( new ConfirmSignupGump( m_From, m_Registrar, m_Tournament, m_Players ) ); + + if ( m_Registrar != null ) + { + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, String.Format( "{0} has declined your offer of partnership.", mob.Name ), from.NetState ); + + m_Registrar.PrivateOverheadMessage( MessageType.Regular, + 0x22, false, String.Format( "You have declined the partnership with {0}.", from.Name ), mob.NetState ); + } + } + } + } + + public class TournamentController : Item + { + private Tournament m_Tournament; + + [CommandProperty( AccessLevel.GameMaster )] + public Tournament Tournament{ get{ return m_Tournament; } set{} } + + private static ArrayList m_Instances = new ArrayList(); + + public static bool IsActive + { + get + { + for ( int i = 0; i < m_Instances.Count; ++i ) + { + TournamentController controller = (TournamentController)m_Instances[i]; + + if ( controller != null && !controller.Deleted && controller.Tournament != null && controller.Tournament.Stage!=TournamentStage.Inactive ) + return true; + } + + return false; + } + } + + public override string DefaultName + { + get { return "tournament controller"; } + } + + [Constructable] + public TournamentController() : base( 0x1B7A ) + { + Visible = false; + Movable = false; + + m_Tournament = new Tournament(); + m_Instances.Add( this ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.AccessLevel >= AccessLevel.GameMaster && m_Tournament != null ) + { + list.Add( new EditEntry( m_Tournament ) ); + + if ( m_Tournament.CurrentStage == TournamentStage.Inactive ) + list.Add( new StartEntry( m_Tournament ) ); + } + } + + private class EditEntry : ContextMenuEntry + { + private Tournament m_Tournament; + + public EditEntry( Tournament tourny ) : base( 5101 ) + { + m_Tournament = tourny; + } + + public override void OnClick() + { + Owner.From.SendGump( new PropertiesGump( Owner.From, m_Tournament ) ); + } + } + + private class StartEntry : ContextMenuEntry + { + private Tournament m_Tournament; + + public StartEntry( Tournament tourny ) : base( 5113 ) + { + m_Tournament = tourny; + } + + public override void OnClick() + { + if ( m_Tournament.Stage == TournamentStage.Inactive ) + { + m_Tournament.SignupStart = DateTime.Now; + m_Tournament.Stage = TournamentStage.Signup; + m_Tournament.Participants.Clear(); + m_Tournament.Pyramid.Levels.Clear(); + m_Tournament.Alert( "Hear ye! Hear ye!", "Tournament signup has opened. You can enter by signing up with the registrar." ); + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster && m_Tournament != null ) + { + from.CloseGump( typeof( PickRulesetGump ) ); + from.CloseGump( typeof( RulesetGump ) ); + from.SendGump( new PickRulesetGump( from, null, m_Tournament.Ruleset ) ); + } + } + + public TournamentController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + m_Tournament.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Tournament = new Tournament( reader ); + break; + } + } + + m_Instances.Add( this ); + } + + public override void OnDelete() + { + base.OnDelete(); + + m_Instances.Remove( this ); + } + } + + public enum TournyType + { + Standard, + FreeForAll, + RandomTeam, + RedVsBlue + } + + [PropertyObject] + public class Tournament + { + private int m_ParticipantsPerMatch; + private int m_PlayersPerParticipant; + private int m_LevelRequirement; + private TournyPyramid m_Pyramid; + private Ruleset m_Ruleset; + + private ArrayList m_Arenas; + private ArrayList m_Participants; + private ArrayList m_Undefeated; + + private TimeSpan m_SignupPeriod; + private DateTime m_SignupStart; + + private TournamentStage m_Stage; + + private GroupingType m_GroupType; + private TieType m_TieType; + private TimeSpan m_SuddenDeath; + + private TournyType m_TournyType; + + private int m_SuddenDeathRounds; + + private EventController m_EventController; + + public bool IsNotoRestricted { get { return ( m_TournyType != TournyType.Standard ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public EventController EventController + { + get { return m_EventController; } + set { m_EventController = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SuddenDeathRounds + { + get{ return m_SuddenDeathRounds; } + set{ m_SuddenDeathRounds = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TournyType TournyType + { + get{ return m_TournyType; } + set{ m_TournyType = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public GroupingType GroupType + { + get{ return m_GroupType; } + set{ m_GroupType = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TieType TieType + { + get{ return m_TieType; } + set{ m_TieType = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan SuddenDeath + { + get{ return m_SuddenDeath; } + set{ m_SuddenDeath = value; } + } + + public Ruleset Ruleset + { + get{ return m_Ruleset; } + set{ m_Ruleset = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ParticipantsPerMatch + { + get{ return m_ParticipantsPerMatch; } + set{ if ( value < 2 ) value = 2; else if ( value > 10 ) value = 10; m_ParticipantsPerMatch = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PlayersPerParticipant + { + get{ return m_PlayersPerParticipant; } + set{ if ( value < 1 ) value = 1; else if ( value > 10 ) value = 10; m_PlayersPerParticipant = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int LevelRequirement + { + get{ return m_LevelRequirement; } + set{ m_LevelRequirement = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan SignupPeriod + { + get{ return m_SignupPeriod; } + set{ m_SignupPeriod = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime SignupStart + { + get{ return m_SignupStart; } + set{ m_SignupStart = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TournamentStage CurrentStage + { + get{ return m_Stage; } + } + + public TournamentStage Stage + { + get{ return m_Stage; } + set{ m_Stage = value; } + } + + public TournyPyramid Pyramid + { + get{ return m_Pyramid; } + set{ m_Pyramid = value; } + } + + public ArrayList Arenas + { + get{ return m_Arenas; } + set{ m_Arenas = value; } + } + + public ArrayList Participants + { + get{ return m_Participants; } + set{ m_Participants = value; } + } + + public ArrayList Undefeated + { + get{ return m_Undefeated; } + set{ m_Undefeated = value; } + } + + public bool HasParticipant( Mobile mob ) + { + for ( int i = 0; i < m_Participants.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)m_Participants[i]; + + if ( part.Players.Contains( mob ) ) + return true; + } + + return false; + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 4 ); // version + + writer.Write( (Item) m_EventController ); + + writer.WriteEncodedInt( (int) m_SuddenDeathRounds ); + + writer.WriteEncodedInt( (int) m_TournyType ); + + writer.WriteEncodedInt( (int) m_GroupType ); + writer.WriteEncodedInt( (int) m_TieType ); + writer.Write( (TimeSpan) m_SuddenDeath ); + + writer.WriteEncodedInt( (int) m_ParticipantsPerMatch ); + writer.WriteEncodedInt( (int) m_PlayersPerParticipant ); + writer.Write( (TimeSpan) m_SignupPeriod ); + } + + public Tournament( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 4: + { + m_EventController = reader.ReadItem() as EventController; + + goto case 3; + } + case 3: + { + m_SuddenDeathRounds = reader.ReadEncodedInt(); + + goto case 2; + } + case 2: + { + m_TournyType = (TournyType)reader.ReadEncodedInt(); + + goto case 1; + } + case 1: + { + m_GroupType = (GroupingType)reader.ReadEncodedInt(); + m_TieType = (TieType)reader.ReadEncodedInt(); + m_SignupPeriod = reader.ReadTimeSpan(); + + goto case 0; + } + case 0: + { + if ( version < 3 ) + m_SuddenDeathRounds = 3; + + m_ParticipantsPerMatch = reader.ReadEncodedInt(); + m_PlayersPerParticipant = reader.ReadEncodedInt(); + m_SignupPeriod = reader.ReadTimeSpan(); + m_Stage = TournamentStage.Inactive; + m_Pyramid = new TournyPyramid(); + m_Ruleset = new Ruleset( RulesetLayout.Root ); + m_Ruleset.ApplyDefault( m_Ruleset.Layout.Defaults[0] ); + m_Participants = new ArrayList(); + m_Undefeated = new ArrayList(); + m_Arenas = new ArrayList(); + + break; + } + } + + Timer.DelayCall( SliceInterval, SliceInterval, new TimerCallback( Slice ) ); + } + + public Tournament() + { + m_ParticipantsPerMatch = 2; + m_PlayersPerParticipant = 1; + m_Pyramid = new TournyPyramid(); + m_Ruleset = new Ruleset( RulesetLayout.Root ); + m_Ruleset.ApplyDefault( m_Ruleset.Layout.Defaults[0] ); + m_Participants = new ArrayList(); + m_Undefeated = new ArrayList(); + m_Arenas = new ArrayList(); + m_SignupPeriod = TimeSpan.FromMinutes( 10.0 ); + + Timer.DelayCall( SliceInterval, SliceInterval, new TimerCallback( Slice ) ); + } + + public void HandleTie( Arena arena, TournyMatch match, ArrayList remaining ) + { + if ( remaining.Count == 1 ) + HandleWon( arena, match, (TournyParticipant)remaining[0] ); + + if ( remaining.Count < 2 ) + return; + + StringBuilder sb = new StringBuilder(); + + sb.Append( "The match has ended in a tie " ); + + if ( remaining.Count == 2 ) + sb.Append( "between " ); + else + sb.Append( "among " ); + + sb.Append( remaining.Count ); + + if ( ((TournyParticipant)remaining[0]).Players.Count == 1 ) + sb.Append( " players: " ); + else + sb.Append( " teams: " ); + + bool hasAppended = false; + + for ( int j = 0; j < match.Participants.Count; ++j ) + { + TournyParticipant part = (TournyParticipant)match.Participants[j]; + + if ( remaining.Contains( part ) ) + { + if ( hasAppended ) + sb.Append( ", " ); + + sb.Append( part.NameList ); + hasAppended = true; + } + else + { + m_Undefeated.Remove( part ); + } + } + + sb.Append( ". " ); + + string whole = ( remaining.Count == 2 ? "both" : "all" ); + + TieType tieType = m_TieType; + + if ( tieType == TieType.FullElimination && remaining.Count >= m_Undefeated.Count ) + tieType = TieType.FullAdvancement; + + switch ( m_TieType ) + { + case TieType.FullAdvancement: + { + sb.AppendFormat( "In accordance with the rules, {0} parties are advanced.", whole ); + break; + } + case TieType.FullElimination: + { + for ( int j = 0; j < remaining.Count; ++j ) + m_Undefeated.Remove( remaining[j] ); + + sb.AppendFormat( "In accordance with the rules, {0} parties are eliminated.", whole ); + break; + } + case TieType.Random: + { + TournyParticipant advanced = (TournyParticipant)remaining[Utility.Random( remaining.Count )]; + + for ( int i = 0; i < remaining.Count; ++i ) + { + if ( remaining[i] != advanced ) + m_Undefeated.Remove( remaining[i] ); + } + + if ( advanced != null ) + sb.AppendFormat( "In accordance with the rules, {0} {1} advanced.", advanced.NameList, advanced.Players.Count == 1 ? "is" : "are" ); + + break; + } + case TieType.Highest: + { + TournyParticipant advanced = null; + + for ( int i = 0; i < remaining.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)remaining[i]; + + if ( advanced == null || part.TotalLadderXP > advanced.TotalLadderXP ) + advanced = part; + } + + for ( int i = 0; i < remaining.Count; ++i ) + { + if ( remaining[i] != advanced ) + m_Undefeated.Remove( remaining[i] ); + } + + if ( advanced != null ) + sb.AppendFormat( "In accordance with the rules, {0} {1} advanced.", advanced.NameList, advanced.Players.Count == 1 ? "is" : "are" ); + + break; + } + case TieType.Lowest: + { + TournyParticipant advanced = null; + + for ( int i = 0; i < remaining.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)remaining[i]; + + if ( advanced == null || part.TotalLadderXP < advanced.TotalLadderXP ) + advanced = part; + } + + for ( int i = 0; i < remaining.Count; ++i ) + { + if ( remaining[i] != advanced ) + m_Undefeated.Remove( remaining[i] ); + } + + if ( advanced != null ) + sb.AppendFormat( "In accordance with the rules, {0} {1} advanced.", advanced.NameList, advanced.Players.Count == 1 ? "is" : "are" ); + + break; + } + } + + Alert( arena, sb.ToString() ); + } + + public void OnEliminated( DuelPlayer player ) + { + Participant part = player.Participant; + + if ( !part.Eliminated ) + return; + + if ( m_TournyType == TournyType.FreeForAll ) + { + int rem = 0; + + for ( int i = 0; i < part.Context.Participants.Count; ++i ) + { + Participant check = (Participant)part.Context.Participants[i]; + + if ( check != null && !check.Eliminated ) + ++rem; + } + + TournyParticipant tp = part.TournyPart; + + if ( tp == null ) + return; + + if ( rem == 1 ) + GiveAwards( tp.Players, TrophyRank.Silver, ComputeCashAward() / 2 ); + else if ( rem == 2 ) + GiveAwards( tp.Players, TrophyRank.Bronze, ComputeCashAward() / 4 ); + } + } + + public void HandleWon( Arena arena, TournyMatch match, TournyParticipant winner ) + { + StringBuilder sb = new StringBuilder(); + + sb.Append( "The match is complete. " ); + sb.Append( winner.NameList ); + + if ( winner.Players.Count > 1 ) + sb.Append( " have bested " ); + else + sb.Append( " has bested " ); + + if ( match.Participants.Count > 2 ) + sb.AppendFormat( "{0} other {1}: ", match.Participants.Count - 1, winner.Players.Count == 1 ? "players" : "teams" ); + + bool hasAppended = false; + + for ( int j = 0; j < match.Participants.Count; ++j ) + { + TournyParticipant part = (TournyParticipant)match.Participants[j]; + + if ( part == winner ) + continue; + + m_Undefeated.Remove( part ); + + if ( hasAppended ) + sb.Append( ", " ); + + sb.Append( part.NameList ); + hasAppended = true; + } + + sb.Append( "." ); + + if ( m_TournyType == TournyType.Standard ) + Alert( arena, sb.ToString() ); + } + + private static readonly TimeSpan SliceInterval = TimeSpan.FromSeconds( 12.0 ); + + private int ComputeCashAward() + { + return m_Participants.Count * m_PlayersPerParticipant * 2500; + } + + private void GiveAwards() + { + switch ( m_TournyType ) + { + case TournyType.FreeForAll: + { + if ( m_Pyramid.Levels.Count < 1 ) + break; + + PyramidLevel top = m_Pyramid.Levels[m_Pyramid.Levels.Count - 1] as PyramidLevel; + + if ( top.FreeAdvance != null || top.Matches.Count != 1 ) + break; + + TournyMatch match = top.Matches[0] as TournyMatch; + TournyParticipant winner = match.Winner; + + if ( winner != null ) + GiveAwards( winner.Players, TrophyRank.Gold, ComputeCashAward() ); + + break; + } + case TournyType.Standard: + { + if ( m_Pyramid.Levels.Count < 2 ) + break; + + PyramidLevel top = m_Pyramid.Levels[m_Pyramid.Levels.Count - 1] as PyramidLevel; + + if ( top.FreeAdvance != null || top.Matches.Count != 1 ) + break; + + int cash = ComputeCashAward(); + + TournyMatch match = top.Matches[0] as TournyMatch; + TournyParticipant winner = match.Winner; + + for ( int i = 0; i < match.Participants.Count; ++i ) + { + TournyParticipant part = (TournyParticipant) match.Participants[i]; + + if ( part == winner ) + GiveAwards( part.Players, TrophyRank.Gold, cash ); + else + GiveAwards( part.Players, TrophyRank.Silver, cash / 2 ); + } + + PyramidLevel next = m_Pyramid.Levels[m_Pyramid.Levels.Count - 2] as PyramidLevel; + + if ( next.Matches.Count > 2 ) + break; + + for ( int i = 0; i < next.Matches.Count; ++i ) + { + match = (TournyMatch)next.Matches[i]; + winner = match.Winner; + + for ( int j = 0; j < match.Participants.Count; ++j ) + { + TournyParticipant part = (TournyParticipant) match.Participants[j]; + + if ( part != winner ) + GiveAwards( part.Players, TrophyRank.Bronze, cash / 4 ); + } + } + + break; + } + } + } + + private void GiveAwards( ArrayList players, TrophyRank rank, int cash ) + { + if ( players.Count == 0 ) + return; + + if ( players.Count > 1 ) + cash /= ( players.Count - 1 ); + + cash += 500; + cash /= 1000; + cash *= 1000; + + StringBuilder sb = new StringBuilder(); + + if ( m_TournyType == TournyType.FreeForAll ) + { + sb.Append( m_Participants.Count * m_PlayersPerParticipant ); + sb.Append( "-man FFA" ); + } + else if ( m_TournyType == TournyType.RandomTeam ) + { + sb.Append( m_ParticipantsPerMatch ); + sb.Append( "-team" ); + } + else if ( m_TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else + { + for ( int i = 0; i < m_ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( m_PlayersPerParticipant ); + } + } + + if ( m_EventController != null ) + sb.Append( ' ' ).Append( m_EventController.Title ); + + sb.Append( " Champion" ); + + string title = sb.ToString(); + + for ( int i = 0; i < players.Count; ++i ) + { + Mobile mob = (Mobile) players[i]; + + if ( mob == null || mob.Deleted ) + continue; + + Item item = new Trophy( title, rank ); + + if ( !mob.PlaceInBackpack( item ) ) + mob.BankBox.DropItem( item ); + + if ( cash > 0 ) + { + item = new BankCheck( cash ); + + if ( !mob.PlaceInBackpack( item ) ) + mob.BankBox.DropItem( item ); + + mob.SendMessage( "You have been awarded a {0} trophy and {1:N0}gp for your participation in this tournament.", rank.ToString().ToLower(), cash ); + } + else + { + mob.SendMessage( "You have been awarded a {0} trophy for your participation in this tournament.", rank.ToString().ToLower() ); + } + } + } + + public void Slice() + { + if ( m_Stage == TournamentStage.Signup ) + { + TimeSpan until = ( m_SignupStart + m_SignupPeriod ) - DateTime.Now; + + if ( until <= TimeSpan.Zero ) + { + for ( int i = m_Participants.Count - 1; i >= 0; --i ) + { + TournyParticipant part = (TournyParticipant)m_Participants[i]; + bool bad = false; + + for ( int j = 0; j < part.Players.Count; ++j ) + { + Mobile check = (Mobile) part.Players[j]; + + if ( check.Deleted || check.Map == null || check.Map == Map.Internal || !check.Alive || Factions.Sigil.ExistsOn( check ) || check.Region.IsPartOf( typeof( Regions.Jail ) ) ) + { + bad = true; + break; + } + } + + if ( bad ) + { + for ( int j = 0; j < part.Players.Count; ++j ) + ((Mobile)part.Players[j]).SendMessage( "You have been disqualified from the tournament." ); + + m_Participants.RemoveAt( i ); + } + } + + if ( m_Participants.Count >= 2 ) + { + m_Stage = TournamentStage.Fighting; + + m_Undefeated.Clear(); + + m_Pyramid.Levels.Clear(); + m_Pyramid.AddLevel( m_ParticipantsPerMatch, m_Participants, m_GroupType, m_TournyType ); + + PyramidLevel level = (PyramidLevel)m_Pyramid.Levels[0]; + + if ( level.FreeAdvance != null ) + m_Undefeated.Add( level.FreeAdvance ); + + for ( int i = 0; i < level.Matches.Count; ++i ) + { + TournyMatch match = (TournyMatch)level.Matches[i]; + + m_Undefeated.AddRange( match.Participants ); + } + + Alert( "Hear ye! Hear ye!", "The tournament will begin shortly." ); + } + else + { + Alert( "Is this all?", "Pitiful. Signup extended." ); + m_SignupStart = DateTime.Now; + } + } + else if ( Math.Abs( until.TotalSeconds - TimeSpan.FromMinutes( 1.0 ).TotalSeconds ) < (SliceInterval.TotalSeconds/2) ) + { + Alert( "Last call!", "If you wish to enter the tournament, sign up with the registrar now." ); + } + else if ( Math.Abs( until.TotalSeconds - TimeSpan.FromMinutes( 5.0 ).TotalSeconds ) < (SliceInterval.TotalSeconds/2) ) + { + Alert( "The tournament will begin in 5 minutes.", "Sign up now before it's too late." ); + } + } + else if ( m_Stage == TournamentStage.Fighting ) + { + if ( m_Undefeated.Count == 1 ) + { + TournyParticipant winner = (TournyParticipant)m_Undefeated[0]; + + try + { + if ( m_EventController != null ) + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", m_EventController.GetTeamName( ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) ) ) ); + else if ( m_TournyType == TournyType.RandomTeam ) + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) + 1 ) ); + else if ( m_TournyType == TournyType.RedVsBlue ) + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) == 0 ? "Red" : "Blue" ) ); + else + Alert( "The tournament has completed!", String.Format( "{0} {1} the champion{2}.", winner.NameList, winner.Players.Count > 1 ? "are" : "is", winner.Players.Count == 1 ? "" : "s" ) ); + } + catch + { + } + + GiveAwards(); + + m_Stage = TournamentStage.Inactive; + m_Undefeated.Clear(); + } + else if ( m_Pyramid.Levels.Count > 0 ) + { + PyramidLevel activeLevel = (PyramidLevel)m_Pyramid.Levels[m_Pyramid.Levels.Count - 1]; + bool stillGoing = false; + + for ( int i = 0; i < activeLevel.Matches.Count; ++i ) + { + TournyMatch match = (TournyMatch)activeLevel.Matches[i]; + + if ( match.Winner == null ) + { + stillGoing = true; + + if ( !match.InProgress ) + { + for ( int j = 0; j < m_Arenas.Count; ++j ) + { + Arena arena = (Arena)m_Arenas[j]; + + if ( !arena.IsOccupied ) + { + match.Start( arena, this ); + break; + } + } + } + } + } + + if ( !stillGoing ) + { + for ( int i = m_Undefeated.Count - 1; i >= 0; --i ) + { + TournyParticipant part = (TournyParticipant)m_Undefeated[i]; + bool bad = false; + + for ( int j = 0; j < part.Players.Count; ++j ) + { + Mobile check = (Mobile) part.Players[j]; + + if ( check.Deleted || check.Map == null || check.Map == Map.Internal || !check.Alive || Factions.Sigil.ExistsOn( check ) || check.Region.IsPartOf( typeof( Regions.Jail ) ) ) + { + bad = true; + break; + } + } + + if ( bad ) + { + for ( int j = 0; j < part.Players.Count; ++j ) + ((Mobile)part.Players[j]).SendMessage( "You have been disqualified from the tournament." ); + + m_Undefeated.RemoveAt( i ); + + if ( m_Undefeated.Count == 1 ) + { + TournyParticipant winner = (TournyParticipant)m_Undefeated[0]; + + try + { + if ( m_EventController != null ) + Alert( "The tournament has completed!", String.Format( "Team {0} has won", m_EventController.GetTeamName( ( (TournyMatch) ( (PyramidLevel) m_Pyramid.Levels[0] ).Matches[0] ).Participants.IndexOf( winner ) ) ) ); + else if ( m_TournyType == TournyType.RandomTeam ) + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) + 1 ) ); + else if ( m_TournyType == TournyType.RedVsBlue ) + Alert( "The tournament has completed!", String.Format( "Team {0} has won!", ((TournyMatch)((PyramidLevel)m_Pyramid.Levels[0]).Matches[0]).Participants.IndexOf( winner ) == 0 ? "Red" : "Blue" ) ); + else + Alert( "The tournament has completed!", String.Format( "{0} {1} the champion{2}.", winner.NameList, winner.Players.Count > 1 ? "are" : "is", winner.Players.Count == 1 ? "" : "s" ) ); + } + catch + { + } + + GiveAwards(); + + m_Stage = TournamentStage.Inactive; + m_Undefeated.Clear(); + break; + } + } + } + + if ( m_Undefeated.Count > 1 ) + m_Pyramid.AddLevel( m_ParticipantsPerMatch, m_Undefeated, m_GroupType, m_TournyType ); + } + } + } + } + + public void Alert( params string[] alerts ) + { + for ( int i = 0; i < m_Arenas.Count; ++i ) + Alert( (Arena) m_Arenas[i], alerts ); + } + + public void Alert( Arena arena, params string[] alerts ) + { + if ( arena != null && arena.Announcer != null ) + { + for ( int j = 0; j < alerts.Length; ++j ) + Timer.DelayCall( TimeSpan.FromSeconds( Math.Max( j-0.5, 0.0 ) ), new TimerStateCallback( Alert_Callback ), new object[]{ arena.Announcer, alerts[j] } ); + } + } + + private void Alert_Callback( object state ) + { + object[] states = (object[])state; + + if ( states[0] != null ) + ((Mobile)states[0]).PublicOverheadMessage( MessageType.Regular, 0x35, false, (string)states[1] ); + } + } + + public class TournyPyramid + { + private ArrayList m_Levels; + + public ArrayList Levels + { + get{ return m_Levels; } + set{ m_Levels = value; } + } + + public TournyPyramid() + { + m_Levels = new ArrayList(); + } + + public void AddLevel( int partsPerMatch, ArrayList participants, GroupingType groupType, TournyType tournyType ) + { + ArrayList copy = new ArrayList( participants ); + + if ( groupType == GroupingType.Nearest || groupType == GroupingType.HighVsLow ) + copy.Sort(); + + PyramidLevel level = new PyramidLevel(); + + switch ( tournyType ) + { + case TournyType.RedVsBlue: + { + TournyParticipant[] parts = new TournyParticipant[2]; + + for ( int i = 0; i < parts.Length; ++i ) + parts[i] = new TournyParticipant( new ArrayList() ); + + for ( int i = 0; i < copy.Count; ++i ) + { + ArrayList players = ((TournyParticipant)copy[i]).Players; + + for ( int j = 0; j < players.Count; ++j ) + { + Mobile mob = (Mobile) players[j]; + + if ( mob.Kills >= 5 ) + parts[0].Players.Add( mob ); + else + parts[1].Players.Add( mob ); + } + } + + level.Matches.Add( new TournyMatch( new ArrayList( parts ) ) ); + break; + } + case TournyType.RandomTeam: + { + TournyParticipant[] parts = new TournyParticipant[partsPerMatch]; + + for ( int i = 0; i < partsPerMatch; ++i ) + parts[i] = new TournyParticipant( new ArrayList() ); + + for ( int i = 0; i < copy.Count; ++i ) + parts[i % parts.Length].Players.AddRange( ((TournyParticipant)copy[i]).Players ); + + level.Matches.Add( new TournyMatch( new ArrayList( parts ) ) ); + break; + } + case TournyType.FreeForAll: + { + level.Matches.Add( new TournyMatch( copy ) ); + break; + } + case TournyType.Standard: + { + if (partsPerMatch >= 2 && participants.Count % partsPerMatch == 1) + { + int lowAdvances = int.MaxValue; + + for ( int i = 0; i < participants.Count; ++i ) + { + TournyParticipant p = (TournyParticipant)participants[i]; + + if ( p.FreeAdvances < lowAdvances ) + lowAdvances = p.FreeAdvances; + } + + ArrayList toAdvance = new ArrayList(); + + for ( int i = 0; i < participants.Count; ++i ) + { + TournyParticipant p = (TournyParticipant)participants[i]; + + if ( p.FreeAdvances == lowAdvances ) + toAdvance.Add( p ); + } + + if ( toAdvance.Count == 0 ) + toAdvance = copy; // sanity + + int idx = Utility.Random( toAdvance.Count ); + + ((TournyParticipant)toAdvance[idx]).AddLog( "Advanced automatically due to an odd number of challengers." ); + level.FreeAdvance = (TournyParticipant)toAdvance[idx]; + ++level.FreeAdvance.FreeAdvances; + copy.Remove( toAdvance[idx] ); + } + + while ( copy.Count >= partsPerMatch ) + { + ArrayList thisMatch = new ArrayList(); + + for ( int i = 0; i < partsPerMatch; ++i ) + { + int idx = 0; + + switch ( groupType ) + { + case GroupingType.HighVsLow: idx = (i * (copy.Count - 1)) / (partsPerMatch - 1); break; + case GroupingType.Nearest: idx = 0; break; + case GroupingType.Random: idx = Utility.Random( copy.Count ); break; + } + + thisMatch.Add( copy[idx] ); + copy.RemoveAt( idx ); + } + + level.Matches.Add( new TournyMatch( thisMatch ) ); + } + + if ( copy.Count > 1 ) + level.Matches.Add( new TournyMatch( copy ) ); + + break; + } + } + + m_Levels.Add( level ); + } + } + + public class PyramidLevel + { + private ArrayList m_Matches; + private TournyParticipant m_FreeAdvance; + + public ArrayList Matches + { + get{ return m_Matches; } + set{ m_Matches = value; } + } + + public TournyParticipant FreeAdvance + { + get{ return m_FreeAdvance; } + set{ m_FreeAdvance = value; } + } + + public PyramidLevel() + { + m_Matches = new ArrayList(); + } + } + + public class TournyMatch + { + private ArrayList m_Participants; + private TournyParticipant m_Winner; + private DuelContext m_Context; + + public ArrayList Participants + { + get{ return m_Participants; } + set{ m_Participants = value; } + } + + public TournyParticipant Winner + { + get{ return m_Winner; } + set{ m_Winner = value; } + } + + public DuelContext Context + { + get{ return m_Context; } + set{ m_Context = value; } + } + + public bool InProgress + { + get{ return ( m_Context != null && m_Context.Registered ); } + } + + public void Start( Arena arena, Tournament tourny ) + { + TournyParticipant first = (TournyParticipant)m_Participants[0]; + + DuelContext dc = new DuelContext( (Mobile)first.Players[0], tourny.Ruleset.Layout, false ); + dc.Ruleset.Options.SetAll(false); + dc.Ruleset.Options.Or(tourny.Ruleset.Options); + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + TournyParticipant tournyPart = (TournyParticipant)m_Participants[i]; + Participant duelPart = new Participant( dc, tournyPart.Players.Count ); + + duelPart.TournyPart = tournyPart; + + for ( int j = 0; j < tournyPart.Players.Count; ++j ) + duelPart.Add( (Mobile) tournyPart.Players[j] ); + + for ( int j = 0; j < duelPart.Players.Length; ++j ) + { + if ( duelPart.Players[j] != null ) + duelPart.Players[j].Ready = true; + } + + dc.Participants.Add( duelPart ); + } + + if ( tourny.EventController != null ) + dc.m_EventGame = tourny.EventController.Construct( dc ); + + dc.m_Tournament = tourny; + dc.m_Match = this; + + dc.m_OverrideArena = arena; + + if ( tourny.SuddenDeath > TimeSpan.Zero && (tourny.SuddenDeathRounds == 0 || tourny.Pyramid.Levels.Count <= tourny.SuddenDeathRounds) ) + dc.StartSuddenDeath( tourny.SuddenDeath ); + + dc.SendReadyGump( 0 ); + + if ( dc.StartedBeginCountdown ) + { + m_Context = dc; + + for ( int i = 0; i < m_Participants.Count; ++i ) + { + TournyParticipant p = (TournyParticipant)m_Participants[i]; + + for ( int j = 0; j < p.Players.Count; ++j ) + { + Mobile mob = (Mobile)p.Players[j]; + + foreach ( Mobile view in mob.GetMobilesInRange( 18 ) ) + { + if ( !mob.CanSee( view ) ) + mob.Send( view.RemovePacket ); + } + + mob.LocalOverheadMessage( MessageType.Emote, 0x3B2, false, "* Your mind focuses intently on the fight and all other distractions fade away *" ); + } + } + } + else + { + dc.Unregister(); + dc.StopCountdown(); + } + } + + public TournyMatch( ArrayList participants ) + { + m_Participants = participants; + + for ( int i = 0; i < participants.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)participants[i]; + + StringBuilder sb = new StringBuilder(); + + sb.Append( "Matched in a duel against " ); + + if ( participants.Count > 2 ) + sb.AppendFormat( "{0} other {1}: ", participants.Count - 1, part.Players.Count == 1 ? "players" : "teams" ); + + bool hasAppended = false; + + for ( int j = 0; j < participants.Count; ++j ) + { + if ( i == j ) + continue; + + if ( hasAppended ) + sb.Append( ", " ); + + sb.Append( ((TournyParticipant)participants[j]).NameList ); + hasAppended = true; + } + + sb.Append( "." ); + + part.AddLog( sb.ToString() ); + } + } + } + + public class TournyParticipant : IComparable + { + private ArrayList m_Players; + private ArrayList m_Log; + private int m_FreeAdvances; + + public ArrayList Players + { + get{ return m_Players; } + set{ m_Players = value; } + } + + public ArrayList Log + { + get{ return m_Log; } + set{ m_Log = value; } + } + + public int FreeAdvances + { + get{ return m_FreeAdvances; } + set{ m_FreeAdvances = value; } + } + + public int TotalLadderXP + { + get + { + Ladder ladder = Ladder.Instance; + + if ( ladder == null ) + return 0; + + int total = 0; + + for ( int i = 0; i < m_Players.Count; ++i ) + { + Mobile mob = (Mobile)m_Players[i]; + LadderEntry entry = ladder.Find( mob ); + + if ( entry != null ) + total += entry.Experience; + } + + return total; + } + } + + public string NameList + { + get + { + StringBuilder sb = new StringBuilder(); + + for ( int i = 0; i < m_Players.Count; ++i ) + { + if ( m_Players[i] == null ) + continue; + + Mobile mob = (Mobile) m_Players[i]; + + if ( sb.Length > 0 ) + { + if ( m_Players.Count == 2 ) + sb.Append( " and " ); + else if ( (i+1) < m_Players.Count ) + sb.Append( ", " ); + else + sb.Append( ", and " ); + } + + sb.Append( mob.Name ); + } + + if ( sb.Length == 0 ) + return "Empty"; + + return sb.ToString(); + } + } + + public void AddLog( string text ) + { + m_Log.Add( text ); + } + + public void AddLog( string format, params object[] args ) + { + AddLog( String.Format( format, args ) ); + } + + public void WonMatch( TournyMatch match ) + { + AddLog( "Match won." ); + } + + public void LostMatch( TournyMatch match ) + { + AddLog( "Match lost." ); + } + + public TournyParticipant( Mobile owner ) + { + m_Log = new ArrayList(); + m_Players = new ArrayList(); + m_Players.Add( owner ); + } + + public TournyParticipant( ArrayList players ) + { + m_Log = new ArrayList(); + m_Players = players; + } + + public int CompareTo( object obj ) + { + TournyParticipant p = (TournyParticipant)obj; + + return p.TotalLadderXP - this.TotalLadderXP; + } + } + + public enum TournyBracketGumpType + { + Index, + Rules_Info, + Participant_List, + Participant_Info, + Round_List, + Round_Info, + Match_Info, + Player_Info + } + + public class TournamentBracketGump : Gump + { + private Mobile m_From; + private Tournament m_Tournament; + private TournyBracketGumpType m_Type; + private ArrayList m_List; + private int m_Page; + private int m_PerPage; + private object m_Object; + + private const int BlackColor32 = 0x000008; + private const int LabelColor32 = 0xFFFFFF; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private void AddBorderedText( int x, int y, int width, int height, string text, int color, int borderColor ) + { + AddColoredText( x - 1, y - 1, width, height, text, borderColor ); + AddColoredText( x - 1, y + 1, width, height, text, borderColor ); + AddColoredText( x + 1, y - 1, width, height, text, borderColor ); + AddColoredText( x + 1, y + 1, width, height, text, borderColor ); + AddColoredText( x, y, width, height, text, color ); + } + + private void AddColoredText( int x, int y, int width, int height, string text, int color ) + { + if ( color == 0 ) + AddHtml( x, y, width, height, text, false, false ); + else + AddHtml( x, y, width, height, Color( text, color ), false, false ); + } + + public void AddRightArrow( int x, int y, int bid, string text ) + { + AddButton( x, y, 0x15E1, 0x15E5, bid, GumpButtonType.Reply, 0 ); + + if ( text != null ) + AddHtml( x + 20, y - 1, 230, 20, text, false, false ); + } + + public void AddRightArrow( int x, int y, int bid ) + { + AddRightArrow( x, y, bid, null ); + } + + public void AddLeftArrow( int x, int y, int bid, string text ) + { + AddButton( x, y, 0x15E3, 0x15E7, bid, GumpButtonType.Reply, 0 ); + + if ( text != null ) + AddHtml( x + 20, y - 1, 230, 20, text, false, false ); + } + + public void AddLeftArrow( int x, int y, int bid ) + { + AddLeftArrow( x, y, bid, null ); + } + + public int ToButtonID( int type, int index ) + { + return 1 + (index * 7) + type; + } + + public bool FromButtonID( int bid, out int type, out int index ) + { + type = ( bid - 1 ) % 7; + index = ( bid - 1 ) / 7; + return ( bid >= 1 ); + } + + public void StartPage( out int index, out int count, out int y, int perPage ) + { + m_PerPage = perPage; + + index = Math.Max( m_Page * perPage, 0 ); + count = Math.Max( Math.Min( m_List.Count - index, perPage ), 0 ); + + y = 53 + ((12 - perPage) * 18); + + if ( m_Page > 0 ) + AddLeftArrow( 242, 35, ToButtonID( 1, 0 ) ); + + if ( (m_Page + 1) * perPage < m_List.Count ) + AddRightArrow( 260, 35, ToButtonID( 1, 1 ) ); + } + + public TournamentBracketGump( Mobile from, Tournament tourny, TournyBracketGumpType type, ArrayList list, int page, object obj ) : base( 50, 50 ) + { + m_From = from; + m_Tournament = tourny; + m_Type = type; + m_List = list; + m_Page = page; + m_Object = obj; + m_PerPage = 12; + + switch ( type ) + { + case TournyBracketGumpType.Index: + { + AddPage( 0 ); + AddBackground( 0, 0, 300, 300, 9380 ); + + StringBuilder sb = new StringBuilder(); + + if ( tourny.TournyType == TournyType.FreeForAll ) + { + sb.Append( "FFA" ); + } + else if ( tourny.TournyType == TournyType.RandomTeam ) + { + sb.Append( "Team" ); + } + else if ( tourny.TournyType == TournyType.RedVsBlue ) + { + sb.Append( "Red v Blue" ); + } + else + { + for ( int i = 0; i < tourny.ParticipantsPerMatch; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( 'v' ); + + sb.Append( tourny.PlayersPerParticipant ); + } + } + + if ( tourny.EventController != null ) + sb.Append( ' ' ).Append( tourny.EventController.Title ); + + sb.Append( " Tournament Bracket" ); + + AddHtml( 25, 35, 250, 20, Center( sb.ToString() ), false, false ); + + AddRightArrow( 25, 53, ToButtonID( 0, 4 ), "Rules" ); + AddRightArrow( 25, 71, ToButtonID( 0, 1 ), "Participants" ); + + if ( m_Tournament.Stage == TournamentStage.Signup ) + { + TimeSpan until = ( m_Tournament.SignupStart + m_Tournament.SignupPeriod ) - DateTime.Now; + string text; + int secs = (int) until.TotalSeconds; + + if ( secs > 0 ) + { + int mins = secs / 60; + secs %= 60; + + if ( mins > 0 && secs > 0 ) + text = String.Format( "The tournament will begin in {0} minute{1} and {2} second{3}.", mins, mins==1?"":"s", secs, secs==1?"":"s" ); + else if ( mins > 0 ) + text = String.Format( "The tournament will begin in {0} minute{1}.", mins, mins==1?"":"s" ); + else if ( secs > 0 ) + text = String.Format( "The tournament will begin in {0} second{1}.", secs, secs==1?"":"s" ); + else + text = "The tournament will begin shortly."; + } + else + { + text = "The tournament will begin shortly."; + } + + AddHtml( 25, 92, 250, 40, text, false, false ); + } + else + { + AddRightArrow( 25, 89, ToButtonID( 0, 2 ), "Rounds" ); + } + + break; + } + case TournyBracketGumpType.Rules_Info: + { + Ruleset ruleset = tourny.Ruleset; + Ruleset basedef = ruleset.Base; + + BitArray defs; + + if ( ruleset.Flavors.Count > 0 ) + { + defs = new BitArray( basedef.Options ); + + for ( int i = 0; i < ruleset.Flavors.Count; ++i ) + defs.Or( ((Ruleset)ruleset.Flavors[i]).Options ); + } + else + { + defs = basedef.Options; + } + + int changes = 0; + + BitArray opts = ruleset.Options; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + ++changes; + } + + AddPage( 0 ); + AddBackground( 0, 0, 300, 60 + 18 + 20 + 20 + 20 + 8 + 20 + (ruleset.Flavors.Count * 18) + 4 + 20 + (changes * 22) + 6, 9380 ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 0 ) ); + AddHtml( 25, 35, 250, 20, Center( "Rules" ), false, false ); + + int y = 53; + + string groupText = null; + + switch ( tourny.GroupType ) + { + case GroupingType.HighVsLow: groupText = "High vs Low"; break; + case GroupingType.Nearest: groupText = "Closest opponent"; break; + case GroupingType.Random: groupText = "Random"; break; + } + + AddHtml( 35, y, 190, 20, String.Format( "Grouping: {0}", groupText ), false, false ); + y += 20; + + string tieText = null; + + switch ( tourny.TieType ) + { + case TieType.Random: tieText = "Random"; break; + case TieType.Highest: tieText = "Highest advances"; break; + case TieType.Lowest: tieText = "Lowest advances"; break; + case TieType.FullAdvancement: tieText = ( tourny.ParticipantsPerMatch == 2 ? "Both advance" : "Everyone advances" ); break; + case TieType.FullElimination: tieText = ( tourny.ParticipantsPerMatch == 2 ? "Both eliminated" : "Everyone eliminated" ); break; + } + + AddHtml( 35, y, 190, 20, String.Format( "Tiebreaker: {0}", tieText ), false, false ); + y += 20; + + string sdText = "Off"; + + if ( tourny.SuddenDeath > TimeSpan.Zero ) + { + sdText = String.Format( "{0}:{1:D2}", (int) tourny.SuddenDeath.TotalMinutes, tourny.SuddenDeath.Seconds ); + + if ( tourny.SuddenDeathRounds > 0 ) + sdText = String.Format( "{0} (first {1} rounds)", sdText, tourny.SuddenDeathRounds ); + else + sdText = String.Format( "{0} (all rounds)", sdText ); + } + + AddHtml( 35, y, 240, 20, String.Format( "Sudden Death: {0}", sdText ), false, false ); + y += 20; + + y += 8; + + AddHtml( 35, y, 190, 20, String.Format( "Ruleset: {0}", basedef.Title ), false, false ); + y += 20; + + for ( int i = 0; i < ruleset.Flavors.Count; ++i, y += 18 ) + AddHtml( 35, y, 190, 20, String.Format( " + {0}", ((Ruleset)ruleset.Flavors[i]).Title ), false, false ); + + y += 4; + + if ( changes > 0 ) + { + AddHtml( 35, y, 190, 20, "Modifications:", false, false ); + y += 20; + + for ( int i = 0; i < opts.Length; ++i ) + { + if ( defs[i] != opts[i] ) + { + string name = ruleset.Layout.FindByIndex( i ); + + if ( name != null ) // sanity + { + AddImage( 35, y, opts[i] ? 0xD3 : 0xD2 ); + AddHtml( 60, y, 165, 22, name, false, false ); + } + + y += 22; + } + } + } + else + { + AddHtml( 35, y, 190, 20, "Modifications: None", false, false ); + y += 20; + } + + break; + } + case TournyBracketGumpType.Participant_List: + { + AddPage( 0 ); + AddBackground( 0, 0, 300, 300, 9380 ); + + if ( m_List == null ) + m_List = new ArrayList( tourny.Participants ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 0 ) ); + AddHtml( 25, 35, 250, 20, Center( String.Format( "{0} Participant{1}", m_List.Count, m_List.Count == 1 ? "" : "s" ) ), false, false ); + + int index, count, y; + StartPage( out index, out count, out y, 12 ); + + for ( int i = 0; i < count; ++i, y += 18 ) + { + TournyParticipant part = (TournyParticipant)m_List[index + i]; + string name = part.NameList; + + if ( m_Tournament.TournyType != TournyType.Standard && part.Players.Count == 1 ) + { + PlayerMobile pm = part.Players[0] as PlayerMobile; + + if ( pm != null && pm.DuelPlayer != null ) + name = Color( name, pm.DuelPlayer.Eliminated ? 0x6633333 : 0x336666 ); + } + + AddRightArrow( 25, y, ToButtonID( 2, index + i ), name ); + } + + break; + } + case TournyBracketGumpType.Participant_Info: + { + TournyParticipant part = obj as TournyParticipant; + + if ( part == null ) + break; + + AddPage( 0 ); + AddBackground( 0, 0, 300, 60 + 18 + 20 + (part.Players.Count * 18) + 20 + 20 + 160, 9380 ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 1 ) ); + AddHtml( 25, 35, 250, 20, Center( "Participants" ), false, false ); + + int y = 53; + + AddHtml( 25, y, 200, 20, part.Players.Count == 1 ? "Players" : "Team", false, false ); + y += 20; + + for ( int i = 0; i < part.Players.Count; ++i ) + { + Mobile mob = (Mobile)part.Players[i]; + string name = mob.Name; + + if ( m_Tournament.TournyType != TournyType.Standard ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm != null && pm.DuelPlayer != null ) + name = Color( name, pm.DuelPlayer.Eliminated ? 0x6633333 : 0x336666 ); + } + + AddRightArrow( 35, y, ToButtonID( 4, i ), name ); + y += 18; + } + + AddHtml( 25, y, 200, 20, String.Format( "Free Advances: {0}", part.FreeAdvances == 0 ? "None" : part.FreeAdvances.ToString() ), false, false ); + y += 20; + + AddHtml( 25, y, 200, 20, "Log:", false, false ); + y += 20; + + StringBuilder sb = new StringBuilder(); + + for ( int i = 0; i < part.Log.Count; ++i ) + { + if ( sb.Length > 0 ) + sb.Append( "
" ); + + sb.Append( part.Log[i] ); + } + + if ( sb.Length == 0 ) + sb.Append( "Nothing logged yet." ); + + AddHtml( 25, y, 250, 150, Color( sb.ToString(), BlackColor32 ), false, true ); + + break; + } + case TournyBracketGumpType.Player_Info: + { + AddPage( 0 ); + AddBackground( 0, 0, 300, 300, 9380 ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 3 ) ); + AddHtml( 25, 35, 250, 20, Center( "Participants" ), false, false ); + + Mobile mob = obj as Mobile; + + if ( mob == null ) + break; + + Ladder ladder = Ladder.Instance; + LadderEntry entry = ( ladder == null ? null : ladder.Find( mob ) ); + + AddHtml( 25, 53, 250, 20, String.Format( "Name: {0}", mob.Name ), false, false ); + AddHtml( 25, 73, 250, 20, String.Format( "Guild: {0}", mob.Guild == null ? "None" : mob.Guild.Name + " [" + mob.Guild.Abbreviation + "]" ), false, false ); + AddHtml( 25, 93, 250, 20, String.Format( "Rank: {0}", entry == null ? "N/A" : LadderGump.Rank( entry.Index + 1 ) ), false, false ); + AddHtml( 25, 113, 250, 20, String.Format( "Level: {0}", entry == null ? 0 : Ladder.GetLevel( entry.Experience ) ), false, false ); + AddHtml( 25, 133, 250, 20, String.Format( "Wins: {0:N0}", entry == null ? 0 : entry.Wins ), false, false ); + AddHtml( 25, 153, 250, 20, String.Format( "Losses: {0:N0}", entry == null ? 0 : entry.Losses ), false, false ); + + break; + } + case TournyBracketGumpType.Round_List: + { + AddPage( 0 ); + AddBackground( 0, 0, 300, 300, 9380 ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 0 ) ); + AddHtml( 25, 35, 250, 20, Center( "Rounds" ), false, false ); + + if ( m_List == null ) + m_List = new ArrayList( tourny.Pyramid.Levels ); + + int index, count, y; + StartPage( out index, out count, out y, 12 ); + + for ( int i = 0; i < count; ++i, y += 18 ) + { + PyramidLevel level = (PyramidLevel)m_List[index + i]; + + AddRightArrow( 25, y, ToButtonID( 3, index + i ), "Round #" + (index + i + 1) ); + } + + break; + } + case TournyBracketGumpType.Round_Info: + { + AddPage( 0 ); + AddBackground( 0, 0, 300, 300, 9380 ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 2 ) ); + AddHtml( 25, 35, 250, 20, Center( "Rounds" ), false, false ); + + PyramidLevel level = m_Object as PyramidLevel; + + if ( level == null ) + break; + + if ( m_List == null ) + m_List = new ArrayList( level.Matches ); + + AddRightArrow( 25, 53, ToButtonID( 5, 0 ), String.Format( "Free Advance: {0}", level.FreeAdvance == null ? "None" : level.FreeAdvance.NameList ) ); + + AddHtml( 25, 73, 200, 20, String.Format( "{0} Match{1}", m_List.Count, m_List.Count == 1 ? "" : "es" ), false, false ); + + int index, count, y; + StartPage( out index, out count, out y, 10 ); + + for ( int i = 0; i < count; ++i, y += 18 ) + { + TournyMatch match = (TournyMatch)m_List[index + i]; + + int color = -1; + + if ( match.InProgress ) + color = 0x336666; + else if ( match.Context != null && match.Winner == null ) + color = 0x666666; + + StringBuilder sb = new StringBuilder(); + + if ( m_Tournament.TournyType == TournyType.Standard ) + { + for ( int j = 0; j < match.Participants.Count; ++j ) + { + if ( sb.Length > 0 ) + sb.Append( " vs " ); + + TournyParticipant part = (TournyParticipant)match.Participants[j]; + string txt = part.NameList; + + if ( color == -1 && match.Context != null && match.Winner == part ) + txt = Color( txt, 0x336633 ); + else if ( color == -1 && match.Context != null ) + txt = Color( txt, 0x663333 ); + + sb.Append( txt ); + } + } + else if ( m_Tournament.EventController != null || m_Tournament.TournyType == TournyType.RandomTeam || m_Tournament.TournyType == TournyType.RedVsBlue ) + { + for ( int j = 0; j < match.Participants.Count; ++j ) + { + if ( sb.Length > 0 ) + sb.Append( " vs " ); + + TournyParticipant part = (TournyParticipant)match.Participants[j]; + string txt; + + if ( m_Tournament.EventController != null ) + txt = String.Format( "Team {0} ({1})", m_Tournament.EventController.GetTeamName( j ), part.Players.Count ); + else if ( m_Tournament.TournyType == TournyType.RandomTeam ) + txt = String.Format( "Team {0} ({1})", j + 1, part.Players.Count ); + else + txt = String.Format( "Team {0} ({1})", j == 0 ? "Red" : "Blue", part.Players.Count ); + + if ( color == -1 && match.Context != null && match.Winner == part ) + txt = Color( txt, 0x336633 ); + else if ( color == -1 && match.Context != null ) + txt = Color( txt, 0x663333 ); + + sb.Append( txt ); + } + } + else if ( m_Tournament.TournyType == TournyType.FreeForAll ) + { + sb.Append( "Free For All" ); + } + + string str = sb.ToString(); + + if ( color >= 0 ) + str = Color( str, color ); + + AddRightArrow( 25, y, ToButtonID( 5, index + i + 1 ), str ); + } + + break; + } + case TournyBracketGumpType.Match_Info: + { + TournyMatch match = obj as TournyMatch; + + if ( match == null ) + break; + + int ct = ( m_Tournament.TournyType == TournyType.FreeForAll ? 2 : match.Participants.Count ); + + AddPage( 0 ); + AddBackground( 0, 0, 300, 60 + 18 + 20 + 20 + 20 + (ct*18) + 6, 9380 ); + + AddLeftArrow( 25, 11, ToButtonID( 0, 5 ) ); + AddHtml( 25, 35, 250, 20, Center( "Rounds" ), false, false ); + + AddHtml( 25, 53, 250, 20, String.Format( "Winner: {0}", match.Winner == null ? "N/A" : match.Winner.NameList ), false, false ); + AddHtml( 25, 73, 250, 20, String.Format( "State: {0}", match.InProgress ? "In progress" : match.Context != null ? "Complete" : "Waiting" ), false, false ); + AddHtml( 25, 93, 250, 20, String.Format( "Participants:" ), false, false ); + + if ( m_Tournament.TournyType == TournyType.Standard ) + { + for ( int i = 0; i < match.Participants.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)match.Participants[i]; + + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), part.NameList ); + } + } + else if ( m_Tournament.EventController != null || m_Tournament.TournyType == TournyType.RandomTeam || m_Tournament.TournyType == TournyType.RedVsBlue ) + { + for ( int i = 0; i < match.Participants.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)match.Participants[i]; + + if ( m_Tournament.EventController != null ) + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", m_Tournament.EventController.GetTeamName( i ), part.Players.Count ) ); + else if ( m_Tournament.TournyType == TournyType.RandomTeam ) + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", i+1, part.Players.Count ) ); + else + AddRightArrow( 25, 113 + (i * 18), ToButtonID( 6, i ), String.Format( "Team {0} ({1})", i==0?"Red":"Blue", part.Players.Count ) ); + } + } + else if ( m_Tournament.TournyType == TournyType.FreeForAll ) + { + AddHtml( 25, 113, 250, 20, "Free For All", false, false ); + } + + break; + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int type, index; + + if ( !FromButtonID( info.ButtonID, out type, out index ) ) + return; + + switch ( type ) + { + case 0: + { + switch ( index ) + { + case 0: m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Index, null, 0, null ) ); break; + case 1: m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Participant_List, null, 0, null ) ); break; + case 2: m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Round_List, null, 0, null ) ); break; + case 4: m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Rules_Info, null, 0, null ) ); break; + case 3: + { + Mobile mob = m_Object as Mobile; + + for ( int i = 0; i < m_Tournament.Participants.Count; ++i ) + { + TournyParticipant part = (TournyParticipant)m_Tournament.Participants[i]; + + if ( part.Players.Contains( mob ) ) + { + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Participant_Info, null, 0, part ) ); + break; + } + } + + break; + } + case 5: + { + TournyMatch match = m_Object as TournyMatch; + + if ( match == null ) + break; + + for ( int i = 0; i < m_Tournament.Pyramid.Levels.Count; ++i ) + { + PyramidLevel level = (PyramidLevel)m_Tournament.Pyramid.Levels[i]; + + if ( level.Matches.Contains( match ) ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Round_Info, null, 0, level ) ); + } + + break; + } + } + + break; + } + case 1: + { + switch ( index ) + { + case 0: + { + if ( m_List != null && m_Page > 0 ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, m_Type, m_List, m_Page - 1, m_Object ) ); + + break; + } + case 1: + { + if ( m_List != null && ((m_Page + 1) * m_PerPage) < m_List.Count ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, m_Type, m_List, m_Page + 1, m_Object ) ); + + break; + } + } + + break; + } + case 2: + { + if ( m_Type != TournyBracketGumpType.Participant_List ) + break; + + if ( index >= 0 && index < m_List.Count ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Participant_Info, null, 0, m_List[index] ) ); + + break; + } + case 3: + { + if ( m_Type != TournyBracketGumpType.Round_List ) + break; + + if ( index >= 0 && index < m_List.Count ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Round_Info, null, 0, m_List[index] ) ); + + break; + } + case 4: + { + if ( m_Type != TournyBracketGumpType.Participant_Info ) + break; + + TournyParticipant part = m_Object as TournyParticipant; + + if ( part != null && index >= 0 && index < part.Players.Count ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Player_Info, null, 0, part.Players[index] ) ); + + break; + } + case 5: + { + if ( m_Type != TournyBracketGumpType.Round_Info ) + break; + + PyramidLevel level = m_Object as PyramidLevel; + + if ( level == null ) + break; + + if ( index == 0 ) + { + if ( level.FreeAdvance != null ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Participant_Info, null, 0, level.FreeAdvance ) ); + else + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, m_Type, m_List, m_Page, m_Object ) ); + } + else if ( index >= 1 && index <= level.Matches.Count ) + { + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Match_Info, null, 0, level.Matches[index-1] ) ); + } + + break; + } + case 6: + { + if ( m_Type != TournyBracketGumpType.Match_Info ) + break; + + TournyMatch match = m_Object as TournyMatch; + + if ( match != null && index >= 0 && index < match.Participants.Count ) + m_From.SendGump( new TournamentBracketGump( m_From, m_Tournament, TournyBracketGumpType.Participant_Info, null, 0, match.Participants[index] ) ); + + break; + } + } + } + } + + public class TournamentBracketItem : Item + { + private TournamentController m_Tournament; + + [CommandProperty( AccessLevel.GameMaster )] + public TournamentController Tournament{ get{ return m_Tournament; } set{ m_Tournament = value; } } + + public override string DefaultName + { + get { return "tournament bracket"; } + } + + [Constructable] + public TournamentBracketItem() : base( 3774 ) + { + Movable = false; + } + + public override void OnDoubleClick(Mobile from) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that + } + else if ( m_Tournament != null ) + { + Tournament tourny = m_Tournament.Tournament; + + if ( tourny != null ) + { + from.CloseGump( typeof( TournamentBracketGump ) ); + from.SendGump( new TournamentBracketGump( from, tourny, TournyBracketGumpType.Index, null, 0, null ) ); + + /*if ( tourny.Stage == TournamentStage.Fighting && tourny.Pyramid.Levels.Count > 0 ) + from.SendGump( new TournamentBracketGump( tourny, (PyramidLevel)tourny.Pyramid.Levels[tourny.Pyramid.Levels.Count - 1] ) ); + else + from.SendGump( new TournamentBracketGump( tourny, 0 ) );*/ + } + } + } + + public TournamentBracketItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (Item) m_Tournament ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Tournament = reader.ReadItem() as TournamentController; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/ConPVP/Trophy.cs b/Scripts/Engines/ConPVP/Trophy.cs new file mode 100644 index 0000000..8860e6d --- /dev/null +++ b/Scripts/Engines/ConPVP/Trophy.cs @@ -0,0 +1,111 @@ +using System; +using System.Text; +using Server; +using Server.Items; + +namespace Server.Items +{ + public enum TrophyRank + { + Bronze, + Silver, + Gold + } + + [Flipable( 5020, 4647 )] + public class Trophy : Item + { + private string m_Title; + private TrophyRank m_Rank; + private Mobile m_Owner; + private DateTime m_Date; + + [CommandProperty( AccessLevel.GameMaster )] + public string Title{ get{ return m_Title; } set{ m_Title = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TrophyRank Rank{ get{ return m_Rank; } set{ m_Rank = value; UpdateStyle(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner{ get{ return m_Owner; } set{ m_Owner = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime Date{ get{ return m_Date; } } + + [Constructable] + public Trophy( string title, TrophyRank rank ) : base( 5020 ) + { + m_Title = title; + m_Rank = rank; + m_Date = DateTime.Now; + + LootType = LootType.Blessed; + + UpdateStyle(); + } + + public Trophy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (string) m_Title ); + writer.Write( (int) m_Rank ); + writer.Write( (Mobile) m_Owner ); + writer.Write( (DateTime) m_Date ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Title = reader.ReadString(); + m_Rank = (TrophyRank) reader.ReadInt(); + m_Owner = reader.ReadMobile(); + m_Date = reader.ReadDateTime(); + + if ( version == 0 ) + LootType = LootType.Blessed; + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( m_Owner == null ) + m_Owner = this.RootParent as Mobile; + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( m_Owner != null ) + LabelTo( from, "{0} -- {1}", m_Title, m_Owner.RawName ); + else if ( m_Title != null ) + LabelTo( from, m_Title ); + + if ( m_Date != DateTime.MinValue ) + LabelTo( from, m_Date.ToString( "d" ) ); + } + + public void UpdateStyle() + { + Name = String.Format( "{0} trophy", m_Rank.ToString().ToLower() ); + + switch ( m_Rank ) + { + case TrophyRank.Gold: Hue = 2213; break; + case TrophyRank.Silver: Hue = 0; break; + case TrophyRank.Bronze: Hue = 2206; break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftContext.cs b/Scripts/Engines/Craft/Core/CraftContext.cs new file mode 100644 index 0000000..df0d8c4 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftContext.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Engines.Craft +{ + public enum CraftMarkOption + { + MarkItem, + DoNotMark, + PromptForMark + } + + public class CraftContext + { + private List m_Items; + private int m_LastResourceIndex; + private int m_LastResourceIndex2; + private int m_LastGroupIndex; + private bool m_DoNotColor; + private CraftMarkOption m_MarkOption; + + public List Items { get { return m_Items; } } + public int LastResourceIndex{ get{ return m_LastResourceIndex; } set{ m_LastResourceIndex = value; } } + public int LastResourceIndex2{ get{ return m_LastResourceIndex2; } set{ m_LastResourceIndex2 = value; } } + public int LastGroupIndex{ get{ return m_LastGroupIndex; } set{ m_LastGroupIndex = value; } } + public bool DoNotColor{ get{ return m_DoNotColor; } set{ m_DoNotColor = value; } } + public CraftMarkOption MarkOption{ get{ return m_MarkOption; } set{ m_MarkOption = value; } } + + public CraftContext() + { + m_Items = new List(); + m_LastResourceIndex = -1; + m_LastResourceIndex2 = -1; + m_LastGroupIndex = -1; + } + + public CraftItem LastMade + { + get + { + if ( m_Items.Count > 0 ) + return m_Items[0]; + + return null; + } + } + + public void OnMade( CraftItem item ) + { + m_Items.Remove( item ); + + if ( m_Items.Count == 10 ) + m_Items.RemoveAt( 9 ); + + m_Items.Insert( 0, item ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftGroup.cs b/Scripts/Engines/Craft/Core/CraftGroup.cs new file mode 100644 index 0000000..d0c5bd2 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftGroup.cs @@ -0,0 +1,39 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftGroup + { + private CraftItemCol m_arCraftItem; + + private string m_NameString; + private int m_NameNumber; + + public CraftGroup( TextDefinition groupName ) + { + m_NameNumber = groupName; + m_NameString = groupName; + m_arCraftItem = new CraftItemCol(); + } + + public void AddCraftItem( CraftItem craftItem ) + { + m_arCraftItem.Add( craftItem ); + } + + public CraftItemCol CraftItems + { + get { return m_arCraftItem; } + } + + public string NameString + { + get { return m_NameString; } + } + + public int NameNumber + { + get { return m_NameNumber; } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftGroupCol.cs b/Scripts/Engines/Craft/Core/CraftGroupCol.cs new file mode 100644 index 0000000..045d1ad --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftGroupCol.cs @@ -0,0 +1,48 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftGroupCol : System.Collections.CollectionBase + { + public CraftGroupCol() + { + } + + public int Add( CraftGroup craftGroup ) + { + return List.Add( craftGroup ); + } + + public void Remove( int index ) + { + if ( index > Count - 1 || index < 0 ) + { + } + else + { + List.RemoveAt( index ); + } + } + + public CraftGroup GetAt( int index ) + { + return ( CraftGroup ) List[index]; + } + + public int SearchFor( TextDefinition groupName ) + { + for ( int i = 0; i < List.Count; i++ ) + { + CraftGroup craftGroup = (CraftGroup)List[i]; + + int nameNumber = craftGroup.NameNumber; + string nameString = craftGroup.NameString; + + if ( ( nameNumber != 0 && nameNumber == groupName.Number ) || ( nameString != null && nameString == groupName.String ) ) + return i; + } + + return -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftGump.cs b/Scripts/Engines/Craft/Core/CraftGump.cs new file mode 100644 index 0000000..31d9637 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftGump.cs @@ -0,0 +1,641 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Gumps; +using Server.Network; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class CraftGump : Gump + { + private Mobile m_From; + private CraftSystem m_CraftSystem; + private BaseTool m_Tool; + + private CraftPage m_Page; + + private const int LabelHue = 0x480; + private const int LabelColor = 0x7FFF; + private const int FontColor = 0xFFFFFF; + + private enum CraftPage + { + None, + PickResource, + PickResource2 + } + + /*public CraftGump( Mobile from, CraftSystem craftSystem, BaseTool tool ): this( from, craftSystem, -1, -1, tool, null ) + { + }*/ + + public CraftGump( Mobile from, CraftSystem craftSystem, BaseTool tool, object notice ) : this( from, craftSystem, tool, notice, CraftPage.None ) + { + } + + private CraftGump( Mobile from, CraftSystem craftSystem, BaseTool tool, object notice, CraftPage page ) : base( 40, 40 ) + { + m_From = from; + m_CraftSystem = craftSystem; + m_Tool = tool; + m_Page = page; + + CraftContext context = craftSystem.GetContext( from ); + + from.CloseGump( typeof( CraftGump ) ); + from.CloseGump( typeof( CraftGumpItem ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 530, 437, 5054 ); + AddImageTiled( 10, 10, 510, 22, 2624 ); + AddImageTiled( 10, 292, 150, 45, 2624 ); + AddImageTiled( 165, 292, 355, 45, 2624 ); + AddImageTiled( 10, 342, 510, 85, 2624 ); + AddImageTiled( 10, 37, 200, 250, 2624 ); + AddImageTiled( 215, 37, 305, 250, 2624 ); + AddAlphaRegion( 10, 10, 510, 417 ); + + if ( craftSystem.GumpTitleNumber > 0 ) + AddHtmlLocalized( 10, 12, 510, 20, craftSystem.GumpTitleNumber, LabelColor, false, false ); + else + AddHtml( 10, 12, 510, 20, craftSystem.GumpTitleString, false, false ); + + AddHtmlLocalized( 10, 37, 200, 22, 1044010, LabelColor, false, false ); //
CATEGORIES
+ AddHtmlLocalized( 215, 37, 305, 22, 1044011, LabelColor, false, false ); //
SELECTIONS
+ AddHtmlLocalized( 10, 302, 150, 25, 1044012, LabelColor, false, false ); //
NOTICES
+ + AddButton( 15, 402, 4017, 4019, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 405, 150, 18, 1011441, LabelColor, false, false ); // EXIT + + AddButton( 270, 402, 4005, 4007, GetButtonID( 6, 2 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 305, 405, 150, 18, 1044013, LabelColor, false, false ); // MAKE LAST + + // Mark option + if ( craftSystem.MarkOption ) + { + AddButton( 270, 362, 4005, 4007, GetButtonID( 6, 6 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 305, 365, 150, 18, 1044017 + (context == null ? 0 : (int)context.MarkOption), LabelColor, false, false ); // MARK ITEM + } + // **************************************** + + // Resmelt option + if ( craftSystem.Resmelt ) + { + AddButton( 15, 342, 4005, 4007, GetButtonID( 6, 1 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 345, 150, 18, 1044259, LabelColor, false, false ); // SMELT ITEM + } + // **************************************** + + // Repair option + if ( craftSystem.Repair ) + { + AddButton( 270, 342, 4005, 4007, GetButtonID( 6, 5 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 305, 345, 150, 18, 1044260, LabelColor, false, false ); // REPAIR ITEM + } + // **************************************** + + // Enhance option + if ( craftSystem.CanEnhance ) + { + AddButton( 270, 382, 4005, 4007, GetButtonID( 6, 8 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 305, 385, 150, 18, 1061001, LabelColor, false, false ); // ENHANCE ITEM + } + // **************************************** + + if ( notice is int && (int)notice > 0 ) + AddHtmlLocalized( 170, 295, 350, 40, (int)notice, LabelColor, false, false ); + else if ( notice is string ) + AddHtml( 170, 295, 350, 40, String.Format( "{1}", FontColor, notice ), false, false ); + + // If the system has more than one resource + if ( craftSystem.CraftSubRes.Init ) + { + string nameString = craftSystem.CraftSubRes.NameString; + int nameNumber = craftSystem.CraftSubRes.NameNumber; + + int resIndex = ( context == null ? -1 : context.LastResourceIndex ); + + Type resourceType = craftSystem.CraftSubRes.ResType; + + if ( resIndex > -1 ) + { + CraftSubRes subResource = craftSystem.CraftSubRes.GetAt( resIndex ); + + nameString = subResource.NameString; + nameNumber = subResource.NameNumber; + resourceType = subResource.ItemType; + } + + int resourceCount = 0; + + if ( from.Backpack != null ) + { + Item[] items = from.Backpack.FindItemsByType( resourceType, true ); + + for ( int i = 0; i < items.Length; ++i ) + resourceCount += items[i].Amount; + } + + AddButton( 15, 362, 4005, 4007, GetButtonID( 6, 0 ), GumpButtonType.Reply, 0 ); + + if ( nameNumber > 0 ) + AddHtmlLocalized( 50, 365, 250, 18, nameNumber, resourceCount.ToString(), LabelColor, false, false ); + else + AddLabel( 50, 362, LabelHue, String.Format( "{0} ({1} Available)", nameString, resourceCount ) ); + } + // **************************************** + + // For dragon scales + if ( craftSystem.CraftSubRes2.Init ) + { + string nameString = craftSystem.CraftSubRes2.NameString; + int nameNumber = craftSystem.CraftSubRes2.NameNumber; + + int resIndex = ( context == null ? -1 : context.LastResourceIndex2 ); + + Type resourceType = craftSystem.CraftSubRes2.ResType; + + if ( resIndex > -1 ) + { + CraftSubRes subResource = craftSystem.CraftSubRes2.GetAt( resIndex ); + + nameString = subResource.NameString; + nameNumber = subResource.NameNumber; + resourceType = subResource.ItemType; + } + + int resourceCount = 0; + + if ( from.Backpack != null ) + { + Item[] items = from.Backpack.FindItemsByType( resourceType, true ); + + for ( int i = 0; i < items.Length; ++i ) + resourceCount += items[i].Amount; + } + + AddButton( 15, 382, 4005, 4007, GetButtonID( 6, 7 ), GumpButtonType.Reply, 0 ); + + if ( nameNumber > 0 ) + AddHtmlLocalized( 50, 385, 250, 18, nameNumber, resourceCount.ToString(), LabelColor, false, false ); + else + AddLabel( 50, 385, LabelHue, String.Format( "{0} ({1} Available)", nameString, resourceCount ) ); + } + // **************************************** + + CreateGroupList(); + + if ( page == CraftPage.PickResource ) + CreateResList( false, from ); + else if ( page == CraftPage.PickResource2 ) + CreateResList( true, from ); + else if ( context != null && context.LastGroupIndex > -1 ) + CreateItemList( context.LastGroupIndex ); + } + + public void CreateResList( bool opt, Mobile from ) + { + CraftSubResCol res = ( opt ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes ); + + for ( int i = 0; i < res.Count; ++i ) + { + int index = i % 10; + + CraftSubRes subResource = res.GetAt( i ); + + if ( index == 0 ) + { + if ( i > 0 ) + AddButton( 485, 260, 4005, 4007, 0, GumpButtonType.Page, (i / 10) + 1 ); + + AddPage( (i / 10) + 1 ); + + if ( i > 0 ) + AddButton( 455, 260, 4014, 4015, 0, GumpButtonType.Page, i / 10 ); + + CraftContext context = m_CraftSystem.GetContext( m_From ); + + AddButton( 220, 260, 4005, 4007, GetButtonID( 6, 4 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 255, 263, 200, 18, (context == null || !context.DoNotColor) ? 1061591 : 1061590, LabelColor, false, false ); + } + + int resourceCount = 0; + + if ( from.Backpack != null ) + { + Item[] items = from.Backpack.FindItemsByType( subResource.ItemType, true ); + + for ( int j = 0; j < items.Length; ++j ) + resourceCount += items[j].Amount; + } + + AddButton( 220, 60 + (index * 20), 4005, 4007, GetButtonID( 5, i ), GumpButtonType.Reply, 0 ); + + if ( subResource.NameNumber > 0 ) + AddHtmlLocalized( 255, 63 + (index * 20), 250, 18, subResource.NameNumber, resourceCount.ToString(), LabelColor, false, false ); + else + AddLabel( 255, 60 + ( index * 20 ), LabelHue, String.Format( "{0} ({1})", subResource.NameString, resourceCount ) ); + } + } + + public void CreateMakeLastList() + { + CraftContext context = m_CraftSystem.GetContext( m_From ); + + if ( context == null ) + return; + + List items = context.Items; + + if ( items.Count > 0 ) + { + for ( int i = 0; i < items.Count; ++i ) + { + int index = i % 10; + + CraftItem craftItem = items[i]; + + if ( index == 0 ) + { + if ( i > 0 ) + { + AddButton( 370, 260, 4005, 4007, 0, GumpButtonType.Page, (i / 10) + 1 ); + AddHtmlLocalized( 405, 263, 100, 18, 1044045, LabelColor, false, false ); // NEXT PAGE + } + + AddPage( (i / 10) + 1 ); + + if ( i > 0 ) + { + AddButton( 220, 260, 4014, 4015, 0, GumpButtonType.Page, i / 10 ); + AddHtmlLocalized( 255, 263, 100, 18, 1044044, LabelColor, false, false ); // PREV PAGE + } + } + + AddButton( 220, 60 + (index * 20), 4005, 4007, GetButtonID( 3, i ), GumpButtonType.Reply, 0 ); + + if ( craftItem.NameNumber > 0 ) + AddHtmlLocalized( 255, 63 + (index * 20), 220, 18, craftItem.NameNumber, LabelColor, false, false ); + else + AddLabel( 255, 60 + (index * 20), LabelHue, craftItem.NameString ); + + AddButton( 480, 60 + (index * 20), 4011, 4012, GetButtonID( 4, i ), GumpButtonType.Reply, 0 ); + } + } + else + { + // NOTE: This is not as OSI; it is an intentional difference + + AddHtmlLocalized( 230, 62, 200, 22, 1044165, LabelColor, false, false ); // You haven't made anything yet. + } + } + + public void CreateItemList( int selectedGroup ) + { + if ( selectedGroup == 501 ) // 501 : Last 10 + { + CreateMakeLastList(); + return; + } + + CraftGroupCol craftGroupCol = m_CraftSystem.CraftGroups; + CraftGroup craftGroup = craftGroupCol.GetAt( selectedGroup ); + CraftItemCol craftItemCol = craftGroup.CraftItems; + + for ( int i = 0; i < craftItemCol.Count; ++i ) + { + + CraftItem craftItem = craftItemCol.GetAt( i ); + + + int index = i % 10; + + + if ( index == 0 ) + { + if ( i > 0 ) + { + AddButton( 370, 260, 4005, 4007, 0, GumpButtonType.Page, (i / 10) + 1 ); + AddHtmlLocalized( 405, 263, 100, 18, 1044045, LabelColor, false, false ); // NEXT PAGE + } + + AddPage( (i / 10) + 1 ); + + if ( i > 0 ) + { + AddButton( 220, 260, 4014, 4015, 0, GumpButtonType.Page, i / 10 ); + AddHtmlLocalized( 255, 263, 100, 18, 1044044, LabelColor, false, false ); // PREV PAGE + } + } + + + + if ( craftItem.NameNumber > 0 ) + AddHtmlLocalized( 255, 63 + (index * 20), 220, 18, craftItem.NameNumber, LabelColor, false, false ); + else + AddLabel( 255, 60 + (index * 20), LabelHue, craftItem.NameString ); + + // Plume : Section � d�commenter si l'on souhaite que seul les items que le joueur peut crafter avec ses skills soient affich�s + bool CantDisplay = false; + + for (int t = 0; t < craftItem.Skills.Count; t++) + { + CraftSkill skill = craftItem.Skills.GetAt(t); + + if (skill.MinSkill > m_From.Skills[skill.SkillToMake].Value) + { + CantDisplay = true; + break; + } + + } + + if (CantDisplay) + continue; + + AddButton(220, 60 + (index * 20), 4005, 4007, GetButtonID(1, i), GumpButtonType.Reply, 0); // Quick Create + AddButton( 480, 60 + (index * 20), 4011, 4012, GetButtonID( 2, i ), GumpButtonType.Reply, 0 ); //Details + } + } + + public int CreateGroupList() + { + CraftGroupCol craftGroupCol = m_CraftSystem.CraftGroups; + + AddButton( 15, 60, 4005, 4007, GetButtonID( 6, 3 ), GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 63, 150, 18, 1044014, LabelColor, false, false ); // LAST TEN + + for ( int i = 0; i < craftGroupCol.Count; i++ ) + { + CraftGroup craftGroup = craftGroupCol.GetAt( i ); + + AddButton( 15, 80 + (i * 20), 4005, 4007, GetButtonID( 0, i ), GumpButtonType.Reply, 0 ); + + if ( craftGroup.NameNumber > 0 ) + AddHtmlLocalized( 50, 83 + (i * 20), 150, 18, craftGroup.NameNumber, LabelColor, false, false ); + else + AddLabel( 50, 80 + (i * 20), LabelHue, craftGroup.NameString ); + } + + return craftGroupCol.Count; + } + + public static int GetButtonID( int type, int index ) + { + return 1 + type + (index * 7); + } + + public void CraftItem( CraftItem item ) + { + int num = m_CraftSystem.CanCraft( m_From, m_Tool, item.ItemType ); + + if ( num > 0 ) + { + m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, num ) ); + } + else + { + Type type = null; + + CraftContext context = m_CraftSystem.GetContext( m_From ); + + if ( context != null ) + { + CraftSubResCol res = ( item.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes ); + int resIndex = ( item.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex ); + + if ( resIndex >= 0 && resIndex < res.Count ) + type = res.GetAt( resIndex ).ItemType; + } + + m_CraftSystem.CreateItem( m_From, item.ItemType, type, m_Tool, item ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID <= 0 ) + return; // Canceled + + int buttonID = info.ButtonID - 1; + int type = buttonID % 7; + int index = buttonID / 7; + + CraftSystem system = m_CraftSystem; + CraftGroupCol groups = system.CraftGroups; + CraftContext context = system.GetContext( m_From ); + + switch ( type ) + { + case 0: // Show group + { + if ( context == null ) + break; + + if ( index >= 0 && index < groups.Count ) + { + context.LastGroupIndex = index; + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null ) ); + } + + break; + } + case 1: // Create item + { + if ( context == null ) + break; + + int groupIndex = context.LastGroupIndex; + + if ( groupIndex >= 0 && groupIndex < groups.Count ) + { + CraftGroup group = groups.GetAt( groupIndex ); + + if ( index >= 0 && index < group.CraftItems.Count ) + CraftItem( group.CraftItems.GetAt( index ) ); + } + + break; + } + case 2: // Item details + { + if ( context == null ) + break; + + int groupIndex = context.LastGroupIndex; + + if ( groupIndex >= 0 && groupIndex < groups.Count ) + { + CraftGroup group = groups.GetAt( groupIndex ); + + if ( index >= 0 && index < group.CraftItems.Count ) + m_From.SendGump( new CraftGumpItem( m_From, system, group.CraftItems.GetAt( index ), m_Tool ) ); + } + + break; + } + case 3: // Create item (last 10) + { + if ( context == null ) + break; + + List lastTen = context.Items; + + if ( index >= 0 && index < lastTen.Count ) + CraftItem( lastTen[index] ); + + break; + } + case 4: // Item details (last 10) + { + if ( context == null ) + break; + + List lastTen = context.Items; + + if ( index >= 0 && index < lastTen.Count ) + m_From.SendGump( new CraftGumpItem( m_From, system, lastTen[index], m_Tool ) ); + + break; + } + case 5: // Resource selected + { + if ( m_Page == CraftPage.PickResource && index >= 0 && index < system.CraftSubRes.Count ) + { + int groupIndex = ( context == null ? -1 : context.LastGroupIndex ); + + CraftSubRes res = system.CraftSubRes.GetAt( index ); + + if ( m_From.Skills[system.MainSkill].Base < res.RequiredSkill ) + { + m_From.SendGump( new CraftGump( m_From, system, m_Tool, res.Message ) ); + } + else + { + if ( context != null ) + context.LastResourceIndex = index; + + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null ) ); + } + } + else if ( m_Page == CraftPage.PickResource2 && index >= 0 && index < system.CraftSubRes2.Count ) + { + int groupIndex = ( context == null ? -1 : context.LastGroupIndex ); + + CraftSubRes res = system.CraftSubRes2.GetAt( index ); + + if ( m_From.Skills[system.MainSkill].Base < res.RequiredSkill ) + { + m_From.SendGump( new CraftGump( m_From, system, m_Tool, res.Message ) ); + } + else + { + if ( context != null ) + context.LastResourceIndex2 = index; + + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null ) ); + } + } + + break; + } + case 6: // Misc. buttons + { + switch ( index ) + { + case 0: // Resource selection + { + if ( system.CraftSubRes.Init ) + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null, CraftPage.PickResource ) ); + + break; + } + case 1: // Smelt item + { + if ( system.Resmelt ) + Resmelt.Do( m_From, system, m_Tool ); + + break; + } + case 2: // Make last + { + if ( context == null ) + break; + + CraftItem item = context.LastMade; + + if ( item != null ) + CraftItem( item ); + else + m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, 1044165, m_Page ) ); // You haven't made anything yet. + + break; + } + case 3: // Last 10 + { + if ( context == null ) + break; + + context.LastGroupIndex = 501; + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null ) ); + + break; + } + case 4: // Toggle use resource hue + { + if ( context == null ) + break; + + context.DoNotColor = !context.DoNotColor; + + m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, null, m_Page ) ); + + break; + } + case 5: // Repair item + { + if ( system.Repair ) + Repair.Do( m_From, system, m_Tool ); + + break; + } + case 6: // Toggle mark option + { + if ( context == null || !system.MarkOption ) + break; + + switch ( context.MarkOption ) + { + case CraftMarkOption.MarkItem: context.MarkOption = CraftMarkOption.DoNotMark; break; + case CraftMarkOption.DoNotMark: context.MarkOption = CraftMarkOption.PromptForMark; break; + case CraftMarkOption.PromptForMark: context.MarkOption = CraftMarkOption.MarkItem; break; + } + + m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, null, m_Page ) ); + + break; + } + case 7: // Resource selection 2 + { + if ( system.CraftSubRes2.Init ) + m_From.SendGump( new CraftGump( m_From, system, m_Tool, null, CraftPage.PickResource2 ) ); + + break; + } + case 8: // Enhance item + { + if ( system.CanEnhance ) + Enhance.BeginTarget( m_From, system, m_Tool ); + + break; + } + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftGumpItem.cs b/Scripts/Engines/Craft/Core/CraftGumpItem.cs new file mode 100644 index 0000000..c8edc7a --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftGumpItem.cs @@ -0,0 +1,337 @@ +using System; +using Server.Gumps; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Craft +{ + public class CraftGumpItem : Gump + { + private Mobile m_From; + private CraftSystem m_CraftSystem; + private CraftItem m_CraftItem; + private BaseTool m_Tool; + + private const int LabelHue = 0x480; // 0x384 + private const int RedLabelHue = 0x20; + + private const int LabelColor = 0x7FFF; + private const int RedLabelColor = 0x6400; + + private const int GreyLabelColor = 0x3DEF; + + private int m_OtherCount; + + private double m_Chance = 0; // Scriptiz : on stocke la chance pour afficher les quantit�s si > 1 + + public CraftGumpItem( Mobile from, CraftSystem craftSystem, CraftItem craftItem, BaseTool tool ) : base( 40, 40 ) + { + m_From = from; + m_CraftSystem = craftSystem; + m_CraftItem = craftItem; + m_Tool = tool; + + from.CloseGump( typeof( CraftGump ) ); + from.CloseGump( typeof( CraftGumpItem ) ); + + AddPage( 0 ); + AddBackground( 0, 0, 530, 417, 5054 ); + AddImageTiled( 10, 10, 510, 22, 2624 ); + AddImageTiled( 10, 37, 150, 148, 2624 ); + AddImageTiled( 165, 37, 355, 90, 2624 ); + AddImageTiled( 10, 190, 155, 22, 2624 ); + AddImageTiled( 10, 217, 150, 53, 2624 ); + AddImageTiled( 165, 132, 355, 80, 2624 ); + AddImageTiled( 10, 275, 155, 22, 2624 ); + AddImageTiled( 10, 302, 150, 53, 2624 ); + AddImageTiled( 165, 217, 355, 80, 2624 ); + AddImageTiled( 10, 360, 155, 22, 2624 ); + AddImageTiled( 165, 302, 355, 80, 2624 ); + AddImageTiled( 10, 387, 510, 22, 2624 ); + AddAlphaRegion( 10, 10, 510, 399 ); + + AddHtmlLocalized( 170, 40, 150, 20, 1044053, LabelColor, false, false ); // ITEM + AddHtmlLocalized( 10, 192, 150, 22, 1044054, LabelColor, false, false ); //
SKILLS
+ AddHtmlLocalized( 10, 277, 150, 22, 1044055, LabelColor, false, false ); //
MATERIALS
+ AddHtmlLocalized( 10, 362, 150, 22, 1044056, LabelColor, false, false ); //
OTHER
+ + if ( craftSystem.GumpTitleNumber > 0 ) + AddHtmlLocalized( 10, 12, 510, 20, craftSystem.GumpTitleNumber, LabelColor, false, false ); + else + AddHtml( 10, 12, 510, 20, craftSystem.GumpTitleString, false, false ); + + AddButton( 15, 387, 4014, 4016, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 390, 150, 18, 1044150, LabelColor, false, false ); // BACK + + bool needsRecipe = ( craftItem.Recipe != null && from is PlayerMobile && !((PlayerMobile)from).HasRecipe( craftItem.Recipe ) ); + + if( needsRecipe ) + { + AddButton( 270, 387, 4005, 4007, 0, GumpButtonType.Page, 0 ); + AddHtmlLocalized( 305, 390, 150, 18, 1044151, GreyLabelColor, false, false ); // MAKE NOW + } + else + { + AddButton( 270, 387, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 305, 390, 150, 18, 1044151, LabelColor, false, false ); // MAKE NOW + } + + if ( craftItem.NameNumber > 0 ) + AddHtmlLocalized( 330, 40, 180, 18, craftItem.NameNumber, LabelColor, false, false ); + else + AddLabel( 330, 40, LabelHue, craftItem.NameString ); + + if ( craftItem.UseAllRes ) + AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 310, 18, 1048176, LabelColor, false, false ); // Makes as many as possible at once + + DrawItem(); + DrawSkill(); + DrawResource(); + + /* + if( craftItem.RequiresSE ) + AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 310, 18, 1063363, LabelColor, false, false ); //* Requires the "Samurai Empire" expansion + * */ + + if( craftItem.RequiredExpansion != Expansion.None ) + { + bool supportsEx = (from.NetState != null && from.NetState.SupportsExpansion( craftItem.RequiredExpansion )); + //TextDefinition.AddHtmlText( this, 170, 302 + (m_OtherCount++ * 20), 310, 18, RequiredExpansionMessage( craftItem.RequiredExpansion ), false, false, supportsEx ? LabelColor : RedLabelColor, supportsEx ? LabelHue : RedLabelHue ); + } + + //if( needsRecipe ) + //AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 310, 18, 1073620, RedLabelColor, false, false ); // You have not learned this recipe. + + } + + private TextDefinition RequiredExpansionMessage( Expansion expansion ) + { + switch( expansion ) + { + case Expansion.SE: + return 1063363; // * Requires the "Samurai Empire" expansion + case Expansion.ML: + return 1072651; // * Requires the "Mondain's Legacy" expansion + default: + return String.Format( "* Requires the \"{0}\" expansion", ExpansionInfo.GetInfo( expansion ).Name ); + } + } + + private bool m_ShowExceptionalChance; + + public void DrawItem() + { + Type type = m_CraftItem.ItemType; + + AddItem(20, 50, CraftItem.ItemIDOf(type), m_CraftItem.ItemHue); + + if ( m_CraftItem.IsMarkable( type ) ) + { + AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 310, 18, 1044059, LabelColor, false, false ); // This item may hold its maker's mark + m_ShowExceptionalChance = true; + } + } + + public void DrawSkill() + { + for ( int i = 0; i < m_CraftItem.Skills.Count; i++ ) + { + CraftSkill skill = m_CraftItem.Skills.GetAt( i ); + double minSkill = skill.MinSkill, maxSkill = skill.MaxSkill; + + if ( minSkill < 0 ) + minSkill = 0; + + string textminSkills = "D�butant"; + + if (minSkill >= 30 && minSkill < 40) + textminSkills = "N�ophite"; + else if (minSkill >= 40 && minSkill < 50) + textminSkills = "Novice"; + else if(minSkill >= 50 && minSkill < 60) + textminSkills = "Apprenti"; + else if(minSkill >= 60 && minSkill < 70) + textminSkills = "Compagnon"; + else if(minSkill >= 70 && minSkill < 80) + textminSkills = "Expert"; + else if(minSkill >= 80 && minSkill < 90) + textminSkills = "Adepte"; + else if(minSkill >= 90 && minSkill < 100) + textminSkills = "Ma�tre"; + else if (minSkill >= 100 && minSkill < 110) + textminSkills = "Grand Ma�tre"; + + AddHtmlLocalized(170, 132 + (i * 20), 200, 18, AosSkillBonuses.GetLabel(skill.SkillToMake), LabelColor, false, false); + + if (m_From.AccessLevel >= AccessLevel.GameMaster) + AddLabel( 430, 132 + (i * 20), LabelHue, String.Format( "{0:F1}", minSkill ) ); + else + AddLabel(430, 132 + (i * 20), LabelHue, String.Format("{0}", textminSkills)); + } + + CraftSubResCol res = ( m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes ); + int resIndex = -1; + + CraftContext context = m_CraftSystem.GetContext( m_From ); + + if ( context != null ) + resIndex = ( m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex ); + + bool allRequiredSkills = true; + double chance = m_CraftItem.GetSuccessChance( m_From, resIndex > -1 ? res.GetAt( resIndex ).ItemType : null, m_CraftSystem, false, ref allRequiredSkills ); + double excepChance = m_CraftItem.GetExceptionalChance( m_CraftSystem, chance, m_From ); + + m_Chance = chance; // Scriptiz : on stocke la chance + + if ( chance < 0.0 ) + chance = 0.0; + else if ( chance > 1.0 ) + chance = 1.0; + + string textchance = "Nulle"; + + if (chance > 0 && chance <= 0.2) + textchance = "Faible"; + else if (chance > 0.2 && chance <= 0.4) + textchance = "Possible"; + else if (chance > 0.4 && chance <= 0.6) + textchance = "Moyenne"; + else if (chance > 0.6 && chance <= 0.8) + textchance = "Favorable"; + else if (chance > 0.8 && chance < 1) + textchance = "Grande"; + else if (chance == 1) + textchance = "Ais�e"; + + AddHtmlLocalized( 170, 80, 250, 18, 1044057, LabelColor, false, false ); + + if(m_From.AccessLevel >= AccessLevel.GameMaster) + AddLabel( 430, 80, LabelHue, String.Format( "{0:F1}%", chance * 100 ) ); + else + AddLabel(430, 80, LabelHue, String.Format("{0}", textchance)); + + if ( m_ShowExceptionalChance ) + { + if( excepChance < 0.0 ) + excepChance = 0.0; + else if( excepChance > 1.0 ) + excepChance = 1.0; + if (m_From.AccessLevel >= AccessLevel.GameMaster) + { + AddHtmlLocalized( 170, 100, 250, 18, 1044058, 32767, false, false ); // Exceptional Chance: + AddLabel( 430, 100, LabelHue, String.Format( "{0:F1}%", excepChance * 100 ) ); + } + } + } + + private static Type typeofBlankScroll = typeof( BlankScroll ); + private static Type typeofSpellScroll = typeof( SpellScroll ); + + public void DrawResource() + { + bool retainedColor = false; + + CraftContext context = m_CraftSystem.GetContext( m_From ); + + CraftSubResCol res = ( m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes ); + int resIndex = -1; + + if ( context != null ) + resIndex = ( m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex ); + + bool cropScroll = ( m_CraftItem.Resources.Count > 1 ) + && m_CraftItem.Resources.GetAt( m_CraftItem.Resources.Count - 1 ).ItemType == typeofBlankScroll + && typeofSpellScroll.IsAssignableFrom( m_CraftItem.ItemType ); + + for ( int i = 0; i < m_CraftItem.Resources.Count - (cropScroll ? 1 : 0) && i < 4; i++ ) + { + Type type; + string nameString; + int nameNumber; + + CraftRes craftResource = m_CraftItem.Resources.GetAt( i ); + + type = craftResource.ItemType; + nameString = craftResource.NameString; + nameNumber = craftResource.NameNumber; + + // Resource Mutation + if ( type == res.ResType && resIndex > -1 ) + { + CraftSubRes subResource = res.GetAt( resIndex ); + + type = subResource.ItemType; + + nameString = subResource.NameString; + nameNumber = subResource.GenericNameNumber; + + if ( nameNumber <= 0 ) + nameNumber = subResource.NameNumber; + } + // ****************** + + if ( !retainedColor && m_CraftItem.RetainsColorFrom( m_CraftSystem, type ) ) + { + retainedColor = true; + AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 310, 18, 1044152, LabelColor, false, false ); // * The item retains the color of this material + AddLabel( 500, 219 + (i * 20), LabelHue, "*" ); + } + + if ( nameNumber > 0 ) + AddHtmlLocalized( 170, 219 + (i * 20), 310, 18, nameNumber, LabelColor, false, false ); + else + AddLabel( 170, 219 + (i * 20), LabelHue, nameString ); + + // Scriptiz : si GM ou 100% r�ussite, on affiche la quantit� requise + if (m_From.AccessLevel >= AccessLevel.GameMaster || m_Chance >= 1) + AddLabel( 430, 219 + (i * 20), LabelHue, craftResource.Amount.ToString() ); + } + + if ( m_CraftItem.NameNumber == 1041267 ) // runebook + { + AddHtmlLocalized( 170, 219 + (m_CraftItem.Resources.Count * 20), 310, 18, 1044447, LabelColor, false, false ); + AddLabel( 430, 219 + (m_CraftItem.Resources.Count * 20), LabelHue, "1" ); + } + + if ( cropScroll ) + AddHtmlLocalized( 170, 302 + (m_OtherCount++ * 20), 360, 18, 1044379, LabelColor, false, false ); // Inscribing scrolls also requires a blank scroll and mana. + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + // Back Button + if ( info.ButtonID == 0 ) + { + CraftGump craftGump = new CraftGump( m_From, m_CraftSystem, m_Tool, null ); + m_From.SendGump( craftGump ); + } + else // Make Button + { + int num = m_CraftSystem.CanCraft( m_From, m_Tool, m_CraftItem.ItemType ); + + if ( num > 0 ) + { + m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, num ) ); + } + else + { + Type type = null; + + CraftContext context = m_CraftSystem.GetContext( m_From ); + + if ( context != null ) + { + CraftSubResCol res = ( m_CraftItem.UseSubRes2 ? m_CraftSystem.CraftSubRes2 : m_CraftSystem.CraftSubRes ); + int resIndex = ( m_CraftItem.UseSubRes2 ? context.LastResourceIndex2 : context.LastResourceIndex ); + + if ( resIndex > -1 ) + type = res.GetAt( resIndex ).ItemType; + } + + m_CraftSystem.CreateItem( m_From, m_CraftItem.ItemType, type, m_Tool, m_CraftItem ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftItem.cs b/Scripts/Engines/Craft/Core/CraftItem.cs new file mode 100644 index 0000000..8d54373 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftItem.cs @@ -0,0 +1,1518 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Factions; +using Server.Mobiles; +using Server.Commands; + +namespace Server.Engines.Craft +{ + public enum ConsumeType + { + All, Half, None + } + + public interface ICraftable + { + int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ); + } + + public class CraftItem + { + private CraftResCol m_arCraftRes; + private CraftSkillCol m_arCraftSkill; + private Type m_Type; + + private string m_GroupNameString; + private int m_GroupNameNumber; + + private string m_NameString; + private int m_NameNumber; + + private int m_ItemHue; + + private int m_Mana; + private int m_Hits; + private int m_Stam; + + private BeverageType m_RequiredBeverage; + + private bool m_UseAllRes; + + private bool m_NeedHeat; + private bool m_NeedOven; + private bool m_NeedMill; + + private bool m_UseSubRes2; + + private bool m_ForceNonExceptional; + + public bool ForceNonExceptional + { + get { return m_ForceNonExceptional; } + set { m_ForceNonExceptional = value; } + } + + //Plume: Ajout Force non low quality + private bool m_ForceNonLow; + + public bool ForceNonLow + { + get { return m_ForceNonLow; } + set { m_ForceNonLow = value; } + } + + private bool m_TopChance; + + public bool TopChance + { + get { return m_TopChance; } + set { m_TopChance = value; } + } + + private double m_MaxChance; + + public double MaxChance + { + get { return m_MaxChance; } + set { m_MaxChance = value; } + } + + private Expansion m_RequiredExpansion; + + public Expansion RequiredExpansion + { + get { return m_RequiredExpansion; } + set { m_RequiredExpansion = value; } + } + + private Recipe m_Recipe; + + public Recipe Recipe + { + get { return m_Recipe; } + } + + public void AddRecipe( int id, CraftSystem system ) + { + if( m_Recipe != null ) + { + Console.WriteLine( "Warning: Attempted add of recipe #{0} to the crafting of {1} in CraftSystem {2}.", id, this.m_Type.Name, system ); + return; + } + + m_Recipe = new Recipe( id, system, this ); + } + + + private static Dictionary _itemIds = new Dictionary(); + + public static int ItemIDOf( Type type ) { + int itemId; + + if ( !_itemIds.TryGetValue( type, out itemId ) ) { + if ( type == typeof( FactionExplosionTrap ) ) { + itemId = 14034; + } else if ( type == typeof( FactionGasTrap ) ) { + itemId = 4523; + } else if ( type == typeof( FactionSawTrap ) ) { + itemId = 4359; + } else if ( type == typeof( FactionSpikeTrap ) ) { + itemId = 4517; + } + + if ( itemId == 0 ) { + object[] attrs = type.GetCustomAttributes( typeof( CraftItemIDAttribute ), false ); + + if ( attrs.Length > 0 ) { + CraftItemIDAttribute craftItemID = ( CraftItemIDAttribute ) attrs[0]; + itemId = craftItemID.ItemID; + } + } + + if ( itemId == 0 ) { + Item item = null; + + try { item = Activator.CreateInstance( type ) as Item; } catch { } + + if ( item != null ) { + itemId = item.ItemID; + item.Delete(); + } + } + + _itemIds[type] = itemId; + } + + return itemId; + } + + public CraftItem( Type type, TextDefinition groupName, TextDefinition name ) + { + m_arCraftRes = new CraftResCol(); + m_arCraftSkill = new CraftSkillCol(); + + m_Type = type; + + m_GroupNameString = groupName; + m_NameString = name; + + m_GroupNameNumber = groupName; + m_NameNumber = name; + m_RequiredBeverage = BeverageType.Water; + } + + public BeverageType RequiredBeverage + { + get { return m_RequiredBeverage; } + set { m_RequiredBeverage = value; } + } + + public void AddRes( Type type, TextDefinition name, int amount ) + { + AddRes( type, name, amount, "" ); + } + + public void AddRes( Type type, TextDefinition name, int amount, TextDefinition message ) + { + CraftRes craftRes = new CraftRes( type, name, amount, message ); + m_arCraftRes.Add( craftRes ); + } + + + public void AddSkill( SkillName skillToMake, double minSkill, double maxSkill ) + { + CraftSkill craftSkill = new CraftSkill( skillToMake, minSkill, maxSkill ); + m_arCraftSkill.Add( craftSkill ); + } + + public int Mana + { + get { return m_Mana; } + set { m_Mana = value; } + } + + public int Hits + { + get { return m_Hits; } + set { m_Hits = value; } + } + + public int Stam + { + get { return m_Stam; } + set { m_Stam = value; } + } + + public bool UseSubRes2 + { + get { return m_UseSubRes2; } + set { m_UseSubRes2 = value; } + } + + public bool UseAllRes + { + get { return m_UseAllRes; } + set { m_UseAllRes = value; } + } + + public bool NeedHeat + { + get { return m_NeedHeat; } + set { m_NeedHeat = value; } + } + + public bool NeedOven + { + get { return m_NeedOven; } + set { m_NeedOven = value; } + } + + public bool NeedMill + { + get { return m_NeedMill; } + set { m_NeedMill = value; } + } + + public Type ItemType + { + get { return m_Type; } + } + + public int ItemHue + { + get { return m_ItemHue; } + set { m_ItemHue = value; } + } + + public string GroupNameString + { + get { return m_GroupNameString; } + } + + public int GroupNameNumber + { + get { return m_GroupNameNumber; } + } + + public string NameString + { + get { return m_NameString; } + } + + public int NameNumber + { + get { return m_NameNumber; } + } + + public CraftResCol Resources + { + get { return m_arCraftRes; } + } + + public CraftSkillCol Skills + { + get { return m_arCraftSkill; } + } + + public bool ConsumeAttributes( Mobile from, ref object message, bool consume ) + { + bool consumMana = false; + bool consumHits = false; + bool consumStam = false; + + if ( Hits > 0 && from.Hits < Hits ) + { + message = "You lack the required hit points to make that."; + return false; + } + else + { + consumHits = consume; + } + + if ( Mana > 0 && from.Mana < Mana ) + { + message = "You lack the required mana to make that."; + return false; + } + else + { + consumMana = consume; + } + + if ( Stam > 0 && from.Stam < Stam ) + { + message = "You lack the required stamina to make that."; + return false; + } + else + { + consumStam = consume; + } + + if ( consumMana ) + from.Mana -= Mana; + + if ( consumHits ) + from.Hits -= Hits; + + if ( consumStam ) + from.Stam -= Stam; + + return true; + } + + #region Tables + public static int[] m_HeatSources = new int[] + { + 0x461, 0x48E, // Sandstone oven/fireplace + 0x92B, 0x96C, // Stone oven/fireplace + 0xDE3, 0xDE9, // Campfire + 0xFAC, 0xFAC, // Firepit + 0x184A, 0x184C, // Heating stand (left) + 0x184E, 0x1850, // Heating stand (right) + 0x398C, 0x399F, // Fire field + 0x2DDB, 0x2DDC, //Elven stove + 0x19AA, 0x19BB, // Veteran Reward Brazier + 0x197A, 0x19A9, // Large Forge + 0x0FB1, 0x0FB1, // Small Forge + 0x2DD8, 0x2DD8 // Elven Forge + }; + + private static int[] m_Ovens = new int[] + { + 0x461, 0x46F, // Sandstone oven + 0x92B, 0x93F, // Stone oven + 0x2DDB, 0x2DDC //Elven stove + }; + + private static int[] m_Mills = new int[] + { + 0x1920, 0x1921, 0x1922, 0x1923, 0x1924, 0x1295, 0x1926, 0x1928, + 0x192C, 0x192D, 0x192E, 0x129F, 0x1930, 0x1931, 0x1932, 0x1934 + }; + + private static Type[][] m_TypesTable = new Type[][] + { + new Type[]{ typeof( Log ), typeof( Board ) }, + new Type[]{ typeof( HeartwoodLog ), typeof( HeartwoodBoard ) }, + new Type[]{ typeof( BloodwoodLog ), typeof( BloodwoodBoard ) }, + new Type[]{ typeof( FrostwoodLog ), typeof( FrostwoodBoard ) }, + new Type[]{ typeof( OakLog ), typeof( OakBoard ) }, + new Type[]{ typeof( AshLog ), typeof( AshBoard ) }, + new Type[]{ typeof( YewLog ), typeof( YewBoard ) }, + new Type[]{ typeof( Leather ), typeof( Hides ) }, + new Type[]{ typeof( SpinedLeather ), typeof( SpinedHides ) }, + new Type[]{ typeof( HornedLeather ), typeof( HornedHides ) }, + new Type[]{ typeof( BarbedLeather ), typeof( BarbedHides ) }, + new Type[]{ typeof( DaemonLeather ), typeof( DaemonHides ) }, + new Type[]{ typeof( BlankMap ), typeof( BlankScroll ) }, + new Type[]{ typeof( Cloth ), typeof( UncutCloth ) }, + new Type[]{ typeof( CheeseWheel ), typeof( CheeseWedge ) }, + new Type[]{ typeof( Pumpkin ), typeof( SmallPumpkin ) }, + new Type[]{ typeof( WoodenBowlOfPeas ), typeof( PewterBowlOfPeas ) } + }; + + private static Type[] m_ColoredItemTable = new Type[] + { + typeof( BaseWeapon ), typeof( BaseArmor ), typeof( BaseClothing ), + typeof( BaseJewel ), typeof( DragonBardingDeed ), + + // Scriptiz : quelques objets qui ne sont plus dyable avec le furniture dye tub + // mais qui retienne la couleur du bois utilis� + typeof(WoodenBench), + typeof(WoodenChair), + typeof(BambooChair), + typeof(Stool), + typeof(FootStool), + typeof(Throne), + typeof(WoodenThrone), + typeof(Easle), + typeof(TallMusicStand), + typeof(ShortMusicStand), + typeof(BambooScreen), + typeof(ShojiScreen), + typeof(ElegantLowTable), + typeof(PlainLowTable), + typeof(LargeTable), + typeof(Nightstand), + typeof(YewWoodTable), + typeof(WritingTable), + typeof(WoodenBox), + typeof(SmallCrate), + typeof(MediumCrate), + typeof(LargeCrate), + typeof(WoodenChest), + typeof(PlainWoodenChest), + typeof(OrnateWoodenChest), + typeof(GildedWoodenChest), + typeof(WoodenFootLocker), + typeof(FinishedWoodenChest), + typeof(TallCabinet), + typeof(ShortCabinet), + typeof(RedArmoire), + typeof(CherryArmoire), + typeof(MapleArmoire), + typeof(ElegantArmoire), + typeof(FullBookcase), + typeof(EmptyBookcase), + typeof(Drawer), + typeof(FancyDrawer), + typeof(Armoire), + typeof(FancyArmoire), + typeof(CommodityDeedBox), + + // Parchemins et chaises elfiques + typeof(BlankScroll), + typeof(OrnateElvenChair), + typeof(BigElvenChair), + typeof(ElvenReadingChair), + }; + + private static Type[] m_ColoredResourceTable = new Type[] + { + typeof( BaseIngot ), typeof( BaseOre ), + typeof( BaseLeather ), typeof( BaseHides ), + typeof( UncutCloth ), typeof( Cloth ), + typeof( BaseGranite ), typeof( BaseScales ), + typeof(BaseWoodBoard), typeof(BaseLog), + + }; + + private static Type[] m_MarkableTable = new Type[] + { + typeof( BaseArmor ), + typeof( BaseWeapon ), + typeof( BaseClothing ), + typeof( BaseInstrument ), + typeof( DragonBardingDeed ), + typeof( BaseTool ), + typeof( BaseHarvestTool ), + typeof( FukiyaDarts ), typeof( Shuriken ), + typeof( Spellbook ), typeof( Runebook ), + typeof( BaseQuiver ), typeof(BaseJewel) + }; + + private static Type[] m_NeverColorTable = new Type[] + { + typeof( OrcHelm ) + }; + #endregion + + public bool IsMarkable( Type type ) + { + if( m_ForceNonExceptional ) //Don't even display the stuff for marking if it can't ever be exceptional. + return false; + + for ( int i = 0; i < m_MarkableTable.Length; ++i ) + { + if ( type == m_MarkableTable[i] || type.IsSubclassOf( m_MarkableTable[i] ) ) + return true; + } + + return false; + } + + public static bool RetainsColor(Type type) + { + bool neverColor = false; + + for (int i = 0; !neverColor && i < m_NeverColorTable.Length; ++i) + neverColor = (type == m_NeverColorTable[i] || type.IsSubclassOf(m_NeverColorTable[i])); + + if (neverColor) + return false; + + bool inItemTable = false; + + for (int i = 0; !inItemTable && i < m_ColoredItemTable.Length; ++i) + inItemTable = (type == m_ColoredItemTable[i] || type.IsSubclassOf(m_ColoredItemTable[i])); + + return inItemTable; + } + + public bool RetainsColorFrom(CraftSystem system, Type type) + { + if (system.RetainsColorFrom(this, type)) + return true; + + bool inItemTable = RetainsColor(m_Type); + + if (!inItemTable) + return false; + + bool inResourceTable = false; + + for (int i = 0; !inResourceTable && i < m_ColoredResourceTable.Length; ++i) + inResourceTable = (type == m_ColoredResourceTable[i] || type.IsSubclassOf(m_ColoredResourceTable[i])); + + return inResourceTable; + } + + public bool Find( Mobile from, int[] itemIDs ) + { + Map map = from.Map; + + if ( map == null ) + return false; + + IPooledEnumerable eable = map.GetItemsInRange( from.Location, 2 ); + + foreach ( Item item in eable ) + { + if ( (item.Z + 16) > from.Z && (from.Z + 16) > item.Z && Find( item.ItemID, itemIDs ) ) + { + eable.Free(); + return true; + } + } + + eable.Free(); + + for ( int x = -2; x <= 2; ++x ) + { + for ( int y = -2; y <= 2; ++y ) + { + int vx = from.X + x; + int vy = from.Y + y; + + StaticTile[] tiles = map.Tiles.GetStaticTiles( vx, vy, true ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + int z = tiles[i].Z; + int id = tiles[i].ID; + + if ( (z + 16) > from.Z && (from.Z + 16) > z && Find( id, itemIDs ) ) + return true; + } + } + } + + return false; + } + + public bool Find( int itemID, int[] itemIDs ) + { + bool contains = false; + + for ( int i = 0; !contains && i < itemIDs.Length; i += 2 ) + contains = ( itemID >= itemIDs[i] && itemID <= itemIDs[i + 1] ); + + return contains; + } + + public bool IsQuantityType( Type[][] types ) + { + for ( int i = 0; i < types.Length; ++i ) + { + Type[] check = types[i]; + + for ( int j = 0; j < check.Length; ++j ) + { + if ( typeof( IHasQuantity ).IsAssignableFrom( check[j] ) ) + return true; + } + } + + return false; + } + + public int ConsumeQuantity( Container cont, Type[][] types, int[] amounts ) + { + if ( types.Length != amounts.Length ) + throw new ArgumentException(); + + Item[][] items = new Item[types.Length][]; + int[] totals = new int[types.Length]; + + for ( int i = 0; i < types.Length; ++i ) + { + items[i] = cont.FindItemsByType( types[i], true ); + + for ( int j = 0; j < items[i].Length; ++j ) + { + IHasQuantity hq = items[i][j] as IHasQuantity; + + if ( hq == null ) + { + totals[i] += items[i][j].Amount; + } + else + { + if (hq is BaseBeverage && ((BaseBeverage)hq).Content != m_RequiredBeverage) + continue; + + totals[i] += hq.Quantity; + } + } + + if ( totals[i] < amounts[i] ) + return i; + } + + for ( int i = 0; i < types.Length; ++i ) + { + int need = amounts[i]; + + for ( int j = 0; j < items[i].Length; ++j ) + { + Item item = items[i][j]; + IHasQuantity hq = item as IHasQuantity; + + if ( hq == null ) + { + int theirAmount = item.Amount; + + if ( theirAmount < need ) + { + item.Delete(); + need -= theirAmount; + } + else + { + item.Consume( need ); + break; + } + } + else + { + if (hq is BaseBeverage && ((BaseBeverage)hq).Content != m_RequiredBeverage) + continue; + + int theirAmount = hq.Quantity; + + if ( theirAmount < need ) + { + hq.Quantity -= theirAmount; + need -= theirAmount; + } + else + { + hq.Quantity -= need; + break; + } + } + } + } + + return -1; + } + + public int GetQuantity( Container cont, Type[] types ) + { + Item[] items = cont.FindItemsByType( types, true ); + + int amount = 0; + + for ( int i = 0; i < items.Length; ++i ) + { + IHasQuantity hq = items[i] as IHasQuantity; + + if ( hq == null ) + { + amount += items[i].Amount; + } + else + { + if (hq is BaseBeverage && ((BaseBeverage)hq).Content != m_RequiredBeverage) + continue; + + amount += hq.Quantity; + } + } + + return amount; + } + + public bool ConsumeRes( Mobile from, Type typeRes, CraftSystem craftSystem, ref int resHue, ref int maxAmount, ConsumeType consumeType, ref object message ) + { + return ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, consumeType, ref message, false ); + } + + public bool ConsumeRes( Mobile from, Type typeRes, CraftSystem craftSystem, ref int resHue, ref int maxAmount, ConsumeType consumeType, ref object message, bool isFailure ) + { + Container ourPack = from.Backpack; + + if ( ourPack == null ) + return false; + + if ( m_NeedHeat && !Find( from, m_HeatSources ) ) + { + message = 1044487; // You must be near a fire source to cook. + return false; + } + + if ( m_NeedOven && !Find( from, m_Ovens ) ) + { + message = 1044493; // You must be near an oven to bake that. + return false; + } + + if ( m_NeedMill && !Find( from, m_Mills ) ) + { + message = 1044491; // You must be near a flour mill to do that. + return false; + } + + Type[][] types = new Type[m_arCraftRes.Count][]; + int[] amounts = new int[m_arCraftRes.Count]; + + maxAmount = int.MaxValue; + + CraftSubResCol resCol = ( m_UseSubRes2 ? craftSystem.CraftSubRes2 : craftSystem.CraftSubRes ); + + for ( int i = 0; i < types.Length; ++i ) + { + CraftRes craftRes = m_arCraftRes.GetAt( i ); + Type baseType = craftRes.ItemType; + + // Resource Mutation + if ( (baseType == resCol.ResType) && ( typeRes != null ) ) + { + baseType = typeRes; + + CraftSubRes subResource = resCol.SearchFor( baseType ); + + if ( subResource != null && from.Skills[craftSystem.MainSkill].Base < subResource.RequiredSkill ) + { + message = subResource.Message; + return false; + } + } + // ****************** + + for ( int j = 0; types[i] == null && j < m_TypesTable.Length; ++j ) + { + if ( m_TypesTable[j][0] == baseType ) + types[i] = m_TypesTable[j]; + } + + if ( types[i] == null ) + types[i] = new Type[]{ baseType }; + + amounts[i] = craftRes.Amount; + + // For stackable items that can ben crafted more than one at a time + if ( UseAllRes ) + { + int tempAmount = ourPack.GetAmount( types[i] ); + tempAmount /= amounts[i]; + if ( tempAmount < maxAmount ) + { + maxAmount = tempAmount; + + if ( maxAmount == 0 ) + { + CraftRes res = m_arCraftRes.GetAt( i ); + + if ( res.MessageNumber > 0 ) + message = res.MessageNumber; + else if ( !String.IsNullOrEmpty( res.MessageString ) ) + message = res.MessageString; + else + message = 502925; // You don't have the resources required to make that item. + + return false; + } + } + } + // **************************** + + if ( isFailure && !craftSystem.ConsumeOnFailure( from, types[i][0], this ) ) + amounts[i] = 0; + } + + // We adjust the amount of each resource to consume the max posible + if ( UseAllRes ) + { + for ( int i = 0; i < amounts.Length; ++i ) + amounts[i] *= maxAmount; + } + else + maxAmount = -1; + + Item consumeExtra = null; + + if ( m_NameNumber == 1041267 ) + { + // Runebooks are a special case, they need a blank recall rune + + List runes = ourPack.FindItemsByType(); + + for ( int i = 0; i < runes.Count; ++i ) + { + RecallRune rune = runes[i]; + + if ( rune != null && !rune.Marked ) + { + consumeExtra = rune; + break; + } + } + + if ( consumeExtra == null ) + { + message = 1044253; // You don't have the components needed to make that. + return false; + } + } + + int index = 0; + + // Consume ALL + if ( consumeType == ConsumeType.All ) + { + m_ResHue = 0; m_ResAmount = 0; m_System = craftSystem; + + if ( IsQuantityType( types ) ) + index = ConsumeQuantity( ourPack, types, amounts ); + else + index = ourPack.ConsumeTotalGrouped( types, amounts, true, new OnItemConsumed( OnResourceConsumed ), new CheckItemGroup( CheckHueGrouping ) ); + + resHue = m_ResHue; + } + + // Consume Half ( for use all resource craft type ) + else if ( consumeType == ConsumeType.Half ) + { + for ( int i = 0; i < amounts.Length; i++ ) + { + amounts[i] /= 2; + + if ( amounts[i] < 1 ) + amounts[i] = 1; + } + + m_ResHue = 0; m_ResAmount = 0; m_System = craftSystem; + + if ( IsQuantityType( types ) ) + index = ConsumeQuantity( ourPack, types, amounts ); + else + index = ourPack.ConsumeTotalGrouped( types, amounts, true, new OnItemConsumed( OnResourceConsumed ), new CheckItemGroup( CheckHueGrouping ) ); + + resHue = m_ResHue; + } + + else // ConstumeType.None ( it's basicaly used to know if the crafter has enough resource before starting the process ) + { + index = -1; + + if ( IsQuantityType( types ) ) + { + for ( int i = 0; i < types.Length; i++ ) + { + if ( GetQuantity( ourPack, types[i] ) < amounts[i] ) + { + index = i; + break; + } + } + } + else + { + for ( int i = 0; i < types.Length; i++ ) + { + if ( ourPack.GetBestGroupAmount( types[i], true, new CheckItemGroup( CheckHueGrouping ) ) < amounts[i] ) + { + index = i; + break; + } + } + } + } + + if ( index == -1 ) + { + if ( consumeType != ConsumeType.None ) + if ( consumeExtra != null ) + consumeExtra.Delete(); + + return true; + } + else + { + CraftRes res = m_arCraftRes.GetAt( index ); + + if ( res.MessageNumber > 0 ) + message = res.MessageNumber; + else if ( res.MessageString != null && res.MessageString != String.Empty ) + message = res.MessageString; + else + message = 502925; // You don't have the resources required to make that item. + + return false; + } + } + + private int m_ResHue; + private int m_ResAmount; + private CraftSystem m_System; + + private void OnResourceConsumed( Item item, int amount ) + { + if ( !RetainsColorFrom( m_System, item.GetType() ) ) + return; + + if ( amount >= m_ResAmount ) + { + m_ResHue = item.Hue; + m_ResAmount = amount; + } + } + + private int CheckHueGrouping( Item a, Item b ) + { + return b.Hue.CompareTo( a.Hue ); + } + + public double GetExceptionalChance( CraftSystem system, double chance, Mobile from ) + { + if( m_ForceNonExceptional ) + return 0.0; + + double bonus = 0.0; + + if (from.Talisman is BaseTalisman) + { + BaseTalisman talisman = (BaseTalisman)from.Talisman; + + if (talisman.Skill == system.MainSkill) + { + chance -= talisman.SuccessBonus / 100.0; + bonus = talisman.ExceptionalBonus / 100.0; + } + } + + switch (system.ECA) + { + default: + case CraftECA.ChanceMinusSixty: chance -= 0.6; break; + case CraftECA.FiftyPercentChanceMinusTenPercent: chance = chance * 0.5 - 0.1; break; + case CraftECA.ChanceMinusSixtyToFourtyFive: + { + double offset = 0.60 - ((from.Skills[system.MainSkill].Value - 95.0) * 0.03); + + if (offset < 0.45) + offset = 0.45; + else if (offset > 0.60) + offset = 0.60; + + chance -= offset; + break; + } + } + + if (chance > 0) + return chance + bonus; + + return chance; + } + + public double GetLowChance(CraftSystem system, double chance, Mobile from) + { + if (m_ForceNonLow) + return 1.1; + + switch (system.ECA) + { + default: + //Plume : � partir de 50.1% de chance de r�ussir l'item, il ne sera jamais LowQuality + case CraftECA.ChanceMinusSixty: chance += 0.5; break; + //Plume : � partir de 60% de chance de r�ussir l'item, il se sera jamais LowQuality + case CraftECA.FiftyPercentChanceMinusTenPercent: chance *= 1.5 +0.1; break; + //Plume : Fonctionnelle selon l'offset + case CraftECA.ChanceMinusSixtyToFourtyFive: + { + double offset = 0.60 - ((from.Skills[system.MainSkill].Value - 95.0) * 0.03); + + if (offset < 0.45) + offset = 0.45; + else if (offset > 0.60) + offset = 0.60; + + chance += offset; + break; + } + } + + if (chance > 0) + return chance; + + return chance; + } + + public bool CheckSkills( Mobile from, Type typeRes, CraftSystem craftSystem, ref int quality, ref bool allRequiredSkills ) + { + return CheckSkills( from, typeRes, craftSystem, ref quality, ref allRequiredSkills, true ); + } + + public bool CheckSkills( Mobile from, Type typeRes, CraftSystem craftSystem, ref int quality, ref bool allRequiredSkills, bool gainSkills ) + { + double chance = GetSuccessChance( from, typeRes, craftSystem, gainSkills, ref allRequiredSkills ); + + if ( GetExceptionalChance( craftSystem, chance, from ) > Utility.RandomDouble() ) + quality = 2; + + if (GetLowChance(craftSystem, chance, from) < Utility.RandomDouble()) + quality = 0; + + return ( chance > Utility.RandomDouble() ); + } + + public double GetSuccessChance( Mobile from, Type typeRes, CraftSystem craftSystem, bool gainSkills, ref bool allRequiredSkills ) + { + double minMainSkill = 0.0; + double maxMainSkill = 0.0; + double valMainSkill = 0.0; + + allRequiredSkills = true; + + for ( int i = 0; i < m_arCraftSkill.Count; i++) + { + CraftSkill craftSkill = m_arCraftSkill.GetAt(i); + + double minSkill = craftSkill.MinSkill; + double maxSkill = craftSkill.MaxSkill; + double valSkill = from.Skills[craftSkill.SkillToMake].Value; + + if ( valSkill < minSkill ) + allRequiredSkills = false; + + if ( craftSkill.SkillToMake == craftSystem.MainSkill ) + { + minMainSkill = minSkill; + maxMainSkill = maxSkill; + valMainSkill = valSkill; + } + + if ( gainSkills ) // This is a passive check. Success chance is entirely dependant on the main skill + from.CheckSkill( craftSkill.SkillToMake, minSkill, maxSkill ); + } + + double chance; + + if ( allRequiredSkills ) + chance = craftSystem.GetChanceAtMin( this ) + ((valMainSkill - minMainSkill) / (maxMainSkill - minMainSkill) * (1.0 - craftSystem.GetChanceAtMin( this ))); + else + chance = 0.0; + + if (allRequiredSkills && from.Talisman is BaseTalisman) + { + BaseTalisman talisman = (BaseTalisman)from.Talisman; + + if (talisman.Skill == craftSystem.MainSkill) + chance += talisman.SuccessBonus / 100.0; + } + + if ( allRequiredSkills && valMainSkill == maxMainSkill ) + chance = 1.0; + + + if (TopChance && (MaxChance < chance)) + chance = MaxChance; + + + return chance; + } + + public void Craft( Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool ) + { + if ( from.BeginAction( typeof( CraftSystem ) ) ) + { + if( RequiredExpansion == Expansion.None || ( from.NetState != null && from.NetState.SupportsExpansion( RequiredExpansion ) ) ) + { + bool allRequiredSkills = true; + double chance = GetSuccessChance( from, typeRes, craftSystem, false, ref allRequiredSkills ); + + if ( allRequiredSkills && chance >= 0.0 ) + { + if( this.Recipe == null || !(from is PlayerMobile) || ((PlayerMobile)from).HasRecipe( this.Recipe ) ) + { + int badCraft = craftSystem.CanCraft( from, tool, m_Type ); + + if( badCraft <= 0 ) + { + int resHue = 0; + int maxAmount = 0; + object message = null; + + if( ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, ConsumeType.None, ref message ) ) + { + message = null; + + if( ConsumeAttributes( from, ref message, false ) ) + { + CraftContext context = craftSystem.GetContext( from ); + + if( context != null ) + context.OnMade( this ); + + int iMin = craftSystem.MinCraftEffect; + int iMax = (craftSystem.MaxCraftEffect - iMin) + 1; + int iRandom = Utility.Random( iMax ); + iRandom += iMin + 1; + new InternalTimer( from, craftSystem, this, typeRes, tool, iRandom ).Start(); + } + else + { + from.EndAction( typeof( CraftSystem ) ); + from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); + } + } + else + { + from.EndAction( typeof( CraftSystem ) ); + from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); + } + } + else + { + from.EndAction( typeof( CraftSystem ) ); + from.SendGump( new CraftGump( from, craftSystem, tool, badCraft ) ); + } + } + else + { + from.EndAction( typeof( CraftSystem ) ); + from.SendGump( new CraftGump( from, craftSystem, tool, 1072847 ) ); // You must learn that recipe from a scroll. + } + } + else + { + from.EndAction( typeof( CraftSystem ) ); + from.SendGump( new CraftGump( from, craftSystem, tool, 1044153 ) ); // You don't have the required skills to attempt this item. + } + } + else + { + from.EndAction( typeof( CraftSystem ) ); + from.SendGump( new CraftGump( from, craftSystem, tool, RequiredExpansionMessage( RequiredExpansion ) ) ); //The {0} expansion is required to attempt this item. + } + } + else + { + from.SendLocalizedMessage( 500119 ); // You must wait to perform another action + } + } + + private object RequiredExpansionMessage( Expansion expansion ) //Eventually convert to TextDefinition, but that requires that we convert all the gumps to ues it too. Not that it wouldn't be a bad idea. + { + switch( expansion ) + { + case Expansion.SE: + return 1063307; // The "Samurai Empire" expansion is required to attempt this item. + case Expansion.ML: + return 1072650; // The "Mondain's Legacy" expansion is required to attempt this item. + default: + return String.Format( "The \"{0}\" expansion is required to attempt this item.", ExpansionInfo.GetInfo( expansion ).Name ); + } + } + + public void CompleteCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CustomCraft customCraft ) + { + int badCraft = craftSystem.CanCraft( from, tool, m_Type ); + + if ( badCraft > 0 ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, badCraft ) ); + else + from.SendLocalizedMessage( badCraft ); + + return; + } + + int checkResHue = 0, checkMaxAmount = 0; + object checkMessage = null; + + // Not enough resource to craft it + if ( !ConsumeRes( from, typeRes, craftSystem, ref checkResHue, ref checkMaxAmount, ConsumeType.None, ref checkMessage ) ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, checkMessage ) ); + else if ( checkMessage is int && (int)checkMessage > 0 ) + from.SendLocalizedMessage( (int)checkMessage ); + else if ( checkMessage is string ) + from.SendMessage( (string)checkMessage ); + + return; + } + else if ( !ConsumeAttributes( from, ref checkMessage, false ) ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, checkMessage ) ); + else if ( checkMessage is int && (int)checkMessage > 0 ) + from.SendLocalizedMessage( (int)checkMessage ); + else if ( checkMessage is string ) + from.SendMessage( (string)checkMessage ); + + return; + } + + bool toolBroken = false; + + int ignored = 1; + int endquality = 1; + + bool allRequiredSkills = true; + + if ( CheckSkills( from, typeRes, craftSystem, ref ignored, ref allRequiredSkills ) ) + { + // Resource + int resHue = 0; + int maxAmount = 0; + + object message = null; + + // Not enough resource to craft it + if ( !ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, ConsumeType.All, ref message ) ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); + else if ( message is int && (int)message > 0 ) + from.SendLocalizedMessage( (int)message ); + else if ( message is string ) + from.SendMessage( (string)message ); + + return; + } + else if ( !ConsumeAttributes( from, ref message, true ) ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); + else if ( message is int && (int)message > 0 ) + from.SendLocalizedMessage( (int)message ); + else if ( message is string ) + from.SendMessage( (string)message ); + + return; + } + + tool.UsesRemaining--; + + if ( craftSystem is DefBlacksmithy ) + { + AncientSmithyHammer hammer = from.FindItemOnLayer( Layer.OneHanded ) as AncientSmithyHammer; + if ( hammer != null && hammer != tool ) + { + hammer.UsesRemaining--; + if ( hammer.UsesRemaining < 1 ) + hammer.Delete(); + } + } + + if (tool.UsesRemaining < 1 && tool.BreakOnDepletion) + toolBroken = true; + + if ( toolBroken ) + tool.Delete(); + + int num = 0; + + Item item; + if ( customCraft != null ) + { + item = customCraft.CompleteCraft( out num ); + } + else if ( typeof( MapItem ).IsAssignableFrom( ItemType ) && from.Map != Map.Trammel && from.Map != Map.Felucca ) + { + item = new IndecipherableMap(); + from.SendLocalizedMessage( 1070800 ); // The map you create becomes mysteriously indecipherable. + } + else + { + item = Activator.CreateInstance( ItemType ) as Item; + } + + if ( item != null ) + { + #region Mondain's Legacy + if (item is Board) + { + Type resourceType = typeRes; + + if (resourceType == null) + resourceType = Resources.GetAt(0).ItemType; + + CraftResource thisResource = CraftResources.GetFromType(resourceType); + + switch (thisResource) + { + case CraftResource.OakWood: item = new OakBoard(); break; + case CraftResource.AshWood: item = new AshBoard(); break; + case CraftResource.YewWood: item = new YewBoard(); break; + case CraftResource.Heartwood: item = new HeartwoodBoard(); break; + case CraftResource.Bloodwood: item = new BloodwoodBoard(); break; + case CraftResource.Frostwood: item = new FrostwoodBoard(); break; + default: item = new Board(); break; + } + } + #endregion + + if( item is ICraftable ) + endquality = ((ICraftable)item).OnCraft( quality, makersMark, from, craftSystem, typeRes, tool, this, resHue ); + else if ( item.Hue == 0 ) + item.Hue = resHue; + + if ( maxAmount > 0 ) + { + if ( !item.Stackable && item is IUsesRemaining ) + ((IUsesRemaining)item).UsesRemaining *= maxAmount; + else + item.Amount = maxAmount; + } + + from.AddToBackpack( item ); + + if( from.AccessLevel > AccessLevel.Player ) + CommandLogging.WriteLine( from, "Crafting {0} with craft system {1}", CommandLogging.Format( item ), craftSystem.GetType().Name ); + + //from.PlaySound( 0x57 ); + } + + if ( num == 0 ) + num = craftSystem.PlayEndingEffect( from, false, true, toolBroken, endquality, makersMark, this ); + + bool queryFactionImbue = false; + int availableSilver = 0; + FactionItemDefinition def = null; + Faction faction = null; + + if ( item is IFactionItem ) + { + def = FactionItemDefinition.Identify( item ); + + if ( def != null ) + { + faction = Faction.Find( from ); + + if ( faction != null ) + { + Town town = Town.FromRegion( from.Region ); + + if ( town != null && town.Owner == faction ) + { + Container pack = from.Backpack; + + if ( pack != null ) + { + availableSilver = pack.GetAmount( typeof( Silver ) ); + + if ( availableSilver >= def.SilverCost ) + queryFactionImbue = Faction.IsNearType( from, def.VendorType, 12 ); + } + } + } + } + } + + // TODO: Scroll imbuing + + if ( queryFactionImbue ) + from.SendGump( new FactionImbueGump( quality, item, from, craftSystem, tool, num, availableSilver, faction, def ) ); + else if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, num ) ); + else if ( num > 0 ) + from.SendLocalizedMessage( num ); + } + else if ( !allRequiredSkills ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, 1044153 ) ); + else + from.SendLocalizedMessage( 1044153 ); // You don't have the required skills to attempt this item. + } + else + { + ConsumeType consumeType = ( UseAllRes ? ConsumeType.Half : ConsumeType.All ); + int resHue = 0; + int maxAmount = 0; + + object message = null; + + // Not enough resource to craft it + if ( !ConsumeRes( from, typeRes, craftSystem, ref resHue, ref maxAmount, consumeType, ref message, true ) ) + { + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, message ) ); + else if ( message is int && (int)message > 0 ) + from.SendLocalizedMessage( (int)message ); + else if ( message is string ) + from.SendMessage( (string)message ); + + return; + } + + tool.UsesRemaining--; + + if (tool.UsesRemaining < 1 && tool.BreakOnDepletion) + toolBroken = true; + + if ( toolBroken ) + tool.Delete(); + + // SkillCheck failed. + int num = craftSystem.PlayEndingEffect( from, true, true, toolBroken, endquality, false, this ); + + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, craftSystem, tool, num ) ); + else if ( num > 0 ) + from.SendLocalizedMessage( num ); + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private int m_iCount; + private int m_iCountMax; + private CraftItem m_CraftItem; + private CraftSystem m_CraftSystem; + private Type m_TypeRes; + private BaseTool m_Tool; + + public InternalTimer( Mobile from, CraftSystem craftSystem, CraftItem craftItem, Type typeRes, BaseTool tool, int iCountMax ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( craftSystem.Delay ), iCountMax ) + { + m_From = from; + m_CraftItem = craftItem; + m_iCount = 0; + m_iCountMax = iCountMax; + m_CraftSystem = craftSystem; + m_TypeRes = typeRes; + m_Tool = tool; + } + + protected override void OnTick() + { + m_iCount++; + + m_From.DisruptiveAction(); + + if ( m_iCount < m_iCountMax ) + { + m_CraftSystem.PlayCraftEffect( m_From ); + } + else + { + m_From.EndAction( typeof( CraftSystem ) ); + + int badCraft = m_CraftSystem.CanCraft( m_From, m_Tool, m_CraftItem.m_Type ); + + if ( badCraft > 0 ) + { + if ( m_Tool != null && !m_Tool.Deleted && m_Tool.UsesRemaining > 0 ) + m_From.SendGump( new CraftGump( m_From, m_CraftSystem, m_Tool, badCraft ) ); + else + m_From.SendLocalizedMessage( badCraft ); + + return; + } + + int quality = 1; + bool allRequiredSkills = true; + + m_CraftItem.CheckSkills( m_From, m_TypeRes, m_CraftSystem, ref quality, ref allRequiredSkills, false ); + + CraftContext context = m_CraftSystem.GetContext( m_From ); + + if ( context == null ) + return; + + if ( typeof( CustomCraft ).IsAssignableFrom( m_CraftItem.ItemType ) ) + { + CustomCraft cc = null; + + try{ cc = Activator.CreateInstance( m_CraftItem.ItemType, new object[] { m_From, m_CraftItem, m_CraftSystem, m_TypeRes, m_Tool, quality } ) as CustomCraft; } + catch{} + + if ( cc != null ) + cc.EndCraftAction(); + + return; + } + + bool makersMark = false; + + if ( quality == 2 && m_From.Skills[m_CraftSystem.MainSkill].Base >= 100.0 ) + makersMark = m_CraftItem.IsMarkable( m_CraftItem.ItemType ); + + if ( makersMark && context.MarkOption == CraftMarkOption.PromptForMark ) + { + m_From.SendGump( new QueryMakersMarkGump( quality, m_From, m_CraftItem, m_CraftSystem, m_TypeRes, m_Tool ) ); + } + else + { + if ( context.MarkOption == CraftMarkOption.DoNotMark ) + makersMark = false; + + m_CraftItem.CompleteCraft( quality, makersMark, m_From, m_CraftSystem, m_TypeRes, m_Tool, null ); + } + } + } + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftItemCol.cs b/Scripts/Engines/Craft/Core/CraftItemCol.cs new file mode 100644 index 0000000..8ac8d28 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftItemCol.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftItemCol : System.Collections.CollectionBase + { + public CraftItemCol() + { + } + + public int Add( CraftItem craftItem ) + { + return List.Add( craftItem ); + } + + public void Remove( int index ) + { + if ( index > Count - 1 || index < 0 ) + { + } + else + { + List.RemoveAt( index ); + } + } + + public CraftItem GetAt( int index ) + { + return ( CraftItem ) List[index]; + } + + public CraftItem SearchForSubclass( Type type ) + { + for ( int i = 0; i < List.Count; i++ ) + { + CraftItem craftItem = ( CraftItem )List[i]; + + if ( craftItem.ItemType == type || type.IsSubclassOf( craftItem.ItemType ) ) + return craftItem; + } + + return null; + } + + public CraftItem SearchFor( Type type ) + { + for ( int i = 0; i < List.Count; i++ ) + { + CraftItem craftItem = ( CraftItem )List[i]; + if ( craftItem.ItemType == type ) + { + return craftItem; + } + } + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftItemIDAttribute.cs b/Scripts/Engines/Craft/Core/CraftItemIDAttribute.cs new file mode 100644 index 0000000..3247aa8 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftItemIDAttribute.cs @@ -0,0 +1,18 @@ +using System; +using Server; + +namespace Server.Engines.Craft +{ + [AttributeUsage( AttributeTargets.Class )] + public class CraftItemIDAttribute : Attribute + { + private int m_ItemID; + + public int ItemID{ get{ return m_ItemID; } } + + public CraftItemIDAttribute( int itemID ) + { + m_ItemID = itemID; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftRes.cs b/Scripts/Engines/Craft/Core/CraftRes.cs new file mode 100644 index 0000000..0d529d1 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftRes.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftRes + { + private Type m_Type; + private int m_Amount; + + private string m_MessageString; + private int m_MessageNumber; + + private string m_NameString; + private int m_NameNumber; + + public CraftRes( Type type, int amount ) + { + m_Type = type; + m_Amount = amount; + } + + public CraftRes( Type type, TextDefinition name, int amount, TextDefinition message ): this ( type, amount ) + { + m_NameNumber = name; + m_MessageNumber = message; + + m_NameString = name; + m_MessageString = message; + } + + public void SendMessage( Mobile from ) + { + if ( m_MessageNumber > 0 ) + from.SendLocalizedMessage( m_MessageNumber ); + else if ( !String.IsNullOrEmpty( m_MessageString ) ) + from.SendMessage( m_MessageString ); + else + from.SendLocalizedMessage( 502925 ); // You don't have the resources required to make that item. + } + + public Type ItemType + { + get { return m_Type; } + } + + public string MessageString + { + get { return m_MessageString; } + } + + public int MessageNumber + { + get { return m_MessageNumber; } + } + + public string NameString + { + get { return m_NameString; } + } + + public int NameNumber + { + get { return m_NameNumber; } + } + + public int Amount + { + get { return m_Amount; } + } + } +} diff --git a/Scripts/Engines/Craft/Core/CraftResCol.cs b/Scripts/Engines/Craft/Core/CraftResCol.cs new file mode 100644 index 0000000..b313a2e --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftResCol.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftResCol : System.Collections.CollectionBase + { + public CraftResCol() + { + } + + public void Add( CraftRes craftRes ) + { + List.Add( craftRes ); + } + + public void Remove( int index ) + { + if ( index > Count - 1 || index < 0 ) + { + } + else + { + List.RemoveAt( index ); + } + } + + public CraftRes GetAt( int index ) + { + return ( CraftRes ) List[index]; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftSkill.cs b/Scripts/Engines/Craft/Core/CraftSkill.cs new file mode 100644 index 0000000..d741795 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftSkill.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftSkill + { + private SkillName m_SkillToMake; + private double m_MinSkill; + private double m_MaxSkill; + + public CraftSkill( SkillName skillToMake, double minSkill, double maxSkill ) + { + m_SkillToMake = skillToMake; + m_MinSkill = minSkill; + m_MaxSkill = maxSkill; + } + + public SkillName SkillToMake + { + get { return m_SkillToMake; } + } + + public double MinSkill + { + get { return m_MinSkill; } + } + + public double MaxSkill + { + get { return m_MaxSkill; } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftSkillCol.cs b/Scripts/Engines/Craft/Core/CraftSkillCol.cs new file mode 100644 index 0000000..a6f22da --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftSkillCol.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftSkillCol : System.Collections.CollectionBase + { + public CraftSkillCol() + { + } + + public void Add( CraftSkill craftSkill ) + { + List.Add( craftSkill ); + } + + public void Remove( int index ) + { + if ( index > Count - 1 || index < 0 ) + { + } + else + { + List.RemoveAt( index ); + } + } + + public CraftSkill GetAt( int index ) + { + return ( CraftSkill ) List[index]; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftSubRes.cs b/Scripts/Engines/Craft/Core/CraftSubRes.cs new file mode 100644 index 0000000..7f5ae31 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftSubRes.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftSubRes + { + private Type m_Type; + private double m_ReqSkill; + private string m_NameString; + private int m_NameNumber; + private int m_GenericNameNumber; + private object m_Message; + + public CraftSubRes( Type type, TextDefinition name, double reqSkill, object message ) : this( type, name, reqSkill, 0, message ) + { + } + + public CraftSubRes( Type type, TextDefinition name, double reqSkill, int genericNameNumber, object message ) + { + m_Type = type; + m_NameNumber = name; + m_NameString = name; + m_ReqSkill = reqSkill; + m_GenericNameNumber = genericNameNumber; + m_Message = message; + } + + public Type ItemType + { + get { return m_Type; } + } + + public string NameString + { + get { return m_NameString; } + } + + public int NameNumber + { + get { return m_NameNumber; } + } + + public int GenericNameNumber + { + get { return m_GenericNameNumber; } + } + + public object Message + { + get { return m_Message; } + } + + public double RequiredSkill + { + get { return m_ReqSkill; } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftSubResCol.cs b/Scripts/Engines/Craft/Core/CraftSubResCol.cs new file mode 100644 index 0000000..50330ac --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftSubResCol.cs @@ -0,0 +1,75 @@ +using System; + +namespace Server.Engines.Craft +{ + public class CraftSubResCol : System.Collections.CollectionBase + { + private Type m_Type; + private string m_NameString; + private int m_NameNumber; + private bool m_Init; + + public bool Init + { + get { return m_Init; } + set { m_Init = value; } + } + + public Type ResType + { + get { return m_Type; } + set { m_Type = value; } + } + + public string NameString + { + get { return m_NameString; } + set { m_NameString = value; } + } + + public int NameNumber + { + get { return m_NameNumber; } + set { m_NameNumber = value; } + } + + public CraftSubResCol() + { + m_Init = false; + } + + public void Add( CraftSubRes craftSubRes ) + { + List.Add( craftSubRes ); + } + + public void Remove( int index ) + { + if ( index > Count - 1 || index < 0 ) + { + } + else + { + List.RemoveAt( index ); + } + } + + public CraftSubRes GetAt( int index ) + { + return ( CraftSubRes ) List[index]; + } + + public CraftSubRes SearchFor( Type type ) + { + for ( int i = 0; i < List.Count; i++ ) + { + CraftSubRes craftSubRes = ( CraftSubRes )List[i]; + if ( craftSubRes.ItemType == type ) + { + return craftSubRes; + } + } + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CraftSystem.cs b/Scripts/Engines/Craft/Core/CraftSystem.cs new file mode 100644 index 0000000..98502d6 --- /dev/null +++ b/Scripts/Engines/Craft/Core/CraftSystem.cs @@ -0,0 +1,400 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Engines.Craft +{ + public enum CraftECA + { + ChanceMinusSixty, + FiftyPercentChanceMinusTenPercent, + ChanceMinusSixtyToFourtyFive + } + + public abstract class CraftSystem + { + private int m_MinCraftEffect; + private int m_MaxCraftEffect; + private double m_Delay; + private bool m_Resmelt; + private bool m_Repair; + private bool m_MarkOption; + private bool m_CanEnhance; + + private CraftItemCol m_CraftItems; + private CraftGroupCol m_CraftGroups; + private CraftSubResCol m_CraftSubRes; + private CraftSubResCol m_CraftSubRes2; + + private List m_Recipes; + private List m_RareRecipes; + + public int MinCraftEffect { get { return m_MinCraftEffect; } } + public int MaxCraftEffect { get { return m_MaxCraftEffect; } } + public double Delay { get { return m_Delay; } } + + public CraftItemCol CraftItems{ get { return m_CraftItems; } } + public CraftGroupCol CraftGroups{ get { return m_CraftGroups; } } + public CraftSubResCol CraftSubRes{ get { return m_CraftSubRes; } } + public CraftSubResCol CraftSubRes2{ get { return m_CraftSubRes2; } } + + public abstract SkillName MainSkill{ get; } + + public virtual int GumpTitleNumber{ get{ return 0; } } + public virtual string GumpTitleString{ get{ return ""; } } + + public virtual CraftECA ECA{ get{ return CraftECA.ChanceMinusSixty; } } + + private Dictionary m_ContextTable = new Dictionary(); + + public abstract double GetChanceAtMin( CraftItem item ); + + public virtual bool RetainsColorFrom( CraftItem item, Type type ) + { + return false; + } + + public CraftContext GetContext( Mobile m ) + { + if ( m == null ) + return null; + + if ( m.Deleted ) + { + m_ContextTable.Remove( m ); + return null; + } + + CraftContext c = null; + m_ContextTable.TryGetValue( m, out c ); + + if ( c == null ) + m_ContextTable[m] = c = new CraftContext(); + + return c; + } + + public void OnMade( Mobile m, CraftItem item ) + { + CraftContext c = GetContext( m ); + + if ( c != null ) + c.OnMade( item ); + } + + public bool Resmelt + { + get { return m_Resmelt; } + set { m_Resmelt = value; } + } + + public bool Repair + { + get{ return m_Repair; } + set{ m_Repair = value; } + } + + public bool MarkOption + { + get{ return m_MarkOption; } + set{ m_MarkOption = value; } + } + + public bool CanEnhance + { + get{ return m_CanEnhance; } + set{ m_CanEnhance = value; } + } + + public CraftSystem( int minCraftEffect, int maxCraftEffect, double delay ) + { + m_MinCraftEffect = minCraftEffect; + m_MaxCraftEffect = maxCraftEffect; + m_Delay = delay; + + m_CraftItems = new CraftItemCol(); + m_CraftGroups = new CraftGroupCol(); + m_CraftSubRes = new CraftSubResCol(); + m_CraftSubRes2 = new CraftSubResCol(); + + m_Recipes = new List(); + m_RareRecipes = new List(); + + InitCraftList(); + } + + public virtual bool ConsumeOnFailure( Mobile from, Type resourceType, CraftItem craftItem ) + { + return true; + } + + public void CreateItem( Mobile from, Type type, Type typeRes, BaseTool tool, CraftItem realCraftItem ) + { + // Verify if the type is in the list of the craftable item + CraftItem craftItem = m_CraftItems.SearchFor( type ); + if ( craftItem != null ) + { + // The item is in the list, try to create it + // Test code: items like sextant parts can be crafted either directly from ingots, or from different parts + realCraftItem.Craft( from, this, typeRes, tool ); + //craftItem.Craft( from, this, typeRes, tool ); + } + } + + public int RandomRecipe() + { + if (m_Recipes.Count == 0) + return -1; + + return m_Recipes[Utility.Random(m_Recipes.Count)]; + } + + public int RandomRareRecipe() + { + if (m_RareRecipes.Count == 0) + return -1; + + return m_RareRecipes[Utility.Random(m_RareRecipes.Count)]; + } + + public int AddCraft( Type typeItem, TextDefinition group, TextDefinition name, double minSkill, double maxSkill, Type typeRes, TextDefinition nameRes, int amount ) + { + return AddCraft( typeItem, group, name, MainSkill, minSkill, maxSkill, typeRes, nameRes, amount, "" ); + } + + public int AddCraft( Type typeItem, TextDefinition group, TextDefinition name, double minSkill, double maxSkill, Type typeRes, TextDefinition nameRes, int amount, TextDefinition message ) + { + return AddCraft( typeItem, group, name, MainSkill, minSkill, maxSkill, typeRes, nameRes, amount, message ); + } + + public int AddCraft( Type typeItem, TextDefinition group, TextDefinition name, SkillName skillToMake, double minSkill, double maxSkill, Type typeRes, TextDefinition nameRes, int amount ) + { + return AddCraft( typeItem, group, name, skillToMake, minSkill, maxSkill, typeRes, nameRes, amount, "" ); + } + + public int AddCraft( Type typeItem, TextDefinition group, TextDefinition name, SkillName skillToMake, double minSkill, double maxSkill, Type typeRes, TextDefinition nameRes, int amount, TextDefinition message ) + { + CraftItem craftItem = new CraftItem( typeItem, group, name ); + craftItem.AddRes( typeRes, nameRes, amount, message ); + craftItem.AddSkill( skillToMake, minSkill, maxSkill ); + + DoGroup( group, craftItem ); + return m_CraftItems.Add( craftItem ); + } + + + private void DoGroup( TextDefinition groupName, CraftItem craftItem ) + { + int index = m_CraftGroups.SearchFor( groupName ); + + if ( index == -1) + { + CraftGroup craftGroup = new CraftGroup( groupName ); + craftGroup.AddCraftItem( craftItem ); + m_CraftGroups.Add( craftGroup ); + } + else + { + m_CraftGroups.GetAt( index ).AddCraftItem( craftItem ); + } + } + + public void SetItemHue(int index, int hue) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.ItemHue = hue; + } + + public void SetManaReq( int index, int mana ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.Mana = mana; + } + + public void SetStamReq( int index, int stam ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.Stam = stam; + } + + public void SetHitsReq( int index, int hits ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.Hits = hits; + } + + public void SetUseAllRes( int index, bool useAll ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.UseAllRes = useAll; + } + + public void SetNeedHeat( int index, bool needHeat ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.NeedHeat = needHeat; + } + + public void SetNeedOven( int index, bool needOven ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.NeedOven = needOven; + } + + public void SetBeverageType(int index, BeverageType requiredBeverage) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.RequiredBeverage = requiredBeverage; + } + + public void SetNeedMill( int index, bool needMill ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.NeedMill = needMill; + } + + public void SetNeededExpansion( int index, Expansion expansion ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.RequiredExpansion = expansion; + } + + public void AddRes( int index, Type type, TextDefinition name, int amount ) + { + AddRes( index, type, name, amount, "" ); + } + + public void AddRes( int index, Type type, TextDefinition name, int amount, TextDefinition message ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.AddRes( type, name, amount, message ); + } + + public void AddSkill( int index, SkillName skillToMake, double minSkill, double maxSkill ) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.AddSkill(skillToMake, minSkill, maxSkill); + } + + public void SetUseSubRes2( int index, bool val ) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.UseSubRes2 = val; + } + + private void AddRecipeBase(int index, int id) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.AddRecipe(id, this); + } + + public void AddRecipe(int index, int id) + { + AddRecipeBase(index, id); + m_Recipes.Add(id); + } + + public void AddRareRecipe(int index, int id) + { + AddRecipeBase(index, id); + m_RareRecipes.Add(id); + } + + public void AddQuestRecipe(int index, int id) + { + AddRecipeBase(index, id); + } + + public void ForceNonExceptional( int index ) + { + CraftItem craftItem = m_CraftItems.GetAt( index ); + craftItem.ForceNonExceptional = true; + } + + //Plume : Ajout du Low + public void ForceNonLow(int index) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.ForceNonLow = true; + } + + public void MaxChance(int index, double max) + { + CraftItem craftItem = m_CraftItems.GetAt(index); + craftItem.TopChance = true; + craftItem.MaxChance = max; + } + + public void SetSubRes( Type type, string name ) + { + m_CraftSubRes.ResType = type; + m_CraftSubRes.NameString = name; + m_CraftSubRes.Init = true; + } + + public void SetSubRes( Type type, int name ) + { + m_CraftSubRes.ResType = type; + m_CraftSubRes.NameNumber = name; + m_CraftSubRes.Init = true; + } + + public void AddSubRes( Type type, int name, double reqSkill, object message ) + { + CraftSubRes craftSubRes = new CraftSubRes( type, name, reqSkill, message ); + m_CraftSubRes.Add( craftSubRes ); + } + + public void AddSubRes( Type type, int name, double reqSkill, int genericName, object message ) + { + CraftSubRes craftSubRes = new CraftSubRes( type, name, reqSkill, genericName, message ); + m_CraftSubRes.Add( craftSubRes ); + } + + public void AddSubRes( Type type, string name, double reqSkill, object message ) + { + CraftSubRes craftSubRes = new CraftSubRes( type, name, reqSkill, message ); + m_CraftSubRes.Add( craftSubRes ); + } + + + public void SetSubRes2( Type type, string name ) + { + m_CraftSubRes2.ResType = type; + m_CraftSubRes2.NameString = name; + m_CraftSubRes2.Init = true; + } + + public void SetSubRes2( Type type, int name ) + { + m_CraftSubRes2.ResType = type; + m_CraftSubRes2.NameNumber = name; + m_CraftSubRes2.Init = true; + } + + public void AddSubRes2( Type type, int name, double reqSkill, object message ) + { + CraftSubRes craftSubRes = new CraftSubRes( type, name, reqSkill, message ); + m_CraftSubRes2.Add( craftSubRes ); + } + + public void AddSubRes2( Type type, int name, double reqSkill, int genericName, object message ) + { + CraftSubRes craftSubRes = new CraftSubRes( type, name, reqSkill, genericName, message ); + m_CraftSubRes2.Add( craftSubRes ); + } + + public void AddSubRes2( Type type, string name, double reqSkill, object message ) + { + CraftSubRes craftSubRes = new CraftSubRes( type, name, reqSkill, message ); + m_CraftSubRes2.Add( craftSubRes ); + } + + public abstract void InitCraftList(); + + public abstract void PlayCraftEffect( Mobile from ); + public abstract int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ); + + public abstract int CanCraft( Mobile from, BaseTool tool, Type itemType ); + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/CustomCraft.cs b/Scripts/Engines/Craft/Core/CustomCraft.cs new file mode 100644 index 0000000..93c4aae --- /dev/null +++ b/Scripts/Engines/Craft/Core/CustomCraft.cs @@ -0,0 +1,36 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.Craft +{ + public abstract class CustomCraft + { + private Mobile m_From; + private CraftItem m_CraftItem; + private CraftSystem m_CraftSystem; + private Type m_TypeRes; + private BaseTool m_Tool; + private int m_Quality; + + public Mobile From{ get{ return m_From; } } + public CraftItem CraftItem{ get{ return m_CraftItem; } } + public CraftSystem CraftSystem{ get{ return m_CraftSystem; } } + public Type TypeRes{ get{ return m_TypeRes; } } + public BaseTool Tool{ get{ return m_Tool; } } + public int Quality{ get{ return m_Quality; } } + + public CustomCraft( Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool, int quality ) + { + m_From = from; + m_CraftItem = craftItem; + m_CraftSystem = craftSystem; + m_TypeRes = typeRes; + m_Tool = tool; + m_Quality = quality; + } + + public abstract void EndCraftAction(); + public abstract Item CompleteCraft( out int message ); + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/Enhance.cs b/Scripts/Engines/Craft/Core/Enhance.cs new file mode 100644 index 0000000..6e7a72b --- /dev/null +++ b/Scripts/Engines/Craft/Core/Enhance.cs @@ -0,0 +1,327 @@ +using System; +using Server; +using Server.Targeting; +using Server.Items; + +namespace Server.Engines.Craft +{ + public enum EnhanceResult + { + None, + NotInBackpack, + BadItem, + BadResource, + AlreadyEnhanced, + Success, + Failure, + Broken, + NoResources, + NoSkill + } + + public class Enhance + { + public static EnhanceResult Invoke( Mobile from, CraftSystem craftSystem, BaseTool tool, Item item, CraftResource resource, Type resType, ref object resMessage ) + { + if ( item == null ) + return EnhanceResult.BadItem; + + if ( !item.IsChildOf( from.Backpack ) ) + return EnhanceResult.NotInBackpack; + + if ( !(item is BaseArmor) && !(item is BaseWeapon) ) + return EnhanceResult.BadItem; + + if ( item is IArcaneEquip ) + { + IArcaneEquip eq = (IArcaneEquip)item; + if ( eq.IsArcane ) + return EnhanceResult.BadItem; + } + + if ( CraftResources.IsStandard( resource ) ) + return EnhanceResult.BadResource; + + int num = craftSystem.CanCraft( from, tool, item.GetType() ); + + if ( num > 0 ) + { + resMessage = num; + return EnhanceResult.None; + } + + CraftItem craftItem = craftSystem.CraftItems.SearchFor( item.GetType() ); + + if ( craftItem == null || craftItem.Resources.Count == 0 ) + return EnhanceResult.BadItem; + + bool allRequiredSkills = false; + if( craftItem.GetSuccessChance( from, resType, craftSystem, false, ref allRequiredSkills ) <= 0.0 ) + return EnhanceResult.NoSkill; + + CraftResourceInfo info = CraftResources.GetInfo( resource ); + + if ( info == null || info.ResourceTypes.Length == 0 ) + return EnhanceResult.BadResource; + + CraftAttributeInfo attributes = info.AttributeInfo; + + if ( attributes == null ) + return EnhanceResult.BadResource; + + int resHue = 0, maxAmount = 0; + + if ( !craftItem.ConsumeRes( from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.None, ref resMessage ) ) + return EnhanceResult.NoResources; + + if ( craftSystem is DefBlacksmithy ) + { + AncientSmithyHammer hammer = from.FindItemOnLayer( Layer.OneHanded ) as AncientSmithyHammer; + if ( hammer != null ) + { + hammer.UsesRemaining--; + if ( hammer.UsesRemaining < 1 ) + hammer.Delete(); + } + } + + int phys = 0, fire = 0, cold = 0, pois = 0, nrgy = 0; + int dura = 0, luck = 0, lreq = 0, dinc = 0; + int baseChance = 0; + + bool physBonus = false; + bool fireBonus = false; + bool coldBonus = false; + bool nrgyBonus = false; + bool poisBonus = false; + bool duraBonus = false; + bool luckBonus = false; + bool lreqBonus = false; + bool dincBonus = false; + + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( !CraftResources.IsStandard( weapon.Resource ) ) + return EnhanceResult.AlreadyEnhanced; + + baseChance = 20; + + dura = weapon.MaxHitPoints; + luck = weapon.Attributes.Luck; + lreq = weapon.WeaponAttributes.LowerStatReq; + dinc = weapon.Attributes.WeaponDamage; + + fireBonus = ( attributes.WeaponFireDamage > 0 ); + coldBonus = ( attributes.WeaponColdDamage > 0 ); + nrgyBonus = ( attributes.WeaponEnergyDamage > 0 ); + poisBonus = ( attributes.WeaponPoisonDamage > 0 ); + + duraBonus = ( attributes.WeaponDurability > 0 ); + luckBonus = ( attributes.WeaponLuck > 0 ); + lreqBonus = ( attributes.WeaponLowerRequirements > 0 ); + dincBonus = ( dinc > 0 ); + } + else + { + BaseArmor armor = (BaseArmor)item; + + if ( !CraftResources.IsStandard( armor.Resource ) ) + return EnhanceResult.AlreadyEnhanced; + + baseChance = 20; + + phys = armor.PhysicalResistance; + fire = armor.FireResistance; + cold = armor.ColdResistance; + pois = armor.PoisonResistance; + nrgy = armor.EnergyResistance; + + dura = armor.MaxHitPoints; + luck = armor.Attributes.Luck; + lreq = armor.ArmorAttributes.LowerStatReq; + + physBonus = ( attributes.ArmorPhysicalResist > 0 ); + fireBonus = ( attributes.ArmorFireResist > 0 ); + coldBonus = ( attributes.ArmorColdResist > 0 ); + nrgyBonus = ( attributes.ArmorEnergyResist > 0 ); + poisBonus = ( attributes.ArmorPoisonResist > 0 ); + + duraBonus = ( attributes.ArmorDurability > 0 ); + luckBonus = ( attributes.ArmorLuck > 0 ); + lreqBonus = ( attributes.ArmorLowerRequirements > 0 ); + dincBonus = false; + } + + int skill = from.Skills[craftSystem.MainSkill].Fixed / 10; + + if ( skill >= 100 ) + baseChance -= (skill - 90) / 10; + + EnhanceResult res = EnhanceResult.Success; + + if ( physBonus ) + CheckResult( ref res, baseChance + phys ); + + if ( fireBonus ) + CheckResult( ref res, baseChance + fire ); + + if ( coldBonus ) + CheckResult( ref res, baseChance + cold ); + + if ( nrgyBonus ) + CheckResult( ref res, baseChance + nrgy ); + + if ( poisBonus ) + CheckResult( ref res, baseChance + pois ); + + if ( duraBonus ) + CheckResult( ref res, baseChance + (dura / 40) ); + + if ( luckBonus ) + CheckResult( ref res, baseChance + 10 + (luck / 2) ); + + if ( lreqBonus ) + CheckResult( ref res, baseChance + (lreq / 4) ); + + if ( dincBonus ) + CheckResult( ref res, baseChance + (dinc / 4) ); + + switch ( res ) + { + case EnhanceResult.Broken: + { + if ( !craftItem.ConsumeRes( from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.Half, ref resMessage ) ) + return EnhanceResult.NoResources; + + item.Delete(); + break; + } + case EnhanceResult.Success: + { + if ( !craftItem.ConsumeRes( from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.All, ref resMessage ) ) + return EnhanceResult.NoResources; + + if( item is BaseWeapon ) + { + BaseWeapon w = (BaseWeapon)item; + + w.Resource = resource; + + int hue = w.GetElementalDamageHue(); + if( hue > 0 ) + w.Hue = hue; + } + else if( item is BaseArmor ) //Sanity + { + ((BaseArmor)item).Resource = resource; + } + + break; + } + case EnhanceResult.Failure: + { + if ( !craftItem.ConsumeRes( from, resType, craftSystem, ref resHue, ref maxAmount, ConsumeType.Half, ref resMessage ) ) + return EnhanceResult.NoResources; + + break; + } + } + + return res; + } + + public static void CheckResult( ref EnhanceResult res, int chance ) + { + if ( res != EnhanceResult.Success ) + return; // we've already failed.. + + int random = Utility.Random( 100 ); + + if ( 10 > random ) + res = EnhanceResult.Failure; + else if ( chance > random ) + res = EnhanceResult.Broken; + } + + public static void BeginTarget( Mobile from, CraftSystem craftSystem, BaseTool tool ) + { + CraftContext context = craftSystem.GetContext( from ); + + if ( context == null ) + return; + + int lastRes = context.LastResourceIndex; + CraftSubResCol subRes = craftSystem.CraftSubRes; + + if ( lastRes >= 0 && lastRes < subRes.Count ) + { + CraftSubRes res = subRes.GetAt( lastRes ); + + if ( from.Skills[craftSystem.MainSkill].Value < res.RequiredSkill ) + { + from.SendGump( new CraftGump( from, craftSystem, tool, res.Message ) ); + } + else + { + CraftResource resource = CraftResources.GetFromType( res.ItemType ); + + if ( resource != CraftResource.None ) + { + from.Target = new InternalTarget( craftSystem, tool, res.ItemType, resource ); + from.SendLocalizedMessage( 1061004 ); // Target an item to enhance with the properties of your selected material. + } + else + { + from.SendGump( new CraftGump( from, craftSystem, tool, 1061010 ) ); // You must select a special material in order to enhance an item with its properties. + } + } + } + else + { + from.SendGump( new CraftGump( from, craftSystem, tool, 1061010 ) ); // You must select a special material in order to enhance an item with its properties. + } + + } + + private class InternalTarget : Target + { + private CraftSystem m_CraftSystem; + private BaseTool m_Tool; + private Type m_ResourceType; + private CraftResource m_Resource; + + public InternalTarget( CraftSystem craftSystem, BaseTool tool, Type resourceType, CraftResource resource ) : base ( 2, false, TargetFlags.None ) + { + m_CraftSystem = craftSystem; + m_Tool = tool; + m_ResourceType = resourceType; + m_Resource = resource; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Item ) + { + object message = null; + EnhanceResult res = Enhance.Invoke( from, m_CraftSystem, m_Tool, (Item)targeted, m_Resource, m_ResourceType, ref message ); + + switch ( res ) + { + case EnhanceResult.NotInBackpack: message = 1061005; break; // The item must be in your backpack to enhance it. + case EnhanceResult.AlreadyEnhanced: message = 1061012; break; // This item is already enhanced with the properties of a special material. + case EnhanceResult.BadItem: message = 1061011; break; // You cannot enhance this type of item with the properties of the selected special material. + case EnhanceResult.BadResource: message = 1061010; break; // You must select a special material in order to enhance an item with its properties. + case EnhanceResult.Broken: message = 1061080; break; // You attempt to enhance the item, but fail catastrophically. The item is lost. + case EnhanceResult.Failure: message = 1061082; break; // You attempt to enhance the item, but fail. Some material is lost in the process. + case EnhanceResult.Success: message = 1061008; break; // You enhance the item with the properties of the special material. + case EnhanceResult.NoSkill: message = 1044153; break; // You don't have the required skills to attempt this item. + } + + from.SendGump( new CraftGump( from, m_CraftSystem, m_Tool, message ) ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/QueryMakersMarkGump.cs b/Scripts/Engines/Craft/Core/QueryMakersMarkGump.cs new file mode 100644 index 0000000..e73ac39 --- /dev/null +++ b/Scripts/Engines/Craft/Core/QueryMakersMarkGump.cs @@ -0,0 +1,54 @@ +using System; +using Server; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class QueryMakersMarkGump : Gump + { + private int m_Quality; + private Mobile m_From; + private CraftItem m_CraftItem; + private CraftSystem m_CraftSystem; + private Type m_TypeRes; + private BaseTool m_Tool; + + public QueryMakersMarkGump( int quality, Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool ) : base( 100, 200 ) + { + from.CloseGump( typeof( QueryMakersMarkGump ) ); + + m_Quality = quality; + m_From = from; + m_CraftItem = craftItem; + m_CraftSystem = craftSystem; + m_TypeRes = typeRes; + m_Tool = tool; + + AddPage( 0 ); + + AddBackground( 0, 0, 220, 170, 5054 ); + AddBackground( 10, 10, 200, 150, 3000 ); + + AddHtmlLocalized( 20, 20, 180, 80, 1018317, false, false ); // Do you wish to place your maker's mark on this item? + + AddHtmlLocalized( 55, 100, 140, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 100, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 125, 140, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 125, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + bool makersMark = ( info.ButtonID == 1 ); + + if ( makersMark ) + m_From.SendLocalizedMessage( 501808 ); // You mark the item. + else + m_From.SendLocalizedMessage( 501809 ); // Cancelled mark. + + m_CraftItem.CompleteCraft( m_Quality, makersMark, m_From, m_CraftSystem, m_TypeRes, m_Tool, null ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/Recipes.cs b/Scripts/Engines/Craft/Core/Recipes.cs new file mode 100644 index 0000000..b34d152 --- /dev/null +++ b/Scripts/Engines/Craft/Core/Recipes.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Commands; + +namespace Server.Engines.Craft +{ + public class Recipe + { + public static void Initialize() + { + CommandSystem.Register( "LearnAllRecipes", AccessLevel.GameMaster, new CommandEventHandler( LearnAllRecipes_OnCommand ) ); + CommandSystem.Register( "ForgetAllRecipes", AccessLevel.GameMaster, new CommandEventHandler( ForgetAllRecipes_OnCommand ) ); + } + + [Usage( "LearnAllRecipes" )] + [Description( "Teaches a player all available recipes." )] + private static void LearnAllRecipes_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + m.SendMessage( "Target a player to teach them all of the recipies." ); + + m.BeginTarget( -1, false, Server.Targeting.TargetFlags.None, new TargetCallback( + delegate( Mobile from, object targeted ) + { + if( targeted is PlayerMobile ) + { + foreach( KeyValuePair kvp in m_Recipes ) + ((PlayerMobile)targeted).AcquireRecipe( kvp.Key ); + + m.SendMessage( "You teach them all of the recipies." ); + } + else + { + m.SendMessage( "That is not a player!" ); + } + } + ) ); + } + + [Usage( "ForgetAllRecipes" )] + [Description( "Makes a player forget all the recipies they've learned." )] + private static void ForgetAllRecipes_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + m.SendMessage( "Target a player to have them forget all of the recipies they've learned." ); + + m.BeginTarget( -1, false, Server.Targeting.TargetFlags.None, new TargetCallback( + delegate( Mobile from, object targeted ) + { + if( targeted is PlayerMobile ) + { + ((PlayerMobile)targeted).ResetRecipes(); + + m.SendMessage( "They forget all their recipies." ); + } + else + { + m.SendMessage( "That is not a player!" ); + } + } + ) ); + } + + + private static Dictionary m_Recipes = new Dictionary(); + + public static Dictionary Recipes { get { return m_Recipes; } } + + private static int m_LargestRecipeID; + public static int LargestRecipeID{ get{ return m_LargestRecipeID; } } + + private CraftSystem m_System; + + public CraftSystem CraftSystem + { + get { return m_System; } + set { m_System = value; } + } + + private CraftItem m_CraftItem; + + public CraftItem CraftItem + { + get { return m_CraftItem; } + set { m_CraftItem = value; } + } + + private int m_ID; + + public int ID + { + get { return m_ID; } + } + + private TextDefinition m_TD; + public TextDefinition TextDefinition + { + get + { + if( m_TD == null ) + m_TD = new TextDefinition( m_CraftItem.NameNumber, m_CraftItem.NameString ); + + return m_TD; + } + } + + public Recipe( int id, CraftSystem system, CraftItem item ) + { + m_ID = id; + m_System = system; + m_CraftItem = item; + + if( m_Recipes.ContainsKey( id ) ) + throw new Exception( "Attempting to create recipe with preexisting ID." ); + + m_Recipes.Add( id, this ); + m_LargestRecipeID = Math.Max( id, m_LargestRecipeID ); + } + } +} diff --git a/Scripts/Engines/Craft/Core/Repair.cs b/Scripts/Engines/Craft/Core/Repair.cs new file mode 100644 index 0000000..848eb33 --- /dev/null +++ b/Scripts/Engines/Craft/Core/Repair.cs @@ -0,0 +1,515 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class Repair + { + public Repair() + { + } + + public static void Do( Mobile from, CraftSystem craftSystem, BaseTool tool ) + { + from.Target = new InternalTarget( craftSystem, tool ); + from.SendLocalizedMessage( 1044276 ); // Target an item to repair. + } + + public static void Do( Mobile from, CraftSystem craftSystem, RepairDeed deed ) + { + from.Target = new InternalTarget( craftSystem, deed ); + from.SendLocalizedMessage( 1044276 ); // Target an item to repair. + } + + private class InternalTarget : Target + { + private CraftSystem m_CraftSystem; + private BaseTool m_Tool; + private RepairDeed m_Deed; + + public InternalTarget( CraftSystem craftSystem, BaseTool tool ) : base ( 2, false, TargetFlags.None ) + { + m_CraftSystem = craftSystem; + m_Tool = tool; + } + + public InternalTarget( CraftSystem craftSystem, RepairDeed deed ) : base( 2, false, TargetFlags.None ) + { + m_CraftSystem = craftSystem; + m_Deed = deed; + } + + private static void EndGolemRepair( object state ) + { + ((Mobile)state).EndAction( typeof( Golem ) ); + } + + private int GetWeakenChance( Mobile mob, SkillName skill, int curHits, int maxHits ) + { + // 40% - (1% per hp lost) - (1% per 10 craft skill) + return (40 + (maxHits - curHits)) - (int)(((m_Deed != null)? m_Deed.SkillLevel : mob.Skills[skill].Value) / 10); + } + + private bool CheckWeaken( Mobile mob, SkillName skill, int curHits, int maxHits ) + { + return ( GetWeakenChance( mob, skill, curHits, maxHits ) > Utility.Random( 100 ) ); + } + + private int GetRepairDifficulty( int curHits, int maxHits ) + { + return (((maxHits - curHits) * 1250) / Math.Max( maxHits, 1 )) - 250; + } + + private bool CheckRepairDifficulty( Mobile mob, SkillName skill, int curHits, int maxHits ) + { + double difficulty = GetRepairDifficulty( curHits, maxHits ) * 0.1; + + + if( m_Deed != null ) + { + double value = m_Deed.SkillLevel; + double minSkill = difficulty - 25.0; + double maxSkill = difficulty + 25; + + if( value < minSkill ) + return false; // Too difficult + else if( value >= maxSkill ) + return true; // No challenge + + double chance = (value - minSkill) / (maxSkill - minSkill); + + return (chance >= Utility.RandomDouble()); + } + else + { + return mob.CheckSkill( skill, difficulty - 25.0, difficulty + 25.0 ); + } + } + + private bool CheckDeed( Mobile from ) + { + if( m_Deed != null ) + { + return m_Deed.Check( from ); + } + + return true; + } + + private bool IsSpecialClothing( BaseClothing clothing ) + { + // Clothing repairable but not craftable + + if( m_CraftSystem is DefTailoring ) + { + return (clothing is BearMask) + || (clothing is DeerMask); + } + + return false; + } + + private bool IsSpecialWeapon( BaseWeapon weapon ) + { + // Weapons repairable but not craftable + + if ( m_CraftSystem is DefTinkering ) + { + return ( weapon is Cleaver ) + || ( weapon is Hatchet ) + || ( weapon is Pickaxe ) + || ( weapon is ButcherKnife ) + || ( weapon is SkinningKnife ); + } + else if ( m_CraftSystem is DefCarpentry ) + { + return ( weapon is Club ) + || ( weapon is BlackStaff ) + || ( weapon is MagicWand ) + #region Temporary + // TODO: Make these items craftable + || (weapon is WildStaff); + #endregion + } + else if ( m_CraftSystem is DefBlacksmithy ) + { + return (weapon is Pitchfork) + #region Temporary + // TODO: Make these items craftable + || (weapon is RadiantScimitar) + || (weapon is WarCleaver) + || (weapon is ElvenSpellblade) + || (weapon is AssassinSpike) + || (weapon is Leafblade) + || (weapon is RuneBlade) + || (weapon is ElvenMachete) + || (weapon is OrnateAxe) + || (weapon is DiamondMace); + #endregion + } + + #region Temporary + // TODO: Make these items craftable + else if (m_CraftSystem is DefBowFletching) + { + return (weapon is ElvenCompositeLongbow) + || (weapon is MagicalShortbow); + } + #endregion + + return false; + } + + private bool IsSpecialArmor(BaseArmor armor) + { + // Armor repairable but not craftable + + #region Temporary + // TODO: Make these items craftable + if (m_CraftSystem is DefTailoring) + { + return (armor is LeafTonlet) + || (armor is LeafArms) + || (armor is LeafChest) + || (armor is LeafGloves) + || (armor is LeafGorget) + || (armor is LeafLegs) + || (armor is HideChest) + || (armor is HideGloves) + || (armor is HideGorget) + || (armor is HidePants) + || (armor is HidePauldrons); + } + else if (m_CraftSystem is DefCarpentry) + { + return (armor is WingedHelm) + || (armor is RavenHelm) + || (armor is VultureHelm) + || (armor is WoodlandArms) + || (armor is WoodlandChest) + || (armor is WoodlandGloves) + || (armor is WoodlandGorget) + || (armor is WoodlandLegs); + } + else if (m_CraftSystem is DefBlacksmithy) + { + return (armor is Circlet) + || (armor is RoyalCirclet) + || (armor is GemmedCirclet); + } + #endregion + + return false; + } + + + protected override void OnTarget( Mobile from, object targeted ) + { + int number; + + if( !CheckDeed( from ) ) + return; + + + bool usingDeed = (m_Deed != null); + bool toDelete = false; + + // TODO: Make an IRepairable + + if ( m_CraftSystem.CanCraft( from, m_Tool, targeted.GetType() ) == 1044267 ) + { + number = 1044282; // You must be near a forge and and anvil to repair items. * Yes, there are two and's * + } + else if ( m_CraftSystem is DefTinkering && targeted is Golem ) + { + Golem g = (Golem)targeted; + int damage = g.HitsMax - g.Hits; + + if ( g.IsDeadBondedPet ) + { + number = 500426; // You can't repair that. + } + else if ( damage <= 0 ) + { + number = 500423; // That is already in full repair. + } + else + { + double skillValue = (usingDeed)? m_Deed.SkillLevel : from.Skills[SkillName.Tinkering].Value; + + if ( skillValue < 60.0 ) + { + number = 1044153; // You don't have the required skills to attempt this item. //TODO: How does OSI handle this with deeds with golems? + } + else if ( !from.CanBeginAction( typeof( Golem ) ) ) + { + number = 501789; // You must wait before trying again. + } + else + { + if ( damage > (int)(skillValue * 0.3) ) + damage = (int)(skillValue * 0.3); + + damage += 30; + + if ( !from.CheckSkill( SkillName.Tinkering, 0.0, 100.0 ) ) + damage /= 2; + + Container pack = from.Backpack; + + if ( pack != null ) + { + int v = pack.ConsumeUpTo( typeof( IronIngot ), (damage+4)/5 ); + + if ( v > 0 ) + { + g.Hits += v*5; + + number = 1044279; // You repair the item. + toDelete = true; + + from.BeginAction( typeof( Golem ) ); + Timer.DelayCall( TimeSpan.FromSeconds( 12.0 ), new TimerStateCallback( EndGolemRepair ), from ); + } + else + { + number = 1044037; // You do not have sufficient metal to make that. + } + } + else + { + number = 1044037; // You do not have sufficient metal to make that. + } + } + } + } + else if ( targeted is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)targeted; + SkillName skill = m_CraftSystem.MainSkill; + int toWeaken = 0; + + if ( Core.AOS ) + { + toWeaken = 1; + } + else if ( skill != SkillName.Tailoring ) + { + double skillLevel = (usingDeed)? m_Deed.SkillLevel : from.Skills[skill].Base; + + if ( skillLevel >= 90.0 ) + toWeaken = 1; + else if ( skillLevel >= 70.0 ) + toWeaken = 2; + else + toWeaken = 3; + } + + if ( m_CraftSystem.CraftItems.SearchForSubclass( weapon.GetType() ) == null && !IsSpecialWeapon( weapon ) ) + { + number = (usingDeed)? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. + } + else if (!weapon.IsChildOf(from.Backpack) && (!Core.ML || weapon.Parent != from)) + { + number = 1044275; // The item must be in your backpack to repair it. + } + else if (!Core.AOS && weapon.PoisonCharges != 0) + { + number = 1005012; // You cannot repair an item while a caustic substance is on it. + } + else if ( weapon.MaxHitPoints <= 0 || weapon.HitPoints == weapon.MaxHitPoints ) + { + number = 1044281; // That item is in full repair + } + else if ( weapon.MaxHitPoints <= toWeaken ) + { + number = 1044278; // That item has been repaired many times, and will break if repairs are attempted again. + } + else + { + if ( CheckWeaken( from, skill, weapon.HitPoints, weapon.MaxHitPoints ) ) + { + weapon.MaxHitPoints -= toWeaken; + weapon.HitPoints = Math.Max( 0, weapon.HitPoints - toWeaken ); + } + + if ( CheckRepairDifficulty( from, skill, weapon.HitPoints, weapon.MaxHitPoints ) ) + { + number = 1044279; // You repair the item. + m_CraftSystem.PlayCraftEffect( from ); + weapon.HitPoints = weapon.MaxHitPoints; + } + else + { + number = (usingDeed)? 1061137 : 1044280; // You fail to repair the item. [And the contract is destroyed] + m_CraftSystem.PlayCraftEffect( from ); + } + + toDelete = true; + } + } + else if ( targeted is BaseArmor ) + { + BaseArmor armor = (BaseArmor)targeted; + SkillName skill = m_CraftSystem.MainSkill; + int toWeaken = 0; + + if ( Core.AOS ) + { + toWeaken = 1; + } + else if ( skill != SkillName.Tailoring ) + { + double skillLevel = (usingDeed)? m_Deed.SkillLevel : from.Skills[skill].Base; + + if ( skillLevel >= 90.0 ) + toWeaken = 1; + else if ( skillLevel >= 70.0 ) + toWeaken = 2; + else + toWeaken = 3; + } + + if (m_CraftSystem.CraftItems.SearchForSubclass(armor.GetType()) == null && !IsSpecialArmor(armor)) + { + number = (usingDeed) ? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. + } + else if (!armor.IsChildOf(from.Backpack) && (!Core.ML || armor.Parent != from)) + { + number = 1044275; // The item must be in your backpack to repair it. + } + else if ( armor.MaxHitPoints <= 0 || armor.HitPoints == armor.MaxHitPoints ) + { + number = 1044281; // That item is in full repair + } + else if ( armor.MaxHitPoints <= toWeaken ) + { + number = 1044278; // That item has been repaired many times, and will break if repairs are attempted again. + } + else + { + if ( CheckWeaken( from, skill, armor.HitPoints, armor.MaxHitPoints ) ) + { + armor.MaxHitPoints -= toWeaken; + armor.HitPoints = Math.Max( 0, armor.HitPoints - toWeaken ); + } + + if ( CheckRepairDifficulty( from, skill, armor.HitPoints, armor.MaxHitPoints ) ) + { + number = 1044279; // You repair the item. + m_CraftSystem.PlayCraftEffect( from ); + armor.HitPoints = armor.MaxHitPoints; + } + else + { + number = (usingDeed)? 1061137 : 1044280; // You fail to repair the item. [And the contract is destroyed] + m_CraftSystem.PlayCraftEffect( from ); + } + + toDelete = true; + } + } + else if ( targeted is BaseClothing ) + { + BaseClothing clothing = (BaseClothing)targeted; + SkillName skill = m_CraftSystem.MainSkill; + int toWeaken = 0; + + if ( Core.AOS ) + { + toWeaken = 1; + } + else if ( skill != SkillName.Tailoring ) + { + double skillLevel = (usingDeed) ? m_Deed.SkillLevel : from.Skills[skill].Base; + + if ( skillLevel >= 90.0 ) + toWeaken = 1; + else if ( skillLevel >= 70.0 ) + toWeaken = 2; + else + toWeaken = 3; + } + + if (m_CraftSystem.CraftItems.SearchForSubclass(clothing.GetType()) == null && !IsSpecialClothing(clothing) && !((targeted is TribalMask) || (targeted is HornedTribalMask)) ) + { + number = (usingDeed) ? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. + } + else if (!clothing.IsChildOf(from.Backpack) && (!Core.ML || clothing.Parent != from)) + { + number = 1044275; // The item must be in your backpack to repair it. + } + else if ( clothing.MaxHitPoints <= 0 || clothing.HitPoints == clothing.MaxHitPoints ) + { + number = 1044281; // That item is in full repair + } + else if ( clothing.MaxHitPoints <= toWeaken ) + { + number = 1044278; // That item has been repaired many times, and will break if repairs are attempted again. + } + else + { + if ( CheckWeaken( from, skill, clothing.HitPoints, clothing.MaxHitPoints ) ) + { + clothing.MaxHitPoints -= toWeaken; + clothing.HitPoints = Math.Max( 0, clothing.HitPoints - toWeaken ); + } + + if ( CheckRepairDifficulty( from, skill, clothing.HitPoints, clothing.MaxHitPoints ) ) + { + number = 1044279; // You repair the item. + m_CraftSystem.PlayCraftEffect( from ); + clothing.HitPoints = clothing.MaxHitPoints; + } + else + { + number = (usingDeed) ? 1061137 : 1044280; // You fail to repair the item. [And the contract is destroyed] + m_CraftSystem.PlayCraftEffect( from ); + } + + toDelete = true; + } + } + else if( !usingDeed && targeted is BlankScroll ) + { + SkillName skill = m_CraftSystem.MainSkill; + + if( from.Skills[skill].Value >= 50.0 ) + { + ((BlankScroll)targeted).Consume( 1 ); + RepairDeed deed = new RepairDeed( RepairDeed.GetTypeFor( m_CraftSystem ), from.Skills[skill].Value, from ); + from.AddToBackpack( deed ); + + number = 500442; // You create the item and put it in your backpack. + } + else + number = 1047005; // You must be at least apprentice level to create a repair service contract. + } + else if ( targeted is Item ) + { + number = (usingDeed)? 1061136 : 1044277; // That item cannot be repaired. // You cannot repair that item with this type of repair contract. + } + else + { + number = 500426; // You can't repair that. + } + + if( !usingDeed ) + { + CraftContext context = m_CraftSystem.GetContext( from ); + from.SendGump( new CraftGump( from, m_CraftSystem, m_Tool, number ) ); + } + else + { + from.SendLocalizedMessage(number); + + if (toDelete) + m_Deed.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/Core/Resmelt.cs b/Scripts/Engines/Craft/Core/Resmelt.cs new file mode 100644 index 0000000..584be94 --- /dev/null +++ b/Scripts/Engines/Craft/Core/Resmelt.cs @@ -0,0 +1,187 @@ +using System; +using Server; +using Server.Targeting; +using Server.Items; + +namespace Server.Engines.Craft +{ + public enum SmeltResult + { + Success, + Invalid, + NoSkill + } + + public class Resmelt + { + public Resmelt() + { + } + + public static void Do( Mobile from, CraftSystem craftSystem, BaseTool tool ) + { + int num = craftSystem.CanCraft( from, tool, null ); + + if ( num > 0 && num != 1044267 ) + { + from.SendGump( new CraftGump( from, craftSystem, tool, num ) ); + } + else + { + from.Target = new InternalTarget( craftSystem, tool ); + from.SendLocalizedMessage( 1044273 ); // Target an item to recycle. + } + } + + private class InternalTarget : Target + { + private CraftSystem m_CraftSystem; + private BaseTool m_Tool; + + public InternalTarget( CraftSystem craftSystem, BaseTool tool ) : base ( 2, false, TargetFlags.None ) + { + m_CraftSystem = craftSystem; + m_Tool = tool; + } + + private SmeltResult Resmelt( Mobile from, Item item, CraftResource resource ) + { + try + { + if (Ethics.Ethic.IsImbued(item)) + return SmeltResult.Invalid; + + if ( CraftResources.GetType( resource ) != CraftResourceType.Metal ) + return SmeltResult.Invalid; + + CraftResourceInfo info = CraftResources.GetInfo( resource ); + + if ( info == null || info.ResourceTypes.Length == 0 ) + return SmeltResult.Invalid; + + CraftItem craftItem = m_CraftSystem.CraftItems.SearchFor( item.GetType() ); + + if ( craftItem == null || craftItem.Resources.Count == 0 ) + return SmeltResult.Invalid; + + CraftRes craftResource = craftItem.Resources.GetAt( 0 ); + + if ( craftResource.Amount < 2 ) + return SmeltResult.Invalid; // Not enough metal to resmelt + + double difficulty = 0.0; + + switch ( resource ) + { + case CraftResource.MRusty: difficulty = 50.0; break; + case CraftResource.MOldcopper: difficulty = 60.0; break; + case CraftResource.MDullcopper: difficulty = 65.0; break; + case CraftResource.MShadow: difficulty = 70.0; break; + case CraftResource.MCopper: difficulty = 75.0; break; + case CraftResource.MBronze: difficulty = 80.0; break; + case CraftResource.MGold: difficulty = 85.0; break; + case CraftResource.MRose: difficulty = 87.0; break; + case CraftResource.MAgapite: difficulty = 90.0; break; + case CraftResource.MValorite: difficulty = 90.0; break; + case CraftResource.MBloodrock: difficulty = 93.0; break; + case CraftResource.MVerite: difficulty = 95.0; break; + case CraftResource.MSilver: difficulty = 95.0; break; + case CraftResource.MDragon: difficulty = 95.0; break; + case CraftResource.MTitan: difficulty = 95.0; break; + case CraftResource.MCrystaline: difficulty = 95.0; break; + case CraftResource.MKrynite: difficulty = 95.0; break; + case CraftResource.MVulcan: difficulty = 95.0; break; + case CraftResource.MBloodcrest: difficulty = 95.0; break; + case CraftResource.MElvin: difficulty = 95.0; break; + case CraftResource.MAcid: difficulty = 95.0; break; + case CraftResource.MAqua: difficulty = 95.0; break; + case CraftResource.MEldar: difficulty = 95.0; break; + case CraftResource.MGlowing: difficulty = 95.0; break; + case CraftResource.MGorgan: difficulty = 95.0; break; + case CraftResource.MSteel: difficulty = 95.5; break; + case CraftResource.MSandrock: difficulty = 95.0; break; + case CraftResource.MMytheril: difficulty = 97.5; break; + case CraftResource.MBlackrock: difficulty = 98.0; break; + } + + if ( difficulty > from.Skills[ SkillName.Mining ].Value ) + return SmeltResult.NoSkill; + + Type resourceType = info.ResourceTypes[0]; + Item ingot = (Item)Activator.CreateInstance( resourceType ); + + if ( item is DragonBardingDeed || (item is BaseArmor && ((BaseArmor)item).PlayerConstructed) || (item is BaseWeapon && ((BaseWeapon)item).PlayerConstructed) || (item is BaseClothing && ((BaseClothing)item).PlayerConstructed) ) + ingot.Amount = craftResource.Amount / 2; + else + ingot.Amount = 1; + + item.Delete(); + from.AddToBackpack( ingot ); + + from.PlaySound( 0x2A ); + from.PlaySound( 0x240 ); + return SmeltResult.Success; + } + catch + { + } + + return SmeltResult.Invalid; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + int num = m_CraftSystem.CanCraft( from, m_Tool, null ); + + if ( num > 0 ) + { + if ( num == 1044267 ) + { + bool anvil, forge; + + DefBlacksmithy.CheckAnvilAndForge( from, 2, out anvil, out forge ); + + if ( !anvil ) + num = 1044266; // You must be near an anvil + else if ( !forge ) + num = 1044265; // You must be near a forge. + } + + from.SendGump( new CraftGump( from, m_CraftSystem, m_Tool, num ) ); + } + else + { + SmeltResult result = SmeltResult.Invalid; + bool isStoreBought = false; + int message; + + if ( targeted is BaseArmor ) + { + result = Resmelt( from, (BaseArmor)targeted, ((BaseArmor)targeted).Resource ); + isStoreBought = !((BaseArmor)targeted).PlayerConstructed; + } + else if ( targeted is BaseWeapon ) + { + result = Resmelt( from, (BaseWeapon)targeted, ((BaseWeapon)targeted).Resource ); + isStoreBought = !((BaseWeapon)targeted).PlayerConstructed; + } + else if ( targeted is DragonBardingDeed ) + { + result = Resmelt( from, (DragonBardingDeed)targeted, ((DragonBardingDeed)targeted).Resource ); + isStoreBought = false; + } + + switch ( result ) + { + default: + case SmeltResult.Invalid: message = 1044272; break; // You can't melt that down into ingots. + case SmeltResult.NoSkill: message = 1044269; break; // You have no idea how to work this metal. + case SmeltResult.Success: message = isStoreBought ? 500418 : 1044270; break; // You melt the item down into ingots. + } + + from.SendGump( new CraftGump( from, m_CraftSystem, m_Tool, message ) ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefAlchemy.cs b/Scripts/Engines/Craft/DefAlchemy.cs new file mode 100644 index 0000000..3e263c3 --- /dev/null +++ b/Scripts/Engines/Craft/DefAlchemy.cs @@ -0,0 +1,261 @@ +using System; +using Server.Items; +using Server.Engines.Plants; +using Xanthos.ShrinkSystem; + +namespace Server.Engines.Craft +{ + public class DefAlchemy : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Alchemy; } + } + + public override int GumpTitleNumber + { + get { return 1044001; } //
ALCHEMY MENU
p + } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefAlchemy(); + + return m_CraftSystem; + } + } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.0; // 0% + } + + private DefAlchemy() : base( 1, 1, 1.25 )// base( 1, 1, 3.1 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + public override void PlayCraftEffect( Mobile from ) + { + from.PlaySound( 0x242 ); + } + + private static Type typeofPotion = typeof( BasePotion ); + + public static bool IsPotion( Type type ) + { + return typeofPotion.IsAssignableFrom( type ); + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( IsPotion( item.ItemType ) ) + { + from.AddToBackpack( new Bottle() ); + return 500287; // You fail to create a useful potion. + } + else + { + return 1044043; // You failed to create the item, and some of your materials are lost. + } + } + else + { + from.PlaySound( 0x240 ); // Sound of a filling bottle + + if ( IsPotion( item.ItemType ) ) + { + if ( quality == -1 ) + return 1048136; // You create the potion and pour it into a keg. + else + return 500279; // You pour the potion into a bottle... + } + else + { + return 1044154; // You create the item. + } + } + } + + public override void InitCraftList() + { + int index = -1; + + // Nightsight Potion + index = AddCraft(typeof(NightSightPotion), "Alt�rations", 1044542, -25.0, 25.0, typeof(SpidersSilk), 1044360, 1, 1044368); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + index = AddCraft(typeof(FrogMorphPotion), "Alt�rations", "Filtre d'amour", 50.0, 87.0, typeof(MorphBase), "Base de m�tamorphose", 1, "Il vous faut une base de m�tamorphose"); + AddRes(index, typeof(BullFrogLard), "Du gras de grenouille", 2, "Il vous faut une base grasse pour cette potion"); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + index = AddCraft(typeof(InvisibilityPotion), "Alt�ration", "Potion d'invisibilit�", 70.0, 110.00, typeof(Bloodmoss), 1044354, 5, 1044362); + AddRes(index, typeof(Nightshade), 1044358, 4, 1044366); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + index = AddCraft(typeof(HallucinogenPotion), "Alt�ration", "Potion d'hallucinations", 75.0, 120.00, typeof(HallucinogenMushroom), 1044354, 4, "Vous n'avez pas assez de champignons"); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + + // Agility Potion + index = AddCraft( typeof( AgilityPotion ), "B�n�fiques", 1044540, 15.0, 65.0, typeof( Bloodmoss ), 1044354, 1, 1044362 ); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + index = AddCraft(typeof(GreaterAgilityPotion), "B�n�fiques", 1044541, 35.0, 85.0, typeof(Bloodmoss), 1044354, 3, 1044362); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + + // Strength Potion + index = AddCraft(typeof(StrengthPotion), "B�n�fiques", 1044546, 25.0, 75.0, typeof(MandrakeRoot), 1044357, 2, 1044365); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(GreaterStrengthPotion), "B�n�fiques", 1044547, 45.0, 95.0, typeof(MandrakeRoot), 1044357, 5, 1044365); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + + + // Explosion Potion + index = AddCraft(typeof(LesserExplosionPotion), "Lancer", 1044555, 5.0, 55.0, typeof(SulfurousAsh), 1044359, 3, 1044367); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(ExplosionPotion), "Lancer", 1044556, 35.0, 85.0, typeof(SulfurousAsh), 1044359, 5, 1044367); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(GreaterExplosionPotion), "Lancer", 1044557, 65.0, 115.0, typeof(SulfurousAsh), 1044359, 10, 1044367); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + if (Core.SE) + { + index = AddCraft(typeof(SmokeBomb), "Lancer", 1030248, 90.0, 120.0, typeof(Eggs), 1044477, 1, 1044253); + AddRes(index, typeof(Ginseng), 1044356, 3, 1044364); + SetNeededExpansion(index, Expansion.SE); + + // Conflagration Potions + index = AddCraft(typeof(ConflagrationPotion), "Lancer", 1072096, 55.0, 105.0, typeof(GraveDust), 1023983, 5, 1044253); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + SetNeededExpansion(index, Expansion.SE); + index = AddCraft(typeof(GreaterConflagrationPotion), "Lancer", 1072099, 65.0, 115.0, typeof(GraveDust), 1023983, 10, 1044253); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + SetNeededExpansion(index, Expansion.SE); + // Confusion Blast Potions + index = AddCraft(typeof(ConfusionBlastPotion), "Lancer", 1072106, 55.0, 105.0, typeof(PigIron), 1023978, 5, 1044253); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + SetNeededExpansion(index, Expansion.SE); + index = AddCraft(typeof(GreaterConfusionBlastPotion), "Lancer", 1072109, 65.0, 115.0, typeof(PigIron), 1023978, 10, 1044253); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + SetNeededExpansion(index, Expansion.SE); + } + + + // Poison Potion + index = AddCraft(typeof(LesserPoisonPotion), "Poisons", 1044548, -5.0, 45.0, typeof(Nightshade), 1044358, 1, 1044366); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(PoisonPotion), "Poisons", 1044549, 15.0, 65.0, typeof(Nightshade), 1044358, 2, 1044366); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(GreaterPoisonPotion), "Poisons", 1044550, 55.0, 105.0, typeof(Nightshade), 1044358, 4, 1044366); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(DeadlyPoisonPotion), "Poisons", 1044551, 90.0, 140.0, typeof(Nightshade), 1044358, 8, 1044366); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(ParasiticPotion), "Poisons", "Parasitic Potion", 65.0, 105.0, typeof(ParasiticPlant), "Plantes parasites", 4, "Vous n'avez pas assez de plantes parasites"); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(DarkglowPotion), "Poisons", "Darkglow Potion", 65.0, 105.0, typeof(LuminescentFungi), "Fongiques luminescents", 5, "Vous n'avez pas assez de champignons"); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + // Heal Potion + index = AddCraft( typeof( LesserHealPotion ), "Soins", 1044543, -25.0, 25.0, typeof( Ginseng ), 1044356, 1, 1044364 ); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + index = AddCraft(typeof(HealPotion), "Soins", 1044544, 15.0, 65.0, typeof(Ginseng), 1044356, 3, 1044364); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + index = AddCraft(typeof(GreaterHealPotion), "Soins", 1044545, 55.0, 105.0, typeof(Ginseng), 1044356, 7, 1044364); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + + + + + // Refresh Potion + index = AddCraft(typeof(RefreshPotion), "Soins", 1044538, -25, 25.0, typeof(BlackPearl), 1044353, 1, 1044361); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + index = AddCraft(typeof(TotalRefreshPotion), "Soins", 1044539, 25.0, 75.0, typeof(BlackPearl), 1044353, 5, 1044361); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + + // Cure Potion + index = AddCraft( typeof( LesserCurePotion ), "Soins", 1044552, -10.0, 40.0, typeof( Garlic ), 1044355, 1, 1044363 ); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + index = AddCraft(typeof(CurePotion), "Soins", 1044553, 25.0, 75.0, typeof(Garlic), 1044355, 3, 1044363); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + index = AddCraft(typeof(GreaterCurePotion), "Soins", 1044554, 65.0, 115.0, typeof(Garlic), 1044355, 6, 1044363); + AddRes( index, typeof ( Bottle ), 1044529, 1, 500315 ); + + + + + + + //Todo : Set max chances 80% + index = AddCraft(typeof(WhiteTeinture), "Teintures", "Teinture Blanche", 20.0, 60.0, typeof(GraveDust), 1023983, 6, 1044253); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + AddRes(index, typeof(BullFrogLard), "Du gras de grenouille", 1, "Il vous faut une base grasse pour la teinture"); + AddRes(index, typeof(WhitePearl), "Perle blanche", 1, "Il vous faut une perle blanche"); + MaxChance(index, 0.8); + + index = AddCraft(typeof(BlackTeinture), "Teintures", "Teinture Noire", 20,60, typeof(BlackPearl), 1044353, 12, 1044361); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + AddRes(index, typeof(BullFrogLard), "Du gras de grenouille", 1, "Il vous faut une base grasse pour la teinture"); + AddRes(index, typeof(DarkSapphire), "Saphir noir", 1, "Il vous faut un saphir noir"); + MaxChance(index, 0.8); + + index = AddCraft(typeof(CyanTeinture), "Teintures", "Teinture Cyan", 30.0, 80, typeof(TribalBerry), 1046460, 4, 1044253); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + AddRes(index, typeof(BullFrogLard), "Du gras de grenouille", 1, "Il vous faut une base grasse pour la teinture"); + AddRes(index, typeof(BlueScales), "�caille marine", 1, "Il vous faut une �caille marine"); + MaxChance(index, 0.8); + + index = AddCraft(typeof(YellowTeinture), "Teintures", "Teinture Jaune", 30.0, 80, typeof(SulfurousAsh), 1044359, 12, 1044367); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + AddRes(index, typeof(BullFrogLard), "Du gras de grenouille", 1, "Il vous faut une base grasse pour la teinture"); + AddRes(index, typeof(YellowScales), "�caille jaune", 1, "Il vous faut une �caille jaune"); + MaxChance(index, 0.8); + + index = AddCraft(typeof(MagentaTeinture), "Teintures", "Teinture Magenta", 30.0, 80, typeof(Bloodmoss), 1044354, 1, 1044362); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + AddRes(index, typeof(BullFrogLard), "Du gras de grenouille", 1, "Il vous faut une base grasse pour la teinture"); + AddRes(index, typeof(RedScales), "�caille rouge", 1, "Il vous faut une �caille rouge"); + MaxChance(index, 0.8); + + // Scriptiz : ajout des potions de shrink + index = AddCraft(typeof(ShrinkPotion), "Autres", "Potion de Shrink", 70.0, 120.0, typeof(Seed), 1060810, 3, "You do not have enough seeds to make that."); + AddRes(index, typeof(RecallRune), 1060577, 3, 1115364); + AddRes(index, typeof(Bottle), 1044529, 1, 500315); + + // Scriptiz : ajout des special Dye Tubs + index = AddCraft(typeof(SpecialDyeTub), "Autres", 1006047, 70.0, 120.0, typeof(Eggs), 1044477, 5, "You do not have enough eggs to make that."); + AddRes(index, typeof(Dyes), "Dyes", 3, "You need Dyes to make that."); + AddRes(index, typeof(DyeTub), 1049753, 1, "You need a Dye Tub to make this."); + + // Scriptiz : ajout des furniture Dye Tubs pour teindre les couettes des lits et les oreillers des chaises + index = AddCraft(typeof(FurnitureDyeTub), "Autres", 1006013, 80.0, 130.0, typeof(SpecialDyeTub), 1006047, 1); + AddRes(index, typeof(Beeswax), "Cire d'abeille", 5, "Il vous manque de la Cire d'abeille"); + + index = AddCraft(typeof(TitanToothPowder), "Autres", "Poudre de dent de titan", 70.0, 100.0, typeof(TitanTooth), "Dent de titan", 1, "Vous n'avez pas de dent de titan."); + AddRes(index, typeof(GreaterPoisonPotion), "Poison fort", 1, "Vous avez besoin d'un poison suffisamment fort... mais pas trop!"); + AddRes(index, typeof(MortarPestle), "Mortier", 1, "Vous devez ruiner un mortier."); + SetUseAllRes(index, true); + + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefBlacksmithy.cs b/Scripts/Engines/Craft/DefBlacksmithy.cs new file mode 100644 index 0000000..429d038 --- /dev/null +++ b/Scripts/Engines/Craft/DefBlacksmithy.cs @@ -0,0 +1,778 @@ +using System; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class DefBlacksmithy : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Blacksmith; } + } + + public override int GumpTitleNumber + { + get { return 1044002; } //
BLACKSMITHY MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefBlacksmithy(); + + return m_CraftSystem; + } + } + + public override CraftECA ECA{ get{ return CraftECA.ChanceMinusSixtyToFourtyFive; } } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.0; // 0% + } + + private DefBlacksmithy() : base( 1, 1, 1.25 )// base( 1, 2, 1.7 ) + { + /* + + base( MinCraftEffect, MaxCraftEffect, Delay ) + + MinCraftEffect : The minimum number of time the mobile will play the craft effect + MaxCraftEffect : The maximum number of time the mobile will play the craft effect + Delay : The delay between each craft effect + + Example: (3, 6, 1.7) would make the mobile do the PlayCraftEffect override + function between 3 and 6 time, with a 1.7 second delay each time. + + */ + } + + private static Type typeofAnvil = typeof( AnvilAttribute ); + private static Type typeofForge = typeof( ForgeAttribute ); + + public static void CheckAnvilAndForge( Mobile from, int range, out bool anvil, out bool forge ) + { + anvil = false; + forge = false; + + Map map = from.Map; + + if ( map == null ) + return; + + IPooledEnumerable eable = map.GetItemsInRange( from.Location, range ); + + foreach ( Item item in eable ) + { + Type type = item.GetType(); + + bool isAnvil = ( type.IsDefined( typeofAnvil, false ) || item.ItemID == 4015 || item.ItemID == 4016 || item.ItemID == 0x2DD5 || item.ItemID == 0x2DD6 ); + bool isForge = ( type.IsDefined( typeofForge, false ) || item.ItemID == 4017 || (item.ItemID >= 6522 && item.ItemID <= 6569) || item.ItemID == 0x2DD8 ); + + if ( isAnvil || isForge ) + { + if ( (from.Z + 16) < item.Z || (item.Z + 16) < from.Z || !from.InLOS( item ) ) + continue; + + anvil = anvil || isAnvil; + forge = forge || isForge; + + if ( anvil && forge ) + break; + } + } + + eable.Free(); + + for ( int x = -range; (!anvil || !forge) && x <= range; ++x ) + { + for ( int y = -range; (!anvil || !forge) && y <= range; ++y ) + { + StaticTile[] tiles = map.Tiles.GetStaticTiles( from.X+x, from.Y+y, true ); + + for ( int i = 0; (!anvil || !forge) && i < tiles.Length; ++i ) + { + int id = tiles[i].ID; + + bool isAnvil = ( id == 4015 || id == 4016 || id == 0x2DD5 || id == 0x2DD6 ); + bool isForge = ( id == 4017 || (id >= 6522 && id <= 6569) || id == 0x2DD8 ); + + if ( isAnvil || isForge ) + { + if ( (from.Z + 16) < tiles[i].Z || (tiles[i].Z + 16) < from.Z || !from.InLOS( new Point3D( from.X+x, from.Y+y, tiles[i].Z + (tiles[i].Height/2) + 1 ) ) ) + continue; + + anvil = anvil || isAnvil; + forge = forge || isForge; + } + } + } + } + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if ( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckTool( tool, from ) ) + return 1048146; // If you have a tool equipped, you must use that tool. + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + bool anvil, forge; + CheckAnvilAndForge( from, 2, out anvil, out forge ); + + if ( anvil && forge ) + return 0; + + return 1044267; // You must be near an anvil and a forge to smith items. + } + + public override void PlayCraftEffect( Mobile from ) + { + // no animation, instant sound + //if ( from.Body.Type == BodyType.Human && !from.Mounted ) + // from.Animate( 9, 5, 1, true, false, 0 ); + //new InternalTimer( from ).Start(); + + from.PlaySound( 0x2A ); + } + + // Delay to synchronize the sound with the hit on the anvil + private class InternalTimer : Timer + { + private Mobile m_From; + + public InternalTimer( Mobile from ) : base( TimeSpan.FromSeconds( 0.7 ) ) + { + m_From = from; + } + + protected override void OnTick() + { + m_From.PlaySound( 0x2A ); + } + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + /* + Synthax for a SIMPLE craft item + AddCraft( ObjectType, Group, MinSkill, MaxSkill, ResourceType, Amount, Message ) + + ObjectType : The type of the object you want to add to the build list. + Group : The group in wich the object will be showed in the craft menu. + MinSkill : The minimum of skill value + MaxSkill : The maximum of skill value + ResourceType : The type of the resource the mobile need to create the item + Amount : The amount of the ResourceType it need to create the item + Message : String or Int for Localized. The message that will be sent to the mobile, if the specified resource is missing. + + Synthax for a COMPLEXE craft item. A complexe item is an item that need either more than + only one skill, or more than only one resource. + + Coming soon.... + */ + + #region Ringmail + AddCraft( typeof( RingmailGloves ), 1011076, 1025099, 12.0, 62.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddCraft( typeof( RingmailLegs ), 1011076, 1025104, 19.4, 69.4, typeof( IronIngot ), 1044036, 16, 1044037 ); + AddCraft( typeof( RingmailArms ), 1011076, 1025103, 16.9, 66.9, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddCraft( typeof( RingmailChest ), 1011076, 1025100, 21.9, 71.9, typeof( IronIngot ), 1044036, 18, 1044037 ); + #endregion + + #region Chainmail + AddCraft( typeof( ChainCoif ), 1011077, 1025051, 14.5, 64.5, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddCraft( typeof( ChainLegs ), 1011077, 1025054, 36.7, 86.7, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddCraft( typeof( ChainChest ), 1011077, 1025055, 39.1, 89.1, typeof( IronIngot ), 1044036, 20, 1044037 ); + #endregion + + int index = -1; + + #region Platemail + AddCraft( typeof( PlateArms ), 1011078, 1025136, 66.3, 116.3, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddCraft( typeof( PlateGloves ), 1011078, 1025140, 58.9, 108.9, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddCraft( typeof( PlateGorget ), 1011078, 1025139, 56.4, 106.4, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddCraft( typeof( PlateLegs ), 1011078, 1025137, 68.8, 118.8, typeof( IronIngot ), 1044036, 20, 1044037 ); + AddCraft( typeof( PlateChest ), 1011078, 1046431, 75.0, 122.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + AddCraft( typeof( FemalePlateChest ), 1011078, 1046430, 44.1, 94.1, typeof( IronIngot ), 1044036, 20, 1044037 ); + + if ( Core.AOS ) // exact pre-aos functionality unknown + AddCraft( typeof( DragonBardingDeed ), 1011078, 1053012, 72.5, 122.5, typeof( IronIngot ), 1044036, 750, 1044037 ); + + if( Core.SE ) + { + + index = AddCraft( typeof( PlateMempo ), 1011078, 1030180, 80.0, 130.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlateDo ), 1011078, 1030184, 80.0, 130.0, typeof( IronIngot ), 1044036, 28, 1044037 ); //Double check skill + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlateHiroSode ), 1011078, 1030187, 80.0, 130.0, typeof( IronIngot ), 1044036, 16, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlateSuneate ), 1011078, 1030195, 65.0, 115.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlateHaidate ), 1011078, 1030200, 65.0, 115.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + } + #endregion + + #region Helmets + AddCraft( typeof( Bascinet ), 1011079, 1025132, 8.3, 58.3, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddCraft( typeof( CloseHelm ), 1011079, 1025128, 37.9, 87.9, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddCraft( typeof( Helmet ), 1011079, 1025130, 37.9, 87.9, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddCraft( typeof( NorseHelm ), 1011079, 1025134, 37.9, 87.9, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddCraft( typeof( PlateHelm ), 1011079, 1025138, 62.6, 112.6, typeof( IronIngot ), 1044036, 15, 1044037 ); + + if( Core.SE ) + { + index = AddCraft( typeof( ChainHatsuburi ), 1011079, 1030175, 30.0, 80.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlateHatsuburi ), 1011079, 1030176, 45.0, 95.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( HeavyPlateJingasa ), 1011079, 1030178, 45.0, 95.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( LightPlateJingasa ), 1011079, 1030188, 45.0, 95.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( SmallPlateJingasa ), 1011079, 1030191, 45.0, 95.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( DecorativePlateKabuto ), 1011079, 1030179, 90.0, 140.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlateBattleKabuto ), 1011079, 1030192, 90.0, 140.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( StandardPlateKabuto ), 1011079, 1030196, 90.0, 140.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + // Scriptiz : les diad�mes sont des bijoux craftables par les thinkers (Diademe & DiademeDecore) + // Scriptiz : on remet les circlet mais on augmente le metal n�cessaire et on descend les skills afin d'�viter le campage + /*if( Core.ML ) + { + //index = AddCraft( typeof( Circlet ), 1011079, 1032645, 62.1, 112.1, typeof( IronIngot ), 1044036, 6, 1044037 ); + index = AddCraft(typeof(Circlet), 1011079, 1032645, 62.6, 112.6, typeof(IronIngot), 1044036, 15, 1044037); + SetNeededExpansion( index, Expansion.ML ); + + //index = AddCraft( typeof( RoyalCirclet ), 1011079, 1032646, 70.0, 120.0, typeof( IronIngot ), 1044036, 6, 1044037 ); + index = AddCraft(typeof(RoyalCirclet), 1011079, 1032646, 70.0, 120.0, typeof(IronIngot), 1044036, 20, 1044037); + SetNeededExpansion( index, Expansion.ML ); + + //index = AddCraft( typeof( GemmedCirclet ), 1011079, 1032647, 75.0, 125.0, typeof( IronIngot ), 1044036, 6, 1044037 ); + index = AddCraft(typeof(GemmedCirclet), 1011079, 1032647, 75.0, 125.0, typeof(IronIngot), 1044036, 20, 1044037); + AddRes( index, typeof( Tourmaline ), 1044237, 1, 1044240 ); + AddRes( index, typeof( Amethyst ), 1044236, 1, 1044240 ); + AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 ); + SetNeededExpansion( index, Expansion.ML ); + }*/ + } + #endregion + + #region Shields + AddCraft( typeof( Buckler ), 1011080, 1027027, -25.0, 25.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddCraft( typeof( BronzeShield ), 1011080, 1027026, -15.2, 34.8, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddCraft( typeof( HeaterShield ), 1011080, 1027030, 24.3, 74.3, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddCraft( typeof( MetalShield ), 1011080, 1027035, -10.2, 39.8, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddCraft( typeof( MetalKiteShield ), 1011080, 1027028, 4.6, 54.6, typeof( IronIngot ), 1044036, 16, 1044037 ); + AddCraft( typeof( WoodenKiteShield ), 1011080, 1027032, -15.2, 34.8, typeof( IronIngot ), 1044036, 8, 1044037 ); + + if ( Core.AOS ) + { + AddCraft( typeof( ChaosShield ), 1011080, 1027107, 85.0, 135.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + AddCraft( typeof( OrderShield ), 1011080, 1027108, 85.0, 135.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + } + #endregion + + #region Bladed + + if ( Core.AOS ) + AddCraft( typeof( BoneHarvester ), 1011081, 1029915, 33.0, 83.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + + AddCraft( typeof( Broadsword ), 1011081, 1023934, 35.4, 85.4, typeof( IronIngot ), 1044036, 10, 1044037 ); + //Myron : Ajout Paladin Sword + if (Core.AOS) + AddCraft(typeof(PaladinSword), 1011081, 1029934, 40.1, 90.1, typeof(IronIngot), 1044036, 20, 1044037); + if ( Core.AOS ) + AddCraft( typeof( CrescentBlade ), 1011081, 1029921, 45.0, 95.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + + AddCraft( typeof( Cutlass ), 1011081, 1025185, 24.3, 74.3, typeof( IronIngot ), 1044036, 8, 1044037 ); + AddCraft( typeof( Dagger ), 1011081, 1023921, -0.4, 49.6, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddCraft( typeof( Katana ),1011081, 1025119, 44.1, 94.1, typeof( IronIngot ), 1044036, 8, 1044037 ); + AddCraft( typeof( Kryss ), 1011081, 1025121, 36.7, 86.7, typeof( IronIngot ), 1044036, 8, 1044037 ); + AddCraft( typeof( Longsword ), 1011081, 1023937, 28.0, 78.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddCraft( typeof( Scimitar ), 1011081, 1025046, 31.7, 81.7, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddCraft( typeof( VikingSword ), 1011081, 1025049, 24.3, 74.3, typeof( IronIngot ), 1044036, 14, 1044037 ); + + if( Core.SE ) + { + index = AddCraft( typeof( NoDachi ), 1011081, 1030221, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Wakizashi ), 1011081, 1030223, 50.0, 100.0, typeof( IronIngot ), 1044036, 8, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Lajatang ), 1011081, 1030226, 80.0, 130.0, typeof( IronIngot ), 1044036, 25, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Daisho ), 1011081, 1030228, 60.0, 110.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Tekagi ), 1011081, 1030230, 55.0, 105.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Shuriken ), 1011081, 1030231, 45.0, 95.0, typeof( IronIngot ), 1044036, 5, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Kama ), 1011081, 1030232, 40.0, 90.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Sai ), 1011081, 1030234, 50.0, 100.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + if( Core.ML ) + { + index = AddCraft( typeof( RadiantScimitar ), 1011081, 1031571, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( WarCleaver ), 1011081, 1031567, 70.0, 120.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( ElvenSpellblade ), 1011081, 1031564, 70.0, 120.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( AssassinSpike ), 1011081, 1031565, 70.0, 120.0, typeof( IronIngot ), 1044036, 9, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( Leafblade ), 1011081, 1031566, 70.0, 120.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( RuneBlade ), 1011081, 1031570, 70.0, 120.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( ElvenMachete ), 1011081, 1031573, 70.0, 120.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + // Scriptiz : on laisse comment� car pas les recettes + + index = AddCraft( typeof( RuneCarvingKnife ), 1011081, 1072915, 70.0, 120.0, typeof( IronIngot ), 1044036, 9, 1044037 ); + AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1053098 ); + AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 ); + AddRes( index, typeof( Muculent ), 1032680, 10, 1053098 ); + AddRareRecipe(index, 0); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( ColdForgedBlade ), 1011081, 1072916, 70.0, 120.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddRes( index, typeof( GrizzledBones ), 1032684, 1, 1053098 ); + AddRes( index, typeof( Taint ), 1032684, 10, 1053098 ); + AddRes( index, typeof( Blight ), 1032675, 10, 1053098 ); + AddRareRecipe(index, 1); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( OverseerSunderedBlade ), 1011081, 1072920, 70.0, 120.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( GrizzledBones ), 1032684, 1, 1053098 ); + AddRes( index, typeof( Blight ), 1032675, 10, 1053098 ); + AddRes( index, typeof( Scourge ), 1032677, 10, 1053098 ); + AddRareRecipe(index, 2); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( LuminousRuneBlade ), 1011081, 1072922, 70.0, 120.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( GrizzledBones ), 1032684, 1, 1053098 ); + AddRes( index, typeof( Corruption ), 1032676, 10, 1053098 ); + AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 ); + AddRareRecipe(index, 3); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( TrueSpellblade ), 1011081, 1073513, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 ); + AddRecipe( index, 4 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( IcySpellblade ), 1011081, 1073514, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 ); + AddRecipe( index, 5 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( FierySpellblade ), 1011081, 1073515, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( FireRuby ), 1032695, 1, 1044240 ); + AddRecipe( index, 6 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( SpellbladeOfDefense ), 1011081, 1073516, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddRes( index, typeof( WhitePearl ), 1032694, 1, 1044240 ); + AddRecipe( index, 7 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( TrueAssassinSpike ), 1011081, 1073517, 75.0, 125.0, typeof( IronIngot ), 1044036, 9, 1044037 ); + AddRes( index, typeof( DarkSapphire ), 1032690, 1, 1044240 ); + AddRecipe( index, 8 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( ChargedAssassinSpike ), 1011081, 1073518, 75.0, 125.0, typeof( IronIngot ), 1044036, 9, 1044037 ); + AddRes( index, typeof( EcruCitrine ), 1032693, 1, 1044240 ); + AddRecipe( index, 9 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( MagekillerAssassinSpike ), 1011081, 1073519, 75.0, 125.0, typeof( IronIngot ), 1044036, 9, 1044037 ); + AddRes( index, typeof( BrilliantAmber ), 1032697, 1, 1044240 ); + AddRecipe( index, 10 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( WoundingAssassinSpike ), 1011081, 1073520, 75.0, 125.0, typeof( IronIngot ), 1044036, 9, 1044037 ); + AddRes( index, typeof( PerfectEmerald ), 1032692, 1, 1044240 ); + AddRecipe( index, 11 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( TrueLeafblade ), 1011081, 1073521, 75.0, 125.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 ); + AddRecipe( index, 12 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( Luckblade ), 1011081, 1073522, 75.0, 125.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddRes( index, typeof( WhitePearl ), 1032694, 1, 1044240 ); + AddRecipe( index, 13 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( MagekillerLeafblade ), 1011081, 1073523, 75.0, 125.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddRes( index, typeof( FireRuby ), 1032695, 1, 1044240 ); + AddRecipe( index, 14 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( LeafbladeOfEase ), 1011081, 1073524, 75.0, 125.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddRes( index, typeof( PerfectEmerald ), 1032692, 1, 1044240 ); + AddRecipe( index, 15 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( KnightsWarCleaver ), 1011081, 1073525, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddRes( index, typeof( PerfectEmerald ), 1032692, 1, 1044240 ); + AddRecipe( index, 16 ); + SetNeededExpansion( index, Expansion.ML ); + + // TODO + index = AddCraft( typeof( ButchersWarCleaver ), 1011081, 1073526, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 ); + AddRecipe( index, 17 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( SerratedWarCleaver ), 1011081, 1073527, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddRes( index, typeof( EcruCitrine ), 1032693, 1, 1044240 ); + AddRecipe( index, 18 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( TrueWarCleaver ), 1011081, 1073528, 75.0, 125.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + AddRes( index, typeof( BrilliantAmber ), 1032697, 1, 1044240 ); + AddRecipe( index, 19 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( AdventurersMachete ), 1011081, 1073533, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( WhitePearl ), 1032694, 1, 1044240 ); + AddRecipe( index, 20 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( OrcishMachete ), 1011081, 1073534, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( Scourge ), 1072136, 1, 1042081 ); + AddRecipe( index, 21 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( MacheteOfDefense ), 1011081, 1073535, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( BrilliantAmber ), 1032697, 1, 1044240 ); + AddRecipe( index, 22 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( DiseasedMachete ), 1011081, 1073536, 75.0, 125.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddRes( index, typeof( Blight ), 1072134, 1, 1042081 ); + AddRecipe( index, 23 ); + SetNeededExpansion( index, Expansion.ML ); + + // TODO + index = AddCraft(typeof(Runesabre), 1011081, 1073537, 75.0, 125.0, typeof(IronIngot), 1044036, 15, 1044037); + AddRes(index, typeof(Turquoise), 1032691, 1, 1044240); + AddRecipe(index, 24); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft( typeof( MagesRuneBlade ), 1011081, 1073538, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 ); + AddRecipe( index, 25 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( RuneBladeOfKnowledge ), 1011081, 1073539, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( EcruCitrine ), 1032693, 1, 1044240 ); + AddRecipe( index, 26 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( CorruptedRuneBlade ), 1011081, 1073540, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( Corruption ), 1072135, 1, 1042081 ); + AddRecipe( index, 27 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( TrueRadiantScimitar ), 1011081, 1073541, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( BrilliantAmber ), 1032697, 1, 1044240 ); + AddRecipe( index, 28 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( DarkglowScimitar ), 1011081, 1073542, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( DarkSapphire ), 1032690, 1, 1044240 ); + AddRecipe( index, 29 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( IcyScimitar ), 1011081, 1073543, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( DarkSapphire ), 1032690, 1, 1044240 ); + AddRecipe( index, 30 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( TwinklingScimitar ), 1011081, 1073544, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( DarkSapphire ), 1032690, 1, 1044240 ); + AddRecipe( index, 31 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft(typeof(BoneMachete), 1011081, 1020526, 45.0, 95.0, typeof(IronIngot), 1044036, 20, 1044037); + AddRes(index, typeof(Bone), 1049064, 6, 1049063); + AddQuestRecipe(index, 32); + SetNeededExpansion(index, Expansion.ML); + + } + } + #endregion + + #region Axes + AddCraft( typeof( Axe ), 1011082, 1023913, 34.2, 84.2, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddCraft( typeof( BattleAxe ), 1011082, 1023911, 30.5, 80.5, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddCraft( typeof( DoubleAxe ), 1011082, 1023915, 29.3, 79.3, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddCraft( typeof( ExecutionersAxe ), 1011082, 1023909, 34.2, 84.2, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddCraft( typeof( LargeBattleAxe ), 1011082, 1025115, 28.0, 78.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddCraft( typeof( TwoHandedAxe ), 1011082, 1025187, 33.0, 83.0, typeof( IronIngot ), 1044036, 16, 1044037 ); + AddCraft( typeof( WarAxe ), 1011082, 1025040, 39.1, 89.1, typeof( IronIngot ), 1044036, 16, 1044037 ); + + if( Core.ML ) + { + index = AddCraft( typeof( OrnateAxe ), 1011082, 1031572, 70.0, 120.0, typeof( IronIngot ), 1044036, 18, 1044037 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( GuardianAxe ), 1011082, 1073545, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 ); + AddRecipe( index, 33 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( SingingAxe ), 1011082, 1073546, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( BrilliantAmber ), 1032697, 1, 1044240 ); + AddRecipe( index, 34 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( ThunderingAxe ), 1011082, 1073547, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( EcruCitrine ), 1032693, 1, 1044240 ); + AddRecipe( index, 35 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( HeavyOrnateAxe ), 1011082, 1073548, 75.0, 125.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + AddRes( index, typeof( Turquoise ), 1032691, 1, 1044240 ); + AddRecipe( index, 36 ); + SetNeededExpansion( index, Expansion.ML ); + + } + #endregion + + #region Pole Arms + + AddCraft( typeof( Bardiche ), 1011083, 1023917, 31.7, 81.7, typeof( IronIngot ), 1044036, 18, 1044037 ); + + if ( Core.AOS ) + AddCraft( typeof( BladedStaff ), 1011083, 1029917, 40.0, 90.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + + if ( Core.AOS ) + AddCraft( typeof( DoubleBladedStaff ), 1011083, 1029919, 45.0, 95.0, typeof( IronIngot ), 1044036, 16, 1044037 ); + + AddCraft( typeof( Halberd ), 1011083, 1025183, 39.1, 89.1, typeof( IronIngot ), 1044036, 20, 1044037 ); + + if ( Core.AOS ) + AddCraft( typeof( Lance ), 1011083, 1029920, 48.0, 98.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + + if ( Core.AOS ) + AddCraft( typeof( Pike ), 1011083, 1029918, 47.0, 97.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + + AddCraft( typeof( ShortSpear ), 1011083, 1025123, 45.3, 95.3, typeof( IronIngot ), 1044036, 6, 1044037 ); + + if ( Core.AOS ) + AddCraft( typeof( Scythe ), 1011083, 1029914, 39.0, 89.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + + AddCraft( typeof( Spear ), 1011083, 1023938, 49.0, 99.0, typeof( IronIngot ), 1044036, 12, 1044037 ); + AddCraft( typeof( WarFork ), 1011083, 1025125, 42.9, 92.9, typeof( IronIngot ), 1044036, 12, 1044037 ); + + // Not craftable (is this an AOS change ??) + //AddCraft( typeof( Pitchfork ), 1011083, 1023720, 36.1, 86.1, typeof( IronIngot ), 1044036, 12, 1044037 ); + #endregion + + #region Bashing + AddCraft( typeof( HammerPick ), 1011084, 1025181, 34.2, 84.2, typeof( IronIngot ), 1044036, 16, 1044037 ); + AddCraft( typeof( Mace ), 1011084, 1023932, 14.5, 64.5, typeof( IronIngot ), 1044036, 6, 1044037 ); + AddCraft( typeof( Maul ), 1011084, 1025179, 19.4, 69.4, typeof( IronIngot ), 1044036, 10, 1044037 ); + + if ( Core.AOS ) + AddCraft( typeof( Scepter ), 1011084, 1029916, 21.4, 71.4, typeof( IronIngot ), 1044036, 10, 1044037 ); + + AddCraft( typeof( WarMace ), 1011084, 1025127, 28.0, 78.0, typeof( IronIngot ), 1044036, 14, 1044037 ); + AddCraft( typeof( WarHammer ), 1011084, 1025177, 34.2, 84.2, typeof( IronIngot ), 1044036, 16, 1044037 ); + + if( Core.SE ) + { + index = AddCraft( typeof( Tessen ), 1011084, 1030222, 85.0, 135.0, typeof( IronIngot ), 1044036, 16, 1044037 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + if( Core.ML ) + { + index = AddCraft(typeof(DiamondMace), 1011084, 1031556, 70.0, 120.0, typeof(IronIngot), 1044036, 20, 1044037); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(ShardThrasher), 1011084, 1072918, 70.0, 120.0, typeof(IronIngot), 1044036, 20, 1044037); + AddRes(index, typeof(EyeOfTheTravesty), 1073126, 1, 1042081); + AddRes(index, typeof(Muculent), 1072139, 10, 1042081); + AddRes(index, typeof(Corruption), 1072135, 10, 1042081); + AddRareRecipe(index, 37); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft( typeof( RubyMace ), 1011084, 1073529, 75.0, 125.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + AddRes( index, typeof( FireRuby ), 1032695, 1, 1044240 ); + AddRecipe( index, 38 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( EmeraldMace ), 1011084, 1073530, 75.0, 125.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + AddRes( index, typeof( PerfectEmerald ), 1032692, 1, 1044240 ); + AddRecipe( index, 39 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( SapphireMace ), 1011084, 1073531, 75.0, 125.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + AddRes( index, typeof( DarkSapphire ), 1032690, 1, 1044240 ); + AddRecipe( index, 40 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( SilverEtchedMace ), 1011084, 1073532, 75.0, 125.0, typeof( IronIngot ), 1044036, 20, 1044037 ); + AddRes( index, typeof( BlueDiamond ), 1032696, 1, 1044240 ); + AddRecipe( index, 41 ); + SetNeededExpansion( index, Expansion.ML ); + } + #endregion + + #region Dragon Scale Armor + index = AddCraft( typeof( DragonGloves ), 1053114, 1029795, 68.9, 118.9, typeof( RedScales ), 1060883, 16, 1060884 ); + SetUseSubRes2( index, true ); + + index = AddCraft( typeof( DragonHelm ), 1053114, 1029797, 72.6, 122.6, typeof( RedScales ), 1060883, 20, 1060884 ); + SetUseSubRes2( index, true ); + + index = AddCraft( typeof( DragonLegs ), 1053114, 1029799, 78.8, 128.8, typeof( RedScales ), 1060883, 28, 1060884 ); + SetUseSubRes2( index, true ); + + index = AddCraft( typeof( DragonArms ), 1053114, 1029815, 76.3, 126.3, typeof( RedScales ), 1060883, 24, 1060884 ); + SetUseSubRes2( index, true ); + + index = AddCraft( typeof( DragonChest ), 1053114, 1029793, 85.0, 135.0, typeof( RedScales ), 1060883, 36, 1060884 ); + SetUseSubRes2( index, true ); + #endregion + + AddCraft(typeof(ThrowingDagger), "Throwing", "Throwing Dagger", 10, 30, typeof(IronIngot), 1044036, 2, 1044037); + AddCraft(typeof(ThrowingAxe), "Throwing", "Throwing Axe", 25, 35, typeof(IronIngot), 1044036, 6, 1044037); + + // Set the overridable material + SetSubRes( typeof( IronIngot ), 1044022 ); + + // Add every material you want the player to be able to choose from + // This will override the overridable material + AddSubRes(typeof(IronIngot), "Fer", 00.0, 10442687); + AddSubRes(typeof(RustyIngot), "Rusty", 30.0, 1044268); + AddSubRes(typeof(OldcopperIngot), "Vieux Cuivre", 30.0, 1044268); + AddSubRes(typeof(DullcopperIngot), "Cuivre terni", 55.0, 1044268); + AddSubRes(typeof(ShadowIngot), "Sombrine", 60.0, 1044268); + AddSubRes(typeof(CopperIngot), "Cuivre", 60.0, 1044268); + AddSubRes(typeof(BronzeIngot), "Bronze", 65.0, 1044268); + AddSubRes(typeof(GoldIngot), "Or", 70.0, 1044268); + AddSubRes(typeof(RoseIngot), "Rose", 99.0, 1044268); + AddSubRes(typeof(AgapiteIngot), "Agapite", 55.0, 1044268); + AddSubRes(typeof(ValoriteIngot), "Valorite", 90.0, 1044268); + //AddSubRes(typeof(BloodrockIngot), "Roche de sang", 75.0, 1044268); + AddSubRes(typeof(VeriteIngot), "Verite", 80.0, 1044268); + AddSubRes(typeof(SilverIngot), "Argent", 85.0, 1044268); + AddSubRes(typeof(DragonIngot), "Dragon", 90.0, 1044268); + AddSubRes(typeof(TitanIngot), "Titan", 95.0, 1044268); + //AddSubRes(typeof(CrystalineIngot), "Crystaline", 99.0, 1044268); + //AddSubRes(typeof(KryniteIngot), "Krynite", 65.0, 1044268); + + //AddSubRes(typeof(BloodcrestIngot), "Craie de sang", 75.0, 1044268); + //AddSubRes(typeof(ElvinIngot), "Elvin", 80.0, 1044268); + //AddSubRes(typeof(AcidIngot), "Acid", 85.0, 1044268); + //AddSubRes(typeof(AquaIngot), "Aqua", 90.0, 1044268); + AddSubRes(typeof(EldarIngot), "Eldar", 95.0, 1044268); + AddSubRes(typeof(GlowingIngot), "Glowing", 99.0, 1044268); + AddSubRes(typeof(VulcanIngot), "Vulcan", 99.0, 1044268); + //AddSubRes(typeof(GorganIngot), "Gorgan", 65.0, 1044268); + //AddSubRes(typeof(SteelIngot), "Acier", 70.0, 1044268); + //AddSubRes(typeof(SandrockIngot), "Pierre de sable", 75.0, 1044268); + //AddSubRes(typeof(MytherilIngot), "Mytheril", 80.0, 1044268); + AddSubRes(typeof(BlackrockIngot), "Pierre noire", 99.0, 1044268); + + + SetSubRes2( typeof( RedScales ), 1060875 ); + + AddSubRes2( typeof( RedScales ), 1060875, 0.0, 1053137, 1044268 ); + AddSubRes2( typeof( YellowScales ), 1060876, 0.0, 1053137, 1044268 ); + AddSubRes2( typeof( BlackScales ), 1060877, 0.0, 1053137, 1044268 ); + AddSubRes2( typeof( GreenScales ), 1060878, 0.0, 1053137, 1044268 ); + AddSubRes2( typeof( WhiteScales ), 1060879, 0.0, 1053137, 1044268 ); + AddSubRes2( typeof( BlueScales ), 1060880, 0.0, 1053137, 1044268 ); + + Resmelt = true; + Repair = true; + MarkOption = true; + CanEnhance = Core.AOS; + } + } + + public class ForgeAttribute : Attribute + { + public ForgeAttribute() + { + } + } + + public class AnvilAttribute : Attribute + { + public AnvilAttribute() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefBowFletching.cs b/Scripts/Engines/Craft/DefBowFletching.cs new file mode 100644 index 0000000..928ee24 --- /dev/null +++ b/Scripts/Engines/Craft/DefBowFletching.cs @@ -0,0 +1,232 @@ +using System; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class DefBowFletching : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Fletching; } + } + + public override int GumpTitleNumber + { + get { return 1044006; } //
BOWCRAFT AND FLETCHING MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefBowFletching(); + + return m_CraftSystem; + } + } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.5; // 50% + } + + private DefBowFletching() : base( 1, 1, 1.25 )// base( 1, 2, 1.7 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + public override void PlayCraftEffect( Mobile from ) + { + // no animation + //if ( from.Body.Type == BodyType.Human && !from.Mounted ) + // from.Animate( 33, 5, 1, true, false, 0 ); + + from.PlaySound( 0x55 ); + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override CraftECA ECA{ get{ return CraftECA.FiftyPercentChanceMinusTenPercent; } } + + public override void InitCraftList() + { + int index = -1; + + // Materials + AddCraft( typeof( Kindling ), 1044457, 1023553, 0.0, 00.0, typeof( Log ), 1044041, 1, 1044351 ); + + index = AddCraft( typeof( Shaft ), 1044457, 1027124, 0.0, 40.0, typeof( Log ), 1044041, 1, 1044351 ); + SetUseAllRes( index, true ); + + // Ammunition + index = AddCraft( typeof( Arrow ), 1044565, 1023903, 0.0, 40.0, typeof( Shaft ), 1044560, 1, 1044561 ); + AddRes( index, typeof( Feather ), 1044562, 1, 1044563 ); + SetUseAllRes( index, true ); + + index = AddCraft( typeof( Bolt ), 1044565, 1027163, 0.0, 40.0, typeof( Shaft ), 1044560, 1, 1044561 ); + AddRes( index, typeof( Feather ), 1044562, 1, 1044563 ); + SetUseAllRes( index, true ); + + if( Core.SE ) + { + index = AddCraft( typeof( FukiyaDarts ), 1044565, 1030246, 50.0, 90.0, typeof( Log ), 1044041, 1, 1044351 ); + SetUseAllRes( index, true ); + SetNeededExpansion( index, Expansion.SE ); + } + + // Weapons + AddCraft( typeof( Bow ), 1044566, 1025042, 30.0, 70.0, typeof( Log ), 1044041, 7, 1044351 ); + AddCraft( typeof( Crossbow ), 1044566, 1023919, 60.0, 100.0, typeof( Log ), 1044041, 7, 1044351 ); + AddCraft( typeof( HeavyCrossbow ), 1044566, 1025117, 80.0, 120.0, typeof( Log ), 1044041, 10, 1044351 ); + + if ( Core.AOS ) + { + AddCraft( typeof( CompositeBow ), 1044566, 1029922, 70.0, 110.0, typeof( Log ), 1044041, 7, 1044351 ); + AddCraft( typeof( RepeatingCrossbow ), 1044566, 1029923, 90.0, 130.0, typeof( Log ), 1044041, 10, 1044351 ); + } + + if( Core.SE ) + { + index = AddCraft( typeof( Yumi ), 1044566, 1030224, 90.0, 130.0, typeof( Log ), 1044041, 10, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + } + + if (Core.ML) + { + index = AddCraft(typeof(BlightGrippedLongbow), 1044566, 1072907, 75.0, 125.0, typeof(Log), 1044041, 20, 1044351); + AddRes(index, typeof(LardOfParoxysmus), 1032681, 1, 1053098); + AddRes(index, typeof(Blight), 1032675, 10, 1053098); + AddRes(index, typeof(Corruption), 1032676, 10, 1053098); + AddRareRecipe(index, 200); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + /* TODO + index = AddCraft( typeof( FaerieFire ), 1044566, 1072908, 75.0, 125.0, typeof( Log ), 1044041, 20, 1044351 ); + AddRes( index, typeof( LardOfParoxysmus ), 1032681, 1, 1053098 ); + AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 ); + AddRes( index, typeof( Taint ), 1032679, 10, 1053098 ); + AddRareRecipe( index, 201 ); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + */ + + index = AddCraft(typeof(SilvanisFeywoodBow), 1044566, 1072955, 75.0, 125.0, typeof(Log), 1044041, 20, 1044351); + AddRes(index, typeof(LardOfParoxysmus), 1032681, 1, 1053098); + AddRes(index, typeof(Scourge), 1032677, 10, 1053098); + AddRes(index, typeof(Muculent), 1032680, 10, 1053098); + AddRareRecipe(index, 202); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + /* TODO + index = AddCraft( typeof( MischiefMaker ), 1044566, 1072910, 75.0, 125.0, typeof( Log ), 1044041, 15, 1044351 ); + AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1053098 ); + AddRes( index, typeof( Corruption ), 1032676, 10, 1053098 ); + AddRes( index, typeof( Putrefication ), 1032678, 10, 1053098 ); + AddRareRecipe( index, 203 ); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + */ + + index = AddCraft(typeof(TheNightReaper), 1044566, 1072912, 75.0, 125.0, typeof(Log), 1044041, 10, 1044351); + AddRes(index, typeof(DreadHornMane), 1032682, 1, 1053098); + AddRes(index, typeof(Blight), 1032675, 10, 1053098); + AddRes(index, typeof(Scourge), 1032677, 10, 1053098); + AddRareRecipe(index, 204); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(BarbedLongbow), 1044566, 1073505, 75.0, 125.0, typeof(Log), 1044041, 20, 1044351); + AddRes(index, typeof(FireRuby), 1026254, 1, 1053098); + AddRecipe(index, 205); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(SlayerLongbow), 1044566, 1073506, 75.0, 125.0, typeof(Log), 1044041, 20, 1044351); + AddRes(index, typeof(BrilliantAmber), 1026256, 1, 1053098); + AddRecipe(index, 206); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(FrozenLongbow), 1044566, 1073507, 75.0, 125.0, typeof(Log), 1044041, 20, 1044351); + AddRes(index, typeof(Turquoise), 1026250, 1, 1053098); + AddRecipe(index, 207); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(LongbowOfMight), 1044566, 1073508, 75.0, 125.0, typeof(Log), 1044041, 10, 1044351); + AddRes(index, typeof(BlueDiamond), 1026255, 1, 1053098); + AddRecipe(index, 208); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(RangersShortbow), 1044566, 1073509, 75.0, 125.0, typeof(Log), 1044041, 15, 1044351); + AddRes(index, typeof(PerfectEmerald), 1026251, 1, 1053098); + AddRecipe(index, 209); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(LightweightShortbow), 1044566, 1073510, 75.0, 125.0, typeof(Log), 1044041, 15, 1044351); + AddRes(index, typeof(WhitePearl), 1026253, 1, 1053098); + AddRecipe(index, 210); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(MysticalShortbow), 1044566, 1073511, 75.0, 125.0, typeof(Log), 1044041, 15, 1044351); + AddRes(index, typeof(EcruCitrine), 1026252, 1, 1053098); + AddRecipe(index, 211); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(AssassinsShortbow), 1044566, 1073512, 75.0, 125.0, typeof(Log), 1044041, 15, 1044351); + AddRes(index, typeof(DarkSapphire), 1026249, 1, 1053098); + AddRecipe(index, 212); + SetNeededExpansion(index, Expansion.ML); + } + + MarkOption = true; + Repair = Core.AOS; + + SetSubRes(typeof(Log), 1072643); + + // Add every material you want the player to be able to choose from + // This will override the overridable material TODO: Verify the required skill amount + AddSubRes(typeof(Log), 1072643, 00.0, 1044041, 1072652); + AddSubRes(typeof(OakLog), 1072644, 65.0, 1044041, 1072652); + AddSubRes(typeof(AshLog), 1072645, 80.0, 1044041, 1072652); + AddSubRes(typeof(YewLog), 1072646, 95.0, 1044041, 1072652); + AddSubRes(typeof(HeartwoodLog), 1072647, 100.0, 1044041, 1072652); + AddSubRes(typeof(BloodwoodLog), 1072648, 100.0, 1044041, 1072652); + AddSubRes(typeof(FrostwoodLog), 1072649, 100.0, 1044041, 1072652); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefCarpentry.cs b/Scripts/Engines/Craft/DefCarpentry.cs new file mode 100644 index 0000000..3fd8e77 --- /dev/null +++ b/Scripts/Engines/Craft/DefCarpentry.cs @@ -0,0 +1,593 @@ +using System; +using Server.Items; + + +namespace Server.Engines.Craft +{ + public class DefCarpentry : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Carpentry; } + } + + public override int GumpTitleNumber + { + get { return 1044004; } //
CARPENTRY MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefCarpentry(); + + return m_CraftSystem; + } + } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.5; // 50% + } + + private DefCarpentry() : base( 1, 1, 1.25 )// base( 1, 1, 3.0 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + public override void PlayCraftEffect( Mobile from ) + { + // no animation + //if ( from.Body.Type == BodyType.Human && !from.Mounted ) + // from.Animate( 9, 5, 1, true, false, 0 ); + + from.PlaySound( 0x23D ); + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + int index = -1; + + // Other Items + if ( Core.Expansion == Expansion.AOS || Core.Expansion == Expansion.SE ) + { + index = AddCraft( typeof( Board ), 1044294, 1027127, 0.0, 0.0, typeof( Log ), 1044466, 1, 1044465 ); + SetUseAllRes( index, true ); + } + + // Scriptiz : ajout de parchemins vierges + AddCraft(typeof(BlankScroll), 1044294, "10 Parchemin vierge", 50.0, 50.1, typeof(Log), 1044041, 10, 1044351); + + AddCraft( typeof( BarrelStaves ), 1044294, 1027857, 00.0, 25.0, typeof( Log ), 1044041, 5, 1044351 ); + AddCraft( typeof( BarrelLid ), 1044294, 1027608, 11.0, 36.0, typeof( Log ), 1044041, 4, 1044351 ); + AddCraft( typeof( ShortMusicStand ), 1044294, 1044313, 78.9, 103.9, typeof( Log ), 1044041, 15, 1044351 ); + AddCraft( typeof( TallMusicStand ), 1044294, 1044315, 81.5, 106.5, typeof( Log ), 1044041, 20, 1044351 ); + AddCraft( typeof( Easle ), 1044294, 1044317, 86.8, 111.8, typeof( Log ), 1044041, 20, 1044351 ); + + index = AddCraft(typeof(BasketFrame), 1044294, "Corps de panier", 25.0, 50.0, typeof(Log), 1044041, 3, 1044351); + AddRes(index, typeof(Nails), "Clous", 5, "Vous n'avez pas assez de clous"); + + if( Core.SE ) + { + index = AddCraft( typeof( RedHangingLantern ), 1044294, 1029412, 65.0, 90.0, typeof( Log ), 1044041, 5, 1044351 ); + AddRes( index, typeof( BlankScroll ), 1044377, 10, 1044378 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( WhiteHangingLantern ), 1044294, 1029416, 65.0, 90.0, typeof( Log ), 1044041, 5, 1044351 ); + AddRes( index, typeof( BlankScroll ), 1044377, 10, 1044378 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( ShojiScreen ), 1044294, 1029423, 80.0, 105.0, typeof( Log ), 1044041, 75, 1044351 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 60, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( BambooScreen ), 1044294, 1029428, 80.0, 105.0, typeof( Log ), 1044041, 75, 1044351 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 60, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + if( Core.AOS ) //Duplicate Entries to preserve ordering depending on era + { + index = AddCraft( typeof( FishingPole ), 1044294, 1023519, 68.4, 93.4, typeof( Log ), 1044041, 5, 1044351 ); //This is in the categor of Other during AoS + AddSkill( index, SkillName.Tailoring, 40.0, 45.0 ); + AddRes( index, typeof( Cloth ), 1044286, 5, 1044287 ); + } + + if (Core.ML) + { + index = AddCraft(typeof(RunedSwitch), 1044294, 1072896, 70.0, 120.0, typeof(Log), 1044041, 2, 1044351); + AddRes(index, typeof(EnchantedSwitch), 1072893, 1, 1053098); + AddRes(index, typeof(RunedPrism), 1073465, 1, 1053098); + AddRes(index, typeof(JeweledFiligree), 1072894, 1, 1053098); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(WarriorStatueSouthDeed), 1044294, 1072887, 0.0, 35.0, typeof(Log), 1044041, 250, 1044351); + AddRecipe(index, 300); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(WarriorStatueEastDeed), 1044294, 1072888, 0.0, 35.0, typeof(Log), 1044041, 250, 1044351); + AddRecipe(index, 301); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(SquirrelStatueSouthDeed), 1044294, 1072884, 0.0, 35.0, typeof(Log), 1044041, 250, 1044351); + AddRecipe(index, 302); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(SquirrelStatueEastDeed), 1044294, 1073398, 0.0, 35.0, typeof(Log), 1044041, 250, 1044351); + AddRecipe(index, 303); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(AcidProofRope), 1044294, 1074886, 80, 130.0, typeof(GreaterStrengthPotion), 1073466, 2, 1044253); + AddRes(index, typeof(ProtectionScroll), 1044395, 1, 1053098); + AddRes(index, typeof(SwitchItem), 1032127, 1, 1053098); + AddRareRecipe(index, 304); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + } + + // Furniture + AddCraft( typeof( FootStool ), 1044291, 1022910, 11.0, 36.0, typeof( Log ), 1044041, 9, 1044351 ); + AddCraft( typeof( Stool ), 1044291, 1022602, 11.0, 36.0, typeof( Log ), 1044041, 9, 1044351 ); + AddCraft( typeof( BambooChair ), 1044291, 1044300, 21.0, 46.0, typeof( Log ), 1044041, 13, 1044351 ); + AddCraft( typeof( WoodenChair ), 1044291, 1044301, 21.0, 46.0, typeof( Log ), 1044041, 13, 1044351 ); + AddCraft( typeof( FancyWoodenChairCushion ), 1044291, 1044302, 42.1, 67.1, typeof( Log ), 1044041, 15, 1044351 ); + AddCraft( typeof( WoodenChairCushion ), 1044291, 1044303, 42.1, 67.1, typeof( Log ), 1044041, 13, 1044351 ); + AddCraft( typeof( WoodenBench ), 1044291, 1022860, 52.6, 77.6, typeof( Log ), 1044041, 17, 1044351 ); + AddCraft( typeof( WoodenThrone ), 1044291, 1044304, 52.6, 77.6, typeof( Log ), 1044041, 17, 1044351 ); + AddCraft( typeof( Throne ), 1044291, 1044305, 73.6, 98.6, typeof( Log ), 1044041, 19, 1044351 ); + AddCraft( typeof( Nightstand ), 1044291, 1044306, 42.1, 67.1, typeof( Log ), 1044041, 17, 1044351 ); + AddCraft( typeof( WritingTable ), 1044291, 1022890, 63.1, 88.1, typeof( Log ), 1044041, 17, 1044351 ); + AddCraft( typeof( YewWoodTable ), 1044291, 1044307, 63.1, 88.1, typeof( Log ), 1044041, 23, 1044351 ); + AddCraft( typeof( LargeTable ), 1044291, 1044308, 84.2, 109.2, typeof( Log ), 1044041, 27, 1044351 ); + + // Scriptiz : chaises elfiques (bas�es sur les thrones) + if (Core.ML) + { + index = AddCraft(typeof(OrnateElvenChair), 1044291, 1072870, 80.0, 105.0, typeof(Log), 1044041, 30, 1044351); + AddRecipe(index, 305); + SetNeededExpansion(index, Expansion.ML); + } + + AddCraft(typeof(BigElvenChair), 1044291, 1072872, 75.6, 100.6, typeof(Log), 1044041, 24, 1044351); + AddCraft(typeof(ElvenReadingChair), 1044291, 1072873, 77.6, 102.6, typeof(Log), 1044041, 26, 1044351); + + + //Vinds : tables avec traverse, modulables + + index = AddCraft(typeof( TableRunnerPurple ), 1044291, "Table Avec Traverse (violette)", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof( TableRunnerBlue ), 1044291,"Table Avec Traverse (Bleue)", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof( TableRunnerRed ), 1044291, "Table Avec Traverse (Rouge)", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof( TableRunnerOrange ), 1044291, "Table Avec Traverse (Orange)", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof(TabletteRunner), 1044291, "Petite table avec Traverse (pivotable)", 63.1, 88.1, typeof(Log), 1044041, 18, 1044351); + AddSkill(index, SkillName.Tailoring, 92.1, 112.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof(ExtTabletteRunner), 1044291, "Rallonge avec traverse", 63.1, 88.1, typeof(Log), 1044041, 18, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof(TableLongRunnerW), 1044291, "Table longue avec traverse (W)", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 92.1, 112.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + index = AddCraft(typeof(TableLongRunnerC), 1044291, "Table longue avec traverse (c)", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + + index = AddCraft(typeof(TableLongRunnerE), 1044291, "Table longue avec traverse (E) ", 63.1, 88.1, typeof(Log), 1044041, 23, 1044351); + AddSkill(index, SkillName.Tailoring, 95.1, 115.1); + AddRes(index, typeof(Cloth), 1044286, 10, 1044287); + + + + + if( Core.SE ) + { + index = AddCraft( typeof( ElegantLowTable ), 1044291, 1030265, 80.0, 105.0, typeof( Log ), 1044041, 35, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PlainLowTable ), 1044291, 1030266, 80.0, 105.0, typeof( Log ), 1044041, 35, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + } + + // Containers + AddCraft( typeof( WoodenBox ), 1044292, 1023709, 21.0, 46.0, typeof( Log ), 1044041, 10, 1044351 ); + AddCraft( typeof( SmallCrate ), 1044292, 1044309, 10.0, 35.0, typeof( Log ), 1044041, 8 , 1044351 ); + AddCraft( typeof( MediumCrate ), 1044292, 1044310, 31.0, 56.0, typeof( Log ), 1044041, 15, 1044351 ); + AddCraft( typeof( LargeCrate ), 1044292, 1044311, 47.3, 72.3, typeof( Log ), 1044041, 18, 1044351 ); + AddCraft( typeof( WoodenChest ), 1044292, 1023650, 73.6, 98.6, typeof( Log ), 1044041, 20, 1044351 ); + AddCraft( typeof( EmptyBookcase ), 1044292, "Etag�re vide", 31.5, 56.5, typeof( Log ), 1044041, 25, 1044351 ); + + // Scriptiz : ajout de l'�tag�re remplie de livres + index = AddCraft(typeof(FullBookcase), 1044292, "Etag�re remplie", 84.2, 109.2, typeof(Log), 1044041, 25, 1044351); + AddRes(index, typeof(BlueBook), "Livres bleus", 3); + AddRes(index, typeof(RedBook), "Livres rouges", 3); + AddRes(index, typeof(TanBook), "Livres beiges", 3); + AddRes(index, typeof(BrownBook), "Livres bruns", 3); + + AddCraft( typeof( FancyArmoire ), 1044292, 1044312, 84.2, 109.2, typeof( Log ), 1044041, 35, 1044351 ); + AddCraft( typeof( Armoire ), 1044292, 1022643, 84.2, 109.2, typeof( Log ), 1044041, 35, 1044351 ); + + if( Core.SE ) + { + index = AddCraft( typeof( PlainWoodenChest ), 1044292, 1030251, 90.0, 115.0, typeof( Log ), 1044041, 30, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( OrnateWoodenChest ), 1044292, 1030253, 90.0, 115.0, typeof( Log ), 1044041, 30, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( GildedWoodenChest ), 1044292, 1030255, 90.0, 115.0, typeof( Log ), 1044041, 30, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( WoodenFootLocker ), 1044292, 1030257, 90.0, 115.0, typeof( Log ), 1044041, 30, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( FinishedWoodenChest ),1044292, 1030259, 90.0, 115.0, typeof( Log ), 1044041, 30, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( TallCabinet ), 1044292, 1030261, 90.0, 115.0, typeof( Log ), 1044041, 35, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( ShortCabinet ), 1044292, 1030263, 90.0, 115.0, typeof( Log ), 1044041, 35, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( RedArmoire ), 1044292, 1030328, 90.0, 115.0, typeof( Log ), 1044041, 40, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( ElegantArmoire ), 1044292, 1030330, 90.0, 115.0, typeof( Log ), 1044041, 40, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( MapleArmoire ), 1044292, 1030332, 90.0, 115.0, typeof( Log ), 1044041, 40, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( CherryArmoire ), 1044292, 1030334, 90.0, 115.0, typeof( Log ), 1044041, 40, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + } + + index = AddCraft( typeof( Keg ), 1044292, 1023711, 57.8, 82.8, typeof( BarrelStaves ), 1044288, 3, 1044253 ); + AddRes( index, typeof( BarrelHoops ), 1044289, 1, 1044253 ); + AddRes( index, typeof( BarrelLid ), 1044251, 1, 1044253 ); + + if (Core.ML) + { + index = AddCraft(typeof(ArcaneBookshelfSouthDeed), 1044292, 1072871, 94.7, 119.7, typeof(Log), 1044041, 80, 1044351); + AddRecipe(index, 306); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(ArcaneBookshelfEastDeed), 1044292, 1073371, 94.7, 119.7, typeof(Log), 1044041, 80, 1044351); + AddRecipe(index, 307); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + /* TODO + index = AddCraft( typeof( OrnateElvenChestSouthDeed ), 1044292, 1072862, 94.7, 119.7, typeof( Log ), 1044041, 40, 1044351 ); + AddRecipe( index, 308 ); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( OrnateElvenChestEastDeed ), 1044292, 1073383, 94.7, 119.7, typeof( Log ), 1044041, 40, 1044351 ); + AddRecipe( index, 309 ); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + */ + + index = AddCraft(typeof(ElvenDresserSouthDeed), 1044292, 1072864, 75.0, 100.0, typeof(Log), 1044041, 45, 1044351); + AddRecipe(index, 310); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(ElvenDresserEastDeed), 1044292, 1073388, 75.0, 100.0, typeof(Log), 1044041, 45, 1044351); + AddRecipe(index, 311); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + /* TODO + index = AddCraft( typeof( FancyElvenArmoire ), 1044292, 1072866, 80.0, 105.0, typeof( Log ), 1044041, 60, 1044351 ); + AddRecipe( index, 312 ); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + */ + } + + // Staves and Shields + AddCraft( typeof( ShepherdsCrook ), "Armes et Boucliers", 1023713, 78.9, 103.9, typeof( Log ), 1044041, 7, 1044351 ); + AddCraft(typeof(QuarterStaff), "Armes et Boucliers", 1023721, 73.6, 98.6, typeof(Log), 1044041, 6, 1044351); + AddCraft(typeof(GnarledStaff), "Armes et Boucliers", 1025112, 78.9, 103.9, typeof(Log), 1044041, 7, 1044351); + AddCraft(typeof(WoodenShield), "Armes et Boucliers", 1027034, 52.6, 77.6, typeof(Log), 1044041, 9, 1044351); + + if( !Core.AOS ) //Duplicate Entries to preserve ordering depending on era + { + index = AddCraft(typeof(FishingPole), "Armes et Boucliers", 1023519, 68.4, 93.4, typeof(Log), 1044041, 5, 1044351); //This is in the categor of Other during AoS + AddSkill( index, SkillName.Tailoring, 40.0, 45.0 ); + AddRes( index, typeof( Cloth ), 1044286, 5, 1044287 ); + } + + AddCraft(typeof(TrainingBow), "Armes et Boucliers", "Arc d'entrainement", 20.0, 40.0, typeof(Log), 1044041, 1, 1044351); + AddCraft(typeof(TrainingDagger), "Armes et Boucliers", "Dague d'entrainement", 20.0, 40.0, typeof(Log), 1044041, 1, 1044351); + AddCraft(typeof(TrainingSword), "Armes et Boucliers", "�p�e d'entrainement", 20.0, 40.0, typeof(Log), 1044041, 1, 1044351); + AddCraft(typeof(TrainingClub), "Armes et Boucliers", "Masse d'entrainement", 20.0, 40.0, typeof(Log), 1044041, 1, 1044351); + + if( Core.SE ) + { + index = AddCraft(typeof(Bokuto), "Armes et Boucliers", 1030227, 70.0, 95.0, typeof(Log), 1044041, 6, 1044351); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft(typeof(Fukiya), "Armes et Boucliers", 1030229, 60.0, 85.0, typeof(Log), 1044041, 6, 1044351); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft(typeof(Tetsubo), "Armes et Boucliers", 1030225, 80.0, 140.3, typeof(Log), 1044041, 10, 1044351); + SetNeededExpansion(index, Expansion.SE); + } + index = AddCraft(typeof(BlankWand), "Armes et Boucliers", "Baguette de bois", 60.0, 80.0, typeof(GoldIngot), "Lingot d'or", 1, "Vous n'avez pas de lingot d'or"); + AddRes(index, typeof(Log), 1044041, 1, 1044351); + ForceNonExceptional(index); + ForceNonLow(index); + + if (Core.ML) + { + index = AddCraft(typeof(PhantomStaff), 1044566, 1072919, 90.0, 130.0, typeof(Log), 1044041, 16, 1044351); + AddRes(index, typeof(DiseasedBark), 1032683, 1, 1053098); + AddRes(index, typeof(Putrefication), 1032678, 10, 1053098); + AddRes(index, typeof(Taint), 1032679, 10, 1053098); + AddRareRecipe(index, 313); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(ArcanistsWildStaff), 1044566, 1073549, 63.8, 113.8, typeof(Log), 1044041, 16, 1044351); + AddRes(index, typeof(WhitePearl), 1026253, 1, 1053098); + AddRecipe(index, 314); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(AncientWildStaff), 1044566, 1073550, 63.8, 113.8, typeof(Log), 1044041, 16, 1044351); + AddRes(index, typeof(PerfectEmerald), 1026251, 1, 1053098); + AddRecipe(index, 315); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(ThornedWildStaff), 1044566, 1073551, 63.8, 113.8, typeof(Log), 1044041, 16, 1044351); + AddRes(index, typeof(FireRuby), 1026254, 1, 1053098); + AddRecipe(index, 316); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(HardenedWildStaff), 1044566, 1073552, 63.8, 113.8, typeof(Log), 1044041, 16, 1044351); + AddRes(index, typeof(Turquoise), 1026250, 1, 1053098); + AddRecipe(index, 317); + SetNeededExpansion(index, Expansion.ML); + } + + // Armor + if (Core.ML) + { + index = AddCraft(typeof(IronwoodCrown), 1062760, 1072924, 85.0, 120.0, typeof(Log), 1044041, 10, 1044351); + AddRes(index, typeof(DiseasedBark), 1032683, 1, 1053098); + AddRes(index, typeof(Corruption), 1032676, 10, 1053098); + AddRes(index, typeof(Putrefication), 1032678, 10, 1053098); + AddRareRecipe(index, 318); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(BrambleCoat), 1062760, 1072925, 85.0, 120.0, typeof(Log), 1044041, 10, 1044351); + AddRes(index, typeof(DiseasedBark), 1032683, 1, 1053098); + AddRes(index, typeof(Taint), 1032679, 10, 1053098); + AddRes(index, typeof(Scourge), 1032677, 10, 1053098); + AddRareRecipe(index, 319); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + } + + // Instruments + index = AddCraft( typeof( LapHarp ), 1044293, 1023762, 63.1, 88.1, typeof( Log ), 1044041, 20, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 ); + + index = AddCraft( typeof( Harp ), 1044293, 1023761, 78.9, 103.9, typeof( Log ), 1044041, 35, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + AddRes( index, typeof( Cloth ), 1044286, 15, 1044287 ); + + index = AddCraft( typeof( Drums ), 1044293, 1023740, 57.8, 82.8, typeof( Log ), 1044041, 20, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 ); + + index = AddCraft( typeof( Lute ), 1044293, 1023763, 68.4, 93.4, typeof( Log ), 1044041, 25, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 ); + + index = AddCraft( typeof( Tambourine ), 1044293, 1023741, 57.8, 82.8, typeof( Log ), 1044041, 15, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 ); + + index = AddCraft( typeof( TambourineTassel ), 1044293, 1044320, 57.8, 82.8, typeof( Log ), 1044041, 15, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + AddRes( index, typeof( Cloth ), 1044286, 15, 1044287 ); + + if( Core.SE ) + { + index = AddCraft( typeof( BambooFlute ), 1044293, 1030247, 80.0, 105.0, typeof( Log ), 1044041, 15, 1044351 ); + AddSkill( index, SkillName.Musicianship, 45.0, 50.0 ); + SetNeededExpansion( index, Expansion.SE ); + } + + // Misc + index = AddCraft(typeof(SmallBedSouthDeed), 1044290, 1044321, 94.7, 119.8, typeof(Log), 1044041, 100, 1044351); + AddSkill(index, SkillName.Tailoring, 75.0, 80.0); + AddRes(index, typeof(Cloth), 1044286, 100, 1044287); + index = AddCraft(typeof(SmallBedEastDeed), 1044290, 1044322, 94.7, 119.8, typeof(Log), 1044041, 100, 1044351); + AddSkill(index, SkillName.Tailoring, 75.0, 80.0); + AddRes(index, typeof(Cloth), 1044286, 100, 1044287); + index = AddCraft(typeof(LargeBedSouthDeed), 1044290, 1044323, 94.7, 119.8, typeof(Log), 1044041, 150, 1044351); + AddSkill(index, SkillName.Tailoring, 75.0, 80.0); + AddRes(index, typeof(Cloth), 1044286, 150, 1044287); + index = AddCraft(typeof(LargeBedEastDeed), 1044290, 1044324, 94.7, 119.8, typeof(Log), 1044041, 150, 1044351); + AddSkill(index, SkillName.Tailoring, 75.0, 80.0); + AddRes( index, typeof( Cloth ), 1044286, 150, 1044287 ); + AddCraft( typeof( DartBoardSouthDeed ), 1044290, 1044325, 15.7, 40.7, typeof( Log ), 1044041, 5, 1044351 ); + AddCraft( typeof( DartBoardEastDeed ), 1044290, 1044326, 15.7, 40.7, typeof( Log ), 1044041, 5, 1044351 ); + AddCraft( typeof( BallotBoxDeed ), 1044290, 1044327, 47.3, 72.3, typeof( Log ), 1044041, 5, 1044351 ); + index = AddCraft( typeof( PentagramDeed ), 1044290, 1044328, 95.0, 125.0, typeof( Log ), 1044041, 100, 1044351 ); + AddSkill( index, SkillName.Magery, 75.0, 80.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 40, 1044037 ); + index = AddCraft( typeof( AbbatoirDeed ), 1044290, 1044329, 95.0, 125.0, typeof( Log ), 1044041, 100, 1044351 ); + AddSkill( index, SkillName.Magery, 50.0, 55.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 40, 1044037 ); + + if ( Core.AOS ) + { + AddCraft( typeof( PlayerBBEast ), 1044290, 1062420, 85.0, 110.0, typeof( Log ), 1044041, 50, 1044351 ); + AddCraft( typeof( PlayerBBSouth ), 1044290, 1062421, 85.0, 110.0, typeof( Log ), 1044041, 50, 1044351 ); + } + + if (Core.ML) + { + index = AddCraft(typeof(TallElvenBedSouthDeed), 1044290, 1072858, 94.7, 119.7, typeof(Log), 1044041, 200, 1044351); + AddSkill(index, SkillName.Tailoring, 75.0, 80.0); + AddRes(index, typeof(Cloth), 1044286, 100, 1044287); + AddRecipe(index, 320); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(TallElvenBedEastDeed), 1044290, 1072859, 94.7, 119.7, typeof(Log), 1044041, 200, 1044351); + AddSkill(index, SkillName.Tailoring, 75.0, 80.0); + AddRes(index, typeof(Cloth), 1044286, 100, 1044287); + AddRecipe(index, 321); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + } + + // Blacksmithy + index = AddCraft( typeof( SmallForgeDeed ), 1044296, 1044330, 73.6, 98.6, typeof( Log ), 1044041, 5, 1044351 ); + AddSkill( index, SkillName.Blacksmith, 75.0, 80.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 75, 1044037 ); + index = AddCraft( typeof( LargeForgeEastDeed ), 1044296, 1044331, 78.9, 103.9, typeof( Log ), 1044041, 5, 1044351 ); + AddSkill( index, SkillName.Blacksmith, 80.0, 85.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 100, 1044037 ); + index = AddCraft( typeof( LargeForgeSouthDeed ), 1044296, 1044332, 78.9, 103.9, typeof( Log ), 1044041, 5, 1044351 ); + AddSkill( index, SkillName.Blacksmith, 80.0, 85.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 100, 1044037 ); + index = AddCraft( typeof( AnvilEastDeed ), 1044296, 1044333, 73.6, 98.6, typeof( Log ), 1044041, 5, 1044351 ); + AddSkill( index, SkillName.Blacksmith, 75.0, 80.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 150, 1044037 ); + index = AddCraft( typeof( AnvilSouthDeed ), 1044296, 1044334, 73.6, 98.6, typeof( Log ), 1044041, 5, 1044351 ); + AddSkill( index, SkillName.Blacksmith, 75.0, 80.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 150, 1044037 ); + + // Training + index = AddCraft( typeof( TrainingDummyEastDeed ), 1044297, 1044335, 68.4, 93.4, typeof( Log ), 1044041, 55, 1044351 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 60, 1044287 ); + index = AddCraft( typeof( TrainingDummySouthDeed ), 1044297, 1044336, 68.4, 93.4, typeof( Log ), 1044041, 55, 1044351 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 60, 1044287 ); + index = AddCraft( typeof( PickpocketDipEastDeed ), 1044297, 1044337, 73.6, 98.6, typeof( Log ), 1044041, 65, 1044351 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 60, 1044287 ); + index = AddCraft( typeof( PickpocketDipSouthDeed ), 1044297, 1044338, 73.6, 98.6, typeof( Log ), 1044041, 65, 1044351 ); + AddSkill( index, SkillName.Tailoring, 50.0, 55.0 ); + AddRes( index, typeof( Cloth ), 1044286, 60, 1044287 ); + + // Tailoring + index = AddCraft( typeof( Dressform ), 1044298, 1044339, 63.1, 88.1, typeof( Log ), 1044041, 25, 1044351 ); + AddSkill( index, SkillName.Tailoring, 65.0, 70.0 ); + AddRes( index, typeof( Cloth ), 1044286, 10, 1044287 ); + index = AddCraft( typeof( SpinningwheelEastDeed ), 1044298, 1044341, 73.6, 98.6, typeof( Log ), 1044041, 75, 1044351 ); + AddSkill( index, SkillName.Tailoring, 65.0, 70.0 ); + AddRes( index, typeof( Cloth ), 1044286, 25, 1044287 ); + index = AddCraft( typeof( SpinningwheelSouthDeed ), 1044298, 1044342, 73.6, 98.6, typeof( Log ), 1044041, 75, 1044351 ); + AddSkill( index, SkillName.Tailoring, 65.0, 70.0 ); + AddRes( index, typeof( Cloth ), 1044286, 25, 1044287 ); + index = AddCraft( typeof( LoomEastDeed ), 1044298, 1044343, 84.2, 109.2, typeof( Log ), 1044041, 85, 1044351 ); + AddSkill( index, SkillName.Tailoring, 65.0, 70.0 ); + AddRes( index, typeof( Cloth ), 1044286, 25, 1044287 ); + index = AddCraft( typeof( LoomSouthDeed ), 1044298, 1044344, 84.2, 109.2, typeof( Log ), 1044041, 85, 1044351 ); + AddSkill( index, SkillName.Tailoring, 65.0, 70.0 ); + AddRes( index, typeof( Cloth ), 1044286, 25, 1044287 ); + + // Cooking + index = AddCraft( typeof( StoneOvenEastDeed ), 1044299, 1044345, 68.4, 93.4, typeof( Log ), 1044041, 85, 1044351 ); + AddSkill( index, SkillName.Tinkering, 50.0, 55.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 125, 1044037 ); + index = AddCraft( typeof( StoneOvenSouthDeed ), 1044299, 1044346, 68.4, 93.4, typeof( Log ), 1044041, 85, 1044351 ); + AddSkill( index, SkillName.Tinkering, 50.0, 55.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 125, 1044037 ); + index = AddCraft( typeof( FlourMillEastDeed ), 1044299, 1044347, 94.7, 119.7, typeof( Log ), 1044041, 100, 1044351 ); + AddSkill( index, SkillName.Tinkering, 50.0, 55.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 50, 1044037 ); + index = AddCraft( typeof( FlourMillSouthDeed ), 1044299, 1044348, 94.7, 119.7, typeof( Log ), 1044041, 100, 1044351 ); + AddSkill( index, SkillName.Tinkering, 50.0, 55.0 ); + AddRes( index, typeof( IronIngot ), 1044036, 50, 1044037 ); + AddCraft( typeof( WaterTroughEastDeed ), 1044299, 1044349, 94.7, 119.7, typeof( Log ), 1044041, 150, 1044351 ); + AddCraft( typeof( WaterTroughSouthDeed ), 1044299, 1044350, 94.7, 119.7, typeof( Log ), 1044041, 150, 1044351 ); + + MarkOption = true; + Repair = Core.AOS; + + SetSubRes( typeof( Log ), 1072643 ); + + // Add every material you want the player to be able to choose from + // This will override the overridable material TODO: Verify the required skill amount + AddSubRes( typeof( Log ), 1072643, 00.0, 1044041, 1072652 ); + AddSubRes( typeof( OakLog ), 1072644, 65.0, 1044041, 1072652 ); + AddSubRes( typeof( AshLog ), 1072645, 80.0, 1044041, 1072652 ); + AddSubRes( typeof( YewLog ), 1072646, 95.0, 1044041, 1072652 ); + AddSubRes( typeof( HeartwoodLog ), 1072647, 100.0, 1044041, 1072652 ); + AddSubRes( typeof( BloodwoodLog ), 1072648, 100.0, 1044041, 1072652 ); + AddSubRes( typeof( FrostwoodLog ), 1072649, 100.0, 1044041, 1072652 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefCartography.cs b/Scripts/Engines/Craft/DefCartography.cs new file mode 100644 index 0000000..581942b --- /dev/null +++ b/Scripts/Engines/Craft/DefCartography.cs @@ -0,0 +1,88 @@ +using System; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class DefCartography : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Cartography; } + } + + public override int GumpTitleNumber + { + get { return 1044008; } //
CARTOGRAPHY MENU
+ } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.0; // 0% + } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefCartography(); + + return m_CraftSystem; + } + } + + private DefCartography() : base( 1, 1, 1.25 )// base( 1, 1, 3.0 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + public override void PlayCraftEffect( Mobile from ) + { + from.PlaySound( 0x249 ); + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + AddCraft( typeof( LocalMap ), 1044448, 1015230, 10.0, 70.0, typeof( BlankMap ), 1044449, 1, 1044450 ); + AddCraft( typeof( CityMap ), 1044448, 1015231, 25.0, 85.0, typeof( BlankMap ), 1044449, 1, 1044450 ); + AddCraft( typeof( SeaChart ), 1044448, 1015232, 35.0, 95.0, typeof( BlankMap ), 1044449, 1, 1044450 ); + AddCraft( typeof( WorldMap ), 1044448, 1015233, 39.5, 99.5, typeof( BlankMap ), 1044449, 1, 1044450 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefCooking.cs b/Scripts/Engines/Craft/DefCooking.cs new file mode 100644 index 0000000..5b933de --- /dev/null +++ b/Scripts/Engines/Craft/DefCooking.cs @@ -0,0 +1,344 @@ +using System; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class DefCooking : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Cooking; } + } + + public override int GumpTitleNumber + { + get { return 1044003; } //
COOKING MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefCooking(); + + return m_CraftSystem; + } + } + + public override CraftECA ECA{ get{ return CraftECA.ChanceMinusSixtyToFourtyFive; } } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.0; // 0% + } + + private DefCooking() : base( 1, 1, 1.25 )// base( 1, 1, 1.5 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + public override void PlayCraftEffect( Mobile from ) + { + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + int index = -1; + + /* Begin Ingredients */ + index = AddCraft( typeof( SackFlour ), 1044495, 1024153, 0.0, 100.0, typeof( WheatSheaf ), 1044489, 2, 1044490 ); + SetNeedMill( index, true ); + + index = AddCraft( typeof( Dough ), 1044495, 1024157, 0.0, 100.0, typeof( SackFlour ), 1044468, 1, 1044253 ); + AddRes( index, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + + index = AddCraft( typeof( SweetDough ), 1044495, 1041340, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( JarHoney ), 1044472, 1, 1044253 ); + + index = AddCraft( typeof( CakeMix ), 1044495, 1041002, 0.0, 100.0, typeof( SackFlour ), 1044468, 1, 1044253 ); + AddRes( index, typeof( SweetDough ), 1044475, 1, 1044253 ); + + index = AddCraft( typeof( CookieMix ), 1044495, 1024159, 0.0, 100.0, typeof( JarHoney ), 1044472, 1, 1044253 ); + AddRes( index, typeof( SweetDough ), 1044475, 1, 1044253 ); + /*D�sactiv� pour le moment + if (Core.ML) + { + index = AddCraft(typeof(CocoaButter), 1044495, 1079998, 0.0, 100.0, typeof(CocoaPulp), 1080530, 1, 1044253); + SetItemHue(index, 0x457); + SetNeededExpansion(index, Expansion.ML); + SetNeedOven(index, true); + + index = AddCraft(typeof(CocoaLiquor), 1044495, 1079999, 0.0, 100.0, typeof(CocoaPulp), 1080530, 1, 1044253); + AddRes(index, typeof(EmptyPewterBowl), 1025629, 1, 1044253); + SetItemHue(index, 0x46A); + SetNeededExpansion(index, Expansion.ML); + SetNeedOven(index, true); + }*/ + /* End Ingredients */ + + /* Begin Preparations */ + index = AddCraft( typeof( UnbakedQuiche ), 1044496, 1041339, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( Eggs ), 1044477, 1, 1044253 ); + + // TODO: This must also support chicken and lamb legs + index = AddCraft( typeof( UnbakedMeatPie ), 1044496, 1041338, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( RawRibs ), 1044482, 1, 1044253 ); + + index = AddCraft( typeof( UncookedSausagePizza ), 1044496, 1041337, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( Sausage ), 1044483, 1, 1044253 ); + + index = AddCraft( typeof( UncookedCheesePizza ), 1044496, 1041341, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( CheeseWheel ), 1044486, 1, 1044253 ); + + index = AddCraft( typeof( UnbakedFruitPie ), 1044496, 1041334, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( Pear ), 1044481, 1, 1044253 ); + + index = AddCraft( typeof( UnbakedPeachCobbler ), 1044496, 1041335, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( Peach ), 1044480, 1, 1044253 ); + + index = AddCraft( typeof( UnbakedApplePie ), 1044496, 1041336, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( Apple ), 1044479, 1, 1044253 ); + + index = AddCraft( typeof( UnbakedPumpkinPie ), 1044496, 1041342, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + AddRes( index, typeof( Pumpkin ), 1044484, 1, 1044253 ); + + if ( Core.SE ) + { + index = AddCraft( typeof( GreenTea ), 1044496, 1030315, 80.0, 130.0, typeof( GreenTeaBasket ), 1030316, 1, 1044253 ); + AddRes( index, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( WasabiClumps ), 1044496, 1029451, 70.0, 120.0, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + AddRes( index, typeof( WoodenBowlOfPeas ), 1025633, 3, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( SushiRolls ), 1044496, 1030303, 90.0, 120.0, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + AddRes( index, typeof( RawFishSteak ), 1044476, 10, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( SushiPlatter ), 1044496, 1030305, 90.0, 120.0, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + AddRes( index, typeof( RawFishSteak ), 1044476, 10, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + } + + index = AddCraft(typeof(TribalPaint), 1044496, 1040000, Core.ML ? 55.0 : 80.0, Core.ML ? 105.0 : 80.0, typeof(SackFlour), 1044468, 1, 1044253); + AddRes( index, typeof( TribalBerry ), 1046460, 1, 1044253 ); + + if ( Core.SE ) + { + index = AddCraft( typeof( EggBomb ), 1044496, 1030249, 90.0, 120.0, typeof( Eggs ), 1044477, 1, 1044253 ); + AddRes( index, typeof( SackFlour ), 1044468, 3, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + } + /* End Preparations */ + + /* Begin Baking */ + index = AddCraft( typeof( BreadLoaf ), 1044497, 1024156, 0.0, 100.0, typeof( Dough ), 1044469, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( Cookies ), 1044497, 1025643, 0.0, 100.0, typeof( CookieMix ), 1044474, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( Cake ), 1044497, 1022537, 0.0, 100.0, typeof( CakeMix ), 1044471, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( Muffins ), 1044497, 1022539, 0.0, 100.0, typeof( SweetDough ), 1044475, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( Quiche ), 1044497, 1041345, 0.0, 100.0, typeof( UnbakedQuiche ), 1044518, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( MeatPie ), 1044497, 1041347, 0.0, 100.0, typeof( UnbakedMeatPie ), 1044519, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( SausagePizza ), 1044497, 1044517, 0.0, 100.0, typeof( UncookedSausagePizza ), 1044520, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( CheesePizza ), 1044497, 1044516, 0.0, 100.0, typeof( UncookedCheesePizza ), 1044521, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( FruitPie ), 1044497, 1041346, 0.0, 100.0, typeof( UnbakedFruitPie ), 1044522, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( PeachCobbler ), 1044497, 1041344, 0.0, 100.0, typeof( UnbakedPeachCobbler ), 1044523, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( ApplePie ), 1044497, 1041343, 0.0, 100.0, typeof( UnbakedApplePie ), 1044524, 1, 1044253 ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( PumpkinPie ), 1044497, 1041348, 0.0, 100.0, typeof( UnbakedPumpkinPie ), 1046461, 1, 1044253 ); + SetNeedOven( index, true ); + + if ( Core.SE ) + { + index = AddCraft( typeof( MisoSoup ), 1044497, 1030317, 60.0, 110.0, typeof( RawFishSteak ), 1044476, 1, 1044253 ); + AddRes( index, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( WhiteMisoSoup ), 1044497, 1030318, 60.0, 110.0, typeof( RawFishSteak ), 1044476, 1, 1044253 ); + AddRes( index, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( RedMisoSoup ), 1044497, 1030319, 60.0, 110.0, typeof( RawFishSteak ), 1044476, 1, 1044253 ); + AddRes( index, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + SetNeedOven( index, true ); + + index = AddCraft( typeof( AwaseMisoSoup ), 1044497, 1030320, 60.0, 110.0, typeof( RawFishSteak ), 1044476, 1, 1044253 ); + AddRes( index, typeof( BaseBeverage ), 1046458, 1, 1044253 ); + SetNeededExpansion( index, Expansion.SE ); + SetNeedOven( index, true ); + } + /* End Baking */ + + /* Begin Barbecue */ + index = AddCraft( typeof( CookedBird ), 1044498, 1022487, 0.0, 100.0, typeof( RawBird ), 1044470, 1, 1044253 ); + SetNeedHeat( index, true ); + SetUseAllRes( index, true ); + + index = AddCraft( typeof( ChickenLeg ), 1044498, 1025640, 0.0, 100.0, typeof( RawChickenLeg ), 1044473, 1, 1044253 ); + SetNeedHeat( index, true ); + SetUseAllRes( index, true ); + + index = AddCraft( typeof( FishSteak ), 1044498, 1022427, 0.0, 100.0, typeof( RawFishSteak ), 1044476, 1, 1044253 ); + SetNeedHeat( index, true ); + SetUseAllRes( index, true ); + + index = AddCraft( typeof( FriedEggs ), 1044498, 1022486, 0.0, 100.0, typeof( Eggs ), 1044477, 1, 1044253 ); + SetNeedHeat( index, true ); + SetUseAllRes( index, true ); + + index = AddCraft( typeof( LambLeg ), 1044498, 1025642, 0.0, 100.0, typeof( RawLambLeg ), 1044478, 1, 1044253 ); + SetNeedHeat( index, true ); + SetUseAllRes( index, true ); + + index = AddCraft( typeof( Ribs ), 1044498, 1022546, 0.0, 100.0, typeof( RawRibs ), 1044485, 1, 1044253 ); + SetNeedHeat( index, true ); + SetUseAllRes( index, true ); + /* End Barbecue */ + + index = AddCraft(typeof(TitanOre), "Misc", "Gravat de titan", 60.0, 85.0, typeof(TitanToothPowder), "Poudre de dent de titan", 1, "Vous n'avez pas assez de poudre de dent de titan"); + SetNeedOven(index, true); + SetUseAllRes(index, true); + + index = AddCraft(typeof(FruitBasket), "Misc", "Panier de fruits", 30.0, 50.0, typeof(Basket), "Panier vide", 1, "Vous n'avez pas de panier convenable"); + AddRes(index, typeof(Pear), "Poire", 1, "Vous n'avez rien pour bien agr�menter le tout"); + AddRes(index, typeof(Grapes), "Raisin", 1, "Vous n'avez rien pour bien agr�menter le tout"); + AddRes(index, typeof(Peach), "P�che", 1, "Vous n'avez rien pour bien agr�menter le tout"); + AddRes(index, typeof(Apple), "Pomme", 1, "Vous n'avez rien pour bien agr�menter le tout"); + AddRes(index, typeof(CreateFoodScroll), "Parchemin de cr�ation de nourriture", 1, "Un parchemin de cr�ation de nourriture ajouterait de la fantaisie"); + + index = AddCraft(typeof(CacaoPowder), "Misc", "Poudre de cacao", 60.0, 85.0, typeof(CacaoSeed), "F�ve de Cacao", 1, "Vous avez besoin de davantage de f�ves"); + SetNeedOven(index, true); + SetUseAllRes(index, true); + + index = AddCraft(typeof(RedLollipop), "Friandises", "Sucette � la pomme", 40.0, 80.0, typeof(Kindling), 1015157, 1, "Vous n'avez rien pour faire le baton"); + AddRes(index, typeof(JarHoney), 1044472, 1, "Vous n'avez rien pour cr�er la consistance"); + AddRes(index, typeof(Apple), "Apple", 1, "Vous n'avez rien pour cr�er la saveur"); + SetNeedHeat(index, true); + + index = AddCraft(typeof(GreenLollipop), "Friandises", "Sucette au melon d'eau", 40.0, 80.0, typeof(Kindling), 1015157, 1, "Vous n'avez rien pour faire le baton"); + AddRes(index, typeof(JarHoney), 1044472, 1, "Vous n'avez rien pour cr�er la consistance"); + AddRes(index, typeof(Watermelon), "Watermelon", 1, "Vous n'avez rien pour cr�er la saveur"); + SetNeedHeat(index, true); + + index = AddCraft(typeof(YellowLollipop), "Friandises", "Sucette au citron", 40.0, 80.0, typeof(Kindling), 1015157, 1, "Vous n'avez rien pour faire le baton"); + AddRes(index, typeof(JarHoney), 1044472, 1, "Vous n'avez rien pour cr�er la consistance"); + AddRes(index, typeof(Lemon), "Lemon", 1, "Vous n'avez rien pour cr�er la saveur"); + SetNeedHeat(index, true); + + index = AddCraft(typeof(RedCandyCane), "Friandises", "Canne aux fruits", 45.0, 70.0, typeof(Sugar), "Sucre", 2, "Vous n'avez pas assez de sucre"); + AddRes(index, typeof(Pear), "Poire", 1, "Vous n'avez rien pour cr�er la saveur"); + AddRes(index, typeof(Peach), "P�che", 1, "Vous n'avez rien pour cr�er la saveur"); + + + index = AddCraft(typeof(GreenCandyCane), "Friandises", "Canne � la limette", 45.0, 70.0, typeof(Sugar), "Sucre", 2, "Vous n'avez pas assez de sucre"); + AddRes(index, typeof(Lime), "Lime", 1, "Vous n'avez rien pour cr�er la saveur"); + + index = AddCraft(typeof(GingerBreadCookie), "Friandises", "Pain d'�pices", 50.0, 75.0, typeof(GingerRoot), "Gingembre", 2, "Vous n'avez pas assez de gingembre"); + AddRes(index, typeof(Sugar), "Sucre", 1, "Vous n'avez rien pour le personnaliser"); + SetNeedOven(index, true); + + index = AddCraft(typeof(Jellybeans), "Friandises", "Drag�es surprises", 60.0, 85.0, typeof(Sugar), "Sucre", 5, "Vous n'avez pas assez de sucre"); + AddRes(index, typeof(FruitBasket), "Panier de fruits", 1, "Vous aurez besoin de davantage de saveurs"); + + index = AddCraft(typeof(Nougat), "Friandises", "Nougat", 70.0, 95.0, typeof(CacaoPowder), "Poudre de cacao", 2, "Vous n'avez pas assez de cacao"); + AddRes(index, typeof(Sugar), "Sucre", 1, "Vous n'avez pas assez de sucre"); + + index = AddCraft(typeof(GingerBreadHouseDeed), "Friandises", "Maison en pain d'�pices (d�coration)", 80.0, 110.0, typeof(GingerRoot), "Gingembre", 10, "Vous n'avez pas assez de gingembre"); + AddRes(index, typeof(Sugar), "Sucre", 5, "Vous n'avez pas assez de sucre pour la d�coration"); + AddRes(index, typeof(CacaoPowder), "Poudre de Cacao", 10, "Vous n'avez pas assez de cacao pour le terrain"); + AddRes(index, typeof(Jellybeans), "Drag�es surprises", 4, "Vous n'avez pas assez de drag�es pour l'arbre"); + AddRes(index, typeof(RedCandyCane), "Canne aux fruits", 2, "Vous n'avez pas assez de cannes pour les poteaux"); + AddRes(index, typeof(GingerBreadCookie), "Bonhomme en pain d'�pices", 2, "Il faut des gens pour habiter dans cette maison!"); + SetNeedOven(index, true); + + /* Begin Chocolatiering */ + if (Core.ML) + { + index = AddCraft(typeof(DarkChocolate), 1080001, 1079994, 15.0, 100.0, typeof(SackOfSugar), 1079997, 1, 1044253); + AddRes(index, typeof(CocoaButter), 1079998, 1, 1044253); + AddRes(index, typeof(CocoaLiquor), 1079999, 1, 1044253); + SetItemHue(index, 0x465); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(MilkChocolate), 1080001, 1079995, 32.5, 107.5, typeof(SackOfSugar), 1079997, 1, 1044253); + AddRes(index, typeof(CocoaButter), 1079998, 1, 1044253); + AddRes(index, typeof(CocoaLiquor), 1079999, 1, 1044253); + AddRes(index, typeof(BaseBeverage), 1022544, 1, 1044253); + SetBeverageType(index, BeverageType.Milk); + SetItemHue(index, 0x461); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(WhiteChocolate), 1080001, 1079996, 52.5, 127.5, typeof(SackOfSugar), 1079997, 1, 1044253); + AddRes(index, typeof(CocoaButter), 1079998, 1, 1044253); + AddRes(index, typeof(Vanilla), 1080000, 1, 1044253); + AddRes(index, typeof(BaseBeverage), 1022544, 1, 1044253); + SetBeverageType(index, BeverageType.Milk); + SetItemHue(index, 0x47E); + SetNeededExpansion(index, Expansion.ML); + } + /* End Chocolatiering */ + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefGlassblowing.cs b/Scripts/Engines/Craft/DefGlassblowing.cs new file mode 100644 index 0000000..fca20e2 --- /dev/null +++ b/Scripts/Engines/Craft/DefGlassblowing.cs @@ -0,0 +1,153 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Craft +{ + public class DefGlassblowing : CraftSystem + { + public override SkillName MainSkill + { + get{ return SkillName.Alchemy; } + } + + public override int GumpTitleNumber + { + get{ return 1044622; } //
Glassblowing MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefGlassblowing(); + + return m_CraftSystem; + } + } + + public override double GetChanceAtMin( CraftItem item ) + { + if (item.ItemType == typeof(HollowPrism)) + return 0.5; // 50% + + return 0.0; // 0% + } + + private DefGlassblowing() : base( 1, 1, 1.25 )// base( 1, 2, 1.7 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckTool( tool, from ) ) + return 1048146; // If you have a tool equipped, you must use that tool. + else if ( !(from is PlayerMobile && ((PlayerMobile)from).Glassblowing && from.Skills[SkillName.Alchemy].Base >= 100.0) ) + return 1044634; // You havent learned glassblowing. + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + bool anvil, forge; + + DefBlacksmithy.CheckAnvilAndForge( from, 2, out anvil, out forge ); + + if ( forge ) + return 0; + + return 1044628; // You must be near a forge to blow glass. + } + + public override void PlayCraftEffect( Mobile from ) + { + from.PlaySound( 0x2B ); // bellows + + //if ( from.Body.Type == BodyType.Human && !from.Mounted ) + // from.Animate( 9, 5, 1, true, false, 0 ); + + //new InternalTimer( from ).Start(); + } + + // Delay to synchronize the sound with the hit on the anvil + private class InternalTimer : Timer + { + private Mobile m_From; + + public InternalTimer( Mobile from ) : base( TimeSpan.FromSeconds( 0.7 ) ) + { + m_From = from; + } + + protected override void OnTick() + { + m_From.PlaySound( 0x2A ); + } + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + from.PlaySound( 0x41 ); // glass breaking + + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + int index = AddCraft( typeof( Bottle ), 1044050, 1023854, 52.5, 102.5, typeof( Sand ), 1044625, 1, 1044627 ); + SetUseAllRes( index, true ); + + // Scriptiz : Ajout des verres craftables + AddCraft(typeof(Glass), 1044050, 1116636, 42.5, 92.5, typeof(Sand), 1044625, 1, 1044627); + + AddCraft( typeof( SmallFlask ), 1044050, 1044610, 52.5, 102.5, typeof( Sand ), 1044625, 2, 1044627 ); + AddCraft( typeof( MediumFlask ), 1044050, 1044611, 52.5, 102.5, typeof( Sand ), 1044625, 3, 1044627 ); + AddCraft( typeof( CurvedFlask ), 1044050, 1044612, 55.0, 105.0, typeof( Sand ), 1044625, 2, 1044627 ); + AddCraft( typeof( LongFlask ), 1044050, 1044613, 57.5, 107.5, typeof( Sand ), 1044625, 4, 1044627 ); + AddCraft( typeof( LargeFlask ), 1044050, 1044623, 60.0, 110.0, typeof( Sand ), 1044625, 5, 1044627 ); + AddCraft( typeof( AniSmallBlueFlask ), 1044050, 1044614, 60.0, 110.0, typeof( Sand ), 1044625, 5, 1044627 ); + AddCraft( typeof( AniLargeVioletFlask ), 1044050, 1044615, 60.0, 110.0, typeof( Sand ), 1044625, 5, 1044627 ); + AddCraft( typeof( AniRedRibbedFlask ), 1044050, 1044624, 60.0, 110.0, typeof( Sand ), 1044625, 7, 1044627 ); + AddCraft( typeof( EmptyVialsWRack ), 1044050, 1044616, 65.0, 115.0, typeof( Sand ), 1044625, 8, 1044627 ); + AddCraft( typeof( FullVialsWRack ), 1044050, 1044617, 65.0, 115.0, typeof( Sand ), 1044625, 9, 1044627 ); + AddCraft( typeof( SpinningHourglass ), 1044050, 1044618, 75.0, 125.0, typeof( Sand ), 1044625, 10, 1044627 ); + + + if (Core.ML) + { + index = AddCraft(typeof(HollowPrism), 1044050, 1072895, 100.0, 150.0, typeof(Sand), 1044625, 8, 1044627); + SetNeededExpansion(index, Expansion.ML); + } + + // Plume : Ajout de la fiole d'alchimie + AddCraft(typeof(AlchemyVial), 1044050, "Fiole d'alchimie", 70.0, 115.0, typeof(Sand), 1044625, 2, 1044627); + + index = AddCraft(typeof(MysticPowerCrystal), 1044050, 1072895, 40.0, 130.0, typeof(Sand), 1044625, 20, 1044627); + AddSkill(index, SkillName.SpiritSpeak, 20.0, 110.0); + AddRes(index, typeof(BaseGem), "Gemmes (vari�es)", 100, "Vous n'avez pas assez de gemmes"); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefInscription.cs b/Scripts/Engines/Craft/DefInscription.cs new file mode 100644 index 0000000..286bc15 --- /dev/null +++ b/Scripts/Engines/Craft/DefInscription.cs @@ -0,0 +1,381 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Engines.Craft +{ + public class DefInscription : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Inscribe; } + } + + public override int GumpTitleNumber + { + get { return 1044009; } //
INSCRIPTION MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if (m_CraftSystem == null) + m_CraftSystem = new DefInscription(); + + return m_CraftSystem; + } + } + + public override double GetChanceAtMin(CraftItem item) + { + return 0.0; // 0% + } + + private DefInscription() + : base(1, 1, 1.25)// base( 1, 1, 3.0 ) + { + } + + public override int CanCraft(Mobile from, BaseTool tool, Type typeItem) + { + if (tool == null || tool.Deleted || tool.UsesRemaining < 0) + return 1044038; // You have worn out your tool! + else if (!BaseTool.CheckAccessible(tool, from)) + return 1044263; // The tool must be on your person to use. + + if (typeItem != null) + { + object o = Activator.CreateInstance(typeItem); + + if (o is SpellScroll) + { + SpellScroll scroll = (SpellScroll)o; + Spellbook book = Spellbook.Find(from, scroll.SpellID); + + bool hasSpell = (book != null && book.HasSpell(scroll.SpellID)); + + scroll.Delete(); + + return (hasSpell ? 0 : 1042404); // null : You don't have that spell! + } + else if (o is Item) + { + ((Item)o).Delete(); + } + } + + return 0; + } + + public override void PlayCraftEffect(Mobile from) + { + from.PlaySound(0x249); + } + + private static Type typeofSpellScroll = typeof(SpellScroll); + + public override int PlayEndingEffect(Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item) + { + if (toolBroken) + from.SendLocalizedMessage(1044038); // You have worn out your tool + + if (!typeofSpellScroll.IsAssignableFrom(item.ItemType)) // not a scroll + { + if (failed) + { + if (lostMaterial) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if (quality == 0) + return 502785; // You were barely able to make this item. It's quality is below average. + else if (makersMark && quality == 2) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if (quality == 2) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + else + { + if (failed) + return 501630; // You fail to inscribe the scroll, and the scroll is ruined. + else + return 501629; // You inscribe the spell and put the scroll in your backpack. + } + } + + private int m_Circle, m_Mana; + + private enum Reg { BlackPearl, Bloodmoss, Garlic, Ginseng, MandrakeRoot, Nightshade, SulfurousAsh, SpidersSilk } + + private Type[] m_RegTypes = new Type[] + { + typeof( BlackPearl ), + typeof( Bloodmoss ), + typeof( Garlic ), + typeof( Ginseng ), + typeof( MandrakeRoot ), + typeof( Nightshade ), + typeof( SulfurousAsh ), + typeof( SpidersSilk ) + }; + + private int m_Index; + + private void AddSpell(Type type, params Reg[] regs) + { + double minSkill, maxSkill; + + switch (m_Circle) + { + default: + case 0: minSkill = -25.0; maxSkill = 25.0; break; + case 1: minSkill = -10.8; maxSkill = 39.2; break; + case 2: minSkill = 03.5; maxSkill = 53.5; break; + case 3: minSkill = 17.8; maxSkill = 67.8; break; + case 4: minSkill = 32.1; maxSkill = 82.1; break; + case 5: minSkill = 46.4; maxSkill = 96.4; break; + case 6: minSkill = 60.7; maxSkill = 120.7; break; // Scirptiz : d�faut = 110.7 + case 7: minSkill = 75.0; maxSkill = 160.0; break; // Scriptiz : d�faut = 125.0 + } + + int amount = (m_Circle >= 7 ? 2 : 1); // Scriptiz : par d�faut 1 de chaque r�actif, maintenant 2 r�actifs pour cercle 8 et 1 r�actif pour les autres + int index = AddCraft(type, 1044369 + m_Circle, 1044381 + m_Index++, minSkill, maxSkill, m_RegTypes[(int)regs[0]], 1044353 + (int)regs[0], amount, 1044361 + (int)regs[0]); + + for (int i = 1; i < regs.Length; ++i) + AddRes(index, m_RegTypes[(int)regs[i]], 1044353 + (int)regs[i], amount, 1044361 + (int)regs[i]); + + AddRes(index, typeof(BlankScroll), 1044377, 1, 1044378); + + int mana = (int)(m_Mana * 1.2); // Scriptiz : 20% de mana n�cessaire en plus + SetManaReq(index, mana); + } + + private void AddNecroSpell(int spell, int mana, double minSkill, Type type, params Type[] regs) + { + int id = CraftItem.ItemIDOf(regs[0]); + + int index = AddCraft(type, 1061677, 1060509 + spell, minSkill, minSkill + 1.0, regs[0], id < 0x4000 ? 1020000 + id : 1078872 + id, 1, 501627); //Yes, on OSI it's only 1.0 skill diff'. Don't blame me, blame OSI. + + for (int i = 1; i < regs.Length; ++i) + { + id = CraftItem.ItemIDOf(regs[i]); + AddRes(index, regs[i], id < 0x4000 ? 1020000 + id : 1078872 + id, 1, 501627); + } + + AddRes(index, typeof(BlankScroll), 1044377, 1, 1044378); + + SetManaReq(index, mana); + } + + public override void InitCraftList() + { + m_Circle = 0; + m_Mana = 4; + + AddSpell(typeof(ReactiveArmorScroll), Reg.Garlic, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(ClumsyScroll), Reg.Bloodmoss, Reg.Nightshade); + AddSpell(typeof(CreateFoodScroll), Reg.Garlic, Reg.Ginseng, Reg.MandrakeRoot); + AddSpell(typeof(FeeblemindScroll), Reg.Nightshade, Reg.Ginseng); + AddSpell(typeof(HealScroll), Reg.Garlic, Reg.Ginseng, Reg.SpidersSilk); + AddSpell(typeof(MagicArrowScroll), Reg.SulfurousAsh); + AddSpell(typeof(NightSightScroll), Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(WeakenScroll), Reg.Garlic, Reg.Nightshade); + + m_Circle = 1; + m_Mana = 6; + + AddSpell(typeof(AgilityScroll), Reg.Bloodmoss, Reg.MandrakeRoot); + AddSpell(typeof(CunningScroll), Reg.Nightshade, Reg.MandrakeRoot); + AddSpell(typeof(CureScroll), Reg.Garlic, Reg.Ginseng); + AddSpell(typeof(HarmScroll), Reg.Nightshade, Reg.SpidersSilk); + AddSpell(typeof(MagicTrapScroll), Reg.Garlic, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(MagicUnTrapScroll), Reg.Bloodmoss, Reg.SulfurousAsh); + AddSpell(typeof(ProtectionScroll), Reg.Garlic, Reg.Ginseng, Reg.SulfurousAsh); + AddSpell(typeof(StrengthScroll), Reg.Nightshade, Reg.MandrakeRoot); + + m_Circle = 2; + m_Mana = 9; + + AddSpell(typeof(BlessScroll), Reg.Garlic, Reg.MandrakeRoot); + AddSpell(typeof(FireballScroll), Reg.BlackPearl); + AddSpell(typeof(MagicLockScroll), Reg.Bloodmoss, Reg.Garlic, Reg.SulfurousAsh); + AddSpell(typeof(PoisonScroll), Reg.Nightshade); + AddSpell(typeof(TelekinisisScroll), Reg.Bloodmoss, Reg.MandrakeRoot); + AddSpell(typeof(TeleportScroll), Reg.Bloodmoss, Reg.MandrakeRoot); + AddSpell(typeof(UnlockScroll), Reg.Bloodmoss, Reg.SulfurousAsh); + AddSpell(typeof(WallOfStoneScroll), Reg.Bloodmoss, Reg.Garlic); + + m_Circle = 3; + m_Mana = 11; + + AddSpell(typeof(ArchCureScroll), Reg.Garlic, Reg.Ginseng, Reg.MandrakeRoot); + AddSpell(typeof(ArchProtectionScroll), Reg.Garlic, Reg.Ginseng, Reg.MandrakeRoot, Reg.SulfurousAsh); + AddSpell(typeof(CurseScroll), Reg.Garlic, Reg.Nightshade, Reg.SulfurousAsh); + AddSpell(typeof(FireFieldScroll), Reg.BlackPearl, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(GreaterHealScroll), Reg.Garlic, Reg.SpidersSilk, Reg.MandrakeRoot, Reg.Ginseng); + AddSpell(typeof(LightningScroll), Reg.MandrakeRoot, Reg.SulfurousAsh); + AddSpell(typeof(ManaDrainScroll), Reg.BlackPearl, Reg.SpidersSilk, Reg.MandrakeRoot); + AddSpell(typeof(RecallScroll), Reg.BlackPearl, Reg.Bloodmoss, Reg.MandrakeRoot); + + m_Circle = 4; + m_Mana = 14; + + AddSpell(typeof(BladeSpiritsScroll), Reg.BlackPearl, Reg.Nightshade, Reg.MandrakeRoot); + AddSpell(typeof(DispelFieldScroll), Reg.BlackPearl, Reg.Garlic, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(IncognitoScroll), Reg.Bloodmoss, Reg.Garlic, Reg.Nightshade); + AddSpell(typeof(MagicReflectScroll), Reg.Garlic, Reg.MandrakeRoot, Reg.SpidersSilk); + AddSpell(typeof(MindBlastScroll), Reg.BlackPearl, Reg.MandrakeRoot, Reg.Nightshade, Reg.SulfurousAsh); + AddSpell(typeof(ParalyzeScroll), Reg.Garlic, Reg.MandrakeRoot, Reg.SpidersSilk); + AddSpell(typeof(PoisonFieldScroll), Reg.BlackPearl, Reg.Nightshade, Reg.SpidersSilk); + AddSpell(typeof(SummonCreatureScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk); + + m_Circle = 5; + m_Mana = 20; + + AddSpell(typeof(DispelScroll), Reg.Garlic, Reg.MandrakeRoot, Reg.SulfurousAsh); + AddSpell(typeof(EnergyBoltScroll), Reg.BlackPearl, Reg.Nightshade); + AddSpell(typeof(ExplosionScroll), Reg.Bloodmoss, Reg.MandrakeRoot); + AddSpell(typeof(InvisibilityScroll), Reg.Bloodmoss, Reg.Nightshade); + AddSpell(typeof(MarkScroll), Reg.Bloodmoss, Reg.BlackPearl, Reg.MandrakeRoot); + AddSpell(typeof(MassCurseScroll), Reg.Garlic, Reg.MandrakeRoot, Reg.Nightshade, Reg.SulfurousAsh); + AddSpell(typeof(ParalyzeFieldScroll), Reg.BlackPearl, Reg.Ginseng, Reg.SpidersSilk); + AddSpell(typeof(RevealScroll), Reg.Bloodmoss, Reg.SulfurousAsh); + + m_Circle = 6; + m_Mana = 40; + + AddSpell(typeof(ChainLightningScroll), Reg.BlackPearl, Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SulfurousAsh); + AddSpell(typeof(EnergyFieldScroll), Reg.BlackPearl, Reg.MandrakeRoot, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(FlamestrikeScroll), Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(GateTravelScroll), Reg.BlackPearl, Reg.MandrakeRoot, Reg.SulfurousAsh); + AddSpell(typeof(ManaVampireScroll), Reg.BlackPearl, Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk); + AddSpell(typeof(MassDispelScroll), Reg.BlackPearl, Reg.Garlic, Reg.MandrakeRoot, Reg.SulfurousAsh); + AddSpell(typeof(MeteorSwarmScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SulfurousAsh, Reg.SpidersSilk); + AddSpell(typeof(PolymorphScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk); + + m_Circle = 7; + m_Mana = 50; + + AddSpell(typeof(EarthquakeScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.Ginseng, Reg.SulfurousAsh); + AddSpell(typeof(EnergyVortexScroll), Reg.BlackPearl, Reg.Bloodmoss, Reg.MandrakeRoot, Reg.Nightshade); + AddSpell(typeof(ResurrectionScroll), Reg.Bloodmoss, Reg.Garlic, Reg.Ginseng); + AddSpell(typeof(SummonAirElementalScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk); + AddSpell(typeof(SummonDaemonScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(SummonEarthElementalScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk); + AddSpell(typeof(SummonFireElementalScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk, Reg.SulfurousAsh); + AddSpell(typeof(SummonWaterElementalScroll), Reg.Bloodmoss, Reg.MandrakeRoot, Reg.SpidersSilk); + + // Scriptiz : les parchos n�cros ne peuvent pas �tre craft�s ! + /* + if ( Core.SE ) + { + AddNecroSpell( 0, 23, 39.6, typeof( AnimateDeadScroll ), Reagent.GraveDust, Reagent.DaemonBlood ); + AddNecroSpell( 1, 13, 19.6, typeof( BloodOathScroll ), Reagent.DaemonBlood ); + AddNecroSpell( 2, 11, 19.6, typeof( CorpseSkinScroll ), Reagent.BatWing, Reagent.GraveDust ); + AddNecroSpell( 3, 7, 19.6, typeof( CurseWeaponScroll ), Reagent.PigIron ); + AddNecroSpell( 4, 11, 19.6, typeof( EvilOmenScroll ), Reagent.BatWing, Reagent.NoxCrystal ); + AddNecroSpell( 5, 11, 39.6, typeof( HorrificBeastScroll ), Reagent.BatWing, Reagent.DaemonBlood ); + AddNecroSpell( 6, 23, 69.6, typeof( LichFormScroll ), Reagent.GraveDust, Reagent.DaemonBlood, Reagent.NoxCrystal ); + AddNecroSpell( 7, 17, 29.6, typeof( MindRotScroll ), Reagent.BatWing, Reagent.DaemonBlood, Reagent.PigIron ); + AddNecroSpell( 8, 5, 19.6, typeof( PainSpikeScroll ), Reagent.GraveDust, Reagent.PigIron ); + AddNecroSpell( 9, 17, 49.6, typeof( PoisonStrikeScroll ), Reagent.NoxCrystal ); + AddNecroSpell( 10, 29, 64.6, typeof( StrangleScroll ), Reagent.DaemonBlood, Reagent.NoxCrystal ); + AddNecroSpell( 11, 17, 29.6, typeof( SummonFamiliarScroll ), Reagent.BatWing, Reagent.GraveDust, Reagent.DaemonBlood ); + AddNecroSpell( 12, 23, 98.6, typeof( VampiricEmbraceScroll ), Reagent.BatWing, Reagent.NoxCrystal, Reagent.PigIron ); + AddNecroSpell( 13, 41, 79.6, typeof( VengefulSpiritScroll ), Reagent.BatWing, Reagent.GraveDust, Reagent.PigIron ); + AddNecroSpell( 14, 23, 59.6, typeof( WitherScroll ), Reagent.GraveDust, Reagent.NoxCrystal, Reagent.PigIron ); + AddNecroSpell( 15, 17, 79.6, typeof( WraithFormScroll ), Reagent.NoxCrystal, Reagent.PigIron ); + AddNecroSpell( 16, 40, 79.6, typeof( ExorcismScroll ), Reagent.NoxCrystal, Reagent.GraveDust ); + } + */ + + int index; + + if (Core.ML) + { + index = AddCraft(typeof(EnchantedSwitch), 1044294, 1072893, 45.0, 95.0, typeof(BlankScroll), 1044377, 1, 1044378); + AddRes(index, typeof(SpidersSilk), 1044360, 1, 1044253); + AddRes(index, typeof(BlackPearl), 1044353, 1, 1044253); + AddRes(index, typeof(SwitchItem), 1073464, 1, 1044253); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(RunedPrism), 1044294, 1073465, 45.0, 95.0, typeof(BlankScroll), 1044377, 1, 1044378); + AddRes(index, typeof(SpidersSilk), 1044360, 1, 1044253); + AddRes(index, typeof(BlackPearl), 1044353, 1, 1044253); + AddRes(index, typeof(HollowPrism), 1072895, 1, 1044253); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + } + + /* TODO + if ( Core.ML ) + { + index = AddCraft( typeof( ScrappersCompendium ), 1044294, 1072940, 75.0, 125.0, typeof( BlankScroll ), 1044377, 100, 1044378 ); + AddRes( index, typeof( DreadHornMane ), 1032682, 1, 1044253 ); + AddRes( index, typeof( Taint ), 1032679, 10, 1044253 ); + AddRes( index, typeof( Corruption ), 1032676, 10, 1044253 ); + AddRareRecipe( index, 400 ); + ForceNonExceptional( index ); + SetNeededExpansion( index, Expansion.ML ); + } + */ + + index = AddCraft(typeof(Runebook), 1044294, 1041267, 45.0, 95.0, typeof(BlankScroll), 1044377, 8, 1044378); + AddRes(index, typeof(RecallScroll), 1044445, 1, 1044253); + AddRes(index, typeof(GateTravelScroll), 1044446, 1, 1044253); + + index = AddCraft(typeof(BottleInscriber), 1044294, "�tiquette pour bouteille", 45.0, 95.0, typeof(BlankScroll), 1044377, 3, 1044378); + AddRes(index, typeof(Beeswax), "Cire d'abeille", 1, "Il vous manque de la Cire d'abeille"); + + index = AddCraft(typeof(IDWand), 1044294, "Baguette d'identification", 40.0, 80.0, typeof(DispelScroll), "Dispel Scroll", 1, "Vous n'avez pas de parchemin de dissipation"); + AddRes(index, typeof(BlankWand), "Baguette de bois", 1, "Vous n'avez pas de baguette en bois"); + + index = AddCraft(typeof(VoodooDollFemale), 1044294, "Poup�e mal�fique (Femme)", 75.0, 105.0, typeof(PoupeeFemale), "Poup�e de femme", 1, "Vous n'avez pas de poup�e femme"); + AddRes(index, typeof(MassCurseScroll), "Sort de mal�diction de masse", 1, "Vous n'avez pas ce sort"); + AddSkill(index, SkillName.SpiritSpeak, 25.0, 50.0); + + index = AddCraft(typeof(VoodooDollMale), 1044294, "Poup�e mal�fique (Homme)", 75.0, 105.0, typeof(PoupeeMale), "Poup�e d'homme", 1, "Vous n'avez pas de poup�e homme"); + AddRes(index, typeof(MassCurseScroll), "Sort de mal�diction de masse", 1, "Vous n'avez pas ce sort"); + AddSkill(index, SkillName.SpiritSpeak, 25.0, 50.0); + + if (Core.AOS) + { + index = AddCraft(typeof(Engines.BulkOrders.BulkOrderBook), "Reliures", 1028793, 65.0, 115.0, typeof(BlankScroll), 1044377, 10, 1044378); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + + } + + if (Core.SE) + { + index = AddCraft(typeof(Spellbook), "Reliures", 1023834, 50.0, 126, typeof(BlankScroll), 1044377, 10, 1044378); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + } + + index = AddCraft(typeof(BlueBook), "Reliures", "Livre bleu", 20, 80, typeof(BlankScroll), 1044377, 5, 1044378); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + + index = AddCraft(typeof(TanBook), "Reliures", "Livre beie", 20, 80, typeof(BlankScroll), 1044377, 5, 1044378); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + + index = AddCraft(typeof(RedBook), "Reliures", "Livre bleu", 20, 80, typeof(BlankScroll), 1044377, 5, 1044378); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + + index = AddCraft(typeof(BrownBook), "Reliures", "Livre brun", 20, 80, typeof(BlankScroll), 1044377, 5, 1044378); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + + + MarkOption = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefMasonry.cs b/Scripts/Engines/Craft/DefMasonry.cs new file mode 100644 index 0000000..d61a9f0 --- /dev/null +++ b/Scripts/Engines/Craft/DefMasonry.cs @@ -0,0 +1,178 @@ +//Myron - Comment des ressources pour coller � celles disponibles dans les autres menus +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Craft +{ + public class DefMasonry : CraftSystem + { + public override SkillName MainSkill + { + get{ return SkillName.Carpentry; } + } + + public override int GumpTitleNumber + { + get{ return 1044500; } //
MASONRY MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefMasonry(); + + return m_CraftSystem; + } + } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.0; // 0% + } + + private DefMasonry() : base( 1, 1, 1.25 )// base( 1, 2, 1.7 ) + { + } + + public override bool RetainsColorFrom( CraftItem item, Type type ) + { + return true; + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckTool( tool, from ) ) + return 1048146; // If you have a tool equipped, you must use that tool. + else if ( !(from is PlayerMobile && ((PlayerMobile)from).Masonry && from.Skills[SkillName.Carpentry].Base >= 100.0) ) + return 1044633; // You havent learned stonecraft. + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + public override void PlayCraftEffect( Mobile from ) + { + // no effects + //if ( from.Body.Type == BodyType.Human && !from.Mounted ) + // from.Animate( 9, 5, 1, true, false, 0 ); + //new InternalTimer( from ).Start(); + } + + // Delay to synchronize the sound with the hit on the anvil + private class InternalTimer : Timer + { + private Mobile m_From; + + public InternalTimer( Mobile from ) : base( TimeSpan.FromSeconds( 0.7 ) ) + { + m_From = from; + } + + protected override void OnTick() + { + m_From.PlaySound( 0x23D ); + } + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + // Decorations + AddCraft( typeof( Vase ), 1044501, 1022888, 52.5, 102.5, typeof( Granite ), 1044514, 1, 1044513 ); + AddCraft( typeof( LargeVase ), 1044501, 1022887, 52.5, 102.5, typeof( Granite ), 1044514, 3, 1044513 ); + + + int index = AddCraft( typeof( SmallUrn ), 1044501, 1029244, 82.0, 132.0, typeof( Granite ), 1044514, 3, 1044513 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( SmallTowerSculpture ), 1044501, 1029242, 82.0, 132.0, typeof( Granite ), 1044514, 3, 1044513 ); + SetNeededExpansion( index, Expansion.SE ); + + + // Furniture + AddCraft( typeof( StoneChair ), 1044502, 1024635, 55.0, 105.0, typeof( Granite ), 1044514, 4, 1044513 ); + AddCraft( typeof( MediumStoneTableEastDeed ), 1044502, 1044508, 65.0, 115.0, typeof( Granite ), 1044514, 6, 1044513 ); + AddCraft( typeof( MediumStoneTableSouthDeed ), 1044502, 1044509, 65.0, 115.0, typeof( Granite ), 1044514, 6, 1044513 ); + AddCraft( typeof( LargeStoneTableEastDeed ), 1044502, 1044511, 75.0, 125.0, typeof( Granite ), 1044514, 9, 1044513 ); + AddCraft( typeof( LargeStoneTableSouthDeed ), 1044502, 1044512, 75.0, 125.0, typeof( Granite ), 1044514, 9, 1044513 ); + + // Statues + AddCraft( typeof( StatueSouth ), 1044503, 1044505, 60.0, 120.0, typeof( Granite ), 1044514, 3, 1044513 ); + AddCraft( typeof( StatueNorth ), 1044503, 1044506, 60.0, 120.0, typeof( Granite ), 1044514, 3, 1044513 ); + AddCraft( typeof( StatueEast ), 1044503, 1044507, 60.0, 120.0, typeof( Granite ), 1044514, 3, 1044513 ); + AddCraft( typeof( StatuePegasus ), 1044503, 1044510, 70.0, 130.0, typeof( Granite ), 1044514, 4, 1044513 ); + + index = AddCraft(typeof(SlayerForge), "Misc", "Bassine � Slayers", 70.0, 100.0, typeof(GoldGranite), "Granite d'or", 2, 1044513); + AddRes(index, typeof(Pitcher), "Pichet d'eau", 3); + AddRes(index, typeof(MagicReflectScroll), "Parchemin de r�flection", 2); + AddSkill(index, SkillName.Imbuing, -10.0, 20.0); + ForceNonExceptional(index); + + SetSubRes( typeof( Granite ), 1044525 ); + + AddSubRes( typeof( Granite ), "Fer", 00.0, 1044513); + AddSubRes(typeof(RustyGranite), "Rusty", 65.0, 1044514); + AddSubRes(typeof(OldcopperGranite), "Vieux Cuivre", 70.0, 1044514); + AddSubRes(typeof(DullcopperGranite), "Cuivre terni", 75.0, 1044514); + AddSubRes(typeof(ShadowGranite), "Sombrine", 80.0, 1044514); + AddSubRes(typeof(CopperGranite), "Cuivre", 85.0, 1044514); + AddSubRes(typeof(BronzeGranite), "Bronze", 90.0, 1044514); + AddSubRes(typeof(GoldGranite), "Or", 95.0, 1044514); + AddSubRes(typeof(RoseGranite), "Rose", 99.0, 1044514); + AddSubRes( typeof( AgapiteGranite ), "Agapite", 65.0, 1044514); + AddSubRes( typeof( ValoriteGranite ), "Valorite", 70.0, 1044514); + //AddSubRes( typeof( BloodrockGranite ), "Roche de sang", 75.0, 1044514); + AddSubRes( typeof( VeriteGranite ), "Verite", 80.0, 1044514); + AddSubRes( typeof( SilverGranite ), "Argent", 85.0, 1044514); + AddSubRes( typeof( DragonGranite ), "Dragon", 90.0, 1044514); + AddSubRes( typeof( TitanGranite ), "Titan", 95.0, 1044514); + //AddSubRes( typeof( CrystalineGranite ), "Crystaline", 99.0, 1044514); + //AddSubRes(typeof(KryniteGranite), "Krynite", 65.0, 1044514); + //AddSubRes(typeof(VulcanGranite), "Vulcan", 70.0, 1044514); + //AddSubRes(typeof(BloodcrestGranite), "Craie de sang", 75.0, 1044514); + //AddSubRes(typeof(ElvinGranite), "Elvin", 80.0, 1044514); + //AddSubRes(typeof(AcidGranite), "Acid", 85.0, 1044514); + //AddSubRes(typeof(AquaGranite), "Aqua", 90.0, 1044514); + AddSubRes(typeof(EldarGranite), "Eldar", 95.0, 1044514); + //AddSubRes(typeof(GlowingGranite), "Glowing", 99.0, 1044514); + //AddSubRes(typeof(GorganGranite), "Gorgan", 65.0, 1044514); + //AddSubRes(typeof(SteelGranite), "Acier", 70.0, 1044514); + //AddSubRes(typeof(SandrockGranite), "Pierre de sable", 75.0, 1044514); + //AddSubRes(typeof(MytherilGranite), "Mytheril", 80.0, 1044514); + //AddSubRes(typeof(BlackrockGranite), "Roche sombre", 85.0, 1044514); + + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefTailoring.cs b/Scripts/Engines/Craft/DefTailoring.cs new file mode 100644 index 0000000..5a7d783 --- /dev/null +++ b/Scripts/Engines/Craft/DefTailoring.cs @@ -0,0 +1,462 @@ +using System; +using Server.Items; + +namespace Server.Engines.Craft +{ + public class DefTailoring : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Tailoring; } + } + + public override int GumpTitleNumber + { + get { return 1044005; } //
TAILORING MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefTailoring(); + + return m_CraftSystem; + } + } + + public override CraftECA ECA{ get{ return CraftECA.ChanceMinusSixtyToFourtyFive; } } + + public override double GetChanceAtMin( CraftItem item ) + { + return 0.5; // 50% + } + + private DefTailoring() : base( 1, 1, 1.25 )// base( 1, 1, 4.5 ) + { + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + + return 0; + } + + private static Type[] m_TailorColorables = new Type[] + { + typeof( GozaMatEastDeed ), typeof( GozaMatSouthDeed ), + typeof( SquareGozaMatEastDeed ), typeof( SquareGozaMatSouthDeed ), + typeof( BrocadeGozaMatEastDeed ), typeof( BrocadeGozaMatSouthDeed ), + typeof( BrocadeSquareGozaMatEastDeed ), typeof( BrocadeSquareGozaMatSouthDeed ) + }; + + public override bool RetainsColorFrom( CraftItem item, Type type ) + { + if ( type != typeof( Cloth ) && type != typeof( UncutCloth ) ) + return false; + + type = item.ItemType; + + bool contains = false; + + for ( int i = 0; !contains && i < m_TailorColorables.Length; ++i ) + contains = ( m_TailorColorables[i] == type ); + + return contains; + } + + public override void PlayCraftEffect( Mobile from ) + { + from.PlaySound( 0x248 ); + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override void InitCraftList() + { + int index = -1; + + #region Hats + AddCraft( typeof( SkullCap ), 1011375, 1025444, 0.0, 25.0, typeof( Cloth ), 1044286, 2, 1044287 ); + AddCraft( typeof( Bandana ), 1011375, 1025440, 0.0, 25.0, typeof( Cloth ), 1044286, 2, 1044287 ); + AddCraft( typeof( FloppyHat ), 1011375, 1025907, 6.2, 31.2, typeof( Cloth ), 1044286, 11, 1044287 ); + AddCraft( typeof( Cap ), 1011375, 1025909, 6.2, 31.2, typeof( Cloth ), 1044286, 11, 1044287 ); + AddCraft( typeof( WideBrimHat ), 1011375, 1025908, 6.2, 31.2, typeof( Cloth ), 1044286, 12, 1044287 ); + AddCraft( typeof( StrawHat ), 1011375, 1025911, 6.2, 31.2, typeof( Cloth ), 1044286, 10, 1044287 ); + AddCraft( typeof( TallStrawHat ), 1011375, 1025910, 6.7, 31.7, typeof( Cloth ), 1044286, 13, 1044287 ); + AddCraft( typeof( WizardsHat ), 1011375, 1025912, 7.2, 32.2, typeof( Cloth ), 1044286, 15, 1044287 ); + AddCraft( typeof( Bonnet ), 1011375, 1025913, 6.2, 31.2, typeof( Cloth ), 1044286, 11, 1044287 ); + AddCraft( typeof( FeatheredHat ), 1011375, 1025914, 6.2, 31.2, typeof( Cloth ), 1044286, 12, 1044287 ); + AddCraft( typeof( TricorneHat ), 1011375, 1025915, 6.2, 31.2, typeof( Cloth ), 1044286, 12, 1044287 ); + AddCraft( typeof( JesterHat ), 1011375, 1025916, 7.2, 32.2, typeof( Cloth ), 1044286, 15, 1044287 ); + + if ( Core.AOS ) + AddCraft( typeof( FlowerGarland ), 1011375, 1028965, 10.0, 35.0, typeof( Cloth ), 1044286, 5, 1044287 ); + + if( Core.SE ) + { + index = AddCraft( typeof( ClothNinjaHood ), 1011375, 1030202, 80.0, 105.0, typeof( Cloth ), 1044286, 13, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( Kasa ), 1011375, 1030211, 60.0, 85.0, typeof( Cloth ), 1044286, 12, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + #endregion + + #region Shirts + AddCraft( typeof( Doublet ), 1015269, 1028059, 0, 25.0, typeof( Cloth ), 1044286, 8, 1044287 ); + AddCraft( typeof( Shirt ), 1015269, 1025399, 20.7, 45.7, typeof( Cloth ), 1044286, 8, 1044287 ); + AddCraft( typeof( FancyShirt ), 1015269, 1027933, 24.8, 49.8, typeof( Cloth ), 1044286, 8, 1044287 ); + AddCraft( typeof( Tunic ), 1015269, 1028097, 00.0, 25.0, typeof( Cloth ), 1044286, 12, 1044287 ); + AddCraft( typeof( Surcoat ), 1015269, 1028189, 8.2, 33.2, typeof( Cloth ), 1044286, 14, 1044287 ); + AddCraft( typeof( PlainDress ), 1015269, 1027937, 12.4, 37.4, typeof( Cloth ), 1044286, 10, 1044287 ); + AddCraft( typeof( FancyDress ), 1015269, 1027935, 33.1, 58.1, typeof( Cloth ), 1044286, 12, 1044287 ); + AddCraft( typeof( Cloak ), 1015269, 1025397, 41.4, 66.4, typeof( Cloth ), 1044286, 14, 1044287 ); + AddCraft( typeof( Robe ), 1015269, 1027939, 53.9, 78.9, typeof( Cloth ), 1044286, 16, 1044287 ); + AddCraft(typeof(RobeACapuche), 1015269, "Robe � Capuche", 55.6, 74.3, typeof(Cloth), 1044286, 16, 1044287); + AddCraft(typeof(JesterSuit), 1015269, 1028095, 8.2, 33.2, typeof(Cloth), 1044286, 24, 1044287); + AddCraft(typeof(ElvenShirt), 1015269, "Chemise Exotique", 80, 110, typeof(Cloth), 1044286, 10, 1044287); + AddCraft(typeof(ElvenDarkShirt), 1015269, "Chemise Exotique (sombre)", 80, 110, typeof(Cloth), 1044286, 10, 1044287); + AddCraft(typeof(MaleElvenRobe), 1015269, "Robe exotique (homme)", 80, 110, typeof(Cloth), 1044286, 30, 1044287); + AddCraft(typeof(FemaleElvenRobe), 1015269, "Robe exotique (femme)", 80, 110, typeof(Cloth), 1044286, 30, 1044287); + + if ( Core.AOS ) + { + AddCraft( typeof( FurCape ), 1015269, 1028969, 35.0, 60.0, typeof( Cloth ), 1044286, 13, 1044287 ); + AddCraft( typeof( GildedDress ), 1015269, 1028973, 37.5, 62.5, typeof( Cloth ), 1044286, 16, 1044287 ); + AddCraft( typeof( FormalShirt ), 1015269, 1028975, 26.0, 51.0, typeof( Cloth ), 1044286, 16, 1044287 ); + } + + if( Core.SE ) + { + index = AddCraft( typeof( ClothNinjaJacket ), 1015269, 1030207, 75.0, 100.0, typeof( Cloth ), 1044286, 12, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( Kamishimo ), 1015269, 1030212, 75.0, 100.0, typeof( Cloth ), 1044286, 15, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( HakamaShita ), 1015269, 1030215, 40.0, 65.0, typeof( Cloth ), 1044286, 14, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( MaleKimono ), 1015269, 1030189, 50.0, 75.0, typeof( Cloth ), 1044286, 16, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( FemaleKimono ), 1015269, 1030190, 50.0, 75.0, typeof( Cloth ), 1044286, 16, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( JinBaori ), 1015269, 1030220, 30.0, 55.0, typeof( Cloth ), 1044286, 12, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + #endregion + + #region Pants + AddCraft( typeof( ShortPants ), 1015279, 1025422, 24.8, 49.8, typeof( Cloth ), 1044286, 6, 1044287 ); + AddCraft( typeof( LongPants ), 1015279, 1025433, 24.8, 49.8, typeof( Cloth ), 1044286, 8, 1044287 ); + AddCraft( typeof( Kilt ), 1015279, 1025431, 20.7, 45.7, typeof( Cloth ), 1044286, 8, 1044287 ); + AddCraft( typeof( Skirt ), 1015279, 1025398, 29.0, 54.0, typeof( Cloth ), 1044286, 10, 1044287 ); + AddCraft(typeof(ElvenPants), 1015279, "Pantalon exotique", 80, 110, typeof(Cloth), 1044286, 12, 1044287); + + if ( Core.AOS ) + AddCraft( typeof( FurSarong ), 1015279, 1028971, 35.0, 60.0, typeof( Cloth ), 1044286, 12, 1044287 ); + + if( Core.SE ) + { + index = AddCraft( typeof( Hakama ), 1015279, 1030213, 50.0, 75.0, typeof( Cloth ), 1044286, 16, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( TattsukeHakama ), 1015279, 1030214, 50.0, 75.0, typeof( Cloth ), 1044286, 16, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + #endregion + + #region Misc + AddCraft( typeof( BodySash ), 1015283, 1025441, 4.1, 29.1, typeof( Cloth ), 1044286, 4, 1044287 ); + AddCraft( typeof( HalfApron ), 1015283, 1025435, 20.7, 45.7, typeof( Cloth ), 1044286, 6, 1044287 ); + AddCraft( typeof( FullApron ), 1015283, 1025437, 29.0, 54.0, typeof( Cloth ), 1044286, 10, 1044287 ); + index = AddCraft(typeof(PoupeeFemale), 1015283, "Poup�e (femme)", 26.9, 80.4, typeof(Cloth), 1044286, 6, 1044287); + AddRes(index, typeof(Cotton), "Coton", 4, "Vous n'avez pas assez de coton"); + + index = AddCraft(typeof(PoupeeMale), 1015283, "Poup�e (homme)", 25.9, 79.4, typeof(Cloth), 1044286, 6, 1044287); + AddRes(index, typeof(Cotton), "Coton", 4, "Vous n'avez pas assez de coton"); + AddCraft(typeof(WoodlandBelt), 1015283, "LE Pagne", 80, 110, typeof(Cloth), 1044286, 10, 1044287); + + // Vinds : oreillers and co + index = AddCraft(typeof(SmallPillow), 1015283, "petit coussin", 61.6, 91.6, typeof(Cloth), 1044462, 4, 1044463); + AddRes(index, typeof(Feather), "Plumes", 30, "Il faudra un peu plus de plumes"); + + index = AddCraft(typeof(Pillow), 1015283, "coussin", 63.6, 93.6, typeof(Cloth), 1044462, 6, 1044463); + AddRes(index, typeof(Feather), "Plumes", 50, "Il vous faudra un peu plus de plumes"); + + index = AddCraft(typeof(BigPillow), 1015283, "gros coussin", 66.8, 96.8, typeof(Cloth), 1044462, 8, 1044463); + AddRes(index, typeof(Feather), "Plumes", 70, "Il vous faudra un peu plus de plumes"); + + index = AddCraft(typeof(SmallDiagPillow), 1015283, "petit oreiller", 61.6, 91.6, typeof(Cloth), 1044462, 4, 1044463); + AddRes(index, typeof(Feather), "Plumes", 30, "Il vous faudra un peu plus de plumes"); + + index = AddCraft(typeof(DiagPillow), 1015283, "oreiller", 66.3, 93.6, typeof(Cloth), 1044462, 6, 1044463); + AddRes(index, typeof(Feather), "Plumes", 50, "Il vous faudra un peu plus de plumes"); + + // fin oreillers + + AddCraft(typeof(RubanCheveux), 1015283,"ruban � cheveux", 0.1, 15.0, typeof(Cloth), 1044286, 1, 1044287); + + if( Core.SE ) + { + index = AddCraft( typeof( Obi ), 1015283, 1030219, 20.0, 45.0, typeof( Cloth ), 1044286, 6, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + if( Core.ML ) + { + index = AddCraft( typeof( ElvenQuiver ), 1015283, 1032657, 65.0, 115.0, typeof( Leather ), 1044462, 28, 1044463 ); + AddRecipe( index, 501 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( QuiverOfFire ), 1015283, 1073109, 65.0, 115.0, typeof( Leather ), 1044462, 28, 1044463 ); + AddRes( index, typeof( FireRuby ), 1032695, 15, 1042081 ); + AddRecipe( index, 502 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( QuiverOfIce ), 1015283, 1073110, 65.0, 115.0, typeof( Leather ), 1044462, 28, 1044463 ); + AddRes( index, typeof( WhitePearl ), 1032694, 15, 1042081 ); + AddRecipe( index, 503 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( QuiverOfBlight ), 1015283, 1073111, 65.0, 115.0, typeof( Leather ), 1044462, 28, 1044463 ); + AddRes( index, typeof( Blight ), 1032675, 10, 1042081 ); + AddRecipe( index, 504 ); + SetNeededExpansion( index, Expansion.ML ); + + index = AddCraft( typeof( QuiverOfLightning ), 1015283, 1073112, 65.0, 115.0, typeof( Leather ), 1044462, 28, 1044463 ); + AddRes( index, typeof( Corruption ), 1032676, 10, 1042081 ); + AddRecipe( index, 505 ); + SetNeededExpansion( index, Expansion.ML ); + } + + AddCraft( typeof( OilCloth ), 1015283, 1041498, 74.6, 99.6, typeof( Cloth ), 1044286, 1, 1044287 ); + + if( Core.SE ) + { + index = AddCraft( typeof( GozaMatEastDeed ), 1015283, 1030404, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( GozaMatSouthDeed ), 1015283, 1030405, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( SquareGozaMatEastDeed ), 1015283, 1030407, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( SquareGozaMatSouthDeed ), 1015283, 1030406, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( BrocadeGozaMatEastDeed ), 1015283, 1030408, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( BrocadeGozaMatSouthDeed ), 1015283, 1030409, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( BrocadeSquareGozaMatEastDeed ), 1015283, 1030411, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( BrocadeSquareGozaMatSouthDeed ), 1015283, 1030410, 55.0, 80.0, typeof( Cloth ), 1044286, 25, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + index = AddCraft(typeof(Backpack), 1015283, "Sac", 60.5, 85.5, typeof(Cloth), 1044286, 1, 1044287); + AddRes(index, typeof(Leather), 1044462, 3, 1044463); + ForceNonExceptional(index); + + index = AddCraft(typeof(Bag), 1015283, "Bourse", 43.8, 67.5, typeof(Cloth), 1044286, 1, 1044287); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + ForceNonExceptional(index); + #endregion + + #region Footwear + if ( Core.AOS ) + AddCraft( typeof( FurBoots ), 1015288, 1028967, 50.0, 75.0, typeof( Cloth ), 1044286, 12, 1044287 ); + + if( Core.SE ) + { + index = AddCraft( typeof( NinjaTabi ), 1015288, 1030210, 70.0, 95.0, typeof( Cloth ), 1044286, 10, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( SamuraiTabi ), 1015288, 1030209, 20.0, 45.0, typeof( Cloth ), 1044286, 6, 1044287 ); + SetNeededExpansion( index, Expansion.SE ); + } + + AddCraft( typeof( Sandals ), 1015288, 1025901, 12.4, 37.4, typeof( Leather ), 1044462, 4, 1044463 ); + AddCraft( typeof( Shoes ), 1015288, 1025904, 16.5, 41.5, typeof( Leather ), 1044462, 6, 1044463 ); + AddCraft( typeof( Boots ), 1015288, 1025899, 33.1, 58.1, typeof( Leather ), 1044462, 8, 1044463 ); + AddCraft( typeof( ThighBoots ), 1015288, 1025906, 41.4, 66.4, typeof( Leather ), 1044462, 10, 1044463 ); + AddCraft(typeof(ElvenBoots), 1015288, "Bottes exotiques", 80, 110, typeof(Leather), 1044462, 15, 1044463); + #endregion + + #region Leather Armor + + if (Core.ML) + { + index = AddCraft(typeof(SpellWovenBritches), 1015293, 1072929, 92.5, 117.5, typeof(Leather), 1044462, 15, 1044463); + AddRes(index, typeof(EyeOfTheTravesty), 1032685, 1, 1044253); + AddRes(index, typeof(Putrefication), 1032678, 10, 1044253); + AddRes(index, typeof(Scourge), 1032677, 10, 1044253); + AddRareRecipe(index, 506); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(SongWovenMantle), 1015293, 1072931, 92.5, 117.5, typeof(Leather), 1044462, 15, 1044463); + AddRes(index, typeof(EyeOfTheTravesty), 1032685, 1, 1044253); + AddRes(index, typeof(Blight), 1032675, 10, 1044253); + AddRes(index, typeof(Muculent), 1032680, 10, 1044253); + AddRareRecipe(index, 507); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(StitchersMittens), 1015293, 1072932, 92.5, 117.5, typeof(Leather), 1044462, 15, 1044463); + AddRes(index, typeof(CapturedEssence), 1032686, 1, 1044253); + AddRes(index, typeof(Corruption), 1032676, 10, 1044253); + AddRes(index, typeof(Taint), 1032679, 10, 1044253); + AddRareRecipe(index, 508); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + } + + AddCraft( typeof( LeatherGorget ), 1015293, 1025063, 53.9, 78.9, typeof( Leather ), 1044462, 4, 1044463 ); + AddCraft( typeof( LeatherCap ), 1015293, 1027609, 6.2, 31.2, typeof( Leather ), 1044462, 2, 1044463 ); + AddCraft( typeof( LeatherGloves ), 1015293, 1025062, 51.8, 76.8, typeof( Leather ), 1044462, 3, 1044463 ); + AddCraft( typeof( LeatherArms ), 1015293, 1025061, 53.9, 78.9, typeof( Leather ), 1044462, 4, 1044463 ); + AddCraft( typeof( LeatherLegs ), 1015293, 1025067, 66.3, 91.3, typeof( Leather ), 1044462, 10, 1044463 ); + AddCraft( typeof( LeatherChest ), 1015293, 1025068, 70.5, 95.5, typeof( Leather ), 1044462, 12, 1044463 ); + + AddCraft(typeof(LeafArms), 1015293, "Leaf Arms", 80, 110, typeof(Leather), 1044462, 15, 1044463); + AddCraft(typeof(LeafChest), 1015293, "Leaf Chest", 80, 110, typeof(Leather), 1044462, 15, 1044463); + AddCraft(typeof(LeafGloves), 1015293, "Leaf Gloves", 80, 110, typeof(Leather), 1044462, 15, 1044463); + AddCraft(typeof(LeafGorget), 1015293, "Leaf Gorget", 80, 110, typeof(Leather), 1044462, 15, 1044463); + AddCraft(typeof(LeafLegs), 1015293, "Leaf Legs", 80, 110, typeof(Leather), 1044462, 15, 1044463); + AddCraft(typeof(LeafTonlet), 1015293, "Leaf Tonlet", 80, 110, typeof(Leather), 1044462, 12, 1044463); + + + if( Core.SE ) + { + index = AddCraft( typeof( LeatherJingasa ), 1015293, 1030177, 45.0, 70.0, typeof( Leather ), 1044462, 4, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherMempo ), 1015293, 1030181, 80.0, 105.0, typeof( Leather ), 1044462, 8, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherDo ), 1015293, 1030182, 75.0, 100.0, typeof( Leather ), 1044462, 12, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherHiroSode ), 1015293, 1030185, 55.0, 80.0, typeof( Leather ), 1044462, 5, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherSuneate ), 1015293, 1030193, 68.0, 93.0, typeof( Leather ), 1044462, 12, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherHaidate ), 1015293, 1030197, 68.0, 93.0, typeof( Leather ), 1044462, 12, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherNinjaPants ), 1015293, 1030204, 80.0, 105.0, typeof( Leather ), 1044462, 13, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherNinjaJacket ), 1015293, 1030206, 85.0, 110.0, typeof( Leather ), 1044462, 13, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherNinjaBelt ), 1015293, 1030203, 50.0, 75.0, typeof( Leather ), 1044462, 5, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherNinjaMitts ), 1015293, 1030205, 65.0, 90.0, typeof( Leather ), 1044462, 12, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( LeatherNinjaHood ), 1015293, 1030201, 90.0, 115.0, typeof( Leather ), 1044462, 14, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft(typeof(VivreCagoule), 1015293, "Cagoule", 90.0, 100.0, typeof(Leather), 1044462, 14, 1044463); + SetNeededExpansion(index, Expansion.SE); + } + + #endregion + + #region Studded Armor + AddCraft( typeof( StuddedGorget ), 1015300, 1025078, 78.8, 103.8, typeof( Leather ), 1044462, 6, 1044463 ); + AddCraft( typeof( StuddedGloves ), 1015300, 1025077, 82.9, 107.9, typeof( Leather ), 1044462, 8, 1044463 ); + AddCraft( typeof( StuddedArms ), 1015300, 1025076, 87.1, 112.1, typeof( Leather ), 1044462, 10, 1044463 ); + AddCraft( typeof( StuddedLegs ), 1015300, 1025082, 91.2, 116.2, typeof( Leather ), 1044462, 12, 1044463 ); + AddCraft( typeof( StuddedChest ), 1015300, 1025083, 94.0, 119.0, typeof( Leather ), 1044462, 14, 1044463 ); + + if( Core.SE ) + { + index = AddCraft( typeof( StuddedMempo ), 1015300, 1030216, 80.0, 105.0, typeof( Leather ), 1044462, 8, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( StuddedDo ), 1015300, 1030183, 95.0, 120.0, typeof( Leather ), 1044462, 14, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( StuddedHiroSode ), 1015300, 1030186, 85.0, 110.0, typeof( Leather ), 1044462, 8, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( StuddedSuneate ), 1015300, 1030194, 92.0, 117.0, typeof( Leather ), 1044462, 14, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + index = AddCraft( typeof( StuddedHaidate ), 1015300, 1030198, 92.0, 117.0, typeof( Leather ), 1044462, 14, 1044463 ); + SetNeededExpansion( index, Expansion.SE ); + } + + #endregion + + #region Female Armor + AddCraft( typeof( LeatherShorts ), 1015306, 1027168, 62.2, 87.2, typeof( Leather ), 1044462, 8, 1044463 ); + AddCraft( typeof( LeatherSkirt ), 1015306, 1027176, 58.0, 83.0, typeof( Leather ), 1044462, 6, 1044463 ); + AddCraft( typeof( LeatherBustierArms ), 1015306, 1027178, 58.0, 83.0, typeof( Leather ), 1044462, 6, 1044463 ); + AddCraft( typeof( StuddedBustierArms ), 1015306, 1027180, 82.9, 107.9, typeof( Leather ), 1044462, 8, 1044463 ); + AddCraft( typeof( FemaleLeatherChest ), 1015306, 1027174, 62.2, 87.2, typeof( Leather ), 1044462, 8, 1044463 ); + AddCraft( typeof( FemaleStuddedChest ), 1015306, 1027170, 87.1, 112.1, typeof( Leather ), 1044462, 10, 1044463 ); + AddCraft(typeof(FemaleLeafChest), 1015306, "Female Leaf Chest", 80, 110, typeof(Leather), 1044462, 15, 1044463); + #endregion + + #region Bone Armor + index = AddCraft( typeof( BoneHelm ), 1049149, 1025206, 85.0, 110.0, typeof( Leather ), 1044462, 4, 1044463 ); + AddRes( index, typeof( Bone ), 1049064, 2, 1049063 ); + + index = AddCraft( typeof( BoneGloves ), 1049149, 1025205, 89.0, 114.0, typeof( Leather ), 1044462, 6, 1044463 ); + AddRes( index, typeof( Bone ), 1049064, 2, 1049063 ); + + index = AddCraft( typeof( BoneArms ), 1049149, 1025203, 92.0, 117.0, typeof( Leather ), 1044462, 8, 1044463 ); + AddRes( index, typeof( Bone ), 1049064, 4, 1049063 ); + + index = AddCraft( typeof( BoneLegs ), 1049149, 1025202, 95.0, 120.0, typeof( Leather ), 1044462, 10, 1044463 ); + AddRes( index, typeof( Bone ), 1049064, 6, 1049063 ); + + index = AddCraft( typeof( BoneChest ), 1049149, 1025199, 96.0, 121.0, typeof( Leather ), 1044462, 12, 1044463 ); + AddRes( index, typeof( Bone ), 1049064, 10, 1049063 ); + #endregion + + #region Contenant + AddCraft(typeof(Basket), "Contenants", "Panier rudimentaire", 35.0, 60.0, typeof(WheatSheaf), "Gerbe de bl�", 4, "Vous n'avez pas assez de bl�"); + + index = AddCraft(typeof(PicnicBasket), "Contenants", "Panier � pique-nique", 45.0, 60.0, typeof(WheatSheaf), "Gerbe de bl�", 2, "Vous n'avez pas assez de bl�"); + AddRes(index, typeof(Leather), 1044462, 1, 1044463); + + index = AddCraft(typeof(GiftBox), "Contenants", "Boite � cadeaux", 75.0, 90.0, typeof(Cloth), 1044286, 4, 1044287); + #endregion + + // Set the overridable material + SetSubRes( typeof( Leather ), 1049150 ); + + // Add every material you want the player to be able to choose from + // This will override the overridable material + AddSubRes( typeof( Leather ), 1049150, 00.0, 1044462, 1049311 ); + AddSubRes( typeof( SpinedLeather ), 1049151, 65.0, 1044462, 1049311 ); + AddSubRes( typeof( HornedLeather ), 1049152, 80.0, 1044462, 1049311 ); + AddSubRes( typeof( BarbedLeather ), 1049153, 99.0, 1044462, 1049311 ); + AddSubRes(typeof(DaemonLeather), "DAEMON", 105.0, 1044462); + MarkOption = true; + Repair = Core.AOS; + CanEnhance = Core.AOS; + + + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Craft/DefTinkering.cs b/Scripts/Engines/Craft/DefTinkering.cs new file mode 100644 index 0000000..83929d6 --- /dev/null +++ b/Scripts/Engines/Craft/DefTinkering.cs @@ -0,0 +1,635 @@ +using System; +using Server; +using Server.Items; +using Server.Factions; +using Server.Targeting; + +namespace Server.Engines.Craft +{ + public class DefTinkering : CraftSystem + { + public override SkillName MainSkill + { + get { return SkillName.Tinkering; } + } + + public override int GumpTitleNumber + { + get { return 1044007; } //
TINKERING MENU
+ } + + private static CraftSystem m_CraftSystem; + + public static CraftSystem CraftSystem + { + get + { + if ( m_CraftSystem == null ) + m_CraftSystem = new DefTinkering(); + + return m_CraftSystem; + } + } + + private DefTinkering() : base( 1, 1, 1.25 )// base( 1, 1, 3.0 ) + { + } + + public override double GetChanceAtMin( CraftItem item ) + { + if ( item.NameNumber == 1044258 || item.NameNumber == 1046445 ) // potion keg and faction trap removal kit + return 0.5; // 50% + + return 0.0; // 0% + } + + public override int CanCraft( Mobile from, BaseTool tool, Type itemType ) + { + if( tool == null || tool.Deleted || tool.UsesRemaining < 0 ) + return 1044038; // You have worn out your tool! + else if ( !BaseTool.CheckAccessible( tool, from ) ) + return 1044263; // The tool must be on your person to use. + else if ( itemType != null && ( itemType.IsSubclassOf( typeof( BaseFactionTrapDeed ) ) || itemType == typeof( FactionTrapRemovalKit ) ) && Faction.Find( from ) == null ) + return 1044573; // You have to be in a faction to do that. + + return 0; + } + + private static Type[] m_TinkerColorables = new Type[] + { + typeof( ForkLeft ), typeof( ForkRight ), + typeof( SpoonLeft ), typeof( SpoonRight ), + typeof( KnifeLeft ), typeof( KnifeRight ), + typeof( Plate ), + typeof( Goblet ), typeof( PewterMug ), + typeof( KeyRing ), + typeof( Candelabra ), typeof( Scales ), + typeof( Key ), typeof( Globe ), + typeof( Spyglass ), typeof( Lantern ), + typeof( HeatingStand ), typeof(CandelabraStand) + }; + + public override bool RetainsColorFrom( CraftItem item, Type type ) + { + if ( !type.IsSubclassOf( typeof( BaseIngot ) ) ) + return false; + + type = item.ItemType; + + bool contains = false; + + for ( int i = 0; !contains && i < m_TinkerColorables.Length; ++i ) + contains = ( m_TinkerColorables[i] == type ); + + return contains; + } + + public override void PlayCraftEffect( Mobile from ) + { + // no sound + //from.PlaySound( 0x241 ); + } + + public override int PlayEndingEffect( Mobile from, bool failed, bool lostMaterial, bool toolBroken, int quality, bool makersMark, CraftItem item ) + { + if ( toolBroken ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool + + if ( failed ) + { + if ( lostMaterial ) + return 1044043; // You failed to create the item, and some of your materials are lost. + else + return 1044157; // You failed to create the item, but no materials were lost. + } + else + { + if ( quality == 0 ) + return 502785; // You were barely able to make this item. It's quality is below average. + else if ( makersMark && quality == 2 ) + return 1044156; // You create an exceptional quality item and affix your maker's mark. + else if ( quality == 2 ) + return 1044155; // You create an exceptional quality item. + else + return 1044154; // You create the item. + } + } + + public override bool ConsumeOnFailure( Mobile from, Type resourceType, CraftItem craftItem ) + { + if ( resourceType == typeof( Silver ) ) + return false; + + return base.ConsumeOnFailure( from, resourceType, craftItem ); + } + + /*Plume et on refait les jewels! + public void AddJewelrySet( GemType gemType, Type itemType ) + { + + int offset = (int)gemType - 1; + + int index = AddCraft( typeof( GoldRing ), 1044049, 1044176 + offset, 40.0, 90.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddRes( index, itemType, 1044231 + offset, 1, 1044240 ); + + index = AddCraft( typeof( SilverBeadNecklace ), 1044049, 1044185 + offset, 40.0, 90.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddRes( index, itemType, 1044231 + offset, 1, 1044240 ); + + index = AddCraft( typeof( GoldNecklace ), 1044049, 1044194 + offset, 40.0, 90.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddRes( index, itemType, 1044231 + offset, 1, 1044240 ); + + index = AddCraft( typeof( GoldEarrings ), 1044049, 1044203 + offset, 40.0, 90.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddRes( index, itemType, 1044231 + offset, 1, 1044240 ); + + index = AddCraft( typeof( GoldBeadNecklace ), 1044049, 1044212 + offset, 40.0, 90.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddRes( index, itemType, 1044231 + offset, 1, 1044240 ); + + index = AddCraft( typeof( GoldBracelet ), 1044049, 1044221 + offset, 40.0, 90.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddRes( index, itemType, 1044231 + offset, 1, 1044240 ); + + } + */ + public override void InitCraftList() + { + int index = -1; + + #region Wooden Items + AddCraft( typeof( JointingPlane ), 1044042, 1024144, 0.0, 50.0, typeof( Log ), 1044041, 4, 1044351 ); + AddCraft( typeof( MouldingPlane ), 1044042, 1024140, 0.0, 50.0, typeof( Log ), 1044041, 4, 1044351 ); + AddCraft( typeof( SmoothingPlane ), 1044042, 1024146, 0.0, 50.0, typeof( Log ), 1044041, 4, 1044351 ); + AddCraft( typeof( ClockFrame ), 1044042, 1024173, 0.0, 50.0, typeof( Log ), 1044041, 6, 1044351 ); + AddCraft( typeof( Axle ), 1044042, 1024187, -25.0, 25.0, typeof( Log ), 1044041, 2, 1044351 ); + AddCraft( typeof( RollingPin ), 1044042, 1024163, 0.0, 50.0, typeof( Log ), 1044041, 5, 1044351 ); + + if( Core.SE ) + { + index = AddCraft( typeof( Nunchaku ), 1044042, 1030158, 70.0, 120.0, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddRes( index, typeof( Log ), 1044041, 8, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + } + #endregion + + #region Tools + AddCraft( typeof( Scissors ), 1044046, 1023998, 5.0, 55.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( MortarPestle ), 1044046, 1023739, 20.0, 70.0, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddCraft( typeof( Scorp ), 1044046, 1024327, 30.0, 80.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( TinkerTools ), 1044046, 1044164, 10.0, 60.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( Hatchet ), 1044046, 1023907, 30.0, 80.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( DrawKnife ), 1044046, 1024324, 30.0, 80.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( SewingKit ), 1044046, 1023997, 10.0, 70.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( Saw ), 1044046, 1024148, 30.0, 80.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( DovetailSaw ), 1044046, 1024136, 30.0, 80.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Froe ), 1044046, 1024325, 30.0, 80.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( Shovel ), 1044046, 1023898, 40.0, 90.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Hammer ), 1044046, 1024138, 30.0, 80.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( Tongs ), 1044046, 1024028, 35.0, 85.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( SmithHammer ), 1044046, 1025091, 40.0, 90.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( SledgeHammer ), 1044046, 1024021, 40.0, 90.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Inshave ), 1044046, 1024326, 30.0, 80.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( Pickaxe ), 1044046, 1023718, 40.0, 90.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Lockpick ), 1044046, 1025371, 45.0, 95.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( Skillet ), 1044046, 1044567, 30.0, 80.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( FlourSifter ), 1044046, 1024158, 50.0, 100.0, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddCraft( typeof( FletcherTools ), 1044046, 1044166, 35.0, 85.0, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddCraft( typeof( MapmakersPen ), 1044046, 1044167, 25.0, 75.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + //Myron - Ajout des outils glassbow et masonry + AddCraft( typeof( ScribesPen ), 1044046, 1044168, 25.0, 75.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( Blowpipe ), 1044046, 1044608, 60.0, 100.0, typeof( IronIngot ), 1044036, 5, 1044037 ); + AddCraft( typeof( MalletAndChisel ), 1044046, 1024787, 60.0, 100.0, typeof( IronIngot ), 1044036, 5, 1044037 ); + AddCraft( typeof( Nails ), 1044046, 1024142, 30.0, 80.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + #endregion + + #region Parts + AddCraft( typeof( Gears ), 1044047, 1024179, 5.0, 55.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( ClockParts ), 1044047, 1024175, 25.0, 75.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( BarrelTap ), 1044047, 1024100, 35.0, 85.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( Springs ), 1044047, 1024189, 5.0, 55.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( SextantParts ), 1044047, 1024185, 30.0, 80.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( BarrelHoops ), 1044047, 1024321, -15.0, 35.0, typeof( IronIngot ), 1044036, 5, 1044037 ); + AddCraft( typeof( Hinge ), 1044047, 1024181, 5.0, 55.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( BolaBall ), 1044047, 1023699, 45.0, 95.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + if (Core.ML) + { + index = AddCraft(typeof(JeweledFiligree), 1044047, 1072894, 70.0, 110.0, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(StarSapphire), 1044231, 1, 1044253); + AddRes(index, typeof(Ruby), 1044234, 1, 1044253); + SetNeededExpansion(index, Expansion.ML); + } + #endregion + + #region Containers + //Myron - Ajouts des coffres m�talliques + AddCraft( typeof( MetalBox ),1044292, 1022472, 21.0, 46.0, typeof( IronIngot ), 1044036, 5, 1044037 ); + AddCraft( typeof( MetalChest ),1044292, 1022475, 73.6, 98.6, typeof( IronIngot ), 1044036, 10, 1044037 ); + index = AddCraft( typeof( MetalGoldenChest ),1044292, "Coffre de fer avec dorures", 73.6, 98.6, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( GoldIngot ), "Or", 1, 1044037 ); + AddCraft(typeof(DonationBox), 1044292, "Boite � dons", 25.0, 55.0, typeof(IronIngot), 1044036, 5, 1044037); + + + // Scriptiz : ajout du semoir pour y ranger ses graines + index = AddCraft(typeof(SeedBox), 1044292, "Semoir", 81.5, 106.5, typeof(Log), 1044041, 5, 1044351); + AddRes(index, typeof(WheatSheaf), 1044489, 3); + #endregion + + #region Utensils + AddCraft( typeof( ButcherKnife ), 1044048, 1025110, 25.0, 75.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( SpoonLeft ), 1044048, 1044158, 0.0, 50.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( SpoonRight ), 1044048, 1044159, 0.0, 50.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( Plate ), 1044048, 1022519, 0.0, 50.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft(typeof(Fork), 1044048, "Une fourchette", 0.0, 50.0, typeof(IronIngot), 1044036, 1, 1044037); + //AddCraft( typeof( ForkLeft ), 1044048, 1044160, 0.0, 50.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + //AddCraft( typeof( ForkRight ), 1044048, 1044161, 0.0, 50.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( Cleaver ), 1044048, 1023778, 20.0, 70.0, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddCraft( typeof( KnifeLeft ), 1044048, 1044162, 0.0, 50.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( KnifeRight ), 1044048, 1044163, 0.0, 50.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddCraft( typeof( Goblet ), 1044048, 1022458, 10.0, 60.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( PewterMug ), 1044048, 1024097, 10.0, 60.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( SkinningKnife ), 1044048, 1023781, 25.0, 75.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + #endregion + + #region Misc + AddCraft( typeof( KeyRing ), 1044050, 1024113, 10.0, 60.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + index = AddCraft( typeof( Candelabra ), 1044050, 1022599, 55.0, 105.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddRes(index, typeof(Candle), "Chandelles", 3, "Vous n'avez pas les chandelles requises"); + index = AddCraft(typeof(CandelabraStand), 1044050, 1022599, 65.0, 105.0, typeof(IronIngot), 1044036, 6, 1044037); + AddRes(index, typeof(Candle), "Chandelles", 3, "Vous n'avez pas les chandelles requises"); + + AddCraft( typeof( Scales ), 1044050, 1026225, 60.0, 110.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Key ), 1044050, 1024112, 20.0, 70.0, typeof( IronIngot ), 1044036, 3, 1044037 ); + AddCraft( typeof( Globe ), 1044050, 1024167, 55.0, 105.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Spyglass ), 1044050, 1025365, 60.0, 110.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft( typeof( Lantern ), 1044050, 1022597, 30.0, 80.0, typeof( IronIngot ), 1044036, 2, 1044037 ); + AddCraft( typeof( HeatingStand ), 1044050, 1026217, 60.0, 110.0, typeof( IronIngot ), 1044036, 4, 1044037 ); + AddCraft(typeof(ResourceBucket), 1044050, "Seau de r�colte", 50.0, 100.0, typeof(DullcopperIngot), "Lingots de Cuivre Terni", 4, "Vous n'avez pas assez de Cuivre Terni pour faire cela"); + + index = AddCraft(typeof(Candle), 1044050, "Chandelle", 23.0, 38.2, typeof(BronzeIngot), "Lingot de bronze", 1, "Vous n'avez pas assez de bronze"); + AddRes(index, typeof(Beeswax), "Cire d'abeille", 2, "Vous n'avez pas assez de cire"); + AddRes(index, typeof(Bandage), "Bout de tissus", 1, "Il vous faut un petit morceau de tissus"); + SetNeedHeat(index, true); + + AddCraft(typeof(RustyNails), 1044050, "Clous rouill�s", 60.0, 90.0, typeof(RustyIngot), "De la rouille", 2, 1044037); + + + if ( Core.SE ) + { + index = AddCraft( typeof( ShojiLantern ), 1044050, 1029404, 65.0, 115.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( Log ), 1044041, 5, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( PaperLantern ), 1044050, 1029406, 65.0, 115.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( Log ), 1044041, 5, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( RoundPaperLantern ), 1044050, 1029418, 65.0, 115.0, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( Log ), 1044041, 5, 1044351 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( WindChimes ), 1044050, 1030290, 80.0, 130.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + index = AddCraft( typeof( FancyWindChimes ), 1044050, 1030291, 80.0, 130.0, typeof( IronIngot ), 1044036, 15, 1044037 ); + SetNeededExpansion( index, Expansion.SE ); + + } + + index = AddCraft(typeof(PoteauArnachement), 1044050, "Poteau d'Arnachement", 65.0, 115.0, typeof(Log), 1044041, 2, 1044351); + AddRes(index, typeof(BronzeIngot), "Lingot de bronze", 6, "Vous n'avez pas assez de bronze pour faire cela"); + AddSkill(index, SkillName.Blacksmith, 45.0, 60.0); + AddSkill(index, SkillName.AnimalLore, 10.0, 30.0); + + #endregion + + #region Jewelry + AddCraft(typeof(GoldRing), 1044049, "Bague", 40.0, 90.0, typeof(IronIngot), 1044036, 2, 1044037); + index = AddCraft(typeof(GoldBeadNecklace), 1044049, "Collier de perles", 30.0, 80.0, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(BlackPearl), "Perles noires", 10, "Vous n'avez pas assez de perles pour faire cela"); + AddCraft(typeof(GoldNecklace), 1044049, "Collier", 50.0, 100.0, typeof(IronIngot), 1044036, 2, 1044037); + AddCraft(typeof(GoldEarrings), 1044049, "Boucles d'oreille", 40.0, 90.0, typeof(IronIngot), 1044036, 2, 1044037); + AddCraft(typeof(GoldBracelet), 1044049, "Bracelet", 40.0, 90.0, typeof(IronIngot), 1044036, 2, 1044037); + AddCraft(typeof(Diademe), 1044049, "Diad�me", 60.0, 110.0, typeof(IronIngot), 1044036, 2, 1044037); + index = AddCraft(typeof(DiademeDecore), 1044049, "Diad�me (riche)", 70.0, 120.0, typeof(IronIngot), 1044036, 3, 1044037); + // Scriptiz : quelques pierres pr�cieuses en plus pour le diademe d�cor� + AddRes(index, typeof(Tourmaline), 1044237, 1, 1044240); + AddRes(index, typeof(Amethyst), 1044236, 1, 1044240); + AddRes(index, typeof(BlueDiamond), 1032696, 1, 1044240); + + /*AddJewelrySet( GemType.StarSapphire, typeof( StarSapphire ) ); + AddJewelrySet( GemType.Emerald, typeof( Emerald ) ); + AddJewelrySet( GemType.Sapphire, typeof( Sapphire ) ); + AddJewelrySet( GemType.Ruby, typeof( Ruby ) ); + AddJewelrySet( GemType.Citrine, typeof( Citrine ) ); + AddJewelrySet( GemType.Amethyst, typeof( Amethyst ) ); + AddJewelrySet( GemType.Tourmaline, typeof( Tourmaline ) ); + AddJewelrySet( GemType.Amber, typeof( Amber ) ); + AddJewelrySet( GemType.Diamond, typeof( Diamond ) );*/ + #endregion + + #region Multi-Component Items + index = AddCraft( typeof( AxleGears ), 1044051, 1024177, 0.0, 0.0, typeof( Axle ), 1044169, 1, 1044253 ); + AddRes( index, typeof( Gears ), 1044254, 1, 1044253 ); + + index = AddCraft( typeof( ClockParts ), 1044051, 1024175, 0.0, 0.0, typeof( AxleGears ), 1044170, 1, 1044253 ); + AddRes( index, typeof( Springs ), 1044171, 1, 1044253 ); + + index = AddCraft( typeof( SextantParts ), 1044051, 1024185, 0.0, 0.0, typeof( AxleGears ), 1044170, 1, 1044253 ); + AddRes( index, typeof( Hinge ), 1044172, 1, 1044253 ); + + index = AddCraft( typeof( ClockRight ), 1044051, 1044257, 0.0, 0.0, typeof( ClockFrame ), 1044174, 1, 1044253 ); + AddRes( index, typeof( ClockParts ), 1044173, 1, 1044253 ); + + index = AddCraft( typeof( ClockLeft ), 1044051, 1044256, 0.0, 0.0, typeof( ClockFrame ), 1044174, 1, 1044253 ); + AddRes( index, typeof( ClockParts ), 1044173, 1, 1044253 ); + + AddCraft( typeof( Sextant ), 1044051, 1024183, 0.0, 0.0, typeof( SextantParts ), 1044175, 1, 1044253 ); + + index = AddCraft( typeof( Bola ), 1044051, 1046441, 60.0, 80.0, typeof( BolaBall ), 1046440, 4, 1042613 ); + AddRes( index, typeof( Leather ), 1044462, 3, 1044463 ); + + index = AddCraft( typeof( PotionKeg ), 1044051, 1044258, 75.0, 100.0, typeof( Keg ), 1044255, 1, 1044253 ); + AddRes( index, typeof( Bottle ), 1044250, 10, 1044253 ); + AddRes( index, typeof( BarrelLid ), 1044251, 1, 1044253 ); + AddRes( index, typeof( BarrelTap ), 1044252, 1, 1044253 ); + + index = AddCraft(typeof(FermentationBarrel), 1044051, "Tonneau de Distillerie", 15.0, 60.0, typeof(Log), 1044041, 1, 1044351); + AddRes(index, typeof(BarrelHoops), 1044289, 1, 1044253); + + index = AddCraft(typeof(CheeseForm), 1044051, "Moule � Fromage", 15.0, 60.0, typeof(BasketFrame), "Corps de panier", 1, "Vous n'avez rien pour cr�er la structure"); + AddRes(index, typeof(BlankScroll), 1044377, 10, 1044378); + + index = AddCraft(typeof(IronBeetleBody), 1044051, "Corps de scarab� de fer", 60, 115.0, typeof(IronOre), 1044036, 1500, 1044037); + AddRes(index, typeof(AgapiteOre), "Agapite", 50, "Vous n'avez pas assez d'agapite"); + AddRes(index, typeof(AxleGears), 1044170, 30, 1044253); + AddSkill(index, SkillName.Mysticism, -10.0, 50.0); + #endregion + + #region Traps + // Dart Trap + index = AddCraft( typeof( DartTrapCraft ), 1044052, 1024396, 30.0, 80.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddRes( index, typeof( Bolt ), 1044570, 1, 1044253 ); + + // Poison Trap + index = AddCraft( typeof( PoisonTrapCraft ), 1044052, 1044593, 30.0, 80.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddRes( index, typeof( BasePoisonPotion ), 1044571, 1, 1044253 ); + + // Explosion Trap + index = AddCraft( typeof( ExplosionTrapCraft ), 1044052, 1044597, 55.0, 105.0, typeof( IronIngot ), 1044036, 1, 1044037 ); + AddRes( index, typeof( BaseExplosionPotion ), 1044569, 1, 1044253 ); + + // Faction Gas Trap + index = AddCraft( typeof( FactionGasTrapDeed ), 1044052, 1044598, 65.0, 115.0, typeof( Silver ), 1044572, Core.AOS ? 250 : 1000, 1044253 ); + AddRes( index, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( BasePoisonPotion ), 1044571, 1, 1044253 ); + + // Faction explosion Trap + index = AddCraft( typeof( FactionExplosionTrapDeed ), 1044052, 1044599, 65.0, 115.0, typeof( Silver ), 1044572, Core.AOS ? 250 : 1000, 1044253 ); + AddRes( index, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( BaseExplosionPotion ), 1044569, 1, 1044253 ); + + // Faction Saw Trap + index = AddCraft( typeof( FactionSawTrapDeed ), 1044052, 1044600, 65.0, 115.0, typeof( Silver ), 1044572, Core.AOS ? 250 : 1000, 1044253 ); + AddRes( index, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( Gears ), 1044254, 1, 1044253 ); + + // Faction Spike Trap + index = AddCraft( typeof( FactionSpikeTrapDeed ), 1044052, 1044601, 65.0, 115.0, typeof( Silver ), 1044572, Core.AOS ? 250 : 1000, 1044253 ); + AddRes( index, typeof( IronIngot ), 1044036, 10, 1044037 ); + AddRes( index, typeof( Springs ), 1044171, 1, 1044253 ); + + // Faction trap removal kit + index = AddCraft( typeof( FactionTrapRemovalKit ), 1044052, 1046445, 90.0, 115.0, typeof( Silver ), 1044572, 500, 1044253 ); + AddRes( index, typeof( IronIngot ), 1044036, 10, 1044037 ); + #endregion + + #region Scriptiz : ajout des panneaux craftables + index = AddCraft(typeof(TailorSign), "Pancartes", "Pancarte de barbier", 60, 80, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(Nails), "Clous", 4, "Vous n'avez pas assez de clous"); + + index = AddCraft(typeof(TinkerSign), "Pancartes", "Pancarte de bricoleur", 60, 80, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(Nails), "Clous", 4, "Vous n'avez pas assez de clous"); + + index = AddCraft(typeof(WoodworkerSign), "Pancartes", "Pancarte de bucheron", 60, 80, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(Nails), "Clous", 4, "Vous n'avez pas assez de clous"); + + index = AddCraft(typeof(BlacksmithSign), "Pancartes", "Pancarte de forgeron", 60, 80, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(Nails), "Clous", 4, "Vous n'avez pas assez de clous"); + + index = AddCraft(typeof(WoodenSign), "Pancartes", "Pancarte inscriptible en bois", 80, 100, typeof(Log), 1044041, 2, 1044351); + AddRes(index, typeof(Nails), "Clous", 4, "Vous n'avez pas assez de clous"); + AddRes(index, typeof(ScribesPen), "Plume de scribe", 1, "Vous n'avez pas de plume de scribe"); + + index = AddCraft(typeof(GoldSign), "Pancartes", "Pancarte inscriptible en or", 80, 100, typeof(GoldIngot), "Lingot d'or", 2, "Vous n'avez pas assez de lingots d'or"); + AddRes(index, typeof(Nails), "Clous", 4, "Vous n'avez pas assez de clous"); + AddRes(index, typeof(ScribesPen), "Plume de scribe", 1, "Vous n'avez pas de plume de scribe"); + #endregion + + // Magic Jewelry + if (Core.ML) + { + index = AddCraft(typeof(ResilientBracer), 1073107, 1072933, 100.0, 125.0, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(CapturedEssence), 1032686, 1, 1044253); + AddRes(index, typeof(BlueDiamond), 1032696, 10, 1044253); + AddRes(index, typeof(Diamond), 1062608, 50, 1044253); + AddRareRecipe(index, 600); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(EssenceOfBattle), 1073107, 1072935, 100.0, 125.0, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(CapturedEssence), 1032686, 1, 1044253); + AddRes(index, typeof(FireRuby), 1032695, 10, 1044253); + AddRes(index, typeof(Ruby), 1062603, 50, 1044253); + AddRareRecipe(index, 601); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + + index = AddCraft(typeof(PendantOfTheMagi), 1073107, 1072937, 100.0, 125.0, typeof(IronIngot), 1044036, 2, 1044037); + AddRes(index, typeof(EyeOfTheTravesty), 1032685, 1, 1044253); + AddRes(index, typeof(WhitePearl), 1032694, 10, 1044253); + AddRes(index, typeof(StarSapphire), 1062600, 50, 1044253); + AddRareRecipe(index, 602); + ForceNonExceptional(index); + SetNeededExpansion(index, Expansion.ML); + } + + // Set the overridable material + SetSubRes( typeof( IronIngot ), 1044022 ); + + // Add every material you want the player to be able to choose from + // This will override the overridable material + AddSubRes(typeof(IronIngot), "Fer", 00.0, 10442687); + AddSubRes(typeof(RustyIngot), "Rusty", 30.0, 1044268); + AddSubRes(typeof(OldcopperIngot), "Vieux Cuivre", 30.0, 1044268); + AddSubRes(typeof(DullcopperIngot), "Cuivre terni", 55.0, 1044268); + AddSubRes(typeof(ShadowIngot), "Sombrine", 60.0, 1044268); + AddSubRes(typeof(CopperIngot), "Cuivre", 60.0, 1044268); + AddSubRes(typeof(BronzeIngot), "Bronze", 65.0, 1044268); + AddSubRes(typeof(GoldIngot), "Or", 70.0, 1044268); + AddSubRes(typeof(RoseIngot), "Rose", 99.0, 1044268); + AddSubRes(typeof(AgapiteIngot), "Agapite", 85.0, 1044268); + AddSubRes(typeof(ValoriteIngot), "Valorite", 90.0, 1044268); + //AddSubRes(typeof(BloodrockIngot), "Roche de sang", 75.0, 1044268); + AddSubRes(typeof(VeriteIngot), "Verite", 80.0, 1044268); + AddSubRes(typeof(SilverIngot), "Argent", 85.0, 1044268); + AddSubRes(typeof(DragonIngot), "Dragon", 90.0, 1044268); + AddSubRes(typeof(TitanIngot), "Titan", 95.0, 1044268); + //AddSubRes(typeof(CrystalineIngot), "Crystaline", 99.0, 1044268); + //AddSubRes(typeof(KryniteIngot), "Krynite", 65.0, 1044268); + //AddSubRes(typeof(BloodcrestIngot), "Craie de sang", 75.0, 1044268); + //AddSubRes(typeof(ElvinIngot), "Elvin", 80.0, 1044268); + //AddSubRes(typeof(AcidIngot), "Acid", 85.0, 1044268); + //AddSubRes(typeof(AquaIngot), "Aqua", 90.0, 1044268); + AddSubRes(typeof(EldarIngot), "Eldar", 95.0, 1044268); + AddSubRes(typeof(GlowingIngot), "Glowing", 99.0, 1044268); + AddSubRes(typeof(VulcanIngot), "Vulcan", 99.0, 1044268); + + //AddSubRes(typeof(GorganIngot), "Gorgan", 65.0, 1044268); + //AddSubRes(typeof(SteelIngot), "Acier", 70.0, 1044268); + //AddSubRes(typeof(SandrockIngot), "Pierre de sable", 75.0, 1044268); + //AddSubRes(typeof(MytherilIngot), "Mytheril", 80.0, 1044268); + AddSubRes(typeof(BlackrockIngot), "Pierre noire", 99.0, 1044268); + + MarkOption = true; + Repair = true; + CanEnhance = Core.AOS; + } + } + + public abstract class TrapCraft : CustomCraft + { + private LockableContainer m_Container; + + public LockableContainer Container{ get{ return m_Container; } } + + public abstract TrapType TrapType{ get; } + + public TrapCraft( Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool, int quality ) : base( from, craftItem, craftSystem, typeRes, tool, quality ) + { + } + + private int Verify( LockableContainer container ) + { + if ( container == null || container.KeyValue == 0 ) + return 1005638; // You can only trap lockable chests. + if ( From.Map != container.Map || !From.InRange( container.GetWorldLocation(), 2 ) ) + return 500446; // That is too far away. + if ( !container.Movable ) + return 502944; // You cannot trap this item because it is locked down. + if ( !container.IsAccessibleTo( From ) ) + return 502946; // That belongs to someone else. + if ( container.Locked ) + return 502943; // You can only trap an unlocked object. + if ( container.TrapType != TrapType.None ) + return 502945; // You can only place one trap on an object at a time. + + return 0; + } + + private bool Acquire( object target, out int message ) + { + LockableContainer container = target as LockableContainer; + + message = Verify( container ); + + if ( message > 0 ) + { + return false; + } + else + { + m_Container = container; + return true; + } + } + + public override void EndCraftAction() + { + From.SendLocalizedMessage( 502921 ); // What would you like to set a trap on? + From.Target = new ContainerTarget( this ); + } + + private class ContainerTarget : Target + { + private TrapCraft m_TrapCraft; + + public ContainerTarget( TrapCraft trapCraft ) : base( -1, false, TargetFlags.None ) + { + m_TrapCraft = trapCraft; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + int message; + + if ( m_TrapCraft.Acquire( targeted, out message ) ) + m_TrapCraft.CraftItem.CompleteCraft( m_TrapCraft.Quality, false, m_TrapCraft.From, m_TrapCraft.CraftSystem, m_TrapCraft.TypeRes, m_TrapCraft.Tool, m_TrapCraft ); + else + Failure( message ); + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + if ( cancelType == TargetCancelType.Canceled ) + Failure( 0 ); + } + + private void Failure( int message ) + { + Mobile from = m_TrapCraft.From; + BaseTool tool = m_TrapCraft.Tool; + + if ( tool != null && !tool.Deleted && tool.UsesRemaining > 0 ) + from.SendGump( new CraftGump( from, m_TrapCraft.CraftSystem, tool, message ) ); + else if ( message > 0 ) + from.SendLocalizedMessage( message ); + } + } + + public override Item CompleteCraft( out int message ) + { + message = Verify( this.Container ); + + if ( message == 0 ) + { + int trapLevel = (int)(From.Skills.Tinkering.Value / 10); + + Container.TrapType = this.TrapType; + Container.TrapPower = trapLevel * 9; + Container.TrapLevel = trapLevel; + Container.TrapOnLockpick = true; + + message = 1005639; // Trap is disabled until you lock the chest. + } + + return null; + } + } + + [CraftItemID( 0x1BFC )] + public class DartTrapCraft : TrapCraft + { + public override TrapType TrapType{ get{ return TrapType.DartTrap; } } + + public DartTrapCraft( Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool, int quality ) : base( from, craftItem, craftSystem, typeRes, tool, quality ) + { + } + } + + [CraftItemID( 0x113E )] + public class PoisonTrapCraft : TrapCraft + { + public override TrapType TrapType{ get{ return TrapType.PoisonTrap; } } + + public PoisonTrapCraft( Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool, int quality ) : base( from, craftItem, craftSystem, typeRes, tool, quality ) + { + } + } + + [CraftItemID( 0x370C )] + public class ExplosionTrapCraft : TrapCraft + { + public override TrapType TrapType{ get{ return TrapType.ExplosionTrap; } } + + public ExplosionTrapCraft( Mobile from, CraftItem craftItem, CraftSystem craftSystem, Type typeRes, BaseTool tool, int quality ) : base( from, craftItem, craftSystem, typeRes, tool, quality ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Doom/GauntletSpawner.cs b/Scripts/Engines/Doom/GauntletSpawner.cs new file mode 100644 index 0000000..87408b2 --- /dev/null +++ b/Scripts/Engines/Doom/GauntletSpawner.cs @@ -0,0 +1,707 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Regions; +using Server.Commands; +using System.Collections.Generic; + +namespace Server.Engines.Doom +{ + public enum GauntletSpawnerState + { + InSequence, + InProgress, + Completed + } + + public class GauntletSpawner : Item + { + public const int PlayersPerSpawn = 5; + + public const int InSequenceItemHue = 0x000; + public const int InProgressItemHue = 0x676; + public const int CompletedItemHue = 0x455; + + private GauntletSpawnerState m_State; + + private string m_TypeName; + private BaseDoor m_Door; + private BaseAddon m_Addon; + private GauntletSpawner m_Sequence; + private List m_Creatures; + + private Rectangle2D m_RegionBounds; + private List m_Traps; + + private Region m_Region; + + [CommandProperty( AccessLevel.GameMaster )] + public string TypeName + { + get{ return m_TypeName; } + set{ m_TypeName = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseDoor Door + { + get{ return m_Door; } + set{ m_Door = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseAddon Addon + { + get{ return m_Addon; } + set{ m_Addon = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public GauntletSpawner Sequence + { + get{ return m_Sequence; } + set{ m_Sequence = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasCompleted + { + get + { + if ( m_Creatures.Count == 0 ) + return false; + + for ( int i = 0; i < m_Creatures.Count; ++i ) + { + Mobile mob = m_Creatures[i]; + + if ( !mob.Deleted ) + return false; + } + + return true; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Rectangle2D RegionBounds + { + get{ return m_RegionBounds; } + set{ m_RegionBounds = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public GauntletSpawnerState State + { + get{ return m_State; } + set + { + if ( m_State == value ) + return; + + m_State = value; + + int hue = 0; + bool lockDoors = ( m_State == GauntletSpawnerState.InProgress ); + + switch ( m_State ) + { + case GauntletSpawnerState.InSequence: hue = InSequenceItemHue; break; + case GauntletSpawnerState.InProgress: hue = InProgressItemHue; break; + case GauntletSpawnerState.Completed: hue = CompletedItemHue; break; + } + + if ( m_Door != null ) + { + m_Door.Hue = hue; + m_Door.Locked = lockDoors; + + if ( lockDoors ) + { + m_Door.KeyValue = Key.RandomValue(); + m_Door.Open = false; + } + + if ( m_Door.Link != null ) + { + m_Door.Link.Hue = hue; + m_Door.Link.Locked = lockDoors; + + if ( lockDoors ) + { + m_Door.Link.KeyValue = Key.RandomValue(); + m_Door.Open = false; + } + } + } + + if ( m_Addon != null ) + m_Addon.Hue = hue; + + if ( m_State == GauntletSpawnerState.InProgress ) + { + CreateRegion(); + FullSpawn(); + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), new TimerCallback( Slice ) ); + } + else + { + ClearCreatures(); + ClearTraps(); + DestroyRegion(); + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + } + } + + private Timer m_Timer; + + public List Creatures + { + get{ return m_Creatures; } + set{ m_Creatures = value; } + } + + public List Traps + { + get{ return m_Traps; } + set{ m_Traps = value; } + } + + public Region Region + { + get{ return m_Region; } + set{ m_Region = value; } + } + + public virtual void CreateRegion() + { + if ( m_Region != null ) + return; + + Map map = this.Map; + + if ( map == null || map == Map.Internal ) + return; + + m_Region = new GauntletRegion( this, map ); + } + + public virtual void DestroyRegion() + { + if ( m_Region != null ) + m_Region.Unregister(); + + m_Region = null; + } + + public virtual int ComputeTrapCount() + { + int area = m_RegionBounds.Width * m_RegionBounds.Height; + + return area / 100; + } + + public virtual void ClearTraps() + { + for ( int i = 0; i < m_Traps.Count; ++i ) + m_Traps[i].Delete(); + + m_Traps.Clear(); + } + + public virtual void SpawnTrap() + { + Map map = this.Map; + + if ( map == null ) + return; + + BaseTrap trap = null; + + int random = Utility.Random( 100 ); + + if ( 22 > random ) + trap = new SawTrap( Utility.RandomBool() ? SawTrapType.WestFloor : SawTrapType.NorthFloor ); + else if ( 44 > random ) + trap = new SpikeTrap( Utility.RandomBool() ? SpikeTrapType.WestFloor : SpikeTrapType.NorthFloor ); + else if ( 66 > random ) + trap = new GasTrap( Utility.RandomBool() ? GasTrapType.NorthWall : GasTrapType.WestWall ); + else if ( 88 > random ) + trap = new FireColumnTrap(); + else + trap = new MushroomTrap(); + + if ( trap == null ) + return; + + if ( trap is FireColumnTrap || trap is MushroomTrap ) + trap.Hue = 0x451; + + // try 10 times to find a valid location + for ( int i = 0; i < 10; ++i ) + { + int x = Utility.Random( m_RegionBounds.X, m_RegionBounds.Width ); + int y = Utility.Random( m_RegionBounds.Y, m_RegionBounds.Height ); + int z = this.Z; + + if ( !map.CanFit( x, y, z, 16, false, false ) ) + z = map.GetAverageZ( x, y ); + + if ( !map.CanFit( x, y, z, 16, false, false ) ) + continue; + + trap.MoveToWorld( new Point3D( x, y, z ), map ); + m_Traps.Add( trap ); + + return; + } + + trap.Delete(); + } + + public virtual int ComputeSpawnCount() + { + int playerCount = 0; + + Map map = this.Map; + + if ( map != null ) + { + Point3D loc = GetWorldLocation(); + + Region reg = Region.Find( loc, map ).GetRegion( "Doom Gauntlet" ); + + if ( reg != null ) + playerCount = reg.GetPlayerCount(); + } + + if ( playerCount == 0 && m_Region != null ) + playerCount = m_Region.GetPlayerCount(); + + int count = (playerCount + PlayersPerSpawn - 1) / PlayersPerSpawn; + + if ( count < 1 ) + count = 1; + + return count; + } + + public virtual void ClearCreatures() + { + for ( int i = 0; i < m_Creatures.Count; ++i ) + m_Creatures[i].Delete(); + + m_Creatures.Clear(); + } + + public virtual void FullSpawn() + { + ClearCreatures(); + + int count = ComputeSpawnCount(); + + for ( int i = 0; i < count; ++i ) + Spawn(); + + ClearTraps(); + + count = ComputeTrapCount(); + + for ( int i = 0; i < count; ++i ) + SpawnTrap(); + } + + public virtual void Spawn() + { + try + { + if ( m_TypeName == null ) + return; + + Type type = ScriptCompiler.FindTypeByName( m_TypeName, true ); + + if ( type == null ) + return; + + object obj = Activator.CreateInstance( type ); + + if ( obj == null ) + return; + + if ( obj is Item ) + { + ((Item)obj).Delete(); + } + else if ( obj is Mobile ) + { + Mobile mob = (Mobile)obj; + + mob.MoveToWorld( GetWorldLocation(), this.Map ); + + m_Creatures.Add( mob ); + } + } + catch + { + } + } + + public virtual void RecurseReset() + { + if ( m_State != GauntletSpawnerState.InSequence ) + { + State = GauntletSpawnerState.InSequence; + + if ( m_Sequence != null && !m_Sequence.Deleted ) + m_Sequence.RecurseReset(); + } + } + + public virtual void Slice() + { + if ( m_State != GauntletSpawnerState.InProgress ) + return; + + int count = ComputeSpawnCount(); + + for ( int i = m_Creatures.Count; i < count; ++i ) + Spawn(); + + if ( HasCompleted ) + { + State = GauntletSpawnerState.Completed; + + if ( m_Sequence != null && !m_Sequence.Deleted ) + { + if ( m_Sequence.State == GauntletSpawnerState.Completed ) + RecurseReset(); + + m_Sequence.State = GauntletSpawnerState.InProgress; + } + } + } + + public override string DefaultName + { + get { return "doom spawner"; } + } + + [Constructable] + public GauntletSpawner() : this( null ) + { + } + + [Constructable] + public GauntletSpawner( string typeName ) : base( 0x36FE ) + { + Visible = false; + Movable = false; + + m_TypeName = typeName; + m_Creatures = new List(); + m_Traps = new List(); + } + + public GauntletSpawner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_RegionBounds ); + + writer.WriteItemList( m_Traps, false ); + + writer.Write( m_Creatures, false ); + + writer.Write( m_TypeName ); + writer.WriteItem( m_Door ); + writer.WriteItem( m_Addon ); + writer.WriteItem( m_Sequence ); + + writer.Write( (int) m_State ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_RegionBounds = reader.ReadRect2D(); + m_Traps = reader.ReadStrongItemList(); + + goto case 0; + } + case 0: + { + if ( version < 1 ) + { + m_Traps = new List(); + m_RegionBounds = new Rectangle2D( X - 40, Y - 40, 80, 80 ); + } + + m_Creatures = reader.ReadStrongMobileList(); + + m_TypeName = reader.ReadString(); + m_Door = reader.ReadItem(); ; + m_Addon = reader.ReadItem(); ; + m_Sequence = reader.ReadItem(); + + State = (GauntletSpawnerState)reader.ReadInt(); + + break; + } + } + } + + public static void Initialize() + { + CommandSystem.Register( "GenGauntlet", AccessLevel.Administrator, new CommandEventHandler( GenGauntlet_OnCommand ) ); + } + + public static void CreateTeleporter( int xFrom, int yFrom, int xTo, int yTo ) + { + Static telePad = new Static( 0x1822 ); + Teleporter teleItem = new Teleporter( new Point3D( xTo, yTo, -1 ), Map.Malas, false ); + + telePad.Hue = 0x482; + telePad.MoveToWorld( new Point3D( xFrom, yFrom, -1 ), Map.Malas ); + + teleItem.MoveToWorld( new Point3D( xFrom, yFrom, -1 ), Map.Malas ); + + teleItem.SourceEffect = true; + teleItem.DestEffect = true; + teleItem.SoundID = 0x1FE; + } + + public static BaseDoor CreateDoorSet( int xDoor, int yDoor, bool doorEastToWest, int hue ) + { + BaseDoor hiDoor = new MetalDoor( doorEastToWest ? DoorFacing.NorthCCW : DoorFacing.WestCW ); + BaseDoor loDoor = new MetalDoor( doorEastToWest ? DoorFacing.SouthCW : DoorFacing.EastCCW ); + + hiDoor.MoveToWorld( new Point3D( xDoor, yDoor, -1 ), Map.Malas ); + loDoor.MoveToWorld( new Point3D( xDoor + (doorEastToWest ? 0 : 1), yDoor + (doorEastToWest ? 1 : 0), -1 ), Map.Malas ); + + hiDoor.Link = loDoor; + loDoor.Link = hiDoor; + + hiDoor.Hue = hue; + loDoor.Hue = hue; + + return hiDoor; + } + + public static GauntletSpawner CreateSpawner( string typeName, int xSpawner, int ySpawner, int xDoor, int yDoor, int xPentagram, int yPentagram, bool doorEastToWest, int xStart, int yStart, int xWidth, int yHeight ) + { + GauntletSpawner spawner = new GauntletSpawner( typeName ); + + spawner.MoveToWorld( new Point3D( xSpawner, ySpawner, -1 ), Map.Malas ); + + if ( xDoor > 0 && yDoor > 0 ) + spawner.Door = CreateDoorSet( xDoor, yDoor, doorEastToWest, 0 ); + + spawner.RegionBounds = new Rectangle2D( xStart, yStart, xWidth, yHeight ); + + if ( xPentagram > 0 && yPentagram > 0 ) + { + PentagramAddon pentagram = new PentagramAddon(); + + pentagram.MoveToWorld( new Point3D( xPentagram, yPentagram, -1 ), Map.Malas ); + + spawner.Addon = pentagram; + } + + return spawner; + } + + public static void CreatePricedHealer( int price, int x, int y ) + { + PricedHealer healer = new PricedHealer( price ); + + healer.MoveToWorld( new Point3D( x, y, -1 ), Map.Malas ); + + healer.Home = healer.Location; + healer.RangeHome = 5; + } + + public static void CreateMorphItem( int x, int y, int inactiveItemID, int activeItemID, int range, int hue ) + { + MorphItem item = new MorphItem( inactiveItemID, activeItemID, range ); + + item.Hue = hue; + item.MoveToWorld( new Point3D( x, y, -1 ), Map.Malas ); + } + + public static void CreateVarietyDealer( int x, int y ) + { + VarietyDealer dealer = new VarietyDealer(); + + /* Begin outfit */ + dealer.Name = "Nix"; + dealer.Title = "the Variety Dealer"; + + dealer.Body = 400; + dealer.Female = false; + dealer.Hue = 0x8835; + + List items = new List( dealer.Items ); + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if ( item.Layer != Layer.ShopBuy && item.Layer != Layer.ShopResale && item.Layer != Layer.ShopSell ) + item.Delete(); + } + + dealer.HairItemID = 0x2049; // Pig Tails + dealer.HairHue = 0x482; + + dealer.FacialHairItemID = 0x203E; + dealer.FacialHairHue = 0x482; + + dealer.AddItem( new FloppyHat( 1 ) ); + dealer.AddItem( new Robe( 1 ) ); + + dealer.AddItem( new LanternOfSouls() ); + + dealer.AddItem( new Sandals( 0x482 ) ); + /* End outfit */ + + dealer.MoveToWorld( new Point3D( x, y, -1 ), Map.Malas ); + + dealer.Home = dealer.Location; + dealer.RangeHome = 2; + } + + public static void GenGauntlet_OnCommand( CommandEventArgs e ) + { + /* Begin healer room */ + CreatePricedHealer( 5000, 387, 400 ); + CreateTeleporter( 390, 407, 394, 405 ); + + BaseDoor healerDoor = CreateDoorSet( 393, 404, true, 0x44E ); + + healerDoor.Locked = true; + healerDoor.KeyValue = Key.RandomValue(); + + if ( healerDoor.Link != null ) + { + healerDoor.Link.Locked = true; + healerDoor.Link.KeyValue = Key.RandomValue(); + } + /* End healer room */ + + /* Begin supply room */ + CreateMorphItem( 433, 371, 0x29F, 0x116, 3, 0x44E ); + CreateMorphItem( 433, 372, 0x29F, 0x115, 3, 0x44E ); + + CreateVarietyDealer( 492, 369 ); + + for ( int x = 434; x <= 478; ++x ) + { + for ( int y = 371; y <= 372; ++y ) + { + Static item = new Static( 0x524 ); + + item.Hue = 1; + item.MoveToWorld( new Point3D( x, y, -1 ), Map.Malas ); + } + } + /* End supply room */ + + /* Begin gauntlet cycle */ + CreateTeleporter( 471, 428, 474, 428 ); + CreateTeleporter( 462, 494, 462, 498 ); + CreateTeleporter( 403, 502, 399, 506 ); + CreateTeleporter( 357, 476, 356, 480 ); + CreateTeleporter( 361, 433, 357, 434 ); + + GauntletSpawner sp1 = CreateSpawner( "DarknightCreeper", 491, 456, 473, 432, 417, 426, true, 473, 412, 39, 60 ); + GauntletSpawner sp2 = CreateSpawner( "FleshRenderer", 482, 520, 468, 496, 426, 422, false, 448, 496, 56, 48 ); + GauntletSpawner sp3 = CreateSpawner( "Impaler", 406, 538, 408, 504, 432, 430, false, 376, 504, 64, 48 ); + GauntletSpawner sp4 = CreateSpawner( "ShadowKnight", 335, 512, 360, 478, 424, 439, false, 300, 478, 72, 64 ); + GauntletSpawner sp5 = CreateSpawner( "AbysmalHorror", 326, 433, 360, 429, 416, 435, true, 300, 408, 60, 56 ); + GauntletSpawner sp6 = CreateSpawner( "DemonKnight", 423, 430, 0, 0, 423, 430, true, 392, 392, 72, 96 ); + + sp1.Sequence = sp2; + sp2.Sequence = sp3; + sp3.Sequence = sp4; + sp4.Sequence = sp5; + sp5.Sequence = sp6; + sp6.Sequence = sp1; + + sp1.State = GauntletSpawnerState.InProgress; + /* End gauntlet cycle */ + + /* Begin exit gate */ + ConfirmationMoongate gate = new ConfirmationMoongate(); + + gate.Dispellable = false; + + gate.Target = new Point3D( 2350, 1270, -85 ); + gate.TargetMap = Map.Malas; + + gate.GumpWidth = 420; + gate.GumpHeight = 280; + + gate.MessageColor = 0x7F00; + gate.MessageNumber = 1062109; // You are about to exit Dungeon Doom. Do you wish to continue? + + gate.TitleColor = 0x7800; + gate.TitleNumber = 1062108; // Please verify... + + gate.Hue = 0x44E; + + gate.MoveToWorld( new Point3D( 433, 326, 4 ), Map.Malas ); + /* End exit gate */ + } + } + + + public class GauntletRegion : BaseRegion + { + private GauntletSpawner m_Spawner; + + public GauntletRegion( GauntletSpawner spawner, Map map ) + : base( null, map, Region.Find( spawner.Location, spawner.Map ), spawner.RegionBounds ) + { + m_Spawner = spawner; + + GoLocation = spawner.Location; + + Register(); + } + + public override void AlterLightLevel( Mobile m, ref int global, ref int personal ) + { + global = 12; + } + + public override void OnEnter( Mobile m ) + { + } + + public override void OnExit( Mobile m ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs b/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs new file mode 100644 index 0000000..6594a5d --- /dev/null +++ b/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs @@ -0,0 +1,735 @@ +using System; +using Server.Spells; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Commands; +using System.Collections.Generic; + + /* + this is From me to you, Under no terms, Conditions... K? to apply you + just simply Unpatch/delete, Stick these in, Same location.. Restart + */ + +namespace Server.Engines.Doom +{ + public class LeverPuzzleController : Item + { + private bool m_Enabled; + private static bool installed; + + private UInt16 m_MyKey; + private UInt16 m_TheirKey; + + private List m_Levers; + private List m_Teles; + private List m_Statues; + private List m_Tiles; + private Mobile m_Successful; + private LampRoomBox m_Box; + private Region m_LampRoom; + + private Timer m_Timer; + private Timer l_Timer; + + public static void Initialize() + { + CommandSystem.Register( "GenLeverPuzzle", AccessLevel.Administrator, new CommandEventHandler( GenLampPuzzle_OnCommand ) ); + } + + [Usage( "GenLeverPuzzle" )] + [Description( "Generates lamp room and lever puzzle in doom." )] + public static void GenLampPuzzle_OnCommand( CommandEventArgs e ) + { + foreach ( Item item in Map.Malas.GetItemsInRange( lp_Center, 0 ) ) + { + if ( item is LeverPuzzleController ) + { + e.Mobile.SendMessage( "Lamp room puzzle already exists: please delete the existing controller first ..." ); + return; + } + } + e.Mobile.SendMessage( "Generating Lamp Room puzzle..." ); + new LeverPuzzleController().MoveToWorld( lp_Center, Map.Malas ); + + if ( !installed ) + e.Mobile.SendMessage( "There was a problem generating the puzzle." ); + else + e.Mobile.SendMessage( "Lamp room puzzle successfully generated." ); + } + + [CommandProperty( AccessLevel.GameMaster )] + public UInt16 MyKey { get{ return m_MyKey; } set{ m_MyKey = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public UInt16 TheirKey { get{ return m_TheirKey; } set{ m_TheirKey = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Enabled { get{ return m_Enabled; } set{ m_Enabled = value; } } + + public Mobile Successful { get{ return m_Successful; } } + + public bool CircleComplete + { + get /* OSI: all 5 must be occupied */ + { + for (int i=0; i<5; i++) + { + if( GetOccupant( i ) == null) + { + return false; + } + } + return true; + } + } + + public LeverPuzzleController() : base( 0x1822 ) + { + Movable=false; + Hue=0x4c; + installed=true; + int i=0; + + m_Levers = new List(); /* codes are 0x1 shifted left x # of bits, easily handled here */ + for (; i<4; i++) + m_Levers.Add( AddLeverPuzzlePart( TA[i], new LeverPuzzleLever( (ushort)(1<(); + for (; i<9; i++) + m_Tiles.Add( new LeverPuzzleRegion( this, TA[i] )); + + m_Teles = new List(); + for (; i<15; i++) + m_Teles.Add( AddLeverPuzzlePart( TA[i], new LampRoomTeleporter( TA[++i] ))); + + m_Statues = new List(); + for (; i<19; i++) + m_Statues.Add( AddLeverPuzzlePart( TA[i], new LeverPuzzleStatue( TA[++i], this ))); + + if(!installed) + Delete(); + else + Enabled=true; + + m_Box = (LampRoomBox)AddLeverPuzzlePart( TA[i], new LampRoomBox( this )); + m_LampRoom = new LampRoomRegion( this ); + GenKey(); + } + + public static Item AddLeverPuzzlePart( int[] Loc, Item newitem ) + { + if( newitem == null || newitem.Deleted ) + { + installed=false; + } + else + { + newitem.MoveToWorld( new Point3D(Loc[0], Loc[1], Loc[2]), Map.Malas ); + } + return newitem; + } + + public override void OnDelete() + { + KillTimers(); + base.OnDelete(); + } + public override void OnAfterDelete() + { + NukeItemList( m_Teles ); + NukeItemList( m_Statues ); + NukeItemList( m_Levers ); + + if( m_LampRoom != null ) + { + m_LampRoom.Unregister(); + } + if ( m_Tiles != null ) + { + foreach( Region region in m_Tiles ) + { + region.Unregister(); + } + } + if( m_Box != null && !m_Box.Deleted ) + { + m_Box.Delete(); + } + } + + public static void NukeItemList( List list ) + { + if ( list != null && list.Count != 0 ) + { + foreach ( Item item in list ) + { + if( item != null && !item.Deleted ) + { + item.Delete(); + } + } + } + } + + public virtual PlayerMobile GetOccupant( int index ) + { + LeverPuzzleRegion region = (LeverPuzzleRegion)m_Tiles[index]; + + if ( region != null ) + { + if( region.Occupant != null && region.Occupant.Alive ) + { + return (PlayerMobile)region.Occupant; + } + } + return null; + } + + public virtual LeverPuzzleStatue GetStatue( int index ) + { + LeverPuzzleStatue statue = (LeverPuzzleStatue)m_Statues[index]; + + if( statue != null && !statue.Deleted ) + { + return statue; + } + return null; + } + + public virtual LeverPuzzleLever GetLever( int index ) + { + LeverPuzzleLever lever = (LeverPuzzleLever)m_Levers[index]; + + if( lever != null && !lever.Deleted ) + { + return lever; + } + return null; + } + + public virtual void PuzzleStatus( int message, string fstring ) + { + for( int i=0; i<2; i++) + { + Item s; + if(( s = GetStatue( i )) != null ) + { + s.PublicOverheadMessage( MessageType.Regular, 0x3B2, message, fstring ); + } + } + } + + public virtual void ResetPuzzle() + { + PuzzleStatus( 1062053, null ); + ResetLevers(); + } + + public virtual void ResetLevers() + { + for(int i=0;i<4; i++) + { + Item l; + if(( l = GetLever( i )) != null ) + { + l.ItemID=0x108E; + Effects.PlaySound( l.Location, Map, 0x3E8 ); + } + } + TheirKey^=TheirKey; + } + + public virtual void KillTimers () + { + if ( l_Timer != null && l_Timer.Running ) + { + l_Timer.Stop(); + } + if ( m_Timer != null && m_Timer.Running ) + { + m_Timer.Stop(); + } + } + + public virtual void RemoveSuccessful() + { + m_Successful=null; + } + + public virtual void LeverPulled( UInt16 code ) + { + int Correct=0; + Mobile m_Player; + + KillTimers(); + + /* if one bit in each of the four nibbles is set, this is false */ + + if( (TheirKey=(ushort)(code|(TheirKey<<=4))) < 0x0FFF ) + { + l_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 30.0 ), new TimerCallback( ResetPuzzle )); + return; + } + + if( !CircleComplete ) + { + PuzzleStatus( 1050004, null ); // The circle is the key... + } + else + { + if( TheirKey == MyKey ) + { + GenKey(); + if (( m_Successful = ( m_Player=GetOccupant( 0 ))) != null ) + { + SendLocationEffect( lp_Center, 0x1153, 0, 60, 1 ); + PlaySounds( lp_Center, cs1 ); + + Effects.SendBoltEffect( m_Player, true ); + m_Player.MoveToWorld( lr_Enter, Map.Malas ); + + m_Timer = new LampRoomTimer( this ); + m_Timer.Start(); + m_Enabled = false; + } + } + else + { + for(int i=0; i<16; i++) /* Count matching SET bits, ie correct codes */ + { + if( (((MyKey>>i)&1)==1)&&(((TheirKey>>i)&1)==1) ) + { + Correct++; + } + } + + PuzzleStatus( Statue_Msg[Correct], (Correct>0) ? Correct.ToString() : null ); + + for (int i=0; i<5; i++) + { + if(( m_Player=GetOccupant( i )) != null ) + { + Timer smash = new RockTimer( m_Player, this ); + smash.Start(); + } + } + } + } + ResetLevers(); + } + + public virtual void GenKey() /* Shuffle & build key */ + { + UInt16 tmp; int n, i; ushort[] CA = { 1,2,4,8 }; + for (i=0; i<4; i++) + { + n=(((n = Utility.Random(0,3))==i) ? n&~i : n ); /* if(i==n) { return pointless; } */ + tmp = CA[i]; + CA[i]=CA[n]; + CA[n]=tmp; + } + for(i=0; i<4; MyKey=(ushort)(CA[(i++)]|(MyKey<<=4))) {} + } + + public class RockTimer : Timer + { + private int Count; + private Mobile m_Player; + private LeverPuzzleController m_Controller; + + public RockTimer( Mobile player, LeverPuzzleController Controller ) + : base( TimeSpan.Zero, TimeSpan.FromSeconds( .25 ) ) + { + Count = 0; + m_Player=player; + m_Controller = Controller; + } + + private int Rock() + { + return 0x1363+Utility.Random( 0, 11 ); + } + + protected override void OnTick() + { + if( m_Player == null || !(m_Player.Map == Map.Malas) ) + { + Stop(); + } + else + { + Count++; + if ( Count == 1 ) /* TODO consolidate */ + { + m_Player.Paralyze( TimeSpan.FromSeconds(2) ); + Effects.SendTargetEffect( m_Player, 0x11B7, 20, 10 ); + PlayerSendASCII( m_Player, 0 ); // You are pinned down ... + + PlaySounds( m_Player.Location, ( !m_Player.Female ) ? fs : ms ); + PlayEffect( ZAdjustedIEFromMobile( m_Player, 50 ), m_Player, 0x11B7, 20, false ); + } + else if ( Count == 2 ) + { + DoDamage( m_Player, 80, 90, false ); + Effects.SendTargetEffect( m_Player, 0x36BD, 20, 10 ); + PlaySounds( m_Player.Location, exp ); + PlayerSendASCII( m_Player, 1 ); // A speeding rock ... + + if( AniSafe( m_Player )) + { + m_Player.Animate( 21, 10, 1, true, true, 0 ); + } + } + else if ( Count == 3 ) + { + Stop(); + + Effects.SendTargetEffect( m_Player, 0x36B0, 20, 10 ); + PlayerSendASCII( m_Player, 1 ); // A speeding rock ... + PlaySounds( m_Player.Location, ( !m_Player.Female ) ? fs2 : ms2 ); + + int j = Utility.Random(6,10); + for(int i=0; i mobiles = new List(); + foreach( Mobile m in m_IEntity.Map.GetMobilesInRange( m_IEntity.Location, 2 )) + { + mobiles.Add( m ); + } + for( int k=0; k mobiles = m_Controller.m_LampRoom.GetMobiles(); + + if ( ticks >= 71 || m_Controller.m_LampRoom.GetPlayerCount() == 0 ) + { + foreach ( Mobile mobile in mobiles ) + { + if( mobile != null && !mobile.Deleted && !mobile.IsDeadBondedPet ) + { + mobile.Kill(); + } + } + m_Controller.Enabled=true; + Stop(); + } + else + { + if ( ticks % 12 == 0 ) + { + level++; + } + foreach ( Mobile mobile in mobiles ) + { + if ( IsValidDamagable( mobile ) ) + { + if ( ticks % 2 == 0 && level == 5 ) + { + if ( mobile.Player ) + { + mobile.Say( 1062092 ); + if( AniSafe( mobile )) + { + mobile.Animate( 32, 5, 1, true, false, 0 ); + } + } + DoDamage( mobile, 15, 20, true ); + } + if ( Utility.Random( (int)(level & ~0xfffffffc), 3) == 3 ) + { + mobile.ApplyPoison( mobile, PA2[level] ); + } + if ( ticks % 12 == 0 && level > 0 && mobile.Player ) + { + mobile.SendLocalizedMessage( PA[level][0], null, PA[level][1] ); + } + } + } + for( int i=0; i<=level; i++ ) + { + SendLocationEffect( RandomPointIn( lr_Rect, -1 ), 0x36B0, Utility.Random( 150, 200 ), 0, PA[level][2] ); + } + } + } + } + + private static bool IsValidDamagable( Mobile m ) + { + if ( m != null && !m.Deleted ) + { + if( m.Player && m.Alive ) + { + return true; + } + + if( m is BaseCreature ) + { + BaseCreature bc=(BaseCreature)m; + if ( ( bc.Controlled || bc.Summoned ) && !bc.IsDeadBondedPet ) + { + return true; + } + } + } + return false; + } + + public static void MoveMobileOut( Mobile m ) + { + if ( m != null ) + { + if( m is PlayerMobile && !m.Alive ) + { + if( m.Corpse != null && !m.Corpse.Deleted ) + { + m.Corpse.MoveToWorld( lr_Exit, Map.Malas ); + } + } + BaseCreature.TeleportPets( m, lr_Exit, Map.Malas ); + m.Location = lr_Exit; + m.ProcessDelta(); + } + } + + public static bool AniSafe( Mobile m ) + { + return ( m != null && !TransformationSpellHelper.UnderTransformation( m ) && m.BodyMod == 0 && m.Alive ); + } + + public static IEntity ZAdjustedIEFromMobile( Mobile m, int ZDelta ) + { + return new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z+ZDelta ), m.Map ); + } + + public static void DoDamage( Mobile m, int min, int max, bool poison ) + { + if ( m != null && !m.Deleted && m.Alive ) + { + int damage = Utility.Random(min,max); + AOS.Damage( m, damage,(poison) ? 0 : 100 , 0, 0,(poison) ? 100 : 0, 0 ); + } + } + + public static Point3D RandomPointIn( Point3D point, int range ) + { + return RandomPointIn( point.X-range, point.Y-range, range*2, range*2, point.Z ); + } + public static Point3D RandomPointIn( Rectangle2D rect, int z ) + { + return RandomPointIn( rect.X, rect.Y, rect.Height, rect.Width, z ); + } + public static Point3D RandomPointIn( int x, int y, int x2, int y2, int z ) + { + return new Point3D( Utility.Random( x, x2 ), Utility.Random( y, y2 ), z ); + } + + public static void PlaySounds( Point3D location, int[] sounds ) + { + foreach( int soundid in sounds ) + Effects.PlaySound( location, Map.Malas, soundid ); + } + + public static void PlayEffect( IEntity from, IEntity to, int itemid, int speed, bool explodes ) + { + Effects.SendMovingParticles( from, to, itemid, speed, 0, true, explodes, 2, 0, 0 ); + } + + public static void SendLocationEffect( IPoint3D p, int itemID, int speed, int duration, int hue ) + { + Effects.SendPacket( p, Map.Malas, new LocationEffect( p, itemID, speed, duration, hue, 0 ) ); + } + + public static void PlayerSendASCII( Mobile player, int index ) + { + player.Send( new AsciiMessage( Serial.MinusOne, 0xFFFF, MessageType.Label, MsgParams[index][0], MsgParams[index][1], null, Msgs[index] )); + } + + /* I cant find any better way to send "speech" using fonts other than default */ + public static void POHMessage( Mobile from, int index ) + { + Packet p = new AsciiMessage( from.Serial, from.Body, MessageType.Regular, MsgParams[index][0], MsgParams[index][1], from.Name, Msgs[index] ); + p.Acquire(); + foreach( NetState state in from.Map.GetClientsInRange( from.Location ) ) + state.Send( p ); + + Packet.Release( p ); + } + + public static string[] Msgs = + { + "You are pinned down by the weight of the boulder!!!", // 0 + "A speeding rock hits you in the head!", // 1 + "OUCH!" // 2 + }; + /* font&hue for above msgs. index matches */ + + public static int[][] MsgParams = + { + new int[]{ 0x66d, 3 }, + new int[]{ 0x66d, 3 }, + new int[]{ 0x34, 3 } + }; + /* World data for items */ + + public static int[][] TA = + { + + new int[]{316, 64, 5}, /* 3D Coords for levers */ + new int[]{323, 58, 5}, + new int[]{332, 63, 5}, + new int[]{323, 71, 5}, + + new int[]{324, 64}, /* 2D Coords for standing regions */ + new int[]{316, 65}, + new int[]{324, 58}, + new int[]{332, 64}, + new int[]{323, 72}, + + new int[]{468, 92, -1}, new int[]{0x181D, 0x482}, /* 3D coord, itemid+hue for L.R. teles */ + new int[]{469, 92, -1}, new int[]{0x1821, 0x3fd}, + new int[]{470, 92, -1}, new int[]{0x1825, 0x66d}, + + new int[]{319, 70, 18}, new int[]{0x12d8}, /* 3D coord, itemid for statues */ + new int[]{329, 60, 18}, new int[]{0x12d9}, + + new int[]{469, 96, 6} /* 3D Coords for Fake Box */ + }; + + /* CLILOC data for statue "correct souls" messages */ + + public static int[] Statue_Msg = { 1050009, 1050007, 1050008, 1050008 }; + + /* Exit & Enter locations for the lamp room */ + + public static Point3D lr_Exit = new Point3D( 353, 172, -1 ); + public static Point3D lr_Enter = new Point3D( 467, 96, -1 ); + + /* "Center" location in puzzle */ + + public static Point3D lp_Center = new Point3D( 324, 64, -1 ); + + /* Lamp Room Area */ + + public static Rectangle2D lr_Rect = new Rectangle2D( 465, 92, 10, 10 ); + + /* Lamp Room area Poison message data */ + + public static int[][] PA = + { + new int[]{ 0, 0, 0xA6 }, + new int[]{ 1050001, 0x485, 0xAA }, + new int[]{ 1050003, 0x485, 0xAC }, + new int[]{ 1050056, 0x485, 0xA8 }, + new int[]{ 1050057, 0x485, 0xA4 }, + new int[]{ 1062091, 0x23F3, 0xAC } + }; + public static Poison[] PA2 = + { + Poison.Lesser, + Poison.Regular, + Poison.Greater, + Poison.Deadly, + Poison.Lethal, + Poison.Lethal + }; + + /* SOUNDS */ + + private static int[] fs={0x144, 0x154}; + private static int[] ms={0x144, 0x14B}; + private static int[] fs2={0x13F, 0x154}; + private static int[] ms2={0x13F, 0x14B}; + private static int[] cs1={0x244}; + private static int[] exp={0x307}; + + public LeverPuzzleController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.WriteItemList( m_Levers, true ); + writer.WriteItemList( m_Statues, true ); + writer.WriteItemList( m_Teles, true ); + writer.Write( m_Box ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Levers = reader.ReadStrongItemList(); + m_Statues = reader.ReadStrongItemList(); + m_Teles = reader.ReadStrongItemList(); + + m_Box = reader.ReadItem() as LampRoomBox; + + m_Tiles = new List(); + for (int i = 4; i<9; i++) + m_Tiles.Add( new LeverPuzzleRegion( this, TA[i] )); + + m_LampRoom = new LampRoomRegion( this ); + m_Enabled = true; + m_TheirKey = 0; + m_MyKey = 0; + GenKey(); + } + } +} + diff --git a/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs b/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs new file mode 100644 index 0000000..0360693 --- /dev/null +++ b/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleItems.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections; +using Server; +using Server.Spells; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.Doom +{ + public class LampRoomBox : Item + { + private LeverPuzzleController m_Controller; + private Mobile m_Wanderer; + + public LampRoomBox( LeverPuzzleController controller ) : base( 0xe80 ) + { + m_Controller = controller; + ItemID = 0xe80; + Movable = false; + } + + public override void OnDoubleClick( Mobile m ) + { + if ( !m.InRange( this.GetWorldLocation(), 3 ) ) + return; + if ( m_Controller.Enabled ) + return; + + if ( (m_Wanderer == null || !m_Wanderer.Alive) ) + { + m_Wanderer = new WandererOfTheVoid(); + m_Wanderer.MoveToWorld( LeverPuzzleController.lr_Enter, Map.Malas ); + m_Wanderer.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1060002, "" ); // I am the guardian of... + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( CallBackMessage ) ); + } + } + + public void CallBackMessage() + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1060003, "" ); // You try to pry the box open... + } + public override void OnAfterDelete() + { + if( m_Controller!=null && !m_Controller.Deleted ) + m_Controller.Delete(); + } + public LampRoomBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( m_Controller ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Controller = reader.ReadItem() as LeverPuzzleController; + } + } + + public class LeverPuzzleStatue : Item + { + private LeverPuzzleController m_Controller; + + public LeverPuzzleStatue( int[] dat, LeverPuzzleController controller ) : base( dat[0] ) + { + m_Controller=controller; + Hue = 0x44E; + Movable = false; + } + public override void OnAfterDelete() + { + if( m_Controller!=null && !m_Controller.Deleted ) + m_Controller.Delete(); + } + public LeverPuzzleStatue( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( m_Controller ); + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Controller = reader.ReadItem() as LeverPuzzleController; + } + } + + public class LeverPuzzleLever : Item + { + private UInt16 m_Code; + private LeverPuzzleController m_Controller; + + [CommandProperty( AccessLevel.GameMaster )] + public UInt16 Code + { + get{ return m_Code; } + } + + public LeverPuzzleLever( UInt16 code, LeverPuzzleController controller ) : base( 0x108E ) + { + m_Controller=controller; + m_Code = code; + Hue = 0x66D; + Movable = false; + } + + public override void OnDoubleClick( Mobile m ) + { + if ( m != null && m_Controller.Enabled ) + { + ItemID^=2; + Effects.PlaySound( Location, Map, 0x3E8 ); + m_Controller.LeverPulled( m_Code ); + } + else + { + m.SendLocalizedMessage( 1060001 ); // You throw the switch, but the mechanism cannot be engaged again so soon. + } + } + + public override void OnAfterDelete() + { + if( m_Controller != null && !m_Controller.Deleted ) + m_Controller.Delete(); + } + + public LeverPuzzleLever( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( (ushort) m_Code ); + writer.Write( m_Controller ); + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Code = reader.ReadUShort(); + m_Controller = reader.ReadItem() as LeverPuzzleController; + } + } + + [TypeAlias( "Server.Engines.Doom.LampRoomTelePorter" )] + public class LampRoomTeleporter : Item + { + public LampRoomTeleporter( int[] dat ) + { + Hue = dat[1]; + ItemID = dat[0]; + Movable = false; + } + + public override bool HandlesOnMovement { get { return true; } } + public override bool OnMoveOver( Mobile m ) + { + if( m != null && m is PlayerMobile ) + { + if ( SpellHelper.CheckCombat( m ) ) + { + m.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + } + else + { + Server.Mobiles.BaseCreature.TeleportPets( m, LeverPuzzleController.lr_Exit, Map.Malas ); + m.MoveToWorld( LeverPuzzleController.lr_Exit, Map.Malas ); + return false; + } + } + return true; + } + + public LampRoomTeleporter( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + + diff --git a/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs b/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs new file mode 100644 index 0000000..9db165f --- /dev/null +++ b/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs @@ -0,0 +1,127 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Engines.Doom +{ + public class LampRoomRegion : BaseRegion + { + private LeverPuzzleController Controller; + + public LampRoomRegion ( LeverPuzzleController controller ) + : base( null, Map.Malas, Region.Find( LeverPuzzleController.lr_Enter, Map.Malas ), LeverPuzzleController.lr_Rect ) + { + Controller = controller; + Register(); + } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( OnLogin ); + } + + public static void OnLogin( LoginEventArgs e ) + { + Mobile m = e.Mobile; + Rectangle2D rect = LeverPuzzleController.lr_Rect; + if ( m.X >= rect.X && m.X <= (rect.X+10) && m.Y >= rect.Y && m.Y <= (rect.Y+10) && m.Map == Map.Internal ) + { + Timer kick = new LeverPuzzleController.LampRoomKickTimer( m ); + kick.Start(); + } + } + + public override void OnEnter( Mobile m ) + { + if ( m == null || m is WandererOfTheVoid ) + return; + + if ( m.AccessLevel > AccessLevel.Player ) + return; + + if ( Controller.Successful != null ) + { + if ( m is PlayerMobile ) + { + if ( m == Controller.Successful ) + { + return; + } + } + else if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + if(( bc.Controlled && bc.ControlMaster == Controller.Successful ) || bc.Summoned ) + { + return; + } + } + } + Timer kick = new LeverPuzzleController.LampRoomKickTimer( m ); + kick.Start(); + } + + public override void OnExit( Mobile m ) + { + if( m != null && m == Controller.Successful ) + Controller.RemoveSuccessful(); + } + + public override void OnDeath( Mobile m ) + { + if( m != null && !m.Deleted && !(m is WandererOfTheVoid) ) + { + Timer kick = new LeverPuzzleController.LampRoomKickTimer( m ); + kick.Start();; + } + } + + public override bool OnSkillUse( Mobile m, int Skill ) /* just in case */ + { + if (( Controller.Successful == null ) || ( m.AccessLevel == AccessLevel.Player && m != Controller.Successful )) + { + return false; + } + return true; + } + } + + public class LeverPuzzleRegion : BaseRegion + { + private LeverPuzzleController Controller; + public Mobile m_Occupant; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Occupant + { + get + { + if ( m_Occupant != null && m_Occupant.Alive ) + return m_Occupant; + return null; + } + } + + public LeverPuzzleRegion ( LeverPuzzleController controller, int[] loc ) + : base( null, Map.Malas, Region.Find( LeverPuzzleController.lr_Enter, Map.Malas ), new Rectangle2D(loc[0],loc[1],1,1) ) + { + Controller = controller; + Register(); + } + + public override void OnEnter( Mobile m ) + { + if( m != null && m_Occupant == null && m is PlayerMobile && m.Alive ) + m_Occupant = m; + } + + public override void OnExit( Mobile m ) + { + if( m != null && m == m_Occupant ) + m_Occupant = null; + } + } +} + + diff --git a/Scripts/Engines/Ethics/Core/Ethic.cs b/Scripts/Engines/Ethics/Core/Ethic.cs new file mode 100644 index 0000000..eb82c6c --- /dev/null +++ b/Scripts/Engines/Ethics/Core/Ethic.cs @@ -0,0 +1,255 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; + +namespace Server.Ethics +{ + public abstract class Ethic + { + public static readonly bool Enabled = false; + + public static Ethic Find( Item item ) + { + if ( ( item.SavedFlags & 0x100 ) != 0 ) + { + if ( item.Hue == Hero.Definition.PrimaryHue ) + return Hero; + + item.SavedFlags &= ~0x100; + } + + if ( ( item.SavedFlags & 0x200 ) != 0 ) + { + if ( item.Hue == Evil.Definition.PrimaryHue ) + return Evil; + + item.SavedFlags &= ~0x200; + } + + return null; + } + + public static bool CheckTrade( Mobile from, Mobile to, Mobile newOwner, Item item ) + { + Ethic itemEthic = Find( item ); + + if ( itemEthic == null || Find( newOwner ) == itemEthic ) + return true; + + if ( itemEthic == Hero ) + ( from == newOwner ? to : from ).SendMessage( "Only heros may receive this item." ); + else if ( itemEthic == Evil ) + ( from == newOwner ? to : from ).SendMessage( "Only the evil may receive this item." ); + + return false; + } + + public static bool CheckEquip( Mobile from, Item item ) + { + Ethic itemEthic = Find( item ); + + if ( itemEthic == null || Find( from ) == itemEthic ) + return true; + + if ( itemEthic == Hero ) + from.SendMessage( "Only heros may wear this item." ); + else if ( itemEthic == Evil ) + from.SendMessage( "Only the evil may wear this item." ); + + return false; + } + + public static bool IsImbued( Item item ) + { + return IsImbued( item, false ); + } + + public static bool IsImbued( Item item, bool recurse ) + { + if ( Find( item ) != null ) + return true; + + if ( recurse ) + { + foreach ( Item child in item.Items ) + { + if ( IsImbued( child, true ) ) + return true; + } + } + + return false; + } + + public static void Initialize() + { + if( Enabled ) + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + } + + public static void EventSink_Speech( SpeechEventArgs e ) + { + if ( e.Blocked || e.Handled ) + return; + + Player pl = Player.Find( e.Mobile ); + + if ( pl == null ) + { + for ( int i = 0; i < Ethics.Length; ++i ) + { + Ethic ethic = Ethics[i]; + + if ( !ethic.IsEligible( e.Mobile ) ) + continue; + + if ( !Insensitive.Equals( ethic.Definition.JoinPhrase.String, e.Speech ) ) + continue; + + bool isNearAnkh = false; + + foreach ( Item item in e.Mobile.GetItemsInRange( 2 ) ) + { + if ( item is Items.AnkhNorth || item is Items.AnkhWest ) + { + isNearAnkh = true; + break; + } + } + + if ( !isNearAnkh ) + continue; + + pl = new Player( ethic, e.Mobile ); + + pl.Attach(); + + e.Mobile.FixedEffect( 0x373A, 10, 30 ); + e.Mobile.PlaySound( 0x209 ); + + e.Handled = true; + break; + } + } + else + { + if (e.Mobile is PlayerMobile && (e.Mobile as PlayerMobile).DuelContext != null) + return; + + Ethic ethic = pl.Ethic; + + for ( int i = 0; i < ethic.Definition.Powers.Length; ++i ) + { + Power power = ethic.Definition.Powers[i]; + + if ( !Insensitive.Equals( power.Definition.Phrase.String, e.Speech ) ) + continue; + + if ( !power.CheckInvoke( pl ) ) + continue; + + power.BeginInvoke( pl ); + e.Handled = true; + + break; + } + } + } + + protected EthicDefinition m_Definition; + + protected PlayerCollection m_Players; + + public EthicDefinition Definition + { + get { return m_Definition; } + } + + public PlayerCollection Players + { + get { return m_Players; } + } + + public static Ethic Find( Mobile mob ) + { + return Find( mob, false, false ); + } + + public static Ethic Find( Mobile mob, bool inherit ) + { + return Find( mob, inherit, false ); + } + + public static Ethic Find( Mobile mob, bool inherit, bool allegiance ) + { + Player pl = Player.Find( mob ); + + if ( pl != null ) + return pl.Ethic; + + if ( inherit && mob is BaseCreature ) + { + BaseCreature bc = (BaseCreature) mob; + + if ( bc.Controlled ) + return Find( bc.ControlMaster, false ); + else if ( bc.Summoned ) + return Find( bc.SummonMaster, false ); + else if ( allegiance ) + return bc.EthicAllegiance; + } + + return null; + } + + public Ethic() + { + m_Players = new PlayerCollection(); + } + + public abstract bool IsEligible( Mobile mob ); + + public virtual void Deserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + int playerCount = reader.ReadEncodedInt(); + + for ( int i = 0; i < playerCount; ++i ) + { + Player pl = new Player( this, reader ); + + if ( pl.Mobile != null ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( pl.CheckAttach ) ); + } + + break; + } + } + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.WriteEncodedInt( m_Players.Count ); + + for ( int i = 0; i < m_Players.Count; ++i ) + m_Players[i].Serialize( writer ); + } + + public static readonly Ethic Hero = new Hero.HeroEthic(); + public static readonly Ethic Evil = new Evil.EvilEthic(); + + public static readonly Ethic[] Ethics = new Ethic[] + { + Hero, + Evil + }; + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Core/Persistance.cs b/Scripts/Engines/Ethics/Core/Persistance.cs new file mode 100644 index 0000000..f07eaa6 --- /dev/null +++ b/Scripts/Engines/Ethics/Core/Persistance.cs @@ -0,0 +1,66 @@ +using System; + +namespace Server.Ethics +{ + public class EthicsPersistance : Item + { + private static EthicsPersistance m_Instance; + + public static EthicsPersistance Instance { get { return m_Instance; } } + + public override string DefaultName + { + get { return "Ethics Persistance - Internal"; } + } + + [Constructable] + public EthicsPersistance() + : base( 1 ) + { + Movable = false; + + if ( m_Instance == null || m_Instance.Deleted ) + m_Instance = this; + else + base.Delete(); + } + + public EthicsPersistance( Serial serial ) + : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + for ( int i = 0; i < Ethics.Ethic.Ethics.Length; ++i ) + Ethics.Ethic.Ethics[i].Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + for ( int i = 0; i < Ethics.Ethic.Ethics.Length; ++i ) + Ethics.Ethic.Ethics[i].Deserialize( reader ); + + break; + } + } + } + + public override void Delete() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Core/Player.cs b/Scripts/Engines/Ethics/Core/Player.cs new file mode 100644 index 0000000..8ce2c60 --- /dev/null +++ b/Scripts/Engines/Ethics/Core/Player.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; + +namespace Server.Ethics +{ + public class PlayerCollection : System.Collections.ObjectModel.Collection + { + } + + [PropertyObject] + public class Player + { + public static Player Find( Mobile mob ) + { + return Find( mob, false ); + } + + public static Player Find( Mobile mob, bool inherit ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + { + if ( inherit && mob is BaseCreature ) + { + BaseCreature bc = mob as BaseCreature; + + if ( bc != null && bc.Controlled ) + pm = bc.ControlMaster as PlayerMobile; + else if ( bc != null && bc.Summoned ) + pm = bc.SummonMaster as PlayerMobile; + } + + if ( pm == null ) + return null; + } + + Player pl = pm.EthicPlayer; + + if ( pl != null && !pl.Ethic.IsEligible( pl.Mobile ) ) + pm.EthicPlayer = pl = null; + + return pl; + } + + private Ethic m_Ethic; + private Mobile m_Mobile; + + private int m_Power; + private int m_History; + + private Mobile m_Steed; + private Mobile m_Familiar; + + private DateTime m_Shield; + + public Ethic Ethic { get { return m_Ethic; } } + public Mobile Mobile { get { return m_Mobile; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public int Power { get { return m_Power; } set { m_Power = value; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public int History { get { return m_History; } set { m_History = value; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public Mobile Steed { get { return m_Steed; } set { m_Steed = value; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public Mobile Familiar { get { return m_Familiar; } set { m_Familiar = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsShielded + { + get + { + if ( m_Shield == DateTime.MinValue ) + return false; + + if ( DateTime.Now < ( m_Shield + TimeSpan.FromHours( 1.0 ) ) ) + return true; + + FinishShield(); + return false; + } + } + + public void BeginShield() + { + m_Shield = DateTime.Now; + } + + public void FinishShield() + { + m_Shield = DateTime.MinValue; + } + + public Player( Ethic ethic, Mobile mobile ) + { + m_Ethic = ethic; + m_Mobile = mobile; + + m_Power = 5; + m_History = 5; + } + + public void CheckAttach() + { + if ( m_Ethic.IsEligible( m_Mobile ) ) + Attach(); + } + + public void Attach() + { + if ( m_Mobile is PlayerMobile ) + ( m_Mobile as PlayerMobile ).EthicPlayer = this; + + m_Ethic.Players.Add( this ); + } + + public void Detach() + { + if ( m_Mobile is PlayerMobile ) + ( m_Mobile as PlayerMobile ).EthicPlayer = null; + + m_Ethic.Players.Remove( this ); + } + + public Player( Ethic ethic, GenericReader reader ) + { + m_Ethic = ethic; + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Mobile = reader.ReadMobile(); + + m_Power = reader.ReadEncodedInt(); + m_History = reader.ReadEncodedInt(); + + m_Steed = reader.ReadMobile(); + m_Familiar = reader.ReadMobile(); + + m_Shield = reader.ReadDeltaTime(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_Mobile ); + + writer.WriteEncodedInt( m_Power ); + writer.WriteEncodedInt( m_History ); + + writer.Write( m_Steed ); + writer.Write( m_Familiar ); + + writer.WriteDeltaTime( m_Shield ); + } + } +} diff --git a/Scripts/Engines/Ethics/Core/Power.cs b/Scripts/Engines/Ethics/Core/Power.cs new file mode 100644 index 0000000..1bba042 --- /dev/null +++ b/Scripts/Engines/Ethics/Core/Power.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics +{ + public abstract class Power + { + protected PowerDefinition m_Definition; + + public PowerDefinition Definition { get { return m_Definition; } } + + public virtual bool CheckInvoke( Player from ) + { + if ( !from.Mobile.CheckAlive() ) + return false; + + if ( from.Power < m_Definition.Power ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You lack the power to invoke this ability." ); + return false; + } + + return true; + } + + public abstract void BeginInvoke( Player from ); + + public virtual void FinishInvoke( Player from ) + { + from.Power -= m_Definition.Power; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Definitions/EthicDefinition.cs b/Scripts/Engines/Ethics/Definitions/EthicDefinition.cs new file mode 100644 index 0000000..b96e5e7 --- /dev/null +++ b/Scripts/Engines/Ethics/Definitions/EthicDefinition.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics +{ + public class EthicDefinition + { + private int m_PrimaryHue; + + private TextDefinition m_Title; + private TextDefinition m_Adjunct; + + private TextDefinition m_JoinPhrase; + + private Power[] m_Powers; + + public int PrimaryHue { get { return m_PrimaryHue; } } + + public TextDefinition Title { get { return m_Title; } } + public TextDefinition Adjunct { get { return m_Adjunct; } } + + public TextDefinition JoinPhrase { get { return m_JoinPhrase; } } + + public Power[] Powers { get { return m_Powers; } } + + public EthicDefinition( int primaryHue, TextDefinition title, TextDefinition adjunct, TextDefinition joinPhrase, Power[] powers ) + { + m_PrimaryHue = primaryHue; + + m_Title = title; + m_Adjunct = adjunct; + + m_JoinPhrase = joinPhrase; + + m_Powers = powers; + } + } +} diff --git a/Scripts/Engines/Ethics/Definitions/PowerDefinition.cs b/Scripts/Engines/Ethics/Definitions/PowerDefinition.cs new file mode 100644 index 0000000..c20d19a --- /dev/null +++ b/Scripts/Engines/Ethics/Definitions/PowerDefinition.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics +{ + public class PowerDefinition + { + private int m_Power; + + private TextDefinition m_Name; + private TextDefinition m_Phrase; + private TextDefinition m_Description; + + public int Power { get { return m_Power; } } + + public TextDefinition Name { get { return m_Name; } } + public TextDefinition Phrase { get { return m_Phrase; } } + public TextDefinition Description { get { return m_Description; } } + + public PowerDefinition( int power, TextDefinition name, TextDefinition phrase, TextDefinition description ) + { + m_Power = power; + + m_Name = name; + m_Phrase = phrase; + m_Description = description; + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Ethic.cs b/Scripts/Engines/Ethics/Evil/Ethic.cs new file mode 100644 index 0000000..db02411 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Ethic.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Factions; + +namespace Server.Ethics.Evil +{ + public sealed class EvilEthic : Ethic + { + public EvilEthic() + { + m_Definition = new EthicDefinition( + 0x455, + "Evil", "(Evil)", + "I am evil incarnate", + new Power[] + { + new UnholySense(), + new UnholyItem(), + new SummonFamiliar(), + new VileBlade(), + new Blight(), + new UnholyShield(), + new UnholySteed(), + new UnholyWord() + } + ); + } + + public override bool IsEligible( Mobile mob ) + { + Faction fac = Faction.Find( mob ); + + return ( fac is Minax || fac is Shadowlords ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Evil/Mobiles/UnholyFamiliar.cs b/Scripts/Engines/Ethics/Evil/Mobiles/UnholyFamiliar.cs new file mode 100644 index 0000000..c77ec04 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Mobiles/UnholyFamiliar.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Ethics; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "an evil corpse" )] + public class UnholyFamiliar : BaseCreature + { + public override bool IsDispellable { get { return false; } } + public override bool IsBondable { get { return false; } } + + [Constructable] + public UnholyFamiliar() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a dark wolf"; + Body = 99; + BaseSoundID = 0xE5; + + SetStr( 96, 120 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + SetMana( 0 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 57.6, 75.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 2500; + Karma = 2500; + + VirtualArmor = 22; + + Tamable = false; + ControlSlots = 1; + } + + public override int Meat { get { return 1; } } + public override int Hides { get { return 7; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + public override PackInstinct PackInstinct { get { return PackInstinct.Canine; } } + + public UnholyFamiliar( Serial serial ) + : base( serial ) + { + } + + public override string ApplyNameSuffix( string suffix ) + { + if ( suffix.Length == 0 ) + suffix = Ethic.Evil.Definition.Adjunct.String; + else + suffix = String.Concat( suffix, " ", Ethic.Evil.Definition.Adjunct.String ); + + return base.ApplyNameSuffix( suffix ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Evil/Mobiles/UnholySteed.cs b/Scripts/Engines/Ethics/Evil/Mobiles/UnholySteed.cs new file mode 100644 index 0000000..ed3bda5 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Mobiles/UnholySteed.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Ethics; + +namespace Server.Mobiles +{ + [CorpseName( "an unholy corpse" )] + public class UnholySteed : BaseMount + { + public override bool IsDispellable { get { return false; } } + public override bool IsBondable { get { return false; } } + + public override bool HasBreath { get { return true; } } + public override bool CanBreath { get { return true; } } + + [Constructable] + public UnholySteed() + : base( "a dark steed", 0x74, 0x3EA7, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + SetStr( 496, 525 ); + SetDex( 86, 105 ); + SetInt( 86, 125 ); + + SetHits( 298, 315 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Fire, 40 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 80.5, 92.5 ); + + Fame = 14000; + Karma = -14000; + + VirtualArmor = 60; + + Tamable = false; + ControlSlots = 1; + } + + public override FoodType FavoriteFood { get { return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public UnholySteed( Serial serial ) + : base( serial ) + { + } + + public override string ApplyNameSuffix( string suffix ) + { + if ( suffix.Length == 0 ) + suffix = Ethic.Evil.Definition.Adjunct.String; + else + suffix = String.Concat( suffix, " ", Ethic.Evil.Definition.Adjunct.String ); + + return base.ApplyNameSuffix( suffix ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Ethic.Find( from ) != Ethic.Evil ) + from.SendMessage( "You may not ride this steed." ); + else + base.OnDoubleClick( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Evil/Powers/Blight.cs b/Scripts/Engines/Ethics/Evil/Powers/Blight.cs new file mode 100644 index 0000000..039c327 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/Blight.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Spells; + +namespace Server.Ethics.Evil +{ + public sealed class Blight : Power + { + public Blight() + { + m_Definition = new PowerDefinition( + 15, + "Blight", + "Velgo Ontawl", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + from.Mobile.BeginTarget( 12, true, Targeting.TargetFlags.None, new TargetStateCallback( Power_OnTarget ), from ); + from.Mobile.SendMessage( "Where do you wish to blight?" ); + } + + private void Power_OnTarget( Mobile fromMobile, object obj, object state ) + { + Player from = state as Player; + + IPoint3D p = obj as IPoint3D; + + if ( p == null ) + return; + + if ( !CheckInvoke( from ) ) + return; + + bool powerFunctioned = false; + + SpellHelper.GetSurfaceTop( ref p ); + + foreach ( Mobile mob in from.Mobile.GetMobilesInRange( 6 ) ) + { + if ( mob == from.Mobile || !SpellHelper.ValidIndirectTarget( from.Mobile, mob ) ) + continue; + + if ( mob.GetStatMod( "Holy Curse" ) != null ) + continue; + + if ( !from.Mobile.CanBeHarmful( mob, false ) ) + continue; + + from.Mobile.DoHarmful( mob, true ); + + mob.AddStatMod( new StatMod( StatType.All, "Holy Curse", -10, TimeSpan.FromMinutes( 30.0 ) ) ); + + mob.FixedParticles( 0x374A, 10, 15, 5028, EffectLayer.Waist ); + mob.PlaySound( 0x1FB ); + + powerFunctioned = true; + } + + if ( powerFunctioned ) + { + SpellHelper.Turn( from.Mobile, p ); + + Effects.PlaySound( p, from.Mobile.Map, 0x1FB ); + + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You curse the area." ); + + FinishInvoke( from ); + } + else + { + from.Mobile.FixedEffect( 0x3735, 6, 30 ); + from.Mobile.PlaySound( 0x5C ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/SummonFamiliar.cs b/Scripts/Engines/Ethics/Evil/Powers/SummonFamiliar.cs new file mode 100644 index 0000000..beffca8 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/SummonFamiliar.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; + +namespace Server.Ethics.Evil +{ + public sealed class SummonFamiliar : Power + { + public SummonFamiliar() + { + m_Definition = new PowerDefinition( + 5, + "Summon Familiar", + "Trubechs Vingir", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + if ( from.Familiar != null && from.Familiar.Deleted ) + from.Familiar = null; + + if ( from.Familiar != null ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You already have an unholy familiar." ); + return; + } + + if ( ( from.Mobile.Followers + 1 ) > from.Mobile.FollowersMax ) + { + from.Mobile.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return; + } + + UnholyFamiliar familiar = new UnholyFamiliar(); + + if ( Mobiles.BaseCreature.Summon( familiar, from.Mobile, from.Mobile.Location, 0x217, TimeSpan.FromHours( 1.0 ) ) ) + { + from.Familiar = familiar; + + FinishInvoke( from ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/UnholyItem.cs b/Scripts/Engines/Ethics/Evil/Powers/UnholyItem.cs new file mode 100644 index 0000000..0d8f106 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/UnholyItem.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.Ethics.Evil +{ + public sealed class UnholyItem : Power + { + public UnholyItem() + { + m_Definition = new PowerDefinition( + 5, + "Unholy Item", + "Vidda K'balc", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + from.Mobile.BeginTarget( 12, false, Targeting.TargetFlags.None, new TargetStateCallback( Power_OnTarget ), from ); + from.Mobile.SendMessage( "Which item do you wish to imbue?" ); + } + + private void Power_OnTarget( Mobile fromMobile, object obj, object state ) + { + Player from = state as Player; + + Item item = obj as Item; + + if ( item == null ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You may not imbue that." ); + return; + } + + if ( item.Parent != from.Mobile ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You may only imbue items you are wearing." ); + return; + } + + if ( ( item.SavedFlags & 0x300 ) != 0 ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "That has already beem imbued." ); + return; + } + + bool canImbue = ( item is Spellbook || item is BaseClothing || item is BaseArmor || item is BaseWeapon ) && ( item.Name == null ); + + if ( canImbue ) + { + if ( !CheckInvoke( from ) ) + return; + + item.Hue = Ethic.Evil.Definition.PrimaryHue; + item.SavedFlags |= 0x200; + + from.Mobile.FixedEffect( 0x375A, 10, 20 ); + from.Mobile.PlaySound( 0x209 ); + + FinishInvoke( from ); + } + else + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You may not imbue that." ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs b/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs new file mode 100644 index 0000000..5637a50 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/UnholySense.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Evil +{ + public sealed class UnholySense : Power + { + public UnholySense() + { + m_Definition = new PowerDefinition( + 0, + "Unholy Sense", + "Drewrok Velgo", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + Ethic opposition = Ethic.Hero; + + int enemyCount = 0; + + int maxRange = 18 + from.Power; + + Player primary = null; + + foreach ( Player pl in opposition.Players ) + { + Mobile mob = pl.Mobile; + + if ( mob == null || mob.Map != from.Mobile.Map || !mob.Alive ) + continue; + + if ( !mob.InRange( from.Mobile, Math.Max( 18, maxRange - pl.Power ) ) ) + continue; + + if ( primary == null || pl.Power > primary.Power ) + primary = pl; + + ++enemyCount; + } + + StringBuilder sb = new StringBuilder(); + + sb.Append( "You sense " ); + sb.Append( enemyCount == 0 ? "no" : enemyCount.ToString() ); + sb.Append( enemyCount == 1 ? " enemy" : " enemies" ); + + if ( primary != null ) + { + sb.Append( ", and a strong presense" ); + + switch ( from.Mobile.GetDirectionTo( primary.Mobile ) ) + { + case Direction.West: + sb.Append( " to the west." ); + break; + case Direction.East: + sb.Append( " to the east." ); + break; + case Direction.North: + sb.Append( " to the north." ); + break; + case Direction.South: + sb.Append( " to the south." ); + break; + + case Direction.Up: + sb.Append( " to the north-west." ); + break; + case Direction.Down: + sb.Append( " to the south-east." ); + break; + case Direction.Left: + sb.Append( " to the south-west." ); + break; + case Direction.Right: + sb.Append( " to the north-east." ); + break; + } + } + else + { + sb.Append( '.' ); + } + + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x59, false, sb.ToString() ); + + FinishInvoke( from ); + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/UnholyShield.cs b/Scripts/Engines/Ethics/Evil/Powers/UnholyShield.cs new file mode 100644 index 0000000..d685fa7 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/UnholyShield.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Evil +{ + public sealed class UnholyShield : Power + { + public UnholyShield() + { + m_Definition = new PowerDefinition( + 20, + "Unholy Shield", + "Velgo K'blac", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + if ( from.IsShielded ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You are already under the protection of an unholy shield." ); + return; + } + + from.BeginShield(); + + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You are now under the protection of an unholy shield." ); + + FinishInvoke( from ); + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/UnholySteed.cs b/Scripts/Engines/Ethics/Evil/Powers/UnholySteed.cs new file mode 100644 index 0000000..0de232d --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/UnholySteed.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; + +namespace Server.Ethics.Evil +{ + public sealed class UnholySteed : Power + { + public UnholySteed() + { + m_Definition = new PowerDefinition( + 30, + "Unholy Steed", + "Trubechs Yeliab", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + if ( from.Steed != null && from.Steed.Deleted ) + from.Steed = null; + + if ( from.Steed != null ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You already have an unholy steed." ); + return; + } + + if ( ( from.Mobile.Followers + 1 ) > from.Mobile.FollowersMax ) + { + from.Mobile.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return; + } + + Mobiles.UnholySteed steed = new Mobiles.UnholySteed(); + + if ( Mobiles.BaseCreature.Summon( steed, from.Mobile, from.Mobile.Location, 0x217, TimeSpan.FromHours( 1.0 ) ) ) + { + from.Steed = steed; + + FinishInvoke( from ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/UnholyWord.cs b/Scripts/Engines/Ethics/Evil/Powers/UnholyWord.cs new file mode 100644 index 0000000..6e1f124 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/UnholyWord.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Evil +{ + public sealed class UnholyWord : Power + { + public UnholyWord() + { + m_Definition = new PowerDefinition( + 100, + "Unholy Word", + "Velgo Oostrac", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + } + } +} diff --git a/Scripts/Engines/Ethics/Evil/Powers/VileBlade.cs b/Scripts/Engines/Ethics/Evil/Powers/VileBlade.cs new file mode 100644 index 0000000..ceb5b02 --- /dev/null +++ b/Scripts/Engines/Ethics/Evil/Powers/VileBlade.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Evil +{ + public sealed class VileBlade : Power + { + public VileBlade() + { + m_Definition = new PowerDefinition( + 10, + "Vile Blade", + "Velgo Reyam", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Ethic.cs b/Scripts/Engines/Ethics/Hero/Ethic.cs new file mode 100644 index 0000000..9f80b20 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Ethic.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Factions; + +namespace Server.Ethics.Hero +{ + public sealed class HeroEthic : Ethic + { + public HeroEthic() + { + m_Definition = new EthicDefinition( + 0x482, + "Hero", "(Hero)", + "I will defend the virtues", + new Power[] + { + new HolySense(), + new HolyItem(), + new SummonFamiliar(), + new HolyBlade(), + new Bless(), + new HolyShield(), + new HolySteed(), + new HolyWord() + } + ); + } + + public override bool IsEligible( Mobile mob ) + { + if ( mob.Kills >= 5 ) + return false; + + Faction fac = Faction.Find( mob ); + + return ( fac is TrueBritannians || fac is CouncilOfMages ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Hero/Mobiles/HolyFamiliar.cs b/Scripts/Engines/Ethics/Hero/Mobiles/HolyFamiliar.cs new file mode 100644 index 0000000..ecc8ef5 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Mobiles/HolyFamiliar.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Ethics; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a holy corpse" )] + public class HolyFamiliar : BaseCreature + { + public override bool IsDispellable { get { return false; } } + public override bool IsBondable { get { return false; } } + + [Constructable] + public HolyFamiliar() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a silver wolf"; + Body = 100; + BaseSoundID = 0xE5; + + SetStr( 96, 120 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + SetMana( 0 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 57.6, 75.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 2500; + Karma = 2500; + + VirtualArmor = 22; + + Tamable = false; + ControlSlots = 1; + } + + public override int Meat { get { return 1; } } + public override int Hides { get { return 7; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + public override PackInstinct PackInstinct { get { return PackInstinct.Canine; } } + + public HolyFamiliar( Serial serial ) + : base( serial ) + { + } + + public override string ApplyNameSuffix( string suffix ) + { + if ( suffix.Length == 0 ) + suffix = Ethic.Hero.Definition.Adjunct.String; + else + suffix = String.Concat( suffix, " ", Ethic.Hero.Definition.Adjunct.String ); + + return base.ApplyNameSuffix( suffix ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Hero/Mobiles/HolySteed.cs b/Scripts/Engines/Ethics/Hero/Mobiles/HolySteed.cs new file mode 100644 index 0000000..11f8bf4 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Mobiles/HolySteed.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Ethics; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a holy corpse" )] + public class HolySteed : BaseMount + { + public override bool IsDispellable { get{ return false; } } + public override bool IsBondable { get { return false; } } + + public override bool HasBreath { get { return true; } } + public override bool CanBreath { get { return true; } } + + [Constructable] + public HolySteed() + : base( "a silver steed", 0x75, 0x3EA8, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + SetStr( 496, 525 ); + SetDex( 86, 105 ); + SetInt( 86, 125 ); + + SetHits( 298, 315 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Fire, 40 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 80.5, 92.5 ); + + Fame = 14000; + Karma = 14000; + + VirtualArmor = 60; + + Tamable = false; + ControlSlots = 1; + } + + public override FoodType FavoriteFood { get { return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public HolySteed( Serial serial ) + : base( serial ) + { + } + + public override string ApplyNameSuffix( string suffix ) + { + if ( suffix.Length == 0 ) + suffix = Ethic.Hero.Definition.Adjunct.String; + else + suffix = String.Concat( suffix, " ", Ethic.Hero.Definition.Adjunct.String ); + + return base.ApplyNameSuffix( suffix ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Ethic.Find( from ) != Ethic.Hero ) + from.SendMessage( "You may not ride this steed." ); + else + base.OnDoubleClick( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Ethics/Hero/Powers/Bless.cs b/Scripts/Engines/Ethics/Hero/Powers/Bless.cs new file mode 100644 index 0000000..b01ae4a --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/Bless.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Spells; + +namespace Server.Ethics.Hero +{ + public sealed class Bless : Power + { + public Bless() + { + m_Definition = new PowerDefinition( + 15, + "Bless", + "Erstok Ontawl", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + from.Mobile.BeginTarget( 12, true, Targeting.TargetFlags.None, new TargetStateCallback( Power_OnTarget ), from ); + from.Mobile.SendMessage( "Where do you wish to bless?" ); + } + + private void Power_OnTarget( Mobile fromMobile, object obj, object state ) + { + Player from = state as Player; + + IPoint3D p = obj as IPoint3D; + + if ( p == null ) + return; + + if ( !CheckInvoke( from ) ) + return; + + bool powerFunctioned = false; + + SpellHelper.GetSurfaceTop( ref p ); + + foreach ( Mobile mob in from.Mobile.GetMobilesInRange( 6 ) ) + { + if ( mob != from.Mobile && SpellHelper.ValidIndirectTarget( from.Mobile, mob ) ) + continue; + + if ( mob.GetStatMod( "Holy Bless" ) != null ) + continue; + + if ( !from.Mobile.CanBeBeneficial( mob, false ) ) + continue; + + from.Mobile.DoBeneficial( mob ); + + mob.AddStatMod( new StatMod( StatType.All, "Holy Bless", 10, TimeSpan.FromMinutes( 30.0 ) ) ); + + mob.FixedParticles( 0x373A, 10, 15, 5018, EffectLayer.Waist ); + mob.PlaySound( 0x1EA ); + + powerFunctioned = true; + } + + if ( powerFunctioned ) + { + SpellHelper.Turn( from.Mobile, p ); + + Effects.PlaySound( p, from.Mobile.Map, 0x299 ); + + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You consecrate the area." ); + + FinishInvoke( from ); + } + else + { + from.Mobile.FixedEffect( 0x3735, 6, 30 ); + from.Mobile.PlaySound( 0x5C ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/HolyBlade.cs b/Scripts/Engines/Ethics/Hero/Powers/HolyBlade.cs new file mode 100644 index 0000000..746d0ec --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/HolyBlade.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Hero +{ + public sealed class HolyBlade : Power + { + public HolyBlade() + { + m_Definition = new PowerDefinition( + 10, + "Holy Blade", + "Erstok Reyam", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/HolyItem.cs b/Scripts/Engines/Ethics/Hero/Powers/HolyItem.cs new file mode 100644 index 0000000..1f14670 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/HolyItem.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.Ethics.Hero +{ + public sealed class HolyItem : Power + { + public HolyItem() + { + m_Definition = new PowerDefinition( + 5, + "Holy Item", + "Vidda K'balc", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + from.Mobile.BeginTarget( 12, false, Targeting.TargetFlags.None, new TargetStateCallback( Power_OnTarget ), from ); + from.Mobile.SendMessage( "Which item do you wish to imbue?" ); + } + + private void Power_OnTarget( Mobile fromMobile, object obj, object state ) + { + Player from = state as Player; + + Item item = obj as Item; + + if ( item == null ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You may not imbue that." ); + return; + } + + if ( item.Parent != from.Mobile ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You may only imbue items you are wearing." ); + return; + } + + if ( ( item.SavedFlags & 0x300 ) != 0 ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "That has already beem imbued." ); + return; + } + + bool canImbue = ( item is Spellbook || item is BaseClothing || item is BaseArmor || item is BaseWeapon ) && ( item.Name == null ); + + if ( canImbue ) + { + if ( !CheckInvoke( from ) ) + return; + + item.Hue = Ethic.Hero.Definition.PrimaryHue; + item.SavedFlags |= 0x100; + + from.Mobile.FixedEffect( 0x375A, 10, 20 ); + from.Mobile.PlaySound( 0x209 ); + + FinishInvoke( from ); + } + else + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You may not imbue that." ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs b/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs new file mode 100644 index 0000000..6833cfa --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/HolySense.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Hero +{ + public sealed class HolySense : Power + { + public HolySense() + { + m_Definition = new PowerDefinition( + 0, + "Holy Sense", + "Drewrok Erstok", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + Ethic opposition = Ethic.Evil; + + int enemyCount = 0; + + int maxRange = 18 + from.Power; + + Player primary = null; + + foreach ( Player pl in opposition.Players ) + { + Mobile mob = pl.Mobile; + + if ( mob == null || mob.Map != from.Mobile.Map || !mob.Alive ) + continue; + + if ( !mob.InRange( from.Mobile, Math.Max( 18, maxRange - pl.Power ) ) ) + continue; + + if ( primary == null || pl.Power > primary.Power ) + primary = pl; + + ++enemyCount; + } + + StringBuilder sb = new StringBuilder(); + + sb.Append( "You sense " ); + sb.Append( enemyCount == 0 ? "no" : enemyCount.ToString() ); + sb.Append( enemyCount == 1 ? " enemy" : " enemies" ); + + if ( primary != null ) + { + sb.Append( ", and a strong presense" ); + + switch ( from.Mobile.GetDirectionTo( primary.Mobile ) ) + { + case Direction.West: + sb.Append( " to the west." ); + break; + case Direction.East: + sb.Append( " to the east." ); + break; + case Direction.North: + sb.Append( " to the north." ); + break; + case Direction.South: + sb.Append( " to the south." ); + break; + + case Direction.Up: + sb.Append( " to the north-west." ); + break; + case Direction.Down: + sb.Append( " to the south-east." ); + break; + case Direction.Left: + sb.Append( " to the south-west." ); + break; + case Direction.Right: + sb.Append( " to the north-east." ); + break; + } + } + else + { + sb.Append( '.' ); + } + + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x59, false, sb.ToString() ); + + FinishInvoke( from ); + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/HolyShield.cs b/Scripts/Engines/Ethics/Hero/Powers/HolyShield.cs new file mode 100644 index 0000000..6d476c0 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/HolyShield.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Hero +{ + public sealed class HolyShield : Power + { + public HolyShield() + { + m_Definition = new PowerDefinition( + 20, + "Holy Shield", + "Erstok K'blac", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + if ( from.IsShielded ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You are already under the protection of a holy shield." ); + return; + } + + from.BeginShield(); + + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You are now under the protection of a holy shield." ); + + FinishInvoke( from ); + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/HolySteed.cs b/Scripts/Engines/Ethics/Hero/Powers/HolySteed.cs new file mode 100644 index 0000000..0ddc70b --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/HolySteed.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; + +namespace Server.Ethics.Hero +{ + public sealed class HolySteed : Power + { + public HolySteed() + { + m_Definition = new PowerDefinition( + 30, + "Holy Steed", + "Trubechs Yeliab", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + if ( from.Steed != null && from.Steed.Deleted ) + from.Steed = null; + + if ( from.Steed != null ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You already have a holy steed." ); + return; + } + + if ( ( from.Mobile.Followers + 1 ) > from.Mobile.FollowersMax ) + { + from.Mobile.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return; + } + + Mobiles.HolySteed steed = new Mobiles.HolySteed(); + + if ( Mobiles.BaseCreature.Summon( steed, from.Mobile, from.Mobile.Location, 0x217, TimeSpan.FromHours( 1.0 ) ) ) + { + from.Steed = steed; + + FinishInvoke( from ); + } + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/HolyWord.cs b/Scripts/Engines/Ethics/Hero/Powers/HolyWord.cs new file mode 100644 index 0000000..9c70355 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/HolyWord.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Ethics.Hero +{ + public sealed class HolyWord : Power + { + public HolyWord() + { + m_Definition = new PowerDefinition( + 100, + "Holy Word", + "Erstok Oostrac", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + } + } +} diff --git a/Scripts/Engines/Ethics/Hero/Powers/SummonFamiliar.cs b/Scripts/Engines/Ethics/Hero/Powers/SummonFamiliar.cs new file mode 100644 index 0000000..048a496 --- /dev/null +++ b/Scripts/Engines/Ethics/Hero/Powers/SummonFamiliar.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; + +namespace Server.Ethics.Hero +{ + public sealed class SummonFamiliar : Power + { + public SummonFamiliar() + { + m_Definition = new PowerDefinition( + 5, + "Summon Familiar", + "Trubechs Vingir", + "" + ); + } + + public override void BeginInvoke( Player from ) + { + if ( from.Familiar != null && from.Familiar.Deleted ) + from.Familiar = null; + + if ( from.Familiar != null ) + { + from.Mobile.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, false, "You already have a holy familiar." ); + return; + } + + if ( ( from.Mobile.Followers + 1 ) > from.Mobile.FollowersMax ) + { + from.Mobile.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return; + } + + HolyFamiliar familiar = new HolyFamiliar(); + + if ( Mobiles.BaseCreature.Summon( familiar, from.Mobile, from.Mobile.Location, 0x217, TimeSpan.FromHours( 1.0 ) ) ) + { + from.Familiar = familiar; + + FinishInvoke( from ); + } + } + } +} diff --git a/Scripts/Engines/Factions/Core/Election.cs b/Scripts/Engines/Factions/Core/Election.cs new file mode 100644 index 0000000..d188d67 --- /dev/null +++ b/Scripts/Engines/Factions/Core/Election.cs @@ -0,0 +1,564 @@ +using System; +using System.Net; +using System.Collections; +using Server; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class Election + { + public static readonly TimeSpan PendingPeriod = TimeSpan.FromDays( 5.0 ); + public static readonly TimeSpan CampaignPeriod = TimeSpan.FromDays( 1.0 ); + public static readonly TimeSpan VotingPeriod = TimeSpan.FromDays( 3.0 ); + + public const int MaxCandidates = 10; + public const int CandidateRank = 5; + + private Faction m_Faction; + private List m_Candidates; + + private ElectionState m_State; + private DateTime m_LastStateTime; + + public Faction Faction{ get{ return m_Faction; } } + + public List Candidates { get { return m_Candidates; } } + + public ElectionState State{ get{ return m_State; } set{ m_State = value; m_LastStateTime = DateTime.Now; } } + public DateTime LastStateTime{ get{ return m_LastStateTime; } } + + [CommandProperty( AccessLevel.GameMaster )] + public ElectionState CurrentState{ get{ return m_State; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public TimeSpan NextStateTime + { + get + { + TimeSpan period; + + switch ( m_State ) + { + default: + case ElectionState.Pending: period = PendingPeriod; break; + case ElectionState.Election: period = VotingPeriod; break; + case ElectionState.Campaign: period = CampaignPeriod; break; + } + + TimeSpan until = (m_LastStateTime + period) - DateTime.Now; + + if ( until < TimeSpan.Zero ) + until = TimeSpan.Zero; + + return until; + } + set + { + TimeSpan period; + + switch ( m_State ) + { + default: + case ElectionState.Pending: period = PendingPeriod; break; + case ElectionState.Election: period = VotingPeriod; break; + case ElectionState.Campaign: period = CampaignPeriod; break; + } + + m_LastStateTime = DateTime.Now - period + value; + } + } + + private Timer m_Timer; + + public void StartTimer() + { + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( Slice ) ); + } + + public Election( Faction faction ) + { + m_Faction = faction; + m_Candidates = new List(); + + StartTimer(); + } + + public Election( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Faction = Faction.ReadReference( reader ); + + m_LastStateTime = reader.ReadDateTime(); + m_State = (ElectionState)reader.ReadEncodedInt(); + + m_Candidates = new List(); + + int count = reader.ReadEncodedInt(); + + for ( int i = 0; i < count; ++i ) + { + Candidate cd = new Candidate( reader ); + + if ( cd.Mobile != null ) + m_Candidates.Add( cd ); + } + + break; + } + } + + StartTimer(); + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + + writer.Write( (DateTime) m_LastStateTime ); + writer.WriteEncodedInt( (int) m_State ); + + writer.WriteEncodedInt( m_Candidates.Count ); + + for ( int i = 0; i < m_Candidates.Count; ++i ) + m_Candidates[i].Serialize( writer ); + } + + public void AddCandidate( Mobile mob ) + { + if ( IsCandidate( mob ) ) + return; + + m_Candidates.Add( new Candidate( mob ) ); + mob.SendLocalizedMessage( 1010117 ); // You are now running for office. + } + + public void RemoveVoter( Mobile mob ) + { + if ( m_State == ElectionState.Election ) + { + for ( int i = 0; i < m_Candidates.Count; ++i ) + { + List voters = m_Candidates[i].Voters; + + for ( int j = 0; j < voters.Count; ++j ) + { + Voter voter = voters[j]; + + if ( voter.From == mob ) + voters.RemoveAt( j-- ); + } + } + } + } + + public void RemoveCandidate( Mobile mob ) + { + Candidate cd = FindCandidate( mob ); + + if ( cd == null ) + return; + + m_Candidates.Remove( cd ); + mob.SendLocalizedMessage( 1038031 ); + + if ( m_State == ElectionState.Election ) + { + if ( m_Candidates.Count == 1 ) + { + m_Faction.Broadcast( 1038031 ); // There are no longer any valid candidates in the Faction Commander election. + + Candidate winner = m_Candidates[0]; + + Mobile winMob = winner.Mobile; + PlayerState pl = PlayerState.Find( winMob ); + + if ( pl == null || pl.Faction != m_Faction || winMob == m_Faction.Commander ) + { + m_Faction.Broadcast( 1038026 ); // Faction leadership has not changed. + } + else + { + m_Faction.Broadcast( 1038028 ); // The faction has a new commander. + m_Faction.Commander = winMob; + } + + m_Candidates.Clear(); + State = ElectionState.Pending; + } + else if ( m_Candidates.Count == 0 ) // well, I guess this'll never happen + { + m_Faction.Broadcast( 1038031 ); // There are no longer any valid candidates in the Faction Commander election. + + m_Candidates.Clear(); + State = ElectionState.Pending; + } + } + } + + public bool IsCandidate( Mobile mob ) + { + return ( FindCandidate( mob ) != null ); + } + + public bool CanVote( Mobile mob ) + { + return ( m_State == ElectionState.Election && !HasVoted( mob ) ); + } + + public bool HasVoted( Mobile mob ) + { + return ( FindVoter( mob ) != null ); + } + + public Candidate FindCandidate( Mobile mob ) + { + for ( int i = 0; i < m_Candidates.Count; ++i ) + { + if ( m_Candidates[i].Mobile == mob ) + return m_Candidates[i]; + } + + return null; + } + + public Candidate FindVoter( Mobile mob ) + { + for ( int i = 0; i < m_Candidates.Count; ++i ) + { + List voters = m_Candidates[i].Voters; + + for ( int j = 0; j < voters.Count; ++j ) + { + Voter voter = voters[j]; + + if ( voter.From == mob ) + return m_Candidates[i]; + } + } + + return null; + } + + public bool CanBeCandidate( Mobile mob ) + { + if ( IsCandidate( mob ) ) + return false; + + if ( m_Candidates.Count >= MaxCandidates ) + return false; + + if ( m_State != ElectionState.Campaign ) + return false; // sanity.. + + PlayerState pl = PlayerState.Find( mob ); + + return ( pl != null && pl.Faction == m_Faction && pl.Rank.Rank >= CandidateRank ); + } + + public void Slice() + { + if ( m_Faction.Election != this ) + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + return; + } + + switch ( m_State ) + { + case ElectionState.Pending: + { + if ( (m_LastStateTime + PendingPeriod) > DateTime.Now ) + break; + + m_Faction.Broadcast( 1038023 ); // Campaigning for the Faction Commander election has begun. + + m_Candidates.Clear(); + State = ElectionState.Campaign; + + break; + } + case ElectionState.Campaign: + { + if ( (m_LastStateTime + CampaignPeriod) > DateTime.Now ) + break; + + if ( m_Candidates.Count == 0 ) + { + m_Faction.Broadcast( 1038025 ); // Nobody ran for office. + State = ElectionState.Pending; + } + else if ( m_Candidates.Count == 1 ) + { + m_Faction.Broadcast( 1038029 ); // Only one member ran for office. + + Candidate winner = m_Candidates[0]; + + Mobile mob = winner.Mobile; + PlayerState pl = PlayerState.Find( mob ); + + if ( pl == null || pl.Faction != m_Faction || mob == m_Faction.Commander ) + { + m_Faction.Broadcast( 1038026 ); // Faction leadership has not changed. + } + else + { + m_Faction.Broadcast( 1038028 ); // The faction has a new commander. + m_Faction.Commander = mob; + } + + m_Candidates.Clear(); + State = ElectionState.Pending; + } + else + { + m_Faction.Broadcast( 1038030 ); + State = ElectionState.Election; + } + + break; + } + case ElectionState.Election: + { + if ( (m_LastStateTime + VotingPeriod) > DateTime.Now ) + break; + + m_Faction.Broadcast( 1038024 ); // The results for the Faction Commander election are in + + Candidate winner = null; + + for ( int i = 0; i < m_Candidates.Count; ++i ) + { + Candidate cd = m_Candidates[i]; + + PlayerState pl = PlayerState.Find( cd.Mobile ); + + if ( pl == null || pl.Faction != m_Faction ) + continue; + + //cd.CleanMuleVotes(); + + if ( winner == null || cd.Votes > winner.Votes ) + winner = cd; + } + + if ( winner == null ) + { + m_Faction.Broadcast( 1038026 ); // Faction leadership has not changed. + } + else if ( winner.Mobile == m_Faction.Commander ) + { + m_Faction.Broadcast( 1038027 ); // The incumbent won the election. + } + else + { + m_Faction.Broadcast( 1038028 ); // The faction has a new commander. + m_Faction.Commander = winner.Mobile; + } + + m_Candidates.Clear(); + State = ElectionState.Pending; + + break; + } + } + } + } + + public class Voter + { + private Mobile m_From; + private Mobile m_Candidate; + + private IPAddress m_Address; + private DateTime m_Time; + + public Mobile From + { + get{ return m_From; } + } + + public Mobile Candidate + { + get{ return m_Candidate; } + } + + public IPAddress Address + { + get{ return m_Address; } + } + + public DateTime Time + { + get{ return m_Time; } + } + + public object[] AcquireFields() + { + TimeSpan gameTime = TimeSpan.Zero; + + if ( m_From is PlayerMobile ) + gameTime = ((PlayerMobile)m_From).GameTime; + + int kp = 0; + + PlayerState pl = PlayerState.Find( m_From ); + + if ( pl != null ) + kp = pl.KillPoints; + + int sk = m_From.Skills.Total; + + int factorSkills = 50 + ( (sk * 100 ) / 10000 ); + int factorKillPts = 100 + (kp*2); + int factorGameTime = 50 + (int) ( (gameTime.Ticks * 100) / TimeSpan.TicksPerDay ); + + int totalFactor = ( factorSkills * factorKillPts * Math.Max( factorGameTime, 100 ) ) / 10000; + + if ( totalFactor > 100 ) + totalFactor = 100; + else if ( totalFactor < 0 ) + totalFactor = 0; + + return new object[]{ m_From, m_Address, m_Time, totalFactor }; + } + + public Voter( Mobile from, Mobile candidate ) + { + m_From = from; + m_Candidate = candidate; + + if ( m_From.NetState != null ) + m_Address = m_From.NetState.Address; + else + m_Address = IPAddress.None; + + m_Time = DateTime.Now; + } + + public Voter( GenericReader reader, Mobile candidate ) + { + m_Candidate = candidate; + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_From = reader.ReadMobile(); + m_Address = Utility.Intern( reader.ReadIPAddress() ); + m_Time = reader.ReadDateTime(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); + + writer.Write( (Mobile) m_From ); + writer.Write( (IPAddress) m_Address ); + writer.Write( (DateTime) m_Time ); + } + } + + public class Candidate + { + private Mobile m_Mobile; + private List m_Voters; + + public Mobile Mobile{ get{ return m_Mobile; } } + public List Voters { get { return m_Voters; } } + + public int Votes{ get{ return m_Voters.Count; } } + + public void CleanMuleVotes() + { + for ( int i = 0; i < m_Voters.Count; ++i ) + { + Voter voter = (Voter)m_Voters[i]; + + if ( (int)voter.AcquireFields()[3] < 90 ) + m_Voters.RemoveAt( i-- ); + } + } + + public Candidate( Mobile mob ) + { + m_Mobile = mob; + m_Voters = new List(); + } + + public Candidate( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_Mobile = reader.ReadMobile(); + + int count = reader.ReadEncodedInt(); + m_Voters = new List( count ); + + for ( int i = 0; i < count; ++i ) + { + Voter voter = new Voter( reader, m_Mobile ); + + if ( voter.From != null ) + m_Voters.Add( voter ); + } + + break; + } + case 0: + { + m_Mobile = reader.ReadMobile(); + + List mobs = reader.ReadStrongMobileList(); + m_Voters = new List( mobs.Count ); + + for ( int i = 0; i < mobs.Count; ++i ) + m_Voters.Add( new Voter( mobs[i], m_Mobile ) ); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 1 ); // version + + writer.Write( (Mobile) m_Mobile ); + + writer.WriteEncodedInt( (int) m_Voters.Count ); + + for ( int i = 0; i < m_Voters.Count; ++i ) + ((Voter)m_Voters[i]).Serialize( writer ); + } + } + + public enum ElectionState + { + Pending, + Campaign, + Election + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/Faction.cs b/Scripts/Engines/Factions/Core/Faction.cs new file mode 100644 index 0000000..b45888f --- /dev/null +++ b/Scripts/Engines/Factions/Core/Faction.cs @@ -0,0 +1,1435 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Guilds; +using Server.Mobiles; +using Server.Prompts; +using Server.Targeting; +using Server.Accounting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Factions +{ + [CustomEnum( new string[]{ "Minax", "Council of Mages", "True Britannians", "Shadowlords" } )] + public abstract class Faction : IComparable + { + public int ZeroRankOffset; + + private FactionDefinition m_Definition; + private FactionState m_State; + private StrongholdRegion m_StrongholdRegion; + + public StrongholdRegion StrongholdRegion + { + get{ return m_StrongholdRegion; } + set{ m_StrongholdRegion = value; } + } + + public FactionDefinition Definition + { + get{ return m_Definition; } + set + { + m_Definition = value; + m_StrongholdRegion = new StrongholdRegion( this ); + } + } + + public FactionState State + { + get{ return m_State; } + set{ m_State = value; } + } + + public Election Election + { + get{ return m_State.Election; } + set{ m_State.Election = value; } + } + + public Mobile Commander + { + get{ return m_State.Commander; } + set{ m_State.Commander = value; } + } + + public int Tithe + { + get{ return m_State.Tithe; } + set{ m_State.Tithe = value; } + } + + public int Silver + { + get{ return m_State.Silver; } + set{ m_State.Silver = value; } + } + + public List Members + { + get{ return m_State.Members; } + set{ m_State.Members = value; } + } + + public static readonly TimeSpan LeavePeriod = TimeSpan.FromDays( 3.0 ); + + public bool FactionMessageReady + { + get{ return m_State.FactionMessageReady; } + } + + public void Broadcast( string text ) + { + Broadcast( 0x3B2, text ); + } + + public void Broadcast( int hue, string text ) + { + List members = Members; + + for ( int i = 0; i < members.Count; ++i ) + members[i].Mobile.SendMessage( hue, text ); + } + + public void Broadcast( int number ) + { + List members = Members; + + for ( int i = 0; i < members.Count; ++i ) + members[i].Mobile.SendLocalizedMessage( number ); + } + + public void Broadcast( string format, params object[] args ) + { + Broadcast( String.Format( format, args ) ); + } + + public void Broadcast( int hue, string format, params object[] args ) + { + Broadcast( hue, String.Format( format, args ) ); + } + + public void BeginBroadcast( Mobile from ) + { + from.SendLocalizedMessage( 1010265 ); // Enter Faction Message + from.Prompt = new BroadcastPrompt( this ); + } + + public void EndBroadcast( Mobile from, string text ) + { + if ( from.AccessLevel == AccessLevel.Player ) + m_State.RegisterBroadcast(); + + Broadcast( Definition.HueBroadcast, "{0} [Commander] {1} : {2}", from.Name, Definition.FriendlyName, text ); + } + + private class BroadcastPrompt : Prompt + { + private Faction m_Faction; + + public BroadcastPrompt( Faction faction ) + { + m_Faction = faction; + } + + public override void OnResponse( Mobile from, string text ) + { + m_Faction.EndBroadcast( from, text ); + } + } + + public static void HandleAtrophy() + { + foreach ( Faction f in Factions ) + { + if ( !f.State.IsAtrophyReady ) + return; + } + + List activePlayers = new List(); + + foreach ( Faction f in Factions ) + { + foreach ( PlayerState ps in f.Members ) + { + if ( ps.KillPoints > 0 && ps.IsActive ) + activePlayers.Add( ps ); + } + } + + int distrib = 0; + + foreach ( Faction f in Factions ) + distrib += f.State.CheckAtrophy(); + + if ( activePlayers.Count == 0 ) + return; + + for ( int i = 0; i < distrib; ++i ) + activePlayers[Utility.Random( activePlayers.Count )].KillPoints++; + } + + public static void DistributePoints( int distrib ) { + List activePlayers = new List(); + + foreach ( Faction f in Factions ) { + foreach ( PlayerState ps in f.Members ) { + if ( ps.KillPoints > 0 && ps.IsActive ) { + activePlayers.Add( ps ); + } + } + } + + if ( activePlayers.Count > 0 ) { + for ( int i = 0; i < distrib; ++i ) { + activePlayers[Utility.Random( activePlayers.Count )].KillPoints++; + } + } + } + + public void BeginHonorLeadership( Mobile from ) + { + from.SendLocalizedMessage( 502090 ); // Click on the player whom you wish to honor. + from.BeginTarget( 12, false, TargetFlags.None, new TargetCallback( HonorLeadership_OnTarget ) ); + } + + public void HonorLeadership_OnTarget( Mobile from, object obj ) + { + if ( obj is Mobile ) + { + Mobile recv = (Mobile) obj; + + PlayerState giveState = PlayerState.Find( from ); + PlayerState recvState = PlayerState.Find( recv ); + + if ( giveState == null ) + return; + + if ( recvState == null || recvState.Faction != giveState.Faction ) + { + from.SendLocalizedMessage( 1042497 ); // Only faction mates can be honored this way. + } + else if ( giveState.KillPoints < 5 ) + { + from.SendLocalizedMessage( 1042499 ); // You must have at least five kill points to honor them. + } + else + { + recvState.LastHonorTime = DateTime.Now; + giveState.KillPoints -= 5; + recvState.KillPoints += 4; + + // TODO: Confirm no message sent to giver + recv.SendLocalizedMessage( 1042500 ); // You have been honored with four kill points. + } + } + else + { + from.SendLocalizedMessage( 1042496 ); // You may only honor another player. + } + } + + public virtual void AddMember( Mobile mob ) + { + Members.Insert( ZeroRankOffset, new PlayerState( mob, this, Members ) ); + + mob.AddToBackpack( FactionItem.Imbue( new Robe(), this, false, Definition.HuePrimary ) ); + mob.SendLocalizedMessage( 1010374 ); // You have been granted a robe which signifies your faction + + mob.InvalidateProperties(); + mob.Delta( MobileDelta.Noto ); + + mob.FixedEffect( 0x373A, 10, 30 ); + mob.PlaySound( 0x209 ); + } + + public static bool IsNearType( Mobile mob, Type type, int range ) + { + bool mobs = type.IsSubclassOf( typeof( Mobile ) ); + bool items = type.IsSubclassOf( typeof( Item ) ); + + IPooledEnumerable eable; + + if ( mobs ) + eable = mob.GetMobilesInRange( range ); + else if ( items ) + eable = mob.GetItemsInRange( range ); + else + return false; + + foreach ( object obj in eable ) + { + if ( type.IsAssignableFrom( obj.GetType() ) ) + { + eable.Free(); + return true; + } + } + + eable.Free(); + return false; + } + + public static bool IsNearType( Mobile mob, Type[] types, int range ) + { + IPooledEnumerable eable = mob.GetObjectsInRange( range ); + + foreach( object obj in eable ) + { + Type objType = obj.GetType(); + + for( int i = 0; i < types.Length; i++ ) + { + if( types[i].IsAssignableFrom( objType ) ) + { + eable.Free(); + return true; + } + } + } + + eable.Free(); + return false; + } + + public void RemovePlayerState( PlayerState pl ) + { + if ( pl == null || !Members.Contains( pl ) ) + return; + + int killPoints = pl.KillPoints; + + if ( pl.RankIndex != -1 ) { + while ( ( pl.RankIndex + 1 ) < ZeroRankOffset ) { + PlayerState pNext = Members[pl.RankIndex+1] as PlayerState; + Members[pl.RankIndex+1] = pl; + Members[pl.RankIndex] = pNext; + pl.RankIndex++; + pNext.RankIndex--; + } + + ZeroRankOffset--; + } + + Members.Remove( pl ); + + PlayerMobile pm = (PlayerMobile)pl.Mobile; + if ( pm == null ) + return; + + Mobile mob = pl.Mobile; + if ( pm.FactionPlayerState == pl ) { + pm.FactionPlayerState = null; + + mob.InvalidateProperties(); + mob.Delta( MobileDelta.Noto ); + + if ( Election.IsCandidate( mob ) ) + Election.RemoveCandidate( mob ); + + if ( pl.Finance != null ) + pl.Finance.Finance = null; + + if ( pl.Sheriff != null ) + pl.Sheriff.Sheriff = null; + + Election.RemoveVoter( mob ); + + if ( Commander == mob ) + Commander = null; + + pm.ValidateEquipment(); + } + + if ( killPoints > 0 ) + DistributePoints( killPoints ); + } + + public void RemoveMember( Mobile mob ) + { + PlayerState pl = PlayerState.Find( mob ); + + if ( pl == null || !Members.Contains( pl ) ) + return; + + int killPoints = pl.KillPoints; + + if( mob.Backpack != null ) + { + //Ordinarily, through normal faction removal, this will never find any sigils. + //Only with a leave delay less than the ReturnPeriod or a Faction Kick/Ban, will this ever do anything + Item[] sigils = mob.Backpack.FindItemsByType( typeof( Sigil ) ); + + for ( int i = 0; i < sigils.Length; ++i ) + ((Sigil)sigils[i]).ReturnHome(); + } + + if ( pl.RankIndex != -1 ) { + while ( ( pl.RankIndex + 1 ) < ZeroRankOffset ) { + PlayerState pNext = Members[pl.RankIndex+1]; + Members[pl.RankIndex+1] = pl; + Members[pl.RankIndex] = pNext; + pl.RankIndex++; + pNext.RankIndex--; + } + + ZeroRankOffset--; + } + + Members.Remove( pl ); + + if ( mob is PlayerMobile ) + ((PlayerMobile)mob).FactionPlayerState = null; + + mob.InvalidateProperties(); + mob.Delta( MobileDelta.Noto ); + + if ( Election.IsCandidate( mob ) ) + Election.RemoveCandidate( mob ); + + Election.RemoveVoter( mob ); + + if ( pl.Finance != null ) + pl.Finance.Finance = null; + + if ( pl.Sheriff != null ) + pl.Sheriff.Sheriff = null; + + if ( Commander == mob ) + Commander = null; + + if ( mob is PlayerMobile ) + ((PlayerMobile)mob).ValidateEquipment(); + + if ( killPoints > 0 ) + DistributePoints( killPoints ); + } + + public void JoinGuilded( PlayerMobile mob, Guild guild ) + { + if ( mob.Young ) + { + guild.RemoveMember( mob ); + mob.SendLocalizedMessage( 1042283 ); // You have been kicked out of your guild! Young players may not remain in a guild which is allied with a faction. + } + else if ( AlreadyHasCharInFaction( mob ) ) + { + guild.RemoveMember( mob ); + mob.SendLocalizedMessage( 1005281 ); // You have been kicked out of your guild due to factional overlap + } + else if ( IsFactionBanned( mob ) ) + { + guild.RemoveMember( mob ); + mob.SendLocalizedMessage( 1005052 ); // You are currently banned from the faction system + } + else + { + AddMember( mob ); + mob.SendLocalizedMessage( 1042756, true, " " + m_Definition.FriendlyName ); // You are now joining a faction: + } + } + + public void JoinAlone( Mobile mob ) + { + AddMember( mob ); + mob.SendLocalizedMessage( 1005058 ); // You have joined the faction + } + + private bool AlreadyHasCharInFaction( Mobile mob ) + { + Account acct = mob.Account as Account; + + if ( acct != null ) + { + for ( int i = 0; i < acct.Length; ++i ) + { + Mobile c = acct[i]; + + if ( Find( c ) != null ) + return true; + } + } + + return false; + } + + public static bool IsFactionBanned( Mobile mob ) + { + Account acct = mob.Account as Account; + + if ( acct == null ) + return false; + + return ( acct.GetTag( "FactionBanned" ) != null ); + } + + public void OnJoinAccepted( Mobile mob ) + { + PlayerMobile pm = mob as PlayerMobile; + + if ( pm == null ) + return; // sanity + + PlayerState pl = PlayerState.Find( pm ); + + if ( pm.Young ) + pm.SendLocalizedMessage( 1010104 ); // You cannot join a faction as a young player + else if ( pl != null && pl.IsLeaving ) + pm.SendLocalizedMessage( 1005051 ); // You cannot use the faction stone until you have finished quitting your current faction + else if ( AlreadyHasCharInFaction( pm ) ) + pm.SendLocalizedMessage( 1005059 ); // You cannot join a faction because you already declared your allegiance with another character + else if ( IsFactionBanned( mob ) ) + pm.SendLocalizedMessage( 1005052 ); // You are currently banned from the faction system + else if ( pm.Guild != null ) + { + Guild guild = pm.Guild as Guild; + + if ( guild.Leader != pm ) + pm.SendLocalizedMessage( 1005057 ); // You cannot join a faction because you are in a guild and not the guildmaster + else if (guild.Type != GuildType.Regular) + pm.SendLocalizedMessage(1042161); // You cannot join a faction because your guild is an Order or Chaos type. + else if ( !Guild.NewGuildSystem && guild.Enemies != null && guild.Enemies.Count > 0 ) //CAN join w/wars in new system + pm.SendLocalizedMessage( 1005056 ); // You cannot join a faction with active Wars + else if ( Guild.NewGuildSystem && guild.Alliance != null ) + pm.SendLocalizedMessage( 1080454 ); // Your guild cannot join a faction while in alliance with non-factioned guilds. + else if ( !CanHandleInflux( guild.Members.Count ) ) + pm.SendLocalizedMessage( 1018031 ); // In the interest of faction stability, this faction declines to accept new members for now. + else + { + List members = new List( guild.Members ); + + for ( int i = 0; i < members.Count; ++i ) + { + PlayerMobile member = members[i] as PlayerMobile; + + if ( member == null ) + continue; + + JoinGuilded( member, guild ); + } + } + } + else if ( !CanHandleInflux( 1 ) ) + { + pm.SendLocalizedMessage( 1018031 ); // In the interest of faction stability, this faction declines to accept new members for now. + } + else + { + JoinAlone( mob ); + } + } + + public bool IsCommander( Mobile mob ) + { + if ( mob == null ) + return false; + + return ( mob.AccessLevel >= AccessLevel.GameMaster || mob == Commander ); + } + + public Faction() + { + m_State = new FactionState( this ); + } + + public override string ToString() + { + return m_Definition.FriendlyName; + } + + public int CompareTo( object obj ) + { + return m_Definition.Sort - ((Faction)obj).m_Definition.Sort; + } + + public static bool CheckLeaveTimer( Mobile mob ) + { + PlayerState pl = PlayerState.Find( mob ); + + if ( pl == null || !pl.IsLeaving ) + return false; + + if ( (pl.Leaving + LeavePeriod) >= DateTime.Now ) + return false; + + mob.SendLocalizedMessage( 1005163 ); // You have now quit your faction + + pl.Faction.RemoveMember( mob ); + + return true; + } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( EventSink_Login ); + EventSink.Logout += new LogoutEventHandler( EventSink_Logout ); + + Timer.DelayCall( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 10.0 ), new TimerCallback( HandleAtrophy ) ); + + Timer.DelayCall( TimeSpan.FromSeconds( 30.0 ), TimeSpan.FromSeconds( 30.0 ), new TimerCallback( ProcessTick ) ); + + CommandSystem.Register( "FactionElection", AccessLevel.GameMaster, new CommandEventHandler( FactionElection_OnCommand ) ); + CommandSystem.Register( "FactionCommander", AccessLevel.Administrator, new CommandEventHandler( FactionCommander_OnCommand ) ); + CommandSystem.Register( "FactionItemReset", AccessLevel.Administrator, new CommandEventHandler( FactionItemReset_OnCommand ) ); + CommandSystem.Register( "FactionReset", AccessLevel.Administrator, new CommandEventHandler( FactionReset_OnCommand ) ); + CommandSystem.Register( "FactionTownReset", AccessLevel.Administrator, new CommandEventHandler( FactionTownReset_OnCommand ) ); + } + + public static void FactionTownReset_OnCommand( CommandEventArgs e ) + { + List monoliths = BaseMonolith.Monoliths; + + for ( int i = 0; i < monoliths.Count; ++i ) + monoliths[i].Sigil = null; + + List towns = Town.Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + towns[i].Silver = 0; + towns[i].Sheriff = null; + towns[i].Finance = null; + towns[i].Tax = 0; + towns[i].Owner = null; + } + + List sigils = Sigil.Sigils; + + for ( int i = 0; i < sigils.Count; ++i ) + { + sigils[i].Corrupted = null; + sigils[i].Corrupting = null; + sigils[i].LastStolen = DateTime.MinValue; + sigils[i].GraceStart = DateTime.MinValue; + sigils[i].CorruptionStart = DateTime.MinValue; + sigils[i].PurificationStart = DateTime.MinValue; + sigils[i].LastMonolith = null; + sigils[i].ReturnHome(); + } + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction f = factions[i]; + + List list = new List( f.State.FactionItems ); + + for ( int j = 0; j < list.Count; ++j ) + { + FactionItem fi = list[j]; + + if ( fi.Expiration == DateTime.MinValue ) + fi.Item.Delete(); + else + fi.Detach(); + } + } + } + + public static void FactionReset_OnCommand( CommandEventArgs e ) + { + List monoliths = BaseMonolith.Monoliths; + + for ( int i = 0; i < monoliths.Count; ++i ) + monoliths[i].Sigil = null; + + List towns = Town.Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + towns[i].Silver = 0; + towns[i].Sheriff = null; + towns[i].Finance = null; + towns[i].Tax = 0; + towns[i].Owner = null; + } + + List sigils = Sigil.Sigils; + + for ( int i = 0; i < sigils.Count; ++i ) + { + sigils[i].Corrupted = null; + sigils[i].Corrupting = null; + sigils[i].LastStolen = DateTime.MinValue; + sigils[i].GraceStart = DateTime.MinValue; + sigils[i].CorruptionStart = DateTime.MinValue; + sigils[i].PurificationStart = DateTime.MinValue; + sigils[i].LastMonolith = null; + sigils[i].ReturnHome(); + } + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction f = factions[i]; + + List playerStateList = new List( f.Members ); + + for( int j = 0; j < playerStateList.Count; ++j ) + f.RemoveMember( playerStateList[j].Mobile ); + + List factionItemList = new List( f.State.FactionItems ); + + for( int j = 0; j < factionItemList.Count; ++j ) + { + FactionItem fi = (FactionItem)factionItemList[j]; + + if ( fi.Expiration == DateTime.MinValue ) + fi.Item.Delete(); + else + fi.Detach(); + } + + List factionTrapList = new List( f.Traps ); + + for( int j = 0; j < factionTrapList.Count; ++j ) + factionTrapList[j].Delete(); + } + } + + public static void FactionItemReset_OnCommand( CommandEventArgs e ) + { + ArrayList pots = new ArrayList(); + + foreach ( Item item in World.Items.Values ) + { + if ( item is IFactionItem && !(item is HoodedShroudOfShadows) ) + pots.Add( item ); + } + + int[] hues = new int[Factions.Count * 2]; + + for ( int i = 0; i < Factions.Count; ++i ) + { + hues[0+(i*2)] = Factions[i].Definition.HuePrimary; + hues[1+(i*2)] = Factions[i].Definition.HueSecondary; + } + + int count = 0; + + for ( int i = 0; i < pots.Count; ++i ) + { + Item item = (Item)pots[i]; + IFactionItem fci = (IFactionItem)item; + + if ( fci.FactionItemState != null || item.LootType != LootType.Blessed ) + continue; + + bool isHued = false; + + for ( int j = 0; j < hues.Length; ++j ) + { + if ( item.Hue == hues[j] ) + { + isHued = true; + break; + } + } + + if ( isHued ) + { + fci.FactionItemState = null; + ++count; + } + } + + e.Mobile.SendMessage( "{0} items reset", count ); + } + + public static void FactionCommander_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Target a player to make them the faction commander." ); + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( FactionCommander_OnTarget ) ); + } + + public static void FactionCommander_OnTarget( Mobile from, object obj ) + { + if ( obj is PlayerMobile ) + { + Mobile targ = (Mobile)obj; + PlayerState pl = PlayerState.Find( targ ); + + if ( pl != null ) + { + pl.Faction.Commander = targ; + from.SendMessage( "You have appointed them as the faction commander." ); + } + else + { + from.SendMessage( "They are not in a faction." ); + } + } + else + { + from.SendMessage( "That is not a player." ); + } + } + + public static void FactionElection_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Target a faction stone to open its election properties." ); + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( FactionElection_OnTarget ) ); + } + + public static void FactionElection_OnTarget( Mobile from, object obj ) + { + if ( obj is FactionStone ) + { + Faction faction = ((FactionStone)obj).Faction; + + if ( faction != null ) + from.SendGump( new ElectionManagementGump( faction.Election ) ); + //from.SendGump( new Gumps.PropertiesGump( from, faction.Election ) ); + else + from.SendMessage( "That stone has no faction assigned." ); + } + else + { + from.SendMessage( "That is not a faction stone." ); + } + } + + public static void FactionKick_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Target a player to remove them from their faction." ); + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( FactionKick_OnTarget ) ); + } + + public static void FactionKick_OnTarget( Mobile from, object obj ) + { + if ( obj is Mobile ) + { + Mobile mob = (Mobile) obj; + PlayerState pl = PlayerState.Find( (Mobile) mob ); + + if ( pl != null ) + { + pl.Faction.RemoveMember( mob ); + + mob.SendMessage( "You have been kicked from your faction." ); + from.SendMessage( "They have been kicked from their faction." ); + } + else + { + from.SendMessage( "They are not in a faction." ); + } + } + else + { + from.SendMessage( "That is not a player." ); + } + } + + public static void ProcessTick() + { + List sigils = Sigil.Sigils; + + for ( int i = 0; i < sigils.Count; ++i ) + { + Sigil sigil = sigils[i]; + + if ( !sigil.IsBeingCorrupted && sigil.GraceStart != DateTime.MinValue && (sigil.GraceStart + Sigil.CorruptionGrace) < DateTime.Now ) + { + if ( sigil.LastMonolith is StrongholdMonolith && ( sigil.Corrupted == null || sigil.LastMonolith.Faction != sigil.Corrupted )) + { + sigil.Corrupting = sigil.LastMonolith.Faction; + sigil.CorruptionStart = DateTime.Now; + } + else + { + sigil.Corrupting = null; + sigil.CorruptionStart = DateTime.MinValue; + } + + sigil.GraceStart = DateTime.MinValue; + } + + if ( sigil.LastMonolith == null || sigil.LastMonolith.Sigil == null ) + { + if ( (sigil.LastStolen + Sigil.ReturnPeriod) < DateTime.Now ) + sigil.ReturnHome(); + } + else + { + if ( sigil.IsBeingCorrupted && (sigil.CorruptionStart + Sigil.CorruptionPeriod) < DateTime.Now ) + { + sigil.Corrupted = sigil.Corrupting; + sigil.Corrupting = null; + sigil.CorruptionStart = DateTime.MinValue; + sigil.GraceStart = DateTime.MinValue; + } + else if ( sigil.IsPurifying && (sigil.PurificationStart + Sigil.PurificationPeriod) < DateTime.Now ) + { + sigil.PurificationStart = DateTime.MinValue; + sigil.Corrupted = null; + sigil.Corrupting = null; + sigil.CorruptionStart = DateTime.MinValue; + sigil.GraceStart = DateTime.MinValue; + } + } + } + } + + public static void HandleDeath( Mobile mob ) + { + HandleDeath( mob, null ); + } + + #region Skill Loss + public const double SkillLossFactor = 1.0 / 3; + public static readonly TimeSpan SkillLossPeriod = TimeSpan.FromMinutes( 20.0 ); + + private static Dictionary m_SkillLoss = new Dictionary(); + + private class SkillLossContext + { + public Timer m_Timer; + public List m_Mods; + } + + public static bool InSkillLoss( Mobile mob ) + { + return m_SkillLoss.ContainsKey( mob ); + } + + public static void ApplySkillLoss( Mobile mob ) + { + if ( InSkillLoss( mob ) ) + return; + + SkillLossContext context = new SkillLossContext(); + m_SkillLoss[mob] = context; + + List mods = context.m_Mods = new List(); + + for ( int i = 0; i < mob.Skills.Length; ++i ) + { + Skill sk = mob.Skills[i]; + double baseValue = sk.Base; + + if ( baseValue > 0 ) + { + SkillMod mod = new DefaultSkillMod( sk.SkillName, true, -(baseValue * SkillLossFactor) ); + + mods.Add( mod ); + mob.AddSkillMod( mod ); + } + } + + context.m_Timer = Timer.DelayCall( SkillLossPeriod, new TimerStateCallback( ClearSkillLoss_Callback ), mob ); + } + + private static void ClearSkillLoss_Callback( object state ) + { + ClearSkillLoss( (Mobile) state ); + } + + public static bool ClearSkillLoss( Mobile mob ) + { + SkillLossContext context; + + if ( !m_SkillLoss.TryGetValue( mob, out context ) ) + return false; + + m_SkillLoss.Remove( mob ); + + List mods = context.m_Mods; + + for ( int i = 0; i < mods.Count; ++i ) + mob.RemoveSkillMod( mods[i] ); + + context.m_Timer.Stop(); + + return true; + } + #endregion + + public int AwardSilver( Mobile mob, int silver ) + { + if ( silver <= 0 ) + return 0; + + int tithed = ( silver * Tithe ) / 100; + + Silver += tithed; + + silver = silver - tithed; + + if ( silver > 0 ) + mob.AddToBackpack( new Silver( silver ) ); + + return silver; + } + + public virtual int MaximumTraps{ get{ return 15; } } + + public List Traps + { + get{ return m_State.Traps; } + set{ m_State.Traps = value; } + } + + public const int StabilityFactor = 300; // 300% greater (3 times) than smallest faction + public const int StabilityActivation = 200; // Stablity code goes into effect when largest faction has > 200 people + + public static Faction FindSmallestFaction() + { + List factions = Factions; + Faction smallest = null; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction faction = factions[i]; + + if ( smallest == null || faction.Members.Count < smallest.Members.Count ) + smallest = faction; + } + + return smallest; + } + + public static bool StabilityActive() + { + List factions = Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction faction = factions[i]; + + if ( faction.Members.Count > StabilityActivation ) + return true; + } + + return false; + } + + public bool CanHandleInflux( int influx ) + { + if( !StabilityActive()) + return true; + + Faction smallest = FindSmallestFaction(); + + if ( smallest == null ) + return true; // sanity + + if ( StabilityFactor > 0 && (((this.Members.Count + influx) * 100) / StabilityFactor) > smallest.Members.Count ) + return false; + + return true; + } + + public static void HandleDeath( Mobile victim, Mobile killer ) + { + if ( killer == null ) + killer = victim.FindMostRecentDamager( true ); + + PlayerState killerState = PlayerState.Find( killer ); + + Container pack = victim.Backpack; + + if ( pack != null ) + { + Container killerPack = ( killer == null ? null : killer.Backpack ); + Item[] sigils = pack.FindItemsByType( typeof( Sigil ) ); + + for ( int i = 0; i < sigils.Length; ++i ) + { + Sigil sigil = (Sigil)sigils[i]; + + if ( killerState != null && killerPack != null ) + { + if ( killer.GetDistanceToSqrt( victim ) > 64 ) { + sigil.ReturnHome(); + killer.SendLocalizedMessage( 1042230 ); // The sigil has gone back to its home location. + } + else if ( Sigil.ExistsOn( killer ) ) + { + sigil.ReturnHome(); + killer.SendLocalizedMessage( 1010258 ); // The sigil has gone back to its home location because you already have a sigil. + } + else if ( !killerPack.TryDropItem( killer, sigil, false ) ) + { + sigil.ReturnHome(); + killer.SendLocalizedMessage( 1010259 ); // The sigil has gone home because your backpack is full. + } + } + else + { + sigil.ReturnHome(); + } + } + } + + if ( killerState == null ) + return; + + if ( victim is BaseCreature ) + { + BaseCreature bc = (BaseCreature)victim; + Faction victimFaction = bc.FactionAllegiance; + + if ( bc.Map == Faction.Facet && victimFaction != null && killerState.Faction != victimFaction ) + { + int silver = killerState.Faction.AwardSilver( killer, bc.FactionSilverWorth ); + + if ( silver > 0 ) + killer.SendLocalizedMessage( 1042748, silver.ToString( "N0" ) ); // Thou hast earned ~1_AMOUNT~ silver for vanquishing the vile creature. + } + + #region Ethics + if ( bc.Map == Faction.Facet && bc.GetEthicAllegiance( killer ) == BaseCreature.Allegiance.Enemy ) + { + Ethics.Player killerEPL = Ethics.Player.Find( killer ); + + if ( killerEPL != null && ( 100 - killerEPL.Power ) > Utility.Random( 100 ) ) + { + ++killerEPL.Power; + ++killerEPL.History; + } + } + #endregion + + return; + } + + PlayerState victimState = PlayerState.Find( victim ); + + if ( victimState == null ) + return; + + #region Dueling + if (victim.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) + return; + #endregion + + if ( killer == victim || killerState.Faction != victimState.Faction ) + ApplySkillLoss( victim ); + + if ( killerState.Faction != victimState.Faction ) + { + if ( victimState.KillPoints <= -6 ) + { + killer.SendLocalizedMessage( 501693 ); // This victim is not worth enough to get kill points from. + + #region Ethics + Ethics.Player killerEPL = Ethics.Player.Find( killer ); + Ethics.Player victimEPL = Ethics.Player.Find( victim ); + + if ( killerEPL != null && victimEPL != null && victimEPL.Power > 0 && victimState.CanGiveSilverTo( killer ) ) + { + int powerTransfer = Math.Max( 1, victimEPL.Power / 5 ); + + if ( powerTransfer > ( 100 - killerEPL.Power ) ) + powerTransfer = 100 - killerEPL.Power; + + if ( powerTransfer > 0 ) + { + victimEPL.Power -= ( powerTransfer + 1 ) / 2; + killerEPL.Power += powerTransfer; + + killerEPL.History += powerTransfer; + + victimState.OnGivenSilverTo( killer ); + } + } + #endregion + } + else + { + int award = Math.Max( victimState.KillPoints / 10, 1 ); + + if ( award > 40 ) + award = 40; + + if ( victimState.CanGiveSilverTo( killer ) ) + { + if ( victimState.KillPoints > 0 ) + { + victimState.IsActive = true; + + if ( 1 > Utility.Random( 3 ) ) + killerState.IsActive = true; + + int silver = 0; + + silver = killerState.Faction.AwardSilver( killer, award * 40 ); + + if ( silver > 0 ) + killer.SendLocalizedMessage( 1042736, String.Format( "{0:N0} silver\t{1}", silver, victim.Name ) ); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~! + } + + victimState.KillPoints -= award; + killerState.KillPoints += award; + + int offset = ( award != 1 ? 0 : 2 ); // for pluralization + + string args = String.Format( "{0}\t{1}\t{2}", award, victim.Name, killer.Name ); + + killer.SendLocalizedMessage( 1042737 + offset, args ); // Thou hast been honored with ~1_KILL_POINTS~ kill point(s) for vanquishing ~2_DEAD_PLAYER~! + victim.SendLocalizedMessage( 1042738 + offset, args ); // Thou has lost ~1_KILL_POINTS~ kill point(s) to ~3_ATTACKER_NAME~ for being vanquished! + + #region Ethics + Ethics.Player killerEPL = Ethics.Player.Find( killer ); + Ethics.Player victimEPL = Ethics.Player.Find( victim ); + + if ( killerEPL != null && victimEPL != null && victimEPL.Power > 0 ) + { + int powerTransfer = Math.Max( 1, victimEPL.Power / 5 ); + + if ( powerTransfer > ( 100 - killerEPL.Power ) ) + powerTransfer = 100 - killerEPL.Power; + + if ( powerTransfer > 0 ) + { + victimEPL.Power -= ( powerTransfer + 1 ) / 2; + killerEPL.Power += powerTransfer; + + killerEPL.History += powerTransfer; + } + } + #endregion + + victimState.OnGivenSilverTo( killer ); + } + else + { + killer.SendLocalizedMessage( 1042231 ); // You have recently defeated this enemy and thus their death brings you no honor. + } + } + } + } + + private static void EventSink_Logout( LogoutEventArgs e ) + { + Mobile mob = e.Mobile; + + Container pack = mob.Backpack; + + if ( pack == null ) + return; + + Item[] sigils = pack.FindItemsByType( typeof( Sigil ) ); + + for ( int i = 0; i < sigils.Length; ++i ) + ((Sigil)sigils[i]).ReturnHome(); + } + + private static void EventSink_Login( LoginEventArgs e ) + { + Mobile mob = e.Mobile; + + CheckLeaveTimer( mob ); + } + + public static readonly Map Facet = Map.Felucca; + + public static void WriteReference( GenericWriter writer, Faction fact ) + { + int idx = Factions.IndexOf( fact ); + + writer.WriteEncodedInt( (int) (idx + 1) ); + } + + public static List Factions{ get{ return Reflector.Factions; } } + + public static Faction ReadReference( GenericReader reader ) + { + int idx = reader.ReadEncodedInt() - 1; + + if ( idx >= 0 && idx < Factions.Count ) + return Factions[idx]; + + return null; + } + + public static Faction Find( Mobile mob ) + { + return Find( mob, false, false ); + } + + public static Faction Find( Mobile mob, bool inherit ) + { + return Find( mob, inherit, false ); + } + + public static Faction Find( Mobile mob, bool inherit, bool creatureAllegiances ) + { + PlayerState pl = PlayerState.Find( mob ); + + if ( pl != null ) + return pl.Faction; + + if ( inherit && mob is BaseCreature ) + { + BaseCreature bc = (BaseCreature)mob; + + if ( bc.Controlled ) + return Find( bc.ControlMaster, false ); + else if ( bc.Summoned ) + return Find( bc.SummonMaster, false ); + else if ( creatureAllegiances && mob is BaseFactionGuard ) + return ((BaseFactionGuard)mob).Faction; + else if ( creatureAllegiances ) + return bc.FactionAllegiance; + } + + return null; + } + + public static Faction Parse( string name ) + { + List factions = Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction faction = factions[i]; + + if ( Insensitive.Equals( faction.Definition.FriendlyName, name ) ) + return faction; + } + + return null; + } + } + + public enum FactionKickType + { + Kick, + Ban, + Unban + } + + public class FactionKickCommand : BaseCommand + { + private FactionKickType m_KickType; + + public FactionKickCommand( FactionKickType kickType ) + { + m_KickType = kickType; + + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllMobiles; + ObjectTypes = ObjectTypes.Mobiles; + + switch ( m_KickType ) + { + case FactionKickType.Kick: + { + Commands = new string[]{ "FactionKick" }; + Usage = "FactionKick"; + Description = "Kicks the targeted player out of his current faction. This does not prevent them from rejoining."; + break; + } + case FactionKickType.Ban: + { + Commands = new string[]{ "FactionBan" }; + Usage = "FactionBan"; + Description = "Bans the account of a targeted player from joining factions. All players on the account are removed from their current faction, if any."; + break; + } + case FactionKickType.Unban: + { + Commands = new string[]{ "FactionUnban" }; + Usage = "FactionUnban"; + Description = "Unbans the account of a targeted player from joining factions."; + break; + } + } + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile mob = (Mobile)obj; + + switch ( m_KickType ) + { + case FactionKickType.Kick: + { + PlayerState pl = PlayerState.Find( mob ); + + if ( pl != null ) + { + pl.Faction.RemoveMember( mob ); + mob.SendMessage( "You have been kicked from your faction." ); + AddResponse( "They have been kicked from their faction." ); + } + else + { + LogFailure( "They are not in a faction." ); + } + + break; + } + case FactionKickType.Ban: + { + Account acct = mob.Account as Account; + + if ( acct != null ) + { + if ( acct.GetTag( "FactionBanned" ) == null ) + { + acct.SetTag( "FactionBanned", "true" ); + AddResponse( "The account has been banned from joining factions." ); + } + else + { + AddResponse( "The account is already banned from joining factions." ); + } + + for ( int i = 0; i < acct.Length; ++i ) + { + mob = acct[i]; + + if ( mob != null ) + { + PlayerState pl = PlayerState.Find( mob ); + + if ( pl != null ) + { + pl.Faction.RemoveMember( mob ); + mob.SendMessage( "You have been kicked from your faction." ); + AddResponse( "They have been kicked from their faction." ); + } + } + } + } + else + { + LogFailure( "They have no assigned account." ); + } + + break; + } + case FactionKickType.Unban: + { + Account acct = mob.Account as Account; + + if ( acct != null ) + { + if ( acct.GetTag( "FactionBanned" ) == null ) + { + AddResponse( "The account is not already banned from joining factions." ); + } + else + { + acct.RemoveTag( "FactionBanned" ); + AddResponse( "The account may now freely join factions." ); + } + } + else + { + LogFailure( "They have no assigned account." ); + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/FactionItem.cs b/Scripts/Engines/Factions/Core/FactionItem.cs new file mode 100644 index 0000000..bcd73af --- /dev/null +++ b/Scripts/Engines/Factions/Core/FactionItem.cs @@ -0,0 +1,146 @@ +using System; + +namespace Server.Factions +{ + public interface IFactionItem + { + FactionItem FactionItemState{ get; set; } + } + + public class FactionItem + { + public static readonly TimeSpan ExpirationPeriod = TimeSpan.FromDays( 21.0 ); + + private Item m_Item; + private Faction m_Faction; + private DateTime m_Expiration; + + public Item Item{ get{ return m_Item; } } + public Faction Faction{ get{ return m_Faction; } } + public DateTime Expiration{ get{ return m_Expiration; } } + + public bool HasExpired + { + get + { + if ( m_Item == null || m_Item.Deleted ) + return true; + + return ( m_Expiration != DateTime.MinValue && DateTime.Now >= m_Expiration ); + } + } + + public void StartExpiration() + { + m_Expiration = DateTime.Now + ExpirationPeriod; + } + + public void CheckAttach() + { + if ( !HasExpired ) + Attach(); + else + Detach(); + } + + public void Attach() + { + if ( m_Item is IFactionItem ) + ((IFactionItem)m_Item).FactionItemState = this; + + if ( m_Faction != null ) + m_Faction.State.FactionItems.Add( this ); + } + + public void Detach() + { + if ( m_Item is IFactionItem ) + ((IFactionItem)m_Item).FactionItemState = null; + + if ( m_Faction != null && m_Faction.State.FactionItems.Contains( this ) ) + m_Faction.State.FactionItems.Remove( this ); + } + + public FactionItem( Item item, Faction faction ) + { + m_Item = item; + m_Faction = faction; + } + + public FactionItem( GenericReader reader, Faction faction ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Item = reader.ReadItem(); + m_Expiration = reader.ReadDateTime(); + break; + } + } + + m_Faction = faction; + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); + + writer.Write( (Item) m_Item ); + writer.Write( (DateTime) m_Expiration ); + } + + public static int GetMaxWearables( Mobile mob ) + { + PlayerState pl = PlayerState.Find( mob ); + + if ( pl == null ) + return 0; + + if ( pl.Faction.IsCommander( mob ) ) + return 9; + + return pl.Rank.MaxWearables; + } + + public static FactionItem Find( Item item ) + { + if ( item is IFactionItem ) + { + FactionItem state = ((IFactionItem)item).FactionItemState; + + if ( state != null && state.HasExpired ) + { + state.Detach(); + state = null; + } + + return state; + } + + return null; + } + + public static Item Imbue( Item item, Faction faction, bool expire, int hue ) + { + if ( !(item is IFactionItem) ) + return item; + + FactionItem state = Find( item ); + + if ( state == null ) + { + state = new FactionItem( item, faction ); + state.Attach(); + } + + if ( expire ) + state.StartExpiration(); + + item.Hue = hue; + return item; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/FactionState.cs b/Scripts/Engines/Factions/Core/FactionState.cs new file mode 100644 index 0000000..df8ce2c --- /dev/null +++ b/Scripts/Engines/Factions/Core/FactionState.cs @@ -0,0 +1,312 @@ +using System; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class FactionState + { + private Faction m_Faction; + private Mobile m_Commander; + private int m_Tithe; + private int m_Silver; + private List m_Members; + private Election m_Election; + private List m_FactionItems; + private List m_FactionTraps; + private DateTime m_LastAtrophy; + + private const int BroadcastsPerPeriod = 2; + private static readonly TimeSpan BroadcastPeriod = TimeSpan.FromHours( 1.0 ); + + private DateTime[] m_LastBroadcasts = new DateTime[BroadcastsPerPeriod]; + + public DateTime LastAtrophy{ get{ return m_LastAtrophy; } set{ m_LastAtrophy = value; } } + + public bool FactionMessageReady + { + get + { + for ( int i = 0; i < m_LastBroadcasts.Length; ++i ) + { + if ( DateTime.Now >= (m_LastBroadcasts[i] + BroadcastPeriod) ) + return true; + } + + return false; + } + } + + public bool IsAtrophyReady{ get{ return DateTime.Now >= (m_LastAtrophy + TimeSpan.FromHours( 47.0 )); } } + + public int CheckAtrophy() + { + if ( DateTime.Now < (m_LastAtrophy + TimeSpan.FromHours( 47.0 )) ) + return 0; + + int distrib = 0; + m_LastAtrophy = DateTime.Now; + + List members = new List( m_Members ); + + for ( int i = 0; i < members.Count; ++i ) + { + PlayerState ps = members[i]; + + if ( ps.IsActive ) + { + ps.IsActive = false; + continue; + } + else if ( ps.KillPoints > 0 ) + { + int atrophy = ( ps.KillPoints + 9 ) / 10; + ps.KillPoints -= atrophy; + distrib += atrophy; + } + } + + return distrib; + } + + public void RegisterBroadcast() + { + for ( int i = 0; i < m_LastBroadcasts.Length; ++i ) + { + if ( DateTime.Now >= (m_LastBroadcasts[i] + BroadcastPeriod) ) + { + m_LastBroadcasts[i] = DateTime.Now; + break; + } + } + } + + public List FactionItems + { + get{ return m_FactionItems; } + set{ m_FactionItems = value; } + } + + public List Traps + { + get{ return m_FactionTraps; } + set{ m_FactionTraps = value; } + } + + public Election Election + { + get{ return m_Election; } + set{ m_Election = value; } + } + + public Mobile Commander + { + get{ return m_Commander; } + set + { + if ( m_Commander != null ) + m_Commander.InvalidateProperties(); + + m_Commander = value; + + if ( m_Commander != null ) + { + m_Commander.SendLocalizedMessage( 1042227 ); // You have been elected Commander of your faction + + m_Commander.InvalidateProperties(); + + PlayerState pl = PlayerState.Find( m_Commander ); + + if ( pl != null && pl.Finance != null ) + pl.Finance.Finance = null; + + if ( pl != null && pl.Sheriff != null ) + pl.Sheriff.Sheriff = null; + } + } + } + + public int Tithe + { + get{ return m_Tithe; } + set{ m_Tithe = value; } + } + + public int Silver + { + get{ return m_Silver; } + set{ m_Silver = value; } + } + + public List Members + { + get{ return m_Members; } + set{ m_Members = value; } + } + + public FactionState( Faction faction ) + { + m_Faction = faction; + m_Tithe = 50; + m_Members = new List(); + m_Election = new Election( faction ); + m_FactionItems = new List(); + m_FactionTraps = new List(); + } + + public FactionState( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 5: + { + m_LastAtrophy = reader.ReadDateTime(); + goto case 4; + } + case 4: + { + int count = reader.ReadEncodedInt(); + + for ( int i = 0; i < count; ++i ) + { + DateTime time = reader.ReadDateTime(); + + if ( i < m_LastBroadcasts.Length ) + m_LastBroadcasts[i] = time; + } + + goto case 3; + } + case 3: + case 2: + case 1: + { + m_Election = new Election( reader ); + + goto case 0; + } + case 0: + { + m_Faction = Faction.ReadReference( reader ); + + m_Commander = reader.ReadMobile(); + + if ( version < 5 ) + m_LastAtrophy = DateTime.Now; + + if ( version < 4 ) + { + DateTime time = reader.ReadDateTime(); + + if ( m_LastBroadcasts.Length > 0 ) + m_LastBroadcasts[0] = time; + } + + m_Tithe = reader.ReadEncodedInt(); + m_Silver = reader.ReadEncodedInt(); + + int memberCount = reader.ReadEncodedInt(); + + m_Members = new List(); + + for ( int i = 0; i < memberCount; ++i ) + { + PlayerState pl = new PlayerState( reader, m_Faction, m_Members ); + + if ( pl.Mobile != null ) + m_Members.Add( pl ); + } + + m_Faction.State = this; + + m_Faction.ZeroRankOffset = m_Members.Count; + m_Members.Sort(); + + for ( int i = m_Members.Count - 1; i >= 0; i-- ) { + PlayerState player = m_Members[i]; + + if ( player.KillPoints <= 0 ) + m_Faction.ZeroRankOffset = i; + else + player.RankIndex = i; + } + + m_FactionItems = new List(); + + if ( version >= 2 ) + { + int factionItemCount = reader.ReadEncodedInt(); + + for ( int i = 0; i < factionItemCount; ++i ) + { + FactionItem factionItem = new FactionItem( reader, m_Faction ); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( factionItem.CheckAttach ) ); // sandbox attachment + } + } + + m_FactionTraps = new List(); + + if ( version >= 3 ) + { + int factionTrapCount = reader.ReadEncodedInt(); + + for ( int i = 0; i < factionTrapCount; ++i ) + { + BaseFactionTrap trap = reader.ReadItem() as BaseFactionTrap; + + if ( trap != null && !trap.CheckDecay() ) + m_FactionTraps.Add( trap ); + } + } + + break; + } + } + + if ( version < 1 ) + m_Election = new Election( m_Faction ); + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 5 ); // version + + writer.Write( m_LastAtrophy ); + + writer.WriteEncodedInt( (int) m_LastBroadcasts.Length ); + + for ( int i = 0; i < m_LastBroadcasts.Length; ++i ) + writer.Write( (DateTime) m_LastBroadcasts[i] ); + + m_Election.Serialize( writer ); + + Faction.WriteReference( writer, m_Faction ); + + writer.Write( (Mobile) m_Commander ); + + writer.WriteEncodedInt( (int) m_Tithe ); + writer.WriteEncodedInt( (int) m_Silver ); + + writer.WriteEncodedInt( (int) m_Members.Count ); + + for ( int i = 0; i < m_Members.Count; ++i ) + { + PlayerState pl = (PlayerState) m_Members[i]; + + pl.Serialize( writer ); + } + + writer.WriteEncodedInt( (int) m_FactionItems.Count ); + + for ( int i = 0; i < m_FactionItems.Count; ++i ) + m_FactionItems[i].Serialize( writer ); + + writer.WriteEncodedInt( (int) m_FactionTraps.Count ); + + for ( int i = 0; i < m_FactionTraps.Count; ++i ) + writer.Write( (Item) m_FactionTraps[i] ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/Generator.cs b/Scripts/Engines/Factions/Core/Generator.cs new file mode 100644 index 0000000..4ee0422 --- /dev/null +++ b/Scripts/Engines/Factions/Core/Generator.cs @@ -0,0 +1,80 @@ +using System; +using Server.Commands; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class Generator + { + public static void Initialize() + { + CommandSystem.Register( "GenerateFactions", AccessLevel.Administrator, new CommandEventHandler( GenerateFactions_OnCommand ) ); + } + + public static void GenerateFactions_OnCommand( CommandEventArgs e ) + { + new FactionPersistance(); + + List factions = Faction.Factions; + + foreach ( Faction faction in factions ) + Generate( faction ); + + List towns = Town.Towns; + + foreach ( Town town in towns ) + Generate( town ); + } + + public static void Generate( Town town ) + { + Map facet = Faction.Facet; + + TownDefinition def = town.Definition; + + if ( !CheckExistance( def.Monolith, facet, typeof( TownMonolith ) ) ) + { + TownMonolith mono = new TownMonolith( town ); + mono.MoveToWorld( def.Monolith, facet ); + mono.Sigil = new Sigil( town ); + } + + if ( !CheckExistance( def.TownStone, facet, typeof( TownStone ) ) ) + new TownStone( town ).MoveToWorld( def.TownStone, facet ); + } + + public static void Generate( Faction faction ) + { + Map facet = Faction.Facet; + + List towns = Town.Towns; + + StrongholdDefinition stronghold = faction.Definition.Stronghold; + + if ( !CheckExistance( stronghold.JoinStone, facet, typeof( JoinStone ) ) ) + new JoinStone( faction ).MoveToWorld( stronghold.JoinStone, facet ); + + if ( !CheckExistance( stronghold.FactionStone, facet, typeof( FactionStone ) ) ) + new FactionStone( faction ).MoveToWorld( stronghold.FactionStone, facet ); + + for ( int i = 0; i < stronghold.Monoliths.Length; ++i ) + { + Point3D monolith = stronghold.Monoliths[i]; + + if ( !CheckExistance( monolith, facet, typeof( StrongholdMonolith ) ) ) + new StrongholdMonolith( towns[i], faction ).MoveToWorld( monolith, facet ); + } + } + + private static bool CheckExistance( Point3D loc, Map facet, Type type ) + { + foreach ( Item item in facet.GetItemsInRange( loc, 0 ) ) + { + if ( type.IsAssignableFrom( item.GetType() ) ) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/GuardList.cs b/Scripts/Engines/Factions/Core/GuardList.cs new file mode 100644 index 0000000..efc3d8f --- /dev/null +++ b/Scripts/Engines/Factions/Core/GuardList.cs @@ -0,0 +1,27 @@ +using System; +using Server; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class GuardList + { + private GuardDefinition m_Definition; + private List m_Guards; + + public GuardDefinition Definition{ get{ return m_Definition; } } + public List Guards{ get{ return m_Guards; } } + + public BaseFactionGuard Construct() + { + try{ return Activator.CreateInstance( m_Definition.Type ) as BaseFactionGuard; } + catch{ return null; } + } + + public GuardList( GuardDefinition definition ) + { + m_Definition = definition; + m_Guards = new List(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/Keywords.cs b/Scripts/Engines/Factions/Core/Keywords.cs new file mode 100644 index 0000000..4a6095f --- /dev/null +++ b/Scripts/Engines/Factions/Core/Keywords.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Factions; +using Server.Mobiles; + +namespace Server.Factions +{ + public class Keywords + { + public static void Initialize() + { + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + } + + private static void ShowScore_Sandbox( object state ) + { + PlayerState pl = (PlayerState)state; + + if ( pl != null ) + pl.Mobile.PublicOverheadMessage( MessageType.Regular, pl.Mobile.SpeechHue, true, pl.KillPoints.ToString( "N0" ) ); // NOTE: Added 'N0' + } + + private static void EventSink_Speech( SpeechEventArgs e ) + { + Mobile from = e.Mobile; + int[] keywords = e.Keywords; + + for ( int i = 0; i < keywords.Length; ++i ) + { + switch ( keywords[i] ) + { + case 0x00E4: // *i wish to access the city treasury* + { + Town town = Town.FromRegion( from.Region ); + + if ( town == null || !town.IsFinance( from ) || !from.Alive ) + break; + + if ( FactionGump.Exists( from ) ) + from.SendLocalizedMessage( 1042160 ); // You already have a faction menu open. + else if ( town.Owner != null && from is PlayerMobile ) + from.SendGump( new FinanceGump( (PlayerMobile)from, town.Owner, town ) ); + + break; + } + case 0x0ED: // *i am sheriff* + { + Town town = Town.FromRegion( from.Region ); + + if ( town == null || !town.IsSheriff( from ) || !from.Alive ) + break; + + if ( FactionGump.Exists( from ) ) + from.SendLocalizedMessage( 1042160 ); // You already have a faction menu open. + else if ( town.Owner != null ) + from.SendGump( new SheriffGump( (PlayerMobile)from, town.Owner, town ) ); + + break; + } + case 0x00EF: // *you are fired* + { + Town town = Town.FromRegion( from.Region ); + + if ( town == null ) + break; + + if ( town.IsFinance( from ) || town.IsSheriff( from ) ) + town.BeginOrderFiring( from ); + + break; + } + case 0x00E5: // *i wish to resign as finance minister* + { + PlayerState pl = PlayerState.Find( from ); + + if ( pl != null && pl.Finance != null ) + { + pl.Finance.Finance = null; + from.SendLocalizedMessage( 1005081 ); // You have been fired as Finance Minister + } + + break; + } + case 0x00EE: // *i wish to resign as sheriff* + { + PlayerState pl = PlayerState.Find( from ); + + if ( pl != null && pl.Sheriff != null ) + { + pl.Sheriff.Sheriff = null; + from.SendLocalizedMessage( 1010270 ); // You have been fired as Sheriff + } + + break; + } + case 0x00E9: // *what is my faction term status* + { + PlayerState pl = PlayerState.Find( from ); + + if ( pl != null && pl.IsLeaving ) + { + if ( Faction.CheckLeaveTimer( from ) ) + break; + + TimeSpan remaining = ( pl.Leaving + Faction.LeavePeriod ) - DateTime.Now; + + if( remaining.TotalDays >= 1 ) + from.SendLocalizedMessage( 1042743, remaining.TotalDays.ToString( "N0" ) ) ;// Your term of service will come to an end in ~1_DAYS~ days. + else if( remaining.TotalHours >= 1 ) + from.SendLocalizedMessage( 1042741, remaining.TotalHours.ToString( "N0" ) ); // Your term of service will come to an end in ~1_HOURS~ hours. + else + from.SendLocalizedMessage( 1042742 ); // Your term of service will come to an end in less than one hour. + } + else if ( pl != null ) + { + from.SendLocalizedMessage( 1042233 ); // You are not in the process of quitting the faction. + } + + break; + } + case 0x00EA: // *message faction* + { + Faction faction = Faction.Find( from ); + + if ( faction == null || !faction.IsCommander( from ) ) + break; + + if ( from.AccessLevel == AccessLevel.Player && !faction.FactionMessageReady ) + from.SendLocalizedMessage( 1010264 ); // The required time has not yet passed since the last message was sent + else + faction.BeginBroadcast( from ); + + break; + } + case 0x00EC: // *showscore* + { + PlayerState pl = PlayerState.Find( from ); + + if ( pl != null ) + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( ShowScore_Sandbox ), pl ); + + break; + } + case 0x0178: // i honor your leadership + { + Faction faction = Faction.Find( from ); + + if ( faction != null ) + faction.BeginHonorLeadership( from ); + + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/MerchantTitles.cs b/Scripts/Engines/Factions/Core/MerchantTitles.cs new file mode 100644 index 0000000..7ee4162 --- /dev/null +++ b/Scripts/Engines/Factions/Core/MerchantTitles.cs @@ -0,0 +1,87 @@ +using System; + +namespace Server.Factions +{ + public enum MerchantTitle + { + None, + Scribe, + Carpenter, + Blacksmith, + Bowyer, + Tialor + } + + public class MerchantTitleInfo + { + private SkillName m_Skill; + private double m_Requirement; + private TextDefinition m_Title; + private TextDefinition m_Label; + private TextDefinition m_Assigned; + + public SkillName Skill{ get{ return m_Skill; } } + public double Requirement{ get{ return m_Requirement; } } + public TextDefinition Title{ get{ return m_Title; } } + public TextDefinition Label{ get{ return m_Label; } } + public TextDefinition Assigned{ get{ return m_Assigned; } } + + public MerchantTitleInfo( SkillName skill, double requirement, TextDefinition title, TextDefinition label, TextDefinition assigned ) + { + m_Skill = skill; + m_Requirement = requirement; + m_Title = title; + m_Label = label; + m_Assigned = assigned; + } + } + + public class MerchantTitles + { + private static MerchantTitleInfo[] m_Info = new MerchantTitleInfo[] + { + new MerchantTitleInfo( SkillName.Inscribe, 90.0, new TextDefinition( 1060773, "Scribe" ), new TextDefinition( 1011468, "SCRIBE" ), new TextDefinition( 1010121, "You now have the faction title of scribe" ) ), + new MerchantTitleInfo( SkillName.Carpentry, 90.0, new TextDefinition( 1060774, "Carpenter" ), new TextDefinition( 1011469, "CARPENTER" ), new TextDefinition( 1010122, "You now have the faction title of carpenter" ) ), + new MerchantTitleInfo( SkillName.Tinkering, 90.0, new TextDefinition( 1022984, "Tinker" ), new TextDefinition( 1011470, "TINKER" ), new TextDefinition( 1010123, "You now have the faction title of tinker" ) ), + new MerchantTitleInfo( SkillName.Blacksmith, 90.0, new TextDefinition( 1023016, "Blacksmith" ), new TextDefinition( 1011471, "BLACKSMITH" ), new TextDefinition( 1010124, "You now have the faction title of blacksmith" ) ), + new MerchantTitleInfo( SkillName.Fletching, 90.0, new TextDefinition( 1023022, "Bowyer" ), new TextDefinition( 1011472, "BOWYER" ), new TextDefinition( 1010125, "You now have the faction title of Bowyer" ) ), + new MerchantTitleInfo( SkillName.Tailoring, 90.0, new TextDefinition( 1022982, "Tailor" ), new TextDefinition( 1018300, "TAILOR" ), new TextDefinition( 1042162, "You now have the faction title of Tailor" ) ), + }; + + public static MerchantTitleInfo[] Info{ get{ return m_Info; } } + + public static MerchantTitleInfo GetInfo( MerchantTitle title ) + { + int idx = (int)title - 1; + + if ( idx >= 0 && idx < m_Info.Length ) + return m_Info[idx]; + + return null; + } + + public static bool HasMerchantQualifications( Mobile mob ) + { + for ( int i = 0; i < m_Info.Length; ++i ) + { + if ( IsQualified( mob, m_Info[i] ) ) + return true; + } + + return false; + } + + public static bool IsQualified( Mobile mob, MerchantTitle title ) + { + return IsQualified( mob, GetInfo( title ) ); + } + + public static bool IsQualified( Mobile mob, MerchantTitleInfo info ) + { + if ( mob == null || info == null ) + return false; + + return ( mob.Skills[info.Skill].Value >= info.Requirement ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/Persistance.cs b/Scripts/Engines/Factions/Core/Persistance.cs new file mode 100644 index 0000000..a63fb89 --- /dev/null +++ b/Scripts/Engines/Factions/Core/Persistance.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class FactionPersistance : Item + { + private static FactionPersistance m_Instance; + + public static FactionPersistance Instance{ get{ return m_Instance; } } + + public override string DefaultName + { + get { return "Faction Persistance - Internal"; } + } + + public FactionPersistance() : base( 1 ) + { + Movable = false; + + if ( m_Instance == null || m_Instance.Deleted ) + m_Instance = this; + else + base.Delete(); + } + + private enum PersistedType + { + Terminator, + Faction, + Town + } + + public FactionPersistance( Serial serial ) : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + writer.WriteEncodedInt( (int) PersistedType.Faction ); + factions[i].State.Serialize( writer ); + } + + List towns = Town.Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + writer.WriteEncodedInt( (int) PersistedType.Town ); + towns[i].State.Serialize( writer ); + } + + writer.WriteEncodedInt( (int) PersistedType.Terminator ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + PersistedType type; + + while ( (type = (PersistedType)reader.ReadEncodedInt()) != PersistedType.Terminator ) + { + switch ( type ) + { + case PersistedType.Faction: new FactionState( reader ); break; + case PersistedType.Town: new TownState( reader ); break; + } + } + + break; + } + } + } + + public override void Delete() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/PlayerState.cs b/Scripts/Engines/Factions/Core/PlayerState.cs new file mode 100644 index 0000000..c4eb527 --- /dev/null +++ b/Scripts/Engines/Factions/Core/PlayerState.cs @@ -0,0 +1,255 @@ +using System; +using Server; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class PlayerState : IComparable + { + private Mobile m_Mobile; + private Faction m_Faction; + private List m_Owner; + private int m_KillPoints; + private DateTime m_Leaving; + private MerchantTitle m_MerchantTitle; + private RankDefinition m_Rank; + private List m_SilverGiven; + private bool m_IsActive; + + private Town m_Sheriff; + private Town m_Finance; + + private DateTime m_LastHonorTime; + + public Mobile Mobile{ get{ return m_Mobile; } } + public Faction Faction{ get{ return m_Faction; } } + public List Owner { get { return m_Owner; } } + public MerchantTitle MerchantTitle{ get{ return m_MerchantTitle; } set{ m_MerchantTitle = value; Invalidate(); } } + public Town Sheriff{ get{ return m_Sheriff; } set{ m_Sheriff = value; Invalidate(); } } + public Town Finance{ get{ return m_Finance; } set{ m_Finance = value; Invalidate(); } } + public List SilverGiven { get { return m_SilverGiven; } } + + public int KillPoints { + get { return m_KillPoints; } + set { + if ( m_KillPoints != value ) { + if ( value > m_KillPoints ) { + if ( m_KillPoints <= 0 ) { + if ( value <= 0 ) { + m_KillPoints = value; + Invalidate(); + return; + } + + m_Owner.Remove( this ); + m_Owner.Insert( m_Faction.ZeroRankOffset, this ); + + m_RankIndex = m_Faction.ZeroRankOffset; + m_Faction.ZeroRankOffset++; + } + while ( ( m_RankIndex - 1 ) >= 0 ) { + PlayerState p = m_Owner[m_RankIndex-1] as PlayerState; + if ( value > p.KillPoints ) { + m_Owner[m_RankIndex] = p; + m_Owner[m_RankIndex-1] = this; + RankIndex--; + p.RankIndex++; + } + else + break; + } + } + else { + if ( value <= 0 ) { + if ( m_KillPoints <= 0 ) { + m_KillPoints = value; + Invalidate(); + return; + } + + while ( ( m_RankIndex + 1 ) < m_Faction.ZeroRankOffset ) { + PlayerState p = m_Owner[m_RankIndex+1] as PlayerState; + m_Owner[m_RankIndex+1] = this; + m_Owner[m_RankIndex] = p; + RankIndex++; + p.RankIndex--; + } + + m_RankIndex = -1; + m_Faction.ZeroRankOffset--; + } + else { + while ( ( m_RankIndex + 1 ) < m_Faction.ZeroRankOffset ) { + PlayerState p = m_Owner[m_RankIndex+1] as PlayerState; + if ( value < p.KillPoints ) { + m_Owner[m_RankIndex+1] = this; + m_Owner[m_RankIndex] = p; + RankIndex++; + p.RankIndex--; + } + else + break; + } + } + } + + m_KillPoints = value; + Invalidate(); + } + } + } + + private bool m_InvalidateRank = true; + private int m_RankIndex = -1; + + public int RankIndex { get { return m_RankIndex; } set { if ( m_RankIndex != value ) { m_RankIndex = value; m_InvalidateRank = true; } } } + + public RankDefinition Rank { + get { + if ( m_InvalidateRank ) { + RankDefinition[] ranks = m_Faction.Definition.Ranks; + int percent; + + if ( m_Owner.Count == 1 ) + percent = 1000; + else if ( m_RankIndex == -1 ) + percent = 0; + else + percent = ( ( m_Faction.ZeroRankOffset - m_RankIndex ) * 1000 ) / m_Faction.ZeroRankOffset; + + for ( int i = 0; i < ranks.Length; i++ ) { + RankDefinition check = ranks[i]; + + if ( percent >= check.Required ) { + m_Rank = check; + m_InvalidateRank = false; + break; + } + } + + Invalidate(); + } + + return m_Rank; + } + } + + public DateTime LastHonorTime{ get{ return m_LastHonorTime; } set{ m_LastHonorTime = value; } } + public DateTime Leaving{ get{ return m_Leaving; } set{ m_Leaving = value; } } + public bool IsLeaving{ get{ return ( m_Leaving > DateTime.MinValue ); } } + + public bool IsActive{ get{ return m_IsActive; } set{ m_IsActive = value; } } + + public bool CanGiveSilverTo( Mobile mob ) + { + if ( m_SilverGiven == null ) + return true; + + for ( int i = 0; i < m_SilverGiven.Count; ++i ) + { + SilverGivenEntry sge = m_SilverGiven[i]; + + if ( sge.IsExpired ) + m_SilverGiven.RemoveAt( i-- ); + else if ( sge.GivenTo == mob ) + return false; + } + + return true; + } + + public void OnGivenSilverTo( Mobile mob ) + { + if ( m_SilverGiven == null ) + m_SilverGiven = new List(); + + m_SilverGiven.Add( new SilverGivenEntry( mob ) ); + } + + public void Invalidate() + { + if ( m_Mobile is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m_Mobile; + pm.InvalidateProperties(); + pm.InvalidateMyRunUO(); + } + } + + public void Attach() + { + if ( m_Mobile is PlayerMobile ) + ((PlayerMobile)m_Mobile).FactionPlayerState = this; + } + + public PlayerState( Mobile mob, Faction faction, List owner ) + { + m_Mobile = mob; + m_Faction = faction; + m_Owner = owner; + + Attach(); + Invalidate(); + } + + public PlayerState( GenericReader reader, Faction faction, List owner ) + { + m_Faction = faction; + m_Owner = owner; + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_IsActive = reader.ReadBool(); + m_LastHonorTime = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_Mobile = reader.ReadMobile(); + + m_KillPoints = reader.ReadEncodedInt(); + m_MerchantTitle = (MerchantTitle)reader.ReadEncodedInt(); + + m_Leaving = reader.ReadDateTime(); + + break; + } + } + + Attach(); + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 1 ); // version + + writer.Write( m_IsActive ); + writer.Write( m_LastHonorTime ); + + writer.Write( (Mobile) m_Mobile ); + + writer.WriteEncodedInt( (int) m_KillPoints ); + writer.WriteEncodedInt( (int) m_MerchantTitle ); + + writer.Write( (DateTime) m_Leaving ); + } + + public static PlayerState Find( Mobile mob ) + { + if ( mob is PlayerMobile ) + return ((PlayerMobile)mob).FactionPlayerState; + + return null; + } + + public int CompareTo( object obj ) + { + return ((PlayerState)obj).m_KillPoints - m_KillPoints; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/Reflector.cs b/Scripts/Engines/Factions/Core/Reflector.cs new file mode 100644 index 0000000..86a428b --- /dev/null +++ b/Scripts/Engines/Factions/Core/Reflector.cs @@ -0,0 +1,78 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class Reflector + { + private static List m_Towns; + + public static List Towns + { + get + { + if (m_Towns == null) + ProcessTypes(); + + return m_Towns; + } + } + + private static List m_Factions; + + public static List Factions + { + get + { + if (m_Factions == null) + Reflector.ProcessTypes(); + + return m_Factions; + } + } + + private static object Construct(Type type) + { + try { return Activator.CreateInstance(type); } + catch { return null; } + } + + private static void ProcessTypes() + { + m_Factions = new List(); + m_Towns = new List(); + + Assembly[] asms = ScriptCompiler.Assemblies; + + for (int i = 0; i < asms.Length; ++i) + { + Assembly asm = asms[i]; + TypeCache tc = ScriptCompiler.GetTypeCache(asm); + Type[] types = tc.Types; + + for (int j = 0; j < types.Length; ++j) + { + Type type = types[j]; + + if (type.IsSubclassOf(typeof(Faction))) + { + Faction faction = Construct(type) as Faction; + + if (faction != null) + Faction.Factions.Add(faction); + } + else if (type.IsSubclassOf(typeof(Town))) + { + Town town = Construct(type) as Town; + + if (town != null) + Town.Towns.Add(town); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/SilverGivenEntry.cs b/Scripts/Engines/Factions/Core/SilverGivenEntry.cs new file mode 100644 index 0000000..d447309 --- /dev/null +++ b/Scripts/Engines/Factions/Core/SilverGivenEntry.cs @@ -0,0 +1,23 @@ +using System; + +namespace Server.Factions +{ + public class SilverGivenEntry + { + public static readonly TimeSpan ExpirePeriod = TimeSpan.FromHours( 3.0 ); + + private Mobile m_GivenTo; + private DateTime m_TimeOfGift; + + public Mobile GivenTo{ get{ return m_GivenTo; } } + public DateTime TimeOfGift{ get{ return m_TimeOfGift; } } + + public bool IsExpired{ get{ return ( m_TimeOfGift + ExpirePeriod ) < DateTime.Now; } } + + public SilverGivenEntry( Mobile givenTo ) + { + m_GivenTo = givenTo; + m_TimeOfGift = DateTime.Now; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/StrongholdRegion.cs b/Scripts/Engines/Factions/Core/StrongholdRegion.cs new file mode 100644 index 0000000..ea7f6bd --- /dev/null +++ b/Scripts/Engines/Factions/Core/StrongholdRegion.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Factions +{ + public class StrongholdRegion : BaseRegion + { + private Faction m_Faction; + + public Faction Faction + { + get { return m_Faction; } + set { m_Faction = value; } + } + + public StrongholdRegion(Faction faction) + : base(faction.Definition.FriendlyName, Faction.Facet, Region.DefaultPriority, faction.Definition.Stronghold.Area) + { + m_Faction = faction; + + Register(); + } + + public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation) + { + if (!base.OnMoveInto(m, d, newLocation, oldLocation)) + return false; + + if (m.AccessLevel >= AccessLevel.Counselor || Contains(oldLocation)) + return true; + + if (m is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)m; + + if (pm.DuelContext != null) + { + m.SendMessage("You may not enter this area while participating in a duel or a tournament."); + return false; + } + } + + return (Faction.Find(m, true, true) != null); + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/Town.cs b/Scripts/Engines/Factions/Core/Town.cs new file mode 100644 index 0000000..9255854 --- /dev/null +++ b/Scripts/Engines/Factions/Core/Town.cs @@ -0,0 +1,554 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Mobiles; +using Server.Commands; +using System.Collections.Generic; + +namespace Server.Factions +{ + [CustomEnum( new string[]{ "Britain", "Magincia", "Minoc", "Moonglow", "Skara Brae", "Trinsic", "Vesper", "Yew" } )] + public abstract class Town : IComparable + { + private TownDefinition m_Definition; + private TownState m_State; + + public TownDefinition Definition + { + get{ return m_Definition; } + set{ m_Definition = value; } + } + + public TownState State + { + get{ return m_State; } + set{ m_State = value; ConstructGuardLists(); } + } + + public int Silver + { + get{ return m_State.Silver; } + set{ m_State.Silver = value; } + } + + public Faction Owner + { + get{ return m_State.Owner; } + set{ Capture( value ); } + } + + public Mobile Sheriff + { + get{ return m_State.Sheriff; } + set{ m_State.Sheriff = value; } + } + + public Mobile Finance + { + get{ return m_State.Finance; } + set{ m_State.Finance = value; } + } + + public int Tax + { + get{ return m_State.Tax; } + set{ m_State.Tax = value; } + } + + public DateTime LastTaxChange + { + get{ return m_State.LastTaxChange; } + set{ m_State.LastTaxChange = value; } + } + + public static readonly TimeSpan TaxChangePeriod = TimeSpan.FromHours( 12.0 ); + public static readonly TimeSpan IncomePeriod = TimeSpan.FromDays( 1.0 ); + + public bool TaxChangeReady + { + get{ return ( m_State.LastTaxChange + TaxChangePeriod ) < DateTime.Now; } + } + + public static Town FromRegion( Region reg ) + { + if ( reg.Map != Faction.Facet ) + return null; + + List towns = Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + Town town = towns[i]; + + if ( reg.IsPartOf( town.Definition.Region ) ) + return town; + } + + return null; + } + + public int FinanceUpkeep + { + get + { + List vendorLists = VendorLists; + int upkeep = 0; + + for ( int i = 0; i < vendorLists.Count; ++i ) + upkeep += vendorLists[i].Vendors.Count * vendorLists[i].Definition.Upkeep; + + return upkeep; + } + } + + public int SheriffUpkeep + { + get + { + List guardLists = GuardLists; + int upkeep = 0; + + for ( int i = 0; i < guardLists.Count; ++i ) + upkeep += guardLists[i].Guards.Count * guardLists[i].Definition.Upkeep; + + return upkeep; + } + } + + public int DailyIncome + { + get{ return (10000 * (100 + m_State.Tax)) / 100; } + } + + public int NetCashFlow + { + get{ return DailyIncome - FinanceUpkeep - SheriffUpkeep; } + } + + public TownMonolith Monolith + { + get + { + List monoliths = BaseMonolith.Monoliths; + + foreach ( BaseMonolith monolith in monoliths ) + { + if ( monolith is TownMonolith ) + { + TownMonolith townMonolith = (TownMonolith)monolith; + + if ( townMonolith.Town == this ) + return townMonolith; + } + } + + return null; + } + } + + public DateTime LastIncome + { + get{ return m_State.LastIncome; } + set{ m_State.LastIncome = value; } + } + + public void BeginOrderFiring( Mobile from ) + { + bool isFinance = IsFinance( from ); + bool isSheriff = IsSheriff( from ); + string type = null; + + // NOTE: Messages not OSI-accurate, intentional + if ( isFinance && isSheriff ) // GM only + type = "vendor or guard"; + else if ( isFinance ) + type = "vendor"; + else if ( isSheriff ) + type = "guard"; + + from.SendMessage( "Target the {0} you wish to dismiss.", type ); + from.BeginTarget( 12, false, TargetFlags.None, new TargetCallback( EndOrderFiring ) ); + } + + public void EndOrderFiring( Mobile from, object obj ) + { + bool isFinance = IsFinance( from ); + bool isSheriff = IsSheriff( from ); + string type = null; + + if ( isFinance && isSheriff ) // GM only + type = "vendor or guard"; + else if ( isFinance ) + type = "vendor"; + else if ( isSheriff ) + type = "guard"; + + if ( obj is BaseFactionVendor ) + { + BaseFactionVendor vendor = (BaseFactionVendor)obj; + + if ( vendor.Town == this && isFinance ) + vendor.Delete(); + } + else if ( obj is BaseFactionGuard ) + { + BaseFactionGuard guard = (BaseFactionGuard)obj; + + if ( guard.Town == this && isSheriff ) + guard.Delete(); + } + else + { + from.SendMessage( "That is not a {0}!", type ); + } + } + + private Timer m_IncomeTimer; + + public void StartIncomeTimer() + { + if ( m_IncomeTimer != null ) + m_IncomeTimer.Stop(); + + m_IncomeTimer = Timer.DelayCall( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( CheckIncome ) ); + } + + public void StopIncomeTimer() + { + if ( m_IncomeTimer != null ) + m_IncomeTimer.Stop(); + + m_IncomeTimer = null; + } + + public void CheckIncome() + { + if ( (LastIncome + IncomePeriod) > DateTime.Now || Owner == null ) + return; + + ProcessIncome(); + } + + public void ProcessIncome() + { + LastIncome = DateTime.Now; + + int flow = NetCashFlow; + + if ( (Silver + flow) < 0 ) + { + ArrayList toDelete = BuildFinanceList(); + + while ( (Silver + flow) < 0 && toDelete.Count > 0 ) + { + int index = Utility.Random( toDelete.Count ); + Mobile mob = (Mobile)toDelete[index]; + + mob.Delete(); + + toDelete.RemoveAt( index ); + flow = NetCashFlow; + } + } + + Silver += flow; + } + + public ArrayList BuildFinanceList() + { + ArrayList list = new ArrayList(); + + List vendorLists = VendorLists; + + for ( int i = 0; i < vendorLists.Count; ++i ) + list.AddRange( vendorLists[i].Vendors ); + + List guardLists = GuardLists; + + for ( int i = 0; i < guardLists.Count; ++i ) + list.AddRange( guardLists[i].Guards ); + + return list; + } + + private List m_VendorLists; + private List m_GuardLists; + + public List VendorLists + { + get{ return m_VendorLists; } + set{ m_VendorLists = value; } + } + + public List GuardLists + { + get{ return m_GuardLists; } + set{ m_GuardLists = value; } + } + + public void ConstructGuardLists() + { + GuardDefinition[] defs = ( Owner == null ? new GuardDefinition[0] : Owner.Definition.Guards ); + + m_GuardLists = new List(); + + for ( int i = 0; i < defs.Length; ++i ) + m_GuardLists.Add( new GuardList( defs[i] ) ); + } + + public GuardList FindGuardList( Type type ) + { + List guardLists = GuardLists; + + for ( int i = 0; i < guardLists.Count; ++i ) + { + GuardList guardList = guardLists[i]; + + if ( guardList.Definition.Type == type ) + return guardList; + } + + return null; + } + + public void ConstructVendorLists() + { + VendorDefinition[] defs = VendorDefinition.Definitions; + + m_VendorLists = new List(); + + for ( int i = 0; i < defs.Length; ++i ) + m_VendorLists.Add( new VendorList( defs[i] ) ); + } + + public VendorList FindVendorList( Type type ) + { + List vendorLists = VendorLists; + + for ( int i = 0; i < vendorLists.Count; ++i ) + { + VendorList vendorList = vendorLists[i]; + + if ( vendorList.Definition.Type == type ) + return vendorList; + } + + return null; + } + + public bool RegisterGuard( BaseFactionGuard guard ) + { + if ( guard == null ) + return false; + + GuardList guardList = FindGuardList( guard.GetType() ); + + if ( guardList == null ) + return false; + + guardList.Guards.Add( guard ); + return true; + } + + public bool UnregisterGuard( BaseFactionGuard guard ) + { + if ( guard == null ) + return false; + + GuardList guardList = FindGuardList( guard.GetType() ); + + if ( guardList == null ) + return false; + + if ( !guardList.Guards.Contains( guard ) ) + return false; + + guardList.Guards.Remove( guard ); + return true; + } + + public bool RegisterVendor( BaseFactionVendor vendor ) + { + if ( vendor == null ) + return false; + + VendorList vendorList = FindVendorList( vendor.GetType() ); + + if ( vendorList == null ) + return false; + + vendorList.Vendors.Add( vendor ); + return true; + } + + public bool UnregisterVendor( BaseFactionVendor vendor ) + { + if ( vendor == null ) + return false; + + VendorList vendorList = FindVendorList( vendor.GetType() ); + + if ( vendorList == null ) + return false; + + if ( !vendorList.Vendors.Contains( vendor ) ) + return false; + + vendorList.Vendors.Remove( vendor ); + return true; + } + + public static void Initialize() + { + List towns = Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + towns[i].Sheriff = towns[i].Sheriff; + towns[i].Finance = towns[i].Finance; + } + + CommandSystem.Register( "GrantTownSilver", AccessLevel.Administrator, new CommandEventHandler( GrantTownSilver_OnCommand ) ); + } + + public Town() + { + m_State = new TownState( this ); + ConstructVendorLists(); + ConstructGuardLists(); + StartIncomeTimer(); + } + + public bool IsSheriff( Mobile mob ) + { + if ( mob == null || mob.Deleted ) + return false; + + return ( mob.AccessLevel >= AccessLevel.GameMaster || mob == Sheriff ); + } + + public bool IsFinance( Mobile mob ) + { + if ( mob == null || mob.Deleted ) + return false; + + return ( mob.AccessLevel >= AccessLevel.GameMaster || mob == Finance ); + } + + public static List Towns { get { return Reflector.Towns; } } + + public const int SilverCaptureBonus = 10000; + + public void Capture( Faction f ) + { + if ( m_State.Owner == f ) + return; + + if ( m_State.Owner == null ) // going from unowned to owned + { + LastIncome = DateTime.Now; + f.Silver += SilverCaptureBonus; + } + else if ( f == null ) // going from owned to unowned + { + LastIncome = DateTime.MinValue; + } + else // otherwise changing hands, income timer doesn't change + { + f.Silver += SilverCaptureBonus; + } + + m_State.Owner = f; + + Sheriff = null; + Finance = null; + + TownMonolith monolith = this.Monolith; + + if ( monolith != null ) + monolith.Faction = f; + + List vendorLists = VendorLists; + + for ( int i = 0; i < vendorLists.Count; ++i ) + { + VendorList vendorList = vendorLists[i]; + List vendors = vendorList.Vendors; + + for ( int j = vendors.Count - 1; j >= 0; --j ) + vendors[j].Delete(); + } + + List guardLists = GuardLists; + + for ( int i = 0; i < guardLists.Count; ++i ) + { + GuardList guardList = guardLists[i]; + List guards = guardList.Guards; + + for ( int j = guards.Count - 1; j >= 0; --j ) + guards[j].Delete(); + } + + ConstructGuardLists(); + } + + public int CompareTo( object obj ) + { + return m_Definition.Sort - ((Town)obj).m_Definition.Sort; + } + + public override string ToString() + { + return m_Definition.FriendlyName; + } + + public static void WriteReference( GenericWriter writer, Town town ) + { + int idx = Towns.IndexOf( town ); + + writer.WriteEncodedInt( (int) (idx + 1) ); + } + + public static Town ReadReference( GenericReader reader ) + { + int idx = reader.ReadEncodedInt() - 1; + + if ( idx >= 0 && idx < Towns.Count ) + return Towns[idx]; + + return null; + } + + public static Town Parse( string name ) + { + List towns = Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + Town town = towns[i]; + + if ( Insensitive.Equals( town.Definition.FriendlyName, name ) ) + return town; + } + + return null; + } + + public static void GrantTownSilver_OnCommand( CommandEventArgs e ) + { + Town town = FromRegion( e.Mobile.Region ); + + if ( town == null ) + e.Mobile.SendMessage( "You are not in a faction town." ); + else if ( e.Length == 0 ) + e.Mobile.SendMessage( "Format: GrantTownSilver " ); + else + { + town.Silver += e.GetInt32( 0 ); + e.Mobile.SendMessage( "You have granted {0:N0} silver to the town. It now has {1:N0} silver.", e.GetInt32( 0 ), town.Silver ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/TownState.cs b/Scripts/Engines/Factions/Core/TownState.cs new file mode 100644 index 0000000..cc1532e --- /dev/null +++ b/Scripts/Engines/Factions/Core/TownState.cs @@ -0,0 +1,168 @@ +using System; + +namespace Server.Factions +{ + public class TownState + { + private Town m_Town; + private Faction m_Owner; + + private Mobile m_Sheriff; + private Mobile m_Finance; + + private int m_Silver; + private int m_Tax; + + private DateTime m_LastTaxChange; + private DateTime m_LastIncome; + + public Town Town + { + get{ return m_Town; } + set{ m_Town = value; } + } + + public Faction Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + public Mobile Sheriff + { + get{ return m_Sheriff; } + set + { + if ( m_Sheriff != null ) + { + PlayerState pl = PlayerState.Find( m_Sheriff ); + + if ( pl != null ) + pl.Sheriff = null; + } + + m_Sheriff = value; + + if ( m_Sheriff != null ) + { + PlayerState pl = PlayerState.Find( m_Sheriff ); + + if ( pl != null ) + pl.Sheriff = m_Town; + } + } + } + + public Mobile Finance + { + get{ return m_Finance; } + set + { + if ( m_Finance != null ) + { + PlayerState pl = PlayerState.Find( m_Finance ); + + if ( pl != null ) + pl.Finance = null; + } + + m_Finance = value; + + if ( m_Finance != null ) + { + PlayerState pl = PlayerState.Find( m_Finance ); + + if ( pl != null ) + pl.Finance = m_Town; + } + } + } + + public int Silver + { + get{ return m_Silver; } + set{ m_Silver = value; } + } + + public int Tax + { + get{ return m_Tax; } + set{ m_Tax = value; } + } + + public DateTime LastTaxChange + { + get{ return m_LastTaxChange; } + set{ m_LastTaxChange = value; } + } + + public DateTime LastIncome + { + get{ return m_LastIncome; } + set{ m_LastIncome = value; } + } + + public TownState( Town town ) + { + m_Town = town; + } + + public TownState( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 3: + { + m_LastIncome = reader.ReadDateTime(); + + goto case 2; + } + case 2: + { + m_Tax = reader.ReadEncodedInt(); + m_LastTaxChange = reader.ReadDateTime(); + + goto case 1; + } + case 1: + { + m_Silver = reader.ReadEncodedInt(); + + goto case 0; + } + case 0: + { + m_Town = Town.ReadReference( reader ); + m_Owner = Faction.ReadReference( reader ); + + m_Sheriff = reader.ReadMobile(); + m_Finance = reader.ReadMobile(); + + m_Town.State = this; + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 3 ); // version + + writer.Write( (DateTime) m_LastIncome ); + + writer.WriteEncodedInt( (int) m_Tax ); + writer.Write( (DateTime) m_LastTaxChange ); + + writer.WriteEncodedInt( (int) m_Silver ); + + Town.WriteReference( writer, m_Town ); + Faction.WriteReference( writer, m_Owner ); + + writer.Write( (Mobile) m_Sheriff ); + writer.Write( (Mobile) m_Finance ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Core/VendorList.cs b/Scripts/Engines/Factions/Core/VendorList.cs new file mode 100644 index 0000000..e5a02de --- /dev/null +++ b/Scripts/Engines/Factions/Core/VendorList.cs @@ -0,0 +1,27 @@ +using System; +using Server; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class VendorList + { + private VendorDefinition m_Definition; + private List m_Vendors; + + public VendorDefinition Definition{ get{ return m_Definition; } } + public List Vendors { get { return m_Vendors; } } + + public BaseFactionVendor Construct( Town town, Faction faction ) + { + try{ return Activator.CreateInstance( m_Definition.Type, new object[]{ town, faction } ) as BaseFactionVendor; } + catch{ return null; } + } + + public VendorList( VendorDefinition definition ) + { + m_Definition = definition; + m_Vendors = new List(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/FactionDefinition.cs b/Scripts/Engines/Factions/Definitions/FactionDefinition.cs new file mode 100644 index 0000000..f58c9c8 --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/FactionDefinition.cs @@ -0,0 +1,100 @@ +using System; + +namespace Server.Factions +{ + public class FactionDefinition + { + private int m_Sort; + + private int m_HuePrimary; + private int m_HueSecondary; + private int m_HueJoin; + private int m_HueBroadcast; + + private int m_WarHorseBody; + private int m_WarHorseItem; + + private string m_FriendlyName; + private string m_Keyword; + private string m_Abbreviation; + + private TextDefinition m_Name; + private TextDefinition m_PropName; + private TextDefinition m_Header; + private TextDefinition m_About; + private TextDefinition m_CityControl; + private TextDefinition m_SigilControl; + private TextDefinition m_SignupName; + private TextDefinition m_FactionStoneName; + private TextDefinition m_OwnerLabel; + + private TextDefinition m_GuardIgnore, m_GuardWarn, m_GuardAttack; + + private StrongholdDefinition m_Stronghold; + + private RankDefinition[] m_Ranks; + private GuardDefinition[] m_Guards; + + public int Sort{ get{ return m_Sort; } } + + public int HuePrimary{ get{ return m_HuePrimary; } } + public int HueSecondary{ get{ return m_HueSecondary; } } + public int HueJoin{ get{ return m_HueJoin; } } + public int HueBroadcast{ get{ return m_HueBroadcast; } } + + public int WarHorseBody{ get{ return m_WarHorseBody; } } + public int WarHorseItem{ get{ return m_WarHorseItem; } } + + public string FriendlyName{ get{ return m_FriendlyName; } } + public string Keyword{ get{ return m_Keyword; } } + public string Abbreviation{ get { return m_Abbreviation; } } + + public TextDefinition Name{ get{ return m_Name; } } + public TextDefinition PropName{ get{ return m_PropName; } } + public TextDefinition Header{ get{ return m_Header; } } + public TextDefinition About{ get{ return m_About; } } + public TextDefinition CityControl{ get{ return m_CityControl; } } + public TextDefinition SigilControl{ get{ return m_SigilControl; } } + public TextDefinition SignupName{ get{ return m_SignupName; } } + public TextDefinition FactionStoneName{ get{ return m_FactionStoneName; } } + public TextDefinition OwnerLabel{ get{ return m_OwnerLabel; } } + + public TextDefinition GuardIgnore{ get{ return m_GuardIgnore; } } + public TextDefinition GuardWarn{ get{ return m_GuardWarn; } } + public TextDefinition GuardAttack{ get{ return m_GuardAttack; } } + + public StrongholdDefinition Stronghold{ get{ return m_Stronghold; } } + + public RankDefinition[] Ranks{ get{ return m_Ranks; } } + public GuardDefinition[] Guards{ get{ return m_Guards; } } + + public FactionDefinition( int sort, int huePrimary, int hueSecondary, int hueJoin, int hueBroadcast, int warHorseBody, int warHorseItem, string friendlyName, string keyword, string abbreviation, TextDefinition name, TextDefinition propName, TextDefinition header, TextDefinition about, TextDefinition cityControl, TextDefinition sigilControl, TextDefinition signupName, TextDefinition factionStoneName, TextDefinition ownerLabel, TextDefinition guardIgnore, TextDefinition guardWarn, TextDefinition guardAttack, StrongholdDefinition stronghold, RankDefinition[] ranks, GuardDefinition[] guards ) + { + m_Sort = sort; + m_HuePrimary = huePrimary; + m_HueSecondary = hueSecondary; + m_HueJoin = hueJoin; + m_HueBroadcast = hueBroadcast; + m_WarHorseBody = warHorseBody; + m_WarHorseItem = warHorseItem; + m_FriendlyName = friendlyName; + m_Keyword = keyword; + m_Abbreviation = abbreviation; + m_Name = name; + m_PropName = propName; + m_Header = header; + m_About = about; + m_CityControl = cityControl; + m_SigilControl = sigilControl; + m_SignupName = signupName; + m_FactionStoneName = factionStoneName; + m_OwnerLabel = ownerLabel; + m_GuardIgnore = guardIgnore; + m_GuardWarn = guardWarn; + m_GuardAttack = guardAttack; + m_Stronghold = stronghold; + m_Ranks = ranks; + m_Guards = guards; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/FactionItemDefinition.cs b/Scripts/Engines/Factions/Definitions/FactionItemDefinition.cs new file mode 100644 index 0000000..b080e43 --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/FactionItemDefinition.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionItemDefinition + { + private int m_SilverCost; + private Type m_VendorType; + + public int SilverCost{ get{ return m_SilverCost; } } + public Type VendorType{ get{ return m_VendorType; } } + + public FactionItemDefinition( int silverCost, Type vendorType ) + { + m_SilverCost = silverCost; + m_VendorType = vendorType; + } + + private static FactionItemDefinition m_MetalArmor = new FactionItemDefinition( 1000, typeof( Blacksmith ) ); + private static FactionItemDefinition m_Weapon = new FactionItemDefinition( 1000, typeof( Blacksmith ) ); + private static FactionItemDefinition m_RangedWeapon = new FactionItemDefinition( 1000, typeof( Bowyer ) ); + private static FactionItemDefinition m_LeatherArmor = new FactionItemDefinition( 750, typeof( Tailor ) ); + private static FactionItemDefinition m_Clothing = new FactionItemDefinition( 200, typeof( Tailor ) ); + private static FactionItemDefinition m_Scroll = new FactionItemDefinition( 500, typeof( Mage ) ); + + public static FactionItemDefinition Identify( Item item ) + { + if ( item is BaseArmor ) + { + if ( CraftResources.GetType( ((BaseArmor)item).Resource ) == CraftResourceType.Leather ) + return m_LeatherArmor; + + return m_MetalArmor; + } + + if ( item is BaseRanged ) + return m_RangedWeapon; + else if ( item is BaseWeapon ) + return m_Weapon; + else if ( item is BaseClothing ) + return m_Clothing; + else if ( item is SpellScroll ) + return m_Scroll; + + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/GuardDefinition.cs b/Scripts/Engines/Factions/Definitions/GuardDefinition.cs new file mode 100644 index 0000000..f105f76 --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/GuardDefinition.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class GuardDefinition + { + private Type m_Type; + + private int m_Price; + private int m_Upkeep; + private int m_Maximum; + + private int m_ItemID; + + private TextDefinition m_Header; + private TextDefinition m_Label; + + public Type Type{ get{ return m_Type; } } + + public int Price{ get{ return m_Price; } } + public int Upkeep{ get{ return m_Upkeep; } } + public int Maximum{ get{ return m_Maximum; } } + public int ItemID{ get{ return m_ItemID; } } + + public TextDefinition Header{ get{ return m_Header; } } + public TextDefinition Label{ get{ return m_Label; } } + + public GuardDefinition( Type type, int itemID, int price, int upkeep, int maximum, TextDefinition header, TextDefinition label ) + { + m_Type = type; + + m_Price = price; + m_Upkeep = upkeep; + m_Maximum = maximum; + m_ItemID = itemID; + + m_Header = header; + m_Label = label; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/RankDefinition.cs b/Scripts/Engines/Factions/Definitions/RankDefinition.cs new file mode 100644 index 0000000..eef525d --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/RankDefinition.cs @@ -0,0 +1,25 @@ +using System; + +namespace Server.Factions +{ + public class RankDefinition + { + private int m_Rank; + private int m_Required; + private int m_MaxWearables; + private TextDefinition m_Title; + + public int Rank{ get{ return m_Rank; } } + public int Required{ get{ return m_Required; } } + public int MaxWearables{ get{ return m_MaxWearables; } } + public TextDefinition Title{ get{ return m_Title; } } + + public RankDefinition( int rank, int required, int maxWearables, TextDefinition title ) + { + m_Rank = rank; + m_Required = required; + m_Title = title; + m_MaxWearables = maxWearables; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/StrongholdDefintion.cs b/Scripts/Engines/Factions/Definitions/StrongholdDefintion.cs new file mode 100644 index 0000000..30a813d --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/StrongholdDefintion.cs @@ -0,0 +1,27 @@ +using System; + +namespace Server.Factions +{ + public class StrongholdDefinition + { + private Rectangle2D[] m_Area; + private Point3D m_JoinStone; + private Point3D m_FactionStone; + private Point3D[] m_Monoliths; + + public Rectangle2D[] Area{ get{ return m_Area; } } + + public Point3D JoinStone{ get{ return m_JoinStone; } } + public Point3D FactionStone{ get{ return m_FactionStone; } } + + public Point3D[] Monoliths{ get{ return m_Monoliths; } } + + public StrongholdDefinition( Rectangle2D[] area, Point3D joinStone, Point3D factionStone, Point3D[] monoliths ) + { + m_Area = area; + m_JoinStone = joinStone; + m_FactionStone = factionStone; + m_Monoliths = monoliths; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/TownDefinition.cs b/Scripts/Engines/Factions/Definitions/TownDefinition.cs new file mode 100644 index 0000000..513491b --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/TownDefinition.cs @@ -0,0 +1,59 @@ +using System; + +namespace Server.Factions +{ + public class TownDefinition + { + private int m_Sort; + private int m_SigilID; + + private string m_Region; + + private string m_FriendlyName; + + private TextDefinition m_TownName; + private TextDefinition m_TownStoneHeader; + private TextDefinition m_StrongholdMonolithName; + private TextDefinition m_TownMonolithName; + private TextDefinition m_TownStoneName; + private TextDefinition m_SigilName; + private TextDefinition m_CorruptedSigilName; + + private Point3D m_Monolith; + private Point3D m_TownStone; + + public int Sort{ get{ return m_Sort; } } + public int SigilID{ get{ return m_SigilID; } } + + public string Region{ get{ return m_Region; } } + public string FriendlyName{ get{ return m_FriendlyName; } } + + public TextDefinition TownName{ get{ return m_TownName; } } + public TextDefinition TownStoneHeader{ get{ return m_TownStoneHeader; } } + public TextDefinition StrongholdMonolithName{ get{ return m_StrongholdMonolithName; } } + public TextDefinition TownMonolithName{ get{ return m_TownMonolithName; } } + public TextDefinition TownStoneName{ get{ return m_TownStoneName; } } + public TextDefinition SigilName{ get{ return m_SigilName; } } + public TextDefinition CorruptedSigilName{ get{ return m_CorruptedSigilName; } } + + public Point3D Monolith{ get{ return m_Monolith; } } + public Point3D TownStone{ get{ return m_TownStone; } } + + public TownDefinition( int sort, int sigilID, string region, string friendlyName, TextDefinition townName, TextDefinition townStoneHeader, TextDefinition strongholdMonolithName, TextDefinition townMonolithName, TextDefinition townStoneName, TextDefinition sigilName, TextDefinition corruptedSigilName, Point3D monolith, Point3D townStone ) + { + m_Sort = sort; + m_SigilID = sigilID; + m_Region = region; + m_FriendlyName = friendlyName; + m_TownName = townName; + m_TownStoneHeader = townStoneHeader; + m_StrongholdMonolithName = strongholdMonolithName; + m_TownMonolithName = townMonolithName; + m_TownStoneName = townStoneName; + m_SigilName = sigilName; + m_CorruptedSigilName = corruptedSigilName; + m_Monolith = monolith; + m_TownStone = townStone; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Definitions/VendorDefinition.cs b/Scripts/Engines/Factions/Definitions/VendorDefinition.cs new file mode 100644 index 0000000..d25f7da --- /dev/null +++ b/Scripts/Engines/Factions/Definitions/VendorDefinition.cs @@ -0,0 +1,83 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class VendorDefinition + { + private Type m_Type; + + private int m_Price; + private int m_Upkeep; + private int m_Maximum; + + private int m_ItemID; + + private TextDefinition m_Header; + private TextDefinition m_Label; + + public Type Type{ get{ return m_Type; } } + + public int Price{ get{ return m_Price; } } + public int Upkeep{ get{ return m_Upkeep; } } + public int Maximum{ get{ return m_Maximum; } } + public int ItemID{ get{ return m_ItemID; } } + + public TextDefinition Header{ get{ return m_Header; } } + public TextDefinition Label{ get{ return m_Label; } } + + public VendorDefinition( Type type, int itemID, int price, int upkeep, int maximum, TextDefinition header, TextDefinition label ) + { + m_Type = type; + + m_Price = price; + m_Upkeep = upkeep; + m_Maximum = maximum; + m_ItemID = itemID; + + m_Header = header; + m_Label = label; + } + + private static VendorDefinition[] m_Definitions = new VendorDefinition[] + { + new VendorDefinition( typeof( FactionBottleVendor ), 0xF0E, + 5000, + 1000, + 10, + new TextDefinition( 1011549, "POTION BOTTLE VENDOR" ), + new TextDefinition( 1011544, "Buy Potion Bottle Vendor" ) + ), + new VendorDefinition( typeof( FactionBoardVendor ), 0x1BD7, + 3000, + 500, + 10, + new TextDefinition( 1011552, "WOOD VENDOR" ), + new TextDefinition( 1011545, "Buy Wooden Board Vendor" ) + ), + new VendorDefinition( typeof( FactionOreVendor ), 0x19B8, + 3000, + 500, + 10, + new TextDefinition( 1011553, "IRON ORE VENDOR" ), + new TextDefinition( 1011546, "Buy Iron Ore Vendor" ) + ), + new VendorDefinition( typeof( FactionReagentVendor ), 0xF86, + 5000, + 1000, + 10, + new TextDefinition( 1011554, "REAGENT VENDOR" ), + new TextDefinition( 1011547, "Buy Reagent Vendor" ) + ), + new VendorDefinition( typeof( FactionHorseVendor ), 0x20DD, + 5000, + 1000, + 1, + new TextDefinition( 1011556, "HORSE BREEDER" ), + new TextDefinition( 1011555, "Buy Horse Breeder" ) + ) + }; + + public static VendorDefinition[] Definitions{ get{ return m_Definitions; } } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/ElectionGump.cs b/Scripts/Engines/Factions/Gumps/ElectionGump.cs new file mode 100644 index 0000000..fa834ff --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/ElectionGump.cs @@ -0,0 +1,128 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class ElectionGump : FactionGump + { + private PlayerMobile m_From; + private Election m_Election; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 0: // back + { + m_From.SendGump( new FactionStoneGump( m_From, m_Election.Faction ) ); + break; + } + case 1: // vote + { + if ( m_Election.State == ElectionState.Election ) + m_From.SendGump( new VoteGump( m_From, m_Election ) ); + + break; + } + case 2: // campaign + { + if ( m_Election.CanBeCandidate( m_From ) ) + m_Election.AddCandidate( m_From ); + + break; + } + } + } + + public ElectionGump( PlayerMobile from, Election election ) : base( 50, 50 ) + { + m_From = from; + m_Election = election; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 180, 5054 ); + AddBackground( 10, 10, 400, 160, 3000 ); + + AddHtmlText( 20, 20, 380, 20, election.Faction.Definition.Header, false, false ); + + // NOTE: Gump not entirely OSI-accurate, intentionally so + + switch ( election.State ) + { + case ElectionState.Pending: + { + TimeSpan toGo = ( election.LastStateTime + Election.PendingPeriod ) - DateTime.Now; + int days = (int) (toGo.TotalDays + 0.5); + + AddHtmlLocalized( 20, 40, 380, 20, 1038034, false, false ); // A new election campaign is pending + + if ( days > 0 ) + { + AddHtmlLocalized( 20, 60, 280, 20, 1018062, false, false ); // Days until next election : + AddLabel( 300, 60, 0, days.ToString() ); + } + else + { + AddHtmlLocalized( 20, 60, 280, 20, 1018059, false, false ); // Election campaigning begins tonight. + } + + break; + } + case ElectionState.Campaign: + { + TimeSpan toGo = ( election.LastStateTime + Election.CampaignPeriod ) - DateTime.Now; + int days = (int) (toGo.TotalDays + 0.5); + + AddHtmlLocalized( 20, 40, 380, 20, 1018058, false, false ); // There is an election campaign in progress. + + if ( days > 0 ) + { + AddHtmlLocalized( 20, 60, 280, 20, 1038033, false, false ); // Days to go: + AddLabel( 300, 60, 0, days.ToString() ); + } + else + { + AddHtmlLocalized( 20, 60, 280, 20, 1018061, false, false ); // Campaign in progress. Voting begins tonight. + } + + if ( m_Election.CanBeCandidate( m_From ) ) + { + AddButton( 20, 110, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 110, 350, 20, 1011427, false, false ); // CAMPAIGN FOR LEADERSHIP + } + else + { + PlayerState pl = PlayerState.Find( m_From ); + + if ( pl == null || pl.Rank.Rank < Election.CandidateRank ) + AddHtmlLocalized( 20, 100, 380, 20, 1010118, false, false ); // You must have a higher rank to run for office + } + + break; + } + case ElectionState.Election: + { + TimeSpan toGo = ( election.LastStateTime + Election.VotingPeriod ) - DateTime.Now; + int days = (int) Math.Ceiling( toGo.TotalDays ); + + AddHtmlLocalized( 20, 40, 380, 20, 1018060, false, false ); // There is an election vote in progress. + + AddHtmlLocalized( 20, 60, 280, 20, 1038033, false, false ); + AddLabel( 300, 60, 0, days.ToString() ); + + AddHtmlLocalized( 55, 100, 380, 20, 1011428, false, false ); // VOTE FOR LEADERSHIP + AddButton( 20, 100, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + break; + } + } + + AddButton( 20, 140, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 140, 350, 20, 1011012, false, false ); // CANCEL + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/ElectionManagementGump.cs b/Scripts/Engines/Factions/Gumps/ElectionManagementGump.cs new file mode 100644 index 0000000..c6e1e1e --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/ElectionManagementGump.cs @@ -0,0 +1,218 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class ElectionManagementGump : Gump + { + public string Right( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public static string FormatTimeSpan( TimeSpan ts ) + { + return String.Format( "{0:D2}:{1:D2}:{2:D2}:{3:D2}", ts.Days, ts.Hours % 24, ts.Minutes % 60, ts.Seconds % 60 ); + } + + public const int LabelColor = 0xFFFFFF; + + private Election m_Election; + private Candidate m_Candidate; + private int m_Page; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + int bid = info.ButtonID; + + if ( m_Candidate == null ) + { + if ( bid == 0 ) + { + } + else if ( bid == 1 ) + { + } + else + { + bid -= 2; + + if ( bid >= 0 && bid < m_Election.Candidates.Count ) + from.SendGump( new ElectionManagementGump( m_Election, m_Election.Candidates[bid], 0 ) ); + } + } + else + { + if ( bid == 0 ) + { + from.SendGump( new ElectionManagementGump( m_Election ) ); + } + else if ( bid == 1 ) + { + m_Election.RemoveCandidate( m_Candidate.Mobile ); + from.SendGump( new ElectionManagementGump( m_Election ) ); + } + else if ( bid == 2 && m_Page > 0 ) + { + from.SendGump( new ElectionManagementGump( m_Election, m_Candidate, m_Page - 1 ) ); + } + else if ( bid == 3 && (m_Page + 1) * 10 < m_Candidate.Voters.Count ) + { + from.SendGump( new ElectionManagementGump( m_Election, m_Candidate, m_Page + 1 ) ); + } + else + { + bid -= 4; + + if ( bid >= 0 && bid < m_Candidate.Voters.Count ) + { + m_Candidate.Voters.RemoveAt( bid ); + from.SendGump( new ElectionManagementGump( m_Election, m_Candidate, m_Page ) ); + } + } + } + } + + public ElectionManagementGump( Election election ) : this( election, null, 0 ) + { + } + + public ElectionManagementGump( Election election, Candidate candidate, int page ) : base( 40, 40 ) + { + m_Election = election; + m_Candidate = candidate; + m_Page = page; + + AddPage( 0 ); + + if ( candidate != null ) + { + AddBackground( 0, 0, 448, 354, 9270 ); + AddAlphaRegion( 10, 10, 428, 334 ); + + AddHtml( 10, 10, 428, 20, Color( Center( "Candidate Management" ), LabelColor ), false, false ); + + AddHtml( 45, 35, 100, 20, Color( "Player Name:", LabelColor ), false, false ); + AddHtml( 145, 35, 100, 20, Color( candidate.Mobile == null ? "null" : candidate.Mobile.Name, LabelColor ), false, false ); + + AddHtml( 45, 55, 100, 20, Color( "Vote Count:", LabelColor ), false, false ); + AddHtml( 145, 55, 100, 20, Color( candidate.Votes.ToString(), LabelColor ), false, false ); + + AddButton( 12, 73, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtml( 45, 75, 100, 20, Color( "Drop Candidate", LabelColor ), false, false ); + + AddImageTiled( 13, 99, 422, 242, 9264 ); + AddImageTiled( 14, 100, 420, 240, 9274 ); + AddAlphaRegion( 14, 100, 420, 240 ); + + AddHtml( 14, 100, 420, 20, Color( Center( "Voters" ), LabelColor ), false, false ); + + if ( page > 0 ) + AddButton( 397, 104, 0x15E3, 0x15E7, 2, GumpButtonType.Reply, 0 ); + else + AddImage( 397, 104, 0x25EA ); + + if ( (page + 1) * 10 < candidate.Voters.Count ) + AddButton( 414, 104, 0x15E1, 0x15E5, 3, GumpButtonType.Reply, 0 ); + else + AddImage( 414, 104, 0x25E6 ); + + + AddHtml( 14, 120, 30, 20, Color( Center( "DEL" ), LabelColor ), false, false ); + AddHtml( 47, 120, 150, 20, Color( "Name", LabelColor ), false, false ); + AddHtml( 195, 120, 100, 20, Color( Center( "Address" ), LabelColor ), false, false ); + AddHtml( 295, 120, 80, 20, Color( Center( "Time" ), LabelColor ), false, false ); + AddHtml( 355, 120, 60, 20, Color( Center( "Legit" ), LabelColor ), false, false ); + + int idx = 0; + + for ( int i = page*10; i >= 0 && i < candidate.Voters.Count && i < (page+1)*10; ++i, ++idx ) + { + Voter voter = (Voter)candidate.Voters[i]; + + AddButton( 13, 138 + (idx * 20), 4002, 4004, 4 + i, GumpButtonType.Reply, 0 ); + + object[] fields = voter.AcquireFields(); + + int x = 45; + + for ( int j = 0; j < fields.Length; ++j ) + { + object obj = fields[j]; + + if ( obj is Mobile ) + { + AddHtml( x + 2, 140 + (idx * 20), 150, 20, Color( ((Mobile)obj).Name, LabelColor ), false, false ); + x += 150; + } + else if ( obj is System.Net.IPAddress ) + { + AddHtml( x, 140 + (idx * 20), 100, 20, Color( Center( obj.ToString() ), LabelColor ), false, false ); + x += 100; + } + else if ( obj is DateTime ) + { + AddHtml( x, 140 + (idx * 20), 80, 20, Color( Center( FormatTimeSpan( ((DateTime)obj) - election.LastStateTime ) ), LabelColor ), false, false ); + x += 80; + } + else if ( obj is int ) + { + AddHtml( x, 140 + (idx * 20), 60, 20, Color( Center( (int)obj + "%" ), LabelColor ), false, false ); + x += 60; + } + } + } + } + else + { + AddBackground( 0, 0, 288, 334, 9270 ); + AddAlphaRegion( 10, 10, 268, 314 ); + + AddHtml( 10, 10, 268, 20, Color( Center( "Election Management" ), LabelColor ), false, false ); + + AddHtml( 45, 35, 100, 20, Color( "Current State:", LabelColor ), false, false ); + AddHtml( 145, 35, 100, 20, Color( election.State.ToString(), LabelColor ), false, false ); + + AddButton( 12, 53, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtml( 45, 55, 100, 20, Color( "Transition Time:", LabelColor ), false, false ); + AddHtml( 145, 55, 100, 20, Color( FormatTimeSpan( election.NextStateTime ), LabelColor ), false, false ); + + AddImageTiled( 13, 79, 262, 242, 9264 ); + AddImageTiled( 14, 80, 260, 240, 9274 ); + AddAlphaRegion( 14, 80, 260, 240 ); + + AddHtml( 14, 80, 260, 20, Color( Center( "Candidates" ), LabelColor ), false, false ); + AddHtml( 14, 100, 30, 20, Color( Center( "-->" ), LabelColor ), false, false ); + AddHtml( 47, 100, 150, 20, Color( "Name", LabelColor ), false, false ); + AddHtml( 195, 100, 80, 20, Color( Center( "Votes" ), LabelColor ), false, false ); + + for ( int i = 0; i < election.Candidates.Count; ++i ) + { + Candidate cd = election.Candidates[i]; + Mobile mob = cd.Mobile; + + if ( mob == null ) + continue; + + AddButton( 13, 118 + (i * 20), 4005, 4007, 2 + i, GumpButtonType.Reply, 0 ); + AddHtml( 47, 120 + (i * 20), 150, 20, Color( mob.Name, LabelColor ), false, false ); + AddHtml( 195, 120 + (i * 20), 80, 20, Color( Center( cd.Votes.ToString() ), LabelColor ), false, false ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/FactionGump.cs b/Scripts/Engines/Factions/Gumps/FactionGump.cs new file mode 100644 index 0000000..d1c9b2c --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/FactionGump.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Factions +{ + public abstract class FactionGump : Gump + { + public virtual int ButtonTypes{ get{ return 10; } } + + public int ToButtonID( int type, int index ) + { + return 1 + (index * ButtonTypes) + type; + } + + public bool FromButtonID( int buttonID, out int type, out int index ) + { + int offset = buttonID - 1; + + if ( offset >= 0 ) + { + type = offset % ButtonTypes; + index = offset / ButtonTypes; + return true; + } + else + { + type = index = 0; + return false; + } + } + + public static bool Exists( Mobile mob ) + { + return ( mob.FindGump( typeof( FactionGump ) ) != null ); + } + + public void AddHtmlText( int x, int y, int width, int height, TextDefinition text, bool back, bool scroll ) + { + if ( text != null && text.Number > 0 ) + AddHtmlLocalized( x, y, width, height, text.Number, back, scroll ); + else if ( text != null && text.String != null ) + AddHtml( x, y, width, height, text.String, back, scroll ); + } + + public FactionGump( int x, int y ) : base( x, y ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/FactionImbueGump.cs b/Scripts/Engines/Factions/Gumps/FactionImbueGump.cs new file mode 100644 index 0000000..3ed610a --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/FactionImbueGump.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Engines.Craft; + +namespace Server.Factions +{ + public class FactionImbueGump : FactionGump + { + private Item m_Item; + private Mobile m_Mobile; + private Faction m_Faction; + private CraftSystem m_CraftSystem; + private BaseTool m_Tool; + private object m_Notice; + private int m_Quality; + + private FactionItemDefinition m_Definition; + + public FactionImbueGump( int quality, Item item, Mobile from, CraftSystem craftSystem, BaseTool tool, object notice, int availableSilver, Faction faction, FactionItemDefinition def ) : base( 100, 200 ) + { + m_Item = item; + m_Mobile = from; + m_Faction = faction; + m_CraftSystem = craftSystem; + m_Tool = tool; + m_Notice = notice; + m_Quality = quality; + m_Definition = def; + + AddPage( 0 ); + + AddBackground( 0, 0, 320, 270, 5054 ); + AddBackground( 10, 10, 300, 250, 3000 ); + + AddHtmlLocalized( 20, 20, 210, 25, 1011569, false, false ); // Imbue with Faction properties? + + + AddHtmlLocalized( 20, 60, 170, 25, 1018302, false, false ); // Item quality: + AddHtmlLocalized( 175, 60, 100, 25, 1018305 - m_Quality, false, false ); // Exceptional, Average, Low + + AddHtmlLocalized( 20, 80, 170, 25, 1011572, false, false ); // Item Cost : + AddLabel( 175, 80, 0x34, def.SilverCost.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 100, 170, 25, 1011573, false, false ); // Your Silver : + AddLabel( 175, 100, 0x34, availableSilver.ToString( "N0" ) ); // NOTE: Added 'N0' + + + AddRadio( 20, 140, 210, 211, true, 1 ); + AddLabel( 55, 140, m_Faction.Definition.HuePrimary - 1, "*****" ); + AddHtmlLocalized( 150, 140, 150, 25, 1011570, false, false ); // Primary Color + + AddRadio( 20, 160, 210, 211, false, 2 ); + AddLabel( 55, 160, m_Faction.Definition.HueSecondary - 1, "*****" ); + AddHtmlLocalized( 150, 160, 150, 25, 1011571, false, false ); // Secondary Color + + + AddHtmlLocalized( 55, 200, 200, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 200, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 230, 200, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 230, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + Container pack = m_Mobile.Backpack; + + if ( pack != null && m_Item.IsChildOf( pack ) ) + { + if ( pack.ConsumeTotal( typeof( Silver ), m_Definition.SilverCost ) ) + { + int hue; + + if ( m_Item is SpellScroll ) + hue = 0; + else if ( info.IsSwitched( 1 ) ) + hue = m_Faction.Definition.HuePrimary; + else + hue = m_Faction.Definition.HueSecondary; + + FactionItem.Imbue( m_Item, m_Faction, true, hue ); + } + else + { + m_Mobile.SendLocalizedMessage( 1042204 ); // You do not have enough silver. + } + } + } + + if ( m_Tool != null && !m_Tool.Deleted && m_Tool.UsesRemaining > 0 ) + m_Mobile.SendGump( new CraftGump( m_Mobile, m_CraftSystem, m_Tool, m_Notice ) ); + else if ( m_Notice is string ) + m_Mobile.SendMessage( (string) m_Notice ); + else if ( m_Notice is int && ((int)m_Notice) > 0 ) + m_Mobile.SendLocalizedMessage( (int) m_Notice ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/FactionStoneGump.cs b/Scripts/Engines/Factions/Gumps/FactionStoneGump.cs new file mode 100644 index 0000000..dd1ee05 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/FactionStoneGump.cs @@ -0,0 +1,347 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class FactionStoneGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + + public override int ButtonTypes{ get{ return 4; } } + + public FactionStoneGump( PlayerMobile from, Faction faction ) : base( 20, 30 ) + { + m_From = from; + m_Faction = faction; + + AddPage( 0 ); + + AddBackground( 0, 0, 550, 440, 5054 ); + AddBackground( 10, 10, 530, 420, 3000 ); + + #region General + AddPage( 1 ); + + AddHtmlText( 20, 30, 510, 20, faction.Definition.Header, false, false ); + + AddHtmlLocalized( 20, 60, 100, 20, 1011429, false, false ); // Led By : + AddHtml( 125, 60, 200, 20, faction.Commander != null ? faction.Commander.Name : "Nobody", false, false ); + + AddHtmlLocalized( 20, 80, 100, 20, 1011457, false, false ); // Tithe rate : + if ( faction.Tithe >= 0 && faction.Tithe <= 100 && (faction.Tithe % 10) == 0 ) + AddHtmlLocalized( 125, 80, 350, 20, 1011480 + (faction.Tithe / 10), false, false ); + else + AddHtml( 125, 80, 350, 20, faction.Tithe + "%", false, false ); + + AddHtmlLocalized( 20, 100, 100, 20, 1011458, false, false ); // Traps placed : + AddHtml( 125, 100, 50, 20, faction.Traps.Count.ToString(), false, false ); + + AddHtmlLocalized( 55, 225, 200, 20, 1011428, false, false ); // VOTE FOR LEADERSHIP + AddButton( 20, 225, 4005, 4007, ToButtonID( 0, 0 ), GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 150, 100, 20, 1011430, false, false ); // CITY STATUS + AddButton( 20, 150, 4005, 4007, 0, GumpButtonType.Page, 2 ); + + AddHtmlLocalized( 55, 175, 100, 20, 1011444, false, false ); // STATISTICS + AddButton( 20, 175, 4005, 4007, 0, GumpButtonType.Page, 4 ); + + bool isMerchantQualified = MerchantTitles.HasMerchantQualifications( from ); + + PlayerState pl = PlayerState.Find( from ); + + if ( pl != null && pl.MerchantTitle != MerchantTitle.None ) + { + AddHtmlLocalized( 55, 200, 250, 20, 1011460, false, false ); // UNDECLARE FACTION MERCHANT + AddButton( 20, 200, 4005, 4007, ToButtonID( 1, 0 ), GumpButtonType.Reply, 0 ); + } + else if ( isMerchantQualified ) + { + AddHtmlLocalized( 55, 200, 250, 20, 1011459, false, false ); // DECLARE FACTION MERCHANT + AddButton( 20, 200, 4005, 4007, 0, GumpButtonType.Page, 5 ); + } + else + { + AddHtmlLocalized( 55, 200, 250, 20, 1011467, false, false ); // MERCHANT OPTIONS + AddImage( 20, 200, 4020 ); + } + + AddHtmlLocalized( 55, 250, 300, 20, 1011461, false, false ); // COMMANDER OPTIONS + if ( faction.IsCommander( from ) ) + AddButton( 20, 250, 4005, 4007, 0, GumpButtonType.Page, 6 ); + else + AddImage( 20, 250, 4020 ); + + AddHtmlLocalized( 55, 275, 300, 20, 1011426, false, false ); // LEAVE THIS FACTION + AddButton( 20, 275, 4005, 4007, ToButtonID( 0, 1 ), GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 300, 200, 20, 1011441, false, false ); // EXIT + AddButton( 20, 300, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + #endregion + + #region City Status + AddPage( 2 ); + + AddHtmlLocalized( 20, 30, 250, 20, 1011430, false, false ); // CITY STATUS + + List towns = Town.Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + Town town = towns[i]; + + AddHtmlText( 40, 55 + (i * 30), 150, 20, town.Definition.TownName, false, false ); + + if ( town.Owner == null ) + { + AddHtmlLocalized( 200, 55 + (i * 30), 150, 20, 1011462, false, false ); // : Neutral + } + else + { + AddHtmlLocalized( 200, 55 + (i * 30), 150, 20, town.Owner.Definition.OwnerLabel, false, false ); + + BaseMonolith monolith = town.Monolith; + + AddImage( 20, 60 + (i * 30), ( monolith != null && monolith.Sigil != null && monolith.Sigil.IsPurifying ) ? 0x938 : 0x939 ); + } + } + + + AddImage( 20, 300, 2361 ); + AddHtmlLocalized( 45, 295, 300, 20, 1011491, false, false ); // sigil may be recaptured + + AddImage( 20, 320, 2360 ); + AddHtmlLocalized( 45, 315, 300, 20, 1011492, false, false ); // sigil may not be recaptured + + AddHtmlLocalized( 55, 350, 100, 20, 1011447, false, false ); // BACK + AddButton( 20, 350, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Statistics + AddPage( 4 ); + + AddHtmlLocalized( 20, 30, 150, 20, 1011444, false, false ); // STATISTICS + + AddHtmlLocalized( 20, 100, 100, 20, 1011445, false, false ); // Name : + AddHtml( 120, 100, 150, 20, from.Name, false, false ); + + AddHtmlLocalized( 20, 130, 100, 20, 1018064, false, false ); // score : + AddHtml( 120, 130, 100, 20, (pl != null ? pl.KillPoints : 0).ToString(), false, false ); + + AddHtmlLocalized( 20, 160, 100, 20, 1011446, false, false ); // Rank : + AddHtml( 120, 160, 100, 20, (pl != null ? pl.Rank.Rank : 0).ToString(), false, false ); + + AddHtmlLocalized( 55, 250, 100, 20, 1011447, false, false ); // BACK + AddButton( 20, 250, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Merchant Options + if ( ( pl == null || pl.MerchantTitle == MerchantTitle.None ) && isMerchantQualified ) + { + AddPage( 5 ); + + AddHtmlLocalized( 20, 30, 250, 20, 1011467, false, false ); // MERCHANT OPTIONS + + AddHtmlLocalized( 20, 80, 300, 20, 1011473, false, false ); // Select the title you wish to display + + MerchantTitleInfo[] infos = MerchantTitles.Info; + + for ( int i = 0; i < infos.Length; ++i ) + { + MerchantTitleInfo info = infos[i]; + + if ( MerchantTitles.IsQualified( from, info ) ) + AddButton( 20, 100 + (i * 30), 4005, 4007, ToButtonID( 1, i + 1 ), GumpButtonType.Reply, 0 ); + else + AddImage( 20, 100 + (i * 30), 4020 ); + + AddHtmlText( 55, 100 + (i * 30), 200, 20, info.Label, false, false ); + } + + AddHtmlLocalized( 55, 340, 100, 20, 1011447, false, false ); // BACK + AddButton( 20, 340, 4005, 4007, 0, GumpButtonType.Page, 1 ); + } + #endregion + + #region Commander Options + if ( faction.IsCommander( from ) ) + { + #region General + AddPage( 6 ); + + AddHtmlLocalized( 20, 30, 200, 20, 1011461, false, false ); // COMMANDER OPTIONS + + AddHtmlLocalized( 20, 70, 120, 20, 1011457, false, false ); // Tithe rate : + if ( faction.Tithe >= 0 && faction.Tithe <= 100 && (faction.Tithe % 10) == 0 ) + AddHtmlLocalized( 140, 70, 250, 20, 1011480 + (faction.Tithe / 10), false, false ); + else + AddHtml( 140, 70, 250, 20, faction.Tithe + "%", false, false ); + + AddHtmlLocalized( 20, 100, 120, 20, 1011474, false, false ); // Silver available : + AddHtml( 140, 100, 50, 20, faction.Silver.ToString( "N0" ), false, false ); // NOTE: Added 'N0' formatting + + AddHtmlLocalized( 55, 130, 200, 20, 1011478, false, false ); // CHANGE TITHE RATE + AddButton( 20, 130, 4005, 4007, 0, GumpButtonType.Page, 8 ); + + AddHtmlLocalized( 55, 160, 200, 20, 1018301, false, false ); // TRANSFER SILVER + if ( faction.Silver >= 10000 ) + AddButton( 20, 160, 4005, 4007, 0, GumpButtonType.Page, 7 ); + else + AddImage( 20, 160, 4020 ); + + AddHtmlLocalized( 55, 310, 100, 20, 1011447, false, false ); // BACK + AddButton( 20, 310, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Town Finance + if ( faction.Silver >= 10000 ) + { + AddPage( 7 ); + + AddHtmlLocalized( 20, 30, 250, 20, 1011476, false, false ); // TOWN FINANCE + + AddHtmlLocalized( 20, 50, 400, 20, 1011477, false, false ); // Select a town to transfer 10000 silver to + + for ( int i = 0; i < towns.Count; ++i ) + { + Town town = towns[i]; + + AddHtmlText( 55, 75 + (i * 30), 200, 20, town.Definition.TownName, false, false ); + + if ( town.Owner == faction ) + AddButton( 20, 75 + (i * 30), 4005, 4007, ToButtonID( 2, i ), GumpButtonType.Reply, 0 ); + else + AddImage( 20, 75 + (i * 30), 4020 ); + } + + AddHtmlLocalized( 55, 310, 100, 20, 1011447, false, false ); // BACK + AddButton( 20, 310, 4005, 4007, 0, GumpButtonType.Page, 1 ); + } + #endregion + + #region Change Tithe Rate + AddPage( 8 ); + + AddHtmlLocalized( 20, 30, 400, 20, 1011479, false, false ); // Select the % for the new tithe rate + + int y = 55; + + for ( int i = 0; i <= 10; ++i ) + { + if ( i == 5 ) + y += 5; + + AddHtmlLocalized( 55, y, 300, 20, 1011480 + i, false, false ); + AddButton( 20, y, 4005, 4007, ToButtonID( 3, i ), GumpButtonType.Reply, 0 ); + + y += 20; + + if ( i == 5 ) + y += 5; + } + + AddHtmlLocalized( 55, 310, 300, 20, 1011447, false, false ); // BACK + AddButton( 20, 310, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + } + #endregion + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int type, index; + + if ( !FromButtonID( info.ButtonID, out type, out index ) ) + return; + + switch ( type ) + { + case 0: // general + { + switch ( index ) + { + case 0: // vote + { + m_From.SendGump( new ElectionGump( m_From, m_Faction.Election ) ); + break; + } + case 1: // leave + { + m_From.SendGump( new LeaveFactionGump( m_From, m_Faction ) ); + break; + } + } + + break; + } + case 1: // merchant title + { + if ( index >= 0 && index <= MerchantTitles.Info.Length ) + { + PlayerState pl = PlayerState.Find( m_From ); + + MerchantTitle newTitle = (MerchantTitle)index; + MerchantTitleInfo mti = MerchantTitles.GetInfo( newTitle ); + + if ( mti == null ) + { + m_From.SendLocalizedMessage( 1010120 ); // Your merchant title has been removed + + if ( pl != null ) + pl.MerchantTitle = newTitle; + } + else if ( MerchantTitles.IsQualified( m_From, mti ) ) + { + m_From.SendLocalizedMessage( mti.Assigned ); + + if ( pl != null ) + pl.MerchantTitle = newTitle; + } + } + + break; + } + case 2: // transfer silver + { + if ( !m_Faction.IsCommander( m_From ) ) + return; + + List towns = Town.Towns; + + if ( index >= 0 && index < towns.Count ) + { + Town town = towns[index]; + + if ( town.Owner == m_Faction ) + { + if ( m_Faction.Silver >= 10000 ) + { + m_Faction.Silver -= 10000; + town.Silver += 10000; + + // 10k in silver has been received by: + m_From.SendLocalizedMessage( 1042726, true, " " + town.Definition.FriendlyName ); + } + } + } + + break; + } + case 3: // change tithe + { + if ( !m_Faction.IsCommander( m_From ) ) + return; + + if ( index >= 0 && index <= 10 ) + m_Faction.Tithe = index*10; + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/FinanceGump.cs b/Scripts/Engines/Factions/Gumps/FinanceGump.cs new file mode 100644 index 0000000..5f054f4 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/FinanceGump.cs @@ -0,0 +1,282 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class FinanceGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + private Town m_Town; + + private static int[] m_PriceOffsets = new int[] + { + -30, -25, -20, -15, -10, -5, + +50, +100, +150, +200, +250, +300 + }; + + public override int ButtonTypes{ get{ return 2; } } + + public FinanceGump( PlayerMobile from, Faction faction, Town town ) : base( 50, 50 ) + { + m_From = from; + m_Faction = faction; + m_Town = town; + + + AddPage( 0 ); + + AddBackground( 0, 0, 320, 410, 5054 ); + AddBackground( 10, 10, 300, 390, 3000 ); + + #region General + AddPage( 1 ); + + AddHtmlLocalized( 20, 30, 260, 25, 1011541, false, false ); // FINANCE MINISTER + + + AddHtmlLocalized( 55, 90, 200, 25, 1011539, false, false ); // CHANGE PRICES + AddButton( 20, 90, 4005, 4007, 0, GumpButtonType.Page, 2 ); + + AddHtmlLocalized( 55, 120, 200, 25, 1011540, false, false ); // BUY SHOPKEEPERS + AddButton( 20, 120, 4005, 4007, 0, GumpButtonType.Page, 3 ); + + AddHtmlLocalized( 55, 150, 200, 25, 1011495, false, false ); // VIEW FINANCES + AddButton( 20, 150, 4005, 4007, 0, GumpButtonType.Page, 4 ); + + AddHtmlLocalized( 55, 360, 200, 25, 1011441, false, false ); // EXIT + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + #endregion + + #region Change Prices + AddPage( 2 ); + + AddHtmlLocalized( 20, 30, 200, 25, 1011539, false, false ); // CHANGE PRICES + + for ( int i = 0; i < m_PriceOffsets.Length; ++i ) + { + int ofs = m_PriceOffsets[i]; + + int x = 20 + ((i / 6) * 150); + int y = 90 + ((i % 6) * 30); + + AddRadio( x, y, 208, 209, ( town.Tax == ofs ), i+1 ); + + if ( ofs < 0 ) + AddLabel( x + 35, y, 0x26, String.Concat( "- ", -ofs, "%" ) ); + else + AddLabel( x + 35, y, 0x12A, String.Concat( "+ ", ofs, "%" ) ); + } + + AddRadio( 20, 270, 208, 209, ( town.Tax == 0 ), 0 ); + AddHtmlLocalized( 55, 270, 90, 25, 1011542, false, false ); // normal + + AddHtmlLocalized( 55, 330, 200, 25, 1011509, false, false ); // Set Prices + AddButton( 20, 330, 4005, 4007, ToButtonID( 0, 0 ), GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Buy Shopkeepers + AddPage( 3 ); + + AddHtmlLocalized( 20, 30, 200, 25, 1011540, false, false ); // BUY SHOPKEEPERS + + List vendorLists = town.VendorLists; + + for ( int i = 0; i < vendorLists.Count; ++i ) + { + VendorList list = vendorLists[i]; + + AddButton( 20, 90 + (i * 40), 4005, 4007, 0, GumpButtonType.Page, 5 + i ); + AddItem( 55, 90 + (i * 40), list.Definition.ItemID ); + AddHtmlText( 100, 90 + (i * 40), 200, 25, list.Definition.Label, false, false ); + } + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region View Finances + AddPage( 4 ); + + int financeUpkeep = town.FinanceUpkeep; + int sheriffUpkeep = town.SheriffUpkeep; + int dailyIncome = town.DailyIncome; + int netCashFlow = town.NetCashFlow; + + + AddHtmlLocalized( 20, 30, 300, 25, 1011524, false, false ); // FINANCE STATEMENT + + AddHtmlLocalized( 20, 80, 300, 25, 1011538, false, false ); // Current total money for town : + AddLabel( 20, 100, 0x44, town.Silver.ToString() ); + + AddHtmlLocalized( 20, 130, 300, 25, 1011520, false, false ); // Finance Minister Upkeep : + AddLabel( 20, 150, 0x44, financeUpkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 180, 300, 25, 1011521, false, false ); // Sheriff Upkeep : + AddLabel( 20, 200, 0x44, sheriffUpkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 230, 300, 25, 1011522, false, false ); // Town Income : + AddLabel( 20, 250, 0x44, dailyIncome.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 280, 300, 25, 1011523, false, false ); // Net Cash flow per day : + AddLabel( 20, 300, 0x44, netCashFlow.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Shopkeeper Pages + for ( int i = 0; i < vendorLists.Count; ++i ) + { + VendorList vendorList = vendorLists[i]; + + AddPage( 5 + i ); + + AddHtmlText( 60, 30, 300, 25, vendorList.Definition.Header, false, false ); + AddItem( 20, 30, vendorList.Definition.ItemID ); + + AddHtmlLocalized( 20, 90, 200, 25, 1011514, false, false ); // You have : + AddLabel( 230, 90, 0x26, vendorList.Vendors.Count.ToString() ); + + AddHtmlLocalized( 20, 120, 200, 25, 1011515, false, false ); // Maximum : + AddLabel( 230, 120, 0x256, vendorList.Definition.Maximum.ToString() ); + + AddHtmlLocalized( 20, 150, 200, 25, 1011516, false, false ); // Cost : + AddLabel( 230, 150, 0x44, vendorList.Definition.Price.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 180, 200, 25, 1011517, false, false ); // Daily Pay : + AddLabel( 230, 180, 0x37, vendorList.Definition.Upkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 210, 200, 25, 1011518, false, false ); // Current Silver : + AddLabel( 230, 210, 0x44, town.Silver.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 240, 200, 25, 1011519, false, false ); // Current Payroll : + AddLabel( 230, 240, 0x44, financeUpkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlText( 55, 300, 200, 25, vendorList.Definition.Label, false, false ); + if ( town.Silver >= vendorList.Definition.Price ) + AddButton( 20, 300, 4005, 4007, ToButtonID( 1, i ), GumpButtonType.Reply, 0 ); + else + AddImage( 20, 300, 4020 ); + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 3 ); + } + #endregion + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( !m_Town.IsFinance( m_From ) || m_Town.Owner != m_Faction ) + { + m_From.SendLocalizedMessage( 1010339 ); // You no longer control this city + return; + } + + int type, index; + + if ( !FromButtonID( info.ButtonID, out type, out index ) ) + return; + + switch ( type ) + { + case 0: // general + { + switch ( index ) + { + case 0: // set price + { + int[] switches = info.Switches; + + if ( switches.Length == 0 ) + break; + + int opt = switches[0]; + int newTax = 0; + + if ( opt >= 1 && opt <= m_PriceOffsets.Length ) + newTax = m_PriceOffsets[opt - 1]; + + if ( m_Town.Tax == newTax ) + break; + + if ( m_From.AccessLevel == AccessLevel.Player && !m_Town.TaxChangeReady ) + { + TimeSpan remaining = DateTime.Now - ( m_Town.LastTaxChange + Town.TaxChangePeriod ); + + if ( remaining.TotalMinutes < 4 ) + m_From.SendLocalizedMessage( 1042165 ); // You must wait a short while before changing prices again. + else if ( remaining.TotalMinutes < 10 ) + m_From.SendLocalizedMessage( 1042166 ); // You must wait several minutes before changing prices again. + else if ( remaining.TotalHours < 1 ) + m_From.SendLocalizedMessage( 1042167 ); // You must wait up to an hour before changing prices again. + else if ( remaining.TotalHours < 4 ) + m_From.SendLocalizedMessage( 1042168 ); // You must wait a few hours before changing prices again. + else + m_From.SendLocalizedMessage( 1042169 ); // You must wait several hours before changing prices again. + } + else + { + m_Town.Tax = newTax; + + if ( m_From.AccessLevel == AccessLevel.Player ) + m_Town.LastTaxChange = DateTime.Now; + } + + break; + } + } + + break; + } + case 1: // make vendor + { + List vendorLists = m_Town.VendorLists; + + if ( index >= 0 && index < vendorLists.Count ) + { + VendorList vendorList = vendorLists[index]; + + Town town = Town.FromRegion( m_From.Region ); + + if ( Town.FromRegion( m_From.Region ) != m_Town ) + { + m_From.SendLocalizedMessage( 1010305 ); // You must be in your controlled city to buy Items + } + else if ( vendorList.Vendors.Count >= vendorList.Definition.Maximum ) + { + m_From.SendLocalizedMessage( 1010306 ); // You currently have too many of this enhancement type to place another + } + else if (BaseBoat.FindBoatAt(m_From.Location, m_From.Map) != null) + { + m_From.SendMessage("You cannot place a vendor here"); + } + else if ( m_Town.Silver >= vendorList.Definition.Price ) + { + BaseFactionVendor vendor = vendorList.Construct( m_Town, m_Faction ); + + if ( vendor != null ) + { + m_Town.Silver -= vendorList.Definition.Price; + + vendor.MoveToWorld( m_From.Location, m_From.Map ); + vendor.Home = vendor.Location; + } + } + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/HorseBreederGump.cs b/Scripts/Engines/Factions/Gumps/HorseBreederGump.cs new file mode 100644 index 0000000..c1c9ae3 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/HorseBreederGump.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class HorseBreederGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + + public HorseBreederGump( PlayerMobile from, Faction faction ) : base( 20, 30 ) + { + m_From = from; + m_Faction = faction; + + AddPage( 0 ); + + AddBackground( 0, 0, 320, 280, 5054 ); + AddBackground( 10, 10, 300, 260, 3000 ); + + AddHtmlText( 20, 30, 300, 25, faction.Definition.Header, false, false ); + + AddHtmlLocalized( 20, 60, 300, 25, 1018306, false, false ); // Purchase a Faction War Horse + AddItem( 70, 120, 0x3FFE ); + + AddItem( 150, 120, 0xEF2 ); + AddLabel( 190, 122, 0x3E3, FactionWarHorse.SilverPrice.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddItem( 150, 150, 0xEEF ); + AddLabel( 190, 152, 0x3E3, FactionWarHorse.GoldPrice.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 55, 210, 200, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 210, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 240, 200, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 240, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID != 1 ) + return; + + if ( Faction.Find( m_From ) != m_Faction ) + return; + + Container pack = m_From.Backpack; + + if ( pack == null ) + return; + + FactionWarHorse horse = new FactionWarHorse( m_Faction ); + + if ( (m_From.Followers + horse.ControlSlots) > m_From.FollowersMax ) + { + // TODO: Message? + horse.Delete(); + } + else + { + if ( pack.GetAmount( typeof( Silver ) ) < FactionWarHorse.SilverPrice ) + { + sender.Mobile.SendLocalizedMessage( 1042204 ); // You do not have enough silver. + horse.Delete(); + } + else if ( pack.GetAmount( typeof( Gold ) ) < FactionWarHorse.GoldPrice ) + { + sender.Mobile.SendLocalizedMessage( 1042205 ); // You do not have enough gold. + horse.Delete(); + } + else if ( pack.ConsumeTotal( typeof( Silver ), FactionWarHorse.SilverPrice ) && pack.ConsumeTotal( typeof( Gold ), FactionWarHorse.GoldPrice ) ) + { + horse.Controlled = true; + horse.ControlMaster = m_From; + + horse.ControlOrder = OrderType.Follow; + horse.ControlTarget = m_From; + + horse.MoveToWorld( m_From.Location, m_From.Map ); + } + else + { + horse.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/JoinStoneGump.cs b/Scripts/Engines/Factions/Gumps/JoinStoneGump.cs new file mode 100644 index 0000000..a113cd9 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/JoinStoneGump.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class JoinStoneGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + + public JoinStoneGump( PlayerMobile from, Faction faction ) : base( 20, 30 ) + { + m_From = from; + m_Faction = faction; + + AddPage( 0 ); + + AddBackground( 0, 0, 550, 440, 5054 ); + AddBackground( 10, 10, 530, 420, 3000 ); + + + AddHtmlText( 20, 30, 510, 20, faction.Definition.Header, false, false ); + AddHtmlText( 20, 130, 510, 100, faction.Definition.About, true, true ); + + + AddHtmlLocalized( 20, 60, 100, 20, 1011429, false, false ); // Led By : + AddHtml( 125, 60, 200, 20, faction.Commander != null ? faction.Commander.Name : "Nobody", false, false ); + + AddHtmlLocalized( 20, 80, 100, 20, 1011457, false, false ); // Tithe rate : + if ( faction.Tithe >= 0 && faction.Tithe <= 100 && (faction.Tithe % 10) == 0 ) + AddHtmlLocalized( 125, 80, 350, 20, 1011480 + (faction.Tithe / 10), false, false ); + else + AddHtml( 125, 80, 350, 20, faction.Tithe + "%", false, false ); + + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 200, 20, 1011425, false, false ); // JOIN THIS FACTION + + AddButton( 300, 400, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 200, 20, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_Faction.OnJoinAccepted( m_From ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/LeaveFactionGump.cs b/Scripts/Engines/Factions/Gumps/LeaveFactionGump.cs new file mode 100644 index 0000000..45614f2 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/LeaveFactionGump.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Gumps; +using Server.Guilds; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class LeaveFactionGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + + public LeaveFactionGump( PlayerMobile from, Faction faction ) : base( 20, 30 ) + { + m_From = from; + m_Faction = faction; + + AddBackground( 0, 0, 270, 120, 5054 ); + AddBackground( 10, 10, 250, 100, 3000 ); + + if ( from.Guild is Guild && ((Guild)from.Guild).Leader == from ) + AddHtmlLocalized( 20, 15, 230, 60, 1018057, true, true ); // Are you sure you want your entire guild to leave this faction? + else + AddHtmlLocalized( 20, 15, 230, 60, 1018063, true, true ); // Are you sure you want to leave this faction? + + AddHtmlLocalized( 55, 80, 75, 20, 1011011, false, false ); // CONTINUE + AddButton( 20, 80, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 170, 80, 75, 20, 1011012, false, false ); // CANCEL + AddButton( 135, 80, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 1: // continue + { + Guild guild = m_From.Guild as Guild; + + if ( guild == null ) + { + PlayerState pl = PlayerState.Find( m_From ); + + if ( pl != null ) + { + pl.Leaving = DateTime.Now; + + if ( Faction.LeavePeriod == TimeSpan.FromDays( 3.0 ) ) + m_From.SendLocalizedMessage( 1005065 ); // You will be removed from the faction in 3 days + else + m_From.SendMessage( "You will be removed from the faction in {0} days.", Faction.LeavePeriod.TotalDays ); + } + } + else if ( guild.Leader != m_From ) + { + m_From.SendLocalizedMessage( 1005061 ); // You cannot quit the faction because you are not the guild master + } + else + { + m_From.SendLocalizedMessage( 1042285 ); // Your guild is now quitting the faction. + + for ( int i = 0; i < guild.Members.Count; ++i ) + { + Mobile mob = (Mobile) guild.Members[i]; + PlayerState pl = PlayerState.Find( mob ); + + if ( pl != null ) + { + pl.Leaving = DateTime.Now; + + if ( Faction.LeavePeriod == TimeSpan.FromDays( 3.0 ) ) + mob.SendLocalizedMessage( 1005060 ); // Your guild will quit the faction in 3 days + else + mob.SendMessage( "Your guild will quit the faction in {0} days.", Faction.LeavePeriod.TotalDays ); + } + } + } + + break; + } + case 2: // cancel + { + m_From.SendLocalizedMessage( 500737 ); // Canceled resignation. + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/SheriffGump.cs b/Scripts/Engines/Factions/Gumps/SheriffGump.cs new file mode 100644 index 0000000..3e30353 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/SheriffGump.cs @@ -0,0 +1,183 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class SheriffGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + private Town m_Town; + + private void CenterItem( int itemID, int x, int y, int w, int h ) + { + Rectangle2D rc = ItemBounds.Table[itemID]; + AddItem( x + ((w - rc.Width) / 2) - rc.X, y + ((h - rc.Height) / 2) - rc.Y, itemID ); + } + + public SheriffGump( PlayerMobile from, Faction faction, Town town ) : base( 50, 50 ) + { + m_From = from; + m_Faction = faction; + m_Town = town; + + + AddPage( 0 ); + + AddBackground( 0, 0, 320, 410, 5054 ); + AddBackground( 10, 10, 300, 390, 3000 ); + + #region General + AddPage( 1 ); + + AddHtmlLocalized( 20, 30, 260, 25, 1011431, false, false ); // Sheriff + + AddHtmlLocalized( 55, 90, 200, 25, 1011494, false, false ); // HIRE GUARDS + AddButton( 20, 90, 4005, 4007, 0, GumpButtonType.Page, 3 ); + + AddHtmlLocalized( 55, 120, 200, 25, 1011495, false, false ); // VIEW FINANCES + AddButton( 20, 120, 4005, 4007, 0, GumpButtonType.Page, 2 ); + + AddHtmlLocalized( 55, 360, 200, 25, 1011441, false, false ); // Exit + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + #endregion + + #region Finances + AddPage( 2 ); + + int financeUpkeep = town.FinanceUpkeep; + int sheriffUpkeep = town.SheriffUpkeep; + int dailyIncome = town.DailyIncome; + int netCashFlow = town.NetCashFlow; + + AddHtmlLocalized( 20, 30, 300, 25, 1011524, false, false ); // FINANCE STATEMENT + + AddHtmlLocalized( 20, 80, 300, 25, 1011538, false, false ); // Current total money for town : + AddLabel( 20, 100, 0x44, town.Silver.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 130, 300, 25, 1011520, false, false ); // Finance Minister Upkeep : + AddLabel( 20, 150, 0x44, financeUpkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 180, 300, 25, 1011521, false, false ); // Sheriff Upkeep : + AddLabel( 20, 200, 0x44, sheriffUpkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 230, 300, 25, 1011522, false, false ); // Town Income : + AddLabel( 20, 250, 0x44, dailyIncome.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 280, 300, 25, 1011523, false, false ); // Net Cash flow per day : + AddLabel( 20, 300, 0x44, netCashFlow.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Hire Guards + AddPage( 3 ); + + AddHtmlLocalized( 20, 30, 300, 25, 1011494, false, false ); // HIRE GUARDS + + List guardLists = town.GuardLists; + + for ( int i = 0; i < guardLists.Count; ++i ) + { + GuardList guardList = guardLists[i]; + int y = 90 + (i * 60); + + AddButton( 20, y, 4005, 4007, 0, GumpButtonType.Page, 4 + i ); + CenterItem( guardList.Definition.ItemID, 50, y - 20, 70, 60 ); + AddHtmlText( 120, y, 200, 25, guardList.Definition.Header, false, false ); + } + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 1 ); + #endregion + + #region Guard Pages + for ( int i = 0; i < guardLists.Count; ++i ) + { + GuardList guardList = guardLists[i]; + + AddPage( 4 + i ); + + AddHtmlText( 90, 30, 300, 25, guardList.Definition.Header, false, false ); + CenterItem( guardList.Definition.ItemID, 10, 10, 80, 80 ); + + AddHtmlLocalized( 20, 90, 200, 25, 1011514, false, false ); // You have : + AddLabel( 230, 90, 0x26, guardList.Guards.Count.ToString() ); + + AddHtmlLocalized( 20, 120, 200, 25, 1011515, false, false ); // Maximum : + AddLabel( 230, 120, 0x12A, guardList.Definition.Maximum.ToString() ); + + AddHtmlLocalized( 20, 150, 200, 25, 1011516, false, false ); // Cost : + AddLabel( 230, 150, 0x44, guardList.Definition.Price.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 180, 200, 25, 1011517, false, false ); // Daily Pay : + AddLabel( 230, 180, 0x37, guardList.Definition.Upkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 210, 200, 25, 1011518, false, false ); // Current Silver : + AddLabel( 230, 210, 0x44, town.Silver.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlLocalized( 20, 240, 200, 25, 1011519, false, false ); // Current Payroll : + AddLabel( 230, 240, 0x44, sheriffUpkeep.ToString( "N0" ) ); // NOTE: Added 'N0' + + AddHtmlText( 55, 300, 200, 25, guardList.Definition.Label, false, false ); + AddButton( 20, 300, 4005, 4007, 1 + i, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 360, 200, 25, 1011067, false, false ); // Previous page + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Page, 3 ); + } + #endregion + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( !m_Town.IsSheriff( m_From ) || m_Town.Owner != m_Faction ) + { + m_From.SendLocalizedMessage( 1010339 ); // You no longer control this city + return; + } + + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_Town.GuardLists.Count ) + { + GuardList guardList = m_Town.GuardLists[index]; + Town town = Town.FromRegion( m_From.Region ); + + if ( Town.FromRegion( m_From.Region ) != m_Town ) + { + m_From.SendLocalizedMessage( 1010305 ); // You must be in your controlled city to buy Items + } + else if ( guardList.Guards.Count >= guardList.Definition.Maximum ) + { + m_From.SendLocalizedMessage( 1010306 ); // You currently have too many of this enhancement type to place another + } + else if (BaseBoat.FindBoatAt(m_From.Location, m_From.Map) != null) + { + m_From.SendMessage("You cannot place a vendor here"); + } + else if ( m_Town.Silver >= guardList.Definition.Price ) + { + BaseFactionGuard guard = guardList.Construct(); + + if ( guard != null ) + { + guard.Faction = m_Faction; + guard.Town = m_Town; + + m_Town.Silver -= guardList.Definition.Price; + + guard.MoveToWorld( m_From.Location, m_From.Map ); + guard.Home = guard.Location; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/TownStoneGump.cs b/Scripts/Engines/Factions/Gumps/TownStoneGump.cs new file mode 100644 index 0000000..6fd39d3 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/TownStoneGump.cs @@ -0,0 +1,206 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Factions +{ + public class TownStoneGump : FactionGump + { + private PlayerMobile m_From; + private Faction m_Faction; + private Town m_Town; + + public TownStoneGump( PlayerMobile from, Faction faction, Town town ) : base( 50, 50 ) + { + m_From = from; + m_Faction = faction; + m_Town = town; + + AddPage( 0 ); + + AddBackground( 0, 0, 320, 250, 5054 ); + AddBackground( 10, 10, 300, 230, 3000 ); + + AddHtmlText( 25, 30, 250, 25, town.Definition.TownStoneHeader, false, false ); + + AddHtmlLocalized( 55, 60, 150, 25, 1011557, false, false ); // Hire Sheriff + AddButton( 20, 60, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 90, 150, 25, 1011559, false, false ); // Hire Finance Minister + AddButton( 20, 90, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 120, 150, 25, 1011558, false, false ); // Fire Sheriff + AddButton( 20, 120, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 150, 150, 25, 1011560, false, false ); // Fire Finance Minister + AddButton( 20, 150, 4005, 4007, 4, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 210, 150, 25, 1011441, false, false ); // EXIT + AddButton( 20, 210, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Town.Owner != m_Faction || !m_Faction.IsCommander( m_From ) ) + { + m_From.SendLocalizedMessage( 1010339 ); // You no longer control this city + return; + } + + switch ( info.ButtonID ) + { + case 1: // hire sheriff + { + if ( m_Town.Sheriff != null ) + { + m_From.SendLocalizedMessage( 1010342 ); // You must fire your Sheriff before you can elect a new one + } + else + { + m_From.SendLocalizedMessage( 1010347 ); // Who shall be your new sheriff + m_From.BeginTarget( 12, false, TargetFlags.None, new TargetCallback( HireSheriff_OnTarget ) ); + } + + break; + } + case 2: // hire finance minister + { + if ( m_Town.Finance != null ) + { + m_From.SendLocalizedMessage( 1010345 ); // You must fire your finance minister before you can elect a new one + } + else + { + m_From.SendLocalizedMessage( 1010348 ); // Who shall be your new Minister of Finances? + m_From.BeginTarget( 12, false, TargetFlags.None, new TargetCallback( HireFinanceMinister_OnTarget ) ); + } + + break; + } + case 3: // fire sheriff + { + if ( m_Town.Sheriff == null ) + { + m_From.SendLocalizedMessage( 1010350 ); // You need to elect a sheriff before you can fire one + } + else + { + m_From.SendLocalizedMessage( 1010349 ); // You have fired your sheriff + m_Town.Sheriff.SendLocalizedMessage( 1010270 ); // You have been fired as Sheriff + m_Town.Sheriff = null; + } + + break; + } + case 4: // fire finance minister + { + if ( m_Town.Finance == null ) + { + m_From.SendLocalizedMessage( 1010352 ); // You need to elect a financial minister before you can fire one + } + else + { + m_From.SendLocalizedMessage( 1010351 ); // You have fired your financial Minister + m_Town.Finance.SendLocalizedMessage( 1010151 ); // You have been fired as Finance Minister + m_Town.Finance = null; + } + + break; + } + } + } + + private void HireSheriff_OnTarget( Mobile from, object obj ) + { + if ( m_Town.Owner != m_Faction || !m_Faction.IsCommander( from ) ) + { + from.SendLocalizedMessage( 1010339 ); // You no longer control this city + return; + } + else if ( m_Town.Sheriff != null ) + { + from.SendLocalizedMessage( 1010342 ); // You must fire your Sheriff before you can elect a new one + } + else if ( obj is Mobile ) + { + Mobile targ = (Mobile)obj; + PlayerState pl = PlayerState.Find( targ ); + + if ( pl == null ) + { + from.SendLocalizedMessage( 1010337 ); // You must pick someone in a faction + } + else if ( pl.Faction != m_Faction ) + { + from.SendLocalizedMessage( 1010338 ); // You must pick someone in the correct faction + } + else if ( m_Faction.Commander == targ ) + { + from.SendLocalizedMessage( 1010335 ); // You cannot elect a commander to a town position + } + else if ( pl.Sheriff != null || pl.Finance != null ) + { + from.SendLocalizedMessage( 1005245 ); // You must pick someone who does not already hold a city post + } + else + { + m_Town.Sheriff = targ; + targ.SendLocalizedMessage( 1010340 ); // You are now the Sheriff + from.SendLocalizedMessage( 1010341 ); // You have elected a Sheriff + } + } + else + { + from.SendLocalizedMessage( 1010334 ); // You must select a player to hold a city position! + } + } + + private void HireFinanceMinister_OnTarget( Mobile from, object obj ) + { + if ( m_Town.Owner != m_Faction || !m_Faction.IsCommander( from ) ) + { + from.SendLocalizedMessage( 1010339 ); // You no longer control this city + return; + } + else if ( m_Town.Finance != null ) + { + from.SendLocalizedMessage( 1010342 ); // You must fire your Sheriff before you can elect a new one + } + else if ( obj is Mobile ) + { + Mobile targ = (Mobile)obj; + PlayerState pl = PlayerState.Find( targ ); + + if ( pl == null ) + { + from.SendLocalizedMessage( 1010337 ); // You must pick someone in a faction + } + else if ( pl.Faction != m_Faction ) + { + from.SendLocalizedMessage( 1010338 ); // You must pick someone in the correct faction + } + else if ( m_Faction.Commander == targ ) + { + from.SendLocalizedMessage( 1010335 ); // You cannot elect a commander to a town position + } + else if ( pl.Sheriff != null || pl.Finance != null ) + { + from.SendLocalizedMessage( 1005245 ); // You must pick someone who does not already hold a city post + } + else + { + m_Town.Finance = targ; + targ.SendLocalizedMessage( 1010343 ); // You are now the Financial Minister + from.SendLocalizedMessage( 1010344 ); // You have elected a Financial Minister + } + } + else + { + from.SendLocalizedMessage( 1010334 ); // You must select a player to hold a city position! + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Gumps/VoteGump.cs b/Scripts/Engines/Factions/Gumps/VoteGump.cs new file mode 100644 index 0000000..9cf8319 --- /dev/null +++ b/Scripts/Engines/Factions/Gumps/VoteGump.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class VoteGump : FactionGump + { + private PlayerMobile m_From; + private Election m_Election; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 ) + { + m_From.SendGump( new FactionStoneGump( m_From, m_Election.Faction ) ); + } + else + { + if ( !m_Election.CanVote( m_From ) ) + return; + + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_Election.Candidates.Count ) + m_Election.Candidates[index].Voters.Add( new Voter( m_From, m_Election.Candidates[index].Mobile ) ); + + m_From.SendGump( new VoteGump( m_From, m_Election ) ); + } + } + + public VoteGump( PlayerMobile from, Election election ) : base( 50, 50 ) + { + m_From = from; + m_Election = election; + + bool canVote = election.CanVote( from ); + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 350, 5054 ); + AddBackground( 10, 10, 400, 330, 3000 ); + + AddHtmlText( 20, 20, 380, 20, election.Faction.Definition.Header, false, false ); + + if ( canVote ) + AddHtmlLocalized( 20, 60, 380, 20, 1011428, false, false ); // VOTE FOR LEADERSHIP + else + AddHtmlLocalized( 20, 60, 380, 20, 1038032, false, false ); // You have already voted in this election. + + for ( int i = 0; i < election.Candidates.Count; ++i ) + { + Candidate cd = election.Candidates[i]; + + if ( canVote ) + AddButton( 20, 100 + (i * 20), 4005, 4007, i + 1, GumpButtonType.Reply, 0 ); + + AddLabel( 55, 100 + (i * 20), 0, cd.Mobile.Name ); + AddLabel( 300, 100 + (i * 20), 0, cd.Votes.ToString() ); + } + + AddButton( 20, 310, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 310, 100, 20, 1011012, false, false ); // CANCEL + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Factions/CouncilOfMages.cs b/Scripts/Engines/Factions/Instances/Factions/CouncilOfMages.cs new file mode 100644 index 0000000..add803d --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Factions/CouncilOfMages.cs @@ -0,0 +1,107 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class CouncilOfMages : Faction + { + private static Faction m_Instance; + + public static Faction Instance{ get{ return m_Instance; } } + + public CouncilOfMages() + { + m_Instance = this; + + Definition = + new FactionDefinition( + 1, + 1325, // blue + 1310, // bluish white + 1325, // join stone : blue + 1325, // broadcast : blue + 0x77, 0x3EB1, // war horse + "Council of Mages", "council", "CoM", + new TextDefinition( 1011535, "COUNCIL OF MAGES" ), + new TextDefinition( 1060770, "Council of Mages faction" ), + new TextDefinition( 1011422, "
COUNCIL OF MAGES
" ), + new TextDefinition( 1011449, + "The council of Mages have their roots in the city of Moonglow, where " + + "they once convened. They began as a small movement, dedicated to " + + "calling forth the Stranger, who saved the lands once before. A " + + "series of war and murders and misbegotten trials by those loyal to " + + "Lord British has caused the group to take up the banner of war." ), + new TextDefinition( 1011455, "This city is controlled by the Council of Mages." ), + new TextDefinition( 1042253, "This sigil has been corrupted by the Council of Mages" ), + new TextDefinition( 1041044, "The faction signup stone for the Council of Mages" ), + new TextDefinition( 1041382, "The Faction Stone of the Council of Mages" ), + new TextDefinition( 1011464, ": Council of Mages" ), + new TextDefinition( 1005187, "Members of the Council of Mages will now be ignored." ), + new TextDefinition( 1005188, "Members of the Council of Mages will now be warned to leave." ), + new TextDefinition( 1005189, "Members of the Council of Mages will now be beaten with a stick." ), + // Moonglow + new StrongholdDefinition( + new Rectangle2D[] + { + new Rectangle2D( 4463, 1487, 15, 35 ), + new Rectangle2D( 4450, 1522, 35, 48 ), + }, + new Point3D( 4469, 1486, 0 ), + new Point3D(4457, 1544, 0), + new Point3D[] + { + new Point3D( 4464, 1534, 21 ), + new Point3D( 4470, 1536, 21 ), + new Point3D( 4468, 1534, 21 ), + new Point3D( 4470, 1534, 21 ), + new Point3D( 4468, 1536, 21 ), + new Point3D( 4466, 1534, 21 ), + new Point3D( 4466, 1536, 21 ), + new Point3D( 4464, 1536, 21 ) + } ), + // Magincia + /* new StrongholdDefinition( + new Rectangle2D[] + { + new Rectangle2D( 3756, 2232, 4, 23 ), + new Rectangle2D( 3760, 2227, 60, 28 ), + new Rectangle2D( 3782, 2219, 18, 8 ), + new Rectangle2D( 3778, 2255, 35, 17 ) + }, + new Point3D( 3750, 2241, 20 ), + new Point3D( 3795, 2259, 20 ), + new Point3D[] + { + new Point3D( 3793, 2255, 20 ), + new Point3D( 3793, 2252, 20 ), + new Point3D( 3793, 2249, 20 ), + new Point3D( 3793, 2246, 20 ), + new Point3D( 3797, 2255, 20 ), + new Point3D( 3797, 2252, 20 ), + new Point3D( 3797, 2249, 20 ), + new Point3D( 3797, 2246, 20 ) + } */ + new RankDefinition[] + { + new RankDefinition( 10, 991, 8, new TextDefinition( 1060789, "Inquisitor of the Council" ) ), + new RankDefinition( 9, 950, 7, new TextDefinition( 1060788, "Archon of Principle" ) ), + new RankDefinition( 8, 900, 6, new TextDefinition( 1060787, "Luminary" ) ), + new RankDefinition( 7, 800, 6, new TextDefinition( 1060787, "Luminary" ) ), + new RankDefinition( 6, 700, 5, new TextDefinition( 1060786, "Diviner" ) ), + new RankDefinition( 5, 600, 5, new TextDefinition( 1060786, "Diviner" ) ), + new RankDefinition( 4, 500, 5, new TextDefinition( 1060786, "Diviner" ) ), + new RankDefinition( 3, 400, 4, new TextDefinition( 1060785, "Mystic" ) ), + new RankDefinition( 2, 200, 4, new TextDefinition( 1060785, "Mystic" ) ), + new RankDefinition( 1, 0, 4, new TextDefinition( 1060785, "Mystic" ) ) + }, + new GuardDefinition[] + { + new GuardDefinition( typeof( FactionHenchman ), 0x1403, 5000, 1000, 10, new TextDefinition( 1011526, "HENCHMAN" ), new TextDefinition( 1011510, "Hire Henchman" ) ), + new GuardDefinition( typeof( FactionMercenary ), 0x0F62, 6000, 2000, 10, new TextDefinition( 1011527, "MERCENARY" ), new TextDefinition( 1011511, "Hire Mercenary" ) ), + new GuardDefinition( typeof( FactionSorceress ), 0x0E89, 7000, 3000, 10, new TextDefinition( 1011507, "SORCERESS" ), new TextDefinition( 1011501, "Hire Sorceress" ) ), + new GuardDefinition( typeof( FactionWizard ), 0x13F8, 8000, 4000, 10, new TextDefinition( 1011508, "ELDER WIZARD" ), new TextDefinition( 1011502, "Hire Elder Wizard" ) ), + } + ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Factions/Minax.cs b/Scripts/Engines/Factions/Instances/Factions/Minax.cs new file mode 100644 index 0000000..b3874b9 --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Factions/Minax.cs @@ -0,0 +1,85 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class Minax : Faction + { + private static Faction m_Instance; + + public static Faction Instance{ get{ return m_Instance; } } + + public Minax() + { + m_Instance = this; + + Definition = + new FactionDefinition( + 0, + 1645, // dark red + 1109, // shadow + 1645, // join stone : dark red + 1645, // broadcast : dark red + 0x78, 0x3EAF, // war horse + "Minax", "minax", "Min", + new TextDefinition( 1011534, "MINAX" ), + new TextDefinition( 1060769, "Minax faction" ), + new TextDefinition( 1011421, "
FOLLOWERS OF MINAX
" ), + new TextDefinition( 1011448, + "The followers of Minax have taken control in the old lands, " + + "and intend to hold it for as long as they can. Allying themselves " + + "with orcs, headless, gazers, trolls, and other beasts, they seek " + + "revenge against Lord British, for slights both real and imagined, " + + "though some of the followers wish only to wreak havoc on the " + + "unsuspecting populace." ), + new TextDefinition( 1011453, "This city is controlled by Minax." ), + new TextDefinition( 1042252, "This sigil has been corrupted by the Followers of Minax" ), + new TextDefinition( 1041043, "The faction signup stone for the Followers of Minax" ), + new TextDefinition( 1041381, "The Faction Stone of Minax" ), + new TextDefinition( 1011463, ": Minax" ), + new TextDefinition( 1005190, "Followers of Minax will now be ignored." ), + new TextDefinition( 1005191, "Followers of Minax will now be told to go away." ), + new TextDefinition( 1005192, "Followers of Minax will now be hanged by their toes." ), + new StrongholdDefinition( + new Rectangle2D[] + { + // Scriptiz : on retire la zone pour �viter qu'elle marche sur la salle 3 n�cro + //new Rectangle2D( 1097, 2570, 70, 50 ) + }, + new Point3D( 1172, 2593, 0 ), + new Point3D( 1117, 2587, 18 ), + new Point3D[] + { + new Point3D( 1113, 2601, 18 ), + new Point3D( 1113, 2598, 18 ), + new Point3D( 1113, 2595, 18 ), + new Point3D( 1113, 2592, 18 ), + new Point3D( 1116, 2601, 18 ), + new Point3D( 1116, 2598, 18 ), + new Point3D( 1116, 2595, 18 ), + new Point3D( 1116, 2592, 18 ) + } ), + new RankDefinition[] + { + new RankDefinition( 10, 991, 8, new TextDefinition( 1060784, "Avenger of Mondain" ) ), + new RankDefinition( 9, 950, 7, new TextDefinition( 1060783, "Dread Knight" ) ), + new RankDefinition( 8, 900, 6, new TextDefinition( 1060782, "Warlord" ) ), + new RankDefinition( 7, 800, 6, new TextDefinition( 1060782, "Warlord" ) ), + new RankDefinition( 6, 700, 5, new TextDefinition( 1060781, "Executioner" ) ), + new RankDefinition( 5, 600, 5, new TextDefinition( 1060781, "Executioner" ) ), + new RankDefinition( 4, 500, 5, new TextDefinition( 1060781, "Executioner" ) ), + new RankDefinition( 3, 400, 4, new TextDefinition( 1060780, "Defiler" ) ), + new RankDefinition( 2, 200, 4, new TextDefinition( 1060780, "Defiler" ) ), + new RankDefinition( 1, 0, 4, new TextDefinition( 1060780, "Defiler" ) ) + }, + new GuardDefinition[] + { + new GuardDefinition( typeof( FactionHenchman ), 0x1403, 5000, 1000, 10, new TextDefinition( 1011526, "HENCHMAN" ), new TextDefinition( 1011510, "Hire Henchman" ) ), + new GuardDefinition( typeof( FactionMercenary ), 0x0F62, 6000, 2000, 10, new TextDefinition( 1011527, "MERCENARY" ), new TextDefinition( 1011511, "Hire Mercenary" ) ), + new GuardDefinition( typeof( FactionBerserker ), 0x0F4B, 7000, 3000, 10, new TextDefinition( 1011505, "BERSERKER" ), new TextDefinition( 1011499, "Hire Berserker" ) ), + new GuardDefinition( typeof( FactionDragoon ), 0x1439, 8000, 4000, 10, new TextDefinition( 1011506, "DRAGOON" ), new TextDefinition( 1011500, "Hire Dragoon" ) ), + } + ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Factions/Shadowlords.cs b/Scripts/Engines/Factions/Instances/Factions/Shadowlords.cs new file mode 100644 index 0000000..ad7bcb6 --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Factions/Shadowlords.cs @@ -0,0 +1,84 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class Shadowlords : Faction + { + private static Faction m_Instance; + + public static Faction Instance{ get{ return m_Instance; } } + + public Shadowlords() + { + m_Instance = this; + + Definition = + new FactionDefinition( + 3, + 1109, // shadow + 2211, // green + 1109, // join stone : shadow + 2211, // broadcast : green + 0x79, 0x3EB0, // war horse + "Shadowlords", "shadow", "SL", + new TextDefinition( 1011537, "SHADOWLORDS" ), + new TextDefinition( 1060772, "Shadowlords faction" ), + new TextDefinition( 1011424, "
SHADES OF DARKNESS
" ), + new TextDefinition( 1011451, + "The Shadow Lords are a faction that has sprung up within the ranks of " + + "Minax. Comprised mostly of undead and those who would seek to be " + + "necromancers, they pose a threat to both the sides of good and evil. " + + "Their plans have disrupted the hold Minax has over Felucca, and their " + + "ultimate goal is to destroy all life." ), + new TextDefinition( 1011456, "This city is controlled by the Shadow Lords." ), + new TextDefinition( 1042255, "This sigil has been corrupted by the Shadowlords" ), + new TextDefinition( 1041046, "The faction signup stone for the Shadowlords" ), + new TextDefinition( 1041384, "The Faction Stone of the Shadowlords" ), + new TextDefinition( 1011466, ": Shadowlords" ), + new TextDefinition( 1005184, "Minions of the Shadowlords will now be ignored." ), + new TextDefinition( 1005185, "Minions of the Shadowlords will now be warned of their impending deaths." ), + new TextDefinition( 1005186, "Minions of the Shadowlords will now be attacked at will." ), + new StrongholdDefinition( + new Rectangle2D[] + { + new Rectangle2D( 960, 688, 8, 9 ), + new Rectangle2D( 944, 697, 24, 23 ) + }, + new Point3D( 969, 768, 0 ), + new Point3D( 947, 713, 0 ), + new Point3D[] + { + new Point3D( 953, 713, 20 ), + new Point3D( 953, 709, 20 ), + new Point3D( 953, 705, 20 ), + new Point3D( 953, 701, 20 ), + new Point3D( 957, 713, 20 ), + new Point3D( 957, 709, 20 ), + new Point3D( 957, 705, 20 ), + new Point3D( 957, 701, 20 ) + } ), + new RankDefinition[] + { + new RankDefinition( 10, 991, 8, new TextDefinition( 1060799, "Purveyor of Darkness" ) ), + new RankDefinition( 9, 950, 7, new TextDefinition( 1060798, "Agent of Evil" ) ), + new RankDefinition( 8, 900, 6, new TextDefinition( 1060797, "Bringer of Sorrow" ) ), + new RankDefinition( 7, 800, 6, new TextDefinition( 1060797, "Bringer of Sorrow" ) ), + new RankDefinition( 6, 700, 5, new TextDefinition( 1060796, "Keeper of Lies" ) ), + new RankDefinition( 5, 600, 5, new TextDefinition( 1060796, "Keeper of Lies" ) ), + new RankDefinition( 4, 500, 5, new TextDefinition( 1060796, "Keeper of Lies" ) ), + new RankDefinition( 3, 400, 4, new TextDefinition( 1060795, "Servant" ) ), + new RankDefinition( 2, 200, 4, new TextDefinition( 1060795, "Servant" ) ), + new RankDefinition( 1, 0, 4, new TextDefinition( 1060795, "Servant" ) ) + }, + new GuardDefinition[] + { + new GuardDefinition( typeof( FactionHenchman ), 0x1403, 5000, 1000, 10, new TextDefinition( 1011526, "HENCHMAN" ), new TextDefinition( 1011510, "Hire Henchman" ) ), + new GuardDefinition( typeof( FactionMercenary ), 0x0F62, 6000, 2000, 10, new TextDefinition( 1011527, "MERCENARY" ), new TextDefinition( 1011511, "Hire Mercenary" ) ), + new GuardDefinition( typeof( FactionDeathKnight ), 0x0F45, 7000, 3000, 10, new TextDefinition( 1011512, "DEATH KNIGHT" ), new TextDefinition( 1011503, "Hire Death Knight" ) ), + new GuardDefinition( typeof( FactionNecromancer ), 0x13F8, 8000, 4000, 10, new TextDefinition( 1011513, "SHADOW MAGE" ), new TextDefinition( 1011504, "Hire Shadow Mage" ) ), + } + ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Factions/TrueBritannians.cs b/Scripts/Engines/Factions/Instances/Factions/TrueBritannians.cs new file mode 100644 index 0000000..a4fa8ff --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Factions/TrueBritannians.cs @@ -0,0 +1,89 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class TrueBritannians : Faction + { + private static Faction m_Instance; + + public static Faction Instance{ get{ return m_Instance; } } + + public TrueBritannians() + { + m_Instance = this; + + Definition = + new FactionDefinition( + 2, + 1254, // dark purple + 2125, // gold + 2214, // join stone : gold + 2125, // broadcast : gold + 0x76, 0x3EB2, // war horse + "True Britannians", "true", "TB", + new TextDefinition( 1011536, "LORD BRITISH" ), + new TextDefinition( 1060771, "True Britannians faction" ), + new TextDefinition( 1011423, "
TRUE BRITANNIANS
" ), + new TextDefinition( 1011450, + "True Britannians are loyal to the throne of Lord British. They refuse " + + "to give up their homelands to the vile Minax, and detest the Shadowlords " + + "for their evil ways. In addition, the Council of Mages threatens the " + + "existence of their ruler, and as such they have armed themselves, and " + + "prepare for war with all." ), + new TextDefinition( 1011454, "This city is controlled by Lord British." ), + new TextDefinition( 1042254, "This sigil has been corrupted by the True Britannians" ), + new TextDefinition( 1041045, "The faction signup stone for the True Britannians" ), + new TextDefinition( 1041383, "The Faction Stone of the True Britannians" ), + new TextDefinition( 1011465, ": True Britannians" ), + new TextDefinition( 1005181, "Followers of Lord British will now be ignored." ), + new TextDefinition( 1005182, "Followers of Lord British will now be warned of their impending doom." ), + new TextDefinition( 1005183, "Followers of Lord British will now be attacked on sight." ), + new StrongholdDefinition( + new Rectangle2D[] + { + new Rectangle2D( 1292, 1556, 25, 25 ), + new Rectangle2D( 1292, 1676, 120, 25 ), + new Rectangle2D( 1388, 1556, 25, 25 ), + new Rectangle2D( 1317, 1563, 71, 18 ), + new Rectangle2D( 1300, 1581, 105, 95 ), + new Rectangle2D( 1405, 1612, 12, 21 ), + new Rectangle2D( 1405, 1633, 11, 5 ) + }, + new Point3D( 1419, 1622, 20 ), + new Point3D( 1330, 1621, 50 ), + new Point3D[] + { + new Point3D( 1328, 1627, 50 ), + new Point3D( 1328, 1621, 50 ), + new Point3D( 1334, 1627, 50 ), + new Point3D( 1334, 1621, 50 ), + new Point3D( 1340, 1627, 50 ), + new Point3D( 1340, 1621, 50 ), + new Point3D( 1345, 1621, 50 ), + new Point3D( 1345, 1627, 50 ) + } ), + new RankDefinition[] + { + new RankDefinition( 10, 991, 8, new TextDefinition( 1060794, "Knight of the Codex" ) ), + new RankDefinition( 9, 950, 7, new TextDefinition( 1060793, "Knight of Virtue" ) ), + new RankDefinition( 8, 900, 6, new TextDefinition( 1060792, "Crusader" ) ), + new RankDefinition( 7, 800, 6, new TextDefinition( 1060792, "Crusader" ) ), + new RankDefinition( 6, 700, 5, new TextDefinition( 1060791, "Sentinel" ) ), + new RankDefinition( 5, 600, 5, new TextDefinition( 1060791, "Sentinel" ) ), + new RankDefinition( 4, 500, 5, new TextDefinition( 1060791, "Sentinel" ) ), + new RankDefinition( 3, 400, 4, new TextDefinition( 1060790, "Defender" ) ), + new RankDefinition( 2, 200, 4, new TextDefinition( 1060790, "Defender" ) ), + new RankDefinition( 1, 0, 4, new TextDefinition( 1060790, "Defender" ) ) + }, + new GuardDefinition[] + { + new GuardDefinition( typeof( FactionHenchman ), 0x1403, 5000, 1000, 10, new TextDefinition( 1011526, "HENCHMAN" ), new TextDefinition( 1011510, "Hire Henchman" ) ), + new GuardDefinition( typeof( FactionMercenary ), 0x0F62, 6000, 2000, 10, new TextDefinition( 1011527, "MERCENARY" ), new TextDefinition( 1011511, "Hire Mercenary" ) ), + new GuardDefinition( typeof( FactionKnight ), 0x0F4D, 7000, 3000, 10, new TextDefinition( 1011528, "KNIGHT" ), new TextDefinition( 1011497, "Hire Knight" ) ), + new GuardDefinition( typeof( FactionPaladin ), 0x143F, 8000, 4000, 10, new TextDefinition( 1011529, "PALADIN" ), new TextDefinition( 1011498, "Hire Paladin" ) ), + } + ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Britain.cs b/Scripts/Engines/Factions/Instances/Towns/Britain.cs new file mode 100644 index 0000000..e113670 --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Britain.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Britain : Town + { + public Britain() + { + Definition = + new TownDefinition( + 0, + 0x1869, + "Britain", + "Britain", + new TextDefinition( 1011433, "BRITAIN" ), + new TextDefinition( 1011561, "TOWN STONE FOR BRITAIN" ), + new TextDefinition( 1041034, "The Faction Sigil Monolith of Britain" ), + new TextDefinition( 1041404, "The Faction Town Sigil Monolith of Britain" ), + new TextDefinition( 1041413, "Faction Town Stone of Britain" ), + new TextDefinition( 1041395, "Faction Town Sigil of Britain" ), + new TextDefinition( 1041386, "Corrupted Faction Town Sigil of Britain" ), + new Point3D( 1592, 1680, 10 ), + new Point3D( 1588, 1676, 10 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Magincia.cs b/Scripts/Engines/Factions/Instances/Towns/Magincia.cs new file mode 100644 index 0000000..31f427b --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Magincia.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Magincia : Town + { + public Magincia() + { + Definition = + new TownDefinition( + 7, + 0x1870, + "Magincia", + "Magincia", + new TextDefinition( 1011440, "MAGINCIA" ), + new TextDefinition( 1011568, "TOWN STONE FOR MAGINCIA" ), + new TextDefinition( 1041041, "The Faction Sigil Monolith of Magincia" ), + new TextDefinition( 1041411, "The Faction Town Sigil Monolith of Magincia" ), + new TextDefinition( 1041420, "Faction Town Stone of Magincia" ), + new TextDefinition( 1041402, "Faction Town Sigil of Magincia" ), + new TextDefinition( 1041393, "Corrupted Faction Town Sigil of Magincia" ), + new Point3D( 3714, 2235, 20 ), + new Point3D( 3712, 2230, 20 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Minoc.cs b/Scripts/Engines/Factions/Instances/Towns/Minoc.cs new file mode 100644 index 0000000..a3f0b1c --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Minoc.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Minoc : Town + { + public Minoc() + { + Definition = + new TownDefinition( + 2, + 0x186B, + "Minoc", + "Minoc", + new TextDefinition( 1011437, "MINOC" ), + new TextDefinition( 1011564, "TOWN STONE FOR MINOC" ), + new TextDefinition( 1041036, "The Faction Sigil Monolith of Minoc" ), + new TextDefinition( 1041406, "The Faction Town Sigil Monolith Minoc" ), + new TextDefinition( 1041415, "Faction Town Stone of Minoc" ), + new TextDefinition( 1041397, "Faction Town Sigil of Minoc" ), + new TextDefinition( 1041388, "Corrupted Faction Town Sigil of Minoc" ), + new Point3D( 2471, 439, 15 ), + new Point3D( 2469, 445, 15 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Moonglow.cs b/Scripts/Engines/Factions/Instances/Towns/Moonglow.cs new file mode 100644 index 0000000..d0f4f18 --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Moonglow.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Moonglow : Town + { + public Moonglow() + { + Definition = + new TownDefinition( + 3, + 0x186C, + "Moonglow", + "Moonglow", + new TextDefinition( 1011435, "MOONGLOW" ), + new TextDefinition( 1011563, "TOWN STONE FOR MOONGLOW" ), + new TextDefinition( 1041037, "The Faction Sigil Monolith of Moonglow" ), + new TextDefinition( 1041407, "The Faction Town Sigil Monolith of Moonglow" ), + new TextDefinition( 1041416, "Faction Town Stone of Moonglow" ), + new TextDefinition( 1041398, "Faction Town Sigil of Moonglow" ), + new TextDefinition( 1041389, "Corrupted Faction Town Sigil of Moonglow" ), + new Point3D( 4436, 1083, 0 ), + new Point3D( 4432, 1086, 0 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/SkaraBrae.cs b/Scripts/Engines/Factions/Instances/Towns/SkaraBrae.cs new file mode 100644 index 0000000..d60584b --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/SkaraBrae.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class SkaraBrae : Town + { + public SkaraBrae() + { + Definition = + new TownDefinition( + 6, + 0x186F, + "Skara Brae", + "Skara Brae", + new TextDefinition( 1011439, "SKARA BRAE" ), + new TextDefinition( 1011567, "TOWN STONE FOR SKARA BRAE" ), + new TextDefinition( 1041040, "The Faction Sigil Monolith of Skara Brae" ), + new TextDefinition( 1041410, "The Faction Town Sigil Monolith of Skara Brae" ), + new TextDefinition( 1041419, "Faction Town Stone of Skara Brae" ), + new TextDefinition( 1041401, "Faction Town Sigil of Skara Brae" ), + new TextDefinition( 1041392, "Corrupted Faction Town Sigil of Skara Brae" ), + new Point3D( 576, 2200, 0 ), + new Point3D( 572, 2196, 0 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Trinsic.cs b/Scripts/Engines/Factions/Instances/Towns/Trinsic.cs new file mode 100644 index 0000000..a411624 --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Trinsic.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Trinsic : Town + { + public Trinsic() + { + Definition = + new TownDefinition( + 1, + 0x186A, + "Trinsic", + "Trinsic", + new TextDefinition( 1011434, "TRINSIC" ), + new TextDefinition( 1011562, "TOWN STONE FOR TRINSIC" ), + new TextDefinition( 1041035, "The Faction Sigil Monolith of Trinsic" ), + new TextDefinition( 1041405, "The Faction Town Sigil Monolith of Trinsic" ), + new TextDefinition( 1041414, "Faction Town Stone of Trinsic" ), + new TextDefinition( 1041396, "Faction Town Sigil of Trinsic" ), + new TextDefinition( 1041387, "Corrupted Faction Town Sigil of Trinsic" ), + new Point3D( 1914, 2717, 20 ), + new Point3D( 1909, 2720, 20 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Vesper.cs b/Scripts/Engines/Factions/Instances/Towns/Vesper.cs new file mode 100644 index 0000000..2530032 --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Vesper.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Vesper : Town + { + public Vesper() + { + Definition = + new TownDefinition( + 5, + 0x186E, + "Vesper", + "Vesper", + new TextDefinition( 1016413, "VESPER" ), + new TextDefinition( 1011566, "TOWN STONE FOR VESPER" ), + new TextDefinition( 1041039, "The Faction Sigil Monolith of Vesper" ), + new TextDefinition( 1041409, "The Faction Town Sigil Monolith of Vesper" ), + new TextDefinition( 1041418, "Faction Town Stone of Vesper" ), + new TextDefinition( 1041400, "Faction Town Sigil of Vesper" ), + new TextDefinition( 1041391, "Corrupted Faction Town Sigil of Vesper" ), + new Point3D( 2982, 818, 0 ), + new Point3D( 2985, 821, 0 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Instances/Towns/Yew.cs b/Scripts/Engines/Factions/Instances/Towns/Yew.cs new file mode 100644 index 0000000..98a269a --- /dev/null +++ b/Scripts/Engines/Factions/Instances/Towns/Yew.cs @@ -0,0 +1,26 @@ +using System; + +namespace Server.Factions +{ + public class Yew : Town + { + public Yew() + { + Definition = + new TownDefinition( + 4, + 0x186D, + "Yew", + "Yew", + new TextDefinition( 1011438, "YEW" ), + new TextDefinition( 1011565, "TOWN STONE FOR YEW" ), + new TextDefinition( 1041038, "The Faction Sigil Monolith of Yew" ), + new TextDefinition( 1041408, "The Faction Town Sigil Monolith of Yew" ), + new TextDefinition( 1041417, "Faction Town Stone of Yew" ), + new TextDefinition( 1041399, "Faction Town Sigil of Yew" ), + new TextDefinition( 1041390, "Corrupted Faction Town Sigil of Yew" ), + new Point3D( 548, 979, 0 ), + new Point3D( 542, 980, 0 ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/BaseMonolith.cs b/Scripts/Engines/Factions/Items/BaseMonolith.cs new file mode 100644 index 0000000..1f55e01 --- /dev/null +++ b/Scripts/Engines/Factions/Items/BaseMonolith.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; + +namespace Server.Factions +{ + public abstract class BaseMonolith : BaseSystemController + { + private Town m_Town; + private Faction m_Faction; + private Sigil m_Sigil; + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Sigil Sigil + { + get{ return m_Sigil; } + set + { + if ( m_Sigil == value ) + return; + + m_Sigil = value; + + if ( m_Sigil != null && m_Sigil.LastMonolith != null && m_Sigil.LastMonolith != this && m_Sigil.LastMonolith.Sigil == m_Sigil ) + m_Sigil.LastMonolith.Sigil = null; + + if ( m_Sigil != null ) + m_Sigil.LastMonolith = this; + + UpdateSigil(); + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Town Town + { + get{ return m_Town; } + set + { + m_Town = value; + OnTownChanged(); + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Faction Faction + { + get{ return m_Faction; } + set + { + m_Faction = value; + Hue = ( m_Faction == null ? 0 : m_Faction.Definition.HuePrimary ); + } + } + + public override void OnLocationChange( Point3D oldLocation ) + { + base.OnLocationChange( oldLocation ); + UpdateSigil(); + } + + public override void OnMapChange() + { + base.OnMapChange(); + UpdateSigil(); + } + + public virtual void UpdateSigil() + { + if ( m_Sigil == null || m_Sigil.Deleted ) + return; + + m_Sigil.MoveToWorld( new Point3D( X, Y, Z + 18 ), Map ); + } + + public virtual void OnTownChanged() + { + } + + public BaseMonolith( Town town, Faction faction ) : base( 0x1183 ) + { + Movable = false; + Town = town; + Faction = faction; + m_Monoliths.Add( this ); + } + + public BaseMonolith( Serial serial ) : base( serial ) + { + m_Monoliths.Add( this ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + m_Monoliths.Remove( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Town.WriteReference( writer, m_Town ); + Faction.WriteReference( writer, m_Faction ); + + writer.Write( (Item) m_Sigil ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Town = Town.ReadReference( reader ); + Faction = Faction.ReadReference( reader ); + m_Sigil = reader.ReadItem() as Sigil; + break; + } + } + } + + private static List m_Monoliths = new List(); + + public static List Monoliths + { + get{ return m_Monoliths; } + set{ m_Monoliths = value; } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/BaseSystemController.cs b/Scripts/Engines/Factions/Items/BaseSystemController.cs new file mode 100644 index 0000000..cc17ae8 --- /dev/null +++ b/Scripts/Engines/Factions/Items/BaseSystemController.cs @@ -0,0 +1,66 @@ +using System; + +namespace Server.Factions +{ + public abstract class BaseSystemController : Item + { + private int m_LabelNumber; + + public virtual int DefaultLabelNumber{ get{ return base.LabelNumber; } } + public new virtual string DefaultName{ get{ return null; } } + + public override int LabelNumber + { + get + { + if ( m_LabelNumber > 0 ) + return m_LabelNumber; + + return DefaultLabelNumber; + } + } + + public virtual void AssignName( TextDefinition name ) + { + if ( name != null && name.Number > 0 ) + { + m_LabelNumber = name.Number; + Name = null; + } + else if ( name != null && name.String != null ) + { + m_LabelNumber = 0; + Name = name.String; + } + else + { + m_LabelNumber = 0; + Name = DefaultName; + } + + InvalidateProperties(); + } + + public BaseSystemController( int itemID ) : base( itemID ) + { + } + + public BaseSystemController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/FactionStone.cs b/Scripts/Engines/Factions/Items/FactionStone.cs new file mode 100644 index 0000000..ae829cf --- /dev/null +++ b/Scripts/Engines/Factions/Items/FactionStone.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class FactionStone : BaseSystemController + { + private Faction m_Faction; + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Faction Faction + { + get{ return m_Faction; } + set + { + m_Faction = value; + + AssignName( m_Faction == null ? null : m_Faction.Definition.FactionStoneName ); + } + } + + public override string DefaultName { get { return "faction stone"; } } + + [Constructable] + public FactionStone() : this( null ) + { + } + + [Constructable] + public FactionStone( Faction faction ) : base( 0xEDC ) + { + Movable = false; + Faction = faction; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Faction == null ) + return; + + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + else if ( FactionGump.Exists( from ) ) + { + from.SendLocalizedMessage( 1042160 ); // You already have a faction menu open. + } + else if ( from is PlayerMobile ) + { + Faction existingFaction = Faction.Find( from ); + + if ( existingFaction == m_Faction || from.AccessLevel >= AccessLevel.GameMaster ) + { + PlayerState pl = PlayerState.Find( from ); + + if ( pl != null && pl.IsLeaving ) + from.SendLocalizedMessage( 1005051 ); // You cannot use the faction stone until you have finished quitting your current faction + else + from.SendGump( new FactionStoneGump( (PlayerMobile) from, m_Faction ) ); + } + else if ( existingFaction != null ) + { + // TODO: Validate + from.SendLocalizedMessage( 1005053 ); // This is not your faction stone! + } + else + { + from.SendGump( new JoinStoneGump( (PlayerMobile) from, m_Faction ) ); + } + } + } + + public FactionStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Faction = Faction.ReadReference( reader ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/JoinStone.cs b/Scripts/Engines/Factions/Items/JoinStone.cs new file mode 100644 index 0000000..99138bf --- /dev/null +++ b/Scripts/Engines/Factions/Items/JoinStone.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class JoinStone : BaseSystemController + { + private Faction m_Faction; + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Faction Faction + { + get{ return m_Faction; } + set + { + m_Faction = value; + + Hue = ( m_Faction == null ? 0 : m_Faction.Definition.HueJoin ); + AssignName( m_Faction == null ? null : m_Faction.Definition.SignupName ); + } + } + + public override string DefaultName { get { return "faction signup stone"; } } + + [Constructable] + public JoinStone() : this( null ) + { + } + + [Constructable] + public JoinStone( Faction faction ) : base( 0xEDC ) + { + Movable = false; + Faction = faction; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Faction == null ) + return; + + if ( !from.InRange( GetWorldLocation(), 2 ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( FactionGump.Exists( from ) ) + from.SendLocalizedMessage( 1042160 ); // You already have a faction menu open. + else if ( Faction.Find( from ) == null && from is PlayerMobile ) + from.SendGump( new JoinStoneGump( (PlayerMobile) from, m_Faction ) ); + } + + public JoinStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Faction = Faction.ReadReference( reader ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Sigil.cs b/Scripts/Engines/Factions/Items/Sigil.cs new file mode 100644 index 0000000..3baf5b7 --- /dev/null +++ b/Scripts/Engines/Factions/Items/Sigil.cs @@ -0,0 +1,471 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class Sigil : BaseSystemController + { + public const int OwnershipHue = 0xB; + + // ?? time corrupting faction has to return the sigil before corruption time resets ? + public static readonly TimeSpan CorruptionGrace = TimeSpan.FromMinutes( (Core.SE) ? 30.0 : 15.0 ); + + // Sigil must be held at a stronghold for this amount of time in order to become corrupted + public static readonly TimeSpan CorruptionPeriod = ( (Core.SE) ? TimeSpan.FromHours( 10.0 ) : TimeSpan.FromHours( 24.0 ) ); + + // After a sigil has been corrupted it must be returned to the town within this period of time + public static readonly TimeSpan ReturnPeriod = TimeSpan.FromHours( 1.0 ); + + // Once it's been returned the corrupting faction owns the town for this period of time + public static readonly TimeSpan PurificationPeriod = TimeSpan.FromDays( 3.0 ); + + private BaseMonolith m_LastMonolith; + + private Town m_Town; + private Faction m_Corrupted; + private Faction m_Corrupting; + + private DateTime m_LastStolen; + private DateTime m_GraceStart; + private DateTime m_CorruptionStart; + private DateTime m_PurificationStart; + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public DateTime LastStolen + { + get{ return m_LastStolen; } + set{ m_LastStolen = value; } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public DateTime GraceStart + { + get{ return m_GraceStart; } + set{ m_GraceStart = value; } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public DateTime CorruptionStart + { + get{ return m_CorruptionStart; } + set{ m_CorruptionStart = value; } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public DateTime PurificationStart + { + get{ return m_PurificationStart; } + set{ m_PurificationStart = value; } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Town Town + { + get{ return m_Town; } + set{ m_Town = value; Update(); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Faction Corrupted + { + get{ return m_Corrupted; } + set{ m_Corrupted = value; Update(); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Faction Corrupting + { + get{ return m_Corrupting; } + set{ m_Corrupting = value; Update(); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public BaseMonolith LastMonolith + { + get{ return m_LastMonolith; } + set{ m_LastMonolith = value; } + } + + [CommandProperty( AccessLevel.Counselor )] + public bool IsBeingCorrupted + { + get{ return ( m_LastMonolith is StrongholdMonolith && m_LastMonolith.Faction == m_Corrupting && m_Corrupting != null ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public bool IsCorrupted + { + get{ return ( m_Corrupted != null ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public bool IsPurifying + { + get{ return ( m_PurificationStart != DateTime.MinValue ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public bool IsCorrupting + { + get{ return ( m_Corrupting != null && m_Corrupting != m_Corrupted ); } + } + + public void Update() + { + ItemID = ( m_Town == null ? 0x1869 : m_Town.Definition.SigilID ); + + if ( m_Town == null ) + AssignName( null ); + else if ( IsCorrupted || IsPurifying ) + AssignName( m_Town.Definition.CorruptedSigilName ); + else + AssignName( m_Town.Definition.SigilName ); + + InvalidateProperties(); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( IsCorrupted ) + TextDefinition.AddTo( list, m_Corrupted.Definition.SigilControl ); + else + list.Add( 1042256 ); // This sigil is not corrupted. + + if ( IsCorrupting ) + list.Add( 1042257 ); // This sigil is in the process of being corrupted. + else if ( IsPurifying ) + list.Add( 1042258 ); // This sigil has recently been corrupted, and is undergoing purification. + else + list.Add( 1042259 ); // This sigil is not in the process of being corrupted. + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsCorrupted ) + { + if ( m_Corrupted.Definition.SigilControl.Number > 0 ) + LabelTo( from, m_Corrupted.Definition.SigilControl.Number ); + else if ( m_Corrupted.Definition.SigilControl.String != null ) + LabelTo( from, m_Corrupted.Definition.SigilControl.String ); + } + else + { + LabelTo( from, 1042256 ); // This sigil is not corrupted. + } + + if ( IsCorrupting ) + LabelTo( from, 1042257 ); // This sigil is in the process of being corrupted. + else if ( IsPurifying ) + LabelTo( from, 1042258 ); // This sigil has been recently corrupted, and is undergoing purification. + else + LabelTo( from, 1042259 ); // This sigil is not in the process of being corrupted. + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + from.SendLocalizedMessage( 1005225 ); // You must use the stealing skill to pick up the sigil + return false; + } + + private Mobile FindOwner( object parent ) + { + if ( parent is Item ) + return ((Item)parent).RootParent as Mobile; + + if ( parent is Mobile ) + return (Mobile) parent; + + return null; + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + Mobile mob = FindOwner( parent ); + + if ( mob != null ) + mob.SolidHueOverride = OwnershipHue; + } + + public override void OnRemoved( object parent ) + { + base.OnRemoved( parent ); + + Mobile mob = FindOwner( parent ); + + if ( mob != null ) + mob.SolidHueOverride = -1; + } + + public Sigil( Town town ) : base( 0x1869 ) + { + Movable = false; + Town = town; + + m_Sigils.Add( this ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.BeginTarget( 1, false, Targeting.TargetFlags.None, new TargetCallback( Sigil_OnTarget ) ); + from.SendLocalizedMessage( 1042251 ); // Click on a sigil monolith or player + } + } + + public static bool ExistsOn( Mobile mob ) + { + Container pack = mob.Backpack; + + return ( pack != null && pack.FindItemByType( typeof( Sigil ) ) != null ); + } + + private void BeginCorrupting( Faction faction ) + { + m_Corrupting = faction; + m_CorruptionStart = DateTime.Now; + } + + private void ClearCorrupting() + { + m_Corrupting = null; + m_CorruptionStart = DateTime.MinValue; + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan TimeUntilCorruption + { + get + { + if ( !IsBeingCorrupted ) + return TimeSpan.Zero; + + TimeSpan ts = ( m_CorruptionStart + CorruptionPeriod ) - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + return ts; + } + } + + private void Sigil_OnTarget( Mobile from, object obj ) + { + if ( Deleted || !IsChildOf( from.Backpack ) ) + return; + + #region Give To Mobile + if ( obj is Mobile ) + { + if ( obj is PlayerMobile ) + { + PlayerMobile targ = (PlayerMobile)obj; + + Faction toFaction = Faction.Find( targ ); + Faction fromFaction = Faction.Find( from ); + + if ( toFaction == null ) + from.SendLocalizedMessage( 1005223 ); // You cannot give the sigil to someone not in a faction + else if ( fromFaction != toFaction ) + from.SendLocalizedMessage( 1005222 ); // You cannot give the sigil to someone not in your faction + else if ( Sigil.ExistsOn( targ ) ) + from.SendLocalizedMessage( 1005220 ); // You cannot give this sigil to someone who already has a sigil + else if( !targ.Alive ) + from.SendLocalizedMessage( 1042248 ); // You cannot give a sigil to a dead person. + else if ( from.NetState != null && targ.NetState != null ) + { + Container pack = targ.Backpack; + + if ( pack != null ) + pack.DropItem( this ); + } + } + else + { + from.SendLocalizedMessage( 1005221 ); //You cannot give the sigil to them + } + } + #endregion + else if ( obj is BaseMonolith ) + { + #region Put in Stronghold + if ( obj is StrongholdMonolith ) + { + StrongholdMonolith m = (StrongholdMonolith)obj; + + if ( m.Faction == null || m.Faction != Faction.Find( from ) ) + from.SendLocalizedMessage( 1042246 ); // You can't place that on an enemy monolith + else if ( m.Town == null || m.Town != m_Town ) + from.SendLocalizedMessage( 1042247 ); // That is not the correct faction monolith + else + { + m.Sigil = this; + + Faction newController = m.Faction; + Faction oldController = m_Corrupting; + + if ( oldController == null ) + { + if ( m_Corrupted != newController ) + BeginCorrupting( newController ); + } + else if ( m_GraceStart > DateTime.MinValue && (m_GraceStart + CorruptionGrace) < DateTime.Now ) + { + if ( m_Corrupted != newController ) + BeginCorrupting( newController ); // grace time over, reset period + else + ClearCorrupting(); + + m_GraceStart = DateTime.MinValue; + } + else if ( newController == oldController ) + { + m_GraceStart = DateTime.MinValue; // returned within grace period + } + else if ( m_GraceStart == DateTime.MinValue ) + { + m_GraceStart = DateTime.Now; + } + + m_PurificationStart = DateTime.MinValue; + } + } + #endregion + + #region Put in Town + else if ( obj is TownMonolith ) + { + TownMonolith m = (TownMonolith)obj; + + if ( m.Town == null || m.Town != m_Town ) + from.SendLocalizedMessage( 1042245 ); // This is not the correct town sigil monolith + else if ( m_Corrupted == null || m_Corrupted != Faction.Find( from ) ) + from.SendLocalizedMessage( 1042244 ); // Your faction did not corrupt this sigil. Take it to your stronghold. + else + { + m.Sigil = this; + + m_Corrupting = null; + m_PurificationStart = DateTime.Now; + m_CorruptionStart = DateTime.MinValue; + + m_Town.Capture( m_Corrupted ); + m_Corrupted = null; + } + } + #endregion + } + else + { + from.SendLocalizedMessage( 1005224 ); // You can't use the sigil on that + } + + Update(); + } + + public Sigil( Serial serial ) : base( serial ) + { + m_Sigils.Add( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Town.WriteReference( writer, m_Town ); + Faction.WriteReference( writer, m_Corrupted ); + Faction.WriteReference( writer, m_Corrupting ); + + writer.Write( (Item) m_LastMonolith ); + + writer.Write( m_LastStolen ); + writer.Write( m_GraceStart ); + writer.Write( m_CorruptionStart ); + writer.Write( m_PurificationStart ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Town = Town.ReadReference( reader ); + m_Corrupted = Faction.ReadReference( reader ); + m_Corrupting = Faction.ReadReference( reader ); + + m_LastMonolith = reader.ReadItem() as BaseMonolith; + + m_LastStolen = reader.ReadDateTime(); + m_GraceStart = reader.ReadDateTime(); + m_CorruptionStart = reader.ReadDateTime(); + m_PurificationStart = reader.ReadDateTime(); + + Update(); + + Mobile mob = RootParent as Mobile; + + if ( mob != null ) + mob.SolidHueOverride = OwnershipHue; + + break; + } + } + } + + public bool ReturnHome() + { + BaseMonolith monolith = m_LastMonolith; + + if ( monolith == null && m_Town != null ) + monolith = m_Town.Monolith; + + if ( monolith != null && !monolith.Deleted ) + monolith.Sigil = this; + + return ( monolith != null && !monolith.Deleted ); + } + + public override void OnParentDeleted( object parent ) + { + base.OnParentDeleted( parent ); + + ReturnHome(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Sigils.Remove( this ); + } + + public override void Delete() + { + if ( ReturnHome() ) + return; + + base.Delete(); + } + + private static List m_Sigils = new List(); + + public static List Sigils{ get{ return m_Sigils; } } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Silver.cs b/Scripts/Engines/Factions/Items/Silver.cs new file mode 100644 index 0000000..2d28ca7 --- /dev/null +++ b/Scripts/Engines/Factions/Items/Silver.cs @@ -0,0 +1,58 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class Silver : Item + { + public override double DefaultWeight + { + get { return 0.02; } + } + + [Constructable] + public Silver() : this( 1 ) + { + } + + [Constructable] + public Silver( int amountFrom, int amountTo ) : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Silver( int amount ) : base( 0xEF0 ) + { + Stackable = true; + Amount = amount; + } + + public Silver( Serial serial ) : base( serial ) + { + } + + public override int GetDropSound() + { + if ( Amount <= 1 ) + return 0x2E4; + else if ( Amount <= 5 ) + return 0x2E5; + else + return 0x2E6; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/StrongholdMonolith.cs b/Scripts/Engines/Factions/Items/StrongholdMonolith.cs new file mode 100644 index 0000000..6467d58 --- /dev/null +++ b/Scripts/Engines/Factions/Items/StrongholdMonolith.cs @@ -0,0 +1,40 @@ +using System; + +namespace Server.Factions +{ + public class StrongholdMonolith : BaseMonolith + { + public override int DefaultLabelNumber{ get{ return 1041042; } } // A Faction Sigil Monolith + + public override void OnTownChanged() + { + AssignName( Town == null ? null : Town.Definition.StrongholdMonolithName ); + } + + public StrongholdMonolith() : this( null, null ) + { + } + + public StrongholdMonolith( Town town, Faction faction ) : base( town, faction ) + { + } + + public StrongholdMonolith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/TownMonolith.cs b/Scripts/Engines/Factions/Items/TownMonolith.cs new file mode 100644 index 0000000..d98baa0 --- /dev/null +++ b/Scripts/Engines/Factions/Items/TownMonolith.cs @@ -0,0 +1,40 @@ +using System; + +namespace Server.Factions +{ + public class TownMonolith : BaseMonolith + { + public override int DefaultLabelNumber{ get{ return 1041403; } } // A Faction Town Sigil Monolith + + public override void OnTownChanged() + { + AssignName( Town == null ? null : Town.Definition.TownMonolithName ); + } + + public TownMonolith() : this( null ) + { + } + + public TownMonolith( Town town ) : base( town, null ) + { + } + + public TownMonolith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/TownStone.cs b/Scripts/Engines/Factions/Items/TownStone.cs new file mode 100644 index 0000000..e32ef44 --- /dev/null +++ b/Scripts/Engines/Factions/Items/TownStone.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Factions +{ + public class TownStone : BaseSystemController + { + private Town m_Town; + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Town Town + { + get{ return m_Town; } + set + { + m_Town = value; + + AssignName( m_Town == null ? null : m_Town.Definition.TownStoneName ); + } + } + + public override string DefaultName { get { return "faction town stone"; } } + + [Constructable] + public TownStone() : this( null ) + { + } + + [Constructable] + public TownStone( Town town ) : base( 0xEDE ) + { + Movable = false; + Town = town; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Town == null ) + return; + + Faction faction = Faction.Find( from ); + + if ( faction == null && from.AccessLevel < AccessLevel.GameMaster ) + return; // TODO: Message? + + if ( m_Town.Owner == null || ( from.AccessLevel < AccessLevel.GameMaster && faction != m_Town.Owner ) ) + from.SendLocalizedMessage( 1010332 ); // Your faction does not control this town + else if ( !m_Town.Owner.IsCommander( from ) ) + from.SendLocalizedMessage( 1005242 ); // Only faction Leaders can use townstones + else if ( FactionGump.Exists( from ) ) + from.SendLocalizedMessage( 1042160 ); // You already have a faction menu open. + else if ( from is PlayerMobile ) + from.SendGump( new TownStoneGump( (PlayerMobile)from, m_Town.Owner, m_Town ) ); + } + + public TownStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Town.WriteReference( writer, m_Town ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Town = Town.ReadReference( reader ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs b/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs new file mode 100644 index 0000000..d0b105e --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/BaseFactionTrap.cs @@ -0,0 +1,294 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Regions; + +namespace Server.Factions +{ + public enum AllowedPlacing + { + Everywhere, + + AnyFactionTown, + ControlledFactionTown, + FactionStronghold + } + + public abstract class BaseFactionTrap : BaseTrap + { + private Faction m_Faction; + private Mobile m_Placer; + private DateTime m_TimeOfPlacement; + + private Timer m_Concealing; + + [CommandProperty( AccessLevel.GameMaster )] + public Faction Faction + { + get{ return m_Faction; } + set{ m_Faction = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Placer + { + get{ return m_Placer; } + set{ m_Placer = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime TimeOfPlacement + { + get{ return m_TimeOfPlacement; } + set{ m_TimeOfPlacement = value; } + } + + public virtual int EffectSound{ get{ return 0; } } + + public virtual int SilverFromDisarm{ get{ return 100; } } + + public virtual int MessageHue{ get{ return 0; } } + + public virtual int AttackMessage{ get{ return 0; } } + public virtual int DisarmMessage{ get{ return 0; } } + + public virtual AllowedPlacing AllowedPlacing{ get{ return AllowedPlacing.Everywhere; } } + + public virtual TimeSpan ConcealPeriod + { + get{ return TimeSpan.FromMinutes( 1.0 ); } + } + + public virtual TimeSpan DecayPeriod + { + get + { + if ( Core.AOS ) + return TimeSpan.FromDays( 1.0 ); + + return TimeSpan.MaxValue; // no decay + } + } + + public override void OnTrigger( Mobile from ) + { + if ( !IsEnemy( from ) ) + return; + + Conceal(); + + DoVisibleEffect(); + Effects.PlaySound( this.Location, this.Map, this.EffectSound ); + DoAttackEffect( from ); + + int silverToAward = ( from.Alive ? 20 : 40 ); + + if ( silverToAward > 0 && m_Placer != null && m_Faction != null ) + { + PlayerState victimState = PlayerState.Find( from ); + + if ( victimState != null && victimState.CanGiveSilverTo( m_Placer ) && victimState.KillPoints > 0 ) + { + int silverGiven = m_Faction.AwardSilver( m_Placer, silverToAward ); + + if ( silverGiven > 0 ) + { + // TODO: Get real message + if ( from.Alive ) + m_Placer.SendMessage( "You have earned {0} silver pieces because {1} fell for your trap.", silverGiven, from.Name ); + else + m_Placer.SendLocalizedMessage( 1042736, String.Format( "{0} silver\t{1}", silverGiven, from.Name ) ); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~! + } + + victimState.OnGivenSilverTo( m_Placer ); + } + } + + from.LocalOverheadMessage( MessageType.Regular, MessageHue, AttackMessage ); + } + + public abstract void DoVisibleEffect(); + public abstract void DoAttackEffect( Mobile m ); + + public virtual int IsValidLocation() + { + return IsValidLocation( GetWorldLocation(), Map ); + } + + public virtual int IsValidLocation( Point3D p, Map m ) + { + if( m == null ) + return 502956; // You cannot place a trap on that. + + if( Core.ML ) + { + foreach( Item item in m.GetItemsInRange( p, 0 ) ) + { + if( item is BaseFactionTrap && ((BaseFactionTrap)item).Faction == this.Faction ) + return 1075263; // There is already a trap belonging to your faction at this location.; + } + } + + switch( AllowedPlacing ) + { + case AllowedPlacing.FactionStronghold: + { + StrongholdRegion region = (StrongholdRegion) Region.Find( p, m ).GetRegion( typeof( StrongholdRegion ) ); + + if ( region != null && region.Faction == m_Faction ) + return 0; + + return 1010355; // This trap can only be placed in your stronghold + } + case AllowedPlacing.AnyFactionTown: + { + Town town = Town.FromRegion( Region.Find( p, m ) ); + + if ( town != null ) + return 0; + + return 1010356; // This trap can only be placed in a faction town + } + case AllowedPlacing.ControlledFactionTown: + { + Town town = Town.FromRegion( Region.Find( p, m ) ); + + if ( town != null && town.Owner == m_Faction ) + return 0; + + return 1010357; // This trap can only be placed in a town your faction controls + } + } + + return 0; + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( !CheckDecay() && CheckRange( m.Location, oldLocation, 6 ) ) + { + if ( Faction.Find( m ) != null && ((m.Skills[SkillName.DetectHidden].Value - 80.0) / 20.0) > Utility.RandomDouble() ) + PrivateOverheadLocalizedMessage( m, 1010154, MessageHue, "", "" ); // [Faction Trap] + } + } + + public void PrivateOverheadLocalizedMessage( Mobile to, int number, int hue, string name, string args ) + { + if ( to == null ) + return; + + NetState ns = to.NetState; + + if ( ns != null ) + ns.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, hue, 3, number, name, args ) ); + } + + public BaseFactionTrap( Faction f, Mobile m, int itemID ) : base( itemID ) + { + Visible = false; + + m_Faction = f; + m_TimeOfPlacement = DateTime.Now; + m_Placer = m; + } + + public BaseFactionTrap( Serial serial ) : base( serial ) + { + } + + public virtual bool CheckDecay() + { + TimeSpan decayPeriod = DecayPeriod; + + if ( decayPeriod == TimeSpan.MaxValue ) + return false; + + if ( (m_TimeOfPlacement + decayPeriod) < DateTime.Now ) + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Delete ) ); + return true; + } + + return false; + } + + public virtual void BeginConceal() + { + if ( m_Concealing != null ) + m_Concealing.Stop(); + + m_Concealing = Timer.DelayCall( ConcealPeriod, new TimerCallback( Conceal ) ); + } + + public virtual void Conceal() + { + if ( m_Concealing != null ) + m_Concealing.Stop(); + + m_Concealing = null; + + if ( !Deleted ) + Visible = false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + writer.Write( (Mobile) m_Placer ); + writer.Write( (DateTime) m_TimeOfPlacement ); + + if ( Visible ) + BeginConceal(); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Faction = Faction.ReadReference( reader ); + m_Placer = reader.ReadMobile(); + m_TimeOfPlacement = reader.ReadDateTime(); + + if ( Visible ) + BeginConceal(); + + CheckDecay(); + } + + public override void OnDelete() + { + if ( m_Faction != null && m_Faction.Traps.Contains( this ) ) + m_Faction.Traps.Remove( this ); + + base.OnDelete(); + } + + public virtual bool IsEnemy( Mobile mob ) + { + if ( mob.Hidden && mob.AccessLevel > AccessLevel.Player ) + return false; + + if ( !mob.Alive || mob.IsDeadBondedPet ) + return false; + + Faction faction = Faction.Find( mob, true ); + + if ( faction == null && mob is BaseFactionGuard ) + faction = ((BaseFactionGuard)mob).Faction; + + if ( faction == null ) + return false; + + return ( faction != m_Faction ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/BaseFactionTrapDeed.cs b/Scripts/Engines/Factions/Items/Traps/BaseFactionTrapDeed.cs new file mode 100644 index 0000000..ad18d0b --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/BaseFactionTrapDeed.cs @@ -0,0 +1,112 @@ +using System; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; +using Server; +using Server.Engines.Craft; + +namespace Server.Factions +{ + public abstract class BaseFactionTrapDeed : Item, ICraftable + { + public abstract Type TrapType{ get; } + + private Faction m_Faction; + + [CommandProperty( AccessLevel.GameMaster )] + public Faction Faction + { + get{ return m_Faction; } + set + { + m_Faction = value; + + if ( m_Faction != null ) + Hue = m_Faction.Definition.HuePrimary; + } + } + + public BaseFactionTrapDeed( int itemID ) : base( itemID ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public BaseFactionTrapDeed( bool createdFromDeed ) : this( 0x14F0 ) + { + } + + public BaseFactionTrapDeed( Serial serial ) : base( serial ) + { + } + + public virtual BaseFactionTrap Construct( Mobile from ) + { + try{ return Activator.CreateInstance( TrapType, new object[]{ m_Faction, from } ) as BaseFactionTrap; } + catch{ return null; } + } + + public override void OnDoubleClick( Mobile from ) + { + Faction faction = Faction.Find( from ); + + if ( faction == null ) + from.SendLocalizedMessage( 1010353, "", 0x23 ); // Only faction members may place faction traps + else if ( faction != m_Faction ) + from.SendLocalizedMessage( 1010354, "", 0x23 ); // You may only place faction traps created by your faction + else if( faction.Traps.Count >= faction.MaximumTraps ) + from.SendLocalizedMessage( 1010358, "", 0x23 ); // Your faction already has the maximum number of traps placed + else + { + BaseFactionTrap trap = Construct( from ); + + if ( trap == null ) + return; + + int message = trap.IsValidLocation( from.Location, from.Map ); + + if ( message > 0 ) + { + from.SendLocalizedMessage( message, "", 0x23 ); + trap.Delete(); + } + else + { + from.SendLocalizedMessage( 1010360 ); // You arm the trap and carefully hide it from view + trap.MoveToWorld( from.Location, from.Map ); + faction.Traps.Add( trap ); + Delete(); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Faction = Faction.ReadReference( reader ); + } + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + ItemID = 0x14F0; + Faction = Faction.Find( from ); + + return 1; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs b/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs new file mode 100644 index 0000000..0a1012a --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/FactionExplosionTrap.cs @@ -0,0 +1,85 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class FactionExplosionTrap : BaseFactionTrap + { + public override int LabelNumber{ get{ return 1044599; } } // faction explosion trap + + public override int AttackMessage{ get{ return 1010543; } } // You are enveloped in an explosion of fire! + public override int DisarmMessage{ get{ return 1010539; } } // You carefully remove the pressure trigger and disable the trap. + public override int EffectSound{ get{ return 0x307; } } + public override int MessageHue{ get{ return 0x78; } } + + public override AllowedPlacing AllowedPlacing{ get{ return AllowedPlacing.AnyFactionTown; } } + + public override void DoVisibleEffect() + { + Effects.SendLocationEffect( GetWorldLocation(), Map, 0x36BD, 15, 10 ); + } + + public override void DoAttackEffect( Mobile m ) + { + m.Damage( Utility.Dice( 6, 10, 40 ), m ); + } + + [Constructable] + public FactionExplosionTrap() : this( null ) + { + } + + public FactionExplosionTrap( Faction f ) : this( f, null ) + { + } + + public FactionExplosionTrap( Faction f, Mobile m ) : base( f, m, 0x11C1 ) + { + } + + public FactionExplosionTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FactionExplosionTrapDeed : BaseFactionTrapDeed + { + public override Type TrapType{ get{ return typeof( FactionExplosionTrap ); } } + public override int LabelNumber{ get{ return 1044603; } } // faction explosion trap deed + + public FactionExplosionTrapDeed() : base( 0x36D2 ) + { + } + + public FactionExplosionTrapDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/FactionGasTrap.cs b/Scripts/Engines/Factions/Items/Traps/FactionGasTrap.cs new file mode 100644 index 0000000..48e7e8a --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/FactionGasTrap.cs @@ -0,0 +1,85 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class FactionGasTrap : BaseFactionTrap + { + public override int LabelNumber{ get{ return 1044598; } } // faction gas trap + + public override int AttackMessage{ get{ return 1010542; } } // A noxious green cloud of poison gas envelops you! + public override int DisarmMessage{ get{ return 502376; } } // The poison leaks harmlessly away due to your deft touch. + public override int EffectSound{ get{ return 0x230; } } + public override int MessageHue{ get{ return 0x44; } } + + public override AllowedPlacing AllowedPlacing{ get{ return AllowedPlacing.FactionStronghold; } } + + public override void DoVisibleEffect() + { + Effects.SendLocationEffect( this.Location, this.Map, 0x3709, 28, 10, 0x1D3, 5 ); + } + + public override void DoAttackEffect( Mobile m ) + { + m.ApplyPoison( m, Poison.Lethal ); + } + + [Constructable] + public FactionGasTrap() : this( null ) + { + } + + public FactionGasTrap( Faction f ) : this( f, null ) + { + } + + public FactionGasTrap( Faction f, Mobile m ) : base( f, m, 0x113C ) + { + } + + public FactionGasTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FactionGasTrapDeed : BaseFactionTrapDeed + { + public override Type TrapType{ get{ return typeof( FactionGasTrap ); } } + public override int LabelNumber{ get{ return 1044602; } } // faction gas trap deed + + public FactionGasTrapDeed() : base( 0x11AB ) + { + } + + public FactionGasTrapDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs b/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs new file mode 100644 index 0000000..73d3a1f --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/FactionSawTrap.cs @@ -0,0 +1,85 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class FactionSawTrap : BaseFactionTrap + { + public override int LabelNumber{ get{ return 1041047; } } // faction saw trap + + public override int AttackMessage{ get{ return 1010544; } } // The blade cuts deep into your skin! + public override int DisarmMessage{ get{ return 1010540; } } // You carefully dismantle the saw mechanism and disable the trap. + public override int EffectSound{ get{ return 0x218; } } + public override int MessageHue{ get{ return 0x5A; } } + + public override AllowedPlacing AllowedPlacing{ get{ return AllowedPlacing.ControlledFactionTown; } } + + public override void DoVisibleEffect() + { + Effects.SendLocationEffect( this.Location, this.Map, 0x11AD, 25, 10 ); + } + + public override void DoAttackEffect( Mobile m ) + { + m.Damage( Utility.Dice( 6, 10, 40 ), m ); + } + + [Constructable] + public FactionSawTrap() : this( null ) + { + } + + public FactionSawTrap( Serial serial ) : base( serial ) + { + } + + public FactionSawTrap( Faction f ) : this( f, null ) + { + } + + public FactionSawTrap( Faction f, Mobile m ) : base( f, m, 0x11AC ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FactionSawTrapDeed : BaseFactionTrapDeed + { + public override Type TrapType{ get{ return typeof( FactionSawTrap ); } } + public override int LabelNumber{ get{ return 1044604; } } // faction saw trap deed + + public FactionSawTrapDeed() : base( 0x1107 ) + { + } + + public FactionSawTrapDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/FactionSpikeTrap.cs b/Scripts/Engines/Factions/Items/Traps/FactionSpikeTrap.cs new file mode 100644 index 0000000..2ad9a78 --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/FactionSpikeTrap.cs @@ -0,0 +1,85 @@ +using System; +using Server; + +namespace Server.Factions +{ + public class FactionSpikeTrap : BaseFactionTrap + { + public override int LabelNumber{ get{ return 1044601; } } // faction spike trap + + public override int AttackMessage{ get{ return 1010545; } } // Large spikes in the ground spring up piercing your skin! + public override int DisarmMessage{ get{ return 1010541; } } // You carefully dismantle the trigger on the spikes and disable the trap. + public override int EffectSound{ get{ return 0x22E; } } + public override int MessageHue{ get{ return 0x5A; } } + + public override AllowedPlacing AllowedPlacing{ get{ return AllowedPlacing.ControlledFactionTown; } } + + public override void DoVisibleEffect() + { + Effects.SendLocationEffect( this.Location, this.Map, 0x11A4, 12, 6 ); + } + + public override void DoAttackEffect( Mobile m ) + { + m.Damage( Utility.Dice( 6, 10, 40 ), m ); + } + + [Constructable] + public FactionSpikeTrap() : this( null ) + { + } + + public FactionSpikeTrap( Faction f ) : this( f, null ) + { + } + + public FactionSpikeTrap( Faction f, Mobile m ) : base( f, m, 0x11A0 ) + { + } + + public FactionSpikeTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FactionSpikeTrapDeed : BaseFactionTrapDeed + { + public override Type TrapType{ get{ return typeof( FactionSpikeTrap ); } } + public override int LabelNumber{ get{ return 1044605; } } // faction spike trap deed + + public FactionSpikeTrapDeed() : base( 0x11A5 ) + { + } + + public FactionSpikeTrapDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Items/Traps/FactionTrapRemovalKit.cs b/Scripts/Engines/Factions/Items/Traps/FactionTrapRemovalKit.cs new file mode 100644 index 0000000..b0adcf7 --- /dev/null +++ b/Scripts/Engines/Factions/Items/Traps/FactionTrapRemovalKit.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionTrapRemovalKit : Item + { + private int m_Charges; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set{ m_Charges = value; } + } + + public override int LabelNumber{ get{ return 1041508; } } // a faction trap removal kit + + [Constructable] + public FactionTrapRemovalKit() : base( 7867 ) + { + LootType = LootType.Blessed; + m_Charges = 25; + } + + public void ConsumeCharge( Mobile consumer ) + { + --m_Charges; + + if ( m_Charges <= 0 ) + { + Delete(); + + if ( consumer != null ) + consumer.SendLocalizedMessage( 1042531 ); // You have used all of the parts in your trap removal kit. + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + // NOTE: OSI does not list uses remaining; intentional difference + list.Add( 1060584, m_Charges.ToString() ); // uses remaining: ~1_val~ + } + + public FactionTrapRemovalKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.WriteEncodedInt( (int) m_Charges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Charges = reader.ReadEncodedInt(); + break; + } + case 0: + { + m_Charges = 25; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/FactionWarHorse.cs b/Scripts/Engines/Factions/Mobiles/FactionWarHorse.cs new file mode 100644 index 0000000..3479238 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/FactionWarHorse.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Factions +{ + [CorpseName( "a war horse corpse" )] + public class FactionWarHorse : BaseMount + { + private Faction m_Faction; + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public Faction Faction + { + get{ return m_Faction; } + set + { + m_Faction = value; + + Body = ( m_Faction == null ? 0xE2 : m_Faction.Definition.WarHorseBody ); + ItemID = ( m_Faction == null ? 0x3EA0 : m_Faction.Definition.WarHorseItem ); + } + } + + public const int SilverPrice = 500; + public const int GoldPrice = 3000; + + [Constructable] + public FactionWarHorse() : this( null ) + { + } + + public FactionWarHorse( Faction faction ) : base( "a war horse", 0xE2, 0x3EA0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0xA8; + + SetStr( 400 ); + SetDex( 125 ); + SetInt( 51, 55 ); + + SetHits( 240 ); + SetMana( 0 ); + + SetDamage( 5, 8 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 300; + Karma = 300; + + Tamable = true; + ControlSlots = 1; + + Faction = faction; + } + + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public FactionWarHorse( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerState pl = PlayerState.Find( from ); + + if ( pl == null ) + from.SendLocalizedMessage( 1010366 ); // You cannot mount a faction war horse! + else if ( pl.Faction != this.Faction ) + from.SendLocalizedMessage( 1010367 ); // You cannot ride an opposing faction's war horse! + else if ( pl.Rank.Rank < 2 ) + from.SendLocalizedMessage( 1010368 ); // You must achieve a faction rank of at least two before riding a war horse! + else + base.OnDoubleClick( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Faction = Faction.ReadReference( reader ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs b/Scripts/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs new file mode 100644 index 0000000..6569a3b --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs @@ -0,0 +1,515 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Factions.AI; + +namespace Server.Factions +{ + public abstract class BaseFactionGuard : BaseCreature + { + private Faction m_Faction; + private Town m_Town; + private Orders m_Orders; + + public override bool BardImmune{ get{ return true; } } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public Faction Faction + { + get{ return m_Faction; } + set{ Unregister(); m_Faction = value; Register(); } + } + + public Orders Orders + { + get{ return m_Orders; } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public Town Town + { + get{ return m_Town; } + set{ Unregister(); m_Town = value; Register(); } + } + + public void Register() + { + if ( m_Town != null && m_Faction != null ) + m_Town.RegisterGuard( this ); + } + + public void Unregister() + { + if ( m_Town != null ) + m_Town.UnregisterGuard( this ); + } + + public abstract GuardAI GuardAI{ get; } + + protected override BaseAI ForcedAI + { + get { return new FactionGuardAI( this ); } + } + + public override TimeSpan ReacquireDelay{ get{ return TimeSpan.FromSeconds( 2.0 ); } } + + public override bool IsEnemy( Mobile m ) + { + Faction ourFaction = m_Faction; + Faction theirFaction = Faction.Find( m ); + + if ( theirFaction == null && m is BaseFactionGuard ) + theirFaction = ((BaseFactionGuard)m).Faction; + + if ( ourFaction != null && theirFaction != null && ourFaction != theirFaction ) + { + ReactionType reactionType = Orders.GetReaction( theirFaction ).Type; + + if ( reactionType == ReactionType.Attack ) + return true; + + if ( theirFaction != null ) + { + List list = m.Aggressed; + + for ( int i = 0; i < list.Count; ++i ) + { + AggressorInfo ai = list[i]; + + if ( ai.Defender is BaseFactionGuard ) + { + BaseFactionGuard bf = (BaseFactionGuard)ai.Defender; + + if ( bf.Faction == ourFaction ) + return true; + } + } + } + } + + return false; + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Player && m.Alive && InRange( m, 10 ) && !InRange( oldLocation, 10 ) && InLOS( m ) && m_Orders.GetReaction( Faction.Find( m ) ).Type == ReactionType.Warn ) + { + Direction = GetDirectionTo( m ); + + string warning = null; + + switch ( Utility.Random( 6 ) ) + { + case 0: warning = "I warn you, {0}, you would do well to leave this area before someone shows you the world of gray."; break; + case 1: warning = "It would be wise to leave this area, {0}, lest your head become my commanders' trophy."; break; + case 2: warning = "You are bold, {0}, for one of the meager {1}. Leave now, lest you be taught the taste of dirt."; break; + case 3: warning = "Your presence here is an insult, {0}. Be gone now, knave."; break; + case 4: warning = "Dost thou wish to be hung by your toes, {0}? Nay? Then come no closer."; break; + case 5: warning = "Hey, {0}. Yeah, you. Get out of here before I beat you with a stick."; break; + } + + Faction faction = Faction.Find( m ); + + Say( warning, m.Name, faction == null ? "civilians" : faction.Definition.FriendlyName ); + } + } + + private const int ListenRange = 12; + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( InRange( from, ListenRange ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + private DateTime m_OrdersEnd; + + private void ChangeReaction( Faction faction, ReactionType type ) + { + if ( faction == null ) + { + switch ( type ) + { + case ReactionType.Ignore: Say( 1005179 ); break; // Civilians will now be ignored. + case ReactionType.Warn: Say( 1005180 ); break; // Civilians will now be warned of their impending deaths. + case ReactionType.Attack: return; + } + } + else + { + TextDefinition def = null; + + switch ( type ) + { + case ReactionType.Ignore: def = faction.Definition.GuardIgnore; break; + case ReactionType.Warn: def = faction.Definition.GuardWarn; break; + case ReactionType.Attack: def = faction.Definition.GuardAttack; break; + } + + if ( def != null && def.Number > 0 ) + Say( def.Number ); + else if ( def != null && def.String != null ) + Say( def.String ); + } + + m_Orders.SetReaction( faction, type ); + } + + private bool WasNamed( string speech ) + { + string name = this.Name; + + return ( name != null && Insensitive.StartsWith( speech, name ) ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + base.OnSpeech( e ); + + Mobile from = e.Mobile; + + if ( !e.Handled && InRange( from, ListenRange ) && from.Alive ) + { + if ( e.HasKeyword( 0xE6 ) && (Insensitive.Equals( e.Speech, "orders" ) || WasNamed( e.Speech )) ) // *orders* + { + if ( m_Town == null || !m_Town.IsSheriff( from ) ) + { + this.Say( 1042189 ); // I don't work for you! + } + else if ( Town.FromRegion( this.Region ) == m_Town ) + { + this.Say( 1042180 ); // Your orders, sire? + m_OrdersEnd = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + } + } + else if ( DateTime.Now < m_OrdersEnd ) + { + if ( m_Town != null && m_Town.IsSheriff( from ) && Town.FromRegion( this.Region ) == m_Town ) + { + m_OrdersEnd = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + + bool understood = true; + ReactionType newType = 0; + + if ( Insensitive.Contains( e.Speech, "attack" ) ) + newType = ReactionType.Attack; + else if ( Insensitive.Contains( e.Speech, "warn" ) ) + newType = ReactionType.Warn; + else if ( Insensitive.Contains( e.Speech, "ignore" ) ) + newType = ReactionType.Ignore; + else + understood = false; + + if ( understood ) + { + understood = false; + + if ( Insensitive.Contains( e.Speech, "civil" ) ) + { + ChangeReaction( null, newType ); + understood = true; + } + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction faction = factions[i]; + + if ( faction != m_Faction && Insensitive.Contains( e.Speech, faction.Definition.Keyword ) ) + { + ChangeReaction( faction, newType ); + understood = true; + } + } + } + else if ( Insensitive.Contains( e.Speech, "patrol" ) ) + { + Home = Location; + RangeHome = 6; + Combatant = null; + m_Orders.Movement = MovementType.Patrol; + Say( 1005146 ); // This spot looks like it needs protection! I shall guard it with my life. + understood = true; + } + else if ( Insensitive.Contains( e.Speech, "follow" ) ) + { + Home = Location; + RangeHome = 6; + Combatant = null; + m_Orders.Follow = from; + m_Orders.Movement = MovementType.Follow; + Say( 1005144 ); // Yes, Sire. + understood = true; + } + + if ( !understood ) + Say( 1042183 ); // I'm sorry, I don't understand your orders... + } + } + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Faction != null && Map == Faction.Facet ) + list.Add( 1060846, m_Faction.Definition.PropName ); // Guard: ~1_val~ + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Faction != null && Map == Faction.Facet ) + { + string text = String.Concat( "(Guard, ", m_Faction.Definition.FriendlyName, ")" ); + + int hue = ( Faction.Find( from ) == m_Faction ? 98 : 38 ); + + PrivateOverheadMessage( MessageType.Label, hue, true, text, from.NetState ); + } + + base.OnSingleClick( from ); + } + + public virtual void GenerateRandomHair() + { + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + } + + private static Type[] m_StrongPotions = new Type[] + { + typeof( GreaterHealPotion ), typeof( GreaterHealPotion ), typeof( GreaterHealPotion ), + typeof( GreaterCurePotion ), typeof( GreaterCurePotion ), typeof( GreaterCurePotion ), + typeof( GreaterStrengthPotion ), typeof( GreaterStrengthPotion ), + typeof( GreaterAgilityPotion ), typeof( GreaterAgilityPotion ), + typeof( TotalRefreshPotion ), typeof( TotalRefreshPotion ), + typeof( GreaterExplosionPotion ) + }; + + private static Type[] m_WeakPotions = new Type[] + { + typeof( HealPotion ), typeof( HealPotion ), typeof( HealPotion ), + typeof( CurePotion ), typeof( CurePotion ), typeof( CurePotion ), + typeof( StrengthPotion ), typeof( StrengthPotion ), + typeof( AgilityPotion ), typeof( AgilityPotion ), + typeof( RefreshPotion ), typeof( RefreshPotion ), + typeof( ExplosionPotion ) + }; + + public void PackStrongPotions( int min, int max ) + { + PackStrongPotions( Utility.RandomMinMax( min, max ) ); + } + + public void PackStrongPotions( int count ) + { + for ( int i = 0; i < count; ++i ) + PackStrongPotion(); + } + + public void PackStrongPotion() + { + PackItem( Loot.Construct( m_StrongPotions ) ); + } + + public void PackWeakPotions( int min, int max ) + { + PackWeakPotions( Utility.RandomMinMax( min, max ) ); + } + + public void PackWeakPotions( int count ) + { + for ( int i = 0; i < count; ++i ) + PackWeakPotion(); + } + + public void PackWeakPotion() + { + PackItem( Loot.Construct( m_WeakPotions ) ); + } + + public Item Immovable( Item item ) + { + item.Movable = false; + return item; + } + + public Item Newbied( Item item ) + { + item.LootType = LootType.Newbied; + return item; + } + + public Item Rehued( Item item, int hue ) + { + item.Hue = hue; + return item; + } + + public Item Layered( Item item, Layer layer ) + { + item.Layer = layer; + return item; + } + + public Item Resourced( BaseWeapon weapon, CraftResource resource ) + { + weapon.Resource = resource; + return weapon; + } + + public Item Resourced( BaseArmor armor, CraftResource resource ) + { + armor.Resource = resource; + return armor; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + Unregister(); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.Delete(); + } + + public virtual void GenerateBody( bool isFemale, bool randomHair ) + { + Hue = Utility.RandomSkinHue(); + + if ( isFemale ) + { + Female = true; + Body = 401; + Name = NameList.RandomName( "female" ); + } + else + { + Female = false; + Body = 400; + Name = NameList.RandomName( "male" ); + } + + if ( randomHair ) + GenerateRandomHair(); + } + + public override bool ClickTitle{ get{ return false; } } + + public BaseFactionGuard( string title ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + m_Orders = new Orders( this ); + Title = title; + + RangeHome = 6; + } + + public BaseFactionGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + Town.WriteReference( writer, m_Town ); + + m_Orders.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Faction = Faction.ReadReference( reader ); + m_Town = Town.ReadReference( reader ); + m_Orders = new Orders( this, reader ); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Register ) ); + } + } + + public class VirtualMount : IMount + { + private VirtualMountItem m_Item; + + public Mobile Rider + { + get{ return m_Item.Rider; } + set{} + } + + public VirtualMount( VirtualMountItem item ) + { + m_Item = item; + } + + public virtual void OnRiderDamaged( int amount, Mobile from, bool willKill ) + { + } + } + + public class VirtualMountItem : Item, IMountItem + { + private Mobile m_Rider; + private VirtualMount m_Mount; + + public Mobile Rider{ get{ return m_Rider; } } + + public VirtualMountItem( Mobile mob ) : base( 0x3EA0 ) + { + Layer = Layer.Mount; + + m_Rider = mob; + m_Mount = new VirtualMount( this ); + } + + public IMount Mount + { + get{ return m_Mount; } + } + + public VirtualMountItem( Serial serial ) : base( serial ) + { + m_Mount = new VirtualMount( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Rider ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Rider = reader.ReadMobile(); + + if ( m_Rider == null ) + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs b/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs new file mode 100644 index 0000000..926cbe8 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/GuardAI.cs @@ -0,0 +1,779 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.Factions.AI; +using Server.Spells; +using Server.Spells.First; +using Server.Spells.Second; +using Server.Spells.Third; +using Server.Spells.Fourth; +using Server.Spells.Fifth; +using Server.Spells.Sixth; +using Server.Spells.Seventh; + +namespace Server.Factions +{ + public enum GuardAI + { + Bless = 0x01, // heal, cure, +stats + Curse = 0x02, // poison, -stats + Melee = 0x04, // weapons + Magic = 0x08, // damage spells + Smart = 0x10 // smart weapons/damage spells + } + + public class ComboEntry + { + private Type m_Spell; + private TimeSpan m_Hold; + private int m_Chance; + + public Type Spell{ get{ return m_Spell; } } + public TimeSpan Hold{ get{ return m_Hold; } } + public int Chance{ get{ return m_Chance; } } + + public ComboEntry( Type spell ) : this( spell, 100, TimeSpan.Zero ) + { + } + + public ComboEntry( Type spell, int chance ) : this( spell, chance, TimeSpan.Zero ) + { + } + + public ComboEntry( Type spell, int chance, TimeSpan hold ) + { + m_Spell = spell; + m_Chance = chance; + m_Hold = hold; + } + } + + public class SpellCombo + { + private int m_Mana; + private ComboEntry[] m_Entries; + + public int Mana{ get{ return m_Mana; } } + public ComboEntry[] Entries{ get{ return m_Entries; } } + + public SpellCombo( int mana, params ComboEntry[] entries ) + { + m_Mana = mana; + m_Entries = entries; + } + + public static readonly SpellCombo Simple = new SpellCombo( 50, + new ComboEntry( typeof( ParalyzeSpell ), 20 ), + new ComboEntry( typeof( ExplosionSpell ), 100, TimeSpan.FromSeconds( 2.8 ) ), + new ComboEntry( typeof( PoisonSpell ), 30 ), + new ComboEntry( typeof( EnergyBoltSpell ) ) + ); + + public static readonly SpellCombo Strong = new SpellCombo( 90, + new ComboEntry( typeof( ParalyzeSpell ), 20 ), + new ComboEntry( typeof( ExplosionSpell ), 50, TimeSpan.FromSeconds( 2.8 ) ), + new ComboEntry( typeof( PoisonSpell ), 30 ), + new ComboEntry( typeof( ExplosionSpell ), 100, TimeSpan.FromSeconds( 2.8 ) ), + new ComboEntry( typeof( EnergyBoltSpell ) ), + new ComboEntry( typeof( PoisonSpell ), 30 ), + new ComboEntry( typeof( EnergyBoltSpell ) ) + ); + + public static Spell Process( Mobile mob, Mobile targ, ref SpellCombo combo, ref int index, ref DateTime releaseTime ) + { + while ( ++index < combo.m_Entries.Length ) + { + ComboEntry entry = combo.m_Entries[index]; + + if ( entry.Spell == typeof( PoisonSpell ) && targ.Poisoned ) + continue; + + if ( entry.Chance > Utility.Random( 100 ) ) + { + releaseTime = DateTime.Now + entry.Hold; + return (Spell) Activator.CreateInstance( entry.Spell, new object[]{ mob, null } ); + } + } + + combo = null; + index = -1; + return null; + } + } + + public class FactionGuardAI : BaseAI + { + private BaseFactionGuard m_Guard; + + private BandageContext m_Bandage; + private DateTime m_BandageStart; + + private SpellCombo m_Combo; + private int m_ComboIndex = -1; + private DateTime m_ReleaseTarget; + + private const int ManaReserve = 30; + + public bool IsAllowed( GuardAI flag ) + { + return ( ( m_Guard.GuardAI & flag ) == flag ); + } + + public bool IsDamaged + { + get{ return ( m_Guard.Hits < m_Guard.HitsMax ); } + } + + public bool IsPoisoned + { + get{ return m_Guard.Poisoned; } + } + + public TimeSpan TimeUntilBandage + { + get + { + if ( m_Bandage != null && m_Bandage.Timer == null ) + m_Bandage = null; + + if ( m_Bandage == null ) + return TimeSpan.MaxValue; + + TimeSpan ts = ( m_BandageStart + m_Bandage.Timer.Delay ) - DateTime.Now; + + if ( ts < TimeSpan.FromSeconds( -1.0 ) ) + { + m_Bandage = null; + return TimeSpan.MaxValue; + } + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + return ts; + } + } + + public bool DequipWeapon() + { + Container pack = m_Guard.Backpack; + + if ( pack == null ) + return false; + + Item weapon = m_Guard.Weapon as Item; + + if ( weapon != null && weapon.Parent == m_Guard && !(weapon is Fists) ) + { + pack.DropItem( weapon ); + return true; + } + + return false; + } + + public bool EquipWeapon() + { + Container pack = m_Guard.Backpack; + + if ( pack == null ) + return false; + + Item weapon = pack.FindItemByType( typeof( BaseWeapon ) ); + + if ( weapon == null ) + return false; + + return m_Guard.EquipItem( weapon ); + } + + public bool StartBandage() + { + m_Bandage = null; + + Container pack = m_Guard.Backpack; + + if ( pack == null ) + return false; + + Item bandage = pack.FindItemByType( typeof( Bandage ) ); + + if ( bandage == null ) + return false; + + m_Bandage = BandageContext.BeginHeal( m_Guard, m_Guard ); + m_BandageStart = DateTime.Now; + return ( m_Bandage != null ); + } + + public bool UseItemByType( Type type ) + { + Container pack = m_Guard.Backpack; + + if ( pack == null ) + return false; + + Item item = pack.FindItemByType( type ); + + if ( item == null ) + return false; + + bool requip = DequipWeapon(); + + item.OnDoubleClick( m_Guard ); + + if ( requip ) + EquipWeapon(); + + return true; + } + + public int GetStatMod( Mobile mob, StatType type ) + { + StatMod mod = mob.GetStatMod( String.Format( "[Magic] {0} Offset", type ) ); + + if ( mod == null ) + return 0; + + return mod.Offset; + } + + public Spell RandomOffenseSpell() + { + int maxCircle = (int)((m_Guard.Skills.Magery.Value + 20.0) / (100.0 / 7.0)); + + if ( maxCircle < 1 ) + maxCircle = 1; + + switch ( Utility.Random( maxCircle*2 ) ) + { + case 0: case 1: return new MagicArrowSpell( m_Guard, null ); + case 2: case 3: return new HarmSpell( m_Guard, null ); + case 4: case 5: return new FireballSpell( m_Guard, null ); + case 6: case 7: return new LightningSpell( m_Guard, null ); + case 8: return new MindBlastSpell( m_Guard, null ); + case 9: return new ParalyzeSpell( m_Guard, null ); + case 10: return new EnergyBoltSpell( m_Guard, null ); + case 11: return new ExplosionSpell( m_Guard, null ); + default: return new FlameStrikeSpell( m_Guard, null ); + } + } + + public Mobile FindDispelTarget( bool activeOnly ) + { + if ( m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel( m_Mobile ) || m_Mobile.AutoDispel ) + return null; + + if ( activeOnly ) + { + List aggressed = m_Mobile.Aggressed; + List aggressors = m_Mobile.Aggressors; + + Mobile active = null; + double activePrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange( comb, 12 ) && CanDispel( comb ) ) + { + active = comb; + activePrio = m_Mobile.GetDistanceToSqrt( comb ); + + if ( activePrio <= 2 ) + return active; + } + + for ( int i = 0; i < aggressed.Count; ++i ) + { + AggressorInfo info = aggressed[i]; + Mobile m = info.Defender; + + if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) ) + { + double prio = m_Mobile.GetDistanceToSqrt( m ); + + if ( active == null || prio < activePrio ) + { + active = m; + activePrio = prio; + + if ( activePrio <= 2 ) + return active; + } + } + } + + for ( int i = 0; i < aggressors.Count; ++i ) + { + AggressorInfo info = aggressors[i]; + Mobile m = info.Attacker; + + if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) ) + { + double prio = m_Mobile.GetDistanceToSqrt( m ); + + if ( active == null || prio < activePrio ) + { + active = m; + activePrio = prio; + + if ( activePrio <= 2 ) + return active; + } + } + } + + return active; + } + else + { + Map map = m_Mobile.Map; + + if ( map != null ) + { + Mobile active = null, inactive = null; + double actPrio = 0.0, inactPrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel( comb ) ) + { + active = inactive = comb; + actPrio = inactPrio = m_Mobile.GetDistanceToSqrt( comb ); + } + + foreach ( Mobile m in m_Mobile.GetMobilesInRange( 12 ) ) + { + if ( m != m_Mobile && CanDispel( m ) ) + { + double prio = m_Mobile.GetDistanceToSqrt( m ); + + if ( !activeOnly && (inactive == null || prio < inactPrio) ) + { + inactive = m; + inactPrio = prio; + } + + if ( (m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio) ) + { + active = m; + actPrio = prio; + } + } + } + + return active != null ? active : inactive; + } + } + + return null; + } + + public bool CanDispel( Mobile m ) + { + return ( m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful( m, false ) && !((BaseCreature)m).IsAnimatedDead ); + } + + public void RunTo( Mobile m ) + { + /*if ( m.Paralyzed || m.Frozen ) + { + if ( m_Mobile.InRange( m, 1 ) ) + RunFrom( m ); + else if ( !m_Mobile.InRange( m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2 ) && !MoveTo( m, true, 1 ) ) + OnFailedMove(); + } + else + {*/ + if ( !m_Mobile.InRange( m, m_Mobile.RangeFight ) ) + { + if ( !MoveTo( m, true, 1 ) ) + OnFailedMove(); + } + else if ( m_Mobile.InRange( m, m_Mobile.RangeFight - 1 ) ) + { + RunFrom( m ); + } + /*}*/ + } + + public void RunFrom( Mobile m ) + { + Run( (m_Mobile.GetDirectionTo( m ) - 4) & Direction.Mask ); + } + + public void OnFailedMove() + { + /*if ( !m_Mobile.DisallowAllMoves && 20 > Utility.Random( 100 ) && IsAllowed( GuardAI.Magic ) ) + { + if ( m_Mobile.Target != null ) + m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled ); + + new TeleportSpell( m_Mobile, null ).Cast(); + + m_Mobile.DebugSay( "I am stuck, I'm going to try teleporting away" ); + } + else*/ if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + m_Mobile.DebugSay( "I am stuck" ); + } + } + + public void Run( Direction d ) + { + if ( (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.Paralyzed || m_Mobile.Frozen || m_Mobile.DisallowAllMoves ) + return; + + m_Mobile.Direction = d | Direction.Running; + + if ( !DoMove( m_Mobile.Direction, true ) ) + OnFailedMove(); + } + + public FactionGuardAI( BaseFactionGuard guard ) : base( guard ) + { + m_Guard = guard; + } + + public override bool Think() + { + if ( m_Mobile.Deleted ) + return false; + + Mobile combatant = m_Guard.Combatant; + + if ( combatant == null || combatant.Deleted || !combatant.Alive || combatant.IsDeadBondedPet || !m_Mobile.CanSee( combatant ) || !m_Mobile.CanBeHarmful( combatant, false ) || combatant.Map != m_Mobile.Map ) + { + // Our combatant is deleted, dead, hidden, or we cannot hurt them + // Try to find another combatant + + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else + { + m_Mobile.Combatant = combatant = null; + } + } + + if ( combatant != null && (!m_Mobile.InLOS( combatant ) || !m_Mobile.InRange( combatant, 12 )) ) + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if ( !m_Mobile.InRange( combatant, 36 ) ) + { + m_Mobile.Combatant = combatant = null; + } + } + + Mobile dispelTarget = FindDispelTarget( true ); + + if ( m_Guard.Target != null && m_ReleaseTarget == DateTime.MinValue ) + m_ReleaseTarget = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + + if ( m_Guard.Target != null && DateTime.Now > m_ReleaseTarget ) + { + Target targ = m_Guard.Target; + + Mobile toHarm = ( dispelTarget == null ? combatant : dispelTarget ); + + if ( (targ.Flags & TargetFlags.Harmful) != 0 && toHarm != null ) + { + if ( m_Guard.Map == toHarm.Map && ( targ.Range < 0 || m_Guard.InRange( toHarm, targ.Range ) ) && m_Guard.CanSee( toHarm ) && m_Guard.InLOS( toHarm ) ) + targ.Invoke( m_Guard, toHarm ); + else if ( targ is DispelSpell.InternalTarget ) + targ.Cancel( m_Guard, TargetCancelType.Canceled ); + } + else if ( (targ.Flags & TargetFlags.Beneficial) != 0 ) + { + targ.Invoke( m_Guard, m_Guard ); + } + else + { + targ.Cancel( m_Guard, TargetCancelType.Canceled ); + } + + m_ReleaseTarget = DateTime.MinValue; + } + + if ( dispelTarget != null ) + { + if ( Action != ActionType.Combat ) + Action = ActionType.Combat; + + m_Guard.Warmode = true; + + RunFrom( dispelTarget ); + } + else if ( combatant != null ) + { + if ( Action != ActionType.Combat ) + Action = ActionType.Combat; + + m_Guard.Warmode = true; + + RunTo( combatant ); + } + else if ( m_Guard.Orders.Movement != MovementType.Stand ) + { + Mobile toFollow = null; + + if ( m_Guard.Town != null && m_Guard.Orders.Movement == MovementType.Follow ) + { + toFollow = m_Guard.Orders.Follow; + + if ( toFollow == null ) + toFollow = m_Guard.Town.Sheriff; + } + + if ( toFollow != null && toFollow.Map == m_Guard.Map && toFollow.InRange( m_Guard, m_Guard.RangePerception * 3 ) && Town.FromRegion( toFollow.Region ) == m_Guard.Town ) + { + if ( Action != ActionType.Combat ) + Action = ActionType.Combat; + + if ( m_Mobile.CurrentSpeed != m_Mobile.ActiveSpeed ) + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + + m_Guard.Warmode = true; + + RunTo( toFollow ); + } + else + { + if ( Action != ActionType.Wander ) + Action = ActionType.Wander; + + if ( m_Mobile.CurrentSpeed != m_Mobile.PassiveSpeed ) + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + + m_Guard.Warmode = false; + + WalkRandomInHome( 2, 2, 1 ); + } + } + else + { + if ( Action != ActionType.Wander ) + Action = ActionType.Wander; + + m_Guard.Warmode = false; + } + + if ( (IsDamaged || IsPoisoned) && m_Guard.Skills.Healing.Base > 20.0 ) + { + TimeSpan ts = TimeUntilBandage; + + if ( ts == TimeSpan.MaxValue ) + StartBandage(); + } + + if ( m_Mobile.Spell == null && DateTime.Now >= m_Mobile.NextSpellTime ) + { + Spell spell = null; + + DateTime toRelease = DateTime.MinValue; + + if ( IsPoisoned ) + { + Poison p = m_Guard.Poison; + + TimeSpan ts = TimeUntilBandage; + + if ( p != Poison.Lesser || ts == TimeSpan.MaxValue || TimeUntilBandage < TimeSpan.FromSeconds( 1.5 ) || (m_Guard.HitsMax - m_Guard.Hits) > Utility.Random( 250 ) ) + { + if ( IsAllowed( GuardAI.Bless ) ) + spell = new CureSpell( m_Guard, null ); + else + UseItemByType( typeof( BaseCurePotion ) ); + } + } + else if ( IsDamaged && (m_Guard.HitsMax - m_Guard.Hits) > Utility.Random( 200 ) ) + { + if( IsAllowed( GuardAI.Magic ) && ((m_Guard.Hits * 100) / Math.Max( m_Guard.HitsMax, 1 )) < 10 && m_Guard.Home != Point3D.Zero && !Utility.InRange( m_Guard.Location, m_Guard.Home, 15 ) && m_Guard.Mana >= 11 ) + { + spell = new RecallSpell( m_Guard, null, new RunebookEntry( m_Guard.Home, m_Guard.Map, "Guard's Home", null ), null ); + } + else if ( IsAllowed( GuardAI.Bless ) ) + { + if ( m_Guard.Mana >= 11 && (m_Guard.Hits + 30) < m_Guard.HitsMax ) + spell = new GreaterHealSpell( m_Guard, null ); + else if ( (m_Guard.Hits + 10) < m_Guard.HitsMax && (m_Guard.Mana < 11 || (m_Guard.NextCombatTime - DateTime.Now) > TimeSpan.FromSeconds( 2.0 )) ) + spell = new HealSpell( m_Guard, null ); + } + else if ( m_Guard.CanBeginAction( typeof( BaseHealPotion ) ) ) + { + UseItemByType( typeof( BaseHealPotion ) ); + } + } + else if ( dispelTarget != null && (IsAllowed( GuardAI.Magic ) || IsAllowed( GuardAI.Bless ) || IsAllowed( GuardAI.Curse )) ) + { + if ( !dispelTarget.Paralyzed && m_Guard.Mana > (ManaReserve + 20) && 40 > Utility.Random( 100 ) ) + spell = new ParalyzeSpell( m_Guard, null ); + else + spell = new DispelSpell( m_Guard, null ); + } + + if ( combatant != null ) + { + if ( m_Combo != null ) + { + if ( spell == null ) + { + spell = SpellCombo.Process( m_Guard, combatant, ref m_Combo, ref m_ComboIndex, ref toRelease ); + } + else + { + m_Combo = null; + m_ComboIndex = -1; + } + } + else if ( 20 > Utility.Random( 100 ) && IsAllowed( GuardAI.Magic ) ) + { + if ( 80 > Utility.Random( 100 ) ) + { + m_Combo = ( IsAllowed( GuardAI.Smart ) ? SpellCombo.Simple : SpellCombo.Strong ); + m_ComboIndex = -1; + + if ( m_Guard.Mana >= (ManaReserve + m_Combo.Mana) ) + spell = SpellCombo.Process( m_Guard, combatant, ref m_Combo, ref m_ComboIndex, ref toRelease ); + else + { + m_Combo = null; + + if ( m_Guard.Mana >= (ManaReserve + 40) ) + spell = RandomOffenseSpell(); + } + } + else if ( m_Guard.Mana >= (ManaReserve + 40) ) + { + spell = RandomOffenseSpell(); + } + } + + if ( spell == null && 2 > Utility.Random( 100 ) && m_Guard.Mana >= (ManaReserve + 10) ) + { + int strMod = GetStatMod( m_Guard, StatType.Str ); + int dexMod = GetStatMod( m_Guard, StatType.Dex ); + int intMod = GetStatMod( m_Guard, StatType.Int ); + + List types = new List(); + + if ( strMod <= 0 ) + types.Add( typeof( StrengthSpell ) ); + + if ( dexMod <= 0 && IsAllowed( GuardAI.Melee ) ) + types.Add( typeof( AgilitySpell ) ); + + if ( intMod <= 0 && IsAllowed( GuardAI.Magic ) ) + types.Add( typeof( CunningSpell ) ); + + if ( IsAllowed( GuardAI.Bless ) ) + { + if ( types.Count > 1 ) + spell = new BlessSpell( m_Guard, null ); + else if ( types.Count == 1 ) + spell = (Spell) Activator.CreateInstance( types[0], new object[]{ m_Guard, null } ); + } + else if ( types.Count > 0 ) + { + if ( types[0] == typeof( StrengthSpell ) ) + UseItemByType( typeof( BaseStrengthPotion ) ); + else if ( types[0] == typeof( AgilitySpell ) ) + UseItemByType( typeof( BaseAgilityPotion ) ); + } + } + + if ( spell == null && 2 > Utility.Random( 100 ) && m_Guard.Mana >= (ManaReserve + 10) && IsAllowed( GuardAI.Curse ) ) + { + if ( !combatant.Poisoned && 40 > Utility.Random( 100 ) ) + { + spell = new PoisonSpell( m_Guard, null ); + } + else + { + int strMod = GetStatMod( combatant, StatType.Str ); + int dexMod = GetStatMod( combatant, StatType.Dex ); + int intMod = GetStatMod( combatant, StatType.Int ); + + List types = new List(); + + if ( strMod >= 0 ) + types.Add( typeof( WeakenSpell ) ); + + if ( dexMod >= 0 && IsAllowed( GuardAI.Melee ) ) + types.Add( typeof( ClumsySpell ) ); + + if ( intMod >= 0 && IsAllowed( GuardAI.Magic ) ) + types.Add( typeof( FeeblemindSpell ) ); + + if ( types.Count > 1 ) + spell = new CurseSpell( m_Guard, null ); + else if ( types.Count == 1 ) + spell = (Spell) Activator.CreateInstance( types[0], new object[]{ m_Guard, null } ); + } + } + } + + if ( spell != null && (m_Guard.HitsMax - m_Guard.Hits + 10) > Utility.Random( 100 ) ) + { + Type type = null; + + if ( spell is GreaterHealSpell ) + type = typeof( BaseHealPotion ); + else if ( spell is CureSpell ) + type = typeof( BaseCurePotion ); + else if ( spell is StrengthSpell ) + type = typeof( BaseStrengthPotion ); + else if ( spell is AgilitySpell ) + type = typeof( BaseAgilityPotion ); + + if ( type == typeof( BaseHealPotion ) && !m_Guard.CanBeginAction( type ) ) + type = null; + + if ( type != null && m_Guard.Target == null && UseItemByType( type ) ) + { + if ( spell is GreaterHealSpell ) + { + if ( (m_Guard.Hits + 30) > m_Guard.HitsMax && (m_Guard.Hits + 10) < m_Guard.HitsMax ) + spell = new HealSpell( m_Guard, null ); + } + else + { + spell = null; + } + } + } + else if ( spell == null && m_Guard.Stam < (m_Guard.StamMax / 3) && IsAllowed( GuardAI.Melee ) ) + { + UseItemByType( typeof( BaseRefreshPotion ) ); + } + + if ( spell == null || !spell.Cast() ) + EquipWeapon(); + } + else if ( m_Mobile.Spell is Spell && ((Spell)m_Mobile.Spell).State == SpellState.Sequencing ) + { + EquipWeapon(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Orders.cs b/Scripts/Engines/Factions/Mobiles/Guards/Orders.cs new file mode 100644 index 0000000..ea9cff6 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Orders.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Factions.AI +{ + public enum ReactionType + { + Ignore, + Warn, + Attack + } + + public enum MovementType + { + Stand, + Patrol, + Follow + } + + public class Reaction + { + private Faction m_Faction; + private ReactionType m_Type; + + public Faction Faction{ get{ return m_Faction; } } + public ReactionType Type{ get{ return m_Type; } set{ m_Type = value; } } + + public Reaction( Faction faction, ReactionType type ) + { + m_Faction = faction; + m_Type = type; + } + + public Reaction( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Faction = Faction.ReadReference( reader ); + m_Type = (ReactionType) reader.ReadEncodedInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + Faction.WriteReference( writer, m_Faction ); + writer.WriteEncodedInt( (int) m_Type ); + } + } + + public class Orders + { + private BaseFactionGuard m_Guard; + + private List m_Reactions; + private MovementType m_Movement; + private Mobile m_Follow; + + public BaseFactionGuard Guard{ get{ return m_Guard; } } + + public MovementType Movement{ get{ return m_Movement; } set{ m_Movement = value; } } + public Mobile Follow{ get{ return m_Follow; } set{ m_Follow = value; } } + + public Reaction GetReaction( Faction faction ) + { + Reaction reaction; + + for ( int i = 0; i < m_Reactions.Count; ++i ) + { + reaction = m_Reactions[i]; + + if ( reaction.Faction == faction ) + return reaction; + } + + reaction = new Reaction( faction, ( faction == null || faction == m_Guard.Faction ) ? ReactionType.Ignore : ReactionType.Attack ); + m_Reactions.Add( reaction ); + + return reaction; + } + + public void SetReaction( Faction faction, ReactionType type ) + { + Reaction reaction = GetReaction( faction ); + + reaction.Type = type; + } + + public Orders( BaseFactionGuard guard ) + { + m_Guard = guard; + m_Reactions = new List(); + m_Movement = MovementType.Patrol; + } + + public Orders( BaseFactionGuard guard, GenericReader reader ) + { + m_Guard = guard; + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_Follow = reader.ReadMobile(); + goto case 0; + } + case 0: + { + int count = reader.ReadEncodedInt(); + m_Reactions = new List( count ); + + for ( int i = 0; i < count; ++i ) + m_Reactions.Add( new Reaction( reader ) ); + + m_Movement = (MovementType)reader.ReadEncodedInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 1 ); // version + + writer.Write( (Mobile) m_Follow ); + + writer.WriteEncodedInt( (int) m_Reactions.Count ); + + for ( int i = 0; i < m_Reactions.Count; ++i ) + m_Reactions[i].Serialize( writer ); + + writer.WriteEncodedInt( (int) m_Movement ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionBerserker.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionBerserker.cs new file mode 100644 index 0000000..4dcefd6 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionBerserker.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionBerserker : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Melee | GuardAI.Curse | GuardAI.Bless; } } + + [Constructable] + public FactionBerserker() : base( "the berserker" ) + { + GenerateBody( false, false ); + + SetStr( 126, 150 ); + SetDex( 61, 85 ); + SetInt( 81, 95 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 50 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Energy, 30, 50 ); + SetResistance( ResistanceType.Poison, 30, 50 ); + + VirtualArmor = 24; + + SetSkill( SkillName.Swords, 100.0, 110.0 ); + SetSkill( SkillName.Wrestling, 100.0, 110.0 ); + SetSkill( SkillName.Tactics, 100.0, 110.0 ); + SetSkill( SkillName.MagicResist, 100.0, 110.0 ); + SetSkill( SkillName.Healing, 100.0, 110.0 ); + SetSkill( SkillName.Anatomy, 100.0, 110.0 ); + + SetSkill( SkillName.Magery, 100.0, 110.0 ); + SetSkill( SkillName.EvalInt, 100.0, 110.0 ); + SetSkill( SkillName.Meditation, 100.0, 110.0 ); + + AddItem( Immovable( Rehued( new BodySash(), 1645 ) ) ); + AddItem( Immovable( Rehued( new Kilt(), 1645 ) ) ); + AddItem( Immovable( Rehued( new Sandals(), 1645 ) ) ); + AddItem( Newbied( new DoubleAxe() ) ); + + HairItemID = 0x2047; // Afro + HairHue = 0x29; + + FacialHairItemID = 0x204B; // Medium Short Beard + FacialHairHue = 0x29; + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionBerserker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionDeathKnight.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionDeathKnight.cs new file mode 100644 index 0000000..d6a83f9 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionDeathKnight.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionDeathKnight : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Melee | GuardAI.Curse | GuardAI.Bless; } } + + [Constructable] + public FactionDeathKnight() : base( "the death knight" ) + { + GenerateBody( false, false ); + Hue = 1; + + SetStr( 126, 150 ); + SetDex( 61, 85 ); + SetInt( 81, 95 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 50 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Energy, 30, 50 ); + SetResistance( ResistanceType.Poison, 30, 50 ); + + VirtualArmor = 24; + + SetSkill( SkillName.Swords, 100.0, 110.0 ); + SetSkill( SkillName.Wrestling, 100.0, 110.0 ); + SetSkill( SkillName.Tactics, 100.0, 110.0 ); + SetSkill( SkillName.MagicResist, 100.0, 110.0 ); + SetSkill( SkillName.Healing, 100.0, 110.0 ); + SetSkill( SkillName.Anatomy, 100.0, 110.0 ); + + SetSkill( SkillName.Magery, 100.0, 110.0 ); + SetSkill( SkillName.EvalInt, 100.0, 110.0 ); + SetSkill( SkillName.Meditation, 100.0, 110.0 ); + + Item shroud = new Item( 0x204E ); + shroud.Layer = Layer.OuterTorso; + + AddItem( Immovable( Rehued( shroud, 1109 ) ) ); + AddItem( Newbied( Rehued( new ExecutionersAxe(), 2211 ) ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionDeathKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionDragoon.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionDragoon.cs new file mode 100644 index 0000000..4276801 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionDragoon.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionDragoon : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse; } } + + [Constructable] + public FactionDragoon() : base( "the dragoon" ) + { + GenerateBody( false, false ); + + SetStr( 151, 175 ); + SetDex( 61, 85 ); + SetInt( 151, 175 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + + VirtualArmor = 32; + + SetSkill( SkillName.Macing, 110.0, 120.0 ); + SetSkill( SkillName.Wrestling, 110.0, 120.0 ); + SetSkill( SkillName.Tactics, 110.0, 120.0 ); + SetSkill( SkillName.MagicResist, 110.0, 120.0 ); + SetSkill( SkillName.Healing, 110.0, 120.0 ); + SetSkill( SkillName.Anatomy, 110.0, 120.0 ); + + SetSkill( SkillName.Magery, 110.0, 120.0 ); + SetSkill( SkillName.EvalInt, 110.0, 120.0 ); + SetSkill( SkillName.Meditation, 110.0, 120.0 ); + + AddItem( Immovable( Rehued( new Cloak(), 1645 ) ) ); + + AddItem( Immovable( Rehued( new PlateChest(), 1645 ) ) ); + AddItem( Immovable( Rehued( new PlateLegs(), 1109 ) ) ); + AddItem( Immovable( Rehued( new PlateArms(), 1109 ) ) ); + AddItem( Immovable( Rehued( new PlateGloves(), 1109 ) ) ); + AddItem( Immovable( Rehued( new PlateGorget(), 1109 ) ) ); + AddItem( Immovable( Rehued( new PlateHelm(), 1109 ) ) ); + + AddItem( Newbied( new WarHammer() ) ); + + AddItem( Immovable( Rehued( new VirtualMountItem( this ), 1109 ) ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionDragoon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionHenchman.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionHenchman.cs new file mode 100644 index 0000000..710cc47 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionHenchman.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionHenchman : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Melee; } } + + [Constructable] + public FactionHenchman() : base( "the henchman" ) + { + GenerateBody( false, true ); + + SetStr( 91, 115 ); + SetDex( 61, 85 ); + SetInt( 81, 95 ); + + SetDamage( 10, 14 ); + + SetResistance( ResistanceType.Physical, 10, 30 ); + SetResistance( ResistanceType.Fire, 10, 30 ); + SetResistance( ResistanceType.Cold, 10, 30 ); + SetResistance( ResistanceType.Energy, 10, 30 ); + SetResistance( ResistanceType.Poison, 10, 30 ); + + VirtualArmor = 8; + + SetSkill( SkillName.Fencing, 80.0, 90.0 ); + SetSkill( SkillName.Wrestling, 80.0, 90.0 ); + SetSkill( SkillName.Tactics, 80.0, 90.0 ); + SetSkill( SkillName.MagicResist, 80.0, 90.0 ); + SetSkill( SkillName.Healing, 80.0, 90.0 ); + SetSkill( SkillName.Anatomy, 80.0, 90.0 ); + + AddItem( new StuddedChest() ); + AddItem( new StuddedLegs() ); + AddItem( new StuddedArms() ); + AddItem( new StuddedGloves() ); + AddItem( new StuddedGorget() ); + AddItem( new Boots() ); + AddItem( Newbied( new Spear() ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 10, 20 ) ) ); + PackWeakPotions( 1, 4 ); + } + + public FactionHenchman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionKnight.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionKnight.cs new file mode 100644 index 0000000..e48aaaf --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionKnight.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionKnight : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Curse | GuardAI.Bless; } } + + [Constructable] + public FactionKnight() : base( "the knight" ) + { + GenerateBody( false, false ); + + SetStr( 126, 150 ); + SetDex( 61, 85 ); + SetInt( 81, 95 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 50 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Energy, 30, 50 ); + SetResistance( ResistanceType.Poison, 30, 50 ); + + VirtualArmor = 24; + + SetSkill( SkillName.Swords, 100.0, 110.0 ); + SetSkill( SkillName.Wrestling, 100.0, 110.0 ); + SetSkill( SkillName.Tactics, 100.0, 110.0 ); + SetSkill( SkillName.MagicResist, 100.0, 110.0 ); + SetSkill( SkillName.Healing, 100.0, 110.0 ); + SetSkill( SkillName.Anatomy, 100.0, 110.0 ); + + SetSkill( SkillName.Magery, 100.0, 110.0 ); + SetSkill( SkillName.EvalInt, 100.0, 110.0 ); + SetSkill( SkillName.Meditation, 100.0, 110.0 ); + + AddItem( Immovable( Rehued( new ChainChest(), 2125 ) ) ); + AddItem( Immovable( Rehued( new ChainLegs(), 2125 ) ) ); + AddItem( Immovable( Rehued( new ChainCoif(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateArms(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateGloves(), 2125 ) ) ); + + AddItem( Immovable( Rehued( new BodySash(), 1254 ) ) ); + AddItem( Immovable( Rehued( new Kilt(), 1254 ) ) ); + AddItem( Immovable( Rehued( new Sandals(), 1254 ) ) ); + + AddItem( Newbied( new Bardiche() ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionMercenary.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionMercenary.cs new file mode 100644 index 0000000..cb0c30d --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionMercenary.cs @@ -0,0 +1,65 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionMercenary : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Melee | GuardAI.Smart; } } + + [Constructable] + public FactionMercenary() : base( "the mercenary" ) + { + GenerateBody( false, true ); + + SetStr( 116, 125 ); + SetDex( 61, 85 ); + SetInt( 81, 95 ); + + SetResistance( ResistanceType.Physical, 20, 40 ); + SetResistance( ResistanceType.Fire, 20, 40 ); + SetResistance( ResistanceType.Cold, 20, 40 ); + SetResistance( ResistanceType.Energy, 20, 40 ); + SetResistance( ResistanceType.Poison, 20, 40 ); + + VirtualArmor = 16; + + SetSkill( SkillName.Fencing, 90.0, 100.0 ); + SetSkill( SkillName.Wrestling, 90.0, 100.0 ); + SetSkill( SkillName.Tactics, 90.0, 100.0 ); + SetSkill( SkillName.MagicResist, 90.0, 100.0 ); + SetSkill( SkillName.Healing, 90.0, 100.0 ); + SetSkill( SkillName.Anatomy, 90.0, 100.0 ); + + AddItem( new ChainChest() ); + AddItem( new ChainLegs() ); + AddItem( new RingmailArms() ); + AddItem( new RingmailGloves() ); + AddItem( new ChainCoif() ); + AddItem( new Boots() ); + AddItem( Newbied( new ShortSpear() ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 20, 30 ) ) ); + PackStrongPotions( 3, 8 ); + } + + public FactionMercenary( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionNecromancer.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionNecromancer.cs new file mode 100644 index 0000000..4a79a17 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionNecromancer.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionNecromancer : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Magic | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse; } } + + [Constructable] + public FactionNecromancer() : base( "the necromancer" ) + { + GenerateBody( false, false ); + Hue = 1; + + SetStr( 151, 175 ); + SetDex( 61, 85 ); + SetInt( 151, 175 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + + VirtualArmor = 32; + + SetSkill( SkillName.Macing, 110.0, 120.0 ); + SetSkill( SkillName.Wrestling, 110.0, 120.0 ); + SetSkill( SkillName.Tactics, 110.0, 120.0 ); + SetSkill( SkillName.MagicResist, 110.0, 120.0 ); + SetSkill( SkillName.Healing, 110.0, 120.0 ); + SetSkill( SkillName.Anatomy, 110.0, 120.0 ); + + SetSkill( SkillName.Magery, 110.0, 120.0 ); + SetSkill( SkillName.EvalInt, 110.0, 120.0 ); + SetSkill( SkillName.Meditation, 110.0, 120.0 ); + + Item shroud = new Item( 0x204E ); + shroud.Layer = Layer.OuterTorso; + + AddItem( Immovable( Rehued( shroud, 1109 ) ) ); + AddItem( Newbied( Rehued( new GnarledStaff(), 2211 ) ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionNecromancer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionPaladin.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionPaladin.cs new file mode 100644 index 0000000..2200085 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionPaladin.cs @@ -0,0 +1,76 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionPaladin : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Curse | GuardAI.Bless; } } + + [Constructable] + public FactionPaladin() : base( "the paladin" ) + { + GenerateBody( false, false ); + + SetStr( 151, 175 ); + SetDex( 61, 85 ); + SetInt( 81, 95 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + + VirtualArmor = 32; + + SetSkill( SkillName.Swords, 110.0, 120.0 ); + SetSkill( SkillName.Wrestling, 110.0, 120.0 ); + SetSkill( SkillName.Tactics, 110.0, 120.0 ); + SetSkill( SkillName.MagicResist, 110.0, 120.0 ); + SetSkill( SkillName.Healing, 110.0, 120.0 ); + SetSkill( SkillName.Anatomy, 110.0, 120.0 ); + + SetSkill( SkillName.Magery, 110.0, 120.0 ); + SetSkill( SkillName.EvalInt, 110.0, 120.0 ); + SetSkill( SkillName.Meditation, 110.0, 120.0 ); + + AddItem( Immovable( Rehued( new PlateChest(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateLegs(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateHelm(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateGorget(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateArms(), 2125 ) ) ); + AddItem( Immovable( Rehued( new PlateGloves(), 2125 ) ) ); + + AddItem( Immovable( Rehued( new BodySash(), 1254 ) ) ); + AddItem( Immovable( Rehued( new Cloak(), 1254 ) ) ); + + AddItem( Newbied( new Halberd() ) ); + + AddItem( Immovable( Rehued( new VirtualMountItem( this ), 1254 ) ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionPaladin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionSorceress.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionSorceress.cs new file mode 100644 index 0000000..627af3f --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionSorceress.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionSorceress : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Magic | GuardAI.Bless | GuardAI.Curse; } } + + [Constructable] + public FactionSorceress() : base( "the sorceress" ) + { + GenerateBody( true, false ); + + SetStr( 126, 150 ); + SetDex( 61, 85 ); + SetInt( 126, 150 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 50 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Energy, 30, 50 ); + SetResistance( ResistanceType.Poison, 30, 50 ); + + VirtualArmor = 24; + + SetSkill( SkillName.Macing, 100.0, 110.0 ); + SetSkill( SkillName.Wrestling, 100.0, 110.0 ); + SetSkill( SkillName.Tactics, 100.0, 110.0 ); + SetSkill( SkillName.MagicResist, 100.0, 110.0 ); + SetSkill( SkillName.Healing, 100.0, 110.0 ); + SetSkill( SkillName.Anatomy, 100.0, 110.0 ); + + SetSkill( SkillName.Magery, 100.0, 110.0 ); + SetSkill( SkillName.EvalInt, 100.0, 110.0 ); + SetSkill( SkillName.Meditation, 100.0, 110.0 ); + + AddItem( Immovable( Rehued( new WizardsHat(), 1325 ) ) ); + AddItem( Immovable( Rehued( new Sandals(), 1325 ) ) ); + AddItem( Immovable( Rehued( new LeatherGorget(), 1325 ) ) ); + AddItem( Immovable( Rehued( new LeatherGloves(), 1325 ) ) ); + AddItem( Immovable( Rehued( new LeatherLegs(), 1325 ) ) ); + AddItem( Immovable( Rehued( new Skirt(), 1325 ) ) ); + AddItem( Immovable( Rehued( new FemaleLeatherChest(), 1325 ) ) ); + AddItem( Newbied( Rehued( new QuarterStaff(), 1310 ) ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionSorceress( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionWizard.cs b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionWizard.cs new file mode 100644 index 0000000..8c780ac --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Guards/Types/FactionWizard.cs @@ -0,0 +1,69 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Factions +{ + public class FactionWizard : BaseFactionGuard + { + public override GuardAI GuardAI{ get{ return GuardAI.Magic | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse; } } + + [Constructable] + public FactionWizard() : base( "the wizard" ) + { + GenerateBody( false, false ); + + SetStr( 151, 175 ); + SetDex( 61, 85 ); + SetInt( 151, 175 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + + VirtualArmor = 32; + + SetSkill( SkillName.Macing, 110.0, 120.0 ); + SetSkill( SkillName.Wrestling, 110.0, 120.0 ); + SetSkill( SkillName.Tactics, 110.0, 120.0 ); + SetSkill( SkillName.MagicResist, 110.0, 120.0 ); + SetSkill( SkillName.Healing, 110.0, 120.0 ); + SetSkill( SkillName.Anatomy, 110.0, 120.0 ); + + SetSkill( SkillName.Magery, 110.0, 120.0 ); + SetSkill( SkillName.EvalInt, 110.0, 120.0 ); + SetSkill( SkillName.Meditation, 110.0, 120.0 ); + + AddItem( Immovable( Rehued( new WizardsHat(), 1325 ) ) ); + AddItem( Immovable( Rehued( new Sandals(), 1325 ) ) ); + AddItem( Immovable( Rehued( new Robe(), 1310 ) ) ); + AddItem( Immovable( Rehued( new LeatherGloves(), 1325 ) ) ); + AddItem( Newbied( Rehued( new GnarledStaff(), 1310 ) ) ); + + PackItem( new Bandage( Utility.RandomMinMax( 30, 40 ) ) ); + PackStrongPotions( 6, 12 ); + } + + public FactionWizard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Vendors/BaseFactionVendor.cs b/Scripts/Engines/Factions/Mobiles/Vendors/BaseFactionVendor.cs new file mode 100644 index 0000000..958957f --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Vendors/BaseFactionVendor.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Factions +{ + public abstract class BaseFactionVendor : BaseVendor + { + private Town m_Town; + private Faction m_Faction; + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Town Town + { + get{ return m_Town; } + set{ Unregister(); m_Town = value; Register(); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public Faction Faction + { + get{ return m_Faction; } + set{ Unregister(); m_Faction = value; Register(); } + } + + public void Register() + { + if ( m_Town != null && m_Faction != null ) + m_Town.RegisterVendor( this ); + } + + public override bool OnMoveOver( Mobile m ) + { + if ( Core.ML ) + return true; + + return base.OnMoveOver( m ); + } + + public void Unregister() + { + if ( m_Town != null ) + m_Town.UnregisterVendor( this ); + } + + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override void InitSBInfo() + { + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + Unregister(); + } + + public override bool CheckVendorAccess( Mobile from ) + { + return true; + } + + public BaseFactionVendor( Town town, Faction faction, string title ) : base( title ) + { + Frozen = true; + CantWalk = true; + Female = false; + BodyValue = 400; + Name = NameList.RandomName( "male" ); + + RangeHome = 0; + + m_Town = town; + m_Faction = faction; + Register(); + } + + public BaseFactionVendor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Town.WriteReference( writer, m_Town ); + Faction.WriteReference( writer, m_Faction ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Town = Town.ReadReference( reader ); + m_Faction = Faction.ReadReference( reader ); + Register(); + break; + } + } + + Frozen = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Vendors/FactionBoardVendor.cs b/Scripts/Engines/Factions/Mobiles/Vendors/FactionBoardVendor.cs new file mode 100644 index 0000000..342835b --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Vendors/FactionBoardVendor.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionBoardVendor : BaseFactionVendor + { + public FactionBoardVendor( Town town, Faction faction ) : base( town, faction, "the LumberMan" ) // NOTE: title inconsistant, as OSI + { + SetSkill( SkillName.Carpentry, 85.0, 100.0 ); + SetSkill( SkillName.Lumberjacking, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + SBInfos.Add( new SBFactionBoard() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new HalfApron() ); + } + + public FactionBoardVendor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SBFactionBoard : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFactionBoard() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + for ( int i = 0; i < 5; ++i ) + Add( new GenericBuyInfo( typeof( Board ), 3, 20, 0x1BD7, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Vendors/FactionBottleVendor.cs b/Scripts/Engines/Factions/Mobiles/Vendors/FactionBottleVendor.cs new file mode 100644 index 0000000..0f1d1ca --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Vendors/FactionBottleVendor.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionBottleVendor : BaseFactionVendor + { + public FactionBottleVendor( Town town, Faction faction ) : base( town, faction, "the Bottle Seller" ) + { + SetSkill( SkillName.Alchemy, 85.0, 100.0 ); + SetSkill( SkillName.TasteID, 65.0, 88.0 ); + } + + public override void InitSBInfo() + { + SBInfos.Add( new SBFactionBottle() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Robe( Utility.RandomPinkHue() ) ); + } + + public FactionBottleVendor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SBFactionBottle : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFactionBottle() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + for ( int i = 0; i < 5; ++i ) + Add( new GenericBuyInfo( typeof( Bottle ), 5, 20, 0xF0E, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Vendors/FactionHorseVendor.cs b/Scripts/Engines/Factions/Mobiles/Vendors/FactionHorseVendor.cs new file mode 100644 index 0000000..f1a84f8 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Vendors/FactionHorseVendor.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Factions +{ + public class FactionHorseVendor : BaseFactionVendor + { + public FactionHorseVendor( Town town, Faction faction ) : base( town, faction, "the Horse Breeder" ) + { + SetSkill( SkillName.AnimalLore, 64.0, 100.0 ); + SetSkill( SkillName.AnimalTaming, 90.0, 100.0 ); + SetSkill( SkillName.Veterinary, 65.0, 88.0 ); + } + + public override void InitSBInfo() + { + } + + public override VendorShoeType ShoeType + { + get{ return Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( Utility.RandomBool() ? (Item)new QuarterStaff() : (Item)new ShepherdsCrook() ); + } + + public FactionHorseVendor( Serial serial ) : base( serial ) + { + } + + public override void VendorBuy( Mobile from ) + { + if ( this.Faction == null || Faction.Find( from, true ) != this.Faction ) + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1042201, from.NetState ); // You are not in my faction, I cannot sell you a horse! + else if ( FactionGump.Exists( from ) ) + from.SendLocalizedMessage( 1042160 ); // You already have a faction menu open. + else if ( from is PlayerMobile ) + from.SendGump( new HorseBreederGump( (PlayerMobile) from, this.Faction ) ); + } + + public override void VendorSell( Mobile from ) + { + } + + public override bool OnBuyItems( Mobile buyer, List list ) + { + return false; + } + + public override bool OnSellItems( Mobile seller, List list ) + { + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Vendors/FactionOreVendor.cs b/Scripts/Engines/Factions/Mobiles/Vendors/FactionOreVendor.cs new file mode 100644 index 0000000..1873e0c --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Vendors/FactionOreVendor.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionOreVendor : BaseFactionVendor + { + public FactionOreVendor( Town town, Faction faction ) : base( town, faction, "the Ore Man" ) + { + // NOTE: Skills verified + SetSkill( SkillName.Carpentry, 85.0, 100.0 ); + SetSkill( SkillName.Lumberjacking, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + SBInfos.Add( new SBFactionOre() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new HalfApron() ); + } + + public FactionOreVendor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SBFactionOre : SBInfo + { + private static readonly object[] m_FixedSizeArgs = { true }; + + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFactionOre() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + for ( int i = 0; i < 5; ++i ) + Add(new GenericBuyInfo(typeof(IronOre), 16, 20, 0x19B8, 0, m_FixedSizeArgs)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Factions/Mobiles/Vendors/FactionReagentVendor.cs b/Scripts/Engines/Factions/Mobiles/Vendors/FactionReagentVendor.cs new file mode 100644 index 0000000..f8beaa9 --- /dev/null +++ b/Scripts/Engines/Factions/Mobiles/Vendors/FactionReagentVendor.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Factions +{ + public class FactionReagentVendor : BaseFactionVendor + { + public FactionReagentVendor( Town town, Faction faction ) : base( town, faction, "the Reagent Man" ) + { + SetSkill( SkillName.EvalInt, 65.0, 88.0 ); + SetSkill( SkillName.Inscribe, 60.0, 83.0 ); + SetSkill( SkillName.Magery, 64.0, 100.0 ); + SetSkill( SkillName.Meditation, 60.0, 83.0 ); + SetSkill( SkillName.MagicResist, 65.0, 88.0 ); + SetSkill( SkillName.Wrestling, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + SBInfos.Add( new SBFactionReagent() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Robe( Utility.RandomBlueHue() ) ); + AddItem( new GnarledStaff() ); + } + + public FactionReagentVendor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SBFactionReagent : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFactionReagent() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + for ( int i = 0; i < 2; ++i ) + { + Add( new GenericBuyInfo( typeof( BlackPearl ), 5, 20, 0xF7A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 20, 0xF8C, 0 ) ); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/BonusHarvestResource.cs b/Scripts/Engines/Harvest/Core/BonusHarvestResource.cs new file mode 100644 index 0000000..8a2337e --- /dev/null +++ b/Scripts/Engines/Harvest/Core/BonusHarvestResource.cs @@ -0,0 +1,31 @@ +using System; + +namespace Server.Engines.Harvest +{ + public class BonusHarvestResource + { + private Type m_Type; + private double m_ReqSkill, m_Chance; + private TextDefinition m_SuccessMessage; + + public Type Type { get { return m_Type; } set { m_Type = value; } } + public double ReqSkill { get { return m_ReqSkill; } set { m_ReqSkill = value; } } + public double Chance { get { return m_Chance; } set { m_Chance = value; } } + + public TextDefinition SuccessMessage { get { return m_SuccessMessage; } } + + public void SendSuccessTo( Mobile m ) + { + TextDefinition.SendMessageTo( m, m_SuccessMessage ); + } + + public BonusHarvestResource( double reqSkill, double chance, TextDefinition message, Type type ) + { + m_ReqSkill = reqSkill; + + m_Chance = chance; + m_Type = type; + m_SuccessMessage = message; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestBank.cs b/Scripts/Engines/Harvest/Core/HarvestBank.cs new file mode 100644 index 0000000..16770db --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestBank.cs @@ -0,0 +1,102 @@ +using System; + +namespace Server.Engines.Harvest +{ + public class HarvestBank + { + private int m_Current; + private int m_Maximum; + private DateTime m_NextRespawn; + private HarvestVein m_Vein, m_DefaultVein; + + HarvestDefinition m_Definition; + + public HarvestDefinition Definition + { + get { return m_Definition; } + } + + public int Current + { + get + { + CheckRespawn(); + return m_Current; + } + } + + public HarvestVein Vein + { + get + { + CheckRespawn(); + return m_Vein; + } + set + { + m_Vein = value; + } + } + + public HarvestVein DefaultVein + { + get + { + CheckRespawn(); + return m_DefaultVein; + } + } + + public void CheckRespawn() + { + if ( m_Current == m_Maximum || m_NextRespawn > DateTime.Now ) + return; + + m_Current = m_Maximum; + + if ( m_Definition.RandomizeVeins ) + { + m_DefaultVein = m_Definition.GetVeinFrom( Utility.RandomDouble() ); + } + + m_Vein = m_DefaultVein; + } + + public void Consume( int amount, Mobile from ) + { + CheckRespawn(); + + if ( m_Current == m_Maximum ) + { + double min = m_Definition.MinRespawn.TotalMinutes; + double max = m_Definition.MaxRespawn.TotalMinutes; + double rnd = Utility.RandomDouble(); + + m_Current = m_Maximum - amount; + + double minutes = min + (rnd * (max - min)); + if ( m_Definition.RaceBonus && from.Race == Race.Elf ) //def.RaceBonus = Core.ML + minutes *= .75; //25% off the time. + + m_NextRespawn = DateTime.Now + TimeSpan.FromMinutes( minutes ); + } + else + { + m_Current -= amount; + } + + if ( m_Current < 0 ) + m_Current = 0; + } + + public HarvestBank( HarvestDefinition def, HarvestVein defaultVein ) + { + m_Maximum = Utility.RandomMinMax( def.MinTotal, def.MaxTotal ); + m_Current = m_Maximum; + m_DefaultVein = defaultVein; + m_Vein = m_DefaultVein; + + m_Definition = def; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestDefinition.cs b/Scripts/Engines/Harvest/Core/HarvestDefinition.cs new file mode 100644 index 0000000..a3c5c00 --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestDefinition.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; + +namespace Server.Engines.Harvest +{ + public class HarvestDefinition + { + private int m_BankWidth, m_BankHeight; + private int m_MinTotal, m_MaxTotal; + private int[] m_Tiles; + private bool m_RangedTiles; + private TimeSpan m_MinRespawn, m_MaxRespawn; + private int m_MaxRange; + private int m_ConsumedPerHarvest, m_ConsumedPerFeluccaHarvest; + private bool m_PlaceAtFeetIfFull; + private SkillName m_Skill; + private int[] m_EffectActions; + private int[] m_EffectCounts; + private int[] m_EffectSounds; + private TimeSpan m_EffectSoundDelay; + private TimeSpan m_EffectDelay; + private object m_NoResourcesMessage, m_OutOfRangeMessage, m_TimedOutOfRangeMessage, m_DoubleHarvestMessage, m_FailMessage, m_PackFullMessage, m_ToolBrokeMessage; + private HarvestResource[] m_Resources; + private HarvestVein[] m_Veins; + private BonusHarvestResource[] m_BonusResources; + private bool m_RaceBonus; + private bool m_RandomizeVeins; + + public int BankWidth{ get{ return m_BankWidth; } set{ m_BankWidth = value; } } + public int BankHeight{ get{ return m_BankHeight; } set{ m_BankHeight = value; } } + public int MinTotal{ get{ return m_MinTotal; } set{ m_MinTotal = value; } } + public int MaxTotal{ get{ return m_MaxTotal; } set{ m_MaxTotal = value; } } + public int[] Tiles{ get{ return m_Tiles; } set{ m_Tiles = value; } } + public bool RangedTiles{ get{ return m_RangedTiles; } set{ m_RangedTiles = value; } } + public TimeSpan MinRespawn{ get{ return m_MinRespawn; } set{ m_MinRespawn = value; } } + public TimeSpan MaxRespawn{ get{ return m_MaxRespawn; } set{ m_MaxRespawn = value; } } + public int MaxRange{ get{ return m_MaxRange; } set{ m_MaxRange = value; } } + public int ConsumedPerHarvest{ get{ return m_ConsumedPerHarvest; } set{ m_ConsumedPerHarvest = value; } } + public int ConsumedPerFeluccaHarvest{ get{ return m_ConsumedPerFeluccaHarvest; } set{ m_ConsumedPerFeluccaHarvest = value; } } + public bool PlaceAtFeetIfFull{ get{ return m_PlaceAtFeetIfFull; } set{ m_PlaceAtFeetIfFull = value; } } + public SkillName Skill{ get{ return m_Skill; } set{ m_Skill = value; } } + public int[] EffectActions{ get{ return m_EffectActions; } set{ m_EffectActions = value; } } + public int[] EffectCounts{ get{ return m_EffectCounts; } set{ m_EffectCounts = value; } } + public int[] EffectSounds{ get{ return m_EffectSounds; } set{ m_EffectSounds = value; } } + public TimeSpan EffectSoundDelay{ get{ return m_EffectSoundDelay; } set{ m_EffectSoundDelay = value; } } + public TimeSpan EffectDelay{ get{ return m_EffectDelay; } set{ m_EffectDelay = value; } } + public object NoResourcesMessage{ get{ return m_NoResourcesMessage; } set{ m_NoResourcesMessage = value; } } + public object OutOfRangeMessage{ get{ return m_OutOfRangeMessage; } set{ m_OutOfRangeMessage = value; } } + public object TimedOutOfRangeMessage{ get{ return m_TimedOutOfRangeMessage; } set{ m_TimedOutOfRangeMessage = value; } } + public object DoubleHarvestMessage{ get{ return m_DoubleHarvestMessage; } set{ m_DoubleHarvestMessage = value; } } + public object FailMessage{ get{ return m_FailMessage; } set{ m_FailMessage = value; } } + public object PackFullMessage{ get{ return m_PackFullMessage; } set{ m_PackFullMessage = value; } } + public object ToolBrokeMessage{ get{ return m_ToolBrokeMessage; } set{ m_ToolBrokeMessage = value; } } + public HarvestResource[] Resources{ get{ return m_Resources; } set{ m_Resources = value; } } + public HarvestVein[] Veins{ get{ return m_Veins; } set{ m_Veins = value; } } + public BonusHarvestResource[] BonusResources{ get { return m_BonusResources; } set { m_BonusResources = value; } } + public bool RaceBonus { get { return m_RaceBonus; } set { m_RaceBonus = value; } } + public bool RandomizeVeins { get { return m_RandomizeVeins; } set { m_RandomizeVeins = value; } } + + private Dictionary> m_BanksByMap; + + public Dictionary> Banks{ get{ return m_BanksByMap; } set{ m_BanksByMap = value; } } + + public void SendMessageTo( Mobile from, object message ) + { + if ( message is int ) + from.SendLocalizedMessage( (int)message ); + else if ( message is string ) + from.SendMessage( (string)message ); + } + + public HarvestBank GetBank( Map map, int x, int y ) + { + if ( map == null || map == Map.Internal ) + return null; + + x /= m_BankWidth; + y /= m_BankHeight; + + Dictionary banks = null; + m_BanksByMap.TryGetValue( map, out banks ); + + if ( banks == null ) + m_BanksByMap[map] = banks = new Dictionary(); + + Point2D key = new Point2D( x, y ); + HarvestBank bank = null; + banks.TryGetValue( key, out bank ); + + if ( bank == null ) + banks[key] = bank = new HarvestBank( this, GetVeinAt( map, x, y ) ); + + return bank; + } + + public HarvestVein GetVeinAt( Map map, int x, int y ) + { + if ( m_Veins.Length == 1 ) + return m_Veins[0]; + + double randomValue; + + if ( m_RandomizeVeins ) + { + randomValue = Utility.RandomDouble(); + } + else + { + Random random = new Random( ( x * 17 ) + ( y * 11 ) + ( map.MapID * 3 ) ); + randomValue = random.NextDouble(); + } + + return GetVeinFrom( randomValue ); + } + + public HarvestVein GetVeinFrom( double randomValue ) + { + if ( m_Veins.Length == 1 ) + return m_Veins[0]; + + randomValue *= 100; + + for ( int i = 0; i < m_Veins.Length; ++i ) + { + if ( randomValue <= m_Veins[i].VeinChance ) + return m_Veins[i]; + + randomValue -= m_Veins[i].VeinChance; + } + + return null; + } + + public BonusHarvestResource GetBonusResource() + { + if ( m_BonusResources == null ) + return null; + + double randomValue = Utility.RandomDouble() * 100; + + for ( int i = 0; i < m_BonusResources.Length; ++i ) + { + if ( randomValue <= m_BonusResources[i].Chance ) + return m_BonusResources[i]; + + randomValue -= m_BonusResources[i].Chance; + } + + return null; + } + + public HarvestDefinition() + { + m_BanksByMap = new Dictionary>(); + } + + public bool Validate( int tileID ) + { + if ( m_RangedTiles ) + { + bool contains = false; + + for ( int i = 0; !contains && i < m_Tiles.Length; i += 2 ) + contains = ( tileID >= m_Tiles[i] && tileID <= m_Tiles[i + 1] ); + + return contains; + } + else + { + int dist = -1; + + for ( int i = 0; dist < 0 && i < m_Tiles.Length; ++i ) + dist = ( m_Tiles[i] - tileID ); + + return ( dist == 0 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestResource.cs b/Scripts/Engines/Harvest/Core/HarvestResource.cs new file mode 100644 index 0000000..fe6b1f3 --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestResource.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Engines.Harvest +{ + public class HarvestResource + { + private Type[] m_Types; + private double m_ReqSkill, m_MinSkill, m_MaxSkill; + private object m_SuccessMessage; + + public Type[] Types{ get{ return m_Types; } set{ m_Types = value; } } + public double ReqSkill{ get{ return m_ReqSkill; } set{ m_ReqSkill = value; } } + public double MinSkill{ get{ return m_MinSkill; } set{ m_MinSkill = value; } } + public double MaxSkill{ get{ return m_MaxSkill; } set{ m_MaxSkill = value; } } + public object SuccessMessage{ get{ return m_SuccessMessage; } } + + public void SendSuccessTo( Mobile m ) + { + if ( m_SuccessMessage is int ) + m.SendLocalizedMessage( (int)m_SuccessMessage ); + else if ( m_SuccessMessage is string ) + m.SendMessage( (string)m_SuccessMessage ); + } + + public HarvestResource( double reqSkill, double minSkill, double maxSkill, object message, params Type[] types ) + { + m_ReqSkill = reqSkill; + m_MinSkill = minSkill; + m_MaxSkill = maxSkill; + m_Types = types; + m_SuccessMessage = message; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestSoundTimer.cs b/Scripts/Engines/Harvest/Core/HarvestSoundTimer.cs new file mode 100644 index 0000000..fd811f5 --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestSoundTimer.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Engines.Harvest +{ + public class HarvestSoundTimer : Timer + { + private Mobile m_From; + private Item m_Tool; + private HarvestSystem m_System; + private HarvestDefinition m_Definition; + private object m_ToHarvest, m_Locked; + private bool m_Last; + + public HarvestSoundTimer( Mobile from, Item tool, HarvestSystem system, HarvestDefinition def, object toHarvest, object locked, bool last ) : base( def.EffectSoundDelay ) + { + m_From = from; + m_Tool = tool; + m_System = system; + m_Definition = def; + m_ToHarvest = toHarvest; + m_Locked = locked; + m_Last = last; + } + + protected override void OnTick() + { + m_System.DoHarvestingSound( m_From, m_Tool, m_Definition, m_ToHarvest ); + + if ( m_Last ) + m_System.FinishHarvesting( m_From, m_Tool, m_Definition, m_ToHarvest, m_Locked ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestSystem.cs b/Scripts/Engines/Harvest/Core/HarvestSystem.cs new file mode 100644 index 0000000..defbd6f --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestSystem.cs @@ -0,0 +1,515 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Engines.Harvest +{ + public abstract class HarvestSystem + { + private List m_Definitions; + + public List Definitions { get { return m_Definitions; } } + + public HarvestSystem() + { + m_Definitions = new List(); + } + + public virtual bool CheckTool( Mobile from, Item tool ) + { + bool wornOut = ( tool == null || tool.Deleted || (tool is IUsesRemaining && ((IUsesRemaining)tool).UsesRemaining <= 0) ); + + if ( wornOut ) + from.SendLocalizedMessage( 1044038 ); // You have worn out your tool! + + return !wornOut; + } + + public virtual bool CheckHarvest( Mobile from, Item tool ) + { + return CheckTool( from, tool ); + } + + public virtual bool CheckHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + return CheckTool( from, tool ); + } + + public virtual bool CheckRange( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, bool timed ) + { + bool inRange = ( from.Map == map && from.InRange( loc, def.MaxRange ) ); + + if ( !inRange ) + def.SendMessageTo( from, timed ? def.TimedOutOfRangeMessage : def.OutOfRangeMessage ); + + return inRange; + } + + public virtual bool CheckResources( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, bool timed ) + { + HarvestBank bank = def.GetBank( map, loc.X, loc.Y ); + bool available = ( bank != null && bank.Current >= def.ConsumedPerHarvest ); + + if ( !available ) + def.SendMessageTo( from, timed ? def.DoubleHarvestMessage : def.NoResourcesMessage ); + + return available; + } + + public virtual void OnBadHarvestTarget( Mobile from, Item tool, object toHarvest ) + { + } + + public virtual object GetLock( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + /* Here we prevent multiple harvesting. + * + * Some options: + * - 'return tool;' : This will allow the player to harvest more than once concurrently, but only if they use multiple tools. This seems to be as OSI. + * - 'return GetType();' : This will disallow multiple harvesting of the same type. That is, we couldn't mine more than once concurrently, but we could be both mining and lumberjacking. + * - 'return typeof( HarvestSystem );' : This will completely restrict concurrent harvesting. + */ + + return tool; + } + + public virtual void OnConcurrentHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + } + + public virtual void OnHarvestStarted( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + } + + public virtual bool BeginHarvesting( Mobile from, Item tool ) + { + if ( !CheckHarvest( from, tool ) ) + return false; + + from.Target = new HarvestTarget( tool, this ); + return true; + } + + public virtual void FinishHarvesting( Mobile from, Item tool, HarvestDefinition def, object toHarvest, object locked ) + { + from.EndAction( locked ); + + if ( !CheckHarvest( from, tool ) ) + return; + + int tileID; + Map map; + Point3D loc; + + if ( !GetHarvestDetails( from, tool, toHarvest, out tileID, out map, out loc ) ) + { + OnBadHarvestTarget( from, tool, toHarvest ); + return; + } + else if ( !def.Validate( tileID ) ) + { + OnBadHarvestTarget( from, tool, toHarvest ); + return; + } + + if ( !CheckRange( from, tool, def, map, loc, true ) ) + return; + else if ( !CheckResources( from, tool, def, map, loc, true ) ) + return; + else if ( !CheckHarvest( from, tool, def, toHarvest ) ) + return; + + if ( SpecialHarvest( from, tool, def, map, loc ) ) + return; + + HarvestBank bank = def.GetBank( map, loc.X, loc.Y ); + + if ( bank == null ) + return; + + HarvestVein vein = bank.Vein; + + if ( vein != null ) + vein = MutateVein( from, tool, def, bank, toHarvest, vein ); + + if ( vein == null ) + return; + + HarvestResource primary = vein.PrimaryResource; + HarvestResource fallback = vein.FallbackResource; + HarvestResource resource = MutateResource( from, tool, def, map, loc, vein, primary, fallback ); + + double skillBase = from.Skills[def.Skill].Base; + double skillValue = from.Skills[def.Skill].Value; + + Type type = null; + + if ( skillBase >= resource.ReqSkill && from.CheckSkill( def.Skill, resource.MinSkill, resource.MaxSkill ) ) + { + type = GetResourceType( from, tool, def, map, loc, resource ); + + if ( type != null ) + type = MutateType( type, from, tool, def, map, loc, resource ); + + if ( type != null ) + { + Item item = Construct( type, from ); + + if ( item == null ) + { + type = null; + } + else + { + //The whole harvest system is kludgy and I'm sure this is just adding to it. + if ( item.Stackable ) + { + int amount = def.ConsumedPerHarvest; + int feluccaAmount = def.ConsumedPerFeluccaHarvest; + + int racialAmount = (int)Math.Ceiling( amount * 1.1 ); + int feluccaRacialAmount = (int)Math.Ceiling( feluccaAmount * 1.1 ); + + bool eligableForRacialBonus = ( def.RaceBonus && from.Race == Race.Human ); + bool inFelucca = (map == Map.Felucca); + + if( eligableForRacialBonus && inFelucca && bank.Current >= feluccaRacialAmount && 0.1 > Utility.RandomDouble() ) + item.Amount = feluccaRacialAmount; + else if( inFelucca && bank.Current >= feluccaAmount ) + item.Amount = feluccaAmount; + else if( eligableForRacialBonus && bank.Current >= racialAmount && 0.1 > Utility.RandomDouble() ) + item.Amount = racialAmount; + else + item.Amount = amount; + } + + bank.Consume( item.Amount, from ); + + if ( Give( from, item, def.PlaceAtFeetIfFull ) ) + { + SendSuccessTo( from, item, resource ); + } + else + { + SendPackFullTo( from, item, def, resource ); + item.Delete(); + } + + BonusHarvestResource bonus = def.GetBonusResource(); + + if ( bonus != null && bonus.Type != null && skillBase >= bonus.ReqSkill ) + { + Item bonusItem = Construct( bonus.Type, from ); + + if ( Give( from, bonusItem, true ) ) //Bonuses always allow placing at feet, even if pack is full irregrdless of def + { + bonus.SendSuccessTo( from ); + } + else + { + item.Delete(); + } + } + + if ( tool is IUsesRemaining ) + { + IUsesRemaining toolWithUses = (IUsesRemaining)tool; + + toolWithUses.ShowUsesRemaining = true; + + if ( toolWithUses.UsesRemaining > 0 ) + --toolWithUses.UsesRemaining; + + if ( toolWithUses.UsesRemaining < 1 ) + { + tool.Delete(); + def.SendMessageTo( from, def.ToolBrokeMessage ); + } + } + } + } + } + + if ( type == null ) + def.SendMessageTo( from, def.FailMessage ); + + OnHarvestFinished( from, tool, def, vein, bank, resource, toHarvest ); + } + + public virtual void OnHarvestFinished( Mobile from, Item tool, HarvestDefinition def, HarvestVein vein, HarvestBank bank, HarvestResource resource, object harvested ) + { + } + + public virtual bool SpecialHarvest( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc ) + { + return false; + } + + public virtual Item Construct( Type type, Mobile from ) + { + try{ return Activator.CreateInstance( type ) as Item; } + catch{ return null; } + } + + public virtual HarvestVein MutateVein( Mobile from, Item tool, HarvestDefinition def, HarvestBank bank, object toHarvest, HarvestVein vein ) + { + return vein; + } + + public virtual void SendSuccessTo( Mobile from, Item item, HarvestResource resource ) + { + resource.SendSuccessTo( from ); + } + + public virtual void SendPackFullTo( Mobile from, Item item, HarvestDefinition def, HarvestResource resource ) + { + def.SendMessageTo( from, def.PackFullMessage ); + } + + public virtual bool Give( Mobile m, Item item, bool placeAtFeet ) + { + if ( m.PlaceInBackpack( item ) ) + return true; + + if ( !placeAtFeet ) + return false; + + Map map = m.Map; + + if ( map == null ) + return false; + + List atFeet = new List(); + + foreach ( Item obj in m.GetItemsInRange( 0 ) ) + atFeet.Add( obj ); + + for ( int i = 0; i < atFeet.Count; ++i ) + { + Item check = atFeet[i]; + + if ( check.StackWith( m, item, false ) ) + return true; + } + + item.MoveToWorld( m.Location, map ); + return true; + } + + public virtual Type MutateType( Type type, Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource ) + { + return from.Region.GetResource( type ); + } + + public virtual Type GetResourceType( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource ) + { + if ( resource.Types.Length > 0 ) + return resource.Types[Utility.Random( resource.Types.Length )]; + + return null; + } + + public virtual HarvestResource MutateResource( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestVein vein, HarvestResource primary, HarvestResource fallback ) + { + bool racialBonus = (def.RaceBonus && from.Race == Race.Elf ); + + if( vein.ChanceToFallback > (Utility.RandomDouble() + (racialBonus ? .20 : 0)) ) + return fallback; + + double skillValue = from.Skills[def.Skill].Value; + + if ( fallback != null && (skillValue < primary.ReqSkill || skillValue < primary.MinSkill) ) + return fallback; + + return primary; + } + + public virtual bool OnHarvesting( Mobile from, Item tool, HarvestDefinition def, object toHarvest, object locked, bool last ) + { + if ( !CheckHarvest( from, tool ) ) + { + from.EndAction( locked ); + return false; + } + + int tileID; + Map map; + Point3D loc; + + if ( !GetHarvestDetails( from, tool, toHarvest, out tileID, out map, out loc ) ) + { + from.EndAction( locked ); + OnBadHarvestTarget( from, tool, toHarvest ); + return false; + } + else if ( !def.Validate( tileID ) ) + { + from.EndAction( locked ); + OnBadHarvestTarget( from, tool, toHarvest ); + return false; + } + else if ( !CheckRange( from, tool, def, map, loc, true ) ) + { + from.EndAction( locked ); + return false; + } + else if ( !CheckResources( from, tool, def, map, loc, true ) ) + { + from.EndAction( locked ); + return false; + } + else if ( !CheckHarvest( from, tool, def, toHarvest ) ) + { + from.EndAction( locked ); + return false; + } + + DoHarvestingEffect( from, tool, def, map, loc ); + + new HarvestSoundTimer( from, tool, this, def, toHarvest, locked, last ).Start(); + + return !last; + } + + public virtual void DoHarvestingSound( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + if ( def.EffectSounds.Length > 0 ) + from.PlaySound( Utility.RandomList( def.EffectSounds ) ); + } + + public virtual void DoHarvestingEffect( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc ) + { + from.Direction = from.GetDirectionTo( loc ); + + if ( !from.Mounted ) + from.Animate( Utility.RandomList( def.EffectActions ), 5, 1, true, false, 0 ); + } + + public virtual HarvestDefinition GetDefinition( int tileID ) + { + HarvestDefinition def = null; + + for ( int i = 0; def == null && i < m_Definitions.Count; ++i ) + { + HarvestDefinition check = m_Definitions[i]; + + if ( check.Validate( tileID ) ) + def = check; + } + + return def; + } + + public virtual void StartHarvesting( Mobile from, Item tool, object toHarvest ) + { + if ( !CheckHarvest( from, tool ) ) + return; + + int tileID; + Map map; + Point3D loc; + + if ( !GetHarvestDetails( from, tool, toHarvest, out tileID, out map, out loc ) ) + { + OnBadHarvestTarget( from, tool, toHarvest ); + return; + } + + HarvestDefinition def = GetDefinition( tileID ); + + if ( def == null ) + { + OnBadHarvestTarget( from, tool, toHarvest ); + return; + } + + if ( !CheckRange( from, tool, def, map, loc, false ) ) + return; + else if ( !CheckResources( from, tool, def, map, loc, false ) ) + return; + else if ( !CheckHarvest( from, tool, def, toHarvest ) ) + return; + + object toLock = GetLock( from, tool, def, toHarvest ); + + if ( !from.BeginAction( toLock ) ) + { + OnConcurrentHarvest( from, tool, def, toHarvest ); + return; + } + + new HarvestTimer( from, tool, this, def, toHarvest, toLock ).Start(); + OnHarvestStarted( from, tool, def, toHarvest ); + } + + public virtual bool GetHarvestDetails( Mobile from, Item tool, object toHarvest, out int tileID, out Map map, out Point3D loc ) + { + if ( toHarvest is Static && !((Static)toHarvest).Movable ) + { + Static obj = (Static)toHarvest; + + tileID = (obj.ItemID & 0x3FFF) | 0x4000; + map = obj.Map; + loc = obj.GetWorldLocation(); + } + else if ( toHarvest is StaticTarget ) + { + StaticTarget obj = (StaticTarget)toHarvest; + + tileID = (obj.ItemID & 0x3FFF) | 0x4000; + map = from.Map; + loc = obj.Location; + } + else if ( toHarvest is LandTarget ) + { + LandTarget obj = (LandTarget)toHarvest; + + tileID = obj.TileID; + map = from.Map; + loc = obj.Location; + } + else + { + tileID = 0; + map = null; + loc = Point3D.Zero; + return false; + } + + return ( map != null && map != Map.Internal ); + } + } +} + +namespace Server +{ + public interface IChopable + { + void OnChop( Mobile from ); + } + + [AttributeUsage( AttributeTargets.Class )] + public class FurnitureAttribute : Attribute + { + public static bool Check( Item item ) + { + // Scriptiz : pour autoriser le dye sur les fournitures Addon ! + if (item is AddonComponent && item != null) + { + AddonComponent acc = item as AddonComponent; + + return (acc.Addon != null && acc.Addon.GetType().IsDefined(typeof(FurnitureAttribute), false)); + } + // Scriptiz : fin modif + + return ( item != null && item.GetType().IsDefined( typeof( FurnitureAttribute ), false ) ); + } + + public FurnitureAttribute() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestTarget.cs b/Scripts/Engines/Harvest/Core/HarvestTarget.cs new file mode 100644 index 0000000..aafeb7a --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestTarget.cs @@ -0,0 +1,114 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Multis; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Hag; + +namespace Server.Engines.Harvest +{ + public class HarvestTarget : Target + { + private Item m_Tool; + private HarvestSystem m_System; + + public HarvestTarget( Item tool, HarvestSystem system ) : base( -1, true, TargetFlags.None ) + { + m_Tool = tool; + m_System = system; + + DisallowMultis = true; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + // Scriptiz : ajout pour casser les FriableRock(s) + if (m_System is Mining && targeted is FriableRock) + { + ((FriableRock)targeted).OnHit(from, m_Tool); + return; + } + + if ( m_System is Mining && targeted is StaticTarget ) + { + int itemID = ((StaticTarget)targeted).ItemID; + + // grave + if ( itemID == 0xED3 || itemID == 0xEDF || itemID == 0xEE0 || itemID == 0xEE1 || itemID == 0xEE2 || itemID == 0xEE8 ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + FindIngredientObjective obj = qs.FindObjective( typeof( FindIngredientObjective ) ) as FindIngredientObjective; + + if ( obj != null && !obj.Completed && obj.Ingredient == Ingredient.Bones ) + { + player.SendLocalizedMessage( 1055037 ); // You finish your grim work, finding some of the specific bones listed in the Hag's recipe. + obj.Complete(); + + return; + } + } + } + } + } + + if ( m_System is Lumberjacking && targeted is IChopable ) + ((IChopable)targeted).OnChop( from ); + else if ( m_System is Lumberjacking && targeted is IAxe && m_Tool is BaseAxe ) + { + IAxe obj = (IAxe)targeted; + Item item = (Item)targeted; + + if ( !item.IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + else if ( obj.Axe( from, (BaseAxe)m_Tool ) ) + from.PlaySound( 0x13E ); + } + else if ( m_System is Lumberjacking && targeted is ICarvable ) + ((ICarvable)targeted).Carve( from, (Item)m_Tool ); + else if ( m_System is Lumberjacking && FurnitureAttribute.Check( targeted as Item ) ) + DestroyFurniture( from, (Item)targeted ); + else if ( m_System is Mining && targeted is TreasureMap ) + ((TreasureMap)targeted).OnBeginDig( from ); + else + m_System.StartHarvesting( from, m_Tool, targeted ); + } + + private void DestroyFurniture( Mobile from, Item item ) + { + if ( !from.InRange( item.GetWorldLocation(), 3 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + else if ( !item.IsChildOf( from.Backpack ) && !item.Movable ) + { + from.SendLocalizedMessage( 500462 ); // You can't destroy that while it is here. + return; + } + + from.SendLocalizedMessage( 500461 ); // You destroy the item. + Effects.PlaySound( item.GetWorldLocation(), item.Map, 0x3B3 ); + + if ( item is Container ) + { + if ( item is TrapableContainer ) + (item as TrapableContainer).ExecuteTrap( from ); + + ((Container)item).Destroy(); + } + else + { + item.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestTimer.cs b/Scripts/Engines/Harvest/Core/HarvestTimer.cs new file mode 100644 index 0000000..c90e393 --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestTimer.cs @@ -0,0 +1,31 @@ +using System; + +namespace Server.Engines.Harvest +{ + public class HarvestTimer : Timer + { + private Mobile m_From; + private Item m_Tool; + private HarvestSystem m_System; + private HarvestDefinition m_Definition; + private object m_ToHarvest, m_Locked; + private int m_Index, m_Count; + + public HarvestTimer( Mobile from, Item tool, HarvestSystem system, HarvestDefinition def, object toHarvest, object locked ) : base( TimeSpan.Zero, def.EffectDelay ) + { + m_From = from; + m_Tool = tool; + m_System = system; + m_Definition = def; + m_ToHarvest = toHarvest; + m_Locked = locked; + m_Count = Utility.RandomList( def.EffectCounts ); + } + + protected override void OnTick() + { + if ( !m_System.OnHarvesting( m_From, m_Tool, m_Definition, m_ToHarvest, m_Locked, ++m_Index == m_Count ) ) + Stop(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Core/HarvestVein.cs b/Scripts/Engines/Harvest/Core/HarvestVein.cs new file mode 100644 index 0000000..3e989c4 --- /dev/null +++ b/Scripts/Engines/Harvest/Core/HarvestVein.cs @@ -0,0 +1,25 @@ +using System; + +namespace Server.Engines.Harvest +{ + public class HarvestVein + { + private double m_VeinChance; + private double m_ChanceToFallback; + private HarvestResource m_PrimaryResource; + private HarvestResource m_FallbackResource; + + public double VeinChance{ get{ return m_VeinChance; } set{ m_VeinChance = value; } } + public double ChanceToFallback{ get{ return m_ChanceToFallback; } set{ m_ChanceToFallback = value; } } + public HarvestResource PrimaryResource{ get{ return m_PrimaryResource; } set{ m_PrimaryResource = value; } } + public HarvestResource FallbackResource{ get{ return m_FallbackResource; } set{ m_FallbackResource = value; } } + + public HarvestVein( double veinChance, double chanceToFallback, HarvestResource primaryResource, HarvestResource fallbackResource ) + { + m_VeinChance = veinChance; + m_ChanceToFallback = chanceToFallback; + m_PrimaryResource = primaryResource; + m_FallbackResource = fallbackResource; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Fishing.cs b/Scripts/Engines/Harvest/Fishing.cs new file mode 100644 index 0000000..f93dc19 --- /dev/null +++ b/Scripts/Engines/Harvest/Fishing.cs @@ -0,0 +1,571 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Engines.Quests; +using Server.Engines.Quests.Collector; +using System.Collections.Generic; + +namespace Server.Engines.Harvest +{ + public class Fishing : HarvestSystem + { + private static Fishing m_System; + + public static Fishing System + { + get + { + if ( m_System == null ) + m_System = new Fishing(); + + return m_System; + } + } + + private HarvestDefinition m_Definition; + + public HarvestDefinition Definition + { + get{ return m_Definition; } + } + + private Fishing() + { + HarvestResource[] res; + HarvestVein[] veins; + + #region Fishing + HarvestDefinition fish = new HarvestDefinition(); + + // Resource banks are every 8x8 tiles + fish.BankWidth = 8; + fish.BankHeight = 8; + + // Every bank holds from 5 to 15 fish + fish.MinTotal = 5; + fish.MaxTotal = 15; + + // A resource bank will respawn its content every 10 to 20 minutes + fish.MinRespawn = TimeSpan.FromMinutes( 10.0 ); + fish.MaxRespawn = TimeSpan.FromMinutes( 20.0 ); + + // Skill checking is done on the Fishing skill + fish.Skill = SkillName.Fishing; + + // Set the list of harvestable tiles + fish.Tiles = m_WaterTiles; + fish.RangedTiles = true; + + // Players must be within 4 tiles to harvest + fish.MaxRange = 4; + + // One fish per harvest action + fish.ConsumedPerHarvest = 1; + fish.ConsumedPerFeluccaHarvest = 1; + + // The fishing + fish.EffectActions = new int[]{ 12 }; + fish.EffectSounds = new int[0]; + fish.EffectCounts = new int[]{ 1 }; + fish.EffectDelay = TimeSpan.Zero; + fish.EffectSoundDelay = TimeSpan.FromSeconds( 8.0 ); + + fish.NoResourcesMessage = 503172; // The fish don't seem to be biting here. + fish.FailMessage = 503171; // You fish a while, but fail to catch anything. + fish.TimedOutOfRangeMessage = 500976; // You need to be closer to the water to fish! + fish.OutOfRangeMessage = 500976; // You need to be closer to the water to fish! + fish.PackFullMessage = 503176; // You do not have room in your backpack for a fish. + fish.ToolBrokeMessage = 503174; // You broke your fishing pole. + + res = new HarvestResource[] + { + new HarvestResource( 00.0, 00.0, 100.0, 1043297, typeof( Fish ) ) + }; + + veins = new HarvestVein[] + { + new HarvestVein( 100.0, 0.0, res[0], null ) + }; + + fish.Resources = res; + fish.Veins = veins; + + if ( Core.ML ) + { + fish.BonusResources = new BonusHarvestResource[] + { + new BonusHarvestResource( 0, 98.4, null, null ), //set to same chance as mining ml gems + new BonusHarvestResource( 70.0, 1.0, "Vous ramenez un petit sac bien �trange", typeof( CacaoBag ) ), + new BonusHarvestResource( 80.0, .6, 1072597, typeof( WhitePearl ) ) + }; + } + + m_Definition = fish; + Definitions.Add( fish ); + #endregion + } + + public override void OnConcurrentHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + from.SendLocalizedMessage( 500972 ); // You are already fishing. + } + + private class MutateEntry + { + public double m_ReqSkill, m_MinSkill, m_MaxSkill; + public bool m_DeepWater; + public Type[] m_Types; + + public MutateEntry( double reqSkill, double minSkill, double maxSkill, bool deepWater, params Type[] types ) + { + m_ReqSkill = reqSkill; + m_MinSkill = minSkill; + m_MaxSkill = maxSkill; + m_DeepWater = deepWater; + m_Types = types; + } + } + + private static MutateEntry[] m_MutateTable = new MutateEntry[] + { + new MutateEntry( 80.0, 80.0, 4080.0, true, typeof( SpecialFishingNet ) ), + new MutateEntry( 80.0, 80.0, 4080.0, true, typeof( BigFish ) ), + new MutateEntry( 90.0, 80.0, 4080.0, true, typeof( TreasureMap ) ), + new MutateEntry( 100.0, 80.0, 4080.0, true, typeof( MessageInABottle ) ), + new MutateEntry( 0.0, 125.0, -2375.0, false, typeof( PrizedFish ), typeof( WondrousFish ), typeof( TrulyRareFish ), typeof( PeculiarFish ) ), + new MutateEntry( 0.0, 105.0, -420.0, false, typeof( Boots ), typeof( Shoes ), typeof( Sandals ), typeof( ThighBoots ) ), + new MutateEntry( 0.0, 200.0, -200.0, false, new Type[1]{ null } ) + }; + + public override bool SpecialHarvest( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FishPearlsObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( Utility.RandomDouble() < 0.5 ) + { + player.SendLocalizedMessage( 1055086, "", 0x59 ); // You pull a shellfish out of the water, and find a rainbow pearl inside of it. + + obj.CurProgress++; + } + else + { + player.SendLocalizedMessage( 1055087, "", 0x2C ); // You pull a shellfish out of the water, but it doesn't have a rainbow pearl. + } + + return true; + } + } + } + + return false; + } + + public override Type MutateType( Type type, Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource ) + { + bool deepWater = SpecialFishingNet.FullValidation( map, loc.X, loc.Y ); + + double skillBase = from.Skills[SkillName.Fishing].Base; + double skillValue = from.Skills[SkillName.Fishing].Value; + + for ( int i = 0; i < m_MutateTable.Length; ++i ) + { + MutateEntry entry = m_MutateTable[i]; + + if ( !deepWater && entry.m_DeepWater ) + continue; + + if ( skillBase >= entry.m_ReqSkill ) + { + double chance = (skillValue - entry.m_MinSkill) / (entry.m_MaxSkill - entry.m_MinSkill); + + if ( chance > Utility.RandomDouble() ) + return entry.m_Types[Utility.Random( entry.m_Types.Length )]; + } + } + + return type; + } + + private static Map SafeMap( Map map ) + { + if ( map == null || map == Map.Internal ) + return Map.Trammel; + + return map; + } + + public override bool CheckResources( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, bool timed ) + { + Container pack = from.Backpack; + + if ( pack != null ) + { + List messages = pack.FindItemsByType(); + + for ( int i = 0; i < messages.Count; ++i ) + { + SOS sos = messages[i]; + + if ((from.Map == Map.Felucca || from.Map == Map.Trammel) && from.InRange(sos.TargetLocation, 60)) + return true; + } + } + + return base.CheckResources( from, tool, def, map, loc, timed ); + } + + public override Item Construct( Type type, Mobile from ) + { + if ( type == typeof( TreasureMap ) ) + { + int level; + if ( from is PlayerMobile && ((PlayerMobile)from).Young && from.Map == Map.Trammel && TreasureMap.IsInHavenIsland( from ) ) + level = 0; + else + level = 1; + + return new TreasureMap( level, from.Map == Map.Felucca ? Map.Felucca : Map.Trammel ); + } + else if ( type == typeof( MessageInABottle ) ) + { + return new MessageInABottle( from.Map == Map.Felucca ? Map.Felucca : Map.Trammel ); + } + + Container pack = from.Backpack; + + if ( pack != null ) + { + List messages = pack.FindItemsByType(); + + for ( int i = 0; i < messages.Count; ++i ) + { + SOS sos = messages[i]; + + if ((from.Map == Map.Felucca || from.Map == Map.Trammel) && from.InRange(sos.TargetLocation, 60)) + { + Item preLoot = null; + + switch ( Utility.Random( 8 ) ) + { + case 0: // Body parts + { + int[] list = new int[] + { + 0x1CDD, 0x1CE5, // arm + 0x1CE0, 0x1CE8, // torso + 0x1CE1, 0x1CE9, // head + 0x1CE2, 0x1CEC // leg + }; + + preLoot = new ShipwreckedItem( Utility.RandomList( list ) ); + break; + } + case 1: // Bone parts + { + int[] list = new int[] + { + 0x1AE0, 0x1AE1, 0x1AE2, 0x1AE3, 0x1AE4, // skulls + 0x1B09, 0x1B0A, 0x1B0B, 0x1B0C, 0x1B0D, 0x1B0E, 0x1B0F, 0x1B10, // bone piles + 0x1B15, 0x1B16 // pelvis bones + }; + + preLoot = new ShipwreckedItem( Utility.RandomList( list ) ); + break; + } + case 2: // Paintings and portraits + { + preLoot = new ShipwreckedItem( Utility.Random( 0xE9F, 10 ) ); + break; + } + case 3: // Pillows + { + preLoot = new ShipwreckedItem( Utility.Random( 0x13A4, 11 ) ); + break; + } + case 4: // Shells + { + preLoot = new ShipwreckedItem( Utility.Random( 0xFC4, 9 ) ); + break; + } + case 5: //Hats + { + if ( Utility.RandomBool() ) + preLoot = new SkullCap(); + else + preLoot = new TricorneHat(); + + break; + } + case 6: // Misc + { + int[] list = new int[] + { + 0x1EB5, // unfinished barrel + 0xA2A, // stool + 0xC1F, // broken clock + 0x1047, 0x1048, // globe + 0x1EB1, 0x1EB2, 0x1EB3, 0x1EB4 // barrel staves + }; + + if ( Utility.Random( list.Length + 1 ) == 0 ) + preLoot = new Candelabra(); + else + preLoot = new ShipwreckedItem( Utility.RandomList( list ) ); + + break; + } + } + + if ( preLoot != null ) + { + if ( preLoot is IShipwreckedItem ) + ( (IShipwreckedItem)preLoot ).IsShipwreckedItem = true; + + return preLoot; + } + + LockableContainer chest; + + if ( Utility.RandomBool() ) + chest = new MetalGoldenChest(); + else + chest = new WoodenChest(); + + if ( sos.IsAncient ) + chest.Hue = 0x481; + + TreasureMapChest.Fill(chest, Math.Max(1, Math.Min(4, sos.Level))); + + if ( sos.IsAncient ) + chest.DropItem( new FabledFishingNet() ); + else + chest.DropItem( new SpecialFishingNet() ); + + chest.Movable = true; + chest.Locked = false; + chest.TrapType = TrapType.None; + chest.TrapPower = 0; + chest.TrapLevel = 0; + + sos.Delete(); + + return chest; + } + } + } + + return base.Construct( type, from ); + } + + public override bool Give( Mobile m, Item item, bool placeAtFeet ) + { + if ( item is TreasureMap || item is MessageInABottle || item is SpecialFishingNet ) + { + BaseCreature serp; + + if ( 0.25 > Utility.RandomDouble() ) + serp = new DeepSeaSerpent(); + else + serp = new SeaSerpent(); + + int x = m.X, y = m.Y; + + Map map = m.Map; + + for ( int i = 0; map != null && i < 20; ++i ) + { + int tx = m.X - 10 + Utility.Random( 21 ); + int ty = m.Y - 10 + Utility.Random( 21 ); + + LandTile t = map.Tiles.GetLandTile( tx, ty ); + + if ( t.Z == -5 && ( (t.ID >= 0xA8 && t.ID <= 0xAB) || (t.ID >= 0x136 && t.ID <= 0x137) ) && !Spells.SpellHelper.CheckMulti( new Point3D( tx, ty, -5 ), map ) ) + { + x = tx; + y = ty; + break; + } + } + + serp.MoveToWorld( new Point3D( x, y, -5 ), map ); + + serp.Home = serp.Location; + serp.RangeHome = 10; + + serp.PackItem( item ); + + m.SendLocalizedMessage( 503170 ); // Uh oh! That doesn't look like a fish! + + return true; // we don't want to give the item to the player, it's on the serpent + } + + if ( item is BigFish || item is WoodenChest || item is MetalGoldenChest ) + placeAtFeet = true; + + return base.Give( m, item, placeAtFeet ); + } + + public override void SendSuccessTo(Mobile from, Item item, HarvestResource resource) + { + if (item is BigFish) + { + from.SendLocalizedMessage(1042635); // Your fishing pole bends as you pull a big fish from the depths! + + ((BigFish)item).Fisher = from; + } + else if (item is WoodenChest || item is MetalGoldenChest) + { + from.SendLocalizedMessage(503175); // You pull up a heavy chest from the depths of the ocean! + } + else + { + int number; + string name; + + if (item is BaseMagicFish) + { + number = 1008124; + name = "a mess of small fish"; + } + else if (item is Fish) + { + number = 1008124; + name = item.ItemData.Name; + } + else if (item is BaseShoes) + { + number = 1008124; + name = item.ItemData.Name; + } + else if (item is TreasureMap) + { + number = 1008125; + name = "a sodden piece of parchment"; + } + else if (item is MessageInABottle) + { + number = 1008125; + name = "a bottle, with a message in it"; + } + else if (item is SpecialFishingNet) + { + number = 1008125; + name = "a special fishing net"; // TODO: this is just a guess--what should it really be named? + } + else + { + number = 1043297; + + if ((item.ItemData.Flags & TileFlag.ArticleA) != 0) + name = "a " + item.ItemData.Name; + else if ((item.ItemData.Flags & TileFlag.ArticleAn) != 0) + name = "an " + item.ItemData.Name; + else + name = item.ItemData.Name; + } + + NetState ns = from.NetState; + + if (ns == null) + return; + + if (number == 1043297 || ns.HighSeas) + from.SendLocalizedMessage(number, name); + else + from.SendLocalizedMessage(number, true, name); + } + } + + public override void OnHarvestStarted( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + base.OnHarvestStarted( from, tool, def, toHarvest ); + + int tileID; + Map map; + Point3D loc; + + if ( GetHarvestDetails( from, tool, toHarvest, out tileID, out map, out loc ) ) + Timer.DelayCall( TimeSpan.FromSeconds( 1.5 ), + delegate + { + if( Core.ML ) + from.RevealingAction(); + + Effects.SendLocationEffect( loc, map, 0x352D, 16, 4 ); + Effects.PlaySound( loc, map, 0x364 ); + } ); + } + + public override void OnHarvestFinished( Mobile from, Item tool, HarvestDefinition def, HarvestVein vein, HarvestBank bank, HarvestResource resource, object harvested ) + { + base.OnHarvestFinished( from, tool, def, vein, bank, resource, harvested ); + + if ( Core.ML ) + from.RevealingAction(); + } + + public override object GetLock( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + return this; + } + + public override bool BeginHarvesting( Mobile from, Item tool ) + { + if ( !base.BeginHarvesting( from, tool ) ) + return false; + + from.SendLocalizedMessage( 500974 ); // What water do you want to fish in? + return true; + } + + public override bool CheckHarvest( Mobile from, Item tool ) + { + if ( !base.CheckHarvest( from, tool ) ) + return false; + + if ( from.Mounted ) + { + from.SendLocalizedMessage( 500971 ); // You can't fish while riding! + return false; + } + + return true; + } + + public override bool CheckHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + if ( !base.CheckHarvest( from, tool, def, toHarvest ) ) + return false; + + if ( from.Mounted ) + { + from.SendLocalizedMessage( 500971 ); // You can't fish while riding! + return false; + } + + return true; + } + + private static int[] m_WaterTiles = new int[] + { + 0x00A8, 0x00AB, + 0x0136, 0x0137, + 0x5797, 0x579C, + 0x746E, 0x7485, + 0x7490, 0x74AB, + 0x74B5, 0x75D5 + }; + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Lumberjacking.cs b/Scripts/Engines/Harvest/Lumberjacking.cs new file mode 100644 index 0000000..247d0d3 --- /dev/null +++ b/Scripts/Engines/Harvest/Lumberjacking.cs @@ -0,0 +1,216 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Engines.Harvest +{ + public class Lumberjacking : HarvestSystem + { + private static Lumberjacking m_System; + + public static Lumberjacking System + { + get + { + if ( m_System == null ) + m_System = new Lumberjacking(); + + return m_System; + } + } + + private HarvestDefinition m_Definition; + + public HarvestDefinition Definition + { + get{ return m_Definition; } + } + + private Lumberjacking() + { + HarvestResource[] res; + HarvestVein[] veins; + + #region Lumberjacking + HarvestDefinition lumber = new HarvestDefinition(); + + // Resource banks are every 4x3 tiles + lumber.BankWidth = 4; + lumber.BankHeight = 3; + + // Every bank holds from 20 to 45 logs + lumber.MinTotal = 20; + lumber.MaxTotal = 45; + + // A resource bank will respawn its content every 20 to 30 minutes + lumber.MinRespawn = TimeSpan.FromMinutes( 20.0 ); + lumber.MaxRespawn = TimeSpan.FromMinutes( 30.0 ); + + // Skill checking is done on the Lumberjacking skill + lumber.Skill = SkillName.Lumberjacking; + + // Set the list of harvestable tiles + lumber.Tiles = m_TreeTiles; + + // Players must be within 2 tiles to harvest + lumber.MaxRange = 2; + + // Ten logs per harvest action + lumber.ConsumedPerHarvest = 10; + lumber.ConsumedPerFeluccaHarvest = 20; + + // The chopping effect + lumber.EffectActions = new int[]{ 13 }; + lumber.EffectSounds = new int[]{ 0x13E }; + lumber.EffectCounts = (Core.AOS ? new int[]{ 1 } : new int[]{ 1, 2, 2, 2, 3 }); + lumber.EffectDelay = TimeSpan.FromSeconds( 1.6 ); + lumber.EffectSoundDelay = TimeSpan.FromSeconds( 0.9 ); + + lumber.NoResourcesMessage = 500493; // There's not enough wood here to harvest. + lumber.FailMessage = 500495; // You hack at the tree for a while, but fail to produce any useable wood. + lumber.OutOfRangeMessage = 500446; // That is too far away. + lumber.PackFullMessage = 500497; // You can't place any wood into your backpack! + lumber.ToolBrokeMessage = 500499; // You broke your axe. + + if ( Core.ML ) + { + res = new HarvestResource[] + { + new HarvestResource( 00.0, 00.0, 100.0, 1072540, typeof( Log ) ), + new HarvestResource( 65.0, 25.0, 105.0, 1072541, typeof( OakLog ) ), + new HarvestResource( 80.0, 40.0, 120.0, 1072542, typeof( AshLog ) ), + new HarvestResource( 95.0, 55.0, 135.0, 1072543, typeof( YewLog ) ), + new HarvestResource( 100.0, 60.0, 140.0, 1072544, typeof( HeartwoodLog ) ), + new HarvestResource( 100.0, 60.0, 140.0, 1072545, typeof( BloodwoodLog ) ), + new HarvestResource( 100.0, 60.0, 140.0, 1072546, typeof( FrostwoodLog ) ), + }; + + + veins = new HarvestVein[] + { + new HarvestVein( 49.0, 0.0, res[0], null ), // Ordinary Logs + new HarvestVein( 30.0, 0.5, res[1], res[0] ), // Oak + new HarvestVein( 10.0, 0.5, res[2], res[0] ), // Ash + new HarvestVein( 05.0, 0.5, res[3], res[0] ), // Yew + new HarvestVein( 03.0, 0.5, res[4], res[0] ), // Heartwood + new HarvestVein( 02.0, 0.5, res[5], res[0] ), // Bloodwood + new HarvestVein( 01.0, 0.5, res[6], res[0] ), // Frostwood + }; + + lumber.BonusResources = new BonusHarvestResource[] + { + new BonusHarvestResource( 0, 81.9, null, null ), //Nothing + new BonusHarvestResource( 0, 2.0, "Vous trouvez du gingembre", typeof(GingerRoot) ), + new BonusHarvestResource( 100, 10.0, 1072548, typeof( BarkFragment ) ), + new BonusHarvestResource( 100, 03.0, 1072550, typeof( LuminescentFungi ) ), + new BonusHarvestResource( 100, 02.0, 1072547, typeof( SwitchItem ) ), + new BonusHarvestResource( 100, 01.0, 1072549, typeof( ParasiticPlant ) ), + new BonusHarvestResource( 100, 00.1, 1072551, typeof( BrilliantAmber ) ) + }; + } + else + { + res = new HarvestResource[] + { + new HarvestResource( 00.0, 00.0, 100.0, 500498, typeof( Log ) ) + }; + + veins = new HarvestVein[] + { + new HarvestVein( 100.0, 0.0, res[0], null ) + }; + } + + lumber.Resources = res; + lumber.Veins = veins; + + lumber.RaceBonus = Core.ML; + lumber.RandomizeVeins = Core.ML; + + m_Definition = lumber; + Definitions.Add( lumber ); + #endregion + } + + public override bool CheckHarvest( Mobile from, Item tool ) + { + if ( !base.CheckHarvest( from, tool ) ) + return false; + + if (tool.Parent != from) + { + from.SendLocalizedMessage(500487); // The axe must be equipped for any serious wood chopping. + return false; + } + + return true; + } + + public override bool CheckHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + if ( !base.CheckHarvest( from, tool, def, toHarvest ) ) + return false; + + if ( tool.Parent != from ) + { + from.SendLocalizedMessage( 500487 ); // The axe must be equipped for any serious wood chopping. + return false; + } + + return true; + } + + public override void OnBadHarvestTarget(Mobile from, Item tool, object toHarvest) + { + if (toHarvest is Mobile) + ((Mobile)toHarvest).PrivateOverheadMessage(MessageType.Regular, 0x3B2, 500450, from.NetState); // You can only skin dead creatures. + else if (toHarvest is Item) + ((Item)toHarvest).LabelTo(from, 500464); // Use this on corpses to carve away meat and hide + else if (toHarvest is Targeting.StaticTarget || toHarvest is Targeting.LandTarget) + from.SendLocalizedMessage(500489); // You can't use an axe on that. + else + from.SendLocalizedMessage(1005213); // You can't do that + } + + public override void OnHarvestStarted( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + base.OnHarvestStarted( from, tool, def, toHarvest ); + + if( Core.ML ) + from.RevealingAction(); + } + + public static void Initialize() + { + Array.Sort( m_TreeTiles ); + } + + #region Tile lists + private static int[] m_TreeTiles = new int[] + { + 0x4CCA, 0x4CCB, 0x4CCC, 0x4CCD, 0x4CD0, 0x4CD3, 0x4CD6, 0x4CD8, + 0x4CDA, 0x4CDD, 0x4CE0, 0x4CE3, 0x4CE6, 0x4CF8, 0x4CFB, 0x4CFE, + 0x4D01, 0x4D41, 0x4D42, 0x4D43, 0x4D44, 0x4D57, 0x4D58, 0x4D59, + 0x4D5A, 0x4D5B, 0x4D6E, 0x4D6F, 0x4D70, 0x4D71, 0x4D72, 0x4D84, + 0x4D85, 0x4D86, 0x52B5, 0x52B6, 0x52B7, 0x52B8, 0x52B9, 0x52BA, + 0x52BB, 0x52BC, 0x52BD, + + 0x4CCE, 0x4CCF, 0x4CD1, 0x4CD2, 0x4CD4, 0x4CD5, 0x4CD7, 0x4CD9, + 0x4CDB, 0x4CDC, 0x4CDE, 0x4CDF, 0x4CE1, 0x4CE2, 0x4CE4, 0x4CE5, + 0x4CE7, 0x4CE8, 0x4CF9, 0x4CFA, 0x4CFC, 0x4CFD, 0x4CFF, 0x4D00, + 0x4D02, 0x4D03, 0x4D45, 0x4D46, 0x4D47, 0x4D48, 0x4D49, 0x4D4A, + 0x4D4B, 0x4D4C, 0x4D4D, 0x4D4E, 0x4D4F, 0x4D50, 0x4D51, 0x4D52, + 0x4D53, 0x4D5C, 0x4D5D, 0x4D5E, 0x4D5F, 0x4D60, 0x4D61, 0x4D62, + 0x4D63, 0x4D64, 0x4D65, 0x4D66, 0x4D67, 0x4D68, 0x4D69, 0x4D73, + 0x4D74, 0x4D75, 0x4D76, 0x4D77, 0x4D78, 0x4D79, 0x4D7A, 0x4D7B, + 0x4D7C, 0x4D7D, 0x4D7E, 0x4D7F, 0x4D87, 0x4D88, 0x4D89, 0x4D8A, + 0x4D8B, 0x4D8C, 0x4D8D, 0x4D8E, 0x4D8F, 0x4D90, 0x4D95, 0x4D96, + 0x4D97, 0x4D99, 0x4D9A, 0x4D9B, 0x4D9D, 0x4D9E, 0x4D9F, 0x4DA1, + 0x4DA2, 0x4DA3, 0x4DA5, 0x4DA6, 0x4DA7, 0x4DA9, 0x4DAA, 0x4DAB, + 0x52BE, 0x52BF, 0x52C0, 0x52C1, 0x52C2, 0x52C3, 0x52C4, 0x52C5, + 0x52C6, 0x52C7 + }; + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Engines/Harvest/Mining.cs b/Scripts/Engines/Harvest/Mining.cs new file mode 100644 index 0000000..d1777d6 --- /dev/null +++ b/Scripts/Engines/Harvest/Mining.cs @@ -0,0 +1,487 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Engines.Harvest +{ + public class Mining : HarvestSystem + { + private static Mining m_System; + + public static Mining System + { + get + { + if ( m_System == null ) + m_System = new Mining(); + + return m_System; + } + } + + private HarvestDefinition m_OreAndStone, m_Sand; + + public HarvestDefinition OreAndStone + { + get{ return m_OreAndStone; } + } + + public HarvestDefinition Sand + { + get{ return m_Sand; } + } + + private Mining() + { + HarvestResource[] res; + HarvestVein[] veins; + + #region Mining for ore and stone + HarvestDefinition oreAndStone = m_OreAndStone = new HarvestDefinition(); + + // Resource banks are every 8x8 tiles + oreAndStone.BankWidth = 2; + oreAndStone.BankHeight = 2; + + // Every bank holds from 10 to 34 ore + oreAndStone.MinTotal = 4; + oreAndStone.MaxTotal = 18; + + // A resource bank will respawn its content every 10 to 20 minutes + oreAndStone.MinRespawn = TimeSpan.FromMinutes( 30.0 ); + oreAndStone.MaxRespawn = TimeSpan.FromMinutes( 40.0 ); + + // Skill checking is done on the Mining skill + oreAndStone.Skill = SkillName.Mining; + + // Set the list of harvestable tiles + oreAndStone.Tiles = m_MountainAndCaveTiles; + + // Players must be within 2 tiles to harvest + oreAndStone.MaxRange = 2; + + // One ore per harvest action + oreAndStone.ConsumedPerHarvest = 1; + oreAndStone.ConsumedPerFeluccaHarvest = 2; + + // The digging effect + oreAndStone.EffectActions = new int[]{ 11 }; + oreAndStone.EffectSounds = new int[]{ 0x125, 0x126 }; + oreAndStone.EffectCounts = new int[]{ 1 }; + oreAndStone.EffectDelay = TimeSpan.FromSeconds( 1.6 ); + oreAndStone.EffectSoundDelay = TimeSpan.FromSeconds( 0.9 ); + + oreAndStone.NoResourcesMessage = 503040; // There is no metal here to mine. + oreAndStone.DoubleHarvestMessage = 503042; // Someone has gotten to the metal before you. + oreAndStone.TimedOutOfRangeMessage = 503041; // You have moved too far away to continue mining. + oreAndStone.OutOfRangeMessage = 500446; // That is too far away. + oreAndStone.FailMessage = 503043; // You loosen some rocks but fail to find any useable ore. + oreAndStone.PackFullMessage = 1010481; // Your backpack is full, so the ore you mined is lost. + oreAndStone.ToolBrokeMessage = 1044038; // You have worn out your tool! + + res = new HarvestResource[] + { + new HarvestResource( 00.0, 00.0, 100.0, "Vous avez trouv� du fer", typeof( IronOre ), typeof( Granite ) ), + new HarvestResource( 45.0, 05.0, 85.0, "Vous avez trouv� de la rouille", typeof( RustyOre ), typeof( RustyGranite )), + new HarvestResource( 48.0, 08.0, 88.0, "Vous avez trouv� du vieux cuivre", typeof( OldcopperOre ), typeof( OldcopperGranite )), + new HarvestResource( 55.0, 15.0, 95.0, "Vous avez trouv� du cuivre terni", typeof( DullcopperOre ), typeof( DullcopperGranite ), typeof( DullCopperElemental ) ), + new HarvestResource( 65.0, 25.0, 105.0, "Vous avez trouv� du sombrine", typeof( ShadowOre ), typeof( ShadowGranite ), typeof( ShadowIronElemental ) ), + new HarvestResource( 60.0, 20.0, 100.0, "Vous avez trouv� du cuivre", typeof( CopperOre ), typeof( CopperGranite ), typeof( CopperElemental ) ), + new HarvestResource( 70.0, 30.0, 120.0, "Vous avez trouv� du bronze", typeof( BronzeOre ), typeof( BronzeGranite ), typeof( BronzeElemental ) ), + new HarvestResource( 85.0, 45.0, 125.0, "Vous avez trouv� de l'or", typeof( GoldOre ), typeof( GoldGranite ), typeof( GoldenElemental ) ), + new HarvestResource( 55.0, 15.0, 95.0, "Vous avez trouv� du rose", typeof( RoseOre ), typeof( RoseGranite )), + //new HarvestResource( 00.0, 00.0, 100.0, "Vous avez trouv� de l'agapite", typeof( AgapiteOre ), typeof( AgapiteGranite ), typeof(AgapiteElemental )), + new HarvestResource( 99.0, 59.0, 139.0, "Vous avez trouv� de la valorite", typeof( ValoriteOre ), typeof( ValoriteGranite ), typeof( ValoriteElemental ) ), + //new HarvestResource( 70.0, 30.0, 110.0, "Vous avez trouv� de la roche de sang", typeof( BloodrockOre ), typeof( BloodrockGranite )), + new HarvestResource( 85, 45.0, 125.0, "Vous avez trouv� du verite", typeof( VeriteOre ), typeof( VeriteGranite ), typeof( VeriteElemental ) ), + //new HarvestResource( 80.0, 40.0, 120.0, "Vous avez trouv� de l'argent", typeof( SilverOre ), typeof( SilverGranite )), + //new HarvestResource( 85.0, 45.0, 125.0, "Vous avez trouv� du dragon", typeof( DragonOre ), typeof( DragonGranite) ), + //new HarvestResource( 90.0, 50.0, 130.0, "Vous avez trouv� du titan", typeof( TitanOre ), typeof( TitanGranite )), + //new HarvestResource( 95.0, 55.0, 135.0, "Vous avez trouv� de la crystaline", typeof( CrystalineOre ), typeof( CrystalineGranite )), + //new HarvestResource( 99.0, 59.0, 139.0, "Vous avez trouv� du krynite", typeof( KryniteOre ), typeof( KryniteGranite )), + //new HarvestResource( 00.0, 00.0, 100.0, "Vous avez trouv� du vulcan", typeof( VulcanOre ), typeof( VulcanGranite ) ), + //new HarvestResource( 65.0, 25.0, 105.0, "Vous avez trouv� de la craie de sang", typeof( BloodcrestOre ), typeof( BloodcrestGranite )), + //new HarvestResource( 70.0, 30.0, 110.0, "Vous avez trouv� de l'elvin", typeof( ElvinOre ), typeof( ElvinGranite )), + //new HarvestResource( 75.0, 35.0, 115.0, "Vous avez trouv� de l'acid", typeof( AcidOre ), typeof( AcidGranite )), + //new HarvestResource( 80.0, 40.0, 120.0, "Vous avez trouv� de l'aqua", typeof( AquaOre ), typeof( AquaGranite )), + new HarvestResource( 75.0, 25.0, 115.0, "Vous avez trouv� un m�tal ressemblant au Rose", typeof( EldarOre ), typeof( EldarGranite )), + //new HarvestResource( 90.0, 50.0, 130.0, "Vous avez trouv� du glowing", typeof( GlowingOre ), typeof( GlowingGranite )), + //new HarvestResource( 95.0, 55.0, 135.0, "Vous avez trouv� du gorgan", typeof( GorganOre ), typeof( GorganGranite )), + //new HarvestResource( 85.0, 45.0, 125.0, "Vous avez trouv� de l'acier", typeof( SteelOre ), typeof( SteelGranite )), + //new HarvestResource( 90.0, 50.0, 130.0, "Vous avez trouv� de la pierre de sable", typeof( SandrockOre ), typeof( SandrockGranite )), + //new HarvestResource( 95.0, 55.0, 135.0, "Vous avez trouv� du du mytheril", typeof( MytherilOre ), typeof( MytherilGranite )), + //new HarvestResource( 99.0, 59.0, 139.0, "Vous avez trouv� de la roche sombre", typeof( BlackrockOre ), typeof( BlackrockGranite ))*/ + + }; + + veins = new HarvestVein[] + { + new HarvestVein( 47.0, 0.0, res[0], null ), // Iron + new HarvestVein( 18.8, 0.5, res[1], res[0] ), // Rusty + new HarvestVein( 06.3, 0.5, res[2], res[0] ), // OldCopper + new HarvestVein( 05.3, 0.5, res[3], res[0] ), // Dullcopper + new HarvestVein( 05.3, 0.5, res[4], res[0] ),//Shadow + new HarvestVein( 05.0, 0.5, res[5], res[2] ), // Copper + new HarvestVein( 04.0, 0.5, res[6], res[0] ), // Bronze + new HarvestVein( 03.4, 0.5, res[7], res[0] ), // Gold + new HarvestVein( 03.0, 0.5, res[8], res[0] ), //Rose + new HarvestVein( 0.4, 0.5, res[9], res[0] ), //Valorite + new HarvestVein( 01.0, 0.5, res[10], res[0] ), // Verite + new HarvestVein( 0.5, 0.5, res[11], res[8] ), // Eldar + + /*new HarvestVein( 01.4, 0.5, res[8], res[0] ), // Valorite + new HarvestVein( 49.6, 0.0, res[9], res[0] ), // Iron + new HarvestVein( 11.2, 0.5, res[10], res[0] ), // Dull Copper + new HarvestVein( 09.8, 0.5, res[11], res[0] ), // Shadow Iron + new HarvestVein( 08.4, 0.5, res[12], res[0] ), // Copper + new HarvestVein( 07.0, 0.5, res[13], res[0] ), // Bronze + new HarvestVein( 05.6, 0.5, res[14], res[0] ), // Gold + new HarvestVein( 04.2, 0.5, res[15], res[0] ), // Agapite + new HarvestVein( 02.8, 0.5, res[16], res[0] ), // Verite + new HarvestVein( 01.4, 0.5, res[17], res[0] ), // Valorite + new HarvestVein( 11.2, 0.5, res[18], res[0] ), // Dull Copper + new HarvestVein( 09.8, 0.5, res[19], res[0] ), // Shadow Iron + new HarvestVein( 08.4, 0.5, res[20], res[0] ), // Copper + new HarvestVein( 07.0, 0.5, res[21], res[0] ), // Bronze + new HarvestVein( 05.6, 0.5, res[22], res[0] ), // Gold + new HarvestVein( 04.2, 0.5, res[23], res[0] ), // Agapite + new HarvestVein( 02.8, 0.5, res[24], res[0] ), // Verite + new HarvestVein( 01.4, 0.5, res[25], res[0] ), // Valorite + new HarvestVein( 07.0, 0.5, res[26], res[0] ), // Bronze + new HarvestVein( 05.6, 0.5, res[27], res[0] ), // Gold + new HarvestVein( 04.2, 0.5, res[28], res[0] ), // Agapite + new HarvestVein( 02.8, 0.5, res[29], res[0] ), // Verite*/ + }; + + oreAndStone.Resources = res; + oreAndStone.Veins = veins; + + if ( Core.ML ) + { + oreAndStone.BonusResources = new BonusHarvestResource[] + { + new BonusHarvestResource( 0, 98.6, null, null ), //Nothing + new BonusHarvestResource( 100, .5, 1072562, typeof( BlueDiamond ) ), + new BonusHarvestResource( 100, .1, 1072567, typeof( DarkSapphire ) ), + new BonusHarvestResource( 100, .1, 1072570, typeof( EcruCitrine ) ), + new BonusHarvestResource( 100, .5, 1072564, typeof( FireRuby ) ), + new BonusHarvestResource( 100, .1, 1072566, typeof( PerfectEmerald ) ), + new BonusHarvestResource( 100, .1, 1072568, typeof( Turquoise ) ) + }; + } + + oreAndStone.RaceBonus = Core.ML; + oreAndStone.RandomizeVeins = Core.ML; + + Definitions.Add( oreAndStone ); + #endregion + + #region Mining for sand + HarvestDefinition sand = m_Sand = new HarvestDefinition(); + + // Resource banks are every 8x8 tiles + sand.BankWidth = 1; + sand.BankHeight = 1; + + // Every bank holds from 6 to 12 sand + sand.MinTotal = 3; + sand.MaxTotal = 6; + + // A resource bank will respawn its content every 10 to 20 minutes + sand.MinRespawn = TimeSpan.FromMinutes( 30.0 ); + sand.MaxRespawn = TimeSpan.FromMinutes( 40.0 ); + + // Skill checking is done on the Mining skill + sand.Skill = SkillName.Mining; + + // Set the list of harvestable tiles + sand.Tiles = m_SandTiles; + + // Players must be within 2 tiles to harvest + sand.MaxRange = 2; + + // One sand per harvest action + sand.ConsumedPerHarvest = 1; + sand.ConsumedPerFeluccaHarvest = 1; + + // The digging effect + sand.EffectActions = new int[]{ 11 }; + sand.EffectSounds = new int[]{ 0x125, 0x126 }; + sand.EffectCounts = new int[]{ 4 }; + sand.EffectDelay = TimeSpan.FromSeconds( 1.6 ); + sand.EffectSoundDelay = TimeSpan.FromSeconds( 0.9 ); + + sand.NoResourcesMessage = 1044629; // There is no sand here to mine. + sand.DoubleHarvestMessage = 1044629; // There is no sand here to mine. + sand.TimedOutOfRangeMessage = 503041; // You have moved too far away to continue mining. + sand.OutOfRangeMessage = 500446; // That is too far away. + sand.FailMessage = 1044630; // You dig for a while but fail to find any of sufficient quality for glassblowing. + sand.PackFullMessage = 1044632; // Your backpack can't hold the sand, and it is lost! + sand.ToolBrokeMessage = 1044038; // You have worn out your tool! + + res = new HarvestResource[] + { + new HarvestResource( 100.0, 70.0, 325.0, 1044631, typeof( Sand )) , + }; + + veins = new HarvestVein[] + { + new HarvestVein( 100.0, 0.0, res[0], null ) + }; + + sand.Resources = res; + sand.Veins = veins; + + sand.BonusResources = new BonusHarvestResource[] + { + new BonusHarvestResource( 0, 97.5, null, null ), //Nothing + new BonusHarvestResource( 90, 2.5, "Vous trouvez des roches argent�es", typeof( SilverOre ) ), + }; + + Definitions.Add( sand ); + #endregion + } + + public override Type GetResourceType( Mobile from, Item tool, HarvestDefinition def, Map map, Point3D loc, HarvestResource resource ) + { + if ( def == m_OreAndStone ) + { + PlayerMobile pm = from as PlayerMobile; + if ( pm != null && pm.StoneMining && pm.ToggleMiningStone && from.Skills[SkillName.Mining].Base >= 100.0 && 0.1 > Utility.RandomDouble() ) + return resource.Types[1]; + + return resource.Types[0]; + } + + return base.GetResourceType( from, tool, def, map, loc, resource ); + } + + public override bool CheckHarvest( Mobile from, Item tool ) + { + if ( !base.CheckHarvest( from, tool ) ) + return false; + + if ( from.Mounted ) + { + from.SendLocalizedMessage( 501864 ); // You can't mine while riding. + return false; + } + else if ( from.IsBodyMod && !from.Body.IsHuman ) + { + from.SendLocalizedMessage( 501865 ); // You can't mine while polymorphed. + return false; + } + + return true; + } + + public override void SendSuccessTo( Mobile from, Item item, HarvestResource resource ) + { + if ( item is BaseGranite ) + from.SendLocalizedMessage( 1044606 ); // You carefully extract some workable stone from the ore vein! + else + base.SendSuccessTo( from, item, resource ); + } + + public override bool CheckHarvest( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + if ( !base.CheckHarvest( from, tool, def, toHarvest ) ) + return false; + + if ( def == m_Sand && !(from is PlayerMobile && from.Skills[SkillName.Mining].Base >= 100.0 && ((PlayerMobile)from).SandMining) ) + { + OnBadHarvestTarget( from, tool, toHarvest ); + return false; + } + else if ( from.Mounted ) + { + from.SendLocalizedMessage( 501864 ); // You can't mine while riding. + return false; + } + else if ( from.IsBodyMod && !from.Body.IsHuman ) + { + from.SendLocalizedMessage( 501865 ); // You can't mine while polymorphed. + return false; + } + + return true; + } + + public override HarvestVein MutateVein( Mobile from, Item tool, HarvestDefinition def, HarvestBank bank, object toHarvest, HarvestVein vein ) + { + if ( tool is GargoylesPickaxe && def == m_OreAndStone ) + { + int veinIndex = Array.IndexOf( def.Veins, vein ); + + if ( veinIndex >= 0 && veinIndex < (def.Veins.Length - 1) ) + return def.Veins[veinIndex + 1]; + } + + return base.MutateVein( from, tool, def, bank, toHarvest, vein ); + } + + private static int[] m_Offsets = new int[] + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1 + }; + + public override void OnHarvestFinished( Mobile from, Item tool, HarvestDefinition def, HarvestVein vein, HarvestBank bank, HarvestResource resource, object harvested ) + { + if ( tool is GargoylesPickaxe && def == m_OreAndStone && 0.1 > Utility.RandomDouble() ) + { + HarvestResource res = vein.PrimaryResource; + + if ( res == resource && res.Types.Length >= 3 ) + { + try + { + Map map = from.Map; + + if ( map == null ) + return; + + BaseCreature spawned = Activator.CreateInstance( res.Types[2], new object[]{ 25 } ) as BaseCreature; + + if ( spawned != null ) + { + int offset = Utility.Random( 8 ) * 2; + + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = from.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = from.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if ( map.CanSpawnMobile( x, y, from.Z ) ) + { + spawned.OnBeforeSpawn( new Point3D( x, y, from.Z ), map ); + spawned.MoveToWorld( new Point3D( x, y, from.Z ), map ); + spawned.Combatant = from; + return; + } + else + { + int z = map.GetAverageZ( x, y ); + + if (Math.Abs(z - from.Z) < 10 && map.CanSpawnMobile(x, y, z)) + { + spawned.OnBeforeSpawn( new Point3D( x, y, z ), map ); + spawned.MoveToWorld( new Point3D( x, y, z ), map ); + spawned.Combatant = from; + return; + } + } + } + + spawned.OnBeforeSpawn( from.Location, from.Map ); + spawned.MoveToWorld( from.Location, from.Map ); + spawned.Combatant = from; + } + } + catch + { + } + } + } + } + + public override bool BeginHarvesting( Mobile from, Item tool ) + { + if ( !base.BeginHarvesting( from, tool ) ) + return false; + + from.SendLocalizedMessage( 503033 ); // Where do you wish to dig? + return true; + } + + public override void OnHarvestStarted( Mobile from, Item tool, HarvestDefinition def, object toHarvest ) + { + base.OnHarvestStarted( from, tool, def, toHarvest ); + + if ( Core.ML ) + from.RevealingAction(); + } + + public override void OnBadHarvestTarget( Mobile from, Item tool, object toHarvest ) + { + if ( toHarvest is LandTarget ) + from.SendLocalizedMessage( 501862 ); // You can't mine there. + else + from.SendLocalizedMessage( 501863 ); // You can't mine that. + } + + #region Tile lists + private static int[] m_MountainAndCaveTiles = new int[] + { + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 268, 269, 270, 271, + 272, 273, 274, 275, 276, 277, 278, 279, 286, 287, + 288, 289, 290, 291, 292, 293, 294, 296, 296, 297, + 321, 322, 323, 324, 467, 468, 469, 470, 471, 472, + 473, 474, 476, 477, 478, 479, 480, 481, 482, 483, + 484, 485, 486, 487, 492, 493, 494, 495, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, + 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, + 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 577, 578, 579, 581, 582, 583, 584, 585, + 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, + 596, 597, 598, 599, 600, 601, 610, 611, 612, 613, + + 1010, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, + 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, 1771, 1772, + 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, + 1783, 1784, 1785, 1786, 1787, 1788, 1789, 1790, 1801, 1802, + 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1811, 1812, 1813, + 1814, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, + 1824, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, + 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, + 1850, 1851, 1852, 1853, 1854, 1861, 1862, 1863, 1864, 1865, + 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, + 1876, 1877, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1981, + 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, + 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2028, 2029, 2030, 2031, 2032, 2033, 2100, + 2101, 2102, 2103, 2104, 2105, + + 0x453B, 0x453C, 0x453D, 0x453E, 0x453F, 0x4540, 0x4541, + 0x4542, 0x4543, 0x4544, 0x4545, 0x4546, 0x4547, 0x4548, + 0x4549, 0x454A, 0x454B, 0x454C, 0x454D, 0x454E, 0x454F + }; + + private static int[] m_SandTiles = new int[] + { + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 68, 69, 70, 71, 72, 73, 74, 75, + + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 402, 424, 425, 426, + 427, 441, 442, 443, 444, 445, 446, 447, 448, 449, + 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 465, 642, 643, 644, 645, + 650, 651, 652, 653, 654, 655, 656, 657, 821, 822, + 823, 824, 825, 826, 827, 828, 833, 834, 835, 836, + 845, 846, 847, 848, 849, 850, 851, 852, 857, 858, + 859, 860, 951, 952, 953, 954, 955, 956, 957, 958, + 967, 968, 969, 970, + + 1447, 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, + 1456, 1457, 1458, 1611, 1612, 1613, 1614, 1615, 1616, + 1617, 1618, 1623, 1624, 1625, 1626, 1635, 1636, 1637, + 1638, 1639, 1640, 1641, 1642, 1647, 1648, 1649, 1650 + }; + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/HelpGump.cs b/Scripts/Engines/Help/HelpGump.cs new file mode 100644 index 0000000..e6a435f --- /dev/null +++ b/Scripts/Engines/Help/HelpGump.cs @@ -0,0 +1,313 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Menus; +using Server.Menus.Questions; +using Server.Accounting; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Engines.Help +{ + public class ContainedMenu : QuestionMenu + { + private Mobile m_From; + + public ContainedMenu( Mobile from ) : base( "You already have an open help request. We will have someone assist you as soon as possible. What would you like to do?", new string[]{ "Leave my old help request like it is.", "Remove my help request from the queue." } ) + { + m_From = from; + } + + public override void OnCancel( NetState state ) + { + m_From.SendLocalizedMessage( 1005306, "", 0x35 ); // Help request unchanged. + } + + public override void OnResponse( NetState state, int index ) + { + if ( index == 0 ) + { + m_From.SendLocalizedMessage( 1005306, "", 0x35 ); // Help request unchanged. + } + else if ( index == 1 ) + { + PageEntry entry = PageQueue.GetEntry( m_From ); + + if ( entry != null && entry.Handler == null ) + { + m_From.SendLocalizedMessage( 1005307, "", 0x35 ); // Removed help request. + entry.AddResponse( entry.Sender, "[Canceled]" ); + PageQueue.Remove( entry ); + } + else + { + m_From.SendLocalizedMessage( 1005306, "", 0x35 ); // Help request unchanged. + } + } + } + } + + public class HelpGump : Gump + { + public static void Initialize() + { + EventSink.HelpRequest += new HelpRequestEventHandler( EventSink_HelpRequest ); + } + + private static void EventSink_HelpRequest( HelpRequestEventArgs e ) + { + foreach ( Gump g in e.Mobile.NetState.Gumps ) + { + if ( g is HelpGump ) + return; + } + + if ( !PageQueue.CheckAllowedToPage( e.Mobile ) ) + return; + + if ( PageQueue.Contains( e.Mobile ) ) + e.Mobile.SendMenu( new ContainedMenu( e.Mobile ) ); + else + e.Mobile.SendGump( new HelpGump( e.Mobile ) ); + } + + private static bool IsYoung( Mobile m ) + { + if ( m is PlayerMobile ) + return ((PlayerMobile)m).Young; + + return false; + } + + public static bool CheckCombat( Mobile m ) + { + for ( int i = 0; i < m.Aggressed.Count; ++i ) + { + AggressorInfo info = m.Aggressed[i]; + + if ( DateTime.Now - info.LastCombatTime < TimeSpan.FromSeconds( 30.0 ) ) + return true; + } + + return false; + } + + public HelpGump( Mobile from ) : base( 0, 0 ) + { + from.CloseGump( typeof( HelpGump ) ); + + bool isYoung = IsYoung( from ); + + AddBackground( 50, 25, 540, 430, 2600 ); + + AddPage( 0 ); + + AddHtmlLocalized( 150, 50, 360, 40, 1001002, false, false ); //
Ultima Online Help Menu
+ AddButton( 425, 415, 2073, 2072, 0, GumpButtonType.Reply, 0 ); // Close + + AddPage( 1 ); + + if ( isYoung ) + { + AddButton( 80, 75, 5540, 5541, 9, GumpButtonType.Reply, 2 ); + AddHtml( 110, 75, 450, 58, @"Young Player Haven Transport. Select this option if you want to be transported to Haven.", true, true ); + + AddButton( 80, 140, 5540, 5541, 1, GumpButtonType.Reply, 2 ); + AddHtml( 110, 140, 450, 58, @"General question about Ultima Online. Select this option if you have a general gameplay question, need help learning to use a skill, or if you would like to search the UO Knowledge Base.", true, true ); + + AddButton( 80, 205, 5540, 5541, 2, GumpButtonType.Reply, 0 ); + AddHtml( 110, 205, 450, 58, @"My character is physically stuck in the game. This choice only covers cases where your character is physically stuck in a location they cannot move out of. This option will only work two times in 24 hours.", true, true ); + + AddButton( 80, 270, 5540, 5541, 0, GumpButtonType.Page, 3 ); + AddHtml( 110, 270, 450, 58, @"Another player is harassing me. Another player is verbally harassing your character. When you select this option you will be sending a text log to Origin Systems. To see what constitutes harassment please visit http://support.uo.com/gm_9.html.", true, true ); + + AddButton( 80, 335, 5540, 5541, 0, GumpButtonType.Page, 2 ); + AddHtml( 110, 335, 450, 58, @"Other. If you are experiencing a problem in the game that does not fall into one of the other categories or is not addressed on the Support web page (located at http://support.uo.com), please use this option.", true, true ); + } + else + { + AddButton( 80, 90, 5540, 5541, 1, GumpButtonType.Reply, 2 ); + AddHtml( 110, 90, 450, 74, @"General question about Ultima Online. Select this option if you have a general gameplay question, need help learning to use a skill, or if you would like to search the UO Knowledge Base.", true, true ); + + AddButton( 80, 170, 5540, 5541, 2, GumpButtonType.Reply, 0 ); + AddHtml( 110, 170, 450, 74, @"My character is physically stuck in the game. This choice only covers cases where your character is physically stuck in a location they cannot move out of. This option will only work two times in 24 hours.", true, true ); + + AddButton( 80, 250, 5540, 5541, 0, GumpButtonType.Page, 3 ); + AddHtml( 110, 250, 450, 74, @"Another player is harassing me. Another player is verbally harassing your character. When you select this option you will be sending a text log to Origin Systems. To see what constitutes harassment please visit http://support.uo.com/gm_9.html.", true, true ); + + AddButton( 80, 330, 5540, 5541, 0, GumpButtonType.Page, 2 ); + AddHtml( 110, 330, 450, 74, @"Other. If you are experiencing a problem in the game that does not fall into one of the other categories or is not addressed on the Support web page (located at http://support.uo.com), please use this option.", true, true ); + } + + AddPage( 2 ); + + AddButton( 80, 90, 5540, 5541, 3, GumpButtonType.Reply, 0 ); + AddHtml( 110, 90, 450, 74, @"Report a bug or contact Origin. Use this option to launch your web browser and mail in a bug report. Your report will be read by our Quality Assurance Staff. We apologize for not being able to reply to individual reports. ", true, true ); + + AddButton( 80, 170, 5540, 5541, 4, GumpButtonType.Reply, 0 ); + AddHtml( 110, 170, 450, 74, @"Suggestion for the Game. If you'd like to make a suggestion for the game, it should be directed to the Development Team Members who participate in the discussion forums on the UO.Com web site. Choosing this option will take you to the Discussion Forums. ", true, true ); + + AddButton( 80, 250, 5540, 5541, 5, GumpButtonType.Reply, 0 ); + AddHtml( 110, 250, 450, 74, @"Account Management For questions regarding your account such as forgotten passwords, payment options, account activation, and account transfer, please choose this option.", true, true ); + + AddButton( 80, 330, 5540, 5541, 6, GumpButtonType.Reply, 0 ); + AddHtml( 110, 330, 450, 74, @"Other. If you are experiencing a problem in the game that does not fall into one of the other categories or is not addressed on the Support web page (located at http://support.uo.com), and requires in-game assistance, use this option. ", true, true ); + + AddPage( 3 ); + + AddButton( 80, 90, 5540, 5541, 7, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 110, 90, 450, 145, 1062572, true, true ); /*
Another player is harassing me (or Exploiting).

+ * VERBAL HARASSMENT
+ * Use this option when another player is verbally harassing your character. + * Verbal harassment behaviors include but are not limited to, using bad language, threats etc.. + * Before you submit a complaint be sure you understand what constitutes harassment + * � what is verbal harassment? - + * and that you have followed these steps:
+ * 1. You have asked the player to stop and they have continued.
+ * 2. You have tried to remove yourself from the situation.
+ * 3. You have done nothing to instigate or further encourage the harassment.
+ * 4. You have added the player to your ignore list. + * - How do I ignore a player?
+ * 5. You have read and understand Origin�s definition of harassment.
+ * 6. Your account information is up to date. (Including a current email address)
+ * *If these steps have not been taken, GMs may be unable to take action against the offending player.
+ * **A chat log will be review by a GM to assess the validity of this complaint. + * Abuse of this system is a violation of the Rules of Conduct.
+ * EXPLOITING
+ * Use this option to report someone who may be exploiting or cheating. + * � What constitutes an exploit? + */ + + AddButton( 80, 240, 5540, 5541, 8, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 110, 240, 450, 145, 1062573, true, true ); /*
Another player is harassing me using game mechanics.

+ *
+ * PHYSICAL HARASSMENT
+ * Use this option when another player is harassing your character using game mechanics. + * Physical harassment includes but is not limited to luring, Kill Stealing, and any act that causes a players death in Trammel. + * Before you submit a complaint be sure you understand what constitutes harassment + * � what is physical harassment? + * and that you have followed these steps:
+ * 1. You have asked the player to stop and they have continued.
+ * 2. You have tried to remove yourself from the situation.
+ * 3. You have done nothing to instigate or further encourage the harassment.
+ * 4. You have added the player to your ignore list. + * - how do I ignore a player?
+ * 5. You have read and understand Origin�s definition of harassment.
+ * 6. Your account information is up to date. (Including a current email address)
+ * *If these steps have not been taken, GMs may be unable to take action against the offending player.
+ * **This issue will be reviewed by a GM to assess the validity of this complaint. + * Abuse of this system is a violation of the Rules of Conduct. + */ + + AddButton( 150, 390, 5540, 5541, 0, GumpButtonType.Page, 1 ); + AddHtmlLocalized( 180, 390, 335, 40, 1001015, false, false ); // NO - I meant to ask for help with another matter. + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + PageType type = (PageType)(-1); + + switch ( info.ButtonID ) + { + case 0: // Close/Cancel + { + from.SendLocalizedMessage( 501235, "", 0x35 ); // Help request aborted. + + break; + } + case 1: // General question + { + type = PageType.Question; + break; + } + case 2: // Stuck + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if (house != null && house.IsAosRules && !from.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) // Dueling + { + from.Location = house.BanLocation; + } + else if (from.Region.IsPartOf(typeof(Server.Regions.Jail))) + { + from.SendLocalizedMessage(1114345, "", 0x35); // You'll need a better jailbreak plan then that! + } + else if ( Factions.Sigil.ExistsOn( from ) ) + { + from.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( from.CanUseStuckMenu() && from.Region.CanUseStuckMenu( from ) && !CheckCombat( from ) && !from.Frozen && !from.Criminal && (Core.AOS || from.Kills < 5) ) + { + StuckMenu menu = new StuckMenu( from, from, true ); + + menu.BeginClose(); + + from.SendGump( menu ); + } + else + { + type = PageType.Stuck; + } + + break; + } + case 3: // Report bug or contact Origin + { + type = PageType.Bug; + break; + } + case 4: // Game suggestion + { + type = PageType.Suggestion; + break; + } + case 5: // Account management + { + type = PageType.Account; + break; + } + case 6: // Other + { + type = PageType.Other; + break; + } + case 7: // Harassment: verbal/exploit + { + type = PageType.VerbalHarassment; + break; + } + case 8: // Harassment: physical + { + type = PageType.PhysicalHarassment; + break; + } + case 9: // Young player transport + { + if ( IsYoung( from ) ) + { + if (from.Region.IsPartOf(typeof(Regions.Jail))) + { + from.SendLocalizedMessage( 1041530, "", 0x35 ); // You'll need a better jailbreak plan then that! + } + else if ( from.Region.IsPartOf( "Haven Island" ) ) + { + from.SendLocalizedMessage( 1041529 ); // You're already in Haven + } + else + { + from.MoveToWorld( new Point3D( 3503, 2574, 14 ), Map.Trammel ); + } + } + + break; + } + } + + if ( type != (PageType)(-1) && PageQueue.CheckAllowedToPage( from ) ) + from.SendGump( new PagePromptGump( from, type ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/PagePrompt.cs b/Scripts/Engines/Help/PagePrompt.cs new file mode 100644 index 0000000..1345e77 --- /dev/null +++ b/Scripts/Engines/Help/PagePrompt.cs @@ -0,0 +1,30 @@ +using System; +using Server.Network; +using Server.Prompts; + +namespace Server.Engines.Help +{ + public class PagePrompt : Prompt + { + private PageType m_Type; + + public PagePrompt( PageType type ) + { + m_Type = type; + } + + public override void OnCancel( Mobile from ) + { + from.SendLocalizedMessage( 501235, "", 0x35 ); // Help request aborted. + } + + public override void OnResponse( Mobile from, string text ) + { + from.SendLocalizedMessage( 501234, "", 0x35 ); /* The next available Counselor/Game Master will respond as soon as possible. + * Please check your Journal for messages every few minutes. + */ + + PageQueue.Enqueue( new PageEntry( from, text, m_Type ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/PagePromptGump.cs b/Scripts/Engines/Help/PagePromptGump.cs new file mode 100644 index 0000000..dbe13d0 --- /dev/null +++ b/Scripts/Engines/Help/PagePromptGump.cs @@ -0,0 +1,61 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Help +{ + public class PagePromptGump : Gump + { + private Mobile m_From; + private PageType m_Type; + + public PagePromptGump( Mobile from, PageType type ) : base( 0, 0 ) + { + m_From = from; + m_Type = type; + + from.CloseGump( typeof( PagePromptGump ) ); + + AddBackground( 50, 50, 540, 350, 2600 ); + + AddPage( 0 ); + + AddHtmlLocalized( 264, 80, 200, 24, 1062524, false, false ); // Enter Description + AddHtmlLocalized( 120, 108, 420, 48, 1062638, false, false ); // Please enter a brief description (up to 200 characters) of your problem: + + AddBackground( 100, 148, 440, 200, 3500 ); + AddTextEntry( 120, 168, 400, 200, 1153, 0, "" ); + + AddButton( 175, 355, 2074, 2075, 1, GumpButtonType.Reply, 0 ); // Okay + AddButton( 405, 355, 2073, 2072, 0, GumpButtonType.Reply, 0 ); // Cancel + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 ) + { + m_From.SendLocalizedMessage( 501235, "", 0x35 ); // Help request aborted. + } + else + { + TextRelay entry = info.GetTextEntry( 0 ); + string text = ( entry == null ? "" : entry.Text.Trim() ); + + if ( text.Length == 0 ) + { + m_From.SendMessage( 0x35, "You must enter a description." ); + m_From.SendGump( new PagePromptGump( m_From, m_Type ) ); + } + else + { + m_From.SendLocalizedMessage( 501234, "", 0x35 ); /* The next available Counselor/Game Master will respond as soon as possible. + * Please check your Journal for messages every few minutes. + */ + + PageQueue.Enqueue( new PageEntry( m_From, text, m_Type ) ); + } + } + } + } +} diff --git a/Scripts/Engines/Help/PageQueue.cs b/Scripts/Engines/Help/PageQueue.cs new file mode 100644 index 0000000..1c7cdb3 --- /dev/null +++ b/Scripts/Engines/Help/PageQueue.cs @@ -0,0 +1,403 @@ +using System; +using System.Collections; +using System.Net.Mail; +using System.IO; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Misc; +using Server.Accounting; +using Server.Engines.Reports; +using Server.Commands; +using System.Collections.Generic; + +namespace Server.Engines.Help +{ + public enum PageType + { + Bug, + Stuck, + Account, + Question, + Suggestion, + Other, + VerbalHarassment, + PhysicalHarassment + } + + public class PageEntry + { + // What page types should have a speech log as attachment? + public static readonly PageType[] SpeechLogAttachment = new PageType[] + { + PageType.VerbalHarassment + }; + + private Mobile m_Sender; + private Mobile m_Handler; + private DateTime m_Sent; + private string m_Message; + private PageType m_Type; + private Point3D m_PageLocation; + private Map m_PageMap; + private List m_SpeechLog; + + private PageInfo m_PageInfo; + + public PageInfo PageInfo + { + get{ return m_PageInfo; } + } + + public Mobile Sender + { + get + { + return m_Sender; + } + } + + public Mobile Handler + { + get + { + return m_Handler; + } + set + { + PageQueue.OnHandlerChanged( m_Handler, value, this ); + m_Handler = value; + } + } + + public DateTime Sent + { + get + { + return m_Sent; + } + } + + public string Message + { + get + { + return m_Message; + } + } + + public PageType Type + { + get + { + return m_Type; + } + } + + public Point3D PageLocation + { + get + { + return m_PageLocation; + } + } + + public Map PageMap + { + get + { + return m_PageMap; + } + } + + public List SpeechLog + { + get + { + return m_SpeechLog; + } + } + + private Timer m_Timer; + + public void Stop() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + + public void AddResponse( Mobile mob, string text ) + { + if ( m_PageInfo != null ) + { + lock ( m_PageInfo ) + m_PageInfo.Responses.Add( PageInfo.GetAccount( mob ), text ); + + if ( PageInfo.ResFromResp( text ) != PageResolution.None ) + m_PageInfo.UpdateResolver(); + } + } + + public PageEntry( Mobile sender, string message, PageType type ) + { + m_Sender = sender; + m_Sent = DateTime.Now; + m_Message = Utility.FixHtml( message ); + m_Type = type; + m_PageLocation = sender.Location; + m_PageMap = sender.Map; + + PlayerMobile pm = sender as PlayerMobile; + if ( pm != null && pm.SpeechLog != null && Array.IndexOf( SpeechLogAttachment, type ) >= 0 ) + m_SpeechLog = new List( pm.SpeechLog ); + + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + + StaffHistory history = Reports.Reports.StaffHistory; + + if ( history != null ) + { + m_PageInfo = new PageInfo( this ); + + history.AddPage( m_PageInfo ); + } + } + + private class InternalTimer : Timer + { + private static TimeSpan StatusDelay = TimeSpan.FromMinutes( 2.0 ); + + private PageEntry m_Entry; + + public InternalTimer( PageEntry entry ) : base( TimeSpan.FromSeconds( 1.0 ), StatusDelay ) + { + m_Entry = entry; + } + + protected override void OnTick() + { + int index = PageQueue.IndexOf( m_Entry ); + + if ( m_Entry.Sender.NetState != null && index != -1 ) + { + m_Entry.Sender.SendLocalizedMessage( 1008077, true, (index + 1).ToString() ); // Thank you for paging. Queue status : + m_Entry.Sender.SendLocalizedMessage( 1008084 ); // You can reference our website at www.uo.com or contact us at support@uo.com. To cancel your page, please select the help button again and select cancel. + + if ( m_Entry.Handler != null && m_Entry.Handler.NetState == null ) { + m_Entry.Handler = null; + } + } + else + { + if ( index != -1 ) + m_Entry.AddResponse( m_Entry.Sender, "[Logout]" ); + + PageQueue.Remove( m_Entry ); + } + } + } + } + + public class PageQueue + { + private static ArrayList m_List = new ArrayList(); + private static Hashtable m_KeyedByHandler = new Hashtable(); + private static Hashtable m_KeyedBySender = new Hashtable(); + + public static void Initialize() + { + CommandSystem.Register( "Pages", AccessLevel.Counselor, new CommandEventHandler( Pages_OnCommand ) ); + } + + public static bool CheckAllowedToPage( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return true; + + if ( pm.DesignContext != null ) + { + from.SendLocalizedMessage( 500182 ); // You cannot request help while customizing a house or transferring a character. + return false; + } + else if ( pm.PagingSquelched ) + { + from.SendMessage( "You cannot request help, sorry." ); + return false; + } + + return true; + } + + public static string GetPageTypeName( PageType type ) + { + if ( type == PageType.VerbalHarassment ) + return "Verbal Harassment"; + else if ( type == PageType.PhysicalHarassment ) + return "Physical Harassment"; + else + return type.ToString(); + } + + public static void OnHandlerChanged( Mobile old, Mobile value, PageEntry entry ) + { + if ( old != null ) + m_KeyedByHandler.Remove( old ); + + if ( value != null ) + m_KeyedByHandler[value] = entry; + } + + [Usage( "Pages" )] + [Description( "Opens the page queue menu." )] + private static void Pages_OnCommand( CommandEventArgs e ) + { + PageEntry entry = (PageEntry)m_KeyedByHandler[e.Mobile]; + + if ( entry != null ) + { + e.Mobile.SendGump( new PageEntryGump( e.Mobile, entry ) ); + } + else if ( m_List.Count > 0 ) + { + e.Mobile.SendGump( new PageQueueGump() ); + } + else + { + e.Mobile.SendMessage( "The page queue is empty." ); + } + } + + public static bool IsHandling( Mobile check ) + { + return m_KeyedByHandler.ContainsKey( check ); + } + + public static bool Contains( Mobile sender ) + { + return m_KeyedBySender.ContainsKey( sender ); + } + + public static int IndexOf( PageEntry e ) + { + return m_List.IndexOf( e ); + } + + public static void Cancel( Mobile sender ) + { + Remove( (PageEntry) m_KeyedBySender[sender] ); + } + + public static void Remove( PageEntry e ) + { + if ( e == null ) + return; + + e.Stop(); + + m_List.Remove( e ); + m_KeyedBySender.Remove( e.Sender ); + + if ( e.Handler != null ) + m_KeyedByHandler.Remove( e.Handler ); + } + + public static PageEntry GetEntry( Mobile sender ) + { + return (PageEntry)m_KeyedBySender[sender]; + } + + public static void Remove( Mobile sender ) + { + Remove( GetEntry( sender ) ); + } + + public static ArrayList List + { + get + { + return m_List; + } + } + + public static void Enqueue( PageEntry entry ) + { + m_List.Add( entry ); + m_KeyedBySender[entry.Sender] = entry; + + bool isStaffOnline = false; + + foreach ( NetState ns in NetState.Instances ) + { + Mobile m = ns.Mobile; + + if ( m != null && m.AccessLevel >= AccessLevel.Counselor && m.AutoPageNotify && !IsHandling( m ) ) + m.SendMessage( "A new page has been placed in the queue." ); + + if ( m != null && m.AccessLevel >= AccessLevel.Counselor && m.AutoPageNotify && m.LastMoveTime >= (DateTime.Now - TimeSpan.FromMinutes( 10.0 )) ) + isStaffOnline = true; + } + + if ( !isStaffOnline ) + entry.Sender.SendMessage( "We are sorry, but no staff members are currently available to assist you. Your page will remain in the queue until one becomes available, or until you cancel it manually." ); + + // Scriptiz : on s'en fou du speech log ici afin de quand m�me envoyer les pages par email + if (Email.FromAddress != null && Email.SpeechLogPageAddresses != null /*&& entry.SpeechLog != null*/) + SendEmail(entry); + } + + private static void SendEmail(PageEntry entry) + { + Mobile sender = entry.Sender; + DateTime time = DateTime.Now; + + MailMessage mail = new MailMessage(Email.FromAddress, Email.SpeechLogPageAddresses); + + + // Scriptiz : sujet appropri� pour l'email + mail.Subject = "RunUO " + (entry.SpeechLog != null ? "Speech Log " : "") + "Page Forwarding"; + //mail.Subject = "RunUO Speech Log Page Forwarding"; + + using ( StringWriter writer = new StringWriter() ) + { + writer.WriteLine( "RunUO Speech Log Page - {0}", PageQueue.GetPageTypeName( entry.Type ) ); + writer.WriteLine(); + + writer.WriteLine( "From: '{0}', Account: '{1}'", sender.RawName, sender.Account is Account ? sender.Account.Username : "???" ); + writer.WriteLine( "Location: {0} [{1}]", sender.Location, sender.Map ); + writer.WriteLine( "Sent on: {0}/{1:00}/{2:00} {3}:{4:00}:{5:00}", time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second ); + writer.WriteLine(); + + writer.WriteLine( "Message:" ); + writer.WriteLine( "'{0}'", entry.Message ); + writer.WriteLine(); + + // Scriptiz : s'il s'agit d'un simple page sans speechlog on ne l'affiche pas + if (entry.SpeechLog != null) + { + writer.WriteLine("Speech Log"); + writer.WriteLine("=========="); + + foreach (SpeechLogEntry logEntry in entry.SpeechLog) + { + Mobile from = logEntry.From; + string fromName = from.RawName; + string fromAccount = from.Account is Account ? from.Account.Username : "???"; + DateTime created = logEntry.Created; + string speech = logEntry.Speech; + + writer.WriteLine("{0}:{1:00}:{2:00} - {3} ({4}): '{5}'", created.Hour, created.Minute, created.Second, fromName, fromAccount, speech); + } + } + + mail.Body = writer.ToString(); + } + + Email.AsyncSend( mail ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/PageQueueGump.cs b/Scripts/Engines/Help/PageQueueGump.cs new file mode 100644 index 0000000..24f0269 --- /dev/null +++ b/Scripts/Engines/Help/PageQueueGump.cs @@ -0,0 +1,834 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Network; +using Server.Gumps; + +namespace Server.Engines.Help +{ + public class MessageSentGump : Gump + { + private string m_Name, m_Text; + private Mobile m_Mobile; + + public MessageSentGump( Mobile mobile, string name, string text ) : base( 30, 30 ) + { + m_Name = name; + m_Text = text; + m_Mobile = mobile; + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 92, 75, 0xA3C ); + + AddImageTiled( 5, 7, 82, 61, 0xA40 ); + AddAlphaRegion( 5, 7, 82, 61 ); + + AddImageTiled( 9, 11, 21, 53, 0xBBC ); + + AddButton( 10, 12, 0x7D2, 0x7D2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 34, 28, 65, 24, 3001002, 0xFFFFFF, false, false ); // Message + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + m_Mobile.SendGump( new PageResponseGump( m_Mobile, m_Name, m_Text ) ); + + //m_Mobile.SendMessage( 0x482, "{0} tells you:", m_Name ); + //m_Mobile.SendMessage( 0x482, m_Text ); + } + } + + public class PageQueueGump : Gump + { + private PageEntry[] m_List; + + public PageQueueGump() : base( 30, 30 ) + { + Add( new GumpPage( 0 ) ); + //Add( new GumpBackground( 0, 0, 410, 448, 9200 ) ); + Add( new GumpImageTiled( 0, 0, 410, 448, 0xA40 ) ); + Add( new GumpAlphaRegion( 1, 1, 408, 446 ) ); + + Add( new GumpLabel( 180, 12, 2100, "Page Queue" ) ); + + ArrayList list = PageQueue.List; + + for ( int i = 0; i < list.Count; ) + { + PageEntry e = (PageEntry)list[i]; + + if ( e.Sender.Deleted || e.Sender.NetState == null ) + { + e.AddResponse( e.Sender, "[Logout]" ); + PageQueue.Remove( e ); + } + else + { + ++i; + } + } + + m_List = (PageEntry[])list.ToArray( typeof( PageEntry ) ); + + if ( m_List.Length > 0 ) + { + Add( new GumpPage( 1 ) ); + + for ( int i = 0; i < m_List.Length; ++i ) + { + PageEntry e = m_List[i]; + + if ( i >= 5 && (i % 5) == 0 ) + { + Add( new GumpButton( 368, 12, 0xFA5, 0xFA7, 0, GumpButtonType.Page, (i / 5) + 1 ) ); + Add( new GumpLabel( 298, 12, 2100, "Next Page" ) ); + Add( new GumpPage( (i / 5) + 1 ) ); + Add( new GumpButton( 12, 12, 0xFAE, 0xFB0, 0, GumpButtonType.Page, (i / 5) ) ); + Add( new GumpLabel( 48, 12, 2100, "Previous Page" ) ); + } + + string typeString = PageQueue.GetPageTypeName( e.Type ); + + string html = String.Format( "[{0}] {1} [{3}]", typeString, e.Message, e.Handler == null ? 0xFF0000 : 0xFF, e.Handler == null ? "Unhandled" : "Handling" ); + + Add( new GumpHtml( 12, 44 + ((i % 5) * 80), 350, 70, html, true, true ) ); + Add( new GumpButton( 370, 44 + ((i % 5) * 80) + 24, 0xFA5, 0xFA7, i + 1, GumpButtonType.Reply, 0 ) ); + } + } + else + { + Add( new GumpLabel( 12, 44, 2100, "The page queue is empty." ) ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID >= 1 && info.ButtonID <= m_List.Length ) + { + if ( PageQueue.List.IndexOf( m_List[info.ButtonID - 1] ) >= 0 ) + { + PageEntryGump g = new PageEntryGump( state.Mobile, m_List[info.ButtonID - 1] ); + + g.SendTo( state ); + } + else + { + state.Mobile.SendGump( new PageQueueGump() ); + state.Mobile.SendMessage( "That page has been removed." ); + } + } + } + } + + public class PredefinedResponse + { + private string m_Title; + private string m_Message; + + public string Title{ get{ return m_Title; } set{ m_Title = value; } } + public string Message{ get{ return m_Message; } set{ m_Message = value; } } + + public PredefinedResponse( string title, string message ) + { + m_Title = title; + m_Message = message; + } + + private static ArrayList m_List; + + public static ArrayList List + { + get + { + if ( m_List == null ) + m_List = Load(); + + return m_List; + } + } + + public static PredefinedResponse Add( string title, string message ) + { + if ( m_List == null ) + m_List = Load(); + + PredefinedResponse resp = new PredefinedResponse( title, message ); + + m_List.Add( resp ); + Save(); + + return resp; + } + + public static void Save() + { + if ( m_List == null ) + m_List = Load(); + + try + { + string path = Path.Combine( Core.BaseDirectory, "Data/pageresponse.cfg" ); + + using ( StreamWriter op = new StreamWriter( path ) ) + { + for ( int i = 0; i < m_List.Count; ++i ) + { + PredefinedResponse resp = (PredefinedResponse)m_List[i]; + + op.WriteLine( "{0}\t{1}", resp.Title, resp.Message ); + } + } + } + catch ( Exception e ) + { + Console.WriteLine( e ); + } + } + + public static ArrayList Load() + { + ArrayList list = new ArrayList(); + + string path = Path.Combine( Core.BaseDirectory, "Data/pageresponse.cfg" ); + + if ( File.Exists( path ) ) + { + try + { + using ( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + try + { + line = line.Trim(); + + if ( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + string[] split = line.Split( '\t' ); + + if ( split.Length == 2 ) + list.Add( new PredefinedResponse( split[0], split[1] ) ); + } + catch + { + } + } + } + } + catch ( Exception e ) + { + Console.WriteLine( e ); + } + } + + return list; + } + } + + public class PredefGump : Gump + { + private const int LabelColor32 = 0xFFFFFF; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public void AddTextInput( int x, int y, int w, int h, int id, string def ) + { + AddImageTiled( x, y, w, h, 0xA40 ); + AddImageTiled( x + 1, y + 1, w - 2, h - 2, 0xBBC ); + AddTextEntry( x + 3, y + 1, w - 4, h - 2, 0x480, id, def ); + } + + private Mobile m_From; + private PredefinedResponse m_Response; + + public PredefGump( Mobile from, PredefinedResponse response ) : base( 30, 30 ) + { + m_From = from; + m_Response = response; + + from.CloseGump( typeof( PredefGump ) ); + + bool canEdit = ( from.AccessLevel >= AccessLevel.GameMaster ); + + AddPage( 0 ); + + if ( response == null ) + { + AddImageTiled( 0, 0, 410, 448, 0xA40 ); + AddAlphaRegion( 1, 1, 408, 446 ); + + AddHtml( 10, 10, 390, 20, Color( Center( "Predefined Responses" ), LabelColor32 ), false, false ); + + ArrayList list = PredefinedResponse.List; + + AddPage( 1 ); + + int i; + + for ( i = 0; i < list.Count; ++i ) + { + if ( i >= 5 && (i % 5) == 0 ) + { + AddButton( 368, 10, 0xFA5, 0xFA7, 0, GumpButtonType.Page, (i / 5) + 1 ); + AddLabel( 298, 10, 2100, "Next Page" ); + AddPage( (i / 5) + 1 ); + AddButton( 12, 10, 0xFAE, 0xFB0, 0, GumpButtonType.Page, i / 5 ); + AddLabel( 48, 10, 2100, "Previous Page" ); + } + + PredefinedResponse resp = (PredefinedResponse)list[i]; + + string html = String.Format( "{0}
{1}", resp.Title, resp.Message ); + + AddHtml( 12, 44 + ((i % 5) * 80), 350, 70, html, true, true ); + + if ( canEdit ) + { + AddButton( 370, 44 + ((i % 5) * 80) + 24, 0xFA5, 0xFA7, 2 + (i * 3), GumpButtonType.Reply, 0 ); + + if ( i > 0 ) + AddButton( 377, 44 + ((i % 5) * 80) + 2, 0x15E0, 0x15E4, 3 + (i * 3), GumpButtonType.Reply, 0 ); + else + AddImage( 377, 44 + ((i % 5) * 80) + 2, 0x25E4 ); + + if ( i < (list.Count - 1) ) + AddButton( 377, 44 + ((i % 5) * 80) + 70 - 2 - 16, 0x15E2, 0x15E6, 4 + (i * 3), GumpButtonType.Reply, 0 ); + else + AddImage( 377, 44 + ((i % 5) * 80) + 70 - 2 - 16, 0x25E8 ); + } + } + + if ( canEdit ) + { + if ( i >= 5 && (i % 5) == 0 ) + { + AddButton( 368, 10, 0xFA5, 0xFA7, 0, GumpButtonType.Page, (i / 5) + 1 ); + AddLabel( 298, 10, 2100, "Next Page" ); + AddPage( (i / 5) + 1 ); + AddButton( 12, 10, 0xFAE, 0xFB0, 0, GumpButtonType.Page, i / 5 ); + AddLabel( 48, 10, 2100, "Previous Page" ); + } + + AddButton( 12, 44 + ((i % 5) * 80), 0xFAB, 0xFAD, 1, GumpButtonType.Reply, 0 ); + AddHtml( 45, 44 + ((i % 5) * 80), 200, 20, Color( "New Response", LabelColor32 ), false, false ); + } + } + else if ( canEdit ) + { + AddImageTiled( 0, 0, 410, 250, 0xA40 ); + AddAlphaRegion( 1, 1, 408, 248 ); + + AddHtml( 10, 10, 390, 20, Color( Center( "Predefined Response Editor" ), LabelColor32 ), false, false ); + + AddButton( 10, 40, 0xFB1, 0xFB3, 1, GumpButtonType.Reply, 0 ); + AddHtml( 45, 40, 200, 20, Color( "Remove", LabelColor32 ), false, false ); + + AddButton( 10, 70, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); + AddHtml( 45, 70, 200, 20, Color( "Title:", LabelColor32 ), false, false ); + AddTextInput( 10, 90, 300, 20, 0, response.Title ); + + AddButton( 10, 120, 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 ); + AddHtml( 45, 120, 200, 20, Color( "Message:", LabelColor32 ), false, false ); + AddTextInput( 10, 140, 390, 100, 1, response.Message ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_From.AccessLevel < AccessLevel.Administrator ) + return; + + if ( m_Response == null ) + { + int index = info.ButtonID - 1; + + if ( index == 0 ) + { + PredefinedResponse resp = new PredefinedResponse( "", "" ); + + ArrayList list = PredefinedResponse.List; + list.Add( resp ); + + m_From.SendGump( new PredefGump( m_From, resp ) ); + } + else + { + --index; + + int type = index % 3; + index /= 3; + + ArrayList list = PredefinedResponse.List; + + if ( index >= 0 && index < list.Count ) + { + PredefinedResponse resp = (PredefinedResponse)list[index]; + + switch ( type ) + { + case 0: // edit + { + m_From.SendGump( new PredefGump( m_From, resp ) ); + break; + } + case 1: // move up + { + if ( index > 0 ) + { + list.RemoveAt( index ); + list.Insert( index - 1, resp ); + + PredefinedResponse.Save(); + m_From.SendGump( new PredefGump( m_From, null ) ); + } + + break; + } + case 2: // move down + { + if ( index < (list.Count - 1) ) + { + list.RemoveAt( index ); + list.Insert( index + 1, resp ); + + PredefinedResponse.Save(); + m_From.SendGump( new PredefGump( m_From, null ) ); + } + + break; + } + } + } + } + } + else + { + ArrayList list = PredefinedResponse.List; + + switch ( info.ButtonID ) + { + case 1: + { + list.Remove( m_Response ); + + PredefinedResponse.Save(); + m_From.SendGump( new PredefGump( m_From, null ) ); + break; + } + case 2: + { + TextRelay te = info.GetTextEntry( 0 ); + + if ( te != null ) + m_Response.Title = te.Text; + + PredefinedResponse.Save(); + m_From.SendGump( new PredefGump( m_From, m_Response ) ); + + break; + } + case 3: + { + TextRelay te = info.GetTextEntry( 1 ); + + if ( te != null ) + m_Response.Message = te.Text; + + PredefinedResponse.Save(); + m_From.SendGump( new PredefGump( m_From, m_Response ) ); + + break; + } + } + } + } + } + + public class PageEntryGump : Gump + { + private PageEntry m_Entry; + private Mobile m_Mobile; + + private static int[] m_AccessLevelHues = new int[] + { + 2100, + 2122, + 2117, + 2129, + 2415, + 2415, + 2415 + }; + + public PageEntryGump( Mobile m, PageEntry entry ) : base( 30, 30 ) + { + try + { + m_Mobile = m; + m_Entry = entry; + + int buttons = 0; + + int bottom = 356; + + AddPage( 0 ); + + AddImageTiled( 0, 0, 410, 456, 0xA40 ); + AddAlphaRegion( 1, 1, 408, 454 ); + + AddPage( 1 ); + + AddLabel( 18, 18, 2100, "Sent:" ); + AddLabelCropped( 128, 18, 264, 20, 2100, entry.Sent.ToString() ); + + AddLabel( 18, 38, 2100, "Sender:" ); + AddLabelCropped( 128, 38, 264, 20, 2100, String.Format( "{0} {1} [{2}]", entry.Sender.RawName, entry.Sender.Location, entry.Sender.Map ) ); + + AddButton( 18, bottom - (buttons * 22), 0xFAB, 0xFAD, 8, GumpButtonType.Reply, 0 ); + AddImageTiled( 52, bottom - (buttons * 22) + 1, 340, 80, 0xA40/*0xBBC*//*0x2458*/ ); + AddImageTiled( 53, bottom - (buttons * 22) + 2, 338, 78, 0xBBC/*0x2426*/ ); + AddTextEntry( 55, bottom - (buttons++ * 22) + 2, 336, 78, 0x480, 0, "" ); + + AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 0, GumpButtonType.Page, 2 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Predefined Response" ); + + if ( entry.Sender != m ) + { + AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Go to Sender" ); + } + + AddLabel( 18, 58, 2100, "Handler:" ); + + if ( entry.Handler == null ) + { + AddLabelCropped( 128, 58, 264, 20, 2100, "Unhandled" ); + + AddButton( 18, bottom - (buttons * 22), 0xFB1, 0xFB3, 5, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Delete Page" ); + + AddButton( 18, bottom - (buttons * 22), 0xFB7, 0xFB9, 4, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Handle Page" ); + } + else + { + AddLabelCropped( 128, 58, 264, 20, m_AccessLevelHues[(int)entry.Handler.AccessLevel], entry.Handler.Name ); + + if ( entry.Handler != m ) + { + AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Go to Handler" ); + } + else + { + AddButton( 18, bottom - (buttons * 22), 0xFA2, 0xFA4, 6, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Abandon Page" ); + + AddButton( 18, bottom - (buttons * 22), 0xFB7, 0xFB9, 7, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Page Handled" ); + } + } + + AddLabel( 18, 78, 2100, "Page Location:" ); + AddLabelCropped( 128, 78, 264, 20, 2100, String.Format( "{0} [{1}]", entry.PageLocation, entry.PageMap ) ); + + AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "Go to Page Location" ); + + if ( entry.SpeechLog != null ) + { + AddButton( 18, bottom - (buttons * 22), 0xFA5, 0xFA7, 10, GumpButtonType.Reply, 0 ); + AddLabel( 52, bottom - (buttons++ * 22), 2100, "View Speech Log" ); + } + + AddLabel( 18, 98, 2100, "Page Type:" ); + AddLabelCropped( 128, 98, 264, 20, 2100, PageQueue.GetPageTypeName( entry.Type ) ); + + AddLabel( 18, 118, 2100, "Message:" ); + AddHtml( 128, 118, 250, 100, entry.Message, true, true ); + + AddPage( 2 ); + + ArrayList preresp = PredefinedResponse.List; + + AddButton( 18, 18, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1 ); + AddButton( 410 - 18 - 32, 18, 0xFAB, 0xFAC, 9, GumpButtonType.Reply, 0 ); + + if ( preresp.Count == 0 ) + { + AddLabel( 52, 18, 2100, "There are no predefined responses." ); + } + else + { + AddLabel( 52, 18, 2100, "Back" ); + + for ( int i = 0; i < preresp.Count; ++i ) + { + AddButton( 18, 40 + (i * 22), 0xFA5, 0xFA7, 100 + i, GumpButtonType.Reply, 0 ); + AddLabel( 52, 40 + (i * 22), 2100, ((PredefinedResponse)preresp[i]).Title ); + } + } + } + catch ( Exception e ) + { + Console.WriteLine(e); + } + } + + public void Resend( NetState state ) + { + PageEntryGump g = new PageEntryGump( m_Mobile, m_Entry ); + + g.SendTo( state ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID != 0 && PageQueue.List.IndexOf( m_Entry ) < 0 ) + { + state.Mobile.SendGump( new PageQueueGump() ); + state.Mobile.SendMessage( "That page has been removed." ); + return; + } + + switch ( info.ButtonID ) + { + case 0: // close + { + if ( m_Entry.Handler != state.Mobile ) + { + PageQueueGump g = new PageQueueGump(); + + g.SendTo( state ); + } + + break; + } + case 1: // go to sender + { + Mobile m = state.Mobile; + + if ( m_Entry.Sender.Deleted ) + { + m.SendMessage( "That character no longer exists." ); + } + else if ( m_Entry.Sender.Map == null || m_Entry.Sender.Map == Map.Internal ) + { + m.SendMessage( "That character is not in the world." ); + } + else + { + m_Entry.AddResponse( state.Mobile, "[Go Sender]" ); + m.MoveToWorld( m_Entry.Sender.Location, m_Entry.Sender.Map ); + + m.SendMessage( "You have been teleported to that page's sender." ); + + Resend( state ); + } + + break; + } + case 2: // go to handler + { + Mobile m = state.Mobile; + Mobile h = m_Entry.Handler; + + if ( h != null ) + { + if ( h.Deleted ) + { + m.SendMessage( "That character no longer exists." ); + } + else if ( h.Map == null || h.Map == Map.Internal ) + { + m.SendMessage( "That character is not in the world." ); + } + else + { + m_Entry.AddResponse( state.Mobile, "[Go Handler]" ); + m.MoveToWorld( h.Location, h.Map ); + + m.SendMessage( "You have been teleported to that page's handler." ); + Resend( state ); + } + } + else + { + m.SendMessage( "Nobody is handling that page." ); + Resend( state ); + } + + break; + } + case 3: // go to page location + { + Mobile m = state.Mobile; + + if ( m_Entry.PageMap == null || m_Entry.PageMap == Map.Internal ) + { + m.SendMessage( "That location is not in the world." ); + } + else + { + m_Entry.AddResponse( state.Mobile, "[Go PageLoc]" ); + m.MoveToWorld( m_Entry.PageLocation, m_Entry.PageMap ); + + state.Mobile.SendMessage( "You have been teleported to the original page location." ); + + Resend( state ); + } + + break; + } + case 4: // handle page + { + if ( m_Entry.Handler == null ) + { + m_Entry.AddResponse( state.Mobile, "[Handling]" ); + m_Entry.Handler = state.Mobile; + + state.Mobile.SendMessage( "You are now handling the page." ); + } + else + { + state.Mobile.SendMessage( "Someone is already handling that page." ); + } + + Resend( state ); + + break; + } + case 5: // delete page + { + if ( m_Entry.Handler == null ) + { + m_Entry.AddResponse( state.Mobile, "[Deleting]" ); + PageQueue.Remove( m_Entry ); + + state.Mobile.SendMessage( "You delete the page." ); + + PageQueueGump g = new PageQueueGump(); + + g.SendTo( state ); + } + else + { + state.Mobile.SendMessage( "Someone is handling that page, it can not be deleted." ); + + Resend( state ); + } + + break; + } + case 6: // abandon page + { + if ( m_Entry.Handler == state.Mobile ) + { + m_Entry.AddResponse( state.Mobile, "[Abandoning]" ); + state.Mobile.SendMessage( "You abandon the page." ); + + m_Entry.Handler = null; + } + else + { + state.Mobile.SendMessage( "You are not handling that page." ); + } + + Resend( state ); + + break; + } + case 7: // page handled + { + if ( m_Entry.Handler == state.Mobile ) + { + m_Entry.AddResponse( state.Mobile, "[Handled]" ); + PageQueue.Remove( m_Entry ); + + m_Entry.Handler = null; + + state.Mobile.SendMessage( "You mark the page as handled, and remove it from the queue." ); + + PageQueueGump g = new PageQueueGump(); + + g.SendTo( state ); + } + else + { + state.Mobile.SendMessage( "You are not handling that page." ); + + Resend( state ); + } + + break; + } + case 8: // Send message + { + TextRelay text = info.GetTextEntry( 0 ); + + if ( text != null ) + { + m_Entry.AddResponse( state.Mobile, "[Response] " + text.Text ); + m_Entry.Sender.SendGump( new MessageSentGump( m_Entry.Sender, state.Mobile.Name, text.Text ) ); + //m_Entry.Sender.SendMessage( 0x482, "{0} tells you:", state.Mobile.Name ); + //m_Entry.Sender.SendMessage( 0x482, text.Text ); + } + + Resend( state ); + + break; + } + case 9: // predef overview + { + Resend( state ); + state.Mobile.SendGump( new PredefGump( state.Mobile, null ) ); + + break; + } + case 10: // View Speech Log + { + Resend( state ); + + if ( m_Entry.SpeechLog != null ) + { + Gump gump = new SpeechLogGump( m_Entry.Sender, m_Entry.SpeechLog ); + state.Mobile.SendGump( gump ); + } + + break; + } + default: + { + int index = info.ButtonID - 100; + ArrayList preresp = PredefinedResponse.List; + + if ( index >= 0 && index < preresp.Count ) + { + m_Entry.AddResponse( state.Mobile, "[PreDef] " + ((PredefinedResponse)preresp[index]).Title ); + m_Entry.Sender.SendGump( new MessageSentGump( m_Entry.Sender, state.Mobile.Name, ((PredefinedResponse)preresp[index]).Message ) ); + } + + Resend( state ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/PageResponseGump.cs b/Scripts/Engines/Help/PageResponseGump.cs new file mode 100644 index 0000000..df23124 --- /dev/null +++ b/Scripts/Engines/Help/PageResponseGump.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Help +{ + public class PageResponseGump : Gump + { + private Mobile m_From; + private string m_Name, m_Text; + + public PageResponseGump( Mobile from, string name, string text ) : base( 0, 0 ) + { + m_From = from; + m_Name = name; + m_Text = text; + + AddBackground( 50, 25, 540, 430, 2600 ); + + AddPage( 0 ); + + AddHtmlLocalized( 150, 40, 360, 40, 1062610, false, false ); //
Ultima Online Help Response
+ + AddHtml( 80, 90, 480, 290, String.Format( "{0} tells {1}: {2}", name, from.Name, text ), true, true ); + + AddHtmlLocalized( 80, 390, 480, 40, 1062611, false, false ); // Clicking the OKAY button will remove the reponse you have received. + AddButton( 400, 417, 2074, 2075, 1, GumpButtonType.Reply, 0 ); // OKAY + + AddButton( 475, 417, 2073, 2072, 0, GumpButtonType.Reply, 0 ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID != 1 ) + m_From.SendGump( new MessageSentGump( m_From, m_Name, m_Text ) ); + } + } +} diff --git a/Scripts/Engines/Help/SpeechLog.cs b/Scripts/Engines/Help/SpeechLog.cs new file mode 100644 index 0000000..5b73994 --- /dev/null +++ b/Scripts/Engines/Help/SpeechLog.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Gumps; +using Server.Commands; +using System.Collections.Generic; + +namespace Server.Engines.Help +{ + public class SpeechLog : IEnumerable + { + // Are speech logs enabled? + public static readonly bool Enabled = true; + + // How long should we maintain each speech entry? + public static readonly TimeSpan EntryDuration = TimeSpan.FromMinutes( 20.0 ); + + // What is the maximum number of entries a log can contain? (0 -> no limit) + public static readonly int MaxLength = 0; + + public static void Initialize() + { + CommandSystem.Register("SpeechLog", AccessLevel.Counselor, new CommandEventHandler(SpeechLog_OnCommand)); + } + + [Usage( "SpeechLog" )] + [Description( "Opens the speech log of a given target." )] + private static void SpeechLog_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + + from.SendMessage( "Target a player to view his speech log." ); + e.Mobile.Target = new SpeechLogTarget(); + } + + private class SpeechLogTarget : Target + { + public SpeechLogTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + PlayerMobile pm = targeted as PlayerMobile; + + if ( pm == null ) + { + from.SendMessage( "Speech logs aren't supported on that target." ); + } + else if ( from != targeted && from.AccessLevel <= pm.AccessLevel && from.AccessLevel != AccessLevel.Owner ) + { + from.SendMessage( "You don't have the required access level to view {0} speech log.", pm.Female ? "her" : "his" ); + } + else if ( pm.SpeechLog == null ) + { + from.SendMessage( "{0} has no speech log.", pm.Female ? "She" : "He" ); + } + else + { + CommandLogging.WriteLine( from, "{0} {1} viewing speech log of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( targeted ) ); + + Gump gump = new SpeechLogGump( pm, pm.SpeechLog ); + from.SendGump( gump ); + } + } + } + + private Queue m_Queue; + + public int Count{ get{ return m_Queue.Count; } } + + public SpeechLog() + { + m_Queue = new Queue(); + } + + public void Add( Mobile from, string speech ) + { + Add( new SpeechLogEntry( from, speech ) ); + } + + public void Add( SpeechLogEntry entry ) + { + if ( MaxLength > 0 && m_Queue.Count >= MaxLength ) + m_Queue.Dequeue(); + + Clean(); + + m_Queue.Enqueue( entry ); + } + + public void Clean() + { + while ( m_Queue.Count > 0 ) + { + SpeechLogEntry entry = (SpeechLogEntry) m_Queue.Peek(); + + if ( DateTime.Now - entry.Created > EntryDuration ) + m_Queue.Dequeue(); + else + break; + } + } + + public void CopyTo( SpeechLogEntry[] array, int index ) + { + m_Queue.CopyTo( array, index ); + } + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return m_Queue.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return m_Queue.GetEnumerator(); + } + + #endregion + } + + public class SpeechLogEntry + { + private Mobile m_From; + private string m_Speech; + private DateTime m_Created; + + public Mobile From{ get{ return m_From; } } + public string Speech{ get{ return m_Speech; } } + public DateTime Created{ get{ return m_Created; } } + + public SpeechLogEntry( Mobile from, string speech ) + { + m_From = from; + m_Speech = speech; + m_Created = DateTime.Now; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/SpeechLogGump.cs b/Scripts/Engines/Help/SpeechLogGump.cs new file mode 100644 index 0000000..b2b5f53 --- /dev/null +++ b/Scripts/Engines/Help/SpeechLogGump.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Gumps; +using Server.Accounting; +using Server.Network; + +namespace Server.Engines.Help +{ + public class SpeechLogGump : Gump + { + public static readonly int MaxEntriesPerPage = 30; + + private Mobile m_Player; + private List m_Log; + private int m_Page; + + public SpeechLogGump( Mobile player, SpeechLog log ) + : this( player, new List( log ) ) + { + } + + public SpeechLogGump( Mobile player, List log ) : this( player, log, ( log.Count - 1 ) / MaxEntriesPerPage ) + { + } + + public SpeechLogGump( Mobile player, List log, int page ) + : base( 500, 30 ) + { + m_Player = player; + m_Log = log; + m_Page = page; + + AddImageTiled( 0, 0, 300, 425, 0xA40 ); + AddAlphaRegion( 1, 1, 298, 423 ); + + string playerName = player.Name; + string playerAccount = player.Account is Account ? player.Account.Username : "???"; + + AddHtml( 10, 10, 280, 20, String.Format( "
SPEECH LOG - {0} ({1})
", playerName, Utility.FixHtml( playerAccount ) ), false, false ); + + int lastPage = ( log.Count - 1 ) / MaxEntriesPerPage; + + string sLog; + + if ( page < 0 || page > lastPage ) + { + sLog = ""; + } + else + { + int max = log.Count - ( lastPage - page ) * MaxEntriesPerPage; + int min = Math.Max( max - MaxEntriesPerPage, 0 ); + + StringBuilder builder = new StringBuilder(); + + for ( int i = min; i < max; i++ ) + { + SpeechLogEntry entry = log[i]; + + Mobile m = entry.From; + + string name = m.Name; + string account = m.Account is Account ? m.Account.Username : "???"; + string speech = entry.Speech; + + if ( i != min ) + builder.Append( "
" ); + + builder.AppendFormat( "{0} ({1}): {2}", name, Utility.FixHtml( account ), Utility.FixHtml( speech ) ); + } + + sLog = builder.ToString(); + } + + AddHtml( 10, 40, 280, 350, sLog, false, true ); + + if ( page > 0 ) + AddButton( 10, 395, 0xFAE, 0xFB0, 1, GumpButtonType.Reply, 0 ); // Previous page + + AddLabel( 45, 395, 0x481, String.Format( "Current page: {0}/{1}", page + 1, lastPage + 1 ) ); + + if ( page < lastPage ) + AddButton( 261, 395, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); // Next page + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + switch ( info.ButtonID ) + { + case 1: // Previous page + { + if ( m_Page - 1 >= 0 ) + from.SendGump( new SpeechLogGump( m_Player, m_Log, m_Page - 1 ) ); + + break; + } + case 2: // Next page + { + if ( ( m_Page + 1 ) * MaxEntriesPerPage < m_Log.Count ) + from.SendGump( new SpeechLogGump( m_Player, m_Log, m_Page + 1 ) ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Help/StuckMenu.cs b/Scripts/Engines/Help/StuckMenu.cs new file mode 100644 index 0000000..a353e2f --- /dev/null +++ b/Scripts/Engines/Help/StuckMenu.cs @@ -0,0 +1,302 @@ +using System; +using Server.Network; +using Server.Gumps; + +namespace Server.Menus.Questions +{ + public class StuckMenuEntry + { + private int m_Name; + private Point3D[] m_Locations; + + public int Name { get { return m_Name; } } + public Point3D[] Locations{ get{ return m_Locations; } } + + public StuckMenuEntry( int name, Point3D[] locations) + { + m_Name = name; + m_Locations = locations; + } + } + + public class StuckMenu : Gump + { + private static StuckMenuEntry[] m_Entries = new StuckMenuEntry[] + { + new StuckMenuEntry( 1078608, new Point3D[] + { + new Point3D( 3503, 2574, 14 ) + /*new Point3D( 1519, 1619, 10 ), + new Point3D( 1457, 1538, 30 ), + new Point3D( 1607, 1568, 20 ), + new Point3D( 1643, 1680, 18 )*/ + } ), + /*// Britain + new StuckMenuEntry( 1011028, new Point3D[] + { + new Point3D( 1522, 1757, 28 ), + new Point3D( 1519, 1619, 10 ), + new Point3D( 1457, 1538, 30 ), + new Point3D( 1607, 1568, 20 ), + new Point3D( 1643, 1680, 18 ) + } ), + + // Trinsic + new StuckMenuEntry( 1011029, new Point3D[] + { + new Point3D( 2005, 2754, 30 ), + new Point3D( 1993, 2827, 0 ), + new Point3D( 2044, 2883, 0 ), + new Point3D( 1876, 2859, 20 ), + new Point3D( 1865, 2687, 0 ) + } ), + + // Vesper + new StuckMenuEntry( 1011030, new Point3D[] + { + new Point3D( 2973, 891, 0 ), + new Point3D( 3003, 776, 0 ), + new Point3D( 2910, 727, 0 ), + new Point3D( 2865, 804, 0 ), + new Point3D( 2832, 927, 0 ) + } ), + + // Minoc + new StuckMenuEntry( 1011031, new Point3D[] + { + new Point3D( 2498, 392, 0 ), + new Point3D( 2433, 541, 0 ), + new Point3D( 2445, 501, 15 ), + new Point3D( 2501, 469, 15 ), + new Point3D( 2444, 420, 15 ) + } ), + + // Yew + new StuckMenuEntry( 1011032, new Point3D[] + { + new Point3D( 490, 1166, 0 ), + new Point3D( 652, 1098, 0 ), + new Point3D( 650, 1013, 0 ), + new Point3D( 536, 979, 0 ), + new Point3D( 464, 970, 0 ) + } ), + + // Cove + new StuckMenuEntry( 1011033, new Point3D[] + { + new Point3D( 2230, 1159, 0 ), + new Point3D( 2218, 1203, 0 ), + new Point3D( 2247, 1194, 0 ), + new Point3D( 2236, 1224, 0 ), + new Point3D( 2273, 1231, 0 ) + } )*/ + }; + + private static StuckMenuEntry[] m_T2AEntries = new StuckMenuEntry[] + { + /*// Papua + new StuckMenuEntry( 1011057, new Point3D[] + { + new Point3D( 5720, 3109, -1 ), + new Point3D( 5677, 3176, -3 ), + new Point3D( 5678, 3227, 0 ), + new Point3D( 5769, 3206, -2 ), + new Point3D( 5777, 3270, -1 ) + } ), + + // Delucia + new StuckMenuEntry( 1011058, new Point3D[] + { + new Point3D( 5216, 4033, 37 ), + new Point3D( 5262, 4049, 37 ), + new Point3D( 5284, 4006, 37 ), + new Point3D( 5189, 3971, 39 ), + new Point3D( 5243, 3960, 37 ) + } )*/ + }; + + private static bool IsInSecondAgeArea( Mobile m ) + { + if ( m.Map != Map.Trammel && m.Map != Map.Felucca ) + return false; + + if ( m.X >= 5120 && m.Y >= 2304 ) + return true; + + if ( m.Region.IsPartOf( "Terathan Keep" ) ) + return true; + + return false; + } + + private Mobile m_Mobile, m_Sender; + private bool m_MarkUse; + + private Timer m_Timer; + + public StuckMenu( Mobile beholder, Mobile beheld, bool markUse ) : base( 150, 50 ) + { + m_Sender = beholder; + m_Mobile = beheld; + m_MarkUse = markUse; + + Closable = false; + Dragable = false; + Disposable = false; + + AddBackground( 0, 0, 270, 320, 2600 ); + + AddHtmlLocalized( 50, 20, 250, 35, 1011027, false, false ); // Chose a town: + + StuckMenuEntry[] entries = IsInSecondAgeArea( beheld ) ? m_T2AEntries : m_Entries; + + for ( int i = 0; i < entries.Length; i++ ) + { + StuckMenuEntry entry = entries[i]; + + AddButton( 50, 55 + 35 * i, 208, 209, i + 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 75, 55 + 35 * i, 335, 40, entry.Name, false, false ); + } + + AddButton( 55, 263, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 90, 265, 200, 35, 1011012, false, false ); // CANCEL + } + + public void BeginClose() + { + StopClose(); + + m_Timer = new CloseTimer( m_Mobile ); + m_Timer.Start(); + + m_Mobile.Frozen = true; + } + + public void StopClose() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Mobile.Frozen = false; + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + StopClose(); + + if ( Factions.Sigil.ExistsOn( m_Mobile ) ) + { + m_Mobile.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( info.ButtonID == 0 ) + { + if ( m_Mobile == m_Sender ) + m_Mobile.SendLocalizedMessage( 1010588 ); // You choose not to go to any city. + } + else if (m_Mobile.Map == Map.TerMur) + { + m_Mobile.SendMessage("Vous ne pourrez sortir d'ici aussi facilement"); + } + else + { + int index = info.ButtonID - 1; + StuckMenuEntry[] entries = IsInSecondAgeArea( m_Mobile ) ? m_T2AEntries : m_Entries; + + if ( index >= 0 && index < entries.Length ) + Teleport( entries[index] ); + } + } + + private void Teleport( StuckMenuEntry entry ) + { + if ( m_MarkUse ) + { + m_Mobile.SendLocalizedMessage( 1010589 ); // You will be teleported within the next two minutes. + + new TeleportTimer( m_Mobile, entry, TimeSpan.FromSeconds( 10.0 + (Utility.RandomDouble() * 110.0) ) ).Start(); + + m_Mobile.UsedStuckMenu(); + } + else + { + new TeleportTimer( m_Mobile, entry, TimeSpan.Zero ).Start(); + } + } + + private class CloseTimer : Timer + { + private Mobile m_Mobile; + private DateTime m_End; + + public CloseTimer( Mobile m ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_End = DateTime.Now + TimeSpan.FromMinutes( 3.0 ); + } + + protected override void OnTick() + { + if ( m_Mobile.NetState == null || DateTime.Now > m_End ) + { + m_Mobile.Frozen = false; + m_Mobile.CloseGump( typeof( StuckMenu ) ); + + Stop(); + } + else + { + m_Mobile.Frozen = true; + } + } + } + + private class TeleportTimer : Timer + { + private Mobile m_Mobile; + private StuckMenuEntry m_Destination; + private DateTime m_End; + + public TeleportTimer( Mobile mobile, StuckMenuEntry destination, TimeSpan delay ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) ) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Mobile = mobile; + m_Destination = destination; + m_End = DateTime.Now + delay; + } + + protected override void OnTick() + { + if ( DateTime.Now < m_End ) + { + m_Mobile.Frozen = true; + } + else + { + m_Mobile.Frozen = false; + Stop(); + + if ( Factions.Sigil.ExistsOn( m_Mobile ) ) + { + m_Mobile.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return; + } + + int idx = Utility.Random( m_Destination.Locations.Length ); + Point3D dest = m_Destination.Locations[idx]; + + Map destMap; + //if ( m_Mobile.Map == Map.Trammel ) + destMap = Map.Trammel; + /*else if ( m_Mobile.Map == Map.Felucca ) + destMap = Map.Felucca; + else + destMap = m_Mobile.Kills >= 5 ? Map.Felucca : Map.Trammel;*/ + + Mobiles.BaseCreature.TeleportPets( m_Mobile, dest, destMap ); + m_Mobile.MoveToWorld( dest, destMap ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Books/GrimmochJournal.cs b/Scripts/Engines/Khaldun/Books/GrimmochJournal.cs new file mode 100644 index 0000000..9de25fa --- /dev/null +++ b/Scripts/Engines/Khaldun/Books/GrimmochJournal.cs @@ -0,0 +1,779 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GrimmochJournal1 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day One :", + "", + "'Tis a grand sight, this", + "primeval tomb, I agree", + "with Tavara on that.", + "And we've a good crew", + "here, they've strong", + "backs and a good" + ), + new BookPageInfo + ( + "attitude. I'm a bit", + "concerned by those", + "that worked as guides", + "for us, however. All", + "seemed well enough", + "until we revealed the", + "immense stone doors", + "of the tomb structure" + ), + new BookPageInfo + ( + "itself. Seemed to send", + "a shiver up their", + "spines and get them all", + "stirred up with", + "whispering. I'll", + "watch the lot of them", + "with a close eye, but", + "I'm confident we won't" + ), + new BookPageInfo + ( + "have any real", + "problems on the dig.", + "I'm especially proud to", + "see Thomas standing", + "out - he was a good", + "hire, despite the", + "warnings from his", + "previous employers." + ), + new BookPageInfo + ( + "He's drummed up the", + "workers into a", + "furious pace - we've", + "nearly halved the", + "estimate on the", + "timeline for", + "excavating the Tomb's", + "entrance." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal1() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal2 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Two :", + "", + "We managed to dig out", + "the last of the", + "remaining rubble", + "today, revealing the", + "entirety of the giant", + "stone doors that sealed" + ), + new BookPageInfo + ( + "ol' Khal Ankur and", + "his folk up ages ago.", + "Actually getting them", + "open was another", + "matter altogether,", + "however. As the", + "workers set to the", + "task with picks and" + ), + new BookPageInfo + ( + "crowbars, I could have", + "sworn I saw Lysander", + "Gathenwale fiddling", + "with something in that", + "musty old tome of his.", + " I've no great", + "knowledge of things", + "magical, but the way" + ), + new BookPageInfo + ( + "his hand moved over", + "that book, and the look", + "of concentration on his", + "face as he whispered", + "something to himself", + "looked like every", + "description of an", + "incantation I've ever" + ), + new BookPageInfo + ( + "heard. The strange", + "thing is, this set of", + "doors that an entire", + "crew of excavators", + "was laboring over for", + "hours, right when", + "Gathenwale finishes", + "with his mumbling..." + ), + new BookPageInfo + ( + "well, I swore the doors", + "just gave open at the", + "exact moment he", + "spoke his last bit of", + "whisper and shut the", + "tome tight in his", + "hands. When he", + "looked up, it was" + ), + new BookPageInfo + ( + "almost as if he was", + "expecting the doors to", + "be open, rather than", + "shocked that they'd", + "finally given way." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal2() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal3 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Three - Day Five:", + "", + "I might have", + "written too hastily in", + "my first entry - this", + "place doesn't seem too", + "bent on giving up any", + "secrets. Though the" + ), + new BookPageInfo + ( + "main antechamber is", + "open to us, the main", + "exit hall is blocked by", + "yet another pile of", + "rubble. Doesn't look a", + "bit like anything", + "caused by a quake or", + "instability in the" + ), + new BookPageInfo + ( + "stonework... I swear it", + "looks as if someone", + "actually piled the", + "stones up themselves,", + "some time after the", + "tomb was built. The", + "stones aren't of the", + "same set nor quality" + ), + new BookPageInfo + ( + "of the carved work", + "that surrounds them", + "- if anything, they", + "resemble the grade of", + "common rock we saw", + "in great quantities on", + "the trip here. Which", + "makes it feel all the" + ), + new BookPageInfo + ( + "more like someone", + "hauled them in and", + "deliberately covered", + "this passage. But then", + "why not decorate them", + "in the same ornate", + "manner as the rest of", + "the stone in this" + ), + new BookPageInfo + ( + "place? Lysander", + "wouldn't hear a word", + "of what I had to say -", + "to him, it was a quake", + "some time in the", + "history of the tomb,", + "and that was it, shut", + "up and move on. So I" + ), + new BookPageInfo + ( + "shut up, and got back", + "to work." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal3() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal6 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Six :", + "", + "The camp was", + "attacked last night by", + "a pack of, well, I don't", + "have a clue. I've never", + "seen the like of these", + "beasts anywhere." + ), + new BookPageInfo + ( + "Huge things, with", + "fangs the size of your", + "forefinger, covered in", + "hair and with the", + "strangest arched back", + "I've ever seen. And so", + "many of them. We", + "were forced back into" + ), + new BookPageInfo + ( + "the Tomb for the", + "night, just to keep our", + "hides on us. And", + "today Gathenwale", + "practically orders us", + "all to move the entire", + "exterior camp into the", + "Tomb. Now, I don't" + ), + new BookPageInfo + ( + "disagree that we'd be", + "well off to use the", + "place as a point of", + "fortification... but I", + "don't like it one bit, in", + "any case. I don't like", + "the look of this place,", + "nor the sound of it." + ), + new BookPageInfo + ( + "The way the wind", + "gets into the", + "passageways,", + "whistling up the", + "strangest noises.", + "Deep, sustained echoes", + "of the wind, not so", + "much flute-like as..." + ), + new BookPageInfo + ( + "well, it sounds", + "ridiculous. In any", + "case, we've set to work", + "moving the bulk of the", + "exterior camp into the", + "main antechamber, so", + "there's no use moaning", + "about it now." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal6() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal6( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal7 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Seven - Day Ten:", + "", + "I cannot stand this", + "place, I cannot bear it.", + "I've got to get out.", + "Something evil lurks", + "in this ancient place,", + "something best left" + ), + new BookPageInfo + ( + "alone. I hear them,", + "yet none of the others", + "do. And yet they", + "must. Hands, claws,", + "scratching at stone,", + "the awful scratching", + "and the piteous cries", + "that sound almost like" + ), + new BookPageInfo + ( + "laughter. I can hear", + "them above even the", + "cracks of the", + "workmen's picks, and", + "at night they are all I", + "can hear. And yet the", + "others hear nothing.", + "We must leave this" + ), + new BookPageInfo + ( + "place, we must.", + "Three workers have", + "gone missing - Tavara", + "expects they've", + "abandoned us - and I", + "count them lucky if", + "they have. I don't care", + "what the others say," + ), + new BookPageInfo + ( + "we must leave this", + "place. We must do as", + "those before and pile", + "up the stones, block all", + "access to this primeval", + "crypt, seal it up again", + "for all eternity." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal7() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal7( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal11 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Eleven - Day", + "Thirteen :", + "", + "Lysander is gone, and", + "two more workers", + "with him. Good", + "riddance to the first.", + "He knows something." + ), + new BookPageInfo + ( + "He heard them too, I", + "know he did - and yet", + "he scowled at me", + "when I mentioned", + "them. I cannot stop", + "the noise in my head,", + "the scratching, the", + "clawing tears at my" + ), + new BookPageInfo + ( + "senses. What is it?", + "What does Lysander", + "seek that I can only", + "turn from? Where", + "has he gone? The", + "only answer to my", + "questions comes as", + "laughter from behind" + ), + new BookPageInfo + ( + "the stones." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal11() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal11( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal14 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Fourteen - Day", + "Sixteen :", + "", + "We are lost... we are", + "lost... all is lost. The", + "dead are piled up at", + "my feet. Bergen and I", + "somehow managed in" + ), + new BookPageInfo + ( + "the madness to piece", + "together a barricade,", + "barring access to the", + "camp antechamber.", + "He knows as well as I", + "that we cannot hold it", + "forever. The dead", + "come. They took" + ), + new BookPageInfo + ( + "Lysander before our", + "eyes. I pity the soul", + "of even such a", + "madman - no one", + "should die in such a", + "manner. And yet so", + "many have. We're", + "trapped here in this" + ), + new BookPageInfo + ( + "horror. So many have", + "died, and for what?", + "What curse have we", + "stumbled upon? I", + "cannot bear it, the", + "moaning, wailing cries", + "of the dead. Poor", + "Thomas, cut to pieces" + ), + new BookPageInfo + ( + "by their blades. We", + "had only an hour to", + "properly bury those", + "we could, before the", + "undead legions struck", + "again. I cannot go on...", + "I cannot go on." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal14() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal14( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal17 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Seventeen - Day", + "Twenty-Two :", + "", + "The fighting never", + "ceases... the blood", + "never stops flowing,", + "like a river through", + "the bloated corpses of" + ), + new BookPageInfo + ( + "the dead. And yet", + "there are still more.", + "Always more, with", + "the red fire gleaming", + "in their eyes. My", + "arm aches, I've taken", + "to the sword as my", + "bow seems to do little" + ), + new BookPageInfo + ( + "good... the dull ache in", + "my arm... so many", + "swings, cleaving a", + "mountain of decaying", + "flesh. And Thomas...", + "he was there, in the", + "thick of it... Thomas", + "was beside me..." + ), + new BookPageInfo + ( + "his face cleaved in", + "twain - and yet beside", + "me, fighting with us", + "against the horde until", + "he was cut down once", + "again. And I swear I", + "see him even now,", + "there in the dark" + ), + new BookPageInfo + ( + "corner of the", + "antechamber, his eyes", + "flickering in the last", + "dying embers of the", + "fire... and he stares at", + "me, and a scream fills", + "the vault - whether", + "his or mine, I can no" + ), + new BookPageInfo + ( + "longer tell." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal17() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal17( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GrimmochJournal23 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The daily journal of Grimmoch Drummel", "Grimmoch", + new BookPageInfo + ( + "Day Twenty-Three :", + "", + "We no longer bury the", + "dead." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrimmochJournal23() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public GrimmochJournal23( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Books/LysanderNotebook.cs b/Scripts/Engines/Khaldun/Books/LysanderNotebook.cs new file mode 100644 index 0000000..e7b6ce4 --- /dev/null +++ b/Scripts/Engines/Khaldun/Books/LysanderNotebook.cs @@ -0,0 +1,539 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LysanderNotebook1 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Lysander's Notebook", "L. Gathenwale", + new BookPageInfo + ( + "Day One :", + "", + "At last, it stands", + "before me. The doors", + "of Thy Sanctum will", + "open to me now, after", + "all these years of", + "searching. I give" + ), + new BookPageInfo + ( + "myself unto Thee,", + "Khal Ankur, I have", + "come for Thy secrets", + "and I will kneel", + "prostrate before Thee.", + " Blessed are the", + "Keepers, praise unto", + "Thee, a thousand" + ), + new BookPageInfo + ( + "fortunes in the night." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LysanderNotebook1() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public LysanderNotebook1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LysanderNotebook2 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Lysander's Notebook", "L. Gathenwale", + new BookPageInfo + ( + "Day Two:", + "", + "The woman, Tavara", + "Sewel, is unbearable.", + "Her entire demeanor", + "sickens me. I would", + "take her life for Thee", + "now, my Lord. But I" + ), + new BookPageInfo + ( + "cannot alert the", + "others. Progress is", + "made too slowly, I", + "cannot stand this", + "perpetual waiting.", + "Today I knelt down", + "with the workers,", + "tossing stones and dirt" + ), + new BookPageInfo + ( + "aside with my very", + "hands as they dug at", + "the last of the rubble", + "covering the entrance", + "to Thy Sanctum. The", + "Sewel woman was", + "shocked at my", + "demeanor, dirtying" + ), + new BookPageInfo + ( + "my robes, on my", + "knees in the muck as I", + "clawed at the rocks.", + "She thought I did this", + "for those sickly", + "scholars, or for her,", + "or for what she", + "laughably calls 'The" + ), + new BookPageInfo + ( + "Gift of Discovery', of", + "learning. As if I did", + "not know what I went", + "to find! I come for", + "Thee, Master. Soon", + "shall I receive Thy", + "gifts, Thy blessings.", + "Patience, eternal" + ), + new BookPageInfo + ( + "patience. I must take", + "my lessons well. I", + "have learned from", + "Thee, Master, I have." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LysanderNotebook2() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public LysanderNotebook2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LysanderNotebook3 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Lysander's Notebook", "L. Gathenwale", + new BookPageInfo + ( + "Day Three - Day Six:", + "", + "What are these Beasts", + "that dare to defy our", + "presence here? Hast", + "Thou sent them,", + "Master? To tear", + "apart these foolish" + ), + new BookPageInfo + ( + "ones that accompany", + "me? That repugnant", + "pustule, Drummel, put", + "forth his absurd little", + "theories as to the", + "nature of the Beasts", + "that attacked our", + "camp, but I'll have" + ), + new BookPageInfo + ( + "none of his words. He", + "asks too many", + "questions. He is a", + "taint upon the grounds", + "of Thy Sanctum,", + "Master - I will deal", + "with him after the", + "Sewel woman." + ), + new BookPageInfo + ( + "Speaking of Sewel, I", + "have convinced that", + "empty-headed harlot", + "that we should move", + "our encampment", + "within the", + "antechamber. She", + "thinks I worry for" + ), + new BookPageInfo + ( + "her safety. I come", + "for thee, Master. I", + "make my camp in Thy", + "chambers. I sleep", + "under Thy roof. I can", + "feel Thine presence", + "even now. Soon,", + "Master. Soon." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LysanderNotebook3() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public LysanderNotebook3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LysanderNotebook7 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Lysander's Notebook", "L. Gathenwale", + new BookPageInfo + ( + "Day Seven :", + "", + "The Sewel woman", + "pratters on endlessly.", + "And she dares to", + "speak Thy Name,", + "Master! I wish so", + "vehemently to take a" + ), + new BookPageInfo + ( + "knife to that little", + "neck of hers. She", + "struts around the", + "chambers of Thy", + "Sanctum with her", + "repugnant airs, her", + "scholarly conjecture", + "on this or that. That I" + ), + new BookPageInfo + ( + "could peel the skin", + "from her face and", + "show her how vile and", + "ugly she truly is, how", + "unworthy of entrance", + "to Thy Sanctum. I", + "must take her,", + "Master. I must rend" + ), + new BookPageInfo + ( + "that little wench to", + "pieces. I ask this gift", + "of Thee, that I might", + "cleanse Thy Sanctum", + "of her presence. Give", + "me the Sewel woman", + "and I shall show you", + "my mastery of Death," + ), + new BookPageInfo + ( + "Master. I shall cut", + "her to bits and scatter", + "them before the", + "others as a warning.", + "I cannot stand her", + "presence, I cannot", + "abide it. And", + "Drummel! He is a" + ), + new BookPageInfo + ( + "pustule that must be", + "lanced, a sickness that", + "I must cure by blade", + "and fire. Not a trace", + "of him will be left", + "when I'm done with", + "him. Praises to Thee,", + "Master. I shall honor" + ), + new BookPageInfo + ( + "Thee with many", + "sacrifices, soon", + "enough." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LysanderNotebook7() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public LysanderNotebook7( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LysanderNotebook8 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Lysander's Notebook", "L. Gathenwale", + new BookPageInfo + ( + "Day Eight - Day Ten :", + "", + "Have you taken them,", + "Master? They could", + "not have found a way", + "past the stones that", + "block our path! The", + "three workers, My" + ), + new BookPageInfo + ( + "Master, where have", + "they gone? Curses", + "upon them! I'll cut", + "them all to pieces if", + "they show their faces", + "again, then burn the", + "rest alive upon a pyre,", + "for all to see, as a" + ), + new BookPageInfo + ( + "warning of Thy", + "Power. How could", + "they have gotten past", + "me? I sleep against", + "the very walls, to", + "hear Thy Words, to", + "feel Thy Breath. I", + "can find no egress" + ), + new BookPageInfo + ( + "from the chambers", + "that the Sewel woman", + "does not know of nor", + "have men working at", + "excavating. Where", + "have they gone,", + "Master? Have you", + "taken them, or do they" + ), + new BookPageInfo + ( + "truly flee from Thy", + "Presence? I will kill", + "them if they show", + "their faces again.", + "Give me Strength, my", + "Master, to let them", + "live a while longer,", + "until they have" + ), + new BookPageInfo + ( + "fulfilled their", + "purpose and I kneel", + "before Thee, covered", + "in their blood." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LysanderNotebook8() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public LysanderNotebook8( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LysanderNotebook11 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Lysander's Notebook", "L. Gathenwale", + new BookPageInfo + ( + "Day Eleven - Day", + "Thirteen:", + "", + "I come for Thee, my", + "Master. I come! The", + "way is clear, I have", + "found Thy path and", + "washed it in the blood" + ), + new BookPageInfo + ( + "of the two workers", + "that caught sight of", + "me. Ah, how sweet it", + "was to cut them open,", + "to see the blood pour", + "out in great torrents, to", + "stand in it, to revel in", + "it. If only I had time" + ), + new BookPageInfo + ( + "for the Sewel woman.", + "But there will be time", + "enough for her. I", + "have learned Thy", + "Patience, Master. I", + "come for Thee. I walk", + "Thy halls in penance,", + "my last steps in this" + ), + new BookPageInfo + ( + "repulsive living", + "frame. I come for", + "Thee and Thy Gifts,", + "my Master. Glory", + "Unto Thee, Khal", + "Ankur, Keeper of the", + "Seventh Death,", + "Master, Leader of the" + ), + new BookPageInfo + ( + "Chosen, the Khaldun.", + "Praises in Thy", + "Name, Master of Life", + "and Death, Lord of All.", + " Khal Ankur, Master,", + "Prophet, I join Thy", + "ranks this night, a", + "member of the" + ), + new BookPageInfo + ( + "Khaldun at last!" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LysanderNotebook11() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public LysanderNotebook11( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Books/TavarasJournal.cs b/Scripts/Engines/Khaldun/Books/TavarasJournal.cs new file mode 100644 index 0000000..16dcef0 --- /dev/null +++ b/Scripts/Engines/Khaldun/Books/TavarasJournal.cs @@ -0,0 +1,1333 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TavarasJournal1 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day One:", + "", + "The workers continue", + "tirelessly in their", + "efforts to unload our", + "supplies even as light", + "fades. I feel I should", + "lend a hand in the" + ), + new BookPageInfo + ( + "effort, and yet I", + "cannot bear to take my", + "attention away from", + "the magnificent stone", + "doors of the tomb.", + "Every inch of their", + "massive frame is", + "covered with" + ), + new BookPageInfo + ( + "intricately carved", + "design work - 'tis", + "truly a sight to see.", + "I've spent the day", + "sketching and", + "cataloging what I can", + "of them while my", + "companions set up our" + ), + new BookPageInfo + ( + "camp and make", + "preparations for", + "tomorrow's work.", + "Though the stonework", + "symbols inspire me to", + "new flights of fancy,", + "some of the workers", + "seem strangely" + ), + new BookPageInfo + ( + "fearful of them. I", + "cannot wait 'til the", + "morrow when those", + "ancient works of stone", + "shall swing open and", + "deliver unto me", + "everything I have", + "dreamed of for the" + ), + new BookPageInfo + ( + "last ten years of my", + "life." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal1() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal2 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Two:", + "", + "Everything we'd", + "heard and read of the", + "tomb has proved", + "correct - and yet,", + "nothing could prepare", + "me for the sight of it" + ), + new BookPageInfo + ( + "with my own eyes.", + "The Tomb of Khal", + "Ankur has given up", + "its secrets at last! The", + "intricate stonework", + "that covered the tomb", + "doors seems to", + "continue throughout" + ), + new BookPageInfo + ( + "the entirety of the", + "catacombs, each", + "hallway and room", + "yielding a seemingly", + "endless amount of", + "information for my", + "companions and I to", + "record. It will take" + ), + new BookPageInfo + ( + "years to catalogue the", + "entirety of the Tomb,", + "if those legends of its", + "massive size prove", + "true. Sadly, a good", + "deal of the Tomb's", + "interior has been", + "damaged or utterly" + ), + new BookPageInfo + ( + "destroyed, whether", + "by seismic activity in", + "the surrounding", + "mountainside or", + "merely the slow", + "efforts of Time", + "itself, I do not know.", + "A good deal of the" + ), + new BookPageInfo + ( + "stonework has been", + "cracked or collapsed", + "entirely, especially", + "near the entrance", + "supports of the main", + "hall. Our passage has", + "indeed already been", + "entirely blocked in the" + ), + new BookPageInfo + ( + "first major room", + "we've discovered, a", + "massive pile of", + "boulders and stones", + "blocking any exit", + "from the", + "antechamber. What", + "could have caused" + ), + new BookPageInfo + ( + "such a localized", + "disruption of the", + "support structures,", + "one can only guess -", + "but it will surely take", + "an entire afternoon's", + "effort to remove even", + "a fraction of it. I look" + ), + new BookPageInfo + ( + "forward to more", + "progress tomorrow", + "once the workers have", + "set to excavating the", + "hall." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal2() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal3 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Three - Day Five:", + "", + "I do not understand", + "this place... not as I", + "once thought I did.", + "Something palatable", + "seems to hinder our", + "every attempt to" + ), + new BookPageInfo + ( + "investigate this", + "ancient site.", + "Excavation work on", + "the first major", + "hallway finished only", + "yesterday - the", + "amount of stone and", + "rubble blocking the" + ), + new BookPageInfo + ( + "egress was", + "astounding, it stands", + "in immense piles", + "outside the Tomb's", + "entrance, as if we", + "were digging the", + "tunnels of this", + "abhorred place" + ), + new BookPageInfo + ( + "ourselves! The", + "satisfaction of", + "completing our efforts", + "was quickly thwarted,", + "however, as we", + "discovered the end of", + "the hallway we had", + "just revealed was" + ), + new BookPageInfo + ( + "blocked by yet another", + "colossal pile of stone.", + "I've had a few of the", + "workers set up", + "primitive scaffolding", + "in the main", + "antechamber so that I", + "can spend my time" + ), + new BookPageInfo + ( + "pouring over the detail", + "work on the stone", + "carvings while the", + "rest of our crew", + "continue excavating", + "the inner halls." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal3() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal6 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Six:", + "", + "Late last night our", + "camp was set upon by", + "a pack of wild beasts", + "- behemoth creatures", + "with a speed and", + "viciousness I'd n'ere" + ), + new BookPageInfo + ( + "before seen. Even", + "Grimmoch, well", + "versed in all manner", + "of wildlife, was", + "unsure as to their", + "nature - though I lay", + "blame upon the", + "darkness covering" + ), + new BookPageInfo + ( + "their movements", + "rather than on his", + "skill as a huntsman.", + "The attacks did not let", + "up the entire night,", + "and we were", + "eventually forced to", + "flee into the Tomb" + ), + new BookPageInfo + ( + "itself to take refuge", + "from the ravenous", + "creatures - e'en", + "Lysander's spells", + "could not keep the foul", + "things from attacking", + "in great numbers.", + "The Tomb performed" + ), + new BookPageInfo + ( + "well as an impromptu", + "fortress, and we", + "managed to spend the", + "night unscathed.", + "Morning's light", + "seemed to have", + "scattered the beasts,", + "as not a single one of" + ), + new BookPageInfo + ( + "them was to be seen as", + "we exited the Tomb -", + "not even a carcass of", + "the few that were", + "slain a'fore we fled.", + "Lysander set the crew", + "to work, moving our", + "supplies and gear into" + ), + new BookPageInfo + ( + "the Tomb, in case the", + "creatures did opt to", + "return. Such savage", + "fury had the beasts -", + "and not a single one", + "ever turned to run,", + "even in the face of", + "certain death." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal6() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal6( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal7 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Seven:", + "", + "T'was written that,", + "upon his death, Khal", + "Ankur's followers,", + "those known as the", + "Keepers of the", + "Seventh Death, sealed" + ), + new BookPageInfo + ( + "themselves within the", + "Sanctum they had", + "carved from the", + "mountains in his", + "honor. The Zealots of", + "his order entombed", + "the lesser followers", + "alive, then, when all" + ), + new BookPageInfo + ( + "but two remained, slit", + "their throats and", + "joined Khal Ankur in", + "death. Surely this is", + "not surprising for a", + "Cult that worshipped", + "death and sacrifice so", + "vehemently as it is" + ), + new BookPageInfo + ( + "said that the Keepers", + "did - and yet, to be in", + "this Tomb, to know", + "that somewhere in its", + "depths hundreds upon", + "hundreds of bodies", + "lay, sealed alive at", + "their own behest..." + ), + new BookPageInfo + ( + "I must confess that", + "the very thought of it", + "troubles my dreams at", + "night. I've asked", + "Lysander if we might", + "reestablish the camp", + "outside the Tomb,", + "setting up night" + ), + new BookPageInfo + ( + "watches and some sort", + "of fortification, but", + "he'll have none of it. I", + "did not press the", + "issue, as I suddenly", + "felt foolish even at", + "my askance." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal7() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal7( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal8 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Eight :", + "", + "Astounding progress", + "was made today, and", + "my very head spins", + "with the excitement", + "of it. Upon full", + "excavation of the far" + ), + new BookPageInfo + ( + "western hall, another", + "large antechamber", + "was revealed. By the", + "larger, mosaic style of", + "the wall carvings and", + "their framing, as well", + "as the numerous", + "vellum scrolls and" + ), + new BookPageInfo + ( + "tomes held within, the", + "room appears to have", + "been a great museum", + "or library of sorts.", + "The sheer amount of", + "written information", + "encased within this", + "room would surely" + ), + new BookPageInfo + ( + "take me decades to", + "study e'en if I could", + "immediately decipher", + "the strange text with", + "which it was written.", + "My sheer joy at the", + "discovery was quickly", + "noted by the brute" + ), + new BookPageInfo + ( + "known as Morg", + "Bergen, who, even in", + "his simple way,", + "seemed just as", + "delighted as I that", + "some progress had", + "been made. I must", + "confess, upon his" + ), + new BookPageInfo + ( + "inclusion in our party", + "at the beginning of", + "this journey I was", + "somewhat suspect of", + "his nature, but he has", + "a startlingly quick wit", + "about him for such a", + "massive, calloused" + ), + new BookPageInfo + ( + "warrior. While", + "Lysander and e'en", + "Grimmoch always", + "seem to investigate the", + "tomb with a scowling", + "determination, Bergen", + "seems to feel the same", + "thrill of discovery as" + ), + new BookPageInfo + ( + "I. I am proud to now", + "count him as a friend,", + "and am thankful for", + "his laughter as well", + "as his strength." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal8() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal8( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal9 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Nine - Day Ten:", + "", + "The excavation of the", + "next set of tunnels", + "has ceased, as three", + "of the workers have", + "gone missing in the", + "night. Bergen voiced" + ), + new BookPageInfo + ( + "the opinion that they", + "had most likely", + "abandoned our group", + "altogether and headed", + "back, as they were of", + "the number that", + "seemed especially", + "disturbed by the" + ), + new BookPageInfo + ( + "Tomb. Lysander had", + "other ideas, however.", + "In the middle of our", + "discussion on the", + "matter, he went into a", + "wild tirade on the", + "possibility that they", + "had somehow" + ), + new BookPageInfo + ( + "infiltrated the tomb's", + "interior without us.", + "The pure, hateful", + "venom in his voice", + "when he spoke of the", + "workers shocked me,", + "as I had always", + "thought him to be a" + ), + new BookPageInfo + ( + "levelheaded man of", + "great learning. As we", + "are still at work", + "digging out the rubble", + "that blocks all access", + "to the inner chambers,", + "I cannot help but", + "believe the workers" + ), + new BookPageInfo + ( + "must have fled the", + "site altogether, as", + "Bergen said." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal9() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal9( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal11 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Eleven - Day", + "Thirteen:", + "", + "Two more workers", + "have gone missing.", + "Even more disturbing", + "is the fact that", + "Lysander has joined" + ), + new BookPageInfo + ( + "them. Late last night", + "the workers finished", + "excavating the next", + "main hall, and we", + "retired to the main", + "antechamber and our", + "camp to rest up for", + "exploration on the" + ), + new BookPageInfo + ( + "'morrow. In the", + "middle of the night we", + "woke to a strange", + "howling sound, and as", + "the men prepared", + "themselves for", + "another onslaught of", + "the beasts that had" + ), + new BookPageInfo + ( + "troubled our outer", + "camp, it was noticed", + "that Lysander was", + "nowhere in our", + "number. I cannot", + "fathom where he has", + "gone - the newly", + "revealed chamber" + ), + new BookPageInfo + ( + "holds no immediate", + "egress, blocked again", + "by piles of stone and", + "rubble, and I cannot", + "believe that Lysander,", + "of all people, would", + "have fled this site -", + "indeed, he had lately" + ), + new BookPageInfo + ( + "grown almost fanatical", + "in his work to", + "discover more of the", + "secrets barred to us", + "by the consistently", + "slow progress of", + "excavating each new", + "hallway. The men are" + ), + new BookPageInfo + ( + "at work even now, and", + "as the ceaseless", + "thumps and cracks of", + "their picks", + "reverberate", + "throughout the", + "entirety of the tomb,", + "the dust continues to" + ), + new BookPageInfo + ( + "pour down from the", + "ancient stonework", + "above us like some", + "horrible, eldritch", + "curse upon us all." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal11() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal11( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal14 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Fourteen - Day", + "Fifteen:", + "", + "Lysander has", + "returned... and yet,", + "how can I describe the", + "horror of it? He", + "stands across the" + ), + new BookPageInfo + ( + "chamber from me", + "even now, a changed", + "man. His hair hangs", + "in grimy knots across", + "his face, his clothes", + "filthy and torn in", + "places... and the blood", + "- covered in blood, his" + ), + new BookPageInfo + ( + "skin shining in", + "scarlet reflections of", + "the torchlight. He", + "will let no one", + "approach; a thick,", + "rusted dagger in his", + "hand warding off any", + "attempts to overcome" + ), + new BookPageInfo + ( + "him. And the blood,", + "which runs down in", + "great rivulets from", + "his arms and hands -", + "it is not his own, and", + "this is enough to keep", + "us at a wary distance.", + "Morg Bergen wishes" + ), + new BookPageInfo + ( + "to subdue him", + "quickly, but there is", + "something in", + "Lysander's eyes - and", + "I remember the power", + "of his spells, even as", + "he swings the jagged", + "dagger back and forth" + ), + new BookPageInfo + ( + "in a wide swath", + "before him.", + "Something about the", + "sight of it makes my", + "stomach churn.", + "Something has", + "happened, something", + "that changes" + ), + new BookPageInfo + ( + "everything. Lysander", + "has lost his sanity to", + "this tomb... or to", + "something within it.", + "Do we dare approach?", + "We must make a", + "decision soon." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal14() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal14( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal16 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Sixteen:", + "", + "Why do I write? I", + "must... not so much", + "because there must be", + "some record of", + "this... what's", + "happened here... as" + ), + new BookPageInfo + ( + "for my own sanity.", + "The act of putting pen", + "to paper calms me,", + "focuses me, even in", + "this madness.", + "Lysander is dead. So", + "many are dead. And", + "we're trapped here," + ), + new BookPageInfo + ( + "trapped forever in", + "this nightmare. He", + "would not let us pass,", + "wild in his psychosis,", + "furious, spitting,", + "covered in blood, he", + "swung the ancient", + "dagger at any who" + ), + new BookPageInfo + ( + "approached. He", + "babbled incoherently,", + "cursed at us, the most", + "hateful curses,", + "prophecy, doom upon", + "us. Bergen would", + "have none of it.", + "Finally, he leapt at" + ), + new BookPageInfo + ( + "Lysander, his", + "massive axe at his", + "side. But he would not", + "be the end of the mad", + "mage... no... they", + "were... those hands,", + "covered in the dirt of", + "the grave, maggots," + ), + new BookPageInfo + ( + "filth. They rose up", + "behind Lysander.", + "That look of curiosity", + "on the mage's face as", + "Bergen skidded to a", + "halt... t'was almost a", + "moment of sanity for", + "him, surely, to" + ), + new BookPageInfo + ( + "attempt to comprehend", + "what could have", + "stopped the warrior in", + "his tracks. And then", + "they were upon him.", + "Skeletal hands, arms", + "and faces with loose,", + "corrupted flesh" + ), + new BookPageInfo + ( + "hanging from yellow", + "bone. Inhuman, yet", + "once human,", + "staggering towards us", + "as their companions", + "tore at Lysander,", + "coming towards us in", + "droves." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal16() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal16( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal16b : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Sixteen, Later :", + "", + "We ran. What could", + "we do? We ran back", + "towards the entrance,", + "cutting at them when", + "we could. T'was a", + "nightmare, and yet" + ), + new BookPageInfo + ( + "nothing to prepare us", + "for what would come.", + "We were almost there,", + "the entrance to this", + "abhorred crypt in", + "sight. Then the earth", + "shook with such a", + "force that we were" + ), + new BookPageInfo + ( + "dropped to our hands", + "and knees, stumbling", + "in the darkness with", + "those... those things", + "surely behind us.", + "The noise of falling", + "rock and crumbling", + "stone drowned out our" + ), + new BookPageInfo + ( + "piteous cries. No sign", + "of the entrance", + "remained.", + "We owe our lives to", + "Bergen, whose wits", + "returned quickly.", + "That he could make us", + "hurry back into the" + ), + new BookPageInfo + ( + "main antechamber...", + "actually run back", + "towards those eldritch", + "dead that stalked us.", + "But we did, the", + "strength of his", + "convictions enough for", + "us in the moment." + ), + new BookPageInfo + ( + "And at our campsite", + "we erected our last", + "defense, a pitiable", + "wall of wood and", + "stone, anything at", + "hand that might block", + "the tide of those", + "nightmare creatures." + ), + new BookPageInfo + ( + "And I sit against it", + "even now. I can hear", + "their moans, their", + "wailing cries in the", + "distance - they'll be", + "here soon, even at the", + "unhurried pace of the", + "shuffling dead." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal16b() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal16b( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal17 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Seventeen - Day", + "Eighteen :", + "", + "I cannot go on much", + "longer. I know now", + "t'was no work of the", + "earth that trapped us", + "here - I can feel His" + ), + new BookPageInfo + ( + "force in it. It was His", + "will, His power that", + "has sealed us here in", + "this nightmare. The", + "barricade will not be", + "enough. So many of", + "them. They come like", + "unto the ocean's waves" + ), + new BookPageInfo + ( + "- ceaseless,", + "neverending. For", + "every five we strike", + "down, another ten rise", + "up against us. And", + "like the sands we", + "cannot help but be", + "brought down, wasted" + ), + new BookPageInfo + ( + "away in this ocean of", + "blood." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal17() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal17( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TavarasJournal19 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal: Discovery of the Tomb", "Tavara Sewel", + new BookPageInfo + ( + "Day Nineteen - Day", + "Twenty-One :", + "", + "The barricade won't", + "hold - never, and", + "they'll come, they", + "come even now. I", + "would tear the last of" + ), + new BookPageInfo + ( + "it down, let them in to", + "devour us all, if only", + "to stop the screaming", + "- the awful, wailing", + "cries that fill the tomb", + "with their presence.", + "May my ancestors", + "forgive me, but it" + ), + new BookPageInfo + ( + "must be done. I must", + "end this." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TavarasJournal19() : base( Utility.Random( 0xFF1, 2 ), false ) + { + } + + public TavarasJournal19( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/KhaldunGen.cs b/Scripts/Engines/Khaldun/KhaldunGen.cs new file mode 100644 index 0000000..c2e7c43 --- /dev/null +++ b/Scripts/Engines/Khaldun/KhaldunGen.cs @@ -0,0 +1,211 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Commands +{ + public class GenKhaldun + { + private static int m_Count; + + public static void Initialize() + { + CommandSystem.Register( "GenKhaldun", AccessLevel.Administrator, new CommandEventHandler( GenKhaldun_OnCommand ) ); + } + + public static bool FindMorphItem( int x, int y, int z, int inactiveItemID, int activeItemID ) + { + IPooledEnumerable eable = Map.Felucca.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + foreach ( Item item in eable ) + { + if ( item is MorphItem && item.Z == z && ((MorphItem)item).InactiveItemID == inactiveItemID && ((MorphItem)item).ActiveItemID == activeItemID ) + { + eable.Free(); + return true; + } + } + + eable.Free(); + return false; + } + + public static bool FindEffectController( int x, int y, int z ) + { + IPooledEnumerable eable = Map.Felucca.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + foreach ( Item item in eable ) + { + if ( item is EffectController && item.Z == z ) + { + eable.Free(); + return true; + } + } + + eable.Free(); + return false; + } + + public static Item TryCreateItem( int x, int y, int z, Item srcItem ) + { + IPooledEnumerable eable = Map.Felucca.GetItemsInBounds( new Rectangle2D( x, y, 1, 1 ) ); + + foreach ( Item item in eable ) + { + if ( item.GetType() == srcItem.GetType() ) + { + eable.Free(); + srcItem.Delete(); + return item; + } + } + + eable.Free(); + srcItem.MoveToWorld( new Point3D( x, y, z ), Map.Felucca ); + m_Count++; + + return srcItem; + } + + public static void CreateMorphItem( int x, int y, int z, int inactiveItemID, int activeItemID, int range ) + { + if ( FindMorphItem( x, y, z, inactiveItemID, activeItemID ) ) + return; + + MorphItem item = new MorphItem( inactiveItemID, activeItemID, range, 3 ); + + item.MoveToWorld( new Point3D( x, y, z ), Map.Felucca ); + m_Count++; + } + + public static void CreateApproachLight( int x, int y, int z, int off, int on, LightType light ) + { + if ( FindMorphItem( x, y, z, off, on ) ) + return; + + MorphItem item = new MorphItem( off, on, 2, 3 ); + item.Light = light; + + item.MoveToWorld( new Point3D( x, y, z ), Map.Felucca ); + m_Count++; + } + + public static void CreateSoundEffect( int x, int y, int z, int sound, int range ) + { + if ( FindEffectController( x, y, z ) ) + return; + + EffectController item = new EffectController(); + item.SoundID = sound; + item.TriggerType = EffectTriggerType.InRange; + item.TriggerRange = range; + + item.MoveToWorld( new Point3D( x, y, z ), Map.Felucca ); + m_Count++; + } + + public static void CreateBigTeleporterItem( int x, int y, bool reverse ) + { + if ( FindMorphItem( x, y, 0, reverse ? 0x17DC : 0x17EE, reverse ? 0x17EE : 0x17DC ) ) + return; + + MorphItem item = new MorphItem( reverse ? 0x17DC : 0x17EE, reverse ? 0x17EE : 0x17DC, 1, 3 ); + + item.MoveToWorld( new Point3D( x, y, 0 ), Map.Felucca ); + m_Count++; + } + + public static void GenKhaldun_OnCommand( CommandEventArgs e ) + { + m_Count = 0; + + // Generate Morph Items + CreateMorphItem( 5459, 1416, 0, 0x1D0, 0x1, 1 ); + CreateMorphItem( 5460, 1416, 0, 0x1D0, 0x1, 1 ); + CreateMorphItem( 5459, 1416, 0, 0x1, 0x53D, 1 ); + CreateMorphItem( 5460, 1416, 0, 0x1, 0x53B, 1 ); + + CreateMorphItem( 5459, 1425, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5459, 1426, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5459, 1427, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5460, 1425, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5460, 1426, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5460, 1427, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5461, 1427, 0, 0x1, 0x53B, 2 ); + CreateMorphItem( 5460, 1422, 0, 0x1, 0x544, 2 ); + CreateMorphItem( 5460, 1419, 0, 0x1, 0x545, 2 ); + CreateMorphItem( 5460, 1420, 0, 0x1, 0x545, 2 ); + CreateMorphItem( 5460, 1423, 0, 0x1, 0x545, 2 ); + CreateMorphItem( 5460, 1424, 0, 0x1, 0x545, 2 ); + CreateMorphItem( 5461, 1426, 0, 0x1, 0x545, 2 ); + CreateMorphItem( 5460, 1417, 0, 0x1, 0x546, 1 ); + CreateMorphItem( 5460, 1418, 0, 0x1, 0x546, 2 ); + CreateMorphItem( 5460, 1421, 0, 0x1, 0x546, 2 ); + CreateMorphItem( 5461, 1425, 0, 0x1, 0x548, 2 ); + CreateMorphItem( 5459, 1420, 0, 0x1, 0x54A, 2 ); + CreateMorphItem( 5459, 1421, 0, 0x1, 0x54A, 2 ); + CreateMorphItem( 5459, 1423, 0, 0x1, 0x54A, 2 ); + CreateMorphItem( 5459, 1418, 0, 0x1, 0x54B, 2 ); + CreateMorphItem( 5459, 1422, 0, 0x1, 0x54B, 2 ); + CreateMorphItem( 5459, 1417, 0, 0x1, 0x54C, 1 ); + CreateMorphItem( 5459, 1419, 0, 0x1, 0x54C, 2 ); + CreateMorphItem( 5459, 1424, 0, 0x1, 0x54C, 2 ); + + CreateMorphItem( 5458, 1426, 0, 0x1, 0x1D1, 2 ); + CreateMorphItem( 5459, 1427, 0, 0x1, 0x1E3, 2 ); + CreateMorphItem( 5458, 1425, 3, 0x1, 0x1E4, 2 ); + CreateMorphItem( 5458, 1427, 6, 0x1, 0x1E5, 2 ); + CreateMorphItem( 5461, 1427, 0, 0x1, 0x1E8, 2 ); + CreateMorphItem( 5460, 1427, 0, 0x1, 0x1E9, 2 ); + CreateMorphItem( 5458, 1425, 0, 0x1, 0x1EA, 2 ); + CreateMorphItem( 5458, 1427, 0, 0x1, 0x1EA, 2 ); + CreateMorphItem( 5458, 1427, 3, 0x1, 0x1EA, 2 ); + + // Generate Approach Lights + CreateApproachLight( 5393, 1417, 0, 0x1857, 0x1858, LightType.Circle150 ); + CreateApproachLight( 5393, 1420, 0, 0x1857, 0x1858, LightType.Circle150 ); + CreateApproachLight( 5395, 1421, 0, 0x1857, 0x1858, LightType.Circle150 ); + CreateApproachLight( 5396, 1417, 0, 0x1857, 0x1858, LightType.Circle150 ); + CreateApproachLight( 5397, 1419, 0, 0x1857, 0x1858, LightType.Circle150 ); + + CreateApproachLight( 5441, 1393, 5, 0x1F2B, 0x19BB, LightType.Circle225 ); + CreateApproachLight( 5446, 1393, 5, 0x1F2B, 0x19BB, LightType.Circle225 ); + + // Generate Sound Effects + CreateSoundEffect( 5425, 1489, 5, 0x102, 1 ); + CreateSoundEffect( 5425, 1491, 5, 0x102, 1 ); + + CreateSoundEffect( 5449, 1499, 10, 0xF5, 1 ); + CreateSoundEffect( 5451, 1499, 10, 0xF5, 1 ); + CreateSoundEffect( 5453, 1499, 10, 0xF5, 1 ); + + CreateSoundEffect( 5524, 1367, 0, 0x102, 1 ); + + CreateSoundEffect( 5450, 1370, 0, 0x220, 2 ); + CreateSoundEffect( 5450, 1372, 0, 0x220, 2 ); + + CreateSoundEffect( 5460, 1416, 0, 0x244, 2 ); + + CreateSoundEffect( 5483, 1439, 5, 0x14, 3 ); + + // Generate Big Teleporter + CreateBigTeleporterItem( 5387, 1325, true ); + CreateBigTeleporterItem( 5388, 1326, true ); + CreateBigTeleporterItem( 5388, 1325, false ); + CreateBigTeleporterItem( 5387, 1326, false ); + + // Generate Central Khaldun entrance + DisappearingRaiseSwitch sw = TryCreateItem( 5459, 1426, 10, new DisappearingRaiseSwitch() ) as DisappearingRaiseSwitch; + RaiseSwitch lv = TryCreateItem( 5403, 1359, 0, new RaiseSwitch() ) as RaiseSwitch; + + RaisableItem stone = TryCreateItem( 5403, 1360, 0, new RaisableItem( 0x788, 10, 0x477, 0x475, TimeSpan.FromMinutes( 1.5 ) ) ) as RaisableItem; + RaisableItem door = TryCreateItem( 5524, 1367, 0, new RaisableItem( 0x1D0, 20, 0x477, 0x475, TimeSpan.FromMinutes( 5.0 ) ) ) as RaisableItem; + + sw.RaisableItem = stone; + lv.RaisableItem = door; + + e.Mobile.SendMessage( String.Format( "{0} dynamic Khaldun item{1} generated.", m_Count, m_Count == 1 ? "" : "s" ) ); + } + } +} diff --git a/Scripts/Engines/Khaldun/KhaldunPitTeleporter.cs b/Scripts/Engines/Khaldun/KhaldunPitTeleporter.cs new file mode 100644 index 0000000..24c05cb --- /dev/null +++ b/Scripts/Engines/Khaldun/KhaldunPitTeleporter.cs @@ -0,0 +1,108 @@ +using System; + +namespace Server.Items +{ + public class KhaldunPitTeleporter : Item + { + private bool m_Active; + private Point3D m_PointDest; + private Map m_MapDest; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get { return m_Active; } + set { m_Active = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D PointDest + { + get { return m_PointDest; } + set { m_PointDest = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Map MapDest + { + get { return m_MapDest; } + set { m_MapDest = value; } + } + + public override int LabelNumber{ get{ return 1016511; } } // the floor of the cavern seems to have collapsed here - a faint light is visible at the bottom of the pit + + [Constructable] + public KhaldunPitTeleporter() : this( new Point3D( 5451, 1374, 0 ), Map.Felucca ) + { + } + + [Constructable] + public KhaldunPitTeleporter( Point3D pointDest, Map mapDest ) : base( 0x053B ) + { + Movable = false; + Hue = 1; + + m_Active = true; + m_PointDest = pointDest; + m_MapDest = mapDest; + } + + public KhaldunPitTeleporter( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile m ) + { + if ( !m_Active ) + return; + + Map map = m_MapDest; + + if ( map == null || map == Map.Internal ) + map = m.Map; + + Point3D p = m_PointDest; + + if ( p == Point3D.Zero ) + p = m.Location; + + if ( m.InRange( this, 3 ) ) + { + Server.Mobiles.BaseCreature.TeleportPets( m, m_PointDest, m_MapDest ); + + m.MoveToWorld( m_PointDest, m_MapDest ); + } + else + { + m.SendLocalizedMessage( 1019045 ); // I can't reach that. + } + } + + public override void OnDoubleClickDead( Mobile m ) + { + OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( m_Active ); + writer.Write( m_PointDest ); + writer.Write( m_MapDest ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Active = reader.ReadBool(); + m_PointDest = reader.ReadPoint3D(); + m_MapDest = reader.ReadMap(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Mobiles/GrimmochDrummel.cs b/Scripts/Engines/Khaldun/Mobiles/GrimmochDrummel.cs new file mode 100644 index 0000000..7e23f2d --- /dev/null +++ b/Scripts/Engines/Khaldun/Mobiles/GrimmochDrummel.cs @@ -0,0 +1,131 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class GrimmochDrummel : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + [Constructable] + public GrimmochDrummel() : base( AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Title = "the Cursed"; + + Hue = 0x8596; + Body = 0x190; + Name = "Grimmoch Drummel"; + + HairItemID = 0x204A; //Krisna + + Bow bow = new Bow(); + bow.Movable = false; + AddItem( bow ); + + AddItem( new Boots( 0x8A4 ) ); + AddItem( new BodySash( 0x8A4 ) ); + + Backpack backpack = new Backpack(); + backpack.Movable = false; + AddItem( backpack ); + + LeatherGloves gloves = new LeatherGloves(); + LeatherChest chest = new LeatherChest(); + gloves.Hue = 0x96F; + chest.Hue = 0x96F; + + AddItem( gloves ); + AddItem( chest ); + + SetStr( 111, 120 ); + SetDex( 151, 160 ); + SetInt( 41, 50 ); + + SetHits( 180, 207 ); + SetMana( 0 ); + + SetDamage( 13, 16 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 45, 55 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 25 ); + + SetSkill( SkillName.Archery, 90.1, 110.0 ); + SetSkill( SkillName.Swords, 60.1, 70.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 60.1, 70.0 ); + SetSkill( SkillName.Anatomy, 90.1, 100.0 ); + + Fame = 5000; + Karma = -1000; + + PackItem( new Arrow( 40 ) ); + + if ( 3 > Utility.Random( 100 ) ) + PackItem( new FireHorn() ); + + if ( 1 > Utility.Random( 3 ) ) + PackItem( Loot.RandomGrimmochJournal() ); + } + + public override int GetIdleSound() + { + return 0x178; + } + + public override int GetAngerSound() + { + return 0x1AC; + } + + public override int GetDeathSound() + { + return 0x27E; + } + + public override int GetHurtSound() + { + return 0x177; + } + + public override bool OnBeforeDeath() + { + Gold gold = new Gold( Utility.RandomMinMax( 190, 230 ) ); + gold.MoveToWorld( Location, Map ); + + Container pack = this.Backpack; + if ( pack != null ) + { + pack.Movable = true; + pack.MoveToWorld( Location, Map ); + } + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public GrimmochDrummel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Mobiles/LysanderGathenwale.cs b/Scripts/Engines/Khaldun/Mobiles/LysanderGathenwale.cs new file mode 100644 index 0000000..14f5c2f --- /dev/null +++ b/Scripts/Engines/Khaldun/Mobiles/LysanderGathenwale.cs @@ -0,0 +1,132 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class LysanderGathenwale : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + [Constructable] + public LysanderGathenwale() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Title = "the Cursed"; + + Hue = 0x8838; + Body = 0x190; + Name = "Lysander Gathenwale"; + + AddItem( new Boots( 0x599 ) ); + AddItem( new Cloak( 0x96F ) ); + + Spellbook spellbook = new Spellbook(); + RingmailGloves gloves = new RingmailGloves(); + StuddedChest chest = new StuddedChest(); + PlateArms arms = new PlateArms(); + + spellbook.Hue = 0x599; + gloves.Hue = 0x599; + chest.Hue = 0x96F; + arms.Hue = 0x599; + + AddItem( spellbook ); + AddItem( gloves ); + AddItem( chest ); + AddItem( arms ); + + SetStr( 111, 120 ); + SetDex( 71, 80 ); + SetInt( 121, 130 ); + + SetHits( 180, 207 ); + SetMana( 227, 265 ); + + SetDamage( 5, 13 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 80.1, 90.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.EvalInt, 95.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + + Fame = 5000; + Karma = -10000; + + Item reags = Loot.RandomReagent(); + reags.Amount = 30; + PackItem( reags ); + } + + public override int GetIdleSound() + { + return 0x1CE; + } + + public override int GetAngerSound() + { + return 0x1AC; + } + + public override int GetDeathSound() + { + return 0x182; + } + + public override int GetHurtSound() + { + return 0x28D; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + if ( Backpack != null ) + Backpack.Destroy(); + + if ( Utility.Random( 3 ) == 0 ) + { + BaseBook notebook = Loot.RandomLysanderNotebook(); + notebook.MoveToWorld( Location, Map ); + } + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public LysanderGathenwale( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Mobiles/MorgBergen.cs b/Scripts/Engines/Khaldun/Mobiles/MorgBergen.cs new file mode 100644 index 0000000..2f53d9d --- /dev/null +++ b/Scripts/Engines/Khaldun/Mobiles/MorgBergen.cs @@ -0,0 +1,111 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class MorgBergen : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + [Constructable] + public MorgBergen() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Title = "the Cursed"; + + Hue = 0x8596; + Body = 0x190; + Name = "Morg Bergen"; + + AddItem( new ShortPants( 0x59C ) ); + + Bardiche bardiche = new Bardiche(); + LeatherGloves gloves = new LeatherGloves(); + LeatherArms arms = new LeatherArms(); + + bardiche.Hue = 0x96F; bardiche.Movable = false; + gloves.Hue = 0x96F; + arms.Hue = 0x96F; + + AddItem( bardiche ); + AddItem( gloves ); + AddItem( arms ); + + SetStr( 111, 120 ); + SetDex( 111, 120 ); + SetInt( 51, 60 ); + + SetHits( 180, 207 ); + SetMana( 0 ); + + SetDamage( 9, 17 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Swords, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 80.1, 90.0 ); + SetSkill( SkillName.Anatomy, 90.1, 100.0 ); + + Fame = 5000; + Karma = -1000; + } + + public override int GetIdleSound() + { + return 0x1CE; + } + + public override int GetAngerSound() + { + return 0x263; + } + + public override int GetDeathSound() + { + return 0x1D1; + } + + public override int GetHurtSound() + { + return 0x25E; + } + + public override bool OnBeforeDeath() + { + Gold gold = new Gold( Utility.RandomMinMax( 190, 230 ) ); + gold.MoveToWorld( Location, Map ); + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public MorgBergen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/Mobiles/TavaraSewel.cs b/Scripts/Engines/Khaldun/Mobiles/TavaraSewel.cs new file mode 100644 index 0000000..5f99df6 --- /dev/null +++ b/Scripts/Engines/Khaldun/Mobiles/TavaraSewel.cs @@ -0,0 +1,120 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class TavaraSewel : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + [Constructable] + public TavaraSewel () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Title = "the Cursed"; + + Hue = 0x8838; + Female = true; + Body = 0x191; + Name = "Tavara Sewel"; + + AddItem( new Kilt( 0x59C ) ); + AddItem( new Sandals( 0x599 ) ); + + Kryss kryss = new Kryss(); + Buckler buckler = new Buckler(); + RingmailGloves gloves = new RingmailGloves(); + FemalePlateChest chest = new FemalePlateChest(); + + kryss.Hue = 0x96F; kryss.Movable = false; + buckler.Hue = 0x96F; buckler.Movable = false; + gloves.Hue = 0x599; + chest.Hue = 0x96F; + + AddItem( kryss ); + AddItem( buckler ); + AddItem( gloves ); + AddItem( chest ); + + SetStr( 111, 120 ); + SetDex( 111, 120 ); + SetInt( 111, 120 ); + + SetHits( 180, 207 ); + SetStam( 126, 150 ); + SetMana( 0 ); + + SetDamage( 13, 16 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Fencing, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 80.1, 90.0 ); + SetSkill( SkillName.Anatomy, 90.1, 100.0 ); + + Fame = 5000; + Karma = -1000; + } + + public override int GetIdleSound() + { + return 0x27F; + } + + public override int GetAngerSound() + { + return 0x258; + } + + public override int GetDeathSound() + { + return 0x25B; + } + + public override int GetHurtSound() + { + return 0x257; + } + + public override bool OnBeforeDeath() + { + Gold gold = new Gold( Utility.RandomMinMax( 190, 230 ) ); + gold.MoveToWorld( Location, Map ); + + if ( Utility.Random( 3 ) == 0 ) + { + BaseBook journal = Loot.RandomTavarasJournal(); + journal.MoveToWorld( Location, Map ); + } + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public TavaraSewel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/PuzzleChest.cs b/Scripts/Engines/Khaldun/PuzzleChest.cs new file mode 100644 index 0000000..22468a1 --- /dev/null +++ b/Scripts/Engines/Khaldun/PuzzleChest.cs @@ -0,0 +1,793 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public enum PuzzleChestCylinder + { + None = 0xE73, + LightBlue = 0x186F, + Blue = 0x186A, + Green = 0x186B, + Orange = 0x186C, + Purple = 0x186D, + Red = 0x186E, + DarkBlue = 0x1869, + Yellow = 0x1870 + } + + public class PuzzleChestSolution + { + public const int Length = 5; + + private PuzzleChestCylinder[] m_Cylinders = new PuzzleChestCylinder[Length]; + + public PuzzleChestCylinder[] Cylinders{ get{ return m_Cylinders; } } + + public PuzzleChestCylinder First{ get{ return m_Cylinders[0]; } set{ m_Cylinders[0] = value; } } + public PuzzleChestCylinder Second{ get{ return m_Cylinders[1]; } set{ m_Cylinders[1] = value; } } + public PuzzleChestCylinder Third{ get{ return m_Cylinders[2]; } set{ m_Cylinders[2] = value; } } + public PuzzleChestCylinder Fourth{ get{ return m_Cylinders[3]; } set{ m_Cylinders[3] = value; } } + public PuzzleChestCylinder Fifth{ get{ return m_Cylinders[4]; } set{ m_Cylinders[4] = value; } } + + public static PuzzleChestCylinder RandomCylinder() + { + switch ( Utility.Random( 8 ) ) + { + case 0: return PuzzleChestCylinder.LightBlue; + case 1: return PuzzleChestCylinder.Blue; + case 2: return PuzzleChestCylinder.Green; + case 3: return PuzzleChestCylinder.Orange; + case 4: return PuzzleChestCylinder.Purple; + case 5: return PuzzleChestCylinder.Red; + case 6: return PuzzleChestCylinder.DarkBlue; + default: return PuzzleChestCylinder.Yellow; + } + } + + public PuzzleChestSolution() + { + for ( int i = 0; i < m_Cylinders.Length; i++ ) { + m_Cylinders[i] = RandomCylinder(); + } + } + + public PuzzleChestSolution( PuzzleChestCylinder first, PuzzleChestCylinder second, PuzzleChestCylinder third, PuzzleChestCylinder fourth, PuzzleChestCylinder fifth ) + { + First = first; + Second = second; + Third = third; + Fourth = fourth; + Fifth = fifth; + } + + public PuzzleChestSolution( PuzzleChestSolution solution ) + { + for ( int i = 0; i < m_Cylinders.Length; i++ ) { + m_Cylinders[i] = solution.m_Cylinders[i]; + } + } + + public bool Matches( PuzzleChestSolution solution, out int cylinders, out int colors ) + { + cylinders = 0; + colors = 0; + + bool[] matchesSrc = new bool[solution.m_Cylinders.Length]; + bool[] matchesDst = new bool[solution.m_Cylinders.Length]; + + for ( int i = 0; i < m_Cylinders.Length; i++ ) + { + if ( m_Cylinders[i] == solution.m_Cylinders[i] ) + { + cylinders++; + + matchesSrc[i] = true; + matchesDst[i] = true; + } + } + + for ( int i = 0; i < m_Cylinders.Length; i++ ) + { + if ( !matchesSrc[i] ) + { + for ( int j = 0; j < solution.m_Cylinders.Length; j++ ) + { + if ( m_Cylinders[i] == solution.m_Cylinders[j] && !matchesDst[j] ) + { + colors++; + + matchesDst[j] = true; + } + } + } + } + + return cylinders == m_Cylinders.Length; + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Cylinders.Length ); + for ( int i = 0; i < m_Cylinders.Length; i++ ) + { + writer.Write( (int) m_Cylinders[i] ); + } + } + + public PuzzleChestSolution( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + int length = reader.ReadEncodedInt(); + for ( int i = 0; ; i++ ) + { + if ( i < length ) + { + PuzzleChestCylinder cylinder = (PuzzleChestCylinder) reader.ReadInt(); + + if ( i < m_Cylinders.Length ) + m_Cylinders[i] = cylinder; + } + else if ( i < m_Cylinders.Length ) + { + m_Cylinders[i] = RandomCylinder(); + } + else + { + break; + } + } + } + } + + public class PuzzleChestSolutionAndTime : PuzzleChestSolution + { + private DateTime m_When; + + public DateTime When{ get{ return m_When; } } + + public PuzzleChestSolutionAndTime( DateTime when, PuzzleChestSolution solution ) : base( solution ) + { + m_When = when; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteDeltaTime( m_When ); + } + + public PuzzleChestSolutionAndTime( GenericReader reader ) : base( reader ) + { + int version = reader.ReadEncodedInt(); + + m_When = reader.ReadDeltaTime(); + } + } + + public abstract class PuzzleChest : BaseTreasureChest + { + public const int HintsCount = 3; + public readonly TimeSpan CleanupTime = TimeSpan.FromHours( 1.0 ); + + private PuzzleChestSolution m_Solution; + private PuzzleChestCylinder[] m_Hints = new PuzzleChestCylinder[HintsCount]; + private Dictionary m_Guesses = new Dictionary(); + + public PuzzleChestSolution Solution + { + get{ return m_Solution; } + set + { + m_Solution = value; + InitHints(); + } + } + + public PuzzleChestCylinder[] Hints{ get{ return m_Hints; } } + + public PuzzleChestCylinder FirstHint{ get{ return m_Hints[0]; } set{ m_Hints[0] = value; } } + public PuzzleChestCylinder SecondHint{ get{ return m_Hints[1]; } set{ m_Hints[1] = value; } } + public PuzzleChestCylinder ThirdHint{ get{ return m_Hints[2]; } set{ m_Hints[2] = value; } } + + public override string DefaultName + { + get { return null; } + } + + public PuzzleChest( int itemID ) : base( itemID ) + { + } + + private void InitHints() + { + List list = new List( Solution.Cylinders.Length - 1 ); + for ( int i = 1; i < Solution.Cylinders.Length; i++ ) + list.Add( Solution.Cylinders[i] ); + + m_Hints = new PuzzleChestCylinder[HintsCount]; + + for ( int i = 0; i < m_Hints.Length; i++ ) { + int pos = Utility.Random( list.Count ); + m_Hints[i] = list[pos]; + list.RemoveAt( pos ); + } + } + + protected override void SetLockLevel() + { + LockLevel = 0; // Can't be unlocked + } + + public override bool CheckLocked( Mobile from ) + { + if ( Locked ) + { + PuzzleChestSolution solution = GetLastGuess( from ); + if ( solution != null ) + solution = new PuzzleChestSolution( solution ); + else + solution = new PuzzleChestSolution( PuzzleChestCylinder.None, PuzzleChestCylinder.None, PuzzleChestCylinder.None, PuzzleChestCylinder.None, PuzzleChestCylinder.None ); + + from.CloseGump( typeof( PuzzleGump ) ); + from.CloseGump( typeof( StatusGump ) ); + from.SendGump( new PuzzleGump( from, this, solution, 0 ) ); + + return true; + } + else + { + return false; + } + } + + public PuzzleChestSolutionAndTime GetLastGuess( Mobile m ) + { + PuzzleChestSolutionAndTime pcst = null; + m_Guesses.TryGetValue( m, out pcst ); + return pcst; + } + + public void SubmitSolution( Mobile m, PuzzleChestSolution solution ) + { + int correctCylinders, correctColors; + + if ( solution.Matches( this.Solution, out correctCylinders, out correctColors ) ) + { + LockPick( m ); + + DisplayTo( m ); + } + else + { + m_Guesses[m] = new PuzzleChestSolutionAndTime( DateTime.Now, solution ); + + m.SendGump( new StatusGump( correctCylinders, correctColors ) ); + + DoDamage( m ); + } + } + + public void DoDamage( Mobile to ) + { + switch ( Utility.Random( 4 ) ) + { + case 0: + { + Effects.SendLocationEffect( to, to.Map, 0x113A, 20, 10 ); + to.PlaySound( 0x231 ); + to.LocalOverheadMessage( MessageType.Regular, 0x44, 1010523 ); // A toxic vapor envelops thee. + + to.ApplyPoison( to, Poison.Regular ); + + break; + } + case 1: + { + Effects.SendLocationEffect( to, to.Map, 0x3709, 30 ); + to.PlaySound( 0x54 ); + to.LocalOverheadMessage( MessageType.Regular, 0xEE, 1010524 ); // Searing heat scorches thy skin. + + AOS.Damage( to, to, Utility.RandomMinMax( 10, 40 ), 0, 100, 0, 0, 0 ); + + break; + } + case 2: + { + to.PlaySound( 0x223 ); + to.LocalOverheadMessage( MessageType.Regular, 0x62, 1010525 ); // Pain lances through thee from a sharp metal blade. + + AOS.Damage( to, to, Utility.RandomMinMax( 10, 40 ), 100, 0, 0, 0, 0 ); + + break; + } + default: + { + to.BoltEffect( 0 ); + to.LocalOverheadMessage( MessageType.Regular, 0xDA, 1010526 ); // Lightning arcs through thy body. + + AOS.Damage( to, to, Utility.RandomMinMax( 10, 40 ), 0, 0, 0, 0, 100 ); + + break; + } + } + } + + private class PuzzleGump : Gump + { + private Mobile m_From; + private PuzzleChest m_Chest; + private PuzzleChestSolution m_Solution; + + public PuzzleGump( Mobile from, PuzzleChest chest, PuzzleChestSolution solution, int check ) : base( 50, 50 ) + { + m_From = from; + m_Chest = chest; + m_Solution = solution; + + Dragable = false; + + AddBackground( 25, 0, 500, 410, 0x53 ); + + AddImage( 62, 20, 0x67 ); + + AddHtmlLocalized( 80, 36, 110, 70, 1018309, true, false ); // A Puzzle Lock + + /* Correctly choose the sequence of cylinders needed to open the latch. Each cylinder + * may potentially be used more than once. Beware! A false attempt could be deadly! + */ + AddHtmlLocalized( 214, 26, 270, 90, 1018310, true, true ); + + AddLeftCylinderButton( 62, 130, PuzzleChestCylinder.LightBlue, 10 ); + AddLeftCylinderButton( 62, 180, PuzzleChestCylinder.Blue, 11 ); + AddLeftCylinderButton( 62, 230, PuzzleChestCylinder.Green, 12 ); + AddLeftCylinderButton( 62, 280, PuzzleChestCylinder.Orange, 13 ); + + AddRightCylinderButton( 451, 130, PuzzleChestCylinder.Purple, 14 ); + AddRightCylinderButton( 451, 180, PuzzleChestCylinder.Red, 15 ); + AddRightCylinderButton( 451, 230, PuzzleChestCylinder.DarkBlue, 16 ); + AddRightCylinderButton( 451, 280, PuzzleChestCylinder.Yellow, 17 ); + + double lockpicking = from.Skills.Lockpicking.Base; + if ( lockpicking >= 60.0 ) + { + AddHtmlLocalized( 160, 125, 230, 24, 1018308, false, false ); // Lockpicking hint: + + AddBackground( 159, 150, 230, 95, 0x13EC ); + + if ( lockpicking >= 80.0 ) + { + AddHtmlLocalized( 165, 157, 200, 40, 1018312, false, false ); // In the first slot: + AddCylinder( 350, 165, chest.Solution.First ); + + AddHtmlLocalized( 165, 197, 200, 40, 1018313, false, false ); // Used in unknown slot: + AddCylinder( 350, 200, chest.FirstHint ); + + if ( lockpicking >= 90.0 ) + AddCylinder( 350, 212, chest.SecondHint ); + + if ( lockpicking >= 100.0 ) + AddCylinder( 350, 224, chest.ThirdHint ); + } + else + { + AddHtmlLocalized( 165, 157, 200, 40, 1018313, false, false ); // Used in unknown slot: + AddCylinder( 350, 160, chest.FirstHint ); + + if ( lockpicking >= 70.0 ) + AddCylinder( 350, 172, chest.SecondHint ); + } + } + + PuzzleChestSolution lastGuess = chest.GetLastGuess( from ); + if ( lastGuess != null ) + { + AddHtmlLocalized( 127, 249, 170, 20, 1018311, false, false ); // Thy previous guess: + + AddBackground( 290, 247, 115, 25, 0x13EC ); + + AddCylinder( 281, 254, lastGuess.First ); + AddCylinder( 303, 254, lastGuess.Second ); + AddCylinder( 325, 254, lastGuess.Third ); + AddCylinder( 347, 254, lastGuess.Fourth ); + AddCylinder( 369, 254, lastGuess.Fifth ); + } + + AddPedestal( 140, 270, solution.First, 0, check == 0 ); + AddPedestal( 195, 270, solution.Second, 1, check == 1 ); + AddPedestal( 250, 270, solution.Third, 2, check == 2 ); + AddPedestal( 305, 270, solution.Fourth, 3, check == 3 ); + AddPedestal( 360, 270, solution.Fifth, 4, check == 4 ); + + AddButton( 258, 370, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + } + + private void AddLeftCylinderButton( int x, int y, PuzzleChestCylinder cylinder, int buttonID ) + { + AddBackground( x, y, 30, 30, 0x13EC ); + AddCylinder( x - 7, y + 10, cylinder ); + AddButton( x + 38, y + 9, 0x13A8, 0x4B9, buttonID, GumpButtonType.Reply, 0 ); + } + + private void AddRightCylinderButton( int x, int y, PuzzleChestCylinder cylinder, int buttonID ) + { + AddBackground( x, y, 30, 30, 0x13EC ); + AddCylinder( x - 7, y + 10, cylinder ); + AddButton( x - 26, y + 9, 0x13A8, 0x4B9, buttonID, GumpButtonType.Reply, 0 ); + } + + private void AddPedestal( int x, int y, PuzzleChestCylinder cylinder, int switchID, bool initialState ) + { + AddItem( x, y, 0xB10 ); + AddItem( x - 23, y + 12, 0xB12 ); + AddItem( x + 23, y + 12, 0xB13 ); + AddItem( x, y + 23, 0xB11 ); + + if ( cylinder != PuzzleChestCylinder.None ) + { + AddItem( x, y + 2, 0x51A ); + AddCylinder( x - 1, y + 19, cylinder ); + } + else + { + AddItem( x, y + 2, 0x521 ); + } + + AddRadio( x + 7, y + 65, 0x867, 0x86A, initialState, switchID ); + } + + private void AddCylinder( int x, int y, PuzzleChestCylinder cylinder ) + { + if ( cylinder != PuzzleChestCylinder.None ) + AddItem( x, y, (int)cylinder ); + else + AddItem( x + 9, y, (int)cylinder ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Chest.Deleted || info.ButtonID == 0 || !m_From.CheckAlive() ) + return; + + if ( m_From.AccessLevel == AccessLevel.Player && ( m_From.Map != m_Chest.Map || !m_From.InRange( m_Chest.GetWorldLocation(), 2 ) ) ) + { + m_From.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500446 ); // That is too far away. + return; + } + + if ( info.ButtonID == 1 ) + { + m_Chest.SubmitSolution( m_From, m_Solution ); + } + else + { + if ( info.Switches.Length == 0 ) + return; + + int pedestal = info.Switches[0]; + if ( pedestal < 0 || pedestal >= m_Solution.Cylinders.Length ) + return; + + PuzzleChestCylinder cylinder; + switch ( info.ButtonID ) + { + case 10: cylinder = PuzzleChestCylinder.LightBlue; break; + case 11: cylinder = PuzzleChestCylinder.Blue; break; + case 12: cylinder = PuzzleChestCylinder.Green; break; + case 13: cylinder = PuzzleChestCylinder.Orange; break; + case 14: cylinder = PuzzleChestCylinder.Purple; break; + case 15: cylinder = PuzzleChestCylinder.Red; break; + case 16: cylinder = PuzzleChestCylinder.DarkBlue; break; + case 17: cylinder = PuzzleChestCylinder.Yellow; break; + default: return; + } + + m_Solution.Cylinders[pedestal] = cylinder; + + m_From.SendGump( new PuzzleGump( m_From, m_Chest, m_Solution, pedestal ) ); + } + } + } + + private class StatusGump : Gump + { + public StatusGump( int correctCylinders, int correctColors ) : base( 50, 50 ) + { + AddBackground( 15, 250, 305, 163, 0x53 ); + AddBackground( 28, 265, 280, 133, 0xBB8 ); + + AddHtmlLocalized( 35, 271, 270, 24, 1018314, false, false ); // Thou hast failed to solve the puzzle! + + AddHtmlLocalized( 35, 297, 250, 24, 1018315, false, false ); // Correctly placed colors: + AddLabel( 285, 297, 0x44, correctCylinders.ToString() ); + + AddHtmlLocalized( 35, 323, 250, 24, 1018316, false, false ); // Used colors in wrong slots: + AddLabel( 285, 323, 0x44, correctColors.ToString() ); + + AddButton( 152, 369, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + } + } + + public override void LockPick( Mobile from ) + { + base.LockPick( from ); + + m_Guesses.Clear(); + } + + private static void GetRandomAOSStats( out int attributeCount, out int min, out int max ) + { + int rnd = Utility.Random( 15 ); + + if ( rnd < 1 ) + { + attributeCount = Utility.RandomMinMax( 2, 6 ); + min = 20; max = 70; + } + else if ( rnd < 3 ) + { + attributeCount = Utility.RandomMinMax( 2, 4 ); + min = 20; max = 50; + } + else if ( rnd < 6 ) + { + attributeCount = Utility.RandomMinMax( 2, 3 ); + min = 20; max = 40; + } + else if ( rnd < 10 ) + { + attributeCount = Utility.RandomMinMax( 1, 2 ); + min = 10; max = 30; + } + else + { + attributeCount = 1; + min = 10; max = 20; + } + } + + protected override void GenerateTreasure() + { + DropItem( new Gold( 600, 900 ) ); + + List gems = new List(); + for ( int i = 0; i < 9; i++ ) + { + Item gem = Loot.RandomGem(); + Type gemType = gem.GetType(); + + foreach ( Item listGem in gems ) { + if ( listGem.GetType() == gemType ) { + listGem.Amount++; + gem.Delete(); + break; + } + } + + if ( !gem.Deleted ) + gems.Add( gem ); + } + + foreach ( Item gem in gems ) + DropItem( gem ); + + if ( 0.2 > Utility.RandomDouble() ) + DropItem( new BagOfReagents( 50 ) ); + + for ( int i = 0; i < 2; i++ ) + { + Item item; + + if ( Core.AOS ) + item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(); + else + item = Loot.RandomArmorOrShieldOrWeapon(); + + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( weapon, attributeCount, min, max ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random( 6 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random( 6 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random( 6 ); + } + + DropItem( item ); + } + else if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if ( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( armor, attributeCount, min, max ); + } + else + { + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random( 6 ); + armor.Durability = (ArmorDurabilityLevel)Utility.Random( 6 ); + } + + DropItem( item ); + } + else if( item is BaseHat ) + { + BaseHat hat = (BaseHat)item; + + if( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( hat, attributeCount, min, max ); + } + + DropItem( item ); + } + else if( item is BaseJewel ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, attributeCount, min, max ); + + DropItem( item ); + } + } + + Solution = new PuzzleChestSolution(); + } + + public void CleanupGuesses() + { + List toDelete = new List(); + + foreach ( KeyValuePair kvp in m_Guesses ) { + if ( DateTime.Now - kvp.Value.When > CleanupTime ) + toDelete.Add( kvp.Key ); + } + + foreach ( Mobile m in toDelete ) + m_Guesses.Remove( m ); + } + + public PuzzleChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + CleanupGuesses(); + + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + m_Solution.Serialize( writer ); + + writer.WriteEncodedInt( (int) m_Hints.Length ); + for ( int i = 0; i < m_Hints.Length; i++ ) + { + writer.Write( (int) m_Hints[i] ); + } + + writer.WriteEncodedInt( (int) m_Guesses.Count ); + foreach ( KeyValuePair kvp in m_Guesses ) { + writer.Write( kvp.Key ); + kvp.Value.Serialize( writer ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Solution = new PuzzleChestSolution( reader ); + + int length = reader.ReadEncodedInt(); + for ( int i = 0; i < length; i++ ) + { + PuzzleChestCylinder cylinder = (PuzzleChestCylinder) reader.ReadInt(); + + if ( length == m_Hints.Length ) + m_Hints[i] = cylinder; + } + if ( length != m_Hints.Length ) + InitHints(); + + int guesses = reader.ReadEncodedInt(); + for ( int i = 0; i < guesses; i++ ) + { + Mobile m = reader.ReadMobile(); + PuzzleChestSolutionAndTime sol = new PuzzleChestSolutionAndTime( reader ); + + m_Guesses[m] = sol; + } + } + } + + [FlipableAttribute( 0xE41, 0xE40 )] + public class MetalGoldenPuzzleChest : PuzzleChest + { + [Constructable] + public MetalGoldenPuzzleChest() : base( 0xE41 ) + { + } + + public MetalGoldenPuzzleChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [FlipableAttribute( 0xE80, 0x9A8 )] + public class StrongBoxPuzzle : PuzzleChest + { + [Constructable] + public StrongBoxPuzzle() : base( 0xE80 ) + { + } + + public StrongBoxPuzzle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Engines/Khaldun/RaisableItem.cs b/Scripts/Engines/Khaldun/RaisableItem.cs new file mode 100644 index 0000000..1a0fd24 --- /dev/null +++ b/Scripts/Engines/Khaldun/RaisableItem.cs @@ -0,0 +1,177 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RaisableItem : Item + { + private int m_MaxElevation; + private int m_MoveSound; + private int m_StopSound; + private TimeSpan m_CloseDelay; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxElevation + { + get{ return m_MaxElevation; } + set + { + if ( value <= 0 ) + m_MaxElevation = 0; + else if ( value >= 60 ) + m_MaxElevation = 60; + else + m_MaxElevation = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MoveSound{ get{ return m_MoveSound; } set{ m_MoveSound = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int StopSound{ get{ return m_StopSound; } set{ m_StopSound = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan CloseDelay{ get{ return m_CloseDelay; } set{ m_CloseDelay = value; } } + + [Constructable] + public RaisableItem( int itemID ) : this( itemID, 20, -1, -1, TimeSpan.FromMinutes( 1.0 ) ) + { + } + + [Constructable] + public RaisableItem( int itemID, int maxElevation, TimeSpan closeDelay ) : this( itemID, maxElevation, -1, -1, closeDelay ) + { + } + + [Constructable] + public RaisableItem( int itemID, int maxElevation, int moveSound, int stopSound, TimeSpan closeDelay ) : base( itemID ) + { + Movable = false; + + m_MaxElevation = maxElevation; + m_MoveSound = moveSound; + m_StopSound = stopSound; + m_CloseDelay = closeDelay; + } + + private int m_Elevation; + private RaiseTimer m_RaiseTimer; + + public bool IsRaisable + { + get{ return m_RaiseTimer == null; } + } + + public void Raise() + { + if ( !IsRaisable ) + return; + + m_RaiseTimer = new RaiseTimer( this ); + m_RaiseTimer.Start(); + } + + private class RaiseTimer : Timer + { + private RaisableItem m_Item; + private DateTime m_CloseTime; + private bool m_Up; + private int m_Step; + + public RaiseTimer( RaisableItem item ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 0.5 ) ) + { + m_Item = item; + m_CloseTime = DateTime.Now + item.CloseDelay; + m_Up = true; + + Priority = TimerPriority.TenMS; + } + + protected override void OnTick() + { + if ( m_Item.Deleted ) + { + Stop(); + return; + } + + if ( m_Step++ % 3 == 0 ) + { + if ( m_Up ) + { + m_Item.Z++; + + if ( ++m_Item.m_Elevation >= m_Item.MaxElevation ) + { + Stop(); + + if ( m_Item.StopSound >= 0 ) + Effects.PlaySound( m_Item.Location, m_Item.Map, m_Item.StopSound ); + + m_Up = false; + m_Step = 0; + + TimeSpan delay = m_CloseTime - DateTime.Now; + Timer.DelayCall( delay > TimeSpan.Zero ? delay : TimeSpan.Zero, new TimerCallback( Start ) ); + + return; + } + } + else + { + m_Item.Z--; + + if ( --m_Item.m_Elevation <= 0 ) + { + Stop(); + + if ( m_Item.StopSound >= 0 ) + Effects.PlaySound( m_Item.Location, m_Item.Map, m_Item.StopSound ); + + m_Item.m_RaiseTimer = null; + + return; + } + } + } + + if ( m_Item.MoveSound >= 0 ) + Effects.PlaySound( m_Item.Location, m_Item.Map, m_Item.MoveSound ); + } + } + + public RaisableItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_MaxElevation ); + writer.WriteEncodedInt( (int) m_MoveSound ); + writer.WriteEncodedInt( (int) m_StopSound ); + writer.Write( (TimeSpan) m_CloseDelay ); + + writer.WriteEncodedInt( (int) m_Elevation ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_MaxElevation = reader.ReadEncodedInt(); + m_MoveSound = reader.ReadEncodedInt(); + m_StopSound = reader.ReadEncodedInt(); + m_CloseDelay = reader.ReadTimeSpan(); + + int elevation = reader.ReadEncodedInt(); + this.Z -= elevation; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Khaldun/RaiseSwitch.cs b/Scripts/Engines/Khaldun/RaiseSwitch.cs new file mode 100644 index 0000000..9f26e6f --- /dev/null +++ b/Scripts/Engines/Khaldun/RaiseSwitch.cs @@ -0,0 +1,223 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class RaiseSwitch : Item + { + private RaisableItem m_RaisableItem; + + [CommandProperty( AccessLevel.GameMaster )] + public RaisableItem RaisableItem + { + get{ return m_RaisableItem; } + set{ m_RaisableItem = value; } + } + + [Constructable] + public RaiseSwitch() : this( 0x1093 ) + { + } + + protected RaiseSwitch( int itemID ) : base( itemID ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile m ) + { + if ( !m.InRange( this, 2 ) ) + { + m.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + if ( RaisableItem != null && RaisableItem.Deleted ) + RaisableItem = null; + + Flip(); + + if ( RaisableItem != null ) + { + if ( RaisableItem.IsRaisable ) + { + RaisableItem.Raise(); + m.LocalOverheadMessage( MessageType.Regular, 0x5A, true, "You hear a grinding noise echoing in the distance." ); + } + else + { + m.LocalOverheadMessage( MessageType.Regular, 0x5A, true, "You flip the switch again, but nothing happens." ); + } + } + } + + protected virtual void Flip() + { + if ( ItemID != 0x1093 ) + { + ItemID = 0x1093; + + StopResetTimer(); + } + else + { + ItemID = 0x1095; + + if ( RaisableItem != null && RaisableItem.CloseDelay >= TimeSpan.Zero ) + StartResetTimer( RaisableItem.CloseDelay ); + else + StartResetTimer( TimeSpan.FromMinutes( 2.0 ) ); + } + + Effects.PlaySound( Location, Map, 0x3E8 ); + } + + private ResetTimer m_ResetTimer; + + protected void StartResetTimer( TimeSpan delay ) + { + StopResetTimer(); + + m_ResetTimer = new ResetTimer( this, delay ); + m_ResetTimer.Start(); + } + + protected void StopResetTimer() + { + if ( m_ResetTimer != null ) + { + m_ResetTimer.Stop(); + m_ResetTimer = null; + } + } + + protected virtual void Reset() + { + if ( ItemID != 0x1093 ) + Flip(); + } + + private class ResetTimer : Timer + { + private RaiseSwitch m_RaiseSwitch; + + public ResetTimer( RaiseSwitch raiseSwitch, TimeSpan delay ) : base( delay ) + { + m_RaiseSwitch = raiseSwitch; + + Priority = ComputePriority( delay ); + } + + protected override void OnTick() + { + if ( m_RaiseSwitch.Deleted ) + return; + + m_RaiseSwitch.m_ResetTimer = null; + + m_RaiseSwitch.Reset(); + } + } + + public RaiseSwitch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Item) m_RaisableItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_RaisableItem = (RaisableItem) reader.ReadItem(); + + Reset(); + } + } + + public class DisappearingRaiseSwitch : RaiseSwitch + { + public int CurrentRange{ get{ return Visible ? 3 : 2; } } + + [Constructable] + public DisappearingRaiseSwitch() : base( 0x108F ) + { + } + + protected override void Flip() + { + } + + protected override void Reset() + { + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Utility.InRange( m.Location, Location, CurrentRange ) || Utility.InRange( oldLocation, Location, CurrentRange ) ) + Refresh(); + } + + public override void OnMapChange() + { + if ( !Deleted ) + Refresh(); + } + + public override void OnLocationChange( Point3D oldLoc ) + { + if ( !Deleted ) + Refresh(); + } + + public void Refresh() + { + bool found = false; + foreach ( Mobile mob in GetMobilesInRange( CurrentRange ) ) + { + if ( mob.Hidden && mob.AccessLevel > AccessLevel.Player ) + continue; + + found = true; + break; + } + + Visible = found; + } + + public DisappearingRaiseSwitch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + if ( RaisableItem != null && RaisableItem.Deleted ) + RaisableItem = null; + + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Refresh ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/MLQuests/Definitions/AGhostOfCovetous.cs b/Scripts/Engines/MLQuests/Definitions/AGhostOfCovetous.cs new file mode 100644 index 0000000..0ddefff --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/AGhostOfCovetous.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class AGhostOfCovetous : MLQuest + { + public override Type NextQuest { get { return typeof( SaveHisDad ); } } + + public AGhostOfCovetous() + { + Activated = true; + Title = 1075287; // A Ghost of Covetous + Description = 1075286; // What? Oh, you startled me! Sorry, I'm a little jumpy. My master Griswolt learned that a ghost has recently taken up residence in the Covetous dungeon. He sent me to capture it, but I . . . well, it terrified me, to be perfectly honest. If you think yourself courageous enough, I'll give you my Spirit Bottle, and you can try to capture it yourself. I'm certain my master would reward you richly for such service. + RefusalMessage = 1075288; // That's okay, I'm sure someone with more courage than either of us will come along eventually. + InProgressMessage = 1075290; // You'll find that ghost in the mountain pass above the Covetous dungeon. + CompletionMessage = 1075291; // (As you try to use the Spirit Bottle, the ghost snatches it out of your hand and smashes it on the rocks) Please, don't be frightened. I need your help! + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( SpiritBottle ), 1, "Spirit Bottle", typeof( Frederic ) ) ); + + Rewards.Add( new DummyReward( 1075284 ) ); // Return the filled Spirit Bottle to Griswolt the Master Necromancer to receive a reward. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Ben" ), new Point3D( 2467, 402, 15 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Ben" ), new Point3D( 2467, 402, 15 ), Map.Felucca ); + } + } + + public class SaveHisDad : MLQuest + { + public override Type NextQuest { get { return typeof( AFathersGratitude ); } } + public override bool IsChainTriggered { get { return true; } } + + public SaveHisDad() + { + Activated = true; + Title = 1075337; // Save His Dad + Description = 1075338; // My father, Andros, is a smith in Minoc. Last week his forge overturned and he was splashed by molten steel. He was horribly burned, and we feared he would die. An alchemist in Vesper promised to make a bandage that could heal him, but he needed the silk of a dread spider. I came here to get some, but I was careless, and succumbed to their poison. Please, won�t you help my father? + RefusalMessage = 1075340; // Oh . . . that�s your decision . . . OooOoooOOoo . . . + InProgressMessage = 1075341; // Thank you! Deliver it to Leon the Alchemist in Vesper. The silk crumbles easily, and much time has already passed since I died. Please! Hurry! + CompletionMessage = 1075342; // How may I help thee? You have the silk of a dread spider? Of course I can make you a bandage, but what happened to Frederic? + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new TimedDeliverObjective( TimeSpan.FromSeconds( 600 ), typeof( DreadSpiderSilk ), 1, "Dread Spider Silk", typeof( Leon ) ) ); + + Rewards.Add( new DummyReward( 1075339 ) ); // Hurry! You must get the silk to Leon the Alchemist quickly, or it will crumble and become useless! + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Frederic" ), new Point3D( 2415, 887, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Frederic" ), new Point3D( 2415, 887, 0 ), Map.Felucca ); + } + } + + public class AFathersGratitude : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public AFathersGratitude() + { + Activated = true; + OneTimeOnly = true; + Title = 1075343; // A Father�s Gratitude + Description = 1075344; // That is simply terrible. First Andros, and now his son. Well, let�s make sure Frederic�s sacrifice wasn�t in vain. Will you take the bandages to his father? You can probably deliver them faster than I can, can�t you? + RefusalMessage = 1075346; // Well I�m sorry to hear you say that. Without your help, I don�t know if I can get these to Andros quickly enough to help him. + InProgressMessage = 1075347; // I don�t know how much longer Andros will survive. You�d better get this to him as quick as you can. Every second counts! + CompletionMessage = 1075348; // Sorry, I�m not accepting commissions at the moment. What? You have the bandage I need from Leon? Thank you so much! But why didn�t my son bring this to me himself? . . . Oh, no! You can't be serious! *sag* My Freddie, my son! Thank you for carrying out his last wish. Here -- I made this for my son, to give to him when he became a journeyman. I want you to have it. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( AlchemistsBandage ), 1, "Alchemist's Bandage", typeof( Andros ) ) ); + + Rewards.Add( new ItemReward( 1075345, typeof( AndrosGratitude ) ) ); // Andros� Gratitude + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Leon" ), new Point3D( 2918, 851, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Leon" ), new Point3D( 2918, 851, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Andros" ), new Point3D( 2531, 581, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Andros" ), new Point3D( 2531, 581, 0 ), Map.Felucca ); + } + } + + #endregion + + #region Mobiles + + public class Ben : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Ben() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Ben"; + Title = "the Apprentice Necromancer"; + BodyValue = 0x190; + Hue = 0x83FD; + HairItemID = 0x2048; + HairHue = 0x463; + FacialHairItemID = 0x204C; + FacialHairHue = 0x463; + + InitStats( 100, 100, 25 ); + + AddItem( new Backpack() ); + AddItem( new Shoes( 0x901 ) ); + AddItem( new LongPants( 0x1BB ) ); + AddItem( new FancyShirt( 0x756 ) ); + + } + + public Ben( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "The Ghost of Frederic Smithson" )] + public class Frederic : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Frederic() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "The Ghost of Frederic Smithson"; + BodyValue = 0x1A; + Hue = 0x455; + Frozen = true; + + InitStats( 100, 100, 25 ); + + } + + public Frederic( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Leon : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Leon() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Leon"; + Title = "the Alchemist"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Shoes( 0x901 ) ); + AddItem( new Robe( 0x657 ) ); + + } + + public Leon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Andros : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Andros() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Andros"; + Title = "the Blacksmith"; + BodyValue = 0x190; + Hue = 0x8409; + FacialHairItemID = 0x2041; + FacialHairHue = 0x45E; + HairItemID = 0x2049; + HairHue = 0x45E; + + InitStats( 100, 100, 25 ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x901 ) ); + AddItem( new FancyShirt( 0x60B ) ); + AddItem( new LongPants( 0x1BB ) ); + AddItem( new FullApron( 0x901 ) ); + AddItem( new SmithHammer() ); + + } + + public Andros( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/BaseEscort.cs b/Scripts/Engines/MLQuests/Definitions/BaseEscort.cs new file mode 100644 index 0000000..db0bc3e --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/BaseEscort.cs @@ -0,0 +1,24 @@ +using System; +using Server; + +namespace Server.Engines.MLQuests.Definitions +{ + // Base class for escorts providing the AwardHumanInNeed option + public class BaseEscort : MLQuest + { + public virtual bool AwardHumanInNeed { get { return true; } } + + public BaseEscort() + { + CompletionNotice = CompletionNoticeShort; + } + + public override void GetRewards( MLQuestInstance instance ) + { + if ( AwardHumanInNeed ) + HumanInNeed.AwardTo( instance.Player ); + + base.GetRewards( instance ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Definitions/Bedlam.cs b/Scripts/Engines/MLQuests/Definitions/Bedlam.cs new file mode 100644 index 0000000..392498e --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Bedlam.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class Momento : MLQuest + { + public Momento() + { + Activated = true; + Title = 1074750; // Momento! + Description = 1074751; // I was going to march right out there and get it myself, but no ... Master Gnosos won't let me. But you see, that bridle means so much to me. A momento of happier, less-dead ... well undead horseback riding. Could you fetch it for me? I think my horse, formerly known as 'Resolve', may still be wearing it. + RefusalMessage = 1074752; // Hrmph. + InProgressMessage = 1074753; // The bridle would be hard to miss on him now ... since he's skeletal. Please do what you need to do to retreive it for me. + CompletionMessage = 1074754; // I'd know that jingling sound anywhere! You have recovered my bridle. Thank you. + + Objectives.Add( new CollectObjective( 1, typeof( ResolvesBridle ), "Resolve's Bridle" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Kia" ), new Point3D( 87, 1640, 0 ), Map.Malas ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Nythalia" ), new Point3D( 91, 1639, 0 ), Map.Malas ); + } + } + + public class CulinaryCrisis : MLQuest + { + public CulinaryCrisis() + { + Activated = true; + Title = 1074755; // Culinary Crisis + Description = 1074756; // You have NO idea how impossible this is. Simply intolerable! How can one expect an artiste' like me to create masterpieces of culinary delight without the best, fresh ingredients? Ever since this whositwhatsit started this uproar, my thrice-daily produce deliveries have ended. I can't survive another hour without produce! + RefusalMessage = 1074757; // You have no artistry in your soul. + InProgressMessage = 1074758; // I must have fresh produce and cheese at once! + CompletionMessage = 1074759; // Those dates look bruised! Oh no, and you fetched a soft cheese. *deep pained sigh* Well, even I can only do so much with inferior ingredients. BAM! + + Objectives.Add( new CollectObjective( 20, typeof( Dates ), 1025927 ) ); // bunch of dates + Objectives.Add( new CollectObjective( 5, typeof( CheeseWheel ), 1022430 ) ); // wheel of cheese + + Rewards.Add( ItemReward.BagOfTreasure ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Emerillo" ), new Point3D( 90, 1639, 0 ), Map.Malas ); + } + } + + public class GoneNative : MLQuest + { + public GoneNative() + { + Activated = true; + Title = 1074855; // Gone Native + Description = 1074856; // Pathetic really. I must say, a senior instructor going native -- forgetting about his students and peers and engaging in such disgraceful behavior! I'm speaking, of course, of Theophilus. Master Theophilus to you. He may have gone native but he still holds a Mastery Degree from Bedlam College! But, well, that's neither here nor there. I need you to take care of my colleague. Convince him of the error of his ways. He may resist. In fact, assume he will and kill him. We'll get him resurrected and be ready to cure his folly. What do you say? + RefusalMessage = 1074857; // I understand. A Master of Bedlam, even one entirely off his rocker, is too much for you to handle. + InProgressMessage = 1074858; // You had better get going. Master Theophilus isn't likely to kill himself just to save me this embarrassment. + CompletionMessage = 1074859; // You look a bit worse for wear! He put up a good fight did he? Hah! That's the spirit � a Master of Bedlam is a match for most. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( MasterTheophilus ) }, "Master Theophilus" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Kia (Bedlam)" )] + public class Kia : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Kia() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Kia"; + Title = "the student"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Sandals( 0x709 ) ); + AddItem( new Robe( 0x497 ) ); + } + + public Kia( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Emerillo (Bedlam)" )] + public class Emerillo : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074222 ); // Could I trouble you for some assistance? + } + + [Constructable] + public Emerillo() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Emerillo"; + Title = "the cook"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + AddItem( new ShortPants( Utility.RandomPinkHue() ) ); + AddItem( new Shirt() ); + AddItem( new HalfApron( 0x8FD ) ); + } + + public Emerillo( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Nythalia : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Nythalia() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Nythalia"; + Title = "the student"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Robe( Utility.RandomBool() ? 0x497 : 0x498 ) ); + } + + public Nythalia( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/BlightedGrove.cs b/Scripts/Engines/MLQuests/Definitions/BlightedGrove.cs new file mode 100644 index 0000000..8d6a6c2 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/BlightedGrove.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; +using Server.Items; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class VilePoison : MLQuest + { + public override Type NextQuest { get { return typeof( ARockAndAHardPlace ); } } + + public VilePoison() + { + Activated = true; + Title = 1074950; // Vile Poison + Description = 1074956; // Heya! I'm sure glad to see you. Listen I'm in a bit of a bind here. I'm supposed to be gathering poisoned water at the base of that corrupted tree there, but I can't get in under the roots to get a good sample. The branches and brush are so tainted that they can't be cut, burned or even magically passed. It's put my work at a real standstill. If you help me out, I'll help you get in there too. Whadda ya say? + RefusalMessage = 1074964; // Okay. If you change your mind, I'll probably still be stuck here trying to get in. + InProgressMessage = 1074968; // My friend, Iosep, is a weaponsmith in Jhelom. If anyone can help us, he can! + CompletionMessage = 1074991; // Greetings. What have you there? Ah, a sample from a poisonous tree, you say? My friend Jamal sent you? Well, let me see that then, and we'll get to work. + + Objectives.Add( new DeliverObjective( typeof( TaintedTreeSample ), 1, "tainted tree sample", typeof( Iosep ) ) ); + + Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jamal" ), new Point3D( 559, 1651, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jamal" ), new Point3D( 559, 1651, 0 ), Map.Trammel ); + + PutSpawner( new Spawner( 1, 5, 10, 0, 2, "Iosep" ), new Point3D( 1354, 3754, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 2, "Iosep" ), new Point3D( 1354, 3754, 0 ), Map.Trammel ); + } + } + + public class ARockAndAHardPlace : MLQuest + { + public override Type NextQuest { get { return typeof( SympatheticMagic ); } } + public override bool IsChainTriggered { get { return true; } } + + public ARockAndAHardPlace() + { + Activated = true; + Title = 1074951; // A Rock and a Hard Place + Description = 1074957; // This is some nasty stuff, that's for certain. I don't even want to think about what sort of blight caused this venomous reaction from that old tree. Let's get to work … we'll need to try something really hard but still workable as our base material. Nothing's harder than stone and diamond. Let's try them first. + RefusalMessage = 1074965; // Sure, no problem. I thought you were interested in figuring this out. + InProgressMessage = 1074969; // If you're a miner, you should have no trouble getting that stuff. If not, you can probably buy some samples from a miner? + CompletionMessage = 1074992; // Have you got the granite and diamonds? Great, let me see them and we'll see what effect this venom has upon them. + + // Any type of granite works + Objectives.Add( new CollectObjective( 4, typeof( BaseGranite ), 1026009 ) ); // rock + Objectives.Add( new CollectObjective( 2, typeof( BlueDiamond ), 1032696 ) ); // Blue Diamond + + Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove. + } + } + + public class SympatheticMagic : MLQuest + { + public override Type NextQuest { get { return typeof( AlreadyDead ); } } + public override bool IsChainTriggered { get { return true; } } + + public SympatheticMagic() + { + Activated = true; + Title = 1074952; // Sympathetic Magic + Description = 1074958; // Hmm, I've never even heard of something that can damage diamond like that. I guess we'll have to go with plan B. Let's try something similar. Sometimes there's a natural immunity to be found when you use a substance that's like the one you're trying to cut. A sort of "sympathetic" thing. Y'know? + RefusalMessage = 1074965; // Sure, no problem. I thought you were interested in figuring this out. + InProgressMessage = 1074970; // I think a lumberjack can help supply bark. + CompletionMessage = 1074993; // You're back with the bark already? Terrific! I bet this will do the trick. + + Objectives.Add( new CollectObjective( 10, typeof( BarkFragment ), 1032687 ) ); // Bark Fragment + + Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove. + } + } + + public class AlreadyDead : MLQuest + { + public override Type NextQuest { get { return typeof( Eureka ); } } + public override bool IsChainTriggered { get { return true; } } + + public AlreadyDead() + { + Activated = true; + Title = 1074953; // Already Dead + Description = 1074959; // Amazing! The bark was reduced to ash in seconds. Whatever this taint is, it plays havok with living things. And of course, it took the edge off both diamonds and granite even faster. What we need is something workable but dead; something that can hold an edge without melting. See what you can come up with, please. + RefusalMessage = 1074965; // Sure, no problem. I thought you were interested in figuring this out. + InProgressMessage = 1074971; // I'm thinking we need something fairly brittle or it won't hold an edge. And, it can't be alive, of course. + CompletionMessage = 1074994; // Great thought! Bone might just do the trick. + + Objectives.Add( new InternalObjective() ); + + Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove. + } + + private class InternalObjective : CollectObjective + { + public override bool ShowDetailed { get { return false; } } + + public InternalObjective() + : base( 10, typeof( Bone ), 1074963 ) // (10) workable samples + { + } + } + } + + public class Eureka : MLQuest + { + public override Type NextQuest { get { return typeof( SubContracting ); } } + public override bool IsChainTriggered { get { return true; } } + + public Eureka() + { + Activated = true; + Title = 1074954; // Eureka! + Description = 1074960; // We're in business! I've put together the instructions for chopping sort of sword, in the style of one of those new-fangled elven machetes. Take those back to Jamal for me, if you would. + RefusalMessage = 1074966; // Well, okay. I guess I thought you'd want to see this through. + InProgressMessage = 1074972; // I'm sure Jamal is eager to get this information. He's probably still hanging around near that big old blighted tree. + CompletionMessage = 1074995; // Heya! You're back. Was Iosep able to help? Let me see what he's sent. + + Objectives.Add( new DeliverObjective( typeof( SealedNotesForJamal ), 1, "sealed note for Jamal", typeof( Jamal ) ) ); + + Rewards.Add( new DummyReward( 1074962 ) ); // A step closer to entering Blighted Grove. + } + + public override void GetRewards( MLQuestInstance instance ) + { + PlayerMobile pm = instance.Player; + + if ( !pm.HasRecipe( 32 ) ) + { + // The ability is awarded regardless of blacksmithy skill + pm.AcquireRecipe( 32 ); + + if ( pm.Skills[SkillName.Blacksmith].Base < 45.0 ) // TODO: Verify threshold + pm.SendLocalizedMessage( 1075005 ); // You observe carefully but you can't grasp the complexities of smithing a bone handled machete. + else + pm.SendLocalizedMessage( 1075006 ); // You have learned how to smith a bone handled machete! + } + + base.GetRewards( instance ); + } + } + + public class SubContracting : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public SubContracting() + { + Activated = true; + Title = 1074955; // Sub Contracting + Description = 1074961; // Wonderful! Now we can both get in there! Let me show you these instructions for making this machete. If you're not skilled in smithing, I'm not sure how much sense it will make though. Listen, if you're heading in there anyway … maybe you'd do me one more favor? I'm ah ... buried in work out here ... so if you'd go in and get me a few water samples, I'd be obliged. + RefusalMessage = 1074967; // Oh. Right, I guess you're really ... ah ... busy too. + InProgressMessage = 1074973; // Once you're inside, look for places where the water has twisted and warped the natural creatures. + CompletionMessage = 1074996; // I hear sloshing ... that must mean you've got my water samples. Whew, I'm so glad you braved the dangers in there ... I mean, I would have but I'm so busy out here. Here's your reward! + + Objectives.Add( new CollectObjective( 3, typeof( SamplesOfCorruptedWater ), "samples of corrupted water" ) ); // On OSI the label is "#1074999" + // TODO: "Return to" should say "Jamal (near Blighted Grove)" + // Maybe every quest NPC has directions as a property? + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Jamal (near Blighted Grove)" )] + public class Jamal : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Jamal() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.2, 0.4 ) + { + Name = "Jamal"; + Title = "the Fisherman"; + Body = 400; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + + AddItem( new Shirt( 0x1BB ) ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + AddItem( new ThighBoots( Utility.RandomAnimalHue() ) ); + AddItem( new Backpack() ); + } + + public Jamal( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + reader.ReadInt(); + } + } + + [QuesterName( "Iosep (Jhelom)" )] + public class Iosep : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074209, // Hey, could you help me out with something? + 1074215 // Don’t test my patience you sniveling worm! + ) ); + } + + [Constructable] + public Iosep() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.2, 0.4 ) + { + Name = "Iosep"; + Title = "the Exporter"; + Body = 400; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + AddItem( new FancyShirt( Utility.RandomBlueHue() ) ); + AddItem( new LongPants( 0x1BB ) ); + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Backpack() ); + } + + public Iosep( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Britannia.cs b/Scripts/Engines/MLQuests/Definitions/Britannia.cs new file mode 100644 index 0000000..3ac7437 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Britannia.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class Aemaeth1 : MLQuest + { + public override Type NextQuest { get { return typeof( Aemaeth2 ); } } + + public Aemaeth1() + { + Activated = true; + Title = 1075321; // Aemaeth + Description = 1075322; // My father died in an accident some months ago. My mother refused to accept his death. We had a little money set by, and she took it to a necromancer, who promised to restore my father to life. Well, he revived my father, all right, the cheat! Now my father is a walking corpse, a travesty . . . a monster. My mother is beside herself -- she won't eat, she can't sleep. I prayed at the shrine of Spirituality for guidance, and I must have fallen asleep. When I awoke, there was this basin of clear water. I cannot leave my mother, for I fear what she might do to herself. Could you take this to the graveyard, and give it to what is left of my father? + RefusalMessage = 1075324; // Oh! Alright then. I hope someone comes along soon who can help me, or I dont know what will become of us. + InProgressMessage = 1075325; // My father - or what remains of him - can be found in the graveyard northwest of the city. + CompletionMessage = 1075326; // What is this you give me? A basin of water? + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, "Basin of Crystal Clear Water", typeof( SkeletonOfSzandor ) ) ); + + Rewards.Add( new DummyReward( 1075323 ) ); // Aurelia's gratitude. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aurelia" ), new Point3D( 1459, 3795, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aurelia" ), new Point3D( 1459, 3795, 0 ), Map.Felucca ); + } + } + + public class Aemaeth2 : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public Aemaeth2() + { + Activated = true; + OneTimeOnly = true; + Title = 1075327; // Aemaeth + Description = 1075328; // You tell me it is time to leave this flesh. I did not understand until now. I thought: I can see my wife and my daughter, I can speak. Is this not life? But now, as I regard my reflection, I see what I have become. This only a mockery of life. Thank you for having the courage to show me the truth. For the love I bear my wife and daughter, I know now that I must pass beyond the veil. Will you return this basin to Aurelia? She will know by this that I am at rest. + RefusalMessage = 1075330; // You wont take this back to my daughter? Please, I cannot leave until she knows I am at peace. + InProgressMessage = 1075331; // My daughter will be at my home, on the east side of the city. + CompletionMessage = 1075332; // Thank goodness! Now we can honor my father for the great man he was while he lived, rather than the horror he became. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( BasinOfCrystalClearWater ), 1, "Basin of Crystal Clear Water", typeof( Aurelia ) ) ); + + Rewards.Add( new ItemReward( 1075304, typeof( MirrorOfPurification ) ) ); // Mirror of Purification + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 2, "SkeletonOfSzandor" ), new Point3D( 1277, 3731, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 2, "SkeletonOfSzandor" ), new Point3D( 1277, 3731, 0 ), Map.Felucca ); + } + } + + public class OddsAndEnds : MLQuest + { + public OddsAndEnds() + { + Activated = true; + Title = 1074354; // Odds and Ends + Description = 1074677; // I've always been fascinated by primitive cultures -- especially the artifacts. I'm a collector, you see. I'm working on building my troglodyte display and I'm saddened to say that I'm short on examples of religion and superstition amongst the creatures. If you come across any primitive fetishes, I'd be happy to trade you something interesting for them. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1074678; // I don't really want to know where you get the primitive fetishes, as I can't support the destruction of their lifestyle and culture. That would be wrong. + CompletionMessage = 1074679; // Bravo! These fetishes are just what I needed. You've earned this reward. + + Objectives.Add( new CollectObjective( 12, typeof( PrimitiveFetish ), "Primitive Fetishes" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class EmbracingHumanity : MLQuest + { + public EmbracingHumanity() + { + Activated = true; + OneTimeOnly = true; // OSI has no limit or delay, VERY exploitable + Title = 1074349; // Embracing Humanity + Description = 1074357; // Well, I don't mind saying it -- I'm flabbergasted! Absolutely astonished. I just heard that some elves want to convert themselves to humans through some magical process. My cousin Nedrick does whatever needs doing. I guess you could check it out for yourself if you're curious. Anyway, I wonder if you'll bring my cousin, Drithen, this here treat my wife baked up for him special. + RefusalMessage = 1074459; // That's okay, I'll find someone else to make the delivery. + InProgressMessage = 1074460; // If I knew where my cousin was, I'd make the delivery myself. + CompletionMessage = 1074461; // Oh, hello there. What do you have for me? + + Objectives.Add( new DeliverObjective( typeof( SpecialTreatForDrithen ), 1, "treat for Drithen", typeof( Drithen ) ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + #endregion + + #region Mobiles + + public class Aurelia : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Aurelia() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Aurelia"; + Title = "the Architect's Daughter"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Sandals( Utility.RandomPinkHue() ) ); + + if ( Utility.RandomBool() ) + AddItem( new Kilt( Utility.RandomPinkHue() ) ); + else + AddItem( new Skirt( Utility.RandomPinkHue() ) ); + + AddItem( new FancyShirt( Utility.RandomRedHue() ) ); + } + + public Aurelia( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Szandor" )] + public class SkeletonOfSzandor : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public SkeletonOfSzandor() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Skeleton of Szandor"; + Title = "the Late Architect"; + Hue = 0x83F2; // TODO: Random human hue? Why??? + Body = 0x32; + InitStats( 100, 100, 25 ); + } + + public SkeletonOfSzandor( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Heartwood.cs b/Scripts/Engines/MLQuests/Definitions/Heartwood.cs new file mode 100644 index 0000000..648ae45 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Heartwood.cs @@ -0,0 +1,4551 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class TheyreBreedingLikeRabbits : MLQuest + { + public TheyreBreedingLikeRabbits() + { + Activated = true; + Title = 1072244; // They're Breeding Like Rabbits + Description = 1072259; // Aaaahhhh! They're everywhere! Aaaaahhh! Ahem. Actually, friend, how do you feel about rabbits? Well, we're being overrun by them. We're finding fuzzy bunnies everywhere. Aaaaahhh! + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Rabbit ) }, "rabbits" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Saril" ), new Point3D( 7075, 376, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Saril" ), new Point3D( 7075, 376, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Cailla" ), new Point3D( 7075, 377, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Cailla" ), new Point3D( 7075, 377, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Tamm" ), new Point3D( 7075, 378, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Tamm" ), new Point3D( 7075, 378, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Landy" ), new Point3D( 7089, 390, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Landy" ), new Point3D( 7089, 390, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alejaha" ), new Point3D( 7043, 387, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alejaha" ), new Point3D( 7043, 387, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Mielan" ), new Point3D( 7063, 350, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Mielan" ), new Point3D( 7063, 350, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Ciala" ), new Point3D( 7031, 411, 7 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Ciala" ), new Point3D( 7031, 411, 7 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aniel" ), new Point3D( 7034, 412, 6 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aniel" ), new Point3D( 7034, 412, 6 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aulan" ), new Point3D( 6986, 340, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aulan" ), new Point3D( 6986, 340, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Brinnae" ), new Point3D( 6996, 351, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Brinnae" ), new Point3D( 6996, 351, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Caelas" ), new Point3D( 7039, 390, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Caelas" ), new Point3D( 7039, 390, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Clehin" ), new Point3D( 7092, 390, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Clehin" ), new Point3D( 7092, 390, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cloorne" ), new Point3D( 7010, 364, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cloorne" ), new Point3D( 7010, 364, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Salaenih" ), new Point3D( 7009, 362, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Salaenih" ), new Point3D( 7009, 362, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Vilo" ), new Point3D( 7029, 377, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Vilo" ), new Point3D( 7029, 377, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tholef" ), new Point3D( 6986, 386, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tholef" ), new Point3D( 6986, 386, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tillanil" ), new Point3D( 6987, 388, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tillanil" ), new Point3D( 6987, 388, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Waelian" ), new Point3D( 6996, 381, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Waelian" ), new Point3D( 6996, 381, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sleen" ), new Point3D( 6997, 381, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sleen" ), new Point3D( 6997, 381, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Unoelil" ), new Point3D( 7010, 388, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Unoelil" ), new Point3D( 7010, 388, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Anolly" ), new Point3D( 7009, 388, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Anolly" ), new Point3D( 7009, 388, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jusae" ), new Point3D( 7042, 377, 2 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Jusae" ), new Point3D( 7042, 377, 2 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cillitha" ), new Point3D( 7043, 377, 2 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Cillitha" ), new Point3D( 7043, 377, 2 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Lohn" ), new Point3D( 7062, 410, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Lohn" ), new Point3D( 7062, 410, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Olla" ), new Point3D( 7063, 410, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Olla" ), new Point3D( 7063, 410, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Thallary" ), new Point3D( 7032, 439, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Thallary" ), new Point3D( 7032, 439, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Ahie" ), new Point3D( 7033, 440, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Ahie" ), new Point3D( 7033, 440, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tyeelor" ), new Point3D( 7010, 364, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Tyeelor" ), new Point3D( 7010, 364, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Athailon" ), new Point3D( 7011, 365, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Athailon" ), new Point3D( 7011, 365, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderTaellia" ), new Point3D( 7038, 387, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderTaellia" ), new Point3D( 7038, 387, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderMallew" ), new Point3D( 7047, 390, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderMallew" ), new Point3D( 7047, 390, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAbbein" ), new Point3D( 7043, 390, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAbbein" ), new Point3D( 7043, 390, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderVicaie" ), new Point3D( 7054, 390, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderVicaie" ), new Point3D( 7054, 390, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderJothan" ), new Point3D( 7056, 383, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderJothan" ), new Point3D( 7056, 383, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "ElderAlethanian" ), new Point3D( 7056, 380, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "ElderAlethanian" ), new Point3D( 7056, 380, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Rebinil" ), new Point3D( 7089, 380, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Rebinil" ), new Point3D( 7089, 380, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aluniol" ), new Point3D( 7089, 383, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Aluniol" ), new Point3D( 7089, 383, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Olaeni" ), new Point3D( 7080, 363, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Olaeni" ), new Point3D( 7080, 363, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Bolaevin" ), new Point3D( 7066, 351, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Bolaevin" ), new Point3D( 7066, 351, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperAneen" ), new Point3D( 7053, 337, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperAneen" ), new Point3D( 7053, 337, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Daelas" ), new Point3D( 7036, 412, 7 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Daelas" ), new Point3D( 7036, 412, 7 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alelle" ), new Point3D( 7028, 406, 7 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Alelle" ), new Point3D( 7028, 406, 7 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperNillaen" ), new Point3D( 7061, 370, 14 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperNillaen" ), new Point3D( 7061, 370, 14 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperRyal" ), new Point3D( 7009, 375, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperRyal" ), new Point3D( 7009, 375, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Braen" ), new Point3D( 7081, 366, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Braen" ), new Point3D( 7081, 366, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAcob" ), new Point3D( 7037, 387, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "ElderAcob" ), new Point3D( 7037, 387, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperCalendor" ), new Point3D( 7062, 370, 14 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperCalendor" ), new Point3D( 7062, 370, 14 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperSiarra" ), new Point3D( 7051, 339, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "LorekeeperSiarra" ), new Point3D( 7051, 339, 0 ), Map.Felucca ); + } + } + + public class TheyllEatAnything : MLQuest + { + public TheyllEatAnything() + { + Activated = true; + Title = 1072248; // They'll Eat Anything + Description = 1072262; // Pork is the fruit of the land! You can barbeque it, boil it, bake it, sautee it. There's pork kebabs, pork creole, pork gumbo, pan fried, deep fried, stir fried. There's apple pork, peppered pork, pork soup, pork salad, pork and potatoes, pork burger, pork sandwich, pork stew, pork chops, pork loins, shredded pork. So, lets get some piggies butchered! + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Pig ) }, "pigs" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class NoGoodFishStealing : MLQuest + { + public NoGoodFishStealing() + { + Activated = true; + Title = 1072251; // No Good, Fish Stealing ... + Description = 1072265; // Mighty creatures they are, aye. Fierce and strong, can't blame 'em for wanting to feed themselves an' all. Blame or no, they're eating all the fish up, so they got to go. Lend a hand? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Walrus ) }, "walruses" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class AHeroInTheMaking : MLQuest + { + public AHeroInTheMaking() + { + Activated = true; + Title = 1072246; // A Hero in the Making + Description = 1072257; // Are you new around here? Well, nevermind that. You look ready for adventure, I can see the gleam of glory in your eyes! Nothing is more valiant, more noble, more praiseworthy than mongbat slaying. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Mongbat ) }, "mongbats" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class BullfightingSortOf : MLQuest + { + public BullfightingSortOf() + { + Activated = true; + Title = 1072247; // Bullfighting ... Sort Of + Description = 1072254; // You there! Yes, you. Listen, I've got a little problem on my hands, but a brave, bold hero like yourself should find it a snap to solve. Bottom line -- we need some of the bulls in the area culled. You're welcome to any meat or hides, and of course, I'll give you a nice reward. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Bull ) }, "bulls" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class AFineFeast : MLQuest + { + public AFineFeast() + { + Activated = true; + Title = 1072243; // A Fine Feast. + Description = 1072261; // Mmm, I do love mutton! It's slaughtering time again and my usual hirelings haven't turned up. I've arranged for a butcher to come by and cut everything up but the basic sheep killing part I haven't gotten worked out yet. Are you up for the task? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Sheep ) }, "sheep" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class ForcedMigration : MLQuest + { + public ForcedMigration() + { + Activated = true; + Title = 1072250; // Forced Migration + Description = 1072264; // Chirp chirp ... tweet chirp. Tra la la. Bloody birds and their blasted noise. I've tried everything but they just won't stop that infernal clamor. Return me to blessed silence and I'll make it worth your while. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Bird ) }, "birds" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class FilthyPests : MLQuest + { + public FilthyPests() + { + Activated = true; + Title = 1072242; // Filthy Pests! + Description = 1072253; // They're everywhere I tell you! They crawl in the walls, they scurry in the bushes. Disgusting critters. Say ... I don't suppose you're up for some sewer rat killing? Sewer rats now, not any other kind of squeaker will do. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Sewerrat ) }, "sewer rats" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class DeadManWalking : MLQuest + { + public DeadManWalking() + { + Activated = true; + Title = 1072983; // Dead Man Walking + Description = 1073009; // Why? I ask you why? They walk around after they're put in the ground. It's just wrong in so many ways. Put them to proper rest, I beg you. I'll find some way to pay you for the kindness. Just kill five zombies and five skeletons. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 5, new Type[] { typeof( Zombie ) }, "zombies" ) ); + Objectives.Add( new KillObjective( 5, new Type[] { typeof( Skeleton ) }, "skeletons" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class KingOfBears : MLQuest + { + public KingOfBears() + { + Activated = true; + Title = 1072996; // King of Bears + Description = 1073030; // A pity really. With the balance of nature awry, we have no choice but to accept the responsibility of making it all right. It's all a part of the circle of life, after all. So, yes, the grizzly bears are running rampant. There are far too many in the region. Will you shoulder your obligations as a higher life form? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( GrizzlyBear ) }, "grizzly bears" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class Specimens : MLQuest + { + public Specimens() + { + Activated = true; + Title = 1072999; // Specimens + Description = 1073032; // I admire them, you know. The solen have their place -- regimented, organized. They're fascinating to watch with their constant strife between red and black. I can't help but want to stir things up from time to time. And that's where you come in. Kill either twelve red or twelve black solen workers and let's see what happens next! + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + ObjectiveType = ObjectiveType.Any; + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( RedSolenWorker ) }, "red solen workers" ) ); + Objectives.Add( new KillObjective( 12, new Type[] { typeof( BlackSolenWorker ) }, "black solen workers" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class Spirits : MLQuest + { + public Spirits() + { + Activated = true; + Title = 1073076; // Spirits + Description = 1073566; // It is a piteous thing when the dead continue to walk the earth. Restless spirits are known to inhabit these parts, taking the lives of unwary travelers. It is about time a hero put the dead back in their graves. I'm sure such a hero would be justly rewarded. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073586; // The restless spirts still walk -- you must kill 15 of them. + + Objectives.Add( new KillObjective( 15, new Type[] { typeof( Spectre ), typeof( Shade ), typeof( Wraith ) }, "spectres or shades or wraiths" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class RollTheBones : MLQuest + { + public RollTheBones() + { + Activated = true; + Title = 1073002; // Roll the Bones + Description = 1073011; // Why? I ask you why? They walk around after they're put in the ground. It's just wrong in so many ways. Put them to proper rest, I beg you. I'll find some way to pay you for the kindness. Just kill eight patchwork skeletons. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( PatchworkSkeleton ) }, "patchwork skeletons" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class ItsAGhastlyJob : MLQuest + { + public ItsAGhastlyJob() + { + Activated = true; + Title = 1073008; // It's a Ghastly Job + Description = 1073012; // Why? I ask you why? They walk around after they're put in the ground. It's just wrong in so many ways. Put them to proper rest, I beg you. I'll find some way to pay you for the kindness. Just kill twelve ghouls. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Ghoul ) }, "ghouls" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class Troglodytes : MLQuest + { + public Troglodytes() + { + Activated = true; + Title = 1074688; // Troglodytes! + Description = 1074689; // Oh nevermind, you don't look capable of my task afterall. Haha! What was I thinking - you could never handle killing troglodytes. It'd be suicide. What? I don't know, I don't want to be responsible ... well okay if you're really sure? + RefusalMessage = 1074690; // Probably the wiser course of action. + InProgressMessage = 1074691; // You still need to kill those troglodytes, remember? + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Troglodyte ) }, "troglodytes" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class UnholyKnights : MLQuest + { + public UnholyKnights() + { + Activated = true; + Title = 1073075; // Unholy Knights + Description = 1073565; // Please, hear me kind traveler. You know when a knight falls, sometimes they are cursed to roam the earth as undead mockeries of their former glory? That is too grim a fate for even any knight to suffer! Please, put them out of their misery. I will offer you what payment I can if you will end the torment of these undead wretches. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073585; // Your task is not done. Continue putting the Skeleton and Bone Knights to rest. + + Objectives.Add( new KillObjective( 16, new Type[] { typeof( BoneKnight ), typeof( SkeletalKnight ) }, "bone knights or skeletal knights" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class AFeatherInYerCap : MLQuest + { + public AFeatherInYerCap() + { + Activated = true; + Title = 1074738; // A Feather in Yer Cap + Description = 1074737; // I've seen how you strut about, as if you were something special. I have some news for you, you don't impress me at all. It's not enough to have a fancy hat you know. That may impress people in the big city, but not here. If you want a reputation you have to climb a mountain, slay some great beast, and then write about it. Trust me, it's a long process. The first step is doing a great feat. If I were you, I'd go pluck a feather from the harpy Saliva, that would give you a good start. + RefusalMessage = 1074736; // The path to greatness isn't for everyone obviously. + InProgressMessage = 1074735; // If you're going to get anywhere in the adventuring game, you have to take some risks. A harpy, well, it's bad, but it's not a dragon. + CompletionMessage = 1074734; // The hero returns from the glorious battle and - oh, such a small feather? + + Objectives.Add( new CollectObjective( 1, typeof( SalivasFeather ), "Saliva's Feather" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ATaleOfTail : MLQuest + { + public ATaleOfTail() + { + Activated = true; + Title = 1074726; // A Tale of Tail + Description = 1074727; // I've heard of you, adventurer. Your reputation is impressive, and now I'll put it to the test. This is not something I ask lightly, for this task is fraught with danger, but it is vital. Seek out the vile hydra Abscess, slay it, and return to me with it's tail. + RefusalMessage = 1074728; // Well, the beast will still be there when you are ready I suppose. + InProgressMessage = 1074729; // Em, I thought I had explained already. Abscess, the hydra, you know? Lots of heads but just the one tail. I need the tail. I have my reasons. Go go go. + CompletionMessage = 1074730; // Ah, the tail. You did it! You know the rumours about dried ground hydra tail powder are all true? Thank you so much! + + Objectives.Add( new CollectObjective( 1, typeof( AbscessTail ), "Abscess' Tail" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ATrogAndHisDog : MLQuest + { + public ATrogAndHisDog() + { + Activated = true; + Title = 1074681; // A Trog and His Dog + Description = 1074680; // I don't know if you can handle it, but I'll give you a go at it. Troglodyte chief - name of Lurg and his mangy wolf pet need killing. Do the deed and I'll reward you. + RefusalMessage = 1074655; // Perhaps I thought too highly of you. + InProgressMessage = 1074682; // The trog chief and his mutt should be easy enough to find. Just kill them and report back. Easy enough. + CompletionMessage = 1074683; // Not half bad. Here's your prize. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Lurg ) }, "Lurg" ) ); + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Grobu ) }, "Grobu" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class Overpopulation : MLQuest + { + public Overpopulation() + { + Activated = true; + Title = 1072252; // Overpopulation + Description = 1072267; // I just can't bear it any longer. Sure, it's my job to thin the deer out so they don't overeat the area and starve themselves come winter time. Sure, I know we killed off the predators that would do this naturally so now we have to make up for it. But they're so graceful and innocent. I just can't do it. Will you? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Hind ) }, "hinds" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class WildBoarCull : MLQuest + { + public WildBoarCull() + { + Activated = true; + Title = 1072245; // Wild Boar Cull + Description = 1072260; // A pity really. With the balance of nature awry, we have no choice but to accept the responsibility of making it all right. It's all a part of the circle of life, after all. So, yes, the boars are running rampant. There are far too many in the region. Will you shoulder your obligations as a higher life form? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Boar ) }, "boars" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class ItsElemental : MLQuest + { + public ItsElemental() + { + Activated = true; + Title = 1073089; // It's Elemental + Description = 1073579; // The universe is all about balance my friend. Tip one end, you must balance the other. That's why I must ask you to kill not just one kind of elemental, but three kinds. Snuff out some Fire, douse a few Water, and crush some Earth elementals and I'll pay you for your trouble. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073599; // Four of each, that's all I ask. Water, earth and fire. + + Objectives.Add( new KillObjective( 4, new Type[] { typeof( FireElemental ) }, "fire elementals" ) ); + Objectives.Add( new KillObjective( 4, new Type[] { typeof( WaterElemental ) }, "water elementals" ) ); + Objectives.Add( new KillObjective( 4, new Type[] { typeof( EarthElemental ) }, "earth elementals" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class CircleOfLife : MLQuest + { + public CircleOfLife() + { + Activated = true; + Title = 1073656; // Circle of Life + Description = 1073695; // There's been a bumper crop of evil with the Bog Things in these parts, my friend. Though they are foul creatures, they are also most fecund. Slay one and you make the land more fertile. Even better, slay several and I will give you whatever coin I can spare. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073736; // Continue to seek and kill the Bog Things. + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( BogThing ) }, "bog things" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class DustToDust : MLQuest + { + public DustToDust() + { + Activated = true; + Title = 1073074; // Dust to Dust + Description = 1073564; // You want to hear about trouble? I got trouble. How's angry piles of granite walking around for trouble? Maybe they don't like the mining, maybe it's the farming. I don't know. All I know is someone's got to turn them back to potting soil. And it'd be worth a pretty penny to the soul that does it. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073584; // You got rocks in your head? I said to kill 12 earth elementals, okay? + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( EarthElemental ) }, "earth elementals" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class CreepyCrawlies : MLQuest + { + public CreepyCrawlies() + { + Activated = true; + Title = 1072987; // Creepy Crawlies + Description = 1073016; // Disgusting! The way they scuttle on those hairy legs just makes me want to gag. I hate spiders! Rid the world of twelve and I'll find something nice to give you in thanks. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( GiantSpider ) }, "giant spiders" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class VoraciousPlants : MLQuest + { + public VoraciousPlants() + { + Activated = true; + Title = 1073001; // Voracious Plants + Description = 1073024; // I bet you can't tangle with those nasty plants ... say eight corpsers and two swamp tentacles! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( Corpser ) }, "corpsers" ) ); + Objectives.Add( new KillObjective( 2, new Type[] { typeof( SwampTentacle ) }, "swamp tentacles" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class GibberJabber : MLQuest + { + public GibberJabber() + { + Activated = true; + Title = 1073004; // Gibber Jabber + Description = 1073024; // I bet you can't kill ... ten gibberlings! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Gibberling ) }, "gibberlings" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class AnimatedMonstrosity : MLQuest + { + public AnimatedMonstrosity() + { + Activated = true; + Title = 1072990; // Animated Monstrosity + Description = 1073020; // I bet you can't kill ... say twelve ... flesh golems! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( FleshGolem ) }, "flesh golems" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class BirdsOfAFeather : MLQuest + { + public BirdsOfAFeather() + { + Activated = true; + Title = 1073007; // Birds of a Feather + Description = 1073022; // I bet you can't kill ... ten harpies! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Harpy ) }, "harpies" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class Frightmares : MLQuest + { + public Frightmares() + { + Activated = true; + Title = 1073000; // Frightmares + Description = 1073036; // I bet you can't handle ten plague spawns! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( PlagueSpawn ) }, "plague spawns" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class MoltenReptiles : MLQuest + { + public MoltenReptiles() + { + Activated = true; + Title = 1072989; // Molten Reptiles + Description = 1073018; // I bet you can't kill ... say ten ... lava lizards! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( LavaLizard ) }, "lava lizards" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class BloodyNuisance : MLQuest + { + public BloodyNuisance() + { + Activated = true; + Title = 1072992; // Bloody Nuisance + Description = 1073021; // I bet you can't kill ... ten gore fiends! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( GoreFiend ) }, "gore fiends" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class BloodSuckers : MLQuest + { + public BloodSuckers() + { + Activated = true; + Title = 1072997; // Blood Suckers + Description = 1073025; // I bet you can't tangle with those bloodsuckers ... say around ten vampire bats! I bet they're too much for you. You may as well confess you can't ... + RefusalMessage = 1073019; // Hahahaha! I knew it! + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( VampireBat ) }, "vampire bats" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class TheAfterlife : MLQuest + { + public TheAfterlife() + { + Activated = true; + Title = 1073073; // The Afterlife + Description = 1073563; // Nobody told me about the Mummy's Curse. How was I supposed to know you shouldn't disturb the tombs? Oh, sure, now all I hear about is the curse of the vengeful dead. I'll tell you what - make a few of these mummies go away and we'll keep this between you and me. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073583; // Uh, I don't think you're quite done killing Mummies yet. + + Objectives.Add( new KillObjective( 15, new Type[] { typeof( Mummy ) }, "mummies" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ForkedTongue : MLQuest + { + public ForkedTongue() + { + Activated = true; + Title = 1073655; // Forked Tongue + Description = 1073694; // I must implore you, brave traveler, to do battle with the vile reptiles which haunt these parts. Those hideous abominations, the Ophidians, are a blight across the land. If you were able to put down a host of the scaly warriors, the Knights or the Avengers, I would forever be in your debt. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073735; // Have you killed the Ophidian Knights or Avengers? + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( OphidianKnight ) }, "ophidian avengers or ophidian knight-errants" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class ImpishDelights : MLQuest + { + public ImpishDelights() + { + Activated = true; + Title = 1073077; // Impish Delights + Description = 1073567; // Imps! Do you hear me? Imps! They're everywhere! They're in everything! Oh, don't be fooled by their size - they vicious little devils! Half-sized evil incarnate, they are! Somebody needs to send them back to where they came from, if you know what I mean. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073587; // Don't let the little devils scare you! You kill 12 imps - then we'll talk reward. + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Imp ) }, "imps" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ThreeWishes : MLQuest + { + public ThreeWishes() + { + Activated = true; + Title = 1073660; // Three Wishes + Description = 1073699; // If I had but one wish, it would be to rid myself of these dread Efreet! Fire and ash, they are cunning and deadly! You look a brave soul - would you be interested in earning a rich reward for slaughtering a few of the smoky devils? + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073740; // Those smoky devils, the Efreets, are still about. + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( Efreet ) }, "efreets" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class EvilEye : MLQuest + { + public EvilEye() + { + Activated = true; + Title = 1073084; // Evil Eye + Description = 1073574; // Kind traveler, hear my plea. You know of the evil orbs? The wrathful eyes? Some call them gazers? They must be a nest nearby, for they are tormenting us poor folk. We need to drive back their numbers. But we are not strong enough to face such horrors ourselves, we need a true hero. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073594; // Have you annihilated a dozen Gazers yet, kind traveler? + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Gazer ) }, "gazers" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class GargoylesWrath : MLQuest + { + public GargoylesWrath() + { + Activated = true; + Title = 1073658; // Gargoyle's Wrath + Description = 1073697; // It is regretable that the Gargoyles insist upon warring with us. Their Enforcers attack men on sight, despite all efforts at reason. To help maintain order in this region, I have been authorized to encourage bounty hunters to reduce their numbers. Eradicate their number and I will reward you handsomely. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073738; // I won't be able to pay you until you've gotten enough Gargoyle Enforcers. + + Objectives.Add( new KillObjective( 6, new Type[] { typeof( GargoyleEnforcer ) }, "gargoyle enforcers" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class UndeadMages : MLQuest + { + public UndeadMages() + { + Activated = true; + Title = 1073080; // Undead Mages + Description = 1073570; // Why must the dead plague the living? With their foul necromancy and dark sorceries, the undead menace the countryside. I fear what will happen if no one is strong enough to face these nightmare sorcerers and thin their numbers. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073590; // Surely, a brave soul like yourself can kill 10 Bone Magi and Skeletal Mages? + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( BoneMagi ), typeof( SkeletalMage ) }, "bone mages or skeletal mages" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class FriendlyNeighborhoodSpiderkiller : MLQuest + { + public FriendlyNeighborhoodSpiderkiller() + { + Activated = true; + Title = 1073662; // Friendly Neighborhood Spider-killer + Description = 1073701; // They aren't called Dread Spiders because they're fluffy and cuddly now, are they? No, there's nothing appealing about those wretches so I sure wouldn't lose any sleep if you were to exterminate a few. I'd even part with a generous amount of gold, I would. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073742; // Dread Spiders? I say keep exterminating the arachnid vermin. + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( DreadSpider ) }, "dread spiders" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class MongbatMenace : MLQuest + { + public MongbatMenace() + { + Activated = true; + Title = 1073003; // Mongbat Menace! + Description = 1073033; // I imagine you don't know about the mongbats. Well, you may think you do, but I know more than just about anyone. You see they come in two varieties ... the stronger and the weaker. Either way, they're a menace. Exterminate ten of the weaker ones and four of the stronger and I'll pay you an honest wage. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Mongbat ) }, "mongbats" ) ); + Objectives.Add( new KillObjective( 4, new Type[] { typeof( GreaterMongbat ) }, "greater mongbats" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class StirringTheNest : MLQuest + { + public StirringTheNest() + { + Activated = true; + Title = 1073087; // Stirring the Nest + Description = 1073577; // Were you the sort of child that enjoyed knocking over anthills? Well, perhaps you'd like to try something a little bigger? There's a Solen nest nearby and I bet if you killed a queen or two, it would be quite the sight to behold. I'd even pay to see that - what do you say? + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073597; // Dead Solen Queens isn't too much to ask, is it? + + ObjectiveType = ObjectiveType.Any; + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( RedSolenQueen ) }, "red solen queens" ) ); + Objectives.Add( new KillObjective( 3, new Type[] { typeof( BlackSolenQueen ) }, "black solen queens" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class WarriorCaste : MLQuest + { + public WarriorCaste() + { + Activated = true; + Title = 1073078; // Warrior Caste + Description = 1073568; // The Terathan are an aggressive species. Left unchecked, they will swarm across our lands. And where will that leave us? Compost in the hive, that's what! Stop them, stop them cold my friend. Kill their warriors and you'll check their movement, that is certain. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073588; // Unless you kill at least 10 Terathan Warriors, you won't have any impact on their hive. + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( TerathanWarrior ) }, "terathan warriors" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class BigWorms : MLQuest + { + public BigWorms() + { + Activated = true; + Title = 1073088; // Big Worms + Description = 1073578; // It makes no sense! Cold blooded serpents cannot live in the ice! It's a biological impossibility! They are an abomination against reason! Please, I beg you - kill them! Make them disappear for me! Do this and I will reward you. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073598; // You wouldn't try and just pretend you murdered 10 Giant Ice Worms, would you? + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( IceSerpent ) }, "giant ice serpents" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class OrcishElite : MLQuest + { + public OrcishElite() + { + Activated = true; + Title = 1073081; // Orcish Elite + Description = 1073571; // Foul brutes! No one loves an orc, but some of them are worse than the rest. Their Captains and their Bombers, for instance, they're the worst of the lot. Kill a few of those, and the rest are just a rabble. Exterminate a few of them and you'll make the world a sunnier place, don't you know. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073591; // The only good orc is a dead orc - and 4 dead Captains and 6 dead Bombers is even better! + + Objectives.Add( new KillObjective( 6, new Type[] { typeof( OrcBomber ) }, "orc bombers" ) ); + Objectives.Add( new KillObjective( 4, new Type[] { typeof( OrcCaptain ) }, "orc captain" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ThinningTheHerd : MLQuest + { + public ThinningTheHerd() + { + Activated = true; + Title = 1072249; // Thinning the Herd + Description = 1072263; // Psst! Hey ... psst! Listen, I need some help here but it's gotta be hush hush. I don't want THEM to know I'm onto them. They watch me. I've seen them, but they don't know that I know what I know. You know? Anyway, I need you to scare them off by killing a few of them. That'll send a clear message that I won't suffer goats watching me! + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Goat ) }, "goats" ) ); + + Rewards.Add( ItemReward.SmallBagOfTrinkets ); + } + } + + public class Squishy : MLQuest + { + public Squishy() + { + Activated = true; + Title = 1072998; // Squishy + Description = 1073031; // Have you ever seen what a slime can do to good gear? Well, it's not pretty, let me tell you! If you take on my task to destroy twelve of them, bear that in mind. They'll corrode your equipment faster than anything. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Slime ) }, "slimes" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class OrcSlaying : MLQuest + { + public OrcSlaying() + { + Activated = true; + Title = 1072986; // Orc Slaying + Description = 1073015; // Those green-skinned freaks have run off with more of my livestock. I want an orc scout killed for each sheep I lost and an orc for each chicken. So that's four orc scouts and eight orcs I'll pay you to slay. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( Orc ) }, "orcs" ) ); + // TODO: This needs to be orc scouts but they aren't in the SVN + Objectives.Add( new KillObjective( 4, new Type[] { typeof( OrcishLord ) }, "orcish lords" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class ABigJob : MLQuest + { + public ABigJob() + { + Activated = true; + Title = 1072988; // A Big Job + Description = 1073017; // It's a big job but you look to be just the adventurer to do it! I'm so glad you came by ... I'm paying well for the death of five ogres and five ettins. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 5, new Type[] { typeof( Ogre ) }, "ogres" ) ); + Objectives.Add( new KillObjective( 5, new Type[] { typeof( Ettin ) }, "ettins" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class TrollingForTrolls : MLQuest + { + public TrollingForTrolls() + { + Activated = true; + Title = 1072985; // Trolling for Trolls + Description = 1073014; // They may not be bright, but they're incredibly destructive. Kill off ten trolls and I'll consider it a favor done for me. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Troll ) }, "trolls" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class ColdHearted : MLQuest + { + public ColdHearted() + { + Activated = true; + Title = 1072991; // Cold Hearted + Description = 1073027; // It's a big job but you look to be just the adventurer to do it! I'm so glad you came by ... I'm paying well for the death of six giant ice serpents and six frost spiders. Hop to it, if you're so inclined. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 6, new Type[] { typeof( IceSerpent ) }, "giant ice serpents" ) ); + Objectives.Add( new KillObjective( 6, new Type[] { typeof( FrostSpider ) }, "frost spiders" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class ForkedTongues : MLQuest + { + public ForkedTongues() + { + Activated = true; + Title = 1072984; // Forked Tongues + Description = 1073013; // You can't trust them, you know. Lizardmen I mean. They have forked tongues ... and you know what that means. Exterminate ten of them and I'll reward you. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Lizardman ) }, "lizardmen" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class ShakingThingsUp : MLQuest + { + public ShakingThingsUp() + { + Activated = true; + Title = 1073083; // Shaking Things Up + Description = 1073573; // A Solen hive is a fascinating piece of ecology. It's put together like a finely crafted clock. Who knows what happens if you remove something? So let's find out. Exterminate a few of the warriors and I'll make it worth your while. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073593; // I don't think you've gotten their attention yet -- you need to kill at least 10 Solen Warriors. + + ObjectiveType = ObjectiveType.Any; + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( RedSolenWarrior ) }, "red solen warriors" ) ); + Objectives.Add( new KillObjective( 10, new Type[] { typeof( BlackSolenWarrior ) }, "black solen warriors" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class Arachnophobia : MLQuest + { + public Arachnophobia() + { + Activated = true; + Title = 1073079; // Arachnophobia + Description = 1073569; // I've seen them hiding in their webs among the woods. Glassy eyes, spindly legs, poisonous fangs. Monsters, I say! Deadly horrors, these black widows. Someone must exterminate the abominations! If only I could find a worthy hero for such a task, then I could give them this considerable reward. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073589; // You've got a good start, but to stop the black-eyed fiends, you need to kill a dozen. + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( GiantBlackWidow ) }, "giant black widows" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class MiniSwampThing : MLQuest + { + public MiniSwampThing() + { + Activated = true; + Title = 1073072; // Mini Swamp Thing + Description = 1073562; // Some say killing a boggling brings good luck. I don't place much stock in old wives' tales, but I can say a few dead bogglings would certainly be lucky for me! Help me out and I can reward you for your efforts. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073582; // Go back and kill all 20 bogglings! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Bogling ) }, "boglings" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ThePerilsOfFarming : MLQuest + { + public ThePerilsOfFarming() + { + Activated = true; + Title = 1073664; // The Perils of Farming + Description = 1073703; // I should be trimming back the vegetation here, but something nasty has taken root. Viscious vines I can't go near. If there's any hope of getting things under control, some one's going to need to destroy a few of those Whipping Vines. Someone strong and fast and tough. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073744; // How are farmers supposed to work with these Whipping Vines around? + + Objectives.Add( new KillObjective( 15, new Type[] { typeof( WhippingVine ) }, "whipping vines" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class IndustriousAsAnAntLion : MLQuest + { + public IndustriousAsAnAntLion() + { + Activated = true; + Title = 1073665; // Industrious as an Ant Lion + Description = 1073704; // Ants are industrious and Lions are noble so who'd think an Ant Lion would be such a problem? The Ant Lion's have been causing mindless destruction in these parts. I suppose it's just how ants are. But I need you to help eliminate the infestation. Would you be willing to help for a bit of reward? + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073745; // Please, rid us of the Ant Lion infestation. + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( AntLion ) }, "ant lions" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class UnholyConstruct : MLQuest + { + public UnholyConstruct() + { + Activated = true; + Title = 1073666; // Unholy Construct + Description = 1073705; // They're unholy, I say. Golems, a walking mockery of all life, born of blackest magic. They're not truly alive, so destroying them isn't a crime, it's a service. A service I will gladly pay for. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073746; // The unholy brutes, the Golems, must be smited! + CompletionMessage = 1073787; // Reduced those Golems to component parts? Good, then -- you deserve this reward! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Golem ) }, "golems" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class AChillInTheAir : MLQuest + { + public AChillInTheAir() + { + Activated = true; + Title = 1073663; // A Chill in the Air + Description = 1073702; // Feel that chill in the air? It means an icy death for the unwary, for deadly Ice Elementals are about. Who knows what magic summoned them, what's important now is getting rid of them. I don't have much, but I'll give all I can if you'd only stop the cold-hearted monsters. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073746; // The chill won't lift until you eradicate a few Ice Elemenals. + + Objectives.Add( new KillObjective( 15, new Type[] { typeof( IceElemental ) }, "ice elementals" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class TheKingOfClothing : MLQuest + { + public TheKingOfClothing() + { + Activated = true; + HasRestartDelay = true; + Title = 1073902; // The King of Clothing + Description = 1074092; // I have heard noble tales of a fine and proud human garment. An article of clothing fit for both man and god alike. It is called a "kilt" I believe? Could you fetch for me some of these kilts so I that I might revel in their majesty and glory? + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073948; // I will be in your debt if you bring me kilts. + CompletionMessage = 1073974; // I say truly - that is a magnificent garment! You have more than earned a reward. + + Objectives.Add( new CollectObjective( 10, typeof( Kilt ), 1025431 ) ); // kilt + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class ThePuffyShirt : MLQuest + { + public ThePuffyShirt() + { + Activated = true; + HasRestartDelay = true; + Title = 1073903; // The Puffy Shirt + Description = 1074093; // We elves believe that beauty is expressed in all things, including the garments we wear. I wish to understand more about human aesthetics, so please kind traveler - could you bring to me magnificent examples of human fancy shirts? For my thanks, I could teach you more about the beauty of elven vestements. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073949; // I will be in your debt if you bring me fancy shirts. + CompletionMessage = 1073973; // I appreciate your service. Now, see what elven hands can create. + + Objectives.Add( new CollectObjective( 10, typeof( FancyShirt ), 1027933 ) ); // fancy shirt + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class FromTheGaultierCollection : MLQuest + { + public FromTheGaultierCollection() + { + Activated = true; + HasRestartDelay = true; + Title = 1073905; // From the Gaultier Collection + Description = 1074095; // It is my understanding, the females of humankind actually wear on certain occasions a studded bustier? This is not simply a fanciful tale? Remarkable! It sounds hideously uncomfortable as well as ludicrously impracticle. But perhaps, I simply do not understand the nuances of human clothing. Perhaps, I need to see such a studded bustier for myself? + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073951; // I will be in your debt if you bring me studded bustiers. + CompletionMessage = 1073976; // Truly, it is worse than I feared. Still, I appreciate your efforts on my behalf. + + Objectives.Add( new CollectObjective( 10, typeof( StuddedBustierArms ), 1027180 ) ); // studded bustier + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class HauteCouture : MLQuest + { + public HauteCouture() + { + Activated = true; + HasRestartDelay = true; + Title = 1073901; // H�ute Couture + Description = 1074091; // Most human apparel is interesting to elven eyes. But there is one garment - the flower garland - which sounds very elven indeed. Could I see how a human crafts such an object of beauty? In exchange, I could share with you the wonders of elven garments. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073947; // I will be in your debt if you bring me flower garlands. + CompletionMessage = 1073973; // I appreciate your service. Now, see what elven hands can create. + + Objectives.Add( new CollectObjective( 10, typeof( FlowerGarland ), 1028965 ) ); // flower garland + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class TheSongOfTheWind : MLQuest + { + public TheSongOfTheWind() + { + Activated = true; + HasRestartDelay = true; + Title = 1073910; // The Song of the Wind + Description = 1074100; // To give voice to the passing wind, this is an idea worthy of an elf! Friend, bring me some of the amazing fancy wind chimes so that I may listen to the song of the passing breeze. Do this, and I will share with you treasured elven secrets. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073956; // I will be in your debt if you bring me fancy wind chimes. + CompletionMessage = 1073980; // Such a delightful sound, I think I shall never tire of it. + + Objectives.Add( new CollectObjective( 10, typeof( FancyWindChimes ), "fancy wind chimes" ) ); + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class BeerGoggles : MLQuest + { + public BeerGoggles() + { + Activated = true; + HasRestartDelay = true; + Title = 1073895; // Beer Goggles + Description = 1074085; // Oh, the deviltry! Why would humans lock their precious liquors inside a wooden coffin? I understand I need a "keg tap" to access the golden brew within such a wooden abomination. Perhaps, if you could bring me such a tap, we could share a drink and I could teach you. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073941; // I will be in your debt if you bring me barrel taps. + CompletionMessage = 1073971; // My thanks for your service. Here is something for you to enjoy. + + Objectives.Add( new CollectObjective( 25, typeof( BarrelTap ), 1024100 ) ); // barrel tap + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class MessageInABottleQuest : MLQuest + { + public MessageInABottleQuest() + { + Activated = true; + HasRestartDelay = true; + Title = 1073894; // Message in a Bottle + Description = 1074084; // We elves are interested in trading our wines with humans but we understand human usually trade such brew in strange transparent bottles. If you could provide some of these empty glass bottles, I might engage in a bit of elven winemaking. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073940; // I will be in your debt if you bring me empty bottles. + CompletionMessage = 1073971; // My thanks for your service. Here is something for you to enjoy. + + Objectives.Add( new CollectObjective( 50, typeof( Bottle ), 1023854 ) ); // empty bottle + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class NecessitysMother : MLQuest + { + public NecessitysMother() + { + Activated = true; + HasRestartDelay = true; + Title = 1073906; // Necessity's Mother + Description = 1074096; // What a thing, this human need to tinker. It seems there is no end to what might be produced with a set of Tinker's Tools. Who knows what an elf might build with some? Could you obtain some tinker's tools and bring them to me? In exchange, I offer you elven lore and knowledge. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073952; // I will be in your debt if you bring me tinker's tools. + CompletionMessage = 1073977; // Now, I shall see what an elf can invent! + + Objectives.Add( new CollectObjective( 10, typeof( TinkerTools ), 1027868 ) ); // tinker's tools + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class TickTock : MLQuest + { + public TickTock() + { + Activated = true; + HasRestartDelay = true; + Title = 1073907; // Tick Tock + Description = 1074097; // Elves find it remarkable the human preoccupation with the passage of time. To have built instruments to try and capture time -- it is a fascinating notion. I would like to see how a clock is put together. Maybe you could provide some clocks for my experimentation? + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073953; // I will be in your debt if you bring me clocks. + CompletionMessage = 1073978; // Enjoy my thanks for your service. + + Objectives.Add( new CollectObjective( 10, typeof( Clock ), 1024171 ) ); // clock + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class ReptilianDentist : MLQuest + { + public ReptilianDentist() + { + Activated = true; + Title = 1074280; // Reptilian Dentist + Description = 1074710; // I'm working on a striking necklace -- something really unique -- and I know just what I need to finish it up. A huge fang! Won't that catch the eye? I would like to employ you to find me such an item, perhaps a snake would make the ideal donor. I'll make it worth your while, of course. + RefusalMessage = 1074723; // I understand. I don't like snakes much either. They're so creepy. + InProgressMessage = 1074722; // Those really big snakes like swamps, I've heard. You might try the blighted grove. + CompletionMessage = 1074721; // Do you have it? *gasp* What a tooth! Here � I must get right to work. + + Objectives.Add( new CollectObjective( 1, typeof( CoilsFang ), "coil's fang" ) ); + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class StopHarpingOnMe : MLQuest + { + public StopHarpingOnMe() + { + Activated = true; + HasRestartDelay = true; + Title = 1073881; // Stop Harping on Me + Description = 1074071; // Humans artistry can be a remarkable thing. For instance, I have heard of a wonderful instrument which creates the most melodious of music. A lap harp. I would be ever so grateful if I could examine one in person. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073927; // I will be in your debt if you bring me lap harp. + CompletionMessage = 1073969; // My thanks for your service. Now, I will show you something of elven carpentry. + + Objectives.Add( new CollectObjective( 20, typeof( LapHarp ), 1023762 ) ); // lap harp + + Rewards.Add( ItemReward.CarpentrySatchel ); + } + } + + public class TheFarEye : MLQuest + { + public TheFarEye() + { + Activated = true; + HasRestartDelay = true; + Title = 1073908; // The Far Eye + Description = 1074098; // The wonders of human invention! Turning sand and metal into a far-seeing eye! This is something I must experience for myself. Bring me some of these spyglasses friend human. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073954; // I will be in your debt if you bring me spyglasses. + CompletionMessage = 1073978; // Enjoy my thanks for your service. + + Objectives.Add( new CollectObjective( 20, typeof( Spyglass ), 1025365 ) ); // spyglass + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class LethalDarts : MLQuest + { + public LethalDarts() + { + Activated = true; + HasRestartDelay = true; + Title = 1073876; // Lethal Darts + Description = 1074066; // We elves are no strangers to archery but I would be interested in learning whether there is anything to learn from the human approach. I would gladly trade you something I have if you could teach me of the deadly crossbow bolt. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073922; // I will be in your debt if you bring me crossbow bolts. + CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery. + CompletionNotice = CompletionNoticeCraft; + + Objectives.Add( new CollectObjective( 10, typeof( Bolt ), 1027163 ) ); // crossbow bolt + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class ASimpleBow : MLQuest + { + public ASimpleBow() + { + Activated = true; + HasRestartDelay = true; + Title = 1073877; // A Simple Bow + Description = 1074067; // I wish to try a bow crafted in the human style. Is it possible for you to bring me such a weapon? I would be happy to return this favor. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073923; // I will be in your debt if you bring me bows. + CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery. + CompletionNotice = CompletionNoticeCraft; + + Objectives.Add( new CollectObjective( 10, typeof( Bow ), 1025041 ) ); // bow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class IngeniousArcheryPartOne : MLQuest + { + public IngeniousArcheryPartOne() + { + Activated = true; + HasRestartDelay = true; + Title = 1073878; // Ingenious Archery, Part I + Description = 1074068; // I have heard of a curious type of bow, you call it a "crossbow". It sounds fascinating and I would very much like to examine one closely. Would you be able to obtain such an instrument for me? + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073924; // I will be in your debt if you bring me crossbows. + CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery. + CompletionNotice = CompletionNoticeCraft; + + Objectives.Add( new CollectObjective( 10, typeof( Crossbow ), 1023919 ) ); // crossbow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class IngeniousArcheryPartTwo : MLQuest + { + public IngeniousArcheryPartTwo() + { + Activated = true; + HasRestartDelay = true; + Title = 1073879; // Ingenious Archery, Part II + Description = 1074069; // These human "crossbows" are complex and clever. The "heavy crossbow" is a remarkable instrument of war. I am interested in seeing one up close, if you could arrange for one to make its way to my hands. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073925; // I will be in your debt if you bring me heavy crossbows. + CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery. + CompletionNotice = CompletionNoticeCraft; + + Objectives.Add( new CollectObjective( 8, typeof( HeavyCrossbow ), 1025116 ) ); // heavy crossbow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class IngeniousArcheryPartThree : MLQuest + { + public IngeniousArcheryPartThree() + { + Activated = true; + HasRestartDelay = true; + Title = 1073880; // Ingenious Archery, Part III + Description = 1074070; // My friend, I am in search of a device, a instrument of remarkable human ingenuity. It is a repeating crossbow. If you were to obtain such a device, I would gladly reveal to you some of the secrets of elven craftsmanship. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073926; // I will be in your debt if you bring me repeating crossbows. + CompletionMessage = 1073968; // My thanks for your service. Now, I shall teach you of elven archery. + CompletionNotice = CompletionNoticeCraft; + + Objectives.Add( new CollectObjective( 10, typeof( RepeatingCrossbow ), 1029923 ) ); // repeating crossbow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class ScaleArmor : MLQuest + { + public ScaleArmor() + { + Activated = true; + Title = 1074711; // Scale Armor + Description = 1074712; // Here's what I need ... there are some creatures called hydra, fearsome beasts, whose scales are especially suitable for a new sort of armor that I'm developing. I need a few such pieces and then some supple alligator skin for the backing. I'm going to need a really large piece that's shaped just right ... the tail I think would do nicely. I appreciate your help. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1074724; // Hydras have been spotted in the Blighted Grove. You won't get those scales without getting your feet wet, I'm afraid. + CompletionMessage = 1074725; // I can't wait to get to work now that you've returned with my scales. + + Objectives.Add( new CollectObjective( 1, typeof( ThrashersTail ), "Thrasher's Tail" ) ); + Objectives.Add( new CollectObjective( 10, typeof( HydraScale ), "Hydra Scales" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class CutsBothWays : MLQuest + { + public CutsBothWays() + { + Activated = true; + HasRestartDelay = true; + Title = 1073913; // Cuts Both Ways + Description = 1074103; // What would you say is a typical human instrument of war? Is a broadsword a typical example? I wish to see more of such human weapons, so I would gladly trade elven knowledge for human steel. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073959; // I will be in your debt if you bring me broadswords. + CompletionMessage = 1073978; // Enjoy my thanks for your service. + + Objectives.Add( new CollectObjective( 12, typeof( Broadsword ), 1023934 ) ); // broadsword + + Rewards.Add( ItemReward.BlacksmithSatchel ); + } + } + + public class DragonProtection : MLQuest + { + public DragonProtection() + { + Activated = true; + HasRestartDelay = true; + Title = 1073915; // Dragon Protection + Description = 1074105; // Mankind, I am told, knows how to take the scales of a terrible dragon and forge them into powerful armor. Such a feat of craftsmanship! I would give anything to view such a creation - I would even teach some of the prize secrets of the elven people. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073961; // I will be in your debt if you bring me dragon armor. + CompletionMessage = 1073978; // Enjoy my thanks for your service. + + Objectives.Add( new CollectObjective( 10, typeof( DragonHelm ), 1029797 ) ); // dragon helm + + Rewards.Add( ItemReward.BlacksmithSatchel ); + } + } + + public class NothingFancy : MLQuest + { + public NothingFancy() + { + Activated = true; + HasRestartDelay = true; + Title = 1073911; // Nothing Fancy + Description = 1074101; // I am curious to see the results of human blacksmithing. To examine the care and quality of a simple item. Perhaps, a simple bascinet helmet? Yes, indeed -- if you could bring to me some bascinet helmets, I would demonstrate my gratitude. + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073957; // I will be in your debt if you bring me bascinets. + CompletionMessage = 1073978; // Enjoy my thanks for your service. + + Objectives.Add( new CollectObjective( 15, typeof( Bascinet ), 1025132 ) ); // bascinet + + Rewards.Add( ItemReward.BlacksmithSatchel ); + } + } + + public class TheBulwark : MLQuest + { + public TheBulwark() + { + Activated = true; + HasRestartDelay = true; + Title = 1073912; // The Bulwark + Description = 1074102; // The clank of human iron and steel is strange to elven ears. For instance, the metallic heater shield which human warriors carry into battle. It is odd to an elf, but nevertheless intriguing. Tell me friend, could you bring me such an example of human smithing skill? + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073958; // I will be in your debt if you bring me heater shields. + CompletionMessage = 1073978; // Enjoy my thanks for your service. + + Objectives.Add( new CollectObjective( 10, typeof( HeaterShield ), 1027030 ) ); // heater shield + + Rewards.Add( ItemReward.BlacksmithSatchel ); + } + } + + public class ArchSupport : MLQuest + { + public ArchSupport() + { + Activated = true; + HasRestartDelay = true; + Title = 1073882; // Arch Support + Description = 1074072; // How clever humans are - to understand the need of feet to rest from time to time! Imagine creating a special stool just for weary toes. I would like to examine and learn the secret of their making. Would you bring me some foot stools to examine? + RefusalMessage = 1073921; // I will patiently await your reconsideration. + InProgressMessage = 1073928; // I will be in your debt if you bring me foot stools. + CompletionMessage = 1073969; // My thanks for your service. Now, I will show you something of elven carpentry. + + Objectives.Add( new CollectObjective( 10, typeof( FootStool ), 1022910 ) ); // foot stool + + Rewards.Add( ItemReward.CarpentrySatchel ); + } + } + + public class ParoxysmusSuccubi : MLQuest + { + public ParoxysmusSuccubi() + { + Activated = true; + Title = 1073067; // Paroxysmus' Succubi + Description = 1074696; // The succubi that have congregated within the sinkhole to worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( Succubus ) }, "succubi", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class ParoxysmusMoloch : MLQuest + { + public ParoxysmusMoloch() + { + Activated = true; + Title = 1073068; // Paroxysmus' Moloch + Description = 1074695; // The moloch daemons that have congregated to worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( Moloch ) }, "molochs", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class ParoxysmusDaemons : MLQuest + { + public ParoxysmusDaemons() + { + Activated = true; + Title = 1073069; // Paroxysmus' Daemons + Description = 1074694; // The daemons that have congregated to worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Daemon ) }, "daemons", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class ParoxysmusArcaneDaemons : MLQuest + { + public ParoxysmusArcaneDaemons() + { + Activated = true; + Title = 1073070; // Paroxysmus' Arcane Daemons + Description = 1074697; // The arcane daemons that worship Paroxysmus pose a tremendous danger. Will you enter the lair and see to their destruction? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( ArcaneDaemon ) }, "arcane daemons", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class CausticCombo : MLQuest + { + public CausticCombo() + { + Activated = true; + Title = 1073062; // Caustic Combo + Description = 1074693; // Vile creatures have exited the sinkhole and begun terrorizing the surrounding area. The demons are bad enough, but the elementals are an abomination, their poisons seeping into the fertile ground here. Will you enter the sinkhole and put a stop to their depredations? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( PoisonElemental ) }, "poison elementals", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + Objectives.Add( new KillObjective( 6, new Type[] { typeof( AcidElemental ) }, "acid elementals", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class PlagueLord : MLQuest + { + public PlagueLord() + { + Activated = true; + Title = 1073061; // Plague Lord + Description = 1074692; // Some of the most horrific creatures have slithered out of the sinkhole there and begun terrorizing the surrounding area. The plague creatures are one of the most destruction of the minions of Paroxysmus. Are you willing to do something about them? + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( PlagueSpawn ) }, "plague spawns", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + Objectives.Add( new KillObjective( 3, new Type[] { typeof( PlagueBeast ) }, "plague beasts", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + Objectives.Add( new KillObjective( 1, new Type[] { typeof( PlagueBeastLord ) }, "plague beast lord", new QuestArea( 1074806, "The Palace of Paroxysmus" ) ) ); // The Palace of Paroxysmus + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class GlassyFoe : MLQuest + { + public GlassyFoe() + { + Activated = true; + Title = 1073055; // Glassy Foe + Description = 1074669; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal lattice seekers. + RefusalMessage = 1074671; // These abominations must not be permitted to fester! + InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live. + CompletionMessage = 1074673; // You have done well. Enjoy this reward. + + Objectives.Add( new KillObjective( 5, new Type[] { typeof( CrystalLatticeSeeker ) }, "crystal lattice seekers", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class DaemonicPrism : MLQuest + { + public DaemonicPrism() + { + Activated = true; + Title = 1073053; // Daemonic Prism + Description = 1074668; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal daemons. + RefusalMessage = 1074671; // These abominations must not be permitted to fester! + InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live. + CompletionMessage = 1074673; // You have done well. Enjoy this reward. + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( CrystalDaemon ) }, "crystal daemons", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class Hailstorm : MLQuest + { + public Hailstorm() + { + Activated = true; + Title = 1073057; // Hailstorm + Description = 1074670; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal vortices. + RefusalMessage = 1074671; // These abominations must not be permitted to fester! + InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live. + CompletionMessage = 1074673; // You have done well. Enjoy this reward. + + Objectives.Add( new KillObjective( 8, new Type[] { typeof( CrystalVortex ) }, "crystal vortices", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + /* TODO: Uncomment when Crystal Hydra is added + public class HowManyHeads : MLQuest + { + public HowManyHeads() + { + Activated = true; + Title = 1073050; // How Many Heads? + Description = 1074674; // Good, you're here. The presence of a twisted creature deep under the earth near Nu'Jelm has corrupted the natural growth of crystals in that region. They've become infused with the twisting energy - they've come to a sort of life. This is an abomination that festers within Sosaria. You must eradicate the crystal hydras. + RefusalMessage = 1074671; // These abominations must not be permitted to fester! + InProgressMessage = 1074672; // You must not waste time. Do not suffer these crystalline abominations to live. + CompletionMessage = 1074673; // You have done well. Enjoy this reward. + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( CrystalHydra ) }, "crystal hydras", new QuestArea( 1074805, "The Prism of Light" ) ) ); // The Prism of Light + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + */ + + /* TODO: Uncomment when Dreadhorn is added + public class DreadhornQuest : MLQuest + { + public DreadhornQuest() + { + Activated = true; + Title = 1074645; // Dreadhorn + Description = 1074646; // Can you comprehend it? I cannot, I confess. The most pristine and perfect Lord of Sosaria has fallen prey to the blight. From the depths of my heart I mourn his corruption; my thoughts are filled with pity for this glorious creature now tainted. And my blood boils with fury at those responsible for the innocent creature's undoing. Will you find Dread Horn, as he is now called, and free him from this misery? + RefusalMessage = 1074647; // How can you not feel as I do? + InProgressMessage = 1074648; // The lush and fertile land where Dread Horn now lives is twisted and tainted, a result of his corruption. The fey folk have sealed the land off through their magics, but you can enter through an enchanted mushroom fairy circle. + CompletionMessage = 1074649; // Thank you. I haven't the words to express my gratitude. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( DreadHorn ) }, "dread horn" ) ); + + Rewards.Add( ItemReward.RewardStrongbox ); + } + } + */ + + /* TODO: Uncomment when SerpentsFangHighExecutioner, TigersClawThief and DragonsFlameGrandMage are added + public class NewLeadership : MLQuest + { + public NewLeadership() + { + Activated = true; + Title = 1072905; // New Leadership + Description = 1072963; // I have a task for you ... adventurer. Will you risk all to win great renown? The Black Order is organized into three sects, each with their own speciality. The Dragon's Flame serves the will of the Grand Mage, the Tiger's Claw answers to the Master Thief, and the Serpent's Fang kills at the direction of the High Executioner. Slay all three and you will strike the order a devastating blow! + RefusalMessage = 1072973; // I do not fault your decision. + InProgressMessage = 1072974; // Once you gain entrance into The Citadel, you will need to move cautiously to find the sect leaders. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( SerpentsFangHighExecutioner ) }, "serpent's fang high executioner", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + Objectives.Add( new KillObjective( 1, new Type[] { typeof( TigersClawThief ) }, "tiger's claw thief", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + Objectives.Add( new KillObjective( 1, new Type[] { typeof( DragonsFlameGrandMage ) }, "dragon's flame mage", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + + Rewards.Add( ItemReward.RewardStrongbox ); + } + } + */ + + /* TODO: Uncomment when SerpentsFangAssassin is added + public class ExAssassins : MLQuest + { + public ExAssassins() + { + Activated = true; + Title = 1072917; // Ex-Assassins + Description = 1072969; // The Serpent's Fang sect members have gone too far! Express to them my displeasure by slaying ten of them. But remember, I do not condone war on women, so I will only accept the deaths of men, human and elf. + RefusalMessage = 1072979; // As you wish. + InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal. + + // TODO: This has to be MALES only! + Objectives.Add( new KillObjective( 10, new Type[] { typeof( SerpentsFangAssassin ) }, "male serpent's fang assassins", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + */ + + /* TODO: Uncomment when DragonsFlameMage is added + public class ExtinguishingTheFlame : MLQuest + { + public ExtinguishingTheFlame() + { + Activated = true; + Title = 1072911; // Extinguishing the Flame + Description = 1072966; // The Dragon's Flame sect members have gone too far! Express to them my displeasure by slaying ten of them. But remember, I do not condone war on women, so I will only accept the deaths of men, human or elf. Either race will do, I care not for the shape of their ears. Yes, this action will properly make clear my disapproval and has a pleasing harmony. + RefusalMessage = 1072979; // As you wish. + InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal. + + // TODO: This has to be MALES only! + Objectives.Add( new KillObjective( 10, new Type[] { typeof( DragonsFlameMage ) }, "male dragon's flame mages", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + */ + + public class DeathToTheNinja : MLQuest + { + public DeathToTheNinja() + { + Activated = true; + Title = 1072913; // Death to the Ninja! + Description = 1072966; // I wish to make a statement of censure against the elite ninjas of the Black Order. Deliver, in the strongest manner, my disdain. But do not make war on women, even those that take arms against you. It is not ... fitting. + RefusalMessage = 1072979; // As you wish. + InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal. + + // TODO: Verify that this has to be males only (as per the description) + Objectives.Add( new KillObjective( 10, new Type[] { typeof( EliteNinja ) }, "elite ninjas", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + /* TODO: Uncomment when TigersClawThief is added + public class CrimeAndPunishment : MLQuest + { + public CrimeAndPunishment() + { + Activated = true; + Title = 1072914; // Crime and Punishment + Description = 1072968; // The Tiger's Claw sect members have gone too far! Express to them my displeasure by slaying ten of them. But remember, I do not condone war on women, so I will only accept the deaths of men, human and elf. + RefusalMessage = 1072979; // As you wish. + InProgressMessage = 1072980; // The Black Order's fortress home is well hidden. Legend has it that a humble fishing village disguises the magical portal. + + // TODO: This has to be MALES only! + Objectives.Add( new KillObjective( 10, new Type[] { typeof( TigersClawThief ) }, "male tiger's claw thieves", new QuestArea( 1074804, "The Citadel" ) ) ); // The Citadel + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + */ + + /* TODO: Uncomment when ShimmeringEffusion is added + public class AllThatGlittersIsNotGood : MLQuest + { + public AllThatGlittersIsNotGood() + { + Activated = true; + Title = 1073048; // All That Glitters is Not Good + Description = 1074654; // The most incredible tale has reached my ears! Deep within the bowels of Sosaria, somewhere under the city of Nu'Jelm, a twisted creature feeds. What created this abomination, no one knows ... though there is some speculation that the fumbling initial efforts to open the portal to The Heartwood, brought it into existence. Regardless of it's origin, it must be destroyed before it damages Sosaria. Will you undertake this quest? + RefusalMessage = 1074655; // Perhaps I thought too highly of you. + InProgressMessage = 1074656; // An explorer discovered the cave system under Nu'Jelm. He made multiple trips into the place bringing back fascinating crystals and artifacts that suggested the hollow place in Sosaria was inhabited by other creatures at some point. You'll need to follow in his footsteps to find this abomination and destroy it. + CompletionMessage = 1074657; // I am overjoyed with your efforts! Your devotion to Sosaria is noted and appreciated. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( ShimmeringEffusion ) }, "shimmering effusion" ) ); + + Rewards.Add( ItemReward.RewardStrongbox ); + } + } + */ + + #endregion + + #region Mobiles + + [QuesterName( "Saril (The Heartwood)" )] + public class Saril : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074186, // Come here, I have a task. + 1074183 // You there! I have a job for you. + ) ); + } + + [Constructable] + public Saril() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Saril"; + Title = "the guard"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new WoodlandLegs() ); + AddItem( new WoodlandArms() ); + AddItem( new WoodlandBelt() ); + AddItem( new WingedHelm() ); + AddItem( new FemaleElvenPlateChest() ); + AddItem( new RadiantScimitar() ); + } + + public Saril( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Cailla (The Heartwood)" )] + public class Cailla : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074187, // Want a job? + 1074210 // Hi.� Looking for something to do? + ) ); + } + + [Constructable] + public Cailla() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Cailla"; + Title = "the guard"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new HidePants() ); + AddItem( new HidePauldrons() ); + AddItem( new HideGloves() ); + AddItem( new WoodlandBelt() ); + AddItem( new RavenHelm() ); + AddItem( new HideFemaleChest() ); + AddItem( new MagicalShortbow() ); + } + + public Cailla( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Tamm (The Heartwood)" )] + public class Tamm : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074213, // Hey buddy.� Looking for work? + 1074187 // Want a job? + ) ); + } + + [Constructable] + public Tamm() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tamm"; + Title = "the guard"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new HidePants() ); + AddItem( new HidePauldrons() ); + AddItem( new WingedHelm() ); + AddItem( new HideChest() ); + AddItem( new ElvenCompositeLongbow() ); + } + + public Tamm( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Landy (The Heartwood)" )] + public class Landy : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074211, // I could use some help. + 1074218 // Hey!� I want to talk to you, now. + ) ); + } + + [Constructable] + public Landy() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Landy"; + Title = "the soil nurturer"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( Utility.RandomYellowHue() ) ); + AddItem( new ShortPants( Utility.RandomYellowHue() ) ); + AddItem( new Tunic( Utility.RandomYellowHue() ) ); + + Item gloves = new LeafGloves(); + gloves.Hue = Utility.RandomYellowHue(); + AddItem( gloves ); + } + + public Landy( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Elder Alejaha (The Heartwood)" )] + public class Alejaha : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074223 ); // Have you done it yet?� Oh, I haven�t told you, have I? + } + + [Constructable] + public Alejaha() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Alejaha"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( Utility.RandomYellowHue() ) ); + AddItem( new ElvenShirt( Utility.RandomYellowHue() ) ); + AddItem( new GemmedCirclet() ); + AddItem( new Cloak( Utility.RandomBrightHue() ) ); + + if ( Utility.RandomBool() ) + AddItem( new Kilt( 0x387 ) ); + else + AddItem( new Skirt( 0x387 ) ); + } + + public Alejaha( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Mielan (The Heartwood)" )] + public class Mielan : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074219, // Hello there, can I have a moment of your time? + 1074223 // Have you done it yet?� Oh, I haven�t told you, have I? + ) ); + } + + [Constructable] + public Mielan() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Mielan"; + Title = "the arcanist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new ElvenShirt( 0x56 ) ); + AddItem( new GemmedCirclet() ); + AddItem( new ElvenPants( 0x901 ) ); + } + + public Mielan( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Ciala (The Heartwood)" )] + public class Ciala : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074206, // Excuse me please traveler, might I have a little of your time? + 1074186 // Come here, I have a task. + ) ); + } + + [Constructable] + public Ciala() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Ciala"; + Title = "the arborist"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Skirt( Utility.RandomBlueHue() ) ); + AddItem( new ElvenShirt( Utility.RandomYellowHue() ) ); + AddItem( new RoyalCirclet() ); + + if ( Utility.RandomBool() ) + AddItem( new Boots( Utility.RandomYellowHue() ) ); + else + AddItem( new ThighBoots( Utility.RandomYellowHue() ) ); + } + + public Ciala( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Aniel (The Heartwood)" )] + public class Aniel : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074220, // May I call you friend?� I have a favor to beg of you. + 1074222 // Could I trouble you for some assistance? + ) ); + } + + [Constructable] + public Aniel() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Aniel"; + Title = "the arborist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenPants( 0x901 ) ); + AddItem( new LeafChest() ); + AddItem( new HalfApron( Utility.RandomYellowHue() ) ); + AddItem( new ElvenBoots( 0x901 ) ); + } + + public Aniel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Aulan (The Heartwood)" )] + public class Aulan : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074188, // Weakling! You are not up to the task I have. + 1074191, // Just keep walking away!� I thought so. Coward!� I�ll bite your legs off! + 1074195 // You there, in the stupid hat! Come here. + ) ); + } + + [Constructable] + public Aulan() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Aulan"; + Title = "the expeditionist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + Item item; + + item = new ElvenBoots(); + item.Hue = Utility.RandomYellowHue(); + AddItem( item ); + + AddItem( new ElvenPants( Utility.RandomGreenHue() ) ); + AddItem( new Cloak( Utility.RandomGreenHue() ) ); + AddItem( new Circlet() ); + + item = new HideChest(); + item.Hue = Utility.RandomYellowHue(); + AddItem( item ); + + item = new HideGloves(); + item.Hue = Utility.RandomYellowHue(); + AddItem( item ); + } + + public Aulan( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Brinnae (The Heartwood)" )] + public class Brinnae : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074212, // *yawn* You busy? + 1074210 // Hi.� Looking for something to do? + ) ); + } + + [Constructable] + public Brinnae() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Brinnae"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots() ); + AddItem( new FemaleLeafChest() ); + AddItem( new LeafArms() ); + AddItem( new HidePants() ); + AddItem( new ElvenCompositeLongbow() ); + } + + public Brinnae( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Elder Caelas (The Heartwood)" )] + public class Caelas : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074204, // Greetings seeker.� I have an urgent matter for you, if you are willing. + 1074201 // Waste not a minute! There�s work to be done. + ) ); + } + + [Constructable] + public Caelas() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Caelas"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new MaleElvenRobe( 0x489 ) ); + AddItem( new Cloak( 0x718 ) ); + AddItem( new RoyalCirclet() ); + } + + public Caelas( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Clehin (The Heartwood)" )] + public class Clehin : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074211, // I could use some help. + 1074186 // Come here, I have a task. + ) ); + } + + [Constructable] + public Clehin() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Clehin"; + Title = "the soil nurturer"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new ElvenShirt() ); + AddItem( new LeafTonlet() ); + } + + public Clehin( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Cloorne : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074185, // Hey you! Want to help me out? + 1074186 //Come here, I have a task. + ) ); + } + + [Constructable] + public Cloorne() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Cloorne"; + Title = "the expeditionist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x3B2 ) ); + AddItem( new RadiantScimitar() ); + AddItem( new WingedHelm() ); + + Item item; + + item = new WoodlandLegs(); + item.Hue = 0x74A; + AddItem( item ); + + item = new HideChest(); + item.Hue = 0x726; + AddItem( item ); + + item = new LeafArms(); + item.Hue = 0x73E; + AddItem( item ); + } + + public Cloorne( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Salaenih (The Heartwood)" )] + public class Salaenih : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074207, // Good day to you friend! Allow me to offer you a fabulous opportunity!� Thrills and adventure await! + 1074209 // Hey, could you help me out with something? + ) ); + } + + [Constructable] + public Salaenih() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Salaenih"; + Title = "the expeditionist"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new WarCleaver() ); + + Item item; + + item = new WoodlandBelt(); + item.Hue = 0x597; + AddItem( item ); + + item = new VultureHelm(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new WoodlandLegs(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new WoodlandChest(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new WoodlandArms(); + item.Hue = 0x1BB; + AddItem( item ); + } + + public Salaenih( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Vilo (The Heartwood)" )] + public class Vilo : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074210, // Hi.� Looking for something to do? + 1074220 // May I call you friend?� I have a favor to beg of you. + ) ); + } + + [Constructable] + public Vilo() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Vilo"; + Title = "the guard"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new OrnateAxe() ); + AddItem( new WoodlandBelt( 0x592 ) ); + AddItem( new VultureHelm() ); + AddItem( new WoodlandLegs() ); + AddItem( new WoodlandChest() ); + AddItem( new WoodlandArms() ); + AddItem( new WoodlandGorget() ); + } + + public Vilo( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Tholef (The Heartwood)" )] + public class Tholef : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074209, // Hey, could you help me out with something? + 1074184 // Come here, I have work for you. + ) ); + } + + [Constructable] + public Tholef() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tholef"; + Title = "the grape tender"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x901 ) ); + AddItem( new FullApron( 0x756 ) ); + AddItem( new ShortPants( 0x28C ) ); + AddItem( new Shirt( 0x28C ) ); + + Item item; + + item = new LeafArms(); + item.Hue = 0x28C; + AddItem( item ); + } + + public Tholef( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Tillanil (The Heartwood)" )] + public class Tillanil : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074187, // Want a job? + 1074222 // Could I trouble you for some assistance? + ) ); + } + + [Constructable] + public Tillanil() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tillanil"; + Title = "the grape tender"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x1BB ) ); + AddItem( new Tunic( 0x759 ) ); + AddItem( new ShortPants( 0x21 ) ); + } + + public Tillanil( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Waelian (The Heartwood)" )] + public class Waelian : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074221, // Greetings!� I have a small task for you good traveler. + 1074201 // Waste not a minute! There�s work to be done. + ) ); + } + + [Constructable] + public Waelian() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Waelian"; + Title = "the trinket weaver"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Shoes( 0x901 ) ); + AddItem( new SmithHammer() ); + AddItem( new LongPants( 0x340 ) ); + AddItem( new GemmedCirclet() ); + + Item item; + + item = new LeafChest(); + item.Hue = 0x344; + AddItem( item ); + } + + public Waelian( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Sleen (The Heartwood)" )] + public class Sleen : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074200, // Thank goodness you are here, there�s no time to lose. + 1074206 // Excuse me please traveler, might I have a little of your time? + ) ); + } + + [Constructable] + public Sleen() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Sleen"; + Title = "the trinket weaver"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new SmithHammer() ); + AddItem( new Cloak( 0x75A ) ); + AddItem( new ElvenShirt() ); + } + + public Sleen( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Unoelil (The Heartwood)" )] + public class Unoelil : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074186, // Come here, I have a task. + 1074209 // Hey, could you help me out with something? + ) ); + } + + [Constructable] + public Unoelil() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Unoelil"; + Title = "the bark weaver"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new ShortPants( 0x1BB ) ); + AddItem( new Tunic( 0x64D ) ); + } + + public Unoelil( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Anolly (The Heartwood)" )] + public class Anolly : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + [Constructable] + public Anolly() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Anolly"; + Title = "the bark weaver"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x901 ) ); + AddItem( new ShortPants( 0x3B3 ) ); + AddItem( new FullApron( 0x1BB ) ); + AddItem( new SmithHammer() ); + } + + public Anolly( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Jusae (The Heartwood)" )] + public class Jusae : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074210, // Hi.� Looking for something to do? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Jusae() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Jusae"; + Title = "the bowcrafter"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x901 ) ); + AddItem( new ShortPants( 0x661 ) ); + AddItem( new MagicalShortbow() ); + + Item item; + + item = new HideChest(); + item.Hue = 0x27B; + AddItem( item ); + + item = new HidePauldrons(); + item.Hue = 0x27E; + AddItem( item ); + } + + public Jusae( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Cillitha (The Heartwood)" )] + public class Cillitha : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074223, // Have you done it yet?� Oh, I haven�t told you, have I? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Cillitha() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Cillitha"; + Title = "the bowcrafter"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new ElvenShirt( 0x731 ) ); + AddItem( new LeafLegs() ); + } + + public Cillitha( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Lohn (The Heartwood)" )] + public class Lohn : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074187, // Want a job? + 1074209 // Hey, could you help me out with something? + ) ); + } + + [Constructable] + public Lohn() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lohn"; + Title = "the metal weaver"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Shoes( 0x901 ) ); + AddItem( new LongPants( 0x359 ) ); + AddItem( new SmithHammer() ); + AddItem( new GemmedCirclet() ); + + Item item; + + item = new LeafChest(); + item.Hue = 0x359; + AddItem( item ); + } + + public Lohn( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Olla (The Heartwood)" )] + public class Olla : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074187, // Want a job? + 1074185 // Hey you! Want to help me out? + ) ); + } + + [Constructable] + public Olla() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Olla"; + Title = "the metal weaver"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new LongPants( 0x3B3 ) ); + AddItem( new SmithHammer() ); + AddItem( new FullApron( 0x1BB ) ); + AddItem( new ElvenShirt() ); + + } + + public Olla( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Thallary (The Heartwood)" )] + public class Thallary : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074221, // Greetings!� I have a small task for you good traveler. + 1074212 // *yawn* You busy? + ) ); + } + + [Constructable] + public Thallary() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Thallary"; + Title = "the cloth weaver"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x901 ) ); + AddItem( new LongPants( 0x72E ) ); + AddItem( new Cloak( 0x3B3 ) ); + AddItem( new FancyShirt( 0x13 ) ); + + } + + public Thallary( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Ahie (The Heartwood)" )] + public class Ahie : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074206, // Excuse me please traveler, might I have a little of your time? + 1074203 // Hello friend. I realize you are busy but if you would be willing to render me a service I can assure you that you will be judiciously renumerated. + ) ); + } + + [Constructable] + public Ahie() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Ahie"; + Title = "the cloth weaver"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Boots( 0x901 ) ); + AddItem( new Skirt( 0x1C ) ); + AddItem( new Cloak( 0x62 ) ); + AddItem( new FancyShirt( 0x738 ) ); + + } + + public Ahie( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Tyeelor : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Tyeelor() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tyeelor"; + Title = "the expeditionist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x1BB ) ); + + Item item; + + item = new WoodlandLegs(); + item.Hue = 0x236; + AddItem( item ); + + item = new WoodlandChest(); + item.Hue = 0x236; + AddItem( item ); + + item = new WoodlandArms(); + item.Hue = 0x236; + AddItem( item ); + + item = new VultureHelm(); + item.Hue = 0x236; + AddItem( item ); + + item = new WoodlandBelt(); + item.Hue = 0x236; + AddItem( item ); + + } + + public Tyeelor( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Athailon : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Athailon() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Athailon"; + Title = "the expeditionist"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new WoodlandBelt() ); + AddItem( new DiamondMace() ); + + Item item; + + item = new WoodlandLegs(); + item.Hue = 0x3B2; + AddItem( item ); + + item = new FemaleElvenPlateChest(); + item.Hue = 0x3B2; + AddItem( item ); + + item = new WoodlandArms(); + item.Hue = 0x3B2; + AddItem( item ); + + item = new WingedHelm(); + item.Hue = 0x3B2; + AddItem( item ); + + } + + public Athailon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElderTaellia : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public ElderTaellia() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Taellia"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ThighBoots( 0x127 ) ); + AddItem( new FemaleElvenRobe( Utility.RandomBrightHue() ) ); + AddItem( new MagicWand() ); + AddItem( new Circlet() ); + + } + + public ElderTaellia( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElderMallew : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public ElderMallew() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Mallew"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new Cloak( 0x3B2 ) ); + AddItem( new Circlet() ); + + Item item; + + item = new LeafTonlet(); + item.Hue = 0x544; + AddItem( item ); + + item = new LeafChest(); + item.Hue = 0x538; + AddItem( item ); + + item = new LeafArms(); + item.Hue = 0x528; + AddItem( item ); + + } + + public ElderMallew( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElderAbbein : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public ElderAbbein() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Abbein"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x72C ) ); + AddItem( new FemaleElvenRobe( 0x8B0 ) ); + AddItem( new RoyalCirclet() ); + + } + + public ElderAbbein( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElderVicaie : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public ElderVicaie() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Vicaie"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots() ); + AddItem( new Tunic( 0x732 ) ); + + Item item; + + item = new LeafLegs(); + item.Hue = 0x3B2; + AddItem( item ); + + } + + public ElderVicaie( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElderJothan : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public ElderJothan() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Jothan"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ThighBoots() ); + AddItem( new ElvenPants( 0x58D ) ); + AddItem( new ElvenShirt( Utility.RandomYellowHue() ) ); + AddItem( new Cloak( Utility.RandomBrightHue() ) ); + AddItem( new Circlet() ); + + } + + public ElderJothan( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElderAlethanian : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public ElderAlethanian() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Alethanian"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots() ); + AddItem( new HidePants() ); + AddItem( new HideFemaleChest() ); + AddItem( new HidePauldrons() ); + AddItem( new GemmedCirclet() ); + + } + + public ElderAlethanian( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Rebinil : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Rebinil() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Rebinil"; + Title = "the healer"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Sandals( 0x715 ) ); + AddItem( new FemaleElvenRobe( 0x742 ) ); + AddItem( new RoyalCirclet() ); + + } + + public Rebinil( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Aluniol : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Aluniol() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Aluniol"; + Title = "the healer"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new MaleElvenRobe( 0x47E ) ); + AddItem( new WildStaff() ); + + } + + public Aluniol( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Olaeni : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Olaeni() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Olaeni"; + Title = "the thaumaturgist"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Shoes( 0x75A ) ); + AddItem( new FemaleElvenRobe( 0x13 ) ); + AddItem( new MagicWand() ); + AddItem( new GemmedCirclet() ); + + } + + public Olaeni( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Bolaevin : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Bolaevin() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Bolaevin"; + Title = "the arcanist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x3B2 ) ); + AddItem( new RoyalCirclet() ); + AddItem( new LeafChest() ); + AddItem( new LeafArms() ); + + Item item; + + item = new LeafLegs(); + item.Hue = 0x1BB; + AddItem( item ); + + } + + public Bolaevin( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LorekeeperAneen : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public LorekeeperAneen() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Aneen"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Sandals( 0x1BB ) ); + AddItem( new MaleElvenRobe( 0x48F) ); + AddItem( new MagicWand() ); + + } + + public LorekeeperAneen( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Daelas : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Daelas() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Daelas"; + Title = "the arborist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new ElvenPants( 0x8AB) ); + + Item item; + + item = new LeafChest(); + item.Hue = 0x8B0; + AddItem( item ); + + item = new LeafGloves(); + item.Hue = 0x1BB; + AddItem( item ); + + } + + public Daelas( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Alelle : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Alelle() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Alelle"; + Title = "the arborist"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots( 0x1BB ) ); + + Item item; + + item = new FemaleLeafChest(); + item.Hue = 0x3A; + AddItem( item ); + + item = new LeafLegs(); + item.Hue = 0x74C; + AddItem( item ); + + item = new LeafGloves(); + item.Hue = 0x1BB; + AddItem( item ); + + } + + public Alelle( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Nillaen (The Heartwood)" )] + public class LorekeeperNillaen : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + [Constructable] + public LorekeeperNillaen() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Nillaen"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Shoes( 0x1BB ) ); + AddItem( new LongPants( 0x1FB ) ); + AddItem( new ElvenShirt() ); + AddItem( new GemmedCirclet() ); + AddItem( new BodySash( 0x25 ) ); + AddItem( new BlackStaff() ); + } + + public LorekeeperNillaen( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Ryal (The Heartwood)" )] + public class LorekeeperRyal : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074204, // Greetings seeker.� I have an urgent matter for you, if you are willing. + 1074200 // Thank goodness you are here, there�s no time to lose. + ) ); + } + + [Constructable] + public LorekeeperRyal() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Ryal"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x1BB ) ); + AddItem( new LeafTonlet() ); + AddItem( new ElvenShirt( 0x2DD ) ); + AddItem( new Cloak( 0x219 ) ); + AddItem( new GnarledStaff() ); + } + + public LorekeeperRyal( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Braen (The Heartwood)" )] + public class Braen : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074187 ); // Want a job? + } + + [Constructable] + public Braen() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Braen"; + Title = "the thaumaturgist"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x714 ) ); + AddItem( new MaleElvenRobe( 0x64A ) ); + AddItem( new MagicWand() ); + } + + public Braen( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Elder Acob (The Heartwood)" )] + public class ElderAcob : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074197 ); // Pardon me, but if you could spare some time I�d greatly appreciate it. + } + + [Constructable] + public ElderAcob() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Acob"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x714 ) ); + AddItem( new ElvenShirt( Utility.RandomBrightHue() ) ); + AddItem( new HidePants() ); + } + + public ElderAcob( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LorekeeperCalendor : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074204 ); // Greetings seeker.� I have an urgent matter for you, if you are willing. + } + + [Constructable] + public LorekeeperCalendor() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Calendor"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x714 ) ); + AddItem( new ElvenShirt( Utility.RandomOrangeHue() ) ); + AddItem( new Kilt( Utility.RandomOrangeHue() ) ); + AddItem( new RoyalCirclet() ); + } + + public LorekeeperCalendor( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LorekeeperSiarra : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074206 ); // Excuse me please traveler, might I have a little of your time? + } + + [Constructable] + public LorekeeperSiarra() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Siarra"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x1BB ) ); + AddItem( new ElvenShirt() ); + AddItem( new LeafTonlet() ); + AddItem( new GemmedCirclet() ); + } + + public LorekeeperSiarra( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Heritage.cs b/Scripts/Engines/MLQuests/Definitions/Heritage.cs new file mode 100644 index 0000000..9b7f91a --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Heritage.cs @@ -0,0 +1,798 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Engines.MLQuests.Rewards; +using Server.Engines.MLQuests.Objectives; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Human To Elf Quests + + public class Seasons : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public Seasons() + { + Activated = true; + Title = 1072782; // Seasons + Description = 1072802; // *rumbling growl* *sniff* ... not-smell ... seek-fight ... not-smell ... fear-stench ... *rumble* ... cold-soon-time comes ... hungry ... eat-fish ... sleep-soon-time ... *deep fang-filled yawn* ... much-fish. + RefusalMessage = 1072810; // *yawn* ... cold-soon-time ... *growl* + InProgressMessage = 1072811; // *sniff* *sniff* ... not-much-fish ... hungry ... *grumble* + CompletionMessage = 1074174; // *sniff* fish! much-fish! + + Objectives.Add( new CollectObjective( 20, typeof( RawFishSteak ), 1022426 ) ); // raw fish steak + + Rewards.Add( new DummyReward( 1072803 ) ); // The boon of Maul. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074940, "", 0x2A ); // You have gained the boon of Maul! Your understanding of the seasons grows. You are one step closer to claiming your elven heritage. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Darius" ), new Point3D( 4310, 954, 10 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Darius" ), new Point3D( 4310, 954, 10 ), Map.Trammel ); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "MaulTheBear" ), new Point3D( 1730, 257, 16 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "MaulTheBear" ), new Point3D( 1730, 257, 16 ), Map.Trammel ); + } + } + + public class CaretakerOfTheLand : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public CaretakerOfTheLand() + { + Activated = true; + Title = 1072783; // Caretaker of the Land + Description = 1072812; // Hrrrrr. Hurrrr. Huuuman. *creaking branches* Suuun on baaark, roooooots diiig deeeeeep, wiiind caaaresses leeeaves … Hrrrrr. Saaap of Sooosaria feeeeeeds us. Hrrrrr. Huuuman leeearn. Caaaretaker of plaaants … teeend … prooove.
+ RefusalMessage = 1072813; // Hrrrrr. Hrrrrr. Huuuman. + InProgressMessage = 1072814; // Hrrrr. Hrrrr. Roooooots neeeeeed saaap of Sooosaria. Hrrrrr. Roooooots tiiingle neeeaaar Yeeew. Seeeaaarch. Hrrrr! + CompletionMessage = 1074175; // Thiiirsty. Hurrr. Hurrr. + + Objectives.Add( new CollectObjective( 1, typeof( SapOfSosaria ), "sap of sosaria" ) ); + + Rewards.Add( new DummyReward( 1072804 ) ); // The boon of Strongroot. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074941, "", 0x2A ); // You have gained the boon of Strongroot! You have been approved by one whose roots touch the bones of Sosaria. You are one step closer to claiming your elven heritage. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Strongroot" ), new Point3D( 597, 1744, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Strongroot" ), new Point3D( 597, 1744, 0 ), Map.Trammel ); + + PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromMinutes( 2 ), 0, 12, "SapOfSosaria" ), new Point3D( 757, 1004, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromMinutes( 2 ), 0, 12, "SapOfSosaria" ), new Point3D( 757, 1004, 0 ), Map.Trammel ); + } + } + + public class WisdomOfTheSphynx : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public WisdomOfTheSphynx() + { + Activated = true; + Title = 1072784; // Wisdom of the Sphynx + Description = 1072822; // I greet thee human and divine my boon thou seek. Convey hence the object of my riddle and I shall reward thee with thy desire.

Three lives have I.
Gentle enough to soothe the skin,
Light enough to caress the sky,
Hard enough to crack rocks
What am I? + RefusalMessage = 1072823; // As thou wish, human. + InProgressMessage = 1072824; // I give thee a hint then human. The answer to my riddle must be held carefully or it cannot be contained at all. Bring this elusive item to me in a suitable container. + CompletionMessage = 1074176; // Ah, thus it ends. + + Objectives.Add( new InternalObjective() ); + + Rewards.Add( new DummyReward( 1072805 ) ); // The boon of Enigma. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074945, "", 0x2A ); // You have gained the boon of Enigma! You are wise enough to know how little you know. You are one step closer to claiming your elven heritage. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Enigma" ), new Point3D( 1828, 961, 7 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Enigma" ), new Point3D( 1828, 961, 7 ), Map.Trammel ); + } + + private class InternalObjective : CollectObjective + { + public override bool ShowDetailed { get { return false; } } + + public InternalObjective() + : base( 1, typeof( Pitcher ), 1074869 ) // The answer to the riddle. + { + } + + public override bool CheckItem( Item item ) + { + Pitcher pitcher = item as Pitcher; // Only pitchers work + + return ( pitcher != null && pitcher.Content == BeverageType.Water && pitcher.Quantity > 0 ); + } + } + } + + public class DefendingTheHerd : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public DefendingTheHerd() + { + Activated = true; + Title = 1072785; // Defending the Herd + Description = 1072825; // *snort* ... guard-mates ... guard-herd *hoof stomp* ... defend-with-hoof-and-horn ... thirsty-drink. *proud head-toss* + RefusalMessage = 1072826; // *snort* + InProgressMessage = 1072827; // *impatient hoof stomp* ... thirsty herd ... water scent. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new EscortObjective( new QuestArea( 1074779, "Bravehorn's drinking pool" ) ) ); // Bravehorn's drinking pool + + Rewards.Add( new DummyReward( 1072806 ) ); // The boon of Bravehorn. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074942, "", 0x2A ); // You have gained the boon of Bravehorn! You have glimpsed the nobility of those that sacrifice themselves for their people. You are one step closer to claiming your elven heritage. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromSeconds( 90 ), 0, 5, "Bravehorn" ), new Point3D( 1193, 2467, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 30 ), TimeSpan.FromSeconds( 90 ), 0, 5, "Bravehorn" ), new Point3D( 1193, 2467, 0 ), Map.Trammel ); + + PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 20 ), TimeSpan.FromSeconds( 30 ), 0, 8, "BravehornsMate" ), new Point3D( 1192, 2467, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 20 ), TimeSpan.FromSeconds( 30 ), 0, 8, "BravehornsMate" ), new Point3D( 1192, 2467, 0 ), Map.Trammel ); + } + } + + public class TheBalanceOfNature : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public TheBalanceOfNature() + { + Activated = true; + Title = 1072786; // The Balance of Nature + Description = 1072829; // Ho, there human. Why do you seek out the Huntsman? The hunter serves the land by culling both predators and prey. The hunter maintains the essential balance of life and does not kill for sport or glory. If you seek my favor, human, then demonstrate you are capable of the duty. Cull the wolves nearby. + RefusalMessage = 1072830; // Then begone. I have no time to waste on you, human. + InProgressMessage = 1072831; // The timber wolves are easily tracked, human. + + Objectives.Add( new KillObjective( 15, new Type[] { typeof( TimberWolf ) }, "timber wolves", new QuestArea( 1074833, "Huntsman's Forest" ) ) ); // Huntsman's Forest + + Rewards.Add( new DummyReward( 1072807 ) ); // The boon of the Huntsman. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074943, "", 0x2A ); // You have gained the boon of the Huntsman! You have been given a taste of the bittersweet duty of those who guard the balance. You are one step closer to claiming your elven heritage. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Huntsman" ), new Point3D( 1676, 593, 16 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Huntsman" ), new Point3D( 1676, 593, 16 ), Map.Trammel ); + + PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 15 ), 0, 10, "TimberWolf" ), new Point3D( 1671, 592, 16 ), Map.Felucca ); + PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 15 ), 0, 10, "TimberWolf" ), new Point3D( 1671, 592, 16 ), Map.Trammel ); + } + } + + public class TheJoysOfLife : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public TheJoysOfLife() + { + Activated = true; + Title = 1072787; // The Joys of Life + Description = 1072832; // *giggle* So serious, so grim! *tickle* Enjoy life! Have fun! Laugh! Be merry! *giggle* Find three of my baubles ... *giggle* I hid them! *giggles hysterically* Hid them! La la la! Bring them quickly! They are magical and will hide themselves again if you are too slow. + RefusalMessage = 1072833; // *giggle* Too serious. Too thinky! + InProgressMessage = 1072834; // Magical baubles hidden, find them as you're bidden! *giggle* + CompletionMessage = 1074177; // *giggle* So pretty! + + Objectives.Add( new CollectObjective( 3, typeof( ABauble ), "arielle's baubles" ) ); + + Rewards.Add( new DummyReward( 1072809 ) ); // The boon of Arielle. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074944, "", 0x2A ); // You have gained the boon of Arielle! You have been taught the importance of laughter and light spirits. You are one step closer to claiming your elven heritage. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Arielle" ), new Point3D( 1560, 1182, -27 ), Map.Ilshenar ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Arielle" ), new Point3D( 3366, 292, 9 ), Map.Felucca ); // Felucca spawn for reds + + PutSpawner( new Spawner( 6, TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 30 ), 0, 20, "ABauble" ), new Point3D( 1585, 1212, -13 ), Map.Ilshenar ); + } + } + + #endregion + + #region Human To Elf Mobiles + + [QuesterName( "Maul" )] + public class MaulTheBear : GrizzlyBear + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public MaulTheBear() + { + Name = "Maul"; + AI = AIType.AI_Vendor; + FightMode = FightMode.None; + Tamable = false; + } + + public MaulTheBear( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Strongroot : Treefellow + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Strongroot() + { + Name = "Strongroot"; + AI = AIType.AI_Vendor; + FightMode = FightMode.None; + } + + public Strongroot( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Enigma : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Enigma() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Enigma"; + BodyValue = 788; + BaseSoundID = 0x3EE; + + InitStats( 100, 100, 25 ); + } + + public Enigma( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Bravehorn : BaseEscortable + { + public override bool StaticMLQuester { get { return true; } } + public override bool InitialInnocent { get { return true; } } + + [Constructable] + public Bravehorn() + { + } + + public override void InitBody() + { + Name = "Bravehorn"; + Body = 0xEA; + + SetStr( 41, 71 ); + SetDex( 47, 77 ); + SetInt( 27, 57 ); + + SetHits( 27, 41 ); + SetMana( 0 ); + + SetDamage( 5, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + + SetSkill( SkillName.MagicResist, 26.8, 44.5 ); + SetSkill( SkillName.Tactics, 29.8, 47.5 ); + SetSkill( SkillName.Wrestling, 29.8, 47.5 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 24; + } + + public override void InitOutfit() + { + } + + public override int GetAttackSound() + { + return 0x82; + } + + public override int GetHurtSound() + { + return 0x83; + } + + public override int GetDeathSound() + { + return 0x84; + } + + public Bravehorn( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BravehornsMate : Hind + { + [Constructable] + public BravehornsMate() + { + Name = "bravehorn's mate"; + Tamable = false; + } + + public BravehornsMate( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Huntsman : Centaur + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Huntsman() + { + Name = "Huntsman"; + AI = AIType.AI_Vendor; + FightMode = FightMode.None; + } + + public Huntsman( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Arielle : Pixie + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Arielle() + { + Name = "Arielle"; + AI = AIType.AI_Vendor; + FightMode = FightMode.None; + } + + public Arielle( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion + + #region Elf To Human Quests + + public class Ingenuity : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public Ingenuity() + { + Activated = true; + Title = 1074350; // Ingenuity + Description = 1074462; // The best thing about my job is that I do a little bit of everything, every day. It's what we're good at really. Just picking up something and making it do something else. Listen, I'm really low on parts. Are you interested in fetching me some supplies? + RefusalMessage = 1074508; // Okay. Best of luck with your other endeavors. + InProgressMessage = 1074509; // Lord overseers are the best source I know for power crystals of the type I need. Iron golems too, can have them but they're harder to find. + CompletionMessage = 1074510; // Do you have those power crystals? I'm ready to put the finishing touches on my latest experiment. + CompletionNotice = CompletionNoticeShortReturn; + + Objectives.Add( new CollectObjective( 10, typeof( PowerCrystal ), "Power Crystals" ) ); + + Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074946, "", 0x2A ); // You have demonstrated your ingenuity! Humans are jacks of all trades and know a little about a lot of things. You are one step closer to achieving humanity. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Nedrick" ), new Point3D( 2958, 3466, 15 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Nedrick" ), new Point3D( 2958, 3466, 15 ), Map.Trammel ); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sledge" ), new Point3D( 2673, 2129, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Sledge" ), new Point3D( 2673, 2129, 0 ), Map.Trammel ); + } + } + + public class HeaveHo : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public HeaveHo() + { + Activated = true; + Title = 1074351; // Heave Ho! + Description = 1074519; // Ho there! There's nothing quite like a day's honest labor to make you appreciate being alive. Hey, maybe you'd like to help out with this project? These crates need to be delivered to Sledge. The only thing is -- it's a bit of a rush job and if you don't make it in time, he won't take them. Can I trust you to help out? + RefusalMessage = 1074521; // Oh yah, if you're too busy, no problem. + InProgressMessage = 1074522; // Sledge can be found in Buc's Den. Better hurry, he won't take those crates if you take too long with them. + CompletionMessage = 1074523; // Hey, if you have cargo for me, you can start unloading over here. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new TimedDeliverObjective( TimeSpan.FromHours( 1 ), typeof( CrateForSledge ), 5, "Crates for Sledge", typeof( Sledge ) ) ); + + Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074948, "", 0x2A ); // You have demonstrated your physical strength! Humans can carry vast loads without complaint. You are one step closer to achieving humanity. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Patricus" ), new Point3D( 3007, 823, -2 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Patricus" ), new Point3D( 3007, 823, -2 ), Map.Trammel ); + } + } + + // This is not a real quest, it is only used as a reference + public class HumanInNeed : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public HumanInNeed() + { + Title = 1075011; // A quest that asks you to defend a human in need. + Description = 0; + RefusalMessage = 0; + InProgressMessage = 0; + } + + public static void AwardTo( PlayerMobile pm ) + { + MLQuestSystem.GetOrCreateContext( pm ).SetDoneQuest( MLQuestSystem.FindQuest( typeof( HumanInNeed ) ) ); + pm.SendLocalizedMessage( 1074949, "", 0x2A ); // You have demonstrated your compassion! Your kind actions have been noted. + } + } + + public class AllSeasonAdventurer : MLQuest + { + public override bool RecordCompletion { get { return true; } } + + public AllSeasonAdventurer() + { + Activated = true; + Title = 1074353; // All Season Adventurer + Description = 1074527; // It's all about hardship, suffering, struggle and pain. Without challenges, you've got nothing to test yourself against -- and that's what life is all about. Self improvement! Honing your body and mind! Overcoming obstacles ... You'll see what I mean if you take on my challenge. + RefusalMessage = 1074528; // My way of life isn't for everyone, that's true enough. + InProgressMessage = 1074529; // You're not making much progress in the honing-mind-and-body department, are you? + CompletionNotice = CompletionNoticeShortReturn; + + Objectives.Add( new KillObjective( 5, new Type[] { typeof( Efreet ) }, "efreets", new QuestArea( 1074808, "Fire" ) ) ); // Fire + Objectives.Add( new KillObjective( 5, new Type[] { typeof( IceFiend ) }, "ice fiends", new QuestArea( 1074809, "Ice" ) ) ); // Ice + + Rewards.Add( new DummyReward( 1074875 ) ); // Another step closer to becoming human. + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.Player.SendLocalizedMessage( 1074947, "", 0x2A ); // You have demonstrated your toughness! Humans are able to endure unimaginable hardships in pursuit of their goals. You are one step closer to achieving humanity. + instance.ClaimRewards(); // skip gump + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Belulah" ), new Point3D( 3782, 1266, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Belulah" ), new Point3D( 3782, 1266, 0 ), Map.Trammel ); + } + } + + #endregion + + #region Elf To Human Mobiles + + [QuesterName( "Sledge (Buc's Den)" )] + public class Sledge : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074188, // Weakling! You are not up to the task I have. + 1074195 // You there, in the stupid hat! Come here. + ) ); + } + + [Constructable] + public Sledge() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Sledge"; + Title = "the Versatile"; + Body = 400; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + AddItem( new Tunic( Utility.RandomNeutralHue() ) ); + AddItem( new LongPants( Utility.RandomBlueHue() ) ); + AddItem( new Cloak( Utility.RandomBrightHue() ) ); + AddItem( new ElvenBoots( Utility.RandomNeutralHue() ) ); + AddItem( new Backpack() ); + } + + public Sledge( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Patricus (Vesper)" )] + public class Patricus : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Patricus() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Patricus"; + Title = "the Trader"; + Body = 400; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + AddItem( new FancyShirt( Utility.RandomNeutralHue() ) ); + AddItem( new LongPants( Utility.RandomBrightHue() ) ); + AddItem( new Cloak( 0x1BB ) ); + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Backpack() ); + } + + public Patricus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Belulah (Nujel'm)" )] // On OSI it's "Belulah (Nu'Jelm)" (incorrect spelling) + public class Belulah : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + /* + * 1074205 - Oh great adventurer, would you please assist a weak soul in need of aid? + * 1074206 - Excuse me please traveler, might I have a little of your time? + */ + MLQuestSystem.Tell( this, pm, Utility.Random( 1074205, 2 ) ); + } + + [Constructable] + public Belulah() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Belulah"; + Title = "the scorned"; + Female = true; + Body = 401; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new FancyShirt( Utility.RandomBlueHue() ) ); + AddItem( new LongPants( Utility.RandomNondyedHue() ) ); + AddItem( new Boots() ); + } + + public Belulah( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/HonestBeggar.cs b/Scripts/Engines/MLQuests/Definitions/HonestBeggar.cs new file mode 100644 index 0000000..4f3ce77 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/HonestBeggar.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class HonestBeggar : MLQuest + { + public override Type NextQuest { get { return typeof( ReginasThanks ); } } + + public HonestBeggar() + { + Activated = true; + Title = 1075392; // Honest Beggar + Description = 1075393; // Beg pardon, sir. I mean, madam. Uh, can I ask a favor of you? I found this jeweled ring. Most people would sell it and keep the money, but not me. I ain't never stole nothing, and I ain't about to start. I tried to take it over to Brit castle, figgerin' it must belong to some highborn lady, but the guards threw me out. You look like they might let you pass. Will you take the ring over there and see if you can find the owner? + RefusalMessage = 1075395; // I see. Too good to help an honest beggar like me, eh? + InProgressMessage = 1075396; // A jewel like this must be worth a lot, so it must belong to some noble or another. I would show it around the castle. Someone�s bound to recognize it. + CompletionMessage = 1075397; // Didst thou find my ring? I thank thee very much! It is an old ring, and a gift from my husband. I was most distraught when I realized it was missing. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( ReginasRing ), 1, "Regina's Ring", typeof( Regina ) ) ); + + Rewards.Add( new DummyReward( 1075394 ) ); // Find the ring�s owner. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Evan" ), new Point3D( 1486, 1706, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Evan" ), new Point3D( 1486, 1706, 0 ), Map.Felucca ); + } + } + + public class ReginasThanks : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public ReginasThanks() + { + Activated = true; + OneTimeOnly = true; + Title = 1075398; // Regina�s Thanks + Description = 1075399; // What�s that you say? It was a humble beggar that found my ring? Such honesty must be rewarded. Here, take this packet and return it to him, and I will be in your debt. + RefusalMessage = 1075401; // Hmph. Very well. What did you say his name was? + InProgressMessage = 1075402; // Take the packet and return it to the beggar who found my ring. + CompletionMessage = 1075403; // What? For me? Let me see . . . these sapphire earrings are for you, it says. Oh, she wants to offer me a job! This is the most wonderful thing that ever happened to me! + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( ReginasLetter ), 1, "Regina's Letter", typeof( Evan ) ) ); + + Rewards.Add( new ItemReward( 1075400, typeof( TransparentHeart ) ) ); // Transparent Heart + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Regina" ), new Point3D( 1362, 1622, 50 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Regina" ), new Point3D( 1422, 1621, 20 ), Map.Felucca ); + } + } + + #endregion + + #region Mobiles + + public class Evan : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Evan() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Evan"; + Title = "the Beggar"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Doublet() ); + AddItem( new ShortPants( 0x755 ) ); + + } + + public Evan( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Regina : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Regina() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Regina"; + Title = "the Noble"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new GildedDress() ); + AddItem( new Boots() ); + + } + + public Regina( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Ilshenar.cs b/Scripts/Engines/MLQuests/Definitions/Ilshenar.cs new file mode 100644 index 0000000..58dd400 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Ilshenar.cs @@ -0,0 +1,335 @@ +using System; +using Server; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + public class Responsibility : BaseEscort + { + public Responsibility() + { + Activated = true; + Title = 1074352; // Responsibility + Description = 1074524; // Oh! I just don't know what to do. My mother is away and my father told me not to talk to strangers ... *worried frown* But my grandfather has sent word that he has been hurt and needs me to tend his wounds. He has a small farm southeast of here. Would you ... could you ... escort me there safely? + RefusalMessage = 1074525; // I hope my grandfather will be alright. + InProgressMessage = 1074526; // Grandfather's farm is a ways west of the Shrine of Spirituality. So, we're not quite there yet. Thank you again for keeping me safe. + + Objectives.Add( new EscortObjective( new QuestArea( 1074781, "Sheep Farm" ) ) ); // Sheep Farm + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + + // OSI sends this instead, but it doesn't make sense for an escortable + //public override void OnComplete( MLQuestInstance instance ) + //{ + // instance.Player.SendLocalizedMessage( 1073775, "", 0x23 ); // Your quest is complete. Return for your reward. + //} + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 10 ), TimeSpan.FromSeconds( 30 ), 0, 5, "Lissbet" ), new Point3D( 1568, 1040, -7 ), Map.Ilshenar ); + PutSpawner( new Spawner( 1, 5, 10, 0, 8, "GrandpaCharley" ), new Point3D( 1322, 1331, -14 ), Map.Ilshenar ); + PutSpawner( new Spawner( 1, TimeSpan.FromSeconds( 10 ), TimeSpan.FromSeconds( 30 ), 0, 3, "Sheep" ), new Point3D( 1308, 1324, -14 ), Map.Ilshenar ); + } + } + + public class SomethingToWailAbout : MLQuest + { + public SomethingToWailAbout() + { + Activated = true; + Title = 1073071; // Something to Wail About + Description = 1073561; // Can you hear them? The never-ending howling? The incessant wailing? These banshees, they never cease! Never! They haunt my nights. Please, I beg you -- will you silence them? I would be ever so grateful. + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073581; // Until you kill 12 Wailing Banshees, there will be no peace. + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( WailingBanshee ) }, "wailing banshees" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Jelrice" ), new Point3D( 1176, 1196, -25 ), Map.Ilshenar ); + } + } + + public class Runaways : MLQuest + { + public Runaways() + { + Activated = true; + Title = 1072993; // Runaways! + Description = 1073026; // You've got to help me out! Those wild ostards have been causing absolute havok around here. Kill them off before they destroy my land. There are around twelve of them. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( FrenziedOstard ) }, "frenzied ostards" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class ViciousPredator : MLQuest + { + public ViciousPredator() + { + Activated = true; + Title = 1072994; // Vicious Predator + Description = 1073028; // You've got to help me out! Those dire wolves have been causing absolute havok around here. Kill them off before they destroy my land. They run around in a pack of around ten. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( DireWolf ) }, "dire wolves" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class GuileIrkAndSpite : MLQuest + { + public GuileIrkAndSpite() + { + Activated = true; + Title = 1074739; // Guile, Irk and Spite + Description = 1074740; // You know them, don't you. The three? They look like you, you'll see. They looked like me, I remember, they looked like, well, you'll see. The three. They'll drive you mad too, if you let them. They are trouble, and they need to be slain. Seek them out. + RefusalMessage = 1074745; // You just don't understand the gravity of the situation. If you did, you'd agree to my task. + InProgressMessage = 1074746; // Perhaps I was unclear. You'll know them when you see them, because you'll see you, and you, and you. Hurry now. + CompletionMessage = 1074747; // Are you one of THEM? Ahhhh! Oh, wait, if you were them, then you'd be me. So you're -- you. Good job! + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Guile ) }, "Guile" ) ); + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Irk ) }, "Irk" ) ); + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Spite ) }, "Spite" ) ); + + Rewards.Add( ItemReward.Strongbox ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "Yorus" ), new Point3D( 1389, 423, -24 ), Map.Ilshenar ); + } + } + + public class Lissbet : BaseEscortable + { + public override bool StaticMLQuester { get { return true; } } + public override bool InitialInnocent { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074204, // Greetings seeker.  I have an urgent matter for you, if you are willing. + 1074222 // Could I trouble you for some assistance? + ) ); + } + + [Constructable] + public Lissbet() + { + } + + public override void InitBody() + { + SetStr( 40, 50 ); + SetDex( 70, 80 ); + SetInt( 80, 90 ); + + Hue = Utility.RandomSkinHue(); + Female = true; + Body = 401; + Name = "Lissbet"; + Title = "the flower girl"; + + HairItemID = 0x203D; + HairHue = 0x1BB; + } + + public override void InitOutfit() + { + AddItem( new Kilt( Utility.RandomYellowHue() ) ); + AddItem( new FancyShirt( Utility.RandomYellowHue() ) ); + AddItem( new Sandals() ); + } + + public Lissbet( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GrandpaCharley : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + [Constructable] + public GrandpaCharley() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Grandpa Charley"; + Title = "the farmer"; + Body = 400; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + int hairHue = 0x3B2 + Utility.Random( 2 ); + Utility.AssignRandomHair( this, hairHue ); + + FacialHairItemID = 0x203E; // Long Beard + FacialHairHue = hairHue; + + SetSkill( SkillName.ItemID, 80, 90 ); + + AddItem( new WideBrimHat( Utility.RandomNondyedHue() ) ); + AddItem( new FancyShirt( Utility.RandomNondyedHue() ) ); + AddItem( new LongPants( Utility.RandomNondyedHue() ) ); + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + AddItem( new ShepherdsCrook() ); + AddItem( new Backpack() ); + } + + public GrandpaCharley( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Jelrice (Ilshenar)" )] + public class Jelrice : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074221 ); // Greetings!  I have a small task for you good traveler. + } + + [Constructable] + public Jelrice() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Jelrice"; + Title = "the trader"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new Skirt( Utility.RandomBlueHue() ) ); + AddItem( new FancyShirt( Utility.RandomRedHue() ) ); + } + + public Jelrice( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Yorus (Ilshenar)" )] + public class Yorus : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074218 ); // Hey!  I want to talk to you, now. + } + + [Constructable] + public Yorus() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Yorus"; + Title = "the tinker"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new LongPants( Utility.RandomBlueHue() ) ); + AddItem( new FancyShirt( Utility.RandomOrangeHue() ) ); + AddItem( new Cloak( Utility.RandomBrightHue() ) ); + } + + public Yorus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Definitions/LostItems.cs b/Scripts/Engines/MLQuests/Definitions/LostItems.cs new file mode 100644 index 0000000..7e1cfb8 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/LostItems.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Items; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; + +namespace Server.Engines.MLQuests.Definitions +{ + // TODO: Assassination Contract, Evidence, Lost in Transit, Last Words + + #region Quests + + public class LostAndFound : MLQuest + { + public LostAndFound() + { + Activated = true; + Title = 1072370; // Lost and Found + Description = 1072589; // The battered, old bucket is inscribed with barely legible writing that indicates it belongs to someone named "Dallid". Maybe they'd pay for its return? + RefusalMessage = 1072590; // You're right, who cares if Dallid might pay for his battered old bucket back. This way you can carry it around with you! + InProgressMessage = 1072591; // Whoever this "Dallid" might be, he's probably looking for his bucket. + CompletionMessage = 1074580; // Is that my bucket? I had to ditch my favorite bucket when a group of ratmen jumped me! + + Objectives.Add( new TimedDeliverObjective( TimeSpan.FromSeconds( 600 ), typeof( BatteredBucket ), 1, "battered bucket", typeof( Dallid ), false ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + #endregion + + #region Items + + public class BatteredBucket : TransientQuestGiverItem + { + // Original label, doesn't fit the expiration message well + //public override int LabelNumber { get { return 1073129; } } // A battered bucket. + + public override string DefaultName { get { return "battered bucket"; } } + + [Constructable] + public BatteredBucket() + : base( 0x2004, TimeSpan.FromMinutes( 10 ) ) + { + LootType = LootType.Blessed; + } + + public BatteredBucket( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Malas.cs b/Scripts/Engines/MLQuests/Definitions/Malas.cs new file mode 100644 index 0000000..44ce875 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Malas.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class PointyEars : MLQuest + { + public PointyEars() + { + Activated = true; + Title = 1074640; // Pointy Ears + Description = 1074641; // I've heard ... there's some that will pay a good bounty for pointed ears, much like we used to pay for each wolf skin. I've got nothing personal against these elves. It's just business. You want in on this? I'm not fussy who I work with. + RefusalMessage = 1074642; // Suit yourself. + InProgressMessage = 1074643; // I can't pay a bounty if you don't bring bag the ears. + CompletionMessage = 1074644; // Here to collect on a bounty? + + Objectives.Add( new CollectObjective( 20, typeof( SeveredElfEars ), 1032590 ) ); // severed elf ears + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Drithen" ), new Point3D( 1983, 1364, -80 ), Map.Malas ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Drithen (Umbra)" )] + public class Drithen : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074188 ); // Weakling! You are not up to the task I have. + } + + [Constructable] + public Drithen() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Drithen"; + Title = "the Fierce"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + AddItem( new Backpack() ); + AddItem( new ElvenBoots( Utility.RandomNeutralHue() ) ); + AddItem( new LongPants( Utility.RandomBlueHue() ) ); + AddItem( new Tunic( Utility.RandomNeutralHue() ) ); + AddItem( new Cloak( Utility.RandomBrightHue() ) ); + + SetSkill( SkillName.Focus, 60.0, 80.0 ); + } + + public Drithen( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/MistakenIdentity.cs b/Scripts/Engines/MLQuests/Definitions/MistakenIdentity.cs new file mode 100644 index 0000000..eb5da1b --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/MistakenIdentity.cs @@ -0,0 +1,342 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Items; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class MistakenIdentity : MLQuest + { + public override Type NextQuest { get { return typeof( YouScratchMyBack ); } } + + public MistakenIdentity() + { + Activated = true; + Title = 1074573; // Mistaken Identity + Description = 1074574; // What do you want? Wonderful, another whining request for a refund on tuition. You know, experiences like that are invaluable ... and infrequent. Having the opportunity to test yourself under such realistic situations isn't something the college offers all students. Fine. Fine. You'll need to submit a refund request form in triplicate before I can return your 1,000,000 gold tuition. You'll need to get some signatures and a few other odds and ends. + RefusalMessage = 1074606; // If you're not willing to follow the proper process then go away. + InProgressMessage = 1074605; // You're not getting a refund without the proper forms and signatures. + CompletionMessage = 1074607; // Oh blast! Not another of those forms. I'm so sick of this endless paperwork. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( TuitionReimbursementForm ), 1, "Tuition Reimbursement Form", typeof( Gorrow ) ) ); + + Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Aernya" ), new Point3D( 2095, 1380, -90 ), Map.Malas ); + } + } + + public class YouScratchMyBack : MLQuest + { + public override Type NextQuest { get { return typeof( FoolingAernya ); } } + public override bool IsChainTriggered { get { return true; } } + + public YouScratchMyBack() + { + Activated = true; + Title = 1074608; // You Scratch My Back + Description = 1074609; // Heh. Heheheh. Good one. You're not a Bedlam student and you're definitely not eligible for a tuition refund. Heheheh. That old witch Aernya doesn't see as well as she used to you know. Otherwise, she would have ... hmmm, wait a minute. I sense a certain 'opportunity' here. I'll sign your forms in return for a little help with a project of my own. What do you say? + RefusalMessage = 1074615; // Hehehe. Your choice. + InProgressMessage = 1074616; // I'm something of a gourmet, you see. It's tough getting some of the ingredients, though. Bring me back some pixie legs, unicorn ribs and ki-rin brains and I'll sign your form. + CompletionMessage = 1074617; // Oh excellent, you're back. I'll get the oven going. That thing about pixie legs, you see, is that they burn and dry out if you're not really careful. Taste just like chicken too! + CompletionNotice = CompletionNoticeShortReturn; + + Objectives.Add( new CollectObjective( 1, typeof( UnicornRibs ), "Unicorn Ribs" ) ); + Objectives.Add( new CollectObjective( 2, typeof( KirinBrains ), "Ki-Rin Brains" ) ); + Objectives.Add( new CollectObjective( 5, typeof( PixieLeg ), "Pixie Leg" ) ); + + Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 4, "Gorrow" ), new Point3D( 993, 512, -50 ), Map.Malas ); + } + } + + public class FoolingAernya : MLQuest + { + public override Type NextQuest { get { return typeof( NotQuiteThatEasy ); } } + public override bool IsChainTriggered { get { return true; } } + + public FoolingAernya() + { + Activated = true; + Title = 1074618; // Fooling Aernya + Description = 1074619; // Now that I've signed your papers you'd better get back to that witch Aernya. Mmmm mmm smell those ribs! + RefusalMessage = 1074620; // Giving up on your scheme eh? Suit yourself. + InProgressMessage = 1074621; // You better hurry back to Mistress Aernya with that signed form. The college only has so much money and with enough claims you may find yourself unable to get your tuition refunded. *wink* + CompletionMessage = 1074622; // What? Hrmph. Gorrow signed your form did he? Let me see that. *squint* + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( SignedTuitionReimbursementForm ), 1, "Signed Tuition Reimbursement Form", typeof( Aernya ) ) ); + + Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement + } + } + + public class NotQuiteThatEasy : MLQuest + { + public override Type NextQuest { get { return typeof( ConvinceMe ); } } + public override bool IsChainTriggered { get { return true; } } + + public NotQuiteThatEasy() + { + Activated = true; + Title = 1074623; // Not Quite That Easy + Description = 1074624; // I wouldn't be too smug just yet, whiner. You still need Master Gnosos' signature before I can cut your refund. Last I heard, he's coordinating the recovery of the portions of the college that are currently overrun. *nasty smile* Off with you. + RefusalMessage = 1074626; // Coward. + InProgressMessage = 1074627; // What are you waiting for? The iron maiden is still the portal to Bedlam. + CompletionMessage = 1074628; // Made it through did you? Did you happen to see Red Death out there? Big horse, skeletal ... burning eyes? No? What's this? Forms? FORMS? I'm up to my eyebrows in ravenous out-of-control undead and you want a signature? + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( SignedTuitionReimbursementForm ), 1, "Signed Tuition Reimbursement Form", typeof( MasterGnosos ) ) ); + + Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement + } + + public override void Generate() + { + base.Generate(); + + PutDeco( new BedlamTeleporter(), new Point3D( 2067, 1371, -75 ), Map.Malas ); + } + + public override void OnAccepted( MLQuestInstance instance ) + { + instance.PlayerContext.BedlamAccess = true; // Permanent access + } + } + + public class ConvinceMe : MLQuest + { + public override Type NextQuest { get { return typeof( TuitionReimbursement ); } } + public override bool IsChainTriggered { get { return true; } } + + public ConvinceMe() + { + Activated = true; + Title = 1074629; // Convince Me + Description = 1074630; // I'm not signing any forms until the situation here is under control. So, you can either help out or you can forget getting your tuition refund. Which will it be? Help control the shambling dead? + RefusalMessage = 1074631; // No signature for you. + InProgressMessage = 1074632; // No signature for you until you kill off some of the shambling dead out there and destroy that blasted horse. + CompletionMessage = 1074633; // Pulled it off huh? Well then you've earned this signature! + CompletionNotice = CompletionNoticeShortReturn; + + QuestArea bedlam = new QuestArea( 1074835, "Bedlam" ); // Bedlam + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( RedDeath ) }, "Red Death", bedlam ) ); + Objectives.Add( new KillObjective( 10, new Type[] { typeof( GoreFiend ) }, "gore fiends", bedlam ) ); + Objectives.Add( new KillObjective( 8, new Type[] { typeof( RottingCorpse ) }, "rotting corpses", bedlam ) ); + + Rewards.Add( new DummyReward( 1074634 ) ); // Tuition Reimbursement + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "MasterGnosos" ), new Point3D( 87, 1639, 0 ), Map.Malas ); + } + } + + public class TuitionReimbursement : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public TuitionReimbursement() + { + Activated = true; + Title = 1074634; // Tuition Reimbursement + Description = 1074635; // Well, there you are. I've added my signature to that of Gorrow, so you should be set to return to Mistress Aernya and get your tuition refunded. + RefusalMessage = 1074636; // Great! If you're going to stick around here, I know we have more tasks for you to perform. + InProgressMessage = 1074637; // Just head out the main gates there and you'll find yourself embracing the iron maiden in the Bloodletter's Guild. + CompletionMessage = 1074638; // *disinterested stare* What? Oh, you've gotten your form filled in. How nice. *glare* And I'd hoped you'd drop this charade before I was forced to rub your nose in it. *nasty smile* You're not even a student and as such, you're not eligible for a refund -- you've never paid tuition. For your services, Master Gnosos has recommended you receive pay. So here. Now go away. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( CompletedTuitionReimbursementForm ), 1, "Completed Tuition Reimbursement Form", typeof( Aernya ) ) ); + + Rewards.Add( ItemReward.Strongbox ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Aernya (Umbra)" )] + public class Aernya : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Aernya() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Aernya"; + Title = "the Mistress of Admissions"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + AddItem( new Skirt( Utility.RandomBool() ? 0x1 : 0x0 ) ); + AddItem( new Cloak( Utility.RandomBrightHue() ) ); + AddItem( new FancyShirt( Utility.RandomBool() ? 0x3B2 : 0x3B3 ) ); + } + + public Aernya( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Gorrow (Luna)" )] + public class Gorrow : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074200, // Thank goodness you are here, there�s no time to lose. + 1074203 // Hello friend. I realize you are busy but if you would be willing to render me a service I can assure you that you will be judiciously renumerated. + ) ); + } + + [Constructable] + public Gorrow() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Gorrow"; + Title = "the Mayor"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + AddItem( new Backpack() ); + AddItem( new Shoes( 0x1BB ) ); + AddItem( new Tunic( Utility.RandomNeutralHue() ) ); + AddItem( new LongPants( 0x901 ) ); + AddItem( new Cloak( Utility.RandomRedHue() ) ); + } + + public Gorrow( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Master Gnosos (Bedlam)" )] + public class MasterGnosos : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074186 ); // Come here, I have a task. + } + + [Constructable] + public MasterGnosos() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Master Gnosos"; + Title = "the necromancer"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = 0x83E8; + InitStats( 100, 100, 25 ); + + HairItemID = 0x2049; + FacialHairItemID = 0x204B; + + AddItem( new Backpack() ); + AddItem( new Shoes( 0x485 ) ); + AddItem( new Robe( 0x497 ) ); + + SetSkill( SkillName.EvalInt, 60.0, 80.0 ); + SetSkill( SkillName.Inscribe, 60.0, 80.0 ); + SetSkill( SkillName.MagicResist, 60.0, 80.0 ); + SetSkill( SkillName.SpiritSpeak, 60.0, 80.0 ); + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Necromancy, 60.0, 80.0 ); + } + + public MasterGnosos( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/NewHaven.cs b/Scripts/Engines/MLQuests/Definitions/NewHaven.cs new file mode 100644 index 0000000..c7e04ed --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/NewHaven.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; + +namespace Server.Engines.MLQuests.Definitions +{ + public class NewHavenEscort : BaseEscort + { + // New Haven escorts do not count for 'helping a human in need' + public override bool AwardHumanInNeed { get { return false; } } + + // Escort reward + private static readonly BaseReward m_Reward = new ItemReward( "Gold", typeof( Gold ), 500 ); + + public NewHavenEscort( int title, int description, int progress, int destination, string region ) + { + Activated = true; + Title = title; + Description = description; + RefusalMessage = 1072288; // I wish you would reconsider my offer. I'll be waiting right here for someone brave enough to assist me. + InProgressMessage = progress; + + Objectives.Add( new EscortObjective( new QuestArea( destination, region ) ) ); + + Rewards.Add( m_Reward ); + } + } + + public class EscortToNHAlchemist : NewHavenEscort + { + public EscortToNHAlchemist() + : base( 1072314, 1042769, 1072326, 1073864, "the New Haven Alchemist" ) + { + } + } + + public class EscortToNHBard : NewHavenEscort + { + public EscortToNHBard() + : base( 1072315, 1042772, 1072327, 1073865, "the New Haven Bard" ) + { + } + } + + public class EscortToNHWarrior : NewHavenEscort + { + public EscortToNHWarrior() + : base( 1072316, 1042787, 1072328, 1073866, "the New Haven Warrior" ) + { + } + } + + public class EscortToNHTailor : NewHavenEscort + { + public EscortToNHTailor() + : base( 1072317, 1042781, 1072329, 1073867, "the New Haven Tailor" ) + { + } + } + + public class EscortToNHCarpenter : NewHavenEscort + { + public EscortToNHCarpenter() + : base( 1072318, 1042775, 1072330, 1073868, "the New Haven Carpenter" ) + { + } + } + + public class EscortToNHMapmaker : NewHavenEscort + { + public EscortToNHMapmaker() + : base( 1072319, 1042793, 1072331, 1073869, "the New Haven Mapmaker" ) + { + } + } + + public class EscortToNHMage : NewHavenEscort + { + public EscortToNHMage() + : base( 1072320, 1042790, 1072332, 1073870, "the New Haven Mage" ) + { + } + } + + public class EscortToNHInn : NewHavenEscort + { + public EscortToNHInn() + : base( 1072321, 1042796, 1072333, 1073871, "the New Haven Inn" ) + { + } + } + + public class EscortToNHFarm : NewHavenEscort + { + public EscortToNHFarm() + : base( 1072322, 1042799, 1072334, 1073872, "the New Haven Farm" ) + { + } + } + + public class EscortToNHDocks : NewHavenEscort + { + public EscortToNHDocks() + : base( 1072323, 1042802, 1072335, 1073873, "the New Haven Docks" ) + { + } + } + + public class EscortToNHBowyer : NewHavenEscort + { + public EscortToNHBowyer() + : base( 1072324, 1042805, 1072336, 1073874, "the New Haven Bowyer" ) + { + } + } + + public class EscortToNHBank : NewHavenEscort + { + public EscortToNHBank() + : base( 1072325, 1042784, 1072337, 1073875, "the New Haven Bank" ) + { + } + } +} diff --git a/Scripts/Engines/MLQuests/Definitions/NewHavenSkillTraining.cs b/Scripts/Engines/MLQuests/Definitions/NewHavenSkillTraining.cs new file mode 100644 index 0000000..3c38cc1 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/NewHavenSkillTraining.cs @@ -0,0 +1,2413 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class CleansingOldHaven : MLQuest + { + public CleansingOldHaven() + { + Activated = true; + OneTimeOnly = true; + Title = 1077719; // Cleansing Old Haven + Description = 1077722; // Head East out of town to Old Haven. Consecrate your weapon, cast Divine Fury, and battle monsters there until you have raised your Chivalry skill to 50.
------

Hail, friend. The life of a Paladin is a life of much sacrifice, humility, bravery, and righteousness. If you wish to pursue such a life, I have an assignment for you. Adventure east to Old Haven, consecrate your weapon, and lay to rest the undead that inhabit there.

Each ability a Paladin wishes to invoke will require a certain amount of "tithing points" to use. A Paladin can earn these tithing points by donating gold at a shrine or holy place. You may tithe at this shrine.

Return to me once you feel that you are worthy of the rank of Apprentice Paladin. + RefusalMessage = 1077723; // Farewell to you my friend. Return to me if you wish to live the life of a Paladin. + InProgressMessage = 1077724; // There are still more undead to lay to rest. You still have more to learn. Return to me once you have done so. + CompletionMessage = 1077726; // Well done, friend. While I know you understand Chivalry is its own reward, I would like to reward you with something that will protect you in battle. It was passed down to me when I was a lad. Now, I am passing it on you. It is called the Bulwark Leggings. Thank you for your service. + CompletionNotice = 1077725; // You have achieved the rank of Apprentice Paladin. Return to Aelorn in New Haven to report your progress. + + Objectives.Add( new GainSkillObjective( SkillName.Chivalry, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077727, typeof( BulwarkLeggings ) ) ); // Bulwark Leggings + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Aelorn" ), new Point3D( 3527, 2516, 45 ), Map.Trammel ); + } + } + + public class TheRudimentsOfSelfDefense : MLQuest + { + public TheRudimentsOfSelfDefense() + { + Activated = true; + OneTimeOnly = true; + Title = 1077609; // The Rudiments of Self Defense + Description = 1077610; // Head East out of town and go to Old Haven. Battle monster there until you have raised your Wrestling skill to 50.Listen up! If you want to learn the rudiments of self-defense, you need toughening up, and there's no better way to toughen up than engaging in combat. Head East out of town to Old Haven and battle the undead there in hand to hand combat. Afraid of dying, you say? Well, you should be! Being an adventurer isn't a bed of posies, or roses, or however that saying goes. If you take a dirt nap, go to one of the nearby wandering healers and they'll get you back on your feet.Come back to me once you feel that you are worthy of the rank Apprentice Wrestler and i will reward you wit a prize. + RefusalMessage = 1077611; // Ok, featherweight. come back to me if you want to learn the rudiments of self-defense. + InProgressMessage = 1077630; // You have not achived the rank of Apprentice Wrestler. Come back to me once you feel that you are worthy of the rank Apprentice Wrestler and i will reward you with something useful. + CompletionMessage = 1077613; // It's about time! Looks like you managed to make it through your self-defense training. As i promised, here's a little something for you. When worn, these Gloves of Safeguarding will increase your awareness and resistances to most elements except poison. Oh yeah, they also increase your natural health regeneration aswell. Pretty handy gloves, indeed. Oh, if you are wondering if your meditation will be hinered while wearing these gloves, it won't be. Mages can wear cloth and leather items without needing to worry about that. Now get out of here and make something of yourself. + CompletionNotice = 1077612; // You have achieved the rank of Apprentice Wrestler. Return to Dimethro in New Haven to receive your prize. + + Objectives.Add( new GainSkillObjective( SkillName.Wrestling, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077614, typeof( GlovesOfSafeguarding ) ) ); // Gloves Of Safeguarding + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Dimethro" ), new Point3D( 3528, 2520, 25 ), Map.Trammel ); + } + } + + public class CrushingBonesAndTakingNames : MLQuest + { + public CrushingBonesAndTakingNames() + { + Activated = true; + OneTimeOnly = true; + Title = 1078070; // Crushing Bones and Taking Names + Description = 1078065; // Head East out of town and go to Old Haven. While wielding your mace,battle monster there until you have raised your Mace Fighting skill to 50. I see you want to learn a real weapon skill and not that toothpick training Jockles hasto offer. Real warriors are called Armsmen, and they wield mace weapons. No doubt about it. Nothing is more satisfying than knocking the wind out of your enemies, smashing there armor, crushing their bones, and taking there names. Want to learn how to wield a mace? Well i have an assignment for you. Head East out of town and go to Old Haven. Undead have plagued the town, so there are plenty of bones for you to smash there. Come back to me after you have ahcived the rank of Apprentice Armsman, and i will reward you with a real weapon. + RefusalMessage = 1078068; // I thought you wanted to be an Armsman and really make something of yourself. You have potential, kid, but if you want to play with toothpicks, run to Jockles and he will teach you how to clean your teeth with a sword. If you change your mind, come back to me, and i will show you how to wield a real weapon. + InProgressMessage = 1078067; // Listen kid. There are a lot of undead in Old Haven, and you haven't smashed enough of them yet. So get back there and do some more cleansing. + CompletionMessage = 1078069; // Now that's what I'm talking about! Well done! Don't you like crushing bones and taking names? As i promised, here is a war mace for you. It hits hard. It swings fast. It hits often. What more do you need? Now get out of here and crush some more enemies! + CompletionNotice = 1078068; // You have achieved the rank of Apprentice Armsman. Return to Churchill in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Macing, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078062, typeof( ChurchillsWarMace ) ) ); // Churchill's War Mace + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Churchill" ), new Point3D( 3531, 2531, 20 ), Map.Trammel ); + } + } + + public class SwiftAsAnArrow : MLQuest + { + public SwiftAsAnArrow() + { + Activated = true; + OneTimeOnly = true; + Title = 1078201; // Swift as an Arrow + Description = 1078205; // Head East out of town and go to Old Haven. While wielding your bow or crossbow, battle monster there until you have raised your Archery skill to 50. Well met, friend. Imagine yourself in a distant grove of trees, You raise your bow, take slow, careful aim, and with the twitch of a finger, you impale your prey with a deadly arrow. You look like you would make a excellent archer, but you will need practice. There is no better way to practice Archery than when you life is on the line. I have a challenge for you. Head East out of town and go to Old Haven. While wielding your bow or crossbow, battle the undead that reside there. Make sure you bring a healthy supply of arrows (or bolts if you prefer a crossbow). If you wish to purchase a bow, crossbow, arrows, or bolts, you can purchase them from me or the Archery shop in town. You can also make your own arrows with the Bowcraft/Fletching skill. You will need fletcher's tools, wood to turn into sharft's, and feathers to make arrows or bolts. Come back to me after you have achived the rank of Apprentice Archer, and i will reward you with a fine Archery weapon. + RefusalMessage = 1078206; // I understand that Archery may not be for you. Feel free to visit me in the future if you change your mind. + InProgressMessage = 1078207; // You're doing great as an Archer! however, you need more practice. + CompletionMessage = 1078209; // Congratulation! I want to reward you for your accomplishment. Take this composite bow. It is called " Heartseeker". With it, you will shoot with swiftness, precision, and power. I hope "Heartseeker" serves you well. + CompletionNotice = 1078208; // You have achieved the rank of Apprentice Archer. Return to Robyn in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Archery, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078210, typeof( Heartseeker ) ) ); // Heartseeker + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Robyn" ), new Point3D( 3535, 2531, 20 ), Map.Trammel ); + } + } + + public class EnGuarde : MLQuest + { + public EnGuarde() + { + Activated = true; + OneTimeOnly = true; + Title = 1078186; // En Guarde! + Description = 1078190; // Head East out of town to Old Haven. Battle monsters there until you have raised your Fencing skill to 50.
------

Well hello there, lad. Fighting with elegance and precision is far more enriching than slugging an enemy with a club or butchering an enemy with a sword. Learn the art of Fencing if you want to master combat and look good doing it!

The key to being a successful fencer is to be the complement and not the opposition to your opponent's strength. Watch for your opponent to become off balance. Then finish him off with finesse and flair.

There are some undead that need cleansing out in Old Haven towards the East. Head over there and slay them, but remember, do it with style!

Come back to me once you have achieved the rank of Apprentice Fencer, and I will reward you with a prize. + RefusalMessage = 1078191; // I understand, lad. Being a hero isn't for everyone. Run along, then. Come back to me if you change your mind. + InProgressMessage = 1078192; // You're doing well so far, but you're not quite ready yet. Head back to Old Haven, to the East, and kill some more undead. + CompletionMessage = 1078194; // Excellent! You are beginning to appreciate the art of Fencing. I told you fighting with elegance and precision is more enriching than fighting like an ogre.

Since you have returned victorious, please take this war fork and use it well. The war fork is a finesse weapon, and this one is magical! I call it "Recaro's Riposte". With it, you will be able to parry and counterstrike with ease! Your enemies will bask in your greatness and glory! Good luck to you, lad, and keep practicing! + CompletionNotice = 1078193; // You have achieved the rank of Apprentice Fencer. Return to Recaro in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Fencing, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078195, typeof( RecarosRiposte ) ) ); // Recaro's Riposte + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Recaro" ), new Point3D( 3536, 2534, 20 ), Map.Trammel ); + } + } + + public class TheArtOfWar : MLQuest + { + public TheArtOfWar() + { + Activated = true; + OneTimeOnly = true; + Title = 1077667; // The Art of War + Description = 1077670; // Head East out of town to Old Haven. Battle monsters there until you have raised your Tactics skill to 50.
------

Knowing how to hold a weapon is only half of the battle. The other half is knowing how to use it against an opponent. It's one thing to kill a few bunnies now and then for fun, but a true warrior knows that the right moves to use against a lich will pretty much get your arse fried by a dragon.

I'll help teach you how to fight so that when you do come up against that dragon, maybe you won't have to walk out of there "OooOOooOOOooOO'ing" and looking for a healer.

There are some undead that need cleaning out in Old Haven towards the east. Why don't you head on over there and practice killing things?

When you feel like you've got the basics down, come back to me and I'll see if I can scrounge up an item to help you in your adventures later on. + RefusalMessage = 1077671; // That's too bad. I really thought you had it in you. Well, I'm sure those undead will still be there later, so if you change your mind, feel free to stop on by and I'll help you the best I can. + InProgressMessage = 1077672; // You're making some progress, that i can tell, but you're not quite good enough to last for very long out there by yourself. Head back to Old Haven, to the east, and kill some more undead. + CompletionMessage = 1077674; // Hey, good job killing those undead! Hopefully someone will come along and clean up the mess. All that blood and guts tends to stink after a few days, and when the wind blows in from the east, it can raise a mighty stink!

Since you performed valiantly, please take these arms and use them well. I've seen a few too many harvests to be running around out there myself, so you might as well take it.

There is a lot left for you to learn, but I think you'll do fine. Remember to keep your elbows in and stick'em where it hurts the most! + CompletionNotice = 1077673; // You have achieved the rank of Apprentice Warrior. Return to Alden Armstrong in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Tactics, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077675, typeof( ArmsOfArmstrong ) ) ); // Arms of Armstrong + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "AldenArmstrong" ), new Point3D( 3535, 2538, 20 ), Map.Trammel ); + } + } + + public class TheWayOfTheBlade : MLQuest + { + public TheWayOfTheBlade() + { + Activated = true; + OneTimeOnly = true; + Title = 1077658; // The way of The Blade + Description = 1077661; // Head East out of town and go to Old Haven. While wielding your sword, battle monster there until you have raised your Swordsmanship skill to 50. *as you approach, you notice Jockles sizing you up with a skeptical look on his face* i can see you want to learn how to handle a blade. It's a lot harder than it looks, and you're going to have to put alot of time and effort if you ever want to be half as good as i am. I'll tell you what, kid, I'll help you get started, but you're going to have to do all the work if you want to learn something. East of here, outside of town, is Old Haven. It's been overrun with the nastiest of undead you've seen, which makes it a perfect place for you to turn that sloppy grin on your face into actual skill at handling a sword. Make sure you have a sturdy Swordsmanship weapon in good repair before you leave. 'tis no fun to travel all the way down there just to find out you forgot your blade! When you feel that you've cut down enough of those foul smelling things to learn how to handle a blade without hurting yourself, come back to me. If i think you've improved enough, I'll give you something suited for a real warrior. + RefusalMessage = 1077662; // Ha! I had a feeling you were a lily-livered pansy. You might have potential, but you're scared by a few smelly undead, maybe it's better that you stay away from sharp objects. After all, you wouldn't want to hurt yourself swinging a sword. If you change your mind, I might give you another chance...maybe. + InProgressMessage = 1077663; // *Jockles looks you up and down* Come on! You've got to work harder than that to get better. Now get out of here, go kill some more of those undead to the east in Old Haven, and don't come back till you've got real skill. + CompletionMessage = 1077665; // Well, well, look at what we have here! You managed to do it after all. I have to say, I'm a little surprised that you came back in one piece, but since you did. I've got a little something for you. This is a fine blade that served me well in my younger days. Of course I've got much better swords at my disposal now, so I'll let you go ahead and use it under one condition. Take goodcare of it and treat it with the respect that a fine sword deserves. You're one of the quickers learners I've seen, but you still have a long way to go. Keep at it, and you'll get there someday. Happy hunting, kid. + CompletionNotice = 1077664; // You have achieved the rank of Apprentice Swordsman. Return to Jockles in New Haven to see what kind of reward he has waiting for you. Hopefully he'll be a little nicer this time! + + Objectives.Add( new GainSkillObjective( SkillName.Swords, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077666, typeof( JocklesQuicksword ) ) ); // Jockles' Quicksword + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Jockles" ), new Point3D( 3535, 2544, 20 ), Map.Trammel ); + } + } + + public class ThouAndThineShield : MLQuest + { + public ThouAndThineShield() + { + Activated = true; + OneTimeOnly = true; + Title = 1077704; // Thou and Thine Shield + Description = 1077707; // Head East out of town and go to Old Haven. Battle monsters, or simply let them hit you, while holding a shield or a weapon until you have raised your Parrying skill to 50. Oh, hello. You probably want me to teach you how to parry, don't you? Very Well. First, you'll need a weapon or a shield. Obviously shields work best of all, but you can parry with a 2-handed weapon. Or if you're feeling particularly brave, a 1-handed weapon will do in a pinch, I'd advise you to go to Old Haven, which you'll find to the East, and practice blocking incoming blows from the undead there. You'll learn quickly if you have more than one opponent attacking you at the same time to practice parrying lots of blows at once. That's the quickest way to master the art of parrying. If you manage to improve your skill enough, i have a shield that you might find useful. Come back to me when you've trained to an apprentice level. + RefusalMessage = 1077708; // It's your choice, obviously, but I'd highly suggest that you learn to parry before adventuring out into the world. Come talk to me again when you get tired of being beat on by your opponents + InProgressMessage = 1077709; // You're doing well, but in my opinion, I Don't think you really want to continue on without improving your parrying skill a bit more. Go to Old Haven, to the East, and practice blocking blows with a shield. + CompletionMessage = 1077711; // Well done! You're much better at parrying blows than you were when we first met. You should be proud of your new ability and I bet your body is greatful to you aswell. *Tyl Ariadne laughs loudly at his ownn (mostly lame) joke* Oh yes, I did promise you a shield if I thought you were worthy of having it, so here you go. My father made these shields for the guards who served my father faithfully for many years, and I just happen to have obe that i can part with. You should find it useful as you explore the lands.Good luck, and may the Virtues be your guide. + CompletionNotice = 1077710; // You have achieved the rank of Apprentice Warrior (for Parrying). Return to Tyl Ariadne in New Haven as soon as you can to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Parry, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077694, typeof( EscutcheonDeAriadne ) ) ); // Escutcheon de Ariadne + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "TylAriadne" ), new Point3D( 3525, 2556, 20 ), Map.Trammel ); + } + } + + public class DefyingTheArcane : MLQuest + { + public DefyingTheArcane() + { + Activated = true; + OneTimeOnly = true; + Title = 1077621; // Defying the Arcane + Description = 1077623; // Head East out of town and go to Old Haven. Battle spell casting monsters there until you have raised your Resisting Spells skill to 50.
------

Hail and well met! To become a true master of the arcane art of Magery, I suggest learning the complementary skill known as Resisting Spells. While the name of this skill may suggest that it helps with resisting all spells, this is not the case. This skill helps you lessen the severity of spells that lower your stats or ones that last for a specific duration of time. It does not lessen damage from spells such as Energy Bolt or Flamestrike.

The Magery spells that can be resisted are Clumsy, Curse, Feeblemind, Mana Drain, Mana Vampire, Paralyze, Paralyze Field, Poison, Poison Field, and Weaken.

The Necromancy spells that can be resisted are Blood Oath, Corpse Skin, Mind Rot, and Pain Spike.

At higher ranks, the Resisting Spells skill also benefits you by adding a bonus to your minimum elemental resists. This bonus is only applied after all other resist modifications - such as from equipment - has been calculated. It's also not cumulative. It compares the number of your minimum resists to the calculated value of your modifications and uses the higher of the two values.

As you can see, Resisting Spells is a difficult skill to understand, and even more difficult to master. This is because in order to improve it, you will have to put yourself in harm's way - as in the path of one of the above spells.

Undead have plagued the town of Old Haven. We need your assistance in cleansing the town of this evil influence. Old Haven is located east of here. Battle the undead spell casters that inhabit there.

Comeback to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize. + RefusalMessage = 1077624; // The ability to resist powerful spells is a taxing experience. I understand your resistance in wanting to pursue it. If you wish to reconsider, feel free to return to me for Resisting Spells training. Good journey to you! + InProgressMessage = 1077632; // You have not achieved the rank of Apprentice Mage. Come back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize. + CompletionMessage = 1077626; // You have successfully begun your journey in becoming a true master of Magery. On behalf of the New Haven Mage Council I wish to present you with this bracelet. When worn, the Bracelet of Resilience will enhance your resistances vs. the elements, physical, and poison harm. The Bracelet of Resilience also magically enhances your ability fend off ranged and melee attacks. I hope it serves you well. + CompletionNotice = 1077625; // You have achieved the rank of Apprentice Mage (for Resisting Spells). Return to Alefian in New Haven to receive your arcane prize. + + Objectives.Add( new GainSkillObjective( SkillName.MagicResist, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077627, typeof( BraceletOfResilience ) ) ); // Bracelet of Resilience + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Alefian" ), new Point3D( 3473, 2497, 72 ), Map.Trammel ); + } + } + + public class StoppingTheWorld : MLQuest + { + public StoppingTheWorld() + { + Activated = true; + OneTimeOnly = true; + Title = 1077597; // Stopping the World + Description = 1077598; // Head East out of town and go to Old Haven. Use spells and abilites to deplete your mana and meditate there until you have raised your Meditation skill to 50. Well met! I can teach you how to 'Stop the World' around you and focus your inner energies on replenishing you mana. What is mana? Mana is the life force for everyone who practices arcane arts. When a practitioner of magic invokes a spell or scribes a scroll. It consumes mana. Having a abundant supply of mana is vital to excelling as a practitioner of the arcane. Those of us who study the art of Meditation are also known as stotics. The Meditation skill allows stoics to increase the rate at which they regenerate mana A Stoic needs to perform abilities or cast spells to deplete mana before he can meditate to replenish it. Meditation can occur passively or actively. Actively Meditation is more difficult to master but allows for the stoic to replenish mana at a significantly faster rate. Metal armor inerferes with the regenerative properties of Meditation. It is wise to wear leather or cloth protection when meditating. Head east out of town and go to Old Haven. Use spells and abilities to deplete your mana and actively meditate to replenish it. Come back once you feel you are at the worthy rank of Apprentice Stoic and i will reward you with a arcane prize. + RefusalMessage = 1077599; // Seek me out if you ever wish to study the art of Meditation. Good journey. + InProgressMessage = 1077628; // You have not achived the rank of Apprentice Stoic. Come back to me once you feel that you are worthy of the rank Apprentice Stoic and i will reward you with a arcane prize. + CompletionMessage = 1077626; // You have successfully begun your journey in becoming a true master of Magery. On behalf of the New Haven Mage Council I wish to present you with this bracelet. When worn, the Bracelet of Resilience will enhance your resistances vs. the elements, physical, and poison harm. The Bracelet of Resilience also magically enhances your ability fend off ranged and melee attacks. I hope it serves you well. + CompletionNotice = 1077600; // You have achieved the rank of Apprentice Stoic (for Meditation). Return to Gustar in New Haven to receive your arcane prize. + + Objectives.Add( new GainSkillObjective( SkillName.Meditation, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077602, typeof( PhilosophersHat ) ) ); // Philosopher's Hat + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Gustar" ), new Point3D( 3474, 2492, 91 ), Map.Trammel ); + } + } + + public class ScribingArcaneKnowledge : MLQuest + { + public ScribingArcaneKnowledge() + { + Activated = true; + OneTimeOnly = true; + Title = 1077615; // Scribing Arcane Knowledge + Description = 1077616; // While Here ar the New Haven Magery Library, use scribe's pen and scribe 3rd and 4th circle Magery scrolls that you have in your spellbook. Remeber, you will need blank scrolls aswell. Do this until you have raised your Inscription skill to 50. Greetings and welcome to the New Haven Magery Library! You wish to learn how to scribe spell scrolls? You have come to the right place! Inscribeed in a steady hand and imbued with te power of reagents, a scroll can mean the difference between life and death in a perilous situation. Those knowledgeable in Inscription man transcribe spells to create useful and valuale magical scrolls. Before you can inscribe a spell, you must first be able to cast the spell without the aid of a scroll. This means that you need the appropriate level of proficiency as a mage, the required mana, and the required reagents. Second, you will need a blank scroll to write on and a scribe's pen. Then, you will need to decide which particular spell you wish to scribe. It may sound easy, but there is a bit more to it. As with the development of all skills, you need to practice Inscription of lower level spells before you can move onto the more difficult ones. The most important aspect of Inscription is mana. Inscribing a scroll with a magic spell drains your mana. When inscribing 3rd or lower spells this is will not be much of a problem for these spells consume a small amount of mana. However, when you are inscribing higher circle spells, you may see your mana drain rapidly. When this happens, pause or meditate before continuing.I suggest you begin scribing any 3rd and 4th circle spells that you know. If you don't possess ant, you can alwayers barter with one of the local mage merchants or a fellow adventurer that is a seasoned Scribe. Come back to me once you feel that you are the worthy rankof Apprentice Scribe and i will reward you with an arcane prize. + RefusalMessage = 1077617; // I understand. When you are ready, feel free to return to me for Inscription training. Thanks for stopping by! + InProgressMessage = 1077631; // You have not achived the rank of Apprentice Scribe. Come back to me once you feel that you are worthy of the rank Apprentice Scribe and i will reward you with a arcane prize. + CompletionMessage = 1077619; // Scribing is a very fulfilling pursuit. I am please to see you embark on this journey. You sling a pen well! On behalf of the New Haven Mage Council I wish to present you with this spellbook. When equipped, the Hallowed Spellbook greatly enhanced the potency of your offensive soells when used against Undead. Be mindful, though. While this book is equiped you invoke powerful spells and abilities vs Humanoids, such as other humans, orcs, ettins, and trolls. Your offensive spells will diminish in effectiveness. I suggest unequipping the Hallowed Spellbook when battling Humanoids. I hope this spellbook serves you well. + CompletionNotice = 1077618; // You have achieved the rank of Apprentice Scribe. Return to Jillian in New Haven to receive your arcane prize. + + Objectives.Add( new GainSkillObjective( SkillName.Inscribe, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077620, typeof( HallowedSpellbook ) ) ); // Hallowed Spellbook + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Jillian" ), new Point3D( 3465, 2490, 71 ), Map.Trammel ); + } + } + + public class TheMagesApprentice : MLQuest + { + public TheMagesApprentice() + { + Activated = true; + OneTimeOnly = true; + Title = 1077576; // The Mage's Apprentice + Description = 1077577; // Head East out of town and go to Old Haven. Cast fireballs and lightning bolts against monsters there until you have raised your Magery skill to 50. Greetings. You seek to unlock the secrets of the arcane art of Magery. The New Haven Mage Council has an assignment for you. Undead have plagued the town of Old Haven. We need your assistance in cleansing the town of this evil influence. Old Haven is located east of here. I suggest using your offensive Magery spells such as Fireball and Lightning Bolt against the Undead that inhabit there. Make sure you have plenty of reagents before embarking on your journey. Reagents are required to cast Magery spells. You can purchase extra reagents at the nearby Reagent shop, or you can find reagents growing in the nearby wooded areas. You can see which reagents are required for each spell by looking in your spellbook. Come back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize. + RefusalMessage = 1077578; // Very well, come back to me when you are ready to practice Magery. You have so much arcane potential. 'Tis a shame to see it go to waste. The New Haven Mage Council could really use your help. + InProgressMessage = 1077579; // You have not achieved the rank of Apprentice Mage. Come back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an arcane prize. + CompletionMessage = 1077581; // Well done! On behalf of the New Haven Mage Council I wish to present you with this staff. Normally a mage must unequip weapons before spell casting. While wielding your new Ember Staff, however, you will be able to invoke your Magery spells. Even if you do not currently possess skill in Mace Fighting, the Ember Staff will allow you to fight as if you do. However, your Magery skill will be temporarily reduced while doing so. Finally, the Ember Staff occasionally smites a foe with a Fireball while wielding it in melee combat. I hope the Ember Staff serves you well. + CompletionNotice = 1077580; // You have achieved the rank of Apprentice Mage. Return to Kaelynna in New Haven to receive your arcane prize. + + Objectives.Add( new GainSkillObjective( SkillName.Magery, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077582, typeof( EmberStaff ) ) ); // Ember Staff + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Kaelynna" ), new Point3D( 3486, 2491, 52 ), Map.Trammel ); + } + } + + public class ScholarlyTask : MLQuest + { + public ScholarlyTask() + { + Activated = true; + OneTimeOnly = true; + Title = 1077603; // A Scholarly Task + Description = 1077604; // Head East out of town and go to Old Haven. Use Evaluating Intelligence on all creatures you see there. You can also cast Magery spells as well to raise Evaluating Intelligence. Do these activities until you have raised your Evaluating Intelligence skill to 50.
------

Hello. Truly knowing your opponent is essential for landing your offensive spells with precision. I can teach you how to enhance the effectiveness of your offensive spells, but first you must learn how to size up your opponents intellectually. I have a scholarly task for you. Head East out of town and go to Old Haven. Use Evaluating Intelligence on all creatures you see there. You can also cast Magery spells as well to raise Evaluating Intelligence.

Come back to me once you feel that you are worthy of the rank of Apprentice Scholar and I will reward you with an arcane prize. + RefusalMessage = 1077605; // Return to me if you reconsider and wish to become an Apprentice Scholar. + InProgressMessage = 1077629; // You have not achieved the rank of Apprentice Scholar. Come back to me once you feel that you are worthy of the rank of Apprentice Scholar and I will reward you with an arcane prize. + CompletionMessage = 1077607; // You have completed the task. Well done. On behalf of the New Haven Mage Council I wish to present you with this ring. When worn, the Ring of the Savant enhances your intellectual aptitude and increases your mana pool. Your spell casting abilities will take less time to invoke and recovering from such spell casting will be hastened. I hope the Ring of the Savant serves you well. + CompletionNotice = 1077606; // You have achieved the rank of Apprentice Scholar. Return to Mithneral in New Haven to receive your arcane prize. + + Objectives.Add( new GainSkillObjective( SkillName.EvalInt, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077608, typeof( RingOfTheSavant ) ) ); // Ring of the Savant + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mithneral" ), new Point3D( 3485, 2491, 71 ), Map.Trammel ); + } + } + + public class TheRightToolForTheJob : MLQuest + { + public TheRightToolForTheJob() + { + Activated = true; + OneTimeOnly = true; + Title = 1077741; // The Right Tool for the Job + Description = 1077744; // Create new scissors and hammers while inside Amelia's workshop. Try making scissors up to 45 skill, the switch to making hammers until 50 skill.
-----

Hello! I guess you're here to learn something about Tinkering, eh? You've come to the right place, as Tinkering is what I've dedicated my life to.

You'll need two things to get started: a supply of ingots and the right tools for the job. You can either buy ingots from the market, or go mine them yourself. As for tools, you can try making your own set of Tinker's Tools, or if you'd prefer to buy them, I have some for sale.

Working here in my shop will let me give you pointers as you go, so you'll be able to learn faster than anywhere else. Start off making scissors until you reach 45 tinkering skill, then switch to hammers until you've achieved 50. Once you've done that, come talk to me and I'll give you something for your hard work. + RefusalMessage = 1077745; // I�m disappointed that you aren�t interested in learning more about Tinkering. It�s really such a useful skill!

*Amelia smiles*

At least you know where to find me if you change your mind, since I rarely spend time outside of this shop. + InProgressMessage = 1077746; // Nice going! You're not quite at Apprentice Tinkering yet, though, so you better get back to work. Remember that the quickest way to learn is to make scissors up until 45 skill, and then switch to hammers. Also, don't forget that working here in my shop will let me give you tips so you can learn faster. + CompletionMessage = 1077748; // You've done it! Look at our brand new Apprentice Tinker! You've still got quite a lot to learn if you want to be a Grandmaster Tinker, but I believe you can do it! Just keep in mind that if you're tinkering just to practice and improve your skill, make items that are moderately difficult (60-80% success chance), and try to stick to ones that use less ingots.

Come here, my brand new Apprentice Tinker, I want to give you something special. I created this just for you, so I hope you like it. It's a set of Tinker's Tools that contains a bit of magic. These tools have more charges than any Tinker's Tools a Tinker can make. You can even use them to make a normal set of tools, so that way you won't ever find yourself stuck somewhere with no tools! + CompletionNotice = 1077747; // You have achieved the rank of Apprentice Tinker. Talk to Amelia Youngstone in New Haven to see what kind of reward she has waiting for you. + + Objectives.Add( new GainSkillObjective( SkillName.Tinkering, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077749, typeof( AmeliasToolbox ) ) ); // Amelia�s Toolbox + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "AmeliaYoungstone" ), new Point3D( 3459, 2529, 53 ), Map.Trammel ); + } + } + + public class KnowThineEnemy : MLQuest + { + public KnowThineEnemy() + { + Activated = true; + OneTimeOnly = true; + Title = 1077685; // Know Thine Enemy + Description = 1077688; // Head East out of town to Old Haven. Battle monsters there, or heal yourself and other players, until you have raised your Anatomy skill to 50.
------

Hail and well met. You must be here to improve your knowledge of Anatomy. Well, you've come to the right place because I can teach you what you need to know. At least all you'll need to know for now. Haha!

Knowing about how living things work inside can be a very useful skill. Not only can you learn where to strike an opponent to hurt him the most, but you can use what you learn to heal wounds better as well. Just walking around town, you can even tell if someone is strong or weak or if they happen to be particularly dexterous or not.

If you're interested in learning more, I'd advise you to head out to Old Haven, just to the east, and jump into the fray. You'll learn best by engaging in combat while keeping you and your fellow adventurers healed, or you can even try sizing up your opponents.

While you're gone, I'll dig up something you may find useful. + RefusalMessage = 1077689; // It's your choice, but I wouldn't head out there without knowing what makes those things tick inside! If you change your mind, you can find me right here dissecting frogs, cats or even the occasional unlucky adventurer. + InProgressMessage = 1077690; // I'm surprised to see you back so soon. You've still got a ways to go if you want to really understand the science of Anatomy. Head out to Old Haven and practice combat and healing yourself or other adventurers. + CompletionMessage = 1077692; // By the Virtues, you've done it! Congratulations mate! You still have quite a ways to go if you want to perfect your knowledge of Anatomy, but I know you'll get there someday. Just keep at it.

In the meantime, here's a piece of armor that you might find useful. It's not fancy, but it'll serve you well if you choose to wear it.

Happy adventuring, and remember to keep your cranium separate from your clavicle! + CompletionNotice = 1077691; // You have achieved the rank of Apprentice Healer (for Anatomy). Return to Andreas Vesalius in New Haven as soon as you can to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Anatomy, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077693, typeof( TunicOfGuarding ) ) ); // Tunic of Guarding + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "AndreasVesalius" ), new Point3D( 3457, 2550, 35 ), Map.Trammel ); + } + } + + public class BruisesBandagesAndBlood : MLQuest + { + public BruisesBandagesAndBlood() + { + Activated = true; + OneTimeOnly = true; + Title = 1077676; // Bruises, Bandages and Blood + Description = 1077679; // Head East out of town and go to Old Haven. Heal yourself and other players until you have raised your Healing skill to 50.
------

Ah, welcome to my humble practice. I am Avicenna, New Haven's resident Healer. A lot of adventurers head out into the wild from here, so I keep rather busy when they come back bruised, bleeding, or worse.

I can teach you how to bandage a wound, sure, but it's not a job for the queasy! For some folks, the mere sight of blood is too much for them, but it's something you'll get used to over time. It is one thing to cut open a living thing, but it's quite another to sew it back up and save it from sure death. 'Tis noble work, healing.

Best way for you to practice fixing up wounds is to head east out to Old Haven and either practice binding up your own wounds, or practice on someone else. Surely they'll be grateful for the assistance.

Make sure to take enough bandages with you! You don't want to run out in the middle of a tough fight. + RefusalMessage = 1077680; // No? Are you sure? Well, when you feel that you're ready to practice your healing, come back to me. I'll be right here, fixing up adventurers and curing the occasional cold! + InProgressMessage = 1077681; // Hail! 'Tis good to see you again. Unfortunately, you're not quite ready to call yourself an Apprentice Healer quite yet. Head back out to Old Haven, due east from here, and bandage up some wounds. Yours or someone else's, it doesn't much matter. + CompletionMessage = 1077683; // Hello there, friend. I see you've returned in one piece, and you're an Apprentice Healer to boot! You should be proud of your accomplishment, as not everyone has "the touch" when it comes to healing.

I can't stand to see such good work go unrewarded, so I have something I'd like you to have. It's not much, but it'll help you heal just a little faster, and maybe keep you alive.

Good luck out there, friend, and don't forget to help your fellow adventurer whenever possible! + CompletionNotice = 1077682; // You have achieved the rank of Apprentice Healer. Return to Avicenna in New Haven as soon as you can to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Healing, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077684, typeof( HealersTouch ) ) ); // Healer's Touch + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Avicenna" ), new Point3D( 3464, 2558, 35 ), Map.Trammel ); + } + } + + public class TheInnerWarrior : MLQuest + { + public TheInnerWarrior() + { + Activated = true; + OneTimeOnly = true; + Title = 1077696; // The Inner Warrior + Description = 1077699; // Head East out of town to Old Haven. Expend stamina and mana until you have raised your Focus skill to 50.
------

Well, hello there. Don't you look like quite the adventurer!

You want to learn more about Focus, do you? I can teach you something about that, but first you should know that not everyone can be disciplined enough to excel at it. Focus is the ability to achieve inner balance in both body and spirit, so that you recover from physical and mental exertion faster than you otherwise would.

If you want to practice Focus, the best place to do that is east of here, in Old Haven, where you'll find an undead infestation. Exert yourself physically by engaging in combat and moving quickly. For testing your mental balance, expend mana in whatever way you find most suitable to your abilities. Casting spells and using abilities work well for consuming your mana.

Go. Train hard, and you will find that your concentration will improve naturally. When you've improved your ability to focus yourself at an Apprentice level, come back to me and I shall give you something worthy of your new ability. + RefusalMessage = 1077700; // I'm disappointed. You have a lot of inner potential, and it would pain me greatly to see you waste that. Oh well. If you change your mind, I'll be right here. + InProgressMessage = 1077701; // Hello again. I see you've returned, but it seems that your Focus skill hasn't improved as much as it could have. Just head east, to Old Haven, and exert yourself physically and mentally as much as possible. To do this physically, engage in combat and move as quickly as you can. For exerting yourself mentally, expend mana in whatever way you find most suitable to your abilities. Casting spells and using abilities work well for consuming your mana.

Return to me when you have gained enough Focus skill to be considered an Apprentice Stoic. + CompletionMessage = 1077703; // Look who it is! I knew you could do it if you just had the discipline to apply yourself. It feels good to recover from battle so quickly, doesn't it? Just wait until you become a Grandmaster, it's amazing!

Please take this gift, as you've more than earned it with your hard work. It will help you recover even faster during battle, and provides a bit of protection as well.

You have so much more potential, so don't stop trying to improve your Focus now! Safe travels! + CompletionNotice = 1077702; // You have achieved the rank of Apprentice Stoic (for Focus). Return to Sarsmea Smythe in New Haven to see what kind of reward she has waiting for you. + + Objectives.Add( new GainSkillObjective( SkillName.Focus, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077695, typeof( ClaspOfConcentration ) ) ); // Clasp of Concentration + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "SarsmeaSmythe" ), new Point3D( 3492, 2577, 15 ), Map.Trammel ); + } + } + + public class TheArtOfStealth : MLQuest + { + public TheArtOfStealth() + { + Activated = true; + OneTimeOnly = true; + Title = 1078154; // The Art of Stealth + Description = 1078158; // Head East out of town and go to Old Haven. While wielding your fencing weapon, battle monsters with focus attack and summon mirror images up to 40 Ninjitsu skill, and continue practicing focus attack on monsters until 50 Ninjitsu skill.
------

Welcome, young one. You seek to learn Ninjitsu. With it, and the book of Ninjitsu, a Ninja can evoke a number of special abilities including transforming into a variety of creatures that give unique bonuses, using stealth to attack unsuspecting opponents or just plain disappear into thin air! If you do not have a book of Ninjitsu, you can purchase one from me.

I have an assignment for you. Head East out of town and go to Old Haven. While wielding your fencing weapon, battle monsters with focus attack and summon mirror images up to Novice rank, and continue focusing your attacks for greater damage on monsters until you become an Apprentice Ninja. Each image will absorb one attack. The art of deception is a strong defense. Use it wisely.

Come back to me once you have achieved the rank of Apprentice Ninja, and I shall reward you with something useful. + RefusalMessage = 1078159; // Come back to me if you with to learn Ninjitsu in the future. + InProgressMessage = 1078160; // You have not achieved the rank of Apprentice Ninja. Come back to me once you have done so. + CompletionMessage = 1078162; // You have done well, young one. Please accept this kryss as a gift. It is called the "Silver Serpent Blade". With it, you will strike with precision and power. This should aid you in your journey as a Ninja. Farewell. + CompletionNotice = 1078161; // You have achieved the rank of Apprentice Ninja. Return to Ryuichi in New Haven to see what kind of reward he has waiting for you. + + Objectives.Add( new GainSkillObjective( SkillName.Ninjitsu, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078163, typeof( SilverSerpentBlade ) ) ); // Silver Serpent Blade + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Ryuichi" ), new Point3D( 3422, 2520, 21 ), Map.Trammel ); + } + } + + public class BecomingOneWithTheShadows : MLQuest + { + public BecomingOneWithTheShadows() + { + Activated = true; + OneTimeOnly = true; + Title = 1078164; // Becoming One with the Shadows + Description = 1078168; // Practice hiding in the Ninja Dojo until you reach 50 Hiding skill.
------

Come closer. Don't be afraid. The shadows will not harm you. To be a successful Ninja, you must learn to become one with the shadows. The Ninja Dojo is the ideal place to learn the art of concealment. Practice hiding here.

Talk to me once you have achieved the rank of Apprentice Rogue (for Hiding), and I shall reward you. + RefusalMessage = 1078169; // If you wish to become one with the shadows, come back and talk to me. + InProgressMessage = 1078170; // You have not achieved the rank of Apprentice Rogue (for Hiding). Talk to me when you feel you have accomplished this. + CompletionMessage = 1078172; // Not bad at all. You have learned to control your fear of the dark and you are becoming one with the shadows. If you haven't already talked to Jun, I advise you do so. Jun can teach you how to stealth undetected. Hiding and Stealth are essential skills to master when becoming a Ninja.

As promised, I have a reward for you. Here are some smokebombs. As long as you are an Apprentice Ninja and have mana available you will be able to use them. They will allow you to hide while in the middle of combat. I hope these serve you well. + CompletionNotice = 1078171; // You have achieved the rank of Apprentice Rogue (for Hiding). Return to Chiyo in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Hiding, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078173, typeof( BagOfSmokeBombs ) ) ); // Bag of Smoke Bombs + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Chiyo" ), new Point3D( 3420, 2516, 21 ), Map.Trammel ); + } + } + + public class WalkingSilently : MLQuest + { + public WalkingSilently() + { + Activated = true; + OneTimeOnly = true; + Title = 1078174; // Walking Silently + Description = 1078178; // Head East out of town and go to Old Haven. While wearing normal clothes, practice Stealth there until you reach 50 Stealth skill.
------

You there. You're not very quiet in your movements. I can help you with that. Not only must you must learn to become one with the shadows, but also you must learn to quiet your movements. Old Haven is the ideal place to learn how to Stealth.

Head East out of town and go to Old Haven. While wearing normal clothes, practice Stealth there. Stealth becomes more difficult as you wear heavier pieces of armor, so for now, only wear clothes while practicing Stealth.

You can only Stealth once you are hidden. If you become visible, use your Hiding skill, and begin slowing walking.

Come back to me once you have achieved the rank of Apprentice Rogue (for Stealth), and I will reward you with something useful. + RefusalMessage = 1078179; // If you want to learn to quiet your movements, talk to me, and I will help you. + InProgressMessage = 1078180; // You have not achieved the rank of Apprentice Rogue (for Stealth). Come back to me when you feel you have accomplished this. + CompletionMessage = 1078182; // Good. You have learned to quiet your movements. If you haven't already talked to Chiyo, I advise you do so. Chiyo can teach you how to become one with the shadows. Hiding and Stealth are essential skills to master when becoming a Ninja.

Here is your reward. This leather Ninja jacket is called "Twilight Jacket". It will offer greater protection to you. I hope this serve you well. + CompletionNotice = 1078181; // You have achieved the rank of Apprentice Rogue (for Stealth). Return to Jun in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Stealth, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078183, typeof( TwilightJacket ) ) ); // Twilight Jacket + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Jun" ), new Point3D( 3422, 2516, 21 ), Map.Trammel ); + } + } + + public class EyesOfARanger : MLQuest + { + public EyesOfARanger() + { + Activated = true; + OneTimeOnly = true; + Title = 1078211; // Eyes of a Ranger + Description = 1078217; // Track animals, monsters, and people on Haven Island until you have raised your Tracking skill to 50.
------

Hello friend. I am Walker, Grandmaster Ranger. An adventurer needs to keep alive in the wilderness. Being able to track those around you is essential to surviving in dangerous places. Certain Ninja abilities are more potent when the Ninja possesses Tracking knowledge. If you want to be a Ninja, or if you simply want to get a leg up on the creatures that habit these parts, I advise you learn how to track them.

You can track any animals, monsters, or people on Haven Island. Clear your mind, focus, and note any tracks in the ground or sounds in the air that can help you find your mark. You can do it, friend. I have faith in you.

Come back to me once you have achieved the rank of Apprentice Ranger (for Tracking), and I will give you something that may help you in your travels. Take care, friend. + RefusalMessage = 1078218; // Farewell, friend. Be careful out here. If you change your mind and want to learn Tracking, come back and talk to me. + InProgressMessage = 1078219; // So far so good, kid. You are still alive, and you are getting the hang of Tracking. There are many more animals, monsters, and people to track. Come back to me once you have tracked them. + CompletionMessage = 1078221; // I knew you could do it! You have become a fine Ranger. Just keep practicing, and one day you will become a Grandmaster Ranger. Just like me.

I have a little something for you that will hopefully aid you in your journeys. These leggings offer some resistances that will hopefully protect you from harm. I hope these serve you well. Farewell, friend. + CompletionNotice = 1078220; // You have achieved the rank of Apprentice Ranger (for Tracking). Return to Walker in New Haven to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Tracking, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078222, typeof( WalkersLeggings ) ) ); // Walker's Leggings + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Walker" ), new Point3D( 3429, 2518, 19 ), Map.Trammel ); + } + } + + public class TheWayOfTheSamurai : MLQuest + { + public TheWayOfTheSamurai() + { + Activated = true; + OneTimeOnly = true; + Title = 1078007; // The Way of the Samurai + Description = 1078010; // Head East out of town and go to Old Haven. use the Confidence defensive stance and attempt to honorably execute monsters there until you have raised your Bushido skill to 50.
------

Greetings. I see you wish to learn the Way of the Samurai. Wielding a blade is easy. Anyone can grasp a sword's hilt. Learning how to fight properly and skillfully is to become an Armsman. Learning how to master weapons, and even more importantly when not to use them, is the Way of the Warrior. The Way of the Samurai. The Code of the Bushido. That is why you are here.

Adventure East to Old Haven. Use the Confidence defensive stance and attempt to honorably execute the undead that inhabit there. You will need a book of Bushido to perform these abilities. If you do not possess a book of Bushido, you can purchase one from me.

If you fail to honorably execute the undead, your defenses will be greatly weakened: Resistances will suffer and Resisting Spells will suffer. A successful parry instantly ends the weakness. If you succeed, however, you will be infused with strength and healing. Your swing speed will also be boosted for a short duration. With practice, you will learn how to master your Bushido abilities.

Return to me once you feel that you have become an Apprentice Samurai. + RefusalMessage = 1078011; // Good journey to you. Return to me if you wish to live the life of a Samurai. + InProgressMessage = 1078012; // You are not ready to become an Apprentice Samurai. There are still more undead to lay to rest. Return to me once you have done so. + CompletionMessage = 1078014; // You have proven yourself young one. You will continue to improve as your skills are honed with age. You are an honorable warrior, worthy of the rank of Apprentice Samurai. Please accept this no-dachi as a gift. It is called "The Dragon's Tail". Upon a successful strike in combat, there is a chance this mighty weapon will replenish your stamina equal to the damage of your attack. I hope "The Dragon's Tail" serves you well. You have earned it. Farewell for now. + CompletionNotice = 1078013; // You have achieved the rank of Apprentice Samurai. Return to Hamato in New Haven to report your progress. + + Objectives.Add( new GainSkillObjective( SkillName.Bushido, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078015, typeof( TheDragonsTail ) ) ); // The Dragon's Tail + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Hamato" ), new Point3D( 3493, 2414, 55 ), Map.Trammel ); + } + } + + public class TheAllureOfDarkMagic : MLQuest + { + public TheAllureOfDarkMagic() + { + Activated = true; + OneTimeOnly = true; + Title = 1078036; // The Allure of Dark Magic + Description = 1078039; // Head East out of town and go to Old Haven. Cast Evil Omen and Pain Spike against monsters there until you have raised your Necromancy skill to 50.
------

Welcome! I see you are allured by the dark magic of Necromancy. First, you must prove yourself worthy of such knowledge. Undead currently occupy the town of Old Haven. Practice your harmful Necromancy spells on them such as Evil Omen and Pain Spike.

Make sure you have plenty of reagents before embarking on your journey. Reagents are required to cast Necromancy spells. You can purchase extra reagents from me, or you can find reagents growing in the nearby wooded areas. You can see which reagents are required for each spell by looking in your spellbook.

Come back to me once you feel that you are worthy of the rank of Apprentice Necromancer and I will reward you with the knowledge you desire. + RefusalMessage = 1078040; // You are weak after all. Come back to me when you are ready to practice Necromancy. + InProgressMessage = 1078041; // You have not achieved the rank of Apprentice Necromancer. Come back to me once you feel that you are worthy of the rank of Apprentice Necromancer and I will reward you with the knowledge you desire. + CompletionMessage = 1078043; // You have done well, my young apprentice. Behold! I now present to you the knowledge you desire. This spellbook contains all the Necromancer spells. The power is intoxicating, isn't it? + CompletionNotice = 1078042; // You have achieved the rank of Apprentice Necromancer. Return to Mulcivikh in New Haven to receive the knowledge you desire. + + Objectives.Add( new GainSkillObjective( SkillName.Necromancy, 500, true, true ) ); + + Rewards.Add( new InternalReward() ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mulcivikh" ), new Point3D( 3548, 2456, 15 ), Map.Trammel ); + } + + private class InternalReward : ItemReward + { + public InternalReward() + : base( 1078052, typeof( NecromancerSpellbook ) ) // Complete Necromancer Spellbook + { + } + + public override Item CreateItem() + { + Item item = base.CreateItem(); + + Spellbook book = item as Spellbook; + + if ( book != null ) + book.Content = ( 1ul << book.BookCount ) - 1; + + return item; + } + } + } + + public class ChannelingTheSupernatural : MLQuest + { + public ChannelingTheSupernatural() + { + Activated = true; + OneTimeOnly = true; + Title = 1078044; // Channeling the Supernatural + Description = 1078047; // Head East out of town and go to Old Haven. Use Spirit Speak and channel energy from either yourself or nearby corpses there. You can also cast Necromancy spells as well to raise Spirit Speak. Do these activities until you have raised your Spirit Speak skill to 50.
------

How do you do? Channeling the supernatural through Spirit Speak allows you heal your wounds. Such channeling expends your mana, so be mindful of this. Spirit Speak enhances the potency of your Necromancy spells. The channeling powers of a Medium are quite useful when practicing the dark magic of Necromancy.

It is best to practice Spirit Speak where there are a lot of corpses. Head East out of town and go to Old Haven. Undead currently reside there. Use Spirit Speak and channel energy from either yourself or nearby corpses. You can also cast Necromancy spells as well to raise Spirit Speak.

Come back to me once you feel that you are worthy of the rank of Apprentice Medium and I will reward you with something useful. + RefusalMessage = 1078048; // Channeling the supernatural isn't for everyone. It is a dark art. See me if you ever wish to pursue the life of a Medium. + InProgressMessage = 1078049; // Back so soon? You have not achieved the rank of Apprentice Medium. Come back to me once you feel that you are worthy of the rank of Apprentice Medium and I will reward you with something useful. + CompletionMessage = 1078051; // Well done! Channeling the supernatural is taxing, indeed. As promised, I will reward you with this bag of Necromancer reagents. You will need these if you wish to also pursue the dark magic of Necromancy. Good journey to you. + CompletionNotice = 1078050; // You have achieved the rank of Apprentice Medium. Return to Morganna in New Haven to receive your reward. + + Objectives.Add( new GainSkillObjective( SkillName.SpiritSpeak, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1078053, typeof( BagOfNecromancerReagents ) ) ); // Bag of Necromancer Reagents + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Morganna" ), new Point3D( 3547, 2463, 15 ), Map.Trammel ); + } + } + + public class TheDeluciansLostMine : MLQuest + { + public TheDeluciansLostMine() + { + Activated = true; + OneTimeOnly = true; + Title = 1077750; // The Delucian�s Lost Mine + Description = 1077753; // Find Jacob's Lost Mine and mine iron ore there, using a pickaxe or shovel. Bring it back to Jacob's forge and smelt the ore into ingots, until you have raised your Mining skill to 50. You may find a packhorse useful for hauling the ore around. The animal trainer in New Haven has packhorses for sale.
-----

Howdy! Welcome to my camp. It's not much, I know, but it's all I'll be needin' up here. I don't need them fancy things those townspeople have down there in New Haven. Nope, not one bit. Just me, Bessie, my pick and a thick vein 'o valorite.

Anyhows, I'm guessin' that you're up here to ask me about minin', aren't ya? Well, don't be expectin' me to tell you where the valorite's at, cause I ain't gonna tell the King of Britannia, much less the likes of you. But I will show ya how to mine and smelt iron, cause there certainly is a 'nough of up in these hills.

*Jacob looks around, with a perplexed look on his face*

Problem is, I can't remember where my iron mine's at, so you'll have to find it yourself. Once you're there, have at it with a pickaxe or shovel, then haul it back to camp and I'll show ya how to smelt it. Ya look a bit wimpy, so you might wanna go buy yourself a packhorse in town from the animal trainer to help you haul around all that ore.

When you're an Apprentice Miner, talk to me and I'll give ya a little somethin' I've got layin' around here... somewhere. + RefusalMessage = 1077754; // Couldn�t find my iron mine, could ya? Well, neither can I!

*Jacob laughs*

Oh, ya don�t wanna find it? Well, allrighty then, ya might as well head on back down to town then and stop cluttering up my camp. Come back and talk to me if you�re interested in learnin� �bout minin�. + InProgressMessage = 1077755; // Where ya been off a gallivantin� all day, pilgrim? You ain�t seen no hard work yet! Get yer arse back out there to my mine and dig up some more iron. Don�t forget to take a pickaxe or shovel, and if you�re so inclined, a packhorse too. + CompletionMessage = 1077757; // Dang gun it! If that don't beat all! Ya went and did it, didn�t ya? What we got ourselves here is a mighty fine brand spankin� new Apprentice Miner!

I can see ya put some meat on them bones too while you were at it!

Here�s that little somethin� I told ya I had for ya. It�s a pickaxe with some high falutin� magic inside that�ll help you find the good stuff when you�re off minin�. It wears out fast, though, so you can only use it a few times a day.

Welp, I�ve got some smeltin� to do, so off with ya. Good luck, pilgrim! + CompletionNotice = 1077756; // You have achieved the rank of Apprentice Miner. Return to Jacob Waltz in at his camp in the hills above New Haven as soon as you can to claim your reward. + + Objectives.Add( new GainSkillObjective( SkillName.Mining, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077758, typeof( JacobsPickaxe ) ) ); // Jacob's Pickaxe + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "JacobWaltz" ), new Point3D( 3504, 2741, 0 ), Map.Trammel ); + } + } + + public class ItsHammerTime : MLQuest + { + public ItsHammerTime() + { + Activated = true; + OneTimeOnly = true; + Title = 1077732; // It�s Hammer Time! + Description = 1077735; // Create new daggers and maces using the forge and anvil in George's shop. Try making daggers up to 45 skill, the switch to making maces until 50 skill.
-----

Hail, and welcome to my humble shop. I'm George Hephaestus, New Haven's blacksmith. I assume that you're here to ask me to train you to be an Apprentice Blacksmith. I certainly can do that, but you're going to have to supply your own ingots.

You can always buy them at the market, but I highly suggest that you mine your own. That way, any items you sell will be pure profit!

So, once you have a supply of ingots, use my forge and anvil here to create items. You'll also need a supply of the proper tools; you can use a smith's hammer, a sledgehammer or tongs. You can either make them yourself if you have the tinkering skill, or buy them from a tinker at the market.

Since I'll be around to give you advice, you'll learn faster here than anywhere else. Start off making daggers until you reach 45 blacksmithing skill, then switch to maces until you've achieved 50. Once you've done that, come talk to me and I'll give you something for your hard work. + RefusalMessage = 1077736; // You're not interested in learning to be a smith, eh? I thought for sure that's why you were here. Oh well, if you change your mind, you can always come back and talk to me. + InProgressMessage = 1077737; // You�re doing well, but you�re not quite there yet. Remember that the quickest way to learn is to make daggers up until 45 skill, and then switch to maces. Also, don�t forget that using my forge and anvil will help you learn faster. + CompletionMessage = 1077739; // I've been watching you get better and better as you've been smithing, and I have to say, you're a natural! It's a long road to being a Grandmaster Blacksmith, but I have no doubt that if you put your mind to it you'll get there someday. Let me give you one final piece of advice. If you're smithing just to practice and improve your skill, make items that are moderately difficult (60-80% success chance), and try to stick to ones that use less ingots.

Now that you're an Apprentice Blacksmith, I have something for you. While you were busy practicing, I was crafting this hammer for you. It's finely balanced, and has a bit of magic imbued within that will help you craft better items. However, that magic needs to restore itself over time, so you can only use it so many times per day. I hope you find it useful! + CompletionNotice = 1077738; // You have achieved the rank of Apprentice Blacksmith. Return to George Hephaestus in New Haven to see what kind of reward he has waiting for you. + + Objectives.Add( new GainSkillObjective( SkillName.Blacksmith, 500, true, true ) ); + + Rewards.Add( new ItemReward( 1077740, typeof( HammerOfHephaestus ) ) ); // Hammer of Hephaestus + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "GeorgeHephaestus" ), new Point3D( 3471, 2542, 36 ), Map.Trammel ); + } + } + + #endregion + + #region Mobiles + + public class Aelorn : KeeperOfChivalry + { + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078133 ); // Hail, friend. Want to live the life of a paladin? + } + + [Constructable] + public Aelorn() + { + Name = "Aelorn"; + Title = "the Chivalry Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x47D; + FacialHairItemID = 0x204D; + FacialHairHue = 0x47D; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + SetSkill( SkillName.Chivalry, 120.0 ); + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new VikingSword() ); + AddItem( new PlateChest() ); + AddItem( new PlateLegs() ); + AddItem( new PlateGloves() ); + AddItem( new PlateArms() ); + AddItem( new PlateGorget() ); + AddItem( new OrderShield() ); + } + + public Aelorn( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Dimethro : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078128 ); // You there! Wanna master hand to hand defense? Of course you do! + } + + [Constructable] + public Dimethro() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Dimethro"; + Title = "the Wrestling Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203D; + HairHue = 0x455; + FacialHairItemID = 0x204D; + FacialHairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Inscribe, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Sandals( 0x455 ) ); + AddItem( new BodySash( 0x455 ) ); + AddItem( new LongPants( 0x455 ) ); + } + + public Dimethro( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Churchill : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078141 ); // Don't listen to Jockles. Real warriors wield mace weapons! + } + + [Constructable] + public Churchill() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Churchill"; + Title = "the Mace Fighting Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Macing, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new OrderShield() ); + AddItem( new WarMace() ); + + Item item; + + item = new PlateLegs(); + item.Hue = 0x966; + AddItem( item ); + + item = new PlateGloves(); + item.Hue = 0x966; + AddItem( item ); + + item = new PlateGorget(); + item.Hue = 0x966; + AddItem( item ); + + item = new PlateChest(); + item.Hue = 0x966; + AddItem( item ); + + item = new PlateArms(); + item.Hue = 0x966; + AddItem( item ); + } + + public Churchill( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Robyn : Bowyer + { + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078202 ); // Archery requires a steady aim and dexterous fingers. + } + + [Constructable] + public Robyn() + { + Name = "Robyn"; + Title = "the Archery Instructor"; + BodyValue = 0x191; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x47D; + Female = true; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Fletching, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Archery, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new Boots( 0x592 ) ); + AddItem( new Cloak( 0x592 ) ); + AddItem( new Bandana( 0x592 ) ); + AddItem( new CompositeBow() ); + + Item item; + + item = new StuddedLegs(); + item.Hue = 0x592; + AddItem( item ); + + item = new StuddedGloves(); + item.Hue = 0x592; + AddItem( item ); + + item = new StuddedGorget(); + item.Hue = 0x592; + AddItem( item ); + + item = new StuddedChest(); + item.Hue = 0x592; + AddItem( item ); + + item = new StuddedArms(); + item.Hue = 0x592; + AddItem( item ); + } + + public Robyn( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Recaro : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078187 ); // The art of fencing requires a dexterous hand, a quick wit and fleet feet. + } + + [Constructable] + public Recaro() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Recaro"; + Title = "the Fencer Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x455; + FacialHairItemID = 0x204D; + FacialHairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Fencing, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Shoes( 0x455 ) ); + AddItem( new WarFork() ); + + Item item; + + item = new StuddedLegs(); + item.Hue = 0x455; + AddItem( item ); + + item = new StuddedGloves(); + item.Hue = 0x455; + AddItem( item ); + + item = new StuddedGorget(); + item.Hue = 0x455; + AddItem( item ); + + item = new StuddedChest(); + item.Hue = 0x455; + AddItem( item ); + + item = new StuddedArms(); + item.Hue = 0x455; + AddItem( item ); + } + + public Recaro( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AldenArmstrong : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078136 ); // There is an art to slaying your enemies swiftly. It's called tactics, and I can teach it to you. + } + + [Constructable] + public AldenArmstrong() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Alden Armstrong"; + Title = "the Tactics Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203B; + HairHue = 0x44E; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Shoes() ); + AddItem( new StuddedLegs() ); + AddItem( new StuddedGloves() ); + AddItem( new StuddedGorget() ); + AddItem( new StuddedChest() ); + AddItem( new StuddedArms() ); + AddItem( new Katana() ); + } + + public AldenArmstrong( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Jockles : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078135 ); // Talk to me to learn the way of the blade. + } + + [Constructable] + public Jockles() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Jockles"; + Title = "the Swordsmanship Instructor"; + BodyValue = 0x190; + Hue = 0x83FA; + HairItemID = 0x203C; + HairHue = 0x8A7; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Broadsword() ); + AddItem( new PlateChest() ); + AddItem( new PlateLegs() ); + AddItem( new PlateGloves() ); + AddItem( new PlateArms() ); + AddItem( new PlateGorget() ); + AddItem( new OrderShield() ); + } + + public Jockles( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TylAriadne : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078140 ); // Want to learn how to parry blows? + } + + [Constructable] + public TylAriadne() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tyl Ariadne"; + Title = "the Parrying Instructor"; + BodyValue = 0x190; + Hue = 0x8374; + HairItemID = 0; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new ElvenBoots( 0x96D ) ); + + Item item; + + item = new StuddedLegs(); + item.Hue = 0x96D; + AddItem( item ); + + item = new StuddedGloves(); + item.Hue = 0x96D; + AddItem( item ); + + item = new StuddedGorget(); + item.Hue = 0x96D; + AddItem( item ); + + item = new StuddedChest(); + item.Hue = 0x96D; + AddItem( item ); + + item = new StuddedArms(); + item.Hue = 0x96D; + AddItem( item ); + + item = new DiamondMace(); + item.Hue = 0x96D; + AddItem( item ); + } + + public TylAriadne( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Alefian : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078130 ); // A mage should learn how to resist spells. + } + + [Constructable] + public Alefian() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Alefian"; + Title = "the Resisting Spells Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203D; + HairHue = 0x457; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Inscribe, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Robe() ); + AddItem( new Sandals() ); + } + + public Alefian( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Gustar : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078126 ); // Meditation allows a mage to replenish mana quickly. I can teach you. + } + + [Constructable] + public Gustar() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Gustar"; + Title = "the Meditation Instructor"; + BodyValue = 0x190; + Hue = 0x83F5; + HairItemID = 0x203B; + HairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Inscribe, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new GustarShroud() ); + AddItem( new Sandals() ); + } + + public Gustar( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GustarShroud : BaseOuterTorso + { + public override string DefaultName{ get{ return " "; } } + [Constructable] + public GustarShroud() : base( 0x2684 ) + { + Hue = 0x479; + } + + public GustarShroud( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Jillian : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078129 ); // I can teach you how to scribe magic scrolls. + } + + [Constructable] + public Jillian() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Jillian"; + Title = "the Inscription Instructor"; + BodyValue = 0x191; + Female = true; + Hue = 0x83EA; + HairItemID = 0x203D; + HairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Inscribe, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Robe( 0x479 ) ); + AddItem( new Sandals() ); + } + + public Jillian( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Kaelynna : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078125 ); // Want to unlock the secrets of magery? + } + + [Constructable] + public Kaelynna() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Kaelynna"; + Title = "the Magery Instructor"; + BodyValue = 0x191; + Female = true; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x47D; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Inscribe, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Robe( 0x592 ) ); + AddItem( new Sandals() ); + } + + public Kaelynna( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Mithneral : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078127 ); // Want to maximize your spell damage? I have a scholarly task for you! + } + + [Constructable] + public Mithneral() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Mithneral"; + Title = "the Evaluating Intelligence Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Inscribe, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Sandals() ); + + Item item; + + item = new GustarShroud(); + item.Hue = 0x51C; + AddItem( item ); + } + + public Mithneral( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AmeliaYoungstone : Tinker + { + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078123 ); // Tinkering is very useful for a blacksmith. You can make your own tools. + } + + [Constructable] + public AmeliaYoungstone() + { + Name = "Amelia Youngstone"; + Title = "the Tinkering Instructor"; + BodyValue = 0x191; + Female = true; + Hue = 0x83EA; + HairItemID = 0x203D; + HairHue = 0x46C; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.ArmsLore, 120.0 ); + SetSkill( SkillName.Blacksmith, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Tinkering, 120.0 ); + SetSkill( SkillName.Mining, 120.0 ); + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new Sandals() ); + AddItem( new Doublet() ); + AddItem( new ShortPants() ); + AddItem( new HalfApron( 0x8AB ) ); + } + + public AmeliaYoungstone( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AndreasVesalius : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078138 ); // Learning of the body will allow you to excel in combat. + } + + [Constructable] + public AndreasVesalius() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Andreas Vesalius"; + Title = "the Anatomy Instructor"; + BodyValue = 0x190; + Hue = 0x83EC; + HairItemID = 0x203C; + HairHue = 0x477; + FacialHairItemID = 0x203E; + FacialHairHue = 0x477; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Boots() ); + AddItem( new BlackStaff() ); + AddItem( new LongPants() ); + AddItem( new Tunic( 0x66D ) ); + } + + public AndreasVesalius( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Avicenna : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078137 ); // A warrior needs to learn how to apply bandages to wounds. + } + + [Constructable] + public Avicenna() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Avicenna"; + Title = "the Healing Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203B; + HairHue = 0x477; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Robe( 0x66D ) ); + AddItem( new Boots() ); + AddItem( new GnarledStaff() ); + } + + public Avicenna( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SarsmeaSmythe : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078139 ); // Know yourself, and you will become a true warrior. + } + + [Constructable] + public SarsmeaSmythe() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Sarsmea Smythe"; + Title = "the Focus Instructor"; + BodyValue = 0x191; + Female = true; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x456; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Focus, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new ThighBoots() ); + AddItem( new StuddedGorget() ); + AddItem( new LeatherLegs() ); + AddItem( new FemaleLeatherChest() ); + AddItem( new StuddedGloves() ); + AddItem( new LeatherNinjaBelt() ); + AddItem( new LightPlateJingasa() ); + } + + public SarsmeaSmythe( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Ryuichi : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078155 ); // I can teach you Ninjitsu. The Art of Stealth. + } + + [Constructable] + public Ryuichi() + : base( "the Ninjitsu Instructor" ) + { + Name = "Ryuichi"; + Hue = 0x8403; + + SetSkill( SkillName.Hiding, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Tracking, 120.0 ); + SetSkill( SkillName.Fencing, 120.0 ); + SetSkill( SkillName.Stealth, 120.0 ); + SetSkill( SkillName.Ninjitsu, 120.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBNinja() ); + } + + public override bool GetGender() + { + return false; + } + + public override void InitOutfit() + { + HairItemID = 0x203B; + HairHue = 0x455; + + AddItem( new SamuraiTabi() ); + AddItem( new LeatherNinjaPants() ); + AddItem( new LeatherNinjaMitts() ); + AddItem( new LeatherNinjaHood() ); + AddItem( new LeatherNinjaJacket() ); + AddItem( new LeatherNinjaBelt() ); + + PackGold( 100, 200 ); + } + + public Ryuichi( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Chiyo : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078165 ); // To be undetected means you cannot be harmed. + } + + [Constructable] + public Chiyo() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Chiyo"; + Title = "the Hiding Instructor"; + BodyValue = 0xF7; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Hiding, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Tracking, 120.0 ); + SetSkill( SkillName.Fencing, 120.0 ); + SetSkill( SkillName.Stealth, 120.0 ); + SetSkill( SkillName.Ninjitsu, 120.0 ); + } + + public Chiyo( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Jun : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078175 ); // Walk Silently. Remain unseen. I can teach you. + } + + [Constructable] + public Jun() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Jun"; + Title = "the Stealth Instructor"; + BodyValue = 0x190; + Hue = 0x8403; + HairItemID = 0x203B; + HairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Hiding, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Tracking, 120.0 ); + SetSkill( SkillName.Fencing, 120.0 ); + SetSkill( SkillName.Stealth, 120.0 ); + SetSkill( SkillName.Ninjitsu, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new SamuraiTabi() ); + AddItem( new LeatherNinjaPants() ); + AddItem( new LeatherNinjaMitts() ); + AddItem( new LeatherNinjaHood() ); + AddItem( new LeatherNinjaJacket() ); + AddItem( new LeatherNinjaBelt() ); + } + + public Jun( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Walker : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1078213, // I don't sleep. I wait. + 1078212, // There is no theory of evolution. Just a list of creatures I allow to live. + 1078214 // I can lead a horse to water and make it drink. + ) ); + } + + [Constructable] + public Walker() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Walker"; + Title = "the Tracking Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203B; + HairHue = 0x47D; + FacialHairItemID = 0x204B; + FacialHairHue = 0x47D; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Hiding, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Tracking, 120.0 ); + SetSkill( SkillName.Fencing, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Stealth, 120.0 ); + SetSkill( SkillName.Ninjitsu, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x455 ) ); + AddItem( new LongPants( 0x455 ) ); + AddItem( new FancyShirt( 0x47D ) ); + AddItem( new FloppyHat( 0x455 ) ); + } + + public Walker( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Hamato : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078134 ); // Seek me to learn the way of the samurai. + } + + [Constructable] + public Hamato() + : base( "the Bushido Instructor" ) + { + Name = "Hamato"; + Hue = 0x8403; + + SetSkill( SkillName.Anatomy, 120.0 ); + SetSkill( SkillName.Parry, 120.0 ); + SetSkill( SkillName.Healing, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Bushido, 120.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBSamurai() ); + } + + public override bool GetGender() + { + return false; + } + + public override void InitOutfit() + { + HairItemID = 0x203D; + HairHue = 0x497; + + AddItem( new Backpack() ); + AddItem( new NoDachi() ); + AddItem( new NinjaTabi() ); + AddItem( new PlateSuneate() ); + AddItem( new LightPlateJingasa() ); + AddItem( new LeatherDo() ); + AddItem( new LeatherHiroSode() ); + + PackGold( 100, 200 ); + } + + public Hamato( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Mulcivikh : Mage + { + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078131 ); // Allured by dark magic, aren't you? + } + + [Constructable] + public Mulcivikh() + { + Name = "Mulcivikh"; + Title = "the Necromancy Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203D; + HairHue = 0x457; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.SpiritSpeak, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.Necromancy, 120.0 ); + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new Sandals( 0x8FD ) ); + AddItem( new BoneHelm() ); + + Item item; + + item = new LeatherLegs(); + item.Hue = 0x2C3; + AddItem( item ); + + item = new LeatherGloves(); + item.Hue = 0x2C3; + AddItem( item ); + + item = new LeatherGorget(); + item.Hue = 0x2C3; + AddItem( item ); + + item = new LeatherChest(); + item.Hue = 0x2C3; + AddItem( item ); + + item = new LeatherArms(); + item.Hue = 0x2C3; + AddItem( item ); + } + + public Mulcivikh( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Morganna : Mage + { + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078132 ); // Want to learn how to channel the supernatural? + } + + [Constructable] + public Morganna() + { + Name = "Morganna"; + Title = "the Spirit Speak Instructor"; + BodyValue = 0x191; + Female = true; + Hue = 0x83EA; + HairItemID = 0x203C; + HairHue = 0x455; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.SpiritSpeak, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.Necromancy, 120.0 ); + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new Sandals() ); + AddItem( new Robe( 0x47D ) ); + AddItem( new SkullCap( 0x455 ) ); + } + + public Morganna( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class JacobWaltz : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078124 ); // You there! I can use some help mining these rocks! + } + + [Constructable] + public JacobWaltz() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Jacob Waltz"; + Title = "the Miner Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x2048; + HairHue = 0x44E; + FacialHairItemID = 0x204D; + FacialHairHue = 0x44E; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.ArmsLore, 120.0 ); + SetSkill( SkillName.Blacksmith, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Tinkering, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Mining, 120.0 ); + + AddItem( new Backpack() ); + AddItem( new Pickaxe() ); + AddItem( new Boots() ); + AddItem( new WideBrimHat( 0x966 ) ); + AddItem( new ShortPants( 0x370 ) ); + AddItem( new Shirt( 0x966 ) ); + AddItem( new HalfApron( 0x1BB ) ); + } + + public JacobWaltz( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GeorgeHephaestus : Blacksmith + { + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1078122 ); // Wanna learn how to make powerful weapons and armor? Talk to me. + } + + [Constructable] + public GeorgeHephaestus() + { + Name = "George Hephaestus"; + Title = "the Blacksmith Instructor"; + BodyValue = 0x190; + Hue = 0x83EA; + HairItemID = 0x203B; + HairHue = 0x47B; + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.ArmsLore, 120.0 ); + SetSkill( SkillName.Blacksmith, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Tinkering, 120.0 ); + SetSkill( SkillName.Swords, 120.0 ); + SetSkill( SkillName.Mining, 120.0 ); + + } + + public override void InitOutfit() + { + AddItem( new Backpack() ); + AddItem( new Boots( 0x973 ) ); + AddItem( new LongPants() ); + AddItem( new Bascinet() ); + AddItem( new FullApron( 0x8AB ) ); + + Item item; + + item = new SmithHammer(); + item.Hue = 0x8AB; + AddItem( item ); + } + + public GeorgeHephaestus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/NewHavenTraining.cs b/Scripts/Engines/MLQuests/Definitions/NewHavenTraining.cs new file mode 100644 index 0000000..72200db --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/NewHavenTraining.cs @@ -0,0 +1,1017 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class SplitEnds : MLQuest + { + public SplitEnds() + { + Activated = true; + HasRestartDelay = true; + Title = 1075506; // Split Ends + Description = 1075507; // *sighs* I think bowcrafting is a might beyond my talents. Say there, you look a bit more confident with tools. Can I persuade thee to make a few arrows? You could have my satchel in return... 'tis useless to me! You'll need a fletching kit to start, some feathers, and a few arrow shafts. Just use the fletching kit while you have the other things, and I'm sure you'll figure out the rest. + RefusalMessage = 1075508; // Oh. Well. I'll just keep trying alone, I suppose... + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + CompletionMessage = 1072272; // Thanks for helping me out. Here's the reward I promised you. + + Objectives.Add( new CollectObjective( 20, typeof( Arrow ), 1023902 ) ); // arrow + + Rewards.Add( new ItemReward( 1074282, typeof( AndricSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Andric" ), new Point3D( 3742, 2582, 40 ), Map.Trammel ); + } + } + + public class IShotAnArrowIntoTheAir : MLQuest + { + public IShotAnArrowIntoTheAir() + { + Activated = true; + Title = 1075486; // I Shot an Arrow Into the Air... + Description = 1075482; // Truth be told, the only way to get a feel for the bow is to shoot one and there's no better practice target than a sheep. If ye can shoot ten of them I think ye will have proven yer abilities. Just grab a bow and make sure to take enough ammunition. Bows tend to use arrows and crossbows use bolts. Ye can buy 'em or have someone craft 'em. How about it then? Come back here when ye are done. + RefusalMessage = 1075483; // Fair enough, the bow isn't for everyone. Good day then. + InProgressMessage = 1075484; // Return once ye have killed ten sheep with a bow and not a moment before. + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Sheep ) }, 1018270 ) ); // sheep + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Kashiel" ), new Point3D( 3744, 2586, 40 ), Map.Trammel ); + } + } + + public class BakersDozen : MLQuest + { + public BakersDozen() + { + Activated = true; + HasRestartDelay = true; + Title = 1075478; // Baker's Dozen + Description = 1075479; // You there! Do you know much about the ways of cooking? If you help me out, I'll show you a thing or two about how it's done. Bring me some cookie mix, about 5 batches will do it, and I will reward you. Although, I don't think you can buy it, you can make some in a snap! First get a rolling pin or frying pan or even a flour sifter. Then you mix one pinch of flour with some water and you've got some dough! Take that dough and add one dollop of honey and you've got sweet dough. add one more drop of honey and you've got cookie mix. See? Nothing to it! Now get to work! + RefusalMessage = 1075480; // Argh, I absolutely must have more of these 'cookies!' Come back if you change your mind. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + CompletionMessage = 1075481; // Thank you! I haven't been this excited about food in months! + + Objectives.Add( new CollectObjective( 5, typeof( CookieMix ), 1024159 ) ); // cookie mix + + Rewards.Add( new ItemReward( 1074282, typeof( AsandosSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Asandos" ), new Point3D( 3505, 2513, 27 ), Map.Trammel ); + } + } + + public class AStitchInTime : MLQuest + { + public AStitchInTime() + { + Activated = true; + HasRestartDelay = true; + Title = 1075523; // A Stitch in Time + Description = 1075522; // Oh how I wish I had a fancy dress like the noble ladies of Castle British! I don't have much... but I have a few trinkets I might trade for it. It would mean the world to me to go to a fancy ball and dance the night away. Oh, and I could tell you how to make one! You just need to use your sewing kit on enough cut cloth, that's all. + RefusalMessage = 1075526; // Won't you reconsider? It'd mean the world to me, it would! + InProgressMessage = 1075527; // Hello again! Do you need anything? You may want to visit the tailor's shop for cloth and a sewing kit, if you don't already have them. + CompletionMessage = 1075528; // It's gorgeous! I only have a few things to give you in return, but I can't thank you enough! Maybe I'll even catch Uzeraan's eye at the, er, *blushes* I mean, I can't wait to wear it to the next town dance! + + Objectives.Add( new CollectObjective( 1, typeof( FancyDress ), 1027935 ) ); // fancy dress + + Rewards.Add( new ItemReward( 1075524, typeof( AnOldRing ) ) ); // an old ring + Rewards.Add( new ItemReward( 1075525, typeof( AnOldNecklace ) ) ); // an old necklace + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Clairesse" ), new Point3D( 3492, 2546, 20 ), Map.Trammel ); + } + } + + public class BatteredBucklers : MLQuest + { + public BatteredBucklers() + { + Activated = true; + HasRestartDelay = true; + Title = 1075511; // Battered Bucklers + Description = 1075512; // Hey there! Yeah... you! Ya' any good with a hammer? Tell ya what, if yer thinking about tryin' some metal work, and have a bit of skill, I can show ya how to bend it into shape. Just get some of those ingots there, and grab a hammer and use it over here at this forge. I need a few more bucklers hammered out to fill this here order with... hmmm about ten more. that'll give some taste of how to work the metal. + RefusalMessage = 1075514; // Not enough muscle on yer bones to use it? hmph, probably afraid of the sparks markin' up yer loverly skin... to good for some honest labor... ha!... off with ya! + InProgressMessage = 1075515; // Come On! Whats that... a bucket? We need ten bucklers... not spitoons. + CompletionMessage = 1075516; // Thanks for the help. Here's something for ya to remember me by. + + Objectives.Add( new CollectObjective( 10, typeof( Buckler ), 1027027 ) ); // buckler + + Rewards.Add( new ItemReward( 1074282, typeof( GervisSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Gervis" ), new Point3D( 3505, 2749, 0 ), Map.Trammel ); + } + } + + public class MoreOrePlease : MLQuest + { + public MoreOrePlease() + { + Activated = true; + HasRestartDelay = true; + Title = 1075530; // More Ore Please + Description = 1075529; // Have a pickaxe? My supplier is late and I need some iron ore so I can complete a bulk order for another merchant. If you can get me some soon I'll pay you double what it's worth on the market. Just find a cave or mountainside and try to use your pickaxe there, maybe you'll strike a good vein! 5 large pieces should do it. + RefusalMessage = 1075531; // Not feeling strong enough today? Its alright, I didn't need a bucket of rocks anyway. + InProgressMessage = 1075532; // Hmmm� we need some more Ore. Try finding a mountain or cave, and give it a whack. + CompletionMessage = 1075533; // I see you found a good vien! Great! This will help get this order out on time. Good work! + + Objectives.Add( new InternalObjective() ); + + Rewards.Add( new ItemReward( 1074282, typeof( MuggSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Mugg" ), new Point3D( 3507, 2747, 0 ), Map.Trammel ); + } + + private class InternalObjective : CollectObjective + { + // Any type of ore is allowed + public InternalObjective() + : base( 5, typeof( BaseOre ), 1026585 ) // ore + { + } + + public override bool CheckItem( Item item ) + { + return ( item.ItemID == 6585 ); // Only large pieces count + } + } + } + + public class ComfortableSeating : MLQuest + { + public ComfortableSeating() + { + Activated = true; + HasRestartDelay = true; + Title = 1075517; // Comfortable Seating + Description = 1075518; // Hail friend, hast thou a moment? A mishap with a saw hath left me in a sorry state, for it shall be a while before I canst return to carpentry. In the meantime, I need a comfortable chair that I may rest. Could thou craft a straw chair? Only a tool, such as a dovetail saw, a few boards, and some skill as a carpenter is needed. Remember, this is a piece of furniture, so please pay attention to detail. + RefusalMessage = 1072687; // I quite understand your reluctance. If you reconsider, I'll be here. + InProgressMessage = 1075509; // Is all going well? I look forward to the simple comforts in my very own home. + CompletionMessage = 1074720; // This is perfect! + + Objectives.Add( new CollectObjective( 1, typeof( BambooChair ), "straw chair" ) ); + + Rewards.Add( new ItemReward( 1074282, typeof( LowelSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Lowel" ), new Point3D( 3440, 2645, 27 ), Map.Trammel ); + } + } + + public class ThePenIsMightier : MLQuest + { + public ThePenIsMightier() + { + Activated = true; + HasRestartDelay = true; + Title = 1075542; // The Pen is Mightier + Description = 1075543; // Do you know anything about 'Inscription?' I've been trying to get my hands on some hand crafted Recall scrolls for a while now, and I could really use some help. I don't have a scribe's pen, let alone a spellbook with Recall in it, or blank scrolls, so there's no way I can do it on my own. How about you though? I could trade you one of my old leather bound books for some. + RefusalMessage = 1075546; // Hmm, thought I had your interest there for a moment. It's not everyday you see a book made from real daemon skin, after all! + InProgressMessage = 1075547; // Inscribing... yes, you'll need a scribe's pen, some reagents, some blank scroll, and of course your own magery book. You might want to visit the magery shop if you're lacking some materials. + CompletionMessage = 1075548; // Ha! Finally! I've had a rune to the waterfalls near Justice Isle that I've been wanting to use for the longest time, and now I can visit at last. Here's that book I promised you... glad to be rid of it, to be honest. + + Objectives.Add( new CollectObjective( 5, typeof( RecallScroll ), "recall scroll" ) ); + + Rewards.Add( new ItemReward( 1075545, typeof( RedLeatherBook ) ) ); // a book bound in red leather + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Lyle" ), new Point3D( 3503, 2584, 14 ), Map.Trammel ); + } + } + + public class AClockworkPuzzle : MLQuest + { + public AClockworkPuzzle() + { + Activated = true; + HasRestartDelay = true; + Title = 1075535; // A clockwork puzzle + Description = 1075534; // 'Tis a riddle, you see! "What kind of clock is only right twice per day? A broken one!" *laughs heartily* Ah, yes *wipes eye*, that's one of my favorites! Ah... to business. Could you fashion me some clock parts? I wish my own clocks to be right all the day long! You'll need some tinker's tools and some iron ingots, I think, but from there it should be just a matter of working the metal. + RefusalMessage = 1072981; // Or perhaps you'd rather not. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + CompletionMessage = 1075536; // Wonderful! Tick tock, tick tock, soon all shall be well with grandfather's clock! + + Objectives.Add( new CollectObjective( 5, typeof( ClockParts ), 1024175 ) ); // clock parts + + Rewards.Add( new ItemReward( 1074282, typeof( NibbetSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Nibbet" ), new Point3D( 3459, 2525, 53 ), Map.Trammel ); + } + } + + public class DeliciousFishes : MLQuest + { + public DeliciousFishes() + { + Activated = true; + HasRestartDelay = true; + Title = 1075555; // Delicious Fishes + Description = 1075556; // Ello there, looking for a good place on the dock to fish? I like the southeast corner meself. What's that? Oh, no, *sighs* me pole is broken and in for fixin'. My grandpappy gave me that pole, means a lot you see. Miss the taste of fish though... Oh say, since you're here, could you catch me a few fish? I can cook a mean fish steak, and I'll split 'em with you! But make sure it's one of the green kind, they're the best for seasoning! + RefusalMessage = 1075558; // Ah, you're missin' out my friend, you're missing out. My peppercorn fishsteaks are famous on this little isle of ours! + InProgressMessage = 1075559; // Eh? Find yerself a pole and get close to some water. Just toss the line on in and hopefully you won't snag someone's old boots! Remember, that's twenty of them green fish we'll be needin', so come back when you've got em, 'aight? + CompletionMessage = 1075560; // Just a moment my friend, just a moment! *rummages in his pack* Here we are! My secret blend of peppers always does the trick, never fails, no not once. These'll fill you up much faster than that tripe they sell in the market! + + Objectives.Add( new CollectObjective( 5, typeof( Fish ), 1022508 ) ); // fish + + Rewards.Add( new ItemReward( 1075557, typeof( PeppercornFishsteak ), 3 ) ); // peppercorn fishsteak + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Norton" ), new Point3D( 3502, 2603, 1 ), Map.Trammel ); + } + } + + public class FleeAndFatigue : MLQuest + { + public FleeAndFatigue() + { + Activated = true; + HasRestartDelay = true; + Title = 1075487; // Flee and Fatigue + Description = 1075488; // I was just *coughs* ambushed near the moongate. *wheeze* Why do I pay my taxes? Where were the guards? You then, you an Alchemist? If you can make me a few Refresh potions, I will be back on my feet and can give those lizards the what for! Find a mortar and pestle, a good amount of black pearl, and ten empty bottles to store the finished potions in. Just use the mortar and pestle and the rest will surely come to you. When you return, the favor will be repaid. + RefusalMessage = 1075489; // Fine fine, off with *cough* thee then! The next time you see a lizardman though, give him a whallop for me, eh? + InProgressMessage = 1075490; // Just remember you need to use your mortar and pestle while you have empty bottles and some black pearl. Refresh potions are what I need. + CompletionMessage = 1075491; // *glug* *glug* Ahh... Yes! Yes! That feels great! Those lizardmen will never know what hit 'em! Here, take this, I can get more from the lizards. + + Objectives.Add( new CollectObjective( 10, typeof( RefreshPotion ), "refresh potions" ) ); + + Rewards.Add( new ItemReward( 1074282, typeof( SadrahSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Sadrah" ), new Point3D( 3742, 2731, 7 ), Map.Trammel ); + } + } + + public class ChopChopOnTheDouble : MLQuest + { + public ChopChopOnTheDouble() + { + Activated = true; + HasRestartDelay = true; + Title = 1075537; // Chop Chop, On The Double! + Description = 1075538; // That's right, move it! I need sixty logs on the double, and they need to be freshly cut! If you can get them to me fast I'll have your payment in your hands before you have the scent of pine out from beneath your nostrils. Just get a sharp axe and hack away at some of the trees in the land and your lumberjacking skill will rise in no time. + RefusalMessage = 1072981; // Or perhaps you'd rather not. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + CompletionMessage = 1075539; // Ahhh! The smell of fresh cut lumber. And look at you, all strong and proud, as if you had done an honest days work! + + Objectives.Add( new CollectObjective( 60, typeof( Log ), 1027133 ) ); // log + + Rewards.Add( new ItemReward( 1074282, typeof( HargroveSatchel ) ) ); // Craftsmans's Satchel + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Hargrove" ), new Point3D( 3445, 2633, 28 ), Map.Trammel ); + } + } + + #endregion + + #region Mobiles + + public class Andric : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Andric() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Andric"; + Title = "the archer trainer"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Archery, 60.0, 80.0 ); + + AddItem( new Backpack() ); + + Item item; + + item = new LeatherChest(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new LeatherLegs(); + item.Hue = 0x6AD; + AddItem( item ); + + item = new LeatherArms(); + item.Hue = 0x6AD; + AddItem( item ); + + item = new LeatherGloves(); + item.Hue = 0x1BB; + AddItem( item ); + + AddItem( new Boots( 0x1BB ) ); + AddItem( new CompositeBow() ); + } + + public Andric( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Kashiel : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Kashiel() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Kashiel"; + Title = "the archer"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + + Item item; + + item = new LeatherChest(); + item.Hue = 0x1BB; + AddItem( item ); + + item = new LeatherLegs(); + item.Hue = 0x901; + AddItem( item ); + + item = new LeatherArms(); + item.Hue = 0x901; + AddItem( item ); + + item = new LeatherGloves(); + item.Hue = 0x1BB; + AddItem( item ); + + AddItem( new Boots( 0x1BB ) ); + AddItem( new CompositeBow() ); + } + + public Kashiel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Asandos : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Asandos() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Asandos"; + Title = "the chef"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x901 ) ); + AddItem( new ShortPants() ); + AddItem( new Shirt() ); + AddItem( new Cap() ); + AddItem( new HalfApron( 0x28 ) ); + } + + public Asandos( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + //[QuesterName( "Clarisse" )] // On OSI the gumps refer to her as this, different from actual name + public class Clairesse : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Clairesse() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Clairesse"; + Title = "the servant"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + AddItem( new PlainDress( 0x3C9 ) ); + } + + public Clairesse( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Gervis : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213, // Hey buddy.� Looking for work? + 1074211 // I could use some help. + ) ); + } + + [Constructable] + public Gervis() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Gervis"; + Title = "the blacksmith trainer"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Blacksmith, 60.0, 80.0 ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x3B3 ) ); + AddItem( new ShortPants( 0x1BB ) ); + AddItem( new Doublet( 0x652 ) ); + AddItem( new SmithHammer() ); + + Item item; + + item = new LeatherGloves(); + item.Hue = 0x3B2; + AddItem( item ); + } + + public Gervis( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Mugg : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074211 ); // I could use some help. + } + + [Constructable] + public Mugg() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Mugg"; + Title = "the miner"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x901 ) ); + AddItem( new ShortPants( 0x3B3 ) ); + AddItem( new Shirt( 0x22B ) ); + AddItem( new HalfApron( 0x5F1 ) ); + AddItem( new SkullCap( 0x177 ) ); + AddItem( new Pickaxe() ); + } + + public Mugg( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Lowel : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Lowel() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lowel"; + Title = "the carpenter"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x543 ) ); + AddItem( new ShortPants( 0x758 ) ); + AddItem( new FancyShirt( 0x53A ) ); + AddItem( new HalfApron( 0x6D2 ) ); + } + + public Lowel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Lyle : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213 // Hey buddy.� Looking for work? + ) ); + } + + [Constructable] + public Lyle() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lyle"; + Title = "the mage"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Robe( 0x2FD ) ); + AddItem( new ThighBoots() ); + } + + public Lyle( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Nibbet : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Nibbet() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Nibbet"; + Title = "the tinker"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x591 ) ); + AddItem( new ShortPants( 0xF8 ) ); + AddItem( new Shirt( 0x2D ) ); + AddItem( new FullApron( 0x288 ) ); + } + + public Nibbet( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Norton : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213, // Hey buddy.� Looking for work? + 1074211 // I could use some help. + ) ); + } + + [Constructable] + public Norton() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Norton"; + Title = "the fisher"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new ThighBoots() ); + AddItem( new LongPants( 0x6C2 ) ); + AddItem( new Shirt( 0x11D ) ); + } + + public Norton( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Sadrah : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074205, // Oh great adventurer, would you please assist a weak soul in need of aid? + 1074213, // Hey buddy.� Looking for work? + 1074211 // I could use some help. + ) ); + } + + [Constructable] + public Sadrah() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Sadrah"; + Title = "the courier"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x901 ) ); + AddItem( new Skirt( 0x52 ) ); + AddItem( new Shirt( 0x127 ) ); + AddItem( new Cloak( 0x65) ); + AddItem( new Longsword() ); + } + + public Sadrah( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Hargrove : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074213, // Hey buddy.� Looking for work? + 1074211 // I could use some help. + ) ); + } + + [Constructable] + public Hargrove() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Hargrove"; + Title = "the Lumberjack"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Boots( 0x901 ) ); + AddItem( new StuddedLegs() ); + AddItem( new Shirt( 0x288 ) ); + AddItem( new Bandana( 0x20 ) ); + AddItem( new BattleAxe() ); + + Item item; + + item = new PlateGloves(); + item.Hue = 0x21E; + AddItem( item ); + + } + + public Hargrove( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Sanctuary.cs b/Scripts/Engines/MLQuests/Definitions/Sanctuary.cs new file mode 100644 index 0000000..1cc46e8 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Sanctuary.cs @@ -0,0 +1,1241 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class BrokenShaft : MLQuest + { + public BrokenShaft() + { + Activated = true; + HasRestartDelay = true; + Title = 1074018; // Broken Shaft + Description = 1074112; // What do humans know of archery? Humans can barely shoot straight. Why, your efforts are absurd. In fact, I will make a wager - if these so called human arrows I've heard about are really as effective and innovative as human braggarts would have me believe, then I'll trade you something useful. I might even teach you something of elven craftsmanship. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( Arrow ), 1023902 ) ); // arrow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Beotham" ), new Point3D( 6285, 114, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Beotham" ), new Point3D( 6285, 114, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Danoel" ), new Point3D( 6282, 116, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Danoel" ), new Point3D( 6282, 116, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tallinin" ), new Point3D( 6279, 122, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tallinin" ), new Point3D( 6279, 122, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tiana" ), new Point3D( 6257, 112, -10 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Tiana" ), new Point3D( 6257, 112, -10 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperOolua" ), new Point3D( 6250, 124, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperOolua" ), new Point3D( 6250, 124, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperRollarn" ), new Point3D( 6244, 110, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "LorekeeperRollarn" ), new Point3D( 6244, 110, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Dallid" ), new Point3D( 6277, 104, -10 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Dallid" ), new Point3D( 6277, 104, -10 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Canir" ), new Point3D( 6274, 130, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Canir" ), new Point3D( 6274, 130, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Yellienir" ), new Point3D( 6257, 126, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Yellienir" ), new Point3D( 6257, 126, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderOnallan" ), new Point3D( 6258, 108, -10 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderOnallan" ), new Point3D( 6258, 108, -10 ), Map.Felucca ); + } + } + + public class BendingTheBow : MLQuest + { + public BendingTheBow() + { + Activated = true; + HasRestartDelay = true; + Title = 1074019; // Bending the Bow + Description = 1074113; // Human craftsmanship! Ha! Why, take an elven bow. It will last for a lifetime, never break and always shoot an arrow straight and true. Can't say the same for a human, can you? Bring me some of these human made bows, and I will show you. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( Bow ), 1025041 ) ); // bow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class ArmsRace : MLQuest + { + public ArmsRace() + { + Activated = true; + HasRestartDelay = true; + Title = 1074020; // Arms Race + Description = 1074114; // Leave it to a human to try and improve upon perfection. To take a bow and turn it into a mechanical contraption like a crossbow. I wish to see more of this sort of "invention". Fetch for me a crossbow, human. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( Crossbow ), 1023919 ) ); // crossbow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class ImprovedCrossbows : MLQuest + { + public ImprovedCrossbows() + { + Activated = true; + HasRestartDelay = true; + Title = 1074021; // Improved Crossbows + Description = 1074115; // How lazy is man! You cannot even be bothered to pull your own drawstring and hold an arrow ready? You must invent a device to do it for you? I cannot understand, but perhaps if I examine a heavy crossbow for myself, I will see their appeal. Go and bring me such a device and I will repay your meager favor. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( HeavyCrossbow ), 1025116 ) ); // heavy crossbow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class BuildingTheBetterCrossbow : MLQuest + { + public BuildingTheBetterCrossbow() + { + Activated = true; + HasRestartDelay = true; + Title = 1074022; // Building the Better Crossbow + Description = 1074116; // More is always better for a human, eh? Take these repeating crossbows. What sort of mind invents such a thing? I must look at it more closely. Bring such a contraption to me and you'll receive a token for your efforts. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( RepeatingCrossbow ), 1029923 ) ); // repeating crossbow + + Rewards.Add( ItemReward.FletchingSatchel ); + } + } + + public class InstrumentOfWar : MLQuest + { + public InstrumentOfWar() + { + Activated = true; + HasRestartDelay = true; + Title = 1074055; // Instrument of War + Description = 1074149; // Pathetic, this human craftsmanship! Take their broadswords - overgrown butter knives, in reality. No, I cannot do them justice - you must see for yourself. Bring me broadswords and I will demonstrate their feebleness. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 12, typeof( Broadsword ), 1023934 ) ); // broadsword + + Rewards.Add( ItemReward.BlacksmithSatchel ); + } + } + + public class TheShield : MLQuest + { + public TheShield() + { + Activated = true; + HasRestartDelay = true; + Title = 1074054; // The Shield + Description = 1074148; // I doubt very much a human shield would stop a good stout elven arrow. You doubt me? I will show you - get me some of these heater shields and I will piece them with sharp elven arrows! + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( HeaterShield ), 1027030 ) ); // heater shield + + Rewards.Add( ItemReward.BlacksmithSatchel ); + } + } + + public class MusicToMyEars : MLQuest + { + public MusicToMyEars() + { + Activated = true; + HasRestartDelay = true; + Title = 1074023; // Music to my Ears + Description = 1074117; // You think you know something of music? Laughable! Take your lap harp. Crude, indelicate instruments that make a noise not unlike the wailing of a choleric child or a dying cat. I will show you - bring lap harps, and I will demonstrate. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( LapHarp ), 1023762 ) ); // lap harp + + Rewards.Add( ItemReward.CarpentrySatchel ); + } + } + + public class TheGlassEye : MLQuest + { + public TheGlassEye() + { + Activated = true; + HasRestartDelay = true; + Title = 1074050; // The Glass Eye + Description = 1074144; // Humans are so pathetically weak, they must be augmented by glass and metal! Imagine such a thing! I must see one of these spyglasses for myself, to understand the pathetic limits of human sight! + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( Spyglass ), 1025365 ) ); // spyglass + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class LazyHumans : MLQuest + { + public LazyHumans() + { + Activated = true; + HasRestartDelay = true; + Title = 1074024; // Lazy Humans + Description = 1074118; // Human fancy knows no bounds! It's pathetic that they are so weak that they must create a special stool upon which to rest their feet when they recline! Humans don't have any clue how to live. Bring me some of these foot stools to examine and I may teach you something worthwhile. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( FootStool ), 1022910 ) ); // foot stool + + Rewards.Add( ItemReward.CarpentrySatchel ); + } + } + + public class InventiveTools : MLQuest + { + public InventiveTools() + { + Activated = true; + HasRestartDelay = true; + Title = 1074048; // Inventive Tools + Description = 1074142; // Bring me some of these tinker's tools! I am certain, in the hands of an elf, they will fashion objects of ingenuity and delight that will shame all human invention! Hurry, do this quickly and I might deign to show you my skill. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( TinkerTools ), 1027868 ) ); // tinker's tools + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class PixieDustToDust : MLQuest + { + public PixieDustToDust() + { + Activated = true; + Title = 1073661; // Pixie dust to dust + Description = 1073700; // Is there anything more foul than a pixie? They have cruel eyes and a mind for mischief, I say. I don't care if some think they're cute -- I say kill them and let the Avatar sort them out. In fact, if you were to kill a few pixies, I'd make sure you had a few coins to rub together, if you get my meaning. + RefusalMessage = 1073733; // Perhaps you'll change your mind and return at some point. + InProgressMessage = 1073741; // There's too much cuteness in the world -- kill those pixies! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Pixie ) }, "pixies" ) ); + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class AnImpressivePlaid : MLQuest + { + public AnImpressivePlaid() + { + Activated = true; + HasRestartDelay = true; + Title = 1074044; // An Impressive Plaid + Description = 1074138; // I do not believe humans are so ridiculous as to wear something called a "kilt". Bring for me some of these kilts, if they truly exist, and I will offer you meager reward. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( Kilt ), 1025431 ) ); // kilt + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class ANiceShirt : MLQuest + { + public ANiceShirt() + { + Activated = true; + HasRestartDelay = true; + Title = 1074045; // A Nice Shirt + Description = 1074139; // Humans call that a fancy shirt? I would wager the ends are frayed, the collar worn, the buttons loosely stitched. Bring me fancy shirts and I will demonstrate the many ways in which they are inferior. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( FancyShirt ), 1027933 ) ); // fancy shirt + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class LeatherAndLace : MLQuest + { + public LeatherAndLace() + { + Activated = true; + HasRestartDelay = true; + Title = 1074047; // Leather and Lace + Description = 1074141; // No self respecting elf female would ever wear a studded bustier! I will prove it - bring me such clothing and I will show you how ridiculous they are! + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( StuddedBustierArms ), 1027180 ) ); // studded bustier + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class FeyHeadgear : MLQuest + { + public FeyHeadgear() + { + Activated = true; + HasRestartDelay = true; + Title = 1074043; // Fey Headgear + Description = 1074137; // Humans do not deserve to wear a thing such as a flower garland. Help me prevent such things from falling into the clumsy hands of humans -- bring me flower garlands! + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( FlowerGarland ), 1028965 ) ); // flower garland + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class NewCloak : MLQuest + { + public NewCloak() + { + Activated = true; + Title = 1074684; // New Cloak + Description = 1074685; // I have created a masterpiece! And all I need to finish it off is the soft fur of a wolf. But not just ANY wolf -- oh no, no, that wouldn't do. I've heard tales of a mighty beast, Grobu, who is bonded to the leader of the troglodytes. Only Grobu's fur will do. Will you retrieve it for me? + RefusalMessage = 1074655; // Perhaps I thought too highly of you. + InProgressMessage = 1074686; // I've told you all I know of the creature. Until you return with Grobu's fur I can't finish my cloak. + CompletionMessage = 1074687; // Ah! So soft, so supple. What a wonderful texture. Here you are ... my thanks. + + Objectives.Add( new CollectObjective( 1, typeof( GrobusFur ), "Grobu's Fur" ) ); + + Rewards.Add( ItemReward.TailorSatchel ); + } + } + + public class ADishBestServedCold : MLQuest + { + public ADishBestServedCold() + { + Activated = true; + Title = 1072372; // A Dish Best Served Cold + Description = 1072657; // *mutter* I'll have my revenge. Oh! You there. Fancy some orc extermination? I despise them all. Bombers, brutes -- you name it, if it's orcish I want it killed. + RefusalMessage = 1072667; // Hrmph. Well maybe another time then. + InProgressMessage = 1072668; // Shouldn't you be slaying orcs? + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Orc ) }, "orcs", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + Objectives.Add( new KillObjective( 5, new Type[] { typeof( OrcBomber ) }, "orc bombers", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + Objectives.Add( new KillObjective( 3, new Type[] { typeof( OrcBrute ) }, "orc brutes", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class ArchEnemies : MLQuest + { + public ArchEnemies() + { + Activated = true; + Title = 1073085; // Arch Enemies + Description = 1073575; // Vermin! They get into everything! I told the boy to leave out some poisoned cheese -- and they shot him. What else can I do? Unless�these ratmen are skilled with a bow, but I'd lay a wager you're better, eh? Could you skin a few of the wretches for me? + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073595; // I don't see 10 tails from Ratman Archers on your belt -- and until I do, no reward for you. + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( RatmanArcher ) }, "ratman archers" ) ); + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class Vermin : MLQuest + { + public Vermin() + { + Activated = true; + Title = 1072995; // Vermin + Description = 1073029; // You've got to help me out! Those ratmen have been causing absolute havok around here. Kill them off before they destroy my land. I'll pay you if you kill off twelve of those dirty rats. + RefusalMessage = 1072270; // Well, okay. But if you decide you are up for it after all, c'mon back and see me. + InProgressMessage = 1072271; // You're not quite done yet. Get back to work! + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Ratman ) }, "ratmen" ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class MougGuurMustDie : MLQuest + { + public override Type NextQuest { get { return typeof( LeaderOfThePack ); } } + + public MougGuurMustDie() + { + Activated = true; + Title = 1072368; // Moug-Guur Must Die + Description = 1072561; // You there! Yes, you. Kill Moug-Guur, the leader of the orcs in this depressing place, and I'll make it worth your while. + RefusalMessage = 1072571; // Fine. It's no skin off my teeth. + InProgressMessage = 1072572; // Small words. Kill Moug-Guur. Go. Now! + CompletionMessage = 1072573; // You're better than I thought you'd be. Not particularly bad, but not entirely inept. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( MougGuur ) }, "Moug-Guur", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class LeaderOfThePack : MLQuest + { + public override Type NextQuest { get { return typeof( SayonaraSzavetra ); } } + public override bool IsChainTriggered { get { return true; } } + + public LeaderOfThePack() + { + Activated = true; + Title = 1072560; // Leader of the Pack + Description = 1072574; // Well now that Moug-Guur is no more -- and I can't say I'm weeping for his demise -- it's time for the ratmen to experience a similar loss of leadership. Slay Chiikkaha. In return, I'll satisfy your greed temporarily. + RefusalMessage = 1072575; // Alright, if you'd rather not, then run along and do whatever worthless things you do when I'm not giving you direction. + InProgressMessage = 1072576; // How difficult is this? The rats live in the tunnels. Go into the tunnels and find the biggest, meanest rat and execute him. Loitering around here won't get the task done. + CompletionMessage = 1072577; // It's about time! Could you have taken longer? + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Chiikkaha ) }, "Chiikkaha", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class SayonaraSzavetra : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public SayonaraSzavetra() + { + Activated = true; + Title = 1072375; // Sayonara, Szavetra + Description = 1072578; // Hmm, maybe you aren't entirely worthless. I suspect a demoness of Szavetra's calibre will tear you apart ... We might as well find out. Kill the succubus, yada yada, and you'll be richly rewarded. + RefusalMessage = 1072579; // Hah! I knew you couldn't handle it. + InProgressMessage = 1072581; // Hahahaha! I can see the fear in your eyes. Pathetic. Szavetra is waiting for you. + CompletionMessage = 1072582; // Amazing! Simply astonishing ... you survived. Well, I supposed I should indulge your avarice with a reward. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( Szavetra ) }, "Szavetra", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.Strongbox ); + } + } + + public class TappingTheKeg : MLQuest + { + public TappingTheKeg() + { + Activated = true; + HasRestartDelay = true; + Title = 1074037; // Tapping the Keg + Description = 1074131; // I have acquired a barrel of human brewed beer. I am loathe to drink it, but how else to prove how inferior it is? I suppose I shall need a barrel tap to drink. Go, bring me a barrel tap quickly, so I might get this over with. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( BarrelTap ), 1024100 ) ); // barrel tap + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class WaitingToBeFilled : MLQuest + { + public WaitingToBeFilled() + { + Activated = true; + HasRestartDelay = true; + Title = 1074036; // Waiting to be Filled + Description = 1074130; // The only good thing I can say about human made bottles is that they are empty and may yet still be filled with elven wine. Go now, fetch a number of empty bottles so that I might save them from the fate of carrying human-made wine. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 20, typeof( Bottle ), 1023854 ) ); // empty bottle + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class BreezesSong : MLQuest + { + public BreezesSong() + { + Activated = true; + HasRestartDelay = true; + Title = 1074052; // Breeze's Song + Description = 1074146; // I understand humans cruely enslave the very wind to their selfish whims! Fancy wind chimes, what a monstrous idea! You must bring me proof of this terrible depredation - hurry, bring me wind chimes! + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074064; // Hurry up! I don't have all day to wait for you to bring what I desire! + CompletionMessage = 1074065; // These human made goods are laughable! It offends so -- I must show you what elven skill is capable of! + + Objectives.Add( new CollectObjective( 10, typeof( FancyWindChimes ), 1030291 ) ); // fancy wind chimes + + Rewards.Add( ItemReward.TinkerSatchel ); + } + } + + public class ProofOfTheDeed : MLQuest + { + public ProofOfTheDeed() + { + Activated = true; + Title = 1072339; // Proof of the Deed + Description = 1072340; // These human vermin must be erradicated! They despoil fair Sosaria with their every footfall upon her soil, every exhalation of breath upon her pristine air. Prove yourself an ally of Sosaria and bring me 20 human ears as proof of your devotion to our cause. + RefusalMessage = 1072342; // Do you find the task distasteful? Are you too weak to shoulder the duty of cleansing Sosaria? So be it. + InProgressMessage = 1072343; // Well, where is the proof of your deed? I will honor your actions when you have brought me the ears of the human scum. + CompletionMessage = 1072344; // Ah, well done. You have chosen the path of duty and fulfilled your task with honor. + + Objectives.Add( new CollectObjective( 20, typeof( SeveredHumanEars ), 1032591 ) ); // severed human ears + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class Marauders : MLQuest + { + public override Type NextQuest { get { return typeof( TheBrainsOfTheOperation ); } } + + public Marauders() + { + Activated = true; + Title = 1072374; // Marauders + Description = 1072686; // What a miserable place we live in. Look around you at the changes we've wrought. The trees are sprouting leaves once more and the grass is reclaiming the blood-soaked soil. Who would have imagined we'd find ourselves here? Our "neighbors" are anything but friendly and those ogres are the worst of the lot. Maybe you'd be interested in helping our community by disposing of some of our least amiable neighbors? + RefusalMessage = 1072687; // I quite understand your reluctance. If you reconsider, I'll be here. + InProgressMessage = 1072688; // You can't miss those ogres, they're huge and just outside the gates here. + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( Ogre ) }, "ogres", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + public class TheBrainsOfTheOperation : MLQuest + { + public override Type NextQuest { get { return typeof( TheBrawn ); } } + public override bool IsChainTriggered { get { return true; } } + + public TheBrainsOfTheOperation() + { + Activated = true; + Title = 1072692; // The Brains of the Operation + Description = 1072707; // *sigh* We have so much to do to clean this area up. Even the fine work you did on those ogres didn't have much of an impact on the community. It's the ogre lords that direct the actions of the other ogres, let's strike at the leaders and perhaps that will thwart the miserable curs. + RefusalMessage = 1072708; // Reluctance doesn't become a hero like you. But, as you wish. + InProgressMessage = 1072709; // Ogre Lords are pretty easy to recognize. They're the ones ordering the other ogres about in a lordly manner. Striking down their leadership will throw the ogres into confusion and dismay! + + Objectives.Add( new KillObjective( 10, new Type[] { typeof( OgreLord ) }, "ogre lords", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class TheBrawn : MLQuest + { + public override Type NextQuest { get { return typeof( TheBiggerTheyAre ); } } + public override bool IsChainTriggered { get { return true; } } + + public TheBrawn() + { + Activated = true; + Title = 1072693; // The Brawn + Description = 1072710; // Inconceiveable! We've learned that the ogre leadership has recruited some heavy-duty guards to their cause. I've never personally fought a cyclopian warrior, but I'm sure you could easily best a few and report back how much trouble they'll cause to our growing community? + RefusalMessage = 1072711; // Oh, I see. *sigh* Perhaps I overestimated your abilities. + InProgressMessage = 1072712; // Make sure you fully assess all of the cyclopian tactical abilities! + + Objectives.Add( new KillObjective( 6, new Type[] { typeof( Cyclops ) }, "cyclops", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class TheBiggerTheyAre : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public TheBiggerTheyAre() + { + Activated = true; + Title = 1072694; // The Bigger They Are ... + Description = 1072713; // The ogre insurgency has taken a turn for the worse! I've just been advised that the titans have concluded their discussions with the ogres and they've allied. We have virtually no information about titans. Engage them and appraise their mettle. + RefusalMessage = 1072714; // Certainly. You've done enough to merit a breather. When you're ready for more, report back to me. + InProgressMessage = 1072715; // Those titans don't skulk very well. You should be able to track them easily ... their footsteps are easily the largest around. + + Objectives.Add( new KillObjective( 3, new Type[] { typeof( Titan ) }, "titans", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.LargeBagOfTreasure ); + } + } + + public class TroubleOnTheWing : MLQuest + { + public TroubleOnTheWing() + { + Activated = true; + Title = 1072371; // Trouble on the Wing + Description = 1072593; // Those gargoyles need to get knocked down a peg or two, if you ask me. They're always flying over here and lobbing things at us. What a nuisance. Drop a dozen of them for me, would you? + RefusalMessage = 1072594; // Don't tell me you're a gargoyle sympathizer? *spits* + InProgressMessage = 1072595; // Those blasted gargoyles hang around the old tower. That's the best place to hunt them down. + + Objectives.Add( new KillObjective( 12, new Type[] { typeof( Gargoyle ) }, "gargoyles", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class BrotherlyLove : MLQuest + { + public BrotherlyLove() + { + Activated = true; + OneTimeOnly = true; + Title = 1072369; // Brotherly Love + Description = 1072585; // *looks around nervously* Do you travel to The Heartwood? I have an urgent letter that must be delivered there in the next 30 minutes -- to Ahie the Cloth Weaver. Will you undertake this journey? + RefusalMessage = 1072587; // *looks disappointed* Let me know if you change your mind. + InProgressMessage = 1072588; // You haven't lost the letter have you? It must be delivered to Ahie directly. Give it into no other hands. + CompletionMessage = 1074579; // Yes, can I help you? + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( APersonalLetterAddressedToAhie ), 1, "letter", typeof( Ahie ) ) ); + + Rewards.Add( ItemReward.BagOfTrinkets ); + } + } + + public class CommonBrigands : MLQuest + { + public CommonBrigands() + { + Activated = true; + Title = 1073082; // Common Brigands + Description = 1073572; // Thank goodness, a hero like you has arrived! Brigands have descended upon this area like locusts, stealing and looting where ever they go. We need someone to put these vile curs where they belong -- in their graves. Are you up to the task? + RefusalMessage = 1073580; // I hope you'll reconsider. Until then, farwell. + InProgressMessage = 1073592; // The Brigands still plague us. Have you killed 20 of their number?
+ + Objectives.Add( new KillObjective( 20, new Type[] { typeof( Brigand ) }, 1074894 ) ); // Common brigands + + Rewards.Add( ItemReward.BagOfTreasure ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Beotham (Sanctuary)" )] + public class Beotham : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074187, // Want a job? + 1074184 // Come here, I have work for you. + ) ); + } + + [Constructable] + public Beotham() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Beotham"; + Title = "the bowcrafter"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x901 ) ); + AddItem( new ShortPants( 0x522 ) ); + AddItem( new FancyShirt( 0x515 ) ); + + Item item; + + item = new LeafGloves(); + item.Hue = 0x901; + AddItem( item ); + } + + public Beotham( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Danoel (Sanctuary)" )] + public class Danoel : BaseCreature + { + // TODO: Add quests: Spring Cleaning + + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074197 ); // Pardon me, but if you could spare some time I�d greatly appreciate it. + } + + [Constructable] + public Danoel() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Danoel"; + Title = "the metal weaver"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new ElvenPants( 0x386 ) ); + AddItem( new ElvenShirt( 0x75F ) ); + AddItem( new FullApron( 0x1BB ) ); + AddItem( new RoyalCirclet() ); + AddItem( new SmithHammer() ); + } + + public Danoel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Tallinin (Sanctuary)" )] + public class Tallinin : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074188, // Weakling! You are not up to the task I have. + 1074211 // I could use some help. + ) ); + } + + [Constructable] + public Tallinin() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tallinin"; + Title = "the cloth weaver"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x901 ) ); + AddItem( new Tunic( 0x37 ) ); + AddItem( new Cloak( 0x735 ) ); + } + + public Tallinin( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Tiana (Sanctuary)" )] + public class Tiana : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074214, // Knave! Come here right now! + 1074218 // Hey!� I want to talk to you, now. + ) ); + } + + [Constructable] + public Tiana() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Tiana"; + Title = "the guard"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots() ); + AddItem( new HidePants() ); + AddItem( new HideFemaleChest() ); + AddItem( new HidePauldrons() ); + + Item item; + + item = new WoodlandBelt(); + item.Hue = 0x673; + AddItem( item ); + + item = new RavenHelm(); + item.Hue = 0x443; + AddItem( item ); + } + + public Tiana( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Oolua (Sanctuary)" )] + public class LorekeeperOolua : BaseCreature + { + // TODO: Add quest Dreadhorn + + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074187 ); // Want a job? + } + + [Constructable] + public LorekeeperOolua() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Oolua"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x75A ) ); + AddItem( new Skirt( Utility.RandomBrightHue() ) ); + AddItem( new FancyShirt( 0x742 ) ); + AddItem( new Cloak( 0x1BB ) ); + AddItem( new WildStaff() ); + } + + public LorekeeperOolua( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Rollarn (Sanctuary)" )] + public class LorekeeperRollarn : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074196, // Excuse me! I�m sorry to interrupt but I urgently need some assistance. + 1074197 // Pardon me, but if you could spare some time I�d greatly appreciate it. + ) ); + } + + [Constructable] + public LorekeeperRollarn() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Rollarn"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x1BB ) ); + AddItem( new Cloak( 0x296 ) ); + AddItem( new Circlet() ); + AddItem( new LeafChest() ); + + Item item; + + item = new LeafLegs(); + item.Hue = 0x71A; + AddItem( item ); + } + + public LorekeeperRollarn( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Dallid (Sanctuary)" )] + public class Dallid : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074185, // Hey you! Want to help me out? + 1074195 // You there, in the stupid hat! Come here. + ) ); + } + + [Constructable] + public Dallid() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Dallid"; + Title = "the cook"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Boots( 0x901 ) ); + AddItem( new ShortPants( 0x73C ) ); + AddItem( new Shirt( 0x744 ) ); + AddItem( new FullApron( 0x1BE ) ); + AddItem( new Cleaver() ); + } + + public Dallid( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Canir (Sanctuary)" )] + public class Canir : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074193, // You there! Yes you. Stop looking about like a toadie and come here. + 1074186 // Come here, I have a task. + ) ); + } + + [Constructable] + public Canir() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Canir"; + Title = "the thaumaturgist"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Sandals( 0x1BB ) ); + AddItem( new FemaleElvenRobe( 0x5A7 ) ); + AddItem( new GemmedCirclet() ); + AddItem( new MagicWand() ); + } + + public Canir( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Yellienir : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Yellienir() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Yellienir"; + Title = "the bark weaver"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new ElvenBoots() ); + AddItem( new LeafTonlet() ); + AddItem( new FemaleLeafChest() ); + AddItem( new LeafArms() ); + AddItem( new Cloak( 0x3B2 ) ); + } + + public Yellienir( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Elder Onallan (Sanctuary)" )] + public class ElderOnallan : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074217, // I want to make you an offer you�d be a fool to �refuse. + 1074218 // Hey!� I want to talk to you, now. + ) ); + } + + [Constructable] + public ElderOnallan() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Elder Onallan"; + Title = "the wise"; + Race = Race.Elf; + BodyValue = 0x25D; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new Shoes( 0x729 ) ); + AddItem( new WildStaff() ); + AddItem( new Cloak( 0x64E ) ); + } + + public ElderOnallan( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/Spellweaving.cs b/Scripts/Engines/MLQuests/Definitions/Spellweaving.cs new file mode 100644 index 0000000..952783f --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/Spellweaving.cs @@ -0,0 +1,691 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Engines.MLQuests.Objectives; +using Server.Items; +using Server.Engines.MLQuests.Rewards; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + public static class Spellweaving + { + public static void AwardTo( PlayerMobile pm ) + { + if ( pm == null ) + return; + + MLQuestContext context = MLQuestSystem.GetOrCreateContext( pm ); + + if ( !context.Spellweaving ) + { + context.Spellweaving = true; + + Effects.SendLocationParticles( EffectItem.Create( pm.Location, pm.Map, EffectItem.DefaultDuration ), 0, 0, 0, 0, 0, 5060, 0 ); + Effects.PlaySound( pm.Location, pm.Map, 0x243 ); + + Effects.SendMovingParticles( new Entity( Server.Serial.Zero, new Point3D( pm.X - 6, pm.Y - 6, pm.Z + 15 ), pm.Map ), pm, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + Effects.SendMovingParticles( new Entity( Server.Serial.Zero, new Point3D( pm.X - 4, pm.Y - 6, pm.Z + 15 ), pm.Map ), pm, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + Effects.SendMovingParticles( new Entity( Server.Serial.Zero, new Point3D( pm.X - 6, pm.Y - 4, pm.Z + 15 ), pm.Map ), pm, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + + Effects.SendTargetParticles( pm, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 ); + } + } + } + + #region Patience + + public class Patience : MLQuest + { + public override Type NextQuest { get { return typeof( NeedsOfTheManyHeartwood1 ); } } + + public Patience() + { + Activated = true; + Title = 1072753; // Patience + Description = 1072762; // Learning to weave spells and control the forces of nature requires sacrifice, discipline, focus, and an unwavering dedication to Sosaria herself. We do not teach the unworthy. They do not comprehend the lessons nor the dedication required. If you would walk the path of the Arcanist, then you must do as I require without hesitation or question. Your first task is to gather miniature mushrooms ... 20 of them from the branches of our mighty home. I give you one hour to complete the task. + RefusalMessage = 1072767; // *nods* Not everyone has the temperment to undertake the way of the Arcanist. + InProgressMessage = 1072774; // The mushrooms I seek can be found growing here in The Heartwood. Seek them out and gather them. You are running out of time. + CompletionMessage = 1074166; // Have you gathered the mushrooms? + + Objectives.Add( new TimedCollectObjective( TimeSpan.FromHours( 1 ), 20, typeof( MiniatureMushroom ), "miniature mushrooms" ) ); + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Aeluva" ), new Point3D( 7064, 349, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Aeluva" ), new Point3D( 7064, 349, 0 ), Map.Trammel ); + + // Split up to prevent stacking on the spawner + PutSpawner( new Spawner( 20, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 30, "MiniatureMushroom" ), new Point3D( 7015, 366, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 20, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 30, "MiniatureMushroom" ), new Point3D( 7015, 366, 0 ), Map.Trammel ); + + PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7081, 373, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 5, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7081, 373, 0 ), Map.Trammel ); + + PutSpawner( new Spawner( 15, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7052, 414, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 15, TimeSpan.FromSeconds( 15 ), TimeSpan.FromSeconds( 30 ), 0, 20, "MiniatureMushroom" ), new Point3D( 7052, 414, 0 ), Map.Trammel ); + } + } + + public class NeedsOfTheManyHeartwood1 : MLQuest + { + public override Type NextQuest { get { return typeof( NeedsOfTheManyHeartwood2 ); } } + public override bool IsChainTriggered { get { return true; } } + + public NeedsOfTheManyHeartwood1() + { + Activated = true; + Title = 1072797; // Needs of the Many - The Heartwood + Description = 1072763; // The way of the Arcanist involves cooperation with others and a strong committment to the community of your people. We have run low on the cotton we use to pack wounds and our people have need. Bring 10 bales of cotton to me. + RefusalMessage = 1072768; // You endanger your progress along the path with your unwillingness. + InProgressMessage = 1072775; // I care not where you acquire the cotton, merely that you provide it. + CompletionMessage = 1074110; // Well, where are the cotton bales? + + Objectives.Add( new CollectObjective( 10, typeof( Cotton ), 1023577 ) ); // bale of cotton + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + } + + public class NeedsOfTheManyHeartwood2 : MLQuest + { + public override Type NextQuest { get { return typeof( MakingAContributionHeartwood ); } } + public override bool IsChainTriggered { get { return true; } } + + public NeedsOfTheManyHeartwood2() + { + Activated = true; + Title = 1072797; // Needs of the Many - The Heartwood + Description = 1072764; // We must look to the defense of our people! Bring boards for new arrows. + RefusalMessage = 1072769; // The people have need of these items. You are proving yourself inadequate to the demands of a member of this community. + InProgressMessage = 1072776; // The requirements are simple -- 250 boards. + CompletionMessage = 1074152; // Well, where are the boards? + + Objectives.Add( new CollectObjective( 250, typeof( Board ), 1027127 ) ); // board + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + } + + public class MakingAContributionHeartwood : MLQuest + { + public override Type NextQuest { get { return typeof( UnnaturalCreations ); } } + public override bool IsChainTriggered { get { return true; } } + + public MakingAContributionHeartwood() + { + Activated = true; + Title = 1072798; // Making a Contribution - The Heartwood + Description = 1072765; // With health and defense assured, we need look to the need of the community for food and drink. We will feast on fish steaks, sweets, and wine. You will supply the ingredients, the cooks will prepare the meal. As a Arcanist relies upon others to build focus and lend their power to her workings, the community needs the effort of all to survive. + RefusalMessage = 1072770; // Do not falter now. You have begun to show promise. + InProgressMessage = 1072777; // Where are the items you've been tasked to supply for the feast? + CompletionMessage = 1074158; // Ah good, you're back. We're eager for the feast. + + Objectives.Add( new CollectObjective( 1, typeof( SackFlour ), 1024153 ) ); // sack of flour + Objectives.Add( new CollectObjective( 10, typeof( JarHoney ), 1022540 ) ); // jar of honey + Objectives.Add( new CollectObjective( 20, typeof( FishSteak ), 1022427 ) ); // fish steak + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + } + + public class UnnaturalCreations : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public UnnaturalCreations() + { + Activated = true; + Title = 1072758; // Unnatural Creations + Description = 1072780; // You have proven your desire to contribute to the community and serve the people. Now you must demonstrate your willingness to defend Sosaria from the greatest blight that plagues her. Unnatural creatures, brought to a sort of perverted life, despoil our fair world. Destroy them -- 5 Exodus Overseers and 2 Exodus Minions. + RefusalMessage = 1072771; // You must serve Sosaria with all your heart and strength. Your unwillingness does not reflect favorably upon you. + InProgressMessage = 1072779; // Every moment you procrastinate, these unnatural creatures damage Sosaria. + CompletionMessage = 1074167; // Well done! Well done, indeed. You are worthy to become an arcanist! + + Objectives.Add( new KillObjective( 5, new Type[] { typeof( ExodusOverseer ) }, "Exodus Overseers" ) ); + Objectives.Add( new KillObjective( 2, new Type[] { typeof( ExodusMinion ) }, "Exodus Minions" ) ); + + Rewards.Add( new ItemReward( 1031601, typeof( ArcaneCircleScroll ) ) ); // Arcane Circle + Rewards.Add( new ItemReward( 1031600, typeof( SpellweavingBook ) ) ); // Spellweaving Spellbook + Rewards.Add( new ItemReward( 1031602, typeof( GiftOfRenewalScroll ) ) ); // Gift of Renewal + } + + public override void GetRewards( MLQuestInstance instance ) + { + Spellweaving.AwardTo( instance.Player ); + base.GetRewards( instance ); + } + } + + #endregion + + #region Discipline + + public class Discipline : MLQuest + { + public override Type NextQuest { get { return typeof( NeedsOfTheManySanctuary ); } } + + public Discipline() + { + Activated = true; + Title = 1072752; // Discipline + Description = 1072761; // Learning to weave spells and control the forces of nature requires sacrifice, discipline, focus, and an unwavering dedication to Sosaria herself. We do not teach the unworthy. They do not comprehend the lessons nor the dedication required. If you would walk the path of the Arcanist, then you must do as I require without hesitation or question. Your first task is to rid our home of rats ... 50 of them in the next hour. + RefusalMessage = 1072767; // *nods* Not everyone has the temperment to undertake the way of the Arcanist. + InProgressMessage = 1072773; // You waste my time. The task is simple. Kill 50 rats in an hour. + // No completion message + + Objectives.Add( new TimedKillObjective( TimeSpan.FromHours( 1 ), 50, new Type[] { typeof( Rat ) }, "rats", new QuestArea( 1074807, "Sanctuary" ) ) ); // Sanctuary + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Koole" ), new Point3D( 6257, 110, -10 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "Koole" ), new Point3D( 6257, 110, -10 ), Map.Trammel ); + } + } + + public class NeedsOfTheManySanctuary : MLQuest + { + public override Type NextQuest { get { return typeof( MakingAContributionSanctuary ); } } + public override bool IsChainTriggered { get { return true; } } + + public NeedsOfTheManySanctuary() + { + Activated = true; + Title = 1072754; // Needs of the Many - Sanctuary + Description = 1072763; // The way of the Arcanist involves cooperation with others and a strong committment to the community of your people. We have run low on the cotton we use to pack wounds and our people have need. Bring 10 bales of cotton to me. + RefusalMessage = 1072768; // You endanger your progress along the path with your unwillingness. + InProgressMessage = 1072775; // I care not where you acquire the cotton, merely that you provide it. + CompletionMessage = 1074110; // Well, where are the cotton bales? + + Objectives.Add( new CollectObjective( 10, typeof( Cotton ), 1023577 ) ); // bale of cotton + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + } + + public class MakingAContributionSanctuary : MLQuest + { + public override Type NextQuest { get { return typeof( SuppliesForSanctuary ); } } + public override bool IsChainTriggered { get { return true; } } + + public MakingAContributionSanctuary() + { + Activated = true; + Title = 1072755; // Making a Contribution - Sanctuary + Description = 1072764; // We must look to the defense of our people! Bring boards for new arrows. + RefusalMessage = 1072769; // The people have need of these items. You are proving yourself inadequate to the demands of a member of this community. + InProgressMessage = 1072776; // The requirements are simple -- 250 boards. + CompletionMessage = 1074152; // Well, where are the boards? + + Objectives.Add( new CollectObjective( 250, typeof( Board ), 1027127 ) ); // board + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + } + + public class SuppliesForSanctuary : MLQuest + { + public override Type NextQuest { get { return typeof( TheHumanBlight ); } } + public override bool IsChainTriggered { get { return true; } } + + public SuppliesForSanctuary() + { + Activated = true; + Title = 1072756; // Supplies for Sanctuary + Description = 1072765; // With health and defense assured, we need look to the need of the community for food and drink. We will feast on fish steaks, sweets, and wine. You will supply the ingredients, the cooks will prepare the meal. As a Arcanist relies upon others to build focus and lend their power to her workings, the community needs the effort of all to survive. + RefusalMessage = 1072770; // Do not falter now. You have begun to show promise. + InProgressMessage = 1072777; // Where are the items you've been tasked to supply for the feast? + CompletionMessage = 1074158; // Ah good, you're back. We're eager for the feast. + + Objectives.Add( new CollectObjective( 1, typeof( SackFlour ), 1024153 ) ); // sack of flour + Objectives.Add( new CollectObjective( 10, typeof( JarHoney ), 1022540 ) ); // jar of honey + Objectives.Add( new CollectObjective( 20, typeof( FishSteak ), 1022427 ) ); // fish steak + + Rewards.Add( new DummyReward( 1074872 ) ); // The opportunity to learn the ways of the Arcanist. + } + } + + public class TheHumanBlight : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public TheHumanBlight() + { + Activated = true; + Title = 1072757; // The Human Blight + Description = 1072766; // You have proven your desire to contribute to the community and serve the people. Now you must demonstrate your willingness to defend Sosaria from the greatest blight that plagues her. The human vermin that have spread as a disease, despoiling the land are the greatest blight we face. Kill humans and return to me the proof of your actions. Bring me 30 human ears. + RefusalMessage = 1072771; // You must serve Sosaria with all your heart and strength. Your unwillingness does not reflect favorably upon you. + InProgressMessage = 1072778; // Why do you delay? The human blight must be averted. + CompletionMessage = 1074160; // I will take the ears you have collected now. Hand them here. + + Objectives.Add( new CollectObjective( 30, typeof( SeveredHumanEars ), 1032591 ) ); // severed human ears + + Rewards.Add( new ItemReward( 1031601, typeof( ArcaneCircleScroll ) ) ); // Arcane Circle + Rewards.Add( new ItemReward( 1031600, typeof( SpellweavingBook ) ) ); // Spellweaving Spellbook + Rewards.Add( new ItemReward( 1031602, typeof( GiftOfRenewalScroll ) ) ); // Gift of Renewal + } + + public override void GetRewards( MLQuestInstance instance ) + { + Spellweaving.AwardTo( instance.Player ); + base.GetRewards( instance ); + } + } + + #endregion + + #region Friend of the Fey + + public class FriendOfTheFey : MLQuest + { + public override Type NextQuest { get { return typeof( TokenOfFriendship ); } } + + public FriendOfTheFey() + { + Activated = true; + Title = 1074284; // Friend of the Fey + Description = 1074286; // The children of Sosaria understand the dedication and committment of an arcanist -- and will, from time to time offer their friendship. If you would forge such a bond, first seek out a goodwill offering to present. Pixies enjoy sweets and pretty things. + RefusalMessage = 1074288; // There's always time to make new friends. + InProgressMessage = 1074290; // I think honey and some sparkly beads would please a pixie. + CompletionMessage = 1074292; // What have we here? Oh yes, gifts for a pixie. + + Objectives.Add( new CollectObjective( 1, typeof( Beads ), 1024235 ) ); // beads + Objectives.Add( new CollectObjective( 1, typeof( JarHoney ), 1022540 ) ); // jar of honey + + Rewards.Add( new DummyReward( 1074874 ) ); // The opportunity to prove yourself worthy of learning to Summon Fey. (Sufficient spellweaving skill is required to cast the spell) + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Synaeva" ), new Point3D( 7064, 350, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Synaeva" ), new Point3D( 7064, 350, 0 ), Map.Trammel ); + } + } + + public class TokenOfFriendship : MLQuest + { + public override Type NextQuest { get { return typeof( Alliance ); } } + public override bool IsChainTriggered { get { return true; } } + + public TokenOfFriendship() + { + Activated = true; + Title = 1074293; // Token of Friendship + Description = 1074297; // I've wrapped your gift suitably to present to a pixie of discriminating taste. Seek out Arielle and give her your offering. + RefusalMessage = 1074310; // I'll hold onto this gift in case you change your mind. + InProgressMessage = 1074315; // Arielle wanders quite a bit, so I'm not sure exactly where to find her. I'm sure she's going to love your gift. + CompletionMessage = 1074319; // *giggle* Oooh! For me? + + Objectives.Add( new DeliverObjective( typeof( GiftForArielle ), 1, "gift for Arielle", typeof( Arielle ) ) ); + + Rewards.Add( new DummyReward( 1074874 ) ); // The opportunity to prove yourself worthy of learning to Summon Fey. (Sufficient spellweaving skill is required to cast the spell) + } + } + + public class Alliance : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public Alliance() + { + Activated = true; + Title = 1074294; // Alliance + Description = 1074298; // *giggle* Mean reapers make pixies unhappy. *light-hearted giggle* You could fix them! + RefusalMessage = 1074311; // *giggle* Okies! + InProgressMessage = 1074316; // Mean reapers are all around trees! *giggle* You fix them up, please. + CompletionNotice = CompletionNoticeShortReturn; + + Objectives.Add( new KillObjective( 20, new Type[] { typeof( Reaper ) }, "reapers" ) ); + + Rewards.Add( new ItemReward( 1031607, typeof( SummonFeyScroll ) ) ); // Summon Fey + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.PlayerContext.SummonFey = true; + instance.Player.SendLocalizedMessage( 1074320, "", 0x2A ); // *giggle* Mean reapers got fixed! Pixie friend now! *giggle* When mean thingies bother you, a brave pixie will help. + + base.GetRewards( instance ); + } + } + + #endregion + + #region Fiendish Friends + + public class FiendishFriends : MLQuest + { + public override Type NextQuest { get { return typeof( CrackingTheWhipI ); } } + + public FiendishFriends() + { + Activated = true; + Title = 1074283; // Fiendish Friends + Description = 1074285; // It is true that a skilled arcanist can summon and dominate an imp to serve at their pleasure. To do such at thing though, you must master the miserable little fiends utterly by demonstrating your superiority. Rough them up some -- kill a few. That will do the trick. + RefusalMessage = 1074287; // You're probably right. They're not worth the effort. + InProgressMessage = 1074289; // Surely you're not having difficulties swatting down those annoying pests? + // TODO: Verify + CompletionMessage = 1074291; // Hah! You showed them! + + Objectives.Add( new KillObjective( 50, new Type[] { typeof( Imp ) }, "imps" ) ); + + Rewards.Add( new DummyReward( 1074873 ) ); // The opportunity to prove yourself worthy of learning to Summon Fiends. (Sufficient spellweaving skill is required to cast the spell) + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderBrae" ), new Point3D( 6266, 124, 0 ), Map.Felucca ); + PutSpawner( new Spawner( 1, 5, 10, 0, 0, "ElderBrae" ), new Point3D( 6266, 124, 0 ), Map.Trammel ); + } + } + + // TODO: Verify + public class CrackingTheWhipI : MLQuest + { + public override Type NextQuest { get { return typeof( CrackingTheWhipII ); } } + public override bool IsChainTriggered { get { return true; } } + + public CrackingTheWhipI() + { + Activated = true; + Title = 1074295; // Cracking the Whip + Description = 1074300; // Now that you've shown those mini pests your might, you should collect suitable implements to use to train your summoned pet. I suggest a stout whip. + RefusalMessage = 1074313; // Heh. Changed your mind, eh? + InProgressMessage = 1074317; // Well, hurry up. If you don't get a whip how do you expect to control the little devil? + CompletionMessage = 1074321; // That's a well-made whip. No imp will ignore the sting of that lash. + + Objectives.Add( new CollectObjective( 1, typeof( StoutWhip ), "Stout Whip" ) ); + + Rewards.Add( new DummyReward( 1074873 ) ); // The opportunity to prove yourself worthy of learning to Summon Fiends. (Sufficient spellweaving skill is required to cast the spell) + } + } + + // TODO: Verify + public class CrackingTheWhipII : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public CrackingTheWhipII() + { + Activated = true; + Title = 1074295; // Cracking the Whip + Description = 1074302; // Now you just need to make the little buggers fear you -- if you can slay an arcane daemon, you'll earn their subservience. + RefusalMessage = 1074314; // If you're not up for it, so be it. + InProgressMessage = 1074318; // You need to vanquish an arcane daemon before the imps will fear you properly. + + Objectives.Add( new KillObjective( 1, new Type[] { typeof( ArcaneDaemon ) }, 1029733 ) ); // arcane demon + + Rewards.Add( new ItemReward( 1031608, typeof( SummonFiendScroll ) ) ); // Summon Fiend + } + + public override void GetRewards( MLQuestInstance instance ) + { + instance.PlayerContext.SummonFiend = true; + instance.Player.SendLocalizedMessage( 1074322, "", 0x2A ); // You've demonstrated your strength, got a means of control, and taught the imps to fear you. You're ready now to summon them. + + base.GetRewards( instance ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Aeluva (The Heartwood)" )] + public class Aeluva : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + /* + * 1074206 - Excuse me please traveler, might I have a little of your time? + * 1074207 - Good day to you friend! Allow me to offer you a fabulous opportunity!  Thrills and adventure await! + */ + MLQuestSystem.Tell( this, pm, Utility.Random( 1074206, 2 ) ); + } + + [Constructable] + public Aeluva() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 ) + { + Name = "Aeluva"; + Title = "the arcanist"; + Race = Race.Elf; + Female = true; + Body = 606; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenShirt() ); + AddItem( new Kilt( Utility.RandomNondyedHue() ) ); // Note: OSI hue = 0x1516, typo? + AddItem( new ElvenBoots() ); + AddItem( new Circlet() ); + } + + public Aeluva( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Koole (Sanctuary)" )] + public class Koole : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074186, // Come here, I have a task. + 1074218 // Hey! I want to talk to you, now. + ) ); + } + + [Constructable] + public Koole() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 ) + { + Name = "Koole"; + Title = "the arcanist"; + Race = Race.Elf; + Body = 605; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + Item item; + + item = new LeafChest(); + item.Hue = 443; + AddItem( item ); + + item = new LeafArms(); + item.Hue = 443; + AddItem( item ); + + AddItem( new LeafTonlet() ); + AddItem( new ThighBoots( Utility.RandomAnimalHue() ) ); + AddItem( new RoyalCirclet() ); + } + + public Koole( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Synaeva (The Heartwood)" )] + public class Synaeva : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074223 ); // Have you done it yet?  Oh, I haven’t told you, have I? + } + + [Constructable] + public Synaeva() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 ) + { + Name = "Synaeva"; + Title = "the arcanist"; + Race = Race.Elf; + Female = true; + Body = 606; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + Item item = new RavenHelm(); + item.Hue = Utility.RandomGreenHue(); + AddItem( item ); + + AddItem( new FemaleLeafChest() ); + AddItem( new LeafArms() ); + AddItem( new LeafTonlet() ); + AddItem( new ElvenBoots() ); + AddItem( new WildStaff() ); + } + + public Synaeva( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Elder Brae (Sanctuary)" )] + public class ElderBrae : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, Utility.RandomList( + 1074215, // Don’t test my patience you sniveling worm! + 1074218 // Hey!  I want to talk to you, now. + ) ); + } + + [Constructable] + public ElderBrae() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2.0 ) + { + Name = "Elder Brae"; + Title = "the wise"; + Race = Race.Elf; + Female = true; + Body = 606; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new GemmedCirclet() ); + AddItem( new FemaleElvenRobe( Utility.RandomBrightHue() ) ); + AddItem( new ElvenBoots( Utility.RandomAnimalHue() ) ); + } + + public ElderBrae( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/TheAncientWorld.cs b/Scripts/Engines/MLQuests/Definitions/TheAncientWorld.cs new file mode 100644 index 0000000..04d4217 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/TheAncientWorld.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class TheAncientWorld : MLQuest + { + public override Type NextQuest { get { return typeof( TheGoldenHorn ); } } + + public TheAncientWorld() + { + Activated = true; + Title = 1074534; // The Ancient World + Description = 1074535; // The lore of my people mentions Mondain many times. In one tale, it is revealed that he created and enslaved a race -- a sort of man bull, known as a 'minotaur'. The tales speak of mighty warriors who charged with blood-soaked horns into the heat of battle. But, alas, the fate of the bull-men is unknown after the rupture. Will you seek information about their civilization? + RefusalMessage = 1074538; // I am disappointed, but I respect your decision. + InProgressMessage = 1074539; // A traveler has told me that worshippers of Mondain still exist and wander the land. Perhaps their lore speaks of whether the bull-men survived. I do not think they share their secrets gladly. You may need to be 'persuasive'. + CompletionMessage = 1074542; // What have you found? + + Objectives.Add( new CollectObjective( 1, typeof( FragmentOfAMap ), "fragment of a map" ) ); + + Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperBroolol" ), new Point3D( 7011, 375, 0 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 5, "LorekeeperBroolol" ), new Point3D( 7011, 375, 0 ), Map.Felucca ); + } + } + + public class TheGoldenHorn : MLQuest + { + public override Type NextQuest { get { return typeof( Bullish ); } } + public override bool IsChainTriggered { get { return true; } } + + public TheGoldenHorn() + { + Activated = true; + Title = 1074543; // The Golden Horn + Description = 1074545; // Ah ha! You see here ... and over here ... The map fragment places the city of the bull-men, Labyrinth, on that piece of Sosaria that was thrown into the sky. Hmmm, I would have you go there and find any artifacts that remain that help tell the story. But, legend speaks of a mighty barrier to prevent invasion of the city. Take this map to Braen and explain the problem. Perhaps he can devise a solution. + RefusalMessage = 1074538; // I am disappointed, but I respect your decision. + InProgressMessage = 1074547; // Braen is nearby, run and speak with him. + CompletionMessage = 1074549; // Yes? What do you want? I'm very busy. + + Objectives.Add( new DeliverObjective( typeof( FragmentOfAMapDelivery ), 1, "fragment of a map", typeof( Braen ) ) ); + + Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur. + } + } + + public class Bullish : MLQuest + { + public override Type NextQuest { get { return typeof( LostCivilization ); } } + public override bool IsChainTriggered { get { return true; } } + + public Bullish() + { + Activated = true; + Title = 1074550; // Bullish + Description = 1074552; // Oh, I see. I will need some materials to infuse you with the essence of a bull-man, so you can fool their defenses. The most similar beast to the original Baratarian bull that the minotaur were bred from is undoubtedly the mighty Gaman, native to the Lands of the Feudal Lords. I need horns, in great quantity to undertake this magic. + RefusalMessage = 1074554; // Oh come now, don't be afraid. The magic won't harm you. + InProgressMessage = 1074555; // I cannot grant you the ability to pass through the bull-men's defenses without the gaman horns. + CompletionMessage = 1074556; // You've returned at last! Give me just a moment to examine what you've brought and I can perform the magic that will allow you enter the Labyrinth. + + Objectives.Add( new CollectObjective( 20, typeof( GamanHorns ), "gaman horns" ) ); + + Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur. + } + } + + public class LostCivilization : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public LostCivilization() + { + Activated = true; + Title = 1074823; // Lost Civilization + Description = 1074825; // *whew* It is done! The fierce essence of the bull has been infused into your aura. You are able now to breach the ancient defenses of the city. Go forth and seek the minotaur -- and then return with wonderous tales and evidence of your visit to the Labyrinth. + RefusalMessage = 1074827; // As you wish. I can't understand why you'd pass up such a remarkable opportunity. Think of the adventures you would have. + InProgressMessage = 1074828; // You won't reach the minotaur city by loitering around here! What are you waiting for? You need to get to Malas and find the access point for the island. You'll be renowned for your discovery! + CompletionMessage = 1074829; // Oh! You've returned at last! I can't wait to hear the tales ... but first, let me see those artifacts. You've certainly earned this reward. + + Objectives.Add( new CollectObjective( 3, typeof( MinotaurArtifact ), "minotaur artifacts" ) ); + + Rewards.Add( ItemReward.Strongbox ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Broolol (The Heartwood)" )] + public class LorekeeperBroolol : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + public override bool CanTeach { get { return true; } } + + public override bool CanShout { get { return true; } } + public override void Shout( PlayerMobile pm ) + { + MLQuestSystem.Tell( this, pm, 1074200 ); // Thank goodness you are here, there�s no time to lose. + } + + [Constructable] + public LorekeeperBroolol() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Lorekeeper Broolol"; + Title = "the keeper of tradition"; + Race = Race.Elf; + BodyValue = 0x25E; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + SetSkill( SkillName.Meditation, 60.0, 80.0 ); + SetSkill( SkillName.Focus, 60.0, 80.0 ); + + AddItem( new ElvenBoots( 0x70D ) ); + AddItem( new FemaleElvenRobe( 0x3A ) ); + AddItem( new WildStaff() ); + } + + public LorekeeperBroolol( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/TownEscorts.cs b/Scripts/Engines/MLQuests/Definitions/TownEscorts.cs new file mode 100644 index 0000000..81f8759 --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/TownEscorts.cs @@ -0,0 +1,131 @@ +using System; +using Server; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; + +namespace Server.Engines.MLQuests.Definitions +{ + public class TownEscort : BaseEscort + { + // Escort reward + private static readonly BaseReward m_Reward = new ItemReward( "Gold", typeof( Gold ), 500 ); + + public TownEscort( int title, int progress, int destination, string region ) + { + Activated = true; + Title = title; + Description = 1072287; // I seek a worthy escort. I can offer some small pay to any able bodied adventurer who can assist me. It is imperative that I reach my destination. + RefusalMessage = 1072288; // I wish you would reconsider my offer. I'll be waiting right here for someone brave enough to assist me. + InProgressMessage = progress; + + Objectives.Add( new EscortObjective( new QuestArea( destination, region ) ) ); + + Rewards.Add( m_Reward ); + } + } + + public class EscortToYew : TownEscort + { + public EscortToYew() + : base( 1072275, 1072289, 1072227, "Yew" ) + { + } + } + + public class EscortToVesper : TownEscort + { + public EscortToVesper() + : base( 1072276, 1072290, 1072229, "Vesper" ) + { + } + } + + public class EscortToTrinsic : TownEscort + { + public EscortToTrinsic() + : base( 1072277, 1072291, 1072236, "Trinsic" ) + { + } + } + + public class EscortToSkaraBrae : TownEscort + { + public EscortToSkaraBrae() + : base( 1072278, 1072292, 1072235, "Skara Brae" ) + { + } + } + + public class EscortToSerpentsHold : TownEscort + { + public EscortToSerpentsHold() + : base( 1072279, 1072293, 1072238, "Serpent's Hold" ) + { + } + } + + public class EscortToNujelm : TownEscort + { + public EscortToNujelm() + : base( 1072280, 1072294, 1072237, "Nujel'm" ) + { + } + } + + public class EscortToMoonglow : TownEscort + { + public EscortToMoonglow() + : base( 1072281, 1072295, 1072232, "Moonglow" ) + { + } + } + + public class EscortToMinoc : TownEscort + { + public EscortToMinoc() + : base( 1072282, 1072296, 1072228, "Minoc" ) + { + } + } + + public class EscortToMagincia : TownEscort + { + public EscortToMagincia() + : base( 1072283, 1072297, 1072233, "Magincia" ) + { + } + } + + public class EscortToJhelom : TownEscort + { + public EscortToJhelom() + : base( 1072284, 1072298, 1072239, "Jhelom" ) + { + } + } + + public class EscortToCove : TownEscort + { + public EscortToCove() + : base( 1072285, 1072299, 1072230, "Cove" ) + { + } + } + + public class EscortToBritain : TownEscort + { + public EscortToBritain() + : base( 1072286, 1072300, 1072231, "Britain" ) + { + } + } + + public class EscortToOcllo : TownEscort + { + public EscortToOcllo() + : base( 1072312, 1072313, 1072234, "Ocllo" ) + { + } + } +} diff --git a/Scripts/Engines/MLQuests/Definitions/UnfadingMemories.cs b/Scripts/Engines/MLQuests/Definitions/UnfadingMemories.cs new file mode 100644 index 0000000..9c2f1ca --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/UnfadingMemories.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + #region Quests + + public class UnfadingMemoriesPartOne : MLQuest + { + public override Type NextQuest { get { return typeof( UnfadingMemoriesPartTwo ); } } + + public UnfadingMemoriesPartOne() + { + Activated = true; + Title = 1075355; // Unfading Memories + Description = 1075356; // Aargh! It�s just not right! It doesn�t capture the unique color of her hair at all! If only I had some Prismatic Amber. That would be perfect. They used to mine it in Malas, but alas, those veins ran dry some time ago. I hear it may have been found in the Prism of Light. Oh, if only there were a bold adventurer within earshot who would go to the Prism of Light and retrieve some for me! + RefusalMessage = 1075358; // Is there no one who can help a humble artist pursue his Muse? + InProgressMessage = 1075359; // You can find Prismatic Amber in the Prism of Light, located just north of the city of Nujel'm. + CompletionMessage = 1075360; // I knew it! See, it�s just the color I needed! Look how it brings out the highlights of her wheaten tresses! + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new CollectObjective( 1, typeof( PrismaticAmber ), "Prismatic Amber" ) ); + + Rewards.Add( new DummyReward( 1075357 ) ); // The joy of contributing to a noble artistic effort, however paltry the end product. + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Emilio" ), new Point3D( 1447, 1664, 10 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Emilio" ), new Point3D( 1447, 1664, 10 ), Map.Felucca ); + } + } + + public class UnfadingMemoriesPartTwo : MLQuest + { + public override Type NextQuest { get { return typeof( UnfadingMemoriesPartThree ); } } + public override bool IsChainTriggered { get { return true; } } + + public UnfadingMemoriesPartTwo() + { + Activated = true; + Title = 1075367; // Unfading Memories + Description = 1075368; // Finished! With the pigment I was able to create from the Prismatic Amber you brought me, I was able to complete my humble work. I should explain. Once, I loved a noble lady of gentleness and refinement, who possessed such beauty that I have found myself unable to love another to this day. But it was from afar that I admired her, for it is not for one so lowly as I to pay court to the likes of her. You have heard of the fair Thalia, Lady of Nujel'm? No? Well, she was my Muse, my inspiration, and when I heard she was to be married, I lost whatever pitiful talent I possessed. I felt I must compose a portrait of her, my masterpiece, or I would never be able to paint again. You, my friend, have helped me complete my work. Now I ask another favor of you. Will you take it to her as a wedding gift? She will probably reject it, but I must make the offer. + RefusalMessage = 1075370; // Alright then, you have already helped me more than I deserved. I shall find someone else to undertake this task. + InProgressMessage = 1075371; // The wedding is taking place in the palace in Nujel'm. You will likely find her there. + CompletionMessage = 1075372; // I�m sorry, I�m getting ready to be married. I don�t have time to . . . what�s that you say? + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( PortraitOfTheBride ), 1, "Portrait of the Bride", typeof( Thalia ) ) ); + + Rewards.Add( new DummyReward( 1075369 ) ); // The Artist�s gratitude. + } + } + + public class UnfadingMemoriesPartThree : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public UnfadingMemoriesPartThree() + { + Activated = true; + OneTimeOnly = true; + Title = 1075373; // Unfading Memories + Description = 1075374; // Emilio painted this? It is absolutely wonderful! I used to love looking at his paintings, but I don�t remember him creating anything like this before. Would you be so kind as to carry a letter to him? Fate may have it that I am to marry another, yet I am compelled to reveal to him that his love was not entirely unrequited. + RefusalMessage = 1075376; // Very well, then. If you will excuse me, I need to get ready. + InProgressMessage = 1075377; // Take the letter back to the Artist�s Guild in Britain, if you would do me this kindness. + CompletionMessage = 1075378; // She said what? She thinks what of me? I . . . I can�t believe it! All this time, I never knew how she truly felt. Thank you, my friend. I believe now I will be able to paint once again. Here, take this bleach. I was going to use it to destroy all of my works. Perhaps you can find a better use for it now. + CompletionNotice = CompletionNoticeShort; + + Objectives.Add( new DeliverObjective( typeof( BridesLetter ), 1, "Bride's Letter", typeof( Emilio ) ) ); + + Rewards.Add( new ItemReward( 1075375, typeof( Bleach ) ) ); // Bleach + } + + public override void Generate() + { + base.Generate(); + + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Thalia" ), new Point3D( 3675, 1322, 20 ), Map.Trammel ); + PutSpawner( new Spawner( 1, 5, 10, 0, 3, "Thalia" ), new Point3D( 3675, 1322, 20 ), Map.Felucca ); + } + } + + #endregion + + #region Mobiles + + [QuesterName( "Emilio (Britain)" )] // OSI's description is "Artist", not very helpful + public class Emilio : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Emilio() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Emilio"; + Title = "the Tortured Artist"; + Race = Race.Human; + BodyValue = 0x190; + Female = false; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Sandals( 0x72B ) ); + AddItem( new LongPants( 0x525 ) ); + AddItem( new FancyShirt( 0x53F ) ); + AddItem( new FloppyHat( 0x58C ) ); + AddItem( new BodySash( 0x1C ) ); + + } + + public Emilio( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [QuesterName( "Thalia (Nujel'm)" )] // OSI's description is "Bride", not very helpful + public class Thalia : BaseCreature + { + public override bool IsInvulnerable { get { return true; } } + + [Constructable] + public Thalia() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + Name = "Thalia"; + Title = "the Bride"; + Race = Race.Human; + BodyValue = 0x191; + Female = true; + Hue = Race.RandomSkinHue(); + InitStats( 100, 100, 25 ); + + Utility.AssignRandomHair( this, true ); + + AddItem( new Backpack() ); + AddItem( new Sandals( 0x8FD ) ); + AddItem( new FancyDress( 0x8FD ) ); + + } + + public Thalia( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/Definitions/WarriorsOfTheGemKeeper.cs b/Scripts/Engines/MLQuests/Definitions/WarriorsOfTheGemKeeper.cs new file mode 100644 index 0000000..e043a0b --- /dev/null +++ b/Scripts/Engines/MLQuests/Definitions/WarriorsOfTheGemKeeper.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Definitions +{ + public class WarriorsOfTheGemkeeper : MLQuest + { + public override Type NextQuest { get { return typeof( CloseEnough ); } } + + public WarriorsOfTheGemkeeper() + { + Activated = true; + Title = 1074536; // Warriors of the Gemkeeper + Description = 1074537; // Here we honor the Gemkeeper's Apprentice and seek to aid her efforts against the humans responsible for the death of her teacher - and the destruction of the elven way of life. Our tales speak of a fierce race of servants of the Gemkeeper, the men-bulls whose battle-skill was renowned. It is desireable to discover the fate of these noble creatures after the Rupture. Will you seek information? + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074540; // I care not how you get the information. Kill as many humans as you must ... but find the fate of the minotaurs. Perhaps another of the Gemkeeper's servants has the knowledge we seek. + CompletionMessage = 1074542; // What have you found? + + Objectives.Add( new CollectObjective( 1, typeof( FragmentOfAMap ), "fragment of a map" ) ); + + Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur. + } + } + + public class CloseEnough : MLQuest + { + public override Type NextQuest { get { return typeof( TakingTheBullByTheHorns ); } } + public override bool IsChainTriggered { get { return true; } } + + public CloseEnough() + { + Activated = true; + Title = 1074544; // Close Enough + Description = 1074546; // Ah ha! You see here ... and over here ... The map fragment places the city of the bull-men, Labyrinth, on that piece of Sosaria that was thrown into the sky. Hmmm, I would have you go there and seek out these warriors to see if they might join our cause. But, legend speaks of a mighty barrier to prevent invasion of the city. Take this map to Canir and explain the problem. Perhaps she can devise a solution. + RefusalMessage = 1074063; // Fine then, I'm shall find another to run my errands then. + InProgressMessage = 1074548; // Canir is nearby, run and speak with her. + CompletionMessage = 1074549; // Yes? What do you want? I'm very busy. + + Objectives.Add( new DeliverObjective( typeof( FragmentOfAMapDelivery ), 1, "fragment of a map", typeof( Canir ) ) ); + + Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur. + } + } + + public class TakingTheBullByTheHorns : MLQuest + { + public override Type NextQuest { get { return typeof( EmissaryToTheMinotaur ); } } + public override bool IsChainTriggered { get { return true; } } + + public TakingTheBullByTheHorns() + { + Activated = true; + Title = 1074551; // Taking the Bull by the Horns + Description = 1074553; // Interesting. I believe I have a way. I will need some materials to infuse you with the essence of a bull-man, so you can fool their defenses. The most similar beast to the original Baratarian bull that the minotaur were bred from is undoubtedly the mighty Gaman, native to the Lands of the Feudal Lords. I need horns, in great quantity to undertake this magic. + RefusalMessage = 1074554; // Oh come now, don't be afraid. The magic won't harm you. + InProgressMessage = 1074555; // I cannot grant you the ability to pass through the bull-men's defenses without the gaman horns. + CompletionMessage = 1074556; // You've returned at last! Give me just a moment to examine what you've brought and I can perform the magic that will allow you enter the Labyrinth. + + Objectives.Add( new CollectObjective( 20, typeof( GamanHorns ), "gaman horns" ) ); + + Rewards.Add( new DummyReward( 1074876 ) ); // Knowledge of the legendary minotaur. + } + } + + public class EmissaryToTheMinotaur : MLQuest + { + public override bool IsChainTriggered { get { return true; } } + + public EmissaryToTheMinotaur() + { + Activated = true; + Title = 1074824; // Emissary to the Minotaur + Description = 1074825; // *whew* It is done! The fierce essence of the bull has been infused into your aura. You are able now to breach the ancient defenses of the city. Go forth and seek the minotaur -- and then return with wonderous tales and evidence of your visit to the Labyrinth. + RefusalMessage = 1074827; // As you wish. I can't understand why you'd pass up such a remarkable opportunity. Think of the adventures you would have. + InProgressMessage = 1074828; // You won't reach the minotaur city by loitering around here! What are you waiting for? You need to get to Malas and find the access point for the island. You'll be renowned for your discovery! + CompletionMessage = 1074829; // Oh! You've returned at last! I can't wait to hear the tales ... but first, let me see those artifacts. You've certainly earned this reward. + + Objectives.Add( new CollectObjective( 3, typeof( MinotaurArtifact ), "minotaur artifacts" ) ); + + Rewards.Add( ItemReward.Strongbox ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/BaseQuestGump.cs b/Scripts/Engines/MLQuests/Gumps/BaseQuestGump.cs new file mode 100644 index 0000000..6c1d988 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/BaseQuestGump.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; + +namespace Server.Engines.MLQuests.Gumps +{ + public enum ButtonPosition : byte + { + Left, + Right + } + + public enum ButtonGraphic : ushort + { + Invalid, + Accept = 0x2EE0, + Clear = 0x2EE3, + Close = 0x2EE6, + Continue = 0x2EE9, + Okay = 0x2EEC, + Previous = 0x2EEF, + Refuse = 0x2EF2, + Resign = 0x2EF5 + } + + public abstract class BaseQuestGump : Gump + { + private struct ButtonInfo + { + private ButtonPosition m_Position; + private ButtonGraphic m_Graphic; + private int m_ButtonID; + + public ButtonPosition Position { get { return m_Position; } } + public ButtonGraphic Graphic { get { return m_Graphic; } } + public int ButtonID { get { return m_ButtonID; } } + + public ButtonInfo( ButtonPosition position, ButtonGraphic graphic, int buttonID ) + { + m_Position = position; + m_Graphic = graphic; + m_ButtonID = buttonID; + } + } + + private int m_Page; + private int m_MaxPages; + private int m_Label; + private string m_Title; + private List m_Buttons; + +#if false + // OSI clone, inefficient layout + public BaseQuestGump( int label ) : base( 75, 25 ) + { + m_Page = 0; + m_MaxPages = 0; + m_Label = label; + m_Title = null; + m_Buttons = new List( 2 ); + } + + public void BuildPage() + { + AddPage( ++m_Page ); + + Closable = false; + AddImageTiled( 50, 20, 400, 460, 0x1404 ); + AddImageTiled( 50, 29, 30, 450, 0x28DC ); + AddImageTiled( 34, 140, 17, 339, 0x242F ); + AddImage( 48, 135, 0x28AB ); + AddImage( -16, 285, 0x28A2 ); + AddImage( 0, 10, 0x28B5 ); + AddImage( 25, 0, 0x28B4 ); + AddImageTiled( 83, 15, 350, 15, 0x280A ); + AddImage( 34, 479, 0x2842 ); + AddImage( 442, 479, 0x2840 ); + AddImageTiled( 51, 479, 392, 17, 0x2775 ); + AddImageTiled( 415, 29, 44, 450, 0xA2D ); + AddImageTiled( 415, 29, 30, 450, 0x28DC ); + AddLabel( 100, 50, 0x481, "" ); + AddImage( 370, 50, 0x589 ); + AddImage( 379, 60, 0x15A9 ); + AddImage( 425, 0, 0x28C9 ); + AddImage( 90, 33, 0x232D ); + AddHtmlLocalized( 130, 45, 270, 16, m_Label, 0xFFFFFF, false, false ); + AddImageTiled( 130, 65, 175, 1, 0x238D ); + + if ( m_Page > 1 ) + AddButton( 130, 430, (int)ButtonGraphic.Previous, (int)ButtonGraphic.Previous + 2, 0, GumpButtonType.Page, m_Page - 1 ); + + if ( m_Page < m_MaxPages ) + AddButton( 275, 430, (int)ButtonGraphic.Continue, (int)ButtonGraphic.Continue + 2, 0, GumpButtonType.Page, m_Page + 1 ); + + foreach ( ButtonInfo button in m_Buttons ) + AddButton( button.Position == ButtonPosition.Left ? 95 : 313, 455, (int)button.Graphic, (int)button.Graphic + 2, button.ButtonID, GumpButtonType.Reply, 0 ); + + if ( m_Title != null ) + AddHtmlLocalized( 130, 68, 220, 48, 1114513, m_Title, 0x2710, false, false ); //
~1_TOKEN~
+ } +#else + // RunUO optimized version + public BaseQuestGump( int label ) + : base( 75, 25 ) + { + m_Page = 0; + m_MaxPages = 0; + m_Label = label; + m_Title = null; + m_Buttons = new List( 2 ); + + Closable = false; + + AddPage( 0 ); + + AddImageTiled( 50, 20, 400, 460, 0x1404 ); + AddImageTiled( 50, 29, 30, 450, 0x28DC ); + AddImageTiled( 34, 140, 17, 339, 0x242F ); + AddImage( 48, 135, 0x28AB ); + AddImage( -16, 285, 0x28A2 ); + AddImage( 0, 10, 0x28B5 ); + AddImage( 25, 0, 0x28B4 ); + AddImageTiled( 83, 15, 350, 15, 0x280A ); + AddImage( 34, 479, 0x2842 ); + AddImage( 442, 479, 0x2840 ); + AddImageTiled( 51, 479, 392, 17, 0x2775 ); + AddImageTiled( 415, 29, 44, 450, 0xA2D ); + AddImageTiled( 415, 29, 30, 450, 0x28DC ); + //AddLabel( 100, 50, 0x481, "" ); + AddImage( 370, 50, 0x589 ); + AddImage( 379, 60, 0x15A9 ); + AddImage( 425, 0, 0x28C9 ); + AddImage( 90, 33, 0x232D ); + AddHtmlLocalized( 130, 45, 270, 16, label, 0xFFFFFF, false, false ); + AddImageTiled( 130, 65, 175, 1, 0x238D ); + } + + public void BuildPage() + { + AddPage( ++m_Page ); + + if ( m_Page > 1 ) + AddButton( 130, 430, (int)ButtonGraphic.Previous, (int)ButtonGraphic.Previous + 2, 0, GumpButtonType.Page, m_Page - 1 ); + + if ( m_Page < m_MaxPages ) + AddButton( 275, 430, (int)ButtonGraphic.Continue, (int)ButtonGraphic.Continue + 2, 0, GumpButtonType.Page, m_Page + 1 ); + + foreach ( ButtonInfo button in m_Buttons ) + AddButton( button.Position == ButtonPosition.Left ? 95 : 313, 455, (int)button.Graphic, (int)button.Graphic + 2, button.ButtonID, GumpButtonType.Reply, 0 ); + + if ( m_Title != null ) + AddHtmlLocalized( 130, 68, 220, 48, 1114513, m_Title, 0x2710, false, false ); //
~1_TOKEN~
+ } +#endif + + public void SetPageCount( int maxPages ) + { + m_MaxPages = maxPages; + } + + public void SetTitle( TextDefinition def ) + { + if ( def.Number > 0 ) + m_Title = String.Format( "#{0}", def.Number ); // OSI does "@@#{0}" instead, why? KR client related? + else + m_Title = def.String; + } + + public void RegisterButton( ButtonPosition position, ButtonGraphic graphic, int buttonID ) + { + m_Buttons.Add( new ButtonInfo( position, graphic, buttonID ) ); + } + + #region Elaborate Formatting Shortcuts + + public void AddDescription( MLQuest quest ) + { + AddHtmlLocalized( 98, 140, 312, 16, ( quest.IsChainTriggered || quest.NextQuest != null ) ? 1075024 : 1072202, 0x2710, false, false ); // Description [(quest chain)] + TextDefinition.AddHtmlText( this, 98, 156, 312, 240, quest.Description, false, true, 0x15F90, 0xBDE784 ); + } + + public void AddObjectives( MLQuest quest ) + { + AddHtmlLocalized( 98, 140, 312, 16, 1049073, 0x2710, false, false ); // Objective: + AddHtmlLocalized( 98, 156, 312, 16, ( quest.ObjectiveType == ObjectiveType.All ) ? 1072208 : 1072209, 0x2710, false, false ); // All of the following / Only one of the following + + int y = 172; + + foreach ( BaseObjective objective in quest.Objectives ) + { + objective.WriteToGump( this, ref y ); + + if ( objective.IsTimed ) + { + if ( objective is CollectObjective ) + y -= 16; + + BaseObjectiveInstance.WriteTimeRemaining( this, ref y, objective.Duration ); + } + } + } + + public void AddObjectivesProgress( MLQuestInstance instance ) + { + MLQuest quest = instance.Quest; + + AddHtmlLocalized( 98, 140, 312, 16, 1049073, 0x2710, false, false ); // Objective: + AddHtmlLocalized( 98, 156, 312, 16, ( quest.ObjectiveType == ObjectiveType.All ) ? 1072208 : 1072209, 0x2710, false, false ); // All of the following / Only one of the following + + int y = 172; + + foreach ( BaseObjectiveInstance objInstance in instance.Objectives ) + objInstance.WriteToGump( this, ref y ); + } + + public void AddRewardsPage( MLQuest quest ) // For the quest log/offer gumps + { + AddHtmlLocalized( 98, 140, 312, 16, 1072201, 0x2710, false, false ); // Reward + + int y = 162; + + if ( quest.Rewards.Count > 1 ) + { + // TODO: Is this what this is for? Does "Only one of the following" occur? + AddHtmlLocalized( 98, 156, 312, 16, 1072208, 0x2710, false, false ); // All of the following + y += 16; + } + + AddRewards( quest, 105, y, 16 ); + } + + public void AddRewards( MLQuest quest ) // For the claim rewards gump + { + int y = 146; + + if ( quest.Rewards.Count > 1 ) + { + // TODO: Is this what this is for? Does "Only one of the following" occur? + AddHtmlLocalized( 100, 140, 312, 16, 1072208, 0x2710, false, false ); // All of the following + y += 16; + } + + AddRewards( quest, 107, y, 26 ); + } + + public void AddRewards( MLQuest quest, int x, int y, int spacing ) + { + int xReward = x + 28; + + foreach ( BaseReward reward in quest.Rewards ) + { + AddImage( x, y + 1, 0x4B9 ); + reward.WriteToGump( this, xReward, ref y ); + y += spacing; + } + } + + public void AddConversation( TextDefinition text ) + { + TextDefinition.AddHtmlText( this, 98, 140, 312, 180, text, false, true, 0x15F90, 0xBDE784 ); + } + + #endregion + + /* OSI gump IDs: + * 800 - QuestOfferGump + * 801 - QuestCancelConfirmGump + * 802 - ?? (gets closed by Toggle Quest Item) + * 803 - QuestRewardGump + * 804 - ?? (gets closed by Toggle Quest Item) + * 805 - QuestLogGump + * 806 - QuestConversationGump (refuse / in progress) + * 807 - ?? (gets closed by Toggle Quest Item and most quest gumps) + * 808 - InfoNPCGump + * 809 - QuestLogDetailedGump + * 810 - QuestReportBackGump + */ + public static void CloseOtherGumps( PlayerMobile pm ) + { + pm.CloseGump( typeof( InfoNPCGump ) ); + pm.CloseGump( typeof( QuestRewardGump ) ); + pm.CloseGump( typeof( QuestConversationGump ) ); + pm.CloseGump( typeof( QuestReportBackGump ) ); + //pm.CloseGump( typeof( UnknownGump807 ) ); + pm.CloseGump( typeof( QuestCancelConfirmGump ) ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/InfoNPCGump.cs b/Scripts/Engines/MLQuests/Gumps/InfoNPCGump.cs new file mode 100644 index 0000000..8b38c6f --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/InfoNPCGump.cs @@ -0,0 +1,22 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class InfoNPCGump : BaseQuestGump + { + public InfoNPCGump( TextDefinition title, TextDefinition message ) + : base( 1060668 ) // INFORMATION + { + RegisterButton( ButtonPosition.Left, ButtonGraphic.Close, 3 ); + + SetPageCount( 1 ); + + BuildPage(); + TextDefinition.AddHtmlText( this, 160, 108, 250, 16, title, false, false, 0x2710, 0x4AC684 ); + TextDefinition.AddHtmlText( this, 98, 156, 312, 180, message, false, true, 0x15F90, 0xBDE784 ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestCancelConfirmGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestCancelConfirmGump.cs new file mode 100644 index 0000000..0e69ba5 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestCancelConfirmGump.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestCancelConfirmGump : Gump + { + private MLQuestInstance m_Instance; + private bool m_CloseGumps; + + public QuestCancelConfirmGump( MLQuestInstance instance ) + : this( instance, true ) + { + } + + public QuestCancelConfirmGump( MLQuestInstance instance, bool closeGumps ) + : base( 120, 50 ) + { + m_Instance = instance; + m_CloseGumps = closeGumps; + + if ( closeGumps ) + BaseQuestGump.CloseOtherGumps( instance.Player ); + + AddPage( 0 ); + + Closable = false; + + AddImageTiled( 0, 0, 348, 262, 0xA8E ); + AddAlphaRegion( 0, 0, 348, 262 ); + + AddImage( 0, 15, 0x27A8 ); + AddImageTiled( 0, 30, 17, 200, 0x27A7 ); + AddImage( 0, 230, 0x27AA ); + + AddImage( 15, 0, 0x280C ); + AddImageTiled( 30, 0, 300, 17, 0x280A ); + AddImage( 315, 0, 0x280E ); + + AddImage( 15, 244, 0x280C ); + AddImageTiled( 30, 244, 300, 17, 0x280A ); + AddImage( 315, 244, 0x280E ); + + AddImage( 330, 15, 0x27A8 ); + AddImageTiled( 330, 30, 17, 200, 0x27A7 ); + AddImage( 330, 230, 0x27AA ); + + AddImage( 333, 2, 0x2716 ); + AddImage( 333, 248, 0x2716 ); + AddImage( 2, 248, 0x2716 ); + AddImage( 2, 2, 0x2716 ); + + AddHtmlLocalized( 25, 22, 200, 20, 1049000, 0x7D00, false, false ); // Confirm Quest Cancellation + AddImage( 25, 40, 0xBBF ); + + /* + * This quest will give you valuable information, skills + * and equipment that will help you advance in the + * game at a quicker pace.
+ *
+ * Are you certain you wish to cancel at this time? + */ + AddHtmlLocalized( 25, 55, 300, 120, 1060836, 0xFFFFFF, false, false ); + + MLQuest quest = instance.Quest; + + if ( quest.IsChainTriggered || quest.NextQuest != null ) + { + AddRadio( 25, 145, 0x25F8, 0x25FB, false, 2 ); + AddHtmlLocalized( 60, 150, 280, 20, 1075023, 0xFFFFFF, false, false ); // Yes, I want to quit this entire chain! + } + + AddRadio( 25, 180, 0x25F8, 0x25FB, true, 1 ); + AddHtmlLocalized( 60, 185, 280, 20, 1049005, 0xFFFFFF, false, false ); // Yes, I really want to quit this quest! + + AddRadio( 25, 215, 0x25F8, 0x25FB, false, 0 ); + AddHtmlLocalized( 60, 220, 280, 20, 1049006, 0xFFFFFF, false, false ); // No, I don't want to quit. + + AddButton( 265, 220, 0xF7, 0xF8, 7, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Instance.Removed ) + return; + + switch ( info.ButtonID ) + { + case 7: // Okay + { + if ( info.IsSwitched( 2 ) ) + m_Instance.Cancel( true ); + else if ( info.IsSwitched( 1 ) ) + m_Instance.Cancel( false ); + + sender.Mobile.SendGump( new QuestLogGump( m_Instance.Player, m_CloseGumps ) ); + break; + } + } + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestConversationGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestConversationGump.cs new file mode 100644 index 0000000..e64e501 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestConversationGump.cs @@ -0,0 +1,25 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestConversationGump : BaseQuestGump + { + public QuestConversationGump( MLQuest quest, PlayerMobile pm, TextDefinition text ) + : base( 3006156 ) // Quest Conversation + { + CloseOtherGumps( pm ); + + SetTitle( quest.Title ); + RegisterButton( ButtonPosition.Right, ButtonGraphic.Close, 3 ); + + SetPageCount( 1 ); + + BuildPage(); + AddConversation( text ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestLogDetailedGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestLogDetailedGump.cs new file mode 100644 index 0000000..e594eab --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestLogDetailedGump.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestLogDetailedGump : BaseQuestGump + { + private MLQuestInstance m_Instance; + private bool m_CloseGumps; + + public QuestLogDetailedGump( MLQuestInstance instance ) + : this( instance, true ) + { + } + + public QuestLogDetailedGump( MLQuestInstance instance, bool closeGumps ) + : base( 1046026 ) // Quest Log + { + m_Instance = instance; + m_CloseGumps = closeGumps; + + PlayerMobile pm = instance.Player; + MLQuest quest = instance.Quest; + + if ( closeGumps ) + { + CloseOtherGumps( pm ); + pm.CloseGump( typeof( QuestLogDetailedGump ) ); + } + + SetTitle( quest.Title ); + RegisterButton( ButtonPosition.Left, ButtonGraphic.Resign, 1 ); + RegisterButton( ButtonPosition.Right, ButtonGraphic.Okay, 2 ); + + SetPageCount( 3 ); + + BuildPage(); + AddDescription( quest ); + + if ( instance.Failed ) // only displayed on the first page + AddHtmlLocalized( 160, 80, 250, 16, 500039, 0x3C00, false, false ); // Failed! + + BuildPage(); + AddObjectivesProgress( instance ); + + BuildPage(); + AddRewardsPage( quest ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Instance.Removed ) + return; + + switch ( info.ButtonID ) + { + case 1: // Resign + { + // TODO: Custom reward loss protection? OSI doesn't have this + //if ( m_Instance.ClaimReward ) + // pm.SendMessage( "You cannot cancel a quest with rewards pending." ); + //else + + sender.Mobile.SendGump( new QuestCancelConfirmGump( m_Instance, m_CloseGumps ) ); + + break; + } + case 2: // Okay + { + sender.Mobile.SendGump( new QuestLogGump( m_Instance.Player, m_CloseGumps ) ); + + break; + } + } + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestLogGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestLogGump.cs new file mode 100644 index 0000000..a12a945 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestLogGump.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestLogGump : BaseQuestGump + { + private PlayerMobile m_Owner; + private bool m_CloseGumps; + + public QuestLogGump( PlayerMobile pm ) + : this( pm, true ) + { + } + + public QuestLogGump( PlayerMobile pm, bool closeGumps ) + : base( 1046026 ) // Quest Log + { + m_Owner = pm; + m_CloseGumps = closeGumps; + + if ( closeGumps ) + { + pm.CloseGump( typeof( QuestLogGump ) ); + pm.CloseGump( typeof( QuestLogDetailedGump ) ); + } + + RegisterButton( ButtonPosition.Right, ButtonGraphic.Okay, 3 ); + + SetPageCount( 1 ); + + BuildPage(); + + int numberColor, stringColor; + + MLQuestContext context = MLQuestSystem.GetContext( pm ); + + if ( context != null ) + { + List instances = context.QuestInstances; + + for ( int i = 0; i < instances.Count; ++i ) + { + if ( instances[i].Failed ) + { + numberColor = 0x3C00; + stringColor = 0x7B0000; + } + else + { + numberColor = stringColor = 0xFFFFFF; + } + + TextDefinition.AddHtmlText( this, 98, 140 + 21 * i, 270, 21, instances[i].Quest.Title, false, false, numberColor, stringColor ); + AddButton( 368, 140 + 21 * i, 0x26B0, 0x26B1, 6 + i, GumpButtonType.Reply, 1 ); + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID < 6 ) + return; + + MLQuestContext context = MLQuestSystem.GetContext( m_Owner ); + + if ( context == null ) + return; + + List instances = context.QuestInstances; + int index = info.ButtonID - 6; + + if ( index >= instances.Count ) + return; + + sender.Mobile.SendGump( new QuestLogDetailedGump( instances[index], m_CloseGumps ) ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestOfferGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestOfferGump.cs new file mode 100644 index 0000000..1e273f3 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestOfferGump.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestOfferGump : BaseQuestGump + { + private MLQuest m_Quest; + private IQuestGiver m_Quester; + + public QuestOfferGump( MLQuest quest, IQuestGiver quester, PlayerMobile pm ) + : base( 1049010 ) // Quest Offer + { + m_Quest = quest; + m_Quester = quester; + + CloseOtherGumps( pm ); + pm.CloseGump( typeof( QuestOfferGump ) ); + + SetTitle( quest.Title ); + RegisterButton( ButtonPosition.Left, ButtonGraphic.Accept, 1 ); + RegisterButton( ButtonPosition.Right, ButtonGraphic.Refuse, 2 ); + + SetPageCount( 3 ); + + BuildPage(); + AddDescription( quest ); + + BuildPage(); + AddObjectives( quest ); + + BuildPage(); + AddRewardsPage( quest ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if ( pm == null ) + return; + + switch ( info.ButtonID ) + { + case 1: // Accept + { + m_Quest.OnAccept( m_Quester, pm ); + break; + } + case 2: // Refuse + { + m_Quest.OnRefuse( m_Quester, pm ); + break; + } + } + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestReportBackGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestReportBackGump.cs new file mode 100644 index 0000000..1268470 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestReportBackGump.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestReportBackGump : BaseQuestGump + { + private MLQuestInstance m_Instance; + + public QuestReportBackGump( MLQuestInstance instance ) + : base( 3006156 ) // Quest Conversation + { + m_Instance = instance; + + MLQuest quest = instance.Quest; + PlayerMobile pm = instance.Player; + + // TODO: Check close sequence + CloseOtherGumps( pm ); + + SetTitle( quest.Title ); + RegisterButton( ButtonPosition.Left, ButtonGraphic.Continue, 4 ); + RegisterButton( ButtonPosition.Right, ButtonGraphic.Close, 3 ); + + SetPageCount( 1 ); + + BuildPage(); + AddConversation( quest.CompletionMessage ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 4 ) + m_Instance.ContinueReportBack( true ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/QuestRewardGump.cs b/Scripts/Engines/MLQuests/Gumps/QuestRewardGump.cs new file mode 100644 index 0000000..566d404 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/QuestRewardGump.cs @@ -0,0 +1,38 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Gumps +{ + public class QuestRewardGump : BaseQuestGump + { + private MLQuestInstance m_Instance; + + public QuestRewardGump( MLQuestInstance instance ) + : base( 1072201 ) // Reward + { + m_Instance = instance; + + MLQuest quest = instance.Quest; + PlayerMobile pm = instance.Player; + + CloseOtherGumps( pm ); + + SetTitle( quest.Title ); + RegisterButton( ButtonPosition.Left, ButtonGraphic.Accept, 1 ); + + SetPageCount( 1 ); + + BuildPage(); + AddRewards( quest ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_Instance.ClaimRewards(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs b/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs new file mode 100644 index 0000000..ef6e462 --- /dev/null +++ b/Scripts/Engines/MLQuests/Gumps/RaceChangeGump.cs @@ -0,0 +1,356 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.MLQuests.Mobiles; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells.Fifth; +using Server.Spells.Ninjitsu; +using Server.Spells.Seventh; + +namespace Server.Engines.MLQuests.Gumps +{ + public interface IRaceChanger + { + bool CheckComplete( PlayerMobile from ); + void ConsumeNeeded( PlayerMobile from ); + void OnCancel( PlayerMobile from ); + } + + public class RaceChangeConfirmGump : Gump + { + public static readonly Type Type = typeof( RaceChangeConfirmGump ); + + private IRaceChanger m_Owner; + private PlayerMobile m_From; + private Race m_Race; + + public RaceChangeConfirmGump( IRaceChanger owner, PlayerMobile from, Race targetRace ) + : base( 50, 50 ) + { + from.CloseGump( Type ); + + m_Owner = owner; + m_From = from; + m_Race = targetRace; + + AddPage( 0 ); + AddBackground( 0, 0, 240, 135, 0x2422 ); + + if ( targetRace == Race.Human ) + AddHtmlLocalized( 15, 15, 210, 75, 1073643, 0, false, false ); // Are you sure you wish to embrace your humanity? + else if ( targetRace == Race.Elf ) + AddHtmlLocalized( 15, 15, 210, 75, 1073642, 0, false, false ); // Are you sure you want to follow the elven ways? + else + AddHtml( 15, 15, 210, 75, String.Format( "Are you sure you want to change your race to {0}?", targetRace.Name ), false, false ); + + AddButton( 160, 95, 0xF7, 0xF8, 1, GumpButtonType.Reply, 0 ); + AddButton( 90, 95, 0xF2, 0xF1, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 0: // Cancel + { + if ( m_Owner != null ) + m_Owner.OnCancel( m_From ); + + break; + } + case 1: // Okay + { + if ( m_Owner == null || m_Owner.CheckComplete( m_From ) ) + Offer( m_Owner, m_From, m_Race ); + + break; + } + } + } + + private class RaceChangeState + { + private static readonly TimeSpan m_TimeoutDelay = TimeSpan.FromMinutes( 1 ); + private static readonly TimerStateCallback m_TimeoutCallback = new TimerStateCallback( Timeout ); + + public IRaceChanger m_Owner; + public Race m_TargetRace; + public Timer m_Timeout; + + public RaceChangeState( IRaceChanger owner, NetState ns, Race targetRace ) + { + m_Owner = owner; + m_TargetRace = targetRace; + m_Timeout = Timer.DelayCall( m_TimeoutDelay, m_TimeoutCallback, ns ); + } + } + + private static Dictionary m_Pending; + + public static void Initialize() + { + m_Pending = new Dictionary(); + + PacketHandlers.RegisterExtended( 0x2A, true, new OnPacketReceive( RaceChangeReply ) ); + } + + public static bool IsPending( NetState state ) + { + return ( state != null && m_Pending.ContainsKey( state ) ); + } + + private static void Offer( IRaceChanger owner, PlayerMobile from, Race targetRace ) + { + NetState ns = from.NetState; + + if ( ns == null || !CanChange( from, targetRace ) ) + return; + + CloseCurrent( ns ); + + m_Pending[ns] = new RaceChangeState( owner, ns, targetRace ); + ns.Send( new RaceChanger( from.Female, targetRace ) ); + } + + private static void CloseCurrent( NetState ns ) + { + RaceChangeState state; + + if ( m_Pending.TryGetValue( ns, out state ) ) + { + state.m_Timeout.Stop(); + m_Pending.Remove( ns ); + } + + ns.Send( CloseRaceChanger.Instance ); + } + + private static void Timeout( NetState ns ) + { + if ( m_Pending.ContainsKey( ns ) ) + { + m_Pending.Remove( ns ); + ns.Send( CloseRaceChanger.Instance ); + } + } + + public static bool IsWearingEquipment( Mobile from ) + { + foreach ( Item item in from.Items ) + { + switch ( item.Layer ) + { + case Layer.Hair: + case Layer.FacialHair: + case Layer.Backpack: + case Layer.Mount: + case Layer.Bank: + { + continue; // ignore + } + default: + { + return true; + } + } + } + + return false; + } + + private static bool CanChange( PlayerMobile from, Race targetRace ) + { + if ( from.Deleted ) + return false; + + if ( from.Race == targetRace ) + from.SendLocalizedMessage( 1111918 ); // You are already that race. + else if ( !MondainsLegacy.CheckML( from, false ) ) + from.SendLocalizedMessage( 1073651 ); // You must have Mondain's Legacy before proceeding... + else if ( !from.Alive ) + from.SendLocalizedMessage( 1073646 ); // Only the living may proceed... + else if ( from.Mounted ) + from.SendLocalizedMessage( 1073647 ); // You may not continue while mounted... + else if ( !from.CanBeginAction( typeof( PolymorphSpell ) ) || DisguiseTimers.IsDisguised( from ) || AnimalForm.UnderTransformation( from ) || !from.CanBeginAction( typeof( IncognitoSpell ) ) || from.IsBodyMod ) // TODO: Does this cover everything? + from.SendLocalizedMessage( 1073648 ); // You may only proceed while in your original state... + else if ( from.Spell != null && from.Spell.IsCasting ) + from.SendLocalizedMessage( 1073649 ); // One may not proceed while embracing magic... + else if ( from.Poisoned ) + from.SendLocalizedMessage( 1073652 ); // You must be healthy to proceed... + else if ( IsWearingEquipment( from ) ) + from.SendLocalizedMessage( 1073650 ); // To proceed you must be unburdened by equipment... + else + return true; + + return false; + } + + private static void RaceChangeReply( NetState state, PacketReader pvSrc ) + { + RaceChangeState raceChangeState; + + if ( !m_Pending.TryGetValue( state, out raceChangeState ) ) + return; + + CloseCurrent( state ); + + PlayerMobile pm = state.Mobile as PlayerMobile; + + if ( pm == null ) + return; + + IRaceChanger owner = raceChangeState.m_Owner; + Race targetRace = raceChangeState.m_TargetRace; + + if ( pvSrc.Size == 5 ) + { + if ( owner != null ) + owner.OnCancel( pm ); + + return; + } + + if ( !CanChange( pm, targetRace ) || ( owner != null && !owner.CheckComplete( pm ) ) ) + return; + + int hue = pvSrc.ReadUInt16(); + int hairItemId = pvSrc.ReadUInt16(); + int hairHue = pvSrc.ReadUInt16(); + int facialHairItemId = pvSrc.ReadUInt16(); + int facialHairHue = pvSrc.ReadUInt16(); + + pm.Race = targetRace; + pm.Hue = targetRace.ClipSkinHue( hue ) | 0x8000; + + if ( targetRace.ValidateHair( pm, hairItemId ) ) + { + pm.HairItemID = hairItemId; + pm.HairHue = targetRace.ClipHairHue( hairHue ); + } + else + { + pm.HairItemID = 0; + } + + if ( targetRace.ValidateFacialHair( pm, facialHairItemId ) ) + { + pm.FacialHairItemID = facialHairItemId; + pm.FacialHairHue = targetRace.ClipHairHue( facialHairHue ); + } + else + { + pm.FacialHairItemID = 0; + } + + if ( targetRace == Race.Human ) + pm.SendLocalizedMessage( 1073654 ); // You are now fully human. + else if ( targetRace == Race.Elf ) + pm.SendLocalizedMessage( 1073653 ); // You are now fully initiated into the Elven culture. + else + pm.SendMessage( "You have fully changed your race to {0}.", targetRace.Name ); + + if ( owner != null ) + owner.ConsumeNeeded( pm ); + } + } + + public sealed class RaceChanger : Packet + { + public RaceChanger( bool female, Race targetRace ) + : base( 0xBF ) + { + EnsureCapacity( 7 ); + + m_Stream.Write( (short)0x2A ); + m_Stream.Write( (byte)( female ? 1 : 0 ) ); + m_Stream.Write( (byte)( targetRace.RaceID + 1 ) ); + } + } + + public sealed class CloseRaceChanger : Packet + { + public static readonly Packet Instance = Packet.SetStatic( new CloseRaceChanger() ); + + private CloseRaceChanger() + : base( 0xBF ) + { + EnsureCapacity( 7 ); + + m_Stream.Write( (short)0x2A ); + m_Stream.Write( (byte)0 ); + m_Stream.Write( (byte)0xFF ); + } + } + + #region For testing + + public class RaceChangeDeed : Item, IRaceChanger + { + public override string DefaultName { get { return "a race change deed"; } } + + [Constructable] + public RaceChangeDeed() + : base( 0x14F0 ) + { + LootType = LootType.Blessed; + } + + public bool CheckComplete( PlayerMobile pm ) + { + if ( Deleted ) + return false; + + if ( !IsChildOf( pm.Backpack ) ) + { + pm.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return false; + } + + return true; + } + + public void ConsumeNeeded( PlayerMobile pm ) + { + Consume(); + } + + public void OnCancel( PlayerMobile pm ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + if ( CheckComplete( pm ) ) + pm.SendGump( new RaceChangeConfirmGump( this, pm, ( pm.Race == Race.Human ) ? Race.Elf : Race.Human ) ); + } + + public RaceChangeDeed( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + #endregion +} diff --git a/Scripts/Engines/MLQuests/IQuestGiver.cs b/Scripts/Engines/MLQuests/IQuestGiver.cs new file mode 100644 index 0000000..fbde572 --- /dev/null +++ b/Scripts/Engines/MLQuests/IQuestGiver.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Engines.MLQuests +{ + public interface IQuestGiver + { + List MLQuests { get; } + + Serial Serial { get; } + bool Deleted { get; } + + Type GetType(); + } +} diff --git a/Scripts/Engines/MLQuests/Items/ABauble.cs b/Scripts/Engines/MLQuests/Items/ABauble.cs new file mode 100644 index 0000000..1c1f404 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/ABauble.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ABauble : Item + { + public override int LabelNumber{ get{ return 1073137; } } // A bauble + + [Constructable] + public ABauble() : base( 0x23B ) + { + LootType = LootType.Blessed; + } + + public ABauble( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/APersonalLetterAddressedToAhie.cs b/Scripts/Engines/MLQuests/Items/APersonalLetterAddressedToAhie.cs new file mode 100644 index 0000000..f6c9a90 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/APersonalLetterAddressedToAhie.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class APersonalLetterAddressedToAhie : TransientItem + { + public override int LabelNumber{ get{ return 1073128; } } // A personal letter addressed to: Ahie + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public APersonalLetterAddressedToAhie() : base( 0x14ED, TimeSpan.FromMinutes( 30 ) ) + { + LootType = LootType.Blessed; + } + + public APersonalLetterAddressedToAhie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/AlchemistsBandage.cs b/Scripts/Engines/MLQuests/Items/AlchemistsBandage.cs new file mode 100644 index 0000000..23c70a0 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/AlchemistsBandage.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AlchemistsBandage : Item + { + public override int LabelNumber{ get{ return 1075452; } } // Alchemist's Bandage + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public AlchemistsBandage() : base( 0xE21 ) + { + LootType = LootType.Blessed; + Hue = 0x482; + } + + public AlchemistsBandage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/AnOldNecklace.cs b/Scripts/Engines/MLQuests/Items/AnOldNecklace.cs new file mode 100644 index 0000000..bb187ce --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/AnOldNecklace.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AnOldNecklace : Necklace + { + public override int LabelNumber{ get{ return 1075525; } } // an old necklace + + [Constructable] + public AnOldNecklace() : base() + { + Hue = 0x222; + } + + public AnOldNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/AnOldRing.cs b/Scripts/Engines/MLQuests/Items/AnOldRing.cs new file mode 100644 index 0000000..ca3c912 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/AnOldRing.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AnOldRing : GoldRing + { + public override int LabelNumber{ get{ return 1075524; } } // an old ring + + [Constructable] + public AnOldRing() : base() + { + Hue = 0x222; + } + + public AnOldRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/AndricSatchel.cs b/Scripts/Engines/MLQuests/Items/AndricSatchel.cs new file mode 100644 index 0000000..f2f086a --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/AndricSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AndricSatchel : Backpack + { + [Constructable] + public AndricSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new Feather( 10 ) ); + DropItem( new FletcherTools() ); + } + + public AndricSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/AndrosGratitude.cs b/Scripts/Engines/MLQuests/Items/AndrosGratitude.cs new file mode 100644 index 0000000..7d2a4c7 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/AndrosGratitude.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AndrosGratitude : SmithHammer + { + public override int LabelNumber{ get{ return 1075345; } } // Andros Gratitude + + [Constructable] + public AndrosGratitude() : base( 10 ) + { + LootType = LootType.Blessed; + } + + public AndrosGratitude( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/AsandosSatchel.cs b/Scripts/Engines/MLQuests/Items/AsandosSatchel.cs new file mode 100644 index 0000000..2ae6003 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/AsandosSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AsandosSatchel : Backpack + { + [Constructable] + public AsandosSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new SackFlour() ); + DropItem( new Skillet() ); + } + + public AsandosSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/BasinOfCrystalClearWater.cs b/Scripts/Engines/MLQuests/Items/BasinOfCrystalClearWater.cs new file mode 100644 index 0000000..c59efb6 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/BasinOfCrystalClearWater.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BasinOfCrystalClearWater : Item + { + public override int LabelNumber{ get{ return 1075303; } } // Basin of Crystal-Clear Water + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public BasinOfCrystalClearWater() : base( 0x1008 ) + { + LootType = LootType.Blessed; + } + + public BasinOfCrystalClearWater( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/BedlamTeleporter.cs b/Scripts/Engines/MLQuests/Items/BedlamTeleporter.cs new file mode 100644 index 0000000..0706e09 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/BedlamTeleporter.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Items +{ + public class BedlamTeleporter : Item + { + public override int LabelNumber { get { return 1074161; } } // Access to Bedlam by invitation only + + private static readonly Point3D PointDest = new Point3D( 120, 1682, 0 ); + private static readonly Map MapDest = Map.Malas; + + public BedlamTeleporter() + : base( 0x124D ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + MLQuestContext context; + + if ( from is PlayerMobile && ( context = MLQuestSystem.GetContext( (PlayerMobile)from ) ) != null && context.BedlamAccess ) + { + BaseCreature.TeleportPets( from, PointDest, MapDest ); + from.MoveToWorld( PointDest, MapDest ); + } + else + { + from.SendLocalizedMessage( 1074276 ); // You press and push on the iron maiden, but nothing happens. + } + } + + public BedlamTeleporter( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/Bleach.cs b/Scripts/Engines/MLQuests/Items/Bleach.cs new file mode 100644 index 0000000..09f6af5 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/Bleach.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Bleach : PigmentsOfTokuno + { + public override int LabelNumber { get { return 1075375; } } // Bleach + + [Constructable] + public Bleach() : base( PigmentType.None ) + { + LootType = LootType.Blessed; + } + + public Bleach( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/BridesLetter.cs b/Scripts/Engines/MLQuests/Items/BridesLetter.cs new file mode 100644 index 0000000..ae8a8fd --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/BridesLetter.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BridesLetter : Item + { + public override int LabelNumber{ get{ return 1075301; } } // Bride's Letter + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public BridesLetter() : base( 0x14ED ) + { + LootType = LootType.Blessed; + } + + public BridesLetter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/CompletedTuitionReimbursementForm.cs b/Scripts/Engines/MLQuests/Items/CompletedTuitionReimbursementForm.cs new file mode 100644 index 0000000..331a51c --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/CompletedTuitionReimbursementForm.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CompletedTuitionReimbursementForm : Item + { + public override int LabelNumber{ get{ return 1074625; } } // Completed Tuition Reimbursement Form + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public CompletedTuitionReimbursementForm() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + } + + public CompletedTuitionReimbursementForm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/CraftmansSatchel.cs b/Scripts/Engines/MLQuests/Items/CraftmansSatchel.cs new file mode 100644 index 0000000..66b2663 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/CraftmansSatchel.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Engines.Craft; +using Server.Items; + +namespace Server.Engines.MLQuests.Items +{ + public abstract class BaseCraftmansSatchel : Backpack + { + protected static readonly Type[] m_TalismanType = new Type[] { typeof( RandomTalisman ) }; + + public BaseCraftmansSatchel() + { + Hue = Utility.RandomBrightHue(); + } + + protected void AddBaseLoot( params Type[][] lootSets ) + { + Item loot = Loot.Construct( lootSets[Utility.Random( lootSets.Length )] ); + + if ( loot == null ) + return; + + RewardBag.Enhance( loot ); + DropItem( loot ); + } + + protected void AddRecipe( CraftSystem system ) + { + // TODO: change craftable artifact recipes to a rarer drop + int recipeID = system.RandomRecipe(); + + if ( recipeID != -1 ) + DropItem( new RecipeScroll( recipeID ) ); + } + + public BaseCraftmansSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TailorSatchel : BaseCraftmansSatchel + { + [Constructable] + public TailorSatchel() + { + AddBaseLoot( Loot.MLArmorTypes, Loot.JewelryTypes, m_TalismanType ); + + if ( Utility.RandomDouble() < 0.50 ) + AddRecipe( DefTailoring.CraftSystem ); + } + + public TailorSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BlacksmithSatchel : BaseCraftmansSatchel + { + [Constructable] + public BlacksmithSatchel() + { + AddBaseLoot( Loot.MLWeaponTypes, Loot.JewelryTypes, m_TalismanType ); + + if ( Utility.RandomDouble() < 0.50 ) + AddRecipe( DefBlacksmithy.CraftSystem ); + } + + public BlacksmithSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TinkerSatchel : BaseCraftmansSatchel + { + [Constructable] + public TinkerSatchel() + { + AddBaseLoot( Loot.MLArmorTypes, Loot.MLWeaponTypes, Loot.MLRangedWeaponTypes, Loot.JewelryTypes, m_TalismanType ); + + if ( Utility.RandomDouble() < 0.50 ) + { + // TODO: Add recipe drops (drops include inscription, alchemy and drops from non-artifact recipes for tailoring, blacksmith, carpentry and fletching. + switch ( Utility.Random( 6 ) ) + { + case 0: AddRecipe( DefInscription.CraftSystem ); break; + case 1: AddRecipe( DefAlchemy.CraftSystem ); break; + // TODO + //case 2: AddNonArtifactRecipe( DefTailoring.CraftSystem ); break; + //case 3: AddNonArtifactRecipe( DefBlacksmithy.CraftSystem ); break; + //case 4: AddNonArtifactRecipe( DefCarpentry.CraftSystem ); break; + //case 5: AddNonArtifactRecipe( DefBowFletching.CraftSystem ); break; + } + } + } + + public TinkerSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FletchingSatchel : BaseCraftmansSatchel + { + [Constructable] + public FletchingSatchel() + { + AddBaseLoot( Loot.MLRangedWeaponTypes, Loot.JewelryTypes, m_TalismanType ); + + if ( Utility.RandomDouble() < 0.50 ) + AddRecipe( DefBowFletching.CraftSystem ); + + // TODO: runic fletching kit + } + + public FletchingSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CarpentrySatchel : BaseCraftmansSatchel + { + [Constructable] + public CarpentrySatchel() + { + AddBaseLoot( Loot.MLArmorTypes, Loot.MLWeaponTypes, Loot.MLRangedWeaponTypes, Loot.JewelryTypes, m_TalismanType ); + + if ( Utility.RandomDouble() < 0.50 ) + AddRecipe( DefCarpentry.CraftSystem ); + + // TODO: Add runic dovetail saw + } + + public CarpentrySatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/CrateForSledge.cs b/Scripts/Engines/MLQuests/Items/CrateForSledge.cs new file mode 100644 index 0000000..729086d --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/CrateForSledge.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CrateForSledge : TransientItem + { + public override int LabelNumber{ get{ return 1074520; } } // Crate for Sledge + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public CrateForSledge() : base( 0x1FFF, TimeSpan.FromHours( 1 ) ) + { + LootType = LootType.Blessed; + } + + public CrateForSledge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/DreadSpiderSilk.cs b/Scripts/Engines/MLQuests/Items/DreadSpiderSilk.cs new file mode 100644 index 0000000..793f968 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/DreadSpiderSilk.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DreadSpiderSilk : Item + { + public override int LabelNumber{ get{ return 1075319; } } // Dread Spider Silk + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public DreadSpiderSilk() : base( 0xDF8 ) + { + LootType = LootType.Blessed; + Hue = 0x481; + } + + public DreadSpiderSilk( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/FragmentOfAMap.cs b/Scripts/Engines/MLQuests/Items/FragmentOfAMap.cs new file mode 100644 index 0000000..b3dfd63 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/FragmentOfAMap.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FragmentOfAMap : Item + { + public override int LabelNumber{ get{ return 1074533; } } // Fragment of a Map + + [Constructable] + public FragmentOfAMap() : base( 0x14ED ) + { + LootType = LootType.Blessed; + } + + public FragmentOfAMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/FragmentOfAMapDelivery.cs b/Scripts/Engines/MLQuests/Items/FragmentOfAMapDelivery.cs new file mode 100644 index 0000000..3cad65a --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/FragmentOfAMapDelivery.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FragmentOfAMapDelivery : Item + { + public override int LabelNumber{ get{ return 1074533; } } // Fragment of a Map + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public FragmentOfAMapDelivery() : base( 0x14ED ) + { + LootType = LootType.Blessed; + } + + public FragmentOfAMapDelivery( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/FriendOfTheLibraryToken.cs b/Scripts/Engines/MLQuests/Items/FriendOfTheLibraryToken.cs new file mode 100644 index 0000000..1819480 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/FriendOfTheLibraryToken.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FriendOfTheLibraryToken : Item + { + public override int LabelNumber{ get{ return 1073136; } } // Friend of the Library Token (allows donations to be made) + + [Constructable] + public FriendOfTheLibraryToken() : base( 0x2F58 ) + { + Layer = Layer.Talisman; + Hue = 0x28A; + } + + public FriendOfTheLibraryToken( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/FriendsOfTheLibraryApplication.cs b/Scripts/Engines/MLQuests/Items/FriendsOfTheLibraryApplication.cs new file mode 100644 index 0000000..9c0976c --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/FriendsOfTheLibraryApplication.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FriendsOfTheLibraryApplication : Item + { + public override int LabelNumber{ get{ return 1073131; } } // Friends of the Library Application + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public FriendsOfTheLibraryApplication() : base( 0xEC0 ) + { + LootType = LootType.Blessed; + } + + public FriendsOfTheLibraryApplication( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/GamanHorns.cs b/Scripts/Engines/MLQuests/Items/GamanHorns.cs new file mode 100644 index 0000000..09ef517 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/GamanHorns.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GamanHorns : Item + { + public override int LabelNumber{ get{ return 1074557; } } // Gaman Horns + + [Constructable] + public GamanHorns() : this( 1 ) + { + } + + [Constructable] + public GamanHorns( int amount ) : base( 0x1084 ) + { + LootType = LootType.Blessed; + Stackable = true; + Amount = amount; + Hue = 0x395; + } + + public GamanHorns( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/GervisSatchel.cs b/Scripts/Engines/MLQuests/Items/GervisSatchel.cs new file mode 100644 index 0000000..a97e3f7 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/GervisSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GervisSatchel : Backpack + { + [Constructable] + public GervisSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new IronIngot( 10 ) ); + DropItem( new SmithHammer() ); + } + + public GervisSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/GiftForArielle.cs b/Scripts/Engines/MLQuests/Items/GiftForArielle.cs new file mode 100644 index 0000000..15a278a --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/GiftForArielle.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GiftForArielle : BaseContainer + { + public override int LabelNumber{ get{ return 1074356; } } // gift for arielle + public override int DefaultGumpID { get { return 0x41; } } + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public GiftForArielle() : base( 0x1882 ) + { + Hue = 0x2C4; + } + + public GiftForArielle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/HargroveSatchel.cs b/Scripts/Engines/MLQuests/Items/HargroveSatchel.cs new file mode 100644 index 0000000..2109076 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/HargroveSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HargroveSatchel : Backpack + { + [Constructable] + public HargroveSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new Gold( 15 ) ); + DropItem( new Hatchet() ); + } + + public HargroveSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/KirinBrains.cs b/Scripts/Engines/MLQuests/Items/KirinBrains.cs new file mode 100644 index 0000000..7279215 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/KirinBrains.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class KirinBrains : Item + { + public override int LabelNumber{ get{ return 1074612; } } // Ki-Rin Brains + + [Constructable] + public KirinBrains() : base( 0x1CF0 ) + { + LootType = LootType.Blessed; + Hue = 0xD7; + } + + public KirinBrains( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/LowelSatchel.cs b/Scripts/Engines/MLQuests/Items/LowelSatchel.cs new file mode 100644 index 0000000..2964473 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/LowelSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LowelSatchel : Backpack + { + [Constructable] + public LowelSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new Board( 10 ) ); + DropItem( new DovetailSaw() ); + } + + public LowelSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/MiniatureMushroom.cs b/Scripts/Engines/MLQuests/Items/MiniatureMushroom.cs new file mode 100644 index 0000000..45f03dc --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/MiniatureMushroom.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MiniatureMushroom : Food + { + public override int LabelNumber{ get{ return 1073138; } } // Miniature mushroom + + [Constructable] + public MiniatureMushroom() : base( 0xD16 ) + { + LootType = LootType.Blessed; + } + + public MiniatureMushroom( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/MirrorOfPurification.cs b/Scripts/Engines/MLQuests/Items/MirrorOfPurification.cs new file mode 100644 index 0000000..9607e26 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/MirrorOfPurification.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MirrorOfPurification : Item + { + public override int LabelNumber{ get{ return 1075304; } } // Mirror of Purification + + [Constructable] + public MirrorOfPurification() : base( 0x1008 ) + { + LootType = LootType.Blessed; + Hue = 0x530; + } + + public MirrorOfPurification( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/MuggSatchel.cs b/Scripts/Engines/MLQuests/Items/MuggSatchel.cs new file mode 100644 index 0000000..3cbded9 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/MuggSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MuggSatchel : Backpack + { + [Constructable] + public MuggSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new Pickaxe() ); + DropItem( new Pickaxe() ); + } + + public MuggSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/NibbetSatchel.cs b/Scripts/Engines/MLQuests/Items/NibbetSatchel.cs new file mode 100644 index 0000000..774830d --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/NibbetSatchel.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NibbetSatchel : Backpack + { + [Constructable] + public NibbetSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new TinkerTools() ); + + switch ( Utility.Random( 10 ) ) + { + case 0: DropItem( new Springs( 3 ) ); break; + case 1: DropItem( new Axle( 3 ) ); break; + case 2: DropItem( new Hinge( 3 ) ); break; + case 3: DropItem( new Key() ); break; + case 4: DropItem( new Scissors() ); break; + case 5: DropItem( new BarrelTap( 3 ) ); break; + case 6: DropItem( new BarrelHoops() ); break; + case 7: DropItem( new Gears( 3 ) ); break; + case 8: DropItem( new Lockpick( 3 ) ); break; + case 9: DropItem( new ClockFrame( 3 ) ); break; + + } + } + + public NibbetSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/NotarizedApplication.cs b/Scripts/Engines/MLQuests/Items/NotarizedApplication.cs new file mode 100644 index 0000000..dddf7dd --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/NotarizedApplication.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NotarizedApplication : Item + { + public override int LabelNumber{ get{ return 1073135; } } // Notarized Application + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public NotarizedApplication() : base( 0x14EF ) + { + LootType = LootType.Blessed; + } + + public NotarizedApplication( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/OfficialSealingWax.cs b/Scripts/Engines/MLQuests/Items/OfficialSealingWax.cs new file mode 100644 index 0000000..8159a15 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/OfficialSealingWax.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OfficialSealingWax : Item + { + public override int LabelNumber{ get{ return 1072744; } } // Official Sealing Wax + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public OfficialSealingWax() : base( 0x1426 ) + { + LootType = LootType.Blessed; + Hue = 0x84; + } + + public OfficialSealingWax( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/PeppercornFishsteak.cs b/Scripts/Engines/MLQuests/Items/PeppercornFishsteak.cs new file mode 100644 index 0000000..9b3ba6d --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/PeppercornFishsteak.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PeppercornFishsteak : FishSteak + { + public override int LabelNumber{ get{ return 1075557; } } // peppercorn fishsteak + + [Constructable] + public PeppercornFishsteak() : base() + { + Hue = 0x222; + } + + public PeppercornFishsteak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/PixieLeg.cs b/Scripts/Engines/MLQuests/Items/PixieLeg.cs new file mode 100644 index 0000000..c26ce13 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/PixieLeg.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PixieLeg : ChickenLeg + { + public override int LabelNumber{ get{ return 1074613; } } // Pixie Leg + + [Constructable] + public PixieLeg() : this( 1 ) + { + } + + [Constructable] + public PixieLeg( int amount ) : base( amount ) + { + LootType = LootType.Blessed; + Hue = 0x1C2; + } + + public PixieLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/PortraitOfTheBride.cs b/Scripts/Engines/MLQuests/Items/PortraitOfTheBride.cs new file mode 100644 index 0000000..dd74bd7 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/PortraitOfTheBride.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PortraitOfTheBride : Item + { + public override int LabelNumber{ get{ return 1075300; } } // Portrait of the Bride + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public PortraitOfTheBride() : base( 0xE9F ) + { + LootType = LootType.Blessed; + } + + public PortraitOfTheBride( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/PrismaticAmber.cs b/Scripts/Engines/MLQuests/Items/PrismaticAmber.cs new file mode 100644 index 0000000..f948f9f --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/PrismaticAmber.cs @@ -0,0 +1,76 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PrismaticAmber : Amber + { + public override int LabelNumber{ get{ return 1075299; } } // Prismatic Amber + + [Constructable] + public PrismaticAmber() : base() + { + } + + public PrismaticAmber( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1075269 ); // Destroyed when dropped + } + + public override bool DropToWorld( Mobile from, Point3D p ) + { + bool ret = base.DropToWorld( from, p ); + + if ( ret ) + DestroyItem( from ); + + return ret; + } + + public override bool DropToMobile( Mobile from, Mobile target, Point3D p ) + { + bool ret = base.DropToMobile( from, target, p ); + + if ( ret ) + DestroyItem( from ); + + return ret; + } + + public override bool DropToItem( Mobile from, Item target, Point3D p ) + { + bool ret = base.DropToItem( from, target, p ); + + if ( ret && Parent != from.Backpack ) + DestroyItem( from ); + + return ret; + } + + public virtual void DestroyItem( Mobile from ) + { + from.SendLocalizedMessage( 500424 ); // You destroyed the item. + Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/PrismaticCrystal.cs b/Scripts/Engines/MLQuests/Items/PrismaticCrystal.cs new file mode 100644 index 0000000..a7500df --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/PrismaticCrystal.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Definitions; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class PrismaticCrystal : Item + { + public override int LabelNumber{ get{ return 1074269; } } // prismatic crystal + + [Constructable] + public PrismaticCrystal() : base( 0x2DA ) + { + Movable = false; + Hue = 0x32; + } + + public PrismaticCrystal( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null || pm.Backpack == null ) + return; + + if ( pm.InRange( GetWorldLocation(), 2 ) ) + { + MLQuestContext context = MLQuestSystem.GetContext( pm ); + + if ( context != null && context.IsDoingQuest( typeof( UnfadingMemoriesPartOne ) ) && pm.Backpack.FindItemByType( typeof( PrismaticAmber ), false ) == null ) + { + Item amber = new PrismaticAmber(); + + if ( pm.PlaceInBackpack( amber ) ) + { + MLQuestSystem.MarkQuestItem( pm, amber ); + Delete(); + } + else + { + pm.SendLocalizedMessage( 502385 ); // Your pack cannot hold this item. + amber.Delete(); + } + } + else + pm.SendLocalizedMessage( 1075464 ); // You already have as many of those as you need. + } + else + pm.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/QuestGiverItem.cs b/Scripts/Engines/MLQuests/Items/QuestGiverItem.cs new file mode 100644 index 0000000..566b357 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/QuestGiverItem.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Items +{ + public abstract class QuestGiverItem : Item, IQuestGiver + { + private List m_MLQuests; + + public List MLQuests + { + get + { + if ( m_MLQuests == null ) + { + m_MLQuests = MLQuestSystem.FindQuestList( GetType() ); + + if ( m_MLQuests == null ) + m_MLQuests = MLQuestSystem.EmptyList; + } + + return m_MLQuests; + } + } + + public bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } } + + public QuestGiverItem( int itemId ) + : base( itemId ) + { + } + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + AddQuestItemProperty( list ); + + if ( CanGiveMLQuest ) + list.Add( 1072269 ); // Quest Giver + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( !IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1042593 ); // That is not in your backpack. + else if ( MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile ) + MLQuestSystem.OnDoubleClick( this, (PlayerMobile)from ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( MLQuestSystem.Enabled ) + MLQuestSystem.HandleDeletion( this ); + } + + public QuestGiverItem( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class TransientQuestGiverItem : TransientItem, IQuestGiver + { + private List m_MLQuests; + + public List MLQuests + { + get + { + if ( m_MLQuests == null ) + { + m_MLQuests = MLQuestSystem.FindQuestList( GetType() ); + + if ( m_MLQuests == null ) + m_MLQuests = MLQuestSystem.EmptyList; + } + + return m_MLQuests; + } + } + + public bool CanGiveMLQuest { get { return ( MLQuests.Count != 0 ); } } + + public TransientQuestGiverItem( int itemId, TimeSpan lifeSpan ) + : base( itemId, lifeSpan ) + { + } + + public override bool Nontransferable { get { return true; } } + + public override void HandleInvalidTransfer( Mobile from ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + AddQuestItemProperty( list ); + + if ( CanGiveMLQuest ) + list.Add( 1072269 ); // Quest Giver + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( !IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1042593 ); // That is not in your backpack. + else if ( MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile ) + MLQuestSystem.OnDoubleClick( this, (PlayerMobile)from ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( MLQuestSystem.Enabled ) + MLQuestSystem.HandleDeletion( this ); + } + + public TransientQuestGiverItem( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/RedLeatherBook.cs b/Scripts/Engines/MLQuests/Items/RedLeatherBook.cs new file mode 100644 index 0000000..71f5258 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/RedLeatherBook.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RedLeatherBook : BlueBook + { + [Constructable] + public RedLeatherBook() + { + Hue = 0x485; + } + + public RedLeatherBook( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/ReginasLetter.cs b/Scripts/Engines/MLQuests/Items/ReginasLetter.cs new file mode 100644 index 0000000..694e71f --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/ReginasLetter.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ReginasLetter : Item + { + public override int LabelNumber{ get{ return 1075306; } } // Regina's Letter + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public ReginasLetter() : base( 0x14ED ) + { + LootType = LootType.Blessed; + } + + public ReginasLetter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/ReginasRing.cs b/Scripts/Engines/MLQuests/Items/ReginasRing.cs new file mode 100644 index 0000000..d2a0345 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/ReginasRing.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ReginasRing : SilverRing + { + public override int LabelNumber{ get{ return 1075305; } } // Regina's Ring + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public ReginasRing() : base() + { + LootType = LootType.Blessed; + } + + public ReginasRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/RewardBags.cs b/Scripts/Engines/MLQuests/Items/RewardBags.cs new file mode 100644 index 0000000..b997115 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/RewardBags.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Items; + +namespace Server.Engines.MLQuests.Items +{ + public static class RewardBag + { + public static void Fill( Container c, int itemCount, double talismanChance ) + { + c.Hue = Utility.RandomNondyedHue(); + + int done = 0; + + if ( Utility.RandomDouble() < talismanChance ) + { + c.DropItem( new RandomTalisman() ); + ++done; + } + + for ( ; done < itemCount; ++done ) + { + Item loot = null; + + switch ( Utility.Random( 5 ) ) + { + case 0: loot = Loot.RandomWeapon( false, true ); break; + case 1: loot = Loot.RandomArmor( false, true ); break; + case 2: loot = Loot.RandomRangedWeapon( false, true ); break; + case 3: loot = Loot.RandomJewelry(); break; + case 4: loot = Loot.RandomHat( false ); break; + } + + if ( loot == null ) + continue; + + Enhance( loot ); + c.DropItem( loot ); + } + } + + public static void Enhance( Item loot ) + { + if ( loot is BaseWeapon ) + BaseRunicTool.ApplyAttributesTo( (BaseWeapon)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 ); + else if ( loot is BaseArmor ) + BaseRunicTool.ApplyAttributesTo( (BaseArmor)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 ); + else if ( loot is BaseShield ) + BaseRunicTool.ApplyAttributesTo( (BaseShield)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 ); + else if ( loot is BaseJewel ) + BaseRunicTool.ApplyAttributesTo( (BaseJewel)loot, Utility.RandomMinMax( 1, 5 ), 10, 80 ); + } + } + + public class SmallBagOfTrinkets : Bag + { + [Constructable] + public SmallBagOfTrinkets() + { + RewardBag.Fill( this, 1, 0.0 ); + } + + public SmallBagOfTrinkets( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BagOfTrinkets : Bag + { + [Constructable] + public BagOfTrinkets() + { + RewardBag.Fill( this, 2, 0.05 ); + } + + public BagOfTrinkets( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BagOfTreasure : Bag + { + [Constructable] + public BagOfTreasure() + { + RewardBag.Fill( this, 3, 0.20 ); + } + + public BagOfTreasure( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeBagOfTreasure : Bag + { + [Constructable] + public LargeBagOfTreasure() + { + RewardBag.Fill( this, 4, 0.50 ); + } + + public LargeBagOfTreasure( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RewardStrongbox : WoodenBox + { + [Constructable] + public RewardStrongbox() + { + RewardBag.Fill( this, 5, 1.0 ); + } + + public RewardStrongbox( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SadrahSatchel.cs b/Scripts/Engines/MLQuests/Items/SadrahSatchel.cs new file mode 100644 index 0000000..efc44b7 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SadrahSatchel.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SadrahSatchel : Backpack + { + [Constructable] + public SadrahSatchel() + { + Hue = Utility.RandomBrightHue(); + DropItem( new Bloodmoss( 10 ) ); + DropItem( new MortarPestle() ); + } + + public SadrahSatchel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SapOfSosaria.cs b/Scripts/Engines/MLQuests/Items/SapOfSosaria.cs new file mode 100644 index 0000000..ea85faf --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SapOfSosaria.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SapOfSosaria : Item + { + public override int LabelNumber{ get{ return 1074178; } } // Sap of Sosaria + + [Constructable] + public SapOfSosaria() : this( 1 ) + { + } + + [Constructable] + public SapOfSosaria( int amount ) : base( 0x1848 ) + { + LootType = LootType.Blessed; + Stackable = true; + Amount = amount; + } + + public SapOfSosaria( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SealedNotesForJamal.cs b/Scripts/Engines/MLQuests/Items/SealedNotesForJamal.cs new file mode 100644 index 0000000..40f6652 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SealedNotesForJamal.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SealedNotesForJamal : Item + { + public override int LabelNumber{ get{ return 1074998; } } // Sealed Notes For Jamal + public override double DefaultWeight{ get{ return 1.0; } } + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public SealedNotesForJamal() : base( 0xEF9 ) + { + LootType = LootType.Blessed; + } + + public SealedNotesForJamal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SealingWaxOrderAddressedToPetrus.cs b/Scripts/Engines/MLQuests/Items/SealingWaxOrderAddressedToPetrus.cs new file mode 100644 index 0000000..383f4cc --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SealingWaxOrderAddressedToPetrus.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SealingWaxOrderAddressedToPetrus : Item + { + public override int LabelNumber{ get{ return 1073132; } } // Sealing Wax Order addressed to Petrus + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public SealingWaxOrderAddressedToPetrus() : base( 0xEBF ) + { + LootType = LootType.Blessed; + } + + public SealingWaxOrderAddressedToPetrus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SeveredElfEars.cs b/Scripts/Engines/MLQuests/Items/SeveredElfEars.cs new file mode 100644 index 0000000..3bd5405 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SeveredElfEars.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable(0x312D, 0x312E)] + public class SeveredElfEars : Item + { + [Constructable] + public SeveredElfEars() : this( 1 ) + { + } + + [Constructable] + public SeveredElfEars( int amount ) : base( Utility.RandomList( 0x312D, 0x312E ) ) + { + Stackable = true; + Amount = amount; + } + + public SeveredElfEars( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SeveredHumanEars.cs b/Scripts/Engines/MLQuests/Items/SeveredHumanEars.cs new file mode 100644 index 0000000..d01887c --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SeveredHumanEars.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable(0x312F, 0x3130)] + public class SeveredHumanEars : Item + { + [Constructable] + public SeveredHumanEars() : this( 1 ) + { + } + + [Constructable] + public SeveredHumanEars( int amount ) : base( Utility.RandomList( 0x312F, 0x3130 ) ) + { + Stackable = true; + Amount = amount; + } + + public SeveredHumanEars( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SignedTuitionReimbursementForm.cs b/Scripts/Engines/MLQuests/Items/SignedTuitionReimbursementForm.cs new file mode 100644 index 0000000..f63cd5c --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SignedTuitionReimbursementForm.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SignedTuitionReimbursementForm : Item + { + public override int LabelNumber{ get{ return 1074614; } } // Signed Tuition Reimbursement Form + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public SignedTuitionReimbursementForm() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + } + + public SignedTuitionReimbursementForm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SpecialTreatForDrithen.cs b/Scripts/Engines/MLQuests/Items/SpecialTreatForDrithen.cs new file mode 100644 index 0000000..b1b6732 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SpecialTreatForDrithen.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpecialTreatForDrithen : Item + { + public override int LabelNumber{ get{ return 1074517; } } // Special Treat for Drithen + + [Constructable] + public SpecialTreatForDrithen() : base( 0x21B ) + { + LootType = LootType.Blessed; + Hue = 0x489; + } + + public SpecialTreatForDrithen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SpeckledPoisonSac.cs b/Scripts/Engines/MLQuests/Items/SpeckledPoisonSac.cs new file mode 100644 index 0000000..3a0fe00 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SpeckledPoisonSac.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpeckledPoisonSac : TransientItem + { + public override int LabelNumber{ get{ return 1073133; } } // Speckled Poison Sac + + [Constructable] + public SpeckledPoisonSac() : base( 0x23A, TimeSpan.FromHours( 1 ) ) + { + LootType = LootType.Blessed; + } + + public SpeckledPoisonSac( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/SpiritBottle.cs b/Scripts/Engines/MLQuests/Items/SpiritBottle.cs new file mode 100644 index 0000000..80221ac --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/SpiritBottle.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpiritBottle : Item + { + public override int LabelNumber{ get{ return 1075283; } } // Spirit bottle + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public SpiritBottle() : base( 0xEFB ) + { + LootType = LootType.Blessed; + } + + public SpiritBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/StoutWhip.cs b/Scripts/Engines/MLQuests/Items/StoutWhip.cs new file mode 100644 index 0000000..778b1c8 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/StoutWhip.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StoutWhip : Item + { + public override int LabelNumber{ get{ return 1074812; } } // Stout Whip + + [Constructable] + public StoutWhip() : base( 0x166F ) + { + LootType = LootType.Blessed; + } + + public StoutWhip( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/TaintedTreeSample.cs b/Scripts/Engines/MLQuests/Items/TaintedTreeSample.cs new file mode 100644 index 0000000..33264f4 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/TaintedTreeSample.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TaintedTreeSample : Item // On OSI the base class is Kindling, and it's ignitable... + { + public override int LabelNumber{ get{ return 1074997; } } // Tainted Tree Sample + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public TaintedTreeSample() : base( 0xDE2 ) + { + LootType = LootType.Blessed; + Hue = 0x9D; + } + + public TaintedTreeSample( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/Teleporters.cs b/Scripts/Engines/MLQuests/Items/Teleporters.cs new file mode 100644 index 0000000..cbe272e --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/Teleporters.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Items +{ + public class MLQuestTeleporter : Teleporter + { + private Type m_QuestType; + private TextDefinition m_Message; + + [CommandProperty(AccessLevel.GameMaster)] + public Type QuestType + { + get { return m_QuestType; } + set { m_QuestType = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TextDefinition Message + { + get { return m_Message; } + set { m_Message = value; } + } + + [Constructable] + public MLQuestTeleporter() + : this(Point3D.Zero, null, null, null) + { + } + + [Constructable] + public MLQuestTeleporter(Point3D pointDest, Map mapDest) + : this(pointDest, mapDest, null, null) + { + } + + [Constructable] + public MLQuestTeleporter(Point3D pointDest, Map mapDest, Type questType, TextDefinition message) + : base(pointDest, mapDest) + { + m_QuestType = questType; + m_Message = message; + } + + public override bool CanTeleport(Mobile m) + { + if (!base.CanTeleport(m)) + return false; + + if (m_QuestType != null) + { + PlayerMobile pm = m as PlayerMobile; + + if (pm == null) + return false; + + MLQuestContext context = MLQuestSystem.GetContext(pm); + + if (context == null || (!context.IsDoingQuest(m_QuestType) && !context.HasDoneQuest(m_QuestType))) + { + TextDefinition.SendMessageTo(m, m_Message); + return false; + } + } + + return true; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_QuestType != null) + list.Add(String.Format("Required quest: {0}", m_QuestType.Name)); + } + + public MLQuestTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((m_QuestType != null) ? m_QuestType.FullName : null); + TextDefinition.Serialize(writer, m_Message); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + string typeName = reader.ReadString(); + + if (typeName != null) + m_QuestType = ScriptCompiler.FindTypeByFullName(typeName, false); + + m_Message = TextDefinition.Deserialize(reader); + } + } + + public interface ITicket + { + void OnTicketUsed(Mobile from); + } + + public class TicketTeleporter : Teleporter + { + private Type m_TicketType; + private TextDefinition m_Message; + + [CommandProperty(AccessLevel.GameMaster)] + public Type TicketType + { + get { return m_TicketType; } + set { m_TicketType = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TextDefinition Message + { + get { return m_Message; } + set { m_Message = value; } + } + + [Constructable] + public TicketTeleporter() + : this(Point3D.Zero, null, null, null) + { + } + + [Constructable] + public TicketTeleporter(Point3D pointDest, Map mapDest) + : this(pointDest, mapDest, null, null) + { + } + + [Constructable] + public TicketTeleporter(Point3D pointDest, Map mapDest, Type ticketType, TextDefinition message) + : base(pointDest, mapDest) + { + m_TicketType = ticketType; + m_Message = message; + } + + public override bool CanTeleport(Mobile m) + { + if (!base.CanTeleport(m)) + return false; + + if (m_TicketType != null) + { + Item ticket = null; + Container pack = m.Backpack; + + if (pack != null) + ticket = pack.FindItemByType(m_TicketType, false); // Check (top level) backpack + + if (ticket == null) + { + foreach (Item item in m.Items) // Check paperdoll + { + if (m_TicketType.IsAssignableFrom(item.GetType())) + { + ticket = item; + break; + } + } + } + + if (ticket == null) + { + TextDefinition.SendMessageTo(m, m_Message); + return false; + } + + if (ticket is ITicket) + ((ITicket)ticket).OnTicketUsed(m); + } + + return true; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_TicketType != null) + list.Add(String.Format("Required ticket: {0}", m_TicketType.Name)); + } + + public TicketTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((m_TicketType != null) ? m_TicketType.FullName : null); + TextDefinition.Serialize(writer, m_Message); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + string typeName = reader.ReadString(); + + if (typeName != null) + m_TicketType = ScriptCompiler.FindTypeByFullName(typeName, false); + + m_Message = TextDefinition.Deserialize(reader); + } + } +} + diff --git a/Scripts/Engines/MLQuests/Items/TransparentHeart.cs b/Scripts/Engines/MLQuests/Items/TransparentHeart.cs new file mode 100644 index 0000000..db0bb96 --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/TransparentHeart.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TransparentHeart : GoldEarrings + { + public override int LabelNumber{ get{ return 1075400; } } // Transparent Heart + + [Constructable] + public TransparentHeart() : base() + { + LootType = LootType.Blessed; + Hue = 0x4AB; + } + + public TransparentHeart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/TuitionReimbursementForm.cs b/Scripts/Engines/MLQuests/Items/TuitionReimbursementForm.cs new file mode 100644 index 0000000..df6085c --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/TuitionReimbursementForm.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TuitionReimbursementForm : Item + { + public override int LabelNumber{ get{ return 1074610; } } // Tuition Reimbursement Form (in triplicate) + + public override bool Nontransferable { get { return true; } } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + AddQuestItemProperty( list ); + } + + [Constructable] + public TuitionReimbursementForm() : base( 0xE3A ) + { + LootType = LootType.Blessed; + } + + public TuitionReimbursementForm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Items/UnicornRibs.cs b/Scripts/Engines/MLQuests/Items/UnicornRibs.cs new file mode 100644 index 0000000..e60dbbc --- /dev/null +++ b/Scripts/Engines/MLQuests/Items/UnicornRibs.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class UnicornRibs : Item + { + public override int LabelNumber{ get{ return 1074611; } } // Unicorn Ribs + + [Constructable] + public UnicornRibs() : this( 1 ) + { + } + + [Constructable] + public UnicornRibs( int amount ) : base( 0x9F1 ) + { + LootType = LootType.Blessed; + Hue = 0x14B; + Stackable = true; + Amount = amount; + } + + public UnicornRibs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/MLQuest.cs b/Scripts/Engines/MLQuests/MLQuest.cs new file mode 100644 index 0000000..43e83b2 --- /dev/null +++ b/Scripts/Engines/MLQuests/MLQuest.cs @@ -0,0 +1,345 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.MLQuests.Gumps; +using Server.Engines.MLQuests.Objectives; +using Server.Engines.MLQuests.Rewards; +using Server.Mobiles; + +namespace Server.Engines.MLQuests +{ + public enum ObjectiveType + { + All, + Any + } + + public class MLQuest + { + private bool m_Deserialized; + private bool m_SaveEnabled; + + public bool Deserialized + { + get { return m_Deserialized; } + set { m_Deserialized = value; } + } + + public bool SaveEnabled + { + get { return m_SaveEnabled; } + set { m_SaveEnabled = value; } + } + + private bool m_Activated; + private List m_Objectives; + private ObjectiveType m_ObjectiveType; + private List m_Rewards; + + private List m_Instances; + + private TextDefinition m_Title; + private TextDefinition m_Description; + private TextDefinition m_RefuseMessage; + private TextDefinition m_InProgressMessage; + private TextDefinition m_CompletionMessage; + private TextDefinition m_CompletionNotice; + + // TODO: Flags? (Deserialized, SaveEnabled, Activated) + private bool m_OneTimeOnly; + private bool m_HasRestartDelay; + + public bool Activated + { + get { return m_Activated; } + set { m_Activated = value; } + } + + public List Objectives + { + get { return m_Objectives; } + set { m_Objectives = value; } + } + + public ObjectiveType ObjectiveType + { + get { return m_ObjectiveType; } + set { m_ObjectiveType = value; } + } + + public List Rewards + { + get { return m_Rewards; } + set { m_Rewards = value; } + } + + public List Instances + { + get { return m_Instances; } + set { m_Instances = value; } + } + + public bool OneTimeOnly + { + get { return m_OneTimeOnly; } + set { m_OneTimeOnly = value; } + } + + public bool HasRestartDelay + { + get { return m_HasRestartDelay; } + set { m_HasRestartDelay = value; } + } + + public bool HasObjective() where T : BaseObjective + { + foreach ( BaseObjective obj in m_Objectives ) + { + if ( obj is T ) + return true; + } + + return false; + } + + public bool IsEscort + { + get { return HasObjective(); } + } + + public bool IsSkillTrainer + { + get { return HasObjective(); } + } + + public bool RequiresCollection + { + get { return HasObjective() || HasObjective(); } + } + + public virtual bool RecordCompletion + { + get { return ( m_OneTimeOnly || m_HasRestartDelay ); } + } + + public virtual bool IsChainTriggered { get { return false; } } + public virtual Type NextQuest { get { return null; } } + + public TextDefinition Title { get { return m_Title; } set { m_Title = value; } } + public TextDefinition Description { get { return m_Description; } set { m_Description = value; } } + public TextDefinition RefusalMessage { get { return m_RefuseMessage; } set { m_RefuseMessage = value; } } + public TextDefinition InProgressMessage { get { return m_InProgressMessage; } set { m_InProgressMessage = value; } } + public TextDefinition CompletionMessage { get { return m_CompletionMessage; } set { m_CompletionMessage = value; } } + public TextDefinition CompletionNotice { get { return m_CompletionNotice; } set { m_CompletionNotice = value; } } + + public static readonly TextDefinition CompletionNoticeDefault = new TextDefinition( 1072273 ); // You've completed a quest! Don't forget to collect your reward. + public static readonly TextDefinition CompletionNoticeShort = new TextDefinition( 1046258 ); // Your quest is complete. + public static readonly TextDefinition CompletionNoticeShortReturn = new TextDefinition( 1073775 ); // Your quest is complete. Return for your reward. + public static readonly TextDefinition CompletionNoticeCraft = new TextDefinition( 1073967 ); // You obtained what you seek, now receive your reward. + + public MLQuest() + { + m_Activated = false; + m_Objectives = new List(); + m_ObjectiveType = ObjectiveType.All; + m_Rewards = new List(); + m_CompletionNotice = CompletionNoticeDefault; + + m_Instances = new List(); + + m_SaveEnabled = true; + } + + public virtual void Generate() + { + if ( MLQuestSystem.Debug ) + Console.WriteLine( "INFO: Generating quest: {0}", GetType() ); + } + + #region Generation Methods + + public void PutSpawner( Spawner s, Point3D loc, Map map ) + { + string name = String.Format( "MLQS-{0}", GetType().Name ); + + // Auto cleanup on regeneration + List toDelete = new List(); + + foreach ( Item item in map.GetItemsInRange( loc, 0 ) ) + { + if ( item is Spawner && item.Name == name ) + toDelete.Add( item ); + } + + foreach ( Item item in toDelete ) + item.Delete(); + + s.Name = name; + s.MoveToWorld( loc, map ); + } + + public void PutDeco( Item deco, Point3D loc, Map map ) + { + // Auto cleanup on regeneration + List toDelete = new List(); + + foreach ( Item item in map.GetItemsInRange( loc, 0 ) ) + { + if ( item.ItemID == deco.ItemID && item.Z == loc.Z ) + toDelete.Add( item ); + } + + foreach ( Item item in toDelete ) + item.Delete(); + + deco.MoveToWorld( loc, map ); + } + + #endregion + + public MLQuestInstance CreateInstance( IQuestGiver quester, PlayerMobile pm ) + { + return new MLQuestInstance( this, quester, pm ); + } + + public bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) + { + return CanOffer( quester, pm, MLQuestSystem.GetContext( pm ), message ); + } + + public virtual bool CanOffer( IQuestGiver quester, PlayerMobile pm, MLQuestContext context, bool message ) + { + if ( !m_Activated || quester.Deleted ) + return false; + + if ( context != null ) + { + if ( context.IsFull ) + { + if ( message ) + MLQuestSystem.Tell( quester, pm, 1080107 ); // I'm sorry, I have nothing for you at this time. + + return false; + } + + MLQuest checkQuest = this; + + while ( checkQuest != null ) + { + DateTime nextAvailable; + + if ( context.HasDoneQuest( checkQuest, out nextAvailable ) ) + { + if ( checkQuest.OneTimeOnly ) + { + if ( message ) + MLQuestSystem.Tell( quester, pm, 1075454 ); // I cannot offer you the quest again. + + return false; + } + else if ( nextAvailable > DateTime.Now ) + { + if ( message ) + MLQuestSystem.Tell( quester, pm, 1075575 ); // I'm sorry, but I don't have anything else for you right now. Could you check back with me in a few minutes? + + return false; + } + } + + if ( checkQuest.NextQuest == null ) + break; + + checkQuest = MLQuestSystem.FindQuest( checkQuest.NextQuest ); + } + } + + foreach ( BaseObjective obj in m_Objectives ) + { + if ( !obj.CanOffer( quester, pm, message ) ) + return false; + } + + return true; + } + + public virtual void SendOffer( IQuestGiver quester, PlayerMobile pm ) + { + pm.SendGump( new QuestOfferGump( this, quester, pm ) ); + } + + public virtual void OnAccept( IQuestGiver quester, PlayerMobile pm ) + { + if ( !CanOffer( quester, pm, true ) ) + return; + + MLQuestInstance instance = CreateInstance( quester, pm ); + + pm.SendLocalizedMessage( 1049019 ); // You have accepted the Quest. + pm.SendSound( 0x2E7 ); // private sound + + OnAccepted( instance ); + + foreach ( BaseObjectiveInstance obj in instance.Objectives ) + obj.OnQuestAccepted(); + } + + public virtual void OnAccepted( MLQuestInstance instance ) + { + } + + public virtual void OnRefuse( IQuestGiver quester, PlayerMobile pm ) + { + pm.SendGump( new QuestConversationGump( this, pm, RefusalMessage ) ); + } + + public virtual void GetRewards( MLQuestInstance instance ) + { + instance.SendRewardGump(); + } + + public virtual void OnRewardClaimed( MLQuestInstance instance ) + { + } + + public virtual void OnCancel( MLQuestInstance instance ) + { + } + + public virtual void OnQuesterDeleted( MLQuestInstance instance ) + { + } + + public virtual void OnPlayerDeath( MLQuestInstance instance ) + { + } + + public virtual TimeSpan GetRestartDelay() + { + return TimeSpan.FromSeconds( Utility.Random( 1, 5 ) * 30 ); + } + + public static void Serialize( GenericWriter writer, MLQuest quest ) + { + MLQuestSystem.WriteQuestRef( writer, quest ); + writer.Write( quest.Version ); + } + + public static void Deserialize( GenericReader reader, int version ) + { + MLQuest quest = MLQuestSystem.ReadQuestRef( reader ); + int oldVersion = reader.ReadInt(); + + if ( quest == null ) + return; // not saved or no longer exists + + quest.Refresh( oldVersion ); + quest.m_Deserialized = true; + } + + public virtual int Version { get { return 0; } } + + public virtual void Refresh( int oldVersion ) + { + } + } +} diff --git a/Scripts/Engines/MLQuests/MLQuestContext.cs b/Scripts/Engines/MLQuests/MLQuestContext.cs new file mode 100644 index 0000000..ebda2c2 --- /dev/null +++ b/Scripts/Engines/MLQuests/MLQuestContext.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; +using Server.Engines.MLQuests.Objectives; + +namespace Server.Engines.MLQuests +{ + [Flags] + public enum MLQuestFlag + { + None = 0x00, + Spellweaving = 0x01, + SummonFey = 0x02, + SummonFiend = 0x04, + BedlamAccess = 0x08 + } + + [PropertyObject] + public class MLQuestContext + { + private class MLDoneQuestInfo + { + public MLQuest m_Quest; + public DateTime m_NextAvailable; + + public MLDoneQuestInfo( MLQuest quest, DateTime nextAvailable ) + { + m_Quest = quest; + m_NextAvailable = nextAvailable; + } + + public void Serialize( GenericWriter writer ) + { + MLQuestSystem.WriteQuestRef( writer, m_Quest ); + writer.Write( m_NextAvailable ); + } + + public static MLDoneQuestInfo Deserialize( GenericReader reader, int version ) + { + MLQuest quest = MLQuestSystem.ReadQuestRef( reader ); + DateTime nextAvailable = reader.ReadDateTime(); + + if ( quest == null || !quest.RecordCompletion ) + return null; // forget about this record + + return new MLDoneQuestInfo( quest, nextAvailable ); + } + } + + private PlayerMobile m_Owner; + private List m_QuestInstances; + private List m_DoneQuests; + private List m_ChainOffers; + private MLQuestFlag m_Flags; + + public PlayerMobile Owner + { + get { return m_Owner; } + } + + public List QuestInstances + { + get { return m_QuestInstances; } + } + + public List ChainOffers + { + get { return m_ChainOffers; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsFull + { + get { return m_QuestInstances.Count >= MLQuestSystem.MaxConcurrentQuests; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Spellweaving + { + get { return GetFlag( MLQuestFlag.Spellweaving ); } + set { SetFlag( MLQuestFlag.Spellweaving, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SummonFey + { + get { return GetFlag( MLQuestFlag.SummonFey ); } + set { SetFlag( MLQuestFlag.SummonFey, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SummonFiend + { + get { return GetFlag( MLQuestFlag.SummonFiend ); } + set { SetFlag( MLQuestFlag.SummonFiend, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool BedlamAccess + { + get { return GetFlag( MLQuestFlag.BedlamAccess ); } + set { SetFlag( MLQuestFlag.BedlamAccess, value ); } + } + + public MLQuestContext( PlayerMobile owner ) + { + m_Owner = owner; + m_QuestInstances = new List(); + m_DoneQuests = new List(); + m_ChainOffers = new List(); + m_Flags = MLQuestFlag.None; + } + + public bool HasDoneQuest( Type questType ) + { + MLQuest quest = MLQuestSystem.FindQuest( questType ); + + return ( quest != null && HasDoneQuest( quest ) ); + } + + public bool HasDoneQuest( MLQuest quest ) + { + foreach ( MLDoneQuestInfo info in m_DoneQuests ) + { + if ( info.m_Quest == quest ) + return true; + } + + return false; + } + + public bool HasDoneQuest( MLQuest quest, out DateTime nextAvailable ) + { + nextAvailable = DateTime.MinValue; + + foreach ( MLDoneQuestInfo info in m_DoneQuests ) + { + if ( info.m_Quest == quest ) + { + nextAvailable = info.m_NextAvailable; + return true; + } + } + + return false; + } + + public void SetDoneQuest( MLQuest quest ) + { + SetDoneQuest( quest, DateTime.MinValue ); + } + + public void SetDoneQuest( MLQuest quest, DateTime nextAvailable ) + { + foreach ( MLDoneQuestInfo info in m_DoneQuests ) + { + if ( info.m_Quest == quest ) + { + info.m_NextAvailable = nextAvailable; + return; + } + } + + m_DoneQuests.Add( new MLDoneQuestInfo( quest, nextAvailable ) ); + } + + public void RemoveDoneQuest( MLQuest quest ) + { + for ( int i = m_DoneQuests.Count - 1; i >= 0; --i ) + { + MLDoneQuestInfo info = m_DoneQuests[i]; + + if ( info.m_Quest == quest ) + m_DoneQuests.RemoveAt( i ); + } + } + + public void HandleDeath() + { + for ( int i = m_QuestInstances.Count - 1; i >= 0; --i ) + m_QuestInstances[i].OnPlayerDeath(); + } + + public void HandleDeletion() + { + for ( int i = m_QuestInstances.Count - 1; i >= 0; --i ) + m_QuestInstances[i].Remove(); + } + + public MLQuestInstance FindInstance( Type questType ) + { + MLQuest quest = MLQuestSystem.FindQuest( questType ); + + if ( quest == null ) + return null; + + return FindInstance( quest ); + } + + public MLQuestInstance FindInstance( MLQuest quest ) + { + foreach ( MLQuestInstance instance in m_QuestInstances ) + { + if ( instance.Quest == quest ) + return instance; + } + + return null; + } + + public bool IsDoingQuest( Type questType ) + { + MLQuest quest = MLQuestSystem.FindQuest( questType ); + + return ( quest != null && IsDoingQuest( quest ) ); + } + + public bool IsDoingQuest( MLQuest quest ) + { + return ( FindInstance( quest ) != null ); + } + + public void Serialize( GenericWriter writer ) + { + // Version info is written in MLQuestPersistence.Serialize + + writer.WriteMobile( m_Owner ); + writer.Write( m_QuestInstances.Count ); + + foreach ( MLQuestInstance instance in m_QuestInstances ) + instance.Serialize( writer ); + + writer.Write( m_DoneQuests.Count ); + + foreach ( MLDoneQuestInfo info in m_DoneQuests ) + info.Serialize( writer ); + + writer.Write( m_ChainOffers.Count ); + + foreach ( MLQuest quest in m_ChainOffers ) + MLQuestSystem.WriteQuestRef( writer, quest ); + + writer.WriteEncodedInt( (int)m_Flags ); + } + + public MLQuestContext( GenericReader reader, int version ) + { + m_Owner = reader.ReadMobile(); + m_QuestInstances = new List(); + m_DoneQuests = new List(); + m_ChainOffers = new List(); + + int instances = reader.ReadInt(); + + for ( int i = 0; i < instances; ++i ) + { + MLQuestInstance instance = MLQuestInstance.Deserialize( reader, version, m_Owner ); + + if ( instance != null ) + m_QuestInstances.Add( instance ); + } + + int doneQuests = reader.ReadInt(); + + for ( int i = 0; i < doneQuests; ++i ) + { + MLDoneQuestInfo info = MLDoneQuestInfo.Deserialize( reader, version ); + + if ( info != null ) + m_DoneQuests.Add( info ); + } + + int chainOffers = reader.ReadInt(); + + for ( int i = 0; i < chainOffers; ++i ) + { + MLQuest quest = MLQuestSystem.ReadQuestRef( reader ); + + if ( quest != null && quest.IsChainTriggered ) + m_ChainOffers.Add( quest ); + } + + m_Flags = (MLQuestFlag)reader.ReadEncodedInt(); + } + + public bool GetFlag( MLQuestFlag flag ) + { + return ( ( m_Flags & flag ) != 0 ); + } + + public void SetFlag( MLQuestFlag flag, bool value ) + { + if ( value ) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + } +} diff --git a/Scripts/Engines/MLQuests/MLQuestEntry.cs b/Scripts/Engines/MLQuests/MLQuestEntry.cs new file mode 100644 index 0000000..501f914 --- /dev/null +++ b/Scripts/Engines/MLQuests/MLQuestEntry.cs @@ -0,0 +1,534 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.MLQuests.Objectives; +using Server.Mobiles; +using Server.Network; +using Server.Engines.MLQuests.Gumps; +using Server.Engines.MLQuests.Rewards; + +namespace Server.Engines.MLQuests +{ + [Flags] + public enum MLQuestInstanceFlags : byte + { + None = 0x00, + ClaimReward = 0x01, + Removed = 0x02, + Failed = 0x04 + } + + public class MLQuestInstance + { + private MLQuest m_Quest; + + private IQuestGiver m_Quester; + private Type m_QuesterType; + private PlayerMobile m_Player; + + private DateTime m_Accepted; + private MLQuestInstanceFlags m_Flags; + + private BaseObjectiveInstance[] m_ObjectiveInstances; + + private Timer m_Timer; + + public MLQuestInstance( MLQuest quest, IQuestGiver quester, PlayerMobile player ) + { + m_Quest = quest; + + m_Quester = quester; + m_QuesterType = ( quester == null ) ? null : quester.GetType(); + m_Player = player; + + m_Accepted = DateTime.Now; + m_Flags = MLQuestInstanceFlags.None; + + m_ObjectiveInstances = new BaseObjectiveInstance[quest.Objectives.Count]; + + BaseObjectiveInstance obj; + bool timed = false; + + for ( int i = 0; i < quest.Objectives.Count; ++i ) + { + m_ObjectiveInstances[i] = obj = quest.Objectives[i].CreateInstance( this ); + + if ( obj.IsTimed ) + timed = true; + } + + Register(); + + if ( timed ) + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), Slice ); + } + + private void Register() + { + if ( m_Quest != null && m_Quest.Instances != null ) + m_Quest.Instances.Add( this ); + + if ( m_Player != null ) + PlayerContext.QuestInstances.Add( this ); + } + + private void Unregister() + { + if ( m_Quest != null && m_Quest.Instances != null ) + m_Quest.Instances.Remove( this ); + + if ( m_Player != null ) + PlayerContext.QuestInstances.Remove( this ); + + Removed = true; + } + + public MLQuest Quest + { + get { return m_Quest; } + set { m_Quest = value; } + } + + public IQuestGiver Quester + { + get { return m_Quester; } + set + { + m_Quester = value; + m_QuesterType = ( value == null ) ? null : value.GetType(); + } + } + + public Type QuesterType + { + get { return m_QuesterType; } + } + + public PlayerMobile Player + { + get { return m_Player; } + set { m_Player = value; } + } + + public MLQuestContext PlayerContext + { + get { return MLQuestSystem.GetOrCreateContext( m_Player ); } + } + + public DateTime Accepted + { + get { return m_Accepted; } + set { m_Accepted = value; } + } + + public bool ClaimReward + { + get { return GetFlag( MLQuestInstanceFlags.ClaimReward ); } + set { SetFlag( MLQuestInstanceFlags.ClaimReward, value ); } + } + + public bool Removed + { + get { return GetFlag( MLQuestInstanceFlags.Removed ); } + set { SetFlag( MLQuestInstanceFlags.Removed, value ); } + } + + public bool Failed + { + get { return GetFlag( MLQuestInstanceFlags.Failed ); } + set { SetFlag( MLQuestInstanceFlags.Failed, value ); } + } + + public BaseObjectiveInstance[] Objectives + { + get { return m_ObjectiveInstances; } + set { m_ObjectiveInstances = value; } + } + + public bool AllowsQuestItem( Item item, Type type ) + { + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + { + if ( !objective.Expired && objective.AllowsQuestItem( item, type ) ) + return true; + } + + return false; + } + + public bool IsCompleted() + { + bool requiresAll = ( m_Quest.ObjectiveType == ObjectiveType.All ); + + foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances ) + { + bool complete = obj.IsCompleted(); + + if ( complete && !requiresAll ) + return true; + else if ( !complete && requiresAll ) + return false; + } + + return requiresAll; + } + + public void CheckComplete() + { + if ( IsCompleted() ) + { + m_Player.PlaySound( 0x5B5 ); // public sound + + foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances ) + obj.OnQuestCompleted(); + + TextDefinition.SendMessageTo( m_Player, m_Quest.CompletionNotice, 0x23 ); + + /* + * Advance to the ClaimReward=true stage if this quest has no + * completion message to show anyway. This suppresses further + * triggers of CheckComplete. + * + * For quests that require collections, this is done later when + * the player double clicks the quester. + */ + if ( !Removed && SkipReportBack && !m_Quest.RequiresCollection ) // An OnQuestCompleted can potentially have removed this instance already + ContinueReportBack( false ); + } + } + + public void Fail() + { + Failed = true; + } + + private void Slice() + { + if ( ClaimReward || Removed ) + { + StopTimer(); + return; + } + + bool hasAnyFails = false; + bool hasAnyLeft = false; + + foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances ) + { + if ( !obj.Expired ) + { + if ( obj.IsTimed && obj.EndTime <= DateTime.Now ) + { + m_Player.SendLocalizedMessage( 1072258 ); // You failed to complete an objective in time! + + obj.Expired = true; + obj.OnExpire(); + + hasAnyFails = true; + } + else + { + hasAnyLeft = true; + } + } + } + + if ( ( m_Quest.ObjectiveType == ObjectiveType.All && hasAnyFails ) || !hasAnyLeft ) + Fail(); + + if ( !hasAnyLeft ) + StopTimer(); + } + + public void SendProgressGump() + { + m_Player.SendGump( new QuestConversationGump( m_Quest, m_Player, m_Quest.InProgressMessage ) ); + } + + public void SendRewardOffer() + { + m_Quest.GetRewards( this ); + } + + // TODO: Split next quest stuff from SendRewardGump stuff? + public void SendRewardGump() + { + Type nextQuestType = m_Quest.NextQuest; + + if ( nextQuestType != null ) + { + ClaimRewards(); // skip reward gump + + if ( Removed ) // rewards were claimed successfully + { + MLQuest nextQuest = MLQuestSystem.FindQuest( nextQuestType ); + + if ( nextQuest != null ) + nextQuest.SendOffer( m_Quester, m_Player ); + } + } + else + { + m_Player.SendGump( new QuestRewardGump( this ) ); + } + } + + public bool SkipReportBack + { + get { return TextDefinition.IsNullOrEmpty( m_Quest.CompletionMessage ); } + } + + public void SendReportBackGump() + { + if ( SkipReportBack ) + ContinueReportBack( true ); // skip ahead + else + m_Player.SendGump( new QuestReportBackGump( this ) ); + } + + public void ContinueReportBack( bool sendRewardGump ) + { + // There is a backpack check here on OSI for the rewards as well (even though it's not needed...) + + if ( m_Quest.ObjectiveType == ObjectiveType.All ) + { + // TODO: 1115877 - You no longer have the required items to complete this quest. + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + { + if ( !objective.IsCompleted() ) + return; + } + + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + { + if ( !objective.OnBeforeClaimReward() ) + return; + } + + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + objective.OnClaimReward(); + } + else + { + /* The following behavior is unverified, as OSI (currently) has no collect quest requiring + * only one objective to be completed. It is assumed that only one objective is claimed + * (the first completed one), even when multiple are complete. + */ + bool complete = false; + + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + { + if ( objective.IsCompleted() ) + { + if ( objective.OnBeforeClaimReward() ) + { + complete = true; + objective.OnClaimReward(); + } + + break; + } + } + + if ( !complete ) + return; + } + + ClaimReward = true; + + if ( m_Quest.HasRestartDelay ) + PlayerContext.SetDoneQuest( m_Quest, DateTime.Now + m_Quest.GetRestartDelay() ); + + // This is correct for ObjectiveType.Any as well + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + objective.OnAfterClaimReward(); + + if ( sendRewardGump ) + SendRewardOffer(); + } + + public void ClaimRewards() + { + if ( m_Quest == null || m_Player == null || m_Player.Deleted || !ClaimReward || Removed ) + return; + + List rewards = new List(); + + foreach ( BaseReward reward in m_Quest.Rewards ) + reward.AddRewardItems( m_Player, rewards ); + + if ( rewards.Count != 0 ) + { + // On OSI a more naive method of checking is used. + // For containers, only the actual container item counts. + bool canFit = true; + + foreach ( Item rewardItem in rewards ) + { + if ( !m_Player.AddToBackpack( rewardItem ) ) + { + canFit = false; + break; + } + } + + if ( !canFit ) + { + foreach ( Item rewardItem in rewards ) + rewardItem.Delete(); + + m_Player.SendLocalizedMessage( 1078524 ); // Your backpack is full. You cannot complete the quest and receive your reward. + return; + } + + foreach ( Item rewardItem in rewards ) + { + string rewardName = ( rewardItem.Name != null ) ? rewardItem.Name : String.Concat( "#", rewardItem.LabelNumber ); + + if ( rewardItem.Stackable ) + m_Player.SendLocalizedMessage( 1115917, String.Concat( rewardItem.Amount, "\t", rewardName ) ); // You receive a reward: ~1_QUANTITY~ ~2_ITEM~ + else + m_Player.SendLocalizedMessage( 1074360, rewardName ); // You receive a reward: ~1_REWARD~ + } + } + + foreach ( BaseObjectiveInstance objective in m_ObjectiveInstances ) + objective.OnRewardClaimed(); + + m_Quest.OnRewardClaimed( this ); + + MLQuestContext context = PlayerContext; + + if ( m_Quest.RecordCompletion && !m_Quest.HasRestartDelay ) // Quests with restart delays are logged earlier as per OSI + context.SetDoneQuest( m_Quest ); + + if ( m_Quest.IsChainTriggered ) + context.ChainOffers.Remove( m_Quest ); + + Type nextQuestType = m_Quest.NextQuest; + + if ( nextQuestType != null ) + { + MLQuest nextQuest = MLQuestSystem.FindQuest( nextQuestType ); + + if ( nextQuest != null && !context.ChainOffers.Contains( nextQuest ) ) + context.ChainOffers.Add( nextQuest ); + } + + Remove(); + } + + public void Cancel() + { + Cancel( false ); + } + + public void Cancel( bool removeChain ) + { + Remove(); + + m_Player.SendSound( 0x5B3 ); // private sound + + foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances ) + obj.OnQuestCancelled(); + + m_Quest.OnCancel( this ); + + if ( removeChain ) + PlayerContext.ChainOffers.Remove( m_Quest ); + } + + public void Remove() + { + Unregister(); + StopTimer(); + } + + private void StopTimer() + { + if ( m_Timer != null ) + { + m_Timer.Stop(); + m_Timer = null; + } + } + + public void OnQuesterDeleted() + { + foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances ) + obj.OnQuesterDeleted(); + + m_Quest.OnQuesterDeleted( this ); + } + + public void OnPlayerDeath() + { + foreach ( BaseObjectiveInstance obj in m_ObjectiveInstances ) + obj.OnPlayerDeath(); + + m_Quest.OnPlayerDeath( this ); + } + + private bool GetFlag( MLQuestInstanceFlags flag ) + { + return ( ( m_Flags & flag ) != 0 ); + } + + private void SetFlag( MLQuestInstanceFlags flag, bool value ) + { + if ( value ) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + + public void Serialize( GenericWriter writer ) + { + // Version info is written in MLQuestPersistence.Serialize + + MLQuestSystem.WriteQuestRef( writer, m_Quest ); + + if ( m_Quester == null || m_Quester.Deleted ) + writer.Write( Serial.MinusOne ); + else + writer.Write( m_Quester.Serial ); + + writer.Write( ClaimReward ); + writer.Write( m_ObjectiveInstances.Length ); + + foreach ( BaseObjectiveInstance objInstance in m_ObjectiveInstances ) + objInstance.Serialize( writer ); + } + + public static MLQuestInstance Deserialize( GenericReader reader, int version, PlayerMobile pm ) + { + MLQuest quest = MLQuestSystem.ReadQuestRef( reader ); + + // TODO: Serialize quester TYPE too, the quest giver reference then becomes optional (only for escorts) + IQuestGiver quester = World.FindEntity( reader.ReadInt() ) as IQuestGiver; + + bool claimReward = reader.ReadBool(); + int objectives = reader.ReadInt(); + + MLQuestInstance instance; + + if ( quest != null && quester != null && pm != null ) + { + instance = quest.CreateInstance( quester, pm ); + instance.ClaimReward = claimReward; + } + else + { + instance = null; + } + + for ( int i = 0; i < objectives; ++i ) + BaseObjectiveInstance.Deserialize( reader, version, ( instance != null && i < instance.Objectives.Length ) ? instance.Objectives[i] : null ); + + if ( instance != null ) + instance.Slice(); + + return instance; + } + } +} diff --git a/Scripts/Engines/MLQuests/MLQuestPersistence.cs b/Scripts/Engines/MLQuests/MLQuestPersistence.cs new file mode 100644 index 0000000..2559a75 --- /dev/null +++ b/Scripts/Engines/MLQuests/MLQuestPersistence.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Engines.MLQuests +{ + public class MLQuestPersistence : Item + { + private static MLQuestPersistence m_Instance; + + public static void EnsureExistence() + { + if ( m_Instance == null ) + m_Instance = new MLQuestPersistence(); + } + + public override string DefaultName + { + get { return "ML quests persistence - Internal"; } + } + + private MLQuestPersistence() + : base( 1 ) + { + Movable = false; + } + + public MLQuestPersistence( Serial serial ) : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + writer.Write( MLQuestSystem.Contexts.Count ); + + foreach ( MLQuestContext context in MLQuestSystem.Contexts.Values ) + context.Serialize( writer ); + + writer.Write( MLQuestSystem.Quests.Count ); + + foreach ( MLQuest quest in MLQuestSystem.Quests.Values ) + MLQuest.Serialize( writer, quest ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + int contexts = reader.ReadInt(); + + for ( int i = 0; i < contexts; ++i ) + { + MLQuestContext context = new MLQuestContext( reader, version ); + + if ( context.Owner != null ) + MLQuestSystem.Contexts[context.Owner] = context; + } + + int quests = reader.ReadInt(); + + for ( int i = 0; i < quests; ++i ) + MLQuest.Deserialize( reader, version ); + } + } +} diff --git a/Scripts/Engines/MLQuests/MLQuestSystem.cs b/Scripts/Engines/MLQuests/MLQuestSystem.cs new file mode 100644 index 0000000..4f4959d --- /dev/null +++ b/Scripts/Engines/MLQuests/MLQuestSystem.cs @@ -0,0 +1,782 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Commands; +using Server.Engines.MLQuests.Definitions; +using Server.Engines.MLQuests.Gumps; +using Server.Engines.MLQuests.Objectives; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using System.Collections; +using Server.Commands.Generic; +using Server.Items; +using Server.Targeting; +using System.IO; + +namespace Server.Engines.MLQuests +{ + public static class MLQuestSystem + { + public static bool Enabled { get { return Core.ML; } } + + public const int MaxConcurrentQuests = 10; + public const int SpeechColor = 0x3B2; + + public static readonly bool AutoGenerateNew = true; + public static readonly bool Debug = false; + + private static Dictionary m_Quests; + private static Dictionary> m_QuestGivers; + private static Dictionary m_Contexts; + + public static readonly List EmptyList = new List(); + + public static Dictionary Quests + { + get { return m_Quests; } + } + + public static Dictionary> QuestGivers + { + get { return m_QuestGivers; } + } + + public static Dictionary Contexts + { + get { return m_Contexts; } + } + + static MLQuestSystem() + { + m_Quests = new Dictionary(); + m_QuestGivers = new Dictionary>(); + m_Contexts = new Dictionary(); + + string cfgPath = Path.Combine( Core.BaseDirectory, Path.Combine( "Data", "MLQuests.cfg" ) ); + + Type baseQuestType = typeof( MLQuest ); + Type baseQuesterType = typeof( IQuestGiver ); + + if ( File.Exists( cfgPath ) ) + { + using ( StreamReader sr = new StreamReader( cfgPath ) ) + { + string line; + + while ( ( line = sr.ReadLine() ) != null ) + { + if ( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + string[] split = line.Split( '\t' ); + + Type type = ScriptCompiler.FindTypeByName( split[0] ); + + if ( type == null || !baseQuestType.IsAssignableFrom( type ) ) + { + if ( Debug ) + Console.WriteLine( "Warning: {1} quest type '{0}'", split[0], ( type == null ) ? "Unknown" : "Invalid" ); + + continue; + } + + MLQuest quest = null; + + try + { + quest = Activator.CreateInstance( type ) as MLQuest; + } + catch { } + + if ( quest == null ) + continue; + + Register( type, quest ); + + for ( int i = 1; i < split.Length; ++i ) + { + Type questerType = ScriptCompiler.FindTypeByName( split[i] ); + + if ( questerType == null || !baseQuesterType.IsAssignableFrom( questerType ) ) + { + if ( Debug ) + Console.WriteLine( "Warning: {1} quester type '{0}'", split[i], ( questerType == null ) ? "Unknown" : "Invalid" ); + + continue; + } + + RegisterQuestGiver( quest, questerType ); + } + } + } + } + } + + private static void Register( Type type, MLQuest quest ) + { + m_Quests[type] = quest; + } + + private static void RegisterQuestGiver( MLQuest quest, Type questerType ) + { + List questList; + + if ( !m_QuestGivers.TryGetValue( questerType, out questList ) ) + m_QuestGivers[questerType] = questList = new List(); + + questList.Add( quest ); + } + + public static void Register( MLQuest quest, params Type[] questerTypes ) + { + Register( quest.GetType(), quest ); + + foreach ( Type questerType in questerTypes ) + RegisterQuestGiver( quest, questerType ); + } + + public static void Initialize() + { + if ( !Enabled ) + return; + + if ( AutoGenerateNew ) + { + foreach ( MLQuest quest in m_Quests.Values ) + { + if ( quest != null && !quest.Deserialized ) + quest.Generate(); + } + } + + MLQuestPersistence.EnsureExistence(); + + CommandSystem.Register( "MLQuestsInfo", AccessLevel.Administrator, new CommandEventHandler( MLQuestsInfo_OnCommand ) ); + CommandSystem.Register( "SaveQuest", AccessLevel.Administrator, new CommandEventHandler( SaveQuest_OnCommand ) ); + CommandSystem.Register( "SaveAllQuests", AccessLevel.Administrator, new CommandEventHandler( SaveAllQuests_OnCommand ) ); + CommandSystem.Register( "InvalidQuestItems", AccessLevel.Administrator, new CommandEventHandler( InvalidQuestItems_OnCommand ) ); + + TargetCommands.Register( new ViewQuestsCommand() ); + TargetCommands.Register( new ViewContextCommand() ); + + EventSink.QuestGumpRequest += new QuestGumpRequestHandler( EventSink_QuestGumpRequest ); + } + + [Usage( "MLQuestsInfo" )] + [Description( "Displays general information about the ML quest system, or a quest by type name." )] + public static void MLQuestsInfo_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + + if ( e.Length == 0 ) + { + m.SendMessage( "Quest table length: {0}", m_Quests.Count ); + return; + } + + Type index = ScriptCompiler.FindTypeByName( e.GetString( 0 ) ); + MLQuest quest; + + if ( index == null || !m_Quests.TryGetValue( index, out quest ) ) + { + m.SendMessage( "Invalid quest type name." ); + return; + } + + m.SendMessage( "Activated: {0}", quest.Activated ); + m.SendMessage( "Number of objectives: {0}", quest.Objectives.Count ); + m.SendMessage( "Objective type: {0}", quest.ObjectiveType ); + m.SendMessage( "Number of active instances: {0}", quest.Instances.Count ); + } + + public class ViewQuestsCommand : BaseCommand + { + public ViewQuestsCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Simple; + Commands = new string[] { "ViewQuests" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "ViewQuests"; + Description = "Displays a targeted mobile's quest overview."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + Mobile from = e.Mobile; + PlayerMobile pm = obj as PlayerMobile; + + if ( pm == null ) + { + LogFailure( "That is not a player." ); + return; + } + + CommandLogging.WriteLine( from, "{0} {1} viewing quest overview of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( pm ) ); + from.SendGump( new QuestLogGump( pm, false ) ); + } + } + + private class ViewContextCommand : BaseCommand + { + public ViewContextCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.Simple; + Commands = new string[] { "ViewMLContext" }; + ObjectTypes = ObjectTypes.Mobiles; + Usage = "ViewMLContext"; + Description = "Opens the ML quest context for a targeted mobile."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + PlayerMobile pm = obj as PlayerMobile; + + if ( pm == null ) + LogFailure( "They have no ML quest context." ); + else + e.Mobile.SendGump( new PropertiesGump( e.Mobile, GetOrCreateContext( pm ) ) ); + } + } + + [Usage( "SaveQuest [saveEnabled=true]" )] + [Description( "Allows serialization for a specific quest to be turned on or off." )] + public static void SaveQuest_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + + if ( e.Length == 0 || e.Length > 2 ) + { + m.SendMessage( "Syntax: SaveQuest [saveEnabled=true]" ); + return; + } + + Type index = ScriptCompiler.FindTypeByName( e.GetString( 0 ) ); + MLQuest quest; + + if ( index == null || !m_Quests.TryGetValue( index, out quest ) ) + { + m.SendMessage( "Invalid quest type name." ); + return; + } + + bool enable = ( e.Length == 2 ) ? e.GetBoolean( 1 ) : true; + + quest.SaveEnabled = enable; + m.SendMessage( "Serialization for quest {0} is now {1}.", quest.GetType().Name, enable ? "enabled" : "disabled" ); + + if ( AutoGenerateNew && !enable ) + m.SendMessage( "Please note that automatic generation of new quests is ON. This quest will be regenerated on the next server start." ); + } + + [Usage( "SaveAllQuests [saveEnabled=true]" )] + [Description( "Allows serialization for all quests to be turned on or off." )] + public static void SaveAllQuests_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + + if ( e.Length > 1 ) + { + m.SendMessage( "Syntax: SaveAllQuests [saveEnabled=true]" ); + return; + } + + bool enable = ( e.Length == 1 ) ? e.GetBoolean( 0 ) : true; + + foreach ( MLQuest quest in m_Quests.Values ) + quest.SaveEnabled = enable; + + m.SendMessage( "Serialization for all quests is now {0}.", enable ? "enabled" : "disabled" ); + + if ( AutoGenerateNew && !enable ) + m.SendMessage( "Please note that automatic generation of new quests is ON. All quests will be regenerated on the next server start." ); + } + + [Usage( "InvalidQuestItems" )] + [Description( "Provides an overview of all quest items not located in the top-level of a player's backpack." )] + public static void InvalidQuestItems_OnCommand( CommandEventArgs e ) + { + Mobile m = e.Mobile; + + ArrayList found = new ArrayList(); + + foreach ( Item item in World.Items.Values ) + { + if ( item.QuestItem ) + { + Backpack pack = item.Parent as Backpack; + + if ( pack != null ) + { + PlayerMobile player = pack.Parent as PlayerMobile; + + if ( player != null && player.Backpack == pack ) + continue; + } + + found.Add( item ); + } + } + + if ( found.Count == 0 ) + m.SendMessage( "No matching objects found." ); + else + m.SendGump( new InterfaceGump( m, new string[] { "Object" }, found, 0, null ) ); + } + + private static bool FindQuest( IQuestGiver quester, PlayerMobile pm, MLQuestContext context, out MLQuest quest, out MLQuestInstance entry ) + { + quest = null; + entry = null; + + List quests = quester.MLQuests; + Type questerType = quester.GetType(); + + // 1. Check quests in progress with this NPC (overriding deliveries is intended) + if ( context != null ) + { + foreach ( MLQuest questEntry in quests ) + { + MLQuestInstance instance = context.FindInstance( questEntry ); + + if ( instance != null && ( instance.Quester == quester || ( !questEntry.IsEscort && instance.QuesterType == questerType ) ) ) + { + entry = instance; + quest = questEntry; + return true; + } + } + } + + // 2. Check deliveries (overriding chain offers is intended) + if ( ( entry = HandleDelivery( pm, quester, questerType ) ) != null ) + { + quest = entry.Quest; + return true; + } + + // 3. Check chain quest offers + if ( context != null ) + { + foreach ( MLQuest questEntry in quests ) + { + if ( questEntry.IsChainTriggered && context.ChainOffers.Contains( questEntry ) ) + { + quest = questEntry; + return true; + } + } + } + + // 4. Random quest + quest = RandomStarterQuest( quester, pm, context ); + + return ( quest != null ); + } + + public static void OnDoubleClick( IQuestGiver quester, PlayerMobile pm ) + { + if ( quester.Deleted || !pm.Alive ) + return; + + MLQuestContext context = GetContext( pm ); + + MLQuest quest; + MLQuestInstance entry; + + if ( !FindQuest( quester, pm, context, out quest, out entry ) ) + { + Tell( quester, pm, 1080107 ); // I'm sorry, I have nothing for you at this time. + return; + } + + if ( entry != null ) + { + TurnToFace( quester, pm ); + + if ( entry.Failed ) + return; // Note: OSI sends no gump at all for failed quests, they have to be cancelled in the quest overview + else if ( entry.ClaimReward ) + entry.SendRewardOffer(); + else if ( entry.IsCompleted() ) + entry.SendReportBackGump(); + else + entry.SendProgressGump(); + } + else if ( quest.CanOffer( quester, pm, context, true ) ) + { + TurnToFace( quester, pm ); + + quest.SendOffer( quester, pm ); + } + } + + public static bool CanMarkQuestItem( PlayerMobile pm, Item item, Type type ) + { + MLQuestContext context = GetContext( pm ); + + if ( context != null ) + { + foreach ( MLQuestInstance quest in context.QuestInstances ) + { + if ( !quest.ClaimReward && quest.AllowsQuestItem( item, type ) ) + return true; + } + } + + return false; + } + + private static void OnMarkQuestItem( PlayerMobile pm, Item item, Type type ) + { + MLQuestContext context = GetContext( pm ); + + if ( context == null ) + return; + + List instances = context.QuestInstances; + + // We don't foreach because CheckComplete() can potentially modify the MLQuests list + for ( int i = instances.Count - 1; i >= 0; --i ) + { + MLQuestInstance instance = instances[i]; + + if ( instance.ClaimReward ) + continue; + + foreach ( BaseObjectiveInstance objective in instance.Objectives ) + { + if ( !objective.Expired && objective.AllowsQuestItem( item, type ) ) + { + objective.CheckComplete(); // yes, this can happen multiple times (for multiple quests) + break; + } + } + } + } + + public static bool MarkQuestItem( PlayerMobile pm, Item item ) + { + Type type = item.GetType(); + + if ( CanMarkQuestItem( pm, item, type ) ) + { + item.QuestItem = true; + OnMarkQuestItem( pm, item, type ); + + return true; + } + + return false; + } + + public static void HandleSkillGain( PlayerMobile pm, SkillName skill ) + { + MLQuestContext context = GetContext( pm ); + + if ( context == null ) + return; + + List instances = context.QuestInstances; + + for ( int i = instances.Count - 1; i >= 0; --i ) + { + MLQuestInstance instance = instances[i]; + + if ( instance.ClaimReward ) + continue; + + foreach ( BaseObjectiveInstance objective in instance.Objectives ) + { + if ( !objective.Expired && objective is GainSkillObjectiveInstance && ( (GainSkillObjectiveInstance)objective ).Handles( skill ) ) + { + objective.CheckComplete(); + break; + } + } + } + } + + public static void HandleKill( PlayerMobile pm, Mobile mob ) + { + MLQuestContext context = GetContext( pm ); + + if ( context == null ) + return; + + List instances = context.QuestInstances; + + Type type = null; + + for ( int i = instances.Count - 1; i >= 0; --i ) + { + MLQuestInstance instance = instances[i]; + + if ( instance.ClaimReward ) + continue; + + /* A kill only counts for a single objective within a quest, + * but it can count for multiple quests. This is something not + * currently observable on OSI, so it is assumed behavior. + */ + foreach ( BaseObjectiveInstance objective in instance.Objectives ) + { + if ( !objective.Expired && objective is KillObjectiveInstance ) + { + KillObjectiveInstance kill = (KillObjectiveInstance)objective; + + if ( type == null ) + type = mob.GetType(); + + if ( kill.AddKill( mob, type ) ) + { + kill.CheckComplete(); + break; + } + } + } + } + } + + public static MLQuestInstance HandleDelivery( PlayerMobile pm, IQuestGiver quester, Type questerType ) + { + MLQuestContext context = GetContext( pm ); + + if ( context == null ) + return null; + + List instances = context.QuestInstances; + MLQuestInstance deliverInstance = null; + + for ( int i = instances.Count - 1; i >= 0; --i ) + { + MLQuestInstance instance = instances[i]; + + // Do NOT skip quests on ClaimReward, because the quester still needs the quest ref! + //if ( instance.ClaimReward ) + // continue; + + foreach ( BaseObjectiveInstance objective in instance.Objectives ) + { + // Note: On OSI, expired deliveries can still be completed. Bug? + if ( !objective.Expired && objective is DeliverObjectiveInstance ) + { + DeliverObjectiveInstance deliver = (DeliverObjectiveInstance)objective; + + if ( deliver.IsDestination( quester, questerType ) ) + { + if ( !deliver.HasCompleted ) // objective completes only once + { + deliver.HasCompleted = true; + deliver.CheckComplete(); + + // The quest is continued with this NPC (important for chains) + instance.Quester = quester; + } + + if ( deliverInstance == null ) + deliverInstance = instance; + + break; // don't return, we may have to complete more deliveries + } + } + } + } + + return deliverInstance; + } + + public static MLQuestContext GetContext( PlayerMobile pm ) + { + MLQuestContext context; + m_Contexts.TryGetValue( pm, out context ); + + return context; + } + + public static MLQuestContext GetOrCreateContext( PlayerMobile pm ) + { + MLQuestContext context; + + if ( !m_Contexts.TryGetValue( pm, out context ) ) + m_Contexts[pm] = context = new MLQuestContext( pm ); + + return context; + } + + public static void HandleDeath( PlayerMobile pm ) + { + MLQuestContext context = GetContext( pm ); + + if ( context != null ) + context.HandleDeath(); + } + + public static void HandleDeletion( PlayerMobile pm ) + { + MLQuestContext context = GetContext( pm ); + + if ( context != null ) + { + context.HandleDeletion(); + m_Contexts.Remove( pm ); + } + } + + public static void HandleDeletion( IQuestGiver quester ) + { + foreach ( MLQuest quest in quester.MLQuests ) + { + List instances = quest.Instances; + + for ( int i = instances.Count - 1; i >= 0; --i ) + { + MLQuestInstance instance = instances[i]; + + if ( instance.Quester == quester ) + instance.OnQuesterDeleted(); + } + } + } + + public static void EventSink_QuestGumpRequest( QuestGumpRequestArgs args ) + { + PlayerMobile pm = args.Mobile as PlayerMobile; + + if ( !Enabled || pm == null ) + return; + + pm.SendGump( new QuestLogGump( pm ) ); + } + + private static List m_EligiblePool = new List(); + + public static MLQuest RandomStarterQuest( IQuestGiver quester, PlayerMobile pm, MLQuestContext context ) + { + List quests = quester.MLQuests; + + if ( quests.Count == 0 ) + return null; + + m_EligiblePool.Clear(); + MLQuest fallback = null; + + foreach ( MLQuest quest in quests ) + { + if ( quest.IsChainTriggered || ( context != null && context.IsDoingQuest( quest ) ) ) + continue; + + /* + * Save first quest that reaches the CanOffer call. + * If no quests are valid at all, return this quest for displaying the CanOffer error message. + */ + if ( fallback == null ) + fallback = quest; + + if ( quest.CanOffer( quester, pm, context, false ) ) + m_EligiblePool.Add( quest ); + } + + if ( m_EligiblePool.Count == 0 ) + return fallback; + + return m_EligiblePool[Utility.Random( m_EligiblePool.Count )]; + } + + public static void TurnToFace( IQuestGiver quester, Mobile mob ) + { + if ( quester is Mobile ) + { + Mobile m = (Mobile)quester; + m.Direction = m.GetDirectionTo( mob ); + } + } + + public static void Tell( IQuestGiver quester, PlayerMobile pm, int cliloc ) + { + TurnToFace( quester, pm ); + + if ( quester is Mobile ) + ((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, pm.NetState ); + else if ( quester is Item ) + MessageHelper.SendLocalizedMessageTo( (Item)quester, pm, cliloc, SpeechColor ); + else + pm.SendLocalizedMessage( cliloc, "", SpeechColor ); + } + + public static void Tell( IQuestGiver quester, PlayerMobile pm, int cliloc, string args ) + { + TurnToFace( quester, pm ); + + if ( quester is Mobile ) + ((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, cliloc, args, pm.NetState ); + else if ( quester is Item ) + MessageHelper.SendLocalizedMessageTo( (Item)quester, pm, cliloc, args, SpeechColor ); + else + pm.SendLocalizedMessage( cliloc, args, SpeechColor ); + } + + public static void Tell( IQuestGiver quester, PlayerMobile pm, string message ) + { + TurnToFace( quester, pm ); + + if ( quester is Mobile ) + ((Mobile)quester).PrivateOverheadMessage( MessageType.Regular, SpeechColor, false, message, pm.NetState ); + else if ( quester is Item ) + MessageHelper.SendMessageTo( (Item)quester, pm, message, SpeechColor ); + else + pm.SendMessage( SpeechColor, message ); + } + + public static void TellDef( IQuestGiver quester, PlayerMobile pm, TextDefinition def ) + { + if ( def == null ) + return; + + if ( def.Number > 0 ) + Tell( quester, pm, def.Number ); + else if ( def.String != null ) + Tell( quester, pm, def.String ); + } + + public static void WriteQuestRef( GenericWriter writer, MLQuest quest ) + { + writer.Write( ( quest != null && quest.SaveEnabled ) ? quest.GetType().FullName : null ); + } + + public static MLQuest ReadQuestRef( GenericReader reader ) + { + string typeName = reader.ReadString(); + + if ( typeName == null ) + return null; // not serialized + + Type questType = ScriptCompiler.FindTypeByFullName( typeName ); + + if ( questType == null ) + return null; // no longer a type + + return FindQuest( questType ); + } + + public static MLQuest FindQuest( Type questType ) + { + MLQuest result; + m_Quests.TryGetValue( questType, out result ); + + return result; + } + + public static List FindQuestList( Type questerType ) + { + List result; + + if ( m_QuestGivers.TryGetValue( questerType, out result ) ) + return result; + + return EmptyList; + } + } +} diff --git a/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs b/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs new file mode 100644 index 0000000..238961c --- /dev/null +++ b/Scripts/Engines/MLQuests/Mobiles/BoonCollector.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.Engines.MLQuests.Gumps; +using Server.Engines.MLQuests.Definitions; + +namespace Server.Engines.MLQuests.Mobiles +{ + public abstract class DoneQuestCollector : BaseCreature, IRaceChanger + { + public override bool IsInvulnerable { get { return true; } } + + public abstract TextDefinition[] Offer { get; } + public abstract TextDefinition[] Incomplete { get; } + public abstract TextDefinition[] Complete { get; } + public abstract Type[] Needed { get; } + + private InternalTimer m_Timer; + + public DoneQuestCollector() + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + TryTalkTo( from, true ); + } + + public override void OnDoubleClickDead( Mobile from ) + { + TryTalkTo( from, true ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Player && InRange( m, 6 ) && !InRange( oldLocation, 6 ) ) + TryTalkTo( m, false ); + + base.OnMovement( m, oldLocation ); + } + + public void TryTalkTo( Mobile from, bool fromClick ) + { + if ( !from.Hidden && !from.HasGump( typeOfRaceChangeConfirmGump ) && !RaceChangeConfirmGump.IsPending( from.NetState ) && CanTalkTo( from ) ) + TalkTo( from as PlayerMobile ); + else if ( fromClick ) + DenyTalk( from ); + } + + public virtual bool CanTalkTo( Mobile from ) + { + return true; + } + + public virtual void DenyTalk( Mobile from ) + { + } + + private static Type typeOfRaceChangeConfirmGump = typeof( RaceChangeConfirmGump ); + + public void TalkTo( PlayerMobile pm ) + { + if ( pm == null || ( m_Timer != null && m_Timer.Running ) ) + return; + + int completed = CompletedCount( pm ); + + if ( completed == Needed.Length ) + { + m_Timer = new InternalTimer( this, pm, Complete, true ); + } + else if ( completed == 0 ) + { + m_Timer = new InternalTimer( this, pm, Offer, false ); + } + else + { + List conversation = new List(); + conversation.AddRange( Incomplete ); + + MLQuestContext context = MLQuestSystem.GetContext( pm ); + + if ( context != null ) + { + foreach ( Type type in Needed ) + { + MLQuest quest = MLQuestSystem.FindQuest( type ); + + if ( quest == null || context.HasDoneQuest( quest ) ) + continue; + + conversation.Add( quest.Title ); + } + } + + m_Timer = new InternalTimer( this, pm, conversation, false ); + } + + m_Timer.Start(); + } + + private int CompletedCount( PlayerMobile pm ) + { + MLQuestContext context = MLQuestSystem.GetContext( pm ); + + if ( context == null ) + return 0; + + int result = 0; + + foreach ( Type type in Needed ) + { + MLQuest quest = MLQuestSystem.FindQuest( type ); + + if ( quest == null || context.HasDoneQuest( quest ) ) + ++result; + } + + return result; + } + + public bool CheckComplete( PlayerMobile pm ) + { + if ( CompletedCount( pm ) == Needed.Length ) + return true; + + pm.SendLocalizedMessage( 1073644 ); // You must complete all the tasks before proceeding... + return false; + } + + public void ConsumeNeeded( PlayerMobile pm ) + { + MLQuestContext context = MLQuestSystem.GetContext( pm ); + + if ( context != null ) + { + foreach ( Type type in Needed ) + { + MLQuest quest = MLQuestSystem.FindQuest( type ); + + if ( quest != null ) + context.RemoveDoneQuest( quest ); + } + } + } + + public void OnCancel( PlayerMobile pm ) + { + pm.SendLocalizedMessage( 1073645 ); // You may try this again later... + } + + public virtual void OnComplete( PlayerMobile pm ) + { + } + + public DoneQuestCollector( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private DoneQuestCollector m_Owner; + private PlayerMobile m_Target; + private IList m_Conversation; + private bool m_IsComplete; + private int m_Index; + + private static TimeSpan GetDelay() + { + return TimeSpan.FromSeconds( Utility.RandomBool() ? 3 : 4 ); + } + + public InternalTimer( DoneQuestCollector owner, PlayerMobile target, IList conversation, bool isComplete ) + : base( TimeSpan.Zero, GetDelay() ) + { + m_Owner = owner; + m_Target = target; + m_Conversation = conversation; + m_IsComplete = isComplete; + m_Index = 0; + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + if ( m_Index >= m_Conversation.Count ) + { + if ( m_IsComplete ) + m_Owner.OnComplete( m_Target ); + + Stop(); + } + else + { + if ( m_Index == 0 ) + { + if ( m_Target.ShowFameTitle && m_Target.Fame >= 10000 ) + m_Owner.Say( true, String.Format( "{0} {1}", m_Target.Female ? "Lady" : "Lord", m_Target.Name ) ); + else + m_Owner.Say( true, m_Target.Name ); + } + + TextDefinition.PublicOverheadMessage( m_Owner, MessageType.Regular, 0x3B2, m_Conversation[m_Index++] ); + Interval = GetDelay(); + } + } + } + } + + public class Darius : DoneQuestCollector + { + private static readonly TextDefinition[] m_Offer = + { + 1073998, // Blessings of Sosaria to you and merry met, friend. + 1073999, // I am glad for your company and wonder if you seek the heritage of your people? I sense within you an elven bloodline -- the purity of which was lost when our brothers and sisters were exiled here in the Rupture. + 1074000, // If it is your desire to reclaim your place amongst the people, you must demonstrate that you understand and embrace the responsibilities expected of you as an elf. + 1074001, // The most basic lessons of our Sosaria are taught by her humblest children. Seek Maul, the great bear, who understands instictively the seasons. + 1074398, // Seek Strongroot, the great treefellow, whose very roots reach to the heart of the world. Seek Enigma, whose wisdom can only be conveyed in riddles and rhymes. Seek Bravehorn, the great hart, who exemplifies the fierce dedication of a protector of his people. + 1074399, // Seek the Huntsman, the centuar tasked with maintaining the balance. And lastly seek Arielle, the pixie, who has perhaps the most important lesson -- not to take yourself too seriously. + 1074400 // Or do none of these things. You must choose your own path in the world, and what use you'll make of your existence. + }; + + private static readonly TextDefinition[] m_Incomplete = + { + 1074002, // You have begun to walk the path of reclaiming your heritage, but you have not learned all the lessons before you. + 1074003 // You yet must perform these services: + }; + + private static readonly TextDefinition[] m_Complete = + { + 1074004, // You have carved a path in history, sought to understand the way from our sage companions. + 1074005, // And now you have returned full circle to the place of your origin within the arms of Mother Sosaria. There is but one thing left to do if you truly wish to embrace your elven heritage. + 1074006, // To be born once more an elf, you must strip of all worldly possessions. Nothing of man or beast much touch your skin. + 1074007 // Then you may step forth into history. + }; + + private static readonly Type[] m_Needed = + { + typeof( Seasons ), + typeof( CaretakerOfTheLand ), + typeof( WisdomOfTheSphynx ), + typeof( DefendingTheHerd ), + typeof( TheBalanceOfNature ), + typeof( TheJoysOfLife ) + }; + + public override TextDefinition[] Offer { get { return m_Offer; } } + public override TextDefinition[] Incomplete { get { return m_Incomplete; } } + public override TextDefinition[] Complete { get { return m_Complete; } } + public override Type[] Needed { get { return m_Needed; } } + + [Constructable] + public Darius() + { + Name = "Darius"; + Title = "the wise"; + Race = Race.Elf; + Hue = Race.RandomSkinHue(); + SpeechHue = Utility.RandomDyedHue(); + + AddItem( new WildStaff() ); + AddItem( new Sandals( 0x1BB ) ); + AddItem( new GemmedCirclet() ); + AddItem( new Tunic( Utility.RandomBrightHue() ) ); + + Utility.AssignRandomHair( this ); + + SetStr( 40, 50 ); + SetDex( 60, 70 ); + SetInt( 90, 100 ); // Verified int + } + + public override bool CanTalkTo( Mobile from ) + { + return ( from.Race == Race.Human ); + } + + public override void DenyTalk( Mobile from ) + { + from.SendLocalizedMessage( 1074017 ); // He's too busy right now, so he ignores you. + } + + public override void OnComplete( PlayerMobile from ) + { + from.SendGump( new RaceChangeConfirmGump( this, from, Race.Elf ) ); + } + + public Darius( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Nedrick : DoneQuestCollector + { + private static readonly TextDefinition[] m_Offer = + { + 1074403, // Greetings, traveler and welcome. + 1074404, // Perhaps you have heard of the service I offer? Perhaps you wish to avail yourself of the opportunity I lay before you. + 1074405, // Elves and humans; we lived together once in peace. Mighty relics that attest to our friendship remain, of course. Yet, memories faded when the Gem was shattered and the world torn asunder. Alone in The Heartwood, our elven brothers and sisters wondered what terrible evil had befallen Sosaria. + 1074406, // Violent change marked the sundering of our ties. We are different -- elves and humans. And yet we are much alike. I can give an elf the chance to walk as a human upon Sosaria. I can undertake the transformation. + 1074407, // But you must prove yourself to me. Humans possess a strength of character and back. Humans are quick-witted and able to pick up a smattering of nearly any talent. Humans are tough both mentally and physically. And of course, humans defend their own -- sometimes with their own lives. + 1074408, // Seek Sledge the Versatile and learn about human ingenuity and creativity. Seek Patricus and demonstrate your integrity and strength. + 1074409, // Seek out a human in need and prove your worth as a defender of humanity. Seek Belulah in Nu'Jelm and heartily challenge the elements in a display of toughness to rival any human. + 1074411 // Or turn away and embrace your heritage. It matters not to me. + }; + + private static readonly TextDefinition[] m_Incomplete = + { + 1074412, // You have made a good start but have more yet to do. + 1074413 // You must yet perform these deeds: + }; + + private static readonly TextDefinition[] m_Complete = + { + 1074410, // You have proven yourself capable and commited and so I will grant you the transformation you seek. + 1074531, // The first time you were born, you entered the world bare of all possessions and concerns. So too as you transform to your new life as a human, you must remove all worldly goods from the touch of your flesh. + 1074532 // I call upon all nearby to witness your rebirth! + }; + + private static readonly Type[] m_Needed = + { + typeof( Ingenuity ), + typeof( HeaveHo ), + typeof( HumanInNeed ), + typeof( AllSeasonAdventurer ) + }; + + public override TextDefinition[] Offer { get { return m_Offer; } } + public override TextDefinition[] Incomplete { get { return m_Incomplete; } } + public override TextDefinition[] Complete { get { return m_Complete; } } + public override Type[] Needed { get { return m_Needed; } } + + [Constructable] + public Nedrick() + { + Name = "Nedrick"; + Title = "the iron worker"; + Race = Race.Human; + Hue = Race.RandomSkinHue(); + SpeechHue = Utility.RandomDyedHue(); + + AddItem( new Boots() ); + AddItem( new LongPants( Utility.RandomNondyedHue() ) ); + AddItem( new FancyShirt( Utility.RandomNondyedHue() ) ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + + SetStr( 70, 80 ); + SetDex( 50, 60 ); + SetInt( 60, 70 ); // Verified int + } + + public override bool CanTalkTo( Mobile from ) + { + return ( from.Race == Race.Elf ); + } + + public override void DenyTalk( Mobile from ) + { + from.SendLocalizedMessage( 1074017 ); // He's too busy right now, so he ignores you. + } + + public override void OnComplete( PlayerMobile from ) + { + from.SendGump( new RaceChangeConfirmGump( this, from, Race.Human ) ); + } + + public Nedrick( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs b/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs new file mode 100644 index 0000000..028ad9e --- /dev/null +++ b/Scripts/Engines/MLQuests/Mobiles/SirHelper.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Engines.MLQuests.Gumps; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.MLQuests.Mobiles +{ + public class SirHelper : Mage + { + private static readonly Gump m_Gump = new InfoNPCGump( 1078029, 1078028 ); + private static readonly TimeSpan m_ShoutDelay = TimeSpan.FromSeconds( 20 ); + private static readonly TimeSpan m_ShoutCooldown = TimeSpan.FromDays( 1 ); // TODO: Verify, could be a lot longer... or until a restart even + + private DateTime m_NextShout; + + public override bool IsActiveVendor { get { return false; } } + + [Constructable] + public SirHelper() + { + Name = "Sir Helper"; + Title = "the Profession Guide"; // TODO: Don't display in paperdoll + + Hue = 0x83EA; + + Direction = Direction.South; + Frozen = true; + } + + public override void InitSBInfo() + { + } + + public override bool GetGender() + { + return false; // male + } + + public override void CheckMorph() + { + } + + public override void InitOutfit() + { + HairItemID = 0x203C; + FacialHairItemID = 0x204D; + HairHue = FacialHairHue = 0x8A7; + + AddItem( new Sandals() ); + + Item item; + + item = new Cloak(); + item.ItemID = 0x26AD; + item.Hue = 0x455; + AddItem( item ); + + item = new Robe(); + item.ItemID = 0x26AE; + item.Hue = 0x4AB; + AddItem( item ); + + item = new Backpack(); + item.Movable = false; + AddItem( item ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.CanBeginAction( this ) ) + { + from.BeginAction( this ); + Timer.DelayCall( m_ShoutCooldown, EndLock, from ); + } + + MLQuestSystem.TurnToFace( this, from ); + from.SendGump( m_Gump ); + + // Paperdoll doesn't open + //base.OnDoubleClick( from ); + } + + public override void OnThink() + { + base.OnThink(); + + if ( m_NextShout <= DateTime.Now ) + { + Packet shoutPacket = null; + + foreach ( NetState state in GetClientsInRange( 12 ) ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InLOS( this ) && m.CanBeginAction( this ) ) + { + if ( shoutPacket == null ) + shoutPacket = Packet.Acquire( new MessageLocalized( Serial, Body, MessageType.Regular, 946, 3, 1078099, Name, "" ) ); // Double Click On Me For Help! + + state.Send( shoutPacket ); + } + } + + Packet.Release( shoutPacket ); + + m_NextShout = DateTime.Now + m_ShoutDelay; + } + } + + private void EndLock( Mobile m ) + { + m.EndAction( this ); + } + + public SirHelper( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Frozen = true; + } + } +} diff --git a/Scripts/Engines/MLQuests/Objectives/BaseObjective.cs b/Scripts/Engines/MLQuests/Objectives/BaseObjective.cs new file mode 100644 index 0000000..99ec75f --- /dev/null +++ b/Scripts/Engines/MLQuests/Objectives/BaseObjective.cs @@ -0,0 +1,214 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Mobiles; +using Server.Gumps; +using System.Collections.Generic; + +namespace Server.Engines.MLQuests.Objectives +{ + public abstract class BaseObjective + { + public virtual bool IsTimed { get { return false; } } + public virtual TimeSpan Duration { get { return TimeSpan.Zero; } } + + public BaseObjective() + { + } + + public virtual bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) + { + return true; + } + + public abstract void WriteToGump( Gump g, ref int y ); + + public virtual BaseObjectiveInstance CreateInstance( MLQuestInstance instance ) + { + return null; + } + } + + public abstract class BaseObjectiveInstance + { + private MLQuestInstance m_Instance; + private DateTime m_EndTime; + private bool m_Expired; + + public MLQuestInstance Instance + { + get { return m_Instance; } + } + + public bool IsTimed + { + get { return ( m_EndTime != DateTime.MinValue ); } + } + + public DateTime EndTime + { + get { return m_EndTime; } + set { m_EndTime = value; } + } + + public bool Expired + { + get { return m_Expired; } + set { m_Expired = value; } + } + + public BaseObjectiveInstance( MLQuestInstance instance, BaseObjective obj ) + { + m_Instance = instance; + + if ( obj.IsTimed ) + m_EndTime = DateTime.Now + obj.Duration; + } + + public virtual void WriteToGump( Gump g, ref int y ) + { + if ( IsTimed ) + WriteTimeRemaining( g, ref y, ( m_EndTime > DateTime.Now ) ? ( m_EndTime - DateTime.Now ) : TimeSpan.Zero ); + } + + public static void WriteTimeRemaining( Gump g, ref int y, TimeSpan timeRemaining ) + { + g.AddHtmlLocalized( 103, y, 120, 16, 1062379, 0x15F90, false, false ); // Est. time remaining: + g.AddLabel( 223, y, 0x481, timeRemaining.TotalSeconds.ToString( "F0" ) ); + y += 16; + } + + public virtual bool AllowsQuestItem( Item item, Type type ) + { + return false; + } + + public virtual bool IsCompleted() + { + return false; + } + + public virtual void CheckComplete() + { + if ( IsCompleted() ) + { + m_Instance.Player.PlaySound( 0x5B6 ); // public sound + m_Instance.CheckComplete(); + } + } + + public virtual void OnQuestAccepted() + { + } + + public virtual void OnQuestCancelled() + { + } + + public virtual void OnQuestCompleted() + { + } + + public virtual bool OnBeforeClaimReward() + { + return true; + } + + public virtual void OnClaimReward() + { + } + + public virtual void OnAfterClaimReward() + { + } + + public virtual void OnRewardClaimed() + { + } + + public virtual void OnQuesterDeleted() + { + } + + public virtual void OnPlayerDeath() + { + } + + public virtual void OnExpire() + { + } + + public enum DataType : byte + { + None, + EscortObjective, + KillObjective, + DeliverObjective + } + + public virtual DataType ExtraDataType { get { return DataType.None; } } + + public virtual void Serialize( GenericWriter writer ) + { + // Version info is written in MLQuestPersistence.Serialize + + if ( IsTimed ) + { + writer.Write( true ); + writer.WriteDeltaTime( m_EndTime ); + } + else + { + writer.Write( false ); + } + + // For type checks on deserialization + // (This way quest objectives can be changed without breaking serialization) + writer.Write( (byte)ExtraDataType ); + } + + public static void Deserialize( GenericReader reader, int version, BaseObjectiveInstance objInstance ) + { + if ( reader.ReadBool() ) + { + DateTime endTime = reader.ReadDeltaTime(); + + if ( objInstance != null ) + objInstance.EndTime = endTime; + } + + DataType extraDataType = (DataType)reader.ReadByte(); + + switch ( extraDataType ) + { + case DataType.EscortObjective: + { + bool completed = reader.ReadBool(); + + if ( objInstance is EscortObjectiveInstance ) + ( (EscortObjectiveInstance)objInstance ).HasCompleted = completed; + + break; + } + case DataType.KillObjective: + { + int slain = reader.ReadInt(); + + if ( objInstance is KillObjectiveInstance ) + ( (KillObjectiveInstance)objInstance ).Slain = slain; + + break; + } + case DataType.DeliverObjective: + { + bool completed = reader.ReadBool(); + + if ( objInstance is DeliverObjectiveInstance ) + ( (DeliverObjectiveInstance)objInstance ).HasCompleted = completed; + + break; + } + } + } + } +} diff --git a/Scripts/Engines/MLQuests/Objectives/CollectObjective.cs b/Scripts/Engines/MLQuests/Objectives/CollectObjective.cs new file mode 100644 index 0000000..c8a9889 --- /dev/null +++ b/Scripts/Engines/MLQuests/Objectives/CollectObjective.cs @@ -0,0 +1,259 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.MLQuests.Objectives +{ + public class CollectObjective : BaseObjective + { + private int m_DesiredAmount; + private Type m_AcceptedType; + private TextDefinition m_Name; + + public int DesiredAmount + { + get { return m_DesiredAmount; } + set { m_DesiredAmount = value; } + } + + public Type AcceptedType + { + get { return m_AcceptedType; } + set { m_AcceptedType = value; } + } + + public TextDefinition Name + { + get { return m_Name; } + set { m_Name = value; } + } + + public virtual bool ShowDetailed + { + get { return true; } + } + + public CollectObjective() + : this( 0, null, null ) + { + } + + public CollectObjective( int amount, Type type, TextDefinition name ) + { + m_DesiredAmount = amount; + m_AcceptedType = type; + m_Name = name; + + if ( MLQuestSystem.Debug && ShowDetailed && name.Number > 0 ) + { + int itemid = LabelToItemID( name.Number ); + + if ( itemid <= 0 || itemid > 0x4000 ) + Console.WriteLine( "Warning: cliloc {0} is likely giving the wrong item ID", name.Number ); + } + } + + public bool CheckType( Type type ) + { + return ( m_AcceptedType != null && m_AcceptedType.IsAssignableFrom( type ) ); + } + + public virtual bool CheckItem( Item item ) + { + return true; + } + + public static int LabelToItemID( int label ) + { + if ( label < 1078872 ) + return ( label - 1020000 ); + else + return ( label - 1078872 ); + } + + public override void WriteToGump( Gump g, ref int y ) + { + if ( ShowDetailed ) + { + string amount = m_DesiredAmount.ToString(); + + g.AddHtmlLocalized( 98, y, 350, 16, 1072205, 0x15F90, false, false ); // Obtain + g.AddLabel( 143, y, 0x481, amount ); + + if ( m_Name.Number > 0 ) + { + g.AddHtmlLocalized( 143 + amount.Length * 15, y, 190, 18, m_Name.Number, 0x77BF, false, false ); + g.AddItem( 350, y, LabelToItemID( m_Name.Number ) ); + } + else if ( m_Name.String != null ) + { + g.AddLabel( 143 + amount.Length * 15, y, 0x481, m_Name.String ); + } + } + else + { + if ( m_Name.Number > 0 ) + g.AddHtmlLocalized( 98, y, 312, 32, m_Name.Number, 0x15F90, false, false ); + else if ( m_Name.String != null ) + g.AddLabel( 98, y, 0x481, m_Name.String ); + } + + y += 32; + } + + public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance ) + { + return new CollectObjectiveInstance( this, instance ); + } + } + + #region Timed + + public class TimedCollectObjective : CollectObjective + { + private TimeSpan m_Duration; + + public override bool IsTimed { get { return true; } } + public override TimeSpan Duration { get { return m_Duration; } } + + public TimedCollectObjective( TimeSpan duration, int amount, Type type, TextDefinition name ) + : base( amount, type, name ) + { + m_Duration = duration; + } + } + + #endregion + + public class CollectObjectiveInstance : BaseObjectiveInstance + { + private CollectObjective m_Objective; + + public CollectObjective Objective + { + get { return m_Objective; } + set { m_Objective = value; } + } + + public CollectObjectiveInstance( CollectObjective objective, MLQuestInstance instance ) + : base( instance, objective ) + { + m_Objective = objective; + } + + private int GetCurrentTotal() + { + Container pack = Instance.Player.Backpack; + + if ( pack == null ) + return 0; + + Item[] items = pack.FindItemsByType( m_Objective.AcceptedType, false ); // Note: subclasses are included + int total = 0; + + foreach ( Item item in items ) + { + if ( item.QuestItem && m_Objective.CheckItem( item ) ) + total += item.Amount; + } + + return total; + } + + public override bool AllowsQuestItem( Item item, Type type ) + { + return ( m_Objective.CheckType( type ) && m_Objective.CheckItem( item ) ); + } + + public override bool IsCompleted() + { + return ( GetCurrentTotal() >= m_Objective.DesiredAmount ); + } + + public override void OnQuestCancelled() + { + PlayerMobile pm = Instance.Player; + Container pack = pm.Backpack; + + if ( pack == null ) + return; + + Type checkType = m_Objective.AcceptedType; + Item[] items = pack.FindItemsByType( checkType, false ); + + foreach ( Item item in items ) + { + if ( item.QuestItem && !MLQuestSystem.CanMarkQuestItem( pm, item, checkType ) ) // does another quest still need this item? (OSI just unmarks everything) + item.QuestItem = false; + } + } + + // Should only be called after IsComplete() is checked to be true + public override void OnClaimReward() + { + Container pack = Instance.Player.Backpack; + + if ( pack == null ) + return; + + // TODO: OSI also counts the item in the cursor? + + Item[] items = pack.FindItemsByType( m_Objective.AcceptedType, false ); + int left = m_Objective.DesiredAmount; + + foreach ( Item item in items ) + { + if ( item.QuestItem && m_Objective.CheckItem( item ) ) + { + if ( left == 0 ) + return; + + if ( item.Amount > left ) + { + item.Consume( left ); + left = 0; + } + else + { + item.Delete(); + left -= item.Amount; + } + } + } + } + + public override void OnAfterClaimReward() + { + OnQuestCancelled(); // same thing, clear other quest items + } + + public override void OnExpire() + { + OnQuestCancelled(); + + // No message + } + + public override void WriteToGump( Gump g, ref int y ) + { + m_Objective.WriteToGump( g, ref y ); + y -= 16; + + if ( m_Objective.ShowDetailed ) + { + base.WriteToGump( g, ref y ); + + g.AddHtmlLocalized( 103, y, 120, 16, 3000087, 0x15F90, false, false ); // Total + g.AddLabel( 223, y, 0x481, GetCurrentTotal().ToString() ); + y += 16; + + g.AddHtmlLocalized( 103, y, 120, 16, 1074782, 0x15F90, false, false ); // Return to + g.AddLabel( 223, y, 0x481, QuesterNameAttribute.GetQuesterNameFor( Instance.QuesterType ) ); + y += 16; + } + } + } +} diff --git a/Scripts/Engines/MLQuests/Objectives/DeliverObjective.cs b/Scripts/Engines/MLQuests/Objectives/DeliverObjective.cs new file mode 100644 index 0000000..5ce185e --- /dev/null +++ b/Scripts/Engines/MLQuests/Objectives/DeliverObjective.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Objectives +{ + public class DeliverObjective : BaseObjective + { + private Type m_Delivery; + private int m_Amount; + private TextDefinition m_Name; + private Type m_Destination; + private bool m_SpawnsDelivery; + + public Type Delivery + { + get { return m_Delivery; } + set { m_Delivery = value; } + } + + public int Amount + { + get { return m_Amount; } + set { m_Amount = value; } + } + + public TextDefinition Name + { + get { return m_Name; } + set { m_Name = value; } + } + + public Type Destination + { + get { return m_Destination; } + set { m_Destination = value; } + } + + public bool SpawnsDelivery + { + get { return m_SpawnsDelivery; } + set { m_SpawnsDelivery = value; } + } + + public DeliverObjective( Type delivery, int amount, TextDefinition name, Type destination ) + : this( delivery, amount, name, destination, true ) + { + } + + public DeliverObjective( Type delivery, int amount, TextDefinition name, Type destination, bool spawnsDelivery ) + { + m_Delivery = delivery; + m_Amount = amount; + m_Name = name; + m_Destination = destination; + m_SpawnsDelivery = spawnsDelivery; + + if ( MLQuestSystem.Debug && name.Number > 0 ) + { + int itemid = CollectObjective.LabelToItemID( name.Number ); + + if ( itemid <= 0 || itemid > 0x4000 ) + Console.WriteLine( "Warning: cliloc {0} is likely giving the wrong item ID", name.Number ); + } + } + + public virtual void SpawnDelivery( Container pack ) + { + if ( !m_SpawnsDelivery || pack == null ) + return; + + List delivery = new List(); + + for ( int i = 0; i < m_Amount; ++i ) + { + Item item = Activator.CreateInstance( m_Delivery ) as Item; + + if ( item == null ) + continue; + + delivery.Add( item ); + + if ( item.Stackable && m_Amount > 1 ) + { + item.Amount = m_Amount; + break; + } + } + + foreach ( Item item in delivery ) + pack.DropItem( item ); // Confirmed: on OSI items are added even if your pack is full + } + + public override void WriteToGump( Gump g, ref int y ) + { + string amount = m_Amount.ToString(); + + g.AddHtmlLocalized( 98, y, 312, 16, 1072207, 0x15F90, false, false ); // Deliver + g.AddLabel( 143, y, 0x481, amount ); + + if ( m_Name.Number > 0 ) + { + g.AddHtmlLocalized( 143 + amount.Length * 15, y, 190, 18, m_Name.Number, 0x77BF, false, false ); + g.AddItem( 350, y, CollectObjective.LabelToItemID( m_Name.Number ) ); + } + else if ( m_Name.String != null ) + { + g.AddLabel( 143 + amount.Length * 15, y, 0x481, m_Name.String ); + } + + y += 32; + + g.AddHtmlLocalized( 103, y, 120, 16, 1072379, 0x15F90, false, false ); // Deliver to + g.AddLabel( 223, y, 0x481, QuesterNameAttribute.GetQuesterNameFor( m_Destination ) ); + + y += 16; + } + + public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance ) + { + return new DeliverObjectiveInstance( this, instance ); + } + } + + #region Timed + + public class TimedDeliverObjective : DeliverObjective + { + private TimeSpan m_Duration; + + public override bool IsTimed { get { return true; } } + public override TimeSpan Duration { get { return m_Duration; } } + + public TimedDeliverObjective( TimeSpan duration, Type delivery, int amount, TextDefinition name, Type destination ) + : this( duration, delivery, amount, name, destination, true ) + { + } + + public TimedDeliverObjective( TimeSpan duration, Type delivery, int amount, TextDefinition name, Type destination, bool spawnsDelivery ) + : base( delivery, amount, name, destination, spawnsDelivery ) + { + m_Duration = duration; + } + } + + #endregion + + public class DeliverObjectiveInstance : BaseObjectiveInstance + { + private DeliverObjective m_Objective; + private bool m_HasCompleted; + + public DeliverObjective Objective + { + get { return m_Objective; } + set { m_Objective = value; } + } + + public bool HasCompleted + { + get { return m_HasCompleted; } + set { m_HasCompleted = value; } + } + + public DeliverObjectiveInstance( DeliverObjective objective, MLQuestInstance instance ) + : base( instance, objective ) + { + m_Objective = objective; + } + + public virtual bool IsDestination( IQuestGiver quester, Type type ) + { + Type destType = m_Objective.Destination; + + return ( destType != null && destType.IsAssignableFrom( type ) ); + } + + public override bool IsCompleted() + { + return m_HasCompleted; + } + + public override void OnQuestAccepted() + { + m_Objective.SpawnDelivery( Instance.Player.Backpack ); + } + + // This is VERY similar to CollectObjective.GetCurrentTotal + private int GetCurrentTotal() + { + Container pack = Instance.Player.Backpack; + + if ( pack == null ) + return 0; + + Item[] items = pack.FindItemsByType( m_Objective.Delivery, false ); // Note: subclasses are included + int total = 0; + + foreach ( Item item in items ) + total += item.Amount; + + return total; + } + + public override bool OnBeforeClaimReward() + { + PlayerMobile pm = Instance.Player; + + int total = GetCurrentTotal(); + int desired = m_Objective.Amount; + + if ( total < desired ) + { + pm.SendLocalizedMessage( 1074861 ); // You do not have everything you need! + pm.SendLocalizedMessage( 1074885, String.Format( "{0}\t{1}", total, desired ) ); // You have ~1_val~ item(s) but require ~2_val~ + return false; + } + + return true; + } + + // TODO: This is VERY similar to CollectObjective.OnClaimReward + public override void OnClaimReward() + { + Container pack = Instance.Player.Backpack; + + if ( pack == null ) + return; + + Item[] items = pack.FindItemsByType( m_Objective.Delivery, false ); + int left = m_Objective.Amount; + + foreach ( Item item in items ) + { + if ( left == 0 ) + break; + + if ( item.Amount > left ) + { + item.Consume( left ); + left = 0; + } + else + { + item.Delete(); + left -= item.Amount; + } + } + } + + public override void OnQuestCancelled() + { + OnClaimReward(); // same effect + } + + public override void OnExpire() + { + OnQuestCancelled(); + + Instance.Player.SendLocalizedMessage( 1074813 ); // You have failed to complete your delivery. + } + + public override void WriteToGump( Gump g, ref int y ) + { + m_Objective.WriteToGump( g, ref y ); + + base.WriteToGump( g, ref y ); + + // No extra instance stuff printed for this objective + } + + public override DataType ExtraDataType { get { return DataType.DeliverObjective; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( m_HasCompleted ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs b/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs new file mode 100644 index 0000000..484a767 --- /dev/null +++ b/Scripts/Engines/MLQuests/Objectives/EscortObjective.cs @@ -0,0 +1,286 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Mobiles; +using Server.Gumps; +using System.Collections.Generic; +using Server.Misc; +using Server.Items; + +namespace Server.Engines.MLQuests.Objectives +{ + public class EscortObjective : BaseObjective + { + private QuestArea m_Destination; + + public QuestArea Destination + { + get { return m_Destination; } + set { m_Destination = value; } + } + + public EscortObjective() + : this( null ) + { + } + + public EscortObjective( QuestArea destination ) + { + m_Destination = destination; + } + + public override bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) + { + if ( ( quester is BaseCreature && ( (BaseCreature)quester ).Controlled ) || ( quester is BaseEscortable && ( (BaseEscortable)quester ).IsBeingDeleted ) ) + return false; + + MLQuestContext context = MLQuestSystem.GetContext( pm ); + + if ( context != null ) + { + foreach ( MLQuestInstance instance in context.QuestInstances ) + { + if ( instance.Quest.IsEscort ) + { + if ( message ) + MLQuestSystem.Tell( quester, pm, 500896 ); // I see you already have an escort. + + return false; + } + } + } + + DateTime nextEscort = pm.LastEscortTime + BaseEscortable.EscortDelay; + + if ( nextEscort > DateTime.Now ) + { + if ( message ) + { + int minutes = (int)Math.Ceiling( ( nextEscort - DateTime.Now ).TotalMinutes ); + + if ( minutes == 1 ) + MLQuestSystem.Tell( quester, pm, "You must rest 1 minute before we set out on this journey." ); + else + MLQuestSystem.Tell( quester, pm, 1071195, minutes.ToString() ); // You must rest ~1_minsleft~ minutes before we set out on this journey. + } + + return false; + } + + return true; + } + + public override void WriteToGump( Gump g, ref int y ) + { + g.AddHtmlLocalized( 98, y, 312, 16, 1072206, 0x15F90, false, false ); // Escort to + + if ( m_Destination.Name.Number > 0 ) + g.AddHtmlLocalized( 173, y, 312, 20, m_Destination.Name.Number, 0xFFFFFF, false, false ); + else if ( m_Destination.Name.String != null ) + g.AddLabel( 173, y, 0x481, m_Destination.Name.String ); + + y += 16; + } + + public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance ) + { + if ( instance == null || m_Destination == null ) + return null; + + return new EscortObjectiveInstance( this, instance ); + } + } + + public class EscortObjectiveInstance : BaseObjectiveInstance + { + private EscortObjective m_Objective; + private bool m_HasCompleted; + private Timer m_Timer; + private DateTime m_LastSeenEscorter; + private BaseCreature m_Escort; + + public bool HasCompleted + { + get { return m_HasCompleted; } + set { m_HasCompleted = value; } + } + + public EscortObjectiveInstance( EscortObjective objective, MLQuestInstance instance ) + : base( instance, objective ) + { + m_Objective = objective; + m_HasCompleted = false; + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), new TimerCallback( CheckDestination ) ); + m_LastSeenEscorter = DateTime.Now; + m_Escort = instance.Quester as BaseCreature; + + if ( MLQuestSystem.Debug && m_Escort == null && instance.Quester != null ) + Console.WriteLine( "Warning: EscortObjective is not supported for type '{0}'", instance.Quester.GetType().Name ); + } + + public override bool IsCompleted() + { + return m_HasCompleted; + } + + private void CheckDestination() + { + if ( m_Escort == null || m_HasCompleted ) // Completed by deserialization + { + StopTimer(); + return; + } + + MLQuestInstance instance = Instance; + PlayerMobile pm = instance.Player; + + if ( instance.Removed ) + { + Abandon(); + } + else if ( m_Objective.Destination.Contains( m_Escort ) ) + { + m_Escort.Say( 1042809, pm.Name ); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay. + + if ( pm.Young || m_Escort.Region.IsPartOf( "Haven Island" ) ) + Titles.AwardFame( pm, 10, true ); + else + VirtueHelper.AwardVirtue( pm, VirtueName.Compassion, ( m_Escort is BaseEscortable && ( (BaseEscortable)m_Escort ).IsPrisoner ) ? 400 : 200 ); + + EndFollow( m_Escort ); + StopTimer(); + + m_HasCompleted = true; + CheckComplete(); + + // Auto claim reward + MLQuestSystem.OnDoubleClick( m_Escort, pm ); + } + else if ( pm.Map != m_Escort.Map || !pm.InRange( m_Escort, 30 ) ) // TODO: verify range + { + if ( m_LastSeenEscorter + BaseEscortable.AbandonDelay <= DateTime.Now ) + Abandon(); + } + else + { + m_LastSeenEscorter = DateTime.Now; + } + } + + private void StopTimer() + { + if ( m_Timer != null ) + { + m_Timer.Stop(); + m_Timer = null; + } + } + + public static void BeginFollow( BaseCreature quester, PlayerMobile pm ) + { + quester.ControlSlots = 0; + quester.SetControlMaster( pm ); + + quester.ActiveSpeed = 0.1; + quester.PassiveSpeed = 0.2; + + quester.ControlOrder = OrderType.Follow; + quester.ControlTarget = pm; + + quester.CantWalk = false; + quester.CurrentSpeed = 0.1; + } + + public static void EndFollow( BaseCreature quester ) + { + quester.ActiveSpeed = 0.2; + quester.PassiveSpeed = 1.0; + + quester.ControlOrder = OrderType.None; + quester.ControlTarget = null; + + quester.CurrentSpeed = 1.0; + + quester.SetControlMaster( null ); + + if ( quester is BaseEscortable ) + ( (BaseEscortable)quester ).BeginDelete(); + } + + public override void OnQuestAccepted() + { + MLQuestInstance instance = Instance; + PlayerMobile pm = instance.Player; + + pm.LastEscortTime = DateTime.Now; + + if ( m_Escort != null ) + BeginFollow( m_Escort, pm ); + } + + public void Abandon() + { + StopTimer(); + + MLQuestInstance instance = Instance; + PlayerMobile pm = instance.Player; + + if ( m_Escort != null && !m_Escort.Deleted ) + { + if ( !pm.Alive ) + m_Escort.Say( 500901 ); // Ack! My escort has come to haunt me! + else + m_Escort.Say( 500902 ); // My escort seems to have abandoned me! + + EndFollow( m_Escort ); + } + + // Note: this sound is sent twice on OSI (once here and once in Cancel()) + //m_Player.SendSound( 0x5B3 ); // private sound + pm.SendLocalizedMessage( 1071194 ); // You have failed your escort quest... + + if ( !instance.Removed ) + instance.Cancel(); + } + + public override void OnQuesterDeleted() + { + if ( IsCompleted() || Instance.Removed ) + return; + + Abandon(); + } + + public override void OnPlayerDeath() + { + // Note: OSI also cancels it when the quest is already complete + if ( /*IsCompleted() ||*/ Instance.Removed ) + return; + + Instance.Cancel(); + } + + public override void OnExpire() + { + Abandon(); + } + + public override void WriteToGump( Gump g, ref int y ) + { + m_Objective.WriteToGump( g, ref y ); + + base.WriteToGump( g, ref y ); + + // No extra instance stuff printed for this objective + } + + public override DataType ExtraDataType { get { return DataType.EscortObjective; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( m_HasCompleted ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Objectives/GainSkillObjective.cs b/Scripts/Engines/MLQuests/Objectives/GainSkillObjective.cs new file mode 100644 index 0000000..20a2cb0 --- /dev/null +++ b/Scripts/Engines/MLQuests/Objectives/GainSkillObjective.cs @@ -0,0 +1,190 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Engines.MLQuests.Objectives +{ + public enum GainSkillObjectiveFlags : byte + { + None = 0x00, + UseReal = 0x01, + Accelerate = 0x02 + } + + public class GainSkillObjective : BaseObjective + { + private SkillName m_Skill; + private int m_ThresholdFixed; + private GainSkillObjectiveFlags m_Flags; + + public SkillName Skill + { + get { return m_Skill; } + set { m_Skill = value; } + } + + public int ThresholdFixed + { + get { return m_ThresholdFixed; } + set { m_ThresholdFixed = value; } + } + + public bool UseReal + { + get { return GetFlag( GainSkillObjectiveFlags.UseReal ); } + set { SetFlag( GainSkillObjectiveFlags.UseReal, value ); } + } + + public bool Accelerate + { + get { return GetFlag( GainSkillObjectiveFlags.Accelerate ); } + set { SetFlag( GainSkillObjectiveFlags.Accelerate, value ); } + } + + public GainSkillObjective() + : this( SkillName.Alchemy, 0 ) + { + } + + public GainSkillObjective( SkillName skill, int thresholdFixed ) + : this( skill, thresholdFixed, false, false ) + { + } + + public GainSkillObjective( SkillName skill, int thresholdFixed, bool useReal, bool accelerate ) + { + m_Skill = skill; + m_ThresholdFixed = thresholdFixed; + m_Flags = GainSkillObjectiveFlags.None; + + if ( useReal ) + m_Flags |= GainSkillObjectiveFlags.UseReal; + + if ( accelerate ) + m_Flags |= GainSkillObjectiveFlags.Accelerate; + } + + public override bool CanOffer( IQuestGiver quester, PlayerMobile pm, bool message ) + { + Skill skill = pm.Skills[m_Skill]; + + if ( ( UseReal ? skill.Fixed : skill.BaseFixedPoint ) >= m_ThresholdFixed ) + { + if ( message ) + MLQuestSystem.Tell( quester, pm, 1077772 ); // I cannot teach you, for you know all I can teach! + + return false; + } + + return true; + } + + public override void WriteToGump( Gump g, ref int y ) + { + int skillLabel = AosSkillBonuses.GetLabel( m_Skill ); + string args; + + if ( m_ThresholdFixed % 10 == 0 ) + args = String.Format( "#{0}\t{1}", skillLabel, m_ThresholdFixed / 10 ); // as seen on OSI + else + args = String.Format( "#{0}\t{1:0.0}", skillLabel, (double)m_ThresholdFixed / 10 ); // for non-integer skill levels + + g.AddHtmlLocalized( 98, y, 312, 16, 1077485, args, 0x15F90, false, false ); // Increase ~1_SKILL~ to ~2_VALUE~ + y += 16; + } + + public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance ) + { + return new GainSkillObjectiveInstance( this, instance ); + } + + private bool GetFlag( GainSkillObjectiveFlags flag ) + { + return ( ( m_Flags & flag ) != 0 ); + } + + private void SetFlag( GainSkillObjectiveFlags flag, bool value ) + { + if ( value ) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + } + + // On OSI, once this is complete, it will *stay* complete, even if you lower your skill again + public class GainSkillObjectiveInstance : BaseObjectiveInstance + { + private GainSkillObjective m_Objective; + + public GainSkillObjective Objective + { + get { return m_Objective; } + set { m_Objective = value; } + } + + public GainSkillObjectiveInstance( GainSkillObjective objective, MLQuestInstance instance ) + : base( instance, objective ) + { + m_Objective = objective; + } + + public bool Handles( SkillName skill ) + { + return ( m_Objective.Skill == skill ); + } + + public override bool IsCompleted() + { + PlayerMobile pm = Instance.Player; + + int valueFixed = m_Objective.UseReal ? pm.Skills[m_Objective.Skill].Fixed : pm.Skills[m_Objective.Skill].BaseFixedPoint; + + return ( valueFixed >= m_Objective.ThresholdFixed ); + } + + // TODO: This may interfere with scrolls, or even quests among each other + // How does OSI deal with this? + public override void OnQuestAccepted() + { + if ( !m_Objective.Accelerate ) + return; + + PlayerMobile pm = Instance.Player; + + pm.AcceleratedSkill = m_Objective.Skill; + pm.AcceleratedStart = DateTime.Now + TimeSpan.FromMinutes( 15 ); // TODO: Is there a max duration? + } + + public override void OnQuestCancelled() + { + if ( !m_Objective.Accelerate ) + return; + + PlayerMobile pm = Instance.Player; + + pm.AcceleratedStart = DateTime.Now; + pm.PlaySound( 0x100 ); + } + + public override void OnQuestCompleted() + { + OnQuestCancelled(); + } + + public override void WriteToGump( Gump g, ref int y ) + { + m_Objective.WriteToGump( g, ref y ); + + base.WriteToGump( g, ref y ); + + if ( IsCompleted() ) + { + g.AddHtmlLocalized( 113, y, 312, 20, 1055121, 0xFFFFFF, false, false ); // Complete + y += 16; + } + } + } +} diff --git a/Scripts/Engines/MLQuests/Objectives/KillObjective.cs b/Scripts/Engines/MLQuests/Objectives/KillObjective.cs new file mode 100644 index 0000000..c25a89b --- /dev/null +++ b/Scripts/Engines/MLQuests/Objectives/KillObjective.cs @@ -0,0 +1,194 @@ +using System; +using Server; +using Server.Engines.MLQuests; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Engines.MLQuests.Objectives +{ + public class KillObjective : BaseObjective + { + private int m_DesiredAmount; + private Type[] m_AcceptedTypes; // Example of Type[] requirement on OSI: killing X bone magis or skeletal mages (probably the same type on OSI though?) + private TextDefinition m_Name; + private QuestArea m_Area; + + public int DesiredAmount + { + get { return m_DesiredAmount; } + set { m_DesiredAmount = value; } + } + + public Type[] AcceptedTypes + { + get { return m_AcceptedTypes; } + set { m_AcceptedTypes = value; } + } + + public TextDefinition Name + { + get { return m_Name; } + set { m_Name = value; } + } + + public QuestArea Area + { + get { return m_Area; } + set { m_Area = value; } + } + + public KillObjective() + : this( 0, null, null, null ) + { + } + + public KillObjective( int amount, Type[] types, TextDefinition name ) + : this( amount, types, name, null ) + { + } + + public KillObjective( int amount, Type[] types, TextDefinition name, QuestArea area ) + { + m_DesiredAmount = amount; + m_AcceptedTypes = types; + m_Name = name; + m_Area = area; + } + + public override void WriteToGump( Gump g, ref int y ) + { + string amount = m_DesiredAmount.ToString(); + + g.AddHtmlLocalized( 98, y, 312, 16, 1072204, 0x15F90, false, false ); // Slay + g.AddLabel( 133, y, 0x481, amount ); + + if ( m_Name.Number > 0 ) + g.AddHtmlLocalized( 133 + amount.Length * 15, y, 190, 18, m_Name.Number, 0x77BF, false, false ); + else if ( m_Name.String != null ) + g.AddLabel( 133 + amount.Length * 15, y, 0x481, m_Name.String ); + + y += 16; + + #region Location + if ( m_Area != null ) + { + g.AddHtmlLocalized( 103, y, 312, 20, 1018327, 0x15F90, false, false ); // Location + + if ( m_Area.Name.Number > 0 ) + g.AddHtmlLocalized( 223, y, 312, 20, m_Area.Name.Number, 0xFFFFFF, false, false ); + else if ( m_Area.Name.String != null ) + g.AddLabel( 223, y, 0x481, m_Area.Name.String ); + + y += 16; + } + #endregion + } + + public override BaseObjectiveInstance CreateInstance( MLQuestInstance instance ) + { + return new KillObjectiveInstance( this, instance ); + } + } + + #region Timed + + public class TimedKillObjective : KillObjective + { + private TimeSpan m_Duration; + + public override bool IsTimed { get { return true; } } + public override TimeSpan Duration { get { return m_Duration; } } + + public TimedKillObjective( TimeSpan duration, int amount, Type[] types, TextDefinition name ) + : this( duration, amount, types, name, null ) + { + } + + public TimedKillObjective( TimeSpan duration, int amount, Type[] types, TextDefinition name, QuestArea area ) + : base( amount, types, name, area ) + { + m_Duration = duration; + } + } + + #endregion + + public class KillObjectiveInstance : BaseObjectiveInstance + { + private KillObjective m_Objective; + private int m_Slain; + + public KillObjective Objective + { + get { return m_Objective; } + set { m_Objective = value; } + } + + public int Slain + { + get { return m_Slain; } + set { m_Slain = value; } + } + + public KillObjectiveInstance( KillObjective objective, MLQuestInstance instance ) + : base( instance, objective ) + { + m_Objective = objective; + m_Slain = 0; + } + + public bool AddKill( Mobile mob, Type type ) + { + int desired = m_Objective.DesiredAmount; + + foreach ( Type acceptedType in m_Objective.AcceptedTypes ) + { + if ( acceptedType.IsAssignableFrom( type ) ) + { + if ( m_Objective.Area != null && !m_Objective.Area.Contains( mob ) ) + return false; + + PlayerMobile pm = Instance.Player; + + if ( ++m_Slain >= desired ) + pm.SendLocalizedMessage( 1075050 ); // You have killed all the required quest creatures of this type. + else + pm.SendLocalizedMessage( 1075051, ( desired - m_Slain ).ToString() ); // You have killed a quest creature. ~1_val~ more left. + + return true; + } + } + + return false; + } + + public override bool IsCompleted() + { + return ( m_Slain >= m_Objective.DesiredAmount ); + } + + public override void WriteToGump( Gump g, ref int y ) + { + m_Objective.WriteToGump( g, ref y ); + + base.WriteToGump( g, ref y ); + + g.AddHtmlLocalized( 103, y, 120, 16, 3000087, 0x15F90, false, false ); // Total + g.AddLabel( 223, y, 0x481, m_Slain.ToString() ); + y += 16; + + g.AddHtmlLocalized( 103, y, 120, 16, 1074782, 0x15F90, false, false ); // Return to + g.AddLabel( 223, y, 0x481, QuesterNameAttribute.GetQuesterNameFor( Instance.QuesterType ) ); + y += 16; + } + + public override DataType ExtraDataType { get { return DataType.KillObjective; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( m_Slain ); + } + } +} diff --git a/Scripts/Engines/MLQuests/QuestArea.cs b/Scripts/Engines/MLQuests/QuestArea.cs new file mode 100644 index 0000000..fa645fb --- /dev/null +++ b/Scripts/Engines/MLQuests/QuestArea.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Engines.MLQuests +{ + public class QuestArea + { + private TextDefinition m_Name; // So we can add custom names, different from the Region name + private string m_RegionName; + private Map m_ForceMap; + + public TextDefinition Name + { + get { return m_Name; } + set { m_Name = value; } + } + + public string RegionName + { + get { return m_RegionName; } + set { m_RegionName = value; } + } + + public Map ForceMap + { + get { return m_ForceMap; } + set { m_ForceMap = value; } + } + + public QuestArea( TextDefinition name, string region ) + : this( name, region, null ) + { + } + + public QuestArea( TextDefinition name, string region, Map forceMap ) + { + m_Name = name; + m_RegionName = region; + m_ForceMap = forceMap; + + if ( MLQuestSystem.Debug ) + ValidationQueue.Add( this ); + } + + public bool Contains( Mobile mob ) + { + return Contains( mob.Region ); + } + + public bool Contains( Region reg ) + { + if ( reg == null || ( m_ForceMap != null && reg.Map != m_ForceMap ) ) + return false; + + return reg.IsPartOf( m_RegionName ); + } + + // Debug method + public void Validate() + { + bool found = false; + + foreach ( Region r in Region.Regions ) + { + if ( r.Name == m_RegionName && ( m_ForceMap == null || r.Map == m_ForceMap ) ) + { + found = true; + break; + } + } + + if ( !found ) + Console.WriteLine( "Warning: QuestArea region '{0}' does not exist (ForceMap = {1})", m_RegionName, ( m_ForceMap == null ) ? "-null-" : m_ForceMap.ToString() ); + } + } +} diff --git a/Scripts/Engines/MLQuests/QuesterNameAttribute.cs b/Scripts/Engines/MLQuests/QuesterNameAttribute.cs new file mode 100644 index 0000000..ee4fc1a --- /dev/null +++ b/Scripts/Engines/MLQuests/QuesterNameAttribute.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Engines.MLQuests +{ + [AttributeUsage( AttributeTargets.Class )] + public class QuesterNameAttribute : Attribute + { + private string m_QuesterName; + + public string QuesterName { get { return m_QuesterName; } } + + public QuesterNameAttribute( string questerName ) + { + m_QuesterName = questerName; + } + + private static readonly Type m_Type = typeof( QuesterNameAttribute ); + private static readonly Dictionary m_Cache = new Dictionary(); + + public static string GetQuesterNameFor( Type t ) + { + if ( t == null ) + return ""; + + string result; + + if ( m_Cache.TryGetValue( t, out result ) ) + return result; + + object[] attributes = t.GetCustomAttributes( m_Type, false ); + + if ( attributes.Length != 0 ) + result = ( (QuesterNameAttribute)attributes[0] ).QuesterName; + else + result = t.Name; + + return ( m_Cache[t] = result ); + } + } +} diff --git a/Scripts/Engines/MLQuests/Rewards/BaseReward.cs b/Scripts/Engines/MLQuests/Rewards/BaseReward.cs new file mode 100644 index 0000000..da0cf4d --- /dev/null +++ b/Scripts/Engines/MLQuests/Rewards/BaseReward.cs @@ -0,0 +1,33 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using System.Collections.Generic; + +namespace Server.Engines.MLQuests.Rewards +{ + public abstract class BaseReward + { + private TextDefinition m_Name; + + public TextDefinition Name + { + get { return m_Name; } + set { m_Name = value; } + } + + public BaseReward( TextDefinition name ) + { + m_Name = name; + } + + protected virtual int LabelHeight { get { return 16; } } + + public void WriteToGump( Gump g, int x, ref int y ) + { + TextDefinition.AddHtmlText( g, x, y, 280, LabelHeight, m_Name, false, false, 0x15F90, 0xBDE784 ); + } + + public abstract void AddRewardItems( PlayerMobile pm, List rewards ); + } +} diff --git a/Scripts/Engines/MLQuests/Rewards/DummyReward.cs b/Scripts/Engines/MLQuests/Rewards/DummyReward.cs new file mode 100644 index 0000000..aa42cfa --- /dev/null +++ b/Scripts/Engines/MLQuests/Rewards/DummyReward.cs @@ -0,0 +1,22 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using System.Collections.Generic; + +namespace Server.Engines.MLQuests.Rewards +{ + public class DummyReward : BaseReward + { + public DummyReward( TextDefinition name ) + : base( name ) + { + } + + protected override int LabelHeight { get { return 180; } } + + public override void AddRewardItems( PlayerMobile pm, List rewards ) + { + } + } +} diff --git a/Scripts/Engines/MLQuests/Rewards/ItemReward.cs b/Scripts/Engines/MLQuests/Rewards/ItemReward.cs new file mode 100644 index 0000000..356e870 --- /dev/null +++ b/Scripts/Engines/MLQuests/Rewards/ItemReward.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Engines.MLQuests.Items; +using Server.Mobiles; + +namespace Server.Engines.MLQuests.Rewards +{ + public class ItemReward : BaseReward + { + public static readonly ItemReward SmallBagOfTrinkets = new ItemReward( 1072268, typeof( SmallBagOfTrinkets ) ); // A small bag of trinkets. + public static readonly ItemReward BagOfTrinkets = new ItemReward( 1072341, typeof( BagOfTrinkets ) ); // A bag of trinkets. + public static readonly ItemReward BagOfTreasure = new ItemReward( 1072583, typeof( BagOfTreasure ) ); // A bag of treasure. + public static readonly ItemReward LargeBagOfTreasure = new ItemReward( 1072706, typeof( LargeBagOfTreasure ) ); // A large bag of treasure. + public static readonly ItemReward Strongbox = new ItemReward( 1072584, typeof( RewardStrongbox ) ); // A strongbox. + + public static readonly ItemReward TailorSatchel = new ItemReward( 1074282, typeof( TailorSatchel ) ); // Craftsman's Satchel + public static readonly ItemReward BlacksmithSatchel = new ItemReward( 1074282, typeof( BlacksmithSatchel ) ); // Craftsman's Satchel + public static readonly ItemReward FletchingSatchel = new ItemReward( 1074282, typeof( FletchingSatchel ) ); // Craftsman's Satchel + public static readonly ItemReward CarpentrySatchel = new ItemReward( 1074282, typeof( CarpentrySatchel ) ); // Craftsman's Satchel + public static readonly ItemReward TinkerSatchel = new ItemReward( 1074282, typeof( TinkerSatchel ) ); // Craftsman's Satchel + + private Type m_Type; + private int m_Amount; + + public ItemReward() + : this( null, null ) + { + } + + public ItemReward( TextDefinition name, Type type ) + : this( name, type, 1 ) + { + } + + public ItemReward( TextDefinition name, Type type, int amount ) + : base( name ) + { + m_Type = type; + m_Amount = amount; + } + + public virtual Item CreateItem() + { + Item spawnedItem = null; + + try + { + spawnedItem = Activator.CreateInstance( m_Type ) as Item; + } + catch ( Exception e ) + { + if ( MLQuestSystem.Debug ) + Console.WriteLine( "WARNING: ItemReward.CreateItem failed for {0}: {1}", m_Type, e ); + } + + return spawnedItem; + } + + public override void AddRewardItems( PlayerMobile pm, List rewards ) + { + Item reward = CreateItem(); + + if ( reward == null ) + return; + + if ( reward.Stackable ) + { + if ( m_Amount > 1 ) + reward.Amount = m_Amount; + + rewards.Add( reward ); + } + else + { + for ( int i = 0; i < m_Amount; ++i ) + { + rewards.Add( reward ); + + if ( i < m_Amount - 1 ) + { + reward = CreateItem(); + + if ( reward == null ) + return; + } + } + } + } + } +} diff --git a/Scripts/Engines/MyRunUO/Config.cs b/Scripts/Engines/MyRunUO/Config.cs new file mode 100644 index 0000000..6a27897 --- /dev/null +++ b/Scripts/Engines/MyRunUO/Config.cs @@ -0,0 +1,51 @@ +using System; +using System.Text; +using System.Threading; + +namespace Server.Engines.MyRunUO +{ + public class Config + { + // Is MyRunUO enabled? + public static bool Enabled = false; + + // Details required for database connection string + public const string DatabaseDriver = "{MySQL ODBC 5.2w Driver}"; + public const string DatabaseServer = "localhost"; + public const string DatabaseName = "MyRunUO"; + public const string DatabaseUserID = "username"; + public const string DatabasePassword = "password"; + + // Should the database use transactions? This is recommended + public static bool UseTransactions = true; + + // Use optimized table loading techniques? (LOAD DATA INFILE) + public static bool LoadDataInFile = true; + + // This must be enabled if the database server is on a remote machine. + public static bool DatabaseNonLocal = (DatabaseServer != "localhost"); + + // Text encoding used + public static Encoding EncodingIO = Encoding.ASCII; + + // Database communication is done in a separate thread. This value is the 'priority' of that thread, or, how much CPU it will try to use + public static ThreadPriority DatabaseThreadPriority = ThreadPriority.BelowNormal; + + // Any character with an AccessLevel equal to or higher than this will not be displayed + public static AccessLevel HiddenAccessLevel = AccessLevel.Counselor; + + // Export character database every 30 minutes + public static TimeSpan CharacterUpdateInterval = TimeSpan.FromMinutes(30.0); + + // Export online list database every 5 minutes + public static TimeSpan StatusUpdateInterval = TimeSpan.FromMinutes(5.0); + + public static string CompileConnectionString() + { + string connectionString = String.Format("DRIVER={0};SERVER={1};DATABASE={2};UID={3};PASSWORD={4};", + DatabaseDriver, DatabaseServer, DatabaseName, DatabaseUserID, DatabasePassword); + + return connectionString; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/MyRunUO/DatabaseCommandQueue.cs b/Scripts/Engines/MyRunUO/DatabaseCommandQueue.cs new file mode 100644 index 0000000..fc85a48 --- /dev/null +++ b/Scripts/Engines/MyRunUO/DatabaseCommandQueue.cs @@ -0,0 +1,202 @@ +using System; +using System.Threading; +using System.Collections; +using System.Data; +using System.Data.Odbc; + +namespace Server.Engines.MyRunUO +{ + public class DatabaseCommandQueue + { + private Queue m_Queue; + private ManualResetEvent m_Sync; + private Thread m_Thread; + + private bool m_HasCompleted; + + private string m_CompletionString; + private string m_ConnectionString; + + public bool HasCompleted + { + get{ return m_HasCompleted; } + } + + public void Enqueue( object obj ) + { + lock ( m_Queue.SyncRoot ) + { + m_Queue.Enqueue( obj ); + try{ m_Sync.Set(); } + catch{} + } + } + + public DatabaseCommandQueue( string completionString, string threadName ) : this( Config.CompileConnectionString(), completionString, threadName ) + { + } + + public DatabaseCommandQueue( string connectionString, string completionString, string threadName ) + { + m_CompletionString = completionString; + m_ConnectionString = connectionString; + + m_Queue = Queue.Synchronized( new Queue() ); + + m_Queue.Enqueue( null ); // signal connect + + /*m_Queue.Enqueue( "DELETE FROM myrunuo_characters" ); + m_Queue.Enqueue( "DELETE FROM myrunuo_characters_layers" ); + m_Queue.Enqueue( "DELETE FROM myrunuo_characters_skills" ); + m_Queue.Enqueue( "DELETE FROM myrunuo_guilds" ); + m_Queue.Enqueue( "DELETE FROM myrunuo_guilds_wars" );*/ + + m_Sync = new ManualResetEvent( true ); + + m_Thread = new Thread( new ThreadStart( Thread_Start ) ); + m_Thread.Name = threadName;//"MyRunUO Database Command Queue"; + m_Thread.Priority = Config.DatabaseThreadPriority; + m_Thread.Start(); + } + + private void Thread_Start() + { + bool connected = false; + + OdbcConnection connection = null; + OdbcCommand command = null; + OdbcTransaction transact = null; + + DateTime start = DateTime.Now; + + bool shouldWriteException = true; + + while ( true ) + { + m_Sync.WaitOne(); + + while ( m_Queue.Count > 0 ) + { + try + { + object obj = m_Queue.Dequeue(); + + if ( obj == null ) + { + if ( connected ) + { + if ( transact != null ) + { + try{ transact.Commit(); } + catch ( Exception commitException ) + { + Console.WriteLine( "MyRunUO: Exception caught when committing transaction" ); + Console.WriteLine( commitException ); + + try + { + transact.Rollback(); + Console.WriteLine( "MyRunUO: Transaction has been rolled back" ); + } + catch ( Exception rollbackException ) + { + Console.WriteLine( "MyRunUO: Exception caught when rolling back transaction" ); + Console.WriteLine( rollbackException ); + } + } + } + + try{ connection.Close(); } + catch{} + + try{ connection.Dispose(); } + catch{} + + try{ command.Dispose(); } + catch{} + + try{ m_Sync.Close(); } + catch{} + + Console.WriteLine( m_CompletionString, (DateTime.Now - start).TotalSeconds ); + m_HasCompleted = true; + + return; + } + else + { + try + { + connected = true; + connection = new OdbcConnection( m_ConnectionString ); + connection.Open(); + command = connection.CreateCommand(); + + if ( Config.UseTransactions ) + { + transact = connection.BeginTransaction(); + command.Transaction = transact; + } + } + catch ( Exception e ) + { + try{ if ( transact != null ) transact.Rollback(); } + catch{} + + try{ if ( connection != null ) connection.Close(); } + catch{} + + try{ if ( connection != null ) connection.Dispose(); } + catch{} + + try{ if ( command != null ) command.Dispose(); } + catch{} + + try{ m_Sync.Close(); } + catch{} + + Console.WriteLine( "MyRunUO: Unable to connect to the database" ); + Console.WriteLine( e ); + m_HasCompleted = true; + return; + } + } + } + else if ( obj is string ) + { + command.CommandText = (string)obj; + command.ExecuteNonQuery(); + } + else + { + string[] parms = (string[])obj; + + command.CommandText = parms[0]; + + if ( command.ExecuteScalar() == null ) + { + command.CommandText = parms[1]; + command.ExecuteNonQuery(); + } + } + } + catch ( Exception e ) + { + if ( shouldWriteException ) + { + Console.WriteLine( "MyRunUO: Exception caught in database thread" ); + Console.WriteLine( e ); + shouldWriteException = false; + } + } + } + + lock ( m_Queue.SyncRoot ) + { + if ( m_Queue.Count == 0 ) + m_Sync.Reset(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/MyRunUO/LayerComparer.cs b/Scripts/Engines/MyRunUO/LayerComparer.cs new file mode 100644 index 0000000..cc35464 --- /dev/null +++ b/Scripts/Engines/MyRunUO/LayerComparer.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; + +namespace Server.Engines.MyRunUO +{ + public class LayerComparer : IComparer + { + private static Layer PlateArms = (Layer)255; + private static Layer ChainTunic = (Layer)254; + private static Layer LeatherShorts = (Layer)253; + + private static Layer[] m_DesiredLayerOrder = new Layer[] + { + Layer.Cloak, + Layer.Bracelet, + Layer.Ring, + Layer.Shirt, + Layer.Pants, + Layer.InnerLegs, + Layer.Shoes, + LeatherShorts, + Layer.Arms, + Layer.InnerTorso, + LeatherShorts, + PlateArms, + Layer.MiddleTorso, + Layer.OuterLegs, + Layer.Neck, + Layer.Waist, + Layer.Gloves, + Layer.OuterTorso, + Layer.OneHanded, + Layer.TwoHanded, + Layer.FacialHair, + Layer.Hair, + Layer.Helm, + Layer.Talisman + }; + + private static int[] m_TranslationTable; + + public static int[] TranslationTable + { + get{ return m_TranslationTable; } + } + + static LayerComparer() + { + m_TranslationTable = new int[256]; + + for ( int i = 0; i < m_DesiredLayerOrder.Length; ++i ) + m_TranslationTable[(int)m_DesiredLayerOrder[i]] = m_DesiredLayerOrder.Length - i; + } + + public static bool IsValid( Item item ) + { + return ( m_TranslationTable[(int)item.Layer] > 0 ); + } + + public static readonly IComparer Instance = new LayerComparer(); + + public LayerComparer() + { + } + + public Layer Fix( int itemID, Layer oldLayer ) + { + if ( itemID == 0x1410 || itemID == 0x1417 ) // platemail arms + return PlateArms; + + if ( itemID == 0x13BF || itemID == 0x13C4 ) // chainmail tunic + return ChainTunic; + + if ( itemID == 0x1C08 || itemID == 0x1C09 ) // leather skirt + return LeatherShorts; + + if ( itemID == 0x1C00 || itemID == 0x1C01 ) // leather shorts + return LeatherShorts; + + return oldLayer; + } + + public int Compare( object x, object y ) + { + Item a = (Item)x; + Item b = (Item)y; + + Layer aLayer = a.Layer; + Layer bLayer = b.Layer; + + aLayer = Fix( a.ItemID, aLayer ); + bLayer = Fix( b.ItemID, bLayer ); + + return m_TranslationTable[(int)bLayer] - m_TranslationTable[(int)aLayer]; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/MyRunUO/MyRunUO.cs b/Scripts/Engines/MyRunUO/MyRunUO.cs new file mode 100644 index 0000000..b347b36 --- /dev/null +++ b/Scripts/Engines/MyRunUO/MyRunUO.cs @@ -0,0 +1,640 @@ +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Misc; +using Server.Items; +using Server.Guilds; +using Server.Mobiles; +using Server.Accounting; +using Server.Commands; + +namespace Server.Engines.MyRunUO +{ + public class MyRunUO : Timer + { + private static double CpuInterval = 0.1; // Processor runs every 0.1 seconds + private static double CpuPercent = 0.25; // Processor runs for 25% of Interval, or ~25ms. This should take around 25% cpu + + public static void Initialize() + { + if ( Config.Enabled ) + { + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), Config.CharacterUpdateInterval, new TimerCallback( Begin ) ); + + CommandSystem.Register( "UpdateMyRunUO", AccessLevel.Administrator, new CommandEventHandler( UpdateMyRunUO_OnCommand ) ); + + CommandSystem.Register( "PublicChar", AccessLevel.Player, new CommandEventHandler( PublicChar_OnCommand ) ); + CommandSystem.Register( "PrivateChar", AccessLevel.Player, new CommandEventHandler( PrivateChar_OnCommand ) ); + } + } + + [Usage( "PublicChar" )] + [Description( "Enables showing extended character stats and skills in MyRunUO." )] + public static void PublicChar_OnCommand( CommandEventArgs e ) + { + PlayerMobile pm = e.Mobile as PlayerMobile; + + if ( pm != null ) + { + if ( pm.PublicMyRunUO ) + { + pm.SendMessage( "You have already chosen to show your skills and stats." ); + } + else + { + pm.PublicMyRunUO = true; + pm.SendMessage( "All of your skills and stats will now be shown publicly in MyRunUO." ); + } + } + } + + [Usage( "PrivateChar" )] + [Description( "Disables showing extended character stats and skills in MyRunUO." )] + public static void PrivateChar_OnCommand( CommandEventArgs e ) + { + PlayerMobile pm = e.Mobile as PlayerMobile; + + if ( pm != null ) + { + if ( !pm.PublicMyRunUO ) + { + pm.SendMessage( "You have already chosen to not show your skills and stats." ); + } + else + { + pm.PublicMyRunUO = false; + pm.SendMessage( "Only a general level of your top three skills will be shown in MyRunUO." ); + } + } + } + + [Usage( "UpdateMyRunUO" )] + [Description( "Starts the process of updating the MyRunUO character and guild database." )] + public static void UpdateMyRunUO_OnCommand( CommandEventArgs e ) + { + if ( m_Command != null && m_Command.HasCompleted ) + m_Command = null; + + if ( m_Timer == null && m_Command == null ) + { + Begin(); + e.Mobile.SendMessage( "MyRunUO update process has been started." ); + } + else + { + e.Mobile.SendMessage( "MyRunUO database is already being updated." ); + } + } + + public static void Begin() + { + if ( m_Command != null && m_Command.HasCompleted ) + m_Command = null; + + if ( m_Timer != null || m_Command != null ) + return; + + m_Timer = new MyRunUO(); + m_Timer.Start(); + } + + private static Timer m_Timer; + + private Stage m_Stage; + private ArrayList m_List; + private List m_Collecting; + private int m_Index; + + private static DatabaseCommandQueue m_Command; + + private string m_SkillsPath; + private string m_LayersPath; + private string m_MobilesPath; + + private StreamWriter m_OpSkills; + private StreamWriter m_OpLayers; + private StreamWriter m_OpMobiles; + + private DateTime m_StartTime; + + public MyRunUO() : base( TimeSpan.FromSeconds( CpuInterval ), TimeSpan.FromSeconds( CpuInterval ) ) + { + m_List = new ArrayList(); + m_Collecting = new List(); + + m_StartTime = DateTime.Now; + Console.WriteLine( "MyRunUO: Updating character database" ); + } + + protected override void OnTick() + { + bool shouldExit = false; + + try + { + shouldExit = Process( DateTime.Now + TimeSpan.FromSeconds( CpuInterval * CpuPercent ) ); + + if ( shouldExit ) + Console.WriteLine( "MyRunUO: Database statements compiled in {0:F2} seconds", (DateTime.Now - m_StartTime).TotalSeconds ); + } + catch ( Exception e ) + { + Console.WriteLine( "MyRunUO: {0}: Exception cought while processing", m_Stage ); + Console.WriteLine( e ); + shouldExit = true; + } + + if ( shouldExit ) + { + m_Command.Enqueue( null ); + + Stop(); + m_Timer = null; + } + } + + private enum Stage + { + CollectingMobiles, + DumpingMobiles, + CollectingGuilds, + DumpingGuilds, + Complete + } + + public bool Process( DateTime endTime ) + { + switch ( m_Stage ) + { + case Stage.CollectingMobiles: CollectMobiles( endTime ); break; + case Stage.DumpingMobiles: DumpMobiles( endTime ); break; + case Stage.CollectingGuilds: CollectGuilds( endTime ); break; + case Stage.DumpingGuilds: DumpGuilds( endTime ); break; + } + + return ( m_Stage == Stage.Complete ); + } + + private static ArrayList m_MobilesToUpdate = new ArrayList(); + + public static void QueueMobileUpdate( Mobile m ) + { + if ( !Config.Enabled || Config.LoadDataInFile ) + return; + + m_MobilesToUpdate.Add( m ); + } + + public void CollectMobiles( DateTime endTime ) + { + if ( Config.LoadDataInFile ) + { + if ( m_Index == 0 ) + m_Collecting.AddRange( Accounts.GetAccounts() ); + + for ( int i = m_Index; i < m_Collecting.Count; ++i ) + { + IAccount acct = m_Collecting[i]; + + for ( int j = 0; j < acct.Length; ++j ) + { + Mobile mob = acct[j]; + + if ( mob != null && mob.AccessLevel < Config.HiddenAccessLevel ) + m_List.Add( mob ); + } + + ++m_Index; + + if ( DateTime.Now >= endTime ) + break; + } + + if ( m_Index == m_Collecting.Count ) + { + m_Collecting = new List(); + m_Stage = Stage.DumpingMobiles; + m_Index = 0; + } + } + else + { + m_List = m_MobilesToUpdate; + m_MobilesToUpdate = new ArrayList(); + m_Stage = Stage.DumpingMobiles; + m_Index = 0; + } + } + + public void CheckConnection() + { + if ( m_Command == null ) + { + m_Command = new DatabaseCommandQueue( "MyRunUO: Characeter database updated in {0:F1} seconds", "MyRunUO Character Database Thread" ); + + if ( Config.LoadDataInFile ) + { + m_OpSkills = GetUniqueWriter( "skills", out m_SkillsPath ); + m_OpLayers = GetUniqueWriter( "layers", out m_LayersPath ); + m_OpMobiles = GetUniqueWriter( "mobiles", out m_MobilesPath ); + + m_Command.Enqueue( "TRUNCATE TABLE myrunuo_characters" ); + m_Command.Enqueue( "TRUNCATE TABLE myrunuo_characters_layers" ); + m_Command.Enqueue( "TRUNCATE TABLE myrunuo_characters_skills" ); + } + + m_Command.Enqueue( "TRUNCATE TABLE myrunuo_guilds" ); + m_Command.Enqueue( "TRUNCATE TABLE myrunuo_guilds_wars" ); + } + } + + public void ExecuteNonQuery( string text ) + { + m_Command.Enqueue( text ); + } + + public void ExecuteNonQuery( string format, params string[] args ) + { + ExecuteNonQuery( String.Format( format, args ) ); + } + + public void ExecuteNonQueryIfNull( string select, string insert ) + { + m_Command.Enqueue( new string[]{ select, insert } ); + } + + private void AppendCharEntity( string input, int charIndex, ref StringBuilder sb, char c ) + { + if ( sb == null ) + { + if ( charIndex > 0 ) + sb = new StringBuilder( input, 0, charIndex, input.Length + 20 ); + else + sb = new StringBuilder( input.Length + 20 ); + } + + sb.Append( "&#" ); + sb.Append( (int)c ); + sb.Append( ";" ); + } + + private void AppendEntityRef( string input, int charIndex, ref StringBuilder sb, string ent ) + { + if ( sb == null ) + { + if ( charIndex > 0 ) + sb = new StringBuilder( input, 0, charIndex, input.Length + 20 ); + else + sb = new StringBuilder( input.Length + 20 ); + } + + sb.Append( ent ); + } + + private string SafeString( string input ) + { + if ( input == null ) + return ""; + + StringBuilder sb = null; + + for ( int i = 0; i < input.Length; ++i ) + { + char c = input[i]; + + if (c < 0x20 || c >= 0x7F) + { + AppendCharEntity( input, i, ref sb, c ); + } + else + { + switch ( c ) + { + case '&': AppendEntityRef( input, i, ref sb, "&" ); break; + case '>': AppendEntityRef( input, i, ref sb, ">" ); break; + case '<': AppendEntityRef( input, i, ref sb, "<" ); break; + case '"': AppendEntityRef( input, i, ref sb, """ ); break; + case '\'': + case ':': + case '/': + case '\\': AppendCharEntity( input, i, ref sb, c ); break; + default: + { + if ( sb != null ) + sb.Append( c ); + + break; + } + } + } + } + + if ( sb != null ) + return sb.ToString(); + + return input; + } + + public const char LineStart = '\"'; + public const string EntrySep = "\",\""; + public const string LineEnd = "\"\n"; + + public void InsertMobile( Mobile mob ) + { + string guildTitle = mob.GuildTitle; + + if ( guildTitle == null || (guildTitle = guildTitle.Trim()).Length == 0 ) + guildTitle = "NULL"; + else + guildTitle = SafeString( guildTitle ); + + string notoTitle = SafeString( Titles.ComputeTitle( null, mob ) ); + string female = ( mob.Female ? "1" : "0" ); + + bool pubBool = ( mob is PlayerMobile ) && ( ((PlayerMobile)mob).PublicMyRunUO ); + + string pubString = ( pubBool ? "1" : "0" ); + + string guildId = ( mob.Guild == null ? "NULL" : mob.Guild.Id.ToString() ); + + if ( Config.LoadDataInFile ) + { + m_OpMobiles.Write( LineStart ); + m_OpMobiles.Write( mob.Serial.Value ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( SafeString( mob.Name ) ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( mob.RawStr ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( mob.RawDex ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( mob.RawInt ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( female ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( mob.Kills ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( guildId ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( guildTitle ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( notoTitle ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( mob.Hue ); + m_OpMobiles.Write( EntrySep ); + m_OpMobiles.Write( pubString ); + m_OpMobiles.Write( LineEnd ); + } + else + { + ExecuteNonQuery( "INSERT INTO myrunuo_characters (char_id, char_name, char_str, char_dex, char_int, char_female, char_counts, char_guild, char_guildtitle, char_nototitle, char_bodyhue, char_public ) VALUES ({0}, '{1}', {2}, {3}, {4}, {5}, {6}, {7}, {8}, '{9}', {10}, {11})", mob.Serial.Value.ToString(), SafeString( mob.Name ), mob.RawStr.ToString(), mob.RawDex.ToString(), mob.RawInt.ToString(), female, mob.Kills.ToString(), guildId, guildTitle, notoTitle, mob.Hue.ToString(), pubString ); + } + } + + public void InsertSkills( Mobile mob ) + { + Skills skills = mob.Skills; + string serial = mob.Serial.Value.ToString(); + + for ( int i = 0; i < skills.Length; ++i ) + { + Skill skill = skills[i]; + + if ( skill.BaseFixedPoint > 0 ) + { + if ( Config.LoadDataInFile ) + { + m_OpSkills.Write( LineStart ); + m_OpSkills.Write( serial ); + m_OpSkills.Write( EntrySep ); + m_OpSkills.Write( i ); + m_OpSkills.Write( EntrySep ); + m_OpSkills.Write( skill.BaseFixedPoint ); + m_OpSkills.Write( LineEnd ); + } + else + { + ExecuteNonQuery( "INSERT INTO myrunuo_characters_skills (char_id, skill_id, skill_value) VALUES ({0}, {1}, {2})", serial, i.ToString(), skill.BaseFixedPoint.ToString() ); + } + } + } + } + + private ArrayList m_Items = new ArrayList(); + + private void InsertItem( string serial, int index, int itemID, int hue ) + { + if ( Config.LoadDataInFile ) + { + m_OpLayers.Write( LineStart ); + m_OpLayers.Write( serial ); + m_OpLayers.Write( EntrySep ); + m_OpLayers.Write( index ); + m_OpLayers.Write( EntrySep ); + m_OpLayers.Write( itemID ); + m_OpLayers.Write( EntrySep ); + m_OpLayers.Write( hue ); + m_OpLayers.Write( LineEnd ); + } + else + { + ExecuteNonQuery( "INSERT INTO myrunuo_characters_layers (char_id, layer_id, item_id, item_hue) VALUES ({0}, {1}, {2}, {3})", serial, index.ToString(), itemID.ToString(), hue.ToString() ); + } + } + + public void InsertItems( Mobile mob ) + { + ArrayList items = m_Items; + items.AddRange( mob.Items ); + string serial = mob.Serial.Value.ToString(); + + items.Sort( LayerComparer.Instance ); + + int index = 0; + + bool hidePants = false; + bool alive = mob.Alive; + bool hideHair = !alive; + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = (Item)items[i]; + + if ( !LayerComparer.IsValid( item ) ) + break; + + if ( !alive && item.ItemID != 8270 ) + continue; + + if ( item.ItemID == 0x1411 || item.ItemID == 0x141A ) // plate legs + hidePants = true; + else if ( hidePants && item.Layer == Layer.Pants ) + continue; + + if ( !hideHair && item.Layer == Layer.Helm ) + hideHair = true; + + InsertItem( serial, index++, item.ItemID, item.Hue ); + } + + if ( mob.FacialHairItemID != 0 && alive ) + InsertItem( serial, index++, mob.FacialHairItemID, mob.FacialHairHue ); + + if ( mob.HairItemID != 0 && !hideHair ) + InsertItem( serial, index++, mob.HairItemID, mob.HairHue ); + + items.Clear(); + } + + public void DeleteMobile( Mobile mob ) + { + ExecuteNonQuery( "DELETE FROM myrunuo_characters WHERE char_id = {0}", mob.Serial.Value.ToString() ); + ExecuteNonQuery( "DELETE FROM myrunuo_characters_skills WHERE char_id = {0}", mob.Serial.Value.ToString() ); + ExecuteNonQuery( "DELETE FROM myrunuo_characters_layers WHERE char_id = {0}", mob.Serial.Value.ToString() ); + } + + public StreamWriter GetUniqueWriter( string type, out string filePath ) + { + filePath = Path.Combine( Core.BaseDirectory, String.Format( "myrunuodb_{0}.txt", type ) ).Replace( Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar ); + + try + { + return new StreamWriter( filePath ); + } + catch + { + for ( int i = 0; i < 100; ++i ) + { + try + { + filePath = Path.Combine( Core.BaseDirectory, String.Format( "myrunuodb_{0}_{1}.txt", type, i ) ).Replace( Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar ); + return new StreamWriter( filePath ); + } + catch + { + } + } + } + + return null; + } + + public void DumpMobiles( DateTime endTime ) + { + CheckConnection(); + + for ( int i = m_Index; i < m_List.Count; ++i ) + { + Mobile mob = (Mobile)m_List[i]; + + if ( mob is PlayerMobile ) + ((PlayerMobile)mob).ChangedMyRunUO = false; + + if ( !mob.Deleted && mob.AccessLevel < Config.HiddenAccessLevel ) + { + if ( !Config.LoadDataInFile ) + DeleteMobile( mob ); + + InsertMobile( mob ); + InsertSkills( mob ); + InsertItems( mob ); + } + else if ( !Config.LoadDataInFile ) + { + DeleteMobile( mob ); + } + + ++m_Index; + + if ( DateTime.Now >= endTime ) + break; + } + + if ( m_Index == m_List.Count ) + { + m_List.Clear(); + m_Stage = Stage.CollectingGuilds; + m_Index = 0; + + if ( Config.LoadDataInFile ) + { + m_OpSkills.Close(); + m_OpLayers.Close(); + m_OpMobiles.Close(); + + ExecuteNonQuery( "LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'", Config.DatabaseNonLocal ? "LOCAL " : "", m_MobilesPath ); + ExecuteNonQuery( "LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters_skills FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'", Config.DatabaseNonLocal ? "LOCAL " : "", m_SkillsPath ); + ExecuteNonQuery( "LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters_layers FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'", Config.DatabaseNonLocal ? "LOCAL " : "", m_LayersPath ); + } + } + } + + public void CollectGuilds( DateTime endTime ) + { + m_List.AddRange( Guild.List.Values ); + m_Stage = Stage.DumpingGuilds; + m_Index = 0; + } + + public void InsertGuild( Guild guild ) + { + string guildType = "Standard"; + + switch ( guild.Type ) + { + case GuildType.Chaos: guildType = "Chaos"; break; + case GuildType.Order: guildType = "Order"; break; + } + + ExecuteNonQuery( "INSERT INTO myrunuo_guilds (guild_id, guild_name, guild_abbreviation, guild_website, guild_charter, guild_type, guild_wars, guild_members, guild_master) VALUES ({0}, '{1}', {2}, {3}, {4}, '{5}', {6}, {7}, {8})", guild.Id.ToString(), SafeString( guild.Name ), guild.Abbreviation == "none" ? "NULL" : "'" + SafeString( guild.Abbreviation ) + "'", guild.Website == null ? "NULL" : "'" + SafeString( guild.Website ) + "'", guild.Charter == null ? "NULL" : "'" + SafeString( guild.Charter ) + "'", guildType, guild.Enemies.Count.ToString(), guild.Members.Count.ToString(), guild.Leader.Serial.Value.ToString() ); + } + + public void InsertWars( Guild guild ) + { + List wars = guild.Enemies; + + string ourId = guild.Id.ToString(); + + for ( int i = 0; i < wars.Count; ++i ) + { + Guild them = wars[i]; + string theirId = them.Id.ToString(); + + ExecuteNonQueryIfNull( + String.Format( "SELECT guild_1 FROM myrunuo_guilds_wars WHERE (guild_1={0} AND guild_2={1}) OR (guild_1={1} AND guild_2={0})", ourId, theirId ), + String.Format( "INSERT INTO myrunuo_guilds_wars (guild_1, guild_2) VALUES ({0}, {1})", ourId, theirId ) ); + } + } + + public void DumpGuilds( DateTime endTime ) + { + CheckConnection(); + + for ( int i = m_Index; i < m_List.Count; ++i ) + { + Guild guild = (Guild)m_List[i]; + + if ( !guild.Disbanded ) + { + InsertGuild( guild ); + InsertWars( guild ); + } + + ++m_Index; + + if ( DateTime.Now >= endTime ) + break; + } + + if ( m_Index == m_List.Count ) + { + m_List.Clear(); + m_Stage = Stage.Complete; + m_Index = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/MyRunUO/MyRunUOStatus.cs b/Scripts/Engines/MyRunUO/MyRunUOStatus.cs new file mode 100644 index 0000000..f1067c3 --- /dev/null +++ b/Scripts/Engines/MyRunUO/MyRunUOStatus.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Commands; +using Server.Network; + +namespace Server.Engines.MyRunUO +{ + public class MyRunUOStatus + { + public static void Initialize() + { + if (Config.Enabled) + { + Timer.DelayCall(TimeSpan.FromSeconds(20.0), Config.StatusUpdateInterval, new TimerCallback(Begin)); + + CommandSystem.Register("UpdateWebStatus", AccessLevel.Administrator, new CommandEventHandler(UpdateWebStatus_OnCommand)); + } + } + + [Usage("UpdateWebStatus")] + [Description("Starts the process of updating the MyRunUO online status database.")] + public static void UpdateWebStatus_OnCommand(CommandEventArgs e) + { + if (m_Command == null || m_Command.HasCompleted) + { + Begin(); + e.Mobile.SendMessage("Web status update process has been started."); + } + else + { + e.Mobile.SendMessage("Web status database is already being updated."); + } + } + + private static DatabaseCommandQueue m_Command; + + public static void Begin() + { + if (m_Command != null && !m_Command.HasCompleted) + return; + + DateTime start = DateTime.Now; + Console.WriteLine("MyRunUO: Updating status database"); + + try + { + m_Command = new DatabaseCommandQueue("MyRunUO: Status database updated in {0:F1} seconds", "MyRunUO Status Database Thread"); + + m_Command.Enqueue("DELETE FROM myrunuo_status"); + + List online = NetState.Instances; + + for (int i = 0; i < online.Count; ++i) + { + NetState ns = online[i]; + Mobile mob = ns.Mobile; + + if (mob != null) + m_Command.Enqueue(String.Format("INSERT INTO myrunuo_status (char_id) VALUES ({0})", mob.Serial.Value.ToString())); + } + } + catch (Exception e) + { + Console.WriteLine("MyRunUO: Error updating status database"); + Console.WriteLine(e); + } + + if (m_Command != null) + m_Command.Enqueue(null); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/AddPartyTarget.cs b/Scripts/Engines/Party/AddPartyTarget.cs new file mode 100644 index 0000000..f42e006 --- /dev/null +++ b/Scripts/Engines/Party/AddPartyTarget.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Engines.PartySystem +{ + public class AddPartyTarget : Target + { + public AddPartyTarget( Mobile from ) : base( 8, false, TargetFlags.None ) + { + from.SendMessage( "Qui voulez-vous ajouter � votre groupe?" ); // Who would you like to add to your party? + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + Mobile m = (Mobile)o; + Party p = Party.Get( from ); + Party mp = Party.Get( m ); + + if ( from == m ) + from.SendMessage( "Vous ne pouvez vous ajouter � votre propre groupe" ); // You cannot add yourself to a party. + else if ( p != null && p.Leader != from ) + from.SendMessage( "Vous devez �tre le meneur pour ajouter des membres � votre groupe" ); // You may only add members to the party if you are the leader. + else if ( m.Party is Mobile ) + return; + else if ( p != null && (p.Members.Count + p.Candidates.Count) >= Party.Capacity ) + from.SendMessage( "Un groupe ne comporte que 10 membres. Cela inclus ceux qui sont invit�s" ); // You may only have 10 in your party (this includes candidates). + else if ( !m.Player && m.Body.IsHuman ) + m.SayTo( from, "Non, je pr�f�re rester ici et regarder des clous rouiller" ); // Nay, I would rather stay here and watch a nail rust. + else if ( !m.Player ) + from.SendMessage( "Cette cr�ature ignore votre offre" ); // The creature ignores your offer. + else if ( mp != null && mp == p ) + from.SendMessage( "Cette personne est d�j� dans votre groupe!" ); // This person is already in your party! + else if ( mp != null ) + from.SendMessage( "Cette personne est d�j� dans un groupe!" ); // This person is already in a party! + else + Party.Invite( from, m ); + } + else + { + from.SendMessage( "Vous ne pouvez ajouter que des cr�atures vivantes � votre groupe!" ); // You may only add living things to your party! + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/DeclineTimer.cs b/Scripts/Engines/Party/DeclineTimer.cs new file mode 100644 index 0000000..1c249f9 --- /dev/null +++ b/Scripts/Engines/Party/DeclineTimer.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Engines.PartySystem +{ + public class DeclineTimer : Timer + { + private Mobile m_Mobile, m_Leader; + + private static Hashtable m_Table = new Hashtable(); + + public static void Start( Mobile m, Mobile leader ) + { + DeclineTimer t = (DeclineTimer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + m_Table[m] = t = new DeclineTimer( m, leader ); + t.Start(); + } + + private DeclineTimer( Mobile m, Mobile leader ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Mobile = m; + m_Leader = leader; + } + + protected override void OnTick() + { + m_Table.Remove( m_Mobile ); + + if ( m_Mobile.Party == m_Leader && PartyCommands.Handler != null ) + PartyCommands.Handler.OnDecline( m_Mobile, m_Leader ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/Packets.cs b/Scripts/Engines/Party/Packets.cs new file mode 100644 index 0000000..cd929fe --- /dev/null +++ b/Scripts/Engines/Party/Packets.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Engines.PartySystem +{ + public sealed class PartyEmptyList : Packet + { + public PartyEmptyList( Mobile m ) : base( 0xBF ) + { + EnsureCapacity( 7 ); + + m_Stream.Write( (short) 0x0006 ); + m_Stream.Write( (byte) 0x02 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (int) m.Serial ); + } + } + + public sealed class PartyMemberList : Packet + { + public PartyMemberList( Party p ) : base( 0xBF ) + { + EnsureCapacity( 7 + p.Count*4 ); + + m_Stream.Write( (short) 0x0006 ); + m_Stream.Write( (byte) 0x01 ); + m_Stream.Write( (byte) p.Count ); + + for ( int i = 0; i < p.Count; ++i ) + m_Stream.Write( (int) p[i].Mobile.Serial ); + } + } + + public sealed class PartyRemoveMember : Packet + { + public PartyRemoveMember( Mobile removed, Party p ) : base( 0xBF ) + { + EnsureCapacity( 11 + p.Count*4 ); + + m_Stream.Write( (short) 0x0006 ); + m_Stream.Write( (byte) 0x02 ); + m_Stream.Write( (byte) p.Count ); + + m_Stream.Write( (int) removed.Serial ); + + for ( int i = 0; i < p.Count; ++i ) + m_Stream.Write( (int) p[i].Mobile.Serial ); + } + } + + public sealed class PartyTextMessage : Packet + { + public PartyTextMessage( bool toAll, Mobile from, string text ) : base( 0xBF ) + { + if ( text == null ) + text = ""; + + EnsureCapacity( 12 + text.Length*2 ); + + m_Stream.Write( (short) 0x0006 ); + m_Stream.Write( (byte) (toAll ? 0x04 : 0x03) ); + m_Stream.Write( (int) from.Serial ); + m_Stream.WriteBigUniNull( text ); + } + } + + public sealed class PartyInvitation : Packet + { + public PartyInvitation( Mobile leader ) : base( 0xBF ) + { + EnsureCapacity( 10 ); + + m_Stream.Write( (short) 0x0006 ); + m_Stream.Write( (byte) 0x07 ); + m_Stream.Write( (int) leader.Serial ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/Party.cs b/Scripts/Engines/Party/Party.cs new file mode 100644 index 0000000..b49306a --- /dev/null +++ b/Scripts/Engines/Party/Party.cs @@ -0,0 +1,478 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Factions; +using Server.Commands; +using System.Collections.Generic; + +namespace Server.Engines.PartySystem +{ + public class Party : IParty + { + private Mobile m_Leader; + private List m_Members; + private List m_Candidates; + private List m_Listeners; // staff listening + + public const int Capacity = 10; + + public static void Initialize() + { + EventSink.Logout += new LogoutEventHandler( EventSink_Logout ); + EventSink.Login += new LoginEventHandler( EventSink_Login ); + EventSink.PlayerDeath += new PlayerDeathEventHandler( EventSink_PlayerDeath ); + + CommandSystem.Register( "ListenToParty", AccessLevel.GameMaster, new CommandEventHandler( ListenToParty_OnCommand ) ); + } + + public static void ListenToParty_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( ListenToParty_OnTarget ) ); + e.Mobile.SendMessage( "Target a partied player." ); + } + + public static void ListenToParty_OnTarget( Mobile from, object obj ) + { + if ( obj is Mobile ) + { + Party p = Party.Get( (Mobile) obj ); + + if ( p == null ) + { + from.SendMessage( "They are not in a party." ); + } + else if ( p.m_Listeners.Contains( from ) ) + { + p.m_Listeners.Remove( from ); + from.SendMessage( "You are no longer listening to that party." ); + } + else + { + p.m_Listeners.Add( from ); + from.SendMessage( "You are now listening to that party." ); + } + } + } + + public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) + { + Mobile from = e.Mobile; + Party p = Party.Get( from ); + + if ( p != null ) + { + Mobile m = from.LastKiller; + + if ( m == from ) + p.SendPublicMessage( from, "I killed myself !!" ); + else if ( m == null ) + p.SendPublicMessage( from, "I was killed !!" ); + else + p.SendPublicMessage( from, String.Format( "I was killed by {0} !!", m.Name ) ); + } + } + + private class RejoinTimer : Timer + { + private Mobile m_Mobile; + + public RejoinTimer( Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + } + + protected override void OnTick() + { + Party p = Party.Get( m_Mobile ); + + if ( p == null ) + return; + + m_Mobile.SendLocalizedMessage( 1005437 ); // You have rejoined the party. + m_Mobile.Send( new PartyMemberList( p ) ); + + Packet message = Packet.Acquire( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008087, "", AffixType.Prepend | AffixType.System, m_Mobile.Name, "" ) ); + Packet attrs = Packet.Acquire( new MobileAttributesN( m_Mobile ) ); + + foreach ( PartyMemberInfo mi in p.Members ) + { + Mobile m = mi.Mobile; + + if ( m != m_Mobile ) + { + m.Send( message ); + m.Send( new MobileStatusCompact( m_Mobile.CanBeRenamedBy( m ), m_Mobile ) ); + m.Send( attrs ); + m_Mobile.Send( new MobileStatusCompact( m.CanBeRenamedBy( m_Mobile ), m ) ); + m_Mobile.Send( new MobileAttributesN( m ) ); + } + } + + Packet.Release( message ); + Packet.Release( attrs ); + } + } + + public static void EventSink_Login( LoginEventArgs e ) + { + Mobile from = e.Mobile; + Party p = Party.Get( from ); + + if ( p != null ) + new RejoinTimer( from ).Start(); + else + from.Party = null; + } + + public static void EventSink_Logout( LogoutEventArgs e ) + { + Mobile from = e.Mobile; + Party p = Party.Get( from ); + + if ( p != null ) + p.Remove( from ); + + from.Party = null; + } + + public static Party Get( Mobile m ) + { + if ( m == null ) + return null; + + return m.Party as Party; + } + + public Party( Mobile leader ) + { + m_Leader = leader; + + m_Members = new List(); + m_Candidates = new List(); + m_Listeners = new List(); + + m_Members.Add( new PartyMemberInfo( leader ) ); + } + + public void Add( Mobile m ) + { + PartyMemberInfo mi = this[m]; + + if ( mi == null ) + { + m_Members.Add( new PartyMemberInfo( m ) ); + m.Party = this; + + Packet memberList = Packet.Acquire( new PartyMemberList( this ) ); + Packet attrs = Packet.Acquire( new MobileAttributesN( m ) ); + + for ( int i = 0; i < m_Members.Count; ++i ) + { + Mobile f = ((PartyMemberInfo)m_Members[i]).Mobile; + + f.Send( memberList ); + + if ( f != m ) + { + f.Send( new MobileStatusCompact( m.CanBeRenamedBy( f ), m ) ); + f.Send( attrs ); + m.Send( new MobileStatusCompact( f.CanBeRenamedBy( m ), f ) ); + m.Send( new MobileAttributesN( f ) ); + } + } + + Packet.Release( memberList ); + Packet.Release( attrs ); + } + } + + public void OnAccept( Mobile from ) + { + OnAccept( from, false ); + } + + public void OnAccept( Mobile from, bool force ) + { + Faction ourFaction = Faction.Find( m_Leader ); + Faction theirFaction = Faction.Find( from ); + + if ( !force && ourFaction != null && theirFaction != null && ourFaction != theirFaction ) + return; + + // : joined the party. + SendToAll( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008094, "", AffixType.Prepend | AffixType.System, from.Name, "" ) ); + + from.SendLocalizedMessage( 1005445 ); // You have been added to the party. + + m_Candidates.Remove( from ); + Add( from ); + } + + public void OnDecline( Mobile from, Mobile leader ) + { + // : Does not wish to join the party. + leader.SendLocalizedMessage( 1008091, false, from.Name ); + + from.SendLocalizedMessage( 1008092 ); // You notify them that you do not wish to join the party. + + m_Candidates.Remove( from ); + from.Send( new PartyEmptyList( from ) ); + + if ( m_Candidates.Count == 0 && m_Members.Count <= 1 ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + { + this[i].Mobile.Send( new PartyEmptyList( this[i].Mobile ) ); + this[i].Mobile.Party = null; + } + + m_Members.Clear(); + } + } + + public void Remove( Mobile m ) + { + if ( m == m_Leader ) + { + Disband(); + } + else + { + for ( int i = 0; i < m_Members.Count; ++i ) + { + if ( ((PartyMemberInfo)m_Members[i]).Mobile == m ) + { + m_Members.RemoveAt( i ); + + m.Party = null; + m.Send( new PartyEmptyList( m ) ); + + m.SendLocalizedMessage( 1005451 ); // You have been removed from the party. + + SendToAll( new PartyRemoveMember( m, this ) ); + SendToAll( 1005452 ); // A player has been removed from your party. + + break; + } + } + + if ( m_Members.Count == 1 ) + { + SendToAll( 1005450 ); // The last person has left the party... + Disband(); + } + } + } + + public bool Contains( Mobile m ) + { + return ( this[m] != null ); + } + + public void Disband() + { + SendToAll( 1005449 ); // Your party has disbanded. + + for ( int i = 0; i < m_Members.Count; ++i ) + { + this[i].Mobile.Send( new PartyEmptyList( this[i].Mobile ) ); + this[i].Mobile.Party = null; + } + + m_Members.Clear(); + } + + public static void Invite( Mobile from, Mobile target ) + { + Faction ourFaction = Faction.Find( from ); + Faction theirFaction = Faction.Find( target ); + + if ( ourFaction != null && theirFaction != null && ourFaction != theirFaction ) + { + from.SendLocalizedMessage( 1008088 ); // You cannot have players from opposing factions in the same party! + target.SendLocalizedMessage( 1008093 ); // The party cannot have members from opposing factions. + return; + } + + Party p = Party.Get( from ); + + if ( p == null ) + from.Party = p = new Party( from ); + + if ( !p.Candidates.Contains( target ) ) + p.Candidates.Add( target ); + + // : You are invited to join the party. Type /accept to join or /decline to decline the offer. + target.Send( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008089, "", AffixType.Prepend | AffixType.System, from.Name, "" ) ); + + from.SendLocalizedMessage( 1008090 ); // You have invited them to join the party. + + target.Send( new PartyInvitation( from ) ); + target.Party = from; + + DeclineTimer.Start( target, from ); + } + + public void SendToAll( int number ) + { + SendToAll( number, "", 0x3B2 ); + } + + public void SendToAll( int number, string args ) + { + SendToAll( number, args, 0x3B2 ); + } + + public void SendToAll( int number, string args, int hue ) + { + SendToAll( new MessageLocalized( Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args ) ); + } + + public void SendPublicMessage( Mobile from, string text ) + { + SendToAll( new PartyTextMessage( true, from, text ) ); + + for ( int i = 0; i < m_Listeners.Count; ++i ) + { + Mobile mob = m_Listeners[i]; + + if ( mob.Party != this ) + m_Listeners[i].SendMessage( "[{0}]: {1}", from.Name, text ); + } + + SendToStaffMessage( from, "[Party]: {0}", text ); + } + + public void SendPrivateMessage( Mobile from, Mobile to, string text ) + { + to.Send( new PartyTextMessage( false, from, text ) ); + + for ( int i = 0; i < m_Listeners.Count; ++i ) + { + Mobile mob = m_Listeners[i]; + + if ( mob.Party != this ) + m_Listeners[i].SendMessage( "[{0}]->[{1}]: {2}", from.Name, to.Name, text ); + } + + SendToStaffMessage( from, "[Party]->[{0}]: {1}", to.Name, text ); + } + + private void SendToStaffMessage( Mobile from, string text ) + { + Packet p = null; + + foreach( NetState ns in from.GetClientsInRange( 8 ) ) + { + Mobile mob = ns.Mobile; + + if( mob != null && mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel && mob.Party != this && !m_Listeners.Contains( mob ) ) + { + if( p == null ) + p = Packet.Acquire( new UnicodeMessage( from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, from.Language, from.Name, text ) ); + + ns.Send( p ); + } + } + + Packet.Release( p ); + } + private void SendToStaffMessage( Mobile from, string format, params object[] args ) + { + SendToStaffMessage( from, String.Format( format, args ) ); + } + + public void SendToAll( Packet p ) + { + p.Acquire(); + + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].Mobile.Send( p ); + + if ( p is MessageLocalized || p is MessageLocalizedAffix || p is UnicodeMessage || p is AsciiMessage ) + { + for ( int i = 0; i < m_Listeners.Count; ++i ) + { + Mobile mob = m_Listeners[i]; + + if ( mob.Party != this ) + mob.Send( p ); + } + } + + p.Release(); + } + + public void OnStamChanged( Mobile m ) + { + Packet p = null; + + for ( int i = 0; i < m_Members.Count; ++i ) + { + Mobile c = m_Members[i].Mobile; + + if ( c != m && m.Map == c.Map && Utility.InUpdateRange( c, m ) && c.CanSee( m ) ) + { + if ( p == null ) + p = Packet.Acquire( new MobileStamN( m ) ); + + c.Send( p ); + } + } + + Packet.Release( p ); + } + + public void OnManaChanged( Mobile m ) + { + Packet p = null; + + for ( int i = 0; i < m_Members.Count; ++i ) + { + Mobile c = m_Members[i].Mobile; + + if ( c != m && m.Map == c.Map && Utility.InUpdateRange( c, m ) && c.CanSee( m ) ) + { + if ( p == null ) + p = Packet.Acquire( new MobileManaN( m ) ); + + c.Send( p ); + } + } + + Packet.Release( p ); + } + + public void OnStatsQuery( Mobile beholder, Mobile beheld ) + { + if ( beholder != beheld && Contains( beholder ) && beholder.Map == beheld.Map && Utility.InUpdateRange( beholder, beheld ) ) + { + if ( !beholder.CanSee( beheld ) ) + beholder.Send( new MobileStatusCompact( beheld.CanBeRenamedBy( beholder ), beheld ) ); + + beholder.Send( new MobileAttributesN( beheld ) ); + } + } + + public int Count{ get{ return m_Members.Count; } } + public bool Active{ get{ return m_Members.Count > 1; } } + public Mobile Leader{ get{ return m_Leader; } } + public List Members{ get{ return m_Members; } } + public List Candidates { get { return m_Candidates; } } + + public PartyMemberInfo this[int index]{ get{ return m_Members[index]; } } + public PartyMemberInfo this[Mobile m] + { + get + { + for ( int i = 0; i < m_Members.Count; ++i ) + if ( m_Members[i].Mobile == m ) + return m_Members[i]; + + return null; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/PartyCommands.cs b/Scripts/Engines/Party/PartyCommands.cs new file mode 100644 index 0000000..1fcdf03 --- /dev/null +++ b/Scripts/Engines/Party/PartyCommands.cs @@ -0,0 +1,123 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Engines.PartySystem +{ + public class PartyCommandHandlers : PartyCommands + { + public static void Initialize() + { + PartyCommands.Handler = new PartyCommandHandlers(); + } + + public override void OnAdd( Mobile from ) + { + Party p = Party.Get( from ); + + if ( p != null && p.Leader != from ) + from.SendLocalizedMessage( 1005453 ); // You may only add members to the party if you are the leader. + else if ( p != null && (p.Members.Count + p.Candidates.Count) >= Party.Capacity ) + from.SendLocalizedMessage( 1008095 ); // You may only have 10 in your party (this includes candidates). + else + from.Target = new AddPartyTarget( from ); + } + + public override void OnRemove( Mobile from, Mobile target ) + { + Party p = Party.Get( from ); + + if ( p == null ) + { + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + return; + } + + if ( p.Leader == from && target == null ) + { + from.SendLocalizedMessage( 1005455 ); // Who would you like to remove from your party? + from.Target = new RemovePartyTarget(); + } + else if ( (p.Leader == from || from == target) && p.Contains( target ) ) + { + p.Remove( target ); + } + } + + public override void OnPrivateMessage( Mobile from, Mobile target, string text ) + { + if ( text.Length > 128 || (text = text.Trim()).Length == 0 ) + return; + + Party p = Party.Get( from ); + + if ( p != null && p.Contains( target ) ) + p.SendPrivateMessage( from, target, text ); + else + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + } + + public override void OnPublicMessage( Mobile from, string text ) + { + if ( text.Length > 128 || (text = text.Trim()).Length == 0 ) + return; + + Party p = Party.Get( from ); + + if ( p != null ) + p.SendPublicMessage( from, text ); + else + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + } + + public override void OnSetCanLoot( Mobile from, bool canLoot ) + { + Party p = Party.Get( from ); + + if ( p == null ) + { + from.SendLocalizedMessage( 3000211 ); // You are not in a party. + } + else + { + PartyMemberInfo mi = p[from]; + + if ( mi != null ) + { + mi.CanLoot = canLoot; + + if ( canLoot ) + from.SendLocalizedMessage( 1005447 ); // You have chosen to allow your party to loot your corpse. + else + from.SendLocalizedMessage( 1005448 ); // You have chosen to prevent your party from looting your corpse. + } + } + } + + public override void OnAccept( Mobile from, Mobile sentLeader ) + { + Mobile leader = from.Party as Mobile; + from.Party = null; + + Party p = Party.Get( leader ); + + if ( leader == null || p == null || !p.Candidates.Contains( from ) ) + from.SendLocalizedMessage( 3000222 ); // No one has invited you to be in a party. + else if ( (p.Members.Count + p.Candidates.Count) <= Party.Capacity ) + p.OnAccept( from ); + } + + public override void OnDecline( Mobile from, Mobile sentLeader ) + { + Mobile leader = from.Party as Mobile; + from.Party = null; + + Party p = Party.Get( leader ); + + if ( leader == null || p == null || !p.Candidates.Contains( from ) ) + from.SendLocalizedMessage( 3000222 ); // No one has invited you to be in a party. + else + p.OnDecline( from, leader ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/PartyMemberInfo.cs b/Scripts/Engines/Party/PartyMemberInfo.cs new file mode 100644 index 0000000..85dad48 --- /dev/null +++ b/Scripts/Engines/Party/PartyMemberInfo.cs @@ -0,0 +1,20 @@ +using System; +using Server; + +namespace Server.Engines.PartySystem +{ + public class PartyMemberInfo + { + private Mobile m_Mobile; + private bool m_CanLoot; + + public Mobile Mobile{ get{ return m_Mobile; } } + public bool CanLoot{ get{ return m_CanLoot; } set{ m_CanLoot = value; } } + + public PartyMemberInfo( Mobile m ) + { + m_Mobile = m; + m_CanLoot = !Core.ML; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Party/RemoveFromParty.cs b/Scripts/Engines/Party/RemoveFromParty.cs new file mode 100644 index 0000000..b178bca --- /dev/null +++ b/Scripts/Engines/Party/RemoveFromParty.cs @@ -0,0 +1,31 @@ +using System; +using Server.Mobiles; +using Server.Engines.PartySystem; + +namespace Server.ContextMenus +{ + public class RemoveFromPartyEntry : ContextMenuEntry + { + private Mobile m_From; + private Mobile m_Target; + + public RemoveFromPartyEntry( Mobile from, Mobile target ) : base( 0198, 12 ) + { + m_From = from; + m_Target = target; + } + + public override void OnClick() + { + Party p = Party.Get( m_From ); + + if ( p == null || p.Leader != m_From || !p.Contains( m_Target ) ) + return; + + if ( m_From == m_Target ) + m_From.SendLocalizedMessage( 1005446 ); // You may only remove yourself from a party if you are not the leader. + else + p.Remove( m_Target ); + } + } +} diff --git a/Scripts/Engines/Party/RemovePartyTarget.cs b/Scripts/Engines/Party/RemovePartyTarget.cs new file mode 100644 index 0000000..f2a3020 --- /dev/null +++ b/Scripts/Engines/Party/RemovePartyTarget.cs @@ -0,0 +1,30 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Engines.PartySystem +{ + public class RemovePartyTarget : Target + { + public RemovePartyTarget() : base( 8, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + Mobile m = (Mobile)o; + Party p = Party.Get( from ); + + if ( p == null || p.Leader != from || !p.Contains( m ) ) + return; + + if ( from == m ) + from.SendLocalizedMessage( 1005446 ); // You may only remove yourself from a party if you are not the leader. + else + p.Remove( m ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/FastAStarAlgorithm.cs b/Scripts/Engines/Pathing/FastAStarAlgorithm.cs new file mode 100644 index 0000000..f9b7854 --- /dev/null +++ b/Scripts/Engines/Pathing/FastAStarAlgorithm.cs @@ -0,0 +1,295 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.PathAlgorithms; +using CalcMoves = Server.Movement.Movement; +using MoveImpl = Server.Movement.MovementImpl; + +namespace Server.PathAlgorithms.FastAStar +{ + public struct PathNode + { + public int cost, total; + public int parent, next, prev; + public int z; + } + + public class FastAStarAlgorithm : PathAlgorithm + { + public static PathAlgorithm Instance = new FastAStarAlgorithm(); + + private const int MaxDepth = 300; + private const int AreaSize = 38; + + private const int NodeCount = AreaSize * AreaSize * PlaneCount; + + private const int PlaneOffset = 128; + private const int PlaneCount = 13; + private const int PlaneHeight = 20; + + private static Direction[] m_Path = new Direction[AreaSize * AreaSize]; + private static PathNode[] m_Nodes = new PathNode[NodeCount]; + private static BitArray m_Touched = new BitArray(NodeCount); + private static BitArray m_OnOpen = new BitArray(NodeCount); + private static int[] m_Successors = new int[8]; + + private static int m_xOffset, m_yOffset; + private static int m_OpenList; + + private Point3D m_Goal; + + public int Heuristic(int x, int y, int z) + { + x -= m_Goal.X - m_xOffset; + y -= m_Goal.Y - m_yOffset; + z -= m_Goal.Z; + + x *= 11; + y *= 11; + + return (x * x) + (y * y) + (z * z); + } + + public override bool CheckCondition(Mobile m, Map map, Point3D start, Point3D goal) + { + return Utility.InRange(start, goal, AreaSize); + } + + private void RemoveFromChain(int node) + { + if (node < 0 || node >= NodeCount) + return; + + if (!m_Touched[node] || !m_OnOpen[node]) + return; + + int prev = m_Nodes[node].prev; + int next = m_Nodes[node].next; + + if (m_OpenList == node) + m_OpenList = next; + + if (prev != -1) + m_Nodes[prev].next = next; + + if (next != -1) + m_Nodes[next].prev = prev; + + m_Nodes[node].prev = -1; + m_Nodes[node].next = -1; + } + + private void AddToChain(int node) + { + if (node < 0 || node >= NodeCount) + return; + + RemoveFromChain(node); + + if (m_OpenList != -1) + m_Nodes[m_OpenList].prev = node; + + m_Nodes[node].next = m_OpenList; + m_Nodes[node].prev = -1; + + m_OpenList = node; + + m_Touched[node] = true; + m_OnOpen[node] = true; + } + + public override Direction[] Find(Mobile m, Map map, Point3D start, Point3D goal) + { + if (!Utility.InRange(start, goal, AreaSize)) + return null; + + m_Touched.SetAll(false); + + m_Goal = goal; + + m_xOffset = (start.X + goal.X - AreaSize) / 2; + m_yOffset = (start.Y + goal.Y - AreaSize) / 2; + + int fromNode = GetIndex(start.X, start.Y, start.Z); + int destNode = GetIndex(goal.X, goal.Y, goal.Z); + + m_OpenList = fromNode; + + m_Nodes[m_OpenList].cost = 0; + m_Nodes[m_OpenList].total = Heuristic(start.X - m_xOffset, start.Y - m_yOffset, start.Z); + m_Nodes[m_OpenList].parent = -1; + m_Nodes[m_OpenList].next = -1; + m_Nodes[m_OpenList].prev = -1; + m_Nodes[m_OpenList].z = start.Z; + + m_OnOpen[m_OpenList] = true; + m_Touched[m_OpenList] = true; + + BaseCreature bc = m as BaseCreature; + + int pathCount, parent; + int backtrack = 0, depth = 0; + + Direction[] path = m_Path; + + while (m_OpenList != -1) + { + int bestNode = FindBest(m_OpenList); + + if (++depth > MaxDepth) + break; + + if (bc != null) + { + MoveImpl.AlwaysIgnoreDoors = bc.CanOpenDoors; + MoveImpl.IgnoreMovableImpassables = bc.CanMoveOverObstacles; + } + + MoveImpl.Goal = goal; + + int[] vals = m_Successors; + int count = GetSuccessors(bestNode, m, map); + + MoveImpl.AlwaysIgnoreDoors = false; + MoveImpl.IgnoreMovableImpassables = false; + MoveImpl.Goal = Point3D.Zero; + + if (count == 0) + break; + + for (int i = 0; i < count; ++i) + { + int newNode = vals[i]; + + bool wasTouched = m_Touched[newNode]; + + if (!wasTouched) + { + int newCost = m_Nodes[bestNode].cost + 1; + int newTotal = newCost + Heuristic(newNode % AreaSize, (newNode / AreaSize) % AreaSize, m_Nodes[newNode].z); + + if (!wasTouched || m_Nodes[newNode].total > newTotal) + { + m_Nodes[newNode].parent = bestNode; + m_Nodes[newNode].cost = newCost; + m_Nodes[newNode].total = newTotal; + + if (!wasTouched || !m_OnOpen[newNode]) + { + AddToChain(newNode); + + if (newNode == destNode) + { + pathCount = 0; + parent = m_Nodes[newNode].parent; + + while (parent != -1) + { + path[pathCount++] = GetDirection(parent % AreaSize, (parent / AreaSize) % AreaSize, newNode % AreaSize, (newNode / AreaSize) % AreaSize); + newNode = parent; + parent = m_Nodes[newNode].parent; + + if (newNode == fromNode) + break; + } + + Direction[] dirs = new Direction[pathCount]; + + while (pathCount > 0) + dirs[backtrack++] = path[--pathCount]; + + return dirs; + } + } + } + } + } + } + + return null; + } + + private int GetIndex(int x, int y, int z) + { + x -= m_xOffset; + y -= m_yOffset; + z += PlaneOffset; + z /= PlaneHeight; + + return x + (y * AreaSize) + (z * AreaSize * AreaSize); + } + + private int FindBest(int node) + { + int least = m_Nodes[node].total; + int leastNode = node; + + while (node != -1) + { + if (m_Nodes[node].total < least) + { + least = m_Nodes[node].total; + leastNode = node; + } + + node = m_Nodes[node].next; + } + + RemoveFromChain(leastNode); + + m_Touched[leastNode] = true; + m_OnOpen[leastNode] = false; + + return leastNode; + } + + public int GetSuccessors(int p, Mobile m, Map map) + { + int px = p % AreaSize; + int py = (p / AreaSize) % AreaSize; + int pz = m_Nodes[p].z; + int x, y, z; + + Point3D p3D = new Point3D(px + m_xOffset, py + m_yOffset, pz); + + int[] vals = m_Successors; + int count = 0; + + for (int i = 0; i < 8; ++i) + { + switch (i) + { + default: + case 0: x = 0; y = -1; break; + case 1: x = 1; y = -1; break; + case 2: x = 1; y = 0; break; + case 3: x = 1; y = 1; break; + case 4: x = 0; y = 1; break; + case 5: x = -1; y = 1; break; + case 6: x = -1; y = 0; break; + case 7: x = -1; y = -1; break; + } + + x += px; + y += py; + + if (x < 0 || x >= AreaSize || y < 0 || y >= AreaSize) + continue; + + if (CalcMoves.CheckMovement(m, map, p3D, (Direction)i, out z)) + { + int idx = GetIndex(x + m_xOffset, y + m_yOffset, z); + + if (idx >= 0 && idx < NodeCount) + { + m_Nodes[idx].z = z; + vals[count++] = idx; + } + } + } + + return count; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/MoveResult.cs b/Scripts/Engines/Pathing/MoveResult.cs new file mode 100644 index 0000000..f52629c --- /dev/null +++ b/Scripts/Engines/Pathing/MoveResult.cs @@ -0,0 +1,14 @@ +using System; + +namespace Server +{ + public delegate MoveResult MoveMethod( Direction d ); + + public enum MoveResult + { + BadState, + Blocked, + Success, + SuccessAutoTurn + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/Movement.cs b/Scripts/Engines/Pathing/Movement.cs new file mode 100644 index 0000000..c2049ab --- /dev/null +++ b/Scripts/Engines/Pathing/Movement.cs @@ -0,0 +1,595 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Movement +{ + public class MovementImpl : IMovementImpl + { + private const int PersonHeight = 16; + private const int StepHeight = 2; + + private const TileFlag ImpassableSurface = TileFlag.Impassable | TileFlag.Surface; + + private static bool m_AlwaysIgnoreDoors; + private static bool m_IgnoreMovableImpassables; + private static bool m_IgnoreSpellFields; + private static Point3D m_Goal; + + public static bool AlwaysIgnoreDoors { get { return m_AlwaysIgnoreDoors; } set { m_AlwaysIgnoreDoors = value; } } + public static bool IgnoreMovableImpassables { get { return m_IgnoreMovableImpassables; } set { m_IgnoreMovableImpassables = value; } } + public static bool IgnoreSpellFields { get { return m_IgnoreSpellFields; } set { m_IgnoreSpellFields = value; } } + public static Point3D Goal { get { return m_Goal; } set { m_Goal = value; } } + + public static void Configure() + { + Movement.Impl = new MovementImpl(); + } + + private MovementImpl() + { + } + + private bool IsOk(bool ignoreDoors, bool ignoreSpellFields, int ourZ, int ourTop, StaticTile[] tiles, List items) + { + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile check = tiles[i]; + ItemData itemData = TileData.ItemTable[check.ID & TileData.MaxItemValue]; + + if ((itemData.Flags & ImpassableSurface) != 0) // Impassable || Surface + { + int checkZ = check.Z; + int checkTop = checkZ + itemData.CalcHeight; + + if (checkTop > ourZ && ourTop > checkZ) + return false; + } + } + + for (int i = 0; i < items.Count; ++i) + { + Item item = items[i]; + int itemID = item.ItemID & TileData.MaxItemValue; + ItemData itemData = TileData.ItemTable[itemID]; + TileFlag flags = itemData.Flags; + + if ((flags & ImpassableSurface) != 0) // Impassable || Surface + { + if (ignoreDoors && ((flags & TileFlag.Door) != 0 || itemID == 0x692 || itemID == 0x846 || itemID == 0x873 || (itemID >= 0x6F5 && itemID <= 0x6F6))) + continue; + + if (ignoreSpellFields && (itemID == 0x82 || itemID == 0x3946 || itemID == 0x3956)) + continue; + + int checkZ = item.Z; + int checkTop = checkZ + itemData.CalcHeight; + + if (checkTop > ourZ && ourTop > checkZ) + return false; + } + } + + return true; + } + + private List[] m_Pools = new List[4] + { + new List(), new List(), + new List(), new List(), + }; + + private List[] m_MobPools = new List[3] + { + new List(), new List(), + new List(), + }; + + private List m_Sectors = new List(); + + private bool Check(Map map, Mobile m, List items, List mobiles, int x, int y, int startTop, int startZ, bool canSwim, bool cantWalk, out int newZ) + { + newZ = 0; + + StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y, true); + LandTile landTile = map.Tiles.GetLandTile(x, y); + + bool landBlocks = (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) != 0; + bool considerLand = !landTile.Ignored; + + if (landBlocks && canSwim && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) != 0) //Impassable, Can Swim, and Is water. Don't block it. + landBlocks = false; + else if (cantWalk && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) == 0) //Can't walk and it's not water + landBlocks = true; + + int landZ = 0, landCenter = 0, landTop = 0; + + map.GetAverageZ(x, y, ref landZ, ref landCenter, ref landTop); + + bool moveIsOk = false; + + int stepTop = startTop + StepHeight; + int checkTop = startZ + PersonHeight; + + bool ignoreDoors = (m_AlwaysIgnoreDoors || !m.Alive || m.Body.BodyID == 0x3DB || m.IsDeadBondedPet); + bool ignoreSpellFields = m is PlayerMobile && map != Map.Felucca; + + #region Tiles + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + ItemData itemData = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + TileFlag flags = itemData.Flags; + + if ((flags & ImpassableSurface) == TileFlag.Surface || (canSwim && (flags & TileFlag.Wet) != 0)) // Surface && !Impassable + { + if (cantWalk && (flags & TileFlag.Wet) == 0) + continue; + + int itemZ = tile.Z; + int itemTop = itemZ; + int ourZ = itemZ + itemData.CalcHeight; + int ourTop = ourZ + PersonHeight; + int testTop = checkTop; + + if (moveIsOk) + { + int cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + + if (cmp > 0 || (cmp == 0 && ourZ > newZ)) + continue; + } + + if (ourZ + PersonHeight > testTop) + testTop = ourZ + PersonHeight; + + if (!itemData.Bridge) + itemTop += itemData.Height; + + if (stepTop >= itemTop) + { + int landCheck = itemZ; + + if (itemData.Height >= StepHeight) + landCheck += StepHeight; + else + landCheck += itemData.Height; + + if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ) + continue; + + if (IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items)) + { + newZ = ourZ; + moveIsOk = true; + } + } + } + } + #endregion + + #region Items + for (int i = 0; i < items.Count; ++i) + { + Item item = items[i]; + ItemData itemData = item.ItemData; + TileFlag flags = itemData.Flags; + + if (!item.Movable && ((flags & ImpassableSurface) == TileFlag.Surface || (m.CanSwim && (flags & TileFlag.Wet) != 0))) // Surface && !Impassable && !Movable + { + if (cantWalk && (flags & TileFlag.Wet) == 0) + continue; + + int itemZ = item.Z; + int itemTop = itemZ; + int ourZ = itemZ + itemData.CalcHeight; + int ourTop = ourZ + PersonHeight; + int testTop = checkTop; + + if (moveIsOk) + { + int cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + + if (cmp > 0 || (cmp == 0 && ourZ > newZ)) + continue; + } + + if (ourZ + PersonHeight > testTop) + testTop = ourZ + PersonHeight; + + if (!itemData.Bridge) + itemTop += itemData.Height; + + if (stepTop >= itemTop) + { + int landCheck = itemZ; + + if (itemData.Height >= StepHeight) + landCheck += StepHeight; + else + landCheck += itemData.Height; + + if (considerLand && landCheck < landCenter && landCenter > ourZ && testTop > landZ) + continue; + + if (IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items)) + { + newZ = ourZ; + moveIsOk = true; + } + } + } + } + #endregion + + if (considerLand && !landBlocks && stepTop >= landZ) + { + int ourZ = landCenter; + int ourTop = ourZ + PersonHeight; + int testTop = checkTop; + + if (ourZ + PersonHeight > testTop) + testTop = ourZ + PersonHeight; + + bool shouldCheck = true; + + if (moveIsOk) + { + int cmp = Math.Abs(ourZ - m.Z) - Math.Abs(newZ - m.Z); + + if (cmp > 0 || (cmp == 0 && ourZ > newZ)) + shouldCheck = false; + } + + if (shouldCheck && IsOk(ignoreDoors, ignoreSpellFields, ourZ, testTop, tiles, items)) + { + newZ = ourZ; + moveIsOk = true; + } + } + + #region Mobiles + if (moveIsOk) + { + for (int i = 0; moveIsOk && i < mobiles.Count; ++i) + { + Mobile mob = mobiles[i]; + + if (mob != m && (mob.Z + 15) > newZ && (newZ + 15) > mob.Z && !CanMoveOver(m, mob)) + moveIsOk = false; + } + } + #endregion + + return moveIsOk; + } + + private bool CanMoveOver(Mobile m, Mobile t) + { + return (!t.Alive || !m.Alive || t.IsDeadBondedPet || m.IsDeadBondedPet) || (t.Hidden && t.AccessLevel > AccessLevel.Player); + } + + public bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ) + { + if (map == null || map == Map.Internal) + { + newZ = 0; + return false; + } + + int xStart = loc.X; + int yStart = loc.Y; + int xForward = xStart, yForward = yStart; + int xRight = xStart, yRight = yStart; + int xLeft = xStart, yLeft = yStart; + + bool checkDiagonals = ((int)d & 0x1) == 0x1; + + Offset(d, ref xForward, ref yForward); + Offset((Direction)(((int)d - 1) & 0x7), ref xLeft, ref yLeft); + Offset((Direction)(((int)d + 1) & 0x7), ref xRight, ref yRight); + + if (xForward < 0 || yForward < 0 || xForward >= map.Width || yForward >= map.Height) + { + newZ = 0; + return false; + } + + int startZ, startTop; + + List itemsStart = m_Pools[0]; + List itemsForward = m_Pools[1]; + List itemsLeft = m_Pools[2]; + List itemsRight = m_Pools[3]; + + bool ignoreMovableImpassables = m_IgnoreMovableImpassables; + TileFlag reqFlags = ImpassableSurface; + + if (m.CanSwim) + reqFlags |= TileFlag.Wet; + + List mobsForward = m_MobPools[0]; + List mobsLeft = m_MobPools[1]; + List mobsRight = m_MobPools[2]; + + bool checkMobs = (m is BaseCreature && !((BaseCreature)m).Controlled && (xForward != m_Goal.X || yForward != m_Goal.Y)); + + if (checkDiagonals) + { + Sector sectorStart = map.GetSector(xStart, yStart); + Sector sectorForward = map.GetSector(xForward, yForward); + Sector sectorLeft = map.GetSector(xLeft, yLeft); + Sector sectorRight = map.GetSector(xRight, yRight); + + List sectors = m_Sectors; + + sectors.Add(sectorStart); + + if (!sectors.Contains(sectorForward)) + sectors.Add(sectorForward); + + if (!sectors.Contains(sectorLeft)) + sectors.Add(sectorLeft); + + if (!sectors.Contains(sectorRight)) + sectors.Add(sectorRight); + + for (int i = 0; i < sectors.Count; ++i) + { + Sector sector = sectors[i]; + + for (int j = 0; j < sector.Items.Count; ++j) + { + Item item = sector.Items[j]; + + if (ignoreMovableImpassables && item.Movable && (item.ItemData.Flags & ImpassableSurface) != 0) + continue; + + if ((item.ItemData.Flags & reqFlags) == 0) + continue; + + if (sector == sectorStart && item.AtWorldPoint(xStart, yStart) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsStart.Add(item); + else if (sector == sectorForward && item.AtWorldPoint(xForward, yForward) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsForward.Add(item); + else if (sector == sectorLeft && item.AtWorldPoint(xLeft, yLeft) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsLeft.Add(item); + else if (sector == sectorRight && item.AtWorldPoint(xRight, yRight) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsRight.Add(item); + } + + if (checkMobs) + { + for (int j = 0; j < sector.Mobiles.Count; ++j) + { + Mobile mob = sector.Mobiles[j]; + + if (sector == sectorForward && mob.X == xForward && mob.Y == yForward) + mobsForward.Add(mob); + else if (sector == sectorLeft && mob.X == xLeft && mob.Y == yLeft) + mobsLeft.Add(mob); + else if (sector == sectorRight && mob.X == xRight && mob.Y == yRight) + mobsRight.Add(mob); + } + } + } + + if (m_Sectors.Count > 0) + m_Sectors.Clear(); + } + else + { + Sector sectorStart = map.GetSector(xStart, yStart); + Sector sectorForward = map.GetSector(xForward, yForward); + + if (sectorStart == sectorForward) + { + for (int i = 0; i < sectorStart.Items.Count; ++i) + { + Item item = sectorStart.Items[i]; + + if (ignoreMovableImpassables && item.Movable && (item.ItemData.Flags & ImpassableSurface) != 0) + continue; + + if ((item.ItemData.Flags & reqFlags) == 0) + continue; + + if (item.AtWorldPoint(xStart, yStart) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsStart.Add(item); + else if (item.AtWorldPoint(xForward, yForward) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsForward.Add(item); + } + } + else + { + for (int i = 0; i < sectorForward.Items.Count; ++i) + { + Item item = sectorForward.Items[i]; + + if (ignoreMovableImpassables && item.Movable && (item.ItemData.Flags & ImpassableSurface) != 0) + continue; + + if ((item.ItemData.Flags & reqFlags) == 0) + continue; + + if (item.AtWorldPoint(xForward, yForward) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsForward.Add(item); + } + + for (int i = 0; i < sectorStart.Items.Count; ++i) + { + Item item = sectorStart.Items[i]; + + if (ignoreMovableImpassables && item.Movable && (item.ItemData.Flags & ImpassableSurface) != 0) + continue; + + if ((item.ItemData.Flags & reqFlags) == 0) + continue; + + if (item.AtWorldPoint(xStart, yStart) && !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue) + itemsStart.Add(item); + } + } + + if (checkMobs) + { + for (int i = 0; i < sectorForward.Mobiles.Count; ++i) + { + Mobile mob = sectorForward.Mobiles[i]; + + if (mob.X == xForward && mob.Y == yForward) + mobsForward.Add(mob); + } + } + } + + GetStartZ(m, map, loc, itemsStart, out startZ, out startTop); + + bool moveIsOk = Check(map, m, itemsForward, mobsForward, xForward, yForward, startTop, startZ, m.CanSwim, m.CantWalk, out newZ); + + if (moveIsOk && checkDiagonals) + { + int hold; + + if (m.Player && m.AccessLevel < AccessLevel.GameMaster) + { + if (!Check(map, m, itemsLeft, mobsLeft, xLeft, yLeft, startTop, startZ, m.CanSwim, m.CantWalk, out hold) || !Check(map, m, itemsRight, mobsRight, xRight, yRight, startTop, startZ, m.CanSwim, m.CantWalk, out hold)) + moveIsOk = false; + } + else + { + if (!Check(map, m, itemsLeft, mobsLeft, xLeft, yLeft, startTop, startZ, m.CanSwim, m.CantWalk, out hold) && !Check(map, m, itemsRight, mobsRight, xRight, yRight, startTop, startZ, m.CanSwim, m.CantWalk, out hold)) + moveIsOk = false; + } + } + + for (int i = 0; i < (checkDiagonals ? 4 : 2); ++i) + { + if (m_Pools[i].Count != 0) + m_Pools[i].Clear(); + } + + for (int i = 0; i < (checkDiagonals ? 3 : 1); ++i) + { + if (m_MobPools[i].Count != 0) + m_MobPools[i].Clear(); + } + + if (!moveIsOk) + newZ = startZ; + + return moveIsOk; + } + + public bool CheckMovement(Mobile m, Direction d, out int newZ) + { + return CheckMovement(m, m.Map, m.Location, d, out newZ); + } + + private void GetStartZ(Mobile m, Map map, Point3D loc, List itemList, out int zLow, out int zTop) + { + int xCheck = loc.X, yCheck = loc.Y; + + LandTile landTile = map.Tiles.GetLandTile(xCheck, yCheck); + int landZ = 0, landCenter = 0, landTop = 0; + bool landBlocks = (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) != 0; + + if (landBlocks && m.CanSwim && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) != 0) + landBlocks = false; + else if (m.CantWalk && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) == 0) + landBlocks = true; + + map.GetAverageZ(xCheck, yCheck, ref landZ, ref landCenter, ref landTop); + + bool considerLand = !landTile.Ignored; + + int zCenter = zLow = zTop = 0; + bool isSet = false; + + if (considerLand && !landBlocks && loc.Z >= landCenter) + { + zLow = landZ; + zCenter = landCenter; + + if (!isSet || landTop > zTop) + zTop = landTop; + + isSet = true; + } + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles(xCheck, yCheck, true); + + for (int i = 0; i < staticTiles.Length; ++i) + { + StaticTile tile = staticTiles[i]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + int calcTop = (tile.Z + id.CalcHeight); + + if ((!isSet || calcTop >= zCenter) && ((id.Flags & TileFlag.Surface) != 0 || (m.CanSwim && (id.Flags & TileFlag.Wet) != 0)) && loc.Z >= calcTop) + { + if (m.CantWalk && (id.Flags & TileFlag.Wet) == 0) + continue; + + zLow = tile.Z; + zCenter = calcTop; + + int top = tile.Z + id.Height; + + if (!isSet || top > zTop) + zTop = top; + + isSet = true; + } + } + + for (int i = 0; i < itemList.Count; ++i) + { + Item item = itemList[i]; + + ItemData id = item.ItemData; + + int calcTop = item.Z + id.CalcHeight; + + if ((!isSet || calcTop >= zCenter) && ((id.Flags & TileFlag.Surface) != 0 || (m.CanSwim && (id.Flags & TileFlag.Wet) != 0)) && loc.Z >= calcTop) + { + if (m.CantWalk && (id.Flags & TileFlag.Wet) == 0) + continue; + + zLow = item.Z; + zCenter = calcTop; + + int top = item.Z + id.Height; + + if (!isSet || top > zTop) + zTop = top; + + isSet = true; + } + } + + if (!isSet) + zLow = zTop = loc.Z; + else if (loc.Z > zTop) + zTop = loc.Z; + } + + public void Offset(Direction d, ref int x, ref int y) + { + switch (d & Direction.Mask) + { + case Direction.North: --y; break; + case Direction.South: ++y; break; + case Direction.West: --x; break; + case Direction.East: ++x; break; + case Direction.Right: ++x; --y; break; + case Direction.Left: --x; ++y; break; + case Direction.Down: ++x; ++y; break; + case Direction.Up: --x; --y; break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/MovementPath.cs b/Scripts/Engines/Pathing/MovementPath.cs new file mode 100644 index 0000000..1bb2065 --- /dev/null +++ b/Scripts/Engines/Pathing/MovementPath.cs @@ -0,0 +1,165 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.PathAlgorithms; +using Server.PathAlgorithms.SlowAStar; +using Server.PathAlgorithms.FastAStar; +using Server.Commands; + +namespace Server +{ + public sealed class MovementPath + { + private Map m_Map; + private Point3D m_Start; + private Point3D m_Goal; + private Direction[] m_Directions; + + public Map Map{ get{ return m_Map; } } + public Point3D Start{ get{ return m_Start; } } + public Point3D Goal{ get{ return m_Goal; } } + public Direction[] Directions{ get{ return m_Directions; } } + public bool Success{ get{ return ( m_Directions != null && m_Directions.Length > 0 ); } } + + public static void Initialize() + { + CommandSystem.Register( "Path", AccessLevel.GameMaster, new CommandEventHandler( Path_OnCommand ) ); + } + + public static void Path_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, true, TargetFlags.None, new TargetCallback( Path_OnTarget ) ); + e.Mobile.SendMessage( "Target a location and a path will be drawn there." ); + } + + private static void Path( Mobile from, IPoint3D p, PathAlgorithm alg, string name, int zOffset ) + { + m_OverrideAlgorithm = alg; + + long start = DateTime.Now.Ticks; + MovementPath path = new MovementPath( from, new Point3D( p ) ); + long end = DateTime.Now.Ticks; + double len = Math.Round( (end-start) / 10000.0, 2 ); + + if ( !path.Success ) + { + from.SendMessage( "{0} path failed: {1}ms", name, len ); + } + else + { + from.SendMessage( "{0} path success: {1}ms", name, len ); + + int x = from.X; + int y = from.Y; + int z = from.Z; + + for ( int i = 0; i < path.Directions.Length; ++i ) + { + Movement.Movement.Offset( path.Directions[i], ref x, ref y ); + + new Items.RecallRune().MoveToWorld( new Point3D( x, y, z+zOffset ), from.Map ); + } + } + } + + public static void Path_OnTarget( Mobile from, object obj ) + { + IPoint3D p = obj as IPoint3D; + + if ( p == null ) + return; + + Spells.SpellHelper.GetSurfaceTop( ref p ); + + Path( from, p, FastAStarAlgorithm.Instance, "Fast", 0 ); + Path( from, p, SlowAStarAlgorithm.Instance, "Slow", 2 ); + m_OverrideAlgorithm = null; + + /*MovementPath path = new MovementPath( from, new Point3D( p ) ); + + if ( !path.Success ) + { + from.SendMessage( "No path to there could be found." ); + } + else + { + //for ( int i = 0; i < path.Directions.Length; ++i ) + // Timer.DelayCall( TimeSpan.FromSeconds( 0.1 + (i * 0.3) ), new TimerStateCallback( Pathfind ), new object[]{ from, path.Directions[i] } ); + int x = from.X; + int y = from.Y; + int z = from.Z; + + for ( int i = 0; i < path.Directions.Length; ++i ) + { + Movement.Movement.Offset( path.Directions[i], ref x, ref y ); + + new Items.RecallRune().MoveToWorld( new Point3D( x, y, z ), from.Map ); + } + }*/ + } + + public static void Pathfind( object state ) + { + object[] states = (object[])state; + Mobile from = (Mobile) states[0]; + Direction d = (Direction) states[1]; + + try + { + from.Direction = d; + from.NetState.BlockAllPackets=true; + from.Move( d ); + from.NetState.BlockAllPackets=false; + from.ProcessDelta(); + } + catch + { + } + } + + private static PathAlgorithm m_OverrideAlgorithm; + + public static PathAlgorithm OverrideAlgorithm + { + get{ return m_OverrideAlgorithm; } + set{ m_OverrideAlgorithm = value; } + } + + public MovementPath( Mobile m, Point3D goal ) + { + Point3D start = m.Location; + Map map = m.Map; + + m_Map = map; + m_Start = start; + m_Goal = goal; + + if ( map == null || map == Map.Internal ) + return; + + if ( Utility.InRange( start, goal, 1 ) ) + return; + + try + { + PathAlgorithm alg = m_OverrideAlgorithm; + + if ( alg == null ) + { + alg = FastAStarAlgorithm.Instance; + + //if ( !alg.CheckCondition( m, map, start, goal ) ) // SlowAstar is still broken + // alg = SlowAStarAlgorithm.Instance; // TODO: Fix SlowAstar + } + + if ( alg != null && alg.CheckCondition( m, map, start, goal ) ) + m_Directions = alg.Find( m, map, start, goal ); + } + catch ( Exception e ) + { + Console.WriteLine( "Warning: {0}: Pathing error from {1} to {2}", e.GetType().Name, start, goal ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/PathAlgorithm.cs b/Scripts/Engines/Pathing/PathAlgorithm.cs new file mode 100644 index 0000000..7964f98 --- /dev/null +++ b/Scripts/Engines/Pathing/PathAlgorithm.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.PathAlgorithms +{ + public abstract class PathAlgorithm + { + public abstract bool CheckCondition( Mobile m, Map map, Point3D start, Point3D goal ); + public abstract Direction[] Find( Mobile m, Map map, Point3D start, Point3D goal ); + + private static Direction[] m_CalcDirections = new Direction[9] + { + Direction.Up, + Direction.North, + Direction.Right, + Direction.West, + Direction.North, + Direction.East, + Direction.Left, + Direction.South, + Direction.Down + }; + + public Direction GetDirection( int xSource, int ySource, int xDest, int yDest ) + { + int x = xDest + 1 - xSource; + int y = yDest + 1 - ySource; + int v = (y * 3) + x; + + if ( v < 0 || v >= 9 ) + return Direction.North; + + return m_CalcDirections[v]; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/PathFollower.cs b/Scripts/Engines/Pathing/PathFollower.cs new file mode 100644 index 0000000..2d26ca9 --- /dev/null +++ b/Scripts/Engines/Pathing/PathFollower.cs @@ -0,0 +1,204 @@ +using System; +using Server; +using Server.Movement; +using CalcMoves = Server.Movement.Movement; + +namespace Server +{ + public class PathFollower + { + // Should we use pathfinding? 'false' for not + private static bool Enabled = true; + + private Mobile m_From; + private IPoint3D m_Goal; + private MovementPath m_Path; + private int m_Index; + private Point3D m_Next, m_LastGoalLoc; + private DateTime m_LastPathTime; + private MoveMethod m_Mover; + + public MoveMethod Mover + { + get{ return m_Mover; } + set{ m_Mover = value; } + } + + public IPoint3D Goal + { + get{ return m_Goal; } + } + + public PathFollower( Mobile from, IPoint3D goal ) + { + m_From = from; + m_Goal = goal; + } + + public MoveResult Move( Direction d ) + { + if ( m_Mover == null ) + return ( m_From.Move( d ) ? MoveResult.Success : MoveResult.Blocked ); + + return m_Mover( d ); + } + + public Point3D GetGoalLocation() + { + if ( m_Goal is Item ) + return ((Item)m_Goal).GetWorldLocation(); + + return new Point3D( m_Goal ); + } + + private static TimeSpan RepathDelay = TimeSpan.FromSeconds( 2.0 ); + + public void Advance( ref Point3D p, int index ) + { + if ( m_Path != null && m_Path.Success ) + { + Direction[] dirs = m_Path.Directions; + + if ( index >= 0 && index < dirs.Length ) + { + int x = p.X, y = p.Y; + + CalcMoves.Offset( dirs[index], ref x, ref y ); + + p.X = x; + p.Y = y; + } + } + } + + public void ForceRepath() + { + m_Path = null; + } + + public bool CheckPath() + { + if ( !Enabled ) + return false; + + bool repath = false; + + Point3D goal = GetGoalLocation(); + + if ( m_Path == null ) + repath = true; + else if ( (!m_Path.Success || goal != m_LastGoalLoc) && (m_LastPathTime + RepathDelay) <= DateTime.Now ) + repath = true; + else if ( m_Path.Success && Check( m_From.Location, m_LastGoalLoc, 0 ) ) + repath = true; + + if ( !repath ) + return false; + + m_LastPathTime = DateTime.Now; + m_LastGoalLoc = goal; + + m_Path = new MovementPath( m_From, goal ); + + m_Index = 0; + m_Next = m_From.Location; + + Advance( ref m_Next, m_Index ); + + return true; + } + + public bool Check( Point3D loc, Point3D goal, int range ) + { + if ( !Utility.InRange( loc, goal, range ) ) + return false; + + if ( range <= 1 && Math.Abs( loc.Z - goal.Z ) >= 16 ) + return false; + + return true; + } + + public bool Follow( bool run, int range ) + { + Point3D goal = GetGoalLocation(); + Direction d; + + if ( Check( m_From.Location, goal, range ) ) + return true; + + bool repathed = CheckPath(); + + if ( !Enabled || !m_Path.Success ) + { + d = m_From.GetDirectionTo( goal ); + + if ( run ) + d |= Direction.Running; + + m_From.SetDirection( d ); + Move( d ); + + return Check( m_From.Location, goal, range ); + } + + d = m_From.GetDirectionTo( m_Next ); + + if ( run ) + d |= Direction.Running; + + m_From.SetDirection( d ); + + MoveResult res = Move( d ); + + if ( res == MoveResult.Blocked ) + { + if ( repathed ) + return false; + + m_Path = null; + CheckPath(); + + if ( !m_Path.Success ) + { + d = m_From.GetDirectionTo( goal ); + + if ( run ) + d |= Direction.Running; + + m_From.SetDirection( d ); + Move( d ); + + return Check( m_From.Location, goal, range ); + } + + d = m_From.GetDirectionTo( m_Next ); + + if ( run ) + d |= Direction.Running; + + m_From.SetDirection( d ); + + res = Move( d ); + + if ( res == MoveResult.Blocked ) + return false; + } + + if ( m_From.X == m_Next.X && m_From.Y == m_Next.Y ) + { + if ( m_From.Z == m_Next.Z ) + { + ++m_Index; + Advance( ref m_Next, m_Index ); + } + else + { + m_Path = null; + } + } + + return Check( m_From.Location, goal, range ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs b/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs new file mode 100644 index 0000000..3e5b7df --- /dev/null +++ b/Scripts/Engines/Pathing/SlowAStarAlgorithm.cs @@ -0,0 +1,263 @@ +using System; +using Server; +using Server.Mobiles; +using Server.PathAlgorithms; +using CalcMoves = Server.Movement.Movement; +using MoveImpl = Server.Movement.MovementImpl; + +namespace Server.PathAlgorithms.SlowAStar +{ + public struct PathNode + { + public int x, y, z; + public int g, h; + public int px, py, pz; + public int dir; + } + + public class SlowAStarAlgorithm : PathAlgorithm + { + public static PathAlgorithm Instance = new SlowAStarAlgorithm(); + + private const int MaxDepth = 300; + private const int MaxNodes = MaxDepth * 16; + + private static PathNode[] m_Closed = new PathNode[MaxNodes]; + private static PathNode[] m_Open = new PathNode[MaxNodes]; + private static PathNode[] m_Successors = new PathNode[8]; + private static Direction[] m_Path = new Direction[MaxNodes]; + + private Point3D m_Goal; + + public int Heuristic( int x, int y, int z ) + { + x -= m_Goal.X; + y -= m_Goal.Y; + z -= m_Goal.Z; + + x *= 11; + y *= 11; + + return (x*x)+(y*y)+(z*z); + } + + public override bool CheckCondition( Mobile m, Map map, Point3D start, Point3D goal ) + { + return false; + } + + public override Direction[] Find( Mobile m, Map map, Point3D start, Point3D goal ) + { + m_Goal = goal; + + BaseCreature bc = m as BaseCreature; + + PathNode curNode; + + PathNode goalNode = new PathNode(); + goalNode.x = goal.X; + goalNode.y = goal.Y; + goalNode.z = goal.Z; + + PathNode startNode = new PathNode(); + startNode.x = start.X; + startNode.y = start.Y; + startNode.z = start.Z; + startNode.h = Heuristic( startNode.x, startNode.y, startNode.z ); + + PathNode[] closed = m_Closed, open = m_Open, successors = m_Successors; + Direction[] path = m_Path; + + int closedCount = 0, openCount = 0, sucCount = 0, pathCount = 0; + int popIndex, curF; + int x, y, z; + int depth = 0; + + int xBacktrack, yBacktrack, zBacktrack, iBacktrack = 0; + + open[openCount++] = startNode; + + while ( openCount > 0 ) + { + curNode = open[0]; + curF = curNode.g + curNode.h; + popIndex = 0; + + for ( int i = 1; i < openCount; ++i ) + { + if ( (open[i].g + open[i].h) < curF ) + { + curNode = open[i]; + curF = curNode.g + curNode.h; + popIndex = i; + } + } + + if ( curNode.x == goalNode.x && curNode.y == goalNode.y && Math.Abs( curNode.z-goalNode.z ) < 16 ) + { + if ( closedCount == MaxNodes ) + break; + + closed[closedCount++] = curNode; + + xBacktrack = curNode.px; + yBacktrack = curNode.py; + zBacktrack = curNode.pz; + + if ( pathCount == MaxNodes ) + break; + + path[pathCount++] = (Direction)curNode.dir; + + while ( xBacktrack != startNode.x || yBacktrack != startNode.y || zBacktrack != startNode.z ) + { + bool found = false; + + for ( int j = 0; !found && j < closedCount; ++j ) + { + if ( closed[j].x == xBacktrack && closed[j].y == yBacktrack && closed[j].z == zBacktrack ) + { + if ( pathCount == MaxNodes ) + break; + + curNode = closed[j]; + path[pathCount++] = (Direction)curNode.dir; + xBacktrack = curNode.px; + yBacktrack = curNode.py; + zBacktrack = curNode.pz; + found = true; + } + } + + if ( !found ) + { + Console.WriteLine( "bugaboo.." ); + return null; + } + + if ( pathCount == MaxNodes ) + break; + } + + if ( pathCount == MaxNodes ) + break; + + Direction[] dirs = new Direction[pathCount]; + + while ( pathCount > 0 ) + dirs[iBacktrack++] = path[--pathCount]; + + return dirs; + } + + --openCount; + + for ( int i = popIndex; i < openCount; ++i ) + open[i] = open[i + 1]; + + sucCount = 0; + + if ( bc != null ) + { + MoveImpl.AlwaysIgnoreDoors = bc.CanOpenDoors; + MoveImpl.IgnoreMovableImpassables = bc.CanMoveOverObstacles; + } + + MoveImpl.Goal = goal; + + for ( int i = 0; i < 8; ++i ) + { + switch ( i ) + { + default: + case 0: x = 0; y = -1; break; + case 1: x = 1; y = -1; break; + case 2: x = 1; y = 0; break; + case 3: x = 1; y = 1; break; + case 4: x = 0; y = 1; break; + case 5: x = -1; y = 1; break; + case 6: x = -1; y = 0; break; + case 7: x = -1; y = -1; break; + } + + if ( CalcMoves.CheckMovement( m, map, new Point3D( curNode.x, curNode.y, curNode.z ), (Direction)i, out z ) ) + { + successors[sucCount].x = x + curNode.x; + successors[sucCount].y = y + curNode.y; + successors[sucCount++].z = z; + } + } + + MoveImpl.AlwaysIgnoreDoors = false; + MoveImpl.IgnoreMovableImpassables = false; + MoveImpl.Goal = Point3D.Zero; + + if ( sucCount == 0 || ++depth > MaxDepth ) + break; + + for ( int i = 0; i < sucCount; ++i ) + { + x = successors[i].x; + y = successors[i].y; + z = successors[i].z; + + successors[i].g = curNode.g + 1; + + int openIndex = -1, closedIndex = -1; + + for ( int j = 0; openIndex == -1 && j < openCount; ++j ) + { + if ( open[j].x == x && open[j].y == y && open[j].z == z ) + openIndex = j; + } + + if ( openIndex >= 0 && open[openIndex].g < successors[i].g ) + continue; + + for ( int j = 0; closedIndex == -1 && j < closedCount; ++j ) + { + if ( closed[j].x == x && closed[j].y == y && closed[j].z == z ) + closedIndex = j; + } + + if ( closedIndex >= 0 && closed[closedIndex].g < successors[i].g ) + continue; + + if ( openIndex >= 0 ) + { + --openCount; + + for ( int j = openIndex; j < openCount; ++j ) + open[j] = open[j + 1]; + } + + if ( closedIndex >= 0 ) + { + --closedCount; + + for ( int j = closedIndex; j < closedCount; ++j ) + closed[j] = closed[j + 1]; + } + + successors[i].px = curNode.x; + successors[i].py = curNode.y; + successors[i].pz = curNode.z; + successors[i].dir = (int)GetDirection( curNode.x, curNode.y, x, y ); + successors[i].h = Heuristic( x, y, z ); + + if ( openCount == MaxNodes ) + break; + + open[openCount++] = successors[i]; + } + + if ( openCount == MaxNodes || closedCount == MaxNodes ) + break; + + closed[closedCount++] = curNode; + } + + return null; + } + } +} diff --git a/Scripts/Engines/Plants/EmptyTheBowlGump.cs b/Scripts/Engines/Plants/EmptyTheBowlGump.cs new file mode 100644 index 0000000..fcade1f --- /dev/null +++ b/Scripts/Engines/Plants/EmptyTheBowlGump.cs @@ -0,0 +1,123 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Plants +{ + public class EmptyTheBowlGump : Gump + { + private PlantItem m_Plant; + + public EmptyTheBowlGump( PlantItem plant ) : base( 20, 20 ) + { + m_Plant = plant; + + DrawBackground(); + + AddLabel( 90, 70, 0x44, "Empty the bowl?" ); + + DrawPicture(); + + AddButton( 98, 150, 0x47E, 0x480, 1, GumpButtonType.Reply, 0 ); // Cancel + + AddButton( 138, 151, 0xD2, 0xD2, 2, GumpButtonType.Reply, 0 ); // Help + AddLabel( 143, 151, 0x835, "?" ); + + AddButton( 168, 150, 0x481, 0x483, 3, GumpButtonType.Reply, 0 ); // Ok + } + + private void DrawBackground() + { + AddBackground( 50, 50, 200, 150, 0xE10 ); + + AddItem( 45, 45, 0xCEF ); + AddItem( 45, 118, 0xCF0 ); + + AddItem( 211, 45, 0xCEB ); + AddItem( 211, 118, 0xCEC ); + } + + private void DrawPicture() + { + AddItem( 90, 100, 0x1602 ); + AddImage( 140, 102, 0x15E1 ); + AddItem( 160, 100, 0x15FD ); + + if ( m_Plant.PlantStatus != PlantStatus.BowlOfDirt && m_Plant.PlantStatus < PlantStatus.Plant ) + AddItem( 156, 130, 0xDCF ); // Seed + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 0 || m_Plant.Deleted || m_Plant.PlantStatus >= PlantStatus.DecorativePlant ) + return; + + if ( info.ButtonID == 3 && !from.InRange( m_Plant.GetWorldLocation(), 3 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 500446 ); // That is too far away. + return; + } + + if ( !m_Plant.IsUsableBy( from ) ) + { + m_Plant.LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + return; + } + + switch ( info.ButtonID ) + { + case 1: // Cancel + { + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 2: // Help + { + from.Send( new DisplayHelpTopic( 71, true ) ); // EMPTYING THE BOWL + + from.SendGump( new EmptyTheBowlGump( m_Plant ) ); + + break; + } + case 3: // Ok + { + PlantBowl bowl = new PlantBowl(); + + if ( !from.PlaceInBackpack( bowl ) ) + { + bowl.Delete(); + + m_Plant.LabelTo( from, 1053047 ); // You cannot empty a bowl with a full pack! + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + + if ( m_Plant.PlantStatus != PlantStatus.BowlOfDirt && m_Plant.PlantStatus < PlantStatus.Plant ) + { + Seed seed = new Seed( m_Plant.PlantType, m_Plant.PlantHue, m_Plant.ShowType ); + + if ( !from.PlaceInBackpack( seed ) ) + { + bowl.Delete(); + seed.Delete(); + + m_Plant.LabelTo( from, 1053047 ); // You cannot empty a bowl with a full pack! + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + } + + m_Plant.Delete(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/MainPlantGump.cs b/Scripts/Engines/Plants/MainPlantGump.cs new file mode 100644 index 0000000..f7f7c05 --- /dev/null +++ b/Scripts/Engines/Plants/MainPlantGump.cs @@ -0,0 +1,424 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Plants +{ + public class MainPlantGump : Gump + { + private PlantItem m_Plant; + + public MainPlantGump( PlantItem plant ) : base( 20, 20 ) + { + m_Plant = plant; + + DrawBackground(); + + DrawPlant(); + + AddButton( 71, 67, 0xD4, 0xD4, 1, GumpButtonType.Reply, 0 ); // Reproduction menu + AddItem( 59, 68, 0xD08 ); + + PlantSystem system = plant.PlantSystem; + + AddButton( 71, 91, 0xD4, 0xD4, 2, GumpButtonType.Reply, 0 ); // Infestation + AddItem( 8, 96, 0x372 ); + AddPlus( 95, 92, system.Infestation ); + + AddButton( 71, 115, 0xD4, 0xD4, 3, GumpButtonType.Reply, 0 ); // Fungus + AddItem( 58, 115, 0xD16 ); + AddPlus( 95, 116, system.Fungus ); + + AddButton( 71, 139, 0xD4, 0xD4, 4, GumpButtonType.Reply, 0 ); // Poison + AddItem( 59, 143, 0x1AE4 ); + AddPlus( 95, 140, system.Poison ); + + AddButton( 71, 163, 0xD4, 0xD4, 5, GumpButtonType.Reply, 0 ); // Disease + AddItem( 55, 167, 0x1727 ); + AddPlus( 95, 164, system.Disease ); + + AddButton( 209, 67, 0xD2, 0xD2, 6, GumpButtonType.Reply, 0 ); // Water + AddItem( 193, 67, 0x1F9D ); + AddPlusMinus( 196, 67, system.Water ); + + AddButton( 209, 91, 0xD4, 0xD4, 7, GumpButtonType.Reply, 0 ); // Poison potion + AddItem( 201, 91, 0xF0A ); + AddLevel( 196, 91, system.PoisonPotion ); + + AddButton( 209, 115, 0xD4, 0xD4, 8, GumpButtonType.Reply, 0 ); // Cure potion + AddItem( 201, 115, 0xF07 ); + AddLevel( 196, 115, system.CurePotion ); + + AddButton( 209, 139, 0xD4, 0xD4, 9, GumpButtonType.Reply, 0 ); // Heal potion + AddItem( 201, 139, 0xF0C ); + AddLevel( 196, 139, system.HealPotion ); + + AddButton( 209, 163, 0xD4, 0xD4, 10, GumpButtonType.Reply, 0 ); // Strength potion + AddItem( 201, 163, 0xF09 ); + AddLevel( 196, 163, system.StrengthPotion ); + + AddImage( 48, 47, 0xD2 ); + AddLevel( 54, 47, (int)m_Plant.PlantStatus ); + + AddImage( 232, 47, 0xD2 ); + AddGrowthIndicator( 239, 47 ); + + AddButton( 48, 183, 0xD2, 0xD2, 11, GumpButtonType.Reply, 0 ); // Help + AddLabel( 54, 183, 0x835, "?" ); + + AddButton( 232, 183, 0xD4, 0xD4, 12, GumpButtonType.Reply, 0 ); // Empty the bowl + AddItem( 219, 180, 0x15FD ); + } + + private void DrawBackground() + { + AddBackground( 50, 50, 200, 150, 0xE10 ); + + AddItem( 45, 45, 0xCEF ); + AddItem( 45, 118, 0xCF0 ); + + AddItem( 211, 45, 0xCEB ); + AddItem( 211, 118, 0xCEC ); + } + + private void DrawPlant() + { + PlantStatus status = m_Plant.PlantStatus; + + if ( status < PlantStatus.FullGrownPlant ) + { + AddImage( 110, 85, 0x589 ); + + AddItem( 122, 94, 0x914 ); + AddItem( 135, 94, 0x914 ); + AddItem( 120, 112, 0x914 ); + AddItem( 135, 112, 0x914 ); + + if ( status >= PlantStatus.Stage2 ) + { + AddItem( 127, 112, 0xC62 ); + } + if ( status == PlantStatus.Stage3 || status == PlantStatus.Stage4 ) + { + AddItem( 129, 85, 0xC7E ); + } + if ( status >= PlantStatus.Stage4 ) + { + AddItem( 121, 117, 0xC62 ); + AddItem( 133, 117, 0xC62 ); + } + if ( status >= PlantStatus.Stage5 ) + { + AddItem( 110, 100, 0xC62 ); + AddItem( 140, 100, 0xC62 ); + AddItem( 110, 130, 0xC62 ); + AddItem( 140, 130, 0xC62 ); + } + if ( status >= PlantStatus.Stage6 ) + { + AddItem( 105, 115, 0xC62 ); + AddItem( 145, 115, 0xC62 ); + AddItem( 125, 90, 0xC62 ); + AddItem( 125, 135, 0xC62 ); + } + } + else + { + PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo( m_Plant.PlantType ); + PlantHueInfo hueInfo = PlantHueInfo.GetInfo( m_Plant.PlantHue ); + + // The large images for these trees trigger a client crash, so use a smaller, generic tree. + if ( m_Plant.PlantType == PlantType.CypressTwisted || m_Plant.PlantType == PlantType.CypressStraight ) + AddItem( 130 + typeInfo.OffsetX, 96 + typeInfo.OffsetY, 0x0CCA, hueInfo.Hue ); + else + AddItem( 130 + typeInfo.OffsetX, 96 + typeInfo.OffsetY, typeInfo.ItemID, hueInfo.Hue ); + } + + if ( status != PlantStatus.BowlOfDirt ) + { + int message = m_Plant.PlantSystem.GetLocalizedHealth(); + + switch ( m_Plant.PlantSystem.Health ) + { + case PlantHealth.Dying: + { + AddItem( 92, 167, 0x1B9D ); + AddItem( 161, 167, 0x1B9D ); + + AddHtmlLocalized( 136, 167, 42, 20, message, 0x00FC00, false, false ); + + break; + } + case PlantHealth.Wilted: + { + AddItem( 91, 164, 0x18E6 ); + AddItem( 161, 164, 0x18E6 ); + + AddHtmlLocalized( 132, 167, 42, 20, message, 0x00C207, false, false ); + + break; + } + case PlantHealth.Healthy: + { + AddItem( 96, 168, 0xC61 ); + AddItem( 162, 168, 0xC61 ); + + AddHtmlLocalized( 129, 167, 42, 20, message, 0x008200, false, false ); + + break; + } + case PlantHealth.Vibrant: + { + AddItem( 93, 162, 0x1A99 ); + AddItem( 162, 162, 0x1A99 ); + + AddHtmlLocalized( 129, 167, 42, 20, message, 0x0083E0, false, false ); + + break; + } + } + } + } + + private void AddPlus( int x, int y, int value ) + { + switch ( value ) + { + case 1: AddLabel( x, y, 0x35, "+" ); break; + case 2: AddLabel( x, y, 0x21, "+" ); break; + } + } + + private void AddPlusMinus( int x, int y, int value ) + { + switch ( value ) + { + case 0: AddLabel( x, y, 0x21, "-" ); break; + case 1: AddLabel( x, y, 0x35, "-" ); break; + case 3: AddLabel( x, y, 0x35, "+" ); break; + case 4: AddLabel( x, y, 0x21, "+" ); break; + } + } + + private void AddLevel( int x, int y, int value ) + { + AddLabel( x, y, 0x835, value.ToString() ); + } + + private void AddGrowthIndicator( int x, int y ) + { + if ( !m_Plant.IsGrowable ) + return; + + switch ( m_Plant.PlantSystem.GrowthIndicator ) + { + case PlantGrowthIndicator.InvalidLocation : AddLabel( x, y, 0x21, "!" ); break; + case PlantGrowthIndicator.NotHealthy : AddLabel( x, y, 0x21, "-" ); break; + case PlantGrowthIndicator.Delay : AddLabel( x, y, 0x35, "-" ); break; + case PlantGrowthIndicator.Grown : AddLabel( x, y, 0x3, "+" ); break; + case PlantGrowthIndicator.DoubleGrown : AddLabel( x, y, 0x3F, "+" ); break; + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 0 || m_Plant.Deleted || m_Plant.PlantStatus >= PlantStatus.DecorativePlant ) + return; + + if ( ( ( info.ButtonID >= 6 && info.ButtonID <= 10 ) || info.ButtonID == 12 ) && !from.InRange( m_Plant.GetWorldLocation(), 3 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 500446 ); // That is too far away. + return; + } + + if ( !m_Plant.IsUsableBy( from ) ) + { + m_Plant.LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + return; + } + + switch ( info.ButtonID ) + { + case 1: // Reproduction menu + { + if ( m_Plant.PlantStatus > PlantStatus.BowlOfDirt ) + { + from.SendGump( new ReproductionGump( m_Plant ) ); + } + else + { + from.SendLocalizedMessage( 1061885 ); // You need to plant a seed in the bowl first. + + from.SendGump( new MainPlantGump( m_Plant ) ); + } + + break; + } + case 2: // Infestation + { + from.Send( new DisplayHelpTopic( 54, true ) ); // INFESTATION LEVEL + + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 3: // Fungus + { + from.Send( new DisplayHelpTopic( 56, true ) ); // FUNGUS LEVEL + + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 4: // Poison + { + from.Send( new DisplayHelpTopic( 58, true ) ); // POISON LEVEL + + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 5: // Disease + { + from.Send( new DisplayHelpTopic( 60, true ) ); // DISEASE LEVEL + + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 6: // Water + { + Item[] item = from.Backpack.FindItemsByType( typeof( BaseBeverage ) ); + + bool foundUsableWater = false; + + if ( item != null && item.Length > 0 ) + { + for ( int i = 0; i < item.Length; ++i ) + { + BaseBeverage beverage = (BaseBeverage)item[i]; + + if ( !beverage.IsEmpty && beverage.Pourable && beverage.Content == BeverageType.Water ) + { + foundUsableWater = true; + m_Plant.Pour( from, beverage ); + break; + } + } + } + + if ( !foundUsableWater ) + { + from.Target = new PlantPourTarget( m_Plant ); + from.SendLocalizedMessage( 1060808, "#" + m_Plant.GetLocalizedPlantStatus().ToString() ); // Target the container you wish to use to water the ~1_val~. + } + + if ( from.HasGump( typeof(MainPlantGump) ) ) + from.CloseGump( typeof( MainPlantGump ) ); + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 7: // Poison potion + { + AddPotion( from, PotionEffect.PoisonGreater, PotionEffect.PoisonDeadly ); + + break; + } + case 8: // Cure potion + { + AddPotion( from, PotionEffect.CureGreater ); + + break; + } + case 9: // Heal potion + { + AddPotion( from, PotionEffect.HealGreater ); + + break; + } + case 10: // Strength potion + { + AddPotion( from, PotionEffect.StrengthGreater ); + + break; + } + case 11: // Help + { + from.Send( new DisplayHelpTopic( 48, true ) ); // PLANT GROWING + + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 12: // Empty the bowl + { + from.SendGump( new EmptyTheBowlGump( m_Plant ) ); + + break; + } + } + } + + private void AddPotion( Mobile from, params PotionEffect[] effects ) + { + Item item = GetPotion( from, effects ); + + if ( item != null ) + { + m_Plant.Pour( from, item ); + } + else + { + int message; + if ( m_Plant.ApplyPotion( effects[0], true, out message ) ) + { + from.SendLocalizedMessage( 1061884 ); // You don't have any strong potions of that type in your pack. + + from.Target = new PlantPourTarget( m_Plant ); + from.SendLocalizedMessage( 1060808, "#" + m_Plant.GetLocalizedPlantStatus().ToString() ); // Target the container you wish to use to water the ~1_val~. + + return; + } + else + { + m_Plant.LabelTo( from, message ); + } + } + + from.SendGump( new MainPlantGump( m_Plant ) ); + } + + public static Item GetPotion( Mobile from, PotionEffect[] effects ) + { + if ( from.Backpack == null ) + return null; + + Item[] items = from.Backpack.FindItemsByType( new Type[] { typeof( BasePotion ), typeof( PotionKeg ) } ); + + foreach ( Item item in items ) + { + if ( item is BasePotion ) + { + BasePotion potion = (BasePotion)item; + + if ( Array.IndexOf( effects, potion.PotionEffect ) >= 0 ) + return potion; + } + else + { + PotionKeg keg = (PotionKeg)item; + + if ( keg.Held > 0 && Array.IndexOf( effects, keg.Type ) >= 0 ) + return keg; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/MiscItems/FertileDirt.cs b/Scripts/Engines/Plants/MiscItems/FertileDirt.cs new file mode 100644 index 0000000..b48a6a6 --- /dev/null +++ b/Scripts/Engines/Plants/MiscItems/FertileDirt.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + // Scriptiz : on en fait un r�actif pour la n�cro + // public class FertileDirt : Item + public class FertileDirt : BaseReagent, ICommodity + { + // Scriptiz : ajout du ICommodity + string Description + { + get + { + return String.Format("{0} fertile dirt", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public FertileDirt() : this( 1 ) + { + } + + [Constructable] + public FertileDirt( int amount ) : base( 0xF81 ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public FertileDirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/MiscItems/GreenThorns.cs b/Scripts/Engines/Plants/MiscItems/GreenThorns.cs new file mode 100644 index 0000000..ae080c6 --- /dev/null +++ b/Scripts/Engines/Plants/MiscItems/GreenThorns.cs @@ -0,0 +1,727 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Network; + +namespace Server.Items +{ + public class GreenThorns : Item + { + public override int LabelNumber { get { return 1060837; } } // green thorns + + [Constructable] + public GreenThorns() : this( 1 ) + { + } + + [Constructable] + public GreenThorns( int amount ) : base( 0xF42 ) + { + Stackable = true; + Weight = 1.0; + Hue = 0x42; + Amount = amount; + } + + public GreenThorns( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + if ( !from.CanBeginAction( typeof( GreenThorns ) ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061908 ); // * You must wait a while before planting another thorn. * + return; + } + + from.Target = new InternalTarget( this ); + from.SendLocalizedMessage( 1061906 ); // Choose a spot to plant the thorn. + } + + private class InternalTarget : Target + { + private GreenThorns m_Thorn; + + public InternalTarget( GreenThorns thorn ) : base( 3, true, TargetFlags.None ) + { + m_Thorn = thorn; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Thorn.Deleted ) + return; + + if ( !m_Thorn.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + if ( !from.CanBeginAction( typeof( GreenThorns ) ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061908 ); // * You must wait a while before planting another thorn. * + return; + } + + if ( from.Map != Map.Trammel && from.Map != Map.Felucca ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x2B2, true, "No solen lairs exist on this facet. Try again in Trammel or Felucca." ); + return; + } + + LandTarget land = targeted as LandTarget; + + if ( land == null ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061912 ); // * You cannot plant a green thorn there! * + } + else + { + GreenThornsEffect effect = GreenThornsEffect.Create( from, land ); + + if ( effect == null ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061913 ); // * You sense it would be useless to plant a green thorn there. * + } + else + { + m_Thorn.Consume(); + + from.LocalOverheadMessage( MessageType.Emote, 0x961, 1061914 ); // * You push the strange green thorn into the ground * + from.NonlocalOverheadMessage( MessageType.Emote, 0x961, 1061915, from.Name ); // * ~1_PLAYER_NAME~ pushes a strange green thorn into the ground. * + + from.BeginAction( typeof( GreenThorns ) ); + new GreenThorns.EndActionTimer( from ).Start(); + + effect.Start(); + } + } + } + + protected override void OnTargetOutOfRange( Mobile from, object targeted ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502825 ); // That location is too far away + } + } + + private class EndActionTimer : Timer + { + private Mobile m_From; + + public EndActionTimer( Mobile from ) : base( TimeSpan.FromMinutes( 3.0 ) ) + { + m_From = from; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_From.EndAction( typeof( GreenThorns ) ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class GreenThornsEffect : Timer + { + private class TilesAndEffect + { + private int[] m_Tiles; + private Type m_Effect; + + public int[] Tiles { get { return m_Tiles; } } + public Type Effect { get { return m_Effect; } } + + public TilesAndEffect( int[] tiles, Type effect ) + { + m_Tiles = tiles; + m_Effect = effect; + } + } + + private static TilesAndEffect[] m_Table = new TilesAndEffect[] + { + new TilesAndEffect( new int[] + { + 0x71, 0x7C, + 0x82, 0xA7, + 0xDC, 0xE3, + 0xE8, 0xEB, + 0x141, 0x144, + 0x14C, 0x14F, + 0x169, 0x174, + 0x1DC, 0x1E7, + 0x1EC, 0x1EF, + 0x272, 0x275, + 0x27E, 0x281, + 0x2D0, 0x2D7, + 0x2E5, 0x2FF, + 0x303, 0x31F, + 0x32C, 0x32F, + 0x33D, 0x340, + 0x345, 0x34C, + 0x355, 0x358, + 0x367, 0x36E, + 0x377, 0x37A, + 0x38D, 0x390, + 0x395, 0x39C, + 0x3A5, 0x3A8, + 0x3F6, 0x405, + 0x547, 0x54E, + 0x553, 0x556, + 0x597, 0x59E, + 0x623, 0x63A, + 0x6F3, 0x6FA, + 0x777, 0x791, + 0x79A, 0x7A9, + 0x7AE, 0x7B1, + }, + typeof( DirtGreenThornsEffect ) ), + + new TilesAndEffect( new int[] + { + 0x9, 0x15, + 0x150, 0x15C + }, + typeof( FurrowsGreenThornsEffect ) ), + + new TilesAndEffect( new int[] + { + 0x9C4, 0x9EB, + 0x3D65, 0x3D65, + 0x3DC0, 0x3DD9, + 0x3DDB, 0x3DDC, + 0x3DDE, 0x3EF0, + 0x3FF6, 0x3FF6, + 0x3FFC, 0x3FFE, + }, + typeof( SwampGreenThornsEffect ) ), + + new TilesAndEffect( new int[] + { + 0x10C, 0x10F, + 0x114, 0x117, + 0x119, 0x11D, + 0x179, 0x18A, + 0x385, 0x38C, + 0x391, 0x394, + 0x39D, 0x3A4, + 0x3A9, 0x3AC, + 0x5BF, 0x5D6, + 0x5DF, 0x5E2, + 0x745, 0x748, + 0x751, 0x758, + 0x75D, 0x760, + 0x76D, 0x773 + }, + typeof( SnowGreenThornsEffect ) ), + + new TilesAndEffect( new int[] + { + 0x16, 0x3A, + 0x44, 0x4B, + 0x11E, 0x121, + 0x126, 0x12D, + 0x192, 0x192, + 0x1A8, 0x1AB, + 0x1B9, 0x1D1, + 0x282, 0x285, + 0x28A, 0x291, + 0x335, 0x33C, + 0x341, 0x344, + 0x34D, 0x354, + 0x359, 0x35C, + 0x3B7, 0x3BE, + 0x3C7, 0x3CA, + 0x5A7, 0x5B2, + 0x64B, 0x652, + 0x657, 0x65A, + 0x663, 0x66A, + 0x66F, 0x672, + 0x7BD, 0x7D0 + }, + typeof( SandGreenThornsEffect ) ) + }; + + public static GreenThornsEffect Create( Mobile from, LandTarget land ) + { + if ( !from.Map.CanSpawnMobile( land.Location ) ) + return null; + + int tileID = land.TileID; + + foreach ( TilesAndEffect taep in m_Table ) + { + bool contains = false; + + for ( int i = 0; !contains && i < taep.Tiles.Length; i += 2 ) + contains = ( tileID >= taep.Tiles[i] && tileID <= taep.Tiles[i + 1] ); + + if ( contains ) + { + GreenThornsEffect effect = (GreenThornsEffect)Activator.CreateInstance( taep.Effect, new object[] { land.Location, from.Map, from } ); + return effect; + } + } + + return null; + } + + private Point3D m_Location; + private Map m_Map; + private Mobile m_From; + + public Point3D Location { get { return m_Location; } } + public Map Map { get { return m_Map; } } + public Mobile From { get { return m_From; } } + + public GreenThornsEffect( Point3D location, Map map, Mobile from ) : base( TimeSpan.FromSeconds( 2.5 ) ) + { + m_Location = location; + m_Map = map; + m_From = from; + + Priority = TimerPriority.TwoFiftyMS; + } + + private int m_Step; + + protected override void OnTick() + { + TimeSpan nextDelay = Play( m_Step++ ); + + if ( nextDelay > TimeSpan.Zero ) + { + Delay = nextDelay; + + Start(); + } + } + + protected abstract TimeSpan Play( int step ); + + protected bool SpawnItem( Item item ) + { + for ( int i = 0; i < 5; i++ ) // Try 5 times + { + int x = Location.X + Utility.RandomMinMax( -1, 1 ); + int y = Location.Y + Utility.RandomMinMax( -1, 1 ); + int z = Map.GetAverageZ( x, y ); + + if ( Map.CanFit( x, y, Location.Z, 1 ) ) + { + item.MoveToWorld( new Point3D( x, y, Location.Z ), Map ); + return true; + } + else if ( Map.CanFit( x, y, z, 1 ) ) + { + item.MoveToWorld( new Point3D( x, y, z ), Map ); + return true; + } + } + + return false; + } + + protected bool SpawnCreature( BaseCreature creature ) + { + for ( int i = 0; i < 5; i++ ) // Try 5 times + { + int x = Location.X + Utility.RandomMinMax( -1, 1 ); + int y = Location.Y + Utility.RandomMinMax( -1, 1 ); + int z = Map.GetAverageZ( x, y ); + + if ( Map.CanSpawnMobile( x, y, Location.Z ) ) + { + creature.MoveToWorld( new Point3D( x, y, Location.Z ), Map ); + creature.Combatant = From; + return true; + } + else if ( Map.CanSpawnMobile( x, y, z ) ) + { + creature.MoveToWorld( new Point3D( x, y, z ), Map ); + creature.Combatant = From; + return true; + } + } + + return false; + } + } + + public class DirtGreenThornsEffect : GreenThornsEffect + { + public DirtGreenThornsEffect( Point3D location, Map map, Mobile from ) : base( location, map, from ) + { + } + + protected override TimeSpan Play( int step ) + { + switch ( step ) + { + case 0: + { + Effects.PlaySound( Location, Map, 0x106 ); + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3735, 1, 182, 0xBE3 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 1: + { + Effects.PlaySound( Location, Map, 0x222 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 2: + { + Effects.PlaySound( Location, Map, 0x21F ); + + return TimeSpan.FromSeconds( 5.0 ); + } + case 3: + { + EffectItem dummy = EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 20.0 ) ); + dummy.PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* The ground erupts with chaotic growth! *" ); + + Effects.PlaySound( Location, Map, 0x12D ); + + SpawnReagents(); + SpawnReagents(); + + return TimeSpan.FromSeconds( 2.0 ); + } + case 4: + { + Effects.PlaySound( Location, Map, 0x12D ); + + SpawnReagents(); + SpawnReagents(); + + return TimeSpan.FromSeconds( 2.0 ); + } + case 5: + { + Effects.PlaySound( Location, Map, 0x12D ); + + SpawnReagents(); + SpawnReagents(); + + return TimeSpan.FromSeconds( 3.0 ); + } + default: + { + Effects.PlaySound( Location, Map, 0x12D ); + + SpawnReagents(); + SpawnReagents(); + + return TimeSpan.Zero; + } + } + } + + private void SpawnReagents() + { + Item reagents; + int amount = Utility.RandomMinMax( 10, 25 ); + + switch ( Utility.Random( 9 ) ) + { + case 0: reagents = new BlackPearl( amount ); break; + case 1: reagents = new Bloodmoss( amount ); break; + case 2: reagents = new Garlic( amount ); break; + case 3: reagents = new Ginseng( amount ); break; + case 4: reagents = new MandrakeRoot( amount ); break; + case 5: reagents = new Nightshade( amount ); break; + case 6: reagents = new SulfurousAsh( amount ); break; + case 7: reagents = new SpidersSilk( amount ); break; + default: reagents = new FertileDirt( amount ); break; + } + + if ( !SpawnItem( reagents ) ) + reagents.Delete(); + } + } + + public class FurrowsGreenThornsEffect : GreenThornsEffect + { + public FurrowsGreenThornsEffect( Point3D location, Map map, Mobile from ) : base( location, map, from ) + { + } + + protected override TimeSpan Play( int step ) + { + switch ( step ) + { + case 0: + { + Effects.PlaySound( Location, Map, 0x106 ); + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3735, 1, 182, 0xBE3 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 1: + { + EffectItem hole = EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 10.0 ) ); + hole.ItemID = 0x913; + + Effects.PlaySound( Location, Map, 0x222 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 2: + { + Effects.PlaySound( Location, Map, 0x21F ); + + return TimeSpan.FromSeconds( 4.0 ); + } + default: + { + EffectItem dummy = EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 20.0 ) ); + dummy.PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* A magical bunny leaps out of its hole, disturbed by the thorn's effect! *" ); + + BaseCreature spawn = new VorpalBunny(); + if ( !SpawnCreature( spawn ) ) + spawn.Delete(); + + return TimeSpan.Zero; + } + } + } + } + + public class SwampGreenThornsEffect : GreenThornsEffect + { + public SwampGreenThornsEffect( Point3D location, Map map, Mobile from ) : base( location, map, from ) + { + } + + protected override TimeSpan Play( int step ) + { + switch ( step ) + { + case 0: + { + Effects.PlaySound( Location, Map, 0x106 ); + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3735, 1, 182, 0xBE3 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 1: + { + Effects.PlaySound( Location, Map, 0x222 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 2: + { + Effects.PlaySound( Location, Map, 0x21F ); + + return TimeSpan.FromSeconds( 1.0 ); + } + default: + { + EffectItem dummy = EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 20.0 ) ); + dummy.PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* Strange green tendrils rise from the ground, whipping wildly! *" ); + Effects.PlaySound( Location, Map, 0x2B0 ); + + BaseCreature spawn = new WhippingVine(); + if ( !SpawnCreature( spawn ) ) + spawn.Delete(); + + return TimeSpan.Zero; + } + } + } + } + + public class SnowGreenThornsEffect : GreenThornsEffect + { + public SnowGreenThornsEffect( Point3D location, Map map, Mobile from ) : base( location, map, from ) + { + } + + protected override TimeSpan Play( int step ) + { + switch ( step ) + { + case 0: + { + Effects.PlaySound( Location, Map, 0x106 ); + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3735, 1, 182, 0xBE3 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 1: + { + Effects.PlaySound( Location, Map, 0x222 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 2: + { + Effects.PlaySound( Location, Map, 0x21F ); + + return TimeSpan.FromSeconds( 4.0 ); + } + default: + { + EffectItem dummy = EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 20.0 ) ); + dummy.PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* Slithering ice serpents rise to the surface to investigate the disturbance! *" ); + + BaseCreature spawn = new GiantIceWorm(); + if ( !SpawnCreature( spawn ) ) + spawn.Delete(); + + for ( int i = 0; i < 3; i++ ) + { + BaseCreature snake = new IceSnake(); + if ( !SpawnCreature( snake ) ) + snake.Delete(); + } + + return TimeSpan.Zero; + } + } + } + } + + public class SandGreenThornsEffect : GreenThornsEffect + { + public SandGreenThornsEffect( Point3D location, Map map, Mobile from ) : base( location, map, from ) + { + } + + protected override TimeSpan Play( int step ) + { + switch ( step ) + { + case 0: + { + Effects.PlaySound( Location, Map, 0x106 ); + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3735, 1, 182, 0xBE3 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 1: + { + Effects.PlaySound( Location, Map, 0x222 ); + + return TimeSpan.FromSeconds( 4.0 ); + } + case 2: + { + Effects.PlaySound( Location, Map, 0x21F ); + + return TimeSpan.FromSeconds( 5.0 ); + } + default: + { + EffectItem dummy = EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 20.0 ) ); + dummy.PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* The sand collapses, revealing a dark hole. *" ); + + GreenThornsSHTeleporter.Create( Location, Map ); + + return TimeSpan.Zero; + } + } + } + } + + public class GreenThornsSHTeleporter : Item + { + public static readonly Point3D Destination = new Point3D( 5738, 1856, 0 ); + + public static void Create( Point3D location, Map map ) + { + GreenThornsSHTeleporter tele = new GreenThornsSHTeleporter(); + + tele.MoveToWorld( location, map ); + + new InternalTimer( tele ).Start(); + } + + public override string DefaultName + { + get { return "a hole"; } + } + + private GreenThornsSHTeleporter() : base( 0x913 ) + { + Movable = false; + Hue = 0x1; + } + + public GreenThornsSHTeleporter( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this, 3 ) ) + { + BaseCreature.TeleportPets( from, Destination, Map ); + + from.Location = Destination; + } + else + { + from.SendLocalizedMessage( 1019045 ); // I can't reach that. + } + } + + private class InternalTimer : Timer + { + private GreenThornsSHTeleporter m_Teleporter; + + public InternalTimer( GreenThornsSHTeleporter teleporter ) : base( TimeSpan.FromMinutes( 1.0 ) ) + { + m_Teleporter = teleporter; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Teleporter.Delete(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/MiscItems/OrangePetals.cs b/Scripts/Engines/Plants/MiscItems/OrangePetals.cs new file mode 100644 index 0000000..7685ce8 --- /dev/null +++ b/Scripts/Engines/Plants/MiscItems/OrangePetals.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class OrangePetals : Item + { + public override int LabelNumber { get { return 1053122; } } // orange petals + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public OrangePetals() : this( 1 ) + { + } + + [Constructable] + public OrangePetals( int amount ) : base( 0x1021 ) + { + Stackable = true; + Hue = 0x2B; + Amount = amount; + } + + public OrangePetals( Serial serial ) : base( serial ) + { + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( item != this ) + return base.CheckItemUse( from, item ); + + if ( from != this.RootParent ) + { + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + return false; + } + + return base.CheckItemUse( from, item ); + } + + public override void OnDoubleClick( Mobile from ) + { + OrangePetalsContext context = GetContext( from ); + + if ( context != null ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061904 ); + return; + } + + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061905 ); + from.PlaySound( 0x3B ); + + Timer timer = new OrangePetalsTimer( from ); + timer.Start(); + + AddContext( from, new OrangePetalsContext( timer ) ); + + this.Consume(); + } + + private static Hashtable m_Table = new Hashtable(); + + private static void AddContext( Mobile m, OrangePetalsContext context ) + { + m_Table[m] = context; + } + + public static void RemoveContext( Mobile m ) + { + OrangePetalsContext context = GetContext( m ); + + if ( context != null ) + RemoveContext( m, context ); + } + + private static void RemoveContext( Mobile m, OrangePetalsContext context ) + { + m_Table.Remove( m ); + + context.Timer.Stop(); + } + + private static OrangePetalsContext GetContext( Mobile m ) + { + return ( m_Table[m] as OrangePetalsContext ); + } + + public static bool UnderEffect( Mobile m ) + { + return ( GetContext( m ) != null ); + } + + private class OrangePetalsTimer : Timer + { + private Mobile m_Mobile; + + public OrangePetalsTimer( Mobile from ) : base ( TimeSpan.FromMinutes( 5.0 ) ) + { + m_Mobile = from; + } + + protected override void OnTick() + { + if ( !m_Mobile.Deleted ) + { + m_Mobile.LocalOverheadMessage( MessageType.Regular, 0x3F, true, + "* You feel the effects of your poison resistance wearing off *" ); + } + + RemoveContext( m_Mobile ); + } + } + + private class OrangePetalsContext + { + private Timer m_Timer; + + public Timer Timer{ get{ return m_Timer; } } + + public OrangePetalsContext( Timer timer ) + { + m_Timer = timer; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/MiscItems/RedLeaves.cs b/Scripts/Engines/Plants/MiscItems/RedLeaves.cs new file mode 100644 index 0000000..0be2d44 --- /dev/null +++ b/Scripts/Engines/Plants/MiscItems/RedLeaves.cs @@ -0,0 +1,108 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Items +{ + public class RedLeaves : Item + { + public override int LabelNumber { get { return 1053123; } } // red leaves + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public RedLeaves() : this( 1 ) + { + } + + [Constructable] + public RedLeaves( int amount ) : base( 0x1E85 ) + { + Stackable = true; + Hue = 0x21; + Amount = amount; + } + + public RedLeaves( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + from.Target = new InternalTarget( this ); + from.SendLocalizedMessage( 1061907 ); // Choose a book you wish to seal with the wax from the red leaf. + } + + private class InternalTarget : Target + { + private RedLeaves m_RedLeaves; + + public InternalTarget( RedLeaves redLeaves ) : base( 3, false, TargetFlags.None ) + { + m_RedLeaves = redLeaves; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_RedLeaves.Deleted ) + return; + + if ( !m_RedLeaves.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + Item item = targeted as Item; + + if ( item == null || !item.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else if ( !(item is BaseBook) ) + { + item.LabelTo( from, 1061911 ); // You can only use red leaves to seal the ink into book pages! + } + else + { + BaseBook book = (BaseBook)item; + + if ( !book.Writable ) + { + book.LabelTo( from, 1061909 ); // The ink in this book has already been sealed. + } + else + { + m_RedLeaves.Consume(); + book.Writable = false; + + book.LabelTo( from, 1061910 ); // You seal the ink to the page using wax from the red leaf. + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/MiscMobiles/GiantIceWorm.cs b/Scripts/Engines/Plants/MiscMobiles/GiantIceWorm.cs new file mode 100644 index 0000000..f884fe4 --- /dev/null +++ b/Scripts/Engines/Plants/MiscMobiles/GiantIceWorm.cs @@ -0,0 +1,74 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + [CorpseName( "a giant ice worm corpse" )] + public class GiantIceWorm : BaseCreature + { + public override bool SubdueBeforeTame { get { return true; } } + + [Constructable] + public GiantIceWorm() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 89; + Name = "a giant ice worm"; + BaseSoundID = 0xDC; + + SetStr( 216, 245 ); + SetDex( 76, 100 ); + SetInt( 66, 85 ); + + SetHits( 130, 147 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Cold, 90 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 0 ); + SetResistance( ResistanceType.Cold, 80, 90 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Poisoning, 75.1, 95.0 ); + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 75.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public override Poison PoisonImmune { get { return Poison.Greater; } } + + public override Poison HitPoison { get { return Poison.Greater; } } + + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + + public GiantIceWorm( Serial serial ) : base ( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/Network/DisplayHelpTopic.cs b/Scripts/Engines/Plants/Network/DisplayHelpTopic.cs new file mode 100644 index 0000000..29cfb64 --- /dev/null +++ b/Scripts/Engines/Plants/Network/DisplayHelpTopic.cs @@ -0,0 +1,18 @@ +using System; +using Server; + +namespace Server.Network +{ + public class DisplayHelpTopic : Packet + { + public DisplayHelpTopic( int topicID, bool display ) : base( 0xBF ) + { + EnsureCapacity( 11 ); + + m_Stream.Write( (short) 0x17 ); + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (int) topicID ); + m_Stream.Write( (bool) display ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantBowl.cs b/Scripts/Engines/Plants/PlantBowl.cs new file mode 100644 index 0000000..800de7f --- /dev/null +++ b/Scripts/Engines/Plants/PlantBowl.cs @@ -0,0 +1,193 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Network; + +namespace Server.Engines.Plants +{ + public class PlantBowl : Item + { + public override int LabelNumber { get { return 1060834; } } // a plant bowl + + [Constructable] + public PlantBowl() : base( 0x15FD ) + { + Weight = 1.0; + } + + public PlantBowl( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + from.Target = new InternalTarget( this ); + from.SendLocalizedMessage( 1061897 ); // Choose a patch of dirt to scoop up. + } + + private class InternalTarget : Target + { + private PlantBowl m_PlantBowl; + + public InternalTarget( PlantBowl plantBowl ) : base( 3, true, TargetFlags.None ) + { + m_PlantBowl = plantBowl; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_PlantBowl.Deleted ) + return; + + if ( !m_PlantBowl.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + if ( targeted is FertileDirt ) + { + int _dirtNeeded = Core.ML ? 20 : 40; + + FertileDirt dirt = (FertileDirt)targeted; + + if ( !dirt.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else if ( dirt.Amount < _dirtNeeded ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061896 ); // You need more dirt to fill a plant bowl! + } + else + { + PlantItem fullBowl = new PlantItem( true ); + + if ( from.PlaceInBackpack( fullBowl ) ) + { + dirt.Consume( _dirtNeeded ); + m_PlantBowl.Delete(); + + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061895 ); // You fill the bowl with fresh dirt. + } + else + { + fullBowl.Delete(); + + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061894 ); // There is no room in your backpack for a bowl full of dirt! + } + } + } + else if ( PlantBowl.IsDirtPatch( targeted ) ) + { + PlantItem fullBowl = new PlantItem( false ); + + if ( from.PlaceInBackpack( fullBowl ) ) + { + m_PlantBowl.Delete(); + + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061895 ); // You fill the bowl with fresh dirt. + } + else + { + fullBowl.Delete(); + + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061894 ); // There is no room in your backpack for a bowl full of dirt! + } + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061893 ); // You'll want to gather fresh dirt in order to raise a healthy plant! + } + } + + protected override void OnTargetOutOfRange( Mobile from, object targeted ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502825 ); // That location is too far away + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public static bool IsDirtPatch( object obj ) + { + int tileID; + + if ( obj is Static && !((Static)obj).Movable ) + tileID = (((Static)obj).ItemID & 0x3FFF) | 0x4000; + else if ( obj is StaticTarget ) + tileID = (((StaticTarget)obj).ItemID & 0x3FFF) | 0x4000; + else if ( obj is LandTarget ) + tileID = ((LandTarget)obj).TileID; + else + return false; + + bool contains = false; + + for ( int i = 0; !contains && i < m_DirtPatchTiles.Length; i += 2 ) + contains = ( tileID >= m_DirtPatchTiles[i] && tileID <= m_DirtPatchTiles[i + 1] ); + + return contains; + } + + private static int[] m_DirtPatchTiles = new int[] + { + 0x9, 0x15, + 0x71, 0x7C, + 0x82, 0xA7, + 0xDC, 0xE3, + 0xE8, 0xEB, + 0x141, 0x144, + 0x14C, 0x15C, + 0x169, 0x174, + 0x1DC, 0x1EF, + 0x272, 0x275, + 0x27E, 0x281, + 0x2D0, 0x2D7, + 0x2E5, 0x2FF, + 0x303, 0x31F, + 0x32C, 0x32F, + 0x33D, 0x340, + 0x345, 0x34C, + 0x355, 0x358, + 0x367, 0x36E, + 0x377, 0x37A, + 0x38D, 0x390, + 0x395, 0x39C, + 0x3A5, 0x3A8, + 0x3F6, 0x405, + 0x547, 0x54E, + 0x553, 0x556, + 0x597, 0x59E, + 0x623, 0x63A, + 0x6F3, 0x6FA, + 0x777, 0x791, + 0x79A, 0x7A9, + 0x7AE, 0x7B1, + 0x98C, 0x99F, + 0x9AC, 0x9BF, + 0x5B27, 0x5B3E, + 0x71F4, 0x71FB, + 0x72C9, 0x72CA, + }; + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantHue.cs b/Scripts/Engines/Plants/PlantHue.cs new file mode 100644 index 0000000..c518a14 --- /dev/null +++ b/Scripts/Engines/Plants/PlantHue.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Engines.Plants +{ + [Flags] + public enum PlantHue + { + Plain = 0x1 | Crossable | Reproduces, + + Red = 0x2 | Crossable | Reproduces, + Blue = 0x4 | Crossable | Reproduces, + Yellow = 0x8 | Crossable | Reproduces, + + BrightRed = Red | Bright, + BrightBlue = Blue | Bright, + BrightYellow = Yellow | Bright, + + Purple = Red | Blue, + Green = Blue | Yellow, + Orange = Red | Yellow, + + BrightPurple = Purple | Bright, + BrightGreen = Green | Bright, + BrightOrange = Orange | Bright, + + Black = 0x10, + White = 0x20, + Pink = 0x40, + Magenta = 0x80, + Aqua = 0x100, + FireRed = 0x200, + + None = 0, + Reproduces = 0x2000000, + Crossable = 0x4000000, + Bright = 0x8000000 + } + + public class PlantHueInfo + { + private static Hashtable m_Table; + + static PlantHueInfo() + { + m_Table = new Hashtable(); + + m_Table[PlantHue.Plain] = new PlantHueInfo( 0, 1060813, PlantHue.Plain, 0x835 ); + m_Table[PlantHue.Red] = new PlantHueInfo( 0x66D, 1060814, PlantHue.Red, 0x24 ); + m_Table[PlantHue.Blue] = new PlantHueInfo( 0x53D, 1060815, PlantHue.Blue, 0x6 ); + m_Table[PlantHue.Yellow] = new PlantHueInfo( 0x8A5, 1060818, PlantHue.Yellow, 0x38 ); + m_Table[PlantHue.BrightRed] = new PlantHueInfo( 0x21, 1060814, PlantHue.BrightRed, 0x21 ); + m_Table[PlantHue.BrightBlue] = new PlantHueInfo( 0x5, 1060815, PlantHue.BrightBlue, 0x6 ); + m_Table[PlantHue.BrightYellow] = new PlantHueInfo( 0x38, 1060818, PlantHue.BrightYellow, 0x35 ); + m_Table[PlantHue.Purple] = new PlantHueInfo( 0xD, 1060816, PlantHue.Purple, 0x10 ); + m_Table[PlantHue.Green] = new PlantHueInfo( 0x59B, 1060819, PlantHue.Green, 0x42 ); + m_Table[PlantHue.Orange] = new PlantHueInfo( 0x46F, 1060817, PlantHue.Orange, 0x2E ); + m_Table[PlantHue.BrightPurple] = new PlantHueInfo( 0x10, 1060816, PlantHue.BrightPurple, 0xD ); + m_Table[PlantHue.BrightGreen] = new PlantHueInfo( 0x42, 1060819, PlantHue.BrightGreen, 0x3F ); + m_Table[PlantHue.BrightOrange] = new PlantHueInfo( 0x2B, 1060817, PlantHue.BrightOrange, 0x2B ); + m_Table[PlantHue.Black] = new PlantHueInfo( 0x455, 1060820, PlantHue.Black, 0 ); + m_Table[PlantHue.White] = new PlantHueInfo( 0x481, 1060821, PlantHue.White, 0x481 ); + m_Table[PlantHue.Pink] = new PlantHueInfo( 0x48E, 1061854, PlantHue.Pink ); + m_Table[PlantHue.Magenta] = new PlantHueInfo( 0x486, 1061852, PlantHue.Magenta ); + m_Table[PlantHue.Aqua] = new PlantHueInfo( 0x495, 1061853, PlantHue.Aqua ); + m_Table[PlantHue.FireRed] = new PlantHueInfo( 0x489, 1061855, PlantHue.FireRed ); + } + + public static PlantHueInfo GetInfo( PlantHue plantHue ) + { + PlantHueInfo info = m_Table[plantHue] as PlantHueInfo; + + if ( info != null ) + return info; + else + return (PlantHueInfo)m_Table[PlantHue.Plain]; + } + + public static PlantHue RandomFirstGeneration() + { + switch ( Utility.Random( 4 ) ) + { + case 0: return PlantHue.Plain; + case 1: return PlantHue.Red; + case 2: return PlantHue.Blue; + default: return PlantHue.Yellow; + } + } + + public static bool CanReproduce(PlantHue plantHue) + { + return (plantHue & PlantHue.Reproduces) != PlantHue.None; + } + + public static bool IsCrossable( PlantHue plantHue ) + { + return (plantHue & PlantHue.Crossable) != PlantHue.None; + } + + public static bool IsBright( PlantHue plantHue ) + { + return (plantHue & PlantHue.Bright) != PlantHue.None; + } + + public static PlantHue GetNotBright( PlantHue plantHue ) + { + return plantHue & ~PlantHue.Bright; + } + + public static bool IsPrimary( PlantHue plantHue ) + { + return plantHue == PlantHue.Red || plantHue == PlantHue.Blue || plantHue == PlantHue.Yellow; + } + + public static PlantHue Cross( PlantHue first, PlantHue second ) + { + if ( !IsCrossable( first ) || !IsCrossable( second ) ) + return PlantHue.None; + + if ( Utility.RandomDouble() < 0.01 ) + return Utility.RandomBool() ? PlantHue.Black : PlantHue.White; + + if ( first == PlantHue.Plain || second == PlantHue.Plain ) + return PlantHue.Plain; + + PlantHue notBrightFirst = GetNotBright( first ); + PlantHue notBrightSecond = GetNotBright( second ); + + if ( notBrightFirst == notBrightSecond ) + return first | PlantHue.Bright; + + bool firstPrimary = IsPrimary( notBrightFirst ); + bool secondPrimary = IsPrimary( notBrightSecond ); + + if ( firstPrimary && secondPrimary ) + return notBrightFirst | notBrightSecond; + + if ( firstPrimary && !secondPrimary ) + return notBrightFirst; + + if ( !firstPrimary && secondPrimary ) + return notBrightSecond; + + return notBrightFirst & notBrightSecond; + } + + private int m_Hue; + private int m_Name; + private PlantHue m_PlantHue; + private int m_GumpHue; + + public int Hue { get { return m_Hue; } } + public int Name { get { return m_Name; } } + public PlantHue PlantHue { get { return m_PlantHue; } } + public int GumpHue { get { return m_GumpHue; } } + + private PlantHueInfo( int hue, int name, PlantHue plantHue ) : this( hue, name, plantHue, hue ) + { + } + + private PlantHueInfo( int hue, int name, PlantHue plantHue, int gumpHue ) + { + m_Hue = hue; + m_Name = name; + m_PlantHue = plantHue; + m_GumpHue = gumpHue; + } + + public bool IsCrossable() + { + return IsCrossable( m_PlantHue ); + } + + public bool IsBright() + { + return IsBright( m_PlantHue ); + } + + public PlantHue GetNotBright() + { + return GetNotBright( m_PlantHue ); + } + + public bool IsPrimary() + { + return IsPrimary( m_PlantHue ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantItem.cs b/Scripts/Engines/Plants/PlantItem.cs new file mode 100644 index 0000000..614e9c9 --- /dev/null +++ b/Scripts/Engines/Plants/PlantItem.cs @@ -0,0 +1,596 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Multis; +using Server.ContextMenus; +using Server.Network; + +namespace Server.Engines.Plants +{ + public enum PlantStatus + { + BowlOfDirt = 0, + Seed = 1, + Sapling = 2, + Plant = 4, + FullGrownPlant = 7, + DecorativePlant = 10, + DeadTwigs = 11, + + Stage1 = 1, + Stage2 = 2, + Stage3 = 3, + Stage4 = 4, + Stage5 = 5, + Stage6 = 6, + Stage7 = 7, + Stage8 = 8, + Stage9 = 9 + } + + public class PlantItem : Item, ISecurable + { + /* + * Clients 7.0.12.0+ expect a container type in the plant label. + * To support older (and only older) clients, change this to false. + */ + private static readonly bool ShowContainerType = true; + + private PlantSystem m_PlantSystem; + + private PlantStatus m_PlantStatus; + private PlantType m_PlantType; + private PlantHue m_PlantHue; + private bool m_ShowType; + + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + public PlantSystem PlantSystem { get { return m_PlantSystem; } } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void OnSingleClick(Mobile from) + { + if (m_PlantStatus >= PlantStatus.DeadTwigs) + LabelTo(from, LabelNumber); + else if (m_PlantStatus >= PlantStatus.DecorativePlant) + LabelTo(from, 1061924); // a decorative plant + else if (m_PlantStatus >= PlantStatus.FullGrownPlant) + LabelTo(from, PlantTypeInfo.GetInfo(m_PlantType).Name); + else + LabelTo(from, 1029913); // plant bowl + } + + + [CommandProperty( AccessLevel.GameMaster )] + public PlantStatus PlantStatus + { + get { return m_PlantStatus; } + set + { + if ( m_PlantStatus == value || value < PlantStatus.BowlOfDirt || value > PlantStatus.DeadTwigs ) + return; + + double ratio; + if ( m_PlantSystem != null ) + ratio = (double) m_PlantSystem.Hits / m_PlantSystem.MaxHits; + else + ratio = 1.0; + + m_PlantStatus = value; + + if ( m_PlantStatus >= PlantStatus.DecorativePlant ) + { + m_PlantSystem = null; + } + else + { + if ( m_PlantSystem == null ) + m_PlantSystem = new PlantSystem( this, false ); + + int hits = (int)( m_PlantSystem.MaxHits * ratio ); + + if ( hits == 0 && m_PlantStatus > PlantStatus.BowlOfDirt ) + m_PlantSystem.Hits = hits + 1; + else + m_PlantSystem.Hits = hits; + } + + Update(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public PlantType PlantType + { + get { return m_PlantType; } + set + { + m_PlantType = value; + Update(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public PlantHue PlantHue + { + get { return m_PlantHue; } + set + { + m_PlantHue = value; + Update(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ShowType + { + get { return m_ShowType; } + set + { + m_ShowType = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ValidGrowthLocation + { + get + { + if ( IsLockedDown && RootParent == null ) + return true; + + + Mobile owner = RootParent as Mobile; + if ( owner == null ) + return false; + + if ( owner.Backpack != null && IsChildOf( owner.Backpack ) ) + return true; + + BankBox bank = owner.FindBankNoCreate(); + if ( bank != null && IsChildOf( bank ) ) + return true; + + return false; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsGrowable + { + get { return m_PlantStatus >= PlantStatus.BowlOfDirt && m_PlantStatus <= PlantStatus.Stage9; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsCrossable + { + get { return PlantHueInfo.IsCrossable( this.PlantHue ) && PlantTypeInfo.IsCrossable( this.PlantType ); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Reproduces + { + get { return PlantHueInfo.CanReproduce(this.PlantHue) && PlantTypeInfo.CanReproduce(this.PlantType); } + } + + private static ArrayList m_Instances = new ArrayList(); + + public static ArrayList Plants{ get{ return m_Instances; } } + + [Constructable] + public PlantItem() : this( false ) + { + } + + [Constructable] + public PlantItem( bool fertileDirt ) : base( 0x1602 ) + { + Weight = 1.0; + + m_PlantStatus = PlantStatus.BowlOfDirt; + m_PlantSystem = new PlantSystem( this, fertileDirt ); + m_Level = SecureLevel.Owner; + + m_Instances.Add( this ); + } + + public PlantItem( Serial serial ) : base( serial ) + { + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public int GetLocalizedPlantStatus() + { + if ( m_PlantStatus >= PlantStatus.Plant ) + return 1060812; // plant + else if ( m_PlantStatus >= PlantStatus.Sapling ) + return 1023305; // sapling + else if ( m_PlantStatus >= PlantStatus.Seed ) + return 1060810; // seed + else + return 1026951; // dirt + } + + public int GetLocalizedContainerType() + { + return 1150435; // bowl + } + + private void Update() + { + if ( m_PlantStatus >= PlantStatus.DeadTwigs ) + { + ItemID = 0x1B9D; + Hue = PlantHueInfo.GetInfo( m_PlantHue ).Hue; + } + else if ( m_PlantStatus >= PlantStatus.FullGrownPlant ) + { + ItemID = PlantTypeInfo.GetInfo( m_PlantType ).ItemID; + Hue = PlantHueInfo.GetInfo( m_PlantHue ).Hue; + } + else if ( m_PlantStatus >= PlantStatus.Plant ) + { + ItemID = 0x1600; + Hue = 0; + } + else + { + ItemID = 0x1602; + Hue = 0; + } + + InvalidateProperties(); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (m_PlantStatus >= PlantStatus.DeadTwigs) + { + base.AddNameProperty(list); + } + else if (m_PlantStatus < PlantStatus.Seed) + { + string args; + + if (ShowContainerType) + args = String.Format("#{0}\t#{1}", GetLocalizedContainerType(), m_PlantSystem.GetLocalizedDirtStatus()); + else + args = String.Format("#{0}", m_PlantSystem.GetLocalizedDirtStatus()); + + list.Add(1060830, args); // a ~1_val~ of ~2_val~ dirt + } + else + { + PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo(m_PlantType); + PlantHueInfo hueInfo = PlantHueInfo.GetInfo(m_PlantHue); + + if (m_PlantStatus >= PlantStatus.DecorativePlant) + { + list.Add(typeInfo.GetPlantLabelDecorative(hueInfo), String.Format("#{0}\t#{1}", hueInfo.Name, typeInfo.Name)); + } + else if (m_PlantStatus >= PlantStatus.FullGrownPlant) + { + list.Add(typeInfo.GetPlantLabelFullGrown(hueInfo), String.Format("#{0}\t#{1}\t#{2}", m_PlantSystem.GetLocalizedHealth(), hueInfo.Name, typeInfo.Name)); + } + else + { + string args; + + if (ShowContainerType) + args = String.Format("#{0}\t#{1}\t#{2}", GetLocalizedContainerType(), m_PlantSystem.GetLocalizedDirtStatus(), m_PlantSystem.GetLocalizedHealth()); + else + args = String.Format("#{0}\t#{1}", m_PlantSystem.GetLocalizedDirtStatus(), m_PlantSystem.GetLocalizedHealth()); + + if (m_ShowType) + { + args += String.Format("\t#{0}\t#{1}\t#{2}", hueInfo.Name, typeInfo.Name, GetLocalizedPlantStatus()); + + if (m_PlantStatus == PlantStatus.Plant) + list.Add(typeInfo.GetPlantLabelPlant(hueInfo), args); + else + list.Add(typeInfo.GetPlantLabelSeed(hueInfo), args); + } + else + { + args += String.Format("\t#{0}\t#{1}", (typeInfo.PlantCategory == PlantCategory.Default) ? hueInfo.Name : (int)typeInfo.PlantCategory, GetLocalizedPlantStatus()); + + list.Add(hueInfo.IsBright() ? 1060832 : 1060831, args); // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~ + } + } + } + } + + public bool IsUsableBy( Mobile from ) + { + Item root = RootParent as Item; + return IsChildOf( from.Backpack ) || IsChildOf( from.FindBankNoCreate() ) || IsLockedDown && IsAccessibleTo( from ) || root != null && root.IsSecure && root.IsAccessibleTo( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_PlantStatus >= PlantStatus.DecorativePlant ) + return; + + Point3D loc = this.GetWorldLocation(); + + if ( !from.InLOS( loc ) || !from.InRange( loc, 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 1019045 ); // I can't reach that. + return; + } + + if ( !IsUsableBy( from ) ) + { + LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + return; + } + + from.SendGump( new MainPlantGump( this ) ); + } + + public void PlantSeed( Mobile from, Seed seed ) + { + if ( m_PlantStatus >= PlantStatus.FullGrownPlant ) + { + LabelTo( from, 1061919 ); // You must use a seed on some prepared soil! + } + else if ( !IsUsableBy( from ) ) + { + LabelTo( from, 1061921 ); // The bowl of dirt must be in your pack, or you must lock it down. + } + else if ( m_PlantStatus != PlantStatus.BowlOfDirt ) + { + from.SendLocalizedMessage( 1080389, "#" + GetLocalizedPlantStatus().ToString() ); // This bowl of dirt already has a ~1_val~ in it! + } + else if ( m_PlantSystem.Water < 2 ) + { + LabelTo( from, 1061920 ); // The dirt needs to be softened first. + } + else + { + m_PlantType = seed.PlantType; + m_PlantHue = seed.PlantHue; + m_ShowType = seed.ShowType; + + seed.Consume(); + + PlantStatus = PlantStatus.Seed; + + m_PlantSystem.Reset( false ); + + LabelTo( from, 1061922 ); // You plant the seed in the bowl of dirt. + } + } + + public void Die() + { + if ( m_PlantStatus >= PlantStatus.FullGrownPlant ) + { + PlantStatus = PlantStatus.DeadTwigs; + } + else + { + PlantStatus = PlantStatus.BowlOfDirt; + m_PlantSystem.Reset( true ); + } + } + + public void Pour( Mobile from, Item item ) + { + if ( m_PlantStatus >= PlantStatus.DeadTwigs ) + return; + + if ( m_PlantStatus == PlantStatus.DecorativePlant ) + { + LabelTo( from, 1053049 ); // This is a decorative plant, it does not need watering! + return; + } + + if ( !IsUsableBy( from ) ) + { + LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + return; + } + + if ( item is BaseBeverage ) + { + BaseBeverage beverage = (BaseBeverage)item; + + if ( beverage.IsEmpty || !beverage.Pourable || beverage.Content != BeverageType.Water ) + { + LabelTo( from, 1053069 ); // You can't use that on a plant! + return; + } + + if ( !beverage.ValidateUse( from, true ) ) + return; + + beverage.Quantity--; + m_PlantSystem.Water++; + + from.PlaySound( 0x4E ); + LabelTo( from, 1061858 ); // You soften the dirt with water. + } + else if ( item is BasePotion ) + { + BasePotion potion = (BasePotion)item; + + int message; + if ( ApplyPotion( potion.PotionEffect, false, out message ) ) + { + potion.Consume(); + from.PlaySound( 0x240 ); + from.AddToBackpack( new Bottle() ); + } + LabelTo( from, message ); + } + else if ( item is PotionKeg ) + { + PotionKeg keg = (PotionKeg)item; + + if ( keg.Held <= 0 ) + { + LabelTo( from, 1053069 ); // You can't use that on a plant! + return; + } + + int message; + if ( ApplyPotion( keg.Type, false, out message ) ) + { + keg.Held--; + from.PlaySound( 0x240 ); + } + LabelTo( from, message ); + } + else + { + LabelTo( from, 1053069 ); // You can't use that on a plant! + } + } + + public bool ApplyPotion( PotionEffect effect, bool testOnly, out int message ) + { + if ( m_PlantStatus >= PlantStatus.DecorativePlant ) + { + message = 1053049; // This is a decorative plant, it does not need watering! + return false; + } + + if ( m_PlantStatus == PlantStatus.BowlOfDirt ) + { + message = 1053066; // You should only pour potions on a plant or seed! + return false; + } + + bool full = false; + + if ( effect == PotionEffect.PoisonGreater || effect == PotionEffect.PoisonDeadly ) + { + if ( m_PlantSystem.IsFullPoisonPotion ) + full = true; + else if ( !testOnly ) + m_PlantSystem.PoisonPotion++; + } + else if ( effect == PotionEffect.CureGreater ) + { + if ( m_PlantSystem.IsFullCurePotion ) + full = true; + else if ( !testOnly ) + m_PlantSystem.CurePotion++; + } + else if ( effect == PotionEffect.HealGreater ) + { + if ( m_PlantSystem.IsFullHealPotion ) + full = true; + else if ( !testOnly ) + m_PlantSystem.HealPotion++; + } + else if ( effect == PotionEffect.StrengthGreater ) + { + if ( m_PlantSystem.IsFullStrengthPotion ) + full = true; + else if ( !testOnly ) + m_PlantSystem.StrengthPotion++; + } + else if ( effect == PotionEffect.PoisonLesser || effect == PotionEffect.Poison || effect == PotionEffect.CureLesser || effect == PotionEffect.Cure || + effect == PotionEffect.HealLesser || effect == PotionEffect.Heal || effect == PotionEffect.Strength ) + { + message = 1053068; // This potion is not powerful enough to use on a plant! + return false; + } + else + { + message = 1053069; // You can't use that on a plant! + return false; + } + + if ( full ) + { + message = 1053065; // The plant is already soaked with this type of potion! + return false; + } + else + { + message = 1053067; // You pour the potion over the plant. + return true; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (int) m_Level ); + + writer.Write( (int) m_PlantStatus ); + writer.Write( (int) m_PlantType ); + writer.Write( (int) m_PlantHue ); + writer.Write( (bool) m_ShowType ); + + if ( m_PlantStatus < PlantStatus.DecorativePlant ) + m_PlantSystem.Save( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + if ( version < 1 ) + m_Level = SecureLevel.CoOwners; + + m_PlantStatus = (PlantStatus)reader.ReadInt(); + m_PlantType = (PlantType)reader.ReadInt(); + m_PlantHue = (PlantHue)reader.ReadInt(); + m_ShowType = reader.ReadBool(); + + if ( m_PlantStatus < PlantStatus.DecorativePlant ) + m_PlantSystem = new PlantSystem( this, reader ); + if (version < 2 && PlantHueInfo.IsCrossable(m_PlantHue)) + m_PlantHue |= PlantHue.Reproduces; + + break; + } + } + + m_Instances.Add( this ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_Instances.Remove( this ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantPourTarget.cs b/Scripts/Engines/Plants/PlantPourTarget.cs new file mode 100644 index 0000000..32c72d4 --- /dev/null +++ b/Scripts/Engines/Plants/PlantPourTarget.cs @@ -0,0 +1,32 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Engines.Plants +{ + public class PlantPourTarget : Target + { + private PlantItem m_Plant; + + public PlantPourTarget( PlantItem plant ) : base( 3, true, TargetFlags.None ) + { + m_Plant = plant; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Plant.Deleted && from.InRange( m_Plant.GetWorldLocation(), 3 ) && targeted is Item ) + { + m_Plant.Pour( from, (Item)targeted ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( !m_Plant.Deleted && m_Plant.PlantStatus < PlantStatus.DecorativePlant && from.InRange( m_Plant.GetWorldLocation(), 3 ) && m_Plant.IsUsableBy( from ) && !from.HasGump( typeof(MainPlantGump) ) ) + { + from.SendGump( new MainPlantGump( m_Plant ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantResources.cs b/Scripts/Engines/Plants/PlantResources.cs new file mode 100644 index 0000000..de588ec --- /dev/null +++ b/Scripts/Engines/Plants/PlantResources.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.Plants +{ + public class PlantResourceInfo + { + private static PlantResourceInfo[] m_ResourceList = new PlantResourceInfo[] + { + new PlantResourceInfo( PlantType.ElephantEarPlant, PlantHue.BrightRed, typeof( RedLeaves ) ), + new PlantResourceInfo( PlantType.PonytailPalm, PlantHue.BrightRed, typeof( RedLeaves ) ), + new PlantResourceInfo( PlantType.CenturyPlant, PlantHue.BrightRed, typeof( RedLeaves ) ), + new PlantResourceInfo( PlantType.Poppies, PlantHue.BrightOrange, typeof( OrangePetals ) ), + new PlantResourceInfo( PlantType.Bulrushes, PlantHue.BrightOrange, typeof( OrangePetals ) ), + new PlantResourceInfo( PlantType.PampasGrass, PlantHue.BrightOrange, typeof( OrangePetals ) ), + new PlantResourceInfo( PlantType.BarrelCactus, PlantHue.BrightGreen, typeof( GreenThorns ) ), + new PlantResourceInfo( PlantType.CocoaTree, PlantHue.Plain, typeof( CocoaPulp ) ) + }; + + public static PlantResourceInfo GetInfo( PlantType plantType, PlantHue plantHue ) + { + foreach ( PlantResourceInfo info in m_ResourceList ) + { + if ( info.PlantType == plantType && info.PlantHue == plantHue ) + return info; + } + + return null; + } + + private PlantType m_PlantType; + private PlantHue m_PlantHue; + private Type m_ResourceType; + + public PlantType PlantType { get { return m_PlantType; } } + public PlantHue PlantHue { get { return m_PlantHue; } } + public Type ResourceType { get { return m_ResourceType; } } + + private PlantResourceInfo( PlantType plantType, PlantHue plantHue, Type resourceType ) + { + m_PlantType = plantType; + m_PlantHue = plantHue; + m_ResourceType = resourceType; + } + + public Item CreateResource() + { + return (Item)Activator.CreateInstance( m_ResourceType ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantSystem.cs b/Scripts/Engines/Plants/PlantSystem.cs new file mode 100644 index 0000000..b268a39 --- /dev/null +++ b/Scripts/Engines/Plants/PlantSystem.cs @@ -0,0 +1,715 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using System.Collections.Generic; + +namespace Server.Engines.Plants +{ + public enum PlantHealth + { + Dying, + Wilted, + Healthy, + Vibrant + } + + public enum PlantGrowthIndicator + { + None, + InvalidLocation, + NotHealthy, + Delay, + Grown, + DoubleGrown + } + + public class PlantSystem + { + public static readonly TimeSpan CheckDelay = TimeSpan.FromHours( 23.0 ); + + private PlantItem m_Plant; + private bool m_FertileDirt; + + private DateTime m_NextGrowth; + private PlantGrowthIndicator m_GrowthIndicator; + + private int m_Water; + + private int m_Hits; + private int m_Infestation; + private int m_Fungus; + private int m_Poison; + private int m_Disease; + private int m_PoisonPotion; + private int m_CurePotion; + private int m_HealPotion; + private int m_StrengthPotion; + + private bool m_Pollinated; + private PlantType m_SeedType; + private PlantHue m_SeedHue; + private int m_AvailableSeeds; + private int m_LeftSeeds; + + private int m_AvailableResources; + private int m_LeftResources; + + public PlantItem Plant { get { return m_Plant; } } + + public bool FertileDirt + { + get { return m_FertileDirt; } + set { m_FertileDirt = value; } + } + + public DateTime NextGrowth + { + get { return m_NextGrowth; } + } + + public PlantGrowthIndicator GrowthIndicator + { + get { return m_GrowthIndicator; } + } + + public bool IsFullWater { get { return m_Water >= 4; } } + public int Water + { + get { return m_Water; } + set + { + if ( value < 0 ) + m_Water = 0; + else if ( value > 4 ) + m_Water = 4; + else + m_Water = value; + + m_Plant.InvalidateProperties(); + } + } + + public int Hits + { + get { return m_Hits; } + set + { + if ( m_Hits == value ) + return; + + if ( value < 0 ) + m_Hits = 0; + else if ( value > MaxHits ) + m_Hits = MaxHits; + else + m_Hits = value; + + if ( m_Hits == 0 ) + m_Plant.Die(); + + m_Plant.InvalidateProperties(); + } + } + + public int MaxHits + { + get { return 10 + (int)m_Plant.PlantStatus * 2; } + } + + public PlantHealth Health + { + get + { + int perc = m_Hits * 100 / MaxHits; + + if ( perc < 33 ) + return PlantHealth.Dying; + else if ( perc < 66 ) + return PlantHealth.Wilted; + else if ( perc < 100 ) + return PlantHealth.Healthy; + else + return PlantHealth.Vibrant; + } + } + + public int Infestation + { + get { return m_Infestation; } + set + { + if ( value < 0 ) + m_Infestation = 0; + else if ( value > 2 ) + m_Infestation = 2; + else + m_Infestation = value; + } + } + + public int Fungus + { + get { return m_Fungus; } + set + { + if ( value < 0 ) + m_Fungus = 0; + else if ( value > 2 ) + m_Fungus = 2; + else + m_Fungus = value; + } + } + + public int Poison + { + get { return m_Poison; } + set + { + if ( value < 0 ) + m_Poison = 0; + else if ( value > 2 ) + m_Poison = 2; + else + m_Poison = value; + } + } + + public int Disease + { + get { return m_Disease; } + set + { + if ( value < 0 ) + m_Disease = 0; + else if ( value > 2 ) + m_Disease = 2; + else + m_Disease = value; + } + } + + public bool IsFullPoisonPotion { get { return m_PoisonPotion >= 2; } } + public int PoisonPotion + { + get { return m_PoisonPotion; } + set + { + if ( value < 0 ) + m_PoisonPotion = 0; + else if ( value > 2 ) + m_PoisonPotion = 2; + else + m_PoisonPotion = value; + } + } + + public bool IsFullCurePotion { get { return m_CurePotion >= 2; } } + public int CurePotion + { + get { return m_CurePotion; } + set + { + if ( value < 0 ) + m_CurePotion = 0; + else if ( value > 2 ) + m_CurePotion = 2; + else + m_CurePotion = value; + } + } + + public bool IsFullHealPotion { get { return m_HealPotion >= 2; } } + public int HealPotion + { + get { return m_HealPotion; } + set + { + if ( value < 0 ) + m_HealPotion = 0; + else if ( value > 2 ) + m_HealPotion = 2; + else + m_HealPotion = value; + } + } + + public bool IsFullStrengthPotion { get { return m_StrengthPotion >= 2; } } + public int StrengthPotion + { + get { return m_StrengthPotion; } + set + { + if ( value < 0 ) + m_StrengthPotion = 0; + else if ( value > 2 ) + m_StrengthPotion = 2; + else + m_StrengthPotion = value; + } + } + + public bool HasMaladies + { + get { return Infestation > 0 || Fungus > 0 || Poison > 0 || Disease > 0 || Water != 2; } + } + + public bool PollenProducing + { + get { return m_Plant.IsCrossable && m_Plant.PlantStatus >= PlantStatus.FullGrownPlant; } + } + + public bool Pollinated + { + get { return m_Pollinated; } + set { m_Pollinated = value; } + } + + public PlantType SeedType + { + get + { + if ( m_Pollinated ) + return m_SeedType; + else + return m_Plant.PlantType; + } + set { m_SeedType = value; } + } + + public PlantHue SeedHue + { + get + { + if ( m_Pollinated ) + return m_SeedHue; + else + return m_Plant.PlantHue; + } + set { m_SeedHue = value; } + } + + public int AvailableSeeds + { + get { return m_AvailableSeeds; } + set { if ( value >= 0 ) m_AvailableSeeds = value; } + } + + public int LeftSeeds + { + get { return m_LeftSeeds; } + set { if ( value >= 0 ) m_LeftSeeds = value; } + } + + public int AvailableResources + { + get { return m_AvailableResources; } + set { if ( value >= 0 ) m_AvailableResources = value; } + } + + public int LeftResources + { + get { return m_LeftResources; } + set { if ( value >= 0 ) m_LeftResources = value; } + } + + public PlantSystem( PlantItem plant, bool fertileDirt ) + { + m_Plant = plant; + m_FertileDirt = fertileDirt; + + m_NextGrowth = DateTime.Now + CheckDelay; + m_GrowthIndicator = PlantGrowthIndicator.None; + m_Hits = MaxHits; + m_LeftSeeds = 8; + m_LeftResources = 8; + } + + public void Reset( bool potions ) + { + m_NextGrowth = DateTime.Now + CheckDelay; + m_GrowthIndicator = PlantGrowthIndicator.None; + + Hits = MaxHits; + m_Infestation = 0; + m_Fungus = 0; + m_Poison = 0; + m_Disease = 0; + + if ( potions ) + { + m_PoisonPotion = 0; + m_CurePotion = 0; + m_HealPotion = 0; + m_StrengthPotion = 0; + } + + m_Pollinated = false; + m_AvailableSeeds = 0; + m_LeftSeeds = 8; + + m_AvailableResources = 0; + m_LeftResources = 8; + } + + public int GetLocalizedDirtStatus() + { + if ( Water <= 1 ) + return 1060826; // hard + else if ( Water <= 2 ) + return 1060827; // soft + else if ( Water <= 3 ) + return 1060828; // squishy + else + return 1060829; // sopping wet + } + + public int GetLocalizedHealth() + { + switch ( Health ) + { + case PlantHealth.Dying: return 1060825; // dying + case PlantHealth.Wilted: return 1060824; // wilted + case PlantHealth.Healthy: return 1060823; // healthy + default: return 1060822; // vibrant + } + } + + public static void Configure() + { + EventSink.WorldLoad += new WorldLoadEventHandler( EventSink_WorldLoad ); + + if ( !Misc.AutoRestart.Enabled ) + EventSink.WorldSave += new WorldSaveEventHandler( EventSink_WorldSave ); + + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static void EventSink_Login( LoginEventArgs args ) + { + Mobile from = args.Mobile; + + if ( from.Backpack != null ) + { + List plants = from.Backpack.FindItemsByType(); + + foreach ( PlantItem plant in plants ) + { + if ( plant.IsGrowable ) + plant.PlantSystem.DoGrowthCheck(); + } + } + + BankBox bank = from.FindBankNoCreate(); + + if ( bank != null ) + { + List plants = bank.FindItemsByType(); + + foreach ( PlantItem plant in plants ) + { + if ( plant.IsGrowable ) + plant.PlantSystem.DoGrowthCheck(); + } + } + } + + public static void GrowAll() + { + ArrayList plants = PlantItem.Plants; + DateTime now = DateTime.Now; + + for ( int i = plants.Count - 1; i >= 0; --i ) + { + PlantItem plant = (PlantItem) plants[i]; + + if ( plant.IsGrowable && (plant.RootParent as Mobile) == null && now >= plant.PlantSystem.NextGrowth ) + plant.PlantSystem.DoGrowthCheck(); + } + } + + private static void EventSink_WorldLoad() + { + GrowAll(); + } + + private static void EventSink_WorldSave( WorldSaveEventArgs args) + { + GrowAll(); + } + + public void DoGrowthCheck() + { + if ( !m_Plant.IsGrowable ) + return; + + if ( DateTime.Now < m_NextGrowth ) + { + m_GrowthIndicator = PlantGrowthIndicator.Delay; + return; + } + + m_NextGrowth = DateTime.Now + CheckDelay; + + if ( !m_Plant.ValidGrowthLocation ) + { + m_GrowthIndicator = PlantGrowthIndicator.InvalidLocation; + return; + } + + if ( m_Plant.PlantStatus == PlantStatus.BowlOfDirt) + { + if ( Water > 2 || Utility.RandomDouble() < 0.9 ) + Water--; + return; + } + + ApplyBeneficEffects(); + + if ( !ApplyMaladiesEffects() ) // Dead + return; + + Grow(); + + UpdateMaladies(); + } + + private void ApplyBeneficEffects() + { + if ( PoisonPotion >= Infestation ) + { + PoisonPotion -= Infestation; + Infestation = 0; + } + else + { + Infestation -= PoisonPotion; + PoisonPotion = 0; + } + + if ( CurePotion >= Fungus ) + { + CurePotion -= Fungus; + Fungus = 0; + } + else + { + Fungus -= CurePotion; + CurePotion = 0; + } + + if ( HealPotion >= Poison ) + { + HealPotion -= Poison; + Poison = 0; + } + else + { + Poison -= HealPotion; + HealPotion = 0; + } + + if ( HealPotion >= Disease ) + { + HealPotion -= Disease; + Disease = 0; + } + else + { + Disease -= HealPotion; + HealPotion = 0; + } + + if ( !HasMaladies ) + { + if ( HealPotion > 0 ) + Hits += HealPotion * 7; + else + Hits += 2; + } + + HealPotion = 0; + } + + private bool ApplyMaladiesEffects() + { + int damage = 0; + + if ( Infestation > 0 ) + damage += Infestation * Utility.RandomMinMax( 3, 6 ); + + if ( Fungus > 0 ) + damage += Fungus * Utility.RandomMinMax( 3, 6 ); + + if ( Poison > 0 ) + damage += Poison * Utility.RandomMinMax( 3, 6 ); + + if ( Disease > 0 ) + damage += Disease * Utility.RandomMinMax( 3, 6 ); + + if ( Water > 2 ) + damage += ( Water - 2 ) * Utility.RandomMinMax( 3, 6 ); + else if ( Water < 2 ) + damage += ( 2 - Water ) * Utility.RandomMinMax( 3, 6 ); + + Hits -= damage; + + return m_Plant.IsGrowable && m_Plant.PlantStatus != PlantStatus.BowlOfDirt; + } + + private void Grow() + { + if ( Health < PlantHealth.Healthy ) + { + m_GrowthIndicator = PlantGrowthIndicator.NotHealthy; + } + else if ( m_FertileDirt && m_Plant.PlantStatus <= PlantStatus.Stage5 && Utility.RandomDouble() < 0.1 ) + { + int curStage = (int)m_Plant.PlantStatus; + m_Plant.PlantStatus = (PlantStatus)( curStage + 2 ); + + m_GrowthIndicator = PlantGrowthIndicator.DoubleGrown; + } + else if ( m_Plant.PlantStatus < PlantStatus.Stage9 ) + { + int curStage = (int)m_Plant.PlantStatus; + m_Plant.PlantStatus = (PlantStatus)( curStage + 1 ); + + m_GrowthIndicator = PlantGrowthIndicator.Grown; + } + else + { + if (Pollinated && LeftSeeds > 0 && m_Plant.Reproduces) + { + LeftSeeds--; + AvailableSeeds++; + } + + if ( LeftResources > 0 && PlantResourceInfo.GetInfo( m_Plant.PlantType, m_Plant.PlantHue ) != null ) + { + LeftResources--; + AvailableResources++; + } + + m_GrowthIndicator = PlantGrowthIndicator.Grown; + } + + if ( m_Plant.PlantStatus >= PlantStatus.Stage9 && !Pollinated ) + { + Pollinated = true; + SeedType = m_Plant.PlantType; + SeedHue = m_Plant.PlantHue; + } + } + + private void UpdateMaladies() + { + double infestationChance = 0.30 - StrengthPotion * 0.075 + ( Water - 2 ) * 0.10; + + PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo( m_Plant.PlantType ); + if ( typeInfo.Flowery ) + infestationChance += 0.10; + + if ( PlantHueInfo.IsBright( m_Plant.PlantHue ) ) + infestationChance += 0.10; + + if ( Utility.RandomDouble() < infestationChance ) + Infestation++; + + + double fungusChance = 0.15 - StrengthPotion * 0.075 + ( Water - 2 ) * 0.10; + + if ( Utility.RandomDouble() < fungusChance ) + Fungus++; + + if ( Water > 2 || Utility.RandomDouble() < 0.9 ) + Water--; + + if ( PoisonPotion > 0 ) + { + Poison += PoisonPotion; + PoisonPotion = 0; + } + + if ( CurePotion > 0 ) + { + Disease += CurePotion; + CurePotion = 0; + } + + StrengthPotion = 0; + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int) 2 ); // version + + writer.Write( (bool) m_FertileDirt ); + + writer.Write( (DateTime) m_NextGrowth ); + writer.Write( (int) m_GrowthIndicator ); + + writer.Write( (int) m_Water ); + + writer.Write( (int) m_Hits ); + writer.Write( (int) m_Infestation ); + writer.Write( (int) m_Fungus ); + writer.Write( (int) m_Poison ); + writer.Write( (int) m_Disease ); + writer.Write( (int) m_PoisonPotion ); + writer.Write( (int) m_CurePotion ); + writer.Write( (int) m_HealPotion ); + writer.Write( (int) m_StrengthPotion ); + + writer.Write( (bool) m_Pollinated ); + writer.Write( (int) m_SeedType ); + writer.Write( (int) m_SeedHue ); + writer.Write( (int) m_AvailableSeeds ); + writer.Write( (int) m_LeftSeeds ); + + writer.Write( (int) m_AvailableResources ); + writer.Write( (int) m_LeftResources ); + } + + public PlantSystem( PlantItem plant, GenericReader reader ) + { + m_Plant = plant; + + int version = reader.ReadInt(); + + m_FertileDirt = reader.ReadBool(); + + if ( version >= 1 ) + m_NextGrowth = reader.ReadDateTime(); + else + m_NextGrowth = reader.ReadDeltaTime(); + + m_GrowthIndicator = (PlantGrowthIndicator)reader.ReadInt(); + + m_Water = reader.ReadInt(); + + m_Hits = reader.ReadInt(); + m_Infestation = reader.ReadInt(); + m_Fungus = reader.ReadInt(); + m_Poison = reader.ReadInt(); + m_Disease = reader.ReadInt(); + m_PoisonPotion = reader.ReadInt(); + m_CurePotion = reader.ReadInt(); + m_HealPotion = reader.ReadInt(); + m_StrengthPotion = reader.ReadInt(); + + m_Pollinated = reader.ReadBool(); + m_SeedType = (PlantType)reader.ReadInt(); + m_SeedHue = (PlantHue)reader.ReadInt(); + m_AvailableSeeds = reader.ReadInt(); + m_LeftSeeds = reader.ReadInt(); + + m_AvailableResources = reader.ReadInt(); + m_LeftResources = reader.ReadInt(); + + if (version < 2 && PlantHueInfo.IsCrossable(m_SeedHue)) + m_SeedHue |= PlantHue.Reproduces; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PlantType.cs b/Scripts/Engines/Plants/PlantType.cs new file mode 100644 index 0000000..6f25f0d --- /dev/null +++ b/Scripts/Engines/Plants/PlantType.cs @@ -0,0 +1,361 @@ +using System; +using Server; + +namespace Server.Engines.Plants +{ + public enum PlantType + { + CampionFlowers, + Poppies, + Snowdrops, + Bulrushes, + Lilies, + PampasGrass, + Rushes, + ElephantEarPlant, + Fern, + PonytailPalm, + SmallPalm, + CenturyPlant, + WaterPlant, + SnakePlant, + PricklyPearCactus, + BarrelCactus, + TribarrelCactus, + CommonGreenBonsai, + CommonPinkBonsai, + UncommonGreenBonsai, + UncommonPinkBonsai, + RareGreenBonsai, + RarePinkBonsai, + ExceptionalBonsai, + ExoticBonsai, + Cactus, + FlaxFlowers, + FoxgloveFlowers, + HopsEast, + OrfluerFlowers, + CypressTwisted, + HedgeShort, + JuniperBush, + SnowdropPatch, + Cattails, + PoppyPatch, + SpiderTree, + WaterLily, + CypressStraight, + HedgeTall, + HopsSouth, + SugarCanes, + CocoaTree + } + + public enum PlantCategory + { + Default, + Common = 1063335, // + Uncommon = 1063336, // + Rare = 1063337, // Bonsai + Exceptional = 1063341, // + Exotic = 1063342, // + Peculiar = 1080528, + Fragrant = 1080529 + } + + public class PlantTypeInfo + { + private static PlantTypeInfo[] m_Table = new PlantTypeInfo[] + { + new PlantTypeInfo( 0xC83, 0, 0, PlantType.CampionFlowers, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC86, 0, 0, PlantType.Poppies, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC88, 0, 10, PlantType.Snowdrops, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC94, -15, 0, PlantType.Bulrushes, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC8B, 0, 0, PlantType.Lilies, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xCA5, -8, 0, PlantType.PampasGrass, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xCA7, -10, 0, PlantType.Rushes, false, true, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC97, -20, 0, PlantType.ElephantEarPlant, true, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC9F, -20, 0, PlantType.Fern, false, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xCA6, -16, -5, PlantType.PonytailPalm, false, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xC9C, -5, -10, PlantType.SmallPalm, false, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xD31, 0, -27, PlantType.CenturyPlant, true, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xD04, 0, 10, PlantType.WaterPlant, true, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xCA9, 0, 0, PlantType.SnakePlant, true, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xD2C, 0, 10, PlantType.PricklyPearCactus, false, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xD26, 0, 10, PlantType.BarrelCactus, false, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0xD27, 0, 10, PlantType.TribarrelCactus, false, false, true, true, PlantCategory.Default ), + new PlantTypeInfo( 0x28DC, -5, 5, PlantType.CommonGreenBonsai, true, false, false, false, PlantCategory.Common ), + new PlantTypeInfo( 0x28DF, -5, 5, PlantType.CommonPinkBonsai, true, false, false, false, PlantCategory.Common ), + new PlantTypeInfo( 0x28DD, -5, 5, PlantType.UncommonGreenBonsai, true, false, false, false, PlantCategory.Uncommon ), + new PlantTypeInfo( 0x28E0, -5, 5, PlantType.UncommonPinkBonsai, true, false, false, false, PlantCategory.Uncommon ), + new PlantTypeInfo( 0x28DE, -5, 5, PlantType.RareGreenBonsai, true, false, false, false, PlantCategory.Rare ), + new PlantTypeInfo( 0x28E1, -5, 5, PlantType.RarePinkBonsai, true, false, false, false, PlantCategory.Rare ), + new PlantTypeInfo( 0x28E2, -5, 5, PlantType.ExceptionalBonsai, true, false, false, false, PlantCategory.Exceptional ), + new PlantTypeInfo( 0x28E3, -5, 5, PlantType.ExoticBonsai, true, false, false, false, PlantCategory.Exotic ), + new PlantTypeInfo( 0x0D25, 0, 0, PlantType.Cactus, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x1A9A, 5, 10, PlantType.FlaxFlowers, false, true, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0C84, 0, 0, PlantType.FoxgloveFlowers, false, true, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x1A9F, 5, -25, PlantType.HopsEast, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CC1, 0, 0, PlantType.OrfluerFlowers, false, true, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CFE, -45, -30, PlantType.CypressTwisted, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0C8F, 0, 0, PlantType.HedgeShort, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CC8, 0, 0, PlantType.JuniperBush, true, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0C8E, -20, 0, PlantType.SnowdropPatch, false, true, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CB7, 0, 0, PlantType.Cattails, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CBE, -20, 0, PlantType.PoppyPatch, false, true, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CC9, 0, 0, PlantType.SpiderTree, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0DC1, -5, 15, PlantType.WaterLily, false, true, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0CFB, -45, -30, PlantType.CypressStraight, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x0DB8, 0, -20, PlantType.HedgeTall, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x1AA1, 10, -25, PlantType.HopsSouth, false, false, false, false, PlantCategory.Peculiar ), + new PlantTypeInfo( 0x246C, -25, -20, PlantType.SugarCanes, false, false, false, false, PlantCategory.Peculiar, 1114898, 1114898, 1094702, 1094703, 1095221, 1113715 ), + new PlantTypeInfo( 0xC9E, -40, -30, PlantType.CocoaTree, false, false, false, true, PlantCategory.Fragrant, 1080536, 1080536, 1080534, 1080531, 1080533, 1113716 ) + }; + + public static PlantTypeInfo GetInfo(PlantType plantType) + { + int index = (int)plantType; + + if (index >= 0 && index < m_Table.Length) + return m_Table[index]; + else + return m_Table[0]; + } + + public static PlantType RandomFirstGeneration() + { + switch (Utility.Random(3)) + { + case 0: return PlantType.CampionFlowers; + case 1: return PlantType.Fern; + default: return PlantType.TribarrelCactus; + } + } + + public static PlantType RandomPeculiarGroupOne() + { + switch (Utility.Random(6)) + { + case 0: return PlantType.Cactus; + case 1: return PlantType.FlaxFlowers; + case 2: return PlantType.FoxgloveFlowers; + case 3: return PlantType.HopsEast; + case 4: return PlantType.CocoaTree; + default: return PlantType.OrfluerFlowers; + } + } + + public static PlantType RandomPeculiarGroupTwo() + { + switch (Utility.Random(5)) + { + case 0: return PlantType.CypressTwisted; + case 1: return PlantType.HedgeShort; + case 2: return PlantType.JuniperBush; + case 3: return PlantType.CocoaTree; + default: return PlantType.SnowdropPatch; + } + } + + public static PlantType RandomPeculiarGroupThree() + { + switch (Utility.Random(5)) + { + case 0: return PlantType.Cattails; + case 1: return PlantType.PoppyPatch; + case 2: return PlantType.SpiderTree; + case 3: return PlantType.CocoaTree; + default: return PlantType.WaterLily; + } + } + + public static PlantType RandomPeculiarGroupFour() + { + switch (Utility.Random(5)) + { + case 0: return PlantType.CypressStraight; + case 1: return PlantType.HedgeTall; + case 2: return PlantType.HopsSouth; + case 3: return PlantType.CocoaTree; + default: return PlantType.SugarCanes; + } + } + + public static PlantType RandomBonsai(double increaseRatio) + { + /* Chances of each plant type are equal to the chances of the previous plant type * increaseRatio: + * E.g.: + * chances_of_uncommon = chances_of_common * increaseRatio + * chances_of_rare = chances_of_uncommon * increaseRatio + * ... + * + * If increaseRatio < 1 -> rare plants are actually rarer than the others + * If increaseRatio > 1 -> rare plants are actually more common than the others (it might be the case with certain monsters) + * + * If a plant type (common, uncommon, ...) has 2 different colors, they have the same chances: + * chances_of_green_common = chances_of_pink_common = chances_of_common / 2 + * ... + */ + + double k1 = increaseRatio >= 0.0 ? increaseRatio : 0.0; + double k2 = k1 * k1; + double k3 = k2 * k1; + double k4 = k3 * k1; + + double exp1 = k1 + 1.0; + double exp2 = k2 + exp1; + double exp3 = k3 + exp2; + double exp4 = k4 + exp3; + + double rand = Utility.RandomDouble(); + + if (rand < 0.5 / exp4) + return PlantType.CommonGreenBonsai; + else if (rand < 1.0 / exp4) + return PlantType.CommonPinkBonsai; + else if (rand < (k1 * 0.5 + 1.0) / exp4) + return PlantType.UncommonGreenBonsai; + else if (rand < exp1 / exp4) + return PlantType.UncommonPinkBonsai; + else if (rand < (k2 * 0.5 + exp1) / exp4) + return PlantType.RareGreenBonsai; + else if (rand < exp2 / exp4) + return PlantType.RarePinkBonsai; + else if (rand < exp3 / exp4) + return PlantType.ExceptionalBonsai; + else + return PlantType.ExoticBonsai; + } + + public static bool IsCrossable(PlantType plantType) + { + return GetInfo(plantType).Crossable; + } + + public static PlantType Cross(PlantType first, PlantType second) + { + if (!IsCrossable(first) || !IsCrossable(second)) + return PlantType.CampionFlowers; + + int firstIndex = (int)first; + int secondIndex = (int)second; + + if (firstIndex + 1 == secondIndex || firstIndex == secondIndex + 1) + return Utility.RandomBool() ? first : second; + else + return (PlantType)((firstIndex + secondIndex) / 2); + } + + public static bool CanReproduce(PlantType plantType) + { + return GetInfo(plantType).Reproduces; + } + + public int GetPlantLabelSeed(PlantHueInfo hueInfo) + { + if (m_PlantLabelSeed != -1) + return m_PlantLabelSeed; + + return hueInfo.IsBright() ? 1061887 : 1061888; // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~ ~6_val~ + } + + public int GetPlantLabelPlant(PlantHueInfo hueInfo) + { + if (m_PlantLabelPlant != -1) + return m_PlantLabelPlant; + + if (m_ContainsPlant) + return hueInfo.IsBright() ? 1060832 : 1060831; // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~ + else + return hueInfo.IsBright() ? 1061887 : 1061888; // a ~1_val~ of ~2_val~ dirt with a ~3_val~ [bright] ~4_val~ ~5_val~ ~6_val~ + } + + public int GetPlantLabelFullGrown(PlantHueInfo hueInfo) + { + if (m_PlantLabelFullGrown != -1) + return m_PlantLabelFullGrown; + + if (m_ContainsPlant) + return hueInfo.IsBright() ? 1061891 : 1061889; // a ~1_HEALTH~ [bright] ~2_COLOR~ ~3_NAME~ + else + return hueInfo.IsBright() ? 1061892 : 1061890; // a ~1_HEALTH~ [bright] ~2_COLOR~ ~3_NAME~ plant + } + + public int GetPlantLabelDecorative(PlantHueInfo hueInfo) + { + if (m_PlantLabelDecorative != -1) + return m_PlantLabelDecorative; + + return hueInfo.IsBright() ? 1074267 : 1070973; // a decorative [bright] ~1_COLOR~ ~2_TYPE~ + } + + public int GetSeedLabel(PlantHueInfo hueInfo) + { + if (m_SeedLabel != -1) + return m_SeedLabel; + + return hueInfo.IsBright() ? 1061918 : 1061917; // [bright] ~1_COLOR~ ~2_TYPE~ seed + } + + public int GetSeedLabelPlural(PlantHueInfo hueInfo) + { + if (m_SeedLabelPlural != -1) + return m_SeedLabelPlural; + + return hueInfo.IsBright() ? 1113493 : 1113492; // ~1_amount~ [bright] ~2_color~ ~3_type~ seeds + } + + private int m_ItemID; + private int m_OffsetX; + private int m_OffsetY; + private PlantType m_PlantType; + private bool m_ContainsPlant; + private bool m_Flowery; + private bool m_Crossable; + private bool m_Reproduces; + private PlantCategory m_PlantCategory; + + // Cliloc overrides + private int m_PlantLabelSeed; + private int m_PlantLabelPlant; + private int m_PlantLabelFullGrown; + private int m_PlantLabelDecorative; + private int m_SeedLabel; + private int m_SeedLabelPlural; + + public int ItemID { get { return m_ItemID; } } + public int OffsetX { get { return m_OffsetX; } } + public int OffsetY { get { return m_OffsetY; } } + public PlantType PlantType { get { return m_PlantType; } } + public PlantCategory PlantCategory { get { return m_PlantCategory; } } + public int Name { get { return (m_ItemID < 0x4000) ? 1020000 + m_ItemID : 1078872 + m_ItemID; } } + + public bool ContainsPlant { get { return m_ContainsPlant; } } + public bool Flowery { get { return m_Flowery; } } + public bool Crossable { get { return m_Crossable; } } + public bool Reproduces { get { return m_Reproduces; } } + + private PlantTypeInfo(int itemID, int offsetX, int offsetY, PlantType plantType, bool containsPlant, bool flowery, bool crossable, bool reproduces, PlantCategory plantCategory) + : this(itemID, offsetX, offsetY, plantType, containsPlant, flowery, crossable, reproduces, plantCategory, -1, -1, -1, -1, -1, -1) + { + } + + private PlantTypeInfo(int itemID, int offsetX, int offsetY, PlantType plantType, bool containsPlant, bool flowery, bool crossable, bool reproduces, PlantCategory plantCategory, int plantLabelSeed, int plantLabelPlant, int plantLabelFullGrown, int plantLabelDecorative, int seedLabel, int seedLabelPlural) + { + m_ItemID = itemID; + m_OffsetX = offsetX; + m_OffsetY = offsetY; + m_PlantType = plantType; + m_ContainsPlant = containsPlant; + m_Flowery = flowery; + m_Crossable = crossable; + m_Reproduces = reproduces; + m_PlantCategory = plantCategory; + m_PlantLabelSeed = plantLabelSeed; + m_PlantLabelPlant = plantLabelPlant; + m_PlantLabelFullGrown = plantLabelFullGrown; + m_PlantLabelDecorative = plantLabelDecorative; + m_SeedLabel = seedLabel; + m_SeedLabelPlural = seedLabelPlural; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/PollinateTarget.cs b/Scripts/Engines/Plants/PollinateTarget.cs new file mode 100644 index 0000000..bec8198 --- /dev/null +++ b/Scripts/Engines/Plants/PollinateTarget.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Engines.Plants +{ + public class PollinateTarget : Target + { + private PlantItem m_Plant; + + public PollinateTarget( PlantItem plant ) : base( 3, true, TargetFlags.None ) + { + m_Plant = plant; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Plant.Deleted && m_Plant.PlantStatus < PlantStatus.DecorativePlant && from.InRange( m_Plant.GetWorldLocation(), 3 ) ) + { + if ( !m_Plant.IsUsableBy( from ) ) + { + m_Plant.LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + } + else if ( !m_Plant.IsCrossable ) + { + m_Plant.LabelTo( from, 1053050 ); // You cannot gather pollen from a mutated plant! + } + else if ( !m_Plant.PlantSystem.PollenProducing ) + { + m_Plant.LabelTo( from, 1053051 ); // You cannot gather pollen from a plant in this stage of development! + } + else if ( m_Plant.PlantSystem.Health < PlantHealth.Healthy ) + { + m_Plant.LabelTo( from, 1053052 ); // You cannot gather pollen from an unhealthy plant! + } + else + { + PlantItem targ = targeted as PlantItem; + + if ( targ == null || targ.PlantStatus >= PlantStatus.DecorativePlant || targ.PlantStatus <= PlantStatus.BowlOfDirt ) + { + m_Plant.LabelTo( from, 1053070 ); // You can only pollinate other specially grown plants! + } + else if ( !targ.IsUsableBy( from ) ) + { + targ.LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + } + else if ( !targ.IsCrossable ) + { + targ.LabelTo( from, 1053073 ); // You cannot cross-pollinate with a mutated plant! + } + else if ( !targ.PlantSystem.PollenProducing ) + { + targ.LabelTo( from, 1053074 ); // This plant is not in the flowering stage. You cannot pollinate it! + } + else if ( targ.PlantSystem.Health < PlantHealth.Healthy ) + { + targ.LabelTo( from, 1053075 ); // You cannot pollinate an unhealthy plant! + } + else if ( targ.PlantSystem.Pollinated ) + { + targ.LabelTo( from, 1053072 ); // This plant has already been pollinated! + } + else if ( targ == m_Plant ) + { + targ.PlantSystem.Pollinated = true; + targ.PlantSystem.SeedType = m_Plant.PlantType; + targ.PlantSystem.SeedHue = m_Plant.PlantHue; + + targ.LabelTo( from, 1053071 ); // You pollinate the plant with its own pollen. + } + else + { + targ.PlantSystem.Pollinated = true; + targ.PlantSystem.SeedType = PlantTypeInfo.Cross( m_Plant.PlantType, targ.PlantType ); + targ.PlantSystem.SeedHue = PlantHueInfo.Cross( m_Plant.PlantHue, targ.PlantHue ); + + targ.LabelTo( from, 1053076 ); // You successfully cross-pollinate the plant. + } + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( !m_Plant.Deleted && m_Plant.PlantStatus < PlantStatus.DecorativePlant && m_Plant.PlantStatus != PlantStatus.BowlOfDirt && from.InRange( m_Plant.GetWorldLocation(), 3 ) && m_Plant.IsUsableBy( from ) ) + { + from.SendGump( new ReproductionGump( m_Plant ) ); + } + } + } +} diff --git a/Scripts/Engines/Plants/ReproductionGump.cs b/Scripts/Engines/Plants/ReproductionGump.cs new file mode 100644 index 0000000..9d60ab6 --- /dev/null +++ b/Scripts/Engines/Plants/ReproductionGump.cs @@ -0,0 +1,272 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Plants +{ + public class ReproductionGump : Gump + { + private PlantItem m_Plant; + + public ReproductionGump( PlantItem plant ) : base( 20, 20 ) + { + m_Plant = plant; + + DrawBackground(); + + AddButton( 70, 67, 0xD4, 0xD4, 1, GumpButtonType.Reply, 0 ); // Main menu + AddItem( 57, 65, 0x1600 ); + + AddLabel( 108, 67, 0x835, "Reproduction" ); + + if ( m_Plant.PlantStatus == PlantStatus.Stage9 ) + { + AddButton( 212, 67, 0xD4, 0xD4, 2, GumpButtonType.Reply, 0 ); // Set to decorative + AddItem( 202, 68, 0xC61 ); + AddLabel( 216, 66, 0x21, "/" ); + } + + AddButton( 80, 116, 0xD4, 0xD4, 3, GumpButtonType.Reply, 0 ); // Pollination + AddItem( 66, 117, 0x1AA2 ); + AddPollinationState( 106, 116 ); + + AddButton( 128, 116, 0xD4, 0xD4, 4, GumpButtonType.Reply, 0 ); // Resources + AddItem( 113, 120, 0x1021 ); + AddResourcesState( 149, 116 ); + + AddButton( 177, 116, 0xD4, 0xD4, 5, GumpButtonType.Reply, 0 ); // Seeds + AddItem( 160, 121, 0xDCF ); + AddSeedsState( 199, 116 ); + + AddButton( 70, 163, 0xD2, 0xD2, 6, GumpButtonType.Reply, 0 ); // Gather pollen + AddItem( 56, 164, 0x1AA2 ); + + AddButton( 138, 163, 0xD2, 0xD2, 7, GumpButtonType.Reply, 0 ); // Gather resources + AddItem( 123, 167, 0x1021 ); + + AddButton( 212, 163, 0xD2, 0xD2, 8, GumpButtonType.Reply, 0 ); // Gather seeds + AddItem( 195, 168, 0xDCF ); + } + + private void DrawBackground() + { + AddBackground( 50, 50, 200, 150, 0xE10 ); + + AddImage( 60, 90, 0xE17 ); + AddImage( 120, 90, 0xE17 ); + + AddImage( 60, 145, 0xE17 ); + AddImage( 120, 145, 0xE17 ); + + AddItem( 45, 45, 0xCEF ); + AddItem( 45, 118, 0xCF0 ); + + AddItem( 211, 45, 0xCEB ); + AddItem( 211, 118, 0xCEC ); + } + + private void AddPollinationState( int x, int y ) + { + PlantSystem system = m_Plant.PlantSystem; + + if ( !system.PollenProducing ) + AddLabel( x, y, 0x35, "-" ); + else if ( !system.Pollinated ) + AddLabel( x, y, 0x21, "!" ); + else + AddLabel( x, y, 0x3F, "+" ); + } + + private void AddResourcesState( int x, int y ) + { + PlantResourceInfo resInfo = PlantResourceInfo.GetInfo( m_Plant.PlantType, m_Plant.PlantHue ); + + PlantSystem system = m_Plant.PlantSystem; + int totalResources = system.AvailableResources + system.LeftResources; + + if ( resInfo == null || totalResources == 0 ) + { + AddLabel( x + 5, y, 0x21, "X" ); + } + else + { + AddLabel( x, y, PlantHueInfo.GetInfo( m_Plant.PlantHue ).GumpHue, + string.Format( "{0}/{1}", system.AvailableResources, totalResources ) ); + } + } + + private void AddSeedsState( int x, int y ) + { + PlantSystem system = m_Plant.PlantSystem; + int totalSeeds = system.AvailableSeeds + system.LeftSeeds; + + if (!m_Plant.Reproduces || totalSeeds == 0) + { + AddLabel( x + 5, y, 0x21, "X" ); + } + else + { + AddLabel( x, y, PlantHueInfo.GetInfo( system.SeedHue ).GumpHue, + string.Format( "{0}/{1}", system.AvailableSeeds, totalSeeds ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 0 || m_Plant.Deleted || m_Plant.PlantStatus >= PlantStatus.DecorativePlant || m_Plant.PlantStatus == PlantStatus.BowlOfDirt ) + return; + + if ( ( info.ButtonID >= 6 && info.ButtonID <= 8 ) && !from.InRange( m_Plant.GetWorldLocation(), 3 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 500446 ); // That is too far away. + return; + } + + if ( !m_Plant.IsUsableBy( from ) ) + { + m_Plant.LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + return; + } + + switch ( info.ButtonID ) + { + case 1: // Main menu + { + from.SendGump( new MainPlantGump( m_Plant ) ); + + break; + } + case 2: // Set to decorative + { + if ( m_Plant.PlantStatus == PlantStatus.Stage9 ) + { + from.SendGump( new SetToDecorativeGump( m_Plant ) ); + } + + break; + } + case 3: // Pollination + { + from.Send( new DisplayHelpTopic( 67, true ) ); // POLLINATION STATE + + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + case 4: // Resources + { + from.Send( new DisplayHelpTopic( 69, true ) ); // RESOURCE PRODUCTION + + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + case 5: // Seeds + { + from.Send( new DisplayHelpTopic( 68, true ) ); // SEED PRODUCTION + + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + case 6: // Gather pollen + { + if ( !m_Plant.IsCrossable ) + { + m_Plant.LabelTo( from, 1053050 ); // You cannot gather pollen from a mutated plant! + } + else if ( !m_Plant.PlantSystem.PollenProducing ) + { + m_Plant.LabelTo( from, 1053051 ); // You cannot gather pollen from a plant in this stage of development! + } + else if ( m_Plant.PlantSystem.Health < PlantHealth.Healthy ) + { + m_Plant.LabelTo( from, 1053052 ); // You cannot gather pollen from an unhealthy plant! + } + else + { + from.Target = new PollinateTarget( m_Plant ); + from.SendLocalizedMessage( 1053054 ); // Target the plant you wish to cross-pollinate to. + + break; + } + + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + case 7: // Gather resources + { + PlantResourceInfo resInfo = PlantResourceInfo.GetInfo( m_Plant.PlantType, m_Plant.PlantHue ); + PlantSystem system = m_Plant.PlantSystem; + + if ( resInfo == null ) + { + if ( m_Plant.IsCrossable ) + m_Plant.LabelTo( from, 1053056 ); // This plant has no resources to gather! + else + m_Plant.LabelTo( from, 1053055 ); // Mutated plants do not produce resources! + } + else if ( system.AvailableResources == 0 ) + { + m_Plant.LabelTo( from, 1053056 ); // This plant has no resources to gather! + } + else + { + Item resource = resInfo.CreateResource(); + + if ( from.PlaceInBackpack( resource ) ) + { + system.AvailableResources--; + m_Plant.LabelTo( from, 1053059 ); // You gather resources from the plant. + } + else + { + resource.Delete(); + m_Plant.LabelTo( from, 1053058 ); // You attempt to gather as many resources as you can hold, but your backpack is full. + } + } + + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + case 8: // Gather seeds + { + PlantSystem system = m_Plant.PlantSystem; + + if (!m_Plant.Reproduces) + { + m_Plant.LabelTo( from, 1053060 ); // Mutated plants do not produce seeds! + } + else if ( system.AvailableSeeds == 0 ) + { + m_Plant.LabelTo( from, 1053061 ); // This plant has no seeds to gather! + } + else + { + Seed seed = new Seed( system.SeedType, system.SeedHue, true ); + + if ( from.PlaceInBackpack( seed ) ) + { + system.AvailableSeeds--; + m_Plant.LabelTo( from, 1053063 ); // You gather seeds from the plant. + } + else + { + seed.Delete(); + m_Plant.LabelTo( from, 1053062 ); // You attempt to gather as many seeds as you can hold, but your backpack is full. + } + } + + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/Seed.cs b/Scripts/Engines/Plants/Seed.cs new file mode 100644 index 0000000..e47a696 --- /dev/null +++ b/Scripts/Engines/Plants/Seed.cs @@ -0,0 +1,253 @@ +using System; +using System.Text; +using Server; +using Server.Targeting; + +namespace Server.Engines.Plants +{ + public class Seed : Item + { + private PlantType m_PlantType; + private PlantHue m_PlantHue; + private bool m_ShowType; + + [CommandProperty( AccessLevel.GameMaster )] + public PlantType PlantType + { + get { return m_PlantType; } + set + { + m_PlantType = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public PlantHue PlantHue + { + get { return m_PlantHue; } + set + { + m_PlantHue = value; + Hue = PlantHueInfo.GetInfo( value ).Hue; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ShowType + { + get { return m_ShowType; } + set + { + m_ShowType = value; + InvalidateProperties(); + } + } + + public override int LabelNumber{ get { return 1060810; } } // seed + + public static Seed RandomBonsaiSeed() + { + return RandomBonsaiSeed( 0.5 ); + } + + public static Seed RandomBonsaiSeed( double increaseRatio ) + { + return new Seed( PlantTypeInfo.RandomBonsai( increaseRatio ), PlantHue.Plain, false ); + } + + public static Seed RandomPeculiarSeed( int group ) + { + switch ( group ) + { + case 1: return new Seed ( PlantTypeInfo.RandomPeculiarGroupOne(), PlantHue.Plain, false ); + case 2: return new Seed ( PlantTypeInfo.RandomPeculiarGroupTwo(), PlantHue.Plain, false ); + case 3: return new Seed ( PlantTypeInfo.RandomPeculiarGroupThree(), PlantHue.Plain, false ); + default: return new Seed ( PlantTypeInfo.RandomPeculiarGroupFour(), PlantHue.Plain, false ); + } + } + + [Constructable] + public Seed() : this( PlantTypeInfo.RandomFirstGeneration(), PlantHueInfo.RandomFirstGeneration(), false ) + { + } + + [Constructable] + public Seed( PlantType plantType, PlantHue plantHue, bool showType ) : base( 0xDCF ) + { + Weight = 1.0; + Stackable = Core.SA; + + m_PlantType = plantType; + m_PlantHue = plantHue; + m_ShowType = showType; + + Hue = PlantHueInfo.GetInfo( plantHue ).Hue; + } + + public Seed( Serial serial ) : base( serial ) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + private int GetLabel(out string args) + { + PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo(m_PlantType); + PlantHueInfo hueInfo = PlantHueInfo.GetInfo(m_PlantHue); + + int title; + + if (m_ShowType || typeInfo.PlantCategory == PlantCategory.Default) + title = hueInfo.Name; + else + title = (int)typeInfo.PlantCategory; + + if (Amount == 1) + { + if (m_ShowType) + { + args = String.Format("#{0}\t#{1}", title, typeInfo.Name); + return typeInfo.GetSeedLabel(hueInfo); + } + else + { + args = String.Format("#{0}", title); + return hueInfo.IsBright() ? 1060839 : 1060838; // [bright] ~1_val~ seed + } + } + else + { + if (m_ShowType) + { + args = String.Format("{0}\t#{1}\t#{2}", Amount, title, typeInfo.Name); + return typeInfo.GetSeedLabelPlural(hueInfo); + } + else + { + args = String.Format("{0}\t#{1}", Amount, title); + return hueInfo.IsBright() ? 1113491 : 1113490; // ~1_amount~ [bright] ~2_val~ seeds + } + } + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + string args; + list.Add( GetLabel( out args ), args ); + } + + public override void OnSingleClick( Mobile from ) + { + string args; + LabelTo( from, GetLabel( out args ), args ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + from.Target = new InternalTarget( this ); + LabelTo( from, 1061916 ); // Choose a bowl of dirt to plant this seed in. + } + + public override bool StackWith( Mobile from, Item dropped, bool playSound ) + { + if ( dropped is Seed ) + { + Seed other = (Seed)dropped; + + if ( other.PlantType == m_PlantType && other.PlantHue == m_PlantHue && other.ShowType == m_ShowType ) + return base.StackWith( from, dropped, playSound ); + } + + return false; + } + + public override void OnAfterDuped( Item newItem ) + { + Seed newSeed = newItem as Seed; + + if ( newSeed == null ) + return; + + newSeed.PlantType = m_PlantType; + newSeed.PlantHue = m_PlantHue; + newSeed.ShowType = m_ShowType; + } + + private class InternalTarget : Target + { + private Seed m_Seed; + + public InternalTarget( Seed seed ) : base( -1, false, TargetFlags.None ) + { + m_Seed = seed; + CheckLOS = false; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Seed.Deleted ) + return; + + if ( !m_Seed.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + return; + } + + if ( targeted is PlantItem ) + { + PlantItem plant = (PlantItem)targeted; + + plant.PlantSeed( from, m_Seed ); + } + else if ( targeted is Item ) + { + ((Item)targeted).LabelTo( from, 1061919 ); // You must use a seed on a bowl of dirt! + } + else + { + from.SendLocalizedMessage( 1061919 ); // You must use a seed on a bowl of dirt! + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (int) m_PlantType ); + writer.Write( (int) m_PlantHue ); + writer.Write( (bool) m_ShowType ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_PlantType = (PlantType)reader.ReadInt(); + m_PlantHue = (PlantHue)reader.ReadInt(); + m_ShowType = reader.ReadBool(); + + if ( Weight != 1.0 ) + Weight = 1.0; + + if ( version < 1 ) + Stackable = Core.SA; + + if (version < 2 && PlantHueInfo.IsCrossable(m_PlantHue)) + m_PlantHue |= PlantHue.Reproduces; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Plants/SetToDecorativeGump.cs b/Scripts/Engines/Plants/SetToDecorativeGump.cs new file mode 100644 index 0000000..18e9a82 --- /dev/null +++ b/Scripts/Engines/Plants/SetToDecorativeGump.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Plants +{ + public class SetToDecorativeGump : Gump + { + private PlantItem m_Plant; + + public SetToDecorativeGump( PlantItem plant ) : base( 20, 20 ) + { + m_Plant = plant; + + DrawBackground(); + + AddLabel( 115, 85, 0x44, "Set plant" ); + AddLabel( 82, 105, 0x44, "to decorative mode?" ); + + AddButton( 98, 140, 0x47E, 0x480, 1, GumpButtonType.Reply, 0 ); // Cancel + + AddButton( 138, 141, 0xD2, 0xD2, 2, GumpButtonType.Reply, 0 ); // Help + AddLabel( 143, 141, 0x835, "?" ); + + AddButton( 168, 140, 0x481, 0x483, 3, GumpButtonType.Reply, 0 ); // Ok + } + + private void DrawBackground() + { + AddBackground( 50, 50, 200, 150, 0xE10 ); + + AddItem( 25, 45, 0xCEB ); + AddItem( 25, 118, 0xCEC ); + + AddItem( 227, 45, 0xCEF ); + AddItem( 227, 118, 0xCF0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 0 || m_Plant.Deleted || m_Plant.PlantStatus != PlantStatus.Stage9 ) + return; + + if ( info.ButtonID == 3 && !from.InRange( m_Plant.GetWorldLocation(), 3 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 500446 ); // That is too far away. + return; + } + + if ( !m_Plant.IsUsableBy( from ) ) + { + m_Plant.LabelTo( from, 1061856 ); // You must have the item in your backpack or locked down in order to use it. + return; + } + + switch ( info.ButtonID ) + { + case 1: // Cancel + { + from.SendGump( new ReproductionGump( m_Plant ) ); + + break; + } + case 2: // Help + { + from.Send( new DisplayHelpTopic( 70, true ) ); // DECORATIVE MODE + + from.SendGump( new SetToDecorativeGump( m_Plant ) ); + + break; + } + case 3: // Ok + { + m_Plant.PlantStatus = PlantStatus.DecorativePlant; + m_Plant.LabelTo( from, 1053077 ); // You prune the plant. This plant will no longer produce resources or seeds, but will require no upkeep. + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Ambitious Solen Queen/AmbitiousQueenQuest.cs b/Scripts/Engines/Quests/Ambitious Solen Queen/AmbitiousQueenQuest.cs new file mode 100644 index 0000000..d861f3e --- /dev/null +++ b/Scripts/Engines/Quests/Ambitious Solen Queen/AmbitiousQueenQuest.cs @@ -0,0 +1,157 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Ambitious +{ + public class AmbitiousQueenQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Ambitious.DontOfferConversation ), + typeof( Ambitious.AcceptConversation ), + typeof( Ambitious.DuringKillQueensConversation ), + typeof( Ambitious.GatherFungiConversation ), + typeof( Ambitious.DuringFungiGatheringConversation ), + typeof( Ambitious.EndConversation ), + typeof( Ambitious.FullBackpackConversation ), + typeof( Ambitious.End2Conversation ), + typeof( Ambitious.KillQueensObjective ), + typeof( Ambitious.ReturnAfterKillsObjective ), + typeof( Ambitious.GatherFungiObjective ), + typeof( Ambitious.GetRewardObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // Ambitious Solen Queen Quest + return 1054146; + } + } + + public override object OfferMessage + { + get + { + /* The Solen queen considers you eagerly for a moment then says,

+ * + * Yes. Yes, I think you could be of use. Normally, of course, I would handle + * these things on my own, but these are busy times. Much to do, much to do. + * And besides, if I am to one day become the Matriarch, then it will be good to + * have experience trusting others to carry out various tasks for me. Yes.

+ * + * That is my plan, you see - I will become the next Matriarch. Our current + * Matriarch is fine and all, but she won't be around forever. And when she steps + * down, I intend to be the next in line. Ruling others is my destiny, you see.

+ * + * What I ask of you is quite simple. First, I need you to remove some of the + * - well - competition, I suppose. Though I dare say most are hardly competent to + * live up to such a title. I'm referring to the other queens of this colony, + * of course. My dear sisters, so to speak. If you could remove 5 of them, I would + * be most pleased. *sighs* By remove, I mean kill them. Don't make that face + * at me - this is how things work in a proper society, and ours has been more proper + * than most since the dawn of time. It's them or me, and whenever I give it + * any thought, I'm quite sure I'd prefer it to be them.

+ * + * I also need you to gather some zoogi fungus for me - 50 should do the trick.

+ * + * Will you accept my offer? + */ + return 1054060; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.Zero; } } + public override bool IsTutorial{ get{ return false; } } + + public override int Picture{ get{ return 0x15C9; } } + + private bool m_RedSolen; + + public bool RedSolen{ get{ return m_RedSolen; } } + + public AmbitiousQueenQuest( PlayerMobile from, bool redSolen ) : base( from ) + { + m_RedSolen = redSolen; + } + + // Serialization + public AmbitiousQueenQuest() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_RedSolen = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_RedSolen ); + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + public static void GiveRewardTo( PlayerMobile player, ref bool bagOfSending, ref bool powderOfTranslocation, ref bool gold ) + { + if ( bagOfSending ) + { + Item reward = new BagOfSending(); + + if ( player.PlaceInBackpack( reward ) ) + { + player.SendLocalizedMessage( 1054074, "", 0x59 ); // You have been given a bag of sending. + bagOfSending = false; + } + else + { + reward.Delete(); + } + } + + if ( powderOfTranslocation ) + { + Item reward = new PowderOfTranslocation( Utility.RandomMinMax( 10, 12 ) ); + + if ( player.PlaceInBackpack( reward ) ) + { + player.SendLocalizedMessage( 1054075, "", 0x59 ); // You have been given some powder of translocation. + powderOfTranslocation = false; + } + else + { + reward.Delete(); + } + } + + if ( gold ) + { + Item reward = new Gold( Utility.RandomMinMax( 250, 350 ) ); + + if ( player.PlaceInBackpack( reward ) ) + { + player.SendLocalizedMessage( 1054076, "", 0x59 ); // You have been given some gold. + gold = false; + } + else + { + reward.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Ambitious Solen Queen/Conversations.cs b/Scripts/Engines/Quests/Ambitious Solen Queen/Conversations.cs new file mode 100644 index 0000000..c14cfb2 --- /dev/null +++ b/Scripts/Engines/Quests/Ambitious Solen Queen/Conversations.cs @@ -0,0 +1,274 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Ambitious +{ + public class DontOfferConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen considers you for a moment then says,

+ * + * Hmmm... I could perhaps benefit from your assistance, but you seem to be + * busy with another task at the moment. Return to me when you complete whatever + * it is that you're working on and maybe I can still put you to good use. + */ + return 1054059; + } + } + + public override bool Logged{ get{ return false; } } + + public DontOfferConversation() + { + } + } + + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen smiles as you decide to help her.

+ * + * Excellent. We'll worry about the zoogi fungus later - start by eliminating + * 5 queens from my colony.

That part's important, by the way; they must + * be queens from my colony. Killing queens from the other solen colony does + * little to help me become Matriarch of this colony and will not count + * toward your task.

+ * + * Oh, and none of those nasty infiltrator queens either. They perform a necessary + * duty, I suppose, spying on the other colony. I fail to see why that couldn't be + * left totally to the warriors, though. Nevertheless, they do not count as well.

+ * + * Very well. Carry on. I'll be waiting for your return. + */ + return 1054061; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new KillQueensObjective() ); + } + } + + public class DuringKillQueensConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen looks up as you approach.

+ * + * You're back, but you have not yet eliminated 5 queens from my colony. + * Return when you have completed this task.

+ * + * Remember, by the way, that queens from the other solen colony and + * infiltrator queens do not count toward your task.

+ * + * Very well. Carry on. I'll be waiting for your return. + */ + return 1054066; + } + } + + public override bool Logged{ get{ return false; } } + + public DuringKillQueensConversation() + { + } + } + + public class GatherFungiConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen looks pleased to see you.

+ * + * Splendid! You've done quite well in reducing my competition to become + * the next Matriarch. Now I must ask that you gather some zoogi fungus for me. + * I must practice processing it into powder of translocation.

+ * + * I believe the amount we agreed upon earlier was 50. Please return when + * you have that amount and then give them to me.

+ * + * Farewell for now. + */ + return 1054068; + } + } + + public GatherFungiConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GatherFungiObjective() ); + } + } + + public class DuringFungiGatheringConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen looks up as you approach.

+ * + * Do you have the zoogi fungus?

+ * + * If so, give them to me. Otherwise, go gather some and then return to me. + */ + return 1054070; + } + } + + public override bool Logged{ get{ return false; } } + + public DuringFungiGatheringConversation() + { + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen smiles as she takes the zoogi fungus from you.

+ * + * Wonderful! I greatly appreciate your help with these tasks. My plans are beginning + * to take shape ensuring that I will be the next Matriarch. But there is still + * much to be done until then.

+ * + * You've done what I've asked of you and for that I thank you. Please accept this + * bag of sending and some powder of translocation as a reward. Oh, and I suppose + * I should give you some gold as well. Yes, yes. Of course. + */ + return 1054073; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + bool bagOfSending = true; + bool powderOfTranslocation = true; + bool gold = true; + + AmbitiousQueenQuest.GiveRewardTo( System.From, ref bagOfSending, ref powderOfTranslocation, ref gold ); + + if ( !bagOfSending && !powderOfTranslocation && !gold ) + { + System.Complete(); + } + else + { + System.AddConversation( new FullBackpackConversation( true, bagOfSending, powderOfTranslocation, gold ) ); + } + } + } + + public class FullBackpackConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen looks at you with a smile.

+ * + * While I'd like to finish conducting our business, it seems that you're a + * bit overloaded with equipment at the moment.

+ * + * Perhaps you should free some room in your backpack before we proceed. + */ + return 1054077; + } + } + + private bool m_Logged; + private bool m_BagOfSending; + private bool m_PowderOfTranslocation; + private bool m_Gold; + + public override bool Logged{ get{ return m_Logged; } } + + public FullBackpackConversation( bool logged, bool bagOfSending, bool powderOfTranslocation, bool gold ) + { + m_Logged = logged; + + m_BagOfSending = bagOfSending; + m_PowderOfTranslocation = powderOfTranslocation; + m_Gold = gold; + } + + public FullBackpackConversation() + { + m_Logged = true; + } + + public override void OnRead() + { + if ( m_Logged ) + System.AddObjective( new GetRewardObjective( m_BagOfSending, m_PowderOfTranslocation, m_Gold ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_BagOfSending = reader.ReadBool(); + m_PowderOfTranslocation = reader.ReadBool(); + m_Gold = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_BagOfSending ); + writer.Write( (bool) m_PowderOfTranslocation ); + writer.Write( (bool) m_Gold ); + } + } + + public class End2Conversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen queen looks up as you approach.

+ * + * Ah good, you've returned. I will conclude our business by giving you any + * remaining rewards I owe you for aiding me. + */ + return 1054078; + } + } + + public End2Conversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Ambitious Solen Queen/Mobiles/AmbitiousSolenQueen.cs b/Scripts/Engines/Quests/Ambitious Solen Queen/Mobiles/AmbitiousSolenQueen.cs new file mode 100644 index 0000000..50f9a92 --- /dev/null +++ b/Scripts/Engines/Quests/Ambitious Solen Queen/Mobiles/AmbitiousSolenQueen.cs @@ -0,0 +1,225 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Ambitious +{ + public abstract class BaseAmbitiousSolenQueen : BaseQuester + { + public abstract bool RedSolen{ get; } + + public override bool DisallowAllMoves{ get{ return false; } } + + public BaseAmbitiousSolenQueen() + { + } + + public override void InitBody() + { + Name = "an ambitious solen queen"; + + Body = 0x30F; + + if ( !RedSolen ) + Hue = 0x453; + + SpeechHue = 0; + } + + public override int GetIdleSound() + { + return 0x10D; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + this.Direction = GetDirectionTo( player ); + + AmbitiousQueenQuest qs = player.Quest as AmbitiousQueenQuest; + + if ( qs != null && qs.RedSolen == this.RedSolen ) + { + if ( qs.IsObjectiveInProgress( typeof( KillQueensObjective ) ) ) + { + qs.AddConversation( new DuringKillQueensConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( ReturnAfterKillsObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( GatherFungiObjective ) ) ) + { + qs.AddConversation( new DuringFungiGatheringConversation() ); + } + else + { + GetRewardObjective lastObj = qs.FindObjective( typeof( GetRewardObjective ) ) as GetRewardObjective; + + if ( lastObj != null && !lastObj.Completed ) + { + bool bagOfSending = lastObj.BagOfSending; + bool powderOfTranslocation = lastObj.PowderOfTranslocation; + bool gold = lastObj.Gold; + + AmbitiousQueenQuest.GiveRewardTo( player, ref bagOfSending, ref powderOfTranslocation, ref gold ); + + lastObj.BagOfSending = bagOfSending; + lastObj.PowderOfTranslocation = powderOfTranslocation; + lastObj.Gold = gold; + + if ( !bagOfSending && !powderOfTranslocation && !gold ) + { + lastObj.Complete(); + } + else + { + qs.AddConversation( new FullBackpackConversation( false, lastObj.BagOfSending, lastObj.PowderOfTranslocation, lastObj.Gold ) ); + } + } + } + } + } + else + { + QuestSystem newQuest = new AmbitiousQueenQuest( player, this.RedSolen ); + + if ( player.Quest == null && QuestSystem.CanOfferQuest( player, typeof( AmbitiousQueenQuest ) ) ) + { + newQuest.SendOffer(); + } + else + { + newQuest.AddConversation( new DontOfferConversation() ); + } + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + this.Direction = GetDirectionTo( from ); + + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + AmbitiousQueenQuest qs = player.Quest as AmbitiousQueenQuest; + + if ( qs != null && qs.RedSolen == this.RedSolen ) + { + QuestObjective obj = qs.FindObjective( typeof( GatherFungiObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( dropped is ZoogiFungus ) + { + ZoogiFungus fungi = (ZoogiFungus)dropped; + + if ( fungi.Amount >= 50 ) + { + obj.Complete(); + + fungi.Amount -= 50; + + if ( fungi.Amount == 0 ) + { + fungi.Delete(); + return true; + } + else + { + return false; + } + } + else + { + SayTo( player, 1054072 ); // Our arrangement was for 50 of the zoogi fungus. Please return to me when you have that amount. + return false; + } + } + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + public BaseAmbitiousSolenQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class RedAmbitiousSolenQueen : BaseAmbitiousSolenQueen + { + public override bool RedSolen{ get{ return true; } } + + [Constructable] + public RedAmbitiousSolenQueen() + { + } + + public RedAmbitiousSolenQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BlackAmbitiousSolenQueen : BaseAmbitiousSolenQueen + { + public override bool RedSolen{ get{ return false; } } + + [Constructable] + public BlackAmbitiousSolenQueen() + { + } + + public BlackAmbitiousSolenQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Ambitious Solen Queen/Objectives.cs b/Scripts/Engines/Quests/Ambitious Solen Queen/Objectives.cs new file mode 100644 index 0000000..7bfca2a --- /dev/null +++ b/Scripts/Engines/Quests/Ambitious Solen Queen/Objectives.cs @@ -0,0 +1,175 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Ambitious +{ + public class KillQueensObjective : QuestObjective + { + public override object Message + { + get + { + // Kill 5 red/black solen queens. + return ((AmbitiousQueenQuest)System).RedSolen ? 1054062 : 1054063; + } + } + + public override int MaxProgress{ get{ return 5; } } + + public KillQueensObjective() + { + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Red/Black Solen Queens killed: + gump.AddHtmlLocalized( 70, 260, 270, 100, ((AmbitiousQueenQuest)System).RedSolen ? 1054064 : 1054065, BaseQuestGump.Blue, false, false ); + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, MaxProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + if ( Completed ) + return false; + + bool redSolen = ((AmbitiousQueenQuest)System).RedSolen; + + if ( redSolen ) + return from is RedSolenQueen; + else + return from is BlackSolenQueen; + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + bool redSolen = ((AmbitiousQueenQuest)System).RedSolen; + + if ( redSolen ) + { + if ( creature is RedSolenQueen ) + CurProgress++; + } + else + { + if ( creature is BlackSolenQueen ) + CurProgress++; + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnAfterKillsObjective() ); + } + } + + public class ReturnAfterKillsObjective : QuestObjective + { + public override object Message + { + get + { + /* You've completed your task of slaying solen queens. Return to + * the ambitious queen who asked for your help. + */ + return 1054067; + } + } + + public ReturnAfterKillsObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new GatherFungiConversation() ); + } + } + + public class GatherFungiObjective : QuestObjective + { + public override object Message + { + get + { + /* Gather zoogi fungus until you have 50 of them, then give them + * to the ambitious queen you are helping. + */ + return 1054069; + } + } + + public GatherFungiObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new EndConversation() ); + } + } + + public class GetRewardObjective : QuestObjective + { + public override object Message + { + get + { + // Return to the ambitious solen queen for your reward. + return 1054148; + } + } + + private bool m_BagOfSending; + private bool m_PowderOfTranslocation; + private bool m_Gold; + + public bool BagOfSending{ get{ return m_BagOfSending; } set{ m_BagOfSending = value; } } + public bool PowderOfTranslocation{ get{ return m_PowderOfTranslocation; } set{ m_PowderOfTranslocation = value; } } + public bool Gold{ get{ return m_Gold; } set{ m_Gold = value; } } + + public GetRewardObjective( bool bagOfSending, bool powderOfTranslocation, bool gold) + { + m_BagOfSending = bagOfSending; + m_PowderOfTranslocation = powderOfTranslocation; + m_Gold = gold; + } + + public GetRewardObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new End2Conversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_BagOfSending = reader.ReadBool(); + m_PowderOfTranslocation = reader.ReadBool(); + m_Gold = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_BagOfSending ); + writer.Write( (bool) m_PowderOfTranslocation ); + writer.Write( (bool) m_Gold ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/CollectorQuest.cs b/Scripts/Engines/Quests/Collector/CollectorQuest.cs new file mode 100644 index 0000000..541547e --- /dev/null +++ b/Scripts/Engines/Quests/Collector/CollectorQuest.cs @@ -0,0 +1,122 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Collector +{ + public class CollectorQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Collector.DontOfferConversation ), + typeof( Collector.DeclineConversation ), + typeof( Collector.AcceptConversation ), + typeof( Collector.ElwoodDuringFishConversation ), + typeof( Collector.ReturnPearlsConversation ), + typeof( Collector.AlbertaPaintingConversation ), + typeof( Collector.AlbertaStoolConversation ), + typeof( Collector.AlbertaEndPaintingConversation ), + typeof( Collector.AlbertaAfterPaintingConversation ), + typeof( Collector.ElwoodDuringPainting1Conversation ), + typeof( Collector.ElwoodDuringPainting2Conversation ), + typeof( Collector.ReturnPaintingConversation ), + typeof( Collector.GabrielAutographConversation ), + typeof( Collector.GabrielNoSheetMusicConversation ), + typeof( Collector.NoSheetMusicConversation ), + typeof( Collector.GetSheetMusicConversation ), + typeof( Collector.GabrielSheetMusicConversation ), + typeof( Collector.GabrielIgnoreConversation ), + typeof( Collector.ElwoodDuringAutograph1Conversation ), + typeof( Collector.ElwoodDuringAutograph2Conversation ), + typeof( Collector.ElwoodDuringAutograph3Conversation ), + typeof( Collector.ReturnAutographConversation ), + typeof( Collector.TomasToysConversation ), + typeof( Collector.TomasDuringCollectingConversation ), + typeof( Collector.ReturnImagesConversation ), + typeof( Collector.ElwoodDuringToys1Conversation ), + typeof( Collector.ElwoodDuringToys2Conversation ), + typeof( Collector.ElwoodDuringToys3Conversation ), + typeof( Collector.FullEndConversation ), + typeof( Collector.FishPearlsObjective ), + typeof( Collector.ReturnPearlsObjective ), + typeof( Collector.FindAlbertaObjective ), + typeof( Collector.SitOnTheStoolObjective ), + typeof( Collector.ReturnPaintingObjective ), + typeof( Collector.FindGabrielObjective ), + typeof( Collector.FindSheetMusicObjective ), + typeof( Collector.ReturnSheetMusicObjective ), + typeof( Collector.ReturnAutographObjective ), + typeof( Collector.FindTomasObjective ), + typeof( Collector.CaptureImagesObjective ), + typeof( Collector.ReturnImagesObjective ), + typeof( Collector.ReturnToysObjective ), + typeof( Collector.MakeRoomObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + //return 1020549; // This localized message seems broken... + return "Collector's Quest"; + } + } + + public override object OfferMessage + { + get + { + /* Elwood greets you warmly, like an old friend he's not + * quite sure he ever had.

+ * + * Hello. Yes. Sit down. Please. Good. Okay, stand. Up to you.

+ * + * So, what brings you to these parts... hey, wait. Just had a thought. + * Would you like to do me a favor? Yes, really. You know, for old + * times sake. The good ole days. You were always one of my best + * suppliers. Or maybe you weren't, who knows any more. Anyway, + * could use some help supplementing my stock. You know me. Always + * looking for something new to add to the collection. Or sometimes + * not so new - just more of the same. But don't have to tell you that. + * You know, don't you. Yes. Just like old times. That's what it'll be. + * You and me - together again. Ah, it's been too long.

+ * + * So what do you think? The fee will be the same as always. I'm a fair + * man. You know that. So what do you say? + */ + return 1055081; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.Zero; } } + public override bool IsTutorial{ get{ return false; } } + + public override int Picture{ get{ return 0x15A9; } } + + public CollectorQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public CollectorQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + public override void Decline() + { + base.Decline(); + + AddConversation( new DeclineConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Conversations.cs b/Scripts/Engines/Quests/Collector/Conversations.cs new file mode 100644 index 0000000..76a014e --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Conversations.cs @@ -0,0 +1,874 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Collector +{ + public class DontOfferConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood looks up from his ale as you greet him.

+ * + * What's that? Who me? No, no. You must be looking for someone else. + */ + return 1055080; + } + } + + public override bool Logged{ get{ return false; } } + + public DontOfferConversation() + { + } + } + + public class DeclineConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood looks a bit flustered and nearly knocks over his + * bottle of ale.

+ * + * Well, I see. It's like that, is it? Yes. Well then. Okay. + * You've changed. Yes. Yes, you have. Something's changed. I know + * I haven't. Not me. Not good ole Elwood.

+ * + * Elwood trails off, though you can still hear him muttering softly. + */ + return 1055082; + } + } + + public override bool Logged{ get{ return false; } } + + public DeclineConversation() + { + } + } + + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood slaps his knee and grins at you.

+ * + * Yes. Yes. That's the spirit. I knew it. Knew it when I + * first saw you. You remind me so much of your dear departed + * father. Or someone. Not sure. Maybe no one. But that's okay. + * Ah, good times.

+ * + * Anyway, so as you know, I'm a collector. Got all kinds of + * interesting things laying around back at my warehouse. + * You know. You've seen it. Haven't you? Yes? No? Nevermind. + * Not important.

+ * + * Right. So, always trying to add new things to my collection. + * Or sometimes just get more of something. Can't have too many. + * Right? Yeah? Sure.

+ * + * Let's see. Where to start. Oh, I know. Pearls. Yes. But not + * just any pearls. Rainbow pearls. Yes. From the lake here in + * Haven. Seems all that magic Uzeraan was throwing around when + * he transformed the island had an interesting effect on some + * of the shellfish down there. Exactly, rainbow pearls. Useless + * for magic, but an item worth collecting. Trust me on this. + * Trust me.

+ * + * Need you to go fish some up for me. Down at the lake. Lake Haven. + * Off ya go. Happy fishing!

+ * + * Elwood turns back to his ale and now seems oblivious to you. + */ + return 1055083; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FishPearlsObjective() ); + } + } + + public class ElwoodDuringFishConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood looks up as you tap him on the shoulder.

+ * + * Good. Good. You're back. Wait. You don't have the rainbow pearls I + * need. Taking a break? Yeah. Sure. There's no hurry. Let me know when + * you've got all those pearls, though. I'll be here. + */ + return 1055089; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringFishConversation() + { + } + } + + public class ReturnPearlsConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood jumps slightly when you call his name.

+ * + * What. I'm awake. Oh, It's you. Hey, look at those pearls. + * Beautiful. Wow. Where'd you get those... oh right. I sent you to get + * them. From the lake. Lake Haven. Great job. Gotta love rainbow + * pearls. Oooh, Colors.

+ * + * Okay, let's see. Next. Need a painting. Go to the Colored Canvas and + * speak to Alberta. Alberta Giacco. Best painter I've ever met. Ask + * her to do a painting of you. Yes. Of you. A portrait. Never know if + * you might up and become famous one day. Need to have a painting of you + * in my collection. From now. Before all the fame. Go. Alberta awaits. + * She's in Vesper.

+ * + * Elwood starts playing with the pearls you brought him and seems + * to have forgotten you're there. + */ + return 1055090; + } + } + + public ReturnPearlsConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindAlbertaObjective() ); + } + } + + public class AlbertaPaintingConversation : QuestConversation + { + public override object Message + { + get + { + /* Alberta looks up from the painting she is working on and + * faces you.

+ * + * Excuse me. I don't mean to be rude, but I'm in the middle + * of something, and can't... oh wait, I see. You must be the one + * Elwood sent over.

+ * + * Very well. If you'll have a seat on the stool over there, we'll + * get started. This will just take a few seconds. I paint quite + * quickly, you see. I'll start once you are seated.

+ * + * Alberta exchanges the painting she was working on for a blank canvas. + */ + return 1055092; + } + } + + public AlbertaPaintingConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SitOnTheStoolObjective() ); + } + } + + public class AlbertaStoolConversation : QuestConversation + { + public override object Message + { + get + { + /* Alberta looks at you sympathetically.

+ * + * Don't worry, this will only take a few seconds. I realize + * that stool can be uncomfortable, and I apologize for that. + * Perhaps I should replace it with a more comfortable chair. + * But then again, it's that very discomfort that helps produce + * such wonderful facial expressions for my paintings. Ah well. + */ + return 1055096; + } + } + + public override bool Logged{ get{ return false; } } + + public AlbertaStoolConversation() + { + } + } + + public class AlbertaEndPaintingConversation : QuestConversation + { + public override object Message + { + get + { + /* Alberta stands back from the canvas and surveys her + * work.

+ * + * Not too bad. Quite good even, if I do say so myself. As always, + * of course.

+ * + * Oh, you're still here. Please let Elwood know that the painting + * has been completed. I'll have it sent to him once it dries.

+ * + * Alberta removes the portrait from her easel and sets + * it aside to dry. + */ + return 1055098; + } + } + + public AlbertaEndPaintingConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnPaintingObjective() ); + } + } + + public class AlbertaAfterPaintingConversation : QuestConversation + { + public override object Message + { + get + { + /* Alberta stops cleaning her brushes and looks your way.

+ * + * Don't worry, I'll send the painting to Elwood once it's dry. Please + * let him know that the painting has been finished. + */ + return 1055102; + } + } + + public override bool Logged{ get{ return false; } } + + public AlbertaAfterPaintingConversation() + { + } + } + + public class ElwoodDuringPainting1Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood yawns and stretches, then focuses his gaze + * on you.

+ * + * Hello. Do I know you? Hold on a second. Yes. Yes, I do. + * You were going to bring me some rainbow pearls. Wait. No. + * You already did that. I remember now. Right. So go get that + * portrait painted. Alberta is in Vesper. Go to her. Alberta + * Giacco. Come back when she's done. + */ + return 1055094; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringPainting1Conversation() + { + } + } + + public class ElwoodDuringPainting2Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood drums his fingers on the counter then looks + * up at you expectantly.

+ * + * Ah, finally. I'm famished. This so-called tavern doesn't + * even serve pizza, so one must have it delivered. It's an + * outrage. Er... wait. Where's my pizza? Yes, my pizza. + * What kind of delivery is this? Didn't even bring my pizza. + * This will severely impact your tip, I'm afraid.

+ * + * Hold on a moment. You were helping me with something else, + * weren't you? Ah. Yes. I've got it now. You were to have a + * portrait done. Well. Good. Yes. But let's not dawdle. + * Off you go. If you happen to see anyone with my pizza, + * please insist they hurry.

+ */ + return 1055097; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringPainting2Conversation() + { + } + } + + public class ReturnPaintingConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood notices you immediately and waves you over.

+ * + * You're back. Good. That's good. Hmm. You don't seem to have that + * painting yet. Don't tell me Alberta refused. That's no good. I made + * her what she is! She was living in the gutter when I found her. The + * gutter. And she has the... what's that? Oh, she finished the portrait. + * Right. Good. Can always count on Alberta. Always. Best painter in + * the land.

+ * + * Just have a couple... er... wait... make that... two more task for you. + * Then our business will be concluded. For now. Old chums like us will + * always work together again. Yes. We go so far back. Right. I think.

+ * + * Anyway. There's a musician. A minstrel. His name's Gabriel Piete. Quite + * the good singer. One of my favorites. Absolute favorite. What I'd like + * is his autograph. Simple. Just his autograph. You're likely to find him + * at the Conservatory of Music in Britain. He's often there. Often. Between + * performances. Hurry now. There ya go.

+ * + * Elwood falls silent though his lips are still moving. It looks like + * he's quietly repeating the word, "autograph." + */ + return 1055100; + } + } + + public ReturnPaintingConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindGabrielObjective() ); + } + } + + public class GabrielAutographConversation : QuestConversation + { + public override object Message + { + get + { + /* Gabriel sighs loudly as you address him and stops whatever + * it was that he was doing.

+ * + * WHAT?!? Can you not see that I'm working here? Ugh, sometimes + * I wish they'd just lock the outer doors to anyone who doesn't + * belong here. So go ahead and fawn. Get it over with, and then + * leave. Sooner you're out of here, the sooner I'm back to work.

+ * + * I see. So you want an autograph. Fine. If it'll get rid of you, + * I'll give you my autograph. But I'll only sign some sheet music + * for one of my songs. Until then, please let me get back to work.

+ * + * You can probably find some of my sheet music at one of the theaters + * in the land. When I perform there, they often sell it as a souvenir. + * Speak to the impresario... the theater manager. My last three + * performances were in Nujel'm, Jhelom, and here in Britian. + */ + return 1055103; + } + } + + public GabrielAutographConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindSheetMusicObjective( true ) ); + } + } + + public class GabrielNoSheetMusicConversation : QuestConversation + { + public override object Message + { + get + { + /* Gabriel does not look happy to see you.

+ * + * Do you have any sheet music? No. Please return when you do, + * but until then please leave me to my work. + */ + return 1055111; + } + } + + public override bool Logged{ get{ return false; } } + + public GabrielNoSheetMusicConversation() + { + } + } + + public class NoSheetMusicConversation : QuestConversation + { + public override object Message + { + get + { + /* Sheet music for a Gabriel Piete song? No, I'm sorry, but we've run out. + * We might get some more after he performs here again, but right now + * we don't have any. My apologies. + */ + return 1055106; + } + } + + public override bool Logged{ get{ return false; } } + + public NoSheetMusicConversation() + { + } + } + + public class GetSheetMusicConversation : QuestConversation + { + public override object Message + { + get + { + // The theater impresario hands you some sheet of music for one of Gabriel Piete's songs. + return 1055109; + } + } + + public GetSheetMusicConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnSheetMusicObjective() ); + } + } + + public class GabrielSheetMusicConversation : QuestConversation + { + public override object Message + { + get + { + /* Gabriel looks up impatiently as you approach.

+ * + * Good. We can finally be done with one another. Here, let me + * sign that and have this business completed.

+ * + * Gabriel takes the sheet music, autographs it, and then hands it back to you. + */ + return 1055113; + } + } + + public GabrielSheetMusicConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnAutographObjective() ); + } + } + + public class GabrielIgnoreConversation : QuestConversation + { + public override object Message + { + get + { + // Gabriel ignores you. + return 1055118; + } + } + + public override bool Logged{ get{ return false; } } + + public GabrielIgnoreConversation() + { + } + } + + public class ElwoodDuringAutograph1Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood jumps and almost falls from his stool when you + * tap his shoulder.

+ * + * Oh my. Don't do that. Scared me half to death. Sneaking up on + * people like that. I don't even know you. Yes, I do. I do know you. + * Ordered a pizza from you and never received it. I'm rather miffed + * about that.

+ * + * No. No. Wait. Of course. Not the pizza. You're here with the + * moonfire brew I wanted. Magical moonfire brew. Not sure what it is. + * Just want some.

+ * + * What's that? Oh. The autograph. Gabriel Piete. Yes. Of course. + * Do you have it? No. Well. Hmm. Don't sneak up on people like that. Not polite. + */ + return 1055105; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringAutograph1Conversation() + { + } + } + + public class ElwoodDuringAutograph2Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood seems to be studying the bottom of his bottle of ale + * as you approach.

+ * + * What's this? Strange. Quite strange. I could have sworn I was + * drinking wine.

+ * + * Oh, hello. Yes. Good to see you. Any luck with that autograph? + * Bet you thought I'd forgotten. No. Not me. Mind like a steel trap. + * Can't get it open no matter how hard you try. Or something. No luck + * yet? Ah well. keep trying. I have faith in you. Whoever you are. + */ + return 1055112; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringAutograph2Conversation() + { + } + } + + public class ElwoodDuringAutograph3Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood scratches his ear then notices you.

+ * + * Good day. What brings you to the Albatross? Me? An autograph? + * You want my autograph? Well, I suppose. What's that? Oh. Yes. + * Gabriel Piete. Yes. Get his autograph and return to me. Good day. + */ + return 1055115; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringAutograph3Conversation() + { + } + } + + public class ReturnAutographConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood looks up eagerly as you tell him about the autographed + * sheet music.

+ * + * Quite good work. Not an easy one to deal with, that one. Gabriel Piete. + * Yes. Well done. Nice autograph.

+ * + * One last task. I would like a set of toy monster figurines made by the + * famous toymaker, Tomas O'Neerlan. You'll find him in Trinsic. He's often + * at the Tinker's Guild. Try looking there.

+ * + * You're doing quite well. Quite well indeed. Knew you would. Just like old + * times. Yes. Quite good. + */ + return 1055116; + } + } + + public ReturnAutographConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindTomasObjective() ); + } + } + + public class TomasToysConversation : QuestConversation + { + public override object Message + { + get + { + /* Tomas smiles freely as you speak to him.

+ * + * Ah, to be sure I can make you some toy monster figurines. + * That's my work, making toys. Worry not, we'll put together + * a good set of monsters for you and your figurines.

+ * + * But I'll be needing something from you before I can begin. + * Here, take these enchanted paints. Using them, you can capture + * a set of images of the creatures you wish me to make into toys. + * It'll only work on the group of creatures I select for your + * set of figurines. Oh, and I'll be needing those enchanted paints + * back when all is said and done.

+ */ + return 1055119; + } + } + + public TomasToysConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new CaptureImagesObjective( true ) ); + } + } + + public class TomasDuringCollectingConversation : QuestConversation + { + public override object Message + { + get + { + /* Tomas greets you warmly as you approach.

+ * + * 'Tis good to see you. I see that you have not yet collected + * all of the images we need. 'Tis fine, but I'll be needing + * those before I can make the toy figurines. Return when you have + * the complete set of images.

+ */ + return 1055129; + } + } + + public override bool Logged{ get{ return false; } } + + public TomasDuringCollectingConversation() + { + } + } + + public class ReturnImagesConversation : QuestConversation + { + public override object Message + { + get + { + /* Tomas grins as you walk toward him.

+ * + * I see that you have collected all of the images we need. + * 'Tis good. I'll begin straight away on the toy figurines. + * I'll have them delivered to you when ready. Where shall I send + * them? To Elwood in Haven? Yes, I know him. We've done business + * in the past. Odd fellow.

Tomas smiles as you return his + * enchanted paints back to him.

+ */ + return 1055131; + } + } + + public ReturnImagesConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnToysObjective() ); + } + } + + public class ElwoodDuringToys1Conversation : QuestConversation + { + public override object Message + { + get + { + /* You watch as Elwood spins around blissfully on his stool.

+ * + * Oh. Forgive me. Didn't see you there. Whoo. Dizzy. Can't see straight. + * Have you gotten those figurines yet? No. Ah. Not to worry. Keep at it. + * No doubt you'll come through with those.

+ * + * Excuse me a moment. I think I need to sit down. Wait. I am sitting down. + * Good then. Yes. Sitting down.

Elwood reaches out and takes hold + * of the counter as if to steady himself. + */ + return 1055123; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringToys1Conversation() + { + } + } + + public class ElwoodDuringToys2Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood suddenly stops and beckons you over to him.

+ * + * Over here. Come here. Don't be alarmed, but I think one of the + * tavernkeepers used to be a wandering healer. Said something about + * the good ole days when people would just walk up and hand gold to + * them. Piles of gold. Out of the blue. Can you imagine? Got so much + * gold, this ex-healer decided to buy a tavern and settle down. Kind + * of sad really. Can't even cure my hangover now. Nice tavern though.

+ * + * Right. Anyway. Let me know when those toy figurines are ready. + * I'll be here. As always. + */ + return 1055130; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringToys2Conversation() + { + } + } + + public class ElwoodDuringToys3Conversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood is singing as you greet him.

+ * + * Come. Join in. It's a Gabriel Piete song. I have the sheet music + * for it. It's even autographed by Gabriel Piete himself. Yes. + * One of his songs. Brilliant.

+ * + * So let me see the toys. Figurines. Let's see them. Oh. You don't + * have them yet. I see. Well. Okay. That's too bad. + */ + return 1055133; + } + } + + public override bool Logged{ get{ return false; } } + + public ElwoodDuringToys3Conversation() + { + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* Elwood takes a sip of his ale as you address him.

+ * + * Ah. That's the stuff. Ale. Nothing better. What's that? Toy figurines + * will be delivered. Right. Yes. Perhaps better than Ale. Tough one.

+ * + * Very good work. Quite. Think we're all done now. You completed everything + * I asked. Would work with you again. Yes. We should.

+ * + * Ah. Yes. your payment. The usual. I think you'll be pleased.

+ * + * With that Elwood rummages around in his backpack. He eventually + * pulls out a small bag and hands it to you. + */ + return 1055134; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class FullEndConversation : QuestConversation + { + private bool m_Logged; + + public override object Message + { + get + { + /* Elwood stares at you as you approach.

+ * + * I know you. Oh yes. You've been running some errands for me. + * We are about done. Noticed that your backpack is a bit full. + * Might want to make some room. Won't be able to hold your payment. + * Come back when you have more room, and we'll conclude our business. + */ + return 1055135; + } + } + + public override bool Logged{ get{ return m_Logged; } } + + public FullEndConversation( bool logged ) + { + m_Logged = logged; + } + + public FullEndConversation() + { + m_Logged = true; + } + + public override void OnRead() + { + if ( m_Logged ) + System.AddObjective( new MakeRoomObjective() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Items/EnchantedPaints.cs b/Scripts/Engines/Quests/Collector/Items/EnchantedPaints.cs new file mode 100644 index 0000000..6e8649a --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Items/EnchantedPaints.cs @@ -0,0 +1,141 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Collector +{ + public class EnchantedPaints : QuestItem + { + [Constructable] + public EnchantedPaints() : base( 0xFC1 ) + { + LootType = LootType.Blessed; + + Weight = 1.0; + } + + public EnchantedPaints( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + CollectorQuest qs = player.Quest as CollectorQuest; + + if ( qs == null ) + return true; + + /*return !( qs.IsObjectiveInProgress( typeof( CaptureImagesObjective ) ) + || qs.IsObjectiveInProgress( typeof( ReturnImagesObjective ) ) );*/ + return false; + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( CaptureImagesObjective ) ) ) + { + player.SendAsciiMessage( 0x59, "Target the creature whose image you wish to create." ); + player.Target = new InternalTarget( this ); + + return; + } + } + } + + from.SendLocalizedMessage( 1010085 ); // You cannot use this. + } + + private class InternalTarget : Target + { + private EnchantedPaints m_Paints; + + public InternalTarget( EnchantedPaints paints ) : base( -1, false, TargetFlags.None ) + { + CheckLOS = false; + m_Paints = paints; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Paints.Deleted || !m_Paints.IsChildOf( from.Backpack ) ) + return; + + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + CaptureImagesObjective obj = qs.FindObjective( typeof( CaptureImagesObjective ) ) as CaptureImagesObjective; + + if ( obj != null && !obj.Completed ) + { + if ( targeted is Mobile ) + { + ImageType image; + CaptureResponse response = obj.CaptureImage(( targeted.GetType().Name=="GreaterMongbat" ? new Mongbat().GetType() : targeted.GetType() ), out image ); + + switch ( response ) + { + case CaptureResponse.Valid: + { + player.SendLocalizedMessage( 1055125 ); // The enchanted paints swirl for a moment then an image begins to take shape. *Click* + player.AddToBackpack( new PaintedImage( image ) ); + + break; + } + case CaptureResponse.AlreadyDone: + { + player.SendAsciiMessage( 0x2C, "You have already captured the image of this creature" ); + + break; + } + case CaptureResponse.Invalid: + { + player.SendLocalizedMessage( 1055124 ); // You have no interest in capturing the image of this creature. + + break; + } + } + } + else + { + player.SendAsciiMessage( 0x35, "You have no interest in that." ); + } + + return; + } + } + } + + from.SendLocalizedMessage( 1010085 ); // You cannot use this. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Items/ImageType.cs b/Scripts/Engines/Quests/Collector/Items/ImageType.cs new file mode 100644 index 0000000..67e0b62 --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Items/ImageType.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Collector +{ + public enum ImageType + { + Betrayer, + Bogling, + BogThing, + Gazer, + Beetle, + GiantBlackWidow, + Scorpion, + JukaMage, + JukaWarrior, + Lich, + MeerMage, + MeerWarrior, + Mongbat, + Mummy, + Pixie, + PlagueBeast, + SandVortex, + StoneGargoyle, + SwampDragon, + Wisp, + Juggernaut + } + + public class ImageTypeInfo + { + private static readonly ImageTypeInfo[] m_Table = new ImageTypeInfo[] + { + new ImageTypeInfo( 9734, typeof( Betrayer ), 75, 45 ), + new ImageTypeInfo( 9735, typeof( Bogling ), 75, 45 ), + new ImageTypeInfo( 9736, typeof( BogThing ), 60, 47 ), + new ImageTypeInfo( 9615, typeof( Gazer ), 75, 45 ), + new ImageTypeInfo( 9743, typeof( Beetle ), 60, 55 ), + new ImageTypeInfo( 9667, typeof( GiantBlackWidow ), 55, 52 ), + new ImageTypeInfo( 9657, typeof( Scorpion ), 65, 47 ), + new ImageTypeInfo( 9758, typeof( JukaMage ), 75, 45 ), + new ImageTypeInfo( 9759, typeof( JukaWarrior ), 75, 45 ), + new ImageTypeInfo( 9636, typeof( Lich ), 75, 45 ), + new ImageTypeInfo( 9756, typeof( MeerMage ), 75, 45 ), + new ImageTypeInfo( 9757, typeof( MeerWarrior ), 75, 45 ), + new ImageTypeInfo( 9638, typeof( Mongbat ), 70, 50 ), + new ImageTypeInfo( 9639, typeof( Mummy ), 75, 45 ), + new ImageTypeInfo( 9654, typeof( Pixie ), 75, 45 ), + new ImageTypeInfo( 9747, typeof( PlagueBeast ), 60, 45 ), + new ImageTypeInfo( 9750, typeof( SandVortex ), 60, 43 ), + new ImageTypeInfo( 9614, typeof( StoneGargoyle ), 75, 45 ), + new ImageTypeInfo( 9753, typeof( SwampDragon ), 50, 55 ), + new ImageTypeInfo( 8448, typeof( Wisp ), 75, 45 ), + new ImageTypeInfo( 9746, typeof( Juggernaut ), 55, 38 ) + }; + + public static ImageTypeInfo Get( ImageType image ) + { + int index = (int)image; + if ( index >= 0 && index < m_Table.Length ) + return m_Table[index]; + else + return m_Table[0]; + } + + public static ImageType[] RandomList( int count ) + { + ArrayList list = new ArrayList( m_Table.Length ); + for ( int i = 0; i < m_Table.Length; i++ ) + list.Add( (ImageType)i ); + + ImageType[] images = new ImageType[count]; + + for ( int i = 0; i < images.Length; i++ ) + { + int index = Utility.Random( list.Count ); + images[i] = (ImageType)list[index]; + + list.RemoveAt( index ); + } + + return images; + } + + private int m_Figurine; + private Type m_Type; + private int m_X; + private int m_Y; + + public int Figurine { get { return m_Figurine; } } + public Type Type { get { return m_Type; } } + public int Name { get { return m_Figurine < 0x4000 ? 1020000 + m_Figurine : 1078872 + m_Figurine; } } + public int X { get { return m_X; } } + public int Y { get { return m_Y; } } + + public ImageTypeInfo( int figurine, Type type, int x, int y ) + { + m_Figurine = figurine; + m_Type = type; + m_X = x; + m_Y = y; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Items/Obsidian.cs b/Scripts/Engines/Quests/Collector/Items/Obsidian.cs new file mode 100644 index 0000000..3c7ff8e --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Items/Obsidian.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Engines.Quests.Collector +{ + public class Obsidian : Item + { + private static readonly string[] m_Names = new string[] + { + null, + "an aggressive cavalier", + "a beguiling rogue", + "a benevolent physician", + "a brilliant artisan", + "a capricious adventurer", + "a clever beggar", + "a convincing charlatan", + "a creative inventor", + "a creative tinker", + "a cunning knave", + "a dauntless explorer", + "a despicable ruffian", + "an earnest malcontent", + "an exultant animal tamer", + "a famed adventurer", + "a fanatical crusader", + "a fastidious clerk", + "a fearless hunter", + "a festive harlequin", + "a fidgety assassin", + "a fierce soldier", + "a fierce warrior", + "a frugal magnate", + "a glib pundit", + "a gnomic shaman", + "a graceful noblewoman", + "a idiotic madman", + "a imaginative designer", + "an inept conjurer", + "an innovative architect", + "an inventive blacksmith", + "a judicious mayor", + "a masterful chef", + "a masterful woodworker", + "a melancholy clown", + "a melodic bard", + "a merciful guard", + "a mirthful jester", + "a nervous surgeon", + "a peaceful scholar", + "a prolific gardener", + "a quixotic knight", + "a regal aristocrat", + "a resourceful smith", + "a reticent alchemist", + "a sanctified priest", + "a scheming patrician", + "a shrewd mage", + "a singing minstrel", + "a skilled tailor", + "a squeamish assassin", + "a stoic swordsman", + "a studious scribe", + "a thought provoking writer", + "a treacherous scoundrel", + "a troubled poet", + "an unflappable wizard", + "a valiant warrior", + "a wayward fool" + }; + + public static string RandomName( Mobile from ) + { + int index = Utility.Random( m_Names.Length ); + if ( m_Names[index] == null ) + return from.Name; + else + return m_Names[index]; + } + + private const int m_Partial = 2; + private const int m_Completed = 10; + + private int m_Quantity; + private string m_StatueName; + + [CommandProperty( AccessLevel.GameMaster )] + public int Quantity + { + get { return m_Quantity; } + set + { + if ( value <= 1 ) + m_Quantity = 1; + else if ( value >= m_Completed ) + m_Quantity = m_Completed; + else + m_Quantity = value; + + if ( m_Quantity < m_Partial ) + ItemID = 0x1EA7; + else if ( m_Quantity < m_Completed ) + ItemID = 0x1F13; + else + ItemID = 0x12CB; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string StatueName + { + get { return m_StatueName; } + set { m_StatueName = value; InvalidateProperties(); } + } + + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + [Constructable] + public Obsidian() : base( 0x1EA7 ) + { + Hue = 0x497; + + m_Quantity = 1; + m_StatueName = ""; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_Quantity < m_Partial ) + list.Add( 1055137 ); // a section of an obsidian statue + else if ( m_Quantity < m_Completed ) + list.Add( 1055138 ); // a partially reconstructed obsidian statue + else + list.Add( 1055139, m_StatueName ); // an obsidian statue of ~1_STATUE_NAME~ + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Quantity < m_Partial ) + LabelTo( from, 1055137 ); // a section of an obsidian statue + else if ( m_Quantity < m_Completed ) + LabelTo( from, 1055138 ); // a partially reconstructed obsidian statue + else + LabelTo( from, 1055139, m_StatueName ); // an obsidian statue of ~1_STATUE_NAME~ + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive && m_Quantity >= m_Partial && m_Quantity < m_Completed && IsChildOf( from.Backpack ) ) + list.Add( new DisassembleEntry( this ) ); + } + + private class DisassembleEntry : ContextMenuEntry + { + private Obsidian m_Obsidian; + + public DisassembleEntry( Obsidian obsidian ) : base( 6142 ) + { + m_Obsidian = obsidian; + } + + public override void OnClick() + { + Mobile from = Owner.From; + if ( !m_Obsidian.Deleted && m_Obsidian.Quantity >= Obsidian.m_Partial && m_Obsidian.Quantity < Obsidian.m_Completed && m_Obsidian.IsChildOf( from.Backpack ) && from.CheckAlive() ) + { + for ( int i = 0; i < m_Obsidian.Quantity - 1; i++ ) + from.AddToBackpack( new Obsidian() ); + + m_Obsidian.Quantity = 1; + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Quantity < m_Completed ) + { + if ( !IsChildOf( from.Backpack ) ) + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x2C, 3, 500309, "", "" ) ); // Nothing Happens. + else + from.Target = new InternalTarget( this ); + } + } + + private class InternalTarget : Target + { + private Obsidian m_Obsidian; + + public InternalTarget( Obsidian obsidian ) : base( -1, false, TargetFlags.None ) + { + m_Obsidian = obsidian; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + Item targ = targeted as Item; + if ( m_Obsidian.Deleted || m_Obsidian.Quantity >= Obsidian.m_Completed || targ == null ) + return; + + if ( m_Obsidian.IsChildOf( from.Backpack ) && targ.IsChildOf( from.Backpack ) && targ is Obsidian && targ != m_Obsidian ) + { + Obsidian targObsidian = (Obsidian)targ; + if ( targObsidian.Quantity < Obsidian.m_Completed ) + { + if ( targObsidian.Quantity + m_Obsidian.Quantity <= Obsidian.m_Completed ) + { + targObsidian.Quantity += m_Obsidian.Quantity; + m_Obsidian.Delete(); + } + else + { + int delta = Obsidian.m_Completed - targObsidian.Quantity; + targObsidian.Quantity += delta; + m_Obsidian.Quantity -= delta; + } + + if ( targObsidian.Quantity >= Obsidian.m_Completed ) + targObsidian.StatueName = Obsidian.RandomName( from ); + + from.Send( new AsciiMessage( targObsidian.Serial, targObsidian.ItemID, MessageType.Regular, 0x59, 3, m_Obsidian.Name, "Something Happened." ) ); + + return; + } + } + + from.Send( new MessageLocalized( m_Obsidian.Serial, m_Obsidian.ItemID, MessageType.Regular, 0x2C, 3, 500309, m_Obsidian.Name, "" ) ); // Nothing Happens. + } + } + + public Obsidian( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteEncodedInt( m_Quantity ); + writer.Write( (string) m_StatueName ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Quantity = reader.ReadEncodedInt(); + m_StatueName = Utility.Intern( reader.ReadString() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Items/PaintedImage.cs b/Scripts/Engines/Quests/Collector/Items/PaintedImage.cs new file mode 100644 index 0000000..5e3abb3 --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Items/PaintedImage.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.Quests.Collector +{ + public class PaintedImage : Item + { + private ImageType m_Image; + + [CommandProperty( AccessLevel.GameMaster )] + public ImageType Image + { + get { return m_Image; } + set { m_Image = value; InvalidateProperties(); } + } + + [Constructable] + public PaintedImage( ImageType image ) : base( 0xFF3 ) + { + Weight = 1.0; + Hue = 0x8FD; + + m_Image = image; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + ImageTypeInfo info = ImageTypeInfo.Get( m_Image ); + list.Add( 1060847, "#1055126\t#" + info.Name ); // a painted image of: + } + + public override void OnSingleClick( Mobile from ) + { + ImageTypeInfo info = ImageTypeInfo.Get( m_Image ); + LabelTo( from, 1060847, "#1055126\t#" + info.Name ); // a painted image of: + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + from.SendGump( new InternalGump( m_Image ) ); + } + + private class InternalGump : Gump + { + public InternalGump( ImageType image ) : base( 75, 25 ) + { + ImageTypeInfo info = ImageTypeInfo.Get( image ); + + AddBackground( 45, 20, 100, 100, 0xA3C ); + AddBackground( 52, 29, 86, 82, 0xBB8 ); + + AddItem( info.X, info.Y, info.Figurine ); + } + } + + public PaintedImage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Image ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Image = (ImageType) reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Mobiles/AlbertaGiacco.cs b/Scripts/Engines/Quests/Collector/Mobiles/AlbertaGiacco.cs new file mode 100644 index 0000000..f435db2 --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Mobiles/AlbertaGiacco.cs @@ -0,0 +1,94 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Collector +{ + public class AlbertaGiacco : BaseQuester + { + [Constructable] + public AlbertaGiacco() : base( "the respected painter" ) + { + } + + public AlbertaGiacco( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83F2; + + Female = true; + Body = 0x191; + Name = "Alberta Giacco"; + } + + public override void InitOutfit() + { + AddItem( new FancyShirt() ); + AddItem( new Skirt( 0x59B ) ); + AddItem( new Boots() ); + AddItem( new FeatheredHat( 0x59B ) ); + AddItem( new FullApron( 0x59B ) ); + + HairItemID = 0x203D; // Pony Tail + HairHue = 0x457; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + QuestSystem qs = to.Quest as CollectorQuest; + + if ( qs == null ) + return false; + + return ( qs.IsObjectiveInProgress( typeof( FindAlbertaObjective ) ) + || qs.IsObjectiveInProgress( typeof( SitOnTheStoolObjective ) ) + || qs.IsObjectiveInProgress( typeof( ReturnPaintingObjective ) ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + Direction = GetDirectionTo( player ); + + QuestObjective obj = qs.FindObjective( typeof( FindAlbertaObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( SitOnTheStoolObjective ) ) ) + { + qs.AddConversation( new AlbertaStoolConversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( ReturnPaintingObjective ) ) ) + { + qs.AddConversation( new AlbertaAfterPaintingConversation() ); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Mobiles/ElwoodMcCarrin.cs b/Scripts/Engines/Quests/Collector/Mobiles/ElwoodMcCarrin.cs new file mode 100644 index 0000000..e065e9b --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Mobiles/ElwoodMcCarrin.cs @@ -0,0 +1,243 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Collector +{ + public class ElwoodMcCarrin : BaseQuester + { + [Constructable] + public ElwoodMcCarrin() : base( "the well-known collector" ) + { + } + + public ElwoodMcCarrin( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83ED; + + Female = false; + Body = 0x190; + Name = "Elwood McCarrin"; + } + + public override void InitOutfit() + { + AddItem( new FancyShirt() ); + AddItem( new LongPants( 0x544 ) ); + AddItem( new Shoes( 0x454 ) ); + AddItem( new JesterHat( 0x4D2 ) ); + AddItem( new FullApron( 0x4D2 ) ); + + HairItemID = 0x203D; // Pony Tail + HairHue = 0x47D; + + FacialHairItemID = 0x2040; // Goatee + FacialHairHue = 0x47D; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + Direction = GetDirectionTo( player ); + + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FishPearlsObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringFishConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( ReturnPearlsObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( FindAlbertaObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringPainting1Conversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( SitOnTheStoolObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringPainting2Conversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnPaintingObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( FindGabrielObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringAutograph1Conversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( FindSheetMusicObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringAutograph2Conversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( ReturnSheetMusicObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringAutograph3Conversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnAutographObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( FindTomasObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringToys1Conversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( CaptureImagesObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringToys2Conversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( ReturnImagesObjective ) ) ) + { + qs.AddConversation( new ElwoodDuringToys3Conversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnToysObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + + if ( GiveReward( player ) ) + { + qs.AddConversation( new EndConversation() ); + } + else + { + qs.AddConversation( new FullEndConversation( true ) ); + } + } + else + { + obj = qs.FindObjective( typeof( MakeRoomObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( GiveReward( player ) ) + { + obj.Complete(); + qs.AddConversation( new EndConversation() ); + } + else + { + qs.AddConversation( new FullEndConversation( false ) ); + } + } + } + } + } + } + } + } + else + { + QuestSystem newQuest = new CollectorQuest( player ); + + if ( qs == null && QuestSystem.CanOfferQuest( player, typeof( CollectorQuest ) ) ) + { + newQuest.SendOffer(); + } + else + { + newQuest.AddConversation( new DontOfferConversation() ); + } + } + } + + public bool GiveReward( Mobile to ) + { + Bag bag = new Bag(); + + bag.DropItem( new Gold( Utility.RandomMinMax( 500, 1000 ) ) ); + + if ( Utility.RandomBool() ) + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if ( Core.AOS ) + { + BaseRunicTool.ApplyAttributesTo( weapon, 2, 20, 30 ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + } + + bag.DropItem( weapon ); + } + else + { + Item item; + + if ( Core.AOS ) + { + item = Loot.RandomArmorOrShieldOrJewelry(); + + if ( item is BaseArmor ) + BaseRunicTool.ApplyAttributesTo( (BaseArmor)item, 2, 20, 30 ); + else if ( item is BaseJewel ) + BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, 2, 20, 30 ); + } + else + { + BaseArmor armor = Loot.RandomArmorOrShield(); + item = armor; + + armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + } + + bag.DropItem( item ); + } + + bag.DropItem( new Obsidian() ); + + if ( to.PlaceInBackpack( bag ) ) + { + return true; + } + else + { + bag.Delete(); + return false; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Mobiles/GabrielPiete.cs b/Scripts/Engines/Quests/Collector/Mobiles/GabrielPiete.cs new file mode 100644 index 0000000..db061c9 --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Mobiles/GabrielPiete.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Collector +{ + public class GabrielPiete : BaseQuester + { + [Constructable] + public GabrielPiete() : base( "the renowned minstrel" ) + { + } + + public GabrielPiete( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83EF; + + Female = false; + Body = 0x190; + Name = "Gabriel Piete"; + } + + public override void InitOutfit() + { + AddItem( new FancyShirt() ); + AddItem( new LongPants( 0x5F7 ) ); + AddItem( new Shoes( 0x5F7 ) ); + + HairItemID = 0x2049; // Pig Tails + HairHue = 0x460; + + FacialHairItemID = 0x2041; // Mustache + FacialHairHue = 0x460; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + QuestSystem qs = to.Quest as CollectorQuest; + + if ( qs == null ) + return false; + + return ( qs.IsObjectiveInProgress( typeof( FindGabrielObjective ) ) + || qs.IsObjectiveInProgress( typeof( FindSheetMusicObjective ) ) + || qs.IsObjectiveInProgress( typeof( ReturnSheetMusicObjective ) ) + || qs.IsObjectiveInProgress( typeof( ReturnAutographObjective ) ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + Direction = GetDirectionTo( player ); + + QuestObjective obj = qs.FindObjective( typeof( FindGabrielObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( FindSheetMusicObjective ) ) ) + { + qs.AddConversation( new GabrielNoSheetMusicConversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnSheetMusicObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( ReturnAutographObjective ) ) ) + { + qs.AddConversation( new GabrielIgnoreConversation() ); + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Mobiles/Impresario.cs b/Scripts/Engines/Quests/Collector/Mobiles/Impresario.cs new file mode 100644 index 0000000..6434794 --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Mobiles/Impresario.cs @@ -0,0 +1,175 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Network; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Collector +{ + public class Impresario : BaseQuester + { + [Constructable] + public Impresario() : base( "the impresario" ) + { + } + + public Impresario( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = Utility.RandomSkinHue(); + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + public override void InitOutfit() + { + AddItem( new FancyShirt( Utility.RandomDyedHue() ) ); + AddItem( new LongPants( Utility.RandomNondyedHue() ) ); + AddItem( new Shoes( Utility.RandomNeutralHue() ) ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this ); + } + + public override bool CanTalkTo( PlayerMobile to ) + { + QuestSystem qs = to.Quest as CollectorQuest; + + if ( qs == null ) + return false; + + return qs.IsObjectiveInProgress( typeof( FindSheetMusicObjective ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + FindSheetMusicObjective obj = qs.FindObjective( typeof( FindSheetMusicObjective ) ) as FindSheetMusicObjective; + + if ( obj != null && !obj.Completed ) + { + Direction = GetDirectionTo( player ); + + if ( obj.IsInRightTheater() ) + { + player.CloseGump( typeof( SheetMusicOfferGump ) ); + player.SendGump( new SheetMusicOfferGump() ); + } + else + { + qs.AddConversation( new NoSheetMusicConversation() ); + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SheetMusicOfferGump : BaseQuestGump + { + public SheetMusicOfferGump() : base( 75, 25 ) + { + Closable = false; + + AddImage( 349, 10, 0x24B0 ); + AddImageTiled( 349, 130, 100, 120, 0x24B3 ); + AddImageTiled( 149, 10, 200, 140, 0x24AF ); + AddImageTiled( 149, 300, 200, 140, 0x24B5 ); + AddImage( 349, 300, 0x24B6 ); + AddImage( 35, 10, 0x24AE ); + AddImageTiled( 35, 150, 120, 100, 0x24B1 ); + AddImage( 35, 300, 0x24B4 ); + + AddHtmlLocalized( 110, 60, 200, 20, 1049069, White, false, false ); // Conversation Event + + AddImage( 65, 14, 0x2776 ); + AddImageTiled( 81, 14, 349, 17, 0x2775 ); + AddImage( 426, 14, 0x2778 ); + + AddImageTiled( 50, 37, 400, 376, 0xA40 ); + AddAlphaRegion( 50, 37, 400, 376 ); + + AddImage( 0, 0, 0x28C8 ); + + AddImageTiled( 75, 90, 200, 1, 0x238D ); + AddImage( 75, 58, 0x2635 ); + AddImage( 380, 45, 0xDF ); + + AddHtmlLocalized( 98, 140, 312, 200, 1055107, LightGreen, false, true ); // Sure, I have some sheet music for a Gabriel Piete song. I'd be happy to sell you a copy for 10 gold. + + AddRadio( 85, 350, 0x25F8, 0x25FB, true, 1 ); + AddHtmlLocalized( 120, 356, 280, 20, 1014088, White, false, false ); // I accept. + + AddRadio( 85, 385, 0x25F8, 0x25FB, false, 0 ); + AddHtmlLocalized( 120, 391, 280, 20, 1049012, White, false, false ); // No thanks, I decline. + + AddButton( 340, 390, 0xF7, 0xF8, 1, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 && info.IsSwitched( 1 ) ) + { + PlayerMobile player = sender.Mobile as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + FindSheetMusicObjective obj = qs.FindObjective( typeof( FindSheetMusicObjective ) ) as FindSheetMusicObjective; + + if ( obj != null && !obj.Completed ) + { + + + if ( player.Backpack!= null && player.Backpack.ConsumeTotal( typeof( Gold ), 10 ) ) + { + obj.Complete(); + } + else + { + BankBox bank = player.FindBankNoCreate(); + if ( bank != null && bank.ConsumeTotal( typeof( Gold ), 10 ) ) + { + obj.Complete(); + } + + else + { + player.SendLocalizedMessage( 1055108 ); // You don't have enough gold to buy the sheet music. + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Mobiles/TomasONeerlan.cs b/Scripts/Engines/Quests/Collector/Mobiles/TomasONeerlan.cs new file mode 100644 index 0000000..008da73 --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Mobiles/TomasONeerlan.cs @@ -0,0 +1,111 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Collector +{ + public class TomasONeerlan : BaseQuester + { + [Constructable] + public TomasONeerlan() : base( "the famed toymaker" ) + { + } + + public TomasONeerlan( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83F8; + + Female = false; + Body = 0x190; + Name = "Tomas O'Neerlan"; + } + + public override void InitOutfit() + { + AddItem( new FancyShirt() ); + AddItem( new LongPants( 0x546 ) ); + AddItem( new Boots( 0x452 ) ); + AddItem( new FullApron( 0x455 ) ); + + HairItemID = 0x203B; //ShortHair + HairHue = 0x455; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + QuestSystem qs = to.Quest as CollectorQuest; + + if ( qs == null ) + return false; + + return ( qs.IsObjectiveInProgress( typeof( FindTomasObjective ) ) + || qs.IsObjectiveInProgress( typeof( CaptureImagesObjective ) ) + || qs.IsObjectiveInProgress( typeof( ReturnImagesObjective ) ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is CollectorQuest ) + { + Direction = GetDirectionTo( player ); + + QuestObjective obj = qs.FindObjective( typeof( FindTomasObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item paints = new EnchantedPaints(); + + if ( !player.PlaceInBackpack( paints ) ) + { + paints.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + else + { + obj.Complete(); + } + } + else if ( qs.IsObjectiveInProgress( typeof( CaptureImagesObjective ) ) ) + { + qs.AddConversation( new TomasDuringCollectingConversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnImagesObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( player.Backpack != null ) + player.Backpack.ConsumeUpTo( typeof( EnchantedPaints ), 1 ); + + obj.Complete(); + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Collector/Objectives.cs b/Scripts/Engines/Quests/Collector/Objectives.cs new file mode 100644 index 0000000..e3f0bdc --- /dev/null +++ b/Scripts/Engines/Quests/Collector/Objectives.cs @@ -0,0 +1,533 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Collector +{ + public class FishPearlsObjective : QuestObjective + { + public override object Message + { + get + { + // Fish up shellfish from Lake Haven and collect rainbow pearls. + return 1055084; + } + } + + public override int MaxProgress{ get{ return 6; } } + + public FishPearlsObjective() + { + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Rainbow pearls collected: + gump.AddHtmlObject( 70, 260, 270, 100, 1055085, BaseQuestGump.Blue, false, false ); + + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, MaxProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnPearlsObjective() ); + } + } + + public class ReturnPearlsObjective : QuestObjective + { + public override object Message + { + get + { + /* You've collected enough rainbow pearls. Speak to + * Elwood to give them to him and get your next task. + */ + return 1055088; + } + } + + public ReturnPearlsObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ReturnPearlsConversation() ); + } + } + + public class FindAlbertaObjective : QuestObjective + { + public override object Message + { + get + { + // Go to Vesper and speak to Alberta Giacco at the Colored Canvas. + return 1055091; + } + } + + public FindAlbertaObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new AlbertaPaintingConversation() ); + } + } + + public class SitOnTheStoolObjective : QuestObjective + { + private static readonly Point3D m_StoolLocation = new Point3D( 2899, 706, 0 ); + private static readonly Map m_StoolMap = Map.Trammel; + + private DateTime m_Begin; + + public override object Message + { + get + { + /* Sit on the stool in front of Alberta's easel so that she can + * paint your portrait. You'll need to sit there for about 30 seconds. + */ + return 1055093; + } + } + + public SitOnTheStoolObjective() + { + m_Begin = DateTime.MaxValue; + } + + public override void CheckProgress() + { + PlayerMobile pm = System.From; + + if ( pm.Map == m_StoolMap && pm.Location == m_StoolLocation ) + { + if ( m_Begin == DateTime.MaxValue ) + { + m_Begin = DateTime.Now; + } + else if ( DateTime.Now - m_Begin > TimeSpan.FromSeconds( 30.0 ) ) + { + Complete(); + } + } + else if ( m_Begin != DateTime.MaxValue ) + { + m_Begin = DateTime.MaxValue; + pm.SendLocalizedMessage( 1055095, "", 0x26 ); // You must remain seated on the stool until the portrait is complete. Alberta will now have to start again with a fresh canvas. + } + } + + public override void OnComplete() + { + System.AddConversation( new AlbertaEndPaintingConversation() ); + } + } + + public class ReturnPaintingObjective : QuestObjective + { + public override object Message + { + get + { + // Return to Elwood and let him know that the painting is complete. + return 1055099; + } + } + + public ReturnPaintingObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ReturnPaintingConversation() ); + } + } + + public class FindGabrielObjective : QuestObjective + { + public override object Message + { + get + { + /* Go to Britain and obtain the autograph of renowned + * minstrel, Gabriel Piete. He is often found at the Conservatory of Music. + */ + return 1055101; + } + } + + public FindGabrielObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new GabrielAutographConversation() ); + } + } + + public enum Theater + { + Britain, + Nujelm, + Jhelom + } + + public class FindSheetMusicObjective : QuestObjective + { + private Theater m_Theater; + + public override object Message + { + get + { + /* Find some sheet music for one of Gabriel's songs. + * Try speaking to an impresario from one of the theaters in the land. + */ + return 1055104; + } + } + + public FindSheetMusicObjective( bool init ) + { + if ( init ) + InitTheater(); + } + + public FindSheetMusicObjective() + { + } + + public void InitTheater() + { + switch ( Utility.Random( 3 ) ) + { + case 1: m_Theater = Theater.Britain; break; + case 2: m_Theater = Theater.Nujelm; break; + default: m_Theater = Theater.Jhelom; break; + } + } + + public bool IsInRightTheater() + { + PlayerMobile player = System.From; + + Region region = Region.Find( player.Location, player.Map ); + + if ( region == null ) + return false; + + switch ( m_Theater ) + { + case Theater.Britain: return region.IsPartOf( "Britain" ); + case Theater.Nujelm: return region.IsPartOf( "Nujel'm" ); + case Theater.Jhelom: return region.IsPartOf( "Jhelom" ); + + default: return false; + } + } + + public override void OnComplete() + { + System.AddConversation( new GetSheetMusicConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Theater = (Theater) reader.ReadEncodedInt(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Theater ); + } + } + + public class ReturnSheetMusicObjective : QuestObjective + { + public override object Message + { + get + { + // Speak to Gabriel to have him autograph the sheet music. + return 1055110; + } + } + + public ReturnSheetMusicObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new GabrielSheetMusicConversation() ); + } + } + + public class ReturnAutographObjective : QuestObjective + { + public override object Message + { + get + { + // Speak to Elwood to give him the autographed sheet music. + return 1055114; + } + } + + public ReturnAutographObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ReturnAutographConversation() ); + } + } + + public class FindTomasObjective : QuestObjective + { + public override object Message + { + get + { + // Go to Trinsic and speak to Tomas O'Neerlan, the famous toymaker. + return 1055117; + } + } + + public FindTomasObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new TomasToysConversation() ); + } + } + + public enum CaptureResponse + { + Valid, + AlreadyDone, + Invalid + } + + public class CaptureImagesObjective : QuestObjective + { + private ImageType[] m_Images; + private bool[] m_Done; + + public override object Message + { + get + { + // Use the enchanted paints to capture the image of all of the creatures listed below. + return 1055120; + } + } + + public override bool Completed + { + get + { + for ( int i = 0; i < m_Done.Length; i++ ) + { + if ( !m_Done[i] ) + return false; + } + + return true; + } + } + + public CaptureImagesObjective( bool init ) + { + if ( init ) + { + m_Images = ImageTypeInfo.RandomList( 4 ); + m_Done = new bool[4]; + } + } + + public CaptureImagesObjective() + { + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + if ( Completed ) + return false; + + Type fromType = from.GetType(); + + for ( int i = 0; i < m_Images.Length; i++ ) + { + ImageTypeInfo info = ImageTypeInfo.Get( m_Images[i] ); + + if ( info.Type == fromType ) + return true; + } + + return false; + } + + public CaptureResponse CaptureImage( Type type, out ImageType image ) + { + for ( int i = 0; i < m_Images.Length; i++ ) + { + ImageTypeInfo info = ImageTypeInfo.Get( m_Images[i] ); + + if ( info.Type == type ) + { + image = m_Images[i]; + + if ( m_Done[i] ) + { + return CaptureResponse.AlreadyDone; + } + else + { + m_Done[i] = true; + + CheckCompletionStatus(); + + return CaptureResponse.Valid; + } + } + } + + image = (ImageType)0; + return CaptureResponse.Invalid; + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + for ( int i = 0; i < m_Images.Length; i++ ) + { + ImageTypeInfo info = ImageTypeInfo.Get( m_Images[i] ); + + gump.AddHtmlObject( 70, 260 + 20 * i, 200, 100, info.Name, BaseQuestGump.Blue, false, false ); + gump.AddLabel( 200, 260 + 20 * i, 0x64, " : " ); + gump.AddHtmlObject( 220, 260 + 20 * i, 100, 100, m_Done[i] ? 1055121 : 1055122, BaseQuestGump.Blue, false, false ); + } + } + else + { + base.RenderProgress( gump ); + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnImagesObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + int count = reader.ReadEncodedInt(); + + m_Images = new ImageType[count]; + m_Done = new bool[count]; + + for ( int i = 0; i < count; i++ ) + { + m_Images[i] = (ImageType) reader.ReadEncodedInt(); + m_Done[i] = reader.ReadBool(); + } + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Images.Length ); + + for ( int i = 0; i < m_Images.Length; i++ ) + { + writer.WriteEncodedInt( (int) m_Images[i] ); + writer.Write( (bool) m_Done[i] ); + } + } + } + + public class ReturnImagesObjective : QuestObjective + { + public override object Message + { + get + { + /* You now have all of the creature images you need. + * Return to Tomas O'Neerlan so that he can make the toy figurines. + */ + return 1055128; + } + } + + public ReturnImagesObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ReturnImagesConversation() ); + } + } + + public class ReturnToysObjective : QuestObjective + { + public override object Message + { + get + { + // Return to Elwood with news that the toy figurines will be delivered when ready. + return 1055132; + } + } + + public ReturnToysObjective() + { + } + } + + public class MakeRoomObjective : QuestObjective + { + public override object Message + { + get + { + // Return to Elwood for your reward when you have some room in your backpack. + return 1055136; + } + } + + public MakeRoomObjective() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/BaseQuester.cs b/Scripts/Engines/Quests/Core/BaseQuester.cs new file mode 100644 index 0000000..1dfd358 --- /dev/null +++ b/Scripts/Engines/Quests/Core/BaseQuester.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.ContextMenus; + +namespace Server.Engines.Quests +{ + public class TalkEntry : ContextMenuEntry + { + private BaseQuester m_Quester; + + public TalkEntry( BaseQuester quester ) : base( quester.TalkNumber ) + { + m_Quester = quester; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( from.CheckAlive() && from is PlayerMobile && m_Quester.CanTalkTo( (PlayerMobile)from ) ) + m_Quester.OnTalk( (PlayerMobile)from, true ); + } + } + + public abstract class BaseQuester : BaseVendor + { + protected List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool IsActiveVendor{ get{ return false; } } + public override bool IsInvulnerable{ get{ return true; } } + public override bool DisallowAllMoves{ get{ return true; } } + public override bool ClickTitle{ get { return false; } } + public override bool CanTeach{ get{ return false; } } + + public virtual int TalkNumber{ get{ return 6146; } } // Talk + + public override void InitSBInfo() + { + } + + public BaseQuester() : this( null ) + { + } + + public BaseQuester( string title ) : base( title) + { + } + + public BaseQuester( Serial serial ) : base( serial ) + { + } + + public abstract void OnTalk( PlayerMobile player, bool contextMenu ); + + public virtual bool CanTalkTo( PlayerMobile to ) + { + return true; + } + + public virtual int GetAutoTalkRange( PlayerMobile m ) + { + return -1; + } + + public override bool CanBeDamaged() + { + return false; + } + + protected Item SetHue( Item item, int hue ) + { + item.Hue = hue; + return item; + } + + public override void AddCustomContextEntries( Mobile from, List list ) + { + base.AddCustomContextEntries( from, list ); + + if ( from.Alive && from is PlayerMobile && TalkNumber > 0 && CanTalkTo( (PlayerMobile)from ) ) + list.Add( new TalkEntry( this ) ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Alive && m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + int range = GetAutoTalkRange( pm ); + + if ( m.Alive && range >= 0 && InRange( m, range ) && !InRange( oldLocation, range ) && CanTalkTo( pm ) ) + OnTalk( pm, false ); + } + } + + public void FocusTo( Mobile to ) + { + QuestSystem.FocusTo( this, to ); + } + + public static Container GetNewContainer() + { + Bag bag = new Bag(); + bag.Hue = QuestSystem.RandomBrightHue(); + return bag; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Items/DynamicTeleporter.cs b/Scripts/Engines/Quests/Core/Items/DynamicTeleporter.cs new file mode 100644 index 0000000..f12e831 --- /dev/null +++ b/Scripts/Engines/Quests/Core/Items/DynamicTeleporter.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests +{ + public abstract class DynamicTeleporter : Item + { + public override int LabelNumber{ get{ return 1049382; } } // a magical teleporter + + public DynamicTeleporter() : this( 0x1822, 0x482 ) + { + } + + public DynamicTeleporter( int itemID, int hue ) : base( itemID ) + { + Movable = false; + Hue = hue; + } + + public abstract bool GetDestination( PlayerMobile player, ref Point3D loc, ref Map map ); + + public virtual int NotWorkingMessage{ get{ return 500309; } } // Nothing Happens. + + public override bool OnMoveOver( Mobile m ) + { + PlayerMobile pm = m as PlayerMobile; + + if ( pm != null ) + { + Point3D loc = Point3D.Zero; + Map map = null; + + if ( GetDestination( pm, ref loc, ref map ) ) + { + BaseCreature.TeleportPets( pm, loc, map ); + + pm.PlaySound( 0x1FE ); + pm.MoveToWorld( loc, map ); + + return false; + } + else + { + pm.SendLocalizedMessage( this.NotWorkingMessage ); + } + } + + return base.OnMoveOver( m ); + } + + public DynamicTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs b/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs new file mode 100644 index 0000000..3ad6540 --- /dev/null +++ b/Scripts/Engines/Quests/Core/Items/EnchantedSextant.cs @@ -0,0 +1,193 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class EnchantedSextant : Item + { + //TODO: Trammel/Haven + private static readonly Point2D[] m_TrammelBanks = new Point2D[] + { + new Point2D( 652, 820 ), + new Point2D( 1813, 2825 ), + new Point2D( 3734, 2149 ), + new Point2D( 2503, 552 ), + new Point2D( 3764, 1317 ), + new Point2D( 587, 2146 ), + new Point2D( 1655, 1606 ), + new Point2D( 1425, 1690 ), + new Point2D( 4471, 1156 ), + new Point2D( 1317, 3773 ), + new Point2D( 2881, 684 ), + new Point2D( 2731, 2192 ), + new Point2D( 3620, 2617 ), + new Point2D( 2880, 3472 ), + new Point2D( 1897, 2684 ), + new Point2D( 5346, 74 ), + new Point2D( 5275, 3977 ), + new Point2D( 5669, 3131 ) + }; + + private static readonly Point2D[] m_FeluccaBanks = new Point2D[] + { + new Point2D( 652, 820 ), + new Point2D( 1813, 2825 ), + new Point2D( 3734, 2149 ), + new Point2D( 2503, 552 ), + new Point2D( 3764, 1317 ), + new Point2D( 3695, 2511 ), + new Point2D( 587, 2146 ), + new Point2D( 1655, 1606 ), + new Point2D( 1425, 1690 ), + new Point2D( 4471, 1156 ), + new Point2D( 1317, 3773 ), + new Point2D( 2881, 684 ), + new Point2D( 2731, 2192 ), + new Point2D( 2880, 3472 ), + new Point2D( 1897, 2684 ), + new Point2D( 5346, 74 ), + new Point2D( 5275, 3977 ), + new Point2D( 5669, 3131 ) + }; + + private static readonly Point2D[] m_IlshenarBanks = new Point2D[] + { + new Point2D( 854, 680 ), + new Point2D( 855, 603 ), + new Point2D( 1226, 554 ), + new Point2D( 1610, 556 ) + }; + + private static readonly Point2D[] m_MalasBanks = new Point2D[] + { + new Point2D( 996, 519 ), + new Point2D( 2048, 1345 ) + }; + + private const double m_LongDistance = 300.0; + private const double m_ShortDistance = 5.0; + + public override int LabelNumber { get { return 1046226; } } // an enchanted sextant + + [Constructable] + public EnchantedSextant() : base( 0x1058 ) + { + Weight = 2.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + Point2D[] banks; + PMList moongates; + if ( from.Map == Map.Trammel ) + { + banks = m_TrammelBanks; + moongates = PMList.Trammel; + } + else if ( from.Map == Map.Felucca ) + { + banks = m_FeluccaBanks; + moongates = PMList.Felucca; + } + else if ( from.Map == Map.Ilshenar ) + { +#if false + banks = m_IlshenarBanks; + moongates = PMList.Ilshenar; +#else + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, 0x482, 3, 1061684, "", "" ) ); // The magic of the sextant fails... + return; +#endif + } + else if ( from.Map == Map.Malas ) + { + banks = m_MalasBanks; + moongates = PMList.Malas; + } + else + { + banks = null; + moongates = null; + } + + Point3D closestMoongate = Point3D.Zero; + double moongateDistance = double.MaxValue; + if ( moongates != null ) + { + foreach ( PMEntry entry in moongates.Entries ) + { + double dist = from.GetDistanceToSqrt( entry.Location ); + if ( moongateDistance > dist ) + { + closestMoongate = entry.Location; + moongateDistance = dist; + } + } + } + + Point2D closestBank = Point2D.Zero; + double bankDistance = double.MaxValue; + if ( banks != null ) + { + foreach ( Point2D p in banks ) + { + double dist = from.GetDistanceToSqrt( p ); + if ( bankDistance > dist ) + { + closestBank = p; + bankDistance = dist; + } + } + } + + int moonMsg; + if ( moongateDistance == double.MaxValue ) + moonMsg = 1048021; // The sextant fails to find a Moongate nearby. + else if ( moongateDistance > m_LongDistance ) + moonMsg = 1046449 + (int)from.GetDirectionTo( closestMoongate ); // A moongate is * from here + else if ( moongateDistance > m_ShortDistance ) + moonMsg = 1048010 + (int)from.GetDirectionTo( closestMoongate ); // There is a Moongate * of here. + else + moonMsg = 1048018; // You are next to a Moongate at the moment. + + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, 0x482, 3, moonMsg, "", "" ) ); + + int bankMsg; + if ( bankDistance == double.MaxValue ) + bankMsg = 1048020; // The sextant fails to find a Bank nearby. + else if ( bankDistance > m_LongDistance ) + bankMsg = 1046462 + (int)from.GetDirectionTo( closestBank ); // A town is * from here + else if ( bankDistance > m_ShortDistance ) + bankMsg = 1048002 + (int)from.GetDirectionTo( closestBank ); // There is a city Bank * of here. + else + bankMsg = 1048019; // You are next to a Bank at the moment. + + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, 0x5AA, 3, bankMsg, "", "" ) ); + } + + public EnchantedSextant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Items/HornOfRetreat.cs b/Scripts/Engines/Quests/Core/Items/HornOfRetreat.cs new file mode 100644 index 0000000..bf01fef --- /dev/null +++ b/Scripts/Engines/Quests/Core/Items/HornOfRetreat.cs @@ -0,0 +1,206 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests +{ + public class HornOfRetreat : Item + { + private Point3D m_DestLoc; + private Map m_DestMap; + private int m_Charges; + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D DestLoc + { + get{ return m_DestLoc; } + set{ m_DestLoc = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Map DestMap + { + get{ return m_DestMap; } + set{ m_DestMap = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set{ m_Charges = value; InvalidateProperties(); } + } + + public override int LabelNumber{ get{ return 1049117; } } // Horn of Retreat + + [Constructable] + public HornOfRetreat() : base( 0xFC4 ) + { + Hue = 0x482; + Weight = 1.0; + Charges = 10; + } + + public virtual bool ValidateUse( Mobile from ) + { + return true; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060741, m_Charges.ToString() ); // charges: ~1_val~ + } + + private Timer m_PlayTimer; + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + if ( !ValidateUse( from ) ) + { + SendLocalizedMessageTo( from, 500309 ); // Nothing Happens. + } + else if( Core.ML && from.Map != Map.Trammel && from.Map != Map.Malas ) + { + from.SendLocalizedMessage( 1076154 ); // You can only use this in Trammel and Malas. + } + else if( m_PlayTimer != null ) + { + SendLocalizedMessageTo( from, 1042144 ); // This is currently in use. + } + else if( Charges > 0 ) + { + from.Animate( 34, 7, 1, true, false, 0 ); + from.PlaySound( 0xFF ); + from.SendLocalizedMessage( 1049115 ); // You play the horn and a sense of peace overcomes you... + + --Charges; + + m_PlayTimer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( PlayTimer_Callback ), from ); + } + else + { + SendLocalizedMessageTo( from, 1042544 ); // This item is out of charges. + } + } + else + { + SendLocalizedMessageTo( from, 1042001 ); // That must be in your pack for you to use it. + } + } + + public virtual void PlayTimer_Callback( object state ) + { + Mobile from = (Mobile)state; + + m_PlayTimer = null; + + HornOfRetreatMoongate gate = new HornOfRetreatMoongate( this.DestLoc, this.DestMap, from, this.Hue ); + + gate.MoveToWorld( from.Location, from.Map ); + + from.PlaySound( 0x20E ); + + gate.SendLocalizedMessageTo( from, 1049102, from.Name ); // Quickly ~1_NAME~! Onward through the gate! + } + + public HornOfRetreat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_DestLoc ); + writer.Write( m_DestMap ); + writer.Write( m_Charges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_DestLoc = reader.ReadPoint3D(); + m_DestMap = reader.ReadMap(); + m_Charges = reader.ReadInt(); + break; + } + } + } + } + + public class HornOfRetreatMoongate : Moongate + { + public override int LabelNumber{ get{ return 1049114; } } // Sanctuary Gate + + private Mobile m_Caster; + + public HornOfRetreatMoongate( Point3D destLoc, Map destMap, Mobile caster, int hue ) + { + m_Caster = caster; + + Target = destLoc; + TargetMap = destMap; + + Hue = hue; + Light = LightType.Circle300; + + Dispellable = false; + + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Delete ) ); + } + + public override void BeginConfirmation( Mobile from ) + { + EndConfirmation( from ); + } + + public override void UseGate( Mobile m ) + { + if (m.Region.IsPartOf(typeof(Regions.Jail))) + { + m.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan then that! + } + else if ( m == m_Caster ) + { + base.UseGate( m ); + Delete(); + } + } + + public HornOfRetreatMoongate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Items/QuestItem.cs b/Scripts/Engines/Quests/Core/Items/QuestItem.cs new file mode 100644 index 0000000..fc8ac71 --- /dev/null +++ b/Scripts/Engines/Quests/Core/Items/QuestItem.cs @@ -0,0 +1,121 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests +{ + public abstract class QuestItem : Item + { + public QuestItem( int itemID ) : base( itemID ) + { + } + + public QuestItem( Serial serial ) : base( serial ) + { + } + + public abstract bool CanDrop( PlayerMobile pm ); + + public virtual bool Accepted { get { return Deleted; } } + + public override bool DropToWorld( Mobile from, Point3D p ) + { + bool ret = base.DropToWorld( from, p ); + + if ( ret && !Accepted && Parent != from.Backpack ) + { + if ( from.AccessLevel > AccessLevel.Player ) + { + return true; + } + else if ( !(from is PlayerMobile) || CanDrop( (PlayerMobile)from ) ) + { + return true; + } + else + { + from.SendLocalizedMessage( 1049343 ); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest. + return false; + } + } + else + { + return ret; + } + } + + public override bool DropToMobile( Mobile from, Mobile target, Point3D p ) + { + bool ret = base.DropToMobile( from, target, p ); + + if ( ret && !Accepted && Parent != from.Backpack ) + { + if ( from.AccessLevel > AccessLevel.Player ) + { + return true; + } + else if ( !(from is PlayerMobile) || CanDrop( (PlayerMobile)from ) ) + { + return true; + } + else + { + from.SendLocalizedMessage( 1049344 ); // You decide against trading the item. You still need it for your quest. + return false; + } + } + else + { + return ret; + } + } + + public override bool DropToItem( Mobile from, Item target, Point3D p ) + { + bool ret = base.DropToItem( from, target, p ); + + if ( ret && !Accepted && Parent != from.Backpack ) + { + if ( from.AccessLevel > AccessLevel.Player ) + { + return true; + } + else if ( !(from is PlayerMobile) || CanDrop( (PlayerMobile)from ) ) + { + return true; + } + else + { + from.SendLocalizedMessage( 1049343 ); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest. + return false; + } + } + else + { + return ret; + } + } + + public override DeathMoveResult OnParentDeath( Mobile parent ) + { + if ( parent is PlayerMobile && !CanDrop( (PlayerMobile)parent ) ) + return DeathMoveResult.MoveToBackpack; + else + return base.OnParentDeath( parent ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestCallbackEntry.cs b/Scripts/Engines/Quests/Core/QuestCallbackEntry.cs new file mode 100644 index 0000000..c930564 --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestCallbackEntry.cs @@ -0,0 +1,26 @@ +using System; +using Server; +using Server.ContextMenus; + +namespace Server.Engines.Quests +{ + public class QuestCallbackEntry : ContextMenuEntry + { + private QuestCallback m_Callback; + + public QuestCallbackEntry( int number, QuestCallback callback ) : this( number, -1, callback ) + { + } + + public QuestCallbackEntry( int number, int range, QuestCallback callback ) : base( number, range ) + { + m_Callback = callback; + } + + public override void OnClick() + { + if ( m_Callback != null ) + m_Callback(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestConversation.cs b/Scripts/Engines/Quests/Core/QuestConversation.cs new file mode 100644 index 0000000..b4d390e --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestConversation.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.Quests +{ + public abstract class QuestConversation + { + private QuestSystem m_System; + private bool m_HasBeenRead; + + public abstract object Message{ get; } + + public virtual QuestItemInfo[] Info{ get{ return null; } } + public virtual bool Logged{ get{ return true; } } + + public QuestSystem System + { + get{ return m_System; } + set{ m_System = value; } + } + + public bool HasBeenRead + { + get{ return m_HasBeenRead; } + set{ m_HasBeenRead = value; } + } + + public QuestConversation() + { + } + + public virtual void BaseDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_HasBeenRead = reader.ReadBool(); + + break; + } + } + + ChildDeserialize( reader ); + } + + public virtual void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + } + + public virtual void BaseSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_HasBeenRead ); + + ChildSerialize( writer ); + } + + public virtual void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + } + + public virtual void OnRead() + { + } + } + + public class QuestConversationsGump : BaseQuestGump + { + private ArrayList m_Conversations; + + public QuestConversationsGump( QuestConversation conv ) : this( BuildList( conv ) ) + { + } + + public QuestConversationsGump( ArrayList conversations ) : base( 30, 50 ) + { + m_Conversations = conversations; + + Closable = false; + + AddPage( 0 ); + + AddImage( 349, 10, 9392 ); + AddImageTiled( 349, 130, 100, 120, 9395 ); + AddImageTiled( 149, 10, 200, 140, 9391 ); + AddImageTiled( 149, 250, 200, 140, 9397 ); + AddImage( 349, 250, 9398 ); + AddImage( 35, 10, 9390 ); + AddImageTiled( 35, 150, 120, 100, 9393 ); + AddImage( 35, 250, 9396 ); + + AddHtmlLocalized( 110, 60, 200, 20, 1049069, White, false, false ); // Conversation Event + + AddImage( 65, 14, 10102 ); + AddImageTiled( 81, 14, 349, 17, 10101 ); + AddImage( 426, 14, 10104 ); + + AddImageTiled( 55, 40, 388, 323, 2624 ); + AddAlphaRegion( 55, 40, 388, 323 ); + + AddImageTiled( 75, 90, 200, 1, 9101 ); + AddImage( 75, 58, 9781 ); + AddImage( 380, 45, 223 ); + + AddButton( 220, 335, 2313, 2312, 1, GumpButtonType.Reply, 0 ); + AddImage( 0, 0, 10440 ); + + AddPage( 1 ); + + for ( int i = 0; i < conversations.Count; ++i ) + { + QuestConversation conv = (QuestConversation)conversations[conversations.Count - 1 - i]; + + if ( i > 0 ) + { + AddButton( 65, 366, 9909, 9911, 0, GumpButtonType.Page, 1 + i ); + AddHtmlLocalized( 90, 367, 50, 20, 1043354, Black, false, false ); // Previous + + AddPage( 1 + i ); + } + + AddHtmlObject( 70, 110, 365, 220, conv.Message, LightGreen, false, true ); + + if ( i > 0 ) + { + AddButton( 420, 366, 9903, 9905, 0, GumpButtonType.Page, i ); + AddHtmlLocalized( 370, 367, 50, 20, 1043353, Black, false, false ); // Next + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + for ( int i = m_Conversations.Count - 1; i >= 0; --i ) + { + QuestConversation qc = (QuestConversation)m_Conversations[i]; + + if ( !qc.HasBeenRead ) + { + qc.HasBeenRead = true; + qc.OnRead(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestItemInfo.cs b/Scripts/Engines/Quests/Core/QuestItemInfo.cs new file mode 100644 index 0000000..67c2fb1 --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestItemInfo.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Gumps; + +namespace Server.Engines.Quests +{ + public class QuestItemInfo + { + private object m_Name; + private int m_ItemID; + + public object Name + { + get{ return m_Name; } + set{ m_Name = value; } + } + + public int ItemID + { + get{ return m_ItemID; } + set{ m_ItemID = value; } + } + + public QuestItemInfo( object name, int itemID ) + { + m_Name = name; + m_ItemID = itemID; + } + } + + public class QuestItemInfoGump : BaseQuestGump + { + public QuestItemInfoGump( QuestItemInfo[] info ) : base( 485, 75 ) + { + int height = 100 + (info.Length * 75); + + AddPage( 0 ); + + AddBackground( 5, 10, 145, height, 5054 ); + + AddImageTiled( 13, 20, 125, 10, 2624 ); + AddAlphaRegion( 13, 20, 125, 10 ); + + AddImageTiled( 13, height - 10, 128, 10, 2624 ); + AddAlphaRegion( 13, height - 10, 128, 10 ); + + AddImageTiled( 13, 20, 10, height - 30, 2624 ); + AddAlphaRegion( 13, 20, 10, height - 30 ); + + AddImageTiled( 131, 20, 10, height - 30, 2624 ); + AddAlphaRegion( 131, 20, 10, height - 30 ); + + AddHtmlLocalized( 67, 35, 120, 20, 1011233, White, false, false ); // INFO + + AddImage( 62, 52, 9157 ); + AddImage( 72, 52, 9157 ); + AddImage( 82, 52, 9157 ); + + AddButton( 25, 31, 1209, 1210, 777, GumpButtonType.Reply, 0 ); + + AddPage( 1 ); + + for ( int i = 0; i < info.Length; ++i ) + { + QuestItemInfo cur = info[i]; + + AddHtmlObject( 25, 65 + (i * 75), 110, 20, cur.Name, 1153, false, false ); + AddItem( 45, 85 + (i * 75), cur.ItemID ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestObjective.cs b/Scripts/Engines/Quests/Core/QuestObjective.cs new file mode 100644 index 0000000..a3f2b94 --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestObjective.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Items; + +namespace Server.Engines.Quests +{ + public abstract class QuestObjective + { + private QuestSystem m_System; + private bool m_HasBeenRead; + private int m_CurProgress; + private bool m_HasCompleted; + + public abstract object Message{ get; } + + public virtual int MaxProgress{ get{ return 1; } } + public virtual QuestItemInfo[] Info{ get{ return null; } } + + public QuestSystem System + { + get{ return m_System; } + set{ m_System = value; } + } + + public bool HasBeenRead + { + get{ return m_HasBeenRead; } + set{ m_HasBeenRead = value; } + } + + public int CurProgress + { + get{ return m_CurProgress; } + set{ m_CurProgress = value; CheckCompletionStatus(); } + } + + public bool HasCompleted + { + get{ return m_HasCompleted; } + set{ m_HasCompleted = value; } + } + + public virtual bool Completed + { + get{ return m_CurProgress >= MaxProgress; } + } + + public bool IsSingleObjective + { + get{ return ( MaxProgress == 1 ); } + } + + public QuestObjective() + { + } + + public virtual void BaseDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_HasBeenRead = reader.ReadBool(); + goto case 0; + } + case 0: + { + m_CurProgress = reader.ReadEncodedInt(); + m_HasCompleted = reader.ReadBool(); + + break; + } + } + + ChildDeserialize( reader ); + } + + public virtual void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + } + + public virtual void BaseSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 1 ); // version + + writer.Write( (bool) m_HasBeenRead ); + writer.WriteEncodedInt( (int) m_CurProgress ); + writer.Write( (bool) m_HasCompleted ); + + ChildSerialize( writer ); + } + + public virtual void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + } + + public virtual void Complete() + { + CurProgress = MaxProgress; + } + + public virtual void RenderMessage( BaseQuestGump gump ) + { + gump.AddHtmlObject( 70, 130, 300, 100, this.Message, BaseQuestGump.Blue, false, false ); + } + + public virtual void RenderProgress( BaseQuestGump gump ) + { + gump.AddHtmlObject( 70, 260, 270, 100, this.Completed ? 1049077 : 1049078, BaseQuestGump.Blue, false, false ); + } + + public virtual void CheckCompletionStatus() + { + if ( Completed && !HasCompleted ) + { + HasCompleted = true; + OnComplete(); + } + } + + public virtual void OnRead() + { + } + + public virtual bool GetTimerEvent() + { + return !Completed; + } + + public virtual void CheckProgress() + { + } + + public virtual void OnComplete() + { + } + + public virtual bool GetKillEvent( BaseCreature creature, Container corpse ) + { + return !Completed; + } + + public virtual void OnKill( BaseCreature creature, Container corpse ) + { + } + + public virtual bool IgnoreYoungProtection( Mobile from ) + { + return false; + } + } + + public class QuestLogUpdatedGump : BaseQuestGump + { + private QuestSystem m_System; + + public QuestLogUpdatedGump( QuestSystem system ) : base( 3, 30 ) + { + m_System = system; + + AddPage( 0 ); + + AddImage( 20, 5, 1417 ); + + AddHtmlLocalized( 0, 78, 120, 40, 1049079, White, false, false ); // Quest Log Updated + + AddImageTiled( 0, 78, 120, 40, 2624 ); + AddAlphaRegion( 0, 78, 120, 40 ); + + AddButton( 30, 15, 5575, 5576, 1, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_System.ShowQuestLog(); + } + } + + public class QuestObjectivesGump : BaseQuestGump + { + private ArrayList m_Objectives; + + public QuestObjectivesGump( QuestObjective obj ) : this( BuildList( obj ) ) + { + } + + public QuestObjectivesGump( ArrayList objectives ) : base( 90, 50 ) + { + m_Objectives = objectives; + + Closable = false; + + AddPage( 0 ); + + AddImage( 0, 0, 3600 ); + AddImageTiled( 0, 14, 15, 375, 3603 ); + AddImageTiled( 380, 14, 14, 375, 3605 ); + AddImage( 0, 376, 3606 ); + AddImageTiled( 15, 376, 370, 16, 3607 ); + AddImageTiled( 15, 0, 370, 16, 3601 ); + AddImage( 380, 0, 3602 ); + AddImage( 380, 376, 3608 ); + + AddImageTiled( 15, 15, 365, 365, 2624 ); + AddAlphaRegion( 15, 15, 365, 365 ); + + AddImage( 20, 87, 1231 ); + AddImage( 75, 62, 9307 ); + + AddHtmlLocalized( 117, 35, 230, 20, 1046026, Blue, false, false ); // Quest Log + + AddImage( 77, 33, 9781 ); + AddImage( 65, 110, 2104 ); + + AddHtmlLocalized( 79, 106, 230, 20, 1049073, Blue, false, false ); // Objective: + + AddImageTiled( 68, 125, 120, 1, 9101 ); + AddImage( 65, 240, 2104 ); + + AddHtmlLocalized( 79, 237, 230, 20, 1049076, Blue, false, false ); // Progress details: + + AddImageTiled( 68, 255, 120, 1, 9101 ); + AddButton( 175, 355, 2313, 2312, 1, GumpButtonType.Reply, 0 ); + + AddImage( 341, 15, 10450 ); + AddImage( 341, 330, 10450 ); + AddImage( 15, 330, 10450 ); + AddImage( 15, 15, 10450 ); + + AddPage( 1 ); + + for ( int i = 0; i < objectives.Count; ++i ) + { + QuestObjective obj = (QuestObjective)objectives[objectives.Count - 1 - i]; + + if ( i > 0 ) + { + AddButton( 55, 346, 9909, 9911, 0, GumpButtonType.Page, 1 + i ); + AddHtmlLocalized( 82, 347, 50, 20, 1043354, White, false, false ); // Previous + + AddPage( 1 + i ); + } + + obj.RenderMessage( this ); + obj.RenderProgress( this ); + + if ( i > 0 ) + { + AddButton( 317, 346, 9903, 9905, 0, GumpButtonType.Page, i ); + AddHtmlLocalized( 278, 347, 50, 20, 1043353, White, false, false ); // Next + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + for ( int i = m_Objectives.Count - 1; i >= 0; --i ) + { + QuestObjective obj = (QuestObjective)m_Objectives[i]; + + if ( !obj.HasBeenRead ) + { + obj.HasBeenRead = true; + obj.OnRead(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestRestartInfo.cs b/Scripts/Engines/Quests/Core/QuestRestartInfo.cs new file mode 100644 index 0000000..876dbd0 --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestRestartInfo.cs @@ -0,0 +1,42 @@ +using System; + +namespace Server.Engines.Quests +{ + public class QuestRestartInfo + { + private Type m_QuestType; + private DateTime m_RestartTime; + + public Type QuestType + { + get{ return m_QuestType; } + set{ m_QuestType = value; } + } + + public DateTime RestartTime + { + get{ return m_RestartTime; } + set{ m_RestartTime = value; } + } + + public void Reset( TimeSpan restartDelay ) + { + if ( restartDelay < TimeSpan.MaxValue ) + m_RestartTime = DateTime.Now + restartDelay; + else + m_RestartTime = DateTime.MaxValue; + } + + public QuestRestartInfo( Type questType, TimeSpan restartDelay ) + { + m_QuestType = questType; + Reset( restartDelay ); + } + + public QuestRestartInfo( Type questType, DateTime restartTime ) + { + m_QuestType = questType; + m_RestartTime = restartTime; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestSerializer.cs b/Scripts/Engines/Quests/Core/QuestSerializer.cs new file mode 100644 index 0000000..a4ef75e --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestSerializer.cs @@ -0,0 +1,197 @@ +using System; + +namespace Server.Engines.Quests +{ + public class QuestSerializer + { + public static object Construct( Type type ) + { + try + { + return Activator.CreateInstance( type ); + } + catch + { + return null; + } + } + + public static void Write( Type type, Type[] referenceTable, GenericWriter writer ) + { + if ( type == null ) + { + writer.WriteEncodedInt( (int) 0x00 ); + } + else + { + for ( int i = 0; i < referenceTable.Length; ++i ) + { + if ( referenceTable[i] == type ) + { + writer.WriteEncodedInt( (int) 0x01 ); + writer.WriteEncodedInt( (int) i ); + return; + } + } + + writer.WriteEncodedInt( (int) 0x02 ); + writer.Write( type.FullName ); + } + } + + public static Type ReadType( Type[] referenceTable, GenericReader reader ) + { + int encoding = reader.ReadEncodedInt(); + + switch ( encoding ) + { + default: + case 0x00: // null + { + return null; + } + case 0x01: // indexed + { + int index = reader.ReadEncodedInt(); + + if ( index >= 0 && index < referenceTable.Length ) + return referenceTable[index]; + + return null; + } + case 0x02: // by name + { + string fullName = reader.ReadString(); + + if ( fullName == null ) + return null; + + return ScriptCompiler.FindTypeByFullName( fullName, false ); + } + } + } + + public static QuestSystem DeserializeQuest( GenericReader reader ) + { + int encoding = reader.ReadEncodedInt(); + + switch ( encoding ) + { + default: + case 0x00: // null + { + return null; + } + case 0x01: + { + Type type = ReadType( QuestSystem.QuestTypes, reader ); + + QuestSystem qs = Construct( type ) as QuestSystem; + + if ( qs != null ) + qs.BaseDeserialize( reader ); + + return qs; + } + } + } + + public static void Serialize( QuestSystem qs, GenericWriter writer ) + { + if ( qs == null ) + { + writer.WriteEncodedInt( 0x00 ); + } + else + { + writer.WriteEncodedInt( 0x01 ); + + Write( qs.GetType(), QuestSystem.QuestTypes, writer ); + + qs.BaseSerialize( writer ); + } + } + + public static QuestObjective DeserializeObjective( Type[] referenceTable, GenericReader reader ) + { + int encoding = reader.ReadEncodedInt(); + + switch ( encoding ) + { + default: + case 0x00: // null + { + return null; + } + case 0x01: + { + Type type = ReadType( referenceTable, reader ); + + QuestObjective obj = Construct( type ) as QuestObjective; + + if ( obj != null ) + obj.BaseDeserialize( reader ); + + return obj; + } + } + } + + public static void Serialize( Type[] referenceTable, QuestObjective obj, GenericWriter writer ) + { + if ( obj == null ) + { + writer.WriteEncodedInt( 0x00 ); + } + else + { + writer.WriteEncodedInt( 0x01 ); + + Write( obj.GetType(), referenceTable, writer ); + + obj.BaseSerialize( writer ); + } + } + + public static QuestConversation DeserializeConversation( Type[] referenceTable, GenericReader reader ) + { + int encoding = reader.ReadEncodedInt(); + + switch ( encoding ) + { + default: + case 0x00: // null + { + return null; + } + case 0x01: + { + Type type = ReadType( referenceTable, reader ); + + QuestConversation conv = Construct( type ) as QuestConversation; + + if ( conv != null ) + conv.BaseDeserialize( reader ); + + return conv; + } + } + } + + public static void Serialize( Type[] referenceTable, QuestConversation conv, GenericWriter writer ) + { + if ( conv == null ) + { + writer.WriteEncodedInt( 0x00 ); + } + else + { + writer.WriteEncodedInt( 0x01 ); + + Write( conv.GetType(), referenceTable, writer ); + + conv.BaseSerialize( writer ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/QuestSystem.cs b/Scripts/Engines/Quests/Core/QuestSystem.cs new file mode 100644 index 0000000..2ba09e6 --- /dev/null +++ b/Scripts/Engines/Quests/Core/QuestSystem.cs @@ -0,0 +1,708 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; + +namespace Server.Engines.Quests +{ +// Nerun's Distro Addition -- 1 of 1 --begin + public class QuestButton + { + public static void Initialize() + { + EventSink.QuestGumpRequest += new QuestGumpRequestHandler( EventSink_QuestGumpRequest ); + } + + private static void EventSink_QuestGumpRequest( QuestGumpRequestArgs args ) + { + PlayerMobile pm = args.Mobile as PlayerMobile; + + if( pm == null ) + return; + + QuestSystem qs = pm.Quest; + + if( qs != null ) + qs.ShowQuestLog(); + } + } +// --------------------------------------end + public delegate void QuestCallback(); + + public abstract class QuestSystem + { + public static readonly Type[] QuestTypes = new Type[] + { + typeof( Doom.TheSummoningQuest ), + typeof( Necro.DarkTidesQuest ), + typeof( Haven.UzeraanTurmoilQuest ), + typeof( Collector.CollectorQuest ), + typeof( Hag.WitchApprenticeQuest ), + typeof( Naturalist.StudyOfSolenQuest ), + typeof( Matriarch.SolenMatriarchQuest ), + typeof( Ambitious.AmbitiousQueenQuest ), + typeof( Ninja.EminosUndertakingQuest ), + typeof( Samurai.HaochisTrialsQuest ), + typeof( Zento.TerribleHatchlingsQuest ) + }; + + public abstract object Name{ get; } + public abstract object OfferMessage{ get; } + + public abstract int Picture{ get; } + + public abstract bool IsTutorial{ get; } + public abstract TimeSpan RestartDelay{ get; } + + public abstract Type[] TypeReferenceTable{ get; } + + private PlayerMobile m_From; + private ArrayList m_Objectives; + private ArrayList m_Conversations; + + public PlayerMobile From + { + get{ return m_From; } + set{ m_From = value; } + } + + public ArrayList Objectives + { + get{ return m_Objectives; } + set{ m_Objectives = value; } + } + + public ArrayList Conversations + { + get{ return m_Conversations; } + set{ m_Conversations = value; } + } + + private Timer m_Timer; + + public virtual void StartTimer() + { + if ( m_Timer != null ) + return; + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), new TimerCallback( Slice ) ); + } + + public virtual void StopTimer() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + + public virtual void Slice() + { + for ( int i = m_Objectives.Count - 1; i >= 0; --i ) + { + QuestObjective obj = (QuestObjective)m_Objectives[i]; + + if ( obj.GetTimerEvent() ) + obj.CheckProgress(); + } + } + + public virtual void OnKill( BaseCreature creature, Container corpse ) + { + for ( int i = m_Objectives.Count - 1; i >= 0; --i ) + { + QuestObjective obj = (QuestObjective)m_Objectives[i]; + + if ( obj.GetKillEvent( creature, corpse ) ) + obj.OnKill( creature, corpse ); + } + } + + public virtual bool IgnoreYoungProtection( Mobile from ) + { + for ( int i = m_Objectives.Count - 1; i >= 0; --i ) + { + QuestObjective obj = (QuestObjective)m_Objectives[i]; + + if ( obj.IgnoreYoungProtection( from ) ) + return true; + } + + return false; + } + + public QuestSystem( PlayerMobile from ) + { + m_From = from; + m_Objectives = new ArrayList(); + m_Conversations = new ArrayList(); + } + + public QuestSystem() + { + } + + public virtual void BaseDeserialize( GenericReader reader ) + { + Type[] referenceTable = this.TypeReferenceTable; + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + int count = reader.ReadEncodedInt(); + + m_Objectives = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + QuestObjective obj = QuestSerializer.DeserializeObjective( referenceTable, reader ); + + if ( obj != null ) + { + obj.System = this; + m_Objectives.Add( obj ); + } + } + + count = reader.ReadEncodedInt(); + + m_Conversations = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + QuestConversation conv = QuestSerializer.DeserializeConversation( referenceTable, reader ); + + if ( conv != null ) + { + conv.System = this; + m_Conversations.Add( conv ); + } + } + + break; + } + } + + ChildDeserialize( reader ); + } + + public virtual void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + } + + public virtual void BaseSerialize( GenericWriter writer ) + { + Type[] referenceTable = this.TypeReferenceTable; + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Objectives.Count ); + + for ( int i = 0; i < m_Objectives.Count; ++i ) + QuestSerializer.Serialize( referenceTable, (QuestObjective) m_Objectives[i], writer ); + + writer.WriteEncodedInt( (int) m_Conversations.Count ); + + for ( int i = 0; i < m_Conversations.Count; ++i ) + QuestSerializer.Serialize( referenceTable, (QuestConversation) m_Conversations[i], writer ); + + ChildSerialize( writer ); + } + + public virtual void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + } + + public bool IsObjectiveInProgress( Type type ) + { + QuestObjective obj = FindObjective( type ); + + return ( obj != null && !obj.Completed ); + } + + public QuestObjective FindObjective( Type type ) + { + for ( int i = m_Objectives.Count - 1; i >= 0; --i ) + { + QuestObjective obj = (QuestObjective)m_Objectives[i]; + + if ( obj.GetType() == type ) + return obj; + } + + return null; + } + + public virtual void SendOffer() + { + m_From.SendGump( new QuestOfferGump( this ) ); + } + + public virtual void GetContextMenuEntries( List list ) + { + if ( m_Objectives.Count > 0 ) + list.Add( new QuestCallbackEntry( 6154, new QuestCallback( ShowQuestLog ) ) ); // View Quest Log + + if ( m_Conversations.Count > 0 ) + list.Add( new QuestCallbackEntry( 6156, new QuestCallback( ShowQuestConversation ) ) ); // Quest Conversation + + list.Add( new QuestCallbackEntry( 6155, new QuestCallback( BeginCancelQuest ) ) ); // Cancel Quest + } + + public virtual void ShowQuestLogUpdated() + { + m_From.CloseGump( typeof( QuestLogUpdatedGump ) ); + m_From.SendGump( new QuestLogUpdatedGump( this ) ); + } + + public virtual void ShowQuestLog() + { + if ( m_Objectives.Count > 0 ) + { + m_From.CloseGump( typeof( QuestItemInfoGump ) ); + m_From.CloseGump( typeof( QuestLogUpdatedGump ) ); + m_From.CloseGump( typeof( QuestObjectivesGump ) ); + m_From.CloseGump( typeof( QuestConversationsGump ) ); + + m_From.SendGump( new QuestObjectivesGump( m_Objectives ) ); + + QuestObjective last = (QuestObjective)m_Objectives[m_Objectives.Count - 1]; + + if ( last.Info != null ) + m_From.SendGump( new QuestItemInfoGump( last.Info ) ); + } + } + + public virtual void ShowQuestConversation() + { + if ( m_Conversations.Count > 0 ) + { + m_From.CloseGump( typeof( QuestItemInfoGump ) ); + m_From.CloseGump( typeof( QuestObjectivesGump ) ); + m_From.CloseGump( typeof( QuestConversationsGump ) ); + + m_From.SendGump( new QuestConversationsGump( m_Conversations ) ); + + QuestConversation last = (QuestConversation)m_Conversations[m_Conversations.Count - 1]; + + if ( last.Info != null ) + m_From.SendGump( new QuestItemInfoGump( last.Info ) ); + } + } + + public virtual void BeginCancelQuest() + { + m_From.SendGump( new QuestCancelGump( this ) ); + } + + public virtual void EndCancelQuest( bool shouldCancel ) + { + if ( m_From.Quest != this ) + return; + + if ( shouldCancel ) + { + m_From.SendLocalizedMessage( 1049015 ); // You have canceled your quest. + Cancel(); + } + else + { + m_From.SendLocalizedMessage( 1049014 ); // You have chosen not to cancel your quest. + } + } + + public virtual void Cancel() + { + ClearQuest( false ); + } + + public virtual void Complete() + { + ClearQuest( true ); + } + + public virtual void ClearQuest( bool completed ) + { + StopTimer(); + + if ( m_From.Quest == this ) + { + m_From.Quest = null; + + TimeSpan restartDelay = this.RestartDelay; + + if ( ( completed && restartDelay > TimeSpan.Zero ) || ( !completed && restartDelay == TimeSpan.MaxValue ) ) + { + List doneQuests = m_From.DoneQuests; + + if ( doneQuests == null ) + m_From.DoneQuests = doneQuests = new List(); + + bool found = false; + + Type ourQuestType = this.GetType(); + + for ( int i = 0; i < doneQuests.Count; ++i ) + { + QuestRestartInfo restartInfo = doneQuests[i]; + + if ( restartInfo.QuestType == ourQuestType ) + { + restartInfo.Reset( restartDelay ); + found = true; + break; + } + } + + if ( !found ) + doneQuests.Add( new QuestRestartInfo( ourQuestType, restartDelay ) ); + } + } + } + + public virtual void AddConversation( QuestConversation conv ) + { + conv.System = this; + + if ( conv.Logged ) + m_Conversations.Add( conv ); + + m_From.CloseGump( typeof( QuestItemInfoGump ) ); + m_From.CloseGump( typeof( QuestObjectivesGump ) ); + m_From.CloseGump( typeof( QuestConversationsGump ) ); + + if ( conv.Logged ) + m_From.SendGump( new QuestConversationsGump( m_Conversations ) ); + else + m_From.SendGump( new QuestConversationsGump( conv ) ); + + if ( conv.Info != null ) + m_From.SendGump( new QuestItemInfoGump( conv.Info ) ); + } + + public virtual void AddObjective( QuestObjective obj ) + { + obj.System = this; + m_Objectives.Add( obj ); + + ShowQuestLogUpdated(); + } + + public virtual void Accept() + { + if ( m_From.Quest != null ) + return; + + m_From.Quest = this; + m_From.SendLocalizedMessage( 1049019 ); // You have accepted the Quest. + + StartTimer(); + } + + public virtual void Decline() + { + m_From.SendLocalizedMessage( 1049018 ); // You have declined the Quest. + } + + public static bool CanOfferQuest( Mobile check, Type questType ) + { + bool inRestartPeriod; + + return CanOfferQuest( check, questType, out inRestartPeriod ); + } + + public static bool CanOfferQuest( Mobile check, Type questType, out bool inRestartPeriod ) + { + inRestartPeriod = false; + + PlayerMobile pm = check as PlayerMobile; + + if ( pm == null ) + return false; + + if ( pm.HasGump( typeof( QuestOfferGump ) ) ) + return false; + + if ( questType == typeof( Necro.DarkTidesQuest ) && pm.Profession != 4 ) // necromancer + return false; + + if ( questType == typeof( Haven.UzeraanTurmoilQuest ) && pm.Profession != 1 && pm.Profession != 2 && pm.Profession != 5 ) // warrior / magician / paladin + return false; + + if ( questType == typeof( Samurai.HaochisTrialsQuest ) && pm.Profession != 6 ) // samurai + return false; + + if ( questType == typeof( Ninja.EminosUndertakingQuest ) && pm.Profession != 7 ) // ninja + return false; + + List doneQuests = pm.DoneQuests; + + if ( doneQuests != null ) + { + for ( int i = 0; i < doneQuests.Count; ++i ) + { + QuestRestartInfo restartInfo = doneQuests[i]; + + if ( restartInfo.QuestType == questType ) + { + DateTime endTime = restartInfo.RestartTime; + + if ( DateTime.Now < endTime ) + { + inRestartPeriod = true; + return false; + } + + doneQuests.RemoveAt( i-- ); + return true; + } + } + } + + return true; + } + + public static void FocusTo( Mobile who, Mobile to ) + { + if ( Utility.RandomBool() ) + { + who.Animate( 17, 7, 1, true, false, 0 ); + } + else + { + switch ( Utility.Random( 3 ) ) + { + case 0: who.Animate( 32, 7, 1, true, false, 0 ); break; + case 1: who.Animate( 33, 7, 1, true, false, 0 ); break; + case 2: who.Animate( 34, 7, 1, true, false, 0 ); break; + } + } + + who.Direction = who.GetDirectionTo( to ); + } + + public static int RandomBrightHue() + { + if ( 0.1 > Utility.RandomDouble() ) + return Utility.RandomList( 0x62, 0x71 ); + + return Utility.RandomList( 0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59 ); + } + } + + public class QuestCancelGump : BaseQuestGump + { + private QuestSystem m_System; + + public QuestCancelGump( QuestSystem system ) : base( 120, 50 ) + { + m_System = system; + + Closable = false; + + AddPage( 0 ); + + AddImageTiled( 0, 0, 348, 262, 2702 ); + AddAlphaRegion( 0, 0, 348, 262 ); + + AddImage( 0, 15, 10152 ); + AddImageTiled( 0, 30, 17, 200, 10151 ); + AddImage( 0, 230, 10154 ); + + AddImage( 15, 0, 10252 ); + AddImageTiled( 30, 0, 300, 17, 10250 ); + AddImage( 315, 0, 10254 ); + + AddImage( 15, 244, 10252 ); + AddImageTiled( 30, 244, 300, 17, 10250 ); + AddImage( 315, 244, 10254 ); + + AddImage( 330, 15, 10152 ); + AddImageTiled( 330, 30, 17, 200, 10151 ); + AddImage( 330, 230, 10154 ); + + AddImage( 333, 2, 10006 ); + AddImage( 333, 248, 10006 ); + AddImage( 2, 248, 10006 ); + AddImage( 2, 2, 10006 ); + + AddHtmlLocalized( 25, 22, 200, 20, 1049000, 32000, false, false ); // Confirm Quest Cancellation + AddImage( 25, 40, 3007 ); + + if ( system.IsTutorial ) + { + AddHtmlLocalized( 25, 55, 300, 120, 1060836, White, false, false ); // This quest will give you valuable information, skills and equipment that will help you advance in the game at a quicker pace.

Are you certain you wish to cancel at this time? + } + else + { + AddHtmlLocalized( 25, 60, 300, 20, 1049001, White, false, false ); // You have chosen to abort your quest: + AddImage( 25, 81, 0x25E7 ); + AddHtmlObject( 48, 80, 280, 20, system.Name, DarkGreen, false, false ); + + AddHtmlLocalized( 25, 120, 280, 20, 1049002, White, false, false ); // Can this quest be restarted after quitting? + AddImage( 25, 141, 0x25E7 ); + AddHtmlLocalized( 48, 140, 280, 20, (system.RestartDelay < TimeSpan.MaxValue) ? 1049016 : 1049017, DarkGreen, false, false ); // Yes/No + } + + AddRadio( 25, 175, 9720, 9723, true, 1 ); + AddHtmlLocalized( 60, 180, 280, 20, 1049005, White, false, false ); // Yes, I really want to quit! + + AddRadio( 25, 210, 9720, 9723, false, 0 ); + AddHtmlLocalized( 60, 215, 280, 20, 1049006, White, false, false ); // No, I don't want to quit. + + AddButton( 265, 220, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_System.EndCancelQuest( info.IsSwitched( 1 ) ); + } + } + + public class QuestOfferGump : BaseQuestGump + { + private QuestSystem m_System; + + public QuestOfferGump( QuestSystem system ) : base( 75, 25 ) + { + m_System = system; + + Closable = false; + + AddPage( 0 ); + + AddImageTiled( 50, 20, 400, 400, 2624 ); + AddAlphaRegion( 50, 20, 400, 400 ); + + AddImage( 90, 33, 9005 ); + AddHtmlLocalized( 130, 45, 270, 20, 1049010, White, false, false ); // Quest Offer + AddImageTiled( 130, 65, 175, 1, 9101 ); + + AddImage( 140, 110, 1209 ); + AddHtmlObject( 160, 108, 250, 20, system.Name, DarkGreen, false, false ); + + AddHtmlObject( 98, 140, 312, 200, system.OfferMessage, LightGreen, false, true ); + + AddRadio( 85, 350, 9720, 9723, true, 1 ); + AddHtmlLocalized( 120, 356, 280, 20, 1049011, White, false, false ); // I accept! + + AddRadio( 85, 385, 9720, 9723, false, 0 ); + AddHtmlLocalized( 120, 391, 280, 20, 1049012, White, false, false ); // No thanks, I decline. + + AddButton( 340, 390, 247, 248, 1, GumpButtonType.Reply, 0 ); + + AddImageTiled( 50, 29, 30, 390, 10460 ); + AddImageTiled( 34, 140, 17, 279, 9263 ); + + AddImage( 48, 135, 10411 ); + AddImage( -16, 285, 10402 ); + AddImage( 0, 10, 10421 ); + AddImage( 25, 0, 10420 ); + + AddImageTiled( 83, 15, 350, 15, 10250 ); + + AddImage( 34, 419, 10306 ); + AddImage( 442, 419, 10304 ); + AddImageTiled( 51, 419, 392, 17, 10101 ); + + AddImageTiled( 415, 29, 44, 390, 2605 ); + AddImageTiled( 415, 29, 30, 390, 10460 ); + AddImage( 425, 0, 10441 ); + + AddImage( 370, 50, 1417 ); + AddImage( 379, 60, system.Picture ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + if ( info.IsSwitched( 1 ) ) + m_System.Accept(); + else + m_System.Decline(); + } + } + } + + public abstract class BaseQuestGump : Gump + { + public const int Black = 0x0000; + public const int White = 0x7FFF; + public const int DarkGreen = 10000; + public const int LightGreen = 90000; + public const int Blue = 19777215; + + public static int C16232( int c16 ) + { + c16 &= 0x7FFF; + + int r = ( ((c16 >> 10) & 0x1F) << 3 ); + int g = ( ((c16 >> 05) & 0x1F) << 3 ); + int b = ( ((c16 >> 00) & 0x1F) << 3 ); + + return (r << 16) | (g << 8) | (b << 0); + } + + public static int C16216( int c16 ) + { + return c16 & 0x7FFF; + } + + public static int C32216( int c32 ) + { + c32 &= 0xFFFFFF; + + int r = ( ((c32 >> 16) & 0xFF) >> 3 ); + int g = ( ((c32 >> 08) & 0xFF) >> 3 ); + int b = ( ((c32 >> 00) & 0xFF) >> 3 ); + + return (r << 10) | (g << 5) | (b << 0); + } + + public static string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public static ArrayList BuildList( object obj ) + { + ArrayList list = new ArrayList(); + + list.Add( obj ); + + return list; + } + + public void AddHtmlObject( int x, int y, int width, int height, object message, int color, bool back, bool scroll ) + { + if ( message is string ) + { + string html = (string)message; + + AddHtml( x, y, width, height, Color( html, C16232( color ) ), back, scroll ); + } + else if ( message is int ) + { + int html = (int)message; + + AddHtmlLocalized( x, y, width, height, html, C16216( color ), back, scroll ); + } + } + + public BaseQuestGump( int x, int y ) : base( x, y ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Regions/CancelQuestRegion.cs b/Scripts/Engines/Quests/Core/Regions/CancelQuestRegion.cs new file mode 100644 index 0000000..77baaad --- /dev/null +++ b/Scripts/Engines/Quests/Core/Regions/CancelQuestRegion.cs @@ -0,0 +1,44 @@ +using System; +using System.Xml; +using Server; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Engines.Quests +{ + public class CancelQuestRegion : BaseRegion + { + private Type m_Quest; + + public Type Quest{ get{ return m_Quest; } } + + public CancelQuestRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + ReadType( xml["quest"], "type", ref m_Quest ); + } + + public override bool OnMoveInto( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation ) + { + if ( !base.OnMoveInto ( m, d, newLocation, oldLocation ) ) + return false; + + if ( m.AccessLevel > AccessLevel.Player ) + return true; + + if ( m_Quest == null ) + return true; + + PlayerMobile player = m as PlayerMobile; + + if ( player != null && player.Quest != null && player.Quest.GetType() == m_Quest ) + { + if ( !player.HasGump( typeof( QuestCancelGump ) ) ) + player.Quest.BeginCancelQuest(); + + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Regions/QuestCompleteObjectiveRegion.cs b/Scripts/Engines/Quests/Core/Regions/QuestCompleteObjectiveRegion.cs new file mode 100644 index 0000000..b5bd6be --- /dev/null +++ b/Scripts/Engines/Quests/Core/Regions/QuestCompleteObjectiveRegion.cs @@ -0,0 +1,43 @@ +using System; +using System.Xml; +using Server; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Engines.Quests +{ + public class QuestCompleteObjectiveRegion : BaseRegion + { + private Type m_Quest; + private Type m_Objective; + + public Type Quest{ get{ return m_Quest ; } } + public Type Objective{ get{ return m_Objective; } } + + public QuestCompleteObjectiveRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + XmlElement questEl = xml["quest"]; + + ReadType( questEl, "type", ref m_Quest ); + ReadType( questEl, "complete", ref m_Objective ); + } + + public override void OnEnter( Mobile m ) + { + base.OnEnter( m ); + + if ( m_Quest != null && m_Objective != null ) + { + PlayerMobile player = m as PlayerMobile; + + if ( player != null && player.Quest != null && player.Quest.GetType() == m_Quest ) + { + QuestObjective obj = player.Quest.FindObjective( m_Objective ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Regions/QuestNoEntryRegion.cs b/Scripts/Engines/Quests/Core/Regions/QuestNoEntryRegion.cs new file mode 100644 index 0000000..38efa94 --- /dev/null +++ b/Scripts/Engines/Quests/Core/Regions/QuestNoEntryRegion.cs @@ -0,0 +1,67 @@ +using System; +using System.Xml; +using Server; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Engines.Quests +{ + public class QuestNoEntryRegion : BaseRegion + { + private Type m_Quest; + private Type m_MinObjective; + private Type m_MaxObjective; + private int m_Message; + + public Type Quest{ get{ return m_Quest; } } + public Type MinObjective{ get{ return m_MinObjective; } } + public Type MaxObjective{ get{ return m_MaxObjective; } } + public int Message{ get{ return m_Message; } } + + public QuestNoEntryRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + XmlElement questEl = xml["quest"]; + + ReadType( questEl, "type", ref m_Quest ); + ReadType( questEl, "min", ref m_MinObjective, false ); + ReadType( questEl, "max", ref m_MaxObjective, false ); + ReadInt32( questEl, "message", ref m_Message, false ); + } + + public override bool OnMoveInto( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation ) + { + if ( !base.OnMoveInto ( m, d, newLocation, oldLocation ) ) + return false; + + if ( m.AccessLevel > AccessLevel.Player ) + return true; + + if( m is BaseCreature ) + { + BaseCreature bc = m as BaseCreature; + + if( !bc.Controlled && !bc.Summoned ) + return true; + } + + if ( m_Quest == null ) + return true; + + PlayerMobile player = m as PlayerMobile; + + if ( player != null && player.Quest != null && player.Quest.GetType() == m_Quest + && ( m_MinObjective == null || player.Quest.FindObjective( m_MinObjective ) != null ) + && ( m_MaxObjective == null || player.Quest.FindObjective( m_MaxObjective ) == null ) ) + { + return true; + } + else + { + if ( m_Message != 0 ) + m.SendLocalizedMessage( m_Message ); + + return false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Core/Regions/QuestOfferRegion.cs b/Scripts/Engines/Quests/Core/Regions/QuestOfferRegion.cs new file mode 100644 index 0000000..8204d4a --- /dev/null +++ b/Scripts/Engines/Quests/Core/Regions/QuestOfferRegion.cs @@ -0,0 +1,43 @@ +using System; +using System.Xml; +using Server; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Engines.Quests +{ + public class QuestOfferRegion : BaseRegion + { + private Type m_Quest; + + public Type Quest{ get{ return m_Quest ; } } + + public QuestOfferRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + ReadType( xml["quest"], "type", ref m_Quest ); + } + + public override void OnEnter( Mobile m ) + { + base.OnEnter( m ); + + if ( m_Quest == null ) + return; + + PlayerMobile player = m as PlayerMobile; + + if ( player != null && player.Quest == null && QuestSystem.CanOfferQuest( m, m_Quest ) ) + { + try + { + QuestSystem qs = (QuestSystem) Activator.CreateInstance( m_Quest, new object[] { player } ); + qs.SendOffer(); + } + catch ( Exception ex ) + { + Console.WriteLine( "Error creating quest {0}: {1}", m_Quest, ex ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Conversations.cs b/Scripts/Engines/Quests/Dark Tides/Conversations.cs new file mode 100644 index 0000000..257ca8c --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Conversations.cs @@ -0,0 +1,607 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Necro +{ + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Important Quest Information

+ * + * During your quest, any important information that a + * NPC gives you, will appear in a + * window such as this one. You can review the information at + * any time during your quest.

Getting Help

+ * + * Some of the text you will come across during your quest, will + * be underlined links to the codex of + * wisdom, or online help system. You can click on the text + * to get detailed information on the underlined subject. You + * may also access the Codex Of Wisdom by pressing "F1" or by + * clicking on the "?" on the toolbar at the top of your screen.

+ * + * Context Menus

Context menus can be called up by + * single left-clicking (or Shift + single left-click, if you + * changed it) on most objects or NPCs in the world. Nearly + * everything, including your own avatar will have context menus + * available. Bringing up your avatar's context menu will give + * you options to cancel your quest and review various quest + * information.

+ */ + return 1049092; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + Container bag = Mardoth.GetNewContainer(); + + bag.DropItem( new DarkTidesHorn() ); + + System.From.AddToBackpack( bag ); + + System.AddConversation( new ReanimateMaabusConversation() ); + } + } + + public class ReanimateMaabusConversation : QuestConversation + { + public override object Message + { + get + { + /* Excellent choice, young apprentice of evil!

+ * + * I will not waste our time with pleasantries. There is much work + * to be done � especially in light of the recent Paladin ambushes + * that we have suffered. The necromantic brotherhood is working + * towards the summoning of the elder daemon Kronus, who will rise + * from the Well of Tears to help us finally crush the Paladin forces + * that have plagued our lands for so long now.

+ * + * To summon Kronus, we must energize the Well of Tears with a series + * of dark rituals. Unfortunately the rituals needed to sufficiently + * energize the Well of Tears have been lost to us. Your task will be + * to recover one of the ritual scrolls needed for the summoning.

+ * + * You will need to find the corpse of the Arch Necromancer Maabus, which + * has been laid to rest in the tomb of elders. We believe his spirit may + * have memory of where we may find the scrolls needed for the summoning. + * You will need to awaken him from the slumber of death, using your + * Animate Dead spell, of course.

+ * + * To reach the tomb, step onto the magical teleporter just to the + * West of where I am standing.

+ * + * Once you have been teleported, follow the path, which will lead you to + * the tomb of Maabus.

One more thing before you go:

+ * + * Should you get into trouble out there or should you lose your way, do + * not worry. I have also given you a magical horn - a Horn of Retreat. + * Play the horn at any time to open a magical gateway that leads back to this + * tower.

+ * + * Should your horn run out of charges, simply + * hand me the horn to have it recharged.

+ * + * Good luck friend. + */ + return 1060099; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1026153, 6178 ), // teleporter + new QuestItemInfo( 1049117, 4036 ), // Horn of Retreat + new QuestItemInfo( 1048032, 3702 ) // a bag + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public ReanimateMaabusConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindMaabusTombObjective() ); + } + } + + public class MaabasConversation : QuestConversation + { + public override object Message + { + get + { + /* Maabus emits an ear-crawling screech as his body reanimates. + * He turns and angrily screams at you:

+ * + * YOU INFIDEL! HOW DARE YOU AWAKEN MAABUS!?!

+ * + * Maabus continues to scream at you angrily for some time. + * As he settles down, you explain to him the purpose of your visit. + * Once you explain that you are on a quest to summon the elder daemon + * Kronus, Maabus begins to cooperate, and begins to speak in a more + * reasonable tone:

+ * + * Well, why didn�t you say so? If you�re going to raise Kronus from + * the Well of Tears, you must first complete a long series of dark + * rituals. I once owned one of the scrolls needed for the summoning, + * but alas it was lost to me when I lost my life to a cowardly Paladin + * ambush near the Paladin city of Light. They would have probably + * hidden the scroll in their precious crystal cave near the city.

+ * + * There is a teleporter in the corner of this tomb. It will transport + * you near the crystal cave at which I believe one of the calling scrolls + * is hidden. Good luck.

+ * + * Maabus' body slumps back into the coffinas your magic expires. + */ + return 1060103; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1026153, 6178 ) // teleporter + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public MaabasConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindCrystalCaveObjective() ); + } + } + + public class HorusConversation : QuestConversation + { + public override object Message + { + get + { + /* An old man, dressed in slightly tattered armor, whom you recognize + * to be a Paladin stands before the Crystal Cave staring blankly into + * the space in front of him. As he begins to speak to you, you realize + * this man is blind. You attempt to persuade the blind man that you are + * a Paladin seeking to inspect the scroll of calling...

+ * + * Greetings traveler!

+ * + * You seek entrance to the Crystal Cave, home of the Calling Scroll? Hmm. + * You reak of death and decay, brother. You reak of death like a Necromancer, + * but yet you claim to be a Paladin in hopes that I will grant thee passage + * into the cave?

+ * + * Please don�t think ill of me for this, but I�m just a blind, old man looking + * to keep the brotherhood of Paladins safe from the clutches of the elder daemon + * Kronus. The Necromancers have been after this particular scroll for quite some + * time, so we must take all the security precautions we can.

+ * + * Before I can let you pass into the Crystal Cave, you must speak to me the secret + * word that is kept in the Scroll of Abraxus in the Vault of Secrets at the Paladin + * city of Light. It�s the only way that I can be sure you are who you claim to be, + * since Necromancers cannot enter the Vault due to powerful protective magic that + * the brotherhood has blessed the vault with. + */ + return 1060105; + } + } + + public HorusConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindMardothAboutVaultObjective() ); + } + } + + public class MardothVaultConversation : QuestConversation + { + public override object Message + { + get + { + /* Mardoth looks at you expectantly until you tell him that you failed + * to retrieve the scroll...

+ * + * You failed? Very unfortunate... So now you must find your way into + * the paladin�s Vault of Secrets, eh? Well, you won't be able to get in + * � there is a powerful magic aura that protects the Vault from all + * Necromancers. We simply cannot enter. However, that's not to say you + * familiar spirit can't.

+ * + * Mardoth grins with obvious satisfaction + * as he explains the details of the Summon + * Familiar spell to you..., which will allow you to summon a + * scavenging Horde Minion to steal the scroll.

+ * + * Very well. You are prepared to go. Take the teleporter just to the + * West of where I am standing to transport + * to the Paladin city of Light. Once you have arrived in the city, follow + * the road of glowing runes to the Vault of Secrets. You know what to do. + */ + return 1060107; + } + } + + public MardothVaultConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindCityOfLightObjective() ); + } + } + + public class VaultOfSecretsConversation : QuestConversation + { + public override object Message + { + get + { + /* You have arrived in the Vault of Secrets. You can feel the + * protective magic in this place restricting you, making you + * feel nearly claustrophobic.

+ * + * Just ahead of you and out of your reach, you see a collection + * of scrolls and books, one of them being entitled + * 'Scroll of Abraxus' . You can only assume that this scroll + * holds the current password required to enter the Crystal Cave.

+ * + * This would be a good opportunity to summon + * your familiar. Since your familiar is not a Necromancer, it + * will not be affected by the anti-magic aura that surrounds the Vault.

+ * + * Summon your familiar with the Summon Familiar spell. + */ + return 1060110; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1023643, 8787 ) // spellbook + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public VaultOfSecretsConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FetchAbraxusScrollObjective() ); + } + } + + public class ReadAbraxusScrollConversation : QuestConversation + { + public override object Message + { + get + { + /* You have obtained the Scroll of Abraxus, which contains the secret + * password needed to gain passage into the Crystal Cave where the + * Scroll of Calling is kept. Read the scroll (double click) and + * figure out the password.

+ * + * Once you have the password, return to the Crystal Cave and speak + * the password to the guard.

+ * + * If you do not know the way to the Crystal Cave from the Paladin City, + * you can use the magic teleporter located just outside of the vault. + */ + return 1060114; + } + } + + public ReadAbraxusScrollConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReadAbraxusScrollObjective() ); + } + } + + public class SecondHorusConversation : QuestConversation + { + public override object Message + { + get + { + /* Very well Paladin, you have proven to me your identity. + * I grant thee passage.

+ * + * Be careful, however � I�ve heard that the cave has been + * infested with a vermin of some sort. Our High Lord + * Melkeer was supposed to send some troops to clear the + * vermin out of the cave, but that was last week already. + * I fear that he forgot.

+ * + * If you can find it in your goodness to dispose of at + * least 5 of those vermin in there, I shall reward your + * efforts. If however you are too busy, and I would + * understand if you were, don�t bother with the vermin.

+ * + * You may now pass through the energy barrier to enter the + * Crystal Cave. Take care honorable Paladin soul. + * Walk in the light my friend. + */ + return 1060118; + } + } + + public SecondHorusConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindCallingScrollObjective() ); + } + } + + public class HealConversation : QuestConversation + { + public override object Message + { + get + { + /* You've just slain a creature. Now is a good time to learn how + * to heal yourself as a Necromancer.

+ * + * As a follower of the dark path, you are able to recover lost + * hitpoints by communing with the spirit world via the skill + * Spirit Speak. Learn more about it now, + * in the codex of Wisdom. + */ + return 1061610; + } + } + + public HealConversation() + { + } + } + + public class HorusRewardConversation : QuestConversation + { + public override object Message + { + get + { + /* I thank you for going out of your way to clean out some + * of the vermin in that cave � here is your reward: a bag + * containing 500 gold coins plus a strange and magical artifact + * that should come in handy in your travels.

+ * + * Take care young Paladin! + */ + return 1060717; + } + } + + public override bool Logged{ get{ return false; } } + + public HorusRewardConversation() + { + } + } + + public class LostCallingScrollConversation : QuestConversation + { + private bool m_FromMardoth; + + public override object Message + { + get + { + if ( m_FromMardoth ) + { + /* You return without the scroll of Calling? I'm afraid that + * won't do. You must return to the Crystal Cave and fetch + * another scroll. Use the teleporter to the West of me to + * get there. Return here when you have the scroll. Do not + * fail me this time, young apprentice of evil. + */ + return 1062058; + } + else // from well of tears + { + /* You have arrived at the well, but no longer have the scroll + * of calling. Use Mardoth's teleporter to return to the + * Crystal Cave and fetch another scroll from the box. + */ + return 1060129; + } + } + } + + public override bool Logged{ get{ return false; } } + + public LostCallingScrollConversation( bool fromMardoth ) + { + m_FromMardoth = fromMardoth; + } + + // Serialization + public LostCallingScrollConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_FromMardoth = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_FromMardoth ); + } + } + + public class MardothKronusConversation : QuestConversation + { + public override object Message + { + get + { + /* You have returned with the scroll! I knew I could count on you. + * You can now perform the rite of calling at the Well of Tears. + * This ritual will help charge the Well to prepare for the coming + * of Kronus. You are prepared to do your part young Necromancer!

+ * + * Just outside of this tower, you will find a path lined with red + * lanterns. Follow this path to get to the Well of Tears. Once + * you have arrived at the Well, use the scroll to perform the + * ritual of calling. Performing the rite will empower the well + * and bring us that much closer to the arrival of Kronus.

+ * + * Once you have completed the ritual, return here for your + * promised reward. + */ + return 1060121; + } + } + + public MardothKronusConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindWellOfTearsObjective() ); + } + } + + public class MardothEndConversation : QuestConversation + { + public override object Message + { + get + { + /* You have done as I asked... I knew I could count on you from + * the moment you walked in here!

+ * + * The forces of evil are strong within you. You will become + * a great Necromancer in this life - perhaps even the greatest.

+ * + * My work for you is done here. I release you from my service + * to go into the world and fight for our cause...

+ * + * Oh...I almost forgot - your reward. Here is a magical + * weapon and 2000 gold for you, in the form of a check. Don't + * spend it all in one place though, eh?

+ * + * Actually, before you can spend any of it at all, you will + * have to cash the check at the + * nearest bank. Shopkeepers never accept checks for payment, + * they require cash.

+ * + * In your pack, you will find an enchanted sextant. Use this + * sextant to guide you to the nearest bank.

+ * + * Farewell, and stay true to the ways of the shadow... + */ + return 1060133; + } + } + + public MardothEndConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindBankObjective() ); + } + } + + public class BankerConversation : QuestConversation + { + public override object Message + { + get + { + /* The banker smiles at you and greets you in a loud and robust voice...

+ * + * Well hello there adventurer! I see you've learned how to cash checks. Wonderful! + * Let me tell you a bit about the banks in this world...

+ * + * Anything that you place into any bank box, can be retrieved from any other + * bank box in the land. For instance, if you place an item into a bank box in + * Britain, it can be retrieved from your bank box in Moonglow or any other city.

+ * + * Bank boxes are very secure. So secure, in fact, that no one can ever get into + * your bank box except for yourself. Security is hard to come by these days, + * but you can trust in the banking system of Britannia! We shall not let you down!

+ * + * I hope to be seeing much more of you as your riches grow! May your bank box overflow + * with the spoils of your adventures.

Farewell adventurer, you are now free to + * explore the world on your own. + */ + return 1060137; + } + } + + public BankerConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class RadarConversation : QuestConversation + { + public override object Message + { + get + { + /* If you are leaving the tower, you should learn about the Radar Map.

+ * + * The Radar Map (or Overhead View) can be opened by pressing 'ALT-R' + * on your keyboard. It shows your immediate surroundings from a bird's + * eye view.

Pressing ALT-R twice, will enlarge the Radar Map a + * little. Use the Radar Map often as you travel throughout the world + * to familiarize yourself with your surroundings. + */ + return 1061692; + } + } + + public override bool Logged{ get{ return false; } } + + public RadarConversation() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/DarkTidesQuest.cs b/Scripts/Engines/Quests/Dark Tides/DarkTidesQuest.cs new file mode 100644 index 0000000..fa35178 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/DarkTidesQuest.cs @@ -0,0 +1,153 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Necro +{ + public class DarkTidesQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Necro.AcceptConversation ), + typeof( Necro.AnimateMaabusCorpseObjective ), + typeof( Necro.BankerConversation ), + typeof( Necro.CashBankCheckObjective ), + typeof( Necro.FetchAbraxusScrollObjective ), + typeof( Necro.FindBankObjective ), + typeof( Necro.FindCallingScrollObjective ), + typeof( Necro.FindCityOfLightObjective ), + typeof( Necro.FindCrystalCaveObjective ), + typeof( Necro.FindMaabusCorpseObjective ), + typeof( Necro.FindMaabusTombObjective ), + typeof( Necro.FindMardothAboutKronusObjective ), + typeof( Necro.FindMardothAboutVaultObjective ), + typeof( Necro.FindMardothEndObjective ), + typeof( Necro.FindVaultOfSecretsObjective ), + typeof( Necro.FindWellOfTearsObjective ), + typeof( Necro.HorusConversation ), + typeof( Necro.LostCallingScrollConversation ), + typeof( Necro.MaabasConversation ), + typeof( Necro.MardothEndConversation ), + typeof( Necro.MardothKronusConversation ), + typeof( Necro.MardothVaultConversation ), + typeof( Necro.RadarConversation ), + typeof( Necro.ReadAbraxusScrollConversation ), + typeof( Necro.ReadAbraxusScrollObjective ), + typeof( Necro.ReanimateMaabusConversation ), + typeof( Necro.RetrieveAbraxusScrollObjective ), + typeof( Necro.ReturnToCrystalCaveObjective ), + typeof( Necro.SecondHorusConversation ), + typeof( Necro.SpeakCavePasswordObjective ), + typeof( Necro.UseCallingScrollObjective ), + typeof( Necro.VaultOfSecretsConversation ), + typeof( Necro.FindHorusAboutRewardObjective ), + typeof( Necro.HealConversation ), + typeof( Necro.HorusRewardConversation ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // Dark Tides + return 1060095; + } + } + + public override object OfferMessage + { + get + { + /* An old man who looks to be 200 years old from the looks + * of his translucently pale and heavily wrinkled skin, turns + * to you and gives you a half-cocked grin that makes you + * feel somewhat uneasy.

+ * + * After a short pause, he begins to speak to you...


+ * + * Hmm. What's this? Another budding Necromancer to join the + * ranks of Evil? Here... let me take a look at you... Ah + * yes... Very Good! I sense the forces of evil are strong + * within you, child � but you need training so that you can + * learn to focus your skills against those aligned against + * our cause. You are destined to become a legendary + * Necromancer - with the proper training, that only I can + * give you.

+ * + * Mardoth pauses just long enough to give you a wide, + * skin-crawling grin.

+ * + * Let me introduce myself. I am Mardoth, the guildmaster of + * the Necromantic Brotherhood. I have taken it upon myself + * to train anyone willing to learn the dark arts of Necromancy. + * The path of destruction, decay and obliteration is not an + * easy one. Only the most evil and the most dedicated can + * hope to master the sinister art of death.

+ * + * I can lend you training and help supply you with equipment � + * in exchange for a few services rendered by you, of course. + * Nothing major, just a little death and destruction here and + * there - the tasks should be easy as a tasty meat pie for one + * as treacherous and evil as yourself.

+ * + * What do you say? Do we have a deal? + */ + return 1060094; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.MaxValue; } } + public override bool IsTutorial{ get{ return true; } } + + public override int Picture{ get{ return 0x15B5; } } + + public DarkTidesQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public DarkTidesQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + if ( from is SummonedPaladin ) + return true; + + return base.IgnoreYoungProtection( from ); + } + + public static bool HasLostCallingScroll( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FindMardothAboutKronusObjective ) ) || qs.IsObjectiveInProgress( typeof( FindWellOfTearsObjective ) ) || qs.IsObjectiveInProgress( typeof( UseCallingScrollObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( KronusScroll ) ) == null ); + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/CrystalCaveBarrier.cs b/Scripts/Engines/Quests/Dark Tides/Items/CrystalCaveBarrier.cs new file mode 100644 index 0000000..b5ee28f --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/CrystalCaveBarrier.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class CrystalCaveBarrier : Item + { + [Constructable] + public CrystalCaveBarrier() : base( 0x3967 ) + { + Movable = false; + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m.AccessLevel > AccessLevel.Player ) + return true; + + bool sendMessage = m.Player; + + if ( m is BaseCreature ) + m = ((BaseCreature)m).ControlMaster; + + PlayerMobile pm = m as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SpeakCavePasswordObjective ) ); + + if ( obj != null && obj.Completed ) + { + if ( sendMessage ) + m.SendLocalizedMessage( 1060648 ); // With Horus' permission, you are able to pass through the barrier. + + return true; + } + } + } + + if ( sendMessage ) + m.SendLocalizedMessage( 1060649, "", 0x66D ); // Without the permission of the guardian Horus, the magic of the barrier prevents your passage. + + return false; + } + + public CrystalCaveBarrier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/DarkTidesHorn.cs b/Scripts/Engines/Quests/Dark Tides/Items/DarkTidesHorn.cs new file mode 100644 index 0000000..3b22430 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/DarkTidesHorn.cs @@ -0,0 +1,44 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class DarkTidesHorn : HornOfRetreat + { + public override bool ValidateUse( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + return ( pm != null && pm.Quest is DarkTidesQuest ); + } + + [Constructable] + public DarkTidesHorn() + { + DestLoc = new Point3D( 2103, 1319, -68 ); + DestMap = Map.Malas; + } + + public DarkTidesHorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/DarkTidesTeleporter.cs b/Scripts/Engines/Quests/Dark Tides/Items/DarkTidesTeleporter.cs new file mode 100644 index 0000000..662a7a2 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/DarkTidesTeleporter.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class DarkTidesTeleporter : DynamicTeleporter + { + [Constructable] + public DarkTidesTeleporter() + { + } + + public override bool GetDestination( PlayerMobile player, ref Point3D loc, ref Map map ) + { + QuestSystem qs = player.Quest; + + if ( qs is DarkTidesQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FindMaabusTombObjective ) ) ) + { + loc = new Point3D( 2038, 1263, -90 ); + map = Map.Malas; + qs.AddConversation( new RadarConversation() ); + return true; + } + else if ( qs.IsObjectiveInProgress( typeof( FindCrystalCaveObjective ) ) ) + { + loc = new Point3D( 1194, 521, -90 ); + map = Map.Malas; + return true; + } + else if ( qs.IsObjectiveInProgress( typeof( FindCityOfLightObjective ) ) ) + { + loc = new Point3D( 1091, 519, -90 ); + map = Map.Malas; + return true; + } + else if ( qs.IsObjectiveInProgress( typeof( ReturnToCrystalCaveObjective ) ) ) + { + loc = new Point3D( 1194, 521, -90 ); + map = Map.Malas; + return true; + } + else if ( DarkTidesQuest.HasLostCallingScroll( player ) ) + { + loc = new Point3D( 1194, 521, -90 ); + map = Map.Malas; + return true; + } + } + + return false; + } + + public DarkTidesTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs b/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs new file mode 100644 index 0000000..5ca5497 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/KronusScroll.cs @@ -0,0 +1,166 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; + +namespace Server.Engines.Quests.Necro +{ + public class KronusScroll : QuestItem + { + public override int LabelNumber { get { return 1060149; } } // Calling of Kronus + + [Constructable] + public KronusScroll() : base( 0x227A ) + { + Weight = 1.0; + Hue = 0x44E; + } + + public KronusScroll( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + DarkTidesQuest qs = player.Quest as DarkTidesQuest; + + if ( qs == null ) + return true; + + /*return !( qs.IsObjectiveInProgress( typeof( FindCallingScrollObjective ) ) + || qs.IsObjectiveInProgress( typeof( FindMardothAboutKronusObjective ) ) + || qs.IsObjectiveInProgress( typeof( FindWellOfTearsObjective ) ) + || qs.IsObjectiveInProgress( typeof( UseCallingScrollObjective ) ) );*/ + return false; + } + + private static readonly Rectangle2D m_WellOfTearsArea = new Rectangle2D( 2080, 1346, 10, 10 ); + private static readonly Map m_WellOfTearsMap = Map.Malas; + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from ) ) + return; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FindMardothAboutKronusObjective ) ) ) + { + pm.SendLocalizedMessage( 1060151, "", 0x41 ); // You read the scroll, but decide against performing the calling until you are instructed to do so by Mardoth. + } + else if ( qs.IsObjectiveInProgress( typeof( FindWellOfTearsObjective ) ) ) + { + pm.SendLocalizedMessage( 1060152, "", 0x41 ); // You must be at the Well of Tears in the city of Necromancers to use this scroll. + } + else if ( qs.IsObjectiveInProgress( typeof( UseCallingScrollObjective ) ) ) + { + if ( pm.Map == m_WellOfTearsMap && m_WellOfTearsArea.Contains( pm ) ) + { + QuestObjective obj = qs.FindObjective( typeof( UseCallingScrollObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + + Delete(); + new CallingTimer( pm ).Start(); + } + else + { + pm.SendLocalizedMessage( 1060152, "", 0x41 ); // You must be at the Well of Tears in the city of Necromancers to use this scroll. + } + } + else + { + pm.SendLocalizedMessage( 1060150, "", 0x41 ); // A strange terror grips your heart as you attempt to read the scroll. You decide it would be a bad idea to read it out loud. + } + } + } + } + + private class CallingTimer : Timer + { + private PlayerMobile m_Player; + private int m_Step; + + public CallingTimer( PlayerMobile player ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ), 6 ) + { + Priority = TimerPriority.TwentyFiveMS; + + m_Player = player; + m_Step = 0; + } + + protected override void OnTick() + { + if ( m_Player.Deleted ) + { + Stop(); + return; + } + + if ( !m_Player.Mounted ) + m_Player.Animate( Utility.RandomBool() ? 16 : 17, 7, 1, true, false, 0 ); + + if ( m_Step == 4 ) + { + int baseX = KronusScroll.m_WellOfTearsArea.X; + int baseY = KronusScroll.m_WellOfTearsArea.Y; + int width = KronusScroll.m_WellOfTearsArea.Width; + int height = KronusScroll.m_WellOfTearsArea.Height; + Map map = KronusScroll.m_WellOfTearsMap; + + Effects.SendLocationParticles( EffectItem.Create( m_Player.Location, m_Player.Map, TimeSpan.FromSeconds( 1.0 ) ), 0, 0, 0, 0x13C4 ); + Effects.PlaySound( m_Player.Location, m_Player.Map, 0x243 ); + + for ( int i = 0; i < 15; i++ ) + { + int x = baseX + Utility.Random( width ); + int y = baseY + Utility.Random( height ); + int z = map.GetAverageZ( x, y ); + + Point3D from = new Point3D( x, y, z + Utility.RandomMinMax( 5, 20 ) ); + Point3D to = new Point3D( x, y, z ); + + int hue = Utility.RandomList( 0x481, 0x482, 0x489, 0x497, 0x66D ); + + Effects.SendPacket( from, map, new HuedEffect( EffectType.Moving, Serial.Zero, Serial.Zero, 0x36D4, from, to, 0, 0, false, true, hue, 0 ) ); + } + } + + if ( m_Step < 5 ) + { + m_Player.Frozen = true; + } + else // Cast completed + { + m_Player.Frozen = false; + + SummonedPaladin.BeginSummon( m_Player ); + } + + m_Step++; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/KronusScrollBox.cs b/Scripts/Engines/Quests/Dark Tides/Items/KronusScrollBox.cs new file mode 100644 index 0000000..5480c98 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/KronusScrollBox.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Necro +{ + public class KronusScrollBox : MetalBox + { + [Constructable] + public KronusScrollBox() + { + ItemID = 0xE80; + Movable = false; + + for ( int i = 0; i < 40; i++ ) + { + Item scroll = Loot.RandomScroll( 0, 15, SpellbookType.Necromancer ); + scroll.Movable = false; + DropItem( scroll ); + } + } + + public KronusScrollBox( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null && pm.InRange( GetWorldLocation(), 2 ) ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FindCallingScrollObjective ) ); + + if ( (obj != null && !obj.Completed) || DarkTidesQuest.HasLostCallingScroll( from ) ) + { + Item scroll = new KronusScroll(); + + if ( pm.PlaceInBackpack( scroll ) ) + { + pm.SendLocalizedMessage( 1060120, "", 0x41 ); // You rummage through the scrolls until you find the Scroll of Calling. You quickly put it in your pack. + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + else + { + pm.SendLocalizedMessage( 1060148, "", 0x41 ); // You were unable to take the scroll. + scroll.Delete(); + } + } + } + } + + base.OnDoubleClick( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs b/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs new file mode 100644 index 0000000..4d855f2 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/MaabusCoffin.cs @@ -0,0 +1,158 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.Quests.Necro +{ + public class MaabusCoffin : BaseAddon + { + private Maabus m_Maabus; + private Point3D m_SpawnLocation; + + [CommandProperty( AccessLevel.GameMaster )] + public Maabus Maabus { get { return m_Maabus; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D SpawnLocation { get { return m_SpawnLocation; } set { m_SpawnLocation = value; } } + + [Constructable] + public MaabusCoffin() + { + AddComponent( new MaabusCoffinComponent( 0x1C2B, 0x1C2B ), -1, -1, 0 ); + + AddComponent( new MaabusCoffinComponent( 0x1D16, 0x1C2C ), 0, -1, 0 ); + AddComponent( new MaabusCoffinComponent( 0x1D17, 0x1C2D ), 1, -1, 0 ); + AddComponent( new MaabusCoffinComponent( 0x1D51, 0x1C2E ), 2, -1, 0 ); + + AddComponent( new MaabusCoffinComponent( 0x1D4E, 0x1C2A ), 0, 0, 0 ); + AddComponent( new MaabusCoffinComponent( 0x1D4D, 0x1C29 ), 1, 0, 0 ); + AddComponent( new MaabusCoffinComponent( 0x1D4C, 0x1C28 ), 2, 0, 0 ); + } + + public void Awake( Mobile caller ) + { + if ( m_Maabus != null || m_SpawnLocation == Point3D.Zero ) + return; + + foreach ( MaabusCoffinComponent c in Components ) + c.TurnToEmpty(); + + m_Maabus = new Maabus(); + + m_Maabus.Location = m_SpawnLocation; + m_Maabus.Map = Map; + + m_Maabus.Direction = m_Maabus.GetDirectionTo( caller ); + + Timer.DelayCall( TimeSpan.FromSeconds( 7.5 ), new TimerCallback( BeginSleep ) ); + } + + public void BeginSleep() + { + if ( m_Maabus == null ) + return; + + Effects.PlaySound( m_Maabus.Location, m_Maabus.Map, 0x48E ); + + Timer.DelayCall( TimeSpan.FromSeconds( 2.5 ), new TimerCallback( Sleep ) ); + } + + public void Sleep() + { + if ( m_Maabus == null ) + return; + + Effects.SendLocationParticles( EffectItem.Create( m_Maabus.Location, m_Maabus.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 0x7E7 ); + Effects.PlaySound( m_Maabus.Location, m_Maabus.Map, 0x1FE ); + + m_Maabus.Delete(); + m_Maabus = null; + + foreach ( MaabusCoffinComponent c in Components ) + c.TurnToFull(); + } + + public MaabusCoffin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Maabus ); + writer.Write( (Point3D) m_SpawnLocation ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Maabus = reader.ReadMobile() as Maabus; + m_SpawnLocation = reader.ReadPoint3D(); + + Sleep(); + } + } + + public class MaabusCoffinComponent : AddonComponent + { + private int m_FullItemID; + private int m_EmptyItemID; + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D SpawnLocation + { + get { return Addon is MaabusCoffin ? ((MaabusCoffin)Addon).SpawnLocation : Point3D.Zero; } + set { if ( Addon is MaabusCoffin ) ((MaabusCoffin)Addon).SpawnLocation = value; } + } + + public MaabusCoffinComponent( int itemID ) : this( itemID, itemID ) + { + } + + public MaabusCoffinComponent( int fullItemID, int emptyItemID ) : base( fullItemID ) + { + m_FullItemID = fullItemID; + m_EmptyItemID = emptyItemID; + } + + public void TurnToEmpty() + { + ItemID = m_EmptyItemID; + } + + public void TurnToFull() + { + ItemID = m_FullItemID; + } + + public MaabusCoffinComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_FullItemID ); + writer.Write( (int) m_EmptyItemID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_FullItemID = reader.ReadInt(); + m_EmptyItemID = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/ScrollOfAbraxus.cs b/Scripts/Engines/Quests/Dark Tides/Items/ScrollOfAbraxus.cs new file mode 100644 index 0000000..ea7bc1d --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/ScrollOfAbraxus.cs @@ -0,0 +1,146 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class ScrollOfAbraxus : QuestItem + { + public override int LabelNumber { get { return 1028827; } } // Scroll of Abraxus + + [Constructable] + public ScrollOfAbraxus() : base( 0x227B ) + { + Weight = 1.0; + } + + public override bool CanDrop( PlayerMobile player ) + { + DarkTidesQuest qs = player.Quest as DarkTidesQuest; + + if ( qs == null ) + return true; + + //return !( qs.IsObjectiveInProgress( typeof( RetrieveAbraxusScrollObjective ) ) || qs.IsObjectiveInProgress( typeof( ReadAbraxusScrollObjective ) ) ); + return false; + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + PlayerMobile pm = RootParent as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( RetrieveAbraxusScrollObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.SendGump( new ScrollOfAbraxusGump() ); + + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( ReadAbraxusScrollObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public ScrollOfAbraxus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ScrollOfAbraxusGump : Gump + { + public ScrollOfAbraxusGump() : base( 150, 50 ) + { + AddPage( 0 ); + + AddImage( 0, 0, 1228 ); + AddImage( 340, 255, 9005 ); + + /* Security at the Crystal Cave

+ * + * We have taken great measuresto ensure the safety of the + * Scroll of Calling, which we have so valiantly taken from + * the Necromancer Maabus during the battle of the wood + * nearly 200 years ago.

+ * + * The scroll must never fall into the hands of the + * Necromancers again, lest they use it to summon the ancient + * daemon Kronus. The scroll of calling is a necessity in the + * series of dark rites the Necromancers must perform to once again + * re-awaken Kronus.

+ * + * Should Kronus ever rise again, the days of the Paladins, and + * indeed humanity as we know it will be numbered.

+ * + * For this reason, we have posted the honorable Horus, former + * General of the Northern Legions to guard the entrance of the + * Crystal Cave where we keep the Scroll of Calling. Horus was + * infused with magical life from the tree Urywen during his last + * battle. The power gave him eternal life, but it also, + * unfortunately, took his eye sight.

+ * + * Since Horus cannot see those he admits to the Crystal Cave, + * he will only allow those that know the secret password to enter. + * Speak the following word to Horus and he shall grant you passage + * to the Crystal Cave:

+ * + * Urywen

+ * + * Do not speak this password anywhere except when seeking passage + * into the Crystal Cave, as our adversaries are lurking in the + * shadows � they are everywhere.

Go with the light, friend.

+ * + * - Frater Melkeer + */ + AddHtmlLocalized( 25, 36, 350, 210, 1060116, 1, false, true ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Items/VaultOfSecretsBarrier.cs b/Scripts/Engines/Quests/Dark Tides/Items/VaultOfSecretsBarrier.cs new file mode 100644 index 0000000..c9f1da5 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Items/VaultOfSecretsBarrier.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class VaultOfSecretsBarrier : Item + { + [Constructable] + public VaultOfSecretsBarrier() : base( 0x49E ) + { + Movable = false; + Visible = false; + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m.AccessLevel > AccessLevel.Player ) + return true; + + PlayerMobile pm = m as PlayerMobile; + + if ( pm != null && pm.Profession == 4 ) + { + m.SendLocalizedMessage( 1060188, "", 0x24 ); // The wicked may not enter! + return false; + } + + return base.OnMoveOver( m ); + } + + public VaultOfSecretsBarrier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Mobiles/Horus.cs b/Scripts/Engines/Quests/Dark Tides/Mobiles/Horus.cs new file mode 100644 index 0000000..7f6b436 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Mobiles/Horus.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class Horus : BaseQuester + { + [Constructable] + public Horus() : base( "the Guardian" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83F3; + Body = 0x190; + + Name = "Horus"; + } + + public override void InitOutfit() + { + AddItem( SetHue( new PlateLegs(), 0x849 ) ); + AddItem( SetHue( new PlateChest(), 0x849 ) ); + AddItem( SetHue( new PlateArms(), 0x849 ) ); + AddItem( SetHue( new PlateGloves(), 0x849 ) ); + AddItem( SetHue( new PlateGorget(), 0x849 ) ); + + AddItem( SetHue( new Bardiche(), 0x482 ) ); + + AddItem( SetHue( new Boots(), 0x001 ) ); + AddItem( SetHue( new Cloak(), 0x482 ) ); + + Utility.AssignRandomHair( this, false ); + Utility.AssignRandomFacialHair( this, false ); + } + + public override int GetAutoTalkRange( PlayerMobile m ) + { + return 3; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + QuestSystem qs = to.Quest; + + return ( qs is DarkTidesQuest && qs.IsObjectiveInProgress( typeof( FindCrystalCaveObjective ) ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FindCrystalCaveObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( InRange( m.Location, 2 ) && !InRange( oldLocation, 2 ) && m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( ReturnToCrystalCaveObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + else + { + obj = qs.FindObjective( typeof( FindHorusAboutRewardObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + cont.DropItem( new Gold( 500 ) ); + + BaseJewel jewel = new GoldBracelet(); + if ( Core.AOS ) + BaseRunicTool.ApplyAttributesTo( jewel, 3, 20, 40 ); + cont.DropItem( jewel ); + + if ( !pm.PlaceInBackpack( cont ) ) + { + cont.Delete(); + pm.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + else + { + obj.Complete(); + } + } + } + } + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SpeakCavePasswordObjective ) ); + bool enabled = ( obj != null && !obj.Completed ); + + list.Add( new SpeakPasswordEntry( this, pm, enabled ) ); + } + } + } + } + + public virtual void OnPasswordSpoken( PlayerMobile from ) + { + QuestSystem qs = from.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SpeakCavePasswordObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + return; + } + } + + from.SendLocalizedMessage( 1060185 ); // Horus ignores you. + } + + private class SpeakPasswordEntry : ContextMenuEntry + { + private Horus m_Horus; + private PlayerMobile m_From; + + public SpeakPasswordEntry( Horus horus, PlayerMobile from, bool enabled ) : base( 6193, 3 ) + { + m_Horus = horus; + m_From = from; + + if ( !enabled ) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if ( m_From.Alive ) + m_Horus.OnPasswordSpoken( m_From ); + } + } + + public Horus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Mobiles/Maabus.cs b/Scripts/Engines/Quests/Dark Tides/Mobiles/Maabus.cs new file mode 100644 index 0000000..b11551f --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Mobiles/Maabus.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Necro +{ + public class Maabus : BaseQuester + { + public Maabus() + { + } + + public override void InitBody() + { + Body = 0x94; + Name = "Maabus"; + } + + public Maabus( Serial serial ) : base( serial ) + { + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return false; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Mobiles/Mardoth.cs b/Scripts/Engines/Quests/Dark Tides/Mobiles/Mardoth.cs new file mode 100644 index 0000000..ea69cb2 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Mobiles/Mardoth.cs @@ -0,0 +1,230 @@ +using System; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Necro +{ + public class Mardoth : BaseQuester + { + [Constructable] + public Mardoth() : base( "the Ancient Necromancer" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x8849; + Body = 0x190; + + Name = "Mardoth"; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is DarkTidesQuest ) + { + if ( dropped is DarkTidesHorn ) + { + if ( player.Young ) + { + DarkTidesHorn horn = (DarkTidesHorn)dropped; + + if ( horn.Charges < 10 ) + { + SayTo( from, 1049384 ); // I have recharged the item for you. + horn.Charges = 10; + } + else + { + SayTo( from, 1049385 ); // That doesn't need recharging yet. + } + } + else + { + player.SendLocalizedMessage(1114333); //You must be young to have this item recharged. + } + + return false; + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override void InitOutfit() + { + AddItem( new Sandals( 0x1 ) ); + AddItem( new Robe( 0x66D ) ); + AddItem( new BlackStaff() ); + AddItem( new WizardsHat( 0x1 ) ); + + FacialHairItemID = 0x2041; + FacialHairHue = 0x482; + + HairItemID = 0x203C; + HairHue = 0x482; + + Item gloves = new BoneGloves(); + gloves.Hue = 0x66D; + AddItem( gloves ); + + Item gorget = new PlateGorget(); + gorget.Hue = 0x1; + AddItem( gorget ); + } + + public override int GetAutoTalkRange( PlayerMobile m ) + { + return 3; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + DarkTidesQuest qs = to.Quest as DarkTidesQuest; + + if ( qs == null ) + return ( to.Quest == null && QuestSystem.CanOfferQuest( to, typeof( DarkTidesQuest ) ) ); + + return ( qs.FindObjective( typeof( FindMardothAboutVaultObjective ) ) != null ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is DarkTidesQuest ) + { + if ( DarkTidesQuest.HasLostCallingScroll( player ) ) + { + qs.AddConversation( new LostCallingScrollConversation( true ) ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( FindMardothAboutVaultObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else + { + obj = qs.FindObjective( typeof( FindMardothAboutKronusObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else + { + obj = qs.FindObjective( typeof( FindMardothEndObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + cont.DropItem( new PigIron( 20 ) ); + cont.DropItem( new NoxCrystal( 20 ) ); + cont.DropItem( new BatWing( 25 ) ); + cont.DropItem( new DaemonBlood( 20 ) ); + cont.DropItem( new GraveDust( 20 ) ); + + BaseWeapon weapon = new BoneHarvester(); + + weapon.Slayer = SlayerName.OrcSlaying; + + if ( Core.AOS ) + { + BaseRunicTool.ApplyAttributesTo( weapon, 3, 20, 40 ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled( 2, 4 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled( 2, 4 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled( 2, 4 ); + } + + cont.DropItem( weapon ); + + cont.DropItem( new BankCheck( 2000 ) ); + cont.DropItem( new EnchantedSextant() ); + + if ( !player.PlaceInBackpack( cont ) ) + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + else + { + obj.Complete(); + } + } + else if ( contextMenu ) + { + FocusTo( player ); + player.SendLocalizedMessage( 1061821 ); // Mardoth has nothing more for you at this time. + } + } + } + } + } + else if ( qs == null && QuestSystem.CanOfferQuest( player, typeof( DarkTidesQuest ) ) ) + { + new DarkTidesQuest( player ).SendOffer(); + } + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m is PlayerMobile && !m.Frozen && !m.Alive && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && InLOS( m ) ) + { + if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + else + { + Direction = GetDirectionTo( m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.Healer ) ); + } + } + } + + public Mardoth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Mobiles/SummonedPaladin.cs b/Scripts/Engines/Quests/Dark Tides/Mobiles/SummonedPaladin.cs new file mode 100644 index 0000000..3f27409 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Mobiles/SummonedPaladin.cs @@ -0,0 +1,241 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Necro +{ + public class SummonedPaladin : BaseCreature + { + private PlayerMobile m_Necromancer; + private bool m_ToDelete; + + public SummonedPaladin( PlayerMobile necromancer ) : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + m_Necromancer = necromancer; + + InitStats( 45, 30, 5 ); + Title = "the Paladin"; + + Hue = 0x83F3; + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, false ); + + FacialHairHue = HairHue; + + AddItem( new Boots( 0x1 ) ); + AddItem( new ChainChest() ); + AddItem( new ChainLegs() ); + AddItem( new RingmailArms() ); + AddItem( new PlateHelm() ); + AddItem( new PlateGloves() ); + AddItem( new PlateGorget() ); + + AddItem( new Cloak( 0xCF ) ); + + AddItem( new ThinLongsword() ); + + SetSkill( SkillName.Swords, 50.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + + PackGold( 500 ); + } + + public override bool IsHarmfulCriminal(Mobile target) + { + if ( target == m_Necromancer ) + return false; + + return base.IsHarmfulCriminal( target ); + } + + public override bool ClickTitle{ get { return false; } } + + public override bool PlayerRangeSensitive{ get { return false; } } + + public override void OnThink() + { + if ( !m_ToDelete && !Frozen ) + { + if ( m_Necromancer == null || m_Necromancer.Deleted || m_Necromancer.Map == Map.Internal ) + { + Delete(); + return; + } + + if ( Combatant != m_Necromancer ) + Combatant = m_Necromancer; + + if ( !m_Necromancer.Alive ) + { + QuestSystem qs = m_Necromancer.Quest; + + if ( qs is DarkTidesQuest && qs.FindObjective( typeof( FindMardothEndObjective ) ) == null ) + qs.AddObjective( new FindMardothEndObjective( false ) ); + + Say( 1060139, m_Necromancer.Name ); // You have made my work easy for me, ~1_NAME~. My task here is done. + + m_ToDelete = true; + + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( Delete ) ); + } + else if ( m_Necromancer.Map != Map || GetDistanceToSqrt( m_Necromancer ) > RangePerception + 1 ) + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + Effects.SendLocationParticles( EffectItem.Create( m_Necromancer.Location, m_Necromancer.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + + Map = m_Necromancer.Map; + Location = m_Necromancer.Location; + + PlaySound( 0x1FE ); + + Say( 1060140 ); // You cannot escape me, knave of evil! + } + } + + base.OnThink(); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + QuestSystem qs = m_Necromancer.Quest; + + if ( qs is DarkTidesQuest && qs.FindObjective( typeof( FindMardothEndObjective ) ) == null ) + qs.AddObjective( new FindMardothEndObjective( true ) ); + } + + public SummonedPaladin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Necromancer ); + writer.Write( (bool) m_ToDelete ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Necromancer = reader.ReadMobile() as PlayerMobile; + m_ToDelete = reader.ReadBool(); + + if ( m_ToDelete ) + Delete(); + } + + public static void BeginSummon( PlayerMobile player ) + { + new SummonTimer( player ).Start(); + } + + private class SummonTimer : Timer + { + private PlayerMobile m_Player; + private SummonedPaladin m_Paladin; + private int m_Step; + + public SummonTimer( PlayerMobile player ) : base( TimeSpan.FromSeconds( 4.0 ) ) + { + Priority = TimerPriority.FiftyMS; + + m_Player = player; + } + + protected override void OnTick() + { + if ( m_Player.Deleted ) + { + if ( m_Step > 0 ) + m_Paladin.Delete(); + + return; + } + + if ( m_Step > 0 && m_Paladin.Deleted ) + return; + + if ( m_Step == 0 ) + { + SummonedPaladinMoongate moongate = new SummonedPaladinMoongate(); + moongate.MoveToWorld( new Point3D( 2091, 1348, -90 ), Map.Malas ); + + Effects.PlaySound( moongate.Location, moongate.Map, 0x20E ); + + m_Paladin = new SummonedPaladin( m_Player ); + m_Paladin.Frozen = true; + + m_Paladin.Location = moongate.Location; + m_Paladin.Map = moongate.Map; + + Delay = TimeSpan.FromSeconds( 2.0 ); + Start(); + } + else if ( m_Step == 1 ) + { + m_Paladin.Direction = m_Paladin.GetDirectionTo( m_Player ); + m_Paladin.Say( 1060122 ); // STOP WICKED ONE! + + Delay = TimeSpan.FromSeconds( 3.0 ); + Start(); + } + else + { + m_Paladin.Frozen = false; + + m_Paladin.Say( 1060123 ); // I will slay you before I allow you to complete your evil rites! + + m_Paladin.Combatant = m_Player; + } + + m_Step++; + } + } + } + + public class SummonedPaladinMoongate : Item + { + public SummonedPaladinMoongate() : base( 0xF6C ) + { + Movable = false; + Hue = 0x482; + Light = LightType.Circle300; + + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Delete ) ); + } + + public SummonedPaladinMoongate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Dark Tides/Objectives.cs b/Scripts/Engines/Quests/Dark Tides/Objectives.cs new file mode 100644 index 0000000..c59d425 --- /dev/null +++ b/Scripts/Engines/Quests/Dark Tides/Objectives.cs @@ -0,0 +1,642 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Necro +{ + public class AnimateMaabusCorpseObjective : QuestObjective + { + public override object Message + { + get + { + /* Re-animate the corpse of Maabus using your Animate Dead + * spell and question him about the Kronus rituals. + */ + return 1060102; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1023643, 8787 ) // spellbook + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public AnimateMaabusCorpseObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new MaabasConversation() ); + } + } + + public class FindCrystalCaveObjective : QuestObjective + { + public override object Message + { + get + { + /* Take the teleporter in the corner of Maabus' tomb to + * the crystal cave where the calling scroll is kept. + */ + return 1060104; + } + } + + public FindCrystalCaveObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new HorusConversation() ); + } + } + + public class FindMardothAboutVaultObjective : QuestObjective + { + public override object Message + { + get + { + /* Infiltrate the city of the Paladins and figure out a way into + * the Vault. See Mardoth for help with this objective. + */ + return 1060106; + } + } + + public FindMardothAboutVaultObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new MardothVaultConversation() ); + } + } + + public class FindMaabusTombObjective : QuestObjective + { + public override object Message + { + get + { + /* Step onto the teleporter near Mardoth and follow the path + * of glowing runes to the tomb of Maabus. + */ + return 1060124; + } + } + + public FindMaabusTombObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 2024, 1240, -90 ), 3 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddObjective( new FindMaabusCorpseObjective() ); + } + } + + public class FindMaabusCorpseObjective : QuestObjective + { + public override object Message + { + get + { + /* This is the tomb of Maabus. Enter within and find + * the corpse of the ancient necromancer. + */ + return 1061142; + } + } + + public FindMaabusCorpseObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 2024, 1223, -90 ), 3 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddObjective( new AnimateMaabusCorpseObjective() ); + } + } + + public class FindCityOfLightObjective : QuestObjective + { + public override object Message + { + get + { + /* Use the teleporter near Mardoth to be transported + * to the Paladin City of Light. + */ + return 1060108; + } + } + + public FindCityOfLightObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 1076, 519, -90 ), 5 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddObjective( new FindVaultOfSecretsObjective() ); + } + } + + public class FindVaultOfSecretsObjective : QuestObjective + { + public override object Message + { + get + { + /* Follow the road paved with glowing runes to + * find the Vault of Secrets. Be careful not + * to give yourself away as a Necromancer while + * in the city. + */ + return 1060109; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1023676, 3679 ) // glowing rune + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public FindVaultOfSecretsObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 1072, 455, -90 ), 1 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddConversation( new VaultOfSecretsConversation() ); + } + } + + public class FetchAbraxusScrollObjective : QuestObjective + { + public override object Message + { + get + { + // Summon your Horde Minion familiar to fetch the scroll for you. + return 1060196; + } + } + + public FetchAbraxusScrollObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 1076, 450, -84 ), 5 ) ) + { + HordeMinionFamiliar hmf = Spells.Necromancy.SummonFamiliarSpell.Table[System.From] as HordeMinionFamiliar; + + if ( hmf != null && hmf.InRange( System.From, 5 ) && hmf.TargetLocation == null ) + { + System.From.SendLocalizedMessage( 1060113 ); // You instinctively will your familiar to fetch the scroll for you. + hmf.TargetLocation = new Point2D( 1076, 450 ); + } + } + } + + public override void OnComplete() + { + System.AddObjective( new RetrieveAbraxusScrollObjective() ); + } + } + + public class RetrieveAbraxusScrollObjective : QuestObjective + { + public override object Message + { + get + { + /* Double click your Horde Minion to open his pack and retrieve + * the Scroll of Abraxus that he looted for you. + */ + return 1060199; + } + } + + public RetrieveAbraxusScrollObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ReadAbraxusScrollConversation() ); + } + } + + public class ReadAbraxusScrollObjective : QuestObjective + { + public override object Message + { + get + { + /* Find the Crystal Cave password by reading (double click) + * the golden scroll entitled "Scroll of Abraxus" that you + * got from your familiar.. + */ + return 1060125; + } + } + + public ReadAbraxusScrollObjective() + { + } + + public override void OnComplete() + { + System.AddObjective( new ReturnToCrystalCaveObjective() ); + } + } + + public class ReturnToCrystalCaveObjective : QuestObjective + { + public override object Message + { + get + { + /* Now that you have the password, return to the Crystal Cave + * to speak with the guard there. Use the teleporter outside + * of the vault to get there if necessary. + */ + return 1060115; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1026153, 6178 ) // teleporter + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public ReturnToCrystalCaveObjective() + { + } + + public override void OnComplete() + { + System.AddObjective( new SpeakCavePasswordObjective() ); + } + } + + public class SpeakCavePasswordObjective : QuestObjective + { + public override object Message + { + get + { + /* Speak the secret word that you read in the scroll + * stolen from the Vault to Horus the guard, using + * his context menu. + */ + return 1060117; + } + } + + public SpeakCavePasswordObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new SecondHorusConversation() ); + } + } + + public class FindCallingScrollObjective : QuestObjective + { + public override object Message + { + get + { + /* Enter the Crystal Cave and find the Scroll of Calling. + * The barrier will now allow you to pass. + */ + return 1060119; + } + } + + private int m_SkitteringHoppersKilled; + private bool m_HealConversationShown; + private bool m_SkitteringHoppersDisposed; + + public FindCallingScrollObjective() + { + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + return !m_SkitteringHoppersDisposed && from is SkitteringHopper; + } + + public override bool GetKillEvent( BaseCreature creature, Container corpse ) + { + return !m_SkitteringHoppersDisposed; + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is SkitteringHopper ) + { + if ( !m_HealConversationShown ) + { + m_HealConversationShown = true; + System.AddConversation( new HealConversation() ); + } + + if ( ++m_SkitteringHoppersKilled >= 5 ) + { + m_SkitteringHoppersDisposed = true; + System.AddObjective( new FindHorusAboutRewardObjective() ); + } + } + } + + public override void OnComplete() + { + System.AddObjective( new FindMardothAboutKronusObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_SkitteringHoppersKilled = reader.ReadEncodedInt(); + m_HealConversationShown = reader.ReadBool(); + m_SkitteringHoppersDisposed = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_SkitteringHoppersKilled ); + writer.Write( (bool) m_HealConversationShown ); + writer.Write( (bool) m_SkitteringHoppersDisposed ); + } + } + + public class FindHorusAboutRewardObjective : QuestObjective + { + public override object Message + { + get + { + /* You have disposed of the creatures as Horus has asked. + * See him on your way out of the Crystal Cave to claim your reward. + */ + return 1060126; + } + } + + public FindHorusAboutRewardObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new HorusRewardConversation() ); + } + } + + public class FindMardothAboutKronusObjective : QuestObjective + { + public override object Message + { + get + { + /* You have obtained the scroll of calling. See Mardoth + * for further instructions. + */ + return 1060127; + } + } + + public FindMardothAboutKronusObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new MardothKronusConversation() ); + } + } + + public class FindWellOfTearsObjective : QuestObjective + { + public override object Message + { + get + { + /* Follow the red lanterns to the Well of Tears where + * you will perform the calling of Kronus. + */ + return 1060128; + } + } + + public FindWellOfTearsObjective() + { + } + + private static readonly Rectangle2D m_WellOfTearsArea = new Rectangle2D( 2080, 1346, 10, 10 ); + + private bool m_Inside; + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && m_WellOfTearsArea.Contains( System.From.Location ) ) + { + if ( DarkTidesQuest.HasLostCallingScroll( System.From ) ) + { + if ( !m_Inside ) + System.AddConversation( new LostCallingScrollConversation( false ) ); + } + else + { + Complete(); + } + + m_Inside = true; + } + else + { + m_Inside = false; + } + } + + public override void OnComplete() + { + System.AddObjective( new UseCallingScrollObjective() ); + } + } + + public class UseCallingScrollObjective : QuestObjective + { + public override object Message + { + get + { + /* Use the Scroll of Calling (double click) near the + * Well of Tears to charge the waters for the arrival + * of Kronus. + */ + return 1060130; + } + } + + public UseCallingScrollObjective() + { + } + } + + public class FindMardothEndObjective : QuestObjective + { + private bool m_Victory; + + public override object Message + { + get + { + if ( m_Victory ) + { + /* Victory! You have done as Mardoth has asked of you. + * Take as much of your foe's loot as you can carry + * and return to Mardoth for your reward. + */ + return 1060131; + } + else + { + /* Although you were slain by the cowardly paladin, + * you managed to complete the rite of calling as + * instructed. Return to Mardoth. + */ + return 1060132; + } + } + } + + public FindMardothEndObjective( bool victory ) + { + m_Victory = victory; + } + + // Serialization + public FindMardothEndObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new MardothEndConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Victory = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Victory ); + } + } + + public class FindBankObjective : QuestObjective + { + public override object Message + { + get + { + /* Use the enchanted sextant in your pack to locate + * the nearest bank. Go there and speak with the + * Banker. + */ + return 1060134; + } + } + + public FindBankObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 2048, 1345, -84 ), 5 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddObjective( new CashBankCheckObjective() ); + } + } + + public class CashBankCheckObjective : QuestObjective + { + public override object Message + { + get + { + /* You have arrived at the Bank. Open your bank box + * and then cash the check that Mardoth gave you. + */ + return 1060644; + } + } + + public CashBankCheckObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new BankerConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Conversations.cs b/Scripts/Engines/Quests/Emino's Undertaking/Conversations.cs new file mode 100644 index 0000000..5c982eb --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Conversations.cs @@ -0,0 +1,610 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Important Quest Information

+ * + * During your quest, any important information that a + * NPC gives you, will appear in a + * window such as this one. You can review the information at + * any time during your quest.

Getting Help

+ * + * Some of the text you will come across during your quest, will + * be underlined links to the codex of + * wisdom, or online help system. You can click on the text + * to get detailed information on the underlined subject. You + * may also access the Codex Of Wisdom by pressing "F1" or by + * clicking on the "?" on the toolbar at the top of your screen.

+ * + * Context Menus

Context menus can be called up by + * single left-clicking (or Shift + single left-click, if you + * changed it) on most objects or NPCs in the world. Nearly + * everything, including your own avatar will have context menus + * available. Bringing up your avatar's context menu will give + * you options to cancel your quest and review various quest + * information.

+ */ + return 1049092; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindEminoBeginObjective() ); + } + } + + public class FindZoelConversation : QuestConversation + { + public override object Message + { + get + { + /* Ah, another fledgling unfurls its wings. Welcome to my + * home young one.

+ * + * I am Daimyo Emino, a passionate collector of sorts. + * One who is vengeful towards those impeding my reign.

+ * + * You have the look of someone who could help me but + * your skills are untested. Are you willing to prove + * your mettle as my hireling?

+ * + * Elite Ninja Zoel awaits you in the backyard. He will + * lead you to the first trial. You will be directed + * further when you arrive at your destination. You + * should speak to him before exploring the yard or cave entrance. + */ + return 1063175; + } + } + + public FindZoelConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindZoelObjective() ); + } + } + + public class RadarConversation : QuestConversation + { + public override object Message + { + get + { + /* To view the surrounding area, you should learn about the Radar Map.

+ * + * The Radar Map (or Overhead View) can be opened by pressing 'ALT-R' + * on your keyboard. It shows your immediate surroundings from a + * bird's eye view.

+ * + * Pressing ALT-R twice, will enlarge the Radar Map a little. + * Use the Radar Map often as you travel throughout the world + * to familiarize yourself with your surroundings. + * */ + return 1063033; + } + } + + public override bool Logged{ get{ return false; } } + + public RadarConversation() + { + } + } + + public class EnterCaveConversation : QuestConversation + { + public override object Message + { + get + { + /* Zoel studies your face as you approach him. Wryly, he says:

+ * + * Daimyo Emino has sent another already? The stains from the + * last have not yet dried!

+ * + * No matter, we�ll finish you off and clean it all at once, eh?

+ * + * Now to the point, your only task is to survive in the abandoned inn.

+ * + * You will be instructed when you need to act and when you should + * return to one of us.

+ * + * Only a true Ninja is deft enough to finish and remain alive.

+ * + * Your future... or your demise... lies in this cave beyond.

+ * + * Now go. + */ + return 1063177; + } + } + + public EnterCaveConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new EnterCaveObjective() ); + } + } + + public class SneakPastGuardiansConversation : QuestConversation + { + public override object Message + { + get + { + /* A glowing archway stands before you.

+ * + * To either side of its frame are mounted demon heads, + * breathing fire and watching your every move.

+ * + * To pass through, you must first vanish from the demons� + * sight. Only then can you slowly traverse the entryway. + */ + return 1063180; + } + } + + public SneakPastGuardiansConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SneakPastGuardiansObjective() ); + } + } + + public class NeedToHideConversation : QuestConversation + { + public override object Message + { + get + { + /* You�ll need to hide in order to pass through the door.

+ * + * To find out how to use active skills, visit the + * Codex of Wisdom. + * To activate a skill, locate it on your skills + * list and click the blue button located to the + * left of the skill's name.

Once you have + * successfully hidden, you may move slowly through the door. + * + */ + return 1063181; + } + } + + public NeedToHideConversation() + { + } + } + + public class UseTeleporterConversation : QuestConversation + { + public override object Message + { + get + { + /* + * Through the door lies a short passageway. + * The path ends abruptly at a strange tile on the floor. + * The special tile is known as a teleporter. + * Step on the teleporter tile and you will be transported + * to a new location. + */ + return 1063182; + } + } + + public UseTeleporterConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new UseTeleporterObjective() ); + } + } + + public class GiveZoelNoteConversation : QuestConversation + { + public override object Message + { + get + { + /* Daimyo Emino smiles as you approach him:

+ * + * I see that you have survived both the first trial and Zoel�s temper.

+ * + * For that you have been rewarded with Leggings and Gloves + * befitting your occupation. The material is the only armor + * a True Ninja needs.

+ * + * You have yet to prove yourself fully, young hireling. + * Another trial must be met. Off to Zoel you go. + * Bring him this note so he knows we have spoken. + */ + return 1063184; + } + } + + public GiveZoelNoteConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GiveZoelNoteObjective() ); + } + } + + public class LostNoteConversation : QuestConversation + { + public override object Message + { + get + { + // You have lost my note? I will scribe another for you. Try not to lose this one. + return 1063187; + } + } + + public override bool Logged{ get{ return false; } } + + public LostNoteConversation() + { + } + } + + public class GainInnInformationConversation : QuestConversation + { + public override object Message + { + get + { + /* Zoel quickly grabs the scroll from your + * hand and reads the note:

+ * + * Still alive then? You�ll have to impress me + * further before I will give my approval of + * you to Daimyo Emino.

+ * + * You must return to the inn and begin the next trial.

+ * + * We believe an associate has, shall we say, + * inadvertently negated our contract.

+ * + * Find out what information you can and return + * to Daimyo Emino with the news. And be careful + * not to lose your head.

+ * + * The Blue Teleporter Tile in Daimyo Emino�s + * residence will lead you to your fate. + * I suggest you hurry.

+ * + * ...And take care to tread softly. There + * is no greater traitor than a heavy footfall upon a path. + */ + return 1063189; + } + } + + public GainInnInformationConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GainInnInformationObjective() ); + } + } + + public class ReturnFromInnConversation : QuestConversation + { + public override object Message + { + get + { + /* You quietly approach the door and see + * a woman named Jedah Entille speaking + * to a shady figure in dark clothing. + * You move closer so you can overhear + * the conversation. Fortunately, your + * entrance did not alert the preoccupied party.

+ * + * Jedah�s brash voice permeates the air:

+ * + * Now that it is hidden, we�ll hide out here + * until Daimyo Emino forgets about us. + * Once he realizes his beloved sword is missing, + * he�ll surely start looking for the thieves. + * We will be long gone by that time.


+ * + * After overhearing the conversation, + * you understand why you were sent on + * this trial. You must immediately tell + * Daimyo Emino what you have learned. + * */ + return 1063196; + } + } + + public ReturnFromInnConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnFromInnObjective() ); + } + } + + public class SearchForSwordConversation : QuestConversation + { + public override object Message + { + get + { + /* Daimyo Emino frowns as you relay the information. + * He pauses for a moment before speaking to you:

+ * + * Jedah was once one of my most promising students, + * but her greed will be her downfall.

+ * + * I will send one of my disciples to deal with her later. + * It is more important to get that sword back first.

+ * + * I�m counting on you to find it. She would have kept it + * close to her. Take the White Teleporter, located in my + * backyard, and check inside boxes and chests around the + * treasure room of the inn and return it to me when you + * find it.

+ * + * Be very careful. Jedah was an expert with traps and no + * doubt she�s protecting the sword with them.

+ * + * If you find a trap, try timing it and you may be able + * to avoid damage.

+ * + * I�ve provided you with several heal potions in case you + * become injured.

+ * + * In the bag you will also find more clothing appropriate + * to your new found profession.

+ * + * Please return the sword to me. I implore you not to take + * anything else that may be hidden in the Inn.

+ * + * Thank you. + */ + return 1063199; + } + } + + public SearchForSwordConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SearchForSwordObjective() ); + } + } + + public class HallwayWalkConversation : QuestConversation + { + public override object Message + { + get + { + /* A narrow hallway greets the teleporter. + * The enclosed space is the perfect setting + * for dangerous traps. Walk through the + * hallway being careful to avoid the traps. + * You may be able to time the traps to avoid injury. + */ + return 1063201; + } + } + + public HallwayWalkConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new HallwayWalkObjective() ); + } + } + + public class ReturnSwordConversation : QuestConversation + { + public override object Message + { + get + { + /* The lid of the chest refuses to budge at first, + * but slowly you are able to pry the lid open.

+ * + * Inside lies the sword you have been in search of. + * You quickly take the sword and stash it in your backpack. + * Bring the sword back to Daimyo Emino. + */ + return 1063203; + } + } + + public ReturnSwordConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnSwordObjective() ); + } + } + + public class SlayHenchmenConversation : QuestConversation + { + public override object Message + { + get + { + /* Screams echo through the chamber as you walk + * away from the chest. Jedah�s Henchmen have + * become cognizant of your presence.

+ * + * It is time for your Ninja Spirit to come alive. + * Slay 3 of the Henchmen before returning to Daimyo Emino. + */ + return 1063205; + } + } + + public SlayHenchmenConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SlayHenchmenObjective() ); + } + } + + public class ContinueSlayHenchmenConversation : QuestConversation + { + public override object Message + { + get + { + // Continue killing the henchmen! + return 1063208; + } + } + + public override bool Logged{ get{ return false; } } + + public ContinueSlayHenchmenConversation() + { + } + } + + public class GiveEminoSwordConversation : QuestConversation + { + public override object Message + { + get + { + /* Go to Daimyo Emino. Go back through the chamber the way you came.

+ * + * Give Daimyo Emino the sword when you've returned to his side. + */ + return 1063211; + } + } + + public GiveEminoSwordConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GiveEminoSwordObjective() ); + } + } + + public class LostSwordConversation : QuestConversation + { + public override object Message + { + get + { + // What? You have returned without the sword? You need to go back and get it again! + return 1063212; + } + } + + public override bool Logged{ get{ return false; } } + + public LostSwordConversation() + { + } + } + + public class EarnGiftsConversation : QuestConversation + { + public override object Message + { + get + { + /* Beyond this path lies Zento City, your future home. + * To the right of the cave entrance you will find a luminous oval + * object known as a Moongate, step through it and you'll + * find yourself in Zento.

+ * + * You may want to visit Ansella Gryen when you arrive.

+ * + * Please accept the gifts I have placed in your pack. You + * have earned them. Farewell for now. + */ + return 1063216; + } + } + + public EarnGiftsConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class EarnLessGiftsConversation : QuestConversation + { + public override object Message + { + get + { + /* You have earned these gifts for returning the sword. + * For that I thank you.

+ * + * However, your reward has been lessened by your greed + * in the treasure room. Do not think I did not notice your full pockets. + */ + return 1063217; + } + } + + public EarnLessGiftsConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/EminosUndertakingQuest.cs b/Scripts/Engines/Quests/Emino's Undertaking/EminosUndertakingQuest.cs new file mode 100644 index 0000000..0fd684e --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/EminosUndertakingQuest.cs @@ -0,0 +1,159 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class EminosUndertakingQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Ninja.AcceptConversation ), + typeof( Ninja.FindZoelConversation ), + typeof( Ninja.RadarConversation ), + typeof( Ninja.EnterCaveConversation ), + typeof( Ninja.SneakPastGuardiansConversation ), + typeof( Ninja.NeedToHideConversation ), + typeof( Ninja.UseTeleporterConversation ), + typeof( Ninja.GiveZoelNoteConversation ), + typeof( Ninja.LostNoteConversation ), + typeof( Ninja.GainInnInformationConversation ), + typeof( Ninja.ReturnFromInnConversation ), + typeof( Ninja.SearchForSwordConversation ), + typeof( Ninja.HallwayWalkConversation ), + typeof( Ninja.ReturnSwordConversation ), + typeof( Ninja.SlayHenchmenConversation ), + typeof( Ninja.ContinueSlayHenchmenConversation ), + typeof( Ninja.GiveEminoSwordConversation ), + typeof( Ninja.LostSwordConversation ), + typeof( Ninja.EarnGiftsConversation ), + typeof( Ninja.EarnLessGiftsConversation ), + typeof( Ninja.FindEminoBeginObjective ), + typeof( Ninja.FindZoelObjective ), + typeof( Ninja.EnterCaveObjective ), + typeof( Ninja.SneakPastGuardiansObjective ), + typeof( Ninja.UseTeleporterObjective ), + typeof( Ninja.GiveZoelNoteObjective ), + typeof( Ninja.GainInnInformationObjective ), + typeof( Ninja.ReturnFromInnObjective ), + typeof( Ninja.SearchForSwordObjective ), + typeof( Ninja.HallwayWalkObjective ), + typeof( Ninja.ReturnSwordObjective ), + typeof( Ninja.SlayHenchmenObjective ), + typeof( Ninja.GiveEminoSwordObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // Emino's Undertaking + return 1063173; + } + } + + public override object OfferMessage + { + get + { + // Your value as a Ninja must be proven. Find Daimyo Emino and accept the test he offers. + return 1063174; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.MaxValue; } } + public override bool IsTutorial{ get{ return true; } } + + public override int Picture{ get{ return 0x15D5; } } + + public EminosUndertakingQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public EminosUndertakingQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + private bool m_SentRadarConversion; + + public override void Slice() + { + if ( !m_SentRadarConversion && ( From.Map != Map.Malas || From.X < 407 || From.X > 431 || From.Y < 801 || From.Y > 830 ) ) + { + m_SentRadarConversion = true; + AddConversation( new RadarConversation() ); + } + + base.Slice(); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_SentRadarConversion = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_SentRadarConversion ); + } + + public static bool HasLostNoteForZoel( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is EminosUndertakingQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( GiveZoelNoteObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( NoteForZoel ) ) == null ); + } + } + + return false; + } + + public static bool HasLostEminosKatana( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is EminosUndertakingQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( GiveEminoSwordObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( EminosKatana ) ) == null ); + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/BlueNinjaQuestTeleporter.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/BlueNinjaQuestTeleporter.cs new file mode 100644 index 0000000..ce49b1e --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/BlueNinjaQuestTeleporter.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class BlueNinjaQuestTeleporter : DynamicTeleporter + { + public override int LabelNumber{ get{ return 1026157; } } // teleporter + + [Constructable] + public BlueNinjaQuestTeleporter() : base( 0x51C, 0x2 ) + { + } + + public override int NotWorkingMessage{ get{ return 1063198; } } // You stand on the strange floor tile but nothing happens. + + public override bool GetDestination( PlayerMobile player, ref Point3D loc, ref Map map ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest && qs.FindObjective( typeof( GainInnInformationObjective ) ) != null ) + { + loc = new Point3D( 411, 1116, 0 ); + map = Map.Malas; + + return true; + } + + return false; + } + + public BlueNinjaQuestTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/EminosKatana.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/EminosKatana.cs new file mode 100644 index 0000000..16d86d5 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/EminosKatana.cs @@ -0,0 +1,48 @@ +using System; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Ninja +{ + public class EminosKatana : QuestItem + { + public override int LabelNumber{ get{ return 1063214; } } // Daimyo Emino's Katana + + [Constructable] + public EminosKatana() : base( 0x13FF ) + { + Weight = 1.0; + } + + public EminosKatana( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + EminosUndertakingQuest qs = player.Quest as EminosUndertakingQuest; + + if ( qs == null ) + return true; + + /*return !qs.IsObjectiveInProgress( typeof( ReturnSwordObjective ) ) + && !qs.IsObjectiveInProgress( typeof( SlayHenchmenObjective ) ) + && !qs.IsObjectiveInProgress( typeof( GiveEminoSwordObjective ) );*/ + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/EminosKatanaChest.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/EminosKatanaChest.cs new file mode 100644 index 0000000..f0c4a95 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/EminosKatanaChest.cs @@ -0,0 +1,148 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.Quests.Ninja +{ + public class EminosKatanaChest : WoodenChest + { + [Constructable] + public EminosKatanaChest() + { + Movable = false; + ItemID = 0xE42; + + GenerateTreasure(); + } + + public EminosKatanaChest( Serial serial ) : base( serial ) + { + } + + public override bool IsDecoContainer{ get{ return false; } } + + private void GenerateTreasure() + { + for ( int i = this.Items.Count - 1; i >= 0; i-- ) + this.Items[i].Delete(); + + for ( int i = 0; i < 75; i++ ) + { + switch ( Utility.Random( 3 ) ) + { + case 0: DropItem( new GoldBracelet() ); break; + case 1: DropItem( new GoldRing() ); break; + case 2: DropItem( Loot.RandomGem() ); break; + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.InRange( GetWorldLocation(), 2 ) ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest ) + { + if ( EminosUndertakingQuest.HasLostEminosKatana( from ) ) + { + Item katana = new EminosKatana(); + + if ( !player.PlaceInBackpack( katana ) ) + { + katana.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + else + { + QuestObjective obj = qs.FindObjective( typeof( HallwayWalkObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item katana = new EminosKatana(); + + if ( player.PlaceInBackpack( katana ) ) + { + GenerateTreasure(); + obj.Complete(); + } + else + { + katana.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + } + } + } + + base.OnDoubleClick( from ); + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + return false; + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + return item == this; + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.Quest is EminosUndertakingQuest ) + { + HallwayWalkObjective obj = player.Quest.FindObjective( typeof( HallwayWalkObjective ) ) as HallwayWalkObjective; + + if ( obj != null ) + { + if ( obj.StolenTreasure ) + from.SendLocalizedMessage( 1063247 ); // The guard is watching you carefully! It would be unwise to remove another item from here. + else + return true; + } + } + + return false; + } + + public override void OnItemLifted( Mobile from, Item item ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.Quest is EminosUndertakingQuest ) + { + HallwayWalkObjective obj = player.Quest.FindObjective( typeof( HallwayWalkObjective ) ) as HallwayWalkObjective; + + if ( obj != null ) + obj.StolenTreasure = true; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/GreenNinjaQuestTeleporter.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/GreenNinjaQuestTeleporter.cs new file mode 100644 index 0000000..0637e11 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/GreenNinjaQuestTeleporter.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class GreenNinjaQuestTeleporter : DynamicTeleporter + { + public override int LabelNumber{ get{ return 1026157; } } // teleporter + + [Constructable] + public GreenNinjaQuestTeleporter() : base( 0x51C, 0x17E ) + { + } + + public override int NotWorkingMessage{ get{ return 1063198; } } // You stand on the strange floor tile but nothing happens. + + public override bool GetDestination( PlayerMobile player, ref Point3D loc, ref Map map ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest && qs.FindObjective( typeof( UseTeleporterObjective ) ) != null ) + { + loc = new Point3D( 410, 1125, 0 ); + map = Map.Malas; + + return true; + } + + return false; + } + + public GreenNinjaQuestTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/GuardianBarrier.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/GuardianBarrier.cs new file mode 100644 index 0000000..f953c56 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/GuardianBarrier.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class GuardianBarrier : Item + { + [Constructable] + public GuardianBarrier() : base( 0x3967 ) + { + Movable = false; + Visible = false; + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m.AccessLevel > AccessLevel.Player ) + return true; + + // If the mobile is to the north of the barrier, allow him to pass + if ( this.Y >= m.Y ) + return true; + + if ( m is BaseCreature ) + { + Mobile master = ((BaseCreature)m).GetMaster(); + + // Allow creatures to cross from the south to the north only if their master is near to the north + if ( master != null && this.Y >= master.Y && master.InRange( this, 4 ) ) + return true; + else + return false; + } + + PlayerMobile pm = m as PlayerMobile; + + if ( pm != null ) + { + EminosUndertakingQuest qs = pm.Quest as EminosUndertakingQuest; + + if ( qs != null ) + { + SneakPastGuardiansObjective obj = qs.FindObjective( typeof( SneakPastGuardiansObjective ) ) as SneakPastGuardiansObjective; + + if ( obj != null ) + { + if ( m.Hidden ) + return true; // Hidden ninjas can pass + + if ( !obj.TaughtHowToUseSkills ) + { + obj.TaughtHowToUseSkills = true; + qs.AddConversation( new NeedToHideConversation() ); + } + } + } + } + + return false; + } + + public GuardianBarrier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/NoteForZoel.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/NoteForZoel.cs new file mode 100644 index 0000000..3df1ea3 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/NoteForZoel.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Ninja +{ + public class NoteForZoel : QuestItem + { + public override int LabelNumber{ get{ return 1063186; } } // A Note for Zoel + + [Constructable] + public NoteForZoel() : base( 0x14EF ) + { + Weight = 1.0; + Hue = 0x6B9; + } + + public NoteForZoel( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + EminosUndertakingQuest qs = player.Quest as EminosUndertakingQuest; + + if ( qs == null ) + return true; + + //return !qs.IsObjectiveInProgress( typeof( GiveZoelNoteObjective ) ); + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Items/WhiteNinjaQuestTeleporter.cs b/Scripts/Engines/Quests/Emino's Undertaking/Items/WhiteNinjaQuestTeleporter.cs new file mode 100644 index 0000000..f36f7d1 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Items/WhiteNinjaQuestTeleporter.cs @@ -0,0 +1,59 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class WhiteNinjaQuestTeleporter : DynamicTeleporter + { + public override int LabelNumber{ get{ return 1026157; } } // teleporter + + [Constructable] + public WhiteNinjaQuestTeleporter() : base( 0x51C, 0x47E ) + { + } + + public override int NotWorkingMessage{ get{ return 1063198; } } // You stand on the strange floor tile but nothing happens. + + public override bool GetDestination( PlayerMobile player, ref Point3D loc, ref Map map ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SearchForSwordObjective ) ); + + if ( obj != null ) + { + if ( !obj.Completed ) + obj.Complete(); + + loc = new Point3D( 411, 1085, 0 ); + map = Map.Malas; + + return true; + } + } + + return false; + } + + public WhiteNinjaQuestTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Emino.cs b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Emino.cs new file mode 100644 index 0000000..42f07a3 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Emino.cs @@ -0,0 +1,227 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.Quests.Ninja +{ + public class Emino : BaseQuester + { + [Constructable] + public Emino() : base( "the Notorious" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83FE; + + Female = false; + Body = 0x190; + Name = "Daimyo Emino"; + } + + public override void InitOutfit() + { + HairItemID = 0x203B; + HairHue = 0x901; + + AddItem( new MaleKimono() ); + AddItem( new SamuraiTabi() ); + AddItem( new Bandana() ); + + AddItem( new PlateHaidate() ); + AddItem( new PlateDo() ); + AddItem( new PlateHiroSode() ); + + Nunchaku nunchaku = new Nunchaku(); + nunchaku.Movable = false; + AddItem( nunchaku ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 2; + } + + public override int TalkNumber{ get { return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest ) + { + if ( EminosUndertakingQuest.HasLostNoteForZoel( player ) ) + { + Item note = new NoteForZoel(); + + if ( player.PlaceInBackpack( note ) ) + { + qs.AddConversation( new LostNoteConversation() ); + } + else + { + note.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + else if ( EminosUndertakingQuest.HasLostEminosKatana( player ) ) + { + qs.AddConversation( new LostSwordConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( FindEminoBeginObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else + { + obj = qs.FindObjective( typeof( UseTeleporterObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item note = new NoteForZoel(); + + if ( player.PlaceInBackpack( note ) ) + { + obj.Complete(); + + player.AddToBackpack( new LeatherNinjaPants() ); + player.AddToBackpack( new LeatherNinjaMitts() ); + } + else + { + note.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + else + { + obj = qs.FindObjective( typeof( ReturnFromInnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + for ( int i = 0; i < 10; i++ ) + cont.DropItem( new LesserHealPotion() ); + + cont.DropItem( new LeatherNinjaHood() ); + cont.DropItem( new LeatherNinjaJacket() ); + + if ( player.PlaceInBackpack( cont ) ) + { + obj.Complete(); + } + else + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + else + { + if ( qs.IsObjectiveInProgress( typeof( SlayHenchmenObjective ) ) ) + { + qs.AddConversation( new ContinueSlayHenchmenConversation() ); + } + else + { + obj = qs.FindObjective( typeof( GiveEminoSwordObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item katana = null; + + if ( player.Backpack != null ) + katana = player.Backpack.FindItemByType( typeof( EminosKatana ) ); + + if ( katana != null ) + { + bool stolenTreasure = false; + + HallwayWalkObjective walk = qs.FindObjective( typeof( HallwayWalkObjective ) ) as HallwayWalkObjective; + if ( walk != null ) + stolenTreasure = walk.StolenTreasure; + + Kama kama = new Kama(); + + if ( stolenTreasure ) + BaseRunicTool.ApplyAttributesTo( kama, 1, 10, 20 ); + else + BaseRunicTool.ApplyAttributesTo( kama, 1, 10, 30 ); + + if ( player.PlaceInBackpack( kama ) ) + { + katana.Delete(); + obj.Complete(); + + if ( stolenTreasure ) + qs.AddConversation( new EarnLessGiftsConversation() ); + else + qs.AddConversation( new EarnGiftsConversation() ); + } + else + { + kama.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + } + } + } + } + } + } + } + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( !m.Frozen && !m.Alive && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && InLOS( m ) ) + { + if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + else + { + Direction = GetDirectionTo( m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.Healer ) ); + } + } + } + + public Emino( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/EnshroudedFigure.cs b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/EnshroudedFigure.cs new file mode 100644 index 0000000..d6c9d61 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/EnshroudedFigure.cs @@ -0,0 +1,56 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; + +namespace Server.Engines.Quests.Ninja +{ + public class EnshroudedFigure : BaseQuester + { + [Constructable] + public EnshroudedFigure() + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x8401; + Female = false; + Body = 0x190; + Name = "enshrouded figure"; + } + + public override void InitOutfit() + { + AddItem( new DeathShroud() ); + AddItem( new ThighBoots() ); + } + + public override int TalkNumber{ get{ return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public EnshroudedFigure( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Henchman.cs b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Henchman.cs new file mode 100644 index 0000000..f930e63 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Henchman.cs @@ -0,0 +1,55 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Ninja +{ + public class Henchman : BaseCreature + { + [Constructable] + public Henchman() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + InitStats( 45, 30, 5 ); + + Hue = Utility.RandomSkinHue(); + Body = 0x190; + Name = "a henchman"; + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this ); + + AddItem( new LeatherNinjaJacket() ); + AddItem( new LeatherNinjaPants() ); + AddItem( new NinjaTabi() ); + + if ( Utility.RandomBool() ) + AddItem( new Kama() ); + else + AddItem( new Tessen() ); + + SetSkill( SkillName.Swords, 50.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public Henchman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/HiddenFigure.cs b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/HiddenFigure.cs new file mode 100644 index 0000000..f071104 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/HiddenFigure.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; + +namespace Server.Engines.Quests.Ninja +{ + public class HiddenFigure : BaseQuester + { + public static int[] Messages = new int[] + { + 1063191, // They won�t find me here. + 1063192 // Ah, a quiet hideout. + }; + + private int m_Message; + + [CommandProperty( AccessLevel.GameMaster )] + public int Message{ get{ return m_Message; } set{ m_Message = value; } } + + [Constructable] + public HiddenFigure() + { + m_Message = Utility.RandomList( Messages ); + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = Utility.RandomSkinHue(); + + Female = Utility.RandomBool(); + + if ( Female ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + } + + public override void InitOutfit() + { + Utility.AssignRandomHair( this ); + + AddItem( new TattsukeHakama( GetRandomHue() ) ); + AddItem( new Kasa() ); + AddItem( new HakamaShita( GetRandomHue() ) ); + + if ( Utility.RandomBool() ) + AddItem( new Shoes( GetShoeHue() ) ); + else + AddItem( new Sandals( GetShoeHue() ) ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 3; + } + + public override int TalkNumber{ get{ return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + PrivateOverheadMessage( MessageType.Regular, 0x3B2, m_Message, player.NetState ); + } + + public HiddenFigure( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_Message ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Message = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/JedahEntille.cs b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/JedahEntille.cs new file mode 100644 index 0000000..54fe30a --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/JedahEntille.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; + +namespace Server.Engines.Quests.Ninja +{ + public class JedahEntille : BaseQuester + { + [Constructable] + public JedahEntille() : base( "the Silent" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83FE; + Female = true; + Body = 0x191; + Name = "Jedah Entille"; + } + + public override void InitOutfit() + { + HairItemID = 0x203C; + HairHue = 0x6BE; + + AddItem( new PlainDress( 0x528 ) ); + AddItem( new ThighBoots() ); + AddItem( new FloppyHat() ); + } + + public override int TalkNumber{ get{ return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public JedahEntille( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Zoel.cs b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Zoel.cs new file mode 100644 index 0000000..e77f3df --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Mobiles/Zoel.cs @@ -0,0 +1,138 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Ninja +{ + public class Zoel : BaseQuester + { + [Constructable] + public Zoel() : base( "the Masterful Tactician" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83FE; + + Female = false; + Body = 0x190; + Name = "Elite Ninja Zoel"; + } + + public override void InitOutfit() + { + HairItemID = 0x203B; + HairHue = 0x901; + + AddItem( new HakamaShita( 0x1 ) ); + AddItem( new NinjaTabi() ); + AddItem( new TattsukeHakama() ); + AddItem( new Bandana() ); + + AddItem( new LeatherNinjaBelt() ); + + Tekagi tekagi = new Tekagi(); + tekagi.Movable = false; + AddItem( tekagi ); + } + + public override int TalkNumber{ get { return -1; } } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 2; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return to.Quest is EminosUndertakingQuest; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FindZoelObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is EminosUndertakingQuest ) + { + if ( dropped is NoteForZoel ) + { + QuestObjective obj = qs.FindObjective( typeof( GiveZoelNoteObjective ) ); + + if ( obj != null && !obj.Completed ) + { + dropped.Delete(); + obj.Complete(); + return true; + } + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( !m.Frozen && !m.Alive && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && InLOS( m ) ) + { + if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + else + { + Direction = GetDirectionTo( m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.Healer ) ); + } + } + } + + public Zoel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Emino's Undertaking/Objectives.cs b/Scripts/Engines/Quests/Emino's Undertaking/Objectives.cs new file mode 100644 index 0000000..7006793 --- /dev/null +++ b/Scripts/Engines/Quests/Emino's Undertaking/Objectives.cs @@ -0,0 +1,393 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Ninja +{ + public class FindEminoBeginObjective : QuestObjective + { + public override object Message + { + get + { + // Your value as a Ninja must be proven. Find Daimyo Emino and accept the test he offers. + return 1063174; + } + } + + public FindEminoBeginObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FindZoelConversation() ); + } + } + + public class FindZoelObjective : QuestObjective + { + public override object Message + { + get + { + // Find Elite Ninja Zoel immediately! + return 1063176; + } + } + + public FindZoelObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new EnterCaveConversation() ); + } + } + + public class EnterCaveObjective : QuestObjective + { + public override object Message + { + get + { + // Enter the cave and walk through it. You will be tested as you travel along the path. + return 1063179; + } + } + + public EnterCaveObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 406, 1141, 0 ), 2 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddConversation( new SneakPastGuardiansConversation() ); + } + } + + public class SneakPastGuardiansObjective : QuestObjective + { + private bool m_TaughtHowToUseSkills; + + public bool TaughtHowToUseSkills + { + get{ return m_TaughtHowToUseSkills; } + set{ m_TaughtHowToUseSkills = value; } + } + + public override object Message + { + get + { + // Use your Ninja training to move invisibly past the magical guardians. + return 1063261; + } + } + + public SneakPastGuardiansObjective() + { + } + + public override void CheckProgress() + { + if ( System.From.Map == Map.Malas && System.From.InRange( new Point3D( 412, 1123, 0 ), 3 ) ) + Complete(); + } + + public override void OnComplete() + { + System.AddConversation( new UseTeleporterConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_TaughtHowToUseSkills = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_TaughtHowToUseSkills ); + } + } + + public class UseTeleporterObjective : QuestObjective + { + public override object Message + { + get + { + /* The special tile is known as a teleporter. + * Step on the teleporter tile and you will be transported to a new location. + */ + return 1063183; + } + } + + public UseTeleporterObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new GiveZoelNoteConversation() ); + } + } + + public class GiveZoelNoteObjective : QuestObjective + { + public override object Message + { + get + { + /* Bring the note to Elite Ninja Zoel and speak with him again. + * He is near the cave entrance. You can hand the note to Zoel + * by dragging it and dropping it on his body. + */ + return 1063185; + } + } + + public GiveZoelNoteObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new GainInnInformationConversation() ); + } + } + + public class GainInnInformationObjective : QuestObjective + { + public override object Message + { + get + { + /* Take the Blue Teleporter Tile from Daimyo Emino's + * house to the Abandoned Inn. Quietly look around + * to gain information. + */ + return 1063190; + } + } + + public GainInnInformationObjective() + { + } + + public override void CheckProgress() + { + Mobile from = System.From; + + if ( from.Map == Map.Malas && from.X > 399 && from.X < 408 && from.Y > 1091 && from.Y < 1099 ) + Complete(); + } + + public override void OnComplete() + { + System.AddConversation( new ReturnFromInnConversation() ); + } + } + + public class ReturnFromInnObjective : QuestObjective + { + public override object Message + { + get + { + // Go back through the blue teleporter and tell Daimyo Emino what you�ve overheard. + return 1063197; + } + } + + public ReturnFromInnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new SearchForSwordConversation() ); + } + } + + public class SearchForSwordObjective : QuestObjective + { + public override object Message + { + get + { + /* Take the white teleporter and check the chests for the sword. + * Leave everything else behind. Avoid damage from traps you may + * encounter. To use a potion, make sure at least one hand is + * free and double click on the bottle. + */ + return 1063200; + } + } + + public SearchForSwordObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new HallwayWalkConversation() ); + } + } + + public class HallwayWalkObjective : QuestObjective + { + private bool m_StolenTreasure; + + public bool StolenTreasure + { + get{ return m_StolenTreasure; } + set{ m_StolenTreasure = value; } + } + + public override object Message + { + get + { + /* Walk through the hallway being careful + * to avoid the traps. You may be able to + * time the traps to avoid injury. + */ + return 1063202; + } + } + + public HallwayWalkObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ReturnSwordConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_StolenTreasure = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_StolenTreasure ); + } + } + + public class ReturnSwordObjective : QuestObjective + { + public override object Message + { + get + { + // Take the sword and bring it back to Daimyo Emino. + return 1063204; + } + } + + public ReturnSwordObjective() + { + } + + public override void CheckProgress() + { + Mobile from = System.From; + + if ( from.Map != Map.Malas || from.Y > 992 ) + Complete(); + } + + public override void OnComplete() + { + System.AddConversation( new SlayHenchmenConversation() ); + } + } + + public class SlayHenchmenObjective : QuestObjective + { + public override object Message + { + get + { + // Kill three henchmen. + return 1063206; + } + } + + public SlayHenchmenObjective() + { + } + + public override int MaxProgress{ get{ return 3; } } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Henchmen killed: + gump.AddHtmlLocalized( 70, 260, 270, 100, 1063207, BaseQuestGump.Blue, false, false ); + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, MaxProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is Henchman ) + CurProgress++; + } + + public override void OnComplete() + { + System.AddConversation( new GiveEminoSwordConversation() ); + } + } + + public class GiveEminoSwordObjective : QuestObjective + { + public override object Message + { + get + { + /* You have proven your fighting skills. Bring the Sword to + * Daimyo Emino immediately. Be sure to follow the + * path back to the teleporter. + */ + return 1063210; + } + } + + public GiveEminoSwordObjective() + { + } + + public override void OnComplete() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Conversations.cs b/Scripts/Engines/Quests/Haochi's Trials/Conversations.cs new file mode 100644 index 0000000..5dc4801 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Conversations.cs @@ -0,0 +1,713 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Important Quest Information

+ * + * During your quest, any important information that a + * NPC gives you, will appear in a window + * such as this one. You can review the information at any time during your + * quest.

+ * + * Getting Help

+ * + * Some of the text you will come across during your quest, + * will be underlined links to the codex of wisdom, + * or online help system. You can click on the text to get detailed information + * on the underlined subject. You may also access the Codex Of Wisdom by + * pressing "F1" or by clicking on the "?" on the toolbar at the top of + * your screen.

Context Menus

+ * + * Context menus can be called up by single left-clicking (or Shift + single + * left-click, if you changed it) on most objects or NPCs in the world. + * Nearly everything, including your own avatar will have context menus available. + * Bringing up your avatar's context menu will give you options to cancel your quest + * and review various quest information.

+ */ + return 1049092; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindHaochiObjective() ); + } + } + + public class RadarConversation : QuestConversation + { + public override object Message + { + get + { + /* To view the surrounding area, you should learn about the Radar Map.

+ * + * The Radar Map (or Overhead View) can be opened by pressing 'ALT-R' + * on your keyboard. It shows your immediate surroundings from a + * bird's eye view.

+ * + * Pressing ALT-R twice, will enlarge the Radar Map a little. + * Use the Radar Map often as you travel throughout the world + * to familiarize yourself with your surroundings. + * */ + return 1063033; + } + } + + public override bool Logged{ get{ return false; } } + + public RadarConversation() + { + } + } + + public class FirstTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + /* Greetings. I am Daimyo Haochi, the Feudal Lord of this region.

+ * + * Since you are here at my side, you must wish to learn the ways of the Samurai.

+ * + * Wielding a blade is easy, anyone can grasp a sword�s hilt. Learning how to + * fight properly and skillfully is to become an Armsman.

+ * + * Learning how to master weapons, and even more importantly when not to use + * them, is the Way of the Warrior. The Way of the Samurai. The Code of the + * Bushido. That is why you are here.

+ * + * You will go through 7 trials to prove your adherence to the Samurai code.

+ * + * The first trial will test your decision making skills. You only have to enter + * the area beyond the green passageway.

+ * + * Do not attempt to hurry your trials. The guards will only let you through + * to each trial when I have deemed you ready.

+ * + * As a last resort you may use the golden teleporter tiles in each trial area + * but do so at your own risk. You may not be able to return and complete your + * trials once you have chosen to escape. + */ + return 1063029; + } + } + + public FirstTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FirstTrialIntroObjective() ); + } + } + + public class FirstTrialKillConversation : QuestConversation + { + public override object Message + { + get + { + /* Beyond you are two troubled groups.

+ * + * The Cursed Souls were once proud warriors that were ensorcelled + * by an evil mage. The mage trapped and killed them later but the spell + * has not lifted from their souls in death.

+ * + * The Young Ronin were former Samurai in training who lost their way. + * They are loyal only to those with enough coin in their pocket.

+ * + * You must decide who needs to be fought to the death. You may wish to + * review combat techniques as well as + * information on healing yourself.

+ * + * Return to Daimyo Haochi after you have finished with your trial.

+ * + * If you should die during any of your trials, visit one of the Ankh Shrines + * and you will be resurrected. You should retrieve your belongings from your + * body before returning to the Daimyo or you may not be able to return to your corpse. + */ + return 1063031; + } + } + + public FirstTrialKillConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FirstTrialKillObjective() ); + } + } + + public class GainKarmaConversation : QuestConversation + { + public override object Message + { + get + { + if ( m_CursedSoul ) + { + // You have just gained some Karma for killing a Cursed Soul. + return 1063040; + } + else + { + // You have just gained some Karma for killing a Young Ronin. + return 1063041; + } + } + } + + public override bool Logged{ get{ return false; } } + + private bool m_CursedSoul; + + public GainKarmaConversation( bool cursedSoul ) + { + m_CursedSoul = cursedSoul; + } + + public GainKarmaConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_CursedSoul = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_CursedSoul ); + } + } + + public class SecondTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + if ( m_CursedSoul ) + { + /* It is good that you rid the land of the Cursed Souls so they can + * be at peace in death. They had been cursed for doing what they + * thought was an honorable deed. Now they can have respect in their death.

+ * + * I have placed a reward in your pack.

+ * + * The second trial will test your courage. You only have to follow the yellow + * path to see what awaits you. + */ + return 1063045; + } + else + { + /* It is good that you rid the land of those dishonorable Samurai. + * Perhaps they will learn a greater lesson in death.

+ * + * I have placed a reward in your pack.

+ * + * The second trial will test your courage. You only have to follow + * the yellow path to see what awaits you. + */ + return 1063046; + } + } + } + + private bool m_CursedSoul; + + public SecondTrialIntroConversation( bool cursedSoul ) + { + m_CursedSoul = cursedSoul; + } + + public SecondTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SecondTrialIntroObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_CursedSoul = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_CursedSoul ); + } + } + + public class SecondTrialAttackConversation : QuestConversation + { + public override object Message + { + get + { + /* Beyond the guards is a test of courage. You must face your fear and attack a + * great beast. You must choose which beast to slay for there is more than + * one beyond the courtyard doors.

+ * + * The imp entered the courtyard unaware of its surroundings. The dragon came + * knowingly, hunting for the flesh of humans � A feast for the beast.

+ * + * You must rid the courtyard of these beasts but you may only choose one to + * attack. Go and choose wisely. + */ + return 1063057; + } + } + + public SecondTrialAttackConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SecondTrialAttackObjective() ); + } + } + + public class ThirdTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + if ( m_Dragon ) + { + /* You faced the dragon knowing it would be your certain death. + * That is the courage of a Samurai.

+ * + * Your spirit speaks as a Samurai already.

+ * + * In these lands, death is not forever. The shrines can make you whole + * again as can a helpful mage or healer.

+ * + * Seek them out when you have been mortally wounded.

+ * + * The next trial will test your benevolence. You only have to walk the blue path. + */ + return 1063060; + } + else + { + /* Fear remains in your eyes but you have learned that not all is + * what it appears to be.

+ * + * You must have known the dragon would slay you instantly. + * You elected the weaker opponent though the imp did not come + * here to destroy. You have much to learn.

+ * + * In these lands, death is not forever. The shrines can make you whole + * again as can a helpful mage or healer.

+ * + * Seek them out when you have been mortally wounded.

+ * + * The next trial will test your benevolence. You only have to walk the blue path. + */ + return 1063059; + } + } + } + + private bool m_Dragon; + + public ThirdTrialIntroConversation( bool dragon ) + { + m_Dragon = dragon; + } + + public ThirdTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ThirdTrialIntroObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Dragon = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Dragon ); + } + } + + public class ThirdTrialKillConversation : QuestConversation + { + public override object Message + { + get + { + /* A pack of wolves circle your feet. They have been injured and are in pain. + * A quick death will end their suffering.

+ * + * Use your Honorable Execution skill or other means to finish off a wounded wolf. + * Do so and return to Daimyo Haochi. + */ + return 1063062; + } + } + + public ThirdTrialKillConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ThirdTrialKillObjective() ); + } + } + + public class FourthTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + /* Daimyo Haochi smiles as you walk up to him. Quietly he says:

+ * + * A Samurai understands the need to help others even as he wields a blade against + * them.

+ * + * You have shown compassion. A true Samurai is benevolent even to an enemy. + * For this you have been rewarded.

+ * + * And now you must prove yourself again. Walk the red path. + * We will talk again later. + */ + return 1063065; + } + } + + public FourthTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FourthTrialIntroObjective() ); + } + } + + public class FourthTrialCatsConversation : QuestConversation + { + public override object Message + { + get + { + /* You approach a disheveled gypsy standing near a small shed. + * You sense that she has not eaten nor bathed in quite some time.

+ * + * Around her is a large colony of mangy and diseased cats. It appears + * she has spent what little money she�s earned to feed the cats instead + * of herself.

+ * + * You have a decision to make. You can give her gold so she can buy some + * food for her animals and herself. You can also remove the necessity + * of the extra mouths to feed so she may concentrate on saving herself.


+ * + * If you elect to give the gypsy money, you can do so by clicking your stack + * of gold and selecting �1�. Then dragging it and dropping it on the Gypsy. + */ + return 1063067; + } + } + + public FourthTrialCatsConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FourthTrialCatsObjective() ); + } + } + + public class FifthTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + if ( m_KilledCat ) + { + /* Respect comes from allowing another to make their own decisions. + * By denying the gypsy her animals, you negate the respect she is due. + * Perhaps you will have learned something to use next time a similar + * situation arises.

+ * + * And now you must prove yourself again. Please retrieve my katana + * from the treasure room and return it to me. + */ + return 1063071; + } + else + { + /* You showed respect by helping another out while allowing the gypsy + * what little dignity she has left.

+ * + * Now she will be able to feed herself and gain enough energy to walk + * to her camp.

+ * + * The cats are her family members� cursed by an evil mage.

+ * + * Once she has enough strength to walk back to the camp, she will be + * able to undo the spell.

+ * + * You have been rewarded for completing your trial. And now you must + * prove yourself again.

Please retrieve my katana from the + * treasure room and return it to me. + */ + return 1063070; + } + } + } + + private bool m_KilledCat; + + public FifthTrialIntroConversation( bool killedCat ) + { + m_KilledCat = killedCat; + } + + public FifthTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FifthTrialIntroObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_KilledCat = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_KilledCat ); + } + } + + public class FifthTrialReturnConversation : QuestConversation + { + public override object Message + { + get + { + /* The guards let you through without question, and pay you no mind as + * you walk into the Daimyo's treasure cache. A vast fortune in gold, + * gemstones, and jewelry is stored here! Surely, the Daimyo wouldn't + * miss a single small item...

+ * + * You spot the sword quickly amongst the cache of gemstones and other valuables. + * In one quick motion you retrieve it and stash it in your pack.
+ */ + return 1063248; + } + } + + public FifthTrialReturnConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FifthTrialReturnObjective() ); + } + } + + public class LostSwordConversation : QuestConversation + { + public override object Message + { + get + { + // What? You have returned without the sword? Go back and look for it again. + return 1063074; + } + } + + public override bool Logged{ get{ return false; } } + + public LostSwordConversation() + { + } + } + + public class SixthTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + if ( m_StolenTreasure ) + { + /* I thank you for returning this sword. However, you should admonished + * for also taking treasure that was not asked for nor given back.

+ * + * Think about your actions youngling.

+ * + * Your training is nearly complete. Before you have your final trial, + * you should pay homage to Samurai who came before you.

+ * + * Go into the Altar Room and light a candle for them. + * Afterwards, return to me. + */ + return 1063077; + } + else + { + /* Thank you for returning this sword to me and leaving the remaining + * treasure alone.

+ * + * Your training is nearly complete. Before you have your final trial, + * you should pay homage to Samurai who came before you.

+ * + * Go into the Altar Room and light a candle for them. Afterwards, return to me. + */ + return 1063076; + } + } + } + + private bool m_StolenTreasure; + + public SixthTrialIntroConversation( bool stolenTreasure ) + { + m_StolenTreasure = stolenTreasure; + } + + public SixthTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SixthTrialIntroObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_StolenTreasure = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_StolenTreasure ); + } + } + + public class SeventhTrialIntroConversation : QuestConversation + { + public override object Message + { + get + { + /* You have done well young Samurai. There is but one thing left to do.

+ * + * In the final room is the holding cell containing young Ninjas who came to + * take my life. They were caught and placed in my custody.

+ * + * Take care of these miscreants and show them where your loyalty lies.

+ * + * This is your final act as a Samurai in training. + */ + return 1063079; + } + } + + public SeventhTrialIntroConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new SeventhTrialIntroObjective() ); + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* You have proven yourself young one. You will continue to improve as your skills + * are honed with age.

+ * + * Now it is time for you to explore the lands. Beyond this path lies Zento + * City, your future home. On these grounds you will find a golden oval object + * known as a Moongate, step through it and you'll find yourself in Zento.

+ * + * You may want to visit Ansella Gryen when you arrive.

+ * + * You have learned the ways. You are an honorable warrior, a Samurai in + * the highest regards.

+ * + * Please accept the gifts I have placed in your pack. You have earned them. + * Farewell for now. + */ + return 1063125; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/HaochisTrialsQuest.cs b/Scripts/Engines/Quests/Haochi's Trials/HaochisTrialsQuest.cs new file mode 100644 index 0000000..f831d81 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/HaochisTrialsQuest.cs @@ -0,0 +1,151 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class HaochisTrialsQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Samurai.AcceptConversation ), + typeof( Samurai.RadarConversation ), + typeof( Samurai.FirstTrialIntroConversation ), + typeof( Samurai.FirstTrialKillConversation ), + typeof( Samurai.GainKarmaConversation ), + typeof( Samurai.SecondTrialIntroConversation ), + typeof( Samurai.SecondTrialAttackConversation ), + typeof( Samurai.ThirdTrialIntroConversation ), + typeof( Samurai.ThirdTrialKillConversation ), + typeof( Samurai.FourthTrialIntroConversation ), + typeof( Samurai.FourthTrialCatsConversation ), + typeof( Samurai.FifthTrialIntroConversation ), + typeof( Samurai.FifthTrialReturnConversation ), + typeof( Samurai.LostSwordConversation ), + typeof( Samurai.SixthTrialIntroConversation ), + typeof( Samurai.SeventhTrialIntroConversation ), + typeof( Samurai.EndConversation ), + typeof( Samurai.FindHaochiObjective ), + typeof( Samurai.FirstTrialIntroObjective ), + typeof( Samurai.FirstTrialKillObjective ), + typeof( Samurai.FirstTrialReturnObjective ), + typeof( Samurai.SecondTrialIntroObjective ), + typeof( Samurai.SecondTrialAttackObjective ), + typeof( Samurai.SecondTrialReturnObjective ), + typeof( Samurai.ThirdTrialIntroObjective ), + typeof( Samurai.ThirdTrialKillObjective ), + typeof( Samurai.ThirdTrialReturnObjective ), + typeof( Samurai.FourthTrialIntroObjective ), + typeof( Samurai.FourthTrialCatsObjective ), + typeof( Samurai.FourthTrialReturnObjective ), + typeof( Samurai.FifthTrialIntroObjective ), + typeof( Samurai.FifthTrialReturnObjective ), + typeof( Samurai.SixthTrialIntroObjective ), + typeof( Samurai.SixthTrialReturnObjective ), + typeof( Samurai.SeventhTrialIntroObjective ), + typeof( Samurai.SeventhTrialReturnObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // Haochi's Trials + return 1063022; + } + } + + public override object OfferMessage + { + get + { + /* As you enter the courtyard you notice a faded sign. + * It reads:

+ * + * Welcome to your new home, Samurai.

+ * + * Though your skills are only a shadow of what they can be some day, + * you must prove your adherence to the code of the Bushido.

+ * + * Seek Daimyo Haochi for guidance.

+ * + * Will you accept the challenge? + */ + return 1063023; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.MaxValue; } } + public override bool IsTutorial{ get{ return true; } } + + public override int Picture{ get{ return 0x15D7; } } + + public HaochisTrialsQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public HaochisTrialsQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + private bool m_SentRadarConversion; + + public override void Slice() + { + if ( !m_SentRadarConversion && ( From.Map != Map.Malas || From.X < 360 || From.X > 400 || From.Y < 760 || From.Y > 780 ) ) + { + m_SentRadarConversion = true; + AddConversation( new RadarConversation() ); + } + + base.Slice(); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_SentRadarConversion = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_SentRadarConversion ); + } + + public static bool HasLostHaochisKatana( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is HaochisTrialsQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FifthTrialReturnObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( HaochisKatana ) ) == null ); + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisKatana.cs b/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisKatana.cs new file mode 100644 index 0000000..edd7a00 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisKatana.cs @@ -0,0 +1,46 @@ +using System; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + public class HaochisKatana : QuestItem + { + public override int LabelNumber{ get{ return 1063165; } } // Daimyo Haochi's Katana + + [Constructable] + public HaochisKatana() : base( 0x13FF ) + { + Weight = 1.0; + } + + public HaochisKatana( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + HaochisTrialsQuest qs = player.Quest as HaochisTrialsQuest; + + if ( qs == null ) + return true; + + //return !qs.IsObjectiveInProgress( typeof( FifthTrialReturnObjective ) ); + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisKatanaGenerator.cs b/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisKatanaGenerator.cs new file mode 100644 index 0000000..054a587 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisKatanaGenerator.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class HaochisKatanaGenerator : Item + { + [Constructable] + public HaochisKatanaGenerator() : base( 0x1B7B ) + { + Visible = false; + Name = "Haochi's katana generator"; + Movable = false; + } + + public override bool OnMoveOver( Mobile m ) + { + PlayerMobile player = m as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is HaochisTrialsQuest ) + { + if ( HaochisTrialsQuest.HasLostHaochisKatana( player ) ) + { + Item katana = new HaochisKatana(); + + if ( !player.PlaceInBackpack( katana ) ) + { + katana.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + else + { + QuestObjective obj = qs.FindObjective( typeof( FifthTrialIntroObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item katana = new HaochisKatana(); + + if ( player.PlaceInBackpack( katana ) ) + { + obj.Complete(); + } + else + { + katana.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + } + } + } + + return base.OnMoveOver( m ); + } + + public HaochisKatanaGenerator( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisTreasureChest.cs b/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisTreasureChest.cs new file mode 100644 index 0000000..34673e5 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Items/HaochisTreasureChest.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.Quests.Samurai +{ + public class HaochisTreasureChest : WoodenFootLocker + { + [Constructable] + public HaochisTreasureChest() + { + Movable = false; + + GenerateTreasure(); + } + + public HaochisTreasureChest( Serial serial ) : base( serial ) + { + } + + public override bool IsDecoContainer{ get{ return false; } } + + private void GenerateTreasure() + { + for ( int i = this.Items.Count - 1; i >= 0; i-- ) + this.Items[i].Delete(); + + for ( int i = 0; i < 75; i++ ) + { + switch ( Utility.Random( 3 ) ) + { + case 0: DropItem( new GoldBracelet() ); break; + case 1: DropItem( new GoldRing() ); break; + case 2: DropItem( Loot.RandomGem() ); break; + } + } + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + return false; + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + return item == this; + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.Quest is HaochisTrialsQuest ) + { + FifthTrialIntroObjective obj = player.Quest.FindObjective( typeof( FifthTrialIntroObjective ) ) as FifthTrialIntroObjective; + + if ( obj != null ) + { + if ( obj.StolenTreasure ) + from.SendLocalizedMessage( 1063247 ); // The guard is watching you carefully! It would be unwise to remove another item from here. + else + return true; + } + } + + return false; + } + + public override void OnItemLifted( Mobile from, Item item ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.Quest is HaochisTrialsQuest ) + { + FifthTrialIntroObjective obj = player.Quest.FindObjective( typeof( FifthTrialIntroObjective ) ) as FifthTrialIntroObjective; + + if ( obj != null ) + obj.StolenTreasure = true; + } + + Timer.DelayCall( TimeSpan.FromMinutes( 2.0 ), new TimerCallback( GenerateTreasure ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( GenerateTreasure ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Items/HonorCandle.cs b/Scripts/Engines/Quests/Haochi's Trials/Items/HonorCandle.cs new file mode 100644 index 0000000..b600f4d --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Items/HonorCandle.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class HonorCandle : CandleLong + { + private static readonly TimeSpan LitDuration = TimeSpan.FromSeconds( 20.0 ); + + public override int LitSound{ get{ return 0; } } + public override int UnlitSound{ get{ return 0; } } + + [Constructable] + public HonorCandle() + { + Movable = false; + Duration = LitDuration; + } + + public HonorCandle( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + bool wasBurning = Burning; + + base.OnDoubleClick( from ); + + if ( !wasBurning && Burning ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player == null ) + return; + + QuestSystem qs = player.Quest; + + if ( qs != null && qs is HaochisTrialsQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SixthTrialIntroObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + + this.SendLocalizedMessageTo( from, 1063251 ); // You light a candle in honor. + } + } + } + + public override void Burn() + { + Douse(); + } + + public override void Douse() + { + base.Douse(); + + Duration = LitDuration; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/CursedSoul.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/CursedSoul.cs new file mode 100644 index 0000000..6161547 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/CursedSoul.cs @@ -0,0 +1,70 @@ +using System; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + [CorpseName( "a cursed soul corpse" )] + public class CursedSoul : BaseCreature + { + [Constructable] + public CursedSoul() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a cursed soul"; + Body = 3; + BaseSoundID = 471; + + SetStr( 20, 40 ); + SetDex( 40, 60 ); + SetInt( 15, 25 ); + + SetHits( 10, 20 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 8, 12 ); + + SetSkill( SkillName.Wrestling, 35.0, 39.0 ); + SetSkill( SkillName.Tactics, 5.0, 15.0 ); + SetSkill( SkillName.MagicResist, 10.0 ); + + Fame = 200; + Karma = -200; + + switch ( Utility.Random( 10 ) ) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: PackItem( new RibCage() ); break; + case 6: PackItem( new BonePile() ); break; + case 7: PackItem( new BonePile() ); break; + case 8: PackItem( new BonePile() ); break; + case 9: PackItem( new BonePile() ); break; + } + } + + public CursedSoul( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/DeadlyImp.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/DeadlyImp.cs new file mode 100644 index 0000000..7dbe331 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/DeadlyImp.cs @@ -0,0 +1,80 @@ +using System; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class DeadlyImp : BaseCreature + { + [Constructable] + public DeadlyImp() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a deadly imp"; + Body = 74; + BaseSoundID = 422; + Hue = 0x66A; + + SetStr( 91, 115 ); + SetDex( 61, 80 ); + SetInt( 86, 105 ); + + SetHits( 1000 ); + + SetDamage( 50, 80 ); + + SetDamageType( ResistanceType.Fire, 100 ); + + SetResistance( ResistanceType.Physical, 95, 98 ); + SetResistance( ResistanceType.Fire, 95, 98 ); + SetResistance( ResistanceType.Cold, 95, 98 ); + SetResistance( ResistanceType.Poison, 95, 98 ); + SetResistance( ResistanceType.Energy, 95, 98 ); + + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + + Fame = 2500; + Karma = -2500; + + CantWalk = true; + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + PlayerMobile player = aggressor as PlayerMobile; + if ( player != null ) + { + QuestSystem qs = player.Quest; + if ( qs is HaochisTrialsQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SecondTrialAttackObjective ) ); + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + qs.AddObjective( new SecondTrialReturnObjective( false ) ); + } + } + } + } + + public DeadlyImp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/DiseasedCat.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/DiseasedCat.cs new file mode 100644 index 0000000..d31149c --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/DiseasedCat.cs @@ -0,0 +1,59 @@ +using System; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class DiseasedCat : BaseCreature + { + [Constructable] + public DiseasedCat() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a diseased cat"; + Body = 0xC9; + Hue = Utility.RandomAnimalHue(); + BaseSoundID = 0x69; + + SetStr( 9 ); + SetDex( 35 ); + SetInt( 5 ); + + SetHits( 6 ); + SetMana( 0 ); + + SetDamage( 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 4.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + VirtualArmor = 8; + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public DiseasedCat( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + if( Name == "a deseased cat" ) + Name = "a diseased cat"; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/FierceDragon.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/FierceDragon.cs new file mode 100644 index 0000000..595748a --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/FierceDragon.cs @@ -0,0 +1,102 @@ +using System; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class FierceDragon : BaseCreature + { + [Constructable] + public FierceDragon() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a fierce dragon"; + Body = 103; + BaseSoundID = 362; + + SetStr( 6000, 6020 ); + SetDex( 0 ); + SetInt( 850, 870 ); + + SetDamage( 50, 80 ); + + SetDamageType( ResistanceType.Fire, 100 ); + + SetResistance( ResistanceType.Physical, 95, 98 ); + SetResistance( ResistanceType.Fire, 95, 98 ); + SetResistance( ResistanceType.Cold, 95, 98 ); + SetResistance( ResistanceType.Poison, 95, 98 ); + SetResistance( ResistanceType.Energy, 95, 98 ); + + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + + Fame = 15000; + Karma = 15000; + + CantWalk = true; + } + + public override int GetIdleSound() + { + return 0x2C4; + } + + public override int GetAttackSound() + { + return 0x2C0; + } + + public override int GetDeathSound() + { + return 0x2C1; + } + + public override int GetAngerSound() + { + return 0x2C4; + } + + public override int GetHurtSound() + { + return 0x2C3; + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + PlayerMobile player = aggressor as PlayerMobile; + if ( player != null ) + { + QuestSystem qs = player.Quest; + if ( qs is HaochisTrialsQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( SecondTrialAttackObjective ) ); + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + qs.AddObjective( new SecondTrialReturnObjective( true ) ); + } + } + } + } + + public FierceDragon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/Haochi.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/Haochi.cs new file mode 100644 index 0000000..c31f946 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/Haochi.cs @@ -0,0 +1,182 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + public class Haochi : BaseQuester + { + [Constructable] + public Haochi() : base( "the Honorable Samurai Legend" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x8403; + + Female = false; + Body = 0x190; + Name = "Daimyo Haochi"; + } + + public override void InitOutfit() + { + HairItemID = 0x204A; + HairHue = 0x901; + + AddItem( new SamuraiTabi() ); + AddItem( new JinBaori() ); + + AddItem( new PlateHaidate() ); + AddItem( new StandardPlateKabuto() ); + AddItem( new PlateMempo() ); + AddItem( new PlateDo() ); + AddItem( new PlateHiroSode() ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 2; + } + + public override int TalkNumber{ get { return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is HaochisTrialsQuest ) + { + if ( HaochisTrialsQuest.HasLostHaochisKatana( player ) ) + { + qs.AddConversation( new LostSwordConversation() ); + return; + } + + QuestObjective obj = qs.FindObjective( typeof( FindHaochiObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + return; + } + + obj = qs.FindObjective( typeof( FirstTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + player.AddToBackpack( new LeatherDo() ); + obj.Complete(); + return; + } + + obj = qs.FindObjective( typeof( SecondTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( ((SecondTrialReturnObjective)obj).Dragon ) + player.AddToBackpack( new LeatherSuneate() ); + + obj.Complete(); + return; + } + + obj = qs.FindObjective( typeof( ThirdTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + player.AddToBackpack( new LeatherHiroSode() ); + obj.Complete(); + return; + } + + obj = qs.FindObjective( typeof( FourthTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( !((FourthTrialReturnObjective)obj).KilledCat ) + { + Container cont = GetNewContainer(); + cont.DropItem( new LeatherHiroSode() ); + cont.DropItem( new JinBaori() ); + player.AddToBackpack( cont ); + } + + obj.Complete(); + return; + } + + obj = qs.FindObjective( typeof( FifthTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container pack = player.Backpack; + if ( pack != null ) + { + Item katana = pack.FindItemByType( typeof( HaochisKatana ) ); + if ( katana != null ) + { + katana.Delete(); + obj.Complete(); + + obj = qs.FindObjective( typeof( FifthTrialIntroObjective ) ); + if ( obj != null && ((FifthTrialIntroObjective)obj).StolenTreasure ) + qs.AddConversation( new SixthTrialIntroConversation( true ) ); + else + qs.AddConversation( new SixthTrialIntroConversation( false ) ); + } + } + + return; + } + + obj = qs.FindObjective( typeof( SixthTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + return; + } + + obj = qs.FindObjective( typeof( SeventhTrialReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + BaseWeapon weapon = new Daisho(); + BaseRunicTool.ApplyAttributesTo( weapon, Utility.Random( 1,3 ), 10, 30 ); + player.AddToBackpack( weapon ); + + BaseArmor armor = new LeatherDo(); + BaseRunicTool.ApplyAttributesTo( armor, Utility.Random( 1,3 ), 10, 20 ); + player.AddToBackpack( armor ); + + obj.Complete(); + return; + } + } + } + + public Haochi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/HaochisGuardsman.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/HaochisGuardsman.cs new file mode 100644 index 0000000..3cf7aff --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/HaochisGuardsman.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + public class HaochisGuardsman : BaseQuester + { + [Constructable] + public HaochisGuardsman() : base( "the Guardsman of Daimyo Haochi" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = Race.Human.RandomSkinHue(); + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + public override void InitOutfit() + { + Utility.AssignRandomHair( this ); + + AddItem( new LeatherDo() ); + AddItem( new LeatherHiroSode() ); + AddItem( new SamuraiTabi( Utility.RandomNondyedHue() ) ); + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new StuddedHaidate() ); break; + case 1: AddItem( new PlateSuneate() ); break; + default: AddItem( new LeatherSuneate() ); break; + } + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new DecorativePlateKabuto() ); break; + case 1: AddItem( new ChainHatsuburi() ); break; + case 2: AddItem( new LightPlateJingasa() ); break; + default: AddItem( new LeatherJingasa() ); break; + } + + Item weapon; + switch ( Utility.Random( 3 ) ) + { + case 0: weapon = new NoDachi(); break; + case 1: weapon = new Lajatang(); break; + default: weapon = new Wakizashi(); break; + } + weapon.Movable = false; + AddItem( weapon ); + } + + public override int TalkNumber{ get { return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public HaochisGuardsman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/InjuredWolf.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/InjuredWolf.cs new file mode 100644 index 0000000..a46a0ec --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/InjuredWolf.cs @@ -0,0 +1,59 @@ +using System; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + [CorpseName( "an injured wolf corpse" )] + public class InjuredWolf : BaseCreature + { + [Constructable] + public InjuredWolf() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Body = 0xE1; + Name = "an injured wolf"; + BaseSoundID = 0xE5; + + Hue = Utility.RandomAnimalHue(); + + SetStr( 10, 20 ); + SetDex( 45, 65 ); + SetInt( 10, 15 ); + + SetHits( 1 ); + + SetDamage( 1, 3 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + + SetSkill( SkillName.MagicResist, 10.0 ); + SetSkill( SkillName.Tactics, 0.0, 5.0 ); + SetSkill( SkillName.Wrestling, 20.0, 30.0 ); + } + + public override int GetIdleSound() + { + return 0xE9; + } + + public InjuredWolf( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/Relnia.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/Relnia.cs new file mode 100644 index 0000000..9e328f0 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/Relnia.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + public class Relnia : BaseQuester + { + [Constructable] + public Relnia() : base( "the Gypsy" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83FF; + + Female = true; + Body = 0x191; + Name = "Disheveled Relnia"; + } + + public override void InitOutfit() + { + HairItemID = 0x203C; + HairHue = 0x654; + + AddItem( new ThighBoots( 0x901 ) ); + AddItem( new FancyShirt( 0x5F3 ) ); + AddItem( new SkullCap( 0x6A7 ) ); + AddItem( new Skirt( 0x544 ) ); + } + + public override int TalkNumber{ get { return -1; } } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is HaochisTrialsQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FourthTrialCatsObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Gold gold = dropped as Gold; + + if ( gold != null ) + { + obj.Complete(); + qs.AddObjective( new FourthTrialReturnObjective( false ) ); + + SayTo( from, 1063241 ); // I thank thee. This gold will be a great help to me and mine! + + gold.Consume(); // Intentional difference from OSI: don't take all the gold of poor newbies! + return gold.Deleted; + } + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + + public Relnia( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/YoungNinja.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/YoungNinja.cs new file mode 100644 index 0000000..7ca93d4 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/YoungNinja.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + [CorpseName( "a young ninja's corpse" )] + public class YoungNinja : BaseCreature + { + [Constructable] + public YoungNinja() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + InitStats( 45, 30, 5 ); + SetHits( 20, 30 ); + + Hue = Utility.RandomSkinHue(); + Body = 0x190; + Name = "a young ninja"; + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this ); + + AddItem( new NinjaTabi() ); + AddItem( new LeatherNinjaPants() ); + AddItem( new LeatherNinjaJacket() ); + AddItem( new LeatherNinjaBelt() ); + + AddItem( new Bandana( Utility.RandomNondyedHue() ) ); + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new Tessen() ); break; + case 1: AddItem( new Kama() ); break; + default: AddItem( new Lajatang() ); break; + } + + SetSkill( SkillName.Swords, 50.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public YoungNinja( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Mobiles/YoungRonin.cs b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/YoungRonin.cs new file mode 100644 index 0000000..62a18e8 --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Mobiles/YoungRonin.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Samurai +{ + [CorpseName( "a young ronin's corpse" )] + public class YoungRonin : BaseCreature + { + [Constructable] + public YoungRonin() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + InitStats( 45, 30, 5 ); + SetHits( 10, 20 ); + + Hue = Utility.RandomSkinHue(); + Body = 0x190; + Name = "a young ronin"; + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this ); + + AddItem( new LeatherDo() ); + AddItem( new LeatherHiroSode() ); + AddItem( new SamuraiTabi() ); + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new StuddedHaidate() ); break; + case 1: AddItem( new PlateSuneate() ); break; + default: AddItem( new LeatherSuneate() ); break; + } + + AddItem( new Bandana( Utility.RandomNondyedHue() ) ); + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new NoDachi() ); break; + case 1: AddItem( new Lajatang() ); break; + default: AddItem( new Wakizashi() ); break; + } + + SetSkill( SkillName.Swords, 50.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public YoungRonin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Haochi's Trials/Objectives.cs b/Scripts/Engines/Quests/Haochi's Trials/Objectives.cs new file mode 100644 index 0000000..b5c4c0c --- /dev/null +++ b/Scripts/Engines/Quests/Haochi's Trials/Objectives.cs @@ -0,0 +1,555 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Samurai +{ + public class FindHaochiObjective : QuestObjective + { + public override object Message + { + get + { + // Speak to Daimyo Haochi. + return 1063026; + } + } + + public FindHaochiObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FirstTrialIntroConversation() ); + } + } + + public class FirstTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + // Follow the green path. The guards will now let you through. + return 1063030; + } + } + + public FirstTrialIntroObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FirstTrialKillConversation() ); + } + } + + public class FirstTrialKillObjective : QuestObjective + { + public override object Message + { + get + { + // Kill 3 Young Ronin or 3 Cursed Souls. Return to Daimyo Haochi when you have finished. + return 1063032; + } + } + + public FirstTrialKillObjective() + { + } + + private int m_CursedSoulsKilled; + private int m_YoungRoninKilled; + + public override int MaxProgress{ get{ return 3; } } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is CursedSoul ) + { + if ( m_CursedSoulsKilled == 0 ) + System.AddConversation( new GainKarmaConversation( true ) ); + + m_CursedSoulsKilled++; + + // Cursed Souls killed: ~1_COUNT~ + System.From.SendLocalizedMessage( 1063038, m_CursedSoulsKilled.ToString() ); + } + else if ( creature is YoungRonin ) + { + if ( m_YoungRoninKilled == 0 ) + System.AddConversation( new GainKarmaConversation( false ) ); + + m_YoungRoninKilled++; + + // Young Ronin killed: ~1_COUNT~ + System.From.SendLocalizedMessage( 1063039, m_YoungRoninKilled.ToString() ); + } + + CurProgress = Math.Max( m_CursedSoulsKilled, m_YoungRoninKilled ); + } + + public override void OnComplete() + { + System.AddObjective( new FirstTrialReturnObjective( m_CursedSoulsKilled > m_YoungRoninKilled ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_CursedSoulsKilled = reader.ReadEncodedInt(); + m_YoungRoninKilled = reader.ReadEncodedInt(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( m_CursedSoulsKilled ); + writer.WriteEncodedInt( m_YoungRoninKilled ); + } + } + + public class FirstTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // The first trial is complete. Return to Daimyo Haochi. + return 1063044; + } + } + + bool m_CursedSoul; + + public FirstTrialReturnObjective( bool cursedSoul ) + { + m_CursedSoul = cursedSoul; + } + + public FirstTrialReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new SecondTrialIntroConversation( m_CursedSoul ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_CursedSoul = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_CursedSoul ); + } + } + + public class SecondTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + // Follow the yellow path. The guards will now let you through. + return 1063047; + } + } + + public SecondTrialIntroObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new SecondTrialAttackConversation() ); + } + } + + public class SecondTrialAttackObjective : QuestObjective + { + public override object Message + { + get + { + // Choose your opponent and attack one with all your skill. + return 1063058; + } + } + + public SecondTrialAttackObjective() + { + } + } + + public class SecondTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // The second trial is complete. Return to Daimyo Haochi. + return 1063229; + } + } + + private bool m_Dragon; + + public bool Dragon{ get{ return m_Dragon; } } + + public SecondTrialReturnObjective( bool dragon ) + { + m_Dragon = dragon; + } + + public SecondTrialReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ThirdTrialIntroConversation( m_Dragon ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Dragon = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Dragon ); + } + } + + public class ThirdTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + /* The next trial will test your benevolence. Follow the blue path. + * The guards will now let you through. + */ + return 1063061; + } + } + + public ThirdTrialIntroObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new ThirdTrialKillConversation() ); + } + } + + public class ThirdTrialKillObjective : QuestObjective + { + public override object Message + { + get + { + /* Use your Honorable Execution skill to finish off the wounded wolf. + * Double click the icon in your Book of Bushido to activate the skill. + * When you are done, return to Daimyo Haochi. + */ + return 1063063; + } + } + + public ThirdTrialKillObjective() + { + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is InjuredWolf ) + Complete(); + } + + public override void OnComplete() + { + System.AddObjective( new ThirdTrialReturnObjective() ); + } + } + + public class ThirdTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // Return to Daimyo Haochi. + return 1063064; + } + } + + public ThirdTrialReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FourthTrialIntroConversation() ); + } + } + + public class FourthTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + // Follow the red path and pass through the guards to the entrance of the fourth trial. + return 1063066; + } + } + + public FourthTrialIntroObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FourthTrialCatsConversation() ); + } + } + + public class FourthTrialCatsObjective : QuestObjective + { + public override object Message + { + get + { + /* Give the gypsy gold or hunt one of the cats to eliminate the undue + * need it has placed on the gypsy. + */ + return 1063068; + } + } + + public FourthTrialCatsObjective() + { + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is DiseasedCat ) + { + Complete(); + System.AddObjective( new FourthTrialReturnObjective( true ) ); + } + } + } + + public class FourthTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // You have made your choice. Return now to Daimyo Haochi. + return 1063242; + } + } + + private bool m_KilledCat; + + public bool KilledCat{ get{ return m_KilledCat; } } + + public FourthTrialReturnObjective( bool killedCat ) + { + m_KilledCat = killedCat; + } + + public FourthTrialReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FifthTrialIntroConversation( m_KilledCat ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_KilledCat = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_KilledCat ); + } + } + + public class FifthTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + // Retrieve Daimyo Haochi�s katana from the treasure room. + return 1063072; + } + } + + private bool m_StolenTreasure; + + public bool StolenTreasure{ get{ return m_StolenTreasure; } set{ m_StolenTreasure = value; } } + + public FifthTrialIntroObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new FifthTrialReturnConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_StolenTreasure = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_StolenTreasure ); + } + } + + public class FifthTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // Give the sword to Daimyo Haochi. + return 1063073; + } + } + + public FifthTrialReturnObjective() + { + } + } + + public class SixthTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + // Light one of the candles near the altar and return to Daimyo Haochi. + return 1063078; + } + } + + public SixthTrialIntroObjective() + { + } + + public override void OnComplete() + { + System.AddObjective( new SixthTrialReturnObjective() ); + } + } + + public class SixthTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // You have done as requested. Return to Daimyo Haochi. + return 1063252; + } + } + + public SixthTrialReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new SeventhTrialIntroConversation() ); + } + } + + public class SeventhTrialIntroObjective : QuestObjective + { + public override object Message + { + get + { + /* Three young Ninja must be dealt with. Your job is to kill them. + * When you have done so, return to Daimyo Haochi. + */ + return 1063080; + } + } + + public override int MaxProgress{ get{ return 3; } } + + public SeventhTrialIntroObjective() + { + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is YoungNinja ) + CurProgress++; + } + + public override void OnComplete() + { + System.AddObjective( new SeventhTrialReturnObjective() ); + } + } + + public class SeventhTrialReturnObjective : QuestObjective + { + public override object Message + { + get + { + // The executions are complete. Return to the Daimyo. + return 1063253; + } + } + + public SeventhTrialReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new EndConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Solen Matriarch/Conversations.cs b/Scripts/Engines/Quests/Solen Matriarch/Conversations.cs new file mode 100644 index 0000000..9342ccc --- /dev/null +++ b/Scripts/Engines/Quests/Solen Matriarch/Conversations.cs @@ -0,0 +1,330 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Matriarch +{ + public class DontOfferConversation : QuestConversation + { + private bool m_Friend; + + public override object Message + { + get + { + if ( m_Friend ) + { + /* The Solen Matriarch smiles as you greet her.

+ * + * It is good to see you again. I would offer to process some zoogi fungus for you, + * but you seem to be busy with another task at the moment. Perhaps you should + * finish whatever is occupying your attention at the moment and return to me once + * you're done. + */ + return 1054081; + } + else + { + /* The Solen Matriarch smiles as she eats the seed you offered.

+ * + * Thank you for that seed. It was quite delicious.

+ * + * I would offer to make you a friend of my colony, but you seem to be busy with + * another task at the moment. Perhaps you should finish whatever is occupying + * your attention at the moment and return to me once you're done. + */ + return 1054079; + } + } + } + + public override bool Logged{ get{ return false; } } + + public DontOfferConversation( bool friend ) + { + m_Friend = friend; + } + + public DontOfferConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Friend = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Friend ); + } + } + + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch looks pleased that you've accepted.

+ * + * Very good. Please start by hunting some infiltrators from the other solen + * colony and eliminating them. Slay 7 of them and then return to me.

+ * + * Farewell for now and good hunting. + */ + return 1054084; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new KillInfiltratorsObjective() ); + } + } + + public class DuringKillInfiltratorsConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch looks up as you approach.

+ * + * You're back, but you have not yet eliminated 7 infiltrators from the enemy + * colony. Return when you have completed this task.

+ * + * Carry on. I'll be waiting for your return. + */ + return 1054089; + } + } + + public override bool Logged{ get{ return false; } } + + public DuringKillInfiltratorsConversation() + { + } + } + + public class GatherWaterConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch nods favorably as you approach her.

+ * + * Marvelous! I'm impressed at your ability to hunt and kill enemies for me. + * My colony is thankful.

+ * + * Now I must ask that you gather some water for me. A standard pitcher of water + * holds approximately one gallon. Please decant 8 gallons of fresh water + * into our water vats.

+ * + * Farewell for now. + */ + return 1054091; + } + } + + public GatherWaterConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GatherWaterObjective() ); + } + } + + public class DuringWaterGatheringConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch looks up as you approach.

+ * + * You're back, but you have not yet gathered 8 gallons of water. Return when + * you have completed this task.

+ * + * Carry on. I'll be waiting for your return. + */ + return 1054094; + } + } + + public override bool Logged{ get{ return false; } } + + public DuringWaterGatheringConversation() + { + } + } + + public class ProcessFungiConversation : QuestConversation + { + private bool m_Friend; + + public override object Message + { + get + { + if ( m_Friend ) + { + /* The Solen Matriarch listens as you report the completion of your + * tasks to her.

+ * + * I give you my thanks for your help, and I will gladly process some zoogi + * fungus into powder of translocation for you. Two of the zoogi fungi are + * required for each measure of the powder. I will process up to 200 zoogi fungi + * into 100 measures of powder of translocation.

+ * + * I will also give you some gold for assisting me and my colony, but first let's + * take care of your zoogi fungus. + */ + return 1054097; + } + else + { + /* The Solen Matriarch listens as you report the completion of your + * tasks to her.

+ * + * I give you my thanks for your help, and I will gladly make you a friend of my + * solen colony. My warriors, workers, and queens will not longer look at you + * as an intruder and attack you when you enter our lair.

+ * + * I will also process some zoogi fungus into powder of translocation for you. + * Two of the zoogi fungi are required for each measure of the powder. I will + * process up to 200 zoogi fungi into 100 measures of powder of translocation.

+ * + * I will also give you some gold for assisting me and my colony, but first let's + * take care of your zoogi fungus. + */ + return 1054096; + } + } + } + + public ProcessFungiConversation( bool friend ) + { + m_Friend = friend; + } + + public override void OnRead() + { + System.AddObjective( new ProcessFungiObjective() ); + } + + public ProcessFungiConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Friend = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Friend ); + } + } + + public class DuringFungiProcessConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch smiles as you greet her.

+ * + * I will gladly process some zoogi fungus into powder of translocation for you. + * Two of the zoogi fungi are required for each measure of the powder. + * I will process up to 200 zoogi fungi into 100 measures of powder of translocation. + */ + return 1054099; + } + } + + public override bool Logged{ get{ return false; } } + + public DuringFungiProcessConversation() + { + } + } + + public class FullBackpackConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch looks at you with a smile.

+ * + * While I'd like to finish conducting our business, it seems that you're a + * bit overloaded with equipment at the moment.

+ * + * Perhaps you should free some room in your backpack before we proceed. + */ + return 1054102; + } + } + + private bool m_Logged; + + public override bool Logged{ get{ return m_Logged; } } + + public FullBackpackConversation( bool logged ) + { + m_Logged = logged; + } + + public FullBackpackConversation() + { + m_Logged = true; + } + + public override void OnRead() + { + if ( m_Logged ) + System.AddObjective( new GetRewardObjective() ); + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* The Solen Matriarch smiles as you greet her.

+ * + * Ah good, you've returned. I will conclude our business by giving you + * gold I owe you for aiding me. + */ + return 1054101; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Solen Matriarch/Mobiles/SolenMatriarch.cs b/Scripts/Engines/Quests/Solen Matriarch/Mobiles/SolenMatriarch.cs new file mode 100644 index 0000000..a6837d0 --- /dev/null +++ b/Scripts/Engines/Quests/Solen Matriarch/Mobiles/SolenMatriarch.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.ContextMenus; +using Server.Engines.Plants; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Matriarch +{ + public abstract class BaseSolenMatriarch : BaseQuester + { + public abstract bool RedSolen{ get; } + + public override bool DisallowAllMoves{ get{ return false; } } + + public BaseSolenMatriarch() + { + Name = "the solen matriarch"; + + Body = 0x328; + + if ( !RedSolen ) + Hue = 0x44E; + + SpeechHue = 0; + } + + public override int GetIdleSound() + { + return 0x10D; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + if ( SolenMatriarchQuest.IsFriend( to, this.RedSolen ) ) + return true; + + SolenMatriarchQuest qs = to.Quest as SolenMatriarchQuest; + + return qs != null && qs.RedSolen == this.RedSolen; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + this.Direction = GetDirectionTo( player ); + + SolenMatriarchQuest qs = player.Quest as SolenMatriarchQuest; + + if ( qs != null && qs.RedSolen == this.RedSolen ) + { + if ( qs.IsObjectiveInProgress( typeof( KillInfiltratorsObjective ) ) ) + { + qs.AddConversation( new DuringKillInfiltratorsConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( ReturnAfterKillsObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( GatherWaterObjective ) ) ) + { + qs.AddConversation( new DuringWaterGatheringConversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnAfterWaterObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( ProcessFungiObjective ) ) ) + { + qs.AddConversation( new DuringFungiProcessConversation() ); + } + else + { + obj = qs.FindObjective( typeof( GetRewardObjective ) ); + + if ( obj != null && !obj.Completed ) + { + if ( SolenMatriarchQuest.GiveRewardTo( player ) ) + { + obj.Complete(); + } + else + { + qs.AddConversation( new FullBackpackConversation( false ) ); + } + } + } + } + } + } + else if ( SolenMatriarchQuest.IsFriend( player, this.RedSolen ) ) + { + QuestSystem newQuest = new SolenMatriarchQuest( player, this.RedSolen ); + + if ( player.Quest == null && QuestSystem.CanOfferQuest( player, typeof( SolenMatriarchQuest ) ) ) + { + newQuest.SendOffer(); + } + else + { + newQuest.AddConversation( new DontOfferConversation( true ) ); + } + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + if ( dropped is Seed ) + { + SolenMatriarchQuest qs = player.Quest as SolenMatriarchQuest; + + if ( qs != null && qs.RedSolen == this.RedSolen ) + { + SayTo( player, 1054080 ); // Thank you for that plant seed. Those have such wonderful flavor. + } + else + { + QuestSystem newQuest = new SolenMatriarchQuest( player, this.RedSolen ); + + if ( player.Quest == null && QuestSystem.CanOfferQuest( player, typeof( SolenMatriarchQuest ) ) ) + { + newQuest.SendOffer(); + } + else + { + newQuest.AddConversation( new DontOfferConversation( SolenMatriarchQuest.IsFriend( player, this.RedSolen ) ) ); + } + } + + dropped.Delete(); + return true; + } + else if ( dropped is ZoogiFungus ) + { + OnGivenFungi( player, (ZoogiFungus)dropped ); + + return dropped.Deleted; + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null ) + { + SolenMatriarchQuest qs = pm.Quest as SolenMatriarchQuest; + + if ( qs != null && qs.RedSolen == this.RedSolen ) + { + if ( qs.IsObjectiveInProgress( typeof( ProcessFungiObjective ) ) ) + { + list.Add( new ProcessZoogiFungusEntry( this, pm ) ); + } + } + } + } + } + + private class ProcessZoogiFungusEntry : ContextMenuEntry + { + private BaseSolenMatriarch m_Matriarch; + private PlayerMobile m_From; + + public ProcessZoogiFungusEntry( BaseSolenMatriarch matriarch, PlayerMobile from ) : base( 6184 ) + { + m_Matriarch = matriarch; + m_From = from; + } + + public override void OnClick() + { + if ( m_From.Alive ) + m_From.Target = new ProcessFungiTarget( m_Matriarch, m_From ); + } + } + + private class ProcessFungiTarget : Target + { + private BaseSolenMatriarch m_Matriarch; + private PlayerMobile m_From; + + public ProcessFungiTarget( BaseSolenMatriarch matriarch, PlayerMobile from ) : base( -1, false, TargetFlags.None ) + { + m_Matriarch = matriarch; + m_From = from; + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + from.SendLocalizedMessage( 1042021, "", 0x59 ); // Cancelled. + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is ZoogiFungus ) + { + ZoogiFungus fungus = (ZoogiFungus)targeted; + + if ( fungus.IsChildOf( m_From.Backpack ) ) + m_Matriarch.OnGivenFungi( m_From, (ZoogiFungus)targeted ); + else + m_From.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + } + + public void OnGivenFungi( PlayerMobile player, ZoogiFungus fungi ) + { + this.Direction = GetDirectionTo( player ); + + SolenMatriarchQuest qs = player.Quest as SolenMatriarchQuest; + + if ( qs != null && qs.RedSolen == this.RedSolen ) + { + QuestObjective obj = qs.FindObjective( typeof( ProcessFungiObjective ) ); + + if ( obj != null && !obj.Completed ) + { + int amount = fungi.Amount / 2; + + if ( amount > 100 ) + amount = 100; + + if ( amount > 0 ) + { + if ( amount * 2 >= fungi.Amount ) + fungi.Delete(); + else + fungi.Amount -= amount * 2; + + PowderOfTranslocation powder = new PowderOfTranslocation( amount ); + player.AddToBackpack( powder ); + + player.SendLocalizedMessage( 1054100 ); // You receive some powder of translocation. + + obj.Complete(); + } + } + } + } + + public BaseSolenMatriarch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class RedSolenMatriarch : BaseSolenMatriarch + { + public override bool RedSolen{ get{ return true; } } + + [Constructable] + public RedSolenMatriarch() + { + } + + public RedSolenMatriarch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BlackSolenMatriarch : BaseSolenMatriarch + { + public override bool RedSolen{ get{ return false; } } + + [Constructable] + public BlackSolenMatriarch() + { + } + + public BlackSolenMatriarch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Solen Matriarch/Objectives.cs b/Scripts/Engines/Quests/Solen Matriarch/Objectives.cs new file mode 100644 index 0000000..24380a4 --- /dev/null +++ b/Scripts/Engines/Quests/Solen Matriarch/Objectives.cs @@ -0,0 +1,216 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Matriarch +{ + public class KillInfiltratorsObjective : QuestObjective + { + public override object Message + { + get + { + // Kill 7 black/red solen infiltrators. + return ((SolenMatriarchQuest)System).RedSolen ? 1054086 : 1054085; + } + } + + public override int MaxProgress{ get{ return 7; } } + + public KillInfiltratorsObjective() + { + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Black/Red Solen Infiltrators killed: + gump.AddHtmlLocalized( 70, 260, 270, 100, ((SolenMatriarchQuest)System).RedSolen ? 1054088 : 1054087, BaseQuestGump.Blue, false, false ); + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, MaxProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + if ( Completed ) + return false; + + bool redSolen = ((SolenMatriarchQuest)System).RedSolen; + + if ( redSolen ) + return from is BlackSolenInfiltratorWarrior || from is BlackSolenInfiltratorQueen; + else + return from is RedSolenInfiltratorWarrior || from is RedSolenInfiltratorQueen; + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + bool redSolen = ((SolenMatriarchQuest)System).RedSolen; + + if ( redSolen ) + { + if ( creature is BlackSolenInfiltratorWarrior || creature is BlackSolenInfiltratorQueen ) + CurProgress++; + } + else + { + if ( creature is RedSolenInfiltratorWarrior || creature is RedSolenInfiltratorQueen ) + CurProgress++; + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnAfterKillsObjective() ); + } + } + + public class ReturnAfterKillsObjective : QuestObjective + { + public override object Message + { + get + { + /* You've completed your task of slaying solen infiltrators. Return to the + * Matriarch who gave you this task. + */ + return 1054090; + } + } + + public ReturnAfterKillsObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new GatherWaterConversation() ); + } + } + + public class GatherWaterObjective : QuestObjective + { + public override object Message + { + get + { + // Gather 8 gallons of water for the water vats of the solen ant lair. + return 1054092; + } + } + + public override int MaxProgress{ get{ return 40; } } + + public GatherWaterObjective() + { + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + gump.AddHtmlLocalized( 70, 260, 270, 100, 1054093, BaseQuestGump.Blue, false, false ); // Gallons of Water gathered: + gump.AddLabel( 70, 280, 0x64, (CurProgress / 5).ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, (MaxProgress / 5).ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnAfterWaterObjective() ); + } + } + + public class ReturnAfterWaterObjective : QuestObjective + { + public override object Message + { + get + { + // You've completed your task of gathering water. Return to the Matriarch who gave you this task. + return 1054095; + } + } + + public ReturnAfterWaterObjective() + { + } + + public override void OnComplete() + { + PlayerMobile player = System.From; + bool redSolen = ((SolenMatriarchQuest)System).RedSolen; + + bool friend = SolenMatriarchQuest.IsFriend( player, redSolen ); + + System.AddConversation( new ProcessFungiConversation( friend ) ); + + if ( redSolen ) + player.SolenFriendship = SolenFriendship.Red; + else + player.SolenFriendship = SolenFriendship.Black; + } + } + + public class ProcessFungiObjective : QuestObjective + { + public override object Message + { + get + { + // Give the Solen Matriarch a stack of zoogi fungus to process into powder of translocation. + return 1054098; + } + } + + public ProcessFungiObjective() + { + } + + public override void OnComplete() + { + if ( SolenMatriarchQuest.GiveRewardTo( System.From ) ) + { + System.Complete(); + } + else + { + System.AddConversation( new FullBackpackConversation( true ) ); + } + } + } + + public class GetRewardObjective : QuestObjective + { + public override object Message + { + get + { + // Return to the solen matriarch for your reward. + return 1054149; + } + } + + public GetRewardObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new EndConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Solen Matriarch/SolenMatriarchQuest.cs b/Scripts/Engines/Quests/Solen Matriarch/SolenMatriarchQuest.cs new file mode 100644 index 0000000..48752f0 --- /dev/null +++ b/Scripts/Engines/Quests/Solen Matriarch/SolenMatriarchQuest.cs @@ -0,0 +1,160 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Matriarch +{ + public class SolenMatriarchQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Matriarch.DontOfferConversation ), + typeof( Matriarch.AcceptConversation ), + typeof( Matriarch.DuringKillInfiltratorsConversation ), + typeof( Matriarch.GatherWaterConversation ), + typeof( Matriarch.DuringWaterGatheringConversation ), + typeof( Matriarch.ProcessFungiConversation ), + typeof( Matriarch.DuringFungiProcessConversation ), + typeof( Matriarch.FullBackpackConversation ), + typeof( Matriarch.EndConversation ), + typeof( Matriarch.KillInfiltratorsObjective ), + typeof( Matriarch.ReturnAfterKillsObjective ), + typeof( Matriarch.GatherWaterObjective ), + typeof( Matriarch.ReturnAfterWaterObjective ), + typeof( Matriarch.ProcessFungiObjective ), + typeof( Matriarch.GetRewardObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // Solen Matriarch Quest + return 1054147; + } + } + + public override object OfferMessage + { + get + { + if ( IsFriend( From, RedSolen ) ) + { + /* The Solen Matriarch smiles happily as you greet her.

+ * + * Hello again. It is always good to see a friend of our colony.

+ * + * Would you like me to process some zoogi fungus into powder of translocation + * for you? I would be happy to do so if you will first undertake a couple + * tasks for me.

+ * + * First, I would like for you to eliminate some infiltrators from the other + * solen colony. They are spying on my colony, and I fear for the safety of my + * people. They must be slain.

+ * + * After that, I must ask that you gather some water for me. Our water supplies + * are inadequate, so we must try to supplement our reserve using water vats here + * in our lair.

+ * + * Will you accept my offer? + */ + return 1054083; + } + else + { + /* The Solen Matriarch smiles happily as she eats the seed you offered.

+ * + * I think you for that seed. I was quite delicious. So full of flavor.

+ * + * Hmm... if you would like, I could make you a friend of my colony. This would stop + * the warriors, workers, and queens of my colony from thinking you are an intruder, + * thus they would not attack you. In addition, as a friend of my colony I will process + * zoogi fungus into powder of translocation for you.

+ * + * To become a friend of my colony, I ask that you complete a couple tasks for me. These + * are the same tasks I will ask of you when you wish me to process zoogi fungus, + * by the way.

+ * + * First, I would like for you to eliminate some infiltrators from the other solen colony. + * They are spying on my colony, and I fear for the safety of my people. They must + * be slain.

+ * + * After that, I must ask that you gather some water for me. Our water supplies are + * inadequate, so we must try to supplement our reserve using water vats here in our + * lair.

+ * + * Will you accept my offer? + */ + return 1054082; + } + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.Zero; } } + public override bool IsTutorial{ get{ return false; } } + + public override int Picture{ get{ return 0x15C9; } } + + private bool m_RedSolen; + + public bool RedSolen{ get{ return m_RedSolen; } } + + public SolenMatriarchQuest( PlayerMobile from, bool redSolen ) : base( from ) + { + m_RedSolen = redSolen; + } + + // Serialization + public SolenMatriarchQuest() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_RedSolen = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_RedSolen ); + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + public static bool IsFriend( PlayerMobile player, bool redSolen ) + { + if ( redSolen ) + return player.SolenFriendship == SolenFriendship.Red; + else + return player.SolenFriendship == SolenFriendship.Black; + } + + public static bool GiveRewardTo( PlayerMobile player ) + { + Gold gold = new Gold( Utility.RandomMinMax( 250, 350 ) ); + + if ( player.PlaceInBackpack( gold ) ) + { + player.SendLocalizedMessage( 1054076 ); // You have been given some gold. + return true; + } + else + { + gold.Delete(); + return false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Study of the Solen Hive/Conversations.cs b/Scripts/Engines/Quests/Study of the Solen Hive/Conversations.cs new file mode 100644 index 0000000..8f58461 --- /dev/null +++ b/Scripts/Engines/Quests/Study of the Solen Hive/Conversations.cs @@ -0,0 +1,205 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Naturalist +{ + public class DontOfferConversation : QuestConversation + { + public override object Message + { + get + { + /* The Naturalist looks up from his scribbled notes.

+ * + * Greetings!

+ * + * If you're interested in helping out a scholar of some repute, I do have some + * work that I could use some assistance with.

+ * + * You seem a little preoccupied with another task right now, however. Perhaps + * you should finish whatever it is that has your attention at the moment and + * return to me once you're done. + */ + return 1054052; + } + } + + public override bool Logged{ get{ return false; } } + + public DontOfferConversation() + { + } + } + + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Ah! This is splendid news! Each time an assistant travels into the + * Solen Hive to gather information for me, I feel as if I am one step + * closer to some grand discovery. Though I felt the same way when I was + * certain that Terathans had the ability to change their shape to resemble + * various fruits and vegetables - a point on which I am certain further + * study of the beasts will prove correct.

+ * + * In any case, I cannot thank you enough! Please return to me when you have + * studied all the Solen Egg Nests hidden within the Solen Hive. + */ + return 1054043; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new StudyNestsObjective() ); + } + } + + public class NaturalistDuringStudyConversation : QuestConversation + { + public override object Message + { + get + { + /* The Naturalist looks up from his notes with a frustrated look + * on his face.

+ * + * Haven't you finished the task I appointed you yet? Gah! It's so + * difficult to find a good apprentice these days.

+ * + * Remember, you must first find an entrance to the Solen Hive. Once inside, + * I need you to examine the Solen Egg Nests for me. When you have studied + * all four nests, you should have enough information to earn yourself a + * reward.

+ * + * Now go on, away with you! I have piles of notes from other more helpful + * apprentices that I still need to study! + */ + return 1054049; + } + } + + public override bool Logged{ get{ return false; } } + + public NaturalistDuringStudyConversation() + { + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* The Naturalist looks up from his notes with a pleased expression + * on his face.

+ * + * Ah! Thank you, my goodly apprentice! These notes you have gathered will + * no doubt assist me in my understanding of these fascinating Solen creatures.

+ * + * Now, since you've done such a fine job, I feel that I should give you a little + * reward.

+ * + * I have a botanist friend who has discovered a strange mutation in the plants + * she has grown. Through science and sorcery, she has managed to produce a mutant + * strain of colored seeds the like of which no gardener has laid eyes upon.

+ * + * As a reward for your fine efforts, I present you with this strange rare seed. + * Which reminds me, I still need to compile my notes on Solen dietary habits. They + * are voracious seed eaters, those Solen Matriarchs!

+ * + * In any case, I must get back to my notes now. I give you my thanks once more, + * and bid a good day to you my little apprentice! If you wish to help me out again, + * just say the word. + */ + return 1054050; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class SpecialEndConversation : QuestConversation + { + public override object Message + { + get + { + /* The Naturalist looks up from his notes with an ecstatic look upon + * his face.

+ * + * Oh my! These notes you've brought me - they say you have information on the + * Secret Solen Egg Nest? I've heard many tales of this secret store of special + * Solen Eggs, but there are many missing gaps in my notes concerning it.

+ * + * The notes you've made here will most certainly advance my understanding of + * this mysterious breed of creatures!

+ * + * Considering the amazing effort you put into your work, I feel as if I should + * give you something extra special as a bonus. Hrmm...

+ * + * I have a botanist friend who has discovered a strange mutation in the plants + * she has grown. Through science and sorcery, she has managed to produce a rare + * mutant strain of colored seeds the like of which no gardener has laid + * eyes upon.

+ * + * I've given a few of her seeds out to various apprentices - but I usually keep + * her very rare stock all for myself. They're quite amazing looking! However, + * since you've done such a fine job for me, I'll present you with one of + * these rare fire-red seeds.

+ * + * Once again, my thanks to you! Now I really must get back to studying these notes! + * Take care, my fine apprentice, and come back if you wish to help me further! + */ + return 1054051; + } + } + + public SpecialEndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class FullBackpackConversation : QuestConversation + { + public override object Message + { + get + { + /* The Naturalist looks at you with a friendly expression.

+ * + * I see you've returned with information for me. While I'd like to finish + * conducting our business, it seems that you're a bit overloaded with + * equipment at the moment. Perhaps you'd better free up some room before + * we get to discussing your reward. + */ + return 1054053; + } + } + + public override bool Logged{ get{ return false; } } + + public FullBackpackConversation() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Study of the Solen Hive/Mobiles/Naturalist.cs b/Scripts/Engines/Quests/Study of the Solen Hive/Mobiles/Naturalist.cs new file mode 100644 index 0000000..b8a5369 --- /dev/null +++ b/Scripts/Engines/Quests/Study of the Solen Hive/Mobiles/Naturalist.cs @@ -0,0 +1,158 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Plants; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Naturalist +{ + public class Naturalist : BaseQuester + { + [Constructable] + public Naturalist() : base( "the Naturalist" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = Utility.RandomSkinHue(); + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + public override void InitOutfit() + { + AddItem( new Tunic( 0x598 ) ); + AddItem( new LongPants( 0x59B ) ); + AddItem( new Boots() ); + + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + StudyOfSolenQuest qs = player.Quest as StudyOfSolenQuest; + + if ( qs != null && qs.Naturalist == this ) + { + StudyNestsObjective study = qs.FindObjective( typeof( StudyNestsObjective ) ) as StudyNestsObjective; + + if ( study != null ) + { + if ( !study.Completed ) + { + PlaySound( 0x41F ); + qs.AddConversation( new NaturalistDuringStudyConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( ReturnToNaturalistObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Seed reward; + + PlantType type; + switch ( Utility.Random( 17 ) ) + { + case 0: type = PlantType.CampionFlowers; break; + case 1: type = PlantType.Poppies; break; + case 2: type = PlantType.Snowdrops; break; + case 3: type = PlantType.Bulrushes; break; + case 4: type = PlantType.Lilies; break; + case 5: type = PlantType.PampasGrass; break; + case 6: type = PlantType.Rushes; break; + case 7: type = PlantType.ElephantEarPlant; break; + case 8: type = PlantType.Fern; break; + case 9: type = PlantType.PonytailPalm; break; + case 10: type = PlantType.SmallPalm; break; + case 11: type = PlantType.CenturyPlant; break; + case 12: type = PlantType.WaterPlant; break; + case 13: type = PlantType.SnakePlant; break; + case 14: type = PlantType.PricklyPearCactus; break; + case 15: type = PlantType.BarrelCactus; break; + default: type = PlantType.TribarrelCactus; break; + } + + if ( study.StudiedSpecialNest ) + { + reward = new Seed( type, PlantHue.FireRed, false ); + } + else + { + PlantHue hue; + switch ( Utility.Random( 3 ) ) + { + case 0: hue = PlantHue.Pink; break; + case 1: hue = PlantHue.Magenta; break; + default: hue = PlantHue.Aqua; break; + } + + reward = new Seed( type, hue, false ); + } + + if ( player.PlaceInBackpack( reward ) ) + { + obj.Complete(); + + PlaySound( 0x449 ); + PlaySound( 0x41B ); + + if ( study.StudiedSpecialNest ) + qs.AddConversation( new SpecialEndConversation() ); + else + qs.AddConversation( new EndConversation() ); + } + else + { + reward.Delete(); + + qs.AddConversation( new FullBackpackConversation() ); + } + } + } + } + } + else + { + QuestSystem newQuest = new StudyOfSolenQuest( player, this ); + + if ( player.Quest == null && QuestSystem.CanOfferQuest( player, typeof( StudyOfSolenQuest ) ) ) + { + PlaySound( 0x42F ); + newQuest.SendOffer(); + } + else + { + PlaySound( 0x448 ); + newQuest.AddConversation( new DontOfferConversation() ); + } + } + } + + public Naturalist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Study of the Solen Hive/NestArea.cs b/Scripts/Engines/Quests/Study of the Solen Hive/NestArea.cs new file mode 100644 index 0000000..8cf7172 --- /dev/null +++ b/Scripts/Engines/Quests/Study of the Solen Hive/NestArea.cs @@ -0,0 +1,91 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Naturalist +{ + public class NestArea + { + private static readonly NestArea[] m_Areas = new NestArea[] + { + new NestArea( false, new Rectangle2D( 5861, 1787, 26, 25 ) ), + + new NestArea( false, new Rectangle2D( 5734, 1788, 14, 50 ), + new Rectangle2D( 5748, 1800, 3, 34 ), + new Rectangle2D( 5751, 1808, 2, 20 ) ), + + new NestArea( false, new Rectangle2D( 5907, 1908, 19, 43 ) ), + + new NestArea( false, new Rectangle2D( 5721, 1926, 24, 29 ), + new Rectangle2D( 5745, 1935, 7, 22 ) ), + + new NestArea( true, new Rectangle2D( 5651, 1853, 21, 32 ), + new Rectangle2D( 5672, 1857, 6, 20 ) ) + }; + + public static int NonSpecialCount + { + get + { + int n = 0; + foreach ( NestArea area in m_Areas ) + { + if ( !area.Special ) + n++; + } + return n; + } + } + + public static NestArea Find( IPoint2D p ) + { + foreach ( NestArea area in m_Areas ) + { + if ( area.Contains( p ) ) + return area; + } + return null; + } + + public static NestArea GetByID( int id ) + { + if ( id >= 0 && id < m_Areas.Length ) + return m_Areas[id]; + else + return null; + } + + private bool m_Special; + private Rectangle2D[] m_Rects; + + public bool Special{ get{ return m_Special; } } + + public int ID + { + get + { + for ( int i = 0; i < m_Areas.Length; i++ ) + { + if ( m_Areas[i] == this ) + return i; + } + return 0; + } + } + + private NestArea( bool special, params Rectangle2D[] rects ) + { + m_Special = special; + m_Rects = rects; + } + + public bool Contains( IPoint2D p ) + { + foreach ( Rectangle2D rect in m_Rects ) + { + if ( rect.Contains( p ) ) + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Study of the Solen Hive/Objectives.cs b/Scripts/Engines/Quests/Study of the Solen Hive/Objectives.cs new file mode 100644 index 0000000..095b1e8 --- /dev/null +++ b/Scripts/Engines/Quests/Study of the Solen Hive/Objectives.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Naturalist +{ + public class StudyNestsObjective : QuestObjective + { + public override object Message + { + get + { + /* Find an entrance to the Solen Hive, and search within for the Solen + * Egg Nests. Each Nest must be studied for some time without a break in + * concentration in order to gather useful information.

+ * + * Once you have completed your study of the Nests, return to the Naturalist + * who gave you this task. + */ + return 1054044; + } + } + + public override int MaxProgress{ get{ return NestArea.NonSpecialCount; } } + + private NestArea m_CurrentNest; + private DateTime m_StudyBegin; + + private enum StudyState { Inactive, FirstStep, SecondStep } + private StudyState m_StudyState; + + private ArrayList m_StudiedNests; + private bool m_StudiedSpecialNest; + + public bool StudiedSpecialNest{ get{ return m_StudiedSpecialNest; } } + + public StudyNestsObjective() + { + m_StudiedNests = new ArrayList(); + } + + public override bool GetTimerEvent() + { + return true; + } + + public override void CheckProgress() + { + PlayerMobile from = System.From; + + if ( m_CurrentNest != null ) + { + NestArea nest = m_CurrentNest; + + if ( ( from.Map == Map.Trammel || from.Map == Map.Felucca ) && nest.Contains( from ) ) + { + if ( m_StudyState != StudyState.Inactive ) + { + TimeSpan time = DateTime.Now - m_StudyBegin; + + if ( time > TimeSpan.FromSeconds( 30.0 ) ) + { + m_StudiedNests.Add( nest ); + m_StudyState = StudyState.Inactive; + + if ( m_CurrentNest.Special ) + { + from.SendLocalizedMessage( 1054057 ); // You complete your examination of this bizarre Egg Nest. The Naturalist will undoubtedly be quite interested in these notes! + m_StudiedSpecialNest = true; + } + else + { + from.SendLocalizedMessage( 1054054 ); // You have completed your study of this Solen Egg Nest. You put your notes away. + CurProgress++; + } + } + else if ( m_StudyState == StudyState.FirstStep && time > TimeSpan.FromSeconds( 15.0 ) ) + { + if ( !nest.Special ) + from.SendLocalizedMessage( 1054058 ); // You begin recording your completed notes on a bit of parchment. + + m_StudyState = StudyState.SecondStep; + } + } + } + else + { + if ( m_StudyState != StudyState.Inactive ) + from.SendLocalizedMessage( 1054046 ); // You abandon your study of the Solen Egg Nest without gathering the needed information. + + m_CurrentNest = null; + } + } + else if ( from.Map == Map.Trammel || from.Map == Map.Felucca ) + { + NestArea nest = NestArea.Find( from ); + + if ( nest != null ) + { + m_CurrentNest = nest; + m_StudyBegin = DateTime.Now; + + if ( m_StudiedNests.Contains( nest ) ) + { + m_StudyState = StudyState.Inactive; + + from.SendLocalizedMessage( 1054047 ); // You glance at the Egg Nest, realizing you've already studied this one. + } + else + { + m_StudyState = StudyState.FirstStep; + + if ( nest.Special ) + from.SendLocalizedMessage( 1054056 ); // You notice something very odd about this Solen Egg Nest. You begin taking notes. + else + from.SendLocalizedMessage( 1054045 ); // You begin studying the Solen Egg Nest to gather information. + + if ( from.Female ) + from.PlaySound( 0x30B ); + else + from.PlaySound( 0x419 ); + } + } + } + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + gump.AddHtmlLocalized( 70, 260, 270, 100, 1054055, BaseQuestGump.Blue, false, false ); // Solen Nests Studied : + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, MaxProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnToNaturalistObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + int count = reader.ReadEncodedInt(); + for ( int i = 0; i < count; i++ ) + { + NestArea nest = NestArea.GetByID( reader.ReadEncodedInt() ); + m_StudiedNests.Add( nest ); + } + + m_StudiedSpecialNest = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_StudiedNests.Count ); + foreach ( NestArea nest in m_StudiedNests ) + { + writer.WriteEncodedInt( (int) nest.ID ); + } + + writer.Write( (bool) m_StudiedSpecialNest ); + } + } + + public class ReturnToNaturalistObjective : QuestObjective + { + public override object Message + { + get + { + /* You have studied enough Solen Egg Nests to gather a fair amount of + * useful information. Return to the Naturalist who gave you this task. + */ + return 1054048; + } + } + + public ReturnToNaturalistObjective() + { + } + + public override void RenderProgress( BaseQuestGump gump ) + { + string count = NestArea.NonSpecialCount.ToString(); + + gump.AddHtmlLocalized( 70, 260, 270, 100, 1054055, BaseQuestGump.Blue, false, false ); // Solen Nests Studied : + gump.AddLabel( 70, 280, 0x64, count ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, count ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Study of the Solen Hive/StudyOfSolenQuest.cs b/Scripts/Engines/Quests/Study of the Solen Hive/StudyOfSolenQuest.cs new file mode 100644 index 0000000..bea76a2 --- /dev/null +++ b/Scripts/Engines/Quests/Study of the Solen Hive/StudyOfSolenQuest.cs @@ -0,0 +1,111 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Naturalist +{ + public class StudyOfSolenQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( StudyNestsObjective ), + typeof( ReturnToNaturalistObjective ), + typeof( DontOfferConversation ), + typeof( AcceptConversation ), + typeof( NaturalistDuringStudyConversation ), + typeof( EndConversation ), + typeof( SpecialEndConversation ), + typeof( FullBackpackConversation ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // "Study of the Solen Hive" + return 1054041; + } + } + + public override object OfferMessage + { + get + { + /* The Naturalist looks up from his notes, regarding you with a hopeful + * look in his eyes.

+ * + * Um..yes..excuse me. I was wondering if you could offer me a bit of assistance. + * You see, I'm a naturalist of some repute - a gentleman and a scholar if you + * will - primarily interested in the study of insects and arachnids. While I've + * written a few interesting books on the marvelous Terathan race and their bizarre + * culture, now I've heard tales of a truly significant new discovery!

+ * + * Apparently a race of ant-like creatures known as the Solen have appeared in + * our world, scuttling up from some previously hidden home. Can you believe it? + * Truly these are amazing times! To a scholar such as myself this is indeed + * an exciting opportunity.

+ * + * That said, while I may be a genius of some reknown, sharp as a tack and quick + * with the quill, I'm afraid I'm not much of the adventuring type. Though I have + * gained assistance before, I still have many unanswered questions.

+ * + * I am particularly interested in the Solen Egg Nests that are studiously + * protected by the Solen workers. If you would be so kind as to assist me, + * I would ask that you travel into the Solen Hive and inspect each of the + * Solen Egg Nests that reside within. You will have to spend some time examining + * each Nest before you have gathered enough information. Once you are done, + * report back to me and I will reward you as best as I can for your valiant + * efforts!

+ * + * Will you accept my offer? + */ + return 1054042; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.Zero; } } + public override bool IsTutorial{ get{ return false; } } + + public override int Picture{ get{ return 0x15C7; } } + + private Naturalist m_Naturalist; + + public Naturalist Naturalist{ get{ return m_Naturalist; } } + + public StudyOfSolenQuest( PlayerMobile from, Naturalist naturalist ) : base( from ) + { + m_Naturalist = naturalist; + } + + // Serialization + public StudyOfSolenQuest() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Naturalist = (Naturalist) reader.ReadMobile(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Mobile) m_Naturalist ); + } + + public override void Accept() + { + base.Accept(); + + if ( m_Naturalist != null ) + m_Naturalist.PlaySound( 0x431 ); + + AddConversation( new AcceptConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Terrible Hatchlings/Conversations.cs b/Scripts/Engines/Quests/Terrible Hatchlings/Conversations.cs new file mode 100644 index 0000000..b53b87b --- /dev/null +++ b/Scripts/Engines/Quests/Terrible Hatchlings/Conversations.cs @@ -0,0 +1,111 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Zento +{ + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Important Quest Information

+ * + * During your quest, any important information that a + * NPC gives you, will appear in a window + * such as this one. You can review the information at any time during your + * quest.

+ * + * Getting Help

+ * + * Some of the text you will come across during your quest, + * will be underlined links to the codex of wisdom, + * or online help system. You can click on the text to get detailed information + * on the underlined subject. You may also access the Codex Of Wisdom by + * pressing "F1" or by clicking on the "?" on the toolbar at the top of + * your screen.

Context Menus

+ * + * Context menus can be called up by single left-clicking (or Shift + single + * left-click, if you changed it) on most objects or NPCs in the world. + * Nearly everything, including your own avatar will have context menus available. + * Bringing up your avatar's context menu will give you options to cancel your quest + * and review various quest information.

+ */ + return 1049092; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FirstKillObjective() ); + } + } + + public class DirectionConversation : QuestConversation + { + public override object Message + { + get + { + // The Deathwatch Beetle Hatchlings live in The Waste - the desert close to this city. + return 1063323; + } + } + + public override bool Logged{ get{ return false; } } + + public DirectionConversation() + { + } + } + + public class TakeCareConversation : QuestConversation + { + public override object Message + { + get + { + // I know you can take care of those nasty Deathwatch Beetle Hatchlings! No get to it! + return 1063324; + } + } + + public override bool Logged{ get{ return false; } } + + public TakeCareConversation() + { + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* Thank you for helping me get rid of these vile beasts! + * You have been rewarded for your good deeds. If you wish to + * help me in the future, visit me again.

+ * + * Farewell. + */ + return 1063321; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs b/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs new file mode 100644 index 0000000..0ed8fe3 --- /dev/null +++ b/Scripts/Engines/Quests/Terrible Hatchlings/Mobiles/AnsellaGryen.cs @@ -0,0 +1,146 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Items; + +namespace Server.Engines.Quests.Zento +{ + public class AnsellaGryen : BaseQuester + { + [Constructable] + public AnsellaGryen() + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83EA; + + Female = true; + Body = 0x191; + Name = "Ansella Gryen"; + } + + public override void InitOutfit() + { + HairItemID = 0x203B; + HairHue = 0x1BB; + + AddItem( new SamuraiTabi( 0x8FD ) ); + AddItem( new FemaleKimono( 0x4B6 ) ); + AddItem( new Obi( 0x526 ) ); + + AddItem( new GoldBracelet() ); + } + + public override int GetAutoTalkRange( PlayerMobile m ) + { + if ( m.Quest == null ) + return 3; + else + return -1; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is TerribleHatchlingsQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FirstKillObjective ) ) ) + { + qs.AddConversation( new DirectionConversation() ); + } + else if ( qs.IsObjectiveInProgress( typeof( SecondKillObjective ) ) + || qs.IsObjectiveInProgress( typeof( ThirdKillObjective ) ) ) + { + qs.AddConversation( new TakeCareConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( ReturnObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + cont.DropItem( new Gold( Utility.RandomMinMax( 100, 200 ) ) ); + + if (Utility.RandomBool()) + { + BaseWeapon weapon = Loot.Construct(Loot.SEWeaponTypes) as BaseWeapon; + + if (weapon != null) + { + BaseRunicTool.ApplyAttributesTo(weapon, 3, 10, 30); + cont.DropItem(weapon); + } + } + else + { + BaseArmor armor = Loot.Construct(Loot.SEArmorTypes) as BaseArmor; + + if (armor != null) + { + BaseRunicTool.ApplyAttributesTo(armor, 1, 10, 20); + cont.DropItem(armor); + } + } + + if ( player.PlaceInBackpack( cont ) ) + { + obj.Complete(); + } + else + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + } + } + else + { + TerribleHatchlingsQuest newQuest = new TerribleHatchlingsQuest( player ); + bool inRestartPeriod = false; + + if ( qs != null ) + { + if ( contextMenu ) + SayTo( player, 1063322 ); // Before you can help me with the Terrible Hatchlings, you'll need to finish the quest you've already taken! + } + else if ( QuestSystem.CanOfferQuest( player, typeof( TerribleHatchlingsQuest ), out inRestartPeriod ) ) + { + newQuest.SendOffer(); + } + else if ( inRestartPeriod && contextMenu ) + { + SayTo( player, 1049357 ); // I have nothing more for you at this time. + } + } + } + + public AnsellaGryen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + public override void TurnToTokuno() { } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Terrible Hatchlings/Objectives.cs b/Scripts/Engines/Quests/Terrible Hatchlings/Objectives.cs new file mode 100644 index 0000000..edde86e --- /dev/null +++ b/Scripts/Engines/Quests/Terrible Hatchlings/Objectives.cs @@ -0,0 +1,178 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Zento +{ + public class FirstKillObjective : QuestObjective + { + public override object Message + { + get + { + // Kill 10 Deathwatch Beetle Hatchlings and return to Ansella Gryen. + return 1063316; + } + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Deathwatch Beetle Hatchlings killed: + gump.AddHtmlLocalized( 70, 260, 270, 100, 1063318, 0x12DC6BF, false, false ); + + gump.AddLabel( 70, 280, 0x64, "0" ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, "10" ); + } + else + { + base.RenderProgress( gump ); + } + } + + public FirstKillObjective() + { + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is DeathwatchBeetleHatchling ) + Complete(); + } + + public override void OnComplete() + { + System.AddObjective( new SecondKillObjective() ); + } + } + + public class SecondKillObjective : QuestObjective + { + public override object Message + { + get + { + /* Great job! One less terrible hatchling in the Waste!

+ * + * Once you've killed 10 of the Deathwatch Beetle Hatchlings, + * return to Ansella for your reward! + */ + return 1063320; + } + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Deathwatch Beetle Hatchlings killed: + gump.AddHtmlLocalized( 70, 260, 270, 100, 1063318, 0x12DC6BF, false, false ); + + gump.AddLabel( 70, 280, 0x64, "1" ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, "10" ); + } + else + { + base.RenderProgress( gump ); + } + } + + public SecondKillObjective() + { + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is DeathwatchBeetleHatchling ) + { + Complete(); + System.AddObjective( new ThirdKillObjective( 2 ) ); + } + } + + public override void OnRead() + { + if ( !Completed ) + { + Complete(); + System.AddObjective( new ThirdKillObjective( 1 ) ); + } + } + } + + public class ThirdKillObjective : QuestObjective + { + public override object Message + { + get + { + // Continue killing Deathwatch Beetle Hatchlings. + return 1063319; + } + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + // Deathwatch Beetle Hatchlings killed: + gump.AddHtmlLocalized( 70, 260, 270, 100, 1063318, 0x12DC6BF, false, false ); + + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, "10" ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override int MaxProgress{ get{ return 10; } } + + public ThirdKillObjective( int startingProgress ) + { + CurProgress = startingProgress; + } + + public ThirdKillObjective() + { + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is DeathwatchBeetleHatchling ) + CurProgress++; + } + + public override void OnComplete() + { + System.AddObjective( new ReturnObjective() ); + } + } + + public class ReturnObjective : QuestObjective + { + public override object Message + { + get + { + // Return to Ansella Gryen for your reward. + return 1063313; + } + } + + public ReturnObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new EndConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Terrible Hatchlings/TerribleHatchlingsQuest.cs b/Scripts/Engines/Quests/Terrible Hatchlings/TerribleHatchlingsQuest.cs new file mode 100644 index 0000000..a7d2379 --- /dev/null +++ b/Scripts/Engines/Quests/Terrible Hatchlings/TerribleHatchlingsQuest.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Zento +{ + public class TerribleHatchlingsQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( AcceptConversation ), + typeof( DirectionConversation ), + typeof( TakeCareConversation ), + typeof( EndConversation ), + typeof( FirstKillObjective ), + typeof( SecondKillObjective ), + typeof( ThirdKillObjective ), + typeof( ReturnObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // Terrible Hatchlings + return 1063314; + } + } + + public override object OfferMessage + { + get + { + /* The Deathwatch Beetle Hatchlings have trampled through my fields + * again, what a nuisance! Please help me get rid of the terrible + * hatchlings. If you kill 10 of them, you will be rewarded. + * The Deathwatch Beetle Hatchlings live in The Waste - + * the desert close to this city.

+ * + * Will you accept this challenge? + */ + return 1063315; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.MaxValue; } } + public override bool IsTutorial{ get{ return true; } } + + public override int Picture{ get{ return 0x15CF; } } + + public TerribleHatchlingsQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public TerribleHatchlingsQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Conversations.cs b/Scripts/Engines/Quests/The Summoning/Conversations.cs new file mode 100644 index 0000000..ee36e0b --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Conversations.cs @@ -0,0 +1,93 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Doom +{ + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* You have accepted Victoria's help. She requires 1000 Daemon + * bones to summon the devourer.

+ * + * You may hand Victoria the bones as you collect them and she + * will keep count of how many you have brought her.

+ * + * Daemon bones can be collected via various means throughout + * Dungeon Doom.

+ * + * Good luck. + */ + return 1050027; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new CollectBonesObjective() ); + } + } + + public class VanquishDaemonConversation : QuestConversation + { + public override object Message + { + get + { + /* Well done brave soul. I shall summon the beast to the circle + * of stones just South-East of here. Take great care - the beast + * takes many forms. Now hurry... + */ + return 1050021; + } + } + + public VanquishDaemonConversation() + { + } + + public override void OnRead() + { + Victoria victoria = ((TheSummoningQuest)System).Victoria; + + if ( victoria == null ) + { + System.From.SendMessage( "Internal error: unable to find Victoria. Quest unable to continue." ); + System.Cancel(); + } + else + { + SummoningAltar altar = victoria.Altar; + + if ( altar == null ) + { + System.From.SendMessage( "Internal error: unable to find summoning altar. Quest unable to continue." ); + System.Cancel(); + } + else if ( altar.Daemon == null || !altar.Daemon.Alive ) + { + BoneDemon daemon = new BoneDemon(); + + daemon.MoveToWorld( altar.Location, altar.Map ); + altar.Daemon = daemon; + + System.AddObjective( new VanquishDaemonObjective( daemon ) ); + } + else + { + victoria.SayTo( System.From, "The devourer has already been summoned." ); + + ((TheSummoningQuest)System).WaitForSummon = true; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Items/BellOfTheDead.cs b/Scripts/Engines/Quests/The Summoning/Items/BellOfTheDead.cs new file mode 100644 index 0000000..75cdc10 --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Items/BellOfTheDead.cs @@ -0,0 +1,135 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.Quests.Doom +{ + public class BellOfTheDead : Item + { + public override int LabelNumber{ get{ return 1050018; } } // bell of the dead + + [Constructable] + public BellOfTheDead() : base( 0x91A ) + { + Hue = 0x835; + Movable = false; + } + + private Chyloth m_Chyloth; + private SkeletalDragon m_Dragon; + private bool m_Summoning; + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public Chyloth Chyloth + { + get{ return m_Chyloth; } + set{ m_Chyloth = value; } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public SkeletalDragon Dragon + { + get{ return m_Dragon; } + set{ m_Dragon = value; } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public bool Summoning + { + get{ return m_Summoning; } + set{ m_Summoning = value; } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + BeginSummon( from ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public virtual void BeginSummon( Mobile from ) + { + if ( m_Chyloth != null && !m_Chyloth.Deleted ) + { + from.SendLocalizedMessage( 1050010 ); // The ferry man has already been summoned. There is no need to ring for him again. + } + else if ( m_Dragon != null && !m_Dragon.Deleted ) + { + from.SendLocalizedMessage( 1050017 ); // The ferryman has recently been summoned already. You decide against ringing the bell again so soon. + } + else if ( !m_Summoning ) + { + m_Summoning = true; + + Effects.PlaySound( GetWorldLocation(), Map, 0x100 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 8.0 ), new TimerStateCallback( EndSummon ), from ); + } + } + + public virtual void EndSummon( object state ) + { + Mobile from = (Mobile)state; + + if ( m_Chyloth != null && !m_Chyloth.Deleted ) + { + from.SendLocalizedMessage( 1050010 ); // The ferry man has already been summoned. There is no need to ring for him again. + } + else if ( m_Dragon != null && !m_Dragon.Deleted ) + { + from.SendLocalizedMessage( 1050017 ); // The ferryman has recently been summoned already. You decide against ringing the bell again so soon. + } + else if ( m_Summoning ) + { + m_Summoning = false; + + Point3D loc = GetWorldLocation(); + + loc.Z -= 16; + + Effects.SendLocationParticles( EffectItem.Create( loc, Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 0, 0, 2023, 0 ); + Effects.PlaySound( loc, Map, 0x1FE ); + + m_Chyloth = new Chyloth(); + + m_Chyloth.Direction = (Direction)(7 & (4 + (int)from.GetDirectionTo( loc ))); + m_Chyloth.MoveToWorld( loc, Map ); + + m_Chyloth.Bell = this; + m_Chyloth.AngryAt = from; + m_Chyloth.BeginGiveWarning(); + m_Chyloth.BeginRemove( TimeSpan.FromSeconds( 40.0 ) ); + } + } + + public BellOfTheDead( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Chyloth ); + writer.Write( (Mobile) m_Dragon ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Chyloth = reader.ReadMobile() as Chyloth; + m_Dragon = reader.ReadMobile() as SkeletalDragon; + + if ( m_Chyloth != null ) + m_Chyloth.Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Items/ChylothShroud.cs b/Scripts/Engines/Quests/The Summoning/Items/ChylothShroud.cs new file mode 100644 index 0000000..e39084f --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Items/ChylothShroud.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Engines.Quests.Doom +{ + public class ChylothShroud : Item + { + [Constructable] + public ChylothShroud() : base( 0x204E ) + { + Hue = 0x846; + Layer = Layer.OuterTorso; + } + + public ChylothShroud( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Items/ChylothStaff.cs b/Scripts/Engines/Quests/The Summoning/Items/ChylothStaff.cs new file mode 100644 index 0000000..2d5feed --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Items/ChylothStaff.cs @@ -0,0 +1,35 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Engines.Quests.Doom +{ + public class ChylothStaff : BlackStaff + { + public override int LabelNumber{ get{ return 1041111; } } // a magic staff + + [Constructable] + public ChylothStaff() + { + Hue = 0x482; + } + + public ChylothStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Items/GoldenSkull.cs b/Scripts/Engines/Quests/The Summoning/Items/GoldenSkull.cs new file mode 100644 index 0000000..7ec7a8c --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Items/GoldenSkull.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Engines.Quests.Doom +{ + public class GoldenSkull : Item + { + public override int LabelNumber{ get{ return 1061619; } } // a golden skull + + [Constructable] + public GoldenSkull() : base( Utility.Random( 0x1AE2, 3 ) ) + { + Weight = 1.0; + Hue = 0x8A5; + LootType = LootType.Blessed; + } + + public GoldenSkull( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Items/GrandGrimoire.cs b/Scripts/Engines/Quests/The Summoning/Items/GrandGrimoire.cs new file mode 100644 index 0000000..91336f6 --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Items/GrandGrimoire.cs @@ -0,0 +1,36 @@ +using System; + +namespace Server.Engines.Quests.Doom +{ + public class GrandGrimoire : Item + { + public override int LabelNumber{ get{ return 1060801; } } // The Grand Grimoire + + [Constructable] + public GrandGrimoire() : base( 0xEFA ) + { + Weight = 1.0; + Hue = 0x835; + Layer = Layer.OneHanded; + LootType = LootType.Blessed; + } + + public GrandGrimoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Items/SummoningAltar.cs b/Scripts/Engines/Quests/The Summoning/Items/SummoningAltar.cs new file mode 100644 index 0000000..bb86249 --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Items/SummoningAltar.cs @@ -0,0 +1,64 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Doom +{ + public class SummoningAltar : AbbatoirAddon + { + private BoneDemon m_Daemon; + + public BoneDemon Daemon + { + get{ return m_Daemon; } + set + { + m_Daemon = value; + CheckDaemon(); + } + } + + public void CheckDaemon() + { + if ( m_Daemon == null || !m_Daemon.Alive ) + { + m_Daemon = null; + Hue = 0; + } + else + { + Hue = 0x66D; + } + } + + [Constructable] + public SummoningAltar() + { + } + + public SummoningAltar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Daemon ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Daemon = reader.ReadMobile() as BoneDemon; + + CheckDaemon(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Mobiles/Chyloth.cs b/Scripts/Engines/Quests/The Summoning/Mobiles/Chyloth.cs new file mode 100644 index 0000000..4549c95 --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Mobiles/Chyloth.cs @@ -0,0 +1,323 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; +using Server.Engines.PartySystem; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Doom +{ + public class Chyloth : BaseQuester + { + [Constructable] + public Chyloth() : base( "the Ferryman" ) + { + } + + public Chyloth( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x8455; + Body = 0x190; + + Name = "Chyloth"; + } + + public override void InitOutfit() + { + EquipItem( new ChylothShroud() ); + EquipItem( new ChylothStaff() ); + } + + private Mobile m_AngryAt; + private BellOfTheDead m_Bell; + + public BellOfTheDead Bell + { + get{ return m_Bell; } + set{ m_Bell = value; } + } + + public Mobile AngryAt + { + get{ return m_AngryAt; } + set{ m_AngryAt = value; } + } + + public virtual void BeginGiveWarning() + { + if ( Deleted || m_AngryAt == null ) + return; + + Timer.DelayCall( TimeSpan.FromSeconds( 4.0 ), new TimerCallback( EndGiveWarning ) ); + } + + public virtual void EndGiveWarning() + { + if ( Deleted || m_AngryAt == null ) + return; + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1050013, m_AngryAt.Name ); // You have summoned me in vain ~1_NAME~! Only the dead may cross! + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1050014 ); // Why have you disturbed me, mortal?!? + + BeginSummonDragon(); + } + + public virtual void BeginSummonDragon() + { + if ( Deleted || m_AngryAt == null ) + return; + + Timer.DelayCall( TimeSpan.FromSeconds( 30.0 ), new TimerCallback( EndSummonDragon ) ); + } + + public virtual void BeginRemove( TimeSpan delay ) + { + Timer.DelayCall( delay, new TimerCallback( EndRemove ) ); + } + + public virtual void EndRemove() + { + if ( Deleted ) + return; + + Point3D loc = this.Location; + Map map = this.Map; + + Effects.SendLocationParticles( EffectItem.Create( loc, map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 0, 0, 2023, 0 ); + Effects.PlaySound( loc, map, 0x1FE ); + + Delete(); + } + + private static int[] m_Offsets = new int[] + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1 + }; + + public virtual void EndSummonDragon() + { + if ( Deleted || m_AngryAt == null ) + return; + + Map map = m_AngryAt.Map; + + if ( map == null ) + return; + + if ( !m_AngryAt.Region.IsPartOf( "Doom" ) ) + return; + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1050015 ); // Feel the wrath of my legions!!! + PublicOverheadMessage( MessageType.Regular, 0x3B2, false, "MUHAHAHAHA HAHAH HAHA" ); // A wee bit crazy, aren't we? + + SkeletalDragon dragon = new SkeletalDragon(); + + int offset = Utility.Random( 8 ) * 2; + + bool foundLoc = false; + + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = m_AngryAt.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = m_AngryAt.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if ( map.CanSpawnMobile( x, y, m_AngryAt.Z ) ) + { + dragon.MoveToWorld( new Point3D( x, y, m_AngryAt.Z ), map ); + foundLoc = true; + break; + } + else + { + int z = map.GetAverageZ( x, y ); + + if ( map.CanSpawnMobile( x, y, z ) ) + { + dragon.MoveToWorld( new Point3D( x, y, z ), map ); + foundLoc = true; + break; + } + } + } + + if ( !foundLoc ) + dragon.MoveToWorld( m_AngryAt.Location, map ); + + dragon.Combatant = m_AngryAt; + + if ( m_Bell != null ) + m_Bell.Dragon = dragon; + } + + public static void TeleportToFerry( Mobile from ) + { + Point3D loc = new Point3D( 408, 251, 2 ); + Map map = Map.Malas; + + Effects.SendLocationParticles( EffectItem.Create( loc, map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 0, 0, 2023, 0 ); + Effects.PlaySound( loc, map, 0x1FE ); + + BaseCreature.TeleportPets( from, loc, map ); + + from.MoveToWorld( loc, map ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is GoldenSkull ) + { + dropped.Delete(); + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1050046, from.Name ); // Very well, ~1_NAME~, I accept your token. You may cross. + BeginRemove( TimeSpan.FromSeconds( 4.0 ) ); + + Party p = PartySystem.Party.Get( from ); + + if ( p != null ) + { + for ( int i = 0; i < p.Members.Count; ++i ) + { + PartyMemberInfo pmi = (PartyMemberInfo)p.Members[i]; + Mobile member = pmi.Mobile; + + if ( member != from && member.Map == Map.Malas && member.Region.IsPartOf( "Doom" ) ) + { + if ( m_AngryAt == member ) + m_AngryAt = null; + + member.CloseGump( typeof( ChylothPartyGump ) ); + member.SendGump( new ChylothPartyGump( from, member ) ); + } + } + } + + if ( m_AngryAt == from ) + m_AngryAt = null; + + TeleportToFerry( from ); + + return false; + } + + return base.OnDragDrop( from, dropped ); + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return false; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ChylothPartyGump : Gump + { + private Mobile m_Leader; + private Mobile m_Member; + + public ChylothPartyGump( Mobile leader, Mobile member ) : base( 150, 50 ) + { + m_Leader = leader; + m_Member = member; + + Closable = false; + + AddPage( 0 ); + + AddImage( 0, 0, 3600 ); + + AddImageTiled( 0, 14, 15, 200, 3603 ); + AddImageTiled( 380, 14, 14, 200, 3605 ); + AddImage( 0, 201, 3606 ); + AddImageTiled( 15, 201, 370, 16, 3607 ); + AddImageTiled( 15, 0, 370, 16, 3601 ); + AddImage( 380, 0, 3602 ); + AddImage( 380, 201, 3608 ); + AddImageTiled( 15, 15, 365, 190, 2624 ); + + AddRadio( 30, 140, 9727, 9730, true, 1 ); + AddHtmlLocalized( 65, 145, 300, 25, 1050050, 0x7FFF, false, false ); // Yes, let's go! + + AddRadio( 30, 175, 9727, 9730, false, 0 ); + AddHtmlLocalized( 65, 178, 300, 25, 1050049, 0x7FFF, false, false ); // No thanks, I'd rather stay here. + + AddHtmlLocalized( 30, 20, 360, 35, 1050047, 0x7FFF, false, false ); // Another player has paid Chyloth for your passage across lake Mortis: + + AddHtmlLocalized( 30, 105, 345, 40, 1050048, 0x5B2D, false, false ); // Do you wish to accept their invitation at this time? + + AddImage( 65, 72, 5605 ); + + AddImageTiled( 80, 90, 200, 1, 9107 ); + AddImageTiled( 95, 92, 200, 1, 9157 ); + + AddLabel( 90, 70, 1645, leader.Name ); + + AddButton( 290, 175, 247, 248, 2, GumpButtonType.Reply, 0 ); + + AddImageTiled( 15, 14, 365, 1, 9107 ); + AddImageTiled( 380, 14, 1, 190, 9105 ); + AddImageTiled( 15, 205, 365, 1, 9107 ); + AddImageTiled( 15, 14, 1, 190, 9105 ); + AddImageTiled( 0, 0, 395, 1, 9157 ); + AddImageTiled( 394, 0, 1, 217, 9155 ); + AddImageTiled( 0, 216, 395, 1, 9157 ); + AddImageTiled( 0, 0, 1, 217, 9155 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 2 && info.IsSwitched( 1 ) ) + { + if ( m_Member.Region.IsPartOf( "Doom" ) ) + { + m_Leader.SendLocalizedMessage( 1050054, m_Member.Name ); // ~1_NAME~ has accepted your invitation to cross lake Mortis. + + Chyloth.TeleportToFerry( m_Member ); + } + else + { + m_Member.SendLocalizedMessage( 1050051 ); // The invitation has been revoked. + } + } + else + { + m_Member.SendLocalizedMessage( 1050052 ); // You have declined their invitation. + m_Leader.SendLocalizedMessage( 1050053, m_Member.Name ); // ~1_NAME~ has declined your invitation to cross lake Mortis. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Mobiles/Victoria.cs b/Scripts/Engines/Quests/The Summoning/Mobiles/Victoria.cs new file mode 100644 index 0000000..6777c92 --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Mobiles/Victoria.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Engines.Quests.Doom +{ + public class Victoria : BaseQuester + { + public override int TalkNumber{ get{ return 6159; } } // Ask about Chyloth + public override bool ClickTitle{ get{ return true; } } + public override bool IsActiveVendor{ get{ return true; } } + public override bool DisallowAllMoves{ get{ return false; } } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBMage() ); + } + + [Constructable] + public Victoria() : base( "the Sorceress" ) + { + } + + public Victoria( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Female = true; + Hue = 0x8835; + Body = 0x191; + + Name = "Victoria"; + } + + private SummoningAltar m_Altar; + + private const int AltarRange = 24; + + public SummoningAltar Altar + { + get + { + if ( m_Altar == null || m_Altar.Deleted || m_Altar.Map != this.Map || !Utility.InRange( m_Altar.Location, this.Location, AltarRange ) ) + { + foreach ( Item item in GetItemsInRange( AltarRange ) ) + { + if ( item is SummoningAltar ) + { + m_Altar = (SummoningAltar)item; + break; + } + } + } + + return m_Altar; + } + } + + public override void InitOutfit() + { + EquipItem( new GrandGrimoire() ); + + EquipItem( SetHue( new Sandals(), 0x455 ) ); + EquipItem( SetHue( new SkullCap(), 0x455 ) ); + EquipItem( SetHue( new PlainDress(), 0x455 ) ); + + HairItemID = 0x203C; + HairHue = 0x482; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is TheSummoningQuest ) + { + if ( dropped is DaemonBone ) + { + DaemonBone bones = (DaemonBone)dropped; + + QuestObjective obj = qs.FindObjective( typeof( CollectBonesObjective ) ); + + if ( obj != null && !obj.Completed ) + { + int need = obj.MaxProgress - obj.CurProgress; + + if ( bones.Amount < need ) + { + obj.CurProgress += bones.Amount; + bones.Delete(); + + qs.ShowQuestLogUpdated(); + } + else + { + obj.Complete(); + bones.Consume( need ); + + if ( !bones.Deleted ) + { + // TODO: Accurate? + SayTo( from, 1050038 ); // You have already given me all the Daemon bones necessary to weave the spell. Keep these for a later time. + } + } + } + else + { + // TODO: Accurate? + SayTo( from, 1050038 ); // You have already given me all the Daemon bones necessary to weave the spell. Keep these for a later time. + } + + return false; + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return ( to.Quest == null && QuestSystem.CanOfferQuest( to, typeof( TheSummoningQuest ) ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs == null && QuestSystem.CanOfferQuest( player, typeof( TheSummoningQuest ) ) ) + { + Direction = GetDirectionTo( player ); + new TheSummoningQuest( this, player ).SendOffer(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/Objectives.cs b/Scripts/Engines/Quests/The Summoning/Objectives.cs new file mode 100644 index 0000000..4c37604 --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/Objectives.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Engines.Quests.Doom +{ + public class CollectBonesObjective : QuestObjective + { + public override object Message + { + get + { + /* Find 1000 Daemon bones and hand them + * to Victoria as you find them. + */ + return 1050026; + } + } + + public override int MaxProgress{ get{ return 1000; } } + + public CollectBonesObjective() + { + } + + public override void OnComplete() + { + Victoria victoria = ((TheSummoningQuest)System).Victoria; + + if ( victoria == null ) + { + System.From.SendMessage( "Internal error: unable to find Victoria. Quest unable to continue." ); + System.Cancel(); + } + else + { + SummoningAltar altar = victoria.Altar; + + if ( altar == null ) + { + System.From.SendMessage( "Internal error: unable to find summoning altar. Quest unable to continue." ); + System.Cancel(); + } + else if ( altar.Daemon == null || !altar.Daemon.Alive ) + { + System.AddConversation( new VanquishDaemonConversation() ); + } + else + { + victoria.SayTo( System.From, "The devourer has already been summoned. Return when the devourer has been slain and I will summon it for you." ); + ((TheSummoningQuest)System).WaitForSummon = true; + } + } + } + + public override void RenderMessage( BaseQuestGump gump ) + { + if ( CurProgress > 0 && CurProgress < MaxProgress ) + gump.AddHtmlObject( 70, 130, 300, 100, 1050028, BaseQuestGump.Blue, false, false ); // Victoria has accepted the Daemon bones, but the requirement is not yet met. + else + base.RenderMessage( gump ); + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( CurProgress > 0 && CurProgress < MaxProgress ) + { + gump.AddHtmlObject( 70, 260, 270, 100, 1050019, BaseQuestGump.Blue, false, false ); // Number of bones collected: + + gump.AddLabel( 70, 280, 100, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 100, "/" ); + gump.AddLabel( 130, 280, 100, MaxProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + } + + public class VanquishDaemonObjective : QuestObjective + { + private BoneDemon m_Daemon; + private Corpse m_CorpseWithSkull; + + public Corpse CorpseWithSkull + { + get{ return m_CorpseWithSkull; } + set{ m_CorpseWithSkull = value; } + } + + public override object Message + { + get + { + /* Go forth and vanquish the devourer that has been summoned! + */ + return 1050037; + } + } + + public VanquishDaemonObjective( BoneDemon daemon ) + { + m_Daemon = daemon; + } + + // Serialization + public VanquishDaemonObjective() + { + } + + public override void CheckProgress() + { + if ( m_Daemon == null || !m_Daemon.Alive ) + Complete(); + } + + public override void OnComplete() + { + Victoria victoria = ((TheSummoningQuest)System).Victoria; + + if ( victoria != null ) + { + SummoningAltar altar = victoria.Altar; + + if ( altar != null ) + altar.CheckDaemon(); + } + + PlayerMobile from = System.From; + + if ( !from.Alive ) + { + from.SendLocalizedMessage( 1050033 ); // The devourer lies dead, unfortunately so do you. You cannot claim your reward while dead. You will need to face him again. + ((TheSummoningQuest)System).WaitForSummon = true; + } + else + { + bool hasRights = true; + + if ( m_Daemon != null ) + { + List lootingRights = BaseCreature.GetLootingRights( m_Daemon.DamageEntries, m_Daemon.HitsMax ); + + for ( int i = 0; i < lootingRights.Count; ++i ) + { + DamageStore ds = lootingRights[i]; + + if ( ds.m_HasRight && ds.m_Mobile == from ) + { + hasRights = true; + break; + } + } + } + + if ( !hasRights ) + { + from.SendLocalizedMessage( 1050034 ); // The devourer lies dead. Unfortunately you did not sufficiently prove your worth in combating the devourer. Victoria shall summon another incarnation of the devourer to the circle of stones. Try again noble adventurer. + ((TheSummoningQuest)System).WaitForSummon = true; + } + else + { + from.SendLocalizedMessage( 1050035 ); // The devourer lies dead. Search his corpse to claim your prize! + + if ( m_Daemon != null ) + m_CorpseWithSkull = m_Daemon.Corpse as Corpse; + } + } + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Daemon = reader.ReadMobile() as BoneDemon; + m_CorpseWithSkull = reader.ReadItem() as Corpse; + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Mobile) m_Daemon ); + writer.Write( (Item) m_CorpseWithSkull ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/The Summoning/TheSummoningQuest.cs b/Scripts/Engines/Quests/The Summoning/TheSummoningQuest.cs new file mode 100644 index 0000000..bb20b1b --- /dev/null +++ b/Scripts/Engines/Quests/The Summoning/TheSummoningQuest.cs @@ -0,0 +1,163 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Doom +{ + public class TheSummoningQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Doom.AcceptConversation ), + typeof( Doom.CollectBonesObjective ), + typeof( Doom.VanquishDaemonConversation ), + typeof( Doom.VanquishDaemonObjective ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + private Victoria m_Victoria; + private bool m_WaitForSummon; + + public Victoria Victoria + { + get{ return m_Victoria; } + } + + public bool WaitForSummon + { + get{ return m_WaitForSummon; } + set{ m_WaitForSummon = value; } + } + + public override object Name + { + get + { + // The Summoning + return 1050025; + } + } + + public override object OfferMessage + { + get + { + /* Victoria turns to you and smiles...

+ * + * Chyloth, eh? He is the ferry man of lake Mortis, beyond which lies + * the nest of the The Dark Father - the fountainhead of all the evil + * that you see around you here.

+ * + * 800 and some years ago, my sisters and I persuaded the ferry man Chyloth + * to take us across the lake to battle the The Dark Father. + * My party was utterly destroyed, except for me. For my insolence, I was + * cursed by the The Dark Father to wander these halls for eternity, + * unable to die - unable to leave.

+ * + * Chyloth usually only crosses over the souls of the undead, but he can be + * persuaded otherwise...with a token of gold, in the form of a human skull. + * Such a gem can be found only in the belly of the hellspawn known as + * the devourer.

+ * + * I can help you summon the beast from the depths of the abyss, but I require + * 1000 Daemon bones to do so. If you accept my help, I will store the Daemon + * bones for you until you have collected all 1000 of them. Once the bones + * are collected in full, I will summon the beast for you, which you must + * slay to claim your prize.

+ * + * Do you accept? + */ + return 1050020; + } + } + + public override bool IsTutorial{ get{ return false; } } + public override TimeSpan RestartDelay{ get{ return TimeSpan.Zero; } } + public override int Picture{ get{ return 0x15B5; } } + + // NOTE: Quest not entirely OSI-accurate: some changes made to prevent numerous OSI bugs + + public override void Slice() + { + if ( m_WaitForSummon && m_Victoria != null ) + { + SummoningAltar altar = m_Victoria.Altar; + + if ( altar != null && (altar.Daemon == null || !altar.Daemon.Alive) ) + { + if ( From.Map == m_Victoria.Map && From.InRange( m_Victoria, 8 ) ) + { + m_WaitForSummon = false; + + AddConversation( new VanquishDaemonConversation() ); + } + } + } + + base.Slice(); + } + + public static int GetDaemonBonesFor( BaseCreature creature ) + { + if ( creature == null || creature.Controlled || creature.Summoned ) + return 0; + + int fame = creature.Fame; + + if ( fame < 1500 ) + return Utility.Dice( 2, 5, -1 ); + else if ( fame < 20000 ) + return Utility.Dice( 2, 4, 8 ); + else + return 50; + } + + public TheSummoningQuest( Victoria victoria, PlayerMobile from ) : base( from ) + { + m_Victoria = victoria; + } + + public TheSummoningQuest() + { + } + + public override void Cancel() + { + base.Cancel(); + + QuestObjective obj = FindObjective( typeof( CollectBonesObjective ) ); + + if ( obj != null && obj.CurProgress > 0 ) + { + From.BankBox.DropItem( new DaemonBone( obj.CurProgress ) ); + + From.SendLocalizedMessage( 1050030 ); // The Daemon bones that you have thus far given to Victoria have been returned to you. + } + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Victoria = reader.ReadMobile() as Victoria; + m_WaitForSummon = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Mobile) m_Victoria ); + writer.Write( (bool) m_WaitForSummon ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs new file mode 100644 index 0000000..e78ef55 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Conversations.cs @@ -0,0 +1,970 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Haven +{ + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Important Quest Information

+ * + * During your quest, any important information that a + * NPC gives you, will appear + * in a window such as this one. You can review the information + * at any time during your quest.

+ * + * Getting Help

+ * + * Some of the text you will come across during your quest, + * will be underlined links to the codex of wisdom, + * or online help system. You can click on the text to get detailed + * information on the underlined subject. You may also access the + * Codex Of Wisdom by pressing "F1" or by clicking on the "?" on the toolbar + * at the top of your screen.

+ * + * Context Menus

+ * + * Context menus can be called up by single left-clicking + * (or Shift + single left-click, if you changed it) on most objects + * or NPCs in the world. Nearly everything, including your own avatar + * will have context menus available. Bringing up your avatar's + * context menu will give you options to cancel your quest and review + * various quest information.

+ */ + return 1049092; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindUzeraanBeginObjective() ); + } + } + + public class UzeraanTitheConversation : QuestConversation + { + public override object Message + { + get + { + /* Uzeraan greets you as you approach...

+ * + * Greetings traveler!

+ * + * I am Uzeraan, the lord of this house and overseer of this fine city, Haven. + * I know we have just met, but time is short and we need to reinforce + * the troops in the mountain pass, so I will not waste your time + * with pleasantries.

+ * + * We have been trying to fight back the wicked Horde Minions which + * have recently begun attacking our cities - but to no avail. + * We desperately need help!

+ * + * Your first task will be to assess the situation in the mountain pass, + * and help our troops defeat the Horde Minions there.

+ * + * Before I send you into battle however, it is time that I teach you a thing + * or two about the way of the Paladin.

+ * + * The Paladin

+ * + * Paladins are the holy warriors of the realm who have dedicated themselves + * as protectors of the virtues and vanquishers of all that is evil.

+ * + * Paladins have several special abilities that + * are not available to the ordinary warrior. Due to the spiritual nature of + * these abilities, the Paladin requires some amount of mana to activate them. + * In addition to mana, the Paladin is also required to spend a certain amount + * of tithing points each time a special ability + * is used.

+ * + * Tithing points and mana are automatically consumed when a special Paladin + * ability is activated. All Paladin abilities are activated through the + * Book of Chivalry

+ * + * Go now, to the shrine just East of here, just before the doors and + * tithe at least 500 gold.

+ * + * Return here when you are done. + */ + return 1060209; + } + } + + public UzeraanTitheConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new TitheGoldObjective() ); + } + } + + public class UzeraanFirstTaskConversation : QuestConversation + { + public override object Message + { + get + { + if ( System.From.Profession == 1 ) // warrior + { + /* Uzeraan greets you as you approach...

+ * + * Greetings traveler!

+ * + * I am Uzeraan, the lord of this house and overseer of this fine city, Haven. + * I know we have just met, but time is short and we need to reinforce the troops + * in the mountain pass, so I will not waste your time with pleasantries.

+ * + * We have been trying to fight back the wicked Horde Minions which have + * recently begun attacking our cities - but to no avail. We desperately need + * help!

+ * + * Your first task will be to assess the situation in the mountain pass, and + * help our troops defeat the Horde Minions there.

+ * + * Take the road marked with glowing runes, that starts just outside of this + * mansion. Before you go into battle, it would be prudent to + * review combat techniques as well as + * information on healing yourself.

+ * + * To aid you in your fight, you may also wish to + * purchase equipment from Frank the Blacksmith, + * who is standing just South of here.

+ * + * Good luck young warrior. + */ + return 1049088; + } + else if ( System.From.Profession == 2 ) // magician + { + /* Uzeraan greets you as you approach...

+ * + * Greetings traveler!

+ * + * I am Uzeraan, the lord of this house and overseer of this fine city, Haven. + * I know we have just met, but time is short and we need to reinforce + * the troops in the mountain pass, so I will not waste your time with + * pleasantries.

+ * + * We have been trying to fight back the wicked Horde Minions which have + * recently begun attacking our cities - but to no avail. We desperately + * need help!

+ * + * Your first task will be to assess the situation in the mountain pass, + * and help our troops defeat the Horde Minions there.

+ * + * Take the road marked with glowing runes, that starts just outside of this + * mansion. Before you go into battle, it would be prudent to + * review your magic skills as well as + * information on healing yourself.

+ * + * To aid you in your fight, you may also wish to + * purchase equipment from Frank the Blacksmith, + * who is standing just South of here.

+ * + * Good luck young mage. + */ + return 1049386; + } + else + { + /* Uzeraan nods at you with approval and begins to speak...

+ * + * Now that you are ready, let me give you your first task.

+ * + * As I mentioned earlier, we have been trying to fight back the wicked + * Horde Minions which have recently begun attacking our cities + * - but to no avail. Our need is great!

+ * + * Your first task will be to assess the situation in the mountain pass, + * and help our troops defeat the Horde Minions there.

+ * + * Take the road marked with glowing runes, that starts just outside of this mansion. + * Before you go into battle, it would be prudent to + * review combat techniques as well as + * information on healing yourself, + * using your Paladin ability 'Close Wounds'.

+ * + * To aid you in your fight, you may also wish to + * purchase equipment from Frank the Blacksmith, + * who is standing just South of here.

+ * + * Good luck young Paladin! + */ + return 1060388; + } + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1023676, 0xE68 ) // glowing rune + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public UzeraanFirstTaskConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new KillHordeMinionsObjective() ); + } + } + + public class UzeraanReportConversation : QuestConversation + { + public override object Message + { + get + { + if ( System.From.Profession == 2 ) // magician + { + /* You give your report to Uzeraan and after a while, he begins to + * speak...

+ * + * Your report is grim, but all hope is not lost! It has become apparent + * that our swords and spells will not drive the evil from Haven.

+ * + * The head of my order, the High Mage Schmendrick, arrived here shortly after + * you went into battle with the Horde Minions. He has brought with him a + * scroll of great power, that should aid us greatly in our battle.

+ * + * Unfortunately, the entrance to one of our mining caves collapsed recently, + * trapping our miners inside.

+ * + * Schmendrick went to install magical teleporters inside the mines so that + * the miners would have a way out. The miners have since returned, but Schmendrick has not. + * Those who have returned, all seem to have lost their minds to madness; + * mumbling strange things of "the souls of the dead seeking revenge".

+ * + * No matter. We must find Schmendrick.

+ * + * Step onto the teleporter, located against the wall, and seek Schmendrick in the mines.

+ * + * I've given you a bag with some Travel Spells, + * in case you need to make a quick escape. In addition, you may wish to cast + * the Night Sight spell on yourself before going + * into the cave, as it it's pretty dark in there.

+ * + * Now please go. Good luck, friend. + */ + return 1049387; + } + else + { + /* You give your report to Uzeraan and after a while, + * he begins to speak...

+ * + * Your report is grim, but all hope is not lost! It has become apparent + * that our swords and spells will not drive the evil from Haven.

+ * + * The head of my order, the High Mage Schmendrick, arrived here shortly after + * you went into battle with the Horde Minions. He has brought with him a + * scroll of great power, that should aid us greatly in our battle.

+ * + * Unfortunately, the entrance to one of our mining caves collapsed recently, + * trapping our miners inside.

+ * + * Schmendrick went to install magical teleporters inside the mines so that + * the miners would have a way out. The miners have since returned, but Schmendrick has not. + * Those who have returned, all seem to have lost their minds to madness; + * mumbling strange things of "the souls of the dead seeking revenge".

+ * + * No matter. We must find Schmendrick.

+ * + * Step onto the teleporter, located against the wall, and seek Schmendrick in the mines.

+ * + * I've given you a bag with some Night Sight + * and Healing potions + * to help you out along the way. Good luck. + */ + return 1049119; + } + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1026153, 0x1822 ), // teleporter + new QuestItemInfo( 1048032, 0xE76 ) // a bag + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public UzeraanReportConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindSchmendrickObjective() ); + } + } + + public class SchmendrickConversation : QuestConversation + { + public override object Message + { + get + { + if ( System.From.Profession == 5 ) // paladin + { + /* Schmendrick barely pays you any attention as you approach him. + * His mind seems to be occupied with something else. You explain to him that + * you came for the scroll of power and after a long while he begins to speak, + * but apparently still not giving you his full attention...

+ * + * Hmmm.. peculiar indeed. Very strange activity here indeed... I wonder...

+ * + * Hmmm. Oh yes! Scroll, you say? I don't have it, sorry. My apprentice + * was carrying it, and he ran off to somewhere in this cave. Find him and + * you will find the scroll.

+ * + * Be sure to bring the scroll to Uzeraan once you have it. He's the only person + * aside from myself who can read the ancient markings on the scroll. + * I need to figure out what's going on down here before I can leave. + * Strange activity indeed...

+ * + * One more thing...

+ * + * Be careful of the restless souls wandering about. They seem to be in the habit + * of spontaneously attacking people. Perhaps using your paladin ability + * Enemy of One might help you overcome the perils + * of these halls.

+ * + * Schmendrick goes back to his work and you seem to completely fade from his awareness... + */ + return 1060749; + } + else + { + /* Schmendrick barely pays you any attention as you approach him. His + * mind seems to be occupied with something else. You explain to him that + * you came for the scroll of power and after a long while he begins to speak, + * but apparently still not giving you his full attention...

+ * + * Hmmm.. peculiar indeed. Very strange activity here indeed... I wonder...

+ * + * Hmmm. Oh yes! Scroll, you say? I don't have it, sorry. My apprentice was + * carrying it, and he ran off to somewhere in this cave. Find him and you will + * find the scroll.

Be sure to bring the scroll to Uzeraan once you + * have it. He's the only person aside from myself who can read the ancient + * markings on the scroll. I need to figure out what's going on down here before + * I can leave. Strange activity indeed...

+ * + * Schmendrick goes back to his work and you seem to completely fade from his + * awareness... + */ + return 1049322; + } + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1023637, 0xE34 ) // scroll + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public SchmendrickConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindApprenticeObjective() ); + } + } + + public class UzeraanScrollOfPowerConversation : QuestConversation + { + public override object Message + { + get + { + /* Uzeraan carefully unravels the scroll and begins to read... + * after a short while his face lights up with a smile and he speaks to you...

+ * + * This is wonderful, friend! For your troubles I've given you a treasure map + * I had laying about, along with a shovel to dig up the treasure. + * Feel free to find the treasure at your leisure.

+ * + * Now let us get back to the business of this scroll. The only trouble, + * is that this scroll calls for some special ingredients that I do + * not have on hand.

+ * + * Though it may involve some danger, I will ask of you to find + * these reagents for me.

+ * + * There are three reagents I need to complete the spell.

+ * + * The first thing I need is some Fertile Dirt.

+ * + * There lives a Dryad on this island who I know would have such a thing on hand. + * I have recalibrated the teleporter to transport you to the Dryad's grove, + * which lies South-West of this mansion.

+ * + * Tell her Uzeraan sent you, and she should cooperate.

+ * + * Should you get into trouble out there or should you lose your way, do not worry. + * I have also given you a magical horn - a Horn of Retreat. + * Play the horn at any time to open a magical gateway that leads back to this mansion.

+ * + * Should your horn run out of charges, + * simply hand me or any of my mansion guards the horn to have it recharged.

+ * + * Good luck friend. + */ + return 1049325; + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1048030, 0x14EB ), // a Treasure Map + new QuestItemInfo( 1023969, 0xF81 ), // Fertile Dirt + new QuestItemInfo( 1049117, 0xFC4 ) // Horn of Retreat + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public UzeraanScrollOfPowerConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindDryadObjective() ); + } + } + + public class DryadConversation : QuestConversation + { + public override object Message + { + get + { + /* The Dryad watches hungrily as you approach, giving you an + * uneasy feeling in the pit of your stomach. You explain that + * Uzeraan has sent you for a quantity of fertile dirt. With a wide grin + * and in a slightly hoarse voice she replies...

+ * + * Fertile Dirt, eh? Well, I have a few patches here...but what have + * you brought me in return? Came empty-handed did you? That's unfortunate + * indeed... but since you were sent by my dear friend Uzeraan, I supposed + * I could oblige you.

+ * + * The Dryad digs around in the ground and hands you a patch of Fertile Dirt.

+ * + * With a smile she goes back to her work...
+ */ + return 1049326; + } + } + + public DryadConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnFertileDirtObjective() ); + } + } + + public class UzeraanFertileDirtConversation : QuestConversation + { + public override object Message + { + get + { + if ( System.From.Profession == 2 ) // magician + { + /* Uzeraan takes the dirt from you and smiles...

+ * + * Wonderful! I knew I could count on you. As a token of my appreciation + * I've given you a bag with some reagents + * as well as some spell scrolls. They should + * help out a bit.

+ * + * The next item I need is a Vial of Blood. I know it seems strange, + * but that's what the formula asks for. I have some locked away in a chest + * not far from here. It's only a short distance from the mansion. Let me + * give you directions...

Exit the front door to the East. Then follow + * the path to the North. You will pass by several pedestals with lanterns on + * them. Continue on this path until you run into a small hut. Walk up the + * stairs and through the door. Inside you will find a chest. Open it and + * bring me a Vial of Blood from inside the chest. It's very easy to find. + * Just follow the road and you can't miss it.

+ * + * Good luck! + */ + return 1049388; + } + else + { + /* Uzeraan takes the dirt from you and smiles...

+ * + * Wonderful! I knew I could count on you. As a token of my appreciation + * I've given you a bag with some bandages as well as some healing potions. + * They should help out a bit.

+ * + * The next item I need is a Vial of Blood. I know it seems strange, + * but that's what the formula asks for. I have some locked away in a chest + * not far from here. It's only a short distance from the mansion. Let me give + * you directions...

+ * + * Exit the front door to the East. Then follow the path to the North. + * You will pass by several pedestals with lanterns on them. Continue on this + * path until you run into a small hut. Walk up the stairs and through the door. + * Inside you will find a chest. Open it and bring me a Vial of Blood + * from inside the chest. It's very easy to find. Just follow the road and you + * can't miss it.

+ * + * Good luck! + */ + return 1049329; + } + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1023965, 0xF7D ), // Daemon Blood + new QuestItemInfo( 1022581, 0xA22 ), // lantern + }; + + public override QuestItemInfo[] Info{ get{ return m_Info; } } + + public UzeraanFertileDirtConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GetDaemonBloodObjective() ); + } + } + + public class UzeraanDaemonBloodConversation : QuestConversation + { + public override object Message + { + get + { + if ( System.From.Profession == 2 ) // magician + { + //return 1049389; // localized message is bugged + return "You hand Uzeraan the Vial of Blood, which he hastily accepts...
" + + "
" + + "Excellent work! Only one reagent remains and the spell is complete! The final " + + "requirement is a Daemon Bone, which will not be as easily acquired as the " + + "previous two components.
" + + "
" + + "There is a haunted graveyard on this island, which is the home to many undead " + + "creatures. Dispose of the undead as you see fit. Be sure to search their remains " + + "after you have smitten them, to check for a Daemon Bone. I'm quite sure " + + "that you will find what we seek, if you are thorough enough with your " + + "extermination.
" + + "
" + + "Take these explosion spell scrolls and magical wizard's hat to aid you in your " + + "battle. The scrolls should help you make short work of the undead.
" + + "
" + + "Return here when you have found a Daemon Bone."; + } + else + { + /* You hand Uzeraan the Vial of Blood, which he hastily accepts...

+ * + * Excellent work! Only one reagent remains and the spell is complete! + * The final requirement is a Daemon Bone, which will not be as easily + * acquired as the previous two components.

+ * + * There is a haunted graveyard on this island, which is the home to many + * undead creatures. Dispose of the undead as you see fit. Be sure to search + * their remains after you have smitten them, to check for a Daemon Bone. + * I'm quite sure that you will find what we seek, if you are thorough enough + * with your extermination.

+ * + * Take this magical silver sword to aid you in your battle. Silver weapons + * will damage the undead twice as much as your regular weapon.

+ * + * Return here when you have found a Daemon Bone. + */ + return 1049333; + } + } + } + + private static QuestItemInfo[] m_Info = new QuestItemInfo[] + { + new QuestItemInfo( 1017412, 0xF80 ), // Daemon Bone + }; + + private static QuestItemInfo[] m_InfoPaladin = new QuestItemInfo[] + { + new QuestItemInfo( 1017412, 0xF80 ), // Daemon Bone + new QuestItemInfo( 1060577, 0x1F14 ), // Recall Rune + }; + + public override QuestItemInfo[] Info + { + get + { + if ( System.From.Profession == 5 ) // paladin + return m_InfoPaladin; + else + return m_Info; + } + } + + public UzeraanDaemonBloodConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new GetDaemonBoneObjective() ); + } + } + + public class UzeraanDaemonBoneConversation : QuestConversation + { + public override object Message + { + get + { + /* As you hand Uzeraan the final reagent, he nods at you with approval + * and starts searching through the pockets of his robe...

+ * + * After a short while he hands you a small pouch...


+ * + * There you are. Your contract of employment with me has expired and so here + * is your pay. 2000 gold in the form of a check and a magical sextant that + * will help you find Moongates and Banks.

+ * + * Before you can actually spend the money I have given you, however, you must + * cash the check.

+ * + * I have recalibrated the teleporter to take you to the Haven + * Bank. Step onto the teleporter to be taken + * to the bank, which lies South-East of here.

+ * + * Thank you for all your help friend. I hope we shall meet + * each other again in the future.

+ * + * Farewell. + */ + return 1049335; + } + } + + public UzeraanDaemonBoneConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new CashBankCheckObjective() ); + } + } + + public class BankerConversation : QuestConversation + { + public override object Message + { + get + { + /* The banker smiles at you and greets you in a loud and robust voice...

+ * + * Well hello there adventurer! I see you've learned how to cash checks. Wonderful! + * Let me tell you a bit about the banks in this world...

+ * + * Anything that you place into any bank box, can be retrieved from any other + * bank box in the land. For instance, if you place an item into a bank box in + * Britain, it can be retrieved from your bank box in Moonglow or any other city.

+ * + * Bank boxes are very secure. So secure, in fact, that no one can ever get into + * your bank box except for yourself. Security is hard to come by these days, + * but you can trust in the banking system of Britannia! We shall not let you down!

+ * + * I hope to be seeing much more of you as your riches grow! May your bank box overflow + * with the spoils of your adventures.

Farewell adventurer, you are now free to + * explore the world on your own. + */ + return 1060137; + } + } + + public BankerConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class RadarConversation : QuestConversation + { + public override object Message + { + get + { + /* If you are leaving the mansion, you should learn about the Radar Map.

+ * + * The Radar Map (or Overhead View) can be opened by pressing 'ALT-R' on your + * keyboard. It shows your immediate surroundings from a bird's eye view.

+ * + * Pressing ALT-R twice, will enlarge the Radar Map a little. Use the Radar Map + * often as you travel throughout the world to familiarize yourself with your surroundings. + */ + return 1049660; + } + } + + public override bool Logged{ get{ return false; } } + + public RadarConversation() + { + } + } + + public class LostScrollOfPowerConversation : QuestConversation + { + private bool m_FromUzeraan; + + public override object Message + { + get + { + if ( m_FromUzeraan ) + { + /* You return without the scroll???

+ * + * All hope is lost without it, friend. Return to the mines and talk to + * Schmendrick to see if he can help us out of this predicament. + */ + return 1049377; + } + else + { + /* You've lost the scroll? Argh! I will have to try and re-construct + * the scroll from memory. Bring me a blank scroll, which you can + * purchase from the mage shop just + * East of Uzeraan's mansion in Haven.

+ * + * Return the scroll to me and I will try to make another scroll for you.

+ * + * When you return, be sure to hand me the scroll (drag and drop). + */ + return 1049345; + } + } + } + + public override bool Logged{ get{ return false; } } + + public LostScrollOfPowerConversation( bool fromUzeraan ) + { + m_FromUzeraan = fromUzeraan; + } + + public LostScrollOfPowerConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_FromUzeraan = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_FromUzeraan ); + } + } + + public class LostFertileDirtConversation : QuestConversation + { + private bool m_FromUzeraan; + + public override object Message + { + get + { + if ( m_FromUzeraan ) + { + /* You return without Fertile Dirt? It is imperative that we + * get all of the ingredients friend.

+ * + * Seek out the Dryad and ask her to help you again. + */ + return 1049374; + } + else + { + /* You've lost the dirt I gave you?

+ * + * My, my, my... What ever shall we do now?

+ * + * I can try to make you some more, but I will need something + * that I can transform. Bring me an apple, and I shall + * see what I can do.

+ * + * You can buy apples from the + * Provisioner's Shop, which is located a ways East + * of Uzeraan's mansion.

+ * + * Hand me the apple when you have it, and I shall see about transforming + * it for you.

+ * + * Good luck.

+ */ + return 1049359; + } + } + } + + public override bool Logged{ get{ return false; } } + + public LostFertileDirtConversation( bool fromUzeraan ) + { + m_FromUzeraan = fromUzeraan; + } + + public LostFertileDirtConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_FromUzeraan = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_FromUzeraan ); + } + } + + public class DryadAppleConversation : QuestConversation + { + public override object Message + { + get + { + /* The Dryad sticks the apple into the ground and you watch it + * rot before your eyes.

+ * + * She pulls the now fertile dirt out of the ground and hands + * it to you.


+ * + * There you go friend. Try not to lose it again this time, eh? + */ + return 1049360; + } + } + + public override bool Logged{ get{ return false; } } + + public DryadAppleConversation() + { + } + } + + public class LostDaemonBloodConversation : QuestConversation + { + public override object Message + { + get + { + /* You return without a Vial of Blood? It is imperative that we + * get all of the ingredients friend.

+ * + * Go back to the chest and fetch another vial. Please hurry. + */ + return 1049375; + } + } + + public override bool Logged{ get{ return false; } } + + public LostDaemonBloodConversation() + { + } + } + + public class LostDaemonBoneConversation : QuestConversation + { + public override object Message + { + get + { + /* You return without a Daemon Bone? It is imperative that we + * get all of the ingredients friend.

+ * + * Go back to the graveyard and continue hunting the undead until you + * find another one. Please hurry. + */ + return 1049376; + } + } + + public override bool Logged{ get{ return false; } } + + public LostDaemonBoneConversation() + { + } + } + + public class FewReagentsConversation : QuestConversation + { + public override object Message + { + get + { + /* I don't feel comfortable sending you into a potentially dangerous situation + * with as few reagents as you have in your pack.

+ * + * Before going on, please acquire at least 30 of each reagent. You can + * purchase reagents from the Mage shop, which is + * located just East this mansion.

+ * + * Remember that there are eight (8) different reagents: Black Pearl, Mandrake Root, + * Sulfurous Ash, Garlic, Ginseng, Blood Moss, Nightshade and Spider's Silk.

+ * + * Come back here when you are ready to go. + */ + return 1049390; + } + } + + public override bool Logged{ get{ return false; } } + + public FewReagentsConversation() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs new file mode 100644 index 0000000..aa78470 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs @@ -0,0 +1,181 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Haven +{ + public enum CannonDirection + { + North, + East, + South, + West + } + + public class Cannon : BaseAddon + { + private CannonDirection m_CannonDirection; + private MilitiaCanoneer m_Canoneer; + + [CommandProperty( AccessLevel.GameMaster )] + public CannonDirection CannonDirection { get { return m_CannonDirection; } } + + [CommandProperty( AccessLevel.GameMaster )] + public MilitiaCanoneer Canoneer { get { return m_Canoneer; } set { m_Canoneer = value; } } + + [Constructable] + public Cannon( CannonDirection direction ) + { + m_CannonDirection = direction; + + switch ( direction ) + { + case CannonDirection.North: + { + AddComponent( new CannonComponent( 0xE8D ), 0, 0, 0 ); + AddComponent( new CannonComponent( 0xE8C ), 0, 1, 0 ); + AddComponent( new CannonComponent( 0xE8B ), 0, 2, 0 ); + + break; + } + case CannonDirection.East: + { + AddComponent( new CannonComponent( 0xE96 ), 0, 0, 0 ); + AddComponent( new CannonComponent( 0xE95 ), -1, 0, 0 ); + AddComponent( new CannonComponent( 0xE94 ), -2, 0, 0 ); + + break; + } + case CannonDirection.South: + { + AddComponent( new CannonComponent( 0xE91 ), 0, 0, 0 ); + AddComponent( new CannonComponent( 0xE92 ), 0, -1, 0 ); + AddComponent( new CannonComponent( 0xE93 ), 0, -2, 0 ); + + break; + } + default: + { + AddComponent( new CannonComponent( 0xE8E ), 0, 0, 0 ); + AddComponent( new CannonComponent( 0xE8F ), 1, 0, 0 ); + AddComponent( new CannonComponent( 0xE90 ), 2, 0, 0 ); + + break; + } + } + } + + public Cannon( Serial serial ) : base( serial ) + { + } + + public void DoFireEffect( IPoint3D target ) + { + Point3D from; + switch ( m_CannonDirection ) + { + case CannonDirection.North: from = new Point3D( X, Y - 1, Z ); break; + case CannonDirection.East: from = new Point3D( X + 1, Y, Z ); break; + case CannonDirection.South: from = new Point3D( X, Y + 1, Z ); break; + default: from = new Point3D( X - 1, Y, Z ); break; + } + + Effects.SendLocationEffect( from, Map, 0x36B0, 16, 1 ); + Effects.PlaySound( from, Map, 0x11D ); + + Effects.SendLocationEffect( target, Map, 0x36B0, 16, 1 ); + Effects.PlaySound( target, Map, 0x11D ); + } + + public void Fire( Mobile from, Mobile target ) + { + DoFireEffect( target ); + + target.Damage( 9999, from ); + } + + public override bool HandlesOnMovement { get { return m_Canoneer != null && !m_Canoneer.Deleted && m_Canoneer.Active; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m_Canoneer == null || m_Canoneer.Deleted || !m_Canoneer.Active ) + return; + + bool canFire; + switch ( m_CannonDirection ) + { + case CannonDirection.North: + canFire = m.X >= X - 7 && m.X <= X + 7 && m.Y == Y - 7 && oldLocation.Y < Y - 7; + break; + case CannonDirection.East: + canFire = m.Y >= Y - 7 && m.Y <= Y + 7 && m.X == X + 7 && oldLocation.X > X + 7; + break; + case CannonDirection.South: + canFire = m.X >= X - 7 && m.X <= X + 7 && m.Y == Y + 7 && oldLocation.Y > Y + 7; + break; + default: + canFire = m.Y >= Y - 7 && m.Y <= Y + 7 && m.X == X - 7 && oldLocation.X < X - 7; + break; + } + + if ( canFire && m_Canoneer.WillFire( this, m ) ) + Fire( m_Canoneer, m ); + } + + public override void Serialize( GenericWriter writer ) + { + if ( m_Canoneer != null && m_Canoneer.Deleted ) + m_Canoneer = null; + + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_CannonDirection ); + writer.Write( (Mobile) m_Canoneer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_CannonDirection = (CannonDirection) reader.ReadEncodedInt(); + m_Canoneer = (MilitiaCanoneer) reader.ReadMobile(); + } + } + + public class CannonComponent : AddonComponent + { + [CommandProperty( AccessLevel.GameMaster )] + public MilitiaCanoneer Canoneer + { + get { return Addon is Cannon ? ((Cannon)Addon).Canoneer : null; } + set { if ( Addon is Cannon ) ((Cannon)Addon).Canoneer = value; } + } + + public CannonComponent( int itemID ) : base( itemID ) + { + } + + public CannonComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/DaemonBloodChest.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/DaemonBloodChest.cs new file mode 100644 index 0000000..f4e2a6f --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/DaemonBloodChest.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class DaemonBloodChest : MetalChest + { + [Constructable] + public DaemonBloodChest() + { + Movable = false; + } + + public DaemonBloodChest( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.InRange( GetWorldLocation(), 2 ) ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( GetDaemonBloodObjective ) ); + + if ( (obj != null && !obj.Completed) || UzeraanTurmoilQuest.HasLostDaemonBlood( player ) ) + { + Item vial = new QuestDaemonBlood(); + + if ( player.PlaceInBackpack( vial ) ) + { + player.SendLocalizedMessage( 1049331, "", 0x22 ); // You take a vial of blood from the chest and put it in your pack. + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + else + { + player.SendLocalizedMessage( 1049338, "", 0x22 ); // You find a vial of blood, but can't pick it up because your pack is too full. Come back when you have more room in your pack. + vial.Delete(); + } + + return; + } + } + } + + base.OnDoubleClick( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestDaemonBlood.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestDaemonBlood.cs new file mode 100644 index 0000000..9580422 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestDaemonBlood.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class QuestDaemonBlood : QuestItem + { + [Constructable] + public QuestDaemonBlood() : base( 0xF7D ) + { + Weight = 1.0; + } + + public QuestDaemonBlood( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + UzeraanTurmoilQuest qs = player.Quest as UzeraanTurmoilQuest; + + if ( qs == null ) + return true; + + /*return !qs.IsObjectiveInProgress( typeof( ReturnDaemonBloodObjective ) );*/ + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestDaemonBone.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestDaemonBone.cs new file mode 100644 index 0000000..a075f63 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestDaemonBone.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class QuestDaemonBone : QuestItem + { + [Constructable] + public QuestDaemonBone() : base( 0xF80 ) + { + Weight = 1.0; + } + + public QuestDaemonBone( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + UzeraanTurmoilQuest qs = player.Quest as UzeraanTurmoilQuest; + + if ( qs == null ) + return true; + + //return !qs.IsObjectiveInProgress( typeof( ReturnDaemonBoneObjective ) ); + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestFertileDirt.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestFertileDirt.cs new file mode 100644 index 0000000..0d4f376 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/QuestFertileDirt.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class QuestFertileDirt : QuestItem + { + [Constructable] + public QuestFertileDirt() : base( 0xF81 ) + { + Weight = 1.0; + } + + public QuestFertileDirt( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + UzeraanTurmoilQuest qs = player.Quest as UzeraanTurmoilQuest; + + if ( qs == null ) + return true; + + //return !qs.IsObjectiveInProgress( typeof( ReturnFertileDirtObjective ) ); + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs new file mode 100644 index 0000000..896a4bb --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickApprenticeCorpse.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class SchmendrickApprenticeCorpse : Corpse + { + private static Mobile GetOwner() + { + Mobile apprentice = new Mobile(); + + apprentice.Hue = Utility.RandomSkinHue(); + apprentice.Female = false; + apprentice.Body = 0x190; + apprentice.Name = NameList.RandomName( "male" ); + + apprentice.Delete(); + + return apprentice; + } + + private static List GetEquipment() + { + List list = new List(); + + list.Add( new Robe( QuestSystem.RandomBrightHue() ) ); + list.Add( new WizardsHat( Utility.RandomNeutralHue() ) ); + list.Add( new Shoes( Utility.RandomNeutralHue() ) ); + + /* + int hairHue = Utility.RandomHairHue(); + + switch ( Utility.Random( 8 ) ) + { + case 0: list.Add( new Afro( hairHue ) ); break; + case 1: list.Add( new KrisnaHair( hairHue ) ); break; + case 2: list.Add( new PageboyHair( hairHue ) ); break; + case 3: list.Add( new PonyTail( hairHue ) ); break; + case 4: list.Add( new ReceedingHair( hairHue ) ); break; + case 5: list.Add( new TwoPigTails( hairHue ) ); break; + case 6: list.Add( new ShortHair( hairHue ) ); break; + case 7: list.Add( new LongHair( hairHue ) ); break; + } + + switch ( Utility.Random( 5 ) ) + { + case 0: list.Add( new LongBeard( hairHue ) ); break; + case 1: list.Add( new MediumLongBeard( hairHue ) ); break; + case 2: list.Add( new Vandyke( hairHue ) ); break; + case 3: list.Add( new Mustache( hairHue ) ); break; + case 4: list.Add( new Goatee( hairHue ) ); break; + } + * */ + + list.Add( new Spellbook() ); + + return list; + } + + private static int m_HairHue; + private static HairInfo GetHair() + { + m_HairHue = Race.Human.RandomHairHue(); + + return new HairInfo( Race.Human.RandomHair( false ), m_HairHue ); + } + + private static FacialHairInfo GetFacialHair() + { + m_HairHue = Race.Human.RandomHairHue(); + + return new FacialHairInfo( Race.Human.RandomFacialHair( false ), m_HairHue ); + } + + private Lantern m_Lantern; + + [Constructable] + public SchmendrickApprenticeCorpse() : base( GetOwner(), GetHair(), GetFacialHair(), GetEquipment() ) + { + Direction = Direction.West; + + foreach ( Item item in EquipItems ) + { + DropItem( item ); + } + + m_Lantern = new Lantern(); + m_Lantern.Movable = false; + m_Lantern.Protected = true; + m_Lantern.Ignite(); + } + + public SchmendrickApprenticeCorpse( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( ItemID == 0x2006 ) // Corpse form + { + list.Add( "a human corpse" ); + list.Add( 1049144, this.Name ); // the remains of ~1_NAME~ the apprentice + } + else + { + list.Add( 1049145 ); // the remains of a wizard's apprentice + } + } + + public override void OnSingleClick( Mobile from ) + { + int hue = Notoriety.GetHue( Server.Misc.NotorietyHandlers.CorpseNotoriety( from, this ) ); + + if ( ItemID == 0x2006 ) // Corpse form + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, 1049144, "", Name ) ); // the remains of ~1_NAME~ the apprentice + else + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, 1049145, "", "" ) ); // the remains of a wizard's apprentice + } + + public override void Open( Mobile from, bool checkSelfLoot ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + return; + + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FindApprenticeObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item scroll = new SchmendrickScrollOfPower(); + + if ( player.PlaceInBackpack( scroll ) ) + { + player.SendLocalizedMessage( 1049147, "", 0x22 ); // You find the scroll and put it in your pack. + obj.Complete(); + } + else + { + player.SendLocalizedMessage( 1049146, "", 0x22 ); // You find the scroll, but can't pick it up because your pack is too full. Come back when you have more room in your pack. + scroll.Delete(); + } + + return; + } + } + } + + from.SendLocalizedMessage( 1049143, "", 0x22 ); // This is the corpse of a wizard's apprentice. You can't bring yourself to search it without a good reason. + } + + public override void OnLocationChange( Point3D oldLoc ) + { + if ( m_Lantern != null && !m_Lantern.Deleted ) + m_Lantern.Location = new Point3D( this.X, this.Y + 1, this.Z ); + } + + public override void OnMapChange() + { + if ( m_Lantern != null && !m_Lantern.Deleted ) + m_Lantern.Map = this.Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Lantern != null && !m_Lantern.Deleted ) + m_Lantern.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + if ( m_Lantern != null && m_Lantern.Deleted ) + m_Lantern = null; + + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Lantern ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Lantern = (Lantern)reader.ReadItem(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickScrollOfPower.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickScrollOfPower.cs new file mode 100644 index 0000000..131dc3b --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/SchmendrickScrollOfPower.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class SchmendrickScrollOfPower : QuestItem + { + public override int LabelNumber { get { return 1049118; } } // a scroll with ancient markings + + public SchmendrickScrollOfPower() : base( 0xE34 ) + { + Weight = 1.0; + Hue = 0x34D; + } + + public SchmendrickScrollOfPower( Serial serial ) : base( serial ) + { + } + + public override bool CanDrop( PlayerMobile player ) + { + UzeraanTurmoilQuest qs = player.Quest as UzeraanTurmoilQuest; + + if ( qs == null ) + return true; + + return !qs.IsObjectiveInProgress( typeof( ReturnScrollOfPowerObjective ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/UzeraanTurmoilHorn.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/UzeraanTurmoilHorn.cs new file mode 100644 index 0000000..9b92be3 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/UzeraanTurmoilHorn.cs @@ -0,0 +1,43 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class UzeraanTurmoilHorn : HornOfRetreat + { + public override bool ValidateUse( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + return ( pm != null && pm.Quest is UzeraanTurmoilQuest ); + } + + [Constructable] + public UzeraanTurmoilHorn() + { + DestLoc = new Point3D( 3597, 2582, 0 ); + DestMap = Map.Trammel; + } + + public UzeraanTurmoilHorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Items/UzeraanTurmoilTeleporter.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/UzeraanTurmoilTeleporter.cs new file mode 100644 index 0000000..fae6b57 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Items/UzeraanTurmoilTeleporter.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class UzeraanTurmoilTeleporter : DynamicTeleporter + { + [Constructable] + public UzeraanTurmoilTeleporter() + { + } + + public override bool GetDestination( PlayerMobile player, ref Point3D loc, ref Map map ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FindSchmendrickObjective ) ) + || qs.IsObjectiveInProgress( typeof( FindApprenticeObjective ) ) + || UzeraanTurmoilQuest.HasLostScrollOfPower( player ) ) + { + loc = new Point3D( 5222, 1858, 0 ); + map = Map.Trammel; + return true; + } + else if ( qs.IsObjectiveInProgress( typeof( FindDryadObjective ) ) + || UzeraanTurmoilQuest.HasLostFertileDirt( player ) ) + { + loc = new Point3D( 3557, 2690, 2 ); + map = Map.Trammel; + return true; + } + else if ( player.Profession != 5 // paladin + && ( qs.IsObjectiveInProgress( typeof( GetDaemonBoneObjective ) ) + || UzeraanTurmoilQuest.HasLostDaemonBone( player ) ) ) + { + loc = new Point3D( 3422, 2653, 48 ); + map = Map.Trammel; + return true; + } + else if ( qs.IsObjectiveInProgress( typeof( CashBankCheckObjective ) ) ) + { + loc = new Point3D( 3624, 2610, 0 ); + map = Map.Trammel; + return true; + } + } + + return false; + } + + public UzeraanTurmoilTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Dryad.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Dryad.cs new file mode 100644 index 0000000..7419858 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Dryad.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.ContextMenus; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class Dryad : BaseQuester + { + public override bool IsActiveVendor{ get{ return true; } } + public override bool DisallowAllMoves{ get{ return false; } } + public override bool ClickTitle{ get { return true; } } + public override bool CanTeach{ get{ return true; } } + + [Constructable] + public Dryad() : base( "the Dryad" ) + { + SetSkill( SkillName.Peacemaking, 80.0, 100.0 ); + SetSkill( SkillName.Cooking, 80.0, 100.0 ); + SetSkill( SkillName.Provocation, 80.0, 100.0 ); + SetSkill( SkillName.Musicianship, 80.0, 100.0 ); + SetSkill( SkillName.Poisoning, 80.0, 100.0 ); + SetSkill( SkillName.Archery, 80.0, 100.0 ); + SetSkill( SkillName.Tailoring, 80.0, 100.0 ); + } + + public Dryad( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x85A7; + + Female = true; + Body = 0x191; + Name = "Anwin Brenna"; + } + + public override void InitOutfit() + { + AddItem( new Kilt( 0x301 ) ); + AddItem( new FancyShirt( 0x300 ) ); + + HairItemID = 0x203D; // Pony Tail + HairHue = 0x22; + + Bow bow = new Bow(); + bow.Movable = false; + AddItem( bow ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBDryad() ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 4; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + UzeraanTurmoilQuest qs = to.Quest as UzeraanTurmoilQuest; + + return ( qs != null && qs.FindObjective( typeof( FindDryadObjective ) ) != null ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( UzeraanTurmoilQuest.HasLostFertileDirt( player ) ) + { + FocusTo( player ); + qs.AddConversation( new LostFertileDirtConversation( false ) ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( FindDryadObjective ) ); + + if ( obj != null && !obj.Completed ) + { + FocusTo( player ); + + Item fertileDirt = new QuestFertileDirt(); + + if ( !player.PlaceInBackpack( fertileDirt ) ) + { + fertileDirt.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + else + { + obj.Complete(); + } + } + else if ( contextMenu ) + { + FocusTo( player ); + SayTo( player, 1049357 ); // I have nothing more for you at this time. + } + } + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + UzeraanTurmoilQuest qs = player.Quest as UzeraanTurmoilQuest; + + if ( qs != null && dropped is Apple && UzeraanTurmoilQuest.HasLostFertileDirt( from ) ) + { + FocusTo( from ); + + Item fertileDirt = new QuestFertileDirt(); + + if ( !player.PlaceInBackpack( fertileDirt ) ) + { + fertileDirt.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + return false; + } + else + { + dropped.Consume(); + qs.AddConversation( new DryadAppleConversation() ); + return dropped.Deleted; + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SBDryad : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBDryad() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bandage ), 5, 20, 0xE21, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bandage ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Bloodmoss ), 3 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( MandrakeRoot ), 2 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MansionGuard.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MansionGuard.cs new file mode 100644 index 0000000..f9800b6 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MansionGuard.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class MansionGuard : BaseQuester + { + [Constructable] + public MansionGuard() : base( "the Mansion Guard" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = Utility.RandomSkinHue(); + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + public override void InitOutfit() + { + AddItem( new PlateChest() ); + AddItem( new PlateArms() ); + AddItem( new PlateGloves() ); + AddItem( new PlateLegs() ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + + Bardiche weapon = new Bardiche(); + weapon.Movable = false; + AddItem( weapon ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 3; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return ( to.Quest == null && QuestSystem.CanOfferQuest( to, typeof( UzeraanTurmoilQuest ) ) ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + if ( player.Quest == null && QuestSystem.CanOfferQuest( player, typeof( UzeraanTurmoilQuest ) ) ) + { + Direction = GetDirectionTo( player ); + + new UzeraanTurmoilQuest( player ).SendOffer(); + } + } + + public MansionGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaCanoneer.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaCanoneer.cs new file mode 100644 index 0000000..d77d70a --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaCanoneer.cs @@ -0,0 +1,113 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class MilitiaCanoneer : BaseQuester + { + private bool m_Active; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get { return m_Active; } + set { m_Active = value; } + } + + [Constructable] + public MilitiaCanoneer() : base( "the Militia Canoneer" ) + { + m_Active = true; + } + + public override void InitBody() + { + InitStats( 100, 125, 25 ); + + Hue = Utility.RandomSkinHue(); + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + public override void InitOutfit() + { + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + + AddItem( new PlateChest() ); + AddItem( new PlateArms() ); + AddItem( new PlateGloves() ); + AddItem( new PlateLegs() ); + + Torch torch = new Torch(); + torch.Movable = false; + AddItem( torch ); + torch.Ignite(); + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return false; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player || m is BaseVendor ) + return false; + + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + Mobile master = bc.GetMaster(); + if( master != null ) + return IsEnemy( master ); + } + + return m.Karma < 0; + } + + public bool WillFire( Cannon cannon, Mobile target ) + { + if ( m_Active && IsEnemy( target ) ) + { + Direction = GetDirectionTo( target ); + Say( Utility.RandomList( 500651, 1049098, 1049320, 1043149 ) ); + return true; + } + + return false; + } + + public MilitiaCanoneer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (bool) m_Active ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Active = reader.ReadBool(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs new file mode 100644 index 0000000..f54a78b --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/MilitiaFighter.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Engines.Quests.Haven +{ + public class MilitiaFighter : BaseCreature + { + [Constructable] + public MilitiaFighter() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + InitStats( 40, 30, 5 ); + Title = "the Militia Fighter"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + Female = false; + Body = 0x190; + Name = NameList.RandomName( "male" ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + + AddItem( new ThighBoots( 0x1BB ) ); + AddItem( new LeatherChest() ); + AddItem( new LeatherArms() ); + AddItem( new LeatherLegs() ); + AddItem( new LeatherCap() ); + AddItem( new LeatherGloves() ); + AddItem( new LeatherGorget() ); + + Item weapon; + switch ( Utility.Random( 6 ) ) + { + case 0: weapon = new Broadsword(); break; + case 1: weapon = new Cutlass(); break; + case 2: weapon = new Katana(); break; + case 3: weapon = new Longsword(); break; + case 4: weapon = new Scimitar(); break; + default: weapon = new VikingSword(); break; + } + weapon.Movable = false; + AddItem( weapon ); + + Item shield = new BronzeShield(); + shield.Movable = false; + AddItem( shield ); + + SetSkill( SkillName.Swords, 20.0 ); + } + + public override bool ClickTitle { get { return false; } } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player || m is BaseVendor ) + return false; + + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + Mobile master = bc.GetMaster(); + if( master != null ) + return IsEnemy( master ); + } + + return m.Karma < 0; + } + + public MilitiaFighter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MilitiaFighterCorpse : Corpse + { + public MilitiaFighterCorpse( Mobile owner, HairInfo hair, FacialHairInfo facialhair, List equipItems ) : base( owner, hair, facialhair, equipItems ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( ItemID == 0x2006 ) // Corpse form + { + list.Add( "a human corpse" ); + list.Add( 1049318, this.Name ); // the remains of ~1_NAME~ the militia fighter + } + else + { + list.Add( 1049319 ); // the remains of a militia fighter + } + } + + public override void OnSingleClick( Mobile from ) + { + int hue = Notoriety.GetHue( Server.Misc.NotorietyHandlers.CorpseNotoriety( from, this ) ); + + if ( ItemID == 0x2006 ) // Corpse form + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, 1049318, "", Name ) ); // the remains of ~1_NAME~ the militia fighter + else + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, 1049319, "", "" ) ); // the remains of a militia fighter + } + + public override void Open( Mobile from, bool checkSelfLoot ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + from.SendLocalizedMessage( 1049661, "", 0x22 ); // Thinking about his sacrifice, you can't bring yourself to loot the body of this militia fighter. + } + } + + public MilitiaFighterCorpse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Schmendrick.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Schmendrick.cs new file mode 100644 index 0000000..e5af6de --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Schmendrick.cs @@ -0,0 +1,156 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class Schmendrick : BaseQuester + { + [Constructable] + public Schmendrick() : base( "the High Mage" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83F3; + + Female = false; + Body = 0x190; + Name = "Schmendrick"; + } + + public override void InitOutfit() + { + AddItem( new Robe( 0x4DD ) ); + AddItem( new WizardsHat( 0x482 ) ); + AddItem( new Shoes( 0x482 ) ); + + HairItemID = 0x203C; + HairHue = 0x455; + + FacialHairItemID = 0x203E; + FacialHairHue = 0x455; + + GlacialStaff staff = new GlacialStaff(); + staff.Movable = false; + AddItem( staff ); + + Backpack pack = new Backpack(); + pack.Movable = false; + AddItem( pack ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 7; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + UzeraanTurmoilQuest qs = to.Quest as UzeraanTurmoilQuest; + + return ( qs != null && qs.FindObjective( typeof( FindSchmendrickObjective ) ) != null ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( UzeraanTurmoilQuest.HasLostScrollOfPower( player ) ) + { + FocusTo( player ); + qs.AddConversation( new LostScrollOfPowerConversation( false ) ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( FindSchmendrickObjective ) ); + + if ( obj != null && !obj.Completed ) + { + FocusTo( player ); + obj.Complete(); + } + else if ( contextMenu ) + { + FocusTo( player ); + SayTo( player, 1049357 ); // I have nothing more for you at this time. + } + } + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is BlankScroll && UzeraanTurmoilQuest.HasLostScrollOfPower( from ) ) + { + FocusTo( from ); + + Item scroll = new SchmendrickScrollOfPower(); + + if ( !from.PlaceInBackpack( scroll ) ) + { + scroll.Delete(); + from.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + return false; + } + else + { + dropped.Consume(); + from.SendLocalizedMessage( 1049346 ); // Schmendrick scribbles on the scroll for a few moments and hands you the finished product. + return dropped.Deleted; + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m is PlayerMobile && !m.Frozen && !m.Alive && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && InLOS( m ) ) + { + if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + else + { + Direction = GetDirectionTo( m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.Healer ) ); + } + } + } + + public Schmendrick( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Uzeraan.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Uzeraan.cs new file mode 100644 index 0000000..4cf3650 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Mobiles/Uzeraan.cs @@ -0,0 +1,434 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Haven +{ + public class Uzeraan : BaseQuester + { + [Constructable] + public Uzeraan() : base( "the Conjurer" ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83F3; + + Female = false; + Body = 0x190; + Name = "Uzeraan"; + } + + public override void InitOutfit() + { + AddItem( new Robe( 0x4DD ) ); + AddItem( new WizardsHat( 0x8A5 ) ); + AddItem( new Shoes( 0x8A5 ) ); + + HairItemID = 0x203C; + HairHue = 0x455; + + FacialHairItemID = 0x203E; + FacialHairHue = 0x455; + + BlackStaff staff = new BlackStaff(); + staff.Movable = false; + AddItem( staff ); + } + + public override int GetAutoTalkRange( PlayerMobile pm ) + { + return 3; + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return to.Quest is UzeraanTurmoilQuest; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( UzeraanTurmoilQuest.HasLostScrollOfPower( player ) ) + { + qs.AddConversation( new LostScrollOfPowerConversation( true ) ); + } + else if ( UzeraanTurmoilQuest.HasLostFertileDirt( player ) ) + { + qs.AddConversation( new LostFertileDirtConversation( true ) ); + } + else if ( UzeraanTurmoilQuest.HasLostDaemonBlood( player ) ) + { + qs.AddConversation( new LostDaemonBloodConversation() ); + } + else if ( UzeraanTurmoilQuest.HasLostDaemonBone( player ) ) + { + qs.AddConversation( new LostDaemonBoneConversation() ); + } + else + { + if ( player.Profession == 2 ) // magician + { + Container backpack = player.Backpack; + + if ( backpack == null + || backpack.GetAmount( typeof( BlackPearl ) ) < 30 + || backpack.GetAmount( typeof( Bloodmoss ) ) < 30 + || backpack.GetAmount( typeof( Garlic ) ) < 30 + || backpack.GetAmount( typeof( Ginseng ) ) < 30 + || backpack.GetAmount( typeof( MandrakeRoot ) ) < 30 + || backpack.GetAmount( typeof( Nightshade ) ) < 30 + || backpack.GetAmount( typeof( SulfurousAsh ) ) < 30 + || backpack.GetAmount( typeof( SpidersSilk ) ) < 30 ) + { + qs.AddConversation( new FewReagentsConversation() ); + } + } + + QuestObjective obj = qs.FindObjective( typeof( FindUzeraanBeginObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else + { + obj = qs.FindObjective( typeof( FindUzeraanFirstTaskObjective ) ); + + if ( obj != null && !obj.Completed ) + { + obj.Complete(); + } + else + { + obj = qs.FindObjective( typeof( FindUzeraanAboutReportObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + if ( player.Profession == 2 ) // magician + { + cont.DropItem( new MarkScroll( 5 ) ); + cont.DropItem( new RecallScroll( 5 ) ); + for ( int i = 0; i < 5; i++ ) + { + cont.DropItem( new RecallRune() ); + } + } + else + { + cont.DropItem( new Gold( 300 ) ); + for ( int i = 0; i < 6; i++ ) + { + cont.DropItem( new NightSightPotion() ); + cont.DropItem( new LesserHealPotion() ); + } + } + + if ( !player.PlaceInBackpack( cont ) ) + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + else + { + obj.Complete(); + } + } + else + { + obj = qs.FindObjective( typeof( ReturnScrollOfPowerObjective ) ); + + if ( obj != null && !obj.Completed ) + { + FocusTo( player ); + SayTo( player, 1049378 ); // Hand me the scroll, if you have it. + } + else + { + obj = qs.FindObjective( typeof( ReturnFertileDirtObjective ) ); + + if ( obj != null && !obj.Completed ) + { + FocusTo( player ); + SayTo( player, 1049381 ); // Hand me the Fertile Dirt, if you have it. + } + else + { + obj = qs.FindObjective( typeof( ReturnDaemonBloodObjective ) ); + + if ( obj != null && !obj.Completed ) + { + FocusTo( player ); + SayTo( player, 1049379 ); // Hand me the Vial of Blood, if you have it. + } + else + { + obj = qs.FindObjective( typeof( ReturnDaemonBoneObjective ) ); + + if ( obj != null && !obj.Completed ) + { + FocusTo( player ); + SayTo( player, 1049380 ); // Hand me the Daemon Bone, if you have it. + } + else + { + SayTo( player, 1049357 ); // I have nothing more for you at this time. + } + } + } + } + } + } + } + } + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( dropped is UzeraanTurmoilHorn ) + { + if ( player.Young ) + { + UzeraanTurmoilHorn horn = (UzeraanTurmoilHorn)dropped; + + if ( horn.Charges < 10 ) + { + SayTo( from, 1049384 ); // I have recharged the item for you. + horn.Charges = 10; + } + else + { + SayTo( from, 1049385 ); // That doesn't need recharging yet. + } + } + else + { + player.SendLocalizedMessage(1114333); //You must be young to have this item recharged. + } + + return false; + } + + if ( dropped is SchmendrickScrollOfPower ) + { + QuestObjective obj = qs.FindObjective( typeof( ReturnScrollOfPowerObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + cont.DropItem( new TreasureMap( player.Young ? 0 : 1, Map.Trammel ) ); + cont.DropItem( new Shovel() ); + cont.DropItem( new UzeraanTurmoilHorn() ); + + if ( !player.PlaceInBackpack( cont ) ) + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + return false; + } + else + { + dropped.Delete(); + obj.Complete(); + return true; + } + } + } + else if ( dropped is QuestFertileDirt ) + { + QuestObjective obj = qs.FindObjective( typeof( ReturnFertileDirtObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + if ( player.Profession == 2 ) // magician + { + cont.DropItem( new BlackPearl( 20 ) ); + cont.DropItem( new Bloodmoss( 20 ) ); + cont.DropItem( new Garlic( 20 ) ); + cont.DropItem( new Ginseng( 20 ) ); + cont.DropItem( new MandrakeRoot( 20 ) ); + cont.DropItem( new Nightshade( 20 ) ); + cont.DropItem( new SulfurousAsh( 20 ) ); + cont.DropItem( new SpidersSilk( 20 ) ); + + for ( int i = 0; i < 3; i++ ) + cont.DropItem( Loot.RandomScroll( 0, 23, SpellbookType.Regular ) ); + } + else + { + cont.DropItem( new Gold( 300 ) ); + cont.DropItem( new Bandage( 25 ) ); + + for ( int i = 0; i < 5; i++ ) + cont.DropItem( new LesserHealPotion() ); + } + + if ( !player.PlaceInBackpack( cont ) ) + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + return false; + } + else + { + dropped.Delete(); + obj.Complete(); + return true; + } + } + } + else if ( dropped is QuestDaemonBlood ) + { + QuestObjective obj = qs.FindObjective( typeof( ReturnDaemonBloodObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Item reward; + + if ( player.Profession == 2 ) // magician + { + Container cont = GetNewContainer(); + + cont.DropItem( new ExplosionScroll( 4 ) ); + cont.DropItem( new MagicWizardsHat() ); + + reward = cont; + } + else + { + BaseWeapon weapon; + switch ( Utility.Random( 6 ) ) + { + case 0: weapon = new Broadsword(); break; + case 1: weapon = new Cutlass(); break; + case 2: weapon = new Katana(); break; + case 3: weapon = new Longsword(); break; + case 4: weapon = new Scimitar(); break; + default: weapon = new VikingSword(); break; + } + + if ( Core.AOS ) + { + BaseRunicTool.ApplyAttributesTo( weapon, 3, 20, 40 ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled( 2, 4 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled( 2, 4 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled( 2, 4 ); + } + + weapon.Slayer = SlayerName.Silver; + + reward = weapon; + } + + if ( !player.PlaceInBackpack( reward ) ) + { + reward.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + return false; + } + else + { + dropped.Delete(); + obj.Complete(); + return true; + } + } + } + else if ( dropped is QuestDaemonBone ) + { + QuestObjective obj = qs.FindObjective( typeof( ReturnDaemonBoneObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + cont.DropItem( new BankCheck( 2000 ) ); + cont.DropItem( new EnchantedSextant() ); + + if ( !player.PlaceInBackpack( cont ) ) + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + return false; + } + else + { + dropped.Delete(); + obj.Complete(); + return true; + } + } + } + } + } + + return base.OnDragDrop( from, dropped ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m is PlayerMobile && !m.Frozen && !m.Alive && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && InLOS( m ) ) + { + if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + else + { + Direction = GetDirectionTo( m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.Healer ) ); + } + } + } + + public Uzeraan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs new file mode 100644 index 0000000..8351a84 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/Objectives.cs @@ -0,0 +1,638 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; + +namespace Server.Engines.Quests.Haven +{ + public class FindUzeraanBeginObjective : QuestObjective + { + public override object Message + { + get + { + // Find Uzeraan. Uzeraan will explain what you need to do next. + return 1046039; + } + } + + public FindUzeraanBeginObjective() + { + } + + public override void OnComplete() + { + if ( System.From.Profession == 5 ) // paladin + System.AddConversation( new UzeraanTitheConversation() ); + else + System.AddConversation( new UzeraanFirstTaskConversation() ); + } + } + + public class TitheGoldObjective : QuestObjective + { + public override object Message + { + get + { + /* Go to the shrine inside of Uzeraan's Mansion, near the front doors and + * tithe at least 500 gold.

+ * + * Return to Uzeraan when you are done. + */ + return 1060386; + } + } + + private int m_OldTithingPoints; + + public TitheGoldObjective() + { + m_OldTithingPoints = -1; + } + + public override void CheckProgress() + { + PlayerMobile pm = System.From; + int curTithingPoints = pm.TithingPoints; + + if ( curTithingPoints >= 500 ) + Complete(); + else if ( curTithingPoints > m_OldTithingPoints && m_OldTithingPoints >= 0 ) + pm.SendLocalizedMessage( 1060240, "", 0x41 ); // You must have at least 500 tithing points before you can continue in your quest. + + m_OldTithingPoints = curTithingPoints; + } + + public override void OnComplete() + { + System.AddObjective( new FindUzeraanFirstTaskObjective() ); + } + } + + public class FindUzeraanFirstTaskObjective : QuestObjective + { + public override object Message + { + get + { + // Return to Uzeraan, now that you have enough tithing points to continue your quest. + return 1060387; + } + } + + public FindUzeraanFirstTaskObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new UzeraanFirstTaskConversation() ); + } + } + + public enum KillHordeMinionsStep + { + First, + LearnKarma, + Others + } + + public class KillHordeMinionsObjective : QuestObjective + { + private KillHordeMinionsStep m_Step; + + public KillHordeMinionsStep Step { get { return m_Step; } } + + public override object Message + { + get + { + switch ( m_Step ) + { + case KillHordeMinionsStep.First: + /* Find the mountain pass beyond the house which lies at the + * end of the runic road.

+ * + * Assist the city Militia by slaying Horde Minions + */ + return 1049089; + + case KillHordeMinionsStep.LearnKarma: + /* You have just gained some Karma + * for killing the horde minion. Learn + * how this affects your Paladin abilities. + */ + return 1060389; + + default: + // Continue driving back the Horde Minions, as Uzeraan instructed you to do. + return 1060507; + } + } + } + + public override int MaxProgress + { + get + { + if ( System.From.Profession == 5 ) // paladin + { + switch ( m_Step ) + { + case KillHordeMinionsStep.First: return 1; + case KillHordeMinionsStep.LearnKarma: return 2; + default: return 5; + } + } + else + { + return 5; + } + } + } + + public override bool Completed + { + get + { + if ( m_Step == KillHordeMinionsStep.LearnKarma && HasBeenRead ) + return true; + else + return base.Completed; + } + } + + public KillHordeMinionsObjective() + { + } + + public KillHordeMinionsObjective( KillHordeMinionsStep step ) + { + m_Step = step; + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + gump.AddHtmlObject( 70, 260, 270, 100, 1049090, BaseQuestGump.Blue, false, false ); // Horde Minions killed: + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override void OnRead() + { + CheckCompletionStatus(); + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + // This restriction continues until the quest is ended + if ( from is HordeMinion && from.Map == Map.Trammel && from.X >= 3314 && from.X <= 3814 && from.Y >= 2345 && from.Y <= 3095 ) // Haven island + return true; + + return false; + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is HordeMinion && corpse.Map == Map.Trammel && corpse.X >= 3314 && corpse.X <= 3814 && corpse.Y >= 2345 && corpse.Y <= 3095 ) // Haven island + { + if ( CurProgress == 0 ) + System.From.Send( new DisplayHelpTopic( 29, false ) ); // HEALING + + CurProgress++; + } + } + + public override void OnComplete() + { + if ( System.From.Profession == 5 ) + { + switch ( m_Step ) + { + case KillHordeMinionsStep.First: + { + QuestObjective obj = new KillHordeMinionsObjective( KillHordeMinionsStep.LearnKarma ); + System.AddObjective( obj ); + obj.CurProgress = CurProgress; + break; + } + case KillHordeMinionsStep.LearnKarma: + { + QuestObjective obj = new KillHordeMinionsObjective( KillHordeMinionsStep.Others ); + System.AddObjective( obj ); + obj.CurProgress = CurProgress; + break; + } + default: + { + System.AddObjective( new FindUzeraanAboutReportObjective() ); + break; + } + } + } + else + { + System.AddObjective( new FindUzeraanAboutReportObjective() ); + } + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Step = (KillHordeMinionsStep) reader.ReadEncodedInt(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Step ); + } + } + + public class FindUzeraanAboutReportObjective : QuestObjective + { + public override object Message + { + get + { + /* It's no use... The Horde Minions are too many. + * They are appearing out of nowhere.

+ * + * Return to Uzeraan and report your findings. + */ + return 1049091; + } + } + + public FindUzeraanAboutReportObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new UzeraanReportConversation() ); + } + } + + public class FindSchmendrickObjective : QuestObjective + { + public override object Message + { + get + { + /* Prepare for battle and step onto the teleporter, + * located against the wall in the main hall of Uzeraan's mansion.

+ * + * Find Schmendrick within the mines. + */ + return 1049120; + } + } + + public FindSchmendrickObjective() + { + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + // This restriction begins when this objective is completed, and continues until the quest is ended + if ( Completed && from is RestlessSoul && from.Map == Map.Trammel && from.X >= 5199 && from.X <= 5271 && from.Y >= 1812 && from.Y <= 1865 ) // Schmendrick's cave + return true; + + return false; + } + + public override void OnComplete() + { + System.AddConversation( new SchmendrickConversation() ); + } + } + + public class FindApprenticeObjective : QuestObjective + { + public override object Message + { + get + { + /* Find Schmendrick's apprentice who is somewhere in the mining cave. + * The apprentice has the scroll of power needed by Uzeraan. + */ + return 1049323; + } + } + + public FindApprenticeObjective() + { + } + + public override void OnComplete() + { + System.AddObjective( new ReturnScrollOfPowerObjective() ); + } + } + + public class ReturnScrollOfPowerObjective : QuestObjective + { + public override object Message + { + get + { + /* You have obtained the scroll of power! Find your way out of the cave.

+ * + * Hand the scroll to Uzeraan (drag and drop) once you arrive in his mansion. + */ + return 1049324; + } + } + + public ReturnScrollOfPowerObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new UzeraanScrollOfPowerConversation() ); + } + } + + public class FindDryadObjective : QuestObjective + { + public override object Message + { + get + { + /* Find the Dryad in the woods of Haven and get a patch + * of fertile dirt from her.

+ * + * Use Uzeraan's teleporter to get there if necessary. + */ + return 1049358; + } + } + + public FindDryadObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new DryadConversation() ); + } + } + + public class ReturnFertileDirtObjective : QuestObjective + { + public override object Message + { + get + { + /* You have acquired the Fertile Dirt!

+ * + * Return to the mansion (North-East + * of the Dryad's Grove) and hand it to Uzeraan. + */ + return 1049327; + } + } + + public ReturnFertileDirtObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new UzeraanFertileDirtConversation() ); + } + } + + public class GetDaemonBloodObjective : QuestObjective + { + public override object Message + { + get + { + /* Bring back a vial of blood.

+ * + * Follow the road leading north from the mansion and walk into the hut + * to find the chest that contains the vial + */ + return 1049361; + } + } + + private bool m_Ambushed; + + public GetDaemonBloodObjective() + { + } + + public override void CheckProgress() + { + PlayerMobile player = System.From; + + if ( !m_Ambushed && player.Map == Map.Trammel && player.InRange( new Point3D( 3456, 2558, 50 ), 30 ) ) + { + int x = player.X - 1; + int y = player.Y - 2; + int z = Map.Trammel.GetAverageZ( x, y ); + + if ( Map.Trammel.CanSpawnMobile( x, y, z ) ) + { + m_Ambushed = true; + + player.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1049330 ); // You have been ambushed! Fight for your honor!!! + + BaseCreature creature = new HordeMinion(); + creature.MoveToWorld( new Point3D( x, y, z ), Map.Trammel ); + creature.Combatant = player; + } + } + } + + public override void OnComplete() + { + System.AddObjective( new ReturnDaemonBloodObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Ambushed = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Ambushed ); + } + } + + public class ReturnDaemonBloodObjective : QuestObjective + { + public override object Message + { + get + { + /* You have the vial of blood!

+ * + * Return to Uzeraan's mansion and hand him the vial. + */ + return 1049332; + } + } + + public ReturnDaemonBloodObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new UzeraanDaemonBloodConversation() ); + } + } + + public class GetDaemonBoneObjective : QuestObjective + { + private Container m_CorpseWithBone; + + public Container CorpseWithBone + { + get { return m_CorpseWithBone; } + set { m_CorpseWithBone = value; } + } + + public override object Message + { + get + { + if ( System.From.Profession == 5 ) + { + /* Use your Sacred Journey + * ability on the rune to the North + * of Uzeraan to travel to the graveyard. + */ + return 1060755; + } + else + { + /* Use Uzeraan's teleporter to get to the Haunted graveyard.

+ * + * Slay the undead until you find a Daemon Bone. + */ + return 1049362; + } + } + } + + public GetDaemonBoneObjective() + { + } + + public override void OnComplete() + { + System.AddObjective( new ReturnDaemonBoneObjective() ); + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + // This restriction continues until the end of the quest + if ( ( from is Zombie || from is Skeleton ) && from.Map == Map.Trammel && from.X >= 3391 && from.X <= 3424 && from.Y >= 2639 && from.Y <= 2664 ) // Haven graveyard + return true; + + return false; + } + + public override bool GetKillEvent( BaseCreature creature, Container corpse ) + { + if ( base.GetKillEvent( creature, corpse ) ) + return true; + + return UzeraanTurmoilQuest.HasLostDaemonBone( System.From ); + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( ( creature is Zombie || creature is Skeleton ) && corpse.Map == Map.Trammel && corpse.X >= 3391 && corpse.X <= 3424 && corpse.Y >= 2639 && corpse.Y <= 2664 ) // Haven graveyard + { + if ( Utility.RandomDouble() < 0.25 ) + m_CorpseWithBone = corpse; + } + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_CorpseWithBone = (Container) reader.ReadItem(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + if ( m_CorpseWithBone != null && m_CorpseWithBone.Deleted ) + m_CorpseWithBone = null; + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Item) m_CorpseWithBone ); + } + } + + public class ReturnDaemonBoneObjective : QuestObjective + { + public override object Message + { + get + { + /* Head East of here (or use the Horn of Retreat) + * to return to Uzeraan's Mansion and deliver the bone to Uzeraan. + */ + return 1049334; + } + } + + public ReturnDaemonBoneObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new UzeraanDaemonBoneConversation() ); + } + } + + public class CashBankCheckObjective : QuestObjective + { + public override object Message + { + get + { + /* Locate the Haven Bank (use the teleporter in Uzeraan's Mansion + * if necessary), which lies South-East + * of Uzeraan's Mansion. Once there, cash your check. + */ + return 1049336; + } + } + + public CashBankCheckObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new BankerConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs b/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs new file mode 100644 index 0000000..1054533 --- /dev/null +++ b/Scripts/Engines/Quests/Uzeraan Turmoil/UzeraanTurmoilQuest.cs @@ -0,0 +1,232 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.Quests.Haven +{ + public class UzeraanTurmoilQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Haven.AcceptConversation ), + typeof( Haven.UzeraanTitheConversation ), + typeof( Haven.UzeraanFirstTaskConversation ), + typeof( Haven.UzeraanReportConversation ), + typeof( Haven.SchmendrickConversation ), + typeof( Haven.UzeraanScrollOfPowerConversation ), + typeof( Haven.DryadConversation ), + typeof( Haven.UzeraanFertileDirtConversation ), + typeof( Haven.UzeraanDaemonBloodConversation ), + typeof( Haven.UzeraanDaemonBoneConversation ), + typeof( Haven.BankerConversation ), + typeof( Haven.RadarConversation ), + typeof( Haven.LostScrollOfPowerConversation ), + typeof( Haven.LostFertileDirtConversation ), + typeof( Haven.DryadAppleConversation ), + typeof( Haven.LostDaemonBloodConversation ), + typeof( Haven.LostDaemonBoneConversation ), + typeof( Haven.FindUzeraanBeginObjective ), + typeof( Haven.TitheGoldObjective ), + typeof( Haven.FindUzeraanFirstTaskObjective ), + typeof( Haven.KillHordeMinionsObjective ), + typeof( Haven.FindUzeraanAboutReportObjective ), + typeof( Haven.FindSchmendrickObjective ), + typeof( Haven.FindApprenticeObjective ), + typeof( Haven.ReturnScrollOfPowerObjective ), + typeof( Haven.FindDryadObjective ), + typeof( Haven.ReturnFertileDirtObjective ), + typeof( Haven.GetDaemonBloodObjective ), + typeof( Haven.ReturnDaemonBloodObjective ), + typeof( Haven.GetDaemonBoneObjective ), + typeof( Haven.ReturnDaemonBoneObjective ), + typeof( Haven.CashBankCheckObjective ), + typeof( Haven.FewReagentsConversation ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // "Uzeraan's Turmoil" + return 1049007; + } + } + + public override object OfferMessage + { + get + { + /* The guard speaks to you as you come closer...

+ * + * Greetings traveler!

+ * + * Uzeraan, the lord of this house and overseer of this city - + * Haven, has requested an audience with you.

+ * + * Hordes of gruesome hell spawn are beginning to overrun the + * city and terrorize the inhabitants. No one seems to be able + * to stop them.

+ * + * Our fine city militia is falling to the evil creatures + * one battalion after the other.

+ * + * Uzeraan, whom you can find through these doors, is looking to + * hire mercenaries to aid in the battle.

+ * + * Will you assist us? + */ + return 1049008; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.MaxValue; } } + public override bool IsTutorial{ get{ return true; } } + + public override int Picture + { + get + { + switch ( From.Profession ) + { + case 1: return 0x15C9; // warrior + case 2: return 0x15C1; // magician + default: return 0x15D3; // paladin + } + } + } + + private bool m_HasLeftTheMansion; + + public override void Slice() + { + if ( !m_HasLeftTheMansion && ( From.Map != Map.Trammel || From.X < 3573 || From.X > 3611 || From.Y < 2568 || From.Y > 2606 ) ) + { + m_HasLeftTheMansion = true; + AddConversation( new RadarConversation() ); + } + + base.Slice(); + } + + public UzeraanTurmoilQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public UzeraanTurmoilQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_HasLeftTheMansion = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_HasLeftTheMansion ); + } + + public static bool HasLostScrollOfPower( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( ReturnScrollOfPowerObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( SchmendrickScrollOfPower ) ) == null ); + } + } + + return false; + } + + public static bool HasLostFertileDirt( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( ReturnFertileDirtObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( QuestFertileDirt ) ) == null ); + } + } + + return false; + } + + public static bool HasLostDaemonBlood( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( ReturnDaemonBloodObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( QuestDaemonBlood ) ) == null ); + } + } + + return false; + } + + public static bool HasLostDaemonBone( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + QuestSystem qs = pm.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( ReturnDaemonBoneObjective ) ) ) + { + Container pack = from.Backpack; + + return ( pack == null || pack.FindItemByType( typeof( QuestDaemonBone ) ) == null ); + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Conversations.cs b/Scripts/Engines/Quests/Witch Apprentice/Conversations.cs new file mode 100644 index 0000000..48323a9 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Conversations.cs @@ -0,0 +1,732 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Hag +{ + public class DontOfferConversation : QuestConversation + { + public override object Message + { + get + { + /* The ancient, wrinkled hag looks up from her vile-smelling cauldron. + * Her single, unblinking eye attempts to focus in on you, but to + * little avail.

+ * + * What's that? Who's there? What do you want with me? I don't have + * time for the likes of you. I have stews to spice and brews to boil. + * Too many things to complete to be helping out a stranger.

+ * + * Besides, it looks as if you've already got yourself a quest that needs + * doing. Perhaps if you finish the task you're on, you can return to me + * and I'll help you out. But until then, leave an old witch alone to her + * magics! Shoo! Away with ye!

+ * + * The witch rushes you off with a wave of her decrepit hand and returns + * to tending the noxious brew boiling in her cauldron. + */ + return 1055000; + } + } + + public override bool Logged{ get{ return false; } } + + public DontOfferConversation() + { + } + } + + public class AcceptConversation : QuestConversation + { + public override object Message + { + get + { + /* Somewhat out of character for the vile old witch, she actually seems + * delighted that you've accepted her offer.

+ * + * Ah! That's the spirit! You're not a useless bag of bones after all, are ye? + * Well then, best get your hind quarters in gear and head towards the road! + * Remember, my young Apprentice could be anywhere along the road heading towards + * the Yew Graveyard, so be sure to run the whole course of it, and stay + * on track!

+ * + * And for Gashnak's sake, come back here when you've found something! And remember, + * I don't have all day! And watch out for the imp Zeefzorpul! And don't return + * empty handed! And pack a warm sweater! And don't trample my lawn on the + * way out!

+ * + * What are you still doing here? Get to it! Shoo! + */ + return 1055002; + } + } + + public AcceptConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindApprenticeObjective( true ) ); + } + } + + public class HagDuringCorpseSearchConversation : QuestConversation + { + public override object Message + { + get + { + /* The wrinkled hag looks up at you with venom in her eyes.

+ * + * What're you doing back here? I thought I told you to go find my lost + * Apprentice! I don't have time for your laziness, you wretched little worm! + * Shoo! Away with ye! And don't come back until you've found out what's + * happened to my Apprentice! + */ + return 1055003; + } + } + + public override bool Logged{ get{ return false; } } + + public HagDuringCorpseSearchConversation() + { + } + } + + public class ApprenticeCorpseConversation : QuestConversation + { + public override object Message + { + get + { + /* You inspect the charred and bloodied corpse, recognizing it from the + * Hag's description as the lost Apprentice you were tasked to + * bring back.

+ * + * It appears as if he has been scorched by fire and magic, and scratched + * at with vicious claws.

+ * + * You wonder if this horrific act is the work of the vile imp Zeefzorpul + * of which the Hag spoke. You decide you'd best return to the Hag and + * report your findings. + */ + return 1055004; + } + } + + public ApprenticeCorpseConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindGrizeldaAboutMurderObjective() ); + } + } + + public class MurderConversation : QuestConversation + { + public override object Message + { + get + { + /* The wrinkled old Hag looks up from her cauldron of boiling + * innards.

+ * + * Bah! Back already? Can't you see I'm busy with my cooking? You + * wouldn't like to have a little taste of my delicious dragon gizzard soup, + * would you? Haw! I thought as much.

+ * + * Enough of this jibber-jabber then - what news of my Apprentice?

+ * + * What's that? You say that horrible little imp Zeefzorpul was behind his + * disappearance!? What would Zeefzorpul want with my Apprentice? Probably + * just wants to make life more miserable for me than it already is.

+ * + * Wait! Bah! That must be it! Zeefzorpul must have found out that I sent + * my Apprentices out with various Magic Brew Recipes - lists of tasks and + * ingredients that needed completing.

+ * + * That despicable Zeefzorpul knows I need the list of ingredients I gave to + * that Apprentice. I've recipes to mix, stews to boil, magics to cast, and + * fortunes to meddle! I won't let that wretched felchscum spoil my day. + * You then, I need you to go find Zeefzorpul and get that scrap of + * parchment back!

+ * + * I'm not sure where he bides his time, but I'm sure if you go find his imp + * friends and rough them up, they'll squeal on him in no time! They all + * know each others' secret hiding places. Go on! Shoo! Go slay a few imps + * until they cough up their secrets! No mercy for those little nasties! + */ + return 1055005; + } + } + + public MurderConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new KillImpsObjective( true ) ); + } + } + + public class HagDuringImpSearchConversation : QuestConversation + { + public override object Message + { + get + { + /* The sickly old hag looks up from her boiling cauldron.

+ * + * Have you found that vile little Zeefzorpul yet? What!? You've come + * back here without finding out where Zeefzorpul is, and what he's done + * with my Magic Brew Recipe?

+ * + * I told you what needs to be done, you little whelp! Now away with ye! + * And don't you return until you've found my list of ingredients! + */ + return 1055006; + } + } + + public override bool Logged{ get{ return false; } } + + public HagDuringImpSearchConversation() + { + } + } + + public class ImpDeathConversation : QuestConversation + { + private Point3D m_ImpLocation; + + public override object Message + { + get + { + /* The wretched imp cries out for mercy.

+ * + * Forgive me! You master! You great warrior, great hooman, great greatest! + * Forgive! Forgive! I give up Zeef! He no good any way! He always smack me + * head and hurt me good! He say I ugly too, even with me pretty teef!

+ * + * But I knows where he hide! I follow him flapping to his hidey hole. + * He think he so smart but he so wrong! I make scribble drawing of where he + * like to hide! But you need the whistle blower to make him come! He no come + * without it! Make with the whistle at his hidey place, and Zeef must come, + * he cannot resist!

+ * + * The frightened imp hands you a crumpled map and a strange flute.

+ * + * You go to where the picture shows and then you play that whistle! Zeef come, + * me promise! But you make promise that you smack Zeef head good! + * Pweese?

+ * + * With this last request, the miserable little imp falls and breathes no more. + */ + return 1055007; + } + } + + public ImpDeathConversation( Point3D impLocation ) + { + m_ImpLocation = impLocation; + } + + public ImpDeathConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindZeefzorpulObjective( m_ImpLocation ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_ImpLocation = reader.ReadPoint3D(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Point3D) m_ImpLocation ); + } + } + + public class ZeefzorpulConversation : QuestConversation + { + public override object Message + { + get + { + /* In a puff of smoke that smells of brimstone, the imp Zeefzorpul + * appears.

+ * + * Wuh-whut!? How did stupid hooman find mighty Zeefzorpul? This crazy + * many times! This crazy not possible! This big crazy with crazy on top! + * But it happening! How can it be true!?

+ * + * GAH! Even mighty Zeefzorpul can no resist that crazy music! Mighty + * Zeefzorpul do what you want! Have you stupid paper back! Mighty Zeefzorpul + * no want it any way. It dumb. It super dumb. Big dumb like stupid dumb + * tree with dumb things on it! So stupid! So dumb that mighty Zeefzorpul + * not even care! You see me not caring? You better cause it certainly + * happening! Me not caring one bit!

+ * + * The strange little imp tosses the piece of parchment at you. Much + * to your surprise, however, he swoops down in a flash of flapping wings + * and steals the Magic Flute from your grasp.

+ * + * Hah! So stupid like a hooman! Mighty Zeefzorpul has defeated stupid + * hooman and is greatest ever imp in world! You serious stupid, mister + * hooman. Big stupid with stupid on top. Now you no can make trick on me + * again with crazy dance music! Mighty Zeefzorpul fly away to his other + * secret home where you never find him again!

+ * + * Me hope you get eated by a troll!

+ * + * With that, the imp Zeefzorpul disappears in another puff of rancid smoke. + */ + return 1055008; + } + } + + public ZeefzorpulConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new ReturnRecipeObjective() ); + } + } + + public class RecipeConversation : QuestConversation + { + public override object Message + { + get + { + /* The wart-covered witch looks up from pouring fetid scraps of meat + * into her cauldron.

+ * + * You've dealt with that troublesome imp Zeefzorpul? Good for you, little + * one! You're not as useless as you appear, even to a daft old wench such + * as myself!

+ * + * Now then, I see you've recovered my precious Magic Brew Recipe. I suppose + * you expect a reward? Well, you can go on expecting, and I can go on being + * ugly. What good is it to me that I have the list, if I don't have an + * apprentice to go gather the ingredients and perform the tasks + * themselves!

+ * + * If you want your precious little reward, you'll have to complete the task + * I gave to my previous Apprentice. Now away with you! Shoo! Shimmy! Skedattle! + * I've heads to boil and stews to spice! Don't you return until you've completed + * every item on that list! + */ + return 1055009; + } + } + + public RecipeConversation() + { + } + + public override void OnRead() + { + System.AddObjective( new FindIngredientObjective( new Ingredient[0] ) ); + } + } + + public class HagDuringIngredientsConversation : QuestConversation + { + public override object Message + { + get + { + /* The ancient crone looks up from her bubbling brew, staring you down + * with her one good eye.

+ * + * You've returned already have you? And what of your task? Have you gathered + * all the needed ingredients?

+ * + * What's that!? You still haven't finished the simple little task I've set before + * you? Then why come back here and bother me? I can't get a single brew + * concocted if you keep bugging me with your whimpering little diatribes! Why, + * you're worse than my last apprentice - and he was the very king of fools!

+ * + * Go on with ye! Away and begone! I don't want to see hide nor hair of your + * whining little face until you've gathered each and every last one of the ingredients + * on that list!

+ * + * With a disgusting hacking noise, the vile witch spits upon the ground and + * brushes you off with a wave of her wrinkled old hand. + */ + return 1055012; + } + } + + public override bool Logged{ get{ return false; } } + + public HagDuringIngredientsConversation() + { + } + } + + public class BlackheartFirstConversation : QuestConversation + { + public override object Message + { + get + { + /* The bawdy old pirate captain looks up from his bottle of Wild Harpy + * whiskey, as drunk as any man you've ever seen.

+ * + * With an excruciatingly slow movement, he pushes back his tricorne hat + * and stares you down with red-rimmed eyes.


+ * + * Whut tha blazes do ye want, landlubber? Some've Captain Blackheart's + * fine Whiskey? Well ye can drown in the seven seas, ya barnacle-covered + * bilge rat!

+ * + * I've cut down pasty-faced runts like yerself for lesser insults! I've + * sailed the seas've this world fer fifty years, and never seen a more + * milk-soaked pansy lass than ye come in here for a favor. Give ye some + * of my special Whiskey? I'd sooner wrestle a sea serpent naked - and I've + * done that some twenty times!

+ * + * Ye see, ol' Captain Blackheart's Whiskey is only for pirate folk. And ye + * don't look like no pirate I've ever seen. Ye have te have the right cut + * of cloth and the right amount of liquor in yer belly te sail on my crew! + * And without that, ye might as well go home and cry to yer mommy. Cause + * ye ain't ever gonna share no drink with me!

+ * + * Now off with ye!

+ * + * With that, Captain Blackheart goes back to singing his bawdy songs + * and drinking his whiskey. It seems as if you'll have to find some way to + * change his mind about your worthiness. + */ + return 1055010; + } + } + + public BlackheartFirstConversation() + { + } + + public override void OnRead() + { + FindIngredientObjective obj = System.FindObjective( typeof( FindIngredientObjective ) ) as FindIngredientObjective; + + if ( obj != null ) + System.AddObjective( new FindIngredientObjective( obj.Ingredients, true ) ); + } + } + + public class BlackheartNoPirateConversation : QuestConversation + { + private bool m_Tricorne; + private bool m_Drunken; + + public override object Message + { + get + { + if ( m_Tricorne) + { + if ( m_Drunken ) + { + /* The filthy Captain flashes a pleased grin at you as he looks you up + * and down.

Well that's more like it, me little deck swabber! + * Ye almost look like ye fit in around here, ready te sail the great seas + * of Britannia, sinking boats and slaying sea serpents!

+ * + * But can ye truly handle yerself? Ye might think ye can test me meddle + * with a sip or two of yer dandy wine, but a real pirate walks the decks + * with a belly full of it. Lookit that, yer not even wobblin'!

+ * + * Ye've impressed me a bit, ye wee tyke, but it'll take more'n that te + * join me crew!

Captain Blackheart tips his mug in your direction, + * offering up a jolly laugh, but it seems you still haven't impressed him + * enough. + */ + return 1055059; + } + else + { + /* Captain Blackheart looks up from polishing his cutlass, glaring at + * you with red-rimmed eyes.

+ * + * Well, well. Lookit the wee little deck swabby. Aren't ye a cute lil' + * lassy? Don't ye look just fancy? Ye think yer ready te join me pirate + * crew? Ye think I should offer ye some've me special Blackheart brew?

+ * + * I'll make ye walk the plank, I will! We'll see how sweet n' darlin' ye + * look when the sea serpents get at ye and rip ye te threads! Won't that be + * a pretty picture, eh?

+ * + * Ye don't have the stomach fer the pirate life, that's plain enough te me. Ye + * prance around here like a wee lil' princess, ye do. If ye want to join my + * crew ye can't just look tha part - ye have to have the stomach fer it, filled + * up with rotgut until ye can't see straight. I don't drink with just any ol' + * landlubber! Ye'd best prove yer mettle before ye talk te me again!

+ * + * The drunken pirate captain leans back in his chair, taking another gulp of + * his drink before he starts in on another bawdy pirate song. + */ + return 1055057; + } + } + else + { + if ( m_Drunken ) + { + /* The inebriated pirate looks up at you with a wry grin.

+ * + * Well hello again, me little matey. I see ye have a belly full of rotgut + * in ye. I bet ye think you're a right hero, ready te face the world. But + * as I told ye before, bein' a member of my pirate crew means more'n just + * being able to hold yer drink. Ye have te look the part - and frankly, me + * little barnacle, ye don't have the cut of cloth te fit in with the crowd I + * like te hang around.

+ * + * So scurry off, ye wee sewer rat, and don't come back round these parts all + * liquored up an' three sheets te tha wind, unless yer truly ready te join + * me pirate crew!

+ * + * Captain Blackheart shoves you aside, banging his cutlass against the + * table as he calls to the waitress for another round. + */ + return 1055056; + } + else + { + /* Captain Blackheart looks up from his drink, almost tipping over + * his chair as he looks you up and down.

+ * + * You again? I thought I told ye te get lost? Go on with ye! Ye ain't + * no pirate - yer not even fit te clean the barnacles off me rear end! + * Don't ye come back babbling te me for any of me Blackheart Whiskey until + * ye look and act like a true pirate!

+ * + * Now shove off, sewer rat - I've got drinkin' te do!

+ * + * The inebriated pirate bolts back another mug of ale and brushes you + * off with a wave of his hand. + */ + return 1055058; + } + } + } + } + + public override bool Logged{ get{ return false; } } + + public BlackheartNoPirateConversation( bool tricorne, bool drunken ) + { + m_Tricorne = tricorne; + m_Drunken = drunken; + } + + public BlackheartNoPirateConversation() + { + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Tricorne = reader.ReadBool(); + m_Drunken = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_Tricorne ); + writer.Write( (bool) m_Drunken ); + } + } + + public class BlackheartPirateConversation : QuestConversation + { + private bool m_FirstMet; + + public override object Message + { + get + { + if ( m_FirstMet ) + { + /* The bawdy old pirate captain looks up from his bottle of Wild Harpy + * whiskey, as drunk as any man you've ever seen.

+ * + * Avast ye, ye loveable pirate! Just in from sailin' the glorious sea? Ye + * look right ready te fall down on the spot, ye do!

+ * + * I tell ye what, from the look've ye, ye deserve a belt of better brew than + * the slop ye've been drinking, and I've just the thing.

+ * + * I call it Captain Blackheart's Whiskey, and it'll give ye hairs on yer chest, + * that's for sure. Why, a keg of this stuff once spilled on my ship, and it + * ate a hole right through the deck!

Go on, drink up, or use it to clean + * the rust off your cutlass - it's the best brew, either way!

+ * + * Captain Blackheart hands you a jug of his famous Whiskey. You think it best + * to return it to the Hag, rather than drink any of the noxious swill. + */ + return 1055054; + } + else + { + /* The drunken pirate, Captain Blackheart, looks up from his bottle + * of whiskey with a pleased expression.

+ * + * Well looky here! I didn't think a landlubber like yourself had the pirate + * blood in ye! But look at that! You certainly look the part now! Sure + * you can still keep on your feet? Har!

+ * + * Avast ye, ye loveable pirate! Ye deserve a belt of better brew than the slop + * ye've been drinking, and I've just the thing.

+ * + * I call it Captain Blackheart's Whiskey, and it'll give ye hairs on yer chest, + * that's for sure. Why, a keg of this stuff once spilled on my ship, and it ate + * a hole right through the deck!

+ * + * Go on, drink up, or use it to clean the rust off your cutlass - it's the best + * brew, either way!

+ * + * Captain Blackheart hands you a jug of his famous Whiskey. You think it best + * to return it to the Hag, rather than drink any of the noxious swill. + */ + return 1055011; + } + } + } + + public BlackheartPirateConversation( bool firstMet ) + { + m_FirstMet = firstMet; + } + + public BlackheartPirateConversation() + { + } + + public override void OnRead() + { + FindIngredientObjective obj = System.FindObjective( typeof( FindIngredientObjective ) ) as FindIngredientObjective; + + if ( obj != null ) + obj.NextStep(); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_FirstMet = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (bool) m_FirstMet ); + } + } + + public class EndConversation : QuestConversation + { + public override object Message + { + get + { + /* The horrible wretch of a witch looks up from her vile experiments + * and focuses her one good eye on you.

+ * + * Eh? What's that? You say you've gathered the ingredients for my delicious + * Magic Brew?

+ * + * Well, well, I don't know exactly what to say. I thought for sure you'd + * end up dead! Haw! Can't blame a lady for wishing, can you? Even if she + * is a bit old and wrinkled.

+ * + * Well, I promised you a reward for your efforts, and I never lie - leastways + * not to someone like you, after the great sacrifices you've made. You know, + * I could use a new Apprentice, in an official capacity as it were. I couldn't + * convince you to stay around and help me out some more could I? There's always + * cauldrons that need cleaning, dung that needs shoveling, newts eye that + * needs a proper chewing, and fires that need stoking.

+ * + * What's that? Not interested? Well, I suppose you have great things ahead of + * you and all that. Feh! Like a puckish little puke like you could ever make + * something of themselves in this cold old world!

+ * + * Nevertheless, I'll give you your blasted reward, and you'd better be happy + * with it because it's all you're getting. Caused me enough trouble as it is. + * Here, take it, and be off with you! It'll be a pleasure to my eye if I + * never have to squint to see you again! And the stench! Smells like you + * washed this very morning! A great fancy folk you are, with your soaps and + * water! Think you're so great...why, I remember when we didn't even have + * soap, and water was made by tiny little fairies and cost a gold piece for + * a thimbleful...I could tell you some stories, I could...

+ * + * Your reward in hand, you decide to leave the old Hag to her mumblings + * before she realizes you're still around and puts you back to work. + */ + return 1055013; + } + } + + public EndConversation() + { + } + + public override void OnRead() + { + System.Complete(); + } + } + + public class RecentlyFinishedConversation : QuestConversation + { + public override object Message + { + get + { + /* The wrinkled old crone stops stirring her noxious stew, looking up at + * you with an annoyed expression on her face.

+ * + * You again? Listen, you little wretch, I'm in no mood for any of your meddlesome + * requests. I've work to do, and no time for your whining.

+ * + * Come back later, and maybe I'll have something for you to do. In the meantime, + * get out of my sight - and don't touch anything on your way out!

+ * + * The vile hag hacks up a gob of phlegm, spitting it on the ground before + * returning to her work. + */ + return 1055064; + } + } + + public RecentlyFinishedConversation() + { + } + + public override bool Logged{ get{ return false; } } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs b/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs new file mode 100644 index 0000000..742ee51 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Ingredient.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Hag +{ + public enum Ingredient + { + SheepLiver, + RabbitsFoot, + MongbatWing, + ChickenGizzard, + RatTail, + FrogsLeg, + DeerHeart, + LizardTongue, + SlimeOoze, + SpiritEssence, + SwampWater, + RedMushrooms, + Bones, + StarChart, + Whiskey + } + + public class IngredientInfo + { + private static IngredientInfo[] m_Table = new IngredientInfo[] + { + // sheep liver + new IngredientInfo( 1055020, 5, typeof( Sheep ) ), + // rabbit's foot + new IngredientInfo( 1055021, 5, typeof( Rabbit ), typeof( JackRabbit ) ), + // mongbat wing + new IngredientInfo( 1055022, 5, typeof( Mongbat ), typeof( GreaterMongbat ) ), + // chicken gizzard + new IngredientInfo( 1055023, 5, typeof( Chicken ) ), + // rat tail + new IngredientInfo( 1055024, 5, typeof( Rat ), typeof( GiantRat ), typeof( Sewerrat ) ), + // frog's leg + new IngredientInfo( 1055025, 5, typeof( BullFrog ) ), + // deer heart + new IngredientInfo( 1055026, 5, typeof( Hind ), typeof( GreatHart ) ), + // lizard tongue + new IngredientInfo( 1055027, 5, typeof( LavaLizard ), typeof( Lizardman ) ), + // slime ooze + new IngredientInfo( 1055028, 5, typeof( Slime ) ), + // spirit essence + new IngredientInfo( 1055029, 5, typeof( Ghoul ), typeof( Spectre ), typeof( Shade ), typeof( Wraith ), typeof( Bogle ) ), + // Swamp Water + new IngredientInfo( 1055030, 1 ), + // Freshly Cut Red Mushrooms + new IngredientInfo( 1055031, 1 ), + // Bones Buried In Hallowed Ground + new IngredientInfo( 1055032, 1 ), + // Star Chart + new IngredientInfo( 1055033, 1 ), + // Captain Blackheart's Whiskey + new IngredientInfo( 1055034, 1 ) + }; + + public static IngredientInfo Get( Ingredient ingredient ) + { + int index = (int)ingredient; + + if ( index >= 0 && index < m_Table.Length ) + return m_Table[index]; + else + return m_Table[0]; + } + + public static Ingredient RandomIngredient( Ingredient[] oldIngredients ) + { + int length = m_Table.Length - oldIngredients.Length; + Ingredient[] ingredients = new Ingredient[length]; + + for ( int i = 0, n = 0; i < m_Table.Length && n < ingredients.Length; i++ ) + { + Ingredient currIngredient = (Ingredient)i; + + bool found = false; + for ( int j = 0; !found && j < oldIngredients.Length; j++ ) + { + if ( oldIngredients[j] == currIngredient ) + found = true; + } + + if ( !found ) + ingredients[n++] = currIngredient; + } + + int index = Utility.Random( ingredients.Length ); + + return ingredients[index]; + } + + private int m_Name; + private Type[] m_Creatures; + private int m_Quantity; + + public int Name{ get{ return m_Name; } } + public Type[] Creatures{ get{ return m_Creatures; } } + public int Quantity{ get{ return m_Quantity; } } + + private IngredientInfo( int name, int quantity, params Type[] creatures ) + { + m_Name = name; + m_Creatures = creatures; + m_Quantity = quantity; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/Cauldron.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/Cauldron.cs new file mode 100644 index 0000000..5553543 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/Cauldron.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Cauldron : Item + { + public override string DefaultName + { + get { return "a cauldron"; } + } + + [Constructable] + public Cauldron() : base( 0x9ED ) + { + Weight = 1.0; + } + + public Cauldron( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs new file mode 100644 index 0000000..84bac68 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/HagApprenticeCorpse.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Misc; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Hag +{ + public class HagApprenticeCorpse : Corpse + { + private static Mobile GetOwner() + { + Mobile apprentice = new Mobile(); + + apprentice.Hue = Utility.RandomSkinHue(); + apprentice.Female = false; + apprentice.Body = 0x190; + + apprentice.Delete(); + + return apprentice; + } + + private static List GetEquipment() + { + return new List(); + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( "a charred corpse" ); + } + + public override void OnSingleClick( Mobile from ) + { + int hue = Notoriety.GetHue( NotorietyHandlers.CorpseNotoriety( from, this ) ); + + from.Send( new AsciiMessage( Serial, ItemID, MessageType.Label, hue, 3, "", "a charred corpse" ) ); + } + + [Constructable] + public HagApprenticeCorpse() : base( GetOwner(), GetEquipment() ) + { + Direction = Direction.South; + + foreach ( Item item in EquipItems ) + { + DropItem( item ); + } + } + + public HagApprenticeCorpse( Serial serial ) : base( serial ) + { + } + + public override void Open( Mobile from, bool checkSelfLoot ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + return; + + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + FindApprenticeObjective obj = qs.FindObjective( typeof( FindApprenticeObjective ) ) as FindApprenticeObjective; + + if ( obj != null && !obj.Completed ) + { + if ( obj.Corpse == this ) + { + obj.Complete(); + Delete(); + } + else + { + SendLocalizedMessageTo( from, 1055047 ); // You examine the corpse, but it doesn't fit the description of the particular apprentice the Hag tasked you with finding. + } + + return; + } + } + } + + SendLocalizedMessageTo( from, 1055048 ); // You examine the corpse, but find nothing of interest. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/HagCauldron.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/HagCauldron.cs new file mode 100644 index 0000000..0ed3025 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/HagCauldron.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HagCauldron : BaseAddon + { + + [Constructable] + public HagCauldron() + { + AddonComponent pot; + pot = new AddonComponent(2420); + AddComponent(pot, 0, 0, 0); //pot w/ support + + AddonComponent fire; + fire = new AddonComponent(4012); //fire pit + fire.Light = LightType.Circle150; + AddComponent(fire, 0, 0, 0); + } + + public HagCauldron( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/HagStew.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/HagStew.cs new file mode 100644 index 0000000..aeb5513 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/HagStew.cs @@ -0,0 +1,76 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HagStew : BaseAddon + { + + [Constructable] + public HagStew() + { + AddonComponent stew; + stew = new AddonComponent(2416); + stew.Name = "stew"; + stew.Visible = true; + AddComponent(stew, 0, 0, -7); //stew + } + + public override void OnComponentUsed(AddonComponent stew, Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + from.SendMessage("You are too far away."); + else + { + { + stew.Visible = false; + + BreadLoaf hagstew = new BreadLoaf(); //this decides your fillrate + hagstew.Eat(from); + + Timer m_timer = new ShowStew(stew); + m_timer.Start(); + } + } + } + + public class ShowStew : Timer + { + private AddonComponent stew; + + public ShowStew(AddonComponent ac) : base(TimeSpan.FromSeconds(30)) + { + stew = ac; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if ( stew.Visible == false ) + { + Stop(); + stew.Visible = true; + return; + } + } + } + + public HagStew( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/HangoverCure.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/HangoverCure.cs new file mode 100644 index 0000000..a4791f0 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/HangoverCure.cs @@ -0,0 +1,90 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Hag +{ + public class HangoverCure : Item + { + private int m_Uses; + + public override int LabelNumber{ get{ return 1055060; } } // Grizelda's Extra Strength Hangover Cure + + [CommandProperty( AccessLevel.GameMaster )] + public int Uses + { + get{ return m_Uses; } + set{ m_Uses = value; } + } + + [Constructable] + public HangoverCure() : base( 0xE2B ) + { + Weight = 1.0; + Hue = 0x2D; + + m_Uses = 20; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + SendLocalizedMessageTo( from, 1042038 ); // You must have the object in your backpack to use it. + return; + } + + if ( m_Uses > 0 ) + { + from.PlaySound( 0x2D6 ); + from.SendLocalizedMessage( 501206 ); // An awful taste fills your mouth. + + if ( from.BAC > 0 ) + { + from.BAC = 0; + from.SendLocalizedMessage( 501204 ); // You are now sober! + } + + m_Uses--; + } + else + { + Delete(); + from.SendLocalizedMessage( 501201 ); // There wasn't enough left to have any effect. + } + } + + public HangoverCure( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.WriteEncodedInt( m_Uses ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Uses = reader.ReadEncodedInt(); + break; + } + case 0: + { + m_Uses = 20; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/MagicFlute.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/MagicFlute.cs new file mode 100644 index 0000000..754b882 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/MagicFlute.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Hag +{ + public class MagicFlute : Item + { + public override int LabelNumber{ get{ return 1055051; } } // magic flute + + [Constructable] + public MagicFlute() : base( 0x1421 ) + { + Hue = 0x8AB; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + SendLocalizedMessageTo( from, 1042292 ); // You must have the object in your backpack to use it. + return; + } + + from.PlaySound( 0x3D ); + + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + FindZeefzorpulObjective obj = qs.FindObjective( typeof( FindZeefzorpulObjective ) ) as FindZeefzorpulObjective; + + if ( obj != null && !obj.Completed ) + { + if ( ( player.Map != Map.Trammel && player.Map != Map.Felucca ) || !player.InRange( obj.ImpLocation, 8 ) ) + { + player.SendLocalizedMessage( 1055053 ); // Nothing happens. Zeefzorpul must not be hiding in this area. + } + else if ( player.InRange( obj.ImpLocation, 4 ) ) + { + Delete(); + + obj.Complete(); + } + else + { + player.SendLocalizedMessage( 1055052 ); // The flute sparkles. Zeefzorpul must be in a good hiding place nearby. + } + } + } + } + } + + public MagicFlute( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Items/MoonfireBrew.cs b/Scripts/Engines/Quests/Witch Apprentice/Items/MoonfireBrew.cs new file mode 100644 index 0000000..6d0eb30 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Items/MoonfireBrew.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Engines.Quests.Hag +{ + public class MoonfireBrew : Item + { + public override int LabelNumber{ get{ return 1055065; } } // a bottle of magical moonfire brew + + [Constructable] + public MoonfireBrew() : base( 0xF04 ) + { + Weight = 1.0; + } + + public MoonfireBrew( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Blackheart.cs b/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Blackheart.cs new file mode 100644 index 0000000..b003850 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Blackheart.cs @@ -0,0 +1,120 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Hag +{ + public class Blackheart : BaseQuester + { + [Constructable] + public Blackheart() : base( "the Drunken Pirate" ) + { + } + + public Blackheart( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83EF; + + Female = false; + Body = 0x190; + Name = "Captain Blackheart"; + } + + public override void InitOutfit() + { + AddItem( new FancyShirt() ); + AddItem( new LongPants( 0x66D ) ); + AddItem( new ThighBoots() ); + AddItem( new TricorneHat( 0x1 ) ); + AddItem( new BodySash( 0x66D ) ); + + LeatherGloves gloves = new LeatherGloves(); + gloves.Hue = 0x66D; + AddItem( gloves ); + + FacialHairItemID = 0x203E; // Long Beard + FacialHairHue = 0x455; + + Item sword = new Cutlass(); + sword.Movable = false; + AddItem( sword ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + Direction = GetDirectionTo( player ); + Animate( 33, 20, 1, true, false, 0 ); + + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + FindIngredientObjective obj = qs.FindObjective( typeof( FindIngredientObjective ) ) as FindIngredientObjective; + + if ( obj != null && !obj.Completed && obj.Ingredient == Ingredient.Whiskey ) + { + PlaySound( Utility.RandomBool() ? 0x42E : 0x43F ); + + Item hat = player.FindItemOnLayer( Layer.Helm ); + bool tricorne = hat is TricorneHat; + + if ( tricorne && player.BAC >= 20 ) + { + obj.Complete(); + + if ( obj.BlackheartMet ) + qs.AddConversation( new BlackheartPirateConversation( false ) ); + else + qs.AddConversation( new BlackheartPirateConversation( true ) ); + } + else if ( !obj.BlackheartMet ) + { + obj.Complete(); + + qs.AddConversation( new BlackheartFirstConversation() ); + } + else + { + qs.AddConversation( new BlackheartNoPirateConversation( tricorne, player.BAC > 0 ) ); + } + + return; + } + } + + PlaySound( 0x42C ); + SayTo( player, 1055041 ); // The drunken pirate shakes his fist at you and goes back to drinking. + } + + private void Heave() + { + this.PublicOverheadMessage( Network.MessageType.Regular, 0x3B2, 500849 ); // *hic* + + Timer.DelayCall( TimeSpan.FromSeconds( Utility.RandomMinMax( 60, 180 ) ), new TimerCallback( Heave ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Heave(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Grizelda.cs b/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Grizelda.cs new file mode 100644 index 0000000..715b31c --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Grizelda.cs @@ -0,0 +1,220 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; + +namespace Server.Engines.Quests.Hag +{ + public class Grizelda : BaseQuester + { + public override bool ClickTitle{ get{ return true; } } + + [Constructable] + public Grizelda() : base( "the Hag" ) + { + } + + public Grizelda( Serial serial ) : base( serial ) + { + } + + public override void InitBody() + { + InitStats( 100, 100, 25 ); + + Hue = 0x83EA; + + Female = true; + Body = 0x191; + Name = "Grizelda"; + } + + public override void InitOutfit() + { + AddItem( new Robe( 0x1 ) ); + AddItem( new Sandals() ); + AddItem( new WizardsHat( 0x1 ) ); + AddItem( new GoldBracelet() ); + + HairItemID = 0x203C; + + Item staff = new GnarledStaff(); + staff.Movable = false; + AddItem( staff ); + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + Direction = GetDirectionTo( player ); + + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + if ( qs.IsObjectiveInProgress( typeof( FindApprenticeObjective ) ) ) + { + PlaySound( 0x259 ); + PlaySound( 0x206 ); + qs.AddConversation( new HagDuringCorpseSearchConversation() ); + } + else + { + QuestObjective obj = qs.FindObjective( typeof( FindGrizeldaAboutMurderObjective ) ); + + if ( obj != null && !obj.Completed ) + { + PlaySound( 0x420 ); + PlaySound( 0x20 ); + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( KillImpsObjective ) ) + || qs.IsObjectiveInProgress( typeof( FindZeefzorpulObjective ) ) ) + { + PlaySound( 0x259 ); + PlaySound( 0x206 ); + qs.AddConversation( new HagDuringImpSearchConversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnRecipeObjective ) ); + + if ( obj != null && !obj.Completed ) + { + PlaySound( 0x258 ); + PlaySound( 0x41B ); + obj.Complete(); + } + else if ( qs.IsObjectiveInProgress( typeof( FindIngredientObjective ) ) ) + { + PlaySound( 0x259 ); + PlaySound( 0x206 ); + qs.AddConversation( new HagDuringIngredientsConversation() ); + } + else + { + obj = qs.FindObjective( typeof( ReturnIngredientsObjective ) ); + + if ( obj != null && !obj.Completed ) + { + Container cont = GetNewContainer(); + + cont.DropItem( new BlackPearl( 30 ) ); + cont.DropItem( new Bloodmoss( 30 ) ); + cont.DropItem( new Garlic( 30 ) ); + cont.DropItem( new Ginseng( 30 ) ); + cont.DropItem( new MandrakeRoot( 30 ) ); + cont.DropItem( new Nightshade( 30 ) ); + cont.DropItem( new SulfurousAsh( 30 ) ); + cont.DropItem( new SpidersSilk( 30 ) ); + + cont.DropItem( new Cauldron() ); + cont.DropItem( new MoonfireBrew() ); + cont.DropItem( new TreasureMap( Utility.RandomMinMax( 1, 4 ), this.Map ) ); + cont.DropItem( new Gold( 2000, 2200 ) ); + + if ( Utility.RandomBool() ) + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if ( Core.AOS ) + { + BaseRunicTool.ApplyAttributesTo( weapon, 2, 20, 30 ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + } + + cont.DropItem( weapon ); + } + else + { + Item item; + + if ( Core.AOS ) + { + item = Loot.RandomArmorOrShieldOrJewelry(); + + if ( item is BaseArmor ) + BaseRunicTool.ApplyAttributesTo( (BaseArmor)item, 2, 20, 30 ); + else if ( item is BaseJewel ) + BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, 2, 20, 30 ); + } + else + { + BaseArmor armor = Loot.RandomArmorOrShield(); + item = armor; + + armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled( 2, 3 ); + } + + cont.DropItem( item ); + } + + if ( player.BAC > 0 ) + cont.DropItem( new HangoverCure() ); + + if ( player.PlaceInBackpack( cont ) ) + { + bool gainedPath = false; + + if ( VirtueHelper.Award( player, VirtueName.Sacrifice, 250, ref gainedPath ) ) // TODO: Check amount on OSI. + player.SendLocalizedMessage( 1054160 ); // You have gained in sacrifice. + + PlaySound( 0x253 ); + PlaySound( 0x20 ); + obj.Complete(); + } + else + { + cont.Delete(); + player.SendLocalizedMessage( 1046260 ); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory. + } + } + } + } + } + } + else + { + QuestSystem newQuest = new WitchApprenticeQuest( player ); + bool inRestartPeriod = false; + + if ( qs != null ) + { + newQuest.AddConversation( new DontOfferConversation() ); + } + else if ( QuestSystem.CanOfferQuest( player, typeof( WitchApprenticeQuest ), out inRestartPeriod ) ) + { + PlaySound( 0x20 ); + PlaySound( 0x206 ); + newQuest.SendOffer(); + } + else if ( inRestartPeriod ) + { + PlaySound( 0x259 ); + PlaySound( 0x206 ); + newQuest.AddConversation( new RecentlyFinishedConversation() ); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Zeefzorpul.cs b/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Zeefzorpul.cs new file mode 100644 index 0000000..bb0f2c6 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Mobiles/Zeefzorpul.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Hag +{ + public class Zeefzorpul : BaseQuester + { + public Zeefzorpul() + { + } + + public override void InitBody() + { + Body = 0x4A; + Name = "Zeefzorpul"; + } + + public Zeefzorpul( Serial serial ) : base( serial ) + { + } + + public override bool CanTalkTo( PlayerMobile to ) + { + return false; + } + + public override void OnTalk( PlayerMobile player, bool contextMenu ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs b/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs new file mode 100644 index 0000000..6ccea11 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/Objectives.cs @@ -0,0 +1,528 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Engines.Quests.Hag +{ + public class FindApprenticeObjective : QuestObjective + { + private static Point3D[] m_CorpseLocations = new Point3D[] + { + new Point3D( 778, 1158, 0 ), + new Point3D( 698, 1443, 0 ), + new Point3D( 785, 1548, 0 ), + new Point3D( 734, 1504, 0 ), + new Point3D( 819, 1266, 0 ) + }; + + private static Point3D RandomCorpseLocation() + { + int index = Utility.Random( m_CorpseLocations.Length ); + + return m_CorpseLocations[index]; + } + + private Corpse m_Corpse; + private Point3D m_CorpseLocation; + + public override object Message + { + get + { + /* To the west of the Hag's house lies the road between Skara Brae + * and Yew. Follow it carefully toward Yew's graveyard, and search for + * any sign of the Hag's apprentice along the road. + */ + return 1055014; + } + } + + public Corpse Corpse{ get{ return m_Corpse; } } + + public FindApprenticeObjective( bool init ) + { + if ( init ) + m_CorpseLocation = RandomCorpseLocation(); + } + + public FindApprenticeObjective() + { + } + + public override void CheckProgress() + { + PlayerMobile player = System.From; + Map map = player.Map; + + if ( ( m_Corpse == null || m_Corpse.Deleted ) && ( map == Map.Trammel || map == Map.Felucca ) && player.InRange( m_CorpseLocation, 8 ) ) + { + m_Corpse = new HagApprenticeCorpse(); + m_Corpse.MoveToWorld( m_CorpseLocation, map ); + + Effects.SendLocationEffect( m_CorpseLocation, map, 0x3728, 10, 10 ); + Effects.PlaySound( m_CorpseLocation, map, 0x1FE ); + + Mobile imp = new Zeefzorpul(); + imp.MoveToWorld( m_CorpseLocation, map ); + + // * You see a strange imp stealing a scrap of paper from the bloodied corpse * + m_Corpse.SendLocalizedMessageTo( player, 1055049 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( DeleteImp ), imp ); + } + } + + private void DeleteImp( object imp ) + { + Mobile m = imp as Mobile; + + if ( m != null && !m.Deleted ) + { + Effects.SendLocationEffect( m.Location, m.Map, 0x3728, 10, 10 ); + Effects.PlaySound( m.Location, m.Map, 0x1FE ); + + m.Delete(); + } + } + + public override void OnComplete() + { + System.AddConversation( new ApprenticeCorpseConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_CorpseLocation = reader.ReadPoint3D(); + goto case 0; + } + case 0: + { + m_Corpse = (Corpse) reader.ReadItem(); + break; + } + } + + if ( version == 0 ) + m_CorpseLocation = RandomCorpseLocation(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + if ( m_Corpse != null && m_Corpse.Deleted ) + m_Corpse = null; + + writer.WriteEncodedInt( (int) 1 ); // version + + writer.Write( (Point3D) m_CorpseLocation ); + writer.Write( (Item) m_Corpse ); + } + } + + public class FindGrizeldaAboutMurderObjective : QuestObjective + { + public override object Message + { + get + { + /* Return to the Hag to tell her of the vile imp Zeefzorpul's role + * in the murder of her Apprentice, and the subsequent theft of a mysterious + * scrap of parchment from the corpse. + */ + return 1055015; + } + } + + public FindGrizeldaAboutMurderObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new MurderConversation() ); + } + } + + public class KillImpsObjective : QuestObjective + { + private int m_MaxProgress; + + public override object Message + { + get + { + /* Search the realm for any imps you can find, and slash, bash, mash, + * or fry them with magics until one of them gives up the secret hiding + * place of the imp Zeefzorpul. + */ + return 1055016; + } + } + + public override int MaxProgress{ get{ return m_MaxProgress; } } + + public KillImpsObjective( bool init ) + { + if ( init ) + m_MaxProgress = Utility.RandomMinMax( 1, 4 ); + } + + public KillImpsObjective() + { + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + if ( !Completed && from is Imp ) + return true; + + return false; + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + if ( creature is Imp ) + CurProgress++; + } + + public override void OnComplete() + { + PlayerMobile from = System.From; + + Point3D loc = WitchApprenticeQuest.RandomZeefzorpulLocation(); + + MapItem mapItem = new MapItem(); + mapItem.SetDisplay( loc.X - 200, loc.Y - 200, loc.X + 200, loc.Y + 200, 200, 200 ); + mapItem.AddWorldPin( loc.X, loc.Y ); + from.AddToBackpack( mapItem ); + + from.AddToBackpack( new MagicFlute() ); + + from.SendLocalizedMessage( 1055061 ); // You have received a map and a magic flute. + + System.AddConversation( new ImpDeathConversation( loc ) ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_MaxProgress = reader.ReadInt(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (int) m_MaxProgress ); + } + } + + public class FindZeefzorpulObjective : QuestObjective + { + private Point3D m_ImpLocation; + + public override object Message + { + get + { + /* Find the location shown in the map that the imp gave you. When you + * have arrived at the location, play the magic flute he provided, + * and the imp Zeefzorpul will be drawn to your presence. + */ + return 1055017; + } + } + + public Point3D ImpLocation{ get{ return m_ImpLocation; } } + + public FindZeefzorpulObjective( Point3D impLocation ) + { + m_ImpLocation = impLocation; + } + + public FindZeefzorpulObjective() + { + } + + public override void OnComplete() + { + Mobile from = System.From; + Map map = from.Map; + + Effects.SendLocationEffect( m_ImpLocation, map, 0x3728, 10, 10 ); + Effects.PlaySound( m_ImpLocation, map, 0x1FE ); + + Mobile imp = new Zeefzorpul(); + imp.MoveToWorld( m_ImpLocation, map ); + + imp.Direction = imp.GetDirectionTo( from ); + + Timer.DelayCall( TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( DeleteImp ), imp ); + } + + private void DeleteImp( object imp ) + { + Mobile m = imp as Mobile; + + if ( m != null && !m.Deleted ) + { + Effects.SendLocationEffect( m.Location, m.Map, 0x3728, 10, 10 ); + Effects.PlaySound( m.Location, m.Map, 0x1FE ); + + m.Delete(); + } + + System.From.SendLocalizedMessage( 1055062 ); // You have received the Magic Brew Recipe. + + System.AddConversation( new ZeefzorpulConversation() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_ImpLocation = reader.ReadPoint3D(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.Write( (Point3D) m_ImpLocation ); + } + } + + public class ReturnRecipeObjective : QuestObjective + { + public override object Message + { + get + { + /* Return to the old Hag and tell her you have recovered her Magic + * Brew Recipe from the bizarre imp named Zeefzorpul. + */ + return 1055018; + } + } + + public ReturnRecipeObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new RecipeConversation() ); + } + } + + public class FindIngredientObjective : QuestObjective + { + private Ingredient[] m_Ingredients; + private bool m_BlackheartMet; + + public override object Message + { + get + { + if ( !m_BlackheartMet ) + { + switch ( Step ) + { + case 1: + /* You must gather each ingredient on the Hag's list so that she can cook + * up her vile Magic Brew. The first ingredient is : + */ + return 1055019; + case 2: + /* You must gather each ingredient on the Hag's list so that she can cook + * up her vile Magic Brew. The second ingredient is : + */ + return 1055044; + default: + /* You must gather each ingredient on the Hag's list so that she can cook + * up her vile Magic Brew. The final ingredient is : + */ + return 1055045; + } + } + else + { + /* You are still attempting to obtain a jug of Captain Blackheart's + * Whiskey, but the drunkard Captain refuses to share his unique brew. + * You must prove your worthiness as a pirate to Blackheart before he'll + * offer you a jug. + */ + return 1055055; + } + } + } + + public override int MaxProgress + { + get + { + IngredientInfo info = IngredientInfo.Get( this.Ingredient ); + + return info.Quantity; + } + } + + public Ingredient[] Ingredients{ get{ return m_Ingredients; } } + public Ingredient Ingredient{ get{ return m_Ingredients[m_Ingredients.Length - 1]; } } + public int Step{ get{ return m_Ingredients.Length; } } + public bool BlackheartMet{ get{ return m_BlackheartMet; } } + + public FindIngredientObjective( Ingredient[] oldIngredients ) : this( oldIngredients, false ) + { + } + + public FindIngredientObjective( Ingredient[] oldIngredients, bool blackheartMet ) + { + if ( !blackheartMet ) + { + m_Ingredients = new Ingredient[oldIngredients.Length + 1]; + + for ( int i = 0; i < oldIngredients.Length; i++ ) + m_Ingredients[i] = oldIngredients[i]; + + m_Ingredients[m_Ingredients.Length - 1] = IngredientInfo.RandomIngredient( oldIngredients ); + } + else + { + m_Ingredients = new Ingredient[oldIngredients.Length]; + + for ( int i = 0; i < oldIngredients.Length; i++ ) + m_Ingredients[i] = oldIngredients[i]; + } + + m_BlackheartMet = blackheartMet; + } + + public FindIngredientObjective() + { + } + + public override void RenderProgress( BaseQuestGump gump ) + { + if ( !Completed ) + { + IngredientInfo info = IngredientInfo.Get( this.Ingredient ); + + gump.AddHtmlLocalized( 70, 260, 270, 100, info.Name, BaseQuestGump.Blue, false, false ); + gump.AddLabel( 70, 280, 0x64, CurProgress.ToString() ); + gump.AddLabel( 100, 280, 0x64, "/" ); + gump.AddLabel( 130, 280, 0x64, info.Quantity.ToString() ); + } + else + { + base.RenderProgress( gump ); + } + } + + public override bool IgnoreYoungProtection( Mobile from ) + { + if ( Completed ) + return false; + + IngredientInfo info = IngredientInfo.Get( this.Ingredient ); + Type fromType = from.GetType(); + + for ( int i = 0; i < info.Creatures.Length; i++ ) + { + if ( fromType == info.Creatures[i] ) + return true; + } + + return false; + } + + public override void OnKill( BaseCreature creature, Container corpse ) + { + IngredientInfo info = IngredientInfo.Get( this.Ingredient ); + + for ( int i = 0; i < info.Creatures.Length; i++ ) + { + Type type = info.Creatures[i]; + + if ( creature.GetType() == type ) + { + System.From.SendLocalizedMessage( 1055043, "#" + info.Name ); // You gather a ~1_INGREDIENT_NAME~ from the corpse. + + CurProgress++; + + break; + } + } + } + + public override void OnComplete() + { + if ( this.Ingredient != Ingredient.Whiskey ) + { + NextStep(); + } + } + + public void NextStep() + { + System.From.SendLocalizedMessage( 1055046 ); // You have completed your current task on the Hag's Magic Brew Recipe list. + + if ( Step < 3 ) + System.AddObjective( new FindIngredientObjective( m_Ingredients ) ); + else + System.AddObjective( new ReturnIngredientsObjective() ); + } + + public override void ChildDeserialize( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + m_Ingredients = new Ingredient[reader.ReadEncodedInt()]; + for ( int i = 0; i < m_Ingredients.Length; i++ ) + m_Ingredients[i] = (Ingredient) reader.ReadEncodedInt(); + + m_BlackheartMet = reader.ReadBool(); + } + + public override void ChildSerialize( GenericWriter writer ) + { + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Ingredients.Length ); + for ( int i = 0; i < m_Ingredients.Length; i++ ) + writer.WriteEncodedInt( (int) m_Ingredients[i] ); + + writer.Write( (bool) m_BlackheartMet ); + } + } + + public class ReturnIngredientsObjective : QuestObjective + { + public override object Message + { + get + { + /* You have gathered all the ingredients listed in the Hag's Magic Brew + * Recipe. Return to the Hag and tell her you have completed her task. + */ + return 1055050; + } + } + + public ReturnIngredientsObjective() + { + } + + public override void OnComplete() + { + System.AddConversation( new EndConversation() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Quests/Witch Apprentice/WitchApprenticeQuest.cs b/Scripts/Engines/Quests/Witch Apprentice/WitchApprenticeQuest.cs new file mode 100644 index 0000000..8135ad4 --- /dev/null +++ b/Scripts/Engines/Quests/Witch Apprentice/WitchApprenticeQuest.cs @@ -0,0 +1,141 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Engines.Quests.Hag +{ + public class WitchApprenticeQuest : QuestSystem + { + private static Type[] m_TypeReferenceTable = new Type[] + { + typeof( Hag.FindApprenticeObjective ), + typeof( Hag.FindGrizeldaAboutMurderObjective ), + typeof( Hag.KillImpsObjective ), + typeof( Hag.FindZeefzorpulObjective ), + typeof( Hag.ReturnRecipeObjective ), + typeof( Hag.FindIngredientObjective ), + typeof( Hag.ReturnIngredientsObjective ), + typeof( Hag.DontOfferConversation ), + typeof( Hag.AcceptConversation ), + typeof( Hag.HagDuringCorpseSearchConversation ), + typeof( Hag.ApprenticeCorpseConversation ), + typeof( Hag.MurderConversation ), + typeof( Hag.HagDuringImpSearchConversation ), + typeof( Hag.ImpDeathConversation ), + typeof( Hag.ZeefzorpulConversation ), + typeof( Hag.RecipeConversation ), + typeof( Hag.HagDuringIngredientsConversation ), + typeof( Hag.BlackheartFirstConversation ), + typeof( Hag.BlackheartNoPirateConversation ), + typeof( Hag.BlackheartPirateConversation ), + typeof( Hag.EndConversation ), + typeof( Hag.RecentlyFinishedConversation ) + }; + + public override Type[] TypeReferenceTable{ get{ return m_TypeReferenceTable; } } + + public override object Name + { + get + { + // "The Witch's Apprentice" + return 1055042; + } + } + + public override object OfferMessage + { + get + { + /* The ancient, wrinkled hag looks up from her vile-smelling cauldron. + * Her single, unblinking eye attempts to focus in on you, but to + * little avail.

+ * + * Eh? Who is it? Who's there? Come to trouble an old woman have you?

+ * + * I'll split ye open and swallow yer guts! I'll turn ye into a pile + * o' goo, I will! Bah! As if I didn't have enough to worry about. As if I've + * not enough trouble as it is!

+ * + * Another of my blasted apprentices has gone missing! Foolish children, + * think they know everything. I should turn the lot of them into toads - + * if only they'd return with their task complete! But that's the trouble, innit? + * They never return!

+ * + * But you don't care, do ye? I suppose you're another one of those meddlesome kids, + * come to ask me for something? Eh? Is that it? You want something from me, + * expect me to hand it over? I've enough troubles with my apprentices, and that + * vile imp, Zeefzorpul! Why, I bet it's him who's got the lot of them! And who + * knows what he's done? Vile little thing.

+ * + * If you expect me to help you with your silly little desires, you'll be doing + * something for me first, eh? I expect you to go seek out my apprentice. + * I sent him along the road west of here up towards Yew's graveyard, but he never + * came back. Find him, and bring him back, and I'll give you a little reward that + * I'm sure you'll find pleasant.

+ * + * But I tells ye to watch out for the imp name've Zeefzorpul! He's a despicable + * little beast who likes to fool and fiddle with folk and generally make life + * miserable for everyone. If ye get him on your bad side, you're sure to end up + * ruing the day ye were born. As if you didn't already, with an ugly mug + * like that!

+ * + * Well, you little whelp? Going to help an old hag or not? + */ + return 1055001; + } + } + + public override TimeSpan RestartDelay{ get{ return TimeSpan.FromMinutes( 5.0 ); } } + public override bool IsTutorial{ get{ return false; } } + + public override int Picture{ get{ return 0x15D3; } } + + public WitchApprenticeQuest( PlayerMobile from ) : base( from ) + { + } + + // Serialization + public WitchApprenticeQuest() + { + } + + public override void Accept() + { + base.Accept(); + + AddConversation( new AcceptConversation() ); + } + + private static Point3D[] m_ZeefzorpulLocations = new Point3D[] + { + new Point3D( 1226, 1573, 0 ), + new Point3D( 1929, 1148, 0 ), + new Point3D( 1366, 2723, 0 ), + new Point3D( 1675, 2984, 0 ), + new Point3D( 2177, 3367, 10 ), + new Point3D( 1171, 3594, 0 ), + new Point3D( 1010, 2667, 5 ), + new Point3D( 1591, 2156, 5 ), + new Point3D( 2592, 464, 60 ), + new Point3D( 474, 1654, 0 ), + new Point3D( 897, 2411, 0 ), + new Point3D( 1471, 2505, 5 ), + new Point3D( 1257, 872, 16 ), + new Point3D( 2581, 1118, 0 ), + new Point3D( 2513, 1102, 0 ), + new Point3D( 1608, 3371, 0 ), + new Point3D( 4687, 1179, 0 ), + new Point3D( 3704, 2196, 20 ), + new Point3D( 3346, 572, 0 ), + new Point3D( 569, 1309, 0 ) + }; + + public static Point3D RandomZeefzorpulLocation() + { + int index = Utility.Random( m_ZeefzorpulLocations.Length ); + + return m_ZeefzorpulLocations[index]; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/RemoteAdmin/Network.cs b/Scripts/Engines/RemoteAdmin/Network.cs new file mode 100644 index 0000000..e6cccdc --- /dev/null +++ b/Scripts/Engines/RemoteAdmin/Network.cs @@ -0,0 +1,285 @@ +using System; +using Server; +using System.Text; +using System.Collections; +using Server.Accounting; +using Server.Network; + +namespace Server.RemoteAdmin +{ + public class AdminNetwork + { + private const string ProtocolVersion = "2"; + + private static ArrayList m_Auth = new ArrayList(); + private static bool m_NewLine = true; + private static StringBuilder m_ConsoleData = new StringBuilder(); + + private const string DateFormat = "MMMM dd hh:mm:ss.f tt"; + + public static void Configure() + { + PacketHandlers.Register(0xF1, 0, false, new OnPacketReceive(OnReceive)); + +#if !MONO + Core.MultiConsoleOut.Add(new EventTextWriter(new EventTextWriter.OnConsoleChar(OnConsoleChar), new EventTextWriter.OnConsoleLine(OnConsoleLine), new EventTextWriter.OnConsoleStr(OnConsoleString))); +#endif + Timer.DelayCall(TimeSpan.FromMinutes(2.5), TimeSpan.FromMinutes(2.5), new TimerCallback(CleanUp)); + } + + public static void OnConsoleString(string str) + { + string outStr; + if (m_NewLine) + { + outStr = String.Format("[{0}]: {1}", DateTime.Now.ToString(DateFormat), str); + m_NewLine = false; + } + else + { + outStr = str; + } + + m_ConsoleData.Append(outStr); + RoughTrimConsoleData(); + + SendToAll(outStr); + } + + public static void OnConsoleChar(char ch) + { + if (m_NewLine) + { + string outStr; + outStr = String.Format("[{0}]: {1}", DateTime.Now.ToString(DateFormat), ch); + + m_ConsoleData.Append(outStr); + SendToAll(outStr); + + m_NewLine = false; + } + else + { + m_ConsoleData.Append(ch); + SendToAll(ch); + } + + RoughTrimConsoleData(); + } + + public static void OnConsoleLine(string line) + { + string outStr; + if (m_NewLine) + outStr = String.Format("[{0}]: {1}{2}", DateTime.Now.ToString(DateFormat), line, Console.Out.NewLine); + else + outStr = String.Format("{0}{1}", line, Console.Out.NewLine); + + m_ConsoleData.Append(outStr); + RoughTrimConsoleData(); + + SendToAll(outStr); + + m_NewLine = true; + } + + static void SendToAll(string outStr) + { + SendToAll(new ConsoleData(outStr)); + } + + static void SendToAll(char ch) + { + SendToAll(new ConsoleData(ch)); + } + + static void SendToAll(ConsoleData packet) + { + packet.Acquire(); + for (int i = 0; i < m_Auth.Count; i++) + ((NetState)m_Auth[i]).Send(packet); + packet.Release(); + } + + static void RoughTrimConsoleData() + { + if (m_ConsoleData.Length >= 4096) + m_ConsoleData.Remove(0, 2048); + } + + static void TightTrimConsoleData() + { + if (m_ConsoleData.Length > 1024) + m_ConsoleData.Remove(0, m_ConsoleData.Length - 1024); + } + + public static void OnReceive(NetState state, PacketReader pvSrc) + { + byte cmd = pvSrc.ReadByte(); + if (cmd == 0x02) + { + Authenticate(state, pvSrc); + } + else if (cmd == 0xFE) + { + state.Send(new CompactServerInfo()); + state.Dispose(); + } + else if (cmd == 0xFF) + { + string statStr = String.Format(", Name={0}, Age={1}, Clients={2}, Items={3}, Chars={4}, Mem={5}K, Ver={6}", Server.Misc.ServerList.ServerName, (int)(DateTime.Now - Server.Items.Clock.ServerStart).TotalHours, NetState.Instances.Count, World.Items.Count, World.Mobiles.Count, (int)(System.GC.GetTotalMemory(false) / 1024), ProtocolVersion); + state.Send(new UOGInfo(statStr)); + state.Dispose(); + } + else if (!IsAuth(state)) + { + Console.WriteLine("ADMIN: Unauthorized packet from {0}, disconnecting", state); + Disconnect(state); + } + else + { + if (!RemoteAdminHandlers.Handle(cmd, state, pvSrc)) + Disconnect(state); + } + } + + private static void DelayedDisconnect(NetState state) + { + Timer.DelayCall(TimeSpan.FromSeconds(15.0), new TimerStateCallback(Disconnect), state); + } + + private static void Disconnect(object state) + { + m_Auth.Remove(state); + ((NetState)state).Dispose(); + } + + public static void Authenticate(NetState state, PacketReader pvSrc) + { + string user = pvSrc.ReadString(30); + string pw = pvSrc.ReadString(30); + + Account a = Accounts.GetAccount(user) as Account; + if (a == null) + { + state.Send(new Login(LoginResponse.NoUser)); + Console.WriteLine("ADMIN: Invalid username '{0}' from {1}", user, state); + DelayedDisconnect(state); + } + else if (!a.HasAccess(state)) + { + state.Send(new Login(LoginResponse.BadIP)); + Console.WriteLine("ADMIN: Access to '{0}' from {1} denied.", user, state); + DelayedDisconnect(state); + } + else if (!a.CheckPassword(pw)) + { + state.Send(new Login(LoginResponse.BadPass)); + Console.WriteLine("ADMIN: Invalid password for user '{0}' from {1}", user, state); + DelayedDisconnect(state); + } + else if (a.AccessLevel < AccessLevel.Administrator || a.Banned) + { + Console.WriteLine("ADMIN: Account '{0}' does not have admin access. Connection Denied.", user); + state.Send(new Login(LoginResponse.NoAccess)); + DelayedDisconnect(state); + } + else + { + Console.WriteLine("ADMIN: Access granted to '{0}' from {1}", user, state); + state.Account = a; + a.LogAccess(state); + a.LastLogin = DateTime.Now; + + state.Send(new Login(LoginResponse.OK)); + TightTrimConsoleData(); + state.Send(Compress(new ConsoleData(m_ConsoleData.ToString()))); + m_Auth.Add(state); + } + } + + public static bool IsAuth(NetState state) + { + return m_Auth.Contains(state); + } + + private static void CleanUp() + {//remove dead instances from m_Auth + ArrayList list = new ArrayList(); + for (int i = 0; i < m_Auth.Count; i++) + { + NetState ns = (NetState)m_Auth[i]; + if (ns.Running) + list.Add(ns); + } + + m_Auth = list; + } + + public static Packet Compress(Packet p) + { + int length; + byte[] source = p.Compile(false, out length); + + if (length > 100 && length < 60000) + { + byte[] dest = new byte[(int)(length * 1.001) + 10]; + int destSize = dest.Length; + + ZLibError error = Compression.Pack(dest, ref destSize, source, length, ZLibQuality.Default); + + if (error != ZLibError.Okay) + { + Console.WriteLine("WARNING: Unable to compress admin packet, zlib error: {0}", error); + return p; + } + else + { + return new AdminCompressedPacket(dest, destSize, length); + } + } + else + { + return p; + } + } + } + + public class EventTextWriter : System.IO.TextWriter + { + public delegate void OnConsoleChar(char ch); + public delegate void OnConsoleLine(string line); + public delegate void OnConsoleStr(string str); + + private OnConsoleChar m_OnChar; + private OnConsoleLine m_OnLine; + private OnConsoleStr m_OnStr; + + public EventTextWriter(OnConsoleChar onChar, OnConsoleLine onLine, OnConsoleStr onStr) + { + m_OnChar = onChar; + m_OnLine = onLine; + m_OnStr = onStr; + } + + public override void Write(char ch) + { + if (m_OnChar != null) + m_OnChar(ch); + } + + public override void Write(string str) + { + if (m_OnStr != null) + m_OnStr(str); + } + + public override void WriteLine(string line) + { + if (m_OnLine != null) + m_OnLine(line); + } + + public override System.Text.Encoding Encoding { get { return System.Text.Encoding.ASCII; } } + } +} \ No newline at end of file diff --git a/Scripts/Engines/RemoteAdmin/PacketHandlers.cs b/Scripts/Engines/RemoteAdmin/PacketHandlers.cs new file mode 100644 index 0000000..58ee7e8 --- /dev/null +++ b/Scripts/Engines/RemoteAdmin/PacketHandlers.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Accounting; +using Server.Items; +using Server.Mobiles; + +namespace Server.RemoteAdmin +{ + public class RemoteAdminHandlers + { + public enum AcctSearchType : byte + { + Username = 0, + IP = 1, + } + + private static OnPacketReceive[] m_Handlers = new OnPacketReceive[256]; + + static RemoteAdminHandlers() + { + //0x02 = login request, handled by AdminNetwork + Register(0x04, new OnPacketReceive(ServerInfoRequest)); + Register(0x05, new OnPacketReceive(AccountSearch)); + Register(0x06, new OnPacketReceive(RemoveAccount)); + Register(0x07, new OnPacketReceive(UpdateAccount)); + } + + public static void Register(byte command, OnPacketReceive handler) + { + m_Handlers[command] = handler; + } + + public static bool Handle(byte command, NetState state, PacketReader pvSrc) + { + if (m_Handlers[command] == null) + { + Console.WriteLine("ADMIN: Invalid packet 0x{0:X2} from {1}, disconnecting", command, state); + return false; + } + else + { + m_Handlers[command](state, pvSrc); + return true; + } + } + + private static void ServerInfoRequest(NetState state, PacketReader pvSrc) + { + state.Send(AdminNetwork.Compress(new ServerInfo())); + } + + private static void AccountSearch(NetState state, PacketReader pvSrc) + { + AcctSearchType type = (AcctSearchType)pvSrc.ReadByte(); + string term = pvSrc.ReadString(); + + if (type == AcctSearchType.IP && !Utility.IsValidIP(term)) + { + state.Send(new MessageBoxMessage("Invalid search term.\nThe IP sent was not valid.", "Invalid IP")); + return; + } + else + { + term = term.ToUpper(); + } + + ArrayList list = new ArrayList(); + + foreach (Account a in Accounts.GetAccounts()) + { + if (!CanAccessAccount(state.Account, a)) continue; + + switch (type) + { + case AcctSearchType.Username: + { + if (a.Username.ToUpper().IndexOf(term) != -1) + list.Add(a); + break; + } + case AcctSearchType.IP: + { + for (int i = 0; i < a.LoginIPs.Length; i++) + { + if (Utility.IPMatch(term, a.LoginIPs[i])) + { + list.Add(a); + break; + } + } + break; + } + } + } + + if (list.Count > 0) + { + if (list.Count <= 25) + state.Send(AdminNetwork.Compress(new AccountSearchResults(list))); + else + state.Send(new MessageBoxMessage("There were more than 25 matches to your search.\nNarrow the search parameters and try again.", "Too Many Results")); + } + else + { + state.Send(new MessageBoxMessage("There were no results to your search.\nPlease try again.", "No Matches")); + } + } + + static bool CanAccessAccount(IAccount beholder, IAccount beheld) + { + return beholder.AccessLevel == AccessLevel.Owner || beheld.AccessLevel < beholder.AccessLevel; // Cannot see accounts of equal or greater access level unless Owner + } + + private static void RemoveAccount(NetState state, PacketReader pvSrc) + { + if (state.Account.AccessLevel < AccessLevel.Administrator) + { + state.Send(new MessageBoxMessage("You do not have permission to delete accounts.", "Account Access Exception")); + return; + } + + IAccount a = Accounts.GetAccount(pvSrc.ReadString()); + + if (a == null) + { + state.Send(new MessageBoxMessage("The account could not be found (and thus was not deleted).", "Account Not Found")); + } + else if (!CanAccessAccount(state.Account, a)) + { + state.Send(new MessageBoxMessage("You cannot delete an account with an access level greater than or equal to your own.", "Account Access Exception")); + } + else if (a == state.Account) + { + state.Send(new MessageBoxMessage("You may not delete your own account.", "Not Allowed")); + } + else + { + RemoteAdminLogging.WriteLine(state, "Deleted Account {0}", a); + a.Delete(); + state.Send(new MessageBoxMessage("The requested account (and all it's characters) has been deleted.", "Account Deleted")); + } + } + + private static void UpdateAccount(NetState state, PacketReader pvSrc) + { + if (state.Account.AccessLevel < AccessLevel.Administrator) + { + state.Send(new MessageBoxMessage("You do not have permission to edit accounts.", "Account Access Exception")); + return; + } + + string username = pvSrc.ReadString(); + string pass = pvSrc.ReadString(); + + Account a = Accounts.GetAccount(username) as Account; + + if (a != null && !CanAccessAccount(state.Account, a)) + { + state.Send(new MessageBoxMessage("You cannot edit an account with an access level greater than or equal to your own.", "Account Access Exception")); + } + else + { + bool CreatedAccount = false; + bool UpdatedPass = false; + bool oldbanned = a == null ? false : a.Banned; + AccessLevel oldAcessLevel = a == null ? 0 : a.AccessLevel; + + if (a == null) + { + a = new Account(username, pass); + CreatedAccount = true; + } + else if (pass != "(hidden)") + { + a.SetPassword(pass); + UpdatedPass = true; + } + + if (a != state.Account) + { + AccessLevel newAccessLevel = (AccessLevel)pvSrc.ReadByte(); + if (a.AccessLevel != newAccessLevel) + { + if (newAccessLevel >= state.Account.AccessLevel) + state.Send(new MessageBoxMessage("Warning: You may not set an access level greater than or equal to your own.", "Account Access Level update denied.")); + else + a.AccessLevel = newAccessLevel; + } + bool newBanned = pvSrc.ReadBoolean(); + if (newBanned != a.Banned) + { + oldbanned = a.Banned; + a.Banned = newBanned; + a.Comments.Add(new AccountComment(state.Account.Username, newBanned ? "Banned via Remote Admin" : "Unbanned via Remote Admin")); + } + } + else + { + pvSrc.ReadInt16();//skip both + state.Send(new MessageBoxMessage("Warning: When editing your own account, Account Status and Access Level cannot be changed.", "Editing Own Account")); + } + + ArrayList list = new ArrayList(); + ushort length = pvSrc.ReadUInt16(); + bool invalid = false; + for (int i = 0; i < length; i++) + { + string add = pvSrc.ReadString(); + if (Utility.IsValidIP(add)) + list.Add(add); + else + invalid = true; + } + + if (list.Count > 0) + a.IPRestrictions = (string[])list.ToArray(typeof(string)); + else + a.IPRestrictions = new string[0]; + + if (invalid) + state.Send(new MessageBoxMessage("Warning: one or more of the IP Restrictions you specified was not valid.", "Invalid IP Restriction")); + + if (CreatedAccount) + RemoteAdminLogging.WriteLine(state, "Created account {0} with Access Level {1}", a.Username, a.AccessLevel); + else + { + string changes = string.Empty; + if (UpdatedPass) changes += " Password Changed."; + if (oldAcessLevel != a.AccessLevel) changes = string.Format("{0} Access level changed from {1} to {2}.", changes, oldAcessLevel, a.AccessLevel); + if (oldbanned != a.Banned) changes += a.Banned ? " Banned." : " Unbanned."; + RemoteAdminLogging.WriteLine(state, "Updated account {0}:{1}", a.Username, changes); + } + + state.Send(new MessageBoxMessage("Account updated successfully.", "Account Updated")); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/RemoteAdmin/Packets.cs b/Scripts/Engines/RemoteAdmin/Packets.cs new file mode 100644 index 0000000..15ec02d --- /dev/null +++ b/Scripts/Engines/RemoteAdmin/Packets.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Accounting; +using Server.Commands; + +namespace Server.RemoteAdmin +{ + public enum LoginResponse : byte + { + NoUser = 0, + BadIP, + BadPass, + NoAccess, + OK + } + + public sealed class AdminCompressedPacket : Packet + { + public AdminCompressedPacket(byte[] CompData, int CDLen, int unCompSize) + : base(0x01) + { + EnsureCapacity(1 + 2 + 2 + CDLen); + m_Stream.Write((ushort)unCompSize); + m_Stream.Write(CompData, 0, CDLen); + } + } + + public sealed class Login : Packet + { + public Login(LoginResponse resp) + : base(0x02, 2) + { + m_Stream.Write((byte)resp); + } + } + + public sealed class ConsoleData : Packet + { + public ConsoleData(string str) + : base(0x03) + { + EnsureCapacity(1 + 2 + 1 + str.Length + 1); + m_Stream.Write((byte)2); + + m_Stream.WriteAsciiNull(str); + } + + public ConsoleData(char ch) + : base(0x03) + { + EnsureCapacity(1 + 2 + 1 + 1); + m_Stream.Write((byte)3); + + m_Stream.Write((byte)ch); + } + } + + public sealed class ServerInfo : Packet + { + public ServerInfo() + : base(0x04) + { + string netVer = Environment.Version.ToString(); + string os = Environment.OSVersion.ToString(); + + EnsureCapacity(1 + 2 + (10 * 4) + netVer.Length + 1 + os.Length + 1); + int banned = 0; + int active = 0; + + foreach (Account acct in Accounts.GetAccounts()) + { + if (acct.Banned) + ++banned; + else + ++active; + } + + m_Stream.Write((int)active); + m_Stream.Write((int)banned); + m_Stream.Write((int)Firewall.List.Count); + m_Stream.Write((int)NetState.Instances.Count); + + m_Stream.Write((int)World.Mobiles.Count); + m_Stream.Write((int)Core.ScriptMobiles); + m_Stream.Write((int)World.Items.Count); + m_Stream.Write((int)Core.ScriptItems); + + m_Stream.Write((uint)(DateTime.Now - Clock.ServerStart).TotalSeconds); + m_Stream.Write((uint)GC.GetTotalMemory(false)); // TODO: uint not sufficient for TotalMemory (long). Fix protocol. + m_Stream.WriteAsciiNull(netVer); + m_Stream.WriteAsciiNull(os); + } + } + + public sealed class AccountSearchResults : Packet + { + public AccountSearchResults(ArrayList results) + : base(0x05) + { + EnsureCapacity(1 + 2 + 2); + + m_Stream.Write((byte)results.Count); + + foreach (Account a in results) + { + m_Stream.WriteAsciiNull(a.Username); + + string pwToSend = a.PlainPassword; + + if (pwToSend == null) + pwToSend = "(hidden)"; + + m_Stream.WriteAsciiNull(pwToSend); + m_Stream.Write((byte)a.AccessLevel); + m_Stream.Write(a.Banned); + unchecked { m_Stream.Write((uint)a.LastLogin.Ticks); } // TODO: This doesn't work, uint.MaxValue is only 7 minutes of ticks. Fix protocol. + + m_Stream.Write((ushort)a.LoginIPs.Length); + for (int i = 0; i < a.LoginIPs.Length; i++) + m_Stream.WriteAsciiNull(a.LoginIPs[i].ToString()); + + m_Stream.Write((ushort)a.IPRestrictions.Length); + for (int i = 0; i < a.IPRestrictions.Length; i++) + m_Stream.WriteAsciiNull(a.IPRestrictions[i]); + } + } + } + + public sealed class CompactServerInfo : Packet + { + public CompactServerInfo() + : base(0x51) + { + EnsureCapacity(1 + 2 + (4 * 4) + 8); + + m_Stream.Write((int)NetState.Instances.Count - 1); // Clients + m_Stream.Write((int)World.Items.Count); // Items + m_Stream.Write((int)World.Mobiles.Count); // Mobiles + m_Stream.Write((uint)(DateTime.Now - Clock.ServerStart).TotalSeconds); // Age (seconds) + + long memory = GC.GetTotalMemory(false); + m_Stream.Write((uint)(memory >> 32)); // Memory high bytes + m_Stream.Write((uint)memory); // Memory low bytes + } + } + + public sealed class UOGInfo : Packet + { + public UOGInfo(string str) + : base(0x52, str.Length + 6) // 'R' + { + m_Stream.WriteAsciiFixed("unUO", 4); + m_Stream.WriteAsciiNull(str); + } + } + + public sealed class MessageBoxMessage : Packet + { + public MessageBoxMessage(string msg, string caption) + : base(0x08) + { + EnsureCapacity(1 + 2 + msg.Length + 1 + caption.Length + 1); + + m_Stream.WriteAsciiNull(msg); + m_Stream.WriteAsciiNull(caption); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs b/Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs new file mode 100644 index 0000000..2a23524 --- /dev/null +++ b/Scripts/Engines/RemoteAdmin/RemoteAdminLogging.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; +using Server; +using Server.Accounting; +using Server.Network; + +namespace Server.RemoteAdmin +{ + public class RemoteAdminLogging + { + const string LogBaseDirectory = "Logs"; + const string LogSubDirectory = "RemoteAdmin"; + + private static StreamWriter m_Output; + private static bool m_Enabled = true; + + public static bool Enabled { get { return m_Enabled; } set { m_Enabled = value; } } + + public static StreamWriter Output { get { return m_Output; } } + + private static bool Initialized = false; + public static void LazyInitialize() + { + if (Initialized || !m_Enabled) return; + Initialized = true; + + if (!Directory.Exists(LogBaseDirectory)) + Directory.CreateDirectory(LogBaseDirectory); + + string directory = Path.Combine(LogBaseDirectory, LogSubDirectory); + + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + try + { + m_Output = new StreamWriter(Path.Combine(directory, String.Format(LogSubDirectory + "{0}.log", DateTime.Now.ToString("yyyyMMdd"))), true); + + m_Output.AutoFlush = true; + + m_Output.WriteLine("##############################"); + m_Output.WriteLine("Log started on {0}", DateTime.Now); + m_Output.WriteLine(); + } + catch + { + Utility.PushColor(ConsoleColor.Red); + Console.WriteLine("RemoteAdminLogging: Failed to initialize LogWriter."); + Utility.PopColor(); + m_Enabled = false; + } + } + + public static object Format(object o) + { + o = Commands.CommandLogging.Format(o); + if (o == null) + return "(null)"; + + return o; + } + + public static void WriteLine(NetState state, string format, params object[] args) + { + for (int i = 0; i < args.Length; i++) + args[i] = Commands.CommandLogging.Format(args[i]); + + WriteLine(state, String.Format(format, args)); + } + + public static void WriteLine(NetState state, string text) + { + LazyInitialize(); + + if (!m_Enabled) return; + + try + { + Account acct = state.Account as Account; + string name = acct == null ? "(UNKNOWN)" : acct.Username; + string accesslevel = acct == null ? "NoAccount" : acct.AccessLevel.ToString(); + string statestr = state == null ? "NULLSTATE" : state.ToString(); + + m_Output.WriteLine("{0}: {1}: {2}: {3}", DateTime.Now, statestr, name, text); + + string path = Core.BaseDirectory; + + Commands.CommandLogging.AppendPath(ref path, LogBaseDirectory); + Commands.CommandLogging.AppendPath(ref path, LogSubDirectory); + Commands.CommandLogging.AppendPath(ref path, accesslevel); + path = Path.Combine(path, String.Format("{0}.log", name)); + + using (StreamWriter sw = new StreamWriter(path, true)) + sw.WriteLine("{0}: {1}: {2}", DateTime.Now, statestr, text); + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/BarGraph.cs b/Scripts/Engines/Reports/Objects/Charts/BarGraph.cs new file mode 100644 index 0000000..41574cc --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Charts/BarGraph.cs @@ -0,0 +1,312 @@ +using System; +using System.Collections; + +namespace Server.Engines.Reports +{ + public enum BarGraphRenderMode + { + Bars, + Lines + } + + public class BarGraph : Chart + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "bg", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new BarGraph(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private int m_Ticks; + private BarGraphRenderMode m_RenderMode; + + private string m_xTitle; + private string m_yTitle; + + private int m_FontSize = 7; + private int m_Interval = 1; + + private BarRegion[] m_Regions; + + public int Ticks{ get{ return m_Ticks; } set{ m_Ticks = value; } } + public BarGraphRenderMode RenderMode{ get{ return m_RenderMode; } set{ m_RenderMode = value; } } + + public string xTitle{ get{ return m_xTitle; } set{ m_xTitle = value; } } + public string yTitle{ get{ return m_yTitle; } set{ m_yTitle = value; } } + + public int FontSize{ get{ return m_FontSize; } set{ m_FontSize = value; } } + public int Interval{ get{ return m_Interval; } set{ m_Interval = value; } } + + public BarRegion[] Regions{ get{ return m_Regions; } set{ m_Regions = value; } } + + public BarGraph( string name, string fileName, int ticks, string xTitle, string yTitle, BarGraphRenderMode rm ) + { + m_Name = name; + m_FileName = fileName; + m_Ticks = ticks; + m_xTitle = xTitle; + m_yTitle = yTitle; + m_RenderMode = rm; + } + + private BarGraph() + { + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + base.SerializeAttributes( op ); + + op.SetInt32( "t", m_Ticks ); + op.SetInt32( "r", (int) m_RenderMode ); + + op.SetString( "x", m_xTitle ); + op.SetString( "y", m_yTitle ); + + op.SetInt32( "s", m_FontSize ); + op.SetInt32( "i", m_Interval ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + base.DeserializeAttributes( ip ); + + m_Ticks = ip.GetInt32( "t" ); + m_RenderMode = (BarGraphRenderMode) ip.GetInt32( "r" ); + + m_xTitle = Utility.Intern( ip.GetString( "x" ) ); + m_yTitle = Utility.Intern( ip.GetString( "y" ) ); + + m_FontSize = ip.GetInt32( "s" ); + m_Interval = ip.GetInt32( "i" ); + } + + public static int LookupReportValue( Snapshot ss, string reportName, string valueName ) + { + for ( int j = 0; j < ss.Children.Count; ++j ) + { + Report report = ss.Children[j] as Report; + + if ( report == null || report.Name != reportName ) + continue; + + for ( int k = 0; k < report.Items.Count; ++k ) + { + ReportItem item = report.Items[k]; + + if ( item.Values[0].Value == valueName ) + return Utility.ToInt32( item.Values[1].Value ); + } + + break; + } + + return -1; + } + + public static BarGraph DailyAverage( SnapshotHistory history, string reportName, string valueName ) + { + int[] totals = new int[24]; + int[] counts = new int[24]; + + int min = history.Snapshots.Count - (7 * 24); // averages over one week + + if ( min < 0 ) + min = 0; + + for ( int i = min; i < history.Snapshots.Count; ++i ) + { + Snapshot ss = history.Snapshots[i]; + + int val = LookupReportValue( ss, reportName, valueName ); + + if ( val == -1 ) + continue; + + int hour = ss.TimeStamp.TimeOfDay.Hours; + + totals[hour] += val; + counts[hour]++; + } + + BarGraph barGraph = new BarGraph( "Hourly average " + valueName, "graphs_" + valueName.ToLower() + "_avg", 10, "Time", valueName, BarGraphRenderMode.Lines ); + + barGraph.m_FontSize = 6; + + for ( int i = 7; i <= totals.Length+7; ++i ) + { + int val; + + if ( counts[i%totals.Length] == 0 ) + val = 0; + else + val = (totals[i%totals.Length] + (counts[i%totals.Length] / 2)) / counts[i%totals.Length]; + + int realHours = i%totals.Length; + int hours; + + if ( realHours == 0 ) + hours = 12; + else if ( realHours > 12 ) + hours = realHours - 12; + else + hours = realHours; + + barGraph.Items.Add( hours + (realHours >= 12 ? " PM" : " AM"), val ); + } + + return barGraph; + } + + public static BarGraph Growth( SnapshotHistory history, string reportName, string valueName ) + { + BarGraph barGraph = new BarGraph( "Growth of " + valueName + " over time", "graphs_" + valueName.ToLower() + "_growth", 10, "Time", valueName, BarGraphRenderMode.Lines ); + + barGraph.FontSize = 6; + barGraph.Interval = 7; + + DateTime startPeriod = history.Snapshots[0].TimeStamp.Date + TimeSpan.FromDays( 1.0 ); + DateTime endPeriod = history.Snapshots[history.Snapshots.Count - 1].TimeStamp.Date; + + ArrayList regions = new ArrayList(); + + DateTime curDate = DateTime.MinValue; + int curPeak = -1; + int curLow = 1000; + int curTotl = 0; + int curCont = 0; + int curValu = 0; + + for ( int i = 0; i < history.Snapshots.Count; ++i ) + { + Snapshot ss = history.Snapshots[i]; + DateTime timeStamp = ss.TimeStamp; + + if ( timeStamp < startPeriod || timeStamp >= endPeriod ) + continue; + + int val = LookupReportValue( ss, reportName, valueName ); + + if ( val == -1 ) + continue; + + DateTime thisDate = timeStamp.Date; + + if ( curDate == DateTime.MinValue ) + curDate = thisDate; + + curCont++; + curTotl += val; + curValu = curTotl / curCont; + + if ( curDate != thisDate && curValu >= 0 ) + { + string mnthName = thisDate.ToString( "MMMM" ); + + if ( regions.Count == 0 ) + { + regions.Add( new BarRegion( barGraph.Items.Count, barGraph.Items.Count, mnthName ) ); + } + else + { + BarRegion region = (BarRegion)regions[regions.Count - 1]; + + if ( region.m_Name == mnthName ) + region.m_RangeTo = barGraph.Items.Count; + else + regions.Add( new BarRegion( barGraph.Items.Count, barGraph.Items.Count, mnthName ) ); + } + + barGraph.Items.Add( thisDate.Day.ToString(), curValu ); + + curPeak = val; + curLow = val; + } + else + { + if ( val > curPeak ) + curPeak = val; + + if ( val > 0 && val < curLow ) + curLow = val; + } + + curDate = thisDate; + } + + barGraph.Regions = (BarRegion[])regions.ToArray( typeof( BarRegion ) ); + + return barGraph; + } + + public static BarGraph OverTime( SnapshotHistory history, string reportName, string valueName, int step, int max, int ival ) + { + BarGraph barGraph = new BarGraph( valueName + " over time", "graphs_" + valueName.ToLower() + "_ot", 10, "Heure (QC)", valueName, BarGraphRenderMode.Lines ); + + TimeSpan ts = TimeSpan.FromHours( (max*step)-0.5 ); + + DateTime mostRecent = history.Snapshots[history.Snapshots.Count - 1].TimeStamp; + DateTime minTime = mostRecent - ts; + + barGraph.FontSize = 6; + barGraph.Interval = ival; + + ArrayList regions = new ArrayList(); + + for ( int i = 0; i < history.Snapshots.Count; ++i ) + { + Snapshot ss = history.Snapshots[i]; + DateTime timeStamp = ss.TimeStamp; + + if ( timeStamp < minTime ) + continue; + + if ( (i % step) != 0 ) + continue; + + int val = LookupReportValue( ss, reportName, valueName ); + + if ( val == -1 ) + continue; + + int realHours = timeStamp.TimeOfDay.Hours; + int hours; + + if ( realHours == 0 ) + hours = 12; + else if ( realHours > 12 ) + hours = realHours - 12; + else + hours = realHours; + + string dayName = timeStamp.DayOfWeek.ToString(); + + if ( regions.Count == 0 ) + { + regions.Add( new BarRegion( barGraph.Items.Count, barGraph.Items.Count, dayName ) ); + } + else + { + BarRegion region = (BarRegion) regions[regions.Count - 1]; + + if ( region.m_Name == dayName ) + region.m_RangeTo = barGraph.Items.Count; + else + regions.Add( new BarRegion( barGraph.Items.Count, barGraph.Items.Count, dayName ) ); + } + + //barGraph.Items.Add( hours + (realHours >= 12 ? " PM" : " AM"), val ); + barGraph.Items.Add(realHours + "h", val); // Scriptiz : affichage 24h + } + + barGraph.Regions = (BarRegion[])regions.ToArray( typeof( BarRegion ) ); + + return barGraph; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/Chart.cs b/Scripts/Engines/Reports/Objects/Charts/Chart.cs new file mode 100644 index 0000000..451965e --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Charts/Chart.cs @@ -0,0 +1,44 @@ +using System; + +namespace Server.Engines.Reports +{ + public abstract class Chart : PersistableObject + { + protected string m_Name; + protected string m_FileName; + protected ChartItemCollection m_Items; + + public string Name{ get{ return m_Name; } set{ m_Name = value; } } + public string FileName{ get{ return m_FileName; } set{ m_FileName = value; } } + public ChartItemCollection Items{ get{ return m_Items; } } + + public Chart() + { + m_Items = new ChartItemCollection(); + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetString( "n", m_Name ); + op.SetString( "f", m_FileName ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_Name = Utility.Intern( ip.GetString( "n" ) ); + m_FileName = Utility.Intern( ip.GetString( "f" ) ); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + for ( int i = 0; i < m_Items.Count; ++i ) + m_Items[i].Serialize( op ); + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + while ( ip.HasChild ) + m_Items.Add( ip.GetChild() as ChartItem ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/ChartItem.cs b/Scripts/Engines/Reports/Objects/Charts/ChartItem.cs new file mode 100644 index 0000000..cf5dce2 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Charts/ChartItem.cs @@ -0,0 +1,46 @@ +using System; + +namespace Server.Engines.Reports +{ + public class ChartItem : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "ci", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new ChartItem(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private string m_Name; + private int m_Value; + + public string Name{ get{ return m_Name; } set{ m_Name = value; } } + public int Value{ get{ return m_Value; } set{ m_Value = value; } } + + private ChartItem() + { + } + + public ChartItem( string name, int value ) + { + m_Name = name; + m_Value = value; + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetString( "n", m_Name ); + op.SetInt32( "v", m_Value ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_Name = Utility.Intern( ip.GetString( "n" ) ); + m_Value = ip.GetInt32( "v" ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Charts/ChartItemCollection.cs b/Scripts/Engines/Reports/Objects/Charts/ChartItemCollection.cs new file mode 100644 index 0000000..fec6b54 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Charts/ChartItemCollection.cs @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.ChartItem. + /// + public class ChartItemCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public ChartItemCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.ChartItem at a specific position in the ChartItemCollection. + /// + public Server.Engines.Reports.ChartItem this[int index] + { + get + { + return ((Server.Engines.Reports.ChartItem)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + public int Add( string name, int value ) + { + return Add( new ChartItem( name, value ) ); + } + + /// + /// Append a Server.Engines.Reports.ChartItem entry to this collection. + /// + /// Server.Engines.Reports.ChartItem instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.ChartItem value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.ChartItem instance is in this collection. + /// + /// Server.Engines.Reports.ChartItem instance to search for. + /// True if the Server.Engines.Reports.ChartItem instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.ChartItem value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.ChartItem instance is in this collection. + /// + /// Server.Engines.Reports.ChartItem instance to find. + /// The zero-based index of the specified Server.Engines.Reports.ChartItem instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.ChartItem value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.ChartItem instance from this collection. + /// + /// The Server.Engines.Reports.ChartItem instance to remove. + public void Remove(Server.Engines.Reports.ChartItem value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.ChartItem instance. + /// + /// An Server.Engines.Reports.ChartItem's enumerator. + public new ChartItemCollectionEnumerator GetEnumerator() + { + return new ChartItemCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.ChartItem instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.ChartItem instance to insert. + public void Insert(int index, Server.Engines.Reports.ChartItem value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.ChartItem. + /// + public class ChartItemCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.ChartItem _currentElement; + + /// + /// Collection to enumerate. + /// + private ChartItemCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal ChartItemCollectionEnumerator(ChartItemCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.ChartItem object in the enumerated ChartItemCollection currently indexed by this instance. + /// + public Server.Engines.Reports.ChartItem Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Charts/PieChart.cs b/Scripts/Engines/Reports/Objects/Charts/PieChart.cs new file mode 100644 index 0000000..adf8692 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Charts/PieChart.cs @@ -0,0 +1,47 @@ +using System; + +namespace Server.Engines.Reports +{ + public class PieChart : Chart + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "pc", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new PieChart(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private bool m_ShowPercents; + + public bool ShowPercents{ get{ return m_ShowPercents; } set{ m_ShowPercents = value; } } + + public PieChart( string name, string fileName, bool showPercents ) + { + m_Name = name; + m_FileName = fileName; + m_ShowPercents = showPercents; + } + + private PieChart() + { + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + base.SerializeAttributes( op ); + + op.SetBoolean( "p", m_ShowPercents ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + base.DeserializeAttributes( ip ); + + m_ShowPercents = ip.GetBoolean( "p" ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ItemValue.cs b/Scripts/Engines/Reports/Objects/Reports/ItemValue.cs new file mode 100644 index 0000000..ed7438d --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/ItemValue.cs @@ -0,0 +1,53 @@ +using System; + +namespace Server.Engines.Reports +{ + public class ItemValue : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "iv", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new ItemValue(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private string m_Value; + private string m_Format; + + public string Value{ get{ return m_Value; } set{ m_Value = value; } } + public string Format{ get{ return m_Format; } set{ m_Format = value; } } + + private ItemValue() + { + } + + public ItemValue( string value ) : this( value, null ) + { + } + + public ItemValue( string value, string format ) + { + m_Value = value; + m_Format = format; + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetString( "v", m_Value ); + op.SetString( "f", m_Format ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_Value = ip.GetString( "v" ); + m_Format = Utility.Intern( ip.GetString( "f" ) ); + + if ( m_Format == null ) + Utility.Intern( ref m_Value ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ItemValueCollection.cs b/Scripts/Engines/Reports/Objects/Reports/ItemValueCollection.cs new file mode 100644 index 0000000..919e3c4 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/ItemValueCollection.cs @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.ItemValue. + /// + public class ItemValueCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public ItemValueCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.ItemValue at a specific position in the ItemValueCollection. + /// + public Server.Engines.Reports.ItemValue this[int index] + { + get + { + return ((Server.Engines.Reports.ItemValue)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + public int Add( string value ) + { + return Add( new ItemValue( value ) ); + } + + public int Add( string value, string format ) + { + return Add( new ItemValue( value, format ) ); + } + + /// + /// Append a Server.Engines.Reports.ItemValue entry to this collection. + /// + /// Server.Engines.Reports.ItemValue instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.ItemValue value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.ItemValue instance is in this collection. + /// + /// Server.Engines.Reports.ItemValue instance to search for. + /// True if the Server.Engines.Reports.ItemValue instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.ItemValue value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.ItemValue instance is in this collection. + /// + /// Server.Engines.Reports.ItemValue instance to find. + /// The zero-based index of the specified Server.Engines.Reports.ItemValue instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.ItemValue value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.ItemValue instance from this collection. + /// + /// The Server.Engines.Reports.ItemValue instance to remove. + public void Remove(Server.Engines.Reports.ItemValue value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.ItemValue instance. + /// + /// An Server.Engines.Reports.ItemValue's enumerator. + public new ItemValueCollectionEnumerator GetEnumerator() + { + return new ItemValueCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.ItemValue instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.ItemValue instance to insert. + public void Insert(int index, Server.Engines.Reports.ItemValue value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.ItemValue. + /// + public class ItemValueCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.ItemValue _currentElement; + + /// + /// Collection to enumerate. + /// + private ItemValueCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal ItemValueCollectionEnumerator(ItemValueCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.ItemValue object in the enumerated ItemValueCollection currently indexed by this instance. + /// + public Server.Engines.Reports.ItemValue Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Reports/Report.cs b/Scripts/Engines/Reports/Objects/Reports/Report.cs new file mode 100644 index 0000000..07a52b7 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/Report.cs @@ -0,0 +1,74 @@ +using System; + +namespace Server.Engines.Reports +{ + public class Report : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "rp", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new Report(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private string m_Name; + private string m_Width; + private ReportColumnCollection m_Columns; + private ReportItemCollection m_Items; + + public string Name{ get{ return m_Name; } set{ m_Name = value; } } + public string Width{ get{ return m_Width; } set{ m_Width = value; } } + public ReportColumnCollection Columns{ get{ return m_Columns; } } + public ReportItemCollection Items{ get{ return m_Items; } } + + private Report() : this( null, null ) + { + } + + public Report( string name, string width ) + { + m_Name = name; + m_Width = width; + m_Columns = new ReportColumnCollection(); + m_Items = new ReportItemCollection(); + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetString( "n", m_Name ); + op.SetString( "w", m_Width ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_Name = Utility.Intern( ip.GetString( "n" ) ); + m_Width = Utility.Intern( ip.GetString( "w" ) ); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + for ( int i = 0; i < m_Columns.Count; ++i ) + m_Columns[i].Serialize( op ); + + for ( int i = 0; i < m_Items.Count; ++i ) + m_Items[i].Serialize( op ); + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + while ( ip.HasChild ) + { + PersistableObject child = ip.GetChild(); + + if ( child is ReportColumn ) + m_Columns.Add( (ReportColumn) child ); + else if ( child is ReportItem ) + m_Items.Add( (ReportItem) child ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportColumn.cs b/Scripts/Engines/Reports/Objects/Reports/ReportColumn.cs new file mode 100644 index 0000000..e5fe3ca --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/ReportColumn.cs @@ -0,0 +1,55 @@ +using System; + +namespace Server.Engines.Reports +{ + public class ReportColumn : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "rc", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new ReportColumn(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private string m_Width; + private string m_Align; + private string m_Name; + + public string Width{ get{ return m_Width; } set{ m_Width = value; } } + public string Align{ get{ return m_Align; } set{ m_Align = value; } } + public string Name{ get{ return m_Name; } set{ m_Name = value; } } + + private ReportColumn() + { + } + + public ReportColumn( string width, string align ) : this( width, align, null ) + { + } + + public ReportColumn( string width, string align, string name ) + { + m_Width = width; + m_Align = align; + m_Name = name; + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetString( "w", m_Width ); + op.SetString( "a", m_Align ); + op.SetString( "n", m_Name ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_Width = Utility.Intern( ip.GetString( "w" ) ); + m_Align = Utility.Intern( ip.GetString( "a" ) ); + m_Name = Utility.Intern( ip.GetString( "n" ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportColumnCollection.cs b/Scripts/Engines/Reports/Objects/Reports/ReportColumnCollection.cs new file mode 100644 index 0000000..b116b4c --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/ReportColumnCollection.cs @@ -0,0 +1,210 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.ReportColumn. + /// + public class ReportColumnCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public ReportColumnCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.ReportColumn at a specific position in the ReportColumnCollection. + /// + public Server.Engines.Reports.ReportColumn this[int index] + { + get + { + return ((Server.Engines.Reports.ReportColumn)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + public int Add( string width, string align ) + { + return Add( new ReportColumn( width, align ) ); + } + + public int Add( string width, string align, string name ) + { + return Add( new ReportColumn( width, align, name ) ); + } + + /// + /// Append a Server.Engines.Reports.ReportColumn entry to this collection. + /// + /// Server.Engines.Reports.ReportColumn instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.ReportColumn value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.ReportColumn instance is in this collection. + /// + /// Server.Engines.Reports.ReportColumn instance to search for. + /// True if the Server.Engines.Reports.ReportColumn instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.ReportColumn value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.ReportColumn instance is in this collection. + /// + /// Server.Engines.Reports.ReportColumn instance to find. + /// The zero-based index of the specified Server.Engines.Reports.ReportColumn instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.ReportColumn value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.ReportColumn instance from this collection. + /// + /// The Server.Engines.Reports.ReportColumn instance to remove. + public void Remove(Server.Engines.Reports.ReportColumn value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.ReportColumn instance. + /// + /// An Server.Engines.Reports.ReportColumn's enumerator. + public new ReportColumnCollectionEnumerator GetEnumerator() + { + return new ReportColumnCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.ReportColumn instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.ReportColumn instance to insert. + public void Insert(int index, Server.Engines.Reports.ReportColumn value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.ReportColumn. + /// + public class ReportColumnCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.ReportColumn _currentElement; + + /// + /// Collection to enumerate. + /// + private ReportColumnCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal ReportColumnCollectionEnumerator(ReportColumnCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.ReportColumn object in the enumerated ReportColumnCollection currently indexed by this instance. + /// + public Server.Engines.Reports.ReportColumn Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportItem.cs b/Scripts/Engines/Reports/Objects/Reports/ReportItem.cs new file mode 100644 index 0000000..0dba26f --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/ReportItem.cs @@ -0,0 +1,39 @@ +using System; + +namespace Server.Engines.Reports +{ + public class ReportItem : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "ri", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new ReportItem(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private ItemValueCollection m_Values; + + public ItemValueCollection Values{ get{ return m_Values; } } + + public ReportItem() + { + m_Values = new ItemValueCollection(); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + for ( int i = 0; i < m_Values.Count; ++i ) + m_Values[i].Serialize( op ); + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + while ( ip.HasChild ) + m_Values.Add( ip.GetChild() as ItemValue ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Reports/ReportItemCollection.cs b/Scripts/Engines/Reports/Objects/Reports/ReportItemCollection.cs new file mode 100644 index 0000000..2ebe1ac --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Reports/ReportItemCollection.cs @@ -0,0 +1,215 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.ReportItem. + /// + public class ReportItemCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public ReportItemCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.ReportItem at a specific position in the ReportItemCollection. + /// + public Server.Engines.Reports.ReportItem this[int index] + { + get + { + return ((Server.Engines.Reports.ReportItem)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + public int Add( string name, object value ) + { + return Add( name, value, null ); + } + + public int Add( string name, object value, string format ) + { + ReportItem item = new ReportItem(); + + item.Values.Add( name ); + item.Values.Add( value == null ? "" : value.ToString(), format ); + + return Add( item ); + } + + /// + /// Append a Server.Engines.Reports.ReportItem entry to this collection. + /// + /// Server.Engines.Reports.ReportItem instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.ReportItem value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.ReportItem instance is in this collection. + /// + /// Server.Engines.Reports.ReportItem instance to search for. + /// True if the Server.Engines.Reports.ReportItem instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.ReportItem value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.ReportItem instance is in this collection. + /// + /// Server.Engines.Reports.ReportItem instance to find. + /// The zero-based index of the specified Server.Engines.Reports.ReportItem instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.ReportItem value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.ReportItem instance from this collection. + /// + /// The Server.Engines.Reports.ReportItem instance to remove. + public void Remove(Server.Engines.Reports.ReportItem value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.ReportItem instance. + /// + /// An Server.Engines.Reports.ReportItem's enumerator. + public new ReportItemCollectionEnumerator GetEnumerator() + { + return new ReportItemCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.ReportItem instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.ReportItem instance to insert. + public void Insert(int index, Server.Engines.Reports.ReportItem value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.ReportItem. + /// + public class ReportItemCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.ReportItem _currentElement; + + /// + /// Collection to enumerate. + /// + private ReportItemCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal ReportItemCollectionEnumerator(ReportItemCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.ReportItem object in the enumerated ReportItemCollection currently indexed by this instance. + /// + public Server.Engines.Reports.ReportItem Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Snapshots/Snapshot.cs b/Scripts/Engines/Reports/Objects/Snapshots/Snapshot.cs new file mode 100644 index 0000000..f758278 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Snapshots/Snapshot.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections; + +namespace Server.Engines.Reports +{ + public class Snapshot : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "ss", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new Snapshot(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private DateTime m_TimeStamp; + private ObjectCollection m_Children; + + public DateTime TimeStamp{ get{ return m_TimeStamp; } set{ m_TimeStamp = value; } } + public ObjectCollection Children{ get{ return m_Children; } set{ m_Children = value; } } + + public Snapshot() + { + m_Children = new ObjectCollection(); + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetDateTime( "t", m_TimeStamp ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_TimeStamp = ip.GetDateTime( "t" ); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + for ( int i = 0; i < m_Children.Count; ++i ) + m_Children[i].Serialize( op ); + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + while ( ip.HasChild ) + m_Children.Add( ip.GetChild() ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Snapshots/SnapshotCollection.cs b/Scripts/Engines/Reports/Objects/Snapshots/SnapshotCollection.cs new file mode 100644 index 0000000..15e20e9 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Snapshots/SnapshotCollection.cs @@ -0,0 +1,200 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.Snapshot. + /// + public class SnapshotCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public SnapshotCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.Snapshot at a specific position in the SnapshotCollection. + /// + public Server.Engines.Reports.Snapshot this[int index] + { + get + { + return ((Server.Engines.Reports.Snapshot)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + /// + /// Append a Server.Engines.Reports.Snapshot entry to this collection. + /// + /// Server.Engines.Reports.Snapshot instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.Snapshot value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.Snapshot instance is in this collection. + /// + /// Server.Engines.Reports.Snapshot instance to search for. + /// True if the Server.Engines.Reports.Snapshot instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.Snapshot value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.Snapshot instance is in this collection. + /// + /// Server.Engines.Reports.Snapshot instance to find. + /// The zero-based index of the specified Server.Engines.Reports.Snapshot instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.Snapshot value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.Snapshot instance from this collection. + /// + /// The Server.Engines.Reports.Snapshot instance to remove. + public void Remove(Server.Engines.Reports.Snapshot value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.Snapshot instance. + /// + /// An Server.Engines.Reports.Snapshot's enumerator. + public new SnapshotCollectionEnumerator GetEnumerator() + { + return new SnapshotCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.Snapshot instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.Snapshot instance to insert. + public void Insert(int index, Server.Engines.Reports.Snapshot value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.Snapshot. + /// + public class SnapshotCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.Snapshot _currentElement; + + /// + /// Collection to enumerate. + /// + private SnapshotCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal SnapshotCollectionEnumerator(SnapshotCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.Snapshot object in the enumerated SnapshotCollection currently indexed by this instance. + /// + public Server.Engines.Reports.Snapshot Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Snapshots/SnapshotHistory.cs b/Scripts/Engines/Reports/Objects/Snapshots/SnapshotHistory.cs new file mode 100644 index 0000000..7a5e880 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Snapshots/SnapshotHistory.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using System.Xml; + +namespace Server.Engines.Reports +{ + public class SnapshotHistory : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "sh", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new SnapshotHistory(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private SnapshotCollection m_Snapshots; + + public SnapshotCollection Snapshots{ get{ return m_Snapshots; } set{ m_Snapshots = value; } } + + public SnapshotHistory() + { + m_Snapshots = new SnapshotCollection(); + } + + public void Save() + { + string path = Path.Combine( Core.BaseDirectory, "reportHistory.xml" ); + PersistanceWriter pw = new XmlPersistanceWriter( path, "Stats" ); + + pw.WriteDocument( this ); + + pw.Close(); + } + + public void Load() + { + string path = Path.Combine( Core.BaseDirectory, "reportHistory.xml" ); + + if ( !File.Exists( path ) ) + return; + + PersistanceReader pr = new XmlPersistanceReader( path, "Stats" ); + + pr.ReadDocument( this ); + + pr.Close(); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + for ( int i = 0; i < m_Snapshots.Count; ++i ) + m_Snapshots[i].Serialize( op ); + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + while ( ip.HasChild ) + m_Snapshots.Add( ip.GetChild() as Snapshot ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/Info.cs b/Scripts/Engines/Reports/Objects/Staffing/Info.cs new file mode 100644 index 0000000..1943135 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/Info.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using Server; +using Server.Accounting; +using Server.Engines; +using Server.Engines.Help; + +namespace Server.Engines.Reports +{ + public abstract class BaseInfo : IComparable + { + private static TimeSpan m_SortRange; + + public static TimeSpan SortRange{ get{ return m_SortRange; } set{ m_SortRange = value; } } + + private string m_Account; + private string m_Display; + private PageInfoCollection m_Pages; + + public string Account{ get{ return m_Account; } set{ m_Account = value; } } + public PageInfoCollection Pages{ get{ return m_Pages; } set{ m_Pages = value; } } + + public string Display + { + get + { + if ( m_Display != null ) + return m_Display; + + if ( m_Account != null ) + { + IAccount acct = Accounts.GetAccount( m_Account ); + + if ( acct != null ) + { + Mobile mob = null; + + for ( int i = 0; i < acct.Length; ++i ) + { + Mobile check = acct[i]; + + if ( check != null && (mob == null || check.AccessLevel > mob.AccessLevel) ) + mob = check; + } + + if ( mob != null && mob.Name != null && mob.Name.Length > 0 ) + return ( m_Display = mob.Name ); + } + } + + return ( m_Display = m_Account ); + } + } + + public int GetPageCount( PageResolution res, DateTime min, DateTime max ) + { + return StaffHistory.GetPageCount( m_Pages, res, min, max ); + } + + public BaseInfo( string account ) + { + m_Account = account; + m_Pages = new PageInfoCollection(); + } + + public void Register( PageInfo page ) + { + m_Pages.Add( page ); + } + + public void Unregister( PageInfo page ) + { + m_Pages.Remove( page ); + } + + public int CompareTo( object obj ) + { + BaseInfo cmp = obj as BaseInfo; + + int v = cmp.GetPageCount( cmp is StaffInfo ? PageResolution.Handled : PageResolution.None, DateTime.Now - m_SortRange, DateTime.Now ) + - this.GetPageCount( this is StaffInfo ? PageResolution.Handled : PageResolution.None, DateTime.Now - m_SortRange, DateTime.Now ); + + if ( v == 0 ) + v = String.Compare( this.Display, cmp.Display ); + + return v; + } + } + + public class StaffInfo : BaseInfo + { + public StaffInfo( string account ) : base( account ) + { + } + } + + public class UserInfo : BaseInfo + { + public UserInfo( string account ) : base( account ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/PageInfo.cs b/Scripts/Engines/Reports/Objects/Staffing/PageInfo.cs new file mode 100644 index 0000000..44efde8 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/PageInfo.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections; +using Server; +using Server.Engines; +using Server.Engines.Help; + +namespace Server.Engines.Reports +{ + public enum PageResolution + { + None, + Handled, + Deleted, + Logged, + Canceled + } + + public class PageInfo : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "pi", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new PageInfo(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private StaffHistory m_History; + private StaffInfo m_Resolver; + private UserInfo m_Sender; + + public StaffInfo Resolver + { + get{ return m_Resolver; } + set + { + if ( m_Resolver == value ) + return; + + lock ( StaffHistory.RenderLock ) + { + if ( m_Resolver != null ) + m_Resolver.Unregister( this ); + + m_Resolver = value; + + if ( m_Resolver != null ) + m_Resolver.Register( this ); + } + } + } + + public UserInfo Sender + { + get{ return m_Sender; } + set + { + if ( m_Sender == value ) + return; + + lock ( StaffHistory.RenderLock ) + { + if ( m_Sender != null ) + m_Sender.Unregister( this ); + + m_Sender = value; + + if ( m_Sender != null ) + m_Sender.Register( this ); + } + } + } + + private PageType m_PageType; + private PageResolution m_Resolution; + + private DateTime m_TimeSent; + private DateTime m_TimeResolved; + + private string m_SentBy; + private string m_ResolvedBy; + + private string m_Message; + private ResponseInfoCollection m_Responses; + + public StaffHistory History + { + get{ return m_History; } + set + { + if ( m_History == value ) + return; + + if ( m_History != null ) + { + Sender = null; + Resolver = null; + } + + m_History = value; + + if ( m_History != null ) + { + Sender = m_History.GetUserInfo( m_SentBy ); + UpdateResolver(); + } + } + } + + public PageType PageType{ get{ return m_PageType; } set{ m_PageType = value; } } + public PageResolution Resolution{ get{ return m_Resolution; } } + + public DateTime TimeSent{ get{ return m_TimeSent; } set{ m_TimeSent = value; } } + public DateTime TimeResolved{ get{ return m_TimeResolved; } } + + public string SentBy + { + get{ return m_SentBy; } + set + { + m_SentBy = value; + + if ( m_History != null ) + Sender = m_History.GetUserInfo( m_SentBy ); + } + } + + public string ResolvedBy + { + get{ return m_ResolvedBy; } + } + + public string Message{ get{ return m_Message; } set{ m_Message = value; } } + public ResponseInfoCollection Responses{ get{ return m_Responses; } set{ m_Responses = value; } } + + public void UpdateResolver() + { + string resolvedBy; + DateTime timeResolved; + PageResolution res = GetResolution( out resolvedBy, out timeResolved ); + + if ( m_History != null && IsStaffResolution( res ) ) + Resolver = m_History.GetStaffInfo( resolvedBy ); + else + Resolver = null; + + m_ResolvedBy = resolvedBy; + m_TimeResolved = timeResolved; + m_Resolution = res; + } + + public bool IsStaffResolution( PageResolution res ) + { + return ( res == PageResolution.Handled ); + } + + public static PageResolution ResFromResp( string resp ) + { + switch ( resp ) + { + case "[Handled]": return PageResolution.Handled; + case "[Deleting]": return PageResolution.Deleted; + case "[Logout]": return PageResolution.Logged; + case "[Canceled]": return PageResolution.Canceled; + } + + return PageResolution.None; + } + + public PageResolution GetResolution( out string resolvedBy, out DateTime timeResolved ) + { + for ( int i = m_Responses.Count - 1; i >= 0; --i ) + { + ResponseInfo resp = m_Responses[i]; + PageResolution res = ResFromResp( resp.Message ); + + if ( res != PageResolution.None ) + { + resolvedBy = resp.SentBy; + timeResolved = resp.TimeStamp; + return res; + } + } + + resolvedBy = m_SentBy; + timeResolved = m_TimeSent; + return PageResolution.None; + } + + public static string GetAccount( Mobile mob ) + { + if ( mob == null ) + return null; + + Accounting.Account acct = mob.Account as Accounting.Account; + + if ( acct == null ) + return null; + + return acct.Username; + } + + public PageInfo() + { + m_Responses = new ResponseInfoCollection(); + } + + public PageInfo( PageEntry entry ) + { + m_PageType = entry.Type; + + m_TimeSent = entry.Sent; + m_SentBy = GetAccount( entry.Sender ); + + m_Message = entry.Message; + m_Responses = new ResponseInfoCollection(); + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetInt32( "p", (int)m_PageType ); + + op.SetDateTime( "ts", m_TimeSent ); + op.SetString( "s", m_SentBy ); + + op.SetString( "m", m_Message ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_PageType = (PageType) ip.GetInt32( "p" ); + + m_TimeSent = ip.GetDateTime( "ts" ); + m_SentBy = ip.GetString( "s" ); + + m_Message = ip.GetString( "m" ); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + lock ( this ) + { + for ( int i = 0; i < m_Responses.Count; ++i ) + m_Responses[i].Serialize( op ); + } + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + while ( ip.HasChild ) + m_Responses.Add( ip.GetChild() as ResponseInfo ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/PageInfoCollection.cs b/Scripts/Engines/Reports/Objects/Staffing/PageInfoCollection.cs new file mode 100644 index 0000000..7fef929 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/PageInfoCollection.cs @@ -0,0 +1,200 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.PageInfo. + /// + public class PageInfoCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public PageInfoCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.PageInfo at a specific position in the PageInfoCollection. + /// + public Server.Engines.Reports.PageInfo this[int index] + { + get + { + return ((Server.Engines.Reports.PageInfo)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + /// + /// Append a Server.Engines.Reports.PageInfo entry to this collection. + /// + /// Server.Engines.Reports.PageInfo instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.PageInfo value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.PageInfo instance is in this collection. + /// + /// Server.Engines.Reports.PageInfo instance to search for. + /// True if the Server.Engines.Reports.PageInfo instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.PageInfo value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.PageInfo instance is in this collection. + /// + /// Server.Engines.Reports.PageInfo instance to find. + /// The zero-based index of the specified Server.Engines.Reports.PageInfo instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.PageInfo value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.PageInfo instance from this collection. + /// + /// The Server.Engines.Reports.PageInfo instance to remove. + public void Remove(Server.Engines.Reports.PageInfo value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.PageInfo instance. + /// + /// An Server.Engines.Reports.PageInfo's enumerator. + public new PageInfoCollectionEnumerator GetEnumerator() + { + return new PageInfoCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.PageInfo instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.PageInfo instance to insert. + public void Insert(int index, Server.Engines.Reports.PageInfo value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.PageInfo. + /// + public class PageInfoCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.PageInfo _currentElement; + + /// + /// Collection to enumerate. + /// + private PageInfoCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal PageInfoCollectionEnumerator(PageInfoCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.PageInfo object in the enumerated PageInfoCollection currently indexed by this instance. + /// + public Server.Engines.Reports.PageInfo Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Staffing/QueueStatus.cs b/Scripts/Engines/Reports/Objects/Staffing/QueueStatus.cs new file mode 100644 index 0000000..b1171ae --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/QueueStatus.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections; +using Server; +using Server.Engines; +using Server.Engines.Help; + +namespace Server.Engines.Reports +{ + public class QueueStatus : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "qs", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new QueueStatus(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private DateTime m_TimeStamp; + private int m_Count; + + public DateTime TimeStamp{ get{ return m_TimeStamp; } set{ m_TimeStamp = value; } } + public int Count{ get{ return m_Count; } set{ m_Count = value; } } + + public QueueStatus() + { + } + + public QueueStatus( int count ) + { + m_TimeStamp = DateTime.Now; + m_Count = count; + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetDateTime( "t", m_TimeStamp ); + op.SetInt32( "c", m_Count ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_TimeStamp = ip.GetDateTime( "t" ); + m_Count = ip.GetInt32( "c" ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/QueueStatusCollection.cs b/Scripts/Engines/Reports/Objects/Staffing/QueueStatusCollection.cs new file mode 100644 index 0000000..4090f98 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/QueueStatusCollection.cs @@ -0,0 +1,200 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.QueueStatus. + /// + public class QueueStatusCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public QueueStatusCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.QueueStatus at a specific position in the QueueStatusCollection. + /// + public Server.Engines.Reports.QueueStatus this[int index] + { + get + { + return ((Server.Engines.Reports.QueueStatus)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + /// + /// Append a Server.Engines.Reports.QueueStatus entry to this collection. + /// + /// Server.Engines.Reports.QueueStatus instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.QueueStatus value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.QueueStatus instance is in this collection. + /// + /// Server.Engines.Reports.QueueStatus instance to search for. + /// True if the Server.Engines.Reports.QueueStatus instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.QueueStatus value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.QueueStatus instance is in this collection. + /// + /// Server.Engines.Reports.QueueStatus instance to find. + /// The zero-based index of the specified Server.Engines.Reports.QueueStatus instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.QueueStatus value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.QueueStatus instance from this collection. + /// + /// The Server.Engines.Reports.QueueStatus instance to remove. + public void Remove(Server.Engines.Reports.QueueStatus value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.QueueStatus instance. + /// + /// An Server.Engines.Reports.QueueStatus's enumerator. + public new QueueStatusCollectionEnumerator GetEnumerator() + { + return new QueueStatusCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.QueueStatus instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.QueueStatus instance to insert. + public void Insert(int index, Server.Engines.Reports.QueueStatus value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.QueueStatus. + /// + public class QueueStatusCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.QueueStatus _currentElement; + + /// + /// Collection to enumerate. + /// + private QueueStatusCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal QueueStatusCollectionEnumerator(QueueStatusCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.QueueStatus object in the enumerated QueueStatusCollection currently indexed by this instance. + /// + public Server.Engines.Reports.QueueStatus Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Staffing/ResponseInfo.cs b/Scripts/Engines/Reports/Objects/Staffing/ResponseInfo.cs new file mode 100644 index 0000000..4c34c77 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/ResponseInfo.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using Server; +using Server.Engines; +using Server.Engines.Help; + +namespace Server.Engines.Reports +{ + public class ResponseInfo : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "rs", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new ResponseInfo(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private DateTime m_TimeStamp; + + private string m_SentBy; + private string m_Message; + + public DateTime TimeStamp{ get{ return m_TimeStamp; } set{ m_TimeStamp = value; } } + + public string SentBy{ get{ return m_SentBy; } set{ m_SentBy = value; } } + public string Message{ get{ return m_Message; } set{ m_Message = value; } } + + public ResponseInfo() + { + } + + public ResponseInfo( string sentBy, string message ) + { + m_TimeStamp = DateTime.Now; + m_SentBy = sentBy; + m_Message = message; + } + + public override void SerializeAttributes( PersistanceWriter op ) + { + op.SetDateTime( "t", m_TimeStamp ); + + op.SetString( "s", m_SentBy ); + op.SetString( "m", m_Message ); + } + + public override void DeserializeAttributes( PersistanceReader ip ) + { + m_TimeStamp = ip.GetDateTime( "t" ); + + m_SentBy = ip.GetString( "s" ); + m_Message = ip.GetString( "m" ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Objects/Staffing/ResponseInfoCollection.cs b/Scripts/Engines/Reports/Objects/Staffing/ResponseInfoCollection.cs new file mode 100644 index 0000000..7176fa5 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/ResponseInfoCollection.cs @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.ResponseInfo. + /// + public class ResponseInfoCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public ResponseInfoCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.ResponseInfo at a specific position in the ResponseInfoCollection. + /// + public Server.Engines.Reports.ResponseInfo this[int index] + { + get + { + return ((Server.Engines.Reports.ResponseInfo)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + public int Add( string sentBy, string message ) + { + return Add( new ResponseInfo( sentBy, message ) ); + } + + /// + /// Append a Server.Engines.Reports.ResponseInfo entry to this collection. + /// + /// Server.Engines.Reports.ResponseInfo instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.ResponseInfo value) + { + return this.List.Add(value); + } + + /// + /// Determines whether a specified Server.Engines.Reports.ResponseInfo instance is in this collection. + /// + /// Server.Engines.Reports.ResponseInfo instance to search for. + /// True if the Server.Engines.Reports.ResponseInfo instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.ResponseInfo value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.ResponseInfo instance is in this collection. + /// + /// Server.Engines.Reports.ResponseInfo instance to find. + /// The zero-based index of the specified Server.Engines.Reports.ResponseInfo instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.ResponseInfo value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.ResponseInfo instance from this collection. + /// + /// The Server.Engines.Reports.ResponseInfo instance to remove. + public void Remove(Server.Engines.Reports.ResponseInfo value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.ResponseInfo instance. + /// + /// An Server.Engines.Reports.ResponseInfo's enumerator. + public new ResponseInfoCollectionEnumerator GetEnumerator() + { + return new ResponseInfoCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.ResponseInfo instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.ResponseInfo instance to insert. + public void Insert(int index, Server.Engines.Reports.ResponseInfo value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.ResponseInfo. + /// + public class ResponseInfoCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.ResponseInfo _currentElement; + + /// + /// Collection to enumerate. + /// + private ResponseInfoCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal ResponseInfoCollectionEnumerator(ResponseInfoCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.ResponseInfo object in the enumerated ResponseInfoCollection currently indexed by this instance. + /// + public Server.Engines.Reports.ResponseInfo Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Objects/Staffing/StaffHistory.cs b/Scripts/Engines/Reports/Objects/Staffing/StaffHistory.cs new file mode 100644 index 0000000..2b0f298 --- /dev/null +++ b/Scripts/Engines/Reports/Objects/Staffing/StaffHistory.cs @@ -0,0 +1,406 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; + +namespace Server.Engines.Reports +{ + public class StaffHistory : PersistableObject + { + #region Type Identification + public static readonly PersistableType ThisTypeID = new PersistableType( "stfhst", new ConstructCallback( Construct ) ); + + private static PersistableObject Construct() + { + return new StaffHistory(); + } + + public override PersistableType TypeID{ get{ return ThisTypeID; } } + #endregion + + private PageInfoCollection m_Pages; + private QueueStatusCollection m_QueueStats; + + private Hashtable m_UserInfo; + private Hashtable m_StaffInfo; + + public PageInfoCollection Pages{ get{ return m_Pages; } set{ m_Pages = value; } } + public QueueStatusCollection QueueStats{ get{ return m_QueueStats; } set{ m_QueueStats = value; } } + + public Hashtable UserInfo{ get{ return m_UserInfo; } set{ m_UserInfo = value; } } + public Hashtable StaffInfo{ get{ return m_StaffInfo; } set{ m_StaffInfo = value; } } + + public void AddPage( PageInfo info ) + { + lock ( SaveLock ) + m_Pages.Add( info ); + + info.History = this; + } + + public StaffHistory() + { + m_Pages = new PageInfoCollection(); + m_QueueStats = new QueueStatusCollection(); + + m_UserInfo = new Hashtable( StringComparer.OrdinalIgnoreCase ); + m_StaffInfo = new Hashtable( StringComparer.OrdinalIgnoreCase ); + } + + public StaffInfo GetStaffInfo( string account ) + { + lock ( RenderLock ) + { + if ( account == null || account.Length == 0 ) + return null; + + StaffInfo info = m_StaffInfo[account] as StaffInfo; + + if ( info == null ) + m_StaffInfo[account] = info = new StaffInfo( account ); + + return info; + } + } + + public UserInfo GetUserInfo( string account ) + { + if ( account == null || account.Length == 0 ) + return null; + + UserInfo info = m_UserInfo[account] as UserInfo; + + if ( info == null ) + m_UserInfo[account] = info = new UserInfo( account ); + + return info; + } + + public static readonly object RenderLock = new object(); + public static readonly object SaveLock = new object(); + + public void Save() + { + lock ( SaveLock ) + { + string path = Path.Combine( Core.BaseDirectory, "staffHistory.xml" ); + PersistanceWriter pw = new XmlPersistanceWriter( path, "Staff" ); + + pw.WriteDocument( this ); + + pw.Close(); + } + } + + public void Load() + { + string path = Path.Combine( Core.BaseDirectory, "staffHistory.xml" ); + + if ( !File.Exists( path ) ) + return; + + PersistanceReader pr = new XmlPersistanceReader( path, "Staff" ); + + pr.ReadDocument( this ); + + pr.Close(); + } + + public override void SerializeChildren( PersistanceWriter op ) + { + for ( int i = 0; i < m_Pages.Count; ++i ) + m_Pages[i].Serialize( op ); + + for ( int i = 0; i < m_QueueStats.Count; ++i ) + m_QueueStats[i].Serialize( op ); + } + + public override void DeserializeChildren( PersistanceReader ip ) + { + DateTime min = DateTime.Now - TimeSpan.FromDays( 8.0 ); + + while ( ip.HasChild ) + { + PersistableObject obj = ip.GetChild(); + + if ( obj is PageInfo ) + { + PageInfo pageInfo = obj as PageInfo; + + pageInfo.UpdateResolver(); + + if ( pageInfo.TimeSent >= min || pageInfo.TimeResolved >= min ) + { + m_Pages.Add( pageInfo ); + pageInfo.History = this; + } + else + { + pageInfo.Sender = null; + pageInfo.Resolver = null; + } + } + else if ( obj is QueueStatus ) + { + QueueStatus queueStatus = obj as QueueStatus; + + if ( queueStatus.TimeStamp >= min ) + m_QueueStats.Add( queueStatus ); + } + } + } + + public StaffInfo[] GetStaff() + { + StaffInfo[] staff = new StaffInfo[m_StaffInfo.Count]; + int index = 0; + + foreach ( StaffInfo staffInfo in m_StaffInfo.Values ) + staff[index++] = staffInfo; + + return staff; + } + + public void Render( ObjectCollection objects ) + { + lock ( RenderLock ) + { + objects.Add( GraphQueueStatus() ); + + StaffInfo[] staff = GetStaff(); + + BaseInfo.SortRange = TimeSpan.FromDays( 7.0 ); + Array.Sort( staff ); + + objects.Add( GraphHourlyPages( m_Pages, PageResolution.None, "New pages by hour", "graph_new_pages_hr" ) ); + objects.Add( GraphHourlyPages( m_Pages, PageResolution.Handled, "Handled pages by hour", "graph_handled_pages_hr" ) ); + objects.Add( GraphHourlyPages( m_Pages, PageResolution.Deleted, "Deleted pages by hour", "graph_deleted_pages_hr" ) ); + objects.Add( GraphHourlyPages( m_Pages, PageResolution.Canceled, "Canceled pages by hour", "graph_canceled_pages_hr" ) ); + objects.Add( GraphHourlyPages( m_Pages, PageResolution.Logged, "Logged-out pages by hour", "graph_logged_pages_hr" ) ); + + BaseInfo.SortRange = TimeSpan.FromDays( 1.0 ); + Array.Sort( staff ); + + objects.Add( ReportTotalPages( staff, TimeSpan.FromDays( 1.0 ), "1 Day" ) ); + objects.AddRange( (PersistableObject[])ChartTotalPages( staff, TimeSpan.FromDays( 1.0 ), "1 Day", "graph_daily_pages" ) ); + + BaseInfo.SortRange = TimeSpan.FromDays( 7.0 ); + Array.Sort( staff ); + + objects.Add( ReportTotalPages( staff, TimeSpan.FromDays( 7.0 ), "1 Week" ) ); + objects.AddRange( (PersistableObject[])ChartTotalPages( staff, TimeSpan.FromDays( 7.0 ), "1 Week", "graph_weekly_pages" ) ); + + BaseInfo.SortRange = TimeSpan.FromDays( 30.0 ); + Array.Sort( staff ); + + objects.Add( ReportTotalPages( staff, TimeSpan.FromDays( 30.0 ), "1 Month" ) ); + objects.AddRange( (PersistableObject[])ChartTotalPages( staff, TimeSpan.FromDays( 30.0 ), "1 Month", "graph_monthly_pages" ) ); + + for ( int i = 0; i < staff.Length; ++i ) + objects.Add( GraphHourlyPages( staff[i] ) ); + } + } + + public static int GetPageCount( StaffInfo staff, DateTime min, DateTime max ) + { + return GetPageCount( staff.Pages, PageResolution.Handled, min, max ); + } + + public static int GetPageCount( PageInfoCollection pages, PageResolution res, DateTime min, DateTime max ) + { + int count = 0; + + for ( int i = 0; i < pages.Count; ++i ) + { + if ( res != PageResolution.None && pages[i].Resolution != res ) + continue; + + DateTime ts = pages[i].TimeResolved; + + if ( ts >= min && ts < max ) + ++count; + } + + return count; + } + + private BarGraph GraphQueueStatus() + { + int[] totals = new int[24]; + int[] counts = new int[24]; + + DateTime max = DateTime.Now; + DateTime min = max - TimeSpan.FromDays( 7.0 ); + + for ( int i = 0; i < m_QueueStats.Count; ++i ) + { + DateTime ts = m_QueueStats[i].TimeStamp; + + if ( ts >= min && ts < max ) + { + DateTime date = ts.Date; + TimeSpan time = ts.TimeOfDay; + + int hour = time.Hours; + + totals[hour] += m_QueueStats[i].Count; + counts[hour]++; + } + } + + BarGraph barGraph = new BarGraph( "Average pages in queue", "graph_pagequeue_avg", 10, "Time", "Pages", BarGraphRenderMode.Lines ); + + barGraph.FontSize = 6; + + for ( int i = 7; i <= totals.Length+7; ++i ) + { + int val; + + if ( counts[i%totals.Length] == 0 ) + val = 0; + else + val = (totals[i%totals.Length] + (counts[i%totals.Length] / 2)) / counts[i%totals.Length]; + + int realHours = i%totals.Length; + int hours; + + if ( realHours == 0 ) + hours = 12; + else if ( realHours > 12 ) + hours = realHours - 12; + else + hours = realHours; + + barGraph.Items.Add( hours + (realHours >= 12 ? " PM" : " AM"), val ); + } + + return barGraph; + } + + private BarGraph GraphHourlyPages( StaffInfo staff ) + { + return GraphHourlyPages( staff.Pages, PageResolution.Handled, "Average pages handled by " + staff.Display, "graphs_" + staff.Account.ToLower() + "_avg" ); + } + + private BarGraph GraphHourlyPages( PageInfoCollection pages, PageResolution res, string title, string fname ) + { + int[] totals = new int[24]; + int[] counts = new int[24]; + + DateTime[] dates = new DateTime[24]; + + DateTime max = DateTime.Now; + DateTime min = max - TimeSpan.FromDays( 7.0 ); + + bool sentStamp = ( res == PageResolution.None ); + + for ( int i = 0; i < pages.Count; ++i ) + { + if ( res != PageResolution.None && pages[i].Resolution != res ) + continue; + + DateTime ts = ( sentStamp ? pages[i].TimeSent : pages[i].TimeResolved ); + + if ( ts >= min && ts < max ) + { + DateTime date = ts.Date; + TimeSpan time = ts.TimeOfDay; + + int hour = time.Hours; + + totals[hour]++; + + if ( dates[hour] != date ) + { + counts[hour]++; + dates[hour] = date; + } + } + } + + BarGraph barGraph = new BarGraph( title, fname, 10, "Time", "Pages", BarGraphRenderMode.Lines ); + + barGraph.FontSize = 6; + + for ( int i = 7; i <= totals.Length+7; ++i ) + { + int val; + + if ( counts[i%totals.Length] == 0 ) + val = 0; + else + val = (totals[i%totals.Length] + (counts[i%totals.Length] / 2)) / counts[i%totals.Length]; + + int realHours = i%totals.Length; + int hours; + + if ( realHours == 0 ) + hours = 12; + else if ( realHours > 12 ) + hours = realHours - 12; + else + hours = realHours; + + barGraph.Items.Add( hours + (realHours >= 12 ? " PM" : " AM"), val ); + } + + return barGraph; + } + + private Report ReportTotalPages( StaffInfo[] staff, TimeSpan ts, string title ) + { + DateTime max = DateTime.Now; + DateTime min = max - ts; + + Report report = new Report( title + " Staff Report", "400" ); + + report.Columns.Add( "65%", "left", "Staff Name" ); + report.Columns.Add( "35%", "center", "Page Count" ); + + for ( int i = 0; i < staff.Length; ++i ) + report.Items.Add( staff[i].Display, GetPageCount( staff[i], min, max ) ); + + return report; + } + + private PieChart[] ChartTotalPages( StaffInfo[] staff, TimeSpan ts, string title, string fname ) + { + DateTime max = DateTime.Now; + DateTime min = max - ts; + + PieChart staffChart = new PieChart( title + " Staff Chart", fname + "_staff", true ); + + int other = 0; + + for ( int i = 0; i < staff.Length; ++i ) + { + int count = GetPageCount( staff[i], min, max ); + + if ( i < 12 && count > 0 ) + staffChart.Items.Add( staff[i].Display, count ); + else + other += count; + } + + if ( other > 0 ) + staffChart.Items.Add( "Other", other ); + + PieChart resChart = new PieChart( title + " Resolutions", fname + "_resol", true ); + + int countTotal = GetPageCount( m_Pages, PageResolution.None, min, max ); + int countHandled = GetPageCount( m_Pages, PageResolution.Handled, min, max ); + int countDeleted = GetPageCount( m_Pages, PageResolution.Deleted, min, max ); + int countCanceled = GetPageCount( m_Pages, PageResolution.Canceled, min, max ); + int countLogged = GetPageCount( m_Pages, PageResolution.Logged, min, max ); + int countUnres = countTotal - ( countHandled + countDeleted + countCanceled + countLogged ); + + resChart.Items.Add( "Handled", countHandled ); + resChart.Items.Add( "Deleted", countDeleted ); + resChart.Items.Add( "Canceled", countCanceled ); + resChart.Items.Add( "Logged Out", countLogged ); + resChart.Items.Add( "Unresolved", countUnres ); + + return new PieChart[]{ staffChart, resChart }; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistableObject.cs b/Scripts/Engines/Reports/Persistance/PersistableObject.cs new file mode 100644 index 0000000..47c7245 --- /dev/null +++ b/Scripts/Engines/Reports/Persistance/PersistableObject.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections; + +namespace Server.Engines.Reports +{ + public abstract class PersistableObject + { + public abstract PersistableType TypeID{ get; } + + public virtual void SerializeAttributes( PersistanceWriter op ) + { + } + + public virtual void SerializeChildren( PersistanceWriter op ) + { + } + + public void Serialize( PersistanceWriter op ) + { + op.BeginObject( this.TypeID ); + SerializeAttributes( op ); + op.BeginChildren(); + SerializeChildren( op ); + op.FinishChildren(); + op.FinishObject(); + } + + public virtual void DeserializeAttributes( PersistanceReader ip ) + { + } + + public virtual void DeserializeChildren( PersistanceReader ip ) + { + } + + public void Deserialize( PersistanceReader ip ) + { + DeserializeAttributes( ip ); + + if ( ip.BeginChildren() ) + { + DeserializeChildren( ip ); + ip.FinishChildren(); + } + } + + public PersistableObject() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistableObjectCollection.cs b/Scripts/Engines/Reports/Persistance/PersistableObjectCollection.cs new file mode 100644 index 0000000..8dfed35 --- /dev/null +++ b/Scripts/Engines/Reports/Persistance/PersistableObjectCollection.cs @@ -0,0 +1,205 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version: 1.1.4322.573 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Server.Engines.Reports +{ + using System; + using System.Collections; + + + /// + /// Strongly typed collection of Server.Engines.Reports.PersistableObject. + /// + public class ObjectCollection : System.Collections.CollectionBase + { + + /// + /// Default constructor. + /// + public ObjectCollection() : + base() + { + } + + /// + /// Gets or sets the value of the Server.Engines.Reports.PersistableObject at a specific position in the ObjectCollection. + /// + public Server.Engines.Reports.PersistableObject this[int index] + { + get + { + return ((Server.Engines.Reports.PersistableObject)(this.List[index])); + } + set + { + this.List[index] = value; + } + } + + /// + /// Append a Server.Engines.Reports.PersistableObject entry to this collection. + /// + /// Server.Engines.Reports.PersistableObject instance. + /// The position into which the new element was inserted. + public int Add(Server.Engines.Reports.PersistableObject value) + { + return this.List.Add(value); + } + + public void AddRange( PersistableObject[] col ) + { + this.InnerList.AddRange( col ); + } + + /// + /// Determines whether a specified Server.Engines.Reports.PersistableObject instance is in this collection. + /// + /// Server.Engines.Reports.PersistableObject instance to search for. + /// True if the Server.Engines.Reports.PersistableObject instance is in the collection; otherwise false. + public bool Contains(Server.Engines.Reports.PersistableObject value) + { + return this.List.Contains(value); + } + + /// + /// Retrieve the index a specified Server.Engines.Reports.PersistableObject instance is in this collection. + /// + /// Server.Engines.Reports.PersistableObject instance to find. + /// The zero-based index of the specified Server.Engines.Reports.PersistableObject instance. If the object is not found, the return value is -1. + public int IndexOf(Server.Engines.Reports.PersistableObject value) + { + return this.List.IndexOf(value); + } + + /// + /// Removes a specified Server.Engines.Reports.PersistableObject instance from this collection. + /// + /// The Server.Engines.Reports.PersistableObject instance to remove. + public void Remove(Server.Engines.Reports.PersistableObject value) + { + this.List.Remove(value); + } + + /// + /// Returns an enumerator that can iterate through the Server.Engines.Reports.PersistableObject instance. + /// + /// An Server.Engines.Reports.PersistableObject's enumerator. + public new ObjectCollectionEnumerator GetEnumerator() + { + return new ObjectCollectionEnumerator(this); + } + + /// + /// Insert a Server.Engines.Reports.PersistableObject instance into this collection at a specified index. + /// + /// Zero-based index. + /// The Server.Engines.Reports.PersistableObject instance to insert. + public void Insert(int index, Server.Engines.Reports.PersistableObject value) + { + this.List.Insert(index, value); + } + + /// + /// Strongly typed enumerator of Server.Engines.Reports.PersistableObject. + /// + public class ObjectCollectionEnumerator : System.Collections.IEnumerator + { + + /// + /// Current index + /// + private int _index; + + /// + /// Current element pointed to. + /// + private Server.Engines.Reports.PersistableObject _currentElement; + + /// + /// Collection to enumerate. + /// + private ObjectCollection _collection; + + /// + /// Default constructor for enumerator. + /// + /// Instance of the collection to enumerate. + internal ObjectCollectionEnumerator(ObjectCollection collection) + { + _index = -1; + _collection = collection; + } + + /// + /// Gets the Server.Engines.Reports.PersistableObject object in the enumerated ObjectCollection currently indexed by this instance. + /// + public Server.Engines.Reports.PersistableObject Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Gets the current element in the collection. + /// + object IEnumerator.Current + { + get + { + if (((_index == -1) + || (_index >= _collection.Count))) + { + throw new System.IndexOutOfRangeException("Enumerator not started."); + } + else + { + return _currentElement; + } + } + } + + /// + /// Reset the cursor, so it points to the beginning of the enumerator. + /// + public void Reset() + { + _index = -1; + _currentElement = null; + } + + /// + /// Advances the enumerator to the next queue of the enumeration, if one is currently available. + /// + /// true, if the enumerator was succesfully advanced to the next queue; false, if the enumerator has reached the end of the enumeration. + public bool MoveNext() + { + if ((_index + < (_collection.Count - 1))) + { + _index = (_index + 1); + _currentElement = this._collection[_index]; + return true; + } + _index = _collection.Count; + return false; + } + } + } +} diff --git a/Scripts/Engines/Reports/Persistance/PersistableType.cs b/Scripts/Engines/Reports/Persistance/PersistableType.cs new file mode 100644 index 0000000..4433048 --- /dev/null +++ b/Scripts/Engines/Reports/Persistance/PersistableType.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; + +namespace Server.Engines.Reports +{ + public delegate PersistableObject ConstructCallback(); + + public sealed class PersistableTypeRegistry + { + private static Hashtable m_Table; + + public static PersistableType Find( string name ) + { + return m_Table[name] as PersistableType; + } + + public static void Register( PersistableType type ) + { + if ( type != null ) + m_Table[type.Name] = type; + } + + static PersistableTypeRegistry() + { + m_Table = new Hashtable( StringComparer.OrdinalIgnoreCase ); + + Register( Report.ThisTypeID ); + Register( BarGraph.ThisTypeID ); + Register( PieChart.ThisTypeID ); + Register( Snapshot.ThisTypeID ); + Register( ItemValue.ThisTypeID ); + Register( ChartItem.ThisTypeID ); + Register( ReportItem.ThisTypeID ); + Register( ReportColumn.ThisTypeID ); + Register( SnapshotHistory.ThisTypeID ); + + Register( PageInfo.ThisTypeID ); + Register( QueueStatus.ThisTypeID ); + Register( StaffHistory.ThisTypeID ); + Register( ResponseInfo.ThisTypeID ); + } + } + + public sealed class PersistableType + { + private string m_Name; + private ConstructCallback m_Constructor; + + public string Name{ get{ return m_Name; } } + public ConstructCallback Constructor{ get{ return m_Constructor; } } + + public PersistableType( string name, ConstructCallback constructor ) + { + m_Name = name; + m_Constructor = constructor; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistanceReader.cs b/Scripts/Engines/Reports/Persistance/PersistanceReader.cs new file mode 100644 index 0000000..da49705 --- /dev/null +++ b/Scripts/Engines/Reports/Persistance/PersistanceReader.cs @@ -0,0 +1,122 @@ +using System; +using System.IO; +using System.Xml; + +namespace Server.Engines.Reports +{ + public abstract class PersistanceReader + { + public abstract int GetInt32( string key ); + public abstract bool GetBoolean( string key ); + public abstract string GetString( string key ); + public abstract DateTime GetDateTime( string key ); + + public abstract bool BeginChildren(); + public abstract void FinishChildren(); + public abstract bool HasChild{ get; } + public abstract PersistableObject GetChild(); + + public abstract void ReadDocument( PersistableObject root ); + public abstract void Close(); + + public PersistanceReader() + { + } + } + + public class XmlPersistanceReader : PersistanceReader + { + private StreamReader m_Reader; + private XmlTextReader m_Xml; + private string m_Title; + + public XmlPersistanceReader( string filePath, string title ) + { + m_Reader = new StreamReader( filePath ); + m_Xml = new XmlTextReader( m_Reader ); + m_Xml.WhitespaceHandling=WhitespaceHandling.None; + m_Title = title; + } + + public override int GetInt32( string key ) + { + return XmlConvert.ToInt32( m_Xml.GetAttribute( key ) ); + } + + public override bool GetBoolean( string key ) + { + return XmlConvert.ToBoolean( m_Xml.GetAttribute( key ) ); + } + + public override string GetString( string key ) + { + return m_Xml.GetAttribute( key ); + } + + public override DateTime GetDateTime( string key ) + { + string val = m_Xml.GetAttribute( key ); + + if ( val == null ) + return DateTime.MinValue; + + return XmlConvert.ToDateTime( val, XmlDateTimeSerializationMode.Local ); + } + + private bool m_HasChild; + + public override bool HasChild + { + get + { + return m_HasChild; + } + } + + private bool m_WasEmptyElement; + + public override bool BeginChildren() + { + m_HasChild = !m_WasEmptyElement; + + m_Xml.Read(); + + return m_HasChild; + } + + public override void FinishChildren() + { + m_Xml.Read(); + } + + public override PersistableObject GetChild() + { + PersistableType type = PersistableTypeRegistry.Find( m_Xml.Name ); + PersistableObject obj = type.Constructor(); + + m_WasEmptyElement = m_Xml.IsEmptyElement; + + obj.Deserialize( this ); + + m_HasChild = ( m_Xml.NodeType == XmlNodeType.Element ); + + return obj; + } + + public override void ReadDocument( PersistableObject root ) + { + Console.Write( "Reports: {0}: Loading...", m_Title ); + m_Xml.Read(); + m_Xml.Read(); + m_HasChild = !m_Xml.IsEmptyElement; + root.Deserialize( this ); + Console.WriteLine( "done" ); + } + + public override void Close() + { + m_Xml.Close(); + m_Reader.Close(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Persistance/PersistanceWriter.cs b/Scripts/Engines/Reports/Persistance/PersistanceWriter.cs new file mode 100644 index 0000000..1344aad --- /dev/null +++ b/Scripts/Engines/Reports/Persistance/PersistanceWriter.cs @@ -0,0 +1,129 @@ +using System; +using System.IO; +using System.Xml; + +namespace Server.Engines.Reports +{ + public abstract class PersistanceWriter + { + public abstract void SetInt32( string key, int value ); + public abstract void SetBoolean( string key, bool value ); + public abstract void SetString( string key, string value ); + public abstract void SetDateTime( string key, DateTime value ); + + public abstract void BeginObject( PersistableType typeID ); + public abstract void BeginChildren(); + public abstract void FinishChildren(); + public abstract void FinishObject(); + + public abstract void WriteDocument( PersistableObject root ); + public abstract void Close(); + + public PersistanceWriter() + { + } + } + + public sealed class XmlPersistanceWriter : PersistanceWriter + { + private string m_RealFilePath; + private string m_TempFilePath; + + private StreamWriter m_Writer; + private XmlTextWriter m_Xml; + private string m_Title; + + public XmlPersistanceWriter( string filePath, string title ) + { + m_RealFilePath = filePath; + m_TempFilePath = Path.ChangeExtension( filePath, ".tmp" ); + + m_Writer = new StreamWriter( m_TempFilePath ); + m_Xml = new XmlTextWriter( m_Writer ); + + m_Title = title; + } + + public override void SetInt32( string key, int value ) + { + m_Xml.WriteAttributeString( key, XmlConvert.ToString( value ) ); + } + + public override void SetBoolean( string key, bool value ) + { + m_Xml.WriteAttributeString( key, XmlConvert.ToString( value ) ); + } + + public override void SetString( string key, string value ) + { + if ( value != null ) + m_Xml.WriteAttributeString( key, value ); + } + + public override void SetDateTime( string key, DateTime value ) + { + if ( value != DateTime.MinValue ) + m_Xml.WriteAttributeString( key, XmlConvert.ToString( value, XmlDateTimeSerializationMode.Local ) ); + } + + public override void BeginObject( PersistableType typeID ) + { + m_Xml.WriteStartElement( typeID.Name ); + } + + public override void BeginChildren() + { + } + + public override void FinishChildren() + { + } + + public override void FinishObject() + { + m_Xml.WriteEndElement(); + } + + public override void WriteDocument( PersistableObject root ) + { + Console.WriteLine( "Reports: {0}: Save started", m_Title ); + + m_Xml.Formatting = Formatting.Indented; + m_Xml.IndentChar = '\t'; + m_Xml.Indentation = 1; + + m_Xml.WriteStartDocument( true ); + + root.Serialize( this ); + + Console.WriteLine( "Reports: {0}: Save complete", m_Title ); + } + + public override void Close() + { + m_Xml.Close(); + m_Writer.Close(); + + try + { + string renamed = null; + + if ( File.Exists( m_RealFilePath ) ) + { + renamed = Path.ChangeExtension( m_RealFilePath, ".rem" ); + File.Move( m_RealFilePath, renamed ); + File.Move( m_TempFilePath, m_RealFilePath ); + File.Delete( renamed ); + } + else + { + File.Move( m_TempFilePath, m_RealFilePath ); + } + } + catch ( Exception ex ) + { + Console.WriteLine( ex ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs b/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs new file mode 100644 index 0000000..01ba58c --- /dev/null +++ b/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs @@ -0,0 +1,923 @@ +using System; +using System.Drawing; +using System.Collections; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; + +namespace Server.Engines.Reports +{ + // Modified from MS sample + + //********************************************************************* + // + // BarGraph Class + // + // This class uses GDI+ to render Bar Chart. + // + //********************************************************************* + + public class BarRegion + { + public int m_RangeFrom, m_RangeTo; + public string m_Name; + + public BarRegion( int rangeFrom, int rangeTo, string name ) + { + m_RangeFrom = rangeFrom; + m_RangeTo = rangeTo; + m_Name = name; + } + } + + public class BarGraphRenderer : ChartRenderer + { + private const float _graphLegendSpacer = 15F; + private const float _labelFontSize = 7f; + private const int _legendFontSize = 9; + private const float _legendRectangleSize = 10F; + private const float _spacer = 5F; + + public BarRegion[] _regions; + + private BarGraphRenderMode _renderMode; + + // Overall related members + private Color _backColor; + private string _fontFamily; + private string _longestTickValue = string.Empty; // Used to calculate max value width + private float _maxTickValueWidth; // Used to calculate left offset of bar graph + private float _totalHeight; + private float _totalWidth; + + // Graph related members + private float _barWidth; + private float _bottomBuffer; // Space from bottom to x axis + private bool _displayBarData; + private Color _fontColor; + private float _graphHeight; + private float _graphWidth; + private float _maxValue = 0.0f; // = final tick value * tick count + private float _scaleFactor; // = _maxValue / _graphHeight + private float _spaceBtwBars; // For now same as _barWidth + private float _topBuffer; // Space from top to the top of y axis + private float _xOrigin; // x position where graph starts drawing + private float _yOrigin; // y position where graph starts drawing + private string _yLabel; + private int _yTickCount; + private float _yTickValue; // Value for each tick = _maxValue/_yTickCount + + // Legend related members + private bool _displayLegend; + private float _legendWidth; + private string _longestLabel = string.Empty; // Used to calculate legend width + private float _maxLabelWidth = 0.0f; + + public string FontFamily + { + get{ return _fontFamily; } + set{ _fontFamily = value; } + } + + public BarGraphRenderMode RenderMode + { + get{ return _renderMode; } + set{ _renderMode = value; } + } + + public Color BackgroundColor + { + set{ _backColor = value; } + } + + public int BottomBuffer + { + set { _bottomBuffer = Convert.ToSingle(value); } + } + + public Color FontColor + { + set{ _fontColor = value; } + } + + public int Height + { + get{ return Convert.ToInt32(_totalHeight); } + set{ _totalHeight = Convert.ToSingle(value); } + } + + public int Width + { + get{ return Convert.ToInt32(_totalWidth); } + set{ _totalWidth = Convert.ToSingle(value); } + } + + public bool ShowLegend + { + get{ return _displayLegend; } + set{ _displayLegend = value; } + } + + public bool ShowData + { + get{ return _displayBarData; } + set{ _displayBarData = value; } + } + public int TopBuffer + { + set { _topBuffer = Convert.ToSingle(value); } + } + + public string VerticalLabel + { + get{ return _yLabel; } + set{ _yLabel = value; } + } + + public int VerticalTickCount + { + get{ return _yTickCount; } + set{ _yTickCount = value; } + } + + private string _xTitle, _yTitle; + + public void SetTitles( string xTitle, string yTitle ) + { + _xTitle = xTitle; + _yTitle = yTitle; + } + + public BarGraphRenderer() + { + AssignDefaultSettings(); + } + + public BarGraphRenderer(Color bgColor) + { + AssignDefaultSettings(); + BackgroundColor = bgColor; + } + + //********************************************************************* + // + // This method collects all data points and calculate all the necessary dimensions + // to draw the bar graph. It is the method called before invoking the Draw() method. + // labels is the x values. + // values is the y values. + // + //********************************************************************* + + public void CollectDataPoints(string[] labels, string[] values) + { + if (labels.Length == values.Length) + { + for(int i=0; i _xOrigin+_graphWidth ) + rc.Width = _xOrigin+_graphWidth-rc.X; + + using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 48, GetColor( i ) ) ) ) + gfx.FillRectangle( brsh, rc ); + + rc.Offset( (rc.Width - 200.0f) * 0.5f, -16.0f ); + rc.Width = 200.0f; + rc.Height = 20.0f; + + gfx.DrawString( reg.m_Name, font, textBrush, rc, textFormat ); + } + } + } + } + } + } + } + + //********************************************************************* + // + // This method returns a bar graph bitmap to the calling function. It is called after + // all dimensions and data points are calculated. + // + //********************************************************************* + + public override Bitmap Draw() + { + int height = Convert.ToInt32(_totalHeight); + int width = Convert.ToInt32(_totalWidth); + + Bitmap bmp = new Bitmap(width, height); + + using(Graphics graph = Graphics.FromImage(bmp)) + { + graph.CompositingQuality = CompositingQuality.HighQuality; + graph.SmoothingMode = SmoothingMode.AntiAlias; + + using ( SolidBrush brsh = new SolidBrush( _backColor ) ) + graph.FillRectangle(brsh, -1, -1, bmp.Width+1, bmp.Height+1); + + DrawRegions(graph); + DrawVerticalLabelArea(graph); + DrawXLabelBack(graph); + DrawBars(graph); + DrawXLabelArea(graph); + + if (_displayLegend) + DrawLegend(graph); + } + + return bmp; + } + + //********************************************************************* + // + // This method draws all the bars for the graph. + // + //********************************************************************* + + public int _interval; + + private void DrawBars(Graphics graph) + { + SolidBrush brsFont = null; + Font valFont = null; + StringFormat sfFormat = null; + + try + { + brsFont = new SolidBrush(_fontColor); + valFont = new Font(_fontFamily, _labelFontSize); + sfFormat = new StringFormat(); + sfFormat.Alignment = StringAlignment.Center; + int i = 0; + + PointF[] linePoints = null; + + if ( _renderMode == BarGraphRenderMode.Lines ) + linePoints = new PointF[DataPoints.Count]; + + int pointIndex = 0; + + // Draw bars and the value above each bar + using ( Pen pen = new Pen(_fontColor,0.15f) ) + { + using ( SolidBrush whiteBrsh = new SolidBrush( Color.FromArgb( 128, Color.White ) ) ) + { + foreach(DataItem item in DataPoints) + { + using(SolidBrush barBrush = new SolidBrush(item.ItemColor)) + { + float itemY = _yOrigin + _graphHeight - item.SweepSize; + + if ( _renderMode == BarGraphRenderMode.Lines ) + { + linePoints[pointIndex++] = new PointF( _xOrigin + item.StartPos + (_barWidth / 2), itemY ); + } + else if ( _renderMode == BarGraphRenderMode.Bars ) + { + float ox = _xOrigin + item.StartPos; + float oy = itemY; + float ow = _barWidth; + float oh = item.SweepSize; + float of = 9.5f; + + PointF[] pts = new PointF[] + { + new PointF( ox, oy ), + new PointF( ox + ow, oy ), + new PointF( ox + of, oy + of ), + new PointF( ox + of + ow, oy + of ), + new PointF( ox, oy + oh ), + new PointF( ox + of, oy + of + oh ), + new PointF( ox + of + ow, oy + of + oh ) + }; + + graph.FillPolygon( barBrush, new PointF[]{ pts[2], pts[3], pts[6], pts[5] } ); + + using ( SolidBrush ltBrsh = new SolidBrush( System.Windows.Forms.ControlPaint.Light(item.ItemColor,0.1f) ) ) + graph.FillPolygon( ltBrsh, new PointF[]{ pts[0], pts[2], pts[5], pts[4] } ); + + using ( SolidBrush drkBrush = new SolidBrush( System.Windows.Forms.ControlPaint.Dark(item.ItemColor,0.05f) ) ) + graph.FillPolygon( drkBrush, new PointF[]{ pts[0], pts[1], pts[3], pts[2] } ); + + graph.DrawLine( pen, pts[0], pts[1] ); + graph.DrawLine( pen, pts[0], pts[2] ); + graph.DrawLine( pen, pts[1], pts[3] ); + graph.DrawLine( pen, pts[2], pts[3] ); + graph.DrawLine( pen, pts[2], pts[5] ); + graph.DrawLine( pen, pts[0], pts[4] ); + graph.DrawLine( pen, pts[4], pts[5] ); + graph.DrawLine( pen, pts[5], pts[6] ); + graph.DrawLine( pen, pts[3], pts[6] ); + + // Draw data value + if (_displayBarData&&(i%_interval)==0) + { + float sectionWidth = ( _barWidth + _spaceBtwBars ); + float startX = _xOrigin + (i * sectionWidth) + (sectionWidth / 2); // This draws the value on center of the bar + float startY = itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels + RectangleF recVal = new RectangleF(startX-((sectionWidth * _interval) / 2), startY, sectionWidth * _interval, valFont.Height); + SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"),valFont,recVal.Size,sfFormat); + //using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 180, 255, 255, 255 ) ) ) + // graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) ); + + //graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat); + + for ( int box = -1; box <= 1; ++box ) + { + for ( int boy = -1; boy <= 1; ++boy ) + { + if ( box == 0 && boy == 0 ) + continue; + + RectangleF rco = new RectangleF( recVal.X+box, recVal.Y+boy, recVal.Width, recVal.Height ); + graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco, sfFormat); + } + } + + graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat); + } + } + + i++; + } + } + + if ( _renderMode == BarGraphRenderMode.Lines ) + { + if ( linePoints.Length >= 2 ) + { + using ( Pen linePen = new Pen( Color.FromArgb(220,Color.Red), 2.5f ) ) + graph.DrawCurve( linePen, linePoints, 0.5f ); + } + + using ( Pen linePen = new Pen( Color.FromArgb(40,_fontColor), 0.8f ) ) + { + for ( int j = 0; j < linePoints.Length; ++j ) + { + graph.DrawLine( linePen, linePoints[j], new PointF( linePoints[j].X, _yOrigin + _graphHeight ) ); + + DataItem item = DataPoints[j]; + float itemY = _yOrigin + _graphHeight - item.SweepSize; + + // Draw data value + if (_displayBarData&&(j%_interval)==0) + { + graph.FillEllipse( brsFont, new RectangleF( linePoints[j].X-2.0f, linePoints[j].Y-2.0f, 4.0f, 4.0f ) ); + + float sectionWidth = ( _barWidth + _spaceBtwBars ); + float startX = _xOrigin + (j * sectionWidth) + (sectionWidth/2); // This draws the value on center of the bar + float startY = itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels + RectangleF recVal = new RectangleF(startX-((sectionWidth * _interval) / 2), startY, sectionWidth * _interval, valFont.Height); + SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"),valFont,recVal.Size,sfFormat); + //using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 48, 255, 255, 255 ) ) ) + // graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) ); + + for ( int box = -1; box <= 1; ++box ) + { + for ( int boy = -1; boy <= 1; ++boy ) + { + if ( box == 0 && boy == 0 ) + continue; + + RectangleF rco = new RectangleF( recVal.X+box, recVal.Y+boy, recVal.Width, recVal.Height ); + graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco, sfFormat); + } + } + + graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat); + } + } + } + } + } + } + } + finally + { + if (brsFont != null) brsFont.Dispose(); + if (valFont != null) valFont.Dispose(); + if (sfFormat != null) sfFormat.Dispose(); + } + } + + //********************************************************************* + // + // This method draws the y label, tick marks, tick values, and the y axis. + // + //********************************************************************* + + private void DrawVerticalLabelArea(Graphics graph) + { + Font lblFont = null; + SolidBrush brs = null; + StringFormat lblFormat = null; + Pen pen = null; + StringFormat sfVLabel = null; + + float fo = (_yTitle==null?0.0f:20.0f); + + try + { + brs = new SolidBrush(_fontColor); + lblFormat = new StringFormat(); + pen = new Pen(_fontColor); + + if ( _yTitle != null ) + { + sfVLabel = new StringFormat(); + sfVLabel.Alignment = StringAlignment.Center; + sfVLabel.LineAlignment = StringAlignment.Center; + sfVLabel.FormatFlags=StringFormatFlags.DirectionVertical; + + lblFont = new Font(_fontFamily, _labelFontSize+4.0f); + graph.DrawString(_yTitle,lblFont,brs,new RectangleF( 0.0f, _yOrigin, 20.0f, _graphHeight ), sfVLabel ); + lblFont.Dispose(); + } + + sfVLabel = new StringFormat(); + lblFormat.Alignment = StringAlignment.Far; + lblFormat.FormatFlags|=StringFormatFlags.NoClip; + + // Draw vertical label at the top of y-axis and place it in the middle top of y-axis + lblFont = new Font(_fontFamily, _labelFontSize+2.0f,FontStyle.Bold); + RectangleF recVLabel = new RectangleF(0, _yOrigin-2*_spacer-lblFont.Height, _xOrigin*2, lblFont.Height); + sfVLabel.Alignment = StringAlignment.Center; + sfVLabel.FormatFlags|=StringFormatFlags.NoClip; + //graph.DrawRectangle(Pens.Black,Rectangle.Truncate(recVLabel)); + graph.DrawString(_yLabel, lblFont, brs, recVLabel, sfVLabel); + lblFont.Dispose(); + + lblFont = new Font(_fontFamily, _labelFontSize); + // Draw all tick values and tick marks + using ( Pen smallPen = new Pen(Color.FromArgb(96,_fontColor),0.8f) ) + { + for (int i=0; i<_yTickCount; i++) + { + float currentY = _topBuffer + (i * _yTickValue/_scaleFactor); // Position for tick mark + float labelY = currentY-lblFont.Height/2; // Place label in the middle of tick + RectangleF lblRec = new RectangleF(_spacer+fo-6, labelY, _maxTickValueWidth, lblFont.Height); + + float currentTick = _maxValue - i*_yTickValue; // Calculate tick value from top to bottom + graph.DrawString(currentTick.ToString("#,###.##"), lblFont, brs, lblRec, lblFormat); // Draw tick value + graph.DrawLine(pen, _xOrigin, currentY, _xOrigin - 4.0f, currentY); // Draw tick mark + + graph.DrawLine(smallPen, _xOrigin, currentY, _xOrigin + _graphWidth, currentY ); + } + } + + // Draw y axis + graph.DrawLine(pen, _xOrigin, _yOrigin, _xOrigin, _yOrigin + _graphHeight); + } + finally + { + if (lblFont != null) lblFont.Dispose(); + if (brs != null) brs.Dispose(); + if (lblFormat != null) lblFormat.Dispose(); + if (pen != null) pen.Dispose(); + if (sfVLabel != null) sfVLabel.Dispose(); + } + } + + //********************************************************************* + // + // This method draws x axis and all x labels + // + //********************************************************************* + + private void DrawXLabelBack(Graphics graph) + { + Font lblFont = null; + SolidBrush brs = null; + StringFormat lblFormat = null; + Pen pen = null; + + try + { + lblFont = new Font(_fontFamily, _labelFontSize); + brs = new SolidBrush(_fontColor); + lblFormat = new StringFormat(); + pen = new Pen(_fontColor); + + lblFormat.Alignment = StringAlignment.Center; + + // Draw x axis + graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + _graphWidth, _yOrigin + _graphHeight ); + } + finally + { + if (lblFont != null) lblFont.Dispose(); + if (brs != null) brs.Dispose(); + if (lblFormat != null) lblFormat.Dispose(); + if (pen != null) pen.Dispose(); + } + } + + private void DrawXLabelArea(Graphics graph) + { + Font lblFont = null; + SolidBrush brs = null; + StringFormat lblFormat = null; + Pen pen = null; + + try + { + brs = new SolidBrush(_fontColor); + pen = new Pen(_fontColor); + + if ( _xTitle != null ) + { + lblFormat = new StringFormat(); + lblFormat.Alignment = StringAlignment.Center; + lblFormat.LineAlignment = StringAlignment.Center; + // sfVLabel.FormatFlags=StringFormatFlags.DirectionVertical; + + lblFont = new Font(_fontFamily, _labelFontSize+2.0f, FontStyle.Bold); + graph.DrawString(_xTitle,lblFont,brs,new RectangleF( _xOrigin, _yOrigin+_graphHeight+14.0f+(_renderMode==BarGraphRenderMode.Bars?10.0f:0.0f)+((DataPoints.Count/_interval)>24?16.0f:0.0f), _graphWidth, 20.0f ), lblFormat ); + } + + lblFont = new Font(_fontFamily, _labelFontSize); + lblFormat = new StringFormat(); + lblFormat.Alignment = StringAlignment.Center; + lblFormat.FormatFlags |= StringFormatFlags.NoClip; + lblFormat.Trimming = StringTrimming.None; + //lblFormat.FormatFlags |= StringFormatFlags.NoWrap; + + float of = 0.0f; + + if ( _renderMode == BarGraphRenderMode.Bars ) + { + of = 10.0f; + + // Draw x axis + graph.DrawLine( pen, _xOrigin + of, _yOrigin + _graphHeight + of, _xOrigin + _graphWidth + of, _yOrigin + _graphHeight + of ); + + graph.DrawLine( pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + of, _yOrigin + _graphHeight + of ); + graph.DrawLine( pen, _xOrigin + _graphWidth, _yOrigin + _graphHeight, _xOrigin + of + _graphWidth, _yOrigin + _graphHeight + of ); + } + + float currentX; + float currentY = _yOrigin + _graphHeight + 2.0f; // All x labels are drawn 2 pixels below x-axis + float labelWidth = _barWidth + _spaceBtwBars; // Fits exactly below the bar + int i = 0; + + // Draw x labels + foreach(DataItem item in DataPoints) + { + if((i%_interval)==0) + { + currentX = _xOrigin + (i * labelWidth)+of+(labelWidth/2); + RectangleF recLbl = new RectangleF(currentX-((labelWidth*_interval)/2), currentY+of, labelWidth*_interval, lblFont.Height*2); + string lblString = _displayLegend ? item.Label : item.Description; // Decide what to show: short or long + + graph.DrawString(lblString, lblFont, brs, recLbl, lblFormat); + } + i++; + } + } + finally + { + if (lblFont != null) lblFont.Dispose(); + if (brs != null) brs.Dispose(); + if (lblFormat != null) lblFormat.Dispose(); + if (pen != null) pen.Dispose(); + } + } + + //********************************************************************* + // + // This method determines where to place the legend box. + // It draws the legend border, legend description, and legend color code. + // + //********************************************************************* + + private void DrawLegend(Graphics graph) + { + Font lblFont = null; + SolidBrush brs = null; + StringFormat lblFormat = null; + Pen pen = null; + + try + { + lblFont = new Font(_fontFamily, _legendFontSize); + brs = new SolidBrush(_fontColor); + lblFormat = new StringFormat(); + pen = new Pen(_fontColor); + lblFormat.Alignment = StringAlignment.Near; + + // Calculate Legend drawing start point + float startX = _xOrigin + _graphWidth + _graphLegendSpacer; + float startY = _yOrigin; + + float xColorCode = startX + _spacer; + float xLegendText = xColorCode + _legendRectangleSize + _spacer; + float legendHeight = 0.0f; + for(int i=0; i _maxTickValueWidth ) + _maxTickValueWidth = measured; + } + + float leftOffset = _spacer + _maxTickValueWidth + (_yTitle == null ? 0.0f : 20.0f); + float rtOffset = 0.0f; + + if (_displayLegend) + { + _legendWidth = _spacer + _legendRectangleSize + _spacer + _maxLabelWidth + _spacer; + rtOffset = _graphLegendSpacer + _legendWidth + _spacer; + } + else + rtOffset = _spacer; // Make graph in the middle + + if ( _renderMode == BarGraphRenderMode.Bars ) + rtOffset += 10.0f; + + rtOffset+=10.0f; + + _graphHeight = _totalHeight - _topBuffer - _bottomBuffer - (_xTitle == null ? 0.0f : 20.0f); // Buffer spaces are used to print labels + _graphWidth = _totalWidth - leftOffset - rtOffset; + _xOrigin = leftOffset; + _yOrigin = _topBuffer; + + // Once the correct _maxValue is determined, then calculate _scaleFactor + _scaleFactor = _maxValue / _graphHeight; + } + + //********************************************************************* + // + // This method determines the longest tick value from the given data points. + // The result is needed to calculate the correct graph dimension. + // + //********************************************************************* + + private void FindLongestTickValue() + { + float currentTick; + string tickString; + for (int i=0; i<_yTickCount; i++) + { + currentTick = _maxValue - i*_yTickValue; + tickString = currentTick.ToString("#,###.##"); + if (_longestTickValue.Length < tickString.Length) + _longestTickValue = tickString; + } + } + + //********************************************************************* + // + // This method calculates the image width in pixel for a given text + // + //********************************************************************* + + private float CalculateImgFontWidth(string text, float size, string family) + { + Bitmap bmp = null; + Graphics graph = null; + Font font = null; + + try + { + font = new Font(family, size); + + // Calculate the size of the string. + bmp = new Bitmap(1,1,PixelFormat.Format32bppArgb); + graph = Graphics.FromImage(bmp); + SizeF oSize = graph.MeasureString(text, font); + oSize.Width=4+(float)Math.Ceiling(oSize.Width); + + return oSize.Width; + } + finally + { + if (graph != null) graph.Dispose(); + if (bmp != null) bmp.Dispose(); + if (font != null) font.Dispose(); + } + } + + //********************************************************************* + // + // This method creates abbreviation from long description; used for making legend + // + //********************************************************************* + + private string MakeShortLabel(string text) + { + string label = text; + if (text.Length > 2) + { + int midPostition = Convert.ToInt32(Math.Floor(text.Length/2.0)); + label = text.Substring(0,1) + text.Substring(midPostition, 1) + text.Substring(text.Length-1,1); + } + return label; + } + + //********************************************************************* + // + // This method calculates the max value and each tick mark value for the bar graph. + // + //********************************************************************* + + private void CalculateTickAndMax() + { + float tempMax = 0.0f; + + // Give graph some head room first about 10% of current max + _maxValue *= 1.1f; + + if (_maxValue != 0.0f) + { + // Find a rounded value nearest to the current max value + // Calculate this max first to give enough space to draw value on each bar + double exp = Convert.ToDouble(Math.Floor(Math.Log10(_maxValue))); + tempMax = Convert.ToSingle(Math.Ceiling(_maxValue / Math.Pow(10, exp)) * Math.Pow(10, exp)); + } + else + tempMax = 1.0f; + + // Once max value is calculated, tick value can be determined; tick value should be a whole number + _yTickValue = tempMax / _yTickCount; + double expTick = Convert.ToDouble(Math.Floor(Math.Log10(_yTickValue))); + _yTickValue = Convert.ToSingle(Math.Ceiling(_yTickValue / Math.Pow(10, expTick)) * Math.Pow(10, expTick)); + + // Re-calculate the max value with the new tick value + _maxValue = _yTickValue * _yTickCount; + } + + //********************************************************************* + // + // This method calculates the height for each bar in the graph + // + //********************************************************************* + + private void CalculateSweepValues() + { + // Called when all values and scale factor are known + // All values calculated here are relative from (_xOrigin, _yOrigin) + int i = 0; + foreach(DataItem item in DataPoints) + { + // This implementation does not support negative value + if (item.Value >= 0) item.SweepSize = item.Value/_scaleFactor; + + // (_spaceBtwBars/2) makes half white space for the first bar + item.StartPos = (_spaceBtwBars/2) + i * (_barWidth+_spaceBtwBars); + i++; + } + } + + //********************************************************************* + // + // This method calculates the width for each bar in the graph + // + //********************************************************************* + + private void CalculateBarWidth(int dataCount, float barGraphWidth) + { + // White space between each bar is the same as bar width itself + _barWidth = barGraphWidth / (dataCount * 2); // Each bar has 1 white space + //_barWidth =/* (float)Math.Floor(*/_barWidth/*)*/; + _spaceBtwBars = _barWidth; + } + + //********************************************************************* + // + // This method assigns default value to the bar graph properties and is only + // called from BarGraph constructors + // + //********************************************************************* + + private void AssignDefaultSettings() + { + // default values + _totalWidth = 680f; + _totalHeight = 450f; + _fontFamily = "Verdana"; + _backColor = Color.White; + _fontColor = Color.Black; + _topBuffer = 30f; + _bottomBuffer = 30f; + _yTickCount = 2; + _displayLegend = false; + _displayBarData = false; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/ChartRenderer.cs b/Scripts/Engines/Reports/Rendering/ChartRenderer.cs new file mode 100644 index 0000000..a353cb2 --- /dev/null +++ b/Scripts/Engines/Reports/Rendering/ChartRenderer.cs @@ -0,0 +1,71 @@ +using System; +using System.Drawing; +using System.Collections; + +namespace Server.Engines.Reports +{ + //********************************************************************* + // + // Chart Class + // + // Base class implementation for BarChart and PieChart + // + //********************************************************************* + + public abstract class ChartRenderer + { + private const int _colorLimit = 9; + + private Color[] _color = + { + Color.Firebrick, + Color.SkyBlue, + Color.MediumSeaGreen, + Color.MediumOrchid, + Color.Chocolate, + Color.SlateBlue, + Color.LightPink, + Color.LightGreen, + Color.Khaki + }; + + // Represent collection of all data points for the chart + private ChartItemsCollection _dataPoints = new ChartItemsCollection(); + + // The implementation of this method is provided by derived classes + public abstract Bitmap Draw(); + + public ChartItemsCollection DataPoints + { + get{ return _dataPoints; } + set{ _dataPoints = value; } + } + + public void SetColor(int index, Color NewColor) + { + if (index < _colorLimit) + { + _color[index] = NewColor; + } + else + { + throw new Exception("Color Limit is " + _colorLimit); + } + } + + public Color GetColor(int index) + { + //return _color[index%_colorLimit]; + + if (index < _colorLimit) + { + return _color[index]; + } + else + { + return _color[(index+2)%_colorLimit]; + //throw new Exception("Color Limit is " + _colorLimit); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/DataItem.cs b/Scripts/Engines/Reports/Rendering/DataItem.cs new file mode 100644 index 0000000..98e5a52 --- /dev/null +++ b/Scripts/Engines/Reports/Rendering/DataItem.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.Drawing; + +namespace Server.Engines.Reports +{ + // Modified from MS sample + + //********************************************************************* + // + // ChartItem Class + // + // This class represents a data point in a chart + // + //********************************************************************* + + public class DataItem + { + private string _label; + private string _description; + private float _value; + private Color _color; + private float _startPos; + private float _sweepSize; + + private DataItem() {} + + public DataItem(string label, string desc, float data, float start, float sweep, Color clr) + { + _label = label; + _description = desc; + _value = data; + _startPos = start; + _sweepSize = sweep; + _color = clr; + } + + public string Label + { + get{ return _label; } + set{ _label = value; } + } + + public string Description + { + get{ return _description; } + set{ _description = value; } + } + + public float Value + { + get{ return _value; } + set{ _value = value; } + } + + public Color ItemColor + { + get{ return _color; } + set{ _color = value; } + } + + public float StartPos + { + get{ return _startPos; } + set{ _startPos = value; } + } + + public float SweepSize + { + get{ return _sweepSize; } + set{ _sweepSize = value; } + } + } + + //********************************************************************* + // + // Custom Collection for ChartItems + // + //********************************************************************* + + public class ChartItemsCollection : CollectionBase + { + public DataItem this[int index] + { + get{ return (DataItem)(List[index]); } + set{ List[index] = value; } + } + + public int Add(DataItem value) + { + return List.Add(value); + } + + public int IndexOf(DataItem value) + { + return List.IndexOf(value); + } + + public bool Contains(DataItem value) + { + return List.Contains(value); + } + + public void Remove(DataItem value) + { + List.Remove(value); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/HtmlRenderer.cs b/Scripts/Engines/Reports/Rendering/HtmlRenderer.cs new file mode 100644 index 0000000..0367096 --- /dev/null +++ b/Scripts/Engines/Reports/Rendering/HtmlRenderer.cs @@ -0,0 +1,544 @@ +using System; +using System.IO; +using System.Web; +using System.Web.UI; +using System.Net; +using System.Drawing; +using System.Drawing.Imaging; +using System.Collections; +using System.Diagnostics; +using HtmlTag = System.Web.UI.HtmlTextWriterTag; +using HtmlAttr = System.Web.UI.HtmlTextWriterAttribute; + +namespace Server.Engines.Reports +{ + public class HtmlRenderer + { + private string m_Type; + private string m_Title; + private string m_OutputDirectory; + + private DateTime m_TimeStamp; + private ObjectCollection m_Objects; + + private HtmlRenderer( string outputDirectory ) + { + m_Type = outputDirectory; + m_Title = ( m_Type == "staff" ? "Staff" : "Stats" ); + m_OutputDirectory = Path.Combine( Core.BaseDirectory, "Reports" ); + + if ( !Directory.Exists( m_OutputDirectory ) ) + Directory.CreateDirectory( m_OutputDirectory ); + + m_OutputDirectory = Path.Combine( m_OutputDirectory, outputDirectory ); + + if ( !Directory.Exists( m_OutputDirectory ) ) + Directory.CreateDirectory( m_OutputDirectory ); + } + + public HtmlRenderer( string outputDirectory, Snapshot ss, SnapshotHistory history ) : this( outputDirectory ) + { + m_TimeStamp = ss.TimeStamp; + + m_Objects = new ObjectCollection(); + + for ( int i = 0; i < ss.Children.Count; ++i ) + m_Objects.Add( ss.Children[i] ); + + m_Objects.Add( BarGraph.OverTime( history, "General Stats", "Clients", 1, 100, 6 ) ); + m_Objects.Add( BarGraph.OverTime( history, "General Stats", "Items", 24, 9, 1 ) ); + m_Objects.Add( BarGraph.OverTime( history, "General Stats", "Players", 24, 9, 1 ) ); + m_Objects.Add( BarGraph.OverTime( history, "General Stats", "NPCs", 24, 9, 1 ) ); + m_Objects.Add( BarGraph.DailyAverage( history, "General Stats", "Clients" ) ); + m_Objects.Add( BarGraph.Growth( history, "General Stats", "Clients" ) ); + } + + public HtmlRenderer( string outputDirectory, StaffHistory history ) : this( outputDirectory ) + { + m_TimeStamp = DateTime.Now; + + m_Objects = new ObjectCollection(); + + history.Render( m_Objects ); + } + + public void Render() + { + Console.WriteLine( "Reports: {0}: Render started", m_Title ); + + RenderFull(); + + for ( int i = 0; i < m_Objects.Count; ++i ) + RenderSingle( m_Objects[i] ); + + Console.WriteLine( "Reports: {0}: Render complete", m_Title ); + } + + private static readonly string FtpHost = null; + + private static readonly string FtpUsername = null; + private static readonly string FtpPassword = null; + + private static readonly string FtpStatsDirectory = null; + private static readonly string FtpStaffDirectory = null; + + public void Upload() + { + if ( FtpHost == null ) + return; + + Console.WriteLine( "Reports: {0}: Upload started", m_Title ); + + string filePath = Path.Combine( m_OutputDirectory, "upload.ftp" ); + + using ( StreamWriter op = new StreamWriter( filePath ) ) + { + op.WriteLine( "open \"{0}\"", FtpHost ); + op.WriteLine( FtpUsername ); + op.WriteLine( FtpPassword ); + op.WriteLine( "cd \"{0}\"", ( m_Type == "staff" ? FtpStaffDirectory : FtpStatsDirectory ) ); + op.WriteLine( "mput \"{0}\"", Path.Combine( m_OutputDirectory, "*.html" ) ); + op.WriteLine( "mput \"{0}\"", Path.Combine( m_OutputDirectory, "*.css" ) ); + op.WriteLine( "binary" ); + op.WriteLine( "mput \"{0}\"", Path.Combine( m_OutputDirectory, "*.png" ) ); + op.WriteLine( "disconnect" ); + op.Write( "quit" ); + } + + ProcessStartInfo psi = new ProcessStartInfo(); + + psi.FileName = "ftp"; + psi.Arguments = String.Format( "-i -s:\"{0}\"", filePath ); + + psi.CreateNoWindow = true; + psi.WindowStyle = ProcessWindowStyle.Hidden; + //psi.UseShellExecute = true; + + try + { + Process p = Process.Start( psi ); + + p.WaitForExit(); + } + catch + { + } + + Console.WriteLine( "Reports: {0}: Upload complete", m_Title ); + + try{ File.Delete( filePath ); } + catch{} + } + + public void RenderFull() + { + string filePath = Path.Combine( m_OutputDirectory, "reports.html" ); + + using ( StreamWriter op = new StreamWriter( filePath ) ) + { + using ( HtmlTextWriter html = new HtmlTextWriter( op, "\t" ) ) + RenderFull( html ); + } + + string cssPath = Path.Combine( m_OutputDirectory, "styles.css" ); + + if ( File.Exists( cssPath ) ) + return; + + using ( StreamWriter css = new StreamWriter( cssPath ) ) + { + css.WriteLine( "body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }" ); + css.WriteLine( "a { color: #28435E; }" ); + css.WriteLine( "a:hover { color: #4878A9; }" ); + css.WriteLine( "td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }" ); + css.WriteLine( "td.lentry { background-color: #D7D7EB; width: 10%; }" ); + css.WriteLine( "td.rentry { background-color: #FFFFFF; width: 90%; }" ); + css.WriteLine( "td.entry { background-color: #FFFFFF; }" ); + css.WriteLine( "td { font-size: 11px; }" ); + css.Write ( ".tbl-border { background-color: #46465A; }" ); + } + } + + private const string ShardTitle = "Shard"; + + public void RenderFull( HtmlTextWriter html ) + { + html.RenderBeginTag( HtmlTag.Html ); + + html.RenderBeginTag( HtmlTag.Head ); + + html.RenderBeginTag( HtmlTag.Title ); + html.Write( "{0} Statistics", ShardTitle ); + html.RenderEndTag(); + + html.AddAttribute( "rel", "stylesheet" ); + html.AddAttribute( HtmlAttr.Type, "text/css" ); + html.AddAttribute( HtmlAttr.Href, "styles.css" ); + html.RenderBeginTag( HtmlTag.Link ); + html.RenderEndTag(); + + html.RenderEndTag(); + + html.RenderBeginTag( HtmlTag.Body ); + + for ( int i = 0; i < m_Objects.Count; ++i ) + { + RenderDirect( m_Objects[i], html ); + html.Write( "

" ); + } + + html.RenderBeginTag( HtmlTag.Center ); + TimeZone tz = TimeZone.CurrentTimeZone; + bool isDaylight = tz.IsDaylightSavingTime( m_TimeStamp ); + TimeSpan utcOffset = tz.GetUtcOffset( m_TimeStamp ); + + html.Write( "Snapshot taken at {0:d} {0:t}. All times are {1}.", m_TimeStamp, tz.StandardName ); + html.RenderEndTag(); + + html.RenderEndTag(); + + html.RenderEndTag(); + } + + public static string SafeFileName( string name ) + { + return name.ToLower().Replace( ' ', '_' ); + } + + public void RenderSingle( PersistableObject obj ) + { + string filePath = Path.Combine( m_OutputDirectory, SafeFileName( FindNameFrom( obj ) ) + ".html" ); + + using ( StreamWriter op = new StreamWriter( filePath ) ) + { + using ( HtmlTextWriter html = new HtmlTextWriter( op, "\t" ) ) + RenderSingle( obj, html ); + } + } + + private string FindNameFrom( PersistableObject obj ) + { + if ( obj is Report ) + return (obj as Report).Name; + else if ( obj is Chart ) + return (obj as Chart).Name; + + return "Invalid"; + } + + public void RenderSingle( PersistableObject obj, HtmlTextWriter html ) + { + html.RenderBeginTag( HtmlTag.Html ); + + html.RenderBeginTag( HtmlTag.Head ); + + html.RenderBeginTag( HtmlTag.Title ); + html.Write( "{0} Statistics - {1}", ShardTitle, FindNameFrom( obj ) ); + html.RenderEndTag(); + + html.AddAttribute( "rel", "stylesheet" ); + html.AddAttribute( HtmlAttr.Type, "text/css" ); + html.AddAttribute( HtmlAttr.Href, "styles.css" ); + html.RenderBeginTag( HtmlTag.Link ); + html.RenderEndTag(); + + html.RenderEndTag(); + + html.RenderBeginTag( HtmlTag.Body ); + + html.RenderBeginTag( HtmlTag.Center ); + + RenderDirect( obj, html ); + + html.Write( "
" ); + + TimeZone tz = TimeZone.CurrentTimeZone; + bool isDaylight = tz.IsDaylightSavingTime( m_TimeStamp ); + TimeSpan utcOffset = tz.GetUtcOffset( m_TimeStamp ); + + html.Write( "Snapshot taken at {0:d} {0:t}. All times are {1}.", m_TimeStamp, tz.StandardName ); + html.RenderEndTag(); + + html.RenderEndTag(); + + html.RenderEndTag(); + } + + public void RenderDirect( PersistableObject obj, HtmlTextWriter html ) + { + if ( obj is Report ) + RenderReport( obj as Report, html ); + else if ( obj is BarGraph ) + RenderBarGraph( obj as BarGraph, html ); + else if ( obj is PieChart ) + RenderPieChart( obj as PieChart, html ); + } + + private void RenderPieChart( PieChart chart, HtmlTextWriter html ) + { + PieChartRenderer pieChart = new PieChartRenderer( Color.White ); + + pieChart.ShowPercents = chart.ShowPercents; + + string[] labels = new string[chart.Items.Count]; + string[] values = new string[chart.Items.Count]; + + for ( int i = 0; i < chart.Items.Count; ++i ) + { + ChartItem item = chart.Items[i]; + + labels[i] = item.Name; + values[i] = item.Value.ToString(); + } + + pieChart.CollectDataPoints( labels, values ); + + Bitmap bmp = pieChart.Draw(); + + string fileName = chart.FileName + ".png"; + bmp.Save( Path.Combine( m_OutputDirectory, fileName ), ImageFormat.Png ); + + html.Write( "" ); + + html.AddAttribute( HtmlAttr.Cellpadding, "0" ); + html.AddAttribute( HtmlAttr.Cellspacing, "0" ); + html.AddAttribute( HtmlAttr.Border, "0" ); + html.RenderBeginTag( HtmlTag.Table ); + + html.RenderBeginTag( HtmlTag.Tr ); + html.AddAttribute( HtmlAttr.Class, "tbl-border" ); + html.RenderBeginTag( HtmlTag.Td ); + + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Cellpadding, "4" ); + html.AddAttribute( HtmlAttr.Cellspacing, "1" ); + html.RenderBeginTag( HtmlTag.Table ); + + html.RenderBeginTag( HtmlTag.Tr ); + + html.AddAttribute( HtmlAttr.Colspan, "10" ); + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Align, "center" ); + html.AddAttribute( HtmlAttr.Class, "header" ); + html.RenderBeginTag( HtmlTag.Td ); + html.Write( chart.Name ); + html.RenderEndTag(); + html.RenderEndTag(); + + html.RenderBeginTag( HtmlTag.Tr ); + + html.AddAttribute( HtmlAttr.Colspan, "10" ); + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Align, "center" ); + html.AddAttribute( HtmlAttr.Class, "entry" ); + html.RenderBeginTag( HtmlTag.Td ); + + html.AddAttribute( HtmlAttr.Width, bmp.Width.ToString() ); + html.AddAttribute( HtmlAttr.Height, bmp.Height.ToString() ); + html.AddAttribute( HtmlAttr.Src, fileName ); + html.RenderBeginTag( HtmlTag.Img ); + html.RenderEndTag(); + + html.RenderEndTag(); + html.RenderEndTag(); + + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + + bmp.Dispose(); + } + + private void RenderBarGraph( BarGraph graph, HtmlTextWriter html ) + { + BarGraphRenderer barGraph = new BarGraphRenderer( Color.Black ); // Scriptiz : Default = Color.White + barGraph.Width = 600; + barGraph.Height = 400; + + + barGraph.RenderMode = graph.RenderMode; + + barGraph._regions = graph.Regions; + barGraph.SetTitles( graph.xTitle, null ); + + if ( graph.yTitle != null ) + barGraph.VerticalLabel = graph.yTitle; + + barGraph.FontColor = Color.FromArgb(193, 193, 193); // Scriptiz : Default = Color.Black + barGraph.ShowData = ( graph.Interval == 1 ); + barGraph.VerticalTickCount = graph.Ticks; + + string[] labels = new string[graph.Items.Count]; + string[] values = new string[graph.Items.Count]; + + for ( int i = 0; i < graph.Items.Count; ++i ) + { + ChartItem item = graph.Items[i]; + + labels[i] = item.Name; + values[i] = item.Value.ToString(); + } + + barGraph._interval = graph.Interval; + barGraph.CollectDataPoints( labels, values ); + + Bitmap bmp = barGraph.Draw(); + + string fileName = graph.FileName + ".png"; + bmp.Save( Path.Combine( m_OutputDirectory, fileName ), ImageFormat.Png ); + + html.Write( "" ); + + html.AddAttribute( HtmlAttr.Cellpadding, "0" ); + html.AddAttribute( HtmlAttr.Cellspacing, "0" ); + html.AddAttribute( HtmlAttr.Border, "0" ); + html.RenderBeginTag( HtmlTag.Table ); + + html.RenderBeginTag( HtmlTag.Tr ); + html.AddAttribute( HtmlAttr.Class, "tbl-border" ); + html.RenderBeginTag( HtmlTag.Td ); + + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Cellpadding, "4" ); + html.AddAttribute( HtmlAttr.Cellspacing, "1" ); + html.RenderBeginTag( HtmlTag.Table ); + + html.RenderBeginTag( HtmlTag.Tr ); + + html.AddAttribute( HtmlAttr.Colspan, "10" ); + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Align, "center" ); + html.AddAttribute( HtmlAttr.Class, "header" ); + html.RenderBeginTag( HtmlTag.Td ); + html.Write( graph.Name ); + html.RenderEndTag(); + html.RenderEndTag(); + + html.RenderBeginTag( HtmlTag.Tr ); + + html.AddAttribute( HtmlAttr.Colspan, "10" ); + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Align, "center" ); + html.AddAttribute( HtmlAttr.Class, "entry" ); + html.RenderBeginTag( HtmlTag.Td ); + + html.AddAttribute( HtmlAttr.Width, bmp.Width.ToString() ); + html.AddAttribute( HtmlAttr.Height, bmp.Height.ToString() ); + html.AddAttribute( HtmlAttr.Src, fileName ); + html.RenderBeginTag( HtmlTag.Img ); + html.RenderEndTag(); + + html.RenderEndTag(); + html.RenderEndTag(); + + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + + bmp.Dispose(); + } + + private void RenderReport( Report report, HtmlTextWriter html ) + { + html.AddAttribute( HtmlAttr.Width, report.Width ); + html.AddAttribute( HtmlAttr.Cellpadding, "0" ); + html.AddAttribute( HtmlAttr.Cellspacing, "0" ); + html.AddAttribute( HtmlAttr.Border, "0" ); + html.RenderBeginTag( HtmlTag.Table ); + + html.RenderBeginTag( HtmlTag.Tr ); + html.AddAttribute( HtmlAttr.Class, "tbl-border" ); + html.RenderBeginTag( HtmlTag.Td ); + + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Cellpadding, "4" ); + html.AddAttribute( HtmlAttr.Cellspacing, "1" ); + html.RenderBeginTag( HtmlTag.Table ); + + html.RenderBeginTag( HtmlTag.Tr ); + html.AddAttribute( HtmlAttr.Colspan, "10" ); + html.AddAttribute( HtmlAttr.Width, "100%" ); + html.AddAttribute( HtmlAttr.Align, "center" ); + html.AddAttribute( HtmlAttr.Class, "header" ); + html.RenderBeginTag( HtmlTag.Td ); + html.Write( report.Name ); + html.RenderEndTag(); + html.RenderEndTag(); + + bool isNamed = false; + + for ( int i = 0; i < report.Columns.Count && !isNamed; ++i ) + isNamed = ( report.Columns[i].Name != null ); + + if ( isNamed ) + { + html.RenderBeginTag( HtmlTag.Tr ); + + for ( int i = 0; i < report.Columns.Count; ++i ) + { + ReportColumn column = report.Columns[i]; + + html.AddAttribute( HtmlAttr.Class, "header" ); + html.AddAttribute( HtmlAttr.Width, column.Width ); + html.AddAttribute( HtmlAttr.Align, column.Align ); + html.RenderBeginTag( HtmlTag.Td ); + + html.Write( column.Name ); + + html.RenderEndTag(); + } + + html.RenderEndTag(); + } + + for ( int i = 0; i < report.Items.Count; ++i ) + { + ReportItem item = report.Items[i]; + + html.RenderBeginTag( HtmlTag.Tr ); + + for ( int j = 0; j < item.Values.Count; ++j ) + { + if ( !isNamed && j == 0 ) + html.AddAttribute( HtmlAttr.Width, report.Columns[j].Width ); + + html.AddAttribute( HtmlAttr.Align, report.Columns[j].Align ); + html.AddAttribute( HtmlAttr.Class, "entry" ); + html.RenderBeginTag( HtmlTag.Td ); + + if ( item.Values[j].Format == null ) + html.Write( item.Values[j].Value ); + else + html.Write( int.Parse( item.Values[j].Value ).ToString( item.Values[j].Format ) ); + + html.RenderEndTag(); + } + + html.RenderEndTag(); + } + + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + html.RenderEndTag(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Rendering/PieChartRenderer.cs b/Scripts/Engines/Reports/Rendering/PieChartRenderer.cs new file mode 100644 index 0000000..580f4cf --- /dev/null +++ b/Scripts/Engines/Reports/Rendering/PieChartRenderer.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; + +namespace Server.Engines.Reports +{ + // Modified from MS sample + + //********************************************************************* + // + // PieChart Class + // + // This class uses GDI+ to render Pie Chart. + // + //********************************************************************* + + public class PieChartRenderer : ChartRenderer + { + private const int _bufferSpace = 125; + private ArrayList _chartItems; + private int _perimeter; + private Color _backgroundColor; + private Color _borderColor; + private float _total; + private int _legendWidth; + private int _legendHeight; + private int _legendFontHeight; + private string _legendFontStyle; + private float _legendFontSize; + private bool _showPercents; + + public bool ShowPercents{ get{ return _showPercents; } set{ _showPercents = value; } } + + public PieChartRenderer() + { + _chartItems = new ArrayList(); + _perimeter = 250; + _backgroundColor = Color.White; + _borderColor = Color.FromArgb(63,63,63); + _legendFontSize = 8; + _legendFontStyle = "Verdana"; + } + + public PieChartRenderer(Color bgColor) + { + _chartItems = new ArrayList(); + _perimeter = 250; + _backgroundColor = bgColor; + _borderColor = Color.FromArgb(63,63,63); + _legendFontSize = 8; + _legendFontStyle = "Verdana"; + } + + //********************************************************************* + // + // This method collects all data points and calculate all the necessary dimensions + // to draw the chart. It is the first method called before invoking the Draw() method. + // + //********************************************************************* + + public void CollectDataPoints(string[] xValues, string[] yValues) + { + _total = 0.0f; + + for (int i = 0;i < xValues.Length;i++) + { + float ftemp = Convert.ToSingle(yValues[i]); + _chartItems.Add(new DataItem(xValues[i], xValues.ToString(), ftemp, 0, 0, Color.AliceBlue)); + _total += ftemp; + } + + float nextStartPos = 0.0f; + int counter = 0; + foreach (DataItem item in _chartItems) + { + item.StartPos = nextStartPos; + item.SweepSize = item.Value / _total * 360; + nextStartPos = item.StartPos + item.SweepSize; + item.ItemColor = GetColor(counter++); + } + + CalculateLegendWidthHeight(); + } + + //********************************************************************* + // + // This method returns a bitmap to the calling function. This is the method + // that actually draws the pie chart and the legend with it. + // + //********************************************************************* + + public override Bitmap Draw() + { + int perimeter = _perimeter; + Rectangle pieRect = new Rectangle(0, 0, perimeter, perimeter-1); + Bitmap bmp = new Bitmap(perimeter + _legendWidth, perimeter); + Font fnt = null; + Pen pen = null; + Graphics grp = null; + StringFormat sf = null, sfp = null; + + try + { + grp = Graphics.FromImage(bmp); + grp.CompositingQuality = CompositingQuality.HighQuality; + grp.SmoothingMode = SmoothingMode.AntiAlias; + sf = new StringFormat(); + + //Paint Back ground + using ( SolidBrush brsh = new SolidBrush( _backgroundColor ) ) + grp.FillRectangle(brsh, -1, -1, perimeter + _legendWidth+1, perimeter+1); + + //Align text to the right + sf.Alignment = StringAlignment.Far; + + //Draw all wedges and legends + for(int i=0; i<_chartItems.Count; i++) + { + DataItem item = (DataItem) _chartItems[i]; + SolidBrush brs = null; + try + { + brs = new SolidBrush(item.ItemColor); + grp.FillPie(brs, pieRect, item.StartPos, item.SweepSize); + + //grp.DrawPie(new Pen(_borderColor,1.2f),pieRect,item.StartPos,item.SweepSize); + + if ( fnt == null ) + fnt = new Font( _legendFontStyle, _legendFontSize ); + + if ( _showPercents && item.SweepSize > 10 ) + { + if ( sfp == null ) + { + sfp = new StringFormat(); + sfp.Alignment = StringAlignment.Center; + sfp.LineAlignment = StringAlignment.Center; + } + + float perc = (item.SweepSize * 100.0f) / 360.0f; + string percString = String.Format( "{0:F0}%", perc ); + + float px = pieRect.X+(pieRect.Width/2); + float py = pieRect.Y+(pieRect.Height/2); + + double angle = item.StartPos + (item.SweepSize/2); + double rads = (angle/180.0)*Math.PI; + + px += (float)(Math.Cos( rads ) * perimeter / 3); + py += (float)(Math.Sin( rads ) * perimeter / 3); + + grp.DrawString( percString, fnt, Brushes.Gray, + new RectangleF( px - 30 - 1, py - 20, 60, 40 ), sfp ); + + grp.DrawString( percString, fnt, Brushes.Gray, + new RectangleF( px - 30 + 1, py - 20, 60, 40 ), sfp ); + + grp.DrawString( percString, fnt, Brushes.Gray, + new RectangleF( px - 30, py - 20 - 1, 60, 40 ), sfp ); + + grp.DrawString( percString, fnt, Brushes.Gray, + new RectangleF( px - 30, py - 20 + 1, 60, 40 ), sfp ); + + + grp.DrawString( percString, fnt, Brushes.White, + new RectangleF( px - 30, py - 20, 60, 40 ), sfp ); + } + + if ( pen == null ) + pen = new Pen( _borderColor, 0.5f ); + + grp.FillRectangle(brs, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10); + grp.DrawRectangle(pen, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10); + + grp.DrawString(item.Label, fnt, + Brushes.Black, perimeter + _bufferSpace + 20, i * _legendFontHeight + 13); + + grp.DrawString(item.Value.ToString("#,###.##"), fnt, + Brushes.Black, perimeter + _bufferSpace + 200, i * _legendFontHeight + 13,sf); + } + finally + { + if (brs !=null) + brs.Dispose(); + } + } + + for(int i=0; i<_chartItems.Count; i++) + { + DataItem item = (DataItem) _chartItems[i]; + SolidBrush brs = null; + try + { + grp.DrawPie(new Pen(_borderColor,0.5f),pieRect,item.StartPos,item.SweepSize); + } + finally + { + if (brs !=null) + brs.Dispose(); + } + } + + //draws the border around Pie + using ( Pen pen2 = new Pen( _borderColor, 2 ) ) + grp.DrawEllipse(pen2, pieRect); + + //draw border around legend + using ( Pen pen1 = new Pen( _borderColor, 1 ) ) + grp.DrawRectangle(pen1, perimeter + _bufferSpace - 10, 10, 220, _chartItems.Count * _legendFontHeight + 25); + + //Draw Total under legend + using ( Font fntb = new Font( _legendFontStyle, _legendFontSize, FontStyle.Bold ) ) + { + grp.DrawString("Total", fntb, + Brushes.Black, perimeter + _bufferSpace + 30, (_chartItems.Count+1) * _legendFontHeight,sf); + grp.DrawString(_total.ToString("#,###.##"), fntb, + Brushes.Black, perimeter + _bufferSpace + 200, (_chartItems.Count+1) * _legendFontHeight,sf); + } + + grp.SmoothingMode = SmoothingMode.AntiAlias; + } + finally + { + if (sf != null) sf.Dispose(); + if (grp != null) grp.Dispose(); + if (sfp != null) sfp.Dispose(); + if (fnt != null) fnt.Dispose(); + if (pen != null) pen.Dispose(); + } + return bmp; + } + + //********************************************************************* + // + // This method calculates the space required to draw the chart legend. + // + //********************************************************************* + + private void CalculateLegendWidthHeight() + { + Font fontLegend = new Font(_legendFontStyle, _legendFontSize); + _legendFontHeight = fontLegend.Height+3; + _legendHeight = fontLegend.Height * (_chartItems.Count + 1); + if (_legendHeight > _perimeter) _perimeter = _legendHeight; + + _legendWidth = _perimeter + _bufferSpace; + fontLegend.Dispose(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Reports/Reports.cs b/Scripts/Engines/Reports/Reports.cs new file mode 100644 index 0000000..be58471 --- /dev/null +++ b/Scripts/Engines/Reports/Reports.cs @@ -0,0 +1,553 @@ +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Factions; +using Server.Accounting; +using Server.Engines.ConPVP; + +namespace Server.Engines.Reports +{ + public class Reports + { + public static bool Enabled = true; + + public static void Initialize() + { + if ( !Enabled ) + return; + + m_StatsHistory = new SnapshotHistory(); + m_StatsHistory.Load(); + + m_StaffHistory = new StaffHistory(); + m_StaffHistory.Load(); + + DateTime now = DateTime.Now; + + DateTime date = now.Date; + TimeSpan timeOfDay = now.TimeOfDay; + + m_GenerateTime = date + TimeSpan.FromHours( Math.Ceiling( timeOfDay.TotalHours ) ); + + Timer.DelayCall( TimeSpan.FromMinutes( 0.5 ), TimeSpan.FromMinutes( 0.5 ), new TimerCallback( CheckRegenerate ) ); + } + + private static DateTime m_GenerateTime; + + public static void CheckRegenerate() + { + if ( DateTime.Now < m_GenerateTime ) + return; + + Generate(); + m_GenerateTime += TimeSpan.FromHours( 1.0 ); + } + + private static SnapshotHistory m_StatsHistory; + private static StaffHistory m_StaffHistory; + + public static StaffHistory StaffHistory{ get{ return m_StaffHistory; } } + + public static void Generate() + { + Snapshot ss = new Snapshot(); + + ss.TimeStamp = DateTime.Now; + + FillSnapshot( ss ); + + m_StatsHistory.Snapshots.Add( ss ); + m_StaffHistory.QueueStats.Add( new QueueStatus( Engines.Help.PageQueue.List.Count ) ); + + ThreadPool.QueueUserWorkItem( new WaitCallback( UpdateOutput ), ss ); + } + + private static void UpdateOutput( object state ) + { + m_StatsHistory.Save(); + m_StaffHistory.Save(); + + HtmlRenderer renderer = new HtmlRenderer( "stats", (Snapshot) state, m_StatsHistory ); + renderer.Render(); + renderer.Upload(); + + renderer = new HtmlRenderer( "staff", m_StaffHistory ); + renderer.Render(); + renderer.Upload(); + } + + public static void FillSnapshot( Snapshot ss ) + { + ss.Children.Add(CompileGeneralStats()); + ss.Children.Add(CompilePCByDL()); + ss.Children.Add(CompileTop15()); + ss.Children.Add(CompileDislikedArenas()); + ss.Children.Add(CompileStatChart()); + + PersistableObject[] obs = CompileSkillReports(); + + for ( int i = 0; i < obs.Length; ++i ) + ss.Children.Add( obs[i] ); + + obs = CompileFactionReports(); + + for ( int i = 0; i < obs.Length; ++i ) + ss.Children.Add( obs[i] ); + } + + public static Report CompileGeneralStats() + { + Report report = new Report( "General Stats", "200" ); + + report.Columns.Add( "50%", "left" ); + report.Columns.Add( "50%", "left" ); + + int npcs = 0, players = 0; + + foreach ( Mobile mob in World.Mobiles.Values ) + { + if ( mob.Player ) + ++players; + else + ++npcs; + } + + report.Items.Add( "NPCs", npcs, "N0" ); + report.Items.Add( "Players", players, "N0" ); + report.Items.Add( "Clients", NetState.Instances.Count, "N0" ); + report.Items.Add( "Accounts", Accounts.Count, "N0" ); + report.Items.Add( "Items", World.Items.Count, "N0" ); + + return report; + } + + private static Chart CompilePCByDL() + { + BarGraph chart = new BarGraph("Player Count By Dueling Level", "graphs_pc_by_dl", 5, "Dueling Level", "Players", BarGraphRenderMode.Bars); + + int lastLevel = -1; + ChartItem lastItem = null; + + Ladder ladder = Ladder.Instance; + + if (ladder != null) + { + ArrayList entries = ladder.ToArrayList(); + + for (int i = entries.Count - 1; i >= 0; --i) + { + LadderEntry entry = (LadderEntry)entries[i]; + int level = Ladder.GetLevel(entry.Experience); + + if (lastItem == null || level != lastLevel) + { + chart.Items.Add(lastItem = new ChartItem(level.ToString(), 1)); + lastLevel = level; + } + else + { + lastItem.Value++; + } + } + } + + return chart; + } + + private static Report CompileTop15() + { + Report report = new Report("Top 15 Duelists", "80%"); + + report.Columns.Add("6%", "center", "Rank"); + report.Columns.Add("6%", "center", "Level"); + report.Columns.Add("6%", "center", "Guild"); + report.Columns.Add("70%", "left", "Name"); + report.Columns.Add("6%", "center", "Wins"); + report.Columns.Add("6%", "center", "Losses"); + + Ladder ladder = Ladder.Instance; + + if (ladder != null) + { + ArrayList entries = ladder.ToArrayList(); + + for (int i = 0; i < entries.Count && i < 15; ++i) + { + LadderEntry entry = (LadderEntry)entries[i]; + int level = Ladder.GetLevel(entry.Experience); + string guild = ""; + + if (entry.Mobile.Guild != null) + guild = entry.Mobile.Guild.Abbreviation; + + ReportItem item = new ReportItem(); + + item.Values.Add(LadderGump.Rank(entry.Index + 1)); + item.Values.Add(level.ToString(), "N0"); + item.Values.Add(guild); + item.Values.Add(entry.Mobile.Name); + item.Values.Add(entry.Wins.ToString(), "N0"); + item.Values.Add(entry.Losses.ToString(), "N0"); + + report.Items.Add(item); + } + } + + return report; + } + + private static Chart CompileDislikedArenas() + { + PieChart chart = new PieChart("Most Disliked Arenas", "graphs_arenas_disliked", false); + + Preferences prefs = Preferences.Instance; + + if (prefs != null) + { + List arenas = Arena.Arenas; + + for (int i = 0; i < arenas.Count; ++i) + { + Arena arena = arenas[i]; + + string name = arena.Name; + + if (name != null) + chart.Items.Add(name, 0); + } + + ArrayList entries = prefs.Entries; + + for (int i = 0; i < entries.Count; ++i) + { + PreferencesEntry entry = (PreferencesEntry)entries[i]; + ArrayList list = entry.Disliked; + + for (int j = 0; j < list.Count; ++j) + { + string disliked = (string)list[j]; + + for (int k = 0; k < chart.Items.Count; ++k) + { + ChartItem item = chart.Items[k]; + + if (item.Name == disliked) + { + ++item.Value; + break; + } + } + } + } + } + + return chart; + } + + public static Chart CompileStatChart() + { + PieChart chart = new PieChart( "Stat Distribution", "graphs_strdexint_distrib", true ); + + ChartItem strItem = new ChartItem( "Strength", 0 ); + ChartItem dexItem = new ChartItem( "Dexterity", 0 ); + ChartItem intItem = new ChartItem( "Intelligence", 0 ); + + foreach ( Mobile mob in World.Mobiles.Values ) + { + if ( mob.RawStatTotal == mob.StatCap && mob is PlayerMobile ) + { + strItem.Value += mob.RawStr; + dexItem.Value += mob.RawDex; + intItem.Value += mob.RawInt; + } + } + + chart.Items.Add( strItem ); + chart.Items.Add( dexItem ); + chart.Items.Add( intItem ); + + return chart; + } + + public class SkillDistribution : IComparable + { + public SkillInfo m_Skill; + public int m_NumberOfGMs; + + public SkillDistribution( SkillInfo skill ) + { + m_Skill = skill; + } + + public int CompareTo( object obj ) + { + return ( ((SkillDistribution)obj).m_NumberOfGMs - m_NumberOfGMs ); + } + } + + public static SkillDistribution[] GetSkillDistribution() + { + int skip = ( Core.ML ? 0 : Core.SE ? 1 : Core.AOS ? 3 : 6 ); + + SkillDistribution[] distribs = new SkillDistribution[SkillInfo.Table.Length - skip]; + + for ( int i = 0; i < distribs.Length; ++i ) + distribs[i] = new SkillDistribution( SkillInfo.Table[i] ); + + foreach ( Mobile mob in World.Mobiles.Values ) + { + if ( mob.SkillsTotal >= 1500 && mob.SkillsTotal <= 7200 && mob is PlayerMobile ) + { + Skills skills = mob.Skills; + + for ( int i = 0; i < skills.Length - skip; ++i ) + { + Skill skill = skills[i]; + + if ( skill.BaseFixedPoint >= 1000 ) + distribs[i].m_NumberOfGMs++; + } + } + } + + return distribs; + } + + public static PersistableObject[] CompileSkillReports() + { + SkillDistribution[] distribs = GetSkillDistribution(); + + Array.Sort( distribs ); + + return new PersistableObject[]{ CompileSkillChart( distribs ), CompileSkillReport( distribs ) }; + } + + public static Report CompileSkillReport( SkillDistribution[] distribs ) + { + Report report = new Report( "Skill Report", "300" ); + + report.Columns.Add( "70%", "left", "Name" ); + report.Columns.Add( "30%", "center", "GMs" ); + + for ( int i = 0; i < distribs.Length; ++i ) + report.Items.Add( distribs[i].m_Skill.Name, distribs[i].m_NumberOfGMs, "N0" ); + + return report; + } + + public static Chart CompileSkillChart( SkillDistribution[] distribs ) + { + PieChart chart = new PieChart( "GM Skill Distribution", "graphs_skill_distrib", true ); + + for ( int i = 0; i < 12; ++i ) + chart.Items.Add( distribs[i].m_Skill.Name, distribs[i].m_NumberOfGMs ); + + int rem = 0; + + for ( int i = 12; i < distribs.Length; ++i ) + rem += distribs[i].m_NumberOfGMs; + + chart.Items.Add( "Other", rem ); + + return chart; + } + + public static PersistableObject[] CompileFactionReports() + { + return new PersistableObject[]{ CompileFactionMembershipChart(), CompileFactionReport(), CompileFactionTownReport(), CompileSigilReport(), CompileFactionLeaderboard() }; + } + + public static Chart CompileFactionMembershipChart() + { + PieChart chart = new PieChart( "Faction Membership", "graphs_faction_membership", true ); + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + chart.Items.Add( factions[i].Definition.FriendlyName, factions[i].Members.Count ); + + return chart; + } + + public static Report CompileFactionLeaderboard() + { + Report report = new Report( "Faction Leaderboard", "60%" ); + + report.Columns.Add( "28%", "center", "Name" ); + report.Columns.Add( "28%", "center", "Faction" ); + report.Columns.Add( "28%", "center", "Office" ); + report.Columns.Add( "16%", "center", "Kill Points" ); + + ArrayList list = new ArrayList(); + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction faction = factions[i]; + + list.AddRange( faction.Members ); + } + + list.Sort(); + list.Reverse(); + + for ( int i = 0; i < list.Count && i < 15; ++i ) + { + PlayerState pl = (PlayerState)list[i]; + + string office; + + if ( pl.Faction.Commander == pl.Mobile ) + office = "Commanding Lord"; + else if ( pl.Finance != null ) + office = String.Format( "{0} Finance Minister", pl.Finance.Definition.FriendlyName ); + else if ( pl.Sheriff != null ) + office = String.Format( "{0} Sheriff", pl.Sheriff.Definition.FriendlyName ); + else + office = ""; + + ReportItem item = new ReportItem(); + + item.Values.Add( pl.Mobile.Name ); + item.Values.Add( pl.Faction.Definition.FriendlyName ); + item.Values.Add( office ); + item.Values.Add( pl.KillPoints.ToString(), "N0" ); + + report.Items.Add( item ); + } + + return report; + } + + public static Report CompileFactionReport() + { + Report report = new Report( "Faction Statistics", "80%" ); + + report.Columns.Add( "20%", "center", "Name" ); + report.Columns.Add( "20%", "center", "Commander" ); + report.Columns.Add( "15%", "center", "Members" ); + report.Columns.Add( "15%", "center", "Merchants" ); + report.Columns.Add( "15%", "center", "Kill Points" ); + report.Columns.Add( "15%", "center", "Silver" ); + + List factions = Faction.Factions; + + for ( int i = 0; i < factions.Count; ++i ) + { + Faction faction = factions[i]; + List members = faction.Members; + + int totalKillPoints = 0; + int totalMerchants = 0; + + for ( int j = 0; j < members.Count; ++j ) + { + totalKillPoints += members[j].KillPoints; + + if ( members[j].MerchantTitle != MerchantTitle.None ) + ++totalMerchants; + } + + ReportItem item = new ReportItem(); + + item.Values.Add( faction.Definition.FriendlyName ); + item.Values.Add( faction.Commander == null ? "" : faction.Commander.Name ); + item.Values.Add( faction.Members.Count.ToString(), "N0" ); + item.Values.Add( totalMerchants.ToString(), "N0" ); + item.Values.Add( totalKillPoints.ToString(), "N0" ); + item.Values.Add( faction.Silver.ToString(), "N0" ); + + report.Items.Add( item ); + } + + return report; + } + + public static Report CompileSigilReport() + { + Report report = new Report( "Faction Town Sigils", "50%" ); + + report.Columns.Add( "35%", "center", "Town" ); + report.Columns.Add( "35%", "center", "Controller" ); + report.Columns.Add( "30%", "center", "Capturable" ); + + List sigils = Sigil.Sigils; + + for ( int i = 0; i < sigils.Count; ++i ) + { + Sigil sigil = sigils[i]; + + string controller = "Unknown"; + + Mobile mob = sigil.RootParent as Mobile; + + if ( mob != null ) + { + Faction faction = Faction.Find( mob ); + + if ( faction != null ) + controller = faction.Definition.FriendlyName; + } + else if ( sigil.LastMonolith != null && sigil.LastMonolith.Faction != null ) + { + controller = sigil.LastMonolith.Faction.Definition.FriendlyName; + } + + ReportItem item = new ReportItem(); + + item.Values.Add( sigil.Town == null ? "" : sigil.Town.Definition.FriendlyName ); + item.Values.Add( controller ); + item.Values.Add( sigil.IsPurifying ? "No" : "Yes" ); + + report.Items.Add( item ); + } + + return report; + } + + public static Report CompileFactionTownReport() + { + Report report = new Report( "Faction Towns", "80%" ); + + report.Columns.Add( "20%", "center", "Name" ); + report.Columns.Add( "20%", "center", "Owner" ); + report.Columns.Add( "17%", "center", "Sheriff" ); + report.Columns.Add( "17%", "center", "Finance Minister" ); + report.Columns.Add( "13%", "center", "Silver" ); + report.Columns.Add( "13%", "center", "Prices" ); + + List towns = Town.Towns; + + for ( int i = 0; i < towns.Count; ++i ) + { + Town town = towns[i]; + + string prices = "Normal"; + + if ( town.Tax < 0 ) + prices = town.Tax.ToString() + "%"; + else if ( town.Tax > 0 ) + prices = "+" + town.Tax.ToString() + "%"; + + ReportItem item = new ReportItem(); + + item.Values.Add( town.Definition.FriendlyName ); + item.Values.Add( town.Owner == null ? "Neutral" : town.Owner.Definition.FriendlyName ); + item.Values.Add( town.Sheriff == null ? "" : town.Sheriff.Name ); + item.Values.Add( town.Finance == null ? "" : town.Finance.Name ); + item.Values.Add( town.Silver.ToString(), "N0" ); + item.Values.Add( prices ); + + report.Items.Add( item ); + } + + return report; + } + } +} diff --git a/Scripts/Engines/Spawner/ProximitySpawner.cs b/Scripts/Engines/Spawner/ProximitySpawner.cs new file mode 100644 index 0000000..3424de1 --- /dev/null +++ b/Scripts/Engines/Spawner/ProximitySpawner.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class ProximitySpawner : Spawner + { + private int m_TriggerRange; + private TextDefinition m_SpawnMessage; + private bool m_InstantFlag; + + [CommandProperty( AccessLevel.GameMaster )] + public int TriggerRange + { + get { return m_TriggerRange; } + set { m_TriggerRange = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TextDefinition SpawnMessage + { + get { return m_SpawnMessage; } + set { m_SpawnMessage = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool InstantFlag + { + get { return m_InstantFlag; } + set { m_InstantFlag = value; } + } + + [Constructable] + public ProximitySpawner() + { + } + + [Constructable] + public ProximitySpawner( string spawnName ) + : base( spawnName ) + { + } + + [Constructable] + public ProximitySpawner( int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnName ) + { + } + + [Constructable] + public ProximitySpawner( int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName, int triggerRange, string spawnMessage, bool instantFlag ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnName ) + { + m_TriggerRange = triggerRange; + m_SpawnMessage = TextDefinition.Parse( spawnMessage ); + m_InstantFlag = instantFlag; + } + + public ProximitySpawner( int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnNames ) + { + } + + public ProximitySpawner( int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames, int triggerRange, TextDefinition spawnMessage, bool instantFlag ) + : base( amount, minDelay, maxDelay, team, homeRange, spawnNames ) + { + m_TriggerRange = triggerRange; + m_SpawnMessage = spawnMessage; + m_InstantFlag = instantFlag; + } + + public override string DefaultName + { + get { return "Proximity Spawner"; } + } + + public override void DoTimer( TimeSpan delay ) + { + if ( !Running ) + return; + + End = DateTime.Now + delay; + } + + public override void Respawn() + { + RemoveSpawned(); + + End = DateTime.Now; + } + + public override void Spawn() + { + for ( int i = 0; i < SpawnNamesCount; ++i ) + { + for ( int j = 0; j < Count; ++j ) + Spawn( i ); + } + } + + public override bool CheckSpawnerFull() + { + return false; + } + + public override bool HandlesOnMovement { get { return true; } } + + public virtual bool ValidTrigger( Mobile m ) + { + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( !bc.Controlled && !bc.Summoned ) + return false; + } + else if ( !m.Player ) + { + return false; + } + + return ( m.Alive && !m.IsDeadBondedPet && m.CanBeDamaged() && !m.Hidden ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( !Running ) + return; + + if ( IsEmpty && End <= DateTime.Now && m.InRange( GetWorldLocation(), m_TriggerRange ) && m.Location != oldLocation && ValidTrigger( m ) ) + { + TextDefinition.SendMessageTo( m, m_SpawnMessage ); + + DoTimer(); + Spawn(); + + if ( m_InstantFlag ) + { + foreach ( ISpawnable spawned in Spawned ) + { + if ( spawned is Mobile ) + ((Mobile)spawned).Combatant = m; + } + } + } + } + + public ProximitySpawner( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_TriggerRange ); + TextDefinition.Serialize( writer, m_SpawnMessage ); + writer.Write( m_InstantFlag ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_TriggerRange = reader.ReadInt(); + m_SpawnMessage = TextDefinition.Deserialize( reader ); + m_InstantFlag = reader.ReadBool(); + } + } +} diff --git a/Scripts/Engines/Spawner/Spawner.cs b/Scripts/Engines/Spawner/Spawner.cs new file mode 100644 index 0000000..838ec3e --- /dev/null +++ b/Scripts/Engines/Spawner/Spawner.cs @@ -0,0 +1,1106 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using Server; +using Server.Commands; +using Server.Items; +using Server.Network; +using Server.Multis; +using CPA = Server.CommandPropertyAttribute; + +/* + UsesSpawnerHome true causes normal behavior, while false will + cause the spawner to set the mobile's home to be its spawn + location, thus, not walking back to the spawner. This will + create a less artificial feel to mobiles attempting to return + to their home location. + + Also, the spawn area and home range work together. If the + area is not set, they will behave pretty much like they + always have. If the area is set, the mobile will spawn within + that rectangle. If both are set, the spawn location will be + based on the rectangle and allow an additional # of tiles, + which is the home range. + + Also, since the home does not necessarily equate to the spawner + location any longer, a gettersetter was added to the + BaseCreature. +*/ + +namespace Server.Mobiles +{ + public class Spawner : Item, ISpawner + { + private int m_Team; + private int m_HomeRange; + private int m_WalkingRange; + private int m_Count; + private TimeSpan m_MinDelay; + private TimeSpan m_MaxDelay; + private List m_SpawnNames; + private List m_Spawned; + private DateTime m_End; + private InternalTimer m_Timer; + private bool m_Running; + private bool m_Group; + private WayPoint m_WayPoint; + private bool m_UsesSpawnerHome; + private Rectangle2D m_SpawnArea; + private bool m_IgnoreHousing; + private bool m_MobilesSeekHome; + + public bool IsFull { get { return (m_Spawned.Count >= m_Count); } } + public bool IsEmpty { get { return (m_Spawned.Count == 0); } } + + public List SpawnNames + { + get { return m_SpawnNames; } + set + { + m_SpawnNames = value; + if (m_SpawnNames.Count < 1) + Stop(); + + InvalidateProperties(); + } + } + + public List Spawned + { + get { return m_Spawned; } + } + + public virtual int SpawnNamesCount { get { return m_SpawnNames.Count; } } + + public override void OnAfterDuped(Item newItem) + { + Spawner s = newItem as Spawner; + + if (s == null) + return; + + s.m_SpawnNames = new List(m_SpawnNames); + s.m_Spawned = new List(); + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IgnoreHousing + { + get + { + return m_IgnoreHousing; + } + set + { + m_IgnoreHousing = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool MobilesSeekHome + { + get + { + return m_MobilesSeekHome; + } + set + { + m_MobilesSeekHome = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Rectangle2D SpawnArea + { + get + { + return m_SpawnArea; + } + set + { + m_SpawnArea = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Count + { + get { return m_Count; } + set { m_Count = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint WayPoint + { + get + { + return m_WayPoint; + } + set + { + m_WayPoint = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Running + { + get { return m_Running; } + set + { + if (value) + Start(); + else + Stop(); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool UsesSpawnerHome + { + get + { + return m_UsesSpawnerHome; + } + set + { + m_UsesSpawnerHome = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HomeRange + { + get { return m_HomeRange; } + set { m_HomeRange = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int WalkingRange + { + get { return m_WalkingRange; } + set { m_WalkingRange = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Team + { + get { return m_Team; } + set { m_Team = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MinDelay + { + get { return m_MinDelay; } + set { m_MinDelay = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MaxDelay + { + get { return m_MaxDelay; } + set { m_MaxDelay = value; InvalidateProperties(); } + } + + public DateTime End + { + get { return m_End; } + set { m_End = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSpawn + { + get + { + if (m_Running) + return m_End - DateTime.Now; + else + return TimeSpan.FromSeconds(0); + } + set + { + Start(); + DoTimer(value); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Group + { + get { return m_Group; } + set { m_Group = value; InvalidateProperties(); } + } + + [Constructable] + public Spawner() + : this(null) + { + } + + [Constructable] + public Spawner(string spawnName) + : this(1, 5, 10, 0, 4, spawnName) + { + } + + [Constructable] + public Spawner(int amount, int minDelay, int maxDelay, int team, int homeRange, string spawnName) + : this(amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), team, homeRange, spawnName) + { + } + + [Constructable] + public Spawner(int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, string spawnName) + : base(0x1f13) + { + List spawnNames = new List(); + + if (!String.IsNullOrEmpty(spawnName)) + spawnNames.Add(spawnName); + + InitSpawner(amount, minDelay, maxDelay, team, homeRange, spawnNames); + } + + public Spawner(int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames) + : base(0x1f13) + { + InitSpawner(amount, minDelay, maxDelay, team, homeRange, spawnNames); + } + + public override string DefaultName + { + get { return "Spawner"; } + } + + private void InitSpawner(int amount, TimeSpan minDelay, TimeSpan maxDelay, int team, int homeRange, List spawnNames) + { + Visible = false; + Movable = false; + m_Running = true; + m_Group = false; + m_MinDelay = minDelay; + m_MaxDelay = maxDelay; + m_Count = amount; + m_Team = team; + m_HomeRange = homeRange; + m_WalkingRange = -1; + m_SpawnNames = spawnNames; + m_Spawned = new List(); + DoTimer(TimeSpan.FromSeconds(1)); + } + + public Spawner(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel < AccessLevel.GameMaster) + return; + + SpawnerGump g = new SpawnerGump(this); + from.SendGump(g); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Running) + { + list.Add(1060742); // active + + list.Add(1060656, m_Count.ToString()); // amount to make: ~1_val~ + list.Add(1061169, m_HomeRange.ToString()); // range ~1_val~ + list.Add(1060658, "walking range\t{0}", m_WalkingRange); // ~1_val~: ~2_val~ + + list.Add(1060659, "group\t{0}", m_Group); // ~1_val~: ~2_val~ + list.Add(1060660, "team\t{0}", m_Team); // ~1_val~: ~2_val~ + list.Add(1060661, "speed\t{0} to {1}", m_MinDelay, m_MaxDelay); // ~1_val~: ~2_val~ + + if (m_SpawnNames.Count != 0) + list.Add(SpawnedStats()); + } + else + { + list.Add(1060743); // inactive + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Running) + LabelTo(from, "[Running]"); + else + LabelTo(from, "[Off]"); + } + + public void Start() + { + if (!m_Running) + { + if (SpawnNamesCount > 0) + { + m_Running = true; + DoTimer(); + } + } + } + + public void Stop() + { + if (m_Running) + { + if (m_Timer != null) + m_Timer.Stop(); + + m_Running = false; + } + } + + public static string ParseType(string s) + { + return s.Split(null, 2)[0]; + } + + public void Defrag() + { + bool removed = false; + + for (int i = 0; i < m_Spawned.Count; ++i) + { + ISpawnable e = m_Spawned[i]; + + bool toRemove = false; + + if (e is Item) + { + Item item = (Item)e; + + if (item.Deleted || item.Parent != null) + toRemove = true; + } + else if (e is Mobile) + { + Mobile m = (Mobile)e; + + if (m.Deleted) + { + toRemove = true; + } + else if (m is BaseCreature) + { + BaseCreature bc = (BaseCreature)m; + + if (bc.Controlled || bc.IsStabled) + { + toRemove = true; + } + } + } + + if (toRemove) + { + m_Spawned.RemoveAt(i); + --i; + removed = true; + } + } + + if (removed) + InvalidateProperties(); + } + + bool ISpawner.UnlinkOnTaming { get { return true; } } + + void ISpawner.Remove(ISpawnable spawn) + { + m_Spawned.Remove(spawn); + + InvalidateProperties(); + } + + public void OnTick() + { + DoTimer(); + + if (m_Group) + { + Defrag(); + + if (m_Spawned.Count == 0) + { + Respawn(); + } + else + { + return; + } + } + else + { + Spawn(); + } + } + + public virtual void Respawn() + { + RemoveSpawned(); + + for (int i = 0; i < m_Count; i++) + Spawn(); + } + + public virtual void Spawn() + { + if (SpawnNamesCount > 0) + Spawn(Utility.Random(SpawnNamesCount)); + } + + public void Spawn(string creatureName) + { + for (int i = 0; i < m_SpawnNames.Count; i++) + { + if (m_SpawnNames[i] == creatureName) + { + Spawn(i); + break; + } + } + } + + protected virtual ISpawnable CreateSpawnedObject(int index) + { + if (index >= m_SpawnNames.Count) + return null; + + Type type = ScriptCompiler.FindTypeByName(ParseType(m_SpawnNames[index])); + + if (type != null) + { + try + { + return Build(type, CommandSystem.Split(m_SpawnNames[index])); + } + catch + { + } + } + + return null; + } + + public static ISpawnable Build(Type type, string[] args) + { + bool isISpawnable = typeof(ISpawnable).IsAssignableFrom(type); + + if (!isISpawnable) + { + return null; + } + + Add.FixArgs(ref args); + + string[,] props = null; + + for (int i = 0; i < args.Length; ++i) + { + if (Insensitive.Equals(args[i], "set")) + { + int remains = args.Length - i - 1; + + if (remains >= 2) + { + props = new string[remains / 2, 2]; + + remains /= 2; + + for (int j = 0; j < remains; ++j) + { + props[j, 0] = args[i + (j * 2) + 1]; + props[j, 1] = args[i + (j * 2) + 2]; + } + + Add.FixSetString(ref args, i); + } + + break; + } + } + + PropertyInfo[] realProps = null; + + if (props != null) + { + realProps = new PropertyInfo[props.GetLength(0)]; + + PropertyInfo[] allProps = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + for (int i = 0; i < realProps.Length; ++i) + { + PropertyInfo thisProp = null; + + string propName = props[i, 0]; + + for (int j = 0; thisProp == null && j < allProps.Length; ++j) + { + if (Insensitive.Equals(propName, allProps[j].Name)) + thisProp = allProps[j]; + } + + if (thisProp != null) + { + CPA attr = Properties.GetCPA(thisProp); + + if (attr != null && AccessLevel.GameMaster >= attr.WriteLevel && thisProp.CanWrite && !attr.ReadOnly) + realProps[i] = thisProp; + } + } + } + + ConstructorInfo[] ctors = type.GetConstructors(); + + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + if (!Add.IsConstructable(ctor, AccessLevel.GameMaster)) + continue; + + ParameterInfo[] paramList = ctor.GetParameters(); + + if (args.Length == paramList.Length) + { + object[] paramValues = Add.ParseValues(paramList, args); + + if (paramValues == null) + continue; + + object built = ctor.Invoke(paramValues); + + if (built != null && realProps != null) + { + for (int j = 0; j < realProps.Length; ++j) + { + if (realProps[j] == null) + continue; + + string result = Properties.InternalSetValue(built, realProps[j], props[j, 1]); + } + } + + return (ISpawnable)built; + } + } + + return null; + } + + public Point3D HomeLocation { get { return this.Location; } } + + public virtual bool CheckSpawnerFull() + { + return (m_Spawned.Count >= m_Count); + } + + public void Spawn(int index) + { + Map map = Map; + + if (map == null || map == Map.Internal || SpawnNamesCount == 0 || index >= SpawnNamesCount || Parent != null) + return; + + Defrag(); + + if (CheckSpawnerFull()) + return; + + ISpawnable spawned = CreateSpawnedObject(index); + + if (spawned == null) + return; + + spawned.Spawner = this; + m_Spawned.Add(spawned); + + Point3D loc = (spawned is BaseVendor ? this.Location : GetSpawnPosition(spawned)); + + spawned.OnBeforeSpawn(loc, map); + spawned.MoveToWorld(loc, map); + spawned.OnAfterSpawn(); + + if (spawned is BaseCreature) + { + BaseCreature bc = (BaseCreature)spawned; + + if (m_WalkingRange >= 0) + bc.RangeHome = m_WalkingRange; + else + bc.RangeHome = m_HomeRange; + + bc.CurrentWayPoint = m_WayPoint; + + bc.SeeksHome = m_MobilesSeekHome; + + if (m_Team > 0) + bc.Team = m_Team; + + bc.Home = (m_UsesSpawnerHome) ? this.HomeLocation : bc.Location; + } + + InvalidateProperties(); + } + + public Point3D GetSpawnPosition() + { + return GetSpawnPosition(null); + } + + private int GetAdjustedLocation(int range, int side, int coord, int coord_this) + { + return (((coord > 0) ? coord : (coord_this - range)) + (Utility.Random(Math.Max((((range * 2) + 1) + side), 1)))); + } + + public Point3D GetSpawnPosition(ISpawnable spawned) + { + Map map = Map; + + if (map == null) + return Location; + + bool waterMob, waterOnlyMob; + + if (spawned is Mobile) + { + Mobile mob = (Mobile)spawned; + + waterMob = mob.CanSwim; + waterOnlyMob = (mob.CanSwim && mob.CantWalk); + } + else + { + waterMob = false; + waterOnlyMob = false; + } + + for (int i = 0; i < 10; ++i) + { + int x = GetAdjustedLocation(m_HomeRange, m_SpawnArea.Width, m_SpawnArea.X, X); + int y = GetAdjustedLocation(m_HomeRange, m_SpawnArea.Height, m_SpawnArea.Y, Y); + + int mapZ = map.GetAverageZ(x, y); + + if (m_IgnoreHousing || ((BaseHouse.FindHouseAt(new Point3D(x, y, mapZ), Map, 16) == null && + BaseHouse.FindHouseAt(new Point3D(x, y, this.Z), Map, 16) == null))) + { + if (waterMob) + { + if (IsValidWater(map, x, y, this.Z)) + return new Point3D(x, y, this.Z); + else if (IsValidWater(map, x, y, mapZ)) + return new Point3D(x, y, mapZ); + } + + if (!waterOnlyMob) + { + if (map.CanSpawnMobile(x, y, this.Z)) + return new Point3D(x, y, this.Z); + else if (map.CanSpawnMobile(x, y, mapZ)) + return new Point3D(x, y, mapZ); + } + } + } + + return this.Location; + } + + public static bool IsValidWater(Map map, int x, int y, int z) + { + if (!Region.Find(new Point3D(x, y, z), map).AllowSpawn() || !map.CanFit(x, y, z, 16, false, true, false)) + return false; + + LandTile landTile = map.Tiles.GetLandTile(x, y); + + if (landTile.Z == z && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Wet) != 0) + return true; + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y, true); + + for (int i = 0; i < staticTiles.Length; ++i) + { + StaticTile staticTile = staticTiles[i]; + + if (staticTile.Z == z && (TileData.ItemTable[staticTile.ID & TileData.MaxItemValue].Flags & TileFlag.Wet) != 0) + return true; + } + + return false; + } + + public void DoTimer() + { + if (!m_Running) + return; + + int minSeconds = (int)m_MinDelay.TotalSeconds; + int maxSeconds = (int)m_MaxDelay.TotalSeconds; + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)); + DoTimer(delay); + } + + public virtual void DoTimer(TimeSpan delay) + { + if (!m_Running) + return; + + m_End = DateTime.Now + delay; + + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = new InternalTimer(this, delay); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + private Spawner m_Spawner; + + public InternalTimer(Spawner spawner, TimeSpan delay) + : base(delay) + { + if (spawner.IsFull) + Priority = TimerPriority.FiveSeconds; + else + Priority = TimerPriority.OneSecond; + + m_Spawner = spawner; + } + + protected override void OnTick() + { + if (m_Spawner != null) + if (!m_Spawner.Deleted) + m_Spawner.OnTick(); + } + } + + public string SpawnedStats() + { + Defrag(); + + Dictionary counts = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (string entry in m_SpawnNames) + { + string name = ParseType(entry); + Type type = ScriptCompiler.FindTypeByName(name); + + if (type == null) + counts[name] = 0; + else + counts[type.Name] = 0; + } + + foreach (ISpawnable spawned in m_Spawned) + { + string name = spawned.GetType().Name; + + if (counts.ContainsKey(name)) + ++counts[name]; + else + counts[name] = 1; + } + + List names = new List(counts.Keys); + names.Sort(); + + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < names.Count; ++i) + result.AppendFormat("{0}{1}: {2}", (i == 0) ? "" : "
", names[i], counts[names[i]]); + + return result.ToString(); + } + + public int CountCreatures(string creatureName) + { + Defrag(); + + int count = 0; + + for (int i = 0; i < m_Spawned.Count; ++i) + if (Insensitive.Equals(creatureName, m_Spawned[i].GetType().Name)) + ++count; + + return count; + } + + public void RemoveSpawned(string creatureName) + { + Defrag(); + + for (int i = m_Spawned.Count - 1; i >= 0; --i) + { + IEntity e = m_Spawned[i]; + + if (Insensitive.Equals(creatureName, e.GetType().Name)) + e.Delete(); + } + + InvalidateProperties(); + } + + public void RemoveSpawned() + { + Defrag(); + + for (int i = m_Spawned.Count - 1; i >= 0; --i) + m_Spawned[i].Delete(); + + InvalidateProperties(); + } + + public void BringToHome() + { + Defrag(); + + for (int i = 0; i < m_Spawned.Count; ++i) + { + ISpawnable e = m_Spawned[i]; + + e.MoveToWorld(this.Location, this.Map); + } + } + + public override void OnDelete() + { + base.OnDelete(); + + RemoveSpawned(); + + if (m_Timer != null) + m_Timer.Stop(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)6); // version + + writer.Write(m_MobilesSeekHome); + + writer.Write(m_IgnoreHousing); + + writer.Write(m_SpawnArea); + + writer.Write(m_UsesSpawnerHome); + + writer.Write(m_WalkingRange); + + writer.Write(m_WayPoint); + + writer.Write(m_Group); + + writer.Write(m_MinDelay); + writer.Write(m_MaxDelay); + writer.Write(m_Count); + writer.Write(m_Team); + writer.Write(m_HomeRange); + writer.Write(m_Running); + + if (m_Running) + writer.WriteDeltaTime(m_End); + + writer.Write(m_SpawnNames.Count); + + for (int i = 0; i < m_SpawnNames.Count; ++i) + writer.Write(m_SpawnNames[i]); + + writer.Write(m_Spawned.Count); + + for (int i = 0; i < m_Spawned.Count; ++i) + { + IEntity e = m_Spawned[i]; + + if (e is Item) + writer.Write((Item)e); + else if (e is Mobile) + writer.Write((Mobile)e); + else + writer.Write(Serial.MinusOne); + } + } + + private static WarnTimer m_WarnTimer; + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 6: + { + m_MobilesSeekHome = reader.ReadBool(); + m_UsesSpawnerHome = reader.ReadBool(); + goto case 5; + } + case 5: + { + m_SpawnArea = reader.ReadRect2D(); + m_UsesSpawnerHome = reader.ReadBool(); + + goto case 4; + } + case 4: + { + m_WalkingRange = reader.ReadInt(); + + goto case 3; + } + case 3: + case 2: + { + m_WayPoint = reader.ReadItem() as WayPoint; + + goto case 1; + } + + case 1: + { + m_Group = reader.ReadBool(); + + goto case 0; + } + + case 0: + { + m_MinDelay = reader.ReadTimeSpan(); + m_MaxDelay = reader.ReadTimeSpan(); + m_Count = reader.ReadInt(); + m_Team = reader.ReadInt(); + m_HomeRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + + TimeSpan ts = TimeSpan.Zero; + + if (m_Running) + ts = reader.ReadDeltaTime() - DateTime.Now; + + int size = reader.ReadInt(); + + m_SpawnNames = new List(size); + + for (int i = 0; i < size; ++i) + { + string creatureString = reader.ReadString(); + + m_SpawnNames.Add(creatureString); + string typeName = ParseType(creatureString); + + if (ScriptCompiler.FindTypeByName(typeName) == null) + { + if (m_WarnTimer == null) + m_WarnTimer = new WarnTimer(); + + m_WarnTimer.Add(Location, Map, typeName); + } + } + + int count = reader.ReadInt(); + + m_Spawned = new List(count); + + for (int i = 0; i < count; ++i) + { + ISpawnable e = World.FindEntity(reader.ReadInt()) as ISpawnable; + + if (e != null) + { + e.Spawner = this; + m_Spawned.Add(e); + } + } + + if (m_Running) + DoTimer(ts); + + break; + } + } + + if (version < 3 && Weight == 0) + Weight = -1; + } + + private class WarnTimer : Timer + { + private List m_List; + + private class WarnEntry + { + public Point3D m_Point; + public Map m_Map; + public string m_Name; + + public WarnEntry(Point3D p, Map map, string name) + { + m_Point = p; + m_Map = map; + m_Name = name; + } + } + + public WarnTimer() + : base(TimeSpan.FromSeconds(1.0)) + { + m_List = new List(); + Start(); + } + + public void Add(Point3D p, Map map, string name) + { + m_List.Add(new WarnEntry(p, map, name)); + } + + protected override void OnTick() + { + try + { + Console.WriteLine("Warning: {0} bad spawns detected, logged: 'badspawn.log'", m_List.Count); + + using (StreamWriter op = new StreamWriter("badspawn.log", true)) + { + op.WriteLine("# Bad spawns : {0}", DateTime.Now); + op.WriteLine("# Format: X Y Z F Name"); + op.WriteLine(); + + foreach (WarnEntry e in m_List) + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name); + + op.WriteLine(); + op.WriteLine(); + } + } + catch + { + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Spawner/SpawnerGump.cs b/Scripts/Engines/Spawner/SpawnerGump.cs new file mode 100644 index 0000000..ea11444 --- /dev/null +++ b/Scripts/Engines/Spawner/SpawnerGump.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Gumps; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class SpawnerGump : Gump + { + private Spawner m_Spawner; + + public SpawnerGump(Spawner spawner) + : base(50, 50) + { + m_Spawner = spawner; + + AddPage(0); + + AddBackground(0, 0, 410, 371, 5054); + + AddLabel(160, 1, 0, "Creatures List"); + + AddButton(5, 347, 0xFB1, 0xFB3, 0, GumpButtonType.Reply, 0); + AddLabel(38, 347, 0x384, "Cancel"); + + AddButton(5, 325, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0); + AddLabel(38, 325, 0x384, "Apply"); + + AddButton(110, 325, 0xFB4, 0xFB6, 2, GumpButtonType.Reply, 0); + AddLabel(143, 325, 0x384, "Bring to Home"); + + AddButton(110, 347, 0xFA8, 0xFAA, 3, GumpButtonType.Reply, 0); + AddLabel(143, 347, 0x384, "Total Respawn"); + + for (int i = 0; i < 13; i++) + { + AddButton(5, (22 * i) + 20, 0xFA5, 0xFA7, 4 + (i * 2), GumpButtonType.Reply, 0); + AddButton(38, (22 * i) + 20, 0xFA2, 0xFA4, 5 + (i * 2), GumpButtonType.Reply, 0); + + AddImageTiled(71, (22 * i) + 20, 309, 23, 0xA40); + AddImageTiled(72, (22 * i) + 21, 307, 21, 0xBBC); + + string str = ""; + + if (i < spawner.SpawnNames.Count) + { + str = (string)spawner.SpawnNames[i]; + int count = m_Spawner.CountCreatures(str); + + AddLabel(382, (22 * i) + 20, 0, count.ToString()); + } + + AddTextEntry(75, (22 * i) + 21, 304, 21, 0, i, str); + } + } + + public List CreateArray(RelayInfo info, Mobile from) + { + List creaturesName = new List(); + + for (int i = 0; i < 13; i++) + { + TextRelay te = info.GetTextEntry(i); + + if (te != null) + { + string str = te.Text; + + if (str.Length > 0) + { + str = str.Trim(); + + string t = Spawner.ParseType(str); + + Type type = ScriptCompiler.FindTypeByName(t); + + if (type != null) + creaturesName.Add(str); + else + from.SendMessage("{0} is not a valid type name.", t); + } + } + } + + return creaturesName; + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Spawner.Deleted || state.Mobile.AccessLevel < AccessLevel.GameMaster) + return; + + switch (info.ButtonID) + { + case 0: // Closed + { + return; + } + case 1: // Apply + { + m_Spawner.SpawnNames = CreateArray(info, state.Mobile); + + break; + } + case 2: // Bring to Home + { + m_Spawner.BringToHome(); + + break; + } + case 3: // Total Respawn + { + m_Spawner.Respawn(); + + break; + } + default: + { + int buttonID = info.ButtonID - 4; + int index = buttonID / 2; + int type = buttonID % 2; + + TextRelay entry = info.GetTextEntry(index); + + if (entry != null && entry.Text.Length > 0) + { + if (type == 0) // Spawn creature + m_Spawner.Spawn(entry.Text); + else // Remove creatures + m_Spawner.RemoveSpawned(entry.Text); + + m_Spawner.SpawnNames = CreateArray(info, state.Mobile); + } + + break; + } + } + + state.Mobile.SendGump(new SpawnerGump(m_Spawner)); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Spawner/SpawnerType.cs b/Scripts/Engines/Spawner/SpawnerType.cs new file mode 100644 index 0000000..4e89aae --- /dev/null +++ b/Scripts/Engines/Spawner/SpawnerType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class SpawnerType + { + public static Type GetType( string name ) + { + return ScriptCompiler.FindTypeByName( name ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs b/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs new file mode 100644 index 0000000..7723ea2 --- /dev/null +++ b/Scripts/Engines/Treasures of Tokuno/BasePigmentsOfTokuno.cs @@ -0,0 +1,269 @@ +using Server; +using System; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class BasePigmentsOfTokuno : Item, IUsesRemaining + { + private static Type[] m_Glasses = new Type[] + { + typeof( MaritimeGlasses ), + typeof( WizardsGlasses ), + typeof( TradeGlasses ), + typeof( LyricalGlasses ), + typeof( NecromanticGlasses ), + typeof( LightOfWayGlasses ), + typeof( FoldedSteelGlasses ), + typeof( PoisonedGlasses ), + typeof( TreasureTrinketGlasses ), + typeof( MaceShieldGlasses ), + typeof( ArtsGlasses ), + typeof( AnthropomorphistGlasses ) + }; + + private static Type[] m_Replicas = new Type[] + { + typeof( ANecromancerShroud ), + typeof( BraveKnightOfTheBritannia ), + typeof( CaptainJohnsHat ), + typeof( DetectiveBoots ), + typeof( DjinnisRing ), + typeof( EmbroideredOakLeafCloak ), + typeof( GuantletsOfAnger ), + typeof( LieutenantOfTheBritannianRoyalGuard ), + typeof( OblivionsNeedle ), + typeof( RoyalGuardSurvivalKnife ), + typeof( SamaritanRobe ), + typeof( TheMostKnowledgePerson ), + typeof( TheRobeOfBritanniaAri ), + typeof( AcidProofRobe ), + typeof( Calm ), + typeof( CrownOfTalKeesh ), + typeof( FangOfRactus ), + typeof( GladiatorsCollar ), + typeof( OrcChieftainHelm ), + typeof( Pacify ), + typeof( Quell ), + typeof( ShroudOfDeciet ), + typeof( Subdue ) + }; + + private static Type[] m_DyableHeritageItems = new Type[] + { + typeof( ChargerOfTheFallen ), + typeof( SamuraiHelm ), + typeof( HolySword ), + typeof( LeggingsOfEmbers ), + typeof( ShaminoCrossbow ) + }; + + public override int LabelNumber { get { return 1070933; } } // Pigments of Tokuno + + private int m_UsesRemaining; + private TextDefinition m_Label; + + protected TextDefinition Label + { + get { return m_Label; } + set { m_Label = value; InvalidateProperties(); } + } + + #region Old Item Serialization Vars + /* DO NOT USE! Only used in serialization of pigments that originally derived from Item */ + private bool m_InheritsItem; + + protected bool InheritsItem + { + get { return m_InheritsItem; } + } + #endregion + + public BasePigmentsOfTokuno() + : base(0xEFF) + { + Weight = 1.0; + m_UsesRemaining = 1; + } + + public BasePigmentsOfTokuno(int uses) + : base(0xEFF) + { + Weight = 1.0; + m_UsesRemaining = uses; + } + + public BasePigmentsOfTokuno(Serial serial) + : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Label != null && m_Label > 0) + TextDefinition.AddTo(list, m_Label); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public override void OnDoubleClick(Mobile from) + { + if (IsAccessibleTo(from) && from.InRange(GetWorldLocation(), 3)) + { + from.SendLocalizedMessage(1070929); // Select the artifact or enhanced magic item to dye. + from.BeginTarget(3, false, Server.Targeting.TargetFlags.None, new TargetStateCallback(InternalCallback), this); + } + else + from.SendLocalizedMessage(502436); // That is not accessible. + } + + private void InternalCallback(Mobile from, object targeted, object state) + { + BasePigmentsOfTokuno pigment = (BasePigmentsOfTokuno)state; + + if (pigment.Deleted || pigment.UsesRemaining <= 0 || !from.InRange(pigment.GetWorldLocation(), 3) || !pigment.IsAccessibleTo(from)) + return; + + Item i = targeted as Item; + + if (i == null) + from.SendLocalizedMessage(1070931); // You can only dye artifacts and enhanced magic items with this tub. + else if (!from.InRange(i.GetWorldLocation(), 3) || !IsAccessibleTo(from)) + from.SendLocalizedMessage(502436); // That is not accessible. + else if (from.Items.Contains(i)) + from.SendLocalizedMessage(1070930); // Can't dye artifacts or enhanced magic items that are being worn. + else if (i.IsLockedDown) + from.SendLocalizedMessage(1070932); // You may not dye artifacts and enhanced magic items which are locked down. + else if (i.QuestItem) + from.SendLocalizedMessage(1151836); // You may not dye toggled quest items. + else if (i is MetalPigmentsOfTokuno) + from.SendLocalizedMessage(1042417); // You cannot dye that. + else if (i is LesserPigmentsOfTokuno) + from.SendLocalizedMessage(1042417); // You cannot dye that. + else if (i is PigmentsOfTokuno) + from.SendLocalizedMessage(1042417); // You cannot dye that. + else if (!IsValidItem(i)) + from.SendLocalizedMessage(1070931); // You can only dye artifacts and enhanced magic items with this tub. //Yes, it says tub on OSI. Don't ask me why ;p + else + { + //Notes: on OSI there IS no hue check to see if it's already hued. and no messages on successful hue either + i.Hue = Hue; + + if (--pigment.UsesRemaining <= 0) + pigment.Delete(); + + from.PlaySound(0x23E); // As per OSI TC1 + } + } + + public static bool IsValidItem(Item i) + { + if (i is BasePigmentsOfTokuno) + return false; + + Type t = i.GetType(); + + CraftResource resource = CraftResource.None; + + if (i is BaseWeapon) + resource = ((BaseWeapon)i).Resource; + else if (i is BaseArmor) + resource = ((BaseArmor)i).Resource; + else if (i is BaseClothing) + resource = ((BaseClothing)i).Resource; + + if (!CraftResources.IsStandard(resource)) + return true; + + if (i is ITokunoDyable) + return true; + + return ( + IsInTypeList(t, TreasuresOfTokuno.LesserArtifactsTotal) + || IsInTypeList(t, TreasuresOfTokuno.GreaterArtifacts) + || IsInTypeList(t, DemonKnight.ArtifactRarity10) + || IsInTypeList(t, DemonKnight.ArtifactRarity11) + || IsInTypeList(t, MondainsLegacy.Artifacts) + || IsInTypeList(t, StealableArtifactsSpawner.TypesOfEntires) + || IsInTypeList(t, Paragon.Artifacts) + || IsInTypeList(t, Leviathan.Artifacts) + || IsInTypeList(t, TreasureMapChest.Artifacts) + || IsInTypeList(t, m_Replicas) + || IsInTypeList(t, m_DyableHeritageItems) + || IsInTypeList(t, m_Glasses) + ); + } + + private static bool IsInTypeList(Type t, Type[] list) + { + for (int i = 0; i < list.Length; i++) + { + if (list[i] == t) return true; + } + + return false; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); + + writer.WriteEncodedInt(m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_UsesRemaining = reader.ReadEncodedInt(); + break; + } + case 0: // Old pigments that inherited from item + { + m_InheritsItem = true; + + if (this is LesserPigmentsOfTokuno) + ((LesserPigmentsOfTokuno)this).Type = (LesserPigmentType)reader.ReadEncodedInt(); + else if (this is PigmentsOfTokuno) + ((PigmentsOfTokuno)this).Type = (PigmentType)reader.ReadEncodedInt(); + else if (this is MetalPigmentsOfTokuno) + reader.ReadEncodedInt(); + + m_UsesRemaining = reader.ReadEncodedInt(); + + break; + } + } + + + } + + #region IUsesRemaining Members + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining + { + get { return true; } + set { } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Engines/Treasures of Tokuno/GreaterArtifacts.cs b/Scripts/Engines/Treasures of Tokuno/GreaterArtifacts.cs new file mode 100644 index 0000000..3de577a --- /dev/null +++ b/Scripts/Engines/Treasures of Tokuno/GreaterArtifacts.cs @@ -0,0 +1,506 @@ +using Server; +using System; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Items +{ + public class DarkenedSky : Kama + { + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int LabelNumber { get { return 1070966; } } // Darkened Sky + + [Constructable] + public DarkenedSky() : base() + { + WeaponAttributes.HitLightning = 60; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 50; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = pois = chaos = direct = 0; + cold = nrgy = 50; + } + + public DarkenedSky( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + public class KasaOfTheRajin : Kasa + { + public override int LabelNumber { get { return 1070969; } } // Kasa of the Raj-in + + public override int BasePhysicalResistance { get { return 12; } } + public override int BaseFireResistance { get { return 17; } } + public override int BaseColdResistance { get { return 21; } } + public override int BasePoisonResistance { get { return 17; } } + public override int BaseEnergyResistance { get { return 17; } } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + [Constructable] + public KasaOfTheRajin() : base() + { + Attributes.SpellDamage = 12; + } + + public KasaOfTheRajin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version <= 1 ) + { + MaxHitPoints = 255; + HitPoints = 255; + } + + if( version == 0 ) + LootType = LootType.Regular; + } + + } + + public class RuneBeetleCarapace : PlateDo + { + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int LabelNumber{ get{ return 1070968; } } // Rune Beetle Carapace + + public override int BaseColdResistance { get { return 14; } } + public override int BaseEnergyResistance { get { return 14; } } + + [Constructable] + public RuneBeetleCarapace() : base() + { + Attributes.BonusMana = 10; + Attributes.RegenMana = 3; + Attributes.LowerManaCost = 15; + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + } + + public RuneBeetleCarapace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + public class Stormgrip : LeatherNinjaMitts + { + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int LabelNumber{ get{ return 1070970; } } // Stormgrip + + public override int BasePhysicalResistance { get { return 10; } } + public override int BaseColdResistance { get { return 18; } } + public override int BaseEnergyResistance { get { return 18; } } + + [Constructable] + public Stormgrip() : base() + { + Attributes.BonusInt = 8; + Attributes.Luck = 125; + Attributes.WeaponDamage = 25; + } + + public Stormgrip( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + public class SwordOfTheStampede : NoDachi + { + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int LabelNumber { get { return 1070964; } } // Sword of the Stampede + + [Constructable] + public SwordOfTheStampede() : base() + { + WeaponAttributes.HitHarm = 100; + Attributes.AttackChance = 10; + Attributes.WeaponDamage = 60; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = pois = nrgy = chaos = direct = 0; + cold = 100; + } + + public SwordOfTheStampede( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + public class SwordsOfProsperity : Daisho + { + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int LabelNumber { get { return 1070963; } } // Swords of Prosperity + + [Constructable] + public SwordsOfProsperity() : base() + { + WeaponAttributes.MageWeapon = 30; + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = 1; + Attributes.Luck = 200; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = cold = pois = nrgy = chaos = direct = 0; + fire = 100; + } + + public SwordsOfProsperity( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + public class TheHorselord : Yumi + { + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int LabelNumber { get { return 1070967; } } // The Horselord + + [Constructable] + public TheHorselord() : base() + { + Attributes.BonusDex = 5; + Attributes.RegenMana = 1; + Attributes.Luck = 125; + Attributes.WeaponDamage = 50; + + Slayer = SlayerName.ElementalBan; + Slayer2 = SlayerName.ReptilianDeath; + } + + public TheHorselord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TomeOfLostKnowledge : Spellbook + { + public override int LabelNumber { get { return 1070971; } } // Tome of Lost Knowledge + + [Constructable] + public TomeOfLostKnowledge() : base() + { + LootType = LootType.Regular; + Hue = 0x530; + + SkillBonuses.SetValues( 0, SkillName.Magery, 15.0 ); + Attributes.BonusInt = 8; + Attributes.LowerManaCost = 15; + Attributes.SpellDamage = 15; + } + + public TomeOfLostKnowledge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WindsEdge : Tessen + { + public override int LabelNumber { get { return 1070965; } } // Wind's Edge + + [Constructable] + public WindsEdge() : base() + { + WeaponAttributes.HitLeechMana = 40; + + Attributes.WeaponDamage = 50; + Attributes.WeaponSpeed = 50; + Attributes.DefendChance = 10; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + + public WindsEdge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public enum PigmentType + { + None, + ParagonGold, + VioletCouragePurple, + InvulnerabilityBlue, + LunaWhite, + DryadGreen, + ShadowDancerBlack, + BerserkerRed, + NoxGreen, + RumRed, + FireOrange, + FadedCoal, + Coal, + FadedGold, + StormBronze, + Rose, + MidnightCoal, + FadedBronze, + FadedRose, + DeepRose + } + + public class PigmentsOfTokuno : BasePigmentsOfTokuno + { + private static int[][] m_Table = new int[][] + { + // Hue, Label + new int[]{ /*PigmentType.None,*/ 0, -1 }, + new int[]{ /*PigmentType.ParagonGold,*/ 0x501, 1070987 }, + new int[]{ /*PigmentType.VioletCouragePurple,*/ 0x486, 1070988 }, + new int[]{ /*PigmentType.InvulnerabilityBlue,*/ 0x4F2, 1070989 }, + new int[]{ /*PigmentType.LunaWhite,*/ 0x47E, 1070990 }, + new int[]{ /*PigmentType.DryadGreen,*/ 0x48F, 1070991 }, + new int[]{ /*PigmentType.ShadowDancerBlack,*/ 0x455, 1070992 }, + new int[]{ /*PigmentType.BerserkerRed,*/ 0x21, 1070993 }, + new int[]{ /*PigmentType.NoxGreen,*/ 0x58C, 1070994 }, + new int[]{ /*PigmentType.RumRed,*/ 0x66C, 1070995 }, + new int[]{ /*PigmentType.FireOrange,*/ 0x54F, 1070996 }, + new int[]{ /*PigmentType.Fadedcoal,*/ 0x96A, 1079579 }, + new int[]{ /*PigmentType.Coal,*/ 0x96B, 1079580 }, + new int[]{ /*PigmentType.FadedGold,*/ 0x972, 1079581 }, + new int[]{ /*PigmentType.StormBronze,*/ 0x977, 1079582 }, + new int[]{ /*PigmentType.Rose,*/ 0x97C, 1079583 }, + new int[]{ /*PigmentType.MidnightCoal,*/ 0x96C, 1079584 }, + new int[]{ /*PigmentType.FadedBronze,*/ 0x975, 1079585 }, + new int[]{ /*PigmentType.FadedRose,*/ 0x97B, 1079586 }, + new int[]{ /*PigmentType.DeepRose,*/ 0x97E, 1079587 } + }; + + public static int[] GetInfo( PigmentType type ) + { + int v = (int)type; + + if( v < 0 || v >= m_Table.Length ) + v = 0; + + return m_Table[v]; + } + + private PigmentType m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public PigmentType Type + { + get { return m_Type; } + set + { + m_Type = value; + + int v = (int)m_Type; + + if ( v >= 0 && v < m_Table.Length ) + { + Hue = m_Table[v][0]; + Label = m_Table[v][1]; + } + else + { + Hue = 0; + Label = -1; + } + } + } + + public override int LabelNumber { get { return 1070933; } } // Pigments of Tokuno + + [Constructable] + public PigmentsOfTokuno() : this( PigmentType.None, 10 ) + { + } + + [Constructable] + public PigmentsOfTokuno( PigmentType type ) : this( type, (type == PigmentType.None||type >= PigmentType.FadedCoal)? 10 : 50 ) + { + } + + [Constructable] + public PigmentsOfTokuno( PigmentType type, int uses ) : base( uses ) + { + Weight = 1.0; + Type = type; + } + + public PigmentsOfTokuno( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); + + writer.WriteEncodedInt( (int)m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); // Required for BasePigmentsOfTokuno insertion + + switch ( version ) + { + case 1: Type = (PigmentType)reader.ReadEncodedInt(); break; + case 0: break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Treasures of Tokuno/LesserArtifacts.cs b/Scripts/Engines/Treasures of Tokuno/LesserArtifacts.cs new file mode 100644 index 0000000..810e614 --- /dev/null +++ b/Scripts/Engines/Treasures of Tokuno/LesserArtifacts.cs @@ -0,0 +1,1051 @@ +using Server; +using System; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Items +{ + public class AncientFarmersKasa : Kasa + { + public override int LabelNumber{ get{ return 1070922; } } // Ancient Farmer's Kasa + public override int BaseColdResistance { get { return 19; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get { return 255; } } + + [Constructable] + public AncientFarmersKasa() : base() + { + Attributes.BonusStr = 5; + Attributes.BonusStam = 5; + Attributes.RegenStam = 5; + + SkillBonuses.SetValues( 0, SkillName.AnimalLore, 5.0 ); + } + + public AncientFarmersKasa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version <= 1 ) + { + MaxHitPoints = 255; + HitPoints = 255; + } + + if( version == 0 ) + SkillBonuses.SetValues( 0, SkillName.AnimalLore, 5.0 ); + } + } + + public class AncientSamuraiDo : PlateDo + { + public override int LabelNumber { get { return 1070926; } } // Ancient Samurai Do + + public override int BasePhysicalResistance { get { return 15; } } + public override int BaseFireResistance { get { return 12; } } + public override int BaseColdResistance { get { return 10; } } + public override int BasePoisonResistance { get { return 11; } } + public override int BaseEnergyResistance { get { return 8; } } + + [Constructable] + public AncientSamuraiDo() : base() + { + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + SkillBonuses.SetValues( 0, SkillName.Parry, 10.0 ); + } + + public AncientSamuraiDo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class ArmsOfTacticalExcellence : LeatherHiroSode + { + public override int LabelNumber { get { return 1070921; } } // Arms of Tactical Excellence + + public override int BaseFireResistance { get { return 9; } } + public override int BaseColdResistance { get { return 13; } } + public override int BasePoisonResistance { get { return 8; } } + + [Constructable] + public ArmsOfTacticalExcellence() : base() + { + Attributes.BonusDex = 5; + SkillBonuses.SetValues( 0, SkillName.Tactics, 12.0 ); + } + + public ArmsOfTacticalExcellence( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class BlackLotusHood : ClothNinjaHood + { + public override int LabelNumber { get { return 1070919; } } // Black Lotus Hood + + public override int BasePhysicalResistance { get { return 0; } } + public override int BaseFireResistance { get { return 11; } } + public override int BaseColdResistance { get { return 15; } } + public override int BasePoisonResistance { get { return 11; } } + public override int BaseEnergyResistance { get { return 11; } } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + [Constructable] + public BlackLotusHood() : base() + { + Attributes.LowerManaCost = 6; + Attributes.AttackChance = 6; + ClothingAttributes.SelfRepair = 5; + } + + public BlackLotusHood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + { + MaxHitPoints = 255; + HitPoints = 255; + } + } + } + + public class DaimyosHelm : PlateBattleKabuto + { + public override int LabelNumber { get { return 1070920; } } // Daimyo's Helm + + public override int BaseColdResistance { get { return 10; } } + + [Constructable] + public DaimyosHelm() : base() + { + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + ArmorAttributes.SelfRepair = 3; + Attributes.WeaponSpeed = 10; + } + + public DaimyosHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class DemonForks : Sai + { + public override int LabelNumber{ get{ return 1070917; } } // Demon Forks + + [Constructable] + public DemonForks() : base() + { + WeaponAttributes.ResistFireBonus = 10; + WeaponAttributes.ResistPoisonBonus = 10; + + Attributes.ReflectPhysical = 10; + Attributes.WeaponDamage = 35; + Attributes.DefendChance = 10; + } + + public DemonForks( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class DragonNunchaku : Nunchaku + { + public override int LabelNumber{ get{ return 1070914; } } // Dragon Nunchaku + + [Constructable] + public DragonNunchaku() : base() + { + WeaponAttributes.ResistFireBonus = 5; + WeaponAttributes.SelfRepair = 3; + WeaponAttributes.HitFireball = 50; + + Attributes.WeaponDamage = 40; + Attributes.WeaponSpeed = 20; + } + + public DragonNunchaku( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class Exiler : Tetsubo + { + public override int LabelNumber{ get{ return 1070913; } } // Exiler + + [Constructable] + public Exiler() : base() + { + WeaponAttributes.HitDispel = 33; + Slayer = SlayerName.Exorcism; + + Attributes.WeaponDamage = 40; + Attributes.WeaponSpeed = 20; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = chaos = direct = 0; + + nrgy = 100; + } + + + public Exiler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class GlovesOfTheSun : LeatherNinjaMitts + { + public override int LabelNumber { get { return 1070924; } } // Gloves of the Sun + + public override int BaseFireResistance { get { return 24; } } + + [Constructable] + public GlovesOfTheSun() : base() + { + Attributes.RegenHits = 2; + Attributes.NightSight = 1; + Attributes.LowerManaCost = 5; + Attributes.LowerRegCost = 18; + } + + public GlovesOfTheSun( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class HanzosBow : Yumi + { + public override int LabelNumber { get { return 1070918; } } // Hanzo's Bow + + [Constructable] + public HanzosBow() : base() + { + WeaponAttributes.HitLeechHits = 40; + WeaponAttributes.SelfRepair = 3; + + Attributes.WeaponDamage = 50; + + SkillBonuses.SetValues( 0, SkillName.Ninjitsu, 10 ); + } + + public HanzosBow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class LegsOfStability : PlateSuneate + { + public override int LabelNumber { get { return 1070925; } } // Legs of Stability + + public override int BasePhysicalResistance { get { return 20; } } + public override int BasePoisonResistance { get { return 18; } } + + [Constructable] + public LegsOfStability() : base() + { + Attributes.BonusStam = 5; + + ArmorAttributes.SelfRepair = 3; + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + } + + public LegsOfStability( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class PeasantsBokuto : Bokuto + { + public override int LabelNumber { get { return 1070912; } } // Peasant's Bokuto + + [Constructable] + public PeasantsBokuto() : base() + { + WeaponAttributes.SelfRepair = 3; + WeaponAttributes.HitLowerDefend = 30; + + Attributes.WeaponDamage = 35; + Attributes.WeaponSpeed = 10; + Slayer = SlayerName.SnakesBane; + } + + public PeasantsBokuto( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class PilferedDancerFans : Tessen + { + public override int LabelNumber { get { return 1070916; } } // Pilfered Dancer Fans + + [Constructable] + public PilferedDancerFans() : base() + { + Attributes.WeaponDamage = 20; + Attributes.WeaponSpeed = 20; + Attributes.CastRecovery = 2; + Attributes.DefendChance = 5; + Attributes.SpellChanneling = 1; + } + + public PilferedDancerFans( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class TheDestroyer : NoDachi + { + public override int LabelNumber { get { return 1070915; } } // The Destroyer + + [Constructable] + public TheDestroyer() : base() + { + WeaponAttributes.HitLeechStam = 40; + + Attributes.BonusStr = 6; + Attributes.AttackChance = 10; + Attributes.WeaponDamage = 50; + } + + public TheDestroyer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + public class TomeOfEnlightenment : Spellbook + { + public override int LabelNumber { get { return 1070934; } } // Tome of Enlightenment + + [Constructable] + public TomeOfEnlightenment() : base() + { + LootType = LootType.Regular; + Hue = 0x455; + + Attributes.BonusInt = 5; + Attributes.SpellDamage = 10; + Attributes.CastSpeed = 1; + } + + public TomeOfEnlightenment( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LeurociansMempoOfFortune : LeatherMempo + { + public override int LabelNumber { get { return 1071460; } } // Leurocian's mempo of fortune + + public override int BasePhysicalResistance{ get{ return 15; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 15; } } + + [Constructable] + public LeurociansMempoOfFortune() : base() + { + LootType = LootType.Regular; + Hue = 0x501; + + Attributes.Luck = 300; + Attributes.RegenMana = 1; + } + + public LeurociansMempoOfFortune( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + } + + //Non weapon/armor ones: + + public class AncientUrn : Item + { + private static string[] m_Names = new string[] + { + "Akira", + "Avaniaga", + "Aya", + "Chie", + "Emiko", + "Fumiyo", + "Gennai", + "Gennosuke", + "Genjo", + "Hamato", + "Harumi", + "Ikuyo", + "Juri", + "Kaori", + "Kaoru", + "Kiyomori", + "Mayako", + "Motoki", + "Musashi", + "Nami", + "Nobukazu", + "Roku", + "Romi", + "Ryo", + "Sanzo", + "Sakamae", + "Satoshi", + "Takamori", + "Takuro", + "Teruyo", + "Toshiro", + "Yago", + "Yeijiro", + "Yoshi", + "Zeshin" + }; + + public static string[] Names { get { return m_Names; } } + + private string m_UrnName; + + [CommandProperty( AccessLevel.GameMaster )] + public string UrnName + { + get { return m_UrnName; } + set { m_UrnName = value; } + } + + public override int LabelNumber { get { return 1071014; } } // Ancient Urn + + [Constructable] + public AncientUrn( string urnName ) : base( 0x241D ) + { + m_UrnName = urnName; + Weight = 1.0; + } + + [Constructable] + public AncientUrn() : this( m_Names[Utility.Random( m_Names.Length )] ) + { + } + + public AncientUrn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + writer.Write( m_UrnName ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + m_UrnName = reader.ReadString(); + + Utility.Intern( ref m_UrnName ); + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1070935, m_UrnName ); // Ancient Urn of ~1_name~ + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, 1070935, m_UrnName ); // Ancient Urn of ~1_name~ + } + + } + + public class HonorableSwords : Item + { + private string m_SwordsName; + + [CommandProperty( AccessLevel.GameMaster )] + public string SwordsName + { + get { return m_SwordsName; } + set { m_SwordsName = value; } + } + + public override int LabelNumber { get { return 1071015; } } // Honorable Swords + + [Constructable] + public HonorableSwords( string swordsName ) : base( 0x2853 ) + { + m_SwordsName = swordsName; + + Weight = 5.0; + } + + [Constructable] + public HonorableSwords() : this( AncientUrn.Names[Utility.Random( AncientUrn.Names.Length )] ) + { + } + + public HonorableSwords( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + writer.Write( m_SwordsName ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + m_SwordsName = reader.ReadString(); + + Utility.Intern( ref m_SwordsName ); + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1070936, m_SwordsName ); // Honorable Swords of ~1_name~ + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, 1070936, m_SwordsName ); // Honorable Swords of ~1_name~ + } + } + + [Flipable( 0x2811, 0x2812 )] + public class ChestOfHeirlooms : LockableContainer + { + public override int LabelNumber{ get{ return 1070937; } } // Chest of heirlooms + + [Constructable] + public ChestOfHeirlooms() : base( 0x2811 ) + { + Locked = true; + LockLevel = 95; + MaxLockLevel = 140; + RequiredSkill = 95; + + TrapType = TrapType.ExplosionTrap; + TrapLevel = 10; + TrapPower = 100; + + GumpID = 0x10B; + + for ( int i = 0; i < 10; ++i ) + { + Item item = Loot.ChestOfHeirloomsContains(); + + int attributeCount = Utility.RandomMinMax( 1, 5 ); + int min = 20; + int max = 80; + + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( Core.AOS ) + BaseRunicTool.ApplyAttributesTo( weapon, attributeCount, min, max ); + else + { + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random( 6 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random( 6 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random( 6 ); + } + } + else if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if ( Core.AOS ) + BaseRunicTool.ApplyAttributesTo( armor, attributeCount, min, max ); + else + { + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random( 6 ); + armor.Durability = (ArmorDurabilityLevel)Utility.Random( 6 ); + } + } + else if( item is BaseHat && Core.AOS ) + BaseRunicTool.ApplyAttributesTo( (BaseHat)item, attributeCount, min, max ); + else if( item is BaseJewel && Core.AOS ) + BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, attributeCount, min, max ); + + DropItem( item ); + } + } + + public ChestOfHeirlooms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FluteOfRenewal : BambooFlute + { + public override int LabelNumber { get { return 1070927; } } // Flute of Renewal + + [Constructable] + public FluteOfRenewal() : base() + { + Slayer = SlayerGroup.Groups[Utility.Random( SlayerGroup.Groups.Length - 1 )].Super.Name; //-1 to exclude Fey slayer. Try to confrim no fey slayer on this on OSI + + ReplenishesCharges = true; + } + + public override int InitMinUses { get { return 300; } } + public override int InitMaxUses { get { return 300; } } + + public FluteOfRenewal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 0 && Slayer == SlayerName.Fey ) + Slayer = SlayerGroup.Groups[Utility.Random( SlayerGroup.Groups.Length - 1 )].Super.Name; + } + } + + public enum LesserPigmentType + { + None, + PaleOrange, + FreshRose, + ChaosBlue, + Silver, + NobleGold, + LightGreen, + PaleBlue, + FreshPlum, + DeepBrown, + BurntBrown + } + + public class LesserPigmentsOfTokuno : BasePigmentsOfTokuno + { + + private static int[][] m_Table = new int[][] + { + // Hue, Label + new int[]{ /*PigmentType.None,*/ 0, -1 }, + new int[]{ /*PigmentType.PaleOrange,*/ 0x02E, 1071458 }, + new int[]{ /*PigmentType.FreshRose,*/ 0x4B9, 1071455 }, + new int[]{ /*PigmentType.ChaosBlue,*/ 0x005, 1071459 }, + new int[]{ /*PigmentType.Silver,*/ 0x3E9, 1071451 }, + new int[]{ /*PigmentType.NobleGold,*/ 0x227, 1071457 }, + new int[]{ /*PigmentType.LightGreen,*/ 0x1C8, 1071454 }, + new int[]{ /*PigmentType.PaleBlue,*/ 0x24F, 1071456 }, + new int[]{ /*PigmentType.FreshPlum,*/ 0x145, 1071450 }, + new int[]{ /*PigmentType.DeepBrown,*/ 0x3F0, 1071452 }, + new int[]{ /*PigmentType.BurntBrown,*/ 0x41A, 1071453 } + }; + + public static int[] GetInfo( LesserPigmentType type ) + { + int v = (int)type; + + if( v < 0 || v >= m_Table.Length ) + v = 0; + + return m_Table[v]; + } + + private LesserPigmentType m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public LesserPigmentType Type + { + get { return m_Type; } + set + { + m_Type = value; + + int v = (int)m_Type; + + if ( v >= 0 && v < m_Table.Length ) + { + Hue = m_Table[v][0]; + Label = m_Table[v][1]; + } + else + { + Hue = 0; + Label = -1; + } + } + } + + [Constructable] + public LesserPigmentsOfTokuno() : this( (LesserPigmentType)Utility.Random(0,11) ) + { + } + + [Constructable] + public LesserPigmentsOfTokuno( LesserPigmentType type ) : base( 1 ) + { + Weight = 1.0; + Type = type; + } + + public LesserPigmentsOfTokuno( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); + + writer.WriteEncodedInt( (int)m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); // Required for BasePigmentsOfTokuno insertion + + switch ( version ) + { + case 1: Type = (LesserPigmentType)reader.ReadEncodedInt(); break; + case 0: break; + } + } + } + + public class MetalPigmentsOfTokuno : BasePigmentsOfTokuno + { + [Constructable] + public MetalPigmentsOfTokuno() : base( 1 ) + { + RandomHue(); + Label = -1; + } + + public MetalPigmentsOfTokuno( Serial serial ) : base( serial ) + { + } + + public void RandomHue() + { + int a = Utility.Random(0,30); + if ( a != 0 ) + Hue = a + 0x960; + else + Hue = 0; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); // Required for BasePigmentsOfTokuno insertion + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs b/Scripts/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs new file mode 100644 index 0000000..2c7e312 --- /dev/null +++ b/Scripts/Engines/Treasures of Tokuno/TreasuresOfTokuno.cs @@ -0,0 +1,637 @@ +using System; +using Server; +using Server.Network; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Gumps; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Misc +{ + public enum TreasuresOfTokunoEra + { + None, + ToTOne, + ToTTwo, + ToTThree + } + + public class TreasuresOfTokuno + { + public const int ItemsPerReward = 10; + + private static Type[] m_LesserArtifactsTotal = new Type[] + { + typeof( AncientFarmersKasa ), typeof( AncientSamuraiDo ), typeof( ArmsOfTacticalExcellence ), typeof( BlackLotusHood ), + typeof( DaimyosHelm ), typeof( DemonForks ), typeof( DragonNunchaku ), typeof( Exiler ), typeof( GlovesOfTheSun ), + typeof( HanzosBow ), typeof( LegsOfStability ), typeof( PeasantsBokuto ), typeof( PilferedDancerFans ), typeof( TheDestroyer ), + typeof( TomeOfEnlightenment ), typeof( AncientUrn ), typeof( HonorableSwords ), typeof( PigmentsOfTokuno ), typeof( FluteOfRenewal ), + typeof( LeurociansMempoOfFortune ), typeof( LesserPigmentsOfTokuno ), typeof( MetalPigmentsOfTokuno ), typeof( ChestOfHeirlooms ) + }; + + public static Type[] LesserArtifactsTotal { get { return m_LesserArtifactsTotal; } } + + private static TreasuresOfTokunoEra _DropEra = TreasuresOfTokunoEra.None; + private static TreasuresOfTokunoEra _RewardEra = TreasuresOfTokunoEra.ToTOne; + + public static TreasuresOfTokunoEra DropEra + { + get { return _DropEra; } + set { _DropEra = value; } + } + + public static TreasuresOfTokunoEra RewardEra + { + get { return _RewardEra; } + set { _RewardEra = value; } + } + + private static Type[][] m_LesserArtifacts = new Type[][] + { + // ToT One Rewards + new Type[] { + typeof( AncientFarmersKasa ), typeof( AncientSamuraiDo ), typeof( ArmsOfTacticalExcellence ), typeof( BlackLotusHood ), + typeof( DaimyosHelm ), typeof( DemonForks ), typeof( DragonNunchaku ), typeof( Exiler ), typeof( GlovesOfTheSun ), + typeof( HanzosBow ), typeof( LegsOfStability ), typeof( PeasantsBokuto ), typeof( PilferedDancerFans ), typeof( TheDestroyer ), + typeof( TomeOfEnlightenment ), typeof( AncientUrn ), typeof( HonorableSwords ), typeof( PigmentsOfTokuno ), + typeof( FluteOfRenewal ), typeof( ChestOfHeirlooms ) + }, + // ToT Two Rewards + new Type[] { + typeof( MetalPigmentsOfTokuno ), typeof( AncientFarmersKasa ), typeof( AncientSamuraiDo ), typeof( ArmsOfTacticalExcellence ), + typeof( MetalPigmentsOfTokuno ), typeof( BlackLotusHood ), typeof( DaimyosHelm ), typeof( DemonForks ), + typeof( MetalPigmentsOfTokuno ), typeof( DragonNunchaku ), typeof( Exiler ), typeof( GlovesOfTheSun ), typeof( HanzosBow ), + typeof( MetalPigmentsOfTokuno ), typeof( LegsOfStability ), typeof( PeasantsBokuto ), typeof( PilferedDancerFans ), typeof( TheDestroyer ), + typeof( MetalPigmentsOfTokuno ), typeof( TomeOfEnlightenment ), typeof( AncientUrn ), typeof( HonorableSwords ), + typeof( MetalPigmentsOfTokuno ), typeof( FluteOfRenewal ), typeof( ChestOfHeirlooms ) + }, + // ToT Three Rewards + new Type[] { + typeof( LesserPigmentsOfTokuno ), typeof( AncientFarmersKasa ), typeof( AncientSamuraiDo ), typeof( ArmsOfTacticalExcellence ), + typeof( LesserPigmentsOfTokuno ), typeof( BlackLotusHood ), typeof( DaimyosHelm ), typeof( HanzosBow ), + typeof( LesserPigmentsOfTokuno ), typeof( DemonForks ), typeof( DragonNunchaku ), typeof( Exiler ), typeof( GlovesOfTheSun ), + typeof( LesserPigmentsOfTokuno ), typeof( LegsOfStability ), typeof( PeasantsBokuto ), typeof( PilferedDancerFans ), typeof( TheDestroyer ), + typeof( LesserPigmentsOfTokuno ), typeof( TomeOfEnlightenment ), typeof( AncientUrn ), typeof( HonorableSwords ), typeof( FluteOfRenewal ), + typeof( LesserPigmentsOfTokuno ), typeof( LeurociansMempoOfFortune ), typeof( ChestOfHeirlooms ) + } + }; + + public static Type[] LesserArtifacts + { + get { return m_LesserArtifacts[(int)RewardEra-1]; } + } + + private static Type[][] m_GreaterArtifacts = null; + + public static Type[] GreaterArtifacts + { + get + { + if( m_GreaterArtifacts == null ) + { + m_GreaterArtifacts = new Type[ToTRedeemGump.NormalRewards.Length][]; + + for( int i = 0; i < m_GreaterArtifacts.Length; i++ ) + { + m_GreaterArtifacts[i] = new Type[ToTRedeemGump.NormalRewards[i].Length]; + + for( int j = 0; j < m_GreaterArtifacts[i].Length; j++ ) + { + m_GreaterArtifacts[i][j] = ToTRedeemGump.NormalRewards[i][j].Type; + } + } + } + + return m_GreaterArtifacts[(int)RewardEra-1]; + } + } + + private static bool CheckLocation( Mobile m ) + { + Region r = m.Region; + + if( r.IsPartOf( typeof( Server.Regions.HouseRegion ) ) || Server.Multis.BaseBoat.FindBoatAt( m, m.Map ) != null ) + return false; + //TODO: a CanReach of something check as opposed to above? + + if( r.IsPartOf( "Yomotsu Mines" ) || r.IsPartOf( "Fan Dancer's Dojo" ) ) + return true; + + return (m.Map == Map.Tokuno); + } + + public static void HandleKill( Mobile victim, Mobile killer ) + { + PlayerMobile pm = killer as PlayerMobile; + BaseCreature bc = victim as BaseCreature; + + if( DropEra == TreasuresOfTokunoEra.None || pm == null || bc == null || !CheckLocation( bc ) || !CheckLocation( pm )|| !killer.InRange( victim, 18 )) + return; + + if( bc.Controlled || bc.Owners.Count > 0 || bc.Fame <= 0 ) + return; + + //25000 for 1/100 chance, 10 hyrus + //1500, 1/1000 chance, 20 lizard men for that chance. + + pm.ToTTotalMonsterFame += (int)(bc.Fame * (1 + Math.Sqrt( pm.Luck ) / 100)); + + //This is the Exponentional regression with only 2 datapoints. + //A log. func would also work, but it didn't make as much sense. + //This function isn't OSI exact beign that I don't know OSI's func they used ;p + int x = pm.ToTTotalMonsterFame; + + //const double A = 8.63316841 * Math.Pow( 10, -4 ); + const double A = 0.000863316841; + //const double B = 4.25531915 * Math.Pow( 10, -6 ); + const double B = 0.00000425531915; + + double chance = A * Math.Pow( 10, B * x ); + + if( chance > Utility.RandomDouble() ) + { + Item i = null; + + try + { + i = Activator.CreateInstance( m_LesserArtifacts[(int)DropEra-1][Utility.Random( m_LesserArtifacts[(int)DropEra-1].Length )] ) as Item; + } + catch + { } + + if( i != null ) + { + pm.SendLocalizedMessage( 1062317 ); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + + if( !pm.PlaceInBackpack( i ) ) + { + if( pm.BankBox != null && pm.BankBox.TryDropItem( killer, i, false ) ) + pm.SendLocalizedMessage( 1079730 ); // The item has been placed into your bank box. + else + { + pm.SendLocalizedMessage( 1072523 ); // You find an artifact, but your backpack and bank are too full to hold it. + i.MoveToWorld( pm.Location, pm.Map ); + } + } + + pm.ToTTotalMonsterFame = 0; + } + } + } + } +} + +namespace Server.Mobiles +{ + public class IharaSoko : BaseVendor + { + public override bool IsActiveVendor { get { return false; } } + public override bool IsInvulnerable { get { return true; } } + public override bool DisallowAllMoves { get { return true; } } + public override bool ClickTitle { get { return true; } } + public override bool CanTeach { get { return false; } } + + protected List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + public override void InitSBInfo() + { + } + + public override void InitOutfit() + { + AddItem( new Waraji( 0x711 ) ); + AddItem( new Backpack() ); + AddItem( new Kamishimo( 0x483 ) ); + + Item item = new LightPlateJingasa(); + item.Hue = 0x711; + + AddItem( item ); + } + + + [Constructable] + public IharaSoko() : base( "the Imperial Minister of Trade" ) + { + Name = "Ihara Soko"; + Female = false; + Body = 0x190; + Hue = 0x8403; + } + + public IharaSoko( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool CanBeDamaged() + { + return false; + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if( m.Alive && m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + int range = 3; + + if( m.Alive && Math.Abs( Z - m.Z ) < 16 && InRange( m, range ) && !InRange( oldLocation, range ) ) + { + if( pm.ToTItemsTurnedIn >= TreasuresOfTokuno.ItemsPerReward ) + { + SayTo( pm, 1070980 ); // Congratulations! You have turned in enough minor treasures to earn a greater reward. + + pm.CloseGump( typeof( ToTTurnInGump ) ); //Sanity + + if( !pm.HasGump( typeof( ToTRedeemGump ) ) ) + pm.SendGump( new ToTRedeemGump( this, false ) ); + } + else + { + if( pm.ToTItemsTurnedIn == 0 ) + SayTo( pm, 1071013 ); // Bring me 10 of the lost treasures of Tokuno and I will reward you with a valuable item. + else + SayTo( pm, 1070981, String.Format( "{0}\t{1}", pm.ToTItemsTurnedIn, TreasuresOfTokuno.ItemsPerReward ) ); // You have turned in ~1_COUNT~ minor artifacts. Turn in ~2_NUM~ to receive a reward. + + ArrayList buttons = ToTTurnInGump.FindRedeemableItems( pm ); + + if( buttons.Count > 0 && !pm.HasGump( typeof( ToTTurnInGump ) ) ) + pm.SendGump( new ToTTurnInGump( this, buttons ) ); + } + } + + int leaveRange = 7; + + if( !InRange( m, leaveRange ) && InRange( oldLocation, leaveRange ) ) + { + pm.CloseGump( typeof( ToTRedeemGump ) ); + pm.CloseGump( typeof( ToTTurnInGump ) ); + } + } + } + + public override void TurnToTokuno(){} + } +} + +namespace Server.Gumps +{ + public class ItemTileButtonInfo : ImageTileButtonInfo + { + private Item m_Item; + + public Item Item + { + get { return m_Item; } + set { m_Item = value; } + } + + public ItemTileButtonInfo( Item i ) : base( i.ItemID, i.Hue, ((i.Name == null || i.Name.Length <= 0)? (TextDefinition)i.LabelNumber : (TextDefinition)i.Name ) ) + { + m_Item = i; + } + } + + public class ToTTurnInGump : BaseImageTileButtonsGump + { + public static ArrayList FindRedeemableItems( Mobile m ) + { + Backpack pack = (Backpack)m.Backpack; + if( pack == null ) + return new ArrayList(); + + ArrayList items = new ArrayList( pack.FindItemsByType( TreasuresOfTokuno.LesserArtifactsTotal ) ); + ArrayList buttons = new ArrayList(); + + for( int i = 0; i < items.Count; i++ ) + { + Item item = (Item)items[i]; + if( item is ChestOfHeirlooms && !((ChestOfHeirlooms)item).Locked ) + continue; + + if( item is ChestOfHeirlooms && ((ChestOfHeirlooms)item).TrapLevel != 10 ) + continue; + + if( item is PigmentsOfTokuno && ((PigmentsOfTokuno)item).Type != PigmentType.None ) + continue; + + buttons.Add( new ItemTileButtonInfo( item ) ); + } + + return buttons; + } + + Mobile m_Collector; + + public ToTTurnInGump( Mobile collector, ArrayList buttons ) : base( 1071012, buttons ) // Click a minor artifact to give it to Ihara Soko. + { + m_Collector = collector; + } + + public ToTTurnInGump( Mobile collector, ItemTileButtonInfo[] buttons ) : base( 1071012, buttons ) // Click a minor artifact to give it to Ihara Soko. + { + m_Collector = collector; + } + + public override void HandleButtonResponse( NetState sender, int adjustedButton, ImageTileButtonInfo buttonInfo ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + Item item = ((ItemTileButtonInfo)buttonInfo).Item; + + if( !( pm != null && item.IsChildOf( pm.Backpack ) && pm.InRange( m_Collector.Location, 7 )) ) + return; + + item.Delete(); + + if( ++pm.ToTItemsTurnedIn >= TreasuresOfTokuno.ItemsPerReward ) + { + m_Collector.SayTo( pm, 1070980 ); // Congratulations! You have turned in enough minor treasures to earn a greater reward. + + pm.CloseGump( typeof( ToTTurnInGump ) ); //Sanity + + if( !pm.HasGump( typeof( ToTRedeemGump ) ) ) + pm.SendGump( new ToTRedeemGump( m_Collector, false ) ); + } + else + { + m_Collector.SayTo( pm, 1070981, String.Format( "{0}\t{1}", pm.ToTItemsTurnedIn, TreasuresOfTokuno.ItemsPerReward ) ); // You have turned in ~1_COUNT~ minor artifacts. Turn in ~2_NUM~ to receive a reward. + + ArrayList buttons = FindRedeemableItems( pm ); + + pm.CloseGump( typeof( ToTTurnInGump ) ); //Sanity + + if( buttons.Count > 0 ) + pm.SendGump( new ToTTurnInGump( m_Collector, buttons ) ); + } + } + + public override void HandleCancel( NetState sender ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !pm.InRange( m_Collector.Location, 7 ) ) + return; + + if( pm.ToTItemsTurnedIn == 0 ) + m_Collector.SayTo( pm, 1071013 ); // Bring me 10 of the lost treasures of Tokuno and I will reward you with a valuable item. + else if( pm.ToTItemsTurnedIn < TreasuresOfTokuno.ItemsPerReward ) //This case should ALWAYS be true with this gump, jsut a sanity check + m_Collector.SayTo( pm, 1070981, String.Format( "{0}\t{1}", pm.ToTItemsTurnedIn, TreasuresOfTokuno.ItemsPerReward ) ); // You have turned in ~1_COUNT~ minor artifacts. Turn in ~2_NUM~ to receive a reward. + else + m_Collector.SayTo( pm, 1070982 ); // When you wish to choose your reward, you have but to approach me again. + } + + } +} + +namespace Server.Gumps +{ + public class ToTRedeemGump : BaseImageTileButtonsGump + { + public class TypeTileButtonInfo : ImageTileButtonInfo + { + private Type m_Type; + + public Type Type { get { return m_Type; } } + + public TypeTileButtonInfo( Type type, int itemID, int hue, TextDefinition label, int localizedToolTip ) : base( itemID, hue, label, localizedToolTip ) + { + m_Type = type; + } + + public TypeTileButtonInfo( Type type, int itemID, TextDefinition label ) : this( type, itemID, 0, label, -1 ) + { + } + + public TypeTileButtonInfo( Type type, int itemID, TextDefinition label, int localizedToolTip ) : this( type, itemID, 0, label, localizedToolTip ) + { + } + } + + public class PigmentsTileButtonInfo : ImageTileButtonInfo + { + private PigmentType m_Pigment; + + public PigmentType Pigment + { + get + { + return m_Pigment; + } + + set + { + m_Pigment = value; + } + } + + public PigmentsTileButtonInfo( PigmentType p ) : base( 0xEFF, PigmentsOfTokuno.GetInfo( p )[0], PigmentsOfTokuno.GetInfo( p )[1] ) + { + m_Pigment = p; + } + } + + #region ToT Normal Rewards Table + private static TypeTileButtonInfo[][] m_NormalRewards = new TypeTileButtonInfo[][] + { + // ToT One Rewards + new TypeTileButtonInfo[] { + new TypeTileButtonInfo( typeof( SwordsOfProsperity ), 0x27A9, 1070963, 1071002 ), + new TypeTileButtonInfo( typeof( SwordOfTheStampede ), 0x27A2, 1070964, 1070978 ), + new TypeTileButtonInfo( typeof( WindsEdge ), 0x27A3, 1070965, 1071003 ), + new TypeTileButtonInfo( typeof( DarkenedSky ), 0x27AD, 1070966, 1071004 ), + new TypeTileButtonInfo( typeof( TheHorselord ), 0x27A5, 1070967, 1071005 ), + new TypeTileButtonInfo( typeof( RuneBeetleCarapace ), 0x277D, 1070968, 1071006 ), + new TypeTileButtonInfo( typeof( KasaOfTheRajin ), 0x2798, 1070969, 1071007 ), + new TypeTileButtonInfo( typeof( Stormgrip ), 0x2792, 1070970, 1071008 ), + new TypeTileButtonInfo( typeof( TomeOfLostKnowledge ), 0x0EFA, 0x530, 1070971, 1071009 ), + new TypeTileButtonInfo( typeof( PigmentsOfTokuno ), 0x0EFF, 1070933, 1071011 ) + }, + // ToT Two Rewards + new TypeTileButtonInfo[] { + new TypeTileButtonInfo( typeof( SwordsOfProsperity ), 0x27A9, 1070963, 1071002 ), + new TypeTileButtonInfo( typeof( SwordOfTheStampede ), 0x27A2, 1070964, 1070978 ), + new TypeTileButtonInfo( typeof( WindsEdge ), 0x27A3, 1070965, 1071003 ), + new TypeTileButtonInfo( typeof( DarkenedSky ), 0x27AD, 1070966, 1071004 ), + new TypeTileButtonInfo( typeof( TheHorselord ), 0x27A5, 1070967, 1071005 ), + new TypeTileButtonInfo( typeof( RuneBeetleCarapace ), 0x277D, 1070968, 1071006 ), + new TypeTileButtonInfo( typeof( KasaOfTheRajin ), 0x2798, 1070969, 1071007 ), + new TypeTileButtonInfo( typeof( Stormgrip ), 0x2792, 1070970, 1071008 ), + new TypeTileButtonInfo( typeof( TomeOfLostKnowledge ), 0x0EFA, 0x530, 1070971, 1071009 ), + new TypeTileButtonInfo( typeof( PigmentsOfTokuno ), 0x0EFF, 1070933, 1071011 ) + }, + // ToT Three Rewards + new TypeTileButtonInfo[] { + new TypeTileButtonInfo( typeof( SwordsOfProsperity ), 0x27A9, 1070963, 1071002 ), + new TypeTileButtonInfo( typeof( SwordOfTheStampede ), 0x27A2, 1070964, 1070978 ), + new TypeTileButtonInfo( typeof( WindsEdge ), 0x27A3, 1070965, 1071003 ), + new TypeTileButtonInfo( typeof( DarkenedSky ), 0x27AD, 1070966, 1071004 ), + new TypeTileButtonInfo( typeof( TheHorselord ), 0x27A5, 1070967, 1071005 ), + new TypeTileButtonInfo( typeof( RuneBeetleCarapace ), 0x277D, 1070968, 1071006 ), + new TypeTileButtonInfo( typeof( KasaOfTheRajin ), 0x2798, 1070969, 1071007 ), + new TypeTileButtonInfo( typeof( Stormgrip ), 0x2792, 1070970, 1071008 ), + new TypeTileButtonInfo( typeof( TomeOfLostKnowledge ), 0x0EFA, 0x530, 1070971, 1071009 ) + } + }; + #endregion + + public static TypeTileButtonInfo[][] NormalRewards + { + get { return m_NormalRewards; } + } + + #region ToT Pigment Rewards Table + private static PigmentsTileButtonInfo[][] m_PigmentRewards = new PigmentsTileButtonInfo[][] + { + // ToT One Pigment Rewards + new PigmentsTileButtonInfo[] { + new PigmentsTileButtonInfo( PigmentType.ParagonGold ), + new PigmentsTileButtonInfo( PigmentType.VioletCouragePurple ), + new PigmentsTileButtonInfo( PigmentType.InvulnerabilityBlue ), + new PigmentsTileButtonInfo( PigmentType.LunaWhite ), + new PigmentsTileButtonInfo( PigmentType.DryadGreen ), + new PigmentsTileButtonInfo( PigmentType.ShadowDancerBlack ), + new PigmentsTileButtonInfo( PigmentType.BerserkerRed ), + new PigmentsTileButtonInfo( PigmentType.NoxGreen ), + new PigmentsTileButtonInfo( PigmentType.RumRed ), + new PigmentsTileButtonInfo( PigmentType.FireOrange ) + }, + // ToT Two Pigment Rewards + new PigmentsTileButtonInfo[] { + new PigmentsTileButtonInfo( PigmentType.FadedCoal ), + new PigmentsTileButtonInfo( PigmentType.Coal ), + new PigmentsTileButtonInfo( PigmentType.FadedGold ), + new PigmentsTileButtonInfo( PigmentType.StormBronze ), + new PigmentsTileButtonInfo( PigmentType.Rose ), + new PigmentsTileButtonInfo( PigmentType.MidnightCoal ), + new PigmentsTileButtonInfo( PigmentType.FadedBronze ), + new PigmentsTileButtonInfo( PigmentType.FadedRose ), + new PigmentsTileButtonInfo( PigmentType.DeepRose ) + }, + // ToT Three Pigment Rewards + new PigmentsTileButtonInfo[] { + new PigmentsTileButtonInfo( PigmentType.ParagonGold ), + new PigmentsTileButtonInfo( PigmentType.VioletCouragePurple ), + new PigmentsTileButtonInfo( PigmentType.InvulnerabilityBlue ), + new PigmentsTileButtonInfo( PigmentType.LunaWhite ), + new PigmentsTileButtonInfo( PigmentType.DryadGreen ), + new PigmentsTileButtonInfo( PigmentType.ShadowDancerBlack ), + new PigmentsTileButtonInfo( PigmentType.BerserkerRed ), + new PigmentsTileButtonInfo( PigmentType.NoxGreen ), + new PigmentsTileButtonInfo( PigmentType.RumRed ), + new PigmentsTileButtonInfo( PigmentType.FireOrange ) + } + }; + #endregion + + public static PigmentsTileButtonInfo[][] PigmentRewards + { + get { return m_PigmentRewards; } + } + + private Mobile m_Collector; + + public ToTRedeemGump( Mobile collector, bool pigments ) : base( pigments ? 1070986 : 1070985, pigments ? (ImageTileButtonInfo[])m_PigmentRewards[(int)TreasuresOfTokuno.RewardEra-1] : (ImageTileButtonInfo[])m_NormalRewards[(int)TreasuresOfTokuno.RewardEra-1] ) + { + m_Collector = collector; + } + + public override void HandleButtonResponse( NetState sender, int adjustedButton, ImageTileButtonInfo buttonInfo ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !pm.InRange( m_Collector.Location, 7 ) || !(pm.ToTItemsTurnedIn >= TreasuresOfTokuno.ItemsPerReward) ) + return; + + bool pigments = (buttonInfo is PigmentsTileButtonInfo); + + Item item = null; + + if( pigments ) + { + PigmentsTileButtonInfo p = buttonInfo as PigmentsTileButtonInfo; + + item = new PigmentsOfTokuno( p.Pigment ); + } + else + { + TypeTileButtonInfo t = buttonInfo as TypeTileButtonInfo; + + if( t.Type == typeof( PigmentsOfTokuno ) ) //Special case of course. + { + pm.CloseGump( typeof( ToTTurnInGump ) ); //Sanity + pm.CloseGump( typeof( ToTRedeemGump ) ); + + pm.SendGump( new ToTRedeemGump( m_Collector, true ) ); + + return; + } + + try + { + item = (Item)Activator.CreateInstance( t.Type ); + } + catch { } + } + + if( item == null ) + return; //Sanity + + if( pm.AddToBackpack( item ) ) + { + pm.ToTItemsTurnedIn -= TreasuresOfTokuno.ItemsPerReward; + m_Collector.SayTo( pm, 1070984, (item.Name == null || item.Name.Length <= 0)? String.Format( "#{0}", item.LabelNumber ) : item.Name ); // You have earned the gratitude of the Empire. I have placed the ~1_OBJTYPE~ in your backpack. + } + else + { + item.Delete(); + m_Collector.SayTo( pm, 500722 ); // You don't have enough room in your backpack! + m_Collector.SayTo( pm, 1070982 ); // When you wish to choose your reward, you have but to approach me again. + } + } + + + public override void HandleCancel( NetState sender ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !pm.InRange( m_Collector.Location, 7 ) ) + return; + + if( pm.ToTItemsTurnedIn == 0 ) + m_Collector.SayTo( pm, 1071013 ); // Bring me 10 of the lost treasures of Tokuno and I will reward you with a valuable item. + else if( pm.ToTItemsTurnedIn < TreasuresOfTokuno.ItemsPerReward ) //This and above case should ALWAYS be FALSE with this gump, jsut a sanity check + m_Collector.SayTo( pm, 1070981, String.Format( "{0}\t{1}", pm.ToTItemsTurnedIn, TreasuresOfTokuno.ItemsPerReward ) ); // You have turned in ~1_COUNT~ minor artifacts. Turn in ~2_NUM~ to receive a reward. + else + m_Collector.SayTo( pm, 1070982 ); // When you wish to choose your reward, you have but to approach me again. + + } + } +} + +/* Notes + +Pigments of tokuno do NOT check for if item is already hued 0; APPARENTLY he still accepts it if it's < 10 charges. + +Chest of Heirlooms don't show if unlocked. + +Chest of heirlooms, locked, HARD to pick at 100 lock picking but not impossible. had 95 health to 0, cause it's trapped >< (explosion i think) +*/ \ No newline at end of file diff --git a/Scripts/Engines/Treasures of Tokuno/TreasuresOfTokunoPersistance.cs b/Scripts/Engines/Treasures of Tokuno/TreasuresOfTokunoPersistance.cs new file mode 100644 index 0000000..350c7e8 --- /dev/null +++ b/Scripts/Engines/Treasures of Tokuno/TreasuresOfTokunoPersistance.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; + +namespace Server.Misc +{ + public class TreasuresOfTokunoPersistance : Item + { + private static TreasuresOfTokunoPersistance m_Instance; + + public static TreasuresOfTokunoPersistance Instance{ get{ return m_Instance; } } + + public override string DefaultName + { + get { return "TreasuresOfTokuno Persistance - Internal"; } + } + + public static void Initialize() + { + if ( m_Instance == null ) + new TreasuresOfTokunoPersistance(); + } + + public TreasuresOfTokunoPersistance() : base( 1 ) + { + Movable = false; + + if ( m_Instance == null || m_Instance.Deleted ) + m_Instance = this; + else + base.Delete(); + } + + public TreasuresOfTokunoPersistance( Serial serial ) : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteEncodedInt( (int)TreasuresOfTokuno.RewardEra ); + writer.WriteEncodedInt( (int)TreasuresOfTokuno.DropEra ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + TreasuresOfTokuno.RewardEra = (TreasuresOfTokunoEra)reader.ReadEncodedInt(); + TreasuresOfTokuno.DropEra = (TreasuresOfTokunoEra)reader.ReadEncodedInt(); + + break; + } + } + } + + public override void Delete() + { + } + } +} diff --git a/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs b/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs new file mode 100644 index 0000000..e11370b --- /dev/null +++ b/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatue.cs @@ -0,0 +1,672 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Spells; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Accounting; +using Server.ContextMenus; +using Server.Engines.VeteranRewards; + +namespace Server.Mobiles +{ + public enum StatueType + { + Marble, + Jade, + Bronze + } + + public enum StatuePose + { + Ready, + Casting, + Salute, + AllPraiseMe, + Fighting, + HandsOnHips + } + + public enum StatueMaterial + { + Antique, + Dark, + Medium, + Light + } + + public class CharacterStatue : Mobile, IRewardItem + { + private StatueType m_Type; + private StatuePose m_Pose; + private StatueMaterial m_Material; + + [CommandProperty(AccessLevel.GameMaster)] + public StatueType StatueType + { + get { return m_Type; } + set { m_Type = value; InvalidateHues(); InvalidatePose(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public StatuePose Pose + { + get { return m_Pose; } + set { m_Pose = value; InvalidatePose(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public StatueMaterial Material + { + get { return m_Material; } + set { m_Material = value; InvalidateHues(); InvalidatePose(); } + } + + private Mobile m_SculptedBy; + private DateTime m_SculptedOn; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile SculptedBy + { + get { return m_SculptedBy; } + set { m_SculptedBy = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime SculptedOn + { + get { return m_SculptedOn; } + set { m_SculptedOn = value; } + } + + private CharacterStatuePlinth m_Plinth; + + public CharacterStatuePlinth Plinth + { + get { return m_Plinth; } + set { m_Plinth = value; } + } + + private bool m_IsRewardItem; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; } + } + + public CharacterStatue(Mobile from, StatueType type) + : base() + { + m_Type = type; + m_Pose = StatuePose.Ready; + m_Material = StatueMaterial.Antique; + + Direction = Direction.South; + AccessLevel = AccessLevel.Counselor; + Hits = HitsMax; + Blessed = true; + Frozen = true; + + CloneBody(from); + CloneClothes(from); + InvalidateHues(); + } + + public CharacterStatue(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + DisplayPaperdollTo(from); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_SculptedBy != null) + { + if (m_SculptedBy.ShowFameTitle && (m_SculptedBy.Player || m_SculptedBy.Body.IsHuman) && m_SculptedBy.Fame >= 10000) + list.Add(1076202, String.Format("{0} {1}", m_SculptedBy.Female ? "Lady" : "Lord", m_SculptedBy.Name)); // Sculpted by ~1_Name~ + else + list.Add(1076202, m_SculptedBy.Name); // Sculpted by ~1_Name~ + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && m_SculptedBy != null) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if ((house != null && house.IsCoOwner(from)) || (int)from.AccessLevel > (int)AccessLevel.Counselor) + list.Add(new DemolishEntry(this)); + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Plinth != null && !m_Plinth.Deleted) + m_Plinth.Delete(); + } + + protected override void OnMapChange(Map oldMap) + { + InvalidatePose(); + + if (m_Plinth != null) + m_Plinth.Map = Map; + } + + protected override void OnLocationChange(Point3D oldLocation) + { + InvalidatePose(); + + if (m_Plinth != null) + m_Plinth.Location = new Point3D(X, Y, Z - 5); + } + + public override bool CanBeRenamedBy(Mobile from) + { + return false; + } + + public override bool CanBeDamaged() + { + return false; + } + + public void OnRequestedAnimation(Mobile from) + { + from.Send(new UpdateStatueAnimation(this, 1, m_Animation, m_Frames)); + } + + public override void OnAosSingleClick(Mobile from) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + + writer.Write((int)m_Type); + writer.Write((int)m_Pose); + writer.Write((int)m_Material); + + writer.Write((Mobile)m_SculptedBy); + writer.Write((DateTime)m_SculptedOn); + + writer.Write((Item)m_Plinth); + writer.Write((bool)m_IsRewardItem); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Type = (StatueType)reader.ReadInt(); + m_Pose = (StatuePose)reader.ReadInt(); + m_Material = (StatueMaterial)reader.ReadInt(); + + m_SculptedBy = reader.ReadMobile(); + m_SculptedOn = reader.ReadDateTime(); + + m_Plinth = reader.ReadItem() as CharacterStatuePlinth; + m_IsRewardItem = reader.ReadBool(); + + InvalidatePose(); + + Frozen = true; + + if (m_SculptedBy == null || Map == Map.Internal) // Remove preview statues + { + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + } + } + + public void Sculpt(Mobile by) + { + m_SculptedBy = by; + m_SculptedOn = DateTime.Now; + + InvalidateProperties(); + } + + public bool Demolish(Mobile by) + { + CharacterStatueDeed deed = new CharacterStatueDeed(null); + + if (by.PlaceInBackpack(deed)) + { + Delete(); + + deed.Statue = this; + deed.StatueType = m_Type; + deed.IsRewardItem = m_IsRewardItem; + + if (m_Plinth != null) + m_Plinth.Delete(); + + return true; + } + else + { + by.SendLocalizedMessage(500720); // You don't have enough room in your backpack! + deed.Delete(); + + return false; + } + } + + public void Restore(CharacterStatue from) + { + m_Material = from.Material; + m_Pose = from.Pose; + + Direction = from.Direction; + + CloneBody(from); + CloneClothes(from); + + InvalidateHues(); + InvalidatePose(); + } + + public void CloneBody(Mobile from) + { + Name = from.Name; + BodyValue = from.BodyValue; + Female = from.Female; + HairItemID = from.HairItemID; + FacialHairItemID = from.FacialHairItemID; + } + + public void CloneClothes(Mobile from) + { + for (int i = Items.Count - 1; i >= 0; i--) + Items[i].Delete(); + + for (int i = from.Items.Count - 1; i >= 0; i--) + { + Item item = from.Items[i]; + + if (item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank) + AddItem(CloneItem(item)); + } + } + + public Item CloneItem(Item item) + { + Item cloned = new Item(item.ItemID); + cloned.Layer = item.Layer; + cloned.Name = item.Name; + cloned.Hue = item.Hue; + cloned.Weight = item.Weight; + cloned.Movable = false; + + return cloned; + } + + public void InvalidateHues() + { + Hue = 0xB8F + (int)m_Type * 4 + (int)m_Material; + + HairHue = Hue; + + if (FacialHairItemID > 0) + FacialHairHue = Hue; + + for (int i = Items.Count - 1; i >= 0; i--) + Items[i].Hue = Hue; + + if (m_Plinth != null) + m_Plinth.InvalidateHue(); + } + + private int m_Animation; + private int m_Frames; + + public void InvalidatePose() + { + switch (m_Pose) + { + case StatuePose.Ready: + m_Animation = 4; + m_Frames = 0; + break; + case StatuePose.Casting: + m_Animation = 16; + m_Frames = 2; + break; + case StatuePose.Salute: + m_Animation = 33; + m_Frames = 1; + break; + case StatuePose.AllPraiseMe: + m_Animation = 17; + m_Frames = 4; + break; + case StatuePose.Fighting: + m_Animation = 31; + m_Frames = 5; + break; + case StatuePose.HandsOnHips: + m_Animation = 6; + m_Frames = 1; + break; + } + + if (Map != null) + { + ProcessDelta(); + + Packet p = null; + + IPooledEnumerable eable = Map.GetClientsInRange(Location); + + foreach (NetState state in eable) + { + state.Mobile.ProcessDelta(); + + if (p == null) + p = Packet.Acquire(new UpdateStatueAnimation(this, 1, m_Animation, m_Frames)); + + state.Send(p); + } + + Packet.Release(p); + + eable.Free(); + } + } + + private class DemolishEntry : ContextMenuEntry + { + private CharacterStatue m_Statue; + + public DemolishEntry(CharacterStatue statue) + : base(6275, 2) + { + m_Statue = statue; + } + + public override void OnClick() + { + if (m_Statue.Deleted) + return; + + m_Statue.Demolish(Owner.From); + } + } + } + + public class CharacterStatueDeed : Item, IRewardItem + { + public override int LabelNumber + { + get + { + StatueType t = m_Type; + + if (m_Statue != null) + { + t = m_Statue.StatueType; + } + + switch (t) + { + case StatueType.Marble: return 1076189; + case StatueType.Jade: return 1076188; + case StatueType.Bronze: return 1076190; + default: return 1076173; + } + } + } + + private CharacterStatue m_Statue; + private StatueType m_Type; + private bool m_IsRewardItem; + + [CommandProperty(AccessLevel.GameMaster)] + public CharacterStatue Statue + { + get { return m_Statue; } + set { m_Statue = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public StatueType StatueType + { + get + { + if (m_Statue != null) + return m_Statue.StatueType; + + return m_Type; + } + set { m_Type = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; InvalidateProperties(); } + } + + public CharacterStatueDeed(CharacterStatue statue) + : base(0x14F0) + { + m_Statue = statue; + + if (statue != null) + { + m_Type = statue.StatueType; + m_IsRewardItem = statue.IsRewardItem; + } + + LootType = LootType.Blessed; + Weight = 1.0; + } + + public CharacterStatueDeed(Serial serial) + : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076222); // 6th Year Veteran Reward + + if (m_Statue != null) + list.Add(1076231, m_Statue.Name); // Statue of ~1_Name~ + } + + public override void OnDoubleClick(Mobile from) + { + Account acct = from.Account as Account; + + if (acct != null && from.AccessLevel == AccessLevel.Player) + { + TimeSpan time = TimeSpan.FromDays(RewardSystem.RewardInterval.TotalDays * 6) - (DateTime.Now - acct.Created); + + if (time > TimeSpan.Zero) + { + from.SendLocalizedMessage(1008126, true, Math.Ceiling(time.TotalDays / RewardSystem.RewardInterval.TotalDays).ToString()); // Your account is not old enough to use this item. Months until you can use this item : + return; + } + } + + if (IsChildOf(from.Backpack)) + { + if (!from.IsBodyMod) + { + from.SendLocalizedMessage(1076194); // Select a place where you would like to put your statue. + from.Target = new CharacterStatueTarget(this, StatueType); + } + else + from.SendLocalizedMessage(1073648); // You may only proceed while in your original state... + } + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void OnDelete() + { + base.OnDelete(); + + if (m_Statue != null) + m_Statue.Delete(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)1); // version + + writer.Write((int)m_Type); + + writer.Write((Mobile)m_Statue); + writer.Write((bool)m_IsRewardItem); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version >= 1) + { + m_Type = (StatueType)reader.ReadInt(); + } + + m_Statue = reader.ReadMobile() as CharacterStatue; + m_IsRewardItem = reader.ReadBool(); + } + } + + public class CharacterStatueTarget : Target + { + private Item m_Maker; + private StatueType m_Type; + + public CharacterStatueTarget(Item maker, StatueType type) + : base(-1, true, TargetFlags.None) + { + m_Maker = maker; + m_Type = type; + } + + protected override void OnTarget(Mobile from, object targeted) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if (p == null || map == null || m_Maker == null || m_Maker.Deleted) + return; + + if (m_Maker.IsChildOf(from.Backpack)) + { + SpellHelper.GetSurfaceTop(ref p); + BaseHouse house = null; + Point3D loc = new Point3D(p); + + if (targeted is Item && !((Item)targeted).IsLockedDown && !((Item)targeted).IsSecure && !(targeted is AddonComponent)) + { + from.SendLocalizedMessage(1076191); // Statues can only be placed in houses. + return; + } + else if (from.IsBodyMod) + { + from.SendLocalizedMessage(1073648); // You may only proceed while in your original state... + return; + } + + AddonFitResult result = CouldFit(loc, map, from, ref house); + + if (result == AddonFitResult.Valid) + { + CharacterStatue statue = new CharacterStatue(from, m_Type); + CharacterStatuePlinth plinth = new CharacterStatuePlinth(statue); + + house.Addons.Add(plinth); + + if (m_Maker is IRewardItem) + statue.IsRewardItem = ((IRewardItem)m_Maker).IsRewardItem; + + statue.Plinth = plinth; + plinth.MoveToWorld(loc, map); + statue.InvalidatePose(); + + /* + * TODO: Previously the maker wasn't deleted until after statue + * customization, leading to redeeding issues. Exact OSI behavior + * needs looking into. + */ + m_Maker.Delete(); + statue.Sculpt(from); + + from.CloseGump(typeof(CharacterStatueGump)); + from.SendGump(new CharacterStatueGump(m_Maker, statue, from)); + } + else if (result == AddonFitResult.Blocked) + from.SendLocalizedMessage(500269); // You cannot build that there. + else if (result == AddonFitResult.NotInHouse) + from.SendLocalizedMessage(1076192); // Statues can only be placed in houses where you are the owner or co-owner. + else if (result == AddonFitResult.DoorTooClose) + from.SendLocalizedMessage(500271); // You cannot build near the door. + } + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public static AddonFitResult CouldFit(Point3D p, Map map, Mobile from, ref BaseHouse house) + { + if (!map.CanFit(p.X, p.Y, p.Z, 20, true, true, true)) + return AddonFitResult.Blocked; + else if (!BaseAddon.CheckHouse(from, p, map, 20, ref house)) + return AddonFitResult.NotInHouse; + else + return CheckDoors(p, 20, house); + } + + public static AddonFitResult CheckDoors(Point3D p, int height, BaseHouse house) + { + ArrayList doors = house.Doors; + + for (int i = 0; i < doors.Count; i++) + { + BaseDoor door = doors[i] as BaseDoor; + + Point3D doorLoc = door.GetWorldLocation(); + int doorHeight = door.ItemData.CalcHeight; + + if (Utility.InRange(doorLoc, p, 1) && (p.Z == doorLoc.Z || ((p.Z + height) > doorLoc.Z && (doorLoc.Z + doorHeight) > p.Z))) + return AddonFitResult.DoorTooClose; + } + + return AddonFitResult.Valid; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatueMaker.cs b/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatueMaker.cs new file mode 100644 index 0000000..5dd2846 --- /dev/null +++ b/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatueMaker.cs @@ -0,0 +1,182 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targets; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class CharacterStatueMaker : Item, IRewardItem + { + public override int LabelNumber { get { return 1076173; } } // Character Statue Maker + + private bool m_IsRewardItem; + private StatueType m_Type; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public StatueType StatueType + { + get { return m_Type; } + set { m_Type = value; InvalidateHue(); } + } + + public CharacterStatueMaker(StatueType type) + : base(0x32F0) + { + m_Type = type; + + InvalidateHue(); + + LootType = LootType.Blessed; + Weight = 5.0; + } + + public CharacterStatueMaker(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this, new object[] { m_Type })) + return; + + if (IsChildOf(from.Backpack)) + { + if (!from.IsBodyMod) + { + from.SendLocalizedMessage(1076194); // Select a place where you would like to put your statue. + from.Target = new CharacterStatueTarget(this, m_Type); + } + else + from.SendLocalizedMessage(1073648); // You may only proceed while in your original state... + } + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076222); // 6th Year Veteran Reward + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + + writer.Write((bool)m_IsRewardItem); + writer.Write((int)m_Type); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Type = (StatueType)reader.ReadInt(); + } + + public void InvalidateHue() + { + Hue = 0xB8F + (int)m_Type * 4; + } + } + + public class MarbleStatueMaker : CharacterStatueMaker + { + [Constructable] + public MarbleStatueMaker() + : base(StatueType.Marble) + { + } + + public MarbleStatueMaker(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class JadeStatueMaker : CharacterStatueMaker + { + [Constructable] + public JadeStatueMaker() + : base(StatueType.Jade) + { + } + + public JadeStatueMaker(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class BronzeStatueMaker : CharacterStatueMaker + { + [Constructable] + public BronzeStatueMaker() + : base(StatueType.Bronze) + { + } + + public BronzeStatueMaker(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatuePlinth.cs b/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatuePlinth.cs new file mode 100644 index 0000000..4c830d1 --- /dev/null +++ b/Scripts/Engines/VeteranRewards/Character Statue Maker/CharacterStatuePlinth.cs @@ -0,0 +1,135 @@ +using System; +using System.Globalization; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Multis; +using Server.Targets; + +namespace Server.Items +{ + public class CharacterStatuePlinth : Static, IAddon + { + public Item Deed { get { return new CharacterStatueDeed(m_Statue); } } + public override int LabelNumber { get { return 1076201; } } // Character Statue + + private CharacterStatue m_Statue; + + public CharacterStatuePlinth(CharacterStatue statue) + : base(0x32F2) + { + m_Statue = statue; + + InvalidateHue(); + } + + public CharacterStatuePlinth(Serial serial) + : base(serial) + { + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Statue != null && !m_Statue.Deleted) + m_Statue.Delete(); + } + + public override void OnMapChange() + { + if (m_Statue != null) + m_Statue.Map = Map; + } + + public override void OnLocationChange(Point3D oldLocation) + { + if (m_Statue != null) + m_Statue.Location = new Point3D(X, Y, Z + 5); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_Statue != null) + from.SendGump(new CharacterPlinthGump(m_Statue)); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + + writer.Write((Mobile)m_Statue); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Statue = reader.ReadMobile() as CharacterStatue; + + if (m_Statue == null || m_Statue.SculptedBy == null || Map == Map.Internal) + { + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(Delete)); + } + } + + public void InvalidateHue() + { + if (m_Statue != null) + Hue = 0xB8F + (int)m_Statue.StatueType * 4 + (int)m_Statue.Material; + } + + public virtual bool CouldFit(IPoint3D p, Map map) + { + Point3D point = new Point3D(p.X, p.Y, p.Z); + + if (map == null || !map.CanFit(point, 20)) + return false; + + BaseHouse house = BaseHouse.FindHouseAt(point, map, 20); + + if (house == null) + return false; + + AddonFitResult result = CharacterStatueTarget.CheckDoors(point, 20, house); + + if (result == AddonFitResult.Valid) + return true; + + return false; + } + + private class CharacterPlinthGump : Gump + { + public CharacterPlinthGump(CharacterStatue statue) + : base(60, 30) + { + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage(0); + AddImage(0, 0, 0x24F4); + AddHtml(55, 50, 150, 20, statue.Name, false, false); + AddHtml(55, 75, 150, 20, statue.SculptedOn.ToString(), false, false); + AddHtmlLocalized(55, 100, 150, 20, GetTypeNumber(statue.StatueType), 0, false, false); + } + + public int GetTypeNumber(StatueType type) + { + switch (type) + { + case StatueType.Marble: return 1076181; + case StatueType.Jade: return 1076180; + case StatueType.Bronze: return 1076230; + default: return 1076181; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs b/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs new file mode 100644 index 0000000..57dbd21 --- /dev/null +++ b/Scripts/Engines/VeteranRewards/Character Statue Maker/Gumps/CharacterStatueGump.cs @@ -0,0 +1,203 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Gumps +{ + public class CharacterStatueGump : Gump + { + private Item m_Maker; + private CharacterStatue m_Statue; + private Mobile m_Owner; + + private enum Buttons + { + Close, + Sculpt, + PosePrev, + PoseNext, + DirPrev, + DirNext, + MatPrev, + MatNext, + Restore + } + + public CharacterStatueGump(Item maker, CharacterStatue statue, Mobile owner) + : base(60, 36) + { + m_Maker = maker; + m_Statue = statue; + m_Owner = owner; + + if (m_Statue == null) + return; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 327, 324, 0x13BE); + AddImageTiled(10, 10, 307, 20, 0xA40); + AddImageTiled(10, 40, 307, 244, 0xA40); + AddImageTiled(10, 294, 307, 20, 0xA40); + AddAlphaRegion(10, 10, 307, 304); + AddHtmlLocalized(14, 12, 327, 20, 1076156, 0x7FFF, false, false); // Character Statue Maker + + // pose + AddHtmlLocalized(133, 41, 120, 20, 1076168, 0x7FFF, false, false); // Choose Pose + AddHtmlLocalized(133, 61, 120, 20, 1076208 + (int)m_Statue.Pose, 0x77E, false, false); + AddButton(163, 81, 0xFA5, 0xFA7, (int)Buttons.PoseNext, GumpButtonType.Reply, 0); + AddButton(133, 81, 0xFAE, 0xFB0, (int)Buttons.PosePrev, GumpButtonType.Reply, 0); + + // direction + AddHtmlLocalized(133, 126, 120, 20, 1076170, 0x7FFF, false, false); // Choose Direction + AddHtmlLocalized(133, 146, 120, 20, GetDirectionNumber(m_Statue.Direction), 0x77E, false, false); + AddButton(163, 167, 0xFA5, 0xFA7, (int)Buttons.DirNext, GumpButtonType.Reply, 0); + AddButton(133, 167, 0xFAE, 0xFB0, (int)Buttons.DirPrev, GumpButtonType.Reply, 0); + + // material + AddHtmlLocalized(133, 211, 120, 20, 1076171, 0x7FFF, false, false); // Choose Material + AddHtmlLocalized(133, 231, 120, 20, GetMaterialNumber(m_Statue.StatueType, m_Statue.Material), 0x77E, false, false); + AddButton(163, 253, 0xFA5, 0xFA7, (int)Buttons.MatNext, GumpButtonType.Reply, 0); + AddButton(133, 253, 0xFAE, 0xFB0, (int)Buttons.MatPrev, GumpButtonType.Reply, 0); + + // cancel + AddButton(10, 294, 0xFB1, 0xFB2, (int)Buttons.Close, GumpButtonType.Reply, 0); + AddHtmlLocalized(45, 294, 80, 20, 1006045, 0x7FFF, false, false); // Cancel + + // sculpt + AddButton(234, 294, 0xFB7, 0xFB9, (int)Buttons.Sculpt, GumpButtonType.Reply, 0); + AddHtmlLocalized(269, 294, 80, 20, 1076174, 0x7FFF, false, false); // Sculpt + + // restore + if (m_Maker is CharacterStatueDeed) + { + AddButton(107, 294, 0xFAB, 0xFAD, (int)Buttons.Restore, GumpButtonType.Reply, 0); + AddHtmlLocalized(142, 294, 80, 20, 1076193, 0x7FFF, false, false); // Restore + } + } + + private int GetMaterialNumber(StatueType type, StatueMaterial material) + { + switch (material) + { + case StatueMaterial.Antique: + + switch (type) + { + case StatueType.Bronze: return 1076187; + case StatueType.Jade: return 1076186; + case StatueType.Marble: return 1076182; + } + + return 1076187; + case StatueMaterial.Dark: + + if (type == StatueType.Marble) + return 1076183; + + return 1076182; + case StatueMaterial.Medium: return 1076184; + case StatueMaterial.Light: return 1076185; + default: return 1076187; + } + } + + private int GetDirectionNumber(Direction direction) + { + switch (direction) + { + case Direction.North: return 1075389; + case Direction.Right: return 1075388; + case Direction.East: return 1075387; + case Direction.Down: return 1076204; + case Direction.South: return 1075386; + case Direction.Left: return 1075391; + case Direction.West: return 1075390; + case Direction.Up: return 1076205; + default: return 1075386; + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Statue == null || m_Statue.Deleted) + return; + + bool sendGump = false; + + if (info.ButtonID == (int)Buttons.Sculpt) + { + if (m_Maker is CharacterStatueDeed) + { + CharacterStatue backup = ((CharacterStatueDeed)m_Maker).Statue; + + if (backup != null) + backup.Delete(); + } + + if (m_Maker != null) + m_Maker.Delete(); + + m_Statue.Sculpt(state.Mobile); + } + else if (info.ButtonID == (int)Buttons.PosePrev) + { + m_Statue.Pose = (StatuePose)(((int)m_Statue.Pose + 5) % 6); + sendGump = true; + } + else if (info.ButtonID == (int)Buttons.PoseNext) + { + m_Statue.Pose = (StatuePose)(((int)m_Statue.Pose + 1) % 6); + sendGump = true; + } + else if (info.ButtonID == (int)Buttons.DirPrev) + { + m_Statue.Direction = (Direction)(((int)m_Statue.Direction + 7) % 8); + m_Statue.InvalidatePose(); + sendGump = true; + } + else if (info.ButtonID == (int)Buttons.DirNext) + { + m_Statue.Direction = (Direction)(((int)m_Statue.Direction + 1) % 8); + m_Statue.InvalidatePose(); + sendGump = true; + } + else if (info.ButtonID == (int)Buttons.MatPrev) + { + m_Statue.Material = (StatueMaterial)(((int)m_Statue.Material + 3) % 4); + sendGump = true; + } + else if (info.ButtonID == (int)Buttons.MatNext) + { + m_Statue.Material = (StatueMaterial)(((int)m_Statue.Material + 1) % 4); + sendGump = true; + } + else if (info.ButtonID == (int)Buttons.Restore) + { + if (m_Maker is CharacterStatueDeed) + { + CharacterStatue backup = ((CharacterStatueDeed)m_Maker).Statue; + + if (backup != null) + m_Statue.Restore(backup); + } + + sendGump = true; + } + else // Close + { + sendGump = !m_Statue.Demolish(state.Mobile); + } + + if (sendGump) + state.Mobile.SendGump(new CharacterStatueGump(m_Maker, m_Statue, m_Owner)); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs b/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs new file mode 100644 index 0000000..5fa958b --- /dev/null +++ b/Scripts/Engines/VeteranRewards/Character Statue Maker/Packets.cs @@ -0,0 +1,23 @@ +using System; +using Server; + +namespace Server.Network +{ + public class UpdateStatueAnimation : Packet + { + public UpdateStatueAnimation( Mobile m, int status, int animation, int frame ) : base( 0xBF, 17 ) + { + m_Stream.Write( (short) 0x11 ); + m_Stream.Write( (short) 0x19 ); + m_Stream.Write( (byte) 0x5 ); + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0xFF ); + m_Stream.Write( (byte) status ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) animation ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) frame ); + } + } +} diff --git a/Scripts/Engines/VeteranRewards/RewardCategory.cs b/Scripts/Engines/VeteranRewards/RewardCategory.cs new file mode 100644 index 0000000..691d75a --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardCategory.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Engines.VeteranRewards +{ + public class RewardCategory + { + private int m_Name; + private string m_NameString; + private List m_Entries; + + public int Name{ get{ return m_Name; } } + public string NameString{ get{ return m_NameString; } } + public List Entries { get { return m_Entries; } } + + public RewardCategory( int name ) + { + m_Name = name; + m_Entries = new List(); + } + + public RewardCategory( string name ) + { + m_NameString = name; + m_Entries = new List(); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/RewardChoiceGump.cs b/Scripts/Engines/VeteranRewards/RewardChoiceGump.cs new file mode 100644 index 0000000..e77dd07 --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardChoiceGump.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.VeteranRewards +{ + public class RewardChoiceGump : Gump + { + private Mobile m_From; + + private void RenderBackground() + { + AddPage( 0 ); + + AddBackground( 10, 10, 600, 450, 2600 ); + + AddButton( 530, 415, 4017, 4019, 0, GumpButtonType.Reply, 0 ); + + AddButton( 60, 415, 4014, 4016, 0, GumpButtonType.Page, 1 ); + AddHtmlLocalized( 95, 415, 200, 20, 1049755, false, false ); // Main Menu + } + + private void RenderCategories() + { + TimeSpan rewardInterval = RewardSystem.RewardInterval; + + string intervalAsString; + + if ( rewardInterval == TimeSpan.FromDays( 30.0 ) ) + intervalAsString = "month"; + else if ( rewardInterval == TimeSpan.FromDays( 60.0 ) ) + intervalAsString = "two months"; + else if ( rewardInterval == TimeSpan.FromDays( 90.0 ) ) + intervalAsString = "three months"; + else if ( rewardInterval == TimeSpan.FromDays( 365.0 ) ) + intervalAsString = "year"; + else + intervalAsString = String.Format( "{0} day{1}", rewardInterval.TotalDays, rewardInterval.TotalDays == 1 ? "" : "s" ); + + AddPage( 1 ); + + AddHtml( 60, 35, 500, 70, "Ultima Online Rewards Program
" + + "Thank you for being a part of the Ultima Online community for a full " + intervalAsString + ". " + + "As a token of our appreciation, you may select from the following in-game reward items listed below. " + + "The gift items will be attributed to the character you have logged-in with on the shard you are on when you chose the item(s). " + + "The number of rewards you are entitled to are listed below and are for your entire account. " + + "To read more about these rewards before making a selection, feel free to visit the uo.com site at " + + "http://www.uo.com/rewards.", true, true ); + + int cur, max; + + RewardSystem.ComputeRewardInfo( m_From, out cur, out max ); + + AddHtmlLocalized( 60, 105, 300, 35, 1006006, false, false ); // Your current total of rewards to choose: + AddLabel( 370, 107, 50, (max - cur).ToString() ); + + AddHtmlLocalized( 60, 140, 300, 35, 1006007, false, false ); // You have already chosen: + AddLabel( 370, 142, 50, cur.ToString() ); + + RewardCategory[] categories = RewardSystem.Categories; + + int page = 2; + + for ( int i = 0; i < categories.Length; ++i ) + { + if ( !RewardSystem.HasAccess( m_From, categories[i] ) ) + { + page += 1; + continue; + } + + AddButton( 100, 180 + (i * 40), 4005, 4005, 0, GumpButtonType.Page, page ); + + page += PagesPerCategory( categories[ i ] ); + + if ( categories[i].NameString != null ) + AddHtml( 135, 180 + (i * 40), 300, 20, categories[i].NameString, false, false ); + else + AddHtmlLocalized( 135, 180 + (i * 40), 300, 20, categories[i].Name, false, false ); + } + + page = 2; + + for ( int i = 0; i < categories.Length; ++i ) + RenderCategory( categories[ i ], i, ref page ); + } + + private int PagesPerCategory( RewardCategory category ) + { + List entries = category.Entries; + int j = 0, i = 0; + + for ( j = 0; j < entries.Count; j++ ) + { + if ( RewardSystem.HasAccess( m_From, entries[ j ] ) ) + i++; + } + + return (int) Math.Ceiling( i / 24.0 ); + } + + private int GetButtonID( int type, int index ) + { + return 2 + (index * 20) + type; + } + + private void RenderCategory( RewardCategory category, int index, ref int page ) + { + AddPage( page ); + + List entries = category.Entries; + + int i = 0; + + for ( int j = 0; j < entries.Count; ++j ) + { + RewardEntry entry = entries[j]; + + if ( !RewardSystem.HasAccess( m_From, entry ) ) + continue; + + if ( i == 24 ) + { + AddButton( 305, 415, 0xFA5, 0xFA7, 0, GumpButtonType.Page, ++page ); + AddHtmlLocalized( 340, 415, 200, 20, 1011066, false, false ); // Next page + + AddPage( page ); + + AddButton( 270, 415, 0xFAE, 0xFB0, 0, GumpButtonType.Page, page - 1 ); + AddHtmlLocalized( 185, 415, 200, 20, 1011067, false, false ); // Previous page + + i = 0; + } + + AddButton( 55 + ((i / 12) * 250), 80 + ((i % 12) * 25), 5540, 5541, GetButtonID( index, j ), GumpButtonType.Reply, 0 ); + + if ( entry.NameString != null ) + AddHtml( 80 + ((i / 12) * 250), 80 + ((i % 12) * 25), 250, 20, entry.NameString, false, false ); + else + AddHtmlLocalized( 80 + ((i / 12) * 250), 80 + ((i % 12) * 25), 250, 20, entry.Name, false, false ); + ++i; + } + + page += 1; + } + + public RewardChoiceGump( Mobile from ) : base( 0, 0 ) + { + m_From = from; + + from.CloseGump( typeof( RewardChoiceGump ) ); + + RenderBackground(); + RenderCategories(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int buttonID = info.ButtonID - 1; + + if ( buttonID == 0 ) + { + int cur, max; + + RewardSystem.ComputeRewardInfo( m_From, out cur, out max ); + + if ( cur < max ) + m_From.SendGump( new RewardNoticeGump( m_From ) ); + } + else + { + --buttonID; + + int type = (buttonID % 20); + int index = (buttonID / 20); + + RewardCategory[] categories = RewardSystem.Categories; + + if ( type >= 0 && type < categories.Length ) + { + RewardCategory category = categories[type]; + + if ( index >= 0 && index < category.Entries.Count ) + { + RewardEntry entry = category.Entries[index]; + + if ( !RewardSystem.HasAccess( m_From, entry ) ) + return; + + m_From.SendGump( new RewardConfirmGump( m_From, entry ) ); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/RewardConfirmGump.cs b/Scripts/Engines/VeteranRewards/RewardConfirmGump.cs new file mode 100644 index 0000000..4d254dd --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardConfirmGump.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.VeteranRewards +{ + public class RewardConfirmGump : Gump + { + private Mobile m_From; + private RewardEntry m_Entry; + + public RewardConfirmGump( Mobile from, RewardEntry entry ) : base( 0, 0 ) + { + m_From = from; + m_Entry = entry; + + from.CloseGump( typeof( RewardConfirmGump ) ); + + AddPage( 0 ); + + AddBackground( 10, 10, 500, 300, 2600 ); + + AddHtmlLocalized( 30, 55, 300, 35, 1006000, false, false ); // You have selected: + + if ( entry.NameString != null ) + AddHtml( 335, 55, 150, 35, entry.NameString, false, false ); + else + AddHtmlLocalized( 335, 55, 150, 35, entry.Name, false, false ); + + AddHtmlLocalized( 30, 95, 300, 35, 1006001, false, false ); // This will be assigned to this character: + AddLabel( 335, 95, 0, from.Name ); + + AddHtmlLocalized( 35, 160, 450, 90, 1006002, true, true ); // Are you sure you wish to select this reward for this character? You will not be able to transfer this reward to another character on another shard. Click 'ok' below to confirm your selection or 'cancel' to go back to the selection screen. + + AddButton( 60, 265, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 95, 266, 150, 35, 1006044, false, false ); // Ok + + AddButton( 295, 265, 4017, 4019, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 330, 266, 150, 35, 1006045, false, false ); // Cancel + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + if ( !RewardSystem.HasAccess( m_From, m_Entry ) ) + return; + + Item item = m_Entry.Construct(); + + if ( item != null ) + { + if ( item is Server.Items.RedSoulstone ) + ((Server.Items.RedSoulstone) item).Account = m_From.Account.Username; + + if ( RewardSystem.ConsumeRewardPoint( m_From ) ) + m_From.AddToBackpack( item ); + else + item.Delete(); + } + } + + int cur, max; + + RewardSystem.ComputeRewardInfo( m_From, out cur, out max ); + + if ( cur < max ) + m_From.SendGump( new RewardNoticeGump( m_From ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/RewardDemolitionGump.cs b/Scripts/Engines/VeteranRewards/RewardDemolitionGump.cs new file mode 100644 index 0000000..1b6352d --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardDemolitionGump.cs @@ -0,0 +1,73 @@ +using System; +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; + +namespace Server.Gumps +{ + public class RewardDemolitionGump : Gump + { + private IAddon m_Addon; + + private enum Buttons + { + Cancel, + Confirm, + } + + public RewardDemolitionGump( IAddon addon, int question ) : base( 150, 50 ) + { + m_Addon = addon; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddBackground( 0, 0, 220, 170, 0x13BE ); + AddBackground( 10, 10, 200, 150, 0xBB8 ); + + AddHtmlLocalized( 20, 30, 180, 60, question, false, false ); // Do you wish to re-deed this decoration? + + AddHtmlLocalized( 55, 100, 150, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 100, 0xFA5, 0xFA7, (int) Buttons.Confirm, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 125, 150, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 125, 0xFA5, 0xFA7, (int) Buttons.Cancel, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Item item = m_Addon as Item; + + if ( item == null || item.Deleted ) + return; + + if ( info.ButtonID == (int) Buttons.Confirm ) + { + Mobile m = sender.Mobile; + BaseHouse house = BaseHouse.FindHouseAt( m ); + + if ( house != null && house.IsOwner( m ) ) + { + if ( m.InRange( item.Location, 2 ) ) + { + Item deed = m_Addon.Deed; + + if ( deed != null ) + { + m.AddToBackpack( deed ); + house.Addons.Remove( item ); + item.Delete(); + } + } + else + m.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + else + m.SendLocalizedMessage( 1049784 ); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + } + } +} diff --git a/Scripts/Engines/VeteranRewards/RewardEntry.cs b/Scripts/Engines/VeteranRewards/RewardEntry.cs new file mode 100644 index 0000000..022eead --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardEntry.cs @@ -0,0 +1,81 @@ +using System; + +namespace Server.Engines.VeteranRewards +{ + public class RewardEntry + { + private RewardList m_List; + private RewardCategory m_Category; + private Type m_ItemType; + private Expansion m_RequiredExpansion; + private int m_Name; + private string m_NameString; + private object[] m_Args; + + public RewardList List{ get{ return m_List; } set{ m_List = value; } } + public RewardCategory Category{ get{ return m_Category; } } + public Type ItemType{ get{ return m_ItemType; } } + public Expansion RequiredExpansion{ get{ return m_RequiredExpansion; } } + public int Name{ get{ return m_Name; } } + public string NameString{ get{ return m_NameString; } } + public object[] Args{ get{ return m_Args; } } + + public Item Construct() + { + try + { + Item item = Activator.CreateInstance( m_ItemType, m_Args ) as Item; + + if ( item is IRewardItem ) + ((IRewardItem)item).IsRewardItem = true; + + return item; + } + catch + { + } + + return null; + } + + public RewardEntry( RewardCategory category, int name, Type itemType, params object[] args ) + { + m_Category = category; + m_ItemType = itemType; + m_RequiredExpansion = Expansion.None; + m_Name = name; + m_Args = args; + category.Entries.Add( this ); + } + + public RewardEntry( RewardCategory category, string name, Type itemType, params object[] args ) + { + m_Category = category; + m_ItemType = itemType; + m_RequiredExpansion = Expansion.None; + m_NameString = name; + m_Args = args; + category.Entries.Add( this ); + } + + public RewardEntry( RewardCategory category, int name, Type itemType, Expansion requiredExpansion, params object[] args ) + { + m_Category = category; + m_ItemType = itemType; + m_RequiredExpansion = requiredExpansion; + m_Name = name; + m_Args = args; + category.Entries.Add( this ); + } + + public RewardEntry( RewardCategory category, string name, Type itemType, Expansion requiredExpansion, params object[] args ) + { + m_Category = category; + m_ItemType = itemType; + m_RequiredExpansion = requiredExpansion; + m_NameString = name; + m_Args = args; + category.Entries.Add( this ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/RewardList.cs b/Scripts/Engines/VeteranRewards/RewardList.cs new file mode 100644 index 0000000..1688ec8 --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardList.cs @@ -0,0 +1,22 @@ +using System; + +namespace Server.Engines.VeteranRewards +{ + public class RewardList + { + private TimeSpan m_Age; + private RewardEntry[] m_Entries; + + public TimeSpan Age{ get{ return m_Age; } } + public RewardEntry[] Entries{ get{ return m_Entries; } } + + public RewardList( TimeSpan interval, int index, RewardEntry[] entries ) + { + m_Age = TimeSpan.FromDays( interval.TotalDays * index ); + m_Entries = entries; + + for ( int i = 0; i < entries.Length; ++i ) + entries[i].List = this; + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/RewardNoticeGump.cs b/Scripts/Engines/VeteranRewards/RewardNoticeGump.cs new file mode 100644 index 0000000..3e13e3d --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardNoticeGump.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Engines.VeteranRewards +{ + public class RewardNoticeGump : Gump + { + private Mobile m_From; + + public RewardNoticeGump( Mobile from ) : base( 0, 0 ) + { + m_From = from; + + from.CloseGump( typeof( RewardNoticeGump ) ); + + AddPage( 0 ); + + AddBackground( 10, 10, 500, 135, 2600 ); + + /* You have reward items available. + * Click 'ok' below to get the selection menu or 'cancel' to be prompted upon your next login. + */ + AddHtmlLocalized( 52, 35, 420, 55, 1006046, true, true ); + + AddButton( 60, 95, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 95, 96, 150, 35, 1006044, false, false ); // Ok + + AddButton( 285, 95, 4017, 4019, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 320, 96, 150, 35, 1006045, false, false ); // Cancel + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_From.SendGump( new RewardChoiceGump( m_From ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/VeteranRewards/RewardOptionGump.cs b/Scripts/Engines/VeteranRewards/RewardOptionGump.cs new file mode 100644 index 0000000..f4345cf --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardOptionGump.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; + +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Gumps +{ + public interface IRewardOption + { + void GetOptions( RewardOptionList list ); + void OnOptionSelected( Mobile from, int choice ); + } + + public class RewardOptionGump : Gump + { + private RewardOptionList m_Options = new RewardOptionList(); + private IRewardOption m_Option; + + public RewardOptionGump( IRewardOption option ) : this( option, 0 ) + { + } + + public RewardOptionGump( IRewardOption option, int title ) : base( 60, 36 ) + { + m_Option = option; + + if ( m_Option != null ) + m_Option.GetOptions( m_Options ); + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + + if ( title > 0 ) + AddHtmlLocalized( 14, 12, 273, 20, title, 0x7FFF, false, false ); + else + AddHtmlLocalized( 14, 12, 273, 20, 1080392, 0x7FFF, false, false ); // Select your choice from the menu below. + + AddPage( 1 ); + + for ( int i = 0; i < m_Options.Count; i++ ) + { + AddButton( 19, 49 + i * 24, 0x845, 0x846, m_Options[ i ].ID, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47 + i * 24, 213, 20, m_Options[ i ].Cliloc, 0x7FFF, false, false ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Option != null && Contains( info.ButtonID ) ) + m_Option.OnOptionSelected( sender.Mobile, info.ButtonID ); + } + + private bool Contains( int chosen ) + { + if ( m_Options == null ) + return false; + + foreach ( RewardOption option in m_Options ) + { + if ( option.ID == chosen ) + return true; + } + + return false; + } + } + + public class RewardOption + { + private int m_ID; + private int m_Cliloc; + + public int ID{ get{ return m_ID; } } + public int Cliloc{ get{ return m_Cliloc; } } + + public RewardOption( int id, int cliloc ) + { + m_ID = id; + m_Cliloc = cliloc; + } + } + + public class RewardOptionList : List + { + public RewardOptionList() : base() + { + } + + public void Add( int id, int cliloc ) + { + Add( new RewardOption( id, cliloc ) ); + } + } +} diff --git a/Scripts/Engines/VeteranRewards/RewardSystem.cs b/Scripts/Engines/VeteranRewards/RewardSystem.cs new file mode 100644 index 0000000..f1f06ec --- /dev/null +++ b/Scripts/Engines/VeteranRewards/RewardSystem.cs @@ -0,0 +1,524 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Accounting; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Engines.VeteranRewards +{ + public class RewardSystem + { + private static RewardCategory[] m_Categories; + private static RewardList[] m_Lists; + + public static RewardCategory[] Categories + { + get + { + if ( m_Categories == null ) + SetupRewardTables(); + + return m_Categories; + } + } + + public static RewardList[] Lists + { + get + { + if ( m_Lists == null ) + SetupRewardTables(); + + return m_Lists; + } + } + + public static bool Enabled = false; // change to true to enable vet rewards + public static bool SkillCapRewards = false; // assuming vet rewards are enabled, should total skill cap bonuses be awarded? (720 skills total at 4th level) + public static TimeSpan RewardInterval = TimeSpan.FromDays(30.0); + + public static bool HasAccess( Mobile mob, RewardCategory category ) + { + List entries = category.Entries; + + for ( int j = 0; j < entries.Count; ++j ) + { + //RewardEntry entry = entries[j]; + if ( RewardSystem.HasAccess( mob, entries[j] ) ) + { + return true; + } + } + return false; + } + + public static bool HasAccess( Mobile mob, RewardEntry entry ) + { + if ( Core.Expansion < entry.RequiredExpansion ) + { + return false; + } + + TimeSpan ts; + return HasAccess( mob, entry.List, out ts ); + } + + public static bool HasAccess( Mobile mob, RewardList list, out TimeSpan ts ) + { + if ( list == null ) + { + ts = TimeSpan.Zero; + return false; + } + + Account acct = mob.Account as Account; + + if ( acct == null ) + { + ts = TimeSpan.Zero; + return false; + } + + TimeSpan totalTime = (DateTime.Now - acct.Created); + + ts = ( list.Age - totalTime ); + + if ( ts <= TimeSpan.Zero ) + return true; + + return false; + } + + public static int GetRewardLevel( Mobile mob ) + { + Account acct = mob.Account as Account; + + if ( acct == null ) + return 0; + + return GetRewardLevel( acct ); + } + + public static int GetRewardLevel( Account acct ) + { + TimeSpan totalTime = (DateTime.Now - acct.Created); + + int level = (int)(totalTime.TotalDays / RewardInterval.TotalDays); + + if ( level < 0 ) + level = 0; + + return level; + } + + public static bool HasHalfLevel( Mobile mob ) + { + Account acct = mob.Account as Account; + + if ( acct == null ) + return false; + + return HasHalfLevel( acct ); + } + + public static bool HasHalfLevel( Account acct ) + { + TimeSpan totalTime = (DateTime.Now - acct.Created); + + Double level = (totalTime.TotalDays / RewardInterval.TotalDays); + + return level >= 0.5; + } + + public static bool ConsumeRewardPoint( Mobile mob ) + { + int cur, max; + + ComputeRewardInfo( mob, out cur, out max ); + + if ( cur >= max ) + return false; + + Account acct = mob.Account as Account; + + if ( acct == null ) + return false; + + //if ( mob.AccessLevel < AccessLevel.GameMaster ) + acct.SetTag( "numRewardsChosen", (cur + 1).ToString() ); + + return true; + } + + public static void ComputeRewardInfo( Mobile mob, out int cur, out int max ) + { + int level; + + ComputeRewardInfo( mob, out cur, out max, out level ); + } + + public static void ComputeRewardInfo( Mobile mob, out int cur, out int max, out int level ) + { + Account acct = mob.Account as Account; + + if ( acct == null ) + { + cur = max = level = 0; + return; + } + + level = GetRewardLevel( acct ); + + if ( level == 0 ) + { + cur = max = 0; + return; + } + + string tag = acct.GetTag( "numRewardsChosen" ); + + if ( String.IsNullOrEmpty( tag ) ) + cur = 0; + else + cur = Utility.ToInt32( tag ); + + if ( level >= 6 ) + max = 9 + ((level - 6) * 2); + else + max = 2 + level; + } + + public static bool CheckIsUsableBy( Mobile from, Item item, object[] args ) + { + if ( m_Lists == null ) + SetupRewardTables(); + + bool isRelaxedRules = ( item is DyeTub || item is MonsterStatuette ); + + Type type = item.GetType(); + + for ( int i = 0; i < m_Lists.Length; ++i ) + { + RewardList list = m_Lists[i]; + RewardEntry[] entries = list.Entries; + TimeSpan ts; + + for ( int j = 0; j < entries.Length; ++j ) + { + if ( entries[j].ItemType == type ) + { + if ( args == null && entries[j].Args.Length == 0 ) + { + if ( (!isRelaxedRules || i > 0) && !HasAccess( from, list, out ts ) ) + { + from.SendLocalizedMessage( 1008126, true, Math.Ceiling( ts.TotalDays / 30.0 ).ToString() ); // Your account is not old enough to use this item. Months until you can use this item : + return false; + } + + return true; + } + + if ( args.Length == entries[j].Args.Length ) + { + bool match = true; + + for ( int k = 0; match && k < args.Length; ++k ) + match = ( args[k].Equals( entries[j].Args[k] ) ); + + if ( match ) + { + if ( (!isRelaxedRules || i > 0) && !HasAccess( from, list, out ts ) ) + { + from.SendLocalizedMessage( 1008126, true, Math.Ceiling( ts.TotalDays / 30.0 ).ToString() ); // Your account is not old enough to use this item. Months until you can use this item : + return false; + } + + return true; + } + } + } + } + } + + // no entry? + return true; + } + + public static int GetRewardYearLabel(Item item, object[] args) + { + int level = GetRewardYear(item, args); + + return 1076216 + ((level < 10) ? level : (level < 12) ? ((level - 9) + 4240) : ((level - 11) + 37585)); + } + + public static int GetRewardYear( Item item, object[] args ) + { + if ( m_Lists == null ) + SetupRewardTables(); + + Type type = item.GetType(); + + for ( int i = 0; i < m_Lists.Length; ++i ) + { + RewardList list = m_Lists[i]; + RewardEntry[] entries = list.Entries; + + for ( int j = 0; j < entries.Length; ++j ) + { + if ( entries[j].ItemType == type ) + { + if ( args == null && entries[j].Args.Length == 0 ) + return i + 1; + + if ( args.Length == entries[j].Args.Length ) + { + bool match = true; + + for ( int k = 0; match && k < args.Length; ++k ) + match = ( args[k].Equals( entries[j].Args[k] ) ); + + if ( match ) + return i + 1; + } + } + } + } + + // no entry? + return 0; + } + + public static void SetupRewardTables() + { + RewardCategory monsterStatues = new RewardCategory( 1049750 ); + RewardCategory cloaksAndRobes = new RewardCategory( 1049752 ); + RewardCategory etherealSteeds = new RewardCategory( 1049751 ); + RewardCategory specialDyeTubs = new RewardCategory( 1049753 ); + RewardCategory houseAddOns = new RewardCategory( 1049754 ); + RewardCategory miscellaneous = new RewardCategory( 1078596 ); + + m_Categories = new RewardCategory[] + { + monsterStatues, + cloaksAndRobes, + etherealSteeds, + specialDyeTubs, + houseAddOns, + miscellaneous + }; + + const int Bronze = 0x972; + const int Copper = 0x96D; + const int Golden = 0x8A5; + const int Agapite = 0x979; + const int Verite = 0x89F; + const int Valorite = 0x8AB; + const int IceGreen = 0x47F; + const int IceBlue = 0x482; + const int DarkGray = 0x497; + const int Fire = 0x489; + const int IceWhite = 0x47E; + const int JetBlack = 0x001; + const int Pink = 0x490; + const int Crimson = 0x485; + + m_Lists = new RewardList[] + { + new RewardList( RewardInterval, 1, new RewardEntry[] + { + new RewardEntry( specialDyeTubs, 1006008, typeof( RewardBlackDyeTub ) ), + new RewardEntry( specialDyeTubs, 1006013, typeof( FurnitureDyeTub ) ), + new RewardEntry( specialDyeTubs, 1006047, typeof( SpecialDyeTub ) ), + new RewardEntry( cloaksAndRobes, 1006009, typeof( RewardCloak ), Bronze, 1041286 ), + new RewardEntry( cloaksAndRobes, 1006010, typeof( RewardRobe ), Bronze, 1041287 ), + new RewardEntry( cloaksAndRobes, 1080366, typeof( RewardDress ), Expansion.ML, Bronze, 1080366 ), + new RewardEntry( cloaksAndRobes, 1006011, typeof( RewardCloak ), Copper, 1041288 ), + new RewardEntry( cloaksAndRobes, 1006012, typeof( RewardRobe ), Copper, 1041289 ), + new RewardEntry( cloaksAndRobes, 1080367, typeof( RewardDress ), Expansion.ML, Copper, 1080367 ), + new RewardEntry( monsterStatues, 1006024, typeof( MonsterStatuette ), MonsterStatuetteType.Crocodile ), + new RewardEntry( monsterStatues, 1006025, typeof( MonsterStatuette ), MonsterStatuetteType.Daemon ), + new RewardEntry( monsterStatues, 1006026, typeof( MonsterStatuette ), MonsterStatuetteType.Dragon ), + new RewardEntry( monsterStatues, 1006027, typeof( MonsterStatuette ), MonsterStatuetteType.EarthElemental ), + new RewardEntry( monsterStatues, 1006028, typeof( MonsterStatuette ), MonsterStatuetteType.Ettin ), + new RewardEntry( monsterStatues, 1006029, typeof( MonsterStatuette ), MonsterStatuetteType.Gargoyle ), + new RewardEntry( monsterStatues, 1006030, typeof( MonsterStatuette ), MonsterStatuetteType.Gorilla ), + new RewardEntry( monsterStatues, 1006031, typeof( MonsterStatuette ), MonsterStatuetteType.Lich ), + new RewardEntry( monsterStatues, 1006032, typeof( MonsterStatuette ), MonsterStatuetteType.Lizardman ), + new RewardEntry( monsterStatues, 1006033, typeof( MonsterStatuette ), MonsterStatuetteType.Ogre ), + new RewardEntry( monsterStatues, 1006034, typeof( MonsterStatuette ), MonsterStatuetteType.Orc ), + new RewardEntry( monsterStatues, 1006035, typeof( MonsterStatuette ), MonsterStatuetteType.Ratman ), + new RewardEntry( monsterStatues, 1006036, typeof( MonsterStatuette ), MonsterStatuetteType.Skeleton ), + new RewardEntry( monsterStatues, 1006037, typeof( MonsterStatuette ), MonsterStatuetteType.Troll ), + new RewardEntry( houseAddOns, 1062692, typeof( ContestMiniHouseDeed ), Expansion.AOS, MiniHouseType.MalasMountainPass ), + new RewardEntry( houseAddOns, 1072216, typeof( ContestMiniHouseDeed ), Expansion.SE, MiniHouseType.ChurchAtNight ), + new RewardEntry( miscellaneous, 1076155, typeof( RedSoulstone ), Expansion.ML ), + new RewardEntry( miscellaneous, 1080523, typeof( CommodityDeedBox ), Expansion.ML ), + } ), + new RewardList( RewardInterval, 2, new RewardEntry[] + { + new RewardEntry( specialDyeTubs, 1006052, typeof( LeatherDyeTub ) ), + new RewardEntry( cloaksAndRobes, 1006014, typeof( RewardCloak ), Agapite, 1041290 ), + new RewardEntry( cloaksAndRobes, 1006015, typeof( RewardRobe ), Agapite, 1041291 ), + new RewardEntry( cloaksAndRobes, 1080369, typeof( RewardDress ), Expansion.ML, Agapite, 1080369 ), + new RewardEntry( cloaksAndRobes, 1006016, typeof( RewardCloak ), Golden, 1041292 ), + new RewardEntry( cloaksAndRobes, 1006017, typeof( RewardRobe ), Golden, 1041293 ), + new RewardEntry( cloaksAndRobes, 1080368, typeof( RewardDress ), Expansion.ML, Golden, 1080368 ), + new RewardEntry( houseAddOns, 1006048, typeof( BannerDeed ) ), + new RewardEntry( houseAddOns, 1006049, typeof( FlamingHeadDeed ) ), + new RewardEntry( houseAddOns, 1080409, typeof( MinotaurStatueDeed ), Expansion.ML ) + } ), + new RewardList( RewardInterval, 3, new RewardEntry[] + { + new RewardEntry( cloaksAndRobes, 1006020, typeof( RewardCloak ), Verite, 1041294 ), + new RewardEntry( cloaksAndRobes, 1006021, typeof( RewardRobe ), Verite, 1041295 ), + new RewardEntry( cloaksAndRobes, 1080370, typeof( RewardDress ), Expansion.ML, Verite, 1080370 ), + new RewardEntry( cloaksAndRobes, 1006022, typeof( RewardCloak ), Valorite, 1041296 ), + new RewardEntry( cloaksAndRobes, 1006023, typeof( RewardRobe ), Valorite, 1041297 ), + new RewardEntry( cloaksAndRobes, 1080371, typeof( RewardDress ), Expansion.ML, Valorite, 1080371 ), + new RewardEntry( monsterStatues, 1006038, typeof( MonsterStatuette ), MonsterStatuetteType.Cow ), + new RewardEntry( monsterStatues, 1006039, typeof( MonsterStatuette ), MonsterStatuetteType.Zombie ), + new RewardEntry( monsterStatues, 1006040, typeof( MonsterStatuette ), MonsterStatuetteType.Llama ), + new RewardEntry( etherealSteeds, 1006019, typeof( EtherealHorse ) ), + new RewardEntry( etherealSteeds, 1006050, typeof( EtherealOstard ) ), + new RewardEntry( etherealSteeds, 1006051, typeof( EtherealLlama ) ), + new RewardEntry( houseAddOns, 1080407, typeof( PottedCactusDeed ), Expansion.ML ) + + } ), + new RewardList( RewardInterval, 4, new RewardEntry[] + { + new RewardEntry( specialDyeTubs, 1049740, typeof( RunebookDyeTub ) ), + new RewardEntry( cloaksAndRobes, 1049725, typeof( RewardCloak ), DarkGray, 1049757 ), + new RewardEntry( cloaksAndRobes, 1049726, typeof( RewardRobe ), DarkGray, 1049756 ), + new RewardEntry( cloaksAndRobes, 1080374, typeof( RewardDress ), Expansion.ML, DarkGray, 1080374 ), + new RewardEntry( cloaksAndRobes, 1049727, typeof( RewardCloak ), IceGreen, 1049759 ), + new RewardEntry( cloaksAndRobes, 1049728, typeof( RewardRobe ), IceGreen, 1049758 ), + new RewardEntry( cloaksAndRobes, 1080372, typeof( RewardDress ), Expansion.ML, IceGreen, 1080372 ), + new RewardEntry( cloaksAndRobes, 1049729, typeof( RewardCloak ), IceBlue, 1049761 ), + new RewardEntry( cloaksAndRobes, 1049730, typeof( RewardRobe ), IceBlue, 1049760 ), + new RewardEntry( cloaksAndRobes, 1080373, typeof( RewardDress ), Expansion.ML, IceBlue, 1080373 ), + new RewardEntry( monsterStatues, 1049742, typeof( MonsterStatuette ), MonsterStatuetteType.Ophidian ), + new RewardEntry( monsterStatues, 1049743, typeof( MonsterStatuette ), MonsterStatuetteType.Reaper ), + new RewardEntry( monsterStatues, 1049744, typeof( MonsterStatuette ), MonsterStatuetteType.Mongbat ), + new RewardEntry( etherealSteeds, 1049746, typeof( EtherealKirin ) ), + new RewardEntry( etherealSteeds, 1049745, typeof( EtherealUnicorn ) ), + new RewardEntry( etherealSteeds, 1049747, typeof( EtherealRidgeback ) ), + new RewardEntry( houseAddOns, 1049737, typeof( DecorativeShieldDeed ) ), + new RewardEntry( houseAddOns, 1049738, typeof( HangingSkeletonDeed ) ) + } ), + new RewardList( RewardInterval, 5, new RewardEntry[] + { + new RewardEntry( specialDyeTubs, 1049741, typeof( StatuetteDyeTub ) ), + new RewardEntry( cloaksAndRobes, 1049731, typeof( RewardCloak ), JetBlack, 1049763 ), + new RewardEntry( cloaksAndRobes, 1049732, typeof( RewardRobe ), JetBlack, 1049762 ), + new RewardEntry( cloaksAndRobes, 1080377, typeof( RewardDress ), Expansion.ML, JetBlack, 1080377 ), + new RewardEntry( cloaksAndRobes, 1049733, typeof( RewardCloak ), IceWhite, 1049765 ), + new RewardEntry( cloaksAndRobes, 1049734, typeof( RewardRobe ), IceWhite, 1049764 ), + new RewardEntry( cloaksAndRobes, 1080376, typeof( RewardDress ), Expansion.ML, IceWhite, 1080376 ), + new RewardEntry( cloaksAndRobes, 1049735, typeof( RewardCloak ), Fire, 1049767 ), + new RewardEntry( cloaksAndRobes, 1049736, typeof( RewardRobe ), Fire, 1049766 ), + new RewardEntry( cloaksAndRobes, 1080375, typeof( RewardDress ), Expansion.ML, Fire, 1080375 ), + new RewardEntry( monsterStatues, 1049768, typeof( MonsterStatuette ), MonsterStatuetteType.Gazer ), + new RewardEntry( monsterStatues, 1049769, typeof( MonsterStatuette ), MonsterStatuetteType.FireElemental ), + new RewardEntry( monsterStatues, 1049770, typeof( MonsterStatuette ), MonsterStatuetteType.Wolf ), + new RewardEntry( etherealSteeds, 1049749, typeof( EtherealSwampDragon ) ), + new RewardEntry( etherealSteeds, 1049748, typeof( EtherealBeetle ) ), + new RewardEntry( houseAddOns, 1049739, typeof( StoneAnkhDeed ) ), + new RewardEntry( houseAddOns, 1080384, typeof( BloodyPentagramDeed ), Expansion.ML ) + } ), + new RewardList( RewardInterval, 6, new RewardEntry[] + { + new RewardEntry( houseAddOns, 1076188, typeof( CharacterStatueMaker ), Expansion.ML, StatueType.Jade ), + new RewardEntry( houseAddOns, 1076189, typeof( CharacterStatueMaker ), Expansion.ML, StatueType.Marble ), + new RewardEntry( houseAddOns, 1076190, typeof( CharacterStatueMaker ), Expansion.ML, StatueType.Bronze ), + new RewardEntry( houseAddOns, 1080527, typeof( RewardBrazierDeed ), Expansion.ML ) + } ), + new RewardList( RewardInterval, 7, new RewardEntry[] + { + new RewardEntry( houseAddOns, 1076157, typeof( CannonDeed ), Expansion.ML ), + new RewardEntry( houseAddOns, 1080550, typeof( TreeStumpDeed ), Expansion.ML ) + } ), + new RewardList( RewardInterval, 8, new RewardEntry[] + { + new RewardEntry( miscellaneous, 1076158, typeof( WeaponEngravingTool ), Expansion.ML ) + } ), + new RewardList( RewardInterval, 9, new RewardEntry[] + { + new RewardEntry( etherealSteeds, 1076159, typeof( RideablePolarBear ), Expansion.ML ), + new RewardEntry( houseAddOns, 1080549, typeof( WallBannerDeed ), Expansion.ML ) + } ), + new RewardList( RewardInterval, 10, new RewardEntry[] + { + new RewardEntry( monsterStatues, 1080520, typeof( MonsterStatuette ), Expansion.ML, MonsterStatuetteType.Harrower ), + new RewardEntry( monsterStatues, 1080521, typeof( MonsterStatuette ), Expansion.ML, MonsterStatuetteType.Efreet ), + + new RewardEntry( cloaksAndRobes, 1080382, typeof( RewardCloak ), Expansion.ML, Pink, 1080382 ), + new RewardEntry( cloaksAndRobes, 1080380, typeof( RewardRobe ), Expansion.ML, Pink, 1080380 ), + new RewardEntry( cloaksAndRobes, 1080378, typeof( RewardDress ), Expansion.ML, Pink, 1080378 ), + new RewardEntry( cloaksAndRobes, 1080383, typeof( RewardCloak ), Expansion.ML, Crimson, 1080383 ), + new RewardEntry( cloaksAndRobes, 1080381, typeof( RewardRobe ), Expansion.ML, Crimson, 1080381 ), + new RewardEntry( cloaksAndRobes, 1080379, typeof( RewardDress ), Expansion.ML, Crimson, 1080379 ), + + new RewardEntry( etherealSteeds, 1080386, typeof( EtherealCuSidhe ), Expansion.ML ), + + new RewardEntry( houseAddOns, 1080548, typeof( MiningCartDeed ), Expansion.ML ), + new RewardEntry( houseAddOns, 1080397, typeof( AnkhOfSacrificeDeed ), Expansion.ML ) + } ), + + new RewardList( RewardInterval, 11, new RewardEntry[] + { + new RewardEntry( etherealSteeds, 1113908, typeof( EtherealReptalon ), Expansion.ML ), + } ), + + new RewardList( RewardInterval, 12, new RewardEntry[] + { + new RewardEntry( etherealSteeds, 1113813, typeof( EtherealHiryu ), Expansion.ML ), + } ), + }; + } + + public static void Initialize() + { + if ( Enabled ) + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static void EventSink_Login( LoginEventArgs e ) + { + if ( !e.Mobile.Alive ) + return; + + int cur, max, level; + + ComputeRewardInfo( e.Mobile, out cur, out max, out level ); + + if ( e.Mobile.SkillsCap == 7000 || e.Mobile.SkillsCap == 7050 || e.Mobile.SkillsCap == 7100 || e.Mobile.SkillsCap == 7150 || e.Mobile.SkillsCap == 7200 ) + { + if ( level > 4 ) + level = 4; + else if ( level < 0 ) + level = 0; + + if ( SkillCapRewards ) + e.Mobile.SkillsCap = 7000 + (level * 50); + else + e.Mobile.SkillsCap = 7000; + } + + if ( Core.ML && e.Mobile is PlayerMobile && !((PlayerMobile)e.Mobile).HasStatReward && HasHalfLevel( e.Mobile ) ) + { + ((PlayerMobile)e.Mobile).HasStatReward = true; + e.Mobile.StatCap += 5; + } + + if ( cur < max ) + e.Mobile.SendGump( new RewardNoticeGump( e.Mobile ) ); + } + } + + public interface IRewardItem + { + bool IsRewardItem{ get; set; } + } +} diff --git a/Scripts/Engines/Virtues/Compassion.cs b/Scripts/Engines/Virtues/Compassion.cs new file mode 100644 index 0000000..6cf9323 --- /dev/null +++ b/Scripts/Engines/Virtues/Compassion.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; + +namespace Server +{ + public class CompassionVirtue + { + private static TimeSpan LossDelay = TimeSpan.FromDays( 7.0 ); + private const int LossAmount = 500; + + public static void Initialize() + { + VirtueGump.Register( 105, new OnVirtueUsed( OnVirtueUsed ) ); + } + + public static void OnVirtueUsed( Mobile from ) + { + from.SendLocalizedMessage( 1053001 ); // This virtue is not activated through the virtue menu. + } + + public static void CheckAtrophy( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + try + { + if ( (pm.LastCompassionLoss + LossDelay) < DateTime.Now ) + { + VirtueHelper.Atrophy( from, VirtueName.Compassion, LossAmount ); + //OSI has no cliloc message for losing compassion. Weird. + pm.LastCompassionLoss = DateTime.Now; + } + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/Honor.cs b/Scripts/Engines/Virtues/Honor.cs new file mode 100644 index 0000000..95d2087 --- /dev/null +++ b/Scripts/Engines/Virtues/Honor.cs @@ -0,0 +1,437 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Targeting; +using Server.Regions; + +namespace Server +{ + public class HonorVirtue + { + + private static readonly TimeSpan UseDelay = TimeSpan.FromMinutes(5.0); + + public static void Initialize() + { + VirtueGump.Register(107, new OnVirtueUsed(OnVirtueUsed)); + } + + private static void OnVirtueUsed(Mobile from) + { + if (from.Alive) + { + from.SendLocalizedMessage(1063160); // Target what you wish to honor. + from.Target = new InternalTarget(); + } + } + + private class InternalTarget : Target + { + public InternalTarget() + : base(12, false, TargetFlags.None) + { + CheckLOS = true; + } + + protected override void OnTarget(Mobile from, object targeted) + { + PlayerMobile pm = from as PlayerMobile; + if (pm == null) + return; + + if (targeted == pm) + { + EmbraceHonor(pm); + } + else if (targeted is Mobile) + Honor(pm, (Mobile)targeted); + } + + protected override void OnTargetOutOfRange(Mobile from, object targeted) + { + from.SendLocalizedMessage(1063232); // You are too far away to honor your opponent + } + } + + private static int GetHonorDuration(PlayerMobile from) + { + switch (VirtueHelper.GetLevel(from, VirtueName.Honor)) + { + case VirtueLevel.Seeker: return 30; + case VirtueLevel.Follower: return 90; + case VirtueLevel.Knight: return 300; + + default: return 0; + } + } + + private static void EmbraceHonor(PlayerMobile pm) + { + if (pm.HonorActive) + { + pm.SendLocalizedMessage(1063230); // You must wait awhile before you can embrace honor again. + return; + } + + if (GetHonorDuration(pm) == 0) + { + pm.SendLocalizedMessage(1063234); // You do not have enough honor to do that + return; + } + + TimeSpan waitTime = DateTime.Now - pm.LastHonorUse; + if (waitTime < UseDelay) + { + TimeSpan remainingTime = UseDelay - waitTime; + int remainingMinutes = (int)Math.Ceiling(remainingTime.TotalMinutes); + + pm.SendLocalizedMessage(1063240, remainingMinutes.ToString()); // You must wait ~1_HONOR_WAIT~ minutes before embracing honor again + return; + } + + pm.SendGump(new HonorSelf(pm)); + + } + + public static void ActivateEmbrace(PlayerMobile pm) + { + int duration = GetHonorDuration(pm); + int usedPoints; + + if (pm.Virtues.Honor < 4399) + usedPoints = 400; + else if (pm.Virtues.Honor < 10599) + usedPoints = 600; + else + usedPoints = 1000; + + VirtueHelper.Atrophy(pm, VirtueName.Honor, usedPoints); + + pm.HonorActive = true; + pm.SendLocalizedMessage(1063235); // You embrace your honor + + Timer.DelayCall(TimeSpan.FromSeconds(duration), + delegate() + { + pm.HonorActive = false; + pm.LastHonorUse = DateTime.Now; + pm.SendLocalizedMessage(1063236); // You no longer embrace your honor + }); + } + + private static void Honor(PlayerMobile source, Mobile target) + { + IHonorTarget honorTarget = target as IHonorTarget; + GuardedRegion reg = (GuardedRegion)source.Region.GetRegion(typeof(GuardedRegion)); + Map map = source.Map; + + if (honorTarget == null) + return; + + if (honorTarget.ReceivedHonorContext != null) + { + if (honorTarget.ReceivedHonorContext.Source == source) + return; + + if (honorTarget.ReceivedHonorContext.CheckDistance()) + { + source.SendLocalizedMessage(1063233); // Somebody else is honoring this opponent + return; + } + } + + if (target.Hits < target.HitsMax) + { + source.SendLocalizedMessage(1063166); // You cannot honor this monster because it is too damaged. + return; + } + + BaseCreature cret = target as BaseCreature; + if (target.Body.IsHuman && (cret == null || (!cret.AlwaysAttackable && !cret.AlwaysMurderer))) + { + + if (reg == null || reg.IsDisabled()) + { + //Allow honor on blue if Out of guardzone + } + else if (map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0) + { + //Allow honor on blue if in Fel + } + else + { + source.SendLocalizedMessage(1001018); // You cannot perform negative acts + return; //cannot honor in trammel town on blue + } + } + + if (Core.ML && target is PlayerMobile) + { + source.SendLocalizedMessage(1075614); // You cannot honor other players. + return; + } + + if (source.SentHonorContext != null) + source.SentHonorContext.Cancel(); + + new HonorContext(source, target); + + source.Direction = source.GetDirectionTo(target); + + if (!source.Mounted) + source.Animate(32, 5, 1, true, true, 0); + + } + } + + public interface IHonorTarget + { + HonorContext ReceivedHonorContext { get; set; } + } + + public class HonorContext + { + private PlayerMobile m_Source; + private Mobile m_Target; + + private double m_HonorDamage; + private int m_TotalDamage; + + private int m_Perfection; + + private enum FirstHit + { + NotDelivered, + Delivered, + Granted + } + + private FirstHit m_FirstHit; + private bool m_Poisoned; + private Point3D m_InitialLocation; + private Map m_InitialMap; + + private InternalTimer m_Timer; + + public PlayerMobile Source { get { return m_Source; } } + public Mobile Target { get { return m_Target; } } + + public HonorContext(PlayerMobile source, Mobile target) + { + m_Source = source; + m_Target = target; + + m_FirstHit = FirstHit.NotDelivered; + m_Poisoned = false; + + m_InitialLocation = source.Location; + m_InitialMap = source.Map; + + source.SentHonorContext = this; + ((IHonorTarget)target).ReceivedHonorContext = this; + + m_Timer = new InternalTimer(this); + m_Timer.Start(); + source.m_hontime = (DateTime.Now + TimeSpan.FromMinutes(40)); + + Timer.DelayCall(TimeSpan.FromMinutes(40), + delegate() + { + if (source.m_hontime < DateTime.Now && source.SentHonorContext != null) + { + Cancel(); + } + }); + } + + public void OnSourceDamaged(Mobile from, int amount) + { + if (from != m_Target) + return; + + if (m_FirstHit == FirstHit.NotDelivered) + m_FirstHit = FirstHit.Granted; + } + + public void OnTargetPoisoned() + { + m_Poisoned = true; // Set this flag for OnTargetDamaged which will be called next + } + + public void OnTargetDamaged(Mobile from, int amount) + { + if (m_FirstHit == FirstHit.NotDelivered) + m_FirstHit = FirstHit.Delivered; + + if (m_Poisoned) + { + m_HonorDamage += amount * 0.8; + m_Poisoned = false; // Reset the flag + + return; + } + + m_TotalDamage += amount; + + if (from == m_Source) + { + if (m_Target.CanSee(m_Source) && m_Target.InLOS(m_Source) && (m_Source.InRange(m_Target, 1) + || (m_Source.Location == m_InitialLocation && m_Source.Map == m_InitialMap))) + { + m_HonorDamage += amount; + } + else + { + m_HonorDamage += amount * 0.8; + } + } + else if (from is BaseCreature && ((BaseCreature)from).GetMaster() == m_Source) + { + m_HonorDamage += amount * 0.8; + } + } + + public void OnTargetHit(Mobile from) + { + if (from != m_Source || m_Perfection == 100) + return; + + int bushido = (int)from.Skills.Bushido.Value; + if (bushido < 50) + return; + + m_Perfection += bushido / 10; + + if (m_Perfection >= 100) + { + m_Perfection = 100; + m_Source.SendLocalizedMessage(1063254); // You have Achieved Perfection in inflicting damage to this opponent! + } + else + { + m_Source.SendLocalizedMessage(1063255); // You gain in Perfection as you precisely strike your opponent. + } + } + + public void OnTargetMissed(Mobile from) + { + if (from != m_Source || m_Perfection == 0) + return; + + m_Perfection -= 25; + + if (m_Perfection <= 0) + { + m_Perfection = 0; + m_Source.SendLocalizedMessage(1063256); // You have lost all Perfection in fighting this opponent. + } + else + { + m_Source.SendLocalizedMessage(1063257); // You have lost some Perfection in fighting this opponent. + } + } + + public void OnSourceBeneficialAction(Mobile to) + { + if (to != m_Target) + return; + + if (m_Perfection >= 0) + { + m_Perfection = 0; + m_Source.SendLocalizedMessage(1063256); // You have lost all Perfection in fighting this opponent. + } + } + + public void OnSourceKilled() + { + return; + } + + public void OnTargetKilled() + { + Cancel(); + + int targetFame = m_Target.Fame; + + if (m_Perfection > 0) + { + int restore = Math.Min(m_Perfection * (targetFame + 5000) / 25000, 10); + + m_Source.Hits += restore; + m_Source.Stam += restore; + m_Source.Mana += restore; + } + + if (m_Source.Virtues.Honor > targetFame) + return; + + double dGain = (targetFame / 100) * (m_HonorDamage / m_TotalDamage); //Initial honor gain is 100th of the monsters honor + + if (m_HonorDamage == m_TotalDamage && m_FirstHit == FirstHit.Granted) + dGain = dGain * 1.5; //honor gain is increased alot more if the combat was fully honorable + else + dGain = dGain * 0.9; + + int gain = Math.Min((int)dGain, 200); + + if (gain < 1) + gain = 1; //Minimum gain of 1 honor when the honor is under the monsters fame + + if (VirtueHelper.IsHighestPath(m_Source, VirtueName.Honor)) + { + m_Source.SendLocalizedMessage(1063228); // You cannot gain more Honor. + return; + } + + bool gainedPath = false; + if (VirtueHelper.Award(m_Source, VirtueName.Honor, (int)gain, ref gainedPath)) + { + if (gainedPath) + m_Source.SendLocalizedMessage(1063226); // You have gained a path in Honor! + else + m_Source.SendLocalizedMessage(1063225); // You have gained in Honor. + } + } + + public int PerfectionDamageBonus + { + get { return m_Perfection; } + } + + public int PerfectionLuckBonus + { + get { return (m_Perfection * m_Perfection) / 10; } + } + + public bool CheckDistance() + { + return true; + } + + public void Cancel() + { + m_Source.SentHonorContext = null; + ((IHonorTarget)m_Target).ReceivedHonorContext = null; + + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private HonorContext m_Context; + + public InternalTimer(HonorContext context) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Context = context; + } + + protected override void OnTick() + { + m_Context.CheckDistance(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/Justice.cs b/Scripts/Engines/Virtues/Justice.cs new file mode 100644 index 0000000..6b68895 --- /dev/null +++ b/Scripts/Engines/Virtues/Justice.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; + +namespace Server +{ + public class JusticeVirtue + { + private static TimeSpan LossDelay = TimeSpan.FromDays( 7.0 ); + private const int LossAmount = 950; + + public static void Initialize() + { + VirtueGump.Register( 109, new OnVirtueUsed( OnVirtueUsed ) ); + } + + public static bool CheckMapRegion( Mobile first, Mobile second ) + { + Map map = first.Map; + + if ( second.Map != map ) + return false; + + return GetMapRegion( map, first.Location ) == GetMapRegion( map, second.Location ); + } + + public static int GetMapRegion( Map map, Point3D loc ) + { + if ( map == null || map.MapID >= 2 ) + return 0; + + if ( loc.X < 5120 ) + return 0; + + if ( loc.Y < 2304 ) + return 1; + + return 2; + } + + public static void OnVirtueUsed( Mobile from ) + { + if ( !from.CheckAlive() ) + return; + + PlayerMobile protector = from as PlayerMobile; + + if ( protector == null ) + return; + + if ( !VirtueHelper.IsSeeker( protector, VirtueName.Justice ) ) + { + protector.SendLocalizedMessage( 1049610 ); // You must reach the first path in this virtue to invoke it. + } + else if ( !protector.CanBeginAction( typeof( JusticeVirtue ) ) ) + { + protector.SendLocalizedMessage( 1049370 ); // You must wait a while before offering your protection again. + } + else if ( protector.JusticeProtectors.Count > 0 ) + { + protector.SendLocalizedMessage( 1049542 ); // You cannot protect someone while being protected. + } + else if ( protector.Map != Map.Felucca ) + { + protector.SendLocalizedMessage( 1049372 ); // You cannot use this ability here. + } + else + { + protector.BeginTarget( 14, false, TargetFlags.None, new TargetCallback( OnVirtueTargeted ) ); + protector.SendLocalizedMessage( 1049366 ); // Choose the player you wish to protect. + } + } + + public static void OnVirtueTargeted( Mobile from, object obj ) + { + PlayerMobile protector = from as PlayerMobile; + PlayerMobile pm = obj as PlayerMobile; + + if ( protector == null ) + return; + + if ( !VirtueHelper.IsSeeker( protector, VirtueName.Justice ) ) + protector.SendLocalizedMessage( 1049610 ); // You must reach the first path in this virtue to invoke it. + else if ( !protector.CanBeginAction( typeof( JusticeVirtue ) ) ) + protector.SendLocalizedMessage( 1049370 ); // You must wait a while before offering your protection again. + else if ( protector.JusticeProtectors.Count > 0 ) + protector.SendLocalizedMessage( 1049542 ); // You cannot protect someone while being protected. + else if ( protector.Map != Map.Felucca ) + protector.SendLocalizedMessage( 1049372 ); // You cannot use this ability here. + else if ( pm == null ) + protector.SendLocalizedMessage( 1049678 ); // Only players can be protected. + else if ( pm.Map != Map.Felucca ) + protector.SendLocalizedMessage( 1049372 ); // You cannot use this ability here. + else if ( pm == protector || pm.Criminal || pm.Kills >= 5 ) + protector.SendLocalizedMessage( 1049436 ); // That player cannot be protected. + else if ( pm.JusticeProtectors.Count > 0 ) + protector.SendLocalizedMessage( 1049369 ); // You cannot protect that player right now. + else if ( pm.HasGump( typeof( AcceptProtectorGump ) ) ) + protector.SendLocalizedMessage( 1049369 ); // You cannot protect that player right now. + else + pm.SendGump( new AcceptProtectorGump( protector, pm ) ); + } + + public static void OnVirtueAccepted( PlayerMobile protector, PlayerMobile protectee ) + { + if ( !VirtueHelper.IsSeeker( protector, VirtueName.Justice ) ) + { + protector.SendLocalizedMessage( 1049610 ); // You must reach the first path in this virtue to invoke it. + } + else if ( !protector.CanBeginAction( typeof( JusticeVirtue ) ) ) + { + protector.SendLocalizedMessage( 1049370 ); // You must wait a while before offering your protection again. + } + else if ( protector.JusticeProtectors.Count > 0 ) + { + protector.SendLocalizedMessage( 1049542 ); // You cannot protect someone while being protected. + } + else if ( protector.Map != Map.Felucca ) + { + protector.SendLocalizedMessage( 1049372 ); // You cannot use this ability here. + } + else if ( protectee.Map != Map.Felucca ) + { + protector.SendLocalizedMessage( 1049372 ); // You cannot use this ability here. + } + else if ( protectee == protector || protectee.Criminal || protectee.Kills >= 5 ) + { + protector.SendLocalizedMessage( 1049436 ); // That player cannot be protected. + } + else if ( protectee.JusticeProtectors.Count > 0 ) + { + protector.SendLocalizedMessage( 1049369 ); // You cannot protect that player right now. + } + else + { + protectee.JusticeProtectors.Add( protector ); + + string args = String.Format( "{0}\t{1}", protector.Name, protectee.Name ); + + protectee.SendLocalizedMessage( 1049451, args ); // You are now being protected by ~1_NAME~. + protector.SendLocalizedMessage( 1049452, args ); // You are now protecting ~2_NAME~. + } + } + + public static void OnVirtueRejected( PlayerMobile protector, PlayerMobile protectee ) + { + string args = String.Format( "{0}\t{1}", protector.Name, protectee.Name ); + + protectee.SendLocalizedMessage( 1049453, args ); // You have declined protection from ~1_NAME~. + protector.SendLocalizedMessage( 1049454, args ); // ~2_NAME~ has declined your protection. + + if ( protector.BeginAction( typeof( JusticeVirtue ) ) ) + Timer.DelayCall( TimeSpan.FromMinutes( 15.0 ), new TimerStateCallback( RejectDelay_Callback ), protector ); + } + + public static void RejectDelay_Callback( object state ) + { + Mobile m = state as Mobile; + + if ( m != null ) + m.EndAction( typeof( JusticeVirtue ) ); + } + + public static void CheckAtrophy( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + try + { + if ( (pm.LastJusticeLoss + LossDelay) < DateTime.Now ) + { + if ( VirtueHelper.Atrophy( from, VirtueName.Justice, LossAmount ) ) + from.SendLocalizedMessage( 1049373 ); // You have lost some Justice. + + pm.LastJusticeLoss = DateTime.Now; + } + } + catch + { + } + } + } + + public class AcceptProtectorGump : Gump + { + private PlayerMobile m_Protector; + private PlayerMobile m_Protectee; + + public AcceptProtectorGump( PlayerMobile protector, PlayerMobile protectee ) : base( 150, 50 ) + { + m_Protector = protector; + m_Protectee = protectee; + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 396, 218, 3600 ); + + AddImageTiled( 15, 15, 365, 190, 2624 ); + AddAlphaRegion( 15, 15, 365, 190 ); + + AddHtmlLocalized( 30, 20, 360, 25, 1049365, 0x7FFF, false, false ); // Another player is offering you their protection: + AddLabel( 90, 55, 1153, protector.Name ); + + AddImage( 50, 45, 9005 ); + AddImageTiled( 80, 80, 200, 1, 9107 ); + AddImageTiled( 95, 82, 200, 1, 9157 ); + + AddRadio( 30, 110, 9727, 9730, true, 1 ); + AddHtmlLocalized( 65, 115, 300, 25, 1049444, 0x7FFF, false, false ); // Yes, I would like their protection. + + AddRadio( 30, 145, 9727, 9730, false, 0 ); + AddHtmlLocalized( 65, 148, 300, 25, 1049445, 0x7FFF, false, false ); // No thanks, I can take care of myself. + + AddButton( 160, 175, 247, 248, 2, GumpButtonType.Reply, 0 ); + + AddImage( 215, 0, 50581 ); + + AddImageTiled( 15, 14, 365, 1, 9107 ); + AddImageTiled( 380, 14, 1, 190, 9105 ); + AddImageTiled( 15, 205, 365, 1, 9107 ); + AddImageTiled( 15, 14, 1, 190, 9105 ); + AddImageTiled( 0, 0, 395, 1, 9157 ); + AddImageTiled( 394, 0, 1, 217, 9155 ); + AddImageTiled( 0, 216, 395, 1, 9157 ); + AddImageTiled( 0, 0, 1, 217, 9155 ); + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 2 ) + { + bool okay = info.IsSwitched( 1 ); + + if ( okay ) + JusticeVirtue.OnVirtueAccepted( m_Protector, m_Protectee ); + else + JusticeVirtue.OnVirtueRejected( m_Protector, m_Protectee ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/Sacrifice.cs b/Scripts/Engines/Virtues/Sacrifice.cs new file mode 100644 index 0000000..5b8bfcb --- /dev/null +++ b/Scripts/Engines/Virtues/Sacrifice.cs @@ -0,0 +1,194 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; +using Server.Network; + +namespace Server +{ + public class SacrificeVirtue + { + private static TimeSpan GainDelay = TimeSpan.FromDays( 1.0 ); + private static TimeSpan LossDelay = TimeSpan.FromDays( 7.0 ); + private const int LossAmount = 500; + + public static void Initialize() + { + VirtueGump.Register( 110, new OnVirtueUsed( OnVirtueUsed ) ); + } + + public static void OnVirtueUsed( Mobile from ) + { + if ( !from.Hidden ) + { + if ( from.Alive ) + from.Target = new InternalTarget(); + else + Resurrect( from ); + } + else + from.SendLocalizedMessage( 1052015 ); // You cannot do that while hidden. + } + + public static void CheckAtrophy( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + try + { + if ( (pm.LastSacrificeLoss + LossDelay) < DateTime.Now ) + { + if ( VirtueHelper.Atrophy( from, VirtueName.Sacrifice, LossAmount ) ) + from.SendLocalizedMessage( 1052041 ); // You have lost some Sacrifice. + + VirtueLevel level = VirtueHelper.GetLevel( from, VirtueName.Sacrifice ); + + pm.AvailableResurrects = (int)level; + pm.LastSacrificeLoss = DateTime.Now; + } + } + catch + { + } + } + + public static void Resurrect( Mobile from ) + { + if ( from.Alive ) + return; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + if ( from.Criminal ) + { + from.SendLocalizedMessage( 1052007 ); // You cannot use this ability while flagged as a criminal. + } + else if ( !VirtueHelper.IsSeeker( from, VirtueName.Sacrifice ) ) + { + from.SendLocalizedMessage( 1052004 ); // You cannot use this ability. + } + else if ( pm.AvailableResurrects <= 0 ) + { + from.SendLocalizedMessage( 1052005 ); // You do not have any resurrections left. + } + else + { + /* + * We need to wait for them to accept the gump or they can just use + * Sacrifice and cancel to have items in their backpack for free. + */ + from.CloseGump( typeof( ResurrectGump ) ); + from.SendGump( new ResurrectGump( from, true ) ); + } + } + + public static void Sacrifice( Mobile from, object targeted ) + { + if ( !from.CheckAlive() ) + return; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + Mobile targ = targeted as Mobile; + + if ( targ == null ) + return; + + if ( !ValidateCreature( targ ) ) + { + from.SendLocalizedMessage( 1052014 ); // You cannot sacrifice your fame for that creature. + } + else if ( ((targ.Hits * 100) / Math.Max( targ.HitsMax, 1 )) < 90 ) + { + from.SendLocalizedMessage( 1052013 ); // You cannot sacrifice for this monster because it is too damaged. + } + else if ( from.Hidden ) + { + from.SendLocalizedMessage( 1052015 ); // You cannot do that while hidden. + } + else if ( VirtueHelper.IsHighestPath( from, VirtueName.Sacrifice ) ) + { + from.SendLocalizedMessage( 1052068 ); // You have already attained the highest path in this virtue. + } + else if ( from.Fame < 2500 ) + { + from.SendLocalizedMessage( 1052017 ); // You do not have enough fame to sacrifice. + } + else if ( DateTime.Now < (pm.LastSacrificeGain + GainDelay) ) + { + from.SendLocalizedMessage( 1052016 ); // You must wait approximately one day before sacrificing again. + } + else + { + int toGain; + + if( from.Fame < 5000 ) + toGain = 500; + else if( from.Fame < 10000 ) + toGain = 1000; + else + toGain = 2000; + + from.Fame = 0; + + // I have seen the error of my ways! + targ.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1052009 ); + + from.SendLocalizedMessage( 1052010 ); // You have set the creature free. + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerCallback( targ.Delete ) ); + + pm.LastSacrificeGain = DateTime.Now; + + bool gainedPath = false; + + if ( VirtueHelper.Award( from, VirtueName.Sacrifice, toGain, ref gainedPath ) ) + { + if ( gainedPath ) + { + from.SendLocalizedMessage( 1052008 ); // You have gained a path in Sacrifice! + + if ( pm.AvailableResurrects < 3 ) + ++pm.AvailableResurrects; + } + else + { + from.SendLocalizedMessage( 1054160 ); // You have gained in sacrifice. + } + } + + from.SendLocalizedMessage( 1052016 ); // You must wait approximately one day before sacrificing again. + } + } + + public static bool ValidateCreature( Mobile m ) + { + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned) ) + return false; + + return ( m is Lich || m is Succubus || m is Daemon || m is EvilMage || m is EnslavedGargoyle || m is GargoyleEnforcer ); + } + + private class InternalTarget : Target + { + public InternalTarget() : base( 8, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + Sacrifice( from, targeted ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/Valor.cs b/Scripts/Engines/Virtues/Valor.cs new file mode 100644 index 0000000..d4e5f17 --- /dev/null +++ b/Scripts/Engines/Virtues/Valor.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; +using Server.Engines.CannedEvil; + +namespace Server +{ + public class ValorVirtue + { + private static TimeSpan LossDelay = TimeSpan.FromDays( 7.0 ); + private const int LossAmount = 250; + + public static void Initialize() + { + VirtueGump.Register( 112, new OnVirtueUsed( OnVirtueUsed ) ); + } + + public static void OnVirtueUsed( Mobile from ) + { + if( from.Alive ) + { + from.SendLocalizedMessage( 1054034 ); // Target the Champion Idol of the Champion you wish to challenge!. + from.Target = new InternalTarget(); + } + } + + public static void CheckAtrophy( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if( pm == null ) + return; + + try + { + if( (pm.LastValorLoss + LossDelay) < DateTime.Now ) + { + if( VirtueHelper.Atrophy( from, VirtueName.Valor, LossAmount ) ) + from.SendLocalizedMessage( 1054040 ); // You have lost some Valor. + + pm.LastValorLoss = DateTime.Now; + } + } + catch + { + } + } + + public static void Valor( Mobile from, object targ ) + { + IdolOfTheChampion idol = targ as IdolOfTheChampion; + + if( idol == null || idol.Deleted || idol.Spawn == null || idol.Spawn.Deleted ) + from.SendLocalizedMessage( 1054035 ); // You must target a Champion Idol to challenge the Champion's spawn! + else if( from.Hidden ) + from.SendLocalizedMessage( 1052015 ); // You cannot do that while hidden. + else if( idol.Spawn.HasBeenAdvanced ) + from.SendLocalizedMessage( 1054038 ); // The Champion of this region has already been challenged! + else + { + VirtueLevel vl = VirtueHelper.GetLevel( from, VirtueName.Valor ); + if( idol.Spawn.Active ) + { + if( idol.Spawn.Champion != null ) //TODO: Message? + return; + + int needed, consumed; + switch( idol.Spawn.GetSubLevel() ) + { + case 0: + { + needed = consumed = 2500; + break; + } + case 1: + { + needed = consumed = 5000; + break; + } + case 2: + { + needed = 10000; + consumed = 7500; + break; + } + default: + { + needed = 20000; + consumed = 10000; + break; + } + } + + if( from.Virtues.GetValue( (int)VirtueName.Valor ) >= needed ) + { + VirtueHelper.Atrophy( from, VirtueName.Valor, consumed ); + from.SendLocalizedMessage( 1054037 ); // Your challenge is heard by the Champion of this region! Beware its wrath! + idol.Spawn.HasBeenAdvanced = true; + idol.Spawn.AdvanceLevel(); + } + else + from.SendLocalizedMessage( 1054039 ); // The Champion of this region ignores your challenge. You must further prove your valor. + } + else + { + if( vl == VirtueLevel.Knight ) + { + VirtueHelper.Atrophy( from, VirtueName.Valor, 11000 ); + from.SendLocalizedMessage( 1054037 ); // Your challenge is heard by the Champion of this region! Beware its wrath! + idol.Spawn.EndRestart(); + idol.Spawn.HasBeenAdvanced = true; + } + else + { + from.SendLocalizedMessage( 1054036 ); // You must be a Knight of Valor to summon the champion's spawn in this manner! + } + } + } + + } + + private class InternalTarget : Target + { + public InternalTarget() : base( 14, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + Valor( from, targeted ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/VirtueGump.cs b/Scripts/Engines/Virtues/VirtueGump.cs new file mode 100644 index 0000000..4ccbee9 --- /dev/null +++ b/Scripts/Engines/Virtues/VirtueGump.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server +{ + public delegate void OnVirtueUsed( Mobile from ); + + public class VirtueGump : Gump + { + private static Hashtable m_Callbacks = new Hashtable(); + + public static void Initialize() + { + EventSink.VirtueGumpRequest += new VirtueGumpRequestEventHandler( EventSink_VirtueGumpRequest ); + EventSink.VirtueItemRequest += new VirtueItemRequestEventHandler( EventSink_VirtueItemRequest ); + EventSink.VirtueMacroRequest += new VirtueMacroRequestEventHandler( EventSink_VirtueMacroRequest ); + } + + public static void Register( int gumpID, OnVirtueUsed callback ) + { + m_Callbacks[gumpID] = callback; + } + + private static void EventSink_VirtueItemRequest( VirtueItemRequestEventArgs e ) + { + if ( e.Beholder != e.Beheld ) + return; + + e.Beholder.CloseGump( typeof( VirtueGump ) ); + + if ( e.Beholder.Kills >= 5 ) + { + e.Beholder.SendLocalizedMessage( 1049609 ); // Murderers cannot invoke this virtue. + return; + } + + OnVirtueUsed callback = (OnVirtueUsed)m_Callbacks[e.GumpID]; + + if ( callback != null ) + callback( e.Beholder ); + else + e.Beholder.SendLocalizedMessage( 1052066 ); // That virtue is not active yet. + } + + + private static void EventSink_VirtueMacroRequest( VirtueMacroRequestEventArgs e ) + { + int virtueID = 0; + + switch ( e.VirtueID ) + { + case 0: // Honor + virtueID = 107; break; + case 1: // Sacrifice + virtueID = 110; break; + case 2: // Valor; + virtueID = 112; break; + } + + EventSink_VirtueItemRequest( new VirtueItemRequestEventArgs( e.Mobile, e.Mobile, virtueID ) ); + } + + private static void EventSink_VirtueGumpRequest( VirtueGumpRequestEventArgs e ) + { + Mobile beholder = e.Beholder; + Mobile beheld = e.Beheld; + + if ( beholder == beheld && beholder.Kills >= 5 ) + { + beholder.SendLocalizedMessage( 1049609 ); // Murderers cannot invoke this virtue. + } + else if ( beholder.Map == beheld.Map && beholder.InRange( beheld, 12 ) ) + { + beholder.CloseGump( typeof( VirtueGump ) ); + beholder.SendGump( new VirtueGump( beholder, beheld ) ); + } + } + + private Mobile m_Beholder, m_Beheld; + + public VirtueGump( Mobile beholder, Mobile beheld ) : base( 0, 0 ) + { + m_Beholder = beholder; + m_Beheld = beheld; + + Serial = beheld.Serial; + + AddPage( 0 ); + + AddImage( 30, 40, 104 ); + + AddPage( 1 ); + + Add( new InternalEntry( 61, 71, 108, GetHueFor( 0 ) ) ); // Humility + Add( new InternalEntry( 123, 46, 112, GetHueFor( 4 ) ) ); // Valor + Add( new InternalEntry( 187, 70, 107, GetHueFor( 5 ) ) ); // Honor + Add( new InternalEntry( 35, 135, 110, GetHueFor( 1 ) ) ); // Sacrifice + Add( new InternalEntry( 211, 133, 105, GetHueFor( 2 ) ) ); // Compassion + Add( new InternalEntry( 61, 195, 111, GetHueFor( 3 ) ) ); // Spiritulaity + Add( new InternalEntry( 186, 195, 109, GetHueFor( 6 ) ) ); // Justice + Add( new InternalEntry( 121, 221, 106, GetHueFor( 7 ) ) ); // Honesty + + if ( m_Beholder == m_Beheld ) + { + AddButton( 57, 269, 2027, 2027, 1, GumpButtonType.Reply, 0 ); + AddButton( 186, 269, 2071, 2071, 2, GumpButtonType.Reply, 0 ); + } + } + + private static int[] m_Table = new int[24] + { + 0x0481, 0x0963, 0x0965, + 0x060A, 0x060F, 0x002A, + 0x08A4, 0x08A7, 0x0034, + 0x0965, 0x08FD, 0x0480, + 0x00EA, 0x0845, 0x0020, + 0x0011, 0x0269, 0x013D, + 0x08A1, 0x08A3, 0x0042, + 0x0543, 0x0547, 0x0061 + }; + + private int GetHueFor( int index ) + { + if ( m_Beheld.Virtues.GetValue( index ) == 0 ) + return 2402; + + int value = m_Beheld.Virtues.GetValue( index ); + + if ( value < 4000 ) + return 2402; + + if( value >= 30000 ) + value = 20000; //Sanity + + + int vl; + + if (value < 10000) + vl = 0; + else if (value >= 20000 && index == 5) + vl = 2; + else if (value >= 21000 && index != 1) + vl = 2; + else if (value >= 22000 && index == 1) + vl = 2; + else + vl = 1; + + + return m_Table[(index * 3) + (int)vl]; + } + + private class InternalEntry : GumpImage + { + public InternalEntry( int x, int y, int gumpID, int hue ) : base( x, y, gumpID, hue ) + { + } + + public override string Compile() + { + return String.Format( "{{ gumppic {0} {1} {2} hue={3} class=VirtueGumpItem }}", X, Y, GumpID, Hue ); + } + + private static byte[] m_Class = Gump.StringToBuffer( " class=VirtueGumpItem" ); + + public override void AppendTo( IGumpWriter disp ) + { + base.AppendTo( disp ); + + disp.AppendLayout( m_Class ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 1 && m_Beholder == m_Beheld ) + m_Beholder.SendGump( new VirtueStatusGump( m_Beholder ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/VirtueHelper.cs b/Scripts/Engines/Virtues/VirtueHelper.cs new file mode 100644 index 0000000..c711215 --- /dev/null +++ b/Scripts/Engines/Virtues/VirtueHelper.cs @@ -0,0 +1,160 @@ +using System; +using Server.Mobiles; + +namespace Server +{ + public enum VirtueLevel + { + None, + Seeker, + Follower, + Knight + } + + public enum VirtueName + { + Humility, + Sacrifice, + Compassion, + Spirituality, + Valor, + Honor, + Justice, + Honesty + } + + public class VirtueHelper + { + public static bool HasAny( Mobile from, VirtueName virtue ) + { + return ( from.Virtues.GetValue( (int)virtue ) > 0 ); + } + + public static bool IsHighestPath( Mobile from, VirtueName virtue ) + { + return ( from.Virtues.GetValue( (int)virtue ) >= GetMaxAmount( virtue ) ); + } + + public static VirtueLevel GetLevel( Mobile from, VirtueName virtue ) + { + int v = from.Virtues.GetValue( (int)virtue ); + int vl; + int vmax = GetMaxAmount(virtue); + + if (v < 4000) + vl = 0; + else if (v >= vmax) + vl = 3; + else + vl = (v + 9999) / 10000; + + return (VirtueLevel)vl; + } + + public static int GetMaxAmount( VirtueName virtue ) + { + if( virtue == VirtueName.Honor ) + return 20000; + + if( virtue == VirtueName.Sacrifice ) + return 22000; + + return 21000; + } + + public static bool Award( Mobile from, VirtueName virtue, int amount, ref bool gainedPath ) + { + int current = from.Virtues.GetValue( (int)virtue ); + + int maxAmount = GetMaxAmount( virtue ); + + if ( current >= maxAmount ) + return false; + + if( (current + amount) >= maxAmount ) + amount = maxAmount - current; + + VirtueLevel oldLevel = GetLevel( from, virtue ); + + from.Virtues.SetValue( (int)virtue, current + amount ); + + gainedPath = ( GetLevel( from, virtue ) != oldLevel ); + + return true; + } + + public static bool Atrophy( Mobile from, VirtueName virtue ) + { + return Atrophy( from, virtue, 1 ); + } + public static bool Atrophy( Mobile from, VirtueName virtue, int amount ) + { + int current = from.Virtues.GetValue( (int)virtue ); + + if( (current - amount) >= 0 ) + from.Virtues.SetValue( (int)virtue, current - amount ); + else + from.Virtues.SetValue( (int)virtue, 0 ); + + return ( current > 0 ); + } + + public static bool IsSeeker( Mobile from, VirtueName virtue ) + { + return ( GetLevel( from, virtue ) >= VirtueLevel.Seeker ); + } + + public static bool IsFollower( Mobile from, VirtueName virtue ) + { + return ( GetLevel( from, virtue ) >= VirtueLevel.Follower ); + } + + public static bool IsKnight( Mobile from, VirtueName virtue ) + { + return ( GetLevel( from, virtue ) >= VirtueLevel.Knight ); + } + public static void AwardVirtue(PlayerMobile pm, VirtueName virtue, int amount) + { + if (virtue == VirtueName.Compassion) + { + if (pm.CompassionGains > 0 && DateTime.Now > pm.NextCompassionDay) + { + pm.NextCompassionDay = DateTime.MinValue; + pm.CompassionGains = 0; + } + + if (pm.CompassionGains >= 5) + { + pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again. + return; + } + } + + bool gainedPath = false; + string virtueName = Enum.GetName(typeof(VirtueName), virtue); + + if (VirtueHelper.Award(pm, virtue, amount, ref gainedPath)) + { + // TODO: Localize? + if (gainedPath) + pm.SendMessage("You have gained a path in {0}!", virtueName); + else + pm.SendMessage("You have gained in {0}.", virtueName); + + if (virtue == VirtueName.Compassion) + { + pm.NextCompassionDay = DateTime.Now + TimeSpan.FromDays(1.0); + ++pm.CompassionGains; + + if (pm.CompassionGains >= 5) + pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again. + } + } + else + { + // TODO: Localize? + pm.SendMessage("You have achieved the highest path of {0} and can no longer gain any further.", virtueName); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/VirtueInfoGump.cs b/Scripts/Engines/Virtues/VirtueInfoGump.cs new file mode 100644 index 0000000..56fd625 --- /dev/null +++ b/Scripts/Engines/Virtues/VirtueInfoGump.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server +{ + public class VirtueInfoGump : Gump + { + private Mobile m_Beholder; + private int m_Desc; + private string m_Page; + private VirtueName m_Virtue; + + public VirtueInfoGump(Mobile beholder, VirtueName virtue, int description) + : this(beholder, virtue, description, null) + { + } + + public VirtueInfoGump(Mobile beholder, VirtueName virtue, int description, string webPage) + : base(0, 0) + { + m_Beholder = beholder; + m_Virtue = virtue; + m_Desc = description; + m_Page = webPage; + + int value = beholder.Virtues.GetValue((int)virtue); + + AddPage(0); + + AddImage(30, 40, 2080); + AddImage(47, 77, 2081); + AddImage(47, 147, 2081); + AddImage(47, 217, 2081); + AddImage(47, 267, 2083); + AddImage(70, 213, 2091); + + AddPage(1); + + int maxValue = VirtueHelper.GetMaxAmount(m_Virtue); + + int valueDesc; + int dots; + + if (value < 4000) + dots = value / 400; + else if (value < 10000) + dots = (value - 4000) / 600; + else if (value < maxValue) + dots = (value - 10000) / ((maxValue - 10000) / 10); + else + dots = 10; + + for (int i = 0; i < 10; ++i) + AddImage(95 + (i * 17), 50, i < dots ? 2362 : 2360); + + + if (value < 1) + valueDesc = 1052044; // You have not started on the path of this Virtue. + else if (value < 400) + valueDesc = 1052045; // You have barely begun your journey through the path of this Virtue. + else if (value < 2000) + valueDesc = 1052046; // You have progressed in this Virtue, but still have much to do. + else if (value < 3600) + valueDesc = 1052047; // Your journey through the path of this Virtue is going well. + else if (value < 4000) + valueDesc = 1052048; // You feel very close to achieving your next path in this Virtue. + else if (dots < 1) + valueDesc = 1052049; // You have achieved a path in this Virtue. + else if (dots < 9) + valueDesc = 1052047; // Your journey through the path of this Virtue is going well. + else if (dots < 10) + valueDesc = 1052048; // You feel very close to achieving your next path in this Virtue. + else + valueDesc = 1052050; // You have achieved the highest path in this Virtue. + + + AddHtmlLocalized(157, 73, 200, 40, 1051000 + (int)virtue, false, false); + AddHtmlLocalized(75, 95, 220, 140, description, false, false); + AddHtmlLocalized(70, 224, 229, 60, valueDesc, false, false); + + AddButton(65, 277, 1209, 1209, 1, GumpButtonType.Reply, 0); + + AddButton(280, 43, 4014, 4014, 2, GumpButtonType.Reply, 0); + + AddHtmlLocalized(83, 275, 400, 40, (webPage == null) ? 1052055 : 1052052, false, false); // This virtue is not yet defined. OR -click to learn more (opens webpage) + + + } + + public override void OnResponse(NetState state, RelayInfo info) + { + switch (info.ButtonID) + { + case 1: + { + m_Beholder.SendGump(new VirtueInfoGump(m_Beholder, m_Virtue, m_Desc, m_Page)); + + if (m_Page != null) + state.Send(new LaunchBrowser(m_Page)); //No message about web browser starting on OSI + break; + } + case 2: + { + m_Beholder.SendGump(new VirtueStatusGump(m_Beholder)); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Engines/Virtues/VirtueStatusGump.cs b/Scripts/Engines/Virtues/VirtueStatusGump.cs new file mode 100644 index 0000000..1656e89 --- /dev/null +++ b/Scripts/Engines/Virtues/VirtueStatusGump.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server +{ + public class VirtueStatusGump : Gump + { + private Mobile m_Beholder; + + public VirtueStatusGump( Mobile beholder ) : base( 0, 0 ) + { + m_Beholder = beholder; + + AddPage( 0 ); + + AddImage( 30, 40, 2080 ); + AddImage( 47, 77, 2081 ); + AddImage( 47, 147, 2081 ); + AddImage( 47, 217, 2081 ); + AddImage( 47, 267, 2083 ); + AddImage( 70, 213, 2091 ); + + AddPage( 1 ); + + AddHtml( 140, 73, 200, 20, "The Virtues", false, false ); + + AddHtmlLocalized( 80, 100, 100, 40, 1051000, false, false ); // Humility + AddHtmlLocalized( 80, 129, 100, 40, 1051001, false, false ); // Sacrifice + AddHtmlLocalized( 80, 159, 100, 40, 1051002, false, false ); // Compassion + AddHtmlLocalized( 80, 189, 100, 40, 1051003, false, false ); // Spirituality + AddHtmlLocalized( 200, 100, 200, 40, 1051004, false, false ); // Valor + AddHtmlLocalized( 200, 129, 200, 40, 1051005, false, false ); // Honor + AddHtmlLocalized( 200, 159, 200, 40, 1051006, false, false ); // Justice + AddHtmlLocalized( 200, 189, 200, 40, 1051007, false, false ); // Honesty + + AddHtmlLocalized( 75, 224, 220, 60, 1052062, false, false ); // Click on a blue gem to view your status in that virtue. + + AddButton( 60, 100, 1210, 1210, 1, GumpButtonType.Reply, 0 ); + AddButton( 60, 129, 1210, 1210, 2, GumpButtonType.Reply, 0 ); + AddButton( 60, 159, 1210, 1210, 3, GumpButtonType.Reply, 0 ); + AddButton( 60, 189, 1210, 1210, 4, GumpButtonType.Reply, 0 ); + AddButton( 180, 100, 1210, 1210, 5, GumpButtonType.Reply, 0 ); + AddButton( 180, 129, 1210, 1210, 6, GumpButtonType.Reply, 0 ); + AddButton( 180, 159, 1210, 1210, 7, GumpButtonType.Reply, 0 ); + AddButton( 180, 189, 1210, 1210, 8, GumpButtonType.Reply, 0 ); + + AddButton( 280, 43, 4014, 4014, 9, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 1: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Humility, 1052051 ) ); + break; + } + case 2: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Sacrifice, 1052053, @"http://update.uo.com/design_389.html" ) ); + break; + } + case 3: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Compassion, 1053000, @"http://update.uo.com/design_412.html" ) ); + break; + } + case 4: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Spirituality, 1052056 ) ); + break; + } + case 5: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Valor, 1054033, @"http://update.uo.com/design_427.html" ) ); + break; + } + case 6: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Honor, 1052058, @"http://guide.uo.com/virtues_2.html" ) ); + break; + } + case 7: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Justice, 1052059, @"http://update.uo.com/design_413.html" ) ); + break; + } + case 8: + { + m_Beholder.SendGump( new VirtueInfoGump( m_Beholder, VirtueName.Honesty, 1052060 ) ); + break; + } + case 9: + { + m_Beholder.SendGump( new VirtueGump( m_Beholder, m_Beholder ) ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/AddDoorGump.cs b/Scripts/Gumps/AddDoorGump.cs new file mode 100644 index 0000000..9eef776 --- /dev/null +++ b/Scripts/Gumps/AddDoorGump.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class AddDoorGump : Gump + { + private int m_Type; + + public AddDoorGump() : this( -1 ) + { + } + + public void AddBlueBack( int width, int height ) + { + AddBackground ( 0, 0, width-00, height-00, 0xE10 ); + AddBackground ( 8, 5, width-16, height-11, 0x053 ); + AddImageTiled ( 15, 14, width-29, height-29, 0xE14 ); + AddAlphaRegion( 15, 14, width-29, height-29 ); + } + + public AddDoorGump( int type ) : base( 50, 40 ) + { + m_Type = type; + + AddPage( 0 ); + + if ( m_Type >= 0 && m_Type < m_Types.Length ) + { + AddBlueBack( 155, 174 ); + + int baseID = m_Types[m_Type].m_BaseID; + + AddItem( 25, 24, baseID ); + AddButton( 26, 37, 0x5782, 0x5782, 1, GumpButtonType.Reply, 0 ); + + AddItem( 47, 45, baseID + 2 ); + AddButton( 43, 57, 0x5783, 0x5783, 2, GumpButtonType.Reply, 0 ); + + AddItem( 87, 22, baseID + 10 ); + AddButton( 116, 35, 0x5785, 0x5785, 6, GumpButtonType.Reply, 0 ); + + AddItem( 65, 45, baseID + 8 ); + AddButton( 96, 55, 0x5784, 0x5784, 5, GumpButtonType.Reply, 0 ); + + AddButton( 73, 36, 0x2716, 0x2716, 9, GumpButtonType.Reply, 0 ); + } + else + { + AddBlueBack( 265, 145 ); + + for ( int i = 0; i < m_Types.Length; ++i ) + { + AddButton( 30 + (i * 49), 13, 0x2624, 0x2625, i + 1, GumpButtonType.Reply, 0 ); + AddItem( 22 + (i * 49), 20, m_Types[i].m_BaseID ); + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + int button = info.ButtonID - 1; + + if ( m_Type == -1 ) + { + if ( button >= 0 && button < m_Types.Length ) + from.SendGump( new AddDoorGump( button ) ); + } + else + { + if ( button >= 0 && button < 8 ) + { + from.SendGump( new AddDoorGump( m_Type ) ); + CommandSystem.Handle( from, String.Format( "{0}Add {1} {2}", CommandSystem.Prefix, m_Types[m_Type].m_Type.Name, (DoorFacing) button ) ); + } + else if ( button == 8 ) + { + from.SendGump( new AddDoorGump( m_Type ) ); + CommandSystem.Handle( from, String.Format( "{0}Link", CommandSystem.Prefix ) ); + } + else + { + from.SendGump( new AddDoorGump() ); + } + } + } + + public static void Initialize() + { + CommandSystem.Register( "AddDoor", AccessLevel.GameMaster, new CommandEventHandler( AddDoor_OnCommand ) ); + } + + [Usage( "AddDoor" )] + [Description( "Displays a menu from which you can interactively add doors." )] + public static void AddDoor_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new AddDoorGump() ); + } + + public static DoorInfo[] m_Types = new DoorInfo[] + { + new DoorInfo( typeof( MetalDoor ), 0x675 ), + new DoorInfo( typeof( RattanDoor ), 0x695 ), + new DoorInfo( typeof( DarkWoodDoor ), 0x6A5 ), + new DoorInfo( typeof( LightWoodDoor ), 0x6D5 ), + new DoorInfo( typeof( StrongWoodDoor ), 0x6E5 ) + }; + } + + public class DoorInfo + { + public Type m_Type; + public int m_BaseID; + + public DoorInfo( Type type, int baseID ) + { + m_Type = type; + m_BaseID = baseID; + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/AddGump.cs b/Scripts/Gumps/AddGump.cs new file mode 100644 index 0000000..3f62daa --- /dev/null +++ b/Scripts/Gumps/AddGump.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Server; +using Server.Commands; +using Server.Network; +using Server.Targeting; + +namespace Server.Gumps +{ + public class AddGump : Gump + { + private string m_SearchString; + private Type[] m_SearchResults; + private int m_Page; + + public static void Initialize() + { + CommandSystem.Register( "AddMenu", AccessLevel.GameMaster, new CommandEventHandler( AddMenu_OnCommand ) ); + } + + [Usage( "AddMenu [searchString]" )] + [Description( "Opens an add menu, with an optional initial search string. This menu allows you to search for Items or Mobiles and add them interactively." )] + private static void AddMenu_OnCommand( CommandEventArgs e ) + { + string val = e.ArgString.Trim(); + Type[] types; + bool explicitSearch = false; + + if ( val.Length == 0 ) + { + types = Type.EmptyTypes; + } + else if ( val.Length < 3 ) + { + e.Mobile.SendMessage( "Invalid search string." ); + types = Type.EmptyTypes; + } + else + { + types = Match( val ).ToArray(); + explicitSearch = true; + } + + e.Mobile.SendGump( new AddGump( e.Mobile, val, 0, types, explicitSearch ) ); + } + + public AddGump( Mobile from, string searchString, int page, Type[] searchResults, bool explicitSearch ) : base( 50, 50 ) + { + m_SearchString = searchString; + m_SearchResults = searchResults; + m_Page = page; + + from.CloseGump( typeof( AddGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 280, 5054 ); + + AddImageTiled( 10, 10, 400, 20, 2624 ); + AddAlphaRegion( 10, 10, 400, 20 ); + AddImageTiled( 41, 11, 184, 18, 0xBBC ); + AddImageTiled( 42, 12, 182, 16, 2624 ); + AddAlphaRegion( 42, 12, 182, 16 ); + + AddButton( 10, 9, 4011, 4013, 1, GumpButtonType.Reply, 0 ); + AddTextEntry( 44, 10, 180, 20, 0x480, 0, searchString ); + + AddHtmlLocalized( 230, 10, 100, 20, 3010005, 0x7FFF, false, false ); + + AddImageTiled( 10, 40, 400, 200, 2624 ); + AddAlphaRegion( 10, 40, 400, 200 ); + + if ( searchResults.Length > 0 ) + { + for ( int i = (page * 10); i < ((page + 1) * 10) && i < searchResults.Length; ++i ) + { + int index = i % 10; + + AddLabel( 44, 39 + (index * 20), 0x480, searchResults[i].Name ); + AddButton( 10, 39 + (index * 20), 4023, 4025, 4 + i, GumpButtonType.Reply, 0 ); + } + } + else + { + AddLabel( 15, 44, 0x480, explicitSearch ? "Nothing matched your search terms." : "No results to display." ); + } + + AddImageTiled( 10, 250, 400, 20, 2624 ); + AddAlphaRegion( 10, 250, 400, 20 ); + + if ( m_Page > 0 ) + AddButton( 10, 249, 4014, 4016, 2, GumpButtonType.Reply, 0 ); + else + AddImage( 10, 249, 4014 ); + + AddHtmlLocalized( 44, 250, 170, 20, 1061028, m_Page > 0 ? 0x7FFF : 0x5EF7, false, false ); // Previous page + + if ( ((m_Page + 1) * 10) < searchResults.Length ) + AddButton( 210, 249, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + else + AddImage( 210, 249, 4005 ); + + AddHtmlLocalized( 244, 250, 170, 20, 1061027, ((m_Page + 1) * 10) < searchResults.Length ? 0x7FFF : 0x5EF7, false, false ); // Next page + } + + private static Type typeofItem = typeof( Item ), typeofMobile = typeof( Mobile ); + + private static void Match( string match, Type[] types, List results ) + { + if ( match.Length == 0 ) + return; + + match = match.ToLower(); + + for ( int i = 0; i < types.Length; ++i ) + { + Type t = types[i]; + + if ( (typeofMobile.IsAssignableFrom( t ) || typeofItem.IsAssignableFrom( t )) && t.Name.ToLower().IndexOf( match ) >= 0 && !results.Contains( t ) ) + { + ConstructorInfo[] ctors = t.GetConstructors(); + + for ( int j = 0; j < ctors.Length; ++j ) + { + if ( ctors[j].GetParameters().Length == 0 && ctors[j].IsDefined( typeof( ConstructableAttribute ), false ) ) + { + results.Add( t ); + break; + } + } + } + } + } + + public static List Match( string match ) + { + List results = new List(); + Type[] types; + + Assembly[] asms = ScriptCompiler.Assemblies; + + for ( int i = 0; i < asms.Length; ++i ) + { + types = ScriptCompiler.GetTypeCache( asms[i] ).Types; + Match( match, types, results ); + } + + types = ScriptCompiler.GetTypeCache( Core.Assembly ).Types; + Match( match, types, results ); + + results.Sort( new TypeNameComparer() ); + + return results; + } + + private class TypeNameComparer : IComparer + { + public int Compare( Type x, Type y ) + { + return x.Name.CompareTo( y.Name ); + } + } + + public class InternalTarget : Target + { + private Type m_Type; + private Type[] m_SearchResults; + private string m_SearchString; + private int m_Page; + + public InternalTarget( Type type, Type[] searchResults, string searchString, int page ) : base( -1, true, TargetFlags.None ) + { + m_Type = type; + m_SearchResults = searchResults; + m_SearchString = searchString; + m_Page = page; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + { + if ( p is Item ) + p = ((Item)p).GetWorldTop(); + else if ( p is Mobile ) + p = ((Mobile)p).Location; + + Server.Commands.Add.Invoke( from, new Point3D( p ), new Point3D( p ), new string[]{ m_Type.Name } ); + + from.Target = new InternalTarget( m_Type, m_SearchResults, m_SearchString, m_Page ); + } + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + if ( cancelType == TargetCancelType.Canceled ) + from.SendGump( new AddGump( from, m_SearchString, m_Page, m_SearchResults, true ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + switch ( info.ButtonID ) + { + case 1: // Search + { + TextRelay te = info.GetTextEntry( 0 ); + string match = ( te == null ? "" : te.Text.Trim() ); + + if ( match.Length < 3 ) + { + from.SendMessage( "Invalid search string." ); + from.SendGump( new AddGump( from, match, m_Page, m_SearchResults, false ) ); + } + else + { + from.SendGump( new AddGump( from, match, 0, Match( match ).ToArray(), true ) ); + } + + break; + } + case 2: // Previous page + { + if ( m_Page > 0 ) + from.SendGump( new AddGump( from, m_SearchString, m_Page - 1, m_SearchResults, true ) ); + + break; + } + case 3: // Next page + { + if ( (m_Page + 1) * 10 < m_SearchResults.Length ) + from.SendGump( new AddGump( from, m_SearchString, m_Page + 1, m_SearchResults, true ) ); + + break; + } + default: + { + int index = info.ButtonID - 4; + + if ( index >= 0 && index < m_SearchResults.Length ) + { + from.SendMessage( "Where do you wish to place this object? to cancel." ); + from.Target = new InternalTarget( m_SearchResults[index], m_SearchResults, m_SearchString, m_Page ); + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/AdminGump.cs b/Scripts/Gumps/AdminGump.cs new file mode 100644 index 0000000..1797034 --- /dev/null +++ b/Scripts/Gumps/AdminGump.cs @@ -0,0 +1,3054 @@ +using System; +using System.Net; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using Server; +using Server.Items; +using Server.Prompts; +using Server.Network; +using Server.Accounting; +using Server.Commands; +using Server.Multis; +using Server.Misc; + +namespace Server.Gumps +{ + public enum AdminGumpPage + { + Information_General, + Information_Perf, + Administer, + Clients, + Accounts, + Accounts_Shared, + Firewall, + Administer_WorldBuilding, + Administer_Server, + Administer_Access, + Administer_Access_Lockdown, + Administer_Commands, + ClientInfo, + AccountDetails, + AccountDetails_Information, + AccountDetails_Characters, + AccountDetails_Access, + AccountDetails_Access_ClientIPs, + AccountDetails_Access_Restrictions, + AccountDetails_Comments, + AccountDetails_Tags, + AccountDetails_ChangePassword, + AccountDetails_ChangeAccess, + FirewallInfo + } + + public class AdminGump : Gump + { + private Mobile m_From; + private AdminGumpPage m_PageType; + private ArrayList m_List; + private int m_ListPage; + private object m_State; + + private const int LabelColor = 0x7FFF; + private const int SelectedColor = 0x421F; + private const int DisabledColor = 0x4210; + + private const int LabelColor32 = 0xFFFFFF; + private const int SelectedColor32 = 0x8080FF; + private const int DisabledColor32 = 0x808080; + + private const int LabelHue = 0x480; + private const int GreenHue = 0x40; + private const int RedHue = 0x20; + + public void AddPageButton(int x, int y, int buttonID, string text, AdminGumpPage page, params AdminGumpPage[] subPages) + { + bool isSelection = (m_PageType == page); + + for (int i = 0; !isSelection && i < subPages.Length; ++i) + isSelection = (m_PageType == subPages[i]); + + AddSelectedButton(x, y, buttonID, text, isSelection); + } + + public void AddSelectedButton(int x, int y, int buttonID, string text, bool isSelection) + { + AddButton(x, y - 1, isSelection ? 4006 : 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 200, 20, Color(text, isSelection ? SelectedColor32 : LabelColor32), false, false); + } + + public void AddButtonLabeled(int x, int y, int buttonID, string text) + { + AddButton(x, y - 1, 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, Color(text, LabelColor32), false, false); + } + + public string Center(string text) + { + return String.Format("
{0}
", text); + } + + public string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + + public void AddBlackAlpha(int x, int y, int width, int height) + { + AddImageTiled(x, y, width, height, 2624); + AddAlphaRegion(x, y, width, height); + } + + public int GetButtonID(int type, int index) + { + return 1 + (index * 11) + type; + } + + public static string FormatTimeSpan(TimeSpan ts) + { + return String.Format("{0:D2}:{1:D2}:{2:D2}:{3:D2}", ts.Days, ts.Hours % 24, ts.Minutes % 60, ts.Seconds % 60); + } + + public static string FormatByteAmount(long totalBytes) + { + if (totalBytes > 1000000000) + return String.Format("{0:F1} GB", (double)totalBytes / 1073741824); + + if (totalBytes > 1000000) + return String.Format("{0:F1} MB", (double)totalBytes / 1048576); + + if (totalBytes > 1000) + return String.Format("{0:F1} KB", (double)totalBytes / 1024); + + return String.Format("{0} Bytes", totalBytes); + } + + public static void Initialize() + { + CommandSystem.Register("Admin", AccessLevel.Administrator, new CommandEventHandler(Admin_OnCommand)); + } + + [Usage("Admin")] + [Description("Opens an interface providing server information and administration features including client, account, and firewall management.")] + public static void Admin_OnCommand(CommandEventArgs e) + { + e.Mobile.SendGump(new AdminGump(e.Mobile, AdminGumpPage.Clients, 0, null, null, null)); + } + + public static int GetHueFor(Mobile m) + { + if (m == null) + return LabelHue; + + switch (m.AccessLevel) + { + case AccessLevel.Owner: + case AccessLevel.Developer: + case AccessLevel.Administrator: return 0x516; + case AccessLevel.Seer: return 0x144; + case AccessLevel.GameMaster: return 0x21; + case AccessLevel.Counselor: return 0x2; + case AccessLevel.Player: + default: + { + if (m.Kills >= 5) + return 0x21; + else if (m.Criminal) + return 0x3B1; + + return 0x58; + } + } + } + + private static string[] m_AccessLevelStrings = new string[] + { + "Player", + "Counselor", + "Game Master", + "Seer", + "Administrator", + "Developer", + "Owner" + }; + + public static string FormatAccessLevel(AccessLevel level) + { + int v = (int)level; + + if (v >= 0 && v < m_AccessLevelStrings.Length) + return m_AccessLevelStrings[v]; + + return "Unknown"; + } + + public AdminGump(Mobile from, AdminGumpPage pageType, int listPage, ArrayList list, string notice, object state) + : base(50, 40) + { + from.CloseGump(typeof(AdminGump)); + + m_From = from; + m_PageType = pageType; + m_ListPage = listPage; + m_State = state; + m_List = list; + + AddPage(0); + + AddBackground(0, 0, 420, 440, 5054); + + AddBlackAlpha(10, 10, 170, 100); + AddBlackAlpha(190, 10, 220, 100); + AddBlackAlpha(10, 120, 400, 260); + AddBlackAlpha(10, 390, 400, 40); + + AddPageButton(10, 10, GetButtonID(0, 0), "INFORMATION", AdminGumpPage.Information_General, AdminGumpPage.Information_Perf); + AddPageButton(10, 30, GetButtonID(0, 1), "ADMINISTER", AdminGumpPage.Administer, AdminGumpPage.Administer_Access, AdminGumpPage.Administer_Commands, AdminGumpPage.Administer_Server, AdminGumpPage.Administer_WorldBuilding, AdminGumpPage.Administer_Access_Lockdown); + AddPageButton(10, 50, GetButtonID(0, 2), "CLIENT LIST", AdminGumpPage.Clients, AdminGumpPage.ClientInfo); + AddPageButton(10, 70, GetButtonID(0, 3), "ACCOUNT LIST", AdminGumpPage.Accounts, AdminGumpPage.Accounts_Shared, AdminGumpPage.AccountDetails, AdminGumpPage.AccountDetails_Information, AdminGumpPage.AccountDetails_Characters, AdminGumpPage.AccountDetails_Access, AdminGumpPage.AccountDetails_Access_ClientIPs, AdminGumpPage.AccountDetails_Access_Restrictions, AdminGumpPage.AccountDetails_Comments, AdminGumpPage.AccountDetails_Tags, AdminGumpPage.AccountDetails_ChangeAccess, AdminGumpPage.AccountDetails_ChangePassword); + AddPageButton(10, 90, GetButtonID(0, 4), "FIREWALL", AdminGumpPage.Firewall, AdminGumpPage.FirewallInfo); + + if (notice != null) + AddHtml(12, 392, 396, 36, Color(notice, LabelColor32), false, false); + + switch (pageType) + { + case AdminGumpPage.Information_General: + { + int banned = 0; + int active = 0; + + foreach (Account acct in Accounts.GetAccounts()) + { + if (acct.Banned) + ++banned; + else + ++active; + } + + AddLabel(20, 130, LabelHue, "Active Accounts:"); + AddLabel(150, 130, LabelHue, active.ToString()); + + AddLabel(20, 150, LabelHue, "Banned Accounts:"); + AddLabel(150, 150, LabelHue, banned.ToString()); + + AddLabel(20, 170, LabelHue, "Firewalled:"); + AddLabel(150, 170, LabelHue, Firewall.List.Count.ToString()); + + AddLabel(20, 190, LabelHue, "Clients:"); + AddLabel(150, 190, LabelHue, NetState.Instances.Count.ToString()); + + AddLabel(20, 210, LabelHue, "Mobiles:"); + AddLabel(150, 210, LabelHue, World.Mobiles.Count.ToString()); + + AddLabel(20, 230, LabelHue, "Mobile Scripts:"); + AddLabel(150, 230, LabelHue, Core.ScriptMobiles.ToString()); + + AddLabel(20, 250, LabelHue, "Items:"); + AddLabel(150, 250, LabelHue, World.Items.Count.ToString()); + + AddLabel(20, 270, LabelHue, "Item Scripts:"); + AddLabel(150, 270, LabelHue, Core.ScriptItems.ToString()); + + AddLabel(20, 290, LabelHue, "Uptime:"); + AddLabel(150, 290, LabelHue, FormatTimeSpan(DateTime.Now - Clock.ServerStart)); + + AddLabel(20, 310, LabelHue, "Memory:"); + AddLabel(150, 310, LabelHue, FormatByteAmount(GC.GetTotalMemory(false))); + + AddLabel(20, 330, LabelHue, "Framework:"); + AddLabel(150, 330, LabelHue, Environment.Version.ToString()); + + AddLabel(20, 350, LabelHue, "Operating System: "); + string os = Environment.OSVersion.ToString(); + + os = os.Replace("Microsoft", "MSFT"); + os = os.Replace("Service Pack", "SP"); + + AddLabel(150, 350, LabelHue, os); + + /*string str; + + try{ str = FormatTimeSpan( Core.Process.TotalProcessorTime ); } + catch{ str = "(unable to retrieve)"; } + + AddLabel( 20, 330, LabelHue, "Process Time:" ); + AddLabel( 250, 330, LabelHue, str );*/ + + /*try{ str = Core.Process.PriorityClass.ToString(); } + catch{ str = "(unable to retrieve)"; } + + AddLabel( 20, 350, LabelHue, "Process Priority:" ); + AddLabel( 250, 350, LabelHue, str );*/ + + AddPageButton(200, 20, GetButtonID(0, 0), "General", AdminGumpPage.Information_General); + AddPageButton(200, 40, GetButtonID(0, 5), "Performance", AdminGumpPage.Information_Perf); + + break; + } + case AdminGumpPage.Information_Perf: + { + AddLabel(20, 130, LabelHue, "Cycles Per Second:"); + AddLabel(40, 150, LabelHue, "Current: " + Core.CyclesPerSecond.ToString("N2")); + AddLabel(40, 170, LabelHue, "Average: " + Core.AverageCPS.ToString("N2")); + + StringBuilder sb = new StringBuilder(); + + int curUser, maxUser; + int curIOCP, maxIOCP; + + System.Threading.ThreadPool.GetAvailableThreads(out curUser, out curIOCP); + System.Threading.ThreadPool.GetMaxThreads(out maxUser, out maxIOCP); + + sb.Append("Worker Threads:
Capacity: "); + sb.Append(maxUser); + sb.Append("
Available: "); + sb.Append(curUser); + sb.Append("
Usage: "); + sb.Append(((maxUser - curUser) * 100) / maxUser); + sb.Append("%

IOCP Threads:
Capacity: "); + sb.Append(maxIOCP); + sb.Append("
Available: "); + sb.Append(curIOCP); + sb.Append("
Usage: "); + sb.Append(((maxIOCP - curIOCP) * 100) / maxIOCP); + sb.Append("%"); + + List pools = BufferPool.Pools; + + lock (pools) + { + for (int i = 0; i < pools.Count; ++i) + { + BufferPool pool = pools[i]; + string name; + int freeCount; + int initialCapacity; + int currentCapacity; + int bufferSize; + int misses; + + pool.GetInfo(out name, out freeCount, out initialCapacity, out currentCapacity, out bufferSize, out misses); + + if (sb.Length > 0) + sb.Append("

"); + + sb.Append(name); + sb.Append("
Size: "); + sb.Append(FormatByteAmount(bufferSize)); + sb.Append("
Capacity: "); + sb.Append(currentCapacity); + sb.Append(" ("); + sb.Append(misses); + sb.Append(" misses)
Available: "); + sb.Append(freeCount); + sb.Append("
Usage: "); + sb.Append(((currentCapacity - freeCount) * 100) / currentCapacity); + sb.Append("% : "); + sb.Append(FormatByteAmount((currentCapacity - freeCount) * bufferSize)); + sb.Append(" of "); + sb.Append(FormatByteAmount(currentCapacity * bufferSize)); + } + } + + + AddLabel(20, 200, LabelHue, "Pooling:"); + AddHtml(20, 220, 380, 150, sb.ToString(), true, true); + + AddPageButton(200, 20, GetButtonID(0, 0), "General", AdminGumpPage.Information_General); + AddPageButton(200, 40, GetButtonID(0, 5), "Performance", AdminGumpPage.Information_Perf); + + break; + } + case AdminGumpPage.Administer_WorldBuilding: + { + AddHtml(10, 125, 400, 20, Color(Center("Generating"), LabelColor32), false, false); + + AddButtonLabeled(20, 150, GetButtonID(3, 100), "Documentation"); + AddButtonLabeled(220, 150, GetButtonID(3, 107), "Rebuild Categorization"); + + AddButtonLabeled(20, 175, GetButtonID(3, 101), "Teleporters"); + AddButtonLabeled(220, 175, GetButtonID(3, 102), "Moongates"); + + AddButtonLabeled(20, 200, GetButtonID(3, 103), "Vendors"); + AddButtonLabeled(220, 200, GetButtonID(3, 106), "Decoration"); + + AddButtonLabeled(20, 225, GetButtonID(3, 104), "Doors"); + AddButtonLabeled(220, 225, GetButtonID(3, 105), "Signs"); + + AddHtml(20, 275, 400, 30, Color(Center("Statics"), LabelColor32), false, false); + + AddButtonLabeled(20, 300, GetButtonID(3, 110), "Freeze (Target)"); + AddButtonLabeled(20, 325, GetButtonID(3, 111), "Freeze (World)"); + AddButtonLabeled(20, 350, GetButtonID(3, 112), "Freeze (Map)"); + + AddButtonLabeled(220, 300, GetButtonID(3, 120), "Unfreeze (Target)"); + AddButtonLabeled(220, 325, GetButtonID(3, 121), "Unfreeze (World)"); + AddButtonLabeled(220, 350, GetButtonID(3, 122), "Unfreeze (Map)"); + + goto case AdminGumpPage.Administer; + } + case AdminGumpPage.Administer_Server: + { + AddHtml(10, 125, 400, 20, Color(Center("Server"), LabelColor32), false, false); + + AddButtonLabeled(20, 150, GetButtonID(3, 200), "Save"); + + /*if ( !Core.Service ) + {*/ + AddButtonLabeled(20, 180, GetButtonID(3, 201), "Shutdown (With Save)"); + AddButtonLabeled(20, 200, GetButtonID(3, 202), "Shutdown (Without Save)"); + + AddButtonLabeled(20, 230, GetButtonID(3, 203), "Shutdown & Restart (With Save)"); + AddButtonLabeled(20, 250, GetButtonID(3, 204), "Shutdown & Restart (Without Save)"); + /*} + else + { + AddLabel( 20, 215, LabelHue, "Shutdown/Restart not available." ); + }*/ + + AddHtml(10, 295, 400, 20, Color(Center("Broadcast"), LabelColor32), false, false); + + AddTextField(20, 320, 380, 20, 0); + AddButtonLabeled(20, 350, GetButtonID(3, 210), "To Everyone"); + AddButtonLabeled(220, 350, GetButtonID(3, 211), "To Staff"); + + goto case AdminGumpPage.Administer; + } + case AdminGumpPage.Administer_Access_Lockdown: + { + AddHtml(10, 125, 400, 20, Color(Center("Server Lockdown"), LabelColor32), false, false); + + AddHtml(20, 150, 380, 80, Color("When enabled, only clients with an access level equal to or greater than the specified lockdown level may access the server. After setting a lockdown level, use the Purge Invalid Clients button to disconnect those clients without access.", LabelColor32), false, false); + + AccessLevel level = Misc.AccountHandler.LockdownLevel; + bool isLockedDown = (level > AccessLevel.Player); + + AddSelectedButton(20, 230, GetButtonID(3, 500), "Not Locked Down", !isLockedDown); + AddSelectedButton(20, 260, GetButtonID(3, 504), "Administrators", (isLockedDown && level <= AccessLevel.Administrator)); + AddSelectedButton(20, 280, GetButtonID(3, 503), "Seers", (isLockedDown && level <= AccessLevel.Seer)); + AddSelectedButton(20, 300, GetButtonID(3, 502), "Game Masters", (isLockedDown && level <= AccessLevel.GameMaster)); + AddSelectedButton(20, 320, GetButtonID(3, 501), "Counselors", (isLockedDown && level <= AccessLevel.Counselor)); + + AddButtonLabeled(20, 350, GetButtonID(3, 510), "Purge Invalid Clients"); + + goto case AdminGumpPage.Administer; + } + case AdminGumpPage.Administer_Access: + { + AddHtml(10, 125, 400, 20, Color(Center("Access"), LabelColor32), false, false); + + AddHtml(10, 155, 400, 20, Color(Center("Connectivity"), LabelColor32), false, false); + + AddButtonLabeled(20, 180, GetButtonID(3, 300), "Kick"); + AddButtonLabeled(220, 180, GetButtonID(3, 301), "Ban"); + + AddButtonLabeled(20, 210, GetButtonID(3, 302), "Firewall"); + AddButtonLabeled(220, 210, GetButtonID(3, 303), "Lockdown"); + + AddHtml(10, 245, 400, 20, Color(Center("Staff"), LabelColor32), false, false); + + AddButtonLabeled(20, 270, GetButtonID(3, 310), "Make Player"); + AddButtonLabeled(20, 290, GetButtonID(3, 311), "Make Counselor"); + AddButtonLabeled(20, 310, GetButtonID(3, 312), "Make Game Master"); + AddButtonLabeled(20, 330, GetButtonID(3, 313), "Make Seer"); + + if (from.AccessLevel > AccessLevel.Administrator) + { + AddButtonLabeled(220, 270, GetButtonID(3, 314), "Make Administrator"); + + if (from.AccessLevel > AccessLevel.Developer) + { + AddButtonLabeled(220, 290, GetButtonID(3, 315), "Make Developer"); + + if (from.AccessLevel >= AccessLevel.Owner) + AddButtonLabeled(220, 310, GetButtonID(3, 316), "Make Owner"); + } + } + + goto case AdminGumpPage.Administer; + } + case AdminGumpPage.Administer_Commands: + { + AddHtml(10, 125, 400, 20, Color(Center("Commands"), LabelColor32), false, false); + + AddButtonLabeled(20, 150, GetButtonID(3, 400), "Add"); + AddButtonLabeled(220, 150, GetButtonID(3, 401), "Remove"); + + AddButtonLabeled(20, 170, GetButtonID(3, 402), "Dupe"); + AddButtonLabeled(220, 170, GetButtonID(3, 403), "Dupe in bag"); + + AddButtonLabeled(20, 200, GetButtonID(3, 404), "Properties"); + AddButtonLabeled(220, 200, GetButtonID(3, 405), "Skills"); + + AddButtonLabeled(20, 230, GetButtonID(3, 406), "Mortal"); + AddButtonLabeled(220, 230, GetButtonID(3, 407), "Immortal"); + + AddButtonLabeled(20, 250, GetButtonID(3, 408), "Squelch"); + AddButtonLabeled(220, 250, GetButtonID(3, 409), "Unsquelch"); + + AddButtonLabeled(20, 270, GetButtonID(3, 410), "Freeze"); + AddButtonLabeled(220, 270, GetButtonID(3, 411), "Unfreeze"); + + AddButtonLabeled(20, 290, GetButtonID(3, 412), "Hide"); + AddButtonLabeled(220, 290, GetButtonID(3, 413), "Unhide"); + + AddButtonLabeled(20, 310, GetButtonID(3, 414), "Kill"); + AddButtonLabeled(220, 310, GetButtonID(3, 415), "Resurrect"); + + AddButtonLabeled(20, 330, GetButtonID(3, 416), "Move"); + AddButtonLabeled(220, 330, GetButtonID(3, 417), "Wipe"); + + AddButtonLabeled(20, 350, GetButtonID(3, 418), "Teleport"); + AddButtonLabeled(220, 350, GetButtonID(3, 419), "Teleport (Multiple)"); + + goto case AdminGumpPage.Administer; + } + case AdminGumpPage.Administer: + { + AddPageButton(200, 20, GetButtonID(3, 0), "World Building", AdminGumpPage.Administer_WorldBuilding); + AddPageButton(200, 40, GetButtonID(3, 1), "Server", AdminGumpPage.Administer_Server); + AddPageButton(200, 60, GetButtonID(3, 2), "Access", AdminGumpPage.Administer_Access, AdminGumpPage.Administer_Access_Lockdown); + AddPageButton(200, 80, GetButtonID(3, 3), "Commands", AdminGumpPage.Administer_Commands); + + break; + } + case AdminGumpPage.Clients: + { + if (m_List == null) + { + m_List = new ArrayList(NetState.Instances); + m_List.Sort(NetStateComparer.Instance); + } + + AddClientHeader(); + + AddLabelCropped(12, 120, 81, 20, LabelHue, "Name"); + AddLabelCropped(95, 120, 81, 20, LabelHue, "Account"); + AddLabelCropped(178, 120, 81, 20, LabelHue, "Access Level"); + AddLabelCropped(273, 120, 109, 20, LabelHue, "IP Address"); + + if (listPage > 0) + AddButton(375, 122, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(375, 122, 0x25EA); + + if ((listPage + 1) * 12 < m_List.Count) + AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(392, 122, 0x25E6); + + if (m_List.Count == 0) + AddLabel(12, 140, LabelHue, "There are no clients to display."); + + for (int i = 0, index = (listPage * 12); i < 12 && index >= 0 && index < m_List.Count; ++i, ++index) + { + NetState ns = m_List[index] as NetState; + + if (ns == null) + continue; + + Mobile m = ns.Mobile; + Account a = ns.Account as Account; + int offset = 140 + (i * 20); + + if (m == null) + { + if (RemoteAdmin.AdminNetwork.IsAuth(ns)) + AddLabelCropped(12, offset, 81, 20, LabelHue, "(remote admin)"); + else + AddLabelCropped(12, offset, 81, 20, LabelHue, "(logging in)"); + } + else + { + AddLabelCropped(12, offset, 81, 20, GetHueFor(m), m.Name); + } + AddLabelCropped(95, offset, 81, 20, LabelHue, a == null ? "(no account)" : a.Username); + AddLabelCropped(178, offset, 81, 20, LabelHue, m == null ? (a != null ? FormatAccessLevel(a.AccessLevel) : "") : FormatAccessLevel(m.AccessLevel)); + AddLabelCropped(273, offset, 109, 20, LabelHue, ns.ToString()); + + if (a != null || m != null) + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(4, index + 2), GumpButtonType.Reply, 0); + } + + break; + } + case AdminGumpPage.ClientInfo: + { + Mobile m = state as Mobile; + + if (m == null) + break; + + AddClientHeader(); + + AddHtml(10, 125, 400, 20, Color(Center("Information"), LabelColor32), false, false); + + int y = 146; + + AddLabel(20, y, LabelHue, "Name:"); + AddLabel(200, y, GetHueFor(m), m.Name); + y += 20; + + Account a = m.Account as Account; + + AddLabel(20, y, LabelHue, "Account:"); + AddLabel(200, y, (a != null && a.Banned) ? RedHue : LabelHue, a == null ? "(no account)" : a.Username); + AddButton(380, y, 0xFA5, 0xFA7, GetButtonID(7, 14), GumpButtonType.Reply, 0); + y += 20; + + NetState ns = m.NetState; + + if (ns == null) + { + AddLabel(20, y, LabelHue, "Address:"); + AddLabel(200, y, RedHue, "Offline"); + y += 20; + + AddLabel(20, y, LabelHue, "Location:"); + AddLabel(200, y, LabelHue, String.Format("{0} [{1}]", m.Location, m.Map)); + y += 44; + } + else + { + AddLabel(20, y, LabelHue, "Address:"); + AddLabel(200, y, GreenHue, ns.ToString()); + y += 20; + + ClientVersion v = ns.Version; + + AddLabel(20, y, LabelHue, "Version:"); + AddLabel(200, y, LabelHue, v == null ? "(null)" : v.ToString()); + y += 20; + + AddLabel(20, y, LabelHue, "Location:"); + AddLabel(200, y, LabelHue, String.Format("{0} [{1}]", m.Location, m.Map)); + y += 24; + } + + AddButtonLabeled(20, y, GetButtonID(7, 0), "Go to"); + AddButtonLabeled(200, y, GetButtonID(7, 1), "Get"); + y += 20; + + AddButtonLabeled(20, y, GetButtonID(7, 2), "Kick"); + AddButtonLabeled(200, y, GetButtonID(7, 3), "Ban"); + y += 20; + + AddButtonLabeled(20, y, GetButtonID(7, 4), "Properties"); + AddButtonLabeled(200, y, GetButtonID(7, 5), "Skills"); + y += 20; + + AddButtonLabeled(20, y, GetButtonID(7, 6), "Mortal"); + AddButtonLabeled(200, y, GetButtonID(7, 7), "Immortal"); + y += 20; + + AddButtonLabeled(20, y, GetButtonID(7, 8), "Squelch"); + AddButtonLabeled(200, y, GetButtonID(7, 9), "Unsquelch"); + y += 20; + + /*AddButtonLabeled( 20, y, GetButtonID( 7, 10 ), "Hide" ); + AddButtonLabeled( 200, y, GetButtonID( 7, 11 ), "Unhide" ); + y += 20;*/ + + AddButtonLabeled(20, y, GetButtonID(7, 12), "Kill"); + AddButtonLabeled(200, y, GetButtonID(7, 13), "Resurrect"); + y += 20; + + break; + } + case AdminGumpPage.Accounts_Shared: + { + if (m_List == null) + m_List = GetAllSharedAccounts(); + + AddLabelCropped(12, 120, 60, 20, LabelHue, "Count"); + AddLabelCropped(72, 120, 120, 20, LabelHue, "Address"); + AddLabelCropped(192, 120, 180, 20, LabelHue, "Accounts"); + + if (listPage > 0) + AddButton(375, 122, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(375, 122, 0x25EA); + + if ((listPage + 1) * 12 < m_List.Count) + AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(392, 122, 0x25E6); + + if (m_List.Count == 0) + AddLabel(12, 140, LabelHue, "There are no accounts to display."); + + StringBuilder sb = new StringBuilder(); + + for (int i = 0, index = (listPage * 12); i < 12 && index >= 0 && index < m_List.Count; ++i, ++index) + { + DictionaryEntry de = (DictionaryEntry)m_List[index]; + + IPAddress ipAddr = (IPAddress)de.Key; + ArrayList accts = (ArrayList)de.Value; + + int offset = 140 + (i * 20); + + AddLabelCropped(12, offset, 60, 20, LabelHue, accts.Count.ToString()); + AddLabelCropped(72, offset, 120, 20, LabelHue, ipAddr.ToString()); + + if (sb.Length > 0) + sb.Length = 0; + + for (int j = 0; j < accts.Count; ++j) + { + if (j > 0) + sb.Append(", "); + + if (j < 4) + { + Account acct = (Account)accts[j]; + + sb.Append(acct.Username); + } + else + { + sb.Append("..."); + break; + } + } + + AddLabelCropped(192, offset, 180, 20, LabelHue, sb.ToString()); + + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(5, index + 56), GumpButtonType.Reply, 0); + } + + break; + } + case AdminGumpPage.Accounts: + { + if (m_List == null) + { + m_List = new ArrayList(); // new ArrayList( (ICollection)Accounts.GetAccounts() ); + // m_List.Sort( AccountComparer.Instance ); + } + + ArrayList rads = (state as ArrayList); + + AddAccountHeader(); + + if (rads == null) + AddLabelCropped(12, 120, 120, 20, LabelHue, "Name"); + else + AddLabelCropped(32, 120, 100, 20, LabelHue, "Name"); + + AddLabelCropped(132, 120, 120, 20, LabelHue, "Access Level"); + AddLabelCropped(252, 120, 120, 20, LabelHue, "Status"); + + if (listPage > 0) + AddButton(375, 122, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(375, 122, 0x25EA); + + if ((listPage + 1) * 12 < m_List.Count) + AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(392, 122, 0x25E6); + + if (m_List.Count == 0) + AddLabel(12, 140, LabelHue, "There are no accounts to display."); + + if (rads != null && notice == null) + { + AddButtonLabeled(10, 390, GetButtonID(5, 27), "Ban marked"); + AddButtonLabeled(10, 410, GetButtonID(5, 28), "Delete marked"); + + AddButtonLabeled(210, 390, GetButtonID(5, 29), "Mark all"); + AddButtonLabeled(210, 410, GetButtonID(5, 35), "Unmark house owners"); + } + + for (int i = 0, index = (listPage * 12); i < 12 && index >= 0 && index < m_List.Count; ++i, ++index) + { + Account a = m_List[index] as Account; + + if (a == null) + continue; + + int offset = 140 + (i * 20); + + AccessLevel accessLevel; + bool online; + + GetAccountInfo(a, out accessLevel, out online); + + if (rads == null) + { + AddLabelCropped(12, offset, 120, 20, LabelHue, a.Username); + } + else + { + AddCheck(10, offset, 0xD2, 0xD3, rads.Contains(a), index); + AddLabelCropped(32, offset, 100, 20, LabelHue, a.Username); + } + + AddLabelCropped(132, offset, 120, 20, LabelHue, FormatAccessLevel(accessLevel)); + + if (online) + AddLabelCropped(252, offset, 120, 20, GreenHue, "Online"); + else if (a.Banned) + AddLabelCropped(252, offset, 120, 20, RedHue, "Banned"); + else + AddLabelCropped(252, offset, 120, 20, RedHue, "Offline"); + + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(5, index + 56), GumpButtonType.Reply, 0); + } + + break; + } + case AdminGumpPage.AccountDetails: + { + AddPageButton(190, 10, GetButtonID(5, 0), "Information", AdminGumpPage.AccountDetails_Information, AdminGumpPage.AccountDetails_ChangeAccess, AdminGumpPage.AccountDetails_ChangePassword); + AddPageButton(190, 30, GetButtonID(5, 1), "Characters", AdminGumpPage.AccountDetails_Characters); + AddPageButton(190, 50, GetButtonID(5, 13), "Access", AdminGumpPage.AccountDetails_Access, AdminGumpPage.AccountDetails_Access_ClientIPs, AdminGumpPage.AccountDetails_Access_Restrictions); + AddPageButton(190, 70, GetButtonID(5, 2), "Comments", AdminGumpPage.AccountDetails_Comments); + AddPageButton(190, 90, GetButtonID(5, 3), "Tags", AdminGumpPage.AccountDetails_Tags); + break; + } + case AdminGumpPage.AccountDetails_ChangePassword: + { + Account a = state as Account; + + if (a == null) + break; + + AddHtml(10, 125, 400, 20, Color(Center("Change Password"), LabelColor32), false, false); + + AddLabel(20, 150, LabelHue, "Username:"); + AddLabel(200, 150, LabelHue, a.Username); + + AddLabel(20, 180, LabelHue, "Password:"); + AddTextField(200, 180, 160, 20, 0); + + AddLabel(20, 210, LabelHue, "Confirm:"); + AddTextField(200, 210, 160, 20, 1); + + AddButtonLabeled(20, 240, GetButtonID(5, 12), "Submit Change"); + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.AccountDetails_ChangeAccess: + { + Account a = state as Account; + + if (a == null) + break; + + AddHtml(10, 125, 400, 20, Color(Center("Change Access Level"), LabelColor32), false, false); + + AddLabel(20, 150, LabelHue, "Username:"); + AddLabel(200, 150, LabelHue, a.Username); + + AddLabel(20, 170, LabelHue, "Current Level:"); + AddLabel(200, 170, LabelHue, FormatAccessLevel(a.AccessLevel)); + + AddButtonLabeled(20, 200, GetButtonID(5, 20), "Player"); + AddButtonLabeled(20, 220, GetButtonID(5, 21), "Counselor"); + AddButtonLabeled(20, 240, GetButtonID(5, 22), "Game Master"); + AddButtonLabeled(20, 260, GetButtonID(5, 23), "Seer"); + + if (from.AccessLevel > AccessLevel.Administrator) + { + AddButtonLabeled(20, 280, GetButtonID(5, 24), "Administrator"); + + if (from.AccessLevel > AccessLevel.Developer) + { + AddButtonLabeled(20, 300, GetButtonID(5, 33), "Developer"); + + if (from.AccessLevel >= AccessLevel.Owner) + AddButtonLabeled(20, 320, GetButtonID(5, 34), "Owner"); + } + } + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.AccountDetails_Information: + { + Account a = state as Account; + + if (a == null) + break; + + int charCount = 0; + + for (int i = 0; i < a.Length; ++i) + { + if (a[i] != null) + ++charCount; + } + + AddHtml(10, 125, 400, 20, Color(Center("Information"), LabelColor32), false, false); + + AddLabel(20, 150, LabelHue, "Username:"); + AddLabel(200, 150, LabelHue, a.Username); + + AddLabel(20, 170, LabelHue, "Access Level:"); + AddLabel(200, 170, LabelHue, FormatAccessLevel(a.AccessLevel)); + + AddLabel(20, 190, LabelHue, "Status:"); + AddLabel(200, 190, a.Banned ? RedHue : GreenHue, a.Banned ? "Banned" : "Active"); + + DateTime banTime; + TimeSpan banDuration; + + if (a.Banned && a.GetBanTags(out banTime, out banDuration)) + { + if (banDuration == TimeSpan.MaxValue) + { + AddLabel(250, 190, LabelHue, "(Infinite)"); + } + else if (banDuration == TimeSpan.Zero) + { + AddLabel(250, 190, LabelHue, "(Zero)"); + } + else + { + TimeSpan remaining = (DateTime.Now - banTime); + + if (remaining < TimeSpan.Zero) + remaining = TimeSpan.Zero; + else if (remaining > banDuration) + remaining = banDuration; + + double remMinutes = remaining.TotalMinutes; + double totMinutes = banDuration.TotalMinutes; + + double perc = remMinutes / totMinutes; + + AddLabel(250, 190, LabelHue, String.Format("{0} [{1:F0}%]", FormatTimeSpan(banDuration), perc * 100)); + } + } + else if (a.Banned) + { + AddLabel(250, 190, LabelHue, "(Unspecified)"); + } + + AddLabel(20, 210, LabelHue, "Created:"); + AddLabel(200, 210, LabelHue, a.Created.ToString()); + + AddLabel(20, 230, LabelHue, "Last Login:"); + AddLabel(200, 230, LabelHue, a.LastLogin.ToString()); + + AddLabel(20, 250, LabelHue, "Character Count:"); + AddLabel(200, 250, LabelHue, charCount.ToString()); + + AddLabel(20, 270, LabelHue, "Comment Count:"); + AddLabel(200, 270, LabelHue, a.Comments.Count.ToString()); + + AddLabel(20, 290, LabelHue, "Tag Count:"); + AddLabel(200, 290, LabelHue, a.Tags.Count.ToString()); + + AddButtonLabeled(20, 320, GetButtonID(5, 8), "Change Password"); + AddButtonLabeled(200, 320, GetButtonID(5, 9), "Change Access Level"); + + if (!a.Banned) + AddButtonLabeled(20, 350, GetButtonID(5, 10), "Ban Account"); + else + AddButtonLabeled(20, 350, GetButtonID(5, 11), "Unban Account"); + + AddButtonLabeled(200, 350, GetButtonID(5, 25), "Delete Account"); + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.AccountDetails_Access: + { + Account a = state as Account; + + if (a == null) + break; + + AddHtml(10, 125, 400, 20, Color(Center("Access"), LabelColor32), false, false); + + AddPageButton(20, 150, GetButtonID(5, 14), "View client addresses", AdminGumpPage.AccountDetails_Access_ClientIPs); + AddPageButton(20, 170, GetButtonID(5, 15), "Manage restrictions", AdminGumpPage.AccountDetails_Access_Restrictions); + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.AccountDetails_Access_ClientIPs: + { + Account a = state as Account; + + if (a == null) + break; + + if (m_List == null) + m_List = new ArrayList(a.LoginIPs); + + AddHtml(10, 195, 400, 20, Color(Center("Client Addresses"), LabelColor32), false, false); + + AddButtonLabeled(227, 225, GetButtonID(5, 16), "View all shared accounts"); + AddButtonLabeled(227, 245, GetButtonID(5, 17), "Ban all shared accounts"); + AddButtonLabeled(227, 265, GetButtonID(5, 18), "Firewall all addresses"); + AddButtonLabeled(227, 285, GetButtonID(5, 36), "Clear all addresses"); + + AddHtml(225, 315, 180, 80, Color("List of IP addresses which have accessed this account.", LabelColor32), false, false); + + AddImageTiled(15, 219, 206, 156, 0xBBC); + AddBlackAlpha(16, 220, 204, 154); + + AddHtml(18, 221, 114, 20, Color("IP Address", LabelColor32), false, false); + + if (listPage > 0) + AddButton(184, 223, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(184, 223, 0x25EA); + + if ((listPage + 1) * 6 < m_List.Count) + AddButton(201, 223, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(201, 223, 0x25E6); + + if (m_List.Count == 0) + AddHtml(18, 243, 200, 60, Color("This account has not yet been accessed.", LabelColor32), false, false); + + for (int i = 0, index = (listPage * 6); i < 6 && index >= 0 && index < m_List.Count; ++i, ++index) + { + AddHtml(18, 243 + (i * 22), 114, 20, Color(m_List[index].ToString(), LabelColor32), false, false); + AddButton(130, 242 + (i * 22), 0xFA2, 0xFA4, GetButtonID(8, index), GumpButtonType.Reply, 0); + AddButton(160, 242 + (i * 22), 0xFA8, 0xFAA, GetButtonID(9, index), GumpButtonType.Reply, 0); + AddButton(190, 242 + (i * 22), 0xFB1, 0xFB3, GetButtonID(10, index), GumpButtonType.Reply, 0); + } + + goto case AdminGumpPage.AccountDetails_Access; + } + case AdminGumpPage.AccountDetails_Access_Restrictions: + { + Account a = state as Account; + + if (a == null) + break; + + if (m_List == null) + m_List = new ArrayList(a.IPRestrictions); + + AddHtml(10, 195, 400, 20, Color(Center("Address Restrictions"), LabelColor32), false, false); + + AddTextField(227, 225, 120, 20, 0); + + AddButtonLabeled(352, 225, GetButtonID(5, 19), "Add"); + + AddHtml(225, 255, 180, 120, Color("Any clients connecting from an address not in this list will be rejected. Or, if the list is empty, any client may connect.", LabelColor32), false, false); + + AddImageTiled(15, 219, 206, 156, 0xBBC); + AddBlackAlpha(16, 220, 204, 154); + + AddHtml(18, 221, 114, 20, Color("IP Address", LabelColor32), false, false); + + if (listPage > 0) + AddButton(184, 223, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(184, 223, 0x25EA); + + if ((listPage + 1) * 6 < m_List.Count) + AddButton(201, 223, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(201, 223, 0x25E6); + + if (m_List.Count == 0) + AddHtml(18, 243, 200, 60, Color("There are no addresses in this list.", LabelColor32), false, false); + + for (int i = 0, index = (listPage * 6); i < 6 && index >= 0 && index < m_List.Count; ++i, ++index) + { + AddHtml(18, 243 + (i * 22), 114, 20, Color(m_List[index].ToString(), LabelColor32), false, false); + AddButton(190, 242 + (i * 22), 0xFB1, 0xFB3, GetButtonID(8, index), GumpButtonType.Reply, 0); + } + + goto case AdminGumpPage.AccountDetails_Access; + } + case AdminGumpPage.AccountDetails_Characters: + { + Account a = state as Account; + + if (a == null) + break; + + AddHtml(10, 125, 400, 20, Color(Center("Characters"), LabelColor32), false, false); + + AddLabelCropped(12, 150, 120, 20, LabelHue, "Name"); + AddLabelCropped(132, 150, 120, 20, LabelHue, "Access Level"); + AddLabelCropped(252, 150, 120, 20, LabelHue, "Status"); + + int index = 0; + + for (int i = 0; i < a.Length; ++i) + { + Mobile m = a[i]; + + if (m == null) + continue; + + int offset = 170 + (index * 20); + + AddLabelCropped(12, offset, 120, 20, GetHueFor(m), m.Name); + AddLabelCropped(132, offset, 120, 20, LabelHue, FormatAccessLevel(m.AccessLevel)); + + if (m.NetState != null) + AddLabelCropped(252, offset, 120, 20, GreenHue, "Online"); + else + AddLabelCropped(252, offset, 120, 20, RedHue, "Offline"); + + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(5, i + 50), GumpButtonType.Reply, 0); + + ++index; + } + + if (index == 0) + AddLabel(12, 170, LabelHue, "The character list is empty."); + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.AccountDetails_Comments: + { + Account a = state as Account; + + if (a == null) + break; + + AddHtml(10, 125, 400, 20, Color(Center("Comments"), LabelColor32), false, false); + + AddButtonLabeled(20, 150, GetButtonID(5, 4), "Add Comment"); + + StringBuilder sb = new StringBuilder(); + + if (a.Comments.Count == 0) + sb.Append("There are no comments for this account."); + + for (int i = 0; i < a.Comments.Count; ++i) + { + if (i > 0) + sb.Append("

"); + + AccountComment c = a.Comments[i]; + + sb.AppendFormat("[{0} on {1}]
{2}", c.AddedBy, c.LastModified, c.Content); + } + + AddHtml(20, 180, 380, 190, sb.ToString(), true, true); + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.AccountDetails_Tags: + { + Account a = state as Account; + + if (a == null) + break; + + AddHtml(10, 125, 400, 20, Color(Center("Tags"), LabelColor32), false, false); + + AddButtonLabeled(20, 150, GetButtonID(5, 5), "Add Tag"); + + StringBuilder sb = new StringBuilder(); + + if (a.Tags.Count == 0) + sb.Append("There are no tags for this account."); + + for (int i = 0; i < a.Tags.Count; ++i) + { + if (i > 0) + sb.Append("
"); + + AccountTag tag = a.Tags[i]; + + sb.AppendFormat("{0} = {1}", tag.Name, tag.Value); + } + + AddHtml(20, 180, 380, 190, sb.ToString(), true, true); + + goto case AdminGumpPage.AccountDetails; + } + case AdminGumpPage.Firewall: + { + AddFirewallHeader(); + + if (m_List == null) + m_List = new ArrayList(Firewall.List); + + AddLabelCropped(12, 120, 358, 20, LabelHue, "IP Address"); + + if (listPage > 0) + AddButton(375, 122, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(375, 122, 0x25EA); + + if ((listPage + 1) * 12 < m_List.Count) + AddButton(392, 122, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(392, 122, 0x25E6); + + if (m_List.Count == 0) + AddLabel(12, 140, LabelHue, "The firewall list is empty."); + + for (int i = 0, index = (listPage * 12); i < 12 && index >= 0 && index < m_List.Count; ++i, ++index) + { + object obj = m_List[index]; + + if (!(obj is Firewall.IFirewallEntry)) + break; + + int offset = 140 + (i * 20); + + AddLabelCropped(12, offset, 358, 20, LabelHue, obj.ToString()); + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(6, index + 4), GumpButtonType.Reply, 0); + } + + break; + } + case AdminGumpPage.FirewallInfo: + { + AddFirewallHeader(); + + if (!(state is Firewall.IFirewallEntry)) + break; + + AddHtml(10, 125, 400, 20, Color(Center(state.ToString()), LabelColor32), false, false); + + AddButtonLabeled(20, 150, GetButtonID(6, 3), "Remove"); + + AddHtml(10, 175, 400, 20, Color(Center("Potentially Affected Accounts"), LabelColor32), false, false); + + if (m_List == null) + { + m_List = new ArrayList(); + + foreach (Account acct in Accounts.GetAccounts()) + { + IPAddress[] loginList = acct.LoginIPs; + + bool contains = false; + + for (int i = 0; !contains && i < loginList.Length; ++i) + { + if (((Firewall.IFirewallEntry)state).IsBlocked(loginList[i])) + { + m_List.Add(acct); + break; + } + } + } + + m_List.Sort(AccountComparer.Instance); + } + + if (listPage > 0) + AddButton(375, 177, 0x15E3, 0x15E7, GetButtonID(1, 0), GumpButtonType.Reply, 0); + else + AddImage(375, 177, 0x25EA); + + if ((listPage + 1) * 12 < m_List.Count) + AddButton(392, 177, 0x15E1, 0x15E5, GetButtonID(1, 1), GumpButtonType.Reply, 0); + else + AddImage(392, 177, 0x25E6); + + if (m_List.Count == 0) + AddLabelCropped(12, 200, 398, 20, LabelHue, "No accounts found."); + + for (int i = 0, index = (listPage * 9); i < 9 && index >= 0 && index < m_List.Count; ++i, ++index) + { + Account a = m_List[index] as Account; + + if (a == null) + continue; + + int offset = 200 + (i * 20); + + AccessLevel accessLevel; + bool online; + + GetAccountInfo(a, out accessLevel, out online); + + AddLabelCropped(12, offset, 120, 20, LabelHue, a.Username); + AddLabelCropped(132, offset, 120, 20, LabelHue, FormatAccessLevel(accessLevel)); + + if (online) + AddLabelCropped(252, offset, 120, 20, GreenHue, "Online"); + else if (a.Banned) + AddLabelCropped(252, offset, 120, 20, RedHue, "Banned"); + else + AddLabelCropped(252, offset, 120, 20, RedHue, "Offline"); + + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(5, index + 56), GumpButtonType.Reply, 0); + } + + break; + } + } + } + + public void AddTextField(int x, int y, int width, int height, int index) + { + AddBackground(x - 2, y - 2, width + 4, height + 4, 0x2486); + AddTextEntry(x + 2, y + 2, width - 4, height - 4, 0, index, ""); + } + + public void AddClientHeader() + { + AddTextField(200, 20, 200, 20, 0); + AddButtonLabeled(200, 50, GetButtonID(4, 0), "Search For Name"); + AddButtonLabeled(200, 80, GetButtonID(4, 1), "Search For IP Address"); + } + + public void AddAccountHeader() + { + AddPage(1); + + AddLabel(200, 20, LabelHue, "Name:"); + AddTextField(250, 20, 150, 20, 0); + + AddLabel(200, 50, LabelHue, "Pass:"); + AddTextField(250, 50, 150, 20, 1); + + AddButtonLabeled(200, 80, GetButtonID(5, 6), "Add"); + AddButtonLabeled(290, 80, GetButtonID(5, 7), "Search"); + + AddButton(384, 84, 0x15E1, 0x15E5, 0, GumpButtonType.Page, 2); + + AddPage(2); + + AddButtonLabeled(200, 20, GetButtonID(5, 31), "View All: Inactive"); + AddButtonLabeled(200, 40, GetButtonID(5, 32), "View All: Banned"); + AddButtonLabeled(200, 60, GetButtonID(5, 26), "View All: Shared"); + AddButtonLabeled(200, 80, GetButtonID(5, 30), "View All: Empty"); + + AddButton(384, 84, 0x15E1, 0x15E5, 0, GumpButtonType.Page, 1); + + AddPage(0); + } + + public void AddFirewallHeader() + { + AddTextField(200, 20, 200, 20, 0); + AddButtonLabeled(320, 50, GetButtonID(6, 0), "Search"); + AddButtonLabeled(200, 50, GetButtonID(6, 1), "Add (Input)"); + AddButtonLabeled(200, 80, GetButtonID(6, 2), "Add (Target)"); + } + + private static ArrayList GetAllSharedAccounts() + { + Hashtable table = new Hashtable(); + ArrayList list; + + foreach (Account acct in Accounts.GetAccounts()) + { + IPAddress[] theirAddresses = acct.LoginIPs; + + for (int i = 0; i < theirAddresses.Length; ++i) + { + list = (ArrayList)table[theirAddresses[i]]; + + if (list == null) + table[theirAddresses[i]] = list = new ArrayList(); + + list.Add(acct); + } + } + + list = new ArrayList(table); + + for (int i = 0; i < list.Count; ++i) + { + DictionaryEntry de = (DictionaryEntry)list[i]; + ArrayList accts = (ArrayList)de.Value; + + if (accts.Count == 1) + list.RemoveAt(i--); + else + accts.Sort(AccountComparer.Instance); + } + + list.Sort(SharedAccountComparer.Instance); + + return list; + } + + private class SharedAccountComparer : IComparer + { + public static readonly IComparer Instance = new SharedAccountComparer(); + + public SharedAccountComparer() + { + } + + public int Compare(object x, object y) + { + DictionaryEntry a = (DictionaryEntry)x; + DictionaryEntry b = (DictionaryEntry)y; + + ArrayList aList = (ArrayList)a.Value; + ArrayList bList = (ArrayList)b.Value; + + return bList.Count - aList.Count; + } + } + + + private static ArrayList GetSharedAccounts(IPAddress ipAddress) + { + ArrayList list = new ArrayList(); + + foreach (Account acct in Accounts.GetAccounts()) + { + IPAddress[] theirAddresses = acct.LoginIPs; + bool contains = false; + + for (int i = 0; !contains && i < theirAddresses.Length; ++i) + contains = ipAddress.Equals(theirAddresses[i]); + + if (contains) + list.Add(acct); + } + + list.Sort(AccountComparer.Instance); + return list; + } + + private static ArrayList GetSharedAccounts(IPAddress[] ipAddresses) + { + ArrayList list = new ArrayList(); + + foreach (Account acct in Accounts.GetAccounts()) + { + IPAddress[] theirAddresses = acct.LoginIPs; + bool contains = false; + + for (int i = 0; !contains && i < theirAddresses.Length; ++i) + { + IPAddress check = theirAddresses[i]; + + for (int j = 0; !contains && j < ipAddresses.Length; ++j) + contains = check.Equals(ipAddresses[j]); + } + + if (contains) + list.Add(acct); + } + + list.Sort(AccountComparer.Instance); + return list; + } + + public static void BanShared_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + string notice; + ArrayList list = null; + + if (okay) + { + Account a = (Account)state; + list = GetSharedAccounts(a.LoginIPs); + + for (int i = 0; i < list.Count; ++i) + { + ((Account)list[i]).SetUnspecifiedBan(from); + ((Account)list[i]).Banned = true; + } + + notice = "All addresses in the list have been banned."; + } + else + { + notice = "You have chosen not to ban all shared accounts."; + } + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, notice, state)); + + if (okay) + from.SendGump(new BanDurationGump(list)); + } + + public static void AccountDelete_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + if (okay) + { + Account a = (Account)state; + + CommandLogging.WriteLine(from, "{0} {1} deleting account {2}", from.AccessLevel, CommandLogging.Format(from), a.Username); + a.Delete(); + + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, null, String.Format("{0} : The account has been deleted.", a.Username), null)); + } + else + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "You have chosen not to delete the account.", state)); + } + } + + public static void ResendGump_Callback(Mobile from, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + object[] states = (object[])state; + ArrayList list = (ArrayList)states[0]; + ArrayList rads = (ArrayList)states[1]; + int page = (int)states[2]; + + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, page, list, null, rads)); + } + + public static void Marked_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + object[] states = (object[])state; + bool ban = (bool)states[0]; + ArrayList list = (ArrayList)states[1]; + ArrayList rads = (ArrayList)states[2]; + int page = (int)states[3]; + + if (okay) + { + if (!ban) + NetState.Pause(); + + for (int i = 0; i < rads.Count; ++i) + { + Account acct = (Account)rads[i]; + + if (ban) + { + CommandLogging.WriteLine(from, "{0} {1} banning account {2}", from.AccessLevel, CommandLogging.Format(from), acct.Username); + acct.SetUnspecifiedBan(from); + acct.Banned = true; + } + else + { + CommandLogging.WriteLine(from, "{0} {1} deleting account {2}", from.AccessLevel, CommandLogging.Format(from), acct.Username); + acct.Delete(); + rads.RemoveAt(i--); + list.Remove(acct); + } + } + + if (!ban) + NetState.Resume(); + + from.SendGump(new NoticeGump(1060637, 30720, String.Format("You have {0} the account{1}.", ban ? "banned" : "deleted", rads.Count == 1 ? "" : "s"), 0xFFC000, 420, 280, new NoticeGumpCallback(ResendGump_Callback), new object[] { list, rads, ban ? page : 0 })); + + if (ban) + from.SendGump(new BanDurationGump(rads)); + } + else + { + from.SendGump(new NoticeGump(1060637, 30720, String.Format("You have chosen not to {0} the account{1}.", ban ? "ban" : "delete", rads.Count == 1 ? "" : "s"), 0xFFC000, 420, 280, new NoticeGumpCallback(ResendGump_Callback), new object[] { list, rads, page })); + } + } + + public static void FirewallShared_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + string notice; + + if (okay) + { + Account a = (Account)state; + + for (int i = 0; i < a.LoginIPs.Length; ++i) + Firewall.Add(a.LoginIPs[i]); + + notice = "All addresses in the list have been firewalled."; + } + else + { + notice = "You have chosen not to firewall all addresses."; + } + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, notice, state)); + } + + public static void Firewall_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + object[] states = (object[])state; + + Account a = (Account)states[0]; + object toFirewall = states[1]; + + string notice; + + if (okay) + { + Firewall.Add(toFirewall); + + notice = String.Format("{0} : Added to firewall.", toFirewall); + } + else + { + notice = "You have chosen not to firewall the address."; + } + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, notice, a)); + } + + public static void RemoveLoginIP_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + object[] states = (object[])state; + + Account a = (Account)states[0]; + IPAddress ip = (IPAddress)states[1]; + + string notice; + + if (okay) + { + IPAddress[] ips = a.LoginIPs; + + if (ips.Length != 0 && ip == ips[0] && AccountHandler.IPTable.ContainsKey(ips[0])) + --AccountHandler.IPTable[ip]; + + List newList = new List(ips); + newList.Remove(ip); + a.LoginIPs = newList.ToArray(); + + notice = String.Format("{0} : Removed address.", ip); + } + else + { + notice = "You have chosen not to remove the address."; + } + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, notice, a)); + } + + public static void RemoveLoginIPs_Callback(Mobile from, bool okay, object state) + { + if (from.AccessLevel < AccessLevel.Administrator) + return; + + Account a = (Account)state; + + string notice; + + if (okay) + { + IPAddress[] ips = a.LoginIPs; + + if (ips.Length != 0 && AccountHandler.IPTable.ContainsKey(ips[0])) + --AccountHandler.IPTable[ips[0]]; + + a.LoginIPs = new IPAddress[0]; + + notice = "All addresses in the list have been removed."; + } + else + { + notice = "You have chosen not to clear all addresses."; + } + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, notice, a)); + } + + public override void OnResponse(Server.Network.NetState sender, RelayInfo info) + { + int val = info.ButtonID - 1; + + if (val < 0) + return; + + Mobile from = m_From; + + if (from.AccessLevel < AccessLevel.Administrator) + return; + + if (m_PageType == AdminGumpPage.Accounts) + { + ArrayList list = m_List; + ArrayList rads = m_State as ArrayList; + + if (list != null && rads != null) + { + for (int i = 0, v = m_ListPage * 12; i < 12 && v < list.Count; ++i, ++v) + { + object obj = list[v]; + + if (info.IsSwitched(v)) + { + if (!rads.Contains(obj)) + rads.Add(obj); + } + else if (rads.Contains(obj)) + { + rads.Remove(obj); + } + } + } + } + + int type = val % 11; + int index = val / 11; + + switch (type) + { + case 0: + { + AdminGumpPage page; + + switch (index) + { + case 0: page = AdminGumpPage.Information_General; break; + case 1: page = AdminGumpPage.Administer; break; + case 2: page = AdminGumpPage.Clients; break; + case 3: page = AdminGumpPage.Accounts; break; + case 4: page = AdminGumpPage.Firewall; break; + case 5: page = AdminGumpPage.Information_Perf; break; + default: return; + } + + from.SendGump(new AdminGump(from, page, 0, null, null, null)); + break; + } + case 1: + { + switch (index) + { + case 0: + { + if (m_List != null && m_ListPage > 0) + from.SendGump(new AdminGump(from, m_PageType, m_ListPage - 1, m_List, null, m_State)); + + break; + } + case 1: + { + if (m_List != null /*&& (m_ListPage + 1) * 12 < m_List.Count*/ ) + from.SendGump(new AdminGump(from, m_PageType, m_ListPage + 1, m_List, null, m_State)); + + break; + } + } + + break; + } + case 3: + { + string notice = null; + AdminGumpPage page = AdminGumpPage.Administer; + + if (index >= 500) + page = AdminGumpPage.Administer_Access_Lockdown; + else if (index >= 400) + page = AdminGumpPage.Administer_Commands; + else if (index >= 300) + page = AdminGumpPage.Administer_Access; + else if (index >= 200) + page = AdminGumpPage.Administer_Server; + else if (index >= 100) + page = AdminGumpPage.Administer_WorldBuilding; + + switch (index) + { + case 0: page = AdminGumpPage.Administer_WorldBuilding; break; + case 1: page = AdminGumpPage.Administer_Server; break; + case 2: page = AdminGumpPage.Administer_Access; break; + case 3: page = AdminGumpPage.Administer_Commands; break; + + case 100: InvokeCommand("DocGen"); notice = "Documentation has been generated."; break; + case 101: InvokeCommand("TelGen"); notice = "Teleporters have been generated."; break; + case 102: InvokeCommand("MoonGen"); notice = "Moongates have been generated."; break; + case 103: InvokeCommand("UOAMVendors"); notice = "Vendor spawners have been generated."; break; + case 104: InvokeCommand("DoorGen"); notice = "Doors have been generated."; break; + case 105: InvokeCommand("SignGen"); notice = "Signs have been generated."; break; + case 106: InvokeCommand("Decorate"); notice = "Decoration has been generated."; break; + case 107: InvokeCommand("RebuildCategorization"); notice = "Categorization menu has been regenerated. The server should be restarted."; break; + + case 110: InvokeCommand("Freeze"); notice = "Target bounding points."; break; + case 120: InvokeCommand("Unfreeze"); notice = "Target bounding points."; break; + + case 200: InvokeCommand("Save"); notice = "The world has been saved."; break; + case 201: Shutdown(false, true); break; + case 202: Shutdown(false, false); break; + case 203: Shutdown(true, true); break; + case 204: Shutdown(true, false); break; + case 210: + case 211: + { + TextRelay relay = info.GetTextEntry(0); + string text = (relay == null ? null : relay.Text.Trim()); + + if (text == null || text.Length == 0) + { + notice = "You must enter text to broadcast it."; + } + else + { + notice = "Your message has been broadcasted."; + InvokeCommand(String.Format("{0} {1}", index == 210 ? "BC" : "SM", text)); + } + + break; + } + + case 300: InvokeCommand("Kick"); notice = "Target the player to kick."; break; + case 301: InvokeCommand("Ban"); notice = "Target the player to ban."; break; + case 302: InvokeCommand("Firewall"); notice = "Target the player to firewall."; break; + + case 303: page = AdminGumpPage.Administer_Access_Lockdown; break; + + case 310: InvokeCommand("Set AccessLevel Player"); notice = "Target the player to change their access level. (Player)"; break; + case 311: InvokeCommand("Set AccessLevel Counselor"); notice = "Target the player to change their access level. (Counselor)"; break; + case 312: InvokeCommand("Set AccessLevel GameMaster"); notice = "Target the player to change their access level. (Game Master)"; break; + case 313: InvokeCommand("Set AccessLevel Seer"); notice = "Target the player to change their access level. (Seer)"; break; + + case 314: + { + if (from.AccessLevel > AccessLevel.Administrator) + { + InvokeCommand("Set AccessLevel Administrator"); + notice = "Target the player to change their access level. (Administrator)"; + } + + break; + } + + case 315: + { + if (from.AccessLevel > AccessLevel.Developer) + { + InvokeCommand("Set AccessLevel Developer"); + notice = "Target the player to change their access level. (Developer)"; + } + + break; + } + + case 316: + { + if (from.AccessLevel >= AccessLevel.Owner) + { + InvokeCommand("Set AccessLevel Owner"); + notice = "Target the player to change their access level. (Owner)"; + } + + break; + } + + case 400: notice = "Enter search terms to add objects."; break; + case 401: InvokeCommand("Remove"); notice = "Target the item or mobile to remove."; break; + case 402: InvokeCommand("Dupe"); notice = "Target the item to dupe."; break; + case 403: InvokeCommand("DupeInBag"); notice = "Target the item to dupe. The item will be duped at it's current location."; break; + case 404: InvokeCommand("Props"); notice = "Target the item or mobile to inspect."; break; + case 405: InvokeCommand("Skills"); notice = "Target a mobile to view their skills."; break; + case 406: InvokeCommand("Set Blessed False"); notice = "Target the mobile to make mortal."; break; + case 407: InvokeCommand("Set Blessed True"); notice = "Target the mobile to make immortal."; break; + case 408: InvokeCommand("Set Squelched True"); notice = "Target the mobile to squelch."; break; + case 409: InvokeCommand("Set Squelched False"); notice = "Target the mobile to unsquelch."; break; + case 410: InvokeCommand("Set Frozen True"); notice = "Target the mobile to freeze."; break; + case 411: InvokeCommand("Set Frozen False"); notice = "Target the mobile to unfreeze."; break; + case 412: InvokeCommand("Set Hidden True"); notice = "Target the mobile to hide."; break; + case 413: InvokeCommand("Set Hidden False"); notice = "Target the mobile to unhide."; break; + case 414: InvokeCommand("Kill"); notice = "Target the mobile to kill."; break; + case 415: InvokeCommand("Resurrect"); notice = "Target the mobile to resurrect."; break; + case 416: InvokeCommand("Move"); notice = "Target the item or mobile to move."; break; + case 417: InvokeCommand("Wipe"); notice = "Target bounding points."; break; + case 418: InvokeCommand("Tele"); notice = "Choose your destination."; break; + case 419: InvokeCommand("Multi Tele"); notice = "Choose your destination."; break; + + case 500: + case 501: + case 502: + case 503: + case 504: + { + Misc.AccountHandler.LockdownLevel = (AccessLevel)(index - 500); + + if (Misc.AccountHandler.LockdownLevel > AccessLevel.Player) + notice = "The lockdown level has been changed."; + else + notice = "The server is now accessible to everyone."; + + break; + } + + case 510: + { + AccessLevel level = Misc.AccountHandler.LockdownLevel; + + if (level > AccessLevel.Player) + { + List clients = NetState.Instances; + int count = 0; + + for (int i = 0; i < clients.Count; ++i) + { + NetState ns = clients[i]; + IAccount a = ns.Account; + + if (a == null) + continue; + + bool hasAccess = false; + + if (a.AccessLevel >= level) + { + hasAccess = true; + } + else + { + for (int j = 0; !hasAccess && j < a.Length; ++j) + { + Mobile m = a[j]; + + if (m != null && m.AccessLevel >= level) + hasAccess = true; + } + } + + if (!hasAccess) + { + ns.Dispose(); + ++count; + } + } + + if (count == 0) + notice = "Nobody without access was found to disconnect."; + else + notice = String.Format("Number of players disconnected: {0}", count); + } + else + { + notice = "The server is not currently locked down."; + } + + break; + } + } + + from.SendGump(new AdminGump(from, page, 0, null, notice, null)); + + switch (index) + { + case 400: InvokeCommand("Add"); break; + case 111: InvokeCommand("FreezeWorld"); break; + case 112: InvokeCommand("FreezeMap"); break; + case 121: InvokeCommand("UnfreezeWorld"); break; + case 122: InvokeCommand("UnfreezeMap"); break; + } + + break; + } + case 4: + { + switch (index) + { + case 0: + case 1: + { + bool forName = (index == 0); + + ArrayList results = new ArrayList(); + + TextRelay matchEntry = info.GetTextEntry(0); + string match = (matchEntry == null ? null : matchEntry.Text.Trim().ToLower()); + string notice = null; + + if (match == null || match.Length == 0) + { + notice = String.Format("You must enter {0} to search.", forName ? "a name" : "an ip address"); + } + else + { + List instances = NetState.Instances; + + for (int i = 0; i < instances.Count; ++i) + { + NetState ns = instances[i]; + + bool isMatch; + + if (forName) + { + Mobile m = ns.Mobile; + IAccount a = ns.Account; + + isMatch = (m != null && m.Name.ToLower().IndexOf(match) >= 0) + || (a != null && a.Username.ToLower().IndexOf(match) >= 0); + } + else + { + isMatch = (ns.ToString().IndexOf(match) >= 0); + } + + if (isMatch) + results.Add(ns); + } + + results.Sort(NetStateComparer.Instance); + } + + if (results.Count == 1) + { + NetState ns = (NetState)results[0]; + object state = ns.Mobile; + + if (state == null) + state = ns.Account; + + if (state is Mobile) + from.SendGump(new AdminGump(from, AdminGumpPage.ClientInfo, 0, null, "One match found.", state)); + else if (state is Account) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "One match found.", state)); + else + from.SendGump(new AdminGump(from, AdminGumpPage.Clients, 0, results, "One match found.", null)); + } + else + { + from.SendGump(new AdminGump(from, AdminGumpPage.Clients, 0, results, notice == null ? (results.Count == 0 ? "Nothing matched your search terms." : null) : notice, null)); + } + + break; + } + default: + { + index -= 2; + + if (m_List != null && index >= 0 && index < m_List.Count) + { + NetState ns = m_List[index] as NetState; + + if (ns == null) + break; + + Mobile m = ns.Mobile; + Account a = ns.Account as Account; + + if (m != null) + from.SendGump(new AdminGump(from, AdminGumpPage.ClientInfo, 0, null, null, m)); + else if (a != null) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, null, a)); + } + + break; + } + } + + break; + } + case 5: + { + switch (index) + { + case 0: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, null, m_State)); break; + case 1: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Characters, 0, null, null, m_State)); break; + case 2: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Comments, 0, null, null, m_State)); break; + case 3: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Tags, 0, null, null, m_State)); break; + case 13: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access, 0, null, null, m_State)); break; + case 14: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, null, m_State)); break; + case 15: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_Restrictions, 0, null, null, m_State)); break; + case 4: from.Prompt = new AddCommentPrompt(m_State as Account); from.SendMessage("Enter the new account comment."); break; + case 5: from.Prompt = new AddTagNamePrompt(m_State as Account); from.SendMessage("Enter the new tag name."); break; + case 6: + { + TextRelay unEntry = info.GetTextEntry(0); + TextRelay pwEntry = info.GetTextEntry(1); + + string un = (unEntry == null ? null : unEntry.Text.Trim()); + string pw = (pwEntry == null ? null : pwEntry.Text.Trim()); + + Account dispAccount = null; + string notice; + + if (un == null || un.Length == 0) + { + notice = "You must enter a username to add an account."; + } + else if (pw == null || pw.Length == 0) + { + notice = "You must enter a password to add an account."; + } + else + { + IAccount account = Accounts.GetAccount(un); + + if (account != null) + { + notice = "There is already an account with that username."; + } + else + { + dispAccount = new Account(un, pw); + notice = String.Format("{0} : Account added.", un); + CommandLogging.WriteLine(from, "{0} {1} adding new account: {2}", from.AccessLevel, CommandLogging.Format(from), un); + } + } + + from.SendGump(new AdminGump(from, dispAccount != null ? AdminGumpPage.AccountDetails_Information : m_PageType, m_ListPage, m_List, notice, dispAccount != null ? dispAccount : m_State)); + break; + } + case 7: + { + ArrayList results; + + TextRelay matchEntry = info.GetTextEntry(0); + string match = (matchEntry == null ? null : matchEntry.Text.Trim().ToLower()); + string notice = null; + + if (match == null || match.Length == 0) + { + results = new ArrayList((ICollection)Accounts.GetAccounts()); + results.Sort(AccountComparer.Instance); + //notice = "You must enter a username to search."; + } + else + { + results = new ArrayList(); + foreach (Account check in Accounts.GetAccounts()) + { + if (check.Username.ToLower().IndexOf(match) >= 0) + results.Add(check); + } + + results.Sort(AccountComparer.Instance); + } + + if (results.Count == 1) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "One match found.", results[0])); + else + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, results, notice == null ? (results.Count == 0 ? "Nothing matched your search terms." : null) : notice, new ArrayList())); + + break; + } + case 8: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_ChangePassword, 0, null, null, m_State)); break; + case 9: from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_ChangeAccess, 0, null, null, m_State)); break; + case 10: + case 11: + { + Account a = m_State as Account; + + if (a == null) + break; + + a.SetUnspecifiedBan(from); + a.Banned = (index == 10); + CommandLogging.WriteLine(from, "{0} {1} {3} account {2}", from.AccessLevel, CommandLogging.Format(from), a.Username, a.Banned ? "banning" : "unbanning"); + from.SendGump(new AdminGump(from, m_PageType, m_ListPage, m_List, String.Format("The account has been {0}.", a.Banned ? "banned" : "unbanned"), m_State)); + + if (index == 10) + from.SendGump(new BanDurationGump(a)); + + break; + } + case 12: + { + Account a = m_State as Account; + + if (a == null) + break; + + TextRelay passwordEntry = info.GetTextEntry(0); + TextRelay confirmEntry = info.GetTextEntry(1); + + string password = (passwordEntry == null ? null : passwordEntry.Text.Trim()); + string confirm = (confirmEntry == null ? null : confirmEntry.Text.Trim()); + + string notice; + AdminGumpPage page = AdminGumpPage.AccountDetails_ChangePassword; + + if (password == null || password.Length == 0) + { + notice = "You must enter the password."; + } + else if (confirm != password) + { + notice = "You must confirm the password. That field must precisely match the password field."; + } + else + { + notice = "The password has been changed."; + a.SetPassword(password); + page = AdminGumpPage.AccountDetails_Information; + CommandLogging.WriteLine(from, "{0} {1} changing password of account {2}", from.AccessLevel, CommandLogging.Format(from), a.Username); + } + + from.SendGump(new AdminGump(from, page, 0, null, notice, m_State)); + + break; + } + case 16: // view shared + { + Account a = m_State as Account; + + if (a == null) + break; + + ArrayList list = GetSharedAccounts(a.LoginIPs); + + if (list.Count > 1 || (list.Count == 1 && !list.Contains(a))) + { + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, list, null, new ArrayList())); + } + else if (a.LoginIPs.Length > 0) + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "There are no other accounts which share an address with this one.", m_State)); + } + else + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "This account has not yet been accessed.", m_State)); + } + + break; + } + case 17: // ban shared + { + Account a = m_State as Account; + + if (a == null) + break; + + ArrayList list = GetSharedAccounts(a.LoginIPs); + + if (list.Count > 0) + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat("You are about to ban {0} account{1}. Do you wish to continue?", list.Count, list.Count != 1 ? "s" : ""); + + for (int i = 0; i < list.Count; ++i) + sb.AppendFormat("
- {0}", ((Account)list[i]).Username); + + from.SendGump(new WarningGump(1060635, 30720, sb.ToString(), 0xFFC000, 420, 400, new WarningGumpCallback(BanShared_Callback), a)); + } + else if (a.LoginIPs.Length > 0) + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "There are no accounts which share an address with this one.", m_State)); + } + else + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "This account has not yet been accessed.", m_State)); + } + + break; + } + case 18: // firewall all + { + Account a = m_State as Account; + + if (a == null) + break; + + if (a.LoginIPs.Length > 0) + { + from.SendGump(new WarningGump(1060635, 30720, String.Format("You are about to firewall {0} address{1}. Do you wish to continue?", a.LoginIPs.Length, a.LoginIPs.Length != 1 ? "s" : ""), 0xFFC000, 420, 400, new WarningGumpCallback(FirewallShared_Callback), a)); + } + else + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "This account has not yet been accessed.", m_State)); + } + + break; + } + case 19: // add + { + Account a = m_State as Account; + + if (a == null) + break; + + TextRelay entry = info.GetTextEntry(0); + string ip = (entry == null ? null : entry.Text.Trim()); + + string notice; + + if (ip == null || ip.Length == 0) + { + notice = "You must enter an address to add."; + } + else + { + string[] list = a.IPRestrictions; + + bool contains = false; + for (int i = 0; !contains && i < list.Length; ++i) + contains = (list[i] == ip); + + if (contains) + { + notice = "That address is already contained in the list."; + } + else + { + string[] newList = new string[list.Length + 1]; + + for (int i = 0; i < list.Length; ++i) + newList[i] = list[i]; + + newList[list.Length] = ip; + + a.IPRestrictions = newList; + + notice = String.Format("{0} : Added to restriction list.", ip); + } + } + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_Restrictions, 0, null, notice, m_State)); + + break; + } + case 20: // Change access level + case 21: + case 22: + case 23: + case 24: + { + Account a = m_State as Account; + + if (a == null) + break; + + AccessLevel newLevel; + + switch (index) + { + default: + case 20: newLevel = AccessLevel.Player; break; + case 21: newLevel = AccessLevel.Counselor; break; + case 22: newLevel = AccessLevel.GameMaster; break; + case 23: newLevel = AccessLevel.Seer; break; + case 24: newLevel = AccessLevel.Administrator; break; + case 33: newLevel = AccessLevel.Developer; break; + case 34: newLevel = AccessLevel.Owner; break; + } + + if (newLevel < from.AccessLevel || from.AccessLevel == AccessLevel.Owner) + { + a.AccessLevel = newLevel; + + CommandLogging.WriteLine(from, "{0} {1} changing access level of account {2} to {3}", from.AccessLevel, CommandLogging.Format(from), a.Username, a.AccessLevel); + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "The access level has been changed.", m_State)); + } + + break; + } + case 25: + { + Account a = m_State as Account; + + if (a == null) + break; + + from.SendGump(new WarningGump(1060635, 30720, String.Format("
Account of {0}

You are about to permanently delete the account. Likewise, all characters on the account will be deleted, including equiped, inventory, and banked items. Any houses tied to the account will be demolished.

Do you wish to continue?", a.Username), 0xFFC000, 420, 280, new WarningGumpCallback(AccountDelete_Callback), m_State)); + break; + } + case 26: // View all shared accounts + { + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts_Shared, 0, null, null, null)); + break; + } + case 27: // Ban marked + { + ArrayList list = m_List; + ArrayList rads = m_State as ArrayList; + + if (list == null || rads == null) + break; + + if (rads.Count > 0) + from.SendGump(new WarningGump(1060635, 30720, String.Format("You are about to ban {0} marked account{1}. Be cautioned, the only way to reverse this is by hand--manually unbanning each account.

Do you wish to continue?", rads.Count, rads.Count == 1 ? "" : "s"), 0xFFC000, 420, 280, new WarningGumpCallback(Marked_Callback), new object[] { true, list, rads, m_ListPage })); + else + from.SendGump(new NoticeGump(1060637, 30720, "You have not yet marked any accounts. Place a check mark next to the accounts you wish to ban and then try again.", 0xFFC000, 420, 280, new NoticeGumpCallback(ResendGump_Callback), new object[] { list, rads, m_ListPage })); + + break; + } + case 28: // Delete marked + { + ArrayList list = m_List; + ArrayList rads = m_State as ArrayList; + + if (list == null || rads == null) + break; + + if (rads.Count > 0) + from.SendGump(new WarningGump(1060635, 30720, String.Format("You are about to permanently delete {0} marked account{1}. Likewise, all characters on the account{1} will be deleted, including equiped, inventory, and banked items. Any houses tied to the account{1} will be demolished.

Do you wish to continue?", rads.Count, rads.Count == 1 ? "" : "s"), 0xFFC000, 420, 280, new WarningGumpCallback(Marked_Callback), new object[] { false, list, rads, m_ListPage })); + else + from.SendGump(new NoticeGump(1060637, 30720, "You have not yet marked any accounts. Place a check mark next to the accounts you wish to ban and then try again.", 0xFFC000, 420, 280, new NoticeGumpCallback(ResendGump_Callback), new object[] { list, rads, m_ListPage })); + + break; + } + case 29: // Mark all + { + ArrayList list = m_List; + ArrayList rads = m_State as ArrayList; + + if (list == null || rads == null) + break; + + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, m_ListPage, m_List, null, new ArrayList(list))); + + break; + } + case 30: // View all empty accounts + { + ArrayList results = new ArrayList(); + + foreach (Account acct in Accounts.GetAccounts()) + { + bool empty = true; + + for (int i = 0; empty && i < acct.Length; ++i) + empty = (acct[i] == null); + + if (empty) + results.Add(acct); + } + + if (results.Count == 1) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "One match found.", results[0])); + else + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, results, (results.Count == 0 ? "Nothing matched your search terms." : null), new ArrayList())); + + break; + } + case 31: // View all inactive accounts + { + ArrayList results = new ArrayList(); + + foreach (Account acct in Accounts.GetAccounts()) + { + if (acct.Inactive) + results.Add(acct); + } + + if (results.Count == 1) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "One match found.", results[0])); + else + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, results, (results.Count == 0 ? "Nothing matched your search terms." : null), new ArrayList())); + + break; + } + case 32: // View all banned accounts + { + ArrayList results = new ArrayList(); + + foreach (Account acct in Accounts.GetAccounts()) + { + if (acct.Banned) + results.Add(acct); + } + + if (results.Count == 1) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, "One match found.", results[0])); + else + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, results, (results.Count == 0 ? "Nothing matched your search terms." : null), new ArrayList())); + + break; + } + case 33: // Change access level (extended) + case 34: + { + goto case 20; + } + case 35: // Unmark house owners + { + ArrayList list = m_List; + ArrayList rads = m_State as ArrayList; + + if (list == null || rads == null) + break; + + ArrayList newRads = new ArrayList(); + + foreach (Account acct in rads) + { + bool hasHouse = false; + + for (int i = 0; i < acct.Length && !hasHouse; ++i) + if (acct[i] != null && BaseHouse.HasHouse(acct[i])) + hasHouse = true; + + if (!hasHouse) + newRads.Add(acct); + } + + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, m_ListPage, m_List, null, newRads)); + + break; + } + case 36: // Clear login addresses + { + Account a = m_State as Account; + + if (a == null) + break; + + IPAddress[] ips = a.LoginIPs; + + if (ips.Length == 0) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "This account has not yet been accessed.", m_State)); + else + from.SendGump(new WarningGump(1060635, 30720, String.Format("You are about to clear the address list for account {0} containing {1} {2}. Do you wish to continue?", a, ips.Length, (ips.Length == 1) ? "entry" : "entries"), 0xFFC000, 420, 280, new WarningGumpCallback(RemoveLoginIPs_Callback), a)); + + break; + } + default: + { + index -= 50; + + Account a = m_State as Account; + + if (a != null && index >= 0 && index < a.Length) + { + Mobile m = a[index]; + + if (m != null) + from.SendGump(new AdminGump(from, AdminGumpPage.ClientInfo, 0, null, null, m)); + } + else + { + index -= 6; + + if (m_List != null && index >= 0 && index < m_List.Count) + { + if (m_List[index] is Account) + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, null, m_List[index])); + else if (m_List[index] is DictionaryEntry) + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, (ArrayList)(((DictionaryEntry)m_List[index]).Value), null, new ArrayList())); + } + } + + break; + } + } + + break; + } + case 6: + { + switch (index) + { + case 0: + { + TextRelay matchEntry = info.GetTextEntry(0); + string match = (matchEntry == null ? null : matchEntry.Text.Trim()); + + string notice = null; + ArrayList results = new ArrayList(); + + if (match == null || match.Length == 0) + { + notice = "You must enter a username to search."; + } + else + { + for (int i = 0; i < Firewall.List.Count; ++i) + { + string check = Firewall.List[i].ToString(); + + if (check.IndexOf(match) >= 0) + results.Add(Firewall.List[i]); + } + } + + if (results.Count == 1) + from.SendGump(new AdminGump(from, AdminGumpPage.FirewallInfo, 0, null, "One match found.", results[0])); + else if (results.Count > 1) + from.SendGump(new AdminGump(from, AdminGumpPage.Firewall, 0, results, String.Format("Search results for : {0}", match), m_State)); + else + from.SendGump(new AdminGump(from, m_PageType, m_ListPage, m_List, notice == null ? "Nothing matched your search terms." : notice, m_State)); + + break; + } + case 1: + { + TextRelay relay = info.GetTextEntry(0); + string text = (relay == null ? null : relay.Text.Trim()); + + if (text == null || text.Length == 0) + { + from.SendGump(new AdminGump(from, m_PageType, m_ListPage, m_List, "You must enter an address or pattern to add.", m_State)); + } + else if (!Utility.IsValidIP(text)) + { + from.SendGump(new AdminGump(from, m_PageType, m_ListPage, m_List, "That is not a valid address or pattern.", m_State)); + } + else + { + object toAdd = Firewall.ToFirewallEntry(text); + + CommandLogging.WriteLine(from, "{0} {1} firewalling {2}", from.AccessLevel, CommandLogging.Format(from), toAdd); + + Firewall.Add(toAdd); + from.SendGump(new AdminGump(from, AdminGumpPage.FirewallInfo, 0, null, String.Format("{0} : Added to firewall.", toAdd), toAdd)); + } + + break; + } + case 2: + { + InvokeCommand("Firewall"); + from.SendGump(new AdminGump(from, m_PageType, m_ListPage, m_List, "Target the player to firewall.", m_State)); + break; + } + case 3: + { + if (m_State is Firewall.IFirewallEntry) + { + CommandLogging.WriteLine(from, "{0} {1} removing {2} from firewall list", from.AccessLevel, CommandLogging.Format(from), m_State); + + Firewall.Remove(m_State); + from.SendGump(new AdminGump(from, AdminGumpPage.Firewall, 0, null, String.Format("{0} : Removed from firewall.", m_State), null)); + } + + break; + } + default: + { + index -= 4; + + if (m_List != null && index >= 0 && index < m_List.Count) + from.SendGump(new AdminGump(from, AdminGumpPage.FirewallInfo, 0, null, null, m_List[index])); + + break; + } + } + + break; + } + case 7: + { + Mobile m = m_State as Mobile; + + if (m == null) + break; + + string notice = null; + bool sendGump = true; + + switch (index) + { + case 0: + { + Map map = m.Map; + Point3D loc = m.Location; + + if (map == null || map == Map.Internal) + { + map = m.LogoutMap; + loc = m.LogoutLocation; + } + + if (map != null && map != Map.Internal) + { + from.MoveToWorld(loc, map); + notice = "You have been teleported to their location."; + } + + break; + } + case 1: + { + m.MoveToWorld(from.Location, from.Map); + notice = "They have been teleported to your location."; + break; + } + case 2: + { + NetState ns = m.NetState; + + if (ns != null) + { + CommandLogging.WriteLine(from, "{0} {1} {2} {3}", from.AccessLevel, CommandLogging.Format(from), "kicking", CommandLogging.Format(m)); + ns.Dispose(); + notice = "They have been kicked."; + } + else + { + notice = "They are already disconnected."; + } + + break; + } + case 3: + { + Account a = m.Account as Account; + + if (a != null) + { + CommandLogging.WriteLine(from, "{0} {1} {2} {3}", from.AccessLevel, CommandLogging.Format(from), "banning", CommandLogging.Format(m)); + a.Banned = true; + + NetState ns = m.NetState; + + if (ns != null) + ns.Dispose(); + + notice = "They have been banned."; + } + + break; + } + case 6: + { + Properties.SetValue(from, m, "Blessed", "False"); + notice = "They are now mortal."; + break; + } + case 7: + { + Properties.SetValue(from, m, "Blessed", "True"); + notice = "They are now immortal."; + break; + } + case 8: + { + Properties.SetValue(from, m, "Squelched", "True"); + notice = "They are now squelched."; + break; + } + case 9: + { + Properties.SetValue(from, m, "Squelched", "False"); + notice = "They are now unsquelched."; + break; + } + case 10: + { + Properties.SetValue(from, m, "Hidden", "True"); + notice = "They are now hidden."; + break; + } + case 11: + { + Properties.SetValue(from, m, "Hidden", "False"); + notice = "They are now unhidden."; + break; + } + case 12: + { + CommandLogging.WriteLine(from, "{0} {1} killing {2}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(m)); + m.Kill(); + notice = "They have been killed."; + break; + } + case 13: + { + CommandLogging.WriteLine(from, "{0} {1} resurrecting {2}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(m)); + m.Resurrect(); + notice = "They have been resurrected."; + break; + } + case 14: + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Information, 0, null, null, m.Account)); + sendGump = false; + break; + } + } + + if (sendGump) + from.SendGump(new AdminGump(from, AdminGumpPage.ClientInfo, 0, null, notice, m_State)); + + switch (index) + { + case 3: + { + Account a = m.Account as Account; + + if (a != null) + from.SendGump(new BanDurationGump(a)); + + break; + } + case 4: + { + from.SendGump(new PropertiesGump(from, m)); + break; + } + case 5: + { + from.SendGump(new SkillsGump(from, m)); + break; + } + } + + break; + } + case 8: + { + if (m_List != null && index >= 0 && index < m_List.Count) + { + Account a = m_State as Account; + + if (a == null) + break; + + if (m_PageType == AdminGumpPage.AccountDetails_Access_ClientIPs) + { + from.SendGump(new WarningGump(1060635, 30720, String.Format("You are about to firewall {0}. All connection attempts from a matching IP will be refused. Are you sure?", m_List[index]), 0xFFC000, 420, 280, new WarningGumpCallback(Firewall_Callback), new object[] { a, m_List[index] })); + } + else if (m_PageType == AdminGumpPage.AccountDetails_Access_Restrictions) + { + ArrayList list = new ArrayList(a.IPRestrictions); + + list.Remove(m_List[index]); + + a.IPRestrictions = (string[])list.ToArray(typeof(string)); + + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_Restrictions, 0, null, String.Format("{0} : Removed from list.", m_List[index]), a)); + } + } + + break; + } + case 9: + { + if (m_List != null && index >= 0 && index < m_List.Count) + { + if (m_PageType == AdminGumpPage.AccountDetails_Access_ClientIPs) + { + object obj = m_List[index]; + + if (!(obj is IPAddress)) + break; + + Account a = m_State as Account; + + if (a == null) + break; + + ArrayList list = GetSharedAccounts((IPAddress)obj); + + if (list.Count > 1 || (list.Count == 1 && !list.Contains(a))) + from.SendGump(new AdminGump(from, AdminGumpPage.Accounts, 0, list, null, new ArrayList())); + else + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Access_ClientIPs, 0, null, "There are no other accounts which share that address.", m_State)); + } + } + + break; + } + case 10: + { + if (m_List != null && index >= 0 && index < m_List.Count) + { + if (m_PageType == AdminGumpPage.AccountDetails_Access_ClientIPs) + { + IPAddress ip = m_List[index] as IPAddress; + + if (ip == null) + break; + + Account a = m_State as Account; + + if (a == null) + break; + + from.SendGump(new WarningGump(1060635, 30720, String.Format("You are about to remove address {0} from account {1}. Do you wish to continue?", ip, a), 0xFFC000, 420, 280, new WarningGumpCallback(RemoveLoginIP_Callback), new object[] { a, ip })); + } + } + + break; + } + } + } + + private void Shutdown(bool restart, bool save) + { + CommandLogging.WriteLine(m_From, "{0} {1} shutting down server (Restart: {2}) (Save: {3})", m_From.AccessLevel, CommandLogging.Format(m_From), restart, save); + + if (save) + InvokeCommand("Save"); + + Core.Kill(restart); + } + + private void InvokeCommand(string c) + { + CommandSystem.Handle(m_From, String.Format("{0}{1}", CommandSystem.Prefix, c)); + } + + public static void GetAccountInfo(Account a, out AccessLevel accessLevel, out bool online) + { + accessLevel = a.AccessLevel; + online = false; + + for (int j = 0; j < a.Length; ++j) + { + Mobile check = a[j]; + + if (check == null) + continue; + + if (check.AccessLevel > accessLevel) + accessLevel = check.AccessLevel; + + if (check.NetState != null) + online = true; + } + } + + private class AddCommentPrompt : Prompt + { + private Account m_Account; + + public AddCommentPrompt(Account acct) + { + m_Account = acct; + } + + public override void OnCancel(Mobile from) + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Comments, 0, null, "Request to add comment was canceled.", m_Account)); + } + + public override void OnResponse(Mobile from, string text) + { + if (m_Account != null) + { + m_Account.Comments.Add(new AccountComment(from.RawName, text)); + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Comments, 0, null, "Comment added.", m_Account)); + } + } + } + + private class AddTagNamePrompt : Prompt + { + private Account m_Account; + + public AddTagNamePrompt(Account acct) + { + m_Account = acct; + } + + public override void OnCancel(Mobile from) + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Tags, 0, null, "Request to add tag was canceled.", m_Account)); + } + + public override void OnResponse(Mobile from, string text) + { + from.Prompt = new AddTagValuePrompt(m_Account, text); + from.SendMessage("Enter the new tag value."); + } + } + + private class AddTagValuePrompt : Prompt + { + private Account m_Account; + private string m_Name; + + public AddTagValuePrompt(Account acct, string name) + { + m_Account = acct; + m_Name = name; + } + + public override void OnCancel(Mobile from) + { + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Tags, 0, null, "Request to add tag was canceled.", m_Account)); + } + + public override void OnResponse(Mobile from, string text) + { + if (m_Account != null) + { + m_Account.AddTag(m_Name, text); + from.SendGump(new AdminGump(from, AdminGumpPage.AccountDetails_Tags, 0, null, "Tag added.", m_Account)); + } + } + } + + private class NetStateComparer : IComparer + { + public static readonly IComparer Instance = new NetStateComparer(); + + public NetStateComparer() + { + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + return 0; + else if (x == null) + return -1; + else if (y == null) + return 1; + + NetState a = x as NetState; + NetState b = y as NetState; + + if (a == null || b == null) + throw new ArgumentException(); + + Mobile aMob = a.Mobile; + Mobile bMob = b.Mobile; + + if (aMob == null && bMob == null) + return 0; + else if (aMob == null) + return 1; + else if (bMob == null) + return -1; + + if (aMob.AccessLevel > bMob.AccessLevel) + return -1; + else if (aMob.AccessLevel < bMob.AccessLevel) + return 1; + else + return Insensitive.Compare(aMob.Name, bMob.Name); + } + } + + private class AccountComparer : IComparer + { + public static readonly IComparer Instance = new AccountComparer(); + + public AccountComparer() + { + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + return 0; + else if (x == null) + return -1; + else if (y == null) + return 1; + + Account a = x as Account; + Account b = y as Account; + + if (a == null || b == null) + throw new ArgumentException(); + + AccessLevel aLevel, bLevel; + bool aOnline, bOnline; + + GetAccountInfo(a, out aLevel, out aOnline); + GetAccountInfo(b, out bLevel, out bOnline); + + if (aOnline && !bOnline) + return -1; + else if (bOnline && !aOnline) + return 1; + else if (aLevel > bLevel) + return -1; + else if (aLevel < bLevel) + return 1; + else + return Insensitive.Compare(a.Username, b.Username); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/BanDurationGump.cs b/Scripts/Gumps/BanDurationGump.cs new file mode 100644 index 0000000..b545259 --- /dev/null +++ b/Scripts/Gumps/BanDurationGump.cs @@ -0,0 +1,260 @@ +using System; +using System.Net; +using System.Text; +using System.Collections; +using System.Diagnostics; +using Server; +using Server.Items; +using Server.Prompts; +using Server.Network; +using Server.Accounting; +using Server.Commands; + +namespace Server.Gumps +{ + public class BanDurationGump : Gump + { + private ArrayList m_List; + + public void AddButtonLabeled( int x, int y, int buttonID, string text ) + { + AddButton( x, y - 1, 4005, 4007, buttonID, GumpButtonType.Reply, 0 ); + AddHtml( x + 35, y, 240, 20, text, false, false ); + } + + public void AddTextField( int x, int y, int width, int height, int index ) + { + AddBackground( x - 2, y - 2, width + 4, height + 4, 0x2486 ); + AddTextEntry( x + 2, y + 2, width - 4, height - 4, 0, index, "" ); + } + + public static ArrayList MakeList( object obj ) + { + ArrayList list = new ArrayList( 1 ); + list.Add( obj ); + return list; + } + + public BanDurationGump( Account a ) : this( MakeList( a ) ) + { + } + + public BanDurationGump( ArrayList list ) : base( (640 - 500) / 2, (480 - 305) / 2 ) + { + m_List = list; + + int width = 500; + int height = 305; + + AddPage( 0 ); + + AddBackground( 0, 0, width, height, 5054 ); + + //AddImageTiled( 10, 10, width - 20, 20, 2624 ); + //AddAlphaRegion( 10, 10, width - 20, 20 ); + AddHtml( 10, 10, width - 20, 20, "
Ban Duration
", false, false ); + + //AddImageTiled( 10, 40, width - 20, height - 50, 2624 ); + //AddAlphaRegion( 10, 40, width - 20, height - 50 ); + + AddButtonLabeled( 15, 45, 1, "Infinite" ); + AddButtonLabeled( 15, 65, 2, "From D:H:M:S" ); + + AddInput( 3, 0, "Days" ); + AddInput( 4, 1, "Hours" ); + AddInput( 5, 2, "Minutes" ); + AddInput( 6, 3, "Seconds" ); + + AddHtml( 170, 45, 240, 20, "Comments:", false, false ); + AddTextField( 170, 65, 315, height - 80, 10 ); + } + + public void AddInput( int bid, int idx, string name ) + { + int x = 15; + int y = 95 + (idx * 50); + + AddButtonLabeled( x, y, bid, name ); + AddTextField( x + 35, y + 20, 100, 20, idx ); + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( from.AccessLevel < AccessLevel.Administrator ) + return; + + TextRelay d = info.GetTextEntry( 0 ); + TextRelay h = info.GetTextEntry( 1 ); + TextRelay m = info.GetTextEntry( 2 ); + TextRelay s = info.GetTextEntry( 3 ); + + TextRelay c = info.GetTextEntry( 10 ); + + TimeSpan duration; + bool shouldSet; + + string fromString = from.ToString(); + + switch ( info.ButtonID ) + { + case 0: + { + for ( int i = 0; i < m_List.Count; ++i ) + { + Account a = (Account)m_List[i]; + + a.SetUnspecifiedBan( from ); + } + + from.SendMessage( "Duration unspecified." ); + return; + } + case 1: // infinite + { + duration = TimeSpan.MaxValue; + shouldSet = true; + break; + } + case 2: // From D:H:M:S + { + if ( d != null && h != null && m != null && s != null ) + { + try + { + duration = new TimeSpan( Utility.ToInt32( d.Text ), Utility.ToInt32( h.Text ), Utility.ToInt32( m.Text ), Utility.ToInt32( s.Text ) ); + shouldSet = true; + + break; + } + catch + { + } + } + + duration = TimeSpan.Zero; + shouldSet = false; + + break; + } + case 3: // From D + { + if ( d != null ) + { + try + { + duration = TimeSpan.FromDays( Utility.ToDouble( d.Text ) ); + shouldSet = true; + + break; + } + catch + { + } + } + + duration = TimeSpan.Zero; + shouldSet = false; + + break; + } + case 4: // From H + { + if ( h != null ) + { + try + { + duration = TimeSpan.FromHours( Utility.ToDouble( h.Text ) ); + shouldSet = true; + + break; + } + catch + { + } + } + + duration = TimeSpan.Zero; + shouldSet = false; + + break; + } + case 5: // From M + { + if ( m != null ) + { + try + { + duration = TimeSpan.FromMinutes( Utility.ToDouble( m.Text ) ); + shouldSet = true; + + break; + } + catch + { + } + } + + duration = TimeSpan.Zero; + shouldSet = false; + + break; + } + case 6: // From S + { + if ( s != null ) + { + try + { + duration = TimeSpan.FromSeconds( Utility.ToDouble( s.Text ) ); + shouldSet = true; + + break; + } + catch + { + } + } + + duration = TimeSpan.Zero; + shouldSet = false; + + break; + } + default: return; + } + + if ( shouldSet ) { + string comment = null; + + if ( c != null ) { + comment = c.Text.Trim(); + + if ( comment.Length == 0 ) + comment = null; + } + + for ( int i = 0; i < m_List.Count; ++i ) + { + Account a = (Account)m_List[i]; + + a.SetBanTags( from, DateTime.Now, duration ); + + if ( comment != null ) + a.Comments.Add( new AccountComment( from.RawName, String.Format( "Duration: {0}, Comment: {1}", (( duration == TimeSpan.MaxValue )? "Infinite" : duration.ToString()), comment ) ) ); + } + + if ( duration == TimeSpan.MaxValue ) + from.SendMessage( "Ban Duration: Infinite" ); + else + from.SendMessage( "Ban Duration: {0}", duration ); + } + else + { + from.SendMessage( "Time values were improperly formatted." ); + from.SendGump( new BanDurationGump( m_List ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/BaseConfirmGump.cs b/Scripts/Gumps/BaseConfirmGump.cs new file mode 100644 index 0000000..868dfa1 --- /dev/null +++ b/Scripts/Gumps/BaseConfirmGump.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class BaseConfirmGump : Gump + { + public virtual int TitleNumber{ get{ return 1075083; } } //
Warning!
+ public virtual int LabelNumber{ get{ return 1074975; } } // Are you sure you wish to select this? + + private enum Buttons + { + Close, + Break, + Confirm + } + + public BaseConfirmGump() : base( 120, 50 ) + { + Closable = false; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddImageTiled( 0, 0, 348, 262, 0xA8E ); + AddAlphaRegion( 0, 0, 348, 262 ); + AddImage( 0, 15, 0x27A8 ); + AddImageTiled( 0, 30, 17, 200, 0x27A7 ); + AddImage( 0, 230, 0x27AA ); + AddImage( 15, 230, 0x280C ); + AddImageTiled( 30, 0, 300, 17, 0x280A ); + AddImage( 315, 0, 0x280E ); + AddImage( 15, 244, 0x280C ); + AddImageTiled( 30, 244, 300, 17, 0x280A ); + AddImage( 315, 244, 0x280E ); + AddImage( 330, 15, 0x27A8 ); + AddImageTiled( 330, 30, 17, 200, 0x27A7 ); + AddImage( 330, 230, 0x27AA ); + AddImage( 333, 2, 0x2716 ); + AddImage( 315, 248, 0x2716 ); + AddImage( 2, 248, 0x2716 ); + AddImage( 2, 2, 0x2716 ); + AddHtmlLocalized( 25, 25, 200, 20, TitleNumber, 0x7D00, false, false ); + AddImage( 25, 40, 0xBBF ); + AddHtmlLocalized( 25, 55, 300, 120, LabelNumber, 0xFFFFFF, false, false ); + + AddRadio( 25, 175, 0x25F8, 0x25FB, true, (int) Buttons.Break ); + AddRadio( 25, 210, 0x25F8, 0x25FB, false, (int) Buttons.Close ); + + AddHtmlLocalized( 60, 180, 280, 20, 1074976, 0xFFFFFF, false, false ); + AddHtmlLocalized( 60, 215, 280, 20, 1074977, 0xFFFFFF, false, false ); + + AddButton( 265, 220, 0xF7, 0xF8, (int) Buttons.Confirm, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( Server.Network.NetState state, RelayInfo info ) + { + if ( info.ButtonID == (int) Buttons.Confirm ) + { + if ( info.IsSwitched( (int) Buttons.Break ) ) + Confirm( state.Mobile ); + else + Refuse( state.Mobile ); + } + } + + public virtual void Confirm( Mobile from ) + { + } + + public virtual void Refuse( Mobile from ) + { + } + } +} diff --git a/Scripts/Gumps/BaseGridGump.cs b/Scripts/Gumps/BaseGridGump.cs new file mode 100644 index 0000000..aa61d73 --- /dev/null +++ b/Scripts/Gumps/BaseGridGump.cs @@ -0,0 +1,197 @@ +using System; + +namespace Server.Gumps +{ + public abstract class BaseGridGump : Gump + { + private int m_CurrentX, m_CurrentY; + private int m_CurrentPage; + + protected GumpBackground m_Background; + protected GumpImageTiled m_Offset; + + public int CurrentPage + { + get{ return m_CurrentPage; } + } + + public int CurrentX + { + get{ return m_CurrentX; } + } + + public int CurrentY + { + get{ return m_CurrentY; } + } + + public BaseGridGump( int x, int y ) : base( x, y ) + { + } + + public virtual int BorderSize{ get{ return 10; } } + public virtual int OffsetSize{ get{ return 1; } } + + public virtual int EntryHeight{ get{ return 20; } } + + public virtual int OffsetGumpID{ get{ return 0x0A40; } } + public virtual int HeaderGumpID{ get{ return 0x0E14; } } + public virtual int EntryGumpID{ get{ return 0x0BBC; } } + public virtual int BackGumpID{ get{ return 0x13BE; } } + + public virtual int TextHue{ get{ return 0; } } + public virtual int TextOffsetX{ get{ return 2; } } + + public const int ArrowLeftID1 = 0x15E3; + public const int ArrowLeftID2 = 0x15E7; + public const int ArrowLeftWidth = 16; + public const int ArrowLeftHeight = 16; + + public const int ArrowRightID1 = 0x15E1; + public const int ArrowRightID2 = 0x15E5; + public const int ArrowRightWidth = 16; + public const int ArrowRightHeight = 16; + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public int GetButtonID( int typeCount, int type, int index ) + { + return 1 + (index * typeCount) + type; + } + + public bool SplitButtonID( int buttonID, int typeCount, out int type, out int index ) + { + if ( buttonID < 1 ) + { + type = 0; + index = 0; + return false; + } + + buttonID -= 1; + + type = buttonID % typeCount; + index = buttonID / typeCount; + + return true; + } + + public void FinishPage() + { + if ( m_Background != null ) + m_Background.Height = m_CurrentY + EntryHeight + OffsetSize + BorderSize; + + if ( m_Offset != null ) + m_Offset.Height = m_CurrentY + EntryHeight + OffsetSize - BorderSize; + } + + public void AddNewPage() + { + FinishPage(); + + m_CurrentX = BorderSize + OffsetSize; + m_CurrentY = BorderSize + OffsetSize; + + AddPage( ++m_CurrentPage ); + + m_Background = new GumpBackground( 0, 0, 100, 100, BackGumpID ); + Add( m_Background ); + + m_Offset = new GumpImageTiled( BorderSize, BorderSize, 100, 100, OffsetGumpID ); + Add( m_Offset ); + } + + public void AddNewLine() + { + m_CurrentY += EntryHeight + OffsetSize; + m_CurrentX = BorderSize + OffsetSize; + } + + public void IncreaseX( int width ) + { + m_CurrentX += width + OffsetSize; + + width = m_CurrentX + BorderSize; + + if ( m_Background != null && width > m_Background.Width ) + m_Background.Width = width; + + width = m_CurrentX - BorderSize; + + if ( m_Offset != null && width > m_Offset.Width ) + m_Offset.Width = width; + } + + public void AddEntryLabel( int width, string text ) + { + AddImageTiled( m_CurrentX, m_CurrentY, width, EntryHeight, EntryGumpID ); + AddLabelCropped( m_CurrentX + TextOffsetX, m_CurrentY, width - TextOffsetX, EntryHeight, TextHue, text ); + + IncreaseX( width ); + } + + public void AddEntryHtml( int width, string text ) + { + AddImageTiled( m_CurrentX, m_CurrentY, width, EntryHeight, EntryGumpID ); + AddHtml( m_CurrentX + TextOffsetX, m_CurrentY, width - TextOffsetX, EntryHeight, text, false, false ); + + IncreaseX( width ); + } + + public void AddEntryHeader( int width ) + { + AddEntryHeader( width, 1 ); + } + + public void AddEntryHeader( int width, int spannedEntries ) + { + AddImageTiled( m_CurrentX, m_CurrentY, width, (EntryHeight * spannedEntries) + (OffsetSize * (spannedEntries - 1)), HeaderGumpID ); + IncreaseX( width ); + } + + public void AddBlankLine() + { + if ( m_Offset != null ) + AddImageTiled( m_Offset.X, m_CurrentY, m_Offset.Width, EntryHeight, BackGumpID + 4 ); + + AddNewLine(); + } + + public void AddEntryButton( int width, int normalID, int pressedID, int buttonID, int buttonWidth, int buttonHeight ) + { + AddEntryButton( width, normalID, pressedID, buttonID, buttonWidth, buttonHeight, 1 ); + } + + public void AddEntryButton( int width, int normalID, int pressedID, int buttonID, int buttonWidth, int buttonHeight, int spannedEntries ) + { + AddImageTiled( m_CurrentX, m_CurrentY, width, (EntryHeight * spannedEntries) + (OffsetSize * (spannedEntries - 1)), HeaderGumpID ); + AddButton( m_CurrentX + ((width - buttonWidth) / 2), m_CurrentY + (((EntryHeight * spannedEntries) + (OffsetSize * (spannedEntries - 1)) - buttonHeight) / 2), normalID, pressedID, buttonID, GumpButtonType.Reply, 0 ); + + IncreaseX( width ); + } + + public void AddEntryPageButton( int width, int normalID, int pressedID, int page, int buttonWidth, int buttonHeight ) + { + AddImageTiled( m_CurrentX, m_CurrentY, width, EntryHeight, HeaderGumpID ); + AddButton( m_CurrentX + ((width - buttonWidth) / 2), m_CurrentY + ((EntryHeight - buttonHeight) / 2), normalID, pressedID, 0, GumpButtonType.Page, page ); + + IncreaseX( width ); + } + + public void AddEntryText( int width, int entryID, string initialText ) + { + AddImageTiled( m_CurrentX, m_CurrentY, width, EntryHeight, EntryGumpID ); + AddTextEntry( m_CurrentX + TextOffsetX, m_CurrentY, width - TextOffsetX, EntryHeight, TextHue, entryID, initialText ); + + IncreaseX( width ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/BaseImageTileButtonsGump.cs b/Scripts/Gumps/BaseImageTileButtonsGump.cs new file mode 100644 index 0000000..050348a --- /dev/null +++ b/Scripts/Gumps/BaseImageTileButtonsGump.cs @@ -0,0 +1,131 @@ +using System; +using Server; +using Server.Network; +using System.Collections; + +namespace Server.Gumps +{ + public class ImageTileButtonInfo + { + private int m_ItemID; + private int m_Hue; + private int m_LocalizedTooltip; + + private TextDefinition m_Label; + + public virtual int ItemID + { + get{ return m_ItemID; } + set{ m_ItemID = value; } + } + public virtual int Hue + { + get{ return m_Hue; } + set{ m_Hue = value; } + } + public virtual int LocalizedTooltip + { + get{ return m_LocalizedTooltip; } + set{ m_LocalizedTooltip = value; } + } + + public virtual TextDefinition Label + { + get{ return m_Label; } + set{ m_Label = value; } + } + + public ImageTileButtonInfo( int itemID, int hue, TextDefinition label, int localizedTooltip ) + { + m_Hue = hue; + m_ItemID = itemID; + m_Label = label; + m_LocalizedTooltip = localizedTooltip; + } + public ImageTileButtonInfo( int itemID, int hue, TextDefinition label ) : this( itemID, hue, label, -1 ) + { + } + } + + public class BaseImageTileButtonsGump : Gump + { + private ImageTileButtonInfo[] m_Buttons; + + protected ImageTileButtonInfo[] Buttons { get { return m_Buttons; } } + + protected virtual int XItems{ get{ return 2; } } + protected virtual int YItems{ get { return 5; } } + + public BaseImageTileButtonsGump( TextDefinition header, ArrayList buttons ) : this( header, (ImageTileButtonInfo[])buttons.ToArray( typeof( ImageTileButtonInfo ) ) ) + { + } + public BaseImageTileButtonsGump( TextDefinition header, ImageTileButtonInfo[] buttons ) : base( 10, 10 ) //Coords are 0, o on OSI, intentional difference + { + m_Buttons = buttons; + AddPage( 0 ); + + int x = XItems * 250; + int y = YItems * 64; + + AddBackground( 0, 0, x+20, y+84, 0x13BE ); + AddImageTiled( 10, 10, x, 20, 0xA40 ); + AddImageTiled( 10, 40, x, y+4, 0xA40 ); + AddImageTiled( 10, y+54, x, 20, 0xA40 ); + AddAlphaRegion( 10, 10, x, y+64 ); + + AddButton( 10, y+54, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); //Cancel Button + AddHtmlLocalized( 45, y+56, x-50, 20, 1060051, 0x7FFF, false, false ); // CANCEL + TextDefinition.AddHtmlText( this, 14, 12, x, 20, header, false, false, 0x7FFF, 0xFFFFFF ); + + AddPage( 1 ); + + int itemsPerPage = XItems * YItems; + + for( int i = 0; i < buttons.Length; i++ ) + { + int position = i % itemsPerPage; + + int innerX = (position % XItems) * 250 + 14; + int innerY = (position / XItems) * 64 + 44; + + int pageNum = i / itemsPerPage + 1; + + if( position == 0 && i != 0 ) + { + AddButton( x-100, y+54, 0xFA5, 0xFA7, 0, GumpButtonType.Page, pageNum ); + AddHtmlLocalized( x-60, y+56, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( pageNum ); + + AddButton( x-200, y+54, 0xFAE, 0xFB0, 0, GumpButtonType.Page, pageNum - 1 ); + AddHtmlLocalized( x-160, y+56, 60, 20, 1011393, 0x7FFF, false, false ); // Back + + } + + ImageTileButtonInfo b = buttons[i]; + + AddImageTiledButton( innerX, innerY, 0x918, 0x919, 100 + i, GumpButtonType.Reply, 0, b.ItemID, b.Hue, 15, 10, b.LocalizedTooltip ); + TextDefinition.AddHtmlText( this, innerX + 84, innerY, 250, 60, b.Label, false, false, 0x7FFF, 0xFFFFFF ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int adjustedID = info.ButtonID - 100; + + if( adjustedID >= 0 && adjustedID < Buttons.Length ) + HandleButtonResponse( sender, adjustedID, Buttons[adjustedID] ); + else + HandleCancel( sender ); + + } + + public virtual void HandleButtonResponse( NetState sender, int adjustedButton, ImageTileButtonInfo buttonInfo ) + { + } + + public virtual void HandleCancel( NetState sender ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/CategorizedAddGump.cs b/Scripts/Gumps/CategorizedAddGump.cs new file mode 100644 index 0000000..48ce64d --- /dev/null +++ b/Scripts/Gumps/CategorizedAddGump.cs @@ -0,0 +1,386 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public abstract class CAGNode + { + public abstract string Caption{ get; } + public abstract void OnClick( Mobile from, int page ); + } + + public class CAGObject : CAGNode + { + private Type m_Type; + private int m_ItemID; + private int m_Hue; + private CAGCategory m_Parent; + + public Type Type{ get{ return m_Type; } } + public int ItemID{ get{ return m_ItemID; } } + public int Hue{ get{ return m_Hue; } } + public CAGCategory Parent{ get{ return m_Parent; } } + + public override string Caption{ get{ return ( m_Type == null ? "bad type" : m_Type.Name ); } } + + public override void OnClick( Mobile from, int page ) + { + if ( m_Type == null ) + { + from.SendMessage( "That is an invalid type name." ); + } + else + { + CommandSystem.Handle( from, String.Format( "{0}Add {1}", CommandSystem.Prefix, m_Type.Name ) ); + + from.SendGump( new CategorizedAddGump( from, m_Parent, page ) ); + } + } + + public CAGObject( CAGCategory parent, XmlTextReader xml ) + { + m_Parent = parent; + + if ( xml.MoveToAttribute( "type" ) ) + m_Type = ScriptCompiler.FindTypeByFullName( xml.Value, false ); + + if ( xml.MoveToAttribute( "gfx" ) ) + m_ItemID = XmlConvert.ToInt32( xml.Value ); + + if ( xml.MoveToAttribute( "hue" ) ) + m_Hue = XmlConvert.ToInt32( xml.Value ); + } + } + + public class CAGCategory : CAGNode + { + private string m_Title; + private CAGNode[] m_Nodes; + private CAGCategory m_Parent; + + public string Title{ get{ return m_Title; } } + public CAGNode[] Nodes{ get{ return m_Nodes; } } + public CAGCategory Parent{ get{ return m_Parent; } } + + public override string Caption{ get{ return m_Title; } } + + public override void OnClick( Mobile from, int page ) + { + from.SendGump( new CategorizedAddGump( from, this, 0 ) ); + } + + private CAGCategory() + { + m_Title = "no data"; + m_Nodes = new CAGNode[0]; + } + + public CAGCategory( CAGCategory parent, XmlTextReader xml ) + { + m_Parent = parent; + + if ( xml.MoveToAttribute( "title" ) ) + m_Title = xml.Value; + else + m_Title = "empty"; + + if ( m_Title == "Docked" ) + m_Title = "Docked 2"; + + if ( xml.IsEmptyElement ) + { + m_Nodes = new CAGNode[0]; + } + else + { + ArrayList nodes = new ArrayList(); + + while ( xml.Read() && xml.NodeType != XmlNodeType.EndElement ) + { + if ( xml.NodeType == XmlNodeType.Element && xml.Name == "object" ) + nodes.Add( new CAGObject( this, xml ) ); + else if ( xml.NodeType == XmlNodeType.Element && xml.Name == "category" ) + { + if( !xml.IsEmptyElement ) + nodes.Add( new CAGCategory( this, xml ) ); + } + else + xml.Skip(); + } + + m_Nodes = (CAGNode[])nodes.ToArray( typeof( CAGNode ) ); + } + } + + private static CAGCategory m_Root; + + public static CAGCategory Root + { + get + { + if ( m_Root == null ) + m_Root = Load( "Data/objects.xml" ); + + return m_Root; + } + } + + public static CAGCategory Load( string path ) + { + if ( File.Exists( path ) ) + { + XmlTextReader xml = new XmlTextReader( path ); + + xml.WhitespaceHandling = WhitespaceHandling.None; + + while ( xml.Read() ) + { + if ( xml.Name == "category" && xml.NodeType == XmlNodeType.Element ) + { + CAGCategory cat = new CAGCategory( null, xml ); + + xml.Close(); + + return cat; + } + } + } + + return new CAGCategory(); + } + } + + public class CategorizedAddGump : Gump + { + public static bool OldStyle = PropsConfig.OldStyle; + + public static readonly int EntryHeight = 24;//PropsConfig.EntryHeight; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + public static readonly int BorderSize = PropsConfig.BorderSize; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY + (((EntryHeight - 20) / 2) / 2); + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY + (((EntryHeight - 20) / 2) / 2); + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY + (((EntryHeight - 20) / 2) / 2); + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + private static bool PrevLabel = false, NextLabel = false; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int EntryWidth = 180; + private static readonly int EntryCount = 15; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + private Mobile m_Owner; + private CAGCategory m_Category; + private int m_Page; + + public CategorizedAddGump( Mobile owner ) : this( owner, CAGCategory.Root, 0 ) + { + } + + public CategorizedAddGump( Mobile owner, CAGCategory category, int page ) : base( GumpOffsetX, GumpOffsetY ) + { + owner.CloseGump( typeof( WhoGump ) ); + + m_Owner = owner; + m_Category = category; + + Initialize( page ); + } + + public void Initialize( int page ) + { + m_Page = page; + + CAGNode[] nodes = m_Category.Nodes; + + int count = nodes.Length - (page * EntryCount); + + if ( count < 0 ) + count = 0; + else if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1)); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( m_Category.Parent != null ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + int emptyWidth = TotalWidth - (PrevWidth * 2) - NextWidth - (OffsetSize * 5) - (OldStyle ? SetWidth + OffsetSize : 0); + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID ); + + AddHtml( x + TextOffsetX, y + ((EntryHeight - 20) / 2), emptyWidth - TextOffsetX, EntryHeight, String.Format( "
{0}
", m_Category.Caption ), false, false ); + + x += emptyWidth + OffsetSize; + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 0 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 2, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( (page + 1) * EntryCount < nodes.Length ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + for ( int i = 0, index = page * EntryCount; i < EntryCount && index < nodes.Length; ++i, ++index ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + CAGNode node = nodes[index]; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y + ((EntryHeight - 20) / 2), EntryWidth - TextOffsetX, EntryHeight, TextHue, node.Caption ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 4, GumpButtonType.Reply, 0 ); + + if ( node is CAGObject ) + { + CAGObject obj = (CAGObject)node; + int itemID = obj.ItemID; + + Rectangle2D bounds = ItemBounds.Table[itemID]; + + if ( itemID != 1 && bounds.Height < (EntryHeight * 2) ) + { + if ( bounds.Height < EntryHeight ) + AddItem( x - OffsetSize - 22 - ((i % 2) * 44) - (bounds.Width / 2) - bounds.X, y + (EntryHeight / 2) - (bounds.Height / 2) - bounds.Y, itemID ); + else + AddItem( x - OffsetSize - 22 - ((i % 2) * 44) - (bounds.Width / 2) - bounds.X, y + EntryHeight - 1 - bounds.Height - bounds.Y, itemID ); + } + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = m_Owner; + + switch ( info.ButtonID ) + { + case 0: // Closed + { + return; + } + case 1: // Up + { + if ( m_Category.Parent != null ) + { + int index = Array.IndexOf( m_Category.Parent.Nodes, m_Category ) / EntryCount; + + if ( index < 0 ) + index = 0; + + from.SendGump( new CategorizedAddGump( from, m_Category.Parent, index ) ); + } + + break; + } + case 2: // Previous + { + if ( m_Page > 0 ) + from.SendGump( new CategorizedAddGump( from, m_Category, m_Page - 1 ) ); + + break; + } + case 3: // Next + { + if ( (m_Page + 1) * EntryCount < m_Category.Nodes.Length ) + from.SendGump( new CategorizedAddGump( from, m_Category, m_Page + 1 ) ); + + break; + } + default: + { + int index = (m_Page * EntryCount) + (info.ButtonID - 4); + + if ( index >= 0 && index < m_Category.Nodes.Length ) + m_Category.Nodes[index].OnClick( from, m_Page ); + + break; + } + } + } + } +} diff --git a/Scripts/Gumps/ClientGump.cs b/Scripts/Gumps/ClientGump.cs new file mode 100644 index 0000000..a5ed511 --- /dev/null +++ b/Scripts/Gumps/ClientGump.cs @@ -0,0 +1,301 @@ +using System; +using System.Net; +using Server; +using Server.Accounting; +using Server.Mobiles; +using Server.Network; +using Server.Targets; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Gumps +{ + public class ClientGump : Gump + { + private NetState m_State; + + private void Resend(Mobile to, RelayInfo info) + { + TextRelay te = info.GetTextEntry(0); + + to.SendGump(new ClientGump(to, m_State, te == null ? "" : te.Text)); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_State == null) + return; + + Mobile focus = m_State.Mobile; + Mobile from = state.Mobile; + + if (focus == null) + { + from.SendMessage("That character is no longer online."); + return; + } + else if (focus.Deleted) + { + from.SendMessage("That character no longer exists."); + return; + } + else if (from != focus && focus.Hidden && from.AccessLevel < focus.AccessLevel && (!(focus is PlayerMobile) || !((PlayerMobile)focus).VisibilityList.Contains(from))) + { + from.SendMessage("That character is no longer visible."); + return; + } + + switch (info.ButtonID) + { + case 1: // Tell + { + TextRelay text = info.GetTextEntry(0); + + if (text != null) + { + focus.SendMessage(0x482, "{0} tells you:", from.Name); + focus.SendMessage(0x482, text.Text); + + CommandLogging.WriteLine(from, "{0} {1} telling {2} \"{3}\" ", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus), text.Text); + } + + from.SendGump(new ClientGump(from, m_State)); + + break; + } + case 4: // Props + { + Resend(from, info); + + if (!BaseCommand.IsAccessible(from, focus)) + from.SendMessage("That is not accessible."); + else + { + from.SendGump(new PropertiesGump(from, focus)); + CommandLogging.WriteLine(from, "{0} {1} opening properties gump of {2} ", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus)); + } + + break; + } + case 5: // Go to + { + if (focus.Map == null || focus.Map == Map.Internal) + { + from.SendMessage("That character is not in the world."); + } + else + { + from.MoveToWorld(focus.Location, focus.Map); + Resend(from, info); + + CommandLogging.WriteLine(from, "{0} {1} going to {2}, Location {3}, Map {4}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus), focus.Location, focus.Map); + } + + break; + } + case 6: // Get + { + if (from.Map == null || from.Map == Map.Internal) + { + from.SendMessage("You cannot bring that person here."); + } + else + { + focus.MoveToWorld(from.Location, from.Map); + Resend(from, info); + + CommandLogging.WriteLine(from, "{0} {1} bringing {2} to Location {3}, Map {4}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus), from.Location, from.Map); + } + + break; + } + case 7: // Move + { + from.Target = new MoveTarget(focus); + Resend(from, info); + + break; + } + case 8: // Kick + { + if (from.AccessLevel >= AccessLevel.GameMaster && from.AccessLevel > focus.AccessLevel) + { + focus.Say("I've been kicked!"); + + m_State.Dispose(); + + CommandLogging.WriteLine(from, "{0} {1} kicking {2} ", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus)); + } + + break; + } + case 9: // Kill + { + if (from.AccessLevel >= AccessLevel.GameMaster && from.AccessLevel > focus.AccessLevel) + { + focus.Kill(); + CommandLogging.WriteLine(from, "{0} {1} killing {2} ", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus)); + } + + Resend(from, info); + + break; + } + case 10: //Res + { + if (from.AccessLevel >= AccessLevel.GameMaster && from.AccessLevel > focus.AccessLevel) + { + focus.PlaySound(0x214); + focus.FixedEffect(0x376A, 10, 16); + + focus.Resurrect(); + + CommandLogging.WriteLine(from, "{0} {1} resurrecting {2} ", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus)); + } + + Resend(from, info); + + break; + } + case 11: // Skills + { + Resend(from, info); + + if (from.AccessLevel > focus.AccessLevel) + { + from.SendGump(new SkillsGump(from, (Mobile)focus)); + CommandLogging.WriteLine(from, "{0} {1} Opening Skills gump of {2} ", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(focus)); + } + + break; + } + } + } + + public ClientGump(Mobile from, NetState state) + : this(from, state, "") + { + } + + private const int LabelColor32 = 0xFFFFFF; + + public string Center(string text) + { + return String.Format("
{0}
", text); + } + + public string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + + public ClientGump(Mobile from, NetState state, string initialText) + : base(30, 20) + { + if (state == null) + return; + + m_State = state; + + AddPage(0); + + AddBackground(0, 0, 400, 274, 5054); + + AddImageTiled(10, 10, 380, 19, 0xA40); + AddAlphaRegion(10, 10, 380, 19); + + AddImageTiled(10, 32, 380, 232, 0xA40); + AddAlphaRegion(10, 32, 380, 232); + + AddHtml(10, 10, 380, 20, Color(Center("User Information"), LabelColor32), false, false); + + int line = 0; + + AddHtml(14, 36 + (line * 20), 200, 20, Color("Address:", LabelColor32), false, false); + AddHtml(70, 36 + (line++ * 20), 200, 20, Color(state.ToString(), LabelColor32), false, false); + + AddHtml(14, 36 + (line * 20), 200, 20, Color("Client:", LabelColor32), false, false); + AddHtml(70, 36 + (line++ * 20), 200, 20, Color(state.Version == null ? "(null)" : state.Version.ToString(), LabelColor32), false, false); + + AddHtml(14, 36 + (line * 20), 200, 20, Color("Version:", LabelColor32), false, false); + + ExpansionInfo info = state.ExpansionInfo; + string expansionName = info.Name; + + AddHtml(70, 36 + (line++ * 20), 200, 20, Color(expansionName, LabelColor32), false, false); + + Account a = state.Account as Account; + Mobile m = state.Mobile; + + if (from.AccessLevel >= AccessLevel.GameMaster && a != null) + { + AddHtml(14, 36 + (line * 20), 200, 20, Color("Account:", LabelColor32), false, false); + AddHtml(70, 36 + (line++ * 20), 200, 20, Color(a.Username, LabelColor32), false, false); + } + + if (m != null) + { + AddHtml(14, 36 + (line * 20), 200, 20, Color("Mobile:", LabelColor32), false, false); + AddHtml(70, 36 + (line++ * 20), 200, 20, Color(String.Format("{0} (0x{1:X})", m.Name, m.Serial.Value), LabelColor32), false, false); + + AddHtml(14, 36 + (line * 20), 200, 20, Color("Location:", LabelColor32), false, false); + AddHtml(70, 36 + (line++ * 20), 200, 20, Color(String.Format("{0} [{1}]", m.Location, m.Map), LabelColor32), false, false); + + AddButton(13, 157, 0xFAB, 0xFAD, 1, GumpButtonType.Reply, 0); + AddHtml(48, 158, 200, 20, Color("Send Message", LabelColor32), false, false); + + AddImageTiled(12, 182, 376, 80, 0xA40); + AddImageTiled(13, 183, 374, 78, 0xBBC); + AddTextEntry(15, 183, 372, 78, 0x480, 0, ""); + + AddImageTiled(245, 35, 142, 144, 5058); + + AddImageTiled(246, 36, 140, 142, 0xA40); + AddAlphaRegion(246, 36, 140, 142); + + line = 0; + + if (BaseCommand.IsAccessible(from, m)) + { + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 4, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Properties", LabelColor32), false, false); + } + + if (from != m) + { + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 5, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Go to them", LabelColor32), false, false); + + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 6, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Bring them here", LabelColor32), false, false); + } + + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 7, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Move to target", LabelColor32), false, false); + + if (from.AccessLevel >= AccessLevel.GameMaster && from.AccessLevel > m.AccessLevel) + { + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 8, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Disconnect", LabelColor32), false, false); + + if (m.Alive) + { + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 9, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Kill", LabelColor32), false, false); + } + else + { + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 10, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Resurrect", LabelColor32), false, false); + } + } + + if (from.AccessLevel >= AccessLevel.Counselor && from.AccessLevel > m.AccessLevel) + { + AddButton(246, 36 + (line * 20), 0xFA5, 0xFA7, 11, GumpButtonType.Reply, 0); + AddHtml(280, 38 + (line++ * 20), 100, 20, Color("Skills browser", LabelColor32), false, false); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/ConfirmBreakCrystalGump.cs b/Scripts/Gumps/ConfirmBreakCrystalGump.cs new file mode 100644 index 0000000..70eff8d --- /dev/null +++ b/Scripts/Gumps/ConfirmBreakCrystalGump.cs @@ -0,0 +1,55 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class ConfirmBreakCrystalGump : BaseConfirmGump + { + public override int LabelNumber{ get{ return 1075084; } } // This statuette will be destroyed when its trapped creature is summoned. The creature will be bonded to you but will disappear if released.

Do you wish to proceed? + + private BaseImprisonedMobile m_Item; + + public ConfirmBreakCrystalGump( BaseImprisonedMobile item ) : base() + { + m_Item = item; + } + + public override void Confirm( Mobile from ) + { + if ( m_Item == null || m_Item.Deleted ) + return; + + BaseCreature summon = m_Item.Summon; + + if ( summon != null ) + { + if ( !summon.SetControlMaster( from ) ) + { + summon.Delete(); + } + else + { + from.SendLocalizedMessage( 1049666 ); // Your pet has bonded with you! + + summon.MoveToWorld( from.Location, from.Map ); + summon.IsBonded = true; + + summon.Skills.Wrestling.Base = 100; + summon.Skills.Tactics.Base = 100; + summon.Skills.MagicResist.Base = 100; + summon.Skills.Anatomy.Base = 100; + + Effects.PlaySound( summon.Location, summon.Map, summon.BaseSoundID ); + Effects.SendLocationParticles( EffectItem.Create( summon.Location, summon.Map, EffectItem.DefaultDuration ), 0x3728, 1, 10, 0x26B6 ); + + m_Item.Release( from, summon ); + m_Item.Delete(); + } + } + } + } + + +} diff --git a/Scripts/Gumps/ConfirmHeritageGump.cs b/Scripts/Gumps/ConfirmHeritageGump.cs new file mode 100644 index 0000000..c89cdf9 --- /dev/null +++ b/Scripts/Gumps/ConfirmHeritageGump.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Gumps +{ + public class ConfirmHeritageGump : Gump + { + private HeritageToken m_Token; + private Type[] m_Selected; + + private enum Buttons + { + Cancel, + Okay + } + + public ConfirmHeritageGump( HeritageToken token, Type[] selected, int cliloc ) : base( 60, 36 ) + { + m_Token = token; + m_Selected = selected; + + AddPage( 0 ); + + AddBackground( 0, 0, 291, 99, 0x13BE ); + AddImageTiled( 5, 6, 280, 20, 0xA40 ); + AddHtmlLocalized( 9, 8, 280, 20, 1070972, 0x7FFF, false, false ); // Click "OKAY" to redeem the following promotional item: + AddImageTiled( 5, 31, 280, 40, 0xA40 ); + AddHtmlLocalized( 9, 35, 272, 40, cliloc, 0x7FFF, false, false ); + AddButton( 180, 73, 0xFB7, 0xFB8, (int) Buttons.Okay, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 215, 75, 100, 20, 1011036, 0x7FFF, false, false ); // OKAY + AddButton( 5, 73, 0xFB1, 0xFB2, (int) Buttons.Cancel, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 75, 100, 20, 1060051, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Token == null || m_Token.Deleted ) + return; + + switch ( info.ButtonID ) + { + case (int) Buttons.Okay: + + Item item = null; + + foreach ( Type type in m_Selected ) + { + try + { + item = Activator.CreateInstance( type ) as Item; + } + catch ( Exception ex ) + { + Console.WriteLine( ex.Message ); + Console.WriteLine( ex.StackTrace ); + } + + if ( item != null ) + { + m_Token.Delete(); + sender.Mobile.AddToBackpack( item ); + } + } + + break; + case (int) Buttons.Cancel: + sender.Mobile.SendGump( new HeritageTokenGump( m_Token ) ); + break; + } + } + } +} diff --git a/Scripts/Gumps/ConfirmHouseResize.cs b/Scripts/Gumps/ConfirmHouseResize.cs new file mode 100644 index 0000000..b80006f --- /dev/null +++ b/Scripts/Gumps/ConfirmHouseResize.cs @@ -0,0 +1,153 @@ +using System; +using Server; +using Server.Items; +using Server.Multis; +using Server.Multis.Deeds; +using Server.Network; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class ConfirmHouseResize : Gump + { + private Mobile m_Mobile; + private BaseHouse m_House; + + public ConfirmHouseResize( Mobile mobile, BaseHouse house ) : base( 110, 100 ) + { + m_Mobile = mobile; + m_House = house; + + mobile.CloseGump( typeof( ConfirmHouseResize ) ); + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 280, 0x13BE ); + AddImageTiled( 10, 10, 400, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 400, 20 ); + AddHtmlLocalized( 10, 10, 400, 20, 1060635, 0x7800, false, false ); //
WARNING
+ AddImageTiled( 10, 40, 400, 200, 0xA40 ); + AddAlphaRegion( 10, 40, 400, 200 ); + + /* You are attempting to resize your house. You will be refunded the house's + value directly to your bank box. All items in the house will *remain behind* + and can be *freely picked up by anyone*. Once the house is demolished, however, + only this account will be able to place on the land for one hour. This *will* + circumvent the normal 7-day waiting period (if it applies to you). This action + will not un-condemn any other houses on your account. If you have other, + grandfathered houses, this action *WILL* condemn them. Are you sure you wish + to continue?*/ + AddHtmlLocalized( 10, 40, 400, 200, 1080196, 0x7F00, false, true ); + + AddImageTiled( 10, 250, 400, 20, 0xA40 ); + AddAlphaRegion( 10, 250, 400, 20 ); + AddButton( 10, 250, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddButton( 210, 250, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 250, 170, 20, 1011036, 0x7FFF, false, false ); // OKAY + AddHtmlLocalized( 240, 250, 170, 20, 1011012, 0x7FFF, false, false ); // CANCEL + + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 1 && !m_House.Deleted ) + { + if ( m_House.IsOwner( m_Mobile ) ) + { + if ( m_House.MovingCrate != null || m_House.InternalizedVendors.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 1080455 ); // You can not resize your house at this time. Please remove all items fom the moving crate and try again. + return; + } + else if( !Guilds.Guild.NewGuildSystem && m_House.FindGuildstone() != null ) + { + m_Mobile.SendLocalizedMessage( 501389 ); // You cannot redeed a house with a guildstone inside. + return; + } + /*else if ( m_House.PlayerVendors.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 503236 ); // You need to collect your vendor's belongings before moving. + return; + }*/ + else if ( m_House.HasRentedVendors && m_House.VendorInventories.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 1062679 ); // You cannot do that that while you still have contract vendors or unclaimed contract vendor inventory in your house. + return; + } + else if ( m_House.HasRentedVendors ) + { + m_Mobile.SendLocalizedMessage( 1062680 ); // You cannot do that that while you still have contract vendors in your house. + return; + } + else if ( m_House.VendorInventories.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 1062681 ); // You cannot do that that while you still have unclaimed contract vendor inventory in your house. + return; + } + + if ( m_Mobile.AccessLevel >= AccessLevel.GameMaster ) + { + m_Mobile.SendMessage( "You do not get a refund for your house as you are not a player" ); + m_House.RemoveKeys(m_Mobile); + new TempNoHousingRegion(m_House, m_Mobile); + m_House.Delete(); + } + else + { + Item toGive = null; + + if ( m_House.IsAosRules ) + { + if ( m_House.Price > 0 ) + toGive = new BankCheck( m_House.Price ); + else + toGive = m_House.GetDeed(); + } + else + { + toGive = m_House.GetDeed(); + + if ( toGive == null && m_House.Price > 0 ) + toGive = new BankCheck( m_House.Price ); + } + + if ( toGive != null ) + { + BankBox box = m_Mobile.BankBox; + + if ( box.TryDropItem( m_Mobile, toGive, false ) ) + { + if ( toGive is BankCheck ) + m_Mobile.SendLocalizedMessage( 1060397, ( (BankCheck)toGive ).Worth.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + + m_House.RemoveKeys( m_Mobile ); + new TempNoHousingRegion( m_House, m_Mobile ); + m_House.Delete(); + } + else + { + toGive.Delete(); + m_Mobile.SendLocalizedMessage( 500390 ); // Your bank box is full. + } + } + else + { + m_Mobile.SendMessage( "Unable to refund house." ); + } + } + } + else + { + m_Mobile.SendLocalizedMessage( 501320 ); // Only the house owner may do this. + } + } + else if ( info.ButtonID == 0 ) + { + m_Mobile.CloseGump( typeof( ConfirmHouseResize ) ); + m_Mobile.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, m_Mobile, m_House ) ); + } + } + } +} diff --git a/Scripts/Gumps/ConfirmReleaseGump.cs b/Scripts/Gumps/ConfirmReleaseGump.cs new file mode 100644 index 0000000..a041dd8 --- /dev/null +++ b/Scripts/Gumps/ConfirmReleaseGump.cs @@ -0,0 +1,54 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class ConfirmReleaseGump : Gump + { + private Mobile m_From; + private BaseCreature m_Pet; + + public ConfirmReleaseGump( Mobile from, BaseCreature pet ) : base( 50, 50 ) + { + m_From = from; + m_Pet = pet; + + m_From.CloseGump( typeof( ConfirmReleaseGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 270, 120, 5054 ); + AddBackground( 10, 10, 250, 100, 3000 ); + + AddHtmlLocalized( 20, 15, 230, 60, 1046257, true, true ); // Are you sure you want to release your pet? + + AddButton( 20, 80, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 80, 75, 20, 1011011, false, false ); // CONTINUE + + AddButton( 135, 80, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 170, 80, 75, 20, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 2 ) + { + if ( !m_Pet.Deleted && m_Pet.Controlled && m_From == m_Pet.ControlMaster && m_From.CheckAlive() /*&& m_Pet.CheckControlChance( m_From )*/ ) + { + if ( m_Pet.Map == m_From.Map && m_Pet.InRange( m_From, 14 ) ) + { + m_Pet.ControlTarget = null; +// >>> [1st change of 1] + if ( m_Pet is BaseHire ) + m_Pet.ControlOrder = OrderType.Dismiss; + else + m_Pet.ControlOrder = OrderType.Release; +// m_Pet.ControlOrder = OrderType.Release; +// end 1st + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/DawnsMusicBoxGump.cs b/Scripts/Gumps/DawnsMusicBoxGump.cs new file mode 100644 index 0000000..d84adcb --- /dev/null +++ b/Scripts/Gumps/DawnsMusicBoxGump.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Network; +using Server.Items; + +namespace Server.Gumps +{ + public class DawnsMusicBoxGump : Gump + { + private DawnsMusicBox m_Box; + + public DawnsMusicBoxGump( DawnsMusicBox box ) + : base( 60, 36 ) + { + m_Box = box; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1075130, 0x7FFF, false, false ); // Choose a track to play + + int page = 1; + int i, y = 49; + + AddPage( page ); + + for ( i = 0; i < m_Box.Tracks.Count; i++, y += 24 ) + { + DawnsMusicInfo info = DawnsMusicBox.GetInfo( m_Box.Tracks[ i ] ); + + if ( i > 0 && i % 10 == 0 ) + { + AddButton( 228, 294, 0xFA5, 0xFA6, 0, GumpButtonType.Page, page + 1 ); + + AddPage( page + 1 ); + y = 49; + + AddButton( 193, 294, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page ); + + page++; + } + + if (info == null) + continue; + + AddButton( 19, y, 0x845, 0x846, 100 + i, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, y - 2, 213, 20, info.Name, 0x7FFF, false, false ); + } + + if ( i % 10 == 0 ) + { + AddButton( 228, 294, 0xFA5, 0xFA6, 0, GumpButtonType.Page, page + 1 ); + + AddPage( page + 1 ); + y = 49; + + AddButton( 193, 294, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page ); + } + + AddButton( 19, y, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, y - 2, 213, 20, 1075207, 0x7FFF, false, false ); // Stop Song + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Box == null || m_Box.Deleted ) + return; + + Mobile m = sender.Mobile; + + if ( !m_Box.IsChildOf( m.Backpack ) && !m_Box.IsLockedDown ) + m.SendLocalizedMessage( 1061856 ); // You must have the item in your backpack or locked down in order to use it. + else if ( m_Box.IsLockedDown && !m_Box.HasAccces( m ) ) + m.SendLocalizedMessage( 502691 ); // You must be the owner to use this. + else if ( info.ButtonID == 1 ) + m_Box.EndMusic( m ); + else if ( info.ButtonID >= 100 && info.ButtonID - 100 < m_Box.Tracks.Count ) + m_Box.PlayMusic( m, m_Box.Tracks[ info.ButtonID - 100 ] ); + } + } +} diff --git a/Scripts/Gumps/Go/ChildNode.cs b/Scripts/Gumps/Go/ChildNode.cs new file mode 100644 index 0000000..bb0961b --- /dev/null +++ b/Scripts/Gumps/Go/ChildNode.cs @@ -0,0 +1,66 @@ +using System; +using System.Xml; +using Server; + +namespace Server.Gumps +{ + public class ChildNode + { + private ParentNode m_Parent; + + private string m_Name; + private Point3D m_Location; + + public ChildNode( XmlTextReader xml, ParentNode parent ) + { + m_Parent = parent; + + Parse( xml ); + } + + private void Parse( XmlTextReader xml ) + { + if ( xml.MoveToAttribute( "name" ) ) + m_Name = xml.Value; + else + m_Name = "empty"; + + int x = 0, y = 0, z = 0; + + if ( xml.MoveToAttribute( "x" ) ) + x = Utility.ToInt32( xml.Value ); + + if ( xml.MoveToAttribute( "y" ) ) + y = Utility.ToInt32( xml.Value ); + + if ( xml.MoveToAttribute( "z" ) ) + z = Utility.ToInt32( xml.Value ); + + m_Location = new Point3D( x, y, z ); + } + + public ParentNode Parent + { + get + { + return m_Parent; + } + } + + public string Name + { + get + { + return m_Name; + } + } + + public Point3D Location + { + get + { + return m_Location; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Go/GoGump.cs b/Scripts/Gumps/Go/GoGump.cs new file mode 100644 index 0000000..87e50af --- /dev/null +++ b/Scripts/Gumps/Go/GoGump.cs @@ -0,0 +1,253 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Gumps +{ + public class GoGump : Gump + { + public static readonly LocationTree Felucca = new LocationTree( "felucca.xml", Map.Felucca ); + public static readonly LocationTree Trammel = new LocationTree( "trammel.xml", Map.Trammel ); + public static readonly LocationTree Ilshenar = new LocationTree( "ilshenar.xml", Map.Ilshenar ); + public static readonly LocationTree Malas = new LocationTree( "malas.xml", Map.Malas ); + public static readonly LocationTree Tokuno = new LocationTree( "tokuno.xml", Map.Tokuno ); + public static readonly LocationTree TerMur = new LocationTree( "termur.xml", Map.TerMur ); + + public static bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static bool PrevLabel = false, NextLabel = false; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int EntryWidth = 180; + private static readonly int EntryCount = 15; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public static void DisplayTo( Mobile from ) + { + LocationTree tree; + + if ( from.Map == Map.Ilshenar ) + tree = Ilshenar; + else if ( from.Map == Map.Felucca ) + tree = Felucca; + else if ( from.Map == Map.Trammel ) + tree = Trammel; + else if ( from.Map == Map.Malas ) + tree = Malas; + else if ( from.Map == Map.Tokuno ) + tree = Tokuno; + else + tree = TerMur; + + ParentNode branch = null; + tree.LastBranch.TryGetValue( from, out branch ); + + if ( branch == null ) + branch = tree.Root; + + if ( branch != null ) + from.SendGump( new GoGump( 0, from, tree, branch ) ); + } + + private LocationTree m_Tree; + private ParentNode m_Node; + private int m_Page; + + private GoGump( int page, Mobile from, LocationTree tree, ParentNode node ) : base( 50, 50 ) + { + from.CloseGump( typeof( GoGump ) ); + + tree.LastBranch[from] = node; + + m_Page = page; + m_Tree = tree; + m_Node = node; + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int count = node.Children.Length - (page * EntryCount); + + if ( count < 0 ) + count = 0; + else if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1)); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( node.Parent != null ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + int emptyWidth = TotalWidth - (PrevWidth * 2) - NextWidth - (OffsetSize * 5) - (OldStyle ? SetWidth + OffsetSize : 0); + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID ); + + AddHtml( x + TextOffsetX, y, emptyWidth - TextOffsetX, EntryHeight, String.Format( "
{0}
", node.Name ), false, false ); + + x += emptyWidth + OffsetSize; + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 0 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 2, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( (page + 1) * EntryCount < node.Children.Length ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + for ( int i = 0, index = page * EntryCount; i < EntryCount && index < node.Children.Length; ++i, ++index ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + object child = node.Children[index]; + string name = ""; + + if ( child is ParentNode ) + name = ((ParentNode)child).Name; + else if ( child is ChildNode ) + name = ((ChildNode)child).Name; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, name ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, index + 4, GumpButtonType.Reply, 0 ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 1: + { + if ( m_Node.Parent != null ) + from.SendGump( new GoGump( 0, from, m_Tree, m_Node.Parent ) ); + + break; + } + case 2: + { + if ( m_Page > 0 ) + from.SendGump( new GoGump( m_Page - 1, from, m_Tree, m_Node ) ); + + break; + } + case 3: + { + if ( (m_Page + 1) * EntryCount < m_Node.Children.Length ) + from.SendGump( new GoGump( m_Page + 1, from, m_Tree, m_Node ) ); + + break; + } + default: + { + int index = info.ButtonID - 4; + + if ( index >= 0 && index < m_Node.Children.Length ) + { + object o = m_Node.Children[index]; + + if ( o is ParentNode ) + { + from.SendGump( new GoGump( 0, from, m_Tree, (ParentNode)o ) ); + } + else + { + ChildNode n = (ChildNode)o; + + from.MoveToWorld( n.Location, m_Tree.Map ); + } + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Go/LocationTree.cs b/Scripts/Gumps/Go/LocationTree.cs new file mode 100644 index 0000000..9c64548 --- /dev/null +++ b/Scripts/Gumps/Go/LocationTree.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Server; + +namespace Server.Gumps +{ + public class LocationTree + { + private Map m_Map; + private ParentNode m_Root; + private Dictionary m_LastBranch; + + public LocationTree( string fileName, Map map ) + { + m_LastBranch = new Dictionary(); + m_Map = map; + + string path = Path.Combine( "Data/Locations/", fileName ); + + if ( File.Exists( path ) ) + { + XmlTextReader xml = new XmlTextReader( new StreamReader( path ) ); + + xml.WhitespaceHandling = WhitespaceHandling.None; + + m_Root = Parse( xml ); + + xml.Close(); + } + } + + public Dictionary LastBranch + { + get + { + return m_LastBranch; + } + } + + public Map Map + { + get + { + return m_Map; + } + } + + public ParentNode Root + { + get + { + return m_Root; + } + } + + private ParentNode Parse( XmlTextReader xml ) + { + xml.Read(); + xml.Read(); + xml.Read(); + + return new ParentNode( xml, null ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Go/ParentNode.cs b/Scripts/Gumps/Go/ParentNode.cs new file mode 100644 index 0000000..0866dc8 --- /dev/null +++ b/Scripts/Gumps/Go/ParentNode.cs @@ -0,0 +1,82 @@ +using System; +using System.Xml; +using System.Collections; +using Server; + +namespace Server.Gumps +{ + public class ParentNode + { + private ParentNode m_Parent; + private object[] m_Children; + + private string m_Name; + + public ParentNode( XmlTextReader xml, ParentNode parent ) + { + m_Parent = parent; + + Parse( xml ); + } + + private void Parse( XmlTextReader xml ) + { + if ( xml.MoveToAttribute( "name" ) ) + m_Name = xml.Value; + else + m_Name = "empty"; + + if ( xml.IsEmptyElement ) + { + m_Children = new object[0]; + } + else + { + ArrayList children = new ArrayList(); + + while (xml.Read() && (xml.NodeType == XmlNodeType.Element || xml.NodeType == XmlNodeType.Comment)) + { + if (xml.NodeType == XmlNodeType.Comment) + continue; + + if (xml.Name == "child") + { + ChildNode n = new ChildNode(xml, this); + + children.Add(n); + } + else + { + children.Add(new ParentNode(xml, this)); + } + } + + m_Children = children.ToArray(); + } + } + + public ParentNode Parent + { + get + { + return m_Parent; + } + } + + public object[] Children + { + get + { + return m_Children; + } + } + + public string Name + { + get + { + return m_Name; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/DeclareFealtyGump.cs b/Scripts/Gumps/Guilds/DeclareFealtyGump.cs new file mode 100644 index 0000000..ed07cb4 --- /dev/null +++ b/Scripts/Gumps/Guilds/DeclareFealtyGump.cs @@ -0,0 +1,54 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class DeclareFealtyGump : GuildMobileListGump + { + public DeclareFealtyGump( Mobile from, Guild guild ) : base( from, guild, true, guild.Members ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011097, false, false ); // Declare your fealty + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 250, 35, 1011098, false, false ); // I have selected my new lord. + + AddButton( 300, 400, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Mobile m = (Mobile)m_List[index]; + + if ( m != null && !m.Deleted ) + { + state.Mobile.GuildFealty = m; + } + } + } + } + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + } + } +} diff --git a/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs b/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs new file mode 100644 index 0000000..f79ddca --- /dev/null +++ b/Scripts/Gumps/Guilds/GrantGuildTitleGump.cs @@ -0,0 +1,57 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GrantGuildTitleGump : GuildMobileListGump + { + public GrantGuildTitleGump( Mobile from, Guild guild ) : base( from, guild, true, guild.Members ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011118, false, false ); // Grant a title to another member. + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011127, false, false ); // I dub thee... + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Mobile m = (Mobile)m_List[index]; + + if ( m != null && !m.Deleted ) + { + m_Mobile.SendLocalizedMessage( 1013074 ); // New title (20 characters max): + m_Mobile.Prompt = new GuildTitlePrompt( m_Mobile, m, m_Guild ); + } + } + } + } + else if ( info.ButtonID == 2 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs b/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs new file mode 100644 index 0000000..898d223 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildAbbrvPrompt.cs @@ -0,0 +1,55 @@ +using System; +using Server; +using Server.Guilds; +using Server.Prompts; + +namespace Server.Gumps +{ + public class GuildAbbrvPrompt : Prompt + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildAbbrvPrompt( Mobile m, Guild g ) + { + m_Mobile = m; + m_Guild = g; + } + + public override void OnCancel( Mobile from ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + text = text.Trim(); + + if ( text.Length > 3 ) + text = text.Substring( 0, 3 ); + + if ( text.Length > 0 ) + { + if ( Guild.FindByAbbrev( text ) != null ) + { + m_Mobile.SendMessage( "{0} conflicts with the abbreviation of an existing guild.", text ); + } + else + { + m_Guild.Abbreviation = text; + m_Guild.GuildMessage( 1018025, true, text ); // Your guild abbreviation has changed: + } + } + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs b/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs new file mode 100644 index 0000000..f2b935f --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildAcceptWarGump.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildAcceptWarGump : GuildListGump + { + public GuildAcceptWarGump( Mobile from, Guild guild ) : base( from, guild, true, guild.WarInvitations ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011147, false, false ); // Select the guild to accept the invitations: + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011100, false, false ); // Accept war invitations. + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Guild g = (Guild)m_List[index]; + + if ( g != null ) + { + m_Guild.WarInvitations.Remove( g ); + g.WarDeclarations.Remove( m_Guild ); + + m_Guild.AddEnemy( g ); + m_Guild.GuildMessage( 1018020, true, "{0} ({1})", g.Name, g.Abbreviation ); + + GuildGump.EnsureClosed( m_Mobile ); + + if ( m_Guild.WarInvitations.Count > 0 ) + m_Mobile.SendGump( new GuildAcceptWarGump( m_Mobile, m_Guild ) ); + else + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + } + else if ( info.ButtonID == 2 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs b/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs new file mode 100644 index 0000000..670adc6 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildAdminCandidatesGump.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; +using Server.Factions; + +namespace Server.Gumps +{ + public class GuildAdminCandidatesGump : GuildMobileListGump + { + public GuildAdminCandidatesGump( Mobile from, Guild guild ) : base( from, guild, true, guild.Candidates ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1013075, false, false ); // Accept or Refuse candidates for membership + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1013076, false, false ); // Accept + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1013077, false, false ); // Refuse + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + switch ( info.ButtonID ) + { + case 0: + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + + break; + } + case 1: // Accept + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Mobile m = (Mobile)m_List[index]; + + if ( m != null && !m.Deleted ) + { + #region Factions + PlayerState guildState = PlayerState.Find( m_Guild.Leader ); + PlayerState targetState = PlayerState.Find( m ); + + Faction guildFaction = ( guildState == null ? null : guildState.Faction ); + Faction targetFaction = ( targetState == null ? null : targetState.Faction ); + + if ( guildFaction != targetFaction ) + { + if ( guildFaction == null ) + m_Mobile.SendLocalizedMessage( 1013027 ); // That player cannot join a non-faction guild. + else if ( targetFaction == null ) + m_Mobile.SendLocalizedMessage( 1013026 ); // That player must be in a faction before joining this guild. + else + m_Mobile.SendLocalizedMessage( 1013028 ); // That person has a different faction affiliation. + + break; + } + else if ( targetState != null && targetState.IsLeaving ) + { + // OSI does this quite strangely, so we'll just do it this way + m_Mobile.SendMessage( "That person is quitting their faction and so you may not recruit them." ); + break; + } + #endregion + + m_Guild.Candidates.Remove( m ); + m_Guild.Accepted.Add( m ); + + GuildGump.EnsureClosed( m_Mobile ); + + if ( m_Guild.Candidates.Count > 0 ) + m_Mobile.SendGump( new GuildAdminCandidatesGump( m_Mobile, m_Guild ) ); + else + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + + break; + } + case 2: // Refuse + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Mobile m = (Mobile)m_List[index]; + + if ( m != null && !m.Deleted ) + { + m_Guild.Candidates.Remove( m ); + + GuildGump.EnsureClosed( m_Mobile ); + + if ( m_Guild.Candidates.Count > 0 ) + m_Mobile.SendGump( new GuildAdminCandidatesGump( m_Mobile, m_Guild ) ); + else + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildCandidatesGump.cs b/Scripts/Gumps/Guilds/GuildCandidatesGump.cs new file mode 100644 index 0000000..ac7bbfd --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildCandidatesGump.cs @@ -0,0 +1,34 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildCandidatesGump : GuildMobileListGump + { + public GuildCandidatesGump( Mobile from, Guild guild ) : base( from, guild, false, guild.Candidates ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 500, 35, 1013030, false, false ); //
Candidates
+ + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 300, 35, 1011120, false, false ); // Return to the main menu. + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs b/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs new file mode 100644 index 0000000..2420639 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildChangeTypeGump.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Mobiles; +using Server.Network; +using Server.Factions; + +namespace Server.Gumps +{ + public class GuildChangeTypeGump : Gump + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildChangeTypeGump(Mobile from, Guild guild) + : base(20, 30) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage(0); + AddBackground(0, 0, 550, 400, 5054); + AddBackground(10, 10, 530, 380, 3000); + + AddHtmlLocalized(20, 15, 510, 30, 1013062, false, false); //
Change Guild Type Menu
+ + AddHtmlLocalized(50, 50, 450, 30, 1013066, false, false); // Please select the type of guild you would like to change to + + AddButton(20, 100, 4005, 4007, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(85, 100, 300, 30, 1013063, false, false); // Standard guild + + AddButton(20, 150, 4005, 4007, 2, GumpButtonType.Reply, 0); + AddItem(50, 143, 7109); + AddHtmlLocalized(85, 150, 300, 300, 1013064, false, false); // Order guild + + AddButton(20, 200, 4005, 4007, 3, GumpButtonType.Reply, 0); + AddItem(45, 200, 7107); + AddHtmlLocalized(85, 200, 300, 300, 1013065, false, false); // Chaos guild + + AddButton(300, 360, 4005, 4007, 4, GumpButtonType.Reply, 0); + AddHtmlLocalized(335, 360, 150, 30, 1011012, false, false); // CANCEL + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if ((Guild.NewGuildSystem && !BaseGuildGump.IsLeader(m_Mobile, m_Guild)) || (!Guild.NewGuildSystem && GuildGump.BadLeader(m_Mobile, m_Guild))) + return; + + GuildType newType; + + switch (info.ButtonID) + { + default: newType = m_Guild.Type; break; + case 1: newType = GuildType.Regular; break; + case 2: newType = GuildType.Order; break; + case 3: newType = GuildType.Chaos; break; + } + + if (m_Guild.Type != newType) + { + PlayerState pl = PlayerState.Find(m_Mobile); + + if (pl != null) + { + m_Mobile.SendLocalizedMessage(1010405); // You cannot change guild types while in a Faction! + } + else if (m_Guild.TypeLastChange.AddDays(7) > DateTime.Now) + { + m_Mobile.SendLocalizedMessage(1011142); // You have already changed your guild type recently. + // TODO: Clilocs 1011142-1011145 suggest a timer for pending changes + } + else + { + m_Guild.Type = newType; + m_Guild.GuildMessage(1018022, true, newType.ToString()); // Guild Message: Your guild type has changed: + } + } + + if (Guild.NewGuildSystem) + { + if (m_Mobile is PlayerMobile) + m_Mobile.SendGump(new GuildInfoGump((PlayerMobile)m_Mobile, m_Guild)); + + return; + } + + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildmasterGump(m_Mobile, m_Guild)); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildCharterGump.cs b/Scripts/Gumps/Guilds/GuildCharterGump.cs new file mode 100644 index 0000000..17ab36d --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildCharterGump.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildCharterGump : Gump + { + private Mobile m_Mobile; + private Guild m_Guild; + + private const string DefaultWebsite = "http://www.runuo.com/"; + + public GuildCharterGump( Mobile from, Guild guild ) : base( 20, 30 ) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 550, 400, 5054 ); + AddBackground( 10, 10, 530, 380, 3000 ); + + AddButton( 20, 360, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 360, 300, 35, 1011120, false, false ); // Return to the main menu. + + string charter; + + if ( (charter = guild.Charter) == null || (charter = charter.Trim()).Length <= 0 ) + AddHtmlLocalized( 20, 20, 400, 35, 1013032, false, false ); // No charter has been defined. + else + AddHtml( 20, 20, 510, 75, charter, true, true ); + + AddButton( 20, 200, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 200, 300, 20, 1011122, false, false ); // Visit the guild website : + + string website; + + if ( (website = guild.Website) == null || (website = website.Trim()).Length <= 0 ) + website = DefaultWebsite; + + AddHtml( 55, 220, 300, 20, website, false, false ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + switch ( info.ButtonID ) + { + case 0: return; // Close + case 1: break; // Return to main menu + case 2: + { + string website; + + if ( (website = m_Guild.Website) == null || (website = website.Trim()).Length <= 0 ) + website = DefaultWebsite; + + m_Mobile.LaunchBrowser( website ); + break; + } + } + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildCharterPrompt.cs b/Scripts/Gumps/Guilds/GuildCharterPrompt.cs new file mode 100644 index 0000000..f11107b --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildCharterPrompt.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Guilds; +using Server.Prompts; + +namespace Server.Gumps +{ + public class GuildCharterPrompt : Prompt + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildCharterPrompt( Mobile m, Guild g ) + { + m_Mobile = m; + m_Guild = g; + } + + public override void OnCancel( Mobile from ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + text = text.Trim(); + + if ( text.Length > 50 ) + text = text.Substring( 0, 50 ); + + if ( text.Length > 0 ) + m_Guild.Charter = text; + + m_Mobile.SendLocalizedMessage( 1013072 ); // Enter the new website for the guild (50 characters max): + m_Mobile.Prompt = new GuildWebsitePrompt( m_Mobile, m_Guild ); + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs b/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs new file mode 100644 index 0000000..b20250b --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildDeclarePeaceGump.cs @@ -0,0 +1,64 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildDeclarePeaceGump : GuildListGump + { + public GuildDeclarePeaceGump( Mobile from, Guild guild ) : base( from, guild, true, guild.Enemies ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011137, false, false ); // Select the guild you wish to declare peace with. + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011138, false, false ); // Send the olive branch. + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Guild g = (Guild)m_List[index]; + + if ( g != null ) + { + m_Guild.RemoveEnemy( g ); + m_Guild.GuildMessage( 1018018, true, "{0} ({1})", g.Name, g.Abbreviation ); // Guild Message: You are now at peace with this guild: + + GuildGump.EnsureClosed( m_Mobile ); + + if ( m_Guild.Enemies.Count > 0 ) + m_Mobile.SendGump( new GuildDeclarePeaceGump( m_Mobile, m_Guild ) ); + else + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + } + else if ( info.ButtonID == 2 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs b/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs new file mode 100644 index 0000000..19ae466 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildDeclareWarGump.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Network; +using Server.Factions; +using System.Collections.Generic; + +namespace Server.Gumps +{ + public class GuildDeclareWarGump : GuildListGump + { + public GuildDeclareWarGump( Mobile from, Guild guild, List list ) + : base( from, guild, true, list ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011065, false, false ); // Select the guild you wish to declare war on. + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011068, false, false ); // Send the challenge! + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Guild g = m_List[index]; + + if ( g != null ) + { + if ( g == m_Guild ) + { + m_Mobile.SendLocalizedMessage( 501184 ); // You cannot declare war against yourself! + } + else if ( (g.WarInvitations.Contains( m_Guild ) && m_Guild.WarDeclarations.Contains( g )) || m_Guild.IsWar( g ) ) + { + m_Mobile.SendLocalizedMessage( 501183 ); // You are already at war with that guild. + } + else if( Faction.Find( m_Guild.Leader ) != null ) + { + m_Mobile.SendLocalizedMessage( 1005288 ); // You cannot declare war while you are in a faction + } + else + { + if ( !m_Guild.WarDeclarations.Contains( g ) ) + { + m_Guild.WarDeclarations.Add( g ); + m_Guild.GuildMessage( 1018019, true, "{0} ({1})", g.Name, g.Abbreviation ); // Guild Message: Your guild has sent an invitation for war: + } + + if ( !g.WarInvitations.Contains( m_Guild ) ) + { + g.WarInvitations.Add( m_Guild ); + g.GuildMessage( 1018021, true, "{0} ({1})", m_Guild.Name, m_Guild.Abbreviation ); // Guild Message: Your guild has received an invitation to war: + } + } + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildWarAdminGump( m_Mobile, m_Guild ) ); + } + } + } + } + else if ( info.ButtonID == 2 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs b/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs new file mode 100644 index 0000000..a0f2e8b --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildDeclareWarPrompt.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Prompts; +using System.Collections.Generic; + +namespace Server.Gumps +{ + public class GuildDeclareWarPrompt : Prompt + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildDeclareWarPrompt( Mobile m, Guild g ) + { + m_Mobile = m; + m_Guild = g; + } + + public override void OnCancel( Mobile from ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildWarAdminGump( m_Mobile, m_Guild ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + text = text.Trim(); + + if ( text.Length >= 3 ) + { + List guilds = Utility.CastConvertList( Guild.Search( text ) ); + + GuildGump.EnsureClosed( m_Mobile ); + + if ( guilds.Count > 0 ) + { + m_Mobile.SendGump( new GuildDeclareWarGump( m_Mobile, m_Guild, guilds ) ); + } + else + { + m_Mobile.SendGump( new GuildWarAdminGump( m_Mobile, m_Guild ) ); + m_Mobile.SendLocalizedMessage( 1018003 ); // No guilds found matching - try another name in the search + } + } + else + { + m_Mobile.SendMessage( "Search string must be at least three letters in length." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildDismissGump.cs b/Scripts/Gumps/Guilds/GuildDismissGump.cs new file mode 100644 index 0000000..a081cee --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildDismissGump.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildDismissGump : GuildMobileListGump + { + public GuildDismissGump ( Mobile from, Guild guild ) : base( from, guild, true, guild.Members ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011124, false, false ); // Whom do you wish to dismiss? + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011125, false, false ); // Kick them out! + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Mobile m = (Mobile)m_List[index]; + + if ( m != null && !m.Deleted ) + { + m_Guild.RemoveMember( m ); + + if ( m_Mobile.AccessLevel >= AccessLevel.GameMaster || m_Mobile == m_Guild.Leader ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + } + } + else if ( info.ButtonID == 2 && (m_Mobile.AccessLevel >= AccessLevel.GameMaster || m_Mobile == m_Guild.Leader) ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildGump.cs b/Scripts/Gumps/Guilds/GuildGump.cs new file mode 100644 index 0000000..27faf87 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildGump.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Network; +using Server.Prompts; +using Server.Targeting; + +namespace Server.Gumps +{ + public class GuildGump : Gump + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildGump( Mobile beholder, Guild guild ) : base( 20, 30 ) + { + m_Mobile = beholder; + m_Guild = guild; + + Dragable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 550, 400, 5054 ); + AddBackground( 10, 10, 530, 380, 3000 ); + + AddHtml( 20, 15, 200, 35, guild.Name, false, false ); + + Mobile leader = guild.Leader; + + if ( leader != null ) + { + string leadTitle; + + if ( (leadTitle = leader.GuildTitle) != null && (leadTitle = leadTitle.Trim()).Length > 0 ) + leadTitle += ": "; + else + leadTitle = ""; + + string leadName; + + if ( (leadName = leader.Name) == null || (leadName = leadName.Trim()).Length <= 0 ) + leadName = "(empty)"; + + AddHtml( 220, 15, 250, 35, leadTitle + leadName, false, false ); + } + + AddButton( 20, 50, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 50, 100, 20, 1013022, false, false ); // Loyal to + + Mobile fealty = beholder.GuildFealty; + + if ( fealty == null || !guild.IsMember( fealty ) ) + fealty = leader; + + if ( fealty == null ) + fealty = beholder; + + string fealtyName; + + if ( fealty == null || (fealtyName = fealty.Name) == null || (fealtyName = fealtyName.Trim()).Length <= 0 ) + fealtyName = "(empty)"; + + if ( beholder == fealty ) + AddHtmlLocalized( 55, 70, 470, 20, 1018002, false, false ); // yourself + else + AddHtml( 55, 70, 470, 20, fealtyName, false, false ); + + AddButton( 215, 50, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 250, 50, 170, 20, 1013023, false, false ); // Display guild abbreviation + AddHtmlLocalized( 250, 70, 50, 20, beholder.DisplayGuildTitle ? 1011262 : 1011263, false, false ); // on/off + + AddButton( 20, 100, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 100, 470, 30, 1011086, false, false ); // View the current roster. + + AddButton( 20, 130, 4005, 4007, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 130, 470, 30, 1011085, false, false ); // Recruit someone into the guild. + + if ( guild.Candidates.Count > 0 ) + { + AddButton( 20, 160, 4005, 4007, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 160, 470, 30, 1011093, false, false ); // View list of candidates who have been sponsored to the guild. + } + else + { + AddImage( 20, 160, 4020 ); + AddHtmlLocalized( 55, 160, 470, 30, 1013031, false, false ); // There are currently no candidates for membership. + } + + AddButton( 20, 220, 4005, 4007, 6, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 220, 470, 30, 1011087, false, false ); // View the guild's charter. + + AddButton( 20, 250, 4005, 4007, 7, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 250, 470, 30, 1011092, false, false ); // Resign from the guild. + + AddButton( 20, 280, 4005, 4007, 8, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 280, 470, 30, 1011095, false, false ); // View list of guilds you are at war with. + + if ( beholder.AccessLevel >= AccessLevel.GameMaster || beholder == leader ) + { + AddButton( 20, 310, 4005, 4007, 9, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 310, 470, 30, 1011094, false, false ); // Access guildmaster functions. + } + else + { + AddImage( 20, 310, 4020 ); + AddHtmlLocalized( 55, 310, 470, 30, 1018013, false, false ); // Reserved for guildmaster + } + + AddButton( 20, 360, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 360, 470, 30, 1011441, false, false ); // EXIT + } + + public static void EnsureClosed( Mobile m ) + { + m.CloseGump( typeof( DeclareFealtyGump ) ); + m.CloseGump( typeof( GrantGuildTitleGump ) ); + m.CloseGump( typeof( GuildAdminCandidatesGump ) ); + m.CloseGump( typeof( GuildCandidatesGump ) ); + m.CloseGump( typeof( GuildChangeTypeGump ) ); + m.CloseGump( typeof( GuildCharterGump ) ); + m.CloseGump( typeof( GuildDismissGump ) ); + m.CloseGump( typeof( GuildGump ) ); + m.CloseGump( typeof( GuildmasterGump ) ); + m.CloseGump( typeof( GuildRosterGump ) ); + m.CloseGump( typeof( GuildWarGump ) ); + } + + public static bool BadLeader( Mobile m, Guild g ) + { + if ( m.Deleted || g.Disbanded || (m.AccessLevel < AccessLevel.GameMaster && g.Leader != m) ) + return true; + + Item stone = g.Guildstone; + + return ( stone == null || stone.Deleted || !m.InRange( stone.GetWorldLocation(), 2 ) ); + } + + public static bool BadMember( Mobile m, Guild g ) + { + if ( m.Deleted || g.Disbanded || (m.AccessLevel < AccessLevel.GameMaster && !g.IsMember( m )) ) + return true; + + Item stone = g.Guildstone; + + return ( stone == null || stone.Deleted || !m.InRange( stone.GetWorldLocation(), 2 ) ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( BadMember( m_Mobile, m_Guild ) ) + return; + + switch ( info.ButtonID ) + { + case 1: // Loyalty + { + EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new DeclareFealtyGump( m_Mobile, m_Guild ) ); + + break; + } + case 2: // Toggle display abbreviation + { + m_Mobile.DisplayGuildTitle = !m_Mobile.DisplayGuildTitle; + + EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + + break; + } + case 3: // View the current roster + { + EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildRosterGump( m_Mobile, m_Guild ) ); + + break; + } + case 4: // Recruit + { + m_Mobile.Target = new GuildRecruitTarget( m_Mobile, m_Guild ); + + break; + } + case 5: // Membership candidates + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildCandidatesGump( m_Mobile, m_Guild ) ); + + break; + } + case 6: // View charter + { + EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildCharterGump( m_Mobile, m_Guild ) ); + + break; + } + case 7: // Resign + { + m_Guild.RemoveMember( m_Mobile ); + + break; + } + case 8: // View wars + { + EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildWarGump( m_Mobile, m_Guild ) ); + + break; + } + case 9: // Guildmaster functions + { + if ( m_Mobile.AccessLevel >= AccessLevel.GameMaster || m_Guild.Leader == m_Mobile ) + { + EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildListGump.cs b/Scripts/Gumps/Guilds/GuildListGump.cs new file mode 100644 index 0000000..5937347 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildListGump.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using System.Collections.Generic; + +namespace Server.Gumps +{ + public abstract class GuildListGump : Gump + { + protected Mobile m_Mobile; + protected Guild m_Guild; + protected List m_List; + + public GuildListGump( Mobile from, Guild guild, bool radio, List list ) : base( 20, 30 ) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 550, 440, 5054 ); + AddBackground( 10, 10, 530, 420, 3000 ); + + Design(); + + m_List = new List( list ); + + for ( int i = 0; i < m_List.Count; ++i ) + { + if ( (i % 11) == 0 ) + { + if ( i != 0 ) + { + AddButton( 300, 370, 4005, 4007, 0, GumpButtonType.Page, (i / 11) + 1 ); + AddHtmlLocalized( 335, 370, 300, 35, 1011066, false, false ); // Next page + } + + AddPage( (i / 11) + 1 ); + + if ( i != 0 ) + { + AddButton( 20, 370, 4014, 4016, 0, GumpButtonType.Page, (i / 11) ); + AddHtmlLocalized( 55, 370, 300, 35, 1011067, false, false ); // Previous page + } + } + + if ( radio ) + AddRadio( 20, 35 + ((i % 11) * 30), 208, 209, false, i ); + + Guild g = m_List[i]; + + string name; + + if ( (name = g.Name) != null && (name = name.Trim()).Length <= 0 ) + name = "(empty)"; + + AddLabel( (radio ? 55 : 20), 35 + ((i % 11) * 30), 0, name ); + } + } + + protected virtual void Design() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildMobileListGump.cs b/Scripts/Gumps/Guilds/GuildMobileListGump.cs new file mode 100644 index 0000000..2412055 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildMobileListGump.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using System.Collections.Generic; + +namespace Server.Gumps +{ + public abstract class GuildMobileListGump : Gump + { + protected Mobile m_Mobile; + protected Guild m_Guild; + protected List m_List; + + public GuildMobileListGump( Mobile from, Guild guild, bool radio, List list ) + : base( 20, 30 ) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 550, 440, 5054 ); + AddBackground( 10, 10, 530, 420, 3000 ); + + Design(); + + m_List = new List( list ); + + for ( int i = 0; i < m_List.Count; ++i ) + { + if ( (i % 11) == 0 ) + { + if ( i != 0 ) + { + AddButton( 300, 370, 4005, 4007, 0, GumpButtonType.Page, (i / 11) + 1 ); + AddHtmlLocalized( 335, 370, 300, 35, 1011066, false, false ); // Next page + } + + AddPage( (i / 11) + 1 ); + + if ( i != 0 ) + { + AddButton( 20, 370, 4014, 4016, 0, GumpButtonType.Page, (i / 11) ); + AddHtmlLocalized( 55, 370, 300, 35, 1011067, false, false ); // Previous page + } + } + + if ( radio ) + AddRadio( 20, 35 + ((i % 11) * 30), 208, 209, false, i ); + + Mobile m = m_List[i]; + + string name; + + if ( (name = m.Name) != null && (name = name.Trim()).Length <= 0 ) + name = "(empty)"; + + AddLabel( (radio ? 55 : 20), 35 + ((i % 11) * 30), 0, name ); + } + } + + protected virtual void Design() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildNamePrompt.cs b/Scripts/Gumps/Guilds/GuildNamePrompt.cs new file mode 100644 index 0000000..bb80d38 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildNamePrompt.cs @@ -0,0 +1,55 @@ +using System; +using Server; +using Server.Guilds; +using Server.Prompts; + +namespace Server.Gumps +{ + public class GuildNamePrompt : Prompt + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildNamePrompt( Mobile m, Guild g ) + { + m_Mobile = m; + m_Guild = g; + } + + public override void OnCancel( Mobile from ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + text = text.Trim(); + + if ( text.Length > 40 ) + text = text.Substring( 0, 40 ); + + if ( text.Length > 0 ) + { + if ( Guild.FindByName( text ) != null ) + { + m_Mobile.SendMessage( "{0} conflicts with the name of an existing guild.", text ); + } + else + { + m_Guild.Name = text; + m_Guild.GuildMessage( 1018024, true, text ); // The name of your guild has changed: + } + } + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildRejectWarGump.cs b/Scripts/Gumps/Guilds/GuildRejectWarGump.cs new file mode 100644 index 0000000..018bcca --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildRejectWarGump.cs @@ -0,0 +1,64 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildRejectWarGump : GuildListGump + { + public GuildRejectWarGump( Mobile from, Guild guild ) : base( from, guild, true, guild.WarInvitations ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011148, false, false ); // Select the guild to reject their invitations: + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011101, false, false ); // Reject war invitations. + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Guild g = (Guild)m_List[index]; + + if ( g != null ) + { + m_Guild.WarInvitations.Remove( g ); + g.WarDeclarations.Remove( m_Guild ); + + GuildGump.EnsureClosed( m_Mobile ); + + if ( m_Guild.WarInvitations.Count > 0 ) + m_Mobile.SendGump( new GuildRejectWarGump( m_Mobile, m_Guild ) ); + else + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + } + else if ( info.ButtonID == 2 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs b/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs new file mode 100644 index 0000000..5334c12 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildRescindDeclarationGump.cs @@ -0,0 +1,64 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildRescindDeclarationGump : GuildListGump + { + public GuildRescindDeclarationGump( Mobile from, Guild guild ) : base( from, guild, true, guild.WarDeclarations ) + { + } + + protected override void Design() + { + AddHtmlLocalized( 20, 10, 400, 35, 1011150, false, false ); // Select the guild to rescind our invitations: + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 245, 30, 1011102, false, false ); // Rescind your war declarations. + + AddButton( 300, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 335, 400, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_List.Count ) + { + Guild g = (Guild)m_List[index]; + + if ( g != null ) + { + m_Guild.WarDeclarations.Remove( g ); + g.WarInvitations.Remove( m_Guild ); + + GuildGump.EnsureClosed( m_Mobile ); + + if ( m_Guild.WarDeclarations.Count > 0 ) + m_Mobile.SendGump( new GuildRescindDeclarationGump( m_Mobile, m_Guild ) ); + else + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } + } + else if ( info.ButtonID == 2 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildRosterGump.cs b/Scripts/Gumps/Guilds/GuildRosterGump.cs new file mode 100644 index 0000000..10abdda --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildRosterGump.cs @@ -0,0 +1,34 @@ +using System; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildRosterGump : GuildMobileListGump + { + public GuildRosterGump( Mobile from, Guild guild ) : base( from, guild, false, guild.Members ) + { + } + + protected override void Design() + { + AddHtml( 20, 10, 500, 35, String.Format( "
{0}
", m_Guild.Name ), false, false ); + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 300, 35, 1011120, false, false ); // Return to the main menu. + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildTitlePrompt.cs b/Scripts/Gumps/Guilds/GuildTitlePrompt.cs new file mode 100644 index 0000000..d10e6f8 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildTitlePrompt.cs @@ -0,0 +1,50 @@ +using System; +using Server; +using Server.Guilds; +using Server.Prompts; + +namespace Server.Gumps +{ + public class GuildTitlePrompt : Prompt + { + private Mobile m_Leader, m_Target; + private Guild m_Guild; + + public GuildTitlePrompt( Mobile leader, Mobile target, Guild g ) + { + m_Leader = leader; + m_Target = target; + m_Guild = g; + } + + public override void OnCancel( Mobile from ) + { + if ( GuildGump.BadLeader( m_Leader, m_Guild ) ) + return; + else if ( m_Target.Deleted || !m_Guild.IsMember( m_Target ) ) + return; + + GuildGump.EnsureClosed( m_Leader ); + m_Leader.SendGump( new GuildmasterGump( m_Leader, m_Guild ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( GuildGump.BadLeader( m_Leader, m_Guild ) ) + return; + else if ( m_Target.Deleted || !m_Guild.IsMember( m_Target ) ) + return; + + text = text.Trim(); + + if ( text.Length > 20 ) + text = text.Substring( 0, 20 ); + + if ( text.Length > 0 ) + m_Target.GuildTitle = text; + + GuildGump.EnsureClosed( m_Leader ); + m_Leader.SendGump( new GuildmasterGump( m_Leader, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildWarAdminGump.cs b/Scripts/Gumps/Guilds/GuildWarAdminGump.cs new file mode 100644 index 0000000..b87f48c --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildWarAdminGump.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildWarAdminGump : Gump + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildWarAdminGump( Mobile from, Guild guild ) : base( 20, 30 ) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 550, 440, 5054 ); + AddBackground( 10, 10, 530, 420, 3000 ); + + AddHtmlLocalized( 20, 10, 510, 35, 1011105, false, false ); //
WAR FUNCTIONS
+ + AddButton( 20, 40, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 40, 400, 30, 1011099, false, false ); // Declare war through guild name search. + + int count = 0; + + if ( guild.Enemies.Count > 0 ) + { + AddButton( 20, 160 + (count * 30), 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 160 + (count++ * 30), 400, 30, 1011103, false, false ); // Declare peace. + } + else + { + AddHtmlLocalized( 20, 160 + (count++ * 30), 400, 30, 1013033, false, false ); // No current wars + } + + if ( guild.WarInvitations.Count > 0 ) + { + AddButton( 20, 160 + (count * 30), 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 160 + (count++ * 30), 400, 30, 1011100, false, false ); // Accept war invitations. + + AddButton( 20, 160 + (count * 30), 4005, 4007, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 160 + (count++ * 30), 400, 30, 1011101, false, false ); // Reject war invitations. + } + else + { + AddHtmlLocalized( 20, 160 + (count++ * 30), 400, 30, 1018012, false, false ); // No current invitations received for war. + } + + if ( guild.WarDeclarations.Count > 0 ) + { + AddButton( 20, 160 + (count * 30), 4005, 4007, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 160 + (count++ * 30), 400, 30, 1011102, false, false ); // Rescind your war declarations. + } + else + { + AddHtmlLocalized( 20, 160 + (count++ * 30), 400, 30, 1013055, false, false ); // No current war declarations + } + + AddButton( 20, 400, 4005, 4007, 6, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 400, 35, 1011104, false, false ); // Return to the previous menu. + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + switch ( info.ButtonID ) + { + case 1: // Declare war + { + m_Mobile.SendLocalizedMessage( 1018001 ); // Declare war through search - Enter Guild Name: + m_Mobile.Prompt = new GuildDeclareWarPrompt( m_Mobile, m_Guild ); + + break; + } + case 2: // Declare peace + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildDeclarePeaceGump( m_Mobile, m_Guild ) ); + + break; + } + case 3: // Accept war + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildAcceptWarGump( m_Mobile, m_Guild ) ); + + break; + } + case 4: // Reject war + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildRejectWarGump( m_Mobile, m_Guild ) ); + + break; + } + case 5: // Rescind declarations + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildRescindDeclarationGump( m_Mobile, m_Guild ) ); + + break; + } + case 6: // Return + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildWarGump.cs b/Scripts/Gumps/Guilds/GuildWarGump.cs new file mode 100644 index 0000000..5c1692b --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildWarGump.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Gumps +{ + public class GuildWarGump : Gump + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildWarGump( Mobile from, Guild guild ) : base( 20, 30 ) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 550, 440, 5054 ); + AddBackground( 10, 10, 530, 420, 3000 ); + + AddHtmlLocalized( 20, 10, 500, 35, 1011133, false, false ); //
WARFARE STATUS
+ + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 300, 35, 1011120, false, false ); // Return to the main menu. + + AddPage( 1 ); + + AddButton( 375, 375, 5224, 5224, 0, GumpButtonType.Page, 2 ); + AddHtmlLocalized( 410, 373, 100, 25, 1011066, false, false ); // Next page + + AddHtmlLocalized( 20, 45, 400, 20, 1011134, false, false ); // We are at war with: + + List enemies = guild.Enemies; + + if ( enemies.Count == 0 ) + { + AddHtmlLocalized( 20, 65, 400, 20, 1013033, false, false ); // No current wars + } + else + { + for ( int i = 0; i < enemies.Count; ++i ) + { + Guild g = enemies[i]; + + AddHtml( 20, 65 + (i * 20), 300, 20, g.Name, false, false ); + } + } + + AddPage( 2 ); + + AddButton( 375, 375, 5224, 5224, 0, GumpButtonType.Page, 3 ); + AddHtmlLocalized( 410, 373, 100, 25, 1011066, false, false ); // Next page + + AddButton( 30, 375, 5223, 5223, 0, GumpButtonType.Page, 1 ); + AddHtmlLocalized( 65, 373, 150, 25, 1011067, false, false ); // Previous page + + AddHtmlLocalized( 20, 45, 400, 20, 1011136, false, false ); // Guilds that we have declared war on: + + List declared = guild.WarDeclarations; + + if ( declared.Count == 0 ) + { + AddHtmlLocalized( 20, 65, 400, 20, 1018012, false, false ); // No current invitations received for war. + } + else + { + for ( int i = 0; i < declared.Count; ++i ) + { + Guild g = (Guild)declared[i]; + + AddHtml( 20, 65 + (i * 20), 300, 20, g.Name, false, false ); + } + } + + AddPage( 3 ); + + AddButton( 30, 375, 5223, 5223, 0, GumpButtonType.Page, 2 ); + AddHtmlLocalized( 65, 373, 150, 25, 1011067, false, false ); // Previous page + + AddHtmlLocalized( 20, 45, 400, 20, 1011135, false, false ); // Guilds that have declared war on us: + + List invites = guild.WarInvitations; + + if ( invites.Count == 0 ) + { + AddHtmlLocalized( 20, 65, 400, 20, 1013055, false, false ); // No current war declarations + } + else + { + for ( int i = 0; i < invites.Count; ++i ) + { + Guild g = invites[i]; + + AddHtml( 20, 65 + (i * 20), 300, 20, g.Name, false, false ); + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + if ( info.ButtonID == 1 ) + { + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs b/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs new file mode 100644 index 0000000..f528546 --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildWebsitePrompt.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Guilds; +using Server.Prompts; + +namespace Server.Gumps +{ + public class GuildWebsitePrompt : Prompt + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildWebsitePrompt( Mobile m, Guild g ) + { + m_Mobile = m; + m_Guild = g; + } + + public override void OnCancel( Mobile from ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( GuildGump.BadLeader( m_Mobile, m_Guild ) ) + return; + + text = text.Trim(); + + if ( text.Length > 50 ) + text = text.Substring( 0, 50 ); + + if ( text.Length > 0 ) + m_Guild.Website = text; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildmasterGump( m_Mobile, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/GuildmasterGump.cs b/Scripts/Gumps/Guilds/GuildmasterGump.cs new file mode 100644 index 0000000..fb692ae --- /dev/null +++ b/Scripts/Gumps/Guilds/GuildmasterGump.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Guilds; +using Server.Network; + +namespace Server.Gumps +{ + public class GuildmasterGump : Gump + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildmasterGump(Mobile from, Guild guild) + : base(20, 30) + { + m_Mobile = from; + m_Guild = guild; + + Dragable = false; + + AddPage(0); + AddBackground(0, 0, 550, 400, 5054); + AddBackground(10, 10, 530, 380, 3000); + + AddHtmlLocalized(20, 15, 510, 35, 1011121, false, false); //
GUILDMASTER FUNCTIONS
+ + AddButton(20, 40, 4005, 4007, 2, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 40, 470, 30, 1011107, false, false); // Set the guild name. + + AddButton(20, 70, 4005, 4007, 3, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 70, 470, 30, 1011109, false, false); // Set the guild's abbreviation. + + if (Guild.OrderChaos) + { + AddButton(20, 100, 4005, 4007, 4, GumpButtonType.Reply, 0); + + switch (m_Guild.Type) + { + case GuildType.Regular: + AddHtmlLocalized(55, 100, 470, 30, 1013059, false, false); // Change guild type: Currently Standard + break; + case GuildType.Order: + AddHtmlLocalized(55, 100, 470, 30, 1013057, false, false); // Change guild type: Currently Order + break; + case GuildType.Chaos: + AddHtmlLocalized(55, 100, 470, 30, 1013058, false, false); // Change guild type: Currently Chaos + break; + } + } + + AddButton(20, 130, 4005, 4007, 5, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 130, 470, 30, 1011112, false, false); // Set the guild's charter. + + AddButton(20, 160, 4005, 4007, 6, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 160, 470, 30, 1011113, false, false); // Dismiss a member. + + AddButton(20, 190, 4005, 4007, 7, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 190, 470, 30, 1011114, false, false); // Go to the WAR menu. + + if (m_Guild.Candidates.Count > 0) + { + AddButton(20, 220, 4005, 4007, 8, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 220, 470, 30, 1013056, false, false); // Administer the list of candidates + } + else + { + AddImage(20, 220, 4020); + AddHtmlLocalized(55, 220, 470, 30, 1013031, false, false); // There are currently no candidates for membership. + } + + AddButton(20, 250, 4005, 4007, 9, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 250, 470, 30, 1011117, false, false); // Set the guildmaster's title. + + AddButton(20, 280, 4005, 4007, 10, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 280, 470, 30, 1011118, false, false); // Grant a title to another member. + + AddButton(20, 310, 4005, 4007, 11, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 310, 470, 30, 1011119, false, false); // Move this guildstone. + + AddButton(20, 360, 4005, 4007, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(55, 360, 245, 30, 1011120, false, false); // Return to the main menu. + + AddButton(300, 360, 4005, 4007, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(335, 360, 100, 30, 1011441, false, false); // EXIT + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (GuildGump.BadLeader(m_Mobile, m_Guild)) + return; + + switch (info.ButtonID) + { + case 1: // Main menu + { + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildGump(m_Mobile, m_Guild)); + + break; + } + case 2: // Set guild name + { + m_Mobile.SendLocalizedMessage(1013060); // Enter new guild name (40 characters max): + m_Mobile.Prompt = new GuildNamePrompt(m_Mobile, m_Guild); + + break; + } + case 3: // Set guild abbreviation + { + m_Mobile.SendLocalizedMessage(1013061); // Enter new guild abbreviation (3 characters max): + m_Mobile.Prompt = new GuildAbbrvPrompt(m_Mobile, m_Guild); + + break; + } + case 4: // Change guild type + { + if (!Guild.OrderChaos) + return; + + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildChangeTypeGump(m_Mobile, m_Guild)); + + break; + } + case 5: // Set charter + { + m_Mobile.SendLocalizedMessage(1013071); // Enter the new guild charter (50 characters max): + m_Mobile.Prompt = new GuildCharterPrompt(m_Mobile, m_Guild); + + break; + } + case 6: // Dismiss member + { + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildDismissGump(m_Mobile, m_Guild)); + + break; + } + case 7: // War menu + { + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildWarAdminGump(m_Mobile, m_Guild)); + + break; + } + case 8: // Administer candidates + { + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildAdminCandidatesGump(m_Mobile, m_Guild)); + + break; + } + case 9: // Set guildmaster's title + { + m_Mobile.SendLocalizedMessage(1013073); // Enter new guildmaster title (20 characters max): + m_Mobile.Prompt = new GuildTitlePrompt(m_Mobile, m_Mobile, m_Guild); + + break; + } + case 10: // Grant title + { + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GrantGuildTitleGump(m_Mobile, m_Guild)); + + break; + } + case 11: // Move guildstone + { + if (m_Guild.Guildstone != null) + { + GuildTeleporter item = new GuildTeleporter(m_Guild.Guildstone); + + if (m_Guild.Teleporter != null) + m_Guild.Teleporter.Delete(); + + m_Mobile.SendLocalizedMessage(501133); // Use the teleporting object placed in your backpack to move this guildstone. + + m_Mobile.AddToBackpack(item); + m_Guild.Teleporter = item; + } + + GuildGump.EnsureClosed(m_Mobile); + m_Mobile.SendGump(new GuildmasterGump(m_Mobile, m_Guild)); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/AdvancedSearch.cs b/Scripts/Gumps/Guilds/New Guild System/AdvancedSearch.cs new file mode 100644 index 0000000..12c4785 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/AdvancedSearch.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; + +namespace Server.Guilds +{ + public delegate void SearchSelectionCallback( GuildDisplayType display ); + + public class GuildAdvancedSearchGump : BaseGuildGump + { + private GuildDisplayType m_Display; + private SearchSelectionCallback m_Callback; + + public GuildAdvancedSearchGump( PlayerMobile pm, Guild g, GuildDisplayType display, SearchSelectionCallback callback ) : base( pm, g ) + { + m_Callback = callback; + m_Display = display; + PopulateGump(); + } + + public override void PopulateGump() + { + base.PopulateGump(); + + AddHtmlLocalized( 431, 43, 110, 26, 1062978, 0xF, false, false ); // Diplomacy + + AddHtmlLocalized( 65, 80, 480, 26, 1063124, 0xF, true, false ); // Advanced Search Options + + AddHtmlLocalized( 65, 110, 480, 26, 1063136 + (int)m_Display, 0xF, false, false ); // Showing All Guilds/w/Relation/Waiting Relation + + AddGroup( 1 ); + AddRadio( 75, 140, 0xD2, 0xD3, false, 2 ); + AddHtmlLocalized( 105, 140, 200, 26, 1063006, 0x0, false, false ); // Show Guilds with Relationship + AddRadio( 75, 170, 0xD2, 0xD3, false, 1 ); + AddHtmlLocalized( 105, 170, 200, 26, 1063005, 0x0, false, false ); // Show Guilds Awaiting Action + AddRadio( 75, 200, 0xD2, 0xD3, false, 0 ); + AddHtmlLocalized( 105, 200, 200, 26, 1063007, 0x0, false, false ); // Show All Guilds + + AddBackground( 450, 370, 100, 26, 0x2486 ); + AddButton( 455, 375, 0x845, 0x846, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 480, 373, 60, 26, 1006044, 0x0, false, false ); // OK + AddBackground( 340, 370, 100, 26, 0x2486 ); + AddButton( 345, 375, 0x845, 0x846, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 370, 373, 60, 26, 1006045, 0x0, false, false ); // Cancel + } + + + public override void OnResponse( NetState sender, RelayInfo info ) + { + base.OnResponse( sender, info ); + + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !IsMember( pm, guild ) ) + return; + + GuildDisplayType display = m_Display; + + if( info.ButtonID == 5 ) + { + for( int i = 0; i < 3; i++ ) + { + if( info.IsSwitched( i ) ) + { + display = (GuildDisplayType)i; + m_Callback( display ); + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs b/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs new file mode 100644 index 0000000..35f7952 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/BaseGuildGump.cs @@ -0,0 +1,144 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Factions; +using Server.Misc; + +namespace Server.Guilds +{ + public abstract class BaseGuildGump : Gump + { + private Guild m_Guild; + private PlayerMobile m_Player; + + protected Guild guild{ get{ return m_Guild; } } + protected PlayerMobile player{ get{ return m_Player; } } + + public BaseGuildGump( PlayerMobile pm, Guild g ) : this( pm, g, 10, 10 ) + { + } + + public BaseGuildGump( PlayerMobile pm, Guild g, int x, int y ) : base( x, y ) + { + m_Guild = g; + m_Player = pm; + + pm.CloseGump( typeof( BaseGuildGump ) ); + } + + //There's prolly a way to have all the vars set of inherited classes before something is called in the Ctor... but... I can't think of it right now, and I can't use Timer.DelayCall here :< + + public virtual void PopulateGump() + { + AddPage( 0 ); + + AddBackground( 0, 0, 600, 440, 0x24AE ); + AddBackground( 66, 40, 150, 26, 0x2486 ); + AddButton( 71, 45, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 96, 43, 110, 26, 1063014, 0x0, false, false ); // My Guild + AddBackground( 236, 40, 150, 26, 0x2486 ); + AddButton( 241, 45, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 266, 43, 110, 26, 1062974, 0x0, false, false ); // Guild Roster + AddBackground( 401, 40, 150, 26, 0x2486 ); + AddButton( 406, 45, 0x845, 0x846, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 431, 43, 110, 26, 1062978, 0x0, false, false ); // Diplomacy + AddPage( 1 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( !IsMember( pm, guild ) ) + return; + + switch( info.ButtonID ) + { + case 1: + { + pm.SendGump( new GuildInfoGump( pm, guild ) ); + break; + } + case 2: + { + pm.SendGump( new GuildRosterGump( pm, guild ) ); + break; + } + case 3: + { + pm.SendGump( new GuildDiplomacyGump( pm, guild ) ); + break; + } + } + } + + public static bool IsLeader( Mobile m, Guild g ) + { + return !( m.Deleted || g.Disbanded || !( m is PlayerMobile ) || (m.AccessLevel < AccessLevel.GameMaster && g.Leader != m) ); + } + + public static bool IsMember( Mobile m, Guild g ) + { + return !( m.Deleted || g.Disbanded || !( m is PlayerMobile ) || (m.AccessLevel < AccessLevel.GameMaster && !g.IsMember( m )) ); + } + + public static bool CheckProfanity( string s ) + { + return CheckProfanity( s, 50 ); + } + public static bool CheckProfanity( string s, int maxLength ) + { + //return NameVerification.Validate( s, 1, 50, true, true, false, int.MaxValue, ProfanityProtection.Exceptions, ProfanityProtection.Disallowed, ProfanityProtection.StartDisallowed ); //What am I doing wrong, this still allows chars like the <3 symbol... 3 AM. someone change this to use this + + //With testing on OSI, Guild stuff seems to follow a 'simpler' method of profanity protection + if( s.Length < 1 || s.Length > maxLength ) + return false; + + char[] exceptions = ProfanityProtection.Exceptions; + + s = s.ToLower(); + + for ( int i = 0; i < s.Length; ++i ) + { + char c = s[i]; + + if ( (c < 'a' || c > 'z') && (c < '0' || c > '9')) + { + bool except = false; + + for( int j = 0; !except && j < exceptions.Length; j++ ) + if( c == exceptions[j] ) + except = true; + + if( !except ) + return false; + } + } + + string[] disallowed = ProfanityProtection.Disallowed; + + for( int i = 0; i < disallowed.Length; i++ ) + { + if ( s.IndexOf( disallowed[i] ) != -1 ) + return false; + } + + return true; + } + + public void AddHtmlText( int x, int y, int width, int height, TextDefinition text, bool back, bool scroll ) + { + if ( text != null && text.Number > 0 ) + AddHtmlLocalized( x, y, width, height, text.Number, back, scroll ); + else if ( text != null && text.String != null ) + AddHtml( x, y, width, height, text.String, back, scroll ); + } + + public static string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/BaseGuildListGump.cs b/Scripts/Gumps/Guilds/New Guild System/BaseGuildListGump.cs new file mode 100644 index 0000000..58e2d6a --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/BaseGuildListGump.cs @@ -0,0 +1,209 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Guilds +{ + public abstract class BaseGuildListGump : BaseGuildGump + { + List m_List; + IComparer m_Comparer; + InfoField[] m_Fields; + bool m_Ascending; + string m_Filter; + int m_StartNumber; + + private const int itemsPerPage = 8; + + public BaseGuildListGump( PlayerMobile pm, Guild g, List list, IComparer currentComparer, bool ascending, string filter, int startNumber, InfoField[] fields ) + : base( pm, g ) + { + m_Filter = filter.Trim(); + + m_Comparer = currentComparer; + m_Fields = fields; + m_Ascending = ascending; + m_StartNumber = startNumber; + m_List = list; + } + + public virtual bool WillFilter{ get{ return (m_Filter.Length >= 0); } } + + public override void PopulateGump() + { + base.PopulateGump(); + + List list = m_List; + if( WillFilter ) + { + m_List = new List(); + for( int i = 0; i < list.Count; i++ ) + { + if( !IsFiltered( list[i], m_Filter ) ) + m_List.Add( list[i] ); + } + } + else + { + m_List = new List( list ); + } + + m_List.Sort( m_Comparer ); + m_StartNumber = Math.Max( Math.Min( m_StartNumber, m_List.Count - 1 ), 0 ); + + + + AddBackground( 130, 75, 385, 30, 0xBB8 ); + AddTextEntry( 135, 80, 375, 30, 0x481, 1, m_Filter ); + AddButton( 520, 75, 0x867, 0x868, 5, GumpButtonType.Reply, 0 ); //Filter Button + + int width = 0; + for( int i = 0; i < m_Fields.Length; i++ ) + { + InfoField f = m_Fields[i]; + + AddImageTiled( 65 + width, 110, f.Width + 10, 26, 0xA40 ); + AddImageTiled( 67 + width, 112, f.Width + 6, 22, 0xBBC ); + AddHtmlText( 70 + width, 113, f.Width, 20, f.Name, false, false ); + + bool isComparer = ( m_Fields[i].Comparer.GetType() == m_Comparer.GetType() ); + + int ButtonID = ( isComparer ) ? ( m_Ascending ? 0x983 : 0x985 ) : 0x2716; + + AddButton( 59 + width + f.Width, 117, ButtonID, ButtonID + (isComparer ? 1 : 0) , 100 + i, GumpButtonType.Reply, 0 ); + + width += (f.Width + 12); + } + + if( m_StartNumber <= 0 ) + AddButton( 65, 80, 0x15E3, 0x15E7, 0, GumpButtonType.Page, 0 ); + else + AddButton( 65, 80, 0x15E3, 0x15E7, 6, GumpButtonType.Reply, 0 ); // Back + + if( m_StartNumber + itemsPerPage > m_List.Count ) + AddButton( 95, 80, 0x15E1, 0x15E5, 0, GumpButtonType.Page, 0 ); + else + AddButton( 95, 80, 0x15E1, 0x15E5, 7, GumpButtonType.Reply, 0 ); // Forward + + + + int itemNumber = 0; + + if( m_Ascending ) + for( int i = m_StartNumber; i < m_StartNumber + itemsPerPage && i < m_List.Count; i++ ) + DrawEntry( m_List[i], i, itemNumber++ ); + else //descending, go from bottom of list to the top + for( int i = m_List.Count - 1 - m_StartNumber; i >= 0 && i >= (m_List.Count - itemsPerPage - m_StartNumber); i-- ) + DrawEntry( m_List[i], i, itemNumber++ ); + + DrawEndingEntry( itemNumber ); + } + + public virtual void DrawEndingEntry( int itemNumber ) + { + } + + public virtual bool HasRelationship( T o ) + { + return false; + } + + public virtual void DrawEntry( T o, int index, int itemNumber ) + { + int width = 0; + for( int j = 0; j < m_Fields.Length; j++ ) + { + InfoField f = m_Fields[j]; + + AddImageTiled( 65 + width, 138 + itemNumber * 28, f.Width + 10, 26, 0xA40 ); + AddImageTiled( 67 + width, 140 + itemNumber * 28, f.Width + 6, 22, 0xBBC ); + AddHtmlText( 70 + width, 141 + itemNumber * 28, f.Width, 20, GetValuesFor( o, m_Fields.Length )[j], false, false ); + + width += (f.Width + 12); + } + + if( HasRelationship( o ) ) + AddButton( 40, 143 + itemNumber * 28, 0x8AF, 0x8AF, 200 + index, GumpButtonType.Reply, 0 ); //Info Button + else + AddButton( 40, 143 + itemNumber * 28, 0x4B9, 0x4BA, 200 + index, GumpButtonType.Reply, 0 ); //Info Button + } + + protected abstract TextDefinition[] GetValuesFor( T o, int aryLength ); + protected abstract bool IsFiltered( T o, string filter ); + + public override void OnResponse( NetState sender, RelayInfo info ) + { + base.OnResponse( sender, info ); + + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !IsMember( pm, guild ) ) + return; + + int id = info.ButtonID; + + switch( id ) + { + case 5: //Filter + { + TextRelay t = info.GetTextEntry( 1 ); + pm.SendGump( GetResentGump( player, guild, m_Comparer, m_Ascending, ( t == null ) ? "" : t.Text, 0 ) ); + break; + } + case 6: //Back + { + pm.SendGump( GetResentGump( player, guild, m_Comparer, m_Ascending, m_Filter, m_StartNumber - itemsPerPage ) ); + break; + } + case 7: //Forward + { + pm.SendGump( GetResentGump( player, guild, m_Comparer, m_Ascending, m_Filter, m_StartNumber + itemsPerPage ) ); + break; + } + } + + if( id >= 100 && id < (100 + m_Fields.Length) ) + { + IComparer comparer = m_Fields[id-100].Comparer; + + if( m_Comparer.GetType() == comparer.GetType() ) + m_Ascending = !m_Ascending; + + pm.SendGump( GetResentGump( player, guild, comparer, m_Ascending, m_Filter, 0 ) ); + } + else if( id >= 200 && id < ( 200 + m_List.Count ) ) + { + pm.SendGump( GetObjectInfoGump( player, guild, m_List[id - 200] ) ); + } + } + + + public abstract Gump GetResentGump( PlayerMobile pm, Guild g, IComparer comparer, bool ascending, string filter, int startNumber ); + public abstract Gump GetObjectInfoGump( PlayerMobile pm, Guild g, T o ); + + public void ResendGump() + { + player.SendGump( GetResentGump( player, guild, m_Comparer, m_Ascending, m_Filter, m_StartNumber ) ); + } + } + public struct InfoField + { + private TextDefinition m_Name; + private int m_Width; + private IComparer m_Comparer; + + public TextDefinition Name{ get{ return m_Name; } } + public int Width{ get{ return m_Width; } } + public IComparer Comparer { get { return m_Comparer; } } + public InfoField( TextDefinition name, int width, IComparer comparer ) + { + m_Name = name; + m_Width = width; + m_Comparer = comparer; + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/Create Guild Gump.cs b/Scripts/Gumps/Guilds/New Guild System/Create Guild Gump.cs new file mode 100644 index 0000000..33e5b93 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/Create Guild Gump.cs @@ -0,0 +1,101 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; + +namespace Server.Guilds +{ + public class CreateGuildGump : Gump + { + public CreateGuildGump( PlayerMobile pm ) : this( pm, "Guild Name", "" ) + { + } + + public CreateGuildGump( PlayerMobile pm, string guildName, string guildAbbrev ) : base( 10, 10 ) + { + pm.CloseGump( typeof( CreateGuildGump ) ); + pm.CloseGump( typeof( BaseGuildGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 500, 300, 0x2422 ); + AddHtmlLocalized( 25, 20, 450, 25, 1062939, 0x0, true, false ); //
GUILD MENU
+ AddHtmlLocalized( 25, 60, 450, 60, 1062940, 0x0, false, false ); // As you are not a member of any guild, you can create your own by providing a unique guild name and paying the standard guild registration fee. + AddHtmlLocalized( 25, 135, 120, 25, 1062941, 0x0, false, false ); // Registration Fee: + AddLabel( 155, 135, 0x481, Guild.RegistrationFee.ToString() ); + AddHtmlLocalized( 25, 165, 120, 25, 1011140, 0x0, false, false ); // Enter Guild Name: + AddBackground( 155, 160, 320, 26, 0xBB8 ); + AddTextEntry( 160, 163, 315, 21, 0x481, 5, guildName ); + AddHtmlLocalized( 25, 191, 120, 26, 1063035, 0x0, false, false ); // Abbreviation: + AddBackground( 155, 186, 320, 26, 0xBB8 ); + AddTextEntry( 160, 189, 315, 21, 0x481, 6, guildAbbrev ); + AddButton( 415, 217, 0xF7, 0xF8, 1, GumpButtonType.Reply, 0 ); + AddButton( 345, 217, 0xF2, 0xF1, 0, GumpButtonType.Reply, 0 ); + + if( pm.AcceptGuildInvites ) + AddButton( 20, 260, 0xD2, 0xD3, 2, GumpButtonType.Reply, 0 ); + else + AddButton( 20, 260, 0xD3, 0xD2, 2, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 45, 260, 200, 30, 1062943, 0x0, false, false ); // Ignore Guild Invites + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || pm.Guild != null ) + return; //Sanity + + switch( info.ButtonID ) + { + case 1: + { + TextRelay tName = info.GetTextEntry( 5 ); + TextRelay tAbbrev = info.GetTextEntry( 6 ); + + string guildName = (tName == null) ? "" : tName.Text; + string guildAbbrev = (tAbbrev == null) ? "" : tAbbrev.Text; + + guildName = Utility.FixHtml( guildName.Trim() ); + guildAbbrev = Utility.FixHtml( guildAbbrev.Trim() ); + + if( guildName.Length <= 0 ) + pm.SendLocalizedMessage( 1070884 ); // Guild name cannot be blank. + else if( guildAbbrev.Length <= 0 ) + pm.SendLocalizedMessage( 1070885 ); // You must provide a guild abbreviation. + else if( guildName.Length > Guild.NameLimit ) + pm.SendLocalizedMessage( 1063036, Guild.NameLimit.ToString() ); // A guild name cannot be more than ~1_val~ characters in length. + else if( guildAbbrev.Length > Guild.AbbrevLimit ) + pm.SendLocalizedMessage( 1063037, Guild.AbbrevLimit.ToString() ); // An abbreviation cannot exceed ~1_val~ characters in length. + else if( Guild.FindByAbbrev( guildAbbrev ) != null || !BaseGuildGump.CheckProfanity( guildAbbrev ) ) + pm.SendLocalizedMessage( 501153 ); // That abbreviation is not available. + else if( Guild.FindByName( guildName ) != null || !BaseGuildGump.CheckProfanity( guildName ) ) + pm.SendLocalizedMessage( 1063000 ); // That guild name is not available. + else if( !Banker.Withdraw( pm, Guild.RegistrationFee ) ) + pm.SendLocalizedMessage( 1063001, Guild.RegistrationFee.ToString() ); // You do not possess the ~1_val~ gold piece fee required to create a guild. + else + { + pm.SendLocalizedMessage( 1060398, Guild.RegistrationFee.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + pm.SendLocalizedMessage( 1063238 ); // Your new guild has been founded. + pm.Guild = new Guild( pm, guildName, guildAbbrev ); + } + + break; + } + case 2: + { + pm.AcceptGuildInvites = !pm.AcceptGuildInvites; + + if( pm.AcceptGuildInvites ) + pm.SendLocalizedMessage( 1070699 ); // You are now accepting guild invitations. + else + pm.SendLocalizedMessage( 1070698 ); // You are now ignoring guild invitations. + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/DiplomacyGump.cs b/Scripts/Gumps/Guilds/New Guild System/DiplomacyGump.cs new file mode 100644 index 0000000..420f2ba --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/DiplomacyGump.cs @@ -0,0 +1,291 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Guilds +{ + public enum GuildDisplayType + { + All, + AwaitingAction, + Relations + } + + public class GuildDiplomacyGump : BaseGuildListGump + { + protected virtual bool AllowAdvancedSearch{ get{ return true; } } + #region Comparers + private class NameComparer : IComparer + { + public static readonly IComparer Instance = new NameComparer(); + + public NameComparer() + { + } + + public int Compare( Guild x, Guild y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + return Insensitive.Compare( x.Name, y.Name ); + } + } + + private class StatusComparer : IComparer + { + private enum GuildCompareStatus + { + Peace, + Ally, + War + } + private Guild m_Guild; + public StatusComparer( Guild g ) + { + m_Guild = g; + } + + public int Compare( Guild x, Guild y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + GuildCompareStatus aStatus = GuildCompareStatus.Peace; + GuildCompareStatus bStatus = GuildCompareStatus.Peace; + + if( m_Guild.IsAlly( x ) ) + aStatus = GuildCompareStatus.Ally; + else if( m_Guild.IsWar( x ) ) + aStatus = GuildCompareStatus.War; + + + if( m_Guild.IsAlly( y ) ) + bStatus = GuildCompareStatus.Ally; + else if( m_Guild.IsWar( y ) ) + bStatus = GuildCompareStatus.War; + + return ((int)aStatus).CompareTo( (int)bStatus ); + } + } + private class AbbrevComparer : IComparer + { + public static readonly IComparer Instance = new AbbrevComparer(); + + public AbbrevComparer() + { + } + + public int Compare( Guild x, Guild y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + return Insensitive.Compare( x.Abbreviation, y.Abbreviation ); + } + } + + #endregion + + GuildDisplayType m_Display; + TextDefinition m_LowerText; + + public GuildDiplomacyGump( PlayerMobile pm, Guild g ) + : this( pm, g, GuildDiplomacyGump.NameComparer.Instance, true, "", 0, GuildDisplayType.All, Utility.CastConvertList( new List( Guild.List.Values ) ), (1063136 + (int)GuildDisplayType.All) ) + { + } + + public GuildDiplomacyGump( PlayerMobile pm, Guild g, IComparer currentComparer, bool ascending, string filter, int startNumber, GuildDisplayType display ) + : this( pm, g, currentComparer, ascending, filter, startNumber, display, Utility.CastConvertList( new List( Guild.List.Values ) ), (1063136 + (int)display) ) + { + } + + public GuildDiplomacyGump( PlayerMobile pm, Guild g, IComparer currentComparer, bool ascending, string filter, int startNumber, List list, TextDefinition lowerText ) + : this( pm, g, currentComparer, ascending, filter, startNumber, GuildDisplayType.All, list, lowerText ) + { + } + + public GuildDiplomacyGump( PlayerMobile pm, Guild g, bool ascending, string filter, int startNumber, List list, TextDefinition lowerText ) + : this( pm, g, GuildDiplomacyGump.NameComparer.Instance, ascending, filter, startNumber, GuildDisplayType.All, list, lowerText ) + { + } + + public GuildDiplomacyGump( PlayerMobile pm, Guild g, IComparer currentComparer, bool ascending, string filter, int startNumber, GuildDisplayType display, List list, TextDefinition lowerText ) + : base( pm, g, list, currentComparer, ascending, filter, startNumber, + new InfoField[] + { + new InfoField( 1062954, 280, GuildDiplomacyGump.NameComparer.Instance ), //Guild Name + new InfoField( 1062957, 50, GuildDiplomacyGump.AbbrevComparer.Instance ), //Abbrev + new InfoField( 1062958, 120, new GuildDiplomacyGump.StatusComparer( g ) ) //Guild Title + }) + { + + m_Display = display; + m_LowerText = lowerText; + PopulateGump(); + } + + public override void PopulateGump() + { + base.PopulateGump(); + + AddHtmlLocalized( 431, 43, 110, 26, 1062978, 0xF, false, false ); // Diplomacy + } + + protected override TextDefinition[] GetValuesFor( Guild g, int aryLength ) + { + TextDefinition[] defs = new TextDefinition[aryLength]; + + defs[0] = ( g == guild ) ? Color( g.Name, 0x006600 ) : g.Name; + defs[1] = g.Abbreviation; + + defs[2] = 3000085; //Peace + + + if( guild.IsAlly( g ) ) + { + if( guild.Alliance.Leader == g ) + defs[2] = 1063237; // Alliance Leader + else + defs[2] = 1062964; // Ally + } + else if( guild.IsWar( g ) ) + { + defs[2] = 3000086; // War + } + + return defs; + } + + public override bool HasRelationship( Guild g ) + { + if( g == guild ) + return false; + + if( guild.FindPendingWar( g ) != null ) + return true; + + AllianceInfo alliance = guild.Alliance; + + if( alliance != null ) + { + Guild leader = alliance.Leader; + + if ( leader != null ) + { + if ( guild == leader && alliance.IsPendingMember( g ) || g == leader && alliance.IsPendingMember( guild ) ) + return true; + } + else if ( alliance.IsPendingMember( g ) ) + return true; + } + + return false; + } + + public override void DrawEndingEntry( int itemNumber ) + { + //AddHtmlLocalized( 66, 153 + itemNumber * 28, 280, 26, 1063136 + (int)m_Display, 0xF, false, false ); // Showing All Guilds/Awaiting Action/ w/Relation Ship + //AddHtmlText( 66, 153 + itemNumber * 28, 280, 26, m_LowerText, false, false ); + + if ( m_LowerText != null && m_LowerText.Number > 0 ) + AddHtmlLocalized( 66, 153 + itemNumber * 28, 280, 26, m_LowerText.Number, 0xF, false, false ); + else if ( m_LowerText != null && m_LowerText.String != null ) + AddHtml( 66, 153 + itemNumber * 28, 280, 26, Color( m_LowerText.String, 0x99 ), false, false ); + + if( AllowAdvancedSearch ) + { + AddBackground( 350, 148 + itemNumber * 28, 200, 26, 0x2486 ); + AddButton( 355, 153 + itemNumber * 28, 0x845, 0x846, 8, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 380, 151 + itemNumber * 28, 160, 26, 1063083, 0x0, false, false ); // Advanced Search + } + } + + + protected override bool IsFiltered( Guild g, string filter ) + { + if( g == null ) + return true; + + switch( m_Display ) + { + case GuildDisplayType.Relations: + { + //if( !( guild.IsWar( g ) || guild.IsAlly( g ) ) ) + + if( !( guild.FindActiveWar( g ) != null || guild.IsAlly( g ) ) ) //As per OSI, only the guild leader wars show up under the sorting by relation + return true; + + return false; + } + case GuildDisplayType.AwaitingAction: + { + return !HasRelationship( g ); + } + } + + return !( Insensitive.Contains( g.Name, filter ) || Insensitive.Contains( g.Abbreviation, filter ) ); + } + + public override bool WillFilter + { + get + { + if( m_Display == GuildDisplayType.All ) + return base.WillFilter; + + return true; + } + } + + + public override Gump GetResentGump( PlayerMobile pm, Guild g, IComparer comparer, bool ascending, string filter, int startNumber ) + { + return new GuildDiplomacyGump( pm, g, comparer, ascending, filter, startNumber, m_Display ); + } + + public override Gump GetObjectInfoGump( PlayerMobile pm, Guild g, Guild o ) + { + if( guild == o ) + return new GuildInfoGump( pm, g ); + + return new OtherGuildInfo( pm, g, (Guild)o ) ; + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + base.OnResponse( sender, info ); + + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !IsMember( pm, guild ) ) + return; + + if( AllowAdvancedSearch && info.ButtonID == 8 ) + pm.SendGump( new GuildAdvancedSearchGump( pm, guild, m_Display, new SearchSelectionCallback( AdvancedSearch_Callback ) )); + + } + + public void AdvancedSearch_Callback( GuildDisplayType display ) + { + m_Display = display; + ResendGump(); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/GuildInfoGump.cs b/Scripts/Gumps/Guilds/New Guild System/GuildInfoGump.cs new file mode 100644 index 0000000..05fd88e --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/GuildInfoGump.cs @@ -0,0 +1,194 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Factions; +using Server.Prompts; + +namespace Server.Guilds +{ + public class GuildInfoGump : BaseGuildGump + { + private bool m_IsResigning; + + public GuildInfoGump(PlayerMobile pm, Guild g) + : this(pm, g, false) + { + } + public GuildInfoGump(PlayerMobile pm, Guild g, bool isResigning) + : base(pm, g) + { + m_IsResigning = isResigning; + PopulateGump(); + } + + public override void PopulateGump() + { + bool isLeader = IsLeader(player, guild); + base.PopulateGump(); + + AddHtmlLocalized(96, 43, 110, 26, 1063014, 0xF, false, false); // My Guild + + AddImageTiled(65, 80, 160, 26, 0xA40); + AddImageTiled(67, 82, 156, 22, 0xBBC); + AddHtmlLocalized(70, 83, 150, 20, 1062954, 0x0, false, false); // Guild Name + AddHtml(233, 84, 320, 26, guild.Name, false, false); + + AddImageTiled(65, 114, 160, 26, 0xA40); + AddImageTiled(67, 116, 156, 22, 0xBBC); + AddHtmlLocalized(70, 117, 150, 20, 1063025, 0x0, false, false); // Alliance + + if (guild.Alliance != null && guild.Alliance.IsMember(guild)) + { + AddHtml(233, 118, 320, 26, guild.Alliance.Name, false, false); + AddButton(40, 120, 0x4B9, 0x4BA, 6, GumpButtonType.Reply, 0); //Alliance Roster + } + + if (Guild.OrderChaos && isLeader) + AddButton(40, 154, 0x4B9, 0x4BA, 100, GumpButtonType.Reply, 0); // Guild Faction + + AddImageTiled(65, 148, 160, 26, 0xA40); + AddImageTiled(67, 150, 156, 22, 0xBBC); + AddHtmlLocalized(70, 151, 150, 20, 1063084, 0x0, false, false); // Guild Faction + + GuildType gt; + Faction f; + + if ((gt = guild.Type) != GuildType.Regular) + AddHtml(233, 152, 320, 26, gt.ToString(), false, false); + else if ((f = Faction.Find(guild.Leader)) != null) + AddHtml(233, 152, 320, 26, f.ToString(), false, false); + + AddImageTiled(65, 196, 480, 4, 0x238D); + + + string s = guild.Charter; + if (String.IsNullOrEmpty(s)) + s = "The guild leader has not yet set the guild charter."; + + AddHtml(65, 216, 480, 80, s, true, true); + if (isLeader) + AddButton(40, 251, 0x4B9, 0x4BA, 4, GumpButtonType.Reply, 0); //Charter Edit button + + s = guild.Website; + if (string.IsNullOrEmpty(s)) + s = "Guild website not yet set."; + AddHtml(65, 306, 480, 30, s, true, false); + if (isLeader) + AddButton(40, 313, 0x4B9, 0x4BA, 5, GumpButtonType.Reply, 0); //Website Edit button + + AddCheck(65, 370, 0xD2, 0xD3, player.DisplayGuildTitle, 0); + AddHtmlLocalized(95, 370, 150, 26, 1063085, 0x0, false, false); // Show Guild Title + AddBackground(450, 370, 100, 26, 0x2486); + + AddButton(455, 375, 0x845, 0x846, 7, GumpButtonType.Reply, 0); + AddHtmlLocalized(480, 373, 60, 26, 3006115, (m_IsResigning) ? 0x5000 : 0, false, false); // Resign + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + base.OnResponse(sender, info); + + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if (!IsMember(pm, guild)) + return; + + + pm.DisplayGuildTitle = info.IsSwitched(0); + + switch (info.ButtonID) + { + //1-3 handled by base.OnResponse + case 4: + { + if (IsLeader(pm, guild)) + { + pm.SendLocalizedMessage(1013071); // Enter the new guild charter (50 characters max): + + pm.BeginPrompt(new PromptCallback(SetCharter_Callback), true); //Have the same callback handle both canceling and deletion cause the 2nd callback would just get a text of "" + } + break; + } + case 5: + { + if (IsLeader(pm, guild)) + { + pm.SendLocalizedMessage(1013072); // Enter the new website for the guild (50 characters max): + pm.BeginPrompt(new PromptCallback(SetWebsite_Callback), true); //Have the same callback handle both canceling and deletion cause the 2nd callback would just get a text of "" + } + break; + } + case 6: + { + //Alliance Roster + if (guild.Alliance != null && guild.Alliance.IsMember(guild)) + pm.SendGump(new AllianceInfo.AllianceRosterGump(pm, guild, guild.Alliance)); + + break; + } + case 7: + { + //Resign + if (!m_IsResigning) + { + pm.SendLocalizedMessage(1063332); // Are you sure you wish to resign from your guild? + pm.SendGump(new GuildInfoGump(pm, guild, true)); + } + else + { + guild.RemoveMember(pm, 1063411); // You resign from your guild. + } + break; + } + case 100: // Custom code to support Order/Chaos in the new guild system + { + // Guild Faction + if (Guild.OrderChaos && IsLeader(pm, guild)) + { + pm.CloseGump(typeof(GuildChangeTypeGump)); + pm.SendGump(new GuildChangeTypeGump(pm, guild)); + } + break; + } + } + } + + public void SetCharter_Callback(Mobile from, string text) + { + if (!IsLeader(from, guild)) + return; + + string charter = Utility.FixHtml(text.Trim()); + + if (charter.Length > 50) + { + from.SendLocalizedMessage(1070774, "50"); // Your guild charter cannot exceed ~1_val~ characters. + } + else + { + guild.Charter = charter; + from.SendLocalizedMessage(1070775); // You submit a new guild charter. + return; + } + } + + public void SetWebsite_Callback(Mobile from, string text) + { + if (!IsLeader(from, guild)) + return; + + string site = Utility.FixHtml(text.Trim()); + + if (site.Length > 50) + from.SendLocalizedMessage(1070777, "50"); // Your guild website cannot exceed ~1_val~ characters. + else + { + guild.Website = site; + from.SendLocalizedMessage(1070778); // You submit a new guild website. + return; + } + } + } +} diff --git a/Scripts/Gumps/Guilds/New Guild System/GuildInvitationRequest.cs b/Scripts/Gumps/Guilds/New Guild System/GuildInvitationRequest.cs new file mode 100644 index 0000000..ee1d3c9 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/GuildInvitationRequest.cs @@ -0,0 +1,63 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; + +namespace Server.Guilds +{ + public class GuildInvitationRequest : BaseGuildGump + { + PlayerMobile m_Inviter; + public GuildInvitationRequest( PlayerMobile pm, Guild g, PlayerMobile inviter ) : base( pm, g ) + { + m_Inviter = inviter; + + PopulateGump(); + } + + public override void PopulateGump() + { + AddPage( 0 ); + + AddBackground( 0, 0, 350, 170, 0x2422 ); + AddHtmlLocalized( 25, 20, 300, 45, 1062946, 0x0, true, false ); //
You have been invited to join a guild! (Warning: Accepting will make you attackable!)
+ AddHtml( 25, 75, 300, 25, String.Format( "
{0}
", guild.Name ), true, false ); + AddButton( 265, 130, 0xF7, 0xF8, 1, GumpButtonType.Reply, 0 ); + AddButton( 195, 130, 0xF2, 0xF1, 0, GumpButtonType.Reply, 0 ); + AddButton( 20, 130, 0xD2, 0xD3, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 130, 150, 30, 1062943, 0x0, false, false ); // Ignore Guild Invites + } + + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if( guild.Disbanded || player.Guild != null ) + return; + + switch( info.ButtonID ) + { + case 0: + { + m_Inviter.SendLocalizedMessage( 1063250, String.Format( "{0}\t{1}", player.Name, guild.Name ) ); // ~1_val~ has declined your invitation to join ~2_val~. + break; + } + case 1: + { + guild.AddMember( player ); + player.SendLocalizedMessage( 1063056, guild.Name ); // You have joined ~1_val~. + m_Inviter.SendLocalizedMessage( 1063249, String.Format( "{0}\t{1}", player.Name, guild.Name ) ); // ~1_val~ has accepted your invitation to join ~2_val~. + + break; + } + case 2: + { + player.AcceptGuildInvites = false; + player.SendLocalizedMessage( 1070698 ); // You are now ignoring guild invitations. + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs b/Scripts/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs new file mode 100644 index 0000000..8b1f5d8 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs @@ -0,0 +1,231 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Prompts; + +namespace Server.Guilds +{ + public class GuildMemberInfoGump : BaseGuildGump + { + PlayerMobile m_Member; + bool m_ToLeader, m_toKick; + + public GuildMemberInfoGump( PlayerMobile pm, Guild g, PlayerMobile member, bool toKick, bool toPromoteToLeader ) : base( pm, g, 10, 40 ) + { + m_ToLeader = toPromoteToLeader; + m_toKick = toKick; + m_Member = member; + PopulateGump(); + } + + public override void PopulateGump() + { + AddPage( 0 ); + + AddBackground( 0, 0, 350, 255, 0x242C ); + AddHtmlLocalized( 20, 15, 310, 26, 1063018, 0x0, false, false ); //
Guild Member Information
+ AddImageTiled( 20, 40, 310, 2, 0x2711 ); + + AddHtmlLocalized( 20, 50, 150, 26, 1062955, 0x0, true, false ); // Name + AddHtml( 180, 53, 150, 26, m_Member.Name, false, false ); + + AddHtmlLocalized( 20, 80, 150, 26, 1062956, 0x0, true, false ); // Rank + AddHtmlLocalized( 180, 83, 150, 26, m_Member.GuildRank.Name, 0x0, false, false ); + + AddHtmlLocalized( 20, 110, 150, 26, 1062953, 0x0, true, false ); // Guild Title + AddHtml( 180, 113, 150, 26, m_Member.GuildTitle, false, false ); + AddImageTiled( 20, 142, 310, 2, 0x2711 ); + + AddBackground( 20, 150, 310, 26, 0x2486 ); + AddButton( 25, 155, 0x845, 0x846, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 153, 270, 26, (m_Member == player.GuildFealty && guild.Leader != m_Member) ? 1063082 : 1062996, 0x0, false, false ); // Clear/Cast Vote For This Member + + AddBackground( 20, 180, 150, 26, 0x2486 ); + AddButton( 25, 185, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 183, 110, 26, 1062993, (m_ToLeader)? 0x990000 : 0, false, false ); // Promote + + AddBackground( 180, 180, 150, 26, 0x2486 ); + AddButton( 185, 185, 0x845, 0x846, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 210, 183, 110, 26, 1062995, 0x0, false, false ); // Set Guild Title + + AddBackground( 20, 210, 150, 26, 0x2486 ); + AddButton( 25, 215, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 213, 110, 26, 1062994, 0x0, false, false ); // Demote + + AddBackground( 180, 210, 150, 26, 0x2486 ); + AddButton( 185, 215, 0x845, 0x846, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 210, 213, 110, 26, 1062997, (m_toKick)? 0x5000 : 0, false, false ); // Kick + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !IsMember( pm, guild ) || !IsMember( m_Member, guild ) ) + return; + + RankDefinition playerRank = pm.GuildRank; + RankDefinition targetRank = m_Member.GuildRank; + + switch( info.ButtonID ) + { + case 1: //Promote + { + if( playerRank.GetFlag( RankFlags.CanPromoteDemote ) && ((playerRank.Rank -1 ) > targetRank.Rank || ( playerRank == RankDefinition.Leader && playerRank.Rank > targetRank.Rank )) ) + { + targetRank = RankDefinition.Ranks[targetRank.Rank + 1]; + + if( targetRank == RankDefinition.Leader ) + { + if( m_ToLeader ) + { + m_Member.GuildRank = targetRank; + pm.SendLocalizedMessage( 1063156, m_Member.Name ); // The guild information for ~1_val~ has been updated. + pm.SendLocalizedMessage( 1063156, pm.Name ); // The guild information for ~1_val~ has been updated. + guild.Leader = m_Member; + } + else + { + pm.SendLocalizedMessage( 1063144 ); // Are you sure you wish to make this member the new guild leader? + pm.SendGump( new GuildMemberInfoGump( player, guild, m_Member, false, true ) ); + } + } + else + { + m_Member.GuildRank = targetRank; + pm.SendLocalizedMessage( 1063156, m_Member.Name ); // The guild information for ~1_val~ has been updated. + } + } + else + pm.SendLocalizedMessage( 1063143 ); // You don't have permission to promote this member. + + break; + } + case 2: //Demote + { + if( playerRank.GetFlag( RankFlags.CanPromoteDemote ) && playerRank.Rank > targetRank.Rank ) + { + if( targetRank == RankDefinition.Lowest ) + { + if( RankDefinition.Lowest.Name.Number == 1062963 ) + pm.SendLocalizedMessage( 1063333 ); // You can't demote a ronin. + else + pm.SendMessage( "You can't demote a {0}.", RankDefinition.Lowest.Name ); + } + else + { + m_Member.GuildRank = RankDefinition.Ranks[targetRank.Rank - 1]; + pm.SendLocalizedMessage( 1063156, m_Member.Name ); // The guild information for ~1_val~ has been updated. + } + } + else + pm.SendLocalizedMessage( 1063146 ); // You don't have permission to demote this member. + + + break; + } + case 3: //Set Guild title + { + if( playerRank.GetFlag( RankFlags.CanSetGuildTitle ) && ( playerRank.Rank > targetRank.Rank || m_Member == player)) + { + pm.SendLocalizedMessage( 1011128 ); // Enter the new title for this guild member or 'none' to remove a title: + + pm.BeginPrompt( new PromptCallback( SetTitle_Callback ) ); + } + else if( m_Member.GuildTitle == null || m_Member.GuildTitle.Length <= 0 ) + { + pm.SendLocalizedMessage( 1070746 ); // You don't have the permission to set that member's guild title. + } + else + { + pm.SendLocalizedMessage( 1063148 ); // You don't have permission to change this member's guild title. + } + + break; + } + case 4: //Vote + { + if( m_Member == pm.GuildFealty && guild.Leader != m_Member ) + pm.SendLocalizedMessage( 1063158 ); // You have cleared your vote for guild leader. + else if( guild.CanVote( m_Member ) )//( playerRank.GetFlag( RankFlags.CanVote ) ) + { + if( m_Member == guild.Leader ) + pm.SendLocalizedMessage( 1063424 ); // You can't vote for the current guild leader. + else if( !guild.CanBeVotedFor( m_Member ) ) + pm.SendLocalizedMessage( 1063425 ); // You can't vote for an inactive guild member. + else + { + pm.GuildFealty = m_Member; + pm.SendLocalizedMessage( 1063159, m_Member.Name ); // You cast your vote for ~1_val~ for guild leader. + } + } + else + pm.SendLocalizedMessage( 1063149 ); // You don't have permission to vote. + + break; + } + case 5: //Kick + { + if( ( playerRank.GetFlag( RankFlags.RemovePlayers ) && playerRank.Rank > targetRank.Rank ) || ( playerRank.GetFlag( RankFlags.RemoveLowestRank ) && targetRank == RankDefinition.Lowest ) ) + { + if( m_toKick ) + { + guild.RemoveMember( m_Member ); + pm.SendLocalizedMessage( 1063157 ); // The member has been removed from your guild. + } + else + { + pm.SendLocalizedMessage( 1063152 ); // Are you sure you wish to kick this member from the guild? + pm.SendGump( new GuildMemberInfoGump( player, guild, m_Member, true, false ) ); + } + } + else + pm.SendLocalizedMessage( 1063151 ); // You don't have permission to remove this member. + + break; + } + } + } + + public void SetTitle_Callback( Mobile from, string text ) + { + PlayerMobile pm = from as PlayerMobile; + PlayerMobile targ = m_Member; + + if( pm == null || targ == null ) + return; + + Guild g = targ.Guild as Guild; + + if( g == null || !IsMember( pm, g ) || !(pm.GuildRank.GetFlag( RankFlags.CanSetGuildTitle ) && (pm.GuildRank.Rank > targ.GuildRank.Rank || pm == targ)) ) + { + if( m_Member.GuildTitle == null || m_Member.GuildTitle.Length <= 0 ) + pm.SendLocalizedMessage( 1070746 ); // You don't have the permission to set that member's guild title. + else + pm.SendLocalizedMessage( 1063148 ); // You don't have permission to change this member's guild title. + + return; + } + + + string title = Utility.FixHtml( text.Trim() ); + + if( title.Length > 20 ) + from.SendLocalizedMessage( 501178 ); // That title is too long. + else if( !BaseGuildGump.CheckProfanity( title ) ) + from.SendLocalizedMessage( 501179 ); // That title is disallowed. + else + { + if( Insensitive.Equals( title, "none" ) ) + targ.GuildTitle = null; + else + targ.GuildTitle = title; + + pm.SendLocalizedMessage( 1063156, targ.Name ); // The guild information for ~1_val~ has been updated. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/GuildRosterGump.cs b/Scripts/Gumps/Guilds/New Guild System/GuildRosterGump.cs new file mode 100644 index 0000000..d24f4c4 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/GuildRosterGump.cs @@ -0,0 +1,266 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Targets; +using Server.Factions; +using System.Collections.Generic; + +namespace Server.Guilds +{ + public class GuildRosterGump : BaseGuildListGump + { + #region Comparers + private class NameComparer : IComparer + { + public static readonly IComparer Instance = new NameComparer(); + + public NameComparer() + { + } + + public int Compare( PlayerMobile x, PlayerMobile y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + return Insensitive.Compare( x.Name, y.Name ); + } + } + + private class LastOnComparer : IComparer + { + public static readonly IComparer Instance = new LastOnComparer(); + + public LastOnComparer() + { + } + + public int Compare( PlayerMobile x, PlayerMobile y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + NetState aState = x.NetState; + NetState bState = y.NetState; + + if (aState == null && bState == null) + return x.LastOnline.CompareTo(y.LastOnline); + else if (aState == null) + return -1; + else if (bState == null) + return 1; + else + return 0; + } + } + private class TitleComparer : IComparer + { + public static readonly IComparer Instance = new TitleComparer(); + + public TitleComparer() + { + } + + public int Compare( PlayerMobile x, PlayerMobile y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + return Insensitive.Compare( x.GuildTitle, y.GuildTitle ); + } + } + + private class RankComparer : IComparer + { + public static readonly IComparer Instance = new RankComparer(); + + public RankComparer() + { + } + + public int Compare( PlayerMobile x, PlayerMobile y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + return x.GuildRank.Rank.CompareTo( y.GuildRank.Rank ); + } + } + + #endregion + + private static InfoField[] m_Fields = + new InfoField[] + { + new InfoField( 1062955, 130, GuildRosterGump.NameComparer.Instance ), //Name + new InfoField( 1062956, 80, GuildRosterGump.RankComparer.Instance ), //Rank + new InfoField( 1062952, 80, GuildRosterGump.LastOnComparer.Instance), //Last On + new InfoField( 1062953, 150, GuildRosterGump.TitleComparer.Instance ) //Guild Title + }; + + public GuildRosterGump( PlayerMobile pm, Guild g ) : this( pm, g, GuildRosterGump.LastOnComparer.Instance, false, "", 0 ) + { + } + + public GuildRosterGump( PlayerMobile pm, Guild g, IComparer currentComparer, bool ascending, string filter, int startNumber ) + : base( pm, g, Utility.SafeConvertList( g.Members ), currentComparer, ascending, filter, startNumber, m_Fields ) + { + PopulateGump(); + } + + public override void PopulateGump() + { + base.PopulateGump(); + + AddHtmlLocalized( 266, 43, 110, 26, 1062974, 0xF, false, false ); // Guild Roster + } + + public override void DrawEndingEntry( int itemNumber ) + { + AddBackground( 225, 148 + itemNumber * 28, 150, 26, 0x2486 ); + AddButton( 230, 153 + itemNumber * 28, 0x845, 0x846, 8, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 255, 151 + itemNumber * 28, 110, 26, 1062992, 0x0, false, false ); // Invite Player + } + + protected override TextDefinition[] GetValuesFor( PlayerMobile pm, int aryLength ) + { + TextDefinition[] defs = new TextDefinition[aryLength]; + + string name = String.Format( "{0}{1}", pm.Name, ( player.GuildFealty == pm && player.GuildFealty != guild.Leader ) ? " *" : "" ); + + if( pm == player ) + name = Color( name, 0x006600 ); + else if( pm.NetState != null ) + name = Color( name, 0x000066 ); + + defs[0] = name; + defs[1] = pm.GuildRank.Name; + defs[2] = (pm.NetState != null) ? new TextDefinition( 1063015 ): new TextDefinition( pm.LastOnline.ToString( "yyyy-MM-dd" ) ); + defs[3] = (pm.GuildTitle == null) ? "" : pm.GuildTitle; + + return defs; + } + + protected override bool IsFiltered( PlayerMobile pm, string filter ) + { + if( pm == null ) + return true; + + return !Insensitive.Contains( pm.Name, filter ); + } + + public override Gump GetResentGump( PlayerMobile pm, Guild g, IComparer comparer, bool ascending, string filter, int startNumber ) + { + return new GuildRosterGump( pm, g, comparer, ascending, filter, startNumber ); + } + + public override Gump GetObjectInfoGump( PlayerMobile pm, Guild g, PlayerMobile o ) + { + return new GuildMemberInfoGump( pm, g, o, false, false ) ; + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + base.OnResponse( sender, info ); + + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( pm == null || !IsMember( pm, guild ) ) + return; + + if( info.ButtonID == 8 ) + { + if( pm.GuildRank.GetFlag( RankFlags.CanInvitePlayer ) ) + { + pm.SendLocalizedMessage( 1063048 ); // Whom do you wish to invite into your guild? + pm.BeginTarget( -1, false, Targeting.TargetFlags.None, new TargetStateCallback( InvitePlayer_Callback ), guild ); + } + else + pm.SendLocalizedMessage( 503301 ); // You don't have permission to do that. + } + } + + public void InvitePlayer_Callback( Mobile from, object targeted, object state ) + { + PlayerMobile pm = from as PlayerMobile; + PlayerMobile targ = targeted as PlayerMobile; + + Guild g = state as Guild; + + PlayerState guildState = PlayerState.Find( g.Leader ); + PlayerState targetState = PlayerState.Find( targ ); + + Faction guildFaction = ( guildState == null ? null : guildState.Faction ); + Faction targetFaction = ( targetState == null ? null : targetState.Faction ); + + if( pm == null || !IsMember( pm, guild ) || !pm.GuildRank.GetFlag( RankFlags.CanInvitePlayer ) ) + { + pm.SendLocalizedMessage( 503301 ); // You don't have permission to do that. + } + else if( targ == null ) + { + pm.SendLocalizedMessage( 1063334 ); // That isn't a valid player. + } + else if( !targ.AcceptGuildInvites ) + { + pm.SendLocalizedMessage( 1063049, targ.Name ); // ~1_val~ is not accepting guild invitations. + } + else if( g.IsMember( targ ) ) + { + pm.SendLocalizedMessage( 1063050, targ.Name ); // ~1_val~ is already a member of your guild! + } + else if( targ.Guild != null ) + { + pm.SendLocalizedMessage( 1063051, targ.Name ); // ~1_val~ is already a member of a guild. + } + else if( targ.HasGump( typeof( BaseGuildGump ) ) || targ.HasGump( typeof( CreateGuildGump ) )) //TODO: Check message if CreateGuildGump Open + { + pm.SendLocalizedMessage( 1063052, targ.Name ); // ~1_val~ is currently considering another guild invitation. + } + #region Factions + else if( targ.Young && guildFaction != null ) + { + pm.SendLocalizedMessage( 1070766 ); // You cannot invite a young player to your faction-aligned guild. + } + else if ( guildFaction != targetFaction ) + { + if ( guildFaction == null ) + pm.SendLocalizedMessage( 1013027 ); // That player cannot join a non-faction guild. + else if ( targetFaction == null ) + pm.SendLocalizedMessage( 1013026 ); // That player must be in a faction before joining this guild. + else + pm.SendLocalizedMessage( 1013028 ); // That person has a different faction affiliation. + } + else if ( targetState != null && targetState.IsLeaving ) + { + // OSI does this quite strangely, so we'll just do it this way + pm.SendMessage( "That person is quitting their faction and so you may not recruit them." ); + } + #endregion + else + { + pm.SendLocalizedMessage( 1063053, targ.Name ); // You invite ~1_val~ to join your guild. + targ.SendGump( new GuildInvitationRequest( targ, guild, pm ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs b/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs new file mode 100644 index 0000000..deb0a75 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/OtherGuildInfo.cs @@ -0,0 +1,636 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Factions; +using Server.Prompts; + +namespace Server.Guilds +{ + public class OtherGuildInfo : BaseGuildGump + { + private Guild m_Other; + public OtherGuildInfo( PlayerMobile pm, Guild g, Guild otherGuild ) : base( pm, g, 10, 40 ) + { + m_Other = otherGuild; + + g.CheckExpiredWars(); + + PopulateGump(); + } + + public void AddButtonAndBackground( int x, int y, int buttonID, int locNum ) + { + AddBackground( x, y, 225, 26, 0x2486 ); + AddButton( x+5, y+5, 0x845, 0x846, buttonID, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( x+30, y+3, 185, 26, locNum, 0x0, false, false ); + } + + public override void PopulateGump() + { + Guild g = Guild.GetAllianceLeader( guild ); + Guild other = Guild.GetAllianceLeader( m_Other ); + + WarDeclaration war = g.FindPendingWar( other ); + WarDeclaration activeWar = g.FindActiveWar( other ); + + AllianceInfo alliance = guild.Alliance; + AllianceInfo otherAlliance = m_Other.Alliance; + //NOTE TO SELF: Only only alliance leader can see pending guild alliance statuses + + bool PendingWar = (war != null); + bool ActiveWar = (activeWar != null); + AddPage( 0 ); + + AddBackground( 0, 0, 520, 335, 0x242C ); + AddHtmlLocalized( 20, 15, 480, 26, 1062975, 0x0, false, false ); //
Guild Relationship
+ AddImageTiled( 20, 40, 480, 2, 0x2711 ); + AddHtmlLocalized( 20, 50, 120, 26, 1062954, 0x0, true, false ); // Guild Name + AddHtml( 150, 53, 360, 26, m_Other.Name, false, false ); + + AddHtmlLocalized( 20, 80, 120, 26, 1063025, 0x0, true, false ); // Alliance + + if( otherAlliance != null ) + { + if( otherAlliance.IsMember( m_Other )) + { + AddHtml( 150, 83, 360, 26, otherAlliance.Name, false, false ); + } + //else if( otherAlliance.Leader == guild && ( otherAlliance.IsPendingMember( m_Other ) || otherAlliance.IsPendingMember( guild ) ) ) + /* else if( (otherAlliance.Leader == guild && otherAlliance.IsPendingMember( m_Other ) ) || ( otherAlliance.Leader == m_Other && otherAlliance.IsPendingMember( guild ) ) ) + { + AddHtml( 150, 83, 360, 26, Color( alliance.Name, 0xF), false, false ); + } + //AddHtml( 150, 83, 360, 26, ( alliance.PendingMembers.Contains( guild ) || alliance.PendingMembers.Contains( m_Other ) ) ? String.Format( "{0}", alliance.Name ) : alliance.Name, false, false ); + //AddHtml( 150, 83, 360, 26, ( otherAlliance == alliance && otherAlliance.PendingMembers.Contains( guild ) || otherAlliance.PendingMembers.Contains( m_Other ) ) ? String.Format( "{0}", otherAlliance.Name ) : otherAlliance.Name, false, false ); + */ + } + + AddHtmlLocalized( 20, 110, 120, 26, 1063139, 0x0, true, false ); // Abbreviation + AddHtml( 150, 113, 120, 26, m_Other.Abbreviation, false, false ); + + + string kills = "0/0"; + string time = "00:00"; + string otherKills = "0/0"; + + WarDeclaration otherWar; + + if( ActiveWar ) + { + kills = String.Format( "{0}/{1}", activeWar.Kills, activeWar.MaxKills ); + + TimeSpan timeRemaining = TimeSpan.Zero; + + if( activeWar.WarLength != TimeSpan.Zero && (activeWar.WarBeginning + activeWar.WarLength) > DateTime.Now ) + timeRemaining = (activeWar.WarBeginning + activeWar.WarLength) - DateTime.Now; + + //time = String.Format( "{0:D2}:{1:D2}", timeRemaining.Hours.ToString(), timeRemaining.Subtract( TimeSpan.FromHours( timeRemaining.Hours ) ).Minutes ); //Is there a formatter for htis? it's 2AM and I'm tired and can't find it + time = String.Format( "{0:D2}:{1:mm}", timeRemaining.Hours, DateTime.MinValue + timeRemaining ); + + otherWar = m_Other.FindActiveWar( guild ); + if( otherWar != null ) + otherKills = String.Format( "{0}/{1}", otherWar.Kills, otherWar.MaxKills ); + } + else if( PendingWar ) + { + kills = Color( String.Format( "{0}/{1}", war.Kills, war.MaxKills ), 0x990000 ); + //time = Color( String.Format( "{0}:{1}", war.WarLength.Hours, ((TimeSpan)(war.WarLength - TimeSpan.FromHours( war.WarLength.Hours ))).Minutes ), 0xFF0000 ); + time = Color( String.Format( "{0:D2}:{1:mm}", war.WarLength.Hours, DateTime.MinValue + war.WarLength ), 0x990000 ); + + otherWar = m_Other.FindPendingWar( guild ); + if( otherWar != null ) + otherKills = Color( String.Format( "{0}/{1}", otherWar.Kills, otherWar.MaxKills ), 0x990000 ); + } + + AddHtmlLocalized( 280, 110, 120, 26, 1062966, 0x0, true, false ); // Your Kills + AddHtml( 410, 113, 120, 26, kills , false, false ); + + AddHtmlLocalized( 20, 140, 120, 26, 1062968, 0x0, true, false ); // Time Remaining + AddHtml( 150, 143, 120, 26, time, false, false ); + + AddHtmlLocalized( 280, 140, 120, 26, 1062967, 0x0, true, false ); // Their Kills + AddHtml( 410, 143, 120, 26, otherKills, false, false ); + + AddImageTiled( 20, 172, 480, 2, 0x2711 ); + + int number = 1062973;//
You are at peace with this guild.
+ + + if( PendingWar ) + { + if( war.WarRequester ) + { + number = 1063027; //
You have challenged this guild to war!
+ } + else + { + number = 1062969; //
This guild has challenged you to war!
+ + AddButtonAndBackground( 20, 260, 5, 1062981 ); // Accept Challenge + AddButtonAndBackground( 275, 260, 6, 1062983 ); //Modify Terms + } + + AddButtonAndBackground( 20, 290, 7, 1062982 ); // Dismiss Challenge + } + else if( ActiveWar ) + { + number = 1062965; //
You are at war with this guild!
+ AddButtonAndBackground( 20, 290, 8, 1062980 ); // Surrender + } + else if ( alliance != null && alliance == otherAlliance ) //alliance, Same Alliance + { + if( alliance.IsMember( guild ) && alliance.IsMember( m_Other ) ) //Both in Same alliance, full members + { + number = 1062970; //
You are allied with this guild.
+ + if( alliance.Leader == guild ) + { + AddButtonAndBackground( 20, 260, 12, 1062984 ); // Remove Guild from Alliance + AddButtonAndBackground( 275, 260, 13, 1063433 ); // Promote to Alliance Leader //Note: No 'confirmation' like the other leader guild promotion things + //Remove guild from alliance //Promote to Alliance Leader + } + + //Show roster, Centered, up + AddButtonAndBackground( 148, 215, 10, 1063164 ); //Show Alliance Roster + //Leave Alliance + AddButtonAndBackground( 20, 290, 11, 1062985 ); // Leave Alliance + } + else if( alliance.Leader == guild && alliance.IsPendingMember( m_Other ) ) + { + number = 1062971; //
You have requested an alliance with this guild.
+ + //Show Alliance Roster, Centered, down. + AddButtonAndBackground( 148, 245, 10, 1063164 ); //Show Alliance Roster + //Withdraw Request + AddButtonAndBackground( 20, 290, 14, 1062986 ); // Withdraw Request + + AddHtml( 150, 83, 360, 26, Color( alliance.Name, 0x99 ), false, false ); + } + else if( alliance.Leader == m_Other && alliance.IsPendingMember( guild ) ) + { + number = 1062972; //
This guild has requested an alliance.
+ + //Show alliance Roster, top + AddButtonAndBackground( 148, 215, 10, 1063164 ); //Show Alliance Roster + //Deny Request + //Accept Request + AddButtonAndBackground( 20, 260, 15, 1062988 ); // Deny Request + AddButtonAndBackground( 20, 290, 16, 1062987 ); // Accept Request + + AddHtml( 150, 83, 360, 26, Color( alliance.Name, 0x99 ), false, false ); + } + } + else + { + AddButtonAndBackground( 20, 260, 2, 1062990 ); // Request Alliance + AddButtonAndBackground( 20, 290, 1, 1062989 ); // Declare War! + } + + AddButtonAndBackground( 275, 290, 0, 3000091 ); //Cancel + + AddHtmlLocalized( 20, 180, 480, 30, number, 0x0, true, false ); + AddImageTiled( 20, 245, 480, 2, 0x2711 ); + } + + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( !IsMember( pm, guild ) ) + return; + + RankDefinition playerRank = pm.GuildRank; + + Guild guildLeader = Guild.GetAllianceLeader( guild ); + Guild otherGuild = Guild.GetAllianceLeader( m_Other ); + + WarDeclaration war = guildLeader.FindPendingWar( otherGuild ); + WarDeclaration activeWar = guildLeader.FindActiveWar( otherGuild ); + WarDeclaration otherWar = otherGuild.FindPendingWar( guildLeader ); + + AllianceInfo alliance = guild.Alliance; + AllianceInfo otherAlliance = otherGuild.Alliance; + + switch( info.ButtonID ) + { + #region War + case 5: //Accept the war + { + if( war != null && !war.WarRequester && activeWar == null ) + { + if( !playerRank.GetFlag( RankFlags.ControlWarStatus ) ) + { + pm.SendLocalizedMessage( 1063440 ); // You don't have permission to negotiate wars. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, alliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else + { + //Accept the war + guild.PendingWars.Remove( war ); + war.WarBeginning = DateTime.Now; + guild.AcceptedWars.Add( war ); + + if( alliance != null && alliance.IsMember( guild ) ) + { + alliance.AllianceMessage( 1070769, ((otherAlliance != null) ? otherAlliance.Name : otherGuild.Name) ); // Guild Message: Your guild is now at war with ~1_GUILDNAME~ + alliance.InvalidateMemberProperties(); + } + else + { + guild.GuildMessage( 1070769, ((otherAlliance != null) ? otherAlliance.Name : otherGuild.Name) ); // Guild Message: Your guild is now at war with ~1_GUILDNAME~ + guild.InvalidateMemberProperties(); + } + //Technically SHOULD say Your guild is now at war w/out any info, intentional diff. + + otherGuild.PendingWars.Remove( otherWar ); + otherWar.WarBeginning = DateTime.Now; + otherGuild.AcceptedWars.Add( otherWar ); + + if( otherAlliance != null && m_Other.Alliance.IsMember( m_Other ) ) + { + otherAlliance.AllianceMessage( 1070769, ((alliance != null) ? alliance.Name : guild.Name) ); // Guild Message: Your guild is now at war with ~1_GUILDNAME~ + otherAlliance.InvalidateMemberProperties(); + } + else + { + otherGuild.GuildMessage( 1070769, ((alliance != null) ? alliance.Name : guild.Name) ); // Guild Message: Your guild is now at war with ~1_GUILDNAME~ + otherGuild.InvalidateMemberProperties(); + } + } + } + + break; + } + case 6: //Modify war terms + { + if( war != null && !war.WarRequester && activeWar == null ) + { + if( !playerRank.GetFlag( RankFlags.ControlWarStatus ) ) + { + pm.SendLocalizedMessage( 1063440 ); // You don't have permission to negotiate wars. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, alliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else + { + pm.SendGump( new WarDeclarationGump( pm, guild, otherGuild ) ); + } + } + break; + } + case 7: //Dismiss war + { + if( war != null ) + { + if( !playerRank.GetFlag( RankFlags.ControlWarStatus ) ) + { + pm.SendLocalizedMessage( 1063440 ); // You don't have permission to negotiate wars. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, alliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else + { + //Dismiss the war + guild.PendingWars.Remove( war ); + otherGuild.PendingWars.Remove( otherWar ); + pm.SendLocalizedMessage( 1070752 ); // The proposal has been updated. + //Messages to opposing guild? (Testing on OSI says no) + } + } + break; + } + case 8: //Surrender + { + if( !playerRank.GetFlag( RankFlags.ControlWarStatus ) ) + { + pm.SendLocalizedMessage( 1063440 ); // You don't have permission to negotiate wars. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, alliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else + { + if( activeWar != null ) + { + if( alliance != null && alliance.IsMember( guild ) ) + { + alliance.AllianceMessage( 1070740, ((otherAlliance != null) ? otherAlliance.Name : otherGuild.Name) );// You have lost the war with ~1_val~. + alliance.InvalidateMemberProperties(); + } + else + { + guild.GuildMessage( 1070740, ((otherAlliance != null) ? otherAlliance.Name : otherGuild.Name) );// You have lost the war with ~1_val~. + guild.InvalidateMemberProperties(); + } + + guild.AcceptedWars.Remove( activeWar ); + + if( otherAlliance != null && otherAlliance.IsMember( otherGuild ) ) + { + otherAlliance.AllianceMessage( 1070739, ((guild.Alliance != null) ? guild.Alliance.Name : guild.Name) );// You have won the war against ~1_val~! + otherAlliance.InvalidateMemberProperties(); + } + else + { + otherGuild.GuildMessage( 1070739, ((guild.Alliance != null) ? guild.Alliance.Name : guild.Name) );// You have won the war against ~1_val~! + otherGuild.InvalidateMemberProperties(); + } + + otherGuild.AcceptedWars.Remove( otherGuild.FindActiveWar( guild ) ); + } + } + break; + } + case 1: //Declare War + { + if( war == null && activeWar == null ) + { + if( !playerRank.GetFlag( RankFlags.ControlWarStatus ) ) + { + pm.SendLocalizedMessage( 1063440 ); // You don't have permission to negotiate wars. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, alliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else if( otherAlliance != null && otherAlliance.Leader != m_Other ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", m_Other.Name, otherAlliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, otherAlliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else + { + pm.SendGump( new WarDeclarationGump( pm, guild, m_Other ) ); + } + } + break; + } + #endregion + case 2: //Request Alliance + { + #region New alliance + if( alliance == null ) + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1070747 ); // You don't have permission to create an alliance. + } + else if( Faction.Find( guild.Leader ) != Faction.Find( m_Other.Leader ) ) + { + pm.SendLocalizedMessage( 1070758 ); // You cannot propose an alliance to a guild with a different faction allegiance. + } + else if( otherAlliance != null ) + { + if( otherAlliance.IsPendingMember( m_Other ) ) + pm.SendLocalizedMessage( 1063416, m_Other.Name ); // ~1_val~ is currently considering another alliance proposal. + else + pm.SendLocalizedMessage( 1063426, m_Other.Name ); // ~1_val~ already belongs to an alliance. + } + else if( m_Other.AcceptedWars.Count > 0 || m_Other.PendingWars.Count > 0 ) + { + pm.SendLocalizedMessage( 1063427, m_Other.Name ); // ~1_val~ is currently involved in a guild war. + } + else if( guild.AcceptedWars.Count > 0 || guild.PendingWars.Count > 0 ) + { + pm.SendLocalizedMessage( 1063427, guild.Name ); // ~1_val~ is currently involved in a guild war. + } + else + { + pm.SendLocalizedMessage( 1063439 ); // Enter a name for the new alliance: + pm.BeginPrompt( new PromptCallback( CreateAlliance_Callback ) ); + } + } + #endregion + #region Existing Alliance + else + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + } + else if( otherAlliance != null ) + { + if( otherAlliance.IsPendingMember( m_Other ) ) + pm.SendLocalizedMessage( 1063416, m_Other.Name ); // ~1_val~ is currently considering another alliance proposal. + else + pm.SendLocalizedMessage( 1063426, m_Other.Name ); // ~1_val~ already belongs to an alliance. + } + else if( alliance.IsPendingMember( guild ) ) + { + pm.SendLocalizedMessage( 1063416, guild.Name ); // ~1_val~ is currently considering another alliance proposal. + } + else if( m_Other.AcceptedWars.Count > 0 || m_Other.PendingWars.Count > 0 ) + { + pm.SendLocalizedMessage( 1063427, m_Other.Name ); // ~1_val~ is currently involved in a guild war. + } + else if( guild.AcceptedWars.Count > 0 || guild.PendingWars.Count > 0 ) + { + pm.SendLocalizedMessage( 1063427, guild.Name ); // ~1_val~ is currently involved in a guild war. + } + else if( Faction.Find( guild.Leader ) != Faction.Find( m_Other.Leader ) ) + { + pm.SendLocalizedMessage( 1070758 ); // You cannot propose an alliance to a guild with a different faction allegiance. + } + else + { + pm.SendLocalizedMessage( 1070750, m_Other.Name ); // An invitation to join your alliance has been sent to ~1_val~. + + m_Other.GuildMessage( 1070780, guild.Name ); // ~1_val~ has proposed an alliance. + + m_Other.Alliance = alliance; //Calls addPendingGuild + //alliance.AddPendingGuild( m_Other ); + } + } + #endregion + break; + } + case 10: //Show Alliance Roster + { + if( alliance != null && alliance == otherAlliance ) + pm.SendGump( new AllianceInfo.AllianceRosterGump( pm, guild, alliance ) ); + + break; + } + case 11: //Leave Alliance + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( alliance != null && alliance.IsMember( guild ) ) + { + guild.Alliance = null; //Calls alliance.Removeguild +// alliance.RemoveGuild( guild ); + + m_Other.InvalidateWarNotoriety(); + + guild.InvalidateMemberNotoriety(); + } + break; + } + case 12: //Remove Guild from alliance + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + } + else if( alliance != null && alliance.IsMember( guild ) && alliance.IsMember( m_Other ) ) + { + m_Other.Alliance = null; + + m_Other.InvalidateMemberNotoriety(); + + guild.InvalidateWarNotoriety(); + } + break; + } + case 13: //Promote to Alliance leader + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + } + else if( alliance != null && alliance.IsMember( guild ) && alliance.IsMember( m_Other ) ) + { + pm.SendLocalizedMessage( 1063434, String.Format( "{0}\t{1}", m_Other.Name, alliance.Name ) ); // ~1_val~ is now the leader of ~2_val~. + + alliance.Leader = m_Other; + } + break; + } + case 14: //Withdraw Request + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( alliance != null && alliance.Leader == guild && alliance.IsPendingMember( m_Other ) ) + { + m_Other.Alliance = null; + pm.SendLocalizedMessage( 1070752 ); // The proposal has been updated. + } + break; + } + case 15: //Deny Alliance Request + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( alliance != null && otherAlliance != null && alliance.Leader == m_Other && otherAlliance.IsPendingMember( guild ) ) + { + pm.SendLocalizedMessage( 1070752 ); // The proposal has been updated. + //m_Other.GuildMessage( 1070782 ); // ~1_val~ has responded to your proposal. //Per OSI commented out. + + guild.Alliance = null; + } + break; + } + case 16: //Accept Alliance Request + { + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1063436 ); // You don't have permission to negotiate an alliance. + } + else if( otherAlliance != null && otherAlliance.Leader == m_Other && otherAlliance.IsPendingMember( guild ) ) + { + pm.SendLocalizedMessage( 1070752 ); // The proposal has been updated. + + otherAlliance.TurnToMember( m_Other ); //No need to verify it's in the guild or already a member, the function does this + + otherAlliance.TurnToMember( guild ); + } + break; + } + } + } + + public void CreateAlliance_Callback( Mobile from, string text ) + { + PlayerMobile pm = from as PlayerMobile; + + + AllianceInfo alliance = guild.Alliance; + AllianceInfo otherAlliance = m_Other.Alliance; + + if( !IsMember( from, guild ) || alliance != null ) + return; + + + RankDefinition playerRank = pm.GuildRank; + + + if( !playerRank.GetFlag( RankFlags.AllianceControl ) ) + { + pm.SendLocalizedMessage( 1070747 ); // You don't have permission to create an alliance. + } + else if( Faction.Find( guild.Leader ) != Faction.Find( m_Other.Leader ) ) + { + //Notes about this: OSI only cares/checks when proposing, you can change your faction all you want later. + pm.SendLocalizedMessage( 1070758 ); // You cannot propose an alliance to a guild with a different faction allegiance. + } + else if( otherAlliance != null ) + { + if( otherAlliance.IsPendingMember( m_Other ) ) + pm.SendLocalizedMessage( 1063416, m_Other.Name ); // ~1_val~ is currently considering another alliance proposal. + else + pm.SendLocalizedMessage( 1063426, m_Other.Name ); // ~1_val~ already belongs to an alliance. + } + else if( m_Other.AcceptedWars.Count > 0 || m_Other.PendingWars.Count > 0 ) + { + pm.SendLocalizedMessage( 1063427, m_Other.Name ); // ~1_val~ is currently involved in a guild war. + } + else if( guild.AcceptedWars.Count > 0 || guild.PendingWars.Count > 0 ) + { + pm.SendLocalizedMessage( 1063427, guild.Name ); // ~1_val~ is currently involved in a guild war. + } + else + { + string name = Utility.FixHtml( text.Trim() ); + + if( !BaseGuildGump.CheckProfanity( name ) ) + pm.SendLocalizedMessage( 1070886 ); // That alliance name is not allowed. + else if( name.Length > Guild.NameLimit ) + pm.SendLocalizedMessage( 1070887, Guild.NameLimit.ToString() ); // An alliance name cannot exceed ~1_val~ characters in length. + else if( AllianceInfo.Alliances.ContainsKey( name.ToLower() ) ) + pm.SendLocalizedMessage( 1063428 ); // That alliance name is not available. + else + { + pm.SendLocalizedMessage( 1070750, m_Other.Name ); // An invitation to join your alliance has been sent to ~1_val~. + + m_Other.GuildMessage( 1070780, guild.Name ); // ~1_val~ has proposed an alliance. + + new AllianceInfo( guild, name, m_Other ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/New Guild System/War Declaration gump.cs b/Scripts/Gumps/Guilds/New Guild System/War Declaration gump.cs new file mode 100644 index 0000000..f472a89 --- /dev/null +++ b/Scripts/Gumps/Guilds/New Guild System/War Declaration gump.cs @@ -0,0 +1,130 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; + +namespace Server.Guilds +{ + public class WarDeclarationGump : BaseGuildGump + { + private Guild m_Other; + + public WarDeclarationGump( PlayerMobile pm, Guild g, Guild otherGuild ) : base( pm, g ) + { + m_Other = otherGuild; + WarDeclaration war = g.FindPendingWar( otherGuild ); + + AddPage( 0 ); + + AddBackground( 0, 0, 500, 340, 0x24AE ); + AddBackground( 65, 50, 370, 30, 0x2486 ); + AddHtmlLocalized( 75, 55, 370, 26, 1062979, 0x3C00, false, false ); //
Declaration of War
+ AddImage( 410, 45, 0x232C ); + AddHtmlLocalized( 65, 95, 200, 20, 1063009, 0x14AF, false, false ); // Duration of War + AddHtmlLocalized( 65, 120, 400, 20, 1063010, 0x0, false, false ); // Enter the number of hours the war will last. + AddBackground( 65, 150, 40, 30, 0x2486 ); + AddTextEntry( 70, 154, 50, 30, 0x481, 10, (war != null) ? war.WarLength.Hours.ToString() : "0" ); + AddHtmlLocalized( 65, 195, 200, 20, 1063011, 0x14AF, false, false ); // Victory Condition + AddHtmlLocalized( 65, 220, 400, 20, 1063012, 0x0, false, false ); // Enter the winning number of kills. + AddBackground( 65, 250, 40, 30, 0x2486 ); + AddTextEntry( 70, 254, 50, 30, 0x481, 11, (war != null) ? war.MaxKills.ToString() : "0" ); + AddBackground( 190, 270, 130, 26, 0x2486 ); + AddButton( 195, 275, 0x845, 0x846, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 220, 273, 90, 26, 1006045, 0x0, false, false ); // Cancel + AddBackground( 330, 270, 130, 26, 0x2486 ); + AddButton( 335, 275, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 360, 273, 90, 26, 1062989, 0x5000, false, false ); // Declare War! + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + + PlayerMobile pm = sender.Mobile as PlayerMobile; + + if( !IsMember( pm, guild ) ) + return; + + RankDefinition playerRank = pm.GuildRank; + + switch( info.ButtonID ) + { + case 1: + { + AllianceInfo alliance = guild.Alliance; + AllianceInfo otherAlliance = m_Other.Alliance; + + if( !playerRank.GetFlag( RankFlags.ControlWarStatus ) ) + { + pm.SendLocalizedMessage( 1063440 ); // You don't have permission to negotiate wars. + } + else if( alliance != null && alliance.Leader != guild ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", guild.Name, alliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, alliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else if( otherAlliance != null && otherAlliance.Leader != m_Other ) + { + pm.SendLocalizedMessage( 1063239, String.Format( "{0}\t{1}", m_Other.Name, otherAlliance.Name ) ); // ~1_val~ is not the leader of the ~2_val~ alliance. + pm.SendLocalizedMessage( 1070707, otherAlliance.Leader.Name ); // You need to negotiate via ~1_val~ instead. + } + else + { + WarDeclaration activeWar = guild.FindActiveWar( m_Other ); + + if( activeWar == null ) + { + WarDeclaration war = guild.FindPendingWar( m_Other ); + WarDeclaration otherWar = m_Other.FindPendingWar( guild ); + + //Note: OSI differs from what it says on website. unlimited war = 0 kills/ 0 hrs. Not > 999. (sidenote: they both cap at 65535, 7.5 years, but, still.) + TextRelay tKills = info.GetTextEntry( 11 ); + TextRelay tWarLength = info.GetTextEntry( 10 ); + + int maxKills = (tKills == null)? 0 : Math.Max( Math.Min( Utility.ToInt32( info.GetTextEntry( 11 ).Text ), 0xFFFF ), 0 ); + TimeSpan warLength = TimeSpan.FromHours( (tWarLength == null) ? 0 : Math.Max( Math.Min( Utility.ToInt32( info.GetTextEntry( 10 ).Text ), 0xFFFF ), 0 ) ); + + if( war != null ) + { + war.MaxKills = maxKills; + war.WarLength = warLength; + war.WarRequester = true; + } + else + { + guild.PendingWars.Add( new WarDeclaration( guild, m_Other, maxKills, warLength, true ) ); + } + + if( otherWar != null ) + { + otherWar.MaxKills = maxKills; + otherWar.WarLength = warLength; + otherWar.WarRequester = false; + } + else + { + m_Other.PendingWars.Add( new WarDeclaration( m_Other, guild, maxKills, warLength, false ) ); + } + + if( war != null ) + { + pm.SendLocalizedMessage( 1070752 ); // The proposal has been updated. + //m_Other.GuildMessage( 1070782 ); // ~1_val~ has responded to your proposal. + } + else + m_Other.GuildMessage( 1070781, ((guild.Alliance != null ) ? guild.Alliance.Name : guild.Name ) ); // ~1_val~ has proposed a war. + + pm.SendLocalizedMessage( 1070751, ((m_Other.Alliance != null ) ? m_Other.Alliance.Name : m_Other.Name ) ); // War proposal has been sent to ~1_val~. + } + } + break; + } + default: + { + pm.SendGump( new OtherGuildInfo( pm, guild, m_Other ) ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Guilds/RecruitTarget.cs b/Scripts/Gumps/Guilds/RecruitTarget.cs new file mode 100644 index 0000000..d9ce5d4 --- /dev/null +++ b/Scripts/Gumps/Guilds/RecruitTarget.cs @@ -0,0 +1,95 @@ +using System; +using Server; +using Server.Guilds; +using Server.Targeting; +using Server.Factions; + +namespace Server.Gumps +{ + public class GuildRecruitTarget : Target + { + private Mobile m_Mobile; + private Guild m_Guild; + + public GuildRecruitTarget( Mobile m, Guild guild ) : base( 10, false, TargetFlags.None ) + { + m_Mobile = m; + m_Guild = guild; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + if ( targeted is Mobile ) + { + Mobile m = (Mobile)targeted; + + PlayerState guildState = PlayerState.Find( m_Guild.Leader ); + PlayerState targetState = PlayerState.Find( m ); + + Faction guildFaction = ( guildState == null ? null : guildState.Faction ); + Faction targetFaction = ( targetState == null ? null : targetState.Faction ); + + if ( !m.Player ) + { + m_Mobile.SendLocalizedMessage( 501161 ); // You may only recruit players into the guild. + } + else if ( !m.Alive ) + { + m_Mobile.SendLocalizedMessage( 501162 ); // Only the living may be recruited. + } + else if ( m_Guild.IsMember( m ) ) + { + m_Mobile.SendLocalizedMessage( 501163 ); // They are already a guildmember! + } + else if ( m_Guild.Candidates.Contains( m ) ) + { + m_Mobile.SendLocalizedMessage( 501164 ); // They are already a candidate. + } + else if ( m_Guild.Accepted.Contains( m ) ) + { + m_Mobile.SendLocalizedMessage( 501165 ); // They have already been accepted for membership, and merely need to use the Guildstone to gain full membership. + } + else if ( m.Guild != null ) + { + m_Mobile.SendLocalizedMessage( 501166 ); // You can only recruit candidates who are not already in a guild. + } + #region Factions + else if ( guildFaction != targetFaction ) + { + if ( guildFaction == null ) + m_Mobile.SendLocalizedMessage( 1013027 ); // That player cannot join a non-faction guild. + else if ( targetFaction == null ) + m_Mobile.SendLocalizedMessage( 1013026 ); // That player must be in a faction before joining this guild. + else + m_Mobile.SendLocalizedMessage( 1013028 ); // That person has a different faction affiliation. + } + else if ( targetState != null && targetState.IsLeaving ) + { + // OSI does this quite strangely, so we'll just do it this way + m_Mobile.SendMessage( "That person is quitting their faction and so you may not recruit them." ); + } + #endregion + else if ( m_Mobile.AccessLevel >= AccessLevel.GameMaster || m_Guild.Leader == m_Mobile ) + { + m_Guild.Accepted.Add( m ); + } + else + { + m_Guild.Candidates.Add( m ); + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( GuildGump.BadMember( m_Mobile, m_Guild ) ) + return; + + GuildGump.EnsureClosed( m_Mobile ); + m_Mobile.SendGump( new GuildGump( m_Mobile, m_Guild ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/HeritageTokenGump.cs b/Scripts/Gumps/HeritageTokenGump.cs new file mode 100644 index 0000000..f0fff36 --- /dev/null +++ b/Scripts/Gumps/HeritageTokenGump.cs @@ -0,0 +1,389 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Gumps +{ + public class HeritageTokenGump : Gump + { + private HeritageToken m_Token; + + public HeritageTokenGump( HeritageToken token ) : base( 60, 36 ) + { + m_Token = token; + + AddPage( 0 ); + + AddBackground( 0, 0, 520, 404, 0x13BE ); + AddImageTiled( 10, 10, 500, 20, 0xA40 ); + AddImageTiled( 10, 40, 500, 324, 0xA40 ); + AddImageTiled( 10, 374, 500, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 500, 384 ); + AddButton( 10, 374, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 376, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 500, 20, 1075576, 0x7FFF, false, false ); // Choose your item from the following pages + + AddPage( 1 ); + + AddImageTiledButton( 14, 44, 0x918, 0x919, 0x64, GumpButtonType.Reply, 0, 0x1411, 0x2C, 18, 8 ); + AddTooltip( 1062912 ); + AddHtmlLocalized( 98, 44, 250, 60, 1078147, 0x7FFF, false, false ); // Royal Leggings of Embers + AddImageTiledButton( 264, 44, 0x918, 0x919, 0x65, GumpButtonType.Reply, 0, 0x234D, 0x0, 18, 12 ); + AddTooltip( 1062914 ); + AddHtmlLocalized( 348, 44, 250, 60, 1062913, 0x7FFF, false, false ); // Rose of Trinsic + AddImageTiledButton( 14, 108, 0x918, 0x919, 0x66, GumpButtonType.Reply, 0, 0x26C3, 0x504, 18, 8 ); + AddTooltip( 1062916 ); + AddHtmlLocalized( 98, 108, 250, 60, 1062915, 0x7FFF, false, false ); // Shamino’s Best Crossbow + AddImageTiledButton( 264, 108, 0x918, 0x919, 0x67, GumpButtonType.Reply, 0, 0x3F1D, 0x0, 18, 8 ); + AddTooltip( 1062918 ); + AddHtmlLocalized( 348, 108, 250, 60, 1062917, 0x7FFF, false, false ); // The Tapestry of Sosaria + AddImageTiledButton( 14, 172, 0x918, 0x919, 0x68, GumpButtonType.Reply, 0, 0x3F14, 0x0, 18, 8 ); + AddTooltip( 1062920 ); + AddHtmlLocalized( 98, 172, 250, 60, 1062919, 0x7FFF, false, false ); // Hearth of the Home Fire + AddImageTiledButton( 264, 172, 0x918, 0x919, 0x69, GumpButtonType.Reply, 0, 0xF60, 0x482, -1, 10 ); + AddTooltip( 1062922 ); + AddHtmlLocalized( 348, 172, 250, 60, 1062921, 0x7FFF, false, false ); // The Holy Sword + AddImageTiledButton( 14, 236, 0x918, 0x919, 0x6A, GumpButtonType.Reply, 0, 0x236C, 0x0, 18, 6 ); + AddTooltip( 1062924 ); + AddHtmlLocalized( 98, 236, 250, 60, 1062923, 0x7FFF, false, false ); // Ancient Samurai Helm + AddImageTiledButton( 264, 236, 0x918, 0x919, 0x6B, GumpButtonType.Reply, 0, 0x2B10, 0x226, 18, 11 ); + AddTooltip( 1075223 ); + AddHtmlLocalized( 348, 236, 250, 60, 1075188, 0x7FFF, false, false ); // Helm of Spirituality + AddImageTiledButton( 14, 300, 0x918, 0x919, 0x6C, GumpButtonType.Reply, 0, 0x2B0C, 0x226, 18, 15 ); + AddTooltip( 1075224 ); + AddHtmlLocalized( 98, 300, 250, 60, 1075192, 0x7FFF, false, false ); // Gauntlets of Valor + AddImageTiledButton( 264, 300, 0x918, 0x919, 0x6D, GumpButtonType.Reply, 0, 0x2B01, 0x0, 18, 9 ); + AddTooltip( 1075225 ); + AddHtmlLocalized( 348, 300, 250, 60, 1075196, 0x7FFF, false, false ); // Dupre’s Shield + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 2 ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( 2 ); + + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + AddImageTiledButton( 14, 44, 0x918, 0x919, 0x6E, GumpButtonType.Reply, 0, 0x2AC6, 0x0, 29, 0 ); + AddTooltip( 1075226 ); + AddHtmlLocalized( 98, 44, 250, 60, 1075197, 0x7FFF, false, false ); // Fountain of Life + AddImageTiledButton( 264, 44, 0x918, 0x919, 0x6F, GumpButtonType.Reply, 0, 0x2AF9, 0x0, -4, -5 ); + AddTooltip( 1075227 ); + AddHtmlLocalized( 348, 44, 250, 60, 1075198, 0x7FFF, false, false ); // Dawn’s Music Box + AddImageTiledButton( 14, 108, 0x918, 0x919, 0x70, GumpButtonType.Reply, 0, 0x2253, 0x0, 18, 12 ); + AddTooltip( 1075228 ); + AddHtmlLocalized( 98, 108, 250, 60, 1078148, 0x7FFF, false, false ); // Ossian Grimoire + AddImageTiledButton( 264, 108, 0x918, 0x919, 0x71, GumpButtonType.Reply, 0, 0x2D98, 0x0, 19, 13 ); + AddTooltip( 1078527 ); + AddHtmlLocalized( 348, 108, 250, 60, 1078142, 0x7FFF, false, false ); // Talisman of the Fey:
Ferret + AddImageTiledButton( 14, 172, 0x918, 0x919, 0x72, GumpButtonType.Reply, 0, 0x2D97, 0x0, 19, 13 ); + AddTooltip( 1078528 ); + AddHtmlLocalized( 98, 172, 250, 60, 1078143, 0x7FFF, false, false ); // Talisman of the Fey:
Squirrel + AddImageTiledButton( 264, 172, 0x918, 0x919, 0x73, GumpButtonType.Reply, 0, 0x2D96, 0x0, 19, 8 ); + AddTooltip( 1078529 ); + AddHtmlLocalized( 348, 172, 250, 60, 1078144, 0x7FFF, false, false ); // Talisman of the Fey:
Cu Sidhe + AddImageTiledButton( 14, 236, 0x918, 0x919, 0x74, GumpButtonType.Reply, 0, 0x2D95, 0x0, -4, 2 ); + AddTooltip( 1078530 ); + AddHtmlLocalized( 98, 236, 250, 60, 1078145, 0x7FFF, false, false ); // Talisman of the Fey:
Reptalon + AddImageTiledButton( 264, 236, 0x918, 0x919, 0x75, GumpButtonType.Reply, 0, 0x2B02, 0x0, -2, 9 ); + AddTooltip( 1078526 ); + AddHtmlLocalized( 348, 236, 250, 60, 1075201, 0x7FFF, false, false ); // Quiver of Infinity + AddImageTiledButton( 14, 300, 0x918, 0x919, 0x76, GumpButtonType.Reply, 0, 0x2A91, 0x0, 25, 5 ); + AddTooltip( 1075986 ); + AddHtmlLocalized( 98, 300, 250, 60, 1074797, 0x7FFF, false, false ); // Bone Throne, Bone Couch
and Bone Table + AddImageTiledButton( 264, 300, 0x918, 0x919, 0x77, GumpButtonType.Reply, 0, 0x2A99, 0x0, 18, 1 ); + AddTooltip( 1075987 ); + AddHtmlLocalized( 348, 300, 250, 60, 1078146, 0x7FFF, false, false ); // Creepy Portraits + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 3 ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( 3 ); + + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 2 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + AddImageTiledButton( 14, 44, 0x918, 0x919, 0x78, GumpButtonType.Reply, 0, 0x2A71, 0x0, 13, 5 ); + AddTooltip( 1075988 ); + AddHtmlLocalized( 98, 44, 250, 60, 1074799, 0x7FFF, false, false ); // Mounted Pixies (5) + AddImageTiledButton( 264, 44, 0x918, 0x919, 0x79, GumpButtonType.Reply, 0, 0x2A98, 0x0, 26, 1 ); + AddTooltip( 1075990 ); + AddHtmlLocalized( 348, 44, 250, 60, 1074800, 0x7FFF, false, false ); // Haunted Mirror + AddImageTiledButton( 14, 108, 0x918, 0x919, 0x7A, GumpButtonType.Reply, 0, 0x2A92, 0x0, 18, 1 ); + AddTooltip( 1075989 ); + AddHtmlLocalized( 98, 108, 250, 60, 1074801, 0x7FFF, false, false ); // Bed of Nails + AddImageTiledButton( 264, 108, 0x918, 0x919, 0x7B, GumpButtonType.Reply, 0, 0x2AB8, 0x0, 18, 1 ); + AddTooltip( 1075991 ); + AddHtmlLocalized( 348, 108, 250, 60, 1074818, 0x7FFF, false, false ); // Sacrificial Altar + AddImageTiledButton( 14, 172, 0x918, 0x919, 0x7C, GumpButtonType.Reply, 0, 0x3F26, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 98, 172, 250, 60, 1076257, 0x7FFF, false, false ); // Broken Covered Chair + AddImageTiledButton( 264, 172, 0x918, 0x919, 0x7D, GumpButtonType.Reply, 0, 0x3F22, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 348, 172, 250, 60, 1076258, 0x7FFF, false, false ); // Broken Bookcase + AddImageTiledButton( 14, 236, 0x918, 0x919, 0x7E, GumpButtonType.Reply, 0, 0x3F24, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 98, 236, 250, 60, 1076259, 0x7FFF, false, false ); // Standing Broken Chair + AddImageTiledButton( 264, 236, 0x918, 0x919, 0x7F, GumpButtonType.Reply, 0, 0x3F25, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 348, 236, 250, 60, 1076260, 0x7FFF, false, false ); // Broken Vanity + AddImageTiledButton( 14, 300, 0x918, 0x919, 0x80, GumpButtonType.Reply, 0, 0x3F23, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 98, 300, 250, 60, 1076261, 0x7FFF, false, false ); // Broken Chest of Drawers + AddImageTiledButton( 264, 300, 0x918, 0x919, 0x81, GumpButtonType.Reply, 0, 0x3F21, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 348, 300, 250, 60, 1076262, 0x7FFF, false, false ); // Broken Armoire + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 4 ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( 4 ); + + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 3 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + AddImageTiledButton( 14, 44, 0x918, 0x919, 0x82, GumpButtonType.Reply, 0, 0x3F0B, 0x0, 18, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 98, 44, 250, 60, 1076263, 0x7FFF, false, false ); // Broken Bed + AddImageTiledButton( 264, 44, 0x918, 0x919, 0x83, GumpButtonType.Reply, 0, 0xC19, 0x0, 13, 8 ); + AddTooltip( 1076610 ); + AddHtmlLocalized( 348, 44, 250, 60, 1076264, 0x7FFF, false, false ); // Broken Fallen Chair + AddImageTiledButton( 14, 108, 0x918, 0x919, 0x84, GumpButtonType.Reply, 0, 0x3DAA, 0x0, 20, -3 ); + AddTooltip( 1076611 ); + AddHtmlLocalized( 98, 108, 250, 60, 1076265, 0x7FFF, false, false ); // Suit of Gold Armor + AddImageTiledButton( 264, 108, 0x918, 0x919, 0x85, GumpButtonType.Reply, 0, 0x151C, 0x0, -20, -3 ); + AddTooltip( 1076612 ); + AddHtmlLocalized( 348, 108, 250, 60, 1076266, 0x7FFF, false, false ); // Suit of Silver Armor + AddImageTiledButton( 14, 172, 0x918, 0x919, 0x86, GumpButtonType.Reply, 0, 0x3DB1, 0x0, 18, 8 ); + AddTooltip( 1076613 ); + AddHtmlLocalized( 98, 172, 250, 60, 1076267, 0x7FFF, false, false ); // Boiling Cauldron + AddImageTiledButton( 264, 172, 0x918, 0x919, 0x87, GumpButtonType.Reply, 0, 0x3F27, 0x0, 18, 8 ); + AddTooltip( 1076614 ); + AddHtmlLocalized( 348, 172, 250, 60, 1024656, 0x7FFF, false, false ); // Guillotine + AddImageTiledButton( 14, 236, 0x918, 0x919, 0x88, GumpButtonType.Reply, 0, 0x3F0C, 0x0, 18, 8 ); + AddTooltip( 1076615 ); + AddHtmlLocalized( 98, 236, 250, 60, 1076268, 0x7FFF, false, false ); // Cherry Blossom Tree + AddImageTiledButton( 264, 236, 0x918, 0x919, 0x89, GumpButtonType.Reply, 0, 0x3F07, 0x0, 18, 8 ); + AddTooltip( 1076616 ); + AddHtmlLocalized( 348, 236, 250, 60, 1076269, 0x7FFF, false, false ); // Apple Tree + AddImageTiledButton( 14, 300, 0x918, 0x919, 0x8A, GumpButtonType.Reply, 0, 0x3F16, 0x0, 18, 8 ); + AddTooltip( 1076617 ); + AddHtmlLocalized( 98, 300, 250, 60, 1076270, 0x7FFF, false, false ); // Peach Tree + AddImageTiledButton( 264, 300, 0x918, 0x919, 0x8B, GumpButtonType.Reply, 0, 0x3F12, 0x0, 18, 8 ); + AddTooltip( 1076618 ); + AddHtmlLocalized( 348, 300, 250, 60, 1076271, 0x7FFF, false, false ); // Hanging Axes + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 5 ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( 5 ); + + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 4 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + AddImageTiledButton( 14, 44, 0x918, 0x919, 0x8C, GumpButtonType.Reply, 0, 0x3F13, 0x0, 18, 8 ); + AddTooltip( 1076619 ); + AddHtmlLocalized( 98, 44, 250, 60, 1076272, 0x7FFF, false, false ); // Hanging Swords + AddImageTiledButton( 264, 44, 0x918, 0x919, 0x8D, GumpButtonType.Reply, 0, 0x3F09, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 348, 44, 250, 60, 1076273, 0x7FFF, false, false ); // Blue fancy rug + AddImageTiledButton( 14, 108, 0x918, 0x919, 0x8E, GumpButtonType.Reply, 0, 0x3F0E, 0x0, 18, 8 ); + AddTooltip( 1076621 ); + AddHtmlLocalized( 98, 108, 250, 60, 1076274, 0x7FFF, false, false ); // Coffin + AddImageTiledButton( 264, 108, 0x918, 0x919, 0x8F, GumpButtonType.Reply, 0, 0x3F1F, 0x0, 18, 8 ); + AddTooltip( 1076623 ); + AddHtmlLocalized( 348, 108, 250, 60, 1074027, 0x7FFF, false, false ); // Vanity + AddImageTiledButton( 14, 172, 0x918, 0x919, 0x90, GumpButtonType.Reply, 0, 0x118B, 0x0, -4, -9 ); + AddTooltip( 1076624 ); + AddHtmlLocalized( 98, 172, 250, 60, 1076635, 0x7FFF, false, false ); // Table With A Purple
Tablecloth + AddImageTiledButton( 264, 172, 0x918, 0x919, 0x91, GumpButtonType.Reply, 0, 0x118C, 0x0, -4, -9 ); + AddTooltip( 1076624 ); + AddHtmlLocalized( 348, 172, 250, 60, 1076636, 0x7FFF, false, false ); // Table With A Blue
Tablecloth + AddImageTiledButton( 14, 236, 0x918, 0x919, 0x92, GumpButtonType.Reply, 0, 0x118D, 0x0, -4, -9 ); + AddTooltip( 1076624 ); + AddHtmlLocalized( 98, 236, 250, 60, 1076637, 0x7FFF, false, false ); // Table With A Red
Tablecloth + AddImageTiledButton( 264, 236, 0x918, 0x919, 0x93, GumpButtonType.Reply, 0, 0x118E, 0x0, -4, -9 ); + AddTooltip( 1076624 ); + AddHtmlLocalized( 348, 236, 250, 60, 1076638, 0x7FFF, false, false ); // Table With An Orange
Tablecloth + AddImageTiledButton( 14, 300, 0x918, 0x919, 0x94, GumpButtonType.Reply, 0, 0x3F1E, 0x0, 18, 8 ); + AddTooltip( 1076625 ); + AddHtmlLocalized( 98, 300, 250, 60, 1076279, 0x7FFF, false, false ); // Unmade Bed + AddImageTiledButton( 264, 300, 0x918, 0x919, 0x95, GumpButtonType.Reply, 0, 0x3F0F, 0x0, 18, 8 ); + AddTooltip( 1076626 ); + AddHtmlLocalized( 348, 300, 250, 60, 1076280, 0x7FFF, false, false ); // Curtains + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 6 ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( 6 ); + + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 5 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + AddImageTiledButton( 14, 44, 0x918, 0x919, 0x96, GumpButtonType.Reply, 0, 0x1E34, 0x0, 18, -17 ); + AddTooltip( 1076627 ); + AddHtmlLocalized( 98, 44, 250, 60, 1076281, 0x7FFF, false, false ); // Scarecrow + AddImageTiledButton( 264, 44, 0x918, 0x919, 0x97, GumpButtonType.Reply, 0, 0xA0C, 0x0, 18, 8 ); + AddTooltip( 1076628 ); + AddHtmlLocalized( 348, 44, 250, 60, 1076282, 0x7FFF, false, false ); // Wall Torch + AddImageTiledButton( 14, 108, 0x918, 0x919, 0x98, GumpButtonType.Reply, 0, 0x3F10, 0x0, 18, 9 ); + AddTooltip( 1076629 ); + AddHtmlLocalized( 98, 108, 250, 60, 1076283, 0x7FFF, false, false ); // Fountain + AddImageTiledButton( 264, 108, 0x918, 0x919, 0x99, GumpButtonType.Reply, 0, 0x3F19, 0x0, 18, 8 ); + AddTooltip( 1076630 ); + AddHtmlLocalized( 348, 108, 250, 60, 1076284, 0x7FFF, false, false ); // Statue + AddImageTiledButton( 14, 172, 0x918, 0x919, 0x9A, GumpButtonType.Reply, 0, 0x1EA5, 0x0, 5, -25 ); + AddTooltip( 1076631 ); + AddHtmlLocalized( 98, 172, 250, 60, 1076285, 0x7FFF, false, false ); // Large Fish Net + AddImageTiledButton( 264, 172, 0x918, 0x919, 0x9B, GumpButtonType.Reply, 0, 0x1EA3, 0x0, 18, -27 ); + AddTooltip( 1076632 ); + AddHtmlLocalized( 348, 172, 250, 60, 1076286, 0x7FFF, false, false ); // Small Fish Net + AddImageTiledButton( 14, 236, 0x918, 0x919, 0x9C, GumpButtonType.Reply, 0, 0x2FDF, 0x0, 18, -36 ); + AddTooltip( 1076633 ); + AddHtmlLocalized( 98, 236, 250, 60, 1076287, 0x7FFF, false, false ); // Ladder + AddImageTiledButton( 264, 236, 0x918, 0x919, 0x9D, GumpButtonType.Reply, 0, 0x3F15, 0x0, 18, 8 ); + AddTooltip( 1076622 ); + AddHtmlLocalized( 348, 236, 250, 60, 1076288, 0x7FFF, false, false ); // Iron Maiden + AddImageTiledButton( 14, 300, 0x918, 0x919, 0x9E, GumpButtonType.Reply, 0, 0x3F0A, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 98, 300, 250, 60, 1076585, 0x7FFF, false, false ); // Blue plain rug + AddImageTiledButton( 264, 300, 0x918, 0x919, 0x9F, GumpButtonType.Reply, 0, 0x3F11, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 348, 300, 250, 60, 1076586, 0x7FFF, false, false ); // Golden decorative rug + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, 7 ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + + AddPage( 7 ); + + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 6 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + AddImageTiledButton( 14, 44, 0x918, 0x919, 0xA0, GumpButtonType.Reply, 0, 0x3F0D, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 98, 44, 250, 60, 1076587, 0x7FFF, false, false ); // Cinnamon fancy rug + AddImageTiledButton( 264, 44, 0x918, 0x919, 0xA1, GumpButtonType.Reply, 0, 0x3F18, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 348, 44, 250, 60, 1076588, 0x7FFF, false, false ); // Red plain rug + AddImageTiledButton( 14, 108, 0x918, 0x919, 0xA2, GumpButtonType.Reply, 0, 0x3F08, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 98, 108, 250, 60, 1076589, 0x7FFF, false, false ); // Blue decorative rug + AddImageTiledButton( 264, 108, 0x918, 0x919, 0xA3, GumpButtonType.Reply, 0, 0x3F17, 0x0, 18, 8 ); + AddTooltip( 1076620 ); + AddHtmlLocalized( 348, 108, 250, 60, 1076590, 0x7FFF, false, false ); // Pink fancy rug + AddImageTiledButton( 14, 172, 0x918, 0x919, 0xA4, GumpButtonType.Reply, 0, 0x312A, 0x0, 18, 8 ); + AddTooltip( 1076615 ); + AddHtmlLocalized( 98, 172, 250, 60, 1076784, 0x7FFF, false, false ); // Cherry Blossom Trunk + AddImageTiledButton( 264, 172, 0x918, 0x919, 0xA5, GumpButtonType.Reply, 0, 0x3128, 0x0, 18, 8 ); + AddTooltip( 1076616 ); + AddHtmlLocalized( 348, 172, 250, 60, 1076785, 0x7FFF, false, false ); // Apple Trunk + AddImageTiledButton( 14, 236, 0x918, 0x919, 0xA6, GumpButtonType.Reply, 0, 0x3129, 0x0, 18, 8 ); + AddTooltip( 1076617 ); + AddHtmlLocalized( 98, 236, 250, 60, 1076786, 0x7FFF, false, false ); // Peach Trunk + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Token == null || m_Token.Deleted || info.ButtonID == 0 ) + return; + + List types = new List(); + int cliloc = 0; + + switch ( info.ButtonID ) + { + // 7th anniversary + case 0x64: types.Add( typeof( LeggingsOfEmbers ) ); cliloc = 1078147; break; + case 0x65: types.Add( typeof( RoseOfTrinsic ) ); cliloc = 1062913; break; + case 0x66: types.Add( typeof( ShaminoCrossbow ) ); cliloc = 1062915; break; + case 0x67: types.Add( typeof( TapestryOfSosaria ) ); cliloc = 1062917; break; + case 0x68: types.Add( typeof( HearthOfHomeFireDeed ) ); cliloc = 1062919; break; + case 0x69: types.Add( typeof( HolySword ) ); cliloc = 1062921; break; + case 0x6A: types.Add( typeof( SamuraiHelm ) ); cliloc = 1062923; break; + + // 8th anniversary + /*case 0x6B: types.Add( typeof( SpiritualityHelm ) ); cliloc = 1075188; break; + case 0x6C: types.Add( typeof( ValorGauntlets ) ); cliloc = 1075192; break;*/ + case 0x6D: types.Add( typeof( DupresShield ) ); cliloc = 1075196; break; + case 0x6E: types.Add( typeof( FountainOfLifeDeed ) ); cliloc = 1075197; break; + case 0x6F: types.Add( typeof( DawnsMusicBox ) ); cliloc = 1075198; break; + case 0x70: types.Add( typeof( OssianGrimoire ) ); cliloc = 1078148; break; + case 0x71: types.Add( typeof( FerretFormTalisman ) ); cliloc = 1078142; break; + case 0x72: types.Add( typeof( SquirrelFormTalisman ) ); cliloc = 1078143; break; + case 0x73: types.Add( typeof( CuSidheFormTalisman ) ); cliloc = 1078144; break; + case 0x74: types.Add( typeof( ReptalonFormTalisman ) ); cliloc = 1078145; break; + case 0x75: types.Add( typeof( QuiverOfInfinity ) ); cliloc = 1075201; break; + + // evil home decor + case 0x76: + types.Add( typeof( BoneThroneDeed ) ); + types.Add( typeof( BoneCouchDeed ) ); + types.Add( typeof( BoneTableDeed ) ); + cliloc = 1074797; + break; + case 0x77: + types.Add( typeof( CreepyPortraitDeed ) ); + types.Add( typeof( DisturbingPortraitDeed ) ); + types.Add( typeof( UnsettlingPortraitDeed ) ); + cliloc = 1078146; + break; + case 0x78: + types.Add( typeof( MountedPixieBlueDeed ) ); + types.Add( typeof( MountedPixieGreenDeed ) ); + types.Add( typeof( MountedPixieLimeDeed ) ); + types.Add( typeof( MountedPixieOrangeDeed ) ); + types.Add( typeof( MountedPixieWhiteDeed ) ); + cliloc = 1074799; + break; + case 0x79: types.Add( typeof( HaunterMirrorDeed ) ); cliloc = 1074800; break; + case 0x7A: types.Add( typeof( BedOfNailsDeed ) ); cliloc = 1074801; break; + case 0x7B: types.Add( typeof( SacrificialAltarDeed ) ); cliloc = 1074818; break; + + // broken furniture + case 0x7C: types.Add( typeof( BrokenCoveredChairDeed ) ); cliloc = 1076257; break; + case 0x7D: types.Add( typeof( BrokenBookcaseDeed ) ); cliloc = 1076258; break; + case 0x7E: types.Add( typeof( StandingBrokenChairDeed ) ); cliloc = 1076259; break; + case 0x7F: types.Add( typeof( BrokenVanityDeed ) ); cliloc = 1076260; break; + case 0x80: types.Add( typeof( BrokenChestOfDrawersDeed ) ); cliloc = 1076261; break; + case 0x81: types.Add( typeof( BrokenArmoireDeed ) ); cliloc = 1076262; break; + case 0x82: types.Add( typeof( BrokenBedDeed ) ); cliloc = 1076263; break; + case 0x83: types.Add( typeof( BrokenFallenChairDeed ) ); cliloc = 1076264; break; + + // other + case 0x84: types.Add( typeof( SuitOfGoldArmorDeed ) ); cliloc = 1076265; break; + case 0x85: types.Add( typeof( SuitOfSilverArmorDeed ) ); cliloc = 1076266; break; + case 0x86: types.Add( typeof( BoilingCauldronDeed ) ); cliloc = 1076267; break; + case 0x87: types.Add( typeof( GuillotineDeed ) ); cliloc = 1024656; break; + case 0x88: types.Add( typeof( CherryBlossomTreeDeed ) ); cliloc = 1076268; break; + case 0x89: types.Add( typeof( AppleTreeDeed ) ); cliloc = 1076269; break; + case 0x8A: types.Add( typeof( PeachTreeDeed ) ); cliloc = 1076270; break; + case 0x8B: types.Add( typeof( HangingAxesDeed ) ); cliloc = 1076271; break; + case 0x8C: types.Add( typeof( HangingSwordsDeed ) ); cliloc = 1076272; break; + case 0x8D: types.Add( typeof( BlueFancyRugDeed ) ); cliloc = 1076273; break; + case 0x8E: types.Add( typeof( WoodenCoffinDeed ) ); cliloc = 1076274; break; + case 0x8F: types.Add( typeof( VanityDeed ) ); cliloc = 1074027; break; + case 0x90: types.Add( typeof( TableWithPurpleClothDeed ) ); cliloc = 1076635; break; + case 0x91: types.Add( typeof( TableWithBlueClothDeed ) ); cliloc = 1076636; break; + case 0x92: types.Add( typeof( TableWithRedClothDeed ) ); cliloc = 1076637; break; + case 0x93: types.Add( typeof( TableWithOrangeClothDeed ) ); cliloc = 1076638; break; + case 0x94: types.Add( typeof( UnmadeBedDeed ) ); cliloc = 1076279; break; + case 0x95: types.Add( typeof( CurtainsDeed ) ); cliloc = 1076280; break; + case 0x96: types.Add( typeof( ScarecrowDeed ) ); cliloc = 1076281; break; + case 0x97: types.Add( typeof( WallTorchDeed ) ); cliloc = 1076282; break; + case 0x98: types.Add( typeof( FountainDeed ) ); cliloc = 1076283; break; + case 0x99: types.Add( typeof( StoneStatueDeed ) ); cliloc = 1076284; break; + case 0x9A: types.Add( typeof( LargeFishingNetDeed ) ); cliloc = 1076285; break; + case 0x9B: types.Add( typeof( SmallFishingNetDeed ) ); cliloc = 1076286; break; + case 0x9C: types.Add( typeof( HouseLadderDeed ) ); cliloc = 1076287; break; + case 0x9D: types.Add( typeof( IronMaidenDeed ) ); cliloc = 1076288; break; + case 0x9E: types.Add( typeof( BluePlainRugDeed ) ); cliloc = 1076585; break; + case 0x9F: types.Add( typeof( GoldenDecorativeRugDeed ) ); cliloc = 1076586; break; + case 0xA0: types.Add( typeof( CinnamonFancyRugDeed ) ); cliloc = 1076587; break; + case 0xA1: types.Add( typeof( RedPlainRugDeed ) ); cliloc = 1076588; break; + case 0xA2: types.Add( typeof( BlueDecorativeRugDeed ) ); cliloc = 1076589; break; + case 0xA3: types.Add( typeof( PinkFancyRugDeed ) ); cliloc = 1076590; break; + case 0xA4: types.Add( typeof( CherryBlossomTrunkDeed ) ); cliloc = 1076784; break; + case 0xA5: types.Add( typeof( AppleTrunkDeed ) ); cliloc = 1076785; break; + case 0xA6: types.Add( typeof( PeachTrunkDeed ) ); cliloc = 1076786; break; + } + + if ( types.Count > 0 && cliloc > 0 ) + { + sender.Mobile.CloseGump( typeof( ConfirmHeritageGump ) ); + sender.Mobile.SendGump( new ConfirmHeritageGump( m_Token, types.ToArray(), cliloc ) ); + } + else + sender.Mobile.SendLocalizedMessage( 501311 ); // This option is currently disabled, while we evaluate it for game balance. + } + } +} diff --git a/Scripts/Gumps/Honorself.cs b/Scripts/Gumps/Honorself.cs new file mode 100644 index 0000000..95fee23 --- /dev/null +++ b/Scripts/Gumps/Honorself.cs @@ -0,0 +1,36 @@ +using System; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Accounting; + +namespace Server.Gumps +{ + public class HonorSelf : Gump + { + PlayerMobile m_from; + public HonorSelf(PlayerMobile from) + : base(150, 50) + { + m_from = from; + AddBackground(0, 0, 245, 145, 9250); + AddButton(157, 101, 247, 248, 1, GumpButtonType.Reply, 0); + AddButton(81, 100, 241, 248, 0, GumpButtonType.Reply, 0); + AddHtml(21, 20, 203, 70, @"Are you sure you want to use +honor points on yourself?", true, false); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + + if (info.ButtonID == 1) + { + HonorVirtue.ActivateEmbrace(m_from); + } + else + { + return; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/HouseDemolishGump.cs b/Scripts/Gumps/HouseDemolishGump.cs new file mode 100644 index 0000000..5821ecb --- /dev/null +++ b/Scripts/Gumps/HouseDemolishGump.cs @@ -0,0 +1,148 @@ +using System; +using Server; +using Server.Items; +using Server.Multis; +using Server.Multis.Deeds; +using Server.Network; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class HouseDemolishGump : Gump + { + private Mobile m_Mobile; + private BaseHouse m_House; + + public HouseDemolishGump( Mobile mobile, BaseHouse house ) : base( 110, 100 ) + { + m_Mobile = mobile; + m_House = house; + + mobile.CloseGump( typeof( HouseDemolishGump ) ); + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 280, 5054 ); + + AddImageTiled( 10, 10, 400, 20, 2624 ); + AddAlphaRegion( 10, 10, 400, 20 ); + + AddHtmlLocalized( 10, 10, 400, 20, 1060635, 30720, false, false ); //
WARNING
+ + AddImageTiled( 10, 40, 400, 200, 2624 ); + AddAlphaRegion( 10, 40, 400, 200 ); + + AddHtmlLocalized( 10, 40, 400, 200, 1061795, 32512, false, true ); /* You are about to demolish your house. + * You will be refunded the house's value directly to your bank box. + * All items in the house will remain behind and can be freely picked up by anyone. + * Once the house is demolished, anyone can attempt to place a new house on the vacant land. + * This action will not un-condemn any other houses on your account, nor will it end your 7-day waiting period (if it applies to you). + * Are you sure you wish to continue? + */ + + AddImageTiled( 10, 250, 400, 20, 2624 ); + AddAlphaRegion( 10, 250, 400, 20 ); + + AddButton( 10, 250, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 250, 170, 20, 1011036, 32767, false, false ); // OKAY + + AddButton( 210, 250, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 240, 250, 170, 20, 1011012, 32767, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 1 && !m_House.Deleted ) + { + if ( m_House.IsOwner( m_Mobile ) ) + { + if ( m_House.MovingCrate != null || m_House.InternalizedVendors.Count > 0 ) + { + return; + } + else if( !Guilds.Guild.NewGuildSystem && m_House.FindGuildstone() != null ) + { + m_Mobile.SendLocalizedMessage( 501389 ); // You cannot redeed a house with a guildstone inside. + return; + } + /*else if ( m_House.PlayerVendors.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 503236 ); // You need to collect your vendor's belongings before moving. + return; + }*/ + else if ( m_House.HasRentedVendors && m_House.VendorInventories.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 1062679 ); // You cannot do that that while you still have contract vendors or unclaimed contract vendor inventory in your house. + return; + } + else if ( m_House.HasRentedVendors ) + { + m_Mobile.SendLocalizedMessage( 1062680 ); // You cannot do that that while you still have contract vendors in your house. + return; + } + else if ( m_House.VendorInventories.Count > 0 ) + { + m_Mobile.SendLocalizedMessage( 1062681 ); // You cannot do that that while you still have unclaimed contract vendor inventory in your house. + return; + } + + + if ( m_Mobile.AccessLevel >= AccessLevel.GameMaster ) + { + m_Mobile.SendMessage( "You do not get a refund for your house as you are not a player" ); + m_House.RemoveKeys(m_Mobile); + m_House.Delete(); + } + else + { + Item toGive = null; + + if ( m_House.IsAosRules ) + { + if ( m_House.Price > 0 ) + toGive = new BankCheck( m_House.Price ); + else + toGive = m_House.GetDeed(); + } + else + { + toGive = m_House.GetDeed(); + + if ( toGive == null && m_House.Price > 0 ) + toGive = new BankCheck( m_House.Price ); + } + + if ( toGive != null ) + { + BankBox box = m_Mobile.BankBox; + + if ( box.TryDropItem( m_Mobile, toGive, false ) ) + { + if ( toGive is BankCheck ) + m_Mobile.SendLocalizedMessage( 1060397, ( (BankCheck)toGive ).Worth.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + + m_House.RemoveKeys( m_Mobile ); + m_House.Delete(); + } + else + { + toGive.Delete(); + m_Mobile.SendLocalizedMessage( 500390 ); // Your bank box is full. + } + } + else + { + m_Mobile.SendMessage( "Unable to refund house." ); + } + } + } + else + { + m_Mobile.SendLocalizedMessage( 501320 ); // Only the house owner may do this. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/HouseGump.cs b/Scripts/Gumps/HouseGump.cs new file mode 100644 index 0000000..b0e58e7 --- /dev/null +++ b/Scripts/Gumps/HouseGump.cs @@ -0,0 +1,755 @@ +using System; +using System.Reflection; +using System.Collections; +using Server.Network; +using Server.Prompts; +using Server.Multis; +using Server.Multis.Deeds; +using Server.Items; + +namespace Server.Gumps +{ + public class HouseListGump : Gump + { + private BaseHouse m_House; + + public HouseListGump( int number, ArrayList list, BaseHouse house, bool accountOf ) : base( 20, 30 ) + { + if ( house.Deleted ) + return; + + m_House = house; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 430, 5054 ); + AddBackground( 10, 10, 400, 410, 3000 ); + + AddButton( 20, 388, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 388, 300, 20, 1011104, false, false ); // Return to previous menu + + AddHtmlLocalized( 20, 20, 350, 20, number, false, false ); + + if ( list != null ) + { + for ( int i = 0; i < list.Count; ++i ) + { + if ( (i % 16) == 0 ) + { + if ( i != 0 ) + { + // Next button + AddButton( 370, 20, 4005, 4007, 0, GumpButtonType.Page, (i / 16) + 1 ); + } + + AddPage( (i / 16) + 1 ); + + if ( i != 0 ) + { + // Previous button + AddButton( 340, 20, 4014, 4016, 0, GumpButtonType.Page, i / 16 ); + } + } + + Mobile m = (Mobile)list[i]; + + string name; + + if ( m == null || (name = m.Name) == null || (name = name.Trim()).Length <= 0 ) + continue; + + AddLabel( 55, 55 + ((i % 16) * 20), 0, accountOf && m.Player && m.Account != null ? String.Format( "Account of {0}", name ) : name ); + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( m_House.Deleted ) + return; + + Mobile from = state.Mobile; + + from.SendGump( new HouseGump( from, m_House ) ); + } + } + + public class HouseRemoveGump : Gump + { + private BaseHouse m_House; + private ArrayList m_List, m_Copy; + private int m_Number; + private bool m_AccountOf; + + public HouseRemoveGump( int number, ArrayList list, BaseHouse house, bool accountOf ) : base( 20, 30 ) + { + if ( house.Deleted ) + return; + + m_House = house; + m_List = list; + m_Number = number; + m_AccountOf = accountOf; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 430, 5054 ); + AddBackground( 10, 10, 400, 410, 3000 ); + + AddButton( 20, 388, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 388, 300, 20, 1011104, false, false ); // Return to previous menu + + AddButton( 20, 365, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 365, 300, 20, 1011270, false, false ); // Remove now! + + AddHtmlLocalized( 20, 20, 350, 20, number, false, false ); + + if ( list != null ) + { + m_Copy = new ArrayList( list ); + + for ( int i = 0; i < list.Count; ++i ) + { + if ( (i % 15) == 0 ) + { + if ( i != 0 ) + { + // Next button + AddButton( 370, 20, 4005, 4007, 0, GumpButtonType.Page, (i / 15) + 1 ); + } + + AddPage( (i / 15) + 1 ); + + if ( i != 0 ) + { + // Previous button + AddButton( 340, 20, 4014, 4016, 0, GumpButtonType.Page, i / 15 ); + } + } + + Mobile m = (Mobile)list[i]; + + string name; + + if ( m == null || (name = m.Name) == null || (name = name.Trim()).Length <= 0 ) + continue; + + AddCheck( 34, 52 + ((i % 15) * 20), 0xD2, 0xD3, false, i ); + AddLabel( 55, 52 + ((i % 15) * 20), 0, accountOf && m.Player && m.Account != null ? String.Format( "Account of {0}", name ) : name ); + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( m_House.Deleted ) + return; + + Mobile from = state.Mobile; + + if ( m_List != null && info.ButtonID == 1 ) // Remove now + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + for ( int i = 0; i < switches.Length; ++i ) + { + int index = switches[i]; + + if ( index >= 0 && index < m_Copy.Count ) + m_List.Remove( m_Copy[index] ); + } + + if ( m_List.Count > 0 ) + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseRemoveGump( m_Number, m_List, m_House, m_AccountOf ) ); + return; + } + } + } + + from.SendGump( new HouseGump( from, m_House ) ); + } + } + + public class HouseGump : Gump + { + private BaseHouse m_House; + + private ArrayList Wrap( string value ) + { + if ( value == null || (value = value.Trim()).Length <= 0 ) + return null; + + string[] values = value.Split( ' ' ); + ArrayList list = new ArrayList(); + string current = ""; + + for ( int i = 0; i < values.Length; ++i ) + { + string val = values[i]; + + string v = current.Length == 0 ? val : current + ' ' + val; + + if ( v.Length < 10 ) + { + current = v; + } + else if ( v.Length == 10 ) + { + list.Add( v ); + + if ( list.Count == 6 ) + return list; + + current = ""; + } + else if ( val.Length <= 10 ) + { + list.Add( current ); + + if ( list.Count == 6 ) + return list; + + current = val; + } + else + { + while ( v.Length >= 10 ) + { + list.Add( v.Substring( 0, 10 ) ); + + if ( list.Count == 6 ) + return list; + + v = v.Substring( 10 ); + } + + current = v; + } + } + + if ( current.Length > 0 ) + list.Add( current ); + + return list; + } + + public HouseGump( Mobile from, BaseHouse house ) : base( 20, 30 ) + { + if ( house.Deleted ) + return; + + m_House = house; + + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + + bool isCombatRestricted = house.IsCombatRestricted( from ); + + bool isOwner = m_House.IsOwner( from ); + bool isCoOwner = isOwner || m_House.IsCoOwner( from ); + bool isFriend = isCoOwner || m_House.IsFriend( from ); + + if ( isCombatRestricted ) + isFriend = isCoOwner = isOwner = false; + + AddPage( 0 ); + + if ( isFriend ) + { + AddBackground( 0, 0, 420, 430, 5054 ); + AddBackground( 10, 10, 400,410, 3000 ); + } + + AddImage( 130, 0, 100 ); + + if ( m_House.Sign != null ) + { + ArrayList lines = Wrap( m_House.Sign.GetName() ); + + if ( lines != null ) + { + for ( int i = 0, y = (101 - (lines.Count * 14)) / 2; i < lines.Count; ++i, y += 14 ) + { + string s = (string)lines[i]; + + AddLabel( 130 + ((143 - (s.Length * 8)) / 2), y, 0, s ); + } + } + } + + if ( !isFriend ) + return; + + AddHtmlLocalized( 55, 103, 75, 20, 1011233, false, false ); // INFO + AddButton( 20, 103, 4005, 4007, 0, GumpButtonType.Page, 1 ); + + AddHtmlLocalized( 170, 103, 75, 20, 1011234, false, false ); // FRIENDS + AddButton( 135, 103, 4005, 4007, 0, GumpButtonType.Page, 2 ); + + AddHtmlLocalized( 295, 103, 75, 20, 1011235, false, false ); // OPTIONS + AddButton( 260, 103, 4005, 4007, 0, GumpButtonType.Page, 3 ); + + AddHtmlLocalized( 295, 390, 75, 20, 1011441, false, false ); // EXIT + AddButton( 260, 390, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 390, 200, 20, 1011236, false, false ); // Change this house's name! + AddButton( 20, 390, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + // Info page + AddPage( 1 ); + + AddHtmlLocalized( 20, 135, 100, 20, 1011242, false, false ); // Owned by: + AddHtml( 120, 135, 100, 20, GetOwnerName(), false, false ); + + AddHtmlLocalized( 20, 170, 275, 20, 1011237, false, false ); // Number of locked down items: + AddHtml( 320, 170, 50, 20, m_House.LockDownCount.ToString(), false, false ); + + AddHtmlLocalized( 20, 190, 275, 20, 1011238, false, false ); // Maximum locked down items: + AddHtml( 320, 190, 50, 20, m_House.MaxLockDowns.ToString(), false, false ); + + AddHtmlLocalized( 20, 210, 275, 20, 1011239, false, false ); // Number of secure containers: + AddHtml( 320, 210, 50, 20, m_House.SecureCount.ToString(), false, false ); + + AddHtmlLocalized( 20, 230, 275, 20, 1011240, false, false ); // Maximum number of secure containers: + AddHtml( 320, 230, 50, 20, m_House.MaxSecures.ToString(), false, false ); + + AddHtmlLocalized( 20, 260, 400, 20, 1018032, false, false ); // This house is properly placed. + AddHtmlLocalized( 20, 280, 400, 20, 1018035, false, false ); // This house is of modern design. + + if ( m_House.Public ) + { + // TODO: Validate exact placement + AddHtmlLocalized( 20, 305, 275, 20, 1011241, false, false ); // Number of visits this building has had + AddHtml( 320, 305, 50, 20, m_House.Visits.ToString(), false, false ); + } + + // Friends page + AddPage( 2 ); + + AddHtmlLocalized( 45, 130, 150, 20, 1011266, false, false ); // List of co-owners + AddButton( 20, 130, 2714, 2715, 2, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 45, 150, 150, 20, 1011267, false, false ); // Add a co-owner + AddButton( 20, 150, 2714, 2715, 3, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 45, 170, 150, 20, 1018036, false, false ); // Remove a co-owner + AddButton( 20, 170, 2714, 2715, 4, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 45, 190, 150, 20, 1011268, false, false ); // Clear co-owner list + AddButton( 20, 190, 2714, 2715, 5, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 225, 130, 155, 20, 1011243, false, false ); // List of Friends + AddButton( 200, 130, 2714, 2715, 6, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 225, 150, 155, 20, 1011244, false, false ); // Add a Friend + AddButton( 200, 150, 2714, 2715, 7, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 225, 170, 155, 20, 1018037, false, false ); // Remove a Friend + AddButton( 200, 170, 2714, 2715, 8, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 225, 190, 155, 20, 1011245, false, false ); // Clear Friends list + AddButton( 200, 190, 2714, 2715, 9, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 120, 215, 280, 20, 1011258, false, false ); // Ban someone from the house + AddButton( 95, 215, 2714, 2715, 10, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 120, 235, 280, 20, 1011259, false, false ); // Eject someone from the house + AddButton( 95, 235, 2714, 2715, 11, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 120, 255, 280, 20, 1011260, false, false ); // View a list of banned people + AddButton( 95, 255, 2714, 2715, 12, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 120, 275, 280, 20, 1011261, false, false ); // Lift a ban + AddButton( 95, 275, 2714, 2715, 13, GumpButtonType.Reply, 0 ); + + // Options page + AddPage( 3 ); + + AddHtmlLocalized( 45, 150, 355, 30, 1011248, false, false ); // Transfer ownership of the house + AddButton( 20, 150, 2714, 2715, 14, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 45, 180, 355, 30, 1011249, false, false ); // Demolish house and get deed back + AddButton( 20, 180, 2714, 2715, 15, GumpButtonType.Reply, 0 ); + + if ( !m_House.Public ) + { + AddHtmlLocalized( 45, 210, 355, 30, 1011247, false, false ); // Change the house locks + AddButton( 20, 210, 2714, 2715, 16, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 45, 240, 350, 90, 1011253, false, false ); // Declare this building to be public. This will make your front door unlockable. + AddButton( 20, 240, 2714, 2715, 17, GumpButtonType.Reply, 0 ); + } + else + { + //AddHtmlLocalized( 45, 280, 350, 30, 1011250, false, false ); // Change the sign type + AddHtmlLocalized( 45, 210, 350, 30, 1011250, false, false ); // Change the sign type + AddButton( 20, 210, 2714, 2715, 0, GumpButtonType.Page, 4 ); + + AddHtmlLocalized( 45, 240, 350, 30, 1011252, false, false ); // Declare this building to be private. + AddButton( 20, 240, 2714, 2715, 17, GumpButtonType.Reply, 0 ); + + // Change the sign type + AddPage( 4 ); + + for ( int i = 0; i < 24; ++i ) + { + AddRadio( 53 + ((i / 4) * 50), 137 + ((i % 4) * 35), 210, 211, false, i + 1 ); + AddItem( 60 + ((i / 4) * 50), 130 + ((i % 4) * 35), 2980 + (i * 2) ); + } + + AddHtmlLocalized( 200, 305, 129, 20, 1011254, false, false ); // Guild sign choices + AddButton( 350, 305, 252, 253, 0, GumpButtonType.Page, 5 ); + + AddHtmlLocalized( 200, 340, 355, 30, 1011277, false, false ); // Okay that is fine. + AddButton( 350, 340, 4005, 4007, 18, GumpButtonType.Reply, 0 ); + + AddPage( 5 ); + + for ( int i = 0; i < 29; ++i ) + { + AddRadio( 53 + ((i / 5) * 50), 137 + ((i % 5) * 35), 210, 211, false, i + 25 ); + AddItem( 60 + ((i / 5) * 50), 130 + ((i % 5) * 35), 3028 + (i * 2) ); + } + + AddHtmlLocalized( 200, 305, 129, 20, 1011255, false, false ); // Shop sign choices + AddButton( 350, 305, 250, 251, 0, GumpButtonType.Page, 4 ); + + AddHtmlLocalized( 200, 340, 355, 30, 1011277, false, false ); // Okay that is fine. + AddButton( 350, 340, 4005, 4007, 18, GumpButtonType.Reply, 0 ); + } + } + + private string GetOwnerName() + { + Mobile m = m_House.Owner; + + if ( m == null ) + return "(unowned)"; + + string name; + + if ( (name = m.Name) == null || (name = name.Trim()).Length <= 0 ) + name = "(no name)"; + + return name; + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_House.Deleted ) + return; + + Mobile from = sender.Mobile; + + bool isCombatRestricted = m_House.IsCombatRestricted( from ); + + bool isOwner = m_House.IsOwner( from ); + bool isCoOwner = isOwner || m_House.IsCoOwner( from ); + bool isFriend = isCoOwner || m_House.IsFriend( from ); + + if ( isCombatRestricted ) + isFriend = isCoOwner = isOwner = false; + + if ( !isFriend || !from.Alive ) + return; + + Item sign = m_House.Sign; + + if ( sign == null || from.Map != sign.Map || !from.InRange( sign.GetWorldLocation(), 18 ) ) + return; + + switch ( info.ButtonID ) + { + case 1: // Rename sign + { + from.Prompt = new RenamePrompt( m_House ); + from.SendLocalizedMessage( 501302 ); // What dost thou wish the sign to say? + + break; + } + case 2: // List of co-owners + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseListGump( 1011275, m_House.CoOwners, m_House, false ) ); + + break; + } + case 3: // Add co-owner + { + if ( isOwner ) + { + from.SendLocalizedMessage( 501328 ); // Target the person you wish to name a co-owner of your household. + from.Target = new CoOwnerTarget( true, m_House ); + } + else + { + from.SendLocalizedMessage( 501327 ); // Only the house owner may add Co-owners. + } + + break; + } + case 4: // Remove co-owner + { + if ( isOwner ) + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseRemoveGump( 1011274, m_House.CoOwners, m_House, false ) ); + } + else + { + from.SendLocalizedMessage( 501329 ); // Only the house owner may remove co-owners. + } + + break; + } + case 5: // Clear co-owners + { + if ( isOwner ) + { + if ( m_House.CoOwners != null ) + m_House.CoOwners.Clear(); + + from.SendLocalizedMessage( 501333 ); // All co-owners have been removed from this house. + } + else + { + from.SendLocalizedMessage( 501330 ); // Only the house owner may remove co-owners. + } + + break; + } + case 6: // List friends + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseListGump( 1011273, m_House.Friends, m_House, false ) ); + + break; + } + case 7: // Add friend + { + if ( isCoOwner ) + { + from.SendLocalizedMessage( 501317 ); // Target the person you wish to name a friend of your household. + from.Target = new HouseFriendTarget( true, m_House ); + } + else + { + from.SendLocalizedMessage( 501316 ); // Only the house owner may add friends. + } + + break; + } + case 8: // Remove friend + { + if ( isCoOwner ) + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseRemoveGump( 1011272, m_House.Friends, m_House, false ) ); + } + else + { + from.SendLocalizedMessage( 501318 ); // Only the house owner may remove friends. + } + + break; + } + case 9: // Clear friends + { + if ( isCoOwner ) + { + if ( m_House.Friends != null ) + m_House.Friends.Clear(); + + from.SendLocalizedMessage( 501332 ); // All friends have been removed from this house. + } + else + { + from.SendLocalizedMessage( 501319 ); // Only the house owner may remove friends. + } + + break; + } + case 10: // Ban + { + from.SendLocalizedMessage( 501325 ); // Target the individual to ban from this house. + from.Target = new HouseBanTarget( true, m_House ); + + break; + } + case 11: // Eject + { + from.SendLocalizedMessage( 501326 ); // Target the individual to eject from this house. + from.Target = new HouseKickTarget( m_House ); + + break; + } + case 12: // List bans + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseListGump( 1011271, m_House.Bans, m_House, true ) ); + + break; + } + case 13: // Remove ban + { + from.CloseGump( typeof( HouseGump ) ); + from.CloseGump( typeof( HouseListGump ) ); + from.CloseGump( typeof( HouseRemoveGump ) ); + from.SendGump( new HouseRemoveGump( 1011269, m_House.Bans, m_House, true ) ); + + break; + } + case 14: // Transfer ownership + { + if ( isOwner ) + { + from.SendLocalizedMessage( 501309 ); // Target the person to whom you wish to give this house. + from.Target = new HouseOwnerTarget( m_House ); + } + else + { + from.SendLocalizedMessage( 501310 ); // Only the house owner may do this. + } + + break; + } + case 15: // Demolish house + { + if ( isOwner ) + { + if ( !Guilds.Guild.NewGuildSystem && m_House.FindGuildstone() != null ) + { + from.SendLocalizedMessage( 501389 ); // You cannot redeed a house with a guildstone inside. + } + else + { + from.CloseGump( typeof( HouseDemolishGump ) ); + from.SendGump( new HouseDemolishGump( from, m_House ) ); + } + } + else + { + from.SendLocalizedMessage( 501320 ); // Only the house owner may do this. + } + + break; + } + case 16: // Change locks + { + if ( m_House.Public ) + { + from.SendLocalizedMessage( 501669 );// Public houses are always unlocked. + } + else + { + if ( isOwner ) + { + m_House.RemoveKeys( from ); + m_House.ChangeLocks( from ); + + from.SendLocalizedMessage( 501306 ); // The locks on your front door have been changed, and new master keys have been placed in your bank and your backpack. + } + else + { + from.SendLocalizedMessage( 501303 ); // Only the house owner may change the house locks. + } + } + + break; + } + case 17: // Declare public/private + { + if ( isOwner ) + { + if ( m_House.Public && m_House.PlayerVendors.Count > 0 ) + { + from.SendLocalizedMessage( 501887 ); // You have vendors working out of this building. It cannot be declared private until there are no vendors in place. + break; + } + + m_House.Public = !m_House.Public; + if ( !m_House.Public ) + { + m_House.ChangeLocks( from ); + + from.SendLocalizedMessage( 501888 ); // This house is now private. + from.SendLocalizedMessage( 501306 ); // The locks on your front door have been changed, and new master keys have been placed in your bank and your backpack. + } + else + { + m_House.RemoveKeys( from ); + m_House.RemoveLocks(); + from.SendLocalizedMessage( 501886 );//This house is now public. Friends of the house my now have vendors working out of this building. + } + } + else + { + from.SendLocalizedMessage( 501307 ); // Only the house owner may do this. + } + + break; + } + case 18: // Change type + { + if ( isOwner ) + { + if ( m_House.Public && info.Switches.Length > 0 ) + { + int index = info.Switches[0] - 1; + + if ( index >= 0 && index < 53 ) + m_House.ChangeSignType( 2980 + (index * 2) ); + } + } + else + { + from.SendLocalizedMessage( 501307 ); // Only the house owner may do this. + } + + break; + } + } + } + } +} + +namespace Server.Prompts +{ + public class RenamePrompt : Prompt + { + private BaseHouse m_House; + + public RenamePrompt( BaseHouse house ) + { + m_House = house; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_House.IsFriend( from ) ) + { + if ( m_House.Sign != null ) + m_House.Sign.Name = text; + + from.SendMessage( "Sign changed." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/HouseGumpAOS.cs b/Scripts/Gumps/HouseGumpAOS.cs new file mode 100644 index 0000000..120c13a --- /dev/null +++ b/Scripts/Gumps/HouseGumpAOS.cs @@ -0,0 +1,1480 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using Server.Network; +using Server.Prompts; +using Server.Mobiles; +using Server.Multis; +using Server.Multis.Deeds; +using Server.Items; + +namespace Server.Gumps +{ + public enum HouseGumpPageAOS + { + Information, + Security, + Storage, + Customize, + Ownership, + ChangeHanger, + ChangeFoundation, + ChangeSign, + RemoveCoOwner, + ListCoOwner, + RemoveFriend, + ListFriend, + RemoveBan, + ListBan, + RemoveAccess, + ListAccess, + ChangePost, + Vendors + } + + public class HouseGumpAOS : Gump + { + private BaseHouse m_House; + private HouseGumpPageAOS m_Page; + + private const int LabelColor = 0x7FFF; + private const int SelectedColor = 0x421F; + private const int DisabledColor = 0x4210; + private const int WarningColor = 0x7E10; + + private const int LabelHue = 0x481; + private const int HighlightedLabelHue = 0x64; + + private ArrayList m_List; + + private string GetOwnerName() + { + Mobile m = m_House.Owner; + + if ( m == null || m.Deleted ) + return "(unowned)"; + + string name; + + if ( (name = m.Name) == null || (name = name.Trim()).Length <= 0 ) + name = "(no name)"; + + return name; + } + + private string GetDateTime( DateTime val ) + { + if ( val == DateTime.MinValue ) + return ""; + + return val.ToString( "yyyy'-'MM'-'dd HH':'mm':'ss" ); + } + + public void AddPageButton( int x, int y, int buttonID, int number, HouseGumpPageAOS page ) + { + bool isSelection = ( m_Page == page ); + + AddButton( x, y, isSelection ? 4006 : 4005, 4007, buttonID, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( x + 45, y, 200, 20, number, isSelection ? SelectedColor : LabelColor, false, false ); + } + + public void AddButtonLabeled( int x, int y, int buttonID, int number ) + { + AddButtonLabeled( x, y, buttonID, number, true ); + } + + public void AddButtonLabeled( int x, int y, int buttonID, int number, bool enabled ) + { + if ( enabled ) + AddButton( x, y, 4005, 4007, buttonID, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( x + 35, y, 240, 20, number, enabled ? LabelColor : DisabledColor, false, false ); + } + + public void AddList( ArrayList list, int button, bool accountOf, bool leadingStar, Mobile from ) + { + if ( list == null ) + return; + + m_List = new ArrayList( list ); + + int lastPage = 0; + int index = 0; + + for ( int i = 0; i < list.Count; ++i ) + { + int xoffset = ((index % 20) / 10) * 200; + int yoffset = (index % 10) * 20; + int page = 1 + (index / 20); + + if ( page != lastPage ) + { + if ( lastPage != 0 ) + AddButton( 40, 360, 4005, 4007, 0, GumpButtonType.Page, page ); + + AddPage( page ); + + if ( lastPage != 0 ) + AddButton( 10, 360, 4014, 4016, 0, GumpButtonType.Page, lastPage ); + + lastPage = page; + } + + + Mobile m = (Mobile)list[i]; + + string name; + int labelHue = LabelHue; + + if ( m is PlayerVendor ) + { + PlayerVendor vendor = (PlayerVendor) m; + + name = vendor.ShopName; + + if ( vendor.IsOwner( from ) ) + labelHue = HighlightedLabelHue; + } + else if ( m != null ) + { + name = m.Name; + } + else + { + continue; + } + + if ( (name = name.Trim()).Length <= 0 ) + continue; + + if ( button != -1 ) + AddButton( 10 + xoffset, 150 + yoffset, 4005, 4007, GetButtonID( button, i ), GumpButtonType.Reply, 0 ); + + if ( accountOf && m.Player && m.Account != null ) + name = "Account of " + name; + + if ( leadingStar ) + name = "* " + name; + + AddLabel( button > 0 ? 45 + xoffset : 10 + xoffset, 150 + yoffset, labelHue, name ); + ++index; + } + } + + public int GetButtonID( int type, int index ) + { + return 1 + (index * 15) + type; + } + + private static int[] m_HangerNumbers = new int[] + { + 2968, 2970, 2972, + 2974, 2976, 2978 + }; + + private static int[] m_FoundationNumbers = (Core.ML ? new int[] + { + 20, 189, 765, 65, 101, 0x2DF7, 0x2DFB, 0x3672, 0x3676 + }: + new int[] + { + 20, 189, 765, 65, 101 + }); + + private static int[] m_PostNumbers = new int[] + { + 9, 29, 54, 90, 147, 169, + 177, 204, 251, 257, 263, + 298, 347, 424, 441, 466, + 514, 600, 601, 602, 603, + 660, 666, 672, 898, 970, + 974, 982 + }; + + private static List _HouseSigns = new List(); + + public HouseGumpAOS( HouseGumpPageAOS page, Mobile from, BaseHouse house ) : base( 50, 40 ) + { + m_House = house; + m_Page = page; + + from.CloseGump( typeof( HouseGumpAOS ) ); + //from.CloseGump( typeof( HouseListGump ) ); + //from.CloseGump( typeof( HouseRemoveGump ) ); + + bool isCombatRestricted = house.IsCombatRestricted( from ); + + bool isOwner = house.IsOwner( from ); + bool isCoOwner = isOwner || house.IsCoOwner( from ); + bool isFriend = isCoOwner || house.IsFriend( from ); + + if ( isCombatRestricted ) + isFriend = isCoOwner = isOwner = false; + + AddPage( 0 ); + + if ( isFriend || page == HouseGumpPageAOS.Vendors ) + { + AddBackground( 0, 0, 420, page != HouseGumpPageAOS.Vendors ? 440 : 420, 5054 ); + + AddImageTiled( 10, 10, 400, 100, 2624 ); + AddAlphaRegion( 10, 10, 400, 100 ); + + AddImageTiled( 10, 120, 400, 260, 2624 ); + AddAlphaRegion( 10, 120, 400, 260 ); + + AddImageTiled( 10, 390, 400, page != HouseGumpPageAOS.Vendors ? 40 : 20, 2624 ); + AddAlphaRegion( 10, 390, 400, page != HouseGumpPageAOS.Vendors ? 40 : 20 ); + + AddButtonLabeled( 250, page != HouseGumpPageAOS.Vendors ? 410 : 390, 0, 1060675 ); // CLOSE + } + + AddImage( 10, 10, 100 ); + + if ( m_House.Sign != null ) + { + ArrayList lines = Wrap( m_House.Sign.GetName() ); + + if ( lines != null ) + { + for ( int i = 0, y = (114 - (lines.Count * 14)) / 2; i < lines.Count; ++i, y += 14 ) + { + string s = (string)lines[i]; + + AddLabel( 10 + ((160 - (s.Length * 8)) / 2), y, 0, s ); + } + } + } + + if ( page == HouseGumpPageAOS.Vendors ) + { + AddHtmlLocalized( 10, 120, 400, 20, 1062428, LabelColor, false, false ); //
SHOPS
+ + AddList( house.AvailableVendorsFor( from ), 1, false, false, from ); + return; + } + + if ( !isFriend ) + return; + + if ( house.Public ) + { + AddButtonLabeled( 10, 390, GetButtonID( 0, 0 ), 1060674 ); // Banish + AddButtonLabeled( 10, 410, GetButtonID( 0, 1 ), 1011261 ); // Lift a Ban + } + else + { + AddButtonLabeled( 10, 390, GetButtonID( 0, 2 ), 1060676 ); // Grant Access + AddButtonLabeled( 10, 410, GetButtonID( 0, 3 ), 1060677 ); // Revoke Access + } + + AddPageButton( 150, 10, GetButtonID( 1, 0 ), 1060668, HouseGumpPageAOS.Information ); + AddPageButton( 150, 30, GetButtonID( 1, 1 ), 1060669, HouseGumpPageAOS.Security ); + AddPageButton( 150, 50, GetButtonID( 1, 2 ), 1060670, HouseGumpPageAOS.Storage ); + AddPageButton( 150, 70, GetButtonID( 1, 3 ), 1060671, HouseGumpPageAOS.Customize ); + AddPageButton( 150, 90, GetButtonID( 1, 4 ), 1060672, HouseGumpPageAOS.Ownership ); + + switch ( page ) + { + case HouseGumpPageAOS.Information: + { + AddHtmlLocalized( 20, 130, 200, 20, 1011242, LabelColor, false, false ); // Owned By: + AddLabel( 210, 130, LabelHue, GetOwnerName() ); + + AddHtmlLocalized( 20, 170, 380, 20, 1018032, SelectedColor, false, false ); // This house is properly placed. + AddHtmlLocalized( 20, 190, 380, 20, 1018035, SelectedColor, false, false ); // This house is of modern design. + AddHtmlLocalized( 20, 210, 380, 20, (house is HouseFoundation) ? 1060681 : 1060680, SelectedColor, false, false ); // This is a (pre | custom)-built house. + AddHtmlLocalized( 20, 230, 380, 20, house.Public ? 1060678 : 1060679, SelectedColor, false, false ); // This house is (private | open to the public). + + switch ( house.DecayType ) + { + case DecayType.Ageless: + case DecayType.AutoRefresh: + { + AddHtmlLocalized( 20, 250, 380, 20, 1062209, SelectedColor, false, false ); // This house is Automatically refreshed. + break; + } + case DecayType.ManualRefresh: + { + AddHtmlLocalized( 20, 250, 380, 20, 1062208, SelectedColor, false, false ); // This house is Grandfathered. + break; + } + case DecayType.Condemned: + { + AddHtmlLocalized( 20, 250, 380, 20, 1062207, WarningColor, false, false ); // This house is Condemned. + break; + } + } + + AddHtmlLocalized( 20, 290, 200, 20, 1060692, SelectedColor, false, false ); // Built On: + AddLabel( 250, 290, LabelHue, GetDateTime( house.BuiltOn ) ); + + AddHtmlLocalized( 20, 310, 200, 20, 1060693, SelectedColor, false, false ); // Last Traded: + AddLabel( 250, 310, LabelHue, GetDateTime( house.LastTraded ) ); + + AddHtmlLocalized( 20, 330, 200, 20, 1061793, SelectedColor, false, false ); // House Value + AddLabel( 250, 330, LabelHue, house.Price.ToString() ); + + AddHtmlLocalized( 20, 360, 300, 20, 1011241, SelectedColor, false, false ); // Number of visits this building has had: + AddLabel( 350, 360, LabelHue, house.Visits.ToString() ); + + break; + } + case HouseGumpPageAOS.Security: + { + AddButtonLabeled( 10, 130, GetButtonID( 3, 0 ), 1011266, isCoOwner ); // View Co-Owner List + AddButtonLabeled( 10, 150, GetButtonID( 3, 1 ), 1011267, isOwner ); // Add a Co-Owner + AddButtonLabeled( 10, 170, GetButtonID( 3, 2 ), 1018036, isOwner ); // Remove a Co-Owner + AddButtonLabeled( 10, 190, GetButtonID( 3, 3 ), 1011268, isOwner ); // Clear Co-Owner List + + AddButtonLabeled( 10, 220, GetButtonID( 3, 4 ), 1011243 ); // View Friends List + AddButtonLabeled( 10, 240, GetButtonID( 3, 5 ), 1011244, isCoOwner ); // Add a Friend + AddButtonLabeled( 10, 260, GetButtonID( 3, 6 ), 1018037, isCoOwner ); // Remove a Friend + AddButtonLabeled( 10, 280, GetButtonID( 3, 7 ), 1011245, isCoOwner ); // Clear Friend List + + if ( house.Public ) + { + AddButtonLabeled( 10, 310, GetButtonID( 3, 8 ), 1011260 ); // View Ban List + AddButtonLabeled( 10, 330, GetButtonID( 3, 9 ), 1060698 ); // Clear Ban List + + AddButtonLabeled( 210, 130, GetButtonID( 3, 12 ), 1060695, isOwner ); // Change to Private + + AddHtmlLocalized( 245, 150, 240, 20, 1060694, SelectedColor, false, false ); // Change to Public + } + else + { + AddButtonLabeled( 10, 310, GetButtonID( 3, 10 ), 1060699 ); // View Access List + AddButtonLabeled( 10, 330, GetButtonID( 3, 11 ), 1060700 ); // Clear Access List + + AddHtmlLocalized( 245, 130, 240, 20, 1060695, SelectedColor, false, false ); // Change to Private + + AddButtonLabeled( 210, 150, GetButtonID( 3, 13 ), 1060694, isOwner ); // Change to Public + } + + break; + } + case HouseGumpPageAOS.Storage: + { + AddHtmlLocalized( 10, 130, 400, 20, 1060682, LabelColor, false, false ); //
HOUSE STORAGE SUMMARY
+ + // This is not as OSI; storage changes not yet implemented + + /*AddHtmlLocalized( 10, 170, 275, 20, 1011237, LabelColor, false, false ); // Number of locked down items: + AddLabel( 310, 170, LabelHue, m_House.LockDownCount.ToString() ); + + AddHtmlLocalized( 10, 190, 275, 20, 1011238, LabelColor, false, false ); // Maximum locked down items: + AddLabel( 310, 190, LabelHue, m_House.MaxLockDowns.ToString() ); + + AddHtmlLocalized( 10, 210, 275, 20, 1011239, LabelColor, false, false ); // Number of secure containers: + AddLabel( 310, 210, LabelHue, m_House.SecureCount.ToString() ); + + AddHtmlLocalized( 10, 230, 275, 20, 1011240, LabelColor, false, false ); // Maximum number of secure containers: + AddLabel( 310, 230, LabelHue, m_House.MaxSecures.ToString() );*/ + + int fromSecures, fromVendors, fromLockdowns, fromMovingCrate; + + int maxSecures = house.GetAosMaxSecures(); + int curSecures = house.GetAosCurSecures( out fromSecures, out fromVendors, out fromLockdowns, out fromMovingCrate ); + + int maxLockdowns = house.GetAosMaxLockdowns(); + int curLockdowns = house.GetAosCurLockdowns(); + + int bonusStorage = (int)((house.BonusStorageScalar * 100)-100); + + if( bonusStorage > 0 ) + { + AddHtmlLocalized( 10, 150, 300, 20, 1072519, LabelColor, false, false ); // Increased Storage + AddLabel( 310, 150, LabelHue, String.Format( "{0}%", bonusStorage ) ); + } + + AddHtmlLocalized( 10, 170, 300, 20, 1060683, LabelColor, false, false ); // Maximum Secure Storage + AddLabel( 310, 170, LabelHue, maxSecures.ToString() ); + + AddHtmlLocalized( 10, 190, 300, 20, 1060685, LabelColor, false, false ); // Used by Moving Crate + AddLabel( 310, 190, LabelHue, fromMovingCrate.ToString() ); + + AddHtmlLocalized( 10, 210, 300, 20, 1060686, LabelColor, false, false ); // Used by Lockdowns + AddLabel( 310, 210, LabelHue, fromLockdowns.ToString() ); + + if ( BaseHouse.NewVendorSystem ) + { + AddHtmlLocalized( 10, 230, 300, 20, 1060688, LabelColor, false, false ); // Used by Secure Containers + AddLabel( 310, 230, LabelHue, fromSecures.ToString() ); + + AddHtmlLocalized( 10, 250, 300, 20, 1060689, LabelColor, false, false ); // Available Storage + AddLabel( 310, 250, LabelHue, Math.Max( maxSecures - curSecures, 0 ).ToString() ); + + AddHtmlLocalized( 10, 290, 300, 20, 1060690, LabelColor, false, false ); // Maximum Lockdowns + AddLabel( 310, 290, LabelHue, maxLockdowns.ToString() ); + + AddHtmlLocalized( 10, 310, 300, 20, 1060691, LabelColor, false, false ); // Available Lockdowns + AddLabel( 310, 310, LabelHue, Math.Max( maxLockdowns - curLockdowns, 0 ).ToString() ); + + int maxVendors = house.GetNewVendorSystemMaxVendors(); + int vendors = house.PlayerVendors.Count + house.VendorRentalContracts.Count; + + AddHtmlLocalized( 10, 350, 300, 20, 1062391, LabelColor, false, false ); // Vendor Count + AddLabel( 310, 350, LabelHue, vendors.ToString() + " / " + maxVendors.ToString() ); + } + else + { + AddHtmlLocalized( 10, 230, 300, 20, 1060687, LabelColor, false, false ); // Used by Vendors + AddLabel( 310, 230, LabelHue, fromVendors.ToString() ); + + AddHtmlLocalized( 10, 250, 300, 20, 1060688, LabelColor, false, false ); // Used by Secure Containers + AddLabel( 310, 250, LabelHue, fromSecures.ToString() ); + + AddHtmlLocalized( 10, 270, 300, 20, 1060689, LabelColor, false, false ); // Available Storage + AddLabel( 310, 270, LabelHue, Math.Max( maxSecures - curSecures, 0 ).ToString() ); + + AddHtmlLocalized( 10, 330, 300, 20, 1060690, LabelColor, false, false ); // Maximum Lockdowns + AddLabel( 310, 330, LabelHue, maxLockdowns.ToString() ); + + AddHtmlLocalized( 10, 350, 300, 20, 1060691, LabelColor, false, false ); // Available Lockdowns + AddLabel( 310, 350, LabelHue, Math.Max( maxLockdowns - curLockdowns, 0 ).ToString() ); + } + + break; + } + case HouseGumpPageAOS.Customize: + { + bool isCustomizable = isOwner && ( house is HouseFoundation ); + + AddButtonLabeled( 10, 120, GetButtonID( 5, 0 ), 1060759, isOwner && !isCustomizable && ( house.ConvertEntry != null ) ); // Convert Into Customizable House + AddButtonLabeled( 10, 160, GetButtonID( 5, 1 ), 1060765, isOwner && isCustomizable ); // Customize This House + AddButtonLabeled( 10, 180, GetButtonID( 5, 2 ), 1060760, isOwner && house.MovingCrate != null ); // Relocate Moving Crate + AddButtonLabeled( 10, 210, GetButtonID( 5, 3 ), 1060761, isOwner && house.Public ); // Change House Sign + AddButtonLabeled( 10, 230, GetButtonID( 5, 4 ), 1060762, isOwner && isCustomizable ); // Change House Sign Hanger + AddButtonLabeled( 10, 250, GetButtonID( 5, 5 ), 1060763, isOwner && isCustomizable && ( ((HouseFoundation)house).Signpost != null ) ); // Change Signpost + AddButtonLabeled( 10, 280, GetButtonID( 5, 6 ), 1062004, isOwner && isCustomizable ); // Change Foundation Style + AddButtonLabeled( 10, 310, GetButtonID( 5, 7 ), 1060764, isCoOwner ); // Rename House + + break; + } + case HouseGumpPageAOS.Ownership: + { + AddButtonLabeled( 10, 130, GetButtonID( 6, 0 ), 1061794, isOwner && house.MovingCrate == null && house.InternalizedVendors.Count == 0 ); // Demolish House + AddButtonLabeled( 10, 150, GetButtonID( 6, 1 ), 1061797, isOwner ); // Trade House + AddButtonLabeled( 10, 190, GetButtonID( 6, 2 ), 1061798, false ); // Make Primary + + break; + } + case HouseGumpPageAOS.ChangeHanger: + { + for ( int i = 0; i < m_HangerNumbers.Length; ++i ) + { + int x = 50 + ((i % 3) * 100); + int y = 180 + ((i / 3) * 80); + + AddButton( x, y, 4005, 4007, GetButtonID( 7, i ), GumpButtonType.Reply, 0 ); + AddItem( x + 20, y, m_HangerNumbers[i] ); + } + + break; + } + case HouseGumpPageAOS.ChangeFoundation: + { + for ( int i = 0; i < m_FoundationNumbers.Length; ++i ) + { + int x = 15 + ((i % 5) * 80); + int y = 180 + ((i / 5) * 100); + + AddButton( x, y, 4005, 4007, GetButtonID( 8, i ), GumpButtonType.Reply, 0 ); + AddItem( x + 25, y, m_FoundationNumbers[i] ); + } + + break; + } + case HouseGumpPageAOS.ChangeSign: + { + int index = 0; + + if ( _HouseSigns.Count == 0 ) + { + // Add standard signs + for ( int i = 0; i < 54; ++i ) + { + _HouseSigns.Add( 2980 + ( i * 2 ) ); + } + + // Add library and beekeeper signs ( ML ) + _HouseSigns.Add( 2966 ); + _HouseSigns.Add( 3140 ); + } + + int signsPerPage = Core.ML ? 24 : 18; + int totalSigns = Core.ML ? 56 : 54; + int pages = (int) Math.Ceiling( (double) totalSigns / signsPerPage ); + + for ( int i = 0; i < pages; ++i ) + { + AddPage( i + 1 ); + + AddButton( 10, 360, 4005, 4007, 0, GumpButtonType.Page, ((i + 1) % pages ) + 1 ); + + for ( int j = 0; j < signsPerPage && totalSigns - ( signsPerPage * i ) - j > 0; ++j ) + { + int x = 30 + ((j % 6) * 60); + int y = 130 + ((j / 6) * 60); + + AddButton( x, y, 4005, 4007, GetButtonID( 9, index ), GumpButtonType.Reply, 0 ); + AddItem( x + 20, y, _HouseSigns[index++] ); + } + } + + break; + } + case HouseGumpPageAOS.RemoveCoOwner: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060730, LabelColor, false, false ); //
CO-OWNER LIST
+ AddList( house.CoOwners, 10, false, true, from ); + break; + } + case HouseGumpPageAOS.ListCoOwner: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060730, LabelColor, false, false ); //
CO-OWNER LIST
+ AddList( house.CoOwners, -1, false, true, from ); + break; + } + case HouseGumpPageAOS.RemoveFriend: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060731, LabelColor, false, false ); //
FRIENDS LIST
+ AddList( house.Friends, 11, false, true, from ); + break; + } + case HouseGumpPageAOS.ListFriend: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060731, LabelColor, false, false ); //
FRIENDS LIST
+ AddList( house.Friends, -1, false, true, from ); + break; + } + case HouseGumpPageAOS.RemoveBan: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060733, LabelColor, false, false ); //
BAN LIST
+ AddList( house.Bans, 12, true, true, from ); + break; + } + case HouseGumpPageAOS.ListBan: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060733, LabelColor, false, false ); //
BAN LIST
+ AddList( house.Bans, -1, true, true, from ); + break; + } + case HouseGumpPageAOS.RemoveAccess: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060732, LabelColor, false, false ); //
ACCESS LIST
+ AddList( house.Access, 13, false, true, from ); + break; + } + case HouseGumpPageAOS.ListAccess: + { + AddHtmlLocalized( 10, 120, 400, 20, 1060732, LabelColor, false, false ); //
ACCESS LIST
+ AddList( house.Access, -1, false, true, from ); + break; + } + case HouseGumpPageAOS.ChangePost: + { + int index = 0; + + for ( int i = 0; i < 2; ++i ) + { + AddPage( i + 1 ); + + AddButton( 10, 360, 4005, 4007, 0, GumpButtonType.Page, ((i + 1) % 2) + 1 ); + + for ( int j = 0; j < 16 && index < m_PostNumbers.Length; ++j ) + { + int x = 15 + ((j % 8) * 50); + int y = 130 + ((j / 8) * 110); + + AddButton( x, y, 4005, 4007, GetButtonID( 14, index ), GumpButtonType.Reply, 0 ); + AddItem( x + 10, y, m_PostNumbers[index++] ); + } + } + + break; + } + } + } + + public static void PublicPrivateNotice_Callback( Mobile from, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( !house.Deleted ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, house ) ); + } + + public static void CustomizeNotice_Callback( Mobile from, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( !house.Deleted ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, house ) ); + } + + public static void ClearCoOwners_Callback( Mobile from, bool okay, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( house.Deleted ) + return; + + if ( okay && house.IsOwner( from ) ) + { + if ( house.CoOwners != null ) + house.CoOwners.Clear(); + + from.SendLocalizedMessage( 501333 ); // All co-owners have been removed from this house. + } + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, house ) ); + } + + public static void ClearFriends_Callback( Mobile from, bool okay, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( house.Deleted ) + return; + + if ( okay && house.IsCoOwner( from ) ) + { + if ( house.Friends != null ) + house.Friends.Clear(); + + from.SendLocalizedMessage( 501332 ); // All friends have been removed from this house. + } + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, house ) ); + } + + public static void ClearBans_Callback( Mobile from, bool okay, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( house.Deleted ) + return; + + if ( okay && house.IsFriend( from ) ) + { + if ( house.Bans != null ) + house.Bans.Clear(); + + from.SendLocalizedMessage( 1060754 ); // All bans for this house have been lifted. + } + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, house ) ); + } + + public static void ClearAccess_Callback( Mobile from, bool okay, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( house.Deleted ) + return; + + if ( okay && house.IsFriend( from ) ) + { + ArrayList list = new ArrayList( house.Access ); + + if ( house.Access != null ) + house.Access.Clear(); + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + if ( !house.HasAccess( m ) && house.IsInside( m ) ) + { + m.Location = house.BanLocation; + m.SendLocalizedMessage( 1060734 ); // Your access to this house has been revoked. + } + } + + from.SendLocalizedMessage( 1061843 ); // This house's Access List has been cleared. + } + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, house ) ); + } + + public static void ConvertHouse_Callback( Mobile from, bool okay, object state ) + { + BaseHouse house = (BaseHouse) state; + + if ( house.Deleted ) + return; + + if ( okay && house.IsOwner( from ) && !house.HasRentedVendors ) + { + HousePlacementEntry e = house.ConvertEntry; + + if ( e != null ) + { + int cost = e.Cost - house.Price; + + if ( cost > 0 ) + { + if ( Banker.Withdraw( from, cost ) ) + { + from.SendLocalizedMessage( 1060398, cost.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + from.SendLocalizedMessage( 1061624 ); // You do not have enough funds in your bank to cover the difference between your old house and your new one. + return; + } + } + else if ( cost < 0 ) + { + if ( Banker.Deposit( from, -cost ) ) + from.SendLocalizedMessage( 1060397, (-cost).ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + else + return; + } + + BaseHouse newHouse = e.ConstructHouse( from ); + + if ( newHouse != null ) + { + newHouse.Price = e.Cost; + + house.MoveAllToCrate(); + + newHouse.Friends = new ArrayList( house.Friends ); + newHouse.CoOwners = new ArrayList( house.CoOwners ); + newHouse.Bans = new ArrayList( house.Bans ); + newHouse.Access = new ArrayList( house.Access ); + newHouse.BuiltOn = house.BuiltOn; + newHouse.LastTraded = house.LastTraded; + newHouse.Public = house.Public; + + newHouse.VendorInventories.AddRange( house.VendorInventories ); + house.VendorInventories.Clear(); + + foreach ( VendorInventory inventory in newHouse.VendorInventories ) + { + inventory.House = newHouse; + } + + newHouse.InternalizedVendors.AddRange( house.InternalizedVendors ); + house.InternalizedVendors.Clear(); + + foreach ( Mobile mobile in newHouse.InternalizedVendors ) + { + if ( mobile is PlayerVendor ) + ((PlayerVendor)mobile).House = newHouse; + else if ( mobile is PlayerBarkeeper ) + ((PlayerBarkeeper)mobile).House = newHouse; + } + + if( house.MovingCrate != null ) + { + newHouse.MovingCrate = house.MovingCrate; + newHouse.MovingCrate.House = newHouse; + house.MovingCrate = null; + } + + List items = house.GetItems(); + List mobiles = house.GetMobiles(); + + newHouse.MoveToWorld( new Point3D( house.X + house.ConvertOffsetX, house.Y + house.ConvertOffsetY, house.Z + house.ConvertOffsetZ ), house.Map ); + house.Delete(); + + foreach ( Item item in items ) + { + item.Location = newHouse.BanLocation; + } + + foreach ( Mobile mobile in mobiles ) + { + mobile.Location = newHouse.BanLocation; + } + + /* You have successfully replaced your original house with a new house. + * The value of the replaced house has been deposited into your bank box. + * All of the items in your original house have been relocated to a Moving Crate in the new house. + * Any deed-based house add-ons have been converted back into deeds. + * Vendors and barkeeps in the house, if any, have been stored in the Moving Crate as well. + * Use the Get Vendor context-sensitive menu option on your character to retrieve them. + * These containers can be used to re-create the vendor in a new location. + * Any barkeepers have been converted into deeds. + */ + from.SendGump( new NoticeGump( 1060637, 30720, 1060012, 32512, 420, 280, null, null ) ); + return; + } + } + } + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, house ) ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_House.Deleted ) + return; + + Mobile from = sender.Mobile; + + bool isCombatRestricted = m_House.IsCombatRestricted( from ); + + bool isOwner = m_House.IsOwner( from ); + bool isCoOwner = isOwner || m_House.IsCoOwner( from ); + bool isFriend = isCoOwner || m_House.IsFriend( from ); + + if ( isCombatRestricted ) + isCoOwner = isFriend = false; + + if ( !from.CheckAlive() ) + return; + + Item sign = m_House.Sign; + + if ( sign == null || from.Map != sign.Map || !from.InRange( sign.GetWorldLocation(), 18 ) ) + return; + + HouseFoundation foundation = m_House as HouseFoundation; + bool isCustomizable = ( foundation != null ); + + int val = info.ButtonID - 1; + + if ( val < 0 ) + return; + + int type = val % 15; + int index = val / 15; + + if ( m_Page == HouseGumpPageAOS.Vendors ) + { + if ( index >= 0 && index < m_List.Count ) + { + PlayerVendor vendor = (PlayerVendor) m_List[index]; + + if ( !vendor.CanInteractWith( from, false ) ) + return; + + if ( from.Map != sign.Map || !from.InRange( sign, 5 ) ) + { + from.SendLocalizedMessage( 1062429 ); // You must be within five paces of the house sign to use this option. + } + else if ( vendor.IsOwner( from ) ) + { + vendor.SendOwnerGump( from ); + } + else + { + vendor.OpenBackpack( from ); + } + } + + return; + } + + if ( !isFriend ) + return; + + switch ( type ) + { + case 0: + { + switch ( index ) + { + case 0: // Banish + { + if ( m_House.Public ) + { + from.SendLocalizedMessage( 501325 ); // Target the individual to ban from this house. + from.Target = new HouseBanTarget( true, m_House ); + } + + break; + } + case 1: // Lift Ban + { + if ( m_House.Public ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveBan, from, m_House ) ); + + break; + } + case 2: // Grant Access + { + if ( !m_House.Public ) + { + from.SendLocalizedMessage( 1060711 ); // Target the person you would like to grant access to. + from.Target = new HouseAccessTarget( m_House ); + } + + break; + } + case 3: // Revoke Access + { + if ( !m_House.Public ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveAccess, from, m_House ) ); + + break; + } + } + + break; + } + case 1: + { + HouseGumpPageAOS page; + + switch ( index ) + { + case 0: page = HouseGumpPageAOS.Information; break; + case 1: page = HouseGumpPageAOS.Security; break; + case 2: page = HouseGumpPageAOS.Storage; break; + case 3: page = HouseGumpPageAOS.Customize; break; + case 4: page = HouseGumpPageAOS.Ownership; break; + default: return; + } + + from.SendGump( new HouseGumpAOS( page, from, m_House ) ); + break; + } + case 3: + { + switch ( index ) + { + case 0: // View Co-Owner List + { + if ( isCoOwner ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ListCoOwner, from, m_House ) ); + + break; + } + case 1: // Add a Co-Owner + { + if ( isOwner ) + { + from.SendLocalizedMessage( 501328 ); // Target the person you wish to name a co-owner of your household. + from.Target = new CoOwnerTarget( true, m_House ); + } + + break; + } + case 2: // Remove a Co-Owner + { + if ( isOwner ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveCoOwner, from, m_House ) ); + + break; + } + case 3: // Clear Co-Owner List + { + if ( isOwner ) + from.SendGump( new WarningGump( 1060635, 30720, 1060736, 32512, 420, 280, new WarningGumpCallback( ClearCoOwners_Callback ), m_House ) ); + + break; + } + case 4: // View Friends List + { + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ListFriend, from, m_House ) ); + + break; + } + case 5: // Add a Friend + { + if ( isCoOwner ) + { + from.SendLocalizedMessage( 501317 ); // Target the person you wish to name a friend of your household. + from.Target = new HouseFriendTarget( true, m_House ); + } + + break; + } + case 6: // Remove a Friend + { + if ( isCoOwner ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveFriend, from, m_House ) ); + + break; + } + case 7: // Clear Friend List + { + if ( isCoOwner ) + from.SendGump( new WarningGump( 1060635, 30720, 1018039, 32512, 420, 280, new WarningGumpCallback( ClearFriends_Callback ), m_House ) ); + + break; + } + case 8: // View Ban List + { + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ListBan, from, m_House ) ); + + break; + } + case 9: // Clear Ban List + { + from.SendGump( new WarningGump( 1060635, 30720, 1060753, 32512, 420, 280, new WarningGumpCallback( ClearBans_Callback ), m_House ) ); + + break; + } + case 10: // View Access List + { + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ListAccess, from, m_House ) ); + + break; + } + case 11: // Clear Access List + { + from.SendGump( new WarningGump( 1060635, 30720, 1061842, 32512, 420, 280, new WarningGumpCallback( ClearAccess_Callback ), m_House ) ); + + break; + } + case 12: // Make Private + { + if ( isOwner ) + { + if ( m_House.PlayerVendors.Count > 0 ) + { + // You have vendors working out of this building. It cannot be declared private until there are no vendors in place. + from.SendGump( new NoticeGump( 1060637, 30720, 501887, 32512, 320, 180, new NoticeGumpCallback( PublicPrivateNotice_Callback ), m_House ) ); + break; + } + + if ( m_House.VendorRentalContracts.Count > 0 ) + { + // You cannot currently take this action because you have vendor contracts locked down in your home. You must remove them first. + from.SendGump( new NoticeGump( 1060637, 30720, 1062351, 32512, 320, 180, new NoticeGumpCallback( PublicPrivateNotice_Callback ), m_House ) ); + break; + } + + m_House.Public = false; + + m_House.ChangeLocks( from ); + + // This house is now private. + from.SendGump( new NoticeGump( 1060637, 30720, 501888, 32512, 320, 180, new NoticeGumpCallback( PublicPrivateNotice_Callback ), m_House ) ); + + Region r = m_House.Region; + List list = r.GetMobiles(); + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + if ( !m_House.HasAccess( m ) && m_House.IsInside( m ) ) + m.Location = m_House.BanLocation; + } + } + + break; + } + case 13: // Make Public + { + if ( isOwner ) + { + m_House.Public = true; + + m_House.RemoveKeys( from ); + m_House.RemoveLocks(); + + if ( BaseHouse.NewVendorSystem ) + { + // This house is now public. The owner may now place vendors and vendor rental contracts. + from.SendGump( new NoticeGump( 1060637, 30720, 501886, 32512, 320, 180, new NoticeGumpCallback( PublicPrivateNotice_Callback ), m_House ) ); + } + else + { + from.SendGump( new NoticeGump( 1060637, 30720, "This house is now public. Friends of the house may now have vendors working out of this building.", 0xF8C000, 320, 180, new NoticeGumpCallback( PublicPrivateNotice_Callback ), m_House ) ); + } + + Region r = m_House.Region; + List list = r.GetMobiles(); + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + if ( m_House.IsBanned( m ) && m_House.IsInside( m ) ) + m.Location = m_House.BanLocation; + } + } + + break; + } + } + + break; + } + case 5: + { + switch ( index ) + { + case 0: // Convert Into Customizable House + { + if ( isOwner && !isCustomizable ) + { + if ( m_House.HasRentedVendors ) + { + // You cannot perform this action while you still have vendors rented out in this house. + from.SendGump( new NoticeGump( 1060637, 30720, 1062395, 32512, 320, 180, new NoticeGumpCallback( CustomizeNotice_Callback ), m_House ) ); + } + else + { + HousePlacementEntry e = m_House.ConvertEntry; + + if ( e != null ) + { + /* You are about to turn your house into a customizable house. + * You will be refunded the value of this house, and then be charged the cost of the equivalent customizable dirt lot. + * All of your possessions in the house will be transported to a Moving Crate. + * Deed-based house add-ons will be converted back into deeds. + * Vendors and barkeeps will also be stored in the Moving Crate. + * Your house will be leveled to its foundation, and you will be able to build new walls, windows, doors, and stairs. + * Are you sure you wish to continue? + */ + from.SendGump( new WarningGump( 1060635, 30720, 1060013, 32512, 420, 280, new WarningGumpCallback( ConvertHouse_Callback ), m_House ) ); + } + } + } + + break; + } + case 1: // Customize This House + { + if ( isOwner && isCustomizable ) + { + if ( m_House.HasRentedVendors ) + { + // You cannot perform this action while you still have vendors rented out in this house. + from.SendGump( new NoticeGump( 1060637, 30720, 1062395, 32512, 320, 180, new NoticeGumpCallback( CustomizeNotice_Callback ), m_House ) ); + } + #region Mondain's Legacy + else if (m_House.HasAddonContainers) + { + // The house can not be customized when add-on containers such as aquariums, elven furniture containers, vanities, and boiling cauldrons + // are present in the house. Please re-deed the add-on containers before customizing the house. + from.SendGump(new NoticeGump(1060637, 30720, 1074863, 32512, 320, 180, new NoticeGumpCallback(CustomizeNotice_Callback), m_House)); + } + #endregion + else + { + foundation.BeginCustomize( from ); + } + } + + break; + } + case 2: // Relocate Moving Crate + { + MovingCrate crate = m_House.MovingCrate; + + if ( isOwner && crate != null ) + { + if ( !m_House.IsInside( from ) ) + { + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + { + crate.MoveToWorld( from.Location, from.Map ); + crate.RestartTimer(); + } + } + + break; + } + case 3: // Change House Sign + { + if ( isOwner && m_House.Public ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ChangeSign, from, m_House ) ); + + break; + } + case 4: // Change House Sign Hanger + { + if ( isOwner && isCustomizable ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ChangeHanger, from, m_House ) ); + + break; + } + case 5: // Change Signpost + { + if ( isOwner && isCustomizable && foundation.Signpost != null ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ChangePost, from, m_House ) ); + + break; + } + case 6: // Change Foundation Style + { + if ( isOwner && isCustomizable ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.ChangeFoundation, from, m_House ) ); + + break; + } + case 7: // Rename House + { + if ( isCoOwner ) + { + from.Prompt = new RenamePrompt( m_House ); + from.SendLocalizedMessage( 501302 ); // What dost thou wish the sign to say? + } + + break; + } + } + + break; + } + case 6: + { + switch ( index ) + { + case 0: // Demolish + { + if ( isOwner && m_House.MovingCrate == null && m_House.InternalizedVendors.Count == 0 ) + { + if (!Guilds.Guild.NewGuildSystem && m_House.FindGuildstone() != null) + { + from.SendLocalizedMessage(501389); // You cannot redeed a house with a guildstone inside. + } + else if (Core.ML && from.AccessLevel < AccessLevel.GameMaster && DateTime.Now <= m_House.BuiltOn.AddHours(1)) + { + from.SendLocalizedMessage(1080178); // You must wait one hour between each house demolition. + } + else + { + from.CloseGump( typeof( HouseDemolishGump ) ); + from.SendGump( new HouseDemolishGump( from, m_House ) ); + } + } + + break; + } + case 1: // Trade House + { + if ( isOwner ) + { + if ( BaseHouse.NewVendorSystem && m_House.HasPersonalVendors ) + { + from.SendLocalizedMessage( 1062467 ); // You cannot trade this house while you still have personal vendors inside. + } + else if ( m_House.DecayLevel == DecayLevel.DemolitionPending ) + { + from.SendLocalizedMessage( 1005321 ); // This house has been marked for demolition, and it cannot be transferred. + } + else + { + from.SendLocalizedMessage( 501309 ); // Target the person to whom you wish to give this house. + from.Target = new HouseOwnerTarget( m_House ); + } + } + + break; + } + case 2: // Make Primary + break; + } + + break; + } + case 7: + { + if ( isOwner && isCustomizable && index >= 0 && index < m_HangerNumbers.Length ) + { + Item hanger = foundation.SignHanger; + + if ( hanger != null ) + hanger.ItemID = m_HangerNumbers[index]; + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, m_House ) ); + } + + break; + } + case 8: + { + if ( isOwner && isCustomizable ) + { + FoundationType newType; + + if( Core.ML && index >= 5 ) + { + switch( index ) + { + case 5: newType = FoundationType.ElvenGrey; break; + case 6: newType = FoundationType.ElvenNatural; break; + case 7: newType = FoundationType.Crystal; break; + case 8: newType = FoundationType.Shadow; break; + default: return; + } + } + else + { + switch( index ) + { + case 0: newType = FoundationType.DarkWood; break; + case 1: newType = FoundationType.LightWood; break; + case 2: newType = FoundationType.Dungeon; break; + case 3: newType = FoundationType.Brick; break; + case 4: newType = FoundationType.Stone; break; + default: return; + } + } + + foundation.Type = newType; + + DesignState state = foundation.BackupState; + HouseFoundation.ApplyFoundation( newType, state.Components ); + state.OnRevised(); + + state = foundation.DesignState; + HouseFoundation.ApplyFoundation( newType, state.Components ); + state.OnRevised(); + + state = foundation.CurrentState; + HouseFoundation.ApplyFoundation( newType, state.Components ); + state.OnRevised(); + + foundation.Delta( ItemDelta.Update ); + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, m_House ) ); + } + + break; + } + case 9: + { + if ( isOwner && m_House.Public && index >= 0 && index < _HouseSigns.Count ) + { + m_House.ChangeSignType( _HouseSigns[index] ); + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, m_House ) ); + } + + break; + } + case 10: + { + if ( isOwner && m_List != null && index >= 0 && index < m_List.Count ) + { + m_House.RemoveCoOwner( from, (Mobile)m_List[index] ); + + if ( m_House.CoOwners.Count > 0 ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveCoOwner, from, m_House ) ); + else + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, m_House ) ); + } + + break; + } + case 11: + { + if ( isCoOwner && m_List != null && index >= 0 && index < m_List.Count ) + { + m_House.RemoveFriend( from, (Mobile)m_List[index] ); + + if ( m_House.Friends.Count > 0 ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveFriend, from, m_House ) ); + else + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, m_House ) ); + } + + break; + } + case 12: + { + if ( m_List != null && index >= 0 && index < m_List.Count ) + { + m_House.RemoveBan( from, (Mobile)m_List[index] ); + + if ( m_House.Bans.Count > 0 ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveBan, from, m_House ) ); + else + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, m_House ) ); + } + + break; + } + case 13: + { + if ( m_List != null && index >= 0 && index < m_List.Count ) + { + m_House.RemoveAccess( from, (Mobile)m_List[index] ); + + if ( m_House.Access.Count > 0 ) + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.RemoveAccess, from, m_House ) ); + else + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Security, from, m_House ) ); + } + + break; + } + case 14: + { + if ( isOwner && isCustomizable && index >= 0 && index < m_PostNumbers.Length ) + { + foundation.SignpostGraphic = m_PostNumbers[index]; + foundation.CheckSignpost(); + + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Customize, from, m_House ) ); + } + + break; + } + } + } + + private ArrayList Wrap( string value ) + { + if ( value == null || (value = value.Trim()).Length <= 0 ) + return null; + + string[] values = value.Split( ' ' ); + ArrayList list = new ArrayList(); + string current = ""; + + for ( int i = 0; i < values.Length; ++i ) + { + string val = values[i]; + + string v = current.Length == 0 ? val : current + ' ' + val; + + if ( v.Length < 10 ) + { + current = v; + } + else if ( v.Length == 10 ) + { + list.Add( v ); + + if ( list.Count == 6 ) + return list; + + current = ""; + } + else if ( val.Length <= 10 ) + { + list.Add( current ); + + if ( list.Count == 6 ) + return list; + + current = val; + } + else + { + while ( v.Length >= 10 ) + { + list.Add( v.Substring( 0, 10 ) ); + + if ( list.Count == 6 ) + return list; + + v = v.Substring( 10 ); + } + + current = v; + } + } + + if ( current.Length > 0 ) + list.Add( current ); + + return list; + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/HouseTransferGump.cs b/Scripts/Gumps/HouseTransferGump.cs new file mode 100644 index 0000000..d56856f --- /dev/null +++ b/Scripts/Gumps/HouseTransferGump.cs @@ -0,0 +1,66 @@ +using System; +using Server; +using Server.Items; +using Server.Multis; +using Server.Multis.Deeds; +using Server.Network; + +namespace Server.Gumps +{ + public class HouseTransferGump : Gump + { + private Mobile m_From, m_To; + private BaseHouse m_House; + + public HouseTransferGump( Mobile from, Mobile to, BaseHouse house ) : base( 110, 100 ) + { + m_From = from; + m_To = to; + m_House = house; + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 280, 5054 ); + + AddImageTiled( 10, 10, 400, 20, 2624 ); + AddAlphaRegion( 10, 10, 400, 20 ); + + AddHtmlLocalized( 10, 10, 400, 20, 1060635, 30720, false, false ); //
WARNING
+ + AddImageTiled( 10, 40, 400, 200, 2624 ); + AddAlphaRegion( 10, 40, 400, 200 ); + + /* Another player is attempting to initiate a house trade with you. + * In order for you to see this window, both you and the other person are standing within two paces of the house to be traded. + * If you click OKAY below, a house trade scroll will appear in your trade window and you can complete the transaction. + * This scroll is a distinctive blue color and will show the name of the house, the name of the owner of that house, and the sextant coordinates of the center of the house when you hover your mouse over it. + * In order for the transaction to be successful, you both must accept the trade and you both must remain within two paces of the house sign. + *

Accepting this house in trade will condemn any and all of your other houses that you may have. + * All of your houses on all shards will be affected. + *

In addition, you will not be able to place another house or have one transferred to you for one (1) real-life week.

+ * Once you accept these terms, these effects cannot be reversed. + * Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one week timer be removed.

+ * If you are absolutely certain you wish to proceed, click the button next to OKAY below. + * If you do not wish to trade for this house, click CANCEL. + */ + AddHtmlLocalized( 10, 40, 400, 200, 1062086, 32512, false, true ); + + AddImageTiled( 10, 250, 400, 20, 2624 ); + AddAlphaRegion( 10, 250, 400, 20 ); + + AddButton( 10, 250, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 250, 170, 20, 1011036, 32767, false, false ); // OKAY + + AddButton( 210, 250, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 240, 250, 170, 20, 1011012, 32767, false, false ); // CANCEL + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 1 && !m_House.Deleted ) + m_House.EndConfirmTransfer( m_From, m_To ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/NoticeGump.cs b/Scripts/Gumps/NoticeGump.cs new file mode 100644 index 0000000..1132353 --- /dev/null +++ b/Scripts/Gumps/NoticeGump.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Gumps +{ + public delegate void NoticeGumpCallback( Mobile from, object state ); + + public class NoticeGump : Gump + { + private NoticeGumpCallback m_Callback; + private object m_State; + + public NoticeGump( int header, int headerColor, object content, int contentColor, int width, int height, NoticeGumpCallback callback, object state ) : base( (640 - width) / 2, (480 - height) / 2 ) + { + m_Callback = callback; + m_State = state; + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, width, height, 5054 ); + + AddImageTiled( 10, 10, width - 20, 20, 2624 ); + AddAlphaRegion( 10, 10, width - 20, 20 ); + AddHtmlLocalized( 10, 10, width - 20, 20, header, headerColor, false, false ); + + AddImageTiled( 10, 40, width - 20, height - 80, 2624 ); + AddAlphaRegion( 10, 40, width - 20, height - 80 ); + + if ( content is int ) + AddHtmlLocalized( 10, 40, width - 20, height - 80, (int)content, contentColor, false, true ); + else if ( content is string ) + AddHtml( 10, 40, width - 20, height - 80, String.Format( "{1}", contentColor, content ), false, true ); + + AddImageTiled( 10, height - 30, width - 20, 20, 2624 ); + AddAlphaRegion( 10, height - 30, width - 20, 20 ); + AddButton( 10, height - 30, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, height - 30, 120, 20, 1011036, 32767, false, false ); // OKAY + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 && m_Callback != null ) + m_Callback( sender.Mobile, m_State ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/PetResurrectGump.cs b/Scripts/Gumps/PetResurrectGump.cs new file mode 100644 index 0000000..0907f70 --- /dev/null +++ b/Scripts/Gumps/PetResurrectGump.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Gumps; + +namespace Server.Gumps +{ + public class PetResurrectGump : Gump + { + private BaseCreature m_Pet; + private double m_HitsScalar; + + public PetResurrectGump( Mobile from, BaseCreature pet ) + : this( from, pet, 0.0 ) + { + } + + public PetResurrectGump( Mobile from, BaseCreature pet, double hitsScalar ) : base( 50, 50 ) + { + from.CloseGump( typeof( PetResurrectGump ) ); + + m_Pet = pet; + m_HitsScalar = hitsScalar; + + AddPage( 0 ); + + AddBackground( 10, 10, 265, 140, 0x242C ); + + AddItem( 205, 40, 0x4 ); + AddItem( 227, 40, 0x5 ); + + AddItem( 180, 78, 0xCAE ); + AddItem( 195, 90, 0xCAD ); + AddItem( 218, 95, 0xCB0 ); + + AddHtmlLocalized( 30, 30, 150, 75, 1049665, false, false ); //
Wilt thou sanctify the resurrection of:
+ AddHtml( 30, 70, 150, 25, String.Format( "
{0}
", pet.Name ), true, false ); + + AddButton( 40, 105, 0x81A, 0x81B, 0x1, GumpButtonType.Reply, 0 ); // Okay + AddButton( 110, 105, 0x819, 0x818, 0x2, GumpButtonType.Reply, 0 ); // Cancel + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( m_Pet.Deleted || !m_Pet.IsBonded || !m_Pet.IsDeadPet ) + return; + + Mobile from = state.Mobile; + + if ( info.ButtonID == 1 ) + { + if ( m_Pet.Map == null || !m_Pet.Map.CanFit( m_Pet.Location, 16, false, false ) ) + { + from.SendLocalizedMessage( 503256 ); // You fail to resurrect the creature. + return; + } + else if( m_Pet.Region != null && m_Pet.Region.IsPartOf( "Khaldun" ) ) //TODO: Confirm for pets, as per Bandage's script. + { + from.SendLocalizedMessage( 1010395 ); // The veil of death in this area is too strong and resists thy efforts to restore life. + return; + } + + m_Pet.PlaySound( 0x214 ); + m_Pet.FixedEffect( 0x376A, 10, 16 ); + m_Pet.ResurrectPet(); + + int Penalty = m_Pet.CalculatePenalty(from); + + for (int i = 0; i < Penalty; ++i) + { + m_Pet.Skills[Utility.RandomList(1, 16, 25, 26, 27, 30, 43, 46)].Base -= 0.1; + } + + /* + double decreaseAmount; + + if( from == m_Pet.ControlMaster ) + decreaseAmount = 0.1; + else + decreaseAmount = 0.2; + + for ( int i = 0; i < m_Pet.Skills.Length; ++i ) //Decrease all skills on pet. + m_Pet.Skills[i].Base -= decreaseAmount; + */ + if( !m_Pet.IsDeadPet && m_HitsScalar > 0 ) + m_Pet.Hits = (int)(m_Pet.HitsMax * m_HitsScalar); + } + + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/PlayerVendorGumps.cs b/Scripts/Gumps/PlayerVendorGumps.cs new file mode 100644 index 0000000..4e39c3b --- /dev/null +++ b/Scripts/Gumps/PlayerVendorGumps.cs @@ -0,0 +1,1057 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Network; +using Server.HuePickers; +using Server.Multis; + +namespace Server.Gumps +{ + public class PlayerVendorBuyGump : Gump + { + private PlayerVendor m_Vendor; + private VendorItem m_VI; + + public PlayerVendorBuyGump( PlayerVendor vendor, VendorItem vi ) : base( 100, 200 ) + { + m_Vendor = vendor; + m_VI = vi; + + AddBackground( 100, 10, 300, 150, 5054 ); + + AddHtmlLocalized( 125, 20, 250, 24, 1019070, false, false ); // You have agreed to purchase: + + if ( !String.IsNullOrEmpty( vi.Description ) ) + AddLabel( 125, 45, 0, vi.Description ); + else + AddHtmlLocalized( 125, 45, 250, 24, 1019072, false, false ); // an item without a description + + AddHtmlLocalized( 125, 70, 250, 24, 1019071, false, false ); // for the amount of: + AddLabel( 125, 95, 0, vi.Price.ToString() ); + + AddButton( 250, 130, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 282, 130, 100, 24, 1011012, false, false ); // CANCEL + + AddButton( 120, 130, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 152, 130, 100, 24, 1011036, false, false ); // OKAY + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( !m_Vendor.CanInteractWith( from, false ) ) + return; + + if ( m_Vendor.IsOwner( from ) ) + { + m_Vendor.SayTo( from, 503212 ); // You own this shop, just take what you want. + return; + } + + if ( info.ButtonID == 1 ) + { + m_Vendor.Say( from.Name ); + + if ( !m_VI.Valid || !m_VI.Item.IsChildOf( m_Vendor.Backpack ) ) + { + m_Vendor.SayTo( from, 503216 ); // You can't buy that. + return; + } + + int totalGold = 0; + + if ( from.Backpack != null ) + totalGold += from.Backpack.GetAmount( typeof( Gold ) ); + + totalGold += Banker.GetBalance( from ); + + if ( totalGold < m_VI.Price ) + { + m_Vendor.SayTo( from, 503205 ); // You cannot afford this item. + } + else if ( !from.PlaceInBackpack( m_VI.Item ) ) + { + m_Vendor.SayTo( from, 503204 ); // You do not have room in your backpack for this. + } + else + { + int leftPrice = m_VI.Price; + + if ( from.Backpack != null ) + leftPrice -= from.Backpack.ConsumeUpTo( typeof( Gold ), leftPrice ); + + if ( leftPrice > 0 ) + Banker.Withdraw( from, leftPrice ); + + m_Vendor.HoldGold += m_VI.Price; + + from.SendLocalizedMessage( 503201 ); // You take the item. + } + } + else + { + from.SendLocalizedMessage( 503207 ); // Cancelled purchase. + } + } + } + + public class PlayerVendorOwnerGump : Gump + { + private PlayerVendor m_Vendor; + + public PlayerVendorOwnerGump( PlayerVendor vendor ) : base( 50, 200 ) + { + m_Vendor = vendor; + + int perDay = m_Vendor.ChargePerDay; + + AddPage( 0 ); + AddBackground( 25, 10, 530, 140, 5054 ); + + AddHtmlLocalized( 425, 25, 120, 20, 1019068, false, false ); // See goods + AddButton( 390, 25, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 425, 48, 120, 20, 1019069, false, false ); // Customize + AddButton( 390, 48, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 425, 72, 120, 20, 1011012, false, false ); // CANCEL + AddButton( 390, 71, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 40, 72, 260, 20, 1038321, false, false ); // Gold held for you: + AddLabel( 300, 72, 0, m_Vendor.HoldGold.ToString() ); + AddHtmlLocalized( 40, 96, 260, 20, 1038322, false, false ); // Gold held in my account: + AddLabel( 300, 96, 0, m_Vendor.BankAccount.ToString() ); + + //AddHtmlLocalized( 40, 120, 260, 20, 1038324, false, false ); // My charge per day is: + // Localization has changed, we must use a string here + AddHtml( 40, 120, 260, 20, "My charge per day is:", false, false ); + AddLabel( 300, 120, 0, perDay.ToString() ); + + double days = (m_Vendor.HoldGold + m_Vendor.BankAccount) / ((double)perDay); + + AddHtmlLocalized( 40, 25, 260, 20, 1038318, false, false ); // Amount of days I can work: + AddLabel( 300, 25, 0, ((int)days).ToString() ); + AddHtmlLocalized( 40, 48, 260, 20, 1038319, false, false ); // Earth days: + AddLabel( 300, 48, 0, ((int)(days / 12.0)).ToString() ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( !m_Vendor.CanInteractWith( from, true ) ) + return; + + switch ( info.ButtonID ) + { + case 1: + { + m_Vendor.OpenBackpack( from ); + + break; + } + case 2: + { + from.SendGump( new PlayerVendorCustomizeGump( m_Vendor, from ) ); + + break; + } + } + } + } + + public class NewPlayerVendorOwnerGump : Gump + { + private PlayerVendor m_Vendor; + + public NewPlayerVendorOwnerGump( PlayerVendor vendor ) : base( 50, 200 ) + { + m_Vendor = vendor; + + int perRealWorldDay = vendor.ChargePerRealWorldDay; + int goldHeld = vendor.HoldGold; + + AddBackground( 25, 10, 530, 180, 0x13BE ); + + AddImageTiled( 35, 20, 510, 160, 0xA40 ); + AddAlphaRegion( 35, 20, 510, 160 ); + + AddImage( 10, 0, 0x28DC ); + AddImage( 537, 175, 0x28DC ); + AddImage( 10, 175, 0x28DC ); + AddImage( 537, 0, 0x28DC ); + + if ( goldHeld < perRealWorldDay ) + { + int goldNeeded = perRealWorldDay - goldHeld; + + AddHtmlLocalized( 40, 35, 260, 20, 1038320, 0x7FFF, false, false ); // Gold needed for 1 day of vendor salary: + AddLabel( 300, 35, 0x1F, goldNeeded.ToString() ); + } + else + { + int days = goldHeld / perRealWorldDay; + + AddHtmlLocalized( 40, 35, 260, 20, 1038318, 0x7FFF, false, false ); // # of days Vendor salary is paid for: + AddLabel( 300, 35, 0x480, days.ToString() ); + } + + AddHtmlLocalized( 40, 58, 260, 20, 1038324, 0x7FFF, false, false ); // My charge per real world day is: + AddLabel( 300, 58, 0x480, perRealWorldDay.ToString() ); + + AddHtmlLocalized( 40, 82, 260, 20, 1038322, 0x7FFF, false, false ); // Gold held in my account: + AddLabel( 300, 82, 0x480, goldHeld.ToString() ); + + AddHtmlLocalized( 40, 108, 260, 20, 1062509, 0x7FFF, false, false ); // Shop Name: + AddLabel( 140, 106, 0x66D, vendor.ShopName ); + + if ( vendor is RentedVendor ) + { + int days, hours; + ((RentedVendor)vendor).ComputeRentalExpireDelay( out days, out hours ); + + AddLabel( 38, 132, 0x480, String.Format( "Location rental will expire in {0} day{1} and {2} hour{3}.", days, days != 1 ? "s" : "", hours, hours != 1 ? "s" : "" ) ); + } + + AddButton( 390, 24, 0x15E1, 0x15E5, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 408, 21, 120, 20, 1019068, 0x7FFF, false, false ); // See goods + + AddButton( 390, 44, 0x15E1, 0x15E5, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 408, 41, 120, 20, 1019069, 0x7FFF, false, false ); // Customize + + AddButton( 390, 64, 0x15E1, 0x15E5, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 408, 61, 120, 20, 1062434, 0x7FFF, false, false ); // Rename Shop + + AddButton( 390, 84, 0x15E1, 0x15E5, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 408, 81, 120, 20, 3006217, 0x7FFF, false, false ); // Rename Vendor + + AddButton( 390, 104, 0x15E1, 0x15E5, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 408, 101, 120, 20, 3006123, 0x7FFF, false, false ); // Open Paperdoll + + AddButton( 390, 124, 0x15E1, 0x15E5, 6, GumpButtonType.Reply, 0 ); + AddLabel( 408, 121, 0x480, "Collect Gold" ); + + AddButton( 390, 144, 0x15E1, 0x15E5, 7, GumpButtonType.Reply, 0 ); + AddLabel( 408, 141, 0x480, "Dismiss Vendor" ); + + AddButton( 390, 162, 0x15E1, 0x15E5, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 408, 161, 120, 20, 1011012, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 1 || info.ButtonID == 2 ) // See goods or Customize + m_Vendor.CheckTeleport( from ); + + if ( !m_Vendor.CanInteractWith( from, true ) ) + return; + + switch ( info.ButtonID ) + { + case 1: // See goods + { + m_Vendor.OpenBackpack( from ); + + break; + } + case 2: // Customize + { + from.SendGump( new NewPlayerVendorCustomizeGump( m_Vendor ) ); + + break; + } + case 3: // Rename Shop + { + m_Vendor.RenameShop( from ); + + break; + } + case 4: // Rename Vendor + { + m_Vendor.Rename( from ); + + break; + } + case 5: // Open Paperdoll + { + m_Vendor.DisplayPaperdollTo( from ); + + break; + } + case 6: // Collect Gold + { + m_Vendor.CollectGold( from ); + + break; + } + case 7: // Dismiss Vendor + { + m_Vendor.Dismiss( from ); + + break; + } + } + } + } + + public class PlayerVendorCustomizeGump : Gump + { + private Mobile m_Vendor; + + private class CustomItem + { + private Type m_Type; + private int m_ItemID; + private int m_LocNum; + private int m_ArtNum; + private bool m_LongText; + + public CustomItem( int itemID, int loc ) : this( null, itemID, loc, 0, false ) + { + } + + public CustomItem( int itemID, int loc, bool longText ) : this( null, itemID, loc, 0, longText ) + { + } + + public CustomItem( Type type, int loc ) : this( type, loc, 0 ) + { + } + + public CustomItem( Type type, int loc, int art ) : this( type, 0, loc, art, false ) + { + } + + public CustomItem( Type type, int itemID, int loc, int art, bool longText ) + { + m_Type = type; + m_ItemID = itemID; + m_LocNum = loc; + m_ArtNum = art; + m_LongText = longText; + } + + public Item Create() + { + if ( m_Type == null ) + return null; + + Item i = null; + + try + { + ConstructorInfo ctor = m_Type.GetConstructor( new Type[0] ); + if ( ctor != null ) + i = ctor.Invoke( null ) as Item; + } + catch + { + } + + return i; + } + + public Type Type{ get{ return m_Type; } } + public int ItemID{ get{ return m_ItemID; } } + public int LocNumber{ get{ return m_LocNum; } } + public int ArtNumber{ get{ return m_ArtNum; } } + public bool LongText{ get{ return m_LongText; } } + } + + private class CustomCategory + { + private CustomItem[] m_Entries; + private Layer m_Layer; + private bool m_CanDye; + private int m_LocNum; + + public CustomCategory( Layer layer, int loc, bool canDye, CustomItem[] items ) + { + m_Entries = items; + m_CanDye = canDye; + m_Layer = layer; + m_LocNum = loc; + } + + public bool CanDye{ get{ return m_CanDye; } } + public CustomItem[] Entries{ get{ return m_Entries; } } + public Layer Layer{ get{ return m_Layer; } } + public int LocNumber{ get{ return m_LocNum; } } + } + + private static CustomCategory[] Categories = new CustomCategory[]{ + new CustomCategory( Layer.InnerTorso, 1011357, true, new CustomItem[]{// Upper Torso + new CustomItem( typeof( Shirt ), 1011359, 5399 ), + new CustomItem( typeof( FancyShirt ), 1011360, 7933 ), + new CustomItem( typeof( PlainDress ), 1011363, 7937 ), + new CustomItem( typeof( FancyDress ), 1011364, 7935 ), + new CustomItem( typeof( Robe ), 1011365, 7939 ) + } ), + + new CustomCategory( Layer.MiddleTorso, 1011371, true, new CustomItem[]{//Over chest + new CustomItem( typeof( Doublet ), 1011358, 8059 ), + new CustomItem( typeof( Tunic ), 1011361, 8097 ), + new CustomItem( typeof( JesterSuit ), 1011366, 8095 ), + new CustomItem( typeof( BodySash ), 1011372, 5441 ), + new CustomItem( typeof( Surcoat ), 1011362, 8189 ), + new CustomItem( typeof( HalfApron ), 1011373, 5435 ), + new CustomItem( typeof( FullApron ), 1011374, 5437 ), + } ), + + new CustomCategory( Layer.Shoes, 1011388, true, new CustomItem[]{//Footwear + new CustomItem( typeof( Sandals ), 1011389, 5901 ), + new CustomItem( typeof( Shoes ), 1011390, 5904 ), + new CustomItem( typeof( Boots ), 1011391, 5899 ), + new CustomItem( typeof( ThighBoots ), 1011392, 5906 ), + } ), + + new CustomCategory( Layer.Helm, 1011375, true, new CustomItem[]{//Hats + new CustomItem( typeof( SkullCap ), 1011376, 5444 ), + new CustomItem( typeof( Bandana ), 1011377, 5440 ), + new CustomItem( typeof( FloppyHat ), 1011378, 5907 ), + new CustomItem( typeof( WideBrimHat ), 1011379, 5908 ), + new CustomItem( typeof( Cap ), 1011380, 5909 ), + new CustomItem( typeof( TallStrawHat ), 1011382, 5910 ) + } ), + + new CustomCategory( Layer.Helm, 1015319, true, new CustomItem[]{//More Hats + new CustomItem( typeof( StrawHat ), 1011382, 5911 ), + new CustomItem( typeof( WizardsHat ), 1011383, 5912 ), + new CustomItem( typeof( Bonnet ), 1011384, 5913 ), + new CustomItem( typeof( FeatheredHat ), 1011385, 5914 ), + new CustomItem( typeof( TricorneHat ), 1011386, 5915 ), + new CustomItem( typeof( JesterHat ), 1011387, 5916 ) + } ), + + new CustomCategory( Layer.Pants, 1011367, true, new CustomItem[]{ //Lower Torso + new CustomItem( typeof( LongPants ), 1011368, 5433 ), + new CustomItem( typeof( Kilt ), 1011369, 5431 ), + new CustomItem( typeof( Skirt ), 1011370, 5398 ), + } ), + + new CustomCategory( Layer.Cloak, 1011393, true, new CustomItem[]{ // Back + new CustomItem( typeof( Cloak ), 1011394, 5397 ) + } ), + + new CustomCategory( Layer.Hair, 1011395, true, new CustomItem[]{ // Hair + new CustomItem( 0x203B, 1011052 ), + new CustomItem( 0x203C, 1011053 ), + new CustomItem( 0x203D, 1011054 ), + new CustomItem( 0x2044, 1011055 ), + new CustomItem( 0x2045, 1011047 ), + new CustomItem( 0x204A, 1011050 ), + new CustomItem( 0x2047, 1011396 ), + new CustomItem( 0x2048, 1011048 ), + new CustomItem( 0x2049, 1011049 ), + } ), + + new CustomCategory( Layer.FacialHair, 1015320, true, new CustomItem[]{//Facial Hair + new CustomItem( 0x2041, 1011062 ), + new CustomItem( 0x203F, 1011060 ), + new CustomItem( 0x204B, 1015321, true ), + new CustomItem( 0x203E, 1011061 ), + new CustomItem( 0x204C, 1015322, true ), + new CustomItem( 0x2040, 1015323 ), + new CustomItem( 0x204D, 1011401 ), + } ), + + new CustomCategory( Layer.FirstValid, 1011397, false, new CustomItem[]{//Held items + new CustomItem( typeof( FishingPole ), 1011406, 3520 ), + new CustomItem( typeof( Pickaxe ), 1011407, 3717 ), + new CustomItem( typeof( Pitchfork ), 1011408, 3720 ), + new CustomItem( typeof( Cleaver ), 1015324, 3778 ), + new CustomItem( typeof( Mace ), 1011409, 3933 ), + new CustomItem( typeof( Torch ), 1011410, 3940 ), + new CustomItem( typeof( Hammer ), 1011411, 4020 ), + new CustomItem( typeof( Longsword ), 1011412, 3936 ), + new CustomItem( typeof( GnarledStaff ), 1011413, 5113 ) + } ), + + new CustomCategory( Layer.FirstValid, 1015325, false, new CustomItem[]{//More held items + new CustomItem( typeof( Crossbow ), 1011414, 3920 ), + new CustomItem( typeof( WarMace ), 1011415, 5126 ), + new CustomItem( typeof( TwoHandedAxe ), 1011416, 5186 ), + new CustomItem( typeof( Spear ), 1011417, 3939 ), + new CustomItem( typeof( Katana ), 1011418, 5118 ), + new CustomItem( typeof( Spellbook ), 1011419, 3834 ) + } ) + }; + + public PlayerVendorCustomizeGump( Mobile v, Mobile from ) : base( 30, 40 ) + { + m_Vendor = v; + int x,y; + + from.CloseGump( typeof( PlayerVendorCustomizeGump ) ); + + AddPage( 0 ); + AddBackground( 0, 0, 585, 393, 5054 ); + AddBackground( 195, 36, 387, 275, 3000 ); + AddHtmlLocalized( 10, 10, 565, 18, 1011356, false, false ); //
VENDOR CUSTOMIZATION MENU
+ AddHtmlLocalized( 60, 355, 150, 18, 1011036, false, false ); // OKAY + AddButton( 25, 355, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 320, 355, 150, 18, 1011012, false, false ); // CANCEL + AddButton( 285, 355, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + + y = 35; + for ( int i=0;i 0) + { + int cnum = info.Switches[0]; + int cat = cnum % 256; + int ent = cnum >> 8; + + if (cat < Categories.Length && cat >= 0) + { + if (ent < Categories[cat].Entries.Length && ent >= 0) + { + Item item = m_Vendor.FindItemOnLayer(Categories[cat].Layer); + + if (item != null) + item.Delete(); + + List items = m_Vendor.Items; + + for (int i = 0; item == null && i < items.Count; ++i) + { + Item checkitem = items[i]; + Type type = checkitem.GetType(); + + for (int j = 0; item == null && j < Categories[cat].Entries.Length; ++j) + { + if (type == Categories[cat].Entries[j].Type) + item = checkitem; + } + } + + if (item != null) + item.Delete(); + + if (Categories[cat].Layer == Layer.FacialHair) + { + if (m_Vendor.Female) + { + from.SendLocalizedMessage(1010639); // You cannot place facial hair on a woman! + } + else + { + int hue = m_Vendor.FacialHairHue; + + m_Vendor.FacialHairItemID = 0; + m_Vendor.ProcessDelta(); // invalidate item ID for clients + + m_Vendor.FacialHairItemID = Categories[cat].Entries[ent].ItemID; + m_Vendor.FacialHairHue = hue; + } + } + else if (Categories[cat].Layer == Layer.Hair) + { + int hue = m_Vendor.HairHue; + + m_Vendor.HairItemID = 0; + m_Vendor.ProcessDelta(); // invalidate item ID for clients + + m_Vendor.HairItemID = Categories[cat].Entries[ent].ItemID; + m_Vendor.HairHue = hue; + } + else + { + item = Categories[cat].Entries[ent].Create(); + + if (item != null) + { + item.Layer = Categories[cat].Layer; + + if (!m_Vendor.EquipItem(item)) + item.Delete(); + } + } + + from.SendGump(new PlayerVendorCustomizeGump(m_Vendor, from)); + } + } + else + { + cat -= 100; + + if (cat < 100) + { + if (cat < Categories.Length && cat >= 0) + { + CustomCategory category = Categories[cat]; + + if (category.Layer == Layer.Hair) + { + new PVHairHuePicker(false, m_Vendor, from).SendTo(state); + } + else if (category.Layer == Layer.FacialHair) + { + new PVHairHuePicker(true, m_Vendor, from).SendTo(state); + } + else + { + Item item = null; + + List items = m_Vendor.Items; + + for (int i = 0; item == null && i < items.Count; ++i) + { + Item checkitem = items[i]; + Type type = checkitem.GetType(); + + for (int j = 0; item == null && j < category.Entries.Length; ++j) + { + if (type == category.Entries[j].Type) + item = checkitem; + } + } + + if (item != null) + new PVHuePicker(item, m_Vendor, from).SendTo(state); + } + } + } + else + { + cat -= 100; + + if (cat < Categories.Length && cat >= 0) + { + CustomCategory category = Categories[cat]; + + if (category.Layer == Layer.Hair) + { + m_Vendor.HairItemID = 0; + } + else if (category.Layer == Layer.FacialHair) + { + m_Vendor.FacialHairItemID = 0; + } + else + { + Item item = null; + + List items = m_Vendor.Items; + + for (int i = 0; item == null && i < items.Count; ++i) + { + Item checkitem = items[i]; + Type type = checkitem.GetType(); + + for (int j = 0; item == null && j < category.Entries.Length; ++j) + { + if (type == category.Entries[j].Type) + item = checkitem; + } + } + + if (item != null) + item.Delete(); + } + + from.SendGump(new PlayerVendorCustomizeGump(m_Vendor, from)); + } + } + } + } + } + + private class PVHuePicker : HuePicker + { + private Item m_Item; + private Mobile m_Vendor; + private Mobile m_Mob; + + public PVHuePicker(Item item, Mobile v, Mobile from) + : base(item.ItemID) + { + m_Item = item; + m_Vendor = v; + m_Mob = from; + } + + public override void OnResponse(int hue) + { + if (m_Item.Deleted) + return; + + if (m_Vendor is PlayerVendor && !((PlayerVendor)m_Vendor).CanInteractWith(m_Mob, true)) + return; + + if (m_Vendor is PlayerBarkeeper && !((PlayerBarkeeper)m_Vendor).IsOwner(m_Mob)) + return; + + m_Item.Hue = hue; + m_Mob.SendGump(new PlayerVendorCustomizeGump(m_Vendor, m_Mob)); + } + } + + private class PVHairHuePicker : HuePicker + { + private bool m_FacialHair; + private Mobile m_Vendor; + private Mobile m_Mob; + + public PVHairHuePicker(bool facialHair, Mobile v, Mobile from) + : base(0xFAB) + { + m_FacialHair = facialHair; + m_Vendor = v; + m_Mob = from; + } + + public override void OnResponse(int hue) + { + if (m_Vendor.Deleted) + return; + + if (m_Vendor is PlayerVendor && !((PlayerVendor)m_Vendor).CanInteractWith(m_Mob, true)) + return; + + if (m_Vendor is PlayerBarkeeper && !((PlayerBarkeeper)m_Vendor).IsOwner(m_Mob)) + return; + + if (m_FacialHair) + m_Vendor.FacialHairHue = hue; + else + m_Vendor.HairHue = hue; + + m_Mob.SendGump(new PlayerVendorCustomizeGump(m_Vendor, m_Mob)); + } + } + } + + public class NewPlayerVendorCustomizeGump : Gump + { + private PlayerVendor m_Vendor; + + private class HairOrBeard + { + private int m_ItemID; + private int m_Name; + + public int ItemID { get { return m_ItemID; } } + public int Name { get { return m_Name; } } + + public HairOrBeard(int itemID, int name) + { + m_ItemID = itemID; + m_Name = name; + } + } + + private static HairOrBeard[] m_HairStyles = new HairOrBeard[] + { + new HairOrBeard( 0x203B, 1011052 ), // Short + new HairOrBeard( 0x203C, 1011053 ), // Long + new HairOrBeard( 0x203D, 1011054 ), // Ponytail + new HairOrBeard( 0x2044, 1011055 ), // Mohawk + new HairOrBeard( 0x2045, 1011047 ), // Pageboy + new HairOrBeard( 0x204A, 1011050 ), // Topknot + new HairOrBeard( 0x2047, 1011396 ), // Curly + new HairOrBeard( 0x2048, 1011048 ), // Receding + new HairOrBeard( 0x2049, 1011049 ) // 2-tails + }; + + private static HairOrBeard[] m_BeardStyles = new HairOrBeard[] + { + new HairOrBeard( 0x2041, 1011062 ), // Mustache + new HairOrBeard( 0x203F, 1011060 ), // Short beard + new HairOrBeard( 0x204B, 1015321 ), // Short Beard & Moustache + new HairOrBeard( 0x203E, 1011061 ), // Long beard + new HairOrBeard( 0x204C, 1015322 ), // Long Beard & Moustache + new HairOrBeard( 0x2040, 1015323 ), // Goatee + new HairOrBeard( 0x204D, 1011401 ) // Vandyke + }; + + public NewPlayerVendorCustomizeGump(PlayerVendor vendor) + : base(50, 50) + { + m_Vendor = vendor; + + AddBackground(0, 0, 370, 370, 0x13BE); + + AddImageTiled(10, 10, 350, 20, 0xA40); + AddImageTiled(10, 40, 350, 20, 0xA40); + AddImageTiled(10, 70, 350, 260, 0xA40); + AddImageTiled(10, 340, 350, 20, 0xA40); + + AddAlphaRegion(10, 10, 350, 350); + + AddHtmlLocalized(10, 12, 350, 18, 1011356, 0x7FFF, false, false); //
VENDOR CUSTOMIZATION MENU
+ + AddHtmlLocalized(10, 42, 150, 18, 1062459, 0x421F, false, false); //
HAIR
+ + for (int i = 0; i < m_HairStyles.Length; i++) + { + HairOrBeard hair = m_HairStyles[i]; + + AddButton(10, 70 + i * 20, 0xFA5, 0xFA7, 0x100 | i, GumpButtonType.Reply, 0); + AddHtmlLocalized(45, 72 + i * 20, 110, 18, hair.Name, 0x7FFF, false, false); + } + + AddButton(10, 70 + m_HairStyles.Length * 20, 0xFB1, 0xFB3, 2, GumpButtonType.Reply, 0); + AddHtmlLocalized(45, 72 + m_HairStyles.Length * 20, 110, 18, 1011403, 0x7FFF, false, false); // Remove + + AddButton(10, 70 + (m_HairStyles.Length + 1) * 20, 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0); + AddHtmlLocalized(45, 72 + (m_HairStyles.Length + 1) * 20, 110, 18, 1011402, 0x7FFF, false, false); // Color + + if (vendor.Female) + { + AddButton(160, 290, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(195, 292, 160, 18, 1015327, 0x7FFF, false, false); // Male + + AddHtmlLocalized(195, 312, 160, 18, 1015328, 0x421F, false, false); // Female + } + else + { + AddHtmlLocalized(160, 42, 210, 18, 1062460, 0x421F, false, false); //
BEARD
+ + for (int i = 0; i < m_BeardStyles.Length; i++) + { + HairOrBeard beard = m_BeardStyles[i]; + + AddButton(160, 70 + i * 20, 0xFA5, 0xFA7, 0x200 | i, GumpButtonType.Reply, 0); + AddHtmlLocalized(195, 72 + i * 20, 160, 18, beard.Name, 0x7FFF, false, false); + } + + AddButton(160, 70 + m_BeardStyles.Length * 20, 0xFB1, 0xFB3, 4, GumpButtonType.Reply, 0); + AddHtmlLocalized(195, 72 + m_BeardStyles.Length * 20, 160, 18, 1011403, 0x7FFF, false, false); // Remove + + AddButton(160, 70 + (m_BeardStyles.Length + 1) * 20, 0xFA5, 0xFA7, 5, GumpButtonType.Reply, 0); + AddHtmlLocalized(195, 72 + (m_BeardStyles.Length + 1) * 20, 160, 18, 1011402, 0x7FFF, false, false); // Color + + AddHtmlLocalized(195, 292, 160, 18, 1015327, 0x421F, false, false); // Male + + AddButton(160, 310, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(195, 312, 160, 18, 1015328, 0x7FFF, false, false); // Female + } + + AddButton(10, 340, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(45, 342, 305, 18, 1060675, 0x7FFF, false, false); // CLOSE + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + if (!m_Vendor.CanInteractWith(from, true)) + return; + + switch (info.ButtonID) + { + case 0: // CLOSE + { + m_Vendor.Direction = m_Vendor.GetDirectionTo(from); + m_Vendor.Animate(32, 5, 1, true, false, 0); // bow + m_Vendor.SayTo(from, 1043310 + Utility.Random(12)); // a little random speech + + break; + } + case 1: // Female/Male + { + if (m_Vendor.Female) + { + m_Vendor.BodyValue = 400; + m_Vendor.Female = false; + } + else + { + m_Vendor.BodyValue = 401; + m_Vendor.Female = true; + + m_Vendor.FacialHairItemID = 0; + } + + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + + break; + } + case 2: // Remove hair + { + m_Vendor.HairItemID = 0; + + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + + break; + } + case 3: // Color hair + { + if (m_Vendor.HairItemID > 0) + { + new PVHuePicker(m_Vendor, false, from).SendTo(from.NetState); + } + else + { + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + } + + break; + } + case 4: // Remove beard + { + m_Vendor.FacialHairItemID = 0; + + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + + break; + } + case 5: // Color beard + { + if (m_Vendor.FacialHairItemID > 0) + { + new PVHuePicker(m_Vendor, true, from).SendTo(from.NetState); + } + else + { + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + } + + break; + } + default: + { + int hairhue = 0; + + if ((info.ButtonID & 0x100) != 0) // Hair style selected + { + int index = info.ButtonID & 0xFF; + + if (index >= m_HairStyles.Length) + return; + + HairOrBeard hairStyle = m_HairStyles[index]; + + hairhue = m_Vendor.HairHue; + + m_Vendor.HairItemID = 0; + m_Vendor.ProcessDelta(); + + m_Vendor.HairItemID = hairStyle.ItemID; + + m_Vendor.HairHue = hairhue; + + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + } + else if ((info.ButtonID & 0x200) != 0) // Beard style selected + { + if (m_Vendor.Female) + return; + + int index = info.ButtonID & 0xFF; + + if (index >= m_BeardStyles.Length) + return; + + HairOrBeard beardStyle = m_BeardStyles[index]; + + hairhue = m_Vendor.FacialHairHue; + + m_Vendor.FacialHairItemID = 0; + m_Vendor.ProcessDelta(); + + m_Vendor.FacialHairItemID = beardStyle.ItemID; + + m_Vendor.FacialHairHue = hairhue; + + from.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + } + + break; + } + } + } + + private class PVHuePicker : HuePicker + { + private PlayerVendor m_Vendor; + private bool m_FacialHair; + private Mobile m_From; + + public PVHuePicker(PlayerVendor vendor, bool facialHair, Mobile from) + : base(0xFAB) + { + m_Vendor = vendor; + m_FacialHair = facialHair; + m_From = from; + } + + public override void OnResponse(int hue) + { + if (!m_Vendor.CanInteractWith(m_From, true)) + return; + + if (m_FacialHair) + m_Vendor.FacialHairHue = hue; + else + m_Vendor.HairHue = hue; + + m_From.SendGump(new NewPlayerVendorCustomizeGump(m_Vendor)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/PolymorphGump.cs b/Scripts/Gumps/PolymorphGump.cs new file mode 100644 index 0000000..549fb6e --- /dev/null +++ b/Scripts/Gumps/PolymorphGump.cs @@ -0,0 +1,263 @@ +using System; +using Server; +using Server.Network; +using Server.Targets; +using Server.Spells; +using Server.Spells.Seventh; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class PolymorphEntry + { + public static readonly PolymorphEntry Chicken = new PolymorphEntry( 8401, 0xD0, 1015236, 15, 10 ); + public static readonly PolymorphEntry Dog = new PolymorphEntry( 8405, 0xD9, 1015237, 17, 10 ); + public static readonly PolymorphEntry Wolf = new PolymorphEntry( 8426, 0xE1, 1015238, 18, 10 ); + public static readonly PolymorphEntry Panther = new PolymorphEntry( 8473, 0xD6, 1015239, 20, 14 ); + public static readonly PolymorphEntry Gorilla = new PolymorphEntry( 8437, 0x1D, 1015240, 23, 10 ); + public static readonly PolymorphEntry BlackBear = new PolymorphEntry( 8399, 0xD3, 1015241, 22, 10 ); + public static readonly PolymorphEntry GrizzlyBear = new PolymorphEntry( 8411, 0xD4, 1015242, 22, 12 ); + public static readonly PolymorphEntry PolarBear = new PolymorphEntry( 8417, 0xD5, 1015243, 26, 10 ); + public static readonly PolymorphEntry HumanMale = new PolymorphEntry( 8397, 0x190, 1015244, 29, 8 ); + public static readonly PolymorphEntry HumanFemale = new PolymorphEntry( 8398, 0x191, 1015254, 29, 10 ); + public static readonly PolymorphEntry Slime = new PolymorphEntry( 8424, 0x33, 1015246, 5, 10 ); + public static readonly PolymorphEntry Orc = new PolymorphEntry( 8416, 0x11, 1015247, 29, 10 ); + public static readonly PolymorphEntry LizardMan = new PolymorphEntry( 8414, 0x21, 1015248, 26, 10 ); + public static readonly PolymorphEntry Gargoyle = new PolymorphEntry( 8409, 0x04, 1015249, 22, 10 ); + public static readonly PolymorphEntry Ogre = new PolymorphEntry( 8415, 0x01, 1015250, 24, 9 ); + public static readonly PolymorphEntry Troll = new PolymorphEntry( 8425, 0x36, 1015251, 25, 9 ); + public static readonly PolymorphEntry Ettin = new PolymorphEntry( 8408, 0x02, 1015252, 25, 8 ); + public static readonly PolymorphEntry Daemon = new PolymorphEntry( 8403, 0x09, 1015253, 25, 8 ); + + // Scriptiz : pour les f�es + public static readonly PolymorphEntry Pixie = new PolymorphEntry( 9654, 0x80, 1029654, 23, 8); + + + private int m_Art, m_Body, m_Num, m_X, m_Y; + + private PolymorphEntry( int Art, int Body, int LocNum, int X, int Y ) + { + m_Art = Art; + m_Body = Body; + m_Num = LocNum; + m_X = X; + m_Y = Y; + } + + public int ArtID { get { return m_Art; } } + public int BodyID { get { return m_Body; } } + public int LocNumber{ get { return m_Num; } } + public int X{ get{ return m_X; } } + public int Y{ get{ return m_Y; } } + } + + + public class PolymorphGump : Gump + { + private class PolymorphCategory + { + private int m_Num; + private PolymorphEntry[] m_Entries; + + public PolymorphCategory( int num, params PolymorphEntry[] entries ) + { + m_Num = num; + m_Entries = entries; + } + + public PolymorphEntry[] Entries{ get { return m_Entries; } } + public int LocNumber{ get { return m_Num; } } + } + + private static PolymorphCategory[] Categories = new PolymorphCategory[] + { + new PolymorphCategory( 1015235, // Animals + PolymorphEntry.Chicken, + PolymorphEntry.Dog, + PolymorphEntry.Wolf, + PolymorphEntry.Panther, + PolymorphEntry.Gorilla, + PolymorphEntry.BlackBear, + PolymorphEntry.GrizzlyBear, + PolymorphEntry.PolarBear, + PolymorphEntry.HumanMale ), + + new PolymorphCategory( 1015245, // Monsters + PolymorphEntry.Slime, + PolymorphEntry.Orc, + PolymorphEntry.LizardMan, + PolymorphEntry.Gargoyle, + PolymorphEntry.Ogre, + PolymorphEntry.Troll, + PolymorphEntry.Ettin, + PolymorphEntry.Daemon, + PolymorphEntry.HumanFemale, + // Scriptiz : ajout pour les f�es + PolymorphEntry.Pixie ) + }; + + + private Mobile m_Caster; + private Item m_Scroll; + + public PolymorphGump( Mobile caster, Item scroll ) : base( 50, 50 ) + { + m_Caster = caster; + m_Scroll = scroll; + + int x,y; + AddPage( 0 ); + AddBackground( 0, 0, 585, 393, 5054 ); + AddBackground( 195, 36, 387, 275, 3000 ); + AddHtmlLocalized( 0, 0, 510, 18, 1015234, false, false ); //
Polymorph Selection Menu
+ AddHtmlLocalized( 60, 355, 150, 18, 1011036, false, false ); // OKAY + AddButton( 25, 355, 4005, 4007, 1, GumpButtonType.Reply, 1 ); + AddHtmlLocalized( 320, 355, 150, 18, 1011012, false, false ); // CANCEL + AddButton( 285, 355, 4005, 4007, 0, GumpButtonType.Reply, 2 ); + + y = 35; + for ( int i=0;i 0 ) + { + int cnum = info.Switches[0]; + int cat = cnum%256; + int ent = cnum>>8; + + if ( cat >= 0 && cat < Categories.Length ) + { + if ( ent >= 0 && ent < Categories[cat].Entries.Length ) + { + Spell spell = new PolymorphSpell( m_Caster, m_Scroll, Categories[cat].Entries[ent].BodyID ); + spell.Cast(); + } + } + } + } + } + + public class NewPolymorphGump : Gump + { + private static readonly PolymorphEntry[] m_Entries = new PolymorphEntry[] + { + PolymorphEntry.Chicken, + PolymorphEntry.Dog, + PolymorphEntry.Wolf, + PolymorphEntry.Panther, + PolymorphEntry.Gorilla, + PolymorphEntry.BlackBear, + PolymorphEntry.GrizzlyBear, + PolymorphEntry.PolarBear, + PolymorphEntry.HumanMale, + PolymorphEntry.HumanFemale, + PolymorphEntry.Slime, + PolymorphEntry.Orc, + PolymorphEntry.LizardMan, + PolymorphEntry.Gargoyle, + PolymorphEntry.Ogre, + PolymorphEntry.Troll, + PolymorphEntry.Ettin, + PolymorphEntry.Daemon, + PolymorphEntry.Pixie // Scriptiz : pour les f�es + }; + + private Mobile m_Caster; + private Item m_Scroll; + + public NewPolymorphGump( Mobile caster, Item scroll ) : base( 0, 0 ) + { + m_Caster = caster; + m_Scroll = scroll; + + AddPage( 0 ); + + AddBackground( 0, 0, 520, 404, 0x13BE ); + AddImageTiled( 10, 10, 500, 20, 0xA40 ); + AddImageTiled( 10, 40, 500, 324, 0xA40 ); + AddImageTiled( 10, 374, 500, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 500, 384 ); + + AddHtmlLocalized( 14, 12, 500, 20, 1015234, 0x7FFF, false, false ); //
Polymorph Selection Menu
+ + AddButton( 10, 374, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 376, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + + for ( int i = 0; i < m_Entries.Length; i++ ) + { + PolymorphEntry entry = m_Entries[i]; + + // Scriptiz : si le type n'est pas une f�e, il ne peux pas se transformer + if(entry == PolymorphEntry.Pixie && caster is PlayerMobile && !((PlayerMobile)caster).IsFairy) + continue; + + int page = i / 10 + 1; + int pos = i % 10; + + if ( pos == 0 ) + { + if ( page > 1 ) + { + AddButton( 400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page ); + AddHtmlLocalized( 440, 376, 60, 20, 1043353, 0x7FFF, false, false ); // Next + } + + AddPage( page ); + + if ( page > 1 ) + { + AddButton( 300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1 ); + AddHtmlLocalized( 340, 376, 60, 20, 1011393, 0x7FFF, false, false ); // Back + } + } + + int x = ( pos % 2 == 0 ) ? 14 : 264; + int y = ( pos / 2 ) * 64 + 44; + + AddImageTiledButton( x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, entry.ArtID, 0x0, entry.X, entry.Y ); + AddHtmlLocalized( x + 84, y, 250, 60, entry.LocNumber, 0x7FFF, false, false ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int idx = info.ButtonID - 1; + + if ( idx < 0 || idx >= m_Entries.Length ) + return; + + Spell spell = new PolymorphSpell( m_Caster, m_Scroll, m_Entries[idx].BodyID ); + spell.Cast(); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/PropsConfig.cs b/Scripts/Gumps/Properties/PropsConfig.cs new file mode 100644 index 0000000..59b4713 --- /dev/null +++ b/Scripts/Gumps/Properties/PropsConfig.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Gumps +{ + public class PropsConfig + { + public static readonly bool OldStyle = false; + + public static readonly int GumpOffsetX = 30; + public static readonly int GumpOffsetY = 30; + + public static readonly int TextHue = 0; + public static readonly int TextOffsetX = 2; + + public static readonly int OffsetGumpID = 0x0A40; // Pure black + public static readonly int HeaderGumpID = OldStyle ? 0x0BBC : 0x0E14; // Light offwhite, textured : Dark navy blue, textured + public static readonly int EntryGumpID = 0x0BBC; // Light offwhite, textured + public static readonly int BackGumpID = 0x13BE; // Gray slate/stoney + public static readonly int SetGumpID = OldStyle ? 0x0000 : 0x0E14; // Empty : Dark navy blue, textured + + public static readonly int SetWidth = 20; + public static readonly int SetOffsetX = OldStyle ? 4 : 2, SetOffsetY = 2; + public static readonly int SetButtonID1 = 0x15E1; // Arrow pointing right + public static readonly int SetButtonID2 = 0x15E5; // " pressed + + public static readonly int PrevWidth = 20; + public static readonly int PrevOffsetX = 2, PrevOffsetY = 2; + public static readonly int PrevButtonID1 = 0x15E3; // Arrow pointing left + public static readonly int PrevButtonID2 = 0x15E7; // " pressed + + public static readonly int NextWidth = 20; + public static readonly int NextOffsetX = 2, NextOffsetY = 2; + public static readonly int NextButtonID1 = 0x15E1; // Arrow pointing right + public static readonly int NextButtonID2 = 0x15E5; // " pressed + + public static readonly int OffsetSize = 1; + + public static readonly int EntryHeight = 20; + public static readonly int BorderSize = 10; + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/PropsGump.cs b/Scripts/Gumps/Properties/PropsGump.cs new file mode 100644 index 0000000..fba3a4a --- /dev/null +++ b/Scripts/Gumps/Properties/PropsGump.cs @@ -0,0 +1,782 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Commands.Generic; +using Server.Network; +using Server.Menus; +using Server.Menus.Questions; +using Server.Targeting; +using CPA = Server.CommandPropertyAttribute; + +namespace Server.Gumps +{ + public class PropertiesGump : Gump + { + private ArrayList m_List; + private int m_Page; + private Mobile m_Mobile; + private object m_Object; + private Type m_Type; + private Stack m_Stack; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static bool PrevLabel = OldStyle, NextLabel = OldStyle; + private static bool TypeLabel = !OldStyle; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int NameWidth = 107; + private static readonly int ValueWidth = 128; + + private static readonly int EntryCount = 15; + + private static readonly int TypeWidth = NameWidth + OffsetSize + ValueWidth; + + private static readonly int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public PropertiesGump(Mobile mobile, object o) + : base(GumpOffsetX, GumpOffsetY) + { + m_Mobile = mobile; + m_Object = o; + m_Type = o.GetType(); + m_List = BuildList(); + + Initialize(0); + } + + public PropertiesGump(Mobile mobile, object o, Stack stack, StackEntry parent) + : base(GumpOffsetX, GumpOffsetY) + { + m_Mobile = mobile; + m_Object = o; + m_Type = o.GetType(); + m_Stack = stack; + m_List = BuildList(); + + if (parent != null) + { + if (m_Stack == null) + m_Stack = new Stack(); + + m_Stack.Push(parent); + } + + Initialize(0); + } + + public PropertiesGump(Mobile mobile, object o, Stack stack, ArrayList list, int page) + : base(GumpOffsetX, GumpOffsetY) + { + m_Mobile = mobile; + m_Object = o; + + if (o != null) + m_Type = o.GetType(); + + m_List = list; + m_Stack = stack; + + Initialize(page); + } + + private void Initialize(int page) + { + m_Page = page; + + int count = m_List.Count - (page * EntryCount); + + if (count < 0) + count = 0; + else if (count > EntryCount) + count = EntryCount; + + int lastIndex = (page * EntryCount) + count - 1; + + if (lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null) + --count; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1)); + + AddPage(0); + + AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0); + + if (OldStyle) + AddImageTiled(x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID); + else + AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); + + if (page > 0) + { + AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0); + + if (PrevLabel) + AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous"); + } + + x += PrevWidth + OffsetSize; + + if (!OldStyle) + AddImageTiled(x, y, emptyWidth, EntryHeight, HeaderGumpID); + + if (TypeLabel && m_Type != null) + AddHtml(x, y, emptyWidth, EntryHeight, String.Format("
{0}
", m_Type.Name), false, false); + + x += emptyWidth + OffsetSize; + + if (!OldStyle) + AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); + + if ((page + 1) * EntryCount < m_List.Count) + { + AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1); + + if (NextLabel) + AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next"); + } + + for (int i = 0, index = page * EntryCount; i < count && index < m_List.Count; ++i, ++index) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + object o = m_List[index]; + + if (o == null) + { + AddImageTiled(x - OffsetSize, y, TotalWidth, EntryHeight, BackGumpID + 4); + } + else if (o is Type) + { + Type type = (Type)o; + + AddImageTiled(x, y, TypeWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, type.Name); + x += TypeWidth + OffsetSize; + + if (SetGumpID != 0) + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + else if (o is PropertyInfo) + { + PropertyInfo prop = (PropertyInfo)o; + + AddImageTiled(x, y, NameWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, NameWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); + x += NameWidth + OffsetSize; + AddImageTiled(x, y, ValueWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, TextHue, ValueToString(prop)); + x += ValueWidth + OffsetSize; + + if (SetGumpID != 0) + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + + CPA cpa = GetCPA(prop); + + if (prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel && !cpa.ReadOnly) + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3, GumpButtonType.Reply, 0); + } + } + } + + public static string[] m_BoolNames = new string[] { "True", "False" }; + public static object[] m_BoolValues = new object[] { true, false }; + + public static string[] m_PoisonNames = new string[] { "None", "Lesser", "Regular", "Greater", "Deadly", "Lethal" }; + public static object[] m_PoisonValues = new object[] { null, Poison.Lesser, Poison.Regular, Poison.Greater, Poison.Deadly, Poison.Lethal }; + + public class StackEntry + { + public object m_Object; + public PropertyInfo m_Property; + + public StackEntry(object obj, PropertyInfo prop) + { + m_Object = obj; + m_Property = prop; + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + if (!BaseCommand.IsAccessible(from, m_Object)) + { + from.SendMessage("You may no longer access their properties."); + return; + } + + switch (info.ButtonID) + { + case 0: // Closed + { + if (m_Stack != null && m_Stack.Count > 0) + { + StackEntry entry = (StackEntry)m_Stack.Pop(); + + from.SendGump(new PropertiesGump(from, entry.m_Object, m_Stack, null)); + } + + break; + } + case 1: // Previous + { + if (m_Page > 0) + from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page - 1)); + + break; + } + case 2: // Next + { + if ((m_Page + 1) * EntryCount < m_List.Count) + from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page + 1)); + + break; + } + default: + { + int index = (m_Page * EntryCount) + (info.ButtonID - 3); + + if (index >= 0 && index < m_List.Count) + { + PropertyInfo prop = m_List[index] as PropertyInfo; + + if (prop == null) + return; + + CPA attr = GetCPA(prop); + + if (!prop.CanWrite || attr == null || from.AccessLevel < attr.WriteLevel || attr.ReadOnly) + return; + + Type type = prop.PropertyType; + + if (IsType(type, typeofMobile) || IsType(type, typeofItem)) + from.SendGump(new SetObjectGump(prop, from, m_Object, m_Stack, type, m_Page, m_List)); + else if (IsType(type, typeofType)) + from.Target = new SetObjectTarget(prop, from, m_Object, m_Stack, type, m_Page, m_List); + else if (IsType(type, typeofPoint3D)) + from.SendGump(new SetPoint3DGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + else if (IsType(type, typeofPoint2D)) + from.SendGump(new SetPoint2DGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + else if (IsType(type, typeofTimeSpan)) + from.SendGump(new SetTimeSpanGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + else if (IsCustomEnum(type)) + from.SendGump(new SetCustomEnumGump(prop, from, m_Object, m_Stack, m_Page, m_List, GetCustomEnumNames(type))); + else if (IsType(type, typeofEnum)) + from.SendGump(new SetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, Enum.GetNames(type), GetObjects(Enum.GetValues(type)))); + else if (IsType(type, typeofBool)) + from.SendGump(new SetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, m_BoolNames, m_BoolValues)); + else if (IsType(type, typeofString) || IsType(type, typeofReal) || IsType(type, typeofNumeric) || IsType(type, typeofText)) + from.SendGump(new SetGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + else if (IsType(type, typeofPoison)) + from.SendGump(new SetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, m_PoisonNames, m_PoisonValues)); + else if (IsType(type, typeofMap)) + from.SendGump(new SetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, Map.GetMapNames(), Map.GetMapValues())); + else if (IsType(type, typeofSkills) && m_Object is Mobile) + { + from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page)); + from.SendGump(new SkillsGump(from, (Mobile)m_Object)); + } + else if (HasAttribute(type, typeofPropertyObject, true)) + { + object obj = prop.GetValue(m_Object, null); + + if (obj != null) + from.SendGump(new PropertiesGump(from, obj, m_Stack, new StackEntry(m_Object, prop))); + else + from.SendGump(new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page)); + } + } + + break; + } + } + } + + private static object[] GetObjects(Array a) + { + object[] list = new object[a.Length]; + + for (int i = 0; i < list.Length; ++i) + list[i] = a.GetValue(i); + + return list; + } + + private static bool IsCustomEnum(Type type) + { + return type.IsDefined(typeofCustomEnum, false); + } + + public static void OnValueChanged(object obj, PropertyInfo prop, Stack stack) + { + if (stack == null || stack.Count == 0) + return; + + if (!prop.PropertyType.IsValueType) + return; + + StackEntry peek = (StackEntry)stack.Peek(); + + if (peek.m_Property.CanWrite) + peek.m_Property.SetValue(peek.m_Object, obj, null); + } + + private static string[] GetCustomEnumNames(Type type) + { + object[] attrs = type.GetCustomAttributes(typeofCustomEnum, false); + + if (attrs.Length == 0) + return new string[0]; + + CustomEnumAttribute ce = attrs[0] as CustomEnumAttribute; + + if (ce == null) + return new string[0]; + + return ce.Names; + } + + private static bool HasAttribute(Type type, Type check, bool inherit) + { + object[] objs = type.GetCustomAttributes(check, inherit); + + return (objs != null && objs.Length > 0); + } + + private static bool IsType(Type type, Type check) + { + return type == check || type.IsSubclassOf(check); + } + + private static bool IsType(Type type, Type[] check) + { + for (int i = 0; i < check.Length; ++i) + if (IsType(type, check[i])) + return true; + + return false; + } + + private static Type typeofMobile = typeof(Mobile); + private static Type typeofItem = typeof(Item); + private static Type typeofType = typeof(Type); + private static Type typeofPoint3D = typeof(Point3D); + private static Type typeofPoint2D = typeof(Point2D); + private static Type typeofTimeSpan = typeof(TimeSpan); + private static Type typeofCustomEnum = typeof(CustomEnumAttribute); + private static Type typeofEnum = typeof(Enum); + private static Type typeofBool = typeof(Boolean); + private static Type typeofString = typeof(String); + private static Type typeofText = typeof(TextDefinition); + private static Type typeofPoison = typeof(Poison); + private static Type typeofMap = typeof(Map); + private static Type typeofSkills = typeof(Skills); + private static Type typeofPropertyObject = typeof(PropertyObjectAttribute); + private static Type typeofNoSort = typeof(NoSortAttribute); + + private static Type[] typeofReal = new Type[] + { + typeof( Single ), + typeof( Double ) + }; + + private static Type[] typeofNumeric = new Type[] + { + typeof( Byte ), + typeof( Int16 ), + typeof( Int32 ), + typeof( Int64 ), + typeof( SByte ), + typeof( UInt16 ), + typeof( UInt32 ), + typeof( UInt64 ) + }; + + private string ValueToString(PropertyInfo prop) + { + return ValueToString(m_Object, prop); + } + + public static string ValueToString(object obj, PropertyInfo prop) + { + try + { + return ValueToString(prop.GetValue(obj, null)); + } + catch (Exception e) + { + return String.Format("!{0}!", e.GetType()); + } + } + + public static string ValueToString(object o) + { + if (o == null) + { + return "-null-"; + } + else if (o is string) + { + return String.Format("\"{0}\"", (string)o); + } + else if (o is bool) + { + return o.ToString(); + } + else if (o is char) + { + return String.Format("0x{0:X} '{1}'", (int)(char)o, (char)o); + } + else if (o is Serial) + { + Serial s = (Serial)o; + + if (s.IsValid) + { + if (s.IsItem) + { + return String.Format("(I) 0x{0:X}", s.Value); + } + else if (s.IsMobile) + { + return String.Format("(M) 0x{0:X}", s.Value); + } + } + + return String.Format("(?) 0x{0:X}", s.Value); + } + else if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong) + { + return String.Format("{0} (0x{0:X})", o); + } + else if (o is Mobile) + { + return String.Format("(M) 0x{0:X} \"{1}\"", ((Mobile)o).Serial.Value, ((Mobile)o).Name); + } + else if (o is Item) + { + return String.Format("(I) 0x{0:X}", ((Item)o).Serial.Value); + } + else if (o is Type) + { + return ((Type)o).Name; + } + else if (o is TextDefinition) + { + return ((TextDefinition)o).Format(true); + } + else + { + return o.ToString(); + } + } + + private ArrayList BuildList() + { + ArrayList list = new ArrayList(); + + if (m_Type == null) + return list; + + PropertyInfo[] props = m_Type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + ArrayList groups = GetGroups(m_Type, props); + + for (int i = 0; i < groups.Count; ++i) + { + DictionaryEntry de = (DictionaryEntry)groups[i]; + ArrayList groupList = (ArrayList)de.Value; + + if (!HasAttribute((Type)de.Key, typeofNoSort, false)) + groupList.Sort(PropertySorter.Instance); + + if (i != 0) + list.Add(null); + + list.Add(de.Key); + list.AddRange(groupList); + } + + return list; + } + + private static Type typeofCPA = typeof(CPA); + private static Type typeofObject = typeof(object); + + private static CPA GetCPA(PropertyInfo prop) + { + object[] attrs = prop.GetCustomAttributes(typeofCPA, false); + + if (attrs.Length > 0) + return attrs[0] as CPA; + else + return null; + } + + private ArrayList GetGroups(Type objectType, PropertyInfo[] props) + { + Hashtable groups = new Hashtable(); + + for (int i = 0; i < props.Length; ++i) + { + PropertyInfo prop = props[i]; + + if (prop.CanRead) + { + CPA attr = GetCPA(prop); + + if (attr != null && m_Mobile.AccessLevel >= attr.ReadLevel) + { + Type type = prop.DeclaringType; + + while (true) + { + Type baseType = type.BaseType; + + if (baseType == null || baseType == typeofObject) + break; + + if (baseType.GetProperty(prop.Name, prop.PropertyType) != null) + type = baseType; + else + break; + } + + ArrayList list = (ArrayList)groups[type]; + + if (list == null) + groups[type] = list = new ArrayList(); + + list.Add(prop); + } + } + } + + ArrayList sorted = new ArrayList(groups); + + sorted.Sort(new GroupComparer(objectType)); + + return sorted; + } + + public static object GetObjectFromString(Type t, string s) + { + if (t == typeof(string)) + { + return s; + } + else if (t == typeof(byte) || t == typeof(sbyte) || t == typeof(short) || t == typeof(ushort) || t == typeof(int) || t == typeof(uint) || t == typeof(long) || t == typeof(ulong)) + { + if (s.StartsWith("0x")) + { + if (t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte)) + { + return Convert.ChangeType(Convert.ToUInt64(s.Substring(2), 16), t); + } + else + { + return Convert.ChangeType(Convert.ToInt64(s.Substring(2), 16), t); + } + } + else + { + return Convert.ChangeType(s, t); + } + } + else if (t == typeof(double) || t == typeof(float)) + { + return Convert.ChangeType(s, t); + } + else if (t.IsDefined(typeof(ParsableAttribute), false)) + { + MethodInfo parseMethod = t.GetMethod("Parse", new Type[] { typeof(string) }); + + return parseMethod.Invoke(null, new object[] { s }); + } + + throw new Exception("bad"); + } + + private static string GetStringFromObject(object o) + { + if (o == null) + { + return "-null-"; + } + else if (o is string) + { + return String.Format("\"{0}\"", (string)o); + } + else if (o is bool) + { + return o.ToString(); + } + else if (o is char) + { + return String.Format("0x{0:X} '{1}'", (int)(char)o, (char)o); + } + else if (o is Serial) + { + Serial s = (Serial)o; + + if (s.IsValid) + { + if (s.IsItem) + { + return String.Format("(I) 0x{0:X}", s.Value); + } + else if (s.IsMobile) + { + return String.Format("(M) 0x{0:X}", s.Value); + } + } + + return String.Format("(?) 0x{0:X}", s.Value); + } + else if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong) + { + return String.Format("{0} (0x{0:X})", o); + } + else if (o is Mobile) + { + return String.Format("(M) 0x{0:X} \"{1}\"", ((Mobile)o).Serial.Value, ((Mobile)o).Name); + } + else if (o is Item) + { + return String.Format("(I) 0x{0:X}", ((Item)o).Serial.Value); + } + else if (o is Type) + { + return ((Type)o).Name; + } + else + { + return o.ToString(); + } + } + + private class PropertySorter : IComparer + { + public static readonly PropertySorter Instance = new PropertySorter(); + + private PropertySorter() + { + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + return 0; + else if (x == null) + return -1; + else if (y == null) + return 1; + + PropertyInfo a = x as PropertyInfo; + PropertyInfo b = y as PropertyInfo; + + if (a == null || b == null) + throw new ArgumentException(); + + return a.Name.CompareTo(b.Name); + } + } + + private class GroupComparer : IComparer + { + private Type m_Start; + + public GroupComparer(Type start) + { + m_Start = start; + } + + private static Type typeofObject = typeof(Object); + + private int GetDistance(Type type) + { + Type current = m_Start; + + int dist; + + for (dist = 0; current != null && current != typeofObject && current != type; ++dist) + current = current.BaseType; + + return dist; + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + return 0; + else if (x == null) + return -1; + else if (y == null) + return 1; + + if (!(x is DictionaryEntry) || !(y is DictionaryEntry)) + throw new ArgumentException(); + + DictionaryEntry de1 = (DictionaryEntry)x; + DictionaryEntry de2 = (DictionaryEntry)y; + + Type a = (Type)de1.Key; + Type b = (Type)de2.Key; + + return GetDistance(a).CompareTo(GetDistance(b)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetBodyGump.cs b/Scripts/Gumps/Properties/SetBodyGump.cs new file mode 100644 index 0000000..80871c1 --- /dev/null +++ b/Scripts/Gumps/Properties/SetBodyGump.cs @@ -0,0 +1,295 @@ +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.HuePickers; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetBodyGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + private int m_OurPage; + private ArrayList m_OurList; + private ModelBodyType m_OurType; + + private const int LabelColor32 = 0xFFFFFF; + private const int SelectedColor32 = 0x8080FF; + private const int TextColor32 = 0xFFFFFF; + + public SetBodyGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) + : this( prop, mobile, o, stack, page, list, 0, null, ModelBodyType.Invalid ) + { + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public void AddTypeButton( int x, int y, int buttonID, string text, ModelBodyType type ) + { + bool isSelection = (m_OurType == type); + + AddButton( x, y - 1, isSelection ? 4006 : 4005, 4007, buttonID, GumpButtonType.Reply, 0 ); + AddHtml( x + 35, y, 200, 20, Color( text, isSelection ? SelectedColor32 : LabelColor32 ), false, false ); + } + + public SetBodyGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list, int ourPage, ArrayList ourList, ModelBodyType ourType ) + : base( 20, 30 ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + m_OurPage = ourPage; + m_OurList = ourList; + m_OurType = ourType; + + AddPage( 0 ); + + AddBackground( 0, 0, 525, 328, 5054 ); + + AddImageTiled( 10, 10, 505, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 505, 20 ); + + AddImageTiled( 10, 35, 505, 283, 0xA40 ); + AddAlphaRegion( 10, 35, 505, 283 ); + + AddTypeButton( 10, 10, 1, "Monster", ModelBodyType.Monsters ); + AddTypeButton( 130, 10, 2, "Animal", ModelBodyType.Animals ); + AddTypeButton( 250, 10, 3, "Marine", ModelBodyType.Sea ); + AddTypeButton( 370, 10, 4, "Human", ModelBodyType.Human ); + + AddImage( 480, 12, 0x25EA ); + AddImage( 497, 12, 0x25E6 ); + + if( ourList == null ) + { + AddLabel( 15, 40, 0x480, "Choose a body type above." ); + } + else if( ourList.Count == 0 ) + { + AddLabel( 15, 40, 0x480, "The server must have UO:3D installed to use this feature." ); + } + else + { + for( int i = 0, index = (ourPage * 12); i < 12 && index >= 0 && index < ourList.Count; ++i, ++index ) + { + InternalEntry entry = (InternalEntry)ourList[index]; + int itemID = entry.ItemID; + + Rectangle2D bounds = ItemBounds.Table[itemID & 0x3FFF]; + + int x = 15 + ((i % 4) * 125); + int y = 40 + ((i / 4) * 93); + + AddItem( x + ((120 - bounds.Width) / 2) - bounds.X, y + ((69 - bounds.Height) / 2) - bounds.Y, itemID ); + AddButton( x + 6, y + 66, 0x98D, 0x98D, 7 + index, GumpButtonType.Reply, 0 ); + + x += 6; + y += 67; + + AddHtml( x + 0, y - 1, 108, 21, Center( entry.DisplayName ), false, false ); + AddHtml( x + 0, y + 1, 108, 21, Center( entry.DisplayName ), false, false ); + AddHtml( x - 1, y + 0, 108, 21, Center( entry.DisplayName ), false, false ); + AddHtml( x + 1, y + 0, 108, 21, Center( entry.DisplayName ), false, false ); + AddHtml( x + 0, y + 0, 108, 21, Color( Center( entry.DisplayName ), TextColor32 ), false, false ); + } + + if( ourPage > 0 ) + AddButton( 480, 12, 0x15E3, 0x15E7, 5, GumpButtonType.Reply, 0 ); + + if( (ourPage + 1) * 12 < ourList.Count ) + AddButton( 497, 12, 0x15E1, 0x15E5, 6, GumpButtonType.Reply, 0 ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if( index == -1 ) + { + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + else if( index >= 0 && index < 4 ) + { + if( m_Monster == null ) + LoadLists(); + + ModelBodyType type; + ArrayList list; + + switch( index ) + { + default: + case 0: type = ModelBodyType.Monsters; list = m_Monster; break; + case 1: type = ModelBodyType.Animals; list = m_Animal; break; + case 2: type = ModelBodyType.Sea; list = m_Sea; break; + case 3: type = ModelBodyType.Human; list = m_Human; break; + } + + m_Mobile.SendGump( new SetBodyGump( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List, 0, list, type ) ); + } + else if( m_OurList != null ) + { + index -= 4; + + if( index == 0 && m_OurPage > 0 ) + { + m_Mobile.SendGump( new SetBodyGump( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List, m_OurPage - 1, m_OurList, m_OurType ) ); + } + else if( index == 1 && ((m_OurPage + 1) * 12) < m_OurList.Count ) + { + m_Mobile.SendGump( new SetBodyGump( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List, m_OurPage + 1, m_OurList, m_OurType ) ); + } + else + { + index -= 2; + + if( index >= 0 && index < m_OurList.Count ) + { + try + { + InternalEntry entry = (InternalEntry)m_OurList[index]; + + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, entry.Body.ToString() ); + m_Property.SetValue( m_Object, entry.Body, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + + m_Mobile.SendGump( new SetBodyGump( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List, m_OurPage, m_OurList, m_OurType ) ); + } + } + } + } + + private static ArrayList m_Monster, m_Animal, m_Sea, m_Human; + + private static void LoadLists() + { + m_Monster = new ArrayList(); + m_Animal = new ArrayList(); + m_Sea = new ArrayList(); + m_Human = new ArrayList(); + + List entries = Docs.LoadBodies(); + + for( int i = 0; i < entries.Count; ++i ) + { + BodyEntry oldEntry = (BodyEntry)entries[i]; + int bodyID = oldEntry.Body.BodyID; + + if( ((Body)bodyID).IsEmpty ) + continue; + + ArrayList list = null; + + switch( oldEntry.BodyType ) + { + case ModelBodyType.Monsters: list = m_Monster; break; + case ModelBodyType.Animals: list = m_Animal; break; + case ModelBodyType.Sea: list = m_Sea; break; + case ModelBodyType.Human: list = m_Human; break; + } + + if( list == null ) + continue; + + int itemID = ShrinkTable.Lookup( bodyID, -1 ); + + if( itemID != -1 ) + list.Add( new InternalEntry( bodyID, itemID, oldEntry.Name ) ); + } + + m_Monster.Sort(); + m_Animal.Sort(); + m_Sea.Sort(); + m_Human.Sort(); + } + + private class InternalEntry : IComparable + { + private int m_Body; + private int m_ItemID; + private string m_Name; + private string m_DisplayName; + + public int Body { get { return m_Body; } } + public int ItemID { get { return m_ItemID; } } + public string Name { get { return m_Name; } } + public string DisplayName { get { return m_DisplayName; } } + + private static string[] m_GroupNames = new string[] + { + "ogres_", "ettins_", "walking_dead_", "gargoyles_", + "orcs_", "flails_", "daemons_", "arachnids_", + "dragons_", "elementals_", "serpents_", "gazers_", + "liche_", "spirits_", "harpies_", "headless_", + "lizard_race_", "mongbat_", "rat_race_", "scorpions_", + "trolls_", "slimes_", "skeletons_", "ethereals_", + "terathan_", "imps_", "cyclops_", "krakens_", + "frogs_", "ophidians_", "centaurs_", "mages_", + "fey_race_", "genies_", "paladins_", "shadowlords_", + "succubi_", "lizards_", "rodents_", "birds_", + "bovines_", "bruins_", "canines_", "deer_", + "equines_", "felines_", "fowl_", "gorillas_", + "kirin_", "llamas_", "ostards_", "porcines_", + "ruminants_", "walrus_", "dolphins_", "sea_horse_", + "sea_serpents_", "character_", "h_", "titans_" + }; + + public InternalEntry( int body, int itemID, string name ) + { + m_Body = body; + m_ItemID = itemID; + m_Name = name; + + m_DisplayName = name.ToLower(); + + for( int i = 0; i < m_GroupNames.Length; ++i ) + { + if( m_DisplayName.StartsWith( m_GroupNames[i] ) ) + { + m_DisplayName = m_DisplayName.Substring( m_GroupNames[i].Length ); + break; + } + } + + m_DisplayName = m_DisplayName.Replace( '_', ' ' ); + } + + public int CompareTo( object obj ) + { + InternalEntry comp = (InternalEntry)obj; + + int v = m_Name.CompareTo( comp.m_Name ); + + if( v == 0 ) + m_Body.CompareTo( comp.m_Body ); + + return v; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetCustomEnumGump.cs b/Scripts/Gumps/Properties/SetCustomEnumGump.cs new file mode 100644 index 0000000..97c62bd --- /dev/null +++ b/Scripts/Gumps/Properties/SetCustomEnumGump.cs @@ -0,0 +1,50 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetCustomEnumGump : SetListOptionGump + { + private string[] m_Names; + + public SetCustomEnumGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int propspage, ArrayList list, string[] names ) : base( prop, mobile, o, stack, propspage, list, names, null ) + { + m_Names = names; + } + + public override void OnResponse( NetState sender, RelayInfo relayInfo ) + { + int index = relayInfo.ButtonID - 1; + + if ( index >= 0 && index < m_Names.Length ) + { + try + { + MethodInfo info = m_Property.PropertyType.GetMethod( "Parse", new Type[]{ typeof( string ) } ); + + string result = ""; + + if ( info != null ) + result = Properties.SetDirect( m_Mobile, m_Object, m_Object, m_Property, m_Property.Name, info.Invoke( null, new object[] { m_Names[index] } ), true ); + else if ( m_Property.PropertyType == typeof( Enum ) || m_Property.PropertyType.IsSubclassOf( typeof( Enum ) ) ) + result = Properties.SetDirect( m_Mobile, m_Object, m_Object, m_Property, m_Property.Name, Enum.Parse( m_Property.PropertyType, m_Names[index], false ), true ); + + m_Mobile.SendMessage( result ); + + if ( result == "Property has been set." ) + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetGump.cs b/Scripts/Gumps/Properties/SetGump.cs new file mode 100644 index 0000000..ea0d357 --- /dev/null +++ b/Scripts/Gumps/Properties/SetGump.cs @@ -0,0 +1,281 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.HuePickers; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (2 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public SetGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + bool canNull = !prop.PropertyType.IsValueType; + bool canDye = prop.IsDefined( typeof( HueAttribute ), false ); + bool isBody = prop.IsDefined( typeof( BodyAttribute ), false ); + + object val = prop.GetValue( m_Object, null ); + string initialText; + + if ( val == null ) + initialText = ""; + else if (val is TextDefinition) + initialText = ((TextDefinition)val).GetValue(); + else + initialText = val.ToString(); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight + (canNull ? (EntryHeight + OffsetSize) : 0) + (canDye ? (EntryHeight + OffsetSize) : 0) + (isBody ? (EntryHeight + OffsetSize) : 0), BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight + (canNull ? (EntryHeight + OffsetSize) : 0) + (canDye ? (EntryHeight + OffsetSize) : 0) + (isBody ? (EntryHeight + OffsetSize) : 0), OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddTextEntry( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, 0, initialText ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( canNull ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Null" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + } + + if ( canDye ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Hue Picker" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + } + + if ( isBody ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Body Picker" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 4, GumpButtonType.Reply, 0 ); + } + } + + private class InternalPicker : HuePicker + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public InternalPicker( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( ((IHued)o).HuedItemID ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + public override void OnResponse( int hue ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, hue.ToString() ); + m_Property.SetValue( m_Object, hue, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + object toSet; + bool shouldSet, shouldSend = true; + + switch ( info.ButtonID ) + { + case 1: + { + TextRelay text = info.GetTextEntry( 0 ); + + if ( text != null ) + { + try + { + toSet = PropertiesGump.GetObjectFromString( m_Property.PropertyType, text.Text ); + shouldSet = true; + } + catch + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage( "Bad format" ); + } + } + else + { + toSet = null; + shouldSet = false; + } + + break; + } + case 2: // Null + { + toSet = null; + shouldSet = true; + + break; + } + case 3: // Hue Picker + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendHuePicker( new InternalPicker( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ) ); + + break; + } + case 4: // Body Picker + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendGump( new SetBodyGump( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ) ); + + break; + } + default: + { + toSet = null; + shouldSet = false; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet==null?"(null)":toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetListOptionGump.cs b/Scripts/Gumps/Properties/SetListOptionGump.cs new file mode 100644 index 0000000..ce70387 --- /dev/null +++ b/Scripts/Gumps/Properties/SetListOptionGump.cs @@ -0,0 +1,187 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetListOptionGump : Gump + { + protected PropertyInfo m_Property; + protected Mobile m_Mobile; + protected object m_Object; + protected Stack m_Stack; + protected int m_Page; + protected ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + private static readonly int EntryCount = 13; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + + private static bool PrevLabel = OldStyle, NextLabel = OldStyle; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + protected object[] m_Values; + + public SetListOptionGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int propspage, ArrayList list, string[] names, object[] values ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = propspage; + m_List = list; + + m_Values = values; + + int pages = (names.Length + EntryCount - 1) / EntryCount; + int index = 0; + + for ( int page = 1; page <= pages; ++page ) + { + AddPage( page ); + + int start = (page - 1) * EntryCount; + int count = names.Length - start; + + if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((count + 2) * (EntryHeight + OffsetSize)); + int backHeight = BorderSize + totalHeight + BorderSize; + + AddBackground( 0, 0, BackWidth, backHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0); + + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 1 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 0, GumpButtonType.Page, page - 1 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, HeaderGumpID ); + + x += emptyWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( page < pages ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 0, GumpButtonType.Page, page + 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + + + AddRect( 0, prop.Name, 0 ); + + for ( int i = 0; i < count; ++i ) + AddRect( i + 1, names[index], ++index ); + } + } + + private void AddRect( int index, string str, int button ) + { + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize + ((index + 1) * (EntryHeight + OffsetSize)); + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( button != 0 ) + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, button, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_Values.Length ) + { + try + { + object toSet = m_Values[index]; + + string result = Properties.SetDirect( m_Mobile, m_Object, m_Object, m_Property, m_Property.Name, toSet, true ); + + m_Mobile.SendMessage( result ); + + if ( result == "Property has been set." ) + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetObjectGump.cs b/Scripts/Gumps/Properties/SetObjectGump.cs new file mode 100644 index 0000000..711a892 --- /dev/null +++ b/Scripts/Gumps/Properties/SetObjectGump.cs @@ -0,0 +1,308 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Commands.Generic; +using Server.Network; +using Server.Prompts; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetObjectGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private Type m_Type; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (5 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public SetObjectGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + + string initialText = PropertiesGump.ValueToString( o, prop ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, initialText ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Change by Serial" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Nullify" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "View Properties" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 4, GumpButtonType.Reply, 0 ); + } + + private class InternalPrompt : Prompt + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private Type m_Type; + private int m_Page; + private ArrayList m_List; + + public InternalPrompt( PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + } + + public override void OnCancel( Mobile from ) + { + m_Mobile.SendGump( new SetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + object toSet; + bool shouldSet; + + try + { + int serial = Utility.ToInt32( text ); + + toSet = World.FindEntity( serial ); + + if ( toSet == null ) + { + shouldSet = false; + m_Mobile.SendMessage( "No object with that serial was found." ); + } + else if ( !m_Type.IsAssignableFrom( toSet.GetType() ) ) + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage( "The object with that serial could not be assigned to a property of type : {0}", m_Type.Name ); + } + else + { + shouldSet = true; + } + } + catch + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage( "Bad format" ); + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet==null?"(null)":toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + m_Mobile.SendGump( new SetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + object toSet; + bool shouldSet, shouldSend = true; + object viewProps = null; + + switch ( info.ButtonID ) + { + case 0: // closed + { + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + + toSet = null; + shouldSet = false; + shouldSend = false; + + break; + } + case 1: // Change by Target + { + m_Mobile.Target = new SetObjectTarget( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ); + toSet = null; + shouldSet = false; + shouldSend = false; + break; + } + case 2: // Change by Serial + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendMessage( "Enter the serial you wish to find:" ); + m_Mobile.Prompt = new InternalPrompt( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ); + + break; + } + case 3: // Nullify + { + toSet = null; + shouldSet = true; + + break; + } + case 4: // View Properties + { + toSet = null; + shouldSet = false; + + object obj = m_Property.GetValue( m_Object, null ); + + if ( obj == null ) + m_Mobile.SendMessage( "The property is null and so you cannot view its properties." ); + else if ( !BaseCommand.IsAccessible( m_Mobile, obj ) ) + m_Mobile.SendMessage( "You may not view their properties." ); + else + viewProps = obj; + + break; + } + default: + { + toSet = null; + shouldSet = false; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet==null?"(null)":toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new SetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + + if ( viewProps != null ) + m_Mobile.SendGump( new PropertiesGump( m_Mobile, viewProps ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetObjectTarget.cs b/Scripts/Gumps/Properties/SetObjectTarget.cs new file mode 100644 index 0000000..7ae9a10 --- /dev/null +++ b/Scripts/Gumps/Properties/SetObjectTarget.cs @@ -0,0 +1,66 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetObjectTarget : Target + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private Type m_Type; + private int m_Page; + private ArrayList m_List; + + public SetObjectTarget( PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list ) : base( -1, false, TargetFlags.None ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + try + { + if ( m_Type == typeof( Type ) ) + targeted = targeted.GetType(); + else if ( (m_Type == typeof( BaseAddon ) || m_Type.IsAssignableFrom( typeof( BaseAddon ) )) && targeted is AddonComponent ) + targeted = ((AddonComponent)targeted).Addon; + + if ( m_Type.IsAssignableFrom( targeted.GetType() ) ) + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, targeted.ToString() ); + m_Property.SetValue( m_Object, targeted, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + else + { + m_Mobile.SendMessage( "That cannot be assigned to a property of type : {0}", m_Type.Name ); + } + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_Type == typeof( Type ) ) + from.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + else + from.SendGump( new SetObjectGump( m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetPoint2DGump.cs b/Scripts/Gumps/Properties/SetPoint2DGump.cs new file mode 100644 index 0000000..b993c20 --- /dev/null +++ b/Scripts/Gumps/Properties/SetPoint2DGump.cs @@ -0,0 +1,237 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetPoint2DGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int CoordWidth = 105; + private static readonly int EntryWidth = CoordWidth + OffsetSize + CoordWidth; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (4 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public SetPoint2DGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + Point2D p = (Point2D)prop.GetValue( o, null ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 0, p.X.ToString() ); + x += CoordWidth + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Y:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 1, p.Y.ToString() ); + x += CoordWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + } + + private class InternalTarget : Target + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public InternalTarget( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( -1, true, TargetFlags.None ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p != null ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, new Point2D( p ).ToString() ); + m_Property.SetValue( m_Object, new Point2D( p ), null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Point2D toSet; + bool shouldSet, shouldSend; + + switch ( info.ButtonID ) + { + case 1: // Current location + { + toSet = new Point2D( m_Mobile.Location ); + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // Pick location + { + m_Mobile.Target = new InternalTarget( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ); + + toSet = Point2D.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // Use values + { + TextRelay x = info.GetTextEntry( 0 ); + TextRelay y = info.GetTextEntry( 1 ); + + toSet = new Point2D( x == null ? 0 : Utility.ToInt32( x.Text ), y == null ? 0 : Utility.ToInt32( y.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + default: + { + toSet = Point2D.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetPoint3DGump.cs b/Scripts/Gumps/Properties/SetPoint3DGump.cs new file mode 100644 index 0000000..fb3ab90 --- /dev/null +++ b/Scripts/Gumps/Properties/SetPoint3DGump.cs @@ -0,0 +1,243 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetPoint3DGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int CoordWidth = 70; + private static readonly int EntryWidth = CoordWidth + OffsetSize + CoordWidth + OffsetSize + CoordWidth; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (4 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public SetPoint3DGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + Point3D p = (Point3D)prop.GetValue( o, null ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location" ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2, GumpButtonType.Reply, 0 ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 0, p.X.ToString() ); + x += CoordWidth + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Y:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 1, p.Y.ToString() ); + x += CoordWidth + OffsetSize; + + AddImageTiled( x, y, CoordWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Z:" ); + AddTextEntry( x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 2, p.Z.ToString() ); + x += CoordWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3, GumpButtonType.Reply, 0 ); + } + + private class InternalTarget : Target + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public InternalTarget( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( -1, true, TargetFlags.None ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p != null ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, new Point3D( p ).ToString() ); + m_Property.SetValue( m_Object, new Point3D( p ), null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Point3D toSet; + bool shouldSet, shouldSend; + + switch ( info.ButtonID ) + { + case 1: // Current location + { + toSet = m_Mobile.Location; + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // Pick location + { + m_Mobile.Target = new InternalTarget( m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List ); + + toSet = Point3D.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // Use values + { + TextRelay x = info.GetTextEntry( 0 ); + TextRelay y = info.GetTextEntry( 1 ); + TextRelay z = info.GetTextEntry( 2 ); + + toSet = new Point3D( x == null ? 0 : Utility.ToInt32( x.Text ), y == null ? 0 : Utility.ToInt32( y.Text ), z == null ? 0 : Utility.ToInt32( z.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + default: + { + toSet = Point3D.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/Properties/SetTimeSpanGump.cs b/Scripts/Gumps/Properties/SetTimeSpanGump.cs new file mode 100644 index 0000000..24c6438 --- /dev/null +++ b/Scripts/Gumps/Properties/SetTimeSpanGump.cs @@ -0,0 +1,238 @@ +using System; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class SetTimeSpanGump : Gump + { + private PropertyInfo m_Property; + private Mobile m_Mobile; + private object m_Object; + private Stack m_Stack; + private int m_Page; + private ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (7 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public SetTimeSpanGump( PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list ) : base( GumpOffsetX, GumpOffsetY ) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + TimeSpan ts = (TimeSpan)prop.GetValue( o, null ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + AddRect( 0, prop.Name, 0, -1 ); + AddRect( 1, ts.ToString(), 0, -1 ); + AddRect( 2, "Zero", 1, -1 ); + AddRect( 3, "From H:M:S", 2, -1 ); + AddRect( 4, "H:", 3, 0 ); + AddRect( 5, "M:", 4, 1 ); + AddRect( 6, "S:", 5, 2 ); + } + + private void AddRect( int index, string str, int button, int text ) + { + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize + (index * (EntryHeight + OffsetSize)); + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str ); + + if ( text != -1 ) + AddTextEntry( x + 16 + TextOffsetX, y, EntryWidth - TextOffsetX - 16, EntryHeight, TextHue, text, "" ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( button != 0 ) + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, button, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + TimeSpan toSet; + bool shouldSet, shouldSend; + + TextRelay h = info.GetTextEntry( 0 ); + TextRelay m = info.GetTextEntry( 1 ); + TextRelay s = info.GetTextEntry( 2 ); + + switch ( info.ButtonID ) + { + case 1: // Zero + { + toSet = TimeSpan.Zero; + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // From H:M:S + { + bool successfulParse = false; + if( h != null && m != null && s != null ) + { + successfulParse = TimeSpan.TryParse( h.Text + ":" + m.Text + ":" + s.Text, out toSet ); + } + else + { + toSet = TimeSpan.Zero; + } + + shouldSet = shouldSend = successfulParse; + + break; + } + case 3: // From H + { + if ( h != null ) + { + try + { + toSet = TimeSpan.FromHours( Utility.ToDouble( h.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 4: // From M + { + if ( m != null ) + { + try + { + toSet = TimeSpan.FromMinutes( Utility.ToDouble( m.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 5: // From S + { + if ( s != null ) + { + try + { + toSet = TimeSpan.FromSeconds( Utility.ToDouble( s.Text ) ); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + default: + { + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if ( shouldSet ) + { + try + { + CommandLogging.LogChangeProperty( m_Mobile, m_Object, m_Property.Name, toSet.ToString() ); + m_Property.SetValue( m_Object, toSet, null ); + PropertiesGump.OnValueChanged( m_Object, m_Property, m_Stack ); + } + catch + { + m_Mobile.SendMessage( "An exception was caught. The property may not have changed." ); + } + } + + if ( shouldSend ) + m_Mobile.SendGump( new PropertiesGump( m_Mobile, m_Object, m_Stack, m_List, m_Page ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/ReclaimVendorGump.cs b/Scripts/Gumps/ReclaimVendorGump.cs new file mode 100644 index 0000000..c148eff --- /dev/null +++ b/Scripts/Gumps/ReclaimVendorGump.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Multis; + +namespace Server.Gumps +{ + public class ReclaimVendorGump : Gump + { + private BaseHouse m_House; + private ArrayList m_Vendors; + + public ReclaimVendorGump( BaseHouse house ) : base( 50, 50 ) + { + m_House = house; + m_Vendors = new ArrayList( house.InternalizedVendors ); + + AddBackground( 0, 0, 170, 50 + m_Vendors.Count * 20, 0x13BE ); + + AddImageTiled( 10, 10, 150, 20, 0xA40 ); + AddHtmlLocalized( 10, 10, 150, 20, 1061827, 0x7FFF, false, false ); //
Reclaim Vendor
+ + AddImageTiled( 10, 40, 150, m_Vendors.Count * 20, 0xA40 ); + + for ( int i = 0; i < m_Vendors.Count; i++ ) + { + Mobile m = (Mobile) m_Vendors[i]; + + int y = 40 + i * 20; + + AddButton( 10, y, 0xFA5, 0xFA7, i + 1, GumpButtonType.Reply, 0 ); + AddLabel( 45, y, 0x481, m.Name ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 0 || !m_House.IsActive || !m_House.IsInside( from ) || !m_House.IsOwner( from ) || !from.CheckAlive() ) + return; + + int index = info.ButtonID - 1; + + if ( index < 0 || index >= m_Vendors.Count ) + return; + + Mobile mob = (Mobile) m_Vendors[index]; + + if ( !m_House.InternalizedVendors.Contains( mob ) ) + return; + + if ( mob.Deleted ) + { + m_House.InternalizedVendors.Remove( mob ); + } + else + { + bool vendor, contract; + BaseHouse.IsThereVendor( from.Location, from.Map, out vendor, out contract ); + + if ( vendor ) + { + from.SendLocalizedMessage( 1062677 ); // You cannot place a vendor or barkeep at this location. + } + else if ( contract ) + { + from.SendLocalizedMessage( 1062678 ); // You cannot place a vendor or barkeep on top of a rental contract! + } + else + { + m_House.InternalizedVendors.Remove( mob ); + mob.MoveToWorld( from.Location, from.Map ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/ReportMurderer.cs b/Scripts/Gumps/ReportMurderer.cs new file mode 100644 index 0000000..b3e2ee9 --- /dev/null +++ b/Scripts/Gumps/ReportMurderer.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using Server.Misc; +using Server.Network; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class ReportMurdererGump : Gump + { + private int m_Idx; + private List m_Killers; + private Mobile m_Victum; + + public static void Initialize() + { + EventSink.PlayerDeath += new PlayerDeathEventHandler( EventSink_PlayerDeath ); + } + + public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) + { + Mobile m = e.Mobile; + + List killers = new List(); + List toGive = new List(); + + foreach ( AggressorInfo ai in m.Aggressors ) + { + if ( ai.Attacker.Player && ai.CanReportMurder && !ai.Reported ) + { + if (!Core.SE || !((PlayerMobile)m).RecentlyReported.Contains(ai.Attacker)) + { + killers.Add(ai.Attacker); + ai.Reported = true; + ai.CanReportMurder = false; + } + } + if ( ai.Attacker.Player && (DateTime.Now - ai.LastCombatTime) < TimeSpan.FromSeconds( 30.0 ) && !toGive.Contains( ai.Attacker ) ) + toGive.Add( ai.Attacker ); + } + + foreach ( AggressorInfo ai in m.Aggressed ) + { + if ( ai.Defender.Player && (DateTime.Now - ai.LastCombatTime) < TimeSpan.FromSeconds( 30.0 ) && !toGive.Contains( ai.Defender ) ) + toGive.Add( ai.Defender ); + } + + foreach ( Mobile g in toGive ) + { + int n = Notoriety.Compute( g, m ); + + int theirKarma = m.Karma, ourKarma = g.Karma; + bool innocent = ( n == Notoriety.Innocent ); + bool criminal = ( n == Notoriety.Criminal || n == Notoriety.Murderer ); + + int fameAward = m.Fame / 200; + int karmaAward = 0; + + if ( innocent ) + karmaAward = ( ourKarma > -2500 ? -850 : -110 - (m.Karma / 100) ); + else if ( criminal ) + karmaAward = 50; + + Titles.AwardFame( g, fameAward, false ); + Titles.AwardKarma( g, karmaAward, true ); + } + + if ( m is PlayerMobile && ((PlayerMobile)m).NpcGuild == NpcGuild.ThievesGuild ) + return; + + if ( killers.Count > 0 ) + new GumpTimer( m, killers ).Start(); + } + + private class GumpTimer : Timer + { + private Mobile m_Victim; + private List m_Killers; + + public GumpTimer( Mobile victim, List killers ) : base( TimeSpan.FromSeconds( 4.0 ) ) + { + m_Victim = victim; + m_Killers = killers; + } + + protected override void OnTick() + { + m_Victim.SendGump( new ReportMurdererGump( m_Victim, m_Killers ) ); + } + } + + public ReportMurdererGump( Mobile victum, List killers ) : this( victum, killers, 0 ) + { + } + + private ReportMurdererGump( Mobile victum, List killers, int idx ) : base( 0, 0 ) + { + m_Killers = killers; + m_Victum = victum; + m_Idx = idx; + BuildGump(); + } + + private void BuildGump() + { + AddBackground( 265, 205, 320, 290, 5054 ); + Closable = false; + Resizable = false; + + AddPage( 0 ); + + AddImageTiled( 225, 175, 50, 45, 0xCE ); //Top left corner + AddImageTiled( 267, 175, 315, 44, 0xC9 ); //Top bar + AddImageTiled( 582, 175, 43, 45, 0xCF ); //Top right corner + AddImageTiled( 225, 219, 44, 270, 0xCA ); //Left side + AddImageTiled( 582, 219, 44, 270, 0xCB ); //Right side + AddImageTiled( 225, 489, 44, 43, 0xCC ); //Lower left corner + AddImageTiled( 267, 489, 315, 43, 0xE9 ); //Lower Bar + AddImageTiled( 582, 489, 43, 43, 0xCD ); //Lower right corner + + AddPage( 1 ); + + AddHtml( 260, 234, 300, 140, ((Mobile)m_Killers[m_Idx]).Name, false, false ); // Player's Name + AddHtmlLocalized( 260, 254, 300, 140, 1049066, false, false ); // Would you like to report... + + AddButton( 260, 300, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 300, 300, 300, 50, 1046362, false, false ); // Yes + + AddButton( 360, 300, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 400, 300, 300, 50, 1046363, false, false ); // No + } + + public static void ReportedListExpiry_Callback( object state ) + { + object[] states = (object[])state; + + PlayerMobile from = (PlayerMobile)states[0]; + Mobile killer = (Mobile)states[1]; + + if (from.RecentlyReported.Contains(killer)) + { + from.RecentlyReported.Remove(killer); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 1: + { + Mobile killer = m_Killers[m_Idx]; + if ( killer != null && !killer.Deleted ) + { + killer.Kills++; + killer.ShortTermMurders++; + + if (Core.SE) + { + ((PlayerMobile)from).RecentlyReported.Add(killer); + Timer.DelayCall(TimeSpan.FromMinutes(10), new TimerStateCallback(ReportedListExpiry_Callback), new object[] { from, killer }); + } + + if (killer is PlayerMobile) + { + PlayerMobile pk = (PlayerMobile)killer; + pk.ResetKillTime(); + pk.SendLocalizedMessage(1049067);//You have been reported for murder! + + if (pk.Kills == 5) + { + pk.SendLocalizedMessage(502134);//You are now known as a murderer! + } + else if (SkillHandlers.Stealing.SuspendOnMurder && pk.Kills == 1 && pk.NpcGuild == NpcGuild.ThievesGuild) + { + pk.SendLocalizedMessage(501562); // You have been suspended by the Thieves Guild. + } + } + } + break; + } + case 2: + { + break; + } + } + + m_Idx++; + if ( m_Idx < m_Killers.Count ) + from.SendGump( new ReportMurdererGump( from, m_Killers, m_Idx ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/ResurrectGump.cs b/Scripts/Gumps/ResurrectGump.cs new file mode 100644 index 0000000..ed8fc5c --- /dev/null +++ b/Scripts/Gumps/ResurrectGump.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.Gumps +{ + public enum ResurrectMessage + { + ChaosShrine = 0, + VirtueShrine = 1, + Healer = 2, + Generic = 3, + } + + public class ResurrectGump : Gump + { + private Mobile m_Healer; + private int m_Price; + private bool m_FromSacrifice; + private double m_HitsScalar; + + public ResurrectGump( Mobile owner ) + : this( owner, owner, ResurrectMessage.Generic, false ) + { + } + + public ResurrectGump( Mobile owner, double hitsScalar ) + : this( owner, owner, ResurrectMessage.Generic, false, hitsScalar ) + { + } + + public ResurrectGump( Mobile owner, bool fromSacrifice ) + : this( owner, owner, ResurrectMessage.Generic, fromSacrifice ) + { + } + + public ResurrectGump( Mobile owner, Mobile healer ) + : this( owner, healer, ResurrectMessage.Generic, false ) + { + } + + public ResurrectGump( Mobile owner, ResurrectMessage msg ) + : this( owner, owner, msg, false ) + { + } + + public ResurrectGump( Mobile owner, Mobile healer, ResurrectMessage msg ) + : this( owner, healer, msg, false ) + { + } + + public ResurrectGump( Mobile owner, Mobile healer, ResurrectMessage msg, bool fromSacrifice ) + : this( owner, healer, msg, fromSacrifice, 0.0 ) + { + } + + public ResurrectGump( Mobile owner, Mobile healer, ResurrectMessage msg, bool fromSacrifice, double hitsScalar ) + : base( 100, 0 ) + { + m_Healer = healer; + m_FromSacrifice = fromSacrifice; + m_HitsScalar = hitsScalar; + + AddPage( 0 ); + + AddBackground( 0, 0, 400, 350, 2600 ); + + AddHtmlLocalized( 0, 20, 400, 35, 1011022, false, false ); //
Resurrection
+ + AddHtmlLocalized( 50, 55, 300, 140, 1011023 + (int)msg, true, true ); /* It is possible for you to be resurrected here by this healer. Do you wish to try?
+ * CONTINUE - You chose to try to come back to life now.
+ * CANCEL - You prefer to remain a ghost for now. + */ + + AddButton( 200, 227, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 235, 230, 110, 35, 1011012, false, false ); // CANCEL + + AddButton( 65, 227, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 100, 230, 110, 35, 1011011, false, false ); // CONTINUE + } + + public ResurrectGump( Mobile owner, Mobile healer, int price ) + : base( 150, 50 ) + { + m_Healer = healer; + m_Price = price; + + Closable = false; + + AddPage( 0 ); + + AddImage( 0, 0, 3600 ); + + AddImageTiled( 0, 14, 15, 200, 3603 ); + AddImageTiled( 380, 14, 14, 200, 3605 ); + + AddImage( 0, 201, 3606 ); + + AddImageTiled( 15, 201, 370, 16, 3607 ); + AddImageTiled( 15, 0, 370, 16, 3601 ); + + AddImage( 380, 0, 3602 ); + + AddImage( 380, 201, 3608 ); + + AddImageTiled( 15, 15, 365, 190, 2624 ); + + AddRadio( 30, 140, 9727, 9730, true, 1 ); + AddHtmlLocalized( 65, 145, 300, 25, 1060015, 0x7FFF, false, false ); // Grudgingly pay the money + + AddRadio( 30, 175, 9727, 9730, false, 0 ); + AddHtmlLocalized( 65, 178, 300, 25, 1060016, 0x7FFF, false, false ); // I'd rather stay dead, you scoundrel!!! + + AddHtmlLocalized( 30, 20, 360, 35, 1060017, 0x7FFF, false, false ); // Wishing to rejoin the living, are you? I can restore your body... for a price of course... + + AddHtmlLocalized( 30, 105, 345, 40, 1060018, 0x5B2D, false, false ); // Do you accept the fee, which will be withdrawn from your bank? + + AddImage( 65, 72, 5605 ); + + AddImageTiled( 80, 90, 200, 1, 9107 ); + AddImageTiled( 95, 92, 200, 1, 9157 ); + + AddLabel( 90, 70, 1645, price.ToString() ); + AddHtmlLocalized( 140, 70, 100, 25, 1023823, 0x7FFF, false, false ); // gold coins + + AddButton( 290, 175, 247, 248, 2, GumpButtonType.Reply, 0 ); + + AddImageTiled( 15, 14, 365, 1, 9107 ); + AddImageTiled( 380, 14, 1, 190, 9105 ); + AddImageTiled( 15, 205, 365, 1, 9107 ); + AddImageTiled( 15, 14, 1, 190, 9105 ); + AddImageTiled( 0, 0, 395, 1, 9157 ); + AddImageTiled( 394, 0, 1, 217, 9155 ); + AddImageTiled( 0, 216, 395, 1, 9157 ); + AddImageTiled( 0, 0, 1, 217, 9155 ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + from.CloseGump( typeof( ResurrectGump ) ); + + if( info.ButtonID == 1 || info.ButtonID == 2 ) + { + if( from.Map == null || !from.Map.CanFit( from.Location, 16, false, false ) ) + { + from.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + return; + } + + if( m_Price > 0 ) + { + if( info.IsSwitched( 1 ) ) + { + if( Banker.Withdraw( from, m_Price ) ) + { + from.SendLocalizedMessage( 1060398, m_Price.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + from.SendLocalizedMessage( 1060022, Banker.GetBalance( from ).ToString() ); // You have ~1_AMOUNT~ gold in cash remaining in your bank box. + } + else + { + from.SendLocalizedMessage( 1060020 ); // Unfortunately, you do not have enough cash in your bank to cover the cost of the healing. + return; + } + } + else + { + from.SendLocalizedMessage( 1060019 ); // You decide against paying the healer, and thus remain dead. + return; + } + } + + from.PlaySound( 0x214 ); + from.FixedEffect( 0x376A, 10, 16 ); + + from.Resurrect(); + + if( m_Healer != null && from != m_Healer ) + { + VirtueLevel level = VirtueHelper.GetLevel( m_Healer, VirtueName.Compassion ); + + switch( level ) + { + case VirtueLevel.Seeker: from.Hits = AOS.Scale( from.HitsMax, 20 ); break; + case VirtueLevel.Follower: from.Hits = AOS.Scale( from.HitsMax, 40 ); break; + case VirtueLevel.Knight: from.Hits = AOS.Scale( from.HitsMax, 80 ); break; + } + } + + if( m_FromSacrifice && from is PlayerMobile ) + { + ((PlayerMobile)from).AvailableResurrects -= 1; + + Container pack = from.Backpack; + Container corpse = from.Corpse; + + if( pack != null && corpse != null ) + { + List items = new List( corpse.Items ); + + for( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if( item.Layer != Layer.Hair && item.Layer != Layer.FacialHair && item.Movable ) + pack.DropItem( item ); + } + } + } + + if( from.Fame > 0 ) + { + int amount = from.Fame / 10; + + Misc.Titles.AwardFame( from, -amount, true ); + } + + if( !Core.AOS && from.ShortTermMurders >= 5 ) + { + double loss = (100.0 - (4.0 + (from.ShortTermMurders / 5.0))) / 100.0; // 5 to 15% loss + + if( loss < 0.85 ) + loss = 0.85; + else if( loss > 0.95 ) + loss = 0.95; + + if( from.RawStr * loss > 10 ) + from.RawStr = (int)(from.RawStr * loss); + if( from.RawInt * loss > 10 ) + from.RawInt = (int)(from.RawInt * loss); + if( from.RawDex * loss > 10 ) + from.RawDex = (int)(from.RawDex * loss); + + for( int s = 0; s < from.Skills.Length; s++ ) + { + if( from.Skills[s].Base * loss > 35 ) + from.Skills[s].Base *= loss; + } + } + + if( from.Alive && m_HitsScalar > 0 ) + from.Hits = (int)(from.HitsMax * m_HitsScalar); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/RewardGump.cs b/Scripts/Gumps/RewardGump.cs new file mode 100644 index 0000000..fd6047f --- /dev/null +++ b/Scripts/Gumps/RewardGump.cs @@ -0,0 +1,189 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Gumps +{ + /* + * A generic version of the EA Clean Up Britannia reward gump. + */ + + public interface IRewardEntry + { + int Price { get; } + int ItemID { get; } + int Hue { get; } + int Tooltip { get; } + TextDefinition Description { get; } + } + + public delegate void RewardPickedHandler(Mobile from, int index); + + public class RewardGump : Gump + { + private TextDefinition m_Title; + private IRewardEntry[] m_Rewards; + private int m_Points; + private RewardPickedHandler m_OnPicked; + + public TextDefinition Title { get { return m_Title; } } + public IRewardEntry[] Rewards { get { return m_Rewards; } } + public int Points { get { return m_Points; } } + public RewardPickedHandler OnPicked { get { return m_OnPicked; } } + + public RewardGump(TextDefinition title, IRewardEntry[] rewards, int points, RewardPickedHandler onPicked) + : base(250, 50) + { + m_Title = title; + m_Rewards = rewards; + m_Points = points; + m_OnPicked = onPicked; + + AddPage(0); + + AddImage(0, 0, 0x1F40); + AddImageTiled(20, 37, 300, 308, 0x1F42); + AddImage(20, 325, 0x1F43); + AddImage(35, 8, 0x39); + AddImageTiled(65, 8, 257, 10, 0x3A); + AddImage(290, 8, 0x3B); + AddImage(32, 33, 0x2635); + AddImageTiled(70, 55, 230, 2, 0x23C5); + + if (m_Title.String != null) + AddHtml(70, 35, 270, 20, m_Title.String, false, false); + else if (m_Title.Number != 0) + AddHtmlLocalized(70, 35, 270, 20, m_Title.Number, 1, false, false); + + AddHtmlLocalized(50, 65, 150, 20, 1072843, 1, false, false); // Your Reward Points: + AddLabel(230, 65, 0x64, m_Points.ToString()); + AddImageTiled(35, 85, 270, 2, 0x23C5); + AddHtmlLocalized(35, 90, 270, 20, 1072844, 1, false, false); // Please Choose a Reward: + + AddPage(1); + + int offset = 110; + int page = 1; + + for (int i = 0; i < m_Rewards.Length; ++i) + { + IRewardEntry entry = m_Rewards[i]; + + Rectangle2D bounds = ItemBounds.Table[entry.ItemID]; + int height = Math.Max(36, bounds.Height); + + if (offset + height > 320) + { + AddHtmlLocalized(240, 335, 60, 20, 1072854, 1, false, false); //
Next
+ AddButton(300, 335, 0x15E1, 0x15E5, 51, GumpButtonType.Page, page + 1); + + AddPage(++page); + + AddButton(150, 335, 0x15E3, 0x15E7, 52, GumpButtonType.Page, page - 1); + AddHtmlLocalized(170, 335, 60, 20, 1074880, 1, false, false); // Previous + + offset = 110; + } + + bool available = (entry.Price <= m_Points); + int half = offset + (height / 2); + + if (available) + AddButton(35, half - 6, 0x837, 0x838, 100 + i, GumpButtonType.Reply, 0); + + AddItem(83 - (bounds.Width / 2) - bounds.X, half - (bounds.Height / 2) - bounds.Y, entry.ItemID, available ? entry.Hue : 995); + + if (entry.Tooltip != 0) + AddTooltip(entry.Tooltip); + + AddLabel(133, half - 10, available ? 0x64 : 0x21, entry.Price.ToString()); + + if (entry.Description != null) + { + if (entry.Description.String != null) + AddHtml(190, offset, 114, height, entry.Description.String, false, false); + else if (entry.Description.Number != 0) + AddHtmlLocalized(190, offset, 114, height, entry.Description.Number, 1, false, false); + } + + offset += height + 10; + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int choice = info.ButtonID; + + if (choice == 0) + return; // Close + + choice -= 100; + + if (choice >= 0 && choice < m_Rewards.Length) + { + IRewardEntry entry = m_Rewards[choice]; + + if (entry.Price <= m_Points) + sender.Mobile.SendGump(new RewardConfirmGump(this, choice, entry)); + } + } + } + + public class RewardConfirmGump : Gump + { + private RewardGump m_Parent; + private int m_Index; + + public RewardConfirmGump(RewardGump parent, int index, IRewardEntry entry) + : base(120, 50) + { + m_Parent = parent; + m_Index = index; + + Closable = false; + + AddPage(0); + + AddImageTiled(0, 0, 348, 262, 0xA8E); + AddAlphaRegion(0, 0, 348, 262); + AddImage(0, 15, 0x27A8); + AddImageTiled(0, 30, 17, 200, 0x27A7); + AddImage(0, 230, 0x27AA); + AddImage(15, 0, 0x280C); + AddImageTiled(30, 0, 300, 17, 0x280A); + AddImage(315, 0, 0x280E); + AddImage(15, 244, 0x280C); + AddImageTiled(30, 244, 300, 17, 0x280A); + AddImage(315, 244, 0x280E); + AddImage(330, 15, 0x27A8); + AddImageTiled(330, 30, 17, 200, 0x27A7); + AddImage(330, 230, 0x27AA); + AddImage(333, 2, 0x2716); + AddImage(333, 248, 0x2716); + AddImage(2, 248, 0x2716); + AddImage(2, 2, 0x2716); + + AddItem(140, 120, entry.ItemID, entry.Hue); + + if (entry.Tooltip != 0) + AddTooltip(entry.Tooltip); + + AddHtmlLocalized(25, 22, 200, 20, 1074974, 0x7D00, false, false); // Confirm Selection + AddImage(25, 40, 0xBBF); + AddHtmlLocalized(25, 55, 300, 120, 1074975, 0xFFFFFF, false, false); // Are you sure you wish to select this? + AddRadio(25, 175, 0x25F8, 0x25FB, true, 1); + AddRadio(25, 210, 0x25F8, 0x25FB, false, 0); + AddHtmlLocalized(60, 180, 280, 20, 1074976, 0xFFFFFF, false, false); // Yes + AddHtmlLocalized(60, 215, 280, 20, 1074977, 0xFFFFFF, false, false); // No + AddButton(265, 220, 0xF7, 0xF8, 7, GumpButtonType.Reply, 0); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 7 && info.IsSwitched(1)) + m_Parent.OnPicked(sender.Mobile, m_Index); + else + sender.Mobile.SendGump(new RewardGump(m_Parent.Title, m_Parent.Rewards, m_Parent.Points, m_Parent.OnPicked)); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/RunebookGump.cs b/Scripts/Gumps/RunebookGump.cs new file mode 100644 index 0000000..abc14cb --- /dev/null +++ b/Scripts/Gumps/RunebookGump.cs @@ -0,0 +1,448 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.Spells; +using Server.Spells.Fourth; +using Server.Spells.Seventh; +using Server.Spells.Chivalry; +using Server.Prompts; + +namespace Server.Gumps +{ + public class RunebookGump : Gump + { + private Runebook m_Book; + + public Runebook Book{ get{ return m_Book; } } + + public int GetMapHue( Map map ) + { + if ( map == Map.Trammel ) + return 10; + else if ( map == Map.Felucca ) + return 81; + else if ( map == Map.Ilshenar ) + return 1102; + else if ( map == Map.Malas ) + return 1102; + else if ( map == Map.Tokuno ) + return 1154; + + return 0; + } + + public string GetName( string name ) + { + if ( name == null || (name = name.Trim()).Length <= 0 ) + return "(indescript)"; + + return name; + } + + private void AddBackground() + { + AddPage( 0 ); + + // Background image + AddImage( 100, 10, 2200 ); + + // Two separators + for ( int i = 0; i < 2; ++i ) + { + int xOffset = 125 + (i * 165); + + AddImage( xOffset, 50, 57 ); + xOffset += 20; + + for ( int j = 0; j < 6; ++j, xOffset += 15 ) + AddImage( xOffset, 50, 58 ); + + AddImage( xOffset - 5, 50, 59 ); + } + + // First four page buttons + for ( int i = 0, xOffset = 130, gumpID = 2225; i < 4; ++i, xOffset += 35, ++gumpID ) + AddButton( xOffset, 187, gumpID, gumpID, 0, GumpButtonType.Page, 2 + i ); + + // Next four page buttons + for ( int i = 0, xOffset = 300, gumpID = 2229; i < 4; ++i, xOffset += 35, ++gumpID ) + AddButton( xOffset, 187, gumpID, gumpID, 0, GumpButtonType.Page, 6 + i ); + + // Charges + AddHtmlLocalized( 140, 40, 80, 18, 1011296, false, false ); // Charges: + AddHtml( 220, 40, 30, 18, m_Book.CurCharges.ToString(), false, false ); + + // Max charges + AddHtmlLocalized( 300, 40, 100, 18, 1011297, false, false ); // Max Charges: + AddHtml( 400, 40, 30, 18, m_Book.MaxCharges.ToString(), false, false ); + } + + private void AddIndex() + { + // Index + AddPage( 1 ); + + // Rename button + AddButton( 125, 15, 2472, 2473, 1, GumpButtonType.Reply, 0 ); + AddHtml( 158, 22, 100, 18, "Renommer le livre", false, false ); // Rename book + + // List of entries + List entries = m_Book.Entries; + + for ( int i = 0; i < 16; ++i ) + { + string desc; + int hue; + + if ( i < entries.Count ) + { + desc = GetName( entries[i].Description ); + hue = GetMapHue( entries[i].Map ); + } + else + { + desc = "Empty"; + hue = 0; + } + + // Use charge button + AddButton( 130 + ((i / 8) * 160), 65 + ((i % 8) * 15), 2103, 2104, 2 + (i * 6) + 0, GumpButtonType.Reply, 0 ); + + // Description label + AddLabelCropped( 145 + ((i / 8) * 160), 60 + ((i % 8) * 15), 115, 17, hue, desc ); + } + + // Turn page button + AddButton( 393, 14, 2206, 2206, 0, GumpButtonType.Page, 2 ); + } + + private void AddDetails( int index, int half ) + { + // Use charge button + AddButton( 130 + (half * 160), 65, 2103, 2104, 2 + (index * 6) + 0, GumpButtonType.Reply, 0 ); + + string desc; + int hue; + + if ( index < m_Book.Entries.Count ) + { + RunebookEntry e = (RunebookEntry)m_Book.Entries[index]; + + desc = GetName( e.Description ); + hue = GetMapHue( e.Map ); + + // Location labels + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if ( Sextant.Format( e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + { + AddLabel( 135 + (half * 160), 80, 0, String.Format( "{0}� {1}'{2}", yLat, yMins, ySouth ? "S" : "N" ) ); + AddLabel( 135 + (half * 160), 95, 0, String.Format( "{0}� {1}'{2}", xLong, xMins, xEast ? "E" : "W" ) ); + } + + // Drop rune button + AddButton( 135 + (half * 160), 115, 2437, 2438, 2 + (index * 6) + 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 150 + (half * 160), 115, 100, 18, 1011298, false, false ); // Drop rune + + // Set as default button + int defButtonID = e != m_Book.Default ? 2361 : 2360; + + AddButton( 160 + (half * 140), 20, defButtonID, defButtonID, 2 + (index * 6) + 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 175 + (half * 140), 15, 100, 18, 1011300, false, false ); // Set default + + if ( Core.AOS ) + { + AddButton( 135 + (half * 160), 140, 2103, 2104, 2 + (index * 6) + 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 150 + (half * 160), 136, 110, 20, 1062722, false, false ); // Recall + + AddButton( 135 + (half * 160), 158, 2103, 2104, 2 + (index * 6) + 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 150 + (half * 160), 154, 110, 20, 1062723, false, false ); // Gate Travel + + AddButton( 135 + (half * 160), 176, 2103, 2104, 2 + (index * 6) + 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 150 + (half * 160), 172, 110, 20, 1062724, false, false ); // Sacred Journey + } + else + { + // Recall button + AddButton( 135 + (half * 160), 140, 2271, 2271, 2 + (index * 6) + 3, GumpButtonType.Reply, 0 ); + + // Gate button + AddButton( 205 + (half * 160), 140, 2291, 2291, 2 + (index * 6) + 4, GumpButtonType.Reply, 0 ); + } + } + else + { + desc = "Empty"; + hue = 0; + } + + // Description label + AddLabelCropped( 145 + (half * 160), 60, 115, 17, hue, desc ); + } + + public RunebookGump( Mobile from, Runebook book ) : base( 150, 200 ) + { + m_Book = book; + + AddBackground(); + AddIndex(); + + for ( int page = 0; page < 8; ++page ) + { + AddPage( 2 + page ); + + AddButton( 125, 14, 2205, 2205, 0, GumpButtonType.Page, 1 + page ); + + if ( page < 7 ) + AddButton( 393, 14, 2206, 2206, 0, GumpButtonType.Page, 3 + page ); + + for ( int half = 0; half < 2; ++half ) + AddDetails( (page * 2) + half, half ); + } + } + + public static bool HasSpell( Mobile from, int spellID ) + { + Spellbook book = Spellbook.Find( from, spellID ); + + return ( book != null && book.HasSpell( spellID ) ); + } + + private class InternalPrompt : Prompt + { + private Runebook m_Book; + + public InternalPrompt( Runebook book ) + { + m_Book = book; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Book.Deleted || !from.InRange( m_Book.GetWorldLocation(), (Core.ML ? 3 : 1) ) ) + return; + + if ( m_Book.CheckAccess( from ) ) + { + m_Book.Description = Utility.FixHtml( text.Trim() ); + + from.CloseGump( typeof( RunebookGump ) ); + from.SendGump( new RunebookGump( from, m_Book ) ); + + from.SendMessage( "Le livre de runes a �t� renomm�." ); + } + else + { + m_Book.Openers.Remove( from ); + + from.SendMessage( "Vous ne pouvez faire cela lorsque le livre est fix� au sol" ); // That cannot be done while the book is locked down. + } + } + + public override void OnCancel( Mobile from ) + { + from.SendMessage( "Requ�te annul�e" ); // Request cancelled. + + if ( !m_Book.Deleted && from.InRange( m_Book.GetWorldLocation(), (Core.ML ? 3 : 1) ) ) + { + from.CloseGump( typeof( RunebookGump ) ); + from.SendGump( new RunebookGump( from, m_Book ) ); + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( m_Book.Deleted || !from.InRange( m_Book.GetWorldLocation(), (Core.ML ? 3 : 1) ) || !Multis.DesignContext.Check( from ) ) + { + m_Book.Openers.Remove( from ); + return; + } + + int buttonID = info.ButtonID; + + if ( buttonID == 1 ) // Rename book + { + if ( !m_Book.IsLockedDown || from.AccessLevel >= AccessLevel.GameMaster ) + { + from.SendMessage( "Choisissez le titre de votre livre de runes" ); // Please enter a title for the runebook: + from.Prompt = new InternalPrompt( m_Book ); + } + else + { + m_Book.Openers.Remove( from ); + + from.SendMessage("Vous ne pouvez faire cela lorsque le livre est fix� au sol", null, 0x35); // That cannot be done while the book is locked down. + } + } + else + { + buttonID -= 2; + + int index = buttonID / 6; + int type = buttonID % 6; + + if ( index >= 0 && index < m_Book.Entries.Count ) + { + RunebookEntry e = (RunebookEntry)m_Book.Entries[index]; + + switch ( type ) + { + case 0: // Use charges + { + if ( m_Book.CurCharges <= 0 ) + { + from.CloseGump( typeof( RunebookGump ) ); + from.SendGump( new RunebookGump( from, m_Book ) ); + + from.SendMessage( "Il n'y a plus de charge dans ce livre" ); // There are no charges left on that item. + } + else + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if ( Sextant.Format( e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + { + string location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + from.SendMessage( location ); + } + + m_Book.OnTravel(); + new RecallSpell( from, m_Book, e, m_Book ).Cast(); + + m_Book.Openers.Remove( from ); + } + + break; + } + case 1: // Drop rune + { + if ( !m_Book.IsLockedDown || from.AccessLevel >= AccessLevel.GameMaster ) + { + m_Book.DropRune( from, e, index ); + + from.CloseGump( typeof( RunebookGump ) ); + if ( !Core.ML ) + from.SendGump( new RunebookGump( from, m_Book ) ); + } + else + { + m_Book.Openers.Remove( from ); + + from.SendMessage("Vous ne pouvez faire cela lorsque le livre est fix� au sol", null, 0x35); // That cannot be done while the book is locked down. + } + + break; + } + case 2: // Set default + { + if ( m_Book.CheckAccess( from ) ) + { + m_Book.Default = e; + + from.CloseGump( typeof( RunebookGump ) ); + from.SendGump( new RunebookGump( from, m_Book ) ); + + from.SendLocalizedMessage( 502417 ); // New default location set. + } + + break; + } + case 3: // Recall + { + if ( HasSpell( from, 31 ) ) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if ( Sextant.Format( e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + { + string location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + from.SendMessage( location ); + } + + m_Book.OnTravel(); + new RecallSpell( from, null, e, null ).Cast(); + } + else + { + from.SendMessage( "Vous n'avez pas ce sort!" ); // You do not have that spell! + } + + m_Book.Openers.Remove( from ); + + break; + } + case 4: // Gate + { + if ( HasSpell( from, 51 ) ) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if ( Sextant.Format( e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + { + string location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + from.SendMessage( location ); + } + + m_Book.OnTravel(); + new GateTravelSpell( from, null, e ).Cast(); + } + else + { + from.SendMessage( "Vous n'avez pas ce sort!" ); // You do not have that spell! + } + + m_Book.Openers.Remove( from ); + + break; + } + case 5: // Sacred Journey + { + if ( Core.AOS ) + { + if ( HasSpell( from, 209 ) ) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if ( Sextant.Format( e.Location, e.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + { + string location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + from.SendMessage( location ); + } + + m_Book.OnTravel(); + new SacredJourneySpell( from, null, e, null ).Cast(); + } + else + { + from.SendMessage( "Vous n'avez pas ce sort!" ); // You do not have that spell! + } + } + + m_Book.Openers.Remove( from ); + + break; + } + } + } + else + m_Book.Openers.Remove( from ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/SetSecureLevelGump.cs b/Scripts/Gumps/SetSecureLevelGump.cs new file mode 100644 index 0000000..90305f5 --- /dev/null +++ b/Scripts/Gumps/SetSecureLevelGump.cs @@ -0,0 +1,93 @@ +using System; +using Server; +using Server.Multis; +using Server.Network; +using Server.Guilds; + +namespace Server.Gumps +{ + public interface ISecurable + { + SecureLevel Level{ get; set; } + } + + public class SetSecureLevelGump : Gump + { + private ISecurable m_Info; + + public SetSecureLevelGump( Mobile owner, ISecurable info, BaseHouse house ) : base( 50, 50 ) + { + m_Info = info; + + AddPage( 0 ); + + int offset = ( Guild.NewGuildSystem )? 20 : 0; + + AddBackground( 0, 0, 220, 160 + offset, 5054 ); + + AddImageTiled( 10, 10, 200, 20, 5124 ); + AddImageTiled( 10, 40, 200, 20, 5124 ); + AddImageTiled( 10, 70, 200, 80 + offset, 5124 ); + + AddAlphaRegion( 10, 10, 200, 140 ); + + AddHtmlLocalized( 10, 10, 200, 20, 1061276, 32767, false, false ); //
SET ACCESS
+ AddHtmlLocalized( 10, 40, 100, 20, 1041474, 32767, false, false ); // Owner: + + AddLabel( 110, 40, 1152, owner == null ? "" : owner.Name ); + + AddButton( 10, 70, GetFirstID( SecureLevel.Owner ), 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 70, 150, 20, 1061277, GetColor( SecureLevel.Owner ), false, false ); // Owner Only + + AddButton( 10, 90, GetFirstID( SecureLevel.CoOwners ), 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 90, 150, 20, 1061278, GetColor( SecureLevel.CoOwners ), false, false ); // Co-Owners + + AddButton( 10, 110, GetFirstID( SecureLevel.Friends ), 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 110, 150, 20, 1061279, GetColor( SecureLevel.Friends ), false, false ); // Friends + + Mobile houseOwner = house.Owner; + if( Guild.NewGuildSystem && house != null && houseOwner != null && houseOwner.Guild != null && ((Guild)houseOwner.Guild).Leader == houseOwner ) //Only the actual House owner AND guild master can set guild secures + { + AddButton( 10, 130, GetFirstID( SecureLevel.Guild ), 4007, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 130, 150, 20, 1063455, GetColor( SecureLevel.Guild ), false, false ); // Guild Members + } + + AddButton( 10, 130 + offset, GetFirstID( SecureLevel.Anyone ), 4007, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 130 + offset, 150, 20, 1061626, GetColor( SecureLevel.Anyone ), false, false ); // Anyone + } + + public int GetColor( SecureLevel level ) + { + return ( m_Info.Level == level ) ? 0x7F18 : 0x7FFF; + } + + public int GetFirstID( SecureLevel level ) + { + return ( m_Info.Level == level ) ? 4006 : 4005; + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + SecureLevel level = m_Info.Level; + + switch ( info.ButtonID ) + { + case 1: level = SecureLevel.Owner; break; + case 2: level = SecureLevel.CoOwners; break; + case 3: level = SecureLevel.Friends; break; + case 4: level = SecureLevel.Anyone; break; + case 5: level = SecureLevel.Guild; break; + } + + if ( m_Info.Level == level ) + { + state.Mobile.SendLocalizedMessage( 1061281 ); // Access level unchanged. + } + else + { + m_Info.Level = level; + state.Mobile.SendLocalizedMessage( 1061280 ); // New access level set. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/SkillsGump.cs b/Scripts/Gumps/SkillsGump.cs new file mode 100644 index 0000000..fb95af5 --- /dev/null +++ b/Scripts/Gumps/SkillsGump.cs @@ -0,0 +1,552 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Gumps +{ + public class EditSkillGump : Gump + { + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 160; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + (2 * (EntryHeight + OffsetSize)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + private Mobile m_From; + private Mobile m_Target; + private Skill m_Skill; + + private SkillsGumpGroup m_Selected; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + try + { + if ( m_From.AccessLevel >= AccessLevel.GameMaster ) + { + TextRelay text = info.GetTextEntry( 0 ); + + if ( text != null ) + { + m_Skill.Base = Convert.ToDouble( text.Text ); + CommandLogging.LogChangeProperty( m_From, m_Target, String.Format( "{0}.Base", m_Skill ), m_Skill.Base.ToString() ); + } + } + else + { + m_From.SendMessage( "You may not change that." ); + } + + m_From.SendGump( new SkillsGump( m_From, m_Target, m_Selected ) ); + } + catch + { + m_From.SendMessage( "Bad format. ###.# expected." ); + m_From.SendGump( new EditSkillGump( m_From, m_Target, m_Skill, m_Selected ) ); + } + } + else + { + m_From.SendGump( new SkillsGump( m_From, m_Target, m_Selected ) ); + } + } + + public EditSkillGump( Mobile from, Mobile target, Skill skill, SkillsGumpGroup selected ) : base( GumpOffsetX, GumpOffsetY ) + { + m_From = from; + m_Target = target; + m_Skill = skill; + m_Selected = selected; + + string initialText = m_Skill.Base.ToString( "F1" ); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BackHeight, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, skill.Name ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddTextEntry( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, 0, initialText ); + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1, GumpButtonType.Reply, 0 ); + } + } + + public class SkillsGump : Gump + { + public static bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + /* + private static bool PrevLabel = OldStyle, NextLabel = OldStyle; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + * */ + + private static readonly int NameWidth = 107; + private static readonly int ValueWidth = 128; + + private static readonly int EntryCount = 15; + + private static readonly int TypeWidth = NameWidth + OffsetSize + ValueWidth; + + private static readonly int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + private static readonly int IndentWidth = 12; + + private Mobile m_From; + private Mobile m_Target; + + private SkillsGumpGroup[] m_Groups; + private SkillsGumpGroup m_Selected; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int buttonID = info.ButtonID - 1; + + int index = buttonID / 3; + int type = buttonID % 3; + + switch ( type ) + { + case 0: + { + if ( index >= 0 && index < m_Groups.Length ) + { + SkillsGumpGroup newSelection = m_Groups[index]; + + if ( m_Selected != newSelection ) + m_From.SendGump( new SkillsGump( m_From, m_Target, newSelection ) ); + else + m_From.SendGump( new SkillsGump( m_From, m_Target, null ) ); + } + + break; + } + case 1: + { + if ( m_Selected != null && index >= 0 && index < m_Selected.Skills.Length ) + { + Skill sk = m_Target.Skills[m_Selected.Skills[index]]; + + if ( sk != null ) + { + if ( m_From.AccessLevel >= AccessLevel.GameMaster ) + { + m_From.SendGump( new EditSkillGump( m_From, m_Target, sk, m_Selected ) ); + } + else + { + m_From.SendMessage( "You may not change that." ); + m_From.SendGump( new SkillsGump( m_From, m_Target, m_Selected ) ); + } + } + else + { + m_From.SendGump( new SkillsGump( m_From, m_Target, m_Selected ) ); + } + } + + break; + } + case 2: + { + if ( m_Selected != null && index >= 0 && index < m_Selected.Skills.Length ) + { + Skill sk = m_Target.Skills[m_Selected.Skills[index]]; + + if ( sk != null ) + { + if ( m_From.AccessLevel >= AccessLevel.GameMaster ) + { + switch ( sk.Lock ) + { + case SkillLock.Up: sk.SetLockNoRelay( SkillLock.Down ); sk.Update(); break; + case SkillLock.Down: sk.SetLockNoRelay( SkillLock.Locked ); sk.Update(); break; + case SkillLock.Locked: sk.SetLockNoRelay( SkillLock.Up ); sk.Update(); break; + } + } + else + { + m_From.SendMessage( "You may not change that." ); + } + + m_From.SendGump( new SkillsGump( m_From, m_Target, m_Selected ) ); + } + } + + break; + } + } + } + + public int GetButtonID( int type, int index ) + { + return 1 + (index * 3) + type; + } + + public SkillsGump( Mobile from, Mobile target ) : this( from, target, null ) + { + } + + public SkillsGump( Mobile from, Mobile target, SkillsGumpGroup selected ) : base( GumpOffsetX, GumpOffsetY ) + { + m_From = from; + m_Target = target; + + m_Groups = SkillsGumpGroup.Groups; + m_Selected = selected; + + int count = m_Groups.Length; + + if ( selected != null ) + count += selected.Skills.Length; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1)); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0); + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, HeaderGumpID ); + + x += emptyWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + for ( int i = 0; i < m_Groups.Length; ++i ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + SkillsGumpGroup group = m_Groups[i]; + + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( group == selected ) + AddButton( x + PrevOffsetX, y + PrevOffsetY, 0x15E2, 0x15E6, GetButtonID( 0, i ), GumpButtonType.Reply, 0 ); + else + AddButton( x + PrevOffsetX, y + PrevOffsetY, 0x15E1, 0x15E5, GetButtonID( 0, i ), GumpButtonType.Reply, 0 ); + + x += PrevWidth + OffsetSize; + + x -= (OldStyle ? OffsetSize : 0); + + AddImageTiled( x, y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID ); + AddLabel( x + TextOffsetX, y, TextHue, group.Name ); + + x += emptyWidth + (OldStyle ? OffsetSize * 2 : 0); + x += OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( group == selected ) + { + int indentMaskX = BorderSize; + int indentMaskY = y + EntryHeight + OffsetSize; + + for ( int j = 0; j < group.Skills.Length; ++j ) + { + Skill sk = target.Skills[group.Skills[j]]; + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + x += OffsetSize; + x += IndentWidth; + + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + AddButton( x + PrevOffsetX, y + PrevOffsetY, 0x15E1, 0x15E5, GetButtonID( 1, j ), GumpButtonType.Reply, 0 ); + + x += PrevWidth + OffsetSize; + + x -= (OldStyle ? OffsetSize : 0); + + AddImageTiled( x, y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0) - OffsetSize - IndentWidth, EntryHeight, EntryGumpID ); + AddLabel( x + TextOffsetX, y, TextHue, sk == null ? "(null)" : sk.Name ); + + x += emptyWidth + (OldStyle ? OffsetSize * 2 : 0) - OffsetSize - IndentWidth; + x += OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( sk != null ) + { + int buttonID1, buttonID2; + int xOffset, yOffset; + + switch ( sk.Lock ) + { + default: + case SkillLock.Up: buttonID1 = 0x983; buttonID2 = 0x983; xOffset = 6; yOffset = 4; break; + case SkillLock.Down: buttonID1 = 0x985; buttonID2 = 0x985; xOffset = 6; yOffset = 4; break; + case SkillLock.Locked: buttonID1 = 0x82C; buttonID2 = 0x82C; xOffset = 5; yOffset = 2; break; + } + + AddButton( x + xOffset, y + yOffset, buttonID1, buttonID2, GetButtonID( 2, j ), GumpButtonType.Reply, 0 ); + + y += 1; + x -= OffsetSize; + x -= 1; + x -= 50; + + AddImageTiled( x, y, 50, EntryHeight - 2, OffsetGumpID ); + + x += 1; + y += 1; + + AddImageTiled( x, y, 48, EntryHeight - 4, EntryGumpID ); + + AddLabelCropped( x + TextOffsetX, y - 1, 48 - TextOffsetX, EntryHeight - 3, TextHue, sk.Base.ToString( "F1" ) ); + + y -= 2; + } + } + + AddImageTiled( indentMaskX, indentMaskY, IndentWidth + OffsetSize, (group.Skills.Length * (EntryHeight + OffsetSize)) - (i < (m_Groups.Length - 1) ? OffsetSize : 0), BackGumpID + 4 ); + } + } + } + } + + public class SkillsGumpGroup + { + private string m_Name; + private SkillName[] m_Skills; + + public string Name{ get{ return m_Name; } } + public SkillName[] Skills{ get{ return m_Skills; } } + + public SkillsGumpGroup( string name, SkillName[] skills ) + { + m_Name = name; + m_Skills = skills; + + Array.Sort( m_Skills, new SkillNameComparer() ); + } + + private class SkillNameComparer : IComparer + { + public SkillNameComparer() + { + } + + public int Compare( object x, object y ) + { + SkillName a = (SkillName)x; + SkillName b = (SkillName)y; + + string aName = SkillInfo.Table[(int)a].Name; + string bName = SkillInfo.Table[(int)b].Name; + + return aName.CompareTo( bName ); + } + } + + private static SkillsGumpGroup[] m_Groups = new SkillsGumpGroup[] + { + new SkillsGumpGroup( "Crafting", new SkillName[] + { + SkillName.Alchemy, + SkillName.Blacksmith, + SkillName.Cartography, + SkillName.Carpentry, + SkillName.Cooking, + SkillName.Fletching, + SkillName.Inscribe, + SkillName.Tailoring, + SkillName.Tinkering, + SkillName.Imbuing + } ), + new SkillsGumpGroup( "Bardic", new SkillName[] + { + SkillName.Discordance, + SkillName.Musicianship, + SkillName.Peacemaking, + SkillName.Provocation + } ), + new SkillsGumpGroup( "Magical", new SkillName[] + { + SkillName.Chivalry, + SkillName.EvalInt, + SkillName.Imbuing, + SkillName.Magery, + SkillName.MagicResist, + SkillName.Meditation, + SkillName.Necromancy, + SkillName.SpiritSpeak, + SkillName.Ninjitsu, + SkillName.Bushido, + SkillName.Spellweaving, + SkillName.Mysticism + } ), + new SkillsGumpGroup( "Miscellaneous", new SkillName[] + { + SkillName.Camping, + SkillName.Fishing, + SkillName.Focus, + SkillName.Healing, + SkillName.Herding, + SkillName.Lockpicking, + SkillName.Lumberjacking, + SkillName.Mining, + SkillName.Snooping, + SkillName.Veterinary + } ), + new SkillsGumpGroup( "Combat Ratings", new SkillName[] + { + SkillName.Archery, + SkillName.Fencing, + SkillName.Macing, + SkillName.Parry, + SkillName.Swords, + SkillName.Tactics, + SkillName.Throwing, + SkillName.Wrestling, + SkillName.Throwing + } ), + new SkillsGumpGroup( "Actions", new SkillName[] + { + SkillName.AnimalTaming, + SkillName.Begging, + SkillName.DetectHidden, + SkillName.Hiding, + SkillName.RemoveTrap, + SkillName.Poisoning, + SkillName.Stealing, + SkillName.Stealth, + SkillName.Tracking + } ), + new SkillsGumpGroup( "Lore & Knowledge", new SkillName[] + { + SkillName.Anatomy, + SkillName.AnimalLore, + SkillName.ArmsLore, + SkillName.Forensics, + SkillName.ItemID, + SkillName.TasteID + } ) + }; + + public static SkillsGumpGroup[] Groups + { + get{ return m_Groups; } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/TithingGump.cs b/Scripts/Gumps/TithingGump.cs new file mode 100644 index 0000000..7aa6672 --- /dev/null +++ b/Scripts/Gumps/TithingGump.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Gumps +{ + public class TithingGump : Gump + { + private Mobile m_From; + private int m_Offer; + + public TithingGump( Mobile from, int offer ) : base( 160, 40 ) + { + int totalGold = from.TotalGold; + + if ( offer > totalGold ) + offer = totalGold; + else if ( offer < 0 ) + offer = 0; + + m_From = from; + m_Offer = offer; + + AddPage( 0 ); + + AddImage( 30, 30, 102 ); + + AddHtmlLocalized( 95, 100, 120, 100, 1060198, 0, false, false ); // May your wealth bring blessings to those in need, if tithed upon this most sacred site. + + AddLabel( 57, 274, 0, "Gold:" ); + AddLabel( 87, 274, 53, (totalGold - offer).ToString() ); + + AddLabel( 137, 274, 0, "Tithe:" ); + AddLabel( 172, 274, 53, offer.ToString() ); + + AddButton( 105, 230, 5220, 5220, 2, GumpButtonType.Reply, 0 ); + AddButton( 113, 230, 5222, 5222, 2, GumpButtonType.Reply, 0 ); + AddLabel( 108, 228, 0, "<" ); + AddLabel( 112, 228, 0, "<" ); + + AddButton( 127, 230, 5223, 5223, 1, GumpButtonType.Reply, 0 ); + AddLabel( 131, 228, 0, "<" ); + + AddButton( 147, 230, 5224, 5224, 3, GumpButtonType.Reply, 0 ); + AddLabel( 153, 228, 0, ">" ); + + AddButton( 168, 230, 5220, 5220, 4, GumpButtonType.Reply, 0 ); + AddButton( 176, 230, 5222, 5222, 4, GumpButtonType.Reply, 0 ); + AddLabel( 172, 228, 0, ">" ); + AddLabel( 176, 228, 0, ">" ); + + AddButton( 217, 272, 4023, 4024, 5, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 0: + { + // You have decided to tithe no gold to the shrine. + m_From.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1060193 ); + break; + } + case 1: + case 2: + case 3: + case 4: + { + int offer = 0; + + switch ( info.ButtonID ) + { + case 1: offer = m_Offer - 100; break; + case 2: offer = 0; break; + case 3: offer = m_Offer + 100; break; + case 4: offer = m_From.TotalGold; break; + } + + m_From.SendGump( new TithingGump( m_From, offer ) ); + break; + } + case 5: + { + int totalGold = m_From.TotalGold; + + if ( m_Offer > totalGold ) + m_Offer = totalGold; + else if ( m_Offer < 0 ) + m_Offer = 0; + + if ( (m_From.TithingPoints + m_Offer) > 100000 ) // TODO: What's the maximum? + m_Offer = (100000 - m_From.TithingPoints); + + if ( m_Offer <= 0 ) + { + // You have decided to tithe no gold to the shrine. + m_From.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1060193 ); + break; + } + + Container pack = m_From.Backpack; + + if ( pack != null && pack.ConsumeTotal( typeof( Gold ), m_Offer ) ) + { + // You tithe gold to the shrine as a sign of devotion. + m_From.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1060195 ); + m_From.TithingPoints += m_Offer; + + m_From.PlaySound( 0x243 ); + m_From.PlaySound( 0x2E6 ); + } + else + { + // You do not have enough gold to tithe that amount! + m_From.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1060194 ); + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/ToTAdminGump.cs b/Scripts/Gumps/ToTAdminGump.cs new file mode 100644 index 0000000..15892e1 --- /dev/null +++ b/Scripts/Gumps/ToTAdminGump.cs @@ -0,0 +1,138 @@ +using System; +using Server; +using Server.Gumps; +using Server.Misc; +using Server.Items; +using Server.Network; +using Server.Commands; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class ToTAdminGump : Gump + { + private int m_ToTEras; + private static string[] m_ToTInfo = + { + //Opening Message + "
Treasures of Tokuno Admin

" + + "-Use the gems to switch eras
" + + "-Drop era and Reward era can be changed seperately
" + + "-Drop era can be deactivated, Reward era is always activated", + //Treasures of Tokuno 1 message + "
Treasures of Tokuno 1

" + + "-10 charge Bleach Pigment can drop as a Lesser Artifact
" + + "-50 charge Neon Pigments available as a reward
", + //Treasures of Tokuno 2 message + "
Treasures of Tokuno 2

" + + "-30 types of 1 charge Metallic Pigments drop as Lesser Artifacts
" + + "-1 charge Bleach Pigment can drop as a Lesser Artifact
" + + "-10 charge Greater Metallic Pigments available as a reward", + //Treasures of Tokuno 3 message + "
Treasures of Tokuno 3

" + + "-10 types of 1 charge Fresh Pigments drop as Lesser Artifacts
" + + "-1 charge Bleach Pigment can drop as a Lesser Artifact
" + + "-Leurocian's Mempo Of Fortune can drop as a Lesser Artifact" + }; + + public ToTAdminGump() : base( 30, 50 ) + { + Closable=true; + Disposable=true; + Dragable=true; + Resizable=false; + + m_ToTEras = Enum.GetValues( typeof( TreasuresOfTokunoEra ) ).Length - 1; + + AddPage( 0 ); + AddBackground( 0, 0, 320, 75 + (m_ToTEras * 25), 9200 ); + AddImageTiled( 25, 18, 270, 10, 9267 ); + AddLabel( 75, 5, 54, "Treasures of Tokuno Admin" ); + AddLabel( 10, 25, 54, "ToT Era" ); + AddLabel( 90, 25, 54, "Drop Era" ); + AddLabel( 195, 25, 54, "Reward Era" ); + AddLabel( 287, 25, 54, "Info" ); + + AddBackground( 320, 0, 200, 150, 9200 ); + AddImageTiled( 325, 5, 190, 140, 2624 ); + AddAlphaRegion( 325, 5, 190, 140 ); + + SetupToTEras(); + } + + public void SetupToTEras() + { + bool isActivated = TreasuresOfTokuno.DropEra != TreasuresOfTokunoEra.None; + AddButton( 75, 50, isActivated ? 2361 : 2360, isActivated ? 2361 : 2360, 1, GumpButtonType.Reply, 0 ); + AddLabel( 90, 45, isActivated ? 167 : 137, isActivated ? "Activated" : "Deactivated" ); + + for ( int i = 0; i < m_ToTEras; i++ ) + { + int yoffset = (i * 25); + + bool isThisDropEra = ((int)TreasuresOfTokuno.DropEra - 1) == i; + bool isThisRewardEra = ((int)TreasuresOfTokuno.RewardEra - 1) == i; + int dropButtonID = isThisDropEra ? 2361 : 2360; + int rewardButtonID = isThisRewardEra ? 2361 : 2360; + + AddLabel( 10, 70 + yoffset, 2100, "ToT " + ( i + 1 ) ); + AddButton( 75, 75 + yoffset, dropButtonID, dropButtonID, 2 + ( i * 2 ), GumpButtonType.Reply, 0); + AddLabel( 90, 70 + yoffset, isThisDropEra ? 167 : 137, isThisDropEra ? "Active" : "Inactive" ); + AddButton( 180, 75 + yoffset, rewardButtonID, rewardButtonID, 2 + ( i * 2 ) + 1, GumpButtonType.Reply, 0); + AddLabel( 195, 70 + yoffset, isThisRewardEra ? 167 : 137, isThisRewardEra ? "Active" : "Inactive" ); + + AddButton( 285, 70 + yoffset, 4005, 4006, i, GumpButtonType.Page, 2 + i); + } + + for ( int i = 0; i < m_ToTInfo.Length; i++ ) + { + AddPage( 1 + i ); + AddHtml( 330, 10, 180, 130, m_ToTInfo[i], false, true ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int button = info.ButtonID; + Mobile from = sender.Mobile; + + if ( button == 1 ) + { + TreasuresOfTokuno.DropEra = TreasuresOfTokunoEra.None; + from.SendMessage( "Treasures of Tokuno Drops have been deactivated" ); + } + else if ( button >= 2 ) + { + int selectedToT; + if ( button % 2 == 0 ) + { + selectedToT = button / 2; + TreasuresOfTokuno.DropEra = (TreasuresOfTokunoEra)( selectedToT ); + from.SendMessage( "Treasures of Tokuno " + selectedToT + " Drops have been enabled" ); + } + else + { + selectedToT = (button - 1) / 2; + TreasuresOfTokuno.RewardEra = (TreasuresOfTokunoEra)( selectedToT ); + from.SendMessage( "Treasures of Tokuno " + selectedToT + " Rewards have been enabled" ); + } + } + } + + public static void Initialize() + { + CommandSystem.Register( "ToTAdmin", AccessLevel.Administrator, new CommandEventHandler( ToTAdmin_OnCommand ) ); + } + + [Usage( "ToTAdmin" )] + [Description( "Displays a menu to configure Treasures of Tokuno." )] + public static void ToTAdmin_OnCommand( CommandEventArgs e ) + { + ToTAdminGump tg; + + tg = new ToTAdminGump(); + e.Mobile.CloseGump( typeof( ToTAdminGump ) ); + e.Mobile.SendGump( tg ); + } + } +} diff --git a/Scripts/Gumps/VendorInventoryGump.cs b/Scripts/Gumps/VendorInventoryGump.cs new file mode 100644 index 0000000..5c1424f --- /dev/null +++ b/Scripts/Gumps/VendorInventoryGump.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class VendorInventoryGump : Gump + { + private BaseHouse m_House; + private ArrayList m_Inventories; + + public VendorInventoryGump( BaseHouse house, Mobile from ) : base( 50, 50 ) + { + m_House = house; + m_Inventories = new ArrayList( house.VendorInventories ); + + AddBackground( 0, 0, 420, 50 + 20 * m_Inventories.Count, 0x13BE ); + + AddImageTiled( 10, 10, 400, 20, 0xA40 ); + AddHtmlLocalized( 15, 10, 200, 20, 1062435, 0x7FFF, false, false ); // Reclaim Vendor Inventory + AddHtmlLocalized( 330, 10, 50, 20, 1062465, 0x7FFF, false, false ); // Expires + + AddImageTiled( 10, 40, 400, 20 * m_Inventories.Count, 0xA40 ); + + for ( int i = 0; i < m_Inventories.Count; i++ ) + { + VendorInventory inventory = (VendorInventory) m_Inventories[i]; + + int y = 40 + 20 * i; + + if ( inventory.Owner == from ) + AddButton( 10, y, 0xFA5, 0xFA7, i + 1, GumpButtonType.Reply, 0 ); + + AddLabel( 45, y, 0x481, String.Format( "{0} ({1})", inventory.ShopName, inventory.VendorName ) ); + + TimeSpan expire = inventory.ExpireTime - DateTime.Now; + int hours = (int) expire.TotalHours; + + AddLabel( 320, y, 0x481, hours.ToString() ); + AddHtmlLocalized( 350, y, 50, 20, 1062466, 0x7FFF, false, false ); // hour(s) + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 ) + return; + + Mobile from = sender.Mobile; + HouseSign sign = m_House.Sign; + + if ( m_House.Deleted || sign == null || sign.Deleted || !from.CheckAlive() ) + return; + + if ( from.Map != sign.Map || !from.InRange( sign, 5 ) ) + { + from.SendLocalizedMessage( 1062429 ); // You must be within five paces of the house sign to use this option. + return; + } + + int index = info.ButtonID - 1; + if ( index < 0 || index >= m_Inventories.Count ) + return; + + VendorInventory inventory = (VendorInventory) m_Inventories[index]; + + if ( inventory.Owner != from || !m_House.VendorInventories.Contains( inventory ) ) + return; + + int totalItems = 0; + int givenToBackpack = 0; + int givenToBankBox = 0; + for ( int i = inventory.Items.Count - 1; i >= 0; i-- ) + { + Item item = inventory.Items[i]; + + if ( item.Deleted ) + { + inventory.Items.RemoveAt( i ); + continue; + } + + totalItems += 1 + item.TotalItems; + + if ( from.PlaceInBackpack( item ) ) + { + inventory.Items.RemoveAt( i ); + givenToBackpack += 1 + item.TotalItems; + } + else if ( from.BankBox.TryDropItem( from, item, false ) ) + { + inventory.Items.RemoveAt( i ); + givenToBankBox += 1 + item.TotalItems; + } + } + + from.SendLocalizedMessage( 1062436, totalItems.ToString() + "\t" + inventory.Gold.ToString() ); // The vendor you selected had ~1_COUNT~ items in its inventory, and ~2_AMOUNT~ gold in its account. + + int givenGold = Banker.DepositUpTo( from, inventory.Gold ); + inventory.Gold -= givenGold; + + from.SendLocalizedMessage( 1060397, givenGold.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + from.SendLocalizedMessage( 1062437, givenToBackpack.ToString() + "\t" + givenToBankBox.ToString() ); // ~1_COUNT~ items have been removed from the shop inventory and placed in your backpack. ~2_BANKCOUNT~ items were removed from the shop inventory and placed in your bank box. + + if ( inventory.Gold > 0 || inventory.Items.Count > 0 ) + { + from.SendLocalizedMessage( 1062440 ); // Some of the shop inventory would not fit in your backpack or bank box. Please free up some room and try again. + } + else + { + inventory.Delete(); + from.SendLocalizedMessage( 1062438 ); // The shop is now empty of inventory and funds, so it has been deleted. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/VendorRentalGumps.cs b/Scripts/Gumps/VendorRentalGumps.cs new file mode 100644 index 0000000..d06768d --- /dev/null +++ b/Scripts/Gumps/VendorRentalGumps.cs @@ -0,0 +1,616 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Prompts; +using Server.Mobiles; +using Server.Targeting; +using Server.Multis; + +namespace Server.Gumps +{ + public abstract class BaseVendorRentalGump : Gump + { + protected enum GumpType + { + UnlockedContract, + LockedContract, + Offer, + VendorLandlord, + VendorRenter + } + + protected BaseVendorRentalGump( GumpType type, VendorRentalDuration duration, int price, int renewalPrice, + Mobile landlord, Mobile renter, bool landlordRenew, bool renterRenew, bool renew ) : base( 100, 100 ) + { + if ( type == GumpType.Offer ) + Closable = false; + + AddPage( 0 ); + + AddImage( 0, 0, 0x1F40 ); + AddImageTiled( 20, 37, 300, 308, 0x1F42 ); + AddImage( 20, 325, 0x1F43 ); + + AddImage( 35, 8, 0x39 ); + AddImageTiled( 65, 8, 257, 10, 0x3A ); + AddImage( 290, 8, 0x3B ); + + AddImageTiled( 70, 55, 230, 2, 0x23C5 ); + + AddImage( 32, 33, 0x2635 ); + AddHtmlLocalized( 70, 35, 270, 20, 1062353, 0x1, false, false ); // Vendor Rental Contract + + + AddPage( 1 ); + + if ( type != GumpType.UnlockedContract ) + { + AddImage( 65, 60, 0x827 ); + AddHtmlLocalized( 79, 58, 270, 20, 1062370, 0x1, false, false ); // Landlord: + AddLabel( 150, 58, 0x64, landlord != null ? landlord.Name : "" ); + + AddImageTiled( 70, 80, 230, 2, 0x23C5 ); + } + + if ( type == GumpType.UnlockedContract || type == GumpType.LockedContract ) + AddButton( 30, 96, 0x15E1, 0x15E5, 0, GumpButtonType.Page, 2 ); + AddHtmlLocalized( 50, 95, 150, 20, 1062354, 0x1, false, false ); // Contract Length + AddHtmlLocalized( 230, 95, 270, 20, duration.Name, 0x1, false, false ); + + if ( type == GumpType.UnlockedContract || type == GumpType.LockedContract ) + AddButton( 30, 116, 0x15E1, 0x15E5, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 115, 150, 20, 1062356, 0x1, false, false ); // Price Per Rental + AddLabel( 230, 115, 0x64, price > 0 ? price.ToString() : "FREE" ); + + AddImageTiled( 50, 160, 250, 2, 0x23BF ); + + if ( type == GumpType.Offer ) + { + AddButton( 67, 180, 0x482, 0x483, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 100, 180, 270, 20, 1049011, 0x28, false, false ); // I accept! + + AddButton( 67, 210, 0x47F, 0x480, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 100, 210, 270, 20, 1049012, 0x28, false, false ); // No thanks, I decline. + } + else + { + AddImage( 49, 170, 0x61 ); + AddHtmlLocalized( 60, 170, 250, 20, 1062355, 0x1, false, false ); // Renew On Expiration? + + if ( type == GumpType.LockedContract || type == GumpType.UnlockedContract || type == GumpType.VendorLandlord ) + AddButton( 30, 192, 0x15E1, 0x15E5, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 85, 190, 250, 20, 1062359, 0x1, false, false ); // Landlord: + AddHtmlLocalized( 230, 190, 270, 20, landlordRenew ? 1049717 : 1049718, 0x1, false, false ); // YES / NO + + if ( type == GumpType.VendorRenter ) + AddButton( 30, 212, 0x15E1, 0x15E5, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 85, 210, 250, 20, 1062360, 0x1, false, false ); // Renter: + AddHtmlLocalized( 230, 210, 270, 20, renterRenew ? 1049717 : 1049718, 0x1, false, false ); // YES / NO + + if ( renew ) + { + AddImage( 49, 233, 0x939 ); + AddHtmlLocalized( 70, 230, 250, 20, 1062482, 0x1, false, false ); // Contract WILL renew + } + else + { + AddImage( 49, 233, 0x938 ); + AddHtmlLocalized( 70, 230, 250, 20, 1062483, 0x1, false, false ); // Contract WILL NOT renew + } + } + + AddImageTiled( 30, 283, 257, 30, 0x5D ); + AddImage( 285, 283, 0x5E ); + AddImage( 20, 288, 0x232C ); + + if ( type == GumpType.LockedContract ) + { + AddButton( 67, 295, 0x15E1, 0x15E5, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 85, 294, 270, 20, 1062358, 0x28, false, false ); // Offer Contract To Someone + } + else if ( type == GumpType.VendorLandlord || type == GumpType.VendorRenter ) + { + if ( type == GumpType.VendorLandlord ) + AddButton( 30, 250, 0x15E1, 0x15E1, 6, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 85, 250, 250, 20, 1062499, 0x1, false, false ); // Renewal Price + AddLabel( 230, 250, 0x64, renewalPrice.ToString() ); + + AddHtmlLocalized( 60, 294, 270, 20, 1062369, 0x1, false, false ); // Renter: + AddLabel( 120, 293, 0x64, renter != null ? renter.Name : "" ); + } + + + if ( type == GumpType.UnlockedContract || type == GumpType.LockedContract ) + { + AddPage( 2 ); + + for ( int i = 0; i < VendorRentalDuration.Instances.Length; i++ ) + { + VendorRentalDuration durationItem = VendorRentalDuration.Instances[i]; + + AddButton( 30, 76 + i * 20, 0x15E1, 0x15E5, 0x10 | i, GumpButtonType.Reply, 1 ); + AddHtmlLocalized( 50, 75 + i * 20, 150, 20, durationItem.Name, 0x1, false, false ); + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( !IsValidResponse( from ) ) + return; + + if ( (info.ButtonID & 0x10) != 0 ) // Contract duration + { + int index = info.ButtonID & 0xF; + + if ( index < VendorRentalDuration.Instances.Length ) + { + SetContractDuration( from, VendorRentalDuration.Instances[index] ); + } + } + else + { + switch ( info.ButtonID ) + { + case 1: // Price Per Rental + SetPricePerRental( from ); + break; + + case 2: // Accept offer + AcceptOffer( from ); + break; + + case 3: // Renew on expiration - landlord + LandlordRenewOnExpiration( from ); + break; + + case 4: // Renew on expiration - renter + RenterRenewOnExpiration( from ); + break; + + case 5: // Offer Contract To Someone + OfferContract( from ); + break; + + case 6: // Renewal price + SetRenewalPrice( from ); + break; + + default: + Cancel( from ); + break; + } + } + } + + protected abstract bool IsValidResponse( Mobile from ); + + protected virtual void SetContractDuration( Mobile from, VendorRentalDuration duration ) + { + } + + protected virtual void SetPricePerRental( Mobile from ) + { + } + + protected virtual void AcceptOffer( Mobile from ) + { + } + + protected virtual void LandlordRenewOnExpiration( Mobile from ) + { + } + + protected virtual void RenterRenewOnExpiration( Mobile from ) + { + } + + protected virtual void OfferContract( Mobile from ) + { + } + + protected virtual void SetRenewalPrice( Mobile from ) + { + } + + protected virtual void Cancel( Mobile from ) + { + } + } + + public class VendorRentalContractGump : BaseVendorRentalGump + { + private VendorRentalContract m_Contract; + + public VendorRentalContractGump( VendorRentalContract contract, Mobile from ) : base( + contract.IsLockedDown ? GumpType.LockedContract : GumpType.UnlockedContract, contract.Duration, + contract.Price, contract.Price, from, null, contract.LandlordRenew, false, false ) + { + m_Contract = contract; + } + + protected override bool IsValidResponse( Mobile from ) + { + return m_Contract.IsUsableBy( from, true, true, true, true ); + } + + protected override void SetContractDuration( Mobile from, VendorRentalDuration duration ) + { + m_Contract.Duration = duration; + + from.SendGump( new VendorRentalContractGump( m_Contract, from ) ); + } + + protected override void SetPricePerRental( Mobile from ) + { + from.SendLocalizedMessage( 1062365 ); // Please enter the amount of gold that should be charged for this contract (ESC to cancel): + from.Prompt = new PricePerRentalPrompt( m_Contract ); + } + + protected override void LandlordRenewOnExpiration( Mobile from ) + { + m_Contract.LandlordRenew = !m_Contract.LandlordRenew; + + from.SendGump( new VendorRentalContractGump( m_Contract, from ) ); + } + + protected override void OfferContract( Mobile from ) + { + if ( m_Contract.IsLandlord( from ) ) + { + from.SendLocalizedMessage( 1062371 ); // Please target the person you wish to offer this contract to. + from.Target = new OfferContractTarget( m_Contract ); + } + } + + private class PricePerRentalPrompt : Prompt + { + private VendorRentalContract m_Contract; + + public PricePerRentalPrompt( VendorRentalContract contract ) + { + m_Contract = contract; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_Contract.IsUsableBy( from, true, true, true, true ) ) + return; + + text = text.Trim(); + + int price; + + if ( !int.TryParse( text, out price ) ) + price = -1; + + if ( price < 0 ) + { + from.SendLocalizedMessage( 1062485 ); // Invalid entry. Rental fee set to 0. + m_Contract.Price = 0; + } + else if ( price > 5000000 ) + { + m_Contract.Price = 5000000; + } + else + { + m_Contract.Price = price; + } + + from.SendGump( new VendorRentalContractGump( m_Contract, from ) ); + } + + public override void OnCancel( Mobile from ) + { + if ( m_Contract.IsUsableBy( from, true, true, true, true ) ) + from.SendGump( new VendorRentalContractGump( m_Contract, from ) ); + } + } + + private class OfferContractTarget : Target + { + private VendorRentalContract m_Contract; + + public OfferContractTarget( VendorRentalContract contract ) : base( -1, false, TargetFlags.None ) + { + m_Contract = contract; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Contract.IsUsableBy( from, true, false, true, true ) ) + return; + + Mobile mob = targeted as Mobile; + + if ( mob == null || !mob.Player || !mob.Alive || mob == from ) + { + from.SendLocalizedMessage(1071984); //That is not a valid target for a rental contract! + } + else if ( !mob.InRange( m_Contract, 5 ) ) + { + from.SendLocalizedMessage( 501853 ); // Target is too far away. + } + else + { + from.SendLocalizedMessage( 1062372 ); // Please wait while that person considers your offer. + + mob.SendLocalizedMessage( 1062373, from.Name ); // ~1_NAME~ is offering you a vendor rental. If you choose to accept this offer, you have 30 seconds to do so. + mob.SendGump( new VendorRentalOfferGump( m_Contract, from ) ); + + m_Contract.Offeree = mob; + } + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + from.SendLocalizedMessage( 1062380 ); // You decide against offering the contract to anyone. + } + } + } + + public class VendorRentalOfferGump : BaseVendorRentalGump + { + private VendorRentalContract m_Contract; + private Mobile m_Landlord; + + public VendorRentalOfferGump( VendorRentalContract contract, Mobile landlord ) : base( + GumpType.Offer, contract.Duration, contract.Price, contract.Price, + landlord, null, contract.LandlordRenew, false, false ) + { + m_Contract = contract; + m_Landlord = landlord; + } + + protected override bool IsValidResponse( Mobile from ) + { + return m_Contract.IsUsableBy( m_Landlord, true, false, false, false ) && from.CheckAlive() && m_Contract.Offeree == from; + } + + protected override void AcceptOffer( Mobile from ) + { + m_Contract.Offeree = null; + + if ( !m_Contract.Map.CanFit( m_Contract.Location, 16, false, false ) ) + { + m_Landlord.SendLocalizedMessage( 1062486 ); // A vendor cannot exist at that location. Please try again. + return; + } + + BaseHouse house = BaseHouse.FindHouseAt( m_Contract ); + if ( house == null ) + return; + + int price = m_Contract.Price; + int goldToGive; + + if ( price > 0 ) + { + if ( Banker.Withdraw( from, price ) ) + { + from.SendLocalizedMessage( 1060398, price.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + + int depositedGold = Banker.DepositUpTo( m_Landlord, price ); + goldToGive = price - depositedGold; + + if ( depositedGold > 0 ) + m_Landlord.SendLocalizedMessage( 1060397, price.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + + if ( goldToGive > 0 ) + m_Landlord.SendLocalizedMessage( 500390 ); // Your bank box is full. + } + else + { + from.SendLocalizedMessage( 1062378 ); // You do not have enough gold in your bank account to cover the cost of the contract. + m_Landlord.SendLocalizedMessage( 1062374, from.Name ); // ~1_NAME~ has declined your vendor rental offer. + + return; + } + } + else + { + goldToGive = 0; + } + + PlayerVendor vendor = new RentedVendor( from, house, m_Contract.Duration, price, m_Contract.LandlordRenew, goldToGive ); + vendor.MoveToWorld( m_Contract.Location, m_Contract.Map ); + + m_Contract.Delete(); + + from.SendLocalizedMessage( 1062377 ); // You have accepted the offer and now own a vendor in this house. Rental contract options and details may be viewed on this vendor via the 'Contract Options' context menu. + m_Landlord.SendLocalizedMessage( 1062376, from.Name ); // ~1_NAME~ has accepted your vendor rental offer. Rental contract details and options may be viewed on this vendor via the 'Contract Options' context menu. + } + + protected override void Cancel( Mobile from ) + { + m_Contract.Offeree = null; + + from.SendLocalizedMessage( 1062375 ); // You decline the offer for a vendor space rental. + m_Landlord.SendLocalizedMessage( 1062374, from.Name ); // ~1_NAME~ has declined your vendor rental offer. + } + } + + public class RenterVendorRentalGump : BaseVendorRentalGump + { + private RentedVendor m_Vendor; + + public RenterVendorRentalGump( RentedVendor vendor ) : base( + GumpType.VendorRenter, vendor.RentalDuration, vendor.RentalPrice, vendor.RenewalPrice, + vendor.Landlord, vendor.Owner, vendor.LandlordRenew, vendor.RenterRenew, vendor.Renew ) + { + m_Vendor = vendor; + } + + protected override bool IsValidResponse( Mobile from ) + { + return m_Vendor.CanInteractWith( from, true ); + } + + protected override void RenterRenewOnExpiration( Mobile from ) + { + m_Vendor.RenterRenew = !m_Vendor.RenterRenew; + + from.SendGump( new RenterVendorRentalGump( m_Vendor ) ); + } + } + + public class LandlordVendorRentalGump : BaseVendorRentalGump + { + private RentedVendor m_Vendor; + + public LandlordVendorRentalGump( RentedVendor vendor ) : base( + GumpType.VendorLandlord, vendor.RentalDuration, vendor.RentalPrice, vendor.RenewalPrice, + vendor.Landlord, vendor.Owner, vendor.LandlordRenew, vendor.RenterRenew, vendor.Renew ) + { + m_Vendor = vendor; + } + + protected override bool IsValidResponse( Mobile from ) + { + return m_Vendor.CanInteractWith( from, false ) && m_Vendor.IsLandlord( from ); + } + + protected override void LandlordRenewOnExpiration( Mobile from ) + { + m_Vendor.LandlordRenew = !m_Vendor.LandlordRenew; + + from.SendGump( new LandlordVendorRentalGump( m_Vendor ) ); + } + + protected override void SetRenewalPrice( Mobile from ) + { + from.SendLocalizedMessage( 1062500 ); // Enter contract renewal price: + + from.Prompt = new ContractRenewalPricePrompt( m_Vendor ); + } + + private class ContractRenewalPricePrompt : Prompt + { + private RentedVendor m_Vendor; + + public ContractRenewalPricePrompt( RentedVendor vendor ) + { + m_Vendor = vendor; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_Vendor.CanInteractWith( from, false ) || !m_Vendor.IsLandlord( from ) ) + return; + + text = text.Trim(); + + int price; + + if ( !int.TryParse( text, out price ) ) + price = -1; + + if ( price < 0 ) + { + from.SendLocalizedMessage( 1062485 ); // Invalid entry. Rental fee set to 0. + m_Vendor.RenewalPrice = 0; + } + else if ( price > 5000000 ) + { + m_Vendor.RenewalPrice = 5000000; + } + else + { + m_Vendor.RenewalPrice = price; + } + + m_Vendor.RenterRenew = false; + + from.SendGump( new LandlordVendorRentalGump( m_Vendor ) ); + } + + public override void OnCancel( Mobile from ) + { + if ( m_Vendor.CanInteractWith( from, false ) && m_Vendor.IsLandlord( from ) ) + from.SendGump( new LandlordVendorRentalGump( m_Vendor ) ); + } + } + } + + public class VendorRentalRefundGump : Gump + { + private RentedVendor m_Vendor; + private Mobile m_Landlord; + private int m_RefundAmount; + + public VendorRentalRefundGump( RentedVendor vendor, Mobile landlord, int refundAmount ) : base( 50, 50 ) + { + m_Vendor = vendor; + m_Landlord = landlord; + m_RefundAmount = refundAmount; + + AddBackground( 0, 0, 420, 320, 0x13BE ); + + AddImageTiled( 10, 10, 400, 300, 0xA40 ); + AddAlphaRegion( 10, 10, 400, 300 ); + + /* The landlord for this vendor is offering you a partial refund of your rental fee + * in exchange for immediate termination of your rental contract.

+ * + * If you accept this offer, the vendor will be immediately dismissed. You will then + * be able to claim the inventory and any funds the vendor may be holding for you via + * a context menu on the house sign for this house. + */ + AddHtmlLocalized( 10, 10, 400, 150, 1062501, 0x7FFF, false, true ); + + AddHtmlLocalized( 10, 180, 150, 20, 1062508, 0x7FFF, false, false ); // Vendor Name: + AddLabel( 160, 180, 0x480, vendor.Name ); + + AddHtmlLocalized( 10, 200, 150, 20, 1062509, 0x7FFF, false, false ); // Shop Name: + AddLabel( 160, 200, 0x480, vendor.ShopName ); + + AddHtmlLocalized( 10, 220, 150, 20, 1062510, 0x7FFF, false, false ); // Refund Amount: + AddLabel( 160, 220, 0x480, refundAmount.ToString() ); + + AddButton( 10, 268, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 268, 350, 20, 1062511, 0x7FFF, false, false ); // Agree, and dismiss vendor + + AddButton( 10, 288, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 288, 350, 20, 1062512, 0x7FFF, false, false ); // No, I want to keep my vendor + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( !m_Vendor.CanInteractWith( from, true ) || !m_Vendor.CanInteractWith( m_Landlord, false ) || !m_Vendor.IsLandlord( m_Landlord ) ) + return; + + if ( info.ButtonID == 1 ) + { + if ( Banker.Withdraw( m_Landlord, m_RefundAmount ) ) + { + m_Landlord.SendLocalizedMessage( 1060398, m_RefundAmount.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + + int depositedGold = Banker.DepositUpTo( from, m_RefundAmount ); + + if ( depositedGold > 0 ) + from.SendLocalizedMessage( 1060397, depositedGold.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + + m_Vendor.HoldGold += m_RefundAmount - depositedGold; + + m_Vendor.Destroy( false ); + + from.SendLocalizedMessage(1071990); //Remember to claim your vendor's belongings from the house sign! + } + else + { + m_Landlord.SendLocalizedMessage( 1062507 ); // You do not have that much money in your bank account. + } + } + else + { + m_Landlord.SendLocalizedMessage( 1062513 ); // The renter declined your offer. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/ViewHousesGump.cs b/Scripts/Gumps/ViewHousesGump.cs new file mode 100644 index 0000000..c92cc15 --- /dev/null +++ b/Scripts/Gumps/ViewHousesGump.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Multis; +using Server.Targeting; +using Server.Accounting; +using Server.Commands; + +namespace Server.Gumps +{ + public class ViewHousesGump : Gump + { + public static void Initialize() + { + CommandSystem.Register( "ViewHouses", AccessLevel.GameMaster, new CommandEventHandler( ViewHouses_OnCommand ) ); + } + + [Usage( "ViewHouses" )] + [Description( "Displays a menu listing all houses of a targeted player. The menu also contains specific house details, and options to: go to house, open house menu, and demolish house." )] + public static void ViewHouses_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( ViewHouses_OnTarget ) ); + } + + public static void ViewHouses_OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + from.SendGump( new ViewHousesGump( from, GetHouses( (Mobile)targeted ), null ) ); + } + + private class HouseComparer : IComparer + { + public static readonly IComparer Instance = new HouseComparer(); + + public int Compare( BaseHouse x, BaseHouse y ) + { + return x.BuiltOn.CompareTo( y.BuiltOn ); + } + } + + public static List GetHouses( Mobile owner ) + { + List list = new List(); + + Account acct = owner.Account as Account; + + if ( acct == null ) + { + list.AddRange( BaseHouse.GetHouses( owner ) ); + } + else + { + for ( int i = 0; i < acct.Length; ++i ) + { + Mobile mob = acct[i]; + + if ( mob != null ) + list.AddRange( BaseHouse.GetHouses( mob ) ); + } + } + + list.Sort( HouseComparer.Instance ); + + return list; + } + + private Mobile m_From; + private List m_List; + private BaseHouse m_Selection; + + public ViewHousesGump( Mobile from, List list, BaseHouse sel ) : base( 50, 40 ) + { + m_From = from; + m_List = list; + m_Selection = sel; + + from.CloseGump( typeof( ViewHousesGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 240, 360, 5054 ); + AddBlackAlpha( 10, 10, 220, 340 ); + + if ( sel == null || sel.Deleted ) + { + m_Selection = null; + + AddHtml( 35, 15, 120, 20, Color( "House Type", White ), false, false ); + + if ( list.Count == 0 ) + AddHtml( 35, 40, 160, 40, Color( "There were no houses found for that player.", White ), false, false ); + + AddImage( 190, 17, 0x25EA ); + AddImage( 207, 17, 0x25E6 ); + + int page = 0; + + for ( int i = 0; i < list.Count; ++i ) + { + if ( (i % 15) == 0 ) + { + if ( page > 0 ) + AddButton( 207, 17, 0x15E1, 0x15E5, 0, GumpButtonType.Page, page+1 ); + + AddPage( ++page ); + + if ( page > 1 ) + AddButton( 190, 17, 0x15E3, 0x15E7, 0, GumpButtonType.Page, page-1 ); + } + + object name = FindHouseName( list[i] ); + + AddHtml( 15, 40 + ((i % 15) * 20), 20, 20, Color( String.Format( "{0}.", i+1 ), White ), false, false ); + + if ( name is int ) + AddHtmlLocalized( 35, 40 + ((i % 15) * 20), 160, 20, (int)name, White16, false, false ); + else if ( name is string ) + AddHtml( 35, 40 + ((i % 15) * 20), 160, 20, Color( (string)name, White ), false, false ); + + AddButton( 198, 39 + ((i % 15) * 20), 4005, 4007, i+1, GumpButtonType.Reply, 0 ); + } + } + else + { + string houseName, owner, location; + Map map = sel.Map; + + houseName = (sel.Sign == null) ? "An Unnamed House" : sel.Sign.GetName(); + owner = (sel.Owner == null) ? "nobody" : sel.Owner.Name; + + int xLong = 0, yLat = 0, xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + bool valid = Sextant.Format( sel.Location, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ); + + if ( valid ) + location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + else + location = "unknown"; + + AddHtml( 10, 15, 220, 20, Color( Center( "House Properties" ), White ), false, false ); + + AddHtml( 15, 40, 210, 20, Color( "Facet:", White ), false, false ); + AddHtml( 15, 40, 210, 20, Color( Right( map == null ? "(null)" : map.Name ), White ), false, false ); + + AddHtml( 15, 60, 210, 20, Color( "Location:", White ), false, false ); + AddHtml( 15, 60, 210, 20, Color( Right( sel.Location.ToString() ), White ), false, false ); + + AddHtml( 15, 80, 210, 20, Color( "Sextant:", White ), false, false ); + AddHtml( 15, 80, 210, 20, Color( Right( location ), White ), false, false ); + + AddHtml( 15, 100, 210, 20, Color( "Owner:", White ), false, false ); + AddHtml( 15, 100, 210, 20, Color( Right( owner ), White ), false, false ); + + AddHtml( 15, 120, 210, 20, Color( "Name:", White ), false, false ); + AddHtml( 15, 120, 210, 20, Color( Right( houseName ), White ), false, false ); + + AddHtml( 15, 140, 210, 20, Color( "Friends:", White ), false, false ); + AddHtml( 15, 140, 210, 20, Color( Right( sel.Friends.Count.ToString() ), White ), false, false ); + + AddHtml( 15, 160, 210, 20, Color( "Co-Owners:", White ), false, false ); + AddHtml( 15, 160, 210, 20, Color( Right( sel.CoOwners.Count.ToString() ), White ), false, false ); + + AddHtml( 15, 180, 210, 20, Color( "Bans:", White ), false, false ); + AddHtml( 15, 180, 210, 20, Color( Right( sel.Bans.Count.ToString() ), White ), false, false ); + + AddHtml( 15, 200, 210, 20, Color( "Decays:", White ), false, false ); + AddHtml( 15, 200, 210, 20, Color( Right( sel.CanDecay ? "Yes" : "No" ), White ), false, false ); + + AddHtml( 15, 220, 210, 20, Color( "Decay Level:", White ), false, false ); + AddHtml( 15, 220, 210, 20, Color( Right( sel.DecayLevel.ToString() ), White ), false, false ); + + AddButton( 15, 245, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtml( 50, 245, 120, 20, Color( "Go to house", White ), false, false ); + + AddButton( 15, 265, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtml( 50, 265, 120, 20, Color( "Open house menu", White ), false, false ); + + AddButton( 15, 285, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtml( 50, 285, 120, 20, Color( "Demolish house", White ), false, false ); + + AddButton( 15, 305, 4005, 4007, 4, GumpButtonType.Reply, 0 ); + AddHtml( 50, 305, 120, 20, Color( "Refresh house", White ), false, false ); + } + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( m_Selection == null ) + { + int v = info.ButtonID - 1; + + if ( v >= 0 && v < m_List.Count ) + m_From.SendGump( new ViewHousesGump( m_From, m_List, m_List[v] ) ); + } + else if ( !m_Selection.Deleted ) + { + switch ( info.ButtonID ) + { + case 0: + { + m_From.SendGump( new ViewHousesGump( m_From, m_List, null ) ); + break; + } + case 1: + { + Map map = m_Selection.Map; + + if ( map != null && map != Map.Internal ) + m_From.MoveToWorld( m_Selection.BanLocation, map ); + + m_From.SendGump( new ViewHousesGump( m_From, m_List, m_Selection ) ); + + break; + } + case 2: + { + m_From.SendGump( new ViewHousesGump( m_From, m_List, m_Selection ) ); + + HouseSign sign = m_Selection.Sign; + + if ( sign != null && !sign.Deleted ) + sign.OnDoubleClick( m_From ); + + break; + } + case 3: + { + m_From.SendGump( new ViewHousesGump( m_From, m_List, m_Selection ) ); + m_From.SendGump( new HouseDemolishGump( m_From, m_Selection ) ); + + break; + } + case 4: + { + m_Selection.RefreshDecay(); + m_From.SendGump( new ViewHousesGump( m_From, m_List, m_Selection ) ); + + break; + } + } + } + } + + public object FindHouseName( BaseHouse house ) + { + int multiID = house.ItemID; + HousePlacementEntry[] entries; + + entries = HousePlacementEntry.ClassicHouses; + + for ( int i = 0; i < entries.Length; ++i ) + { + if ( entries[i].MultiID == multiID ) + return entries[i].Description; + } + + entries = HousePlacementEntry.TwoStoryFoundations; + + for ( int i = 0; i < entries.Length; ++i ) + { + if ( entries[i].MultiID == multiID ) + return entries[i].Description; + } + + entries = HousePlacementEntry.ThreeStoryFoundations; + + for ( int i = 0; i < entries.Length; ++i ) + { + if ( entries[i].MultiID == multiID ) + return entries[i].Description; + } + + return house.GetType().Name; + } + + private const int White16 = 0x7FFF; + private const int White = 0xFFFFFF; + + public string Right( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/WarningGump.cs b/Scripts/Gumps/WarningGump.cs new file mode 100644 index 0000000..9edc2b1 --- /dev/null +++ b/Scripts/Gumps/WarningGump.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Gumps +{ + public delegate void WarningGumpCallback( Mobile from, bool okay, object state ); + + public class WarningGump : Gump + { + private WarningGumpCallback m_Callback; + private object m_State; + private bool m_CancelButton; + + public WarningGump( int header, int headerColor, object content, int contentColor, int width, int height, WarningGumpCallback callback, object state ) + : this( header, headerColor, content, contentColor, width, height, callback, state, true ) + { + } + + public WarningGump( int header, int headerColor, object content, int contentColor, int width, int height, WarningGumpCallback callback, object state, bool cancelButton ) : base( (640 - width) / 2, (480 - height) / 2 ) + { + m_Callback = callback; + m_State = state; + m_CancelButton = cancelButton; + + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, width, height, 5054 ); + + AddImageTiled( 10, 10, width - 20, 20, 2624 ); + AddAlphaRegion( 10, 10, width - 20, 20 ); + AddHtmlLocalized( 10, 10, width - 20, 20, header, headerColor, false, false ); + + AddImageTiled( 10, 40, width - 20, height - 80, 2624 ); + AddAlphaRegion( 10, 40, width - 20, height - 80 ); + + if ( content is int ) + AddHtmlLocalized( 10, 40, width - 20, height - 80, (int)content, contentColor, false, true ); + else if ( content is string ) + AddHtml( 10, 40, width - 20, height - 80, String.Format( "{1}", contentColor, content ), false, true ); + + AddImageTiled( 10, height - 30, width - 20, 20, 2624 ); + AddAlphaRegion( 10, height - 30, width - 20, 20 ); + + AddButton( 10, height - 30, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, height - 30, 170, 20, 1011036, 32767, false, false ); // OKAY + + if( m_CancelButton ) + { + AddButton( 10 + ((width - 20) / 2), height - 30, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40 + ((width - 20) / 2), height - 30, 170, 20, 1011012, 32767, false, false ); // CANCEL + } + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 && m_Callback != null ) + m_Callback( sender.Mobile, true, m_State ); + else if ( m_Callback != null ) + m_Callback( sender.Mobile, false, m_State ); + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/WhoGump.cs b/Scripts/Gumps/WhoGump.cs new file mode 100644 index 0000000..35d3174 --- /dev/null +++ b/Scripts/Gumps/WhoGump.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using Server.Commands; +using Server.Mobiles; +using Server.Network; + +namespace Server.Gumps +{ + public class WhoGump : Gump + { + public static void Initialize() + { + CommandSystem.Register( "Who", AccessLevel.Counselor, new CommandEventHandler( WhoList_OnCommand ) ); + CommandSystem.Register( "WhoList", AccessLevel.Counselor, new CommandEventHandler( WhoList_OnCommand ) ); + } + + [Usage( "WhoList [filter]" )] + [Aliases( "Who" )] + [Description( "Lists all connected clients. Optionally filters results by name." )] + private static void WhoList_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new WhoGump( e.Mobile, e.ArgString ) ); + } + + public static bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static bool PrevLabel = false, NextLabel = false; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + private static readonly int EntryWidth = 180; + private static readonly int EntryCount = 15; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (EntryCount + 1)); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + private Mobile m_Owner; + private List m_Mobiles; + private int m_Page; + + private class InternalComparer : IComparer + { + public static readonly IComparer Instance = new InternalComparer(); + + public InternalComparer() + { + } + + public int Compare( Mobile x, Mobile y ) + { + if ( x == null || y == null ) + throw new ArgumentException(); + + if ( x.AccessLevel > y.AccessLevel ) + return -1; + else if ( x.AccessLevel < y.AccessLevel ) + return 1; + else + return Insensitive.Compare( x.Name, y.Name ); + } + } + + public WhoGump( Mobile owner, string filter ) : this( owner, BuildList( owner, filter ), 0 ) + { + } + + public WhoGump( Mobile owner, List list, int page ) : base( GumpOffsetX, GumpOffsetY ) + { + owner.CloseGump( typeof( WhoGump ) ); + + m_Owner = owner; + m_Mobiles = list; + + Initialize( page ); + } + + public static List BuildList( Mobile owner, string filter ) + { + if ( filter != null && (filter = filter.Trim()).Length == 0 ) + filter = null; + else + filter = filter.ToLower(); + + List list = new List(); + List states = NetState.Instances; + + for ( int i = 0; i < states.Count; ++i ) + { + Mobile m = states[i].Mobile; + + if (m != null && (m == owner || !m.Hidden || owner.AccessLevel >= m.AccessLevel || (m is PlayerMobile && ((PlayerMobile)m).VisibilityList.Contains(owner)))) + { + if ( filter != null && ( m.Name == null || m.Name.ToLower().IndexOf( filter ) < 0 ) ) + continue; + + list.Add( m ); + } + } + + list.Sort( InternalComparer.Instance ); + + return list; + } + + public void Initialize( int page ) + { + m_Page = page; + + int count = m_Mobiles.Count - (page * EntryCount); + + if ( count < 0 ) + count = 0; + else if ( count > EntryCount ) + count = EntryCount; + + int totalHeight = OffsetSize + ((EntryHeight + OffsetSize) * (count + 1)); + + AddPage( 0 ); + + AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID ); + AddImageTiled( BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID ); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - (OffsetSize * 4) - (OldStyle ? SetWidth + OffsetSize : 0); + + if ( !OldStyle ) + AddImageTiled( x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID ); + + AddLabel( x + TextOffsetX, y, TextHue, String.Format( "Page {0} of {1} ({2})", page+1, (m_Mobiles.Count + EntryCount - 1) / EntryCount, m_Mobiles.Count ) ); + + x += emptyWidth + OffsetSize; + + if ( OldStyle ) + AddImageTiled( x, y, TotalWidth - (OffsetSize * 3) - SetWidth, EntryHeight, HeaderGumpID ); + else + AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID ); + + if ( page > 0 ) + { + AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 ); + + if ( PrevLabel ) + AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" ); + } + + x += PrevWidth + OffsetSize; + + if ( !OldStyle ) + AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID ); + + if ( (page + 1) * EntryCount < m_Mobiles.Count ) + { + AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1 ); + + if ( NextLabel ) + AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" ); + } + + for ( int i = 0, index = page * EntryCount; i < EntryCount && index < m_Mobiles.Count; ++i, ++index ) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + Mobile m = m_Mobiles[index]; + + AddImageTiled( x, y, EntryWidth, EntryHeight, EntryGumpID ); + AddLabelCropped( x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, GetHueFor( m ), m.Deleted ? "(deleted)" : m.Name ); + + x += EntryWidth + OffsetSize; + + if ( SetGumpID != 0 ) + AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID ); + + if ( m.NetState != null && !m.Deleted ) + AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3, GumpButtonType.Reply, 0 ); + } + } + + private static int GetHueFor( Mobile m ) + { + switch ( m.AccessLevel ) + { + case AccessLevel.Owner: + case AccessLevel.Developer: + case AccessLevel.Administrator: return 0x516; + case AccessLevel.Seer: return 0x144; + case AccessLevel.GameMaster: return 0x21; + case AccessLevel.Counselor: return 0x2; + case AccessLevel.Player: default: + { + if ( m.Kills >= 5 ) + return 0x21; + else if ( m.Criminal ) + return 0x3B1; + + return 0x58; + } + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + switch ( info.ButtonID ) + { + case 0: // Closed + { + return; + } + case 1: // Previous + { + if ( m_Page > 0 ) + from.SendGump( new WhoGump( from, m_Mobiles, m_Page - 1 ) ); + + break; + } + case 2: // Next + { + if ( (m_Page + 1) * EntryCount < m_Mobiles.Count ) + from.SendGump( new WhoGump( from, m_Mobiles, m_Page + 1 ) ); + + break; + } + default: + { + int index = (m_Page * EntryCount) + (info.ButtonID - 3); + + if ( index >= 0 && index < m_Mobiles.Count ) + { + Mobile m = m_Mobiles[index]; + + if ( m.Deleted ) + { + from.SendMessage( "That player has deleted their character." ); + from.SendGump( new WhoGump( from, m_Mobiles, m_Page ) ); + } + else if ( m.NetState == null ) + { + from.SendMessage( "That player is no longer online." ); + from.SendGump( new WhoGump( from, m_Mobiles, m_Page ) ); + } + else if (m == from || !m.Hidden || from.AccessLevel >= m.AccessLevel || (m is PlayerMobile && ((PlayerMobile)m).VisibilityList.Contains(from))) + { + from.SendGump( new ClientGump( from, m.NetState ) ); + } + else + { + from.SendMessage( "You cannot see them." ); + from.SendGump( new WhoGump( from, m_Mobiles, m_Page ) ); + } + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Gumps/YoungGumps.cs b/Scripts/Gumps/YoungGumps.cs new file mode 100644 index 0000000..2665010 --- /dev/null +++ b/Scripts/Gumps/YoungGumps.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Accounting; + +namespace Server.Gumps +{ + public class YoungDungeonWarning : Gump + { + public YoungDungeonWarning() : base( 150, 200 ) + { + AddBackground( 0, 0, 250, 170, 0xA28 ); + + AddHtmlLocalized( 20, 43, 215, 70, 1018030, true, true ); // Warning: monsters may attack you on site down here in the dungeons! + + AddButton( 70, 123, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 105, 125, 100, 35, 1011036, false, false ); // OKAY + } + } + + public class YoungDeathNotice : Gump + { + public YoungDeathNotice() : base( 100, 15 ) + { + Closable = false; + + AddBackground( 25, 10, 425, 444, 0x13BE ); + + AddImageTiled( 33, 20, 407, 425, 0xA40 ); + AddAlphaRegion( 33, 20, 407, 425 ); + + AddHtmlLocalized( 190, 24, 120, 20, 1046287, 0x7D00, false, false ); // You have died. + + // As a ghost you cannot interact with the world. You cannot touch items nor can you use them. + AddHtmlLocalized( 50, 50, 380, 40, 1046288, 0xFFFFFF, false, false ); + // You can pass through doors as though they do not exist. However, you cannot pass through walls. + AddHtmlLocalized( 50, 100, 380, 45, 1046289, 0xFFFFFF, false, false ); + // Since you are a new player, any items you had on your person at the time of your death will be in your backpack upon resurrection. + AddHtmlLocalized( 50, 140, 380, 60, 1046291, 0xFFFFFF, false, false ); + // To be resurrected you must find a healer in town or wandering in the wilderness. Some powerful players may also be able to resurrect you. + AddHtmlLocalized( 50, 204, 380, 65, 1046292, 0xFFFFFF, false, false ); + // While you are still in young status, you will be transported to the nearest healer (along with your items) at the time of your death. + AddHtmlLocalized( 50, 269, 380, 65, 1046293, 0xFFFFFF, false, false ); + // To rejoin the world of the living simply walk near one of the NPC healers, and they will resurrect you as long as you are not marked as a criminal. + AddHtmlLocalized( 50, 334, 380, 70, 1046294, 0xFFFFFF, false, false ); + + AddButton( 195, 410, 0xF8, 0xF9, 0, GumpButtonType.Reply, 0 ); + } + } + + public class RenounceYoungGump : Gump + { + public RenounceYoungGump() : base( 150, 50 ) + { + AddBackground( 0, 0, 450, 400, 0xA28 ); + + AddHtmlLocalized( 0, 30, 450, 35, 1013004, false, false ); //
Renouncing 'Young Player' Status
+ + /* As a 'Young' player, you are currently under a system of protection that prevents + * you from being attacked by other players and certain monsters.

+ * + * If you choose to renounce your status as a 'Young' player, you will lose this protection. + * You will become vulnerable to other players, and many monsters that had only glared + * at you menacingly before will now attack you on sight!

+ * + * Select OKAY now if you wish to renounce your status as a 'Young' player, otherwise + * press CANCEL. + */ + AddHtmlLocalized( 30, 70, 390, 210, 1013005, true, true ); + + AddButton( 45, 298, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 78, 300, 100, 35, 1011036, false, false ); // OKAY + + AddButton( 178, 298, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 211, 300, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 1 ) + { + Account acc = from.Account as Account; + + if ( acc != null ) + { + acc.RemoveYoungStatus( 502085 ); // You have chosen to renounce your `Young' player status. + } + } + else + { + from.SendLocalizedMessage( 502086 ); // You have chosen not to renounce your `Young' player status. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Holiday Stuff/Christmas/2010/Addons/FireFliesDeed.cs b/Scripts/Holiday Stuff/Christmas/2010/Addons/FireFliesDeed.cs new file mode 100644 index 0000000..33561b7 --- /dev/null +++ b/Scripts/Holiday Stuff/Christmas/2010/Addons/FireFliesDeed.cs @@ -0,0 +1,281 @@ +using Server; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using System; + +namespace Server.Items +{ + public class Fireflies : Item, IAddon + { + public override int LabelNumber { get { return 1150061; }} + + public Item Deed + { + get + { + FirefliesDeed deed = new FirefliesDeed(); + + return deed; + } + } + + public bool FacingSouth + { + get + { + if( ItemID == 0x2336 ) + return true; + + return false; + } + } + + [Constructable] + public Fireflies() + : this( 0x1596 ) + { + } + + [Constructable] + public Fireflies( int itemID ) + : base( itemID ) + { + LootType = LootType.Blessed; + Movable = false; + } + + public Fireflies( Serial serial ) + : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if( from.InRange( Location, 3 ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( RewardDemolitionGump ) ); + from.SendGump( new RewardDemolitionGump( this, 1049783 ) ); // Do you wish to re-deed this decoration? + } + else + from.SendLocalizedMessage( 1049784 ); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if( map == null || !map.CanFit( p.X, p.Y, p.Z, ItemData.Height ) ) + return false; + + if( FacingSouth ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // north wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // west wall + } + } + + public class FirefliesDeed : Item + { + public override int LabelNumber { get { return 1150061; } } + + [Constructable] + public FirefliesDeed() + : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public FirefliesDeed( Serial serial ) + : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( FacingGump ) ); + + if( !from.SendGump( new FacingGump( this, from ) ) ) + { + from.SendLocalizedMessage( 1150062 ); // You fail to re-deed the holiday fireflies. + } + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class FacingGump : Gump + { + private FirefliesDeed m_Deed; + private Mobile m_Placer; + + private enum Buttons + { + Cancel, + South, + East + } + + public FacingGump( FirefliesDeed deed, Mobile player ) + : base( 150, 50 ) + { + m_Deed = deed; + m_Placer = player; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddItem( 90, 30, 0x2332 ); + AddItem( 180, 30, 0x2336 ); + + AddButton( 50, 35, 0x868, 0x869, ( int )Buttons.East, GumpButtonType.Reply, 0 ); + AddButton( 145, 35, 0x868, 0x869, ( int )Buttons.South, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int m_ItemID; + + switch( (int)info.ButtonID ) + { + case ( int )Buttons.East: m_ItemID = 0x2332; break; + case ( int )Buttons.South: m_ItemID = 0x2336; break; + default: return; + } + + m_Placer.Target = new InternalTarget( m_Deed, m_ItemID ); + + } + } + + private class InternalTarget : Target + { + private FirefliesDeed m_FirefliesDeed; + private int m_ItemID; + + public InternalTarget( FirefliesDeed m_Deed, int itemid ) + : base( -1, true, TargetFlags.None ) + { + m_FirefliesDeed = m_Deed; + m_ItemID = itemid; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if( m_FirefliesDeed == null || m_FirefliesDeed.Deleted ) + return; + + if( m_FirefliesDeed.IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if( house != null && house.IsOwner( from ) ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if( p == null || map == null || map == Map.Internal ) + return; + + Point3D p3d = new Point3D( p ); + ItemData id = TileData.ItemTable[ m_ItemID & TileData.MaxItemValue ]; + + if( map.CanFit( p3d, id.Height ) ) + { + house = BaseHouse.FindHouseAt( p3d, map, id.Height ); + + if( house != null && house.IsOwner( from ) ) + { + bool north = BaseAddon.IsWall( p3d.X, p3d.Y - 1, p3d.Z, map ); + bool west = BaseAddon.IsWall( p3d.X - 1, p3d.Y, p3d.Z, map ); + + bool isclear = true; + + foreach( Item item in Map.Malas.GetItemsInRange( p3d, 0 ) ) + { + if( item is Fireflies ) + { + isclear = false; + } + } + + if( ( ( m_ItemID == 0x2336 && north ) || ( m_ItemID == 0x2332 && west ) ) && isclear ) + { + Fireflies flies = new Fireflies( m_ItemID ); + + house.Addons.Add( flies ); + + flies.MoveToWorld( p3d, from.Map ); + + m_FirefliesDeed.Delete(); + } + + else + from.SendLocalizedMessage( 1150065 ); // Holiday fireflies must be placed next to a wall. + } + else + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + else + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Holiday Stuff/Christmas/2010/Items/AngelDecoration.cs b/Scripts/Holiday Stuff/Christmas/2010/Items/AngelDecoration.cs new file mode 100644 index 0000000..d3b2bdb --- /dev/null +++ b/Scripts/Holiday Stuff/Christmas/2010/Items/AngelDecoration.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Items.Holiday +{ + [TypeAlias( "Server.Items.AngelDecoration" )] + [Flipable( 0x46FA, 0x46FB )] + public class AngelDecoration : Item + { + public AngelDecoration() : base ( 0x46FA ) + { + LootType = LootType.Blessed; + + Weight = 30; + } + + public AngelDecoration( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Christmas/2010/Items/RockingHorse.cs b/Scripts/Holiday Stuff/Christmas/2010/Items/RockingHorse.cs new file mode 100644 index 0000000..c26c86d --- /dev/null +++ b/Scripts/Holiday Stuff/Christmas/2010/Items/RockingHorse.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Items.Holiday +{ + [TypeAlias( "Server.Items.RockingHorse" )] + [Flipable( 0x4214, 0x4215 )] + public class RockingHorse : Item + { + public RockingHorse() : base ( 0x4214 ) + { + LootType = LootType.Blessed; + + Weight = 30; + } + + public RockingHorse( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Easter/2011/Items/DragonEasterEgg.cs b/Scripts/Holiday Stuff/Easter/2011/Items/DragonEasterEgg.cs new file mode 100644 index 0000000..a1104a9 --- /dev/null +++ b/Scripts/Holiday Stuff/Easter/2011/Items/DragonEasterEgg.cs @@ -0,0 +1,44 @@ +using System; + +namespace Server.Items +{ + public class DragonEasterEgg : Item, IDyable + { + public override int LabelNumber { get { return 1097278; } } + + [Constructable] + public DragonEasterEgg() + : base( 0x47E6 ) + { + } + + public DragonEasterEgg( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int ) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if( Deleted || !sender.AllowDyables ) + return false; + + Hue = sender.DyedHue; + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs b/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs new file mode 100644 index 0000000..b534a3f --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs @@ -0,0 +1,363 @@ +using System; +using Server.Items; +using Server.Targeting; +using Server.Events.Halloween; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Engines.Events +{ + public class TrickOrTreat + { + public static TimeSpan OneSecond = TimeSpan.FromSeconds( 1 ); + + public static void Initialize() + { + DateTime now = DateTime.Now; + + if( DateTime.Now >= HolidaySettings.StartHalloween && DateTime.Now <= HolidaySettings.FinishHalloween ) + { + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + } + } + + private static void EventSink_Speech( SpeechEventArgs e ) + { + + if( Insensitive.Contains( e.Speech, "trick or treat" ) ) + { + e.Mobile.Target = new TrickOrTreatTarget(); + + e.Mobile.SendLocalizedMessage( 1076764 ); /* Pick someone to Trick or Treat. */ + } + } + + private class TrickOrTreatTarget : Target + { + public TrickOrTreatTarget() + : base( 15, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targ ) + { + if( targ != null && CheckMobile( from ) ) + { + if( !( targ is Mobile ) ) + { + from.SendLocalizedMessage( 1076781 ); /* There is little chance of getting candy from that! */ + return; + } + if( !( targ is BaseVendor ) || ( ( BaseVendor )targ ).Deleted ) + { + from.SendLocalizedMessage( 1076765 ); /* That doesn't look friendly. */ + return; + } + + DateTime now = DateTime.Now; + + BaseVendor m_Begged = targ as BaseVendor; + + if( CheckMobile( m_Begged ) ) + { + if( m_Begged.NextTrickOrTreat > now ) + { + from.SendLocalizedMessage( 1076767 ); /* That doesn't appear to have any more candy. */ + return; + } + + m_Begged.NextTrickOrTreat = now + TimeSpan.FromMinutes( Utility.RandomMinMax( 5, 10 ) ); + + if( from.Backpack != null && !from.Backpack.Deleted ) + { + if( Utility.RandomDouble() > .10 ) + { + switch( Utility.Random( 3 ) ) + { + case 0: m_Begged.Say( 1076768 ); break; /* Oooooh, aren't you cute! */ + case 1: m_Begged.Say( 1076779 ); break; /* All right...This better not spoil your dinner! */ + case 2: m_Begged.Say( 1076778 ); break; /* Here you go! Enjoy! */ + default: break; + } + + if( Utility.RandomDouble() <= .01 && from.Skills.Begging.Value >= 100 ) + { + from.AddToBackpack( HolidaySettings.RandomGMBeggerItem ); + + from.SendLocalizedMessage( 1076777 ); /* You receive a special treat! */ + } + else + { + from.AddToBackpack( HolidaySettings.RandomTreat ); + + from.SendLocalizedMessage( 1076769 ); /* You receive some candy. */ + } + } + else + { + m_Begged.Say( 1076770 ); /* TRICK! */ + + int m_Action = Utility.Random( 4 ); + + if( m_Action == 0 ) + { + Timer.DelayCall( OneSecond, OneSecond, 10, new TimerStateCallback( Bleeding ), from ); + } + else if( m_Action == 1 ) + { + Timer.DelayCall( TimeSpan.FromSeconds( 2 ), new TimerStateCallback( SolidHueMobile ), from ); + } + else + { + Timer.DelayCall( TimeSpan.FromSeconds( 2 ), new TimerStateCallback( MakeTwin ), from ); + } + } + } + } + } + } + } + + public static void Bleeding( Mobile m_From ) + { + if( TrickOrTreat.CheckMobile( m_From ) ) + { + if( m_From.Location != Point3D.Zero ) + { + int amount = Utility.RandomMinMax( 3, 7 ); + + for( int i = 0; i < amount; i++ ) + { + new Blood( Utility.RandomMinMax( 0x122C, 0x122F ) ).MoveToWorld( RandomPointOneAway( m_From.X, m_From.Y, m_From.Z, m_From.Map ), m_From.Map ); + } + } + } + } + + public static void RemoveHueMod( Mobile target ) + { + if( target != null && !target.Deleted ) + { + target.SolidHueOverride = -1; + } + } + + public static void SolidHueMobile( Mobile target ) + { + if( CheckMobile( target ) ) + { + target.SolidHueOverride = Utility.RandomMinMax( 2501, 2644 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerStateCallback( RemoveHueMod ), target ); + } + } + + public static void MakeTwin( Mobile m_From ) + { + List m_Items = new List(); + + if( CheckMobile( m_From ) ) + { + Mobile twin = new NaughtyTwin( m_From ); + + if( twin != null && !twin.Deleted ) + { + foreach( Item item in m_From.Items ) + { + if( item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank ) + { + m_Items.Add( item ); + } + } + + if( m_Items.Count > 0 ) + { + for( int i = 0; i < m_Items.Count; i++ ) /* dupe exploits start out like this ... */ + { + twin.AddItem( Mobile.LiftItemDupe( m_Items[ i ], 1 ) ); + } + + foreach( Item item in twin.Items ) /* ... and end like this */ + { + if( item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank ) + { + item.Movable = false; + } + } + } + + twin.Hue = m_From.Hue; + twin.BodyValue = m_From.BodyValue; + twin.Kills = m_From.Kills; + + Point3D point = RandomPointOneAway( m_From.X, m_From.Y, m_From.Z, m_From.Map ); + + twin.MoveToWorld( m_From.Map.CanSpawnMobile( point ) ? point : m_From.Location, m_From.Map ); + + Timer.DelayCall( TimeSpan.FromSeconds( 5 ), new TimerStateCallback( DeleteTwin ), twin ); + } + } + } + + public static void DeleteTwin( Mobile m_Twin ) + { + if( TrickOrTreat.CheckMobile( m_Twin ) ) + { + m_Twin.Delete(); + } + } + + public static Point3D RandomPointOneAway( int x, int y, int z, Map map ) + { + Point3D loc = new Point3D( x + Utility.Random( -1, 3 ), y + Utility.Random( -1, 3 ), 0 ); + + loc.Z = ( map.CanFit( loc, 0 )) ? map.GetAverageZ( loc.X, loc.Y ) : z; + + return loc; + } + + public static bool CheckMobile( Mobile mobile ) + { + return ( mobile != null && mobile.Map != null && !mobile.Deleted && mobile.Alive && mobile.Map != Map.Internal ); + } + } + + public class NaughtyTwin : BaseCreature + { + private Mobile m_From; + + private static Point3D[] Felucca_Locations = + { + new Point3D( 4467, 1283, 5 ), // Moonglow + new Point3D( 1336, 1997, 5 ), // Britain + new Point3D( 1499, 3771, 5 ), // Jhelom + new Point3D( 771, 752, 5 ), // Yew + new Point3D( 2701, 692, 5 ), // Minoc + new Point3D( 1828, 2948,-20), // Trinsic + new Point3D( 643, 2067, 5 ), // Skara Brae + new Point3D( 3563, 2139, Map.Trammel.GetAverageZ( 3563, 2139 ) ), // (New) Magincia + }; + + private static Point3D[] Malas_Locations = + { + new Point3D(1015, 527, -65), // Luna + new Point3D(1997, 1386, -85) // Umbra + }; + + private static Point3D[] Ilshenar_Locations = + { + new Point3D( 1215, 467, -13 ), // Compassion + new Point3D( 722, 1366, -60 ), // Honesty + new Point3D( 744, 724, -28 ), // Honor + new Point3D( 281, 1016, 0 ), // Humility + new Point3D( 987, 1011, -32 ), // Justice + new Point3D( 1174, 1286, -30 ), // Sacrifice + new Point3D( 1532, 1340, - 3 ), // Spirituality + new Point3D( 528, 216, -45 ), // Valor + new Point3D( 1721, 218, 96 ) // Chaos + }; + + private static Point3D[] Tokuno_Locations = + { + new Point3D( 1169, 998, 41 ), // Isamu-Jima + new Point3D( 802, 1204, 25 ), // Makoto-Jima + new Point3D( 270, 628, 15 ) // Homare-Jima + }; + + public NaughtyTwin( Mobile from ) + : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 ) + { + if( TrickOrTreat.CheckMobile( from ) ) + { + Body = from.Body; + + m_From = from; + Name = String.Format( "{0}\'s Naughty Twin", from.Name ); + + Timer.DelayCall( TrickOrTreat.OneSecond, Utility.RandomBool() ? new TimerStateCallback( StealCandy ) : new TimerStateCallback( ToGate ), m_From ); + } + } + + public override void OnThink() + { + if( m_From == null || m_From.Deleted ) + { + Delete(); + } + } + + public static Item FindCandyTypes( Mobile target ) + { + Type[] types = { typeof(WrappedCandy), typeof(RedLollipop), typeof(GreenLollipop), typeof(YellowLollipop), typeof(RedCandyCane), typeof(GreenCandyCane), typeof(Jellybeans), typeof(Nougat)}; + + if( TrickOrTreat.CheckMobile( target ) ) + { + for( int i = 0; i < types.Length; i++ ) + { + Item item = target.Backpack.FindItemByType( types[ i ] ); + + if( item != null ) + { + return item; + } + } + } + return null; + } + + public static void StealCandy( Mobile target ) + { + if( TrickOrTreat.CheckMobile( target ) ) + { + Item item = FindCandyTypes( target ); + + target.SendLocalizedMessage( 1113967 ); /* Your naughty twin steals some of your candy. */ + + if( item != null && !item.Deleted ) + { + item.Delete(); + } + } + } + + public static void ToGate( Mobile target ) + { + if( TrickOrTreat.CheckMobile( target ) ) + { + target.SendLocalizedMessage( 1113972 ); /* Your naughty twin teleports you away with a naughty laugh! */ + + target.MoveToWorld( RandomMoongate( target ), target.Map ); + } + } + + public static Point3D RandomMoongate( Mobile target ) + { + Map map = target.Map; + + switch( target.Map.MapID ) + { + case 2: return Ilshenar_Locations[ Utility.Random( Ilshenar_Locations.Length ) ]; + case 3: return Malas_Locations[ Utility.Random( Malas_Locations.Length ) ]; + case 4: return Tokuno_Locations[ Utility.Random( Tokuno_Locations.Length ) ]; + default: return Felucca_Locations[ Utility.Random( Felucca_Locations.Length ) ]; + } + } + + public NaughtyTwin( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Holiday Stuff/Halloween/2006/Items/HalloweenPumpkin.cs b/Scripts/Holiday Stuff/Halloween/2006/Items/HalloweenPumpkin.cs new file mode 100644 index 0000000..3f1c0b2 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2006/Items/HalloweenPumpkin.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class HalloweenPumpkin : Item + { + private static readonly string[] m_Staff = + { + "Ryan", "Mark", "Eos", "Athena", "Xavier", "Krrios", "Zippy" + }; + + [Constructable] + public HalloweenPumpkin() + : base() + { + Weight = Utility.RandomMinMax( 3, 20 ); + ItemID = ( Utility.RandomDouble() <= .02 ) ? Utility.RandomList( 0x4694, 0x4698 ) : Utility.RandomList( 0xc6a, 0xc6b, 0xc6c ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + return; + + bool douse = false; + + switch ( ItemID ) + { + case 0x4694: ItemID = 0x4691; break; + case 0x4691: ItemID = 0x4694; douse = true; break; + case 0x4698: ItemID = 0x4695; break; + case 0x4695: ItemID = 0x4698; douse = true; break; + default: return; + } + + from.SendLocalizedMessage( douse ? 1113988 : 1113987 ); // You extinguish/light the Jack-O-Lantern + Effects.PlaySound( GetWorldLocation(), Map, douse ? 0x3be : 0x47 ); + } + + private void AssignRandomName() + { + Name = String.Format( "{0}'s Jack-O-Lantern", m_Staff[ Utility.Random( m_Staff.Length ) ] ); + } + + public override bool OnDragLift( Mobile from ) + { + if ( Name == null && ( ItemID == 0x4694 || ItemID == 0x4691 || ItemID == 0x4698 || ItemID == 0x4695 ) ) + { + if ( Utility.RandomBool() ) + { + new PumpkinHead().MoveToWorld( GetWorldLocation(), Map ); + + Delete(); + return false; + } + + AssignRandomName(); + } + + return true; + } + + public HalloweenPumpkin( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Name == null && ItemID == 0x4698 ) + AssignRandomName(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2006/Items/PumpkinScarecrow.cs b/Scripts/Holiday Stuff/Halloween/2006/Items/PumpkinScarecrow.cs new file mode 100644 index 0000000..a9a0166 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2006/Items/PumpkinScarecrow.cs @@ -0,0 +1,36 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Items +{ + public class PumpkinScarecrow : Item + { + public override int LabelNumber { get { return 1096947; } } + + [Constructable] + public PumpkinScarecrow() + : base( Utility.RandomBool() ? 0x469B : 0x469C ) + { + } + + public PumpkinScarecrow( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2006/Items/RuinedTapestry.cs b/Scripts/Holiday Stuff/Halloween/2006/Items/RuinedTapestry.cs new file mode 100644 index 0000000..497d3b2 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2006/Items/RuinedTapestry.cs @@ -0,0 +1,36 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Items +{ + public class RuinedTapestry : Item + { + public override string DefaultName{ get { return "Ruined Tapestry "; } } + + [Constructable] + public RuinedTapestry() + : base( Utility.RandomBool() ? 0x4699 : 0x469A ) + { + } + + public RuinedTapestry( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2006/Items/TwilightLantern.cs b/Scripts/Holiday Stuff/Halloween/2006/Items/TwilightLantern.cs new file mode 100644 index 0000000..865da0c --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2006/Items/TwilightLantern.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + + public class TwilightLantern : Lantern + { + public override string DefaultName { get { return "Twilight Lantern"; } } + + [Constructable] + public TwilightLantern() + : base() + { + Hue = Utility.RandomBool() ? 244 : 997; + } + + public override bool AllowEquipedCast( Mobile from ) + { + return true; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060482 ); // Spell Channeling + } + + public TwilightLantern( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Engines/PumpkinPatch.cs b/Scripts/Holiday Stuff/Halloween/2009/Engines/PumpkinPatch.cs new file mode 100644 index 0000000..38214d3 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Engines/PumpkinPatch.cs @@ -0,0 +1,74 @@ +using System; +using Server.Items; +using Server.Events.Halloween; + +namespace Server.Engines.Events +{ + public class PumpkinPatchSpawner + { + private static Timer m_Timer; + + private static Rectangle2D[] m_PumpkinFields = + { + new Rectangle2D( 4557, 1471, 20, 10 ), + new Rectangle2D( 796, 2152, 36, 24 ), + new Rectangle2D( 816, 2251, 16, 8 ), + new Rectangle2D( 816, 2261, 16, 8 ), + new Rectangle2D( 816, 2271, 16, 8 ), + new Rectangle2D( 816, 2281, 16, 8 ), + new Rectangle2D( 835, 2344, 16, 16 ), + new Rectangle2D( 816, 2344, 16, 24 ) + }; + + public static void Initialize() + { + DateTime now = DateTime.Now; + + if( DateTime.Now >= HolidaySettings.StartHalloween && DateTime.Now <= HolidaySettings.FinishHalloween ) + { + m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromMinutes( .50 ), 0, new TimerCallback( PumpkinPatchSpawnerCallback )); + } + } + + protected static void PumpkinPatchSpawnerCallback() + { + AddPumpkin( Map.Felucca ); + AddPumpkin( Map.Trammel ); + } + + private static void AddPumpkin( Map map ) + { + for( int i = 0; i < m_PumpkinFields.Length; i++ ) + { + Rectangle2D rect = m_PumpkinFields[ i ]; + + int spawncount = ( ( rect.Height * rect.Width ) / 20 ); + int pumpkins = 0; + + foreach( Item item in map.GetItemsInBounds( rect ) ) + { + if( item is HalloweenPumpkin ) + { + pumpkins++; + } + } + + if( spawncount > pumpkins ) + { + Item item = new HalloweenPumpkin(); + + item.MoveToWorld( RandomPointIn( rect, map ), map ); + } + } + } + + private static Point3D RandomPointIn( Rectangle2D rect, Map map ) + { + int x = Utility.Random( rect.X, rect.Width ); + int y = Utility.Random( rect.Y, rect.Height ); + int z = map.GetAverageZ( x, y ); + + return new Point3D( x, y, z ); + } + } +} \ No newline at end of file diff --git a/Scripts/Holiday Stuff/Halloween/2009/Foods/CreepyCake.cs b/Scripts/Holiday Stuff/Halloween/2009/Foods/CreepyCake.cs new file mode 100644 index 0000000..4ed0aba --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Foods/CreepyCake.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + /* + first seen halloween 2009. subsequently in 2010, + 2011 and 2012. GM Beggar-only Semi-Rare Treats + */ + + public class CreepyCake : Food + { + public override string DefaultName { get { return "Creepy Cake"; } } + + [Constructable] + public CreepyCake() + : base( 0x9e9 ) + { + Hue = 0x3E4; + } + + public CreepyCake( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Foods/HarvestWine.cs b/Scripts/Holiday Stuff/Halloween/2009/Foods/HarvestWine.cs new file mode 100644 index 0000000..5d518c6 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Foods/HarvestWine.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + /* + first seen halloween 2009. subsequently in 2010, + 2011 and 2012. GM Beggar-only Semi-Rare Treats + */ + + public class HarvestWine : BeverageBottle + { + public override string DefaultName { get { return "Harvest Wine"; } } + public override double DefaultWeight { get { return 1; } } + + [Constructable] + public HarvestWine() + : base( BeverageType.Wine ) + { + Hue = 0xe0; + } + + public HarvestWine( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Foods/MrPlainsCookies.cs b/Scripts/Holiday Stuff/Halloween/2009/Foods/MrPlainsCookies.cs new file mode 100644 index 0000000..720b9c7 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Foods/MrPlainsCookies.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MrPlainsCookies : Food + { + public override string DefaultName{ get { return "Mr Plain's Cookies"; } } + + [Constructable] + public MrPlainsCookies( ) + : base( 0x160C ) + { + this.Weight = 1.0; + this.FillFactor = 4; + Hue = 0xF4; + } + + public MrPlainsCookies( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Foods/MurkyMilk.cs b/Scripts/Holiday Stuff/Halloween/2009/Foods/MurkyMilk.cs new file mode 100644 index 0000000..424cce4 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Foods/MurkyMilk.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + /* + first seen halloween 2009. subsequently in 2010, + 2011 and 2012. GM Beggar-only Semi-Rare Treats + */ + + public class MurkyMilk : Pitcher + { + public override string DefaultName { get { return "Murky Milk";; } } + public override int MaxQuantity { get { return 5; } } + public override double DefaultWeight { get { return 1; } } + + [Constructable] + public MurkyMilk( ) + : base( BeverageType.Milk ) + { + Hue = 0x3e5; + Quantity = MaxQuantity; + ItemID = ( Utility.RandomBool() ) ? 0x09F0 : 0x09AD; + } + + public MurkyMilk( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Foods/PumpkinPizza.cs b/Scripts/Holiday Stuff/Halloween/2009/Foods/PumpkinPizza.cs new file mode 100644 index 0000000..34f962e --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Foods/PumpkinPizza.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + /* + first seen halloween 2009. subsequently in 2010, + 2011 and 2012. GM Beggar-only Semi-Rare Treats + */ + + public class PumpkinPizza : CheesePizza + { + public override string DefaultName { get { return "Pumpkin Pizza"; } } + + [Constructable] + public PumpkinPizza( ) + : base() + { + Hue = 0xF3; + } + + public PumpkinPizza( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Items/GrimWarning.cs b/Scripts/Holiday Stuff/Halloween/2009/Items/GrimWarning.cs new file mode 100644 index 0000000..2127234 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Items/GrimWarning.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + /* + first seen halloween 2009. subsequently in 2010, + 2011 and 2012. GM Beggar-only Semi-Rare Treats + */ + + public class GrimWarning : Item + { + public override double DefaultWeight { get { return 1; } } + + [Constructable] + public GrimWarning () + : base( 0x42BD ) + { + } + + public GrimWarning( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2009/Items/SkullsOnPike.cs b/Scripts/Holiday Stuff/Halloween/2009/Items/SkullsOnPike.cs new file mode 100644 index 0000000..50a6a1b --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2009/Items/SkullsOnPike.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + /* + first seen halloween 2009. subsequently in 2010, + 2011 and 2012. GM Beggar-only Semi-Rare Treats + */ + + public class SkullsOnPike : Item + { + public override double DefaultWeight { get { return 1; } } + + [Constructable] + public SkullsOnPike() + : base( 0x42B5 ) + { + } + + public SkullsOnPike( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2010/Items/ChairInAGhostCostume.cs b/Scripts/Holiday Stuff/Halloween/2010/Items/ChairInAGhostCostume.cs new file mode 100644 index 0000000..1e4287c --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2010/Items/ChairInAGhostCostume.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ChairInAGhostCostume : Item + { + public override double DefaultWeight { get { return 5; } } + + [Constructable] + public ChairInAGhostCostume() + : base( 0x3F26 ) + { + } + + public ChairInAGhostCostume( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2010/Items/ColoredSmallWebs.cs b/Scripts/Holiday Stuff/Halloween/2010/Items/ColoredSmallWebs.cs new file mode 100644 index 0000000..38fb02a --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2010/Items/ColoredSmallWebs.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ColoredSmallWebs : Item + { + public override double DefaultWeight { get { return 5; } } + + [Constructable] + public ColoredSmallWebs() + : base( Utility.RandomBool() ? 0x10d6 : 0x10d7 ) + { + Hue = Utility.RandomBool() ? 0x455 : 0x4E9; + } + + public ColoredSmallWebs( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2010/Items/ExcellentIronMaiden.cs b/Scripts/Holiday Stuff/Halloween/2010/Items/ExcellentIronMaiden.cs new file mode 100644 index 0000000..5c87a0d --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2010/Items/ExcellentIronMaiden.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ExcellentIronMaiden : Item + { + public override double DefaultWeight { get { return 5; } } + + [Constructable] + public ExcellentIronMaiden() + : base( 0x3f15 ) + { + } + + public ExcellentIronMaiden( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2010/Items/HalloweenGuillotine.cs b/Scripts/Holiday Stuff/Halloween/2010/Items/HalloweenGuillotine.cs new file mode 100644 index 0000000..84a9d73 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2010/Items/HalloweenGuillotine.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HalloweenGuillotine : Item + { + public override double DefaultWeight { get { return 5; } } + + [Constructable] + public HalloweenGuillotine() : base( 0x3F27 ) + { + } + + public HalloweenGuillotine( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2011/Items/BasePaintedMask.cs b/Scripts/Holiday Stuff/Halloween/2011/Items/BasePaintedMask.cs new file mode 100644 index 0000000..0d1b350 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2011/Items/BasePaintedMask.cs @@ -0,0 +1,77 @@ +using System; +//using System.Collections.Generic; +using System.Text; + +namespace Server.Items.Holiday +{ + [TypeAlias( "Server.Items.ClownMask", "Server.Items.DaemonMask", "Server.Items.PlagueMask" )] + public class BasePaintedMask : Item + { + public override string DefaultName + { + get + { + if( m_Staffer != null ) + { + return String.Format( "{0} hand painted by {1}", MaskName, m_Staffer ); + } + + return MaskName; + } + } + + public virtual string MaskName { get { return "A Mask"; } } + + private string m_Staffer; + + private static string[] m_Staffers = + { + "Ryan", + "Mark", + "Krrios", + "Zippy", + "Athena", + "Eos", + "Xavier" + }; + + public BasePaintedMask( int itemid ) + : this( m_Staffers[ Utility.Random( m_Staffers.Length ) ], itemid ) + { + + } + + public BasePaintedMask( string staffer, int itemid ) + : base( itemid + Utility.Random( 2 ) ) + { + m_Staffer = staffer; + + Utility.Intern( m_Staffer ); + } + + public BasePaintedMask( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )1 ); // version + writer.Write( ( string )m_Staffer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 1 ) + { + m_Staffer = Utility.Intern( reader.ReadString() ); + } + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2011/Items/ClownMask.cs b/Scripts/Holiday Stuff/Halloween/2011/Items/ClownMask.cs new file mode 100644 index 0000000..01e418e --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2011/Items/ClownMask.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items.Holiday +{ + public class PaintedEvilClownMask : BasePaintedMask + { + public override string MaskName { get { return "Evil Clown Mask"; } } + + [Constructable] + public PaintedEvilClownMask( ) + : base( 0x4a90 ) + { + } + + public PaintedEvilClownMask( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2011/Items/DaemonMask.cs b/Scripts/Holiday Stuff/Halloween/2011/Items/DaemonMask.cs new file mode 100644 index 0000000..ce10791 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2011/Items/DaemonMask.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items.Holiday +{ + public class PaintedDaemonMask : BasePaintedMask + { + public override string MaskName { get { return "Daemon Mask"; } } + + [Constructable] + public PaintedDaemonMask() + : base( 0x4a92 ) + { + } + + public PaintedDaemonMask( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Holiday Stuff/Halloween/2011/Items/PlagueMask.cs b/Scripts/Holiday Stuff/Halloween/2011/Items/PlagueMask.cs new file mode 100644 index 0000000..8da50ad --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2011/Items/PlagueMask.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items.Holiday +{ + public class PaintedPlagueMask : BasePaintedMask + { + public override string MaskName { get { return "Plague Mask"; } } + + [Constructable] + public PaintedPlagueMask() + : base( 0x4A8E ) + { + } + + public PaintedPlagueMask( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2011/Mobiles/PumpkinHead.cs b/Scripts/Holiday Stuff/Halloween/2011/Mobiles/PumpkinHead.cs new file mode 100644 index 0000000..09ab99d --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2011/Mobiles/PumpkinHead.cs @@ -0,0 +1,131 @@ +using System; +using Server; +using Server.Items; +using Server.Items.Holiday; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a killer pumpkin corpse" )] + public class PumpkinHead : BaseCreature + { + public override bool AutoDispel { get { return true; } } + public override bool BardImmune { get { return true; } } + public override bool Unprovokable { get { return true; } } + public override bool AreaPeaceImmune { get { return true; } } + + [Constructable] + public PumpkinHead() + : base( Utility.RandomBool() ? AIType.AI_Melee : AIType.AI_Mage, FightMode.Closest, 10, 1, 0.05, 0.1 ) + { + Name = "a killer pumpkin"; + Body = 1246 + Utility.Random( 2 ); + + BaseSoundID = 268; + + SetStr( 350 ); + SetDex( 125 ); + SetInt( 250 ); + + SetHits( 500 ); + SetMana( 1000 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55 ); + SetResistance( ResistanceType.Fire, 50 ); + SetResistance( ResistanceType.Cold, 50 ); + SetResistance( ResistanceType.Poison, 65 ); + SetResistance( ResistanceType.Energy, 80 ); + + SetSkill( SkillName.DetectHidden, 100.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.Necromancy, 100.0 ); + SetSkill( SkillName.SpiritSpeak, 120.0 ); + SetSkill( SkillName.Magery, 160.0 ); + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.MagicResist, 100.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 49; + } + + public override void GenerateLoot() + { + if( Utility.RandomDouble() < .05 ) + { + //PackItem( new TwilightLantern() ); OLD Halloween + + switch( Utility.Random( 5 ) ) + { + case 0: PackItem( new PaintedEvilClownMask() ); break; + case 1: PackItem( new PaintedDaemonMask() ); break; + case 2: PackItem( new PaintedPlagueMask() ); break; + case 3: PackItem( new PaintedEvilJesterMask() ); break; + case 4: PackItem( new PaintedPorcelainMask() ); break; + default: break; + } + } + + PackItem( new WrappedCandy() ); + AddLoot( LootPack.UltraRich, 2 ); + } + + public virtual void Lifted_Callback( Mobile from ) + { + if( from != null && !from.Deleted && from is PlayerMobile ) + { + Combatant = from; + + Warmode = true; + } + } + + public override Item NewHarmfulItem() + { + Item bad = new AcidSlime( TimeSpan.FromSeconds( 10 ), 25, 30 ); + + bad.Name = "gooey nasty pumpkin hummus"; + + bad.Hue = 144; + + return bad; + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if( Utility.RandomBool() ) + { + if( from != null && from.Map != null && Map != Map.Internal && Map == from.Map && from.InRange( this, 12 ) ) + { + SpillAcid( ( willKill ) ? this : from, ( willKill ) ? 3 : 1 ); + } + } + + base.OnDamage( amount, from, willKill ); + } + + public PumpkinHead( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs b/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs new file mode 100644 index 0000000..4b59b74 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs @@ -0,0 +1,290 @@ +using System; +using Server.Items; +using Server.Mobiles; +using System.Collections.Generic; +using Server.Events.Halloween; + +namespace Server.Engines.Events +{ + public class HalloweenHauntings + { + public static Dictionary ReAnimated { get { return m_ReAnimated; } set { m_ReAnimated = value; } } + + private static Timer m_Timer; + private static Timer m_ClearTimer; + + private static int m_TotalZombieLimit; + private static int m_DeathQueueLimit; + private static int m_QueueDelaySeconds; + private static int m_QueueClearIntervalSeconds; + + private static Dictionary m_ReAnimated; + + private static List m_DeathQueue; + + private static Rectangle2D[] m_Cemetaries = new Rectangle2D[] + { + new Rectangle2D(1272,3712,30,20), // Jhelom + new Rectangle2D(1337,1444,48,52), // Britain + new Rectangle2D(2424,1098,20,28), // Trinsic + new Rectangle2D(2728,840,54,54), // Vesper + new Rectangle2D(4528,1314,20,28), // Moonglow + new Rectangle2D(712,1104,30,22), // Yew + new Rectangle2D(5824,1464,22,6), // Fire Dungeon + new Rectangle2D(5224,3655,14,5), // T2A + + new Rectangle2D(1272,3712,20,30), // Jhelom + new Rectangle2D(1337,1444,52,48), // Britain + new Rectangle2D(2424,1098,28,20), // Trinsic + new Rectangle2D(2728,840,54,54), // Vesper + new Rectangle2D(4528,1314,28,20), // Moonglow + new Rectangle2D(712,1104,22,30), // Yew + new Rectangle2D(5824,1464,6,22), // Fire Dungeon + new Rectangle2D(5224,3655,5,14), // T2A + }; + + public static void Initialize() + { + m_TotalZombieLimit = 200; + m_DeathQueueLimit = 200; + m_QueueDelaySeconds = 120; + m_QueueClearIntervalSeconds = 1800; + + DateTime today = DateTime.Now; + TimeSpan tick = TimeSpan.FromSeconds( m_QueueDelaySeconds ); + TimeSpan clear = TimeSpan.FromSeconds( m_QueueClearIntervalSeconds ); + + m_ReAnimated = new Dictionary(); + m_DeathQueue = new List(); + + if( today >= HolidaySettings.StartHalloween && today <= HolidaySettings.FinishHalloween ) + { + m_Timer = Timer.DelayCall( tick, tick, new TimerCallback( Timer_Callback ) ); + + m_ClearTimer = Timer.DelayCall( clear, clear, new TimerCallback( Clear_Callback ) ); + + EventSink.PlayerDeath += new PlayerDeathEventHandler( EventSink_PlayerDeath ); + } + } + + public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) + { + if( e.Mobile != null && !e.Mobile.Deleted ) /* not sure .. better safe than sorry? */ + { + if( e.Mobile is PlayerMobile ) + { + PlayerMobile player = e.Mobile as PlayerMobile; + + if( m_Timer.Running && !m_DeathQueue.Contains( player ) && m_DeathQueue.Count < m_DeathQueueLimit ) + { + m_DeathQueue.Add( player ); + } + } + } + } + + private static void Clear_Callback() + { + m_ReAnimated.Clear(); + + m_DeathQueue.Clear(); + + if( DateTime.Now <= HolidaySettings.FinishHalloween ) + { + m_ClearTimer.Stop(); + } + } + + private static void Timer_Callback() + { + PlayerMobile player = null; + + if( DateTime.Now <= HolidaySettings.FinishHalloween ) + { + for( int index = 0; m_DeathQueue.Count > 0 && index < m_DeathQueue.Count; index++ ) + { + if( !m_ReAnimated.ContainsKey( m_DeathQueue[ index ] ) ) + { + player = m_DeathQueue[ index ]; + + break; + } + } + + if( player != null && !player.Deleted && m_ReAnimated.Count < m_TotalZombieLimit ) + { + Map map = Utility.RandomBool() ? Map.Trammel : Map.Felucca; + + Point3D home = ( GetRandomPointInRect( m_Cemetaries[ Utility.Random( m_Cemetaries.Length ) ], map )); + + if( map.CanSpawnMobile( home ) ) + { + ZombieSkeleton zombieskel = new ZombieSkeleton( player ); + + m_ReAnimated.Add( player, zombieskel ); + zombieskel.Home = home; + zombieskel.RangeHome = 10; + + zombieskel.MoveToWorld( home, map ); + + m_DeathQueue.Remove( player ); + } + } + } + else + { + m_Timer.Stop(); + } + } + + private static Point3D GetRandomPointInRect( Rectangle2D rect, Map map ) + { + int x = Utility.Random( rect.X, rect.Width ); + int y = Utility.Random( rect.Y, rect.Height ); + + return new Point3D( x, y, map.GetAverageZ( x, y ) ); + } + } + + public class PlayerBones : BaseContainer + { + [Constructable] + public PlayerBones( String name ) + : base( Utility.RandomMinMax( 0x0ECA, 0x0ED2 ) ) + { + Name = String.Format( "{0}'s bones", name ); + + switch( Utility.Random( 10 ) ) + { + case 0: Hue = 0xa09; break; + case 1: Hue = 0xa93; break; + case 2: Hue = 0xa47; break; + default: break; + } + } + + public PlayerBones( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [CorpseName( "a rotting corpse" )] + public class ZombieSkeleton : BaseCreature + { + private static readonly string m_Name = "Zombie Skeleton"; + + private PlayerMobile m_DeadPlayer; + + public ZombieSkeleton() + : this( null ) + { + } + + public ZombieSkeleton( PlayerMobile player ) + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + m_DeadPlayer = player; + + Name = ( player != null ) ? String.Format( "{0}'s {1}", player.Name, m_Name ) : m_Name; + + Body = 0x93; + BaseSoundID = 0x1c3; + + SetStr( 500 ); + SetDex( 500 ); + SetInt( 500 ); + + SetHits( 2500 ); + SetMana( 500 ); + SetStam( 500 ); + + SetDamage( 8, 18 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Fire, 50 ); + SetResistance( ResistanceType.Energy, 50 ); + SetResistance( ResistanceType.Physical, 50 ); + SetResistance( ResistanceType.Cold, 50 ); + SetResistance( ResistanceType.Poison, 50 ); + + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 95.1, 100 ); + SetSkill( SkillName.Wrestling, 85.1, 95 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 18; + } + + public override void GenerateLoot() + { + switch( Utility.Random( 10 ) ) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: if( m_DeadPlayer != null && !m_DeadPlayer.Deleted ) { PackItem( new PlayerBones( m_DeadPlayer.Name ) ); } break; + default: break; + } + + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune { get { return true; } } + + public override Poison PoisonImmune { get { return Poison.Regular; } } + + public ZombieSkeleton( Serial serial ) + : base( serial ) + { + } + + public override void OnDelete() + { + if( HalloweenHauntings.ReAnimated != null ) + { + if( m_DeadPlayer != null && !m_DeadPlayer.Deleted ) + { + if( HalloweenHauntings.ReAnimated.Count > 0 && HalloweenHauntings.ReAnimated.ContainsKey( m_DeadPlayer ) ) + { + HalloweenHauntings.ReAnimated.Remove( m_DeadPlayer ); + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )0 ); + + writer.WriteMobile( m_DeadPlayer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + m_DeadPlayer = ( PlayerMobile )reader.ReadMobile(); + } + } +} \ No newline at end of file diff --git a/Scripts/Holiday Stuff/Halloween/2012/Items/EvilJesterMask.cs b/Scripts/Holiday Stuff/Halloween/2012/Items/EvilJesterMask.cs new file mode 100644 index 0000000..55a2a08 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2012/Items/EvilJesterMask.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items.Holiday +{ + public class PaintedEvilJesterMask : BasePaintedMask + { + public override string MaskName { get { return "Evil Jester Mask"; } } + + [Constructable] + public PaintedEvilJesterMask() + : base( 0x4BA5 ) + { + } + + public PaintedEvilJesterMask( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/2012/Items/PorcelainMask.cs b/Scripts/Holiday Stuff/Halloween/2012/Items/PorcelainMask.cs new file mode 100644 index 0000000..54eebc9 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/2012/Items/PorcelainMask.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items.Holiday +{ + public class PaintedPorcelainMask : BasePaintedMask + { + public override string MaskName { get { return "Porcelain Mask"; } } + + [Constructable] + public PaintedPorcelainMask() + : base( 0x4BA7 ) + { + } + + public PaintedPorcelainMask( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/HolidaySettings.cs b/Scripts/Holiday Stuff/Halloween/HolidaySettings.cs new file mode 100644 index 0000000..10f89ba --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/HolidaySettings.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.Events.Halloween +{ + class HolidaySettings + { + public static DateTime StartHalloween { get { return new DateTime( 2012, 10, 24 ); } } // YY MM DD + public static DateTime FinishHalloween { get { return new DateTime( 2012, 11, 15 ); } } + + public static Item RandomGMBeggerItem { get { return ( Item )Activator.CreateInstance( m_GMBeggarTreats[ Utility.Random( m_GMBeggarTreats.Length ) ] ); } } + public static Item RandomTreat { get { return (Item)Activator.CreateInstance ( m_Treats[ Utility.Random( m_Treats.Length ) ]) ; } } + + private static Type[] m_GMBeggarTreats = + { + typeof( CreepyCake ), + typeof( PumpkinPizza ), + typeof( GrimWarning ), + typeof( HarvestWine ), + typeof( MurkyMilk ), + typeof( MrPlainsCookies ), + typeof( SkullsOnPike ), + typeof( ChairInAGhostCostume ), + typeof( ExcellentIronMaiden ), + typeof( HalloweenGuillotine ), + typeof( ColoredSmallWebs ) + }; + + private static Type[] m_Treats = + { + typeof(WrappedCandy), + typeof(RedLollipop), + typeof(GreenLollipop), + typeof(YellowLollipop), + typeof(RedCandyCane), + typeof(GreenCandyCane), + typeof(Jellybeans), + typeof(Nougat) + }; + } +} diff --git a/Scripts/Holiday Stuff/Halloween/Treats/Jellybeans.c_ b/Scripts/Holiday Stuff/Halloween/Treats/Jellybeans.c_ new file mode 100644 index 0000000..ad6f49c --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/Treats/Jellybeans.c_ @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class JellyBeans : CandyCane + { + public override int LabelNumber { get { return 1096932; } } /* jellybeans */ + + [Constructable] + public JellyBeans() + : this( 1 ) + { + } + + public JellyBeans( int amount ) + : base( 0x468C ) + { + Stackable = true; + } + + public JellyBeans( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/Treats/Lollipops.c_ b/Scripts/Holiday Stuff/Halloween/Treats/Lollipops.c_ new file mode 100644 index 0000000..4031926 --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/Treats/Lollipops.c_ @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + [TypeAlias( "Server.Items.Lollipop" )] + public class Lollipops : CandyCane + { + [Constructable] + public Lollipops() + : this( 1 ) + { + } + + [Constructable] + public Lollipops( int amount ) + : base( 0x468D + Utility.Random( 3 )) + { + Stackable = true; + } + + public Lollipops( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/Treats/NougatSwirl.c_ b/Scripts/Holiday Stuff/Halloween/Treats/NougatSwirl.c_ new file mode 100644 index 0000000..4046d0e --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/Treats/NougatSwirl.c_ @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NougatSwirl : CandyCane + { + public override int LabelNumber { get { return 1096936; } } /* nougat swirl */ + + [Constructable] + public NougatSwirl() : this(1) + { + + } + + [Constructable] + public NougatSwirl( int amount ) + : base( 0x4690 ) + { + Stackable = true; + } + + public NougatSwirl( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/Treats/Taffy.c_ b/Scripts/Holiday Stuff/Halloween/Treats/Taffy.c_ new file mode 100644 index 0000000..16be51b --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/Treats/Taffy.c_ @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Taffy : CandyCane + { + public override int LabelNumber { get { return 1096949; } } /* taffy */ + + [Constructable] + public Taffy() + : this( 1 ) + { + } + + public Taffy( int amount ) + : base( 0x469D ) + { + Stackable = true; + } + + public Taffy( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Halloween/Treats/WrappedCandy.cs b/Scripts/Holiday Stuff/Halloween/Treats/WrappedCandy.cs new file mode 100644 index 0000000..d6ae87f --- /dev/null +++ b/Scripts/Holiday Stuff/Halloween/Treats/WrappedCandy.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WrappedCandy : BaseCandyCane + { + public override int LabelNumber { get { return 1096950; } } /* wrapped candy */ + + [Constructable] + public WrappedCandy() + : this( 1 ) + { + } + + public WrappedCandy( int amount ) + : base( 0x469e ) + { + Stackable = true; + } + + public WrappedCandy( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Valentine/2010/Items/AnimatedHeartShapedBox.cs b/Scripts/Holiday Stuff/Valentine/2010/Items/AnimatedHeartShapedBox.cs new file mode 100644 index 0000000..7cecc6a --- /dev/null +++ b/Scripts/Holiday Stuff/Valentine/2010/Items/AnimatedHeartShapedBox.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x49CC, 0x49D0 )] + public class AnimatedHeartShapedBox : HeartShapedBox + { + [Constructable] + public AnimatedHeartShapedBox() + { + ItemID = 0x49CC; + } + + public AnimatedHeartShapedBox( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Valentine/2011/Items/StValentinesBears.cs b/Scripts/Holiday Stuff/Valentine/2011/Items/StValentinesBears.cs new file mode 100644 index 0000000..9372b80 --- /dev/null +++ b/Scripts/Holiday Stuff/Valentine/2011/Items/StValentinesBears.cs @@ -0,0 +1,300 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public abstract class StValentinesBear : Item + { + public override string DefaultName + { + get + { + if ( m_Owner != null ) + return String.Format( "{0}'s St. Valentine Bear", m_Owner ); + else + return "St. Valentine Bear"; + } + } + + private string m_Owner; + private string m_Line1; + private string m_Line2; + private string m_Line3; + + private DateTime m_EditLimit; + + [CommandProperty( AccessLevel.GameMaster )] + public string Owner + { + get { return m_Owner; } + set { m_Owner = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Line1 + { + get { return m_Line1; } + set { m_Line1 = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Line2 + { + get { return m_Line2; } + set { m_Line2 = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Line3 + { + get { return m_Line3; } + set { m_Line3 = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime EditLimit + { + get { return m_EditLimit; } + set { m_EditLimit = value; } + } + + public bool IsSigned + { + get { return ( m_Line1 != null || m_Line2 != null || m_Line3 != null ); } + } + + public bool CanSign + { + get { return ( !IsSigned || DateTime.Now <= m_EditLimit ); } + } + + public StValentinesBear( int itemid, string name ) + : base( itemid ) + { + m_Owner = name; + LootType = LootType.Blessed; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_Owner != null ) + list.Add( 1150295, m_Owner ); // ~1_NAME~'s St. Valentine Bear + else + list.Add( 1150294 ); // St. Valentine Bear + + AddLine( list, 1150301, m_Line1 ); // [ ~1_LINE0~ ] + AddLine( list, 1150302, m_Line2 ); // [ ~1_LINE1~ ] + AddLine( list, 1150303, m_Line3 ); // [ ~1_LINE2~ ] + } + + private static void AddLine( ObjectPropertyList list, int cliloc, string line ) + { + if ( line != null ) + list.Add( cliloc, line ); + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + ShowLine( from, 1150301, m_Line1 ); // [ ~1_LINE0~ ] + ShowLine( from, 1150302, m_Line2 ); // [ ~1_LINE1~ ] + ShowLine( from, 1150303, m_Line3 ); // [ ~1_LINE2~ ] + } + + private void ShowLine( Mobile from, int cliloc, string line ) + { + if ( line != null ) + LabelTo( from, cliloc, line ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !CupidsArrow.CheckSeason( from ) || !CanSign ) + return; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1080063 ); // This must be in your backpack to use it. + return; + } + + from.SendGump( new InternalGump( this ) ); + } + + public StValentinesBear( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + + writer.Write( m_Owner ); + writer.Write( m_Line1 ); + writer.Write( m_Line2 ); + writer.Write( m_Line3 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Owner = Utility.Intern( reader.ReadString() ); + m_Line1 = Utility.Intern( reader.ReadString() ); + m_Line2 = Utility.Intern( reader.ReadString() ); + m_Line3 = Utility.Intern( reader.ReadString() ); + } + + private class InternalGump : Gump + { + private StValentinesBear m_Bear; + + public InternalGump( StValentinesBear bear ) + : base( 50, 50 ) + { + m_Bear = bear; + + AddPage( 0 ); + AddBackground( 0, 0, 420, 320, 9300 ); + AddHtml( 10, 10, 400, 21, "
St. Valentine Bear
", false, false ); + AddHtmlLocalized( 10, 40, 400, 75, 1150293, 0, false, false ); // Enter up to three lines of personalized greeting for your St. Valentine Bear. You many enter up to 25 characters per line. Once you enter text, you will only be able to correct mistakes for 10 minutes. + + AddHtmlLocalized( 10, 129, 400, 21, 1150296, 0, false, false ); // Line 1: + AddBackground( 10, 150, 400, 24, 9350 ); + AddTextEntry( 15, 152, 390, 20, 0, 0, "", 25 ); + + AddHtmlLocalized( 10, 179, 400, 21, 1150297, 0, false, false ); // Line 2: + AddBackground( 10, 200, 400, 24, 9350 ); + AddTextEntry( 15, 202, 390, 20, 0, 1, "", 25 ); + + AddHtmlLocalized( 10, 229, 400, 21, 1150298, 0, false, false ); // Line 3: + AddBackground( 10, 250, 400, 24, 9350 ); + AddTextEntry( 15, 252, 390, 20, 0, 2, "", 25 ); + + AddButton( 15, 285, 242, 241, 0, GumpButtonType.Reply, 0 ); + AddButton( 335, 285, 247, 248, 1, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( m_Bear.Deleted || !m_Bear.IsChildOf( from.Backpack ) || !m_Bear.CanSign || info.ButtonID != 1 ) + return; + + string line1 = GetLine( info, 0 ); + string line2 = GetLine( info, 1 ); + string line3 = GetLine( info, 2 ); + + if ( string.IsNullOrEmpty( line1 ) + || string.IsNullOrEmpty( line2 ) + || string.IsNullOrEmpty( line3 ) ) + { + from.SendMessage( "Lines cannot be left blank." ); + return; + } + else if ( line1.Length > 25 + || line2.Length > 25 + || line3.Length > 25 ) + { + from.SendMessage( "Lines may not exceed 25 characters." ); + return; + } + + if ( !m_Bear.IsSigned ) + m_Bear.EditLimit = DateTime.Now + TimeSpan.FromMinutes( 10 ); + + m_Bear.Line1 = Utility.FixHtml( line1 ); + m_Bear.Line2 = Utility.FixHtml( line2 ); + m_Bear.Line3 = Utility.FixHtml( line3 ); + + from.SendMessage( "You add the personalized greeting to your St. Valentine Bear." ); + } + + private static string GetLine( RelayInfo info, int idx ) + { + TextRelay tr = info.GetTextEntry( idx ); + + return ( tr == null ) ? null : tr.Text; + } + } + } + + [FlipableAttribute( 0x48E0, 0x48E1 )] + public class StValentinesPanda : StValentinesBear + { + [Constructable] + public StValentinesPanda() + : this( null ) + { + } + + [Constructable] + public StValentinesPanda( string name ) + : base( 0x48E0, name ) + { + } + + public StValentinesPanda( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x48E2, 0x48E3 )] + public class StValentinesPolarBear : StValentinesBear + { + [Constructable] + public StValentinesPolarBear() + : this( null ) + { + } + + [Constructable] + public StValentinesPolarBear( string name ) + : base( 0x48E2, name ) + { + } + + public StValentinesPolarBear( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Valentine/2012/Items/CupidStatue.cs b/Scripts/Holiday Stuff/Valentine/2012/Items/CupidStatue.cs new file mode 100644 index 0000000..7bb1da9 --- /dev/null +++ b/Scripts/Holiday Stuff/Valentine/2012/Items/CupidStatue.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x4F7C, 0x4F7D )] + public class CupidStatue : Item + { + public override int LabelNumber { get { return 1099220; } } // cupid statue + + [Constructable] + public CupidStatue() + : base( 0x4F7D ) + { + LootType = LootType.Blessed; + } + + public CupidStatue( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Holiday Stuff/Valentine/2012/Items/CupidsArrow.cs b/Scripts/Holiday Stuff/Valentine/2012/Items/CupidsArrow.cs new file mode 100644 index 0000000..1421c80 --- /dev/null +++ b/Scripts/Holiday Stuff/Valentine/2012/Items/CupidsArrow.cs @@ -0,0 +1,135 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Items +{ + public class CupidsArrow : Item + { + // TODO: Check messages + + public override int LabelNumber { get { return 1152270; } } // Cupid's Arrow 2012 + + private string m_From; + private string m_To; + + [CommandProperty( AccessLevel.GameMaster )] + public string From + { + get { return m_From; } + set { m_From = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string To + { + get { return m_To; } + set { m_To = value; InvalidateProperties(); } + } + + public bool IsSigned + { + get { return ( m_From != null && m_To != null ); } + } + + [Constructable] + public CupidsArrow() + : base( 0x4F7F ) + { + LootType = LootType.Blessed; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + base.AddNameProperty( list ); + + if ( IsSigned ) + list.Add( 1152273, String.Format( "{0}\t{1}", m_From, m_To ) ); // ~1_val~ is madly in love with ~2_val~ + } + + public static bool CheckSeason( Mobile from ) + { + if ( DateTime.Now.Month == 2 ) + return true; + + from.SendLocalizedMessage( 1152318 ); // You may not use this item out of season. + return false; + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsSigned ) + LabelTo( from, 1152273, String.Format( "{0}\t{1}", m_From, m_To ) ); // ~1_val~ is madly in love with ~2_val~ + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsSigned || !CheckSeason( from ) ) + return; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1080063 ); // This must be in your backpack to use it. + return; + } + + from.BeginTarget( 10, false, TargetFlags.None, new TargetCallback( OnTarget ) ); + from.SendMessage( "Who do you wish to use this on?" ); + } + + private void OnTarget( Mobile from, object targeted ) + { + if ( IsSigned || !IsChildOf( from.Backpack ) ) + return; + + if ( targeted is Mobile ) + { + Mobile m = (Mobile)targeted; + + if ( !m.Alive ) + { + from.SendLocalizedMessage( 1152269 ); // That target is dead and even Cupid's arrow won't make them love you. + return; + } + + m_From = from.Name; + m_To = m.Name; + + InvalidateProperties(); + + from.SendMessage( "You inscribe the arrow." ); + } + else + { + from.SendMessage( "That is not a person." ); + } + } + + public CupidsArrow( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + + writer.Write( m_From ); + writer.Write( m_To ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_From = Utility.Intern( reader.ReadString() ); + m_To = Utility.Intern( reader.ReadString() ); + } + } +} diff --git a/Scripts/Holiday Stuff/Valentine/2012/Items/HeartShapedBox.cs b/Scripts/Holiday Stuff/Valentine/2012/Items/HeartShapedBox.cs new file mode 100644 index 0000000..191970f --- /dev/null +++ b/Scripts/Holiday Stuff/Valentine/2012/Items/HeartShapedBox.cs @@ -0,0 +1,55 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x49CA, 0x49CB )] + public class HeartShapedBox : BaseContainer + { + public override int DefaultDropSound { get { return m_DropSound; } } + + [Constructable] + public HeartShapedBox() + : base( 0x49CA ) + { + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + PrepareSound( from ); + return base.OnDragDropInto( from, item, p ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + PrepareSound( from ); + return base.OnDragDrop( from, dropped ); + } + + private static int m_DropSound; + + private static void PrepareSound( Mobile from ) + { + m_DropSound = from.Female ? 0x430 : 0x320; + } + + public HeartShapedBox( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Addons/AbbatoirAddon.cs b/Scripts/Items/Addons/AbbatoirAddon.cs new file mode 100644 index 0000000..48b9a96 --- /dev/null +++ b/Scripts/Items/Addons/AbbatoirAddon.cs @@ -0,0 +1,71 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AbbatoirAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new AbbatoirDeed(); } } + + [Constructable] + public AbbatoirAddon() + { + AddComponent( new AddonComponent( 0x120E ), -1, -1, 0 ); + AddComponent( new AddonComponent( 0x120F ), 0, -1, 0 ); + AddComponent( new AddonComponent( 0x1210 ), 1, -1, 0 ); + AddComponent( new AddonComponent( 0x1215 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x1216 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1211 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1214 ), -1, 1, 0 ); + AddComponent( new AddonComponent( 0x1213 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1212 ), 1, 1, 0 ); + } + + public AbbatoirAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AbbatoirDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new AbbatoirAddon(); } } + public override int LabelNumber{ get{ return 1044329; } } // abbatoir + + [Constructable] + public AbbatoirDeed() + { + } + + public AbbatoirDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/AddonComponent.cs b/Scripts/Items/Addons/AddonComponent.cs new file mode 100644 index 0000000..b521858 --- /dev/null +++ b/Scripts/Items/Addons/AddonComponent.cs @@ -0,0 +1,285 @@ +using System; +using Server; + +namespace Server.Items +{ + [Server.Engines.Craft.Anvil] + public class AnvilComponent : AddonComponent + { + [Constructable] + public AnvilComponent( int itemID ) : base( itemID ) + { + } + + public AnvilComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Server.Engines.Craft.Forge] + public class ForgeComponent : AddonComponent + { + [Constructable] + public ForgeComponent( int itemID ) : base( itemID ) + { + } + + public ForgeComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LocalizedAddonComponent : AddonComponent + { + private int m_LabelNumber; + + [CommandProperty( AccessLevel.GameMaster )] + public int Number + { + get{ return m_LabelNumber; } + set{ m_LabelNumber = value; InvalidateProperties(); } + } + + public override int LabelNumber{ get{ return m_LabelNumber; } } + + [Constructable] + public LocalizedAddonComponent( int itemID, int labelNumber ) : base( itemID ) + { + m_LabelNumber = labelNumber; + } + + public LocalizedAddonComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_LabelNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadInt(); + break; + } + } + } + } + + public class AddonComponent : Item, IChopable + { + private Point3D m_Offset; + private BaseAddon m_Addon; + + [CommandProperty( AccessLevel.GameMaster )] + public BaseAddon Addon + { + get + { + return m_Addon; + } + set + { + m_Addon = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Offset + { + get + { + return m_Offset; + } + set + { + m_Offset = value; + } + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get + { + return base.Hue; + } + set + { + base.Hue = value; + + if ( m_Addon != null && m_Addon.ShareHue ) + m_Addon.Hue = value; + } + } + + public virtual bool NeedsWall{ get{ return false; } } + public virtual Point3D WallPosition{ get{ return Point3D.Zero; } } + + [Constructable] + public AddonComponent( int itemID ) : base( itemID ) + { + Movable = false; + ApplyLightTo( this ); + } + + public AddonComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Addon != null ) + m_Addon.OnComponentUsed( this, from ); + } + + public void OnChop( Mobile from ) + { + if ( m_Addon != null && from.InRange( GetWorldLocation(), 3 ) ) + m_Addon.OnChop( from ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + public override void OnLocationChange( Point3D old ) + { + if ( m_Addon != null ) + m_Addon.Location = new Point3D( X - m_Offset.X, Y - m_Offset.Y, Z - m_Offset.Z ); + } + + public override void OnMapChange() + { + if ( m_Addon != null ) + m_Addon.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Addon != null ) + m_Addon.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Addon ); + writer.Write( m_Offset ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Addon = reader.ReadItem() as BaseAddon; + m_Offset = reader.ReadPoint3D(); + + if ( m_Addon != null ) + m_Addon.OnComponentLoaded( this ); + + ApplyLightTo( this ); + + break; + } + } + + if ( version < 1 && Weight == 0 ) + Weight = -1; + } + + public static void ApplyLightTo( Item item ) + { + if ( (item.ItemData.Flags & TileFlag.LightSource) == 0 ) + return; // not a light source + + int itemID = item.ItemID; + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + LightEntry entry = m_Entries[i]; + int[] toMatch = entry.m_ItemIDs; + bool contains = false; + + for ( int j = 0; !contains && j < toMatch.Length; ++j ) + contains = ( itemID == toMatch[j] ); + + if ( contains ) + { + item.Light = entry.m_Light; + return; + } + } + } + + private static LightEntry[] m_Entries = new LightEntry[] + { + new LightEntry( LightType.WestSmall, 1122, 1123, 1124, 1141, 1142, 1143, 1144, 1145, 1146, 2347, 2359, 2360, 2361, 2362, 2363, 2364, 2387, 2388, 2389, 2390, 2391, 2392 ), + new LightEntry( LightType.NorthSmall, 1131, 1133, 1134, 1147, 1148, 1149, 1150, 1151, 1152, 2352, 2373, 2374, 2375, 2376, 2377, 2378, 2401, 2402, 2403, 2404, 2405, 2406 ), + new LightEntry( LightType.Circle300, 6526, 6538, 6571 ), + new LightEntry( LightType.Circle150, 5703, 6587 ) + }; + + private class LightEntry + { + public LightType m_Light; + public int[] m_ItemIDs; + + public LightEntry( LightType light, params int[] itemIDs ) + { + m_Light = light; + m_ItemIDs = itemIDs; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/AddonContainerComponent.cs b/Scripts/Items/Addons/AddonContainerComponent.cs new file mode 100644 index 0000000..4ef8ffb --- /dev/null +++ b/Scripts/Items/Addons/AddonContainerComponent.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; + +namespace Server.Items +{ + public class AddonContainerComponent : Item, IChopable + { + public virtual bool NeedsWall { get { return false; } } + public virtual Point3D WallPosition { get { return Point3D.Zero; } } + + private Point3D m_Offset; + private BaseAddonContainer m_Addon; + + [CommandProperty( AccessLevel.GameMaster )] + public BaseAddonContainer Addon + { + get { return m_Addon; } + set { m_Addon = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Offset + { + get { return m_Offset; } + set { m_Offset = value; } + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get { return base.Hue; } + set + { + base.Hue = value; + + if ( m_Addon != null && m_Addon.ShareHue ) + m_Addon.Hue = value; + } + } + + [Constructable] + public AddonContainerComponent( int itemID ) : base( itemID ) + { + Movable = false; + + AddonComponent.ApplyLightTo( this ); + } + + public AddonContainerComponent( Serial serial ) : base( serial ) + { + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( Addon != null ) + return Addon.OnDragDrop( from, dropped ); + + return false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Addon != null ) + m_Addon.OnComponentUsed( this, from ); + } + + public override void OnLocationChange( Point3D old ) + { + if ( m_Addon != null ) + m_Addon.Location = new Point3D( X - m_Offset.X, Y - m_Offset.Y, Z - m_Offset.Z ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + if ( m_Addon != null ) + m_Addon.GetContextMenuEntries( from, list ); + } + + public override void OnMapChange() + { + if ( m_Addon != null ) + m_Addon.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Addon != null ) + m_Addon.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Addon ); + writer.Write( m_Offset ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Addon = reader.ReadItem() as BaseAddonContainer; + m_Offset = reader.ReadPoint3D(); + + if ( m_Addon != null ) + m_Addon.OnComponentLoaded( this ); + + AddonComponent.ApplyLightTo( this ); + } + + public virtual void OnChop( Mobile from ) + { + if ( m_Addon != null && from.InRange( GetWorldLocation(), 3 ) ) + m_Addon.OnChop( from ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + + public class LocalizedContainerComponent : AddonContainerComponent + { + private int m_LabelNumber; + + public override int LabelNumber + { + get + { + if ( m_LabelNumber > 0 ) + return m_LabelNumber; + + return base.LabelNumber; + } + } + + public LocalizedContainerComponent( int itemID, int labelNumber ) : base( itemID ) + { + m_LabelNumber = labelNumber; + } + + public LocalizedContainerComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_LabelNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_LabelNumber = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Addons/AlchemistTableEastAddon.cs b/Scripts/Items/Addons/AlchemistTableEastAddon.cs new file mode 100644 index 0000000..9ae3aa5 --- /dev/null +++ b/Scripts/Items/Addons/AlchemistTableEastAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AlchemistTableEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new AlchemistTableEastDeed(); } } + + [Constructable] + public AlchemistTableEastAddon() + { + AddComponent( new AddonComponent( 0x2DD3 ), 0, 0, 0 ); + } + + public AlchemistTableEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class AlchemistTableEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new AlchemistTableEastAddon(); } } + public override int LabelNumber{ get{ return 1073397; } } // alchemist table (east) + + [Constructable] + public AlchemistTableEastDeed() + { + } + + public AlchemistTableEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/AlchemistTableSouthAddon.cs b/Scripts/Items/Addons/AlchemistTableSouthAddon.cs new file mode 100644 index 0000000..0ae5fa3 --- /dev/null +++ b/Scripts/Items/Addons/AlchemistTableSouthAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AlchemistTableSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new AlchemistTableSouthDeed(); } } + + [Constructable] + public AlchemistTableSouthAddon() + { + AddComponent( new AddonComponent( 0x2DD4 ), 0, 0, 0 ); + } + + public AlchemistTableSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class AlchemistTableSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new AlchemistTableSouthAddon(); } } + public override int LabelNumber{ get{ return 1073396; } } // alchemist table (south) + + [Constructable] + public AlchemistTableSouthDeed() + { + } + + public AlchemistTableSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/AnvilEastAddon.cs b/Scripts/Items/Addons/AnvilEastAddon.cs new file mode 100644 index 0000000..641183d --- /dev/null +++ b/Scripts/Items/Addons/AnvilEastAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AnvilEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new AnvilEastDeed(); } } + + [Constructable] + public AnvilEastAddon() + { + AddComponent( new AnvilComponent( 0xFAF ), 0, 0, 0 ); + } + + public AnvilEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AnvilEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new AnvilEastAddon(); } } + public override int LabelNumber{ get{ return 1044333; } } // anvil (east) + + [Constructable] + public AnvilEastDeed() + { + } + + public AnvilEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/AnvilSouthAddon.cs b/Scripts/Items/Addons/AnvilSouthAddon.cs new file mode 100644 index 0000000..bc38cb7 --- /dev/null +++ b/Scripts/Items/Addons/AnvilSouthAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AnvilSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new AnvilSouthDeed(); } } + + [Constructable] + public AnvilSouthAddon() + { + AddComponent( new AnvilComponent( 0xFB0 ), 0, 0, 0 ); + } + + public AnvilSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AnvilSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new AnvilSouthAddon(); } } + public override int LabelNumber{ get{ return 1044334; } } // anvil (south) + + [Constructable] + public AnvilSouthDeed() + { + } + + public AnvilSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ArcaneBookshelfEastAddon.cs b/Scripts/Items/Addons/ArcaneBookshelfEastAddon.cs new file mode 100644 index 0000000..6389789 --- /dev/null +++ b/Scripts/Items/Addons/ArcaneBookshelfEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcaneBookshelfEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ArcaneBookshelfEastDeed(); } } + + [Constructable] + public ArcaneBookshelfEastAddon() + { + AddComponent( new AddonComponent( 0x3084 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3085 ), -1, 0, 0 ); + } + + public ArcaneBookshelfEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ArcaneBookshelfEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ArcaneBookshelfEastAddon(); } } + public override int LabelNumber{ get{ return 1073371; } } // arcane bookshelf (east) + + [Constructable] + public ArcaneBookshelfEastDeed() + { + } + + public ArcaneBookshelfEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ArcaneBookshelfSouthAddon.cs b/Scripts/Items/Addons/ArcaneBookshelfSouthAddon.cs new file mode 100644 index 0000000..addf26f --- /dev/null +++ b/Scripts/Items/Addons/ArcaneBookshelfSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcaneBookshelfSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ArcaneBookshelfSouthDeed(); } } + + [Constructable] + public ArcaneBookshelfSouthAddon() + { + AddComponent( new AddonComponent( 0x3087 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3086 ), 0, 1, 0 ); + } + + public ArcaneBookshelfSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ArcaneBookshelfSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ArcaneBookshelfSouthAddon(); } } + public override int LabelNumber{ get{ return 1072871; } } // arcane bookshelf (south) + + [Constructable] + public ArcaneBookshelfSouthDeed() + { + } + + public ArcaneBookshelfSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ArcaneCircleAddon.cs b/Scripts/Items/Addons/ArcaneCircleAddon.cs new file mode 100644 index 0000000..33e1b0d --- /dev/null +++ b/Scripts/Items/Addons/ArcaneCircleAddon.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Items +{ + public class ArcaneCircleAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new ArcaneCircleDeed(); } } + + [Constructable] + public ArcaneCircleAddon() + { + AddComponent(new AddonComponent(0x3083), -1, -1, 0); + AddComponent(new AddonComponent(0x3080), -1, 0, 0); + AddComponent(new AddonComponent(0x3082), 0, -1, 0); + AddComponent(new AddonComponent(0x3081), 1, -1, 0); + AddComponent(new AddonComponent(0x307D), -1, 1, 0); + AddComponent(new AddonComponent(0x307F), 0, 0, 0); + AddComponent(new AddonComponent(0x307E), 1, 0, 0); + AddComponent(new AddonComponent(0x307C), 0, 1, 0); + AddComponent(new AddonComponent(0x307B), 1, 1, 0); + } + + public ArcaneCircleAddon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0) + ValidationQueue.Add(this); + } + + public void Validate() + { + foreach (AddonComponent c in Components) + { + if (c.ItemID == 0x3083) + { + c.Offset = new Point3D(-1, -1, 0); + c.MoveToWorld(new Point3D(X + c.Offset.X, Y + c.Offset.Y, Z + c.Offset.Z), Map); + } + } + } + } + + public class ArcaneCircleDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new ArcaneCircleAddon(); } } + public override int LabelNumber { get { return 1072703; } } // arcane circle + + [Constructable] + public ArcaneCircleDeed() + { + } + + public ArcaneCircleDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ArcanistStatueEastAddon.cs b/Scripts/Items/Addons/ArcanistStatueEastAddon.cs new file mode 100644 index 0000000..ef41b8d --- /dev/null +++ b/Scripts/Items/Addons/ArcanistStatueEastAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcanistStatueEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ArcanistStatueEastDeed(); } } + + [Constructable] + public ArcanistStatueEastAddon() + { + AddComponent( new AddonComponent( 0x2D0E ), 0, 0, 0 ); + } + + public ArcanistStatueEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ArcanistStatueEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ArcanistStatueEastAddon(); } } + public override int LabelNumber{ get{ return 1072886; } } // arcanist statue (east) + + [Constructable] + public ArcanistStatueEastDeed() + { + } + + public ArcanistStatueEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ArcanistStatueSouthAddon.cs b/Scripts/Items/Addons/ArcanistStatueSouthAddon.cs new file mode 100644 index 0000000..7e2881e --- /dev/null +++ b/Scripts/Items/Addons/ArcanistStatueSouthAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcanistStatueSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ArcanistStatueSouthDeed(); } } + + [Constructable] + public ArcanistStatueSouthAddon() + { + AddComponent( new AddonComponent( 0x2D0F ), 0, 0, 0 ); + } + + public ArcanistStatueSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ArcanistStatueSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ArcanistStatueSouthAddon(); } } + public override int LabelNumber{ get{ return 1072885; } } // arcanist statue (south) + + [Constructable] + public ArcanistStatueSouthDeed() + { + } + + public ArcanistStatueSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ArcheryButteAddon.cs b/Scripts/Items/Addons/ArcheryButteAddon.cs new file mode 100644 index 0000000..9044063 --- /dev/null +++ b/Scripts/Items/Addons/ArcheryButteAddon.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections; +using Server; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x100A/*East*/, 0x100B/*South*/ )] + public class ArcheryButte : AddonComponent + { + private double m_MinSkill; + private double m_MaxSkill; + + private int m_Arrows, m_Bolts; + + private DateTime m_LastUse; + + [CommandProperty( AccessLevel.GameMaster )] + public double MinSkill + { + get{ return m_MinSkill; } + set{ m_MinSkill = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public double MaxSkill + { + get{ return m_MaxSkill; } + set{ m_MaxSkill = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastUse + { + get{ return m_LastUse; } + set{ m_LastUse = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool FacingEast + { + get{ return ( ItemID == 0x100A ); } + set{ ItemID = value ? 0x100A : 0x100B; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Arrows + { + get{ return m_Arrows; } + set{ m_Arrows = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Bolts + { + get{ return m_Bolts; } + set{ m_Bolts = value; } + } + + [Constructable] + public ArcheryButte() : this( 0x100A ) + { + } + + public ArcheryButte( int itemID ) : base( itemID ) + { + m_MinSkill = -25.0; + m_MaxSkill = +25.0; + } + + public ArcheryButte( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( (m_Arrows > 0 || m_Bolts > 0) && from.InRange( GetWorldLocation(), 1 ) ) + Gather( from ); + else + Fire( from ); + } + + public void Gather( Mobile from ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500592 ); // You gather the arrows and bolts. + + if ( m_Arrows > 0 ) + from.AddToBackpack( new Arrow( m_Arrows ) ); + + if ( m_Bolts > 0 ) + from.AddToBackpack( new Bolt( m_Bolts ) ); + + m_Arrows = 0; + m_Bolts = 0; + + m_Entries = null; + } + + private static TimeSpan UseDelay = TimeSpan.FromSeconds( 2.0 ); + + private class ScoreEntry + { + private int m_Total; + private int m_Count; + + public int Total{ get{ return m_Total; } set{ m_Total = value; } } + public int Count{ get{ return m_Count; } set{ m_Count = value; } } + + public void Record( int score ) + { + m_Total += score; + m_Count += 1; + } + + public ScoreEntry() + { + } + } + + private Hashtable m_Entries; + + private ScoreEntry GetEntryFor( Mobile from ) + { + if ( m_Entries == null ) + m_Entries = new Hashtable(); + + ScoreEntry e = (ScoreEntry)m_Entries[from]; + + if ( e == null ) + m_Entries[from] = e = new ScoreEntry(); + + return e; + } + + public void Fire( Mobile from ) + { + BaseRanged bow = from.Weapon as BaseRanged; + + if ( bow == null ) + { + SendLocalizedMessageTo( from, 500593 ); // You must practice with ranged weapons on this. + return; + } + + if ( DateTime.Now < (m_LastUse + UseDelay) ) + return; + + Point3D worldLoc = GetWorldLocation(); + + if ( FacingEast ? from.X <= worldLoc.X : from.Y <= worldLoc.Y ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500596 ); // You would do better to stand in front of the archery butte. + return; + } + + if ( FacingEast ? from.Y != worldLoc.Y : from.X != worldLoc.X ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500597 ); // You aren't properly lined up with the archery butte to get an accurate shot. + return; + } + + if ( !from.InRange( worldLoc, 6 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500598 ); // You are too far away from the archery butte to get an accurate shot. + return; + } + else if ( from.InRange( worldLoc, 4 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500599 ); // You are too close to the target. + return; + } + + Container pack = from.Backpack; + Type ammoType = bow.AmmoType; + + bool isArrow = ( ammoType == typeof( Arrow ) ); + bool isBolt = ( ammoType == typeof( Bolt ) ); + bool isKnown = ( isArrow || isBolt ); + + if ( pack == null || !pack.ConsumeTotal( ammoType, 1 ) ) + { + if ( isArrow ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500594 ); // You do not have any arrows with which to practice. + else if ( isBolt ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500595 ); // You do not have any crossbow bolts with which to practice. + else + SendLocalizedMessageTo( from, 500593 ); // You must practice with ranged weapons on this. + + return; + } + + m_LastUse = DateTime.Now; + + from.Direction = from.GetDirectionTo( GetWorldLocation() ); + bow.PlaySwingAnimation( from ); + from.MovingEffect( this, bow.EffectID, 18, 1, false, false ); + + ScoreEntry se = GetEntryFor( from ); + + if ( !from.CheckSkill( bow.Skill, m_MinSkill, m_MaxSkill ) ) + { + from.PlaySound( bow.MissSound ); + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500604, from.Name ); // You miss the target altogether. + + se.Record( 0 ); + + if ( se.Count == 1 ) + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1062719, se.Total.ToString() ); + else + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1042683, String.Format( "{0}\t{1}", se.Total, se.Count ) ); + + return; + } + + Effects.PlaySound( Location, Map, 0x2B1 ); + + double rand = Utility.RandomDouble(); + + int area, score, splitScore; + + if ( 0.10 > rand ) + { + area = 0; // bullseye + score = 50; + splitScore = 100; + } + else if ( 0.25 > rand ) + { + area = 1; // inner ring + score = 10; + splitScore = 20; + } + else if ( 0.50 > rand ) + { + area = 2; // middle ring + score = 5; + splitScore = 15; + } + else + { + area = 3; // outer ring + score = 2; + splitScore = 5; + } + + bool split = ( isKnown && ((m_Arrows + m_Bolts) * 0.02) > Utility.RandomDouble() ); + + if ( split ) + { + PublicOverheadMessage(MessageType.Regular, 0x3B2, 1010027 + area, String.Format("{0}\t{1}", from.Name, isArrow ? "arrow" : "bolt")); + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1010035 + area, from.Name ); + + if ( isArrow ) + ++m_Arrows; + else if ( isBolt ) + ++m_Bolts; + } + + se.Record( split ? splitScore : score ); + + if ( se.Count == 1 ) + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1062719, se.Total.ToString() ); + else + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1042683, String.Format( "{0}\t{1}", se.Total, se.Count ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_MinSkill ); + writer.Write( m_MaxSkill ); + writer.Write( m_Arrows ); + writer.Write( m_Bolts ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_MinSkill = reader.ReadDouble(); + m_MaxSkill = reader.ReadDouble(); + m_Arrows = reader.ReadInt(); + m_Bolts = reader.ReadInt(); + + if ( m_MinSkill == 0.0 && m_MaxSkill == 30.0 ) + { + m_MinSkill = -25.0; + m_MaxSkill = +25.0; + } + + break; + } + } + } + } + + public class ArcheryButteAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ArcheryButteDeed(); } } + + [Constructable] + public ArcheryButteAddon() + { + AddComponent( new ArcheryButte( 0x100A ), 0, 0, 0 ); + } + + public ArcheryButteAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ArcheryButteDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ArcheryButteAddon(); } } + public override int LabelNumber{ get{ return 1024106; } } // archery butte + + [Constructable] + public ArcheryButteDeed() + { + } + + public ArcheryButteDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/BallotBox.cs b/Scripts/Items/Addons/BallotBox.cs new file mode 100644 index 0000000..d9238c2 --- /dev/null +++ b/Scripts/Items/Addons/BallotBox.cs @@ -0,0 +1,392 @@ +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Gumps; +using Server.Network; +using Server.Prompts; +using System.Collections.Generic; + +namespace Server.Items +{ + public class BallotBox : AddonComponent + { + public static readonly int MaxTopicLines = 6; + + public override int LabelNumber{ get{ return 1041006; } } // a ballot box + + private string[] m_Topic; + private List m_Yes; + private List m_No; + + public string[] Topic + { + get{ return m_Topic; } + } + + public List Yes + { + get{ return m_Yes; } + } + + public List No + { + get{ return m_No; } + } + + [Constructable] + public BallotBox() : base( 0x9A8 ) + { + m_Topic = new string[0]; + m_Yes = new List(); + m_No = new List(); + } + + public BallotBox( Serial serial ) : base( serial ) + { + } + + public void ClearTopic() + { + m_Topic = new string[0]; + + ClearVotes(); + } + + public void AddLineToTopic( string line ) + { + if ( m_Topic.Length >= MaxTopicLines ) + return; + + string[] newTopic = new string[m_Topic.Length + 1]; + m_Topic.CopyTo( newTopic, 0 ); + newTopic[m_Topic.Length] = line; + + m_Topic = newTopic; + + ClearVotes(); + } + + public void ClearVotes() + { + Yes.Clear(); + No.Clear(); + } + + public bool IsOwner( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + return ( house != null && house.IsOwner( from ) ); + } + + public bool HasVoted( Mobile from ) + { + return ( Yes.Contains( from ) || No.Contains( from ) ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + SendLocalizedMessageTo( from, 500369 ); // I'm a ballot box, not a container! + return false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + else + { + bool isOwner = IsOwner( from ); + from.SendGump( new InternalGump( this, isOwner ) ); + } + } + + private class InternalGump : Gump + { + private BallotBox m_Box; + + public InternalGump( BallotBox box, bool isOwner ) : base( 110, 70 ) + { + m_Box = box; + + AddBackground( 0, 0, 400, 350, 0xA28 ); + + if ( isOwner ) + AddHtmlLocalized( 0, 15, 400, 35, 1011000, false, false ); //
Ballot Box Owner's Menu
+ else + AddHtmlLocalized( 0, 15, 400, 35, 1011001, false, false ); //
Ballot Box -- Vote Here!
+ + AddHtmlLocalized( 0, 50, 400, 35, 1011002, false, false ); //
Topic
+ + int lineCount = box.Topic.Length; + AddBackground( 25, 90, 350, Math.Max( 20 * lineCount, 20 ), 0x1400 ); + + for ( int i = 0; i < lineCount; i++ ) + { + string line = box.Topic[i]; + + if ( !String.IsNullOrEmpty( line ) ) + AddLabelCropped( 30, 90 + i * 20, 340, 20, 0x3E3, line ); + } + + int yesCount = box.Yes.Count; + int noCount = box.No.Count; + int totalVotes = yesCount + noCount; + + AddHtmlLocalized( 0, 215, 400, 35, 1011003, false, false ); //
votes
+ + if ( !isOwner ) + AddButton( 20, 240, 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 242, 25, 35, 1011004, false, false ); // aye: + AddLabel( 78, 242, 0x0, String.Format( "[{0}]", yesCount ) ); + + if ( !isOwner ) + AddButton( 20, 275, 0xFA5, 0xFA7, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 277, 25, 35, 1011005, false, false ); // nay: + AddLabel( 78, 277, 0x0, String.Format( "[{0}]", noCount ) ); + + if ( totalVotes > 0 ) + { + AddImageTiled( 130, 242, ( yesCount * 225 ) / totalVotes, 10, 0xD6 ); + AddImageTiled( 130, 277, ( noCount * 225 ) / totalVotes, 10, 0xD6 ); + } + + AddButton( 45, 305, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 308, 40, 35, 1011008, false, false ); // done + + if ( isOwner ) + { + AddButton( 120, 305, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 155, 308, 100, 35, 1011006, false, false ); // change topic + + AddButton( 240, 305, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 275, 308, 300, 100, 1011007, false, false ); // reset votes + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Box.Deleted || info.ButtonID == 0 ) + return; + + Mobile from = sender.Mobile; + + if ( from.Map != m_Box.Map || !from.InRange( m_Box.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + bool isOwner = m_Box.IsOwner( from ); + + switch ( info.ButtonID ) + { + case 1: // change topic + { + if ( isOwner ) + { + m_Box.ClearTopic(); + + from.SendLocalizedMessage( 500370, "", 0x35 ); // Enter a line of text for your ballot, and hit ENTER. Hit ESC after the last line is entered. + from.Prompt = new TopicPrompt( m_Box ); + } + + break; + } + case 2: // reset votes + { + if ( isOwner ) + { + m_Box.ClearVotes(); + from.SendLocalizedMessage( 500371 ); // Votes zeroed out. + } + + goto default; + } + case 3: // aye + { + if ( !isOwner ) + { + if ( m_Box.HasVoted( from ) ) + { + from.SendLocalizedMessage( 500374 ); // You have already voted on this ballot. + } + else + { + m_Box.Yes.Add( from ); + from.SendLocalizedMessage( 500373 ); // Your vote has been registered. + } + } + + goto default; + } + case 4: // nay + { + if ( !isOwner ) + { + if ( m_Box.HasVoted( from ) ) + { + from.SendLocalizedMessage( 500374 ); // You have already voted on this ballot. + } + else + { + m_Box.No.Add( from ); + from.SendLocalizedMessage( 500373 ); // Your vote has been registered. + } + } + + goto default; + } + default: + { + from.SendGump( new InternalGump( m_Box, isOwner ) ); + break; + } + } + } + } + + private class TopicPrompt : Prompt + { + private BallotBox m_Box; + + public TopicPrompt( BallotBox box ) + { + m_Box = box; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Box.Deleted || !m_Box.IsOwner( from ) ) + return; + + if ( from.Map != m_Box.Map || !from.InRange( m_Box.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + m_Box.AddLineToTopic( text.TrimEnd() ); + + if ( m_Box.Topic.Length < MaxTopicLines ) + { + from.SendLocalizedMessage( 500377, "", 0x35 ); // Next line or ESC to finish: + from.Prompt = new TopicPrompt( m_Box ); + } + else + { + from.SendLocalizedMessage( 500376, "", 0x35 ); // Ballot entry complete. + from.SendGump( new InternalGump( m_Box, true ) ); + } + } + + public override void OnCancel( Mobile from ) + { + if ( m_Box.Deleted || !m_Box.IsOwner( from ) ) + return; + + if ( from.Map != m_Box.Map || !from.InRange( m_Box.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + from.SendLocalizedMessage( 500376, "", 0x35 ); // Ballot entry complete. + from.SendGump( new InternalGump( m_Box, true ) ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteEncodedInt( m_Topic.Length ); + + for ( int i = 0; i < m_Topic.Length; i++ ) + writer.Write( (string) m_Topic[i] ); + + writer.Write( m_Yes, true ); + writer.Write( m_No, true ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Topic = new string[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_Topic.Length; i++ ) + m_Topic[i] = reader.ReadString(); + + m_Yes = reader.ReadStrongMobileList(); + m_No = reader.ReadStrongMobileList(); + } + } + + public class BallotBoxAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BallotBoxDeed(); } } + + public BallotBoxAddon() + { + AddComponent( new BallotBox(), 0, 0, 0 ); + } + + public BallotBoxAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BallotBoxDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BallotBoxAddon(); } } + + public override int LabelNumber{ get{ return 1044327; } } // ballot box + + [Constructable] + public BallotBoxDeed() + { + } + + public BallotBoxDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Addons/BaseAddon.cs b/Scripts/Items/Addons/BaseAddon.cs new file mode 100644 index 0000000..03808cb --- /dev/null +++ b/Scripts/Items/Addons/BaseAddon.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Regions; + +namespace Server.Items +{ + public enum AddonFitResult + { + Valid, + Blocked, + NotInHouse, + DoorTooClose, + NoWall, + DoorsNotClosed + } + + public interface IAddon + { + Item Deed{ get; } + + bool CouldFit( IPoint3D p, Map map ); + } + + public abstract class BaseAddon : Item, IChopable, IAddon + { + #region Mondain's Legacy + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set + { + if (m_Resource != value) + { + m_Resource = value; + Hue = CraftResources.GetHue(m_Resource); + + InvalidateProperties(); + } + } + } + #endregion + + private List m_Components; + + public void AddComponent( AddonComponent c, int x, int y, int z ) + { + if ( Deleted ) + return; + + m_Components.Add( c ); + + c.Addon = this; + c.Offset = new Point3D( x, y, z ); + c.MoveToWorld( new Point3D( X + x, Y + y, Z + z ), Map ); + } + + public BaseAddon() : base( 1 ) + { + Movable = false; + Visible = false; + + m_Components = new List(); + } + + public virtual bool RetainDeedHue{ get{ return false; } } + + public virtual void OnChop( Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsOwner( from ) && house.Addons.Contains( this ) ) + { + Effects.PlaySound( GetWorldLocation(), Map, 0x3B3 ); + from.SendLocalizedMessage( 500461 ); // You destroy the item. + + int hue = 0; + + if ( RetainDeedHue ) + { + for ( int i = 0; hue == 0 && i < m_Components.Count; ++i ) + { + AddonComponent c = m_Components[i]; + + if ( c.Hue != 0 ) + hue = c.Hue; + } + } + + Delete(); + + house.Addons.Remove( this ); + + BaseAddonDeed deed = Deed; + + if ( deed != null ) + { + if ( RetainDeedHue ) + deed.Hue = hue; + + from.AddToBackpack( deed ); + } + } + } + + public virtual BaseAddonDeed Deed{ get{ return null; } } + + Item IAddon.Deed + { + get{ return this.Deed; } + } + + public List Components + { + get + { + return m_Components; + } + } + + public BaseAddon( Serial serial ) : base( serial ) + { + } + + public bool CouldFit( IPoint3D p, Map map ) + { + BaseHouse h = null; + return ( CouldFit( p, map, null, ref h ) == AddonFitResult.Valid ); + } + + public virtual AddonFitResult CouldFit( IPoint3D p, Map map, Mobile from, ref BaseHouse house ) + { + if ( Deleted ) + return AddonFitResult.Blocked; + + foreach ( AddonComponent c in m_Components ) + { + Point3D p3D = new Point3D( p.X + c.Offset.X, p.Y + c.Offset.Y, p.Z + c.Offset.Z ); + + if ( !map.CanFit( p3D.X, p3D.Y, p3D.Z, c.ItemData.Height, false, true, ( c.Z == 0 ) ) ) + return AddonFitResult.Blocked; + else if ( !CheckHouse( from, p3D, map, c.ItemData.Height, ref house ) ) + return AddonFitResult.NotInHouse; + + if ( c.NeedsWall ) + { + Point3D wall = c.WallPosition; + + if ( !IsWall( p3D.X + wall.X, p3D.Y + wall.Y, p3D.Z + wall.Z, map ) ) + return AddonFitResult.NoWall; + } + } + + ArrayList doors = house.Doors; + + for ( int i = 0; i < doors.Count; ++i ) + { + BaseDoor door = doors[i] as BaseDoor; + + Point3D doorLoc = door.GetWorldLocation(); + int doorHeight = door.ItemData.CalcHeight; + + foreach ( AddonComponent c in m_Components ) + { + Point3D addonLoc = new Point3D( p.X + c.Offset.X, p.Y + c.Offset.Y, p.Z + c.Offset.Z ); + int addonHeight = c.ItemData.CalcHeight; + + if ( Utility.InRange( doorLoc, addonLoc, 1 ) && (addonLoc.Z == doorLoc.Z || ((addonLoc.Z + addonHeight) > doorLoc.Z && (doorLoc.Z + doorHeight) > addonLoc.Z)) ) + return AddonFitResult.DoorTooClose; + } + } + + return AddonFitResult.Valid; + } + + public static bool CheckHouse( Mobile from, Point3D p, Map map, int height, ref BaseHouse house ) + { + house = BaseHouse.FindHouseAt( p, map, height ); + + if (house == null || (from != null && !house.IsOwner(from))) + return false; + + return true; + } + + public static bool IsWall( int x, int y, int z, Map map ) + { + if ( map == null ) + return false; + + StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y, true ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + if ( (id.Flags & TileFlag.Wall) != 0 && (z + 16) > t.Z && (t.Z + t.Height) > z ) + return true; + } + + return false; + } + + public virtual void OnComponentLoaded( AddonComponent c ) + { + } + + public virtual void OnComponentUsed( AddonComponent c, Mobile from ) + { + } + + public override void OnLocationChange( Point3D oldLoc ) + { + if ( Deleted ) + return; + + foreach ( AddonComponent c in m_Components ) + c.Location = new Point3D( X + c.Offset.X, Y + c.Offset.Y, Z + c.Offset.Z ); + } + + public override void OnMapChange() + { + if ( Deleted ) + return; + + foreach ( AddonComponent c in m_Components ) + c.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + foreach ( AddonComponent c in m_Components ) + c.Delete(); + } + + public virtual bool ShareHue{ get{ return true; } } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get + { + return base.Hue; + } + set + { + if ( base.Hue != value ) + { + base.Hue = value; + + if ( !Deleted && this.ShareHue && m_Components != null ) + { + foreach ( AddonComponent c in m_Components ) + c.Hue = value; + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.WriteItemList( m_Components ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Components = reader.ReadStrongItemList(); + break; + } + } + + if ( version < 1 && Weight == 0 ) + Weight = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/BaseAddonContainer.cs b/Scripts/Items/Addons/BaseAddonContainer.cs new file mode 100644 index 0000000..21494a2 --- /dev/null +++ b/Scripts/Items/Addons/BaseAddonContainer.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Regions; + +namespace Server.Items +{ + public abstract class BaseAddonContainer : BaseContainer, IChopable, IAddon + { + public override bool DisplayWeight { get { return false; } } + + [Hue, CommandProperty(AccessLevel.GameMaster)] + public override int Hue + { + get + { + return base.Hue; + } + set + { + if (base.Hue != value) + { + base.Hue = value; + + if (!Deleted && this.ShareHue && m_Components != null) + { + Hue = value; + + foreach (AddonContainerComponent c in m_Components) + c.Hue = value; + } + } + } + } + + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set + { + if (m_Resource != value) + { + m_Resource = value; + Hue = CraftResources.GetHue(m_Resource); + + InvalidateProperties(); + } + } + } + + Item IAddon.Deed + { + get { return this.Deed; } + } + + public virtual bool RetainDeedHue { get { return false; } } + public virtual bool NeedsWall { get { return false; } } + public virtual bool ShareHue { get { return true; } } + public virtual Point3D WallPosition { get { return Point3D.Zero; } } + public virtual BaseAddonContainerDeed Deed { get { return null; } } + + private List m_Components; + + public List Components + { + get { return m_Components; } + } + + public BaseAddonContainer(int itemID) + : base(itemID) + { + AddonComponent.ApplyLightTo(this); + + m_Components = new List(); + } + + public BaseAddonContainer(Serial serial) + : base(serial) + { + } + + public override void OnLocationChange(Point3D oldLoc) + { + base.OnLocationChange(oldLoc); + + if (Deleted) + return; + + foreach (AddonContainerComponent c in m_Components) + c.Location = new Point3D(X + c.Offset.X, Y + c.Offset.Y, Z + c.Offset.Z); + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if (Deleted) + return; + + foreach (AddonContainerComponent c in m_Components) + c.Map = Map; + } + + public override void OnDelete() + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house != null) + house.Addons.Remove(this); + + base.OnDelete(); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + list.Add(CraftResources.GetLocalizationNumber(m_Resource)); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + foreach (AddonContainerComponent c in m_Components) + c.Delete(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.WriteItemList(m_Components); + writer.Write((int)m_Resource); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Components = reader.ReadStrongItemList(); + m_Resource = (CraftResource)reader.ReadInt(); + + AddonComponent.ApplyLightTo(this); + } + + public virtual void DropItemsToGround() + { + for (int i = Items.Count - 1; i >= 0; i--) + Items[i].MoveToWorld(Location); + } + + public void AddComponent(AddonContainerComponent c, int x, int y, int z) + { + if (Deleted) + return; + + m_Components.Add(c); + + c.Addon = this; + c.Offset = new Point3D(x, y, z); + c.MoveToWorld(new Point3D(X + x, Y + y, Z + z), Map); + } + + public AddonFitResult CouldFit(IPoint3D p, Map map, Mobile from, ref BaseHouse house) + { + if (Deleted) + return AddonFitResult.Blocked; + + foreach (AddonContainerComponent c in m_Components) + { + Point3D p3D = new Point3D(p.X + c.Offset.X, p.Y + c.Offset.Y, p.Z + c.Offset.Z); + + if (!map.CanFit(p3D.X, p3D.Y, p3D.Z, c.ItemData.Height, false, true, (c.Z == 0))) + return AddonFitResult.Blocked; + else if (!BaseAddon.CheckHouse(from, p3D, map, c.ItemData.Height, ref house)) + return AddonFitResult.NotInHouse; + + if (c.NeedsWall) + { + Point3D wall = c.WallPosition; + + if (!BaseAddon.IsWall(p3D.X + wall.X, p3D.Y + wall.Y, p3D.Z + wall.Z, map)) + return AddonFitResult.NoWall; + } + } + + Point3D p3 = new Point3D(p.X, p.Y, p.Z); + + if (!map.CanFit(p3.X, p3.Y, p3.Z, ItemData.Height, false, true, (Z == 0))) + return AddonFitResult.Blocked; + else if (!BaseAddon.CheckHouse(from, p3, map, ItemData.Height, ref house)) + return AddonFitResult.NotInHouse; + + if (NeedsWall) + { + Point3D wall = WallPosition; + + if (!BaseAddon.IsWall(p3.X + wall.X, p3.Y + wall.Y, p3.Z + wall.Z, map)) + return AddonFitResult.NoWall; + } + + if (house != null) + { + ArrayList doors = house.Doors; + + for (int i = 0; i < doors.Count; ++i) + { + BaseDoor door = doors[i] as BaseDoor; + + if (door != null && door.Open) + return AddonFitResult.DoorsNotClosed; + + Point3D doorLoc = door.GetWorldLocation(); + int doorHeight = door.ItemData.CalcHeight; + + foreach (AddonContainerComponent c in m_Components) + { + Point3D addonLoc = new Point3D(p.X + c.Offset.X, p.Y + c.Offset.Y, p.Z + c.Offset.Z); + int addonHeight = c.ItemData.CalcHeight; + + if (Utility.InRange(doorLoc, addonLoc, 1) && (addonLoc.Z == doorLoc.Z || ((addonLoc.Z + addonHeight) > doorLoc.Z && (doorLoc.Z + doorHeight) > addonLoc.Z))) + return AddonFitResult.DoorTooClose; + } + + Point3D addonLo = new Point3D(p.X, p.Y, p.Z); + int addonHeigh = ItemData.CalcHeight; + + if (Utility.InRange(doorLoc, addonLo, 1) && (addonLo.Z == doorLoc.Z || ((addonLo.Z + addonHeigh) > doorLoc.Z && (doorLoc.Z + doorHeight) > addonLo.Z))) + return AddonFitResult.DoorTooClose; + } + } + + return AddonFitResult.Valid; + } + + public bool CouldFit(IPoint3D p, Map map) + { + BaseHouse house = null; + + return (CouldFit(p, map, null, ref house) == AddonFitResult.Valid); + } + + public virtual void OnChop(Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house != null && house.IsOwner(from)) + { + if (!IsSecure) + { + Effects.PlaySound(GetWorldLocation(), Map, 0x3B3); + from.SendLocalizedMessage(500461); // You destroy the item. + + int hue = 0; + + if (RetainDeedHue) + { + for (int i = 0; hue == 0 && i < m_Components.Count; ++i) + { + AddonContainerComponent c = m_Components[i]; + + if (c.Hue != 0) + hue = c.Hue; + } + } + + DropItemsToGround(); + + Delete(); + + house.Addons.Remove(this); + + BaseAddonContainerDeed deed = Deed; + + if (deed != null) + { + deed.Resource = Resource; + + if (RetainDeedHue) + deed.Hue = hue; + + from.AddToBackpack(deed); + } + } + else + from.SendLocalizedMessage(1074870); // This item must be unlocked/unsecured before re-deeding it. + } + } + + public virtual void OnComponentLoaded(AddonContainerComponent c) + { + } + + public virtual void OnComponentUsed(AddonContainerComponent c, Mobile from) + { + } + } +} diff --git a/Scripts/Items/Addons/BaseAddonContainerDeed.cs b/Scripts/Items/Addons/BaseAddonContainerDeed.cs new file mode 100644 index 0000000..549af99 --- /dev/null +++ b/Scripts/Items/Addons/BaseAddonContainerDeed.cs @@ -0,0 +1,165 @@ +using System; + +using Server; +using Server.Multis; +using Server.Targeting; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x14F0, 0x14EF )] + public abstract class BaseAddonContainerDeed : Item, ICraftable + { + public abstract BaseAddonContainer Addon{ get; } + + private CraftResource m_Resource; + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get{ return m_Resource; } + set + { + if ( m_Resource != value ) + { + m_Resource = value; + Hue = CraftResources.GetHue( m_Resource ); + + InvalidateProperties(); + } + } + } + + public BaseAddonContainerDeed() : base( 0x14F0 ) + { + Weight = 1.0; + + if ( !Core.AOS ) + LootType = LootType.Newbied; + } + + public BaseAddonContainerDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + // version 1 + writer.Write( (int) m_Resource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + m_Resource = (CraftResource) reader.ReadInt(); + break; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + from.Target = new InternalTarget( this ); + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( !CraftResources.IsStandard( m_Resource ) ) + list.Add( CraftResources.GetLocalizationNumber( m_Resource ) ); + } + + #region ICraftable + public virtual int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Type resourceType = typeRes; + + if ( resourceType == null ) + resourceType = craftItem.Resources.GetAt( 0 ).ItemType; + + Resource = CraftResources.GetFromType( resourceType ); + + CraftContext context = craftSystem.GetContext( from ); + + if ( context != null && context.DoNotColor ) + Hue = 0; + + return quality; + } + #endregion + + private class InternalTarget : Target + { + private BaseAddonContainerDeed m_Deed; + + public InternalTarget( BaseAddonContainerDeed deed ) : base( -1, true, TargetFlags.None ) + { + m_Deed = deed; + + CheckLOS = false; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if ( p == null || map == null || m_Deed.Deleted ) + return; + + if ( m_Deed.IsChildOf( from.Backpack ) ) + { + BaseAddonContainer addon = m_Deed.Addon; + addon.Resource = m_Deed.Resource; + + Server.Spells.SpellHelper.GetSurfaceTop( ref p ); + + BaseHouse house = null; + + AddonFitResult res = addon.CouldFit( p, map, from, ref house ); + + if ( res == AddonFitResult.Valid ) + addon.MoveToWorld( new Point3D( p ), map ); + else if ( res == AddonFitResult.Blocked ) + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + else if ( res == AddonFitResult.NotInHouse ) + from.SendLocalizedMessage( 500274 ); // You can only place this in a house that you own! + else if ( res == AddonFitResult.DoorsNotClosed ) + from.SendMessage( "You must close all house doors before placing this." ); + else if ( res == AddonFitResult.DoorTooClose ) + from.SendLocalizedMessage( 500271 ); // You cannot build near the door. + else if ( res == AddonFitResult.NoWall ) + from.SendLocalizedMessage( 500268 ); // This object needs to be mounted on something. + + if ( res == AddonFitResult.Valid ) + { + m_Deed.Delete(); + house.Addons.Add( addon ); + house.AddSecure( from, addon ); + } + else + { + addon.Delete(); + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + } + } +} diff --git a/Scripts/Items/Addons/BaseAddonDeed.cs b/Scripts/Items/Addons/BaseAddonDeed.cs new file mode 100644 index 0000000..0c6a32b --- /dev/null +++ b/Scripts/Items/Addons/BaseAddonDeed.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Targeting; + +namespace Server.Items +{ + [Flipable( 0x14F0, 0x14EF )] + public abstract class BaseAddonDeed : Item + { + public abstract BaseAddon Addon + { + get; + } + + #region Mondain's Legacy + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set + { + if (m_Resource != value) + { + m_Resource = value; + Hue = CraftResources.GetHue(m_Resource); + + InvalidateProperties(); + } + } + } + #endregion + + public BaseAddonDeed() : base( 0x14F0 ) + { + Weight = 1.0; + + if ( !Core.AOS ) + LootType = LootType.Newbied; + } + + public BaseAddonDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 0.0 ) + Weight = 1.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + from.Target = new InternalTarget( this ); + else + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + + private class InternalTarget : Target + { + private BaseAddonDeed m_Deed; + + public InternalTarget( BaseAddonDeed deed ) : base( -1, true, TargetFlags.None ) + { + m_Deed = deed; + + CheckLOS = false; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if ( p == null || map == null || m_Deed.Deleted ) + return; + + if ( m_Deed.IsChildOf( from.Backpack ) ) + { + BaseAddon addon = m_Deed.Addon; + + Server.Spells.SpellHelper.GetSurfaceTop( ref p ); + + BaseHouse house = null; + + AddonFitResult res = addon.CouldFit( p, map, from, ref house ); + + if ( res == AddonFitResult.Valid ) + addon.MoveToWorld( new Point3D( p ), map ); + else if ( res == AddonFitResult.Blocked ) + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + else if ( res == AddonFitResult.NotInHouse ) + from.SendLocalizedMessage( 500274 ); // You can only place this in a house that you own! + else if ( res == AddonFitResult.DoorTooClose ) + from.SendLocalizedMessage( 500271 ); // You cannot build near the door. + else if ( res == AddonFitResult.NoWall ) + from.SendLocalizedMessage( 500268 ); // This object needs to be mounted on something. + + if ( res == AddonFitResult.Valid ) + { + m_Deed.Delete(); + house.Addons.Add( addon ); + } + else + { + addon.Delete(); + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/BearRugs.cs b/Scripts/Items/Addons/BearRugs.cs new file mode 100644 index 0000000..30d4d59 --- /dev/null +++ b/Scripts/Items/Addons/BearRugs.cs @@ -0,0 +1,269 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BrownBearRugEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BrownBearRugEastDeed(); } } + + [Constructable] + public BrownBearRugEastAddon() + { + AddComponent( new AddonComponent( 0x1E40 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E41 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E42 ), 1,-1, 0 ); + AddComponent( new AddonComponent( 0x1E43 ), 0,-1, 0 ); + AddComponent( new AddonComponent( 0x1E44 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1E45 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1E46 ),-1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E47 ),-1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E48 ),-1,-1, 0 ); + } + + public BrownBearRugEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrownBearRugEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BrownBearRugEastAddon(); } } + public override int LabelNumber{ get{ return 1049397; } } // a brown bear rug deed facing east + + [Constructable] + public BrownBearRugEastDeed() + { + } + + public BrownBearRugEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrownBearRugSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BrownBearRugSouthDeed(); } } + + [Constructable] + public BrownBearRugSouthAddon() + { + AddComponent( new AddonComponent( 0x1E36 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E37 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1E38 ),-1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E39 ),-1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E3A ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1E3B ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E3C ), 1,-1, 0 ); + AddComponent( new AddonComponent( 0x1E3D ), 0,-1, 0 ); + AddComponent( new AddonComponent( 0x1E3E ),-1,-1, 0 ); + } + + public BrownBearRugSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrownBearRugSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BrownBearRugSouthAddon(); } } + public override int LabelNumber{ get{ return 1049398; } } // a brown bear rug deed facing south + + [Constructable] + public BrownBearRugSouthDeed() + { + } + + public BrownBearRugSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PolarBearRugEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new PolarBearRugEastDeed(); } } + + [Constructable] + public PolarBearRugEastAddon() + { + AddComponent( new AddonComponent( 0x1E53 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E54 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E55 ), 1,-1, 0 ); + AddComponent( new AddonComponent( 0x1E56 ), 0,-1, 0 ); + AddComponent( new AddonComponent( 0x1E57 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1E58 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1E59 ),-1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E5A ),-1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E5B ),-1,-1, 0 ); + } + + public PolarBearRugEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PolarBearRugEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new PolarBearRugEastAddon(); } } + public override int LabelNumber{ get{ return 1049399; } } // a polar bear rug deed facing east + + [Constructable] + public PolarBearRugEastDeed() + { + } + + public PolarBearRugEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PolarBearRugSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new PolarBearRugSouthDeed(); } } + + [Constructable] + public PolarBearRugSouthAddon() + { + AddComponent( new AddonComponent( 0x1E49 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E4A ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1E4B ),-1, 1, 0 ); + AddComponent( new AddonComponent( 0x1E4C ),-1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E4D ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1E4E ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1E4F ), 1,-1, 0 ); + AddComponent( new AddonComponent( 0x1E50 ), 0,-1, 0 ); + AddComponent( new AddonComponent( 0x1E51 ),-1,-1, 0 ); + } + + public PolarBearRugSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PolarBearRugSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new PolarBearRugSouthAddon(); } } + public override int LabelNumber{ get{ return 1049400; } } // a polar bear rug deed facing south + + [Constructable] + public PolarBearRugSouthDeed() + { + } + + public PolarBearRugSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/BloodPentagram.cs b/Scripts/Items/Addons/BloodPentagram.cs new file mode 100644 index 0000000..3223584 --- /dev/null +++ b/Scripts/Items/Addons/BloodPentagram.cs @@ -0,0 +1,70 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BloodPentagram : BaseAddon + { + [Constructable] + public BloodPentagram () + { + AddComponent( new AddonComponent( 0x1CF9 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1CF8 ), 0, 2, 0 ); + AddComponent( new AddonComponent( 0x1CF7 ), 0, 3, 0 ); + AddComponent( new AddonComponent( 0x1CF6 ), 0, 4, 0 ); + AddComponent( new AddonComponent( 0x1CF5 ), 0, 5, 0 ); + + AddComponent( new AddonComponent( 0x1CFB ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1CFA ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1D09 ), 1, 2, 0 ); + AddComponent( new AddonComponent( 0x1D08 ), 1, 3, 0 ); + AddComponent( new AddonComponent( 0x1D07 ), 1, 4, 0 ); + AddComponent( new AddonComponent( 0x1CF4 ), 1, 5, 0 ); + + AddComponent( new AddonComponent( 0x1CFC ), 2, 0, 0 ); + AddComponent( new AddonComponent( 0x1D0A ), 2, 1, 0 ); + AddComponent( new AddonComponent( 0x1D11 ), 2, 2, 0 ); + AddComponent( new AddonComponent( 0x1D10 ), 2, 3, 0 ); + AddComponent( new AddonComponent( 0x1D06 ), 2, 4, 0 ); + AddComponent( new AddonComponent( 0x1CF3 ), 2, 5, 0 ); + + AddComponent( new AddonComponent( 0x1CFD ), 3, 0, 0 ); + AddComponent( new AddonComponent( 0x1D0B ), 3, 1, 0 ); + AddComponent( new AddonComponent( 0x1D12 ), 3, 2, 0 ); + AddComponent( new AddonComponent( 0x1D0F ), 3, 3, 0 ); + AddComponent( new AddonComponent( 0x1D05 ), 3, 4, 0 ); + AddComponent( new AddonComponent( 0x1CF2 ), 3, 5, 0 ); + + AddComponent( new AddonComponent( 0x1CFE ), 4, 0, 0 ); + AddComponent( new AddonComponent( 0x1D0C ), 4, 1, 0 ); + AddComponent( new AddonComponent( 0x1D0D ), 4, 2, 0 ); + AddComponent( new AddonComponent( 0x1D0E ), 4, 3, 0 ); + AddComponent( new AddonComponent( 0x1D04 ), 4, 4, 0 ); + AddComponent( new AddonComponent( 0x1CF1 ), 4, 5, 0 ); + + AddComponent( new AddonComponent( 0x1CFF ), 5, 0, 0 ); + AddComponent( new AddonComponent( 0x1D00 ), 5, 1, 0 ); + AddComponent( new AddonComponent( 0x1D01 ), 5, 2, 0 ); + AddComponent( new AddonComponent( 0x1D02 ), 5, 3, 0 ); + AddComponent( new AddonComponent( 0x1D03 ), 5, 4, 0 ); + } + + public BloodPentagram( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/DartBoard.cs b/Scripts/Items/Addons/DartBoard.cs new file mode 100644 index 0000000..a02732e --- /dev/null +++ b/Scripts/Items/Addons/DartBoard.cs @@ -0,0 +1,218 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class DartBoard : AddonComponent + { + public override bool NeedsWall{ get{ return true; } } + public override Point3D WallPosition{ get{ return this.East ? new Point3D( -1, 0, 0 ) : new Point3D( 0, -1, 0 ); } } + + public bool East{ get{ return this.ItemID == 0x1E2F; } } + + [Constructable] + public DartBoard() : this( true ) + { + } + + [Constructable] + public DartBoard( bool east ) : base( east ? 0x1E2F : 0x1E2E ) + { + } + + public DartBoard( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + Direction dir; + if ( from.Location != this.Location ) + dir = from.GetDirectionTo( this ); + else if ( this.East ) + dir = Direction.West; + else + dir = Direction.North; + + from.Direction = dir; + + bool canThrow = true; + + if ( !from.InRange( this, 4 ) || !from.InLOS( this ) ) + canThrow = false; + else if ( this.East ) + canThrow = ( dir == Direction.Left || dir == Direction.West || dir == Direction.Up ); + else + canThrow = ( dir == Direction.Up || dir == Direction.North || dir == Direction.Right ); + + if ( canThrow ) + Throw( from ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public void Throw( Mobile from ) + { + BaseKnife knife = from.Weapon as BaseKnife; + + if ( knife == null ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500751 ); // Try holding a knife... + return; + } + + from.Animate( from.Mounted ? 26 : 9, 7, 1, true, false, 0 ); + from.MovingEffect( this, knife.ItemID, 7, 1, false, false ); + from.PlaySound( 0x238 ); + + double rand = Utility.RandomDouble(); + + int message; + if ( rand < 0.05 ) + message = 500752; // BULLSEYE! 50 Points! + else if ( rand < 0.20 ) + message = 500753; // Just missed the center! 20 points. + else if ( rand < 0.45 ) + message = 500754; // 10 point shot. + else if ( rand < 0.70 ) + message = 500755; // 5 pointer. + else if ( rand < 0.85 ) + message = 500756; // 1 point. Bad throw. + else + message = 500757; // Missed. + + PublicOverheadMessage( MessageType.Regular, 0x3B2, message ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DartBoardEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new DartBoardEastDeed(); } } + + public DartBoardEastAddon() + { + AddComponent( new DartBoard( true ), 0, 0, 0 ); + } + + public DartBoardEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DartBoardEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new DartBoardEastAddon(); } } + + public override int LabelNumber{ get{ return 1044326; } } // dartboard (east) + + [Constructable] + public DartBoardEastDeed() + { + } + + public DartBoardEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DartBoardSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new DartBoardSouthDeed(); } } + + public DartBoardSouthAddon() + { + AddComponent( new DartBoard( false ), 0, 0, 0 ); + } + + public DartBoardSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DartBoardSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new DartBoardSouthAddon(); } } + + public override int LabelNumber{ get{ return 1044325; } } // dartboard (south) + + [Constructable] + public DartBoardSouthDeed() + { + } + + public DartBoardSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenBedEastAddon.cs b/Scripts/Items/Addons/ElvenBedEastAddon.cs new file mode 100644 index 0000000..368037d --- /dev/null +++ b/Scripts/Items/Addons/ElvenBedEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenBedEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenBedEastDeed(); } } + + [Constructable] + public ElvenBedEastAddon() + { + AddComponent( new AddonComponent( 0x304D ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x304C ), 1, 0, 0 ); + } + + public ElvenBedEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenBedEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenBedEastAddon(); } } + public override int LabelNumber{ get{ return 1072861; } } // elven bed (east) + + [Constructable] + public ElvenBedEastDeed() + { + } + + public ElvenBedEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenBedSouthAddon.cs b/Scripts/Items/Addons/ElvenBedSouthAddon.cs new file mode 100644 index 0000000..70148f8 --- /dev/null +++ b/Scripts/Items/Addons/ElvenBedSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenBedSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenBedSouthDeed(); } } + + [Constructable] + public ElvenBedSouthAddon() + { + AddComponent( new AddonComponent( 0x3050 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3051 ), 0, -1, 0 ); + } + + public ElvenBedSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenBedSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenBedSouthAddon(); } } + public override int LabelNumber{ get{ return 1072860; } } // elven bed (south) + + [Constructable] + public ElvenBedSouthDeed() + { + } + + public ElvenBedSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenDresserEastAddon.cs b/Scripts/Items/Addons/ElvenDresserEastAddon.cs new file mode 100644 index 0000000..e349f9b --- /dev/null +++ b/Scripts/Items/Addons/ElvenDresserEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenDresserEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenDresserEastDeed(); } } + + [Constructable] + public ElvenDresserEastAddon() + { + AddComponent( new AddonComponent( 0x30E4 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x30E3 ), 0, -1, 0 ); + } + + public ElvenDresserEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenDresserEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenDresserEastAddon(); } } + public override int LabelNumber{ get{ return 1073388; } } // elven dresser (east) + + [Constructable] + public ElvenDresserEastDeed() + { + } + + public ElvenDresserEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenDresserSouthAddon.cs b/Scripts/Items/Addons/ElvenDresserSouthAddon.cs new file mode 100644 index 0000000..313a707 --- /dev/null +++ b/Scripts/Items/Addons/ElvenDresserSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenDresserSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenDresserSouthDeed(); } } + + [Constructable] + public ElvenDresserSouthAddon() + { + AddComponent( new AddonComponent( 0x30E5 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x30E6 ), 1, 0, 0 ); + } + + public ElvenDresserSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenDresserSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenDresserSouthAddon(); } } + public override int LabelNumber{ get{ return 1072864; } } // elven dresser (south) + + [Constructable] + public ElvenDresserSouthDeed() + { + } + + public ElvenDresserSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenForgeAddon.cs b/Scripts/Items/Addons/ElvenForgeAddon.cs new file mode 100644 index 0000000..4543dc1 --- /dev/null +++ b/Scripts/Items/Addons/ElvenForgeAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenForgeAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenForgeDeed(); } } + + [Constructable] + public ElvenForgeAddon() + { + AddComponent( new AddonComponent( 0x2DD8 ), 0, 0, 0 ); + } + + public ElvenForgeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenForgeDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenForgeAddon(); } } + public override int LabelNumber{ get{ return 1072875; } } // squirrel statue (east) + + [Constructable] + public ElvenForgeDeed() + { + } + + public ElvenForgeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenLoveseatEastAddon.cs b/Scripts/Items/Addons/ElvenLoveseatEastAddon.cs new file mode 100644 index 0000000..5d32d79 --- /dev/null +++ b/Scripts/Items/Addons/ElvenLoveseatEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenLoveseatEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenLoveseatEastDeed(); } } + + [Constructable] + public ElvenLoveseatEastAddon() + { + AddComponent( new AddonComponent( 0x3089 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3088 ), 1, 0, 0 ); + } + + public ElvenLoveseatEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenLoveseatEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenLoveseatEastAddon(); } } + public override int LabelNumber{ get{ return 1073372; } } // elven loveseat (east) + + [Constructable] + public ElvenLoveseatEastDeed() + { + } + + public ElvenLoveseatEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenLoveseatSouthAddon.cs b/Scripts/Items/Addons/ElvenLoveseatSouthAddon.cs new file mode 100644 index 0000000..995a69a --- /dev/null +++ b/Scripts/Items/Addons/ElvenLoveseatSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenLoveseatSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenLoveseatSouthDeed(); } } + + [Constructable] + public ElvenLoveseatSouthAddon() + { + AddComponent( new AddonComponent( 0x308A ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x308B ), 0, -1, 0 ); + } + + public ElvenLoveseatSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenLoveseatSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenLoveseatSouthAddon(); } } + public override int LabelNumber{ get{ return 1072867; } } // elven loveseat (south) + + [Constructable] + public ElvenLoveseatSouthDeed() + { + } + + public ElvenLoveseatSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs b/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs new file mode 100644 index 0000000..b0dcc3f --- /dev/null +++ b/Scripts/Items/Addons/ElvenSpinningwheelEastAddon.cs @@ -0,0 +1,137 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenSpinningwheelEastAddon : BaseAddon, ISpinningWheel + { + public override BaseAddonDeed Deed{ get{ return new ElvenSpinningwheelEastDeed(); } } + + [Constructable] + public ElvenSpinningwheelEastAddon() + { + AddComponent( new AddonComponent( 0x2DD9 ), 0, 0, 0 ); + } + + public ElvenSpinningwheelEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private Timer m_Timer; + + public override void OnComponentLoaded( AddonComponent c ) + { + switch ( c.ItemID ) + { + case 0x2E3D: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + public bool Spinning{ get{ return m_Timer != null; } } + + public void BeginSpin( SpinCallback callback, Mobile from, int hue ) + { + m_Timer = new SpinTimer( this, callback, from, hue ); + m_Timer.Start(); + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x2DD9: + case 0x101C: + case 0x10A4: ++c.ItemID; break; + } + } + } + + public void EndSpin( SpinCallback callback, Mobile from, int hue ) + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + if ( callback != null ) + callback( this, from, hue ); + } + + private class SpinTimer : Timer + { + private ElvenSpinningwheelEastAddon m_Wheel; + private SpinCallback m_Callback; + private Mobile m_From; + private int m_Hue; + + public SpinTimer( ElvenSpinningwheelEastAddon wheel, SpinCallback callback, Mobile from, int hue ) : base( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Wheel = wheel; + m_Callback = callback; + m_From = from; + m_Hue = hue; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Wheel.EndSpin( m_Callback, m_From, m_Hue ); + } + } + } + + public class ElvenSpinningwheelEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenSpinningwheelEastAddon(); } } + public override int LabelNumber{ get{ return 1073393; } } // elven spinning wheel (east) + + [Constructable] + public ElvenSpinningwheelEastDeed() + { + } + + public ElvenSpinningwheelEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs b/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs new file mode 100644 index 0000000..e2c9416 --- /dev/null +++ b/Scripts/Items/Addons/ElvenSpinningwheelSouthAddon.cs @@ -0,0 +1,139 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenSpinningwheelSouthAddon : BaseAddon, ISpinningWheel + { + public override BaseAddonDeed Deed{ get{ return new ElvenSpinningwheelSouthDeed(); } } + + [Constructable] + public ElvenSpinningwheelSouthAddon() + { + AddComponent( new AddonComponent( 0x2DDA ), 0, 0, 0 ); + } + + public ElvenSpinningwheelSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private Timer m_Timer; + + public override void OnComponentLoaded( AddonComponent c ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + public bool Spinning{ get{ return m_Timer != null; } } + + public void BeginSpin( SpinCallback callback, Mobile from, int hue ) + { + m_Timer = new SpinTimer( this, callback, from, hue ); + m_Timer.Start(); + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1015: + case 0x1019: + case 0x101C: + case 0x10A4: ++c.ItemID; break; + } + } + } + + public void EndSpin( SpinCallback callback, Mobile from, int hue ) + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + if ( callback != null ) + callback( this, from, hue ); + } + + private class SpinTimer : Timer + { + private ElvenSpinningwheelSouthAddon m_Wheel; + private SpinCallback m_Callback; + private Mobile m_From; + private int m_Hue; + + public SpinTimer( ElvenSpinningwheelSouthAddon wheel, SpinCallback callback, Mobile from, int hue ) : base( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Wheel = wheel; + m_Callback = callback; + m_From = from; + m_Hue = hue; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Wheel.EndSpin( m_Callback, m_From, m_Hue ); + } + } + } + + public class ElvenSpinningwheelSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenSpinningwheelSouthAddon(); } } + public override int LabelNumber{ get{ return 1072878; } } // spinning wheel (south) + + [Constructable] + public ElvenSpinningwheelSouthDeed() + { + } + + public ElvenSpinningwheelSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenStoveEastAddon.cs b/Scripts/Items/Addons/ElvenStoveEastAddon.cs new file mode 100644 index 0000000..ec72e35 --- /dev/null +++ b/Scripts/Items/Addons/ElvenStoveEastAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenStoveEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenStoveEastDeed(); } } + + [Constructable] + public ElvenStoveEastAddon() + { + AddComponent( new AddonComponent( 0x2DDB ), 0, 0, 0 ); + } + + public ElvenStoveEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenStoveEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenStoveEastAddon(); } } + public override int LabelNumber{ get{ return 1073395; } } // elven oven (east) + + [Constructable] + public ElvenStoveEastDeed() + { + } + + public ElvenStoveEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenStoveSouthAddon.cs b/Scripts/Items/Addons/ElvenStoveSouthAddon.cs new file mode 100644 index 0000000..66177c1 --- /dev/null +++ b/Scripts/Items/Addons/ElvenStoveSouthAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenStoveSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenStoveSouthDeed(); } } + + [Constructable] + public ElvenStoveSouthAddon() + { + AddComponent( new AddonComponent( 0x2DDC ), 0, 0, 0 ); + } + + public ElvenStoveSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenStoveSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenStoveSouthAddon(); } } + public override int LabelNumber{ get{ return 1073394; } } // elven oven (south) + + [Constructable] + public ElvenStoveSouthDeed() + { + } + + public ElvenStoveSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenWashbasinEastAddon.cs b/Scripts/Items/Addons/ElvenWashbasinEastAddon.cs new file mode 100644 index 0000000..6c12297 --- /dev/null +++ b/Scripts/Items/Addons/ElvenWashbasinEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenWashBasinEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenWashBasinEastDeed(); } } + + [Constructable] + public ElvenWashBasinEastAddon() + { + AddComponent( new AddonComponent( 0x30DF ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x30E0 ), 0, 1, 0 ); + } + + public ElvenWashBasinEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenWashBasinEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenWashBasinEastAddon(); } } + public override int LabelNumber{ get{ return 1073387; } } // elven wash basin (east) + + [Constructable] + public ElvenWashBasinEastDeed() + { + } + + public ElvenWashBasinEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ElvenWashbasinSouthAddon.cs b/Scripts/Items/Addons/ElvenWashbasinSouthAddon.cs new file mode 100644 index 0000000..7ca5b67 --- /dev/null +++ b/Scripts/Items/Addons/ElvenWashbasinSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenWashBasinSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ElvenWashBasinSouthDeed(); } } + + [Constructable] + public ElvenWashBasinSouthAddon() + { + AddComponent( new AddonComponent( 0x30E1 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x30E2 ), 1, 0, 0 ); + } + + public ElvenWashBasinSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenWashBasinSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ElvenWashBasinSouthAddon(); } } + public override int LabelNumber{ get{ return 1072865; } } // elven wash basin (south) + + [Constructable] + public ElvenWashBasinSouthDeed() + { + } + + public ElvenWashBasinSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/FancyElvenTableEastAddon.cs b/Scripts/Items/Addons/FancyElvenTableEastAddon.cs new file mode 100644 index 0000000..7d48d53 --- /dev/null +++ b/Scripts/Items/Addons/FancyElvenTableEastAddon.cs @@ -0,0 +1,65 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FancyElvenTableEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new FancyElvenTableEastDeed(); } } + + [Constructable] + public FancyElvenTableEastAddon() + { + AddComponent( new AddonComponent( 0x3094 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x3093 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3092 ), 1, 0, 0 ); + } + + public FancyElvenTableEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class FancyElvenTableEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new FancyElvenTableEastAddon(); } } + public override int LabelNumber{ get{ return 1073386; } } // hardwood table (east) + + [Constructable] + public FancyElvenTableEastDeed() + { + } + + public FancyElvenTableEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/FancyElvenTableSouthAddon.cs b/Scripts/Items/Addons/FancyElvenTableSouthAddon.cs new file mode 100644 index 0000000..6bf4d9f --- /dev/null +++ b/Scripts/Items/Addons/FancyElvenTableSouthAddon.cs @@ -0,0 +1,65 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FancyElvenTableSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new FancyElvenTableSouthDeed(); } } + + [Constructable] + public FancyElvenTableSouthAddon() + { + AddComponent( new AddonComponent( 0x3095 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x3096 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3097 ), 0, -1, 0 ); + } + + public FancyElvenTableSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class FancyElvenTableSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new FancyElvenTableSouthAddon(); } } + public override int LabelNumber{ get{ return 1073385; } } // hardwood table (south) + + [Constructable] + public FancyElvenTableSouthDeed() + { + } + + public FancyElvenTableSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/FireColumnAddon.cs b/Scripts/Items/Addons/FireColumnAddon.cs new file mode 100644 index 0000000..39e0034 --- /dev/null +++ b/Scripts/Items/Addons/FireColumnAddon.cs @@ -0,0 +1,67 @@ +using System; +using System.Text; +using System.Net; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class FireColumnAddon : BaseAddon + { + public override bool ShareHue + { + get { return false; } + } + + [Constructable] + public FireColumnAddon() + : this( false ) + { + } + + [Constructable] + public FireColumnAddon( bool bloody ) + { + AddComponent( new AddonComponent( 0x3A5 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3A5 ), 0, 0, 5 ); + AddComponent( new AddonComponent( 0x3A5 ), 0, 0, 10 ); + AddComponent( new AddonComponent( 0x3A5 ), 0, 0, 15 ); + + AddComponent( new AddonComponent( 0x19BB ), 0, 0, 21 ); + AddComponent( new AddonComponent( 0x19AB ), 0, 0, 23 ); + + if ( bloody ) + { + AddComponent( new AddonComponent( 0x122B ), -2, 0, 0 ); + AddComponent( new AddonComponent( 0x122E ), 0, -2, 0 ); + AddComponent( new AddonComponent( 0x122D ), -1, 1, 0 ); + AddComponent( new AddonComponent( 0x122F ), 1, -1, 0 ); + AddComponent( new AddonComponent( 0x122D ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x122A ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x122B ), 2, -1, 0 ); + AddComponent( new AddonComponent( 0x122B ), 0, 2, 0 ); + AddComponent( new AddonComponent( 0x122E ), 1, 1, 0 ); + } + } + + public FireColumnAddon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/FlourMillEastAddon.cs b/Scripts/Items/Addons/FlourMillEastAddon.cs new file mode 100644 index 0000000..7b8990d --- /dev/null +++ b/Scripts/Items/Addons/FlourMillEastAddon.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Items +{ + public interface IFlourMill + { + int MaxFlour{ get; } + int CurFlour{ get; set; } + } + + public enum FlourMillStage + { + Empty, + Filled, + Working + } + + public class FlourMillEastAddon : BaseAddon, IFlourMill + { + public override BaseAddonDeed Deed{ get{ return new FlourMillEastDeed(); } } + + private int m_Flour; + private Timer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxFlour + { + get{ return 2; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurFlour + { + get{ return m_Flour; } + set{ m_Flour = Math.Max( 0, Math.Min( value, MaxFlour ) ); UpdateStage(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasFlour + { + get{ return ( m_Flour > 0 ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsFull + { + get{ return ( m_Flour >= MaxFlour ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsWorking + { + get{ return ( m_Timer != null ); } + } + + public void StartWorking( Mobile from ) + { + if ( IsWorking ) + return; + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( FinishWorking_Callback ), from ); + UpdateStage(); + } + + private void FinishWorking_Callback( object state ) + { + if ( m_Timer != null ) + { + m_Timer.Stop(); + m_Timer = null; + } + + Mobile from = state as Mobile; + + if ( from != null && !from.Deleted && !this.Deleted && IsFull ) + { + SackFlour flour = new SackFlour(); + + flour.ItemID = ( Utility.RandomBool() ? 4153 : 4165 ); + + if ( from.PlaceInBackpack( flour ) ) + { + m_Flour = 0; + } + else + { + flour.Delete(); + from.SendLocalizedMessage( 500998 ); // There is not enough room in your backpack! You stop grinding. + } + } + + UpdateStage(); + } + + private static int[][] m_StageTable = new int[][] + { + new int[]{ 0x1920, 0x1921, 0x1925 }, + new int[]{ 0x1922, 0x1923, 0x1926 }, + new int[]{ 0x1924, 0x1924, 0x1928 } + }; + + private int[] FindItemTable( int itemID ) + { + for ( int i = 0; i < m_StageTable.Length; ++i ) + { + int[] itemTable = m_StageTable[i]; + + for ( int j = 0; j < itemTable.Length; ++j ) + { + if ( itemTable[j] == itemID ) + return itemTable; + } + } + + return null; + } + + public void UpdateStage() + { + if ( IsWorking ) + UpdateStage( FlourMillStage.Working ); + else if ( HasFlour ) + UpdateStage( FlourMillStage.Filled ); + else + UpdateStage( FlourMillStage.Empty ); + } + + public void UpdateStage( FlourMillStage stage ) + { + List components = this.Components; + + int[][] stageTable = m_StageTable; + + for ( int i = 0; i < components.Count; ++i ) + { + AddonComponent component = components[i] as AddonComponent; + + if ( component == null ) + continue; + + int[] itemTable = FindItemTable( component.ItemID ); + + if ( itemTable != null ) + component.ItemID = itemTable[(int)stage]; + } + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 4 ) || !from.InLOS( this ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( !IsFull ) + from.SendLocalizedMessage( 500997 ); // You need more wheat to make a sack of flour. + else + StartWorking( from ); + } + + [Constructable] + public FlourMillEastAddon() + { + AddComponent( new AddonComponent( 0x1920 ),-1, 0, 0 ); + AddComponent( new AddonComponent( 0x1922 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1924 ), 1, 0, 0 ); + } + + public FlourMillEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Flour ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Flour = reader.ReadInt(); + break; + } + } + + UpdateStage(); + } + } + + public class FlourMillEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new FlourMillEastAddon(); } } + public override int LabelNumber{ get{ return 1044347; } } // flour mill (east) + + [Constructable] + public FlourMillEastDeed() + { + } + + public FlourMillEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/FlourMillSouthAddon.cs b/Scripts/Items/Addons/FlourMillSouthAddon.cs new file mode 100644 index 0000000..4ff97e0 --- /dev/null +++ b/Scripts/Items/Addons/FlourMillSouthAddon.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Items +{ + public class FlourMillSouthAddon : BaseAddon, IFlourMill + { + public override BaseAddonDeed Deed{ get{ return new FlourMillSouthDeed(); } } + private int m_Flour; + private Timer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxFlour + { + get{ return 2; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurFlour + { + get{ return m_Flour; } + set{ m_Flour = Math.Max( 0, Math.Min( value, MaxFlour ) ); UpdateStage(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasFlour + { + get{ return ( m_Flour > 0 ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsFull + { + get{ return ( m_Flour >= MaxFlour ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsWorking + { + get{ return ( m_Timer != null ); } + } + + public void StartWorking( Mobile from ) + { + if ( IsWorking ) + return; + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( FinishWorking_Callback ), from ); + UpdateStage(); + } + + private void FinishWorking_Callback( object state ) + { + if ( m_Timer != null ) + { + m_Timer.Stop(); + m_Timer = null; + } + + Mobile from = state as Mobile; + + if ( from != null && !from.Deleted && !this.Deleted && IsFull ) + { + SackFlour flour = new SackFlour(); + + flour.ItemID = ( Utility.RandomBool() ? 4153 : 4165 ); + + if ( from.PlaceInBackpack( flour ) ) + { + m_Flour = 0; + } + else + { + flour.Delete(); + from.SendLocalizedMessage( 500998 ); // There is not enough room in your backpack! You stop grinding. + } + } + + UpdateStage(); + } + + private static int[][] m_StageTable = new int[][] + { + new int[]{ 0x192C, 0x192D, 0x1931 }, + new int[]{ 0x192E, 0x192F, 0x1932 }, + new int[]{ 0x1930, 0x1930, 0x1934 } + }; + + private int[] FindItemTable( int itemID ) + { + for ( int i = 0; i < m_StageTable.Length; ++i ) + { + int[] itemTable = m_StageTable[i]; + + for ( int j = 0; j < itemTable.Length; ++j ) + { + if ( itemTable[j] == itemID ) + return itemTable; + } + } + + return null; + } + + public void UpdateStage() + { + if ( IsWorking ) + UpdateStage( FlourMillStage.Working ); + else if ( HasFlour ) + UpdateStage( FlourMillStage.Filled ); + else + UpdateStage( FlourMillStage.Empty ); + } + + public void UpdateStage( FlourMillStage stage ) + { + List components = this.Components; + + int[][] stageTable = m_StageTable; + + for ( int i = 0; i < components.Count; ++i ) + { + AddonComponent component = components[i] as AddonComponent; + + if ( component == null ) + continue; + + int[] itemTable = FindItemTable( component.ItemID ); + + if ( itemTable != null ) + component.ItemID = itemTable[(int)stage]; + } + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 4 ) || !from.InLOS( this ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( !IsFull ) + from.SendLocalizedMessage( 500997 ); // You need more wheat to make a sack of flour. + else + StartWorking( from ); + } + + [Constructable] + public FlourMillSouthAddon() + { + AddComponent( new AddonComponent( 0x192C ), 0,-1, 0 ); + AddComponent( new AddonComponent( 0x192E ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1930 ), 0, 1, 0 ); + } + + public FlourMillSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Flour ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Flour = reader.ReadInt(); + break; + } + } + + UpdateStage(); + } + } + + public class FlourMillSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new FlourMillSouthAddon(); } } + public override int LabelNumber{ get{ return 1044348; } } // flour mill (south) + + [Constructable] + public FlourMillSouthDeed() + { + } + + public FlourMillSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/FlowerTapestries.cs b/Scripts/Items/Addons/FlowerTapestries.cs new file mode 100644 index 0000000..a22aa7d --- /dev/null +++ b/Scripts/Items/Addons/FlowerTapestries.cs @@ -0,0 +1,241 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LightFlowerTapestryEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LightFlowerTapestryEastDeed(); } } + + [Constructable] + public LightFlowerTapestryEastAddon() + { + AddComponent( new AddonComponent( 0xFDC ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xFDB ), 0, 1, 0 ); + } + + public LightFlowerTapestryEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightFlowerTapestryEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LightFlowerTapestryEastAddon(); } } + public override int LabelNumber{ get{ return 1049393; } } // a flower tapestry deed facing east + + [Constructable] + public LightFlowerTapestryEastDeed() + { + } + + public LightFlowerTapestryEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightFlowerTapestrySouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LightFlowerTapestrySouthDeed(); } } + + [Constructable] + public LightFlowerTapestrySouthAddon() + { + AddComponent( new AddonComponent( 0xFD9 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xFDA ), 1, 0, 0 ); + } + + public LightFlowerTapestrySouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightFlowerTapestrySouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LightFlowerTapestrySouthAddon(); } } + public override int LabelNumber{ get{ return 1049394; } } // a flower tapestry deed facing south + + [Constructable] + public LightFlowerTapestrySouthDeed() + { + } + + public LightFlowerTapestrySouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkFlowerTapestryEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new DarkFlowerTapestryEastDeed(); } } + + [Constructable] + public DarkFlowerTapestryEastAddon() + { + AddComponent( new AddonComponent( 0xFE0 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xFDF ), 0, 1, 0 ); + } + + public DarkFlowerTapestryEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkFlowerTapestryEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new DarkFlowerTapestryEastAddon(); } } + public override int LabelNumber{ get{ return 1049395; } } // a dark flower tapestry deed facing east + + [Constructable] + public DarkFlowerTapestryEastDeed() + { + } + + public DarkFlowerTapestryEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkFlowerTapestrySouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new DarkFlowerTapestrySouthDeed(); } } + + [Constructable] + public DarkFlowerTapestrySouthAddon() + { + AddComponent( new AddonComponent( 0xFDD ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xFDE ), 1, 0, 0 ); + } + + public DarkFlowerTapestrySouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkFlowerTapestrySouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new DarkFlowerTapestrySouthAddon(); } } + public override int LabelNumber{ get{ return 1049396; } } // a dark flower tapestry deed facing south + + [Constructable] + public DarkFlowerTapestrySouthDeed() + { + } + + public DarkFlowerTapestrySouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/GiantWebs.cs b/Scripts/Items/Addons/GiantWebs.cs new file mode 100644 index 0000000..55e263e --- /dev/null +++ b/Scripts/Items/Addons/GiantWebs.cs @@ -0,0 +1,207 @@ +using System; +using System.Text; +using System.Net; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class GiantWeb1 : BaseAddon + { + [Constructable] + public GiantWeb1() + { + int itemID = 4280; + int count = 5; + bool leftToRight = false; + + for ( int i = 0; i < count; ++i ) + AddComponent( new AddonComponent( itemID++ ), leftToRight ? i : count - 1 - i, -( leftToRight ? i : count - 1 - i ), 0 ); + } + + public GiantWeb1( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } + + public class GiantWeb2 : BaseAddon + { + [Constructable] + public GiantWeb2() + { + int itemID = 4285; + int count = 5; + bool leftToRight = true; + + for ( int i = 0; i < count; ++i ) + AddComponent( new AddonComponent( itemID++ ), leftToRight ? i : count - 1 - i, -( leftToRight ? i : count - 1 - i ), 0 ); + } + + public GiantWeb2( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } + + public class GiantWeb3 : BaseAddon + { + [Constructable] + public GiantWeb3() + { + int itemID = 4290; + int count = 4; + bool leftToRight = true; + + for ( int i = 0; i < count; ++i ) + AddComponent( new AddonComponent( itemID++ ), leftToRight ? i : count - 1 - i, -( leftToRight ? i : count - 1 - i ), 0 ); + } + + public GiantWeb3( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } + + public class GiantWeb4 : BaseAddon + { + [Constructable] + public GiantWeb4() + { + int itemID = 4294; + int count = 4; + bool leftToRight = false; + + for ( int i = 0; i < count; ++i ) + AddComponent( new AddonComponent( itemID++ ), leftToRight ? i : count - 1 - i, -( leftToRight ? i : count - 1 - i ), 0 ); + } + + public GiantWeb4( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } + + public class GiantWeb5 : BaseAddon + { + [Constructable] + public GiantWeb5() + { + int itemID = 4298; + int count = 4; + bool leftToRight = true; + + for ( int i = 0; i < count; ++i ) + AddComponent( new AddonComponent( itemID++ ), leftToRight ? i : count - 1 - i, -( leftToRight ? i : count - 1 - i ), 0 ); + } + + public GiantWeb5( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } + + public class GiantWeb6 : BaseAddon + { + [Constructable] + public GiantWeb6() + { + int itemID = 4302; + int count = 4; + bool leftToRight = false; + + for ( int i = 0; i < count; ++i ) + AddComponent( new AddonComponent( itemID++ ), leftToRight ? i : count - 1 - i, -( leftToRight ? i : count - 1 - i ), 0 ); + } + + public GiantWeb6( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/GozaMats.cs b/Scripts/Items/Addons/GozaMats.cs new file mode 100644 index 0000000..a34254f --- /dev/null +++ b/Scripts/Items/Addons/GozaMats.cs @@ -0,0 +1,538 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GozaMatEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new GozaMatEastDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public GozaMatEastAddon() : this( 0 ) + { + } + + [Constructable] + public GozaMatEastAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28a4, 1030688 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x28a5, 1030688 ), 0, 0, 0 ); + Hue = hue; + } + + public GozaMatEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GozaMatEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new GozaMatEastAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030404; } } // goza (east) + + [Constructable] + public GozaMatEastDeed() + { + } + + public GozaMatEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GozaMatSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new GozaMatSouthDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public GozaMatSouthAddon() : this( 0 ) + { + } + + [Constructable] + public GozaMatSouthAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28a6, 1030688 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0x28a7, 1030688 ), 0, 0, 0 ); + Hue = hue; + } + + public GozaMatSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GozaMatSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new GozaMatSouthAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030405; } } // goza (south) + + [Constructable] + public GozaMatSouthDeed() + { + } + + public GozaMatSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SquareGozaMatEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SquareGozaMatEastDeed(); } } + public override int LabelNumber{ get{ return 1030688; } } // goza mat + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public SquareGozaMatEastAddon() : this( 0 ) + { + } + + [Constructable] + public SquareGozaMatEastAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28a8, 1030688 ), 0, 0, 0 ); + Hue = hue; + } + + public SquareGozaMatEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SquareGozaMatEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SquareGozaMatEastAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030407; } } // square goza (east) + + [Constructable] + public SquareGozaMatEastDeed() + { + } + + public SquareGozaMatEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SquareGozaMatSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SquareGozaMatSouthDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public SquareGozaMatSouthAddon() : this( 0 ) + { + } + + [Constructable] + public SquareGozaMatSouthAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28a9, 1030688 ), 0, 0, 0 ); + Hue = hue; + } + + public SquareGozaMatSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SquareGozaMatSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SquareGozaMatSouthAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030406; } } // square goza (south) + + + [Constructable] + public SquareGozaMatSouthDeed() + { + } + + public SquareGozaMatSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrocadeGozaMatEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BrocadeGozaMatEastDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public BrocadeGozaMatEastAddon() : this( 0 ) + { + } + + [Constructable] + public BrocadeGozaMatEastAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28AB, 1030688 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x28AA, 1030688 ), 1, 0, 0 ); + Hue = hue; + } + + public BrocadeGozaMatEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrocadeGozaMatEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BrocadeGozaMatEastAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030408; } } // brocade goza (east) + + [Constructable] + public BrocadeGozaMatEastDeed() + { + } + + public BrocadeGozaMatEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + public class BrocadeGozaMatSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BrocadeGozaMatSouthDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public BrocadeGozaMatSouthAddon() : this( 0 ) + { + } + + [Constructable] + public BrocadeGozaMatSouthAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28AD, 1030688 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x28AC, 1030688 ), 0, 1, 0 ); + Hue = hue; + } + + public BrocadeGozaMatSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrocadeGozaMatSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BrocadeGozaMatSouthAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030409; } } // brocade goza (south) + + [Constructable] + public BrocadeGozaMatSouthDeed() + { + } + + public BrocadeGozaMatSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + public class BrocadeSquareGozaMatEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BrocadeSquareGozaMatEastDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public BrocadeSquareGozaMatEastAddon() : this( 0 ) + { + } + + [Constructable] + public BrocadeSquareGozaMatEastAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28AE, 1030688 ), 0, 0, 0 ); + Hue = hue; + } + + public BrocadeSquareGozaMatEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrocadeSquareGozaMatEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BrocadeSquareGozaMatEastAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030411; } } // brocade square goza (east) + + [Constructable] + public BrocadeSquareGozaMatEastDeed() + { + } + + public BrocadeSquareGozaMatEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrocadeSquareGozaMatSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new BrocadeSquareGozaMatSouthDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public BrocadeSquareGozaMatSouthAddon() : this( 0 ) + { + } + + [Constructable] + public BrocadeSquareGozaMatSouthAddon( int hue ) + { + AddComponent( new LocalizedAddonComponent( 0x28AF, 1030688 ), 0, 0, 0 ); + Hue = hue; + } + + public BrocadeSquareGozaMatSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrocadeSquareGozaMatSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new BrocadeSquareGozaMatSouthAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1030410; } } // brocade square goza (south) + + + [Constructable] + public BrocadeSquareGozaMatSouthDeed() + { + } + + public BrocadeSquareGozaMatSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/GrayBrickFireplaceEastAddon.cs b/Scripts/Items/Addons/GrayBrickFireplaceEastAddon.cs new file mode 100644 index 0000000..77afbb3 --- /dev/null +++ b/Scripts/Items/Addons/GrayBrickFireplaceEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GrayBrickFireplaceEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new GrayBrickFireplaceEastDeed(); } } + + [Constructable] + public GrayBrickFireplaceEastAddon() + { + AddComponent( new AddonComponent( 0x93D ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x937 ), 0, 1, 0 ); + } + + public GrayBrickFireplaceEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GrayBrickFireplaceEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new GrayBrickFireplaceEastAddon(); } } + public override int LabelNumber{ get{ return 1061846; } } // grey brick fireplace (east) + + [Constructable] + public GrayBrickFireplaceEastDeed() + { + } + + public GrayBrickFireplaceEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/GrayBrickFireplaceSouthAddon.cs b/Scripts/Items/Addons/GrayBrickFireplaceSouthAddon.cs new file mode 100644 index 0000000..0246378 --- /dev/null +++ b/Scripts/Items/Addons/GrayBrickFireplaceSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GrayBrickFireplaceSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new GrayBrickFireplaceSouthDeed(); } } + + [Constructable] + public GrayBrickFireplaceSouthAddon() + { + AddComponent( new AddonComponent( 0x94B ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x945 ), 0, 0, 0 ); + } + + public GrayBrickFireplaceSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GrayBrickFireplaceSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new GrayBrickFireplaceSouthAddon(); } } + public override int LabelNumber{ get{ return 1061847; } } // grey brick fireplace (south) + + [Constructable] + public GrayBrickFireplaceSouthDeed() + { + } + + public GrayBrickFireplaceSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/JackOLantern.cs b/Scripts/Items/Addons/JackOLantern.cs new file mode 100644 index 0000000..a78af03 --- /dev/null +++ b/Scripts/Items/Addons/JackOLantern.cs @@ -0,0 +1,101 @@ +using System; +using System.Text; +using System.Net; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class JackOLantern : BaseAddon + { + public override bool ShareHue + { + get { return false; } + } + + private AddonComponent GetComponent( int itemID, int hue ) + { + AddonComponent ac = new AddonComponent( itemID ); + + ac.Hue = hue; + ac.Name = "jack-o-lantern"; + + return ac; + } + + [Constructable] + public JackOLantern() + : this( 1 > Utility.Random( 2 ) ) + { + } + + [Constructable] + public JackOLantern( bool south ) + { + AddComponent( new AddonComponent( 5703 ), 0, 0, +0 ); + + int hue = 1161; + //( 1 > Utility.Random( 5 ) ? 2118 : 1161 ); + + if ( !south ) + { + AddComponent( GetComponent( 3178, 0000 ), 0, 0, -1 ); + AddComponent( GetComponent( 3883, hue ), 0, 0, +1 ); + AddComponent( GetComponent( 3862, hue ), 0, 0, +0 ); + } + else + { + AddComponent( GetComponent( 3179, 0000 ), 0, 0, +0 ); + AddComponent( GetComponent( 3885, hue ), 0, 0, -1 ); + AddComponent( GetComponent( 3871, hue ), 0, 0, +0 ); + } + } + + public JackOLantern( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write((byte)2); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + + if ( version == 0 ) + { + Timer.DelayCall( TimeSpan.Zero, delegate() + { + for ( int i = 0; i < Components.Count; ++i ) + { + AddonComponent ac = Components[i] as AddonComponent; + + if ( ac != null && ac.Hue == 2118 ) + ac.Hue = 1161; + } + } ); + } + if (version <= 1) + { + Timer.DelayCall(TimeSpan.Zero, delegate() + { + for (int i = 0; i < Components.Count; ++i) + { + AddonComponent ac = Components[i] as AddonComponent; + + if (ac != null) + ac.Name = "jack-o-lantern"; + } + }); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LargeBedEastAddon.cs b/Scripts/Items/Addons/LargeBedEastAddon.cs new file mode 100644 index 0000000..e30a0bc --- /dev/null +++ b/Scripts/Items/Addons/LargeBedEastAddon.cs @@ -0,0 +1,77 @@ +using System; +using Server; + +namespace Server.Items +{ + // Scriptiz : dyable avec un furniture dye tub ! + [Furniture] + public class LargeBedEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LargeBedEastDeed(); } } + + public override bool RetainDeedHue { get { return true; } } // Scriptiz : on garde la couleur du deed + + [Constructable] + public LargeBedEastAddon() + : this(0) // Scriptiz : on migre vers le constructeur avec hue 0 par d�faut + { + } + + // Scriptiz : constructeur pour garder la hue du deed + public LargeBedEastAddon(int hue) + { + AddComponent( new AddonComponent( 0xA7D ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xA7C ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0xA79 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0xA78 ), 1, 1, 0 ); + Hue = hue; + } + + public LargeBedEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeBedEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LargeBedEastAddon(this.Hue); } } // Scriptiz : on garde la hue + public override int LabelNumber{ get{ return 1044324; } } // large bed (east) + + [Constructable] + public LargeBedEastDeed() + { + } + + public LargeBedEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LargeBedSouthAddon.cs b/Scripts/Items/Addons/LargeBedSouthAddon.cs new file mode 100644 index 0000000..9671181 --- /dev/null +++ b/Scripts/Items/Addons/LargeBedSouthAddon.cs @@ -0,0 +1,76 @@ +using System; +using Server; + +namespace Server.Items +{ + // Scriptiz : dyable avec un furniture dye tub ! + [Furniture] + public class LargeBedSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LargeBedSouthDeed(); } } + + public override bool RetainDeedHue { get { return true; } } // Scriptiz : on garde la couleur du deed + + [Constructable] + public LargeBedSouthAddon() + : this(0) + { + } + + public LargeBedSouthAddon(int hue) + { + AddComponent(new AddonComponent(0xA83), 0, 0, 0); + AddComponent(new AddonComponent(0xA7F), 0, 1, 0); + AddComponent(new AddonComponent(0xA82), 1, 0, 0); + AddComponent(new AddonComponent(0xA7E), 1, 1, 0); + Hue = hue; + } + + public LargeBedSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeBedSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LargeBedSouthAddon(this.Hue); } } + public override int LabelNumber{ get{ return 1044323; } } // large bed (south) + + [Constructable] + public LargeBedSouthDeed() + { + } + + public LargeBedSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LargeForgeEastAddon.cs b/Scripts/Items/Addons/LargeForgeEastAddon.cs new file mode 100644 index 0000000..5e32494 --- /dev/null +++ b/Scripts/Items/Addons/LargeForgeEastAddon.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LargeForgeEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LargeForgeEastDeed(); } } + + [Constructable] + public LargeForgeEastAddon() + { + AddComponent( new ForgeComponent( 0x1986 ), 0, 0, 0 ); + AddComponent( new ForgeComponent( 0x198A ), 0, 1, 0 ); + AddComponent( new ForgeComponent( 0x1996 ), 0, 2, 0 ); + AddComponent( new ForgeComponent( 0x1992 ), 0, 3, 0 ); + } + + public LargeForgeEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeForgeEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LargeForgeEastAddon(); } } + public override int LabelNumber{ get{ return 1044331; } } // large forge (east) + + [Constructable] + public LargeForgeEastDeed() + { + } + + public LargeForgeEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LargeForgeSouthAddon.cs b/Scripts/Items/Addons/LargeForgeSouthAddon.cs new file mode 100644 index 0000000..b750331 --- /dev/null +++ b/Scripts/Items/Addons/LargeForgeSouthAddon.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LargeForgeSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LargeForgeSouthDeed(); } } + + [Constructable] + public LargeForgeSouthAddon() + { + AddComponent( new ForgeComponent( 0x197A ), 0, 0, 0 ); + AddComponent( new ForgeComponent( 0x197E ), 1, 0, 0 ); + AddComponent( new ForgeComponent( 0x19A2 ), 2, 0, 0 ); + AddComponent( new ForgeComponent( 0x199E ), 3, 0, 0 ); + } + + public LargeForgeSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeForgeSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LargeForgeSouthAddon(); } } + public override int LabelNumber{ get{ return 1044332; } } // large forge (south) + + [Constructable] + public LargeForgeSouthDeed() + { + } + + public LargeForgeSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LargeStoneTableEastAddon.cs b/Scripts/Items/Addons/LargeStoneTableEastAddon.cs new file mode 100644 index 0000000..0da731c --- /dev/null +++ b/Scripts/Items/Addons/LargeStoneTableEastAddon.cs @@ -0,0 +1,73 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LargeStoneTableEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LargeStoneTableEastDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public LargeStoneTableEastAddon() : this( 0 ) + { + } + + [Constructable] + public LargeStoneTableEastAddon( int hue ) + { + AddComponent( new AddonComponent( 0x1202 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1203 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1201 ), 0, 2, 0 ); + Hue = hue; + } + + public LargeStoneTableEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeStoneTableEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LargeStoneTableEastAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1044511; } } // large stone table (east) + + [Constructable] + public LargeStoneTableEastDeed() + { + } + + public LargeStoneTableEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LargeStoneTableSouthAddon.cs b/Scripts/Items/Addons/LargeStoneTableSouthAddon.cs new file mode 100644 index 0000000..2fa6de6 --- /dev/null +++ b/Scripts/Items/Addons/LargeStoneTableSouthAddon.cs @@ -0,0 +1,73 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LargeStoneTableSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new LargeStoneTableSouthDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public LargeStoneTableSouthAddon() : this( 0 ) + { + } + + [Constructable] + public LargeStoneTableSouthAddon( int hue ) + { + AddComponent( new AddonComponent( 0x1205 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1206 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1204 ), 2, 0, 0 ); + Hue = hue; + } + + public LargeStoneTableSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeStoneTableSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LargeStoneTableSouthAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1044512; } } // large stone table (South) + + [Constructable] + public LargeStoneTableSouthDeed() + { + } + + public LargeStoneTableSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LoomEastAddon.cs b/Scripts/Items/Addons/LoomEastAddon.cs new file mode 100644 index 0000000..1cfa2a0 --- /dev/null +++ b/Scripts/Items/Addons/LoomEastAddon.cs @@ -0,0 +1,84 @@ +using System; +using Server; + +namespace Server.Items +{ + public interface ILoom + { + int Phase{ get; set; } + } + + public class LoomEastAddon : BaseAddon, ILoom + { + public override BaseAddonDeed Deed{ get{ return new LoomEastDeed(); } } + + private int m_Phase; + + public int Phase{ get{ return m_Phase; } set{ m_Phase = value; } } + + [Constructable] + public LoomEastAddon() + { + AddComponent( new AddonComponent( 0x1060 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x105F ), 0, 1, 0 ); + } + + public LoomEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Phase ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Phase = reader.ReadInt(); + break; + } + } + } + } + + public class LoomEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LoomEastAddon(); } } + public override int LabelNumber{ get{ return 1044343; } } // loom (east) + + [Constructable] + public LoomEastDeed() + { + } + + public LoomEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/LoomSouthAddon.cs b/Scripts/Items/Addons/LoomSouthAddon.cs new file mode 100644 index 0000000..3fd66a2 --- /dev/null +++ b/Scripts/Items/Addons/LoomSouthAddon.cs @@ -0,0 +1,79 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LoomSouthAddon : BaseAddon, ILoom + { + public override BaseAddonDeed Deed{ get{ return new LoomSouthDeed(); } } + + private int m_Phase; + + public int Phase{ get{ return m_Phase; } set{ m_Phase = value; } } + + [Constructable] + public LoomSouthAddon() + { + AddComponent( new AddonComponent( 0x1061 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1062 ), 1, 0, 0 ); + } + + public LoomSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Phase ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Phase = reader.ReadInt(); + break; + } + } + } + } + + public class LoomSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new LoomSouthAddon(); } } + public override int LabelNumber{ get{ return 1044344; } } // loom (south) + + [Constructable] + public LoomSouthDeed() + { + } + + public LoomSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/MediumStoneTableEastAddon.cs b/Scripts/Items/Addons/MediumStoneTableEastAddon.cs new file mode 100644 index 0000000..94e2a54 --- /dev/null +++ b/Scripts/Items/Addons/MediumStoneTableEastAddon.cs @@ -0,0 +1,72 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MediumStoneTableEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new MediumStoneTableEastDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public MediumStoneTableEastAddon() : this( 0 ) + { + } + + [Constructable] + public MediumStoneTableEastAddon( int hue ) + { + AddComponent( new AddonComponent( 0x1202 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1201 ), 0, 1, 0 ); + Hue = hue; + } + + public MediumStoneTableEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumStoneTableEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new MediumStoneTableEastAddon( this.Hue ); } } + public override int LabelNumber{ get{ return 1044508; } } // stone table (east) + + [Constructable] + public MediumStoneTableEastDeed() + { + } + + public MediumStoneTableEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/MediumStoneTableSouthAddon.cs b/Scripts/Items/Addons/MediumStoneTableSouthAddon.cs new file mode 100644 index 0000000..83e19ba --- /dev/null +++ b/Scripts/Items/Addons/MediumStoneTableSouthAddon.cs @@ -0,0 +1,72 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MediumStoneTableSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new MediumStoneTableSouthDeed(); } } + + public override bool RetainDeedHue{ get{ return true; } } + + [Constructable] + public MediumStoneTableSouthAddon() : this( 0 ) + { + } + + [Constructable] + public MediumStoneTableSouthAddon( int hue ) + { + AddComponent( new AddonComponent( 0x1205 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1204 ), 1, 0, 0 ); + Hue = hue; + } + + public MediumStoneTableSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumStoneTableSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new MediumStoneTableSouthAddon( Hue ); } } + public override int LabelNumber{ get{ return 1044509; } } // stone table (South) + + [Constructable] + public MediumStoneTableSouthDeed() + { + } + + public MediumStoneTableSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/OrnateElvenTableEastAddon.cs b/Scripts/Items/Addons/OrnateElvenTableEastAddon.cs new file mode 100644 index 0000000..6ec3367 --- /dev/null +++ b/Scripts/Items/Addons/OrnateElvenTableEastAddon.cs @@ -0,0 +1,65 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrnateElvenTableEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new OrnateElvenTableEastDeed(); } } + + [Constructable] + public OrnateElvenTableEastAddon() + { + AddComponent( new AddonComponent( 0x308E ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x308D ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x308C ), 1, 0, 0 ); + } + + public OrnateElvenTableEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrnateElvenTableEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new OrnateElvenTableEastAddon(); } } + public override int LabelNumber{ get{ return 1073384; } } // ornate table (east) + + [Constructable] + public OrnateElvenTableEastDeed() + { + } + + public OrnateElvenTableEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/OrnateElvenTableSouthAddon.cs b/Scripts/Items/Addons/OrnateElvenTableSouthAddon.cs new file mode 100644 index 0000000..9a92bb0 --- /dev/null +++ b/Scripts/Items/Addons/OrnateElvenTableSouthAddon.cs @@ -0,0 +1,65 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrnateElvenTableSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new OrnateElvenTableSouthDeed(); } } + + [Constructable] + public OrnateElvenTableSouthAddon() + { + AddComponent( new AddonComponent( 0x308F ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x3090 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3091 ), 0, -1, 0 ); + } + + public OrnateElvenTableSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrnateElvenTableSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new OrnateElvenTableSouthAddon(); } } + public override int LabelNumber{ get{ return 1072869; } } // ornate table (south) + + [Constructable] + public OrnateElvenTableSouthDeed() + { + } + + public OrnateElvenTableSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ParrotPerchAddon.cs b/Scripts/Items/Addons/ParrotPerchAddon.cs new file mode 100644 index 0000000..4f40c52 --- /dev/null +++ b/Scripts/Items/Addons/ParrotPerchAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ParrotPerchAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new ParrotPerchDeed(); } } + + [Constructable] + public ParrotPerchAddon() + { + AddComponent( new AddonComponent( 0x2FF4 ), 0, 0, 0 ); + } + + public ParrotPerchAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ParrotPerchDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new ParrotPerchAddon(); } } + public override int LabelNumber{ get{ return 1072617; } } // parrot perch + + [Constructable] + public ParrotPerchDeed() + { + } + + public ParrotPerchDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/PentagramAddon.cs b/Scripts/Items/Addons/PentagramAddon.cs new file mode 100644 index 0000000..b231338 --- /dev/null +++ b/Scripts/Items/Addons/PentagramAddon.cs @@ -0,0 +1,71 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PentagramAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new PentagramDeed(); } } + + [Constructable] + public PentagramAddon() + { + AddComponent( new AddonComponent( 0xFE7 ), -1, -1, 0 ); + AddComponent( new AddonComponent( 0xFE8 ), 0, -1, 0 ); + AddComponent( new AddonComponent( 0xFEB ), 1, -1, 0 ); + AddComponent( new AddonComponent( 0xFE6 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0xFEA ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xFEE ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0xFE9 ), -1, 1, 0 ); + AddComponent( new AddonComponent( 0xFEC ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0xFED ), 1, 1, 0 ); + } + + public PentagramAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PentagramDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new PentagramAddon(); } } + public override int LabelNumber{ get{ return 1044328; } } // pentagram + + [Constructable] + public PentagramDeed() + { + } + + public PentagramDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/PickpocketDips.cs b/Scripts/Items/Addons/PickpocketDips.cs new file mode 100644 index 0000000..353f126 --- /dev/null +++ b/Scripts/Items/Addons/PickpocketDips.cs @@ -0,0 +1,274 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1EC0, 0x1EC3 )] + public class PickpocketDip : AddonComponent + { + private double m_MinSkill; + private double m_MaxSkill; + + private Timer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public double MinSkill + { + get{ return m_MinSkill; } + set{ m_MinSkill = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public double MaxSkill + { + get{ return m_MaxSkill; } + set{ m_MaxSkill = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Swinging + { + get{ return ( m_Timer != null ); } + } + + public PickpocketDip( int itemID ) : base( itemID ) + { + m_MinSkill = -25.0; + m_MaxSkill = +25.0; + } + + public void UpdateItemID() + { + int baseItemID = 0x1EC0 + (((ItemID - 0x1EC0) / 3) * 3); + + ItemID = baseItemID + (Swinging ? 1 : 0); + } + + public void BeginSwing() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + + UpdateItemID(); + } + + public void EndSwing() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + UpdateItemID(); + } + + public void Use( Mobile from ) + { + from.Direction = from.GetDirectionTo( GetWorldLocation() ); + + Effects.PlaySound( GetWorldLocation(), Map, 0x4F ); + + if ( from.CheckSkill( SkillName.Stealing, m_MinSkill, m_MaxSkill ) ) + { + SendLocalizedMessageTo( from, 501834 ); // You successfully avoid disturbing the dip while searching it. + } + else + { + Effects.PlaySound( GetWorldLocation(), Map, 0x390 ); + + BeginSwing(); + ProcessDelta(); + SendLocalizedMessageTo( from, 501831 ); // You carelessly bump the dip and start it swinging. + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 1 ) ) + SendLocalizedMessageTo( from, 501816 ); // You are too far away to do that. + else if ( Swinging ) + SendLocalizedMessageTo( from, 501815 ); // You have to wait until it stops swinging. + else if ( from.Skills[SkillName.Stealing].Base >= m_MaxSkill ) + SendLocalizedMessageTo( from, 501830 ); // Your ability to steal cannot improve any further by simply practicing on a dummy. + else if ( from.Mounted ) + SendLocalizedMessageTo( from, 501829 ); // You can't practice on this while on a mount. + else + Use( from ); + } + + public PickpocketDip( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_MinSkill ); + writer.Write( m_MaxSkill ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_MinSkill = reader.ReadDouble(); + m_MaxSkill = reader.ReadDouble(); + + if ( m_MinSkill == 0.0 && m_MaxSkill == 30.0 ) + { + m_MinSkill = -25.0; + m_MaxSkill = +25.0; + } + + break; + } + } + + UpdateItemID(); + } + + private class InternalTimer : Timer + { + private PickpocketDip m_Dip; + + public InternalTimer( PickpocketDip dip ) : base( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Dip = dip; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Dip.EndSwing(); + } + } + } + + public class PickpocketDipEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new PickpocketDipEastDeed(); } } + + [Constructable] + public PickpocketDipEastAddon() + { + AddComponent( new PickpocketDip( 0x1EC3 ), 0, 0, 0 ); + } + + public PickpocketDipEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PickpocketDipEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new PickpocketDipEastAddon(); } } + public override int LabelNumber{ get{ return 1044337; } } // pickpocket dip (east) + + [Constructable] + public PickpocketDipEastDeed() + { + } + + public PickpocketDipEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PickpocketDipSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new PickpocketDipSouthDeed(); } } + + [Constructable] + public PickpocketDipSouthAddon() + { + AddComponent( new PickpocketDip( 0x1EC0 ), 0, 0, 0 ); + } + + public PickpocketDipSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PickpocketDipSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new PickpocketDipSouthAddon(); } } + public override int LabelNumber{ get{ return 1044338; } } // pickpocket dip (south) + + [Constructable] + public PickpocketDipSouthDeed() + { + } + + public PickpocketDipSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/PyramidAddon.cs b/Scripts/Items/Addons/PyramidAddon.cs new file mode 100644 index 0000000..08c9d16 --- /dev/null +++ b/Scripts/Items/Addons/PyramidAddon.cs @@ -0,0 +1,63 @@ +using System; +using System.Text; +using System.Net; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class PyramidAddon : BaseAddon + { + public override bool ShareHue + { + get { return false; } + } + + [Constructable] + public PyramidAddon() + { + AddComponent( new AddonComponent( 1006 ), 0, 0, 5 ); + + for ( int o = 1; o <= 2; ++o ) + { + AddComponent( new AddonComponent( 1011 ), -o, -o, ( 2 - o ) * 5 ); + AddComponent( new AddonComponent( 1012 ), +o, +o, ( 2 - o ) * 5 ); + AddComponent( new AddonComponent( 1013 ), +o, -o, ( 2 - o ) * 5 ); + AddComponent( new AddonComponent( 1014 ), -o, +o, ( 2 - o ) * 5 ); + } + + for ( int o = -1; o <= 1; ++o ) + { + AddComponent( new AddonComponent( 1007 ), o, 2, 0 ); + AddComponent( new AddonComponent( 1008 ), 2, o, 0 ); + AddComponent( new AddonComponent( 1009 ), o, -2, 0 ); + AddComponent( new AddonComponent( 1010 ), -2, o, 0 ); + } + + AddComponent( new AddonComponent( 1007 ), 0, 1, 5 ); + AddComponent( new AddonComponent( 1008 ), 1, 0, 5 ); + AddComponent( new AddonComponent( 1009 ), 0, -1, 5 ); + AddComponent( new AddonComponent( 1010 ), -1, 0, 5 ); + } + + public PyramidAddon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/RejuvinationAnkhs.cs b/Scripts/Items/Addons/RejuvinationAnkhs.cs new file mode 100644 index 0000000..1a616cf --- /dev/null +++ b/Scripts/Items/Addons/RejuvinationAnkhs.cs @@ -0,0 +1,180 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class RejuvinationAddonComponent : AddonComponent + { + public RejuvinationAddonComponent( int itemID ) : base( itemID ) + { + } + + public RejuvinationAddonComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.BeginAction( typeof( RejuvinationAddonComponent ) ) ) + { + from.FixedEffect( 0x373A, 1, 16 ); + + int random = Utility.Random( 1, 4 ); + + if ( random == 1 || random == 4 ) + { + from.Hits = from.HitsMax; + SendLocalizedMessageTo( from, 500801 ); // A sense of warmth fills your body! + } + + if ( random == 2 || random == 4 ) + { + from.Mana = from.ManaMax; + SendLocalizedMessageTo( from, 500802 ); // A feeling of power surges through your veins! + } + + if ( random == 3 || random == 4 ) + { + from.Stam = from.StamMax; + SendLocalizedMessageTo( from, 500803 ); // You feel as though you've slept for days! + } + + Timer.DelayCall( TimeSpan.FromHours( 2.0 ), new TimerStateCallback( ReleaseUseLock_Callback ), new object[]{ from, random } ); + } + } + + public virtual void ReleaseUseLock_Callback( object state ) + { + object[] states = (object[])state; + + Mobile from = (Mobile)states[0]; + int random = (int)states[1]; + + from.EndAction( typeof( RejuvinationAddonComponent ) ); + + if ( random == 4 ) + { + from.Hits = from.HitsMax; + from.Mana = from.ManaMax; + from.Stam = from.StamMax; + SendLocalizedMessageTo( from, 500807 ); // You feel completely rejuvinated! + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class BaseRejuvinationAnkh : BaseAddon + { + public BaseRejuvinationAnkh() + { + } + + public override bool HandlesOnMovement{ get{ return true; } } + + private DateTime m_NextMessage; + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m.Player && Utility.InRange( Location, m.Location, 3 ) && !Utility.InRange( Location, oldLocation, 3 ) ) + { + if ( DateTime.Now >= m_NextMessage ) + { + if ( Components.Count > 0 ) + ((AddonComponent)Components[0]).SendLocalizedMessageTo( m, 1010061 ); // An overwhelming sense of peace fills you. + + m_NextMessage = DateTime.Now + TimeSpan.FromSeconds( 25.0 ); + } + } + } + + public BaseRejuvinationAnkh( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RejuvinationAnkhWest : BaseRejuvinationAnkh + { + [Constructable] + public RejuvinationAnkhWest() + { + AddComponent( new RejuvinationAddonComponent( 0x3 ), 0, 0, 0 ); + AddComponent( new RejuvinationAddonComponent( 0x2 ), 0, 1, 0 ); + } + + public RejuvinationAnkhWest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RejuvinationAnkhNorth : BaseRejuvinationAnkh + { + [Constructable] + public RejuvinationAnkhNorth() + { + AddComponent( new RejuvinationAddonComponent( 0x4 ), 0, 0, 0 ); + AddComponent( new RejuvinationAddonComponent( 0x5 ), 1, 0, 0 ); + } + + public RejuvinationAnkhNorth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SHTeleporter.cs b/Scripts/Items/Addons/SHTeleporter.cs new file mode 100644 index 0000000..5664f3b --- /dev/null +++ b/Scripts/Items/Addons/SHTeleporter.cs @@ -0,0 +1,453 @@ +using System; +using Server.Commands; + +namespace Server.Items +{ + public class SHTeleComponent : AddonComponent + { + private bool m_Active; + private SHTeleComponent m_TeleDest; + private Point3D m_TeleOffset; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get { return m_Active; } + set + { + m_Active = value; + + SHTeleporter sourceAddon = Addon as SHTeleporter; + + if ( sourceAddon != null ) + sourceAddon.ChangeActive( value ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D TeleOffset + { + get { return m_TeleOffset; } + set { m_TeleOffset = value; } + } + + [CommandProperty( AccessLevel.Counselor )] + public Point3D TelePoint + { + get { return new Point3D( Location.X + TeleOffset.X, Location.Y + TeleOffset.Y, Location.Z + TeleOffset.Z ); } + set { m_TeleOffset = new Point3D( value.X - Location.X, value.Y - Location.Y, value.Z - Location.Z ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SHTeleComponent TeleDest + { + get { return m_TeleDest; } + set + { + m_TeleDest = value; + + SHTeleporter sourceAddon = Addon as SHTeleporter; + + if ( sourceAddon != null ) + sourceAddon.ChangeDest( value ); + } + } + + public override string DefaultName + { + get { return "a hole"; } + } + + [Constructable] + public SHTeleComponent() : this( 0x1775 ) + { + } + + [Constructable] + public SHTeleComponent( int itemID ) : this( itemID, new Point3D( 0, 0, 0 ) ) + { + } + + [Constructable] + public SHTeleComponent( int itemID, Point3D offset ) : base( itemID ) + { + Movable = false; + Hue = 1; + + m_Active = true; + m_TeleOffset = offset; + } + + public SHTeleComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile m ) + { + if ( !m_Active || m_TeleDest == null || m_TeleDest.Deleted || m_TeleDest.Map == Map.Internal ) + return; + + if ( m.InRange( this, 3 ) ) + { + Map map = m_TeleDest.Map; + Point3D p = m_TeleDest.TelePoint; + + Server.Mobiles.BaseCreature.TeleportPets( m, p, map ); + + m.MoveToWorld( p, map ); + } + else + { + m.SendLocalizedMessage( 1019045 ); // I can't reach that. + } + } + + public override void OnDoubleClickDead( Mobile m ) + { + OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( m_Active ); + writer.Write( m_TeleDest ); + writer.Write( m_TeleOffset ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Active = reader.ReadBool(); + m_TeleDest = reader.ReadItem() as SHTeleComponent; + m_TeleOffset = reader.ReadPoint3D(); + } + } + + public class SHTeleporter : BaseAddon + { + public static void Initialize() + { + CommandSystem.Register( "SHTelGen", AccessLevel.Administrator, new CommandEventHandler( SHTelGen_OnCommand ) ); + } + + [Usage( "SHTelGen" )] + [Description( "Generates solen hives teleporters." )] + public static void SHTelGen_OnCommand( CommandEventArgs e ) + { + World.Broadcast( 0x35, true, "Solen hives teleporters are being generated, please wait." ); + + DateTime startTime = DateTime.Now; + + int count = new SHTeleporterCreator().CreateSHTeleporters(); + + DateTime endTime = DateTime.Now; + + World.Broadcast( 0x35, true, "{0} solen hives teleporters have been created. The entire process took {1:F1} seconds.", count, (endTime - startTime).TotalSeconds ); + } + + public class SHTeleporterCreator + { + private int m_Count; + + public SHTeleporterCreator() + { + m_Count = 0; + } + + public static SHTeleporter FindSHTeleporter( Map map, Point3D p ) + { + IPooledEnumerable eable = map.GetItemsInRange( p, 0 ); + + foreach ( Item item in eable ) + { + if ( item is SHTeleporter && item.Z == p.Z ) + { + eable.Free(); + return (SHTeleporter)item; + } + } + + eable.Free(); + return null; + } + + public SHTeleporter AddSHT( Map map, bool ext, int x, int y, int z ) + { + Point3D p = new Point3D( x, y, z ); + SHTeleporter tele = FindSHTeleporter( map, p ); + + if ( tele == null ) + { + tele = new SHTeleporter( ext ); + tele.MoveToWorld( p, map ); + + m_Count++; + } + + return tele; + } + + public static void Link( SHTeleporter tele1, SHTeleporter tele2 ) + { + tele1.ChangeDest( tele2 ); + tele2.ChangeDest( tele1 ); + } + + public void AddSHTCouple( Map map, bool ext1, int x1, int y1, int z1, bool ext2, int x2, int y2, int z2 ) + { + SHTeleporter tele1 = AddSHT( map, ext1, x1, y1, z1 ); + SHTeleporter tele2 = AddSHT( map, ext2, x2, y2, z2 ); + + Link( tele1, tele2 ); + } + + public void AddSHTCouple( bool ext1, int x1, int y1, int z1, bool ext2, int x2, int y2, int z2 ) + { + AddSHTCouple( Map.Trammel, ext1, x1, y1, z1, ext2, x2, y2, z2 ); + AddSHTCouple( Map.Felucca, ext1, x1, y1, z1, ext2, x2, y2, z2 ); + } + + public int CreateSHTeleporters() + { + SHTeleporter tele1, tele2; + + AddSHTCouple( true, 2608, 763, 0, false, 5918, 1794, 0 ); + AddSHTCouple( false, 5897, 1877, 0, false, 5871, 1867, 0 ); + AddSHTCouple( false, 5852, 1848, 0, false, 5771, 1867, 0 ); + + tele1 = AddSHT( Map.Trammel, false, 5747, 1895, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Trammel, false, 5658, 1898, 0 ); + Link( tele1, tele2 ); + + tele1 = AddSHT( Map.Felucca, false, 5747, 1895, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Felucca, false, 5658, 1898, 0 ); + Link( tele1, tele2 ); + + AddSHTCouple( false, 5727, 1894, 0, false, 5756, 1794, 0 ); + AddSHTCouple( false, 5784, 1929, 0, false, 5700, 1929, 0 ); + + tele1 = AddSHT( Map.Trammel, false, 5711, 1952, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Trammel, false, 5657, 1954, 0 ); + Link( tele1, tele2 ); + + tele1 = AddSHT( Map.Felucca, false, 5711, 1952, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Felucca, false, 5657, 1954, 0 ); + Link( tele1, tele2 ); + + tele1 = AddSHT( Map.Trammel, false, 5655, 2018, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Trammel, true, 1690, 2789, 0 ); + Link( tele1, tele2 ); + + tele1 = AddSHT( Map.Felucca, false, 5655, 2018, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Felucca, true, 1690, 2789, 0 ); + Link( tele1, tele2 ); + + AddSHTCouple( false, 5809, 1905, 0, false, 5876, 1891, 0 ); + + tele1 = AddSHT( Map.Trammel, false, 5814, 2015, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Trammel, false, 5913, 1893, 0 ); + Link( tele1, tele2 ); + + tele1 = AddSHT( Map.Felucca, false, 5814, 2015, 0 ); + tele1.LeftTele.TeleOffset = new Point3D( -1, 3, 0 ); + tele2 = AddSHT( Map.Felucca, false, 5913, 1893, 0 ); + Link( tele1, tele2 ); + + AddSHTCouple( false, 5919, 2021, 0, true, 1724, 814, 0 ); + + tele1 = AddSHT( Map.Trammel, false, 5654, 1791, 0 ); + tele2 = AddSHT( Map.Trammel, true, 730, 1451, 0 ); + Link( tele1, tele2 ); + AddSHT( Map.Trammel, false, 5734, 1859, 0 ).ChangeDest( tele2 ); + + tele1 = AddSHT( Map.Felucca, false, 5654, 1791, 0 ); + tele2 = AddSHT( Map.Felucca, true, 730, 1451, 0 ); + Link( tele1, tele2 ); + AddSHT( Map.Felucca, false, 5734, 1859, 0 ).ChangeDest( tele2 ); + + return m_Count; + } + } + + private bool m_External; + + private SHTeleComponent m_UpTele; + private SHTeleComponent m_RightTele; + private SHTeleComponent m_DownTele; + private SHTeleComponent m_LeftTele; + + private bool m_Changing; + + [CommandProperty( AccessLevel.GameMaster )] + public bool External { get { return m_External; } } + + public SHTeleComponent UpTele { get { return m_UpTele; } } + public SHTeleComponent RightTele { get { return m_RightTele; } } + public SHTeleComponent DownTele { get { return m_DownTele; } } + public SHTeleComponent LeftTele { get { return m_LeftTele; } } + + [Constructable] + public SHTeleporter() : this( true ) + { + } + + [Constructable] + public SHTeleporter( bool external ) + { + m_Changing = false; + m_External = external; + + if ( external ) + { + AddComponent( new AddonComponent( 0x549 ), -1, -1, 0 ); + AddComponent( new AddonComponent( 0x54D ), 0, -1, 0 ); + AddComponent( new AddonComponent( 0x54E ), 1, -1, 0 ); + AddComponent( new AddonComponent( 0x548 ), 2, -1, 0 ); + AddComponent( new AddonComponent( 0x54B ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x53B ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x53B ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x544 ), 2, 0, 0 ); + AddComponent( new AddonComponent( 0x54C ), -1, 1, 0 ); + AddComponent( new AddonComponent( 0x53B ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x53B ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x545 ), 2, 1, 0 ); + AddComponent( new AddonComponent( 0x547 ), -1, 2, 0 ); + AddComponent( new AddonComponent( 0x541 ), 0, 2, 0 ); + AddComponent( new AddonComponent( 0x543 ), 1, 2, 0 ); + AddComponent( new AddonComponent( 0x540 ), 2, 2, 0 ); + } + + Point3D upOS = external ? new Point3D( -1, 0, 0 ) : new Point3D( -2, -1, 0 ); + m_UpTele = new SHTeleComponent( external ? 0x1775 : 0x495, upOS ); + AddComponent( m_UpTele, 0, 0, 0 ); + + Point3D rightOS = external ? new Point3D( -2, 0, 0 ) : new Point3D( 2, -1, 0 ); + m_RightTele = new SHTeleComponent( external ? 0x1775 : 0x495, rightOS ); + AddComponent( m_RightTele, 1, 0, 0 ); + + Point3D downOS = external ? new Point3D( -2, -1, 0 ) : new Point3D( 2, 2, 0 ); + m_DownTele = new SHTeleComponent( external ? 0x1776 : 0x495, downOS ); + AddComponent( m_DownTele, 1, 1, 0 ); + + Point3D leftOS = external ? new Point3D( -1, -1, 0 ) : new Point3D( -1, 2, 0 ); + m_LeftTele = new SHTeleComponent( external ? 0x1775 : 0x495, leftOS ); + AddComponent( m_LeftTele, 0, 1, 0 ); + } + + public SHTeleporter( Serial serial ) : base( serial ) + { + m_Changing = false; + } + + public override bool ShareHue{ get { return false; } } + + public void ChangeActive( bool active ) + { + if ( m_Changing ) + return; + + m_Changing = true; + + m_UpTele.Active = active; + m_RightTele.Active = active; + m_DownTele.Active = active; + m_LeftTele.Active = active; + + m_Changing = false; + } + + public void ChangeDest( SHTeleComponent dest ) + { + if ( m_Changing ) + return; + + m_Changing = true; + + if ( dest == null || !(dest.Addon is SHTeleporter) ) + { + m_UpTele.TeleDest = dest; + m_RightTele.TeleDest = dest; + m_DownTele.TeleDest = dest; + m_LeftTele.TeleDest = dest; + } + else + { + SHTeleporter destAddon = (SHTeleporter)dest.Addon; + + m_UpTele.TeleDest = destAddon.UpTele; + m_RightTele.TeleDest = destAddon.RightTele; + m_DownTele.TeleDest = destAddon.DownTele; + m_LeftTele.TeleDest = destAddon.LeftTele; + } + + m_Changing = false; + } + + public void ChangeDest( SHTeleporter destAddon ) + { + if ( m_Changing ) + return; + + m_Changing = true; + + if ( destAddon != null ) + { + m_UpTele.TeleDest = destAddon.UpTele; + m_RightTele.TeleDest = destAddon.RightTele; + m_DownTele.TeleDest = destAddon.DownTele; + m_LeftTele.TeleDest = destAddon.LeftTele; + } + else + { + m_UpTele.TeleDest = null; + m_RightTele.TeleDest = null; + m_DownTele.TeleDest = null; + m_LeftTele.TeleDest = null; + } + + m_Changing = false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( m_External ); + + writer.Write( m_UpTele ); + writer.Write( m_RightTele ); + writer.Write( m_DownTele ); + writer.Write( m_LeftTele ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_External = reader.ReadBool(); + + m_UpTele = (SHTeleComponent)reader.ReadItem(); + m_RightTele = (SHTeleComponent)reader.ReadItem(); + m_DownTele = (SHTeleComponent)reader.ReadItem(); + m_LeftTele = (SHTeleComponent)reader.ReadItem(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SandstoneFireplaceEastAddon.cs b/Scripts/Items/Addons/SandstoneFireplaceEastAddon.cs new file mode 100644 index 0000000..f5780f6 --- /dev/null +++ b/Scripts/Items/Addons/SandstoneFireplaceEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SandstoneFireplaceEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SandstoneFireplaceEastDeed(); } } + + [Constructable] + public SandstoneFireplaceEastAddon() + { + AddComponent( new AddonComponent( 0x489 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x475 ), 0, 1, 0 ); + } + + public SandstoneFireplaceEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SandstoneFireplaceEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SandstoneFireplaceEastAddon(); } } + public override int LabelNumber{ get{ return 1061844; } } // sandstone fireplace (east) + + [Constructable] + public SandstoneFireplaceEastDeed() + { + } + + public SandstoneFireplaceEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SandstoneFireplaceSouthAddon.cs b/Scripts/Items/Addons/SandstoneFireplaceSouthAddon.cs new file mode 100644 index 0000000..b76a8fd --- /dev/null +++ b/Scripts/Items/Addons/SandstoneFireplaceSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SandstoneFireplaceSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SandstoneFireplaceSouthDeed(); } } + + [Constructable] + public SandstoneFireplaceSouthAddon() + { + AddComponent( new AddonComponent( 0x482 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x47B ), 0, 0, 0 ); + } + + public SandstoneFireplaceSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SandstoneFireplaceSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SandstoneFireplaceSouthAddon(); } } + public override int LabelNumber{ get{ return 1061845; } } // sandstone fireplace (south) + + [Constructable] + public SandstoneFireplaceSouthDeed() + { + } + + public SandstoneFireplaceSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SandstoneFountainAddon.cs b/Scripts/Items/Addons/SandstoneFountainAddon.cs new file mode 100644 index 0000000..d83b33d --- /dev/null +++ b/Scripts/Items/Addons/SandstoneFountainAddon.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SandstoneFountainAddon : BaseAddon + { + [Constructable] + public SandstoneFountainAddon() + { + int itemID = 0x19C3; + + AddComponent( new AddonComponent( itemID++ ), -2, +1, 0 ); + AddComponent( new AddonComponent( itemID++ ), -1, +1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +0, +1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +1, +1, 0 ); + + AddComponent( new AddonComponent( itemID++ ), +1, +0, 0 ); + AddComponent( new AddonComponent( itemID++ ), +1, -1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +1, -2, 0 ); + + AddComponent( new AddonComponent( itemID++ ), +0, -2, 0 ); + AddComponent( new AddonComponent( itemID++ ), +0, -1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +0, +0, 0 ); + + AddComponent( new AddonComponent( itemID++ ), -1, +0, 0 ); + AddComponent( new AddonComponent( itemID++ ), -2, +0, 0 ); + + AddComponent( new AddonComponent( itemID++ ), -2, -1, 0 ); + AddComponent( new AddonComponent( itemID++ ), -1, -1, 0 ); + + AddComponent( new AddonComponent( itemID++ ), -1, -2, 0 ); + AddComponent( new AddonComponent( ++itemID ), -2, -2, 0 ); + } + + public SandstoneFountainAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SerpentPillarAddon.cs b/Scripts/Items/Addons/SerpentPillarAddon.cs new file mode 100644 index 0000000..df57ba2 --- /dev/null +++ b/Scripts/Items/Addons/SerpentPillarAddon.cs @@ -0,0 +1,54 @@ +using System; +using System.Text; +using System.Net; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class SerpentPillarAddon : BaseAddon + { + [Constructable] + public SerpentPillarAddon() + { + AddComponent( new AddonComponent( 9020 ), -2, +1, 0 ); + AddComponent( new AddonComponent( 9021 ), -2, +0, 0 ); + AddComponent( new AddonComponent( 9022 ), -2, -1, 0 ); + AddComponent( new AddonComponent( 9023 ), -2, -2, 0 ); + AddComponent( new AddonComponent( 9024 ), -1, -2, 0 ); + AddComponent( new AddonComponent( 9025 ), +0, -2, 0 ); + AddComponent( new AddonComponent( 9026 ), +1, -2, 0 ); + + AddComponent( new AddonComponent( 9027 ), -1, +1, 0 ); + AddComponent( new AddonComponent( 9028 ), -1, +0, 0 ); + AddComponent( new AddonComponent( 9029 ), -1, -1, 0 ); + + AddComponent( new AddonComponent( 9030 ), +0, +1, 0 ); + AddComponent( new AddonComponent( 9031 ), +0, +0, 0 ); + AddComponent( new AddonComponent( 9032 ), +0, -1, 0 ); + + AddComponent( new AddonComponent( 9033 ), +1, +0, 0 ); + AddComponent( new AddonComponent( 9034 ), +1, -1, 0 ); + } + + public SerpentPillarAddon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/ShrineOfWisdomAddon.cs b/Scripts/Items/Addons/ShrineOfWisdomAddon.cs new file mode 100644 index 0000000..c929ec6 --- /dev/null +++ b/Scripts/Items/Addons/ShrineOfWisdomAddon.cs @@ -0,0 +1,65 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShrineOfWisdomAddon : BaseAddon + { + [Constructable] + public ShrineOfWisdomAddon() + { + AddComponent( new ShrineOfWisdomComponent( 0x14C3 ), 0, 0, 0 ); + AddComponent( new ShrineOfWisdomComponent( 0x14C6 ), 1, 0, 0 ); + AddComponent( new ShrineOfWisdomComponent( 0x14D4 ), 0, 1, 0 ); + AddComponent( new ShrineOfWisdomComponent( 0x14D5 ), 1, 1, 0 ); + Hue = 0x47E; + } + + public ShrineOfWisdomAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Server.Engines.Craft.Forge] + public class ShrineOfWisdomComponent : AddonComponent + { + public override int LabelNumber{ get{ return 1062046; } } // Shrine of Wisdom + + [Constructable] + public ShrineOfWisdomComponent( int itemID ) : base( itemID ) + { + } + + public ShrineOfWisdomComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SkullPileAddon.cs b/Scripts/Items/Addons/SkullPileAddon.cs new file mode 100644 index 0000000..4172249 --- /dev/null +++ b/Scripts/Items/Addons/SkullPileAddon.cs @@ -0,0 +1,44 @@ +using System; +using System.Text; +using System.Net; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class SkullPileAddon : BaseAddon + { + [Constructable] + public SkullPileAddon() + { + AddComponent( new AddonComponent( 6872 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 6873 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 6874 ), -1, 1, 0 ); + AddComponent( new AddonComponent( 6875 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 6876 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 6877 ), 1, -1, 0 ); + AddComponent( new AddonComponent( 6878 ), 2, -1, 0 ); + AddComponent( new AddonComponent( 6879 ), 2, 0, 0 ); + } + + public SkullPileAddon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SmallBedEastAddon.cs b/Scripts/Items/Addons/SmallBedEastAddon.cs new file mode 100644 index 0000000..1fa32f1 --- /dev/null +++ b/Scripts/Items/Addons/SmallBedEastAddon.cs @@ -0,0 +1,73 @@ +using System; +using Server; + +namespace Server.Items +{ + // Scriptiz : dyable avec un furniture dye tub ! + [Furniture] + public class SmallBedEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SmallBedEastDeed(); } } + + public override bool RetainDeedHue { get { return true; } } + + [Constructable] + public SmallBedEastAddon() + : this(0) + { + } + + public SmallBedEastAddon(int hue) + { + AddComponent(new AddonComponent(0xA5D), 0, 0, 0); + AddComponent(new AddonComponent(0xA62), 1, 0, 0); + } + + public SmallBedEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallBedEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SmallBedEastAddon(this.Hue); } } + public override int LabelNumber{ get{ return 1044322; } } // small bed (east) + + [Constructable] + public SmallBedEastDeed() + { + } + + public SmallBedEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SmallBedSouthAddon.cs b/Scripts/Items/Addons/SmallBedSouthAddon.cs new file mode 100644 index 0000000..7321431 --- /dev/null +++ b/Scripts/Items/Addons/SmallBedSouthAddon.cs @@ -0,0 +1,73 @@ +using System; +using Server; + +namespace Server.Items +{ + // Scriptiz : dyable avec un furniture dye tub ! + [Furniture] + public class SmallBedSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SmallBedSouthDeed(); } } + + public override bool RetainDeedHue { get { return true; } } + + [Constructable] + public SmallBedSouthAddon() + : this(0) + { + } + + public SmallBedSouthAddon(int hue) + { + AddComponent(new AddonComponent(0xA63), 0, 0, 0); + AddComponent(new AddonComponent(0xA5C), 0, 1, 0); + } + + public SmallBedSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallBedSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SmallBedSouthAddon(this.Hue); } } + public override int LabelNumber{ get{ return 1044321; } } // small bed (south) + + [Constructable] + public SmallBedSouthDeed() + { + } + + public SmallBedSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SmallForgeAddon.cs b/Scripts/Items/Addons/SmallForgeAddon.cs new file mode 100644 index 0000000..6ac48cd --- /dev/null +++ b/Scripts/Items/Addons/SmallForgeAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SmallForgeAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SmallForgeDeed(); } } + + [Constructable] + public SmallForgeAddon() + { + AddComponent( new ForgeComponent( 0xFB1 ), 0, 0, 0 ); + } + + public SmallForgeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallForgeDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SmallForgeAddon(); } } + public override int LabelNumber{ get{ return 1044330; } } // small forge + + [Constructable] + public SmallForgeDeed() + { + } + + public SmallForgeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SolenAntHole.cs b/Scripts/Items/Addons/SolenAntHole.cs new file mode 100644 index 0000000..2e44198 --- /dev/null +++ b/Scripts/Items/Addons/SolenAntHole.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Items +{ + public class SolenAntHoleComponent : AddonComponent + { + public SolenAntHoleComponent( int itemID ) : base( itemID ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this, 2 ) ) + { + Map map = Map; + + if ( map == Map.Trammel || map == Map.Felucca ) + { + from.MoveToWorld( new Point3D( 5922, 2024, 0 ), map ); + PublicOverheadMessage( MessageType.Regular, 0x3B2, true, String.Format( "* {0} dives into the hole and disappears!*", from.Name ) ); + } + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public SolenAntHoleComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + + public class SolenAntHole : BaseAddon + { + public override bool ShareHue { get { return false; } } + public override bool HandlesOnMovement { get { return true; } } + + private List m_Spawned; + + [Constructable] + public SolenAntHole() : base() + { + m_Spawned = new List(); + + AddComponent( new AddonComponent( 0x914 ), "dirt", 0, 0, 0, 0 ); + AddComponent( new SolenAntHoleComponent( 0x122A ), "a hole", 0x1, 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1B23 ), "dirt", 0x970, 1, 1, 0 ); + AddComponent( new AddonComponent( 0xEE0 ), "dirt", 0, 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1B24 ), "dirt", 0x970, 1, -1, 0 ); + AddComponent( new AddonComponent( 0xEE1 ), "dirt", 0, 0, -1, 0 ); + AddComponent( new AddonComponent( 0x1B25 ), "dirt", 0x970, -1, -1, 0 ); + AddComponent( new AddonComponent( 0xEE2 ), "dirt", 0, -1, 0, 0 ); + AddComponent( new AddonComponent( 0x1B26 ), "dirt", 0x970, -1, 1, 0 ); + AddComponent( new AddonComponent( 0xED3 ), "dirt", 0, 0, 1, 0 ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( !m.Player || !m.Alive || m.Hidden || !SpawnKilled() ) + return; + + if ( Utility.InRange( Location, m.Location, 3 ) && !Utility.InRange( Location, oldLocation, 3 ) ) + { + int count = 1 + Utility.Random( 4 ); + + for ( int i = 0; i < count; i++ ) + SpawnAnt(); + + if ( 0.05 > Utility.RandomDouble() ) + SpawnAnt( new Beetle() ); + } + } + + public void AddComponent( AddonComponent c, string name, int hue, int x, int y, int z ) + { + c.Hue = hue; + c.Name = name; + AddComponent( c, x, y, z ); + } + + public void SpawnAnt() + { + int random = Utility.Random( 3 ); + Map map = Map; + + if ( map == Map.Trammel ) + { + if ( random < 2 ) + SpawnAnt( new RedSolenWorker() ); + else + SpawnAnt( new RedSolenWarrior() ); + } + else if ( map == Map.Felucca ) + { + if ( random < 2 ) + SpawnAnt( new BlackSolenWorker() ); + else + SpawnAnt( new BlackSolenWarrior() ); + } + } + + public void SpawnAnt( BaseCreature ant ) + { + m_Spawned.Add( ant ); + + Map map = Map; + Point3D p = Location; + + for ( int i = 0; i < 5; i++ ) + if ( SpellHelper.FindValidSpawnLocation( map, ref p, false ) ) + break; + + ant.MoveToWorld( p, map ); + ant.Home = Location; + ant.RangeHome = 10; + } + + public bool SpawnKilled() + { + for ( int i = m_Spawned.Count - 1; i >= 0; i-- ) + { + if ( !m_Spawned[ i ].Alive || m_Spawned[ i ].Deleted ) + m_Spawned.RemoveAt( i ); + } + + return m_Spawned.Count < 2; + } + + public SolenAntHole( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteMobileList( m_Spawned ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Spawned = reader.ReadStrongMobileList(); + } + } +} diff --git a/Scripts/Items/Addons/SpinningwheelEastAddon.cs b/Scripts/Items/Addons/SpinningwheelEastAddon.cs new file mode 100644 index 0000000..3a7e4a1 --- /dev/null +++ b/Scripts/Items/Addons/SpinningwheelEastAddon.cs @@ -0,0 +1,147 @@ +using System; +using Server; + +namespace Server.Items +{ + public delegate void SpinCallback( ISpinningWheel sender, Mobile from, int hue ); + + public interface ISpinningWheel + { + bool Spinning{ get; } + void BeginSpin( SpinCallback callback, Mobile from, int hue ); + } + + public class SpinningwheelEastAddon : BaseAddon, ISpinningWheel + { + public override BaseAddonDeed Deed{ get{ return new SpinningwheelEastDeed(); } } + + [Constructable] + public SpinningwheelEastAddon() + { + AddComponent( new AddonComponent( 0x1019 ), 0, 0, 0 ); + } + + public SpinningwheelEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private Timer m_Timer; + + public override void OnComponentLoaded( AddonComponent c ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + public bool Spinning{ get{ return m_Timer != null; } } + + public void BeginSpin( SpinCallback callback, Mobile from, int hue ) + { + m_Timer = new SpinTimer( this, callback, from, hue ); + m_Timer.Start(); + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1015: + case 0x1019: + case 0x101C: + case 0x10A4: ++c.ItemID; break; + } + } + } + + public void EndSpin( SpinCallback callback, Mobile from, int hue ) + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + if ( callback != null ) + callback( this, from, hue ); + } + + private class SpinTimer : Timer + { + private SpinningwheelEastAddon m_Wheel; + private SpinCallback m_Callback; + private Mobile m_From; + private int m_Hue; + + public SpinTimer( SpinningwheelEastAddon wheel, SpinCallback callback, Mobile from, int hue ) : base( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Wheel = wheel; + m_Callback = callback; + m_From = from; + m_Hue = hue; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Wheel.EndSpin( m_Callback, m_From, m_Hue ); + } + } + } + + public class SpinningwheelEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SpinningwheelEastAddon(); } } + public override int LabelNumber{ get{ return 1044341; } } // spining wheel (east) + + [Constructable] + public SpinningwheelEastDeed() + { + } + + public SpinningwheelEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SpinningwheelSouthAddon.cs b/Scripts/Items/Addons/SpinningwheelSouthAddon.cs new file mode 100644 index 0000000..3f8e40b --- /dev/null +++ b/Scripts/Items/Addons/SpinningwheelSouthAddon.cs @@ -0,0 +1,139 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpinningwheelSouthAddon : BaseAddon, ISpinningWheel + { + public override BaseAddonDeed Deed{ get{ return new SpinningwheelSouthDeed(); } } + + [Constructable] + public SpinningwheelSouthAddon() + { + AddComponent( new AddonComponent( 0x1015 ), 0, 0, 0 ); + } + + public SpinningwheelSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private Timer m_Timer; + + public override void OnComponentLoaded( AddonComponent c ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + public bool Spinning{ get{ return m_Timer != null; } } + + public void BeginSpin( SpinCallback callback, Mobile from, int hue ) + { + m_Timer = new SpinTimer( this, callback, from, hue ); + m_Timer.Start(); + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1015: + case 0x1019: + case 0x101C: + case 0x10A4: ++c.ItemID; break; + } + } + } + + public void EndSpin( SpinCallback callback, Mobile from, int hue ) + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + foreach ( AddonComponent c in Components ) + { + switch ( c.ItemID ) + { + case 0x1016: + case 0x101A: + case 0x101D: + case 0x10A5: --c.ItemID; break; + } + } + + if ( callback != null ) + callback( this, from, hue ); + } + + private class SpinTimer : Timer + { + private SpinningwheelSouthAddon m_Wheel; + private SpinCallback m_Callback; + private Mobile m_From; + private int m_Hue; + + public SpinTimer( SpinningwheelSouthAddon wheel, SpinCallback callback, Mobile from, int hue ) : base( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Wheel = wheel; + m_Callback = callback; + m_From = from; + m_Hue = hue; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Wheel.EndSpin( m_Callback, m_From, m_Hue ); + } + } + } + + public class SpinningwheelSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SpinningwheelSouthAddon(); } } + public override int LabelNumber{ get{ return 1044342; } } // spining wheel (south) + + [Constructable] + public SpinningwheelSouthDeed() + { + } + + public SpinningwheelSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SquirrelStatueEastAddon.cs b/Scripts/Items/Addons/SquirrelStatueEastAddon.cs new file mode 100644 index 0000000..4894240 --- /dev/null +++ b/Scripts/Items/Addons/SquirrelStatueEastAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SquirrelStatueEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SquirrelStatueEastDeed(); } } + + [Constructable] + public SquirrelStatueEastAddon() + { + AddComponent( new AddonComponent( 0x2D10 ), 0, 0, 0 ); + } + + public SquirrelStatueEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SquirrelStatueEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SquirrelStatueEastAddon(); } } + public override int LabelNumber{ get{ return 1073398; } } // squirrel statue (east) + + [Constructable] + public SquirrelStatueEastDeed() + { + } + + public SquirrelStatueEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/SquirrelStatueSouthAddon.cs b/Scripts/Items/Addons/SquirrelStatueSouthAddon.cs new file mode 100644 index 0000000..410d72d --- /dev/null +++ b/Scripts/Items/Addons/SquirrelStatueSouthAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SquirrelStatueSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SquirrelStatueSouthDeed(); } } + + [Constructable] + public SquirrelStatueSouthAddon() + { + AddComponent( new AddonComponent( 0x2D11 ), 0, 0, 0 ); + } + + public SquirrelStatueSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SquirrelStatueSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SquirrelStatueSouthAddon(); } } + public override int LabelNumber{ get{ return 1072884; } } // squirrel statue (south) + + [Constructable] + public SquirrelStatueSouthDeed() + { + } + + public SquirrelStatueSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/StoneFireplaceEastAddon.cs b/Scripts/Items/Addons/StoneFireplaceEastAddon.cs new file mode 100644 index 0000000..db25ce3 --- /dev/null +++ b/Scripts/Items/Addons/StoneFireplaceEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StoneFireplaceEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new StoneFireplaceEastDeed(); } } + + [Constructable] + public StoneFireplaceEastAddon() + { + AddComponent( new AddonComponent( 0x959 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x953 ), 0, 1, 0 ); + } + + public StoneFireplaceEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StoneFireplaceEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new StoneFireplaceEastAddon(); } } + public override int LabelNumber{ get{ return 1061848; } } // stone fireplace (east) + + [Constructable] + public StoneFireplaceEastDeed() + { + } + + public StoneFireplaceEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/StoneFireplaceSouthAddon.cs b/Scripts/Items/Addons/StoneFireplaceSouthAddon.cs new file mode 100644 index 0000000..4165491 --- /dev/null +++ b/Scripts/Items/Addons/StoneFireplaceSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StoneFireplaceSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new StoneFireplaceSouthDeed(); } } + + [Constructable] + public StoneFireplaceSouthAddon() + { + AddComponent( new AddonComponent( 0x967 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x961 ), 0, 0, 0 ); + } + + public StoneFireplaceSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StoneFireplaceSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new StoneFireplaceSouthAddon(); } } + public override int LabelNumber{ get{ return 1061849; } } // stone fireplace (south) + + [Constructable] + public StoneFireplaceSouthDeed() + { + } + + public StoneFireplaceSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/StoneFountainAddon.cs b/Scripts/Items/Addons/StoneFountainAddon.cs new file mode 100644 index 0000000..16468b1 --- /dev/null +++ b/Scripts/Items/Addons/StoneFountainAddon.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StoneFountainAddon : BaseAddon + { + [Constructable] + public StoneFountainAddon() + { + int itemID = 0x1731; + + AddComponent( new AddonComponent( itemID++ ), -2, +1, 0 ); + AddComponent( new AddonComponent( itemID++ ), -1, +1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +0, +1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +1, +1, 0 ); + + AddComponent( new AddonComponent( itemID++ ), +1, +0, 0 ); + AddComponent( new AddonComponent( itemID++ ), +1, -1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +1, -2, 0 ); + + AddComponent( new AddonComponent( itemID++ ), +0, -2, 0 ); + AddComponent( new AddonComponent( itemID++ ), +0, -1, 0 ); + AddComponent( new AddonComponent( itemID++ ), +0, +0, 0 ); + + AddComponent( new AddonComponent( itemID++ ), -1, +0, 0 ); + AddComponent( new AddonComponent( itemID++ ), -2, +0, 0 ); + + AddComponent( new AddonComponent( itemID++ ), -2, -1, 0 ); + AddComponent( new AddonComponent( itemID++ ), -1, -1, 0 ); + + AddComponent( new AddonComponent( itemID++ ), -1, -2, 0 ); + AddComponent( new AddonComponent( ++itemID ), -2, -2, 0 ); + } + + public StoneFountainAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/StoneOvenEastAddon.cs b/Scripts/Items/Addons/StoneOvenEastAddon.cs new file mode 100644 index 0000000..e948916 --- /dev/null +++ b/Scripts/Items/Addons/StoneOvenEastAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StoneOvenEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new StoneOvenEastDeed(); } } + + [Constructable] + public StoneOvenEastAddon() + { + AddComponent( new AddonComponent( 0x92C ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x92B ), 0, 1, 0 ); + } + + public StoneOvenEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StoneOvenEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new StoneOvenEastAddon(); } } + public override int LabelNumber{ get{ return 1044345; } } // stone oven (east) + + [Constructable] + public StoneOvenEastDeed() + { + } + + public StoneOvenEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/StoneOvenSouthAddon.cs b/Scripts/Items/Addons/StoneOvenSouthAddon.cs new file mode 100644 index 0000000..49b477f --- /dev/null +++ b/Scripts/Items/Addons/StoneOvenSouthAddon.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StoneOvenSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new StoneOvenSouthDeed(); } } + + [Constructable] + public StoneOvenSouthAddon() + { + AddComponent( new AddonComponent( 0x931 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x930 ), 0, 0, 0 ); + } + + public StoneOvenSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StoneOvenSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new StoneOvenSouthAddon(); } } + public override int LabelNumber{ get{ return 1044346; } } // stone oven (south) + + [Constructable] + public StoneOvenSouthDeed() + { + } + + public StoneOvenSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/StretchedHides.cs b/Scripts/Items/Addons/StretchedHides.cs new file mode 100644 index 0000000..e124007 --- /dev/null +++ b/Scripts/Items/Addons/StretchedHides.cs @@ -0,0 +1,237 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SmallStretchedHideEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SmallStretchedHideEastDeed(); } } + + [Constructable] + public SmallStretchedHideEastAddon() + { + AddComponent( new AddonComponent( 0x1069 ), 0, 0, 0 ); + } + + public SmallStretchedHideEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallStretchedHideEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SmallStretchedHideEastAddon(); } } + public override int LabelNumber{ get{ return 1049401; } } // a small stretched hide deed facing east + + [Constructable] + public SmallStretchedHideEastDeed() + { + } + + public SmallStretchedHideEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallStretchedHideSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new SmallStretchedHideSouthDeed(); } } + + [Constructable] + public SmallStretchedHideSouthAddon() + { + AddComponent( new AddonComponent( 0x107A ), 0, 0, 0 ); + } + + public SmallStretchedHideSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallStretchedHideSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new SmallStretchedHideSouthAddon(); } } + public override int LabelNumber{ get{ return 1049402; } } // a small stretched hide deed facing south + + [Constructable] + public SmallStretchedHideSouthDeed() + { + } + + public SmallStretchedHideSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumStretchedHideEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new MediumStretchedHideEastDeed(); } } + + [Constructable] + public MediumStretchedHideEastAddon() + { + AddComponent( new AddonComponent( 0x106B ), 0, 0, 0 ); + } + + public MediumStretchedHideEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumStretchedHideEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new MediumStretchedHideEastAddon(); } } + public override int LabelNumber{ get{ return 1049403; } } // a medium stretched hide deed facing east + + [Constructable] + public MediumStretchedHideEastDeed() + { + } + + public MediumStretchedHideEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumStretchedHideSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new MediumStretchedHideSouthDeed(); } } + + [Constructable] + public MediumStretchedHideSouthAddon() + { + AddComponent( new AddonComponent( 0x107C ), 0, 0, 0 ); + } + + public MediumStretchedHideSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumStretchedHideSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new MediumStretchedHideSouthAddon(); } } + public override int LabelNumber{ get{ return 1049404; } } // a medium stretched hide deed facing south + + [Constructable] + public MediumStretchedHideSouthDeed() + { + } + + public MediumStretchedHideSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/TallElvenBedEastAddon.cs b/Scripts/Items/Addons/TallElvenBedEastAddon.cs new file mode 100644 index 0000000..686dbb6 --- /dev/null +++ b/Scripts/Items/Addons/TallElvenBedEastAddon.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TallElvenBedEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new TallElvenBedEastDeed(); } } + + [Constructable] + public TallElvenBedEastAddon() + { + AddComponent( new AddonComponent( 0x3054 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3053 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x3055 ), 2, -1, 0 ); + AddComponent( new AddonComponent( 0x3052 ), 2, 0, 0 ); + } + + public TallElvenBedEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TallElvenBedEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new TallElvenBedEastAddon(); } } + public override int LabelNumber{ get{ return 1072859; } } // tall elven bed (east) + + [Constructable] + public TallElvenBedEastDeed() + { + } + + public TallElvenBedEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/TallElvenBedSouthAddon.cs b/Scripts/Items/Addons/TallElvenBedSouthAddon.cs new file mode 100644 index 0000000..5749c24 --- /dev/null +++ b/Scripts/Items/Addons/TallElvenBedSouthAddon.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TallElvenBedSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new TallElvenBedSouthDeed(); } } + + [Constructable] + public TallElvenBedSouthAddon() + { + AddComponent( new AddonComponent( 0x3058 ), 0, 0, 0 ); // angolo alto sx + AddComponent( new AddonComponent( 0x3057 ), -1, 1, 0 ); // angolo basso sx + AddComponent( new AddonComponent( 0x3059 ), 0, -1, 0 ); // angolo alto dx + AddComponent( new AddonComponent( 0x3056 ), 0, 1, 0 ); // angolo basso dx + } + + public TallElvenBedSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TallElvenBedSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new TallElvenBedSouthAddon(); } } + public override int LabelNumber{ get{ return 1072858; } } // tall elven bed (south) + + [Constructable] + public TallElvenBedSouthDeed() + { + } + + public TallElvenBedSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/Telescope.cs b/Scripts/Items/Addons/Telescope.cs new file mode 100644 index 0000000..9345c1c --- /dev/null +++ b/Scripts/Items/Addons/Telescope.cs @@ -0,0 +1,106 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Telescope : BaseAddon + { + [Constructable] + public Telescope() + { + AddComponent( new AddonComponent( 0x1494 ), 0, 5, 0 ); + AddComponent( new AddonComponent( 0x145B ), 0, 6, 0 ); + AddComponent( new AddonComponent( 0x145A ), 0, 7, 0 ); + + AddComponent( new AddonComponent( 0x1495 ), 1, 4, 0 ); + AddComponent( new AddonComponent( 0x145C ), 1, 7, 0 ); + AddComponent( new AddonComponent( 0x145D ), 1, 8, 0 ); + + AddComponent( new AddonComponent( 0x1496 ), 2, 3, 0 ); + AddComponent( new AddonComponent( 0x1499 ), 2, 4, 0 ); + AddComponent( new AddonComponent( 0x148E ), 2, 6, 0 ); + AddComponent( new AddonComponent( 0x1493 ), 2, 7, 0 ); + AddComponent( new AddonComponent( 0x1492 ), 2, 8, 0 ); + AddComponent( new AddonComponent( 0x145E ), 2, 9, 0 ); + AddComponent( new AddonComponent( 0x1459 ), 2,10, 0 ); + + AddComponent( new AddonComponent( 0x1497 ), 3, 2, 0 ); + AddComponent( new AddonComponent( 0x145F ), 3, 9, 0 ); + AddComponent( new AddonComponent( 0x1461 ), 3,10, 0 ); + + AddComponent( new AddonComponent( 0x149A ), 4, 1, 0 ); + AddComponent( new AddonComponent( 0x1498 ), 4, 2, 0 ); + AddComponent( new AddonComponent( 0x148F ), 4, 4, 0 ); + AddComponent( new AddonComponent( 0x148D ), 4, 6, 0 ); + AddComponent( new AddonComponent( 0x1488 ), 4, 8, 0 ); + AddComponent( new AddonComponent( 0x1460 ), 4, 9, 0 ); + AddComponent( new AddonComponent( 0x1462 ), 4,10, 0 ); + + AddComponent( new AddonComponent( 0x147D ), 5, 0, 0 ); + AddComponent( new AddonComponent( 0x1490 ), 5, 4, 0 ); + AddComponent( new AddonComponent( 0x148B ), 5, 5, 0 ); + AddComponent( new AddonComponent( 0x148A ), 5, 6, 0 ); + AddComponent( new AddonComponent( 0x1486 ), 5, 7, 0 ); + AddComponent( new AddonComponent( 0x1485 ), 5, 8, 0 ); + + AddComponent( new AddonComponent( 0x147C ), 6, 0, 0 ); + AddComponent( new AddonComponent( 0x1491 ), 6, 4, 0 ); + AddComponent( new AddonComponent( 0x148C ), 6, 5, 0 ); + AddComponent( new AddonComponent( 0x1489 ), 6, 6, 0 ); + AddComponent( new AddonComponent( 0x1487 ), 6, 7, 0 ); + AddComponent( new AddonComponent( 0x1484 ), 6, 8, 0 ); + AddComponent( new AddonComponent( 0x1463 ), 6,10, 0 ); + + AddComponent( new AddonComponent( 0x147B ), 7, 0, 0 ); + AddComponent( new AddonComponent( 0x147F ), 7, 3, 0 ); + AddComponent( new AddonComponent( 0x1480 ), 7, 4, 0 ); + AddComponent( new AddonComponent( 0x1482 ), 7, 5, 0 ); + AddComponent( new AddonComponent( 0x1469 ), 7, 6, 0 ); + AddComponent( new AddonComponent( 0x1468 ), 7, 7, 0 ); + AddComponent( new AddonComponent( 0x1465 ), 7, 8, 0 ); + AddComponent( new AddonComponent( 0x1464 ), 7, 9, 0 ); + + AddComponent( new AddonComponent( 0x147A ), 8, 0, 0 ); + AddComponent( new AddonComponent( 0x1479 ), 8, 1, 0 ); + AddComponent( new AddonComponent( 0x1477 ), 8, 2, 0 ); + AddComponent( new AddonComponent( 0x147E ), 8, 3, 0 ); + AddComponent( new AddonComponent( 0x1481 ), 8, 4, 0 ); + AddComponent( new AddonComponent( 0x1483 ), 8, 5, 0 ); + AddComponent( new AddonComponent( 0x146A ), 8, 6, 0 ); + AddComponent( new AddonComponent( 0x1467 ), 8, 7, 0 ); + AddComponent( new AddonComponent( 0x1466 ), 8, 8, 0 ); + + AddComponent( new AddonComponent( 0x1478 ), 9, 1, 0 ); + AddComponent( new AddonComponent( 0x1475 ), 9, 2, 0 ); + AddComponent( new AddonComponent( 0x1474 ), 9, 3, 0 ); + AddComponent( new AddonComponent( 0x146F ), 9, 4, 0 ); + AddComponent( new AddonComponent( 0x146E ), 9, 5, 0 ); + AddComponent( new AddonComponent( 0x146D ), 9, 6, 0 ); + AddComponent( new AddonComponent( 0x146B ), 9, 7, 0 ); + + AddComponent( new AddonComponent( 0x1476 ),10, 2, 0 ); + AddComponent( new AddonComponent( 0x1473 ),10, 3, 0 ); + AddComponent( new AddonComponent( 0x1470 ),10, 4, 0 ); + AddComponent( new AddonComponent( 0x1471 ),10, 5, 0 ); + AddComponent( new AddonComponent( 0x1472 ),10, 6, 0 ); + } + + public Telescope( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/TrainingDummies.cs b/Scripts/Items/Addons/TrainingDummies.cs new file mode 100644 index 0000000..0937d85 --- /dev/null +++ b/Scripts/Items/Addons/TrainingDummies.cs @@ -0,0 +1,284 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1070, 0x1074 )] + public class TrainingDummy : AddonComponent + { + private double m_MinSkill; + private double m_MaxSkill; + + private Timer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public double MinSkill + { + get{ return m_MinSkill; } + set{ m_MinSkill = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public double MaxSkill + { + get{ return m_MaxSkill; } + set{ m_MaxSkill = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Swinging + { + get{ return ( m_Timer != null ); } + } + + [Constructable] + public TrainingDummy() : this( 0x1074 ) + { + } + + [Constructable] + public TrainingDummy( int itemID ) : base( itemID ) + { + m_MinSkill = -25.0; + m_MaxSkill = +25.0; + } + + public void UpdateItemID() + { + int baseItemID = (ItemID / 2) * 2; + + ItemID = baseItemID + (Swinging ? 1 : 0); + } + + public void BeginSwing() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + } + + public void EndSwing() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + UpdateItemID(); + } + + public void OnHit() + { + UpdateItemID(); + Effects.PlaySound( GetWorldLocation(), Map, Utility.RandomList( 0x3A4, 0x3A6, 0x3A9, 0x3AE, 0x3B4, 0x3B6 ) ); + } + + public void Use( Mobile from, BaseWeapon weapon ) + { + BeginSwing(); + + from.Direction = from.GetDirectionTo( GetWorldLocation() ); + weapon.PlaySwingAnimation( from ); + + from.CheckSkill( weapon.Skill, m_MinSkill, m_MaxSkill ); + } + + public override void OnDoubleClick( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon is BaseRanged ) + SendLocalizedMessageTo( from, 501822 ); // You can't practice ranged weapons on this. + else if ( weapon == null || !from.InRange( GetWorldLocation(), weapon.MaxRange ) ) + SendLocalizedMessageTo( from, 501816 ); // You are too far away to do that. + else if ( Swinging ) + SendLocalizedMessageTo( from, 501815 ); // You have to wait until it stops swinging. + else if ( from.Skills[weapon.Skill].Base >= m_MaxSkill ) + SendLocalizedMessageTo( from, 501828 ); // Your skill cannot improve any further by simply practicing with a dummy. + else if ( from.Mounted ) + SendLocalizedMessageTo( from, 501829 ); // You can't practice on this while on a mount. + else + Use( from, weapon ); + } + + public TrainingDummy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_MinSkill ); + writer.Write( m_MaxSkill ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_MinSkill = reader.ReadDouble(); + m_MaxSkill = reader.ReadDouble(); + + if ( m_MinSkill == 0.0 && m_MaxSkill == 30.0 ) + { + m_MinSkill = -25.0; + m_MaxSkill = +25.0; + } + + break; + } + } + + UpdateItemID(); + } + + private class InternalTimer : Timer + { + private TrainingDummy m_Dummy; + private bool m_Delay = true; + + public InternalTimer( TrainingDummy dummy ) : base( TimeSpan.FromSeconds( 0.25 ), TimeSpan.FromSeconds( 2.75 ) ) + { + m_Dummy = dummy; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Delay ) + m_Dummy.OnHit(); + else + m_Dummy.EndSwing(); + + m_Delay = !m_Delay; + } + } + } + + public class TrainingDummyEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new TrainingDummyEastDeed(); } } + + [Constructable] + public TrainingDummyEastAddon() + { + AddComponent( new TrainingDummy( 0x1074 ), 0, 0, 0 ); + } + + public TrainingDummyEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TrainingDummyEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new TrainingDummyEastAddon(); } } + public override int LabelNumber{ get{ return 1044335; } } // training dummy (east) + + [Constructable] + public TrainingDummyEastDeed() + { + } + + public TrainingDummyEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TrainingDummySouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new TrainingDummySouthDeed(); } } + + [Constructable] + public TrainingDummySouthAddon() + { + AddComponent( new TrainingDummy( 0x1070 ), 0, 0, 0 ); + } + + public TrainingDummySouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TrainingDummySouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new TrainingDummySouthAddon(); } } + public override int LabelNumber{ get{ return 1044336; } } // training dummy (south) + + [Constructable] + public TrainingDummySouthDeed() + { + } + + public TrainingDummySouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/WarriorStatueEastAddon.cs b/Scripts/Items/Addons/WarriorStatueEastAddon.cs new file mode 100644 index 0000000..0dd669c --- /dev/null +++ b/Scripts/Items/Addons/WarriorStatueEastAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WarriorStatueEastAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new WarriorStatueEastDeed(); } } + + [Constructable] + public WarriorStatueEastAddon() + { + AddComponent( new AddonComponent( 0x2D12 ), 0, 0, 0 ); + } + + public WarriorStatueEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class WarriorStatueEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new WarriorStatueEastAddon(); } } + public override int LabelNumber{ get{ return 1072888; } } // warrior statue (east) + + [Constructable] + public WarriorStatueEastDeed() + { + } + + public WarriorStatueEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/WarriorStatueSouthAddon.cs b/Scripts/Items/Addons/WarriorStatueSouthAddon.cs new file mode 100644 index 0000000..3ba7631 --- /dev/null +++ b/Scripts/Items/Addons/WarriorStatueSouthAddon.cs @@ -0,0 +1,63 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WarriorStatueSouthAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new WarriorStatueSouthDeed(); } } + + [Constructable] + public WarriorStatueSouthAddon() + { + AddComponent( new AddonComponent( 0x2D13 ), 0, 0, 0 ); + } + + public WarriorStatueSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class WarriorStatueSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new WarriorStatueSouthAddon(); } } + public override int LabelNumber{ get{ return 1072887; } } // warrior statue (south) + + [Constructable] + public WarriorStatueSouthDeed() + { + } + + public WarriorStatueSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/WaterTroughEastAddon.cs b/Scripts/Items/Addons/WaterTroughEastAddon.cs new file mode 100644 index 0000000..acd64de --- /dev/null +++ b/Scripts/Items/Addons/WaterTroughEastAddon.cs @@ -0,0 +1,70 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WaterTroughEastAddon : BaseAddon, IWaterSource + { + public override BaseAddonDeed Deed{ get{ return new WaterTroughEastDeed(); } } + + [Constructable] + public WaterTroughEastAddon() + { + AddComponent( new AddonComponent( 0xB41 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xB42 ), 0, 1, 0 ); + } + + public WaterTroughEastAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public int Quantity + { + get{ return 500; } + set{} + } + } + + public class WaterTroughEastDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new WaterTroughEastAddon(); } } + public override int LabelNumber{ get{ return 1044349; } } // water trough (east) + + [Constructable] + public WaterTroughEastDeed() + { + } + + public WaterTroughEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/WaterTroughSouthAddon.cs b/Scripts/Items/Addons/WaterTroughSouthAddon.cs new file mode 100644 index 0000000..f2826a4 --- /dev/null +++ b/Scripts/Items/Addons/WaterTroughSouthAddon.cs @@ -0,0 +1,70 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WaterTroughSouthAddon : BaseAddon, IWaterSource + { + public override BaseAddonDeed Deed{ get{ return new WaterTroughSouthDeed(); } } + + [Constructable] + public WaterTroughSouthAddon() + { + AddComponent( new AddonComponent( 0xB43 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0xB44 ), 1, 0, 0 ); + } + + public WaterTroughSouthAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public int Quantity + { + get{ return 500; } + set{} + } + } + + public class WaterTroughSouthDeed : BaseAddonDeed + { + public override BaseAddon Addon{ get{ return new WaterTroughSouthAddon(); } } + public override int LabelNumber{ get{ return 1044350; } } // water trough (south) + + [Constructable] + public WaterTroughSouthDeed() + { + } + + public WaterTroughSouthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Addons/WaterVat.cs b/Scripts/Items/Addons/WaterVat.cs new file mode 100644 index 0000000..9cb23b6 --- /dev/null +++ b/Scripts/Items/Addons/WaterVat.cs @@ -0,0 +1,87 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WaterVatEast : BaseAddon + { + [Constructable] + public WaterVatEast() + { + AddComponent( new AddonComponent( 0x1558 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x14DE ), -1, 1, 0 ); + AddComponent( new AddonComponent( 0x1552 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x14DF ), 1, -1, 0 ); + AddComponent( new AddonComponent( 0x1554 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1559 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1550 ), 1, 3, 0 ); + AddComponent( new AddonComponent( 0x1555 ), 3, 1, 0 ); + AddComponent( new AddonComponent( 0x14D7 ), 2, 2, 0 ); + + // Blockers + AddComponent( new AddonComponent( 0x21A4 ), 2, -1, 0 ); + AddComponent( new AddonComponent( 0x21A4 ), 3, 0, 0 ); + AddComponent( new AddonComponent( 0x21A4 ), -1, 2, 0 ); + AddComponent( new AddonComponent( 0x21A4 ), 0, 3, 0 ); + } + + public WaterVatEast( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class WaterVatSouth : BaseAddon + { + [Constructable] + public WaterVatSouth() + { + AddComponent( new AddonComponent( 0x1558 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x14DE ), -1, 1, 0 ); + AddComponent( new AddonComponent( 0x1552 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x14DF ), 1, -1, 0 ); + AddComponent( new AddonComponent( 0x1554 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1559 ), 1, 1, 0 ); + AddComponent( new AddonComponent( 0x1551 ), 1, 3, 0 ); + AddComponent( new AddonComponent( 0x1556 ), 3, 1, 0 ); + AddComponent( new AddonComponent( 0x14D7 ), 2, 2, 0 ); + + // Blockers + AddComponent( new AddonComponent( 0x21A4 ), 2, -1, 0 ); + AddComponent( new AddonComponent( 0x21A4 ), 3, 0, 0 ); + AddComponent( new AddonComponent( 0x21A4 ), -1, 2, 0 ); + AddComponent( new AddonComponent( 0x21A4 ), 0, 3, 0 ); + } + + public WaterVatSouth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Aquarium/Aquarium.cs b/Scripts/Items/Aquarium/Aquarium.cs new file mode 100644 index 0000000..967a6e8 --- /dev/null +++ b/Scripts/Items/Aquarium/Aquarium.cs @@ -0,0 +1,1166 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Multis; +using Server.Network; +using Server.Gumps; +using Server.ContextMenus; + +namespace Server.Items +{ + public class Aquarium : BaseAddonContainer + { + public static readonly TimeSpan EvaluationInterval = TimeSpan.FromDays( 1 ); + + // items info + private int m_LiveCreatures; + + [CommandProperty( AccessLevel.GameMaster )] + public int LiveCreatures + { + get{ return m_LiveCreatures; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DeadCreatures + { + get + { + int dead = 0; + + for ( int i = 0; i < Items.Count; i ++ ) + { + if ( Items[ i ] is BaseFish ) + { + BaseFish fish = (BaseFish) Items[ i ]; + + if ( fish.Dead ) + dead += 1; + } + } + + return dead; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxLiveCreatures + { + get + { + int state = ( m_Food.State == (int) FoodState.Overfed ) ? 1 : (int) FoodState.Full - m_Food.State; + + state += (int) WaterState.Strong - m_Water.State; + + state = (int) Math.Pow( state, 1.75 ); + + return MaxItems - state; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsFull + { + get{ return ( Items.Count >= MaxItems ); } + } + + // vacation info + private int m_VacationLeft; + + [CommandProperty( AccessLevel.GameMaster )] + public int VacationLeft + { + get{ return m_VacationLeft; } + set{ m_VacationLeft = value; InvalidateProperties(); } + } + + // aquarium state + private AquariumState m_Food; + private AquariumState m_Water; + + [CommandProperty( AccessLevel.GameMaster )] + public AquariumState Food + { + get{ return m_Food; } + set{ m_Food = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public AquariumState Water + { + get{ return m_Water; } + set{ m_Water = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool OptimalState + { + get{ return ( m_Food.State == (int) FoodState.Full && m_Water.State == (int) WaterState.Strong ); } + } + + // events + private List m_Events; + private bool m_RewardAvailable; + private bool m_EvaluateDay; + + public List Events + { + get{ return m_Events; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RewardAvailable + { + get{ return m_RewardAvailable; } + set{ m_RewardAvailable = value; InvalidateProperties(); } + } + + // evaluate timer + private Timer m_Timer; + + public override BaseAddonContainerDeed Deed + { + get + { + if ( ItemID == 0x3062 ) + return new AquariumEastDeed(); + else + return new AquariumNorthDeed(); + } + } + + public override double DefaultWeight{ get{ return 10.0; } } + + public Aquarium( int itemID ) : base( itemID ) + { + Movable = false; + + if ( itemID == 0x3060 ) + AddComponent( new AddonContainerComponent( 0x3061 ), -1, 0, 0 ); + + if ( itemID == 0x3062 ) + AddComponent( new AddonContainerComponent( 0x3063 ), 0, -1, 0 ); + + MaxItems = 30; + + m_Food = new AquariumState(); + m_Water = new AquariumState(); + + m_Food.State = (int) FoodState.Full; + m_Water.State = (int) WaterState.Strong; + + m_Food.Maintain = Utility.RandomMinMax( 1, 2 ); + m_Food.Improve = m_Food.Maintain + Utility.RandomMinMax( 1, 2 ); + + m_Water.Maintain = Utility.RandomMinMax( 1, 3 ); + + m_Events = new List(); + + m_Timer = Timer.DelayCall( EvaluationInterval, EvaluationInterval, new TimerCallback( Evaluate ) ); + } + + public Aquarium( Serial serial ) : base( serial ) + { + } + + public override void OnDelete() + { + if ( m_Timer != null ) + { + m_Timer.Stop(); + m_Timer = null; + } + } + + public override void OnDoubleClick( Mobile from ) + { + ExamineAquarium( from ); + } + + public virtual bool HasAccess( Mobile from ) + { + if ( from == null || from.Deleted ) + return false; + else if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + return ( house != null && house.IsCoOwner( from ) ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( !HasAccess( from ) ) + { + from.SendLocalizedMessage( 1073821 ); // You do not have access to that item for use with the aquarium. + return false; + } + + if ( m_VacationLeft > 0 ) + { + from.SendLocalizedMessage( 1074427 ); // The aquarium is in vacation mode. + return false; + } + + bool takeItem = true; + + if ( dropped is FishBowl ) + { + FishBowl bowl = (FishBowl) dropped; + + if ( bowl.Empty || !AddFish( from, bowl.Fish ) ) + return false; + + bowl.InvalidateProperties(); + + takeItem = false; + } + else if ( dropped is BaseFish ) + { + BaseFish fish = (BaseFish) dropped; + + if ( !AddFish( from, fish ) ) + return false; + } + else if ( dropped is VacationWafer ) + { + m_VacationLeft = VacationWafer.VacationDays; + dropped.Delete(); + + from.SendLocalizedMessage( 1074428, m_VacationLeft.ToString() ); // The aquarium will be in vacation mode for ~1_DAYS~ days + } + else if ( dropped is AquariumFood ) + { + m_Food.Added += 1; + dropped.Delete(); + + from.SendLocalizedMessage( 1074259, "1" ); // ~1_NUM~ unit(s) of food have been added to the aquarium. + } + else if ( dropped is BaseBeverage ) + { + BaseBeverage beverage = (BaseBeverage) dropped; + + if ( beverage.IsEmpty || !beverage.Pourable || beverage.Content != BeverageType.Water ) + { + from.SendLocalizedMessage( 500840 ); // Can't pour that in there. + return false; + } + + m_Water.Added += 1; + beverage.Quantity -= 1; + + from.PlaySound( 0x4E ); + from.SendLocalizedMessage( 1074260, "1" ); // ~1_NUM~ unit(s) of water have been added to the aquarium. + + takeItem = false; + } + else if ( !AddDecoration( from, dropped ) ) + { + takeItem = false; + } + + from.CloseGump( typeof( AquariumGump ) ); + + InvalidateProperties(); + + if ( takeItem ) + from.PlaySound( 0x42 ); + + return takeItem; + } + + public override void DropItemsToGround() + { + Point3D loc = GetWorldLocation(); + + for ( int i = Items.Count - 1; i >= 0; i-- ) + { + Item item = Items[ i ]; + + item.MoveToWorld( loc, Map ); + + if ( item is BaseFish ) + { + BaseFish fish = (BaseFish) item; + + if ( !fish.Dead ) + fish.StartTimer(); + } + } + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( item != this ) + return false; + + return base.CheckItemUse( from, item ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( item != this ) + { + reject = LRReason.CannotLift; + return false; + } + + return base.CheckLift( from, item, ref reject ); + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( m_VacationLeft > 0 ) + list.Add( 1074430, m_VacationLeft.ToString() ); // Vacation days left: ~1_DAYS + + if ( m_Events.Count > 0 ) + list.Add( 1074426, m_Events.Count.ToString() ); // ~1_NUM~ event(s) to view! + + if ( m_RewardAvailable ) + list.Add( 1074362 ); // A reward is available! + + list.Add( 1074247, "{0}\t{1}", m_LiveCreatures, MaxLiveCreatures ); // Live Creatures: ~1_NUM~ / ~2_MAX~ + + int dead = DeadCreatures; + + if ( dead > 0 ) + list.Add( 1074248, dead.ToString() ); // Dead Creatures: ~1_NUM~ + + int decorations = Items.Count - m_LiveCreatures - dead; + + if ( decorations > 0 ) + list.Add( 1074249, decorations.ToString() ); // Decorations: ~1_NUM~ + + list.Add( 1074250, "#{0}", FoodNumber() ); // Food state: ~1_STATE~ + list.Add( 1074251, "#{0}", WaterNumber() ); // Water state: ~1_STATE~ + + if ( m_Food.State == (int) FoodState.Dead ) + list.Add( 1074577, "{0}\t{1}", m_Food.Added, m_Food.Improve ); // Food Added: ~1_CUR~ Needed: ~2_NEED~ + else if ( m_Food.State == (int) FoodState.Overfed ) + list.Add( 1074577, "{0}\t{1}", m_Food.Added, m_Food.Maintain ); // Food Added: ~1_CUR~ Needed: ~2_NEED~ + else + list.Add( 1074253, "{0}\t{1}\t{2}", m_Food.Added, m_Food.Maintain, m_Food.Improve ); // Food Added: ~1_CUR~ Feed: ~2_NEED~ Improve: ~3_GROW~ + + if ( m_Water.State == (int) WaterState.Dead ) + list.Add( 1074578, "{0}\t{1}", m_Water.Added, m_Water.Improve ); // Water Added: ~1_CUR~ Needed: ~2_NEED~ + else if ( m_Water.State == (int) WaterState.Strong ) + list.Add( 1074578, "{0}\t{1}", m_Water.Added, m_Water.Maintain ); // Water Added: ~1_CUR~ Needed: ~2_NEED~ + else + list.Add( 1074254, "{0}\t{1}\t{2}", m_Water.Added, m_Water.Maintain, m_Water.Improve ); // Water Added: ~1_CUR~ Maintain: ~2_NEED~ Improve: ~3_GROW~ + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + { + list.Add( new ExamineEntry( this ) ); + + if ( HasAccess( from ) ) + { + if ( m_RewardAvailable ) + list.Add( new CollectRewardEntry( this ) ); + + if ( m_Events.Count > 0 ) + list.Add( new ViewEventEntry( this ) ); + + if ( m_VacationLeft > 0 ) + list.Add( new CancelVacationMode( this ) ); + } + } + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + list.Add( new GMAddFood( this ) ); + list.Add( new GMAddWater( this ) ); + list.Add( new GMForceEvaluate( this ) ); + list.Add( new GMOpen( this ) ); + list.Add( new GMFill( this ) ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( 3 ); // Version + + // version 1 + if ( m_Timer != null ) + writer.Write( m_Timer.Next ); + else + writer.Write( DateTime.Now + EvaluationInterval ); + + // version 0 + writer.Write( (int) m_LiveCreatures ); + writer.Write( (int) m_VacationLeft ); + + m_Food.Serialize( writer ); + m_Water.Serialize( writer ); + + writer.Write( (int) m_Events.Count ); + + for ( int i = 0; i < m_Events.Count; i ++ ) + writer.Write( (int) m_Events[ i ] ); + + writer.Write( (bool) m_RewardAvailable ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + case 2: + case 1: + { + DateTime next = reader.ReadDateTime(); + + if ( next < DateTime.Now ) + next = DateTime.Now; + + m_Timer = Timer.DelayCall( next - DateTime.Now, EvaluationInterval, new TimerCallback( Evaluate ) ); + + goto case 0; + } + case 0: + { + m_LiveCreatures = reader.ReadInt(); + m_VacationLeft = reader.ReadInt(); + + m_Food = new AquariumState(); + m_Water = new AquariumState(); + + m_Food.Deserialize( reader ); + m_Water.Deserialize( reader ); + + m_Events = new List(); + + int count = reader.ReadInt(); + + for ( int i = 0; i < count; i ++ ) + m_Events.Add( reader.ReadInt() ); + + m_RewardAvailable = reader.ReadBool(); + + break; + } + } + + if ( version < 2 ) + { + Weight = DefaultWeight; + Movable = false; + } + + if ( version < 3 ) + ValidationQueue.Add(this); + } + + private void RecountLiveCreatures() + { + m_LiveCreatures = 0; + List fish = FindItemsByType(); + + foreach ( BaseFish f in fish ) + { + if ( !f.Dead ) + ++m_LiveCreatures; + } + } + + public void Validate() + { + RecountLiveCreatures(); + } + + #region Members + public int FoodNumber() + { + if ( m_Food.State == (int) FoodState.Full ) + return 1074240; + + if ( m_Food.State == (int) FoodState.Overfed ) + return 1074239; + + return 1074236 + m_Food.State; + } + + public int WaterNumber() + { + return 1074242 + m_Water.State; + } + #endregion + + #region Virtual members + public virtual void KillFish( int amount ) + { + List toKill = new List(); + + for ( int i = 0; i < Items.Count; i ++ ) + { + if ( Items[ i ] is BaseFish ) + { + BaseFish fish = (BaseFish) Items[ i ]; + + if ( !fish.Dead ) + toKill.Add( fish ); + } + } + + while ( amount > 0 && toKill.Count > 0 ) + { + int kill = Utility.Random( toKill.Count ); + + toKill[ kill ].Kill(); + + toKill.RemoveAt( kill ); + + amount -= 1; + m_LiveCreatures -= 1; + + if ( m_LiveCreatures < 0 ) + m_LiveCreatures = 0; + + m_Events.Add( 1074366 ); // An unfortunate accident has left a creature floating upside-down. It is starting to smell. + } + } + + public virtual void Evaluate() + { + if ( m_VacationLeft > 0 ) + { + m_VacationLeft -= 1; + } + else if ( m_EvaluateDay ) + { + // reset events + m_Events = new List(); + + // food events + if ( + ( m_Food.Added < m_Food.Maintain && m_Food.State != (int) FoodState.Overfed && m_Food.State != (int) FoodState.Dead ) || + ( m_Food.Added >= m_Food.Improve && m_Food.State == (int) FoodState.Full ) + ) + m_Events.Add( 1074368 ); // The tank looks worse than it did yesterday. + + if ( + ( m_Food.Added >= m_Food.Improve && m_Food.State != (int) FoodState.Full && m_Food.State != (int) FoodState.Overfed ) || + ( m_Food.Added < m_Food.Maintain && m_Food.State == (int) FoodState.Overfed ) + ) + m_Events.Add( 1074367 ); // The tank looks healthier today. + + // water events + if ( m_Water.Added < m_Water.Maintain && m_Water.State != (int) WaterState.Dead ) + m_Events.Add( 1074370 ); // This tank can use more water. + + if ( m_Water.Added >= m_Water.Improve && m_Water.State != (int) WaterState.Strong ) + m_Events.Add( 1074369 ); // The water looks clearer today. + + UpdateFoodState(); + UpdateWaterState(); + + // reward + if ( m_LiveCreatures > 0 ) + m_RewardAvailable = true; + } + else + { + // new fish + if ( OptimalState && m_LiveCreatures < MaxLiveCreatures ) + { + if ( Utility.RandomDouble() < 0.005 * m_LiveCreatures ) + { + BaseFish fish = null; + int message = 0; + + switch ( Utility.Random( 6 ) ) + { + case 0: + { + message = 1074371; // Brine shrimp have hatched overnight in the tank. + fish = new BrineShrimp(); + break; + } + case 1: + { + message = 1074365; // A new creature has hatched overnight in the tank. + fish = new Coral(); + break; + } + case 2: + { + message = 1074365; // A new creature has hatched overnight in the tank. + fish = new FullMoonFish(); + break; + } + case 3: + { + message = 1074373; // A sea horse has hatched overnight in the tank. + fish = new SeaHorseFish(); + break; + } + case 4: + { + message = 1074365; // A new creature has hatched overnight in the tank. + fish = new StrippedFlakeFish(); + break; + } + case 5: + { + message = 1074365; // A new creature has hatched overnight in the tank. + fish = new StrippedSosarianSwill(); + break; + } + } + + if ( Utility.RandomDouble() < 0.05 ) + fish.Hue = m_FishHues[ Utility.Random( m_FishHues.Length ) ]; + else if ( Utility.RandomDouble() < 0.5 ) + fish.Hue = Utility.RandomMinMax( 0x100, 0x3E5 ); + + if ( AddFish( fish ) ) + m_Events.Add( message ); + else + fish.Delete(); + } + } + + // kill fish *grins* + if ( m_LiveCreatures < MaxLiveCreatures ) + { + if ( Utility.RandomDouble() < 0.01 ) + KillFish( 1 ); + } + else + { + KillFish( m_LiveCreatures - MaxLiveCreatures ); + } + } + + m_EvaluateDay = !m_EvaluateDay; + InvalidateProperties(); + } + + public virtual void GiveReward( Mobile to ) + { + if ( !m_RewardAvailable ) + return; + + int max = (int) ( ( (double) m_LiveCreatures / 30 ) * m_Decorations.Length ); + + int random = ( max <= 0 ) ? 0 : Utility.Random( max ); + + if ( random >= m_Decorations.Length ) + random = m_Decorations.Length - 1; + + Item item; + + try + { + item = Activator.CreateInstance( m_Decorations[ random ] ) as Item; + } + catch + { + return; + } + + if ( item == null ) + return; + + if ( !to.PlaceInBackpack( item ) ) + { + item.Delete(); + to.SendLocalizedMessage( 1074361 ); // The reward could not be given. Make sure you have room in your pack. + return; + } + + to.SendLocalizedMessage( 1074360, String.Format( "#{0}", item.LabelNumber ) ); // You receive a reward: ~1_REWARD~ + to.PlaySound( 0x5A3 ); + + m_RewardAvailable = false; + + InvalidateProperties(); + } + + public virtual void UpdateFoodState() + { + if ( m_Food.Added < m_Food.Maintain ) + m_Food.State = ( m_Food.State <= 0 ) ? 0 : m_Food.State - 1; + else if ( m_Food.Added >= m_Food.Improve ) + m_Food.State = ( m_Food.State >= (int) FoodState.Overfed ) ? (int) FoodState.Overfed : m_Food.State + 1; + + m_Food.Maintain = Utility.Random( (int) FoodState.Overfed + 1 - m_Food.State, 2 ); + + if ( m_Food.State == (int) FoodState.Overfed ) + m_Food.Improve = 0; + else + m_Food.Improve = m_Food.Maintain + 2; + + m_Food.Added = 0; + } + + public virtual void UpdateWaterState() + { + if ( m_Water.Added < m_Water.Maintain ) + m_Water.State = ( m_Water.State <= 0 ) ? 0 : m_Water.State - 1; + else if ( m_Water.Added >= m_Water.Improve ) + m_Water.State = ( m_Water.State >= (int) WaterState.Strong ) ? (int) WaterState.Strong : m_Water.State + 1; + + m_Water.Maintain = Utility.Random( (int) WaterState.Strong + 2 - m_Water.State, 2 ); + + if ( m_Water.State == (int) WaterState.Strong ) + m_Water.Improve = 0; + else + m_Water.Improve = m_Water.Maintain + 2; + + m_Water.Added = 0; + } + + public virtual bool RemoveItem( Mobile from, int at ) + { + if ( at < 0 && at >= Items.Count ) + return false; + + Item item = Items[ at ]; + + if ( item.IsLockedDown ) // for legacy aquariums + { + from.SendLocalizedMessage( 1010449 ); // You may not use this object while it is locked down. + return false; + } + + if ( item is BaseFish ) + { + BaseFish fish = (BaseFish) item; + + FishBowl bowl; + + if ( (bowl = GetEmptyBowl( from )) != null ) + { + bowl.AddItem( fish ); + + from.SendLocalizedMessage( 1074511 ); // You put the creature into a fish bowl. + } + else + { + if ( !from.PlaceInBackpack( fish ) ) + { + from.SendLocalizedMessage( 1074514 ); // You have no place to put it. + return false; + } + else + { + from.SendLocalizedMessage( 1074512 ); // You put the gasping creature into your pack. + } + } + + if ( !fish.Dead ) + m_LiveCreatures -= 1; + } + else + { + if ( !from.PlaceInBackpack( item ) ) + { + from.SendLocalizedMessage( 1074514 ); // You have no place to put it. + return false; + } + else + { + from.SendLocalizedMessage( 1074513 ); // You put the item into your pack. + } + } + + InvalidateProperties(); + return true; + } + + public virtual void ExamineAquarium( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + from.CloseGump( typeof( AquariumGump ) ); + from.SendGump( new AquariumGump( this, HasAccess( from ) ) ); + + from.PlaySound( 0x5A4 ); + } + + public virtual bool AddFish( BaseFish fish ) + { + return AddFish( null, fish ); + } + + public virtual bool AddFish( Mobile from, BaseFish fish ) + { + if ( fish == null ) + return false; + + if ( IsFull || m_LiveCreatures >= MaxLiveCreatures || fish.Dead ) + { + if ( from != null ) + from.SendLocalizedMessage( 1073633 ); // The aquarium can not hold the creature. + + return false; + } + + AddItem( fish ); + fish.StopTimer(); + + m_LiveCreatures += 1; + + if ( from != null ) + from.SendLocalizedMessage( 1073632, String.Format( "#{0}", fish.LabelNumber ) ); // You add the following creature to your aquarium: ~1_FISH~ + + InvalidateProperties(); + return true; + } + + public virtual bool AddDecoration( Item item ) + { + return AddDecoration( null, item ); + } + + public virtual bool AddDecoration( Mobile from, Item item ) + { + if ( item == null ) + return false; + + if ( IsFull ) + { + if ( from != null ) + from.SendLocalizedMessage( 1073636 ); // The decoration will not fit in the aquarium. + + return false; + } + + if ( !Accepts( item ) ) + { + if ( from != null ) + from.SendLocalizedMessage( 1073822 ); // The aquarium can not hold that item. + + return false; + } + + AddItem( item ); + + if ( from != null ) + from.SendLocalizedMessage( 1073635, ( item.LabelNumber != 0 ) ? String.Format( "#{0}", item.LabelNumber ) : item.Name ); // You add the following decoration to your aquarium: ~1_NAME~ + + InvalidateProperties(); + return true; + } + #endregion + + #region Static members + public static FishBowl GetEmptyBowl( Mobile from ) + { + if ( from == null || from.Backpack == null ) + return null; + + Item[] items = from.Backpack.FindItemsByType( typeof( FishBowl ) ); + + for ( int i = 0; i < items.Length; i ++ ) + { + if ( items[ i ] is FishBowl ) + { + FishBowl bowl = (FishBowl) items[ i ]; + + if ( bowl.Empty ) + return bowl; + } + } + + return null; + } + + private static Type[] m_Decorations = new Type[] + { + typeof( FishBones ), + typeof( WaterloggedBoots ), + typeof( CaptainBlackheartsFishingPole ), + typeof( CraftysFishingHat ), + typeof( AquariumFishNet ), + typeof( AquariumMessage ), + typeof( IslandStatue ), + typeof( Shell ), + typeof( ToyBoat ) + }; + + public static bool Accepts( Item item ) + { + if ( item == null ) + return false; + + Type type = item.GetType(); + + for ( int i = 0; i < m_Decorations.Length; i ++ ) + { + if ( type == m_Decorations[ i ] ) + return true; + } + + return false; + } + + private static int[] m_FishHues = new int[] + { + 0x1C2, 0x1C3, 0x2A3, 0x47E, 0x51D + }; + + public static int[] FishHues + { + get{ return m_FishHues; } + } + #endregion + + #region Context entries + private class ExamineEntry : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public ExamineEntry( Aquarium aquarium ) : base( 6235, 2 ) // Examine Aquarium + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted ) + return; + + m_Aquarium.ExamineAquarium( Owner.From ); + } + } + + private class CollectRewardEntry : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public CollectRewardEntry( Aquarium aquarium ) : base( 6237, 2 ) // Collect Reward + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted || !m_Aquarium.HasAccess( Owner.From ) ) + return; + + m_Aquarium.GiveReward( Owner.From ); + } + } + + private class ViewEventEntry : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public ViewEventEntry( Aquarium aquarium ) : base( 6239, 2 ) // View events + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted || !m_Aquarium.HasAccess( Owner.From ) || m_Aquarium.Events.Count == 0 ) + return; + + Owner.From.SendLocalizedMessage( m_Aquarium.Events[ 0 ] ); + + if ( m_Aquarium.Events[ 0 ] == 1074366 ) + Owner.From.PlaySound( 0x5A2 ); + + m_Aquarium.Events.RemoveAt( 0 ); + m_Aquarium.InvalidateProperties(); + } + } + + private class CancelVacationMode : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public CancelVacationMode( Aquarium aquarium ) : base( 6240, 2 ) // Cancel vacation mode + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted || !m_Aquarium.HasAccess( Owner.From ) ) + return; + + Owner.From.SendLocalizedMessage( 1074429 ); // Vacation mode has been cancelled. + m_Aquarium.VacationLeft = 0; + m_Aquarium.InvalidateProperties(); + } + } + + // GM context entries + private class GMAddFood : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public GMAddFood( Aquarium aquarium ) : base( 6231, -1 ) // GM Add Food + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted ) + return; + + m_Aquarium.Food.Added += 1; + m_Aquarium.InvalidateProperties(); + } + } + + private class GMAddWater : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public GMAddWater( Aquarium aquarium ) : base( 6232, -1 ) // GM Add Water + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted ) + return; + + m_Aquarium.Water.Added += 1; + m_Aquarium.InvalidateProperties(); + } + } + + private class GMForceEvaluate : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public GMForceEvaluate( Aquarium aquarium ) : base( 6233, -1 ) // GM Force Evaluate + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted ) + return; + + m_Aquarium.Evaluate(); + } + } + + private class GMOpen : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public GMOpen( Aquarium aquarium ) : base( 6234, -1 ) // GM Open Container + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted ) + return; + + Owner.From.SendGump( new AquariumGump( m_Aquarium, true ) ); + } + } + + private class GMFill : ContextMenuEntry + { + private Aquarium m_Aquarium; + + public GMFill( Aquarium aquarium ) : base( 6236, -1 ) // GM Fill Food and Water + { + m_Aquarium = aquarium; + } + + public override void OnClick() + { + if ( m_Aquarium.Deleted ) + return; + + m_Aquarium.Food.Added = m_Aquarium.Food.Maintain; + m_Aquarium.Water.Added = m_Aquarium.Water.Maintain; + m_Aquarium.InvalidateProperties(); + } + } + #endregion + } + + public class AquariumEastDeed : BaseAddonContainerDeed + { + public override BaseAddonContainer Addon{ get{ return new Aquarium( 0x3062 ); } } + public override int LabelNumber{ get{ return 1074501; } } // Large Aquarium (east) + + [Constructable] + public AquariumEastDeed() : base() + { + } + + public AquariumEastDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AquariumNorthDeed : BaseAddonContainerDeed + { + public override BaseAddonContainer Addon{ get{ return new Aquarium( 0x3060 ); } } + public override int LabelNumber{ get{ return 1074497; } } // Large Aquarium (north) + + [Constructable] + public AquariumNorthDeed() : base() + { + } + + public AquariumNorthDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( 0 ); // Version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/AquariumFishingNet.cs b/Scripts/Items/Aquarium/AquariumFishingNet.cs new file mode 100644 index 0000000..7e3cace --- /dev/null +++ b/Scripts/Items/Aquarium/AquariumFishingNet.cs @@ -0,0 +1,199 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class AquariumFishNet : SpecialFishingNet + { + public override int LabelNumber{ get{ return 1074463; } } // An aquarium fishing net + + [Constructable] + public AquariumFishNet() + { + ItemID = 0xDC8; + + if ( Hue == 0x8A0 ) + Hue = 0x240; + } + + protected override void AddNetProperties( ObjectPropertyList list ) + { + } + + public override bool RequireDeepWater { get { return false; } } + + protected override void FinishEffect( Point3D p, Map map, Mobile from ) + { + if ( from.Skills.Fishing.Value < 10 ) + { + from.SendLocalizedMessage( 1074487 ); // The creatures are too quick for you! + } + else + { + BaseFish fish = GiveFish( from ); + FishBowl bowl = Aquarium.GetEmptyBowl( from ); + + if ( bowl != null ) + { + fish.StopTimer(); + bowl.AddItem( fish ); + from.SendLocalizedMessage( 1074489 ); // A live creature jumps into the fish bowl in your pack! + Delete(); + return; + } + else + { + if ( from.PlaceInBackpack( fish ) ) + { + from.PlaySound( 0x5A2 ); + from.SendLocalizedMessage( 1074490 ); // A live creature flops around in your pack before running out of air. + + fish.Kill(); + Delete(); + return; + } + else + { + fish.Delete(); + + from.SendLocalizedMessage( 1074488 ); // You could not hold the creature. + } + } + } + + InUse = false; + Movable = true; + + if ( !from.PlaceInBackpack( this ) ) + { + if ( from.Map == null || from.Map == Map.Internal ) + Delete(); + else + MoveToWorld( from.Location, from.Map ); + } + } + + private BaseFish GiveFish( Mobile from ) + { + double skill = from.Skills.Fishing.Value; + + if ( ( skill / 100.0 ) >= Utility.RandomDouble() ) + { + int max = (int) skill / 5; + + if ( max > 20 ) + max = 20; + + switch ( Utility.Random( max ) ) + { + case 0: return new MinocBlueFish(); + case 1: return new Shrimp(); + case 2: return new FandancerFish(); + case 3: return new GoldenBroadtail(); + case 4: return new RedDartFish(); + case 5: return new AlbinoCourtesanFish(); + case 6: return new MakotoCourtesanFish(); + case 7: return new NujelmHoneyFish(); + case 8: return new Jellyfish(); + case 9: return new SpeckledCrab(); + case 10: return new LongClawCrab(); + case 11: return new AlbinoFrog(); + case 12: return new KillerFrog(); + case 13: return new VesperReefTiger(); + case 14: return new PurpleFrog(); + case 15: return new BritainCrownFish(); + case 16: return new YellowFinBluebelly(); + case 17: return new SpottedBuccaneer(); + case 18: return new SpinedScratcherFish(); + default: return new SmallMouthSuckerFin(); + } + } + + return new MinocBlueFish(); + } + + public AquariumFishNet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // Legacy code + public class AquariumFishingNet : Item + { + public override int LabelNumber{ get{ return 1074463; } } // An aquarium fishing net + + public AquariumFishingNet() + { + } + + public AquariumFishingNet( Serial serial ) : base( serial ) + { + } + + private Item CreateReplacement() + { + Item result = new AquariumFishNet(); + result.Hue = Hue; + result.LootType = LootType; + result.Movable = Movable; + result.Name = Name; + result.QuestItem = QuestItem; + result.Visible = Visible; + + return result; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + + Item replacement = CreateReplacement(); + + if ( !from.PlaceInBackpack( replacement ) ) + { + replacement.Delete(); + from.SendLocalizedMessage( 500720 ); // You don't have enough room in your backpack! + } + else + { + Delete(); + from.Use( replacement ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/AquariumFood.cs b/Scripts/Items/Aquarium/AquariumFood.cs new file mode 100644 index 0000000..b3fa824 --- /dev/null +++ b/Scripts/Items/Aquarium/AquariumFood.cs @@ -0,0 +1,35 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class AquariumFood : Item + { + public override int LabelNumber{ get{ return 1074819; } } // Aquarium food + + [Constructable] + public AquariumFood() : base( 0xEFC ) + { + } + + public AquariumFood( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/AquariumGump.cs b/Scripts/Items/Aquarium/AquariumGump.cs new file mode 100644 index 0000000..9d7dc02 --- /dev/null +++ b/Scripts/Items/Aquarium/AquariumGump.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections; +using Server.Gumps; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class AquariumGump : Gump + { + private Aquarium m_Aquarium; + + public AquariumGump( Aquarium aquarium, bool edit ) : base( 100, 100 ) + { + m_Aquarium = aquarium; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 350, 323, 0xE10 ); + AddImage( 0, 0, 0x2C96 ); + + if ( m_Aquarium.Items.Count == 0 ) + return; + + for ( int i = 1; i <= m_Aquarium.Items.Count; i ++ ) + DisplayPage( i, edit ); + } + + public virtual void DisplayPage( int page, bool edit ) + { + AddPage( page ); + + Item item = m_Aquarium.Items[ page - 1 ]; + + // item name + if ( item.LabelNumber != 0 ) + AddHtmlLocalized( 20, 217, 250, 20, item.LabelNumber, 0xFFFFFF, false, false ); // Name + + // item details + if ( item is BaseFish ) + AddHtmlLocalized( 20, 239, 315, 20, ( (BaseFish) item ).GetDescription(), 0xFFFFFF, false, false ); + else + AddHtmlLocalized( 20, 239, 315, 20, 1073634, 0xFFFFFF, false, false ); // An aquarium decoration + + // item image + AddItem( 150, 80, item.ItemID, item.Hue ); + + // item number / all items + AddHtml( 20, 195, 250, 20, String.Format( "{0}/{1}", page, m_Aquarium.Items.Count ), false, false ); + + // remove item + if ( edit ) + { + AddBackground( 230, 195, 100, 26, 0x13BE ); + AddButton( 235, 200, 0x845, 0x846, page, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 260, 198, 60, 26, 1073838, 0x0, false, false ); // Remove + } + + // next page + if ( page < m_Aquarium.Items.Count ) + { + AddButton( 195, 280, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page + 1 ); + AddHtmlLocalized( 230, 283, 100, 18, 1044045, 0xFFFFFF, false, false ); // NEXT PAGE + } + + // previous page + if ( page > 1 ) + { + AddButton( 45, 280, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page - 1 ); + AddHtmlLocalized( 80, 283, 100, 18, 1044044, 0xFFFFFF, false, false ); // PREV PAGE + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Aquarium == null || m_Aquarium.Deleted ) + return; + + bool edit = m_Aquarium.HasAccess( sender.Mobile ); + + if ( info.ButtonID > 0 && info.ButtonID <= m_Aquarium.Items.Count && edit ) + m_Aquarium.RemoveItem( sender.Mobile, info.ButtonID - 1 ); + + if ( info.ButtonID > 0 ) + sender.Mobile.SendGump( new AquariumGump( m_Aquarium, edit ) ); + } + } +} diff --git a/Scripts/Items/Aquarium/AquariumState.cs b/Scripts/Items/Aquarium/AquariumState.cs new file mode 100644 index 0000000..0adad68 --- /dev/null +++ b/Scripts/Items/Aquarium/AquariumState.cs @@ -0,0 +1,98 @@ +using System; +using Server; + +namespace Server.Items +{ + public enum WaterState + { + Dead, + Dying, + Unhealthy, + Healthy, + Strong + } + + public enum FoodState + { + Dead, + Starving, + Hungry, + Full, + Overfed + } + + [PropertyObject] + public class AquariumState + { + private int m_State; + private int m_Maintain; + private int m_Improve; + private int m_Added; + + [CommandProperty( AccessLevel.GameMaster )] + public int State + { + get{ return m_State; } + set + { + m_State = value; + + if ( m_State < 0 ) + m_State = 0; + + if ( m_State > 4 ) + m_State = 4; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Maintain + { + get{ return m_Maintain; } + set{ m_Maintain = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Improve + { + get{ return m_Improve; } + set{ m_Improve = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Added + { + get{ return m_Added; } + set{ m_Added = value; } + } + + public AquariumState() + { + } + + public override string ToString() + { + return "..."; + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.Write( 0 ); // version + + writer.Write( m_State ); + writer.Write( m_Maintain ); + writer.Write( m_Improve ); + writer.Write( m_Added ); + } + + public virtual void Deserialize( GenericReader reader ) + { + int version = reader.ReadInt(); + + m_State = reader.ReadInt(); + m_Maintain = reader.ReadInt(); + m_Improve = reader.ReadInt(); + m_Added = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/BaseFish.cs b/Scripts/Items/Aquarium/BaseFish.cs new file mode 100644 index 0000000..6c90147 --- /dev/null +++ b/Scripts/Items/Aquarium/BaseFish.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BaseFish : Item + { + private static readonly TimeSpan DeathDelay = TimeSpan.FromMinutes( 5 ); + + private Timer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Dead + { + get{ return ( ItemID == 0x3B0C ); } + } + + [Constructable] + public BaseFish( int itemID ) : base( itemID ) + { + StartTimer(); + } + + public BaseFish( Serial serial ) : base( serial ) + { + } + + public virtual void StartTimer() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = Timer.DelayCall( DeathDelay, new TimerCallback( Kill ) ); + + InvalidateProperties(); + } + + public virtual void StopTimer() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + InvalidateProperties(); + } + + public override void OnDelete() + { + StopTimer(); + } + + public virtual void Kill() + { + ItemID = 0x3B0C; + StopTimer(); + + InvalidateProperties(); + } + + public int GetDescription() + { + // TODO: This will never return "very unusual dead aquarium creature" due to the way it is killed + if ( ItemID > 0x3B0F ) + return Dead ? 1074424 : 1074422; // A very unusual [dead/live] aquarium creature + else if ( Hue != 0 ) + return Dead ? 1074425 : 1074423; // A [dead/live] aquarium creature of unusual color + + return Dead ? 1073623 : 1073622; // A [dead/live] aquarium creature + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( GetDescription() ); + + if ( !Dead && m_Timer != null ) + list.Add( 1074507 ); // Gasping for air + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( !( Parent is Aquarium ) && !( Parent is FishBowl ) ) + StartTimer(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/AlbinoCourtesanFish.cs b/Scripts/Items/Aquarium/Fish/AlbinoCourtesanFish.cs new file mode 100644 index 0000000..1d82e0f --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/AlbinoCourtesanFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AlbinoCourtesanFish : BaseFish + { + public override int LabelNumber{ get{ return 1074592; } } // Albino Courtesan Fish + + [Constructable] + public AlbinoCourtesanFish() : base( 0x3B04 ) + { + } + + public AlbinoCourtesanFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/AlbinoFrog.cs b/Scripts/Items/Aquarium/Fish/AlbinoFrog.cs new file mode 100644 index 0000000..b09cb6a --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/AlbinoFrog.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AlbinoFrog : BaseFish + { + public override int LabelNumber{ get{ return 1073824; } } // An Albino Frog + + [Constructable] + public AlbinoFrog() : base( 0x3B0D ) + { + Hue = 0x47E; + } + + public AlbinoFrog( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/BritainCrownFish.cs b/Scripts/Items/Aquarium/Fish/BritainCrownFish.cs new file mode 100644 index 0000000..90987ae --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/BritainCrownFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BritainCrownFish : BaseFish + { + public override int LabelNumber{ get{ return 1074589; } } // Britain Crown Fish + + [Constructable] + public BritainCrownFish() : base( 0x3AFF ) + { + } + + public BritainCrownFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/FandancerFish.cs b/Scripts/Items/Aquarium/Fish/FandancerFish.cs new file mode 100644 index 0000000..b11c829 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/FandancerFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FandancerFish : BaseFish + { + public override int LabelNumber{ get{ return 1074591; } } // Fandancer Fish + + [Constructable] + public FandancerFish() : base( 0x3B02 ) + { + } + + public FandancerFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/GoldenBroadtail.cs b/Scripts/Items/Aquarium/Fish/GoldenBroadtail.cs new file mode 100644 index 0000000..c21de95 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/GoldenBroadtail.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GoldenBroadtail : BaseFish + { + public override int LabelNumber{ get{ return 1073828; } } // A Golden Broadtail + + [Constructable] + public GoldenBroadtail() : base( 0x3B03 ) + { + } + + public GoldenBroadtail( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/Jellyfish.cs b/Scripts/Items/Aquarium/Fish/Jellyfish.cs new file mode 100644 index 0000000..666a604 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/Jellyfish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Jellyfish : BaseFish + { + public override int LabelNumber{ get{ return 1074593; } } // Jellyfish + + [Constructable] + public Jellyfish() : base( 0x3B0E ) + { + } + + public Jellyfish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/KillerFrog.cs b/Scripts/Items/Aquarium/Fish/KillerFrog.cs new file mode 100644 index 0000000..d2a0577 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/KillerFrog.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class KillerFrog : BaseFish + { + public override int LabelNumber{ get{ return 1073825; } } // A Killer Frog + + [Constructable] + public KillerFrog() : base( 0x3B0D ) + { + } + + public KillerFrog( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/LongClawCrab.cs b/Scripts/Items/Aquarium/Fish/LongClawCrab.cs new file mode 100644 index 0000000..a988791 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/LongClawCrab.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LongClawCrab : BaseFish + { + public override int LabelNumber{ get{ return 1073827; } } // A Long Claw Crab + + [Constructable] + public LongClawCrab() : base( 0x3AFC ) + { + Hue = 0x527; + } + + public LongClawCrab( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/MakotoCourtesanFish.cs b/Scripts/Items/Aquarium/Fish/MakotoCourtesanFish.cs new file mode 100644 index 0000000..7441b07 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/MakotoCourtesanFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MakotoCourtesanFish : BaseFish + { + public override int LabelNumber{ get{ return 1073835; } } // A Makoto Courtesan Fish + + [Constructable] + public MakotoCourtesanFish() : base( 0x3AFD ) + { + } + + public MakotoCourtesanFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/MinocBlueFish.cs b/Scripts/Items/Aquarium/Fish/MinocBlueFish.cs new file mode 100644 index 0000000..3bf3d47 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/MinocBlueFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MinocBlueFish : BaseFish + { + public override int LabelNumber{ get{ return 1073829; } } // A Minoc Blue Fish + + [Constructable] + public MinocBlueFish() : base( 0x3AFE ) + { + } + + public MinocBlueFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/NujelmHoneyFish.cs b/Scripts/Items/Aquarium/Fish/NujelmHoneyFish.cs new file mode 100644 index 0000000..86f6ffa --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/NujelmHoneyFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NujelmHoneyFish : BaseFish + { + public override int LabelNumber{ get{ return 1073830; } } // A Nujel'm Honey Fish + + [Constructable] + public NujelmHoneyFish() : base( 0x3B06 ) + { + } + + public NujelmHoneyFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/PurpleFrog.cs b/Scripts/Items/Aquarium/Fish/PurpleFrog.cs new file mode 100644 index 0000000..ae85c0e --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/PurpleFrog.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PurpleFrog : BaseFish + { + public override int LabelNumber{ get{ return 1073823; } } // A Purple Frog + + [Constructable] + public PurpleFrog() : base( 0x3B0D ) + { + Hue = 0x4FA; + } + + public PurpleFrog( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/RedDartFish.cs b/Scripts/Items/Aquarium/Fish/RedDartFish.cs new file mode 100644 index 0000000..f160906 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/RedDartFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RedDartFish : BaseFish + { + public override int LabelNumber{ get{ return 1073834; } } // A Red Dart Fish + + [Constructable] + public RedDartFish() : base( 0x3B00 ) + { + } + + public RedDartFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/Shrimp.cs b/Scripts/Items/Aquarium/Fish/Shrimp.cs new file mode 100644 index 0000000..0601526 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/Shrimp.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Shrimp : BaseFish + { + public override int LabelNumber{ get{ return 1074596; } } // Shrimp + + [Constructable] + public Shrimp() : base( 0x3B14 ) + { + } + + public Shrimp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/SmallMouthSuckerFin.cs b/Scripts/Items/Aquarium/Fish/SmallMouthSuckerFin.cs new file mode 100644 index 0000000..35bb7ec --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/SmallMouthSuckerFin.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SmallMouthSuckerFin : BaseFish + { + public override int LabelNumber{ get{ return 1074590; } } // Small Mouth Sucker Fin + + [Constructable] + public SmallMouthSuckerFin() : base( 0x3B01 ) + { + } + + public SmallMouthSuckerFin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/SpeckledCrab.cs b/Scripts/Items/Aquarium/Fish/SpeckledCrab.cs new file mode 100644 index 0000000..368d169 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/SpeckledCrab.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpeckledCrab : BaseFish + { + public override int LabelNumber{ get{ return 1073826; } } // A Speckled Crab + + [Constructable] + public SpeckledCrab() : base( 0x3AFC ) + { + } + + public SpeckledCrab( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/SpinedScratcherFish.cs b/Scripts/Items/Aquarium/Fish/SpinedScratcherFish.cs new file mode 100644 index 0000000..2164a0b --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/SpinedScratcherFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpinedScratcherFish : BaseFish + { + public override int LabelNumber{ get{ return 1073832; } } // A Spined Scratcher Fish + + [Constructable] + public SpinedScratcherFish() : base( 0x3B05 ) + { + } + + public SpinedScratcherFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/SpottedBuccaneer.cs b/Scripts/Items/Aquarium/Fish/SpottedBuccaneer.cs new file mode 100644 index 0000000..4ecb71a --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/SpottedBuccaneer.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpottedBuccaneer : BaseFish + { + public override int LabelNumber{ get{ return 1073833; } } // A Spotted Buccaneer + + [Constructable] + public SpottedBuccaneer() : base( 0x3B09 ) + { + } + + public SpottedBuccaneer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/VesperReefTiger.cs b/Scripts/Items/Aquarium/Fish/VesperReefTiger.cs new file mode 100644 index 0000000..37f21fa --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/VesperReefTiger.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class VesperReefTiger : BaseFish + { + public override int LabelNumber{ get{ return 1073836; } } // A Vesper Reef Tiger + + [Constructable] + public VesperReefTiger() : base( 0x3B08 ) + { + } + + public VesperReefTiger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Fish/YellowFinBluebelly.cs b/Scripts/Items/Aquarium/Fish/YellowFinBluebelly.cs new file mode 100644 index 0000000..59dd0c6 --- /dev/null +++ b/Scripts/Items/Aquarium/Fish/YellowFinBluebelly.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class YellowFinBluebelly : BaseFish + { + public override int LabelNumber{ get{ return 1073831; } } // A Yellow Fin Bluebelly + + [Constructable] + public YellowFinBluebelly() : base( 0x3B07 ) + { + } + + public YellowFinBluebelly( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/FishBowl.cs b/Scripts/Items/Aquarium/FishBowl.cs new file mode 100644 index 0000000..07e5f5b --- /dev/null +++ b/Scripts/Items/Aquarium/FishBowl.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class FishBowl : BaseContainer + { + public override int LabelNumber{ get{ return 1074499; } } // A fish bowl + + [CommandProperty( AccessLevel.GameMaster )] + public bool Empty + { + get{ return ( Items.Count == 0 ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseFish Fish + { + get + { + if ( Empty ) + return null; + + if ( Items[ 0 ] is BaseFish ) + return (BaseFish) Items[ 0 ]; + + return null; + } + } + + public override double DefaultWeight { get { return 2.0; } } + + [Constructable] + public FishBowl() : base( 0x241C ) + { + Hue = 0x47E; + MaxItems = 1; + } + + public FishBowl( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + } + + public override bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + if ( !CheckHold( from, dropped, sendFullMessage, true ) ) + return false; + + DropItem( dropped ); + return true; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( !IsAccessibleTo( from ) ) + { + from.SendLocalizedMessage( 502436 ); // That is not accessible. + return false; + } + + if ( !( dropped is BaseFish ) ) + { + from.SendLocalizedMessage( 1074836 ); // The container can not hold that type of object. + return false; + } + + if ( base.OnDragDrop( from, dropped ) ) + { + ((BaseFish) dropped).StopTimer(); + InvalidateProperties(); + + return true; + } + + return false; + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( item != this ) + return false; + + return base.CheckItemUse( from, item ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( item != this ) + { + reject = LRReason.CannotLift; + return false; + } + + return base.CheckLift( from, item, ref reject ); + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( !Empty ) + { + BaseFish fish = Fish; + + if ( fish != null ) + list.Add( 1074494, "#{0}", fish.LabelNumber ); // Contains: ~1_CREATURE~ + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( !Empty && IsAccessibleTo( from ) ) + list.Add( new RemoveCreature( this ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + Weight = DefaultWeight; + } + + private class RemoveCreature : ContextMenuEntry + { + private FishBowl m_Bowl; + + public RemoveCreature( FishBowl bowl ) : base( 6242, 3 ) // Remove creature + { + m_Bowl = bowl; + } + + public override void OnClick() + { + if ( m_Bowl == null || m_Bowl.Deleted || !m_Bowl.IsAccessibleTo( Owner.From ) ) + return; + + BaseFish fish = m_Bowl.Fish; + + if ( fish != null ) + { + if ( fish.IsLockedDown ) // for legacy fish bowls + { + Owner.From.SendLocalizedMessage( 1010449 ); // You may not use this object while it is locked down. + } + else if ( !Owner.From.PlaceInBackpack( fish ) ) + { + Owner.From.SendLocalizedMessage( 1074496 ); // There is no room in your pack for the creature. + } + else + { + Owner.From.SendLocalizedMessage( 1074495 ); // The creature has been removed from the fish bowl. + fish.StartTimer(); + m_Bowl.InvalidateProperties(); + } + } + } + } + } +} diff --git a/Scripts/Items/Aquarium/Reward Fish/BrineShrimp.cs b/Scripts/Items/Aquarium/Reward Fish/BrineShrimp.cs new file mode 100644 index 0000000..d239364 --- /dev/null +++ b/Scripts/Items/Aquarium/Reward Fish/BrineShrimp.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BrineShrimp : BaseFish + { + public override int LabelNumber{ get{ return 1074415; } } // Brine shrimp + + [Constructable] + public BrineShrimp() : base( 0x3B11 ) + { + } + + public BrineShrimp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Reward Fish/Coral.cs b/Scripts/Items/Aquarium/Reward Fish/Coral.cs new file mode 100644 index 0000000..b5b4cd3 --- /dev/null +++ b/Scripts/Items/Aquarium/Reward Fish/Coral.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Coral : BaseFish + { + public override int LabelNumber{ get{ return 1074588; } } // Coral + + [Constructable] + public Coral() : base( Utility.RandomList( 0x3AF9, 0x3AFA, 0x3AFB ) ) + { + } + + public Coral( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Reward Fish/FullMoonFish.cs b/Scripts/Items/Aquarium/Reward Fish/FullMoonFish.cs new file mode 100644 index 0000000..6118e4e --- /dev/null +++ b/Scripts/Items/Aquarium/Reward Fish/FullMoonFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FullMoonFish : BaseFish + { + public override int LabelNumber{ get{ return 1074597; } } // A Full Moon Fish + + [Constructable] + public FullMoonFish() : base( 0x3B15 ) + { + } + + public FullMoonFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Reward Fish/SeaHorse.cs b/Scripts/Items/Aquarium/Reward Fish/SeaHorse.cs new file mode 100644 index 0000000..6b9c4ac --- /dev/null +++ b/Scripts/Items/Aquarium/Reward Fish/SeaHorse.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SeaHorseFish : BaseFish + { + public override int LabelNumber{ get{ return 1074414; } } // A sea horse + + [Constructable] + public SeaHorseFish() : base( 0x3B10 ) + { + } + + public SeaHorseFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Reward Fish/StrippedFlakeFish.cs b/Scripts/Items/Aquarium/Reward Fish/StrippedFlakeFish.cs new file mode 100644 index 0000000..124f331 --- /dev/null +++ b/Scripts/Items/Aquarium/Reward Fish/StrippedFlakeFish.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StrippedFlakeFish : BaseFish + { + public override int LabelNumber{ get{ return 1074595; } } // Stripped Flake Fish + + [Constructable] + public StrippedFlakeFish() : base( 0x3B0A ) + { + } + + public StrippedFlakeFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Reward Fish/StrippedSosarianSwill.cs b/Scripts/Items/Aquarium/Reward Fish/StrippedSosarianSwill.cs new file mode 100644 index 0000000..a2ef545 --- /dev/null +++ b/Scripts/Items/Aquarium/Reward Fish/StrippedSosarianSwill.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StrippedSosarianSwill : BaseFish + { + public override int LabelNumber{ get{ return 1074594; } } // Stripped Sosarian Swill + + [Constructable] + public StrippedSosarianSwill() : base( 0x3B0A ) + { + } + + public StrippedSosarianSwill( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/AquariumMessage.cs b/Scripts/Items/Aquarium/Rewards/AquariumMessage.cs new file mode 100644 index 0000000..19979d7 --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/AquariumMessage.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AquariumMessage : MessageInABottle + { + public override int LabelNumber{ get{ return 1073894; } } // Message in a Bottle + + [Constructable] + public AquariumMessage() : base() + { + } + + public AquariumMessage( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/CaptainBlackheartsFishingPole.cs b/Scripts/Items/Aquarium/Rewards/CaptainBlackheartsFishingPole.cs new file mode 100644 index 0000000..21d0514 --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/CaptainBlackheartsFishingPole.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CaptainBlackheartsFishingPole : FishingPole + { + public override int LabelNumber{ get{ return 1074571; } } // Captain Blackheart's Fishing Pole + + [Constructable] + public CaptainBlackheartsFishingPole() : base() + { + } + + public CaptainBlackheartsFishingPole( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/CraftysFishingHat.cs b/Scripts/Items/Aquarium/Rewards/CraftysFishingHat.cs new file mode 100644 index 0000000..ba7d48f --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/CraftysFishingHat.cs @@ -0,0 +1,50 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CraftysFishingHat : BaseHat + { + public override int LabelNumber{ get{ return 1074572; } } // Crafty's Fishing Hat + + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public CraftysFishingHat() : base( 0x1713 ) + { + } + + public CraftysFishingHat( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/FishBones.cs b/Scripts/Items/Aquarium/Rewards/FishBones.cs new file mode 100644 index 0000000..131ee75 --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/FishBones.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FishBones : Item + { + public override int LabelNumber{ get{ return 1074601; } } // Fish bones + public override double DefaultWeight{ get{ return 1.0; } } + + [Constructable] + public FishBones() : base( 0x3B0C ) + { + } + + public FishBones( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/IslandStatue.cs b/Scripts/Items/Aquarium/Rewards/IslandStatue.cs new file mode 100644 index 0000000..4ede01e --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/IslandStatue.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class IslandStatue : Item + { + public override int LabelNumber{ get{ return 1074600; } } // An island statue + public override double DefaultWeight{ get{ return 1.0; } } + + [Constructable] + public IslandStatue() : base( 0x3B0F ) + { + } + + public IslandStatue( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/Shell.cs b/Scripts/Items/Aquarium/Rewards/Shell.cs new file mode 100644 index 0000000..d7cc0bc --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/Shell.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Shell : Item + { + public override int LabelNumber{ get{ return 1074598; } } // A shell + public override double DefaultWeight{ get{ return 1.0; } } + + [Constructable] + public Shell() : base( Utility.RandomList( 0x3B12, 0x3B13 ) ) + { + } + + public Shell( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/ToyBoat.cs b/Scripts/Items/Aquarium/Rewards/ToyBoat.cs new file mode 100644 index 0000000..bc19382 --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/ToyBoat.cs @@ -0,0 +1,43 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x14F3, 0x14F4 )] + public class ToyBoat : Item + { + public override int LabelNumber{ get{ return 1074363; } } // A toy boat + public override double DefaultWeight{ get{ return 1.0; } } + + [Constructable] + public ToyBoat() : base( 0x14F4 ) + { + } + + public ToyBoat( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/Rewards/WaterloggedBoots.cs b/Scripts/Items/Aquarium/Rewards/WaterloggedBoots.cs new file mode 100644 index 0000000..790fd73 --- /dev/null +++ b/Scripts/Items/Aquarium/Rewards/WaterloggedBoots.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WaterloggedBoots : BaseShoes + { + public override int LabelNumber{ get{ return 1074364; } } // Waterlogged boots + + [Constructable] + public WaterloggedBoots() : base( 0x1711 ) + { + if ( Utility.RandomBool() ) + { + // thigh boots + ItemID = 0x1711; + Weight = 4.0; + } + else + { + // boots + ItemID = 0x170B; + Weight = 3.0; + } + } + + public WaterloggedBoots( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1073634 ); // An aquarium decoration + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Aquarium/VacationWafer.cs b/Scripts/Items/Aquarium/VacationWafer.cs new file mode 100644 index 0000000..bdc3969 --- /dev/null +++ b/Scripts/Items/Aquarium/VacationWafer.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class VacationWafer : Item + { + public const int VacationDays = 7; + + public override int LabelNumber{ get{ return 1074431; } } // An aquarium flake sphere + + [Constructable] + public VacationWafer() : base( 0x973 ) + { + } + + public VacationWafer( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1074432, VacationDays.ToString() ); // Vacation days: ~1_DAYS~ + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 && ItemID == 0x971 ) + ItemID = 0x973; + } + } +} diff --git a/Scripts/Items/Armor/ArmorEnums.cs b/Scripts/Items/Armor/ArmorEnums.cs new file mode 100644 index 0000000..c2335b4 --- /dev/null +++ b/Scripts/Items/Armor/ArmorEnums.cs @@ -0,0 +1,65 @@ +using System; + +namespace Server.Items +{ + public enum ArmorQuality + { + Low, + Regular, + Exceptional + } + + public enum ArmorDurabilityLevel + { + Regular, + Durable, + Substantial, + Massive, + Fortified, + Indestructible + } + + public enum ArmorProtectionLevel + { + Regular, + Defense, + Guarding, + Hardening, + Fortification, + Invulnerability, + } + + public enum ArmorBodyType + { + Gorget, + Gloves, + Helmet, + Arms, + Legs, + Chest, + Shield + } + + public enum ArmorMaterialType + { + Cloth, + Leather, + Studded, + Bone, + Spined, + Horned, + Barbed, + Daemon, + Ringmail, + Chainmail, + Plate, + Dragon // On OSI, Dragon is seen and considered its own type. + } + + public enum ArmorMeditationAllowance + { + All, + Half, + None + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/ArmorOfFortune.cs b/Scripts/Items/Armor/Artifacts/ArmorOfFortune.cs new file mode 100644 index 0000000..4d67cee --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/ArmorOfFortune.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArmorOfFortune : StuddedChest + { + public override int LabelNumber{ get{ return 1061098; } } // Armor of Fortune + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ArmorOfFortune() + { + Hue = 0x501; + Attributes.Luck = 200; + Attributes.DefendChance = 15; + Attributes.LowerRegCost = 40; + ArmorAttributes.MageArmor = 1; + } + + public ArmorOfFortune( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/Craftable/BrambleCoat.cs b/Scripts/Items/Armor/Artifacts/Craftable/BrambleCoat.cs new file mode 100644 index 0000000..4b4744d --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/Craftable/BrambleCoat.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class BrambleCoat : WoodlandChest + { + public override int LabelNumber{ get{ return 1072925; } } // Bramble Coat + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 8; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 8; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + [Constructable] + public BrambleCoat() + { + Hue = 0x1; + + ArmorAttributes.SelfRepair = 3; + Attributes.BonusHits = 4; + Attributes.Luck = 150; + Attributes.ReflectPhysical = 25; + Attributes.DefendChance = 15; + } + + public BrambleCoat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/Craftable/IronwoodCrown.cs b/Scripts/Items/Armor/Artifacts/Craftable/IronwoodCrown.cs new file mode 100644 index 0000000..ab84dca --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/Craftable/IronwoodCrown.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class IronwoodCrown : RavenHelm + { + public override int LabelNumber{ get{ return 1072924; } } // Ironwood Crown + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 7; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + [Constructable] + public IronwoodCrown() + { + Hue = 0x1; + + ArmorAttributes.SelfRepair = 3; + + Attributes.BonusStr = 5; + Attributes.BonusDex = 5; + Attributes.BonusInt = 5; + } + + public IronwoodCrown( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/Craftable/SongWovenMantle.cs b/Scripts/Items/Armor/Artifacts/Craftable/SongWovenMantle.cs new file mode 100644 index 0000000..b09dfb9 --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/Craftable/SongWovenMantle.cs @@ -0,0 +1,43 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SongWovenMantle : LeafArms + { + public override int LabelNumber{ get{ return 1072931; } } // Song Woven Mantle + + public override int BasePhysicalResistance{ get{ return 14; } } + public override int BaseColdResistance{ get{ return 14; } } + public override int BaseEnergyResistance{ get{ return 16; } } + + [Constructable] + public SongWovenMantle() + { + Hue = 0x493; + + SkillBonuses.SetValues( 0, SkillName.Musicianship, 10.0 ); + + Attributes.Luck = 100; + Attributes.DefendChance = 5; + } + + public SongWovenMantle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/Craftable/SpellWovenBritches.cs b/Scripts/Items/Armor/Artifacts/Craftable/SpellWovenBritches.cs new file mode 100644 index 0000000..7de350f --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/Craftable/SpellWovenBritches.cs @@ -0,0 +1,43 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SpellWovenBritches : LeafLegs + { + public override int LabelNumber{ get{ return 1072929; } } // Spell Woven Britches + + public override int BaseFireResistance{ get{ return 15; } } + public override int BasePoisonResistance{ get{ return 16; } } + + [Constructable] + public SpellWovenBritches() + { + Hue = 0x487; + + SkillBonuses.SetValues( 0, SkillName.Meditation, 10.0 ); + + Attributes.BonusInt = 8; + Attributes.SpellDamage = 10; + Attributes.LowerManaCost = 10; + } + + public SpellWovenBritches( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/Craftable/StitchersMittens.cs b/Scripts/Items/Armor/Artifacts/Craftable/StitchersMittens.cs new file mode 100644 index 0000000..360ec9a --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/Craftable/StitchersMittens.cs @@ -0,0 +1,43 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StitchersMittens : LeafGloves + { + public override int LabelNumber{ get{ return 1072932; } } // Stitcher's Mittens + + public override int BasePhysicalResistance{ get{ return 20; } } + public override int BaseColdResistance{ get{ return 20; } } + + [Constructable] + public StitchersMittens() + { + Hue = 0x481; + + SkillBonuses.SetValues( 0, SkillName.Healing, 10.0 ); + + Attributes.BonusDex = 5; + Attributes.LowerRegCost = 30; + } + + public StitchersMittens( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/GauntletsOfNobility.cs b/Scripts/Items/Armor/Artifacts/GauntletsOfNobility.cs new file mode 100644 index 0000000..9a24c72 --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/GauntletsOfNobility.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GauntletsOfNobility : RingmailGloves + { + public override int LabelNumber{ get{ return 1061092; } } // Gauntlets of Nobility + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 18; } } + public override int BasePoisonResistance{ get{ return 20; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public GauntletsOfNobility() + { + Hue = 0x4FE; + Attributes.BonusStr = 8; + Attributes.Luck = 100; + Attributes.WeaponDamage = 20; + } + + public GauntletsOfNobility( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( Hue == 0x562 ) + Hue = 0x4FE; + + PhysicalBonus = 0; + PoisonBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/HelmOfInsight.cs b/Scripts/Items/Armor/Artifacts/HelmOfInsight.cs new file mode 100644 index 0000000..ab3480a --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/HelmOfInsight.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HelmOfInsight : PlateHelm + { + public override int LabelNumber{ get{ return 1061096; } } // Helm of Insight + public override int ArtifactRarity{ get{ return 11; } } + + public override int BaseEnergyResistance{ get{ return 17; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HelmOfInsight() + { + Hue = 0x554; + Attributes.BonusInt = 8; + Attributes.BonusMana = 15; + Attributes.RegenMana = 2; + Attributes.LowerManaCost = 8; + } + + public HelmOfInsight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + EnergyBonus = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/HolyKnightsBreastplate.cs b/Scripts/Items/Armor/Artifacts/HolyKnightsBreastplate.cs new file mode 100644 index 0000000..f0c0d83 --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/HolyKnightsBreastplate.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HolyKnightsBreastplate : PlateChest + { + public override int LabelNumber{ get{ return 1061097; } } // Holy Knight's Breastplate + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 35; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HolyKnightsBreastplate() + { + Hue = 0x47E; + Attributes.BonusHits = 10; + Attributes.ReflectPhysical = 15; + } + + public HolyKnightsBreastplate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + PhysicalBonus = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/InquisitorsResolution.cs b/Scripts/Items/Armor/Artifacts/InquisitorsResolution.cs new file mode 100644 index 0000000..4575c1e --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/InquisitorsResolution.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public class InquisitorsResolution : PlateGloves + { + public override int LabelNumber{ get{ return 1060206; } } // The Inquisitor's Resolution + public override int ArtifactRarity{ get{ return 10; } } + + public override int BaseColdResistance{ get{ return 22; } } + public override int BaseEnergyResistance{ get{ return 17; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public InquisitorsResolution() + { + Hue = 0x4F2; + Attributes.CastRecovery = 3; + Attributes.LowerManaCost = 8; + ArmorAttributes.MageArmor = 1; + } + + public InquisitorsResolution( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + ColdBonus = 0; + EnergyBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/JackalsCollar.cs b/Scripts/Items/Armor/Artifacts/JackalsCollar.cs new file mode 100644 index 0000000..86d411c --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/JackalsCollar.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class JackalsCollar : PlateGorget + { + public override int LabelNumber{ get{ return 1061594; } } // Jackal's Collar + public override int ArtifactRarity{ get{ return 11; } } + + public override int BaseFireResistance{ get{ return 23; } } + public override int BaseColdResistance{ get{ return 17; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public JackalsCollar() + { + Hue = 0x6D1; + Attributes.BonusDex = 15; + Attributes.RegenHits = 2; + } + + public JackalsCollar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( Hue == 0x54B ) + Hue = 0x6D1; + + FireBonus = 0; + ColdBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/LeggingsOfBane.cs b/Scripts/Items/Armor/Artifacts/LeggingsOfBane.cs new file mode 100644 index 0000000..df51edd --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/LeggingsOfBane.cs @@ -0,0 +1,61 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LeggingsOfBane : ChainLegs + { + public override int LabelNumber{ get{ return 1061100; } } // Leggings of Bane + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePoisonResistance{ get{ return 36; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public LeggingsOfBane() + { + Hue = 0x4F5; + ArmorAttributes.DurabilityBonus = 100; + this.HitPoints = this.MaxHitPoints = 255; //Cause the Durability bonus and such and the min/max hits as well as all other hits being whole #'s... + Attributes.BonusStam = 8; + Attributes.AttackChance = 20; + } + + public LeggingsOfBane( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version <= 1 ) + { + if( this.HitPoints > 255 || this.MaxHitPoints > 255 ) + this.HitPoints = this.MaxHitPoints = 255; + } + + if ( version < 1 ) + { + if ( Hue == 0x559 ) + Hue = 0x4F5; + + if ( ArmorAttributes.DurabilityBonus == 0 ) + ArmorAttributes.DurabilityBonus = 100; + + PoisonBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/MidnightBracers.cs b/Scripts/Items/Armor/Artifacts/MidnightBracers.cs new file mode 100644 index 0000000..d052bb2 --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/MidnightBracers.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MidnightBracers : BoneArms + { + public override int LabelNumber{ get{ return 1061093; } } // Midnight Bracers + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 23; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public MidnightBracers() + { + Hue = 0x455; + SkillBonuses.SetValues( 0, SkillName.Necromancy, 20.0 ); + Attributes.SpellDamage = 10; + ArmorAttributes.MageArmor = 1; + } + + public MidnightBracers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + PhysicalBonus = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/OrnateCrownOfTheHarrower.cs b/Scripts/Items/Armor/Artifacts/OrnateCrownOfTheHarrower.cs new file mode 100644 index 0000000..20620d9 --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/OrnateCrownOfTheHarrower.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrnateCrownOfTheHarrower : BoneHelm + { + public override int LabelNumber{ get{ return 1061095; } } // Ornate Crown of the Harrower + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePoisonResistance{ get{ return 17; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public OrnateCrownOfTheHarrower() + { + Hue = 0x4F6; + Attributes.RegenHits = 2; + Attributes.RegenStam = 3; + Attributes.WeaponDamage = 25; + } + + public OrnateCrownOfTheHarrower( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( Hue == 0x55A ) + Hue = 0x4F6; + + PoisonBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/ShadowDancerLeggings.cs b/Scripts/Items/Armor/Artifacts/ShadowDancerLeggings.cs new file mode 100644 index 0000000..045fcdf --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/ShadowDancerLeggings.cs @@ -0,0 +1,55 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShadowDancerLeggings : LeatherLegs + { + public override int LabelNumber{ get{ return 1061598; } } // Shadow Dancer Leggings + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 17; } } + public override int BasePoisonResistance{ get{ return 18; } } + public override int BaseEnergyResistance{ get{ return 18; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ShadowDancerLeggings() + { + ItemID = 0x13D2; + Hue = 0x455; + SkillBonuses.SetValues( 0, SkillName.Stealth, 20.0 ); + SkillBonuses.SetValues( 1, SkillName.Stealing, 20.0 ); + } + + public ShadowDancerLeggings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( ItemID == 0x13CB ) + ItemID = 0x13D2; + + PhysicalBonus = 0; + PoisonBonus = 0; + EnergyBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/TunicOfFire.cs b/Scripts/Items/Armor/Artifacts/TunicOfFire.cs new file mode 100644 index 0000000..1dc9d8b --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/TunicOfFire.cs @@ -0,0 +1,56 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TunicOfFire : ChainChest + { + public override int LabelNumber{ get{ return 1061099; } } // Tunic of Fire + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 24; } } + public override int BaseFireResistance{ get{ return 34; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TunicOfFire() + { + Hue = 0x54F; + ArmorAttributes.SelfRepair = 5; + Attributes.NightSight = 1; + Attributes.ReflectPhysical = 15; + } + + public TunicOfFire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( Hue == 0x54E ) + Hue = 0x54F; + + if ( Attributes.NightSight == 0 ) + Attributes.NightSight = 1; + + PhysicalBonus = 0; + FireBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Artifacts/VoiceOfTheFallenKing.cs b/Scripts/Items/Armor/Artifacts/VoiceOfTheFallenKing.cs new file mode 100644 index 0000000..7c52e59 --- /dev/null +++ b/Scripts/Items/Armor/Artifacts/VoiceOfTheFallenKing.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + public class VoiceOfTheFallenKing : LeatherGorget + { + public override int LabelNumber{ get{ return 1061094; } } // Voice of the Fallen King + public override int ArtifactRarity{ get{ return 11; } } + + public override int BaseColdResistance{ get{ return 18; } } + public override int BaseEnergyResistance{ get{ return 18; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public VoiceOfTheFallenKing() + { + Hue = 0x76D; + Attributes.BonusStr = 8; + Attributes.RegenHits = 5; + Attributes.RegenStam = 3; + } + + public VoiceOfTheFallenKing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( Hue == 0x551 ) + Hue = 0x76D; + + ColdBonus = 0; + EnergyBonus = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/BaseArmor.cs b/Scripts/Items/Armor/BaseArmor.cs new file mode 100644 index 0000000..6244092 --- /dev/null +++ b/Scripts/Items/Armor/BaseArmor.cs @@ -0,0 +1,1886 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Network; +using Server.Engines.Craft; +using Server.Factions; +using AMA = Server.Items.ArmorMeditationAllowance; +using AMT = Server.Items.ArmorMaterialType; +using ABT = Server.Items.ArmorBodyType; + +namespace Server.Items +{ + public abstract class BaseArmor : BaseWearable, IScissorable, IFactionItem, ICraftable, IWearableDurability + { + #region Factions + private FactionItem m_FactionState; + + public FactionItem FactionItemState + { + get{ return m_FactionState; } + set + { + m_FactionState = value; + + if ( m_FactionState == null ) + Hue = CraftResources.GetHue( Resource ); + + LootType = ( m_FactionState == null ? LootType.Regular : LootType.Blessed ); + } + } + #endregion + + + + /* Armor internals work differently now (Jun 19 2003) + * + * The attributes defined below default to -1. + * If the value is -1, the corresponding virtual 'Aos/Old' property is used. + * If not, the attribute value itself is used. Here's the list: + * - ArmorBase + * - StrBonus + * - DexBonus + * - IntBonus + * - StrReq + * - DexReq + * - IntReq + * - MeditationAllowance + */ + + // Instance values. These values must are unique to each armor piece. + private int m_MaxHitPoints; + private int m_HitPoints; + private Mobile m_Crafter; + private ArmorQuality m_Quality; + private ArmorDurabilityLevel m_Durability; + private ArmorProtectionLevel m_Protection; + private CraftResource m_Resource; + private bool m_Identified; + private bool m_PlayerConstructed; + private int m_PhysicalBonus, m_FireBonus, m_ColdBonus, m_PoisonBonus, m_EnergyBonus; + + private AosAttributes m_AosAttributes; + private AosArmorAttributes m_AosArmorAttributes; + private AosSkillBonuses m_AosSkillBonuses; + + // Overridable values. These values are provided to override the defaults which get defined in the individual armor scripts. + private int m_ArmorBase = -1; + private int m_StrBonus = -1, m_DexBonus = -1, m_IntBonus = -1; + private int m_StrReq = -1, m_DexReq = -1, m_IntReq = -1; + private AMA m_Meditate = (AMA)(-1); + + + public virtual bool AllowMaleWearer{ get{ return true; } } + public virtual bool AllowFemaleWearer{ get{ return true; } } + + public abstract AMT MaterialType{ get; } + + public virtual int RevertArmorBase{ get{ return ArmorBase; } } + public virtual int ArmorBase{ get{ return 0; } } + + public virtual AMA DefMedAllowance{ get{ return AMA.None; } } + public virtual AMA AosMedAllowance{ get{ return DefMedAllowance; } } + public virtual AMA OldMedAllowance{ get{ return DefMedAllowance; } } + + + public virtual int AosStrBonus{ get{ return 0; } } + public virtual int AosDexBonus{ get{ return 0; } } + public virtual int AosIntBonus{ get{ return 0; } } + public virtual int AosStrReq{ get{ return 0; } } + public virtual int AosDexReq{ get{ return 0; } } + public virtual int AosIntReq{ get{ return 0; } } + + + public virtual int OldStrBonus{ get{ return 0; } } + public virtual int OldDexBonus{ get{ return 0; } } + public virtual int OldIntBonus{ get{ return 0; } } + public virtual int OldStrReq{ get{ return 0; } } + public virtual int OldDexReq{ get{ return 0; } } + public virtual int OldIntReq{ get{ return 0; } } + + public virtual bool CanFortify{ get{ return true; } } + + public override void OnAfterDuped( Item newItem ) + { + BaseArmor armor = newItem as BaseArmor; + + if ( armor == null ) + return; + + armor.m_AosAttributes = new AosAttributes( newItem, m_AosAttributes ); + armor.m_AosArmorAttributes = new AosArmorAttributes( newItem, m_AosArmorAttributes ); + armor.m_AosSkillBonuses = new AosSkillBonuses( newItem, m_AosSkillBonuses ); + } + + [CommandProperty( AccessLevel.GameMaster )] + public AMA MeditationAllowance + { + get{ return ( m_Meditate == (AMA)(-1) ? Core.AOS ? AosMedAllowance : OldMedAllowance : m_Meditate ); } + set{ m_Meditate = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int BaseArmorRating + { + get + { + if ( m_ArmorBase == -1 ) + return ArmorBase; + else + return m_ArmorBase; + } + set + { + m_ArmorBase = value; Invalidate(); + } + } + + public double BaseArmorRatingScaled + { + get + { + return ( BaseArmorRating * ArmorScalar ); + } + } + + public virtual double ArmorRating + { + get + { + int ar = BaseArmorRating; + + if ( m_Protection != ArmorProtectionLevel.Regular ) + ar += 10 + (5 * (int)m_Protection); + + switch ( m_Resource ) + { + case CraftResource.MBronze: ar += 2; break; + case CraftResource.MGold: ar += 2; break; + case CraftResource.MCopper: ar += 3; break; + case CraftResource.MOldcopper: ar += 1; break; + case CraftResource.MDullcopper: ar += 4; break; + case CraftResource.MSilver: ar += 9; break; + case CraftResource.MShadow: ar += 6; break; + case CraftResource.MBloodrock: ar += 7; break; + case CraftResource.MBlackrock: ar += 8; break; + case CraftResource.MMytheril: ar += 12; break; + case CraftResource.MRose: ar += 1; break; + case CraftResource.MVerite: ar += 7; break; + case CraftResource.MAgapite: ar += 9; break; + case CraftResource.MRusty: ar += 0; break; + case CraftResource.MValorite: ar += 10; break; + case CraftResource.MDragon: ar += 8; break; + case CraftResource.MTitan: ar += 12; break; + case CraftResource.MCrystaline: ar += 13; break; + case CraftResource.MKrynite: ar += 14; break; + case CraftResource.MVulcan: ar += 15; break; + case CraftResource.MBloodcrest: ar += 16; break; + case CraftResource.MElvin: ar += 17; break; + case CraftResource.MAcid: ar += 18; break; + case CraftResource.MAqua: ar += 19; break; + case CraftResource.MEldar: ar += 8; break; + case CraftResource.MGlowing: ar += 21; break; + case CraftResource.MGorgan: ar += 22; break; + case CraftResource.MSandrock: ar += 23; break; + case CraftResource.MSteel: ar += 24; break; + case CraftResource.SpinedLeather: ar += 2; break; + case CraftResource.HornedLeather: ar += 4; break; + case CraftResource.BarbedLeather: ar += 6; break; + case CraftResource.DaemonLeather: ar += 5; break; + } + + ar += -8 + (8 * (int)m_Quality); + return ScaleArmorByDurability( ar ); + } + } + + public double ArmorRatingScaled + { + get + { + return ( ArmorRating * ArmorScalar ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int StrBonus + { + get{ return ( m_StrBonus == -1 ? Core.AOS ? AosStrBonus : OldStrBonus : m_StrBonus ); } + set{ m_StrBonus = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DexBonus + { + get{ return ( m_DexBonus == -1 ? Core.AOS ? AosDexBonus : OldDexBonus : m_DexBonus ); } + set{ m_DexBonus = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int IntBonus + { + get{ return ( m_IntBonus == -1 ? Core.AOS ? AosIntBonus : OldIntBonus : m_IntBonus ); } + set{ m_IntBonus = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int StrRequirement + { + get{ return ( m_StrReq == -1 ? Core.AOS ? AosStrReq : OldStrReq : m_StrReq ); } + set{ m_StrReq = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DexRequirement + { + get{ return ( m_DexReq == -1 ? Core.AOS ? AosDexReq : OldDexReq : m_DexReq ); } + set{ m_DexReq = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int IntRequirement + { + get{ return ( m_IntReq == -1 ? Core.AOS ? AosIntReq : OldIntReq : m_IntReq ); } + set{ m_IntReq = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Identified + { + get{ return m_Identified; } + set{ m_Identified = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool PlayerConstructed + { + get{ return m_PlayerConstructed; } + set{ m_PlayerConstructed = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get + { + return m_Resource; + } + set + { + if ( m_Resource != value ) + { + UnscaleDurability(); + + m_Resource = value; + if (CraftItem.RetainsColor(this.GetType())) + { + Hue = CraftResources.GetHue(m_Resource); + } + + Invalidate(); + InvalidateProperties(); + + if ( Parent is Mobile ) + ((Mobile)Parent).UpdateResistances(); + + ScaleDurability(); + } + } + } + + public virtual double ArmorScalar + { + get + { + int pos = (int)BodyPosition; + + if ( pos >= 0 && pos < m_ArmorScalars.Length ) + return m_ArmorScalars[pos]; + + return 1.0; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxHitPoints + { + get{ return m_MaxHitPoints; } + set{ m_MaxHitPoints = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitPoints + { + get + { + return m_HitPoints; + } + set + { + if ( value != m_HitPoints && MaxHitPoints > 0 ) + { + m_HitPoints = value; + + if ( m_HitPoints < 0 ) + Delete(); + else if ( m_HitPoints > MaxHitPoints ) + m_HitPoints = MaxHitPoints; + + InvalidateProperties(); + } + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public ArmorQuality Quality + { + get{ return m_Quality; } + set{ UnscaleDurability(); m_Quality = value; Invalidate(); InvalidateProperties(); ScaleDurability(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ArmorDurabilityLevel Durability + { + get{ return m_Durability; } + set{ UnscaleDurability(); m_Durability = value; ScaleDurability(); InvalidateProperties(); } + } + + public virtual int ArtifactRarity + { + get{ return 0; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ArmorProtectionLevel ProtectionLevel + { + get + { + return m_Protection; + } + set + { + if ( m_Protection != value ) + { + m_Protection = value; + + Invalidate(); + InvalidateProperties(); + + if ( Parent is Mobile ) + ((Mobile)Parent).UpdateResistances(); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosAttributes Attributes + { + get{ return m_AosAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosArmorAttributes ArmorAttributes + { + get{ return m_AosArmorAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosSkillBonuses SkillBonuses + { + get{ return m_AosSkillBonuses; } + set{} + } + + public int ComputeStatReq( StatType type ) + { + int v; + + if ( type == StatType.Str ) + v = StrRequirement; + else if ( type == StatType.Dex ) + v = DexRequirement; + else + v = IntRequirement; + + return AOS.Scale( v, 100 - GetLowerStatReq() ); + } + + public int ComputeStatBonus( StatType type ) + { + if ( type == StatType.Str ) + return StrBonus + Attributes.BonusStr; + else if ( type == StatType.Dex ) + return DexBonus + Attributes.BonusDex; + else + return IntBonus + Attributes.BonusInt; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PhysicalBonus{ get{ return m_PhysicalBonus; } set{ m_PhysicalBonus = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int FireBonus{ get{ return m_FireBonus; } set{ m_FireBonus = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ColdBonus{ get{ return m_ColdBonus; } set{ m_ColdBonus = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int PoisonBonus{ get{ return m_PoisonBonus; } set{ m_PoisonBonus = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int EnergyBonus{ get{ return m_EnergyBonus; } set{ m_EnergyBonus = value; InvalidateProperties(); } } + + public virtual int BasePhysicalResistance{ get{ return 0; } } + public virtual int BaseFireResistance{ get{ return 0; } } + public virtual int BaseColdResistance{ get{ return 0; } } + public virtual int BasePoisonResistance{ get{ return 0; } } + public virtual int BaseEnergyResistance{ get{ return 0; } } + + public override int PhysicalResistance{ get{ return BasePhysicalResistance + GetProtOffset() + GetResourceAttrs().ArmorPhysicalResist + m_PhysicalBonus; } } + public override int FireResistance{ get{ return BaseFireResistance + GetProtOffset() + GetResourceAttrs().ArmorFireResist + m_FireBonus; } } + public override int ColdResistance{ get{ return BaseColdResistance + GetProtOffset() + GetResourceAttrs().ArmorColdResist + m_ColdBonus; } } + public override int PoisonResistance{ get{ return BasePoisonResistance + GetProtOffset() + GetResourceAttrs().ArmorPoisonResist + m_PoisonBonus; } } + public override int EnergyResistance{ get{ return BaseEnergyResistance + GetProtOffset() + GetResourceAttrs().ArmorEnergyResist + m_EnergyBonus; } } + + public virtual int InitMinHits{ get{ return 0; } } + public virtual int InitMaxHits{ get{ return 0; } } + + [CommandProperty( AccessLevel.GameMaster )] + public ArmorBodyType BodyPosition + { + get + { + switch ( this.Layer ) + { + default: + case Layer.Neck: return ArmorBodyType.Gorget; + case Layer.TwoHanded: return ArmorBodyType.Shield; + case Layer.Gloves: return ArmorBodyType.Gloves; + case Layer.Helm: return ArmorBodyType.Helmet; + case Layer.Arms: return ArmorBodyType.Arms; + + case Layer.InnerLegs: + case Layer.OuterLegs: + case Layer.Pants: return ArmorBodyType.Legs; + + case Layer.InnerTorso: + case Layer.OuterTorso: + case Layer.Shirt: return ArmorBodyType.Chest; + } + } + } + + //Plume ajout de la difficult� + [CommandProperty(AccessLevel.GameMaster)] + public int ArmorDifficulty + { + get + { + int difficulty = 0; + + if (Attributes.AttackChance != 0) + difficulty++; + if (Attributes.BonusDex != 0) + difficulty++; + if (Attributes.BonusHits != 0) + difficulty++; + if (Attributes.BonusInt != 0) + difficulty++; + if (Attributes.BonusMana != 0) + difficulty++; + if (Attributes.BonusStam != 0) + difficulty++; + if (Attributes.BonusStr != 0) + difficulty++; + if (Attributes.CastRecovery != 0) + difficulty++; + if (Attributes.CastSpeed != 0) + difficulty++; + if (Attributes.DefendChance != 0) + difficulty++; + if (Attributes.EnhancePotions != 0) + difficulty++; + if (Attributes.LowerManaCost != 0) + difficulty++; + if (Attributes.LowerRegCost != 0) + difficulty++; + if (Attributes.Luck != 0) + difficulty++; + if (Attributes.NightSight != 0) + difficulty++; + if (Attributes.ReflectPhysical != 0) + difficulty++; + if (Attributes.RegenHits != 0) + difficulty++; + if (Attributes.RegenMana != 0) + difficulty++; + if (Attributes.RegenStam != 0) + difficulty++; + if (Attributes.SpellChanneling != 0) + difficulty++; + if (Attributes.SpellDamage != 0) + difficulty++; + if (Attributes.WeaponDamage != 0) + difficulty++; + if (Attributes.WeaponSpeed != 0) + difficulty++; + if (ArmorAttributes.DurabilityBonus != 0) + difficulty++; + if (ArmorAttributes.LowerStatReq != 0) + difficulty++; + if (ArmorAttributes.MageArmor != 0) + difficulty++; + if (SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (SkillBonuses.Skill_5_Value != 0) + difficulty++; + if (ColdBonus != 0) + difficulty++; + if (PhysicalBonus != 0) + difficulty++; + if (FireBonus != 0) + difficulty++; + if (PoisonBonus != 0) + difficulty++; + if (EnergyBonus != 0) + difficulty++; + + if (difficulty > 5) + difficulty = 5; + + return difficulty; + } + } + + public void DistributeBonuses( int amount ) + { + for ( int i = 0; i < amount; ++i ) + { + switch ( Utility.Random( 5 ) ) + { + case 0: ++m_PhysicalBonus; break; + case 1: ++m_FireBonus; break; + case 2: ++m_ColdBonus; break; + case 3: ++m_PoisonBonus; break; + case 4: ++m_EnergyBonus; break; + } + } + + InvalidateProperties(); + } + + public CraftAttributeInfo GetResourceAttrs() + { + CraftResourceInfo info = CraftResources.GetInfo( m_Resource ); + + if ( info == null ) + return CraftAttributeInfo.Blank; + + return info.AttributeInfo; + } + + public int GetProtOffset() + { + switch ( m_Protection ) + { + case ArmorProtectionLevel.Guarding: return 1; + case ArmorProtectionLevel.Hardening: return 2; + case ArmorProtectionLevel.Fortification: return 3; + case ArmorProtectionLevel.Invulnerability: return 4; + } + + return 0; + } + + public void UnscaleDurability() + { + int scale = 100 + GetDurabilityBonus(); + + m_HitPoints = ((m_HitPoints * 100) + (scale - 1)) / scale; + m_MaxHitPoints = ((m_MaxHitPoints * 100) + (scale - 1)) / scale; + InvalidateProperties(); + } + + public void ScaleDurability() + { + int scale = 100 + GetDurabilityBonus(); + + m_HitPoints = ((m_HitPoints * scale) + 99) / 100; + m_MaxHitPoints = ((m_MaxHitPoints * scale) + 99) / 100; + InvalidateProperties(); + } + + public int GetDurabilityBonus() + { + int bonus = 0; + + if ( m_Quality == ArmorQuality.Exceptional ) + bonus += 20; + + switch ( m_Durability ) + { + case ArmorDurabilityLevel.Durable: bonus += 20; break; + case ArmorDurabilityLevel.Substantial: bonus += 50; break; + case ArmorDurabilityLevel.Massive: bonus += 70; break; + case ArmorDurabilityLevel.Fortified: bonus += 100; break; + case ArmorDurabilityLevel.Indestructible: bonus += 120; break; + } + + if ( Core.AOS ) + { + bonus += m_AosArmorAttributes.DurabilityBonus; + + CraftResourceInfo resInfo = CraftResources.GetInfo( m_Resource ); + CraftAttributeInfo attrInfo = null; + + if ( resInfo != null ) + attrInfo = resInfo.AttributeInfo; + + if ( attrInfo != null ) + bonus += attrInfo.ArmorDurability; + } + + return bonus; + } + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 502437 ); // Items you wish to cut must be in your backpack. + return false; + } + + if ( Ethics.Ethic.IsImbued( this ) ) + { + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + return false; + } + + CraftSystem system = DefTailoring.CraftSystem; + + CraftItem item = system.CraftItems.SearchFor( GetType() ); + + if ( item != null && item.Resources.Count == 1 && item.Resources.GetAt( 0 ).Amount >= 2 ) + { + try + { + Item res = (Item)Activator.CreateInstance( CraftResources.GetInfo( m_Resource ).ResourceTypes[0] ); + + ScissorHelper( from, res, m_PlayerConstructed ? (item.Resources.GetAt( 0 ).Amount / 2) : 1 ); + return true; + } + catch + { + } + } + + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + return false; + } + + private static double[] m_ArmorScalars = { 0.07, 0.07, 0.14, 0.15, 0.22, 0.35 }; + + public static double[] ArmorScalars + { + get + { + return m_ArmorScalars; + } + set + { + m_ArmorScalars = value; + } + } + + public static void ValidateMobile( Mobile m ) + { + for ( int i = m.Items.Count - 1; i >= 0; --i ) + { + if ( i >= m.Items.Count ) + continue; + + Item item = m.Items[i]; + + if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if( armor.RequiredRace != null && m.Race != armor.RequiredRace ) + { + if( armor.RequiredRace == Race.Elf ) + m.SendLocalizedMessage( 1072203 ); // Only Elves may use this. + else + m.SendMessage( "Only {0} may use this.", armor.RequiredRace.PluralName ); + + m.AddToBackpack( armor ); + } + else if ( !armor.AllowMaleWearer && !m.Female && m.AccessLevel < AccessLevel.GameMaster ) + { + if ( armor.AllowFemaleWearer ) + m.SendLocalizedMessage( 1010388 ); // Only females can wear this. + else + m.SendMessage( "You may not wear this." ); + + m.AddToBackpack( armor ); + } + else if ( !armor.AllowFemaleWearer && m.Female && m.AccessLevel < AccessLevel.GameMaster ) + { + if ( armor.AllowMaleWearer ) + m.SendLocalizedMessage( 1063343 ); // Only males can wear this. + else + m.SendMessage( "You may not wear this." ); + + m.AddToBackpack( armor ); + } + } + } + } + + public int GetLowerStatReq() + { + if ( !Core.AOS ) + return 0; + + int v = m_AosArmorAttributes.LowerStatReq; + + CraftResourceInfo info = CraftResources.GetInfo( m_Resource ); + + if ( info != null ) + { + CraftAttributeInfo attrInfo = info.AttributeInfo; + + if ( attrInfo != null ) + v += attrInfo.ArmorLowerRequirements; + } + + if ( v > 100 ) + v = 100; + + return v; + } + + public override void OnAdded( object parent ) + { + if ( parent is Mobile ) + { + Mobile from = (Mobile)parent; + + if ( Core.AOS ) + m_AosSkillBonuses.AddTo( from ); + + from.Delta( MobileDelta.Armor ); // Tell them armor rating has changed + } + } + + public virtual double ScaleArmorByDurability( double armor ) + { + int scale = 100; + + if ( m_MaxHitPoints > 0 && m_HitPoints < m_MaxHitPoints ) + scale = 50 + ((50 * m_HitPoints) / m_MaxHitPoints); + + return ( armor * scale ) / 100; + } + + protected void Invalidate() + { + if ( Parent is Mobile ) + ((Mobile)Parent).Delta( MobileDelta.Armor ); // Tell them armor rating has changed + } + + public BaseArmor( Serial serial ) : base( serial ) + { + } + + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Attributes = 0x00000001, + ArmorAttributes = 0x00000002, + PhysicalBonus = 0x00000004, + FireBonus = 0x00000008, + ColdBonus = 0x00000010, + PoisonBonus = 0x00000020, + EnergyBonus = 0x00000040, + Identified = 0x00000080, + MaxHitPoints = 0x00000100, + HitPoints = 0x00000200, + Crafter = 0x00000400, + Quality = 0x00000800, + Durability = 0x00001000, + Protection = 0x00002000, + Resource = 0x00004000, + BaseArmor = 0x00008000, + StrBonus = 0x00010000, + DexBonus = 0x00020000, + IntBonus = 0x00040000, + StrReq = 0x00080000, + DexReq = 0x00100000, + IntReq = 0x00200000, + MedAllowance = 0x00400000, + SkillBonuses = 0x00800000, + PlayerConstructed = 0x01000000 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 8 ); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag( ref flags, SaveFlag.Attributes, !m_AosAttributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.ArmorAttributes, !m_AosArmorAttributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.PhysicalBonus, m_PhysicalBonus != 0 ); + SetSaveFlag( ref flags, SaveFlag.FireBonus, m_FireBonus != 0 ); + SetSaveFlag( ref flags, SaveFlag.ColdBonus, m_ColdBonus != 0 ); + SetSaveFlag( ref flags, SaveFlag.PoisonBonus, m_PoisonBonus != 0 ); + SetSaveFlag( ref flags, SaveFlag.EnergyBonus, m_EnergyBonus != 0 ); + SetSaveFlag( ref flags, SaveFlag.Identified, m_Identified != false ); + SetSaveFlag( ref flags, SaveFlag.MaxHitPoints, m_MaxHitPoints != 0 ); + SetSaveFlag( ref flags, SaveFlag.HitPoints, m_HitPoints != 0 ); + SetSaveFlag( ref flags, SaveFlag.Crafter, m_Crafter != null ); + SetSaveFlag( ref flags, SaveFlag.Quality, m_Quality != ArmorQuality.Regular ); + SetSaveFlag( ref flags, SaveFlag.Durability, m_Durability != ArmorDurabilityLevel.Regular ); + SetSaveFlag( ref flags, SaveFlag.Protection, m_Protection != ArmorProtectionLevel.Regular ); + SetSaveFlag( ref flags, SaveFlag.Resource, m_Resource != DefaultResource ); + SetSaveFlag( ref flags, SaveFlag.BaseArmor, m_ArmorBase != -1 ); + SetSaveFlag( ref flags, SaveFlag.StrBonus, m_StrBonus != -1 ); + SetSaveFlag( ref flags, SaveFlag.DexBonus, m_DexBonus != -1 ); + SetSaveFlag( ref flags, SaveFlag.IntBonus, m_IntBonus != -1 ); + SetSaveFlag( ref flags, SaveFlag.StrReq, m_StrReq != -1 ); + SetSaveFlag( ref flags, SaveFlag.DexReq, m_DexReq != -1 ); + SetSaveFlag( ref flags, SaveFlag.IntReq, m_IntReq != -1 ); + SetSaveFlag( ref flags, SaveFlag.MedAllowance, m_Meditate != (AMA)(-1) ); + SetSaveFlag( ref flags, SaveFlag.SkillBonuses, !m_AosSkillBonuses.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.PlayerConstructed, m_PlayerConstructed != false ); + + writer.WriteEncodedInt( (int) flags ); + + if ( GetSaveFlag( flags, SaveFlag.Attributes ) ) + m_AosAttributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.ArmorAttributes ) ) + m_AosArmorAttributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.PhysicalBonus ) ) + writer.WriteEncodedInt( (int) m_PhysicalBonus ); + + if ( GetSaveFlag( flags, SaveFlag.FireBonus ) ) + writer.WriteEncodedInt( (int) m_FireBonus ); + + if ( GetSaveFlag( flags, SaveFlag.ColdBonus ) ) + writer.WriteEncodedInt( (int) m_ColdBonus ); + + if ( GetSaveFlag( flags, SaveFlag.PoisonBonus ) ) + writer.WriteEncodedInt( (int) m_PoisonBonus ); + + if ( GetSaveFlag( flags, SaveFlag.EnergyBonus ) ) + writer.WriteEncodedInt( (int) m_EnergyBonus ); + + if ( GetSaveFlag( flags, SaveFlag.MaxHitPoints ) ) + writer.WriteEncodedInt( (int) m_MaxHitPoints ); + + if ( GetSaveFlag( flags, SaveFlag.HitPoints ) ) + writer.WriteEncodedInt( (int) m_HitPoints ); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + writer.Write( (Mobile) m_Crafter ); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + writer.WriteEncodedInt( (int) m_Quality ); + + if ( GetSaveFlag( flags, SaveFlag.Durability ) ) + writer.WriteEncodedInt( (int) m_Durability ); + + if ( GetSaveFlag( flags, SaveFlag.Protection ) ) + writer.WriteEncodedInt( (int) m_Protection ); + + if ( GetSaveFlag( flags, SaveFlag.Resource ) ) + writer.WriteEncodedInt( (int) m_Resource ); + + if ( GetSaveFlag( flags, SaveFlag.BaseArmor ) ) + writer.WriteEncodedInt( (int) m_ArmorBase ); + + if ( GetSaveFlag( flags, SaveFlag.StrBonus ) ) + writer.WriteEncodedInt( (int) m_StrBonus ); + + if ( GetSaveFlag( flags, SaveFlag.DexBonus ) ) + writer.WriteEncodedInt( (int) m_DexBonus ); + + if ( GetSaveFlag( flags, SaveFlag.IntBonus ) ) + writer.WriteEncodedInt( (int) m_IntBonus ); + + if ( GetSaveFlag( flags, SaveFlag.StrReq ) ) + writer.WriteEncodedInt( (int) m_StrReq ); + + if ( GetSaveFlag( flags, SaveFlag.DexReq ) ) + writer.WriteEncodedInt( (int) m_DexReq ); + + if ( GetSaveFlag( flags, SaveFlag.IntReq ) ) + writer.WriteEncodedInt( (int) m_IntReq ); + + if ( GetSaveFlag( flags, SaveFlag.MedAllowance ) ) + writer.WriteEncodedInt( (int) m_Meditate ); + + if ( GetSaveFlag( flags, SaveFlag.SkillBonuses ) ) + m_AosSkillBonuses.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 8: + case 7: + case 6: + case 5: + { + SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Attributes ) ) + m_AosAttributes = new AosAttributes( this, reader ); + else + m_AosAttributes = new AosAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.ArmorAttributes ) ) + m_AosArmorAttributes = new AosArmorAttributes( this, reader ); + else + m_AosArmorAttributes = new AosArmorAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.PhysicalBonus ) ) + m_PhysicalBonus = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.FireBonus ) ) + m_FireBonus = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.ColdBonus ) ) + m_ColdBonus = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.PoisonBonus ) ) + m_PoisonBonus = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.EnergyBonus ) ) + m_EnergyBonus = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Identified ) ) + m_Identified = ( version >= 7 || reader.ReadBool() ); + + if ( GetSaveFlag( flags, SaveFlag.MaxHitPoints ) ) + m_MaxHitPoints = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.HitPoints ) ) + m_HitPoints = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + m_Crafter = reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + m_Quality = (ArmorQuality)reader.ReadEncodedInt(); + else + m_Quality = ArmorQuality.Regular; + + if ( version == 5 && m_Quality == ArmorQuality.Low ) + m_Quality = ArmorQuality.Regular; + + if ( GetSaveFlag( flags, SaveFlag.Durability ) ) + { + m_Durability = (ArmorDurabilityLevel)reader.ReadEncodedInt(); + + if ( m_Durability > ArmorDurabilityLevel.Indestructible ) + m_Durability = ArmorDurabilityLevel.Durable; + } + + if ( GetSaveFlag( flags, SaveFlag.Protection ) ) + { + m_Protection = (ArmorProtectionLevel)reader.ReadEncodedInt(); + + if ( m_Protection > ArmorProtectionLevel.Invulnerability ) + m_Protection = ArmorProtectionLevel.Defense; + } + + if ( GetSaveFlag( flags, SaveFlag.Resource ) ) + m_Resource = (CraftResource)reader.ReadEncodedInt(); + else + m_Resource = DefaultResource; + + if ( m_Resource == CraftResource.None ) + m_Resource = DefaultResource; + + if ( GetSaveFlag( flags, SaveFlag.BaseArmor ) ) + m_ArmorBase = reader.ReadEncodedInt(); + else + m_ArmorBase = -1; + + if ( GetSaveFlag( flags, SaveFlag.StrBonus ) ) + m_StrBonus = reader.ReadEncodedInt(); + else + m_StrBonus = -1; + + if ( GetSaveFlag( flags, SaveFlag.DexBonus ) ) + m_DexBonus = reader.ReadEncodedInt(); + else + m_DexBonus = -1; + + if ( GetSaveFlag( flags, SaveFlag.IntBonus ) ) + m_IntBonus = reader.ReadEncodedInt(); + else + m_IntBonus = -1; + + if ( GetSaveFlag( flags, SaveFlag.StrReq ) ) + m_StrReq = reader.ReadEncodedInt(); + else + m_StrReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.DexReq ) ) + m_DexReq = reader.ReadEncodedInt(); + else + m_DexReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.IntReq ) ) + m_IntReq = reader.ReadEncodedInt(); + else + m_IntReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.MedAllowance ) ) + m_Meditate = (AMA)reader.ReadEncodedInt(); + else + m_Meditate = (AMA)(-1); + + if ( GetSaveFlag( flags, SaveFlag.SkillBonuses ) ) + m_AosSkillBonuses = new AosSkillBonuses( this, reader ); + + if ( GetSaveFlag( flags, SaveFlag.PlayerConstructed ) ) + m_PlayerConstructed = true; + + break; + } + case 4: + { + m_AosAttributes = new AosAttributes( this, reader ); + m_AosArmorAttributes = new AosArmorAttributes( this, reader ); + goto case 3; + } + case 3: + { + m_PhysicalBonus = reader.ReadInt(); + m_FireBonus = reader.ReadInt(); + m_ColdBonus = reader.ReadInt(); + m_PoisonBonus = reader.ReadInt(); + m_EnergyBonus = reader.ReadInt(); + goto case 2; + } + case 2: + case 1: + { + m_Identified = reader.ReadBool(); + goto case 0; + } + case 0: + { + m_ArmorBase = reader.ReadInt(); + m_MaxHitPoints = reader.ReadInt(); + m_HitPoints = reader.ReadInt(); + m_Crafter = reader.ReadMobile(); + m_Quality = (ArmorQuality)reader.ReadInt(); + m_Durability = (ArmorDurabilityLevel)reader.ReadInt(); + m_Protection = (ArmorProtectionLevel)reader.ReadInt(); + + AMT mat = (AMT)reader.ReadInt(); + + if ( m_ArmorBase == RevertArmorBase ) + m_ArmorBase = -1; + + /*m_BodyPos = (ArmorBodyType)*/reader.ReadInt(); + + + if ( version < 4 ) + { + m_AosAttributes = new AosAttributes( this ); + m_AosArmorAttributes = new AosArmorAttributes( this ); + } + + if ( version < 3 && m_Quality == ArmorQuality.Exceptional ) + DistributeBonuses( 4 ); + + if ( version >= 2 ) + { + m_Resource = (CraftResource)reader.ReadInt(); + } + else + { + OreInfo info; + + switch ( reader.ReadInt() ) + { + default: + case 0: info = OreInfo.MIron; break; + case 1: info = OreInfo.MBronze; break; + case 2: info = OreInfo.MGold; break; + case 3: info = OreInfo.MCopper; break; + case 4: info = OreInfo.MOldcopper; break; + case 5: info = OreInfo.MDullcopper; break; + case 6: info = OreInfo.MSilver; break; + case 7: info = OreInfo.MShadow; break; + case 8: info = OreInfo.MBloodrock; break; + case 9: info = OreInfo.MBlackrock; break; + case 10: info = OreInfo.MMytheril; break; + case 11: info = OreInfo.MRose; break; + case 12: info = OreInfo.MVerite; break; + case 13: info = OreInfo.MAgapite; break; + case 14: info = OreInfo.MRusty; break; + case 15: info = OreInfo.MValorite; break; + case 16: info = OreInfo.MDragon; break; + case 17: info = OreInfo.MTitan; break; + case 18: info = OreInfo.MCrystaline; break; + case 19: info = OreInfo.MKrynite; break; + case 20: info = OreInfo.MVulcan; break; + case 21: info = OreInfo.MBloodcrest; break; + case 22: info = OreInfo.MElvin; break; + case 23: info = OreInfo.MAcid; break; + case 24: info = OreInfo.MAqua; break; + case 25: info = OreInfo.MEldar; break; + case 26: info = OreInfo.MGlowing; break; + case 27: info = OreInfo.MGorgan; break; + case 28: info = OreInfo.MSandrock; break; + case 29: info = OreInfo.MSteel; break; + } + + m_Resource = CraftResources.GetFromOreInfo( info, mat ); + } + + m_StrBonus = reader.ReadInt(); + m_DexBonus = reader.ReadInt(); + m_IntBonus = reader.ReadInt(); + m_StrReq = reader.ReadInt(); + m_DexReq = reader.ReadInt(); + m_IntReq = reader.ReadInt(); + + if ( m_StrBonus == OldStrBonus ) + m_StrBonus = -1; + + if ( m_DexBonus == OldDexBonus ) + m_DexBonus = -1; + + if ( m_IntBonus == OldIntBonus ) + m_IntBonus = -1; + + if ( m_StrReq == OldStrReq ) + m_StrReq = -1; + + if ( m_DexReq == OldDexReq ) + m_DexReq = -1; + + if ( m_IntReq == OldIntReq ) + m_IntReq = -1; + + m_Meditate = (AMA)reader.ReadInt(); + + if ( m_Meditate == OldMedAllowance ) + m_Meditate = (AMA)(-1); + + if ( m_Resource == CraftResource.None ) + { + if ( mat == ArmorMaterialType.Studded || mat == ArmorMaterialType.Leather ) + m_Resource = CraftResource.RegularLeather; + else if ( mat == ArmorMaterialType.Spined ) + m_Resource = CraftResource.SpinedLeather; + else if ( mat == ArmorMaterialType.Horned ) + m_Resource = CraftResource.HornedLeather; + else if ( mat == ArmorMaterialType.Barbed ) + m_Resource = CraftResource.BarbedLeather; + else if (mat == ArmorMaterialType.Daemon) + m_Resource = CraftResource.DaemonLeather; + else + m_Resource = CraftResource.MIron; + } + + if ( m_MaxHitPoints == 0 && m_HitPoints == 0 ) + m_HitPoints = m_MaxHitPoints = Utility.RandomMinMax( InitMinHits, InitMaxHits ); + + break; + } + } + + if ( m_AosSkillBonuses == null ) + m_AosSkillBonuses = new AosSkillBonuses( this ); + + if ( Core.AOS && Parent is Mobile ) + m_AosSkillBonuses.AddTo( (Mobile)Parent ); + + int strBonus = ComputeStatBonus( StatType.Str ); + int dexBonus = ComputeStatBonus( StatType.Dex ); + int intBonus = ComputeStatBonus( StatType.Int ); + + if ( Parent is Mobile && (strBonus != 0 || dexBonus != 0 || intBonus != 0) ) + { + Mobile m = (Mobile)Parent; + + string modName = Serial.ToString(); + + if ( strBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + if ( Parent is Mobile ) + ((Mobile)Parent).CheckStatTimers(); + + if ( version < 7 ) + m_PlayerConstructed = true; // we don't know, so, assume it's crafted + if (version < 8) + m_Identified = true; // we don't know, so, assume it's identified + } + + public virtual CraftResource DefaultResource{ get{ return CraftResource.MIron; } } + + public BaseArmor( int itemID ) : base( itemID ) + { + m_Quality = ArmorQuality.Regular; + m_Durability = ArmorDurabilityLevel.Regular; + m_Crafter = null; + m_Identified = true; + m_Resource = DefaultResource; + Hue = CraftResources.GetHue( m_Resource ); + + m_HitPoints = m_MaxHitPoints = Utility.RandomMinMax( InitMinHits, InitMaxHits ); + + this.Layer = (Layer)ItemData.Quality; + + m_AosAttributes = new AosAttributes( this ); + m_AosArmorAttributes = new AosArmorAttributes( this ); + m_AosSkillBonuses = new AosSkillBonuses( this ); + } + + public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if ( !Ethics.Ethic.CheckTrade( from, to, newOwner, this ) ) + return false; + + return base.AllowSecureTrade( from, to, newOwner, accepted ); + } + + public virtual Race RequiredRace { get { return null; } } + + public override bool CanEquip( Mobile from ) + { + if( !Ethics.Ethic.CheckEquip( from, this ) ) + return false; + + if( from.AccessLevel < AccessLevel.GameMaster ) + { + if( RequiredRace != null && from.Race != RequiredRace ) + { + if( RequiredRace == Race.Elf ) + from.SendLocalizedMessage( 1072203 ); // Only Elves may use this. + else + from.SendMessage( "Only {0} may use this.", RequiredRace.PluralName ); + + return false; + } + else if( !AllowMaleWearer && !from.Female ) + { + if( AllowFemaleWearer ) + from.SendLocalizedMessage( 1010388 ); // Only females can wear this. + else + from.SendMessage( "You may not wear this." ); + + return false; + } + else if( !AllowFemaleWearer && from.Female ) + { + if( AllowMaleWearer ) + from.SendLocalizedMessage( 1063343 ); // Only males can wear this. + else + from.SendMessage( "You may not wear this." ); + + return false; + } + else if (!m_Identified) + { + from.SendMessage("Cette pi�ce d'armure vous semble inconnue"); + return false; + } + else + { + int strBonus = ComputeStatBonus(StatType.Str), strReq = ComputeStatReq(StatType.Str); + int dexBonus = ComputeStatBonus(StatType.Dex), dexReq = ComputeStatReq(StatType.Dex); + int intBonus = ComputeStatBonus(StatType.Int), intReq = ComputeStatReq(StatType.Int); + + if (from.Dex < dexReq || (from.Dex + dexBonus) < 1) + { + from.SendLocalizedMessage(502077); // You do not have enough dexterity to equip this item. + return false; + } + else if (from.Str < strReq || (from.Str + strBonus) < 1) + { + from.SendLocalizedMessage(500213); // You are not strong enough to equip that. + return false; + } + else if (from.Int < intReq || (from.Int + intBonus) < 1) + { + from.SendMessage("You are not smart enough to equip that."); + return false; + } + } + } + + return base.CanEquip( from ); + } + + public override bool CheckPropertyConfliction( Mobile m ) + { + if ( base.CheckPropertyConfliction( m ) ) + return true; + + if ( Layer == Layer.Pants ) + return ( m.FindItemOnLayer( Layer.InnerLegs ) != null ); + + if ( Layer == Layer.Shirt ) + return ( m.FindItemOnLayer( Layer.InnerTorso ) != null ); + + return false; + } + + public override bool OnEquip( Mobile from ) + { + from.CheckStatTimers(); + + int strBonus = ComputeStatBonus( StatType.Str ); + int dexBonus = ComputeStatBonus( StatType.Dex ); + int intBonus = ComputeStatBonus( StatType.Int ); + + if ( strBonus != 0 || dexBonus != 0 || intBonus != 0 ) + { + string modName = this.Serial.ToString(); + + if ( strBonus != 0 ) + from.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + from.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + from.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + return base.OnEquip( from ); + } + + public override void OnRemoved( object parent ) + { + if ( parent is Mobile ) + { + Mobile m = (Mobile)parent; + string modName = this.Serial.ToString(); + + m.RemoveStatMod( modName + "Str" ); + m.RemoveStatMod( modName + "Dex" ); + m.RemoveStatMod( modName + "Int" ); + + if ( Core.AOS ) + m_AosSkillBonuses.Remove(); + + ((Mobile)parent).Delta( MobileDelta.Armor ); // Tell them armor rating has changed + m.CheckStatTimers(); + } + + base.OnRemoved( parent ); + } + + public virtual int OnHit( BaseWeapon weapon, int damageTaken ) + { + double HalfAr = ArmorRating / 2.0; + int Absorbed = (int)(HalfAr + HalfAr*Utility.RandomDouble()); + + damageTaken -= Absorbed; + if ( damageTaken < 0 ) + damageTaken = 0; + + if ( Absorbed < 2 ) + Absorbed = 2; + + if ( 25 > Utility.Random( 100 ) ) // 25% chance to lower durability + { + if ( Core.AOS && m_AosArmorAttributes.SelfRepair > Utility.Random( 10 ) ) + { + HitPoints += 2; + } + else + { + int wear; + + if ( weapon.Type == WeaponType.Bashing ) + wear = Absorbed / 2; + else + wear = Utility.Random( 2 ); + + if ( wear > 0 && m_MaxHitPoints > 0 ) + { + if ( m_HitPoints >= wear ) + { + HitPoints -= wear; + wear = 0; + } + else + { + wear -= HitPoints; + HitPoints = 0; + } + + if ( wear > 0 ) + { + if ( m_MaxHitPoints > wear ) + { + MaxHitPoints -= wear; + + if ( Parent is Mobile ) + ((Mobile)Parent).LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061121 ); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + } + } + + return damageTaken; + } + + private string GetNameString() + { + string name = this.Name; + + if ( name == null ) + name = String.Format( "#{0}", LabelNumber ); + + return name; + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get{ return base.Hue; } + set{ base.Hue = value; InvalidateProperties(); } + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + // Plume : On affiche que le nom de l'item, mat�riel dispo via ArmLore + //string oreType; + + //switch ( m_Resource ) + //{ + // case CraftResource.MBronze: oreType = "Bronze"; break; // dull copper + // case CraftResource.MGold: oreType = "Or"; break; // shadow iron + // case CraftResource.MCopper: oreType = "Cuivre"; break; // copper + // case CraftResource.MOldcopper: oreType = "Vieux cuivre"; break; // bronze + // case CraftResource.MDullcopper: oreType = "Cuivre terni"; break; // golden + // case CraftResource.MSilver: oreType = "Silver"; break; // agapite + // case CraftResource.MShadow: oreType = "Sombrine"; break; // verite + // case CraftResource.MBloodrock: oreType = "Pierre de sang"; break; // valorite + // case CraftResource.MBlackrock: oreType = "Pierre noire"; break; // dull copper + // case CraftResource.MMytheril: oreType = "Mytheril"; break; // shadow iron + // case CraftResource.MRose: oreType = "Rose"; break; // copper + // case CraftResource.MVerite: oreType = "Verite"; break; // bronze + // case CraftResource.MAgapite: oreType = "Agapite"; break; // golden + // case CraftResource.MRusty: oreType = "Rouille"; break; // agapite + // case CraftResource.MValorite: oreType = "Valorite"; break; // verite + // case CraftResource.MDragon: oreType = "Dragon"; break; // valorite + // case CraftResource.MTitan: oreType = "Titan"; break; // dull copper + // case CraftResource.MCrystaline: oreType = "Crystaline"; break; // shadow iron + // case CraftResource.MKrynite: oreType = "Krynite"; break; // copper + // case CraftResource.MVulcan: oreType = "Vulcan"; break; // bronze + // case CraftResource.MBloodcrest: oreType = "Craie de sang"; break; // golden + // case CraftResource.MElvin: oreType = "Elvin"; break; // agapite + // case CraftResource.MAcid: oreType = "Acid"; break; // valorite + // case CraftResource.MAqua: oreType = "Aqua"; break; // copper + // case CraftResource.MEldar: oreType = "Eldar"; break; // bronze + // case CraftResource.MGlowing: oreType = "Glowing"; break; // golden + // case CraftResource.MGorgan: oreType = "Gorgan"; break; // agapite + // case CraftResource.MSandrock: oreType = "Pierre de sable"; break; // verite + // case CraftResource.MSteel: oreType = "Acier"; break; // valorite + // case CraftResource.SpinedLeather: oreType = "spined"; break; // spined + // case CraftResource.HornedLeather: oreType = "horned"; break; // horned + // case CraftResource.BarbedLeather: oreType = "barbed"; break; // barbed + // case CraftResource.RedScales: oreType = "red"; break; // red + // case CraftResource.YellowScales: oreType = "yellow"; break; // yellow + // case CraftResource.BlackScales: oreType = "black"; break; // black + // case CraftResource.GreenScales: oreType = "green"; break; // green + // case CraftResource.WhiteScales: oreType = "white"; break; // white + // case CraftResource.BlueScales: oreType = "blue"; break; // blue + // default: oreType = null; break; + + //} + //if ( m_Quality == ArmorQuality.Exceptional ) + //{ + // if ( oreType != null ) + // list.Add( 1053100, "{0}\t{1}", oreType, GetNameString() ); // exceptional ~1_oretype~ ~2_armortype~ + // else + // list.Add( 1050040, GetNameString() ); // exceptional ~1_ITEMNAME~ + //} + //else + //{ + // if ( oreType != null) + // list.Add( 1053099, "{0}\t{1}", oreType, GetNameString() ); // ~1_oretype~ ~2_armortype~ + // else + if ( Name == null ) + list.Add( LabelNumber ); + else + list.Add( Name ); + //} + } + + public override bool AllowEquipedCast( Mobile from ) + { + if ( base.AllowEquipedCast( from ) ) + return true; + + return ( m_AosAttributes.SpellChanneling != 0 ); + } + + public virtual int GetLuckBonus() + { + CraftResourceInfo resInfo = CraftResources.GetInfo( m_Resource ); + + if ( resInfo == null ) + return 0; + + CraftAttributeInfo attrInfo = resInfo.AttributeInfo; + + if ( attrInfo == null ) + return 0; + + return attrInfo.ArmorLuck; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if (m_HitPoints <= 0) + list.Add("Endommag�e"); + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if (RequiredRace == Race.Elf) + list.Add(1075086); // Elves Only + + if (m_Identified) + { + #region Factions + if ( m_FactionState != null ) + list.Add( 1041350 ); // faction item + #endregion + + m_AosSkillBonuses.GetProperties( list ); + + int prop; + + + if ((prop = ArtifactRarity) > 0) + list.Add(1061078, prop.ToString()); // artifact rarity ~1_val~ + + if ((prop = m_AosAttributes.WeaponDamage) != 0) + list.Add(1060401, prop.ToString()); // damage increase ~1_val~% + + if ((prop = m_AosAttributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = m_AosAttributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = m_AosAttributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = m_AosAttributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = m_AosAttributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = m_AosAttributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = m_AosAttributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = m_AosAttributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = m_AosAttributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = m_AosAttributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = GetLowerStatReq()) != 0) + list.Add(1060435, prop.ToString()); // lower requirements ~1_val~% + + if ((prop = (GetLuckBonus() + m_AosAttributes.Luck)) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = m_AosArmorAttributes.MageArmor) != 0) + list.Add(1060437); // mage armor + + if ((prop = m_AosAttributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = m_AosAttributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if ((prop = m_AosAttributes.NightSight) != 0) + list.Add(1060441); // night sight + + if ((prop = m_AosAttributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = m_AosAttributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = m_AosAttributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if ((prop = m_AosArmorAttributes.SelfRepair) != 0) + list.Add(1060450, prop.ToString()); // self repair ~1_val~ + + if ((prop = m_AosAttributes.SpellChanneling) != 0) + list.Add(1060482); // spell channeling + + if ((prop = m_AosAttributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = m_AosAttributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = m_AosAttributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = m_AosAttributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if (Core.ML && (prop = m_AosAttributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + base.AddResistanceProperties(list); + + if ((prop = GetDurabilityBonus()) > 0) + list.Add(1060410, prop.ToString()); // durability ~1_val~% + + if ((prop = ComputeStatReq(StatType.Str)) > 0) + list.Add(1061170, prop.ToString()); // strength requirement ~1_val~ + //Plume : Disponible via ArmLore + //if (m_HitPoints >= 0 && m_MaxHitPoints > 0) + // list.Add(1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints); // durability ~1_val~ / ~2_val~ + + } + if (!m_Identified) + list.Add("Non identifi�"); + } + + public override void OnSingleClick( Mobile from ) + { + List attrs = new List(); + + if ( DisplayLootType ) + { + if ( LootType == LootType.Blessed ) + attrs.Add( new EquipInfoAttribute( 1038021 ) ); // blessed + else if ( LootType == LootType.Cursed ) + attrs.Add( new EquipInfoAttribute( 1049643 ) ); // cursed + } + + #region Factions + if ( m_FactionState != null ) + attrs.Add( new EquipInfoAttribute( 1041350 ) ); // faction item + #endregion + + if ( m_Quality == ArmorQuality.Exceptional ) + attrs.Add( new EquipInfoAttribute( 1018305 - (int)m_Quality ) ); + + if ( m_Identified || from.AccessLevel >= AccessLevel.GameMaster) + { + if ( m_Durability != ArmorDurabilityLevel.Regular ) + attrs.Add( new EquipInfoAttribute( 1038000 + (int)m_Durability ) ); + + if ( m_Protection > ArmorProtectionLevel.Regular && m_Protection <= ArmorProtectionLevel.Invulnerability ) + attrs.Add( new EquipInfoAttribute( 1038005 + (int)m_Protection ) ); + } + else if ( m_Durability != ArmorDurabilityLevel.Regular || (m_Protection > ArmorProtectionLevel.Regular && m_Protection <= ArmorProtectionLevel.Invulnerability) ) + attrs.Add( new EquipInfoAttribute( 1038000 ) ); // Unidentified + + int number; + + if ( Name == null ) + { + number = LabelNumber; + } + else + { + this.LabelTo( from, Name ); + number = 1041000; + } + + if ( attrs.Count == 0 && Crafter == null && Name != null ) + return; + + EquipmentInfo eqInfo = new EquipmentInfo( number, m_Crafter, false, attrs.ToArray() ); + + from.Send( new DisplayEquipmentInfo( this, eqInfo ) ); + } + + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (ArmorQuality)quality; + + if ( makersMark ) + Crafter = from; + + Type resourceType = typeRes; + + if ( resourceType == null ) + resourceType = craftItem.Resources.GetAt( 0 ).ItemType; + + Resource = CraftResources.GetFromType( resourceType ); + PlayerConstructed = true; + Identified = true; + + CraftContext context = craftSystem.GetContext( from ); + + if ( context != null && context.DoNotColor ) + Hue = 0; + + if (Resource == CraftResource.MVulcan) + { + DistributeBonuses((int)from.FireResistance / 20); + } + + if (Resource == CraftResource.MGlowing) + { + int hours = 0; + int minutes = 0; + + Clock.GetTime( Map, Location.X, Location.Y, out hours, out minutes ); + + if ( hours < 18 && hours >7) + { + + DistributeBonuses(3); + } + } + + if( Quality == ArmorQuality.Exceptional ) + { + if (Resource == CraftResource.RegularLeather || Resource == CraftResource.SpinedLeather || Resource == CraftResource.HornedLeather || Resource == CraftResource.BarbedLeather || Resource == CraftResource.DaemonLeather) + DistributeBonuses(3); + else + DistributeBonuses(4); // Not sure since when, but right now 15 points are added, not 14. + + //DistributeBonuses( (tool is BaseRunicTool ? 6 : Core.SE ? 15 : 14) ); // Not sure since when, but right now 15 points are added, not 14. + + // if (!(Core.ML && this is BaseShield)) // Guessed Core.ML removed exceptional resist bonuses from crafted shields + // DistributeBonuses((tool is BaseRunicTool ? 6 : Core.SE ? 15 : 14)); // Not sure since when, but right now 15 points are added, not 14. + + if( Core.ML && !(this is BaseShield) ) + { + int bonus; + if(Resource == CraftResource.RegularLeather || Resource == CraftResource.SpinedLeather || Resource == CraftResource.HornedLeather || Resource == CraftResource.BarbedLeather || Resource == CraftResource.DaemonLeather) + bonus = (int)(from.Skills.ArmsLore.Value / 25); + else + bonus = (int)(from.Skills.ArmsLore.Value / 20); + + for( int i = 0; i < bonus; i++ ) + { + switch( Utility.Random( 5 ) ) + { + case 0: m_PhysicalBonus++; break; + case 1: m_FireBonus++; break; + case 2: m_ColdBonus++; break; + case 3: m_EnergyBonus++; break; + case 4: m_PoisonBonus++; break; + } + } + + from.CheckSkill( SkillName.ArmsLore, 0, 100 ); + } + } + + #region Mondain's Legacy + + if (Core.AOS && tool is BaseRunicTool) + ((BaseRunicTool)tool).ApplyAttributesTo(this); + + if (Core.ML) + { + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + + if (resInfo == null) + return quality; + + CraftAttributeInfo attrInfo = resInfo.AttributeInfo; + + if (attrInfo == null) + return quality; + + + m_AosAttributes.WeaponDamage += attrInfo.ArmorDamage; + m_AosAttributes.AttackChance += attrInfo.ArmorHitChance; + m_AosAttributes.RegenHits += attrInfo.ArmorRegenHits; + m_AosArmorAttributes.MageArmor += attrInfo.ArmorMage; + + + } + + #endregion + + return quality; + } + + #endregion + } +} diff --git a/Scripts/Items/Armor/Bone/BoneArms.cs b/Scripts/Items/Armor/Bone/BoneArms.cs new file mode 100644 index 0000000..daf3f5a --- /dev/null +++ b/Scripts/Items/Armor/Bone/BoneArms.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x144e, 0x1453 )] + public class BoneArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 30; } } + public override int RevertArmorBase{ get{ return 4; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public BoneArms() : base( 0x144E ) + { + Weight = 2.0; + } + + public BoneArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Bone/BoneChest.cs b/Scripts/Items/Armor/Bone/BoneChest.cs new file mode 100644 index 0000000..b0018d7 --- /dev/null +++ b/Scripts/Items/Armor/Bone/BoneChest.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x144f, 0x1454 )] + public class BoneChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 60; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -6; } } + + public override int ArmorBase{ get{ return 30; } } + public override int RevertArmorBase{ get{ return 11; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public BoneChest() : base( 0x144F ) + { + Weight = 6.0; + } + + public BoneChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + if ( Weight == 1.0 ) + Weight = 6.0; + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Bone/BoneGloves.cs b/Scripts/Items/Armor/Bone/BoneGloves.cs new file mode 100644 index 0000000..458fd60 --- /dev/null +++ b/Scripts/Items/Armor/Bone/BoneGloves.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1450, 0x1455 )] + public class BoneGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 30; } } + public override int RevertArmorBase{ get{ return 2; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public BoneGloves() : base( 0x1450 ) + { + Weight = 2.0; + } + + public BoneGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Bone/BoneLegs.cs b/Scripts/Items/Armor/Bone/BoneLegs.cs new file mode 100644 index 0000000..cda05fc --- /dev/null +++ b/Scripts/Items/Armor/Bone/BoneLegs.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1452, 0x1457 )] + public class BoneLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -4; } } + + public override int ArmorBase{ get{ return 30; } } + public override int RevertArmorBase{ get{ return 7; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public BoneLegs() : base( 0x1452 ) + { + Weight = 3.0; + } + + public BoneLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Chain/ChainChest.cs b/Scripts/Items/Armor/Chain/ChainChest.cs new file mode 100644 index 0000000..b1a014a --- /dev/null +++ b/Scripts/Items/Armor/Chain/ChainChest.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13bf, 0x13c4 )] + public class ChainChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 4; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 1; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 60; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -5; } } + + public override int ArmorBase{ get{ return 28; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Chainmail; } } + + [Constructable] + public ChainChest() : base( 0x13BF ) + { + Weight = 7.0; + } + + public ChainChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Chain/ChainHatsuburi.cs b/Scripts/Items/Armor/Chain/ChainHatsuburi.cs new file mode 100644 index 0000000..edb5cf1 --- /dev/null +++ b/Scripts/Items/Armor/Chain/ChainHatsuburi.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ChainHatsuburi : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 50; } } + public override int OldStrReq{ get{ return 50; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Chainmail; } } + + [Constructable] + public ChainHatsuburi() : base( 0x2774 ) + { + Weight = 7.0; + } + + public ChainHatsuburi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Chain/ChainLegs.cs b/Scripts/Items/Armor/Chain/ChainLegs.cs new file mode 100644 index 0000000..8fa7a3e --- /dev/null +++ b/Scripts/Items/Armor/Chain/ChainLegs.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13be, 0x13c3 )] + public class ChainLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 4; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 1; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 60; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -3; } } + + public override int ArmorBase{ get{ return 28; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Chainmail; } } + + [Constructable] + public ChainLegs() : base( 0x13BE ) + { + Weight = 7.0; + } + + public ChainLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/DaemonBone/DaemonArms.cs b/Scripts/Items/Armor/DaemonBone/DaemonArms.cs new file mode 100644 index 0000000..b1abe59 --- /dev/null +++ b/Scripts/Items/Armor/DaemonBone/DaemonArms.cs @@ -0,0 +1,63 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x144e, 0x1453 )] + public class DaemonArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 46; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041371; } } // daemon bone arms + + [Constructable] + public DaemonArms() : base( 0x144E ) + { + Weight = 2.0; + Hue = 0x648; + + ArmorAttributes.SelfRepair = 1; + } + + public DaemonArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ArmorAttributes.SelfRepair == 0 ) + ArmorAttributes.SelfRepair = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/DaemonBone/DaemonChest.cs b/Scripts/Items/Armor/DaemonBone/DaemonChest.cs new file mode 100644 index 0000000..4d2f31c --- /dev/null +++ b/Scripts/Items/Armor/DaemonBone/DaemonChest.cs @@ -0,0 +1,63 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x144f, 0x1454 )] + public class DaemonChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + public override int AosStrReq{ get{ return 60; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -6; } } + + public override int ArmorBase{ get{ return 46; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041372; } } // daemon bone armor + + [Constructable] + public DaemonChest() : base( 0x144F ) + { + Weight = 6.0; + Hue = 0x648; + + ArmorAttributes.SelfRepair = 1; + } + + public DaemonChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 6.0; + + if ( ArmorAttributes.SelfRepair == 0 ) + ArmorAttributes.SelfRepair = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/DaemonBone/DaemonGloves.cs b/Scripts/Items/Armor/DaemonBone/DaemonGloves.cs new file mode 100644 index 0000000..f684a0c --- /dev/null +++ b/Scripts/Items/Armor/DaemonBone/DaemonGloves.cs @@ -0,0 +1,63 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1450, 0x1455 )] + public class DaemonGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 46; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041373; } } // daemon bone gloves + + [Constructable] + public DaemonGloves() : base( 0x1450 ) + { + Weight = 2.0; + Hue = 0x648; + + ArmorAttributes.SelfRepair = 1; + } + + public DaemonGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + + if ( ArmorAttributes.SelfRepair == 0 ) + ArmorAttributes.SelfRepair = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/DaemonBone/DaemonLegs.cs b/Scripts/Items/Armor/DaemonBone/DaemonLegs.cs new file mode 100644 index 0000000..05a8a7c --- /dev/null +++ b/Scripts/Items/Armor/DaemonBone/DaemonLegs.cs @@ -0,0 +1,58 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1452, 0x1457 )] + public class DaemonLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -4; } } + + public override int ArmorBase{ get{ return 46; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041375; } } // daemon bone leggings + + [Constructable] + public DaemonLegs() : base( 0x1452 ) + { + Weight = 3.0; + Hue = 0x648; + + ArmorAttributes.SelfRepair = 1; + } + + public DaemonLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( ArmorAttributes.SelfRepair == 0 ) + ArmorAttributes.SelfRepair = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Dragon/DragonArms.cs b/Scripts/Items/Armor/Dragon/DragonArms.cs new file mode 100644 index 0000000..27706e2 --- /dev/null +++ b/Scripts/Items/Armor/Dragon/DragonArms.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2657, 0x2658 )] + public class DragonArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 75; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Dragon; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RedScales; } } + + [Constructable] + public DragonArms() : base( 0x2657 ) + { + Weight = 5.0; + } + + public DragonArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 15.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Dragon/DragonChest.cs b/Scripts/Items/Armor/Dragon/DragonChest.cs new file mode 100644 index 0000000..274e4f5 --- /dev/null +++ b/Scripts/Items/Armor/Dragon/DragonChest.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2641, 0x2642 )] + public class DragonChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 75; } } + public override int OldStrReq{ get{ return 60; } } + + public override int OldDexBonus{ get{ return -8; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Dragon; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RedScales; } } + + [Constructable] + public DragonChest() : base( 0x2641 ) + { + Weight = 10.0; + } + + public DragonChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 15.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Dragon/DragonGloves.cs b/Scripts/Items/Armor/Dragon/DragonGloves.cs new file mode 100644 index 0000000..c4fbaa1 --- /dev/null +++ b/Scripts/Items/Armor/Dragon/DragonGloves.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2643, 0x2644 )] + public class DragonGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 75; } } + public override int OldStrReq{ get{ return 30; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Dragon; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RedScales; } } + + [Constructable] + public DragonGloves() : base( 0x2643 ) + { + Weight = 2.0; + } + + public DragonGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Dragon/DragonHelm.cs b/Scripts/Items/Armor/Dragon/DragonHelm.cs new file mode 100644 index 0000000..8a7489c --- /dev/null +++ b/Scripts/Items/Armor/Dragon/DragonHelm.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [Flipable( 0x2645, 0x2646 )] + public class DragonHelm : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 75; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Dragon; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RedScales; } } + + [Constructable] + public DragonHelm() : base( 0x2645 ) + { + Weight = 5.0; + } + + public DragonHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Dragon/DragonLegs.cs b/Scripts/Items/Armor/Dragon/DragonLegs.cs new file mode 100644 index 0000000..3527a6d --- /dev/null +++ b/Scripts/Items/Armor/Dragon/DragonLegs.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2647, 0x2648 )] + public class DragonLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 75; } } + public override int OldStrReq{ get{ return 60; } } + + public override int OldDexBonus{ get{ return -6; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Dragon; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RedScales; } } + + [Constructable] + public DragonLegs() : base( 0x2647 ) + { + Weight = 6.0; + } + + public DragonLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Glasses/AnthropomorphistGlasses.cs b/Scripts/Items/Armor/Glasses/AnthropomorphistGlasses.cs new file mode 100644 index 0000000..2dc458f --- /dev/null +++ b/Scripts/Items/Armor/Glasses/AnthropomorphistGlasses.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AnthropomorphistGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073379; } } //Anthropomorphist Reading Glasses + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 20; } } + public override int BaseEnergyResistance{ get{ return 20; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + + [Constructable] + public AnthropomorphistGlasses() + { + Attributes.BonusHits = 5; + Attributes.RegenMana = 3; + Attributes.ReflectPhysical = 20; + + Hue = 0x80; + } + public AnthropomorphistGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x80; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/ArtsGlasses.cs b/Scripts/Items/Armor/Glasses/ArtsGlasses.cs new file mode 100644 index 0000000..719d297 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/ArtsGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArtsGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073363; } } //Reading Glasses of the Arts + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 8; } } + public override int BaseColdResistance{ get{ return 8; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ArtsGlasses() + { + Attributes.BonusStr = 5; + Attributes.BonusInt = 5; + Attributes.BonusHits = 15; + + Hue = 0x73; + } + public ArtsGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x73; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/ElvenGlasses.cs b/Scripts/Items/Armor/Glasses/ElvenGlasses.cs new file mode 100644 index 0000000..42086d4 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/ElvenGlasses.cs @@ -0,0 +1,149 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ElvenGlasses : BaseArmor + { + public override int LabelNumber { get { return 1032216; } } // elven glasses + + public override int BasePhysicalResistance { get { return 2; } } + public override int BaseFireResistance { get { return 4; } } + public override int BaseColdResistance { get { return 4; } } + public override int BasePoisonResistance { get { return 3; } } + public override int BaseEnergyResistance { get { return 2; } } + + public override int InitMinHits { get { return 36; } } + public override int InitMaxHits { get { return 48; } } + + public override int AosStrReq { get { return 45; } } + public override int OldStrReq { get { return 40; } } + + public override int ArmorBase { get { return 30; } } + + public override ArmorMaterialType MaterialType { get { return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + public override ArmorMeditationAllowance DefMedAllowance { get { return ArmorMeditationAllowance.All; } } + + private AosWeaponAttributes m_AosWeaponAttributes; + + [CommandProperty(AccessLevel.GameMaster)] + public AosWeaponAttributes WeaponAttributes + { + get { return m_AosWeaponAttributes; } + set { } + } + + [Constructable] + public ElvenGlasses() + : base(0x2FB8) + { + Weight = 2; + m_AosWeaponAttributes = new AosWeaponAttributes(this); + } + + public ElvenGlasses(Serial serial) + : base(serial) + { + } + + public override void AppendChildNameProperties(ObjectPropertyList list) + { + base.AppendChildNameProperties(list); + + int prop; + + if ((prop = m_AosWeaponAttributes.HitColdArea) != 0) + list.Add(1060416, prop.ToString()); // hit cold area ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitDispel) != 0) + list.Add(1060417, prop.ToString()); // hit dispel ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitEnergyArea) != 0) + list.Add(1060418, prop.ToString()); // hit energy area ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitFireArea) != 0) + list.Add(1060419, prop.ToString()); // hit fire area ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitFireball) != 0) + list.Add(1060420, prop.ToString()); // hit fireball ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitHarm) != 0) + list.Add(1060421, prop.ToString()); // hit harm ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitLeechHits) != 0) + list.Add(1060422, prop.ToString()); // hit life leech ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitLightning) != 0) + list.Add(1060423, prop.ToString()); // hit lightning ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitLowerAttack) != 0) + list.Add(1060424, prop.ToString()); // hit lower attack ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitLowerDefend) != 0) + list.Add(1060425, prop.ToString()); // hit lower defense ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitMagicArrow) != 0) + list.Add(1060426, prop.ToString()); // hit magic arrow ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitLeechMana) != 0) + list.Add(1060427, prop.ToString()); // hit mana leech ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitPhysicalArea) != 0) + list.Add(1060428, prop.ToString()); // hit physical area ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitPoisonArea) != 0) + list.Add(1060429, prop.ToString()); // hit poison area ~1_val~% + + if ((prop = m_AosWeaponAttributes.HitLeechStam) != 0) + list.Add(1060430, prop.ToString()); // hit stamina leech ~1_val~% + } + + private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + { + if (setIf) + flags |= toSet; + } + + private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) + { + return ((flags & toGet) != 0); + } + + private enum SaveFlag + { + None = 0x00000000, + WeaponAttributes = 0x00000001, + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag(ref flags, SaveFlag.WeaponAttributes, !m_AosWeaponAttributes.IsEmpty); + + writer.Write((int)flags); + + if (GetSaveFlag(flags, SaveFlag.WeaponAttributes)) + m_AosWeaponAttributes.Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + SaveFlag flags = (SaveFlag)reader.ReadInt(); + + if (GetSaveFlag(flags, SaveFlag.WeaponAttributes)) + m_AosWeaponAttributes = new AosWeaponAttributes(this, reader); + else + m_AosWeaponAttributes = new AosWeaponAttributes(this); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Glasses/FoldedSteelGlasses.cs b/Scripts/Items/Armor/Glasses/FoldedSteelGlasses.cs new file mode 100644 index 0000000..f01c032 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/FoldedSteelGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FoldedSteelGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073380; } } //Folded Steel Reading Glasses + + public override int BasePhysicalResistance{ get{ return 20; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public FoldedSteelGlasses() + { + Attributes.BonusStr = 8; + Attributes.NightSight = 1; + Attributes.DefendChance = 15; + + Hue = 0x47E; + } + public FoldedSteelGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x47E; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/LightOfWayGlasses.cs b/Scripts/Items/Armor/Glasses/LightOfWayGlasses.cs new file mode 100644 index 0000000..04e0f10 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/LightOfWayGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LightOfWayGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073378; } } //Light Of Way Reading Glasses + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public LightOfWayGlasses() + { + Attributes.BonusStr = 7; + Attributes.BonusInt = 5; + Attributes.WeaponDamage = 30; + + Hue = 0x256; + } + public LightOfWayGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x256; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/LyricalGlasses.cs b/Scripts/Items/Armor/Glasses/LyricalGlasses.cs new file mode 100644 index 0000000..49c3561 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/LyricalGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LyricalGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073382; } } //Lyrical Reading Glasses + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public LyricalGlasses() + { + WeaponAttributes.HitLowerDefend = 20; + Attributes.NightSight = 1; + Attributes.ReflectPhysical = 15; + + Hue = 0x47F; + } + public LyricalGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x47F; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/MaceShieldGlasses.cs b/Scripts/Items/Armor/Glasses/MaceShieldGlasses.cs new file mode 100644 index 0000000..0a2c099 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/MaceShieldGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MaceShieldGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073381; } } //Mace And Shield Reading Glasses + + public override int BasePhysicalResistance{ get{ return 25; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public MaceShieldGlasses() + { + WeaponAttributes.HitLowerDefend = 30; + Attributes.BonusStr = 10; + Attributes.BonusDex = 5; + + Hue = 0x1DD; + } + public MaceShieldGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x1DD; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/MaritimeGlasses.cs b/Scripts/Items/Armor/Glasses/MaritimeGlasses.cs new file mode 100644 index 0000000..2f75eb8 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/MaritimeGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MaritimeGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073364; } } //Maritime Reading Glasses + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 30; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public MaritimeGlasses() + { + Attributes.Luck = 150; + Attributes.NightSight = 1; + Attributes.ReflectPhysical = 20; + + Hue = 0x581; + } + public MaritimeGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x581; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/NecromanticGlasses.cs b/Scripts/Items/Armor/Glasses/NecromanticGlasses.cs new file mode 100644 index 0000000..b76c998 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/NecromanticGlasses.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NecromanticGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073377; } } //Necromantic Reading Glasses + + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public NecromanticGlasses() + { + Attributes.LowerManaCost = 15; + Attributes.LowerRegCost = 30; + + Hue = 0x22D; + } + public NecromanticGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x22D; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/PoisonedGlasses.cs b/Scripts/Items/Armor/Glasses/PoisonedGlasses.cs new file mode 100644 index 0000000..d582976 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/PoisonedGlasses.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PoisonedGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073376; } } //Poisoned Reading Glasses + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 30; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public PoisonedGlasses() + { + Attributes.BonusStam = 3; + Attributes.RegenStam = 4; + + Hue = 0x113; + } + public PoisonedGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x113; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/TradeGlasses.cs b/Scripts/Items/Armor/Glasses/TradeGlasses.cs new file mode 100644 index 0000000..6e4da55 --- /dev/null +++ b/Scripts/Items/Armor/Glasses/TradeGlasses.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TradeGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073362; } } //Reading Glasses of the Trades + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TradeGlasses() + { + Attributes.BonusStr = 10; + Attributes.BonusInt = 10; + } + public TradeGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Armor/Glasses/TreasureTrinketGlasses.cs b/Scripts/Items/Armor/Glasses/TreasureTrinketGlasses.cs new file mode 100644 index 0000000..10a168f --- /dev/null +++ b/Scripts/Items/Armor/Glasses/TreasureTrinketGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TreasureTrinketGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073373; } } //Treasures and Trinkets Reading Glasses + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TreasureTrinketGlasses() + { + Attributes.BonusInt = 10; + Attributes.BonusHits = 5; + Attributes.SpellDamage = 10; + + Hue = 0x1C2; + } + public TreasureTrinketGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x1C2; + } + } +} diff --git a/Scripts/Items/Armor/Glasses/WizardsGlasses.cs b/Scripts/Items/Armor/Glasses/WizardsGlasses.cs new file mode 100644 index 0000000..4f482ba --- /dev/null +++ b/Scripts/Items/Armor/Glasses/WizardsGlasses.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WizardsGlasses : ElvenGlasses + { + public override int LabelNumber{ get{ return 1073374; } } //Wizard's Crystal Reading Glasses + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public WizardsGlasses() + { + Attributes.BonusMana = 10; + Attributes.RegenMana = 3; + Attributes.SpellDamage = 15; + + Hue = 0x2B0; + } + public WizardsGlasses( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Hue == 0 ) + Hue = 0x2B0; + } + } +} diff --git a/Scripts/Items/Armor/Helmets/Bascinet.cs b/Scripts/Items/Armor/Helmets/Bascinet.cs new file mode 100644 index 0000000..c0f6eb6 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/Bascinet.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Bascinet : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 7; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 18; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public Bascinet() : base( 0x140C ) + { + Weight = 5.0; + } + + public Bascinet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/BoneHelm.cs b/Scripts/Items/Armor/Helmets/BoneHelm.cs new file mode 100644 index 0000000..ada1619 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/BoneHelm.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x1451, 0x1456 )] + public class BoneHelm : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 40; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public BoneHelm() : base( 0x1451 ) + { + Weight = 3.0; + } + + public BoneHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + if ( Weight == 1.0 ) + Weight = 3.0; + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/ChainCoif.cs b/Scripts/Items/Armor/Helmets/ChainCoif.cs new file mode 100644 index 0000000..e93ba32 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/ChainCoif.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x13BB, 0x13C0 )] + public class ChainCoif : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 4; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 1; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 60; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 28; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Chainmail; } } + + [Constructable] + public ChainCoif() : base( 0x13BB ) + { + Weight = 1.0; + } + + public ChainCoif( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/Circlet.cs b/Scripts/Items/Armor/Helmets/Circlet.cs new file mode 100644 index 0000000..05984df --- /dev/null +++ b/Scripts/Items/Armor/Helmets/Circlet.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B6E, 0x3165 )] + public class Circlet : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 1; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + // Scriptiz : tous peuvent le porter + //public override Race RequiredRace{ get { return Race.Elf; } } + + [Constructable] + public Circlet() : base( 0x2B6E ) + { + Weight = 2.0; + } + + public Circlet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/CloseHelm.cs b/Scripts/Items/Armor/Helmets/CloseHelm.cs new file mode 100644 index 0000000..920d69c --- /dev/null +++ b/Scripts/Items/Armor/Helmets/CloseHelm.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CloseHelm : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public CloseHelm() : base( 0x1408 ) + { + Weight = 5.0; + } + + public CloseHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/DaemonHelm.cs b/Scripts/Items/Armor/Helmets/DaemonHelm.cs new file mode 100644 index 0000000..b41fadd --- /dev/null +++ b/Scripts/Items/Armor/Helmets/DaemonHelm.cs @@ -0,0 +1,61 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x1451, 0x1456 )] + public class DaemonHelm : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 40; } } + + public override int ArmorBase{ get{ return 46; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Bone; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041374; } } // daemon bone helmet + + [Constructable] + public DaemonHelm() : base( 0x1451 ) + { + Hue = 0x648; + Weight = 3.0; + + ArmorAttributes.SelfRepair = 1; + } + + public DaemonHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 3.0; + + if ( ArmorAttributes.SelfRepair == 0 ) + ArmorAttributes.SelfRepair = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/GemmedCirclet.cs b/Scripts/Items/Armor/Helmets/GemmedCirclet.cs new file mode 100644 index 0000000..01613cb --- /dev/null +++ b/Scripts/Items/Armor/Helmets/GemmedCirclet.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B70, 0x3167 )] + public class GemmedCirclet : BaseArmor + { + // Scriptiz : tous peuvent le porter + //public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 1; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 35; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public GemmedCirclet() : base( 0x2B70 ) + { + Weight = 2.0; + } + + public GemmedCirclet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/Helmet.cs b/Scripts/Items/Armor/Helmets/Helmet.cs new file mode 100644 index 0000000..6923554 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/Helmet.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Helmet : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 45; } } + public override int OldStrReq{ get{ return 40; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public Helmet() : base( 0x140A ) + { + Weight = 5.0; + } + + public Helmet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/LeatherCap.cs b/Scripts/Items/Armor/Helmets/LeatherCap.cs new file mode 100644 index 0000000..a35a97d --- /dev/null +++ b/Scripts/Items/Armor/Helmets/LeatherCap.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x1db9, 0x1dba )] + public class LeatherCap : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherCap() : base( 0x1DB9 ) + { + Weight = 2.0; + } + + public LeatherCap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/NorseHelm.cs b/Scripts/Items/Armor/Helmets/NorseHelm.cs new file mode 100644 index 0000000..93ae482 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/NorseHelm.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NorseHelm : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 4; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 40; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public NorseHelm() : base( 0x140E ) + { + Weight = 5.0; + } + + public NorseHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/OrcHelm.cs b/Scripts/Items/Armor/Helmets/OrcHelm.cs new file mode 100644 index 0000000..7f5fd96 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/OrcHelm.cs @@ -0,0 +1,57 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrcHelm : BaseArmor + { + public override int BasePhysicalResistance { get { return 3; } } + public override int BaseFireResistance { get { return 1; } } + public override int BaseColdResistance { get { return 3; } } + public override int BasePoisonResistance { get { return 3; } } + public override int BaseEnergyResistance { get { return 5; } } + + public override int InitMinHits { get { return 30; } } + public override int InitMaxHits { get { return 50; } } + + public override int AosStrReq { get { return 30; } } + public override int OldStrReq { get { return 10; } } + + public override int ArmorBase { get { return 20; } } + + public override double DefaultWeight { get { return 5; } } + + public override ArmorMaterialType MaterialType { get { return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance { get { return ArmorMeditationAllowance.None; } } + + [Constructable] + public OrcHelm() + : base(0x1F0B) + { + } + + public OrcHelm(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + if (version == 0 && (Weight == 1 || Weight == 5)) + { + Weight = -1; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/PlateHelm.cs b/Scripts/Items/Armor/Helmets/PlateHelm.cs new file mode 100644 index 0000000..433c349 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/PlateHelm.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PlateHelm : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 80; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateHelm() : base( 0x1412 ) + { + Weight = 5.0; + } + + public PlateHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/RavenHelm.cs b/Scripts/Items/Armor/Helmets/RavenHelm.cs new file mode 100644 index 0000000..e5eb132 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/RavenHelm.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B71, 0x3168 )] + public class RavenHelm : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public RavenHelm() : base( 0x2B71 ) + { + Weight = 5.0; + } + + public RavenHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/RoyalCirclet.cs b/Scripts/Items/Armor/Helmets/RoyalCirclet.cs new file mode 100644 index 0000000..9174942 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/RoyalCirclet.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B6F, 0x3166 )] + public class RoyalCirclet : BaseArmor + { + // Scriptiz : tous peuvent le porter + //public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 1; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 35; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public RoyalCirclet() : base( 0x2B6F ) + { + Weight = 2.0; + } + + public RoyalCirclet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/VultureHelm.cs b/Scripts/Items/Armor/Helmets/VultureHelm.cs new file mode 100644 index 0000000..2ff6129 --- /dev/null +++ b/Scripts/Items/Armor/Helmets/VultureHelm.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B72, 0x3169 )] + public class VultureHelm : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public VultureHelm() : base( 0x2B72 ) + { + Weight = 5.0; + } + + public VultureHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Helmets/WingedHelm.cs b/Scripts/Items/Armor/Helmets/WingedHelm.cs new file mode 100644 index 0000000..4e1803c --- /dev/null +++ b/Scripts/Items/Armor/Helmets/WingedHelm.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B73, 0x316A )] + public class WingedHelm : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 55; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public WingedHelm() : base( 0x2B73 ) + { + Weight = 5.0; + } + + public WingedHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/FemaleLeafChest.cs b/Scripts/Items/Armor/Leather/FemaleLeafChest.cs new file mode 100644 index 0000000..116444b --- /dev/null +++ b/Scripts/Items/Armor/Leather/FemaleLeafChest.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2FCB, 0x3181 )] + public class FemaleLeafChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public FemaleLeafChest() : base( 0x2FCB ) + { + Weight = 2.0; + } + + public FemaleLeafChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/FemaleLeatherChest.cs b/Scripts/Items/Armor/Leather/FemaleLeatherChest.cs new file mode 100644 index 0000000..7335976 --- /dev/null +++ b/Scripts/Items/Armor/Leather/FemaleLeatherChest.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c06, 0x1c07 )] + public class FemaleLeatherChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public FemaleLeatherChest() : base( 0x1C06 ) + { + Weight = 1.0; + } + + public FemaleLeatherChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeafArms.cs b/Scripts/Items/Armor/Leather/LeafArms.cs new file mode 100644 index 0000000..7f9cad1 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeafArms.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2FC8, 0x317E )] + public class LeafArms : BaseArmor + { + //public override Race RequiredRace { get { return Race.Elf; } } + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 15; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeafArms() : base( 0x2FC8 ) + { + Weight = 2.0; + } + + public LeafArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeafChest.cs b/Scripts/Items/Armor/Leather/LeafChest.cs new file mode 100644 index 0000000..df34ac8 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeafChest.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2FC5, 0x317B )] + public class LeafChest : BaseArmor + { + //public override Race RequiredRace { get { return Race.Elf; } } + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeafChest() : base( 0x2FC5 ) + { + Weight = 2.0; + } + + public LeafChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeafGloves.cs b/Scripts/Items/Armor/Leather/LeafGloves.cs new file mode 100644 index 0000000..90c7a9c --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeafGloves.cs @@ -0,0 +1,140 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [Flipable] + public class LeafGloves : BaseArmor, IArcaneEquip + { + //public override Race RequiredRace { get { return Race.Elf; } } + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeafGloves() : base( 0x2FC6 ) + { + Weight = 2.0; + } + + public LeafGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + if ( IsArcane ) + { + writer.Write( true ); + writer.Write( (int) m_CurArcaneCharges ); + writer.Write( (int) m_MaxArcaneCharges ); + } + else + { + writer.Write( false ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + if ( reader.ReadBool() ) + { + m_CurArcaneCharges = reader.ReadInt(); + m_MaxArcaneCharges = reader.ReadInt(); + + if ( Hue == 2118 ) + Hue = ArcaneGem.DefaultArcaneHue; + } + + break; + } + } + } + + #region Arcane Impl + private int m_MaxArcaneCharges, m_CurArcaneCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxArcaneCharges + { + get{ return m_MaxArcaneCharges; } + set{ m_MaxArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurArcaneCharges + { + get{ return m_CurArcaneCharges; } + set{ m_CurArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsArcane + { + get{ return ( m_MaxArcaneCharges > 0 && m_CurArcaneCharges >= 0 ); } + } + + public void Update() + { + if ( IsArcane ) + ItemID = 0x26B0; // TODO: Check + else if ( ItemID == 0x26B0 ) + ItemID = 0x2FC6; + + if ( IsArcane && CurArcaneCharges == 0 ) + Hue = 0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( IsArcane ) + list.Add( 1061837, "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ); // arcane charges: ~1_val~ / ~2_val~ + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsArcane ) + LabelTo( from, 1061837, String.Format( "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ) ); + } + + public void Flip() + { + if ( ItemID == 0x2FC6 ) + ItemID = 0x317C; + else if ( ItemID == 0x317C ) + ItemID = 0x2FC6; + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeafGorget.cs b/Scripts/Items/Armor/Leather/LeafGorget.cs new file mode 100644 index 0000000..9981650 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeafGorget.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeafGorget : BaseArmor + { + //public override Race RequiredRace { get { return Race.Elf; } } + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeafGorget() : base( 0x2FC7 ) + { + Weight = 2.0; + } + + public LeafGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeafLegs.cs b/Scripts/Items/Armor/Leather/LeafLegs.cs new file mode 100644 index 0000000..32af895 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeafLegs.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2FC9, 0x317F )] + public class LeafLegs : BaseArmor + { + //public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeafLegs() : base( 0x2FC9 ) + { + Weight = 2.0; + } + + public LeafLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeafTonlet.cs b/Scripts/Items/Armor/Leather/LeafTonlet.cs new file mode 100644 index 0000000..cce1d15 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeafTonlet.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2FCA, 0x3180 )] + public class LeafTonlet : BaseArmor + { + //public override Race RequiredRace { get { return Race.Elf; } } + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeafTonlet() : base( 0x2FCA ) + { + Weight = 2.0; + } + + public LeafTonlet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherArms.cs b/Scripts/Items/Armor/Leather/LeatherArms.cs new file mode 100644 index 0000000..f5018e4 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherArms.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13cd, 0x13c5 )] + public class LeatherArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherArms() : base( 0x13CD ) + { + Weight = 2.0; + } + + public LeatherArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherBustierArms.cs b/Scripts/Items/Armor/Leather/LeatherBustierArms.cs new file mode 100644 index 0000000..eb3f3d3 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherBustierArms.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c0a, 0x1c0b )] + public class LeatherBustierArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public LeatherBustierArms() : base( 0x1C0A ) + { + Weight = 1.0; + } + + public LeatherBustierArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherChest.cs b/Scripts/Items/Armor/Leather/LeatherChest.cs new file mode 100644 index 0000000..4694e39 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherChest.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13cc, 0x13d3 )] + public class LeatherChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherChest() : base( 0x13CC ) + { + Weight = 6.0; + } + + public LeatherChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 6.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherDo.cs b/Scripts/Items/Armor/Leather/LeatherDo.cs new file mode 100644 index 0000000..676aa26 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherDo.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherDo : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 40; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherDo() : base( 0x27C6 ) + { + Weight = 6.0; + } + + public LeatherDo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherGloves.cs b/Scripts/Items/Armor/Leather/LeatherGloves.cs new file mode 100644 index 0000000..13ccebc --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherGloves.cs @@ -0,0 +1,139 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [Flipable] + public class LeatherGloves : BaseArmor, IArcaneEquip + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherGloves() : base( 0x13C6 ) + { + Weight = 1.0; + } + + public LeatherGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + if ( IsArcane ) + { + writer.Write( true ); + writer.Write( (int) m_CurArcaneCharges ); + writer.Write( (int) m_MaxArcaneCharges ); + } + else + { + writer.Write( false ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + if ( reader.ReadBool() ) + { + m_CurArcaneCharges = reader.ReadInt(); + m_MaxArcaneCharges = reader.ReadInt(); + + if ( Hue == 2118 ) + Hue = ArcaneGem.DefaultArcaneHue; + } + + break; + } + } + } + + #region Arcane Impl + private int m_MaxArcaneCharges, m_CurArcaneCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxArcaneCharges + { + get{ return m_MaxArcaneCharges; } + set{ m_MaxArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurArcaneCharges + { + get{ return m_CurArcaneCharges; } + set{ m_CurArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsArcane + { + get{ return ( m_MaxArcaneCharges > 0 && m_CurArcaneCharges >= 0 ); } + } + + public void Update() + { + if ( IsArcane ) + ItemID = 0x26B0; + else if ( ItemID == 0x26B0 ) + ItemID = 0x13C6; + + if ( IsArcane && CurArcaneCharges == 0 ) + Hue = 0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( IsArcane ) + list.Add( 1061837, "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ); // arcane charges: ~1_val~ / ~2_val~ + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsArcane ) + LabelTo( from, 1061837, String.Format( "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ) ); + } + + public void Flip() + { + if ( ItemID == 0x13C6 ) + ItemID = 0x13CE; + else if ( ItemID == 0x13CE ) + ItemID = 0x13C6; + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherGorget.cs b/Scripts/Items/Armor/Leather/LeatherGorget.cs new file mode 100644 index 0000000..ae49fde --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherGorget.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherGorget : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherGorget() : base( 0x13C7 ) + { + Weight = 1.0; + } + + public LeatherGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherHaidate.cs b/Scripts/Items/Armor/Leather/LeatherHaidate.cs new file mode 100644 index 0000000..ee3af5d --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherHaidate.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherHaidate : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType { get { return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherHaidate() : base( 0x278A ) + { + Weight = 4.0; + } + + public LeatherHaidate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherHiroSode.cs b/Scripts/Items/Armor/Leather/LeatherHiroSode.cs new file mode 100644 index 0000000..f57e0bc --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherHiroSode.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherHiroSode : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherHiroSode() : base( 0x277E ) + { + Weight = 1.0; + } + + public LeatherHiroSode( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherJingasa.cs b/Scripts/Items/Armor/Leather/LeatherJingasa.cs new file mode 100644 index 0000000..993bc37 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherJingasa.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherJingasa : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 4; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherJingasa() : base( 0x2776 ) + { + Weight = 3.0; + } + + public LeatherJingasa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherLegs.cs b/Scripts/Items/Armor/Leather/LeatherLegs.cs new file mode 100644 index 0000000..b5bcbdc --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherLegs.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13cb, 0x13d2 )] + public class LeatherLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherLegs() : base( 0x13CB ) + { + Weight = 4.0; + } + + public LeatherLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherMempo.cs b/Scripts/Items/Armor/Leather/LeatherMempo.cs new file mode 100644 index 0000000..503a5d8 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherMempo.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherMempo : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 30; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherMempo() : base( 0x277A ) + { + Weight = 2.0; + } + + public LeatherMempo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherNinjaHood.cs b/Scripts/Items/Armor/Leather/LeatherNinjaHood.cs new file mode 100644 index 0000000..584d8f0 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherNinjaHood.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherNinjaHood : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherNinjaHood() : base( 0x278E ) + { + Weight = 2.0; + } + + public LeatherNinjaHood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherNinjaJacket.cs b/Scripts/Items/Armor/Leather/LeatherNinjaJacket.cs new file mode 100644 index 0000000..c156fed --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherNinjaJacket.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherNinjaJacket : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherNinjaJacket() : base( 0x2793 ) + { + Weight = 5.0; + } + + public LeatherNinjaJacket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherNinjaMitts.cs b/Scripts/Items/Armor/Leather/LeatherNinjaMitts.cs new file mode 100644 index 0000000..400b3d2 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherNinjaMitts.cs @@ -0,0 +1,66 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherNinjaMitts : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 25; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherNinjaMitts() : base( 0x2792 ) + { + Weight = 2.0; + } + + public LeatherNinjaMitts( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + if ( reader.ReadBool() ) + { + reader.ReadInt(); + reader.ReadInt(); + } + + Weight = 2.0; + ItemID = 0x2792; + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherNinjaPants.cs b/Scripts/Items/Armor/Leather/LeatherNinjaPants.cs new file mode 100644 index 0000000..7dc8e18 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherNinjaPants.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherNinjaPants : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 10; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherNinjaPants() : base( 0x2791 ) + { + Weight = 3.0; + } + + public LeatherNinjaPants( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherShorts.cs b/Scripts/Items/Armor/Leather/LeatherShorts.cs new file mode 100644 index 0000000..9268ae0 --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherShorts.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c00, 0x1c01 )] + public class LeatherShorts : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public LeatherShorts() : base( 0x1C00 ) + { + Weight = 3.0; + } + + public LeatherShorts( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherSkirt.cs b/Scripts/Items/Armor/Leather/LeatherSkirt.cs new file mode 100644 index 0000000..5e6e40b --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherSkirt.cs @@ -0,0 +1,55 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c08, 0x1c09 )] + public class LeatherSkirt : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public LeatherSkirt() : base( 0x1C08 ) + { + Weight = 1.0; + } + + public LeatherSkirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + if ( Weight == 3.0 ) + Weight = 1.0; + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Leather/LeatherSuneate.cs b/Scripts/Items/Armor/Leather/LeatherSuneate.cs new file mode 100644 index 0000000..cec625f --- /dev/null +++ b/Scripts/Items/Armor/Leather/LeatherSuneate.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeatherSuneate : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + [Constructable] + public LeatherSuneate() : base( 0x2786 ) + { + Weight = 4.0; + } + + public LeatherSuneate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/DecorativePlateKabuto.cs b/Scripts/Items/Armor/Plate/DecorativePlateKabuto.cs new file mode 100644 index 0000000..80fc912 --- /dev/null +++ b/Scripts/Items/Armor/Plate/DecorativePlateKabuto.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class DecorativePlateKabuto : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 70; } } + public override int OldStrReq{ get{ return 70; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public DecorativePlateKabuto() : base( 0x2778 ) + { + Weight = 6.0; + } + + public DecorativePlateKabuto( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/FemalePlateChest.cs b/Scripts/Items/Armor/Plate/FemalePlateChest.cs new file mode 100644 index 0000000..efa1f6b --- /dev/null +++ b/Scripts/Items/Armor/Plate/FemalePlateChest.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c04, 0x1c05 )] + public class FemalePlateChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 95; } } + public override int OldStrReq{ get{ return 45; } } + + public override int OldDexBonus{ get{ return -5; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public FemalePlateChest() : base( 0x1C04 ) + { + Weight = 4.0; + } + + public FemalePlateChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 4.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/FemaleWoodlandChest.cs b/Scripts/Items/Armor/Plate/FemaleWoodlandChest.cs new file mode 100644 index 0000000..e505dbc --- /dev/null +++ b/Scripts/Items/Armor/Plate/FemaleWoodlandChest.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + //Is this a filler-type item? the clilocs don't match up and at a glacnce I can't find direct reference of it + [FlipableAttribute( 0x2B6D, 0x3164 )] + public class FemaleElvenPlateChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 95; } } + public override int OldStrReq{ get{ return 95; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + public override int ArmorBase{ get{ return 30; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public FemaleElvenPlateChest() : base( 0x2B6D ) + { + Weight = 8.0; + } + + public FemaleElvenPlateChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/HeavyPlateJingasa.cs b/Scripts/Items/Armor/Plate/HeavyPlateJingasa.cs new file mode 100644 index 0000000..f9e26ae --- /dev/null +++ b/Scripts/Items/Armor/Plate/HeavyPlateJingasa.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class HeavyPlateJingasa : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 7; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 70; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 55; } } + + public override int ArmorBase{ get{ return 4; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public HeavyPlateJingasa() : base( 0x2777 ) + { + Weight = 5.0; + } + + public HeavyPlateJingasa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/LightPlateJingasa.cs b/Scripts/Items/Armor/Plate/LightPlateJingasa.cs new file mode 100644 index 0000000..02d4324 --- /dev/null +++ b/Scripts/Items/Armor/Plate/LightPlateJingasa.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LightPlateJingasa : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 7; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 55; } } + + public override int ArmorBase{ get{ return 4; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public LightPlateJingasa() : base( 0x2781 ) + { + Weight = 5.0; + } + + public LightPlateJingasa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateArms.cs b/Scripts/Items/Armor/Plate/PlateArms.cs new file mode 100644 index 0000000..a6a5b73 --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateArms.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1410, 0x1417 )] + public class PlateArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 80; } } + public override int OldStrReq{ get{ return 40; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateArms() : base( 0x1410 ) + { + Weight = 5.0; + } + + public PlateArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateBattleKabuto.cs b/Scripts/Items/Armor/Plate/PlateBattleKabuto.cs new file mode 100644 index 0000000..cd2e34e --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateBattleKabuto.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateBattleKabuto : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 60; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 70; } } + public override int OldStrReq{ get{ return 70; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateBattleKabuto() : base( 0x2785 ) + { + Weight = 6.0; + } + + public PlateBattleKabuto( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateChest.cs b/Scripts/Items/Armor/Plate/PlateChest.cs new file mode 100644 index 0000000..f8b601d --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateChest.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1415, 0x1416 )] + public class PlateChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 95; } } + public override int OldStrReq{ get{ return 60; } } + + public override int OldDexBonus{ get{ return -8; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateChest() : base( 0x1415 ) + { + Weight = 10.0; + } + + public PlateChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 10.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateDo.cs b/Scripts/Items/Armor/Plate/PlateDo.cs new file mode 100644 index 0000000..78fcfbc --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateDo.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateDo : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 60; } } + public override int InitMaxHits{ get{ return 70; } } + + public override int AosStrReq{ get{ return 85; } } + public override int OldStrReq{ get{ return 85; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateDo() : base( 0x277D ) + { + Weight = 10.0; + } + + public PlateDo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateGloves.cs b/Scripts/Items/Armor/Plate/PlateGloves.cs new file mode 100644 index 0000000..ebc978f --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateGloves.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1414, 0x1418 )] + public class PlateGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 70; } } + public override int OldStrReq{ get{ return 30; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateGloves() : base( 0x1414 ) + { + Weight = 2.0; + } + + public PlateGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateGorget.cs b/Scripts/Items/Armor/Plate/PlateGorget.cs new file mode 100644 index 0000000..ed5ea02 --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateGorget.cs @@ -0,0 +1,48 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateGorget : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 45; } } + public override int OldStrReq{ get{ return 30; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateGorget() : base( 0x1413 ) + { + Weight = 2.0; + } + + public PlateGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateHaidate.cs b/Scripts/Items/Armor/Plate/PlateHaidate.cs new file mode 100644 index 0000000..fcea17e --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateHaidate.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateHaidate : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 80; } } + public override int OldStrReq{ get{ return 80; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateHaidate() : base( 0x278D ) + { + Weight = 7.0; + } + + public PlateHaidate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateHatsuburi.cs b/Scripts/Items/Armor/Plate/PlateHatsuburi.cs new file mode 100644 index 0000000..6a977db --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateHatsuburi.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateHatsuburi : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 65; } } + public override int OldStrReq{ get{ return 65; } } + + public override int ArmorBase{ get{ return 4; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateHatsuburi() : base( 0x2775 ) + { + Weight = 5.0; + } + + public PlateHatsuburi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateHiroSode.cs b/Scripts/Items/Armor/Plate/PlateHiroSode.cs new file mode 100644 index 0000000..090e7f3 --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateHiroSode.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateHiroSode : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 75; } } + + public override int AosStrReq{ get{ return 75; } } + public override int OldStrReq{ get{ return 75; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateHiroSode() : base( 0x2780 ) + { + Weight = 3.0; + } + + public PlateHiroSode( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateLegs.cs b/Scripts/Items/Armor/Plate/PlateLegs.cs new file mode 100644 index 0000000..7a8a770 --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateLegs.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1411, 0x141a )] + public class PlateLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 90; } } + + public override int OldStrReq{ get{ return 60; } } + public override int OldDexBonus{ get{ return -6; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateLegs() : base( 0x1411 ) + { + Weight = 7.0; + } + + public PlateLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateMempo.cs b/Scripts/Items/Armor/Plate/PlateMempo.cs new file mode 100644 index 0000000..e89334b --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateMempo.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateMempo : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 60; } } + public override int InitMaxHits{ get{ return 70; } } + + public override int AosStrReq{ get{ return 50; } } + public override int OldStrReq{ get{ return 50; } } + + public override int ArmorBase{ get{ return 4; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateMempo() : base( 0x2779 ) + { + Weight = 3.0; + } + + public PlateMempo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/PlateSuneate.cs b/Scripts/Items/Armor/Plate/PlateSuneate.cs new file mode 100644 index 0000000..a96c76d --- /dev/null +++ b/Scripts/Items/Armor/Plate/PlateSuneate.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class PlateSuneate : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 80; } } + public override int OldStrReq{ get{ return 80; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public PlateSuneate() : base( 0x2788 ) + { + Weight = 7.0; + } + + public PlateSuneate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/SmallPlateJingasa.cs b/Scripts/Items/Armor/Plate/SmallPlateJingasa.cs new file mode 100644 index 0000000..12101c1 --- /dev/null +++ b/Scripts/Items/Armor/Plate/SmallPlateJingasa.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SmallPlateJingasa : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 7; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 55; } } + + public override int ArmorBase{ get{ return 4; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public SmallPlateJingasa() : base( 0x2784 ) + { + Weight = 5.0; + } + + public SmallPlateJingasa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/StandardPlateKabuto.cs b/Scripts/Items/Armor/Plate/StandardPlateKabuto.cs new file mode 100644 index 0000000..ed46f62 --- /dev/null +++ b/Scripts/Items/Armor/Plate/StandardPlateKabuto.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StandardPlateKabuto : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 2; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 2; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 60; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 70; } } + public override int OldStrReq{ get{ return 70; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public StandardPlateKabuto() : base( 0x2789 ) + { + Weight = 6.0; + } + + public StandardPlateKabuto( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/WoodlandArms.cs b/Scripts/Items/Armor/Plate/WoodlandArms.cs new file mode 100644 index 0000000..db8e3da --- /dev/null +++ b/Scripts/Items/Armor/Plate/WoodlandArms.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B6C, 0x3163 )] + public class WoodlandArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 80; } } + public override int OldStrReq{ get{ return 80; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public WoodlandArms() : base( 0x2B6C ) + { + Weight = 5.0; + } + + public WoodlandArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/WoodlandChest.cs b/Scripts/Items/Armor/Plate/WoodlandChest.cs new file mode 100644 index 0000000..57fb8e3 --- /dev/null +++ b/Scripts/Items/Armor/Plate/WoodlandChest.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B67, 0x315E )] + public class WoodlandChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 95; } } + public override int OldStrReq{ get{ return 95; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public WoodlandChest() : base( 0x2B67 ) + { + Weight = 8.0; + } + + public WoodlandChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/WoodlandGloves.cs b/Scripts/Items/Armor/Plate/WoodlandGloves.cs new file mode 100644 index 0000000..bd36922 --- /dev/null +++ b/Scripts/Items/Armor/Plate/WoodlandGloves.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B6A, 0x3161 )] + public class WoodlandGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 70; } } + public override int OldStrReq{ get{ return 70; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public WoodlandGloves() : base( 0x2B6A ) + { + Weight = 2.0; + } + + public WoodlandGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/WoodlandGorget.cs b/Scripts/Items/Armor/Plate/WoodlandGorget.cs new file mode 100644 index 0000000..cb1f82d --- /dev/null +++ b/Scripts/Items/Armor/Plate/WoodlandGorget.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B69, 0x3160 )] + public class WoodlandGorget : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 45; } } + public override int OldStrReq{ get{ return 45; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public WoodlandGorget() : base( 0x2B69 ) + { + } + + public WoodlandGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + if( version == 0 ) + Weight = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Plate/WoodlandLegs.cs b/Scripts/Items/Armor/Plate/WoodlandLegs.cs new file mode 100644 index 0000000..06d5bbe --- /dev/null +++ b/Scripts/Items/Armor/Plate/WoodlandLegs.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B6B, 0x3162 )] + public class WoodlandLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 2; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 90; } } + public override int OldStrReq{ get{ return 90; } } + + public override int ArmorBase{ get{ return 40; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public WoodlandLegs() : base( 0x2B6B ) + { + Weight = 8.0; + } + + public WoodlandLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ranger/RangerArms.cs b/Scripts/Items/Armor/Ranger/RangerArms.cs new file mode 100644 index 0000000..c32c830 --- /dev/null +++ b/Scripts/Items/Armor/Ranger/RangerArms.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13dc, 0x13d4 )] + public class RangerArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041493; } } // studded sleeves, ranger armor + + [Constructable] + public RangerArms() : base( 0x13DC ) + { + Weight = 4.0; + Hue = 0x59C; + } + + public RangerArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 4.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ranger/RangerChest.cs b/Scripts/Items/Armor/Ranger/RangerChest.cs new file mode 100644 index 0000000..1f2671f --- /dev/null +++ b/Scripts/Items/Armor/Ranger/RangerChest.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13db, 0x13e2 )] + public class RangerChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 35; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041497; } } // studded tunic, ranger armor + + [Constructable] + public RangerChest() : base( 0x13DB ) + { + Weight = 8.0; + Hue = 0x59C; + } + + public RangerChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 8.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ranger/RangerGloves.cs b/Scripts/Items/Armor/Ranger/RangerGloves.cs new file mode 100644 index 0000000..ee77301 --- /dev/null +++ b/Scripts/Items/Armor/Ranger/RangerGloves.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13d5, 0x13dd )] + public class RangerGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041494; } } // studded gloves, ranger armor + + [Constructable] + public RangerGloves() : base( 0x13D5 ) + { + Weight = 1.0; + Hue = 0x59C; + } + + public RangerGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ranger/RangerGorget.cs b/Scripts/Items/Armor/Ranger/RangerGorget.cs new file mode 100644 index 0000000..e50a747 --- /dev/null +++ b/Scripts/Items/Armor/Ranger/RangerGorget.cs @@ -0,0 +1,50 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class RangerGorget : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041495; } } // studded gorget, ranger armor + + [Constructable] + public RangerGorget() : base( 0x13D6 ) + { + Weight = 1.0; + Hue = 0x59C; + } + + public RangerGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ranger/RangerLegs.cs b/Scripts/Items/Armor/Ranger/RangerLegs.cs new file mode 100644 index 0000000..0726adc --- /dev/null +++ b/Scripts/Items/Armor/Ranger/RangerLegs.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13da, 0x13e1 )] + public class RangerLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1041496; } } // studded leggings, ranger armor + + [Constructable] + public RangerLegs() : base( 0x13DA ) + { + Weight = 3.0; + Hue = 0x59C; + } + + public RangerLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ring/RingmailArms.cs b/Scripts/Items/Armor/Ring/RingmailArms.cs new file mode 100644 index 0000000..7e32704 --- /dev/null +++ b/Scripts/Items/Armor/Ring/RingmailArms.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13ee, 0x13ef )] + public class RingmailArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 1; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 22; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Ringmail; } } + + [Constructable] + public RingmailArms() : base( 0x13EE ) + { + Weight = 15.0; + } + + public RingmailArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 15.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ring/RingmailChest.cs b/Scripts/Items/Armor/Ring/RingmailChest.cs new file mode 100644 index 0000000..7cf523e --- /dev/null +++ b/Scripts/Items/Armor/Ring/RingmailChest.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13ec, 0x13ed )] + public class RingmailChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 1; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -2; } } + + public override int ArmorBase{ get{ return 22; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Ringmail; } } + + [Constructable] + public RingmailChest() : base( 0x13EC ) + { + Weight = 15.0; + } + + public RingmailChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 15.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ring/RingmailGloves.cs b/Scripts/Items/Armor/Ring/RingmailGloves.cs new file mode 100644 index 0000000..db248dc --- /dev/null +++ b/Scripts/Items/Armor/Ring/RingmailGloves.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13eb, 0x13f2 )] + public class RingmailGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 1; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 22; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Ringmail; } } + + [Constructable] + public RingmailGloves() : base( 0x13EB ) + { + Weight = 2.0; + } + + public RingmailGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Ring/RingmailLegs.cs b/Scripts/Items/Armor/Ring/RingmailLegs.cs new file mode 100644 index 0000000..9e581c9 --- /dev/null +++ b/Scripts/Items/Armor/Ring/RingmailLegs.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13f0, 0x13f1 )] + public class RingmailLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 1; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 22; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Ringmail; } } + + [Constructable] + public RingmailLegs() : base( 0x13F0 ) + { + Weight = 15.0; + } + + public RingmailLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/FemaleStuddedChest.cs b/Scripts/Items/Armor/Studded/FemaleStuddedChest.cs new file mode 100644 index 0000000..1bb390d --- /dev/null +++ b/Scripts/Items/Armor/Studded/FemaleStuddedChest.cs @@ -0,0 +1,55 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c02, 0x1c03 )] + public class FemaleStuddedChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 35; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public FemaleStuddedChest() : base( 0x1C02 ) + { + Weight = 6.0; + } + + public FemaleStuddedChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 6.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/HideChest.cs b/Scripts/Items/Armor/Studded/HideChest.cs new file mode 100644 index 0000000..4589773 --- /dev/null +++ b/Scripts/Items/Armor/Studded/HideChest.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B74, 0x316B )] + public class HideChest : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public HideChest() : base( 0x2B74 ) + { + Weight = 6.0; + } + + public HideChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/HideFemaleChest.cs b/Scripts/Items/Armor/Studded/HideFemaleChest.cs new file mode 100644 index 0000000..db84672 --- /dev/null +++ b/Scripts/Items/Armor/Studded/HideFemaleChest.cs @@ -0,0 +1,56 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B79, 0x3170 )] + public class HideFemaleChest : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 35; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public HideFemaleChest() : base( 0x2B79 ) + { + Weight = 6.0; + } + + public HideFemaleChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/HideGloves.cs b/Scripts/Items/Armor/Studded/HideGloves.cs new file mode 100644 index 0000000..436ec24 --- /dev/null +++ b/Scripts/Items/Armor/Studded/HideGloves.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B75, 0x316C )] + public class HideGloves : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 15; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public HideGloves() : base( 0x2B75 ) + { + Weight = 2.0; + } + + public HideGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/HideGorget.cs b/Scripts/Items/Armor/Studded/HideGorget.cs new file mode 100644 index 0000000..5da8e59 --- /dev/null +++ b/Scripts/Items/Armor/Studded/HideGorget.cs @@ -0,0 +1,55 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B76, 0x316D )] + public class HideGorget : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 15; } } + public override int OldStrReq{ get{ return 15; } } + + public override int ArmorBase{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public HideGorget() : base( 0x2B76 ) + { + Weight = 3.0; + } + + public HideGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/HidePants.cs b/Scripts/Items/Armor/Studded/HidePants.cs new file mode 100644 index 0000000..29b02f3 --- /dev/null +++ b/Scripts/Items/Armor/Studded/HidePants.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B78, 0x316F )] + public class HidePants : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public HidePants() : base( 0x2B78 ) + { + Weight = 5.0; + } + + public HidePants( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/HidePauldrons.cs b/Scripts/Items/Armor/Studded/HidePauldrons.cs new file mode 100644 index 0000000..fa2f122 --- /dev/null +++ b/Scripts/Items/Armor/Studded/HidePauldrons.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2B77, 0x316E )] + public class HidePauldrons : BaseArmor + { + public override Race RequiredRace { get { return Race.Elf; } } + + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 4; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 2; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public HidePauldrons() : base( 0x2B77 ) + { + Weight = 4.0; + } + + public HidePauldrons( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedArms.cs b/Scripts/Items/Armor/Studded/StuddedArms.cs new file mode 100644 index 0000000..b53d69c --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedArms.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13dc, 0x13d4 )] + public class StuddedArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public StuddedArms() : base( 0x13DC ) + { + Weight = 4.0; + } + + public StuddedArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 4.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedBustierArms.cs b/Scripts/Items/Armor/Studded/StuddedBustierArms.cs new file mode 100644 index 0000000..71b7786 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedBustierArms.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1c0c, 0x1c0d )] + public class StuddedBustierArms : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 35; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + public override bool AllowMaleWearer{ get{ return false; } } + + [Constructable] + public StuddedBustierArms() : base( 0x1C0C ) + { + Weight = 1.0; + } + + public StuddedBustierArms( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedChest.cs b/Scripts/Items/Armor/Studded/StuddedChest.cs new file mode 100644 index 0000000..16941d7 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedChest.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13db, 0x13e2 )] + public class StuddedChest : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 35; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public StuddedChest() : base( 0x13DB ) + { + Weight = 8.0; + } + + public StuddedChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 8.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedDo.cs b/Scripts/Items/Armor/Studded/StuddedDo.cs new file mode 100644 index 0000000..cce685f --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedDo.cs @@ -0,0 +1,47 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StuddedDo : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 55; } } + public override int OldStrReq{ get{ return 55; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public StuddedDo() : base( 0x27C7 ) + { + Weight = 8.0; + } + + public StuddedDo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedGloves.cs b/Scripts/Items/Armor/Studded/StuddedGloves.cs new file mode 100644 index 0000000..5346725 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedGloves.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13d5, 0x13dd )] + public class StuddedGloves : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public StuddedGloves() : base( 0x13D5 ) + { + Weight = 1.0; + } + + public StuddedGloves( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedGorget.cs b/Scripts/Items/Armor/Studded/StuddedGorget.cs new file mode 100644 index 0000000..7f82aec --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedGorget.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StuddedGorget : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public StuddedGorget() : base( 0x13D6 ) + { + Weight = 1.0; + } + + public StuddedGorget( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedHaidate.cs b/Scripts/Items/Armor/Studded/StuddedHaidate.cs new file mode 100644 index 0000000..519e5b0 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedHaidate.cs @@ -0,0 +1,47 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StuddedHaidate : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 30; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public StuddedHaidate() : base( 0x278B ) + { + Weight = 5.0; + } + + public StuddedHaidate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedHiroSode.cs b/Scripts/Items/Armor/Studded/StuddedHiroSode.cs new file mode 100644 index 0000000..aab771b --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedHiroSode.cs @@ -0,0 +1,47 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StuddedHiroSode : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 55; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 30; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public StuddedHiroSode() : base( 0x277F ) + { + Weight = 1.0; + } + + public StuddedHiroSode( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedLegs.cs b/Scripts/Items/Armor/Studded/StuddedLegs.cs new file mode 100644 index 0000000..8f377f2 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedLegs.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13da, 0x13e1 )] + public class StuddedLegs : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.Half; } } + + [Constructable] + public StuddedLegs() : base( 0x13DA ) + { + Weight = 5.0; + } + + public StuddedLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedMempo.cs b/Scripts/Items/Armor/Studded/StuddedMempo.cs new file mode 100644 index 0000000..fd7bf46 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedMempo.cs @@ -0,0 +1,47 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StuddedMempo : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 30; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public StuddedMempo() : base( 0x279D ) + { + Weight = 2.0; + } + + public StuddedMempo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Armor/Studded/StuddedSuneate.cs b/Scripts/Items/Armor/Studded/StuddedSuneate.cs new file mode 100644 index 0000000..275d1a3 --- /dev/null +++ b/Scripts/Items/Armor/Studded/StuddedSuneate.cs @@ -0,0 +1,47 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class StuddedSuneate : BaseArmor + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 30; } } + public override int OldStrReq{ get{ return 30; } } + + public override int ArmorBase{ get{ return 3; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public StuddedSuneate() : base( 0x27D2 ) + { + Weight = 5.0; + } + + public StuddedSuneate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/BonePile.cs b/Scripts/Items/Body Parts/BonePile.cs new file mode 100644 index 0000000..6be3a5a --- /dev/null +++ b/Scripts/Items/Body Parts/BonePile.cs @@ -0,0 +1,45 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x1B09, 0x1B10 )] + public class BonePile : Item, IScissorable + { + [Constructable] + public BonePile( ) : base( 0x1B09 + Utility.Random( 8 ) ) + { + Stackable = false; + Weight = 10.0; + } + + public BonePile( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) + return false; + + base.ScissorHelper( from, new Bone(), Utility.RandomMinMax( 10, 15 ) ); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/Head.cs b/Scripts/Items/Body Parts/Head.cs new file mode 100644 index 0000000..3c2420c --- /dev/null +++ b/Scripts/Items/Body Parts/Head.cs @@ -0,0 +1,128 @@ +using System; +using Server; + +namespace Server.Items +{ + public enum HeadType + { + Regular, + Duel, + Tournament + } + + public class Head : Item + { + private string m_PlayerName; + private HeadType m_HeadType; + + [CommandProperty( AccessLevel.GameMaster )] + public string PlayerName + { + get { return m_PlayerName; } + set { m_PlayerName = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public HeadType HeadType + { + get { return m_HeadType; } + set { m_HeadType = value; } + } + + public override string DefaultName + { + get + { + if ( m_PlayerName == null ) + return base.DefaultName; + + switch ( m_HeadType ) + { + default: + return String.Format( "the head of {0}", m_PlayerName ); + + case HeadType.Duel: + return String.Format( "the head of {0}, taken in a duel", m_PlayerName ); + + case HeadType.Tournament: + return String.Format( "the head of {0}, taken in a tournament", m_PlayerName ); + } + } + } + + [Constructable] + public Head() + : this( null ) + { + } + + [Constructable] + public Head( string playerName ) + : this( HeadType.Regular, playerName ) + { + } + + [Constructable] + public Head( HeadType headType, string playerName ) + : base( 0x1DA0 ) + { + m_HeadType = headType; + m_PlayerName = playerName; + } + + public Head( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (string) m_PlayerName ); + writer.WriteEncodedInt( (int) m_HeadType ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + m_PlayerName = reader.ReadString(); + m_HeadType = (HeadType) reader.ReadEncodedInt(); + break; + + case 0: + string format = this.Name; + + if ( format != null ) + { + if ( format.StartsWith( "the head of " ) ) + format = format.Substring( "the head of ".Length ); + + if ( format.EndsWith( ", taken in a duel" ) ) + { + format = format.Substring( 0, format.Length - ", taken in a duel".Length ); + m_HeadType = HeadType.Duel; + } + else if ( format.EndsWith( ", taken in a tournament" ) ) + { + format = format.Substring( 0, format.Length - ", taken in a tournament".Length ); + m_HeadType = HeadType.Tournament; + } + } + + m_PlayerName = format; + this.Name = null; + + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/LeftArm.cs b/Scripts/Items/Body Parts/LeftArm.cs new file mode 100644 index 0000000..bd6c204 --- /dev/null +++ b/Scripts/Items/Body Parts/LeftArm.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LeftArm : Item + { + [Constructable] + public LeftArm() : base( 0x1DA1 ) + { + } + + public LeftArm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/LeftLeg.cs b/Scripts/Items/Body Parts/LeftLeg.cs new file mode 100644 index 0000000..d905b12 --- /dev/null +++ b/Scripts/Items/Body Parts/LeftLeg.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LeftLeg : Item + { + [Constructable] + public LeftLeg() : base( 0x1DA3 ) + { + } + + public LeftLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/RibCage.cs b/Scripts/Items/Body Parts/RibCage.cs new file mode 100644 index 0000000..ca58b93 --- /dev/null +++ b/Scripts/Items/Body Parts/RibCage.cs @@ -0,0 +1,45 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x1B17, 0x1B18 )] + public class RibCage : Item, IScissorable + { + [Constructable] + public RibCage() : base( 0x1B17 + Utility.Random( 2 ) ) + { + Stackable = false; + Weight = 5.0; + } + + public RibCage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) + return false; + + base.ScissorHelper( from, new Bone(), Utility.RandomMinMax( 3, 5 ) ); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/RightArm.cs b/Scripts/Items/Body Parts/RightArm.cs new file mode 100644 index 0000000..5c2b020 --- /dev/null +++ b/Scripts/Items/Body Parts/RightArm.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RightArm : Item + { + [Constructable] + public RightArm() : base( 0x1DA2 ) + { + } + + public RightArm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/RightLeg.cs b/Scripts/Items/Body Parts/RightLeg.cs new file mode 100644 index 0000000..4eb9b83 --- /dev/null +++ b/Scripts/Items/Body Parts/RightLeg.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RightLeg : Item + { + [Constructable] + public RightLeg() : base( 0x1DA4 ) + { + } + + public RightLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Body Parts/Torso.cs b/Scripts/Items/Body Parts/Torso.cs new file mode 100644 index 0000000..153001a --- /dev/null +++ b/Scripts/Items/Body Parts/Torso.cs @@ -0,0 +1,32 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Torso : Item + { + [Constructable] + public Torso() : base( 0x1D9F ) + { + Weight = 2.0; + } + + public Torso( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/BaseBook.cs b/Scripts/Items/Books/BaseBook.cs new file mode 100644 index 0000000..01c4ba6 --- /dev/null +++ b/Scripts/Items/Books/BaseBook.cs @@ -0,0 +1,536 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Server; +using Server.ContextMenus; +using Server.Network; +using Server.Gumps; +using Server.Multis; + +namespace Server.Items +{ + public class BookPageInfo + { + private string[] m_Lines; + + public string[] Lines + { + get + { + return m_Lines; + } + set + { + m_Lines = value; + } + } + + public BookPageInfo() + { + m_Lines = new string[0]; + } + + public BookPageInfo( params string[] lines ) + { + m_Lines = lines; + } + + public BookPageInfo( GenericReader reader ) + { + int length = reader.ReadInt(); + + m_Lines = new string[length]; + + for ( int i = 0; i < m_Lines.Length; ++i ) + m_Lines[i] = Utility.Intern( reader.ReadString() ); + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( m_Lines.Length ); + + for ( int i = 0; i < m_Lines.Length; ++i ) + writer.Write( m_Lines[i] ); + } + } + + public class BaseBook : Item, ISecurable + { + private string m_Title; + private string m_Author; + private BookPageInfo[] m_Pages; + private bool m_Writable; + private SecureLevel m_SecureLevel; + + [CommandProperty( AccessLevel.GameMaster )] + public string Title + { + get { return m_Title; } + set { m_Title = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Author + { + get { return m_Author; } + set { m_Author = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Writable + { + get { return m_Writable; } + set { m_Writable = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int PagesCount + { + get { return m_Pages.Length; } + } + + public BookPageInfo[] Pages + { + get { return m_Pages; } + } + + [Constructable] + public BaseBook( int itemID ) : this( itemID, 20, true ) + { + } + + [Constructable] + public BaseBook( int itemID, int pageCount, bool writable ) : this( itemID, null, null, pageCount, writable ) + { + } + + [Constructable] + public BaseBook( int itemID, string title, string author, int pageCount, bool writable ) : base( itemID ) + { + m_Title = title; + m_Author = author; + m_Writable = writable; + + BookContent content = this.DefaultContent; + + if ( content == null ) + { + m_Pages = new BookPageInfo[pageCount]; + + for ( int i = 0; i < m_Pages.Length; ++i ) + m_Pages[i] = new BookPageInfo(); + } + else + { + m_Pages = content.Copy(); + } + } + + // Intended for defined books only + public BaseBook( int itemID, bool writable ) : base( itemID ) + { + m_Writable = writable; + + BookContent content = this.DefaultContent; + + if ( content == null ) + { + m_Pages = new BookPageInfo[0]; + } + else + { + m_Title = content.Title; + m_Author = content.Author; + m_Pages = content.Copy(); + } + } + + public virtual BookContent DefaultContent{ get{ return null; } } + + public BaseBook( Serial serial ) : base( serial ) + { + } + + [Flags] + private enum SaveFlags + { + None = 0x00, + Title = 0x01, + Author = 0x02, + Writable = 0x04, + Content = 0x08 + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + BookContent content = this.DefaultContent; + + SaveFlags flags = SaveFlags.None; + + if ( m_Title != ( content == null ? null : content.Title ) ) + flags |= SaveFlags.Title; + + if ( m_Author != ( content == null ? null : content.Author ) ) + flags |= SaveFlags.Author; + + if ( m_Writable ) + flags |= SaveFlags.Writable; + + if ( content == null || !content.IsMatch( m_Pages ) ) + flags |= SaveFlags.Content; + + + + writer.Write( (int) 4 ); // version + + writer.Write( (int)m_SecureLevel ); + + writer.Write( (byte) flags ); + + if ( (flags & SaveFlags.Title) != 0 ) + writer.Write( m_Title ); + + if ( (flags & SaveFlags.Author) != 0 ) + writer.Write( m_Author ); + + if ( (flags & SaveFlags.Content) != 0 ) + { + writer.WriteEncodedInt( m_Pages.Length ); + + for ( int i = 0; i < m_Pages.Length; ++i ) + m_Pages[i].Serialize( writer ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 4: + { + m_SecureLevel = (SecureLevel)reader.ReadInt(); + goto case 3; + } + case 3: + case 2: + { + BookContent content = this.DefaultContent; + + SaveFlags flags = (SaveFlags) reader.ReadByte(); + + if ( (flags & SaveFlags.Title) != 0 ) + m_Title = Utility.Intern( reader.ReadString() ); + else if ( content != null ) + m_Title = content.Title; + + if ( (flags & SaveFlags.Author) != 0 ) + m_Author = reader.ReadString(); + else if ( content != null ) + m_Author = content.Author; + + m_Writable = ( flags & SaveFlags.Writable ) != 0; + + if ( (flags & SaveFlags.Content) != 0 ) + { + m_Pages = new BookPageInfo[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_Pages.Length; ++i ) + m_Pages[i] = new BookPageInfo( reader ); + } + else + { + if ( content != null ) + m_Pages = content.Copy(); + else + m_Pages = new BookPageInfo[0]; + } + + break; + } + case 1: + case 0: + { + m_Title = reader.ReadString(); + m_Author = reader.ReadString(); + m_Writable = reader.ReadBool(); + + if ( version == 0 || reader.ReadBool() ) + { + m_Pages = new BookPageInfo[reader.ReadInt()]; + + for ( int i = 0; i < m_Pages.Length; ++i ) + m_Pages[i] = new BookPageInfo( reader ); + } + else + { + BookContent content = this.DefaultContent; + + if ( content != null ) + m_Pages = content.Copy(); + else + m_Pages = new BookPageInfo[0]; + } + + break; + } + } + + if ( version < 3 && ( Weight == 1 || Weight == 2 ) ) + Weight = -1; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_Title != null && m_Title.Length > 0 ) + list.Add( m_Title ); + else + base.AddNameProperty( list ); + } + + /*public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Title != null && m_Title.Length > 0 ) + list.Add( 1060658, "Title\t{0}", m_Title ); // ~1_val~: ~2_val~ + + if ( m_Author != null && m_Author.Length > 0 ) + list.Add( 1060659, "Author\t{0}", m_Author ); // ~1_val~: ~2_val~ + + if ( m_Pages != null && m_Pages.Length > 0 ) + list.Add( 1060660, "Pages\t{0}", m_Pages.Length ); // ~1_val~: ~2_val~ + }*/ + + public override void OnSingleClick ( Mobile from ) + { + LabelTo( from, "{0} by {1}", m_Title, m_Author ); + LabelTo( from, "[{0} pages]", m_Pages.Length ); + } + + public override void OnDoubleClick ( Mobile from ) + { + if ( m_Title == null && m_Author == null && m_Writable == true ) + { + Title = "a book"; + Author = from.Name; + } + + from.Send( new BookHeader( from, this ) ); + from.Send( new BookPageDetails( this ) ); + } + + public string ContentAsString + { + get + { + StringBuilder sb = new StringBuilder(); + + foreach (BookPageInfo bpi in this.m_Pages) + { + foreach (string line in bpi.Lines) + { + sb.AppendLine(line); + } + } + + return sb.ToString(); + } + } + + public string[] ContentAsStringArray + { + get + { + List lines = new List(); + + foreach (BookPageInfo bpi in this.m_Pages) + { + lines.AddRange(bpi.Lines); + } + + return lines.ToArray(); + } + } + + public static void Initialize() + { + PacketHandlers.Register( 0xD4, 0, true, new OnPacketReceive( HeaderChange ) ); + PacketHandlers.Register( 0x66, 0, true, new OnPacketReceive( ContentChange ) ); + PacketHandlers.Register( 0x93, 99, true, new OnPacketReceive( OldHeaderChange ) ); + } + + public static void OldHeaderChange( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + BaseBook book = World.FindItem( pvSrc.ReadInt32() ) as BaseBook; + + if ( book == null || !book.Writable || !from.InRange( book.GetWorldLocation(), 1 ) || !book.IsAccessibleTo( from ) ) + return; + + pvSrc.Seek( 4, SeekOrigin.Current ); // Skip flags and page count + + string title = pvSrc.ReadStringSafe( 60 ); + string author = pvSrc.ReadStringSafe( 30 ); + + book.Title = Utility.FixHtml( title ); + book.Author = Utility.FixHtml( author ); + } + + public static void HeaderChange( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + BaseBook book = World.FindItem( pvSrc.ReadInt32() ) as BaseBook; + + if ( book == null || !book.Writable || !from.InRange( book.GetWorldLocation(), 1 ) || !book.IsAccessibleTo( from ) ) + return; + + pvSrc.Seek( 4, SeekOrigin.Current ); // Skip flags and page count + + int titleLength = pvSrc.ReadUInt16(); + + if ( titleLength > 60 ) + return; + + string title = pvSrc.ReadUTF8StringSafe( titleLength ); + + int authorLength = pvSrc.ReadUInt16(); + + if ( authorLength > 30 ) + return; + + string author = pvSrc.ReadUTF8StringSafe( authorLength ); + + book.Title = Utility.FixHtml( title ); + book.Author = Utility.FixHtml( author ); + } + + public static void ContentChange( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + BaseBook book = World.FindItem( pvSrc.ReadInt32() ) as BaseBook; + + if ( book == null || !book.Writable || !from.InRange( book.GetWorldLocation(), 1 ) || !book.IsAccessibleTo( from ) ) + return; + + int pageCount = pvSrc.ReadUInt16(); + + if ( pageCount > book.PagesCount ) + return; + + for ( int i = 0; i < pageCount; ++i ) + { + int index = pvSrc.ReadUInt16(); + + if ( index >= 1 && index <= book.PagesCount ) + { + --index; + + int lineCount = pvSrc.ReadUInt16(); + + if ( lineCount <= 8 ) + { + string[] lines = new string[lineCount]; + + for ( int j = 0; j < lineCount; ++j ) + if ( (lines[j] = pvSrc.ReadUTF8StringSafe()).Length >= 80 ) + return; + + book.Pages[index].Lines = lines; + } + else + { + return; + } + } + else + { + return; + } + } + } + + #region ISecurable Members + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get + { + return m_SecureLevel; + } + set + { + m_SecureLevel = value; + } + } + + #endregion + } + + public sealed class BookPageDetails : Packet + { + public BookPageDetails( BaseBook book ) : base( 0x66 ) + { + EnsureCapacity( 256 ); + + m_Stream.Write( (int) book.Serial ); + m_Stream.Write( (ushort) book.PagesCount ); + + for ( int i = 0; i < book.PagesCount; ++i ) + { + BookPageInfo page = book.Pages[i]; + + m_Stream.Write( (ushort) (i + 1) ); + m_Stream.Write( (ushort) page.Lines.Length ); + + for ( int j = 0; j < page.Lines.Length; ++j ) + { + byte[] buffer = Utility.UTF8.GetBytes( page.Lines[j] ); + + m_Stream.Write( buffer, 0, buffer.Length ); + m_Stream.Write( (byte) 0 ); + } + } + } + } + + public sealed class BookHeader : Packet + { + public BookHeader( Mobile from, BaseBook book ) : base ( 0xD4 ) + { + string title = book.Title == null ? "" : book.Title; + string author = book.Author == null ? "" : book.Author; + + byte[] titleBuffer = Utility.UTF8.GetBytes( title ); + byte[] authorBuffer = Utility.UTF8.GetBytes( author ); + + EnsureCapacity( 15 + titleBuffer.Length + authorBuffer.Length ); + + m_Stream.Write( (int) book.Serial ); + m_Stream.Write( (bool) true ); + m_Stream.Write( (bool) book.Writable && from.InRange( book.GetWorldLocation(), 1 ) ); + m_Stream.Write( (ushort) book.PagesCount ); + + m_Stream.Write( (ushort) (titleBuffer.Length + 1) ); + m_Stream.Write( titleBuffer, 0, titleBuffer.Length ); + m_Stream.Write( (byte) 0 ); // terminate + + m_Stream.Write( (ushort) (authorBuffer.Length + 1) ); + m_Stream.Write( authorBuffer, 0, authorBuffer.Length ); + m_Stream.Write( (byte) 0 ); // terminate + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/BlueBook.cs b/Scripts/Items/Books/BlueBook.cs new file mode 100644 index 0000000..0117a51 --- /dev/null +++ b/Scripts/Items/Books/BlueBook.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BlueBook : BaseBook + { + + [Constructable] + public BlueBook() : base( 0xFF2, 40, true ) + { + } + + [Constructable] + public BlueBook( int pageCount, bool writable ) : base( 0xFF2, pageCount, writable ) + { + } + + [Constructable] + public BlueBook( string title, string author, int pageCount, bool writable ) : base( 0xFF2, title, author, pageCount, writable ) + { + } + + // Intended for defined books only + public BlueBook( bool writable ) : base( 0xFF2, writable ) + { + } + + public BlueBook( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + } +} diff --git a/Scripts/Items/Books/BrownBook.cs b/Scripts/Items/Books/BrownBook.cs new file mode 100644 index 0000000..1dfc430 --- /dev/null +++ b/Scripts/Items/Books/BrownBook.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BrownBook : BaseBook + { + [Constructable] + public BrownBook() : base( 0xFEF ) + { + } + + [Constructable] + public BrownBook( int pageCount, bool writable ) : base( 0xFEF, pageCount, writable ) + { + } + + [Constructable] + public BrownBook( string title, string author, int pageCount, bool writable ) : base( 0xFEF, title, author, pageCount, writable ) + { + } + + // Intended for defined books only + public BrownBook( bool writable ) : base( 0xFEF, writable ) + { + } + + public BrownBook( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/BlackthornWelcomeBook.cs b/Scripts/Items/Books/Defined/BlackthornWelcomeBook.cs new file mode 100644 index 0000000..153ada2 --- /dev/null +++ b/Scripts/Items/Books/Defined/BlackthornWelcomeBook.cs @@ -0,0 +1,297 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BlackthornWelcomeBook : RedBook + { + public static readonly BookContent Content = new BookContent + ( + "A Welcome", "Lord Blackthorn", + new BookPageInfo + ( + " Greetings to you,", + "new member of the", + "Trusted.", + " You now read these", + "words because you", + "have been deemed", + "worthy to join the", + "ranks of" + ), + new BookPageInfo + ( + "Britannia's defenders.", + "Some will call you a", + "betrayer of mankind, I", + "say they are", + "misguided. I call you", + "a defender for Sosaria", + "needs saving from", + "itself." + ), + new BookPageInfo + ( + " The forces of order", + "once ruled our world.", + "Like a great", + "darkness over our", + "lives we lived under", + "the oppressive watch", + "of a king who", + "dictated our actions" + ), + new BookPageInfo + ( + "and passed judgement", + "on our character. He", + "suppressed our way of", + "life by denying our", + "freedom and the", + "ability to determine", + "who we are and what", + "we stand for. Even" + ), + new BookPageInfo + ( + "today in the absense", + "of this man we still", + "see the symbol of his", + "tyranny, we watch his", + "personal guards patrol", + "the cities to", + "intimidate us, and we", + "feel his laws like a" + ), + new BookPageInfo + ( + "vice on our lives.", + " You are here", + "because you choose to", + "be free. Like many", + "Britannians you have", + "felt the opression of", + "one man's ideas", + "weighing down upon" + ), + new BookPageInfo + ( + "you like chains. You", + "have felt the embrace", + "of fear, wondering if", + "you face consequence", + "for simply having", + "ideas not in harmony", + "with those forced upon", + "you. You have seen" + ), + new BookPageInfo + ( + "men fight and die for", + "the principles of a", + "zealot and wondered,", + "'Who will fight for", + "my principles should", + "they be opposed?'", + "You tire of living", + "under the shadow of" + ), + new BookPageInfo + ( + "dreams that do not", + "belong to you. And", + "most of all, you have", + "wondered what you", + "can do to live free.", + " Your journey to", + "freedom begins here.", + " I, like you, once" + ), + new BookPageInfo + ( + "desired my freedom", + "from the limits placed", + "on me. I watched in", + "disgust as this world", + "became engrossed with", + "the preaching of", + "virtue and none of the", + "practice. I held my" + ), + new BookPageInfo + ( + "convictions in check,", + "fearful of the reaction", + "of men blinded by", + "belief. I forced", + "myself to bury the", + "very idealogy that", + "made me an individual.", + "I was fortunate that" + ), + new BookPageInfo + ( + "a being of unique", + "power and", + "unimaginable", + "intelligence saw", + "through to the true", + "person I was, the", + "person I was meant to", + "be. Exodus found" + ), + new BookPageInfo + ( + "within me a man of", + "free will,", + "determination, and", + "incomprehension for", + "the plight of", + "oppression forced on so", + "many Britannians.", + " Exodus has also" + ), + new BookPageInfo + ( + "chosen you because of", + "the strength of your", + "character.", + " Many of the men", + "who were once my", + "peers look upon me", + "and see a betrayer of", + "humanity. They" + ), + new BookPageInfo + ( + "claim my newfound", + "form is unnatural and", + "wrong. Because they", + "see the unknown in", + "me, they show fear.", + "They disapprove of", + "my choices and in", + "their ignorance see" + ), + new BookPageInfo + ( + "evil. Yet I hide my", + "true self no longer", + "from these men. My", + "thoughts and my", + "personal morality have", + "been liberated in the", + "face of the oppression", + "that once consumed me." + ), + new BookPageInfo + ( + "Where they see a", + "man no longer human.", + "I see a man that has", + "not betrayed his", + "humanity but has been", + "freed from it. This", + "is the power that has", + "been granted to me by" + ), + new BookPageInfo + ( + "Exodus. I have been", + "given my freedom. I", + "have been released", + "from my fears.", + " Exodus will give", + "you the power to", + "conquer your fears as", + "well." + ), + new BookPageInfo + ( + " When your fear", + "of this world is gone,", + "then the world truly", + "belongs to you in a", + "way it never has", + "before. You, trusted", + "one, will soon be given", + "a gift. Your body," + ), + new BookPageInfo + ( + "like mine, will be", + "enlightened and raised", + "to a level no mortal", + "can know. The power", + "to control your own", + "destiny will belong to", + "you for the first time", + "in your life." + ), + new BookPageInfo + ( + " You will, at long", + "last, be cleansed of", + "fear.", + " Together, with the", + "power of Exodus", + "behind us, we shall", + "finally wage war on", + "the oppression that" + ), + new BookPageInfo + ( + "once held us back", + "from our full", + "potential. We shall", + "claim this world, and", + "reshape it in an image", + "of freedom for all of", + "us. Those who once", + "told you who you are" + ), + new BookPageInfo + ( + "and how you should", + "live will no longer be", + "able to stand in the", + "way of your free will.", + "Many say you will", + "be abandoning your", + "humanity but in truth,", + "you will be more than" + ), + new BookPageInfo + ( + "human.", + " You will be freed." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public BlackthornWelcomeBook() : base( false ) + { + Hue = 0x89B; + } + + public BlackthornWelcomeBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/BookContent.cs b/Scripts/Items/Books/Defined/BookContent.cs new file mode 100644 index 0000000..fe7529e --- /dev/null +++ b/Scripts/Items/Books/Defined/BookContent.cs @@ -0,0 +1,61 @@ +using System; + +namespace Server.Items +{ + public class BookContent + { + private string m_Title; + private string m_Author; + + private BookPageInfo[] m_Pages; + + public string Title{ get{ return m_Title; } } + public string Author{ get{ return m_Author; } } + + public BookPageInfo[] Pages{ get{ return m_Pages; } } + + public BookContent( string title, string author, params BookPageInfo[] pages ) + { + m_Title = title; + m_Author = author; + m_Pages = pages; + } + + public BookPageInfo[] Copy() + { + BookPageInfo[] copy = new BookPageInfo[m_Pages.Length]; + + for ( int i = 0; i < copy.Length; ++i ) + copy[i] = new BookPageInfo( m_Pages[i].Lines ); + + return copy; + } + + public bool IsMatch( BookPageInfo[] cmp ) + { + if ( cmp.Length != m_Pages.Length ) + return false; + + for ( int i = 0; i < cmp.Length; ++i ) + { + string[] a = m_Pages[i].Lines; + string[] b = cmp[i].Lines; + + if ( a.Length != b.Length ) + { + return false; + } + else if ( a != b ) + { + for ( int j = 0; j < a.Length; ++j ) + { + if ( a[j] != b[j] ) + return false; + } + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/DrakovsJournal.cs b/Scripts/Items/Books/Defined/DrakovsJournal.cs new file mode 100644 index 0000000..aaa3ff5 --- /dev/null +++ b/Scripts/Items/Books/Defined/DrakovsJournal.cs @@ -0,0 +1,129 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DrakovsJournal : BlueBook + { + public static readonly BookContent Content = new BookContent + ( + "Drakov's Journal", "Drakov", + new BookPageInfo + ( + "My Master", + "", + "This journal was", + "found on one of", + "our controllers. It", + "seems he has lost", + "faith in you. Know", + "that he has been" + ), + new BookPageInfo + ( + "dealth with and will", + "never again speak", + "ill of you or our", + "cause.", + " -Galzon" + ), + new BookPageInfo + ( + "We have completted", + "construction of the", + "devices needed to", + "build the clockwork", + "overseers and minions", + "as per the request of", + "the Master. The", + "gargoyles have been" + ), + new BookPageInfo + ( + "most useful and their", + "knowledge of the", + "techniques for the", + "construction of these", + "creatures will serve", + "us well.", + " -----", + "I am not one to" + ), + new BookPageInfo + ( + "criticize the Master,", + "but I believe he may", + "have erred in his", + "decision to destroy", + "the wingless ones.", + "Already our forces", + "are weakened by the", + "constant attacks of" + ), + new BookPageInfo + ( + "the humans Their", + "strength and", + "unquestioning", + "compliance would", + "have made them very", + "useful in the fight", + "against the humans.", + "But the Master felt" + ), + new BookPageInfo + ( + "their presence to be", + "an annoyance and", + "a distraction to the", + "winged ones. It was", + "not difficult at all", + "to remove them from", + "this world. But now", + "I fear without more" + ), + new BookPageInfo + ( + "allies, willing or", + "not, we stand", + "little chance of", + "defeating the foul", + "humans from our", + "lands. Perhaps if", + "the Master had", + "shown a little" + ), + new BookPageInfo + ( + "mercy and forsight", + "we would not be", + "in such dire peril." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public DrakovsJournal() : base( false ) + { + } + + public DrakovsJournal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/FropozJournal.cs b/Scripts/Items/Books/Defined/FropozJournal.cs new file mode 100644 index 0000000..c8e5fc9 --- /dev/null +++ b/Scripts/Items/Books/Defined/FropozJournal.cs @@ -0,0 +1,182 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FropozJournal : RedBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal", "Fropoz", + new BookPageInfo + ( + "I have done as my", + "Master has", + "instructed me.", + "", + "The painted humans", + "have been driven into", + "Britannia and are even", + "now wreaking havoc" + ), + new BookPageInfo + ( + "across the land,", + "providing us with the", + "distraction my Master", + "requested. We", + "have provided them", + "with the masks", + "necessary to defeat", + "the orcs, thus" + ), + new BookPageInfo + ( + "causing even more", + "distress for the people", + "of Britannia. The", + "unsuspecting fools", + "are too busy dealing", + "with the orc hordes to", + "continue their", + "exploration of our" + ), + new BookPageInfo + ( + "lands. We are", + "safe...for now.", + " ----", + "The attacks", + "continue exactly as", + "planned. My Master", + "is pleased with my", + "work and we are" + ), + new BookPageInfo + ( + "closer to our goals than", + "ever before. The", + "gargoyles have proven", + "to be more troublesome", + "than we first", + "anticipated, but I", + "believe we can", + "subjugate them fully" + ), + new BookPageInfo + ( + "given enough time. It's", + "unfortunate that we", + "did not discover their", + "knowledge sooner.", + "Even now they", + "prepare our armies", + "for battle, but not", + "without resistance." + ), + new BookPageInfo + ( + "Now that some of", + "them know of the", + "other lands and of", + "humans, they will", + "double their efforts to", + "seek help. This", + "cannot be allowed.", + " -----" + ), + new BookPageInfo + ( + "Damn them!! The", + "humans proved", + "more resourcefull than", + "we thought them", + "capable of. Already", + "their homes are free", + "of orcs and savages", + "and they once again" + ), + new BookPageInfo + ( + "are treading in our", + "lands. We may have to", + "move sooner than we", + "thought. I will", + "prepar my brethern", + "and our golems.", + "Hopefully, we can", + "buy our Master some" + ), + new BookPageInfo + ( + "more time before the", + "humans discover us.", + " -----", + "It's too late. The", + "gargoyles whom have", + "evaded our capture", + "have opened the doors", + "to our land." + ), + new BookPageInfo + ( + "They pray the", + "humans will help", + "them, despite the", + "actions of their", + "cousins in Britannia. I", + "fear they are right.", + "I must go to warn", + "the MastKai Hohiro," + ), + new BookPageInfo + ( + ), + new BookPageInfo + ( + "10.11.2001", + "first one to be here", + "", + "Congrats. I didn't really", + "care to log on earlier,", + "nor did I come straight", + "here. 2pm, Magus" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public FropozJournal() : base( false ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( "Fropoz's Journal" ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, "Fropoz's Journal" ); + } + + public FropozJournal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/KaburJournal.cs b/Scripts/Items/Books/Defined/KaburJournal.cs new file mode 100644 index 0000000..7ca40e0 --- /dev/null +++ b/Scripts/Items/Books/Defined/KaburJournal.cs @@ -0,0 +1,267 @@ +using System; +using Server; + +namespace Server.Items +{ + public class KaburJournal : RedBook + { + public static readonly BookContent Content = new BookContent + ( + "Journal", "Kabur", + new BookPageInfo + ( + "The campaign to slaughter", + "the Meer goes well.", + "Although they seem to", + "oppose the forces of", + "ours at every turn, we", + "still defeat them in", + "combat. Spies of the", + "Meer have been found and" + ), + new BookPageInfo + ( + "slain outside of the", + "fortress of ours. The", + "fools underestimate us.", + "We have the power of", + "Lord Exodus behind us.", + "Soon they will learn to", + "serve the Juka and I", + "shall carry the head of" + ), + new BookPageInfo + ( + "the wench, Dasha, on a", + "spike for all the warriors", + "of ours to share triumph", + "under.", + "", + "One of the warriors of", + "the Juka died today.", + "During the training" + ), + new BookPageInfo + ( + "exercises of ours he", + "spoke out in favor of", + "the warriors of the", + "Meer, saying that they", + "were indeed powerful and", + "would provide a challenge", + "to the Juka. A Juka in", + "fear is no Juka. I gave" + ), + new BookPageInfo + ( + "him the death of a", + "coward, outside of battle.", + "", + "More spies of the Meer", + "have been found around", + "the fortress of ours.", + "Many have been seen and", + "escaped the wrath of the" + ), + new BookPageInfo + ( + "warriors of ours. Those", + "who have been captured", + "and tortured have", + "revealed nothing to us,", + "even when subjected to", + "the spells of the females.", + " I know the Meer must", + "have plans against us if" + ), + new BookPageInfo + ( + "they send so many spies.", + " I may send the troops", + "of the Juka to invade", + "the camps of theirs as a", + "warning.", + "", + "I have met Dasha in", + "battle this day. The" + ), + new BookPageInfo + ( + "efforts of hers to draw", + "me into a Black Duel", + "were foolish. Had we", + "not been interrupted in", + "the cave I would have", + "ended the life of hers", + "but I will have to wait", + "for another battle. Lord" + ), + new BookPageInfo + ( + "Exodus has ordered more", + "patrols around the", + "fortress of ours. If", + "Dasha is any indication,", + "the Meer will strike soon.", + "", + "More Meer stand outside", + "of the fortress of ours" + ), + new BookPageInfo + ( + "than I have ever seen at", + "once. They must seek", + "vengeance for the", + "destruction of their", + "forest. Many Juka stand", + "ready at the base of the", + "mountain to face the", + "forces of theirs but" + ), + new BookPageInfo + ( + "today may be the final", + "battle. Exodus has", + "summoned me, I must", + "prepare.", + "", + "Dusk has passed and the", + "Juka now live in a new", + "age, a later time. I have" + ), + new BookPageInfo + ( + "just returned from", + "exploring the new world", + "that surrounds the", + "fortress of the Juka.", + "During the attack of the", + "Meer the madman", + "Adranath tried to destroy", + "the fortress of ours" + ), + new BookPageInfo + ( + "with great magic. At", + "once he was still and", + "light surrounded the", + "fortress. Everything", + "faded from view. When I", + "regained the senses of", + "mine I saw no sign of", + "the Meer but Dasha." + ), + new BookPageInfo + ( + "She has not been found", + "since this new being,", + "Blackthorn, blasted her", + "from the top of the", + "fortress.", + "The forest was gone, now", + "replaced by grasslands.", + "In the far distance I" + ), + new BookPageInfo + ( + "could see humans that", + "had covered the bodies of", + "theirs in marks. Even", + "Gargoyles populate this", + "place. Exodus has", + "explained to me that the", + "Juka and the fortress of", + "ours have been pulled" + ), + new BookPageInfo + ( + "forward in time. The", + "world we knew is now", + "thousands of years in the", + "past. Lord Exodus say", + "he has has saved the", + "Juka from extinction. I", + "do not want to believe", + "him. I asked this" + ), + new BookPageInfo + ( + "stranger about the Meer,", + "but he tells me a new", + "enemy remains to be", + "destroyed. It seems the", + "enemies of ours have", + "passed away to dust like", + "the forest." + ), + new BookPageInfo + ( + "I have spoken with other", + "Juka and I suspect I have", + "been told the truth. All", + "the Juka had powerful", + "dreams. In the dreams", + "of ours the Meer invaded", + "the fortress of ours and", + "a great battle took place." + ), + new BookPageInfo + ( + " All the Juka and all the", + "Meer perished and the", + "fortress was destroyed", + "from Adranath's spells. I", + "would not like to believe", + "that the Meer could ever", + "destroy us, but now it", + "seems we have seen a" + ), + new BookPageInfo + ( + "vision of the fate of", + "ours now lost in time. I", + "must now wonder if the", + "Meer did not die in the", + "battle with the Juka, how", + "did they die? And more", + "importantly, where is", + "Dasha?" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public KaburJournal() : base( false ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( "Khabur's Journal" ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, "Khabur's Journal" ); + } + + public KaburJournal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/LibraryBooks.cs b/Scripts/Items/Books/Defined/LibraryBooks.cs new file mode 100644 index 0000000..8350277 --- /dev/null +++ b/Scripts/Items/Books/Defined/LibraryBooks.cs @@ -0,0 +1,6211 @@ +using System; +using Server; + +namespace Server.Items +{ + #region A Grammar of Orcish + public class GrammarOfOrcish : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "A Grammar of Orcish", "Yorick of Yew", + new BookPageInfo + ( + "This volume, and", + "others in the series,", + "are sponsored by", + "donations from Lord", + "Blackthorn, ever a", + "supporter of", + "understanding the", + "other sentient races" + ), + new BookPageInfo + ( + "of Britannia.", + "-", + "", + " The Orcish tongue", + "may fall unpleasingly", + "'pon the ear, yet it", + "has within it a", + "complex grammar oft" + ), + new BookPageInfo + ( + "misunderstood by", + "those who merely", + "hear the few broken", + "words of English our", + "orcish brothers", + "manage without", + "education.", + " These are the basic" + ), + new BookPageInfo + ( + "rules of orcish:", + " Orcish has five", + "tenses: present, past,", + "future imperfect,", + "present interjectional,", + "and prehensile.", + " Examples: gugroflu,", + "gugrofloog, gugrobo," + ), + new BookPageInfo + ( + "gugroglu!, gugrogug.", + " All transitive verbs", + "in the prehensile", + "tense end in \"ug.\"", + " Examples:", + "urgleighug,", + "biggugdaghgug,", + "curdakalmug." + ), + new BookPageInfo + ( + " All present", + "interjectional", + "conjugations start", + "with the letter G", + "unless the contain the", + "third declensive", + "accent of the letter U.", + " Examples:" + ), + new BookPageInfo + ( + "ghothudunglug, but not", + "azhbuugub.", + " The past tense can", + "only refer to events", + "since the last meal,", + "but the prehensile", + "tense can refer to", + "any event within" + ), + new BookPageInfo + ( + "reach.", + " The present tense", + "is conjugated like the", + "future imperfect", + "tense, when the", + "interrogative mode is", + "used by pitching the", + "sound a quarter-tone" + ), + new BookPageInfo + ( + "higher.", + "Orcish hath no", + "concept of person, as", + "in first person, third", + "person, I, we, etc.", + " Orcish grammar", + "relies upon the three", + "cardinal rules of" + ), + new BookPageInfo + ( + "accretion, prefixing,", + "and agglutination, in", + "addition to pitch. In", + "the former, phonemes", + "combine into larger", + "words which may", + "contain full phrasal", + "significance. In the" + ), + new BookPageInfo + ( + "second, prefixing", + "specific phonetic", + "sounds changes the", + "subject of the", + "sentence into object,", + "interrogative,", + "addressed individual,", + "or dinner." + ), + new BookPageInfo + ( + " Agglutination occurs", + "whenever four of the", + "same letter are", + "present in a word, in", + "which case, any two", + "of them may be", + "removed or slurred.", + " Pitch changes the" + ), + new BookPageInfo + ( + "phoneme value of", + "individual syllables,", + "thus completely", + "altering what a word", + "may mean. The", + "classic example is", + "\"Aktgluthugrot", + "bigglogubuu" + ), + new BookPageInfo + ( + "dargilgaglug lublublub\"", + "which can mean \"You", + "are such a pretty", + "girl,\" \"My mother ate", + "your primroses,\" or", + "\"Jellyfish nose paints", + "alms potato,\"", + "depending on pitch." + ), + new BookPageInfo + ( + " Orcish poetry often", + "relies upon repeating", + "the same phrase in", + "multiple pitches, even", + "changing pitch", + "midword. None of", + "this great art is", + "translatable." + ), + new BookPageInfo + ( + " The orcish language", + "uses the following", + "vowels: ab, ad, ag, akt,", + "at, augh, auh, azh, e,", + "i, o, oo, u, uu. The", + "vowel sound a is not", + "recognized as a vowel", + "and does not exist in" + ), + new BookPageInfo + ( + "their alphabet.", + "The orcish alphabet is", + "best learned using the", + "classic rhyme", + "repeated at 23", + "different pitches:", + " Lugnog ghu blat", + "suggaroglug," + ), + new BookPageInfo + ( + "Gaghbuu dakdar ab", + "highugbo,", + " Gothnogbuim ad", + "gilgubbugbuilug", + "Bilgeaugh thurggulg", + "stuiggro!", + "", + "A translation of the" + ), + new BookPageInfo + ( + "first pitch:", + "Eat food, the first", + "letter is ab,", + "Kill people, next letter", + "is ad,", + "I forget the rest", + "But augh is in there", + "somewhere!" + ), + new BookPageInfo + ( + "", + " What follows is a", + "complete phonetic", + "library of the orcish", + "language:", + "ab, ad, ag, akt, alm,", + "at, augh, auh, azh,", + "ba, ba, bag, bar, baz," + ), + new BookPageInfo + ( + "bid, bilge, bo, bog, bog,", + "brui, bu, buad, bug,", + "bug, buil, buim, bum,", + "buo, buor, buu, ca,", + "car, clog, cro, cuk,", + "cur, da, dagh, dagh,", + "dak, dar, deak, der,", + "dil, dit, dor, dre, dri," + ), + new BookPageInfo + ( + "dru, du, dud, duf,", + "dug, dug, duh, dun,", + "eag, eg, egg, eichel,", + "ek, ep, ewk, faugh,", + "fid, flu, fog, foo,", + "foz, fruk, fu, fub,", + "fud, fun, fup, fur,", + "gaa, gag, gagh, gan," + ), + new BookPageInfo + ( + "gar, gh, gha, ghat,", + "ghed, ghig, gho, ghu,", + "gig, gil, gka, glu, glu,", + "glug, gna, gno, gnu,", + "gol, gom, goth, grunt,", + "grut, gu, gub, gub,", + "gug, gug, gugh, guk,", + "guk," + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GrammarOfOrcish() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public GrammarOfOrcish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region A Politic Call to Anarchy + public class CallToAnarchy : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "A Politic Call to Anarchy", "Lord Blackthorn", + new BookPageInfo + ( + " Let it never be said", + "that I have aught as", + "quarrel with my liege", + "Lord British, for", + "indeed we be of the", + "best of friends,", + "sharing amicable", + "games of chess 'pon a" + ), + new BookPageInfo + ( + "winter's night, and", + "talking at length into", + "the wee hours of the", + "issues that affect the", + "realm of Britannia.", + " Yet true friendship", + "doth not prevent true", + "philosophical" + ), + new BookPageInfo + ( + "disagreement either.", + "While I view with", + "approval my lord's", + "affection for his", + "carefully crafted", + "philosophy of the", + "Eight Virtues,", + "wherein moral" + ), + new BookPageInfo + ( + "behavior is", + "encouraged in the", + "populace, I view with", + "less approval the", + "expenditure of public", + "funds upon the", + "construction of", + "\"shrines\" to said" + ), + new BookPageInfo + ( + "ideals.", + " The issue is not one", + "of funds, however,", + "but a disagreement", + "most intellectual over", + "the proper way of", + "humankind in an", + "ethical sense. Surely" + ), + new BookPageInfo + ( + "freedom of decision", + "must be regarded as", + "paramount in any", + "such moral decision?", + "Though none fail to", + "censure the", + "murderer, a subtler", + "question arises when" + ), + new BookPageInfo + ( + "we ask if his", + "behavior would be", + "ethical if he were", + "forced to it.", + " I say to thee, the", + "reader, quite flatly,", + "that no ethical system", + "shall have sway over" + ), + new BookPageInfo + ( + "me unless it", + "convinceth me, for", + "that freely made", + "choice is to me the", + "sign that the system", + "hath validity.", + " Whereas the system", + "of \"Virtues\" that my" + ), + new BookPageInfo + ( + "liege espouses is", + "indeed a compilation", + "of commonly approved", + "virtues, I approve of", + "it. Where it seeks to", + "control the populace", + "and restrict their", + "diversity and their" + ), + new BookPageInfo + ( + "range of behaviors, I", + "quarrel with it. And", + "thus do I issue this", + "politic call to anarchy,", + "whilst humbly", + "begging forgiveness", + "of Lord British for", + "my impertinence:" + ), + new BookPageInfo + ( + " Celebrate thy", + "differences. Take", + "thy actions according", + "to thy own lights.", + "Question from what", + "source a law, a rule,", + "a judge, and a virtue", + "may arise. 'Twere" + ), + new BookPageInfo + ( + "possible (though I", + "suggest it not", + "seriously) that a", + "daemon planted the", + "seed of these", + "\"Virtues\" in my Lord", + "British's mind; 'twere", + "possible that the" + ), + new BookPageInfo + ( + "Shrines were but a", + "plan to destroy this", + "world. Thou canst not", + "know unless thou", + "questioneth, doubteth,", + "and in the end,", + "unless thou relyest", + "upon THYSELF and" + ), + new BookPageInfo + ( + "thy judgement.", + " I offer these words", + "as mere philosophical", + "musings for those", + "who seek", + "enlightenment, for", + "'tis the issue that", + "hath occupied mine" + ), + new BookPageInfo + ( + "interest and that of", + "Lord British for", + "some time now." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public CallToAnarchy() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public CallToAnarchy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region A Primer on Arms and Weapons + public class ArmsAndWeaponsPrimer : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "A Primer on Arms and Weapons", "Martin", + new BookPageInfo + ( + " These are the", + "basic elements to", + "consider in assessing", + "a weapon, of which", + "all warriors who", + "regard themselves as", + "more than mere", + "mercenaries should be" + ), + new BookPageInfo + ( + "aware.", + " First and most", + "obvious is the amount", + "of damage that the", + "weapon may do", + "against unprotected", + "flesh. While 'tis this", + "which first attracts" + ), + new BookPageInfo + ( + "the attention of the", + "novice, 'tis a deadly", + "mistake to regard it", + "as the sole value of a", + "weapon. While it may", + "prove devastating", + "indeed as a means of", + "causing damage, a" + ), + new BookPageInfo + ( + "weapon must also", + "serve as stout shield", + "when engaged in", + "combat.", + " Hence the second", + "issue to which to pay", + "attention is the", + "amount of protection" + ), + new BookPageInfo + ( + "that a weapon may", + "offer. Pay close", + "attention to the guard", + "on it, if it be a blade,", + "or the stoutness of", + "its wood if it is a pole", + "arm.", + " Oft related to this" + ), + new BookPageInfo + ( + "is the weight of the", + "weapon, for a heavy", + "weapon is more", + "difficult to maneuver", + "to block with, though", + "it may do more", + "damage to thy", + "opponent." + ), + new BookPageInfo + ( + " If a weapon is too", + "heavy for the wielder", + "to move it freely,", + "they should choose", + "another and not", + "attempt to prove their", + "prowess by the size", + "of their sword." + ), + new BookPageInfo + ( + " The reach of a", + "weapon both increases", + "its defensive ability,", + "and renders it more", + "useful in open spaces", + "as it allows attack", + "against the opponent", + "without the need to" + ), + new BookPageInfo + ( + "close. But be aware of", + "the limitations of thy", + "weapon! For a", + "weapon with great", + "reach may be useless", + "in close quarters, for", + "lack of space to", + "maneuver it. Should" + ), + new BookPageInfo + ( + "that dagger-wielding", + "enemy close on thee", + "and thy halberd, 'tis", + "best to flee.", + " Lastly, a factor", + "that must always be", + "considered is the", + "condition of the" + ), + new BookPageInfo + ( + "weapon. It might be a", + "wondrous magical", + "blade of surpassing", + "sharpness and it may", + "leap to block blows", + "with a mind of its", + "own. It also might be", + "of such flimsy" + ), + new BookPageInfo + ( + "construction, or", + "damaged to such an", + "extent, that the first", + "time it clangs against", + "steel, 'twill shatter", + "into useless shards.", + " Seek ye a good", + "blacksmith should thy" + ), + new BookPageInfo + ( + "weapon become", + "damaged, but be", + "aware that their", + "ministrations may", + "simply make the", + "matter worse.", + " While mages of", + "some ability oft create" + ), + new BookPageInfo + ( + "magical weapons", + "which enhance skill,", + "are preternaturally", + "sharp, or incinerate", + "the enemy as they", + "fall, to my mind the", + "greatest gift that they", + "can grant a stout" + ), + new BookPageInfo + ( + "sword is to make it", + "resistant to damage,", + "for thy own skill can", + "make up the", + "difference. Except", + "for the fireball, but", + "if the corpse is", + "charred, then so will" + ), + new BookPageInfo + ( + "be the possessions,", + "which maketh looting", + "difficult!" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public ArmsAndWeaponsPrimer() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public ArmsAndWeaponsPrimer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region A Song of Samlethe + public class SongOfSamlethe : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "A Song of Samlethe", "Sandra", + new BookPageInfo + ( + "The first bear did", + "swim by day,", + "And it did sleep by", + "night.", + "It kept itself within", + "its cave", + "and ate by starry", + "light." + ), + new BookPageInfo + ( + "", + "The second bear it did", + "cavort", + "'Neath canopies of", + "trees,", + "And danced its", + "strange bearish sort", + "Of joy for all to see." + ), + new BookPageInfo + ( + "", + "The first bear, well,", + "'twas hunted,", + "And today adorns a", + "floor.", + "Its ruggish face has", + "been dented", + "By footfalls and the" + ), + new BookPageInfo + ( + "door.", + "", + "The second bear did", + "step once", + "Into a mushroom ring,", + "And now does dance", + "the dunce", + "For wisps and" + ), + new BookPageInfo + ( + "unseen things.", + "", + "So do not dance, and", + "do not sleep,", + "Or else be led astray!", + "For bears all end up", + "six feet deep", + "At the end of" + ), + new BookPageInfo + ( + "Samlethe's day." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public SongOfSamlethe() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public SongOfSamlethe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region A Tale of Three Tribes + public class TaleOfThreeTribes : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "A Tale of Three Tribes", "Janet, Scribe", + new BookPageInfo + ( + " The dungeon known", + "as Despise is in fact", + "not a dungeon as", + "such, but rather a", + "large natural cave.", + "Inhospitable and", + "unfriendly to", + "visitors, it is filled" + ), + new BookPageInfo + ( + "with damp spots", + "where the deadly", + "Exploding Red Spotted", + "Toadstool grows in", + "abundance.", + " According to the", + "oldest of historical", + "texts, in days gone" + ), + new BookPageInfo + ( + "by the cave was once", + "the home of three", + "separate tribes who", + "had come to an", + "accommodation with", + "each other. Oddly", + "enough, the three", + "tribes were of" + ), + new BookPageInfo + ( + "dragons, lizard men,", + "and rat men. While", + "today few except", + "extremists associated", + "with Lord Blackthorn", + "regard these latter", + "two as being", + "intelligent beings," + ), + new BookPageInfo + ( + "apparently they have", + "indeed fallen from a", + "more evolved state", + "over the years.", + " 'Tis said that these", + "three races did dwell", + "in relative harmony", + "within the vast cave," + ), + new BookPageInfo + ( + "building when they", + "required it, and", + "trading amongst", + "themselves if needed.", + " But over time,", + "something happened,", + "and they were forced", + "to withdraw from" + ), + new BookPageInfo + ( + "their society, until", + "today thou mayst", + "find individuals of", + "each species within", + "the dungeon, but", + "never again as a", + "civilization.", + " 'Tis also said that" + ), + new BookPageInfo + ( + "someday the three", + "tribes may return to", + "Despise, to once again", + "inhabit it together.", + " Until then, nothing", + "remains as token of", + "this save an oddly", + "intelligent skeleton," + ), + new BookPageInfo + ( + "magically enchanted,", + "that doth speak when", + "questions are asked,", + "and from whom I", + "obtained these tales", + "one day, when I was", + "pursued by evil", + "monsters and fled" + ), + new BookPageInfo + ( + "into his skeletal arms.", + " Fortunately, I", + "escaped and lived to", + "write it all down!" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TaleOfThreeTribes() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public TaleOfThreeTribes( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Beltran's Guide to Guilds + public class GuideToGuilds : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Beltran's Guide to Guilds", "Beltran", + new BookPageInfo + ( + " This reference", + "work is intended", + "merely to serve as", + "resource for those", + "curious as to the full", + "range of trades and", + "societies extant in", + "Britannia and nearby" + ), + new BookPageInfo + ( + "nations. For each", + "trade or guild, their", + "blazon is given.", + "", + " Armourer's Guild.", + "Gold bar above black", + "bar." + ), + new BookPageInfo + ( + " Association of", + "Warriors. Blue cross", + "on a red field.", + "", + " Barters' Guild.", + "Green and white", + "stripes, diagonal." + ), + new BookPageInfo + ( + " Blacksmith's Guild.", + "Gold alongside black.", + "", + " Federation of", + "Rogues and Beggars.", + "Red above black.", + "", + " Fighters and" + ), + new BookPageInfo + ( + "Footmen. Blue", + "horzontal bar on red", + "field.", + "", + " Guild of Archers.", + "A gold swath parting", + "red and blue." + ), + new BookPageInfo + ( + " Guild of", + "Armaments. Swath of", + "gold on black field,", + "gold accents.", + "", + " Guild of Assassins.", + "Black and red", + "quartered." + ), + new BookPageInfo + ( + "", + " Guild of Barbers.", + "Red and white", + "stripes.", + "", + " Guild of Cavalry and", + "Horse. Vertical blue", + "on a red field." + ), + new BookPageInfo + ( + "", + " Guild of", + "Fishermen. Blue and", + "white, quartered.", + "", + " Guild of Mages.", + "Purple and blue, in a", + "crossed pennant" + ), + new BookPageInfo + ( + "pattern.", + "", + " Guild of", + "Provisioners. White", + "bar above green bar.", + "", + " Guild of Sorcery. A", + "field divided" + ), + new BookPageInfo + ( + "diagonally in blue and", + "purple.", + "", + " Healers Guild. Gold", + "swath dividing green", + "from purple, gold", + "accents." + ), + new BookPageInfo + ( + " Lord British's", + "Healers of Virtue.", + "Golden ankh on dark", + "green.", + "", + " Masters of Illusion.", + "Blue and purple", + "checkers." + ), + new BookPageInfo + ( + "", + " Merchants' Guild.", + "Gold coins on green", + "field.", + "", + " Mining Cooperative.", + "A gold cross,", + "quartering blue and" + ), + new BookPageInfo + ( + "black.", + "", + " Order of Engineers.", + "Purple, gold, and blue", + "vertical.", + "", + " Sailors' Maritime", + "Association. A white" + ), + new BookPageInfo + ( + "bar centered on a blue", + "field.", + "", + " Seamen's Chapter.", + "Blue and white in a", + "crossed pennant", + "pattern." + ), + new BookPageInfo + ( + " Society of Cooks and", + "Chefs. White and red", + "diagonal fields", + "checker on green", + "field.", + "", + " Society of", + "Shipwrights. White" + ), + new BookPageInfo + ( + "diagonal above blue.", + "", + " Society of Thieves.", + "Black and red diagonal", + "stripes.", + "", + " Society of", + "Weaponsmakers. Gold" + ), + new BookPageInfo + ( + "diagonal above black.", + "", + " Tailor's Hall. Purple", + "above gold above red.", + "", + " The Bardic", + "Collegium. Purple and", + "red checkers on gold" + ), + new BookPageInfo + ( + "field.", + "", + " Traders' Guild.", + "White bar centered", + "down green field." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public GuideToGuilds() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public GuideToGuilds( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Birds of Britannia + public class BirdsOfBritannia : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Birds of Britannia", "Thom the Heathen", + new BookPageInfo + ( + " The WREN is a", + "tiny insect-eating", + "bird with a loud voice.", + " The cheerful trills", + "of Wrens are", + "extraordinarily", + "varied and melodious.", + " The SWALLOW" + ), + new BookPageInfo + ( + "is easily recognized", + "by its forked tail.", + "Swallows catch", + "insects in flight, and", + "have squeaky,", + "twittering songs.", + " The WARBLER is", + "an exceptional singer," + ), + new BookPageInfo + ( + "whose extensive", + "songs combine the", + "best qualities of", + "Wrens and Swallows.", + " The NUTHATCH", + "climbs down trees", + "head first, searching", + "for insects in the" + ), + new BookPageInfo + ( + "bark. It sings a", + "repetitive series of", + "notes with a nasal", + "tone quality.", + " The agile", + "CHICKADEE has a", + "buzzy", + "\"chick-a-dee-dee\"" + ), + new BookPageInfo + ( + "call, from which its", + "name is derived. Its", + "song is a series of", + "whistled notes.", + " The THRUSH is a", + "brown bird with a", + "spotted breast, which", + "eats worms and" + ), + new BookPageInfo + ( + "snails, and has a", + "beautiful singing", + "voice. Thrushes use", + "a stone as an anvil to", + "smash the shells of", + "snails.", + " The little", + "NIGHTINGALE is" + ), + new BookPageInfo + ( + "also known for its", + "beautiful song, which", + "it sings even at night.", + " The STARLING", + "is a small dark bird", + "with a yellow bill and", + "a squeaky,", + "high-pitched song." + ), + new BookPageInfo + ( + "Starlings can mimic", + "the sounds of other", + "birds.", + " The SKYLARK", + "sings a series of", + "high-pitched", + "melodious trills in", + "flight." + ), + new BookPageInfo + ( + " The FINCH is a", + "small seed-eating bird", + "with a conical beak", + "and a musical,", + "warbling song.", + " The CROSSBILL", + "is a kind of Finch", + "with a strange" + ), + new BookPageInfo + ( + "crossed bill, which it", + "uses to extract seeds", + "from pine cones.", + " The CANARY is a", + "kind of Finch that is", + "often kept as a pet.", + "Miners would often", + "take Canaries" + ), + new BookPageInfo + ( + "underground with", + "them, to warn them", + "of the presence of", + "hazardous vapors in", + "the air.", + " The SPARROW", + "weaves a nest of", + "grass, and has an" + ), + new BookPageInfo + ( + "unmusical chirp for a", + "voice.", + " The TOWHEE is a", + "kind of Sparrow that", + "continually reminds", + "listeners to drink", + "their tea.", + " The SHRIKE is a" + ), + new BookPageInfo + ( + "gray bird with a", + "hooked bill. Shrikes", + "have the habit of", + "impaling their prey", + "on thorns.", + " The", + "WOODPECKER has a", + "pointed beak that is" + ), + new BookPageInfo + ( + "suitable for pecking at", + "wood to get at the", + "insects inside.", + " The", + "KINGFISHER dives", + "for fish, which it", + "catches with its long,", + "pointed beak." + ), + new BookPageInfo + ( + " The TERN", + "migrates over great", + "distances, from one", + "end of Britannia to", + "the other each year.", + "Terns dive from the", + "air to catch fish.", + " The PLOVER is a" + ), + new BookPageInfo + ( + "bird that distracts", + "predators by", + "pretending to have a", + "broken wing.", + " The LAPWING is", + "a kind of Plover that", + "has a long black crest.", + " The HAWK is a" + ), + new BookPageInfo + ( + "predator that feeds on", + "small birds, mice,", + "squirrels, and other", + "small animals. Small", + "hawks are known as", + "Kites.", + " The DOVE is a", + "seed-eating bird with" + ), + new BookPageInfo + ( + "a peaceful reputation.", + " Doves have a", + "low-pitched cooing", + "song.", + " The PARROT is a", + "brightly colored bird", + "with a hooked bill,", + "favored as a" + ), + new BookPageInfo + ( + "companion by pirates.", + " Parrots can be", + "taught to imitate the", + "human voice.", + " The CUCKOO is a", + "devious bird that lays", + "eggs in the nests of", + "Warblers and other" + ), + new BookPageInfo + ( + "small birds. Cuckoos", + "have the uncanny", + "ability to keep track", + "of time, singing once", + "at the beginning of", + "each hour.", + " The", + "ROADRUNNER is" + ), + new BookPageInfo + ( + "an unusual bird with", + "a long tail, which", + "runs swiftly along", + "the ground hunting", + "for lizards and", + "snakes.", + " The SWIFT is a", + "very agile bird that" + ), + new BookPageInfo + ( + "spends nearly its", + "entire life in the air.", + "With their mouths", + "wide open, Swifts", + "capture insects in", + "mid-flight.", + " The", + "HUMMINGBIRD is a" + ), + new BookPageInfo + ( + "cross between a", + "Swift and a Fairy.", + "These tiny, brightly", + "colored birds hover", + "magically near", + "flowers, and live on", + "the nectar they", + "provide." + ), + new BookPageInfo + ( + " The OWL is a", + "reputedly wise bird", + "that is active at night,", + "unlike most birds.", + "Owls have excellent", + "night vision and", + "low-pitched hooting", + "calls. Their wings" + ), + new BookPageInfo + ( + "are silent in flight.", + " The", + "GOATSUCKER is a", + "strange owl-like bird", + "that is thought to live", + "on the milk of goats.", + "These mysterious", + "birds make jarring" + ), + new BookPageInfo + ( + "sounds at night, for", + "which reason they", + "are also called", + "Nightjars.", + " The DUCK is a", + "bird that swims more", + "often than it flies,", + "and has a nasal voice" + ), + new BookPageInfo + ( + "that is described as a", + "\"quack\".", + " The SWAN is a", + "kind of long-necked", + "Duck that is all white.", + " Swans are usually", + "voiceless, but they", + "are said to have an" + ), + new BookPageInfo + ( + "extraordinarily", + "beautiful song." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public BirdsOfBritannia() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public BirdsOfBritannia( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Britannian Flora: A Casual Guide + public class BritannianFlora : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Britannian Flora: A Casual Guide", "Herbert the Lost", + new BookPageInfo + ( + " Oft 'pon rambling", + "through the woods", + "avoiding bears have I", + "spotted some plant", + "whose like I have", + "never seen before,", + "and concluded that I", + "was a blithering idiot" + ), + new BookPageInfo + ( + "for failing to notice it", + "in the past. Equally", + "as oft have I", + "concluded that I was a", + "worse idiot for not", + "running faster from", + "the bear.", + " While not all my" + ), + new BookPageInfo + ( + "readers may share", + "my proclivities for", + "tree-climbing, it", + "occurred to me that", + "mayhap mine", + "information might", + "serve some humble", + "purpose." + ), + new BookPageInfo + ( + " The two most", + "unique flowering", + "plants in the", + "Britannian", + "countryside are the", + "orfleur and the", + "whiteflower, also", + "called white horns." + ), + new BookPageInfo + ( + " The orfleur is", + "notable for its", + "massive orange-red", + "blossoms, which", + "dwarf marigolds like", + "the sun dwarfs your", + "common fireball spell.", + "The odor of said" + ), + new BookPageInfo + ( + "blooms is best", + "described as", + "peppermint-apple,", + "with a dash of garlic.", + "'Tis a popular potted", + "plant despite, or", + "perhaps because of,", + "its exotic nature." + ), + new BookPageInfo + ( + " Whiteflowers exude", + "a subtle fragrance not", + "unlike that of freshly", + "shaven wood mixed", + "with cool lemon ice.", + "Their tall stands", + "always droop with the", + "heavy weight of the" + ), + new BookPageInfo + ( + "massive blooms, oft", + "as large as a child's", + "head.", + " The flowers are so", + "large that one may", + "scoop out the pollen in", + "handfuls, and during", + "the spring season" + ), + new BookPageInfo + ( + "many a prank hath", + "been played by idle", + "boys 'pon their", + "sisters by dumping", + "said pollen into their", + "clothing drawers,", + "causing sneezes for", + "days." + ), + new BookPageInfo + ( + " The most", + "interesting native tree", + "to Britannia is the", + "spider tree. The", + "reason for its naming", + "is obscure, but may", + "have to do with the", + "twisted gray stalks" + ), + new BookPageInfo + ( + "from which the", + "spherical canopy", + "sprouts. 'Tis", + "something of a", + "misnomer to term", + "these \"trunks\" as", + "they are spindly and", + "flexible. Spider trees" + ), + new BookPageInfo + ( + "provide a fresh,", + "piney smell to a room", + "and are therefore", + "often potted.", + " In jungle climes,", + "one finds the blade", + "plant, whose sharp", + "leaves oft collect" + ), + new BookPageInfo + ( + "water for the thirsty", + "traveler, yet can", + "draw blood easily.", + " The deadliest plant,", + "if you can call a", + "fungus such, is the", + "Exploding Red Spotted", + "Toadstool. No pattern" + ), + new BookPageInfo + ( + "can be discerned to", + "its habitats save", + "malice, for merely", + "approaching results in", + "the cap exploding", + "with powder, noxious", + "gas, and tiny painful", + "pellets flying in all" + ), + new BookPageInfo + ( + "directions.", + "Unfortunately, 'tis", + "impossible to tell it", + "apart from the", + "Ordinary Red Spotted", + "Toadstool save through", + "experimentation.", + " Truly odd among the" + ), + new BookPageInfo + ( + "varied flora of", + "Britannia, however,", + "are those which bear", + "names clearly alien to", + "our tongue. Among", + "these I name the", + "Tuscany pine (for I", + "have never seen a" + ), + new BookPageInfo + ( + "region of this world", + "named Tuscany), the", + "o'hii tree, whose very", + "name sounds like", + "some tropical isle, and", + "the welsh poppy,", + "which while", + "different from the" + ), + new BookPageInfo + ( + "ordinary poppy in", + "color and appearance,", + "is prefaced with the", + "odd word \"welsh,\"", + "which as far as I", + "know means to forgo", + "paying a debt." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public BritannianFlora() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public BritannianFlora( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Classic Children's Tales, Volume 2 + public class ChildrenTalesVol2 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Classic Children's Tales, Volume 2", "Guilhem, Editor", + new BookPageInfo + ( + "Clarke's Printery", + "is Honored to", + "Present Tales from", + "Ages Past!", + " Guilhem the", + "Scholar Shall End", + "EachVolume with", + "Staid Commentary." + ), + new BookPageInfo + ( + "", + "THE RHYME", + "Dance in the Star", + "Chamber", + "And Dance in the Pit", + "And Eat of your", + "Entrees", + "In the Glass House" + ), + new BookPageInfo + ( + "you Sit", + "", + "COMMENTARY", + " A common feeding", + "rhyme for little", + "babies, 'tis thought", + "that this little ditty is", + "part of the corpus of" + ), + new BookPageInfo + ( + "legendary tales", + "regarding the world", + "before Sosaria (see", + "the wonderful fables", + "of Fabio the Poor for", + "fictionalized versions", + "of these stories, also", + "available from this" + ), + new BookPageInfo + ( + "same publisher).", + " According to these", + "old tales, which", + "survive mostly in the", + "hills and remote", + "villages where Lord", + "British is as yet a", + "distant and mythical" + ), + new BookPageInfo + ( + "ruler, the gods of old", + "(a fanciful notion!)", + "met to discuss the", + "progress of creating", + "the world in mystical", + "rooms. A simple", + "analysis reveals these", + "rooms to be mere" + ), + new BookPageInfo + ( + "mythological", + "generalizations.", + " \"The Star", + "Chamber\" is clearly a", + "reference to the sky.", + "\"The Pit\" is certainly", + "an Underworld", + "analogous to the" + ), + new BookPageInfo + ( + "Snakehills of other", + "tales, and \"the Glass", + "House\" is no doubt the", + "vantage point from", + "which the gods", + "observed their", + "creation. All is simple", + "when seen from this" + ), + new BookPageInfo + ( + "perspective, leaving", + "only the mysterious", + "reference to dinners.", + "Oddly enough, the", + "rhyme is universally", + "used only for", + "midnight feedings,", + "never during the day." + ), + new BookPageInfo + ( + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public ChildrenTalesVol2() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public ChildrenTalesVol2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Classic Tales of Vesper, Volume 1 + public class TalesOfVesperVol1 : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Classic Tales of Vesper, Volume 1", "Clarke's Printery", + new BookPageInfo + ( + "'Tis an Honor to", + "present to Thee these", + "Tales collected from", + "Ages Past. In this", + "Inaugural Volume, we", + "present this Verse", + "oft Recited as a", + "Lullabye for sleepy" + ), + new BookPageInfo + ( + "Children.", + "", + "Preface", + "by Guilhem the", + "Scholar", + "", + " The meaning of this", + "verse has oft been" + ), + new BookPageInfo + ( + "discussed in halls of", + "scholarly sorts, for", + "its mysterious", + "singsongy melody is", + "oddly disturbing to", + "adult ears, though", + "children seem to find", + "it restful as they" + ), + new BookPageInfo + ( + "sleep. Perhaps it is", + "but the remnant of a", + "longer ballad once", + "extant, for there are", + "internal indications", + "that it once told a", + "longer story about", + "ill-fated lovers, and a" + ), + new BookPageInfo + ( + "magical experiment", + "gone awry. However,", + "poetic license and the", + "folk process has", + "distorted the words", + "until now the locale of", + "the tale is no more", + "than \"in the wind,\"" + ), + new BookPageInfo + ( + "which while it serves", + "a pleasingly", + "metaphorical purpose,", + "fails to inform the", + "listener as to any real", + "locale!", + " Another possibility", + "is that this is some" + ), + new BookPageInfo + ( + "form of creation", + "myth explaining the", + "genesis of the various", + "humanoid creatures", + "that roam the lands of", + "Britannia. It does not", + "take a stretch of the", + "imagination to name" + ), + new BookPageInfo + ( + "the middle verse's", + "\"girl becomes tree\" as", + "a possible explanation", + "for the reaper, for in", + "the area surrounding", + "Minoc, reapers are", + "oft referred to among", + "the lumberjacking" + ), + new BookPageInfo + ( + "community as", + "\"widowmakers.\" That", + "these creatures are", + "of arcane origin is", + "assumed, but the", + "verse seems to imply", + "a long ago creator, and", + "uses the antique" + ), + new BookPageInfo + ( + "magickal terminology", + "of \"plaiting strands", + "of ether\" that is so", + "often found in", + "ancient texts. In", + "addition, the", + "reference to", + "\"snakehills\" may" + ), + new BookPageInfo + ( + "profitably be regarded", + "as a reference to an", + "actual location, such", + "as perhaps a local", + "term for the", + "Serpent's Spine.", + " A commoner", + "interpretation is that" + ), + new BookPageInfo + ( + "like many nursery", + "rhymes, it is a", + "simple explanation", + "for death, wherein", + "the wind snatches up", + "boys and girls and", + "when they sleep in", + "order to keep the" + ), + new BookPageInfo + ( + "balance of the world.", + "Notable tales have", + "been written for", + "children of", + "adventures in \"the", + "Snakehills,\" which", + "are presumed to be an", + "Afterworld whence" + ), + new BookPageInfo + ( + "the spirit lives on. A", + "grim lullabye, to be", + "sure, but no worse", + "than \"lest I die before", + "I wake\" surely.", + " In either case, 'tis", + "an old favorite,", + "herein printed for" + ), + new BookPageInfo + ( + "the first time for", + "thy enjoyment and", + "perusal!", + "", + "In the Wind where", + "the Balance", + "Is Whispered in", + "Hallways" + ), + new BookPageInfo + ( + "In the Wind where", + "the Magic", + "Flows All through the", + "Night", + "There live Mages and", + "Mages", + "With Robes made of", + "Whole Days" + ), + new BookPageInfo + ( + "Reading Books full of", + "Doings", + "Printed on Light", + "", + "In the Wind where", + "the Lovers", + "Are Crossed under", + "Shadows" + ), + new BookPageInfo + ( + "Where they Meet and", + "are Parted", + "By the Orders of", + "Fate", + "The Girl becomes", + "Tree,", + "And thus becomes", + "Widow" + ), + new BookPageInfo + ( + "The Boy becomes", + "Earth", + "And Wanders Till", + "Late", + "", + "In the Wind are the", + "Monsters", + "First Born First" + ), + new BookPageInfo + ( + "Created", + "When Chanting and", + "Ether", + "Mix Meddling and", + "Nigh", + "Fear going to Wind,", + "Fear Finding its", + "Plaitings," + ), + new BookPageInfo + ( + "Go Not to the", + "Snakehills", + "Lest You Care to Die" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TalesOfVesperVol1() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public TalesOfVesperVol1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Deceit: A Dungeon of Horrors + public class DeceitDungeonOfHorror : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Deceit: A Dungeon of Horrors", "Mercenary Justin", + new BookPageInfo + ( + " My employers have", + "oft taken me into this", + "den of hideous", + "creatures, and I", + "thought that it", + "behooved me to write", + "down what I know of", + "it, now that I am" + ), + new BookPageInfo + ( + "retired from the life", + "of an adventurer for", + "hire.", + " Deceit was once a", + "temple to forgotten", + "powers of old. It was", + "taken over by mages", + "who eventually were" + ), + new BookPageInfo + ( + "driven out by the", + "depredations of their", + "own evil lackeys.", + "However, many of", + "the magical traps and", + "devices that they", + "placed for their", + "defenses remain," + ), + new BookPageInfo + ( + "particularly those the", + "wizards used to", + "protect their", + "treasures.", + " The dungeon is", + "mystically linked by", + "crystal balls placed in", + "different locations." + ), + new BookPageInfo + ( + "These magical orbs do", + "transmit speech, and", + "even have memory of", + "things that have been", + "said near them. No", + "doubt they once", + "served as a warning", + "system" + ), + new BookPageInfo + ( + " Be wary of a", + "brazier that giveth", + "warning when", + "approached; thou canst", + "use it to summon", + "deadly creatures.", + " There be a", + "tantalizing chest," + ), + new BookPageInfo + ( + "undoubtedly full of", + "treasure, that cannot", + "be reached save past a", + "complex set of", + "pressure plates that", + "trigger deadly spikes.", + "As I never had", + "sufficient folk with" + ), + new BookPageInfo + ( + "me to unlock the", + "puzzle, I never", + "obtained the riches", + "that awaited there.", + " Do not investigate", + "iron maidens too", + "closely, for they may", + "suck you within" + ), + new BookPageInfo + ( + "them!", + " There is one place", + "where a deadly trap", + "can only be disarmed", + "by making use of a", + "statue that cleverly", + "conceals a lever.", + " Oft one encounters" + ), + new BookPageInfo + ( + "the deadly exploding", + "toadstool; the ones in", + "Deceit are deadlier", + "than most, as they", + "explode continually.", + "Likewise, the very", + "pools of water and", + "slime on the floor" + ), + new BookPageInfo + ( + "may poison thee.", + " The most magical", + "device in the dungeon", + "is a mystical bridge", + "that can only be", + "triggered by a level", + "embedded in the floor.", + "Be wary however," + ), + new BookPageInfo + ( + "for the bridge thus", + "created doth burst", + "into flame when one", + "passeth across it!" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public DeceitDungeonOfHorror() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public DeceitDungeonOfHorror( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Dimensional Travel, a Monograph + public class DimensionalTravel : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Dimensional Travel, a Monograph", "Dryus Doost, Mage", + new BookPageInfo + ( + " 'Tis beyond the", + "scope of this small", + "monograph to discuss", + "the details of", + "moongates, and the", + "manners in which", + "they distort the", + "fabric of reality in" + ), + new BookPageInfo + ( + "such a manner as to", + "permit the passage of", + "living flesh from", + "place to place, world to", + "world, or indeed from", + "dimension to", + "dimension.", + " Instead, allow me to" + ), + new BookPageInfo + ( + "bring thy attention,", + "Gentle Reader, to the", + "curious", + "characteristics that", + "are shared by certain", + "individuals within", + "our realm.", + " Long has it been" + ), + new BookPageInfo + ( + "known that the blue", + "moongate permits", + "travel from place to", + "place, and none have", + "trouble in taking this", + "path. Yet 'tis also", + "known, albeit only to a", + "few, that certain" + ), + new BookPageInfo + ( + "individuals are unable", + "to traverse the black", + "moongates that permit", + "travel from one", + "dimension to another.", + " The noted mage and", + "peer of our realm,", + "Lord Blackthorn, once" + ), + new BookPageInfo + ( + "told me in", + "conversation that his", + "arcane research had", + "indicated that the", + "issue was one of", + "conversation of ether.", + "To wit, given the", + "postulate that matter" + ), + new BookPageInfo + ( + "within a given", + "dimension may be but", + "a cross-section of", + "ethereal matter that", + "exists in multiple", + "dimensions, it", + "becomes obvious that", + "said ethereal" + ), + new BookPageInfo + ( + "structure cannot", + "enter dimensions in", + "which it is already", + "present.", + " Imagine an", + "individual (and the", + "Lord Blackthorn", + "hinted that he was" + ), + new BookPageInfo + ( + "one such) who exists", + "already in some form", + "in multiple", + "dimensions; said", + "individual would not", + "be able to cross into", + "another dimension", + "because HE IS" + ), + new BookPageInfo + ( + "ALREADY THERE.", + " The implications of", + "this are staggering,", + "and merit further", + "study. 'Tis well", + "known by theorists in", + "the field that", + "divisions in the" + ), + new BookPageInfo + ( + "ethereal structure of", + "an individual are", + "already implicit at the", + "temporal level, as", + "causality forces", + "divisions upon the", + "ether. This is the", + "basic operating" + ), + new BookPageInfo + ( + "mechanism by which", + "white moongates", + "function, permitting", + "time travel.", + " As time travel is", + "not barred by the", + "presence of an earlier", + "self (though" + ), + new BookPageInfo + ( + "encountering said", + "earlier self can prove", + "arcanely perilous),", + "there must be some", + "rigidity to the", + "ethereal structure", + "that bars multiple", + "instantiations of" + ), + new BookPageInfo + ( + "structures from", + "manifesting within", + "the same context.", + " If one regards time", + "and causal bifurcation", + "as a web, perhaps the", + "appropriate analogy", + "for dimensional" + ), + new BookPageInfo + ( + "matrices is that of a", + "crystalline structure,", + "with rigid linkages.", + "The only way in", + "which an individual", + "such as Lord", + "Blackthorn, who", + "exists in multiple" + ), + new BookPageInfo + ( + "dimensional matrices,", + "can cross worlds via", + "a black moongate,", + "would be for the", + "entire crystalline", + "structure of the", + "dimension to", + "perfectly match the" + ), + new BookPageInfo + ( + "ethereal resonance of", + "the destination", + "dimension.", + " The problem of why", + "certain individuals", + "are already replicated", + "in multiple crystalline", + "matrices is one that I" + ), + new BookPageInfo + ( + "fail to provide any", + "schema for in these", + "poor theories. It is", + "my fondest hope that", + "someday someone", + "shall conquer that", + "thorny problem and", + "enlighten the world." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public DimensionalTravel() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public DimensionalTravel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Ethical Hedonism: An Introduction + public class EthicalHedonism : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Ethical Hedonism: An Introduction", "Richard Garriott", + new BookPageInfo + ( + " Societies oft have", + "common codes of", + "conduct which it", + "expects all its people", + "to abide by. Now,", + "while 'tis true that", + "this can offer some", + "advantages, most of" + ), + new BookPageInfo + ( + "the codes I see today", + "around Britannia have", + "fatal flaws. Let us", + "examine them.", + " First, there is", + "Blackthorn's code of", + "Chaos or basically", + "Anarchy. Whereas" + ), + new BookPageInfo + ( + "this affords the", + "individual maximum", + "opportunity for", + "individuality and even", + "pursuit of personal", + "happiness, it does not", + "offer even basic", + "interpersonal conduct" + ), + new BookPageInfo + ( + "codes to prevent", + "people from killing", + "each other.", + " Without such basic", + "tenets, all the people", + "will need to spend a", + "significant portion of", + "their time and effort" + ), + new BookPageInfo + ( + "towards personal", + "protection and thus", + "less time towards", + "other more beneficial", + "pursuits.", + " Then there are the", + "moral codes that are", + "so popular today." + ), + new BookPageInfo + ( + "These codes are built", + "largely on historical", + "tradition rather than", + "current logic and thus", + "are also antiquated.", + "For example many", + "moral codes we see", + "today include" + ), + new BookPageInfo + ( + "statements about not", + "eating certain foods", + "that once were often", + "poisonous, but today", + "can be prepared", + "safely.", + " Many forbid contact", + "between young people" + ), + new BookPageInfo + ( + "of the opposite", + "gender, which can in", + "fact be hazardous; but", + "the codes often have", + "lost the context as to", + "why this is done,", + "instead merely calling", + "it amoral. In this day" + ), + new BookPageInfo + ( + "and age to call that a", + "necessary moral", + "would need a new", + "reasoning. I put forth", + "that tradition is not", + "enough", + " Then there are", + "Lord British's" + ), + new BookPageInfo + ( + "Virtues. It strikes me", + "that while a system", + "of virtues is", + "wonderful as a", + "touchstone to guide a", + "society to good", + "behavior, these are", + "but shades of the" + ), + new BookPageInfo + ( + "underlying truth as to", + "why one may wish to", + "live a life according to", + "certain rules of", + "conduct.", + " On the other hand,", + "clearly the Virtues", + "that I have heard" + ), + new BookPageInfo + ( + "Lord British speak of", + "are clearly positive", + "codes of conduct, far", + "better than the world", + "of anarchy that Lord", + "Blackthorn suggests.", + "Yet, are not these", + "Virtues still derived" + ), + new BookPageInfo + ( + "from a set of", + "principles which", + "though they sound", + "good, are difficult to", + "pin down as actual,", + "undeniable, rational", + "truths?", + " Worse yet though" + ), + new BookPageInfo + ( + "imagine a society", + "who's code of", + "conduct was based on", + "pure survival of the", + "strongest. While this", + "society may function", + "and even accomplish", + "much, it can be" + ), + new BookPageInfo + ( + "fairly argued that", + "personal happiness", + "would suffer greatly,", + "except for those at", + "the top. To rule that", + "out, however, we", + "must first believe", + "that people have a" + ), + new BookPageInfo + ( + "right to pursue", + "happiness.", + " I hope is a safe", + "assumption that all", + "beings wish to be", + "happy; I will broadly", + "describe this as", + "Hedonism. Yet, if all" + ), + new BookPageInfo + ( + "people did is live a", + "life of hedonism,", + "their hedonism might", + "be in conflict with", + "those near them, so I", + "will use the term", + "Ethics to describe", + "limits one might put" + ), + new BookPageInfo + ( + "on one's hedonistic", + "tendencies to allow", + "others to pursue their", + "happiness as well.", + " Allow me to give", + "this example: If one", + "were to live alone on a", + "desert isle, one could" + ), + new BookPageInfo + ( + "live a life of pure", + "hedonism, for no", + "action one might take", + "could interfere with", + "another's right to", + "pursue their", + "happiness. Poison the", + "lake if you like, there" + ), + new BookPageInfo + ( + "is no one to blame but", + "yourself!", + " Now suppose two", + "of you live on that", + "island. Thou dost not", + "want thy neighbor to", + "feel free to poison the", + "lake. Would it not be" + ), + new BookPageInfo + ( + "better to consider it", + "unethical to poison the", + "lake without first", + "thinking of those", + "whose pursuit of", + "happiness might be", + "affected by this", + "action?" + ), + new BookPageInfo + ( + " I put forth that it is", + "the fact that we as a", + "people choose to live in", + "groups known as a", + "society that causes us", + "to compromise our", + "pure hedonism with", + "logical ethics." + ), + new BookPageInfo + ( + "Likewise we accept", + "not being able to kill", + "others without", + "reason, because our", + "own pursuit of", + "happiness would be", + "greatly interfered", + "with if we feared" + ), + new BookPageInfo + ( + "others would do the", + "same to us. From", + "this basis of logic can", + "be formed the Tenets", + "of Ethical Hedonism.", + " For more on this", + "subject, see The", + "Tenants of Ethical" + ), + new BookPageInfo + ( + "Hedonism, by", + "Richard Garriott and", + "Herman Miller." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public EthicalHedonism() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public EthicalHedonism( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region My Story + public class MyStory : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "My Story", "Sherry the Mouse", + new BookPageInfo + ( + " 'Twas on a chill", + "night, when the moon", + "shone pasty-faced", + "above the horizon,", + "balanced on the", + "towers of Lord", + "British's castle, that", + "the events I am about" + ), + new BookPageInfo + ( + "to relate took place,", + "some years ago now. I", + "witnessed them all", + "from my tiny", + "mousehole.", + " Milords British and", + "Blackthorn are", + "accustomed to a game" + ), + new BookPageInfo + ( + "of chess 'pon an", + "evening, over which", + "they argue the issues", + "that affect the course", + "of the realm. Lord", + "Blackthorn was on his", + "way to Lord British's", + "chambers, and Lord" + ), + new BookPageInfo + ( + "British stood by a", + "window casement,", + "just having finished", + "setting the pieces", + "upon the board.", + " Suddenly the", + "shutters blew open,", + "and Lord British fell" + ), + new BookPageInfo + ( + "to the ground, one", + "hand shielding his", + "eyes. A chill wind", + "entered the room, and", + "it seemed a gash was", + "torn in the very air.", + "Through the gash I", + "could see stars and" + ), + new BookPageInfo + ( + "swirling clouds of", + "stellar dust, and a", + "coldness sucked all", + "the warmth from the", + "air. A terrible wind", + "tossed books and", + "blankets across the", + "room, and furniture" + ), + new BookPageInfo + ( + "toppled.", + " From within this", + "gash issued a great", + "voice, unlike any I", + "have ever heard. And", + "these are the words it", + "spoke (for I", + "memorized them most" + ), + new BookPageInfo + ( + "carefully):", + " \"Greetings, Lord", + "British. I am the", + "Time Lord, a being", + "from beyond your", + "dimension, as thou", + "art from a world", + "other than Sosaria. I" + ), + new BookPageInfo + ( + "am here to bring thee", + "warning. Dost thou", + "recall how long ago a", + "mysterious Stranger", + "came to Sosaria and", + "saved the world from", + "the evil wizard", + "Mondain? He" + ), + new BookPageInfo + ( + "shattered the Gem of", + "Immortality, within", + "which dwelled a", + "perfect likeness of", + "this world.\"", + " Lord British slowly", + "stood and faced the", + "hole in the air. \"I" + ), + new BookPageInfo + ( + "remember,\" he said.", + "\"Oft have I wished", + "that stranger would", + "return.\"", + " \"He hath returned,\"", + "spoke the voice. \"But", + "not to here. When the", + "Gem was shattered, a" + ), + new BookPageInfo + ( + "thousand shards were", + "scattered across the", + "dimensions, and in", + "each shard there is a", + "perfect likeness of", + "this world. And thou", + "dost live upon one", + "such shard, for thou" + ), + new BookPageInfo + ( + "art not of the true", + "world-thou art", + "merely a reflection.\"", + " Lord British looked", + "shaken by this, and I", + "did not know what to", + "think! Was I merely a", + "shadow of the real" + ), + new BookPageInfo + ( + "me, which lives still", + "somewhere else", + "across uncounted", + "universes?", + " \"My task is to heal", + "this shattered world,", + "Lord British,\" said", + "the voice. \"And I seek" + ), + new BookPageInfo + ( + "to enlist thee in my", + "cause. Be warned that", + "in this case, healing", + "carries with it a", + "terrible price.\"", + " Concern warred", + "with curiosity on my", + "liege's face, but ever" + ), + new BookPageInfo + ( + "one to shoulder a", + "burden, he", + "straightened and", + "faced the gash in the", + "air bravely. \"Name", + "thy price.\"", + " \"A shard of a", + "universe is a" + ), + new BookPageInfo + ( + "powerful thing, and a", + "universe shattered is", + "always in danger", + "from the powers of", + "darkness. Already", + "three shards were", + "turned to evil, and", + "sent to plague the" + ), + new BookPageInfo + ( + "original universe in", + "the form of", + "Shadowlords. Many", + "times have I brought", + "the Stranger back to", + "Britannia, to preserve", + "it from its own folly", + "or from outside" + ), + new BookPageInfo + ( + "dangers. Yet as long", + "as the world", + "remaineth in pieces,", + "it remaineth", + "vulnerable. We must", + "bring the shards into", + "harmony, so that they", + "resonate in such a" + ), + new BookPageInfo + ( + "manner that matches", + "the original universe.", + "Then the two", + "universes shall", + "merge, and be again", + "as one.\"", + " \"But if we are only", + "shadows...\" Lord" + ), + new BookPageInfo + ( + "British said", + "wonderingly.", + " The light from the", + "stars within the hole", + "seemed to dim.", + "\"Indeed, the", + "reflections shall", + "become one with the" + ), + new BookPageInfo + ( + "original. Thou wouldst", + "cease to be as thou", + "art, and become part", + "of the larger you.", + "Thou shalt not die;", + "however, uncounted", + "generations have", + "passed and borne" + ), + new BookPageInfo + ( + "children since that", + "day, and they have no", + "counterparts. They", + "would perish utterly.\"", + " Lord British sagged", + "in shock, realizing", + "the terrible price that", + "would be paid to heal" + ), + new BookPageInfo + ( + "the universe. \"All of", + "my people,\" he", + "breathed.", + " \"'Tis for the greater", + "good.\"", + " Lord British bowed", + "his head.", + " 'Twas then I saw" + ), + new BookPageInfo + ( + "the movement by the", + "door, half-hid by the", + "heavy red curtains.", + "Lord Blackthorn stood", + "there, concealed from", + "the rest of the room,", + "his face white. How", + "long had he been" + ), + new BookPageInfo + ( + "listening? I cannot", + "say, yet I suspect", + "that he had heard all", + "that the mysterious", + "voice had to say.", + " \"How then, shall I", + "aid thee?\" Lord", + "British said," + ), + new BookPageInfo + ( + "weariness in his", + "voice.", + " \"Aid the nobilty that", + "resideth in the", + "human heart. Protect", + "the Virtues that so", + "recently came to thee", + "in thought late at" + ), + new BookPageInfo + ( + "night. They are the", + "Virtues of life, as", + "your counterpart", + "understands them to", + "be. For when thy", + "populace doth live and", + "breathe these Virtues,", + "shall it match the" + ), + new BookPageInfo + ( + "true Britannia, and", + "thy shard shall", + "rejoin with it.\"", + " The gash in the air", + "began to close, and", + "with it warmth stole", + "back into the room.", + " \"I was going to" + ), + new BookPageInfo + ( + "discuss my idea with", + "Blackthorn tonight,\"", + "Lord British", + "breathed. \"Have I no", + "thoughts that are my", + "own? Is my life but", + "a reflection of", + "another me?\"" + ), + new BookPageInfo + ( + " \"Nay,\" said the", + "voice, smaller through", + "the diminished", + "opening. \"Say, rather,", + "that you are parallel,", + "for there is no", + "guarantee that thou", + "shalt accomplish what" + ), + new BookPageInfo + ( + "I have set thee to. I", + "speak tonight to a", + "thousand of thee, and", + "ask the same of all.", + "Perhaps not all shall", + "seek to aid me.\" And", + "with that, the gash", + "closed, and the voice" + ), + new BookPageInfo + ( + "was gone, leaving a", + "room that appeare", + "tossed by a mighty", + "storm.", + " \"Destroy the world", + "to save the universe,\"", + "Lord British said", + "bitterly. \"I do not" + ), + new BookPageInfo + ( + "wonder that some", + "may balk.\"", + " Lord Blackthorn", + "collected himself, and", + "strode into the room,", + "a decent mimicry of", + "surprise on his face.", + "\"My liege! What has" + ), + new BookPageInfo + ( + "happened here?\" he", + "exclaimed, feigning", + "dismay well. But not", + "well enough to fool", + "his old friend, whose", + "eyes narrowed at", + "seeing him there.", + " \"How much didst" + ), + new BookPageInfo + ( + "thou hear?\" demanded", + "Lord British.", + " \"Why, nothing,\"", + "managed Blackthorn,", + "his head ducked away", + "from his friend, as", + "he bent to retrieve the", + "fallen chess pieces. \"I" + ), + new BookPageInfo + ( + "merely came for our", + "game of chess.\"", + " Together they", + "righted the pedestal", + "table, and set the", + "pieces upon the black", + "and white squares.", + "\"Such simplicity to" + ), + new BookPageInfo + ( + "the game, Blackthorn,\"", + "mused Lord British,", + "idly brushing one", + "finger against the", + "board. \"Black and", + "white, each to its own", + "color, as if life were", + "so simple. What think" + ), + new BookPageInfo + ( + "you?\"", + " Blackthorn sat", + "heavily on a hassock", + "beside the chess table.", + "\"I think that matters", + "are never so simple,", + "my liege. And that I", + "would regret it deeply" + ), + new BookPageInfo + ( + "if someone, such as a", + "friend, saw it thus.\"", + " Lord British's eyes", + "met his. \"Yet", + "sometimes one must", + "sacrifice a pawn to", + "save a king.\"", + " Lord Blackthorn met" + ), + new BookPageInfo + ( + "his gaze squarely.", + "\"Even pawns have", + "lives and loves at", + "home, my lord.\" Then", + "he reached out for a", + "pawn, and firmly", + "moved it forward two", + "squares. \"Shall we" + ), + new BookPageInfo + ( + "play a game?\" he", + "asked.", + " The chess game that", + "night was a draw,", + "and they played", + "grimly.", + " And the next day,", + "Lord British gathered" + ), + new BookPageInfo + ( + "the nobles to proclaim", + "the idea of a new", + "system of Virtues,", + "and declared that", + "shrines should be", + "built across the land.", + " Lord Blackthorn", + "opposed it bitterly," + ), + new BookPageInfo + ( + "and many thought", + "him strange for doing", + "so, for ever had he", + "been a noble and", + "upright man, and", + "ever had he and Lord", + "British been in", + "accord. Declaring that" + ), + new BookPageInfo + ( + "he should start his", + "own shrine, he", + "departed the castle", + "that day to live in a", + "tower in a lake on the", + "north side of the", + "city.", + " They are still the" + ), + new BookPageInfo + ( + "best of friends, yet a", + "sadness hangs", + "between them, as if", + "they were forced into", + "making choices that", + "appealed not to them.", + "And at night, when I", + "creep softly from one" + ), + new BookPageInfo + ( + "corner of my liege's", + "bedchamber to", + "another, I sometimes", + "see him take a pawn", + "from his night table,", + "and hold it in his", + "hand, and quietly", + "weep." + ), + new BookPageInfo + ( + " But I am but a", + "mouse, and none hear", + "me. This tale goes", + "unknown, save for", + "my writing these", + "enormous letters with", + "mine ink-stained tiny", + "paws for thee to" + ), + new BookPageInfo + ( + "read, for I fear", + "indeed for our world", + "and for our people in", + "these perilous times." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public MyStory() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public MyStory( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region On the Diversity of Our Land + public class DiversityOfOurLand : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "On the Diversity of Our Land", "Lord Blackthorn", + new BookPageInfo + ( + " While I deplore the", + "depredations of the", + "misguided and", + "belligerent races with", + "which we share our", + "fair Britannia, and", + "alongside the populace,", + "do mourn the needless" + ), + new BookPageInfo + ( + "deaths that their", + "raids cause, I cannot", + "countenance the policy", + "of wholesale slaughter", + "of these races that", + "seems to be the habit", + "of our soldierly", + "element." + ), + new BookPageInfo + ( + " Can we not regard", + "the ratmen, lizard", + "men, and orcs are", + "fellow intelligent", + "beings with whom we", + "share a planet? Why", + "must we slay them", + "on sight, rather than" + ), + new BookPageInfo + ( + "attempt to engage", + "them in dialogue?", + "There is no policy of", + "shooting at wisps", + "when they grace us", + "with their presence", + "(not that an arrow", + "could do much to" + ), + new BookPageInfo + ( + "pierce them!).", + " To view these", + "creatures as vermin", + "denies their obvious", + "intelligence, and we", + "cannot underestimate", + "the repercussions", + "that their slaughter" + ), + new BookPageInfo + ( + "may have. If we", + "regard the slaying of", + "fellow humans as a", + "crime, so must we", + "regard the killing of", + "an orc.", + " At the same time,", + "should a lizardman" + ), + new BookPageInfo + ( + "slay a human, should", + "we not forgive their", + "ignorance and", + "foolishness? Let us", + "not surrender the", + "high moral ground by", + "descending to", + "bestiality." + ), + new BookPageInfo + ( + " Now, I say not that", + "we should fail to", + "defend ourselves in", + "case of attack, for", + "even amongst humans", + "we see war, we see", + "famine, and we see", + "assault (though we" + ), + new BookPageInfo + ( + "owe a debt of", + "gratitude to our Lord", + "British for", + "preserving us from", + "the worst of these!).", + "However, incursions", + "such as the recent", + "tragedy which cost us" + ), + new BookPageInfo + ( + "the life of Japheth,", + "Guildmaster of", + "Trinsic's Paladins,", + "are folly.", + " I had met Japheth,", + "and like all paladins,", + "he burned with an", + "inner fire. Yet" + ), + new BookPageInfo + ( + "though I had the", + "utmost respect for", + "him, none could deny", + "the hatred that", + "flashed in his eyes at", + "the mere mention of", + "orcs. And thus he", + "carried his battle to" + ), + new BookPageInfo + ( + "the orc camps, and", + "died there, unable to", + "rise above his own", + "childhood experiences", + "depicted in his book,", + "\"The Burning of", + "Trinsic.\" 'Tis a", + "shame that even our" + ), + new BookPageInfo + ( + "mightiest men fall", + "prey to this", + "ignorance!", + " Are there not", + "legends of orcs", + "adopting human", + "children to raise as", + "their own? Tales of" + ), + new BookPageInfo + ( + "complex societies built", + "underground by races", + "we regard as bestial?", + " Let us not repeat", + "the mistake of", + "Japheth of the", + "Paladins, and let us", + "cease to persecute the" + ), + new BookPageInfo + ( + "nonhuman races,", + "before we discover", + "that we are harming", + "ourselves in the", + "process." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public DiversityOfOurLand() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public DiversityOfOurLand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Quest of the Virtues + public class QuestOfVirtues : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Quest of the Virtues", "Autenil", + new BookPageInfo + ( + "Volume 1", + "Chapter 1: Starting out", + "I begin my Quest in the", + "fine bank of Skara Brae.", + "My Quest is to travel by", + "foot to the eight shrines", + "of Britannia. Although", + "this may sound easy, it" + ), + new BookPageInfo + ( + "is hampered because I", + "have forsaken my abilities", + "and worldly possessions.", + "Instead, all that I have", + "to live by are a set of", + "plain clothes, a ship to", + "sail the seas and my", + "diary in which to record" + ), + new BookPageInfo + ( + "my adventures. Onward", + "Ho towards the Shrine of", + "Spirituality!", + "", + "Chapter 2: The Road to", + "Spirituality", + "", + "Since I have forsaken" + ), + new BookPageInfo + ( + "magic as a form of", + "travel, I must find a way", + "to the mainland from this", + "island town. Fortunately,", + "I was able to barter a", + "ride from the ferryman.", + "Upon reaching the", + "mainland, I followed the" + ), + new BookPageInfo + ( + "road until it turned", + "North, yet I must", + "continue Eastward. I", + "paused to listen to the", + "pleasant sounds of the", + "birds chirping and enjoyed", + "the peace away from the", + "busy life. Upon reaching" + ), + new BookPageInfo + ( + "the Hedge Maze I recalled", + "a story about the mage", + "Relvinian in the days of", + "old and turned South to", + "go around it. Possessing", + "no weapons and having", + "forsaken my training, I", + "heeded the sign that said," + ), + new BookPageInfo + ( + "\"Enter and Become One", + "Among Ghosts.\" The River", + "forced me to turn South", + "and then continue East.", + "", + "Chapter 3: Spirituality", + "", + "Spirituality is the leader" + ), + new BookPageInfo + ( + "of the Virtues. It is the", + "meditation and", + "understanding of all other", + "Virtues. Without", + "Spirituality, one cannot", + "completely follow the", + "Virtues, for It is the", + "dedication and adherance" + ), + new BookPageInfo + ( + "to them.", + "", + "Chapter 4: Finding Honor", + "", + "My next visit will be to", + "the Shrine of Honor,", + "which lies a fair distance", + "to the South. There is a" + ), + new BookPageInfo + ( + "road to my East that I", + "will follow to the town", + "of Trinsic. I found a", + "warm room at the", + "Traveller's Inn, and woke", + "refreshed in the morning", + "to hear the sounds of", + "nature as I prepared to" + ), + new BookPageInfo + ( + "continue my journeys. I", + "thanked the kind innkeeper", + "and headed out of Trinsic", + "and South. I conversed", + "briefly with one lucky", + "enough to own a house in", + "the beautiful country and", + "he bade me good fortune" + ), + new BookPageInfo + ( + "on my travels. I used my", + "rusty blade to cut", + "through dense jungles", + "past ruins of a forgotten", + "realm, now inhabited only", + "by the Undead. Many a", + "mongbat did hamper my", + "journey, but finally I" + ), + new BookPageInfo + ( + "arrived at the Shrine of", + "Honor.", + "", + "Chapter 5: Honor", + "", + "Many link Honor and", + "battle, but it can be", + "used with any aspect of" + ), + new BookPageInfo + ( + "Life. Honor is to abide", + "by the rules, dishonor is", + "to cheat; to seek the", + "unfair advantage. I vowed", + "to always live life with", + "Honor.", + "", + "Chapter 6: Seeking Valor" + ), + new BookPageInfo + ( + "I must now embark on my", + "trusty small ship, the", + "Hollandia, to the South", + "and East, to a small", + "island where few have", + "travelled. I know not yet", + "what I will encounter at", + "sea, so I bid the Virtues" + ), + new BookPageInfo + ( + "grant me safety. So", + "begins my voyage. I", + "managed to sail unnoticed", + "past some water", + "elementals which took a", + "fair bit of navigation", + "from my tillerman.", + "However, I arrived without" + ), + new BookPageInfo + ( + "incident.", + "", + "Chapter 7: Valor", + "", + "The Shrine of Valor is", + "protected by many a", + "beast far too poisonous", + "and foul for myself to" + ), + new BookPageInfo + ( + "vanquish. One mush show", + "Valor to approach the", + "Shrine! Valor is often", + "shown in one's willingness", + "to fight what maybe a", + "losing battle upon which", + "he believes. It takes", + "Valor to stand your" + ), + new BookPageInfo + ( + "ground against the many", + "murderers and lawbreakers", + "in our lands. You may", + "lose, but you show Valor", + "in that you fight that", + "which must be opposed.", + "Fight the fights you", + "believe in, not just the" + ), + new BookPageInfo + ( + "fights you think you can", + "win.", + "", + "Chapter 8: The Voyage to", + "Humility", + "", + "My journey will continue", + "to the East towards the" + ), + new BookPageInfo + ( + "Shrine of Humility. I", + "launch my boat from the", + "West side of the Island", + "of Valor, where I made", + "my daring escape from", + "the many Giant Serpents", + "chasing me with their", + "poisonous venom and" + ), + new BookPageInfo + ( + "hissing tongues. Beautiful", + "blue waves washed over", + "the bow of the boat as", + "dolphins played, merrily", + "leading me on. The voyage", + "is long and the water", + "turbulent but finally land", + "was struck. Quickly I ran," + ), + new BookPageInfo + ( + "eager to find my final", + "destination for the day.", + "", + "Chapter 9: Humility", + "", + "The Shrine of Humility is", + "surprisingly spartan; it is", + "merely a grove of stone" + ), + new BookPageInfo + ( + "pillars with an ankh and", + "the Humility stone at its", + "center. I would", + "characterize Humility as", + "this Quest; returning to", + "my roots in this world. I", + "have rejected my", + "possessions and my wealth" + ), + new BookPageInfo + ( + "in order to rely only", + "upon my cunning and", + "instincts. No longer have", + "I that which makes me", + "Glorious to others, but I", + "have only that which I", + "need to survive. I may no", + "longer rely upon myself, I" + ), + new BookPageInfo + ( + "must rely upon others", + "for my survival. My", + "journey to Humility has", + "only made me realize even", + "more how Blessed I have", + "been." + ), + new BookPageInfo + ( + "Chapter 10: Onward to", + "Honesty", + "", + "Now the journey will turn", + "South towards the Island", + "of Ice. However, my", + "voyages and excursions", + "into the jungle have made" + ), + new BookPageInfo + ( + "me quite tired, so I will", + "camp here beside a river", + "near the Shrine of", + "Humility for the night. I", + "awake the next morning", + "refreshed and invigorated,", + "but also under attack! A", + "Headless One has noticed" + ), + new BookPageInfo + ( + "my rise from slumber and", + "attacks viciously. My", + "trusty cleaver was in my", + "hand instantly, but my", + "lack of skill with the", + "weapon delayed the death", + "of the creature. I", + "launched the Hollandia and" + ), + new BookPageInfo + ( + "set sail for the Island of", + "Ice, seeking the Shrine of", + "Honesty. As I sail the", + "vast oceans, I find myself", + "desiring the company of", + "my fellow man. Hopefully I", + "shall meet some kind of", + "traveller with whom I may" + ), + new BookPageInfo + ( + "exchange a few words.", + "Shortly I was landing my", + "boat on the North end of", + "the Island of Ice. I", + "quickly made my way", + "through snow across the", + "frigid tundra while trying", + "to keep warm. The Shrine" + ), + new BookPageInfo + ( + "of Honesty bid me", + "welcome as I felth the", + "warmth radiate throughout", + "me.", + "", + "Chapter 11: Honesty", + "", + "Honesty is to uphold and" + ), + new BookPageInfo + ( + "defend the truth at all", + "times. Furthermore,", + "Honesty requires us to", + "be fair and true to our", + "fellow man; not taking", + "undue advantage. Honesty", + "is a Virtue often lacking", + "in today's world. It seems" + ), + new BookPageInfo + ( + "as though people are out", + "to gain wealth with no", + "regard to Honesty", + "towards other people.", + "Honesty is the foundation", + "upon which trust is built.", + "If the foundation", + "crumbles, everything built" + ), + new BookPageInfo + ( + "upon it must fall. The", + "cold environment which", + "houses the Shrine of", + "Honesty is a testament", + "to its value in today's", + "society. The symbolic cold", + "and secluded location", + "shows us that only the" + ), + new BookPageInfo + ( + "most dedicated to", + "pursuing Honesty will", + "achieve it. May we all be", + "Honest with our fellow", + "man and remember to", + "treat them how we would", + "like to be treated." + ), + new BookPageInfo + ( + "Chapter 12: The Path to", + "Sacrifice.", + "", + "I made my way to the", + "West side of the Island", + "of Ice. From there I", + "launch the Hollandia and", + "sail slightly to the North" + ), + new BookPageInfo + ( + "and West. I land my boat", + "just East of the Shrine", + "of Sacrifice, so my road", + "is West. Although I enjoy", + "the sea, I am happy to", + "be back on the mainland", + "for the final three", + "Shrines." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public QuestOfVirtues() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public QuestOfVirtues( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Regarding Llamas + public class RegardingLlamas : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Regarding Llamas", "Simon", + new BookPageInfo + ( + " Llamas are curious", + "beasts, shaggy and", + "sought after for their", + "wool, yet of a", + "curiously arrogant", + "disposition reflected", + "in their eyes. They", + "live in mountainous" + ), + new BookPageInfo + ( + "areas, though who", + "may have first tamed", + "them is lost in the", + "mists of history.", + " 'Tis a well-known", + "fact that llamas can", + "indeed be tamed, and", + "used as grazing" + ), + new BookPageInfo + ( + "animals, for their", + "meat, and of course", + "for their wool. Yet", + "'tis lesser known that", + "their ornery", + "disposition and", + "tendency to spit at", + "those they dislike" + ), + new BookPageInfo + ( + "makes them appealing", + "guard creatures as", + "well, though they", + "have little sound with", + "which to sound an", + "alarum." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public RegardingLlamas() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public RegardingLlamas( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Talking to Wisps + public class TalkingToWisps : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Talking to Wisps", "Yorick ofMoonglow", + new BookPageInfo + ( + "This volume was", + "sponsored by", + "donations from Lord", + "Blackthorn, ever a", + "supporter of", + "understanding the", + "other sentient races", + "of Britannia." + ), + new BookPageInfo + ( + "-", + " Wisps are the most", + "intelligent of the", + "nonhuman races", + "inhabiting Britannia.", + "'Tis claimed by the", + "great sages that", + "someday we shall be" + ), + new BookPageInfo + ( + "able to converse with", + "them openly in our", + "native", + "tongue--indeed, we", + "must hope that wisps", + "learn our language,", + "for it is not possible", + "for humans to" + ), + new BookPageInfo + ( + "pronounce wispish!", + " The wispish", + "language seems to", + "only contain one", + "vowel, the letter Y.", + "However, the letters", + "W, C, M, and L seem", + "to be treated" + ), + new BookPageInfo + ( + "grammatically as", + "vowels, and in", + "addition every letter", + "is followed by what", + "sounds to the human", + "ear like a glottal stop.", + "It is possible that the", + "glottal stop is" + ), + new BookPageInfo + ( + "considered a vowel as", + "well.", + " Wisps do make use", + "of what sound to us", + "like pitch and", + "emphasis shifts", + "similar to", + "exclamations and" + ), + new BookPageInfo + ( + "questions.", + " The average word is", + "wispish seems to", + "consist of three", + "phonemes and three", + "glottal stops, plus", + "possibly a pitch shift.", + "It often sounds like a" + ), + new BookPageInfo + ( + "fire burning or", + "crackling. Some have", + "speculated that what", + "we are analyzing is", + "in fact nothing more", + "than the very air", + "crackling near the", + "wisp's glow, and not" + ), + new BookPageInfo + ( + "language, but this is", + "of course unlikely." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TalkingToWisps() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public TalkingToWisps( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Taming Dragons + public class TamingDragons : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Taming Dragons", "Wyrd Beastmaster", + new BookPageInfo + ( + " I have not much to", + "tell about dragons. The", + "sole time I approached", + "one with an eye", + "towards taming it,", + "my initial attempts at", + "calming it met with", + "failure. It fixed a" + ), + new BookPageInfo + ( + "massive beady eye", + "upon me, and began", + "its slithering", + "approach, intending no", + "doubt to insert me", + "into its maw and bear", + "down with its teeth.", + " However, as I was" + ), + new BookPageInfo + ( + "engaged in what", + "remains to this day", + "the most terrifying", + "combat of my life,", + "the dragon suddenly", + "whirled as if in a", + "panic, ran a short", + "distance, took off into" + ), + new BookPageInfo + ( + "the air, then", + "transformed into a", + "whirlwind. Lastly, it", + "exploded, showering", + "gouts of black blood", + "and heaving, stinking", + "flesh upon miles of", + "countryside. The" + ), + new BookPageInfo + ( + "fireball was massive,", + "enough to light a city,", + "I should surmise.", + " I never did discover", + "the exact cause of", + "this strange behavior,", + "except to assume that", + "it was not typical for" + ), + new BookPageInfo + ( + "this reptilian species.", + "My best guesses", + "revolve around a", + "magical fracture in", + "the nature of reality,", + "which is far too", + "esoteric a territory", + "for one of my limited" + ), + new BookPageInfo + ( + "scholarship.", + " Hence my basic", + "advice to those who", + "seek to tame a", + "dragon-be sure that", + "thou hast mastered", + "the twin skills of", + "taming animals, and" + ), + new BookPageInfo + ( + "running away very", + "very fast." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TamingDragons() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public TamingDragons( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Bold Stranger + public class BoldStranger : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Bold Stranger", "Old Fabio the Poor", + new BookPageInfo + ( + " In a time before", + "time, the Gods that Be", + "assembled a group of", + "artisans, craftsmen", + "and lore masters", + "(for, yes, even in", + "those days, art", + "existed) to create the" + ), + new BookPageInfo + ( + "world of Sosaria. To", + "this group, the gods", + "gave a tiny world,", + "Rytabul, in which to", + "test their works, to", + "see if they were of", + "the quality desired", + "for the true world in" + ), + new BookPageInfo + ( + "which they would be", + "placed. And though", + "the gods were tight", + "fisted with their gold,", + "this small crew", + "worked hard and long,", + "and were happy in", + "their tasks." + ), + new BookPageInfo + ( + " A small corner of", + "Rytabul had been", + "claimed by the artisan", + "Selrahc the Slow.", + "Though he was not", + "the fastest of the", + "assembled workers,", + "the gods smiled upon" + ), + new BookPageInfo + ( + "his work, even", + "presenting him with", + "a mystic talisman", + "proclaiming his work", + "the best among the", + "newer artisans. And", + "so Selrahc went about", + "his business, creating" + ), + new BookPageInfo + ( + "hundreds of designs", + "which would one day", + "add color and variety", + "to Sosaria.", + " One day a", + "stranger appeared to", + "Selrahc. His chest", + "was bare and he wore" + ), + new BookPageInfo + ( + "trousers of the", + "brightest green, and", + "wherever he went,", + "plants grew in his", + "footsteps. This", + "caused Selrahc no end", + "of trouble, the", + "stranger always" + ), + new BookPageInfo + ( + "looking over his", + "shoulder, and the", + "plants sprouting in", + "places Selrahc", + "required to ply his", + "art. And so Selrahc", + "approached the", + "stranger and bade" + ), + new BookPageInfo + ( + "him speak. But this", + "man in green", + "remained silent.", + "Selrahc pleaded with", + "the stranger to give", + "his name, and would", + "he please leave", + "Selrahc to his work." + ), + new BookPageInfo + ( + "But this mysterious", + "stranger remained", + "mute.", + " This angered", + "Selrahc mightily. Who", + "was this silent man,", + "interfering with", + "tasks the gods" + ), + new BookPageInfo + ( + "themselves had", + "entrusted to Selrahc?", + "In an attempt to", + "embarrass this", + "interloper, Selrahc", + "stole his green", + "trousers, leaving him", + "naked and open to" + ), + new BookPageInfo + ( + "comments about his", + "very manhood, and", + "still the stranger", + "would not speak,", + "would not leave this", + "tiny corner of", + "Rytabul.", + " Vexed to his very" + ), + new BookPageInfo + ( + "limits, Selrahc took", + "his war axe and", + "smote the silent one", + "mightily, again and", + "again, until the silent", + "stranger ran away,", + "having never said a", + "word, and never" + ), + new BookPageInfo + ( + "showed himself in", + "Rytabul again.", + " Thus endeth the", + "tale of the bold", + "stranger." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public BoldStranger() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public BoldStranger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Burning of Trinsic + public class BurningOfTrinsic : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Burning of Trinsic", "Japheth of Trinsic", + new BookPageInfo + ( + " 'Twas a sight to", + "see, the sunlight", + "falling lightly on the", + "sandstone walls of", + "Trinsic 'pon a", + "morning in spring.", + " Children ran along", + "the parapets and" + ), + new BookPageInfo + ( + "walkways, their", + "laughter and running", + "providing music to the", + "daybreak, despite", + "their oft-ragged", + "clothing.", + " And I was one of", + "those young ones," + ), + new BookPageInfo + ( + "letting my joy rise", + "up to the skies.", + " Little did we all", + "know of the darker", + "days that would lie", + "ahead, for we were", + "too young.", + " Had we but gained" + ), + new BookPageInfo + ( + "access to the quiet", + "councils held in the", + "Paladin tower as it", + "faced the sea,", + "councils lit by", + "candlelight and", + "worry, we would", + "have learned more of" + ), + new BookPageInfo + ( + "the fears of", + "imminent attack from", + "the forest, where", + "foul creatures born", + "of dank caves and", + "darkness were", + "marauding ever more", + "often into the lands" + ), + new BookPageInfo + ( + "around Trinsic's", + "moat.", + " But we were", + "children! The", + "parapets and the moat", + "were places to play,", + "not stout defenses,", + "and we gave no" + ), + new BookPageInfo + ( + "thought to the", + "necessities that must", + "have required their", + "construction.", + " We used to reach", + "the sheltered", + "orchards on the lee", + "side of the parapet" + ), + new BookPageInfo + ( + "walls, where the", + "southern river cut", + "through the city, by", + "swimming across the", + "water.", + " The rich folk who", + "lived in the great", + "manses there would" + ), + new BookPageInfo + ( + "shout from their", + "windows and shake", + "their fists, for we", + "would run through", + "their gardens and", + "tear up the delicate", + "foxgloves and", + "orfleurs with our" + ), + new BookPageInfo + ( + "unshod dirty feet.", + "Then we would dive", + "into the water and", + "splash merrily to the", + "fruit trees.", + " The southern", + "river lazily slid", + "under the an ungated" + ), + new BookPageInfo + ( + "arch in the mighty", + "wall, and we would", + "lay on the grassy", + "bank and watch it", + "gurgle by the lily", + "pads.", + " That spring that", + "pleasant spot became" + ), + new BookPageInfo + ( + "the doorway through", + "which our city of", + "Trinsic let in the", + "monstrous deformed", + "humanoids that", + "savaged us. I lay upon", + "that grassy bank and", + "watched them wade" + ), + new BookPageInfo + ( + "in, their coarse hair", + "wet and matted, algae", + "and muck festooning", + "their wild brows.", + " They caught sight", + "of a quicksilver girl", + "with bright blond hair", + "and lively eyes. Her" + ), + new BookPageInfo + ( + "name was Leyla, and", + "that spring I had held", + "fond dreams of", + "holding her hand and", + "sharing flavored ice", + "while dangling our", + "feet off the small", + "bridge by Smugglers" + ), + new BookPageInfo + ( + "Gate.", + " And I said nothing", + "when they caught", + "her, and did not cry", + "out when they", + "dragged her off", + "through that breach in", + "our wall, and did not" + ), + new BookPageInfo + ( + "warn the city when I", + "saw the helmeted orc", + "captains call the", + "charge upon the", + "mansions.", + " Blame me not, for", + "I was but a child, and", + "one who hid in the" + ), + new BookPageInfo + ( + "branches of the peach", + "trees, all a-tremble", + "whilst I watched the", + "smoke rise from Sean", + "the tailor's, and fire", + "lash out at the roof of", + "witchy Eleanor's", + "tavern." + ), + new BookPageInfo + ( + " To this day I have", + "had no word of", + "Leyla, and to this", + "day the smell of", + "burning wood can", + "conjure terrible", + "dreams. Yet with the", + "eyes of adulthood, 'tis" + ), + new BookPageInfo + ( + "possible to examine", + "the flaws in the", + "defense of Trinsic on", + "that fateful day, and", + "the reasons why our", + "walls are now", + "double-thick, and", + "why our buildings" + ), + new BookPageInfo + ( + "are now built as", + "fortresses within a", + "somber fortified city.", + " While I can look", + "out from the top of", + "the new Paladin", + "tower, and spy the", + "mighty white sails" + ), + new BookPageInfo + ( + "across the barrier", + "island, and can", + "descry the small", + "hollow south of the", + "city where gypsies", + "are wont to camp, I", + "can also envision the", + "city as it might be" + ), + new BookPageInfo + ( + "burning, and I bless", + "the bargain we made:", + "space for safety,", + "grace for sturdiness,", + "and wood for stone.", + " Whilst I live, I", + "shall not see Trinsic", + "burn, and no more" + ), + new BookPageInfo + ( + "cries of little girls", + "will haunt the sleep", + "of our fair citizens.", + " - Japheth, Paladin", + "Guildmaster of the", + "City of Trinsic" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public BurningOfTrinsic() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public BurningOfTrinsic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Fight + public class TheFight : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Fight", "M. de la Garza", + new BookPageInfo + ( + " A cold autumn's", + "morning with misty", + "fog secures a dozen", + "brave knights,", + "supplying hidden", + "shelter from prying", + "eyes deep in the", + "foothills of the" + ), + new BookPageInfo + ( + "vibrant valley.", + "Dragons soar like", + "fierce warriors,", + "circling around and", + "around, then roaring", + "like thunder, rallying", + "all that listen. The", + "dragons land swiftly" + ), + new BookPageInfo + ( + "beside the proud", + "warriors, bending", + "necks and extending", + "wings, lifting black", + "claws and allowing", + "valiant fighters to", + "ride forth and win an", + "arisen battle. The" + ), + new BookPageInfo + ( + "increasing winds", + "silence the sounds of", + "combat, and they", + "fight, standing their", + "ground like mothers", + "protecting their", + "childern, bright", + "armor flashing as" + ), + new BookPageInfo + ( + "each one falls.", + " A cold autumn's", + "evening with misty", + "fog cradles a dozen", + "battered corpses of", + "knights, creasing", + "them in currents of", + "winds that run deep" + ), + new BookPageInfo + ( + "in the foothills of the", + "desolate valley.", + "Dragons glide like", + "silent angels, circling", + "around and around,", + "then calling like", + "banshees; keening", + "cries of mourning." + ), + new BookPageInfo + ( + "The dragons land", + "heavily beside the", + "peaceful bodies,", + "bending necks and", + "extending wings,", + "lifting black claws", + "and allowing valiant", + "fighters to ride forth" + ), + new BookPageInfo + ( + "and win an arisen", + "battle. The increasing", + "winds silence the", + "sounds of combat, and", + "they fight, standing", + "their ground like", + "mothers protecting", + "their childern, bright" + ), + new BookPageInfo + ( + "armor flashing as", + "each one falls.", + " A cold autumn's", + "evening with misty", + "fog cradles a dozen", + "battered corpses of", + "knights, creasing", + "them in currents of" + ), + new BookPageInfo + ( + "winds that run deep", + "in the foothills of the", + "desolate valley.", + "Dragons glide like", + "silent angels, circling", + "around and around,", + "then calling like", + "banshees; keening" + ), + new BookPageInfo + ( + "cries of mourning.", + "The dragons land", + "heavily beside the", + "peaceful bodies,", + "bending necks and", + "extending wings,", + "lifting black claws", + "and pinching the" + ), + new BookPageInfo + ( + "sacred ground and", + "new eternal home.", + "The dying winds", + "whistle among the", + "dead in somber", + "procession, and they", + "lie, grasping weapons", + "to protect themselves" + ), + new BookPageInfo + ( + "like knights still in", + "battle, shattered", + "armor shining like", + "newly born stars." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TheFight() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public TheFight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Life of a Travelling Minstrel + public class LifeOfATravellingMinstrel : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Life of a Travelling Minstrel", "Sarah of Yew", + new BookPageInfo + ( + " While 'tis true that", + "the musician who", + "seeketh only to make", + "sweet music for", + "herself and for", + "others needs little", + "more than some", + "talent, and stern" + ), + new BookPageInfo + ( + "practice at the chosen", + "instrument, those of", + "us who seek the open", + "road shall find indeed", + "that a greater skill is", + "required. Herein", + "discover those secrets", + "which I have learned" + ), + new BookPageInfo + ( + "over the years as an", + "itinerant performer...", + " Once I was in", + "Jhelom, and", + "accidentally angered a", + "bravo of some local", + "repute, whose blade", + "flickered all too" + ), + new BookPageInfo + ( + "eagerly near my", + "slender neck (for I", + "was young then).", + "After various threats", + "to \"ruin my pretty", + "face\" this bravo", + "grabbed my arm in a", + "most unseemly" + ), + new BookPageInfo + ( + "fashion and tossed", + "me into a barbaric", + "enclosure locally", + "entitled a dueling pit.", + "My plaintive cries", + "for help went", + "unheeded by the", + "guards, for the" + ), + new BookPageInfo + ( + "inhabitants of Jhelom", + "are eager indeed to", + "measure fighting", + "prowess at any time!", + " What saved me was", + "the ability to", + "improvise a melody", + "and tune that" + ), + new BookPageInfo + ( + "satirized the", + "proceedings, and", + "sufficiently angered", + "an onlooker to prod", + "him to coming to my", + "defense. Once that", + "fight was underway,", + "I was able to make" + ), + new BookPageInfo + ( + "good my escape.", + "Hence, I regard the", + "ability to incite fights", + "as indispensable to", + "the prudent bard.", + " Upon another", + "occasion, 'twas the", + "obverse side of that" + ), + new BookPageInfo + ( + "coin which saved me,", + "for I was being held", + "prisoner by a", + "particularly nasty", + "band of ruffians who", + "had seized me", + "unawares from the", + "road to Vesper." + ), + new BookPageInfo + ( + " They had worked", + "themselves into a", + "frenzy and were", + "ready to attack and I", + "fear, tear me limb", + "from limb, when I", + "began to sing", + "frantically, tapping" + ), + new BookPageInfo + ( + "my falled drum with", + "my tied up feet. The", + "melody developed into", + "a soothing one, and", + "the brigands slowly", + "calmed down to the", + "extent of apologizing,", + "and they let me go!" + ), + new BookPageInfo + ( + " A final example I", + "would pray you grant", + "your attention: once I", + "was lost upon a large", + "isle far to the east of", + "the mainland, well", + "beyond Serpent's", + "Hold, where lava" + ), + new BookPageInfo + ( + "made its sluggish", + "way across the", + "surface landscape.", + "And this accursed", + "land was filled with", + "vile beasts and", + "cunning dragons.", + " I was being pursued" + ), + new BookPageInfo + ( + "by one of said fell", + "dragons when I found", + "myself trapped. I", + "quickly skirted a", + "bubbling pool of molten", + "rock and attempted to", + "hide.", + " The dragon scented" + ), + new BookPageInfo + ( + "me and was", + "preparing to skirt the", + "pool, when I began to", + "play a lusty tune", + "upon my lute that", + "attracted its attention.", + "Mesmerized and", + "enticed by the" + ), + new BookPageInfo + ( + "melody, it stepped", + "directly toward sme,", + "and into the", + "lava-where its foot", + "was so burned that it", + "quickly hopped away,", + "undignified and", + "annoyed." + ), + new BookPageInfo + ( + " 'Tis my fond hope", + "that other travelling", + "minstrels shall learn", + "from my experiences", + "and apply themselves", + "to practicing these", + "skills in order to", + "preserve life and" + ), + new BookPageInfo + ( + "limb." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public LifeOfATravellingMinstrel() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public LifeOfATravellingMinstrel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Major Trade Associations + public class MajorTradeAssociation : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Major Trade Associations", "Pieter of Vesper", + new BookPageInfo + ( + " There are ten major", + "trade associations that", + "operate legitimately in", + "the lands of Britannia", + "and among its trading", + "partners. Many of", + "these guilds are", + "divided into local or" + ), + new BookPageInfo + ( + "specialty subguilds,", + "who use the same", + "colors but vary the", + "heraldic pattern.", + " There are many", + "lesser trade", + "associations that have", + "closed membership," + ), + new BookPageInfo + ( + "and one can join them", + "only by invitation.", + "Beltran's Guide to", + "Guilds is the", + "definitive text on the", + "full range of guilds", + "and other associations", + "in Britannia, and I" + ), + new BookPageInfo + ( + "heartily recommend", + "it.", + " In what follows I", + "have attempted to", + "bring together the", + "known information", + "regarding these", + "guilds. I offer thee" + ), + new BookPageInfo + ( + "the name, typical", + "membership, heraldic", + "colors, known", + "specialty", + "organizations within", + "the larger guild, and", + "any known", + "affiliations to other" + ), + new BookPageInfo + ( + "guilds, which often", + "occur because of", + "trade reasons.", + "", + "The Guild of Arcane", + "Arts", + "Members: alchemists", + "and wizards" + ), + new BookPageInfo + ( + "Colors: blue and purple", + "Subguilds: Illusionists,", + "Mages, Wizards", + "Affiliations: Healer's", + "Guild", + "", + "The Warrior's Guild", + "Members:" + ), + new BookPageInfo + ( + "mercenaries,", + "soldiery, guardsmen,", + "weapons masters,", + "paladins.", + "Colors: Blue and red", + "Subguilds: Cavalry,", + "Fighters, Warriors", + "Affiliations: League" + ), + new BookPageInfo + ( + "of Rangers", + "", + "League of Rangers", + "Members: rangers,", + "bowyers, animal", + "trainers", + "Colors: Red, gold and", + "blue" + ), + new BookPageInfo + ( + "", + "Guild of Healers", + "Members: healers", + "Colors: Green, gold,", + "and purple", + "Affiliations: Guild of", + "Arcane Arts" + ), + new BookPageInfo + ( + "Mining Cooperative", + "Members: miners", + "Colors: blue and black", + "checkers, with a gold", + "cross", + "Affiliations: Order of", + "Engineers" + ), + new BookPageInfo + ( + "Merchants'", + "Association", + "Members:", + "innkeepers,", + "tavernkeepers,", + "jewelers,", + "provisioners", + "Colors: gold coins on a" + ), + new BookPageInfo + ( + "green field for", + "Merchants. White", + "and green for the", + "others.", + "Subguilds: Barters,", + "Provisioners,", + "Traders, Merchants" + ), + new BookPageInfo + ( + "Order of Engineers", + "Members: tinkers and", + "engineers", + "Colors: Blue, gold, and", + "purple vertical bars", + "Affiliations: Mining", + "Cooperative" + ), + new BookPageInfo + ( + "Society of Clothiers", + "Members: tailors and", + "weavers", + "Colors: Purple, gold,", + "and red horizontal", + "bars", + "", + "Maritime Guild" + ), + new BookPageInfo + ( + "Members: fishermen,", + "sailors, mapmakers,", + "shipwrights", + "Colors: blue and white", + "Subguilds:", + "Fishermen, Sailors,", + "Shipwrights" + ), + new BookPageInfo + ( + "Bardic Collegium", + "Members: bards,", + "musicians,", + "storytellers, and other", + "performers", + "Colors: Purple, red", + "and gold checkerboard" + ), + new BookPageInfo + ( + "Society of Thieves", + "Members: beggars,", + "cutpurses, assassins,", + "and brigands", + "Colors: red and black", + "Subguilds: Rogues", + "(beggars), Assassins,", + "Thieves" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public MajorTradeAssociation() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public MajorTradeAssociation( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Rankings of Trades + public class RankingsOfTrades : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Rankings of Trades", "Lord Higginbotham", + new BookPageInfo + ( + " Whilst 'tis true that", + "within each trade, one", + "finds differing titles", + "and accolades granted", + "to the members of a", + "given guild,", + "nonetheless for the", + "betterment of trade" + ), + new BookPageInfo + ( + "and understanding,", + "we must have a", + "commonality of", + "titling.", + " For those who may", + "find themselves", + "ignorant of the finer", + "distinctions between a" + ), + new BookPageInfo + ( + "three-knot member of", + "the Sailors' Maritime", + "Association and a", + "second thaumaturge,", + "this book shall serve", + "as a simple", + "introduction to the", + "common cant used" + ), + new BookPageInfo + ( + "when members of", + "differing guilds and", + "trade organizations", + "must trade with each", + "other and must", + "establish relative", + "credentials.", + " Neophyte" + ), + new BookPageInfo + ( + "Has shown interest", + "in learning the craft", + "and some meager", + "talent.", + " Novice", + "Is practicing basic", + "skills but has not been", + "admitted to full" + ), + new BookPageInfo + ( + "standing.", + " Apprentice", + "A student of the", + "discipline.", + " Journeyman", + "Warranted to practice", + "the discipline under", + "the eyes of a tutor." + ), + new BookPageInfo + ( + " Expert", + "A full member of the", + "guild.", + " Adept", + "A member of the", + "guild qualified to", + "teach others.", + " Master" + ), + new BookPageInfo + ( + "Acknowledged as", + "qualified to lead a hall", + "or business.", + " Grandmaster", + "Rarely a permanent", + "title, granted in", + "common parlance to", + "those who have" + ), + new BookPageInfo + ( + "shown extreme", + "mastery of their", + "craft recently." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public RankingsOfTrades() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public RankingsOfTrades( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region The Wild Girl of the Forest + public class WildGirlOfTheForest : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "The Wild Girl of the Forest", "Horace the Trader", + new BookPageInfo + ( + " Her name was", + "Leyla, she said, and", + "her hair was braided", + "wild with creepers", + "and thorns. I", + "marveled that they", + "did not hurt her, but", + "when I asked, she but" + ), + new BookPageInfo + ( + "shrugged and let her", + "eyes roam once more", + "across the woods.", + "Though I had my", + "hands securely", + "fastened by her", + "ropes, I itched to", + "reach out and comb" + ), + new BookPageInfo + ( + "that unruly golden", + "mane, dirtied and", + "leaf-ridden.", + " Her provenance,", + "she told me over", + "nights illumined by", + "campfires, was once", + "the city of Trinsic." + ), + new BookPageInfo + ( + "She claimed to have", + "been kidnapped and", + "raised by orcs, which", + "I judged an unlikely", + "tale, for all know orcs", + "delight in eating the", + "meat of honest folk.", + "When I told her this," + ), + new BookPageInfo + ( + "she laughed a fey", + "laugh, and gaily", + "admitted that honest", + "she was not, for oft", + "had she stolen folk", + "away from caravans", + "to loot their", + "possessions from an" + ), + new BookPageInfo + ( + "unconscious body!", + " At this, I began to", + "fear for my life, and", + "her smile seemed full", + "of teeth sharper than", + "a human ought to", + "have, for the tale of", + "orcish raising had" + ), + new BookPageInfo + ( + "struck fear into the", + "marrow of my bones.", + "\"Wilt thou eat me?\" I", + "asked, a-tremble,", + "fearing the answer.", + " And she cocked", + "her head at me, like a", + "wild animal facing a" + ), + new BookPageInfo + ( + "word that it dost not", + "understand, and the", + "fixity in her eyes", + "was a glimpse into", + "the deeper reaches of", + "the Abyss. But she", + "finally grunted, and", + "said, \"Nay,\" in a" + ), + new BookPageInfo + ( + "voice that recalled to", + "me a child. \"Nay,\"", + "she said, \"for thou", + "dost remind me of a", + "boy I knew once,", + "when I was a girl", + "who played in a city", + "of great sandstone" + ), + new BookPageInfo + ( + "walls, before I was", + "taken. He had sandy", + "hair like thee, and I", + "dreamt as a child of", + "holding his hand and", + "sharing flavored ice.", + "His name was", + "Japheth.\"" + ), + new BookPageInfo + ( + " The next morning", + "she let me go,", + "stripped of my pouch", + "and clothes, and bade", + "me run through the", + "woods, and to fear", + "recapture, for surely", + "her heart would not" + ), + new BookPageInfo + ( + "soften again. 'Twas a", + "fearful run, and I", + "came to the road to", + "Yew with welts and", + "scratches run", + "rampant crost my", + "skin, but I did not see", + "her again." + ), + new BookPageInfo + ( + " Oft have I", + "wondered of the boy", + "named Japheth, and", + "whether he", + "remembers a girl who", + "lived in sandstone", + "walls. The only", + "Japheth I know is the" + ), + new BookPageInfo + ( + "Guildmaster of", + "Paladins who died", + "last year warring", + "amidst the orcs, and", + "though he had indeed", + "sandy hair, I cannot", + "picture him side by", + "side with a feral girl" + ), + new BookPageInfo + ( + "whose tongue has", + "tasted of human", + "flesh.", + " Yet the paths of", + "fate are strange", + "indeed, and I suppose", + "'tis possible that this", + "paladin died" + ), + new BookPageInfo + ( + "defending his", + "remembered lady's", + "honor, unknowingly", + "struck down by the", + "orc that she called", + "father." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public WildGirlOfTheForest() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public WildGirlOfTheForest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Treatise on Alchemy + public class TreatiseOnAlchemy : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Treatise on Alchemy", "Felicia Hierophant", + new BookPageInfo + ( + " The alchemical", + "arts are notable for", + "their deceptive", + "simplicity. 'Tis true", + "that to our best", + "knowledge currently,", + "there are but eight", + "valid potions that can" + ), + new BookPageInfo + ( + "be made (though I", + "emphasize that new", + "discoveries may", + "always await).", + "However, the delicate", + "balance of confecting", + "the potions is", + "difficult indeed, and" + ), + new BookPageInfo + ( + "requires great skill.", + " To give thee an", + "example of the", + "simpler potions that", + "can be created by", + "those well-versed in", + "the subtleties of", + "alchemy:" + ), + new BookPageInfo + ( + " Black pearl, that", + "rare substance that is", + "oft found lying", + "unannounced upon the", + "surface of the", + "ground, when", + "properly crushed", + "with mortar and" + ), + new BookPageInfo + ( + "pestle, can yield a", + "fine powder. Said", + "powder in the proper", + "proportions when", + "mixed via the", + "alchemical arts can", + "yield a wonderfully", + "refreshing drink." + ), + new BookPageInfo + ( + " The revolting blood", + "moss so gingerly", + "scraped off of", + "windowsills by", + "fastidious housewives", + "is but a tiny cousin to", + "the wilder version,", + "which when properly" + ), + new BookPageInfo + ( + "prepared yields a", + "magical liquid that for", + "a time can make the", + "imbiber a more agile", + "and dextrous", + "individual.", + " However, beware", + "of the deadly" + ), + new BookPageInfo + ( + "nightshade, for it", + "yields a deceptively", + "sweet-tasting poison", + "that can prove highly", + "fatal to the drinker,", + "and in fact is also", + "used by assassins to", + "coat their blades." + ), + new BookPageInfo + ( + "Fortunately, this", + "latter art of poisoning", + "is little known!", + " There is much to", + "reward the student of", + "alchemy, indeed. The", + "rumours of longtime", + "alchemists losing" + ), + new BookPageInfo + ( + "their hair and", + "acquiring an", + "unhealthy pallor, not", + "to mention unsightly", + "blotches upon their", + "once-fair skin, are", + "unhappily, true. Yet", + "the joys of the mind" + ), + new BookPageInfo + ( + "make up for the", + "complete loss of", + "interest that others", + "may have in thee as", + "an object of", + "courtship, and I have", + "never regretted that", + "choice. Honestly," + ), + new BookPageInfo + ( + "truly. Not once." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TreatiseOnAlchemy() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public TreatiseOnAlchemy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Virtue + public class VirtueBook : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Virtue", "Lord British", + new BookPageInfo + ( + " Within this world", + "live people with many", + "different ideals, and", + "this is good. Yet what", + "is it within the people", + "of our land that sorts", + "out the good from the", + "evil, the cherished" + ), + new BookPageInfo + ( + "form the disdained?", + "Virtue, I say it is,", + "and virtue is the", + "logical outcome of a", + "people who wish to", + "live together in a", + "bonded society.", + " For without Virtues" + ), + new BookPageInfo + ( + "as a code of conduct", + "which people maintain", + "in their relations", + "with each other, the", + "fabric of that society", + "will become weakened.", + "For a society to grow", + "and prosper for all," + ), + new BookPageInfo + ( + "each must grant the", + "others a common base", + "of consideration.", + " I call this base the", + "Virtues. For though", + "one person might gain", + "personal advantage by", + "breaching such a" + ), + new BookPageInfo + ( + "code, the society as a", + "whole would suffer.", + " There are three", + "Principle Virtues that", + "should guide people to", + "enlightenment. These", + "are: Truth, Love and", + "Courage. From all the" + ), + new BookPageInfo + ( + "infinite reasons one", + "may have to found an", + "action, such as greed", + "or charity, envy or", + "pity, the three", + "Principle Virtues", + "stand out.", + " In fact all other" + ), + new BookPageInfo + ( + "virtues and vices can", + "be show to be built", + "from these principles", + "and their opposite", + "corruption's of", + "Falsehood, Hatred and", + "Cowardice. These", + "three Principles can" + ), + new BookPageInfo + ( + "be combined in eight", + "ways, which I will", + "call the eight virtues.", + "The eight virtues", + "which we should", + "build our society upon", + "follow.", + " Truth alone becomes" + ), + new BookPageInfo + ( + "Honesty, for without", + "honesty between our", + "people, how can we", + "build the trust which", + "is needed to", + "maximize our", + "successes.", + " Love alone becomes" + ), + new BookPageInfo + ( + "compassion, for at", + "some time or another", + "all of us will need the", + "compassion of others,", + "and most likely", + "compassion will be", + "shown to those who", + "have shown it." + ), + new BookPageInfo + ( + " Courage alone", + "becomes Valor,", + "without valor our", + "people will never", + "reach into the", + "unknown or to the", + "risky and will never", + "achieve." + ), + new BookPageInfo + ( + " Truth tempered by", + "Love give us Justice,", + "for only in a loving", + "search for the truth", + "can one dispense fair", + "Justice, rather than", + "create a cold and", + "callous people." + ), + new BookPageInfo + ( + " Love and Courage", + "give us Sacrifice, for", + "a people who love each", + "other will be willing", + "to make personal", + "sacrifices to help", + "other in need, which", + "one day, may be" + ), + new BookPageInfo + ( + "needed in return.", + " Courage and Truth", + "give us Honor, great", + "knights know this", + "well, that chivalric", + "honor can be found", + "by adhering to this", + "code of conduct." + ), + new BookPageInfo + ( + " Combining Truth,", + "Love and Courage", + "suggest the virtue of", + "Spirituality the virtue", + "that causes one to be", + "introspective, to", + "wonder about ones", + "place in this world" + ), + new BookPageInfo + ( + "and whether one's", + "deeds will be recorded", + "as a gift to the world", + "or a plague.", + " The final Virtue is", + "more complicated. For", + "the eighth combination", + "is that devoid of" + ), + new BookPageInfo + ( + "Truth, Love or", + "Courage which can", + "only exist in a state", + "of great Pride, which", + "of course is not a", + "virtue at all. Perhaps", + "this trick of fate is a", + "test to see if one can" + ), + new BookPageInfo + ( + "realize that the true", + "virtue is that of", + "Humility. I feel that", + "the people of", + "Magincia fail to see", + "this to such a degree", + "that I would not be", + "surprised if some ill" + ), + new BookPageInfo + ( + "fate awaited their", + "future.", + " Thus from the", + "infinite possibilities", + "which spawned the", + "Three Principles of", + "Truth, Love and", + "Courage, come the" + ), + new BookPageInfo + ( + "Eight Virtues of", + "Honesty, Compassion,", + "Valor, Justice,", + "Sacrifice, Honor,", + "Spirituality, and", + "Humility." + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public VirtueBook() : base( Utility.Random( 0xFEF, 2 ), false ) + { + } + + public VirtueBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion +} \ No newline at end of file diff --git a/Scripts/Items/Books/Defined/NewAquariumBook.cs b/Scripts/Items/Books/Defined/NewAquariumBook.cs new file mode 100644 index 0000000..6242c88 --- /dev/null +++ b/Scripts/Items/Books/Defined/NewAquariumBook.cs @@ -0,0 +1,132 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NewAquariumBook : BlueBook + { + public static readonly BookContent Content = new BookContent + ( + "Your New Aquarium", "Les Bilgewater", + new BookPageInfo + ( + "Welcome to the", + "wonderful world", + "of aquarium ownership.", + "With a little time and", + "skill your aquarium can", + "become a work of art!" + ), + new BookPageInfo + ( + "Catching Fish:", + "You will need to", + "aquire a fishing net,", + "and a number of fish", + "bowls, from your local", + "fisherman.", + "To use the net,", + "select it from your" + ), + new BookPageInfo + ( + "backpack, and cast it", + "into shallow water.", + "Then we wait.", + " The fish will be so", + "happy to be in your", + "aquarium, they will", + "jump right into your", + "fish bowl when caught!" + ), + new BookPageInfo + ( + "Just take them home", + "and pour them into", + "your aquarium, and", + "BING! You have a happy", + "new addition to your", + "collection!" + ), + new BookPageInfo + ( + "Caring for our", + "Underwater Allies:", + "", + " Fish need clean", + "water and food to", + "survive.", + " Our aquarium comes", + "with a status monitoring" + ), + new BookPageInfo + ( + "aid. Must be Magic!", + " Just look at the", + "front of your aquarium", + "(mouse over). See the", + "helpful and friendly", + "guide? It tells how much", + "food and water is", + "needed to maintain," + ), + new BookPageInfo + ( + "and improve the quality", + "of your tank.", + " You dont want to", + "overfeed your fish", + "very often. In fact,", + "you only want to feed", + "them every other day.", + "But, remember to keep" + ), + new BookPageInfo + ( + "the water strong and", + "healthy, and add more", + "on a regular basis", + "to keep your aquarium", + "a pretty, sparkely blue.", + "", + " Well, I hope you", + "get as much enjoyment," + ), + new BookPageInfo + ( + "collecting a beautiful", + "array of our fine, finned,", + "friends from the sea,", + "as I do!", + "", + "Happy Fishing!" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public NewAquariumBook() : base( false ) + { + Hue = 0; + } + + public NewAquariumBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Books/Defined/TranslatedGargoyleJournal.cs b/Scripts/Items/Books/Defined/TranslatedGargoyleJournal.cs new file mode 100644 index 0000000..87b01e9 --- /dev/null +++ b/Scripts/Items/Books/Defined/TranslatedGargoyleJournal.cs @@ -0,0 +1,164 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TranslatedGargoyleJournal : BlueBook + { + public static readonly BookContent Content = new BookContent + ( + "Translated Journal", "Velis", + new BookPageInfo + ( + "This text has been", + "translated from a", + "gargoyle's journal", + "following his capture", + "and subsequent", + "reeducation.", + "", + " -Velis" + ), + new BookPageInfo + ( + "I write this in the", + "hopes that someday a", + "soul of pure heart and", + "mind will read it. We", + "are not the evil beings", + "that our cousin", + "gargoyles have made", + "us out to be. We" + ), + new BookPageInfo + ( + "consider them", + "uncivilized and they", + "have no concept of the", + "Principles. To you", + "who reads this, I beg", + "for your help in", + "saving my brethern", + "and preserving my" + ), + new BookPageInfo + ( + "race. We stand at the", + "edge of destruction as", + "does the rest of the", + "world. Once it was", + "written law that we", + "would not allow the", + "knowledge of our", + "civilization to spread" + ), + new BookPageInfo + ( + "into the world, no we", + "are left with little", + "choice...contact the", + "outside world in the hopes", + "of finding help to save", + "it or becoming the", + "unwilling bringers of", + "its damnation." + ), + new BookPageInfo + ( + " I fear my capture is", + "certain, the", + "controllers grow ever", + "closer to my hiding", + "place and I know if", + "they discover me, my", + "fate will be as that of", + "my brothers." + ), + new BookPageInfo + ( + "Although we resisted", + "with all our strength", + "it is now clear that we", + "must have assistance", + "or our people will be", + "gone. And if our", + "oppressor achieves", + "his goals our race will" + ), + new BookPageInfo + ( + "surely be joined buy", + "others.", + " Those of us who", + "have not yet been", + "taken hope to open a", + "path from the outside", + "world into the city.", + "We believe we have" + ), + new BookPageInfo + ( + "found weak areas in", + "the mountains that we", + "can successfully", + "knock through with", + "our limited supplies.", + "We will have to work", + "quickly and the risk", + "of being discovered is" + ), + new BookPageInfo + ( + "great, but no choice", + "remains..." + ), + new BookPageInfo + ( + ), + new BookPageInfo + ( + ), + new BookPageInfo + ( + "Kai Hohiro, 12pm.", + "10.11.2001", + "first one to be here" + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public TranslatedGargoyleJournal() : base( false ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( "Translated Gargoyle Journal" ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, "Translated Gargoyle Journal" ); + } + + public TranslatedGargoyleJournal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/RedBook.cs b/Scripts/Items/Books/RedBook.cs new file mode 100644 index 0000000..d0ee673 --- /dev/null +++ b/Scripts/Items/Books/RedBook.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RedBook : BaseBook + { + [Constructable] + public RedBook() : base( 0xFF1 ) + { + } + + [Constructable] + public RedBook( int pageCount, bool writable ) : base( 0xFF1, pageCount, writable ) + { + } + + [Constructable] + public RedBook( string title, string author, int pageCount, bool writable ) : base( 0xFF1, title, author, pageCount, writable ) + { + } + + // Intended for defined books only + public RedBook( bool writable ) : base( 0xFF1, writable ) + { + } + + public RedBook( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Books/TanBook.cs b/Scripts/Items/Books/TanBook.cs new file mode 100644 index 0000000..40e9d71 --- /dev/null +++ b/Scripts/Items/Books/TanBook.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TanBook : BaseBook + { + [Constructable] + public TanBook() : base( 0xFF0 ) + { + } + + [Constructable] + public TanBook( int pageCount, bool writable ) : base( 0xFF0, pageCount, writable ) + { + } + + [Constructable] + public TanBook( string title, string author, int pageCount, bool writable ) : base( 0xFF0, title, author, pageCount, writable ) + { + } + + // Intended for defined books only + public TanBook( bool writable ) : base( 0xFF0, writable ) + { + } + + public TanBook( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Champion Artifacts/Decorative/ArtifactLargeVase.cs b/Scripts/Items/Champion Artifacts/Decorative/ArtifactLargeVase.cs new file mode 100644 index 0000000..3e58caa --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/ArtifactLargeVase.cs @@ -0,0 +1,32 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class ArtifactLargeVase : Item + { + [Constructable] + public ArtifactLargeVase() : base( 0x0B47 ) + { + } + + public ArtifactLargeVase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/ArtifactVase.cs b/Scripts/Items/Champion Artifacts/Decorative/ArtifactVase.cs new file mode 100644 index 0000000..b1de225 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/ArtifactVase.cs @@ -0,0 +1,32 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class ArtifactVase : Item + { + [Constructable] + public ArtifactVase() : base( 0x0B48 ) + { + } + + public ArtifactVase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/DemonSkull.cs b/Scripts/Items/Champion Artifacts/Decorative/DemonSkull.cs new file mode 100644 index 0000000..ac9e663 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/DemonSkull.cs @@ -0,0 +1,33 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class DemonSkull : Item + { + [Constructable] + public DemonSkull() + : base(0x224e + Utility.Random(4)) + { + } + + public DemonSkull( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/DirtPatch.cs b/Scripts/Items/Champion Artifacts/Decorative/DirtPatch.cs new file mode 100644 index 0000000..81600aa --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/DirtPatch.cs @@ -0,0 +1,32 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class DirtPatch : Item + { + [Constructable] + public DirtPatch(): base(0x0913) + { + } + + public DirtPatch(Serial serial): base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/EvilIdolSkull.cs b/Scripts/Items/Champion Artifacts/Decorative/EvilIdolSkull.cs new file mode 100644 index 0000000..795ec45 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/EvilIdolSkull.cs @@ -0,0 +1,34 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class EvilIdolSkull : Item + { + public override int LabelNumber{ get{ return 1095237; } } // Evil Idol + + [Constructable] + public EvilIdolSkull() : base( 0x1F18 ) + { + } + + public EvilIdolSkull( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/Futon.cs b/Scripts/Items/Champion Artifacts/Decorative/Futon.cs new file mode 100644 index 0000000..b4ff3ca --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/Futon.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class Futon : Item + { + [Constructable] + public Futon() : base( Utility.RandomDouble() > 0.5 ? 0x295C : 0x295E ) + { + } + + public Futon( Serial serial ) : base( serial ) + { + } + + public void Flip() + { + switch ( ItemID ) + { + case 0x295C: ItemID = 0x295D; break; + case 0x295E: ItemID = 0x295F; break; + + case 0x295D: ItemID = 0x295C; break; + case 0x295F: ItemID = 0x295E; break; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/LavaTile.cs b/Scripts/Items/Champion Artifacts/Decorative/LavaTile.cs new file mode 100644 index 0000000..1861575 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/LavaTile.cs @@ -0,0 +1,32 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class LavaTile : Item + { + [Constructable] + public LavaTile() : base( 0x12EE ) + { + } + + public LavaTile( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/Pier.cs b/Scripts/Items/Champion Artifacts/Decorative/Pier.cs new file mode 100644 index 0000000..db954d6 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/Pier.cs @@ -0,0 +1,57 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class Pier : Item + { + /* + * This does not make a lot of sense, being a "Pier" + * and having possible itemids that have nothing + * to do with piers. The three items here are basically + * permutations of the same "drop", or item that + * will be randomly selected when the item drops. + * + * It was either this, or make 2 + * new classes named to reflect that they are rocks + * in water, or put them all in one class. Either + * is kind of senseless, so it is what it is. + * + */ + + private static int[] m_itemids = new int[] + { + 0x3486, 0x348b, 0x3ae + }; + + [Constructable] + public Pier() + : base(m_itemids[Utility.Random(3)]) + { + } + + public Pier(int itemid) + : base(itemid) + { + } + + public Pier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/SkullPole.cs b/Scripts/Items/Champion Artifacts/Decorative/SkullPole.cs new file mode 100644 index 0000000..bcff3fc --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/SkullPole.cs @@ -0,0 +1,33 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class SkullPole : Item + { + [Constructable] + public SkullPole() : base( 0x2204 ) + { + Weight = 5; + } + + public SkullPole( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/SwampTile.cs b/Scripts/Items/Champion Artifacts/Decorative/SwampTile.cs new file mode 100644 index 0000000..34dd0d7 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/SwampTile.cs @@ -0,0 +1,32 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class SwampTile : Item + { + [Constructable] + public SwampTile() : base( 0x320D ) + { + } + + public SwampTile( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/TatteredAncientMummyWrapping.cs b/Scripts/Items/Champion Artifacts/Decorative/TatteredAncientMummyWrapping.cs new file mode 100644 index 0000000..c57de5b --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/TatteredAncientMummyWrapping.cs @@ -0,0 +1,35 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class TatteredAncientMummyWrapping : Item + { + public override int LabelNumber{ get{ return 1094912; } } // Tattered Ancient Mummy Wrapping [Replica] + + [Constructable] + public TatteredAncientMummyWrapping() : base( 0xE21 ) + { + Hue = 0x909; + } + + public TatteredAncientMummyWrapping( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/WallBlood.cs b/Scripts/Items/Champion Artifacts/Decorative/WallBlood.cs new file mode 100644 index 0000000..c4c61d6 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/WallBlood.cs @@ -0,0 +1,33 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class WallBlood : Item + { + [Constructable] + public WallBlood() + : base(Utility.RandomBool() ? 0x1D95 : 0x1D94) + { + } + + public WallBlood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/WaterTile.cs b/Scripts/Items/Champion Artifacts/Decorative/WaterTile.cs new file mode 100644 index 0000000..dfcca1f --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/WaterTile.cs @@ -0,0 +1,32 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class WaterTile : Item + { + [Constructable] + public WaterTile() : base( 0x346E ) + { + } + + public WaterTile( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/Web.cs b/Scripts/Items/Champion Artifacts/Decorative/Web.cs new file mode 100644 index 0000000..18f4540 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/Web.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Web : Item + { + private static int[] m_itemids = new int[] + { + 0x10d7, 0x10d8, 0x10dd + }; + + [Constructable] + public Web() + : base(m_itemids[Utility.Random(3)]) + { + } + + [Constructable] + public Web(int itemid) + : base(itemid) + { + } + + public Web( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Decorative/WindSpirit.cs b/Scripts/Items/Champion Artifacts/Decorative/WindSpirit.cs new file mode 100644 index 0000000..8822969 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Decorative/WindSpirit.cs @@ -0,0 +1,34 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class WindSpirit : Item + { + public override int LabelNumber{ get{ return 1094925; } } // Wind Spirit [Replica] + + [Constructable] + public WindSpirit() : base( 0x1F1F ) + { + } + + public WindSpirit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/ANecromancerShroud.cs b/Scripts/Items/Champion Artifacts/Shared/ANecromancerShroud.cs new file mode 100644 index 0000000..3e444fe --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/ANecromancerShroud.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ANecromancerShroud : Robe + { + public override int LabelNumber{ get{ return 1094913; } } // A Necromancer Shroud [Replica] + + public override int BaseColdResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public ANecromancerShroud() + { + Hue = 0x455; + } + + public ANecromancerShroud( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/BraveKnightOfTheBritannia.cs b/Scripts/Items/Champion Artifacts/Shared/BraveKnightOfTheBritannia.cs new file mode 100644 index 0000000..6ac5d49 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/BraveKnightOfTheBritannia.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BraveKnightOfTheBritannia : Katana + { + public override int LabelNumber{ get{ return 1094909; } } // Brave Knight of The Britannia [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public BraveKnightOfTheBritannia() + { + Hue = 0x47e; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 35; + + WeaponAttributes.HitLeechStam = 48; + WeaponAttributes.HitHarm = 26; + WeaponAttributes.HitLeechHits = 22; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = chaos = direct = 0; + fire = 40; + cold = 30; + pois = 10; + nrgy = 20; + } + + public BraveKnightOfTheBritannia( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/CaptainJohnsHat.cs b/Scripts/Items/Champion Artifacts/Shared/CaptainJohnsHat.cs new file mode 100644 index 0000000..c296b94 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/CaptainJohnsHat.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CaptainJohnsHat : TricorneHat + { + public override int LabelNumber{ get{ return 1094911; } } // Captain John's Hat [Replica] + + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 7; } } + public override int BaseEnergyResistance{ get{ return 23; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public CaptainJohnsHat() + { + Hue = 0x455; + + Attributes.BonusDex = 8; + Attributes.NightSight = 1; + Attributes.AttackChance = 15; + + SkillBonuses.Skill_1_Name = SkillName.Swords; + SkillBonuses.Skill_1_Value = 20; + } + + public CaptainJohnsHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/DetectiveBoots.cs b/Scripts/Items/Champion Artifacts/Shared/DetectiveBoots.cs new file mode 100644 index 0000000..d30f5a9 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/DetectiveBoots.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DetectiveBoots : Boots + { + public override int LabelNumber{ get{ return 1094894 + m_Level; } } // [Quality] Detective of the Royal Guard [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + private int m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public int Level + { + get{ return m_Level; } + set{ m_Level = Math.Max( Math.Min( 2, value), 0 ); Attributes.BonusInt = 2 + m_Level; InvalidateProperties(); } + } + + [Constructable] + public DetectiveBoots() + { + Hue = 0x455; + Level = Utility.RandomMinMax( 0, 2 ); + } + + public DetectiveBoots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Level = Attributes.BonusInt - 2; + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/DjinnisRing.cs b/Scripts/Items/Champion Artifacts/Shared/DjinnisRing.cs new file mode 100644 index 0000000..5a81edf --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/DjinnisRing.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DjinnisRing : SilverRing + { + public override int LabelNumber{ get{ return 1094927; } } // Djinni's Ring [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + [Constructable] + public DjinnisRing() + { + Attributes.BonusInt = 5; + Attributes.SpellDamage = 10; + Attributes.CastSpeed = 2; + } + + public DjinnisRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/EmbroideredOakLeafCloak.cs b/Scripts/Items/Champion Artifacts/Shared/EmbroideredOakLeafCloak.cs new file mode 100644 index 0000000..8d9f2d4 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/EmbroideredOakLeafCloak.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class EmbroideredOakLeafCloak : BaseOuterTorso + { + public override int LabelNumber{ get{ return 1094901; } } // Embroidered Oak Leaf Cloak [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public EmbroideredOakLeafCloak() : base( 0x2684 ) + { + Hue = 0x483; + StrRequirement = 0; + + SkillBonuses.Skill_1_Name = SkillName.Stealth; + SkillBonuses.Skill_1_Value = 5; + } + + public EmbroideredOakLeafCloak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/GuantletsOfAnger.cs b/Scripts/Items/Champion Artifacts/Shared/GuantletsOfAnger.cs new file mode 100644 index 0000000..e6764bc --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/GuantletsOfAnger.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GuantletsOfAnger : PlateGloves + { + public override int LabelNumber{ get{ return 1094902; } } // Gauntlets of Anger [Replica] + + public override int BasePhysicalResistance{ get{ return 4; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 6; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public GuantletsOfAnger() + { + Hue = 0x29b; + + Attributes.BonusHits = 8; + Attributes.RegenHits = 2; + Attributes.DefendChance = 10; + } + + public GuantletsOfAnger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/LieutenantOfTheBritannianRoyalGuard.cs b/Scripts/Items/Champion Artifacts/Shared/LieutenantOfTheBritannianRoyalGuard.cs new file mode 100644 index 0000000..0ec3287 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/LieutenantOfTheBritannianRoyalGuard.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LieutenantOfTheBritannianRoyalGuard : BodySash + { + public override int LabelNumber{ get{ return 1094910; } } // Lieutenant of the Britannian Royal Guard [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public LieutenantOfTheBritannianRoyalGuard() + { + Hue = 0xe8; + + Attributes.BonusInt = 5; + Attributes.RegenMana = 2; + Attributes.LowerRegCost = 10; + } + + public LieutenantOfTheBritannianRoyalGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/OblivionsNeedle.cs b/Scripts/Items/Champion Artifacts/Shared/OblivionsNeedle.cs new file mode 100644 index 0000000..bbc35aa --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/OblivionsNeedle.cs @@ -0,0 +1,44 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OblivionsNeedle : Dagger + { + public override int LabelNumber{ get{ return 1094916; } } // Oblivion's Needle [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public OblivionsNeedle() + { + Attributes.BonusStam = 20; + Attributes.AttackChance = 20; + Attributes.DefendChance = -20; + Attributes.WeaponDamage = 40; + + WeaponAttributes.HitLeechStam = 50; + } + + public OblivionsNeedle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/RoyalGuardSurvivalKnife.cs b/Scripts/Items/Champion Artifacts/Shared/RoyalGuardSurvivalKnife.cs new file mode 100644 index 0000000..f5a53af --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/RoyalGuardSurvivalKnife.cs @@ -0,0 +1,44 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RoyalGuardSurvivalKnife : SkinningKnife + { + public override int LabelNumber{ get{ return 1094918; } } // Royal Guard Survival Knife [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public RoyalGuardSurvivalKnife() + { + Attributes.SpellChanneling = 1; + Attributes.Luck = 140; + Attributes.EnhancePotions = 25; + + WeaponAttributes.UseBestSkill = 1; + WeaponAttributes.LowerStatReq = 50; + } + + public RoyalGuardSurvivalKnife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/SamaritanRobe.cs b/Scripts/Items/Champion Artifacts/Shared/SamaritanRobe.cs new file mode 100644 index 0000000..c3e935c --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/SamaritanRobe.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SamaritanRobe : Robe + { + public override int LabelNumber{ get{ return 1094926; } } // Good Samaritan of Britannia [Replica] + + public override int BasePhysicalResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public SamaritanRobe() + { + Hue = 0x2a3; + } + + public SamaritanRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/TheMostKnowledgePerson.cs b/Scripts/Items/Champion Artifacts/Shared/TheMostKnowledgePerson.cs new file mode 100644 index 0000000..f86ed04 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/TheMostKnowledgePerson.cs @@ -0,0 +1,44 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheMostKnowledgePerson : BaseOuterTorso + { + public override int LabelNumber{ get{ return 1094893; } } // The Most Knowledge Person [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + public override bool CanBeBlessed{ get{ return false; } } + + [Constructable] + public TheMostKnowledgePerson() : base( 0x2684 ) + { + Hue = 0x117; + StrRequirement = 0; + + Attributes.BonusHits = 3 + Utility.RandomMinMax( 0, 2 ); + } + + public TheMostKnowledgePerson( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Shared/TheRobeOfBritanniaAri.cs b/Scripts/Items/Champion Artifacts/Shared/TheRobeOfBritanniaAri.cs new file mode 100644 index 0000000..4e945a9 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Shared/TheRobeOfBritanniaAri.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheRobeOfBritanniaAri : BaseOuterTorso + { + public override int LabelNumber{ get{ return 1094931; } } // The Robe of Britannia "Ari" [Replica] + + public override int BasePhysicalResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public TheRobeOfBritanniaAri() : base( 0x2684 ) + { + Hue = 0x48b; + StrRequirement = 0; + } + + public TheRobeOfBritanniaAri( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/AcidProofRobe.cs b/Scripts/Items/Champion Artifacts/Unique/AcidProofRobe.cs new file mode 100644 index 0000000..a821c19 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/AcidProofRobe.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AcidProofRobe : Robe + { + public override int LabelNumber{ get{ return 1095236; } } // Acid-Proof Robe [Replica] + + public override int BaseFireResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public AcidProofRobe() + { + Hue = 0x455; + LootType = LootType.Blessed; + } + + public AcidProofRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1 && Hue == 1) + { + Hue = 0x455; + } + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/Calm.cs b/Scripts/Items/Champion Artifacts/Unique/Calm.cs new file mode 100644 index 0000000..7740697 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/Calm.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Calm : Halberd + { + public override int LabelNumber{ get{ return 1094915; } } // Calm [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public Calm() + { + Hue = 0x2cb; + + Attributes.SpellChanneling = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 50; + + WeaponAttributes.HitLeechMana = 100; + WeaponAttributes.UseBestSkill = 1; + } + + public Calm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/CrownOfTalKeesh.cs b/Scripts/Items/Champion Artifacts/Unique/CrownOfTalKeesh.cs new file mode 100644 index 0000000..a22d5f7 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/CrownOfTalKeesh.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CrownOfTalKeesh : Bandana + { + public override int LabelNumber{ get{ return 1094903; } } // Crown of Tal'Keesh [Replica] + + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 20; } } + public override int BaseEnergyResistance{ get{ return 20; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public CrownOfTalKeesh() + { + Hue = 0x4F2; + + Attributes.BonusInt = 8; + Attributes.RegenMana = 4; + Attributes.SpellDamage = 10; + } + + public CrownOfTalKeesh( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/FangOfRactus.cs b/Scripts/Items/Champion Artifacts/Unique/FangOfRactus.cs new file mode 100644 index 0000000..a40edb4 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/FangOfRactus.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class FangOfRactus : Kryss + { + public override int LabelNumber{ get{ return 1094892; } } // Fang of Ractus [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public FangOfRactus() + { + Hue = 0x117; + + Attributes.SpellChanneling = 1; + Attributes.AttackChance = 5; + Attributes.DefendChance = 5; + Attributes.WeaponDamage = 35; + + WeaponAttributes.HitPoisonArea = 20; + WeaponAttributes.ResistPoisonBonus = 15; + } + + public FangOfRactus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/GladiatorsCollar.cs b/Scripts/Items/Champion Artifacts/Unique/GladiatorsCollar.cs new file mode 100644 index 0000000..8e8789b --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/GladiatorsCollar.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GladiatorsCollar : PlateGorget + { + public override int LabelNumber{ get{ return 1094917; } } // Gladiator's Collar [Replica] + + public override int BasePhysicalResistance{ get{ return 18; } } + public override int BaseFireResistance{ get{ return 18; } } + public override int BaseColdResistance{ get{ return 17; } } + public override int BasePoisonResistance{ get{ return 18; } } + public override int BaseEnergyResistance{ get{ return 16; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public GladiatorsCollar() + { + Hue = 0x26d; + + Attributes.BonusHits = 10; + Attributes.AttackChance = 10; + + ArmorAttributes.MageArmor = 1; + } + + public GladiatorsCollar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/OrcChieftainHelm.cs b/Scripts/Items/Champion Artifacts/Unique/OrcChieftainHelm.cs new file mode 100644 index 0000000..343c7c9 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/OrcChieftainHelm.cs @@ -0,0 +1,57 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrcChieftainHelm : OrcHelm + { + public override int LabelNumber{ get{ return 1094924; } } // Orc Chieftain Helm [Replica] + + public override int BasePhysicalResistance{ get{ return 23; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 23; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public OrcChieftainHelm() + { + Hue = 0x2a3; + + Attributes.Luck = 100; + Attributes.RegenHits = 3; + + if( Utility.RandomBool() ) + Attributes.BonusHits = 30; + else + Attributes.AttackChance = 30; + } + + public OrcChieftainHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1 && Hue == 0x3f) /* Pigmented? */ + { + Hue = 0x2a3; + } + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/Pacify.cs b/Scripts/Items/Champion Artifacts/Unique/Pacify.cs new file mode 100644 index 0000000..a7f7b76 --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/Pacify.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Pacify : Pike + { + public override int LabelNumber{ get{ return 1094929; } } // Pacify [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public Pacify() + { + Hue = 0x835; + + Attributes.SpellChanneling = 1; + Attributes.AttackChance = 10; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 50; + + WeaponAttributes.HitLeechMana = 100; + WeaponAttributes.UseBestSkill = 1; + } + + public Pacify( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/Quell.cs b/Scripts/Items/Champion Artifacts/Unique/Quell.cs new file mode 100644 index 0000000..593cdff --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/Quell.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Quell : Bardiche + { + public override int LabelNumber{ get{ return 1094928; } } // Quell [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public Quell() + { + Hue = 0x225; + + Attributes.SpellChanneling = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 50; + Attributes.AttackChance = 10; + + WeaponAttributes.HitLeechMana = 100; + WeaponAttributes.UseBestSkill = 1; + } + + public Quell( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/ShroudOfDeceit.cs b/Scripts/Items/Champion Artifacts/Unique/ShroudOfDeceit.cs new file mode 100644 index 0000000..9eba1ed --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/ShroudOfDeceit.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShroudOfDeciet : BoneChest + { + public override int LabelNumber{ get{ return 1094914; } } // Shroud of Deceit [Replica] + + public override int BasePhysicalResistance{ get{ return 11; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 18; } } + public override int BasePoisonResistance{ get{ return 15; } } + public override int BaseEnergyResistance{ get{ return 13; } } + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public ShroudOfDeciet() + { + Hue = 0x38F; + + Attributes.RegenHits = 3; + + ArmorAttributes.MageArmor = 1; + + SkillBonuses.Skill_1_Name = SkillName.MagicResist; + SkillBonuses.Skill_1_Value = 10; + } + + public ShroudOfDeciet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Champion Artifacts/Unique/Subdue.cs b/Scripts/Items/Champion Artifacts/Unique/Subdue.cs new file mode 100644 index 0000000..0e2f2fd --- /dev/null +++ b/Scripts/Items/Champion Artifacts/Unique/Subdue.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Subdue : Scythe + { + public override int LabelNumber{ get{ return 1094930; } } // Subdue [Replica] + + public override int InitMinHits{ get{ return 150; } } + public override int InitMaxHits{ get{ return 150; } } + + public override bool CanFortify{ get{ return false; } } + + [Constructable] + public Subdue() + { + Hue = 0x2cb; + Attributes.SpellChanneling = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 50; + Attributes.AttackChance = 10; + + WeaponAttributes.HitLeechMana = 100; + WeaponAttributes.UseBestSkill = 1; + } + + public Subdue( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Clothing/Artifacts/CrimsonCincture.cs b/Scripts/Items/Clothing/Artifacts/CrimsonCincture.cs new file mode 100644 index 0000000..d2b4bdc --- /dev/null +++ b/Scripts/Items/Clothing/Artifacts/CrimsonCincture.cs @@ -0,0 +1,38 @@ +using System; + +namespace Server.Items +{ + public class CrimsonCincture : HalfApron, ITokunoDyable + { + public override int LabelNumber{ get{ return 1075043; } } // Crimson Cincture + + [Constructable] + public CrimsonCincture() : base() + { + Hue = 0x485; + + Attributes.BonusDex = 5; + Attributes.BonusHits = 10; + Attributes.RegenHits = 2; + } + + public CrimsonCincture( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Clothing/Artifacts/DivineCountenance.cs b/Scripts/Items/Clothing/Artifacts/DivineCountenance.cs new file mode 100644 index 0000000..9e876d0 --- /dev/null +++ b/Scripts/Items/Clothing/Artifacts/DivineCountenance.cs @@ -0,0 +1,61 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DivineCountenance : HornedTribalMask + { + public override int LabelNumber{ get{ return 1061289; } } // Divine Countenance + + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 8; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BaseEnergyResistance{ get{ return 25; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public DivineCountenance() + { + Hue = 0x482; + + Attributes.BonusInt = 8; + Attributes.RegenMana = 2; + Attributes.ReflectPhysical = 15; + Attributes.LowerManaCost = 8; + } + + public DivineCountenance( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Resistances.Physical = 0; + Resistances.Fire = 0; + Resistances.Cold = 0; + Resistances.Energy = 0; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Artifacts/HatOfTheMagi.cs b/Scripts/Items/Clothing/Artifacts/HatOfTheMagi.cs new file mode 100644 index 0000000..a2b0f02 --- /dev/null +++ b/Scripts/Items/Clothing/Artifacts/HatOfTheMagi.cs @@ -0,0 +1,56 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HatOfTheMagi : WizardsHat + { + public override int LabelNumber{ get{ return 1061597; } } // Hat of the Magi + + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePoisonResistance{ get{ return 20; } } + public override int BaseEnergyResistance{ get{ return 20; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HatOfTheMagi() + { + Hue = 0x481; + + Attributes.BonusInt = 8; + Attributes.RegenMana = 4; + Attributes.SpellDamage = 10; + } + + public HatOfTheMagi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Resistances.Poison = 0; + Resistances.Energy = 0; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Artifacts/HuntersHeaddress.cs b/Scripts/Items/Clothing/Artifacts/HuntersHeaddress.cs new file mode 100644 index 0000000..d3939fa --- /dev/null +++ b/Scripts/Items/Clothing/Artifacts/HuntersHeaddress.cs @@ -0,0 +1,56 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HuntersHeaddress : DeerMask + { + public override int LabelNumber{ get{ return 1061595; } } // Hunter's Headdress + + public override int ArtifactRarity{ get{ return 11; } } + + public override int BaseColdResistance{ get{ return 23; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HuntersHeaddress() + { + Hue = 0x594; + + SkillBonuses.SetValues( 0, SkillName.Archery, 20 ); + + Attributes.BonusDex = 8; + Attributes.NightSight = 1; + Attributes.AttackChance = 15; + + } + + public HuntersHeaddress( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch ( version ) + { + case 0: + { + Resistances.Cold = 0; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Artifacts/SpiritOfTheTotem.cs b/Scripts/Items/Clothing/Artifacts/SpiritOfTheTotem.cs new file mode 100644 index 0000000..e9b1830 --- /dev/null +++ b/Scripts/Items/Clothing/Artifacts/SpiritOfTheTotem.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpiritOfTheTotem : BearMask + { + public override int LabelNumber{ get{ return 1061599; } } // Spirit of the Totem + + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 20; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public SpiritOfTheTotem() + { + Hue = 0x455; + + Attributes.BonusStr = 20; + Attributes.ReflectPhysical = 15; + Attributes.AttackChance = 15; + } + + public SpiritOfTheTotem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Resistances.Physical = 0; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/BaseClothing.cs b/Scripts/Items/Clothing/BaseClothing.cs new file mode 100644 index 0000000..d1d0d5f --- /dev/null +++ b/Scripts/Items/Clothing/BaseClothing.cs @@ -0,0 +1,1185 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.Craft; +using Server.Factions; +using Server.Network; + +namespace Server.Items +{ + public enum ClothingQuality + { + Low, + Regular, + Exceptional + } + + public interface IArcaneEquip + { + bool IsArcane{ get; } + int CurArcaneCharges{ get; set; } + int MaxArcaneCharges{ get; set; } + } + + public abstract class BaseClothing : BaseWearable, IDyable, IScissorable, IFactionItem, ICraftable, IWearableDurability + { + #region Factions + private FactionItem m_FactionState; + + public FactionItem FactionItemState + { + get{ return m_FactionState; } + set + { + m_FactionState = value; + + if ( m_FactionState == null ) + Hue = 0; + + LootType = ( m_FactionState == null ? LootType.Regular : LootType.Blessed ); + } + } + #endregion + + public virtual bool CanFortify{ get{ return true; } } + + private int m_MaxHitPoints; + private int m_HitPoints; + private Mobile m_Crafter; + private ClothingQuality m_Quality; + private bool m_PlayerConstructed; + private bool m_Identified; + protected CraftResource m_Resource; + private int m_StrReq = -1; + + private AosAttributes m_AosAttributes; + private AosArmorAttributes m_AosClothingAttributes; + private AosSkillBonuses m_AosSkillBonuses; + private AosElementAttributes m_AosResistances; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxHitPoints + { + get{ return m_MaxHitPoints; } + set{ m_MaxHitPoints = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitPoints + { + get + { + return m_HitPoints; + } + set + { + if ( value != m_HitPoints && MaxHitPoints > 0 ) + { + m_HitPoints = value; + + if ( m_HitPoints < 0 ) + Delete(); + else if ( m_HitPoints > MaxHitPoints ) + m_HitPoints = MaxHitPoints; + + InvalidateProperties(); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int StrRequirement + { + get{ return ( m_StrReq == -1 ? (Core.AOS ? AosStrReq : OldStrReq) : m_StrReq ); } + set{ m_StrReq = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ClothingQuality Quality + { + get{ return m_Quality; } + set{ m_Quality = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Identified + { + get { return m_Identified; } + set { m_Identified = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool PlayerConstructed + { + get{ return m_PlayerConstructed; } + set{ m_PlayerConstructed = value; } + } + + public virtual CraftResource DefaultResource{ get{ return CraftResource.None; } } + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get{ return m_Resource; } + set{ m_Resource = value; Hue = CraftResources.GetHue( m_Resource ); InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosAttributes Attributes + { + get{ return m_AosAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosArmorAttributes ClothingAttributes + { + get{ return m_AosClothingAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosSkillBonuses SkillBonuses + { + get{ return m_AosSkillBonuses; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosElementAttributes Resistances + { + get{ return m_AosResistances; } + set{} + } + + //Plume ajout de la difficult� + [CommandProperty(AccessLevel.GameMaster)] + public int ClothingDifficulty + { + get + { + int difficulty = 0; + + if (Attributes.AttackChance != 0) + difficulty++; + if (Attributes.BonusDex != 0) + difficulty++; + if (Attributes.BonusHits != 0) + difficulty++; + if (Attributes.BonusInt != 0) + difficulty++; + if (Attributes.BonusMana != 0) + difficulty++; + if (Attributes.BonusStam != 0) + difficulty++; + if (Attributes.BonusStr != 0) + difficulty++; + if (Attributes.CastRecovery != 0) + difficulty++; + if (Attributes.CastSpeed != 0) + difficulty++; + if (Attributes.DefendChance != 0) + difficulty++; + if (Attributes.EnhancePotions != 0) + difficulty++; + if (Attributes.LowerManaCost != 0) + difficulty++; + if (Attributes.LowerRegCost != 0) + difficulty++; + if (Attributes.Luck != 0) + difficulty++; + if (Attributes.NightSight != 0) + difficulty++; + if (Attributes.ReflectPhysical != 0) + difficulty++; + if (Attributes.RegenHits != 0) + difficulty++; + if (Attributes.RegenMana != 0) + difficulty++; + if (Attributes.RegenStam != 0) + difficulty++; + if (Attributes.SpellChanneling != 0) + difficulty++; + if (Attributes.SpellDamage != 0) + difficulty++; + if (Attributes.WeaponDamage != 0) + difficulty++; + if (Attributes.WeaponSpeed != 0) + difficulty++; + if (ClothingAttributes.DurabilityBonus != 0) + difficulty++; + if (ClothingAttributes.LowerStatReq != 0) + difficulty++; + if (ClothingAttributes.MageArmor != 0) + difficulty++; + if (ClothingAttributes.SelfRepair != 0) + difficulty++; + if (SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (SkillBonuses.Skill_5_Value != 0) + difficulty++; + if (!(this is BaseHat)) + { + if (Resistances.Chaos != 0) + difficulty++; + if (Resistances.Cold != 0) + difficulty++; + if (Resistances.Direct != 0) + difficulty++; + if (Resistances.Energy != 0) + difficulty++; + if (Resistances.Fire != 0) + difficulty++; + if (Resistances.Physical != 0) + difficulty++; + if (Resistances.Poison != 0) + difficulty++; + } + + if (difficulty > 5) + difficulty = 5; + + return difficulty; + } + } + + public virtual int BasePhysicalResistance{ get{ return 0; } } + public virtual int BaseFireResistance{ get{ return 0; } } + public virtual int BaseColdResistance{ get{ return 0; } } + public virtual int BasePoisonResistance{ get{ return 0; } } + public virtual int BaseEnergyResistance{ get{ return 0; } } + + public override int PhysicalResistance{ get{ return BasePhysicalResistance + m_AosResistances.Physical; } } + public override int FireResistance{ get{ return BaseFireResistance + m_AosResistances.Fire; } } + public override int ColdResistance{ get{ return BaseColdResistance + m_AosResistances.Cold; } } + public override int PoisonResistance{ get{ return BasePoisonResistance + m_AosResistances.Poison; } } + public override int EnergyResistance{ get{ return BaseEnergyResistance + m_AosResistances.Energy; } } + + public virtual int ArtifactRarity{ get{ return 0; } } + + public virtual int BaseStrBonus{ get{ return 0; } } + public virtual int BaseDexBonus{ get{ return 0; } } + public virtual int BaseIntBonus{ get{ return 0; } } + + public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if ( !Ethics.Ethic.CheckTrade( from, to, newOwner, this ) ) + return false; + + return base.AllowSecureTrade( from, to, newOwner, accepted ); + } + + public virtual Race RequiredRace { get { return null; } } + + public override bool CanEquip( Mobile from ) + { + if ( !Ethics.Ethic.CheckEquip( from, this ) ) + return false; + + if( from.AccessLevel < AccessLevel.GameMaster ) + { + if( RequiredRace != null && from.Race != RequiredRace ) + { + if( RequiredRace == Race.Elf ) + from.SendLocalizedMessage( 1072203 ); // Only Elves may use this. + else + from.SendMessage( "Only {0} may use this.", RequiredRace.PluralName ); + + return false; + } + else if( !AllowMaleWearer && !from.Female ) + { + if( AllowFemaleWearer ) + from.SendLocalizedMessage( 1010388 ); // Only females can wear this. + else + from.SendMessage( "You may not wear this." ); + + return false; + } + else if( !AllowFemaleWearer && from.Female ) + { + if( AllowMaleWearer ) + from.SendLocalizedMessage( 1063343 ); // Only males can wear this. + else + from.SendMessage( "You may not wear this." ); + + return false; + } + else if (!m_Identified) + { + from.SendMessage("Ce v�tement vous semble inconnu"); + return false; + } + else + { + int strBonus = ComputeStatBonus( StatType.Str ); + int strReq = ComputeStatReq( StatType.Str ); + + if( from.Str < strReq || (from.Str + strBonus) < 1 ) + { + from.SendLocalizedMessage( 500213 ); // You are not strong enough to equip that. + return false; + } + } + + } + + return base.CanEquip( from ); + } + + public virtual int AosStrReq{ get{ return 10; } } + public virtual int OldStrReq{ get{ return 0; } } + + public virtual int InitMinHits{ get{ return 0; } } + public virtual int InitMaxHits{ get{ return 0; } } + + public virtual bool AllowMaleWearer{ get{ return true; } } + public virtual bool AllowFemaleWearer{ get{ return true; } } + public virtual bool CanBeBlessed{ get{ return true; } } + + public int ComputeStatReq( StatType type ) + { + int v; + + //if ( type == StatType.Str ) + v = StrRequirement; + + return AOS.Scale( v, 100 - GetLowerStatReq() ); + } + + public int ComputeStatBonus( StatType type ) + { + if ( type == StatType.Str ) + return BaseStrBonus + Attributes.BonusStr; + else if ( type == StatType.Dex ) + return BaseDexBonus + Attributes.BonusDex; + else + return BaseIntBonus + Attributes.BonusInt; + } + + public virtual void AddStatBonuses( Mobile parent ) + { + if ( parent == null ) + return; + + int strBonus = ComputeStatBonus( StatType.Str ); + int dexBonus = ComputeStatBonus( StatType.Dex ); + int intBonus = ComputeStatBonus( StatType.Int ); + + if ( strBonus == 0 && dexBonus == 0 && intBonus == 0 ) + return; + + string modName = this.Serial.ToString(); + + if ( strBonus != 0 ) + parent.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + parent.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + parent.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + public static void ValidateMobile( Mobile m ) + { + for ( int i = m.Items.Count - 1; i >= 0; --i ) + { + if ( i >= m.Items.Count ) + continue; + + Item item = m.Items[i]; + + if ( item is BaseClothing ) + { + BaseClothing clothing = (BaseClothing)item; + + if( clothing.RequiredRace != null && m.Race != clothing.RequiredRace ) + { + if( clothing.RequiredRace == Race.Elf ) + m.SendLocalizedMessage( 1072203 ); // Only Elves may use this. + else + m.SendMessage( "Only {0} may use this.", clothing.RequiredRace.PluralName ); + + m.AddToBackpack( clothing ); + } + else if ( !clothing.AllowMaleWearer && !m.Female && m.AccessLevel < AccessLevel.GameMaster ) + { + if ( clothing.AllowFemaleWearer ) + m.SendLocalizedMessage( 1010388 ); // Only females can wear this. + else + m.SendMessage( "You may not wear this." ); + + m.AddToBackpack( clothing ); + } + else if ( !clothing.AllowFemaleWearer && m.Female && m.AccessLevel < AccessLevel.GameMaster ) + { + if ( clothing.AllowMaleWearer ) + m.SendLocalizedMessage( 1063343 ); // Only males can wear this. + else + m.SendMessage( "You may not wear this." ); + + m.AddToBackpack( clothing ); + } + } + } + } + + public int GetLowerStatReq() + { + if ( !Core.AOS ) + return 0; + + return m_AosClothingAttributes.LowerStatReq; + } + + public override void OnAdded( object parent ) + { + Mobile mob = parent as Mobile; + + if ( mob != null ) + { + if ( Core.AOS ) + m_AosSkillBonuses.AddTo( mob ); + + AddStatBonuses( mob ); + mob.CheckStatTimers(); + } + + base.OnAdded( parent ); + } + + public override void OnRemoved( object parent ) + { + Mobile mob = parent as Mobile; + + if ( mob != null ) + { + if ( Core.AOS ) + m_AosSkillBonuses.Remove(); + + string modName = this.Serial.ToString(); + + mob.RemoveStatMod( modName + "Str" ); + mob.RemoveStatMod( modName + "Dex" ); + mob.RemoveStatMod( modName + "Int" ); + + mob.CheckStatTimers(); + } + + base.OnRemoved( parent ); + } + + public virtual int OnHit( BaseWeapon weapon, int damageTaken ) + { + int Absorbed = Utility.RandomMinMax( 1, 4 ); + + damageTaken -= Absorbed; + + if ( damageTaken < 0 ) + damageTaken = 0; + + if ( 25 > Utility.Random( 100 ) ) // 25% chance to lower durability + { + if ( Core.AOS && m_AosClothingAttributes.SelfRepair > Utility.Random( 10 ) ) + { + HitPoints += 2; + } + else + { + int wear; + + if ( weapon.Type == WeaponType.Bashing ) + wear = Absorbed / 2; + else + wear = Utility.Random( 2 ); + + if ( wear > 0 && m_MaxHitPoints > 0 ) + { + if ( m_HitPoints >= wear ) + { + HitPoints -= wear; + wear = 0; + } + else + { + wear -= HitPoints; + HitPoints = 0; + } + + if ( wear > 0 ) + { + if ( m_MaxHitPoints > wear ) + { + MaxHitPoints -= wear; + + if ( Parent is Mobile ) + ((Mobile)Parent).LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061121 ); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + } + } + + return damageTaken; + } + + public BaseClothing( int itemID, Layer layer ) : this( itemID, layer, 0 ) + { + } + + public BaseClothing( int itemID, Layer layer, int hue ) : base( itemID ) + { + Layer = layer; + Hue = hue; + + m_Resource = DefaultResource; + m_Quality = ClothingQuality.Regular; + + m_HitPoints = m_MaxHitPoints = Utility.RandomMinMax( InitMinHits, InitMaxHits ); + m_Identified = true; + m_AosAttributes = new AosAttributes( this ); + m_AosClothingAttributes = new AosArmorAttributes( this ); + m_AosSkillBonuses = new AosSkillBonuses( this ); + m_AosResistances = new AosElementAttributes( this ); + } + + public override void OnAfterDuped( Item newItem ) + { + BaseClothing clothing = newItem as BaseClothing; + + if ( clothing == null ) + return; + + clothing.m_AosAttributes = new AosAttributes( newItem, m_AosAttributes ); + clothing.m_AosResistances = new AosElementAttributes( newItem, m_AosResistances ); + clothing.m_AosSkillBonuses = new AosSkillBonuses( newItem, m_AosSkillBonuses ); + clothing.m_AosClothingAttributes = new AosArmorAttributes( newItem, m_AosClothingAttributes ); + } + + public BaseClothing( Serial serial ) : base( serial ) + { + } + + public override bool AllowEquipedCast( Mobile from ) + { + if ( base.AllowEquipedCast( from ) ) + return true; + + return ( m_AosAttributes.SpellChanneling != 0 ); + } + + public void UnscaleDurability() + { + int scale = 100 + m_AosClothingAttributes.DurabilityBonus; + + m_HitPoints = ( ( m_HitPoints * 100 ) + ( scale - 1 ) ) / scale; + m_MaxHitPoints = ( ( m_MaxHitPoints * 100 ) + ( scale - 1 ) ) / scale; + + InvalidateProperties(); + } + + public void ScaleDurability() + { + int scale = 100 + m_AosClothingAttributes.DurabilityBonus; + + m_HitPoints = ( ( m_HitPoints * scale ) + 99 ) / 100; + m_MaxHitPoints = ( ( m_MaxHitPoints * scale ) + 99 ) / 100; + + InvalidateProperties(); + } + + public override bool CheckPropertyConfliction( Mobile m ) + { + if ( base.CheckPropertyConfliction( m ) ) + return true; + + if ( Layer == Layer.Pants ) + return ( m.FindItemOnLayer( Layer.InnerLegs ) != null ); + + if ( Layer == Layer.Shirt ) + return ( m.FindItemOnLayer( Layer.InnerTorso ) != null ); + + return false; + } + + private string GetNameString() + { + string name = this.Name; + + if ( name == null ) + name = String.Format( "#{0}", LabelNumber ); + + return name; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + string oreType; + + switch ( m_Resource ) + { + case CraftResource.MBronze: oreType = "Bronze"; break; // dull copper + case CraftResource.MGold: oreType = "Or"; break; // shadow iron + case CraftResource.MCopper: oreType = "Cuivre"; break; // copper + case CraftResource.MOldcopper: oreType = "Vieux cuivre"; break; // bronze + case CraftResource.MDullcopper: oreType = "Cuivre terni"; break; // golden + case CraftResource.MSilver: oreType = "Silver"; break; // agapite + case CraftResource.MShadow: oreType = "Sombrine"; break; // verite + case CraftResource.MBloodrock: oreType = "Pierre de sang"; break; // valorite + case CraftResource.MBlackrock: oreType = "Pierre noire"; break; // dull copper + case CraftResource.MMytheril: oreType = "Mytheril"; break; // shadow iron + case CraftResource.MRose: oreType = "Rose"; break; // copper + case CraftResource.MVerite: oreType = "Verite"; break; // bronze + case CraftResource.MAgapite: oreType = "Agapite"; break; // golden + case CraftResource.MRusty: oreType = "Rouille"; break; // agapite + case CraftResource.MValorite: oreType = "Valorite"; break; // verite + case CraftResource.MDragon: oreType = "Dragon"; break; // valorite + case CraftResource.MTitan: oreType = "Titan"; break; // dull copper + case CraftResource.MCrystaline: oreType = "Crystaline"; break; // shadow iron + case CraftResource.MKrynite: oreType = "Krynite"; break; // copper + case CraftResource.MVulcan: oreType = "Vulcan"; break; // bronze + case CraftResource.MBloodcrest: oreType = "Craie de sang"; break; // golden + case CraftResource.MElvin: oreType = "Elvin"; break; // agapite + case CraftResource.MAcid: oreType = "Acid"; break; // valorite + case CraftResource.MAqua: oreType = "Aqua"; break; // copper + case CraftResource.MEldar: oreType = "Eldar"; break; // bronze + case CraftResource.MGlowing: oreType = "Glowing"; break; // golden + case CraftResource.MGorgan: oreType = "Gorgan"; break; // agapite + case CraftResource.MSandrock: oreType = "Pierre de sable"; break; // verite + case CraftResource.MSteel: oreType = "Acier"; break; // valorite + case CraftResource.SpinedLeather: oreType = "spined"; break; // spined + case CraftResource.HornedLeather: oreType = "horned"; break; // horned + case CraftResource.BarbedLeather: oreType = "barbed"; break; // barbed + case CraftResource.DaemonLeather: oreType = "daemon"; break; // daemon + case CraftResource.RedScales: oreType = "red"; break; // red + case CraftResource.YellowScales: oreType = "yellow"; break; // yellow + case CraftResource.BlackScales: oreType = "black"; break; // black + case CraftResource.GreenScales: oreType = "green"; break; // green + case CraftResource.WhiteScales: oreType = "white"; break; // white + case CraftResource.BlueScales: oreType = "blue"; break; // blue + default: oreType = null; break; + } + if ( oreType == null ) + list.Add( 1053099, "{0}\t{1}", oreType, GetNameString() ); // ~1_oretype~ ~2_armortype~ + else if ( Name == null ) + list.Add( LabelNumber ); + else + list.Add( Name ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if (m_Identified) + { + #region Factions + if ( m_FactionState != null ) + list.Add( 1041350 ); // faction item + #endregion + + if ( m_Quality == ClothingQuality.Exceptional ) + list.Add( 1060636 ); // exceptional + + if( RequiredRace == Race.Elf ) + list.Add( 1075086 ); // Elves Only + + if ( m_AosSkillBonuses != null ) + m_AosSkillBonuses.GetProperties( list ); + + int prop; + + if ( (prop = ArtifactRarity) > 0 ) + list.Add( 1061078, prop.ToString() ); // artifact rarity ~1_val~ + + if ( (prop = m_AosAttributes.WeaponDamage) != 0 ) + list.Add( 1060401, prop.ToString() ); // damage increase ~1_val~% + + if ( (prop = m_AosAttributes.DefendChance) != 0 ) + list.Add( 1060408, prop.ToString() ); // defense chance increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusDex) != 0 ) + list.Add( 1060409, prop.ToString() ); // dexterity bonus ~1_val~ + + if ( (prop = m_AosAttributes.EnhancePotions) != 0 ) + list.Add( 1060411, prop.ToString() ); // enhance potions ~1_val~% + + if ( (prop = m_AosAttributes.CastRecovery) != 0 ) + list.Add( 1060412, prop.ToString() ); // faster cast recovery ~1_val~ + + if ( (prop = m_AosAttributes.CastSpeed) != 0 ) + list.Add( 1060413, prop.ToString() ); // faster casting ~1_val~ + + if ( (prop = m_AosAttributes.AttackChance) != 0 ) + list.Add( 1060415, prop.ToString() ); // hit chance increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusHits) != 0 ) + list.Add( 1060431, prop.ToString() ); // hit point increase ~1_val~ + + if ( (prop = m_AosAttributes.BonusInt) != 0 ) + list.Add( 1060432, prop.ToString() ); // intelligence bonus ~1_val~ + + if ( (prop = m_AosAttributes.LowerManaCost) != 0 ) + list.Add( 1060433, prop.ToString() ); // lower mana cost ~1_val~% + + if ( (prop = m_AosAttributes.LowerRegCost) != 0 ) + list.Add( 1060434, prop.ToString() ); // lower reagent cost ~1_val~% + + if ( (prop = m_AosClothingAttributes.LowerStatReq) != 0 ) + list.Add( 1060435, prop.ToString() ); // lower requirements ~1_val~% + + if ( (prop = m_AosAttributes.Luck) != 0 ) + list.Add( 1060436, prop.ToString() ); // luck ~1_val~ + + if ( (prop = m_AosClothingAttributes.MageArmor) != 0 ) + list.Add( 1060437 ); // mage armor + + if ( (prop = m_AosAttributes.BonusMana) != 0 ) + list.Add( 1060439, prop.ToString() ); // mana increase ~1_val~ + + if ( (prop = m_AosAttributes.RegenMana) != 0 ) + list.Add( 1060440, prop.ToString() ); // mana regeneration ~1_val~ + + if ( (prop = m_AosAttributes.NightSight) != 0 ) + list.Add( 1060441 ); // night sight + + if ( (prop = m_AosAttributes.ReflectPhysical) != 0 ) + list.Add( 1060442, prop.ToString() ); // reflect physical damage ~1_val~% + + if ( (prop = m_AosAttributes.RegenStam) != 0 ) + list.Add( 1060443, prop.ToString() ); // stamina regeneration ~1_val~ + + if ( (prop = m_AosAttributes.RegenHits) != 0 ) + list.Add( 1060444, prop.ToString() ); // hit point regeneration ~1_val~ + + if ( (prop = m_AosClothingAttributes.SelfRepair) != 0 ) + list.Add( 1060450, prop.ToString() ); // self repair ~1_val~ + + if ( (prop = m_AosAttributes.SpellChanneling) != 0 ) + list.Add( 1060482 ); // spell channeling + + if ( (prop = m_AosAttributes.SpellDamage) != 0 ) + list.Add( 1060483, prop.ToString() ); // spell damage increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusStam) != 0 ) + list.Add( 1060484, prop.ToString() ); // stamina increase ~1_val~ + + if ( (prop = m_AosAttributes.BonusStr) != 0 ) + list.Add( 1060485, prop.ToString() ); // strength bonus ~1_val~ + + if ( (prop = m_AosAttributes.WeaponSpeed) != 0 ) + list.Add( 1060486, prop.ToString() ); // swing speed increase ~1_val~% + + if (Core.ML && (prop = m_AosAttributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + base.AddResistanceProperties( list ); + + if ( (prop = m_AosClothingAttributes.DurabilityBonus) > 0 ) + list.Add( 1060410, prop.ToString() ); // durability ~1_val~% + + if ( (prop = ComputeStatReq( StatType.Str )) > 0 ) + list.Add( 1061170, prop.ToString() ); // strength requirement ~1_val~ + + if ( m_HitPoints >= 0 && m_MaxHitPoints > 0 ) + list.Add( 1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints ); // durability ~1_val~ / ~2_val~ + } + if (!m_Identified) + list.Add("Non identifi�"); + } + + public override void OnSingleClick( Mobile from ) + { + List attrs = new List(); + + AddEquipInfoAttributes( from, attrs ); + + int number; + + if ( Name == null ) + { + number = LabelNumber; + } + else + { + this.LabelTo( from, Name ); + number = 1041000; + } + + if ( attrs.Count == 0 && Crafter == null && Name != null ) + return; + + EquipmentInfo eqInfo = new EquipmentInfo( number, m_Crafter, false, attrs.ToArray() ); + + from.Send( new DisplayEquipmentInfo( this, eqInfo ) ); + } + + public virtual void AddEquipInfoAttributes( Mobile from, List attrs ) + { + if ( DisplayLootType ) + { + if ( LootType == LootType.Blessed ) + attrs.Add( new EquipInfoAttribute( 1038021 ) ); // blessed + else if ( LootType == LootType.Cursed ) + attrs.Add( new EquipInfoAttribute( 1049643 ) ); // cursed + } + + #region Factions + if ( m_FactionState != null ) + attrs.Add( new EquipInfoAttribute( 1041350 ) ); // faction item + #endregion + + if ( m_Quality == ClothingQuality.Exceptional ) + attrs.Add( new EquipInfoAttribute( 1018305 - (int)m_Quality ) ); + } + + #region Serialization + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Resource = 0x00000001, + Attributes = 0x00000002, + ClothingAttributes = 0x00000004, + SkillBonuses = 0x00000008, + Resistances = 0x00000010, + MaxHitPoints = 0x00000020, + HitPoints = 0x00000040, + PlayerConstructed = 0x00000080, + Crafter = 0x00000100, + Quality = 0x00000200, + StrReq = 0x00000400, + Identified = 0x00000800 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 6 ); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag( ref flags, SaveFlag.Resource, m_Resource != DefaultResource ); + SetSaveFlag( ref flags, SaveFlag.Attributes, !m_AosAttributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.ClothingAttributes,!m_AosClothingAttributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.SkillBonuses, !m_AosSkillBonuses.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.Resistances, !m_AosResistances.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.MaxHitPoints, m_MaxHitPoints != 0 ); + SetSaveFlag( ref flags, SaveFlag.HitPoints, m_HitPoints != 0 ); + SetSaveFlag( ref flags, SaveFlag.PlayerConstructed, m_PlayerConstructed != false ); + SetSaveFlag( ref flags, SaveFlag.Crafter, m_Crafter != null ); + SetSaveFlag( ref flags, SaveFlag.Quality, m_Quality != ClothingQuality.Regular ); + SetSaveFlag( ref flags, SaveFlag.StrReq, m_StrReq != -1 ); + SetSaveFlag(ref flags, SaveFlag.Identified, m_Identified != false); + + writer.WriteEncodedInt( (int) flags ); + + if ( GetSaveFlag( flags, SaveFlag.Resource ) ) + writer.WriteEncodedInt( (int) m_Resource ); + + if ( GetSaveFlag( flags, SaveFlag.Attributes ) ) + m_AosAttributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.ClothingAttributes ) ) + m_AosClothingAttributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.SkillBonuses ) ) + m_AosSkillBonuses.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.Resistances ) ) + m_AosResistances.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.MaxHitPoints ) ) + writer.WriteEncodedInt( (int) m_MaxHitPoints ); + + if ( GetSaveFlag( flags, SaveFlag.HitPoints ) ) + writer.WriteEncodedInt( (int) m_HitPoints ); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + writer.Write( (Mobile) m_Crafter ); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + writer.WriteEncodedInt( (int) m_Quality ); + + if ( GetSaveFlag( flags, SaveFlag.StrReq ) ) + writer.WriteEncodedInt( (int) m_StrReq ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 6: + case 5: + { + SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Resource ) ) + m_Resource = (CraftResource)reader.ReadEncodedInt(); + else + m_Resource = DefaultResource; + + if ( GetSaveFlag( flags, SaveFlag.Attributes ) ) + m_AosAttributes = new AosAttributes( this, reader ); + else + m_AosAttributes = new AosAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.ClothingAttributes ) ) + m_AosClothingAttributes = new AosArmorAttributes( this, reader ); + else + m_AosClothingAttributes = new AosArmorAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.SkillBonuses ) ) + m_AosSkillBonuses = new AosSkillBonuses( this, reader ); + else + m_AosSkillBonuses = new AosSkillBonuses( this ); + + if ( GetSaveFlag( flags, SaveFlag.Resistances ) ) + m_AosResistances = new AosElementAttributes( this, reader ); + else + m_AosResistances = new AosElementAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.MaxHitPoints ) ) + m_MaxHitPoints = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.HitPoints ) ) + m_HitPoints = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + m_Crafter = reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + m_Quality = (ClothingQuality)reader.ReadEncodedInt(); + else + m_Quality = ClothingQuality.Regular; + + if ( GetSaveFlag( flags, SaveFlag.StrReq ) ) + m_StrReq = reader.ReadEncodedInt(); + else + m_StrReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.PlayerConstructed ) ) + m_PlayerConstructed = true; + if (GetSaveFlag(flags, SaveFlag.Identified)) + m_Identified = (version >= 6 || reader.ReadBool()); + break; + } + case 4: + { + m_Resource = (CraftResource)reader.ReadInt(); + + goto case 3; + } + case 3: + { + m_AosAttributes = new AosAttributes( this, reader ); + m_AosClothingAttributes = new AosArmorAttributes( this, reader ); + m_AosSkillBonuses = new AosSkillBonuses( this, reader ); + m_AosResistances = new AosElementAttributes( this, reader ); + + goto case 2; + } + case 2: + { + m_PlayerConstructed = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_Crafter = reader.ReadMobile(); + m_Quality = (ClothingQuality)reader.ReadInt(); + break; + } + case 0: + { + m_Crafter = null; + m_Quality = ClothingQuality.Regular; + break; + } + } + + if ( version < 2 ) + m_PlayerConstructed = true; // we don't know, so, assume it's crafted + + if (version < 6) + m_Identified = true; // we don't know, so, assume it's identfied + + if ( version < 3 ) + { + m_AosAttributes = new AosAttributes( this ); + m_AosClothingAttributes = new AosArmorAttributes( this ); + m_AosSkillBonuses = new AosSkillBonuses( this ); + m_AosResistances = new AosElementAttributes( this ); + } + + if ( version < 4 ) + m_Resource = DefaultResource; + + if ( m_MaxHitPoints == 0 && m_HitPoints == 0 ) + m_HitPoints = m_MaxHitPoints = Utility.RandomMinMax( InitMinHits, InitMaxHits ); + + Mobile parent = Parent as Mobile; + + if ( parent != null ) + { + if ( Core.AOS ) + m_AosSkillBonuses.AddTo( parent ); + + AddStatBonuses( parent ); + parent.CheckStatTimers(); + } + } + #endregion + + public virtual bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + else if ( RootParent is Mobile && from != RootParent ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public virtual bool Scissor( Mobile from, Scissors scissors ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 502437 ); // Items you wish to cut must be in your backpack. + return false; + } + + if ( Ethics.Ethic.IsImbued( this ) ) + { + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + return false; + } + + CraftSystem system = DefTailoring.CraftSystem; + + CraftItem item = system.CraftItems.SearchFor( GetType() ); + + if ( item != null && item.Resources.Count == 1 && item.Resources.GetAt( 0 ).Amount >= 2 ) + { + try + { + Type resourceType = null; + + CraftResourceInfo info = CraftResources.GetInfo( m_Resource ); + + if ( info != null && info.ResourceTypes.Length > 0 ) + resourceType = info.ResourceTypes[0]; + + if ( resourceType == null ) + resourceType = item.Resources.GetAt( 0 ).ItemType; + + Item res = (Item)Activator.CreateInstance( resourceType ); + + ScissorHelper( from, res, m_PlayerConstructed ? (item.Resources.GetAt( 0 ).Amount / 2) : 1 ); + + res.LootType = LootType.Regular; + + return true; + } + catch + { + } + } + + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + return false; + } + + public void DistributeBonuses( int amount ) + { + for ( int i = 0; i < amount; ++i ) + { + switch ( Utility.Random( 5 ) ) + { + case 0: ++m_AosResistances.Physical; break; + case 1: ++m_AosResistances.Fire; break; + case 2: ++m_AosResistances.Cold; break; + case 3: ++m_AosResistances.Poison; break; + case 4: ++m_AosResistances.Energy; break; + } + } + + InvalidateProperties(); + } + + #region ICraftable Members + + public virtual int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (ClothingQuality)quality; + + if ( makersMark ) + Crafter = from; + + if ( DefaultResource != CraftResource.None ) + { + Type resourceType = typeRes; + + if ( resourceType == null ) + resourceType = craftItem.Resources.GetAt( 0 ).ItemType; + + Resource = CraftResources.GetFromType( resourceType ); + } + else + { + Hue = resHue; + } + + PlayerConstructed = true; + Identified = true; + + CraftContext context = craftSystem.GetContext( from ); + + if ( context != null && context.DoNotColor ) + Hue = 0; + + return quality; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Cloaks.cs b/Scripts/Items/Clothing/Cloaks.cs new file mode 100644 index 0000000..976ccdb --- /dev/null +++ b/Scripts/Items/Clothing/Cloaks.cs @@ -0,0 +1,315 @@ +using System; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public abstract class BaseCloak : BaseClothing + { + public BaseCloak( int itemID ) : this( itemID, 0 ) + { + } + + public BaseCloak( int itemID, int hue ) : base( itemID, Layer.Cloak, hue ) + { + } + + public BaseCloak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable] + public class Cloak : BaseCloak, IArcaneEquip + { + #region Arcane Impl + private int m_MaxArcaneCharges, m_CurArcaneCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxArcaneCharges + { + get{ return m_MaxArcaneCharges; } + set{ m_MaxArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurArcaneCharges + { + get{ return m_CurArcaneCharges; } + set{ m_CurArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsArcane + { + get{ return ( m_MaxArcaneCharges > 0 && m_CurArcaneCharges >= 0 ); } + } + + public void Update() + { + if ( IsArcane ) + ItemID = 0x26AD; + else if ( ItemID == 0x26AD ) + ItemID = 0x1515; + + if ( IsArcane && CurArcaneCharges == 0 ) + Hue = 0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( IsArcane ) + list.Add( 1061837, "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ); // arcane charges: ~1_val~ / ~2_val~ + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsArcane ) + LabelTo( from, 1061837, String.Format( "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ) ); + } + + public void Flip() + { + if ( ItemID == 0x1515 ) + ItemID = 0x1530; + else if ( ItemID == 0x1530 ) + ItemID = 0x1515; + } + #endregion + + [Constructable] + public Cloak() : this( 0 ) + { + } + + [Constructable] + public Cloak( int hue ) : base( 0x1515, hue ) + { + Weight = 5.0; + } + + public Cloak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + if ( IsArcane ) + { + writer.Write( true ); + writer.Write( (int) m_CurArcaneCharges ); + writer.Write( (int) m_MaxArcaneCharges ); + } + else + { + writer.Write( false ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + if ( reader.ReadBool() ) + { + m_CurArcaneCharges = reader.ReadInt(); + m_MaxArcaneCharges = reader.ReadInt(); + + if ( Hue == 2118 ) + Hue = ArcaneGem.DefaultArcaneHue; + } + + break; + } + } + + if ( Weight == 4.0 ) + Weight = 5.0; + } + } + + [Flipable] + public class RewardCloak : BaseCloak, IRewardItem + { + private int m_LabelNumber; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Number + { + get{ return m_LabelNumber; } + set{ m_LabelNumber = value; InvalidateProperties(); } + } + + public override int LabelNumber + { + get + { + if ( m_LabelNumber > 0 ) + return m_LabelNumber; + + return base.LabelNumber; + } + } + + public override int BasePhysicalResistance{ get{ return 3; } } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( parent is Mobile ) + ((Mobile)parent).VirtualArmorMod += 2; + } + + public override void OnRemoved(object parent) + { + base.OnRemoved( parent ); + + if ( parent is Mobile ) + ((Mobile)parent).VirtualArmorMod -= 2; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( RewardSystem.GetRewardYearLabel( this, new object[]{ Hue, m_LabelNumber } ) ); // X Year Veteran Reward + } + + public override bool CanEquip( Mobile m ) + { + if ( !base.CanEquip( m ) ) + return false; + + return !m_IsRewardItem || Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( m, this, new object[]{ Hue, m_LabelNumber } ); + } + + [Constructable] + public RewardCloak() : this( 0 ) + { + } + + [Constructable] + public RewardCloak( int hue ) : this( hue, 0 ) + { + } + + [Constructable] + public RewardCloak( int hue, int labelNumber ) : base( 0x1515, hue ) + { + Weight = 5.0; + LootType = LootType.Blessed; + + m_LabelNumber = labelNumber; + } + + public RewardCloak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_LabelNumber ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + break; + } + } + + if ( Parent is Mobile ) + ((Mobile)Parent).VirtualArmorMod += 2; + } + } + + [Flipable( 0x230A, 0x2309 )] + public class FurCape : BaseCloak + { + [Constructable] + public FurCape() : this( 0 ) + { + } + + [Constructable] + public FurCape( int hue ) : base( 0x230A, hue ) + { + Weight = 4.0; + } + + public FurCape( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Hats.cs b/Scripts/Items/Clothing/Hats.cs new file mode 100644 index 0000000..9ac6264 --- /dev/null +++ b/Scripts/Items/Clothing/Hats.cs @@ -0,0 +1,1072 @@ +using System; +using Server.Engines.Craft; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Items +{ + public abstract class BaseHat : BaseClothing, IShipwreckedItem + { + private bool m_IsShipwreckedItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsShipwreckedItem + { + get { return m_IsShipwreckedItem; } + set { m_IsShipwreckedItem = value; } + } + + public BaseHat( int itemID ) : this( itemID, 0 ) + { + } + + public BaseHat( int itemID, int hue ) : base( itemID, Layer.Helm, hue ) + { + } + + public BaseHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_IsShipwreckedItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsShipwreckedItem = reader.ReadBool(); + break; + } + } + } + + public override void AddEquipInfoAttributes( Mobile from, List attrs ) + { + base.AddEquipInfoAttributes( from, attrs ); + + if( m_IsShipwreckedItem ) + attrs.Add( new EquipInfoAttribute( 1041645 ) ); // recovered from a shipwreck + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( m_IsShipwreckedItem ) + list.Add( 1041645 ); // recovered from a shipwreck + } + + public override int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (ClothingQuality)quality; + + if( Quality == ClothingQuality.Exceptional ) + DistributeBonuses( (tool is BaseRunicTool ? 6 : (Core.SE ? 15 : 14)) ); //BLAME OSI. (We can't confirm it's an OSI bug yet.) + + return base.OnCraft( quality, makersMark, from, craftSystem, typeRes, tool, craftItem, resHue ); + } + + } + [Flipable( 0x2798, 0x27E3 )] + public class Kasa : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public Kasa() : this( 0 ) + { + } + + [Constructable] + public Kasa( int hue ) : base( 0x2798, hue ) + { + Weight = 3.0; + } + + public Kasa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x278F, 0x27DA )] + public class ClothNinjaHood : BaseHat + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 6; } } + public override int BasePoisonResistance{ get{ return 9; } } + public override int BaseEnergyResistance{ get{ return 9; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public ClothNinjaHood() : this( 0 ) + { + } + + [Constructable] + public ClothNinjaHood( int hue ) : base( 0x278F, hue ) + { + Weight = 2.0; + } + + public ClothNinjaHood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2306, 0x2305 )] + public class FlowerGarland : BaseHat + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 6; } } + public override int BasePoisonResistance{ get{ return 9; } } + public override int BaseEnergyResistance{ get{ return 9; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public FlowerGarland() : this( 0 ) + { + } + + [Constructable] + public FlowerGarland( int hue ) : base( 0x2306, hue ) + { + Weight = 1.0; + } + + public FlowerGarland( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FloppyHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public FloppyHat() : this( 0 ) + { + } + + [Constructable] + public FloppyHat( int hue ) : base( 0x1713, hue ) + { + Weight = 1.0; + } + + public FloppyHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WideBrimHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public WideBrimHat() : this( 0 ) + { + } + + [Constructable] + public WideBrimHat( int hue ) : base( 0x1714, hue ) + { + Weight = 1.0; + } + + public WideBrimHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Cap : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public Cap() : this( 0 ) + { + } + + [Constructable] + public Cap( int hue ) : base( 0x1715, hue ) + { + Weight = 1.0; + } + + public Cap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SkullCap : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 8; } } + public override int BaseEnergyResistance{ get{ return 8; } } + + public override int InitMinHits{ get{ return ( Core.ML ? 14 : 7 ); } } + public override int InitMaxHits{ get{ return ( Core.ML ? 28 : 12 ); } } + + [Constructable] + public SkullCap() : this( 0 ) + { + } + + [Constructable] + public SkullCap( int hue ) : base( 0x1544, hue ) + { + Weight = 1.0; + } + + public SkullCap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Bandana : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 8; } } + public override int BaseEnergyResistance{ get{ return 8; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public Bandana() : this( 0 ) + { + } + + [Constructable] + public Bandana( int hue ) : base( 0x1540, hue ) + { + Weight = 1.0; + } + + public Bandana( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BearMask : BaseHat + { + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 8; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public BearMask() : this( 0 ) + { + } + + [Constructable] + public BearMask( int hue ) : base( 0x1545, hue ) + { + Weight = 5.0; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public BearMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DeerMask : BaseHat + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 8; } } + public override int BasePoisonResistance{ get{ return 1; } } + public override int BaseEnergyResistance{ get{ return 7; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public DeerMask() : this( 0 ) + { + } + + [Constructable] + public DeerMask( int hue ) : base( 0x1547, hue ) + { + Weight = 4.0; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public DeerMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class HornedTribalMask : BaseHat + { + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 9; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public HornedTribalMask() : this( 0 ) + { + } + + [Constructable] + public HornedTribalMask( int hue ) : base( 0x1549, hue ) + { + Weight = 2.0; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public HornedTribalMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TribalMask : BaseHat + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 6; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public TribalMask() : this( 0 ) + { + } + + [Constructable] + public TribalMask( int hue ) : base( 0x154B, hue ) + { + Weight = 2.0; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public TribalMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TallStrawHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public TallStrawHat() : this( 0 ) + { + } + + [Constructable] + public TallStrawHat( int hue ) : base( 0x1716, hue ) + { + Weight = 1.0; + } + + public TallStrawHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StrawHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public StrawHat() : this( 0 ) + { + } + + [Constructable] + public StrawHat( int hue ) : base( 0x1717, hue ) + { + Weight = 1.0; + } + + public StrawHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class OrcishKinMask : BaseHat + { + public override int BasePhysicalResistance{ get{ return 1; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 7; } } + public override int BaseEnergyResistance{ get{ return 8; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public override string DefaultName + { + get { return "a mask of orcish kin"; } + } + + [Constructable] + public OrcishKinMask() : this( 0x8A4 ) + { + } + + [Constructable] + public OrcishKinMask( int hue ) : base( 0x141B, hue ) + { + Weight = 2.0; + } + + public override bool CanEquip( Mobile m ) + { + if ( !base.CanEquip( m ) ) + return false; + + if ( m.BodyMod == 183 || m.BodyMod == 184 ) + { + m.SendLocalizedMessage( 1061629 ); // You can't do that while wearing savage kin paint. + return false; + } + + return true; + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( parent is Mobile ) + Misc.Titles.AwardKarma( (Mobile)parent, -20, true ); + } + + public OrcishKinMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + /*if ( Hue != 0x8A4 ) + Hue = 0x8A4;*/ + } + } + + public class SavageMask : BaseHat + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 6; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + public static int GetRandomHue() + { + int v = Utility.RandomBirdHue(); + + if ( v == 2101 ) + v = 0; + + return v; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + [Constructable] + public SavageMask() : this( GetRandomHue() ) + { + } + + [Constructable] + public SavageMask( int hue ) : base( 0x154B, hue ) + { + Weight = 2.0; + } + + public SavageMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + /*if ( Hue != 0 && (Hue < 2101 || Hue > 2130) ) + Hue = GetRandomHue();*/ + } + } + + public class WizardsHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public WizardsHat() : this( 0 ) + { + } + + [Constructable] + public WizardsHat( int hue ) : base( 0x1718, hue ) + { + Weight = 1.0; + } + + public WizardsHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MagicWizardsHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int LabelNumber{ get{ return 1041072; } } // a magical wizard's hat + + public override int BaseStrBonus{ get{ return -5; } } + public override int BaseDexBonus{ get{ return -5; } } + public override int BaseIntBonus{ get{ return +5; } } + + [Constructable] + public MagicWizardsHat() : this( 0 ) + { + } + + [Constructable] + public MagicWizardsHat( int hue ) : base( 0x1718, hue ) + { + Weight = 1.0; + } + + public MagicWizardsHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Bonnet : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public Bonnet() : this( 0 ) + { + } + + [Constructable] + public Bonnet( int hue ) : base( 0x1719, hue ) + { + Weight = 1.0; + } + + public Bonnet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FeatheredHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public FeatheredHat() : this( 0 ) + { + } + + [Constructable] + public FeatheredHat( int hue ) : base( 0x171A, hue ) + { + Weight = 1.0; + } + + public FeatheredHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TricorneHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public TricorneHat() : this( 0 ) + { + } + + [Constructable] + public TricorneHat( int hue ) : base( 0x171B, hue ) + { + Weight = 1.0; + } + + public TricorneHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class JesterHat : BaseHat + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 30; } } + + [Constructable] + public JesterHat() : this( 0 ) + { + } + + [Constructable] + public JesterHat( int hue ) : base( 0x171C, hue ) + { + Weight = 1.0; + } + + public JesterHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/MiddleTorso.cs b/Scripts/Items/Clothing/MiddleTorso.cs new file mode 100644 index 0000000..023ebcd --- /dev/null +++ b/Scripts/Items/Clothing/MiddleTorso.cs @@ -0,0 +1,303 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseMiddleTorso : BaseClothing + { + public BaseMiddleTorso( int itemID ) : this( itemID, 0 ) + { + } + + public BaseMiddleTorso( int itemID, int hue ) : base( itemID, Layer.MiddleTorso, hue ) + { + } + + public BaseMiddleTorso( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1541, 0x1542 )] + public class BodySash : BaseMiddleTorso + { + [Constructable] + public BodySash() : this( 0 ) + { + } + + [Constructable] + public BodySash( int hue ) : base( 0x1541, hue ) + { + Weight = 1.0; + } + + public BodySash( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x153d, 0x153e )] + public class FullApron : BaseMiddleTorso + { + [Constructable] + public FullApron() : this( 0 ) + { + } + + [Constructable] + public FullApron( int hue ) : base( 0x153d, hue ) + { + Weight = 4.0; + } + + public FullApron( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1f7b, 0x1f7c )] + public class Doublet : BaseMiddleTorso + { + [Constructable] + public Doublet() : this( 0 ) + { + } + + [Constructable] + public Doublet( int hue ) : base( 0x1F7B, hue ) + { + Weight = 2.0; + } + + public Doublet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1ffd, 0x1ffe )] + public class Surcoat : BaseMiddleTorso + { + [Constructable] + public Surcoat() : this( 0 ) + { + } + + [Constructable] + public Surcoat( int hue ) : base( 0x1FFD, hue ) + { + Weight = 6.0; + } + + public Surcoat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 6.0; + } + } + + [Flipable( 0x1fa1, 0x1fa2 )] + public class Tunic : BaseMiddleTorso + { + [Constructable] + public Tunic() : this( 0 ) + { + } + + [Constructable] + public Tunic( int hue ) : base( 0x1FA1, hue ) + { + Weight = 5.0; + } + + public Tunic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2310, 0x230F )] + public class FormalShirt : BaseMiddleTorso + { + [Constructable] + public FormalShirt() : this( 0 ) + { + } + + [Constructable] + public FormalShirt( int hue ) : base( 0x2310, hue ) + { + Weight = 1.0; + } + + public FormalShirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + if ( Weight == 2.0 ) + Weight = 1.0; + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1f9f, 0x1fa0 )] + public class JesterSuit : BaseMiddleTorso + { + [Constructable] + public JesterSuit() : this( 0 ) + { + } + + [Constructable] + public JesterSuit( int hue ) : base( 0x1F9F, hue ) + { + Weight = 4.0; + } + + public JesterSuit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x27A1, 0x27EC )] + public class JinBaori : BaseMiddleTorso + { + [Constructable] + public JinBaori() : this( 0 ) + { + } + + [Constructable] + public JinBaori( int hue ) : base( 0x27A1, hue ) + { + Weight = 3.0; + } + + public JinBaori( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/OuterLegs.cs b/Scripts/Items/Clothing/OuterLegs.cs new file mode 100644 index 0000000..92b016a --- /dev/null +++ b/Scripts/Items/Clothing/OuterLegs.cs @@ -0,0 +1,168 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseOuterLegs : BaseClothing + { + public BaseOuterLegs( int itemID ) : this( itemID, 0 ) + { + } + + public BaseOuterLegs( int itemID, int hue ) : base( itemID, Layer.OuterLegs, hue ) + { + } + + public BaseOuterLegs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x230C, 0x230B )] + public class FurSarong : BaseOuterLegs + { + [Constructable] + public FurSarong() : this( 0 ) + { + } + + [Constructable] + public FurSarong( int hue ) : base( 0x230C, hue ) + { + Weight = 3.0; + } + + public FurSarong( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 4.0 ) + Weight = 3.0; + } + } + + [Flipable( 0x1516, 0x1531 )] + public class Skirt : BaseOuterLegs + { + [Constructable] + public Skirt() : this( 0 ) + { + } + + [Constructable] + public Skirt( int hue ) : base( 0x1516, hue ) + { + Weight = 4.0; + } + + public Skirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1537, 0x1538 )] + public class Kilt : BaseOuterLegs + { + [Constructable] + public Kilt() : this( 0 ) + { + } + + [Constructable] + public Kilt( int hue ) : base( 0x1537, hue ) + { + Weight = 2.0; + } + + public Kilt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x279A, 0x27E5 )] + public class Hakama : BaseOuterLegs + { + [Constructable] + public Hakama() : this( 0 ) + { + } + + [Constructable] + public Hakama( int hue ) : base( 0x279A, hue ) + { + Weight = 2.0; + } + + public Hakama( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/OuterTorso.cs b/Scripts/Items/Clothing/OuterTorso.cs new file mode 100644 index 0000000..ab7d020 --- /dev/null +++ b/Scripts/Items/Clothing/OuterTorso.cs @@ -0,0 +1,889 @@ +using System; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public abstract class BaseOuterTorso : BaseClothing + { + public BaseOuterTorso( int itemID ) : this( itemID, 0 ) + { + } + + public BaseOuterTorso( int itemID, int hue ) : base( itemID, Layer.OuterTorso, hue ) + { + } + + public BaseOuterTorso( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x230E, 0x230D )] + public class GildedDress : BaseOuterTorso + { + [Constructable] + public GildedDress() : this( 0 ) + { + } + + [Constructable] + public GildedDress( int hue ) : base( 0x230E, hue ) + { + Weight = 3.0; + } + + public GildedDress( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1F00, 0x1EFF )] + public class FancyDress : BaseOuterTorso + { + [Constructable] + public FancyDress() : this( 0 ) + { + } + + [Constructable] + public FancyDress( int hue ) : base( 0x1F00, hue ) + { + Weight = 3.0; + } + + public FancyDress( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DeathRobe : Robe + { + private Timer m_DecayTimer; + private DateTime m_DecayTime; + + private static TimeSpan m_DefaultDecayTime = TimeSpan.FromMinutes(1.0); + + public override bool DisplayLootType + { + get { return false; } + } + + [Constructable] + public DeathRobe() + { + LootType = LootType.Newbied; + Hue = 2301; + BeginDecay(m_DefaultDecayTime); + } + + public new bool Scissor(Mobile from, Scissors scissors) + { + from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. + return false; + } + + public void BeginDecay() + { + BeginDecay(m_DefaultDecayTime); + } + + private void BeginDecay(TimeSpan delay) + { + if (m_DecayTimer != null) + m_DecayTimer.Stop(); + + m_DecayTime = DateTime.Now + delay; + + m_DecayTimer = new InternalTimer(this, delay); + m_DecayTimer.Start(); + } + + public override bool OnDroppedToWorld(Mobile from, Point3D p) + { + BeginDecay(m_DefaultDecayTime); + + return true; + } + + public override bool OnDroppedToMobile(Mobile from, Mobile target) + { + if (m_DecayTimer != null) + { + m_DecayTimer.Stop(); + m_DecayTimer = null; + } + + return true; + } + + public override void OnAfterDelete() + { + if (m_DecayTimer != null) + m_DecayTimer.Stop(); + + m_DecayTimer = null; + } + + private class InternalTimer : Timer + { + private DeathRobe m_Robe; + + public InternalTimer(DeathRobe c, TimeSpan delay) + : base(delay) + { + m_Robe = c; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + if (m_Robe.Parent != null || m_Robe.IsLockedDown) + Stop(); + else + m_Robe.Delete(); + } + } + + public DeathRobe(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)2); // version + + writer.Write(m_DecayTimer != null); + + if (m_DecayTimer != null) + writer.WriteDeltaTime(m_DecayTime); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 2: + { + if (reader.ReadBool()) + { + m_DecayTime = reader.ReadDeltaTime(); + BeginDecay(m_DecayTime - DateTime.Now); + } + break; + } + case 1: + case 0: + { + if (Parent == null) + BeginDecay(m_DefaultDecayTime); + break; + } + } + + if (version < 1 && Hue == 0) + Hue = 2301; + } + } + + [Flipable] + public class RewardRobe : BaseOuterTorso, IRewardItem + { + private int m_LabelNumber; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Number + { + get{ return m_LabelNumber; } + set{ m_LabelNumber = value; InvalidateProperties(); } + } + + public override int LabelNumber + { + get + { + if ( m_LabelNumber > 0 ) + return m_LabelNumber; + + return base.LabelNumber; + } + } + + public override int BasePhysicalResistance{ get{ return 3; } } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( parent is Mobile ) + ((Mobile)parent).VirtualArmorMod += 2; + } + + public override void OnRemoved(object parent) + { + base.OnRemoved( parent ); + + if ( parent is Mobile ) + ((Mobile)parent).VirtualArmorMod -= 2; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( RewardSystem.GetRewardYearLabel( this, new object[]{ Hue, m_LabelNumber } ) ); // X Year Veteran Reward + } + + public override bool CanEquip( Mobile m ) + { + if ( !base.CanEquip( m ) ) + return false; + + return !m_IsRewardItem || RewardSystem.CheckIsUsableBy( m, this, new object[]{ Hue, m_LabelNumber } ); + } + + [Constructable] + public RewardRobe() : this( 0 ) + { + } + + [Constructable] + public RewardRobe( int hue ) : this( hue, 0 ) + { + } + + [Constructable] + public RewardRobe( int hue, int labelNumber ) : base( 0x1F03, hue ) + { + Weight = 3.0; + LootType = LootType.Blessed; + + m_LabelNumber = labelNumber; + } + + public RewardRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_LabelNumber ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + break; + } + } + + if ( Parent is Mobile ) + ((Mobile)Parent).VirtualArmorMod += 2; + } + } + + [Flipable] + public class RewardDress : BaseOuterTorso, IRewardItem + { + private int m_LabelNumber; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Number + { + get{ return m_LabelNumber; } + set{ m_LabelNumber = value; InvalidateProperties(); } + } + + public override int LabelNumber + { + get + { + if ( m_LabelNumber > 0 ) + return m_LabelNumber; + + return base.LabelNumber; + } + } + + public override int BasePhysicalResistance{ get{ return 3; } } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( parent is Mobile ) + ((Mobile)parent).VirtualArmorMod += 2; + } + + public override void OnRemoved(object parent) + { + base.OnRemoved( parent ); + + if ( parent is Mobile ) + ((Mobile)parent).VirtualArmorMod -= 2; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( RewardSystem.GetRewardYearLabel( this, new object[]{ Hue, m_LabelNumber } ) ); // X Year Veteran Reward + } + + public override bool CanEquip( Mobile m ) + { + if ( !base.CanEquip( m ) ) + return false; + + return !m_IsRewardItem || RewardSystem.CheckIsUsableBy( m, this, new object[]{ Hue, m_LabelNumber } ); + } + + [Constructable] + public RewardDress() : this( 0 ) + { + } + + [Constructable] + public RewardDress( int hue ) : this( hue, 0 ) + { + } + + [Constructable] + public RewardDress( int hue, int labelNumber ) : base( 0x1F01, hue ) + { + Weight = 2.0; + LootType = LootType.Blessed; + + m_LabelNumber = labelNumber; + } + + public RewardDress( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_LabelNumber ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + break; + } + } + + if ( Parent is Mobile ) + ((Mobile)Parent).VirtualArmorMod += 2; + } + } + + [Flipable] + public class Robe : BaseOuterTorso, IArcaneEquip + { + #region Arcane Impl + private int m_MaxArcaneCharges, m_CurArcaneCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxArcaneCharges + { + get{ return m_MaxArcaneCharges; } + set{ m_MaxArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurArcaneCharges + { + get{ return m_CurArcaneCharges; } + set{ m_CurArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsArcane + { + get{ return ( m_MaxArcaneCharges > 0 && m_CurArcaneCharges >= 0 ); } + } + + public void Update() + { + if ( IsArcane ) + ItemID = 0x26AE; + else if ( ItemID == 0x26AE ) + ItemID = 0x1F04; + + if ( IsArcane && CurArcaneCharges == 0 ) + Hue = 0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( IsArcane ) + list.Add( 1061837, "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ); // arcane charges: ~1_val~ / ~2_val~ + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsArcane ) + LabelTo( from, 1061837, String.Format( "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ) ); + } + + public void Flip() + { + if ( ItemID == 0x1F03 ) + ItemID = 0x1F04; + else if ( ItemID == 0x1F04 ) + ItemID = 0x1F03; + } + #endregion + + [Constructable] + public Robe() : this( 0 ) + { + } + + [Constructable] + public Robe( int hue ) : base( 0x1F03, hue ) + { + Weight = 3.0; + } + + public Robe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + if ( IsArcane ) + { + writer.Write( true ); + writer.Write( (int) m_CurArcaneCharges ); + writer.Write( (int) m_MaxArcaneCharges ); + } + else + { + writer.Write( false ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + if ( reader.ReadBool() ) + { + m_CurArcaneCharges = reader.ReadInt(); + m_MaxArcaneCharges = reader.ReadInt(); + + if ( Hue == 2118 ) + Hue = ArcaneGem.DefaultArcaneHue; + } + + break; + } + } + } + } + + public class MonkRobe : BaseOuterTorso + { + [Constructable] + public MonkRobe() : this( 0x21E ) + { + } + + [Constructable] + public MonkRobe( int hue ) : base( 0x2687, hue ) + { + Weight = 1.0; + StrRequirement = 0; + } + public override int LabelNumber{ get{ return 1076584; } } // A monk's robe + public override bool CanBeBlessed { get { return false; } } + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + public MonkRobe( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1f01, 0x1f02 )] + public class PlainDress : BaseOuterTorso + { + [Constructable] + public PlainDress() : this( 0 ) + { + } + + [Constructable] + public PlainDress( int hue ) : base( 0x1F01, hue ) + { + Weight = 2.0; + } + + public PlainDress( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 2.0; + } + } + + [Flipable( 0x2799, 0x27E4 )] + public class Kamishimo : BaseOuterTorso + { + [Constructable] + public Kamishimo() : this( 0 ) + { + } + + [Constructable] + public Kamishimo( int hue ) : base( 0x2799, hue ) + { + Weight = 3.0; + } + + public Kamishimo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x279C, 0x27E7 )] + public class HakamaShita : BaseOuterTorso + { + [Constructable] + public HakamaShita() : this( 0 ) + { + } + + [Constructable] + public HakamaShita( int hue ) : base( 0x279C, hue ) + { + Weight = 3.0; + } + + public HakamaShita( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2782, 0x27CD )] + public class MaleKimono : BaseOuterTorso + { + [Constructable] + public MaleKimono() : this( 0 ) + { + } + + [Constructable] + public MaleKimono( int hue ) : base( 0x2782, hue ) + { + Weight = 3.0; + } + + public override bool AllowFemaleWearer{ get{ return false; } } + + public MaleKimono( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2783, 0x27CE )] + public class FemaleKimono : BaseOuterTorso + { + [Constructable] + public FemaleKimono() : this( 0 ) + { + } + + [Constructable] + public FemaleKimono( int hue ) : base( 0x2783, hue ) + { + Weight = 3.0; + } + + public override bool AllowMaleWearer{ get{ return false; } } + + public FemaleKimono( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2FB9, 0x3173 )] + public class MaleElvenRobe : BaseOuterTorso + { + //public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public MaleElvenRobe() : this( 0 ) + { + } + + [Constructable] + public MaleElvenRobe( int hue ) : base( 0x2FB9, hue ) + { + Weight = 2.0; + Name = "Robe exotique"; + } + + public MaleElvenRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [Flipable( 0x2FBA, 0x3174 )] + public class FemaleElvenRobe : BaseOuterTorso + { + //public override Race RequiredRace { get { return Race.Elf; } } + [Constructable] + public FemaleElvenRobe() : this( 0 ) + { + } + + [Constructable] + public FemaleElvenRobe( int hue ) : base( 0x2FBA, hue ) + { + Weight = 2.0; + Name = "Robe exotique"; + } + + public override bool AllowMaleWearer{ get{ return false; } } + + public FemaleElvenRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Pants.cs b/Scripts/Items/Clothing/Pants.cs new file mode 100644 index 0000000..6e25eb7 --- /dev/null +++ b/Scripts/Items/Clothing/Pants.cs @@ -0,0 +1,168 @@ +using System; + +namespace Server.Items +{ + public abstract class BasePants : BaseClothing + { + public BasePants( int itemID ) : this( itemID, 0 ) + { + } + + public BasePants( int itemID, int hue ) : base( itemID, Layer.Pants, hue ) + { + } + + public BasePants( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x152e, 0x152f )] + public class ShortPants : BasePants + { + [Constructable] + public ShortPants() : this( 0 ) + { + } + + [Constructable] + public ShortPants( int hue ) : base( 0x152E, hue ) + { + Weight = 2.0; + } + + public ShortPants( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1539, 0x153a )] + public class LongPants : BasePants + { + [Constructable] + public LongPants() : this( 0 ) + { + } + + [Constructable] + public LongPants( int hue ) : base( 0x1539, hue ) + { + Weight = 2.0; + } + + public LongPants( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x279B, 0x27E6 )] + public class TattsukeHakama : BasePants + { + [Constructable] + public TattsukeHakama() : this( 0 ) + { + } + + [Constructable] + public TattsukeHakama( int hue ) : base( 0x279B, hue ) + { + Weight = 2.0; + } + + public TattsukeHakama( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x2FC3, 0x3179 )] + public class ElvenPants : BasePants + { + //public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public ElvenPants() : this( 0 ) + { + } + + [Constructable] + public ElvenPants( int hue ) : base( 0x2FC3, hue ) + { + Weight = 2.0; + Name = "Pantalon exotique"; + } + + public ElvenPants( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Shirts.cs b/Scripts/Items/Clothing/Shirts.cs new file mode 100644 index 0000000..a51b376 --- /dev/null +++ b/Scripts/Items/Clothing/Shirts.cs @@ -0,0 +1,206 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseShirt : BaseClothing + { + public BaseShirt( int itemID ) : this( itemID, 0 ) + { + } + + public BaseShirt( int itemID, int hue ) : base( itemID, Layer.Shirt, hue ) + { + } + + public BaseShirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1efd, 0x1efe )] + public class FancyShirt : BaseShirt + { + [Constructable] + public FancyShirt() : this( 0 ) + { + } + + [Constructable] + public FancyShirt( int hue ) : base( 0x1EFD, hue ) + { + Weight = 2.0; + } + + public FancyShirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1517, 0x1518 )] + public class Shirt : BaseShirt + { + [Constructable] + public Shirt() : this( 0 ) + { + } + + [Constructable] + public Shirt( int hue ) : base( 0x1517, hue ) + { + Weight = 1.0; + } + + public Shirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } + + [Flipable( 0x2794, 0x27DF )] + public class ClothNinjaJacket : BaseShirt + { + [Constructable] + public ClothNinjaJacket() : this( 0 ) + { + } + + [Constructable] + public ClothNinjaJacket( int hue ) : base( 0x2794, hue ) + { + Weight = 5.0; + Layer = Layer.InnerTorso; + } + + public ClothNinjaJacket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ElvenShirt : BaseShirt + { + //public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public ElvenShirt() : this( 0 ) + { + } + + [Constructable] + public ElvenShirt( int hue ) : base( 0x3175, hue ) + { + Weight = 2.0; + Name = "Chemise Exotique" ; + } + + public ElvenShirt(Serial serial) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ElvenDarkShirt : BaseShirt + { + //public override Race RequiredRace { get { return Race.Elf; } } + [Constructable] + public ElvenDarkShirt() : this( 0 ) + { + } + + [Constructable] + public ElvenDarkShirt( int hue ) : base( 0x3176, hue ) + { + Weight = 2.0; + Name = "Chemise Exotique (Sombre)"; + } + + public ElvenDarkShirt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Clothing/Shoes.cs b/Scripts/Items/Clothing/Shoes.cs new file mode 100644 index 0000000..3920e96 --- /dev/null +++ b/Scripts/Items/Clothing/Shoes.cs @@ -0,0 +1,464 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseShoes : BaseClothing + { + public BaseShoes( int itemID ) : this( itemID, 0 ) + { + } + + public BaseShoes( int itemID, int hue ) : base( itemID, Layer.Shoes, hue ) + { + } + + public BaseShoes( Serial serial ) : base( serial ) + { + } + + public override bool Scissor( Mobile from, Scissors scissors ) + { + if( DefaultResource == CraftResource.None ) + return base.Scissor( from, scissors ); + + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: break; // empty, resource removed + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + m_Resource = DefaultResource; + break; + } + } + } + } + + [Flipable( 0x2307, 0x2308 )] + public class FurBoots : BaseShoes + { + [Constructable] + public FurBoots() : this( 0 ) + { + } + + [Constructable] + public FurBoots( int hue ) : base( 0x2307, hue ) + { + Weight = 3.0; + } + + public FurBoots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x170b, 0x170c )] + public class Boots : BaseShoes + { + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public Boots() : this( 0 ) + { + } + + [Constructable] + public Boots( int hue ) : base( 0x170B, hue ) + { + Weight = 3.0; + } + + public Boots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable] + public class ThighBoots : BaseShoes, IArcaneEquip + { + #region Arcane Impl + private int m_MaxArcaneCharges, m_CurArcaneCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxArcaneCharges + { + get{ return m_MaxArcaneCharges; } + set{ m_MaxArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurArcaneCharges + { + get{ return m_CurArcaneCharges; } + set{ m_CurArcaneCharges = value; InvalidateProperties(); Update(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsArcane + { + get{ return ( m_MaxArcaneCharges > 0 && m_CurArcaneCharges >= 0 ); } + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( IsArcane ) + LabelTo( from, 1061837, String.Format( "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ) ); + } + + public void Update() + { + if ( IsArcane ) + ItemID = 0x26AF; + else if ( ItemID == 0x26AF ) + ItemID = 0x1711; + + if ( IsArcane && CurArcaneCharges == 0 ) + Hue = 0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( IsArcane ) + list.Add( 1061837, "{0}\t{1}", m_CurArcaneCharges, m_MaxArcaneCharges ); // arcane charges: ~1_val~ / ~2_val~ + } + + public void Flip() + { + if ( ItemID == 0x1711 ) + ItemID = 0x1712; + else if ( ItemID == 0x1712 ) + ItemID = 0x1711; + } + #endregion + + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public ThighBoots() : this( 0 ) + { + } + + [Constructable] + public ThighBoots( int hue ) : base( 0x1711, hue ) + { + Weight = 4.0; + } + + public ThighBoots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + if ( IsArcane ) + { + writer.Write( true ); + writer.Write( (int) m_CurArcaneCharges ); + writer.Write( (int) m_MaxArcaneCharges ); + } + else + { + writer.Write( false ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + if ( reader.ReadBool() ) + { + m_CurArcaneCharges = reader.ReadInt(); + m_MaxArcaneCharges = reader.ReadInt(); + + if ( Hue == 2118 ) + Hue = ArcaneGem.DefaultArcaneHue; + } + + break; + } + } + } + } + + [FlipableAttribute( 0x170f, 0x1710 )] + public class Shoes : BaseShoes + { + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public Shoes() : this( 0 ) + { + } + + [Constructable] + public Shoes( int hue ) : base( 0x170F, hue ) + { + Weight = 2.0; + } + + public Shoes( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x170d, 0x170e )] + public class Sandals : BaseShoes + { + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + [Constructable] + public Sandals() : this( 0 ) + { + } + + [Constructable] + public Sandals( int hue ) : base( 0x170D, hue ) + { + Weight = 1.0; + } + + public Sandals( Serial serial ) : base( serial ) + { + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2797, 0x27E2 )] + public class NinjaTabi : BaseShoes + { + [Constructable] + public NinjaTabi() : this( 0 ) + { + } + + [Constructable] + public NinjaTabi( int hue ) : base( 0x2797, hue ) + { + Weight = 2.0; + } + + public NinjaTabi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2796, 0x27E1 )] + public class SamuraiTabi : BaseShoes + { + [Constructable] + public SamuraiTabi() : this( 0 ) + { + } + + [Constructable] + public SamuraiTabi( int hue ) : base( 0x2796, hue ) + { + Weight = 2.0; + } + + public SamuraiTabi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2796, 0x27E1 )] + public class Waraji : BaseShoes + { + [Constructable] + public Waraji() : this( 0 ) + { + } + + [Constructable] + public Waraji( int hue ) : base( 0x2796, hue ) + { + Weight = 2.0; + } + + public Waraji( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x2FC4, 0x317A )] + public class ElvenBoots : BaseShoes + { + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + //public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public ElvenBoots() : this( 0 ) + { + } + + [Constructable] + public ElvenBoots( int hue ) : base( 0x2FC4, hue ) + { + Weight = 2.0; + Name = "Bottes exotiques"; + } + + public ElvenBoots( Serial serial ) : base( serial ) + { + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Clothing/Waist.cs b/Scripts/Items/Clothing/Waist.cs new file mode 100644 index 0000000..791d3ad --- /dev/null +++ b/Scripts/Items/Clothing/Waist.cs @@ -0,0 +1,148 @@ +using System; + +namespace Server.Items +{ + + public abstract class BaseWaist : BaseClothing + { + public BaseWaist( int itemID ) : this( itemID, 0 ) + { + } + + public BaseWaist( int itemID, int hue ) : base( itemID, Layer.Waist, hue ) + { + } + + public BaseWaist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x153b, 0x153c )] + public class HalfApron : BaseWaist + { + [Constructable] + public HalfApron() : this( 0 ) + { + } + + [Constructable] + public HalfApron( int hue ) : base( 0x153b, hue ) + { + Weight = 2.0; + } + + public HalfApron( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x27A0, 0x27EB )] + public class Obi : BaseWaist + { + [Constructable] + public Obi() : this( 0 ) + { + } + + [Constructable] + public Obi( int hue ) : base( 0x27A0, hue ) + { + Weight = 1.0; + } + + public Obi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x2B68, 0x315F )] + public class WoodlandBelt : BaseWaist + { + //public override Race RequiredRace { get { return Race.Elf; } } + + [Constructable] + public WoodlandBelt() : this( 0 ) + { + } + + [Constructable] + public WoodlandBelt( int hue ) : base( 0x2B68, hue ) + { + Weight = 4.0; + Name = "Ceinture Arboricole"; // impossible de rester s�rieux devant cet item ^^ + } + + public WoodlandBelt( Serial serial ) : base( serial ) + { + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public override bool Scissor( Mobile from, Scissors scissors ) + { + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Construction/Ankhs.cs b/Scripts/Items/Construction/Ankhs.cs new file mode 100644 index 0000000..3b2d0be --- /dev/null +++ b/Scripts/Items/Construction/Ankhs.cs @@ -0,0 +1,445 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.ContextMenus; + +namespace Server.Items +{ + public class Ankhs + { + public const int ResurrectRange = 2; + public const int TitheRange = 2; + public const int LockRange = 2; + + public static void GetContextMenuEntries( Mobile from, Item item, List list ) + { + if ( from is PlayerMobile ) + list.Add( new LockKarmaEntry( (PlayerMobile)from ) ); + + list.Add( new ResurrectEntry( from, item ) ); + + if ( Core.AOS ) + list.Add( new TitheEntry( from ) ); + } + + public static void Resurrect( Mobile m, Item item ) + { + if ( m.Alive ) + return; + + if ( !m.InRange( item.GetWorldLocation(), ResurrectRange ) ) + m.SendLocalizedMessage( 500446 ); // That is too far away. + else if( m.Map != null && m.Map.CanFit( m.Location, 16, false, false ) ) + { + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.VirtueShrine ) ); + } + else + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + + private class ResurrectEntry : ContextMenuEntry + { + private Mobile m_Mobile; + private Item m_Item; + + public ResurrectEntry( Mobile mobile, Item item ) : base( 6195, ResurrectRange ) + { + m_Mobile = mobile; + m_Item = item; + + Enabled = !m_Mobile.Alive; + } + + public override void OnClick() + { + Resurrect( m_Mobile, m_Item ); + } + } + + private class LockKarmaEntry : ContextMenuEntry + { + private PlayerMobile m_Mobile; + + public LockKarmaEntry( PlayerMobile mobile ) : base( mobile.KarmaLocked ? 6197 : 6196, LockRange ) + { + m_Mobile = mobile; + } + + public override void OnClick() + { + m_Mobile.KarmaLocked = !m_Mobile.KarmaLocked; + + if ( m_Mobile.KarmaLocked ) + m_Mobile.SendLocalizedMessage( 1060192 ); // Your karma has been locked. Your karma can no longer be raised. + else + m_Mobile.SendLocalizedMessage( 1060191 ); // Your karma has been unlocked. Your karma can be raised again. + } + } + + private class TitheEntry : ContextMenuEntry + { + private Mobile m_Mobile; + + public TitheEntry( Mobile mobile ) : base( 6198, TitheRange ) + { + m_Mobile = mobile; + + Enabled = m_Mobile.Alive; + } + + public override void OnClick() + { + if (m_Mobile.CheckAlive()) + { + + if (m_Mobile is PlayerMobile && ((PlayerMobile)m_Mobile).IsArtedarKnight) // Vinds :Les Chevaliers d'artedar ne gagnent pas de tithe par le don d'or + + m_Mobile.SendMessage("Artedar n'a que faire de cette absurde Pi�t� !!"); + + + else m_Mobile.SendGump(new TithingGump(m_Mobile, 0)); + } + } + } + } + + public class AnkhWest : Item + { + private InternalItem m_Item; + + [Constructable] + public AnkhWest() : this( false ) + { + } + + [Constructable] + public AnkhWest( bool bloodied ) : base( bloodied ? 0x1D98 : 0x3 ) + { + Movable = false; + + m_Item = new InternalItem( bloodied, this ); + } + + public AnkhWest( Serial serial ) : base( serial ) + { + } + + public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Parent == null && Utility.InRange( Location, m.Location, 1 ) && !Utility.InRange( Location, oldLocation, 1 ) ) + Ankhs.Resurrect( m, this ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + Ankhs.GetContextMenuEntries( from, this, list ); + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get{ return base.Hue; } + set{ base.Hue = value; if ( m_Item.Hue != value ) m_Item.Hue = value; } + } + + public override void OnDoubleClickDead( Mobile m ) + { + Ankhs.Resurrect( m, this ); + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X, Y + 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + + private class InternalItem : Item + { + private AnkhWest m_Item; + + public InternalItem( bool bloodied, AnkhWest item ) : base( bloodied ? 0x1D97 : 0x2 ) + { + Movable = false; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X, Y - 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Parent == null && Utility.InRange( Location, m.Location, 1 ) && !Utility.InRange( Location, oldLocation, 1 ) ) + Ankhs.Resurrect( m, this ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + Ankhs.GetContextMenuEntries( from, this, list ); + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get{ return base.Hue; } + set{ base.Hue = value; if ( m_Item.Hue != value ) m_Item.Hue = value; } + } + + public override void OnDoubleClickDead( Mobile m ) + { + Ankhs.Resurrect( m, this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as AnkhWest; + } + } + } + + [TypeAlias( "Server.Items.AnkhEast" )] + public class AnkhNorth : Item + { + private InternalItem m_Item; + + [Constructable] + public AnkhNorth() : this( false ) + { + } + + [Constructable] + public AnkhNorth( bool bloodied ) : base( bloodied ? 0x1E5D : 0x4 ) + { + Movable = false; + + m_Item = new InternalItem( bloodied, this ); + } + + public AnkhNorth( Serial serial ) + : base( serial ) + { + } + + public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Parent == null && Utility.InRange( Location, m.Location, 1 ) && !Utility.InRange( Location, oldLocation, 1 ) ) + Ankhs.Resurrect( m, this ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + Ankhs.GetContextMenuEntries( from, this, list ); + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get{ return base.Hue; } + set{ base.Hue = value; if ( m_Item.Hue != value ) m_Item.Hue = value; } + } + + public override void OnDoubleClickDead( Mobile m ) + { + Ankhs.Resurrect( m, this ); + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + + [TypeAlias( "Server.Items.AnkhEast+InternalItem" )] + private class InternalItem : Item + { + private AnkhNorth m_Item; + + public InternalItem( bool bloodied, AnkhNorth item ) + : base( bloodied ? 0x1E5C : 0x5 ) + { + Movable = false; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Parent == null && Utility.InRange( Location, m.Location, 1 ) && !Utility.InRange( Location, oldLocation, 1 ) ) + Ankhs.Resurrect( m, this ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + Ankhs.GetContextMenuEntries( from, this, list ); + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get{ return base.Hue; } + set{ base.Hue = value; if ( m_Item.Hue != value ) m_Item.Hue = value; } + } + + public override void OnDoubleClickDead( Mobile m ) + { + Ankhs.Resurrect( m, this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as AnkhNorth; + } + } + } +} diff --git a/Scripts/Items/Construction/Chairs/Benchs.cs b/Scripts/Items/Construction/Chairs/Benchs.cs new file mode 100644 index 0000000..b96bc94 --- /dev/null +++ b/Scripts/Items/Construction/Chairs/Benchs.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0xB2D, 0xB2C )] + public class WoodenBench : Item + { + [Constructable] + public WoodenBench() : base( 0xB2D ) + { + Weight = 6; + } + + public WoodenBench(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Chairs/Chairs.cs b/Scripts/Items/Construction/Chairs/Chairs.cs new file mode 100644 index 0000000..923b868 --- /dev/null +++ b/Scripts/Items/Construction/Chairs/Chairs.cs @@ -0,0 +1,244 @@ +using System; + +namespace Server.Items +{ + [Furniture] + [Flipable( 0xB4F, 0xB4E, 0xB50, 0xB51 )] + public class FancyWoodenChairCushion : Item + { + [Constructable] + public FancyWoodenChairCushion() : base(0xB4F) + { + Weight = 20.0; + } + + public FancyWoodenChairCushion(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 20.0; + } + } + + [Furniture] + [Flipable( 0xB53, 0xB52, 0xB54, 0xB55 )] + public class WoodenChairCushion : Item + { + [Constructable] + public WoodenChairCushion() : base(0xB53) + { + Weight = 20.0; + } + + public WoodenChairCushion(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 20.0; + } + } + + [Flipable( 0xB57, 0xB56, 0xB59, 0xB58 )] + public class WoodenChair : Item + { + [Constructable] + public WoodenChair() : base(0xB57) + { + Weight = 20.0; + } + + public WoodenChair(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 20.0; + } + } + + [Flipable( 0xB5B, 0xB5A, 0xB5C, 0xB5D )] + public class BambooChair : Item + { + [Constructable] + public BambooChair() : base(0xB5B) + { + Weight = 20.0; + } + + public BambooChair(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 20.0; + } + } + + [DynamicFliping] + [Flipable(0x1218, 0x1219, 0x121A, 0x121B)] + public class StoneChair : Item + { + [Constructable] + public StoneChair() : base(0x1218) + { + Weight = 20; + } + + public StoneChair(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [DynamicFliping] + [Flipable( 0x2DE3, 0x2DE4, 0x2DE5, 0x2DE6 )] + public class OrnateElvenChair : Item + { + [Constructable] + public OrnateElvenChair() : base( 0x2DE3 ) + { + Weight = 1.0; + } + + public OrnateElvenChair( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [DynamicFliping] + [Flipable( 0x2DEB, 0x2DEC, 0x2DED, 0x2DEE )] + public class BigElvenChair : Item + { + [Constructable] + public BigElvenChair() : base( 0x2DEB ) + { + } + + public BigElvenChair( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [DynamicFliping] + [Flipable( 0x2DF5, 0x2DF6 )] + public class ElvenReadingChair : Item + { + [Constructable] + public ElvenReadingChair() : base( 0x2DF5 ) + { + } + + public ElvenReadingChair( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Chairs/Stools.cs b/Scripts/Items/Construction/Chairs/Stools.cs new file mode 100644 index 0000000..7003f91 --- /dev/null +++ b/Scripts/Items/Construction/Chairs/Stools.cs @@ -0,0 +1,64 @@ +using System; + +namespace Server.Items +{ + public class Stool : Item + { + [Constructable] + public Stool() : base( 0xA2A ) + { + Weight = 10.0; + } + + public Stool(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 10.0; + } + } + + public class FootStool : Item + { + [Constructable] + public FootStool() : base( 0xB5E ) + { + Weight = 6.0; + } + + public FootStool(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 10.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Chairs/Thrones.cs b/Scripts/Items/Construction/Chairs/Thrones.cs new file mode 100644 index 0000000..8799ff9 --- /dev/null +++ b/Scripts/Items/Construction/Chairs/Thrones.cs @@ -0,0 +1,66 @@ +using System; + +namespace Server.Items +{ + [Flipable(0xB32, 0xB33)] + public class Throne : Item + { + [Constructable] + public Throne() : base(0xB33) + { + Weight = 1.0; + } + + public Throne(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 1.0; + } + } + + [Flipable( 0xB2E, 0xB2F, 0xB31, 0xB30 )] + public class WoodenThrone : Item + { + [Constructable] + public WoodenThrone() : base(0xB2E) + { + Weight = 15.0; + } + + public WoodenThrone(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 15.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Decorative/DecorativeShield.cs b/Scripts/Items/Construction/Decorative/DecorativeShield.cs new file mode 100644 index 0000000..bf68b0e --- /dev/null +++ b/Scripts/Items/Construction/Decorative/DecorativeShield.cs @@ -0,0 +1,426 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + + [FlipableAttribute( 0x156C, 0x156D )] + public class DecorativeShield1 : Item + { + [Constructable] + public DecorativeShield1() : base( 0x156C ) + { + Movable = false; + } + + public DecorativeShield1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + [FlipableAttribute( 0x156E, 0x156F )] + public class DecorativeShield2 : Item + { + [Constructable] + public DecorativeShield2() : base( 0x156E ) + { + Movable = false; + } + + public DecorativeShield2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1570, 0x1571 )] + public class DecorativeShield3 : Item + { + [Constructable] + public DecorativeShield3() : base( 0x1570 ) + { + Movable = false; + } + + public DecorativeShield3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1572, 0x1573 )] + public class DecorativeShield4 : Item + { + [Constructable] + public DecorativeShield4() : base( 0x1572 ) + { + Movable = false; + } + + public DecorativeShield4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1574, 0x1575 )] + public class DecorativeShield5 : Item + { + [Constructable] + public DecorativeShield5() : base( 0x1574 ) + { + Movable = false; + } + + public DecorativeShield5( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1576, 0x1577 )] + public class DecorativeShield6 : Item + { + [Constructable] + public DecorativeShield6() : base( 0x1576 ) + { + Movable = false; + } + + public DecorativeShield6( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1578, 0x1579 )] + public class DecorativeShield7 : Item + { + [Constructable] + public DecorativeShield7() : base( 0x1578 ) + { + Movable = false; + } + + public DecorativeShield7( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x157A, 0x157B )] + public class DecorativeShield8 : Item + { + [Constructable] + public DecorativeShield8() : base( 0x157A ) + { + Movable = false; + } + + public DecorativeShield8( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x157C, 0x157D )] + public class DecorativeShield9 : Item + { + [Constructable] + public DecorativeShield9() : base( 0x157C ) + { + Movable = false; + } + + public DecorativeShield9( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x157E, 0x157F )] + public class DecorativeShield10 : Item + { + [Constructable] + public DecorativeShield10() : base( 0x157E ) + { + Movable = false; + } + + public DecorativeShield10( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1580, 0x1581 )] + public class DecorativeShield11 : Item + { + [Constructable] + public DecorativeShield11() : base( 0x1580 ) + { + Movable = false; + } + + public DecorativeShield11( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1582, 0x1583, 0x1634, 0x1635 )] + public class DecorativeShieldSword1North : Item + { + [Constructable] + public DecorativeShieldSword1North() : base( Utility.Random( 0x1582, 2 ) ) + { + Movable = false; + } + + public DecorativeShieldSword1North( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1634, 0x1635, 0x1582, 0x1583 )] + public class DecorativeShieldSword1West : Item + { + [Constructable] + public DecorativeShieldSword1West() : base( Utility.Random( 0x1634, 2 ) ) + { + Movable = false; + } + + public DecorativeShieldSword1West( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1584, 0x1585, 0x1636, 0x1637 )] + public class DecorativeShieldSword2North : Item + { + [Constructable] + public DecorativeShieldSword2North() : base( Utility.Random( 0x1584, 2 ) ) + { + Movable = false; + } + + public DecorativeShieldSword2North( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1636, 0x1637, 0x1584, 0x1585 )] + public class DecorativeShieldSword2West : Item + { + [Constructable] + public DecorativeShieldSword2West() : base( Utility.Random( 0x1636, 2 ) ) + { + Movable = false; + } + + public DecorativeShieldSword2West( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Decorative/DecorativeWeapon.cs b/Scripts/Items/Construction/Decorative/DecorativeWeapon.cs new file mode 100644 index 0000000..ccb93d5 --- /dev/null +++ b/Scripts/Items/Construction/Decorative/DecorativeWeapon.cs @@ -0,0 +1,546 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x155E, 0x155F, 0x155C, 0x155D )] + public class DecorativeBowWest : Item + { + [Constructable] + public DecorativeBowWest() : base( Utility.Random( 0x155E, 2 ) ) + { + Movable = false; + } + + public DecorativeBowWest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x155C, 0x155D, 0x155E, 0x155F )] + public class DecorativeBowNorth : Item + { + [Constructable] + public DecorativeBowNorth() : base( Utility.Random( 0x155C, 2 ) ) + { + Movable = false; + } + + public DecorativeBowNorth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1560, 0x1561, 0x1562, 0x1563 )] + public class DecorativeAxeNorth : Item + { + [Constructable] + public DecorativeAxeNorth() : base( Utility.Random( 0x1560, 2 ) ) + { + Movable = false; + } + + public DecorativeAxeNorth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1562, 0x1563, 0x1560, 0x1561 )] + public class DecorativeAxeWest : Item + { + [Constructable] + public DecorativeAxeWest() : base( Utility.Random( 0x1562, 2 ) ) + { + Movable = false; + } + + public DecorativeAxeWest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DecorativeSwordNorth : Item + { + private InternalItem m_Item; + + [Constructable] + public DecorativeSwordNorth() : base( 0x1565 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public DecorativeSwordNorth( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private DecorativeSwordNorth m_Item; + + public InternalItem( DecorativeSwordNorth item ) : base( 0x1564 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as DecorativeSwordNorth; + } + } + } + public class DecorativeSwordWest : Item + { + private InternalItem m_Item; + + [Constructable] + public DecorativeSwordWest() : base( 0x1566 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public DecorativeSwordWest( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 1 , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private DecorativeSwordWest m_Item; + + public InternalItem( DecorativeSwordWest item ) : base( 0x1567 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as DecorativeSwordWest; + } + } + } + public class DecorativeDAxeNorth : Item + { + private InternalItem m_Item; + + [Constructable] + public DecorativeDAxeNorth() : base( 0x1569 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public DecorativeDAxeNorth( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private DecorativeDAxeNorth m_Item; + + public InternalItem( DecorativeDAxeNorth item ) : base( 0x1568 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as DecorativeDAxeNorth; + } + } + } + public class DecorativeDAxeWest : Item + { + private InternalItem m_Item; + + [Constructable] + public DecorativeDAxeWest() : base( 0x156A ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public DecorativeDAxeWest( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 1 , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private DecorativeDAxeWest m_Item; + + public InternalItem( DecorativeDAxeWest item ) : base( 0x156B ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as DecorativeDAxeWest; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Decorative/PaintingPortraits.cs b/Scripts/Items/Construction/Decorative/PaintingPortraits.cs new file mode 100644 index 0000000..e6ab4de --- /dev/null +++ b/Scripts/Items/Construction/Decorative/PaintingPortraits.cs @@ -0,0 +1,200 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + public class LargePainting : Item + { + [Constructable] + public LargePainting() : base( 0x0EA0 ) + { + Movable = false; + } + + public LargePainting( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x0E9F, 0x0EC8 )] + public class WomanPortrait1 : Item + { + [Constructable] + public WomanPortrait1() : base( 0x0E9F ) + { + Movable = false; + } + + public WomanPortrait1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x0EE7, 0x0EC9 )] + public class WomanPortrait2 : Item + { + [Constructable] + public WomanPortrait2() : base( 0x0EE7 ) + { + Movable = false; + } + + public WomanPortrait2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x0EA2, 0x0EA1 )] + public class ManPortrait1 : Item + { + [Constructable] + public ManPortrait1() : base( 0x0EA2 ) + { + Movable = false; + } + + public ManPortrait1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x0EA3, 0x0EA4 )] + public class ManPortrait2 : Item + { + [Constructable] + public ManPortrait2() : base( 0x0EA3 ) + { + Movable = false; + } + + public ManPortrait2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x0EA6, 0x0EA5 )] + public class LadyPortrait1 : Item + { + [Constructable] + public LadyPortrait1() : base( 0x0EA6 ) + { + Movable = false; + } + + public LadyPortrait1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x0EA7, 0x0EA8 )] + public class LadyPortrait2 : Item + { + [Constructable] + public LadyPortrait2() : base( 0x0EA7 ) + { + Movable = false; + } + + public LadyPortrait2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Decorative/Tapestry.cs b/Scripts/Items/Construction/Decorative/Tapestry.cs new file mode 100644 index 0000000..db42d29 --- /dev/null +++ b/Scripts/Items/Construction/Decorative/Tapestry.cs @@ -0,0 +1,1192 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + public class Tapestry1N : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry1N() : base( 0xEAA ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry1N( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry1N m_Item; + + public InternalItem( Tapestry1N item ) : base( 0xEAB ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry1N; + } + } + } + + public class Tapestry2N : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry2N() : base( 0xEAC ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry2N( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry2N m_Item; + + public InternalItem( Tapestry2N item ) : base( 0xEAD ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry2N; + } + } + } + public class Tapestry2W : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry2W() : base( 0xEAE ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry2W( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 1 , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry2W m_Item; + + public InternalItem( Tapestry2W item ) : base( 0xEAF ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 1 , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry2W; + } + } + } + + public class Tapestry3N : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry3N() : base( 0xFD6 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry3N( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 2, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry3N m_Item; + + public InternalItem( Tapestry3N item ) : base( 0xFD5 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 2, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry3N; + } + } + } + + public class Tapestry3W : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry3W() : base( 0xFD7 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry3W( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 2 , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry3W m_Item; + + public InternalItem( Tapestry3W item ) : base( 0xFD8 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 2 , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry3W; + } + } + } + + public class Tapestry4N : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry4N() : base( 0xFDA ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry4N( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry4N m_Item; + + public InternalItem( Tapestry4N item ) : base( 0xFD9 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry4N; + } + } + } + public class Tapestry4W : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry4W() : base( 0xFDB ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry4W( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + + private class InternalItem : Item + { + private Tapestry4W m_Item; + + public InternalItem( Tapestry4W item ) : base( 0xFDC ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry4W; + } + } + } + + public class Tapestry5N : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry5N() : base( 0xFDE ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry5N( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry5N m_Item; + + public InternalItem( Tapestry5N item ) : base( 0xFDD ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry5N; + } + } + } + public class Tapestry5W : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry5W() : base( 0xFDF ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry5W( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + + private class InternalItem : Item + { + private Tapestry5W m_Item; + + public InternalItem( Tapestry5W item ) : base( 0xFE0 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry5W; + } + } + } + + public class Tapestry6N : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry6N() : base( 0xFE2 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry6N( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + private class InternalItem : Item + { + private Tapestry6N m_Item; + + public InternalItem( Tapestry6N item ) : base( 0xFE1 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y , Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry6N; + } + } + } + public class Tapestry6W : Item + { + private InternalItem m_Item; + + [Constructable] + public Tapestry6W() : base( 0xFE3 ) + { + Movable = false; + + m_Item = new InternalItem( this ); + } + + public Tapestry6W( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y - 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + } + + private class InternalItem : Item + { + private Tapestry6W m_Item; + + public InternalItem( Tapestry6W item ) : base( 0xFE4 ) + { + Movable = true; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X , Y + 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as Tapestry6W; + } + } + } +} diff --git a/Scripts/Items/Construction/Doors/BaseDoor.cs b/Scripts/Items/Construction/Doors/BaseDoor.cs new file mode 100644 index 0000000..d275ecc --- /dev/null +++ b/Scripts/Items/Construction/Doors/BaseDoor.cs @@ -0,0 +1,589 @@ +using System; +using System.Collections.Generic; +using Server.Commands; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseDoor : Item, ILockable, ITelekinesisable + { + private bool m_Open, m_Locked; + private int m_OpenedID, m_OpenedSound; + private int m_ClosedID, m_ClosedSound; + private Point3D m_Offset; + private BaseDoor m_Link; + private uint m_KeyValue; + + private Timer m_Timer; + + private static Point3D[] m_Offsets = new Point3D[] + { + new Point3D(-1, 1, 0 ), + new Point3D( 1, 1, 0 ), + new Point3D(-1, 0, 0 ), + new Point3D( 1,-1, 0 ), + new Point3D( 1, 1, 0 ), + new Point3D( 1,-1, 0 ), + new Point3D( 0, 0, 0 ), + new Point3D( 0,-1, 0 ), + + new Point3D( 0, 0, 0 ), + new Point3D( 0, 0, 0 ), + new Point3D( 0, 0, 0 ), + new Point3D( 0, 0, 0 ) + }; + + // Called by RunUO + public static void Initialize() + { + EventSink.OpenDoorMacroUsed += new OpenDoorMacroEventHandler( EventSink_OpenDoorMacroUsed ); + + CommandSystem.Register( "Link", AccessLevel.GameMaster, new CommandEventHandler( Link_OnCommand ) ); + CommandSystem.Register( "ChainLink", AccessLevel.GameMaster, new CommandEventHandler( ChainLink_OnCommand ) ); + } + + [Usage( "Link" )] + [Description( "Links two targeted doors together." )] + private static void Link_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( Link_OnFirstTarget ) ); + e.Mobile.SendMessage( "Target the first door to link." ); + } + + private static void Link_OnFirstTarget( Mobile from, object targeted ) + { + BaseDoor door = targeted as BaseDoor; + + if ( door == null ) + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( Link_OnFirstTarget ) ); + from.SendMessage( "That is not a door. Try again." ); + } + else + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( Link_OnSecondTarget ), door ); + from.SendMessage( "Target the second door to link." ); + } + } + + private static void Link_OnSecondTarget( Mobile from, object targeted, object state ) + { + BaseDoor first = (BaseDoor)state; + BaseDoor second = targeted as BaseDoor; + + if ( second == null ) + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( Link_OnSecondTarget ), first ); + from.SendMessage( "That is not a door. Try again." ); + } + else + { + first.Link = second; + second.Link = first; + from.SendMessage( "The doors have been linked." ); + } + } + + [Usage( "ChainLink" )] + [Description( "Chain-links two or more targeted doors together." )] + private static void ChainLink_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( ChainLink_OnTarget ), new List() ); + e.Mobile.SendMessage( "Target the first of a sequence of doors to link." ); + } + + private static void ChainLink_OnTarget( Mobile from, object targeted, object state ) + { + BaseDoor door = targeted as BaseDoor; + + if ( door == null ) + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( ChainLink_OnTarget ), state ); + from.SendMessage( "That is not a door. Try again." ); + } + else + { + List list = (List)state; + + if ( list.Count > 0 && list[0] == door ) + { + if ( list.Count >= 2 ) + { + for ( int i = 0; i < list.Count; ++i ) + list[i].Link = list[(i + 1) % list.Count]; + + from.SendMessage( "The chain of doors have been linked." ); + } + else + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( ChainLink_OnTarget ), state ); + from.SendMessage( "You have not yet targeted two unique doors. Target the second door to link." ); + } + } + else if ( list.Contains( door ) ) + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( ChainLink_OnTarget ), state ); + from.SendMessage( "You have already targeted that door. Target another door, or retarget the first door to complete the chain." ); + } + else + { + list.Add( door ); + + from.BeginTarget( -1, false, TargetFlags.None, new TargetStateCallback( ChainLink_OnTarget ), state ); + + if ( list.Count == 1 ) + from.SendMessage( "Target the second door to link." ); + else + from.SendMessage( "Target another door to link. To complete the chain, retarget the first door." ); + } + } + } + + private static void EventSink_OpenDoorMacroUsed( OpenDoorMacroEventArgs args ) + { + Mobile m = args.Mobile; + + if ( m.Map != null ) + { + int x = m.X, y = m.Y; + + switch ( m.Direction & Direction.Mask ) + { + case Direction.North: --y; break; + case Direction.Right: ++x; --y; break; + case Direction.East: ++x; break; + case Direction.Down: ++x; ++y; break; + case Direction.South: ++y; break; + case Direction.Left: --x; ++y; break; + case Direction.West: --x; break; + case Direction.Up: --x; --y; break; + } + + Sector sector = m.Map.GetSector( x, y ); + + foreach ( Item item in sector.Items ) + { + if ( item.Location.X == x && item.Location.Y == y && (item.Z + item.ItemData.Height) > m.Z && (m.Z + 16) > item.Z && item is BaseDoor && m.CanSee( item ) && m.InLOS( item ) ) + { + if ( m.CheckAlive() ) + { + m.SendLocalizedMessage( 500024 ); // Opening door... + item.OnDoubleClick( m ); + } + + break; + } + } + } + } + + public static Point3D GetOffset( DoorFacing facing ) + { + return m_Offsets[(int)facing]; + } + + private class InternalTimer : Timer + { + private BaseDoor m_Door; + + public InternalTimer( BaseDoor door ) : base( TimeSpan.FromSeconds( 20.0 ), TimeSpan.FromSeconds( 10.0 ) ) + { + Priority = TimerPriority.OneSecond; + m_Door = door; + } + + protected override void OnTick() + { + if ( m_Door.Open && m_Door.IsFreeToClose() ) + m_Door.Open = false; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Locked + { + get + { + return m_Locked; + } + set + { + m_Locked = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public uint KeyValue + { + get + { + return m_KeyValue; + } + set + { + m_KeyValue = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Open + { + get + { + return m_Open; + } + set + { + if ( m_Open != value ) + { + m_Open = value; + + ItemID = m_Open ? m_OpenedID : m_ClosedID; + + if ( m_Open ) + Location = new Point3D( X + m_Offset.X, Y + m_Offset.Y, Z + m_Offset.Z ); + else + Location = new Point3D( X - m_Offset.X, Y - m_Offset.Y, Z - m_Offset.Z ); + + Effects.PlaySound( this, Map, m_Open ? m_OpenedSound : m_ClosedSound ); + + if ( m_Open ) + m_Timer.Start(); + else + m_Timer.Stop(); + } + } + } + + public bool CanClose() + { + if ( !m_Open ) + return true; + + Map map = Map; + + if ( map == null ) + return false; + + Point3D p = new Point3D( X - m_Offset.X, Y - m_Offset.Y, Z - m_Offset.Z ); + + return CheckFit( map, p, 16 ); + } + + private bool CheckFit( Map map, Point3D p, int height ) + { + if ( map == Map.Internal ) + return false; + + int x = p.X; + int y = p.Y; + int z = p.Z; + + Sector sector = map.GetSector( x, y ); + List items = sector.Items; + List mobs = sector.Mobiles; + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if ( !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint( x, y ) && !(item is BaseDoor) ) + { + ItemData id = item.ItemData; + bool surface = id.Surface; + bool impassable = id.Impassable; + + if ( (surface || impassable) && (item.Z + id.CalcHeight) > z && (z + height) > item.Z ) + return false; + } + } + + for ( int i = 0; i < mobs.Count; ++i ) + { + Mobile m = mobs[i]; + + if ( m.Location.X == x && m.Location.Y == y ) + { + if ( m.Hidden && m.AccessLevel > AccessLevel.Player ) + continue; + + if ( !m.Alive ) + continue; + + if ( (m.Z + 16) > z && (z + height) > m.Z ) + return false; + } + } + + return true; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int OpenedID + { + get + { + return m_OpenedID; + } + set + { + m_OpenedID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ClosedID + { + get + { + return m_ClosedID; + } + set + { + m_ClosedID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int OpenedSound + { + get + { + return m_OpenedSound; + } + set + { + m_OpenedSound = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ClosedSound + { + get + { + return m_ClosedSound; + } + set + { + m_ClosedSound = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Offset + { + get + { + return m_Offset; + } + set + { + m_Offset = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseDoor Link + { + get + { + if ( m_Link != null && m_Link.Deleted ) + m_Link = null; + + return m_Link; + } + set + { + m_Link = value; + } + } + + public virtual bool UseChainedFunctionality{ get{ return false; } } + + public List GetChain() + { + List list = new List(); + BaseDoor c = this; + + do + { + list.Add( c ); + c = c.Link; + } while ( c != null && !list.Contains( c ) ); + + return list; + } + + public bool IsFreeToClose() + { + if ( !UseChainedFunctionality ) + return CanClose(); + + List list = GetChain(); + + bool freeToClose = true; + + for ( int i = 0; freeToClose && i < list.Count; ++i ) + freeToClose = list[i].CanClose(); + + return freeToClose; + } + + public void OnTelekinesis( Mobile from ) + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5022 ); + Effects.PlaySound( Location, Map, 0x1F5 ); + + Use( from ); + } + + public virtual bool IsInside( Mobile from ) + { + return false; + } + + public virtual bool UseLocks() + { + return true; + } + + public virtual void Use( Mobile from ) + { + if ( m_Locked && !m_Open && UseLocks() ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502502 ); // That is locked, but you open it with your godly powers. + //from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, 502502, "", "" ) ); // That is locked, but you open it with your godly powers. + } + else if ( Key.ContainsKey( from.Backpack, this.KeyValue ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501282 ); // You quickly unlock, open, and relock the door + } + else if ( IsInside( from ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501280 ); // That is locked, but is usable from the inside. + } + else + { + if ( Hue == 0x44E && Map == Map.Malas ) // doom door into healer room in doom + this.SendLocalizedMessageTo( from, 1060014 ); // Only the dead may pass. + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502503 ); // That is locked. + + return; + } + } + + if ( m_Open && !IsFreeToClose() ) + return; + + if ( m_Open ) + OnClosed( from ); + else + OnOpened( from ); + + if ( UseChainedFunctionality ) + { + bool open = !m_Open; + + List list = GetChain(); + + for ( int i = 0; i < list.Count; ++i ) + list[i].Open = open; + } + else + { + Open = !m_Open; + + BaseDoor link = this.Link; + + if ( m_Open && link != null && !link.Open ) + link.Open = true; + } + } + + public virtual void OnOpened( Mobile from ) + { + } + + public virtual void OnClosed( Mobile from ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel == AccessLevel.Player && (/*!from.InLOS( this ) || */!from.InRange( GetWorldLocation(), 2 )) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else + Use( from ); + } + + public BaseDoor( int closedID, int openedID, int openedSound, int closedSound, Point3D offset ) : base( closedID ) + { + m_OpenedID = openedID; + m_ClosedID = closedID; + m_OpenedSound = openedSound; + m_ClosedSound = closedSound; + m_Offset = offset; + + m_Timer = new InternalTimer( this ); + + Movable = false; + } + + public BaseDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_KeyValue ); + + writer.Write( m_Open ); + writer.Write( m_Locked ); + writer.Write( m_OpenedID ); + writer.Write( m_ClosedID ); + writer.Write( m_OpenedSound ); + writer.Write( m_ClosedSound ); + writer.Write( m_Offset ); + writer.Write( m_Link ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_KeyValue = reader.ReadUInt(); + m_Open = reader.ReadBool(); + m_Locked = reader.ReadBool(); + m_OpenedID = reader.ReadInt(); + m_ClosedID = reader.ReadInt(); + m_OpenedSound = reader.ReadInt(); + m_ClosedSound = reader.ReadInt(); + m_Offset = reader.ReadPoint3D(); + m_Link = reader.ReadItem() as BaseDoor; + + m_Timer = new InternalTimer( this ); + + if ( m_Open ) + m_Timer.Start(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Doors/Doors.cs b/Scripts/Items/Construction/Doors/Doors.cs new file mode 100644 index 0000000..1edf210 --- /dev/null +++ b/Scripts/Items/Construction/Doors/Doors.cs @@ -0,0 +1,359 @@ +using System; + +namespace Server.Items +{ + public enum DoorFacing + { + WestCW, + EastCCW, + WestCCW, + EastCW, + SouthCW, + NorthCCW, + SouthCCW, + NorthCW, + //Sliding Doors + SouthSW, + SouthSE, + WestSS, + WestSN + } + + public class IronGateShort : BaseDoor + { + [Constructable] + public IronGateShort( DoorFacing facing ) : base( 0x84c + (2 * (int)facing), 0x84d + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public IronGateShort( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class IronGate : BaseDoor + { + [Constructable] + public IronGate( DoorFacing facing ) : base( 0x824 + (2 * (int)facing), 0x825 + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public IronGate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightWoodGate : BaseDoor + { + [Constructable] + public LightWoodGate( DoorFacing facing ) : base( 0x839 + (2 * (int)facing), 0x83A + (2 * (int)facing), 0xEB, 0xF2, BaseDoor.GetOffset( facing ) ) + { + } + + public LightWoodGate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkWoodGate : BaseDoor + { + [Constructable] + public DarkWoodGate( DoorFacing facing ) : base( 0x866 + (2 * (int)facing), 0x867 + (2 * (int)facing), 0xEB, 0xF2, BaseDoor.GetOffset( facing ) ) + { + } + + public DarkWoodGate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MetalDoor : BaseDoor + { + [Constructable] + public MetalDoor( DoorFacing facing ) : base( 0x675 + (2 * (int)facing), 0x676 + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public MetalDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BarredMetalDoor : BaseDoor + { + [Constructable] + public BarredMetalDoor( DoorFacing facing ) : base( 0x685 + (2 * (int)facing), 0x686 + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public BarredMetalDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BarredMetalDoor2 : BaseDoor + { + [Constructable] + public BarredMetalDoor2( DoorFacing facing ) : base( 0x1FED + (2 * (int)facing), 0x1FEE + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public BarredMetalDoor2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RattanDoor : BaseDoor + { + [Constructable] + public RattanDoor( DoorFacing facing ) : base( 0x695 + (2 * (int)facing), 0x696 + (2 * (int)facing), 0xEB, 0xF2, BaseDoor.GetOffset( facing ) ) + { + } + + public RattanDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkWoodDoor : BaseDoor + { + [Constructable] + public DarkWoodDoor( DoorFacing facing ) : base( 0x6A5 + (2 * (int)facing), 0x6A6 + (2 * (int)facing), 0xEA, 0xF1, BaseDoor.GetOffset( facing ) ) + { + } + + public DarkWoodDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumWoodDoor : BaseDoor + { + [Constructable] + public MediumWoodDoor( DoorFacing facing ) : base( 0x6B5 + (2 * (int)facing), 0x6B6 + (2 * (int)facing), 0xEA, 0xF1, BaseDoor.GetOffset( facing ) ) + { + } + + public MediumWoodDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MetalDoor2 : BaseDoor + { + [Constructable] + public MetalDoor2( DoorFacing facing ) : base( 0x6C5 + (2 * (int)facing), 0x6C6 + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public MetalDoor2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightWoodDoor : BaseDoor + { + [Constructable] + public LightWoodDoor( DoorFacing facing ) : base( 0x6D5 + (2 * (int)facing), 0x6D6 + (2 * (int)facing), 0xEA, 0xF1, BaseDoor.GetOffset( facing ) ) + { + } + + public LightWoodDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StrongWoodDoor : BaseDoor + { + [Constructable] + public StrongWoodDoor( DoorFacing facing ) : base( 0x6E5 + (2 * (int)facing), 0x6E6 + (2 * (int)facing), 0xEA, 0xF1, BaseDoor.GetOffset( facing ) ) + { + } + + public StrongWoodDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Doors/HouseDoors.cs b/Scripts/Items/Construction/Doors/HouseDoors.cs new file mode 100644 index 0000000..2d03239 --- /dev/null +++ b/Scripts/Items/Construction/Doors/HouseDoors.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Gumps; +using System.Collections.Generic; +using Server.ContextMenus; + +namespace Server.Items +{ + public class MetalHouseDoor : BaseHouseDoor + { + [Constructable] + public MetalHouseDoor( DoorFacing facing ) : base( facing, 0x675 + (2 * (int)facing), 0x676 + (2 * (int)facing), 0xEC, 0xF3, BaseDoor.GetOffset( facing ) ) + { + } + + public MetalHouseDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkWoodHouseDoor : BaseHouseDoor + { + [Constructable] + public DarkWoodHouseDoor( DoorFacing facing ) : base( facing, 0x6A5 + (2 * (int)facing), 0x6A6 + (2 * (int)facing), 0xEA, 0xF1, BaseDoor.GetOffset( facing ) ) + { + } + + public DarkWoodHouseDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GenericHouseDoor : BaseHouseDoor + { + [Constructable] + public GenericHouseDoor( DoorFacing facing, int baseItemID, int openedSound, int closedSound ) : this( facing, baseItemID, openedSound, closedSound, true ) + { + } + + [Constructable] + public GenericHouseDoor( DoorFacing facing, int baseItemID, int openedSound, int closedSound, bool autoAdjust ) + : base( facing, baseItemID + (autoAdjust ? (2 * (int)facing) : 0), baseItemID + 1 + (autoAdjust ? (2 * (int)facing) : 0), openedSound, closedSound, BaseDoor.GetOffset( facing ) ) + { + } + + public GenericHouseDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class BaseHouseDoor : BaseDoor, ISecurable + { + private DoorFacing m_Facing; + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public DoorFacing Facing + { + get{ return m_Facing; } + set{ m_Facing = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public BaseHouseDoor( DoorFacing facing, int closedID, int openedID, int openedSound, int closedSound, Point3D offset ) : base( closedID, openedID, openedSound, closedSound, offset ) + { + m_Facing = facing; + m_Level = SecureLevel.Anyone; + } + + public BaseHouse FindHouse() + { + Point3D loc; + + if ( Open ) + loc = new Point3D( X - Offset.X, Y - Offset.Y, Z - Offset.Z ); + else + loc = this.Location; + + return BaseHouse.FindHouseAt( loc, Map, 20 ); + } + + public bool CheckAccess( Mobile m ) + { + BaseHouse house = FindHouse(); + + if ( house == null ) + return false; + + if ( !house.IsAosRules ) + return true; + + if ( house.Public ? house.IsBanned( m ) : !house.HasAccess( m ) ) + return false; + + return house.HasSecureAccess( m, m_Level ); + } + + public override void OnOpened( Mobile from ) + { + BaseHouse house = FindHouse(); + + if ( house != null && house.IsFriend( from ) && from.AccessLevel == AccessLevel.Player && house.RefreshDecay() ) + from.SendLocalizedMessage( 1043293 ); // Your house's age and contents have been refreshed. + + if ( house != null && house.Public && !house.IsFriend( from ) ) + house.Visits++; + } + + public override bool UseLocks() + { + BaseHouse house = FindHouse(); + + return ( house == null || !house.IsAosRules ); + } + + public override void Use( Mobile from ) + { + if ( !CheckAccess( from ) ) + from.SendLocalizedMessage( 1061637 ); // You are not allowed to access this. + else + base.Use( from ); + } + + public BaseHouseDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Level ); + + writer.Write( (int) m_Facing ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + if ( version < 1 ) + m_Level = SecureLevel.Anyone; + + m_Facing = (DoorFacing)reader.ReadInt(); + break; + } + } + } + + public override bool IsInside( Mobile from ) + { + int x,y,w,h; + + const int r = 2; + const int bs = r*2+1; + const int ss = r+1; + + switch ( m_Facing ) + { + case DoorFacing.WestCW: + case DoorFacing.EastCCW: x = -r; y = -r; w = bs; h = ss; break; + + case DoorFacing.EastCW: + case DoorFacing.WestCCW: x = -r; y = 0; w = bs; h = ss; break; + + case DoorFacing.SouthCW: + case DoorFacing.NorthCCW: x = -r; y = -r; w = ss; h = bs; break; + + case DoorFacing.NorthCW: + case DoorFacing.SouthCCW: x = 0; y = -r; w = ss; h = bs; break; + + //No way to test the 'insideness' of SE Sliding doors on OSI, so leaving them default to false until furthur information gained + + default: return false; + } + + int rx = from.X - X; + int ry = from.Y - Y; + int az = Math.Abs( from.Z - Z ); + + return ( rx >= x && rx < (x+w) && ry >= y && ry < (y+h) && az <= 4 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Doors/Portcullis.cs b/Scripts/Items/Construction/Doors/Portcullis.cs new file mode 100644 index 0000000..b55f12a --- /dev/null +++ b/Scripts/Items/Construction/Doors/Portcullis.cs @@ -0,0 +1,60 @@ +using System; + +namespace Server.Items +{ + public class PortcullisNS : BaseDoor + { + public override bool UseChainedFunctionality{ get{ return true; } } + + [Constructable] + public PortcullisNS() : base( 0x6F5, 0x6F5, 0xF0, 0xEF, new Point3D( 0, 0, 20 ) ) + { + } + + public PortcullisNS( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PortcullisEW : BaseDoor + { + public override bool UseChainedFunctionality{ get{ return true; } } + + [Constructable] + public PortcullisEW() : base( 0x6F6, 0x6F6, 0xF0, 0xEF, new Point3D( 0, 0, 20 ) ) + { + } + + public PortcullisEW( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Doors/SecretDoors.cs b/Scripts/Items/Construction/Doors/SecretDoors.cs new file mode 100644 index 0000000..986c92a --- /dev/null +++ b/Scripts/Items/Construction/Doors/SecretDoors.cs @@ -0,0 +1,160 @@ +using System; + +namespace Server.Items +{ + public class SecretStoneDoor1 : BaseDoor + { + [Constructable] + public SecretStoneDoor1( DoorFacing facing ) : base( 0xE8 + (2 * (int)facing), 0xE9 + (2 * (int)facing), 0xED, 0xF4, BaseDoor.GetOffset( facing ) ) + { + } + + public SecretStoneDoor1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretDungeonDoor : BaseDoor + { + [Constructable] + public SecretDungeonDoor( DoorFacing facing ) : base( 0x314 + (2 * (int)facing), 0x315 + (2 * (int)facing), 0xED, 0xF4, BaseDoor.GetOffset( facing ) ) + { + } + + public SecretDungeonDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretStoneDoor2 : BaseDoor + { + [Constructable] + public SecretStoneDoor2( DoorFacing facing ) : base( 0x324 + (2 * (int)facing), 0x325 + (2 * (int)facing), 0xED, 0xF4, BaseDoor.GetOffset( facing ) ) + { + } + + public SecretStoneDoor2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretWoodenDoor : BaseDoor + { + [Constructable] + public SecretWoodenDoor( DoorFacing facing ) : base( 0x334 + (2 * (int)facing), 0x335 + (2 * (int)facing), 0xED, 0xF4, BaseDoor.GetOffset( facing ) ) + { + } + + public SecretWoodenDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretLightWoodDoor : BaseDoor + { + [Constructable] + public SecretLightWoodDoor( DoorFacing facing ) : base( 0x344 + (2 * (int)facing), 0x345 + (2 * (int)facing), 0xED, 0xF4, BaseDoor.GetOffset( facing ) ) + { + } + + public SecretLightWoodDoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SecretStoneDoor3 : BaseDoor + { + [Constructable] + public SecretStoneDoor3( DoorFacing facing ) : base( 0x354 + (2 * (int)facing), 0x355 + (2 * (int)facing), 0xED, 0xF4, BaseDoor.GetOffset( facing ) ) + { + } + + public SecretStoneDoor3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) // Default Serialize method + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) // Default Deserialize method + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Floors/Floors.cs b/Scripts/Items/Construction/Floors/Floors.cs new file mode 100644 index 0000000..2df48b7 --- /dev/null +++ b/Scripts/Items/Construction/Floors/Floors.cs @@ -0,0 +1,628 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseFloor : Item + { + public BaseFloor( int itemID, int count ) : base( Utility.Random( itemID, count ) ) + { + Movable = false; + } + + public BaseFloor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StonePaversLight : BaseFloor + { + [Constructable] + public StonePaversLight() : base( 0x519, 4 ) + { + } + + public StonePaversLight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StonePaversMedium : BaseFloor + { + [Constructable] + public StonePaversMedium() : base( 0x51D, 4 ) + { + } + + public StonePaversMedium( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StonePaversDark : BaseFloor + { + [Constructable] + public StonePaversDark() : base( 0x521, 4 ) + { + } + + public StonePaversDark( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreyFlagstones : BaseFloor + { + [Constructable] + public GreyFlagstones() : base( 0x4FC, 4 ) + { + } + + public GreyFlagstones( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SandFlagstones : BaseFloor + { + [Constructable] + public SandFlagstones() : base( 0x500, 4 ) + { + } + + public SandFlagstones( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MarbleFloor : BaseFloor + { + [Constructable] + public MarbleFloor() : base( 0x50D, 2 ) + { + } + + public MarbleFloor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenMarbleFloor : BaseFloor + { + [Constructable] + public GreenMarbleFloor() : base( 0x50F, 2 ) + { + } + + public GreenMarbleFloor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreyMarbleFloor : BaseFloor + { + [Constructable] + public GreyMarbleFloor() : base( 0x511, 4 ) + { + } + + public GreyMarbleFloor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CobblestonesFloor : BaseFloor + { + [Constructable] + public CobblestonesFloor() : base( 0x515, 4 ) + { + } + + public CobblestonesFloor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SandstoneFloorN : BaseFloor + { + [Constructable] + public SandstoneFloorN() : base( 0x525, 4 ) + { + } + + public SandstoneFloorN( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SandstoneFloorW : BaseFloor + { + [Constructable] + public SandstoneFloorW() : base( 0x529, 4 ) + { + } + + public SandstoneFloorW( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkSandstoneFloorN : BaseFloor + { + [Constructable] + public DarkSandstoneFloorN() : base( 0x52F, 4 ) + { + } + + public DarkSandstoneFloorN( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkSandstoneFloorW : BaseFloor + { + [Constructable] + public DarkSandstoneFloorW() : base( 0x533, 4 ) + { + } + + public DarkSandstoneFloorW( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BricksFloor1 : BaseFloor + { + [Constructable] + public BricksFloor1() : base( 0x4E2, 8 ) + { + } + + public BricksFloor1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BricksFloor2 : BaseFloor + { + [Constructable] + public BricksFloor2() : base( 0x537, 4 ) + { + } + + public BricksFloor2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CaveFloorCenter : BaseFloor + { + [Constructable] + public CaveFloorCenter() : base( 0x53B, 4 ) + { + } + + public CaveFloorCenter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CaveFloorSouth : BaseFloor + { + [Constructable] + public CaveFloorSouth() : base( 0x541, 3 ) + { + } + + public CaveFloorSouth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CaveFloorEast : BaseFloor + { + [Constructable] + public CaveFloorEast() : base( 0x544, 3 ) + { + } + + public CaveFloorEast( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CaveFloorWest : BaseFloor + { + [Constructable] + public CaveFloorWest() : base( 0x54A, 3 ) + { + } + + public CaveFloorWest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CaveFloorNorth : BaseFloor + { + [Constructable] + public CaveFloorNorth() : base( 0x54D, 3 ) + { + } + + public CaveFloorNorth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MarblePavers : BaseFloor + { + [Constructable] + public MarblePavers() : base( 0x495, 4 ) + { + } + + public MarblePavers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BlueSlateFloorCenter : BaseFloor + { + [Constructable] + public BlueSlateFloorCenter() : base( 0x49B, 1 ) + { + } + + public BlueSlateFloorCenter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreySlateFloor : BaseFloor + { + [Constructable] + public GreySlateFloor() : base( 0x49C, 1 ) + { + } + + public GreySlateFloor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/BarrelParts.cs b/Scripts/Items/Construction/Misc/BarrelParts.cs new file mode 100644 index 0000000..20699c0 --- /dev/null +++ b/Scripts/Items/Construction/Misc/BarrelParts.cs @@ -0,0 +1,115 @@ +using System; + +namespace Server.Items +{ + public class BarrelLid : Item + { + [Constructable] + public BarrelLid() : base(0x1DB8) + { + Weight = 2; + } + + public BarrelLid(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1EB1, 0x1EB2, 0x1EB3, 0x1EB4)] + public class BarrelStaves : Item + { + [Constructable] + public BarrelStaves() : base(0x1EB1) + { + Weight = 1; + } + + public BarrelStaves(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BarrelHoops : Item + { + public override int LabelNumber { get { return 1011228; } } // Barrel hoops + + [Constructable] + public BarrelHoops() : base(0x1DB7) + { + Weight = 5; + } + + public BarrelHoops(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BarrelTap : Item + { + [Constructable] + public BarrelTap() : base(0x1004) + { + Weight = 1; + } + + public BarrelTap(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/Easle.cs b/Scripts/Items/Construction/Misc/Easle.cs new file mode 100644 index 0000000..bc0c18f --- /dev/null +++ b/Scripts/Items/Construction/Misc/Easle.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Items +{ + [Flipable(0xF65, 0xF67, 0xF69)] + public class Easle : Item + { + [Constructable] + public Easle() : base(0xF65) + { + Weight = 25.0; + } + + public Easle(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 10.0 ) + Weight = 25.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/MeltedWax.cs b/Scripts/Items/Construction/Misc/MeltedWax.cs new file mode 100644 index 0000000..45ec0cc --- /dev/null +++ b/Scripts/Items/Construction/Misc/MeltedWax.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class MeltedWax : Item + { + public override int LabelNumber{ get{ return 1016492; } } // melted wax + + [Constructable] + public MeltedWax() : base( 0x122A ) + { + Movable = false; + Hue = 0x835; + } + + public MeltedWax(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/MusicStand.cs b/Scripts/Items/Construction/Misc/MusicStand.cs new file mode 100644 index 0000000..b81e72f --- /dev/null +++ b/Scripts/Items/Construction/Misc/MusicStand.cs @@ -0,0 +1,66 @@ +using System; + +namespace Server.Items +{ + [Flipable(0xEBB, 0xEBC)] + public class TallMusicStand : Item + { + [Constructable] + public TallMusicStand() : base(0xEBB) + { + Weight = 10.0; + } + + public TallMusicStand(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 8.0 ) + Weight = 10.0; + } + } + + [Flipable(0xEB6,0xEB8)] + public class ShortMusicStand : Item + { + [Constructable] + public ShortMusicStand() : base(0xEB6) + { + Weight = 10.0; + } + + public ShortMusicStand(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 10.0; + } + } +} diff --git a/Scripts/Items/Construction/Misc/Obelisk.cs b/Scripts/Items/Construction/Misc/Obelisk.cs new file mode 100644 index 0000000..e48d89f --- /dev/null +++ b/Scripts/Items/Construction/Misc/Obelisk.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Obelisk : Item + { + public override int LabelNumber{ get{ return 1016474; } } // an obelisk + + [Constructable] + public Obelisk() : base(0x1184) + { + Movable = false; + } + + public Obelisk(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/Screens.cs b/Scripts/Items/Construction/Misc/Screens.cs new file mode 100644 index 0000000..3e6ae3c --- /dev/null +++ b/Scripts/Items/Construction/Misc/Screens.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x24D0, 0x24D1, 0x24D2, 0x24D3, 0x24D4 )] + public class BambooScreen : Item + { + [Constructable] + public BambooScreen() : base(0x24D0) + { + Weight = 20.0; + } + + public BambooScreen(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + [Flipable( 0x24CB, 0x24CC, 0x24CD, 0x24CE, 0x24CF )] + public class ShojiScreen : Item + { + [Constructable] + public ShojiScreen() : base(0x24CB) + { + Weight = 20.0; + } + + public ShojiScreen(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/Statues.cs b/Scripts/Items/Construction/Misc/Statues.cs new file mode 100644 index 0000000..2fe7ff1 --- /dev/null +++ b/Scripts/Items/Construction/Misc/Statues.cs @@ -0,0 +1,350 @@ +using System; + +namespace Server.Items +{ + public class StatueSouth : Item + { + [Constructable] + public StatueSouth() : base(0x139A) + { + Weight = 10; + } + + public StatueSouth(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatueSouth2 : Item + { + [Constructable] + public StatueSouth2() : base(0x1227) + { + Weight = 10; + } + + public StatueSouth2(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatueNorth : Item + { + [Constructable] + public StatueNorth() : base(0x139B) + { + Weight = 10; + } + + public StatueNorth(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatueWest : Item + { + [Constructable] + public StatueWest() : base(0x1226) + { + Weight = 10; + } + + public StatueWest(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatueEast : Item + { + [Constructable] + public StatueEast() : base(0x139C) + { + Weight = 10; + } + + public StatueEast(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatueEast2 : Item + { + [Constructable] + public StatueEast2() : base(0x1224) + { + Weight = 10; + } + + public StatueEast2(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatueSouthEast : Item + { + [Constructable] + public StatueSouthEast() : base(0x1225) + { + Weight = 10; + } + + public StatueSouthEast(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BustSouth : Item + { + [Constructable] + public BustSouth() : base(0x12CB) + { + Weight = 10; + } + + public BustSouth(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BustEast : Item + { + [Constructable] + public BustEast() : base(0x12CA) + { + Weight = 10; + } + + public BustEast(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatuePegasus : Item + { + [Constructable] + public StatuePegasus() : base(0x139D) + { + Weight = 10; + } + + public StatuePegasus(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class StatuePegasus2 : Item + { + [Constructable] + public StatuePegasus2() : base(0x1228) + { + Weight = 10; + } + + public StatuePegasus2(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class SmallTowerSculpture : Item + { + [Constructable] + public SmallTowerSculpture() : base(0x241A) + { + Weight = 20.0; + } + + public SmallTowerSculpture(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/Vase.cs b/Scripts/Items/Construction/Misc/Vase.cs new file mode 100644 index 0000000..50300d5 --- /dev/null +++ b/Scripts/Items/Construction/Misc/Vase.cs @@ -0,0 +1,85 @@ +using System; + +namespace Server.Items +{ + public class Vase : Item + { + [Constructable] + public Vase() : base( 0xB46 ) + { + Weight = 10; + } + + public Vase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeVase : Item + { + [Constructable] + public LargeVase() : base( 0xB45 ) + { + Weight = 15; + } + + public LargeVase( Serial serial ) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallUrn : Item + { + [Constructable] + public SmallUrn() : base( 0x241C ) + { + Weight = 20.0; + } + + public SmallUrn(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write( (int)0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Misc/Vines.cs b/Scripts/Items/Construction/Misc/Vines.cs new file mode 100644 index 0000000..be43bc8 --- /dev/null +++ b/Scripts/Items/Construction/Misc/Vines.cs @@ -0,0 +1,42 @@ +using System; + +namespace Server.Items +{ + public class Vines : Item + { + [Constructable] + public Vines() : this( Utility.Random( 8 ) ) + { + } + + [Constructable] + public Vines( int v ) : base( 0xCEB ) + { + if ( v < 0 || v > 7 ) + v = 0; + + ItemID += v; + Weight = 1.0; + } + + public Vines(Serial serial) : base(serial) + { + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Ruined/RuinedItemSingle.cs b/Scripts/Items/Construction/Ruined/RuinedItemSingle.cs new file mode 100644 index 0000000..f3e75aa --- /dev/null +++ b/Scripts/Items/Construction/Ruined/RuinedItemSingle.cs @@ -0,0 +1,315 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xC10, 0xC11 )] + public class RuinedFallenChairA : Item + { + [Constructable] + public RuinedFallenChairA() : base( 0xC10 ) + { + Movable = false; + } + + public RuinedFallenChairA( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + [FlipableAttribute( 0xC13, 0xC12 )] + public class RuinedArmoire : Item + { + [Constructable] + public RuinedArmoire() : base( 0xC13 ) + { + Movable = false; + } + + public RuinedArmoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + [FlipableAttribute( 0xC14, 0xC15 )] + public class RuinedBookcase : Item + { + [Constructable] + public RuinedBookcase() : base( 0xC14 ) + { + Movable = false; + } + + public RuinedBookcase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + public class RuinedBooks : Item + { + [Constructable] + public RuinedBooks() : base( 0xC16 ) + { + Movable = false; + } + + public RuinedBooks( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC17, 0xC18 )] + public class CoveredChair : Item + { + [Constructable] + public CoveredChair() : base( 0xC17 ) + { + Movable = false; + } + + public CoveredChair( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + [FlipableAttribute( 0xC19, 0xC1A )] + public class RuinedFallenChairB : Item + { + [Constructable] + public RuinedFallenChairB() : base( 0xC19 ) + { + Movable = false; + } + + public RuinedFallenChairB( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } + + [FlipableAttribute( 0xC1B, 0xC1C, 0xC1E, 0xC1D )] + public class RuinedChair : Item + { + [Constructable] + public RuinedChair() : base( 0xC1B ) + { + Movable = false; + } + + public RuinedChair( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RuinedClock : Item + { + [Constructable] + public RuinedClock() : base( 0xC1F ) + { + Movable = false; + } + + public RuinedClock( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC24, 0xC25 )] + public class RuinedDrawers : Item + { + [Constructable] + public RuinedDrawers() : base( 0xC24 ) + { + Movable = false; + } + + public RuinedDrawers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RuinedPainting : Item + { + [Constructable] + public RuinedPainting() : base( 0xC2C ) + { + Movable = false; + } + + public RuinedPainting( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC2D, 0xC2F, 0xC2E, 0xC30 )] + public class WoodDebris : Item + { + [Constructable] + public WoodDebris() : base( 0xC2D ) + { + Movable = false; + } + + public WoodDebris( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Signs/BaseSign.cs b/Scripts/Items/Construction/Signs/BaseSign.cs new file mode 100644 index 0000000..0743923 --- /dev/null +++ b/Scripts/Items/Construction/Signs/BaseSign.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Prompts; + +namespace Server.Items +{ + public abstract class BaseSign : Item + { + public BaseSign( int dispID ) : base( dispID ) + { + Movable = false; + } + + public BaseSign( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + // Scriptiz : pour renommer les panneaux ! + protected class RenamePrompt : Prompt + { + private BaseSign m_Sign; + + public RenamePrompt(BaseSign sign) + { + m_Sign = sign; + } + + public override void OnResponse(Mobile from, string text) + { + if (m_Sign.Deleted || !m_Sign.IsChildOf(from.Backpack)) + { + from.SendMessage("Mettez le panneau dans votre sac pour y graver quelque chose"); + return; + } + + m_Sign.Name = Utility.FixHtml(text); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Signs/LocalizedSign.cs b/Scripts/Items/Construction/Signs/LocalizedSign.cs new file mode 100644 index 0000000..b97b1d7 --- /dev/null +++ b/Scripts/Items/Construction/Signs/LocalizedSign.cs @@ -0,0 +1,56 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LocalizedSign : Sign + { + private int m_LabelNumber; + + public override int LabelNumber{ get{ return m_LabelNumber; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Number{ get{ return m_LabelNumber; } set{ m_LabelNumber = value; InvalidateProperties(); } } + + [Constructable] + public LocalizedSign( SignType type, SignFacing facing, int labelNumber ) : base( ( 0xB95 + (2 * (int)type) ) + (int)facing ) + { + m_LabelNumber = labelNumber; + } + + [Constructable] + public LocalizedSign( int itemID, int labelNumber ) : base( itemID ) + { + m_LabelNumber = labelNumber; + } + + public LocalizedSign( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_LabelNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Signs/Sign.cs b/Scripts/Items/Construction/Signs/Sign.cs new file mode 100644 index 0000000..c3ad26f --- /dev/null +++ b/Scripts/Items/Construction/Signs/Sign.cs @@ -0,0 +1,107 @@ +using System; +using Server; + +namespace Server.Items +{ + public enum SignFacing + { + North, + West + } + + public enum SignType + { + Library, + DarkWoodenPost, + LightWoodenPost, + MetalPostC, + MetalPostB, + MetalPostA, + MetalPost, + Bakery, + Tailor, + Tinker, + Butcher, + Healer, + Mage, + Woodworker, + Customs, + Inn, + Shipwright, + Stables, + BarberShop, + Bard, + Fletcher, + Armourer, + Jeweler, + Tavern, + ReagentShop, + Blacksmith, + Painter, + Provisioner, + Bowyer, + WoodenSign, + BrassSign, + ArmamentsGuild, + ArmourersGuild, + BlacksmithsGuild, + WeaponsGuild, + BardicGuild, + BartersGuild, + ProvisionersGuild, + TradersGuild, + CooksGuild, + HealersGuild, + MagesGuild, + SorcerersGuild, + IllusionistGuild, + MinersGuild, + ArchersGuild, + SeamensGuild, + FishermensGuild, + SailorsGuild, + ShipwrightsGuild, + TailorsGuild, + ThievesGuild, + RoguesGuild, + AssassinsGuild, + TinkersGuild, + WarriorsGuild, + CavalryGuild, + FightersGuild, + MerchantsGuild, + Bank, + Theatre + } + + public class Sign : BaseSign + { + [Constructable] + public Sign( SignType type, SignFacing facing ) : base( ( 0xB95 + (2 * (int)type) ) + (int)facing ) + { + } + + [Constructable] + public Sign( int itemID ) : base( itemID ) + { + } + + public Sign( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Signs/SubtextSign.cs b/Scripts/Items/Construction/Signs/SubtextSign.cs new file mode 100644 index 0000000..7db659f --- /dev/null +++ b/Scripts/Items/Construction/Signs/SubtextSign.cs @@ -0,0 +1,70 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SubtextSign : Sign + { + private string m_Subtext; + + [CommandProperty(AccessLevel.GameMaster)] + public string Subtext + { + get { return m_Subtext; } + set { m_Subtext = value; InvalidateProperties(); } + } + + [Constructable] + public SubtextSign(SignType type, SignFacing facing, string subtext) + : base(type, facing) + { + m_Subtext = subtext; + } + + [Constructable] + public SubtextSign(int itemID, string subtext) + : base(itemID) + { + m_Subtext = subtext; + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (!String.IsNullOrEmpty(m_Subtext)) + LabelTo(from, m_Subtext); + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + if (!String.IsNullOrEmpty(m_Subtext)) + list.Add(m_Subtext); + } + + public SubtextSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + + writer.Write(m_Subtext); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Subtext = reader.ReadString(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Tables/Tables.cs b/Scripts/Items/Construction/Tables/Tables.cs new file mode 100644 index 0000000..dd9c915 --- /dev/null +++ b/Scripts/Items/Construction/Tables/Tables.cs @@ -0,0 +1,438 @@ +using System; + +namespace Server.Items +{ + public class ElegantLowTable : Item + { + [Constructable] + public ElegantLowTable() : base(0x2819) + { + Weight = 1.0; + } + + public ElegantLowTable(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + public class PlainLowTable : Item + { + [Constructable] + public PlainLowTable() : base(0x281A) + { + Weight = 1.0; + } + + public PlainLowTable(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + [Flipable(0xB90,0xB7D)] + public class LargeTable : Item + { + [Constructable] + public LargeTable() : base(0xB90) + { + Weight = 1.0; + } + + public LargeTable(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 4.0 ) + Weight = 1.0; + } + } + + [Flipable(0xB35,0xB34)] + public class Nightstand : Item + { + [Constructable] + public Nightstand() : base(0xB35) + { + Weight = 1.0; + } + + public Nightstand(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 4.0 ) + Weight = 1.0; + } + } + + [Flipable(0xB8F,0xB7C)] + public class YewWoodTable : Item + { + [Constructable] + public YewWoodTable() : base(0xB8F) + { + Weight = 1.0; + } + + public YewWoodTable(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 4.0 ) + Weight = 1.0; + } + + } + // Vinds : ajout des tables avec runner. existent d�ja sous forme static ou addon. Je pr�fere sous forme d'item standard pour les pjs. + + public class TableRunnerPurple : Item + { + [Constructable] + public TableRunnerPurple() + : base(0x118b) + { + Weight = 1.0; + } + + public TableRunnerPurple(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + public class TableRunnerBlue : Item + { + [Constructable] + public TableRunnerBlue() + : base(0x118c) + { + Weight = 1.0; + } + + public TableRunnerBlue(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + + public class TableRunnerRed : Item + { + [Constructable] + public TableRunnerRed() + : base(0x118d) + { + Weight = 1.0; + } + + public TableRunnerRed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + public class TableRunnerOrange : Item + { + [Constructable] + public TableRunnerOrange() + : base(0x118e) + { + Weight = 1.0; + } + + public TableRunnerOrange(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + [Flipable(0x118F, 0x1191)] + public class TabletteRunner : Item + { + [Constructable] + public TabletteRunner() + : base(0x118f) + { + Name = "petite table avec traverse"; + Weight = 1.0; + } + + public TabletteRunner(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + [Flipable(0x1192, 0x1190)] + public class ExtTabletteRunner : Item + { + [Constructable] + public ExtTabletteRunner() + : base(0x1190) + { + Name = "Rallonge avec traverse"; + Weight = 1.0; + } + + public ExtTabletteRunner(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + [Flipable(0x1667, 0x166A)] + public class TableLongRunnerW : Item + { + [Constructable] + public TableLongRunnerW() + : base(0x1667) + { + Name = "Table avec traverse"; + Weight = 1.0; + } + + public TableLongRunnerW(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + [Flipable(0x1668, 0x166b)] + public class TableLongRunnerC : Item + { + [Constructable] + public TableLongRunnerC() + : base(0x1668) + { + Name = "Table avec traverse"; + Weight = 1.0; + } + + public TableLongRunnerC(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + [Flipable(0x1669, 0x166c)] + public class TableLongRunnerE : Item + { + [Constructable] + public TableLongRunnerE() + : base(0x1669) + { + Name = "Table avec traverse"; + Weight = 1.0; + } + + public TableLongRunnerE(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + + + +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Tables/WritingTable.cs b/Scripts/Items/Construction/Tables/WritingTable.cs new file mode 100644 index 0000000..4123d85 --- /dev/null +++ b/Scripts/Items/Construction/Tables/WritingTable.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Items +{ + [Flipable(0xB4A,0xB49, 0xB4B, 0xB4C)] + public class WritingTable : Item + { + [Constructable] + public WritingTable() : base(0xB4A) + { + Weight = 1.0; + } + + public WritingTable(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 4.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Walls/BaseWall.cs b/Scripts/Items/Construction/Walls/BaseWall.cs new file mode 100644 index 0000000..d772845 --- /dev/null +++ b/Scripts/Items/Construction/Walls/BaseWall.cs @@ -0,0 +1,30 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseWall : Item + { + public BaseWall( int itemID ) : base( itemID ) + { + Movable = false; + } + + public BaseWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Walls/DarkWoodWall.cs b/Scripts/Items/Construction/Walls/DarkWoodWall.cs new file mode 100644 index 0000000..c7a1732 --- /dev/null +++ b/Scripts/Items/Construction/Walls/DarkWoodWall.cs @@ -0,0 +1,54 @@ +using System; + +namespace Server.Items +{ + public enum DarkWoodWallTypes + { + Corner, + SouthWall, + EastWall, + CornerPost, + EastDoorFrame, + SouthDoorFrame, + WestDoorFrame, + NorthDoorFrame, + SouthWindow, + EastWindow, + CornerMedium, + EastWallMedium, + SouthWallMedium, + CornerPostMedium, + CornerShort, + EastWallShort, + SouthWallShort, + CornerPostShort, + SouthWallVShort, + EastWallVShort + } + + public class DarkWoodWall : BaseWall + { + [Constructable] + public DarkWoodWall( DarkWoodWallTypes type ) : base( 0x0006 + (int)type ) + { + } + + public DarkWoodWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Walls/ThickGrayStoneWall.cs b/Scripts/Items/Construction/Walls/ThickGrayStoneWall.cs new file mode 100644 index 0000000..46eb715 --- /dev/null +++ b/Scripts/Items/Construction/Walls/ThickGrayStoneWall.cs @@ -0,0 +1,64 @@ +/**************************************** + * NAME : Thick Gray Stone Wall * + * SCRIPT : ThickGrayStoneWall.cs * + * VERSION : v1.00 * + * CREATOR : Mans Sjoberg (Allmight) * + * CREATED : 10-07.2002 * + * **************************************/ + +using System; + +namespace Server.Items +{ + public enum ThickGrayStoneWallTypes + { + WestArch, + NorthArch, + SouthArchTop, + EastArchTop, + EastArch, + SouthArch, + Wall1, + Wall2, + Wall3, + SouthWindow, + Wall4, + EastWindow, + WestArch2, + NorthArch2, + SouthArchTop2, + EastArchTop2, + EastArch2, + SouthArch2, + SWArchEdge2, + SouthWindow2, + NEArchEdge2, + EastWindow2 + } + + public class ThickGrayStoneWall : BaseWall + { + [Constructable] + public ThickGrayStoneWall( ThickGrayStoneWallTypes type) : base( 0x007A + (int)type ) + { + } + + public ThickGrayStoneWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Walls/ThinBrickWall.cs b/Scripts/Items/Construction/Walls/ThinBrickWall.cs new file mode 100644 index 0000000..4fd79b5 --- /dev/null +++ b/Scripts/Items/Construction/Walls/ThinBrickWall.cs @@ -0,0 +1,70 @@ +using System; + +namespace Server.Items +{ + public enum ThinBrickWallTypes + { + Corner, + SouthWall, + EastWall, + CornerPost, + EastDoorFrame, + SouthDoorFrame, + WestDoorFrame, + NorthDoorFrame, + SouthWindow, + EastWindow, + CornerMedium, + SouthWallMedium, + EastWallMedium, + CornerPostMedium, + CornerShort, + SouthWallShort, + EastWallShort, + CornerPostShort, + CornerArch, + SouthArch, + WestArch, + EastArch, + NorthArch, + SouthCenterArchTall, + EastCenterArchTall, + EastCornerArchTall, + SouthCornerArchTall, + SouthCornerArch, + EastCornerArch, + SouthCenterArch, + EastCenterArch, + CornerVVShort, + SouthWallVVShort, + EastWallVVShort, + SouthWallVShort, + EastWallVShort + }; + + public class ThinBrickWall : BaseWall + { + [Constructable] + public ThinBrickWall( ThinBrickWallTypes type ) : base( 0x0033 + (int)type ) + { + } + + public ThinBrickWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Walls/ThinStoneWall.cs b/Scripts/Items/Construction/Walls/ThinStoneWall.cs new file mode 100644 index 0000000..29643a1 --- /dev/null +++ b/Scripts/Items/Construction/Walls/ThinStoneWall.cs @@ -0,0 +1,59 @@ +using System; + +namespace Server.Items +{ + public enum ThinStoneWallTypes + { + Corner, + EastWall, + SouthWall, + CornerPost, + EastDoorFrame, + SouthDoorFrame, + NorthDoorFrame, + WestDoorFrame, + SouthWindow, + EastWindow, + CornerMedium, + SouthWallMedium, + EastWallMedium, + CornerPostMedium, + CornerArch, + EastArch, + SouthArch, + NorthArch, + WestArch, + CornerShort, + EastWallShort, + SouthWallShort, + CornerPostShort, + SouthWallShort2, + EastWallShort2 + } + + public class ThinStoneWall : BaseWall + { + [Constructable] + public ThinStoneWall( ThinStoneWallTypes type ) : base( 0x001A + (int)type ) + { + } + + public ThinStoneWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Construction/Walls/WhiteStoneWall.cs b/Scripts/Items/Construction/Walls/WhiteStoneWall.cs new file mode 100644 index 0000000..e6016da --- /dev/null +++ b/Scripts/Items/Construction/Walls/WhiteStoneWall.cs @@ -0,0 +1,77 @@ +/**************************************** + * NAME : White Stone Wall * + * SCRIPT : WhiteStoneWall.cs * + * VERSION : v1.00 * + * CREATOR : Mans Sjoberg (Allmight) * + * CREATED : 10-07.2002 * + * **************************************/ + +using System; + +namespace Server.Items +{ + public enum WhiteStoneWallTypes + { + EastWall, + SouthWall, + SECorner, + NWCornerPost, + EastArrowLoop, + SouthArrowLoop, + EastWindow, + SouthWindow, + SouthWallMedium, + EastWallMedium, + SECornerMedium, + NWCornerPostMedium, + SouthWallShort, + EastWallShort, + SECornerShort, + NWCornerPostShort, + NECornerPostShort, + SWCornerPostShort, + SouthWallVShort, + EastWallVShort, + SECornerVShort, + NWCornerPostVShort, + SECornerArch, + SouthArch, + WestArch, + EastArch, + NorthArch, + EastBattlement, + SECornerBattlement, + SouthBattlement, + NECornerBattlement, + SWCornerBattlement, + Column, + SouthWallVVShort, + EastWallVVShort + } + + public class WhiteStoneWall : BaseWall + { + [Constructable] + public WhiteStoneWall( WhiteStoneWallTypes type) : base( 0x0057 + (int)type ) + { + } + + public WhiteStoneWall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/BaseTreasureChest.cs b/Scripts/Items/Containers/BaseTreasureChest.cs new file mode 100644 index 0000000..59adbba --- /dev/null +++ b/Scripts/Items/Containers/BaseTreasureChest.cs @@ -0,0 +1,255 @@ +using Server; +using Server.Items; +using Server.Network; +using System; +using System.Collections; + +namespace Server.Items +{ + public class BaseTreasureChest : LockableContainer + { + private TreasureLevel m_TreasureLevel; + private short m_MaxSpawnTime = 60; + private short m_MinSpawnTime = 10; + private TreasureResetTimer m_ResetTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public TreasureLevel Level + { + get + { + return m_TreasureLevel; + } + set + { + m_TreasureLevel = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public short MaxSpawnTime + { + get + { + return m_MaxSpawnTime; + } + set + { + m_MaxSpawnTime = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public short MinSpawnTime + { + get + { + return m_MinSpawnTime; + } + set + { + m_MinSpawnTime = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override bool Locked { + get { return base.Locked; } + set { + if ( base.Locked != value ) { + base.Locked = value; + + if ( !value ) + StartResetTimer(); + } + } + } + + public override bool IsDecoContainer + { + get{ return false; } + } + + public BaseTreasureChest( int itemID ) : this( itemID, TreasureLevel.Level2 ) + { + } + + public BaseTreasureChest( int itemID, TreasureLevel level ) : base( itemID ) + { + m_TreasureLevel = level; + Locked = true; + Movable = false; + + SetLockLevel(); + GenerateTreasure(); + } + + public BaseTreasureChest( Serial serial ) : base( serial ) + { + } + + public override string DefaultName + { + get + { + if ( this.Locked ) + return "a locked treasure chest"; + + return "a treasure chest"; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + writer.Write( (byte) m_TreasureLevel ); + writer.Write( m_MinSpawnTime ); + writer.Write( m_MaxSpawnTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_TreasureLevel = (TreasureLevel)reader.ReadByte(); + m_MinSpawnTime = reader.ReadShort(); + m_MaxSpawnTime = reader.ReadShort(); + + if( !Locked ) + StartResetTimer(); + } + + protected virtual void SetLockLevel() + { + switch( m_TreasureLevel ) + { + case TreasureLevel.Level1: + this.RequiredSkill = this.LockLevel = 5; + break; + + case TreasureLevel.Level2: + this.RequiredSkill = this.LockLevel = 20; + break; + + case TreasureLevel.Level3: + this.RequiredSkill = this.LockLevel = 50; + break; + + case TreasureLevel.Level4: + this.RequiredSkill = this.LockLevel = 70; + break; + + case TreasureLevel.Level5: + this.RequiredSkill = this.LockLevel = 90; + break; + + case TreasureLevel.Level6: + this.RequiredSkill = this.LockLevel = 100; + break; + } + } + + private void StartResetTimer() + { + if( m_ResetTimer == null ) + m_ResetTimer = new TreasureResetTimer( this ); + else + m_ResetTimer.Delay = TimeSpan.FromMinutes( Utility.Random( m_MinSpawnTime, m_MaxSpawnTime )); + + m_ResetTimer.Start(); + } + + protected virtual void GenerateTreasure() + { + int MinGold = 1; + int MaxGold = 2; + + switch( m_TreasureLevel ) + { + case TreasureLevel.Level1: + MinGold = 100; + MaxGold = 300; + break; + + case TreasureLevel.Level2: + MinGold = 300; + MaxGold = 600; + break; + + case TreasureLevel.Level3: + MinGold = 600; + MaxGold = 900; + break; + + case TreasureLevel.Level4: + MinGold = 900; + MaxGold = 1200; + break; + + case TreasureLevel.Level5: + MinGold = 1200; + MaxGold = 5000; + break; + + case TreasureLevel.Level6: + MinGold = 5000; + MaxGold = 9000; + break; + } + + DropItem( new Gold( MinGold, MaxGold ) ); + } + + public void ClearContents() + { + for ( int i = Items.Count - 1; i >= 0; --i ) + { + if ( i < Items.Count ) + Items[i].Delete(); + } + } + + public void Reset() + { + if( m_ResetTimer != null ) + { + if( m_ResetTimer.Running ) + m_ResetTimer.Stop(); + } + + Locked = true; + ClearContents(); + GenerateTreasure(); + } + + public enum TreasureLevel + { + Level1, + Level2, + Level3, + Level4, + Level5, + Level6, + }; + + private class TreasureResetTimer : Timer + { + private BaseTreasureChest m_Chest; + + public TreasureResetTimer( BaseTreasureChest chest ) : base ( TimeSpan.FromMinutes( Utility.Random( chest.MinSpawnTime, chest.MaxSpawnTime ) ) ) + { + m_Chest = chest; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Chest.Reset(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/Container.cs b/Scripts/Items/Containers/Container.cs new file mode 100644 index 0000000..fa06f2b --- /dev/null +++ b/Scripts/Items/Containers/Container.cs @@ -0,0 +1,992 @@ +using System; +using System.Collections.Generic; +using Server.Multis; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; + +namespace Server.Items +{ + public abstract class BaseContainer : Container + { + public override int DefaultMaxWeight + { + get + { + if ( IsSecure ) + return 0; + + return base.DefaultMaxWeight; + } + } + + public BaseContainer( int itemID ) : base( itemID ) + { + } + + public override bool IsAccessibleTo( Mobile m ) + { + if ( !BaseHouse.CheckAccessible( m, this ) ) + return false; + + return base.IsAccessibleTo( m ); + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + if ( this.IsSecure && !BaseHouse.CheckHold( m, this, item, message, checkItems, plusItems, plusWeight ) ) + return false; + + return base.CheckHold( m, item, message, checkItems, plusItems, plusWeight ); + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( IsDecoContainer && item is BaseBook ) + return true; + + return base.CheckItemUse( from, item ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public override bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + if ( !CheckHold( from, dropped, sendFullMessage, true ) ) + return false; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsLockedDown( this ) ) + { + if ( dropped is VendorRentalContract || ( dropped is Container && ((Container)dropped).FindItemByType( typeof( VendorRentalContract ) ) != null ) ) + { + from.SendLocalizedMessage( 1062492 ); // You cannot place a rental contract in a locked down container. + return false; + } + + if ( !house.LockDown( from, dropped, false ) ) + return false; + } + + List list = this.Items; + + for ( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if ( !(item is Container) && item.StackWith( from, dropped, false ) ) + return true; + } + + DropItem( dropped ); + + return true; + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( !CheckHold( from, item, true, true ) ) + return false; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsLockedDown( this ) ) + { + if ( item is VendorRentalContract || ( item is Container && ((Container)item).FindItemByType( typeof( VendorRentalContract ) ) != null ) ) + { + from.SendLocalizedMessage( 1062492 ); // You cannot place a rental contract in a locked down container. + return false; + } + + if ( !house.LockDown( from, item, false ) ) + return false; + } + + item.Location = new Point3D( p.X, p.Y, 0 ); + AddItem( item ); + + from.SendSound( GetDroppedSound( item ), GetWorldLocation() ); + + return true; + } + + public override void UpdateTotal( Item sender, TotalType type, int delta ) + { + base.UpdateTotal( sender, type, delta ); + + if ( type == TotalType.Weight && RootParent is Mobile ) + ((Mobile) RootParent).InvalidateProperties(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel > AccessLevel.Player || from.InRange( this.GetWorldLocation(), 2 ) || this.RootParent is PlayerVendor ) + Open( from ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public virtual void Open( Mobile from ) + { + DisplayTo( from ); + } + + public BaseContainer( Serial serial ) : base( serial ) + { + } + + /* Note: base class insertion; we cannot serialize anything here */ + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + // Scriptiz : on a envie de pouvoir serializer ! + writer.Write((int)0); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + // Scriptiz : apr�s un premier restart on peut lire la version qui n'existait pas avant + int version = reader.ReadInt(); + } + } + + public class CreatureBackpack : Backpack //Used on BaseCreature + { + [Constructable] + public CreatureBackpack( string name ) + { + Name = name; + Layer = Layer.Backpack; + Hue = 5; + Weight = 3.0; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( Name != null ) + list.Add( 1075257, Name ); // Contents of ~1_PETNAME~'s pack. + else + base.AddNameProperty( list ); + } + + public override void OnItemRemoved( Item item ) + { + if ( Items.Count == 0 ) + this.Delete(); + + base.OnItemRemoved( item ); + } + + public override bool OnDragLift( Mobile from ) + { + if ( from.AccessLevel > AccessLevel.Player ) + return true; + + from.SendLocalizedMessage( 500169 ); // You cannot pick that up. + return false; + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + return false; + } + + public override bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + return false; + } + + public CreatureBackpack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + Weight = 13.0; + } + } + + public class StrongBackpack : Backpack //Used on Pack animals + { + [Constructable] + public StrongBackpack() + { + Layer = Layer.Backpack; + Weight = 13.0; + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + return base.CheckHold( m, item, false, checkItems, plusItems, plusWeight ); + } + + public override int DefaultMaxWeight{ get{ return 1600; } } + + public override bool CheckContentDisplay( Mobile from ) + { + object root = this.RootParent; + + if ( root is BaseCreature && ((BaseCreature)root).Controlled && ((BaseCreature)root).ControlMaster == from ) + return true; + + return base.CheckContentDisplay( from ); + } + + public StrongBackpack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + Weight = 13.0; + } + } + + public class Backpack : BaseContainer, IDyable + { + [Constructable] + public Backpack() : base( 0xE75 ) + { + Layer = Layer.Backpack; + Weight = 3.0; + } + + public override int DefaultMaxWeight { + get { + if ( Core.ML ) { + Mobile m = ParentEntity as Mobile; + if ( m != null && m.Player && m.Backpack == this ) { + return 550; + } else { + return base.DefaultMaxWeight; + } + } else { + return base.DefaultMaxWeight; + } + } + } + + public Backpack( Serial serial ) : base( serial ) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && ItemID == 0x9B2 ) + ItemID = 0xE75; + } + } + + public class Pouch : TrapableContainer + { + [Constructable] + public Pouch() : base( 0xE79 ) + { + Weight = 1.0; + } + + public Pouch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class BaseBagBall : BaseContainer, IDyable + { + public BaseBagBall( int itemID ) : base( itemID ) + { + Weight = 1.0; + } + + public BaseBagBall( Serial serial ) : base( serial ) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallBagBall : BaseBagBall + { + [Constructable] + public SmallBagBall() : base( 0x2256 ) + { + } + + public SmallBagBall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeBagBall : BaseBagBall + { + [Constructable] + public LargeBagBall() : base( 0x2257 ) + { + } + + public LargeBagBall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Bag : BaseContainer, IDyable + { + [Constructable] + public Bag() : base( 0xE76 ) + { + Weight = 2.0; + } + + public Bag( Serial serial ) : base( serial ) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Barrel : BaseContainer + { + [Constructable] + public Barrel() : base( 0xE77 ) + { + Weight = 25.0; + } + + public Barrel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 0.0 ) + Weight = 25.0; + } + } + + public class Keg : BaseContainer + { + [Constructable] + public Keg() : base( 0xE7F ) + { + Weight = 15.0; + } + + public Keg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PicnicBasket : BaseContainer + { + [Constructable] + public PicnicBasket() : base( 0xE7A ) + { + Weight = 2.0; // Stratics doesn't know weight + } + + public PicnicBasket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Basket : BaseContainer + { + [Constructable] + public Basket() : base( 0x990 ) + { + Weight = 1.0; // Stratics doesn't know weight + } + + public Basket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x9AA, 0xE7D )] + public class WoodenBox : LockableContainer + { + [Constructable] + public WoodenBox() : base( 0x9AA ) + { + Weight = 4.0; + } + + public WoodenBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x9A9, 0xE7E )] + public class SmallCrate : LockableContainer + { + [Constructable] + public SmallCrate() : base( 0x9A9 ) + { + Weight = 2.0; + } + + public SmallCrate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 4.0 ) + Weight = 2.0; + } + } + + [Flipable( 0xE3F, 0xE3E )] + public class MediumCrate : LockableContainer + { + [Constructable] + public MediumCrate() : base( 0xE3F ) + { + Weight = 2.0; + } + + public MediumCrate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 2.0; + } + } + + [Flipable( 0xE3D, 0xE3C )] + public class LargeCrate : LockableContainer + { + [Constructable] + public LargeCrate() : base( 0xE3D ) + { + Weight = 1.0; + } + + public LargeCrate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 8.0 ) + Weight = 1.0; + } + } + + [DynamicFliping] + [Flipable( 0x9A8, 0xE80 )] + public class MetalBox : LockableContainer + { + [Constructable] + public MetalBox() : base( 0x9A8 ) + { + } + + public MetalBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 3 ) + Weight = -1; + } + } + + [DynamicFliping] + [Flipable( 0x9AB, 0xE7C )] + public class MetalChest : LockableContainer + { + [Constructable] + public MetalChest() : base( 0x9AB ) + { + } + + public MetalChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 25 ) + Weight = -1; + } + } + + [DynamicFliping] + [Flipable( 0xE41, 0xE40 )] + public class MetalGoldenChest : LockableContainer + { + [Constructable] + public MetalGoldenChest() : base( 0xE41 ) + { + } + + public MetalGoldenChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 25 ) + Weight = -1; + } + } + + [Flipable( 0xe43, 0xe42 )] + public class WoodenChest : LockableContainer + { + [Constructable] + public WoodenChest() : base( 0xe43 ) + { + Weight = 2.0; + } + + public WoodenChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 15.0 ) + Weight = 2.0; + } + } + + [Flipable( 0x280B, 0x280C )] + public class PlainWoodenChest : LockableContainer + { + [Constructable] + public PlainWoodenChest() : base( 0x280B ) + { + } + + public PlainWoodenChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 15 ) + Weight = -1; + } + } + + [Flipable( 0x280D, 0x280E )] + public class OrnateWoodenChest : LockableContainer + { + [Constructable] + public OrnateWoodenChest() : base( 0x280D ) + { + } + + public OrnateWoodenChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 15 ) + Weight = -1; + } + } + + [Flipable( 0x280F, 0x2810 )] + public class GildedWoodenChest : LockableContainer + { + [Constructable] + public GildedWoodenChest() : base( 0x280F ) + { + } + + public GildedWoodenChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 15 ) + Weight = -1; + } + } + + [Flipable( 0x2811, 0x2812 )] + public class WoodenFootLocker : LockableContainer + { + [Constructable] + public WoodenFootLocker() : base( 0x2811 ) + { + GumpID = 0x10B; + } + + public WoodenFootLocker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 15 ) + Weight = -1; + + if ( version < 2 ) + GumpID = 0x10B; + } + } + + [Flipable( 0x2813, 0x2814 )] + public class FinishedWoodenChest : LockableContainer + { + [Constructable] + public FinishedWoodenChest() : base( 0x2813 ) + { + } + + public FinishedWoodenChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 15 ) + Weight = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/FillableContainers.cs b/Scripts/Items/Containers/FillableContainers.cs new file mode 100644 index 0000000..24b36dd --- /dev/null +++ b/Scripts/Items/Containers/FillableContainers.cs @@ -0,0 +1,1527 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class FillableContainer : LockableContainer + { + public virtual int MinRespawnMinutes { get { return 60; } } + public virtual int MaxRespawnMinutes { get { return 90; } } + + public virtual bool IsLockable { get { return true; } } + public virtual bool IsTrapable { get { return IsLockable; } } + + public virtual int SpawnThreshold { get { return 2; } } + + protected FillableContent m_Content; + + protected DateTime m_NextRespawnTime; + protected Timer m_RespawnTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextRespawnTime { get { return m_NextRespawnTime; } } + + [CommandProperty(AccessLevel.GameMaster)] + public FillableContentType ContentType + { + get { return FillableContent.Lookup(m_Content); } + set { Content = FillableContent.Lookup(value); } + } + + public FillableContent Content + { + get { return m_Content; } + set + { + if (m_Content == value) + return; + + m_Content = value; + + for (int i = Items.Count - 1; i >= 0; --i) + { + if (i < Items.Count) + Items[i].Delete(); + } + + Respawn(); + } + } + + public FillableContainer(int itemID) + : base(itemID) + { + Movable = false; + } + + public override void OnMapChange() + { + base.OnMapChange(); + AcquireContent(); + } + + public override void OnLocationChange(Point3D oldLocation) + { + base.OnLocationChange(oldLocation); + AcquireContent(); + } + + public virtual void AcquireContent() + { + if (m_Content != null) + return; + + m_Content = FillableContent.Acquire(this.GetWorldLocation(), this.Map); + + if (m_Content != null) + Respawn(); + } + + public override void OnItemRemoved(Item item) + { + CheckRespawn(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_RespawnTimer != null) + { + m_RespawnTimer.Stop(); + m_RespawnTimer = null; + } + } + + public int GetItemsCount() + { + int count = 0; + + foreach (Item item in this.Items) + { + count += item.Amount; + } + + return count; + } + + public void CheckRespawn() + { + bool canSpawn = (m_Content != null && !Deleted && GetItemsCount() <= SpawnThreshold && !Movable && Parent == null && !IsLockedDown && !IsSecure); + + if (canSpawn) + { + if (m_RespawnTimer == null) + { + int mins = Utility.RandomMinMax(this.MinRespawnMinutes, this.MaxRespawnMinutes); + TimeSpan delay = TimeSpan.FromMinutes(mins); + + m_NextRespawnTime = DateTime.Now + delay; + m_RespawnTimer = Timer.DelayCall(delay, new TimerCallback(Respawn)); + } + } + else if (m_RespawnTimer != null) + { + m_RespawnTimer.Stop(); + m_RespawnTimer = null; + } + } + + public void Respawn() + { + if (m_RespawnTimer != null) + { + m_RespawnTimer.Stop(); + m_RespawnTimer = null; + } + + if (m_Content == null || Deleted) + return; + + GenerateContent(); + + if (IsLockable) + { + Locked = true; + + int difficulty = (m_Content.Level - 1) * 30; + + LockLevel = difficulty - 10; + MaxLockLevel = difficulty + 30; + RequiredSkill = difficulty; + } + + if (IsTrapable && (m_Content.Level > 1 || 4 > Utility.Random(5))) + { + if (m_Content.Level > Utility.Random(5)) + TrapType = TrapType.PoisonTrap; + else + TrapType = TrapType.ExplosionTrap; + + TrapPower = m_Content.Level * Utility.RandomMinMax(10, 30); + TrapLevel = m_Content.Level; + } + else + { + TrapType = TrapType.None; + TrapPower = 0; + TrapLevel = 0; + } + + CheckRespawn(); + } + + protected virtual int GetSpawnCount() + { + int itemsCount = GetItemsCount(); + + if (itemsCount > SpawnThreshold) + return 0; + + int maxSpawnCount = (1 + SpawnThreshold - itemsCount) * 2; + + return Utility.RandomMinMax(0, maxSpawnCount); + } + + public virtual void GenerateContent() + { + if (m_Content == null || Deleted) + return; + + int toSpawn = GetSpawnCount(); + + for (int i = 0; i < toSpawn; ++i) + { + Item item = m_Content.Construct(); + + if (item != null) + { + List list = this.Items; + + for (int j = 0; j < list.Count; ++j) + { + Item subItem = list[j]; + + if (!(subItem is Container) && subItem.StackWith(null, item, false)) + break; + } + + if (item != null && !item.Deleted) + DropItem(item); + } + } + } + + public FillableContainer(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + + writer.Write((int)ContentType); + + if (m_RespawnTimer != null) + { + writer.Write(true); + writer.WriteDeltaTime((DateTime)m_NextRespawnTime); + } + else + { + writer.Write(false); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + { + m_Content = FillableContent.Lookup((FillableContentType)reader.ReadInt()); + goto case 0; + } + case 0: + { + if (reader.ReadBool()) + { + m_NextRespawnTime = reader.ReadDeltaTime(); + + TimeSpan delay = m_NextRespawnTime - DateTime.Now; + m_RespawnTimer = Timer.DelayCall(delay > TimeSpan.Zero ? delay : TimeSpan.Zero, new TimerCallback(Respawn)); + } + else + { + CheckRespawn(); + } + + break; + } + } + } + } + + [Flipable(0xA97, 0xA99, 0xA98, 0xA9A, 0xA9B, 0xA9C)] + public class LibraryBookcase : FillableContainer + { + public override bool IsLockable { get { return false; } } + public override int SpawnThreshold { get { return 5; } } + + protected override int GetSpawnCount() + { + return (5 - GetItemsCount()); + } + + public override void AcquireContent() + { + if (m_Content != null) + return; + + m_Content = FillableContent.Library; + + if (m_Content != null) + Respawn(); + } + + [Constructable] + public LibraryBookcase() + : base(0xA97) + { + Weight = 1.0; + } + + public LibraryBookcase(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0 && m_Content == null) + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(AcquireContent)); + } + } + + [Flipable(0xE3D, 0xE3C)] + public class FillableLargeCrate : FillableContainer + { + [Constructable] + public FillableLargeCrate() + : base(0xE3D) + { + Weight = 1.0; + } + + public FillableLargeCrate(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [Flipable(0x9A9, 0xE7E)] + public class FillableSmallCrate : FillableContainer + { + [Constructable] + public FillableSmallCrate() + : base(0x9A9) + { + Weight = 1.0; + } + + public FillableSmallCrate(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [Flipable(0x9AA, 0xE7D)] + public class FillableWoodenBox : FillableContainer + { + [Constructable] + public FillableWoodenBox() + : base(0x9AA) + { + Weight = 4.0; + } + + public FillableWoodenBox(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [Flipable(0x9A8, 0xE80)] + public class FillableMetalBox : FillableContainer + { + [Constructable] + public FillableMetalBox() + : base(0x9A8) + { + } + + public FillableMetalBox(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0 && Weight == 3) + Weight = -1; + } + } + + public class FillableBarrel : FillableContainer + { + public override bool IsLockable { get { return false; } } + + [Constructable] + public FillableBarrel() + : base(0xE77) + { + } + + public FillableBarrel(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0 && Weight == 25) + Weight = -1; + } + } + + [Flipable(0x9AB, 0xE7C)] + public class FillableMetalChest : FillableContainer + { + [Constructable] + public FillableMetalChest() + : base(0x9AB) + { + } + + public FillableMetalChest(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Weight == 25) + Weight = -1; + } + } + + [Flipable(0xE41, 0xE40)] + public class FillableMetalGoldenChest : FillableContainer + { + [Constructable] + public FillableMetalGoldenChest() + : base(0xE41) + { + } + + public FillableMetalGoldenChest(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Weight == 25) + Weight = -1; + } + } + + [Flipable(0xE43, 0xE42)] + public class FillableWoodenChest : FillableContainer + { + [Constructable] + public FillableWoodenChest() + : base(0xE43) + { + } + + public FillableWoodenChest(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Weight == 2) + Weight = -1; + } + } + + public class FillableEntry + { + protected Type[] m_Types; + protected int m_Weight; + + public Type[] Types { get { return m_Types; } } + public int Weight { get { return m_Weight; } } + + public FillableEntry(Type type) + : this(1, new Type[] { type }) + { + } + + public FillableEntry(int weight, Type type) + : this(weight, new Type[] { type }) + { + } + + public FillableEntry(Type[] types) + : this(1, types) + { + } + + public FillableEntry(int weight, Type[] types) + { + m_Weight = weight; + m_Types = types; + } + + public FillableEntry(int weight, Type[] types, int offset, int count) + { + m_Weight = weight; + m_Types = new Type[count]; + + for (int i = 0; i < m_Types.Length; ++i) + m_Types[i] = types[offset + i]; + } + + public virtual Item Construct() + { + Item item = Loot.Construct(m_Types); + + if (item is Key) + ((Key)item).ItemID = Utility.RandomList((int)KeyType.Copper, (int)KeyType.Gold, (int)KeyType.Iron, (int)KeyType.Rusty); + else if (item is Arrow || item is Bolt) + item.Amount = Utility.RandomMinMax(2, 6); + else if (item is Bandage || item is Lockpick) + item.Amount = Utility.RandomMinMax(1, 3); + + return item; + } + } + + public class FillableBvrge : FillableEntry + { + private BeverageType m_Content; + + public BeverageType Content { get { return m_Content; } } + + public FillableBvrge(Type type, BeverageType content) + : this(1, type, content) + { + } + + public FillableBvrge(int weight, Type type, BeverageType content) + : base(weight, type) + { + m_Content = content; + } + + public override Item Construct() + { + Item item; + + int index = Utility.Random(m_Types.Length); + + if (m_Types[index] == typeof(BeverageBottle)) + { + item = new BeverageBottle(m_Content); + } + else if (m_Types[index] == typeof(Jug)) + { + item = new Jug(m_Content); + } + else + { + item = base.Construct(); + + if (item is BaseBeverage) + { + BaseBeverage bev = (BaseBeverage)item; + + bev.Content = m_Content; + bev.Quantity = bev.MaxQuantity; + } + } + + return item; + } + } + + public enum FillableContentType + { + None = -1, + Weaponsmith, Provisioner, Mage, + Alchemist, Armorer, ArtisanGuild, + Baker, Bard, Blacksmith, + Bowyer, Butcher, Carpenter, + Clothier, Cobbler, Docks, + Farm, FighterGuild, Guard, + Healer, Herbalist, Inn, + Jeweler, Library, Merchant, + Mill, Mine, Observatory, + Painter, Ranger, Stables, + Tanner, Tavern, ThiefGuild, + Tinker, Veterinarian + } + + public class FillableContent + { + private int m_Level; + private Type[] m_Vendors; + + private FillableEntry[] m_Entries; + private int m_Weight; + + public int Level { get { return m_Level; } } + public Type[] Vendors { get { return m_Vendors; } } + + public FillableContentType TypeID { get { return Lookup(this); } } + + public FillableContent(int level, Type[] vendors, FillableEntry[] entries) + { + m_Level = level; + m_Vendors = vendors; + m_Entries = entries; + + for (int i = 0; i < entries.Length; ++i) + m_Weight += entries[i].Weight; + } + + public virtual Item Construct() + { + int index = Utility.Random(m_Weight); + + for (int i = 0; i < m_Entries.Length; ++i) + { + FillableEntry entry = m_Entries[i]; + + if (index < entry.Weight) + return entry.Construct(); + + index -= entry.Weight; + } + + return null; + } + + public static FillableContent Alchemist = new FillableContent( + 1, + new Type[] + { + typeof( Mobiles.Alchemist ) + }, + new FillableEntry[] + { + new FillableEntry( typeof( NightSightPotion ) ), + new FillableEntry( typeof( LesserCurePotion ) ), + new FillableEntry( typeof( AgilityPotion ) ), + new FillableEntry( typeof( StrengthPotion ) ), + new FillableEntry( typeof( LesserPoisonPotion ) ), + new FillableEntry( typeof( RefreshPotion ) ), + new FillableEntry( typeof( LesserHealPotion ) ), + new FillableEntry( typeof( LesserExplosionPotion ) ), + new FillableEntry( typeof( MortarPestle ) ) + }); + + public static FillableContent Armorer = new FillableContent( + 2, + new Type[] + { + typeof( Armorer ) + }, + new FillableEntry[] + { + new FillableEntry( 2, typeof( ChainCoif ) ), + new FillableEntry( 1, typeof( PlateGorget ) ), + new FillableEntry( 1, typeof( BronzeShield ) ), + new FillableEntry( 1, typeof( Buckler ) ), + new FillableEntry( 2, typeof( MetalKiteShield ) ), + new FillableEntry( 2, typeof( HeaterShield ) ), + new FillableEntry( 1, typeof( WoodenShield ) ), + new FillableEntry( 1, typeof( MetalShield ) ) + }); + + public static FillableContent ArtisanGuild = new FillableContent( + 1, + new Type[] + { + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( PaintsAndBrush ) ), + new FillableEntry( 1, typeof( SledgeHammer ) ), + new FillableEntry( 2, typeof( SmithHammer ) ), + new FillableEntry( 2, typeof( Tongs ) ), + new FillableEntry( 4, typeof( Lockpick ) ), + new FillableEntry( 4, typeof( TinkerTools ) ), + new FillableEntry( 1, typeof( MalletAndChisel ) ), + new FillableEntry( 1, typeof( StatueEast2 ) ), + new FillableEntry( 1, typeof( StatueSouth ) ), + new FillableEntry( 1, typeof( StatueSouthEast ) ), + new FillableEntry( 1, typeof( StatueWest ) ), + new FillableEntry( 1, typeof( StatueNorth ) ), + new FillableEntry( 1, typeof( StatueEast ) ), + new FillableEntry( 1, typeof( BustEast ) ), + new FillableEntry( 1, typeof( BustSouth ) ), + new FillableEntry( 1, typeof( BearMask ) ), + new FillableEntry( 1, typeof( DeerMask ) ), + new FillableEntry( 4, typeof( OrcHelm ) ), + new FillableEntry( 1, typeof( TribalMask ) ), + new FillableEntry( 1, typeof( HornedTribalMask ) ) + }); + + public static FillableContent Baker = new FillableContent( + 1, + new Type[] + { + typeof( Baker ), + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( RollingPin ) ), + new FillableEntry( 2, typeof( SackFlour ) ), + new FillableEntry( 2, typeof( BreadLoaf ) ), + new FillableEntry( 1, typeof( FrenchBread ) ) + }); + + public static FillableContent Bard = new FillableContent( + 1, + new Type[] + { + typeof( Bard ), + typeof( BardGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( LapHarp ) ), + new FillableEntry( 2, typeof( Lute ) ), + new FillableEntry( 1, typeof( Drums ) ), + new FillableEntry( 1, typeof( Tambourine ) ), + new FillableEntry( 1, typeof( TambourineTassel ) ) + }); + + public static FillableContent Blacksmith = new FillableContent( + 2, + new Type[] + { + typeof( Blacksmith ), + typeof( BlacksmithGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 8, typeof( SmithHammer ) ), + new FillableEntry( 8, typeof( Tongs ) ), + new FillableEntry( 8, typeof( SledgeHammer ) ), + //new FillableEntry( 8, typeof( IronOre ) ), TODO: Smaller ore + new FillableEntry( 8, typeof( IronIngot ) ), + new FillableEntry( 1, typeof( IronWire ) ), + new FillableEntry( 1, typeof( SilverWire ) ), + new FillableEntry( 1, typeof( GoldWire ) ), + new FillableEntry( 1, typeof( CopperWire ) ), + new FillableEntry( 1, typeof( HorseShoes ) ), + new FillableEntry( 1, typeof( ForgedMetal ) ) + }); + + public static FillableContent Bowyer = new FillableContent( + 2, + new Type[] + { + typeof( Bowyer ) + }, + new FillableEntry[] + { + new FillableEntry( 2, typeof( Bow ) ), + new FillableEntry( 2, typeof( Crossbow ) ), + new FillableEntry( 1, typeof( Arrow ) ) + }); + + public static FillableContent Butcher = new FillableContent( + 1, + new Type[] + { + typeof( Butcher ), + }, + new FillableEntry[] + { + new FillableEntry( 2, typeof( Cleaver ) ), + new FillableEntry( 2, typeof( SlabOfBacon ) ), + new FillableEntry( 2, typeof( Bacon ) ), + new FillableEntry( 1, typeof( RawFishSteak ) ), + new FillableEntry( 1, typeof( FishSteak ) ), + new FillableEntry( 2, typeof( CookedBird ) ), + new FillableEntry( 2, typeof( RawBird ) ), + new FillableEntry( 2, typeof( Ham ) ), + new FillableEntry( 1, typeof( RawLambLeg ) ), + new FillableEntry( 1, typeof( LambLeg ) ), + new FillableEntry( 1, typeof( Ribs ) ), + new FillableEntry( 1, typeof( RawRibs ) ), + new FillableEntry( 2, typeof( Sausage ) ), + new FillableEntry( 1, typeof( RawChickenLeg ) ), + new FillableEntry( 1, typeof( ChickenLeg ) ) + }); + + public static FillableContent Carpenter = new FillableContent( + 1, + new Type[] + { + typeof( Carpenter ), + typeof( Architect ), + typeof( RealEstateBroker ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( ChiselsNorth ) ), + new FillableEntry( 1, typeof( ChiselsWest ) ), + new FillableEntry( 2, typeof( DovetailSaw ) ), + new FillableEntry( 2, typeof( Hammer ) ), + new FillableEntry( 2, typeof( MouldingPlane ) ), + new FillableEntry( 2, typeof( Nails ) ), + new FillableEntry( 2, typeof( JointingPlane ) ), + new FillableEntry( 2, typeof( SmoothingPlane ) ), + new FillableEntry( 2, typeof( Saw ) ), + new FillableEntry( 2, typeof( DrawKnife ) ), + new FillableEntry( 1, typeof( Log ) ), + new FillableEntry( 1, typeof( Froe ) ), + new FillableEntry( 1, typeof( Inshave ) ), + new FillableEntry( 1, typeof( Scorp ) ) + }); + + public static FillableContent Clothier = new FillableContent( + 1, + new Type[] + { + typeof( Tailor ), + typeof( Weaver ), + typeof( TailorGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Cotton ) ), + new FillableEntry( 1, typeof( Wool ) ), + new FillableEntry( 1, typeof( DarkYarn ) ), + new FillableEntry( 1, typeof( LightYarn ) ), + new FillableEntry( 1, typeof( LightYarnUnraveled ) ), + new FillableEntry( 1, typeof( SpoolOfThread ) ), + // Four different types + //new FillableEntry( 1, typeof( FoldedCloth ) ), + //new FillableEntry( 1, typeof( FoldedCloth ) ), + //new FillableEntry( 1, typeof( FoldedCloth ) ), + //new FillableEntry( 1, typeof( FoldedCloth ) ), + new FillableEntry( 1, typeof( Dyes ) ), + new FillableEntry( 2, typeof( Leather ) ) + }); + + public static FillableContent Cobbler = new FillableContent( + 1, + new Type[] + { + typeof( Cobbler ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Boots ) ), + new FillableEntry( 2, typeof( Shoes ) ), + new FillableEntry( 2, typeof( Sandals ) ), + new FillableEntry( 1, typeof( ThighBoots ) ) + }); + + public static FillableContent Docks = new FillableContent( + 1, + new Type[] + { + typeof( Fisherman ), + typeof( FisherGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( FishingPole ) ), + // Two different types + //new FillableEntry( 1, typeof( SmallFish ) ), + //new FillableEntry( 1, typeof( SmallFish ) ), + new FillableEntry( 4, typeof( Fish ) ) + }); + + public static FillableContent Farm = new FillableContent( + 1, + new Type[] + { + typeof( Farmer ), + typeof( Rancher ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Shirt ) ), + new FillableEntry( 1, typeof( ShortPants ) ), + new FillableEntry( 1, typeof( Skirt ) ), + new FillableEntry( 1, typeof( PlainDress ) ), + new FillableEntry( 1, typeof( Cap ) ), + new FillableEntry( 2, typeof( Sandals ) ), + new FillableEntry( 2, typeof( GnarledStaff ) ), + new FillableEntry( 2, typeof( Pitchfork ) ), + new FillableEntry( 1, typeof( Bag ) ), + new FillableEntry( 1, typeof( Kindling ) ), + new FillableEntry( 1, typeof( Lettuce ) ), + new FillableEntry( 1, typeof( Onion ) ), + new FillableEntry( 1, typeof( Turnip ) ), + new FillableEntry( 1, typeof( Ham ) ), + new FillableEntry( 1, typeof( Bacon ) ), + new FillableEntry( 1, typeof( RawLambLeg ) ), + new FillableEntry( 1, typeof( SheafOfHay ) ), + new FillableBvrge( 1, typeof( Pitcher ), BeverageType.Milk ) + }); + + public static FillableContent FighterGuild = new FillableContent( + 3, + new Type[] + { + typeof( WarriorGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 12, Loot.ArmorTypes ), + new FillableEntry( 8, Loot.WeaponTypes ), + new FillableEntry( 3, Loot.ShieldTypes ), + new FillableEntry( 1, typeof( Arrow ) ) + }); + + public static FillableContent Guard = new FillableContent( + 3, + new Type[] + { + }, + new FillableEntry[] + { + new FillableEntry( 12, Loot.ArmorTypes ), + new FillableEntry( 8, Loot.WeaponTypes ), + new FillableEntry( 3, Loot.ShieldTypes ), + new FillableEntry( 1, typeof( Arrow ) ) + }); + + public static FillableContent Healer = new FillableContent( + 1, + new Type[] + { + typeof( Healer ), + typeof( HealerGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Bandage ) ), + new FillableEntry( 1, typeof( MortarPestle ) ), + new FillableEntry( 1, typeof( LesserHealPotion ) ) + }); + + public static FillableContent Herbalist = new FillableContent( + 1, + new Type[] + { + typeof( Herbalist ) + }, + new FillableEntry[] + { + new FillableEntry( 10, typeof( Garlic ) ), + new FillableEntry( 10, typeof( Ginseng ) ), + new FillableEntry( 10, typeof( MandrakeRoot ) ), + new FillableEntry( 1, typeof( DeadWood ) ), + new FillableEntry( 1, typeof( WhiteDriedFlowers ) ), + new FillableEntry( 1, typeof( GreenDriedFlowers ) ), + new FillableEntry( 1, typeof( DriedOnions ) ), + new FillableEntry( 1, typeof( DriedHerbs ) ) + }); + + public static FillableContent Inn = new FillableContent( + 1, + new Type[] + { + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Candle ) ), + new FillableEntry( 1, typeof( Torch ) ), + new FillableEntry( 1, typeof( Lantern ) ) + }); + + public static FillableContent Jeweler = new FillableContent( + 2, + new Type[] + { + typeof( Jeweler ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( GoldRing ) ), + new FillableEntry( 1, typeof( GoldBracelet ) ), + new FillableEntry( 1, typeof( GoldEarrings ) ), + new FillableEntry( 1, typeof( GoldNecklace ) ), + new FillableEntry( 1, typeof( GoldBeadNecklace ) ), + new FillableEntry( 1, typeof( Necklace ) ), + new FillableEntry( 1, typeof( Beads ) ), + new FillableEntry( 9, Loot.GemTypes ) + }); + + public static FillableContent Library = new FillableContent( + 1, + new Type[] + { + typeof( Scribe ) + }, + new FillableEntry[] + { + new FillableEntry( 8, Loot.LibraryBookTypes ), + new FillableEntry( 1, typeof( RedBook ) ), + new FillableEntry( 1, typeof( BlueBook ) ) + }); + + public static FillableContent Mage = new FillableContent( + 2, + new Type[] + { + typeof( Mage ), + typeof( HolyMage ), + typeof( MageGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 16, typeof( BlankScroll ) ), + new FillableEntry( 14, typeof( Spellbook ) ), + new FillableEntry( 12, Loot.RegularScrollTypes, 0, 8 ), + new FillableEntry( 11, Loot.RegularScrollTypes, 8, 8 ), + new FillableEntry( 10, Loot.RegularScrollTypes, 16, 8 ), + new FillableEntry( 9, Loot.RegularScrollTypes, 24, 8 ), + new FillableEntry( 8, Loot.RegularScrollTypes, 32, 8 ), + new FillableEntry( 7, Loot.RegularScrollTypes, 40, 8 ), + new FillableEntry( 6, Loot.RegularScrollTypes, 48, 8 ), + new FillableEntry( 5, Loot.RegularScrollTypes, 56, 8 ) + }); + + public static FillableContent Merchant = new FillableContent( + 1, + new Type[] + { + typeof( MerchantGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( CheeseWheel ) ), + new FillableEntry( 1, typeof( CheeseWedge ) ), + new FillableEntry( 1, typeof( CheeseSlice ) ), + new FillableEntry( 1, typeof( Eggs ) ), + new FillableEntry( 4, typeof( Fish ) ), + new FillableEntry( 2, typeof( RawFishSteak ) ), + new FillableEntry( 2, typeof( FishSteak ) ), + new FillableEntry( 1, typeof( Apple ) ), + new FillableEntry( 2, typeof( Banana ) ), + new FillableEntry( 2, typeof( Bananas ) ), + new FillableEntry( 2, typeof( OpenCoconut ) ), + new FillableEntry( 1, typeof( SplitCoconut ) ), + new FillableEntry( 1, typeof( Coconut ) ), + new FillableEntry( 1, typeof( Dates ) ), + new FillableEntry( 1, typeof( Grapes ) ), + new FillableEntry( 1, typeof( Lemon ) ), + new FillableEntry( 1, typeof( Lemons ) ), + new FillableEntry( 1, typeof( Lime ) ), + new FillableEntry( 1, typeof( Limes ) ), + new FillableEntry( 1, typeof( Peach ) ), + new FillableEntry( 1, typeof( Pear ) ), + new FillableEntry( 2, typeof( SlabOfBacon ) ), + new FillableEntry( 2, typeof( Bacon ) ), + new FillableEntry( 2, typeof( CookedBird ) ), + new FillableEntry( 2, typeof( RawBird ) ), + new FillableEntry( 2, typeof( Ham ) ), + new FillableEntry( 1, typeof( RawLambLeg ) ), + new FillableEntry( 1, typeof( LambLeg ) ), + new FillableEntry( 1, typeof( Ribs ) ), + new FillableEntry( 1, typeof( RawRibs ) ), + new FillableEntry( 2, typeof( Sausage ) ), + new FillableEntry( 1, typeof( RawChickenLeg ) ), + new FillableEntry( 1, typeof( ChickenLeg ) ), + new FillableEntry( 1, typeof( Watermelon ) ), + new FillableEntry( 1, typeof( SmallWatermelon ) ), + new FillableEntry( 3, typeof( Turnip ) ), + new FillableEntry( 2, typeof( YellowGourd ) ), + new FillableEntry( 2, typeof( GreenGourd ) ), + new FillableEntry( 2, typeof( Pumpkin ) ), + new FillableEntry( 1, typeof( SmallPumpkin ) ), + new FillableEntry( 2, typeof( Onion ) ), + new FillableEntry( 2, typeof( Lettuce ) ), + new FillableEntry( 2, typeof( Squash ) ), + new FillableEntry( 2, typeof( HoneydewMelon ) ), + new FillableEntry( 1, typeof( Carrot ) ), + new FillableEntry( 2, typeof( Cantaloupe ) ), + new FillableEntry( 2, typeof( Cabbage ) ), + new FillableEntry( 4, typeof( EarOfCorn ) ) + }); + + public static FillableContent Mill = new FillableContent( + 1, + new Type[] + { + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( SackFlour ) ) + }); + + public static FillableContent Mine = new FillableContent( + 1, + new Type[] + { + typeof( Miner ) + }, + new FillableEntry[] + { + new FillableEntry( 2, typeof( Pickaxe ) ), + new FillableEntry( 2, typeof( Shovel ) ), + new FillableEntry( 2, typeof( IronIngot ) ), + //new FillableEntry( 2, typeof( IronOre ) ), TODO: Smaller Ore + new FillableEntry( 1, typeof( ForgedMetal ) ) + }); + + public static FillableContent Observatory = new FillableContent( + 1, + new Type[] + { + }, + new FillableEntry[] + { + new FillableEntry( 2, typeof( Sextant ) ), + new FillableEntry( 2, typeof( Clock ) ), + new FillableEntry( 1, typeof( Spyglass ) ) + }); + + public static FillableContent Painter = new FillableContent( + 1, + new Type[] + { + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( PaintsAndBrush ) ), + new FillableEntry( 2, typeof( PenAndInk ) ) + }); + + public static FillableContent Provisioner = new FillableContent( + 1, + new Type[] + { + typeof( Provisioner ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( CheeseWheel ) ), + new FillableEntry( 1, typeof( CheeseWedge ) ), + new FillableEntry( 1, typeof( CheeseSlice ) ), + new FillableEntry( 1, typeof( Eggs ) ), + new FillableEntry( 4, typeof( Fish ) ), + new FillableEntry( 1, typeof( DirtyFrypan ) ), + new FillableEntry( 1, typeof( DirtyPan ) ), + new FillableEntry( 1, typeof( DirtyKettle ) ), + new FillableEntry( 1, typeof( DirtySmallRoundPot ) ), + new FillableEntry( 1, typeof( DirtyRoundPot ) ), + new FillableEntry( 1, typeof( DirtySmallPot ) ), + new FillableEntry( 1, typeof( DirtyPot ) ), + new FillableEntry( 1, typeof( Apple ) ), + new FillableEntry( 2, typeof( Banana ) ), + new FillableEntry( 2, typeof( Bananas ) ), + new FillableEntry( 2, typeof( OpenCoconut ) ), + new FillableEntry( 1, typeof( SplitCoconut ) ), + new FillableEntry( 1, typeof( Coconut ) ), + new FillableEntry( 1, typeof( Dates ) ), + new FillableEntry( 1, typeof( Grapes ) ), + new FillableEntry( 1, typeof( Lemon ) ), + new FillableEntry( 1, typeof( Lemons ) ), + new FillableEntry( 1, typeof( Lime ) ), + new FillableEntry( 1, typeof( Limes ) ), + new FillableEntry( 1, typeof( Peach ) ), + new FillableEntry( 1, typeof( Pear ) ), + new FillableEntry( 2, typeof( SlabOfBacon ) ), + new FillableEntry( 2, typeof( Bacon ) ), + new FillableEntry( 1, typeof( RawFishSteak ) ), + new FillableEntry( 1, typeof( FishSteak ) ), + new FillableEntry( 2, typeof( CookedBird ) ), + new FillableEntry( 2, typeof( RawBird ) ), + new FillableEntry( 2, typeof( Ham ) ), + new FillableEntry( 1, typeof( RawLambLeg ) ), + new FillableEntry( 1, typeof( LambLeg ) ), + new FillableEntry( 1, typeof( Ribs ) ), + new FillableEntry( 1, typeof( RawRibs ) ), + new FillableEntry( 2, typeof( Sausage ) ), + new FillableEntry( 1, typeof( RawChickenLeg ) ), + new FillableEntry( 1, typeof( ChickenLeg ) ), + new FillableEntry( 1, typeof( Watermelon ) ), + new FillableEntry( 1, typeof( SmallWatermelon ) ), + new FillableEntry( 3, typeof( Turnip ) ), + new FillableEntry( 2, typeof( YellowGourd ) ), + new FillableEntry( 2, typeof( GreenGourd ) ), + new FillableEntry( 2, typeof( Pumpkin ) ), + new FillableEntry( 1, typeof( SmallPumpkin ) ), + new FillableEntry( 2, typeof( Onion ) ), + new FillableEntry( 2, typeof( Lettuce ) ), + new FillableEntry( 2, typeof( Squash ) ), + new FillableEntry( 2, typeof( HoneydewMelon ) ), + new FillableEntry( 1, typeof( Carrot ) ), + new FillableEntry( 2, typeof( Cantaloupe ) ), + new FillableEntry( 2, typeof( Cabbage ) ), + new FillableEntry( 4, typeof( EarOfCorn ) ) + }); + + public static FillableContent Ranger = new FillableContent( + 2, + new Type[] + { + typeof( Ranger ), + typeof( RangerGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 2, typeof( StuddedChest ) ), + new FillableEntry( 2, typeof( StuddedLegs ) ), + new FillableEntry( 2, typeof( StuddedArms ) ), + new FillableEntry( 2, typeof( StuddedGloves ) ), + new FillableEntry( 1, typeof( StuddedGorget ) ), + + new FillableEntry( 2, typeof( LeatherChest ) ), + new FillableEntry( 2, typeof( LeatherLegs ) ), + new FillableEntry( 2, typeof( LeatherArms ) ), + new FillableEntry( 2, typeof( LeatherGloves ) ), + new FillableEntry( 1, typeof( LeatherGorget ) ), + + new FillableEntry( 2, typeof( FeatheredHat ) ), + new FillableEntry( 1, typeof( CloseHelm ) ), + new FillableEntry( 1, typeof( TallStrawHat ) ), + new FillableEntry( 1, typeof( Bandana ) ), + new FillableEntry( 1, typeof( Cloak ) ), + new FillableEntry( 2, typeof( Boots ) ), + new FillableEntry( 2, typeof( ThighBoots ) ), + + new FillableEntry( 2, typeof( GnarledStaff ) ), + new FillableEntry( 1, typeof( Whip ) ), + + new FillableEntry( 2, typeof( Bow ) ), + new FillableEntry( 2, typeof( Crossbow ) ), + new FillableEntry( 2, typeof( HeavyCrossbow ) ), + new FillableEntry( 4, typeof( Arrow ) ) + }); + + public static FillableContent Stables = new FillableContent( + 1, + new Type[] + { + typeof( AnimalTrainer ), + typeof( GypsyAnimalTrainer ) + }, + new FillableEntry[] + { + //new FillableEntry( 1, typeof( Wheat ) ), + new FillableEntry( 1, typeof( Carrot ) ) + }); + + public static FillableContent Tanner = new FillableContent( + 2, + new Type[] + { + typeof( Tanner ), + typeof( LeatherWorker ), + typeof( Furtrader ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( FeatheredHat ) ), + new FillableEntry( 1, typeof( LeatherArms ) ), + new FillableEntry( 2, typeof( LeatherLegs ) ), + new FillableEntry( 2, typeof( LeatherChest ) ), + new FillableEntry( 2, typeof( LeatherGloves ) ), + new FillableEntry( 1, typeof( LeatherGorget ) ), + new FillableEntry( 2, typeof( Leather ) ) + }); + + public static FillableContent Tavern = new FillableContent( + 1, + new Type[] + { + typeof( TavernKeeper ), + typeof( Barkeeper ), + typeof( Waiter ), + typeof( Cook ) + }, + new FillableEntry[] + { + new FillableBvrge( 1, typeof( BeverageBottle ), BeverageType.Ale ), + new FillableBvrge( 1, typeof( BeverageBottle ), BeverageType.Wine ), + new FillableBvrge( 1, typeof( BeverageBottle ), BeverageType.Liquor ), + new FillableBvrge( 1, typeof( Jug ), BeverageType.Cider ) + }); + + public static FillableContent ThiefGuild = new FillableContent( + 1, + new Type[] + { + typeof( Thief ), + typeof( ThiefGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Lockpick ) ), + new FillableEntry( 1, typeof( BearMask ) ), + new FillableEntry( 1, typeof( DeerMask ) ), + new FillableEntry( 1, typeof( TribalMask ) ), + new FillableEntry( 1, typeof( HornedTribalMask ) ), + new FillableEntry( 4, typeof( OrcHelm ) ) + }); + + public static FillableContent Tinker = new FillableContent( + 1, + new Type[] + { + typeof( Tinker ), + typeof( TinkerGuildmaster ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Lockpick ) ), + //new FillableEntry( 1, typeof( KeyRing ) ), + new FillableEntry( 2, typeof( Clock ) ), + new FillableEntry( 2, typeof( ClockParts ) ), + new FillableEntry( 2, typeof( AxleGears ) ), + new FillableEntry( 2, typeof( Gears ) ), + new FillableEntry( 2, typeof( Hinge ) ), + //new FillableEntry( 1, typeof( ArrowShafts ) ), + new FillableEntry( 2, typeof( Sextant ) ), + new FillableEntry( 2, typeof( SextantParts ) ), + new FillableEntry( 2, typeof( Axle ) ), + new FillableEntry( 2, typeof( Springs ) ), + new FillableEntry( 5, typeof( TinkerTools ) ), + new FillableEntry( 4, typeof( Key ) ) + }); + + public static FillableContent Veterinarian = new FillableContent( + 1, + new Type[] + { + typeof( Veterinarian ) + }, + new FillableEntry[] + { + new FillableEntry( 1, typeof( Bandage ) ), + new FillableEntry( 1, typeof( MortarPestle ) ), + new FillableEntry( 1, typeof( LesserHealPotion ) ), + //new FillableEntry( 1, typeof( Wheat ) ), + new FillableEntry( 1, typeof( Carrot ) ) + }); + + public static FillableContent Weaponsmith = new FillableContent( + 2, + new Type[] + { + typeof( Weaponsmith ) + }, + new FillableEntry[] + { + new FillableEntry( 8, Loot.WeaponTypes ), + new FillableEntry( 1, typeof( Arrow ) ) + }); + + public static FillableContent Lookup(FillableContentType type) + { + int v = (int)type; + + if (v >= 0 && v < m_ContentTypes.Length) + return m_ContentTypes[v]; + + return null; + } + + public static FillableContentType Lookup(FillableContent content) + { + if (content == null) + return FillableContentType.None; + + return (FillableContentType)Array.IndexOf(m_ContentTypes, content); + } + + private static Hashtable m_AcquireTable; + + private static FillableContent[] m_ContentTypes = new FillableContent[] + { + Weaponsmith, Provisioner, Mage, + Alchemist, Armorer, ArtisanGuild, + Baker, Bard, Blacksmith, + Bowyer, Butcher, Carpenter, + Clothier, Cobbler, Docks, + Farm, FighterGuild, Guard, + Healer, Herbalist, Inn, + Jeweler, Library, Merchant, + Mill, Mine, Observatory, + Painter, Ranger, Stables, + Tanner, Tavern, ThiefGuild, + Tinker, Veterinarian + }; + + public static FillableContent Acquire(Point3D loc, Map map) + { + if (map == null || map == Map.Internal) + return null; + + if (m_AcquireTable == null) + { + m_AcquireTable = new Hashtable(); + + for (int i = 0; i < m_ContentTypes.Length; ++i) + { + FillableContent fill = m_ContentTypes[i]; + + for (int j = 0; j < fill.m_Vendors.Length; ++j) + m_AcquireTable[fill.m_Vendors[j]] = fill; + } + } + + Mobile nearest = null; + FillableContent content = null; + + foreach (Mobile mob in map.GetMobilesInRange(loc, 20)) + { + if (nearest != null && mob.GetDistanceToSqrt(loc) > nearest.GetDistanceToSqrt(loc) && !(nearest is Cobbler && mob is Provisioner)) + continue; + + FillableContent check = m_AcquireTable[mob.GetType()] as FillableContent; + + if (check != null) + { + nearest = mob; + content = check; + } + } + + return content; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/FurnitureContainer.cs b/Scripts/Items/Containers/FurnitureContainer.cs new file mode 100644 index 0000000..5b52986 --- /dev/null +++ b/Scripts/Items/Containers/FurnitureContainer.cs @@ -0,0 +1,417 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2815, 0x2816 )] + public class TallCabinet : BaseContainer + { + [Constructable] + public TallCabinet() : base( 0x2815 ) + { + Weight = 1.0; + } + + public TallCabinet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2817, 0x2818 )] + public class ShortCabinet : BaseContainer + { + [Constructable] + public ShortCabinet() : base( 0x2817 ) + { + Weight = 1.0; + } + + public ShortCabinet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2857, 0x2858 )] + public class RedArmoire : BaseContainer + { + [Constructable] + public RedArmoire() : base( 0x2857 ) + { + Weight = 1.0; + } + + public RedArmoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0x285D, 0x285E )] + public class CherryArmoire : BaseContainer + { + [Constructable] + public CherryArmoire() : base( 0x285D ) + { + Weight = 1.0; + } + + public CherryArmoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0x285B, 0x285C )] + public class MapleArmoire : BaseContainer + { + [Constructable] + public MapleArmoire() : base( 0x285B ) + { + Weight = 1.0; + } + + public MapleArmoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0x2859, 0x285A )] + public class ElegantArmoire : BaseContainer + { + [Constructable] + public ElegantArmoire() : base( 0x2859 ) + { + Weight = 1.0; + } + + public ElegantArmoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0xa97, 0xa99, 0xa98, 0xa9a, 0xa9b, 0xa9c )] + public class FullBookcase : BaseContainer + { + [Constructable] + public FullBookcase() : base( 0xA97 ) + { + Weight = 1.0; + } + + public FullBookcase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0xa9d, 0xa9e )] + public class EmptyBookcase : BaseContainer + { + [Constructable] + public EmptyBookcase() : base( 0xA9D ) + { + } + + public EmptyBookcase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 1.0 ) + Weight = -1; + } + } + + [Flipable( 0xa2c, 0xa34 )] + public class Drawer : BaseContainer + { + [Constructable] + public Drawer() : base( 0xA2C ) + { + Weight = 1.0; + } + + public Drawer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0xa30, 0xa38 )] + public class FancyDrawer : BaseContainer + { + [Constructable] + public FancyDrawer() : base( 0xA30 ) + { + Weight = 1.0; + } + + public FancyDrawer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [Flipable( 0xa4f, 0xa53 )] + public class Armoire : BaseContainer + { + [Constructable] + public Armoire() : base( 0xA4F ) + { + Weight = 1.0; + } + + public override void DisplayTo( Mobile m ) + { + if ( DynamicFurniture.Open( this, m ) ) + base.DisplayTo( m ); + } + + public Armoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + DynamicFurniture.Close( this ); + } + } + + [Flipable( 0xa4d, 0xa51 )] + public class FancyArmoire : BaseContainer + { + [Constructable] + public FancyArmoire() : base( 0xA4D ) + { + Weight = 1.0; + } + + public override void DisplayTo( Mobile m ) + { + if ( DynamicFurniture.Open( this, m ) ) + base.DisplayTo( m ); + } + + public FancyArmoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + DynamicFurniture.Close( this ); + } + } + + public class DynamicFurniture + { + private static Dictionary m_Table = new Dictionary(); + + public static bool Open( Container c, Mobile m ) + { + if ( m_Table.ContainsKey( c ) ) + { + c.SendRemovePacket(); + Close( c ); + c.Delta( ItemDelta.Update ); + c.ProcessDelta(); + return false; + } + + if ( c is Armoire || c is FancyArmoire ) + { + Timer t = new FurnitureTimer( c, m ); + t.Start(); + m_Table[c] = t; + + switch ( c.ItemID ) + { + case 0xA4D: c.ItemID = 0xA4C; break; + case 0xA4F: c.ItemID = 0xA4E; break; + case 0xA51: c.ItemID = 0xA50; break; + case 0xA53: c.ItemID = 0xA52; break; + } + } + + return true; + } + + public static void Close( Container c ) + { + Timer t = null; + + m_Table.TryGetValue( c, out t ); + + if ( t != null ) + { + t.Stop(); + m_Table.Remove( c ); + } + + if ( c is Armoire || c is FancyArmoire ) + { + switch ( c.ItemID ) + { + case 0xA4C: c.ItemID = 0xA4D; break; + case 0xA4E: c.ItemID = 0xA4F; break; + case 0xA50: c.ItemID = 0xA51; break; + case 0xA52: c.ItemID = 0xA53; break; + } + } + } + } + + public class FurnitureTimer : Timer + { + private Container m_Container; + private Mobile m_Mobile; + + public FurnitureTimer( Container c, Mobile m ) : base( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ) ) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Container = c; + m_Mobile = m; + } + + protected override void OnTick() + { + if ( m_Mobile.Map != m_Container.Map || !m_Mobile.InRange( m_Container.GetWorldLocation(), 3 ) ) + DynamicFurniture.Close( m_Container ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/LockableContainer.cs b/Scripts/Items/Containers/LockableContainer.cs new file mode 100644 index 0000000..d0e756e --- /dev/null +++ b/Scripts/Items/Containers/LockableContainer.cs @@ -0,0 +1,424 @@ +using System; +using Server.Network; +using Server.Items; +using Server.Engines.Craft; + +namespace Server.Items +{ + public abstract class LockableContainer : TrapableContainer, ILockable, ILockpickable, ICraftable, IShipwreckedItem + { + private bool m_Locked; + private int m_LockLevel, m_MaxLockLevel, m_RequiredSkill; + private uint m_KeyValue; + private Mobile m_Picker; + private bool m_TrapOnLockpick; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Picker + { + get + { + return m_Picker; + } + set + { + m_Picker = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxLockLevel + { + get + { + return m_MaxLockLevel; + } + set + { + m_MaxLockLevel = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int LockLevel + { + get + { + return m_LockLevel; + } + set + { + m_LockLevel = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RequiredSkill + { + get + { + return m_RequiredSkill; + } + set + { + m_RequiredSkill = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool Locked + { + get + { + return m_Locked; + } + set + { + m_Locked = value; + + if ( m_Locked ) + m_Picker = null; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public uint KeyValue + { + get + { + return m_KeyValue; + } + set + { + m_KeyValue = value; + } + } + + public override bool TrapOnOpen + { + get + { + return !m_TrapOnLockpick; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool TrapOnLockpick + { + get + { + return m_TrapOnLockpick; + } + set + { + m_TrapOnLockpick = value; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 6 ); // version + + writer.Write( m_IsShipwreckedItem ); + + writer.Write( (bool) m_TrapOnLockpick ); + + writer.Write( (int) m_RequiredSkill ); + + writer.Write( (int) m_MaxLockLevel ); + + writer.Write( m_KeyValue ); + writer.Write( (int) m_LockLevel ); + writer.Write( (bool) m_Locked ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 6: + { + m_IsShipwreckedItem = reader.ReadBool(); + + goto case 5; + } + case 5: + { + m_TrapOnLockpick = reader.ReadBool(); + + goto case 4; + } + case 4: + { + m_RequiredSkill = reader.ReadInt(); + + goto case 3; + } + case 3: + { + m_MaxLockLevel = reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_KeyValue = reader.ReadUInt(); + + goto case 1; + } + case 1: + { + m_LockLevel = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if ( version < 3 ) + m_MaxLockLevel = 100; + + if ( version < 4 ) + { + if ( (m_MaxLockLevel - m_LockLevel) == 40 ) + { + m_RequiredSkill = m_LockLevel + 6; + m_LockLevel = m_RequiredSkill - 10; + m_MaxLockLevel = m_RequiredSkill + 39; + } + else + { + m_RequiredSkill = m_LockLevel; + } + } + + m_Locked = reader.ReadBool(); + + break; + } + } + } + + public LockableContainer( int itemID ) : base( itemID ) + { + m_MaxLockLevel = 100; + } + + public LockableContainer( Serial serial ) : base( serial ) + { + } + + public override bool CheckContentDisplay( Mobile from ) + { + return !m_Locked && base.CheckContentDisplay( from ); + } + + public override bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + if (this is DonationBox && dropped is Gold) + { + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "Merci pour votre don, il servira une noble cause"); + return base.TryDropItem(from, dropped, sendFullMessage); + } + if ( from.AccessLevel < AccessLevel.GameMaster && m_Locked ) + { + from.SendLocalizedMessage( 501747 ); // It appears to be locked. + return false; + } + + return base.TryDropItem( from, dropped, sendFullMessage ); + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( from.AccessLevel < AccessLevel.GameMaster && m_Locked ) + { + from.SendLocalizedMessage( 501747 ); // It appears to be locked. + return false; + } + + return base.OnDragDropInto( from, item, p ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( !base.CheckLift( from, item, ref reject ) ) + return false; + + if ( item != this && from.AccessLevel < AccessLevel.GameMaster && m_Locked ) + return false; + + return true; + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( !base.CheckItemUse( from, item ) ) + return false; + + if ( item != this && from.AccessLevel < AccessLevel.GameMaster && m_Locked ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return false; + } + + return true; + } + + public override bool DisplaysContent{ get{ return !m_Locked; } } + + public virtual bool CheckLocked( Mobile from ) + { + bool inaccessible = false; + + if ( m_Locked ) + { + int number; + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + number = 502502; // That is locked, but you open it with your godly powers. + } + else + { + number = 501747; // It appears to be locked. + inaccessible = true; + } + + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", "" ) ); + } + + return inaccessible; + } + + public override void OnTelekinesis( Mobile from ) + { + if ( CheckLocked( from ) ) + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5022 ); + Effects.PlaySound( Location, Map, 0x1F5 ); + return; + } + + base.OnTelekinesis( from ); + } + + public override void OnDoubleClickSecureTrade( Mobile from ) + { + if ( CheckLocked( from ) ) + return; + + base.OnDoubleClickSecureTrade( from ); + } + + public override void Open( Mobile from ) + { + if ( CheckLocked( from ) ) + return; + + base.Open( from ); + } + + public override void OnSnoop( Mobile from ) + { + if ( CheckLocked( from ) ) + return; + + base.OnSnoop( from ); + } + + public virtual void LockPick( Mobile from ) + { + Locked = false; + Picker = from; + + if ( this.TrapOnLockpick && ExecuteTrap( from ) ) + { + this.TrapOnLockpick = false; + } + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( m_IsShipwreckedItem ) + list.Add( 1041645 ); // recovered from a shipwreck + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( m_IsShipwreckedItem ) + LabelTo( from, 1041645 ); //recovered from a shipwreck + } + + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + if ( from.CheckSkill( SkillName.Tinkering, -5.0, 15.0 ) ) + { + from.SendLocalizedMessage( 500636 ); // Your tinker skill was sufficient to make the item lockable. + + Key key = new Key( KeyType.Copper, Key.RandomValue() ); + + KeyValue = key.KeyValue; + DropItem( key ); + + double tinkering = from.Skills[SkillName.Tinkering].Value; + + int level; + + if(this is DonationBox) + level = (int)(tinkering * 0.9); + else + level = (int)(tinkering * 0.8); + + RequiredSkill = level - 4; + LockLevel = level - 14; + MaxLockLevel = level + 35; + + if ( LockLevel == 0 ) + LockLevel = -1; + else if ( LockLevel > 95 ) + LockLevel = 95; + + if ( RequiredSkill > 95 ) + RequiredSkill = 95; + + if ( MaxLockLevel > 95 ) + MaxLockLevel = 95; + } + else + { + from.SendLocalizedMessage( 500637 ); // Your tinker skill was insufficient to make the item lockable. + } + + return 1; + } + + #endregion + + #region IShipwreckedItem Members + + private bool m_IsShipwreckedItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsShipwreckedItem + { + get { return m_IsShipwreckedItem; } + set { m_IsShipwreckedItem = value; } + } + #endregion + + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/MarkContainer.cs b/Scripts/Items/Containers/MarkContainer.cs new file mode 100644 index 0000000..3d5feb5 --- /dev/null +++ b/Scripts/Items/Containers/MarkContainer.cs @@ -0,0 +1,267 @@ +using System; +using Server; +using Server.Commands; + +namespace Server.Items +{ + public class MarkContainer : LockableContainer + { + public static void Initialize() + { + CommandSystem.Register( "SecretLocGen", AccessLevel.Administrator, new CommandEventHandler( SecretLocGen_OnCommand ) ); + } + + [Usage( "SecretLocGen" )] + [Description( "Generates mark containers to Malas secret locations." )] + public static void SecretLocGen_OnCommand( CommandEventArgs e ) + { + CreateMalasPassage( 951, 546, -70, 1006, 994, -70, false, false ); + CreateMalasPassage( 914, 192, -79, 1019, 1062, -70, false, false ); + CreateMalasPassage( 1614, 143, -90, 1214, 1313, -90, false, false ); + CreateMalasPassage( 2176, 324, -90, 1554, 172, -90, false, false ); + CreateMalasPassage( 864, 812, -90, 1061, 1161, -70, false, false ); + CreateMalasPassage( 1051, 1434, -85, 1076, 1244, -70, false, true ); + CreateMalasPassage( 1326, 523, -87, 1201, 1554, -70, false, false ); + CreateMalasPassage( 424, 189, -1, 2333, 1501, -90, true, false ); + CreateMalasPassage( 1313, 1115, -85, 1183, 462, -45, false, false ); + + e.Mobile.SendMessage( "Secret mark containers have been created." ); + } + + private static bool FindMarkContainer( Point3D p, Map map ) + { + IPooledEnumerable eable = map.GetItemsInRange( p, 0 ); + + foreach ( Item item in eable ) + { + if ( item.Z == p.Z && item is MarkContainer ) + { + eable.Free(); + return true; + } + } + + eable.Free(); + return false; + } + + private static void CreateMalasPassage( int x, int y, int z, int xTarget, int yTarget, int zTarget, bool bone, bool locked ) + { + Point3D location = new Point3D( x, y, z ); + + if ( FindMarkContainer( location, Map.Malas ) ) + return; + + MarkContainer cont = new MarkContainer( bone, locked ); + cont.TargetMap = Map.Malas; + cont.Target = new Point3D( xTarget, yTarget, zTarget ); + cont.Description = "strange location"; + + cont.MoveToWorld( location, Map.Malas ); + } + + private bool m_AutoLock; + private InternalTimer m_RelockTimer; + private Map m_TargetMap; + private Point3D m_Target; + private string m_Description; + + [CommandProperty( AccessLevel.GameMaster )] + public bool AutoLock + { + get { return m_AutoLock; } + set + { + m_AutoLock = value; + + if ( !m_AutoLock ) + StopTimer(); + else if ( !Locked && m_RelockTimer == null ) + m_RelockTimer = new InternalTimer( this ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Map TargetMap { get { return m_TargetMap; } set { m_TargetMap = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Target { get { return m_Target; } set { m_Target = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Bone + { + get { return ItemID == 0xECA; } + set + { + ItemID = value ? 0xECA : 0xE79; + Hue = value ? 1102 : 0; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Description { get { return m_Description; } set { m_Description = value; } } + + public override bool IsDecoContainer + { + get{ return false; } + } + + [Constructable] + public MarkContainer() : this( false ) + { + } + + [Constructable] + public MarkContainer( bool bone ) : this( bone, false ) + { + } + + [Constructable] + public MarkContainer( bool bone, bool locked ) : base( bone ? 0xECA : 0xE79 ) + { + Movable = false; + + if ( bone ) + Hue = 1102; + + m_AutoLock = locked; + Locked = locked; + + if ( locked ) + LockLevel = -255; + } + + public MarkContainer( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public override bool Locked + { + get { return base.Locked; } + set + { + base.Locked = value; + + if ( m_AutoLock ) + { + StopTimer(); + + if ( !Locked ) + m_RelockTimer = new InternalTimer( this ); + } + } + } + + public void StopTimer() + { + if ( m_RelockTimer != null ) + m_RelockTimer.Stop(); + + m_RelockTimer = null; + } + + private class InternalTimer : Timer + { + private MarkContainer m_Container; + private DateTime m_RelockTime; + + public MarkContainer Container { get { return m_Container; } } + public DateTime RelockTime { get { return m_RelockTime; } } + + public InternalTimer( MarkContainer container ) : this( container, TimeSpan.FromMinutes( 5.0 ) ) + { + } + + public InternalTimer( MarkContainer container, TimeSpan delay ) : base( delay ) + { + m_Container = container; + m_RelockTime = DateTime.Now + delay; + + Start(); + } + + protected override void OnTick() + { + m_Container.Locked = true; + m_Container.LockLevel = -255; + } + } + + public void Mark( RecallRune rune ) + { + if ( TargetMap != null ) + { + rune.Marked = true; + rune.TargetMap = m_TargetMap; + rune.Target = m_Target; + rune.Description = m_Description; + rune.House = null; + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + RecallRune rune = dropped as RecallRune; + + if ( rune != null && base.OnDragDrop( from, dropped ) ) + { + Mark( rune ); + + return true; + } + else + { + return false; + } + } + + public override bool OnDragDropInto( Mobile from, Item dropped, Point3D p ) + { + RecallRune rune = dropped as RecallRune; + + if ( rune != null && base.OnDragDropInto( from, dropped, p ) ) + { + Mark( rune ); + + return true; + } + else + { + return false; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( m_AutoLock ); + + if ( !Locked && m_AutoLock ) + writer.WriteDeltaTime( m_RelockTimer.RelockTime ); + + writer.Write( m_TargetMap ); + writer.Write( m_Target ); + writer.Write( m_Description ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_AutoLock = reader.ReadBool(); + + if ( !Locked && m_AutoLock ) + m_RelockTimer = new InternalTimer( this, reader.ReadDeltaTime() - DateTime.Now ); + + m_TargetMap = reader.ReadMap(); + m_Target = reader.ReadPoint3D(); + m_Description = reader.ReadString(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/ParagonChest.cs b/Scripts/Items/Containers/ParagonChest.cs new file mode 100644 index 0000000..cb35c95 --- /dev/null +++ b/Scripts/Items/Containers/ParagonChest.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.ContextMenus; +using Server.Engines.PartySystem; + +namespace Server.Items +{ + [Flipable] + public class ParagonChest : LockableContainer + { + private static int[] m_ItemIDs = new int[] + { + 0x9AB, 0xE40, 0xE41, 0xE7C + }; + + private static int[] m_Hues = new int[] + { + 0x0, 0x455, 0x47E, 0x89F, 0x8A5, 0x8AB, + 0x966, 0x96D, 0x972, 0x973, 0x979 + }; + + private string m_Name; + + [Constructable] + public ParagonChest( string name, int level ) : base( Utility.RandomList( m_ItemIDs ) ) + { + m_Name = name; + Hue = Utility.RandomList( m_Hues ); + Fill( level ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, 1063449, m_Name ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1063449, m_Name ); + } + + private static void GetRandomAOSStats( out int attributeCount, out int min, out int max ) + { + int rnd = Utility.Random( 15 ); + + if ( rnd < 1 ) + { + attributeCount = Utility.RandomMinMax( 2, 6 ); + min = 20; max = 70; + } + else if ( rnd < 3 ) + { + attributeCount = Utility.RandomMinMax( 2, 4 ); + min = 20; max = 50; + } + else if ( rnd < 6 ) + { + attributeCount = Utility.RandomMinMax( 2, 3 ); + min = 20; max = 40; + } + else if ( rnd < 10 ) + { + attributeCount = Utility.RandomMinMax( 1, 2 ); + min = 10; max = 30; + } + else + { + attributeCount = 1; + min = 10; max = 20; + } + } + + public void Flip() + { + switch ( ItemID ) + { + case 0x9AB : ItemID = 0xE7C; break; + case 0xE7C : ItemID = 0x9AB; break; + + case 0xE40 : ItemID = 0xE41; break; + case 0xE41 : ItemID = 0xE40; break; + } + } + + private void Fill( int level ) + { + TrapType = TrapType.ExplosionTrap; + TrapPower = level * 25; + TrapLevel = level; + Locked = true; + + switch ( level ) + { + case 1: RequiredSkill = 36; break; + case 2: RequiredSkill = 76; break; + case 3: RequiredSkill = 84; break; + case 4: RequiredSkill = 92; break; + case 5: RequiredSkill = 100; break; + } + + LockLevel = RequiredSkill - 10; + MaxLockLevel = RequiredSkill + 40; + + DropItem( new Gold( level * 200 ) ); + + for ( int i = 0; i < level; ++i ) + DropItem( Loot.RandomScroll( 0, 63, SpellbookType.Regular ) ); + + for ( int i = 0; i < level * 2; ++i ) + { + Item item; + + if ( Core.AOS ) + item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(); + else + item = Loot.RandomArmorOrShieldOrWeapon(); + + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( weapon, attributeCount, min, max ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random( 6 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random( 6 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random( 6 ); + } + + DropItem( item ); + } + else if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if ( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( armor, attributeCount, min, max ); + } + else + { + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random( 6 ); + armor.Durability = (ArmorDurabilityLevel)Utility.Random( 6 ); + } + + DropItem( item ); + } + else if( item is BaseHat ) + { + BaseHat hat = (BaseHat)item; + + if( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( hat, attributeCount, min, max ); + } + + DropItem( item ); + } + else if( item is BaseJewel ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, attributeCount, min, max ); + + DropItem( item ); + } + } + + for ( int i = 0; i < level; i++ ) + { + Item item = Loot.RandomPossibleReagent(); + item.Amount = Utility.RandomMinMax( 40, 60 ); + DropItem( item ); + } + + for ( int i = 0; i < level; i++ ) + { + Item item = Loot.RandomGem(); + DropItem( item ); + } + + DropItem( new TreasureMap( level + 1, ( Utility.RandomBool() ? Map.Felucca : Map.Trammel ) ) ); + } + + public ParagonChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Name ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Name = Utility.Intern( reader.ReadString() ); + } + } +} diff --git a/Scripts/Items/Containers/SalvageBag.cs b/Scripts/Items/Containers/SalvageBag.cs new file mode 100644 index 0000000..67cb879 --- /dev/null +++ b/Scripts/Items/Containers/SalvageBag.cs @@ -0,0 +1,412 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Craft; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class SalvageBag : Bag + { + private bool m_Failure; + + public override int LabelNumber { get { return 1079931; } } // Salvage Bag + + [Constructable] + public SalvageBag() + : this( Utility.RandomBlueHue() ) + { + } + + [Constructable] + public SalvageBag( int hue ) + { + Weight = 2.0; + Hue = hue; + m_Failure = false; + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if( from.Alive ) + { + list.Add( new SalvageIngotsEntry( this, IsChildOf( from.Backpack ) && Resmeltables() ) ); + list.Add( new SalvageClothEntry( this, IsChildOf( from.Backpack ) && Scissorables() ) ); + list.Add( new SalvageAllEntry( this, IsChildOf( from.Backpack ) && Resmeltables() && Scissorables() ) ); + } + } + + #region Checks + private bool Resmeltables() //Where context menu checks for metal items and dragon barding deeds + { + foreach( Item i in Items ) + { + if( i != null && !i.Deleted ) + { + if( i is BaseWeapon ) + { + if( CraftResources.GetType( ( (BaseWeapon)i ).Resource ) == CraftResourceType.Metal ) + return true; + } + if( i is BaseArmor ) + { + if( CraftResources.GetType( ( (BaseArmor)i ).Resource ) == CraftResourceType.Metal ) + return true; + } + if( i is DragonBardingDeed ) + return true; + } + } + return false; + } + + private bool Scissorables() //Where context menu checks for Leather items and cloth items + { + foreach( Item i in Items ) + { + if( i != null && !i.Deleted ) + { + if( i is IScissorable ) + { + if( i is BaseClothing ) + return true; + if( i is BaseArmor ) + { + if( CraftResources.GetType( ( (BaseArmor)i ).Resource ) == CraftResourceType.Leather ) + return true; + } + if( ( i is Cloth ) || ( i is BoltOfCloth ) || ( i is Hides ) || ( i is BonePile ) ) + return true; + } + } + } + return false; + } + #endregion + + #region Resmelt.cs + private bool Resmelt( Mobile from, Item item, CraftResource resource ) + { + try + { + if( CraftResources.GetType( resource ) != CraftResourceType.Metal ) + return false; + + CraftResourceInfo info = CraftResources.GetInfo( resource ); + + if( info == null || info.ResourceTypes.Length == 0 ) + return false; + + CraftItem craftItem = DefBlacksmithy.CraftSystem.CraftItems.SearchFor( item.GetType() ); + + if( craftItem == null || craftItem.Resources.Count == 0 ) + return false; + + CraftRes craftResource = craftItem.Resources.GetAt( 0 ); + + if( craftResource.Amount < 2 ) + return false; // Not enough metal to resmelt + + double difficulty = 0.0; + + switch ( resource ) + { + case CraftResource.MRusty: difficulty = 50.0; break; + case CraftResource.MOldcopper: difficulty = 60.0; break; + case CraftResource.MDullcopper: difficulty = 65.0; break; + case CraftResource.MShadow: difficulty = 70.0; break; + case CraftResource.MCopper: difficulty = 75.0; break; + case CraftResource.MBronze: difficulty = 80.0; break; + case CraftResource.MGold: difficulty = 85.0; break; + case CraftResource.MRose: difficulty = 87.0; break; + case CraftResource.MAgapite: difficulty = 90.0; break; + case CraftResource.MValorite: difficulty = 90.0; break; + case CraftResource.MBloodrock: difficulty = 93.0; break; + case CraftResource.MVerite: difficulty = 95.0; break; + case CraftResource.MSilver: difficulty = 95.0; break; + case CraftResource.MDragon: difficulty = 95.0; break; + case CraftResource.MTitan: difficulty = 95.0; break; + case CraftResource.MCrystaline: difficulty = 95.0; break; + case CraftResource.MKrynite: difficulty = 95.0; break; + case CraftResource.MVulcan: difficulty = 95.0; break; + case CraftResource.MBloodcrest: difficulty = 95.0; break; + case CraftResource.MElvin: difficulty = 95.0; break; + case CraftResource.MAcid: difficulty = 95.0; break; + case CraftResource.MAqua: difficulty = 95.0; break; + case CraftResource.MEldar: difficulty = 95.0; break; + case CraftResource.MGlowing: difficulty = 95.0; break; + case CraftResource.MGorgan: difficulty = 95.0; break; + case CraftResource.MSteel: difficulty = 95.5; break; + case CraftResource.MSandrock: difficulty = 95.0; break; + case CraftResource.MMytheril: difficulty = 97.5; break; + case CraftResource.MBlackrock: difficulty = 98.0; break; + } + + Type resourceType = info.ResourceTypes[ 0 ]; + Item ingot = (Item)Activator.CreateInstance( resourceType ); + + if( item is DragonBardingDeed || ( item is BaseArmor && ( (BaseArmor)item ).PlayerConstructed ) || ( item is BaseWeapon && ( (BaseWeapon)item ).PlayerConstructed ) || ( item is BaseClothing && ( (BaseClothing)item ).PlayerConstructed ) ) + { + double mining = from.Skills[ SkillName.Mining ].Value; + if( mining > 100.0 ) + mining = 100.0; + double amount = ( ( ( 4 + mining ) * craftResource.Amount - 4 ) * 0.0068 ); + if( amount < 2 ) + ingot.Amount = 2; + else + ingot.Amount = (int)amount; + } + else + { + ingot.Amount = 2; + } + + if ( difficulty > from.Skills[ SkillName.Mining ].Value ) + { + m_Failure = true; + ingot.Delete(); + } + else + item.Delete(); + + from.AddToBackpack( ingot ); + + from.PlaySound( 0x2A ); + from.PlaySound( 0x240 ); + + return true; + } + catch( Exception ex ) + { + Console.WriteLine( ex.ToString() ); + } + + return false; + } + #endregion + + #region Salvaging + private void SalvageIngots( Mobile from ) + { + Item[] tools = from.Backpack.FindItemsByType( typeof( BaseTool ) ); + + bool ToolFound = false; + foreach( Item tool in tools ) + { + if( tool is BaseTool && ( (BaseTool)tool ).CraftSystem == DefBlacksmithy.CraftSystem ) + ToolFound = true; + } + + if( !ToolFound ) + { + from.SendLocalizedMessage( 1079822 ); // You need a blacksmithing tool in order to salvage ingots. + return; + } + + bool anvil, forge; + DefBlacksmithy.CheckAnvilAndForge( from, 2, out anvil, out forge ); + + if( !forge ) + { + from.SendLocalizedMessage( 1044265 ); // You must be near a forge. + return; + } + + int salvaged = 0; + int notSalvaged = 0; + + Container sBag = this; + + List Smeltables = sBag.FindItemsByType(); + + for(int i = Smeltables.Count - 1; i >= 0; i--) + { + Item item = Smeltables[ i ]; + + if( item is BaseArmor ) + { + if( Resmelt( from, item, ( (BaseArmor)item ).Resource ) ) + salvaged++; + else + notSalvaged++; + } + else if( item is BaseWeapon ) + { + if( Resmelt( from, item, ( (BaseWeapon)item ).Resource ) ) + salvaged++; + else + notSalvaged++; + } + else if( item is DragonBardingDeed ) + { + if( Resmelt( from, item, ( (DragonBardingDeed)item ).Resource ) ) + salvaged++; + + else + notSalvaged++; + } + } + if( m_Failure ) + { + from.SendLocalizedMessage( 1079975 ); // You failed to smelt some metal for lack of skill. + m_Failure = false; + } + else + from.SendLocalizedMessage( 1079973, String.Format( "{0}\t{1}", salvaged, salvaged + notSalvaged ) ); // Salvaged: ~1_COUNT~/~2_NUM~ blacksmithed items + } + + private void SalvageCloth( Mobile from ) + { + Scissors scissors = from.Backpack.FindItemByType( typeof( Scissors ) ) as Scissors; + if( scissors == null ) + { + from.SendLocalizedMessage( 1079823 ); // You need scissors in order to salvage cloth. + return; + } + + int salvaged = 0; + int notSalvaged = 0; + + Container sBag = this; + + List scissorables = sBag.FindItemsByType(); + + for (int i = scissorables.Count - 1; i >= 0; --i) + { + Item item = scissorables[i]; + + if (item is IScissorable) + { + IScissorable scissorable = (IScissorable)item; + + if (Scissors.CanScissor(from, scissorable) && scissorable.Scissor(from, scissors)) + ++salvaged; + else + ++notSalvaged; + } + } + + from.SendLocalizedMessage( 1079974, String.Format( "{0}\t{1}", salvaged, salvaged + notSalvaged ) ); // Salvaged: ~1_COUNT~/~2_NUM~ tailored items + + Container pack = from.Backpack; + + foreach (Item i in ((Container)this).FindItemsByType(typeof(Item), true)) + { + if ((i is Leather) || (i is Cloth) || (i is SpinedLeather) || (i is HornedLeather) || (i is BarbedLeather) || (i is DaemonLeather) || (i is Bandage) || (i is Bone)) + { + from.AddToBackpack( i ); + } + } + } + + private void SalvageAll( Mobile from ) + { + SalvageIngots( from ); + + SalvageCloth( from ); + } + #endregion + + #region ContextMenuEntries + private class SalvageAllEntry : ContextMenuEntry + { + private SalvageBag m_Bag; + + public SalvageAllEntry( SalvageBag bag, bool enabled ) + : base( 6276 ) + { + m_Bag = bag; + + if( !enabled ) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if( m_Bag.Deleted ) + return; + + Mobile from = Owner.From; + + if( from.CheckAlive() ) + m_Bag.SalvageAll( from ); + } + } + + private class SalvageIngotsEntry : ContextMenuEntry + { + private SalvageBag m_Bag; + + public SalvageIngotsEntry( SalvageBag bag, bool enabled ) + : base( 6277 ) + { + m_Bag = bag; + + if( !enabled ) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if( m_Bag.Deleted ) + return; + + Mobile from = Owner.From; + + if( from.CheckAlive() ) + m_Bag.SalvageIngots( from ); + } + } + + private class SalvageClothEntry : ContextMenuEntry + { + private SalvageBag m_Bag; + + public SalvageClothEntry( SalvageBag bag, bool enabled ) + : base( 6278 ) + { + m_Bag = bag; + + if( !enabled ) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if( m_Bag.Deleted ) + return; + + Mobile from = Owner.From; + + if( from.CheckAlive() ) + m_Bag.SalvageCloth( from ); + } + } + #endregion + + #region Serialization + public SalvageBag( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + #endregion + } +} diff --git a/Scripts/Items/Containers/Strongbox.cs b/Scripts/Items/Containers/Strongbox.cs new file mode 100644 index 0000000..667719e --- /dev/null +++ b/Scripts/Items/Containers/Strongbox.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xE80, 0x9A8 )] + public class StrongBox : BaseContainer, IChopable + { + private Mobile m_Owner; + private BaseHouse m_House; + + public override double DefaultWeight{ get{ return 100; } } + public override int LabelNumber { get { return 1023712; } } + + public StrongBox( Mobile owner, BaseHouse house ) : base( 0xE80 ) + { + m_Owner = owner; + m_House = house; + + MaxItems = 25; + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get + { + return m_Owner; + } + set + { + m_Owner = value; + InvalidateProperties(); + } + } + + public override int DefaultMaxWeight{ get{ return 0; } } + + public StrongBox( Serial serial ) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Owner ); + writer.Write( m_House ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Owner = reader.ReadMobile(); + m_House = reader.ReadItem() as BaseHouse; + + break; + } + } + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerCallback( Validate ) ); + } + + private void Validate() + { + if ( m_Owner != null && m_House != null && !m_House.IsCoOwner( m_Owner ) ) + { + Console.WriteLine( "Warning: Destroying strongbox of {0}", m_Owner.Name ); + Destroy(); + } + } + + public override bool Decays + { + get + { + if ( m_House != null && m_Owner != null && !m_Owner.Deleted ) + return !m_House.IsCoOwner( m_Owner ); + else + return true; + } + } + + public override TimeSpan DecayTime + { + get + { + return TimeSpan.FromMinutes( 30.0 ); + } + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_Owner != null ) + list.Add( 1042887, m_Owner.Name ); // a strong box owned by ~1_OWNER_NAME~ + else + base.AddNameProperty( list ); + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Owner != null ) + { + LabelTo( from, 1042887, m_Owner.Name ); // a strong box owned by ~1_OWNER_NAME~ + + if ( CheckContentDisplay( from ) ) + LabelTo( from, "({0} items, {1} stones)", TotalItems, TotalWeight ); + } + else + { + base.OnSingleClick( from ); + } + } + + public override bool IsAccessibleTo( Mobile m ) + { + if ( m_Owner == null || m_Owner.Deleted || m_House == null || m_House.Deleted || m.AccessLevel >= AccessLevel.GameMaster ) + return true; + + return m == m_Owner && m_House.IsCoOwner( m ) && base.IsAccessibleTo( m ); + } + + private void Chop( Mobile from ) + { + Effects.PlaySound( Location, Map, 0x3B3 ); + from.SendLocalizedMessage( 500461 ); // You destroy the item. + Destroy(); + } + + public void OnChop( Mobile from ) + { + if ( m_House != null && !m_House.Deleted && m_Owner != null && !m_Owner.Deleted ) + { + if ( from == m_Owner || m_House.IsOwner( from ) ) + Chop( from ); + } + else + { + Chop( from ); + } + } + + public Container ConvertToStandardContainer() + { + Container metalBox = new MetalBox(); + List subItems = new List( Items ); + + foreach ( Item subItem in subItems ) + { + metalBox.AddItem( subItem ); + } + + this.Delete(); + + return metalBox; + } + } +} diff --git a/Scripts/Items/Containers/TrapableContainer.cs b/Scripts/Items/Containers/TrapableContainer.cs new file mode 100644 index 0000000..9dd3432 --- /dev/null +++ b/Scripts/Items/Containers/TrapableContainer.cs @@ -0,0 +1,260 @@ +using System; + +namespace Server.Items +{ + public enum TrapType + { + None, + MagicTrap, + ExplosionTrap, + DartTrap, + PoisonTrap + } + + public abstract class TrapableContainer : BaseContainer, ITelekinesisable + { + private TrapType m_TrapType; + private int m_TrapPower; + private int m_TrapLevel; + + [CommandProperty( AccessLevel.GameMaster )] + public TrapType TrapType + { + get + { + return m_TrapType; + } + set + { + m_TrapType = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TrapPower + { + get + { + return m_TrapPower; + } + set + { + m_TrapPower = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TrapLevel + { + get + { + return m_TrapLevel; + } + set + { + m_TrapLevel = value; + } + } + + public virtual bool TrapOnOpen{ get{ return true; } } + + public TrapableContainer( int itemID ) : base( itemID ) + { + } + + public TrapableContainer( Serial serial ) : base( serial ) + { + } + + private void SendMessageTo( Mobile to, int number, int hue ) + { + if ( Deleted || !to.CanSee( this ) ) + return; + + to.Send( new Network.MessageLocalized( Serial, ItemID, Network.MessageType.Regular, hue, 3, number, "", "" ) ); + } + + private void SendMessageTo( Mobile to, string text, int hue ) + { + if ( Deleted || !to.CanSee( this ) ) + return; + + to.Send( new Network.UnicodeMessage( Serial, ItemID, Network.MessageType.Regular, hue, 3, "ENU", "", text ) ); + } + + public virtual bool ExecuteTrap( Mobile from ) + { + if ( m_TrapType != TrapType.None ) + { + Point3D loc = this.GetWorldLocation(); + Map facet = this.Map; + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + SendMessageTo( from, "That is trapped, but you open it with your godly powers.", 0x3B2 ); + return false; + } + + switch ( m_TrapType ) + { + case TrapType.ExplosionTrap: + { + SendMessageTo( from, 502999, 0x3B2 ); // You set off a trap! + + if ( from.InRange( loc, 3 ) ) + { + int damage; + + if ( m_TrapLevel > 0 ) + damage = Utility.RandomMinMax( 10, 30 ) * m_TrapLevel; + else + damage = m_TrapPower; + + AOS.Damage( from, damage, 0, 100, 0, 0, 0 ); + + // Your skin blisters from the heat! + from.LocalOverheadMessage( Network.MessageType.Regular, 0x2A, 503000 ); + } + + Effects.SendLocationEffect( loc, facet, 0x36BD, 15, 10 ); + Effects.PlaySound( loc, facet, 0x307 ); + + break; + } + case TrapType.MagicTrap: + { + if ( from.InRange( loc, 1 ) ) + from.Damage( m_TrapPower ); + //AOS.Damage( from, m_TrapPower, 0, 100, 0, 0, 0 ); + + Effects.PlaySound( loc, Map, 0x307 ); + + Effects.SendLocationEffect( new Point3D( loc.X - 1, loc.Y, loc.Z ), Map, 0x36BD, 15 ); + Effects.SendLocationEffect( new Point3D( loc.X + 1, loc.Y, loc.Z ), Map, 0x36BD, 15 ); + + Effects.SendLocationEffect( new Point3D( loc.X, loc.Y - 1, loc.Z ), Map, 0x36BD, 15 ); + Effects.SendLocationEffect( new Point3D( loc.X, loc.Y + 1, loc.Z ), Map, 0x36BD, 15 ); + + Effects.SendLocationEffect( new Point3D( loc.X + 1, loc.Y + 1, loc.Z + 11 ), Map, 0x36BD, 15 ); + + break; + } + case TrapType.DartTrap: + { + SendMessageTo( from, 502999, 0x3B2 ); // You set off a trap! + + if ( from.InRange( loc, 3 ) ) + { + int damage; + + if ( m_TrapLevel > 0 ) + damage = Utility.RandomMinMax( 5, 15 ) * m_TrapLevel; + else + damage = m_TrapPower; + + AOS.Damage( from, damage, 100, 0, 0, 0, 0 ); + + // A dart imbeds itself in your flesh! + from.LocalOverheadMessage( Network.MessageType.Regular, 0x62, 502998 ); + } + + Effects.PlaySound( loc, facet, 0x223 ); + + break; + } + case TrapType.PoisonTrap: + { + SendMessageTo( from, 502999, 0x3B2 ); // You set off a trap! + + if ( from.InRange( loc, 3 ) ) + { + Poison poison; + + if ( m_TrapLevel > 0 ) + { + poison = Poison.GetPoison( Math.Max( 0, Math.Min( 4, m_TrapLevel - 1 ) ) ); + } + else + { + AOS.Damage( from, m_TrapPower, 0, 0, 0, 100, 0 ); + poison = Poison.Greater; + } + + from.ApplyPoison( from, poison ); + + // You are enveloped in a noxious green cloud! + from.LocalOverheadMessage( Network.MessageType.Regular, 0x44, 503004 ); + } + + Effects.SendLocationEffect( loc, facet, 0x113A, 10, 20 ); + Effects.PlaySound( loc, facet, 0x231 ); + + break; + } + } + + m_TrapType = TrapType.None; + m_TrapPower = 0; + m_TrapLevel = 0; + return true; + } + + return false; + } + + public virtual void OnTelekinesis( Mobile from ) + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5022 ); + Effects.PlaySound( Location, Map, 0x1F5 ); + + if (this.TrapOnOpen) + { + ExecuteTrap(from); + } + } + + public override void Open( Mobile from ) + { + if ( !this.TrapOnOpen || !ExecuteTrap( from ) ) + base.Open( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (int) m_TrapLevel ); + + writer.Write( (int) m_TrapPower ); + writer.Write( (int) m_TrapType ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_TrapLevel = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_TrapPower = reader.ReadInt(); + goto case 0; + } + case 0: + { + m_TrapType = (TrapType)reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/TreasureChest.cs b/Scripts/Items/Containers/TreasureChest.cs new file mode 100644 index 0000000..ceb2c08 --- /dev/null +++ b/Scripts/Items/Containers/TreasureChest.cs @@ -0,0 +1,89 @@ +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; +using System; + +namespace Server.Items +{ + [FlipableAttribute( 0xe43, 0xe42 )] + public class WoodenTreasureChest : BaseTreasureChest + { + [Constructable] + public WoodenTreasureChest() : base( 0xE43 ) + { + } + + public WoodenTreasureChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xe41, 0xe40 )] + public class MetalGoldenTreasureChest : BaseTreasureChest + { + [Constructable] + public MetalGoldenTreasureChest() : base( 0xE41 ) + { + } + + public MetalGoldenTreasureChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x9ab, 0xe7c )] + public class MetalTreasureChest : BaseTreasureChest + { + [Constructable] + public MetalTreasureChest() : base( 0x9AB ) + { + } + + public MetalTreasureChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Containers/TreasureMapChest.cs b/Scripts/Items/Containers/TreasureMapChest.cs new file mode 100644 index 0000000..628b8d8 --- /dev/null +++ b/Scripts/Items/Containers/TreasureMapChest.cs @@ -0,0 +1,582 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.PartySystem; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class TreasureMapChest : LockableContainer + { + public override int LabelNumber{ get{ return 3000541; } } + + public static Type[] Artifacts { get { return m_Artifacts; } } + + private static Type[] m_Artifacts = new Type[] + { + typeof( CandelabraOfSouls ), typeof( GoldBricks ), typeof( PhillipsWoodenSteed ), + typeof( ArcticDeathDealer ), typeof( BlazeOfDeath ), typeof( BurglarsBandana ), + typeof( CavortingClub ), typeof( DreadPirateHat ), + typeof( EnchantedTitanLegBone ), typeof( GwennosHarp ), typeof( IolosLute ), + typeof( LunaLance ), typeof( NightsKiss ), typeof( NoxRangersHeavyCrossbow ), + typeof( PolarBearMask ), typeof( VioletCourage ), typeof( HeartOfTheLion ), + typeof( ColdBlood ), typeof( AlchemistsBauble ) + }; + + private int m_Level; + private DateTime m_DeleteTime; + private Timer m_Timer; + private Mobile m_Owner; + private bool m_Temporary; + + private List m_Guardians; + + [CommandProperty( AccessLevel.GameMaster )] + public int Level{ get{ return m_Level; } set{ m_Level = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner{ get{ return m_Owner; } set{ m_Owner = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime DeleteTime{ get{ return m_DeleteTime; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Temporary{ get{ return m_Temporary; } set{ m_Temporary = value; } } + + public List Guardians { get { return m_Guardians; } } + + [Constructable] + public TreasureMapChest( int level ) : this( null, level, false ) + { + } + + public TreasureMapChest( Mobile owner, int level, bool temporary ) : base( 0xE40 ) + { + m_Owner = owner; + m_Level = level; + m_DeleteTime = DateTime.Now + TimeSpan.FromHours( 3.0 ); + + m_Temporary = temporary; + m_Guardians = new List(); + + m_Timer = new DeleteTimer( this, m_DeleteTime ); + m_Timer.Start(); + + Fill( this, level ); + } + + private static void GetRandomAOSStats( out int attributeCount, out int min, out int max ) + { + int rnd = Utility.Random( 15 ); + + if ( Core.SE ) + { + if ( rnd < 1 ) + { + attributeCount = Utility.RandomMinMax( 3, 5 ); + min = 50; max = 100; + } + else if ( rnd < 3 ) + { + attributeCount = Utility.RandomMinMax( 2, 5 ); + min = 40; max = 80; + } + else if ( rnd < 6 ) + { + attributeCount = Utility.RandomMinMax( 2, 4 ); + min = 30; max = 60; + } + else if ( rnd < 10 ) + { + attributeCount = Utility.RandomMinMax( 1, 3 ); + min = 20; max = 40; + } + else + { + attributeCount = 1; + min = 10; max = 20; + } + } + else + { + if ( rnd < 1 ) + { + attributeCount = Utility.RandomMinMax( 2, 5 ); + min = 20; max = 70; + } + else if ( rnd < 3 ) + { + attributeCount = Utility.RandomMinMax( 2, 4 ); + min = 20; max = 50; + } + else if ( rnd < 6 ) + { + attributeCount = Utility.RandomMinMax( 2, 3 ); + min = 20; max = 40; + } + else if ( rnd < 10 ) + { + attributeCount = Utility.RandomMinMax( 1, 2 ); + min = 10; max = 30; + } + else + { + attributeCount = 1; + min = 10; max = 20; + } + } + } + + public static void Fill( LockableContainer cont, int level ) + { + cont.Movable = false; + cont.Locked = true; + int numberItems; + + if ( level == 0 ) + { + cont.LockLevel = 0; // Can't be unlocked + + cont.DropItem( new Gold( Utility.RandomMinMax( 50, 100 ) ) ); + + if ( Utility.RandomDouble() < 0.75 ) + cont.DropItem( new TreasureMap( 0, Map.Trammel ) ); + } + else + { + cont.TrapType = TrapType.ExplosionTrap; + cont.TrapPower = level * 25; + cont.TrapLevel = level; + + // Scriptiz : ajout des talismans aux coffres + for (int i = 1; i <= level; i++ ) + { + if (Utility.Random(10) < level) + cont.DropItem(new RandomTalisman()); + } + + switch ( level ) + { + case 1: cont.RequiredSkill = 36; break; + case 2: cont.RequiredSkill = 76; break; + case 3: cont.RequiredSkill = 84; break; + case 4: cont.RequiredSkill = 92; break; + case 5: cont.RequiredSkill = 100; break; + case 6: cont.RequiredSkill = 100; break; + } + + cont.LockLevel = cont.RequiredSkill - 10; + cont.MaxLockLevel = cont.RequiredSkill + 40; + + //Publish 67 gold change + //if ( Core.SA ) + // cont.DropItem( new Gold( level * 5000 ) ); + //else + cont.DropItem( new Gold( level * 1000 ) ); + + for ( int i = 0; i < level * 5; ++i ) + cont.DropItem( Loot.RandomScroll( 0, 63, SpellbookType.Regular ) ); + + if ( Core.SE) + { + switch ( level ) + { + case 1: numberItems = 5; break; + case 2: numberItems = 10; break; + case 3: numberItems = 15; break; + case 4: numberItems = 38; break; + case 5: numberItems = 50; break; + case 6: numberItems = 60; break; + default: numberItems = 0; break; + }; + } + else + numberItems = level * 6; + + for ( int i = 0; i < numberItems; ++i ) + { + Item item; + + if ( Core.AOS ) + item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(); + else + item = Loot.RandomArmorOrShieldOrWeapon(); + + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( weapon, attributeCount, min, max ); + } + else + { + weapon.DamageLevel = (WeaponDamageLevel)Utility.Random( 6 ); + weapon.AccuracyLevel = (WeaponAccuracyLevel)Utility.Random( 6 ); + weapon.DurabilityLevel = (WeaponDurabilityLevel)Utility.Random( 6 ); + } + + cont.DropItem( item ); + } + else if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if ( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( armor, attributeCount, min, max ); + } + else + { + armor.ProtectionLevel = (ArmorProtectionLevel)Utility.Random( 6 ); + armor.Durability = (ArmorDurabilityLevel)Utility.Random( 6 ); + } + + cont.DropItem( item ); + } + else if( item is BaseHat ) + { + BaseHat hat = (BaseHat)item; + + if( Core.AOS ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( hat, attributeCount, min, max ); + } + + cont.DropItem( item ); + } + else if( item is BaseJewel ) + { + int attributeCount; + int min, max; + + GetRandomAOSStats( out attributeCount, out min, out max ); + + BaseRunicTool.ApplyAttributesTo( (BaseJewel)item, attributeCount, min, max ); + + cont.DropItem( item ); + } + } + } + + int reagents; + if ( level == 0 ) + reagents = 12; + else + reagents = level * 3; + + for ( int i = 0; i < reagents; i++ ) + { + Item item = Loot.RandomPossibleReagent(); + item.Amount = Utility.RandomMinMax( 40, 60 ); + cont.DropItem( item ); + } + + int gems; + if ( level == 0 ) + gems = 2; + else + gems = level * 3; + + for ( int i = 0; i < gems; i++ ) + { + Item item = Loot.RandomGem(); + cont.DropItem( item ); + } + + if ( level == 6 && Core.AOS ) + cont.DropItem( (Item)Activator.CreateInstance( m_Artifacts[Utility.Random(m_Artifacts.Length)] ) ); + } + + public override bool CheckLocked( Mobile from ) + { + if ( !this.Locked ) + return false; + + if ( this.Level == 0 && from.AccessLevel < AccessLevel.GameMaster ) + { + foreach ( Mobile m in this.Guardians ) + { + if ( m.Alive ) + { + from.SendLocalizedMessage( 1046448 ); // You must first kill the guardians before you may open this chest. + return true; + } + } + + LockPick( from ); + return false; + } + else + { + return base.CheckLocked( from ); + } + } + + private List m_Lifted = new List(); + + private bool CheckLoot( Mobile m, bool criminalAction ) + { + if ( m_Temporary ) + return false; + + if ( m.AccessLevel >= AccessLevel.GameMaster || m_Owner == null || m == m_Owner ) + return true; + + Party p = Party.Get( m_Owner ); + + if ( p != null && p.Contains( m ) ) + return true; + + Map map = this.Map; + + if ( map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0 ) + { + if ( criminalAction ) + m.CriminalAction( true ); + else + m.SendLocalizedMessage( 1010630 ); // Taking someone else's treasure is a criminal offense! + + return true; + } + + m.SendLocalizedMessage( 1010631 ); // You did not discover this chest! + return false; + } + + public override bool IsDecoContainer + { + get{ return false; } + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + return CheckLoot( from, item != this ) && base.CheckItemUse( from, item ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + return CheckLoot( from, true ) && base.CheckLift( from, item, ref reject ); + } + + public override void OnItemLifted( Mobile from, Item item ) + { + bool notYetLifted = !m_Lifted.Contains( item ); + + from.RevealingAction(); + + if ( notYetLifted ) + { + m_Lifted.Add( item ); + + if ( 0.1 >= Utility.RandomDouble() ) // 10% chance to spawn a new monster + TreasureMap.Spawn( m_Level, GetWorldLocation(), Map, from, false ); + } + + base.OnItemLifted( from, item ); + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + if ( m.AccessLevel < AccessLevel.GameMaster ) + { + m.SendLocalizedMessage( 1048122, "", 0x8A5 ); // The chest refuses to be filled with treasure again. + return false; + } + + return base.CheckHold( m, item, message, checkItems, plusItems, plusWeight ); + } + + public TreasureMapChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( m_Guardians, true ); + writer.Write( (bool) m_Temporary ); + + writer.Write( m_Owner ); + + writer.Write( (int) m_Level ); + writer.WriteDeltaTime( m_DeleteTime ); + writer.Write( m_Lifted, true ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_Guardians = reader.ReadStrongMobileList(); + m_Temporary = reader.ReadBool(); + + goto case 1; + } + case 1: + { + m_Owner = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_Level = reader.ReadInt(); + m_DeleteTime = reader.ReadDeltaTime(); + m_Lifted = reader.ReadStrongItemList(); + + if ( version < 2 ) + m_Guardians = new List(); + + break; + } + } + + if ( !m_Temporary ) + { + m_Timer = new DeleteTimer( this, m_DeleteTime ); + m_Timer.Start(); + } + else + { + Delete(); + } + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + base.OnAfterDelete(); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + list.Add( new RemoveEntry( from, this ) ); + } + + public void BeginRemove( Mobile from ) + { + if ( !from.Alive ) + return; + + from.CloseGump( typeof( RemoveGump ) ); + from.SendGump( new RemoveGump( from, this ) ); + } + + public void EndRemove( Mobile from ) + { + if ( Deleted || from != m_Owner || !from.InRange( GetWorldLocation(), 3 ) ) + return; + + from.SendLocalizedMessage( 1048124, "", 0x8A5 ); // The old, rusted chest crumbles when you hit it. + this.Delete(); + } + + private class RemoveGump : Gump + { + private Mobile m_From; + private TreasureMapChest m_Chest; + + public RemoveGump( Mobile from, TreasureMapChest chest ) : base( 15, 15 ) + { + m_From = from; + m_Chest = chest; + + Closable = false; + Disposable = false; + + AddPage( 0 ); + + AddBackground( 30, 0, 240, 240, 2620 ); + + AddHtmlLocalized( 45, 15, 200, 80, 1048125, 0xFFFFFF, false, false ); // When this treasure chest is removed, any items still inside of it will be lost. + AddHtmlLocalized( 45, 95, 200, 60, 1048126, 0xFFFFFF, false, false ); // Are you certain you're ready to remove this chest? + + AddButton( 40, 153, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 75, 155, 180, 40, 1048127, 0xFFFFFF, false, false ); // Remove the Treasure Chest + + AddButton( 40, 195, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 75, 197, 180, 35, 1006045, 0xFFFFFF, false, false ); // Cancel + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_Chest.EndRemove( m_From ); + } + } + + private class RemoveEntry : ContextMenuEntry + { + private Mobile m_From; + private TreasureMapChest m_Chest; + + public RemoveEntry( Mobile from, TreasureMapChest chest ) : base( 6149, 3 ) + { + m_From = from; + m_Chest = chest; + + Enabled = ( from == chest.Owner ); + } + + public override void OnClick() + { + if ( m_Chest.Deleted || m_From != m_Chest.Owner || !m_From.CheckAlive() ) + return; + + m_Chest.BeginRemove( m_From ); + } + } + + private class DeleteTimer : Timer + { + private Item m_Item; + + public DeleteTimer( Item item, DateTime time ) : base( time - DateTime.Now ) + { + m_Item = item; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } +} diff --git a/Scripts/Items/Decoration Artifacts/BaseDecorationArtifact.cs b/Scripts/Items/Decoration Artifacts/BaseDecorationArtifact.cs new file mode 100644 index 0000000..89a46ee --- /dev/null +++ b/Scripts/Items/Decoration Artifacts/BaseDecorationArtifact.cs @@ -0,0 +1,79 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BaseDecorationArtifact : Item + { + public abstract int ArtifactRarity{ get; } + + public override bool ForceShowProperties{ get{ return true; } } + + public BaseDecorationArtifact( int itemID ) : base( itemID ) + { + Weight = 10.0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1061078, this.ArtifactRarity.ToString() ); // artifact rarity ~1_val~ + } + + public BaseDecorationArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public abstract class BaseDecorationContainerArtifact : BaseContainer + { + public abstract int ArtifactRarity{ get; } + + public override bool ForceShowProperties{ get{ return true; } } + + public BaseDecorationContainerArtifact( int itemID ) : base( itemID ) + { + Weight = 10.0; + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1061078, this.ArtifactRarity.ToString() ); // artifact rarity ~1_val~ + } + + public BaseDecorationContainerArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Decoration Artifacts/DoomDecorationArtifacts.cs b/Scripts/Items/Decoration Artifacts/DoomDecorationArtifacts.cs new file mode 100644 index 0000000..f62a43c --- /dev/null +++ b/Scripts/Items/Decoration Artifacts/DoomDecorationArtifacts.cs @@ -0,0 +1,698 @@ +using System; +using Server; + +namespace Server.Items +{ + #region BackpackArtifact + public class BackpackArtifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public BackpackArtifact() : base( 0x9B2 ) + { + } + + public BackpackArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BloodyWaterArtifact + public class BloodyWaterArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public BloodyWaterArtifact() : base( 0xE23 ) + { + } + + public BloodyWaterArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BooksWestArtifact + public class BooksWestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public BooksWestArtifact() : base( 0x1E25 ) + { + } + + public BooksWestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BooksNorthArtifact + public class BooksNorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public BooksNorthArtifact() : base( 0x1E24 ) + { + } + + public BooksNorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BooksFaceDownArtifact + public class BooksFaceDownArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public BooksFaceDownArtifact() : base( 0x1E21 ) + { + } + + public BooksFaceDownArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BottleArtifact + public class BottleArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public BottleArtifact() : base( 0xE28 ) + { + } + + public BottleArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BrazierArtifact + public class BrazierArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public BrazierArtifact() : base( 0xE31 ) + { + Light = LightType.Circle150; + } + + public BrazierArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region CocoonArtifact + public class CocoonArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 7; } } + + [Constructable] + public CocoonArtifact() : base( 0x10DA ) + { + } + + public CocoonArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region DamagedBooksArtifact + public class DamagedBooksArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public DamagedBooksArtifact() : base( 0xC16 ) + { + } + + public DamagedBooksArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region EggCaseArtifact + public class EggCaseArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public EggCaseArtifact() : base( 0x10D9 ) + { + } + + public EggCaseArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region GruesomeStandardArtifact + public class GruesomeStandardArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public GruesomeStandardArtifact() : base( 0x428 ) + { + } + + public GruesomeStandardArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region LampPostArtifact + public class LampPostArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public LampPostArtifact() : base( 0xB24 ) + { + Light = LightType.Circle300; + } + + public LampPostArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region LeatherTunicArtifact + public class LeatherTunicArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public LeatherTunicArtifact() : base( 0x13CA ) + { + } + + public LeatherTunicArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region RockArtifact + public class RockArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public RockArtifact() : base( 0x1363 ) + { + } + + public RockArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region RuinedPaintingArtifact + public class RuinedPaintingArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 12; } } + + [Constructable] + public RuinedPaintingArtifact() : base( 0xC2C ) + { + } + + public RuinedPaintingArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SaddleArtifact + public class SaddleArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public SaddleArtifact() : base( 0xF38 ) + { + } + + public SaddleArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SkinnedDeerArtifact + public class SkinnedDeerArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public SkinnedDeerArtifact() : base( 0x1E91 ) + { + } + + public SkinnedDeerArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SkinnedGoatArtifact + public class SkinnedGoatArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public SkinnedGoatArtifact() : base( 0x1E88 ) + { + } + + public SkinnedGoatArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SkullCandleArtifact + public class SkullCandleArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public SkullCandleArtifact() : base( 0x1858 ) + { + Light = LightType.Circle150; + } + + public SkullCandleArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region StretchedHideArtifact + public class StretchedHideArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public StretchedHideArtifact() : base( 0x106B ) + { + } + + public StretchedHideArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region StuddedLeggingsArtifact + public class StuddedLeggingsArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public StuddedLeggingsArtifact() : base( 0x13D8 ) + { + } + + public StuddedLeggingsArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region StuddedTunicArtifact + public class StuddedTunicArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 7; } } + + [Constructable] + public StuddedTunicArtifact() : base( 0x13D9 ) + { + } + + public StuddedTunicArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region TarotCardsArtifact + public class TarotCardsArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public TarotCardsArtifact() : base( 0x12A5 ) + { + } + + public TarotCardsArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion +} \ No newline at end of file diff --git a/Scripts/Items/Decoration Artifacts/SEDecorationArtifacts.cs b/Scripts/Items/Decoration Artifacts/SEDecorationArtifacts.cs new file mode 100644 index 0000000..ef6c782 --- /dev/null +++ b/Scripts/Items/Decoration Artifacts/SEDecorationArtifacts.cs @@ -0,0 +1,1627 @@ +using System; +using Server; + +namespace Server.Items +{ + #region Basket1Artifact + public class Basket1Artifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public Basket1Artifact() : base( 0x24DD ) + { + } + + public Basket1Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket2Artifact + public class Basket2Artifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public Basket2Artifact() : base( 0x24D7 ) + { + } + + public Basket2Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket3WestArtifact + public class Basket3WestArtifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public Basket3WestArtifact() : base( 0x24D9 ) + { + } + + public Basket3WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket3NorthArtifact + public class Basket3NorthArtifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 1; } } + + [Constructable] + public Basket3NorthArtifact() : base( 0x24DA ) + { + } + + public Basket3NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket4Artifact + public class Basket4Artifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public Basket4Artifact() : base( 0x24D8 ) + { + } + + public Basket4Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket5WestArtifact + public class Basket5WestArtifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public Basket5WestArtifact() : base( 0x24DC ) + { + } + + public Basket5WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket5NorthArtifact + public class Basket5NorthArtifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public Basket5NorthArtifact() : base( 0x24DB ) + { + } + + public Basket5NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Basket6Artifact + public class Basket6Artifact : BaseDecorationContainerArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public Basket6Artifact() : base( 0x24D5 ) + { + } + + public Basket6Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BowlArtifact + public class BowlArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public BowlArtifact() : base( 0x24DE ) + { + } + + public BowlArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BowlsVerticalArtifact + public class BowlsVerticalArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public BowlsVerticalArtifact() : base( 0x24DF ) + { + } + + public BowlsVerticalArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region BowlsHorizontalArtifact + public class BowlsHorizontalArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public BowlsHorizontalArtifact() : base( 0x24E0 ) + { + } + + public BowlsHorizontalArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region CupsArtifact + public class CupsArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public CupsArtifact() : base( 0x24E1 ) + { + } + + public CupsArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region FanWestArtifact + public class FanWestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public FanWestArtifact() : base( 0x240A ) + { + } + + public FanWestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region FanNorthArtifact + public class FanNorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public FanNorthArtifact() : base( 0x2409 ) + { + } + + public FanNorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region TripleFanWestArtifact + public class TripleFanWestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public TripleFanWestArtifact() : base( 0x240C ) + { + } + + public TripleFanWestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region TripleFanNorthArtifact + public class TripleFanNorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public TripleFanNorthArtifact() : base( 0x240B ) + { + } + + public TripleFanNorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region FlowersArtifact + public class FlowersArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 7; } } + + [Constructable] + public FlowersArtifact() : base( 0x284A ) + { + } + + public FlowersArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting1WestArtifact + public class Painting1WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public Painting1WestArtifact() : base( 0x240E ) + { + } + + public Painting1WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting1NorthArtifact + public class Painting1NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public Painting1NorthArtifact() : base( 0x240D ) + { + } + + public Painting1NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting2WestArtifact + public class Painting2WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public Painting2WestArtifact() : base( 0x2410 ) + { + } + + public Painting2WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting2NorthArtifact + public class Painting2NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public Painting2NorthArtifact() : base( 0x240F ) + { + } + + public Painting2NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting3Artifact + public class Painting3Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public Painting3Artifact() : base( 0x2411 ) + { + } + + public Painting3Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting4WestArtifact + public class Painting4WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 6; } } + + [Constructable] + public Painting4WestArtifact() : base( 0x2412 ) + { + } + + public Painting4WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting4NorthArtifact + public class Painting4NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 6; } } + + [Constructable] + public Painting4NorthArtifact() : base( 0x2411 ) + { + } + + public Painting4NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting5WestArtifact + public class Painting5WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public Painting5WestArtifact() : base( 0x2416 ) + { + } + + public Painting5WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting5NorthArtifact + public class Painting5NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public Painting5NorthArtifact() : base( 0x2415 ) + { + } + + public Painting5NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting6WestArtifact + public class Painting6WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public Painting6WestArtifact() : base( 0x2418 ) + { + } + + public Painting6WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Painting6NorthArtifact + public class Painting6NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public Painting6NorthArtifact() : base( 0x2417 ) + { + } + + public Painting6NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SakeArtifact + public class SakeArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 4; } } + + [Constructable] + public SakeArtifact() : base( 0x24E2 ) + { + } + + public SakeArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Sculpture1Artifact + public class Sculpture1Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public Sculpture1Artifact() : base( 0x2419 ) + { + } + + public Sculpture1Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Sculpture2Artifact + public class Sculpture2Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public Sculpture2Artifact() : base( 0x241B ) + { + } + + public Sculpture2Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region DolphinLeftArtifact + public class DolphinLeftArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public DolphinLeftArtifact() : base( 0x2846 ) + { + } + + public DolphinLeftArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region DolphinRightArtifact + public class DolphinRightArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public DolphinRightArtifact() : base( 0x2847 ) + { + } + + public DolphinRightArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region ManStatuetteSouthArtifact + public class ManStatuetteSouthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public ManStatuetteSouthArtifact() : base( 0x2848 ) + { + } + + public ManStatuetteSouthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region ManStatuetteEastArtifact + public class ManStatuetteEastArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public ManStatuetteEastArtifact() : base( 0x2849 ) + { + } + + public ManStatuetteEastArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay1WestArtifact + public class SwordDisplay1WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public SwordDisplay1WestArtifact() : base( 0x2842 ) + { + } + + public SwordDisplay1WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay1NorthArtifact + public class SwordDisplay1NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 5; } } + + [Constructable] + public SwordDisplay1NorthArtifact() : base( 0x2843 ) + { + } + + public SwordDisplay1NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay2WestArtifact + public class SwordDisplay2WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 6; } } + + [Constructable] + public SwordDisplay2WestArtifact() : base( 0x2844 ) + { + } + + public SwordDisplay2WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay2NorthArtifact + public class SwordDisplay2NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 6; } } + + [Constructable] + public SwordDisplay2NorthArtifact() : base( 0x2845 ) + { + } + + public SwordDisplay2NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay3SouthArtifact + public class SwordDisplay3SouthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public SwordDisplay3SouthArtifact() : base( 0x2855 ) + { + } + + public SwordDisplay3SouthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay3EastArtifact + public class SwordDisplay3EastArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public SwordDisplay3EastArtifact() : base( 0x2856 ) + { + } + + public SwordDisplay3EastArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay4WestArtifact + public class SwordDisplay4WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 8; } } + + [Constructable] + public SwordDisplay4WestArtifact() : base( 0x2853 ) + { + } + + public SwordDisplay4WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay4NorthArtifact + public class SwordDisplay4NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public SwordDisplay4NorthArtifact() : base( 0x2854 ) + { + } + + public SwordDisplay4NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay5WestArtifact + public class SwordDisplay5WestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public SwordDisplay5WestArtifact() : base( 0x2851 ) + { + } + + public SwordDisplay5WestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region SwordDisplay5NorthArtifact + public class SwordDisplay5NorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 9; } } + + [Constructable] + public SwordDisplay5NorthArtifact() : base( 0x2852 ) + { + } + + public SwordDisplay5NorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region TeapotWestArtifact + public class TeapotWestArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public TeapotWestArtifact() : base( 0x24E7 ) + { + } + + public TeapotWestArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region TeapotNorthArtifact + public class TeapotNorthArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public TeapotNorthArtifact() : base( 0x24E6 ) + { + } + + public TeapotNorthArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region TowerLanternArtifact + public class TowerLanternArtifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsOn + { + get{ return this.ItemID == 0x24BF; } + set{ this.ItemID = value ? 0x24BF : 0x24C0; } + } + + [Constructable] + public TowerLanternArtifact() : base( 0x24C0 ) + { + this.Light = LightType.Circle225; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( this.IsOn ) + { + this.IsOn = false; + from.PlaySound( 0x3BE ); + } + else + { + this.IsOn = true; + from.PlaySound( 0x47 ); + } + } + else + { + from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + + public TowerLanternArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + if ( version == 0 ) + this.Light = LightType.Circle225; + } + } + #endregion + + #region Urn1Artifact + public class Urn1Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public Urn1Artifact() : base( 0x241D ) + { + } + + public Urn1Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region Urn2Artifact + public class Urn2Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public Urn2Artifact() : base( 0x241E ) + { + } + + public Urn2Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region ZenRock1Artifact + public class ZenRock1Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 2; } } + + [Constructable] + public ZenRock1Artifact() : base( 0x24E4 ) + { + } + + public ZenRock1Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region ZenRock2Artifact + public class ZenRock2Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public ZenRock2Artifact() : base( 0x24E3 ) + { + } + + public ZenRock2Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion + + #region ZenRock3Artifact + public class ZenRock3Artifact : BaseDecorationArtifact + { + public override int ArtifactRarity{ get{ return 3; } } + + [Constructable] + public ZenRock3Artifact() : base( 0x24E5 ) + { + } + + public ZenRock3Artifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + #endregion +} \ No newline at end of file diff --git a/Scripts/Items/Decoration Artifacts/StealableArtifactsSpawner.cs b/Scripts/Items/Decoration Artifacts/StealableArtifactsSpawner.cs new file mode 100644 index 0000000..6872943 --- /dev/null +++ b/Scripts/Items/Decoration Artifacts/StealableArtifactsSpawner.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections; +using Server; +using Server.Commands; + +namespace Server.Items +{ + public class StealableArtifactsSpawner : Item + { + public class StealableEntry + { + private Map m_Map; + private Point3D m_Location; + private int m_MinDelay; + private int m_MaxDelay; + private Type m_Type; + private int m_Hue; + + public Map Map{ get{ return m_Map; } } + public Point3D Location{ get{ return m_Location; } } + public int MinDelay{ get{ return m_MinDelay; } } + public int MaxDelay{ get{ return m_MaxDelay; } } + public Type Type{ get{ return m_Type; } } + public int Hue{ get{ return m_Hue; } } + + public StealableEntry( Map map, Point3D location, int minDelay, int maxDelay, Type type ) : this( map, location, minDelay, maxDelay, type, 0 ) + { + } + + public StealableEntry( Map map, Point3D location, int minDelay, int maxDelay, Type type, int hue ) + { + m_Map = map; + m_Location = location; + m_MinDelay = minDelay; + m_MaxDelay = maxDelay; + m_Type = type; + m_Hue = hue; + } + + public Item CreateInstance() + { + Item item = (Item) Activator.CreateInstance( m_Type ); + + if ( m_Hue > 0 ) + item.Hue = m_Hue; + + item.Movable = false; + item.MoveToWorld( this.Location, this.Map ); + + return item; + } + } + + private static StealableEntry[] m_Entries = new StealableEntry[] + { + // Doom - Artifact rarity 1 + new StealableEntry( Map.Malas, new Point3D( 317, 56, -1 ), 72, 108, typeof( RockArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 360, 31, 8 ), 72, 108, typeof( SkullCandleArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 369, 372, -1 ), 72, 108, typeof( BottleArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 378, 372, 0 ), 72, 108, typeof( DamagedBooksArtifact ) ), + // Doom - Artifact rarity 2 + new StealableEntry( Map.Malas, new Point3D( 432, 16, -1 ), 144, 216, typeof( StretchedHideArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 489, 9, 0 ), 144, 216, typeof( BrazierArtifact ) ), + // Doom - Artifact rarity 3 + new StealableEntry( Map.Malas, new Point3D( 471, 96, -1 ), 288, 432, typeof( LampPostArtifact ), GetLampPostHue() ), + new StealableEntry( Map.Malas, new Point3D( 421, 198, 2 ), 288, 432, typeof( BooksNorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 431, 189, -1 ), 288, 432, typeof( BooksWestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 435, 196, -1 ), 288, 432, typeof( BooksFaceDownArtifact ) ), + // Doom - Artifact rarity 5 + new StealableEntry( Map.Malas, new Point3D( 447, 9, 8 ), 1152, 1728, typeof( StuddedLeggingsArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 423, 28, 0 ), 1152, 1728, typeof( EggCaseArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 347, 44, 4 ), 1152, 1728, typeof( SkinnedGoatArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 497, 57, -1 ), 1152, 1728, typeof( GruesomeStandardArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 381, 375, 11 ), 1152, 1728, typeof( BloodyWaterArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 489, 369, 2 ), 1152, 1728, typeof( TarotCardsArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 497, 369, 5 ), 1152, 1728, typeof( BackpackArtifact ) ), + // Doom - Artifact rarity 7 + new StealableEntry( Map.Malas, new Point3D( 475, 23, 4 ), 4608, 6912, typeof( StuddedTunicArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 423, 28, 0 ), 4608, 6912, typeof( CocoonArtifact ) ), + // Doom - Artifact rarity 8 + new StealableEntry( Map.Malas, new Point3D( 354, 36, -1 ), 9216, 13824, typeof( SkinnedDeerArtifact ) ), + // Doom - Artifact rarity 9 + new StealableEntry( Map.Malas, new Point3D( 433, 11, -1 ), 18432, 27648, typeof( SaddleArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 403, 31, 4 ), 18432, 27648, typeof( LeatherTunicArtifact ) ), + // Doom - Artifact rarity 10 + new StealableEntry( Map.Malas, new Point3D( 257, 70, -2 ), 36864, 55296, typeof( ZyronicClaw ) ), + new StealableEntry( Map.Malas, new Point3D( 354, 176, 7 ), 36864, 55296, typeof( TitansHammer ) ), + new StealableEntry( Map.Malas, new Point3D( 369, 389, -1 ), 36864, 55296, typeof( BladeOfTheRighteous ) ), + new StealableEntry( Map.Malas, new Point3D( 467, 92, 4 ), 36864, 55296, typeof( InquisitorsResolution ) ), + // Doom - Artifact rarity 12 + new StealableEntry( Map.Malas, new Point3D( 487, 364, -1 ), 147456, 221184, typeof( RuinedPaintingArtifact ) ), + + // Yomotsu Mines - Artifact rarity 1 + new StealableEntry( Map.Malas, new Point3D( 18, 110, -1 ), 72, 108, typeof( Basket1Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 66, 114, -1 ), 72, 108, typeof( Basket2Artifact ) ), + // Yomotsu Mines - Artifact rarity 2 + new StealableEntry( Map.Malas, new Point3D( 63, 12, 11 ), 144, 216, typeof( Basket4Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 5, 29, -1 ), 144, 216, typeof( Basket5NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 30, 81, 3 ), 144, 216, typeof( Basket5WestArtifact ) ), + // Yomotsu Mines - Artifact rarity 3 + new StealableEntry( Map.Malas, new Point3D( 115, 7, -1 ), 288, 432, typeof( Urn1Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 85, 13, -1 ), 288, 432, typeof( Urn2Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 110, 53, -1 ), 288, 432, typeof( Sculpture1Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 108, 37, -1 ), 288, 432, typeof( Sculpture2Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 121, 14, -1 ), 288, 432, typeof( TeapotNorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 121, 115, -1 ), 288, 432, typeof( TeapotWestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 84, 40, -1 ), 288, 432, typeof( TowerLanternArtifact ) ), + // Yomotsu Mines - Artifact rarity 9 + new StealableEntry( Map.Malas, new Point3D( 94, 7, -1 ), 18432, 27648, typeof( ManStatuetteSouthArtifact ) ), + + // Fan Dancer's Dojo - Artifact rarity 1 + new StealableEntry( Map.Malas, new Point3D( 113, 640, -2 ), 72, 108, typeof( Basket3NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 102, 355, -1 ), 72, 108, typeof( Basket3WestArtifact ) ), + // Fan Dancer's Dojo - Artifact rarity 2 + new StealableEntry( Map.Malas, new Point3D( 99, 370, -1 ), 144, 216, typeof( Basket6Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 100, 357, -1 ), 144, 216, typeof( ZenRock1Artifact ) ), + // Fan Dancer's Dojo - Artifact rarity 3 + new StealableEntry( Map.Malas, new Point3D( 73, 473, -1 ), 288, 432, typeof( FanNorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 99, 372, -1 ), 288, 432, typeof( FanWestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 92, 326, -1 ), 288, 432, typeof( BowlsVerticalArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 97, 470, -1 ), 288, 432, typeof( ZenRock2Artifact ) ), + new StealableEntry( Map.Malas, new Point3D( 103, 691, -1 ), 288, 432, typeof( ZenRock3Artifact ) ), + // Fan Dancer's Dojo - Artifact rarity 4 + new StealableEntry( Map.Malas, new Point3D( 103, 336, 4 ), 576, 864, typeof( Painting1NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 59, 381, 4 ), 576, 864, typeof( Painting1WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 84, 401, 2 ), 576, 864, typeof( Painting2NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 59, 392, 2 ), 576, 864, typeof( Painting2WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 107, 483, -1 ), 576, 864, typeof( TripleFanNorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 50, 475, -1 ), 576, 864, typeof( TripleFanWestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 107, 460, -1 ), 576, 864, typeof( BowlArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 90, 502, -1 ), 576, 864, typeof( CupsArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 107, 688, -1 ), 576, 864, typeof( BowlsHorizontalArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 112, 676, -1 ), 576, 864, typeof( SakeArtifact ) ), + // Fan Dancer's Dojo - Artifact rarity 5 + new StealableEntry( Map.Malas, new Point3D( 135, 614, -1 ), 1152, 1728, typeof( SwordDisplay1NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 50, 482, -1 ), 1152, 1728, typeof( SwordDisplay1WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 119, 672, -1 ), 1152, 1728, typeof( Painting3Artifact ) ), + // Fan Dancer's Dojo - Artifact rarity 6 + new StealableEntry( Map.Malas, new Point3D( 90, 326, -1 ), 2304, 3456, typeof( Painting4NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 99, 354, -1 ), 2304, 3456, typeof( Painting4WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 179, 652, -1 ), 2304, 3456, typeof( SwordDisplay2NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 118, 627, -1 ), 2304, 3456, typeof( SwordDisplay2WestArtifact ) ), + // Fan Dancer's Dojo - Artifact rarity 7 + new StealableEntry( Map.Malas, new Point3D( 90, 483, -1 ), 4608, 6912, typeof( FlowersArtifact ) ), + // Fan Dancer's Dojo - Artifact rarity 8 + new StealableEntry( Map.Malas, new Point3D( 71, 562, -1 ), 9216, 13824, typeof( DolphinLeftArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 102, 677, -1 ), 9216, 13824, typeof( DolphinRightArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 61, 499, 0 ), 9216, 13824, typeof( SwordDisplay3SouthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 182, 669, -1 ), 9216, 13824, typeof( SwordDisplay3EastArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 162, 647, -1 ), 9216, 13824, typeof( SwordDisplay4WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 124, 624, 0 ), 9216, 13824, typeof( Painting5NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 146, 649, 2 ), 9216, 13824, typeof( Painting5WestArtifact ) ), + // Fan Dancer's Dojo - Artifact rarity 9 + new StealableEntry( Map.Malas, new Point3D( 100, 488, -1 ), 18432, 27648, typeof( SwordDisplay4NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 175, 606, 0 ), 18432, 27648, typeof( SwordDisplay5NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 157, 608, -1 ), 18432, 27648, typeof( SwordDisplay5WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 187, 643, 1 ), 18432, 27648, typeof( Painting6NorthArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 146, 623, 1 ), 18432, 27648, typeof( Painting6WestArtifact ) ), + new StealableEntry( Map.Malas, new Point3D( 178, 629, -1 ), 18432, 27648, typeof( ManStatuetteEastArtifact ) ) + }; + + public static StealableEntry[] Entries{ get{ return m_Entries; } } + + private static Type[] m_TypesOfEntries = null; + public static Type[] TypesOfEntires + { + get + { + if( m_TypesOfEntries == null ) + { + m_TypesOfEntries = new Type[m_Entries.Length]; + + for( int i = 0; i < m_Entries.Length; i++ ) + m_TypesOfEntries[i] = m_Entries[i].Type; + } + + return m_TypesOfEntries; + } + } + + private static StealableArtifactsSpawner m_Instance; + + public static StealableArtifactsSpawner Instance{ get{ return m_Instance; } } + + private static int GetLampPostHue() + { + if ( 0.9 > Utility.RandomDouble() ) + return 0; + + return Utility.RandomList( 0x455, 0x47E, 0x482, 0x486, 0x48F, 0x4F2, 0x58C, 0x66C ); + } + + + public static void Initialize() + { + CommandSystem.Register( "GenStealArties", AccessLevel.Administrator, new CommandEventHandler( GenStealArties_OnCommand ) ); + CommandSystem.Register( "RemoveStealArties", AccessLevel.Administrator, new CommandEventHandler( RemoveStealArties_OnCommand ) ); + } + + [Usage( "GenStealArties" )] + [Description( "Generates the stealable artifacts spawner." )] + private static void GenStealArties_OnCommand( CommandEventArgs args ) + { + Mobile from = args.Mobile; + + if ( Create() ) + from.SendMessage( "Stealable artifacts spawner generated." ); + else + from.SendMessage( "Stealable artifacts spawner already present." ); + } + + [Usage( "RemoveStealArties" )] + [Description( "Removes the stealable artifacts spawner and every not yet stolen stealable artifacts." )] + private static void RemoveStealArties_OnCommand( CommandEventArgs args ) + { + Mobile from = args.Mobile; + + if ( Remove() ) + from.SendMessage( "Stealable artifacts spawner removed." ); + else + from.SendMessage( "Stealable artifacts spawner not present." ); + } + + public static bool Create() + { + if ( m_Instance != null && !m_Instance.Deleted ) + return false; + + m_Instance = new StealableArtifactsSpawner(); + return true; + } + + public static bool Remove() + { + if ( m_Instance == null ) + return false; + + m_Instance.Delete(); + m_Instance = null; + return true; + } + + public static StealableInstance GetStealableInstance( Item item ) + { + if ( Instance == null ) + return null; + + return (StealableInstance) Instance.m_Table[item]; + } + + + public class StealableInstance + { + private StealableEntry m_Entry; + private Item m_Item; + private DateTime m_NextRespawn; + + public StealableEntry Entry{ get{ return m_Entry; } } + + public Item Item + { + get{ return m_Item; } + set + { + if ( m_Item != null && value == null ) + { + int delay = Utility.RandomMinMax( this.Entry.MinDelay, this.Entry.MaxDelay ); + this.NextRespawn = DateTime.Now + TimeSpan.FromMinutes( delay ); + } + + if ( Instance != null ) + { + if ( m_Item != null ) + Instance.m_Table.Remove( m_Item ); + + if ( value != null ) + Instance.m_Table[value] = this; + } + + m_Item = value; + } + } + + public DateTime NextRespawn + { + get{ return m_NextRespawn; } + set{ m_NextRespawn = value; } + } + + public StealableInstance( StealableEntry entry ) : this( entry, null, DateTime.Now ) + { + } + + public StealableInstance( StealableEntry entry, Item item, DateTime nextRespawn ) + { + m_Item = item; + m_NextRespawn = nextRespawn; + m_Entry = entry; + } + + public void CheckRespawn() + { + if ( this.Item != null && ( this.Item.Deleted || this.Item.Movable || this.Item.Parent != null ) ) + this.Item = null; + + if ( this.Item == null && DateTime.Now >= this.NextRespawn ) + { + this.Item = this.Entry.CreateInstance(); + } + } + } + + private Timer m_RespawnTimer; + private StealableInstance[] m_Artifacts; + private Hashtable m_Table; + + public override string DefaultName + { + get { return "Stealable Artifacts Spawner - Internal"; } + } + + private StealableArtifactsSpawner() : base( 1 ) + { + Movable = false; + + m_Artifacts = new StealableInstance[m_Entries.Length]; + m_Table = new Hashtable( m_Entries.Length ); + + for ( int i = 0; i < m_Entries.Length; i++ ) + { + m_Artifacts[i] = new StealableInstance( m_Entries[i] ); + } + + m_RespawnTimer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromMinutes( 15.0 ), new TimerCallback( CheckRespawn ) ); + } + + public override void OnDelete() + { + base.OnDelete(); + + if ( m_RespawnTimer != null ) + { + m_RespawnTimer.Stop(); + m_RespawnTimer = null; + } + + foreach ( StealableInstance si in m_Artifacts ) + { + if ( si.Item != null ) + si.Item.Delete(); + } + + m_Instance = null; + } + + public void CheckRespawn() + { + foreach ( StealableInstance si in m_Artifacts ) + { + si.CheckRespawn(); + } + } + + public StealableArtifactsSpawner( Serial serial ) : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteEncodedInt( m_Artifacts.Length ); + + for ( int i = 0; i < m_Artifacts.Length; i++ ) + { + StealableInstance si = m_Artifacts[i]; + + writer.Write( (Item) si.Item ); + writer.WriteDeltaTime( (DateTime) si.NextRespawn ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Artifacts = new StealableInstance[m_Entries.Length]; + m_Table = new Hashtable( m_Entries.Length ); + + int length = reader.ReadEncodedInt(); + + for ( int i = 0; i < length; i++ ) + { + Item item = reader.ReadItem(); + DateTime nextRespawn = reader.ReadDeltaTime(); + + if ( i < m_Artifacts.Length ) + { + StealableInstance si = new StealableInstance( m_Entries[i], item, nextRespawn ); + m_Artifacts[i] = si; + + if ( si.Item != null ) + m_Table[si.Item] = si; + } + } + + for ( int i = length; i < m_Entries.Length; i++ ) + { + m_Artifacts[i] = new StealableInstance( m_Entries[i] ); + } + + m_RespawnTimer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromMinutes( 15.0 ), new TimerCallback( CheckRespawn ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/BarkeepContract.cs b/Scripts/Items/Deeds/BarkeepContract.cs new file mode 100644 index 0000000..1bd16f5 --- /dev/null +++ b/Scripts/Items/Deeds/BarkeepContract.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Multis; + +namespace Server.Items +{ + public class BarkeepContract : Item + { + public override string DefaultName + { + get { return "a barkeep contract"; } + } + + [Constructable] + public BarkeepContract() : base( 0x14F0 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public BarkeepContract( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.SendLocalizedMessage( 503248 ); // Your godly powers allow you to place this vendor whereever you wish. + + Mobile v = new PlayerBarkeeper( from, BaseHouse.FindHouseAt( from ) ); + + v.Direction = from.Direction & Direction.Mask; + v.MoveToWorld( from.Location, from.Map ); + + this.Delete(); + } + else + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house == null || !house.IsOwner( from ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You are not the full owner of this house." ); + } + else if ( !house.CanPlaceNewBarkeep() ) + { + from.SendLocalizedMessage( 1062490 ); // That action would exceed the maximum number of barkeeps for this house. + } + else + { + bool vendor, contract; + BaseHouse.IsThereVendor( from.Location, from.Map, out vendor, out contract ); + + if ( vendor ) + { + from.SendLocalizedMessage( 1062677 ); // You cannot place a vendor or barkeep at this location. + } + else if ( contract ) + { + from.SendLocalizedMessage( 1062678 ); // You cannot place a vendor or barkeep on top of a rental contract! + } + else + { + Mobile v = new PlayerBarkeeper( from, house ); + + v.Direction = from.Direction & Direction.Mask; + v.MoveToWorld( from.Location, from.Map ); + + this.Delete(); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/ClothingBlessDeed.cs b/Scripts/Items/Deeds/ClothingBlessDeed.cs new file mode 100644 index 0000000..1709533 --- /dev/null +++ b/Scripts/Items/Deeds/ClothingBlessDeed.cs @@ -0,0 +1,112 @@ +using System; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class ClothingBlessTarget : Target // Create our targeting class (which we derive from the base target class) + { + private ClothingBlessDeed m_Deed; + + public ClothingBlessTarget( ClothingBlessDeed deed ) : base( 1, false, TargetFlags.None ) + { + m_Deed = deed; + } + + protected override void OnTarget( Mobile from, object target ) // Override the protected OnTarget() for our feature + { + if ( m_Deed.Deleted || m_Deed.RootParent != from ) + return; + + if ( target is BaseClothing ) + { + BaseClothing item = (BaseClothing)target; + + if ( item is IArcaneEquip ) + { + IArcaneEquip eq = (IArcaneEquip)item; + if ( eq.IsArcane ) + { + from.SendLocalizedMessage( 1005019 ); // This bless deed is for Clothes only. + return; + } + } + + if ( item.LootType == LootType.Blessed || item.BlessedFor == from || (Mobile.InsuranceEnabled && item.Insured) ) // Check if its already newbied (blessed) + { + from.SendLocalizedMessage( 1045113 ); // That item is already blessed + } + else if ( item.LootType != LootType.Regular ) + { + from.SendLocalizedMessage( 1045114 ); // You can not bless that item + } + else if ( !item.CanBeBlessed || item.RootParent != from ) + { + from.SendLocalizedMessage( 500509 ); // You cannot bless that object + } + else + { + item.LootType = LootType.Blessed; + from.SendLocalizedMessage( 1010026 ); // You bless the item.... + + m_Deed.Delete(); // Delete the bless deed + } + } + else + { + from.SendLocalizedMessage( 500509 ); // You cannot bless that object + } + } + } + + public class ClothingBlessDeed : Item // Create the item class which is derived from the base item class + { + public override string DefaultName + { + get { return "a clothing bless deed"; } + } + + [Constructable] + public ClothingBlessDeed() : base( 0x14F0 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public ClothingBlessDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + } + + public override bool DisplayLootType{ get{ return false; } } + + public override void OnDoubleClick( Mobile from ) // Override double click of the deed to call our target + { + if ( !IsChildOf( from.Backpack ) ) // Make sure its in their pack + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + from.SendLocalizedMessage( 1005018 ); // What would you like to bless? (Clothes Only) + from.Target = new ClothingBlessTarget( this ); // Call our target + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/CommodityDeed.cs b/Scripts/Items/Deeds/CommodityDeed.cs new file mode 100644 index 0000000..3369479 --- /dev/null +++ b/Scripts/Items/Deeds/CommodityDeed.cs @@ -0,0 +1,275 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Items +{ + public interface ICommodity /* added IsDeedable prop so expansion-based deedables can determine true/false */ + { + int DescriptionNumber { get; } + bool IsDeedable { get; } + } + + public class CommodityDeed : Item + { + private Item m_Commodity; + + [CommandProperty(AccessLevel.GameMaster)] + public Item Commodity + { + get + { + return m_Commodity; + } + } + + public bool SetCommodity(Item item) + { + InvalidateProperties(); + + if (m_Commodity == null && item is ICommodity && ((ICommodity)item).IsDeedable) + { + m_Commodity = item; + m_Commodity.Internalize(); + InvalidateProperties(); + + return true; + } + else + { + return false; + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write(m_Commodity); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Commodity = reader.ReadItem(); + + switch (version) + { + case 0: + { + if (m_Commodity != null) + { + Hue = 0x592; + } + break; + } + } + } + + public CommodityDeed(Item commodity) + : base(0x14F0) + { + Weight = 1.0; + Hue = 0x47; + + m_Commodity = commodity; + + LootType = LootType.Blessed; + } + + [Constructable] + public CommodityDeed() + : this(null) + { + } + + public CommodityDeed(Serial serial) + : base(serial) + { + } + + public override void OnDelete() + { + if (m_Commodity != null) + m_Commodity.Delete(); + + base.OnDelete(); + } + + public override int LabelNumber { get { return m_Commodity == null ? 1047016 : 1047017; } } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Commodity != null) + { + string args; + + if (m_Commodity.Name == null) + args = String.Format("#{0}\t{1}", (m_Commodity is ICommodity) ? ((ICommodity)m_Commodity).DescriptionNumber : m_Commodity.LabelNumber, m_Commodity.Amount); + else + args = String.Format("{0}\t{1}", m_Commodity.Name, m_Commodity.Amount); + + list.Add(1060658, args); // ~1_val~: ~2_val~ + } + else + { + list.Add(1060748); // unfilled + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Commodity != null) + { + string args; + + if (m_Commodity.Name == null) + args = String.Format("#{0}\t{1}", (m_Commodity is ICommodity) ? ((ICommodity)m_Commodity).DescriptionNumber : m_Commodity.LabelNumber, m_Commodity.Amount); + else + args = String.Format("{0}\t{1}", m_Commodity.Name, m_Commodity.Amount); + + LabelTo(from, 1060658, args); // ~1_val~: ~2_val~ + } + } + + public override void OnDoubleClick(Mobile from) + { + int number; + + BankBox box = from.FindBankNoCreate(); + CommodityDeedBox cox = CommodityDeedBox.Find(this); + + // Veteran Rewards mods + if (m_Commodity != null) + { + if (box != null && IsChildOf(box)) + { + number = 1047031; // The commodity has been redeemed. + + box.DropItem(m_Commodity); + + m_Commodity = null; + Delete(); + } + else if (cox != null) + { + if (cox.IsSecure) + { + number = 1047031; // The commodity has been redeemed. + + cox.DropItem(m_Commodity); + + m_Commodity = null; + Delete(); + } + else + number = 1080525; // The commodity deed box must be secured before you can use it. + } + else + { + if (Core.ML) + { + number = 1080526; // That must be in your bank box or commodity deed box to use it. + } + else + { + number = 1047024; // To claim the resources .... + } + } + } + else if (cox != null && !cox.IsSecure) + { + number = 1080525; // The commodity deed box must be secured before you can use it. + } + else if ((box == null || !IsChildOf(box)) && cox == null) + { + if (Core.ML) + { + number = 1080526; // That must be in your bank box or commodity deed box to use it. + } + else + { + number = 1047026; // That must be in your bank box to use it. + } + } + else + { + number = 1047029; // Target the commodity to fill this deed with. + + from.Target = new InternalTarget(this); + } + + from.SendLocalizedMessage(number); + } + + private class InternalTarget : Target + { + private CommodityDeed m_Deed; + + public InternalTarget(CommodityDeed deed) + : base(3, false, TargetFlags.None) + { + m_Deed = deed; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Deed.Deleted) + return; + + int number; + + if (m_Deed.Commodity != null) + { + number = 1047028; // The commodity deed has already been filled. + } + else if (targeted is Item) + { + BankBox box = from.FindBankNoCreate(); + CommodityDeedBox cox = CommodityDeedBox.Find(m_Deed); + + // Veteran Rewards mods + if (box != null && m_Deed.IsChildOf(box) && ((Item)targeted).IsChildOf(box) || + cox != null && cox.IsSecure && ((Item)targeted).IsChildOf(cox)) + { + if (m_Deed.SetCommodity((Item)targeted)) + { + m_Deed.Hue = 0x592; + number = 1047030; // The commodity deed has been filled. + } + else + { + number = 1047027; // That is not a commodity the bankers will fill a commodity deed with. + } + } + else + { + if (Core.ML) + { + number = 1080526; // That must be in your bank box or commodity deed box to use it. + } + else + { + number = 1047026; // That must be in your bank box to use it. + } + } + } + else + { + number = 1047027; // That is not a commodity the bankers will fill a commodity deed with. + } + + from.SendLocalizedMessage(number); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/DragonBardingDeed.cs b/Scripts/Items/Deeds/DragonBardingDeed.cs new file mode 100644 index 0000000..2656df5 --- /dev/null +++ b/Scripts/Items/Deeds/DragonBardingDeed.cs @@ -0,0 +1,149 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Engines.Craft; +namespace Server.Items +{ + [TypeAlias( "Server.Items.DragonBarding" )] + public class DragonBardingDeed : Item, ICraftable + { + private bool m_Exceptional; + private Mobile m_Crafter; + private CraftResource m_Resource; + + public override int LabelNumber{ get{ return m_Exceptional ? 1053181 : 1053012; } } // dragon barding deed + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter{ get{ return m_Crafter; } set{ m_Crafter = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Exceptional{ get{ return m_Exceptional; } set{ m_Exceptional = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource{ get{ return m_Resource; } set{ m_Resource = value; Hue = CraftResources.GetHue( value ); InvalidateProperties(); } } + + public DragonBardingDeed() : base( 0x14F0 ) + { + Weight = 1.0; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Exceptional && m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.BeginTarget( 6, false, TargetFlags.None, new TargetCallback( OnTarget ) ); + from.SendLocalizedMessage( 1053024 ); // Select the swamp dragon you wish to place the barding on. + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public virtual void OnTarget( Mobile from, object obj ) + { + if ( Deleted ) + return; + + SwampDragon pet = obj as SwampDragon; + + if ( pet == null || pet.HasBarding ) + { + from.SendLocalizedMessage( 1053025 ); // That is not an unarmored swamp dragon. + } + else if ( !pet.Controlled || pet.ControlMaster != from ) + { + from.SendLocalizedMessage( 1053026 ); // You can only put barding on a tamed swamp dragon that you own. + } + else if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1060640 ); // The item must be in your backpack to use it. + } + else + { + pet.BardingExceptional = this.Exceptional; + pet.BardingCrafter = this.Crafter; + pet.BardingHP = pet.BardingMaxHP; + pet.BardingResource = this.Resource; + pet.HasBarding = true; + pet.Hue = this.Hue; + + this.Delete(); + + from.SendLocalizedMessage( 1053027 ); // You place the barding on your swamp dragon. Use a bladed item on your dragon to remove the armor. + } + } + + public DragonBardingDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_Exceptional ); + writer.Write( (Mobile) m_Crafter ); + writer.Write( (int) m_Resource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Exceptional = reader.ReadBool(); + m_Crafter = reader.ReadMobile(); + + if ( version < 1 ) + reader.ReadInt(); + + m_Resource = (CraftResource) reader.ReadInt(); + break; + } + } + } + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Exceptional = ( quality >= 2 ); + + if ( makersMark ) + Crafter = from; + + Type resourceType = typeRes; + + if ( resourceType == null ) + resourceType = craftItem.Resources.GetAt( 0 ).ItemType; + + Resource = CraftResources.GetFromType( resourceType ); + + CraftContext context = craftSystem.GetContext( from ); + + if ( context != null && context.DoNotColor ) + Hue = 0; + + return quality; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/HairRestylingDeed.cs b/Scripts/Items/Deeds/HairRestylingDeed.cs new file mode 100644 index 0000000..54e3185 --- /dev/null +++ b/Scripts/Items/Deeds/HairRestylingDeed.cs @@ -0,0 +1,157 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Items +{ + public class HairRestylingDeed : Item + { + public override int LabelNumber{ get{ return 1041061; } } // a coupon for a free hair restyling + + [Constructable] + public HairRestylingDeed() : base( 0x14F0 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public HairRestylingDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack... + } + else + { + from.SendGump( new InternalGump( from, this ) ); + } + } + + private class InternalGump : Gump + { + private Mobile m_From; + private HairRestylingDeed m_Deed; + + public InternalGump( Mobile from, HairRestylingDeed deed ) : base( 50, 50 ) + { + m_From = from; + m_Deed = deed; + + from.CloseGump( typeof( InternalGump ) ); + + AddBackground( 100, 10, 400, 385, 0xA28 ); + + AddHtmlLocalized( 100, 25, 400, 35, 1013008, false, false ); + AddButton( 175, 340, 0xFA5, 0xFA7, 0x0, GumpButtonType.Reply, 0 ); // CANCEL + + AddHtmlLocalized( 210, 342, 90, 35, 1011012, false, false );//
HAIRSTYLE SELECTION MENU
+ + int[][] RacialData = (from.Race == Race.Human) ? HumanArray : ElvenArray; + + for(int i=1; i 10 ) + return; + + int[][] RacialData = (m_From.Race == Race.Human) ? HumanArray : ElvenArray; + + if ( m_From is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m_From; + + pm.SetHairMods( -1, -1 ); // clear any hairmods (disguise kit, incognito) + m_From.HairItemID = (m_From.Female) ? RacialData[info.ButtonID][2] : RacialData[info.ButtonID][3]; + m_Deed.Delete(); + } + } +/* + gump data: bgX, bgY, htmlX, htmlY, imgX, imgY, butX, butY +*/ + + int[][] LayoutArray = + { + new int[] { 0 }, /* padding: its more efficient than code to ++ the index/buttonid */ + new int[] { 425, 280, 342, 295, 000, 000, 310, 292 }, + new int[] { 235, 060, 150, 075, 168, 020, 118, 073 }, + new int[] { 235, 115, 150, 130, 168, 070, 118, 128 }, + new int[] { 235, 170, 150, 185, 168, 130, 118, 183 }, + new int[] { 235, 225, 150, 240, 168, 185, 118, 238 }, + new int[] { 425, 060, 342, 075, 358, 018, 310, 073 }, + new int[] { 425, 115, 342, 130, 358, 075, 310, 128 }, + new int[] { 425, 170, 342, 185, 358, 125, 310, 183 }, + new int[] { 425, 225, 342, 240, 358, 185, 310, 238 }, + new int[] { 235, 280, 150, 295, 168, 245, 118, 292 } // slot 10, Curly - N/A for elfs. + }; + +/* + racial arrays are: cliloc_F, cliloc_M, ItemID_F, ItemID_M, gump_img_F, gump_img_M +*/ + int[][] HumanArray = /* why on earth cant these utilies be consistent with hex/dec */ + { + new int[] { 0 }, + new int[] { 1011064, 1011064, 0, 0, 0, 0 }, // bald + new int[] { 1011052, 1011052, 0x203B, 0x203B, 0xed1c, 0xC60C }, // Short + new int[] { 1011053, 1011053, 0x203C, 0x203C, 0xed1d, 0xc60d }, // Long + new int[] { 1011054, 1011054, 0x203D, 0x203D, 0xed1e, 0xc60e }, // Ponytail + new int[] { 1011055, 1011055, 0x2044, 0x2044, 0xed27, 0xC60F }, // Mohawk + new int[] { 1011047, 1011047, 0x2045, 0x2045, 0xED26, 0xED26 }, // Pageboy + new int[] { 1074393, 1011048, 0x2046, 0x2048, 0xed28, 0xEDE5 }, // Buns, Receding + new int[] { 1011049, 1011049, 0x2049, 0x2049, 0xede6, 0xede6 }, // 2-tails + new int[] { 1011050, 1011050, 0x204A, 0x204A, 0xED29, 0xED29 }, // Topknot + new int[] { 1011396, 1011396, 0x2047, 0x2047, 0xed25, 0xc618 } // Curly + }; + int[][] ElvenArray = + { + new int[] { 0 }, + new int[] { 1011064, 1011064, 0, 0, 0, 0, }, // bald + new int[] { 1074386, 1074386, 0x2fc0, 0x2fc0, 0xedf5, 0xc6e5 }, // long feather + new int[] { 1074387, 1074387, 0x2fc1, 0x2fc1, 0xedf6, 0xc6e6 }, // short + new int[] { 1074388, 1074388, 0x2fc2, 0x2fc2, 0xedf7, 0xc6e7 }, // mullet + new int[] { 1074391, 1074391, 0x2fce, 0x2fce, 0xeddc, 0xc6cc }, // knob + new int[] { 1074392, 1074392, 0x2fcf, 0x2fcf, 0xeddd, 0xc6cd }, // braided + new int[] { 1074394, 1074394, 0x2fd1, 0x2fd1, 0xeddf, 0xc6cf }, // spiked + new int[] { 1074389, 1074385, 0x2fcc, 0x2fbf, 0xedda, 0xc6e4 }, // flower, mid-long + new int[] { 1074393, 1074390, 0x2fd0, 0x2fcd, 0xedde, 0xc6cb } // buns, long + }; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/HolidayTreeDeed.cs b/Scripts/Items/Deeds/HolidayTreeDeed.cs new file mode 100644 index 0000000..28966b3 --- /dev/null +++ b/Scripts/Items/Deeds/HolidayTreeDeed.cs @@ -0,0 +1,164 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class HolidayTreeDeed : Item + { + public override int LabelNumber{ get{ return 1041116; } } // a deed for a holiday tree + + [Constructable] + public HolidayTreeDeed() : base( 0x14F0 ) + { + Hue = 0x488; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public HolidayTreeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + LootType = LootType.Blessed; + } + + public bool ValidatePlacement( Mobile from, Point3D loc ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if ( !from.InRange( this.GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return false; + } + + if ( DateTime.Now.Month != 12 ) + { + from.SendLocalizedMessage( 1005700 ); // You will have to wait till next December to put your tree back up for display. + return false; + } + + Map map = from.Map; + + if ( map == null ) + return false; + + BaseHouse house = BaseHouse.FindHouseAt( loc, map, 20 ); + + if ( house == null || !house.IsFriend( from ) ) + { + from.SendLocalizedMessage( 1005701 ); // The holiday tree can only be placed in your house. + return false; + } + + if ( !map.CanFit( loc, 20 ) ) + { + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + return false; + } + + return true; + } + + public void BeginPlace( Mobile from, HolidayTreeType type ) + { + from.BeginTarget( -1, true, TargetFlags.None, new TargetStateCallback( Placement_OnTarget ), type ); + } + + public void Placement_OnTarget( Mobile from, object targeted, object state ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + + Point3D loc = new Point3D( p ); + + if ( p is StaticTarget ) + loc.Z -= TileData.ItemTable[((StaticTarget)p).ItemID].CalcHeight; /* NOTE: OSI does not properly normalize Z positioning here. + * A side affect is that you can only place on floors (due to the CanFit call). + * That functionality may be desired. And so, it's included in this script. + */ + + if ( ValidatePlacement( from, loc ) ) + EndPlace( from, (HolidayTreeType) state, loc ); + } + + public void EndPlace( Mobile from, HolidayTreeType type, Point3D loc ) + { + this.Delete(); + HolidayTree tree = new HolidayTree( from, type, loc ); + BaseHouse house = BaseHouse.FindHouseAt( tree ); + if ( house != null ) + house.Addons.Add( tree ); + } + + public override void OnDoubleClick( Mobile from ) + { + from.CloseGump( typeof( HolidayTreeChoiceGump ) ); + from.SendGump( new HolidayTreeChoiceGump( from, this ) ); + } + } + + public class HolidayTreeChoiceGump : Gump + { + private Mobile m_From; + private HolidayTreeDeed m_Deed; + + public HolidayTreeChoiceGump( Mobile from, HolidayTreeDeed deed ) : base( 200, 200 ) + { + m_From = from; + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 220, 120, 5054 ); + AddBackground( 10, 10, 200, 100, 3000 ); + + AddButton( 20, 35, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 35, 145, 25, 1018322, false, false ); // Classic + + AddButton( 20, 65, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 65, 145, 25, 1018321, false, false ); // Modern + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed.Deleted ) + return; + + switch ( info.ButtonID ) + { + case 1: + { + m_Deed.BeginPlace( m_From, HolidayTreeType.Classic ); + break; + } + case 2: + { + m_Deed.BeginPlace( m_From, HolidayTreeType.Modern ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/NameChangeDeed.cs b/Scripts/Items/Deeds/NameChangeDeed.cs new file mode 100644 index 0000000..e676dca --- /dev/null +++ b/Scripts/Items/Deeds/NameChangeDeed.cs @@ -0,0 +1,132 @@ +using System; +using Server.Gumps; +using Server.Misc; +using Server.Network; +using Server.Prompts; + +namespace Server.Items +{ + public class NameChangeDeed : Item + { + public override string DefaultName + { + get { return "a name change deed"; } + } + + [Constructable] + public NameChangeDeed() + : base(0x14F0) + { + LootType = LootType.Blessed; + } + + public NameChangeDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (this.RootParent == from) + { + from.CloseGump(typeof(NameChangeDeedGump)); + from.SendGump(new NameChangeDeedGump(this)); + } + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public class NameChangeDeedGump : Gump + { + Item m_Sender; + + public void AddBlackAlpha(int x, int y, int width, int height) + { + AddImageTiled(x, y, width, height, 2624); + AddAlphaRegion(x, y, width, height); + } + + public void AddTextField(int x, int y, int width, int height, int index) + { + AddBackground(x - 2, y - 2, width + 4, height + 4, 0x2486); + AddTextEntry(x + 2, y + 2, width - 4, height - 4, 0, index, ""); + } + + public string Center(string text) + { + return String.Format("
{0}
", text); + } + + public string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + + public void AddButtonLabeled(int x, int y, int buttonID, string text) + { + AddButton(x, y - 1, 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, Color(text, 0xFFFFFF), false, false); + } + + public NameChangeDeedGump(Item sender) + : base(50, 50) + { + m_Sender = sender; + + Closable = true; + Dragable = true; + Resizable = false; + + AddPage(0); + + AddBlackAlpha(10, 120, 250, 85); + AddHtml(10, 125, 250, 20, Color(Center("Name Change Deed"), 0xFFFFFF), false, false); + + AddLabel(73, 15, 1152, ""); + AddLabel(20, 150, 0x480, "New Name:"); + AddTextField(100, 150, 150, 20, 0); + + AddButtonLabeled(75, 180, 1, "Submit"); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Sender == null || m_Sender.Deleted || info.ButtonID != 1 || m_Sender.RootParent != sender.Mobile) + return; + + Mobile m = sender.Mobile; + TextRelay nameEntry = info.GetTextEntry(0); + + string newName = (nameEntry == null ? null : nameEntry.Text.Trim()); + + + if (!NameVerification.Validate(newName, 2, 16, true, false, true, 1, NameVerification.SpaceDashPeriodQuote)) + { + m.SendMessage("That name is unacceptable."); + return; + } + else + { + m.RawName = newName; + m.SendMessage("Your name has been changed!"); + m.SendMessage(String.Format("You are now known as {0}", newName)); + m_Sender.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/NewPlayerTicket.cs b/Scripts/Items/Deeds/NewPlayerTicket.cs new file mode 100644 index 0000000..fe1f24c --- /dev/null +++ b/Scripts/Items/Deeds/NewPlayerTicket.cs @@ -0,0 +1,199 @@ +using System; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Items +{ + public class NewPlayerTicket : Item + { + private Mobile m_Owner; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + public override int LabelNumber{ get{ return 1062094; } } // a young player ticket + + [Constructable] + public NewPlayerTicket() : base( 0x14EF ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1041492 ); // This is half a prize ticket! Double-click this ticket and target any other ticket marked NEW PLAYER and get a prize! This ticket will only work for YOU, so don't give it away! + } + + public override bool DisplayLootType{ get{ return false; } } + + public NewPlayerTicket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Owner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Owner = reader.ReadMobile(); + break; + } + } + + if ( Name == "a young player ticket" ) + Name = null; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from != m_Owner ) + { + from.SendLocalizedMessage( 501926 ); // This isn't your ticket! Shame on you! You have to use YOUR ticket. + } + else if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + from.SendLocalizedMessage( 501927 ); // Target any other ticket marked NEW PLAYER to win a prize. + from.Target = new InternalTarget( this ); + } + } + + private class InternalTarget : Target + { + private NewPlayerTicket m_Ticket; + + public InternalTarget( NewPlayerTicket ticket ) : base( 2, false, TargetFlags.None ) + { + m_Ticket = ticket; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted == m_Ticket ) + { + from.SendLocalizedMessage( 501928 ); // You can't target the same ticket! + } + else if ( targeted is NewPlayerTicket ) + { + NewPlayerTicket theirTicket = targeted as NewPlayerTicket; + Mobile them = theirTicket.m_Owner; + + if ( them == null || them.Deleted ) + { + from.SendLocalizedMessage( 501930 ); // That is not a valid ticket. + } + else + { + from.SendGump( new InternalGump( from, m_Ticket ) ); + them.SendGump( new InternalGump( them, theirTicket ) ); + } + } + else if ( targeted is Item && ((Item)targeted).ItemID == 0x14F0 ) + { + from.SendLocalizedMessage( 501931 ); // You need to find another ticket marked NEW PLAYER. + } + else + { + from.SendLocalizedMessage( 501929 ); // You will need to select a ticket. + } + } + } + + private class InternalGump : Gump + { + private Mobile m_From; + private NewPlayerTicket m_Ticket; + + public InternalGump( Mobile from, NewPlayerTicket ticket ) : base( 50, 50 ) + { + m_From = from; + m_Ticket = ticket; + + AddBackground( 0, 0, 400, 385, 0xA28 ); + + AddHtmlLocalized( 30, 45, 340, 70, 1013011, true, true ); // Choose the gift you prefer. WARNING: if you cancel, and your partner does not, you will need to find another matching ticket! + + AddButton( 46, 128, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 130, 320, 35, 1013012, false, false ); // A sextant + + AddButton( 46, 163, 0xFA5, 0xFA7, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 165, 320, 35, 1013013, false, false ); // A coupon for a single hair restyling + + //AddButton( 46, 198, 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 ); + //AddHtmlLocalized( 80, 200, 320, 35, 1013014, false, false ); // A spellbook with all 1st - 4th spells. + + AddButton( 46, 233, 0xFA5, 0xFA7, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 235, 320, 35, 1013015, false, false ); // A wand of fireworks + + AddButton( 46, 268, 0xFA5, 0xFA7, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 270, 320, 35, 1013016, false, false ); // A spyglass + + AddButton( 46, 303, 0xFA5, 0xFA7, 6, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 305, 320, 35, 1013017, false, false ); // Dyes and a dye tub + + AddButton( 120, 340, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 154, 342, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Ticket.Deleted ) + return; + + int number = 0; + + Item item = null; + Item item2 = null; + + switch ( info.ButtonID ) + { + case 1: item = new Sextant(); number = 1010494; break; // A sextant has been placed in your backpack. + case 2: item = new HairRestylingDeed(); number = 501933; break; // A coupon for a free hair restyling has been placed in your backpack. + // Scriptiz : pas de spellbook ! + //case 3: item = new Spellbook( 0xFFFFFFFF ); number = 1010495; break; // A spellbook with all 1st to 4th circle spells has been placed in your backpack. + case 4: item = new FireworksWand(); number = 501935; break; // A wand of fireworks has been placed in your backpack. + case 5: item = new Spyglass(); number = 501936; break; // A spyglass has been placed in your backpack. + case 6: item = new DyeTub(); item2 = new Dyes(); number = 501937; break; // The dyes and dye tub have been placed in your backpack. + } + + if ( item != null ) + { + m_Ticket.Delete(); + + m_From.SendLocalizedMessage( number ); + m_From.AddToBackpack( item ); + + if ( item2 != null ) + m_From.AddToBackpack( item2 ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Deeds/VendorRentalContract.cs b/Scripts/Items/Deeds/VendorRentalContract.cs new file mode 100644 index 0000000..d1ad3fb --- /dev/null +++ b/Scripts/Items/Deeds/VendorRentalContract.cs @@ -0,0 +1,368 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.ContextMenus; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class VendorRentalContract : Item + { + public override int LabelNumber{ get{ return 1062332; } } // a vendor rental contract + + private VendorRentalDuration m_Duration; + private int m_Price; + private bool m_LandlordRenew; + + private Mobile m_Offeree; + private Timer m_OfferExpireTimer; + + public VendorRentalDuration Duration + { + get{ return m_Duration; } + set + { + if ( value != null ) + m_Duration = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Price + { + get{ return m_Price; } + set{ m_Price = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LandlordRenew + { + get{ return m_LandlordRenew; } + set{ m_LandlordRenew = value; } + } + + public Mobile Offeree + { + get{ return m_Offeree; } + set + { + if ( m_OfferExpireTimer != null ) + { + m_OfferExpireTimer.Stop(); + m_OfferExpireTimer = null; + } + + m_Offeree = value; + + if ( value != null ) + { + m_OfferExpireTimer = new OfferExpireTimer( this ); + m_OfferExpireTimer.Start(); + } + + InvalidateProperties(); + } + } + + [Constructable] + public VendorRentalContract() : base( 0x14F0 ) + { + Weight = 1.0; + Hue = 0x672; + + m_Duration = VendorRentalDuration.Instances[0]; + m_Price = 1500; + } + + public VendorRentalContract( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Offeree != null ) + list.Add( 1062368, Offeree.Name ); // Being Offered To ~1_NAME~ + } + + public bool IsLandlord( Mobile m ) + { + if ( IsLockedDown ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.DecayType != DecayType.Condemned ) + return house.IsOwner( m ); + } + + return false; + } + + public bool IsUsableBy( Mobile from, bool byLandlord, bool byBackpack, bool noOfferee, bool sendMessage ) + { + if ( this.Deleted || !from.CheckAlive( sendMessage ) ) + return false; + + if ( noOfferee && Offeree != null ) + { + if ( sendMessage ) + from.SendLocalizedMessage( 1062343 ); // That item is currently in use. + + return false; + } + + if ( byBackpack && IsChildOf( from.Backpack ) ) + return true; + + if ( byLandlord && IsLandlord( from ) ) + { + if ( from.Map != this.Map || !from.InRange( this, 5 ) ) + { + if ( sendMessage ) + from.SendLocalizedMessage( 501853 ); // Target is too far away. + + return false; + } + + return true; + } + + return false; + } + + public override void OnDelete() + { + if ( IsLockedDown ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null ) + { + house.VendorRentalContracts.Remove( this ); + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Offeree != null ) + { + from.SendLocalizedMessage( 1062343 ); // That item is currently in use. + } + else if ( !IsLockedDown ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + return; + } + + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house == null || !house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 1062333 ); // You must be standing inside of a house that you own to make use of this contract. + } + else if ( !house.IsAosRules ) + { + from.SendMessage( "Rental contracts can only be placed in AOS-enabled houses." ); + } + else if ( !house.Public ) + { + from.SendLocalizedMessage( 1062335 ); // Rental contracts can only be placed in public houses. + } + else if ( !house.CanPlaceNewVendor() ) + { + from.SendLocalizedMessage( 1062352 ); // You do not have enought storage available to place this contract. + } + else + { + from.SendLocalizedMessage( 1062337 ); // Target the exact location you wish to rent out. + from.Target = new RentTarget( this ); + } + } + else if ( IsLandlord( from ) ) + { + if ( from.InRange( this, 5 ) ) + { + from.CloseGump( typeof( VendorRentalContractGump ) ); + from.SendGump( new VendorRentalContractGump( this, from ) ); + } + else + { + from.SendLocalizedMessage( 501853 ); // Target is too far away. + } + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( IsUsableBy( from, true, true, true, false ) ) + { + list.Add( new ContractOptionEntry( this ) ); + } + } + + private class ContractOptionEntry : ContextMenuEntry + { + private VendorRentalContract m_Contract; + + public ContractOptionEntry( VendorRentalContract contract ) : base( 6209 ) + { + m_Contract = contract; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( m_Contract.IsUsableBy( from, true, true, true, true ) ) + { + from.CloseGump( typeof( VendorRentalContractGump ) ); + from.SendGump( new VendorRentalContractGump( m_Contract, from ) ); + } + } + } + + private class RentTarget : Target + { + private VendorRentalContract m_Contract; + + public RentTarget( VendorRentalContract contract ) : base( -1, false, TargetFlags.None ) + { + m_Contract = contract; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Contract.IsUsableBy( from, false, true, true, true ) ) + return; + + IPoint3D location = targeted as IPoint3D; + if ( location == null ) + return; + + Point3D pLocation = new Point3D( location ); + Map map = from.Map; + + BaseHouse house = BaseHouse.FindHouseAt( pLocation, map, 0 ); + + if ( house == null || !house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 1062338 ); // The location being rented out must be inside of your house. + } + else if ( BaseHouse.FindHouseAt( from ) != house ) + { + from.SendLocalizedMessage( 1062339 ); // You must be located inside of the house in which you are trying to place the contract. + } + else if ( !house.IsAosRules ) + { + from.SendMessage( "Rental contracts can only be placed in AOS-enabled houses." ); + } + else if ( !house.Public ) + { + from.SendLocalizedMessage( 1062335 ); // Rental contracts can only be placed in public houses. + } + else if ( house.DecayType == DecayType.Condemned ) + { + from.SendLocalizedMessage( 1062468 ); // You cannot place a contract in a condemned house. + } + else if ( !house.CanPlaceNewVendor() ) + { + from.SendLocalizedMessage( 1062352 ); // You do not have enought storage available to place this contract. + } + else if ( !map.CanFit( pLocation, 16, false, false ) ) + { + from.SendLocalizedMessage( 1062486 ); // A vendor cannot exist at that location. Please try again. + } + else + { + bool vendor, contract; + BaseHouse.IsThereVendor( pLocation, map, out vendor, out contract ); + + if ( vendor ) + { + from.SendLocalizedMessage( 1062342 ); // You may not place a rental contract at this location while other beings occupy it. + } + else if ( contract ) + { + from.SendLocalizedMessage( 1062341 ); // That location is cluttered. Please clear out any objects there and try again. + } + else + { + m_Contract.MoveToWorld( pLocation, map ); + + if ( !house.LockDown( from, m_Contract ) ) + { + from.AddToBackpack( m_Contract ); + } + } + } + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + from.SendLocalizedMessage( 1062336 ); // You decide not to place the contract at this time. + } + } + + private class OfferExpireTimer : Timer + { + private VendorRentalContract m_Contract; + + public OfferExpireTimer( VendorRentalContract contract ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Contract = contract; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + Mobile offeree = m_Contract.Offeree; + + if ( offeree != null ) + { + offeree.CloseGump( typeof( VendorRentalOfferGump ) ); + + m_Contract.Offeree = null; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteEncodedInt( m_Duration.ID ); + + writer.Write( (int) m_Price ); + writer.Write( (bool) m_LandlordRenew ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + int durationID = reader.ReadEncodedInt(); + if ( durationID < VendorRentalDuration.Instances.Length ) + m_Duration = VendorRentalDuration.Instances[durationID]; + else + m_Duration = VendorRentalDuration.Instances[0]; + + m_Price = reader.ReadInt(); + m_LandlordRenew = reader.ReadBool(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Facial/Beard.cs b/Scripts/Items/Facial/Beard.cs new file mode 100644 index 0000000..ff57422 --- /dev/null +++ b/Scripts/Items/Facial/Beard.cs @@ -0,0 +1,330 @@ +using System; + +namespace Server.Items +{ + public abstract class Beard : Item + { + /*public static Beard CreateByID( int id, int hue ) + { + switch ( id ) + { + case 0x203E: return new LongBeard( hue ); + case 0x203F: return new ShortBeard( hue ); + case 0x2040: return new Goatee( hue ); + case 0x2041: return new Mustache( hue ); + case 0x204B: return new MediumShortBeard( hue ); + case 0x204C: return new MediumLongBeard( hue ); + case 0x204D: return new Vandyke( hue ); + default: return new GenericBeard( id, hue ); + } + }*/ + + protected Beard( int itemID ) : this( itemID, 0 ) + { + } + + protected Beard( int itemID, int hue ) : base( itemID ) + { + LootType = LootType.Blessed; + Layer = Layer.FacialHair; + Hue = hue; + } + + public Beard( Serial serial ) : base( serial ) + { + } + + public override bool DisplayLootType{ get{ return false; } } + + public override bool VerifyMove( Mobile from ) + { + return ( from.AccessLevel >= AccessLevel.GameMaster ); + } + + public override DeathMoveResult OnParentDeath( Mobile parent ) + { + //Dupe( Amount ); + + parent.FacialHairItemID = this.ItemID; + parent.FacialHairHue = this.Hue; + + return DeathMoveResult.MoveToCorpse; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + } + } + + public class GenericBeard : Beard + { + + private GenericBeard( int itemID ) : this( itemID, 0 ) + { + } + + + private GenericBeard( int itemID, int hue ) : base( itemID, hue ) + { + } + + public GenericBeard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LongBeard : Beard + { + + private LongBeard() + : this( 0 ) + { + } + + private LongBeard( int hue ) + : base( 0x203E, hue ) + { + } + + public LongBeard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ShortBeard : Beard + { + + private ShortBeard() + : this( 0 ) + { + } + + + private ShortBeard( int hue ) + : base( 0x203f, hue ) + { + } + + public ShortBeard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Goatee : Beard + { + + private Goatee() + : this( 0 ) + { + } + + + private Goatee( int hue ) + : base( 0x2040, hue ) + { + } + + public Goatee( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Mustache : Beard + { + + private Mustache() + : this( 0 ) + { + } + + + private Mustache( int hue ) + : base( 0x2041, hue ) + { + } + + public Mustache( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumShortBeard : Beard + { + + private MediumShortBeard() + : this( 0 ) + { + } + + + private MediumShortBeard( int hue ) + : base( 0x204B, hue ) + { + } + + public MediumShortBeard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MediumLongBeard : Beard + { + + private MediumLongBeard() + : this( 0 ) + { + } + + + private MediumLongBeard( int hue ) + : base( 0x204C, hue ) + { + } + + public MediumLongBeard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Vandyke : Beard + { + + private Vandyke() + : this( 0 ) + { + } + + + private Vandyke( int hue ) + : base( 0x204D, hue ) + { + } + + public Vandyke( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Facial/Hair.cs b/Scripts/Items/Facial/Hair.cs new file mode 100644 index 0000000..4e047c0 --- /dev/null +++ b/Scripts/Items/Facial/Hair.cs @@ -0,0 +1,491 @@ +using System; + +namespace Server.Items +{ + public abstract class Hair : Item + { + /* + + public static Hair GetRandomHair( bool female ) + { + return GetRandomHair( female, Utility.RandomHairHue() ); + } + + public static Hair GetRandomHair( bool female, int hairHue ) + { + if( female ) + { + switch ( Utility.Random( 9 ) ) + { + case 0: return new Afro( hairHue ); + case 1: return new KrisnaHair( hairHue ); + case 2: return new PageboyHair( hairHue ); + case 3: return new PonyTail( hairHue ); + case 4: return new ReceedingHair( hairHue ); + case 5: return new TwoPigTails( hairHue ); + case 6: return new ShortHair( hairHue ); + case 7: return new LongHair( hairHue ); + default: return new BunsHair( hairHue ); + } + } + else + { + switch ( Utility.Random( 8 ) ) + { + case 0: return new Afro( hairHue ); + case 1: return new KrisnaHair( hairHue ); + case 2: return new PageboyHair( hairHue ); + case 3: return new PonyTail( hairHue ); + case 4: return new ReceedingHair( hairHue ); + case 5: return new TwoPigTails( hairHue ); + case 6: return new ShortHair( hairHue ); + default: return new LongHair( hairHue ); + } + } + } + + + public static Hair CreateByID( int id, int hue ) + { + switch ( id ) + { + case 0x203B: return new ShortHair( hue ); + case 0x203C: return new LongHair( hue ); + case 0x203D: return new PonyTail( hue ); + case 0x2044: return new Mohawk( hue ); + case 0x2045: return new PageboyHair( hue ); + case 0x2046: return new BunsHair( hue ); + case 0x2047: return new Afro( hue ); + case 0x2048: return new ReceedingHair( hue ); + case 0x2049: return new TwoPigTails( hue ); + case 0x204A: return new KrisnaHair( hue ); + default: return new GenericHair( id, hue ); + } + } + * */ + + protected Hair( int itemID ) + : this( itemID, 0 ) + { + } + + protected Hair( int itemID, int hue ) + : base( itemID ) + { + LootType = LootType.Blessed; + Layer = Layer.Hair; + Hue = hue; + } + + public Hair( Serial serial ) + : base( serial ) + { + } + + public override bool DisplayLootType { get { return false; } } + + public override bool VerifyMove( Mobile from ) + { + return (from.AccessLevel >= AccessLevel.GameMaster); + } + + public override DeathMoveResult OnParentDeath( Mobile parent ) + { +// Dupe( Amount ); + + parent.HairItemID = this.ItemID; + parent.HairHue = this.Hue; + + return DeathMoveResult.MoveToCorpse; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + } + } + + public class GenericHair : Hair + { + + private GenericHair( int itemID ) + : this( itemID, 0 ) + { + } + + + private GenericHair( int itemID, int hue ) + : base( itemID, hue ) + { + } + + public GenericHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Mohawk : Hair + { + + private Mohawk() + : this( 0 ) + { + } + + + private Mohawk( int hue ) + : base( 0x2044, hue ) + { + } + + public Mohawk( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PageboyHair : Hair + { + + private PageboyHair() + : this( 0 ) + { + } + + + private PageboyHair( int hue ) + : base( 0x2045, hue ) + { + } + + public PageboyHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BunsHair : Hair + { + + private BunsHair() + : this( 0 ) + { + } + + + private BunsHair( int hue ) + : base( 0x2046, hue ) + { + } + + public BunsHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LongHair : Hair + { + + private LongHair() + : this( 0 ) + { + } + + + private LongHair( int hue ) + : base( 0x203C, hue ) + { + } + + public LongHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ShortHair : Hair + { + + private ShortHair() + : this( 0 ) + { + } + + + private ShortHair( int hue ) + : base( 0x203B, hue ) + { + } + + public ShortHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PonyTail : Hair + { + + private PonyTail() + : this( 0 ) + { + } + + + private PonyTail( int hue ) + : base( 0x203D, hue ) + { + } + + public PonyTail( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Afro : Hair + { + + private Afro() + : this( 0 ) + { + } + + + private Afro( int hue ) + : base( 0x2047, hue ) + { + } + + public Afro( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ReceedingHair : Hair + { + + private ReceedingHair() + : this( 0 ) + { + } + + + private ReceedingHair( int hue ) + : base( 0x2048, hue ) + { + } + + public ReceedingHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TwoPigTails : Hair + { + + private TwoPigTails() + : this( 0 ) + { + } + + + private TwoPigTails( int hue ) + : base( 0x2049, hue ) + { + } + + public TwoPigTails( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class KrisnaHair : Hair + { + + private KrisnaHair() + : this( 0 ) + { + } + + + private KrisnaHair( int hue ) + : base( 0x204A, hue ) + { + } + + public KrisnaHair( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableCabbage.cs b/Scripts/Items/Farming/FarmableCabbage.cs new file mode 100644 index 0000000..4373661 --- /dev/null +++ b/Scripts/Items/Farming/FarmableCabbage.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableCabbage : FarmableCrop + { + public static int GetCropID() + { + return 3254; + } + + public override Item GetCropObject() + { + Cabbage cabbage = new Cabbage(); + + cabbage.ItemID = Utility.Random( 3195, 2 ); + + return cabbage; + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableCabbage() : base( GetCropID() ) + { + } + + public FarmableCabbage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableCarrot.cs b/Scripts/Items/Farming/FarmableCarrot.cs new file mode 100644 index 0000000..c63a91f --- /dev/null +++ b/Scripts/Items/Farming/FarmableCarrot.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableCarrot : FarmableCrop + { + public static int GetCropID() + { + return 3190; + } + + public override Item GetCropObject() + { + Carrot carrot = new Carrot(); + + carrot.ItemID = Utility.Random( 3191, 2 ); + + return carrot; + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableCarrot() : base( GetCropID() ) + { + } + + public FarmableCarrot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableCotton.cs b/Scripts/Items/Farming/FarmableCotton.cs new file mode 100644 index 0000000..99eface --- /dev/null +++ b/Scripts/Items/Farming/FarmableCotton.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableCotton : FarmableCrop + { + public static int GetCropID() + { + return Utility.Random( 3153, 4 ); + } + + public override Item GetCropObject() + { + return new Cotton(); + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableCotton() : base( GetCropID() ) + { + } + + public FarmableCotton( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableCrop.cs b/Scripts/Items/Farming/FarmableCrop.cs new file mode 100644 index 0000000..061c49b --- /dev/null +++ b/Scripts/Items/Farming/FarmableCrop.cs @@ -0,0 +1,94 @@ +using System; +using Server; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + public abstract class FarmableCrop : Item + { + private bool m_Picked; + + public abstract Item GetCropObject(); + public abstract int GetPickedID(); + + public FarmableCrop( int itemID ) : base( itemID ) + { + Movable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + Map map = this.Map; + Point3D loc = this.Location; + + if ( Parent != null || Movable || IsLockedDown || IsSecure || map == null || map == Map.Internal ) + return; + + if ( !from.InRange( loc, 2 ) || !from.InLOS( this ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous ne pouvez atteindre cela" ); // I can't reach that. + else if ( !m_Picked ) + OnPicked( from, loc, map ); + } + + public virtual void OnPicked( Mobile from, Point3D loc, Map map ) + { + ItemID = GetPickedID(); + + Item spawn = GetCropObject(); + + if ( spawn != null ) + spawn.MoveToWorld( loc, map ); + + m_Picked = true; + + Unlink(); + + Timer.DelayCall( TimeSpan.FromMinutes( 5.0 ), new TimerCallback( Delete ) ); + } + + public void Unlink() + { + ISpawner se = this.Spawner; + + if ( se != null ) + { + this.Spawner.Remove( this ); + this.Spawner = null; + } + + } + + public FarmableCrop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_Picked ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + m_Picked = reader.ReadBool(); + break; + } + if ( m_Picked ) + { + Unlink(); + Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableFlax.cs b/Scripts/Items/Farming/FarmableFlax.cs new file mode 100644 index 0000000..1ff7552 --- /dev/null +++ b/Scripts/Items/Farming/FarmableFlax.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableFlax : FarmableCrop + { + public static int GetCropID() + { + return Utility.Random( 6809, 3 ); + } + + public override Item GetCropObject() + { + Flax flax = new Flax(); + + flax.ItemID = Utility.Random( 6812, 2 ); + + return flax; + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableFlax() : base( GetCropID() ) + { + } + + public FarmableFlax( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableLettuce.cs b/Scripts/Items/Farming/FarmableLettuce.cs new file mode 100644 index 0000000..073e31b --- /dev/null +++ b/Scripts/Items/Farming/FarmableLettuce.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableLettuce : FarmableCrop + { + public static int GetCropID() + { + return 3254; + } + + public override Item GetCropObject() + { + Lettuce lettuce = new Lettuce(); + + lettuce.ItemID = Utility.Random( 3184, 2 ); + + return lettuce; + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableLettuce() : base( GetCropID() ) + { + } + + public FarmableLettuce( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableOnion.cs b/Scripts/Items/Farming/FarmableOnion.cs new file mode 100644 index 0000000..2fd9f72 --- /dev/null +++ b/Scripts/Items/Farming/FarmableOnion.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableOnion : FarmableCrop + { + public static int GetCropID() + { + return 3183; + } + + public override Item GetCropObject() + { + Onion onion = new Onion(); + + onion.ItemID = Utility.Random( 3181, 2 ); + + return onion; + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableOnion() : base( GetCropID() ) + { + } + + public FarmableOnion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmablePumpkin.cs b/Scripts/Items/Farming/FarmablePumpkin.cs new file mode 100644 index 0000000..7d32afc --- /dev/null +++ b/Scripts/Items/Farming/FarmablePumpkin.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmablePumpkin : FarmableCrop + { + public static int GetCropID() + { + return Utility.Random( 3166, 3 ); + } + + public override Item GetCropObject() + { + Pumpkin pumpkin = new Pumpkin(); + + pumpkin.ItemID = Utility.Random( 3178, 3 ); + + return pumpkin; + } + + public override int GetPickedID() + { + return Utility.Random( 3166, 3 ); + } + + [Constructable] + public FarmablePumpkin() + : base( GetCropID() ) + { + } + + public FarmablePumpkin( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableTurnip.cs b/Scripts/Items/Farming/FarmableTurnip.cs new file mode 100644 index 0000000..687219e --- /dev/null +++ b/Scripts/Items/Farming/FarmableTurnip.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableTurnip : FarmableCrop + { + public static int GetCropID() + { + return Utility.Random( 3169, 3 ); + } + + public override Item GetCropObject() + { + Turnip turnip = new Turnip(); + + turnip.ItemID = Utility.Random( 3385, 2 ); + + return turnip; + } + + public override int GetPickedID() + { + return 3254; + } + + [Constructable] + public FarmableTurnip() : base( GetCropID() ) + { + } + + public FarmableTurnip( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Farming/FarmableWheat.cs b/Scripts/Items/Farming/FarmableWheat.cs new file mode 100644 index 0000000..9c677a6 --- /dev/null +++ b/Scripts/Items/Farming/FarmableWheat.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FarmableWheat : FarmableCrop + { + public static int GetCropID() + { + return Utility.Random( 3157, 4 ); + } + + public override Item GetCropObject() + { + return new WheatSheaf(); + } + + public override int GetPickedID() + { + return Utility.Random( 3502, 2 ); + } + + [Constructable] + public FarmableWheat() : base( GetCropID() ) + { + } + + public FarmableWheat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/Asian.cs b/Scripts/Items/Food/Asian.cs new file mode 100644 index 0000000..dea9a91 --- /dev/null +++ b/Scripts/Items/Food/Asian.cs @@ -0,0 +1,366 @@ +using System; + +namespace Server.Items +{ + public class Wasabi : Item + { + [Constructable] + public Wasabi() : base( 0x24E8 ) + { + Weight = 1.0; + } + + public Wasabi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WasabiClumps : Food + { + [Constructable] + public WasabiClumps() : base( 0x24EB ) + { + Name = "P�te de wasabi"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public WasabiClumps( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EmptyBentoBox : Item + { + [Constructable] + public EmptyBentoBox() : base( 0x2834 ) + { + Name = "Boite de bento vide"; + Weight = 5.0; + } + + public EmptyBentoBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BentoBox : Food + { + [Constructable] + public BentoBox() : base( 0x2836 ) + { + Name = "Boite de bento"; + Stackable = false; + Weight = 5.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyBentoBox() ); + return true; + } + + public BentoBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SushiRolls : Food + { + [Constructable] + public SushiRolls() : base( 0x283E ) + { + Name = "Makis"; + Stackable = false; + Weight = 3.0; + FillFactor = 2; + } + + public SushiRolls( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SushiPlatter : Food + { + [Constructable] + public SushiPlatter() : base( 0x2840 ) + { + Name = "Plateau de sushis"; + Stackable = Core.ML; + Weight = 3.0; + FillFactor = 2; + } + + public SushiPlatter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenTeaBasket : Item + { + [Constructable] + public GreenTeaBasket() : base( 0x284B ) + { + Name = "Boite de th� vert"; + Weight = 10.0; + } + + public GreenTeaBasket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenTea : Food + { + [Constructable] + public GreenTea() : base( 0x284C ) + { + Name = "Th� vert"; + Stackable = false; + Weight = 4.0; + FillFactor = 2; + } + + public GreenTea( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MisoSoup : Food + { + [Constructable] + public MisoSoup() : base( 0x284D ) + { + Name = "Soupe miso"; + Stackable = false; + Weight = 4.0; + FillFactor = 2; + } + + public MisoSoup( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WhiteMisoSoup : Food + { + [Constructable] + public WhiteMisoSoup() : base( 0x284E ) + { + Name = "Soupe miso blanche"; + Stackable = false; + Weight = 4.0; + FillFactor = 2; + } + + public WhiteMisoSoup( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RedMisoSoup : Food + { + [Constructable] + public RedMisoSoup() : base( 0x284F ) + { + Name = "Soupe miso rouge"; + Stackable = false; + Weight = 4.0; + FillFactor = 2; + } + + public RedMisoSoup( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AwaseMisoSoup : Food + { + [Constructable] + public AwaseMisoSoup() : base( 0x2850 ) + { + Name = "Soupe miso awase"; + Stackable = false; + Weight = 4.0; + FillFactor = 2; + } + + public AwaseMisoSoup( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/Beverage.cs b/Scripts/Items/Food/Beverage.cs new file mode 100644 index 0000000..4c15351 --- /dev/null +++ b/Scripts/Items/Food/Beverage.cs @@ -0,0 +1,1556 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Engines.Plants; +using Server.Engines.Quests; +using Server.Engines.Quests.Hag; +using Server.Engines.Quests.Matriarch; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public enum BeverageType + { + Ale, + Cider, + Liquor, + Milk, + Wine, + Water, + + // Scriptiz : Ajout des breuvages de vivre � la fin de l'�num�ration !! + BiereCommune, + BiereAmbre, + BiereMiel, + BiereBrune, + BiereEpice, + BiereSorciere, + MoinetteYew, + Kwak, + + // Scriptiz : ajout de quelques breuvages pour Crystal + LaitChevre, + LaitBrebis, + JusPomme, + JusPeche, + JusRaisin + } + + public interface IHasQuantity + { + int Quantity { get; set; } + } + + public interface IWaterSource : IHasQuantity + { + } + + // TODO: Flipable attributes + [TypeAlias("Server.Items.BottleBiereCommune", "Server.Items.BottleBiereAmbre", "Server.Items.BottleBiereMiel", + "Server.Items.BottleBiereBrune", "Server.Items.BottleBiereEpice", "Server.Items.BottleMoinetteYew", "Server.Items.BottleKwak", + "Server.Items.BottleBiereSorciere", "Server.Items.BottleAle", "Server.Items.BottleLiquor", "Server.Items.BottleWine")] + public class BeverageBottle : BaseBeverage + { + public override int BaseLabelNumber { get { return 1042959; } } // a bottle of Ale + public override int MaxQuantity { get { return 5; } } + public override bool Fillable { get { return false; } } + + public override int ComputeItemID() + { + if (!IsEmpty) + { + switch (Content) + { + case BeverageType.Ale: return 0x99F; + case BeverageType.Cider: return 0x99F; + case BeverageType.Liquor: return 0x99B; + case BeverageType.Milk: return 0x99B; + case BeverageType.Wine: return 0x9C7; + case BeverageType.Water: return 0x99B; + + // Boissons de vivre + case BeverageType.BiereCommune: return 0x99F; + case BeverageType.BiereAmbre: return 0x99F; + case BeverageType.BiereMiel: return 0x99F; + case BeverageType.BiereBrune: return 0x99F; + case BeverageType.BiereEpice: return 0x99F; + case BeverageType.MoinetteYew: return 0x99F; + case BeverageType.Kwak: return 0x99F; + case BeverageType.BiereSorciere: return 0x99F; + + // Scriptiz : ajout de quelques trucs pour Crystal + case BeverageType.LaitChevre: return 0x99B; + case BeverageType.LaitBrebis: return 0x99B; + case BeverageType.JusPomme: return 0x99F; + case BeverageType.JusPeche: return 0x99F; + case BeverageType.JusRaisin: return 0x9C7; + } + } + + return 0; + } + + [Constructable] + public BeverageBottle(BeverageType type) + : base(type) + { + Weight = 1.0; + } + + public BeverageBottle(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + if (CheckType("BottleAle")) Content = BeverageType.Ale; + else if (CheckType("BottleLiquor")) Content = BeverageType.Liquor; + else if (CheckType("BottleWine")) Content = BeverageType.Wine; + + // Scriptiz : traitement des breuvages de Vivre + else if (CheckType("BottleBiereCommune")) Content = BeverageType.BiereCommune; + else if (CheckType("BottleBiereAmbre")) Content = BeverageType.BiereAmbre; + else if (CheckType("BottleBiereMiel")) Content = BeverageType.BiereMiel; + else if (CheckType("BottleBiereBrune")) Content = BeverageType.BiereBrune; + else if (CheckType("BottleBiereEpice")) Content = BeverageType.BiereEpice; + else if (CheckType("BottleMoinetteYew")) Content = BeverageType.MoinetteYew; + else if (CheckType("BottleKwak")) Content = BeverageType.Kwak; + else if (CheckType("BottleBiereSorciere")) Content = BeverageType.BiereSorciere; + else if (CheckType("BottleLiquor")) Content = BeverageType.Liquor; + else if (CheckType("BottleWine")) Content = BeverageType.Wine; + + // Scriptiz : Ajouts pour Crystal + else if (CheckType("BottleLaitChevre")) Content = BeverageType.LaitChevre; + else if (CheckType("BottleLaitBrebis")) Content = BeverageType.LaitBrebis; + else if (CheckType("BottleJusPomme")) Content = BeverageType.JusPomme; + else if (CheckType("BottleJusPeche")) Content = BeverageType.JusPeche; + else if (CheckType("BottleJusRaisin")) Content = BeverageType.JusRaisin; + else throw new Exception(World.LoadingType); + + Quantity = MaxQuantity; + + break; + } + } + } + } + + public class Jug : BaseBeverage + { + public override int BaseLabelNumber { get { return 1042965; } } // a jug of Ale + public override int MaxQuantity { get { return 10; } } + public override bool Fillable { get { return false; } } + + public override int ComputeItemID() + { + if (!IsEmpty) + return 0x9C8; + + return 0; + } + + [Constructable] + public Jug(BeverageType type) + : base(type) + { + Weight = 1.0; + } + + public Jug(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class CeramicMug : BaseBeverage + { + public override int BaseLabelNumber { get { return 1042982; } } // a ceramic mug of Ale + public override int MaxQuantity { get { return 1; } } + + public override int ComputeItemID() + { + if (ItemID >= 0x995 && ItemID <= 0x999) + return ItemID; + else if (ItemID == 0x9CA) + return ItemID; + + return 0x995; + } + + [Constructable] + public CeramicMug() + { + Weight = 1.0; + } + + [Constructable] + public CeramicMug(BeverageType type) + : base(type) + { + Weight = 1.0; + } + + public CeramicMug(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PewterMug : BaseBeverage + { + public override int BaseLabelNumber { get { return 1042994; } } // a pewter mug with Ale + public override int MaxQuantity { get { return 1; } } + + public override int ComputeItemID() + { + if (ItemID >= 0xFFF && ItemID <= 0x1002) + return ItemID; + + return 0xFFF; + } + + [Constructable] + public PewterMug() + { + Weight = 1.0; + } + + [Constructable] + public PewterMug(BeverageType type) + : base(type) + { + Weight = 1.0; + } + + public PewterMug(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Goblet : BaseBeverage + { + public override int BaseLabelNumber { get { return 1043000; } } // a goblet of Ale + public override int MaxQuantity { get { return 1; } } + + public override int ComputeItemID() + { + if (ItemID == 0x99A || ItemID == 0x9B3 || ItemID == 0x9BF || ItemID == 0x9CB) + return ItemID; + + return 0x99A; + } + + [Constructable] + public Goblet() + { + Weight = 1.0; + } + + [Constructable] + public Goblet(BeverageType type) + : base(type) + { + Weight = 1.0; + } + + public Goblet(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [TypeAlias("Server.Items.MugBiereCommune", "Server.Items.MugBiereAmbre", "Server.Items.MugBiereMiel", "Server.Items.MugBiereBrune", + "Server.Items.MugBiereEpice", "Server.Items.MugMoinetteYew", "Server.Items.MugKwak", "Server.Items.MugBiereSorciere", "Server.Items.MugAle", + "Server.Items.GlassCider", "Server.Items.GlassLiquor", "Server.Items.GlassMilk", "Server.Items.GlassWine", "Server.Items.GlassWater")] + public class GlassMug : BaseBeverage + { + public override int EmptyLabelNumber { get { return 1022456; } } // mug + public override int BaseLabelNumber { get { return 1042976; } } // a mug of Ale + public override int MaxQuantity { get { return 5; } } + + public override int ComputeItemID() + { + if (IsEmpty) + return (ItemID >= 0x1F81 && ItemID <= 0x1F84 ? ItemID : 0x1F81); + + switch (Content) + { + case BeverageType.Ale: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.Cider: return (ItemID >= 0x1F7D && ItemID <= 0x1F80 ? ItemID : 0x1F7D); + case BeverageType.Liquor: return (ItemID >= 0x1F85 && ItemID <= 0x1F88 ? ItemID : 0x1F85); + case BeverageType.Milk: return (ItemID >= 0x1F89 && ItemID <= 0x1F8C ? ItemID : 0x1F89); + case BeverageType.Wine: return (ItemID >= 0x1F8D && ItemID <= 0x1F90 ? ItemID : 0x1F8D); + case BeverageType.Water: return (ItemID >= 0x1F91 && ItemID <= 0x1F94 ? ItemID : 0x1F91); + + // Scriptiz : breuvages pour Vivre + case BeverageType.BiereCommune: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.BiereAmbre: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.BiereMiel: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.BiereBrune: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.BiereEpice: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.MoinetteYew: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.Kwak: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + case BeverageType.BiereSorciere: return (ItemID == 0x9EF ? 0x9EF : 0x9EE); + + // Scriptiz : ajout des breuvages pour Crystal + case BeverageType.LaitBrebis: + case BeverageType.LaitChevre: return (ItemID >= 0x1F89 && ItemID <= 0x1F8C ? ItemID : 0x1F89); + case BeverageType.JusPeche: + case BeverageType.JusPomme: return (ItemID >= 0x1F7D && ItemID <= 0x1F80 ? ItemID : 0x1F7D); + case BeverageType.JusRaisin: return (ItemID >= 0x1F8D && ItemID <= 0x1F90 ? ItemID : 0x1F8D); + } + + return 0; + } + + [Constructable] + public GlassMug() + { + Weight = 1.0; + } + + [Constructable] + public GlassMug(BeverageType type) + : base(type) + { + Weight = 1.0; + } + + public GlassMug(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + if (CheckType("MugAle")) Content = BeverageType.Ale; + else if (CheckType("GlassCider")) Content = BeverageType.Cider; + else if (CheckType("GlassLiquor")) Content = BeverageType.Liquor; + else if (CheckType("GlassMilk")) Content = BeverageType.Milk; + else if (CheckType("GlassWine")) Content = BeverageType.Wine; + else if (CheckType("GlassWater")) Content = BeverageType.Water; + + // Scriptiz : Breuvages de Vivre + else if (CheckType("MugBiereCommune")) Content = BeverageType.BiereCommune; + else if (CheckType("MugBiereAmbre")) Content = BeverageType.BiereAmbre; + else if (CheckType("MugBiereMiel")) Content = BeverageType.BiereMiel; + else if (CheckType("MugBiereBrune")) Content = BeverageType.BiereBrune; + else if (CheckType("MugBiereEpice")) Content = BeverageType.BiereEpice; + else if (CheckType("MugMoinetteYew")) Content = BeverageType.MoinetteYew; + else if (CheckType("MugKwak")) Content = BeverageType.Kwak; + else if (CheckType("MugBiereSorciere")) Content = BeverageType.BiereSorciere; + + // Scriptiz : Ajouts pour Crystal + else if (CheckType("MugLaitChevre")) Content = BeverageType.LaitChevre; + else if (CheckType("MugLaitBrebis")) Content = BeverageType.LaitBrebis; + else if (CheckType("MugJusPomme")) Content = BeverageType.JusPomme; + else if (CheckType("MugJusPeche")) Content = BeverageType.JusPeche; + else if (CheckType("MugJusRaisin")) Content = BeverageType.JusRaisin; + else throw new Exception(World.LoadingType); + + Quantity = MaxQuantity; + + break; + } + } + } + } + + [TypeAlias("Server.Items.PitcherBiereCommune", "Server.Items.PitcherBiereAmbre", "Server.Items.PitcherBiereMiel", "Server.Items.PitcherBiereBrune", "Server.Items.PitcherBiereEpice", + "Server.Items.PitcherMoinetteYew", "Server.Items.PitcherKwak", "Server.Items.PitcherBiereSorciere", "Server.Items.PitcherAle", + "Server.Items.PitcherCider", "Server.Items.PitcherLiquor", "Server.Items.PitcherMilk", "Server.Items.PitcherWine", + "Server.Items.PitcherWater", "Server.Items.GlassPitcher")] + public class Pitcher : BaseBeverage + { + public override int BaseLabelNumber { get { return 1048128; } } // a Pitcher of Ale + public override int MaxQuantity { get { return 40; } } // Scriptiz : les pichets passent � 40 doses (cfr uo.com) + + public override int ComputeItemID() + { + if (IsEmpty) + { + if (ItemID == 0x9A7 || ItemID == 0xFF7) + return ItemID; + + return 0xFF6; + } + + switch (Content) + { + // Scriptiz : ajout des bi�res de Vivre + case BeverageType.BiereAmbre: + case BeverageType.BiereBrune: + case BeverageType.BiereCommune: + case BeverageType.BiereEpice: + case BeverageType.BiereMiel: + case BeverageType.BiereSorciere: + case BeverageType.MoinetteYew: + case BeverageType.Kwak: + case BeverageType.Ale: + { + if (ItemID == 0x1F96) + return ItemID; + + return 0x1F95; + } + // Scriptiz : ajout de boissons + case BeverageType.JusPeche: + case BeverageType.JusPomme: + case BeverageType.Cider: + { + if (ItemID == 0x1F98) + return ItemID; + + return 0x1F97; + } + case BeverageType.Liquor: + { + if (ItemID == 0x1F9A) + return ItemID; + + return 0x1F99; + } + // Scriptiz : ajout de breuvages + case BeverageType.LaitChevre: + case BeverageType.LaitBrebis: + case BeverageType.Milk: + { + if (ItemID == 0x9AD) + return ItemID; + + return 0x9F0; + } + // Scriptiz : ajout de breuvages + case BeverageType.JusRaisin: + case BeverageType.Wine: + { + if (ItemID == 0x1F9C) + return ItemID; + + return 0x1F9B; + } + case BeverageType.Water: + { + if (ItemID == 0xFF8 || ItemID == 0xFF9 || ItemID == 0x1F9E) + return ItemID; + + return 0x1F9D; + } + } + + return 0; + } + + [Constructable] + public Pitcher() + { + Weight = 2.0; + } + + [Constructable] + public Pitcher(BeverageType type) + : base(type) + { + Weight = 2.0; + } + + public Pitcher(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + if (CheckType("PitcherWater") || CheckType("GlassPitcher")) + base.InternalDeserialize(reader, false); + else + base.InternalDeserialize(reader, true); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + if (CheckType("PitcherAle")) Content = BeverageType.Ale; + else if (CheckType("PitcherCider")) Content = BeverageType.Cider; + else if (CheckType("PitcherLiquor")) Content = BeverageType.Liquor; + else if (CheckType("PitcherMilk")) Content = BeverageType.Milk; + else if (CheckType("PitcherWine")) Content = BeverageType.Wine; + else if (CheckType("PitcherWater")) Content = BeverageType.Water; + else if (CheckType("GlassPitcher")) Content = BeverageType.Water; + + // Scriptiz : breuvages de Vivre + else if (CheckType("PitcherBiereCommune")) Content = BeverageType.BiereCommune; + else if (CheckType("PitcherBiereAmbre")) Content = BeverageType.BiereAmbre; + else if (CheckType("PitcherBiereMiel")) Content = BeverageType.BiereMiel; + else if (CheckType("PitcherBiereBrune")) Content = BeverageType.BiereBrune; + else if (CheckType("PitcherBiereEpice")) Content = BeverageType.BiereEpice; + else if (CheckType("PitcherMoinetteYew")) Content = BeverageType.MoinetteYew; + else if (CheckType("PitcherKwak")) Content = BeverageType.Kwak; + else if (CheckType("PitcherBiereSorciere")) Content = BeverageType.BiereSorciere; + + // Scriptiz : Ajouts pour Crystal + else if (CheckType("PitcherLaitChevre")) Content = BeverageType.LaitChevre; + else if (CheckType("PitcherLaitBrebis")) Content = BeverageType.LaitBrebis; + else if (CheckType("PitcherJusPomme")) Content = BeverageType.JusPomme; + else if (CheckType("PitcherJusPeche")) Content = BeverageType.JusPeche; + else if (CheckType("PitcherJusRaisin")) Content = BeverageType.JusRaisin; + else throw new Exception(World.LoadingType); + + Quantity = MaxQuantity; + + break; + } + } + } + } + + public abstract class BaseBeverage : Item, IHasQuantity + { + private BeverageType m_Content; + private int m_Quantity; + private Mobile m_Poisoner; + private Poison m_Poison; + + public override int LabelNumber + { + get + { + if ((int)this.m_Content > (int)BeverageType.Water) return BaseLabelNumber; // Scriptiz : basenumber si boisson custom ! + + int num = BaseLabelNumber; + + if (IsEmpty || num == 0) + return EmptyLabelNumber; + + return BaseLabelNumber + (int)m_Content; + } + } + + // Scriptiz : Cr�ation du nom pour les breuvages sp�ciaux de vivre + public override string DefaultName + { + get + { + if (this == null) return null; + + if ((int)this.m_Content <= (int)BeverageType.Water) return null; + + if (this.m_Quantity == 0) return null; + + string theName = null; // construisons le nom final + + if (this.GetType() == typeof(Pitcher)) + theName = "Pichet de "; + else if (this.GetType() == typeof(BeverageBottle)) + theName = "Bouteille de "; + else if (this.GetType() == typeof(Jug)) + theName = "Pot de "; + + switch (this.m_Content) + { + case BeverageType.BiereCommune: + theName += "Bi�re Commune"; + break; + case BeverageType.BiereAmbre: + theName += "Bi�re Ambr�e"; + break; + case BeverageType.BiereMiel: + theName += "Bi�re au Miel"; + break; + case BeverageType.BiereBrune: + theName += "Bi�re Brune"; + break; + case BeverageType.BiereEpice: + theName += "Bi�re aux Epices"; + break; + case BeverageType.BiereSorciere: + theName += "Bi�re de Sorci�re"; + break; + case BeverageType.MoinetteYew: + theName += "Moinette de Yew"; + break; + case BeverageType.Kwak: + theName += "Bi�re Kwak"; + break; + // Scriptiz : ajout de quelques trucs pour Crystal + case BeverageType.LaitChevre: + theName += "Lait de Ch�vre"; + break; + case BeverageType.LaitBrebis: + theName += "Lait de Brebis"; + break; + case BeverageType.JusPomme: + theName += "Jus de Pommes"; + break; + case BeverageType.JusPeche: + theName += "Jus de P�ches"; + break; + case BeverageType.JusRaisin: + theName += "Jus de Raisins"; + break; + } + + return theName; + } + } + + public virtual bool ShowQuantity { get { return (MaxQuantity > 1); } } + public virtual bool Fillable { get { return true; } } + public virtual bool Pourable { get { return true; } } + + public virtual int EmptyLabelNumber { get { return base.LabelNumber; } } + public virtual int BaseLabelNumber { get { return 0; } } + + public abstract int MaxQuantity { get; } + public abstract int ComputeItemID(); + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsEmpty + { + get { return (m_Quantity <= 0); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ContainsAlchohol + { + get { return (!IsEmpty && m_Content != BeverageType.Milk && m_Content != BeverageType.Water); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsFull + { + get { return (m_Quantity >= MaxQuantity); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Poison Poison + { + get { return m_Poison; } + set { m_Poison = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Poisoner + { + get { return m_Poisoner; } + set { m_Poisoner = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public BeverageType Content + { + get { return m_Content; } + set + { + m_Content = value; + + InvalidateProperties(); + + int itemID = ComputeItemID(); + + if (itemID > 0) + ItemID = itemID; + else + Delete(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Quantity + { + get { return m_Quantity; } + set + { + if (value < 0) + value = 0; + else if (value > MaxQuantity) + value = MaxQuantity; + + m_Quantity = value; + + InvalidateProperties(); + + int itemID = ComputeItemID(); + + if (itemID > 0) + ItemID = itemID; + else + Delete(); + } + } + + public virtual int GetQuantityDescription() + { + int perc = (m_Quantity * 100) / MaxQuantity; + + if (perc <= 0) + return 1042975; // It's empty. + else if (perc <= 33) + return 1042974; // It's nearly empty. + else if (perc <= 66) + return 1042973; // It's half full. + else + return 1042972; // It's full. + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (ShowQuantity) + list.Add(GetQuantityDescription()); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (ShowQuantity) + LabelTo(from, GetQuantityDescription()); + } + + // Scriptiz : ajout du menu contextuel pour vider un breuvage + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive) + list.Add(new ContextMenus.BeverageEntry(from, this)); + } + + public virtual bool ValidateUse(Mobile from, bool message) + { + if (Deleted) + return false; + + if (!Movable && !Fillable) + { + Multis.BaseHouse house = Multis.BaseHouse.FindHouseAt(this); + + if (house == null || !house.IsLockedDown(this)) + { + if (message) + from.SendLocalizedMessage(502946, "", 0x59); // That belongs to someone else. + + return false; + } + } + + if (from.Map != Map || !from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + if (message) + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + + return false; + } + + return true; + } + + public virtual void Fill_OnTarget(Mobile from, object targ) + { + if (!IsEmpty || !Fillable || !ValidateUse(from, false)) + return; + + if (targ is BaseBeverage) + { + BaseBeverage bev = (BaseBeverage)targ; + + if (bev.IsEmpty || !bev.ValidateUse(from, true)) + return; + + this.Content = bev.Content; + this.Poison = bev.Poison; + this.Poisoner = bev.Poisoner; + + if (bev.Quantity > this.MaxQuantity) + { + this.Quantity = this.MaxQuantity; + bev.Quantity -= this.MaxQuantity; + } + else + { + this.Quantity += bev.Quantity; + bev.Quantity = 0; + } + from.PlaySound(0x2D6); + } + // Scriptiz : Permet de remplir son pichet sur des WaterThrough et sur des water barrel statiques + else if (targ is Static) + { + Static s = (Static)targ; + if (from.Map != s.Map || !from.InRange(s.GetWorldLocation(), 2) || !from.InLOS(s)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous ne pouvez atteindre cela"); // I can't reach that. + return; + } + bool filled = BaseBeverage.FillFromStaticWaterSource(from, this, s.ItemID); + if (filled) from.SendMessage("Vous remplissez votre contenant d'eau"); // You fill the container with water. + } + // Scriptiz : Permet de remplir sur des tiles d'eau + else if (targ is StaticTarget) + { + StaticTarget st = (StaticTarget)targ; + if (!from.InRange(new Point2D(st.Location.X, st.Location.Y), 2) || !from.InLOS(st)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous ne pouvez atteindre cela"); // I can't reach that. + return; + } + bool filled = BaseBeverage.FillFromStaticWaterSource(from, this, st.ItemID); + if (filled) from.SendMessage("Vous remplissez votre contenant d'eau"); // You fill the container with water. + } + else if (targ is BaseWaterContainer && !(targ is Bucket)) + { + BaseWaterContainer bwc = targ as BaseWaterContainer; + + if (Quantity == 0 || (Content == BeverageType.Water && !IsFull)) + { + int iNeed = Math.Min((MaxQuantity - Quantity), bwc.Quantity); + + if (iNeed > 0 && !bwc.IsEmpty && !IsFull) + { + bwc.Quantity -= iNeed; + Quantity += iNeed; + Content = BeverageType.Water; + + from.PlaySound(0x4E); + } + } + } + else if (targ is Item) + { + Item item = (Item)targ; + IWaterSource src; + + src = (item as IWaterSource); + + if (src == null && item is AddonComponent) + src = (((AddonComponent)item).Addon as IWaterSource); + + if (src == null || src.Quantity <= 0) + return; + + if (from.Map != item.Map || !from.InRange(item.GetWorldLocation(), 2) || !from.InLOS(item)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous ne pouvez atteindre cela"); // I can't reach that. + return; + } + + this.Content = BeverageType.Water; + this.Poison = null; + this.Poisoner = null; + + if (src.Quantity > this.MaxQuantity) + { + this.Quantity = this.MaxQuantity; + src.Quantity -= this.MaxQuantity; + } + else + { + this.Quantity += src.Quantity; + src.Quantity = 0; + } + from.PlaySound(0x2D6); + from.SendMessage("Vous remplissez votre contenant d'eau"); // You fill the container with water. + } + else if (targ is Cow) + { + Cow cow = (Cow)targ; + + if (cow.TryMilk(from)) + { + Content = BeverageType.Milk; + Quantity = MaxQuantity; + from.SendMessage("Vous remplissez votre contenant de lait"); // You fill the container with milk. + from.PlaySound(0x2D6); + } + } + else if (targ is LandTarget) + { + int tileID = ((LandTarget)targ).TileID; + + PlayerMobile player = from as PlayerMobile; + + if (player != null) + { + QuestSystem qs = player.Quest; + + if (qs is WitchApprenticeQuest) + { + FindIngredientObjective obj = qs.FindObjective(typeof(FindIngredientObjective)) as FindIngredientObjective; + + if (obj != null && !obj.Completed && obj.Ingredient == Ingredient.SwampWater) + { + bool contains = false; + + for (int i = 0; !contains && i < m_SwampTiles.Length; i += 2) + contains = (tileID >= m_SwampTiles[i] && tileID <= m_SwampTiles[i + 1]); + + if (contains) + { + Delete(); + + player.SendLocalizedMessage(1055035); // You dip the container into the disgusting swamp water, collecting enough for the Hag's vile stew. + obj.Complete(); + return; // Scriptiz : si c'�tait pour la qu�te on s'arr�te l� + } + } + } + + // Scriptiz : Le joueur peut remplir � partir de LandTarget + LandTarget lt = (LandTarget)targ; + if (!from.InRange(new Point2D(lt.Location.X, lt.Location.Y), 2) || !from.InLOS(lt)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous ne pouvez atteindre cela"); // I can't reach that. + return; + } + + int[] waterTiles = new int[] { + 0xA8, 0xA9, 0xAA, 0xAB, + 0x136, 0x137, + 0x3FF0, 0x3FF1, 0x3FF2, 0x3FF3, + }; + + bool water = false; + for (int i = 0; i < waterTiles.Length; i++) + { + if (waterTiles[i] == tileID) + { + water = true; + break; + } + } + + if (water) + { + this.Poison = null; + this.Poisoner = null; + + int randomSeed = Utility.Random(1, 100); + + if (randomSeed <= 20) + { + if (randomSeed <= 5) + this.Poison = Poison.Regular; + else + this.Poison = Poison.Lesser; + } + + this.Content = BeverageType.Water; + this.Quantity = this.MaxQuantity; + from.SendMessage("Vous remplissez votre contenant d'eau"); // You fill the container with water. + from.PlaySound(0x2D6); + } + } + } + } + + // Scriptiz : permet de remplir son pichet � partir de staticTarget ou de StaticItem + private static bool FillFromStaticWaterSource(Mobile from, BaseBeverage b, int staticId) + { + if (!b.IsEmpty || !b.Fillable || !b.ValidateUse(from, false)) + return false; + + if (from == null) return false; + if (b == null) return false; + + b.Poison = null; + b.Poisoner = null; + + int randomSeed = Utility.Random(1, 100); + + // water barrels + if (staticId == 5453 || staticId == 3707) + { + b.Quantity = (b.MaxQuantity < 5 ? b.MaxQuantity : 5); + + if (Utility.Random(100) <= 5) + b.Poison = Poison.Lesser; + } + // water trough + else if (staticId >= 2881 && staticId <= 2884) + { + if (randomSeed <= 10) + b.Poison = Poison.Lesser; + } + // water tiles & waterfalls + else if ((staticId >= 6038 && staticId <= 6066) || (staticId >= 13422 && staticId <= 13525) || (staticId >= 13549 && staticId <= 13608)) + { + if (randomSeed <= 20) + { + if (randomSeed <= 5) + b.Poison = Poison.Regular; + else + b.Poison = Poison.Lesser; + } + } + // fountains + else if ((staticId >= 5937 && staticId <= 5978) || (staticId >= 6595 && staticId <= 6636)) + { + if (randomSeed <= 20) + { + if (randomSeed <= 5) + b.Poison = Poison.Regular; + else + b.Poison = Poison.Lesser; + } + } + // swamp tiles (disactivated) + //else if (staticId >= 12809 && staticId <= 12933) + //{ + // if (randomSeed <= 50) + // b.Poison = Poison.Regular; + // else if (randomSeed <= 80) + // b.Poison = Poison.Greater; + // else if (randomSeed <= 100) + // b.Poison = Poison.Deadly; + //} + else + { + b.Quantity = 0; + return false; + } + + // Fill the beverage + b.Content = BeverageType.Water; + if (staticId != 5453 && staticId != 3707) b.Quantity = b.MaxQuantity; + + from.PlaySound(0x2D6); + return true; + } + + private static int[] m_SwampTiles = new int[] + { + 0x9C4, 0x9EB, + 0x3D65, 0x3D65, + 0x3DC0, 0x3DD9, + 0x3DDB, 0x3DDC, + 0x3DDE, 0x3EF0, + 0x3FF6, 0x3FF6, + 0x3FFC, 0x3FFE, + }; + + #region Effects of achohol + private static Hashtable m_Table = new Hashtable(); + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler(EventSink_Login); + } + + private static void EventSink_Login(LoginEventArgs e) + { + CheckHeaveTimer(e.Mobile); + } + + public static void CheckHeaveTimer(Mobile from) + { + if (from.BAC > 0 && from.Map != Map.Internal && !from.Deleted) + { + Timer t = (Timer)m_Table[from]; + + if (t == null) + { + if (from.BAC > 60) + from.BAC = 60; + + t = new HeaveTimer(from); + t.Start(); + + m_Table[from] = t; + } + } + else + { + Timer t = (Timer)m_Table[from]; + + if (t != null) + { + t.Stop(); + m_Table.Remove(from); + + from.SendMessage("Vous vous sentez mieux"); // You feel sober. + } + } + } + + // Scriptiz : calcul le FillFactor en fonction du type du breuvage + public int ComputeFillFactor() + { + switch (Content) + { + case BeverageType.BiereAmbre: + case BeverageType.BiereBrune: + case BeverageType.BiereCommune: + case BeverageType.BiereEpice: + case BeverageType.BiereMiel: + case BeverageType.BiereSorciere: + case BeverageType.Kwak: + case BeverageType.MoinetteYew: + return 3; + case BeverageType.LaitBrebis: + case BeverageType.LaitChevre: + case BeverageType.JusPeche: + case BeverageType.JusPomme: + case BeverageType.JusRaisin: + case BeverageType.Ale: + case BeverageType.Cider: + case BeverageType.Liquor: + case BeverageType.Milk: + case BeverageType.Wine: + return 2; + case BeverageType.Water: + return 1; + default: return 1; + } + } + + private class HeaveTimer : Timer + { + private Mobile m_Drunk; + + public HeaveTimer(Mobile drunk) + : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0)) + { + m_Drunk = drunk; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if (m_Drunk.Deleted || m_Drunk.Map == Map.Internal) + { + Stop(); + m_Table.Remove(m_Drunk); + } + else if (m_Drunk.Alive) + { + if (m_Drunk.BAC > 60) + m_Drunk.BAC = 60; + + // chance to get sober + if (10 > Utility.Random(100)) + --m_Drunk.BAC; + + // lose some stats + m_Drunk.Stam -= 1; + m_Drunk.Mana -= 1; + + if (Utility.Random(1, 4) == 1) + { + if (!m_Drunk.Mounted) + { + // turn in a random direction + m_Drunk.Direction = (Direction)Utility.Random(8); + + // heave + m_Drunk.Animate(32, 5, 1, true, false, 0); + } + + // *hic* + m_Drunk.PublicOverheadMessage(Network.MessageType.Regular, 0x3B2, 500849); + } + + if (m_Drunk.BAC <= 0) + { + Stop(); + m_Table.Remove(m_Drunk); + + m_Drunk.SendMessage("Vous vous sentez mieux"); // You feel sober. + } + } + } + } + #endregion + + public virtual void Pour_OnTarget(Mobile from, object targ) + { + if (IsEmpty || !Pourable || !ValidateUse(from, false)) + return; + + if (targ is BaseBeverage) + { + BaseBeverage bev = (BaseBeverage)targ; + + if (!bev.ValidateUse(from, true)) + return; + + if (bev.IsFull && bev.Content == this.Content) + { + from.SendMessage("Vous ne pouvez verser ici, c'est d�j� plein"); // Couldn't pour it there. It was already full. + } + else if (!bev.IsEmpty) + { + from.SendMessage("Vous ne pouvez verser ici"); // Can't pour it there. + } + else + { + bev.Content = this.Content; + bev.Poison = this.Poison; + bev.Poisoner = this.Poisoner; + + if (this.Quantity > bev.MaxQuantity) + { + bev.Quantity = bev.MaxQuantity; + this.Quantity -= bev.MaxQuantity; + } + else + { + bev.Quantity += this.Quantity; + this.Quantity = 0; + } + + from.PlaySound(0x4E); + } + } + else if (from == targ) + { + if (from.Thirst < 20) + from.Thirst += ComputeFillFactor(); // Scriptiz : ajout du FillFactor (anciennement : 1) + + if (ContainsAlchohol) + { + int bac = 0; + + switch (this.Content) + { + case BeverageType.Ale: bac = 1; break; + case BeverageType.Wine: bac = 2; break; + case BeverageType.Cider: bac = 3; break; + case BeverageType.Liquor: bac = 4; break; + + // Scriptiz : Breuvages alcolis�s de Vivre + case BeverageType.BiereCommune: + case BeverageType.BiereAmbre: + case BeverageType.BiereMiel: + case BeverageType.BiereBrune: + case BeverageType.BiereEpice: + case BeverageType.MoinetteYew: + case BeverageType.BiereSorciere: bac = 1; break; + case BeverageType.Kwak: bac = 2; break; + } + + from.BAC += bac; + + if (from.BAC > 60) + from.BAC = 60; + + CheckHeaveTimer(from); + } + + from.PlaySound(Utility.RandomList(0x30, 0x2D6)); + + if (m_Poison != null) + from.ApplyPoison(m_Poisoner, m_Poison); + + --Quantity; + } + else if (targ is BaseWaterContainer && !(targ is Bucket)) + { + BaseWaterContainer bwc = targ as BaseWaterContainer; + + if (Content != BeverageType.Water) + { + from.SendLocalizedMessage(500842); // Can't pour that in there. + } + else if (bwc.Items.Count != 0) + { + from.SendLocalizedMessage(500841); // That has something in it. + } + else + { + int itNeeds = Math.Min((bwc.MaxQuantity - bwc.Quantity), Quantity); + + if (itNeeds > 0) + { + bwc.Quantity += itNeeds; + Quantity -= itNeeds; + + from.PlaySound(0x4E); + } + } + } + else if (targ is PlantItem) + { + ((PlantItem)targ).Pour(from, this); + } + else if (targ is AddonComponent && + (((AddonComponent)targ).Addon is WaterVatEast || ((AddonComponent)targ).Addon is WaterVatSouth) && + this.Content == BeverageType.Water) + { + PlayerMobile player = from as PlayerMobile; + + if (player != null) + { + SolenMatriarchQuest qs = player.Quest as SolenMatriarchQuest; + + if (qs != null) + { + QuestObjective obj = qs.FindObjective(typeof(GatherWaterObjective)); + + if (obj != null && !obj.Completed) + { + BaseAddon vat = ((AddonComponent)targ).Addon; + + if (vat.X > 5784 && vat.X < 5814 && vat.Y > 1903 && vat.Y < 1934 && + ((qs.RedSolen && vat.Map == Map.Trammel) || (!qs.RedSolen && vat.Map == Map.Felucca))) + { + if (obj.CurProgress + Quantity > obj.MaxProgress) + { + int delta = obj.MaxProgress - obj.CurProgress; + + Quantity -= delta; + obj.CurProgress = obj.MaxProgress; + } + else + { + obj.CurProgress += Quantity; + Quantity = 0; + } + } + } + } + } + } + else + { + from.SendMessage("Vous ne pouvez verser ici"); // Can't pour it there. + } + } + + public override void OnDoubleClick(Mobile from) + { + if (IsEmpty) + { + if (!Fillable || !ValidateUse(from, true)) + return; + + from.BeginTarget(-1, true, TargetFlags.None, new TargetCallback(Fill_OnTarget)); + SendLocalizedMessageTo(from, 500837); // Fill from what? + } + else if (Pourable && ValidateUse(from, true)) + { + from.BeginTarget(-1, true, TargetFlags.None, new TargetCallback(Pour_OnTarget)); + from.SendMessage("Sur quoi voulez-vous l'utiliser?"); // What do you want to use this on? + } + } + + public static bool ConsumeTotal(Container pack, BeverageType content, int quantity) + { + return ConsumeTotal(pack, typeof(BaseBeverage), content, quantity); + } + + public static bool ConsumeTotal(Container pack, Type itemType, BeverageType content, int quantity) + { + Item[] items = pack.FindItemsByType(itemType); + + // First pass, compute total + int total = 0; + + for (int i = 0; i < items.Length; ++i) + { + BaseBeverage bev = items[i] as BaseBeverage; + + if (bev != null && bev.Content == content && !bev.IsEmpty) + total += bev.Quantity; + } + + if (total >= quantity) + { + // We've enough, so consume it + + int need = quantity; + + for (int i = 0; i < items.Length; ++i) + { + BaseBeverage bev = items[i] as BaseBeverage; + + if (bev == null || bev.Content != content || bev.IsEmpty) + continue; + + int theirQuantity = bev.Quantity; + + if (theirQuantity < need) + { + bev.Quantity = 0; + need -= theirQuantity; + } + else + { + bev.Quantity -= need; + return true; + } + } + } + + return false; + } + + public BaseBeverage() + { + ItemID = ComputeItemID(); + } + + public BaseBeverage(BeverageType type) + { + m_Content = type; + m_Quantity = MaxQuantity; + ItemID = ComputeItemID(); + } + + public BaseBeverage(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write((Mobile)m_Poisoner); + + Poison.Serialize(m_Poison, writer); + writer.Write((int)m_Content); + writer.Write((int)m_Quantity); + } + + protected bool CheckType(string name) + { + return (World.LoadingType == String.Format("Server.Items.{0}", name)); + } + + public override void Deserialize(GenericReader reader) + { + InternalDeserialize(reader, true); + } + + protected void InternalDeserialize(GenericReader reader, bool read) + { + base.Deserialize(reader); + + if (!read) + return; + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Poisoner = reader.ReadMobile(); + goto case 0; + } + case 0: + { + m_Poison = Poison.Deserialize(reader); + m_Content = (BeverageType)reader.ReadInt(); + m_Quantity = reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/BeverageEmpty.cs b/Scripts/Items/Food/BeverageEmpty.cs new file mode 100644 index 0000000..fcf6065 --- /dev/null +++ b/Scripts/Items/Food/BeverageEmpty.cs @@ -0,0 +1,59 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute( 0x1f81, 0x1f82, 0x1f83, 0x1f84 )] + public class Glass : Item + { + [Constructable] + public Glass() : base( 0x1f81 ) + { + this.Weight = 0.1; + } + + public Glass( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GlassBottle : Item + { + [Constructable] + public GlassBottle() : base( 0xe2b ) + { + this.Weight = 0.3; + } + + public GlassBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Food/Bowls.cs b/Scripts/Items/Food/Bowls.cs new file mode 100644 index 0000000..6f9db14 --- /dev/null +++ b/Scripts/Items/Food/Bowls.cs @@ -0,0 +1,547 @@ +using System; + +namespace Server.Items +{ + public class EmptyWoodenBowl : Item + { + [Constructable] + public EmptyWoodenBowl() : base( 0x15F8 ) + { + Name = "Bol de bois"; + Weight = 1.0; + } + + public EmptyWoodenBowl( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EmptyPewterBowl : Item + { + [Constructable] + public EmptyPewterBowl() : base( 0x15FD ) + { + Name = "Bol d'�tain"; + Weight = 1.0; + } + + public EmptyPewterBowl( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodenBowlOfCarrots : Food + { + [Constructable] + public WoodenBowlOfCarrots() : base( 0x15F9 ) + { + Name = "Bol de carottes"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyWoodenBowl() ); + return true; + } + + public WoodenBowlOfCarrots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodenBowlOfCorn : Food + { + [Constructable] + public WoodenBowlOfCorn() : base( 0x15FA ) + { + Name = "Bol de ma�s"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyWoodenBowl() ); + return true; + } + + public WoodenBowlOfCorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodenBowlOfLettuce : Food + { + [Constructable] + public WoodenBowlOfLettuce() : base( 0x15FB ) + { + Name = "Bol de salade"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyWoodenBowl() ); + return true; + } + + public WoodenBowlOfLettuce( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodenBowlOfPeas : Food + { + [Constructable] + public WoodenBowlOfPeas() : base( 0x15FC ) + { + Name = "Bol de pois"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyWoodenBowl() ); + return true; + } + + public WoodenBowlOfPeas( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PewterBowlOfCarrots : Food + { + [Constructable] + public PewterBowlOfCarrots() : base( 0x15FE ) + { + Name = "Bol de carottes"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyPewterBowl() ); + return true; + } + + public PewterBowlOfCarrots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PewterBowlOfCorn : Food + { + [Constructable] + public PewterBowlOfCorn() : base( 0x15FF ) + { + Name = "Bol de ma�s"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyPewterBowl() ); + return true; + } + + public PewterBowlOfCorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PewterBowlOfLettuce : Food + { + [Constructable] + public PewterBowlOfLettuce() : base( 0x1600 ) + { + Name = "Bol de salade"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyPewterBowl() ); + return true; + } + + public PewterBowlOfLettuce( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PewterBowlOfPeas : Food + { + [Constructable] + public PewterBowlOfPeas() : base( 0x1601 ) + { + Name = "Bol de pois"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyPewterBowl() ); + return true; + } + + public PewterBowlOfPeas( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PewterBowlOfPotatos : Food + { + [Constructable] + public PewterBowlOfPotatos() : base( 0x1602 ) + { + Name = "Bol de pommes de terre"; + Stackable = false; + Weight = 1.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyPewterBowl() ); + return true; + } + + public PewterBowlOfPotatos( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [TypeAlias( "Server.Items.EmptyLargeWoodenBowl" )] + public class EmptyWoodenTub : Item + { + [Constructable] + public EmptyWoodenTub() : base( 0x1605 ) + { + Name = "Grand bol de bois"; + Weight = 2.0; + } + + public EmptyWoodenTub( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [TypeAlias( "Server.Items.EmptyLargePewterBowl" )] + public class EmptyPewterTub : Item + { + [Constructable] + public EmptyPewterTub() : base( 0x1603 ) + { + Name = "Grand bol d'�tain"; + Weight = 2.0; + } + + public EmptyPewterTub( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodenBowlOfStew : Food + { + [Constructable] + public WoodenBowlOfStew() : base( 0x1604 ) + { + Name = "Grand bol de rago�t"; + Stackable = false; + Weight = 2.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyWoodenTub() ); + return true; + } + + public WoodenBowlOfStew( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodenBowlOfTomatoSoup : Food + { + [Constructable] + public WoodenBowlOfTomatoSoup() : base( 0x1606 ) + { + Name = "Grand bol de soupe aux tomates"; + Stackable = false; + Weight = 2.0; + FillFactor = 2; + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new EmptyWoodenTub() ); + return true; + } + + public WoodenBowlOfTomatoSoup( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/Chocolatiering.cs b/Scripts/Items/Food/Chocolatiering.cs new file mode 100644 index 0000000..555eb32 --- /dev/null +++ b/Scripts/Items/Food/Chocolatiering.cs @@ -0,0 +1,291 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CocoaLiquor : Item + { + public override int LabelNumber { get { return 1080007; } } // Cocoa liquor + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public CocoaLiquor() + : base( 0x103F ) + { + Hue = 0x46A; + } + + public CocoaLiquor( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SackOfSugar : Item + { + public override int LabelNumber { get { return 1080003; } } // Sack of sugar + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public SackOfSugar() + : this( 1 ) + { + } + + [Constructable] + public SackOfSugar( int amount ) + : base( 0x1039 ) + { + Hue = 0x461; + Stackable = true; + Amount = amount; + } + + public SackOfSugar( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CocoaButter : Item + { + public override int LabelNumber { get { return 1080005; } } // Cocoa butter + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public CocoaButter() + : base( 0x1044 ) + { + Hue = 0x457; + } + + public CocoaButter( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Vanilla : Item + { + public override int LabelNumber { get { return 1080009; } } // Vanilla + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public Vanilla() + : this( 1 ) + { + } + + [Constructable] + public Vanilla( int amount ) + : base( 0xE2A ) + { + Hue = 0x462; + Stackable = true; + Amount = amount; + } + + public Vanilla( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CocoaPulp : Item + { + public override int LabelNumber { get { return 1080530; } } // cocoa pulp + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public CocoaPulp() + : this( 1 ) + { + } + + [Constructable] + public CocoaPulp( int amount ) + : base( 0xF7C ) + { + Hue = 0x219; + Stackable = true; + Amount = amount; + } + + public CocoaPulp( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkChocolate : BaseCandyCane + { + public override int LabelNumber { get { return 1079994; } } // Dark chocolate + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public DarkChocolate() + : base( 0xF10 ) + { + Name = "Carreau de chocolat noir"; + Hue = 0x465; + LootType = LootType.Regular; + } + + public DarkChocolate( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MilkChocolate : BaseCandyCane + { + public override int LabelNumber { get { return 1079995; } } // Milk chocolate + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public MilkChocolate() + : base( 0xF18 ) + { + Name = "Carreau de chocolat au lait"; + Hue = 0x461; + LootType = LootType.Regular; + } + + public MilkChocolate( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WhiteChocolate : BaseCandyCane + { + public override int LabelNumber { get { return 1079996; } } // White chocolate + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public WhiteChocolate() + : base( 0xF11 ) + { + Name = "Carreau de chocolat blanc"; + Hue = 0x47E; + LootType = LootType.Regular; + } + + public WhiteChocolate( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/CookableFood.cs b/Scripts/Items/Food/CookableFood.cs new file mode 100644 index 0000000..a546d33 --- /dev/null +++ b/Scripts/Items/Food/CookableFood.cs @@ -0,0 +1,954 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public abstract class CookableFood : Item + { + private int m_CookingLevel; + + [CommandProperty( AccessLevel.GameMaster )] + public int CookingLevel + { + get + { + return m_CookingLevel; + } + set + { + m_CookingLevel = value; + } + } + + public CookableFood( int itemID, int cookingLevel ) : base( itemID ) + { + m_CookingLevel = cookingLevel; + } + + public CookableFood( Serial serial ) : base( serial ) + { + } + + public abstract Food Cook(); + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + // Version 1 + writer.Write( (int) m_CookingLevel ); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_CookingLevel = reader.ReadInt(); + + break; + } + } + } + +#if false + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.Target = new InternalTarget( this ); + } +#endif + + public static bool IsHeatSource( object targeted ) + { + int itemID; + + if ( targeted is Item ) + itemID = ((Item)targeted).ItemID; + else if ( targeted is StaticTarget ) + itemID = ((StaticTarget)targeted).ItemID; + else + return false; + + if ( itemID >= 0xDE3 && itemID <= 0xDE9 ) + return true; // Campfire + else if ( itemID >= 0x461 && itemID <= 0x48E ) + return true; // Sandstone oven/fireplace + else if ( itemID >= 0x92B && itemID <= 0x96C ) + return true; // Stone oven/fireplace + else if ( itemID == 0xFAC ) + return true; // Firepit + else if ( itemID >= 0x184A && itemID <= 0x184C ) + return true; // Heating stand (left) + else if ( itemID >= 0x184E && itemID <= 0x1850 ) + return true; // Heating stand (right) + else if ( itemID >= 0x398C && itemID <= 0x399F ) + return true; // Fire field + + return false; + } + + private class InternalTarget : Target + { + private CookableFood m_Item; + + public InternalTarget( CookableFood item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) return; + + if ( CookableFood.IsHeatSource( targeted ) ) + { + if ( from.BeginAction( typeof( CookableFood ) ) ) + { + from.PlaySound( 0x225 ); + + m_Item.Consume(); + + InternalTimer t = new InternalTimer( from, targeted as IPoint3D, from.Map, m_Item ); + t.Start(); + } + else + { + from.SendMessage( "Vous devez attendre avant de faire cuire � nouveau" ); // You must wait to perform another action + } + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private IPoint3D m_Point; + private Map m_Map; + private CookableFood m_CookableFood; + + public InternalTimer( Mobile from, IPoint3D p, Map map, CookableFood cookableFood ) : base( TimeSpan.FromSeconds( 5.0 ) ) + { + m_From = from; + m_Point = p; + m_Map = map; + m_CookableFood = cookableFood; + } + + protected override void OnTick() + { + m_From.EndAction( typeof( CookableFood ) ); + + if ( m_From.Map != m_Map || (m_Point != null && m_From.GetDistanceToSqrt( m_Point ) > 3) ) + { + m_From.SendMessage("Vous avez calcin� votre nourriture!"); // You burn the food to a crisp! It's ruined. + return; + } + + if ( m_From.CheckSkill( SkillName.Cooking, m_CookableFood.CookingLevel, 100 ) ) + { + Food cookedFood = m_CookableFood.Cook(); + + if ( m_From.AddToBackpack( cookedFood ) ) + m_From.PlaySound( 0x57 ); + } + else + { + m_From.SendMessage( "Vous avez calcin� votre nourriture!" ); // You burn the food to a crisp! It's ruined. + } + } + } + } + } + + // ********** RawRibs ********** + public class RawRibs : CookableFood + { + [Constructable] + public RawRibs() : this( 1 ) + { + } + + [Constructable] + public RawRibs( int amount ) : base( 0x9F1, 10 ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} C�telettes crues", Amount); + else + list.Add("{0} Cotelette crue", Amount); + } + + public RawRibs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new Ribs(); + } + } + + + // ********** RawLambLeg ********** + public class RawLambLeg : CookableFood + { + [Constructable] + public RawLambLeg() : this( 1 ) + { + } + + [Constructable] + public RawLambLeg( int amount ) : base( 0x1609, 10 ) + { + Stackable = true; + Amount = amount; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} Gigots d'agneau crus", Amount); + else + list.Add("{0} Gigot d'agneau cru", Amount); + } + + public RawLambLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 1 ) + Weight = -1; + } + + public override Food Cook() + { + return new LambLeg(); + } + } + + // ********** RawChickenLeg ********** + public class RawChickenLeg : CookableFood + { + [Constructable] + public RawChickenLeg() : base( 0x1607, 10 ) + { + Weight = 1.0; + Stackable = true; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} Cuisses de poulet crues", Amount); + else + list.Add("{0} Cuisse de poulet crue", Amount); + } + + public RawChickenLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new ChickenLeg(); + } + } + + + // ********** RawBird ********** + public class RawBird : CookableFood + { + [Constructable] + public RawBird() : this( 1 ) + { + } + + [Constructable] + public RawBird( int amount ) : base( 0x9B9, 10 ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} Oiseaux crus", Amount); + else + list.Add("{0} Oiseau cru", Amount); + } + + public RawBird( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new CookedBird(); + } + } + + + // ********** UnbakedPeachCobbler ********** + public class UnbakedPeachCobbler : CookableFood + { + public override int LabelNumber{ get{ return 1041335; } } // unbaked peach cobbler + + [Constructable] + public UnbakedPeachCobbler() : base( 0x1042, 25 ) + { + Name = "Tourte aux p�ches crue"; + Weight = 1.0; + } + + public UnbakedPeachCobbler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + public override Food Cook() + { + return new PeachCobbler(); + } + } + + // ********** UnbakedFruitPie ********** + public class UnbakedFruitPie : CookableFood + { + public override int LabelNumber{ get{ return 1041334; } } // unbaked fruit pie + + [Constructable] + public UnbakedFruitPie() : base( 0x1042, 25 ) + { + Name = "Tarte aux fruits crue"; + Weight = 1.0; + } + + public UnbakedFruitPie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new FruitPie(); + } + } + + // ********** UnbakedMeatPie ********** + public class UnbakedMeatPie : CookableFood + { + public override int LabelNumber{ get{ return 1041338; } } // unbaked meat pie + + [Constructable] + public UnbakedMeatPie() : base( 0x1042, 25 ) + { + Name = "Tourte crue"; + Weight = 1.0; + } + + public UnbakedMeatPie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new MeatPie(); + } + } + + // ********** UnbakedPumpkinPie ********** + public class UnbakedPumpkinPie : CookableFood + { + public override int LabelNumber{ get{ return 1041342; } } // unbaked pumpkin pie + + [Constructable] + public UnbakedPumpkinPie() : base( 0x1042, 25 ) + { + Name = "Tarte � la citrouille crue"; + Weight = 1.0; + } + + public UnbakedPumpkinPie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new PumpkinPie(); + } + } + + // ********** UnbakedApplePie ********** + public class UnbakedApplePie : CookableFood + { + public override int LabelNumber{ get{ return 1041336; } } // unbaked apple pie + + [Constructable] + public UnbakedApplePie() : base( 0x1042, 25 ) + { + Name = "Tarte aux pommes crue"; + Weight = 1.0; + } + + public UnbakedApplePie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new ApplePie(); + } + } + + // ********** UncookedCheesePizza ********** + [TypeAlias( "Server.Items.UncookedPizza" )] + public class UncookedCheesePizza : CookableFood + { + public override int LabelNumber{ get{ return 1041341; } } // uncooked cheese pizza + + [Constructable] + public UncookedCheesePizza() : base( 0x1083, 20 ) + { + Name = "Pizza au fromage crue"; + Weight = 1.0; + } + + public UncookedCheesePizza( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ItemID == 0x1040 ) + ItemID = 0x1083; + + if ( Hue == 51 ) + Hue = 0; + } + + public override Food Cook() + { + return new CheesePizza(); + } + } + + // ********** UncookedSausagePizza ********** + public class UncookedSausagePizza : CookableFood + { + public override int LabelNumber{ get{ return 1041337; } } // uncooked sausage pizza + + [Constructable] + public UncookedSausagePizza() : base( 0x1083, 20 ) + { + Name = "Pizza aux saucisses crue"; + Weight = 1.0; + } + + public UncookedSausagePizza( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new SausagePizza(); + } + } + +#if false + // ********** UncookedPizza ********** + public class UncookedPizza : CookableFood + { + [Constructable] + public UncookedPizza() : base( 0x1083, 20 ) + { + Name = "Pizza crue"; + Weight = 1.0; + } + + public UncookedPizza( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ItemID == 0x1040 ) + ItemID = 0x1083; + + if ( Hue == 51 ) + Hue = 0; + } + + public override Food Cook() + { + return new Pizza(); + } + } +#endif + + // ********** UnbakedQuiche ********** + public class UnbakedQuiche : CookableFood + { + public override int LabelNumber{ get{ return 1041339; } } // unbaked quiche + + [Constructable] + public UnbakedQuiche() : base( 0x1042, 25 ) + { + Name = "Quiche crue"; + Weight = 1.0; + } + + public UnbakedQuiche( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new Quiche(); + } + } + + // ********** Eggs ********** + public class Eggs : CookableFood + { + [Constructable] + public Eggs() : this( 1 ) + { + } + + [Constructable] + public Eggs( int amount ) : base( 0x9B5, 15 ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} Oeufs crus", Amount); + else + list.Add("{0} Oeuf cru", Amount); + } + + public Eggs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + Stackable = true; + + if ( Weight == 0.5 ) + Weight = 1.0; + } + } + + public override Food Cook() + { + return new FriedEggs(); + } + } + + // ********** BrightlyColoredEggs ********** + public class BrightlyColoredEggs : CookableFood + { + public override string DefaultName + { + get { return "brightly colored eggs"; } + } + + [Constructable] + public BrightlyColoredEggs() : base( 0x9B5, 15 ) + { + Name = "Oeuf color�"; + Weight = 0.5; + Hue = 3 + (Utility.Random( 20 ) * 5); + } + + public BrightlyColoredEggs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new FriedEggs(); + } + } + + // ********** EasterEggs ********** + public class EasterEggs : CookableFood + { + public override int LabelNumber{ get{ return 1016105; } } // Easter Eggs + + [Constructable] + public EasterEggs() : base( 0x9B5, 15 ) + { + Name = "Oeuf de P�ques"; + Weight = 0.5; + Hue = 3 + (Utility.Random( 20 ) * 5); + } + + public EasterEggs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new FriedEggs(); + } + } + + // ********** CookieMix ********** + public class CookieMix : CookableFood + { + [Constructable] + public CookieMix() : base( 0x103F, 20 ) + { + Name = "M�lange � biscuit"; + Weight = 1.0; + } + + public CookieMix( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new Cookies(); + } + } + + // ********** CakeMix ********** + public class CakeMix : CookableFood + { + public override int LabelNumber{ get{ return 1041002; } } // cake mix + + [Constructable] + public CakeMix() : base( 0x103F, 40 ) + { + Name = "M�lange � g�teau"; + Weight = 1.0; + } + + public CakeMix( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override Food Cook() + { + return new Cake(); + } + } + + public class RawFishSteak : CookableFood + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public RawFishSteak() : this( 1 ) + { + } + + [Constructable] + public RawFishSteak( int amount ) : base( 0x097A, 10 ) + { + Stackable = true; + Amount = amount; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} Filets de poisson cru", Amount); + else + list.Add("{0} Filet de poisson cru", Amount); + } + + public RawFishSteak( Serial serial ) : base( serial ) + { + } + + public override Food Cook() + { + return new FishSteak(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Food/Cooking.cs b/Scripts/Items/Food/Cooking.cs new file mode 100644 index 0000000..5a938f9 --- /dev/null +++ b/Scripts/Items/Food/Cooking.cs @@ -0,0 +1,702 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class UtilityItem + { + static public int RandomChoice( int itemID1, int itemID2 ) + { + int iRet = 0; + switch ( Utility.Random( 2 ) ) + { + default: + case 0: iRet = itemID1; break; + case 1: iRet = itemID2; break; + } + return iRet; + } + } + + // ********** Dough ********** + public class Dough : Item + { + [Constructable] + public Dough() : base( 0x103d ) + { + Stackable = Core.ML; + Weight = 1.0; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} P�tes", Amount); + else + list.Add("{0} P�te", Amount); + } + + public Dough( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + +#if false + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.Target = new InternalTarget( this ); + } +#endif + + private class InternalTarget : Target + { + private Dough m_Item; + + public InternalTarget( Dough item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) return; + + if ( targeted is Eggs ) + { + m_Item.Delete(); + + ((Eggs)targeted).Consume(); + + from.AddToBackpack( new UnbakedQuiche() ); + from.AddToBackpack( new Eggshells() ); + } + else if ( targeted is CheeseWheel ) + { + m_Item.Delete(); + + ((CheeseWheel)targeted).Consume(); + + from.AddToBackpack( new CheesePizza() ); + } + else if ( targeted is Sausage ) + { + m_Item.Delete(); + + ((Sausage)targeted).Consume(); + + from.AddToBackpack( new SausagePizza() ); + } + else if ( targeted is Apple ) + { + m_Item.Delete(); + + ((Apple)targeted).Consume(); + + from.AddToBackpack( new UnbakedApplePie() ); + } + + else if ( targeted is Peach ) + { + m_Item.Delete(); + + ((Peach)targeted).Consume(); + + from.AddToBackpack( new UnbakedPeachCobbler() ); + } + } + } + } + + // ********** SweetDough ********** + public class SweetDough : Item + { + public override int LabelNumber{ get{ return 1041340; } } // sweet dough + + [Constructable] + public SweetDough() : base( 0x103d ) + { + Stackable = Core.ML; + Weight = 1.0; + Hue = 150; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} P�tes sucr�es", Amount); + else + list.Add("{0} P�te sucr�e", Amount); + } + + public SweetDough( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 51 ) + Hue = 150; + } + +#if false + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.Target = new InternalTarget( this ); + } +#endif + + private class InternalTarget : Target + { + private SweetDough m_Item; + + public InternalTarget( SweetDough item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) return; + + if ( targeted is BowlFlour ) + { + m_Item.Delete(); + ((BowlFlour)targeted).Delete(); + + from.AddToBackpack( new CakeMix() ); + } + else if ( targeted is Campfire ) + { + from.PlaySound( 0x225 ); + m_Item.Delete(); + InternalTimer t = new InternalTimer( from, (Campfire)targeted ); + t.Start(); + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private Campfire m_Campfire; + + public InternalTimer( Mobile from, Campfire campfire ) : base( TimeSpan.FromSeconds( 5.0 ) ) + { + m_From = from; + m_Campfire = campfire; + } + + protected override void OnTick() + { + if ( m_From.GetDistanceToSqrt( m_Campfire ) > 3 ) + { + m_From.SendMessage("Vous avez calcin� votre nourriture!"); // You burn the food to a crisp! It's ruined. + return; + } + + if ( m_From.CheckSkill( SkillName.Cooking, 0, 10 ) ) + { + if ( m_From.AddToBackpack( new Muffins() ) ) + m_From.PlaySound( 0x57 ); + } + else + { + m_From.SendMessage("Vous avez calcin� votre nourriture!"); // You burn the food to a crisp! It's ruined. + } + } + } + } + } + + // ********** JarHoney ********** + public class JarHoney : Item + { + [Constructable] + public JarHoney() : base( 0x9ec ) + { + Weight = 1.0; + Stackable = true; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} pot de miel", Amount); + else + list.Add("{0} pots de miel", Amount); + } + + public JarHoney( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + Stackable = true; + } + + /*public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.Target = new InternalTarget( this ); + }*/ + + private class InternalTarget : Target + { + private JarHoney m_Item; + + public InternalTarget( JarHoney item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) return; + + if ( targeted is Dough ) + { + m_Item.Delete(); + ((Dough)targeted).Consume(); + + from.AddToBackpack( new SweetDough() ); + } + + if (targeted is BowlFlour) + { + m_Item.Consume(); + ((BowlFlour)targeted).Delete(); + + from.AddToBackpack( new CookieMix() ); + } + } + } + } + + // ********** BowlFlour ********** + public class BowlFlour : Item + { + [Constructable] + public BowlFlour() : base( 0xa1e ) + { + Name = "Bol de farine"; + Weight = 1.0; + } + + public BowlFlour( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // ********** WoodenBowl ********** + public class WoodenBowl : Item + { + [Constructable] + public WoodenBowl() : base( 0x15f8 ) + { + Name = "Bol de bois"; + Weight = 1.0; + } + + public WoodenBowl( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + // ********** PitcherWater ********** + /*public class PitcherWater : Item + { + [Constructable] + public PitcherWater() : base(Utility.Random( 0x1f9d, 2 )) + { + Weight = 1.0; + } + + public PitcherWater( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private PitcherWater m_Item; + + public InternalTarget( PitcherWater item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) return; + + if ( targeted is BowlFlour ) + { + m_Item.Delete(); + ((BowlFlour)targeted).Delete(); + + from.AddToBackpack( new Dough() ); + from.AddToBackpack( new WoodenBowl() ); + } + } + } + }*/ + + // ********** SackFlour ********** + [TypeAlias( "Server.Items.SackFlourOpen" )] + public class SackFlour : Item, IHasQuantity + { + private int m_Quantity; + + [CommandProperty( AccessLevel.GameMaster )] + public int Quantity + { + get{ return m_Quantity; } + set + { + if ( value < 0 ) + value = 0; + else if ( value > 20 ) + value = 20; + + m_Quantity = value; + + if ( m_Quantity == 0 ) + Delete(); + else if ( m_Quantity < 20 && (ItemID == 0x1039 || ItemID == 0x1045) ) + ++ItemID; + } + } + + [Constructable] + public SackFlour() : base( 0x1039 ) + { + Name = "Sac de farine"; + Weight = 5.0; + m_Quantity = 20; + } + + public SackFlour( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (int) m_Quantity ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + case 1: + { + m_Quantity = reader.ReadInt(); + break; + } + case 0: + { + m_Quantity = 20; + break; + } + } + + if ( version < 2 && Weight == 1.0 ) + Weight = 5.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + if ( (ItemID == 0x1039 || ItemID == 0x1045) ) + ++ItemID; + +#if false + this.Delete(); + + from.AddToBackpack( new SackFlourOpen() ); +#endif + } + + } + +#if false + // ********** SackFlourOpen ********** + public class SackFlourOpen : Item + { + public override int LabelNumber{ get{ return 1024166; } } // open sack of flour + + [Constructable] + public SackFlourOpen() : base(UtilityItem.RandomChoice( 0x1046, 0x103a )) + { + Weight = 1.0; + } + + public SackFlourOpen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private SackFlourOpen m_Item; + + public InternalTarget( SackFlourOpen item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) return; + + if ( targeted is WoodenBowl ) + { + m_Item.Delete(); + ((WoodenBowl)targeted).Delete(); + + from.AddToBackpack( new BowlFlour() ); + } + else if ( targeted is TribalBerry ) + { + if ( from.Skills[SkillName.Cooking].Base >= 80.0 ) + { + m_Item.Delete(); + ((TribalBerry)targeted).Delete(); + + from.AddToBackpack( new TribalPaint() ); + + from.SendLocalizedMessage( 1042002 ); // You combine the berry and the flour into the tribal paint worn by the savages. + } + else + { + from.SendLocalizedMessage( 1042003 ); // You don't have the cooking skill to create the body paint. + } + } + } + } + } +#endif + + // ********** Eggshells ********** + public class Eggshells : Item + { + [Constructable] + public Eggshells() : base( 0x9b4 ) + { + Name = "Coquille d'oeuf"; + Weight = 0.5; + } + + public Eggshells( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WheatSheaf : Item + { + [Constructable] + public WheatSheaf() : this( 1 ) + { + } + + [Constructable] + public WheatSheaf( int amount ) : base( 7869 ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add("{0} Gerbes de bl�", Amount); + else + list.Add("{0} Gerbe de bl�", Amount); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + from.BeginTarget( 4, false, TargetFlags.None, new TargetCallback( OnTarget ) ); + } + + public virtual void OnTarget( Mobile from, object obj ) + { + if ( obj is AddonComponent ) + obj = (obj as AddonComponent).Addon; + + IFlourMill mill = obj as IFlourMill; + + if ( mill != null ) + { + int needs = mill.MaxFlour - mill.CurFlour; + + if ( needs > this.Amount ) + needs = this.Amount; + + mill.CurFlour += needs; + Consume( needs ); + } + } + + public WheatSheaf( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/Food.cs b/Scripts/Items/Food/Food.cs new file mode 100644 index 0000000..80a1be5 --- /dev/null +++ b/Scripts/Items/Food/Food.cs @@ -0,0 +1,1361 @@ +using System; +using System.Collections; +using Server.Network; +using System.Collections.Generic; +using Server.ContextMenus; + +namespace Server.Items +{ + public abstract class Food : Item + { + private Mobile m_Poisoner; + private Poison m_Poison; + private int m_FillFactor; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Poisoner + { + get { return m_Poisoner; } + set { m_Poisoner = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get { return m_Poison; } + set { m_Poison = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int FillFactor + { + get { return m_FillFactor; } + set { m_FillFactor = value; } + } + + public Food( int itemID ) : this( 1, itemID ) + { + } + + public Food( int amount, int itemID ) : base( itemID ) + { + Stackable = true; + Amount = amount; + m_FillFactor = 1; + } + + public Food( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + { + if (Name == "Chou") + list.Add("{0} {1}x", Amount, Name); + else if (Name == "R�gime de bananes") + list.Add("{0} R�gimes de bananes", Amount); + else if (Name == "Noix de coco") + list.Add("{0} {1}", Amount, Name); + else if (Name == "Grappe de raisins") + list.Add("{0} Grappes de raisins", Amount); + else if (Name == "Miche de pain") + list.Add("{0} Miches de pain", Amount); + else if (Name == "Filet de poisson") + list.Add("{0} Filets de poisson", Amount); + else if (Name == "�pi de ma�s") + list.Add("{0} �pis de ma�s", Amount); + else if (Name == "Gerbe de bl�") + list.Add("{0} Gerbes de bl�", Amount); + else if (Name == "Tranche de fromage") + list.Add("{0} Tranches de fromage", Amount); + else if (Name == "Gigot d'agneau") + list.Add("{0} Gigots d'agneau", Amount); + else if (Name == "Cuisse de poulet") + list.Add("{0} Cuisses de poulet", Amount); + else if ( Name == "Plateau de sushis") + list.Add("{0} Plateaux de sushis", Amount); + else + list.Add("{0} {1}s", Amount, Name); + } + else + list.Add("{0} {1}", Amount, Name); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + list.Add( new ContextMenus.EatEntry( from, this ) ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + Eat( from ); + } + } + + public virtual bool Eat( Mobile from ) + { + // Fill the Mobile with FillFactor + if (CheckHunger(from)) + { + // Play a random "eat" sound + from.PlaySound( Utility.Random( 0x3A, 3 ) ); + + if ( from.Body.IsHuman && !from.Mounted ) + from.Animate( 34, 5, 1, true, false, 0 ); + + if ( m_Poison != null ) + from.ApplyPoison( m_Poisoner, m_Poison ); + + Consume(); + + return true; + } + + return false; + } + + public virtual bool CheckHunger(Mobile from) + { + return FillHunger(from, m_FillFactor); + } + + public static bool FillHunger(Mobile from, int fillFactor) + { + if (from.Hunger >= 20) + { + from.SendLocalizedMessage(500867); // You are simply too full to eat any more! + return false; + } + + int iHunger = from.Hunger + fillFactor; + + if (from.Stam < from.StamMax) + from.Stam += Utility.Random(6, 3) + fillFactor / 5; + + if ( iHunger >= 20 ) + { + from.Hunger = 20; + from.SendLocalizedMessage( 500872 ); // You manage to eat the food, but you are stuffed! + } + else + { + from.Hunger = iHunger; + + if ( iHunger < 5 ) + from.SendLocalizedMessage( 500868 ); // You eat the food, but are still extremely hungry. + else if ( iHunger < 10 ) + from.SendLocalizedMessage( 500869 ); // You eat the food, and begin to feel more satiated. + else if ( iHunger < 15 ) + from.SendLocalizedMessage( 500870 ); // After eating the food, you feel much less hungry. + else + from.SendLocalizedMessage( 500871 ); // You feel quite full after consuming the food. + } + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 4 ); // version + + writer.Write( m_Poisoner ); + + Poison.Serialize( m_Poison, writer ); + writer.Write( m_FillFactor ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + switch ( reader.ReadInt() ) + { + case 0: m_Poison = null; break; + case 1: m_Poison = Poison.Lesser; break; + case 2: m_Poison = Poison.Regular; break; + case 3: m_Poison = Poison.Greater; break; + case 4: m_Poison = Poison.Deadly; break; + } + + break; + } + case 2: + { + m_Poison = Poison.Deserialize( reader ); + break; + } + case 3: + { + m_Poison = Poison.Deserialize( reader ); + m_FillFactor = reader.ReadInt(); + break; + } + case 4: + { + m_Poisoner = reader.ReadMobile(); + goto case 3; + } + } + } + } + + public class BreadLoaf : Food + { + [Constructable] + public BreadLoaf() : this( 1 ) + { + } + + [Constructable] + public BreadLoaf( int amount ) : base( amount, 0x103B ) + { + this.Name = "Miche de pain"; + this.Weight = 1.0; + this.FillFactor = 3; + } + + public BreadLoaf( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Bacon : Food + { + [Constructable] + public Bacon() : this( 1 ) + { + } + + [Constructable] + public Bacon( int amount ) : base( amount, 0x979 ) + { + this.Name = "Bacon"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Bacon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SlabOfBacon : Food + { + [Constructable] + public SlabOfBacon() : this( 1 ) + { + } + + [Constructable] + public SlabOfBacon( int amount ) : base( amount, 0x976 ) + { + this.Name = "Bacon"; + this.Weight = 1.0; + this.FillFactor = 3; + } + + public SlabOfBacon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FishSteak : Food + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public FishSteak() : this( 1 ) + { + } + + [Constructable] + public FishSteak( int amount ) : base( amount, 0x97B ) + { + this.Name = "Filet de poisson"; + this.FillFactor = 3; + } + + public FishSteak( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CheeseWheel : Food + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public CheeseWheel() : this( 1 ) + { + } + + [Constructable] + public CheeseWheel( int amount ) : base( amount, 0x97E ) + { + this.Name = "Fromage"; + this.FillFactor = 3; + } + + public CheeseWheel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CheeseWedge : Food + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public CheeseWedge() : this( 1 ) + { + } + + [Constructable] + public CheeseWedge( int amount ) : base( amount, 0x97D ) + { + this.Name = "Fromage"; + this.FillFactor = 3; + } + + public CheeseWedge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CheeseSlice : Food + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public CheeseSlice() : this( 1 ) + { + } + + [Constructable] + public CheeseSlice( int amount ) : base( amount, 0x97C ) + { + this.Name = "Tranche de fromage"; + this.FillFactor = 1; + } + + public CheeseSlice( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FrenchBread : Food + { + [Constructable] + public FrenchBread() : this( 1 ) + { + } + + [Constructable] + public FrenchBread( int amount ) : base( amount, 0x98C ) + { + this.Name = "Baguette"; + this.Weight = 2.0; + this.FillFactor = 3; + } + + public FrenchBread( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class FriedEggs : Food + { + [Constructable] + public FriedEggs() : this( 1 ) + { + } + + [Constructable] + public FriedEggs( int amount ) : base( amount, 0x9B6 ) + { + this.Name = "Oeuf"; + this.Weight = 1.0; + this.FillFactor = 4; + } + + public FriedEggs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CookedBird : Food + { + [Constructable] + public CookedBird() : this( 1 ) + { + } + + [Constructable] + public CookedBird( int amount ) : base( amount, 0x9B7 ) + { + this.Name = "Poulet"; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public CookedBird( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RoastPig : Food + { + [Constructable] + public RoastPig() : this( 1 ) + { + } + + [Constructable] + public RoastPig( int amount ) : base( amount, 0x9BB ) + { + this.Name = "M�choui"; + this.Weight = 45.0; + this.FillFactor = 20; + } + + public RoastPig( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Sausage : Food + { + [Constructable] + public Sausage() : this( 1 ) + { + } + + [Constructable] + public Sausage( int amount ) : base( amount, 0x9C0 ) + { + this.Name = "Saucisse"; + this.Weight = 1.0; + this.FillFactor = 4; + } + + public Sausage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Ham : Food + { + [Constructable] + public Ham() : this( 1 ) + { + } + + [Constructable] + public Ham( int amount ) : base( amount, 0x9C9 ) + { + this.Name = "Jambon"; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public Ham( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Cake : Food + { + [Constructable] + public Cake() : base( 0x9E9 ) + { + this.Name = "G�teau"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 10; + } + + public Cake( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Ribs : Food + { + [Constructable] + public Ribs() : this( 1 ) + { + } + + [Constructable] + public Ribs( int amount ) : base( amount, 0x9F2 ) + { + this.Name = "C�telette"; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public Ribs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Cookies : Food + { + [Constructable] + public Cookies() : base( 0x160b ) + { + this.Name = "Biscuit"; + Stackable = Core.ML; + this.Weight = 1.0; + this.FillFactor = 4; + } + + public Cookies( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Muffins : Food + { + [Constructable] + public Muffins() : base( 0x9eb ) + { + this.Name = "Muffins"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 4; + } + + public Muffins( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [TypeAlias( "Server.Items.Pizza" )] + public class CheesePizza : Food + { + //public override int LabelNumber{ get{ return 1044516; } } // cheese pizza + + [Constructable] + public CheesePizza() : base( 0x1040 ) + { + this.Name = "Pizza au fromage"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 6; + } + + public CheesePizza( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SausagePizza : Food + { + //public override int LabelNumber{ get{ return 1044517; } } // sausage pizza + + [Constructable] + public SausagePizza() : base( 0x1040 ) + { + this.Name = "Pizza aux saucisses"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 6; + } + + public SausagePizza( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +#if false + public class Pizza : Food + { + [Constructable] + public Pizza() : base( 0x1040 ) + { + this.Name = "Pizza"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 6; + } + + public Pizza( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +#endif + + public class FruitPie : Food + { + //public override int LabelNumber{ get{ return 1041346; } } // baked fruit pie + + [Constructable] + public FruitPie() : base( 0x1041 ) + { + this.Name = "Tarte aux fruits"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public FruitPie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MeatPie : Food + { + //public override int LabelNumber{ get{ return 1041347; } } // baked meat pie + + [Constructable] + public MeatPie() : base( 0x1041 ) + { + this.Name = "Tourte"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public MeatPie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PumpkinPie : Food + { + //public override int LabelNumber{ get{ return 1041348; } } // baked pumpkin pie + + [Constructable] + public PumpkinPie() : base( 0x1041 ) + { + this.Name = "Tarte � la citrouille"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public PumpkinPie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ApplePie : Food + { + //public override int LabelNumber{ get{ return 1041343; } } // baked apple pie + + [Constructable] + public ApplePie() : base( 0x1041 ) + { + this.Name = "Tarte aux pommes"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public ApplePie( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PeachCobbler : Food + { + //public override int LabelNumber{ get{ return 1041344; } } // baked peach cobbler + + [Constructable] + public PeachCobbler() : base( 0x1041 ) + { + this.Name = "Tourte aux p�ches"; + Stackable = false; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public PeachCobbler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Quiche : Food + { + //public override int LabelNumber{ get{ return 1041345; } } // baked quiche + + [Constructable] + public Quiche() : base( 0x1041 ) + { + this.Name = "Quiche"; + Stackable = Core.ML; + this.Weight = 1.0; + this.FillFactor = 5; + } + + public Quiche( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LambLeg : Food + { + [Constructable] + public LambLeg() : this( 1 ) + { + } + + [Constructable] + public LambLeg( int amount ) : base( amount, 0x160a ) + { + this.Name = "Gigot d'agneau"; + this.Weight = 2.0; + this.FillFactor = 5; + } + + public LambLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ChickenLeg : Food + { + [Constructable] + public ChickenLeg() : this( 1 ) + { + } + + [Constructable] + public ChickenLeg( int amount ) : base( amount, 0x1608 ) + { + this.Name = "Cuisse de poulet"; + this.Weight = 1.0; + this.FillFactor = 4; + } + + public ChickenLeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC74, 0xC75 )] + public class HoneydewMelon : Food + { + [Constructable] + public HoneydewMelon() : this( 1 ) + { + } + + [Constructable] + public HoneydewMelon( int amount ) : base( amount, 0xC74 ) + { + this.Name = "Melon"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public HoneydewMelon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC64, 0xC65 )] + public class YellowGourd : Food + { + [Constructable] + public YellowGourd() : this( 1 ) + { + } + + [Constructable] + public YellowGourd( int amount ) : base( amount, 0xC64 ) + { + this.Name = "Courgette"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public YellowGourd( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC66, 0xC67 )] + public class GreenGourd : Food + { + [Constructable] + public GreenGourd() : this( 1 ) + { + } + + [Constructable] + public GreenGourd( int amount ) : base( amount, 0xC66 ) + { + this.Name = "Zucchini"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public GreenGourd( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC7F, 0xC81 )] + public class EarOfCorn : Food + { + [Constructable] + public EarOfCorn() : this( 1 ) + { + } + + [Constructable] + public EarOfCorn( int amount ) : base( amount, 0xC81 ) + { + this.Name = "�pi de ma�s"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public EarOfCorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Turnip : Food + { + [Constructable] + public Turnip() : this( 1 ) + { + } + + [Constructable] + public Turnip( int amount ) : base( amount, 0xD3A ) + { + this.Name = "Navet"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Turnip( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SheafOfHay : Item + { + [Constructable] + public SheafOfHay() : base( 0xF36 ) + { + this.Name = "Gerbe de bl�"; + this.Weight = 10.0; + } + + public SheafOfHay( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/Fruits.cs b/Scripts/Items/Food/Fruits.cs new file mode 100644 index 0000000..b78f11a --- /dev/null +++ b/Scripts/Items/Food/Fruits.cs @@ -0,0 +1,651 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + public class FruitBasket : Food + { + [Constructable] + public FruitBasket() : base( 1, 0x993 ) + { + Name = "Un panier de fruits"; + Weight = 2.0; + FillFactor = 5; + Stackable = false; + } + + public FruitBasket( Serial serial ) : base( serial ) + { + } + + public override bool Eat( Mobile from ) + { + if ( !base.Eat( from ) ) + return false; + + from.AddToBackpack( new Basket() ); + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x171f, 0x1720 )] + public class Banana : Food + { + [Constructable] + public Banana() : this( 1 ) + { + } + + [Constructable] + public Banana( int amount ) : base( amount, 0x171f ) + { + this.Name = "Banane"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Banana( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1721, 0x1722 )] + public class Bananas : Food + { + [Constructable] + public Bananas() : this( 1 ) + { + } + + [Constructable] + public Bananas( int amount ) : base( amount, 0x1721 ) + { + this.Name = "R�gime de bananes"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Bananas( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SplitCoconut : Food + { + [Constructable] + public SplitCoconut() : this( 1 ) + { + } + + [Constructable] + public SplitCoconut( int amount ) : base( amount, 0x1725 ) + { + this.Name = "Noix de coco"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public SplitCoconut( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Lemon : Food + { + [Constructable] + public Lemon() : this( 1 ) + { + } + + [Constructable] + public Lemon( int amount ) : base( amount, 0x1728 ) + { + this.Name = "Citron"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Lemon( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Lemons : Food + { + [Constructable] + public Lemons() : this( 1 ) + { + } + + [Constructable] + public Lemons( int amount ) : base( amount, 0x1729 ) + { + this.Name = "Citron"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Lemons( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Lime : Food + { + [Constructable] + public Lime() : this( 1 ) + { + } + + [Constructable] + public Lime( int amount ) : base( amount, 0x172a ) + { + this.Name = "Lime"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Lime( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Limes : Food + { + [Constructable] + public Limes() : this( 1 ) + { + } + + [Constructable] + public Limes( int amount ) : base( amount, 0x172B ) + { + this.Name = "Lime"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Limes( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Coconut : Food + { + [Constructable] + public Coconut() : this( 1 ) + { + } + + [Constructable] + public Coconut( int amount ) : base( amount, 0x1726 ) + { + this.Name = "Noix de coco"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Coconut( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class OpenCoconut : Food + { + [Constructable] + public OpenCoconut() : this( 1 ) + { + } + + [Constructable] + public OpenCoconut( int amount ) : base( amount, 0x1723 ) + { + this.Name = "Noix de coco"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public OpenCoconut( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Dates : Food + { + [Constructable] + public Dates() : this( 1 ) + { + } + + [Constructable] + public Dates( int amount ) : base( amount, 0x1727 ) + { + this.Name = "Datte"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Dates( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Grapes : Food + { + [Constructable] + public Grapes() : this( 1 ) + { + } + + [Constructable] + public Grapes( int amount ) : base( amount, 0x9D1 ) + { + this.Name = "Grappe de raisins"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Grapes( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Peach : Food + { + [Constructable] + public Peach() : this( 1 ) + { + } + + [Constructable] + public Peach( int amount ) : base( amount, 0x9D2 ) + { + this.Name = "P�che"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Peach( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Pear : Food + { + [Constructable] + public Pear() : this( 1 ) + { + } + + [Constructable] + public Pear( int amount ) : base( amount, 0x994 ) + { + this.Name = "Poire"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Pear( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Apple : Food + { + [Constructable] + public Apple() : this( 1 ) + { + } + + [Constructable] + public Apple( int amount ) : base( amount, 0x9D0 ) + { + this.Name = "Pomme"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Apple( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Watermelon : Food + { + [Constructable] + public Watermelon() : this( 1 ) + { + } + + [Constructable] + public Watermelon( int amount ) : base( amount, 0xC5C ) + { + this.Name = "Past�que"; + this.Weight = 5.0; + this.FillFactor = 5; + } + + public Watermelon( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( FillFactor == 2 ) + FillFactor = 5; + + if ( Weight == 2.0 ) + Weight = 5.0; + } + } + } + + public class SmallWatermelon : Food + { + [Constructable] + public SmallWatermelon() : this( 1 ) + { + } + + [Constructable] + public SmallWatermelon( int amount ) : base( amount, 0xC5D ) + { + this.Name = "Melon"; + this.Weight = 5.0; + this.FillFactor = 5; + } + + public SmallWatermelon( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xc72, 0xc73 )] + public class Squash : Food + { + [Constructable] + public Squash() : this( 1 ) + { + } + + [Constructable] + public Squash( int amount ) : base( amount, 0xc72 ) + { + this.Name = "Courge"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Squash( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xc79, 0xc7a )] + public class Cantaloupe : Food + { + [Constructable] + public Cantaloupe() : this( 1 ) + { + } + + [Constructable] + public Cantaloupe( int amount ) : base( amount, 0xc79 ) + { + this.Name = "Cantaloup"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Cantaloupe( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Food/Vegetables.cs b/Scripts/Items/Food/Vegetables.cs new file mode 100644 index 0000000..85a9fda --- /dev/null +++ b/Scripts/Items/Food/Vegetables.cs @@ -0,0 +1,219 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xc77, 0xc78 )] + public class Carrot : Food + { + [Constructable] + public Carrot() : this( 1 ) + { + } + + [Constructable] + public Carrot( int amount ) : base( amount, 0xc78 ) + { + this.Name = "Carotte"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Carrot( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xc7b, 0xc7c )] + public class Cabbage : Food + { + [Constructable] + public Cabbage() : this( 1 ) + { + } + + [Constructable] + public Cabbage( int amount ) : base( amount, 0xc7b ) + { + this.Name = "Chou"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Cabbage( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xc6d, 0xc6e )] + public class Onion : Food + { + [Constructable] + public Onion() : this( 1 ) + { + } + + [Constructable] + public Onion( int amount ) : base( amount, 0xc6d ) + { + this.Name = "Oignon"; + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Onion( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xc70, 0xc71 )] + public class Lettuce : Food + { + [Constructable] + public Lettuce() : this( 1 ) + { + } + + [Constructable] + public Lettuce( int amount ) : base( amount, 0xc70 ) + { + this.Name = "Laitue"; + + this.Weight = 1.0; + this.FillFactor = 1; + } + + public Lettuce( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0xC6A, 0xC6B )] + public class Pumpkin : Food + { + [Constructable] + public Pumpkin() : this( 1 ) + { + } + + [Constructable] + public Pumpkin( int amount ) : base( amount, 0xC6A ) + { + this.Name = "Citrouille"; + this.Weight = 1.0; + this.FillFactor = 8; + } + + public Pumpkin( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( FillFactor == 4 ) + FillFactor = 8; + + if ( Weight == 5.0 ) + Weight = 1.0; + } + } + } + + public class SmallPumpkin : Food + { + [Constructable] + public SmallPumpkin() : this( 1 ) + { + } + + [Constructable] + public SmallPumpkin( int amount ) : base( amount, 0xC6C ) + { + this.Name = "Potiron"; + + this.Weight = 1.0; + this.FillFactor = 8; + } + + public SmallPumpkin( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Backgammon.cs b/Scripts/Items/Games/Backgammon.cs new file mode 100644 index 0000000..f55ba25 --- /dev/null +++ b/Scripts/Items/Games/Backgammon.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; + +namespace Server.Items +{ + [Flipable( 0xE1C, 0xFAD )] + public class Backgammon : BaseBoard + { + [Constructable] + public Backgammon() : base( 0xE1C ) + { + } + + public override void CreatePieces() + { + for ( int i = 0; i < 5; i++ ) + { + CreatePiece( new PieceWhiteChecker( this ), 42, ( 17 * i ) + 6 ); + CreatePiece( new PieceBlackChecker( this ), 42, ( 17 * i ) + 119 ); + + CreatePiece( new PieceBlackChecker( this ), 142, ( 17 * i ) + 6 ); + CreatePiece( new PieceWhiteChecker( this ), 142, ( 17 * i ) + 119 ); + } + + for ( int i = 0; i < 3; i++ ) + { + CreatePiece( new PieceBlackChecker( this ), 108, ( 17 * i ) + 6 ); + CreatePiece( new PieceWhiteChecker( this ), 108, ( 17 * i ) + 153 ); + } + + for ( int i = 0; i < 2; i++ ) + { + CreatePiece( new PieceWhiteChecker( this ), 223, ( 17 * i ) + 6 ); + CreatePiece( new PieceBlackChecker( this ), 223, ( 17 * i ) + 170 ); + } + } + + public Backgammon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + } +} diff --git a/Scripts/Items/Games/BaseBoard.cs b/Scripts/Items/Games/BaseBoard.cs new file mode 100644 index 0000000..4650dcb --- /dev/null +++ b/Scripts/Items/Games/BaseBoard.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.ContextMenus; +using Server.Gumps; + +namespace Server.Items +{ + public abstract class BaseBoard : Container, ISecurable + { + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + public BaseBoard( int itemID ) : base( itemID ) + { + CreatePieces(); + + Weight = 5.0; + } + + public abstract void CreatePieces(); + + public void Reset() + { + for ( int i = Items.Count - 1; i >= 0; --i ) + { + if ( i < Items.Count ) + Items[i].Delete(); + } + + CreatePieces(); + } + + public void CreatePiece( BasePiece piece, int x, int y ) + { + AddItem( piece ); + piece.Location = new Point3D( x, y, 0 ); + } + + public override bool DisplaysContent{ get{ return false; } } // Do not display (x items, y stones) + + public override bool IsDecoContainer{ get{ return false; } } + + public BaseBoard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); // version + + writer.Write( (int)m_Level ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 1 ) + m_Level = (SecureLevel)reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 5.0; + } + + public override TimeSpan DecayTime{ get{ return TimeSpan.FromDays( 1.0 ); } } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + BasePiece piece = dropped as BasePiece; + + return ( piece != null && piece.Board == this && base.OnDragDrop( from, dropped ) ); + } + + public override bool OnDragDropInto( Mobile from, Item dropped, Point3D point ) + { + BasePiece piece = dropped as BasePiece; + + if ( piece != null && piece.Board == this && base.OnDragDropInto( from, dropped, point ) ) + { + Packet p = new PlaySound( 0x127, GetWorldLocation() ); + + p.Acquire(); + + if ( RootParent == from ) + { + from.Send( p ); + } + else + { + foreach ( NetState state in this.GetClientsInRange( 2 ) ) + state.Send( p ); + } + + p.Release(); + + return true; + } + else + { + return false; + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( ValidateDefault( from, this ) ) + list.Add( new DefaultEntry( from, this ) ); + + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public static bool ValidateDefault( Mobile from, BaseBoard board ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if ( !from.Alive ) + return false; + + if ( board.IsChildOf( from.Backpack ) ) + return true; + + object root = board.RootParent; + + if ( root is Mobile && root != from ) + return false; + + if ( board.Deleted || board.Map != from.Map || !from.InRange( board.GetWorldLocation(), 1 ) ) + return false; + + BaseHouse house = BaseHouse.FindHouseAt( board ); + + return ( house != null && house.IsOwner( from ) ); + } + + public class DefaultEntry : ContextMenuEntry + { + private Mobile m_From; + private BaseBoard m_Board; + + public DefaultEntry( Mobile from, BaseBoard board ) : base( 6162, from.AccessLevel >= AccessLevel.GameMaster ? -1 : 1 ) + { + m_From = from; + m_Board = board; + } + + public override void OnClick() + { + if ( BaseBoard.ValidateDefault( m_From, m_Board ) ) + m_Board.Reset(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/BasePiece.cs b/Scripts/Items/Games/BasePiece.cs new file mode 100644 index 0000000..916bd41 --- /dev/null +++ b/Scripts/Items/Games/BasePiece.cs @@ -0,0 +1,105 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BasePiece : Item + { + private BaseBoard m_Board; + + public BaseBoard Board + { + get { return m_Board; } + set { m_Board = value; } + } + + public override bool IsVirtualItem{ get{ return true; } } + + public BasePiece( int itemID, BaseBoard board ) : base( itemID ) + { + m_Board = board; + } + + public BasePiece( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + writer.Write( m_Board ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Board = (BaseBoard)reader.ReadItem(); + + if ( m_Board == null || Parent == null ) + Delete(); + + break; + } + } + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Board == null || m_Board.Deleted ) + Delete(); + else if ( !IsChildOf( m_Board ) ) + m_Board.DropItem( this ); + else + base.OnSingleClick( from ); + } + + public override bool OnDragLift( Mobile from ) + { + if ( m_Board == null || m_Board.Deleted ) + { + Delete(); + return false; + } + else if ( !IsChildOf( m_Board ) ) + { + m_Board.DropItem( this ); + return false; + } + else + { + return true; + } + } + + public override bool CanTarget{ get{ return false; } } + + public override bool DropToMobile( Mobile from, Mobile target, Point3D p ) + { + return false; + } + + public override bool DropToItem( Mobile from, Item target, Point3D p ) + { + return ( target == m_Board && p.X != -1 && p.Y != -1 && base.DropToItem( from, target, p ) ); + } + + public override bool DropToWorld( Mobile from, Point3D p ) + { + return false; + } + + public override int GetLiftSound( Mobile from ) + { + return -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/CheckerBoard.cs b/Scripts/Items/Games/CheckerBoard.cs new file mode 100644 index 0000000..8cb3ae4 --- /dev/null +++ b/Scripts/Items/Games/CheckerBoard.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections; + +namespace Server.Items +{ + public class CheckerBoard : BaseBoard + { + public override int LabelNumber{ get{ return 1016449; } } // a checker board + + [Constructable] + public CheckerBoard() : base( 0xFA6 ) + { + } + + public override void CreatePieces() + { + for ( int i = 0; i < 4; i++ ) + { + CreatePiece( new PieceWhiteChecker( this ), ( 50 * i ) + 45, 25 ); + CreatePiece( new PieceWhiteChecker( this ), ( 50 * i ) + 70, 50 ); + CreatePiece( new PieceWhiteChecker( this ), ( 50 * i ) + 45, 75 ); + CreatePiece( new PieceBlackChecker( this ), ( 50 * i ) + 70, 150 ); + CreatePiece( new PieceBlackChecker( this ), ( 50 * i ) + 45, 175 ); + CreatePiece( new PieceBlackChecker( this ), ( 50 * i ) + 70, 200 ); + } + } + + public CheckerBoard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/CheckersPieces.cs b/Scripts/Items/Games/CheckersPieces.cs new file mode 100644 index 0000000..a5d2138 --- /dev/null +++ b/Scripts/Items/Games/CheckersPieces.cs @@ -0,0 +1,61 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PieceWhiteChecker : BasePiece + { + public override string DefaultName + { + get { return "white checker"; } + } + + public PieceWhiteChecker( BaseBoard board ) : base( 0x3584, board ) + { + } + + public PieceWhiteChecker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackChecker : BasePiece + { + public override string DefaultName + { + get { return "black checker"; } + } + + public PieceBlackChecker( BaseBoard board ) : base( 0x358B, board ) + { + } + + public PieceBlackChecker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/ChessPieces.cs b/Scripts/Items/Games/ChessPieces.cs new file mode 100644 index 0000000..a036d11 --- /dev/null +++ b/Scripts/Items/Games/ChessPieces.cs @@ -0,0 +1,341 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PieceWhiteKing : BasePiece + { + public override string DefaultName + { + get { return "white king"; } + } + + public PieceWhiteKing( BaseBoard board ) : base( 0x3587, board ) + { + } + + public PieceWhiteKing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackKing : BasePiece + { + public override string DefaultName + { + get { return "black king"; } + } + + public PieceBlackKing( BaseBoard board ) : base( 0x358E, board ) + { + } + + public PieceBlackKing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceWhiteQueen : BasePiece + { + public override string DefaultName + { + get { return "white queen"; } + } + + public PieceWhiteQueen( BaseBoard board ) : base( 0x358A, board ) + { + } + + public PieceWhiteQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackQueen : BasePiece + { + public override string DefaultName + { + get { return "black queen"; } + } + + public PieceBlackQueen( BaseBoard board ) : base( 0x3591, board ) + { + } + + public PieceBlackQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceWhiteRook : BasePiece + { + public override string DefaultName + { + get { return "white rook"; } + } + + public PieceWhiteRook( BaseBoard board ) : base( 0x3586, board ) + { + } + + public PieceWhiteRook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackRook : BasePiece + { + public override string DefaultName + { + get { return "black rook"; } + } + + public PieceBlackRook( BaseBoard board ) : base( 0x358D, board ) + { + } + + public PieceBlackRook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceWhiteBishop : BasePiece + { + public override string DefaultName + { + get { return "white bishop"; } + } + + public PieceWhiteBishop( BaseBoard board ) : base( 0x3585, board ) + { + } + + public PieceWhiteBishop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackBishop : BasePiece + { + public override string DefaultName + { + get { return "black bishop"; } + } + + public PieceBlackBishop( BaseBoard board ) : base( 0x358C, board ) + { + } + + public PieceBlackBishop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceWhiteKnight : BasePiece + { + public override string DefaultName + { + get { return "white knight"; } + } + + public PieceWhiteKnight( BaseBoard board ) : base( 0x3588, board ) + { + } + + public PieceWhiteKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackKnight : BasePiece + { + public override string DefaultName + { + get { return "black knight"; } + } + + public PieceBlackKnight( BaseBoard board ) : base( 0x358F, board ) + { + } + + public PieceBlackKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceWhitePawn : BasePiece + { + public override string DefaultName + { + get { return "white pawn"; } + } + + public PieceWhitePawn( BaseBoard board ) : base( 0x3589, board ) + { + } + + public PieceWhitePawn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class PieceBlackPawn : BasePiece + { + public override string DefaultName + { + get { return "black pawn"; } + } + + public PieceBlackPawn( BaseBoard board ) : base( 0x3590, board ) + { + } + + public PieceBlackPawn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Games/Chessboard.cs b/Scripts/Items/Games/Chessboard.cs new file mode 100644 index 0000000..7be8dca --- /dev/null +++ b/Scripts/Items/Games/Chessboard.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections; + +namespace Server.Items +{ + public class Chessboard : BaseBoard + { + public override int LabelNumber{ get{ return 1016450; } } // a chessboard + + [Constructable] + public Chessboard() : base( 0xFA6 ) + { + } + + public override void CreatePieces() + { + for ( int i = 0; i < 8; i++ ) + { + CreatePiece( new PieceBlackPawn( this ), 67, ( 25 * i ) + 17 ); + CreatePiece( new PieceWhitePawn( this ), 192, ( 25 * i ) + 17 ); + } + + // Rook + CreatePiece( new PieceBlackRook( this ), 42, 5 ); + CreatePiece( new PieceBlackRook( this ), 42, 180 ); + + CreatePiece( new PieceWhiteRook( this ), 216, 5 ); + CreatePiece( new PieceWhiteRook( this ), 216, 180 ); + + // Knight + CreatePiece( new PieceBlackKnight( this ), 42, 30 ); + CreatePiece( new PieceBlackKnight( this ), 42, 155 ); + + CreatePiece( new PieceWhiteKnight( this ), 216, 30 ); + CreatePiece( new PieceWhiteKnight( this ), 216, 155 ); + + // Bishop + CreatePiece( new PieceBlackBishop( this ), 42, 55 ); + CreatePiece( new PieceBlackBishop( this ), 42, 130 ); + + CreatePiece( new PieceWhiteBishop( this ), 216, 55 ); + CreatePiece( new PieceWhiteBishop( this ), 216, 130 ); + + // Queen + CreatePiece( new PieceBlackQueen( this ), 42, 105 ); + CreatePiece( new PieceWhiteQueen( this ), 216, 105 ); + + // King + CreatePiece( new PieceBlackKing( this ), 42, 80 ); + CreatePiece( new PieceWhiteKing( this ), 216, 80 ); + } + + public Chessboard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Dices.cs b/Scripts/Items/Games/Dices.cs new file mode 100644 index 0000000..80da7ef --- /dev/null +++ b/Scripts/Items/Games/Dices.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class Dices : Item, ITelekinesisable + { + [Constructable] + public Dices() : base( 0xFA7 ) + { + Weight = 1.0; + } + + public Dices( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + return; + Roll(from); + } + + public void OnTelekinesis(Mobile from) + { + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x376A, 9, 32, 5022); + Effects.PlaySound(Location, Map, 0x1F5); + + Roll(from); + } + + public void Roll(Mobile from) + { + this.PublicOverheadMessage( MessageType.Regular, 0, false, string.Format( "*{0} rolls {1}, {2}*", from.Name, Utility.Random( 1, 6 ), Utility.Random( 1, 6 ) ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongDealerIndicator.cs b/Scripts/Items/Games/Mahjong/MahjongDealerIndicator.cs new file mode 100644 index 0000000..4016cb9 --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongDealerIndicator.cs @@ -0,0 +1,73 @@ +using System; +using Server; + +namespace Server.Engines.Mahjong +{ + public class MahjongDealerIndicator + { + public static MahjongPieceDim GetDimensions( Point2D position, MahjongPieceDirection direction ) + { + if ( direction == MahjongPieceDirection.Up || direction == MahjongPieceDirection.Down ) + return new MahjongPieceDim( position, 40, 20 ); + else + return new MahjongPieceDim( position, 20, 40 ); + } + + private MahjongGame m_Game; + private Point2D m_Position; + private MahjongPieceDirection m_Direction; + private MahjongWind m_Wind; + + public MahjongGame Game { get { return m_Game; } } + public Point2D Position { get { return m_Position; } } + public MahjongPieceDirection Direction { get { return m_Direction; } } + public MahjongWind Wind { get { return m_Wind; } } + + public MahjongDealerIndicator( MahjongGame game, Point2D position, MahjongPieceDirection direction, MahjongWind wind ) + { + m_Game = game; + m_Position = position; + m_Direction = direction; + m_Wind = wind; + } + + public MahjongPieceDim Dimensions + { + get { return GetDimensions( m_Position, m_Direction ); } + } + + public void Move( Point2D position, MahjongPieceDirection direction, MahjongWind wind ) + { + MahjongPieceDim dim = GetDimensions( position, direction ); + + if ( !dim.IsValid() ) + return; + + m_Position = position; + m_Direction = direction; + m_Wind = wind; + + m_Game.Players.SendGeneralPacket( true, true ); + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + writer.Write( m_Position ); + writer.Write( (int) m_Direction ); + writer.Write( (int) m_Wind ); + } + + public MahjongDealerIndicator( MahjongGame game, GenericReader reader ) + { + m_Game = game; + + int version = reader.ReadInt(); + + m_Position = reader.ReadPoint2D(); + m_Direction = (MahjongPieceDirection) reader.ReadInt(); + m_Wind = (MahjongWind) reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongDices.cs b/Scripts/Items/Games/Mahjong/MahjongDices.cs new file mode 100644 index 0000000..9a5669a --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongDices.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Engines.Mahjong +{ + public class MahjongDices + { + private MahjongGame m_Game; + private int m_First; + private int m_Second; + + public MahjongGame Game { get { return m_Game; } } + public int First { get { return m_First; } } + public int Second { get { return m_Second; } } + + public MahjongDices( MahjongGame game ) + { + m_Game = game; + m_First = Utility.Random( 1, 6 ); + m_Second = Utility.Random( 1, 6 ); + } + + public void RollDices( Mobile from ) + { + m_First = Utility.Random( 1, 6 ); + m_Second = Utility.Random( 1, 6 ); + + m_Game.Players.SendGeneralPacket( true, true ); + + if ( from != null ) + m_Game.Players.SendLocalizedMessage( 1062695, string.Format( "{0}\t{1}\t{2}", from.Name, m_First, m_Second ) ); // ~1_name~ rolls the dice and gets a ~2_number~ and a ~3_number~! + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + writer.Write( m_First ); + writer.Write( m_Second ); + } + + public MahjongDices( MahjongGame game, GenericReader reader ) + { + m_Game = game; + + int version = reader.ReadInt(); + + m_First = reader.ReadInt(); + m_Second = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongEnums.cs b/Scripts/Items/Games/Mahjong/MahjongEnums.cs new file mode 100644 index 0000000..fb2d5ff --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongEnums.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Engines.Mahjong +{ + public enum MahjongPieceDirection + { + Up, + Left, + Down, + Right + } + + public enum MahjongWind + { + North, + East, + South, + West + } + + public enum MahjongTileType + { + Dagger1 = 1, + Dagger2, + Dagger3, + Dagger4, + Dagger5, + Dagger6, + Dagger7, + Dagger8, + Dagger9, + Gem1, + Gem2, + Gem3, + Gem4, + Gem5, + Gem6, + Gem7, + Gem8, + Gem9, + Number1, + Number2, + Number3, + Number4, + Number5, + Number6, + Number7, + Number8, + Number9, + North, + East, + South, + West, + Green, + Red, + White + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongGame.cs b/Scripts/Items/Games/Mahjong/MahjongGame.cs new file mode 100644 index 0000000..6560f70 --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongGame.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.ContextMenus; + +namespace Server.Engines.Mahjong +{ + public class MahjongGame : Item, ISecurable + { + public const int MaxPlayers = 4; + public const int BaseScore = 30000; + + private MahjongTile[] m_Tiles; + private MahjongDealerIndicator m_DealerIndicator; + private MahjongWallBreakIndicator m_WallBreakIndicator; + private MahjongDices m_Dices; + private MahjongPlayers m_Players; + private bool m_ShowScores; + private bool m_SpectatorVision; + private DateTime m_LastReset; + + public MahjongTile[] Tiles { get { return m_Tiles; } } + public MahjongDealerIndicator DealerIndicator { get { return m_DealerIndicator; } } + public MahjongWallBreakIndicator WallBreakIndicator { get { return m_WallBreakIndicator; } } + public MahjongDices Dices { get { return m_Dices; } } + public MahjongPlayers Players { get { return m_Players; } } + + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ShowScores + { + get { return m_ShowScores; } + set + { + if ( m_ShowScores == value ) + return; + + m_ShowScores = value; + + if ( value ) + m_Players.SendPlayersPacket( true, true ); + + m_Players.SendGeneralPacket( true, true ); + + m_Players.SendLocalizedMessage( value ? 1062777 : 1062778 ); // The dealer has enabled/disabled score display. + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SpectatorVision + { + get { return m_SpectatorVision; } + set + { + if ( m_SpectatorVision == value ) + return; + + m_SpectatorVision = value; + + if ( m_Players.IsInGamePlayer( m_Players.DealerPosition ) ) + m_Players.Dealer.Send( new MahjongGeneralInfo( this ) ); + + m_Players.SendTilesPacket( false, true ); + + m_Players.SendLocalizedMessage( value ? 1062715 : 1062716 ); // The dealer has enabled/disabled Spectator Vision. + + InvalidateProperties(); + } + } + + [Constructable] + public MahjongGame() : base( 0xFAA ) + { + Weight = 5.0; + + BuildWalls(); + m_DealerIndicator = new MahjongDealerIndicator( this, new Point2D( 300, 300 ), MahjongPieceDirection.Up, MahjongWind.North ); + m_WallBreakIndicator = new MahjongWallBreakIndicator( this, new Point2D( 335, 335 ) ); + m_Dices = new MahjongDices( this ); + m_Players = new MahjongPlayers( this, MaxPlayers, BaseScore ); + m_LastReset = DateTime.Now; + m_Level = SecureLevel.CoOwners; + } + + public MahjongGame( Serial serial ) : base( serial ) + { + } + + private void BuildHorizontalWall( ref int index, int x, int y, int stackLevel, MahjongPieceDirection direction, MahjongTileTypeGenerator typeGenerator ) + { + for ( int i = 0; i < 17; i++ ) + { + Point2D position = new Point2D( x + i*20, y ); + m_Tiles[index + i] = new MahjongTile( this, index + i, typeGenerator.Next(), position, stackLevel, direction, false ); + } + + index += 17; + } + + private void BuildVerticalWall( ref int index, int x, int y, int stackLevel, MahjongPieceDirection direction, MahjongTileTypeGenerator typeGenerator ) + { + for ( int i = 0; i < 17; i++ ) + { + Point2D position = new Point2D( x, y + i*20 ); + m_Tiles[index + i] = new MahjongTile( this, index + i, typeGenerator.Next(), position, stackLevel, direction, false ); + } + + index += 17; + } + + private void BuildWalls() + { + m_Tiles = new MahjongTile[17 * 8]; + + MahjongTileTypeGenerator typeGenerator = new MahjongTileTypeGenerator( 4 ); + + int i = 0; + + BuildHorizontalWall( ref i, 165, 110, 0, MahjongPieceDirection.Up, typeGenerator ); + BuildHorizontalWall( ref i, 165, 115, 1, MahjongPieceDirection.Up, typeGenerator ); + + BuildVerticalWall( ref i, 530, 165, 0, MahjongPieceDirection.Left, typeGenerator ); + BuildVerticalWall( ref i, 525, 165, 1, MahjongPieceDirection.Left, typeGenerator ); + + BuildHorizontalWall( ref i, 165, 530, 0, MahjongPieceDirection.Down, typeGenerator ); + BuildHorizontalWall( ref i, 165, 525, 1, MahjongPieceDirection.Down, typeGenerator ); + + BuildVerticalWall( ref i, 110, 165, 0, MahjongPieceDirection.Right, typeGenerator ); + BuildVerticalWall( ref i, 115, 165, 1, MahjongPieceDirection.Right, typeGenerator ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_SpectatorVision ) + list.Add( 1062717 ); // Spectator Vision Enabled + else + list.Add( 1062718 ); // Spectator Vision Disabled + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + m_Players.CheckPlayers(); + + if ( from.Alive && IsAccessibleTo( from ) && m_Players.GetInGameMobiles( true, false ).Count == 0 ) + list.Add( new ResetGameEntry( this ) ); + + SetSecureLevelEntry.AddTo( from, this, list ); + } + + private class ResetGameEntry : ContextMenuEntry + { + private MahjongGame m_Game; + + public ResetGameEntry( MahjongGame game ) : base( 6162 ) + { + m_Game = game; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( from.CheckAlive() && !m_Game.Deleted && m_Game.IsAccessibleTo( from ) && m_Game.Players.GetInGameMobiles( true, false ).Count == 0 ) + m_Game.ResetGame( from ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + m_Players.CheckPlayers(); + + m_Players.Join( from ); + } + + public void ResetGame( Mobile from ) + { + if ( DateTime.Now - m_LastReset < TimeSpan.FromSeconds( 5.0 ) ) + return; + + m_LastReset = DateTime.Now; + + if ( from != null ) + m_Players.SendLocalizedMessage( 1062771, from.Name ); // ~1_name~ has reset the game. + + m_Players.SendRelievePacket( true, true ); + + BuildWalls(); + m_DealerIndicator = new MahjongDealerIndicator( this, new Point2D( 300, 300 ), MahjongPieceDirection.Up, MahjongWind.North ); + m_WallBreakIndicator = new MahjongWallBreakIndicator( this, new Point2D( 335, 335 ) ); + m_Players = new MahjongPlayers( this, MaxPlayers, BaseScore ); + } + + public void ResetWalls( Mobile from ) + { + if ( DateTime.Now - m_LastReset < TimeSpan.FromSeconds( 5.0 ) ) + return; + + m_LastReset = DateTime.Now; + + BuildWalls(); + + m_Players.SendTilesPacket( true, true ); + + if ( from != null ) + m_Players.SendLocalizedMessage( 1062696 ); // The dealer rebuilds the wall. + } + + public int GetStackLevel( MahjongPieceDim dim ) + { + int level = -1; + foreach ( MahjongTile tile in m_Tiles ) + { + if ( tile.StackLevel > level && dim.IsOverlapping( tile.Dimensions ) ) + level = tile.StackLevel; + } + return level; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Level ); + + writer.Write( m_Tiles.Length ); + + for ( int i = 0; i < m_Tiles.Length; i++ ) + m_Tiles[i].Save( writer ); + + m_DealerIndicator.Save( writer ); + + m_WallBreakIndicator.Save( writer ); + + m_Dices.Save( writer ); + + m_Players.Save( writer ); + + writer.Write( m_ShowScores ); + writer.Write( m_SpectatorVision ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + + goto case 0; + } + case 0: + { + if ( version < 1 ) + m_Level = SecureLevel.CoOwners; + + int length = reader.ReadInt(); + m_Tiles = new MahjongTile[length]; + + for ( int i = 0; i < length; i++ ) + m_Tiles[i] = new MahjongTile( this, reader ); + + m_DealerIndicator = new MahjongDealerIndicator( this, reader ); + + m_WallBreakIndicator = new MahjongWallBreakIndicator( this, reader ); + + m_Dices = new MahjongDices( this, reader ); + + m_Players = new MahjongPlayers( this, reader ); + + m_ShowScores = reader.ReadBool(); + m_SpectatorVision = reader.ReadBool(); + + m_LastReset = DateTime.Now; + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs b/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs new file mode 100644 index 0000000..57dedec --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongPacketHandlers.cs @@ -0,0 +1,245 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Engines.Mahjong +{ + public delegate void OnMahjongPacketReceive( MahjongGame game, NetState state, PacketReader pvSrc ); + + public sealed class MahjongPacketHandlers + { + private static OnMahjongPacketReceive[] m_SubCommandDelegates = new OnMahjongPacketReceive[0x100]; + + public static void RegisterSubCommand( int subCmd, OnMahjongPacketReceive onReceive ) + { + m_SubCommandDelegates[subCmd] = onReceive; + } + + public static OnMahjongPacketReceive GetSubCommandDelegate( int cmd ) + { + if ( cmd >= 0 && cmd < 0x100 ) + { + return m_SubCommandDelegates[cmd]; + } + else + { + return null; + } + } + + public static void Initialize() + { + PacketHandlers.Register( 0xDA, 0, true, new OnPacketReceive( OnPacket ) ); + + RegisterSubCommand( 0x6, new OnMahjongPacketReceive( ExitGame ) ); + RegisterSubCommand( 0xA, new OnMahjongPacketReceive( GivePoints ) ); + RegisterSubCommand( 0xB, new OnMahjongPacketReceive( RollDice ) ); + RegisterSubCommand( 0xC, new OnMahjongPacketReceive( BuildWalls ) ); + RegisterSubCommand( 0xD, new OnMahjongPacketReceive( ResetScores ) ); + RegisterSubCommand( 0xF, new OnMahjongPacketReceive( AssignDealer ) ); + RegisterSubCommand( 0x10, new OnMahjongPacketReceive( OpenSeat ) ); + RegisterSubCommand( 0x11, new OnMahjongPacketReceive( ChangeOption ) ); + RegisterSubCommand( 0x15, new OnMahjongPacketReceive( MoveWallBreakIndicator ) ); + RegisterSubCommand( 0x16, new OnMahjongPacketReceive( TogglePublicHand ) ); + RegisterSubCommand( 0x17, new OnMahjongPacketReceive( MoveTile ) ); + RegisterSubCommand( 0x18, new OnMahjongPacketReceive( MoveDealerIndicator ) ); + } + + public static void OnPacket( NetState state, PacketReader pvSrc ) + { + MahjongGame game = World.FindItem( pvSrc.ReadInt32() ) as MahjongGame; + + if ( game != null ) + game.Players.CheckPlayers(); + + pvSrc.ReadByte(); + + int cmd = pvSrc.ReadByte(); + + OnMahjongPacketReceive onReceive = GetSubCommandDelegate( cmd ); + + if ( onReceive != null ) + { + onReceive( game, state, pvSrc ); + } + else + { + pvSrc.Trace( state ); + } + } + + private static MahjongPieceDirection GetDirection( int value ) + { + switch ( value ) + { + case 0: return MahjongPieceDirection.Up; + case 1: return MahjongPieceDirection.Left; + case 2: return MahjongPieceDirection.Down; + default: return MahjongPieceDirection.Right; + } + } + + private static MahjongWind GetWind( int value ) + { + switch ( value ) + { + case 0: return MahjongWind.North; + case 1: return MahjongWind.East; + case 2: return MahjongWind.South; + default: return MahjongWind.West; + } + } + + public static void ExitGame( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null ) + return; + + Mobile from = state.Mobile; + + game.Players.LeaveGame( from ); + } + + public static void GivePoints( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGamePlayer( state.Mobile ) ) + return; + + int to = pvSrc.ReadByte(); + int amount = pvSrc.ReadInt32(); + + game.Players.TransferScore( state.Mobile, to, amount ); + } + + public static void RollDice( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGamePlayer( state.Mobile ) ) + return; + + game.Dices.RollDices( state.Mobile ); + } + + public static void BuildWalls( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + game.ResetWalls( state.Mobile ); + } + + public static void ResetScores( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + game.Players.ResetScores( MahjongGame.BaseScore ); + } + + public static void AssignDealer( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + int position = pvSrc.ReadByte(); + + game.Players.AssignDealer( position ); + } + + public static void OpenSeat( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + int position = pvSrc.ReadByte(); + + if ( game.Players.GetPlayer( position ) == state.Mobile ) + return; + + game.Players.OpenSeat( position ); + } + + public static void ChangeOption( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + pvSrc.ReadInt16(); + pvSrc.ReadByte(); + + int options = pvSrc.ReadByte(); + + game.ShowScores = (options & 0x1) != 0; + game.SpectatorVision = (options & 0x2) != 0; + } + + public static void MoveWallBreakIndicator( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + int y = pvSrc.ReadInt16(); + int x = pvSrc.ReadInt16(); + + game.WallBreakIndicator.Move( new Point2D( x, y ) ); + } + + public static void TogglePublicHand( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGamePlayer( state.Mobile ) ) + return; + + pvSrc.ReadInt16(); + pvSrc.ReadByte(); + + bool publicHand = pvSrc.ReadBoolean(); + + game.Players.SetPublic( game.Players.GetPlayerIndex( state.Mobile ), publicHand ); + } + + public static void MoveTile( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGamePlayer( state.Mobile ) ) + return; + + int number = pvSrc.ReadByte(); + + if ( number < 0 || number >= game.Tiles.Length ) + return; + + pvSrc.ReadByte(); // Current direction + + MahjongPieceDirection direction = GetDirection( pvSrc.ReadByte() ); + + pvSrc.ReadByte(); + + bool flip = pvSrc.ReadBoolean(); + + pvSrc.ReadInt16(); // Current Y + pvSrc.ReadInt16(); // Current X + + pvSrc.ReadByte(); + + int y = pvSrc.ReadInt16(); + int x = pvSrc.ReadInt16(); + + pvSrc.ReadByte(); + + game.Tiles[number].Move( new Point2D( x, y ), direction, flip, game.Players.GetPlayerIndex( state.Mobile ) ); + } + + public static void MoveDealerIndicator( MahjongGame game, NetState state, PacketReader pvSrc ) + { + if ( game == null || !game.Players.IsInGameDealer( state.Mobile ) ) + return; + + MahjongPieceDirection direction = GetDirection( pvSrc.ReadByte() ); + + MahjongWind wind = GetWind( pvSrc.ReadByte() ); + + int y = pvSrc.ReadInt16(); + int x = pvSrc.ReadInt16(); + + game.DealerIndicator.Move( new Point2D( x, y ), direction, wind ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongPieceDim.cs b/Scripts/Items/Games/Mahjong/MahjongPieceDim.cs new file mode 100644 index 0000000..4435acd --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongPieceDim.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Engines.Mahjong +{ + public struct MahjongPieceDim + { + private Point2D m_Position; + private int m_Width; + private int m_Height; + + public Point2D Position { get { return m_Position; } } + public int Width { get { return m_Width; } } + public int Height { get { return m_Height; } } + + public MahjongPieceDim( Point2D position, int width, int height ) + { + m_Position = position; + m_Width = width; + m_Height = height; + } + + public bool IsValid() + { + return m_Position.X >= 0 && m_Position.Y >= 0 && m_Position.X + m_Width <= 670 && m_Position.Y + m_Height <= 670; + } + + public bool IsOverlapping( MahjongPieceDim dim ) + { + return m_Position.X < dim.m_Position.X + dim.m_Width && m_Position.Y < dim.m_Position.Y + dim.m_Height && m_Position.X + m_Width > dim.m_Position.X && m_Position.Y + m_Height > dim.m_Position.Y; + } + + public int GetHandArea() + { + if ( m_Position.X + m_Width > 150 && m_Position.X < 520 && m_Position.Y < 35 ) + return 0; + + if ( m_Position.X + m_Width > 635 && m_Position.Y + m_Height > 150 && m_Position.Y < 520 ) + return 1; + + if ( m_Position.X + m_Width > 150 && m_Position.X < 520 && m_Position.Y + m_Height > 635 ) + return 2; + + if ( m_Position.X < 35 && m_Position.Y + m_Height > 150 && m_Position.Y < 520 ) + return 3; + + return -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongPlayers.cs b/Scripts/Items/Games/Mahjong/MahjongPlayers.cs new file mode 100644 index 0000000..78dbc6d --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongPlayers.cs @@ -0,0 +1,552 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Engines.Mahjong +{ + public class MahjongPlayers + { + private MahjongGame m_Game; + private Mobile[] m_Players; + private bool[] m_InGame; + private bool[] m_PublicHand; + private int[] m_Scores; + private int m_DealerPosition; + private ArrayList m_Spectators; + + public MahjongGame Game { get { return m_Game; } } + public int Seats { get { return m_Players.Length; } } + public Mobile Dealer { get { return m_Players[m_DealerPosition]; } } + public int DealerPosition { get { return m_DealerPosition; } } + + public MahjongPlayers( MahjongGame game, int maxPlayers, int baseScore ) + { + m_Game = game; + m_Spectators = new ArrayList(); + + m_Players = new Mobile[maxPlayers]; + m_InGame = new bool[maxPlayers]; + m_PublicHand = new bool[maxPlayers]; + m_Scores = new int[maxPlayers]; + + for ( int i = 0; i < m_Scores.Length; i++ ) + m_Scores[i] = baseScore; + } + + public Mobile GetPlayer( int index ) + { + if ( index < 0 || index >= m_Players.Length ) + return null; + else + return m_Players[index]; + } + + public int GetPlayerIndex( Mobile mobile ) + { + for ( int i = 0; i < m_Players.Length; i++ ) + { + if ( m_Players[i] == mobile ) + return i; + } + return -1; + } + + public bool IsInGameDealer( Mobile mobile ) + { + if ( Dealer != mobile ) + return false; + else + return m_InGame[m_DealerPosition]; + } + + public bool IsInGamePlayer( int index ) + { + if ( index < 0 || index >= m_Players.Length || m_Players[index] == null ) + return false; + else + return m_InGame[index]; + } + + public bool IsInGamePlayer( Mobile mobile ) + { + int index = GetPlayerIndex( mobile ); + + return IsInGamePlayer( index ); + } + + public bool IsSpectator( Mobile mobile ) + { + return m_Spectators.Contains( mobile ); + } + + public int GetScore( int index ) + { + if ( index < 0 || index >= m_Scores.Length ) + return 0; + else + return m_Scores[index]; + } + + public bool IsPublic( int index ) + { + if ( index < 0 || index >= m_PublicHand.Length ) + return false; + else + return m_PublicHand[index]; + } + + public void SetPublic( int index, bool value ) + { + if ( index < 0 || index >= m_PublicHand.Length || m_PublicHand[index] == value ) + return; + + m_PublicHand[index] = value; + + SendTilesPacket( true, !m_Game.SpectatorVision ); + + if ( IsInGamePlayer( index ) ) + m_Players[index].SendLocalizedMessage( value ? 1062775 : 1062776 ); // Your hand is [not] publicly viewable. + } + + public ArrayList GetInGameMobiles( bool players, bool spectators ) + { + ArrayList list = new ArrayList(); + + if ( players ) + { + for ( int i = 0; i < m_Players.Length; i++ ) + { + if ( IsInGamePlayer( i ) ) + list.Add( m_Players[i] ); + } + } + + if ( spectators ) + { + list.AddRange( m_Spectators ); + } + + return list; + } + + public void CheckPlayers() + { + bool removed = false; + + for ( int i = 0; i < m_Players.Length; i++ ) + { + Mobile player = m_Players[i]; + + if ( player != null ) + { + if ( player.Deleted ) + { + m_Players[i] = null; + + SendPlayerExitMessage( player ); + UpdateDealer( true ); + + removed = true; + } + else if ( m_InGame[i] ) + { + if ( player.NetState == null ) + { + m_InGame[i] = false; + + SendPlayerExitMessage( player ); + UpdateDealer( true ); + + removed = true; + } + else if ( !m_Game.IsAccessibleTo( player ) || player.Map != m_Game.Map || !player.InRange( m_Game.GetWorldLocation(), 5 ) ) + { + m_InGame[i] = false; + + player.Send( new MahjongRelieve( m_Game ) ); + + SendPlayerExitMessage( player ); + UpdateDealer( true ); + + removed = true; + } + } + } + } + + for ( int i = 0; i < m_Spectators.Count; ) + { + Mobile mobile = (Mobile)m_Spectators[i]; + + if ( mobile.NetState == null || mobile.Deleted ) + { + m_Spectators.RemoveAt( i ); + } + else if ( !m_Game.IsAccessibleTo( mobile ) || mobile.Map != m_Game.Map || !mobile.InRange( m_Game.GetWorldLocation(), 5 ) ) + { + m_Spectators.RemoveAt( i ); + + mobile.Send( new MahjongRelieve( m_Game ) ); + } + else + { + i++; + } + } + + if ( removed && !UpdateSpectators() ) + SendPlayersPacket( true, true ); + } + + private void UpdateDealer( bool message ) + { + if ( IsInGamePlayer( m_DealerPosition ) ) + return; + + for ( int i = m_DealerPosition + 1; i < m_Players.Length; i++ ) + { + if ( IsInGamePlayer( i ) ) + { + m_DealerPosition = i; + + if ( message ) + SendDealerChangedMessage(); + + return; + } + } + + for ( int i = 0; i < m_DealerPosition; i++ ) + { + if ( IsInGamePlayer( i ) ) + { + m_DealerPosition = i; + + if ( message ) + SendDealerChangedMessage(); + + return; + } + } + } + + private int GetNextSeat() + { + for ( int i = m_DealerPosition; i < m_Players.Length; i++ ) + { + if ( m_Players[i] == null ) + return i; + } + + for ( int i = 0; i < m_DealerPosition; i++ ) + { + if ( m_Players[i] == null ) + return i; + } + + return -1; + } + + private bool UpdateSpectators() + { + if ( m_Spectators.Count == 0 ) + return false; + + int nextSeat = GetNextSeat(); + + if ( nextSeat >= 0 ) + { + Mobile newPlayer = (Mobile)m_Spectators[0]; + + m_Spectators.RemoveAt( 0 ); + + AddPlayer( newPlayer, nextSeat, false ); + + UpdateSpectators(); + + return true; + } + else + { + return false; + } + } + + private void AddPlayer( Mobile player, int index, bool sendJoinGame ) + { + m_Players[index] = player; + m_InGame[index] = true; + + UpdateDealer( false ); + + if ( sendJoinGame ) + player.Send( new MahjongJoinGame( m_Game ) ); + + SendPlayersPacket( true, true ); + + player.Send( new MahjongGeneralInfo( m_Game ) ); + player.Send( new MahjongTilesInfo( m_Game, player ) ); + + if ( m_DealerPosition == index ) + SendLocalizedMessage( 1062773, player.Name ); // ~1_name~ has entered the game as the dealer. + else + SendLocalizedMessage( 1062772, player.Name ); // ~1_name~ has entered the game as a player. + } + + private void AddSpectator( Mobile mobile ) + { + if ( !IsSpectator( mobile ) ) + { + m_Spectators.Add( mobile ); + } + + mobile.Send( new MahjongJoinGame( m_Game ) ); + mobile.Send( new MahjongPlayersInfo( m_Game, mobile ) ); + mobile.Send( new MahjongGeneralInfo( m_Game ) ); + mobile.Send( new MahjongTilesInfo( m_Game, mobile ) ); + } + + public void Join( Mobile mobile ) + { + int index = GetPlayerIndex( mobile ); + + if ( index >= 0 ) + { + AddPlayer( mobile, index, true ); + } + else + { + int nextSeat = GetNextSeat(); + + if ( nextSeat >= 0 ) + { + AddPlayer( mobile, nextSeat, true ); + } + else + { + AddSpectator( mobile ); + } + } + } + + public void LeaveGame( Mobile player ) + { + int index = GetPlayerIndex( player ); + if ( index >= 0 ) + { + m_InGame[index] = false; + + SendPlayerExitMessage( player ); + UpdateDealer( true ); + + SendPlayersPacket( true, true ); + } + else + { + m_Spectators.Remove( player ); + } + } + + public void ResetScores( int value ) + { + for ( int i = 0; i < m_Scores.Length; i++ ) + { + m_Scores[i] = value; + } + + SendPlayersPacket( true, m_Game.ShowScores ); + + SendLocalizedMessage( 1062697 ); // The dealer redistributes the score sticks evenly. + } + + public void TransferScore( Mobile from, int toPosition, int amount ) + { + int fromPosition = GetPlayerIndex( from ); + Mobile to = GetPlayer( toPosition ); + + if ( fromPosition < 0 || to == null || m_Scores[fromPosition] < amount ) + return; + + m_Scores[fromPosition] -= amount; + m_Scores[toPosition] += amount; + + if ( m_Game.ShowScores ) + { + SendPlayersPacket( true, true ); + } + else + { + from.Send( new MahjongPlayersInfo( m_Game, from ) ); + to.Send( new MahjongPlayersInfo( m_Game, to ) ); + } + + SendLocalizedMessage( 1062774, string.Format( "{0}\t{1}\t{2}", from.Name, to.Name, amount ) ); // ~1_giver~ gives ~2_receiver~ ~3_number~ points. + } + + public void OpenSeat( int index ) + { + Mobile player = GetPlayer( index ); + if ( player == null ) + return; + + if ( m_InGame[index] ) + player.Send( new MahjongRelieve( m_Game ) ); + + m_Players[index] = null; + + SendLocalizedMessage( 1062699, player.Name ); // ~1_name~ is relieved from the game by the dealer. + + UpdateDealer( true ); + + if ( !UpdateSpectators() ) + SendPlayersPacket( true, true ); + } + + public void AssignDealer( int index ) + { + Mobile to = GetPlayer( index ); + + if ( to == null || !m_InGame[index] ) + return; + + int oldDealer = m_DealerPosition; + + m_DealerPosition = index; + + if ( IsInGamePlayer( oldDealer ) ) + m_Players[oldDealer].Send( new MahjongPlayersInfo( m_Game, m_Players[oldDealer] ) ); + + to.Send( new MahjongPlayersInfo( m_Game, to ) ); + + SendDealerChangedMessage(); + } + + private void SendDealerChangedMessage() + { + if ( Dealer != null ) + SendLocalizedMessage( 1062698, Dealer.Name ); // ~1_name~ is assigned the dealer. + } + + private void SendPlayerExitMessage( Mobile who ) + { + SendLocalizedMessage( 1062762, who.Name ); // ~1_name~ has left the game. + } + + public void SendPlayersPacket( bool players, bool spectators ) + { + foreach ( Mobile mobile in GetInGameMobiles( players, spectators ) ) + { + mobile.Send( new MahjongPlayersInfo( m_Game, mobile ) ); + } + } + + public void SendGeneralPacket( bool players, bool spectators ) + { + ArrayList mobiles = GetInGameMobiles( players, spectators ); + + if ( mobiles.Count == 0 ) + return; + + MahjongGeneralInfo generalInfo = new MahjongGeneralInfo( m_Game ); + + generalInfo.Acquire(); + + foreach ( Mobile mobile in mobiles ) + { + mobile.Send( generalInfo ); + } + + generalInfo.Release(); + } + + public void SendTilesPacket( bool players, bool spectators ) + { + foreach ( Mobile mobile in GetInGameMobiles( players, spectators ) ) + { + mobile.Send( new MahjongTilesInfo( m_Game, mobile ) ); + } + } + + public void SendTilePacket( MahjongTile tile, bool players, bool spectators ) + { + foreach ( Mobile mobile in GetInGameMobiles( players, spectators ) ) + { + mobile.Send( new MahjongTileInfo( tile, mobile ) ); + } + } + + public void SendRelievePacket( bool players, bool spectators ) + { + ArrayList mobiles = GetInGameMobiles( players, spectators ); + + if ( mobiles.Count == 0 ) + return; + + MahjongRelieve relieve = new MahjongRelieve( m_Game ); + + relieve.Acquire(); + + foreach ( Mobile mobile in mobiles ) + { + mobile.Send( relieve ); + } + + relieve.Release(); + } + + public void SendLocalizedMessage( int number ) + { + foreach ( Mobile mobile in GetInGameMobiles( true, true ) ) + { + mobile.SendLocalizedMessage( number ); + } + } + + public void SendLocalizedMessage( int number, string args ) + { + foreach ( Mobile mobile in GetInGameMobiles( true, true ) ) + { + mobile.SendLocalizedMessage( number, args ); + } + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + writer.Write( Seats ); + + for ( int i = 0; i < Seats; i++ ) + { + writer.Write( m_Players[i] ); + writer.Write( m_PublicHand[i] ); + writer.Write( m_Scores[i] ); + } + + writer.Write( m_DealerPosition ); + } + + public MahjongPlayers( MahjongGame game, GenericReader reader ) + { + m_Game = game; + m_Spectators = new ArrayList(); + + int version = reader.ReadInt(); + + int seats = reader.ReadInt(); + m_Players = new Mobile[seats]; + m_InGame = new bool[seats]; + m_PublicHand = new bool[seats]; + m_Scores = new int[seats]; + + for ( int i = 0; i < seats; i++ ) + { + m_Players[i] = reader.ReadMobile(); + m_PublicHand[i] = reader.ReadBool(); + m_Scores[i] = reader.ReadInt(); + } + + m_DealerPosition = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongTile.cs b/Scripts/Items/Games/Mahjong/MahjongTile.cs new file mode 100644 index 0000000..20f2dc2 --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongTile.cs @@ -0,0 +1,97 @@ +using System; +using Server; + +namespace Server.Engines.Mahjong +{ + public class MahjongTile + { + public static MahjongPieceDim GetDimensions( Point2D position, MahjongPieceDirection direction ) + { + if ( direction == MahjongPieceDirection.Up || direction == MahjongPieceDirection.Down ) + return new MahjongPieceDim( position, 20, 30 ); + else + return new MahjongPieceDim( position, 30, 20 ); + } + + private MahjongGame m_Game; + private int m_Number; + private MahjongTileType m_Value; + protected Point2D m_Position; + private int m_StackLevel; + private MahjongPieceDirection m_Direction; + private bool m_Flipped; + + public MahjongGame Game { get { return m_Game; } } + public int Number { get { return m_Number; } } + public MahjongTileType Value { get { return m_Value; } } + public Point2D Position { get { return m_Position; } } + public int StackLevel { get { return m_StackLevel; } } + public MahjongPieceDirection Direction { get { return m_Direction; } } + public bool Flipped { get { return m_Flipped; } } + + public MahjongTile( MahjongGame game, int number, MahjongTileType value, Point2D position, int stackLevel, MahjongPieceDirection direction, bool flipped ) + { + m_Game = game; + m_Number = number; + m_Value = value; + m_Position = position; + m_StackLevel = stackLevel; + m_Direction = direction; + m_Flipped = flipped; + } + + public MahjongPieceDim Dimensions + { + get { return GetDimensions( m_Position, m_Direction ); } + } + + public bool IsMovable + { + get { return m_Game.GetStackLevel( Dimensions ) <= m_StackLevel; } + } + + public void Move( Point2D position, MahjongPieceDirection direction, bool flip, int validHandArea ) + { + MahjongPieceDim dim = GetDimensions( position, direction ); + int curHandArea = Dimensions.GetHandArea(); + int newHandArea = dim.GetHandArea(); + + if ( !IsMovable || !dim.IsValid() || ( validHandArea >= 0 && ((curHandArea >= 0 && curHandArea != validHandArea) || (newHandArea >= 0 && newHandArea != validHandArea)) ) ) + return; + + m_Position = position; + m_Direction = direction; + m_StackLevel = -1; // Avoid self interference + m_StackLevel = m_Game.GetStackLevel( dim ) + 1; + m_Flipped = flip; + + m_Game.Players.SendTilePacket( this, true, true ); + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + writer.Write( m_Number ); + writer.Write( (int) m_Value ); + writer.Write( m_Position ); + writer.Write( m_StackLevel ); + writer.Write( (int) m_Direction ); + writer.Write( m_Flipped ); + } + + public MahjongTile( MahjongGame game, GenericReader reader ) + { + m_Game = game; + + int version = reader.ReadInt(); + + m_Number = reader.ReadInt(); + m_Value = (MahjongTileType) reader.ReadInt(); + m_Position = reader.ReadPoint2D(); + m_StackLevel = reader.ReadInt(); + m_Direction = (MahjongPieceDirection) reader.ReadInt(); + m_Flipped = reader.ReadBool(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongTileTypeGenerator.cs b/Scripts/Items/Games/Mahjong/MahjongTileTypeGenerator.cs new file mode 100644 index 0000000..93e0953 --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongTileTypeGenerator.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Engines.Mahjong +{ + public class MahjongTileTypeGenerator + { + private ArrayList m_LeftTileTypes; + + public ArrayList LeftTileTypes { get { return m_LeftTileTypes; } } + + public MahjongTileTypeGenerator( int count ) + { + m_LeftTileTypes = new ArrayList( 34 * count ); + + for ( int i = 1; i <= 34; i++ ) + { + for ( int j = 0; j < count; j++ ) + { + m_LeftTileTypes.Add( (MahjongTileType)i ); + } + } + } + + public MahjongTileType Next() + { + int random = Utility.Random( m_LeftTileTypes.Count ); + MahjongTileType next = (MahjongTileType)m_LeftTileTypes[random]; + m_LeftTileTypes.RemoveAt( random ); + + return next; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/MahjongWallBreakIndicator.cs b/Scripts/Items/Games/Mahjong/MahjongWallBreakIndicator.cs new file mode 100644 index 0000000..1cdeaf6 --- /dev/null +++ b/Scripts/Items/Games/Mahjong/MahjongWallBreakIndicator.cs @@ -0,0 +1,58 @@ +using System; +using Server; + +namespace Server.Engines.Mahjong +{ + public class MahjongWallBreakIndicator + { + public static MahjongPieceDim GetDimensions( Point2D position ) + { + return new MahjongPieceDim( position, 20, 20 ); + } + + private MahjongGame m_Game; + private Point2D m_Position; + + public MahjongGame Game { get { return m_Game; } } + public Point2D Position { get { return m_Position; } } + + public MahjongWallBreakIndicator( MahjongGame game, Point2D position ) + { + m_Game = game; + m_Position = position; + } + + public MahjongPieceDim Dimensions + { + get { return GetDimensions( m_Position ); } + } + + public void Move( Point2D position ) + { + MahjongPieceDim dim = GetDimensions( position ); + + if ( !dim.IsValid() ) + return; + + m_Position = position; + + m_Game.Players.SendGeneralPacket( true, true ); + } + + public void Save( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + writer.Write( m_Position ); + } + + public MahjongWallBreakIndicator( MahjongGame game, GenericReader reader ) + { + m_Game = game; + + int version = reader.ReadInt(); + + m_Position = reader.ReadPoint2D(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Games/Mahjong/Packets.cs b/Scripts/Items/Games/Mahjong/Packets.cs new file mode 100644 index 0000000..459ed8a --- /dev/null +++ b/Scripts/Items/Games/Mahjong/Packets.cs @@ -0,0 +1,208 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Engines.Mahjong +{ + public sealed class MahjongJoinGame : Packet + { + public MahjongJoinGame( MahjongGame game ) : base( 0xDA ) + { + EnsureCapacity( 9 ); + + m_Stream.Write( (int) game.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0x19 ); + } + } + + public sealed class MahjongPlayersInfo : Packet + { + public MahjongPlayersInfo( MahjongGame game, Mobile to ) : base( 0xDA ) + { + MahjongPlayers players = game.Players; + + EnsureCapacity( 11 + 45 * players.Seats ); + + m_Stream.Write( (int) game.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0x2 ); + + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) players.Seats ); + + int n = 0; + for ( int i = 0; i < players.Seats; i++ ) + { + Mobile mobile = players.GetPlayer( i ); + + if ( mobile != null ) + { + m_Stream.Write( (int) mobile.Serial ); + m_Stream.Write( players.DealerPosition == i ? (byte) 0x1 : (byte) 0x2 ); + m_Stream.Write( (byte) i ); + + if ( game.ShowScores || mobile == to ) + m_Stream.Write( (int) players.GetScore( i ) ); + else + m_Stream.Write( (int) 0 ); + + m_Stream.Write( (short) 0 ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( players.IsPublic( i ) ); + + m_Stream.WriteAsciiFixed( mobile.Name, 30 ); + m_Stream.Write( !players.IsInGamePlayer( i ) ); + + n++; + } + else if ( game.ShowScores ) + { + m_Stream.Write( (int) 0 ); + m_Stream.Write( (byte) 0x2 ); + m_Stream.Write( (byte) i ); + + m_Stream.Write( (int) players.GetScore( i ) ); + + m_Stream.Write( (short) 0 ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( players.IsPublic( i ) ); + + m_Stream.WriteAsciiFixed( "", 30 ); + m_Stream.Write( true ); + + n++; + } + } + + if ( n != players.Seats ) + { + m_Stream.Seek( 10, System.IO.SeekOrigin.Begin ); + m_Stream.Write( (byte) n ); + } + } + } + + public sealed class MahjongGeneralInfo : Packet + { + public MahjongGeneralInfo( MahjongGame game ) : base( 0xDA ) + { + EnsureCapacity( 13 ); + + m_Stream.Write( (int) game.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0x5 ); + + m_Stream.Write( (short) 0 ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (byte) ((game.ShowScores ? 0x1 : 0x0) | (game.SpectatorVision ? 0x2 : 0x0)) ); + + m_Stream.Write( (byte) game.Dices.First ); + m_Stream.Write( (byte) game.Dices.Second ); + + m_Stream.Write( (byte) game.DealerIndicator.Wind ); + m_Stream.Write( (short) game.DealerIndicator.Position.Y ); + m_Stream.Write( (short) game.DealerIndicator.Position.X ); + m_Stream.Write( (byte) game.DealerIndicator.Direction ); + + m_Stream.Write( (short) game.WallBreakIndicator.Position.Y ); + m_Stream.Write( (short) game.WallBreakIndicator.Position.X ); + } + } + + public sealed class MahjongTilesInfo : Packet + { + public MahjongTilesInfo( MahjongGame game, Mobile to ) : base( 0xDA ) + { + MahjongTile[] tiles = game.Tiles; + MahjongPlayers players = game.Players; + + EnsureCapacity( 11 + 9 * tiles.Length ); + + m_Stream.Write( (int) game.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0x4 ); + + m_Stream.Write( (short) tiles.Length ); + + foreach ( MahjongTile tile in tiles ) + { + m_Stream.Write( (byte) tile.Number ); + + if ( tile.Flipped ) + { + int hand = tile.Dimensions.GetHandArea(); + + if ( hand < 0 || players.IsPublic( hand ) || players.GetPlayer( hand ) == to || (game.SpectatorVision && players.IsSpectator( to )) ) + m_Stream.Write( (byte)tile.Value ); + else + m_Stream.Write( (byte) 0 ); + } + else + { + m_Stream.Write( (byte) 0 ); + } + + m_Stream.Write( (short) tile.Position.Y ); + m_Stream.Write( (short) tile.Position.X ); + m_Stream.Write( (byte) tile.StackLevel ); + m_Stream.Write( (byte) tile.Direction ); + + m_Stream.Write( tile.Flipped ? (byte) 0x10 : (byte) 0x0 ); + } + } + } + + public sealed class MahjongTileInfo : Packet + { + public MahjongTileInfo( MahjongTile tile, Mobile to ) : base( 0xDA ) + { + MahjongGame game = tile.Game; + MahjongPlayers players = game.Players; + + EnsureCapacity( 18 ); + + m_Stream.Write( (int) tile.Game.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0x3 ); + + m_Stream.Write( (byte) tile.Number ); + + if ( tile.Flipped ) + { + int hand = tile.Dimensions.GetHandArea(); + + if ( hand < 0 || players.IsPublic( hand ) || players.GetPlayer( hand ) == to || (game.SpectatorVision && players.IsSpectator( to )) ) + m_Stream.Write( (byte)tile.Value ); + else + m_Stream.Write( (byte) 0 ); + } + else + { + m_Stream.Write( (byte) 0 ); + } + + m_Stream.Write( (short) tile.Position.Y ); + m_Stream.Write( (short) tile.Position.X ); + m_Stream.Write( (byte) tile.StackLevel ); + m_Stream.Write( (byte) tile.Direction ); + + m_Stream.Write( tile.Flipped ? (byte) 0x10 : (byte) 0x0 ); + } + } + + public sealed class MahjongRelieve : Packet + { + public MahjongRelieve( MahjongGame game ) : base( 0xDA ) + { + EnsureCapacity( 9 ); + + m_Stream.Write( (int) game.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0x1A ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Amber.cs b/Scripts/Items/Gems/Amber.cs new file mode 100644 index 0000000..202efe3 --- /dev/null +++ b/Scripts/Items/Gems/Amber.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Amber : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Amber() : this( 1 ) + { + } + + [Constructable] + public Amber( int amount ) : base( 0xF25 ) + { + Gems = GemType.Amber; + Stackable = true; + Amount = amount; + } + + public Amber( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if (version < 1) + Gems = GemType.Amber; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Amethyst.cs b/Scripts/Items/Gems/Amethyst.cs new file mode 100644 index 0000000..5bccbef --- /dev/null +++ b/Scripts/Items/Gems/Amethyst.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Amethyst : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Amethyst() : this( 1 ) + { + } + + [Constructable] + public Amethyst( int amount ) : base( 0xF16 ) + { + Stackable = true; + Amount = amount; + Gems = GemType.Amethyst; + } + + public Amethyst( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.Amethyst; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Citrine.cs b/Scripts/Items/Gems/Citrine.cs new file mode 100644 index 0000000..19b6849 --- /dev/null +++ b/Scripts/Items/Gems/Citrine.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Citrine : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Citrine() : this( 1 ) + { + } + + [Constructable] + public Citrine( int amount ) : base( 0xF15 ) + { + Stackable = true; + Amount = amount; + Gems = GemType.Citrine; + } + + public Citrine( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.Citrine; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Diamond.cs b/Scripts/Items/Gems/Diamond.cs new file mode 100644 index 0000000..5b0038f --- /dev/null +++ b/Scripts/Items/Gems/Diamond.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Diamond : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Diamond() : this( 1 ) + { + } + + [Constructable] + public Diamond( int amount ) : base( 0xF26 ) + { + Gems = GemType.Diamond; + Stackable = true; + Amount = amount; + } + + public Diamond( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if (version < 1) + Gems = GemType.Diamond; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Emerald.cs b/Scripts/Items/Gems/Emerald.cs new file mode 100644 index 0000000..aa1a854 --- /dev/null +++ b/Scripts/Items/Gems/Emerald.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Emerald : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Emerald() : this( 1 ) + { + } + + [Constructable] + public Emerald( int amount ) : base( 0xF10 ) + { + Stackable = true; + Amount = amount; + Gems = GemType.Emerald; + } + + public Emerald( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.Emerald; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Ruby.cs b/Scripts/Items/Gems/Ruby.cs new file mode 100644 index 0000000..f9ae971 --- /dev/null +++ b/Scripts/Items/Gems/Ruby.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Ruby : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Ruby() : this( 1 ) + { + } + + [Constructable] + public Ruby( int amount ) : base( 0xF13 ) + { + Stackable = true; + Amount = amount; + Gems = GemType.Ruby; + } + + public Ruby( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.Ruby; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Sapphire.cs b/Scripts/Items/Gems/Sapphire.cs new file mode 100644 index 0000000..12971cb --- /dev/null +++ b/Scripts/Items/Gems/Sapphire.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Sapphire : BaseGem + { + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Sapphire() : this( 1 ) + { + } + + [Constructable] + public Sapphire( int amount ) : base( 0xF19 ) + { + Stackable = true; + Amount = amount; + Gems = GemType.Sapphire; + } + + public Sapphire( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.Sapphire; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/StarSapphire.cs b/Scripts/Items/Gems/StarSapphire.cs new file mode 100644 index 0000000..59d9760 --- /dev/null +++ b/Scripts/Items/Gems/StarSapphire.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StarSapphire : BaseGem + { + GemType Gem { get { return GemType.StarSapphire; } } + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public StarSapphire() : this( 1 ) + { + } + + [Constructable] + public StarSapphire( int amount ) : base( 0xF21 ) + { + Stackable = true; + Amount = amount; + Gems = GemType.StarSapphire; + } + + public StarSapphire( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.StarSapphire; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Gems/Tourmaline.cs b/Scripts/Items/Gems/Tourmaline.cs new file mode 100644 index 0000000..5bb738f --- /dev/null +++ b/Scripts/Items/Gems/Tourmaline.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Tourmaline : BaseGem + { + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Tourmaline() : this( 1 ) + { + } + + [Constructable] + public Tourmaline( int amount ) : base( 0xF2D ) + { + Stackable = true; + Amount = amount; + Gems = GemType.Tourmaline; + } + + public Tourmaline( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1) + Gems = GemType.Tourmaline; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Guilds/GuildDeed.cs b/Scripts/Items/Guilds/GuildDeed.cs new file mode 100644 index 0000000..f311a72 --- /dev/null +++ b/Scripts/Items/Guilds/GuildDeed.cs @@ -0,0 +1,143 @@ +using System; +using Server.Network; +using Server.Prompts; +using Server.Guilds; +using Server.Multis; +using Server.Regions; + +namespace Server.Items +{ + public class GuildDeed : Item + { + public override int LabelNumber{ get{ return 1041055; } } // a guild deed + + [Constructable] + public GuildDeed() : base( 0x14F0 ) + { + Weight = 1.0; + } + + public GuildDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 0.0 ) + Weight = 1.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if( Guild.NewGuildSystem ) + return; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.Guild != null ) + { + from.SendLocalizedMessage( 501137 ); // You must resign from your current guild before founding another! + } + else + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house == null ) + { + from.SendLocalizedMessage( 501138 ); // You can only place a guildstone in a house. + } + else if ( house.FindGuildstone() != null ) + { + from.SendLocalizedMessage( 501142 );//Only one guildstone may reside in a given house. + } + else if ( !house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 501141 ); // You can only place a guildstone in a house you own! + } + else + { + from.SendLocalizedMessage( 1013060 ); // Enter new guild name (40 characters max): + from.Prompt = new InternalPrompt( this ); + } + } + } + + private class InternalPrompt : Prompt + { + private GuildDeed m_Deed; + + public InternalPrompt( GuildDeed deed ) + { + m_Deed = deed; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Deed.Deleted ) + return; + + if ( !m_Deed.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.Guild != null ) + { + from.SendLocalizedMessage( 501137 ); // You must resign from your current guild before founding another! + } + else + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house == null ) + { + from.SendLocalizedMessage( 501138 ); // You can only place a guildstone in a house. + } + else if ( house.FindGuildstone() != null ) + { + from.SendLocalizedMessage( 501142 );//Only one guildstone may reside in a given house. + } + else if ( !house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 501141 ); // You can only place a guildstone in a house you own! + } + else + { + m_Deed.Delete(); + + if ( text.Length > 40 ) + text = text.Substring( 0, 40 ); + + Guild guild = new Guild( from, text, "none" ); + + from.Guild = guild; + from.GuildTitle = "Guildmaster"; + + Guildstone stone = new Guildstone( guild ); + + stone.MoveToWorld( from.Location, from.Map ); + + guild.Guildstone = stone; + } + } + } + + public override void OnCancel( Mobile from ) + { + from.SendLocalizedMessage( 501145 ); // Placement of guildstone cancelled. + } + } + } +} diff --git a/Scripts/Items/Guilds/GuildTeleporter.cs b/Scripts/Items/Guilds/GuildTeleporter.cs new file mode 100644 index 0000000..cd934d1 --- /dev/null +++ b/Scripts/Items/Guilds/GuildTeleporter.cs @@ -0,0 +1,105 @@ +using System; +using Server.Network; +using Server.Prompts; +using Server.Guilds; +using Server.Multis; +using Server.Regions; + +namespace Server.Items +{ + public class GuildTeleporter : Item + { + private Item m_Stone; + + public override int LabelNumber{ get{ return 1041054; } } // guildstone teleporter + + [Constructable] + public GuildTeleporter() : this( null ) + { + } + + public GuildTeleporter( Item stone ) : base( 0x1869 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + + m_Stone = stone; + } + + public GuildTeleporter( Serial serial ) : base( serial ) + { + } + + public override bool DisplayLootType{ get{ return false; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Stone ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Stone = reader.ReadItem(); + + break; + } + } + + if ( Weight == 0.0 ) + Weight = 1.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if( Guild.NewGuildSystem ) + return; + + Guildstone stone = m_Stone as Guildstone; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( stone == null || stone.Deleted || stone.Guild == null || stone.Guild.Teleporter != this ) + { + from.SendLocalizedMessage( 501197 ); // This teleporting object can not determine what guildstone to teleport + } + else + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house == null ) + { + from.SendLocalizedMessage( 501138 ); // You can only place a guildstone in a house. + } + else if ( !house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 501141 ); // You can only place a guildstone in a house you own! + } + else if( house.FindGuildstone() != null ) + { + from.SendLocalizedMessage( 501142 );//Only one guildstone may reside in a given house. + } + else + { + m_Stone.MoveToWorld( from.Location, from.Map ); + Delete(); + stone.Guild.Teleporter = null; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Guilds/Guildstone.cs b/Scripts/Items/Guilds/Guildstone.cs new file mode 100644 index 0000000..b38b4b4 --- /dev/null +++ b/Scripts/Items/Guilds/Guildstone.cs @@ -0,0 +1,454 @@ +using System; +using System.IO; +using Server.Gumps; +using Server.Guilds; +using Server.Network; +using Server.Factions; +using Server.Multis; + +namespace Server.Items +{ + public class Guildstone : Item, IAddon, IChopable + { + private Guild m_Guild; + private string m_GuildName; + private string m_GuildAbbrev; + + [CommandProperty(AccessLevel.GameMaster)] + public string GuildName + { + get { return m_GuildName; } + set { m_GuildName = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string GuildAbbrev + { + get { return m_GuildAbbrev; } + set { m_GuildAbbrev = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Guild Guild + { + get + { + return m_Guild; + } + } + + public override int LabelNumber { get { return 1041429; } } // a guildstone + + public Guildstone(Guild g) + : this(g, g.Name, g.Abbreviation) + { + } + + public Guildstone(Guild g, string guildName, string abbrev) + : base(Guild.NewGuildSystem ? 0xED6 : 0xED4) + { + m_Guild = g; + m_GuildName = guildName; + m_GuildAbbrev = abbrev; + + Movable = false; + } + + public Guildstone(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + if (m_Guild != null && !m_Guild.Disbanded) + { + m_GuildName = m_Guild.Name; + m_GuildAbbrev = m_Guild.Abbreviation; + } + + writer.Write((int)3); // version + + writer.Write(m_BeforeChangeover); + + writer.Write(m_GuildName); + writer.Write(m_GuildAbbrev); + + writer.Write(m_Guild); + } + + private bool m_BeforeChangeover; + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_BeforeChangeover = reader.ReadBool(); + goto case 2; + } + case 2: + { + m_GuildName = reader.ReadString(); + m_GuildAbbrev = reader.ReadString(); + + goto case 1; + } + case 1: + { + m_Guild = reader.ReadGuild() as Guild; + + goto case 0; + } + case 0: + { + break; + } + } + + if (Guild.NewGuildSystem && ItemID == 0xED4) + ItemID = 0xED6; + + if (version <= 2) + m_BeforeChangeover = true; + + if (Guild.NewGuildSystem && m_BeforeChangeover) + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(AddToHouse)); + + if (!Guild.NewGuildSystem && m_Guild == null) + this.Delete(); + } + + private void AddToHouse() + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (Guild.NewGuildSystem && m_BeforeChangeover && house != null && !house.Addons.Contains(this)) + { + house.Addons.Add(this); + m_BeforeChangeover = false; + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Guild != null && !m_Guild.Disbanded) + { + string name; + string abbr; + + if ((name = m_Guild.Name) == null || (name = name.Trim()).Length <= 0) + name = "(unnamed)"; + + if ((abbr = m_Guild.Abbreviation) == null || (abbr = abbr.Trim()).Length <= 0) + abbr = ""; + + //list.Add( 1060802, Utility.FixHtml( name ) ); // Guild name: ~1_val~ + list.Add(1060802, String.Format("{0} [{1}]", Utility.FixHtml(name), Utility.FixHtml(abbr))); + } + else if (m_GuildName != null && m_GuildAbbrev != null) + { + list.Add(1060802, String.Format("{0} [{1}]", Utility.FixHtml(m_GuildName), Utility.FixHtml(m_GuildAbbrev))); + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Guild != null && !m_Guild.Disbanded) + { + string name; + + if ((name = m_Guild.Name) == null || (name = name.Trim()).Length <= 0) + name = "(unnamed)"; + + this.LabelTo(from, name); + } + else if (m_GuildName != null) + { + this.LabelTo(from, m_GuildName); + } + } + + public override void OnAfterDelete() + { + if (!Guild.NewGuildSystem && m_Guild != null && !m_Guild.Disbanded) + m_Guild.Disband(); + } + + public override void OnDoubleClick(Mobile from) + { + if (Guild.NewGuildSystem) + return; + + if (m_Guild == null || m_Guild.Disbanded) + { + Delete(); + } + else if (!from.InRange(GetWorldLocation(), 2)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else if (m_Guild.Accepted.Contains(from)) + { + #region Factions + PlayerState guildState = PlayerState.Find(m_Guild.Leader); + PlayerState targetState = PlayerState.Find(from); + + Faction guildFaction = (guildState == null ? null : guildState.Faction); + Faction targetFaction = (targetState == null ? null : targetState.Faction); + + if (guildFaction != targetFaction || (targetState != null && targetState.IsLeaving)) + return; + + if (guildState != null && targetState != null) + targetState.Leaving = guildState.Leaving; + #endregion + + m_Guild.Accepted.Remove(from); + m_Guild.AddMember(from); + + GuildGump.EnsureClosed(from); + from.SendGump(new GuildGump(from, m_Guild)); + } + else if (from.AccessLevel < AccessLevel.GameMaster && !m_Guild.IsMember(from)) + { + from.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, 501158, "", "")); // You are not a member ... + } + else + { + GuildGump.EnsureClosed(from); + from.SendGump(new GuildGump(from, m_Guild)); + } + } + + #region IAddon Members + public Item Deed + { + get { return new GuildstoneDeed(m_Guild, m_GuildName, m_GuildAbbrev); } + } + + public bool CouldFit(IPoint3D p, Map map) + { + return map.CanFit(p.X, p.Y, p.Z, this.ItemData.Height); + } + + #endregion + + #region IChopable Members + + public void OnChop(Mobile from) + { + if (!Guild.NewGuildSystem) + return; + + BaseHouse house = BaseHouse.FindHouseAt(this); + + if ((house == null && m_BeforeChangeover) || (house != null && house.IsOwner(from) && house.Addons.Contains(this))) + { + Effects.PlaySound(GetWorldLocation(), Map, 0x3B3); + from.SendLocalizedMessage(500461); // You destroy the item. + + Delete(); + + if (house != null && house.Addons.Contains(this)) + house.Addons.Remove(this); + + Item deed = Deed; + + if (deed != null) + { + from.AddToBackpack(deed); + } + } + } + + #endregion + } + + [Flipable(0x14F0, 0x14EF)] + public class GuildstoneDeed : Item + { + public override int LabelNumber { get { return 1041233; } } // deed to a guildstone + + private Guild m_Guild; + private string m_GuildName; + private string m_GuildAbbrev; + + [CommandProperty(AccessLevel.GameMaster)] + public string GuildName + { + get { return m_GuildName; } + set { m_GuildName = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string GuildAbbrev + { + get { return m_GuildAbbrev; } + set { m_GuildAbbrev = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Guild Guild + { + get + { + return m_Guild; + } + } + + [Constructable] + public GuildstoneDeed() + : this(null, null) + { + } + + [Constructable] + public GuildstoneDeed(string guildName, string abbrev) + : this(null, guildName, abbrev) + { + } + + public GuildstoneDeed(Guild g, string guildName, string abbrev) + : base(0x14F0) + { + m_Guild = g; + m_GuildName = guildName; + m_GuildAbbrev = abbrev; + + Weight = 1.0; + } + + public GuildstoneDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + if (m_Guild != null && !m_Guild.Disbanded) + { + m_GuildName = m_Guild.Name; + m_GuildAbbrev = m_Guild.Abbreviation; + } + + writer.Write((int)1); // version + + writer.Write(m_GuildName); + writer.Write(m_GuildAbbrev); + + writer.Write(m_Guild); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_GuildName = reader.ReadString(); + m_GuildAbbrev = reader.ReadString(); + + m_Guild = reader.ReadGuild() as Guild; + + break; + } + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Guild != null && !m_Guild.Disbanded) + { + string name; + string abbr; + + if ((name = m_Guild.Name) == null || (name = name.Trim()).Length <= 0) + name = "(unnamed)"; + + if ((abbr = m_Guild.Abbreviation) == null || (abbr = abbr.Trim()).Length <= 0) + abbr = ""; + + //list.Add( 1060802, Utility.FixHtml( name ) ); // Guild name: ~1_val~ + list.Add(1060802, String.Format("{0} [{1}]", Utility.FixHtml(name), Utility.FixHtml(abbr))); + } + else if (m_GuildName != null && m_GuildAbbrev != null) + { + list.Add(1060802, String.Format("{0} [{1}]", Utility.FixHtml(m_GuildName), Utility.FixHtml(m_GuildAbbrev))); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + if (house != null && house.IsOwner(from)) + { + from.SendLocalizedMessage(1062838); // Where would you like to place this decoration? + from.BeginTarget(-1, true, Targeting.TargetFlags.None, new TargetStateCallback(Placement_OnTarget), null); + } + else + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public void Placement_OnTarget(Mobile from, object targeted, object state) + { + IPoint3D p = targeted as IPoint3D; + + if (p == null || Deleted) + return; + + Point3D loc = new Point3D(p); + + BaseHouse house = BaseHouse.FindHouseAt(loc, from.Map, 16); + + if (IsChildOf(from.Backpack)) + { + if (house != null && house.IsOwner(from)) + { + Item addon = new Guildstone(m_Guild, m_GuildName, m_GuildAbbrev); + + addon.MoveToWorld(loc, from.Map); + + house.Addons.Add(addon); + Delete(); + } + else + { + from.SendLocalizedMessage(1042036); // That location is not in your house. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Artifacts/BraceletOfHealth.cs b/Scripts/Items/Jewels/Artifacts/BraceletOfHealth.cs new file mode 100644 index 0000000..ee9cb64 --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/BraceletOfHealth.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BraceletOfHealth : GoldBracelet + { + public override int LabelNumber{ get{ return 1061103; } } // Bracelet of Health + public override int ArtifactRarity{ get{ return 11; } } + + [Constructable] + public BraceletOfHealth() + { + Hue = 0x21; + Attributes.BonusHits = 5; + Attributes.RegenHits = 10; + } + + public BraceletOfHealth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Artifacts/Craftable/EssenceOfBattle.cs b/Scripts/Items/Jewels/Artifacts/Craftable/EssenceOfBattle.cs new file mode 100644 index 0000000..2f3a191 --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/Craftable/EssenceOfBattle.cs @@ -0,0 +1,36 @@ +using System; + +namespace Server.Items +{ + public class EssenceOfBattle : GoldRing + { + public override int LabelNumber{ get{ return 1072935; } } // Essence of Battle + + [Constructable] + public EssenceOfBattle() + { + Hue = 0x550; + Attributes.BonusDex = 7; + Attributes.BonusStr = 7; + Attributes.WeaponDamage = 30; + } + + public EssenceOfBattle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Jewels/Artifacts/Craftable/PendantOfTheMagi.cs b/Scripts/Items/Jewels/Artifacts/Craftable/PendantOfTheMagi.cs new file mode 100644 index 0000000..22cf5ac --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/Craftable/PendantOfTheMagi.cs @@ -0,0 +1,38 @@ +using System; + +namespace Server.Items +{ + public class PendantOfTheMagi : GoldNecklace + { + public override int LabelNumber{ get{ return 1072937; } } // Pendant of the Magi + + [Constructable] + public PendantOfTheMagi() + { + Hue = 0x48D; + Attributes.BonusInt = 10; + Attributes.RegenMana = 3; + Attributes.SpellDamage = 5; + Attributes.LowerManaCost = 10; + Attributes.LowerRegCost = 30; + } + + public PendantOfTheMagi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Jewels/Artifacts/Craftable/ResillientBracer.cs b/Scripts/Items/Jewels/Artifacts/Craftable/ResillientBracer.cs new file mode 100644 index 0000000..85f8072 --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/Craftable/ResillientBracer.cs @@ -0,0 +1,41 @@ +using System; + +namespace Server.Items +{ + public class ResilientBracer : GoldBracelet + { + public override int LabelNumber{ get{ return 1072933; } } // Resillient Bracer + + public override int PhysicalResistance{ get { return 20; } } + + [Constructable] + public ResilientBracer() + { + Hue = 0x488; + + SkillBonuses.SetValues( 0, SkillName.MagicResist, 15.0 ); + + Attributes.BonusHits = 5; + Attributes.RegenHits = 2; + Attributes.DefendChance = 10; + } + + public ResilientBracer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Jewels/Artifacts/OrnamentOfTheMagician.cs b/Scripts/Items/Jewels/Artifacts/OrnamentOfTheMagician.cs new file mode 100644 index 0000000..1831f0a --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/OrnamentOfTheMagician.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrnamentOfTheMagician : GoldBracelet + { + public override int LabelNumber{ get{ return 1061105; } } // Ornament of the Magician + public override int ArtifactRarity{ get{ return 11; } } + + [Constructable] + public OrnamentOfTheMagician() + { + Hue = 0x554; + Attributes.CastRecovery = 3; + Attributes.CastSpeed = 2; + Attributes.LowerManaCost = 10; + Attributes.LowerRegCost = 20; + Resistances.Energy = 15; + } + + public OrnamentOfTheMagician( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 0x12B ) + Hue = 0x554; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Artifacts/RingOfTheElements.cs b/Scripts/Items/Jewels/Artifacts/RingOfTheElements.cs new file mode 100644 index 0000000..f32a856 --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/RingOfTheElements.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RingOfTheElements : GoldRing + { + public override int LabelNumber{ get{ return 1061104; } } // Ring of the Elements + public override int ArtifactRarity{ get{ return 11; } } + + [Constructable] + public RingOfTheElements() + { + Hue = 0x4E9; + Attributes.Luck = 100; + Resistances.Fire = 16; + Resistances.Cold = 16; + Resistances.Poison = 16; + Resistances.Energy = 16; + } + + public RingOfTheElements( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Artifacts/RingOfTheVile.cs b/Scripts/Items/Jewels/Artifacts/RingOfTheVile.cs new file mode 100644 index 0000000..d09cc99 --- /dev/null +++ b/Scripts/Items/Jewels/Artifacts/RingOfTheVile.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RingOfTheVile : GoldRing + { + public override int LabelNumber{ get{ return 1061102; } } // Ring of the Vile + public override int ArtifactRarity{ get{ return 11; } } + + [Constructable] + public RingOfTheVile() + { + Hue = 0x4F7; + Attributes.BonusDex = 8; + Attributes.RegenStam = 6; + Attributes.AttackChance = 15; + Resistances.Poison = 20; + } + + public RingOfTheVile( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 0x4F4 ) + Hue = 0x4F7; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/BaseJewel.cs b/Scripts/Items/Jewels/BaseJewel.cs new file mode 100644 index 0000000..461f86a --- /dev/null +++ b/Scripts/Items/Jewels/BaseJewel.cs @@ -0,0 +1,696 @@ +using System; +using Server.Engines.Craft; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Items +{ + public enum GemType + { + None, + StarSapphire, + Emerald, + Sapphire, + Ruby, + Citrine, + Amethyst, + Tourmaline, + Amber, + Diamond + } + + public abstract class BaseJewel : BaseWearable, ICraftable + { + private int m_MaxHitPoints; + private int m_HitPoints; + private Mobile m_Crafter; + private bool m_Identified; + private bool m_PlayerConstructed; + + private AosAttributes m_AosAttributes; + private AosElementAttributes m_AosResistances; + private AosSkillBonuses m_AosSkillBonuses; + private CraftResource m_Resource; + private GemType m_GemType; + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxHitPoints + { + get { return m_MaxHitPoints; } + set { m_MaxHitPoints = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitPoints + { + get + { + return m_HitPoints; + } + set + { + if (value != m_HitPoints && MaxHitPoints > 0) + { + m_HitPoints = value; + + if (m_HitPoints < 0) + Delete(); + else if (m_HitPoints > MaxHitPoints) + m_HitPoints = MaxHitPoints; + + InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Crafter + { + get { return m_Crafter; } + set { m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.Player)] + public AosAttributes Attributes + { + get { return m_AosAttributes; } + set { } + } + + [CommandProperty(AccessLevel.GameMaster)] + public AosElementAttributes Resistances + { + get { return m_AosResistances; } + set { } + } + + [CommandProperty(AccessLevel.GameMaster)] + public AosSkillBonuses SkillBonuses + { + get { return m_AosSkillBonuses; } + set { } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; Hue = CraftResources.GetHue(m_Resource); GetNameProperty(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public GemType GemType + { + get { return m_GemType; } + set { m_GemType = value; InvalidateProperties(); GetNameProperty(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool PlayerConstructed + { + get { return m_PlayerConstructed; } + set { m_PlayerConstructed = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Identified + { + get { return m_Identified; } + set { m_Identified = value; InvalidateProperties(); } + } + #region difficulty + //Plume ajout de la difficult� + [CommandProperty(AccessLevel.GameMaster)] + public int JewelDifficulty + { + get + { + int difficulty = 0; + + if (Attributes.AttackChance != 0) + difficulty++; + if (Attributes.BonusDex != 0) + difficulty++; + if (Attributes.BonusHits != 0) + difficulty++; + if (Attributes.BonusInt != 0) + difficulty++; + if (Attributes.BonusMana != 0) + difficulty++; + if (Attributes.BonusStam != 0) + difficulty++; + if (Attributes.BonusStr != 0) + difficulty++; + if (Attributes.CastRecovery != 0) + difficulty++; + if (Attributes.CastSpeed != 0) + difficulty++; + if (Attributes.DefendChance != 0) + difficulty++; + if (Attributes.EnhancePotions != 0) + difficulty++; + if (Attributes.LowerManaCost != 0) + difficulty++; + if (Attributes.LowerRegCost != 0) + difficulty++; + if (Attributes.Luck != 0) + difficulty++; + if (Attributes.NightSight != 0) + difficulty++; + if (Attributes.ReflectPhysical != 0) + difficulty++; + if (Attributes.RegenHits != 0) + difficulty++; + if (Attributes.RegenMana != 0) + difficulty++; + if (Attributes.RegenStam != 0) + difficulty++; + if (Attributes.SpellChanneling != 0) + difficulty++; + if (Attributes.SpellDamage != 0) + difficulty++; + if (Attributes.WeaponDamage != 0) + difficulty++; + if (Attributes.WeaponSpeed != 0) + difficulty++; + if (Resistances.Chaos != 0) + difficulty++; + if (Resistances.Cold != 0) + difficulty++; + if (Resistances.Direct != 0) + difficulty++; + if (Resistances.Energy != 0) + difficulty++; + if (Resistances.Fire != 0) + difficulty++; + if (Resistances.Physical != 0) + difficulty++; + if (Resistances.Poison != 0) + difficulty++; + if (SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (SkillBonuses.Skill_5_Value != 0) + difficulty++; + + if (difficulty > 5) + difficulty = 5; + + return difficulty; + } + } + #endregion + public override int PhysicalResistance { get { return m_AosResistances.Physical; } } + public override int FireResistance { get { return m_AosResistances.Fire; } } + public override int ColdResistance { get { return m_AosResistances.Cold; } } + public override int PoisonResistance { get { return m_AosResistances.Poison; } } + public override int EnergyResistance { get { return m_AosResistances.Energy; } } + public virtual int BaseGemTypeNumber { get { return 0; } } + + public virtual int InitMinHits { get { return 0; } } + public virtual int InitMaxHits { get { return 0; } } + + public override int LabelNumber + { + get + { + if (m_GemType == GemType.None) + return base.LabelNumber; + + return BaseGemTypeNumber + (int)m_GemType - 1; + } + } + // Plume : Ajout du sertissage + public override void OnDoubleClick(Mobile from) + { + if (PlayerConstructed && GemType == GemType.None) + { + if (from.Skills[SkillName.Tinkering].Value > 80) + { + from.BeginTarget(1, false, TargetFlags.None, new TargetCallback(SertissageTarget)); + from.SendMessage("Quelle pierre voulez-vous y sertir?"); + } + else + from.SendMessage("Un bijoutier exp�riment� pourrait y sertir une pierre pr�cieuse"); + return; + } + + base.OnDoubleClick(from); + } + + public void SertissageTarget(Mobile from, object obj) + { + if (!(obj is BaseGem)) + { + from.SendMessage("Ceci ne pourrait �tre ench�ss� sur un bijou."); + return; + } + + BaseGem targ = obj as BaseGem; + int amount = 1; + + if (this is BaseBracelet) + amount = 4; + else if (this is BaseRing) + amount = 1; + else if (this is BaseNecklace) + amount = 3; + else if (this is BaseEarrings) + amount = 2; + else if (this is Diademe) + amount = 1; + else if (this is DiademeDecore) + amount = 4; + + if (targ.Amount < amount) + { + from.SendMessage("Vous n'avez pas assez de pierres pour sertir un bijou"); + return; + } + if (!from.CheckSkill(SkillName.Tinkering, 60.0, 120.0)) + { + from.SendMessage("Vous ne r�ussisez pas � sertir le bijou et brisez les pierres"); + targ.Consume(amount); + return; + } + from.SendMessage("Vous sertissez le bijou"); + + GemType = targ.Gems; + + targ.Consume(amount); + return; + } + + public void GetNameProperty() + { + if (!PlayerConstructed) + return; + + string metaltype = ""; + string gemtype = ""; + + if (Resource != CraftResource.None) + metaltype = CraftResources.GetName(m_Resource); + + if (Resource == CraftResource.MIron) + Hue = 2105; + if (Resource == CraftResource.MGold) + Hue = 0; + + + switch (GemType) + { + case GemType.Amber: gemtype = "d'ambres"; break; + case GemType.Amethyst: gemtype = "d'am�thystes"; break; + case GemType.Citrine: gemtype = "de citrines"; break; + case GemType.Diamond: gemtype = "de diamants"; break; + case GemType.Emerald: gemtype = "d'�meraudes"; break; + case GemType.Ruby: gemtype = "de rubis"; break; + case GemType.Sapphire: gemtype = "de saphirs"; break; + case GemType.StarSapphire: gemtype = "de saphirs �toil�s"; break; + case GemType.Tourmaline: gemtype = "de tourmalines"; break; + } + + if (this is GoldBracelet) + Name = string.Format("Un bracelet{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " serti " + gemtype : ""); + else if (this is GoldRing) + Name = string.Format("Une bague{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " sertie " + gemtype : ""); + else if (this is GoldBeadNecklace) + Name = string.Format("Un collier de perle{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " serti " + gemtype : ""); + else if (this is GoldNecklace) + Name = string.Format("Un collier{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " serti " + gemtype : ""); + else if (this is GoldEarrings) + Name = string.Format("Des boucles d'oreille{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " serties " + gemtype : ""); + else if (this is Diademe) + Name = string.Format("Un diad�me{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " serti " + gemtype : ""); + else if (this is DiademeDecore) + Name = string.Format("Un diad�me{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " richement serti " + gemtype : ""); + else + Name = string.Format("Un bijou{0}{1}", Resource != CraftResource.None ? " en " + metaltype : "", GemType != GemType.None ? " serti " + gemtype : ""); + + } + + public override void OnAfterDuped(Item newItem) + { + BaseJewel jewel = newItem as BaseJewel; + + if (jewel == null) + return; + + jewel.m_AosAttributes = new AosAttributes(newItem, m_AosAttributes); + jewel.m_AosResistances = new AosElementAttributes(newItem, m_AosResistances); + jewel.m_AosSkillBonuses = new AosSkillBonuses(newItem, m_AosSkillBonuses); + } + + public virtual int ArtifactRarity { get { return 0; } } + + public BaseJewel(int itemID, Layer layer) + : base(itemID) + { + m_AosAttributes = new AosAttributes(this); + m_AosResistances = new AosElementAttributes(this); + m_AosSkillBonuses = new AosSkillBonuses(this); + m_Resource = CraftResource.MIron; + m_GemType = GemType.None; + m_Identified = true; + m_Crafter = null; + Layer = layer; + m_HitPoints = m_MaxHitPoints = Utility.RandomMinMax(InitMinHits, InitMaxHits); + } + + public override bool CanEquip(Mobile from) + { + if (!m_Identified) + { + from.SendMessage("Ce bijou vous semble inconnu"); + return false; + } + return base.CanEquip(from); + + } + + public override void OnAdded(object parent) + { + if (Core.AOS && parent is Mobile) + { + Mobile from = (Mobile)parent; + + m_AosSkillBonuses.AddTo(from); + + int strBonus = m_AosAttributes.BonusStr; + int dexBonus = m_AosAttributes.BonusDex; + int intBonus = m_AosAttributes.BonusInt; + + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) + { + string modName = this.Serial.ToString(); + + if (strBonus != 0) + from.AddStatMod(new StatMod(StatType.Str, modName + "Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + from.AddStatMod(new StatMod(StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + from.AddStatMod(new StatMod(StatType.Int, modName + "Int", intBonus, TimeSpan.Zero)); + } + + from.CheckStatTimers(); + } + } + + public override void OnRemoved(object parent) + { + if (Core.AOS && parent is Mobile) + { + Mobile from = (Mobile)parent; + + m_AosSkillBonuses.Remove(); + + string modName = this.Serial.ToString(); + + from.RemoveStatMod(modName + "Str"); + from.RemoveStatMod(modName + "Dex"); + from.RemoveStatMod(modName + "Int"); + + from.CheckStatTimers(); + } + } + + public BaseJewel(Serial serial) + : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Identified) + { + m_AosSkillBonuses.GetProperties(list); + + int prop; + + if ((prop = ArtifactRarity) > 0) + list.Add(1061078, prop.ToString()); // artifact rarity ~1_val~ + + if ((prop = m_AosAttributes.WeaponDamage) != 0) + list.Add(1060401, prop.ToString()); // damage increase ~1_val~% + + if ((prop = m_AosAttributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = m_AosAttributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = m_AosAttributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = m_AosAttributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = m_AosAttributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = m_AosAttributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = m_AosAttributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = m_AosAttributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = m_AosAttributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = m_AosAttributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = m_AosAttributes.Luck) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = m_AosAttributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = m_AosAttributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if ((prop = m_AosAttributes.NightSight) != 0) + list.Add(1060441); // night sight + + if ((prop = m_AosAttributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = m_AosAttributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = m_AosAttributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if ((prop = m_AosAttributes.SpellChanneling) != 0) + list.Add(1060482); // spell channeling + + if ((prop = m_AosAttributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = m_AosAttributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = m_AosAttributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = m_AosAttributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if (Core.ML && (prop = m_AosAttributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + base.AddResistanceProperties(list); + // Plume : Disponible uniquement via ArmLore + //if ( m_HitPoints >= 0 && m_MaxHitPoints > 0 ) + // list.Add( 1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints ); // durability ~1_val~ / ~2_val~ + + } + if (!m_Identified) + list.Add("Non identifi�"); + if (m_Crafter != null) + list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ + + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)6); // version + + writer.Write((Mobile)m_Crafter); + writer.Write((bool)m_PlayerConstructed); + writer.Write((bool)m_Identified); + + writer.WriteEncodedInt((int)m_MaxHitPoints); + writer.WriteEncodedInt((int)m_HitPoints); + + writer.WriteEncodedInt((int)m_Resource); + writer.WriteEncodedInt((int)m_GemType); + + m_AosAttributes.Serialize(writer); + m_AosResistances.Serialize(writer); + m_AosSkillBonuses.Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 6: + { + m_Crafter = reader.ReadMobile(); + goto case 5; + } + case 5: + { + m_PlayerConstructed = reader.ReadBool(); + goto case 4; + } + case 4: + { + m_Identified = reader.ReadBool(); + goto case 3; + } + case 3: + { + m_MaxHitPoints = reader.ReadEncodedInt(); + m_HitPoints = reader.ReadEncodedInt(); + goto case 2; + } + case 2: + { + m_Resource = (CraftResource)reader.ReadEncodedInt(); + m_GemType = (GemType)reader.ReadEncodedInt(); + + goto case 1; + } + case 1: + { + m_AosAttributes = new AosAttributes(this, reader); + m_AosResistances = new AosElementAttributes(this, reader); + m_AosSkillBonuses = new AosSkillBonuses(this, reader); + + if (Core.AOS && Parent is Mobile) + m_AosSkillBonuses.AddTo((Mobile)Parent); + + int strBonus = m_AosAttributes.BonusStr; + int dexBonus = m_AosAttributes.BonusDex; + int intBonus = m_AosAttributes.BonusInt; + + if (Parent is Mobile && (strBonus != 0 || dexBonus != 0 || intBonus != 0)) + { + Mobile m = (Mobile)Parent; + + string modName = Serial.ToString(); + + if (strBonus != 0) + m.AddStatMod(new StatMod(StatType.Str, modName + "Str", strBonus, TimeSpan.Zero)); + + if (dexBonus != 0) + m.AddStatMod(new StatMod(StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero)); + + if (intBonus != 0) + m.AddStatMod(new StatMod(StatType.Int, modName + "Int", intBonus, TimeSpan.Zero)); + } + + if (Parent is Mobile) + ((Mobile)Parent).CheckStatTimers(); + + break; + } + case 0: + { + m_AosAttributes = new AosAttributes(this); + m_AosResistances = new AosElementAttributes(this); + m_AosSkillBonuses = new AosSkillBonuses(this); + + break; + } + } + if (version < 5) + { + m_PlayerConstructed = false; //Assume it wasn't crafted + } + if (version < 4) + { + m_Identified = true; //Assume it was identified + } + if (version < 2) + { + m_Resource = CraftResource.MIron; + m_GemType = GemType.None; + } + } + #region ICraftable Members + + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue) + { + + PlayerConstructed = true; + Identified = true; + + if (makersMark) + Crafter = from; + + Type resourceType = typeRes; + + if (resourceType == null) + resourceType = craftItem.Resources.GetAt(0).ItemType; + + Resource = CraftResources.GetFromType(resourceType); + + CraftContext context = craftSystem.GetContext(from); + + if (context != null && context.DoNotColor) + Hue = 0; + //Plume Edit pour les gemmes + /* + if ( 1 < craftItem.Resources.Count ) + { + resourceType = craftItem.Resources.GetAt( 1 ).ItemType; + + if ( resourceType == typeof( StarSapphire ) ) + GemType = GemType.StarSapphire; + else if ( resourceType == typeof( Emerald ) ) + GemType = GemType.Emerald; + else if ( resourceType == typeof( Sapphire ) ) + GemType = GemType.Sapphire; + else if ( resourceType == typeof( Ruby ) ) + GemType = GemType.Ruby; + else if ( resourceType == typeof( Citrine ) ) + GemType = GemType.Citrine; + else if ( resourceType == typeof( Amethyst ) ) + GemType = GemType.Amethyst; + else if ( resourceType == typeof( Tourmaline ) ) + GemType = GemType.Tourmaline; + else if ( resourceType == typeof( Amber ) ) + GemType = GemType.Amber; + else if ( resourceType == typeof( Diamond ) ) + GemType = GemType.Diamond; + } + */ + return 1; + + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Beads.cs b/Scripts/Items/Jewels/Beads.cs new file mode 100644 index 0000000..c042f13 --- /dev/null +++ b/Scripts/Items/Jewels/Beads.cs @@ -0,0 +1,31 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class Beads : Item + { + [Constructable] + public Beads() : base( 0x108B ) + { + Weight = 1.0; + } + + public Beads( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Bracelet.cs b/Scripts/Items/Jewels/Bracelet.cs new file mode 100644 index 0000000..1c6c9ab --- /dev/null +++ b/Scripts/Items/Jewels/Bracelet.cs @@ -0,0 +1,85 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseBracelet : BaseJewel + { + public override int BaseGemTypeNumber{ get{ return 1044221; } } // star sapphire bracelet + + public BaseBracelet( int itemID ) : base( itemID, Layer.Bracelet ) + { + } + + public BaseBracelet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoldBracelet : BaseBracelet + { + [Constructable] + public GoldBracelet() : base( 0x1086 ) + { + Weight = 0.1; + } + + public GoldBracelet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SilverBracelet : BaseBracelet + { + [Constructable] + public SilverBracelet() : base( 0x1F06 ) + { + Weight = 0.1; + } + + public SilverBracelet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Jewels/Earrings.cs b/Scripts/Items/Jewels/Earrings.cs new file mode 100644 index 0000000..15572a3 --- /dev/null +++ b/Scripts/Items/Jewels/Earrings.cs @@ -0,0 +1,85 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseEarrings : BaseJewel + { + public override int BaseGemTypeNumber{ get{ return 1044203; } } // star sapphire earrings + + public BaseEarrings( int itemID ) : base( itemID, Layer.Earrings ) + { + } + + public BaseEarrings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoldEarrings : BaseEarrings + { + [Constructable] + public GoldEarrings() : base( 0x1087 ) + { + Weight = 0.1; + } + + public GoldEarrings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SilverEarrings : BaseEarrings + { + [Constructable] + public SilverEarrings() : base( 0x1F07 ) + { + Weight = 0.1; + } + + public SilverEarrings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Necklace.cs b/Scripts/Items/Jewels/Necklace.cs new file mode 100644 index 0000000..9a8928c --- /dev/null +++ b/Scripts/Items/Jewels/Necklace.cs @@ -0,0 +1,167 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseNecklace : BaseJewel + { + public override int BaseGemTypeNumber{ get{ return 1044241; } } // star sapphire necklace + + public BaseNecklace( int itemID ) : base( itemID, Layer.Neck ) + { + } + + public BaseNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Necklace : BaseNecklace + { + [Constructable] + public Necklace() : base( 0x1085 ) + { + Weight = 0.1; + } + + public Necklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoldNecklace : BaseNecklace + { + [Constructable] + public GoldNecklace() : base( 0x1088 ) + { + Weight = 0.1; + } + + public GoldNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoldBeadNecklace : BaseNecklace + { + [Constructable] + public GoldBeadNecklace() : base( 0x1089 ) + { + Weight = 0.1; + } + + public GoldBeadNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class SilverNecklace : BaseNecklace + { + [Constructable] + public SilverNecklace() : base( 0x1F08 ) + { + Weight = 0.1; + } + + public SilverNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SilverBeadNecklace : BaseNecklace + { + [Constructable] + public SilverBeadNecklace() : base( 0x1F05 ) + { + Weight = 0.1; + } + + public SilverBeadNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Jewels/Ring.cs b/Scripts/Items/Jewels/Ring.cs new file mode 100644 index 0000000..9e75e45 --- /dev/null +++ b/Scripts/Items/Jewels/Ring.cs @@ -0,0 +1,85 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseRing : BaseJewel + { + public override int BaseGemTypeNumber{ get{ return 1044176; } } // star sapphire ring + + public BaseRing( int itemID ) : base( itemID, Layer.Ring ) + { + } + + public BaseRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoldRing : BaseRing + { + [Constructable] + public GoldRing() : base( 0x108a ) + { + Weight = 0.1; + } + + public GoldRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SilverRing : BaseRing + { + [Constructable] + public SilverRing() : base( 0x1F09 ) + { + Weight = 0.1; + } + + public SilverRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Lights/BaseEquipableLight.cs b/Scripts/Items/Lights/BaseEquipableLight.cs new file mode 100644 index 0000000..d2297c1 --- /dev/null +++ b/Scripts/Items/Lights/BaseEquipableLight.cs @@ -0,0 +1,64 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BaseEquipableLight : BaseLight + { + [Constructable] + public BaseEquipableLight( int itemID ) : base( itemID ) + { + Layer = Layer.TwoHanded; + } + + public BaseEquipableLight( Serial serial ) : base( serial ) + { + } + + public override void Ignite() + { + if ( !(Parent is Mobile) && RootParent is Mobile ) + { + Mobile holder = (Mobile)RootParent; + + if ( holder.EquipItem( this ) ) + { + if ( this is Candle ) + holder.SendLocalizedMessage( 502969 ); // You put the candle in your left hand. + else if ( this is Torch ) + holder.SendLocalizedMessage( 502971 ); // You put the torch in your left hand. + + base.Ignite(); + } + else + { + holder.SendLocalizedMessage( 502449 ); // You cannot hold this item. + } + } + else + { + base.Ignite(); + } + } + + public override void OnAdded ( object parent ) + { + if ( Burning && parent is Container ) + Douse(); + + base.OnAdded( parent ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/BaseLight.cs b/Scripts/Items/Lights/BaseLight.cs new file mode 100644 index 0000000..e3e1d0c --- /dev/null +++ b/Scripts/Items/Lights/BaseLight.cs @@ -0,0 +1,233 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BaseLight : Item + { + private Timer m_Timer; + private DateTime m_End; + private bool m_BurntOut = false; + private bool m_Burning = false; + private bool m_Protected = false; + private TimeSpan m_Duration = TimeSpan.Zero; + + public abstract int LitItemID{ get; } + + public virtual int UnlitItemID{ get { return 0; } } + public virtual int BurntOutItemID{ get { return 0; } } + + public virtual int LitSound{ get { return 0x47; } } + public virtual int UnlitSound{ get { return 0x3be; } } + public virtual int BurntOutSound{ get { return 0x4b8; } } + + public static readonly bool Burnout = false; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Burning + { + get { return m_Burning; } + set + { + if ( m_Burning != value ) + { + m_Burning = true; + DoTimer( m_Duration ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool BurntOut + { + get { return m_BurntOut; } + set { m_BurntOut = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Protected + { + get { return m_Protected; } + set { m_Protected = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan Duration + { + get + { + if ( m_Duration != TimeSpan.Zero && m_Burning ) + { + return m_End - DateTime.Now; + } + else + return m_Duration; + } + + set { m_Duration = value; } + } + + [Constructable] + public BaseLight( int itemID ) : base( itemID ) + { + } + + public BaseLight( Serial serial ) : base( serial ) + { + } + + public virtual void PlayLitSound() + { + if ( LitSound != 0 ) + { + Point3D loc = GetWorldLocation(); + Effects.PlaySound( loc, Map, LitSound ); + } + } + + public virtual void PlayUnlitSound() + { + int sound = UnlitSound; + + if ( m_BurntOut && BurntOutSound != 0 ) + sound = BurntOutSound; + + + if ( sound != 0 ) + { + Point3D loc = GetWorldLocation(); + Effects.PlaySound( loc, Map, sound ); + } + } + + public virtual void Ignite() + { + if ( !m_BurntOut ) + { + PlayLitSound(); + + m_Burning = true; + ItemID = LitItemID; + DoTimer( m_Duration ); + } + } + + public virtual void Douse() + { + m_Burning = false; + + if ( m_BurntOut && BurntOutItemID != 0 ) + ItemID = BurntOutItemID; + else + ItemID = UnlitItemID; + + if ( m_BurntOut ) + m_Duration = TimeSpan.Zero; + else if ( m_Duration != TimeSpan.Zero ) + m_Duration = m_End - DateTime.Now; + + if ( m_Timer != null ) + m_Timer.Stop(); + + PlayUnlitSound(); + } + + public virtual void Burn() + { + m_BurntOut = true; + Douse(); + } + + private void DoTimer( TimeSpan delay ) + { + m_Duration = delay; + + if ( m_Timer != null ) + m_Timer.Stop(); + + if ( delay == TimeSpan.Zero ) + return; + + m_End = DateTime.Now + delay; + + m_Timer = new InternalTimer( this, delay ); + m_Timer.Start(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_BurntOut ) + return; + + if ( m_Protected && from.AccessLevel == AccessLevel.Player ) + return; + + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + return; + + if ( m_Burning ) + { + if ( UnlitItemID != 0 ) + Douse(); + } + else + { + Ignite(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + writer.Write( m_BurntOut ); + writer.Write( m_Burning ); + writer.Write( m_Duration ); + writer.Write( m_Protected ); + + if ( m_Burning && m_Duration != TimeSpan.Zero ) + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_BurntOut = reader.ReadBool(); + m_Burning = reader.ReadBool(); + m_Duration = reader.ReadTimeSpan(); + m_Protected = reader.ReadBool(); + + if ( m_Burning && m_Duration != TimeSpan.Zero ) + DoTimer( reader.ReadDeltaTime() - DateTime.Now ); + + break; + } + } + } + + private class InternalTimer : Timer + { + private BaseLight m_Light; + + public InternalTimer( BaseLight light, TimeSpan delay ) : base( delay ) + { + m_Light = light; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + if ( m_Light != null && !m_Light.Deleted ) + m_Light.Burn(); + } + } + } +} diff --git a/Scripts/Items/Lights/Brazier.cs b/Scripts/Items/Lights/Brazier.cs new file mode 100644 index 0000000..df9bb75 --- /dev/null +++ b/Scripts/Items/Lights/Brazier.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Brazier : BaseLight + { + public override int LitItemID{ get { return 0xE31; } } + + [Constructable] + public Brazier() : base( 0xE31 ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = true; + Light = LightType.Circle225; + Weight = 20.0; + } + + public Brazier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/BrazierTall.cs b/Scripts/Items/Lights/BrazierTall.cs new file mode 100644 index 0000000..9e7f96b --- /dev/null +++ b/Scripts/Items/Lights/BrazierTall.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BrazierTall : BaseLight + { + public override int LitItemID{ get { return 0x19AA; } } + + [Constructable] + public BrazierTall() : base( 0x19AA ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = true; + Light = LightType.Circle300; + Weight = 25.0; + } + + public BrazierTall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/Candelabra.cs b/Scripts/Items/Lights/Candelabra.cs new file mode 100644 index 0000000..e9fa87d --- /dev/null +++ b/Scripts/Items/Lights/Candelabra.cs @@ -0,0 +1,75 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Candelabra : BaseLight, IShipwreckedItem + { + public override int LitItemID{ get { return 0xB1D; } } + public override int UnlitItemID{ get { return 0xA27; } } + + [Constructable] + public Candelabra() : base( 0xA27 ) + { + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle225; + Weight = 3.0; + } + + public Candelabra( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + + writer.Write( m_IsShipwreckedItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsShipwreckedItem = reader.ReadBool(); + break; + } + } + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( m_IsShipwreckedItem ) + list.Add( 1041645 ); // recovered from a shipwreck + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( m_IsShipwreckedItem ) + LabelTo( from, 1041645 ); //recovered from a shipwreck + } + + #region IShipwreckedItem Members + + private bool m_IsShipwreckedItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsShipwreckedItem + { + get { return m_IsShipwreckedItem; } + set { m_IsShipwreckedItem = value; } + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/CandelabraStand.cs b/Scripts/Items/Lights/CandelabraStand.cs new file mode 100644 index 0000000..f7c12d2 --- /dev/null +++ b/Scripts/Items/Lights/CandelabraStand.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CandelabraStand : BaseLight + { + public override int LitItemID{ get { return 0xB26; } } + public override int UnlitItemID{ get { return 0xA29; } } + + [Constructable] + public CandelabraStand() : base( 0xA29 ) + { + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle225; + Weight = 20.0; + } + + public CandelabraStand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/Candle.cs b/Scripts/Items/Lights/Candle.cs new file mode 100644 index 0000000..e071296 --- /dev/null +++ b/Scripts/Items/Lights/Candle.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Candle : BaseEquipableLight + { + public override int LitItemID{ get { return 0xA0F; } } + public override int UnlitItemID{ get { return 0xA28; } } + + [Constructable] + public Candle() : base( 0xA28 ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 20 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle150; + Weight = 1.0; + } + + public Candle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/CandleLarge.cs b/Scripts/Items/Lights/CandleLarge.cs new file mode 100644 index 0000000..af357b4 --- /dev/null +++ b/Scripts/Items/Lights/CandleLarge.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CandleLarge : BaseLight + { + public override int LitItemID{ get { return 0xB1A; } } + public override int UnlitItemID{ get { return 0xA26; } } + + [Constructable] + public CandleLarge() : base( 0xA26 ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 25 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle150; + Weight = 2.0; + } + + public CandleLarge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/CandleLong.cs b/Scripts/Items/Lights/CandleLong.cs new file mode 100644 index 0000000..c575e50 --- /dev/null +++ b/Scripts/Items/Lights/CandleLong.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CandleLong : BaseLight + { + public override int LitItemID{ get { return 0x1430; } } + public override int UnlitItemID{ get { return 0x1433; } } + + [Constructable] + public CandleLong() : base( 0x1433 ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 30 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle150; + Weight = 1.0; + } + + public CandleLong( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/CandleShort.cs b/Scripts/Items/Lights/CandleShort.cs new file mode 100644 index 0000000..bc66c0d --- /dev/null +++ b/Scripts/Items/Lights/CandleShort.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CandleShort : BaseLight + { + public override int LitItemID{ get { return 0x142C; } } + public override int UnlitItemID{ get { return 0x142F; } } + + [Constructable] + public CandleShort() : base( 0x142F ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 25 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle150; + Weight = 1.0; + } + + public CandleShort( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/CandleSkull.cs b/Scripts/Items/Lights/CandleSkull.cs new file mode 100644 index 0000000..096c1d0 --- /dev/null +++ b/Scripts/Items/Lights/CandleSkull.cs @@ -0,0 +1,59 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CandleSkull : BaseLight + { + public override int LitItemID + { + get + { + if ( ItemID == 0x1583 || ItemID == 0x1854 ) + return 0x1854; + + return 0x1858; + } + } + + public override int UnlitItemID + { + get + { + if ( ItemID == 0x1853 || ItemID == 0x1584 ) + return 0x1853; + + return 0x1857; + } + } + + [Constructable] + public CandleSkull() : base( 0x1853 ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 25 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle150; + Weight = 5.0; + } + + public CandleSkull( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/DarkSource.cs b/Scripts/Items/Lights/DarkSource.cs new file mode 100644 index 0000000..327567f --- /dev/null +++ b/Scripts/Items/Lights/DarkSource.cs @@ -0,0 +1,30 @@ +using System; + +namespace Server.Items +{ + public class DarkSource : Item + { + [Constructable] + public DarkSource() : base( 0x1646 ) + { + Layer = Layer.TwoHanded; + Movable = false; + } + + public DarkSource( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/HangingLantern.cs b/Scripts/Items/Lights/HangingLantern.cs new file mode 100644 index 0000000..bcef9e8 --- /dev/null +++ b/Scripts/Items/Lights/HangingLantern.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HangingLantern : BaseLight + { + public override int LitItemID{ get { return 0xA1A; } } + public override int UnlitItemID{ get { return 0xA1D; } } + + [Constructable] + public HangingLantern() : base( 0xA1D ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle300; + Weight = 40.0; + } + + public HangingLantern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/HeatingStand.cs b/Scripts/Items/Lights/HeatingStand.cs new file mode 100644 index 0000000..d08988f --- /dev/null +++ b/Scripts/Items/Lights/HeatingStand.cs @@ -0,0 +1,106 @@ +using System; +using Server; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Items +{ + public class HeatingStand : BaseLight + { + public override int LitItemID{ get { return 0x184A; } } + public override int UnlitItemID{ get { return 0x1849; } } + + [Constructable] + public HeatingStand() : base( 0x1849 ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 25 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Empty; + Weight = 1.0; + } + + public override void OnDoubleClick(Mobile from) + { + if(ItemID == UnlitItemID) + { + from.SendMessage("Que voulez vous chauffer?"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + } + base.OnDoubleClick(from); + } + + public void OnTarget(Mobile from, object obj) + { + if (!(obj is AlchemyVial)) + { + from.SendMessage("Chauffer cette solution ne vous servira � rien"); + return; + } + + AlchemyVial vial = (AlchemyVial)obj; + + if (vial.AlchemyLiquidType == LiquidType.None) + { + from.SendMessage("Votre fiole est vide"); + return; + } + + if (vial.AlchemyLiquidType != LiquidType.ChangelingBlood) + { + from.SendMessage("Il ne servirait � rien de tenter de faire chauffer cette �prouvette"); + return; + } + + if (!from.CheckSkill(SkillName.Alchemy,20,90)) + { + from.SendMessage("L'�prouvette explose!"); + from.Hits -= 5; + return; + } + + from.SendMessage("Le liquide bout et se transforme. Vous le versez lentement dans une autre �prouvette"); + vial.Consume(); + from.AddToBackpack(new MorphBase()); + } + + public override void Ignite() + { + base.Ignite(); + + if ( ItemID == LitItemID ) + Light = LightType.Circle150; + else if ( ItemID == UnlitItemID ) + Light = LightType.Empty; + } + + public override void Douse() + { + base.Douse(); + + if ( ItemID == LitItemID ) + Light = LightType.Circle150; + else if ( ItemID == UnlitItemID ) + Light = LightType.Empty; + } + + public HeatingStand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/LampPost1.cs b/Scripts/Items/Lights/LampPost1.cs new file mode 100644 index 0000000..e45511b --- /dev/null +++ b/Scripts/Items/Lights/LampPost1.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LampPost1 : BaseLight + { + public override int LitItemID{ get { return 0xB20; } } + public override int UnlitItemID{ get { return 0xB21; } } + + [Constructable] + public LampPost1() : base( 0xB21 ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle300; + Weight = 40.0; + } + + public LampPost1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/LampPost2.cs b/Scripts/Items/Lights/LampPost2.cs new file mode 100644 index 0000000..6946d79 --- /dev/null +++ b/Scripts/Items/Lights/LampPost2.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LampPost2 : BaseLight + { + public override int LitItemID{ get { return 0xB22; } } + public override int UnlitItemID{ get { return 0xB23; } } + + [Constructable] + public LampPost2() : base( 0xB23 ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle300; + Weight = 40.0; + } + + public LampPost2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/LampPost3.cs b/Scripts/Items/Lights/LampPost3.cs new file mode 100644 index 0000000..251ab4c --- /dev/null +++ b/Scripts/Items/Lights/LampPost3.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LampPost3 : BaseLight + { + public override int LitItemID{ get { return 0xB24; } } + public override int UnlitItemID{ get { return 0xB25; } } + + [Constructable] + public LampPost3() : base( 0xb25 ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle300; + Weight = 40.0; + } + + public LampPost3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/Lantern.cs b/Scripts/Items/Lights/Lantern.cs new file mode 100644 index 0000000..88d8126 --- /dev/null +++ b/Scripts/Items/Lights/Lantern.cs @@ -0,0 +1,86 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Lantern : BaseEquipableLight + { + public override int LitItemID + { + get + { + if ( ItemID == 0xA15 || ItemID == 0xA17 ) + return ItemID; + + return 0xA22; + } + } + + public override int UnlitItemID + { + get + { + if ( ItemID == 0xA18 ) + return ItemID; + + return 0xA25; + } + } + + [Constructable] + public Lantern() : base( 0xA25 ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 20 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle300; + Weight = 2.0; + } + + public Lantern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class LanternOfSouls : Lantern + { + public override int LabelNumber{ get{ return 1061618; } } // Lantern of Souls + + [Constructable] + public LanternOfSouls() + { + Hue = 0x482; + } + + public LanternOfSouls( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/LightSource.cs b/Scripts/Items/Lights/LightSource.cs new file mode 100644 index 0000000..b3c0190 --- /dev/null +++ b/Scripts/Items/Lights/LightSource.cs @@ -0,0 +1,30 @@ +using System; + +namespace Server.Items +{ + public class LightSource : Item + { + [Constructable] + public LightSource() : base( 0x1647 ) + { + Layer = Layer.TwoHanded; + Movable = false; + } + + public LightSource( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/PaperLantern.cs b/Scripts/Items/Lights/PaperLantern.cs new file mode 100644 index 0000000..a9769b9 --- /dev/null +++ b/Scripts/Items/Lights/PaperLantern.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class PaperLantern : BaseLight + { + public override int LitItemID{ get { return 0x24BD; } } + public override int UnlitItemID{ get { return 0x24BE; } } + + [Constructable] + public PaperLantern() : base( 0x24BE ) + { + Movable = true; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle150; + Weight = 3.0; + } + + public PaperLantern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/RedHangingLantern.cs b/Scripts/Items/Lights/RedHangingLantern.cs new file mode 100644 index 0000000..607b929 --- /dev/null +++ b/Scripts/Items/Lights/RedHangingLantern.cs @@ -0,0 +1,71 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class RedHangingLantern : BaseLight + { + public override int LitItemID + { + get + { + if ( ItemID == 0x24C2 ) + return 0x24C1; + else + return 0x24C3; + } + } + + public override int UnlitItemID + { + get + { + if ( ItemID == 0x24C1 ) + return 0x24C2; + else + return 0x24C4; + } + } + + [Constructable] + public RedHangingLantern() : base( 0x24C2 ) + { + Movable = true; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle300; + Weight = 3.0; + } + + public RedHangingLantern( Serial serial ) : base( serial ) + { + } + + public void Flip() + { + Light = LightType.Circle300; + + switch ( ItemID ) + { + case 0x24C2: ItemID = 0x24C4; break; + case 0x24C1: ItemID = 0x24C3; break; + + case 0x24C4: ItemID = 0x24C2; break; + case 0x24C3: ItemID = 0x24C1; break; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/RoundPaperLantern.cs b/Scripts/Items/Lights/RoundPaperLantern.cs new file mode 100644 index 0000000..3044e4d --- /dev/null +++ b/Scripts/Items/Lights/RoundPaperLantern.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class RoundPaperLantern : BaseLight + { + public override int LitItemID{ get { return 0x24C9; } } + public override int UnlitItemID{ get { return 0x24CA; } } + + [Constructable] + public RoundPaperLantern() : base( 0x24CA ) + { + Movable = true; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle150; + Weight = 3.0; + } + + public RoundPaperLantern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/ShojiLantern.cs b/Scripts/Items/Lights/ShojiLantern.cs new file mode 100644 index 0000000..1277b5b --- /dev/null +++ b/Scripts/Items/Lights/ShojiLantern.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class ShojiLantern : BaseLight + { + public override int LitItemID{ get { return 0x24BB; } } + public override int UnlitItemID{ get { return 0x24BC; } } + + [Constructable] + public ShojiLantern() : base( 0x24BC ) + { + Movable = true; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle150; + Weight = 3.0; + } + + public ShojiLantern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/Torch.cs b/Scripts/Items/Lights/Torch.cs new file mode 100644 index 0000000..a53efd0 --- /dev/null +++ b/Scripts/Items/Lights/Torch.cs @@ -0,0 +1,62 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Torch : BaseEquipableLight + { + public override int LitItemID{ get { return 0xA12; } } + public override int UnlitItemID{ get { return 0xF6B; } } + + public override int LitSound{ get { return 0x54; } } + public override int UnlitSound{ get { return 0x4BB; } } + + [Constructable] + public Torch() : base( 0xF6B ) + { + if ( Burnout ) + Duration = TimeSpan.FromMinutes( 30 ); + else + Duration = TimeSpan.Zero; + + Burning = false; + Light = LightType.Circle300; + Weight = 1.0; + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( parent is Mobile && Burning ) + Mobiles.MeerMage.StopEffect( (Mobile)parent, true ); + } + + public override void Ignite() + { + base.Ignite(); + + if ( Parent is Mobile && Burning ) + Mobiles.MeerMage.StopEffect( (Mobile)Parent, true ); + } + + public Torch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/WallSconce.cs b/Scripts/Items/Lights/WallSconce.cs new file mode 100644 index 0000000..a3c123e --- /dev/null +++ b/Scripts/Items/Lights/WallSconce.cs @@ -0,0 +1,74 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class WallSconce : BaseLight + { + public override int LitItemID + { + get + { + if ( ItemID == 0x9FB ) + return 0x9FD; + else + return 0xA02; + } + } + + public override int UnlitItemID + { + get + { + if ( ItemID == 0x9FD ) + return 0x9FB; + else + return 0xA00; + } + } + + [Constructable] + public WallSconce() : base( 0x9FB ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.WestBig; + Weight = 3.0; + } + + public WallSconce( Serial serial ) : base( serial ) + { + } + + public void Flip() + { + if ( Light == LightType.WestBig ) + Light = LightType.NorthBig; + else if ( Light == LightType.NorthBig ) + Light = LightType.WestBig; + + switch ( ItemID ) + { + case 0x9FB: ItemID = 0xA00; break; + case 0x9FD: ItemID = 0xA02; break; + + case 0xA00: ItemID = 0x9FB; break; + case 0xA02: ItemID = 0x9FD; break; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/WallTorch.cs b/Scripts/Items/Lights/WallTorch.cs new file mode 100644 index 0000000..724cf84 --- /dev/null +++ b/Scripts/Items/Lights/WallTorch.cs @@ -0,0 +1,74 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class WallTorch : BaseLight + { + public override int LitItemID + { + get + { + if ( ItemID == 0xA05 ) + return 0xA07; + else + return 0xA0C; + } + } + + public override int UnlitItemID + { + get + { + if ( ItemID == 0xA07 ) + return 0xA05; + else + return 0xA0A; + } + } + + [Constructable] + public WallTorch() : base( 0xA05 ) + { + Movable = false; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.WestBig; + Weight = 3.0; + } + + public WallTorch( Serial serial ) : base( serial ) + { + } + + public void Flip() + { + if ( Light == LightType.WestBig ) + Light = LightType.NorthBig; + else if ( Light == LightType.NorthBig ) + Light = LightType.WestBig; + + switch ( ItemID ) + { + case 0xA05: ItemID = 0xA0A; break; + case 0xA07: ItemID = 0xA0C; break; + + case 0xA0A: ItemID = 0xA05; break; + case 0xA0C: ItemID = 0xA07; break; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Lights/WhiteHangingLantern.cs b/Scripts/Items/Lights/WhiteHangingLantern.cs new file mode 100644 index 0000000..34d119b --- /dev/null +++ b/Scripts/Items/Lights/WhiteHangingLantern.cs @@ -0,0 +1,71 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class WhiteHangingLantern : BaseLight + { + public override int LitItemID + { + get + { + if ( ItemID == 0x24C6 ) + return 0x24C5; + else + return 0x24C7; + } + } + + public override int UnlitItemID + { + get + { + if ( ItemID == 0x24C5 ) + return 0x24C6; + else + return 0x24C8; + } + } + + [Constructable] + public WhiteHangingLantern() : base( 0x24C6 ) + { + Movable = true; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Light = LightType.Circle300; + Weight = 3.0; + } + + public WhiteHangingLantern( Serial serial ) : base( serial ) + { + } + + public void Flip() + { + Light = LightType.Circle300; + + switch ( ItemID ) + { + case 0x24C6: ItemID = 0x24C8; break; + case 0x24C5: ItemID = 0x24C7; break; + + case 0x24C8: ItemID = 0x24C6; break; + case 0x24C7: ItemID = 0x24C5; break; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/BlankMap.cs b/Scripts/Items/Maps/BlankMap.cs new file mode 100644 index 0000000..5b2a206 --- /dev/null +++ b/Scripts/Items/Maps/BlankMap.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BlankMap : MapItem + { + [Constructable] + public BlankMap() + { + } + + public override void OnDoubleClick( Mobile from ) + { + SendLocalizedMessageTo( from, 500208 ); // It appears to be blank. + } + + public BlankMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/CityMap.cs b/Scripts/Items/Maps/CityMap.cs new file mode 100644 index 0000000..1195978 --- /dev/null +++ b/Scripts/Items/Maps/CityMap.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CityMap : MapItem + { + [Constructable] + public CityMap() + { + SetDisplay( 0, 0, 5119, 4095, 400, 400 ); + } + + public override void CraftInit( Mobile from ) + { + double skillValue = from.Skills[SkillName.Cartography].Value; + int dist = 64 + (int)(skillValue * 4); + + if ( dist < 200 ) + dist = 200; + + int size = 32 + (int)(skillValue * 2); + + if ( size < 200 ) + size = 200; + else if ( size > 400 ) + size = 400; + + SetDisplay( from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, size, size ); + } + + public override int LabelNumber{ get{ return 1015231; } } // city map + + public CityMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/IndecipherableMap.cs b/Scripts/Items/Maps/IndecipherableMap.cs new file mode 100644 index 0000000..a2d3453 --- /dev/null +++ b/Scripts/Items/Maps/IndecipherableMap.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class IndecipherableMap : MapItem + { + public override int LabelNumber{ get{ return 1070799; } } // indecipherable map + + [Constructable] + public IndecipherableMap() + { + if ( Utility.RandomDouble() < 0.2 ) + Hue = 0x965; + else + Hue = 0x961; + } + + public IndecipherableMap( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 1070801 ); // You cannot decipher this ruined map. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/LocalMap.cs b/Scripts/Items/Maps/LocalMap.cs new file mode 100644 index 0000000..3805e6d --- /dev/null +++ b/Scripts/Items/Maps/LocalMap.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LocalMap : MapItem + { + [Constructable] + public LocalMap() + { + SetDisplay( 0, 0, 5119, 4095, 400, 400 ); + } + + public override void CraftInit( Mobile from ) + { + double skillValue = from.Skills[SkillName.Cartography].Value; + int dist = 64 + (int)(skillValue * 2); + + SetDisplay( from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, 200, 200 ); + } + + public override int LabelNumber{ get{ return 1015230; } } // local map + + public LocalMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/MapItem.cs b/Scripts/Items/Maps/MapItem.cs new file mode 100644 index 0000000..f3e3a93 --- /dev/null +++ b/Scripts/Items/Maps/MapItem.cs @@ -0,0 +1,407 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x14EB, 0x14EC )] + public class MapItem : Item, ICraftable + { + private Rectangle2D m_Bounds; + + private int m_Width, m_Height; + + private bool m_Protected; + private bool m_Editable; + + private List m_Pins = new List(); + + private const int MaxUserPins = 50; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Protected + { + get { return m_Protected; } + set { m_Protected = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Rectangle2D Bounds + { + get { return m_Bounds; } + set { m_Bounds = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Width + { + get { return m_Width; } + set { m_Width = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Height + { + get { return m_Height; } + set { m_Height = value; } + } + + public List Pins + { + get { return m_Pins; } + } + + [Constructable] + public MapItem() : base( 0x14EC ) + { + Weight = 1.0; + + m_Width = 200; + m_Height = 200; + } + + public virtual void CraftInit( Mobile from ) + { + } + + public void SetDisplay( int x1, int y1, int x2, int y2, int w, int h ) + { + Width = w; + Height = h; + + if ( x1 < 0 ) + x1 = 0; + + if ( y1 < 0 ) + y1 = 0; + + if ( x2 >= 5120 ) + x2 = 5119; + + if ( y2 >= 4096 ) + y2 = 4095; + + Bounds = new Rectangle2D( x1, y1, x2-x1, y2-y1 ); + } + + public MapItem( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + DisplayTo( from ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + public virtual void DisplayTo( Mobile from ) + { + from.Send( new NewMapDetails( this ) ); + from.Send( new MapDisplay( this ) ); + + for ( int i = 0; i < m_Pins.Count; ++i ) + from.Send( new MapAddPin( this, m_Pins[i] ) ); + + from.Send( new MapSetEditable( this, ValidateEdit( from ) ) ); + } + + public virtual void OnAddPin( Mobile from, int x, int y ) + { + if ( !ValidateEdit( from ) ) + return; + else if ( m_Pins.Count >= MaxUserPins ) + return; + + Validate( ref x, ref y ); + AddPin( x, y ); + } + + public virtual void OnRemovePin( Mobile from, int number ) + { + if ( !ValidateEdit( from ) ) + return; + + RemovePin( number ); + } + + public virtual void OnChangePin( Mobile from, int number, int x, int y ) + { + if ( !ValidateEdit( from ) ) + return; + + Validate( ref x, ref y ); + ChangePin( number, x, y ); + } + + public virtual void OnInsertPin( Mobile from, int number, int x, int y ) + { + if ( !ValidateEdit( from ) ) + return; + else if ( m_Pins.Count >= MaxUserPins ) + return; + + Validate( ref x, ref y ); + InsertPin( number, x, y ); + } + + public virtual void OnClearPins( Mobile from ) + { + if ( !ValidateEdit( from ) ) + return; + + ClearPins(); + } + + public virtual void OnToggleEditable( Mobile from ) + { + if ( Validate( from ) ) + m_Editable = !m_Editable; + + from.Send( new MapSetEditable( this, Validate( from ) && m_Editable ) ); + } + + public virtual void Validate( ref int x, ref int y ) + { + if ( x < 0 ) + x = 0; + else if ( x >= m_Width ) + x = m_Width - 1; + + if ( y < 0 ) + y = 0; + else if ( y >= m_Height ) + y = m_Height - 1; + } + + public virtual bool ValidateEdit( Mobile from ) + { + return m_Editable && Validate( from ); + } + + public virtual bool Validate( Mobile from ) + { + if ( !from.CanSee( this ) || from.Map != this.Map || !from.Alive || InSecureTrade ) + return false; + else if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + else if ( !Movable || m_Protected || !from.InRange( GetWorldLocation(), 2 ) ) + return false; + + object root = RootParent; + + if ( root is Mobile && root != from ) + return false; + + return true; + } + + public void ConvertToWorld( int x, int y, out int worldX, out int worldY ) + { + worldX = ( ( m_Bounds.Width * x ) / Width ) + m_Bounds.X; + worldY = ( ( m_Bounds.Height * y ) / Height ) + m_Bounds.Y; + } + + public void ConvertToMap( int x, int y, out int mapX, out int mapY ) + { + mapX = ( ( x - m_Bounds.X ) * Width ) / m_Bounds.Width; + mapY = ( ( y - m_Bounds.Y ) * Width ) / m_Bounds.Height; + } + + public virtual void AddWorldPin( int x, int y ) + { + int mapX, mapY; + ConvertToMap( x, y, out mapX, out mapY ); + + AddPin( mapX, mapY ); + } + + public virtual void AddPin( int x, int y ) + { + m_Pins.Add( new Point2D( x, y ) ); + } + + public virtual void RemovePin( int index ) + { + if ( index > 0 && index < m_Pins.Count ) + m_Pins.RemoveAt( index ); + } + + public virtual void InsertPin( int index, int x, int y ) + { + if ( index < 0 || index >= m_Pins.Count ) + m_Pins.Add( new Point2D( x, y ) ); + else + m_Pins.Insert( index, new Point2D( x, y ) ); + } + + public virtual void ChangePin( int index, int x, int y ) + { + if ( index >= 0 && index < m_Pins.Count ) + m_Pins[index] = new Point2D( x, y ); + } + + public virtual void ClearPins() + { + m_Pins.Clear(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_Bounds ); + + writer.Write( m_Width ); + writer.Write( m_Height ); + + writer.Write( m_Protected ); + + writer.Write( m_Pins.Count ); + for ( int i = 0; i < m_Pins.Count; ++i ) + writer.Write( m_Pins[i] ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Bounds = reader.ReadRect2D(); + + m_Width = reader.ReadInt(); + m_Height = reader.ReadInt(); + + m_Protected = reader.ReadBool(); + + int count = reader.ReadInt(); + for ( int i = 0; i < count; i++ ) + m_Pins.Add( reader.ReadPoint2D() ); + + break; + } + } + } + + public static void Initialize() + { + PacketHandlers.Register( 0x56, 11, true, new OnPacketReceive( OnMapCommand ) ); + } + + private static void OnMapCommand( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + MapItem map = World.FindItem( pvSrc.ReadInt32() ) as MapItem; + + if ( map == null ) + return; + + int command = pvSrc.ReadByte(); + int number = pvSrc.ReadByte(); + + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + + switch ( command ) + { + case 1: map.OnAddPin( from, x, y ); break; + case 2: map.OnInsertPin( from, number, x, y ); break; + case 3: map.OnChangePin( from, number, x, y ); break; + case 4: map.OnRemovePin( from, number ); break; + case 5: map.OnClearPins( from ); break; + case 6: map.OnToggleEditable( from ); break; + } + } + + private sealed class MapDetails : Packet + { + public MapDetails( MapItem map ) : base ( 0x90, 19 ) + { + m_Stream.Write( (int) map.Serial ); + m_Stream.Write( (short) 0x139D ); + m_Stream.Write( (short) map.Bounds.Start.X ); + m_Stream.Write( (short) map.Bounds.Start.Y ); + m_Stream.Write( (short) map.Bounds.End.X ); + m_Stream.Write( (short) map.Bounds.End.Y ); + m_Stream.Write( (short) map.Width ); + m_Stream.Write( (short) map.Height ); + } + } + + private sealed class NewMapDetails : Packet + { + public NewMapDetails(MapItem map) + : base(0xF5, 21) + { + Map newmap = map.Map; + + if (newmap != Map.Trammel) + newmap = Map.Trammel; + + m_Stream.Write((int)map.Serial); + m_Stream.Write((short)0x139D); + m_Stream.Write((short)map.Bounds.Start.X); + m_Stream.Write((short)map.Bounds.Start.Y); + m_Stream.Write((short)map.Bounds.End.X); + m_Stream.Write((short)map.Bounds.End.Y); + m_Stream.Write((short)map.Width); + m_Stream.Write((short)map.Height); + m_Stream.Write((short) /*( map.Facet == null ? 0 :*/ newmap.MapID); + } + } + + private abstract class MapCommand : Packet + { + public MapCommand( MapItem map, int command, int number, int x, int y ) : base ( 0x56, 11 ) + { + m_Stream.Write( (int) map.Serial ); + m_Stream.Write( (byte) command ); + m_Stream.Write( (byte) number ); + m_Stream.Write( (short) x ); + m_Stream.Write( (short) y ); + } + } + + private sealed class MapDisplay : MapCommand + { + public MapDisplay( MapItem map ) : base( map, 5, 0, 0, 0 ) + { + } + } + + private sealed class MapAddPin : MapCommand + { + public MapAddPin( MapItem map, Point2D point ) : base( map, 1, 0, point.X, point.Y ) + { + } + } + + private sealed class MapSetEditable : MapCommand + { + public MapSetEditable( MapItem map, bool editable ) : base( map, 7, editable ? 1 : 0, 0, 0 ) + { + } + } + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + CraftInit( from ); + return 1; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/PresetMap.cs b/Scripts/Items/Maps/PresetMap.cs new file mode 100644 index 0000000..745d2de --- /dev/null +++ b/Scripts/Items/Maps/PresetMap.cs @@ -0,0 +1,151 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PresetMap : MapItem + { + private int m_LabelNumber; + + [Constructable] + public PresetMap( PresetMapType type ) + { + int v = (int)type; + + if ( v >= 0 && v < PresetMapEntry.Table.Length ) + InitEntry( PresetMapEntry.Table[v] ); + } + + public PresetMap( PresetMapEntry entry ) + { + InitEntry( entry ); + } + + public void InitEntry( PresetMapEntry entry ) + { + m_LabelNumber = entry.Name; + + Width = entry.Width; + Height = entry.Height; + + Bounds = entry.Bounds; + } + + public override int LabelNumber{ get{ return (m_LabelNumber == 0 ? base.LabelNumber : m_LabelNumber); } } + + public PresetMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (int) m_LabelNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadInt(); + break; + } + } + } + } + + public class PresetMapEntry + { + private int m_Name; + private int m_Width, m_Height; + private Rectangle2D m_Bounds; + + public int Name{ get{ return m_Name; } } + public int Width{ get{ return m_Width; } } + public int Height{ get{ return m_Height; } } + public Rectangle2D Bounds{ get{ return m_Bounds; } } + + public PresetMapEntry( int name, int width, int height, int xLeft, int yTop, int xRight, int yBottom ) + { + m_Name = name; + m_Width = width; + m_Height = height; + m_Bounds = new Rectangle2D( xLeft, yTop, xRight - xLeft, yBottom - yTop ); + } + + private static PresetMapEntry[] m_Table = new PresetMapEntry[] + { + new PresetMapEntry( 1041189, 200, 200, 1092, 1396, 1736, 1924 ), // map of Britain + new PresetMapEntry( 1041203, 200, 200, 0256, 1792, 1736, 2560 ), // map of Britain to Skara Brae + new PresetMapEntry( 1041192, 200, 200, 1024, 1280, 2304, 3072 ), // map of Britain to Trinsic + new PresetMapEntry( 1041183, 200, 200, 2500, 1900, 3000, 2400 ), // map of Buccaneer's Den + new PresetMapEntry( 1041198, 200, 200, 2560, 1792, 3840, 2560 ), // map of Buccaneer's Den to Magincia + new PresetMapEntry( 1041194, 200, 200, 2560, 1792, 3840, 3072 ), // map of Buccaneer's Den to Ocllo + new PresetMapEntry( 1041181, 200, 200, 1088, 3572, 1528, 4056 ), // map of Jhelom + new PresetMapEntry( 1041186, 200, 200, 3530, 2022, 3818, 2298 ), // map of Magincia + new PresetMapEntry( 1041199, 200, 200, 3328, 1792, 3840, 2304 ), // map of Magincia to Ocllo + new PresetMapEntry( 1041182, 200, 200, 2360, 0356, 2706, 0702 ), // map of Minoc + new PresetMapEntry( 1041190, 200, 200, 0000, 0256, 2304, 3072 ), // map of Minoc to Yew + new PresetMapEntry( 1041191, 200, 200, 2467, 0572, 2878, 0746 ), // map of Minoc to Vesper + new PresetMapEntry( 1041188, 200, 200, 4156, 0808, 4732, 1528 ), // map of Moonglow + new PresetMapEntry( 1041201, 200, 200, 3328, 0768, 4864, 1536 ), // map of Moonglow to Nujelm + new PresetMapEntry( 1041185, 200, 200, 3446, 1030, 3832, 1424 ), // map of Nujelm + new PresetMapEntry( 1041197, 200, 200, 3328, 1024, 3840, 2304 ), // map of Nujelm to Magincia + new PresetMapEntry( 1041187, 200, 200, 3582, 2456, 3770, 2742 ), // map of Ocllo + new PresetMapEntry( 1041184, 200, 200, 2714, 3329, 3100, 3639 ), // map of Serpent's Hold + new PresetMapEntry( 1041200, 200, 200, 2560, 2560, 3840, 3840 ), // map of Serpent's Hold to Ocllo + new PresetMapEntry( 1041180, 200, 200, 0524, 2064, 0960, 2452 ), // map of Skara Brae + new PresetMapEntry( 1041204, 200, 200, 0000, 0000, 5199, 4095 ), // map of The World + new PresetMapEntry( 1041177, 200, 200, 1792, 2630, 2118, 2952 ), // map of Trinsic + new PresetMapEntry( 1041193, 200, 200, 1792, 1792, 3072, 3072 ), // map of Trinsic to Buccaneer's Den + new PresetMapEntry( 1041195, 200, 200, 0256, 1792, 2304, 4095 ), // map of Trinsic to Jhelom + new PresetMapEntry( 1041178, 200, 200, 2636, 0592, 3064, 1012 ), // map of Vesper + new PresetMapEntry( 1041196, 200, 200, 2636, 0592, 3840, 1536 ), // map of Vesper to Nujelm + new PresetMapEntry( 1041179, 200, 200, 0236, 0741, 0766, 1269 ), // map of Yew + new PresetMapEntry( 1041202, 200, 200, 0000, 0512, 1792, 2048 ) // map of Yew to Britain + }; + + public static PresetMapEntry[] Table{ get{ return m_Table; } } + } + + public enum PresetMapType + { + Britain, + BritainToSkaraBrae, + BritainToTrinsic, + BucsDen, + BucsDenToMagincia, + BucsDenToOcllo, + Jhelom, + Magincia, + MaginciaToOcllo, + Minoc, + MinocToYew, + MinocToVesper, + Moonglow, + MoonglowToNujelm, + Nujelm, + NujelmToMagincia, + Ocllo, + SerpentsHold, + SerpentsHoldToOcllo, + SkaraBrae, + TheWorld, + Trinsic, + TrinsicToBucsDen, + TrinsicToJhelom, + Vesper, + VesperToNujelm, + Yew, + YewToBritain + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/SeaChart.cs b/Scripts/Items/Maps/SeaChart.cs new file mode 100644 index 0000000..3c53cdb --- /dev/null +++ b/Scripts/Items/Maps/SeaChart.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SeaChart : MapItem + { + [Constructable] + public SeaChart() + { + SetDisplay( 0, 0, 5119, 4095, 400, 400 ); + } + + public override void CraftInit( Mobile from ) + { + double skillValue = from.Skills[SkillName.Cartography].Value; + int dist = 64 + (int)(skillValue * 10); + + if ( dist < 200 ) + dist = 200; + + int size = 24 + (int)(skillValue * 3.3); + + if ( size < 200 ) + size = 200; + else if ( size > 400 ) + size = 400; + + SetDisplay( from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, size, size ); + } + + public override int LabelNumber{ get{ return 1015232; } } // sea chart + + public SeaChart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/TreasureMap.cs b/Scripts/Items/Maps/TreasureMap.cs new file mode 100644 index 0000000..e2c263e --- /dev/null +++ b/Scripts/Items/Maps/TreasureMap.cs @@ -0,0 +1,936 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Items +{ + public class TreasureMap : MapItem + { + private int m_Level; + private bool m_Completed; + private Mobile m_CompletedBy; + private Mobile m_Decoder; + private Map m_Map; + private Point2D m_Location; + + [CommandProperty( AccessLevel.GameMaster )] + public int Level{ get{ return m_Level; } set{ m_Level = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Completed{ get{ return m_Completed; } set{ m_Completed = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile CompletedBy{ get{ return m_CompletedBy; } set{ m_CompletedBy = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Decoder{ get{ return m_Decoder; } set{ m_Decoder = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Map ChestMap{ get{ return m_Map; } set{ m_Map = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point2D ChestLocation{ get{ return m_Location; } set{ m_Location = value; } } + + private static Point2D[] m_Locations; + private static Point2D[] m_HavenLocations; + + private static Type[][] m_SpawnTypes = new Type[][] + { + new Type[]{ typeof( HeadlessOne ), typeof( Skeleton ) }, + new Type[]{ typeof( Mongbat ), typeof( Ratman ), typeof( HeadlessOne ), typeof( Skeleton ), typeof( Zombie ) }, + new Type[]{ typeof( OrcishMage ), typeof( Gargoyle ), typeof( Gazer ), typeof( HellHound ), typeof( EarthElemental ) }, + new Type[]{ typeof( Lich ), typeof( OgreLord ), typeof( DreadSpider ), typeof( AirElemental ), typeof( FireElemental ) }, + new Type[]{ typeof( DreadSpider ), typeof( LichLord ), typeof( Daemon ), typeof( ElderGazer ), typeof( OgreLord ) }, + new Type[]{ typeof( LichLord ), typeof( Daemon ), typeof( ElderGazer ), typeof( PoisonElemental ), typeof( BloodElemental ) }, + new Type[]{ typeof( AncientWyrm ), typeof( Balron ), typeof( BloodElemental ), typeof( PoisonElemental ), typeof( Titan ) } + }; + + public const double LootChance = 0.01; // 1% chance to appear as loot + + public static Point2D GetRandomLocation() + { + if ( m_Locations == null ) + LoadLocations(); + + if ( m_Locations.Length > 0 ) + return m_Locations[Utility.Random( m_Locations.Length )]; + + return Point2D.Zero; + } + + public static Point2D GetRandomHavenLocation() + { + if ( m_HavenLocations == null ) + LoadLocations(); + + if ( m_HavenLocations.Length > 0 ) + return m_HavenLocations[Utility.Random( m_HavenLocations.Length )]; + + return Point2D.Zero; + } + + private static void LoadLocations() + { + string filePath = Path.Combine( Core.BaseDirectory, "Data/treasure.cfg" ); + + List list = new List(); + List havenList = new List(); + + if ( File.Exists( filePath ) ) + { + using ( StreamReader ip = new StreamReader( filePath ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + try + { + string[] split = line.Split( ' ' ); + + int x = Convert.ToInt32( split[0] ), y = Convert.ToInt32( split[1] ); + + Point2D loc = new Point2D( x, y ); + list.Add( loc ); + + if ( IsInHavenIsland( loc ) ) + havenList.Add( loc ); + } + catch + { + } + } + } + } + + m_Locations = list.ToArray(); + m_HavenLocations = havenList.ToArray(); + } + + public static bool IsInHavenIsland( IPoint2D loc ) + { + return ( loc.X >= 3314 && loc.X <= 3814 && loc.Y >= 2345 && loc.Y <= 3095 ); + } + + public static BaseCreature Spawn( int level, Point3D p, bool guardian ) + { + if ( level >= 0 && level < m_SpawnTypes.Length ) + { + BaseCreature bc; + + try + { + bc = (BaseCreature)Activator.CreateInstance( m_SpawnTypes[level][Utility.Random( m_SpawnTypes[level].Length )] ); + } + catch + { + return null; + } + + bc.Home = p; + bc.RangeHome = 5; + + if ( guardian && level == 0 ) + { + bc.Name = "a chest guardian"; + bc.Hue = 0x835; + } + + return bc; + } + + return null; + } + + public static BaseCreature Spawn( int level, Point3D p, Map map, Mobile target, bool guardian ) + { + if ( map == null ) + return null; + + BaseCreature c = Spawn( level, p, guardian ); + + if ( c != null ) + { + bool spawned = false; + + for ( int i = 0; !spawned && i < 10; ++i ) + { + int x = p.X - 3 + Utility.Random( 7 ); + int y = p.Y - 3 + Utility.Random( 7 ); + + if ( map.CanSpawnMobile( x, y, p.Z ) ) + { + c.MoveToWorld( new Point3D( x, y, p.Z ), map ); + spawned = true; + } + else + { + int z = map.GetAverageZ( x, y ); + + if ( map.CanSpawnMobile( x, y, z ) ) + { + c.MoveToWorld( new Point3D( x, y, z ), map ); + spawned = true; + } + } + } + + if ( !spawned ) + { + c.Delete(); + return null; + } + + if ( target != null ) + c.Combatant = target; + + return c; + } + + return null; + } + + [Constructable] + public TreasureMap( int level, Map map ) + { + m_Level = level; + //m_Map = map; + m_Map = Map.Trammel; // Scriptiz : les tr�sors sont uniquement sur Trammel ! + + if ( level == 0 ) + m_Location = GetRandomHavenLocation(); + else + m_Location = GetRandomLocation(); + + Width = 300; + Height = 300; + + int width = 600; + int height = 600; + + int x1 = m_Location.X - Utility.RandomMinMax( width / 4, (width / 4) * 3 ); + int y1 = m_Location.Y - Utility.RandomMinMax( height / 4, (height / 4) * 3 ); + + if ( x1 < 0 ) + x1 = 0; + + if ( y1 < 0 ) + y1 = 0; + + int x2 = x1 + width; + int y2 = y1 + height; + + if ( x2 >= 5120 ) + x2 = 5119; + + if ( y2 >= 4096 ) + y2 = 4095; + + x1 = x2 - width; + y1 = y2 - height; + + Bounds = new Rectangle2D( x1, y1, width, height ); + Protected = true; + + AddWorldPin( m_Location.X, m_Location.Y ); + } + + public TreasureMap( Serial serial ) : base( serial ) + { + } + + public static bool HasDiggingTool( Mobile m ) + { + if ( m.Backpack == null ) + return false; + + List items = m.Backpack.FindItemsByType(); + + foreach ( BaseHarvestTool tool in items ) + { + if ( tool.HarvestSystem == Engines.Harvest.Mining.System ) + return true; + } + + return false; + } + + public void OnBeginDig( Mobile from ) + { + if ( m_Completed ) + { + from.SendLocalizedMessage( 503028 ); // The treasure for this map has already been found. + } + else if ( m_Level == 0 && !CheckYoung( from ) ) + { + from.SendLocalizedMessage( 1046447 ); // Only a young player may use this treasure map. + } + /* + else if ( from != m_Decoder ) + { + from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure. + } + */ + else if ( m_Decoder != from && !HasRequiredSkill( from ) ) + { + from.SendLocalizedMessage( 503031 ); // You did not decode this map and have no clue where to look for the treasure. + } + else if ( !from.CanBeginAction( typeof( TreasureMap ) ) ) + { + from.SendLocalizedMessage( 503020 ); // You are already digging treasure. + } + else if ( from.Map != this.m_Map ) + { + from.SendLocalizedMessage( 1010479 ); // You seem to be in the right place, but may be on the wrong facet! + } + else + { + from.SendLocalizedMessage( 503033 ); // Where do you wish to dig? + from.Target = new DigTarget( this ); + } + } + + private class DigTarget : Target + { + private TreasureMap m_Map; + + public DigTarget( TreasureMap map ) : base( 6, true, TargetFlags.None ) + { + m_Map = map; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Map.Deleted ) + return; + + Map map = m_Map.m_Map; + + if ( m_Map.m_Completed ) + { + from.SendLocalizedMessage( 503028 ); // The treasure for this map has already been found. + } + /* + else if ( from != m_Map.m_Decoder ) + { + from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure. + } + */ + else if ( m_Map.m_Decoder != from && !m_Map.HasRequiredSkill( from ) ) + { + from.SendLocalizedMessage( 503031 ); // You did not decode this map and have no clue where to look for the treasure. + return; + } + else if ( !from.CanBeginAction( typeof( TreasureMap ) ) ) + { + from.SendLocalizedMessage( 503020 ); // You are already digging treasure. + } + else if ( !HasDiggingTool( from ) ) + { + from.SendMessage( "You must have a digging tool to dig for treasure." ); + } + else if ( from.Map != map ) + { + from.SendLocalizedMessage( 1010479 ); // You seem to be in the right place, but may be on the wrong facet! + } + else + { + IPoint3D p = targeted as IPoint3D; + + Point3D targ3D; + if ( p is Item ) + targ3D = ((Item)p).GetWorldLocation(); + else + targ3D = new Point3D( p ); + + int maxRange; + double skillValue = from.Skills[SkillName.Mining].Value; + + if ( skillValue >= 100.0 ) + maxRange = 4; + else if ( skillValue >= 81.0 ) + maxRange = 3; + else if ( skillValue >= 51.0 ) + maxRange = 2; + else + maxRange = 1; + + Point2D loc = m_Map.m_Location; + int x = loc.X, y = loc.Y; + + Point3D chest3D0 = new Point3D( loc, 0 ); + + if ( Utility.InRange( targ3D, chest3D0, maxRange ) ) + { + if ( from.Location.X == x && from.Location.Y == y ) + { + from.SendLocalizedMessage( 503030 ); // The chest can't be dug up because you are standing on top of it. + } + else if ( map != null ) + { + int z = map.GetAverageZ( x, y ); + + if ( !map.CanFit( x, y, z, 16, true, true ) ) + { + from.SendLocalizedMessage( 503021 ); // You have found the treasure chest but something is keeping it from being dug up. + } + else if ( from.BeginAction( typeof( TreasureMap ) ) ) + { + new DigTimer( from, m_Map, new Point3D( x, y, z ), map ).Start(); + } + else + { + from.SendLocalizedMessage( 503020 ); // You are already digging treasure. + } + } + } + else if ( m_Map.Level > 0 ) + { + if ( Utility.InRange( targ3D, chest3D0, 8 ) ) // We're close, but not quite + { + from.SendLocalizedMessage( 503032 ); // You dig and dig but no treasure seems to be here. + } + else + { + from.SendLocalizedMessage( 503035 ); // You dig and dig but fail to find any treasure. + } + } + else + { + if ( Utility.InRange( targ3D, chest3D0, 8 ) ) // We're close, but not quite + { + from.SendAsciiMessage( 0x44, "The treasure chest is very close!" ); + } + else + { + Direction dir = Utility.GetDirection( targ3D, chest3D0 ); + + string sDir; + switch ( dir ) + { + case Direction.North: sDir = "north"; break; + case Direction.Right: sDir = "northeast"; break; + case Direction.East: sDir = "east"; break; + case Direction.Down: sDir = "southeast"; break; + case Direction.South: sDir = "south"; break; + case Direction.Left: sDir = "southwest"; break; + case Direction.West: sDir = "west"; break; + default: sDir = "northwest"; break; + } + + from.SendAsciiMessage( 0x44, "Try looking for the treasure chest more to the {0}.", sDir ); + } + } + } + } + } + + private class DigTimer : Timer + { + private Mobile m_From; + private TreasureMap m_TreasureMap; + + private Point3D m_Location; + private Map m_Map; + + private TreasureChestDirt m_Dirt1; + private TreasureChestDirt m_Dirt2; + private TreasureMapChest m_Chest; + + private int m_Count; + + private DateTime m_NextSkillTime; + private DateTime m_NextSpellTime; + private DateTime m_NextActionTime; + private DateTime m_LastMoveTime; + + public DigTimer( Mobile from, TreasureMap treasureMap, Point3D location, Map map ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) ) + { + m_From = from; + m_TreasureMap = treasureMap; + + m_Location = location; + m_Map = map; + + m_NextSkillTime = from.NextSkillTime; + m_NextSpellTime = from.NextSpellTime; + m_NextActionTime = from.NextActionTime; + m_LastMoveTime = from.LastMoveTime; + + Priority = TimerPriority.TenMS; + } + + private void Terminate() + { + Stop(); + m_From.EndAction( typeof( TreasureMap ) ); + + if ( m_Chest != null ) + m_Chest.Delete(); + + if ( m_Dirt1 != null ) + { + m_Dirt1.Delete(); + m_Dirt2.Delete(); + } + } + + protected override void OnTick() + { + if ( m_NextSkillTime != m_From.NextSkillTime || m_NextSpellTime != m_From.NextSpellTime || m_NextActionTime != m_From.NextActionTime ) + { + Terminate(); + return; + } + + if ( m_LastMoveTime != m_From.LastMoveTime ) + { + m_From.SendLocalizedMessage( 503023 ); // You cannot move around while digging up treasure. You will need to start digging anew. + Terminate(); + return; + } + + int z = ( m_Chest != null ) ? m_Chest.Z + m_Chest.ItemData.Height : int.MinValue; + int height = 16; + + if ( z > m_Location.Z ) + height -= ( z - m_Location.Z ); + else + z = m_Location.Z; + + if ( !m_Map.CanFit( m_Location.X, m_Location.Y, z, height, true, true, false ) ) + { + m_From.SendLocalizedMessage( 503024 ); // You stop digging because something is directly on top of the treasure chest. + Terminate(); + return; + } + + m_Count++; + + m_From.RevealingAction(); + m_From.Direction = m_From.GetDirectionTo( m_Location ); + + if ( m_Count > 1 && m_Dirt1 == null ) + { + m_Dirt1 = new TreasureChestDirt(); + m_Dirt1.MoveToWorld( m_Location, m_Map ); + + m_Dirt2 = new TreasureChestDirt(); + m_Dirt2.MoveToWorld( new Point3D( m_Location.X, m_Location.Y - 1, m_Location.Z ), m_Map ); + } + + if ( m_Count == 5 ) + { + m_Dirt1.Turn1(); + } + else if ( m_Count == 10 ) + { + m_Dirt1.Turn2(); + m_Dirt2.Turn2(); + } + else if ( m_Count > 10 ) + { + if ( m_Chest == null ) + { + m_Chest = new TreasureMapChest( m_From, m_TreasureMap.Level, true ); + m_Chest.MoveToWorld( new Point3D( m_Location.X, m_Location.Y, m_Location.Z - 15 ), m_Map ); + } + else + { + m_Chest.Z++; + } + + Effects.PlaySound( m_Chest, m_Map, 0x33B ); + } + + if ( m_Chest != null && m_Chest.Location.Z >= m_Location.Z ) + { + Stop(); + m_From.EndAction( typeof( TreasureMap ) ); + + m_Chest.Temporary = false; + m_TreasureMap.Completed = true; + m_TreasureMap.CompletedBy = m_From; + + int spawns; + switch ( m_TreasureMap.Level ) + { + case 0: spawns = 3; break; + case 1: spawns = 0; break; + default: spawns = 4; break; + } + + for ( int i = 0; i < spawns; ++i ) + { + BaseCreature bc = Spawn( m_TreasureMap.Level, m_Chest.Location, m_Chest.Map, null, true ); + + if ( bc != null ) + m_Chest.Guardians.Add( bc ); + } + } + else + { + if ( m_From.Body.IsHuman && !m_From.Mounted ) + m_From.Animate( 11, 5, 1, true, false, 0 ); + + new SoundTimer( m_From, 0x125 + (m_Count % 2) ).Start(); + } + } + + private class SoundTimer : Timer + { + private Mobile m_From; + private int m_SoundID; + + public SoundTimer( Mobile from, int soundID ) : base( TimeSpan.FromSeconds( 0.9 ) ) + { + m_From = from; + m_SoundID = soundID; + + Priority = TimerPriority.TenMS; + } + + protected override void OnTick() + { + m_From.PlaySound( m_SoundID ); + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + if ( !m_Completed && m_Decoder == null ) + Decode( from ); + else + DisplayTo( from ); + } + + private bool CheckYoung( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if ( from is PlayerMobile && ((PlayerMobile)from).Young ) + return true; + + if ( from == this.Decoder ) + { + this.Level = 1; + from.SendLocalizedMessage( 1046446 ); // This is now a level one treasure map. + return true; + } + + return false; + } + + private double GetMinSkillLevel() + { + switch ( m_Level ) + { + case 1: return -3.0; + case 2: return 41.0; + case 3: return 51.0; + case 4: return 61.0; + case 5: return 70.0; + case 6: return 70.0; + + default: return 0.0; + } + } + + private bool HasRequiredSkill( Mobile from ) + { + return ( from.Skills[SkillName.Cartography].Value >= GetMinSkillLevel() ); + } + + public void Decode( Mobile from ) + { + if ( m_Completed || m_Decoder != null ) + return; + + if ( m_Level == 0 ) + { + if ( !CheckYoung( from ) ) + { + from.SendLocalizedMessage( 1046447 ); // Only a young player may use this treasure map. + return; + } + } + else + { + double minSkill = GetMinSkillLevel(); + + if ( from.Skills[SkillName.Cartography].Value < minSkill ) + from.SendLocalizedMessage( 503013 ); // The map is too difficult to attempt to decode. + + double maxSkill = minSkill + 60.0; + + if ( !from.CheckSkill( SkillName.Cartography, minSkill, maxSkill ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 503018 ); // You fail to make anything of the map. + return; + } + } + + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 503019 ); // You successfully decode a treasure map! + Decoder = from; + if (Core.AOS) + LootType = LootType.Blessed; + DisplayTo( from ); + } + + public override void DisplayTo( Mobile from ) + { + if ( m_Completed ) + { + SendLocalizedMessageTo( from, 503014 ); // This treasure hunt has already been completed. + } + else if ( m_Level == 0 && !CheckYoung( from ) ) + { + from.SendLocalizedMessage( 1046447 ); // Only a young player may use this treasure map. + return; + } + else if ( m_Decoder != from && !HasRequiredSkill( from ) ) + { + from.SendLocalizedMessage( 503031 ); // You did not decode this map and have no clue where to look for the treasure. + return; + } + else + { + SendLocalizedMessageTo( from, 503017 ); // The treasure is marked by the red pin. Grab a shovel and go dig it up! + } + + from.PlaySound( 0x249 ); + base.DisplayTo( from ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( !m_Completed ) + { + if ( m_Decoder == null ) + { + list.Add( new DecodeMapEntry( this ) ); + } + else + { + bool digTool = HasDiggingTool( from ); + + list.Add( new OpenMapEntry( this ) ); + list.Add( new DigEntry( this, digTool ) ); + } + } + } + + private class DecodeMapEntry : ContextMenuEntry + { + private TreasureMap m_Map; + + public DecodeMapEntry( TreasureMap map ) : base( 6147, 2 ) + { + m_Map = map; + } + + public override void OnClick() + { + if ( !m_Map.Deleted ) + m_Map.Decode( Owner.From ); + } + } + + private class OpenMapEntry : ContextMenuEntry + { + private TreasureMap m_Map; + + public OpenMapEntry( TreasureMap map ) : base( 6150, 2 ) + { + m_Map = map; + } + + public override void OnClick() + { + if ( !m_Map.Deleted ) + m_Map.DisplayTo( Owner.From ); + } + } + + private class DigEntry : ContextMenuEntry + { + private TreasureMap m_Map; + + public DigEntry( TreasureMap map, bool enabled ) : base( 6148, 2 ) + { + m_Map = map; + + if ( !enabled ) + this.Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if ( m_Map.Deleted ) + return; + + Mobile from = Owner.From; + + if ( HasDiggingTool( from ) ) + m_Map.OnBeginDig( from ); + else + from.SendMessage( "You must have a digging tool to dig for treasure." ); + } + } + + public override int LabelNumber + { + get + { + if ( m_Decoder != null ) + { + if ( m_Level == 6 ) + return 1063453; + else + return 1041516 + m_Level; + } + else if ( m_Level == 6 ) + return 1063452; + else + return 1041510 + m_Level; + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( m_Map == Map.Felucca ? 1041502 : 1041503 ); // for somewhere in Felucca : for somewhere in Trammel + + if ( m_Completed ) + { + list.Add( 1041507, m_CompletedBy == null ? "someone" : m_CompletedBy.Name ); // completed by ~1_val~ + } + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Completed ) + { + from.Send( new MessageLocalizedAffix( Serial, ItemID, MessageType.Label, 0x3B2, 3, 1048030, "", AffixType.Append, String.Format( " completed by {0}", m_CompletedBy == null ? "someone" : m_CompletedBy.Name ), "" ) ); + } + else if ( m_Decoder != null ) + { + if ( m_Level == 6 ) + LabelTo( from, 1063453 ); + else + LabelTo( from, 1041516 + m_Level ); + } + else + { + if ( m_Level == 6 ) + LabelTo( from, 1041522, String.Format( "#{0}\t \t#{1}", 1063452, m_Map == Map.Felucca ? 1041502 : 1041503 ) ); + else + LabelTo( from, 1041522, String.Format( "#{0}\t \t#{1}", 1041510 + m_Level, m_Map == Map.Felucca ? 1041502 : 1041503 ) ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.Write( (Mobile) m_CompletedBy ); + + writer.Write( m_Level ); + writer.Write( m_Completed ); + writer.Write( m_Decoder ); + writer.Write( m_Map ); + writer.Write( m_Location ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_CompletedBy = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_Level = (int)reader.ReadInt(); + m_Completed = reader.ReadBool(); + m_Decoder = reader.ReadMobile(); + m_Map = reader.ReadMap(); + m_Location = reader.ReadPoint2D(); + + if ( version == 0 && m_Completed ) + m_CompletedBy = m_Decoder; + + break; + } + } + if (Core.AOS && m_Decoder != null && LootType == LootType.Regular) + LootType = LootType.Blessed; + } + } + + public class TreasureChestDirt : Item + { + public TreasureChestDirt() : base( 0x912 ) + { + Movable = false; + + Timer.DelayCall( TimeSpan.FromMinutes( 2.0 ), new TimerCallback( Delete ) ); + } + + public TreasureChestDirt( Serial serial ) : base( serial ) + { + } + + public void Turn1() + { + this.ItemID = 0x913; + } + + public void Turn2() + { + this.ItemID = 0x914; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Maps/WorldMap.cs b/Scripts/Items/Maps/WorldMap.cs new file mode 100644 index 0000000..df68ea7 --- /dev/null +++ b/Scripts/Items/Maps/WorldMap.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WorldMap : MapItem + { + [Constructable] + public WorldMap() + { + SetDisplay( 0, 0, 5119, 4095, 400, 400 ); + } + + public override void CraftInit( Mobile from ) + { + // Unlike the others, world map is not based on crafted location + + double skillValue = from.Skills[SkillName.Cartography].Value; + int x20 = (int)(skillValue * 20); + int size = 25 + (int)(skillValue * 6.6); + + if ( size < 200 ) + size = 200; + else if ( size > 400 ) + size = 400; + + // Scriptiz : on ajuste les world map aux �les accessibles (point de d�part � new haven plut�t que britain) + SetDisplay(3439 - x20, 2510 - x20, 3567 + x20, 2638 + x20, size, size); + //SetDisplay( 1344 - x20, 1600 - x20, 1472 + x20, 1728 + x20, size, size ); + } + + public override int LabelNumber{ get{ return 1015233; } } // world map + + public WorldMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/AdmiralsHeartyRum.cs b/Scripts/Items/Minor Artifacts/AdmiralsHeartyRum.cs new file mode 100644 index 0000000..d0d1bfd --- /dev/null +++ b/Scripts/Items/Minor Artifacts/AdmiralsHeartyRum.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AdmiralsHeartyRum : BeverageBottle + { + public override int LabelNumber{ get{ return 1063477; } } + + [Constructable] + public AdmiralsHeartyRum() : base( BeverageType.Ale ) + { + Hue = 0x66C; + } + + public AdmiralsHeartyRum( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/AlchemistsBauble.cs b/Scripts/Items/Minor Artifacts/AlchemistsBauble.cs new file mode 100644 index 0000000..f1f4339 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/AlchemistsBauble.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AlchemistsBauble : GoldBracelet + { + public override int LabelNumber{ get{ return 1070638; } } + + [Constructable] + public AlchemistsBauble() + { + Hue = 0x290; + SkillBonuses.SetValues( 0, SkillName.Magery, 10.0 ); + Attributes.EnhancePotions = 30; + Attributes.LowerRegCost = 20; + Resistances.Poison = 10; + } + + public AlchemistsBauble( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ArcticDeathDealer.cs b/Scripts/Items/Minor Artifacts/ArcticDeathDealer.cs new file mode 100644 index 0000000..7ddbad2 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ArcticDeathDealer.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcticDeathDealer : WarMace + { + public override int LabelNumber{ get{ return 1063481; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ArcticDeathDealer() + { + Hue = 0x480; + WeaponAttributes.HitHarm = 33; + WeaponAttributes.HitLowerAttack = 40; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 40; + WeaponAttributes.ResistColdBonus = 10; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + cold = 50; + phys = 50; + + pois = fire = nrgy = chaos = direct = 0; + } + + public ArcticDeathDealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/BlazeOfDeath.cs b/Scripts/Items/Minor Artifacts/BlazeOfDeath.cs new file mode 100644 index 0000000..6f5a23a --- /dev/null +++ b/Scripts/Items/Minor Artifacts/BlazeOfDeath.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BlazeOfDeath : Halberd + { + public override int LabelNumber{ get{ return 1063486; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BlazeOfDeath() + { + Hue = 0x501; + WeaponAttributes.HitFireArea = 50; + WeaponAttributes.HitFireball = 50; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 35; + WeaponAttributes.ResistFireBonus = 10; + WeaponAttributes.LowerStatReq = 100; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + fire = 50; + phys = 50; + + cold = pois = nrgy = chaos = direct = 0; + } + + public BlazeOfDeath( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/BowOfTheJukaKing.cs b/Scripts/Items/Minor Artifacts/BowOfTheJukaKing.cs new file mode 100644 index 0000000..04896ff --- /dev/null +++ b/Scripts/Items/Minor Artifacts/BowOfTheJukaKing.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BowOfTheJukaKing : Bow + { + public override int LabelNumber{ get{ return 1070636; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BowOfTheJukaKing() + { + Hue = 0x460; + WeaponAttributes.HitMagicArrow = 25; + Slayer = SlayerName.ReptilianDeath; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 40; + } + + public BowOfTheJukaKing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/BurglarsBandana.cs b/Scripts/Items/Minor Artifacts/BurglarsBandana.cs new file mode 100644 index 0000000..d05022d --- /dev/null +++ b/Scripts/Items/Minor Artifacts/BurglarsBandana.cs @@ -0,0 +1,58 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BurglarsBandana : Bandana + { + public override int LabelNumber{ get{ return 1063473; } } + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BurglarsBandana() + { + Hue = Utility.RandomBool() ? 0x58C : 0x10; + + SkillBonuses.SetValues( 0, SkillName.Stealing, 10.0 ); + SkillBonuses.SetValues( 1, SkillName.Stealth, 10.0 ); + SkillBonuses.SetValues( 2, SkillName.Snooping, 10.0 ); + + Attributes.BonusDex = 5; + } + + public BurglarsBandana( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 2 ) + { + Resistances.Physical = 0; + Resistances.Fire = 0; + Resistances.Cold = 0; + Resistances.Poison = 0; + Resistances.Energy = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/CandelabraOfSouls.cs b/Scripts/Items/Minor Artifacts/CandelabraOfSouls.cs new file mode 100644 index 0000000..19be66e --- /dev/null +++ b/Scripts/Items/Minor Artifacts/CandelabraOfSouls.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CandelabraOfSouls : Item + { + public override int LabelNumber{ get{ return 1063478; } } + + [Constructable] + public CandelabraOfSouls() : base( 0xB26 ) + { + } + + public CandelabraOfSouls( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/CaptainQuacklebushsCutlass.cs b/Scripts/Items/Minor Artifacts/CaptainQuacklebushsCutlass.cs new file mode 100644 index 0000000..158be86 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/CaptainQuacklebushsCutlass.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CaptainQuacklebushsCutlass : Cutlass + { + public override int LabelNumber{ get{ return 1063474; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public CaptainQuacklebushsCutlass() + { + Hue = 0x66C; + Attributes.BonusDex = 5; + Attributes.AttackChance = 10; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 50; + WeaponAttributes.UseBestSkill = 1; + } + + public CaptainQuacklebushsCutlass( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( Attributes.AttackChance == 50 ) + Attributes.AttackChance = 10; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/CavortingClub.cs b/Scripts/Items/Minor Artifacts/CavortingClub.cs new file mode 100644 index 0000000..13af361 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/CavortingClub.cs @@ -0,0 +1,44 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CavortingClub : Club + { + public override int LabelNumber{ get{ return 1063472; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public CavortingClub() + { + Hue = 0x593; + WeaponAttributes.SelfRepair = 3; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 35; + WeaponAttributes.ResistFireBonus = 8; + WeaponAttributes.ResistColdBonus = 8; + WeaponAttributes.ResistPoisonBonus = 8; + WeaponAttributes.ResistEnergyBonus = 8; + } + + public CavortingClub( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ColdBlood.cs b/Scripts/Items/Minor Artifacts/ColdBlood.cs new file mode 100644 index 0000000..a14b9ad --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ColdBlood.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ColdBlood : Cleaver + { + public override int LabelNumber{ get{ return 1070818; } } // Cold Blood + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ColdBlood() + { + Hue = 0x4F2; + + Attributes.WeaponSpeed = 40; + + Attributes.BonusHits = 6; + Attributes.BonusStam = 6; + Attributes.BonusMana = 6; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + cold = 100; + + fire = phys = pois = nrgy = chaos = direct = 0; + } + + public ColdBlood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/DreadPirateHat.cs b/Scripts/Items/Minor Artifacts/DreadPirateHat.cs new file mode 100644 index 0000000..fe4f399 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/DreadPirateHat.cs @@ -0,0 +1,61 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DreadPirateHat : TricorneHat + { + public override int LabelNumber{ get{ return 1063467; } } + + public override int BaseColdResistance{ get{ return 14; } } + public override int BasePoisonResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public DreadPirateHat() + { + Hue = 0x497; + + SkillBonuses.SetValues( 0, Utility.RandomCombatSkill(), 10.0 ); + + Attributes.BonusDex = 8; + Attributes.AttackChance = 10; + Attributes.NightSight = 1; + } + + public DreadPirateHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 3 ) + { + Resistances.Cold = 0; + Resistances.Poison = 0; + } + + if ( version < 1 ) + { + Attributes.Luck = 0; + Attributes.AttackChance = 10; + Attributes.NightSight = 1; + SkillBonuses.SetValues( 0, Utility.RandomCombatSkill(), 10.0 ); + SkillBonuses.SetBonus( 1, 0 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/EnchantedTitanLegBone.cs b/Scripts/Items/Minor Artifacts/EnchantedTitanLegBone.cs new file mode 100644 index 0000000..076d750 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/EnchantedTitanLegBone.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class EnchantedTitanLegBone : ShortSpear + { + public override int LabelNumber{ get{ return 1063482; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public EnchantedTitanLegBone() + { + Hue = 0x8A5; + WeaponAttributes.HitLowerDefend = 40; + WeaponAttributes.HitLightning = 40; + Attributes.AttackChance = 10; + Attributes.WeaponDamage = 20; + WeaponAttributes.ResistPhysicalBonus = 10; + } + + public EnchantedTitanLegBone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/GhostShipAnchor.cs b/Scripts/Items/Minor Artifacts/GhostShipAnchor.cs new file mode 100644 index 0000000..1341673 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/GhostShipAnchor.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GhostShipAnchor : Item + { + public override int LabelNumber{ get{ return 1070816; } } // Ghost Ship Anchor + + [Constructable] + public GhostShipAnchor() : base( 0x14F7 ) + { + Hue = 0x47E; + } + + public GhostShipAnchor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( ItemID == 0x1F47 ) + ItemID = 0x14F7; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/GlovesOfThePugilist.cs b/Scripts/Items/Minor Artifacts/GlovesOfThePugilist.cs new file mode 100644 index 0000000..126b133 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/GlovesOfThePugilist.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GlovesOfThePugilist : LeatherGloves + { + public override int LabelNumber{ get{ return 1070690; } } + + public override int BasePhysicalResistance{ get{ return 18; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public GlovesOfThePugilist() + { + Hue = 0x6D1; + SkillBonuses.SetValues( 0, SkillName.Wrestling, 10.0 ); + Attributes.BonusDex = 8; + Attributes.WeaponDamage = 15; + } + + public GlovesOfThePugilist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/GoldBricks.cs b/Scripts/Items/Minor Artifacts/GoldBricks.cs new file mode 100644 index 0000000..ceaa039 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/GoldBricks.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GoldBricks : Item + { + public override int LabelNumber{ get{ return 1063489; } } + + [Constructable] + public GoldBricks() : base( 0x1BEB ) + { + } + + public GoldBricks( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/GwennosHarp.cs b/Scripts/Items/Minor Artifacts/GwennosHarp.cs new file mode 100644 index 0000000..bc5020d --- /dev/null +++ b/Scripts/Items/Minor Artifacts/GwennosHarp.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GwennosHarp : LapHarp + { + public override int LabelNumber{ get{ return 1063480; } } + + public override int InitMinUses{ get{ return 1600; } } + public override int InitMaxUses{ get{ return 1600; } } + + [Constructable] + public GwennosHarp() + { + Hue = 0x47E; + Slayer = SlayerName.Repond; + Slayer2 = SlayerName.ReptilianDeath; + } + + public GwennosHarp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/HeartOfTheLion.cs b/Scripts/Items/Minor Artifacts/HeartOfTheLion.cs new file mode 100644 index 0000000..9c8cf63 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/HeartOfTheLion.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HeartOfTheLion : PlateChest + { + public override int LabelNumber{ get{ return 1070817; } } // Heart of the Lion + + public override int BasePhysicalResistance{ get{ return 15; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 10; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HeartOfTheLion() + { + Hue = 0x501; + Attributes.Luck = 95; + Attributes.DefendChance = 15; + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + } + + public HeartOfTheLion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/IolosLute.cs b/Scripts/Items/Minor Artifacts/IolosLute.cs new file mode 100644 index 0000000..3d76616 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/IolosLute.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class IolosLute : Lute + { + public override int LabelNumber{ get{ return 1063479; } } + + public override int InitMinUses{ get{ return 1600; } } + public override int InitMaxUses{ get{ return 1600; } } + + [Constructable] + public IolosLute() + { + Hue = 0x47E; + Slayer = SlayerName.Silver; + //Slayer2 = SlayerName.DaemonDismissal; + Slayer2 = SlayerName.Exorcism; + } + + public IolosLute( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/LunaLance.cs b/Scripts/Items/Minor Artifacts/LunaLance.cs new file mode 100644 index 0000000..7195681 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/LunaLance.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LunaLance : Lance + { + public override int LabelNumber{ get{ return 1063469; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public LunaLance() + { + Hue = 0x47E; + SkillBonuses.SetValues( 0, SkillName.Chivalry, 10.0 ); + Attributes.BonusStr = 5; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 35; + WeaponAttributes.UseBestSkill = 1; + } + + public LunaLance( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/AegisOfGrace.cs b/Scripts/Items/Minor Artifacts/ML/AegisOfGrace.cs new file mode 100644 index 0000000..6e1632f --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/AegisOfGrace.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class AegisOfGrace : DragonHelm + { + public override int LabelNumber{ get{ return 1075047; } } // Aegis of Grace + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 9; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 7; } } + public override int BaseEnergyResistance{ get{ return 15; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Dragon; } } + public override CraftResource DefaultResource{ get{ return CraftResource.MIron; } } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + [Constructable] + public AegisOfGrace() + { + SkillBonuses.SetValues( 0, SkillName.MagicResist, 10.0 ); + + Attributes.DefendChance = 20; + + ArmorAttributes.SelfRepair = 2; + } + + public override Race RequiredRace + { + get + { + return Race.Elf; + } + } + + public AegisOfGrace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/BladeDance.cs b/Scripts/Items/Minor Artifacts/ML/BladeDance.cs new file mode 100644 index 0000000..d8b65ac --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/BladeDance.cs @@ -0,0 +1,44 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class BladeDance : RuneBlade + { + public override int LabelNumber{ get{ return 1075033; } } // Blade Dance + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BladeDance() + { + Hue = 0x66C; + + Attributes.BonusMana = 8; + Attributes.SpellChanneling = 1; + Attributes.WeaponDamage = 30; + WeaponAttributes.HitLeechMana = 20; + WeaponAttributes.UseBestSkill = 1; + } + + public BladeDance( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/BloodwoodSpirit.cs b/Scripts/Items/Minor Artifacts/ML/BloodwoodSpirit.cs new file mode 100644 index 0000000..5964616 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/BloodwoodSpirit.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BloodwoodSpirit : BaseTalisman + { + public override int LabelNumber{ get{ return 1075034; } } // Bloodwood Spirit + public override bool ForceShowName{ get{ return true; } } + + [Constructable] + public BloodwoodSpirit() : base( 0x2F5A ) + { + Hue = 0x27; + MaxChargeTime = 1200; + + Removal = TalismanRemoval.Damage; + Blessed = GetRandomBlessed(); + Protection = GetRandomProtection(false); + + SkillBonuses.SetValues( 0, SkillName.SpiritSpeak, 10.0 ); + SkillBonuses.SetValues( 1, SkillName.Necromancy, 5.0 ); + } + + public BloodwoodSpirit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if (version == 0 && (Protection == null || Protection.IsEmpty)) + Protection = GetRandomProtection(false); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/Bonesmasher.cs b/Scripts/Items/Minor Artifacts/ML/Bonesmasher.cs new file mode 100644 index 0000000..1dde6ac --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/Bonesmasher.cs @@ -0,0 +1,44 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class Bonesmasher : DiamondMace + { + public override int LabelNumber{ get{ return 1075030; } } // Bonesmasher + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public Bonesmasher() + { + ItemID = 0x2D30; + Hue = 0x482; + + SkillBonuses.SetValues( 0, SkillName.Macing, 10.0 ); + + WeaponAttributes.HitLeechMana = 40; + WeaponAttributes.SelfRepair = 2; + } + + public Bonesmasher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/Boomstick.cs b/Scripts/Items/Minor Artifacts/ML/Boomstick.cs new file mode 100644 index 0000000..45df0ee --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/Boomstick.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Boomstick : WildStaff + { + public override int LabelNumber{ get{ return 1075032; } } // Boomstick + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public Boomstick() : base() + { + Hue = 0x25; + + Attributes.SpellChanneling = 1; + Attributes.RegenMana = 3; + Attributes.CastSpeed = 1; + Attributes.LowerRegCost = 20; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = nrgy = direct = 0; + chaos = 100; + } + + public Boomstick( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/BrightsightLenses.cs b/Scripts/Items/Minor Artifacts/ML/BrightsightLenses.cs new file mode 100644 index 0000000..becdb25 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/BrightsightLenses.cs @@ -0,0 +1,56 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BrightsightLenses : ElvenGlasses + { + public override int LabelNumber { get { return 1075039; } } // Brightsight Lenses + + public override int BasePhysicalResistance { get { return 9; } } + public override int BaseFireResistance { get { return 29; } } + public override int BaseColdResistance { get { return 7; } } + public override int BasePoisonResistance { get { return 8; } } + public override int BaseEnergyResistance { get { return 7; } } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + [Constructable] + public BrightsightLenses() + : base() + { + Hue = 0x501; + + Attributes.NightSight = 1; + Attributes.RegenMana = 3; + + ArmorAttributes.SelfRepair = 3; + } + + public BrightsightLenses(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1) + { + WeaponAttributes.SelfRepair = 0; + ArmorAttributes.SelfRepair = 3; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/FeyLeggings.cs b/Scripts/Items/Minor Artifacts/ML/FeyLeggings.cs new file mode 100644 index 0000000..8b2605b --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/FeyLeggings.cs @@ -0,0 +1,50 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class FeyLeggings : ChainLegs + { + public override int LabelNumber{ get{ return 1075041; } } // Fey Leggings + + public override int BasePhysicalResistance{ get{ return 12; } } + public override int BaseFireResistance{ get{ return 8; } } + public override int BaseColdResistance{ get{ return 7; } } + public override int BasePoisonResistance{ get{ return 4; } } + public override int BaseEnergyResistance{ get{ return 19; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get { return 255; } } + + + [Constructable] + public FeyLeggings() + { + Attributes.BonusHits = 6; + Attributes.DefendChance = 20; + + ArmorAttributes.MageArmor = 1; + } + + public override Race RequiredRace { get { return Race.Elf; } } + + public FeyLeggings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/FleshRipper.cs b/Scripts/Items/Minor Artifacts/ML/FleshRipper.cs new file mode 100644 index 0000000..4158982 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/FleshRipper.cs @@ -0,0 +1,47 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class FleshRipper : AssassinSpike + { + public override int LabelNumber{ get{ return 1075045; } } // Flesh Ripper + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public FleshRipper() + { + Hue = 0x341; + + SkillBonuses.SetValues( 0, SkillName.Anatomy, 10.0 ); + + Attributes.BonusStr = 5; + Attributes.AttackChance = 15; + Attributes.WeaponSpeed = 40; + + WeaponAttributes.UseBestSkill = 1; + // TODO: Mage Slayer + } + + public FleshRipper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/HelmOfSwiftness.cs b/Scripts/Items/Minor Artifacts/ML/HelmOfSwiftness.cs new file mode 100644 index 0000000..fce507e --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/HelmOfSwiftness.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HelmOfSwiftness : WingedHelm + { + public override int LabelNumber{ get{ return 1075037; } } // Helm of Swiftness + + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 6; } } + public override int BasePoisonResistance{ get{ return 6; } } + public override int BaseEnergyResistance{ get{ return 8; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HelmOfSwiftness() : base() + { + Hue = 0x592; + + Attributes.BonusInt = 5; + Attributes.CastSpeed = 1; + Attributes.CastRecovery = 2; + ArmorAttributes.MageArmor = 1; + } + + public HelmOfSwiftness( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/MelisandesCorrodedHatchet.cs b/Scripts/Items/Minor Artifacts/ML/MelisandesCorrodedHatchet.cs new file mode 100644 index 0000000..5939885 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/MelisandesCorrodedHatchet.cs @@ -0,0 +1,43 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class MelisandesCorrodedHatchet : Hatchet + { + public override int LabelNumber{ get{ return 1072115; } } // Melisande's Corroded Hatchet + + [Constructable] + public MelisandesCorrodedHatchet() + { + Hue = 0x494; + + SkillBonuses.SetValues( 0, SkillName.Lumberjacking, 5.0 ); + + Attributes.SpellChanneling = 1; + Attributes.WeaponSpeed = 15; + Attributes.WeaponDamage = -50; + + WeaponAttributes.SelfRepair = 4; + } + + public MelisandesCorrodedHatchet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/PadsOfTheCuSidhe.cs b/Scripts/Items/Minor Artifacts/ML/PadsOfTheCuSidhe.cs new file mode 100644 index 0000000..7618724 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/PadsOfTheCuSidhe.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PadsOfTheCuSidhe : FurBoots + { + public override int LabelNumber{ get{ return 1075048; } } // Pads of the Cu Sidhe + + [Constructable] + public PadsOfTheCuSidhe() : base( 0x47E ) + { + } + + public PadsOfTheCuSidhe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/QuiverOfElements.cs b/Scripts/Items/Minor Artifacts/ML/QuiverOfElements.cs new file mode 100644 index 0000000..523ce4b --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/QuiverOfElements.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class QuiverOfElements : BaseQuiver + { + public override int LabelNumber{ get{ return 1075040; } } // Quiver of the Elements + + [Constructable] + public QuiverOfElements() : base() + { + Hue = 0xEB; + + WeightReduction = 50; + } + + public QuiverOfElements( Serial serial ) : base( serial ) + { + } + + public override void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + phys = fire = cold = pois = nrgy = direct = 0; + chaos = 100; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/QuiverOfRage.cs b/Scripts/Items/Minor Artifacts/ML/QuiverOfRage.cs new file mode 100644 index 0000000..060840c --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/QuiverOfRage.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class QuiverOfRage : BaseQuiver + { + public override int LabelNumber{ get{ return 1075038; } } // Quiver of Rage + + [Constructable] + public QuiverOfRage() : base() + { + Hue = 0x24C; + + WeightReduction = 25; + DamageIncrease = 10; + } + + public QuiverOfRage( Serial serial ) : base( serial ) + { + } + + public override void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + chaos = direct = 0; + phys = fire = cold = pois = nrgy = 20; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/RaedsGlory.cs b/Scripts/Items/Minor Artifacts/ML/RaedsGlory.cs new file mode 100644 index 0000000..3f73fe3 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/RaedsGlory.cs @@ -0,0 +1,45 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class RaedsGlory : WarCleaver + { + public override int LabelNumber{ get{ return 1075036; } } // Raed's Glory + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public RaedsGlory() + { + ItemID = 0x2D23; + Hue = 0x1E6; + + Attributes.BonusMana = 8; + Attributes.SpellChanneling = 1; + Attributes.WeaponSpeed = 20; + + WeaponAttributes.HitLeechHits = 40; + } + + public RaedsGlory( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/RighteousAnger.cs b/Scripts/Items/Minor Artifacts/ML/RighteousAnger.cs new file mode 100644 index 0000000..abc58bd --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/RighteousAnger.cs @@ -0,0 +1,43 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class RighteousAnger : ElvenMachete + { + public override int LabelNumber{ get{ return 1075049; } } // Righteous Anger + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public RighteousAnger() + { + Hue = 0x284; + + Attributes.AttackChance = 15; + Attributes.DefendChance = 5; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 40; + } + + public RighteousAnger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/RobeOfTheEclipse.cs b/Scripts/Items/Minor Artifacts/ML/RobeOfTheEclipse.cs new file mode 100644 index 0000000..0571f17 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/RobeOfTheEclipse.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1F03, 0x1F04 )] + public class RobeOfTheEclipse : BaseOuterTorso + { + public override int LabelNumber{ get{ return 1075082; } } // Robe of the Eclipse + + [Constructable] + public RobeOfTheEclipse() : base( 0x1F03, 0x486 ) + { + Weight = 3.0; + + Attributes.Luck = 95; + + // TODO: Supports arcane? + } + + public RobeOfTheEclipse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/RobeOfTheEquinox.cs b/Scripts/Items/Minor Artifacts/ML/RobeOfTheEquinox.cs new file mode 100644 index 0000000..845f2a3 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/RobeOfTheEquinox.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1F03, 0x1F04 )] + public class RobeOfTheEquinox : BaseOuterTorso + { + public override int LabelNumber{ get{ return 1075042; } } // Robe of the Equinox + + [Constructable] + public RobeOfTheEquinox() : base( 0x1F04, 0xD6 ) + { + Weight = 3.0; + + Attributes.Luck = 95; + + // TODO: Supports arcane? + // TODO: Elves Only + } + + public RobeOfTheEquinox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/SoulSeeker.cs b/Scripts/Items/Minor Artifacts/ML/SoulSeeker.cs new file mode 100644 index 0000000..6994109 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/SoulSeeker.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class SoulSeeker : RadiantScimitar + { + public override int LabelNumber{ get{ return 1075046; } } // Soul Seeker + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public SoulSeeker() + { + Hue = 0x38C; + + WeaponAttributes.HitLeechStam = 40; + WeaponAttributes.HitLeechMana = 40; + WeaponAttributes.HitLeechHits = 40; + Attributes.WeaponSpeed = 60; + Slayer = SlayerName.Repond; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + cold = 100; + + pois = fire = phys = nrgy = chaos = direct = 0; + } + + public SoulSeeker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/TalonBite.cs b/Scripts/Items/Minor Artifacts/ML/TalonBite.cs new file mode 100644 index 0000000..330cd22 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/TalonBite.cs @@ -0,0 +1,48 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class TalonBite : OrnateAxe + { + public override int LabelNumber{ get{ return 1075029; } } // Talon Bite + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TalonBite() + { + ItemID = 0x2D34; + Hue = 0x47E; + + SkillBonuses.SetValues( 0, SkillName.Tactics, 10.0 ); + + Attributes.BonusDex = 8; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 35; + + WeaponAttributes.HitHarm = 33; + WeaponAttributes.UseBestSkill = 1; + } + + public TalonBite( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ML/TotemOfVoid.cs b/Scripts/Items/Minor Artifacts/ML/TotemOfVoid.cs new file mode 100644 index 0000000..13aa2e4 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/TotemOfVoid.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class TotemOfVoid : BaseTalisman + { + public override int LabelNumber{ get{ return 1075035; } } // Totem of the Void + public override bool ForceShowName{ get{ return true; } } + + [Constructable] + public TotemOfVoid() : base( 0x2F5B ) + { + Hue = 0x2D0; + MaxChargeTime = 1800; + + Blessed = GetRandomBlessed(); + Protection = GetRandomProtection(false); + + Attributes.RegenHits = 2; + Attributes.LowerManaCost = 10; + } + + public TotemOfVoid( Serial serial ) : base( serial ) + { + } + + public override Type GetSummoner() + { + return Utility.RandomBool() ? typeof( SummonedSkeletalKnight ) : typeof( SummonedSheep ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if (version == 0 && (Protection == null || Protection.IsEmpty)) + Protection = GetRandomProtection(false); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/WildfireBow.cs b/Scripts/Items/Minor Artifacts/ML/WildfireBow.cs new file mode 100644 index 0000000..4efa6d3 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/WildfireBow.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WildfireBow : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1075044; } } // Wildfire Bow + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public WildfireBow() : base() + { + Hue = 0x489; + + SkillBonuses.SetValues( 0, SkillName.Archery, 10 ); + WeaponAttributes.ResistFireBonus = 25; + + Velocity = 15; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = cold = pois = nrgy = chaos = direct = 0; + fire = 100; + } + + public WildfireBow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/ML/Windsong.cs b/Scripts/Items/Minor Artifacts/ML/Windsong.cs new file mode 100644 index 0000000..b0f683a --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ML/Windsong.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Windsong : MagicalShortbow + { + public override int LabelNumber{ get{ return 1075031; } } // Windsong + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public Windsong() : base() + { + Hue = 0xF7; + + Attributes.WeaponDamage = 35; + WeaponAttributes.SelfRepair = 3; + + Velocity = 25; + } + + public Windsong( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Minor Artifacts/NightsKiss.cs b/Scripts/Items/Minor Artifacts/NightsKiss.cs new file mode 100644 index 0000000..842a37e --- /dev/null +++ b/Scripts/Items/Minor Artifacts/NightsKiss.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NightsKiss : Dagger + { + public override int LabelNumber{ get{ return 1063475; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public NightsKiss() + { + ItemID = 0xF51; + Hue = 0x455; + WeaponAttributes.HitLeechHits = 40; + Slayer = SlayerName.Repond; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 35; + } + + public NightsKiss( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/NoxRangersHeavyCrossbow.cs b/Scripts/Items/Minor Artifacts/NoxRangersHeavyCrossbow.cs new file mode 100644 index 0000000..a3de213 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/NoxRangersHeavyCrossbow.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public class NoxRangersHeavyCrossbow : HeavyCrossbow + { + public override int LabelNumber{ get{ return 1063485; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public NoxRangersHeavyCrossbow() + { + Hue = 0x58C; + WeaponAttributes.HitLeechStam = 40; + Attributes.SpellChanneling = 1; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 20; + WeaponAttributes.ResistPoisonBonus = 10; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + pois = 50; + phys = 50; + + fire = cold = nrgy = chaos = direct = 0; + } + + public NoxRangersHeavyCrossbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/OrcishVisage.cs b/Scripts/Items/Minor Artifacts/OrcishVisage.cs new file mode 100644 index 0000000..9959821 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/OrcishVisage.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrcishVisage : OrcHelm + { + public override int LabelNumber{ get{ return 1070691; } } + + public override int BasePhysicalResistance{ get{ return 8; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public OrcishVisage() + { + Hue = 0x592; + ArmorAttributes.SelfRepair = 3; + Attributes.BonusStr = 10; + Attributes.BonusStam = 5; + } + + public OrcishVisage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/PhillipsWoodenSteed.cs b/Scripts/Items/Minor Artifacts/PhillipsWoodenSteed.cs new file mode 100644 index 0000000..1122a20 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/PhillipsWoodenSteed.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PhillipsWoodenSteed : MonsterStatuette + { + [Constructable] + public PhillipsWoodenSteed() : base( MonsterStatuetteType.PhillipsWoodenSteed ) + { + LootType = LootType.Regular; + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public PhillipsWoodenSteed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/PixieSwatter.cs b/Scripts/Items/Minor Artifacts/PixieSwatter.cs new file mode 100644 index 0000000..a86103c --- /dev/null +++ b/Scripts/Items/Minor Artifacts/PixieSwatter.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PixieSwatter : Scepter + { + public override int LabelNumber{ get{ return 1070854; } } // Pixie Swatter + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public PixieSwatter() + { + Hue = 0x8A; + WeaponAttributes.HitPoisonArea = 75; + Attributes.WeaponSpeed = 30; + + WeaponAttributes.UseBestSkill = 1; + WeaponAttributes.ResistFireBonus = 12; + WeaponAttributes.ResistEnergyBonus = 12; + + Slayer = SlayerName.Fey; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + fire = 100; + + cold = pois = phys = nrgy = chaos = direct = 0; + } + + public PixieSwatter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/PolarBearMask.cs b/Scripts/Items/Minor Artifacts/PolarBearMask.cs new file mode 100644 index 0000000..915ec4f --- /dev/null +++ b/Scripts/Items/Minor Artifacts/PolarBearMask.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PolarBearMask : BearMask + { + public override int LabelNumber{ get{ return 1070637; } } + + public override int BasePhysicalResistance{ get{ return 15; } } + public override int BaseColdResistance{ get{ return 21; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public PolarBearMask() + { + Hue = 0x481; + + ClothingAttributes.SelfRepair = 3; + + Attributes.RegenHits = 2; + Attributes.NightSight = 1; + } + + public PolarBearMask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 2 ) + { + Resistances.Physical = 0; + Resistances.Cold = 0; + } + + if ( Attributes.NightSight == 0 ) + Attributes.NightSight = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/SeahorseStatuette.cs b/Scripts/Items/Minor Artifacts/SeahorseStatuette.cs new file mode 100644 index 0000000..2f00c80 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/SeahorseStatuette.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SeahorseStatuette : MonsterStatuette + { + [Constructable] + public SeahorseStatuette() : base( MonsterStatuetteType.Seahorse ) + { + LootType = LootType.Regular; + + Hue = Utility.RandomList( 0, 0x482, 0x489, 0x495, 0x4F2 ); + } + + public SeahorseStatuette( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ShieldOfInvulnerability.cs b/Scripts/Items/Minor Artifacts/ShieldOfInvulnerability.cs new file mode 100644 index 0000000..7fa2171 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ShieldOfInvulnerability.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShieldOfInvulnerability : OrderShield + { + public override int LabelNumber{ get{ return 1070693; } } + + public override int BasePhysicalResistance{ get{ return 8; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ShieldOfInvulnerability() + { + Hue = 0x4F2; + + Attributes.SpellChanneling = 1; + Attributes.ReflectPhysical = 10; + Attributes.DefendChance = 15; + ArmorAttributes.LowerStatReq = 100; + } + + public override bool Validate( Mobile m ) + { + return true; + } + + public ShieldOfInvulnerability( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/ShipModelOfTheHMSCape.cs b/Scripts/Items/Minor Artifacts/ShipModelOfTheHMSCape.cs new file mode 100644 index 0000000..9835f6c --- /dev/null +++ b/Scripts/Items/Minor Artifacts/ShipModelOfTheHMSCape.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShipModelOfTheHMSCape : Item + { + public override int LabelNumber{ get{ return 1063476; } } + + [Constructable] + public ShipModelOfTheHMSCape() : base( 0x14F3 ) + { + Hue = 0x37B; + } + + public ShipModelOfTheHMSCape( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/StaffOfPower.cs b/Scripts/Items/Minor Artifacts/StaffOfPower.cs new file mode 100644 index 0000000..6ad51d5 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/StaffOfPower.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StaffOfPower : BlackStaff + { + public override int LabelNumber{ get{ return 1070692; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public StaffOfPower() + { + Hue = 0x4F2; + WeaponAttributes.MageWeapon = 15; + Attributes.SpellChanneling = 1; + Attributes.SpellDamage = 5; + Attributes.CastRecovery = 2; + Attributes.LowerManaCost = 5; + } + + public StaffOfPower( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/VioletCourage.cs b/Scripts/Items/Minor Artifacts/VioletCourage.cs new file mode 100644 index 0000000..b56b3b8 --- /dev/null +++ b/Scripts/Items/Minor Artifacts/VioletCourage.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class VioletCourage : FemalePlateChest + { + public override int LabelNumber{ get{ return 1063471; } } + + public override int BasePhysicalResistance{ get{ return 14; } } + public override int BaseFireResistance{ get{ return 12; } } + public override int BaseColdResistance{ get{ return 12; } } + public override int BasePoisonResistance{ get{ return 8; } } + public override int BaseEnergyResistance{ get{ return 9; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public VioletCourage() + { + Hue = 0x486; + Attributes.Luck = 95; + Attributes.DefendChance = 15; + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + } + + public VioletCourage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Minor Artifacts/WrathOfTheDryad.cs b/Scripts/Items/Minor Artifacts/WrathOfTheDryad.cs new file mode 100644 index 0000000..4a7479d --- /dev/null +++ b/Scripts/Items/Minor Artifacts/WrathOfTheDryad.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WrathOfTheDryad : GnarledStaff + { + public override int LabelNumber{ get{ return 1070853; } } // Wrath of the Dryad + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public WrathOfTheDryad() + { + Hue = 0x29C; + WeaponAttributes.HitLeechMana = 50; + WeaponAttributes.HitLightning = 33; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 40; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + pois = 100; + + cold = fire = phys = nrgy = chaos = direct = 0; + } + + public WrathOfTheDryad( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/AcidSlime.cs b/Scripts/Items/Misc/AcidSlime.cs new file mode 100644 index 0000000..9b97f97 --- /dev/null +++ b/Scripts/Items/Misc/AcidSlime.cs @@ -0,0 +1,102 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Items +{ + public class AcidSlime : Item + { + private TimeSpan m_Duration; + private int m_MinDamage; + private int m_MaxDamage; + private DateTime m_Created; + private bool m_Drying; + private Timer m_Timer; + + [Constructable] + public AcidSlime() : this( TimeSpan.FromSeconds( 10.0 ), 5, 10 ) + { + } + + public override string DefaultName { get { return "slime"; } } + + [Constructable] + public AcidSlime( TimeSpan duration, int minDamage, int maxDamage ) + : base( 0x122A ) + { + Hue = 0x3F; + Movable = false; + m_MinDamage = minDamage; + m_MaxDamage = maxDamage; + m_Created = DateTime.Now; + m_Duration = duration; + m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1 ), new TimerCallback( OnTick ) ); + } + + public override void OnAfterDelete() + { + if( m_Timer != null ) + m_Timer.Stop(); + } + + private void OnTick() + { + DateTime now = DateTime.Now; + TimeSpan age = now - m_Created; + + if( age > m_Duration ) { + Delete(); + } else { + if( !m_Drying && age > (m_Duration - age) ) + { + m_Drying = true; + ItemID = 0x122B; + } + + List toDamage = new List(); + + foreach( Mobile m in GetMobilesInRange( 0 ) ) + { + BaseCreature bc = m as BaseCreature; + if( m.Alive && !m.IsDeadBondedPet && (bc == null || bc.Controlled || bc.Summoned) ) + { + toDamage.Add( m ); + } + } + + for ( int i = 0; i < toDamage.Count; i++ ) + Damage( toDamage[i] ); + } + } + + public override bool OnMoveOver( Mobile m ) + { + Damage( m ); + return true; + } + + public void Damage ( Mobile m ) + { + int damage = Utility.RandomMinMax( m_MinDamage, m_MaxDamage ); + if ( Core.AOS ) + AOS.Damage( m, damage, 0, 0, 0, 100, 0 ); + else + m.Damage( damage ); + } + + public AcidSlime( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + } + + public override void Deserialize( GenericReader reader ) + { + } + } +} diff --git a/Scripts/Items/Misc/ArcaneGem.cs b/Scripts/Items/Misc/ArcaneGem.cs new file mode 100644 index 0000000..272da35 --- /dev/null +++ b/Scripts/Items/Misc/ArcaneGem.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Targeting; + +namespace Server.Items +{ + public class ArcaneGem : Item + { + public override string DefaultName + { + get { return "arcane gem"; } + } + + [Constructable] + public ArcaneGem() : base( 0x1EA7 ) + { + Stackable = Core.ML; + Weight = 1.0; + } + + public ArcaneGem( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + from.BeginTarget( 2, false, TargetFlags.None, new TargetCallback( OnTarget ) ); + from.SendMessage( "What do you wish to use the gem on?" ); + } + } + + public int GetChargesFor( Mobile m ) + { + int v = (int)(m.Skills[SkillName.Tailoring].Value / 5); + + if ( v < 16 ) + return 16; + else if ( v > 24 ) + return 24; + + return v; + } + + public const int DefaultArcaneHue = 2117; + + public void OnTarget( Mobile from, object obj ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + + if ( obj is IArcaneEquip && obj is Item ) + { + Item item = (Item)obj; + CraftResource resource = CraftResource.None; + + if( item is BaseClothing ) + resource = ((BaseClothing)item).Resource; + else if( item is BaseArmor ) + resource = ((BaseArmor)item).Resource; + else if( item is BaseWeapon ) // Sanity, weapons cannot recieve gems... + resource = ((BaseWeapon)item).Resource; + + IArcaneEquip eq = (IArcaneEquip)obj; + + if ( !item.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + else if ( item.LootType == LootType.Blessed ) + { + from.SendMessage( "You can only use this on exceptionally crafted robes, thigh boots, cloaks, or leather gloves." ); + return; + } + else if ( resource != CraftResource.None && resource != CraftResource.RegularLeather ) + { + from.SendLocalizedMessage( 1049690 ); // Arcane gems can not be used on that type of leather. + return; + } + + int charges = GetChargesFor( from ); + + if ( eq.IsArcane ) + { + if ( eq.CurArcaneCharges >= eq.MaxArcaneCharges ) + { + from.SendMessage( "That item is already fully charged." ); + } + else + { + if ( eq.CurArcaneCharges <= 0 ) + item.Hue = DefaultArcaneHue; + + if ( (eq.CurArcaneCharges + charges) > eq.MaxArcaneCharges ) + eq.CurArcaneCharges = eq.MaxArcaneCharges; + else + eq.CurArcaneCharges += charges; + + from.SendMessage( "You recharge the item." ); + if ( Amount <= 1 ) + Delete(); + else Amount--; + } + } + else if ( from.Skills[SkillName.Tailoring].Value >= 80.0 ) + { + bool isExceptional = false; + + if ( item is BaseClothing ) + isExceptional = ( ((BaseClothing)item).Quality == ClothingQuality.Exceptional ); + else if ( item is BaseArmor ) + isExceptional = ( ((BaseArmor)item).Quality == ArmorQuality.Exceptional ); + else if ( item is BaseWeapon ) + isExceptional = ( ((BaseWeapon)item).Quality == WeaponQuality.Exceptional ); + + if ( isExceptional ) + { + if ( item is BaseClothing ) + { + ((BaseClothing)item).Quality = ClothingQuality.Regular; + ((BaseClothing)item).Crafter = from; + } + else if ( item is BaseArmor ) + { + ((BaseArmor)item).Quality = ArmorQuality.Regular; + ((BaseArmor)item).Crafter = from; + ((BaseArmor)item).PhysicalBonus = ((BaseArmor)item).FireBonus = ((BaseArmor)item).ColdBonus = ((BaseArmor)item).PoisonBonus = ((BaseArmor)item).EnergyBonus = 0; // Is there a method to remove bonuses? + } + else if ( item is BaseWeapon ) // Sanity, weapons cannot recieve gems... + { + ((BaseWeapon)item).Quality = WeaponQuality.Regular; + ((BaseWeapon)item).Crafter = from; + } + + eq.CurArcaneCharges = eq.MaxArcaneCharges = charges; + + item.Hue = DefaultArcaneHue; + + from.SendMessage( "You enhance the item with your gem." ); + if ( Amount <= 1 ) + Delete(); + else Amount--; + } + else + { + from.SendMessage( "Only exceptional items can be enhanced with the gem." ); + } + } + else + { + from.SendMessage( "You do not have enough skill in tailoring to enhance the item." ); + } + } + else + { + from.SendMessage( "You can only use this on exceptionally crafted robes, thigh boots, cloaks, or leather gloves." ); + } + } + + public static bool ConsumeCharges( Mobile from, int amount ) + { + List items = from.Items; + int avail = 0; + + for ( int i = 0; i < items.Count; ++i ) + { + Item obj = items[i]; + + if ( obj is IArcaneEquip ) + { + IArcaneEquip eq = (IArcaneEquip)obj; + + if ( eq.IsArcane ) + avail += eq.CurArcaneCharges; + } + } + + if ( avail < amount ) + return false; + + for ( int i = 0; i < items.Count; ++i ) + { + Item obj = items[i]; + + if ( obj is IArcaneEquip ) + { + IArcaneEquip eq = (IArcaneEquip)obj; + + if ( eq.IsArcane ) + { + if ( eq.CurArcaneCharges > amount ) + { + eq.CurArcaneCharges -= amount; + break; + } + else + { + amount -= eq.CurArcaneCharges; + eq.CurArcaneCharges = 0; + } + } + } + } + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/BankCheck.cs b/Scripts/Items/Misc/BankCheck.cs new file mode 100644 index 0000000..c8b6350 --- /dev/null +++ b/Scripts/Items/Misc/BankCheck.cs @@ -0,0 +1,169 @@ +using System; +using System.Globalization; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Engines.Quests; +using Necro = Server.Engines.Quests.Necro; +using Haven = Server.Engines.Quests.Haven; + +namespace Server.Items +{ + public class BankCheck : Item + { + private int m_Worth; + + [CommandProperty( AccessLevel.GameMaster )] + public int Worth + { + get{ return m_Worth; } + set{ m_Worth = value; InvalidateProperties(); } + } + + public BankCheck( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Worth ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Worth = reader.ReadInt(); + break; + } + } + } + + [Constructable] + public BankCheck( int worth ) : base( 0x14F0 ) + { + Weight = 1.0; + Hue = 0x34; + LootType = LootType.Blessed; + + m_Worth = worth; + } + + public override bool DisplayLootType{ get{ return Core.AOS; } } + + public override int LabelNumber{ get{ return 1041361; } } // A bank check + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + string worth; + + if ( Core.ML ) + worth = m_Worth.ToString( "N0", CultureInfo.GetCultureInfo( "en-US" ) ); + else + worth = m_Worth.ToString(); + + list.Add( 1060738, worth ); // value: ~1_val~ + } + + public override void OnSingleClick( Mobile from ) + { + from.Send( new MessageLocalizedAffix( Serial, ItemID, MessageType.Label, 0x3B2, 3, 1041361, "", AffixType.Append, String.Concat( " ", m_Worth.ToString() ), "" ) ); // A bank check: + } + + public override void OnDoubleClick( Mobile from ) + { + BankBox box = from.FindBankNoCreate(); + + if ( box != null && IsChildOf( box ) ) + { + Delete(); + + int deposited = 0; + + int toAdd = m_Worth; + + Gold gold; + + while ( toAdd > 60000 ) + { + gold = new Gold( 60000 ); + + if ( box.TryDropItem( from, gold, false ) ) + { + toAdd -= 60000; + deposited += 60000; + } + else + { + gold.Delete(); + + from.AddToBackpack( new BankCheck( toAdd ) ); + toAdd = 0; + + break; + } + } + + if ( toAdd > 0 ) + { + gold = new Gold( toAdd ); + + if ( box.TryDropItem( from, gold, false ) ) + { + deposited += toAdd; + } + else + { + gold.Delete(); + + from.AddToBackpack( new BankCheck( toAdd ) ); + } + } + + // Gold was deposited in your account: + from.SendLocalizedMessage( 1042672, true, " " + deposited.ToString() ); + + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is Necro.DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( Necro.CashBankCheckObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + + if ( qs is Haven.UzeraanTurmoilQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( Haven.CashBankCheckObjective ) ); + + if ( obj != null && !obj.Completed ) + obj.Complete(); + } + } + } + else + { + from.SendLocalizedMessage( 1047026 ); // That must be in your bank box to use it. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Bedlam/GlobOfMonstreousInterredGrizzle.cs b/Scripts/Items/Misc/Bedlam/GlobOfMonstreousInterredGrizzle.cs new file mode 100644 index 0000000..90ac822 --- /dev/null +++ b/Scripts/Items/Misc/Bedlam/GlobOfMonstreousInterredGrizzle.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GlobOfMonstreousInterredGrizzle : Item + { + public override int LabelNumber{ get{ return 1072117; } } // Glob of Monsterous Interred Grizzle + + [Constructable] + public GlobOfMonstreousInterredGrizzle() : base( 0x2F3 ) + { + } + + public GlobOfMonstreousInterredGrizzle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Bedlam/GrizzledSkullCollection.cs b/Scripts/Items/Misc/Bedlam/GrizzledSkullCollection.cs new file mode 100644 index 0000000..139ecb4 --- /dev/null +++ b/Scripts/Items/Misc/Bedlam/GrizzledSkullCollection.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GrizzledSkullCollection : Item + { + public override int LabelNumber{ get{ return 1072116; } } // Grizzled Skull collection + + [Constructable] + public GrizzledSkullCollection() : base( 0x21FC ) + { + } + + public GrizzledSkullCollection( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Bedlam/MonsterousInterredGrizzleMaggots.cs b/Scripts/Items/Misc/Bedlam/MonsterousInterredGrizzleMaggots.cs new file mode 100644 index 0000000..34e3db0 --- /dev/null +++ b/Scripts/Items/Misc/Bedlam/MonsterousInterredGrizzleMaggots.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MonsterousInterredGrizzleMaggots : Item + { + public override int LabelNumber{ get{ return 1075090; } } // Monsterous Interred Grizzle Maggots + + [Constructable] + public MonsterousInterredGrizzleMaggots() : base( 0x2633 ) + { + } + + public MonsterousInterredGrizzleMaggots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Bedlam/ResolvesBridle.cs b/Scripts/Items/Misc/Bedlam/ResolvesBridle.cs new file mode 100644 index 0000000..bb0b4be --- /dev/null +++ b/Scripts/Items/Misc/Bedlam/ResolvesBridle.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ResolvesBridle : Item + { + public override int LabelNumber{ get{ return 1074761; } } // Resolve's Bridle + + [Constructable] + public ResolvesBridle() : base( 0x1374 ) + { + } + + public ResolvesBridle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Bedlam/TombstoneOfTheDamned.cs b/Scripts/Items/Misc/Bedlam/TombstoneOfTheDamned.cs new file mode 100644 index 0000000..917f4d4 --- /dev/null +++ b/Scripts/Items/Misc/Bedlam/TombstoneOfTheDamned.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TombstoneOfTheDamned : Item + { + public override int LabelNumber{ get{ return 1072123; } } // Tombstone of the Damned + + [Constructable] + public TombstoneOfTheDamned() : base( Utility.RandomMinMax( 0xED7, 0xEDE ) ) + { + } + + public TombstoneOfTheDamned( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Beeswax.cs b/Scripts/Items/Misc/Beeswax.cs new file mode 100644 index 0000000..bd1546f --- /dev/null +++ b/Scripts/Items/Misc/Beeswax.cs @@ -0,0 +1,40 @@ +using System; + +namespace Server.Items +{ + public class Beeswax : Item + { + [Constructable] + public Beeswax() : this( 1 ) + { + } + + [Constructable] + public Beeswax( int amount ) : base( 0x1422 ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + } + + public Beeswax( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Blighted Grove/AbscessTail.cs b/Scripts/Items/Misc/Blighted Grove/AbscessTail.cs new file mode 100644 index 0000000..ddd8b15 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/AbscessTail.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AbscessTail : Item + { + public override int LabelNumber{ get{ return 1074231; } } // Abscess' Tail + + [Constructable] + public AbscessTail() : base( 0x1A9D ) + { + LootType = LootType.Blessed; + Hue = 0x51D; // TODO check + } + + public AbscessTail( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/CoilsFang.cs b/Scripts/Items/Misc/Blighted Grove/CoilsFang.cs new file mode 100644 index 0000000..379d4fb --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/CoilsFang.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CoilsFang : Item + { + public override int LabelNumber{ get{ return 1074229; } } // Coil's Fang + + [Constructable] + public CoilsFang() : base( 0x10E8 ) + { + LootType = LootType.Blessed; + Hue = 0x487; + } + + public CoilsFang( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/EternallyCorruptTree.cs b/Scripts/Items/Misc/Blighted Grove/EternallyCorruptTree.cs new file mode 100644 index 0000000..2dc5b58 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/EternallyCorruptTree.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class EternallyCorruptTree : Item + { + public override int LabelNumber{ get{ return 1072093; } } // Eternally Corrupt Tree + + [Constructable] + public EternallyCorruptTree() : base( 0x20FA ) + { + Hue = Utility.RandomMinMax( 0x899, 0x8B0 ); + } + + public EternallyCorruptTree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/HydraScale.cs b/Scripts/Items/Misc/Blighted Grove/HydraScale.cs new file mode 100644 index 0000000..187065d --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/HydraScale.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HydraScale : Item + { + public override int LabelNumber{ get{ return 1074760; } } // A hydra scale. + + [Constructable] + public HydraScale() : base( 0x26B4 ) + { + LootType = LootType.Blessed; + Hue = 0xC2; // TODO check + } + + public HydraScale( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/MelisandesFermentedWine.cs b/Scripts/Items/Misc/Blighted Grove/MelisandesFermentedWine.cs new file mode 100644 index 0000000..3d578de --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/MelisandesFermentedWine.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MelisandesFermentedWine : GreaterExplosionPotion + { + public override int LabelNumber{ get{ return 1072114; } } // Melisande's Fermented Wine + + [Constructable] + public MelisandesFermentedWine() + { + Stackable = false; + ItemID = 0x99B; + Hue = Utility.RandomList( 0xB, 0xF, 0x48D ); // TODO update + } + + public MelisandesFermentedWine( Serial serial ) : base( serial ) + { + } + + public override void Drink( Mobile from ) + { + if ( MondainsLegacy.CheckML( from ) ) + base.Drink( from ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1074502 ); // It looks explosive. + list.Add( 1075085 ); // Requirement: Mondain's Legacy + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + + diff --git a/Scripts/Items/Misc/Blighted Grove/MelisandesHairDye.cs b/Scripts/Items/Misc/Blighted Grove/MelisandesHairDye.cs new file mode 100644 index 0000000..8422023 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/MelisandesHairDye.cs @@ -0,0 +1,90 @@ +using System; +using Server; +using Server.Gumps; + +namespace Server.Items +{ + public class MelisandesHairDye : Item + { + public override int LabelNumber{ get{ return 1041088; } } // Hair Dye + + [Constructable] + public MelisandesHairDye() : base( 0xEFF ) + { + Hue = Utility.RandomMinMax( 0x47E, 0x499 ); + } + + public MelisandesHairDye( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + if ( MondainsLegacy.CheckML( from ) ) + from.SendGump( new ConfirmGump( this ) ); + } + else + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1075085 ); // Requirement: Mondain's Legacy + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private class ConfirmGump : BaseConfirmGump + { + public override int TitleNumber{ get{ return 1074395; } } //
Use Permanent Hair Dye
+ public override int LabelNumber{ get{ return 1074396; } } // This special hair dye is made of a unique mixture of leaves, permanently changing one's hair color until another dye is used. + + private Item m_Item; + + public ConfirmGump( Item item ) : base() + { + m_Item = item; + } + + public override void Confirm( Mobile from ) + { + if ( m_Item != null && !m_Item.Deleted && m_Item.IsChildOf( from.Backpack ) ) + { + if ( from.HairItemID != 0 ) + { + from.HairHue = m_Item.Hue; + from.PlaySound( 0x240 ); + from.SendLocalizedMessage( 502622 ); // You dye your hair. + m_Item.Delete(); + } + else + from.SendLocalizedMessage( 502623 ); // You have no hair to dye and you cannot use this. + } + else + from.SendLocalizedMessage( 1073461 ); // You don't have enough dye. + } + + public override void Refuse( Mobile from ) + { + from.SendLocalizedMessage( 502620 ); // You decide not to dye your hair. + } + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/SalivasFeather.cs b/Scripts/Items/Misc/Blighted Grove/SalivasFeather.cs new file mode 100644 index 0000000..653f9a0 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/SalivasFeather.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SalivasFeather : Item + { + public override int LabelNumber{ get{ return 1074234; } } // Saliva's Feather + + [Constructable] + public SalivasFeather() : base( 0x1020 ) + { + LootType = LootType.Blessed; + Hue = 0x5C; + } + + public SalivasFeather( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/SamplesOfCorruptedWater.cs b/Scripts/Items/Misc/Blighted Grove/SamplesOfCorruptedWater.cs new file mode 100644 index 0000000..5393a85 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/SamplesOfCorruptedWater.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SamplesOfCorruptedWater : Item + { + public override int LabelNumber{ get{ return 1074999; } } // samples of corrupted water + + [Constructable] + public SamplesOfCorruptedWater() : base( 0xEFE ) + { + LootType = LootType.Blessed; + } + + public SamplesOfCorruptedWater( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/TaintedSeeds.cs b/Scripts/Items/Misc/Blighted Grove/TaintedSeeds.cs new file mode 100644 index 0000000..3fde780 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/TaintedSeeds.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TaintedSeeds : Item + { + public override int LabelNumber{ get{ return 1074233; } } // Tainted Seeds + + [Constructable] + public TaintedSeeds() : base( 0xDFA ) + { + LootType = LootType.Blessed; + Hue = 0x48; // TODO check + } + + public TaintedSeeds( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/ThorvaldsMedallion.cs b/Scripts/Items/Misc/Blighted Grove/ThorvaldsMedallion.cs new file mode 100644 index 0000000..59e3772 --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/ThorvaldsMedallion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ThorvaldsMedallion : Item + { + public override int LabelNumber{ get{ return 1074232; } } // Thorvald's Medallion + + [Constructable] + public ThorvaldsMedallion() : base( 0x2AAA ) + { + LootType = LootType.Blessed; + Hue = 0x47F; // TODO check + } + + public ThorvaldsMedallion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blighted Grove/ThrashersTail.cs b/Scripts/Items/Misc/Blighted Grove/ThrashersTail.cs new file mode 100644 index 0000000..6ff534d --- /dev/null +++ b/Scripts/Items/Misc/Blighted Grove/ThrashersTail.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ThrashersTail : Item + { + public override int LabelNumber{ get{ return 1074230; } } // Thrasher's Tail + + [Constructable] + public ThrashersTail() : base( 0x1A9D ) + { + LootType = LootType.Blessed; + Hue = 0x455; + } + + public ThrashersTail( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Blocker.cs b/Scripts/Items/Misc/Blocker.cs new file mode 100644 index 0000000..d9b470e --- /dev/null +++ b/Scripts/Items/Misc/Blocker.cs @@ -0,0 +1,106 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class Blocker : Item + { + public override int LabelNumber{ get{ return 503057; } } // Impassable! + + [Constructable] + public Blocker() : base( 0x21A4 ) + { + Movable = false; + } + + public Blocker( Serial serial ) : base( serial ) + { + } + + protected override Packet GetWorldPacketFor( NetState state ) { + Mobile mob = state.Mobile; + + if ( mob != null && mob.AccessLevel >= AccessLevel.GameMaster ) + return new GMItemPacket( this ); + + return base.GetWorldPacketFor( state ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public sealed class GMItemPacket : Packet + { + public GMItemPacket( Item item ) : base( 0x1A ) + { + this.EnsureCapacity( 20 ); + + // 14 base length + // +2 - Amount + // +2 - Hue + // +1 - Flags + + uint serial = (uint)item.Serial.Value; + int itemID = 0x1183; + int amount = item.Amount; + Point3D loc = item.Location; + int x = loc.X; + int y = loc.Y; + int hue = item.Hue; + int flags = item.GetPacketFlags(); + int direction = (int)item.Direction; + + if ( amount != 0 ) + serial |= 0x80000000; + else + serial &= 0x7FFFFFFF; + + m_Stream.Write( (uint) serial ); + m_Stream.Write( (short) (itemID & 0x7FFF) ); + + if ( amount != 0 ) + m_Stream.Write( (short) amount ); + + x &= 0x7FFF; + + if ( direction != 0 ) + x |= 0x8000; + + m_Stream.Write( (short) x ); + + y &= 0x3FFF; + + if ( hue != 0 ) + y |= 0x8000; + + if ( flags != 0 ) + y |= 0x4000; + + m_Stream.Write( (short) y ); + + if ( direction != 0 ) + m_Stream.Write( (byte) direction ); + + m_Stream.Write( (sbyte) loc.Z ); + + if ( hue != 0 ) + m_Stream.Write( (ushort) hue ); + + if ( flags != 0 ) + m_Stream.Write( (byte) flags ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Blood.cs b/Scripts/Items/Misc/Blood.cs new file mode 100644 index 0000000..fd4aaf4 --- /dev/null +++ b/Scripts/Items/Misc/Blood.cs @@ -0,0 +1,57 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Blood : Item + { + [Constructable] + public Blood() : this( Utility.RandomList( 0x1645, 0x122A, 0x122B, 0x122C, 0x122D, 0x122E, 0x122F )) + { + } + + [Constructable] + public Blood( int itemID ) : base( itemID ) + { + Movable = false; + + new InternalTimer( this ).Start(); + } + + public Blood( Serial serial ) : base( serial ) + { + new InternalTimer( this ).Start(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private Item m_Blood; + + public InternalTimer( Item blood ) : base( TimeSpan.FromSeconds( 5.0 ) ) + { + Priority = TimerPriority.OneSecond; + + m_Blood = blood; + } + + protected override void OnTick() + { + m_Blood.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Bola.cs b/Scripts/Items/Misc/Bola.cs new file mode 100644 index 0000000..0015bb8 --- /dev/null +++ b/Scripts/Items/Misc/Bola.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class Bola : Item + { + [Constructable] + public Bola() + : this(1) + { + } + + [Constructable] + public Bola(int amount) + : base(0x26AC) + { + Weight = 4.0; + Stackable = true; + Amount = amount; + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1040019); // The bola must be in your pack to use it. + } + else if (!from.CanBeginAction(typeof(Bola))) + { + from.SendLocalizedMessage(1049624); // You have to wait a few moments before you can use another bola! + } + else if (from.Target is BolaTarget) + { + from.SendLocalizedMessage(1049631); // This bola is already being used. + } + else if (!HasFreeHands(from)) + { + from.SendLocalizedMessage(1040015); // Your hands must be free to use this + } + else if (from.Mounted) + { + from.SendLocalizedMessage(1040016); // You cannot use this while riding a mount + } + else if (Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(from)) + { + from.SendLocalizedMessage(1070902); // You can't use this while in an animal form! + } + else + { + EtherealMount.StopMounting(from); + + from.Target = new BolaTarget(this); + from.LocalOverheadMessage(MessageType.Emote, 0x3B2, 1049632); // * You begin to swing the bola...* + from.NonlocalOverheadMessage(MessageType.Emote, 0x3B2, 1049633, from.Name); // ~1_NAME~ begins to menacingly swing a bola... + } + } + + private static void ReleaseBolaLock(object state) + { + ((Mobile)state).EndAction(typeof(Bola)); + } + + private static void FinishThrow(object state) + { + object[] states = (object[])state; + + Mobile from = (Mobile)states[0]; + Mobile to = (Mobile)states[1]; + + if (Core.AOS) + new Bola().MoveToWorld(to.Location, to.Map); + + if (to is ChaosDragoon || to is ChaosDragoonElite) + from.SendLocalizedMessage(1042047); // You fail to knock the rider from its mount. + + IMount mt = to.Mount; + if (mt != null && !(to is ChaosDragoon || to is ChaosDragoonElite)) + mt.Rider = null; + + if (to is PlayerMobile) + { + if (Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(to)) + { + to.SendLocalizedMessage(1114066, from.Name); // ~1_NAME~ knocked you out of animal form! + } + else if (to.Mounted) + { + to.SendLocalizedMessage(1040023); // You have been knocked off of your mount! + } + + (to as PlayerMobile).SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(Core.ML ? 10 : 3), true); + } + + if (Core.AOS && from is PlayerMobile) /* only failsafe, attacker should already be dismounted */ + { + (from as PlayerMobile).SetMountBlock(BlockMountType.BolaRecovery, TimeSpan.FromSeconds(Core.ML ? 10 : 3), true); + } + + to.Damage(1); + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), new TimerStateCallback(ReleaseBolaLock), from); + } + + private static bool HasFreeHands(Mobile from) + { + Item one = from.FindItemOnLayer(Layer.OneHanded); + Item two = from.FindItemOnLayer(Layer.TwoHanded); + + if (Core.SE) + { + Container pack = from.Backpack; + + if (pack != null) + { + if (one != null && one.Movable) + { + pack.DropItem(one); + one = null; + } + + if (two != null && two.Movable) + { + pack.DropItem(two); + two = null; + } + } + } + else if (Core.AOS) + { + if (one != null && one.Movable) + { + from.AddToBackpack(one); + one = null; + } + + if (two != null && two.Movable) + { + from.AddToBackpack(two); + two = null; + } + } + + return (one == null && two == null); + } + + public class BolaTarget : Target + { + private Bola m_Bola; + + public BolaTarget(Bola bola) + : base(8, false, TargetFlags.Harmful) + { + m_Bola = bola; + } + + protected override void OnTarget(Mobile from, object obj) + { + if (m_Bola.Deleted) + return; + + if (obj is Mobile) + { + Mobile to = (Mobile)obj; + + if (!m_Bola.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1040019); // The bola must be in your pack to use it. + } + else if (!HasFreeHands(from)) + { + from.SendLocalizedMessage(1040015); // Your hands must be free to use this + } + else if (from.Mounted) + { + from.SendLocalizedMessage(1040016); // You cannot use this while riding a mount + } + else if (Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(from)) + { + from.SendLocalizedMessage(1070902); // You can't use this while in an animal form! + } + else if (!to.Mounted && !Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(to)) + { + from.SendLocalizedMessage(1049628); // You have no reason to throw a bola at that. + } + else if (!from.CanBeHarmful(to)) + { + } + else if (from.BeginAction(typeof(Bola))) + { + EtherealMount.StopMounting(from); + + from.DoHarmful(to); + + m_Bola.Consume(); + + from.Direction = from.GetDirectionTo(to); + from.Animate(11, 5, 1, true, false, 0); + from.MovingEffect(to, 0x26AC, 10, 0, false, false); + + Timer.DelayCall(TimeSpan.FromSeconds(0.5), new TimerStateCallback(FinishThrow), new object[] { from, to }); + } + else + { + from.SendLocalizedMessage(1049624); // You have to wait a few moments before you can use another bola! + } + } + else + { + from.SendLocalizedMessage(1049629); // You cannot throw a bola at that. + } + } + } + + public Bola(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/BolaBall.cs b/Scripts/Items/Misc/BolaBall.cs new file mode 100644 index 0000000..bfc1a39 --- /dev/null +++ b/Scripts/Items/Misc/BolaBall.cs @@ -0,0 +1,39 @@ +using System; + +namespace Server.Items +{ + public class BolaBall : Item + { + [Constructable] + public BolaBall() : this( 1 ) + { + } + + [Constructable] + public BolaBall( int amount ) : base( 0xE73 ) + { + Weight = 4.0; + Stackable = true; + Amount = amount; + Hue = 0x8AC; + } + + public BolaBall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/BulletinBoards.cs b/Scripts/Items/Misc/BulletinBoards.cs new file mode 100644 index 0000000..7b44dcf --- /dev/null +++ b/Scripts/Items/Misc/BulletinBoards.cs @@ -0,0 +1,624 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x1E5E, 0x1E5F )] + public class BulletinBoard : BaseBulletinBoard + { + [Constructable] + public BulletinBoard() : base( 0x1E5E ) + { + } + + public BulletinBoard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class BaseBulletinBoard : Item + { + private string m_BoardName; + + [CommandProperty( AccessLevel.GameMaster )] + public string BoardName + { + get{ return m_BoardName; } + set{ m_BoardName = value; } + } + + public BaseBulletinBoard( int itemID ) : base( itemID ) + { + m_BoardName = "bulletin board"; + Movable = false; + } + + // Threads will be removed six hours after the last post was made + private static TimeSpan ThreadDeletionTime = TimeSpan.FromHours( 6.0 ); + + // A player may only create a thread once every two minutes + private static TimeSpan ThreadCreateTime = TimeSpan.FromMinutes( 2.0 ); + + // A player may only reply once every thirty seconds + private static TimeSpan ThreadReplyTime = TimeSpan.FromSeconds( 30.0 ); + + public static bool CheckTime( DateTime time, TimeSpan range ) + { + return (time + range) < DateTime.Now; + } + + public static string FormatTS( TimeSpan ts ) + { + int totalSeconds = (int)ts.TotalSeconds; + int seconds = totalSeconds % 60; + int minutes = totalSeconds / 60; + + if ( minutes != 0 && seconds != 0 ) + return String.Format( "{0} minute{1} and {2} second{3}", minutes, minutes==1?"":"s", seconds, seconds==1?"":"s" ); + else if ( minutes != 0 ) + return String.Format( "{0} minute{1}", minutes, minutes==1?"":"s" ); + else + return String.Format( "{0} second{1}", seconds, seconds==1?"":"s" ); + } + + public virtual void Cleanup() + { + List items = this.Items; + + for ( int i = items.Count - 1; i >= 0; --i ) + { + if ( i >= items.Count ) + continue; + + BulletinMessage msg = items[i] as BulletinMessage; + + if ( msg == null ) + continue; + + if ( msg.Thread == null && CheckTime( msg.LastPostTime, ThreadDeletionTime ) ) + { + msg.Delete(); + RecurseDelete( msg ); // A root-level thread has expired + } + } + } + + private void RecurseDelete( BulletinMessage msg ) + { + List found = new List(); + List items = this.Items; + + for ( int i = items.Count - 1; i >= 0; --i ) + { + if ( i >= items.Count ) + continue; + + BulletinMessage check = items[i] as BulletinMessage; + + if ( check == null ) + continue; + + if ( check.Thread == msg ) + { + check.Delete(); + found.Add( check ); + } + } + + for ( int i = 0; i < found.Count; ++i ) + RecurseDelete( (BulletinMessage)found[i] ); + } + + public virtual bool GetLastPostTime( Mobile poster, bool onlyCheckRoot, ref DateTime lastPostTime ) + { + List items = this.Items; + bool wasSet = false; + + for ( int i = 0; i < items.Count; ++i ) + { + BulletinMessage msg = items[i] as BulletinMessage; + + if ( msg == null || msg.Poster != poster ) + continue; + + if ( onlyCheckRoot && msg.Thread != null ) + continue; + + if ( msg.Time > lastPostTime ) + { + wasSet = true; + lastPostTime = msg.Time; + } + } + + return wasSet; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( CheckRange( from ) ) + { + Cleanup(); + + NetState state = from.NetState; + + state.Send( new BBDisplayBoard( this ) ); + if ( state.ContainerGridLines ) + state.Send( new ContainerContent6017( from, this ) ); + else + state.Send( new ContainerContent( from, this ) ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + + public virtual bool CheckRange( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + return ( from.Map == this.Map && from.InRange( GetWorldLocation(), 2 ) ); + } + + public void PostMessage( Mobile from, BulletinMessage thread, string subject, string[] lines ) + { + if ( thread != null ) + thread.LastPostTime = DateTime.Now; + + AddItem( new BulletinMessage( from, thread, subject, lines ) ); + } + + public BaseBulletinBoard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (string) m_BoardName ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_BoardName = reader.ReadString(); + break; + } + } + } + + public static void Initialize() + { + PacketHandlers.Register( 0x71, 0, true, new OnPacketReceive( BBClientRequest ) ); + } + + public static void BBClientRequest( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + int packetID = pvSrc.ReadByte(); + BaseBulletinBoard board = World.FindItem( pvSrc.ReadInt32() ) as BaseBulletinBoard; + + if ( board == null || !board.CheckRange( from ) ) + return; + + switch ( packetID ) + { + case 3: BBRequestContent( from, board, pvSrc ); break; + case 4: BBRequestHeader( from, board, pvSrc ); break; + case 5: BBPostMessage( from, board, pvSrc ); break; + case 6: BBRemoveMessage( from, board, pvSrc ); break; + } + } + + public static void BBRequestContent( Mobile from, BaseBulletinBoard board, PacketReader pvSrc ) + { + BulletinMessage msg = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage; + + if ( msg == null || msg.Parent != board ) + return; + + from.Send( new BBMessageContent( board, msg ) ); + } + + public static void BBRequestHeader( Mobile from, BaseBulletinBoard board, PacketReader pvSrc ) + { + BulletinMessage msg = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage; + + if ( msg == null || msg.Parent != board ) + return; + + from.Send( new BBMessageHeader( board, msg ) ); + } + + public static void BBPostMessage( Mobile from, BaseBulletinBoard board, PacketReader pvSrc ) + { + BulletinMessage thread = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage; + + if ( thread != null && thread.Parent != board ) + thread = null; + + int breakout = 0; + + while ( thread != null && thread.Thread != null && breakout++ < 10 ) + thread = thread.Thread; + + DateTime lastPostTime = DateTime.MinValue; + + if ( board.GetLastPostTime( from, ( thread == null ), ref lastPostTime ) ) + { + if ( !CheckTime( lastPostTime, (thread == null ? ThreadCreateTime : ThreadReplyTime) ) ) + { + if ( thread == null ) + from.SendMessage( "You must wait {0} before creating a new thread.", FormatTS( ThreadCreateTime ) ); + else + from.SendMessage( "You must wait {0} before replying to another thread.", FormatTS( ThreadReplyTime ) ); + + return; + } + } + + string subject = pvSrc.ReadUTF8StringSafe( pvSrc.ReadByte() ); + + if ( subject.Length == 0 ) + return; + + string[] lines = new string[pvSrc.ReadByte()]; + + if ( lines.Length == 0 ) + return; + + for ( int i = 0; i < lines.Length; ++i ) + lines[i] = pvSrc.ReadUTF8StringSafe( pvSrc.ReadByte() ); + + board.PostMessage( from, thread, subject, lines ); + } + + public static void BBRemoveMessage( Mobile from, BaseBulletinBoard board, PacketReader pvSrc ) + { + BulletinMessage msg = World.FindItem( pvSrc.ReadInt32() ) as BulletinMessage; + + if ( msg == null || msg.Parent != board ) + return; + + if ( from.AccessLevel < AccessLevel.GameMaster && msg.Poster != from ) + return; + + msg.Delete(); + } + } + + public struct BulletinEquip + { + public int itemID; + public int hue; + + public BulletinEquip( int itemID, int hue ) + { + this.itemID = itemID; + this.hue = hue; + } + } + + public class BulletinMessage : Item + { + private Mobile m_Poster; + private string m_Subject; + private DateTime m_Time, m_LastPostTime; + private BulletinMessage m_Thread; + private string m_PostedName; + private int m_PostedBody; + private int m_PostedHue; + private BulletinEquip[] m_PostedEquip; + private string[] m_Lines; + + public string GetTimeAsString() + { + return m_Time.ToString( "MMM dd, yyyy" ); + } + + public override bool CheckTarget( Mobile from, Server.Targeting.Target targ, object targeted ) + { + return false; + } + + public override bool IsAccessibleTo( Mobile check ) + { + return false; + } + + public BulletinMessage( Mobile poster, BulletinMessage thread, string subject, string[] lines ) : base( 0xEB0 ) + { + Movable = false; + + m_Poster = poster; + m_Subject = subject; + m_Time = DateTime.Now; + m_LastPostTime = m_Time; + m_Thread = thread; + m_PostedName = m_Poster.Name; + m_PostedBody = m_Poster.Body; + m_PostedHue = m_Poster.Hue; + m_Lines = lines; + + List list = new List(); + + for ( int i = 0; i < poster.Items.Count; ++i ) + { + Item item = poster.Items[i]; + + if ( item.Layer >= Layer.OneHanded && item.Layer <= Layer.Mount ) + list.Add( new BulletinEquip( item.ItemID, item.Hue ) ); + } + + m_PostedEquip = list.ToArray(); + } + + public Mobile Poster{ get{ return m_Poster; } } + public BulletinMessage Thread{ get{ return m_Thread; } } + public string Subject{ get{ return m_Subject; } } + public DateTime Time{ get{ return m_Time; } } + public DateTime LastPostTime{ get{ return m_LastPostTime; } set{ m_LastPostTime = value; } } + public string PostedName{ get{ return m_PostedName; } } + public int PostedBody{ get{ return m_PostedBody; } } + public int PostedHue{ get{ return m_PostedHue; } } + public BulletinEquip[] PostedEquip{ get{ return m_PostedEquip; } } + public string[] Lines{ get{ return m_Lines; } } + + public BulletinMessage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (Mobile) m_Poster ); + writer.Write( (string) m_Subject ); + writer.Write( (DateTime) m_Time ); + writer.Write( (DateTime) m_LastPostTime ); + writer.Write( (bool) (m_Thread != null) ); + writer.Write( (Item) m_Thread ); + writer.Write( (string) m_PostedName ); + writer.Write( (int) m_PostedBody ); + writer.Write( (int) m_PostedHue ); + + writer.Write( (int) m_PostedEquip.Length ); + + for ( int i = 0; i < m_PostedEquip.Length; ++i ) + { + writer.Write( (int) m_PostedEquip[i].itemID ); + writer.Write( (int) m_PostedEquip[i].hue ); + } + + writer.Write( (int) m_Lines.Length ); + + for ( int i = 0; i < m_Lines.Length; ++i ) + writer.Write( (string) m_Lines[i] ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Poster = reader.ReadMobile(); + m_Subject = reader.ReadString(); + m_Time = reader.ReadDateTime(); + m_LastPostTime = reader.ReadDateTime(); + bool hasThread = reader.ReadBool(); + m_Thread = reader.ReadItem() as BulletinMessage; + m_PostedName = reader.ReadString(); + m_PostedBody = reader.ReadInt(); + m_PostedHue = reader.ReadInt(); + + m_PostedEquip = new BulletinEquip[reader.ReadInt()]; + + for ( int i = 0; i < m_PostedEquip.Length; ++i ) + { + m_PostedEquip[i].itemID = reader.ReadInt(); + m_PostedEquip[i].hue = reader.ReadInt(); + } + + m_Lines = new string[reader.ReadInt()]; + + for ( int i = 0; i < m_Lines.Length; ++i ) + m_Lines[i] = reader.ReadString(); + + if ( hasThread && m_Thread == null ) + Delete(); + + if (version == 0) + ValidationQueue.Add(this); + + break; + } + } + } + public void Validate() + { + if (!(Parent is BulletinBoard && ((BulletinBoard)Parent).Items.Contains(this))) + Delete(); + } + } + + public class BBDisplayBoard : Packet + { + public BBDisplayBoard( BaseBulletinBoard board ) : base( 0x71 ) + { + string name = board.BoardName; + + if ( name == null ) + name = ""; + + EnsureCapacity( 38 ); + + byte[] buffer = Utility.UTF8.GetBytes( name ); + + m_Stream.Write( (byte) 0x00 ); // PacketID + m_Stream.Write( (int) board.Serial ); // Bulletin board serial + + // Bulletin board name + if ( buffer.Length >= 29 ) + { + m_Stream.Write( buffer, 0, 29 ); + m_Stream.Write( (byte) 0 ); + } + else + { + m_Stream.Write( buffer, 0, buffer.Length ); + m_Stream.Fill( 30 - buffer.Length ); + } + } + } + + public class BBMessageHeader : Packet + { + public BBMessageHeader( BaseBulletinBoard board, BulletinMessage msg ) : base( 0x71 ) + { + string poster = SafeString( msg.PostedName ); + string subject = SafeString( msg.Subject ); + string time = SafeString( msg.GetTimeAsString() ); + + EnsureCapacity( 22 + poster.Length + subject.Length + time.Length ); + + m_Stream.Write( (byte) 0x01 ); // PacketID + m_Stream.Write( (int) board.Serial ); // Bulletin board serial + m_Stream.Write( (int) msg.Serial ); // Message serial + + BulletinMessage thread = msg.Thread; + + if ( thread == null ) + m_Stream.Write( (int) 0 ); // Thread serial--root + else + m_Stream.Write( (int) thread.Serial ); // Thread serial--parent + + WriteString( poster ); + WriteString( subject ); + WriteString( time ); + } + + public void WriteString( string v ) + { + byte[] buffer = Utility.UTF8.GetBytes( v ); + int len = buffer.Length + 1; + + if ( len > 255 ) + len = 255; + + m_Stream.Write( (byte) len ); + m_Stream.Write( buffer, 0, len-1 ); + m_Stream.Write( (byte) 0 ); + } + + public string SafeString( string v ) + { + if ( v == null ) + return String.Empty; + + return v; + } + } + + public class BBMessageContent : Packet + { + public BBMessageContent( BaseBulletinBoard board, BulletinMessage msg ) : base( 0x71 ) + { + string poster = SafeString( msg.PostedName ); + string subject = SafeString( msg.Subject ); + string time = SafeString( msg.GetTimeAsString() ); + + EnsureCapacity( 22 + poster.Length + subject.Length + time.Length ); + + m_Stream.Write( (byte) 0x02 ); // PacketID + m_Stream.Write( (int) board.Serial ); // Bulletin board serial + m_Stream.Write( (int) msg.Serial ); // Message serial + + WriteString( poster ); + WriteString( subject ); + WriteString( time ); + + m_Stream.Write( (short) msg.PostedBody ); + m_Stream.Write( (short) msg.PostedHue ); + + int len = msg.PostedEquip.Length; + + if ( len > 255 ) + len = 255; + + m_Stream.Write((byte)len); + + for (int i = 0; i < len; ++i) + WriteString(msg.Lines[i], true); + } + + public void WriteString(string v) + { + WriteString(v, false); + } + + public void WriteString(string v, bool padding) + { + byte[] buffer = Utility.UTF8.GetBytes(v); + int tail = padding ? 2 : 1; + int len = buffer.Length + tail; + + if (len > 255) + len = 255; + + m_Stream.Write((byte)len); + m_Stream.Write(buffer, 0, len - tail); + + if (padding) + m_Stream.Write((short)0); // padding compensates for a client bug + else + m_Stream.Write((byte)0); + } + + public string SafeString( string v ) + { + if ( v == null ) + return String.Empty; + + return v; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/ClockworkAssembly.cs b/Scripts/Items/Misc/ClockworkAssembly.cs new file mode 100644 index 0000000..58c2975 --- /dev/null +++ b/Scripts/Items/Misc/ClockworkAssembly.cs @@ -0,0 +1,134 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Items +{ + public class ClockworkAssembly : Item + { + public override string DefaultName + { + get { return "clockwork assembly"; } + } + + [Constructable] + public ClockworkAssembly() : base( 0x1EA8 ) + { + Weight = 5.0; + Hue = 1102; + } + + public ClockworkAssembly( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + + double tinkerSkill = from.Skills[SkillName.Tinkering].Value; + + if ( tinkerSkill < 60.0 ) + { + from.SendMessage( "You must have at least 60.0 skill in tinkering to construct a golem." ); + return; + } + else if ( (from.Followers + 4) > from.FollowersMax ) + { + from.SendLocalizedMessage( 1049607 ); // You have too many followers to control that creature. + return; + } + + double scalar; + + if ( tinkerSkill >= 100.0 ) + scalar = 1.0; + else if ( tinkerSkill >= 90.0 ) + scalar = 0.9; + else if ( tinkerSkill >= 80.0 ) + scalar = 0.8; + else if ( tinkerSkill >= 70.0 ) + scalar = 0.7; + else + scalar = 0.6; + + Container pack = from.Backpack; + + if ( pack == null ) + return; + + int res = pack.ConsumeTotal( + new Type[] + { + typeof( PowerCrystal ), + typeof( IronIngot ), + typeof( BronzeIngot ), + typeof( Gears ) + }, + new int[] + { + 1, + 50, + 50, + 5 + } ); + + switch ( res ) + { + case 0: + { + from.SendMessage( "You must have a power crystal to construct the golem." ); + break; + } + case 1: + { + from.SendMessage( "You must have 50 iron ingots to construct the golem." ); + break; + } + case 2: + { + from.SendMessage( "You must have 50 bronze ingots to construct the golem." ); + break; + } + case 3: + { + from.SendMessage( "You must have 5 gears to construct the golem." ); + break; + } + default: + { + Golem g = new Golem( true, scalar ); + + if ( g.SetControlMaster( from ) ) + { + Delete(); + + g.MoveToWorld( from.Location, from.Map ); + from.PlaySound( 0x241 ); + } + + break; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/CommunicationCrystals.cs b/Scripts/Items/Misc/CommunicationCrystals.cs new file mode 100644 index 0000000..a990ee9 --- /dev/null +++ b/Scripts/Items/Misc/CommunicationCrystals.cs @@ -0,0 +1,484 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Targeting; +using System.Collections.Generic; + +namespace Server.Items +{ + public class CrystalRechargeInfo + { + public static readonly CrystalRechargeInfo[] Table = new CrystalRechargeInfo[] + { + new CrystalRechargeInfo( typeof( Citrine ), 500 ), + new CrystalRechargeInfo( typeof( Amber ), 500 ), + new CrystalRechargeInfo( typeof( Tourmaline ), 750 ), + new CrystalRechargeInfo( typeof( Emerald ), 1000 ), + new CrystalRechargeInfo( typeof( Sapphire ), 1000 ), + new CrystalRechargeInfo( typeof( Amethyst ), 1000 ), + new CrystalRechargeInfo( typeof( StarSapphire ), 1250 ), + new CrystalRechargeInfo( typeof( Diamond ), 2000 ) + }; + + public static CrystalRechargeInfo Get( Type type ) + { + foreach ( CrystalRechargeInfo info in Table ) + { + if ( info.Type == type ) + return info; + } + + return null; + } + + private Type m_Type; + private int m_Amount; + + public Type Type{ get{ return m_Type; } } + public int Amount{ get{ return m_Amount; } } + + private CrystalRechargeInfo( Type type, int amount ) + { + m_Type = type; + m_Amount = amount; + } + } + + public class BroadcastCrystal : Item + { + public static readonly int MaxCharges = 2000; + + public override int LabelNumber{ get{ return 1060740; } } // communication crystal + + private int m_Charges; + private List m_Receivers; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get{ return this.ItemID == 0x1ECD; } + set + { + this.ItemID = value ? 0x1ECD : 0x1ED0; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set + { + m_Charges = value; + InvalidateProperties(); + } + } + + public List Receivers + { + get{ return m_Receivers; } + } + + [Constructable] + public BroadcastCrystal() : this( 2000 ) + { + } + + [Constructable] + public BroadcastCrystal( int charges ) : base( 0x1ED0 ) + { + Light = LightType.Circle150; + + m_Charges = charges; + + m_Receivers = new List(); + } + + public BroadcastCrystal( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( this.Active ? 1060742 : 1060743 ); // active / inactive + list.Add( 1060745 ); // broadcast + list.Add( 1060741, this.Charges.ToString() ); // charges: ~1_val~ + + if ( Receivers.Count > 0 ) + list.Add( 1060746, Receivers.Count.ToString() ); // links: ~1_val~ + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick( from ); + + LabelTo( from, this.Active ? 1060742 : 1060743 ); // active / inactive + LabelTo( from, 1060745 ); // broadcast + LabelTo( from, 1060741, this.Charges.ToString() ); // charges: ~1_val~ + + if ( Receivers.Count > 0 ) + LabelTo( from, 1060746, Receivers.Count.ToString() ); // links: ~1_val~ + } + + public override bool HandlesOnSpeech + { + get{ return Active && Receivers.Count > 0 && ( RootParent == null || RootParent is Mobile ); } + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( !Active || Receivers.Count == 0 || ( RootParent != null && !(RootParent is Mobile) ) ) + return; + + if ( e.Type == MessageType.Emote ) + return; + + Mobile from = e.Mobile; + string speech = e.Speech; + + foreach ( ReceiverCrystal receiver in new List( Receivers ) ) + { + if ( receiver.Deleted ) + { + Receivers.Remove( receiver ); + } + else if ( Charges > 0 ) + { + receiver.TransmitMessage( from, speech ); + Charges--; + } + else + { + this.Active = false; + break; + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private BroadcastCrystal m_Crystal; + + public InternalTarget( BroadcastCrystal crystal ) : base( 2, false, TargetFlags.None ) + { + m_Crystal = crystal; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Crystal.IsAccessibleTo( from ) ) + return; + + if ( from.Map != m_Crystal.Map || !from.InRange( m_Crystal.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + if ( targeted == m_Crystal ) + { + if ( m_Crystal.Active ) + { + m_Crystal.Active = false; + from.SendLocalizedMessage( 500672 ); // You turn the crystal off. + } + else + { + if ( m_Crystal.Charges > 0 ) + { + m_Crystal.Active = true; + from.SendLocalizedMessage( 500673 ); // You turn the crystal on. + } + else + { + from.SendLocalizedMessage( 500676 ); // This crystal is out of charges. + } + } + } + else if ( targeted is ReceiverCrystal ) + { + ReceiverCrystal receiver = (ReceiverCrystal) targeted; + + if ( m_Crystal.Receivers.Count >= 10 ) + { + from.SendLocalizedMessage( 1010042 ); // This broadcast crystal is already linked to 10 receivers. + } + else if ( receiver.Sender == m_Crystal ) + { + from.SendLocalizedMessage( 500674 ); // This crystal is already linked with that crystal. + } + else if ( receiver.Sender != null ) + { + from.SendLocalizedMessage( 1010043 ); // That receiver crystal is already linked to another broadcast crystal. + } + else + { + receiver.Sender = m_Crystal; + from.SendLocalizedMessage( 500675 ); // That crystal has been linked to this crystal. + } + } + else if ( targeted == from ) + { + foreach( ReceiverCrystal receiver in new List( m_Crystal.Receivers ) ) + { + receiver.Sender = null; + } + + from.SendLocalizedMessage( 1010046 ); // You unlink the broadcast crystal from all of its receivers. + } + else + { + Item targItem = targeted as Item; + + if ( targItem != null && targItem.VerifyMove( from ) ) + { + CrystalRechargeInfo info = CrystalRechargeInfo.Get( targItem.GetType() ); + + if ( info != null ) + { + if ( m_Crystal.Charges >= MaxCharges ) + { + from.SendLocalizedMessage( 500678 ); // This crystal is already fully charged. + } + else + { + targItem.Consume(); + + if ( m_Crystal.Charges + info.Amount >= MaxCharges ) + { + m_Crystal.Charges = MaxCharges; + from.SendLocalizedMessage( 500679 ); // You completely recharge the crystal. + } + else + { + m_Crystal.Charges += info.Amount; + from.SendLocalizedMessage( 500680 ); // You recharge the crystal. + } + } + + return; + } + } + + from.SendLocalizedMessage( 500681 ); // You cannot use this crystal on that. + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteEncodedInt( m_Charges ); + writer.WriteItemList( m_Receivers ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadEncodedInt(); + m_Receivers = reader.ReadStrongItemList(); + } + } + + public class ReceiverCrystal : Item + { + public override int LabelNumber{ get{ return 1060740; } } // communication crystal + + private BroadcastCrystal m_Sender; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get{ return this.ItemID == 0x1ED1; } + set + { + this.ItemID = value ? 0x1ED1 : 0x1ED0; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BroadcastCrystal Sender + { + get{ return m_Sender; } + set + { + if ( m_Sender != null ) + { + m_Sender.Receivers.Remove( this ); + m_Sender.InvalidateProperties(); + } + + m_Sender = value; + + if ( value != null ) + { + value.Receivers.Add( this ); + value.InvalidateProperties(); + } + } + } + + [Constructable] + public ReceiverCrystal() : base( 0x1ED0 ) + { + Light = LightType.Circle150; + } + + public ReceiverCrystal( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( this.Active ? 1060742 : 1060743 ); // active / inactive + list.Add( 1060744 ); // receiver + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, this.Active ? 1060742 : 1060743 ); // active / inactive + LabelTo( from, 1060744 ); // receiver + } + + public void TransmitMessage( Mobile from, string message ) + { + if ( !this.Active ) + return; + + string text = String.Format( "{0} says {1}", from.Name, message ); + + if ( this.RootParent is Mobile ) + { + ((Mobile)this.RootParent).SendMessage( 0x2B2, "Crystal: " + text ); + } + else if ( this.RootParent is Item ) + { + ((Item)this.RootParent).PublicOverheadMessage( MessageType.Regular, 0x2B2, false, "Crystal: " + text ); + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x2B2, false, text ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private ReceiverCrystal m_Crystal; + + public InternalTarget( ReceiverCrystal crystal ) : base( -1, false, TargetFlags.None ) + { + m_Crystal = crystal; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !m_Crystal.IsAccessibleTo( from ) ) + return; + + if ( from.Map != m_Crystal.Map || !from.InRange( m_Crystal.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + if ( targeted == m_Crystal ) + { + if ( m_Crystal.Active ) + { + m_Crystal.Active = false; + from.SendLocalizedMessage( 500672 ); // You turn the crystal off. + } + else + { + m_Crystal.Active = true; + from.SendLocalizedMessage( 500673 ); // You turn the crystal on. + } + } + else if ( targeted == from ) + { + if ( m_Crystal.Sender != null ) + { + m_Crystal.Sender = null; + from.SendLocalizedMessage( 1010044 ); // You unlink the receiver crystal. + } + else + { + from.SendLocalizedMessage( 1010045 ); // That receiver crystal is not linked. + } + } + else + { + Item targItem = targeted as Item; + + if ( targItem != null && targItem.VerifyMove( from ) ) + { + CrystalRechargeInfo info = CrystalRechargeInfo.Get( targItem.GetType() ); + + if ( info != null ) + { + from.SendLocalizedMessage( 500677 ); // This crystal cannot be recharged. + return; + } + } + + from.SendLocalizedMessage( 1010045 ); // That receiver crystal is not linked. + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteItem( m_Sender ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Sender = reader.ReadItem(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Corpses/Corpse.cs b/Scripts/Items/Misc/Corpses/Corpse.cs new file mode 100644 index 0000000..165fd1c --- /dev/null +++ b/Scripts/Items/Misc/Corpses/Corpse.cs @@ -0,0 +1,1359 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Engines.PartySystem; +using Server.Engines.Quests; +using Server.Engines.Quests.Doom; +using Server.Engines.Quests.Haven; +using Server.Guilds; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using System.IO; + +namespace Server.Items +{ + public interface IDevourer + { + bool Devour( Corpse corpse ); + } + + [Flags] + public enum CorpseFlag + { + None = 0x00000000, + + /// + /// Has this corpse been carved? + /// + Carved = 0x00000001, + + /// + /// If true, this corpse will not turn into bones + /// + NoBones = 0x00000002, + + /// + /// If true, the corpse has turned into bones + /// + IsBones = 0x00000004, + + /// + /// Has this corpse yet been visited by a taxidermist? + /// + VisitedByTaxidermist = 0x00000008, + + /// + /// Has this corpse yet been used to channel spiritual energy? (AOS Spirit Speak) + /// + Channeled = 0x00000010, + + /// + /// Was the owner criminal when he died? + /// + Criminal = 0x00000020, + /// + /// Has this corpse been animated? + /// + Animated = 0x00000040, + /// + /// Has this corpse been self looted? + /// + SelfLooted = 0x00000080, + } + + public class Corpse : Container, ICarvable + { + private Mobile m_Owner; // Whos corpse is this? + private Mobile m_Killer; // Who killed the owner? + private CorpseFlag m_Flags; // @see CorpseFlag + + private List m_Looters; // Who's looted this corpse? + private List m_EquipItems; // List of dropped equipment when the owner died. Ingame, these items display /on/ the corpse, not just inside + private List m_RestoreEquip; // List of items equipped when the owner died. Includes insured and blessed items. + private List m_Aggressors; // Anyone from this list will be able to loot this corpse; we attacked them, or they attacked us when we were freely attackable + + private string m_CorpseName; // Value of the CorpseNameAttribute attached to the owner when he died -or- null if the owner had no CorpseNameAttribute; use "the remains of ~name~" + private IDevourer m_Devourer; // The creature that devoured this corpse + + // For notoriety: + private AccessLevel m_AccessLevel; // Which AccessLevel the owner had when he died + private Guild m_Guild; // Which Guild the owner was in when he died + private int m_Kills; // How many kills the owner had when he died + + private DateTime m_TimeOfDeath; // What time was this corpse created? + + private HairInfo m_Hair; // This contains the hair of the owner + private FacialHairInfo m_FacialHair; // This contains the facial hair of the owner + + // For Forensics Evaluation + public string m_Forensicist; // Name of the first PlayerMobile who used Forensic Evaluation on the corpse + + + public static readonly TimeSpan MonsterLootRightSacrifice = TimeSpan.FromMinutes( 2.0 ); + + public static readonly TimeSpan InstancedCorpseTime = TimeSpan.FromMinutes( 3.0 ); + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool InstancedCorpse + { + get + { + if ( !Core.SE ) + return false; + + return ( DateTime.Now < (m_TimeOfDeath + InstancedCorpseTime) ); + } + } + + private Dictionary m_InstancedItems; + + private class InstancedItemInfo + { + private Mobile m_Mobile; + private Item m_Item; + + private bool m_Perpetual; //Needed for Rummaged stuff. CONTRARY to the Patchlog, cause a later FoF contradicts it. Verify on OSI. + public bool Perpetual { get { return m_Perpetual; } set { m_Perpetual = value; } } + + public InstancedItemInfo( Item i, Mobile m ) + { + m_Item = i; + m_Mobile = m; + } + + public bool IsOwner( Mobile m ) + { + if ( m_Item.LootType == LootType.Cursed ) //Cursed Items are part of everyone's instanced corpse... (?) + return true; + + if ( m == null ) + return false; //sanity + + if ( m_Mobile == m ) + return true; + + Party myParty = Party.Get( m_Mobile ); + + return (myParty != null && myParty == Party.Get( m )); + } + } + + public override bool IsChildVisibleTo( Mobile m, Item child ) + { + if ( !m.Player || m.AccessLevel > AccessLevel.Player ) //Staff and creatures not subject to instancing. + return true; + + if ( m_InstancedItems != null ) + { + InstancedItemInfo info; + + if ( m_InstancedItems.TryGetValue( child, out info ) && (InstancedCorpse || info.Perpetual) ) + { + return info.IsOwner( m ); //IsOwner checks Party stuff. + } + } + + return true; + } + + private void AssignInstancedLoot() + { + if ( m_Aggressors.Count == 0 || this.Items.Count == 0 ) + return; + + if ( m_InstancedItems == null ) + m_InstancedItems = new Dictionary(); + + List m_Stackables = new List(); + List m_Unstackables = new List(); + + for ( int i = 0; i < this.Items.Count; i++ ) + { + Item item = this.Items[i]; + + if ( item.LootType != LootType.Cursed ) //Don't have curesd items take up someone's item spot.. (?) + { + if ( item.Stackable ) + m_Stackables.Add( item ); + else + m_Unstackables.Add( item ); + } + } + + List attackers = new List( m_Aggressors ); + + for ( int i = 1; i < attackers.Count -1; i++ ) //randomize + { + int rand = Utility.Random( i + 1 ); + + Mobile temp = attackers[rand]; + attackers[rand] = attackers[i]; + attackers[i] = temp; + } + + //stackables first, for the remaining stackables, have those be randomly added after + + for ( int i = 0; i < m_Stackables.Count; i++ ) + { + Item item = m_Stackables[i]; + + if ( item.Amount >= attackers.Count ) + { + int amountPerAttacker = (item.Amount / attackers.Count); + int remainder = (item.Amount % attackers.Count); + + for ( int j = 0; j < ((remainder == 0) ? attackers.Count -1 : attackers.Count); j++ ) + { + Item splitItem = Mobile.LiftItemDupe( item, item.Amount - amountPerAttacker ); //LiftItemDupe automagically adds it as a child item to the corpse + + m_InstancedItems.Add( splitItem, new InstancedItemInfo( splitItem, attackers[j] ) ); + + //What happens to the remaining portion? TEMP FOR NOW UNTIL OSI VERIFICATION: Treat as Single Item. + } + + if ( remainder == 0 ) + { + m_InstancedItems.Add( item, new InstancedItemInfo( item, attackers[attackers.Count - 1] ) ); + //Add in the original item (which has an equal amount as the others) to the instance for the last attacker, cause it wasn't added above. + } + else + { + m_Unstackables.Add( item ); + } + } + else + { + //What happens in this case? TEMP FOR NOW UNTIL OSI VERIFICATION: Treat as Single Item. + m_Unstackables.Add( item ); + } + } + + for ( int i = 0; i < m_Unstackables.Count; i++ ) + { + Mobile m = attackers[i % attackers.Count]; + Item item = m_Unstackables[i]; + + m_InstancedItems.Add( item, new InstancedItemInfo( item, m ) ); + } + } + + public void AddCarvedItem( Item carved, Mobile carver ) + { + this.DropItem( carved ); + + if ( this.InstancedCorpse ) + { + if ( m_InstancedItems == null ) + m_InstancedItems = new Dictionary(); + + m_InstancedItems.Add( carved, new InstancedItemInfo( carved, carver ) ); + } + } + + public override bool IsDecoContainer + { + get{ return false; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime TimeOfDeath + { + get{ return m_TimeOfDeath; } + set{ m_TimeOfDeath = value; } + } + + public override bool DisplayWeight { get { return false; } } + + public HairInfo Hair { get { return m_Hair; } } + public FacialHairInfo FacialHair { get { return m_FacialHair; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsBones + { + get { return GetFlag( CorpseFlag.IsBones ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Devoured + { + get { return (m_Devourer != null); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Carved + { + get{ return GetFlag( CorpseFlag.Carved ); } + set { SetFlag( CorpseFlag.Carved, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool VisitedByTaxidermist + { + get { return GetFlag( CorpseFlag.VisitedByTaxidermist ); } + set { SetFlag( CorpseFlag.VisitedByTaxidermist, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Channeled + { + get { return GetFlag( CorpseFlag.Channeled ); } + set { SetFlag( CorpseFlag.Channeled, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Animated + { + get { return GetFlag(CorpseFlag.Animated); } + set { SetFlag(CorpseFlag.Animated, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool SelfLooted + { + get { return GetFlag(CorpseFlag.SelfLooted); } + set { SetFlag(CorpseFlag.SelfLooted, value); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public AccessLevel AccessLevel + { + get{ return m_AccessLevel; } + } + + public List Aggressors + { + get{ return m_Aggressors; } + } + + public List Looters + { + get{ return m_Looters; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Killer + { + get{ return m_Killer; } + } + + public List EquipItems + { + get{ return m_EquipItems; } + } + + public List RestoreEquip + { + get { return m_RestoreEquip; } + set { m_RestoreEquip = value; } + } + + public Guild Guild + { + get{ return m_Guild; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Kills + { + get{ return m_Kills; } + set{ m_Kills = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Criminal + { + get { return GetFlag( CorpseFlag.Criminal ); } + set { SetFlag( CorpseFlag.Criminal, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get{ return m_Owner; } + } + + public void TurnToBones() + { + if ( Deleted ) + return; + + ProcessDelta(); + SendRemovePacket(); + ItemID = Utility.Random( 0xECA, 9 ); // bone graphic + Hue = 0; + ProcessDelta(); + + SetFlag( CorpseFlag.NoBones, true ); + SetFlag( CorpseFlag.IsBones, true ); + + BeginDecay( m_BoneDecayTime ); + } + + // Scriptiz : on double le temps de decay (de 7 � 15min par phase de decay) + private static TimeSpan m_DefaultDecayTime = TimeSpan.FromMinutes( 30.0 ); + private static TimeSpan m_BoneDecayTime = TimeSpan.FromMinutes( 30.0 ); + + private Timer m_DecayTimer; + private DateTime m_DecayTime; + + public void BeginDecay( TimeSpan delay ) + { + if ( m_DecayTimer != null ) + m_DecayTimer.Stop(); + + m_DecayTime = DateTime.Now + delay; + + m_DecayTimer = new InternalTimer( this, delay ); + m_DecayTimer.Start(); + } + + public override void OnAfterDelete() + { + if ( m_DecayTimer != null ) + m_DecayTimer.Stop(); + + m_DecayTimer = null; + } + + private class InternalTimer : Timer + { + private Corpse m_Corpse; + + public InternalTimer( Corpse c, TimeSpan delay ) : base( delay ) + { + m_Corpse = c; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + /*** ADDED ***/ + // Alambik's Undead system + if (m_Corpse.Amount == 3 && m_Corpse.Killer != null && m_Corpse.Killer.Player) // Protocol for corpse is Amount = owner's body value + { + // Scriptiz : on ajoute deux conditions sur le Killer pour �viter que des gardes + // ne kills � longueur de journ�e des zombies + Mobile zombie = new Zombie(true); // Create zombie with no packed items + zombie.MoveToWorld(m_Corpse.Location, m_Corpse.Map); + zombie.Emote("*se redresse*"); + m_Corpse.Delete(); + } + else + /*** END ***/ + if ( !m_Corpse.GetFlag( CorpseFlag.NoBones ) ) + m_Corpse.TurnToBones(); + else + m_Corpse.Delete(); + } + } + + public static string GetCorpseName( Mobile m ) + { + if (m is BaseCreature) + { + BaseCreature bc = (BaseCreature)m; + + if (bc.CorpseNameOverride != null) + return bc.CorpseNameOverride; + } + + Type t = m.GetType(); + + object[] attrs = t.GetCustomAttributes( typeof( CorpseNameAttribute ), true ); + + if ( attrs != null && attrs.Length > 0 ) + { + CorpseNameAttribute attr = attrs[0] as CorpseNameAttribute; + + if ( attr != null ) + return attr.Name; + } + + return null; + } + + public static void Initialize() + { + Mobile.CreateCorpseHandler += new CreateCorpseHandler( Mobile_CreateCorpseHandler ); + } + + public static Container Mobile_CreateCorpseHandler( Mobile owner, HairInfo hair, FacialHairInfo facialhair, List initialContent, List equipItems ) + { + bool shouldFillCorpse = true; + + //if ( owner is BaseCreature ) + // shouldFillCorpse = !((BaseCreature)owner).IsBonded; + + Corpse c; + if( owner is MilitiaFighter ) + c = new MilitiaFighterCorpse( owner, hair, facialhair, shouldFillCorpse ? equipItems : new List() ); + else + c = new Corpse( owner, hair, facialhair, shouldFillCorpse ? equipItems : new List() ); + + owner.Corpse = c; + + if ( shouldFillCorpse ) + { + for ( int i = 0; i < initialContent.Count; ++i ) + { + Item item = initialContent[i]; + + if ( Core.AOS && owner.Player && item.Parent == owner.Backpack ) + c.AddItem( item ); + else + c.DropItem( item ); + + if ( owner.Player && Core.AOS ) + c.SetRestoreInfo( item, item.Location ); + } + + if (Core.SE && !owner.Player) + { + c.AssignInstancedLoot(); + } + else if (Core.AOS) + { + PlayerMobile pm = owner as PlayerMobile; + + if (pm != null) + c.RestoreEquip = pm.EquipSnapshot; + } + } + else + { + c.Carved = true; // TODO: Is it needed? + } + + Point3D loc = owner.Location; + Map map = owner.Map; + + if ( map == null || map == Map.Internal ) + { + loc = owner.LogoutLocation; + map = owner.LogoutMap; + } + + c.MoveToWorld( loc, map ); + + return c; + } + + // Why was this public? + // public override bool IsPublicContainer{ get{ return true; } } + + public Corpse( Mobile owner, List equipItems ) : this( owner, null, null, equipItems ) + { + } + + public Corpse( Mobile owner, HairInfo hair, FacialHairInfo facialhair, List equipItems ) + : base( 0x2006 ) + { + // To supress console warnings, stackable must be true + Stackable = true; + Amount = owner.Body; // protocol defines that for itemid 0x2006, amount=body + Stackable = false; + + Movable = false; + Hue = owner.Hue; + Direction = owner.Direction; + Name = owner.Name; + + m_Owner = owner; + + m_CorpseName = GetCorpseName( owner ); + + m_TimeOfDeath = DateTime.Now; + + m_AccessLevel = owner.AccessLevel; + m_Guild = owner.Guild as Guild; + m_Kills = owner.Kills; + SetFlag( CorpseFlag.Criminal, owner.Criminal ); + + m_Hair = hair; + m_FacialHair = facialhair; + + + // This corpse does not turn to bones if: the owner is not a player + SetFlag( CorpseFlag.NoBones, !owner.Player ); + + m_Looters = new List(); + m_EquipItems = equipItems; + + m_Aggressors = new List( owner.Aggressors.Count + owner.Aggressed.Count ); + //bool addToAggressors = !( owner is BaseCreature ); + + bool isBaseCreature = (owner is BaseCreature); + + TimeSpan lastTime = TimeSpan.MaxValue; + + for ( int i = 0; i < owner.Aggressors.Count; ++i ) + { + AggressorInfo info = owner.Aggressors[i]; + + if ( (DateTime.Now - info.LastCombatTime) < lastTime ) + { + m_Killer = info.Attacker; + lastTime = (DateTime.Now - info.LastCombatTime); + } + + if ( !isBaseCreature && !info.CriminalAggression ) + m_Aggressors.Add( info.Attacker ); + } + + for ( int i = 0; i < owner.Aggressed.Count; ++i ) + { + AggressorInfo info = owner.Aggressed[i]; + + if ( (DateTime.Now - info.LastCombatTime) < lastTime ) + { + m_Killer = info.Defender; + lastTime = (DateTime.Now - info.LastCombatTime); + } + + if ( !isBaseCreature ) + m_Aggressors.Add( info.Defender ); + } + + if ( isBaseCreature ) + { + BaseCreature bc = (BaseCreature)owner; + + Mobile master = bc.GetMaster(); + if( master != null ) + m_Aggressors.Add( master ); + + List rights = BaseCreature.GetLootingRights( bc.DamageEntries, bc.HitsMax ); + for ( int i = 0; i < rights.Count; ++i ) + { + DamageStore ds = rights[i]; + + if ( ds.m_HasRight ) + m_Aggressors.Add( ds.m_Mobile ); + } + } + + BeginDecay( m_DefaultDecayTime ); + + DevourCorpse(); + } + + public Corpse( Serial serial ) : base( serial ) + { + } + + protected bool GetFlag( CorpseFlag flag ) + { + return ((m_Flags & flag) != 0); + } + + protected void SetFlag( CorpseFlag flag, bool on ) + { + m_Flags = (on ? m_Flags | flag : m_Flags & ~flag); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write((int)12); // version + + if (m_RestoreEquip == null) + { + writer.Write(false); + } + else + { + writer.Write(true); + writer.Write(m_RestoreEquip); + } + + writer.Write( (int)m_Flags ); + + writer.WriteDeltaTime( m_TimeOfDeath ); + + List> list = ( m_RestoreTable == null ? null : new List>( m_RestoreTable ) ); + int count = ( list == null ? 0 : list.Count ); + + writer.Write( count ); + + for ( int i = 0; i < count; ++i ) + { + KeyValuePair kvp = list[i]; + Item item = kvp.Key; + Point3D loc = kvp.Value; + + writer.Write( item ); + + if ( item.Location == loc ) + { + writer.Write( false ); + } + else + { + writer.Write( true ); + writer.Write( loc ); + } + } + + writer.Write( m_DecayTimer != null ); + + if ( m_DecayTimer != null ) + writer.WriteDeltaTime( m_DecayTime ); + + writer.Write( m_Looters ); + writer.Write( m_Killer ); + + writer.Write( m_Aggressors ); + + writer.Write( m_Owner ); + + writer.Write( (string) m_CorpseName ); + + writer.Write( (int) m_AccessLevel ); + writer.Write( (Guild) m_Guild ); + writer.Write( (int) m_Kills ); + + writer.Write( m_EquipItems ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 12: + { + if (reader.ReadBool()) + m_RestoreEquip = reader.ReadStrongItemList(); + + goto case 11; + } + case 11: + { + // Version 11, we move all bools to a CorpseFlag + m_Flags = (CorpseFlag)reader.ReadInt(); + + m_TimeOfDeath = reader.ReadDeltaTime(); + + int count = reader.ReadInt(); + + for (int i = 0; i < count; ++i) + { + Item item = reader.ReadItem(); + + if (reader.ReadBool()) + SetRestoreInfo(item, reader.ReadPoint3D()); + else if (item != null) + SetRestoreInfo(item, item.Location); + } + + if (reader.ReadBool()) + BeginDecay(reader.ReadDeltaTime() - DateTime.Now); + + m_Looters = reader.ReadStrongMobileList(); + m_Killer = reader.ReadMobile(); + + m_Aggressors = reader.ReadStrongMobileList(); + m_Owner = reader.ReadMobile(); + + m_CorpseName = reader.ReadString(); + + m_AccessLevel = (AccessLevel)reader.ReadInt(); + reader.ReadInt(); // guild reserve + m_Kills = reader.ReadInt(); + + m_EquipItems = reader.ReadStrongItemList(); + break; + } + case 10: + { + m_TimeOfDeath = reader.ReadDeltaTime(); + + goto case 9; + } + case 9: + { + int count = reader.ReadInt(); + + for ( int i = 0; i < count; ++i ) + { + Item item = reader.ReadItem(); + + if ( reader.ReadBool() ) + SetRestoreInfo( item, reader.ReadPoint3D() ); + else if ( item != null ) + SetRestoreInfo( item, item.Location ); + } + + goto case 8; + } + case 8: + { + SetFlag( CorpseFlag.VisitedByTaxidermist, reader.ReadBool() ); + + goto case 7; + } + case 7: + { + if ( reader.ReadBool() ) + BeginDecay( reader.ReadDeltaTime() - DateTime.Now ); + + goto case 6; + } + case 6: + { + m_Looters = reader.ReadStrongMobileList(); + m_Killer = reader.ReadMobile(); + + goto case 5; + } + case 5: + { + SetFlag( CorpseFlag.Carved, reader.ReadBool() ); + + goto case 4; + } + case 4: + { + m_Aggressors = reader.ReadStrongMobileList(); + + goto case 3; + } + case 3: + { + m_Owner = reader.ReadMobile(); + + goto case 2; + } + case 2: + { + SetFlag( CorpseFlag.NoBones, reader.ReadBool() ); + + goto case 1; + } + case 1: + { + m_CorpseName = reader.ReadString(); + + goto case 0; + } + case 0: + { + if ( version < 10 ) + m_TimeOfDeath = DateTime.Now; + + if ( version < 7 ) + BeginDecay( m_DefaultDecayTime ); + + if ( version < 6 ) + m_Looters = new List(); + + if ( version < 4 ) + m_Aggressors = new List(); + + m_AccessLevel = (AccessLevel)reader.ReadInt(); + reader.ReadInt(); // guild reserve + m_Kills = reader.ReadInt(); + SetFlag( CorpseFlag.Criminal, reader.ReadBool() ); + + m_EquipItems = reader.ReadStrongItemList(); + + break; + } + } + } + + public bool DevourCorpse() + { + if( Devoured || Deleted || m_Killer == null || m_Killer.Deleted || !m_Killer.Alive || !(m_Killer is IDevourer) || m_Owner == null || m_Owner.Deleted ) + return false; + + m_Devourer = (IDevourer)m_Killer; // Set the devourer the killer + return m_Devourer.Devour( this ); // Devour the corpse if it hasn't + } + + public override void SendInfoTo( NetState state, bool sendOplPacket ) + { + base.SendInfoTo( state, sendOplPacket ); + + if (((Body)Amount).IsHuman && ItemID == 0x2006) + { + if (state.ContainerGridLines) + { + state.Send(new CorpseContent6017(state.Mobile, this)); + } + else + { + state.Send(new CorpseContent(state.Mobile, this)); + } + + state.Send(new CorpseEquip(state.Mobile, this)); + } + } + + public bool IsCriminalAction( Mobile from ) + { + if ( from == m_Owner || from.AccessLevel >= AccessLevel.GameMaster ) + return false; + + Party p = Party.Get( m_Owner ); + + if ( p != null && p.Contains( from ) ) + { + PartyMemberInfo pmi = p[m_Owner]; + + if ( pmi != null && pmi.CanLoot ) + return false; + } + + return ( NotorietyHandlers.CorpseNotoriety( from, this ) == Notoriety.Innocent ); + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( !base.CheckItemUse( from, item ) ) + return false; + + if ( item != this ) + return CanLoot( from, item ); + + return true; + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( !base.CheckLift( from, item, ref reject ) ) + return false; + + return CanLoot( from,item ); + } + + public override void OnItemUsed( Mobile from, Item item ) + { + base.OnItemUsed( from, item ); + + if ( item is Food ) + from.RevealingAction(); + + if ( item != this && IsCriminalAction( from ) ) + from.CriminalAction( true ); + + if ( !m_Looters.Contains( from ) ) + m_Looters.Add( from ); + + if ( m_InstancedItems != null && m_InstancedItems.ContainsKey( item ) ) + m_InstancedItems.Remove( item ); + } + + public override void OnItemLifted( Mobile from, Item item ) + { + base.OnItemLifted( from, item ); + + if ( item != this && from != m_Owner ) + from.RevealingAction(); + + if ( item != this && IsCriminalAction( from ) ) + from.CriminalAction( true ); + + if ( !m_Looters.Contains( from ) ) + m_Looters.Add( from ); + + if ( m_InstancedItems != null && m_InstancedItems.ContainsKey( item ) ) + m_InstancedItems.Remove( item ); + + // Scriptiz : on log les loots ! + if (from != null && m_Owner != null && item != null && from.Player && m_Owner.Player) + { + string sItem = String.Format("{0} ({1})", item.GetType().Name, item.Serial); + string sLooter = String.Format("{0} ({1})", from.Name, (from.Account != null ? from.Account.Username : "null")); + string sLooted = String.Format("{0} ({1})", m_Owner.Name, (m_Owner.Account != null ? m_Owner.Account.Username : "null")); + LogLoot(String.Format(DateTime.Now + ": {0} a �t� loot� par {1} sur le corps de {2}", sItem, sLooter, sLooted)); + } + } + + // Scriptiz : on log les loots ! + public void LogLoot(string msg) + { + if (!Directory.Exists("Logs")) + Directory.CreateDirectory("Logs"); + + string directory = "Logs/Death"; + + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + try + { + StreamWriter writer = new StreamWriter(Path.Combine(directory, String.Format("Loots-{0}.log", DateTime.Now.ToLongDateString())), true); + writer.AutoFlush = true; + writer.WriteLine(msg); + writer.Close(); + } + catch (Exception ex) + { + Console.WriteLine("Corpse.LogLoot : " + ex.Message); + } + } + + private class OpenCorpseEntry : ContextMenuEntry + { + public OpenCorpseEntry() : base( 6215, 2 ) + { + } + + public override void OnClick() + { + Corpse corpse = Owner.Target as Corpse; + + if ( corpse != null && Owner.From.CheckAlive() ) + corpse.Open( Owner.From, false ); + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( Core.AOS && m_Owner == from && from.Alive ) + list.Add( new OpenCorpseEntry() ); + } + + private Dictionary m_RestoreTable; + + public bool GetRestoreInfo( Item item, ref Point3D loc ) + { + if ( m_RestoreTable == null || item == null ) + return false; + + return m_RestoreTable.TryGetValue( item, out loc ); + } + + public void SetRestoreInfo( Item item, Point3D loc ) + { + if ( item == null ) + return; + + if ( m_RestoreTable == null ) + m_RestoreTable = new Dictionary(); + + m_RestoreTable[item] = loc; + } + + public void ClearRestoreInfo( Item item ) + { + if ( m_RestoreTable == null || item == null ) + return; + + m_RestoreTable.Remove( item ); + + if ( m_RestoreTable.Count == 0 ) + m_RestoreTable = null; + } + + public bool CanLoot( Mobile from, Item item ) + { + // Scriptiz : Les objets marqu�s non Lootable ne peuvent pas �tre loot�s + if (item != null && !item.Lootable && Owner != null && Owner.Player) + { + from.SendMessage("Vous ne pouvez pas looter cet objet."); + return false; + } + + if ( !IsCriminalAction( from ) ) + return true; + + Map map = this.Map; + + if ( map == null || (map.Rules & MapRules.HarmfulRestrictions) != 0 ) + return false; + + return true; + } + + public bool CheckLoot( Mobile from, Item item ) + { + if ( !CanLoot( from, item ) ) + { + if ( m_Owner == null || !m_Owner.Player ) + from.SendLocalizedMessage( 1005035 ); // You did not earn the right to loot this creature! + else + from.SendLocalizedMessage( 1010049 ); // You may not loot this corpse. + + return false; + } + else if ( IsCriminalAction( from ) ) + { + if ( m_Owner == null || !m_Owner.Player ) + from.SendLocalizedMessage( 1005036 ); // Looting this monster corpse will be a criminal act! + else + from.SendLocalizedMessage( 1005038 ); // Looting this corpse will be a criminal act! + } + + return true; + } + + public virtual void Open( Mobile from, bool checkSelfLoot ) + { + if ( from.AccessLevel > AccessLevel.Player || from.InRange( this.GetWorldLocation(), 2 ) ) + { + + #region Self Looting + if (checkSelfLoot && from == m_Owner && !GetFlag(CorpseFlag.SelfLooted) && this.Items.Count != 0) + { + DeathRobe robe = from.FindItemOnLayer(Layer.OuterTorso) as DeathRobe; + + if (robe != null) + { + Map map = from.Map; + + if (map != null && map != Map.Internal) + robe.MoveToWorld(from.Location, map); + } + + Container pack = from.Backpack; + + if (m_RestoreEquip != null && pack != null) + { + List packItems = new List(pack.Items); // Only items in the top-level pack are re-equipped + + for (int i = 0; i < packItems.Count; i++) + { + Item packItem = packItems[i]; + + if (m_RestoreEquip.Contains(packItem) && packItem.Movable) + from.EquipItem(packItem); + } + } + + List items = new List(this.Items); + + bool didntFit = false; + + for (int i = 0; !didntFit && i < items.Count; ++i) + { + Item item = items[i]; + Point3D loc = item.Location; + + if ((item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) || !item.Movable || !GetRestoreInfo(item, ref loc)) + continue; + + if (pack != null && pack.CheckHold(from, item, false, true)) + { + item.Location = loc; + pack.AddItem(item); + + if (m_RestoreEquip != null && m_RestoreEquip.Contains(item)) + from.EquipItem(item); + } + else + { + didntFit = true; + } + } + + from.PlaySound(0x3E3); + + if (this.Items.Count != 0) + { + from.SendLocalizedMessage(1062472); // You gather some of your belongings. The rest remain on the corpse. + } + else + { + SetFlag(CorpseFlag.Carved, true); + + if (ItemID == 0x2006) + { + ProcessDelta(); + SendRemovePacket(); + ItemID = Utility.Random(0xECA, 9); // bone graphic + Hue = 0; + ProcessDelta(); + } + + from.SendLocalizedMessage(1062471); // You quickly gather all of your belongings. + } + + SetFlag(CorpseFlag.SelfLooted, true); + } + + #endregion + + if ( !CheckLoot( from, null ) ) + return; + + #region Quests + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest ) + { + GetDaemonBoneObjective obj = qs.FindObjective( typeof( GetDaemonBoneObjective ) ) as GetDaemonBoneObjective; + + if ( obj != null && obj.CorpseWithBone == this && ( !obj.Completed || UzeraanTurmoilQuest.HasLostDaemonBone( player ) ) ) + { + Item bone = new QuestDaemonBone(); + + if ( player.PlaceInBackpack( bone ) ) + { + obj.CorpseWithBone = null; + player.SendLocalizedMessage( 1049341, "", 0x22 ); // You rummage through the bones and find a Daemon Bone! You quickly place the item in your pack. + + if ( !obj.Completed ) + obj.Complete(); + } + else + { + bone.Delete(); + player.SendLocalizedMessage( 1049342, "", 0x22 ); // Rummaging through the bones you find a Daemon Bone, but can't pick it up because your pack is too full. Come back when you have more room in your pack. + } + + return; + } + } + else if ( qs is TheSummoningQuest ) + { + VanquishDaemonObjective obj = qs.FindObjective( typeof( VanquishDaemonObjective ) ) as VanquishDaemonObjective; + + if ( obj != null && obj.Completed && obj.CorpseWithSkull == this ) + { + GoldenSkull sk = new GoldenSkull(); + + if ( player.PlaceInBackpack( sk ) ) + { + obj.CorpseWithSkull = null; + player.SendLocalizedMessage( 1050022 ); // For your valor in combating the devourer, you have been awarded a golden skull. + qs.Complete(); + } + else + { + sk.Delete(); + player.SendLocalizedMessage( 1050023 ); // You find a golden skull, but your backpack is too full to carry it. + } + } + } + } + + #endregion + + base.OnDoubleClick( from ); + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + } + + public override void OnDoubleClick( Mobile from ) + { + Open( from, Core.AOS ); + } + + public override bool CheckContentDisplay( Mobile from ) + { + return false; + } + + public override bool DisplaysContent{ get{ return false; } } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( ItemID == 0x2006 ) // Corpse form + { + if ( m_CorpseName != null ) + list.Add( m_CorpseName ); + else + list.Add( 1046414, this.Name ); // the remains of ~1_NAME~ + } + else // Bone form + { + list.Add( 1046414, this.Name ); // the remains of ~1_NAME~ + } + } + + public override void OnAosSingleClick( Mobile from ) + { + int hue = Notoriety.GetHue( NotorietyHandlers.CorpseNotoriety( from, this ) ); + ObjectPropertyList opl = this.PropertyList; + + if ( opl.Header > 0 ) + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs ) ); + } + + public override void OnSingleClick( Mobile from ) + { + int hue = Notoriety.GetHue( NotorietyHandlers.CorpseNotoriety( from, this ) ); + + if ( ItemID == 0x2006 ) // Corpse form + { + if ( m_CorpseName != null ) + from.Send( new AsciiMessage( Serial, ItemID, MessageType.Label, hue, 3, "", m_CorpseName ) ); + else + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name ) ); + } + else // Bone form + { + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, hue, 3, 1046414, "", Name ) ); + } + } + + public void Carve( Mobile from, Item item ) + { + if ( IsCriminalAction( from ) && this.Map != null && (this.Map.Rules & MapRules.HarmfulRestrictions) != 0 ) + { + if ( m_Owner == null || !m_Owner.Player ) + from.SendLocalizedMessage( 1005035 ); // You did not earn the right to loot this creature! + else + from.SendLocalizedMessage( 1010049 ); // You may not loot this corpse. + + return; + } + + Mobile dead = m_Owner; + + if ( GetFlag( CorpseFlag.Carved ) || dead == null ) + { + from.SendLocalizedMessage( 500485 ); // You see nothing useful to carve from the corpse. + } + else if ( ((Body)Amount).IsHuman && ItemID == 0x2006 ) + { + new Blood( 0x122D ).MoveToWorld( Location, Map ); + + new Torso().MoveToWorld( Location, Map ); + new LeftLeg().MoveToWorld( Location, Map ); + new LeftArm().MoveToWorld( Location, Map ); + new RightLeg().MoveToWorld( Location, Map ); + new RightArm().MoveToWorld( Location, Map ); + new Head( dead.Name ).MoveToWorld( Location, Map ); + + SetFlag( CorpseFlag.Carved, true ); + + ProcessDelta(); + SendRemovePacket(); + ItemID = Utility.Random( 0xECA, 9 ); // bone graphic + Hue = 0; + ProcessDelta(); + + if ( IsCriminalAction( from ) ) + from.CriminalAction( true ); + } + else if ( dead is BaseCreature ) + { + ((BaseCreature)dead).OnCarve( from, this, item ); + } + else + { + from.SendLocalizedMessage( 500485 ); // You see nothing useful to carve from the corpse. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Corpses/CorpseNameAttribute.cs b/Scripts/Items/Misc/Corpses/CorpseNameAttribute.cs new file mode 100644 index 0000000..9a8f85f --- /dev/null +++ b/Scripts/Items/Misc/Corpses/CorpseNameAttribute.cs @@ -0,0 +1,20 @@ +using System; + +namespace Server +{ + [AttributeUsage( AttributeTargets.Class )] + public class CorpseNameAttribute : Attribute + { + private string m_Name; + + public string Name + { + get{ return m_Name; } + } + + public CorpseNameAttribute( string name ) + { + m_Name = name; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Corpses/DecayedCorpse.cs b/Scripts/Items/Misc/Corpses/DecayedCorpse.cs new file mode 100644 index 0000000..5aa61da --- /dev/null +++ b/Scripts/Items/Misc/Corpses/DecayedCorpse.cs @@ -0,0 +1,115 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DecayedCorpse : Container + { + private Timer m_DecayTimer; + private DateTime m_DecayTime; + + private static TimeSpan m_DefaultDecayTime = TimeSpan.FromMinutes( 30.0 ); + + public DecayedCorpse( string name ) : base( Utility.Random( 0xECA, 9 ) ) + { + Movable = false; + Name = name; + + BeginDecay( m_DefaultDecayTime ); + } + + public void BeginDecay( TimeSpan delay ) + { + if ( m_DecayTimer != null ) + m_DecayTimer.Stop(); + + m_DecayTime = DateTime.Now + delay; + + m_DecayTimer = new InternalTimer( this, delay ); + m_DecayTimer.Start(); + } + + public override void OnAfterDelete() + { + if ( m_DecayTimer != null ) + m_DecayTimer.Stop(); + + m_DecayTimer = null; + } + + private class InternalTimer : Timer + { + private DecayedCorpse m_Corpse; + + public InternalTimer( DecayedCorpse c, TimeSpan delay ) : base( delay ) + { + m_Corpse = c; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Corpse.Delete(); + } + } + + // Do not display (x items, y stones) + public override bool CheckContentDisplay( Mobile from ) + { + return false; + } + + // Do not display (x items, y stones) + public override bool DisplaysContent{ get{ return false; } } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1046414, Name ); // the remains of ~1_NAME~ + } + + public override void OnSingleClick( Mobile from ) + { + this.LabelTo( from, 1046414, Name ); // the remains of ~1_NAME~ + } + + public DecayedCorpse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_DecayTimer != null ); + + if ( m_DecayTimer != null ) + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + BeginDecay( m_DefaultDecayTime ); + + break; + } + case 1: + { + if ( reader.ReadBool() ) + BeginDecay( reader.ReadDeltaTime() - DateTime.Now ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Corpses/Packets.cs b/Scripts/Items/Misc/Corpses/Packets.cs new file mode 100644 index 0000000..91e6b7b --- /dev/null +++ b/Scripts/Items/Misc/Corpses/Packets.cs @@ -0,0 +1,201 @@ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Network +{ + public sealed class CorpseEquip : Packet + { + public CorpseEquip( Mobile beholder, Corpse beheld ) : base( 0x89 ) + { + List list = beheld.EquipItems; + + int count = list.Count; + if( beheld.Hair != null && beheld.Hair.ItemID > 0 ) + count++; + if( beheld.FacialHair != null && beheld.FacialHair.ItemID > 0 ) + count++; + + EnsureCapacity( 8 + (count * 5) ); + + m_Stream.Write( (int) beheld.Serial ); + + for ( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if ( !item.Deleted && beholder.CanSee( item ) && item.Parent == beheld ) + { + m_Stream.Write( (byte) (item.Layer + 1) ); + m_Stream.Write( (int) item.Serial ); + } + } + + if( beheld.Hair != null && beheld.Hair.ItemID > 0 ) + { + m_Stream.Write( (byte)(Layer.Hair + 1) ); + m_Stream.Write( (int)HairInfo.FakeSerial( beheld.Owner ) - 2 ); + } + + if( beheld.FacialHair != null && beheld.FacialHair.ItemID > 0 ) + { + m_Stream.Write( (byte)(Layer.FacialHair + 1) ); + m_Stream.Write( (int)FacialHairInfo.FakeSerial( beheld.Owner ) - 2 ); + } + + m_Stream.Write( (byte) Layer.Invalid ); + } + } + + public sealed class CorpseContent : Packet + { + public CorpseContent( Mobile beholder, Corpse beheld ) + : base( 0x3C ) + { + List items = beheld.EquipItems; + int count = items.Count; + + if( beheld.Hair != null && beheld.Hair.ItemID > 0 ) + count++; + if( beheld.FacialHair != null && beheld.FacialHair.ItemID > 0 ) + count++; + + EnsureCapacity( 5 + (count * 19) ); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write( (ushort)0 ); + + for( int i = 0; i < items.Count; ++i ) + { + Item child = items[i]; + + if( !child.Deleted && child.Parent == beheld && beholder.CanSee( child ) ) + { + m_Stream.Write( (int)child.Serial ); + m_Stream.Write( (ushort)child.ItemID ); + m_Stream.Write( (byte)0 ); // signed, itemID offset + m_Stream.Write( (ushort)child.Amount ); + m_Stream.Write( (short)child.X ); + m_Stream.Write( (short)child.Y ); + m_Stream.Write( (int)beheld.Serial ); + m_Stream.Write( (ushort)child.Hue ); + + ++written; + } + } + + if( beheld.Hair != null && beheld.Hair.ItemID > 0 ) + { + m_Stream.Write( (int)HairInfo.FakeSerial( beheld.Owner ) - 2 ); + m_Stream.Write( (ushort)beheld.Hair.ItemID ); + m_Stream.Write( (byte)0 ); // signed, itemID offset + m_Stream.Write( (ushort)1 ); + m_Stream.Write( (short)0 ); + m_Stream.Write( (short)0 ); + m_Stream.Write( (int)beheld.Serial ); + m_Stream.Write( (ushort)beheld.Hair.Hue ); + + ++written; + } + + if( beheld.FacialHair != null && beheld.FacialHair.ItemID > 0 ) + { + m_Stream.Write( (int)FacialHairInfo.FakeSerial( beheld.Owner ) - 2 ); + m_Stream.Write( (ushort)beheld.FacialHair.ItemID ); + m_Stream.Write( (byte)0 ); // signed, itemID offset + m_Stream.Write( (ushort)1 ); + m_Stream.Write( (short)0 ); + m_Stream.Write( (short)0 ); + m_Stream.Write( (int)beheld.Serial ); + m_Stream.Write( (ushort)beheld.FacialHair.Hue ); + + ++written; + } + + m_Stream.Seek( pos, SeekOrigin.Begin ); + m_Stream.Write( (ushort)written ); + } + } + + public sealed class CorpseContent6017 : Packet + { + public CorpseContent6017(Mobile beholder, Corpse beheld) + : base(0x3C) + { + List items = beheld.EquipItems; + int count = items.Count; + + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + count++; + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + count++; + + EnsureCapacity(5 + (count * 20)); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write((ushort)0); + + for (int i = 0; i < items.Count; ++i) + { + Item child = items[i]; + + if (!child.Deleted && child.Parent == beheld && beholder.CanSee(child)) + { + m_Stream.Write((int)child.Serial); + m_Stream.Write((ushort)child.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)child.Amount); + m_Stream.Write((short)child.X); + m_Stream.Write((short)child.Y); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write((int)beheld.Serial); + m_Stream.Write((ushort)child.Hue); + + ++written; + } + } + + if (beheld.Hair != null && beheld.Hair.ItemID > 0) + { + m_Stream.Write((int)HairInfo.FakeSerial(beheld.Owner) - 2); + m_Stream.Write((ushort)beheld.Hair.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)1); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write((int)beheld.Serial); + m_Stream.Write((ushort)beheld.Hair.Hue); + + ++written; + } + + if (beheld.FacialHair != null && beheld.FacialHair.ItemID > 0) + { + m_Stream.Write((int)FacialHairInfo.FakeSerial(beheld.Owner) - 2); + m_Stream.Write((ushort)beheld.FacialHair.ItemID); + m_Stream.Write((byte)0); // signed, itemID offset + m_Stream.Write((ushort)1); + m_Stream.Write((short)0); + m_Stream.Write((short)0); + m_Stream.Write((byte)0); // Grid Location? + m_Stream.Write((int)beheld.Serial); + m_Stream.Write((ushort)beheld.FacialHair.Hue); + + ++written; + } + + m_Stream.Seek(pos, SeekOrigin.Begin); + m_Stream.Write((ushort)written); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/DeceitBrazier.cs b/Scripts/Items/Misc/DeceitBrazier.cs new file mode 100644 index 0000000..b110ece --- /dev/null +++ b/Scripts/Items/Misc/DeceitBrazier.cs @@ -0,0 +1,226 @@ +using System; +using Server.Misc; +using Server.Network; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Items +{ + public class DeceitBrazier : Item + { + private static Type[] m_Creatures = new Type[] + { + #region Animals + typeof( FireSteed ), //Set the tents up people! + #endregion + + #region Undead + typeof( Skeleton ), typeof( SkeletalKnight ), typeof( SkeletalMage ), typeof( Mummy ), + typeof( BoneKnight ), typeof( Lich ), typeof( LichLord ), typeof( BoneMagi ), + typeof( Wraith ), typeof( Shade ), typeof( Spectre ), typeof( Zombie ), + typeof( RottingCorpse ), typeof( Ghoul ), + #endregion + + #region Demons + typeof( Balron ), typeof( Daemon ), typeof( Imp ), typeof( GreaterMongbat ), + typeof( Mongbat ), typeof( IceFiend ), typeof( Gargoyle ), typeof( StoneGargoyle ), + typeof( FireGargoyle ), typeof( HordeMinion ), + #endregion + + #region Gazers + typeof( Gazer ), typeof( ElderGazer ), typeof( GazerLarva ), + #endregion + + #region Uncategorized + typeof( Harpy ), typeof( StoneHarpy ), typeof( HeadlessOne ), typeof( HellHound ), + typeof( HellCat ), typeof( Phoenix ), typeof( LavaLizard ), typeof( SandVortex ), + typeof( ShadowWisp ), typeof( SwampTentacle ), typeof( PredatorHellCat ), typeof( Wisp ), + #endregion + + #region Arachnid + typeof( GiantSpider ), typeof( DreadSpider ), typeof( FrostSpider ), typeof( Scorpion ), + #endregion + + #region Repond + typeof( ArcticOgreLord ), typeof( Cyclops ), typeof( Ettin ), typeof( EvilMage ), + typeof( FrostTroll ), typeof( Ogre ), typeof( OgreLord ), typeof( Orc ), + typeof( OrcishLord ), typeof( OrcishMage ), typeof( OrcBrute ), typeof( Ratman ), + typeof( RatmanMage ), typeof( OrcCaptain ), typeof( Troll ), typeof( Titan ), + typeof( EvilMageLord ), typeof( OrcBomber ), typeof( RatmanArcher ), + #endregion + + #region Reptilian + typeof( Dragon ), typeof( Drake ), typeof( Snake ), typeof( GreaterDragon ), + typeof( IceSerpent ), typeof( GiantSerpent ), typeof( IceSnake ), typeof( LavaSerpent ), + typeof( Lizardman ), typeof( Wyvern ), typeof( WhiteWyrm ), + typeof( ShadowWyrm ), typeof( SilverSerpent ), typeof( LavaSnake ), + #endregion + + #region Elementals + typeof( EarthElemental ), typeof( PoisonElemental ), typeof( FireElemental ), typeof( SnowElemental ), + typeof( IceElemental ), typeof( AcidElemental ), typeof( WaterElemental ), typeof( Efreet ), + typeof( AirElemental ), typeof( Golem ), + #endregion + + #region Random Critters + typeof( Sewerrat ), typeof( GiantRat ), typeof( DireWolf ), typeof( TimberWolf ), + typeof( Cougar ), typeof( Alligator ) + #endregion + }; + + public static Type[] Creatures { get { return m_Creatures; } } + + private Timer m_Timer; + private DateTime m_NextSpawn; + private int m_SpawnRange; + private TimeSpan m_NextSpawnDelay; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextSpawn { get { return m_NextSpawn; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpawnRange { get { return m_SpawnRange; } set { m_SpawnRange = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan NextSpawnDelay { get { return m_NextSpawnDelay; } set { m_NextSpawnDelay = value; } } + + public override int LabelNumber { get { return 1023633; } } // Brazier + + [Constructable] + public DeceitBrazier() : base( 0xE31 ) + { + Movable = false; + Light = LightType.Circle225; + m_NextSpawn = DateTime.Now; + m_NextSpawnDelay = TimeSpan.FromMinutes( 15.0 ); + m_SpawnRange = 5; + } + + public DeceitBrazier( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (int)m_SpawnRange ); + writer.Write( m_NextSpawnDelay ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version >= 0 ) + { + m_SpawnRange = reader.ReadInt(); + m_NextSpawnDelay = reader.ReadTimeSpan(); + } + + m_NextSpawn = DateTime.Now; + } + + public virtual void HeedWarning() + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500761 );// Heed this warning well, and use this brazier at your own peril. + } + + public override bool HandlesOnMovement { get { return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if( m_NextSpawn < DateTime.Now ) // means we haven't spawned anything if the next spawn is below + { + if( Utility.InRange( m.Location, Location, 1 ) && !Utility.InRange( oldLocation, Location, 1 ) && m.Player && !(m.AccessLevel > AccessLevel.Player || m.Hidden) ) + { + if( m_Timer == null || !m_Timer.Running ) + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 2 ), new TimerCallback( HeedWarning ) ); + } + } + + base.OnMovement( m, oldLocation ); + } + + public Point3D GetSpawnPosition() + { + Map map = Map; + + if( map == null ) + return Location; + + // Try 10 times to find a Spawnable location. + for( int i = 0; i < 10; i++ ) + { + int x = Location.X + (Utility.Random( (m_SpawnRange * 2) + 1 ) - m_SpawnRange); + int y = Location.Y + (Utility.Random( (m_SpawnRange * 2) + 1 ) - m_SpawnRange); + int z = Map.GetAverageZ( x, y ); + + if( Map.CanSpawnMobile( new Point2D( x, y ), this.Z ) ) + return new Point3D( x, y, this.Z ); + else if( Map.CanSpawnMobile( new Point2D( x, y ), z ) ) + return new Point3D( x, y, z ); + } + + return this.Location; + } + + public virtual void DoEffect( Point3D loc, Map map ) + { + Effects.SendLocationParticles( EffectItem.Create( loc, map, EffectItem.DefaultDuration ), 0x3709, 10, 30, 5052 ); + Effects.PlaySound( loc, map, 0x225 ); + } + + public override void OnDoubleClick( Mobile from ) + { + if( Utility.InRange( from.Location, Location, 2 ) ) + { + try + { + if( m_NextSpawn < DateTime.Now ) + { + Map map = this.Map; + BaseCreature bc = (BaseCreature)Activator.CreateInstance( m_Creatures[Utility.Random( m_Creatures.Length )] ); + + if( bc != null ) + { + Point3D spawnLoc = GetSpawnPosition(); + + DoEffect( spawnLoc, map ); + + Timer.DelayCall( TimeSpan.FromSeconds( 1 ), delegate() + { + bc.Home = Location; + bc.RangeHome = m_SpawnRange; + bc.FightMode = FightMode.Closest; + + bc.MoveToWorld( spawnLoc, map ); + + DoEffect( spawnLoc, map ); + + bc.ForceReacquire(); + } ); + + m_NextSpawn = DateTime.Now + m_NextSpawnDelay; + } + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500760 ); // The brazier fizzes and pops, but nothing seems to happen. + } + } + catch + { + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/EffectController.cs b/Scripts/Items/Misc/EffectController.cs new file mode 100644 index 0000000..acc881c --- /dev/null +++ b/Scripts/Items/Misc/EffectController.cs @@ -0,0 +1,339 @@ +using System; + +namespace Server.Items +{ + public enum ECEffectType + { + None, + Moving, + Location, + Target, + Lightning + } + + public enum EffectTriggerType + { + None, + Sequenced, + DoubleClick, + InRange + } + + public class EffectController : Item + { + private TimeSpan m_EffectDelay; + + private ECEffectType m_EffectType; + private EffectTriggerType m_TriggerType; + + private IEntity m_Source; + private IEntity m_Target; + + private TimeSpan m_TriggerDelay; + private EffectController m_Trigger; + + private int m_ItemID; + private int m_Hue; + private int m_RenderMode; + + private int m_Speed; + private int m_Duration; + + private bool m_FixedDirection; + private bool m_Explodes; + + private int m_ParticleEffect; + private int m_ExplodeParticleEffect; + private int m_ExplodeSound; + + private EffectLayer m_EffectLayer; + private int m_Unknown; + + private TimeSpan m_SoundDelay; + private int m_SoundID; + private bool m_PlaySoundAtTrigger; + + private int m_TriggerRange; + + [CommandProperty( AccessLevel.GameMaster )] + public ECEffectType EffectType{ get{ return m_EffectType; } set{ m_EffectType = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public EffectTriggerType TriggerType{ get{ return m_TriggerType; } set{ m_TriggerType = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public EffectLayer EffectLayer{ get{ return m_EffectLayer; } set{ m_EffectLayer = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan EffectDelay{ get{ return m_EffectDelay; } set{ m_EffectDelay = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan TriggerDelay{ get{ return m_TriggerDelay; } set{ m_TriggerDelay = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan SoundDelay{ get{ return m_SoundDelay; } set{ m_SoundDelay = value; } } + + + [CommandProperty( AccessLevel.GameMaster )] + public Item SourceItem{ get{ return m_Source as Item; } set{ m_Source = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile SourceMobile{ get{ return m_Source as Mobile; } set{ m_Source = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SourceNull{ get{ return ( m_Source == null ); } set{ if ( value ) m_Source = null; } } + + + [CommandProperty( AccessLevel.GameMaster )] + public Item TargetItem{ get{ return m_Target as Item; } set{ m_Target = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile TargetMobile{ get{ return m_Target as Mobile; } set{ m_Target = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool TargetNull{ get{ return ( m_Target == null ); } set{ if ( value ) m_Target = null; } } + + + [CommandProperty( AccessLevel.GameMaster )] + public EffectController Sequence{ get{ return m_Trigger; } set{ m_Trigger = value; } } + + + [CommandProperty( AccessLevel.GameMaster )] + private bool FixedDirection{ get{ return m_FixedDirection; } set{ m_FixedDirection = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + private bool Explodes{ get{ return m_Explodes; } set{ m_Explodes = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + private bool PlaySoundAtTrigger{ get{ return m_PlaySoundAtTrigger; } set{ m_PlaySoundAtTrigger = value; } } + + + [CommandProperty( AccessLevel.GameMaster )] + public int EffectItemID{ get{ return m_ItemID; } set{ m_ItemID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int EffectHue{ get{ return m_Hue; } set{ m_Hue = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int RenderMode{ get{ return m_RenderMode; } set{ m_RenderMode = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Speed{ get{ return m_Speed; } set{ m_Speed = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Duration{ get{ return m_Duration; } set{ m_Duration = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ParticleEffect{ get{ return m_ParticleEffect; } set{ m_ParticleEffect = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ExplodeParticleEffect{ get{ return m_ExplodeParticleEffect; } set{ m_ExplodeParticleEffect = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ExplodeSound{ get{ return m_ExplodeSound; } set{ m_ExplodeSound = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Unknown{ get{ return m_Unknown; } set{ m_Unknown = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SoundID{ get{ return m_SoundID; } set{ m_SoundID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int TriggerRange{ get{ return m_TriggerRange; } set{ m_TriggerRange = value; } } + + public override string DefaultName + { + get { return "Effect Controller"; } + } + + [Constructable] + public EffectController() : base( 0x1B72 ) + { + Movable = false; + Visible = false; + m_TriggerType = EffectTriggerType.Sequenced; + m_EffectLayer = (EffectLayer)255; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_TriggerType == EffectTriggerType.DoubleClick ) + DoEffect( from ); + } + + public override bool HandlesOnMovement{ get{ return ( m_TriggerType == EffectTriggerType.InRange ); } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Location != oldLocation && m_TriggerType == EffectTriggerType.InRange && Utility.InRange( GetWorldLocation(), m.Location, m_TriggerRange ) && !Utility.InRange( GetWorldLocation(), oldLocation, m_TriggerRange ) ) + DoEffect( m ); + } + + public EffectController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_EffectDelay ); + writer.Write( m_TriggerDelay ); + writer.Write( m_SoundDelay ); + + if ( m_Source is Item ) + writer.Write( m_Source as Item ); + else + writer.Write( m_Source as Mobile ); + + if ( m_Target is Item ) + writer.Write( m_Target as Item ); + else + writer.Write( m_Target as Mobile ); + + writer.Write( m_Trigger as Item ); + + writer.Write( m_FixedDirection ); + writer.Write( m_Explodes ); + writer.Write( m_PlaySoundAtTrigger ); + + writer.WriteEncodedInt( (int) m_EffectType ); + writer.WriteEncodedInt( (int) m_EffectLayer ); + writer.WriteEncodedInt( (int) m_TriggerType ); + + writer.WriteEncodedInt( m_ItemID ); + writer.WriteEncodedInt( m_Hue ); + writer.WriteEncodedInt( m_RenderMode ); + writer.WriteEncodedInt( m_Speed ); + writer.WriteEncodedInt( m_Duration ); + writer.WriteEncodedInt( m_ParticleEffect ); + writer.WriteEncodedInt( m_ExplodeParticleEffect ); + writer.WriteEncodedInt( m_ExplodeSound ); + writer.WriteEncodedInt( m_Unknown ); + writer.WriteEncodedInt( m_SoundID ); + writer.WriteEncodedInt( m_TriggerRange ); + } + + private IEntity ReadEntity( GenericReader reader ) + { + return World.FindEntity( reader.ReadInt() ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_EffectDelay = reader.ReadTimeSpan(); + m_TriggerDelay = reader.ReadTimeSpan(); + m_SoundDelay = reader.ReadTimeSpan(); + + m_Source = ReadEntity( reader ); + m_Target = ReadEntity( reader ); + m_Trigger = reader.ReadItem() as EffectController; + + m_FixedDirection = reader.ReadBool(); + m_Explodes = reader.ReadBool(); + m_PlaySoundAtTrigger = reader.ReadBool(); + + m_EffectType = (ECEffectType)reader.ReadEncodedInt(); + m_EffectLayer = (EffectLayer)reader.ReadEncodedInt(); + m_TriggerType = (EffectTriggerType)reader.ReadEncodedInt(); + + m_ItemID = reader.ReadEncodedInt(); + m_Hue = reader.ReadEncodedInt(); + m_RenderMode = reader.ReadEncodedInt(); + m_Speed = reader.ReadEncodedInt(); + m_Duration = reader.ReadEncodedInt(); + m_ParticleEffect = reader.ReadEncodedInt(); + m_ExplodeParticleEffect = reader.ReadEncodedInt(); + m_ExplodeSound = reader.ReadEncodedInt(); + m_Unknown = reader.ReadEncodedInt(); + m_SoundID = reader.ReadEncodedInt(); + m_TriggerRange = reader.ReadEncodedInt(); + + break; + } + } + } + + public void PlaySound( object trigger ) + { + IEntity ent = null; + + if ( m_PlaySoundAtTrigger ) + ent = trigger as IEntity; + + if ( ent == null ) + ent = this; + + Effects.PlaySound( (ent is Item) ? ((Item)ent).GetWorldLocation() : ent.Location, ent.Map, m_SoundID ); + } + + public void DoEffect( object trigger ) + { + if ( Deleted || m_TriggerType == EffectTriggerType.None ) + return; + + if( trigger is Mobile && ((Mobile)trigger).Hidden && ((Mobile)trigger).AccessLevel > AccessLevel.Player ) + return; + + if ( m_SoundID > 0 ) + Timer.DelayCall( m_SoundDelay, new TimerStateCallback( PlaySound ), trigger ); + + if ( m_Trigger != null ) + Timer.DelayCall( m_TriggerDelay, new TimerStateCallback( m_Trigger.DoEffect ), trigger ); + + if ( m_EffectType != ECEffectType.None ) + Timer.DelayCall( m_EffectDelay, new TimerStateCallback( InternalDoEffect ), trigger ); + } + + public void InternalDoEffect( object trigger ) + { + IEntity from = m_Source, to = m_Target; + + if ( from == null ) + from = (IEntity)trigger; + + if ( to == null ) + to = (IEntity)trigger; + + switch ( m_EffectType ) + { + case ECEffectType.Lightning: + { + Effects.SendBoltEffect( from, false, m_Hue ); + break; + } + case ECEffectType.Location: + { + Effects.SendLocationParticles( EffectItem.Create( from.Location, from.Map, EffectItem.DefaultDuration ), m_ItemID, m_Speed, m_Duration, m_Hue, m_RenderMode, m_ParticleEffect, m_Unknown ); + break; + } + case ECEffectType.Moving: + { + if ( from == this ) + from = EffectItem.Create( from.Location, from.Map, EffectItem.DefaultDuration ); + + if ( to == this ) + to = EffectItem.Create( to.Location, to.Map, EffectItem.DefaultDuration ); + + Effects.SendMovingParticles( from, to, m_ItemID, m_Speed, m_Duration, m_FixedDirection, m_Explodes, m_Hue, m_RenderMode, m_ParticleEffect, m_ExplodeParticleEffect, m_ExplodeSound, m_EffectLayer, m_Unknown ); + break; + } + case ECEffectType.Target: + { + Effects.SendTargetParticles( from, m_ItemID, m_Speed, m_Duration, m_Hue, m_RenderMode, m_ParticleEffect, m_EffectLayer, m_Unknown ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/EffectItem.cs b/Scripts/Items/Misc/EffectItem.cs new file mode 100644 index 0000000..6028253 --- /dev/null +++ b/Scripts/Items/Misc/EffectItem.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections; +using Server; +using System.Collections.Generic; + +namespace Server.Items +{ + public class EffectItem : Item + { + private static List m_Free = new List(); // List of available EffectItems + + public static readonly TimeSpan DefaultDuration = TimeSpan.FromSeconds( 5.0 ); + + public static EffectItem Create( Point3D p, Map map, TimeSpan duration ) + { + EffectItem item = null; + + for ( int i = m_Free.Count - 1; item == null && i >= 0; --i ) // We reuse new entries first so decay works better + { + EffectItem free = m_Free[i]; + + m_Free.RemoveAt( i ); + + if ( !free.Deleted && free.Map == Map.Internal ) + item = free; + } + + if ( item == null ) + item = new EffectItem(); + else + item.ItemID = 1; + + item.MoveToWorld( p, map ); + item.BeginFree( duration ); + + return item; + } + + private EffectItem() : base( 1 ) // nodraw + { + Movable = false; + } + + public void BeginFree( TimeSpan duration ) + { + new FreeTimer( this, duration ).Start(); + } + + public override bool Decays + { + get + { + return true; + } + } + + public EffectItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + + private class FreeTimer : Timer + { + private EffectItem m_Item; + + public FreeTimer( EffectItem item, TimeSpan delay ) : base( delay ) + { + m_Item = item; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Item.Internalize(); + + m_Free.Add( m_Item ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/ExecutionersCap.cs b/Scripts/Items/Misc/ExecutionersCap.cs new file mode 100644 index 0000000..f2945f6 --- /dev/null +++ b/Scripts/Items/Misc/ExecutionersCap.cs @@ -0,0 +1,44 @@ +using System; + +namespace Server.Items +{ + // Scriptiz : on en fait un r�actif pour la n�cro + // public class ExecutionersCap : Item + public class ExecutionersCap : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} executioner's cap", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public ExecutionersCap() : base(0xF83) + { + Weight = 1.0; + } + + public ExecutionersCap(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Firebomb.cs b/Scripts/Items/Misc/Firebomb.cs new file mode 100644 index 0000000..1a4b547 --- /dev/null +++ b/Scripts/Items/Misc/Firebomb.cs @@ -0,0 +1,317 @@ +using Server.Network; +using Server.Spells; +using Server.Targeting; +using System; +using System.Collections.Generic; + +namespace Server.Items +{ + public class Firebomb : Item + { + private Timer m_Timer; + private int m_Ticks = 0; + private Mobile m_LitBy; + private List m_Users; + + [Constructable] + public Firebomb() + : this(0x99B) + { + } + + [Constructable] + public Firebomb(int itemID) + : base(itemID) + { + //Name = "a firebomb"; + Weight = 2.0; + Hue = 1260; + } + + public Firebomb(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + return; + } + + if (Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting))) + { + // to prevent exploiting for pvp + from.SendLocalizedMessage(1075857); // You cannot use that while paralyzed. + return; + } + + if (m_Timer == null) + { + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), new TimerCallback(OnFirebombTimerTick)); + m_LitBy = from; + from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now! + } + else + from.SendLocalizedMessage(1060581); // You've already lit it! Better throw it now! + + if (m_Users == null) + m_Users = new List(); + + if (!m_Users.Contains(from)) + m_Users.Add(from); + + from.Target = new ThrowTarget(this); + } + + private void OnFirebombTimerTick() + { + if (Deleted) + { + m_Timer.Stop(); + return; + } + + if (Map == Map.Internal && HeldBy == null) + return; + + switch (m_Ticks) + { + case 0: + case 1: + case 2: + { + ++m_Ticks; + + if (HeldBy != null) + HeldBy.PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString()); + else if (RootParent == null) + PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString()); + else if (RootParent is Mobile) + ((Mobile)RootParent).PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString()); + + break; + } + default: + { + if (HeldBy != null) + HeldBy.DropHolding(); + + if (m_Users != null) + { + foreach (Mobile m in m_Users) + { + ThrowTarget targ = m.Target as ThrowTarget; + + if (targ != null && targ.Bomb == this) + Target.Cancel(m); + } + + m_Users.Clear(); + m_Users = null; + } + + if (RootParent is Mobile) + { + Mobile parent = (Mobile)RootParent; + parent.SendLocalizedMessage(1060583); // The firebomb explodes in your hand! + AOS.Damage(parent, Utility.Random(3) + 4, 0, 100, 0, 0, 0); + } + else if (RootParent == null) + { + List toDamage = new List(); + IPooledEnumerable eable = Map.GetMobilesInRange(Location, 1); + + foreach (Mobile m in eable) + { + toDamage.Add(m); + } + eable.Free(); + + Mobile victim; + for (int i = 0; i < toDamage.Count; ++i) + { + victim = toDamage[i]; + + if (m_LitBy == null || (SpellHelper.ValidIndirectTarget(m_LitBy, victim) && m_LitBy.CanBeHarmful(victim, false))) + { + if (m_LitBy != null) + m_LitBy.DoHarmful(victim); + + AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0); + } + } + (new FirebombField(m_LitBy, toDamage)).MoveToWorld(Location, Map); + } + + m_Timer.Stop(); + Delete(); + break; + } + } + } + + private void OnFirebombTarget(Mobile from, object obj) + { + if (Deleted || Map == Map.Internal || !IsChildOf(from.Backpack)) + return; + + IPoint3D p = obj as IPoint3D; + + if (p == null) + return; + + SpellHelper.GetSurfaceTop(ref p); + + from.RevealingAction(); + + IEntity to; + + if (p is Mobile) + to = (Mobile)p; + else + to = new Entity(Serial.Zero, new Point3D(p), Map); + + Effects.SendMovingEffect(from, to, ItemID, 7, 0, false, false, Hue, 0); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(FirebombReposition_OnTick), new object[] { p, Map }); + Internalize(); + } + + private void FirebombReposition_OnTick(object state) + { + if (Deleted) + return; + + object[] states = (object[])state; + IPoint3D p = (IPoint3D)states[0]; + Map map = (Map)states[1]; + + MoveToWorld(new Point3D(p), map); + } + + private class ThrowTarget : Target + { + private Firebomb m_Bomb; + + public Firebomb Bomb + { + get { return m_Bomb; } + } + + public ThrowTarget(Firebomb bomb) + : base(12, true, TargetFlags.None) + { + m_Bomb = bomb; + } + + protected override void OnTarget(Mobile from, object targeted) + { + m_Bomb.OnFirebombTarget(from, targeted); + } + } + } + + public class FirebombField : Item + { + private List m_Burning; + private Timer m_Timer; + private Mobile m_LitBy; + private DateTime m_Expire; + + public FirebombField(Mobile litBy, List toDamage) + : base(0x376A) + { + Movable = false; + m_LitBy = litBy; + m_Expire = DateTime.Now + TimeSpan.FromSeconds(10); + m_Burning = toDamage; + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), new TimerCallback(OnFirebombFieldTimerTick)); + } + + public FirebombField(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + // Don't serialize these... + } + + public override void Deserialize(GenericReader reader) + { + } + + public override bool OnMoveOver(Mobile m) + { + if (ItemID == 0x398C && m_LitBy == null || (SpellHelper.ValidIndirectTarget(m_LitBy, m) && m_LitBy.CanBeHarmful(m, false))) + { + if (m_LitBy != null) + m_LitBy.DoHarmful(m); + + AOS.Damage(m, m_LitBy, 2, 0, 100, 0, 0, 0); + m.PlaySound(0x208); + + if (!m_Burning.Contains(m)) + m_Burning.Add(m); + } + + return true; + } + + private void OnFirebombFieldTimerTick() + { + if (Deleted) + { + m_Timer.Stop(); + return; + } + + if (ItemID == 0x376A) + { + ItemID = 0x398C; + return; + } + + Mobile victim; + for (int i = 0; i < m_Burning.Count; ) + { + victim = m_Burning[i]; + + if (victim.Location == Location && victim.Map == Map && (m_LitBy == null || (SpellHelper.ValidIndirectTarget(m_LitBy, victim) && m_LitBy.CanBeHarmful(victim, false)))) + { + if (m_LitBy != null) + m_LitBy.DoHarmful(victim); + + AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0); + ++i; + } + else + m_Burning.RemoveAt(i); + } + + if (DateTime.Now >= m_Expire) + { + m_Timer.Stop(); + Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/FlipableAddonAttribute.cs b/Scripts/Items/Misc/FlipableAddonAttribute.cs new file mode 100644 index 0000000..8d7d1df --- /dev/null +++ b/Scripts/Items/Misc/FlipableAddonAttribute.cs @@ -0,0 +1,130 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using Server.Multis; + +namespace Server.Items +{ + [AttributeUsage( AttributeTargets.Class )] + public class FlipableAddonAttribute : Attribute + { + private static string m_MethodName = "Flip"; + + private static Type[] m_Params = new Type[] + { + typeof( Mobile ), typeof( Direction ) + }; + + private Direction[] m_Directions; + + public Direction[] Directions + { + get { return m_Directions; } + } + + public FlipableAddonAttribute( params Direction[] directions ) + { + m_Directions = directions; + } + + public virtual void Flip( Mobile from, Item addon ) + { + if ( m_Directions != null && m_Directions.Length > 1 ) + { + try + { + MethodInfo flipMethod = addon.GetType().GetMethod( m_MethodName, m_Params ); + + if ( flipMethod != null ) + { + int index = 0; + + for ( int i = 0; i < m_Directions.Length; i++ ) + { + if ( addon.Direction == m_Directions[ i ] ) + { + index = i + 1; + break; + } + } + + if ( index >= m_Directions.Length ) + index = 0; + + ClearComponents( addon ); + + flipMethod.Invoke( addon, new object[ 2 ] { from, m_Directions[ index ] } ); + + BaseHouse house = null; + AddonFitResult result = AddonFitResult.Valid; + + addon.Map = Map.Internal; + + if ( addon is BaseAddon ) + result = ( (BaseAddon) addon ).CouldFit( addon.Location, from.Map, from, ref house ); + else if ( addon is BaseAddonContainer ) + result = ( (BaseAddonContainer) addon ).CouldFit( addon.Location, from.Map, from, ref house ); + + addon.Map = from.Map; + + if ( result != AddonFitResult.Valid ) + { + if ( index == 0 ) + index = m_Directions.Length - 1; + else + index -= 1; + + ClearComponents( addon ); + + flipMethod.Invoke( addon, new object[ 2 ] { from, m_Directions[ index ] } ); + + if ( result == AddonFitResult.Blocked ) + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + else if ( result == AddonFitResult.NotInHouse ) + from.SendLocalizedMessage( 500274 ); // You can only place this in a house that you own! + else if ( result == AddonFitResult.DoorsNotClosed ) + from.SendMessage( "You must close all house doors before placing this." ); + else if ( result == AddonFitResult.DoorTooClose ) + from.SendLocalizedMessage( 500271 ); // You cannot build near the door. + else if ( result == AddonFitResult.NoWall ) + from.SendLocalizedMessage( 500268 ); // This object needs to be mounted on something. + } + + addon.Direction = m_Directions[ index ]; + } + } + catch + { + } + } + } + + private void ClearComponents( Item item ) + { + if ( item is BaseAddon ) + { + BaseAddon addon = (BaseAddon) item; + + foreach ( AddonComponent c in addon.Components ) + { + c.Addon = null; + c.Delete(); + } + + addon.Components.Clear(); + } + else if ( item is BaseAddonContainer ) + { + BaseAddonContainer addon = (BaseAddonContainer) item; + + foreach ( AddonContainerComponent c in addon.Components ) + { + c.Addon = null; + c.Delete(); + } + + addon.Components.Clear(); + } + } + } +} diff --git a/Scripts/Items/Misc/FlipableAttribute.cs b/Scripts/Items/Misc/FlipableAttribute.cs new file mode 100644 index 0000000..116e366 --- /dev/null +++ b/Scripts/Items/Misc/FlipableAttribute.cs @@ -0,0 +1,118 @@ +using System; +using Server; +using System.Reflection; +using Server.Targeting; +using Server.Commands; + +namespace Server.Items +{ + public class FlipCommandHandlers + { + public static void Initialize() + { + CommandSystem.Register( "Flip", AccessLevel.GameMaster, new CommandEventHandler( Flip_OnCommand ) ); + } + + [Usage( "Flip" )] + [Description( "Turns an item." )] + public static void Flip_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new FlipTarget(); + } + + private class FlipTarget : Target + { + public FlipTarget() + : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if( targeted is Item ) + { + Item item = (Item)targeted; + + if( item.Movable == false && from.AccessLevel == AccessLevel.Player ) + return; + + Type type = targeted.GetType(); + + FlipableAttribute[] AttributeArray = (FlipableAttribute[])type.GetCustomAttributes( typeof( FlipableAttribute ), false ); + + if( AttributeArray.Length == 0 ) + { + return; + } + + FlipableAttribute fa = AttributeArray[0]; + + fa.Flip( (Item)targeted ); + } + } + } + } + + [AttributeUsage( AttributeTargets.Class )] + public class DynamicFlipingAttribute : Attribute + { + public DynamicFlipingAttribute() + { + } + } + + [AttributeUsage( AttributeTargets.Class )] + public class FlipableAttribute : Attribute + { + private int[] m_ItemIDs; + + public int[] ItemIDs + { + get { return m_ItemIDs; } + } + + public FlipableAttribute() + : this( null ) + { + } + + public FlipableAttribute( params int[] itemIDs ) + { + m_ItemIDs = itemIDs; + } + + public virtual void Flip( Item item ) + { + if( m_ItemIDs == null ) + { + try + { + MethodInfo flipMethod = item.GetType().GetMethod( "Flip", Type.EmptyTypes ); + if( flipMethod != null ) + flipMethod.Invoke( item, new object[0] ); + } + catch + { + } + + } + else + { + int index = 0; + for( int i = 0; i < m_ItemIDs.Length; i++ ) + { + if( item.ItemID == m_ItemIDs[i] ) + { + index = i + 1; + break; + } + } + + if( index > m_ItemIDs.Length - 1 ) + index = 0; + + item.ItemID = m_ItemIDs[index]; + } + } + } +} diff --git a/Scripts/Items/Misc/GlassItems.cs b/Scripts/Items/Misc/GlassItems.cs new file mode 100644 index 0000000..4778489 --- /dev/null +++ b/Scripts/Items/Misc/GlassItems.cs @@ -0,0 +1,1190 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x182E, 0x182F, 0x1830, 0x1831 )] + public class SmallFlask : Item + { + [Constructable] + public SmallFlask() : base( 0x182E ) + { + Weight = 1.0; + Movable = true; + } + + public SmallFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x182A, 0x182B, 0x182C, 0x182D )] + public class MediumFlask : Item + { + [Constructable] + public MediumFlask() : base( 0x182A ) + { + Weight = 1.0; + Movable = true; + } + + public MediumFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x183B, 0x183C, 0x183D )] + public class LargeFlask : Item + { + [Constructable] + public LargeFlask() : base( 0x183B ) + { + Weight = 1.0; + Movable = true; + } + + public LargeFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837 )] + public class CurvedFlask : Item + { + [Constructable] + public CurvedFlask() : base( 0x1832 ) + { + Weight = 1.0; + Movable = true; + } + + public CurvedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1838, 0x1839, 0x183A )] + public class LongFlask : Item + { + [Constructable] + public LongFlask() : base( 0x1838 ) + { + Weight = 1.0; + Movable = true; + } + + public LongFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x1810, 0x1811 )] + public class SpinningHourglass : Item + { + [Constructable] + public SpinningHourglass() : base( 0x1810 ) + { + Weight = 1.0; + Movable = true; + } + + public SpinningHourglass( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenBottle : Item + { + [Constructable] + public GreenBottle() : base( 0x0EFB ) + { + Weight = 1.0; + Movable = true; + } + + public GreenBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RedBottle : Item + { + [Constructable] + public RedBottle() : base( 0x0EFC ) + { + Weight = 1.0; + Movable = true; + } + + public RedBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallBrownBottle : Item + { + [Constructable] + public SmallBrownBottle() : base( 0x0EFD ) + { + Weight = 1.0; + Movable = true; + } + + public SmallBrownBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallGreenBottle : Item + { + [Constructable] + public SmallGreenBottle() : base( 0x0F01 ) + { + Weight = 1.0; + Movable = true; + } + + public SmallGreenBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallVioletBottle : Item + { + [Constructable] + public SmallVioletBottle() : base( 0x0F02 ) + { + Weight = 1.0; + Movable = true; + } + + public SmallVioletBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TinyYellowBottle : Item + { + [Constructable] + public TinyYellowBottle() : base( 0x0F03 ) + { + Weight = 1.0; + Movable = true; + } + + public TinyYellowBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + //remove + public class SmallBlueFlask : Item + { + [Constructable] + public SmallBlueFlask() : base( 0x182A ) + { + Weight = 1.0; + Movable = true; + } + + public SmallBlueFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallYellowFlask : Item + { + [Constructable] + public SmallYellowFlask() : base( 0x182B ) + { + Weight = 1.0; + Movable = true; + } + + public SmallYellowFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallRedFlask : Item + { + [Constructable] + public SmallRedFlask() : base( 0x182C ) + { + Weight = 1.0; + Movable = true; + } + + public SmallRedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallEmptyFlask : Item + { + [Constructable] + public SmallEmptyFlask() : base( 0x182D ) + { + Weight = 1.0; + Movable = true; + } + + public SmallEmptyFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class YellowBeaker : Item + { + [Constructable] + public YellowBeaker() : base( 0x182E ) + { + Weight = 1.0; + Movable = true; + } + + public YellowBeaker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RedBeaker : Item + { + [Constructable] + public RedBeaker() : base( 0x182F ) + { + Weight = 1.0; + Movable = true; + } + + public RedBeaker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BlueBeaker : Item + { + [Constructable] + public BlueBeaker() : base( 0x1830 ) + { + Weight = 1.0; + Movable = true; + } + + public BlueBeaker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenBeaker : Item + { + [Constructable] + public GreenBeaker() : base( 0x1831 ) + { + Weight = 1.0; + Movable = true; + } + + public GreenBeaker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EmptyCurvedFlaskW : Item + { + [Constructable] + public EmptyCurvedFlaskW() : base( 0x1832 ) + { + Weight = 1.0; + Movable = true; + } + + public EmptyCurvedFlaskW( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RedCurvedFlask : Item + { + [Constructable] + public RedCurvedFlask() : base( 0x1833 ) + { + Weight = 1.0; + Movable = true; + } + + public RedCurvedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LtBlueCurvedFlask : Item + { + [Constructable] + public LtBlueCurvedFlask() : base( 0x1834 ) + { + Weight = 1.0; + Movable = true; + } + + public LtBlueCurvedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EmptyCurvedFlaskE : Item + { + [Constructable] + public EmptyCurvedFlaskE() : base( 0x1835 ) + { + Weight = 1.0; + Movable = true; + } + + public EmptyCurvedFlaskE( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BlueCurvedFlask : Item + { + [Constructable] + public BlueCurvedFlask() : base( 0x1836 ) + { + Weight = 1.0; + Movable = true; + } + + public BlueCurvedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenCurvedFlask : Item + { + [Constructable] + public GreenCurvedFlask() : base( 0x1837 ) + { + Weight = 1.0; + Movable = true; + } + + public GreenCurvedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RedRibbedFlask : Item + { + [Constructable] + public RedRibbedFlask() : base( 0x1838 ) + { + Weight = 1.0; + Movable = true; + } + + public RedRibbedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class VioletRibbedFlask : Item + { + [Constructable] + public VioletRibbedFlask() : base( 0x1839 ) + { + Weight = 1.0; + Movable = true; + } + + public VioletRibbedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EmptyRibbedFlask : Item + { + [Constructable] + public EmptyRibbedFlask() : base( 0x183A ) + { + Weight = 1.0; + Movable = true; + } + + public EmptyRibbedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeYellowFlask : Item + { + [Constructable] + public LargeYellowFlask() : base( 0x183B ) + { + Weight = 1.0; + Movable = true; + } + + public LargeYellowFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeVioletFlask : Item + { + [Constructable] + public LargeVioletFlask() : base( 0x183C ) + { + Weight = 1.0; + Movable = true; + } + + public LargeVioletFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeEmptyFlask : Item + { + [Constructable] + public LargeEmptyFlask() : base( 0x183D ) + { + Weight = 1.0; + Movable = true; + } + + public LargeEmptyFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AniRedRibbedFlask : Item + { + [Constructable] + public AniRedRibbedFlask() : base( 0x183E ) + { + Weight = 1.0; + Movable = true; + } + + public AniRedRibbedFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AniLargeVioletFlask : Item + { + [Constructable] + public AniLargeVioletFlask() : base( 0x1841 ) + { + Weight = 1.0; + Movable = true; + } + + public AniLargeVioletFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AniSmallBlueFlask : Item + { + [Constructable] + public AniSmallBlueFlask() : base( 0x1844 ) + { + Weight = 1.0; + Movable = true; + } + + public AniSmallBlueFlask( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallBlueBottle : Item + { + [Constructable] + public SmallBlueBottle() : base( 0x1847 ) + { + Weight = 1.0; + Movable = true; + } + + public SmallBlueBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallGreenBottle2 : Item + { + [Constructable] + public SmallGreenBottle2() : base( 0x1848 ) + { + Weight = 1.0; + Movable = true; + } + + public SmallGreenBottle2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x185B, 0x185C )] + public class EmptyVialsWRack : Item + { + [Constructable] + public EmptyVialsWRack() : base( 0x185B ) + { + Weight = 1.0; + Movable = true; + } + + public EmptyVialsWRack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x185D, 0x185E )] + public class FullVialsWRack : Item + { + [Constructable] + public FullVialsWRack() : base( 0x185D ) + { + Weight = 1.0; + Movable = true; + } + + public FullVialsWRack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class HourglassAni : Item + { + [Constructable] + public HourglassAni() : base( 0x1811 ) + { + Weight = 1.0; + Movable = true; + } + + public HourglassAni( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Hourglass : Item + { + [Constructable] + public Hourglass() : base( 0x1810 ) + { + Weight = 1.0; + Movable = true; + } + + public Hourglass( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TinyRedBottle : Item + { + [Constructable] + public TinyRedBottle() : base( 0x0F04 ) + { + Weight = 1.0; + Movable = true; + } + + public TinyRedBottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Gold.cs b/Scripts/Items/Misc/Gold.cs new file mode 100644 index 0000000..743c38d --- /dev/null +++ b/Scripts/Items/Misc/Gold.cs @@ -0,0 +1,76 @@ +using System; + +namespace Server.Items +{ + public class Gold : Item + { + public override double DefaultWeight + { + get { return ( Core.ML ? ( 0.02 / 3 ) : 0.02 ); } + } + + [Constructable] + public Gold() : this( 1 ) + { + } + + [Constructable] + public Gold( int amountFrom, int amountTo ) : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Gold( int amount ) : base( 0xEED ) + { + Stackable = true; + Amount = amount; + } + + public Gold( Serial serial ) : base( serial ) + { + } + + public override int GetDropSound() + { + if ( Amount <= 1 ) + return 0x2E4; + else if ( Amount <= 5 ) + return 0x2E5; + else + return 0x2E6; + } + + protected override void OnAmountChange( int oldValue ) + { + int newValue = this.Amount; + + UpdateTotal( this, TotalType.Gold, newValue - oldValue ); + } + + public override int GetTotal( TotalType type ) + { + int baseTotal = base.GetTotal( type ); + + if ( type == TotalType.Gold ) + baseTotal += this.Amount; + + return baseTotal; + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Guillotine.cs b/Scripts/Items/Misc/Guillotine.cs new file mode 100644 index 0000000..be3ab73 --- /dev/null +++ b/Scripts/Items/Misc/Guillotine.cs @@ -0,0 +1,115 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class Guillotine : Item + { + [Constructable] + public Guillotine() + : base( 4656 ) + { + Movable = false; + } + + private DateTime m_NextUse; + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) || !from.InLOS( this ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that + } + else if ( Visible && ( ItemID == 4656 || ItemID == 4702 ) && DateTime.Now >= m_NextUse ) + { + Point3D p = this.GetWorldLocation(); + + if ( 1 > Utility.Random( Math.Max( Math.Abs( from.X - p.X ), Math.Abs( from.Y - p.Y ) ) ) ) + { + Effects.PlaySound( from.Location, from.Map, from.GetHurtSound() ); + from.PublicOverheadMessage( MessageType.Regular, from.SpeechHue, true, "Ouch!" ); + Spells.SpellHelper.Damage( TimeSpan.FromSeconds( 0.5 ), from, Utility.Dice( 2, 10, 5 ) ); + } + + Effects.PlaySound( this.GetWorldLocation(), this.Map, 0x387 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 0.25 ), new TimerCallback( Down1 ) ); + Timer.DelayCall( TimeSpan.FromSeconds( 0.50 ), new TimerCallback( Down2 ) ); + + Timer.DelayCall( TimeSpan.FromSeconds( 5.00 ), new TimerCallback( BackUp ) ); + + m_NextUse = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + } + } + + private void Down1() + { + ItemID = ( ItemID == 4656 ? 4678 : 4712 ); + } + + private void Down2() + { + ItemID = ( ItemID == 4678 ? 4679 : 4713 ); + + Point3D p = this.GetWorldLocation(); + Map f = this.Map; + + if ( f == null ) + return; + + new Blood( 4650 ).MoveToWorld( p, f ); + + for ( int i = 0; i < 4; ++i ) + { + int x = p.X - 2 + Utility.Random( 5 ); + int y = p.Y - 2 + Utility.Random( 5 ); + int z = p.Z; + + if ( !f.CanFit( x, y, z, 1, false, false, true ) ) + { + z = f.GetAverageZ( x, y ); + + if ( !f.CanFit( x, y, z, 1, false, false, true ) ) + continue; + } + + new Blood().MoveToWorld( new Point3D( x, y, z ), f ); + } + } + + private void BackUp() + { + if ( ItemID == 4678 || ItemID == 4679 ) + ItemID = 4656; + else if ( ItemID == 4712 || ItemID == 4713 ) + ItemID = 4702; + } + + public Guillotine( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + + if ( ItemID == 4678 || ItemID == 4679 ) + ItemID = 4656; + else if ( ItemID == 4712 || ItemID == 4713 ) + ItemID = 4702; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/HairDye.cs b/Scripts/Items/Misc/HairDye.cs new file mode 100644 index 0000000..87a97e0 --- /dev/null +++ b/Scripts/Items/Misc/HairDye.cs @@ -0,0 +1,193 @@ +using System; +using System.Text; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HairDye : Item + { + public override int LabelNumber{ get{ return 1041060; } } // Hair Dye + + [Constructable] + public HairDye() : base( 0xEFF ) + { + Weight = 1.0; + } + + public HairDye( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + from.CloseGump( typeof( HairDyeGump ) ); + from.SendGump( new HairDyeGump( this ) ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 906, 1019045 ); // I can't reach that. + } + } + } + + public class HairDyeGump : Gump + { + private HairDye m_HairDye; + + private class HairDyeEntry + { + private string m_Name; + private int m_HueStart; + private int m_HueCount; + + public string Name + { + get + { + return m_Name; + } + } + + public int HueStart + { + get + { + return m_HueStart; + } + } + + public int HueCount + { + get + { + return m_HueCount; + } + } + + public HairDyeEntry( string name, int hueStart, int hueCount ) + { + m_Name = name; + m_HueStart = hueStart; + m_HueCount = hueCount; + } + } + + private static HairDyeEntry[] m_Entries = new HairDyeEntry[] + { + new HairDyeEntry( "*****", 1602, 26 ), + new HairDyeEntry( "*****", 1628, 27 ), + new HairDyeEntry( "*****", 1502, 32 ), + new HairDyeEntry( "*****", 1302, 32 ), + new HairDyeEntry( "*****", 1402, 32 ), + new HairDyeEntry( "*****", 1202, 24 ), + new HairDyeEntry( "*****", 2402, 29 ), + new HairDyeEntry( "*****", 2213, 6 ), + new HairDyeEntry( "*****", 1102, 8 ), + new HairDyeEntry( "*****", 1110, 8 ), + new HairDyeEntry( "*****", 1118, 16 ), + new HairDyeEntry( "*****", 1134, 16 ) + }; + + public HairDyeGump( HairDye dye ) : base( 50, 50 ) + { + m_HairDye = dye; + + AddPage( 0 ); + + AddBackground( 100, 10, 350, 355, 2600 ); + AddBackground( 120, 54, 110, 270, 5100 ); + + AddHtmlLocalized( 70, 25, 400, 35, 1011013, false, false ); //
Hair Color Selection Menu
+ + AddButton( 149, 328, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 185, 329, 250, 35, 1011014, false, false ); // Dye my hair this color! + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + AddLabel( 130, 59 + (i * 22), m_Entries[i].HueStart - 1, m_Entries[i].Name ); + AddButton( 207, 60 + (i * 22), 5224, 5224, 0, GumpButtonType.Page, i + 1 ); + } + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + HairDyeEntry e = m_Entries[i]; + + AddPage( i + 1 ); + + for ( int j = 0; j < e.HueCount; ++j ) + { + AddLabel( 278 + ((j / 16) * 80), 52 + ((j % 16) * 17), e.HueStart + j - 1, "*****" ); + AddRadio( 260 + ((j / 16) * 80), 52 + ((j % 16) * 17), 210, 211, false, (i * 100) + j ); + } + } + } + + public override void OnResponse( NetState from, RelayInfo info ) + { + if ( m_HairDye.Deleted ) + return; + + Mobile m = from.Mobile; + int[] switches = info.Switches; + + if ( !m_HairDye.IsChildOf( m.Backpack ) ) + { + m.SendLocalizedMessage( 1042010 ); //You must have the objectin your backpack to use it. + return; + } + + if ( info.ButtonID != 0 && switches.Length > 0 ) + { + if( m.HairItemID == 0 && m.FacialHairItemID == 0 ) + { + m.SendLocalizedMessage( 502623 ); // You have no hair to dye and cannot use this + } + else + { + // To prevent this from being exploited, the hue is abstracted into an internal list + + int entryIndex = switches[0] / 100; + int hueOffset = switches[0] % 100; + + if ( entryIndex >= 0 && entryIndex < m_Entries.Length ) + { + HairDyeEntry e = m_Entries[entryIndex]; + + if ( hueOffset >= 0 && hueOffset < e.HueCount ) + { + int hue = e.HueStart + hueOffset; + + m.HairHue = hue; + m.FacialHairHue = hue; + + m.SendLocalizedMessage( 501199 ); // You dye your hair + m_HairDye.Delete(); + m.PlaySound( 0x4E ); + } + } + } + } + else + { + m.SendLocalizedMessage( 501200 ); // You decide not to dye your hair + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/HoveringWisp.cs b/Scripts/Items/Misc/HoveringWisp.cs new file mode 100644 index 0000000..c1febb8 --- /dev/null +++ b/Scripts/Items/Misc/HoveringWisp.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HoveringWisp : Item + { + public override int LabelNumber{ get{ return 1072881; } } // hovering wisp + + [Constructable] + public HoveringWisp() : base( 0x2100 ) + { + } + + public HoveringWisp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/IDurability.cs b/Scripts/Items/Misc/IDurability.cs new file mode 100644 index 0000000..cf16cf7 --- /dev/null +++ b/Scripts/Items/Misc/IDurability.cs @@ -0,0 +1,24 @@ +using System; +using Server; + +namespace Server.Items +{ + interface IDurability + { + bool CanFortify { get; } + + int InitMinHits { get; } + int InitMaxHits { get; } + + int HitPoints { get; set; } + int MaxHitPoints { get; set; } + + void ScaleDurability(); + void UnscaleDurability(); + } + + interface IWearableDurability : IDurability + { + int OnHit( BaseWeapon weapon, int damageTaken ); + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/InteriorDecorator.cs b/Scripts/Items/Misc/InteriorDecorator.cs new file mode 100644 index 0000000..884ea54 --- /dev/null +++ b/Scripts/Items/Misc/InteriorDecorator.cs @@ -0,0 +1,391 @@ +using System; +using Server; +using Server.Network; +using Server.Regions; +using Server.Multis; +using Server.Gumps; +using Server.Targeting; + +namespace Server.Items +{ + public enum DecorateCommand + { + None, + Turn, + Up, + Down, + // Scriptiz : on ajoute des fl�ches pour faire glisser + West, + North, + East, + South + } + + public class InteriorDecorator : Item + { + private DecorateCommand m_Command; + + [CommandProperty(AccessLevel.GameMaster)] + public DecorateCommand Command { get { return m_Command; } set { m_Command = value; InvalidateProperties(); } } + + [Constructable] + public InteriorDecorator() + : base(0xFC1) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public override int LabelNumber { get { return 1041280; } } // an interior decorator + + public InteriorDecorator(Serial serial) + : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + // Scriptiz : Source de probl�mes � cause des nouvelles commandes + //if (m_Command != DecorateCommand.None) + // list.Add(1018322 + (int)m_Command); // Turn/Up/Down + + // Scriptiz : Gestion des anciennes et nouvelles commandes + if (m_Command >= DecorateCommand.None) + list.Add(m_Command.ToString()); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!CheckUse(this, from)) + return; + + if (from.FindGump(typeof(InteriorDecorator.InternalGump)) == null) + from.SendGump(new InternalGump(this)); + + if (m_Command != DecorateCommand.None) + from.Target = new InternalTarget(this); + } + + public static bool InHouse(Mobile from) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + + return (house != null && house.IsCoOwner(from)); + } + + public static bool CheckUse(InteriorDecorator tool, Mobile from) + { + /*if ( tool.Deleted || !tool.IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + else*/ + if (!InHouse(from)) + from.SendLocalizedMessage(502092); // You must be in your house to do this. + else + return true; + + return false; + } + + private class InternalGump : Gump + { + private InteriorDecorator m_Decorator; + + public InternalGump(InteriorDecorator decorator) + : base(150, 50) + { + m_Decorator = decorator; + + AddBackground(0, 0, 200, 330, 2600); // Scriptiz : default height is 200, increased for arrows + + AddButton(50, 45, (decorator.Command == DecorateCommand.Turn ? 2154 : 2152), 2154, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(90, 50, 70, 40, 1018323, false, false); // Turn + + AddButton(50, 95, (decorator.Command == DecorateCommand.Up ? 2154 : 2152), 2154, 2, GumpButtonType.Reply, 0); + AddHtmlLocalized(90, 100, 70, 40, 1018324, false, false); // Up + + AddButton(50, 145, (decorator.Command == DecorateCommand.Down ? 2154 : 2152), 2154, 3, GumpButtonType.Reply, 0); + AddHtmlLocalized(90, 150, 70, 40, 1018325, false, false); // Down + + // Scriptiz : ajout du bouton pour faire glisser un objet vers l'ouest (10) + if (decorator.Command == DecorateCommand.West) + AddImage(40, 180, 4507, 35); + else + AddButton(40, 180, 4507, 4507, 10, GumpButtonType.Reply, 0); + + // Scriptiz : ajout du bouton pour faire glisser un objet vers le nord (11) + if (decorator.Command == DecorateCommand.North) + AddImage(110, 180, 4501, 35); + else + AddButton(110, 180, 4501, 4501, 11, GumpButtonType.Reply, 0); + + // Scriptiz : ajout du bouton pour faire glisser un objet vers l'est (12) + if (decorator.Command == DecorateCommand.East) + AddImage(110, 250, 4503, 35); + else + AddButton(110, 250, 4503, 4503, 12, GumpButtonType.Reply, 0); + + // Scriptiz : ajout du bouton pour faire glisser un objet vers le sud (13) + if (decorator.Command == DecorateCommand.South) + AddImage(40, 250, 4505, 35); + else + AddButton(40, 250, 4505, 4505, 13, GumpButtonType.Reply, 0); + + if (Utility.Random(50) == 0) AddLabel(63, 230, 0, "(C) Scriptiz"); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + DecorateCommand command = DecorateCommand.None; + + switch (info.ButtonID) + { + case 1: command = DecorateCommand.Turn; break; + case 2: command = DecorateCommand.Up; break; + case 3: command = DecorateCommand.Down; break; + + // Scriptiz : boutons pour faire glisser vers une des directions cardinales + case 10: command = DecorateCommand.West; break; + case 11: command = DecorateCommand.North; break; + case 12: command = DecorateCommand.East; break; + case 13: command = DecorateCommand.South; break; + } + + if (command != DecorateCommand.None) + { + m_Decorator.Command = command; + sender.Mobile.SendGump(new InternalGump(m_Decorator)); + sender.Mobile.Target = new InternalTarget(m_Decorator); + } + else + Target.Cancel(sender.Mobile); + } + } + + private class InternalTarget : Target + { + private InteriorDecorator m_Decorator; + + public InternalTarget(InteriorDecorator decorator) + : base(-1, false, TargetFlags.None) + { + CheckLOS = false; + + m_Decorator = decorator; + } + + protected override void OnTargetNotAccessible(Mobile from, object targeted) + { + OnTarget(from, targeted); + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item && InteriorDecorator.CheckUse(m_Decorator, from)) + { + BaseHouse house = BaseHouse.FindHouseAt(from); + Item item = (Item)targeted; + + bool isDecorableComponent = false; + + if (item is AddonComponent || item is AddonContainerComponent || item is BaseAddonContainer) + { + object addon = null; + int count = 0; + + if (item is AddonComponent) + { + AddonComponent component = (AddonComponent)item; + count = component.Addon.Components.Count; + addon = component.Addon; + } + else if (item is AddonContainerComponent) + { + AddonContainerComponent component = (AddonContainerComponent)item; + count = component.Addon.Components.Count; + addon = component.Addon; + } + else if (item is BaseAddonContainer) + { + BaseAddonContainer container = (BaseAddonContainer)item; + count = container.Components.Count; + addon = container; + } + + if (count == 1 && Core.SE) + isDecorableComponent = true; + + if (m_Decorator.Command == DecorateCommand.Turn) + { + FlipableAddonAttribute[] attributes = (FlipableAddonAttribute[])addon.GetType().GetCustomAttributes(typeof(FlipableAddonAttribute), false); + + if (attributes.Length > 0) + isDecorableComponent = true; + } + } + + if (house == null || !house.IsCoOwner(from)) + { + from.SendLocalizedMessage(502092); // You must be in your house to do this. + } + else if (item.Parent != null || !house.IsInside(item)) + { + from.SendLocalizedMessage(1042270); // That is not in your house. + } + else if (!house.IsLockedDown(item) && !house.IsSecure(item) && !isDecorableComponent) + { + if (item is AddonComponent && m_Decorator.Command == DecorateCommand.Up) + from.SendLocalizedMessage(1042274); // You cannot raise it up any higher. + else if (item is AddonComponent && m_Decorator.Command == DecorateCommand.Down) + from.SendLocalizedMessage(1042275); // You cannot lower it down any further. + else + from.SendLocalizedMessage(1042271); // That is not locked down. + } + else if (item is VendorRentalContract) + { + from.SendLocalizedMessage(1062491); // You cannot use the house decorator on that object. + } + // Scriptiz : on peut d�placer m�me des objets lourds + //else if (item.TotalWeight + item.PileWeight > 100) + //{ + // from.SendLocalizedMessage(1042272); // That is too heavy. + //} + else + { + switch (m_Decorator.Command) + { + case DecorateCommand.Up: Up(item, from); break; + case DecorateCommand.Down: Down(item, from); break; + case DecorateCommand.Turn: Turn(item, from); break; + + // Scriptiz : ajout des commandes pour faire glisser l'objet + case DecorateCommand.West: Move(item, from, Direction.West); break; + case DecorateCommand.North: Move(item, from, Direction.North); break; + case DecorateCommand.East: Move(item, from, Direction.East); break; + case DecorateCommand.South: Move(item, from, Direction.South); break; + } + } + } + + from.Target = new InternalTarget(m_Decorator); + } + + protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) + { + if (cancelType == TargetCancelType.Canceled) + from.CloseGump(typeof(InteriorDecorator.InternalGump)); + } + + private static void Turn(Item item, Mobile from) + { + if (item is AddonComponent || item is AddonContainerComponent || item is BaseAddonContainer) + { + object addon = null; + + if (item is AddonComponent) + addon = ((AddonComponent)item).Addon; + else if (item is AddonContainerComponent) + addon = ((AddonContainerComponent)item).Addon; + else if (item is BaseAddonContainer) + addon = (BaseAddonContainer)item; + + FlipableAddonAttribute[] aAttributes = (FlipableAddonAttribute[])addon.GetType().GetCustomAttributes(typeof(FlipableAddonAttribute), false); + + if (aAttributes.Length > 0) + { + aAttributes[0].Flip(from, (Item)addon); + return; + } + } + + FlipableAttribute[] attributes = (FlipableAttribute[])item.GetType().GetCustomAttributes(typeof(FlipableAttribute), false); + + if (attributes.Length > 0) + attributes[0].Flip(item); + else + from.SendLocalizedMessage(1042273); // You cannot turn that. + } + + private static void Up(Item item, Mobile from) + { + int floorZ = GetFloorZ(item); + + if (floorZ > int.MinValue && item.Z < (floorZ + 15)) // Confirmed : no height checks here + item.Location = new Point3D(item.Location, item.Z + 1); + else + from.SendLocalizedMessage(1042274); // You cannot raise it up any higher. + } + + private static void Down(Item item, Mobile from) + { + int floorZ = GetFloorZ(item); + + if (floorZ > int.MinValue && item.Z > GetFloorZ(item)) + item.Location = new Point3D(item.Location, item.Z - 1); + else + from.SendLocalizedMessage(1042275); // You cannot lower it down any further. + } + + // Scriptiz : ajout d'une m�thode pour d�placer un objet dans une maison + private static void Move(Item item, Mobile from, Direction dir) + { + int x = 0, y = 0, deltaX = 0, deltaY = 0; + switch (dir) + { + case Direction.West: x = -1; deltaX = -2; break; + case Direction.North: y = -1; deltaY = -2; break; + case Direction.East: x = 1; deltaX = 1; break; + case Direction.South: y = 1; deltaY = 2; break; + } + + BaseHouse house = BaseHouse.FindHouseAt(from); + if (house.IsInside(new Point3D(item.X + deltaX, item.Y + deltaY, item.Z), GetFloorZ(item))) + { + item.X += x; + item.Y += y; + } + else from.SendMessage("Vous ne pouvez pas d�placer cet objet en dehors de la maison."); + } + + private static int GetFloorZ(Item item) + { + Map map = item.Map; + + if (map == null) + return int.MinValue; + + StaticTile[] tiles = map.Tiles.GetStaticTiles(item.X, item.Y, true); + + int z = int.MinValue; + + for (int i = 0; i < tiles.Length; ++i) + { + StaticTile tile = tiles[i]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + int top = tile.Z; // Confirmed : no height checks here + + if (id.Surface && !id.Impassable && top > z && top <= item.Z) + z = top; + } + + return z; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Key.cs b/Scripts/Items/Misc/Key.cs new file mode 100644 index 0000000..2daf0aa --- /dev/null +++ b/Scripts/Items/Misc/Key.cs @@ -0,0 +1,474 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Targeting; +using Server.Prompts; + +namespace Server.Items +{ + public enum KeyType + { + Copper = 0x100E, + Gold = 0x100F, + Iron = 0x1010, + Rusty = 0x1013 + } + + public interface ILockable + { + bool Locked{ get; set; } + uint KeyValue{ get; set; } + } + + public class Key : Item + { + private string m_Description; + private uint m_KeyVal; + private Item m_Link; + private int m_MaxRange; + + public static uint RandomValue() + { + return (uint)(0xFFFFFFFE * Utility.RandomDouble()) + 1; + } + + public static void RemoveKeys( Mobile m, uint keyValue ) + { + if ( keyValue == 0 ) + return; + + RemoveKeys( m.Backpack, keyValue ); + RemoveKeys( m.BankBox, keyValue ); + } + + public static void RemoveKeys( Container cont, uint keyValue ) + { + if ( cont == null || keyValue == 0 ) + return; + + Item[] items = cont.FindItemsByType( new Type[] { typeof( Key ), typeof( KeyRing ) } ); + + foreach ( Item item in items ) + { + if ( item is Key ) + { + Key key = (Key) item; + + if ( key.KeyValue == keyValue ) + key.Delete(); + } + else + { + KeyRing keyRing = (KeyRing) item; + + keyRing.RemoveKeys( keyValue ); + } + } + } + + public static bool ContainsKey( Container cont, uint keyValue ) + { + if ( cont == null ) + return false; + + Item[] items = cont.FindItemsByType( new Type[] { typeof( Key ), typeof( KeyRing ) } ); + + foreach ( Item item in items ) + { + if ( item is Key ) + { + Key key = (Key) item; + + if ( key.KeyValue == keyValue ) + return true; + } + else + { + KeyRing keyRing = (KeyRing) item; + + if ( keyRing.ContainsKey( keyValue ) ) + return true; + } + } + + return false; + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Description + { + get + { + return m_Description; + } + set + { + m_Description = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxRange + { + get + { + return m_MaxRange; + } + + set + { + m_MaxRange = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public uint KeyValue + { + get + { + return m_KeyVal; + } + + set + { + m_KeyVal = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Link + { + get + { + return m_Link; + } + + set + { + m_Link = value; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); // version + + writer.Write( (int) m_MaxRange ); + + writer.Write( (Item) m_Link ); + + writer.Write( (string) m_Description ); + writer.Write( (uint) m_KeyVal ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + case 2: + { + m_MaxRange = reader.ReadInt(); + LootType = LootType.Blessed; + + goto case 1; + } + case 1: + { + m_Link = reader.ReadItem(); + + goto case 0; + } + case 0: + { + if ( version < 2 || m_MaxRange == 0 ) + m_MaxRange = 3; + + m_Description = reader.ReadString(); + + m_KeyVal = reader.ReadUInt(); + + break; + } + } + } + + [Constructable] + public Key() : this( KeyType.Iron, 0 ) + { + } + + [Constructable] + public Key( KeyType type ) : this( type, 0 ) + { + } + + [Constructable] + public Key( uint val ) : this ( KeyType.Iron, val ) + { + } + + [Constructable] + public Key( KeyType type, uint LockVal ) : this( type, LockVal, null ) + { + m_KeyVal = LockVal; + } + + public Key( KeyType type, uint LockVal, Item link ) : base( (int)type ) + { + Weight = 1.0; + + m_MaxRange = 3; + m_KeyVal = LockVal; + m_Link = link; + + // Scriptiz : on ne peut pas looter les clefs et elles sont blessed pour si corps sur bateau + Lootable = false; + LootType = LootType.Blessed; + } + + public Key( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !this.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 501661 ); // That key is unreachable. + return; + } + + Target t; + int number; + + if ( m_KeyVal != 0 ) + { + number = 501662; // What shall I use this key on? + t = new UnlockTarget( this ); + } + else + { + number = 501663; // This key is a key blank. Which key would you like to make a copy of? + t = new CopyTarget( this ); + } + + from.SendLocalizedMessage( number ); + from.Target = t; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + string desc; + + if ( m_KeyVal == 0 ) + desc = "(blank)"; + else if ( (desc = m_Description) == null || (desc = desc.Trim()).Length <= 0 ) + desc = null; + + if ( desc != null ) + list.Add( desc ); + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + string desc; + + if ( m_KeyVal == 0 ) + desc = "(blank)"; + else if ( (desc = m_Description) == null || (desc = desc.Trim()).Length <= 0 ) + desc = ""; + + if ( desc.Length > 0 ) + from.Send( new UnicodeMessage( Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", "", desc ) ); + } + + public bool UseOn( Mobile from, ILockable o ) + { + if ( o.KeyValue == this.KeyValue ) + { + if ( o is BaseDoor && !((BaseDoor)o).UseLocks() ) + { + return false; + } + else + { + o.Locked = !o.Locked; + + if ( o is LockableContainer ) + { + LockableContainer cont = (LockableContainer)o; + + if ( cont.LockLevel == -255 ) + cont.LockLevel = cont.RequiredSkill - 10; + } + + if ( o is Item ) + { + Item item = (Item) o; + + if ( o.Locked ) + item.SendLocalizedMessageTo( from, 1048000 ); // You lock it. + else + item.SendLocalizedMessageTo( from, 1048001 ); // You unlock it. + + if ( item is LockableContainer ) + { + LockableContainer cont = (LockableContainer) item; + + if ( cont.TrapType != TrapType.None && cont.TrapOnLockpick ) + { + if ( o.Locked ) + item.SendLocalizedMessageTo( from, 501673 ); // You re-enable the trap. + else + item.SendLocalizedMessageTo( from, 501672 ); // You disable the trap temporarily. Lock it again to re-enable it. + } + } + } + + return true; + } + } + else + { + return false; + } + } + + private class RenamePrompt : Prompt + { + private Key m_Key; + + public RenamePrompt( Key key ) + { + m_Key = key; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Key.Deleted || !m_Key.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 501661 ); // That key is unreachable. + return; + } + + m_Key.Description = Utility.FixHtml( text ); + } + } + + private class UnlockTarget : Target + { + private Key m_Key; + + public UnlockTarget( Key key ) : base( key.MaxRange, false, TargetFlags.None ) + { + m_Key = key; + CheckLOS = false; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Key.Deleted || !m_Key.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 501661 ); // That key is unreachable. + return; + } + + int number; + + if ( targeted == m_Key ) + { + number = 501665; // Enter a description for this key. + + from.Prompt = new RenamePrompt( m_Key ); + } + else if ( targeted is ILockable ) + { + if ( m_Key.UseOn( from, (ILockable) targeted ) ) + number = -1; + else + number = 501668; // This key doesn't seem to unlock that. + } + else + { + number = 501666; // You can't unlock that! + } + + if ( number != -1 ) + { + from.SendLocalizedMessage( number ); + } + } + } + + private class CopyTarget : Target + { + private Key m_Key; + + public CopyTarget( Key key ) : base( 3, false, TargetFlags.None ) + { + m_Key = key; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Key.Deleted || !m_Key.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 501661 ); // That key is unreachable. + return; + } + + int number; + + if ( targeted is Key ) + { + Key k = (Key)targeted; + + if ( k.m_KeyVal == 0 ) + { + number = 501675; // This key is also blank. + } + else if ( from.CheckTargetSkill( SkillName.Tinkering, k, 0, 75.0 ) ) + { + number = 501676; // You make a copy of the key. + + m_Key.Description = k.Description; + m_Key.KeyValue = k.KeyValue; + m_Key.Link = k.Link; + m_Key.MaxRange = k.MaxRange; + } + else if ( Utility.RandomDouble() <= 0.1 ) // 10% chance to destroy the key + { + from.SendLocalizedMessage( 501677 ); // You fail to make a copy of the key. + + number = 501678; // The key was destroyed in the attempt. + + m_Key.Delete(); + } + else + { + number = 501677; // You fail to make a copy of the key. + } + } + else + { + number = 501688; // Not a key. + } + + from.SendLocalizedMessage( number ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/KeyRing.cs b/Scripts/Items/Misc/KeyRing.cs new file mode 100644 index 0000000..39bd4e3 --- /dev/null +++ b/Scripts/Items/Misc/KeyRing.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using System.Collections.Generic; + +namespace Server.Items +{ + public class KeyRing : Item + { + public static readonly int MaxKeys = 20; + + private List m_Keys; + + public List Keys { get { return m_Keys; } } + + [Constructable] + public KeyRing() : base( 0x1011 ) + { + Weight = 1.0; // They seem to have no weight on OSI ?! + + m_Keys = new List(); + + // Scriptiz : on ne peut pas looter les clefs et blessed au cas o� le corps est sur le bateau + Lootable = false; + LootType = LootType.Blessed; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( !this.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1060640 ); // The item must be in your backpack to use it. + return false; + } + + Key key = dropped as Key; + + if ( key == null || key.KeyValue == 0 ) + { + from.SendLocalizedMessage( 501689 ); // Only non-blank keys can be put on a keyring. + return false; + } + else if ( this.Keys.Count >= MaxKeys ) + { + from.SendLocalizedMessage( 1008138 ); // This keyring is full. + return false; + } + else + { + Add( key ); + from.SendLocalizedMessage( 501691 ); // You put the key on the keyring. + return true; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !this.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1060640 ); // The item must be in your backpack to use it. + return; + } + + from.SendLocalizedMessage( 501680 ); // What do you want to unlock? + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private KeyRing m_KeyRing; + + public InternalTarget( KeyRing keyRing ) : base( -1, false, TargetFlags.None ) + { + m_KeyRing = keyRing; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_KeyRing.Deleted || !m_KeyRing.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1060640 ); // The item must be in your backpack to use it. + return; + } + + if ( m_KeyRing == targeted ) + { + m_KeyRing.Open( from ); + from.SendLocalizedMessage( 501685 ); // You open the keyring. + } + else if ( targeted is ILockable ) + { + ILockable o = (ILockable) targeted; + + foreach ( Key key in m_KeyRing.Keys ) + { + if ( key.UseOn( from, o ) ) + return; + } + + from.SendLocalizedMessage( 1008140 ); // You do not have a key for that. + } + else + { + from.SendLocalizedMessage( 501666 ); // You can't unlock that! + } + } + } + + public override void OnDelete() + { + base.OnDelete(); + + foreach ( Key key in m_Keys ) + { + key.Delete(); + } + + m_Keys.Clear(); + } + + public void Add( Key key ) + { + key.Internalize(); + m_Keys.Add( key ); + + UpdateItemID(); + } + + public void Open( Mobile from ) + { + Container cont = this.Parent as Container; + + if ( cont == null ) + return; + + for ( int i = m_Keys.Count - 1; i >= 0; i-- ) + { + Key key = m_Keys[i]; + + if ( !key.Deleted && !cont.TryDropItem( from, key, true ) ) + break; + + m_Keys.RemoveAt( i ); + } + + UpdateItemID(); + } + + public void RemoveKeys( uint keyValue ) + { + for ( int i = m_Keys.Count - 1; i >= 0; i-- ) + { + Key key = m_Keys[i]; + + if ( key.KeyValue == keyValue ) + { + key.Delete(); + m_Keys.RemoveAt( i ); + } + } + + UpdateItemID(); + } + + public bool ContainsKey( uint keyValue ) + { + foreach ( Key key in m_Keys ) + { + if ( key.KeyValue == keyValue ) + return true; + } + + return false; + } + + private void UpdateItemID() + { + if ( this.Keys.Count < 1 ) + this.ItemID = 0x1011; + else if ( this.Keys.Count < 3 ) + this.ItemID = 0x1769; + else if ( this.Keys.Count < 5 ) + this.ItemID = 0x176A; + else + this.ItemID = 0x176B; + } + + public KeyRing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + + writer.WriteItemList( m_Keys ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + if (version == 0) LootType = LootType.Blessed; + + m_Keys = reader.ReadStrongItemList(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/LOSBlocker.cs b/Scripts/Items/Misc/LOSBlocker.cs new file mode 100644 index 0000000..edfb47d --- /dev/null +++ b/Scripts/Items/Misc/LOSBlocker.cs @@ -0,0 +1,118 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class LOSBlocker : Item + { + public static void Initialize() + { + TileData.ItemTable[0x21A2].Flags = TileFlag.Wall | TileFlag.NoShoot; + TileData.ItemTable[0x21A2].Height = 20; + } + + public override string DefaultName + { + get { return "no line of sight"; } + } + + [Constructable] + public LOSBlocker() : base( 0x21A2 ) + { + Movable = false; + } + + public LOSBlocker( Serial serial ) : base( serial ) + { + } + + protected override Packet GetWorldPacketFor( NetState state ) { + Mobile mob = state.Mobile; + + if ( mob != null && mob.AccessLevel >= AccessLevel.GameMaster ) { + return new GMItemPacket( this ); + } + + return base.GetWorldPacketFor( state ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version < 1 && ItemID == 0x2199) + this.ItemID = 0x21A2; + } + + public sealed class GMItemPacket : Packet + { + public GMItemPacket( Item item ) : base( 0x1A ) + { + this.EnsureCapacity( 20 ); + + // 14 base length + // +2 - Amount + // +2 - Hue + // +1 - Flags + + uint serial = (uint)item.Serial.Value; + int itemID = 0x36FF; + int amount = item.Amount; + Point3D loc = item.Location; + int x = loc.X; + int y = loc.Y; + int hue = item.Hue; + int flags = item.GetPacketFlags(); + int direction = (int)item.Direction; + + if ( amount != 0 ) + serial |= 0x80000000; + else + serial &= 0x7FFFFFFF; + + m_Stream.Write( (uint) serial ); + m_Stream.Write( (short) (itemID & 0x7FFF) ); + + if ( amount != 0 ) + m_Stream.Write( (short) amount ); + + x &= 0x7FFF; + + if ( direction != 0 ) + x |= 0x8000; + + m_Stream.Write( (short) x ); + + y &= 0x3FFF; + + if ( hue != 0 ) + y |= 0x8000; + + if ( flags != 0 ) + y |= 0x4000; + + m_Stream.Write( (short) y ); + + if ( direction != 0 ) + m_Stream.Write( (byte) direction ); + + m_Stream.Write( (sbyte) loc.Z ); + + if ( hue != 0 ) + m_Stream.Write( (ushort) hue ); + + if ( flags != 0 ) + m_Stream.Write( (byte) flags ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Labyrinth/MinotaurArtifact.cs b/Scripts/Items/Misc/Labyrinth/MinotaurArtifact.cs new file mode 100644 index 0000000..3bb2d3f --- /dev/null +++ b/Scripts/Items/Misc/Labyrinth/MinotaurArtifact.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MinotaurArtifact : Item + { + public override int LabelNumber{ get{ return 1074826; } } // Minotaur Artifact + public override double DefaultWeight{ get{ return 5.0; } } + + [Constructable] + public MinotaurArtifact() : base( Utility.RandomList( 0xB46, 0xB48, 0x9ED ) ) + { + if ( ItemID == 0x9ED ) + Weight = 30; + + LootType = LootType.Blessed; + Hue = 0x100; + } + + public MinotaurArtifact( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Misc/Moonstone.cs b/Scripts/Items/Misc/Moonstone.cs new file mode 100644 index 0000000..3c80f98 --- /dev/null +++ b/Scripts/Items/Misc/Moonstone.cs @@ -0,0 +1,203 @@ +using System; +using Server; +using Server.Network; +using Server.Mobiles; + +namespace Server.Items +{ + public enum MoonstoneType + { + Felucca, Trammel + } + + public class Moonstone : Item + { + private MoonstoneType m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public MoonstoneType Type + { + get + { + return m_Type; + } + set + { + m_Type = value; + InvalidateProperties(); + } + } + + public override int LabelNumber{ get{ return 1041490 + (int)m_Type; } } + + [Constructable] + public Moonstone( MoonstoneType type ) : base( 0xF8B ) + { + Weight = 1.0; + m_Type = type; + } + + public Moonstone( Serial serial ) : base( serial ) + { + } + + public override void OnSingleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + Hue = Utility.RandomBirdHue(); + ProcessDelta(); + from.SendLocalizedMessage( 1005398 ); // The stone's substance shifts as you examine it. + } + + base.OnSingleClick( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.Mounted ) + { + from.SendLocalizedMessage( 1005399 ); // You can not bury a stone while you sit on a mount. + } + else if ( !from.Body.IsHuman ) + { + from.SendLocalizedMessage( 1005400 ); // You can not bury a stone in this form. + } + else if ( Factions.Sigil.ExistsOn( from ) ) + { + from.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( from.Map == GetTargetMap() || ( from.Map != Map.Trammel && from.Map != Map.Felucca ) ) + { + from.SendLocalizedMessage( 1005401 ); // You cannot bury the stone here. + } + else if ( from is PlayerMobile && ((PlayerMobile)from).Young ) + { + from.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young. + } + else if ( from.Kills >= 5 ) + { + from.SendLocalizedMessage( 1005402 ); // The magic of the stone cannot be evoked by someone with blood on their hands. + } + else if ( from.Criminal ) + { + from.SendLocalizedMessage( 1005403 ); // The magic of the stone cannot be evoked by the lawless. + } + else if ( !Region.Find( from.Location, from.Map ).IsDefault || !Region.Find( from.Location, GetTargetMap() ).IsDefault ) + { + from.SendLocalizedMessage( 1005401 ); // You cannot bury the stone here. + } + else if ( !GetTargetMap().CanFit( from.Location, 16 ) ) + { + from.SendLocalizedMessage( 1005408 ); // Something is blocking the facet gate exit. + } + else + { + Movable = false; + MoveToWorld( from.Location, from.Map ); + + from.Animate( 32, 5, 1, true, false, 0 ); + + new SettleTimer( this, from.Location, from.Map, GetTargetMap(), from ).Start(); + } + } + + public Map GetTargetMap() + { + return ( m_Type == MoonstoneType.Felucca ) ? Map.Felucca : Map.Trammel; + } + + private class SettleTimer : Timer + { + private Item m_Stone; + private Point3D m_Location; + private Map m_Map, m_TargetMap; + private Mobile m_Caster; + private int m_Count; + + public SettleTimer( Item stone, Point3D loc, Map map, Map targetMap, Mobile caster ) : base( TimeSpan.FromSeconds( 2.5 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Stone = stone; + + m_Location = loc; + m_Map = map; + m_TargetMap = targetMap; + + m_Caster = caster; + } + + protected override void OnTick() + { + ++m_Count; + + if ( m_Count == 1 ) + { + m_Stone.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1005414 ); // The stone settles into the ground. + } + else if ( m_Count >= 10 ) + { + m_Stone.Location = new Point3D( m_Stone.X, m_Stone.Y, m_Stone.Z - 1 ); + + if ( m_Count == 16 ) + { + if ( !Region.Find( m_Location, m_Map ).IsDefault || !Region.Find( m_Location, m_TargetMap ).IsDefault ) + { + m_Stone.Movable = true; + m_Caster.AddToBackpack( m_Stone ); + Stop(); + return; + } + else if ( !m_TargetMap.CanFit( m_Location, 16 ) ) + { + m_Stone.Movable = true; + m_Caster.AddToBackpack( m_Stone ); + Stop(); + return; + } + + int hue = m_Stone.Hue; + + if ( hue == 0 ) + hue = Utility.RandomBirdHue(); + + new MoonstoneGate( m_Location, m_TargetMap, m_Map, m_Caster, hue ); + new MoonstoneGate( m_Location, m_Map, m_TargetMap, m_Caster, hue ); + + m_Stone.Delete(); + Stop(); + } + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (MoonstoneType)reader.ReadInt(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/MoonstoneGate.cs b/Scripts/Items/Misc/MoonstoneGate.cs new file mode 100644 index 0000000..0d3da92 --- /dev/null +++ b/Scripts/Items/Misc/MoonstoneGate.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Network; +using Server.Engines.PartySystem; + +namespace Server.Items +{ + public class MoonstoneGate : Moongate + { + private Mobile m_Caster; + + public MoonstoneGate( Point3D loc, Map map, Map targetMap, Mobile caster, int hue ) : base( loc, targetMap ) + { + MoveToWorld( loc, map ); + Dispellable = false; + Hue = hue; + + m_Caster = caster; + + new InternalTimer( this ).Start(); + + Effects.PlaySound( loc, map, 0x20E ); + } + + public MoonstoneGate( Serial serial ) : base( serial ) + { + } + + public override void CheckGate( Mobile m, int range ) + { + if ( m.Kills >= 5 ) + return; + + Party casterParty = Party.Get( m_Caster ); + Party userParty = Party.Get( m ); + + if ( m == m_Caster || (casterParty != null && userParty == casterParty) ) + base.CheckGate( m, range ); + } + + public override void UseGate( Mobile m ) + { + if ( m.Kills >= 5 ) + return; + + Party casterParty = Party.Get( m_Caster ); + Party userParty = Party.Get( m ); + + if ( m == m_Caster || (casterParty != null && userParty == casterParty) ) + base.UseGate( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Item = item; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/MorphItem.cs b/Scripts/Items/Misc/MorphItem.cs new file mode 100644 index 0000000..1ac40d3 --- /dev/null +++ b/Scripts/Items/Misc/MorphItem.cs @@ -0,0 +1,146 @@ +using System; + +namespace Server.Items +{ + public class MorphItem : Item + { + private int m_InactiveItemID; + private int m_ActiveItemID; + private int m_InRange; + private int m_OutRange; + + [CommandProperty( AccessLevel.GameMaster )] + public int InactiveItemID + { + get{ return m_InactiveItemID; } + set{ m_InactiveItemID = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ActiveItemID + { + get{ return m_ActiveItemID; } + set{ m_ActiveItemID = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int InRange + { + get{ return m_InRange; } + set{ if ( value > 18 ) value = 18; m_InRange = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int OutRange + { + get{ return m_OutRange; } + set{ if ( value > 18 ) value = 18; m_OutRange = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurrentRange{ get{ return ItemID == InactiveItemID ? InRange : OutRange; } } + + [Constructable] + public MorphItem( int inactiveItemID, int activeItemID, int range ) : this( inactiveItemID, activeItemID, range, range ) + { + } + + [Constructable] + public MorphItem( int inactiveItemID, int activeItemID, int inRange, int outRange ) : base( inactiveItemID ) + { + Movable = false; + + InactiveItemID = inactiveItemID; + ActiveItemID = activeItemID; + InRange = inRange; + OutRange = outRange; + } + + public MorphItem( Serial serial ) : base( serial ) + { + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( Utility.InRange( m.Location, Location, CurrentRange ) || Utility.InRange( oldLocation, Location, CurrentRange ) ) + Refresh(); + } + + public override void OnMapChange() + { + if ( !Deleted ) + Refresh(); + } + + public override void OnLocationChange( Point3D oldLoc ) + { + if ( !Deleted ) + Refresh(); + } + + public void Refresh() + { + bool found = false; + + foreach ( Mobile mob in GetMobilesInRange( CurrentRange ) ) + { + if ( mob.Hidden && mob.AccessLevel > AccessLevel.Player ) + continue; + + found = true; + break; + } + + if ( found ) + ItemID = ActiveItemID; + else + ItemID = InactiveItemID; + + Visible = ( ItemID != 0x1 ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_OutRange ); + + writer.Write( (int) m_InactiveItemID ); + writer.Write( (int) m_ActiveItemID ); + writer.Write( (int) m_InRange ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_OutRange = reader.ReadInt(); + goto case 0; + } + case 0: + { + m_InactiveItemID = reader.ReadInt(); + m_ActiveItemID = reader.ReadInt(); + m_InRange = reader.ReadInt(); + + if ( version < 1 ) + m_OutRange = m_InRange; + + break; + } + } + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Refresh ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/OilCloth.cs b/Scripts/Items/Misc/OilCloth.cs new file mode 100644 index 0000000..0b1eb92 --- /dev/null +++ b/Scripts/Items/Misc/OilCloth.cs @@ -0,0 +1,179 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class OilCloth : Item, IScissorable, IDyable + { + public override int LabelNumber{ get{ return 1041498; } } // oil cloth + + public override double DefaultWeight + { + get { return 1.0; } + } + + [Constructable] + public OilCloth() //: base( 0x175D ) + : this(1) // Scriptiz : stackable + { + Hue = 2001; + } + + // Scriptiz : constructeur Stackable + [Constructable] + public OilCloth(int amount) : + base(0x175D) + { + Stackable = true; + Amount = amount; + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) + return false; + + base.ScissorHelper( from, new Bandage(), 1 ); + + return true; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( OnTarget ) ); + from.SendLocalizedMessage( 1005424 ); // Select the weapon or armor you wish to use the cloth on. + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public void OnTarget(Mobile from, object obj) + { + // TODO: Need details on how oil cloths should get consumed here + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + else if (obj is Item && ((Item)obj).RootParent != from) + { + from.SendLocalizedMessage(1005425); // You may only wipe down items you are holding or carrying. + } + else if (obj is BaseWeapon) + { + BaseWeapon weapon = (BaseWeapon)obj; + + if (weapon.Poison == null || weapon.PoisonCharges <= 0) + { + from.LocalOverheadMessage(Network.MessageType.Regular, 0x3B2, 1005422); // Hmmmm... this does not need to be cleaned. + } + else + { + if (weapon.PoisonCharges < 2) + weapon.PoisonCharges = 0; + else + weapon.PoisonCharges -= 2; + + if (weapon.PoisonCharges > 0) + from.SendLocalizedMessage(1005423); // You have removed some of the caustic substance, but not all. + else + from.SendLocalizedMessage(1010497); // You have cleaned the item. + } + } + else if (obj == from && obj is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)obj; + + if (pm.BodyMod == 183 || pm.BodyMod == 184) + { + pm.SavagePaintExpiration = TimeSpan.Zero; + + pm.BodyMod = 0; + pm.HueMod = -1; + + from.SendLocalizedMessage(1040006); // You wipe away all of your body paint. + + Consume(); + } + else + { + from.LocalOverheadMessage(Network.MessageType.Regular, 0x3B2, 1005422); // Hmmmm... this does not need to be cleaned. + } + } + else if (obj is DyeTub) + { + DyeTub tub = (DyeTub)obj; + + if (!tub.Redyable) + { + tub.Redyable = true; + tub.Charges = 0; + tub.DyedHue = 0; + from.SendMessage("Vous nettoyez le bac de teinture"); + + Consume(); + } + } + + #region Firebomb + else if (obj is BaseBeverage) + { + BaseBeverage beverage = (BaseBeverage)obj; + + if (beverage.Content == BeverageType.Liquor) + { + Firebomb bomb = new Firebomb(beverage.ItemID); + bomb.Name = beverage.Name; + + beverage.ReplaceWith(bomb); + + from.SendLocalizedMessage(1060580); // You prepare a firebomb. + Consume(); + } + } + else if (obj is Firebomb) + { + from.SendLocalizedMessage(1060579); // That is already a firebomb! + } + #endregion + else + { + from.SendLocalizedMessage(1005426); // The cloth will not work on that. + } + } + + public OilCloth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Origami.cs b/Scripts/Items/Misc/Origami.cs new file mode 100644 index 0000000..7aa649c --- /dev/null +++ b/Scripts/Items/Misc/Origami.cs @@ -0,0 +1,247 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class OrigamiPaper : Item + { + public override int LabelNumber{ get{ return 1030288; } } // origami paper + + [Constructable] + public OrigamiPaper() : base( 0x2830 ) + { + } + + public OrigamiPaper( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + this.Delete(); + + Item i = null; + + switch ( Utility.Random( (from.BAC >= 5) ? 6 : 5) ) + { + case 0: i = new OrigamiButterfly(); break; + case 1: i = new OrigamiSwan(); break; + case 2: i = new OrigamiFrog(); break; + case 3: i = new OrigamiShape(); break; + case 4: i = new OrigamiSongbird(); break; + case 5: i = new OrigamiFish(); break; + } + + if( i != null ) + from.AddToBackpack( i ); + + from.SendLocalizedMessage( 1070822 ); // You fold the paper into an interesting shape. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrigamiButterfly : Item + { + public override int LabelNumber{ get{ return 1030296; } } // a delicate origami butterfly + + [Constructable] + public OrigamiButterfly() : base( 0x2838 ) + { + LootType = LootType.Blessed; + } + + public OrigamiButterfly( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrigamiSwan : Item + { + public override int LabelNumber{ get{ return 1030297; } } // a delicate origami swan + + [Constructable] + public OrigamiSwan() : base( 0x2839 ) + { + LootType = LootType.Blessed; + + + } + + public OrigamiSwan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrigamiFrog : Item + { + public override int LabelNumber{ get{ return 1030298; } } // a delicate origami frog + + [Constructable] + public OrigamiFrog() : base( 0x283A ) + { + LootType = LootType.Blessed; + + + } + + public OrigamiFrog( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrigamiShape : Item + { + public override int LabelNumber{ get{ return 1030299; } } // an intricate geometric origami shape + + [Constructable] + public OrigamiShape() : base( 0x283B ) + { + LootType = LootType.Blessed; + + + } + + public OrigamiShape( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrigamiSongbird : Item + { + public override int LabelNumber{ get{ return 1030300; } } // a delicate origami songbird + + [Constructable] + public OrigamiSongbird() : base( 0x283C ) + { + LootType = LootType.Blessed; + + + } + + public OrigamiSongbird( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class OrigamiFish : Item + { + public override int LabelNumber{ get{ return 1030301; } } // a delicate origami fish + + [Constructable] + public OrigamiFish() : base( 0x283D ) + { + LootType = LootType.Blessed; + + + } + + public OrigamiFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Painted Caves/GrobusFur.cs b/Scripts/Items/Misc/Painted Caves/GrobusFur.cs new file mode 100644 index 0000000..629e08e --- /dev/null +++ b/Scripts/Items/Misc/Painted Caves/GrobusFur.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Items +{ + public class GrobusFur : Item + { + public override int LabelNumber{ get{ return 1074676; } } // Grobu's Fur + + [Constructable] + public GrobusFur() : base( 0x11F4 ) + { + LootType = LootType.Blessed; + Hue = 0x455; + } + + public GrobusFur( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Painted Caves/PrimitiveFetish.cs b/Scripts/Items/Misc/Painted Caves/PrimitiveFetish.cs new file mode 100644 index 0000000..919f1bc --- /dev/null +++ b/Scripts/Items/Misc/Painted Caves/PrimitiveFetish.cs @@ -0,0 +1,35 @@ +using System; + +namespace Server.Items +{ + public class PrimitiveFetish : Item + { + public override int LabelNumber{ get{ return 1074675; } } // Primitive Fetish + + [Constructable] + public PrimitiveFetish() : base( 0x23F ) + { + LootType = LootType.Blessed; + Hue = 0x244; + } + + public PrimitiveFetish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Palace of Paroxysmus/AcidProofRope.cs b/Scripts/Items/Misc/Palace of Paroxysmus/AcidProofRope.cs new file mode 100644 index 0000000..8590194 --- /dev/null +++ b/Scripts/Items/Misc/Palace of Paroxysmus/AcidProofRope.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AcidProofRope : Item + { + public override int LabelNumber{ get{ return 1074886; } } // Acid Proof Rope + + [Constructable] + public AcidProofRope() : base( 0x20D ) + { + Hue = 0x3D1; // TODO check + } + + public AcidProofRope( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Palace of Paroxysmus/ParoxysmusCorrodedStein.cs b/Scripts/Items/Misc/Palace of Paroxysmus/ParoxysmusCorrodedStein.cs new file mode 100644 index 0000000..7f25036 --- /dev/null +++ b/Scripts/Items/Misc/Palace of Paroxysmus/ParoxysmusCorrodedStein.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ParoxysmusCorrodedStein : Item + { + public override int LabelNumber{ get{ return 1072083; } } // Paroxysmus' Corroded Stein + + [Constructable] + public ParoxysmusCorrodedStein() : base( 0x9D6 ) + { + } + + public ParoxysmusCorrodedStein( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Palace of Paroxysmus/ParoxysmusDinner.cs b/Scripts/Items/Misc/Palace of Paroxysmus/ParoxysmusDinner.cs new file mode 100644 index 0000000..7e4d4cd --- /dev/null +++ b/Scripts/Items/Misc/Palace of Paroxysmus/ParoxysmusDinner.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ParoxysmusDinner : Item + { + public override int LabelNumber{ get{ return 1072086; } } // Paroxysmus' Dinner + + [Constructable] + public ParoxysmusDinner() : base( 0x1E95 ) + { + } + + public ParoxysmusDinner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Palace of Paroxysmus/StringOfPartsOfParoxysmusVictims.cs b/Scripts/Items/Misc/Palace of Paroxysmus/StringOfPartsOfParoxysmusVictims.cs new file mode 100644 index 0000000..7f4aa8b --- /dev/null +++ b/Scripts/Items/Misc/Palace of Paroxysmus/StringOfPartsOfParoxysmusVictims.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StringOfPartsOfParoxysmusVictims : Item + { + public override int LabelNumber{ get{ return 1072082; } } // String of Parts of Paroxysmus' Victims + + [Constructable] + public StringOfPartsOfParoxysmusVictims() : base( 0xFD2 ) + { + } + + public StringOfPartsOfParoxysmusVictims( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Palace of Paroxysmus/SweatOfParoxysmus.cs b/Scripts/Items/Misc/Palace of Paroxysmus/SweatOfParoxysmus.cs new file mode 100644 index 0000000..4cfbcae --- /dev/null +++ b/Scripts/Items/Misc/Palace of Paroxysmus/SweatOfParoxysmus.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SweatOfParoxysmus : Item + { + public override int LabelNumber{ get{ return 1072081; } } // Sweat of Paroxysmus + + [Constructable] + public SweatOfParoxysmus() : base( 0xF01 ) + { + } + + public SweatOfParoxysmus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/PlayerBulletinBoards.cs b/Scripts/Items/Misc/PlayerBulletinBoards.cs new file mode 100644 index 0000000..2acfc72 --- /dev/null +++ b/Scripts/Items/Misc/PlayerBulletinBoards.cs @@ -0,0 +1,640 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Prompts; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; + +namespace Server.Items +{ + public class PlayerBBSouth : BasePlayerBB + { + public override int LabelNumber{ get{ return 1062421; } } // bulletin board (south) + + [Constructable] + public PlayerBBSouth() : base( 0x2311 ) + { + Weight = 15.0; + } + + public PlayerBBSouth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PlayerBBEast : BasePlayerBB + { + public override int LabelNumber{ get{ return 1062420; } } // bulletin board (east) + + [Constructable] + public PlayerBBEast() : base( 0x2312 ) + { + Weight = 15.0; + } + + public PlayerBBEast( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public abstract class BasePlayerBB : Item, ISecurable + { + private PlayerBBMessage m_Greeting; + private List m_Messages; + private string m_Title; + private SecureLevel m_Level; + + public List Messages + { + get{ return m_Messages; } + } + + public PlayerBBMessage Greeting + { + get{ return m_Greeting; } + set{ m_Greeting = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Title + { + get{ return m_Title; } + set{ m_Title = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + public BasePlayerBB( int itemID ) : base( itemID ) + { + m_Messages = new List(); + m_Level = SecureLevel.Anyone; + } + + public BasePlayerBB( Serial serial ) : base( serial ) + { + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.Write( (int) m_Level ); + + writer.Write( m_Title ); + + if ( m_Greeting != null ) + { + writer.Write( true ); + m_Greeting.Serialize( writer ); + } + else + { + writer.Write( false ); + } + + writer.WriteEncodedInt( m_Messages.Count ); + + for ( int i = 0; i < m_Messages.Count; ++i ) + m_Messages[i].Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + if ( version < 1 ) + m_Level = SecureLevel.Anyone; + + m_Title = reader.ReadString(); + + if ( reader.ReadBool() ) + m_Greeting = new PlayerBBMessage( reader ); + + int count = reader.ReadEncodedInt(); + + m_Messages = new List( count ); + + for ( int i = 0; i < count; ++i ) + m_Messages.Add( new PlayerBBMessage( reader ) ); + + break; + } + } + } + + public static bool CheckAccess( BaseHouse house, Mobile from ) + { + if ( house.Public || !house.IsAosRules ) + return !house.IsBanned( from ); + + return house.HasAccess( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house == null || !house.IsLockedDown( this ) ) + from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable. + else if ( !from.InRange( this.GetWorldLocation(), 2 ) || !from.InLOS( this ) ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else if ( CheckAccess( house, from ) ) + from.SendGump( new PlayerBBGump( from, house, this, 0 ) ); + } + + public class PostPrompt : Prompt + { + private int m_Page; + private BaseHouse m_House; + private BasePlayerBB m_Board; + private bool m_Greeting; + + public PostPrompt( int page, BaseHouse house, BasePlayerBB board, bool greeting ) + { + m_Page = page; + m_House = house; + m_Board = board; + m_Greeting = greeting; + } + + public override void OnCancel( Mobile from ) + { + OnResponse( from, "" ); + } + + public override void OnResponse( Mobile from, string text ) + { + int page = m_Page; + BaseHouse house = m_House; + BasePlayerBB board = m_Board; + + if ( house == null || !house.IsLockedDown( board ) ) + { + from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable. + return; + } + else if ( !from.InRange( board.GetWorldLocation(), 2 ) || !from.InLOS( board ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + else if ( !CheckAccess( house, from ) ) + { + from.SendLocalizedMessage( 1062398 ); // You are not allowed to post to this bulletin board. + return; + } + else if ( m_Greeting && !house.IsOwner( from ) ) + { + return; + } + + text = text.Trim(); + + if ( text.Length > 255 ) + text = text.Substring( 0, 255 ); + + if ( text.Length > 0 ) + { + PlayerBBMessage message = new PlayerBBMessage( DateTime.Now, from, text ); + + if ( m_Greeting ) + { + board.Greeting = message; + } + else + { + board.Messages.Add( message ); + + if ( board.Messages.Count > 50 ) + { + board.Messages.RemoveAt( 0 ); + + if ( page > 0 ) + --page; + } + } + } + + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + } + } + + public class SetTitlePrompt : Prompt + { + private int m_Page; + private BaseHouse m_House; + private BasePlayerBB m_Board; + + public SetTitlePrompt( int page, BaseHouse house, BasePlayerBB board ) + { + m_Page = page; + m_House = house; + m_Board = board; + } + + public override void OnCancel( Mobile from ) + { + OnResponse( from, "" ); + } + + public override void OnResponse( Mobile from, string text ) + { + int page = m_Page; + BaseHouse house = m_House; + BasePlayerBB board = m_Board; + + if ( house == null || !house.IsLockedDown( board ) ) + { + from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable. + return; + } + else if ( !from.InRange( board.GetWorldLocation(), 2 ) || !from.InLOS( board ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + else if ( !CheckAccess( house, from ) ) + { + from.SendLocalizedMessage( 1062398 ); // You are not allowed to post to this bulletin board. + return; + } + + text = text.Trim(); + + if ( text.Length > 255 ) + text = text.Substring( 0, 255 ); + + if ( text.Length > 0 ) + board.Title = text; + + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + } + } + } + + public class PlayerBBMessage + { + private DateTime m_Time; + private Mobile m_Poster; + private string m_Message; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime Time + { + get{ return m_Time; } + set{ m_Time = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Poster + { + get{ return m_Poster; } + set{ m_Poster = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Message + { + get{ return m_Message; } + set{ m_Message = value; } + } + + public PlayerBBMessage( DateTime time, Mobile poster, string message ) + { + m_Time = time; + m_Poster = poster; + m_Message = message; + } + + public PlayerBBMessage( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 0: + { + m_Time = reader.ReadDateTime(); + m_Poster = reader.ReadMobile(); + m_Message = reader.ReadString(); + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_Time ); + writer.Write( m_Poster ); + writer.Write( m_Message ); + } + } + + public class PlayerBBGump : Gump + { + private int m_Page; + private Mobile m_From; + private BaseHouse m_House; + private BasePlayerBB m_Board; + + private const int LabelColor = 0x7FFF; + private const int LabelHue = 1153; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int page = m_Page; + Mobile from = m_From; + BaseHouse house = m_House; + BasePlayerBB board = m_Board; + + if ( house == null || !house.IsLockedDown( board ) ) + { + from.SendLocalizedMessage( 1062396 ); // This bulletin board must be locked down in a house to be usable. + return; + } + else if ( !from.InRange( board.GetWorldLocation(), 2 ) || !from.InLOS( board ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + else if ( !BasePlayerBB.CheckAccess( house, from ) ) + { + from.SendLocalizedMessage( 1062398 ); // You are not allowed to post to this bulletin board. + return; + } + + switch ( info.ButtonID ) + { + case 1: // Post message + { + from.Prompt = new BasePlayerBB.PostPrompt( page, house, board, false ); + from.SendLocalizedMessage( 1062397 ); // Please enter your message: + + break; + } + case 2: // Set title + { + if ( house.IsOwner( from ) ) + { + from.Prompt = new BasePlayerBB.SetTitlePrompt( page, house, board ); + from.SendLocalizedMessage( 1062402 ); // Enter new title: + } + + break; + } + case 3: // Post greeting + { + if ( house.IsOwner( from ) ) + { + from.Prompt = new BasePlayerBB.PostPrompt( page, house, board, true ); + from.SendLocalizedMessage( 1062404 ); // Enter new greeting (this will always be the first post): + } + + break; + } + case 4: // Scroll up + { + if ( page == 0 ) + page = board.Messages.Count; + else + page -= 1; + + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + + break; + } + case 5: // Scroll down + { + page += 1; + page %= board.Messages.Count + 1; + + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + + break; + } + case 6: // Banish poster + { + if ( house.IsOwner( from ) ) + { + if ( page >= 1 && page <= board.Messages.Count ) + { + PlayerBBMessage message = (PlayerBBMessage)board.Messages[page - 1]; + Mobile poster = message.Poster; + + if ( poster == null ) + { + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + return; + } + + if ( poster.AccessLevel > AccessLevel.Player && from.AccessLevel <= poster.AccessLevel ) + { + from.SendLocalizedMessage( 501354 ); // Uh oh...a bigger boot may be required. + } + else if ( house.IsFriend( poster ) ) + { + from.SendLocalizedMessage( 1060750 ); // That person is a friend, co-owner, or owner of this house, and therefore cannot be banished! + } + else if ( poster is PlayerVendor ) + { + from.SendLocalizedMessage( 501351 ); // You cannot eject a vendor. + } + else if ( house.Bans.Count >= BaseHouse.MaxBans ) + { + from.SendLocalizedMessage( 501355 ); // The ban limit for this house has been reached! + } + else if ( house.IsBanned( poster ) ) + { + from.SendLocalizedMessage( 501356 ); // This person is already banned! + } + else if ( poster is BaseCreature && ((BaseCreature)poster).NoHouseRestrictions ) + { + from.SendLocalizedMessage( 1062040 ); // You cannot ban that. + } + else + { + if ( !house.Bans.Contains( poster ) ) + house.Bans.Add( poster ); + + from.SendLocalizedMessage( 1062417 ); // That person has been banned from this house. + + if ( house.IsInside( poster ) && !BasePlayerBB.CheckAccess( house, poster ) ) + poster.MoveToWorld( house.BanLocation, house.Map ); + } + } + + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + } + + break; + } + case 7: // Delete message + { + if ( house.IsOwner( from ) ) + { + if ( page >= 1 && page <= board.Messages.Count ) + board.Messages.RemoveAt( page - 1 ); + + from.SendGump( new PlayerBBGump( from, house, board, 0 ) ); + } + + break; + } + case 8: // Post props + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + PlayerBBMessage message = board.Greeting; + + if ( page >= 1 && page <= board.Messages.Count ) + message = (PlayerBBMessage)board.Messages[page - 1]; + + from.SendGump( new PlayerBBGump( from, house, board, page ) ); + from.SendGump( new PropertiesGump( from, message ) ); + } + + break; + } + } + } + + public PlayerBBGump( Mobile from, BaseHouse house, BasePlayerBB board, int page ) : base( 50, 10 ) + { + from.CloseGump( typeof( PlayerBBGump ) ); + + m_Page = page; + m_From = from; + m_House = house; + m_Board = board; + + AddPage( 0 ); + + AddImage( 30, 30, 5400 ); + + AddButton( 393, 145, 2084, 2084, 4, GumpButtonType.Reply, 0 ); // Scroll up + AddButton( 390, 371, 2085, 2085, 5, GumpButtonType.Reply, 0 ); // Scroll down + + AddButton( 32, 183, 5412, 5413, 1, GumpButtonType.Reply, 0 ); // Post message + + if ( house.IsOwner( from ) ) + { + AddButton( 63, 90, 5601, 5605, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 81, 89, 230, 20, 1062400, LabelColor, false, false ); // Set title + + AddButton( 63, 109, 5601, 5605, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 81, 108, 230, 20, 1062401, LabelColor, false, false ); // Post greeting + } + + string title = board.Title; + + if ( title != null ) + AddHtml( 183, 68, 180, 23, title, false, false ); + + AddHtmlLocalized( 385, 89, 60, 20, 1062409, LabelColor, false, false ); // Post + + AddLabel( 440, 89, LabelHue, page.ToString() ); + AddLabel( 455, 89, LabelHue, "/" ); + AddLabel( 470, 89, LabelHue, board.Messages.Count.ToString() ); + + PlayerBBMessage message = board.Greeting; + + if ( page >= 1 && page <= board.Messages.Count ) + message = (PlayerBBMessage)board.Messages[page - 1]; + + AddImageTiled( 150, 220, 240, 1, 2700 ); // Separator + + AddHtmlLocalized( 150, 180, 100, 20, 1062405, 16715, false, false ); // Posted On: + AddHtmlLocalized( 150, 200, 100, 20, 1062406, 16715, false, false ); // Posted By: + + if ( message != null ) + { + AddHtml( 255, 180, 150, 20, message.Time.ToString( "yyyy-MM-dd HH:mm:ss" ), false, false ); + + Mobile poster = message.Poster; + string name = ( poster == null ? null : poster.Name ); + + if ( name == null || (name = name.Trim()).Length == 0 ) + name = "Someone"; + + AddHtml( 255, 200, 150, 20, name, false, false ); + + string body = message.Message; + + if ( body == null ) + body = ""; + + AddHtml( 150, 240, 250, 100, body, false, false ); + + if ( message != board.Greeting && house.IsOwner( from ) ) + { + AddButton( 130, 395, 1209, 1210, 6, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 150, 393, 150, 20, 1062410, LabelColor, false, false ); // Banish Poster + + AddButton( 310, 395, 1209, 1210, 7, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 330, 393, 150, 20, 1062411, LabelColor, false, false ); // Delete Message + } + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + AddButton( 135, 242, 1209, 1210, 8, GumpButtonType.Reply, 0 ); // Post props + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/PlayerVendorDeed.cs b/Scripts/Items/Misc/PlayerVendorDeed.cs new file mode 100644 index 0000000..7a6d9e0 --- /dev/null +++ b/Scripts/Items/Misc/PlayerVendorDeed.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Multis; + +namespace Server.Items +{ + public class ContractOfEmployment : Item + { + public override int LabelNumber{ get{ return 1041243; } } // a contract of employment + + [Constructable] + public ContractOfEmployment() : base( 0x14F0 ) + { + Weight = 1.0; + //LootType = LootType.Blessed; + } + + public ContractOfEmployment( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.SendLocalizedMessage( 503248 ); // Your godly powers allow you to place this vendor whereever you wish. + + Mobile v = new PlayerVendor( from, BaseHouse.FindHouseAt( from ) ); + + v.Direction = from.Direction & Direction.Mask; + v.MoveToWorld( from.Location, from.Map ); + + v.SayTo( from, 503246 ); // Ah! it feels good to be working again. + + this.Delete(); + } + else + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house == null ) + { + from.SendLocalizedMessage( 503240 ); // Vendors can only be placed in houses. + } + else if ( !BaseHouse.NewVendorSystem && !house.IsFriend( from ) ) + { + from.SendLocalizedMessage( 503242 ); // You must ask the owner of this building to name you a friend of the household in order to place a vendor here. + } + else if ( BaseHouse.NewVendorSystem && !house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 1062423 ); // Only the house owner can directly place vendors. Please ask the house owner to offer you a vendor contract so that you may place a vendor in this house. + } + else if ( !house.Public || !house.CanPlaceNewVendor() ) + { + from.SendLocalizedMessage( 503241 ); // You cannot place this vendor or barkeep. Make sure the house is public and has sufficient storage available. + } + else + { + bool vendor, contract; + BaseHouse.IsThereVendor( from.Location, from.Map, out vendor, out contract ); + + if ( vendor ) + { + from.SendLocalizedMessage( 1062677 ); // You cannot place a vendor or barkeep at this location. + } + else if ( contract ) + { + from.SendLocalizedMessage( 1062678 ); // You cannot place a vendor or barkeep on top of a rental contract! + } + else + { + Mobile v = new PlayerVendor( from, house ); + + v.Direction = from.Direction & Direction.Mask; + v.MoveToWorld( from.Location, from.Map ); + + v.SayTo( from, 503246 ); // Ah! it feels good to be working again. + + this.Delete(); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/PoolOfAcid.cs b/Scripts/Items/Misc/PoolOfAcid.cs new file mode 100644 index 0000000..bf68862 --- /dev/null +++ b/Scripts/Items/Misc/PoolOfAcid.cs @@ -0,0 +1,101 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Spells; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Items +{ + public class PoolOfAcid : Item + { + private TimeSpan m_Duration; + private int m_MinDamage; + private int m_MaxDamage; + private DateTime m_Created; + private bool m_Drying; + private Timer m_Timer; + + [Constructable] + public PoolOfAcid() : this( TimeSpan.FromSeconds( 10.0 ), 2, 5 ) + { + } + + public override string DefaultName { get { return "a pool of acid"; } } + + [Constructable] + public PoolOfAcid( TimeSpan duration, int minDamage, int maxDamage ) + : base( 0x122A ) + { + Hue = 0x3F; + Movable = false; + + m_MinDamage = minDamage; + m_MaxDamage = maxDamage; + m_Created = DateTime.Now; + m_Duration = duration; + + m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1 ), new TimerCallback( OnTick ) ); + } + + public override void OnAfterDelete() + { + if( m_Timer != null ) + m_Timer.Stop(); + } + + private void OnTick() + { + DateTime now = DateTime.Now; + TimeSpan age = now - m_Created; + + if( age > m_Duration ) { + Delete(); + } else { + if( !m_Drying && age > (m_Duration - age) ) + { + m_Drying = true; + ItemID = 0x122B; + } + + List toDamage = new List(); + + foreach( Mobile m in GetMobilesInRange( 0 ) ) + { + BaseCreature bc = m as BaseCreature; + + if( m.Alive && !m.IsDeadBondedPet && (bc == null || bc.Controlled || bc.Summoned) ) + { + toDamage.Add( m ); + } + } + + for ( int i = 0; i < toDamage.Count; i++ ) + Damage( toDamage[i] ); + } + } + public override bool OnMoveOver( Mobile m ) + { + Damage( m ); + return true; + } + + public void Damage ( Mobile m ) + { + m.Damage( Utility.RandomMinMax( m_MinDamage, m_MaxDamage ) ); + } + + public PoolOfAcid( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + //Don't serialize these + } + + public override void Deserialize( GenericReader reader ) + { + } + } +} diff --git a/Scripts/Items/Misc/PowerCrystal.cs b/Scripts/Items/Misc/PowerCrystal.cs new file mode 100644 index 0000000..3c5259e --- /dev/null +++ b/Scripts/Items/Misc/PowerCrystal.cs @@ -0,0 +1,45 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + public class PowerCrystal : Item + { + public override string DefaultName + { + get { return "power crystal"; } + } + + [Constructable] + public PowerCrystal() : base( 0x1F1C ) + { + Weight = 1.0; + } + + public PowerCrystal( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this.GetWorldLocation(), 3 )) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + else + from.SendAsciiMessage( "This looks like part of a larger contraption." ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/PowerGenerator.cs b/Scripts/Items/Misc/PowerGenerator.cs new file mode 100644 index 0000000..b068e90 --- /dev/null +++ b/Scripts/Items/Misc/PowerGenerator.cs @@ -0,0 +1,571 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class PowerGenerator : BaseAddon + { + [Constructable] + public PowerGenerator() : this( Utility.RandomMinMax( 3, 6 ) ) + { + } + + [Constructable] + public PowerGenerator( int sideLength ) + { + AddGeneratorComponent( 0x4FA1, 0, 0, 0 ); + AddGeneratorComponent( 0x76, -1, 0, 0 ); + AddGeneratorComponent( 0x75, 0, -1, 0 ); + AddGeneratorComponent( 0x37F4, 0, 0, 13 ); + + AddComponent( new ControlPanel( sideLength ), 1, 0, -2 ); + } + + public override bool ShareHue{ get{ return false; } } + + private void AddGeneratorComponent( int itemID, int x, int y, int z ) + { + AddonComponent component = new AddonComponent( itemID ); + component.Name = "a power generator"; + component.Hue = 0x451; + + AddComponent( component, x, y, z ); + } + + public PowerGenerator( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ControlPanel : AddonComponent + { + private static readonly TimeSpan m_UseTimeout = TimeSpan.FromMinutes( 2.0 ); + + public struct Node + { + private int m_X; + private int m_Y; + + public int X{ get{ return m_X; } set{ m_X = value; } } + public int Y{ get{ return m_Y; } set{ m_Y = value; } } + + public Node( int x, int y ) + { + m_X = x; + m_Y = y; + } + } + + private int m_SideLength; + private Node[] m_Path; + + [CommandProperty( AccessLevel.GameMaster )] + public int SideLength + { + get{ return m_SideLength; } + set + { + if ( value < 3 ) + value = 3; + else if ( value > 6 ) + value = 6; + + if ( m_SideLength != value ) + { + m_SideLength = value; + InitPath(); + } + } + } + + public Node[] Path{ get{ return m_Path; } } + + public override string DefaultName + { + get { return "a control panel"; } + } + + public ControlPanel( int sideLength ) : base( 0xBDC ) + { + Hue = 0x835; + + SideLength = sideLength; + } + + private enum PathDirection + { + Left, + Up, + Right, + Down + } + + public void InitPath() + { + // Depth-First Search algorithm + + int totalNodes = SideLength * SideLength; + + Node[] stack = new Node[totalNodes]; + Node current = stack[0] = new Node( 0, 0 ); + int stackSize = 1; + + bool[,] visited = new bool[SideLength, SideLength]; + visited[0, 0] = true; + + while ( true ) + { + PathDirection[] choices = new PathDirection[4]; + int count = 0; + + if ( current.X > 0 && !visited[current.X - 1, current.Y] ) + choices[count++] = PathDirection.Left; + + if ( current.Y > 0 && !visited[current.X, current.Y - 1] ) + choices[count++] = PathDirection.Up; + + if ( current.X < SideLength - 1 && !visited[current.X + 1, current.Y] ) + choices[count++] = PathDirection.Right; + + if ( current.Y < SideLength - 1 && !visited[current.X, current.Y + 1] ) + choices[count++] = PathDirection.Down; + + if ( count > 0 ) + { + PathDirection dir = choices[Utility.Random( count )]; + + switch ( dir ) + { + case PathDirection.Left: + current = new Node( current.X - 1, current.Y ); + break; + case PathDirection.Up: + current = new Node( current.X, current.Y - 1 ); + break; + case PathDirection.Right: + current = new Node( current.X + 1, current.Y ); + break; + default: + current = new Node( current.X, current.Y + 1 ); + break; + } + + stack[stackSize++] = current; + + if ( current.X == SideLength - 1 && current.Y == SideLength - 1 ) + break; + + visited[current.X, current.Y] = true; + } + else + { + current = stack[--stackSize - 1]; + } + } + + m_Path = new Node[stackSize]; + + for ( int i = 0; i < stackSize; i++ ) + { + m_Path[i] = stack[i]; + } + + if ( m_User != null ) + { + m_User.CloseGump( typeof( GameGump ) ); + m_User = null; + } + } + + private Mobile m_User; + private DateTime m_LastUse; + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this, 3 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + + if ( m_User != null ) + { + if ( m_User == from ) + return; + + if ( m_User.Deleted || m_User.Map != Map || !m_User.InRange( this, 3 ) + || m_User.NetState == null || DateTime.Now - m_LastUse >= m_UseTimeout ) + { + m_User.CloseGump( typeof( GameGump ) ); + } + else + { + from.SendMessage( "Someone is currently using the control panel." ); + return; + } + } + + m_User = from; + m_LastUse = DateTime.Now; + + from.SendGump( new GameGump( this, from, 0, false ) ); + } + + private class GameGump : Gump + { + private enum NodeHue + { + Gray, + Blue, + Red + } + + private ControlPanel m_Panel; + private Mobile m_From; + private int m_Step; + + public GameGump( ControlPanel panel, Mobile from, int step, bool hint ) : base( 5, 30 ) + { + m_Panel = panel; + m_From = from; + m_Step = step; + + int sideLength = panel.SideLength; + + AddBackground( 50, 0, 530, 410, 0xA28 ); + + AddImage( 0, 0, 0x28C8 ); + AddImage( 547, 0, 0x28C9 ); + + AddBackground( 95, 20, 442, 90, 0xA28 ); + + AddHtml( 229, 35, 300, 45, "GENERATOR CONTROL PANEL", false, false ); + + AddHtml( 223, 60, 300, 70, "Use the Directional Controls to", false, false ); + AddHtml( 253, 75, 300, 85, "Close the Grid Circuit", false, false ); + + AddImage( 140, 40, 0x28D3 ); + AddImage( 420, 40, 0x28D3 ); + + AddBackground( 365, 120, 178, 210, 0x1400 ); + + AddImage( 365, 115, 0x28D4 ); + AddImage( 365, 288, 0x28D4 ); + + AddImage( 414, 189, 0x589 ); + AddImage( 435, 210, 0xA52 ); + + AddButton( 408, 222, 0x29EA, 0x29EC, 1, GumpButtonType.Reply, 0 ); // Left + AddButton( 448, 185, 0x29CC, 0x29CE, 2, GumpButtonType.Reply, 0 ); // Up + AddButton( 473, 222, 0x29D6, 0x29D8, 3, GumpButtonType.Reply, 0 ); // Right + AddButton( 448, 243, 0x29E0, 0x29E2, 4, GumpButtonType.Reply, 0 ); // Down + + AddBackground( 90, 115, 30 + 40 * sideLength, 30 + 40 * sideLength, 0xA28 ); + AddBackground( 100, 125, 10 + 40 * sideLength, 10 + 40 * sideLength, 0x1400 ); + + for ( int i = 0; i < sideLength; i++ ) + { + for ( int j = 0; j < sideLength - 1; j++ ) + { + AddImage( 120 + 40 * i, 162 + 40 * j, 0x13F9 ); + } + } + + for ( int i = 0; i < sideLength - 1; i++ ) + { + for ( int j = 0; j < sideLength; j++ ) + { + AddImage( 138 + 40 * i, 147 + 40 * j, 0x13FD ); + } + } + + Node[] path = panel.Path; + + NodeHue[,] hues = new NodeHue[sideLength, sideLength]; + + for ( int i = 0; i <= step; i++ ) + { + Node n = path[i]; + hues[n.X, n.Y] = NodeHue.Blue; + } + + Node lastNode = path[path.Length - 1]; + hues[lastNode.X, lastNode.Y] = NodeHue.Red; + + for ( int i = 0; i < sideLength; i++ ) + { + for ( int j = 0; j < sideLength; j++ ) + { + AddNode( 110 + 40 * i, 135 + 40 * j, hues[i, j] ); + } + } + + Node curNode = path[step]; + AddImage( 118 + 40 * curNode.X, 143 + 40 * curNode.Y, 0x13A8 ); + + if ( hint ) + { + Node nextNode = path[step + 1]; + AddImage( 119 + 40 * nextNode.X, 143 + 40 * nextNode.Y, 0x939 ); + } + + if ( from.Skills.Lockpicking.Value >= 65.0 ) + { + AddButton( 365, 350, 0xFA6, 0xFA7, 5, GumpButtonType.Reply, 0 ); + AddHtml( 405, 345, 140, 40, "Attempt to Decipher the Circuit Path", false, false ); + } + } + + private void AddNode( int x, int y, NodeHue hue ) + { + int id; + switch ( hue ) + { + case NodeHue.Gray: id = 0x25F8; break; + case NodeHue.Blue: id = 0x868; break; + default: id = 0x9A8; break; + } + + AddImage( x, y, id ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Panel.Deleted || info.ButtonID == 0 || !m_From.CheckAlive() ) + { + m_Panel.m_User = null; + return; + } + + if ( m_From.Map != m_Panel.Map || !m_From.InRange( m_Panel, 3 ) ) + { + m_From.SendLocalizedMessage( 500446 ); // That is too far away. + m_Panel.m_User = null; + return; + } + + Node nextNode = m_Panel.Path[m_Step + 1]; + + if ( info.ButtonID == 5 ) // Attempt to Decipher + { + double lockpicking = m_From.Skills.Lockpicking.Value; + + if ( lockpicking < 65.0 ) + return; + + m_From.PlaySound( 0x241 ); + + if ( 40.0 + Utility.RandomDouble() * 80.0 < lockpicking ) + { + m_From.SendGump( new GameGump( m_Panel, m_From, m_Step, true ) ); + m_Panel.m_LastUse = DateTime.Now; + } + else + { + m_Panel.DoDamage( m_From ); + m_Panel.m_User = null; + } + } + else + { + Node curNode = m_Panel.Path[m_Step]; + + int newX, newY; + switch ( info.ButtonID ) + { + case 1: // Left + newX = curNode.X - 1; + newY = curNode.Y; + break; + case 2: // Up + newX = curNode.X; + newY = curNode.Y - 1; + break; + case 3: // Right + newX = curNode.X + 1; + newY = curNode.Y; + break; + case 4: // Down + newX = curNode.X; + newY = curNode.Y + 1; + break; + + default: + return; + } + + if ( nextNode.X == newX && nextNode.Y == newY ) + { + if ( m_Step + 1 == m_Panel.Path.Length - 1 ) + { + m_Panel.Solve( m_From ); + m_Panel.m_User = null; + } + else + { + m_From.PlaySound( 0x1F4 ); + m_From.SendGump( new GameGump( m_Panel, m_From, m_Step + 1, false ) ); + m_Panel.m_LastUse = DateTime.Now; + } + } + else + { + m_Panel.DoDamage( m_From ); + m_Panel.m_User = null; + } + } + } + } + + private Hashtable m_DamageTable = new Hashtable(); + + public void DoDamage( Mobile to ) + { + to.Send( new UnicodeMessage( Serial, ItemID, MessageType.Regular, 0x3B2, 3, "", "", "The generator shoots an arc of electricity at you!" ) ); + to.BoltEffect( 0 ); + to.LocalOverheadMessage( MessageType.Regular, 0xC9, true, "* Your body convulses from electric shock *" ); + to.NonlocalOverheadMessage( MessageType.Regular, 0xC9, true, string.Format( "* {0} spasms from electric shock *", to.Name ) ); + + AOS.Damage( to, to, 60, 0, 0, 0, 0, 100 ); + + if ( !to.Alive ) + return; + + if ( m_DamageTable[to] == null ) + { + to.Frozen = true; + + DamageTimer timer = new DamageTimer( this, to ); + m_DamageTable[to] = timer; + + timer.Start(); + } + } + + private class DamageTimer : Timer + { + private ControlPanel m_Panel; + private Mobile m_To; + private int m_Step; + + public DamageTimer( ControlPanel panel, Mobile to ) : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + m_Panel = panel; + m_To = to; + m_Step = 0; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if ( m_Panel.Deleted || m_To.Deleted || !m_To.Alive ) + { + End(); + return; + } + + m_To.PlaySound( 0x28 ); + + m_To.LocalOverheadMessage( MessageType.Regular, 0xC9, true, "* Your body convulses from electric shock *" ); + m_To.NonlocalOverheadMessage( MessageType.Regular, 0xC9, true, string.Format( "* {0} spasms from electric shock *", m_To.Name ) ); + + AOS.Damage( m_To, m_To, 20, 0, 0, 0, 0, 100 ); + + if ( ++m_Step >= 3 || !m_To.Alive ) + { + End(); + } + } + + private void End() + { + m_Panel.m_DamageTable.Remove( m_To ); + m_To.Frozen = false; + + Stop(); + } + } + + public void Solve( Mobile from ) + { + Effects.PlaySound( Location, Map, 0x211 ); + Effects.PlaySound( Location, Map, 0x1F3 ); + + Effects.SendLocationEffect( Location, Map, 0x36B0, 4, 4 ); + Effects.SendLocationEffect( new Point3D( X - 1, Y - 1, Z + 2 ), Map, 0x36B0, 4, 4 ); + Effects.SendLocationEffect( new Point3D( X - 2, Y - 1, Z + 2 ), Map, 0x36B0, 4, 4 ); + + from.SendMessage( "You scrounge some gems from the wreckage." ); + + for ( int i = 0; i < SideLength; i++ ) + { + from.AddToBackpack( new ArcaneGem() ); + } + + from.AddToBackpack( new Diamond( SideLength ) ); + + Item ore = new ShadowOre( 9 ); + ore.MoveToWorld( new Point3D( X - 1, Y, Z + 2 ), Map ); + + ore = new ShadowOre( 14 ); + ore.MoveToWorld( new Point3D( X - 2, Y - 1, Z + 2 ), Map ); + + Delete(); + } + + public ControlPanel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_SideLength ); + + writer.WriteEncodedInt( (int) m_Path.Length ); + for ( int i = 0; i < m_Path.Length; i++ ) + { + Node cur = m_Path[i]; + + writer.WriteEncodedInt( cur.X ); + writer.WriteEncodedInt( cur.Y ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_SideLength = reader.ReadEncodedInt(); + + m_Path = new Node[reader.ReadEncodedInt()]; + for ( int i = 0; i < m_Path.Length; i++ ) + { + m_Path[i] = new Node( reader.ReadEncodedInt(), reader.ReadEncodedInt() ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Prism of Light/CrystallineFragments.cs b/Scripts/Items/Misc/Prism of Light/CrystallineFragments.cs new file mode 100644 index 0000000..51faefc --- /dev/null +++ b/Scripts/Items/Misc/Prism of Light/CrystallineFragments.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CrystallineFragments : Item + { + public override int LabelNumber{ get{ return 1073160; } } // Crystalline Fragments + + [Constructable] + public CrystallineFragments() : base( 0x223B ) + { + LootType = LootType.Blessed; + Hue = 0x47E; + } + + public CrystallineFragments( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Prism of Light/IcyHeart.cs b/Scripts/Items/Misc/Prism of Light/IcyHeart.cs new file mode 100644 index 0000000..c258486 --- /dev/null +++ b/Scripts/Items/Misc/Prism of Light/IcyHeart.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class IcyHeart : Item + { + public override int LabelNumber{ get{ return 1073162; } } // Icy Heart + + [Constructable] + public IcyHeart() : base( 0x24B ) + { + } + + public IcyHeart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Prism of Light/LuckyDagger.cs b/Scripts/Items/Misc/Prism of Light/LuckyDagger.cs new file mode 100644 index 0000000..a8f50bf --- /dev/null +++ b/Scripts/Items/Misc/Prism of Light/LuckyDagger.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LuckyDagger : Item + { + [Constructable] + public LuckyDagger() : base( 0xF52 ) + { + Hue = 0x8A5; + } + + public LuckyDagger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Prism of Light/ProtectorsEssence.cs b/Scripts/Items/Misc/Prism of Light/ProtectorsEssence.cs new file mode 100644 index 0000000..5abbbaa --- /dev/null +++ b/Scripts/Items/Misc/Prism of Light/ProtectorsEssence.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ProtectorsEssence : Item + { + public override int LabelNumber{ get{ return 1073159; } } // Protector's Essence + + [Constructable] + public ProtectorsEssence() : base( 0x23F ) + { + } + + public ProtectorsEssence( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Prism of Light/ShimmeringCrystal.cs b/Scripts/Items/Misc/Prism of Light/ShimmeringCrystal.cs new file mode 100644 index 0000000..63c4585 --- /dev/null +++ b/Scripts/Items/Misc/Prism of Light/ShimmeringCrystal.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShimmeringCrystals : Item + { + public override int LabelNumber{ get{ return 1075095; } } // Shimmering Crystals + public override bool ForceShowProperties{ get{ return true; } } + + private static readonly int[] m_ItemIDs = new int[] + { + 0x2206, 0x2207, 0x2208, 0x2209, 0x220A, 0x220B, 0x220C, 0x220D, 0x220E, + 0x2210, 0x2211, 0x2212, 0x2213, 0x2214, 0x2215, 0x2216, 0x2217, 0x2218, + 0x221A, 0x221B, 0x221C, 0x221D, 0x221E, 0x221F, 0x2220, 0x2221, 0x2222, + 0x2224, 0x2225, 0x2226, 0x2227, 0x2228, 0x2229, 0x222A, 0x222B, 0x222C + }; + + [Constructable] + public ShimmeringCrystals() : base( Utility.RandomList( m_ItemIDs ) ) + { + } + + public ShimmeringCrystals( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/PromotionalToken.cs b/Scripts/Items/Misc/PromotionalToken.cs new file mode 100644 index 0000000..979c60f --- /dev/null +++ b/Scripts/Items/Misc/PromotionalToken.cs @@ -0,0 +1,159 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public abstract class PromotionalToken : Item + { + public abstract Item CreateItemFor( Mobile from ); + + public abstract TextDefinition ItemName{ get; } + public abstract TextDefinition ItemReceiveMessage { get; } + public abstract TextDefinition ItemGumpName { get; } + + public PromotionalToken() : base( 0x2AAA ) + { + LootType = LootType.Blessed; + Light = LightType.Circle300; + Weight = 5.0; + } + + public PromotionalToken( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070998, ItemName.ToString() ); // Use this to redeem
your ~1_PROMO~ + } + + public override void OnDoubleClick( Mobile from ) + { + if( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + else + { + from.CloseGump( typeof( PromotionalTokenGump ) ); + from.SendGump( new PromotionalTokenGump( this ) ); + } + } + + public override void OnRemoved( object parent ) + { + Mobile m = null; + + if( parent is Item ) + m = ((Item)parent).RootParent as Mobile; + else if( parent is Mobile ) + m = (Mobile)parent; + + if( m != null ) + m.CloseGump( typeof( PromotionalTokenGump ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int LabelNumber { get { return 1070997; } } // A promotional token + + + private class PromotionalTokenGump : Gump + { + private PromotionalToken m_Token; + + public PromotionalTokenGump( PromotionalToken token ) : base( 10, 10 ) + { + m_Token = token; + + AddPage( 0 ); + + AddBackground( 0, 0, 240, 135, 0x2422 ); + AddHtmlLocalized( 15, 15, 210, 75, 1070972, 0x0, true, false ); // Click "OKAY" to redeem the following promotional item: + TextDefinition.AddHtmlText( this, 15, 60, 210, 75, m_Token.ItemGumpName, false, false ); + + AddButton( 160, 95, 0xF7, 0xF8, 1, GumpButtonType.Reply, 0 ); //Okay + AddButton( 90, 95, 0xF2, 0xF1, 0, GumpButtonType.Reply, 0 ); //Cancel + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if( info.ButtonID != 1 ) + return; + + Mobile from = sender.Mobile; + + if( !m_Token.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + else + { + Item i = m_Token.CreateItemFor( from ); + + if( i != null ) + { + from.BankBox.AddItem( i ); + TextDefinition.SendMessageTo( from, m_Token.ItemReceiveMessage ); + m_Token.Delete(); + } + } + } + } + } + + public class SoulstoneFragmentToken : PromotionalToken + { + + public override Item CreateItemFor( Mobile from ) + { + if( from != null && from.Account != null ) + return new SoulstoneFragment( from.Account.ToString() ); + else + return null; + } + + public override TextDefinition ItemGumpName{ get{ return 1070999; } }//
Soulstone Fragment
+ public override TextDefinition ItemName { get { return 1071000; } }//soulstone fragment + public override TextDefinition ItemReceiveMessage{ get{ return 1070976; } } // A soulstone fragment has been created in your bank box. + + [Constructable] + public SoulstoneFragmentToken() : base() + { + } + + public SoulstoneFragmentToken( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Misc/PublicMoongate.cs b/Scripts/Items/Misc/PublicMoongate.cs new file mode 100644 index 0000000..f72f77e --- /dev/null +++ b/Scripts/Items/Misc/PublicMoongate.cs @@ -0,0 +1,470 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Commands; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class PublicMoongate : Item + { + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + [Constructable] + public PublicMoongate() : base( 0xF6C ) + { + Movable = false; + Light = LightType.Circle300; + } + + public PublicMoongate( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.Player ) + return; + + if ( from.InRange( GetWorldLocation(), 1 ) ) + UseGate( from ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + public override bool OnMoveOver( Mobile m ) + { + // Changed so criminals are not blocked by it. + if ( m.Player ) + UseGate( m ); + + return true; + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m is PlayerMobile ) + { + if ( !Utility.InRange( m.Location, this.Location, 1 ) && Utility.InRange( oldLocation, this.Location, 1 ) ) + m.CloseGump( typeof( MoongateGump ) ); + } + } + + public bool UseGate( Mobile m ) + { + if ( m.Criminal ) + { + m.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( m ) ) + { + m.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + return false; + } + else if ( m.Spell != null ) + { + m.SendLocalizedMessage( 1049616 ); // You are too busy to do that at the moment. + return false; + } + else + { + m.CloseGump( typeof( MoongateGump ) ); + m.SendGump( new MoongateGump( m, this ) ); + + if ( !m.Hidden || m.AccessLevel == AccessLevel.Player ) + Effects.PlaySound( m.Location, m.Map, 0x20E ); + + return true; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public static void Initialize() + { + CommandSystem.Register( "MoonGen", AccessLevel.Administrator, new CommandEventHandler( MoonGen_OnCommand ) ); + } + + [Usage( "MoonGen" )] + [Description( "Generates public moongates. Removes all old moongates." )] + public static void MoonGen_OnCommand( CommandEventArgs e ) + { + DeleteAll(); + + int count = 0; + + count += MoonGen( PMList.Trammel ); + count += MoonGen( PMList.Felucca ); + count += MoonGen( PMList.Ilshenar ); + count += MoonGen( PMList.Malas ); + count += MoonGen( PMList.Tokuno ); + + World.Broadcast( 0x35, true, "{0} moongates generated.", count ); + } + + private static void DeleteAll() + { + List list = new List(); + + foreach ( Item item in World.Items.Values ) + { + if ( item is PublicMoongate ) + list.Add( item ); + } + + foreach ( Item item in list ) + item.Delete(); + + if ( list.Count > 0 ) + World.Broadcast( 0x35, true, "{0} moongates removed.", list.Count ); + } + + private static int MoonGen( PMList list ) + { + foreach ( PMEntry entry in list.Entries ) + { + Item item = new PublicMoongate(); + + item.MoveToWorld( entry.Location, list.Map ); + + if ( entry.Number == 1060642 ) // Umbra + item.Hue = 0x497; + } + + return list.Entries.Length; + } + } + + public class PMEntry + { + private Point3D m_Location; + private int m_Number; + + public Point3D Location + { + get + { + return m_Location; + } + } + + public int Number + { + get + { + return m_Number; + } + } + + public PMEntry( Point3D loc, int number ) + { + m_Location = loc; + m_Number = number; + } + } + + public class PMList + { + private int m_Number, m_SelNumber; + private Map m_Map; + private PMEntry[] m_Entries; + + public int Number + { + get + { + return m_Number; + } + } + + public int SelNumber + { + get + { + return m_SelNumber; + } + } + + public Map Map + { + get + { + return m_Map; + } + } + + public PMEntry[] Entries + { + get + { + return m_Entries; + } + } + + public PMList( int number, int selNumber, Map map, PMEntry[] entries ) + { + m_Number = number; + m_SelNumber = selNumber; + m_Map = map; + m_Entries = entries; + } + + public static readonly PMList Trammel = + new PMList(1012000, 1012012, Map.Trammel, new PMEntry[] + { + new PMEntry( new Point3D( 4467, 1283, 5 ), 1012003 ), // Moonglow + new PMEntry( new Point3D( 1336, 1997, 5 ), 1012004 ), // Britain + new PMEntry( new Point3D( 1499, 3771, 5 ), 1012005 ), // Jhelom + new PMEntry( new Point3D( 771, 752, 5 ), 1012006 ), // Yew + new PMEntry( new Point3D( 2701, 692, 5 ), 1012007 ), // Minoc + new PMEntry( new Point3D( 1828, 2948,-20), 1012008 ), // Trinsic + new PMEntry( new Point3D( 643, 2067, 5 ), 1012009 ), // Skara Brae + /* Dynamic Z for Magincia to support both old and new maps. */ + new PMEntry( new Point3D( 3563, 2139, Map.Trammel.GetAverageZ( 3563, 2139 ) ), 1012010 ), // (New) Magincia + new PMEntry( new Point3D( 3450, 2677, 25), 1078098 ) // New Haven + }); + + public static readonly PMList Felucca = + new PMList(1012001, 1012013, Map.Felucca, new PMEntry[] + { + new PMEntry( new Point3D( 4467, 1283, 5 ), 1012003 ), // Moonglow + new PMEntry( new Point3D( 1336, 1997, 5 ), 1012004 ), // Britain + new PMEntry( new Point3D( 1499, 3771, 5 ), 1012005 ), // Jhelom + new PMEntry( new Point3D( 771, 752, 5 ), 1012006 ), // Yew + new PMEntry( new Point3D( 2701, 692, 5 ), 1012007 ), // Minoc + new PMEntry( new Point3D( 1828, 2948,-20), 1012008 ), // Trinsic + new PMEntry( new Point3D( 643, 2067, 5 ), 1012009 ), // Skara Brae + /* Dynamic Z for Magincia to support both old and new maps. */ + new PMEntry( new Point3D( 3563, 2139, Map.Felucca.GetAverageZ( 3563, 2139 ) ), 1012010 ), // (New) Magincia + new PMEntry( new Point3D( 2711, 2234, 0 ), 1019001 ) // Buccaneer's Den + }); + + public static readonly PMList Ilshenar = + new PMList( 1012002, 1012014, Map.Ilshenar, new PMEntry[] + { + new PMEntry( new Point3D( 1215, 467, -13 ), 1012015 ), // Compassion + new PMEntry( new Point3D( 722, 1366, -60 ), 1012016 ), // Honesty + new PMEntry( new Point3D( 744, 724, -28 ), 1012017 ), // Honor + new PMEntry( new Point3D( 281, 1016, 0 ), 1012018 ), // Humility + new PMEntry( new Point3D( 987, 1011, -32 ), 1012019 ), // Justice + new PMEntry( new Point3D( 1174, 1286, -30 ), 1012020 ), // Sacrifice + new PMEntry( new Point3D( 1532, 1340, - 3 ), 1012021 ), // Spirituality + new PMEntry( new Point3D( 528, 216, -45 ), 1012022 ), // Valor + new PMEntry( new Point3D( 1721, 218, 96 ), 1019000 ) // Chaos + } ); + + public static readonly PMList Malas = + new PMList( 1060643, 1062039, Map.Malas, new PMEntry[] + { + new PMEntry( new Point3D( 1015, 527, -65 ), 1060641 ), // Luna + new PMEntry( new Point3D( 1997, 1386, -85 ), 1060642 ) // Umbra + } ); + + public static readonly PMList Tokuno = + new PMList( 1063258, 1063415, Map.Tokuno, new PMEntry[] + { + new PMEntry( new Point3D( 1169, 998, 41 ), 1063412 ), // Isamu-Jima + new PMEntry( new Point3D( 802, 1204, 25 ), 1063413 ), // Makoto-Jima + new PMEntry( new Point3D( 270, 628, 15 ), 1063414 ) // Homare-Jima + } ); + + public static readonly PMList[] UORLists = new PMList[] { Trammel/*, Felucca*/ }; + public static readonly PMList[] UORListsYoung = new PMList[] { Trammel }; + public static readonly PMList[] LBRLists = new PMList[] { Trammel/*, Felucca, Ilshenar*/ }; + public static readonly PMList[] LBRListsYoung = new PMList[] { Trammel/*, Ilshenar*/ }; + public static readonly PMList[] AOSLists = new PMList[] { Trammel/*, Felucca, Ilshenar, Malas*/ }; + public static readonly PMList[] AOSListsYoung = new PMList[] { Trammel/*, Ilshenar, Malas */}; + public static readonly PMList[] SELists = new PMList[] { Trammel/*, Felucca, Ilshenar, Malas, Tokuno*/ }; + public static readonly PMList[] SEListsYoung = new PMList[] { Trammel/*, Ilshenar, Malas, Tokuno*/ }; + public static readonly PMList[] RedLists = new PMList[] { /*Felucca*/ }; + public static readonly PMList[] SigilLists = new PMList[] { /*Felucca*/ }; + } + + public class MoongateGump : Gump + { + private Mobile m_Mobile; + private Item m_Moongate; + private PMList[] m_Lists; + + public MoongateGump( Mobile mobile, Item moongate ) : base( 100, 100 ) + { + m_Mobile = mobile; + m_Moongate = moongate; + + PMList[] checkLists; + + if ( mobile.Player ) + { + if ( Factions.Sigil.ExistsOn( mobile ) ) + { + checkLists = PMList.SigilLists; + } + else if ( mobile.Kills >= 5 ) + { + checkLists = PMList.RedLists; + } + else + { + ClientFlags flags = mobile.NetState == null ? ClientFlags.None : mobile.NetState.Flags; + bool young = mobile is PlayerMobile ? ((PlayerMobile)mobile).Young : false; + + if ( Core.SE && (flags & ClientFlags.Tokuno) != 0 ) + checkLists = young ? PMList.SEListsYoung : PMList.SELists; + else if ( Core.AOS && (flags & ClientFlags.Malas) != 0 ) + checkLists = young ? PMList.AOSListsYoung : PMList.AOSLists; + else if ( (flags & ClientFlags.Ilshenar) != 0 ) + checkLists = young ? PMList.LBRListsYoung : PMList.LBRLists; + else + checkLists = young ? PMList.UORListsYoung : PMList.UORLists; + } + } + else + { + checkLists = PMList.SELists; + } + + m_Lists = new PMList[checkLists.Length]; + + for ( int i = 0; i < m_Lists.Length; ++i ) + m_Lists[i] = checkLists[i]; + + for ( int i = 0; i < m_Lists.Length; ++i ) + { + if ( m_Lists[i].Map == mobile.Map ) + { + PMList temp = m_Lists[i]; + + m_Lists[i] = m_Lists[0]; + m_Lists[0] = temp; + + break; + } + } + + AddPage( 0 ); + + AddBackground( 0, 0, 380, 280, 5054 ); + + AddButton( 10, 210, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 210, 140, 25, 1011036, false, false ); // OKAY + + AddButton( 10, 235, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 235, 140, 25, 1011012, false, false ); // CANCEL + + AddHtmlLocalized( 5, 5, 200, 20, 1012011, false, false ); // Pick your destination: + + for ( int i = 0; i < checkLists.Length; ++i ) + { + AddButton( 10, 35 + (i * 25), 2117, 2118, 0, GumpButtonType.Page, Array.IndexOf( m_Lists, checkLists[i] ) + 1 ); + AddHtmlLocalized( 30, 35 + (i * 25), 150, 20, checkLists[i].Number, false, false ); + } + + for ( int i = 0; i < m_Lists.Length; ++i ) + RenderPage( i, Array.IndexOf( checkLists, m_Lists[i] ) ); + } + + private void RenderPage( int index, int offset ) + { + PMList list = m_Lists[index]; + + AddPage( index + 1 ); + + AddButton( 10, 35 + (offset * 25), 2117, 2118, 0, GumpButtonType.Page, index + 1 ); + AddHtmlLocalized( 30, 35 + (offset * 25), 150, 20, list.SelNumber, false, false ); + + PMEntry[] entries = list.Entries; + + for ( int i = 0; i < entries.Length; ++i ) + { + AddRadio( 200, 35 + (i * 25), 210, 211, false, (index * 100) + i ); + AddHtmlLocalized( 225, 35 + (i * 25), 150, 20, entries[i].Number, false, false ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 0 ) // Cancel + return; + else if ( m_Mobile.Deleted || m_Moongate.Deleted || m_Mobile.Map == null ) + return; + + int[] switches = info.Switches; + + if ( switches.Length == 0 ) + return; + + int switchID = switches[0]; + int listIndex = switchID / 100; + int listEntry = switchID % 100; + + if ( listIndex < 0 || listIndex >= m_Lists.Length ) + return; + + PMList list = m_Lists[listIndex]; + + if ( listEntry < 0 || listEntry >= list.Entries.Length ) + return; + + PMEntry entry = list.Entries[listEntry]; + + if ( !m_Mobile.InRange( m_Moongate.GetWorldLocation(), 1 ) || m_Mobile.Map != m_Moongate.Map ) + { + m_Mobile.SendLocalizedMessage( 1019002 ); // You are too far away to use the gate. + } + else if ( m_Mobile.Player && m_Mobile.Kills >= 5 && list.Map != Map.Felucca ) + { + m_Mobile.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( Factions.Sigil.ExistsOn( m_Mobile ) && list.Map != Factions.Faction.Facet ) + { + m_Mobile.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( m_Mobile.Criminal ) + { + m_Mobile.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + } + else if ( SpellHelper.CheckCombat( m_Mobile ) ) + { + m_Mobile.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + } + else if ( m_Mobile.Spell != null ) + { + m_Mobile.SendLocalizedMessage( 1049616 ); // You are too busy to do that at the moment. + } + else if ( m_Mobile.Map == list.Map && m_Mobile.InRange( entry.Location, 1 ) ) + { + m_Mobile.SendLocalizedMessage( 1019003 ); // You are already there. + } + else + { + BaseCreature.TeleportPets( m_Mobile, entry.Location, list.Map ); + + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + m_Mobile.Hidden = true; + + m_Mobile.MoveToWorld( entry.Location, list.Map ); + + Effects.PlaySound( entry.Location, list.Map, 0x1FE ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Rares.cs b/Scripts/Items/Misc/Rares.cs new file mode 100644 index 0000000..b279d6b --- /dev/null +++ b/Scripts/Items/Misc/Rares.cs @@ -0,0 +1,718 @@ +using System; + +namespace Server.Items +{ + public class Rope : Item + { + [Constructable] + public Rope() : this( 1 ) + { + } + + [Constructable] + public Rope( int amount ) : base( 0x14F8 ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + + + public Rope( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class IronWire : Item + { + [Constructable] + public IronWire() : this( 1 ) + { + } + + [Constructable] + public IronWire( int amount ) : base( 0x1876 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + + + public IronWire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 && Weight == 2.0 ) + Weight = 5.0; + } + } + + public class SilverWire : Item + { + [Constructable] + public SilverWire() : this( 1 ) + { + } + + [Constructable] + public SilverWire( int amount ) : base( 0x1877 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + + + public SilverWire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 && Weight == 2.0 ) + Weight = 5.0; + } + } + + public class GoldWire : Item + { + [Constructable] + public GoldWire() : this( 1 ) + { + } + + [Constructable] + public GoldWire( int amount ) : base( 0x1878 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + + + public GoldWire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 && Weight == 2.0 ) + Weight = 5.0; + } + } + + public class CopperWire : Item + { + [Constructable] + public CopperWire() : this( 1 ) + { + } + + [Constructable] + public CopperWire( int amount ) : base( 0x1879 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + + + public CopperWire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 && Weight == 2.0 ) + Weight = 5.0; + } + } + + public class WhiteDriedFlowers : Item + { + [Constructable] + public WhiteDriedFlowers() : this( 1 ) + { + } + + [Constructable] + public WhiteDriedFlowers( int amount ) : base( 0xC3C ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + + + public WhiteDriedFlowers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GreenDriedFlowers : Item + { + [Constructable] + public GreenDriedFlowers() : this( 1 ) + { + } + + [Constructable] + public GreenDriedFlowers( int amount ) : base( 0xC3E ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + + + public GreenDriedFlowers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DriedOnions : Item + { + [Constructable] + public DriedOnions() : this( 1 ) + { + } + + [Constructable] + public DriedOnions( int amount ) : base( 0xC40 ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + + + public DriedOnions( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DriedHerbs : Item + { + [Constructable] + public DriedHerbs() : this( 1 ) + { + } + + [Constructable] + public DriedHerbs( int amount ) : base( 0xC42 ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + + + public DriedHerbs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class HorseShoes : Item + { + [Constructable] + public HorseShoes() : base( 0xFB6 ) + { + Weight = 3.0; + } + + public HorseShoes( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ForgedMetal : Item + { + [Constructable] + public ForgedMetal() : base( 0xFB8 ) + { + Weight = 5.0; + } + + public ForgedMetal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Whip : Item + { + [Constructable] + public Whip() : base( 0x166E ) + { + Weight = 1.0; + } + + public Whip( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PaintsAndBrush : Item + { + [Constructable] + public PaintsAndBrush() : base( 0xFC1 ) + { + Weight = 1.0; + } + + public PaintsAndBrush( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PenAndInk : Item + { + [Constructable] + public PenAndInk() : base( 0xFBF ) + { + Weight = 1.0; + } + + public PenAndInk( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ChiselsNorth : Item + { + [Constructable] + public ChiselsNorth() : base( 0x1026 ) + { + Weight = 1.0; + } + + public ChiselsNorth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ChiselsWest : Item + { + [Constructable] + public ChiselsWest() : base( 0x1027 ) + { + Weight = 1.0; + } + + public ChiselsWest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtyPan : Item + { + [Constructable] + public DirtyPan() : base( 0x9E8 ) + { + Weight = 1.0; + } + + public DirtyPan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtySmallRoundPot : Item + { + [Constructable] + public DirtySmallRoundPot() : base( 0x9E7 ) + { + Weight = 1.0; + } + + public DirtySmallRoundPot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtyPot : Item + { + [Constructable] + public DirtyPot() : base( 0x9E6 ) + { + Weight = 1.0; + } + + public DirtyPot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtyRoundPot : Item + { + [Constructable] + public DirtyRoundPot() : base( 0x9DF ) + { + Weight = 1.0; + } + + public DirtyRoundPot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtyFrypan : Item + { + [Constructable] + public DirtyFrypan() : base( 0x9DE ) + { + Weight = 1.0; + } + + public DirtyFrypan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtySmallPot : Item + { + [Constructable] + public DirtySmallPot() : base( 0x9DD ) + { + Weight = 1.0; + } + + public DirtySmallPot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DirtyKettle : Item + { + [Constructable] + public DirtyKettle() : base( 0x9DC ) + { + Weight = 1.0; + } + + public DirtyKettle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Scales.cs b/Scripts/Items/Misc/Scales.cs new file mode 100644 index 0000000..54a24e8 --- /dev/null +++ b/Scripts/Items/Misc/Scales.cs @@ -0,0 +1,93 @@ +using System; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class Scales : Item + { + [Constructable] + public Scales() : base( 0x1852 ) + { + Weight = 4.0; + } + + public Scales( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 502431 ); // What would you like to weigh? + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private Scales m_Item; + + public InternalTarget( Scales item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + string message; + + if ( targeted == m_Item ) + { + message = "It cannot weight itself."; + } + else if ( targeted is Item ) + { + Item item = (Item)targeted; + object root = item.RootParent; + + if ( (root != null && root != from) || item.Parent == from ) + { + message = "You decide that item's current location is too awkward to get an accurate result."; + } + else if ( item.Movable ) + { + if ( item.Amount > 1 ) + message = "You place one item on the scale. "; + else + message = "You place that item on the scale. "; + + double weight = item.Weight; + + if ( weight <= 0.0 ) + message += "It is lighter than a feather."; + else + message += String.Format( "It weighs {0} stones.", weight ); + } + else + { + message = "You cannot weigh that object."; + } + } + else + { + message = "You cannot weigh that object."; + } + + from.SendMessage( message ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/SerpentPillar.cs b/Scripts/Items/Misc/SerpentPillar.cs new file mode 100644 index 0000000..bb4a898 --- /dev/null +++ b/Scripts/Items/Misc/SerpentPillar.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Multis; + +namespace Server.Items +{ + public class SerpentPillar : Item + { + private bool m_Active; + private string m_Word; + private Rectangle2D m_Destination; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get{ return m_Active; } + set{ m_Active = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Word + { + get{ return m_Word; } + set{ m_Word = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Rectangle2D Destination + { + get{ return m_Destination; } + set{ m_Destination = value; } + } + + [Constructable] + public SerpentPillar() : this( null, new Rectangle2D(), false ) + { + } + + public SerpentPillar( string word, Rectangle2D destination ) : this( word, destination, true ) + { + } + + public SerpentPillar( string word, Rectangle2D destination, bool active ) : base( 0x233F ) + { + Movable = false; + + m_Active = active; + m_Word = word; + m_Destination = destination; + } + + public override bool HandlesOnSpeech{ get{ return true; } } + + public override void OnSpeech( SpeechEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !e.Handled && from.InRange( this, 10 ) && e.Speech.ToLower() == this.Word ) + { + BaseBoat boat = BaseBoat.FindBoatAt( from, from.Map ); + + if ( boat == null ) + return; + + if ( !this.Active ) + { + if ( boat.TillerMan != null ) + boat.TillerMan.Say( 502507 ); // Ar, Legend has it that these pillars are inactive! No man knows how it might be undone! + + return; + } + + Map map = from.Map; + + for ( int i = 0; i < 5; i++ ) // Try 5 times + { + int x = Utility.Random( Destination.X, Destination.Width ); + int y = Utility.Random( Destination.Y, Destination.Height ); + int z = map.GetAverageZ( x, y ); + + Point3D dest = new Point3D( x, y, z ); + + if ( boat.CanFit( dest, map, boat.ItemID ) ) + { + int xOffset = x - boat.X; + int yOffset = y - boat.Y; + int zOffset = z - boat.Z; + + boat.Teleport( xOffset, yOffset, zOffset ); + + return; + } + } + + if ( boat.TillerMan != null ) + boat.TillerMan.Say( 502508 ); // Ar, I refuse to take that matey through here! + } + } + + public SerpentPillar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_Active ); + writer.Write( (string) m_Word ); + writer.Write( (Rectangle2D) m_Destination ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Active = reader.ReadBool(); + m_Word = reader.ReadString(); + m_Destination = reader.ReadRect2D(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/SpecialBeardDye.cs b/Scripts/Items/Misc/SpecialBeardDye.cs new file mode 100644 index 0000000..6c038d3 --- /dev/null +++ b/Scripts/Items/Misc/SpecialBeardDye.cs @@ -0,0 +1,186 @@ +using System; +using System.Text; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class SpecialBeardDye : Item + { + public override int LabelNumber{ get{ return 1041087; } } // Special Beard Dye + + [Constructable] + public SpecialBeardDye() : base( 0xE26 ) + { + Weight = 1.0; + LootType = LootType.Newbied; + } + + public SpecialBeardDye( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + from.CloseGump( typeof( SpecialBeardDyeGump ) ); + from.SendGump( new SpecialBeardDyeGump( this ) ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 906, 1019045 ); // I can't reach that. + } + } + } + + public class SpecialBeardDyeGump : Gump + { + private SpecialBeardDye m_SpecialBeardDye; + + private class SpecialBeardDyeEntry + { + private string m_Name; + private int m_HueStart; + private int m_HueCount; + + public string Name + { + get + { + return m_Name; + } + } + + public int HueStart + { + get + { + return m_HueStart; + } + } + + public int HueCount + { + get + { + return m_HueCount; + } + } + + public SpecialBeardDyeEntry( string name, int hueStart, int hueCount ) + { + m_Name = name; + m_HueStart = hueStart; + m_HueCount = hueCount; + } + } + + private static SpecialBeardDyeEntry[] m_Entries = new SpecialBeardDyeEntry[] + { + new SpecialBeardDyeEntry( "*****", 12, 10 ), + new SpecialBeardDyeEntry( "*****", 32, 5 ), + new SpecialBeardDyeEntry( "*****", 38, 8 ), + new SpecialBeardDyeEntry( "*****", 54, 3 ), + new SpecialBeardDyeEntry( "*****", 62, 10 ), + new SpecialBeardDyeEntry( "*****", 81, 2 ), + new SpecialBeardDyeEntry( "*****", 89, 2 ), + new SpecialBeardDyeEntry( "*****", 1153, 2 ) + }; + + public SpecialBeardDyeGump( SpecialBeardDye dye ) : base( 0, 0 ) + { + m_SpecialBeardDye = dye; + + AddPage( 0 ); + AddBackground( 150, 60, 350, 358, 2600 ); + AddBackground( 170, 104, 110, 270, 5100 ); + AddHtmlLocalized( 230, 75, 200, 20, 1011013, false, false ); // Hair Color Selection Menu + AddHtmlLocalized( 235, 380, 300, 20, 1013007, false, false ); // Dye my beard this color! + AddButton( 200, 380, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); // DYE HAIR + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + AddLabel( 180, 109 + (i * 22), m_Entries[i].HueStart - 1, m_Entries[i].Name ); + AddButton( 257, 110 + (i * 22), 5224, 5224, 0, GumpButtonType.Page, i + 1 ); + } + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + SpecialBeardDyeEntry e = m_Entries[i]; + + AddPage( i + 1 ); + + for ( int j = 0; j < e.HueCount; ++j ) + { + AddLabel( 328 + ((j / 16) * 80), 102 + ((j % 16) * 17), e.HueStart + j - 1, "*****" ); + AddRadio( 310 + ((j / 16) * 80), 102 + ((j % 16) * 17), 210, 211, false, (i * 100) + j ); + } + } + } + + public override void OnResponse( NetState from, RelayInfo info ) + { + if ( m_SpecialBeardDye.Deleted ) + return; + + Mobile m = from.Mobile; + int[] switches = info.Switches; + + if ( !m_SpecialBeardDye.IsChildOf( m.Backpack ) ) + { + m.SendLocalizedMessage( 1042010 ); //You must have the objectin your backpack to use it. + return; + } + + if ( info.ButtonID != 0 && switches.Length > 0 ) + { + if( m.FacialHairItemID == 0 ) + { + m.SendLocalizedMessage( 502623 ); // You have no hair to dye and cannot use this + } + else + { + // To prevent this from being exploited, the hue is abstracted into an internal list + + int entryIndex = switches[0] / 100; + int hueOffset = switches[0] % 100; + + if ( entryIndex >= 0 && entryIndex < m_Entries.Length ) + { + SpecialBeardDyeEntry e = m_Entries[entryIndex]; + + if ( hueOffset >= 0 && hueOffset < e.HueCount ) + { + int hue = e.HueStart + hueOffset; + + m.FacialHairHue = hue; + + m.SendLocalizedMessage( 501199 ); // You dye your hair + m_SpecialBeardDye.Delete(); + m.PlaySound( 0x4E ); + } + } + } + } + else + { + m.SendLocalizedMessage( 501200 ); // You decide not to dye your hair + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/SpecialHairDye.cs b/Scripts/Items/Misc/SpecialHairDye.cs new file mode 100644 index 0000000..7cc9aad --- /dev/null +++ b/Scripts/Items/Misc/SpecialHairDye.cs @@ -0,0 +1,191 @@ +using System; +using System.Text; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class SpecialHairDye : Item + { + public override string DefaultName + { + get { return "Special Hair Dye"; } + } + + [Constructable] + public SpecialHairDye() : base( 0xE26 ) + { + Weight = 1.0; + LootType = LootType.Newbied; + } + + public SpecialHairDye( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + from.CloseGump( typeof( SpecialHairDyeGump ) ); + from.SendGump( new SpecialHairDyeGump( this ) ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 906, 1019045 ); // I can't reach that. + } + + } + } + + public class SpecialHairDyeGump : Gump + { + private SpecialHairDye m_SpecialHairDye; + + private class SpecialHairDyeEntry + { + private string m_Name; + private int m_HueStart; + private int m_HueCount; + + public string Name + { + get + { + return m_Name; + } + } + + public int HueStart + { + get + { + return m_HueStart; + } + } + + public int HueCount + { + get + { + return m_HueCount; + } + } + + public SpecialHairDyeEntry( string name, int hueStart, int hueCount ) + { + m_Name = name; + m_HueStart = hueStart; + m_HueCount = hueCount; + } + } + + private static SpecialHairDyeEntry[] m_Entries = new SpecialHairDyeEntry[] + { + new SpecialHairDyeEntry( "*****", 12, 10 ), + new SpecialHairDyeEntry( "*****", 32, 5 ), + new SpecialHairDyeEntry( "*****", 38, 8 ), + new SpecialHairDyeEntry( "*****", 54, 3 ), + new SpecialHairDyeEntry( "*****", 62, 10 ), + new SpecialHairDyeEntry( "*****", 81, 2 ), + new SpecialHairDyeEntry( "*****", 89, 2 ), + new SpecialHairDyeEntry( "*****", 1153, 2 ) + }; + + public SpecialHairDyeGump( SpecialHairDye dye ) : base( 0, 0 ) + { + m_SpecialHairDye = dye; + + AddPage( 0 ); + AddBackground( 150, 60, 350, 358, 2600 ); + AddBackground( 170, 104, 110, 270, 5100 ); + AddHtmlLocalized( 230, 75, 200, 20, 1011013, false, false ); // Hair Color Selection Menu + AddHtmlLocalized( 235, 380, 300, 20, 1011014, false, false ); // Dye my hair this color! + AddButton( 200, 380, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); // DYE HAIR + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + AddLabel( 180, 109 + (i * 22), m_Entries[i].HueStart - 1, m_Entries[i].Name ); + AddButton( 257, 110 + (i * 22), 5224, 5224, 0, GumpButtonType.Page, i + 1 ); + } + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + SpecialHairDyeEntry e = m_Entries[i]; + + AddPage( i + 1 ); + + for ( int j = 0; j < e.HueCount; ++j ) + { + AddLabel( 328 + ((j / 16) * 80), 102 + ((j % 16) * 17), e.HueStart + j - 1, "*****" ); + AddRadio( 310 + ((j / 16) * 80), 102 + ((j % 16) * 17), 210, 211, false, (i * 100) + j ); + } + } + } + + public override void OnResponse( NetState from, RelayInfo info ) + { + if ( m_SpecialHairDye.Deleted ) + return; + + Mobile m = from.Mobile; + int[] switches = info.Switches; + + if ( !m_SpecialHairDye.IsChildOf( m.Backpack ) ) + { + m.SendLocalizedMessage( 1042010 ); //You must have the objectin your backpack to use it. + return; + } + + if ( info.ButtonID != 0 && switches.Length > 0 ) + { + if( m.HairItemID == 0 ) + { + m.SendLocalizedMessage( 502623 ); // You have no hair to dye and cannot use this + } + else + { + // To prevent this from being exploited, the hue is abstracted into an internal list + + int entryIndex = switches[0] / 100; + int hueOffset = switches[0] % 100; + + if ( entryIndex >= 0 && entryIndex < m_Entries.Length ) + { + SpecialHairDyeEntry e = m_Entries[entryIndex]; + + if ( hueOffset >= 0 && hueOffset < e.HueCount ) + { + m_SpecialHairDye.Delete(); + + int hue = e.HueStart + hueOffset; + + m.HairHue = hue; + + m.SendLocalizedMessage( 501199 ); // You dye your hair + m.PlaySound( 0x4E ); + } + } + } + } + else + { + m.SendLocalizedMessage( 501200 ); // You decide not to dye your hair + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Static.cs b/Scripts/Items/Misc/Static.cs new file mode 100644 index 0000000..f2231c7 --- /dev/null +++ b/Scripts/Items/Misc/Static.cs @@ -0,0 +1,98 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Static : Item + { + public Static() : base( 0x80 ) + { + Movable = false; + } + + [Constructable] + public Static( int itemID ) : base( itemID ) + { + Movable = false; + } + + [Constructable] + public Static( int itemID, int count ) : this( Utility.Random( itemID, count ) ) + { + } + + public Static( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 0 ) + Weight = -1; + } + } + + public class LocalizedStatic : Static + { + private int m_LabelNumber; + + [CommandProperty( AccessLevel.GameMaster )] + public int Number + { + get{ return m_LabelNumber; } + set{ m_LabelNumber = value; InvalidateProperties(); } + } + + public override int LabelNumber{ get{ return m_LabelNumber; } } + + [Constructable] + public LocalizedStatic( int itemID ) : this( itemID, itemID < 0x4000 ? 1020000 + itemID : 1078872 + itemID ) + { + } + + [Constructable] + public LocalizedStatic( int itemID, int labelNumber ) : base( itemID ) + { + m_LabelNumber = labelNumber; + } + + public LocalizedStatic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (byte) 0 ); // version + writer.WriteEncodedInt( (int) m_LabelNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadByte(); + + switch ( version ) + { + case 0: + { + m_LabelNumber = reader.ReadEncodedInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/SwarmOfFlies.cs b/Scripts/Items/Misc/SwarmOfFlies.cs new file mode 100644 index 0000000..a705ec8 --- /dev/null +++ b/Scripts/Items/Misc/SwarmOfFlies.cs @@ -0,0 +1,37 @@ +using System; + +namespace Server.Items +{ + public class SwarmOfFlies : Item + { + public override string DefaultName + { + get { return "a swarm of flies"; } + } + + [Constructable] + public SwarmOfFlies() : base( 0x91B ) + { + Hue = 1; + Movable = false; + } + + public SwarmOfFlies( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Teleporter.cs b/Scripts/Items/Misc/Teleporter.cs new file mode 100644 index 0000000..bddda5f --- /dev/null +++ b/Scripts/Items/Misc/Teleporter.cs @@ -0,0 +1,1152 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class Teleporter : Item + { + private bool m_Active, m_Creatures, m_CombatCheck, m_CriminalCheck; + private Point3D m_PointDest; + private Map m_MapDest; + private bool m_SourceEffect; + private bool m_DestEffect; + private int m_SoundID; + private TimeSpan m_Delay; + + [CommandProperty(AccessLevel.GameMaster)] + public bool SourceEffect + { + get { return m_SourceEffect; } + set { m_SourceEffect = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DestEffect + { + get { return m_DestEffect; } + set { m_DestEffect = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SoundID + { + get { return m_SoundID; } + set { m_SoundID = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan Delay + { + get { return m_Delay; } + set { m_Delay = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Active + { + get { return m_Active; } + set { m_Active = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D PointDest + { + get { return m_PointDest; } + set { m_PointDest = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Map MapDest + { + get { return m_MapDest; } + set { m_MapDest = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Creatures + { + get { return m_Creatures; } + set { m_Creatures = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CombatCheck + { + get { return m_CombatCheck; } + set { m_CombatCheck = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool CriminalCheck + { + get { return m_CriminalCheck; } + set { m_CriminalCheck = value; InvalidateProperties(); } + } + + public override int LabelNumber { get { return 1026095; } } // teleporter + + [Constructable] + public Teleporter() + : this(new Point3D(0, 0, 0), null, false) + { + } + + [Constructable] + public Teleporter(Point3D pointDest, Map mapDest) + : this(pointDest, mapDest, false) + { + } + + [Constructable] + public Teleporter(Point3D pointDest, Map mapDest, bool creatures) + : base(0x1BC3) + { + Movable = false; + Visible = false; + + m_Active = true; + m_PointDest = pointDest; + m_MapDest = mapDest; + m_Creatures = creatures; + + m_CombatCheck = false; + m_CriminalCheck = false; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_Active) + list.Add(1060742); // active + else + list.Add(1060743); // inactive + + if (m_MapDest != null) + list.Add(1060658, "Map\t{0}", m_MapDest); + + if (m_PointDest != Point3D.Zero) + list.Add(1060659, "Coords\t{0}", m_PointDest); + + list.Add(1060660, "Creatures\t{0}", m_Creatures ? "Yes" : "No"); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_Active) + { + if (m_MapDest != null && m_PointDest != Point3D.Zero) + LabelTo(from, "{0} [{1}]", m_PointDest, m_MapDest); + else if (m_MapDest != null) + LabelTo(from, "[{0}]", m_MapDest); + else if (m_PointDest != Point3D.Zero) + LabelTo(from, m_PointDest.ToString()); + } + else + { + LabelTo(from, "(inactive)"); + } + } + + public virtual bool CanTeleport(Mobile m) + { + if (!m_Creatures && !m.Player) + { + return false; + } + else if (m_CriminalCheck && m.Criminal) + { + m.SendLocalizedMessage(1005561, "", 0x22); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if (m_CombatCheck && SpellHelper.CheckCombat(m)) + { + m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + return false; + } + + return true; + } + + public virtual void StartTeleport(Mobile m) + { + if (m_Delay == TimeSpan.Zero) + DoTeleport(m); + else + Timer.DelayCall(m_Delay, DoTeleport, m); + } + + public virtual void DoTeleport(Mobile m) + { + Map map = m_MapDest; + + if (map == null || map == Map.Internal) + map = m.Map; + + Point3D p = m_PointDest; + + if (p == Point3D.Zero) + p = m.Location; + + Server.Mobiles.BaseCreature.TeleportPets(m, p, map); + + bool sendEffect = (!m.Hidden || m.AccessLevel == AccessLevel.Player); + + if (m_SourceEffect && sendEffect) + Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10); + + m.MoveToWorld(p, map); + + if (m_DestEffect && sendEffect) + Effects.SendLocationEffect(m.Location, m.Map, 0x3728, 10, 10); + + if (m_SoundID > 0 && sendEffect) + Effects.PlaySound(m.Location, m.Map, m_SoundID); + } + + public override bool OnMoveOver(Mobile m) + { + if (m_Active && CanTeleport(m)) + { + StartTeleport(m); + return false; + } + + return true; + } + + public Teleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)4); // version + + writer.Write((bool)m_CriminalCheck); + writer.Write((bool)m_CombatCheck); + + writer.Write((bool)m_SourceEffect); + writer.Write((bool)m_DestEffect); + writer.Write((TimeSpan)m_Delay); + writer.WriteEncodedInt((int)m_SoundID); + + writer.Write(m_Creatures); + + writer.Write(m_Active); + writer.Write(m_PointDest); + writer.Write(m_MapDest); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 4: + { + m_CriminalCheck = reader.ReadBool(); + goto case 3; + } + case 3: + { + m_CombatCheck = reader.ReadBool(); + goto case 2; + } + case 2: + { + m_SourceEffect = reader.ReadBool(); + m_DestEffect = reader.ReadBool(); + m_Delay = reader.ReadTimeSpan(); + m_SoundID = reader.ReadEncodedInt(); + + goto case 1; + } + case 1: + { + m_Creatures = reader.ReadBool(); + + goto case 0; + } + case 0: + { + m_Active = reader.ReadBool(); + m_PointDest = reader.ReadPoint3D(); + m_MapDest = reader.ReadMap(); + + break; + } + } + } + } + + public class SkillTeleporter : Teleporter + { + private SkillName m_Skill; + private double m_Required; + private string m_MessageString; + private int m_MessageNumber; + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get { return m_Skill; } + set { m_Skill = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Required + { + get { return m_Required; } + set { m_Required = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string MessageString + { + get { return m_MessageString; } + set { m_MessageString = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MessageNumber + { + get { return m_MessageNumber; } + set { m_MessageNumber = value; InvalidateProperties(); } + } + + private void EndMessageLock(object state) + { + ((Mobile)state).EndAction(this); + } + + public override bool CanTeleport(Mobile m) + { + if (!base.CanTeleport(m)) + return false; + + Skill sk = m.Skills[m_Skill]; + + if (sk == null || sk.Base < m_Required) + { + if (m.BeginAction(this)) + { + if (m_MessageString != null) + m.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "ENU", null, m_MessageString)); + else if (m_MessageNumber != 0) + m.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, m_MessageNumber, null, "")); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerStateCallback(EndMessageLock), m); + } + + return false; + } + + return true; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + int skillIndex = (int)m_Skill; + string skillName; + + if (skillIndex >= 0 && skillIndex < SkillInfo.Table.Length) + skillName = SkillInfo.Table[skillIndex].Name; + else + skillName = "(Invalid)"; + + list.Add(1060661, "{0}\t{1:F1}", skillName, m_Required); + + if (m_MessageString != null) + list.Add(1060662, "Message\t{0}", m_MessageString); + else if (m_MessageNumber != 0) + list.Add(1060662, "Message\t#{0}", m_MessageNumber); + } + + [Constructable] + public SkillTeleporter() + { + } + + public SkillTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((int)m_Skill); + writer.Write((double)m_Required); + writer.Write((string)m_MessageString); + writer.Write((int)m_MessageNumber); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Skill = (SkillName)reader.ReadInt(); + m_Required = reader.ReadDouble(); + m_MessageString = reader.ReadString(); + m_MessageNumber = reader.ReadInt(); + + break; + } + } + } + } + + public class KeywordTeleporter : Teleporter + { + private string m_Substring; + private int m_Keyword; + private int m_Range; + + [CommandProperty(AccessLevel.GameMaster)] + public string Substring + { + get { return m_Substring; } + set { m_Substring = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Keyword + { + get { return m_Keyword; } + set { m_Keyword = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Range + { + get { return m_Range; } + set { m_Range = value; InvalidateProperties(); } + } + + public override bool HandlesOnSpeech { get { return true; } } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && Active) + { + Mobile m = e.Mobile; + + if (!m.InRange(GetWorldLocation(), m_Range)) + return; + + bool isMatch = false; + + if (m_Keyword >= 0 && e.HasKeyword(m_Keyword)) + isMatch = true; + else if (m_Substring != null && e.Speech.ToLower().IndexOf(m_Substring.ToLower()) >= 0) + isMatch = true; + + if (!isMatch || !CanTeleport(m)) + return; + + e.Handled = true; + StartTeleport(m); + } + } + + public override void DoTeleport(Mobile m) + { + if (!m.InRange(GetWorldLocation(), m_Range) || m.Map != Map) + return; + + base.DoTeleport(m); + } + + public override bool OnMoveOver(Mobile m) + { + return true; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060661, "Range\t{0}", m_Range); + + if (m_Keyword >= 0) + list.Add(1060662, "Keyword\t{0}", m_Keyword); + + if (m_Substring != null) + list.Add(1060663, "Substring\t{0}", m_Substring); + } + + [Constructable] + public KeywordTeleporter() + { + m_Keyword = -1; + m_Substring = null; + } + + public KeywordTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Substring); + writer.Write(m_Keyword); + writer.Write(m_Range); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Substring = reader.ReadString(); + m_Keyword = reader.ReadInt(); + m_Range = reader.ReadInt(); + + break; + } + } + } + } + + public class WaitTeleporter : KeywordTeleporter + { + private static Dictionary m_Table; + + public static void Initialize() + { + m_Table = new Dictionary(); + + EventSink.Logout += new LogoutEventHandler(EventSink_Logout); + } + + public static void EventSink_Logout(LogoutEventArgs e) + { + Mobile from = e.Mobile; + TeleportingInfo info; + + if (from == null || !m_Table.TryGetValue(from, out info)) + return; + + info.Timer.Stop(); + m_Table.Remove(from); + } + + private int m_StartNumber; + private string m_StartMessage; + private int m_ProgressNumber; + private string m_ProgressMessage; + private bool m_ShowTimeRemaining; + + [CommandProperty(AccessLevel.GameMaster)] + public int StartNumber + { + get { return m_StartNumber; } + set { m_StartNumber = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string StartMessage + { + get { return m_StartMessage; } + set { m_StartMessage = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ProgressNumber + { + get { return m_ProgressNumber; } + set { m_ProgressNumber = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string ProgressMessage + { + get { return m_ProgressMessage; } + set { m_ProgressMessage = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowTimeRemaining + { + get { return m_ShowTimeRemaining; } + set { m_ShowTimeRemaining = value; } + } + + [Constructable] + public WaitTeleporter() + { + } + + public static string FormatTime(TimeSpan ts) + { + if (ts.TotalHours >= 1) + { + int h = (int)Math.Round(ts.TotalHours); + return String.Format("{0} hour{1}", h, (h == 1) ? "" : "s"); + } + else if (ts.TotalMinutes >= 1) + { + int m = (int)Math.Round(ts.TotalMinutes); + return String.Format("{0} minute{1}", m, (m == 1) ? "" : "s"); + } + + int s = Math.Max((int)Math.Round(ts.TotalSeconds), 0); + return String.Format("{0} second{1}", s, (s == 1) ? "" : "s"); + } + + private void EndLock(Mobile m) + { + m.EndAction(this); + } + + public override void StartTeleport(Mobile m) + { + TeleportingInfo info; + + if (m_Table.TryGetValue(m, out info)) + { + if (info.Teleporter == this) + { + if (m.BeginAction(this)) + { + if (m_ProgressMessage != null) + m.SendMessage(m_ProgressMessage); + else if (m_ProgressNumber != 0) + m.SendLocalizedMessage(m_ProgressNumber); + + if (m_ShowTimeRemaining) + m.SendMessage("Time remaining: {0}", FormatTime(m_Table[m].Timer.Next - DateTime.Now)); + + Timer.DelayCall(TimeSpan.FromSeconds(5), EndLock, m); + } + + return; + } + else + { + info.Timer.Stop(); + } + } + + if (m_StartMessage != null) + m.SendMessage(m_StartMessage); + else if (m_StartNumber != 0) + m.SendLocalizedMessage(m_StartNumber); + + if (Delay == TimeSpan.Zero) + DoTeleport(m); + else + m_Table[m] = new TeleportingInfo(this, Timer.DelayCall(Delay, DoTeleport, m)); + } + + public override void DoTeleport(Mobile m) + { + m_Table.Remove(m); + + base.DoTeleport(m); + } + + public WaitTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_StartNumber); + writer.Write(m_StartMessage); + writer.Write(m_ProgressNumber); + writer.Write(m_ProgressMessage); + writer.Write(m_ShowTimeRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_StartNumber = reader.ReadInt(); + m_StartMessage = reader.ReadString(); + m_ProgressNumber = reader.ReadInt(); + m_ProgressMessage = reader.ReadString(); + m_ShowTimeRemaining = reader.ReadBool(); + } + + private class TeleportingInfo + { + private WaitTeleporter m_Teleporter; + private Timer m_Timer; + + public WaitTeleporter Teleporter { get { return m_Teleporter; } } + public Timer Timer { get { return m_Timer; } } + + public TeleportingInfo(WaitTeleporter tele, Timer t) + { + m_Teleporter = tele; + m_Timer = t; + } + } + } + + public class TimeoutTeleporter : Teleporter + { + private TimeSpan m_TimeoutDelay; + private Dictionary m_Teleporting; + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TimeoutDelay + { + get { return m_TimeoutDelay; } + set { m_TimeoutDelay = value; } + } + + [Constructable] + public TimeoutTeleporter() + : this(new Point3D(0, 0, 0), null, false) + { + } + + [Constructable] + public TimeoutTeleporter(Point3D pointDest, Map mapDest) + : this(pointDest, mapDest, false) + { + } + + [Constructable] + public TimeoutTeleporter(Point3D pointDest, Map mapDest, bool creatures) + : base(pointDest, mapDest, creatures) + { + m_Teleporting = new Dictionary(); + } + + public void StartTimer(Mobile m) + { + StartTimer(m, m_TimeoutDelay); + } + + private void StartTimer(Mobile m, TimeSpan delay) + { + Timer t; + + if (m_Teleporting.TryGetValue(m, out t)) + t.Stop(); + + m_Teleporting[m] = Timer.DelayCall(delay, StartTeleport, m); + } + + public void StopTimer(Mobile m) + { + Timer t; + + if (m_Teleporting.TryGetValue(m, out t)) + { + t.Stop(); + m_Teleporting.Remove(m); + } + } + + public override void DoTeleport(Mobile m) + { + m_Teleporting.Remove(m); + + base.DoTeleport(m); + } + + public override bool OnMoveOver(Mobile m) + { + if (Active) + { + if (!CanTeleport(m)) + return false; + + StartTimer(m); + } + + return true; + } + + public TimeoutTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_TimeoutDelay); + writer.Write(m_Teleporting.Count); + + foreach (KeyValuePair kvp in m_Teleporting) + { + writer.Write(kvp.Key); + writer.Write(kvp.Value.Next); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_TimeoutDelay = reader.ReadTimeSpan(); + m_Teleporting = new Dictionary(); + + int count = reader.ReadInt(); + + for (int i = 0; i < count; ++i) + { + Mobile m = reader.ReadMobile(); + DateTime end = reader.ReadDateTime(); + + StartTimer(m, end - DateTime.Now); + } + } + } + + public class TimeoutGoal : Item + { + private TimeoutTeleporter m_Teleporter; + + [CommandProperty(AccessLevel.GameMaster)] + public TimeoutTeleporter Teleporter + { + get { return m_Teleporter; } + set { m_Teleporter = value; } + } + + [Constructable] + public TimeoutGoal() + : base(0x1822) + { + Movable = false; + Visible = false; + + Hue = 1154; + } + + public override bool OnMoveOver(Mobile m) + { + if (m_Teleporter != null) + m_Teleporter.StopTimer(m); + + return true; + } + + public override string DefaultName + { + get { return "timeout teleporter goal"; } + } + + public TimeoutGoal(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.WriteItem(m_Teleporter); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Teleporter = reader.ReadItem(); + } + } + + public class ConditionTeleporter : Teleporter + { + [Flags] + protected enum ConditionFlag + { + None = 0x000, + DenyMounted = 0x001, + DenyFollowers = 0x002, + DenyPackContents = 0x004, + DenyHolding = 0x008, + DenyEquipment = 0x010, + DenyTransformed = 0x020, + StaffOnly = 0x040, + DenyPackEthereals = 0x080, + DeadOnly = 0x100 + } + + private ConditionFlag m_Flags; + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyMounted + { + get { return GetFlag(ConditionFlag.DenyMounted); } + set { SetFlag(ConditionFlag.DenyMounted, value); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyFollowers + { + get { return GetFlag(ConditionFlag.DenyFollowers); } + set { SetFlag(ConditionFlag.DenyFollowers, value); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyPackContents + { + get { return GetFlag(ConditionFlag.DenyPackContents); } + set { SetFlag(ConditionFlag.DenyPackContents, value); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyHolding + { + get { return GetFlag(ConditionFlag.DenyHolding); } + set { SetFlag(ConditionFlag.DenyHolding, value); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyEquipment + { + get { return GetFlag(ConditionFlag.DenyEquipment); } + set { SetFlag(ConditionFlag.DenyEquipment, value); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyTransformed + { + get { return GetFlag(ConditionFlag.DenyTransformed); } + set { SetFlag(ConditionFlag.DenyTransformed, value); InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool StaffOnly + { + get{ return GetFlag( ConditionFlag.StaffOnly ); } + set{ SetFlag( ConditionFlag.StaffOnly, value ); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DenyPackEthereals + { + get { return GetFlag(ConditionFlag.DenyPackEthereals); } + set { SetFlag(ConditionFlag.DenyPackEthereals, value); InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DeadOnly + { + get { return GetFlag(ConditionFlag.DeadOnly); } + set { SetFlag(ConditionFlag.DeadOnly, value); InvalidateProperties(); } + } + + public override bool CanTeleport(Mobile m) + { + if (!base.CanTeleport(m)) + return false; + + if (GetFlag(ConditionFlag.StaffOnly) && m.AccessLevel < AccessLevel.Counselor) + return false; + + if (GetFlag(ConditionFlag.DenyMounted) && m.Mounted) + { + m.SendLocalizedMessage(1077252); // You must dismount before proceeding. + return false; + } + + if (GetFlag(ConditionFlag.DenyFollowers) && (m.Followers != 0 || (m is PlayerMobile && ((PlayerMobile)m).AutoStabled.Count != 0))) + { + m.SendLocalizedMessage(1077250); // No pets permitted beyond this point. + return false; + } + + Container pack = m.Backpack; + + if (pack != null) + { + if (GetFlag(ConditionFlag.DenyPackContents) && pack.TotalItems != 0) + { + m.SendMessage("You must empty your backpack before proceeding."); + return false; + } + + if (GetFlag(ConditionFlag.DenyPackEthereals) && (pack.FindItemByType(typeof(EtherealMount)) != null || pack.FindItemByType(typeof(BaseImprisonedMobile)) != null)) + { + m.SendMessage("You must empty your backpack of ethereal mounts before proceeding."); + return false; + } + } + + if (GetFlag(ConditionFlag.DenyHolding) && m.Holding != null) + { + m.SendMessage("You must let go of what you are holding before proceeding."); + return false; + } + + if (GetFlag(ConditionFlag.DenyEquipment)) + { + foreach (Item item in m.Items) + { + switch (item.Layer) + { + case Layer.Hair: + case Layer.FacialHair: + case Layer.Backpack: + case Layer.Mount: + case Layer.Bank: + { + continue; // ignore + } + default: + { + m.SendMessage("You must remove all of your equipment before proceeding."); + return false; + } + } + } + } + + if (GetFlag(ConditionFlag.DenyTransformed) && m.IsBodyMod) + { + m.SendMessage("You cannot go there in this form."); + return false; + } + + if (GetFlag(ConditionFlag.DeadOnly) && m.Alive) + { + m.SendLocalizedMessage(1060014); // Only the dead may pass. + return false; + } + + return true; + } + + [Constructable] + public ConditionTeleporter() + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + StringBuilder props = new StringBuilder(); + + if (GetFlag(ConditionFlag.DenyMounted)) + props.Append("
Deny Mounted"); + + if (GetFlag(ConditionFlag.DenyFollowers)) + props.Append("
Deny Followers"); + + if (GetFlag(ConditionFlag.DenyPackContents)) + props.Append("
Deny Pack Contents"); + + if (GetFlag(ConditionFlag.DenyPackEthereals)) + props.Append("
Deny Pack Ethereals"); + + if (GetFlag(ConditionFlag.DenyHolding)) + props.Append("
Deny Holding"); + + if (GetFlag(ConditionFlag.DenyEquipment)) + props.Append("
Deny Equipment"); + + if (GetFlag(ConditionFlag.DenyTransformed)) + props.Append("
Deny Transformed"); + + if (GetFlag(ConditionFlag.StaffOnly)) + props.Append("
Staff Only"); + + if (GetFlag(ConditionFlag.DeadOnly)) + props.Append("
Dead Only"); + + if (props.Length != 0) + { + props.Remove(0, 4); + list.Add(props.ToString()); + } + } + + public ConditionTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((int)m_Flags); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Flags = (ConditionFlag)reader.ReadInt(); + } + + protected bool GetFlag(ConditionFlag flag) + { + return ((m_Flags & flag) != 0); + } + + protected void SetFlag(ConditionFlag flag, bool value) + { + if (value) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/The Citadel/DragonFlameSectBadge.cs b/Scripts/Items/Misc/The Citadel/DragonFlameSectBadge.cs new file mode 100644 index 0000000..ab4eab9 --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/DragonFlameSectBadge.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DragonFlameSectBadge : Item + { + public override int LabelNumber{ get{ return 1073141; } } // A Dragon Flame Sect Badge + + [Constructable] + public DragonFlameSectBadge() : base( 0x23E ) + { + LootType = LootType.Blessed; + } + + public DragonFlameSectBadge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/The Citadel/OrdersFromMinax.cs b/Scripts/Items/Misc/The Citadel/OrdersFromMinax.cs new file mode 100644 index 0000000..f61e094 --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/OrdersFromMinax.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class OrdersFromMinax : Item + { + public override int LabelNumber{ get{ return 1074639; } } // Orders from Minax + + [Constructable] + public OrdersFromMinax() : base( 0x2279 ) + { + LootType = LootType.Blessed; + } + + public OrdersFromMinax( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/The Citadel/SerpentFangSectBadge.cs b/Scripts/Items/Misc/The Citadel/SerpentFangSectBadge.cs new file mode 100644 index 0000000..bbb384e --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/SerpentFangSectBadge.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SerpentFangSectBadge : Item + { + public override int LabelNumber{ get{ return 1073139; } } // A Serpent Fang Sect Badge + + [Constructable] + public SerpentFangSectBadge() : base( 0x23C ) + { + LootType = LootType.Blessed; + } + + public SerpentFangSectBadge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/The Citadel/TigerClawSectBadge.cs b/Scripts/Items/Misc/The Citadel/TigerClawSectBadge.cs new file mode 100644 index 0000000..46b0118 --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/TigerClawSectBadge.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TigerClawSectBadge : Item + { + public override int LabelNumber{ get{ return 1073140; } } // A Tiger Claw Sect Badge + + [Constructable] + public TigerClawSectBadge() : base( 0x23D ) + { + LootType = LootType.Blessed; + } + + public TigerClawSectBadge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/The Citadel/TravestysCollectionOfShells.cs b/Scripts/Items/Misc/The Citadel/TravestysCollectionOfShells.cs new file mode 100644 index 0000000..8979588 --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/TravestysCollectionOfShells.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TravestysCollectionOfShells : Item + { + public override int LabelNumber{ get{ return 1072090; } } // Travesty's Collection of Shells + + [Constructable] + public TravestysCollectionOfShells() : base( 0xFD3 ) + { + } + + public TravestysCollectionOfShells( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/The Citadel/TravestysFineTeakwoodTray.cs b/Scripts/Items/Misc/The Citadel/TravestysFineTeakwoodTray.cs new file mode 100644 index 0000000..08e2f7e --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/TravestysFineTeakwoodTray.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TravestysFineTeakwoodTray : Item + { + public override int LabelNumber{ get{ return 1075094; } } // Travesty's Fine Teakwood Tray + + [Constructable] + public TravestysFineTeakwoodTray() : base( Utility.Random( 0x991, 2 ) ) + { + } + + public TravestysFineTeakwoodTray( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/The Citadel/TravestysSushiPreparations.cs b/Scripts/Items/Misc/The Citadel/TravestysSushiPreparations.cs new file mode 100644 index 0000000..ee24741 --- /dev/null +++ b/Scripts/Items/Misc/The Citadel/TravestysSushiPreparations.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TravestysSushiPreparations : Item + { + public override int LabelNumber{ get{ return 1075093; } } // Travesty's Sushi Preparations + + [Constructable] + public TravestysSushiPreparations() : base( Utility.Random( 0x1E15, 2 ) ) + { + } + + public TravestysSushiPreparations( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/TrashBarrel.cs b/Scripts/Items/Misc/TrashBarrel.cs new file mode 100644 index 0000000..504cb6d --- /dev/null +++ b/Scripts/Items/Misc/TrashBarrel.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Multis; + +namespace Server.Items +{ + public class TrashBarrel : Container, IChopable + { + public override int LabelNumber{ get{ return 1041064; } } // a trash barrel + + public override int DefaultMaxWeight{ get{ return 0; } } // A value of 0 signals unlimited weight + + public override bool IsDecoContainer + { + get{ return false; } + } + + [Constructable] + public TrashBarrel() : base( 0xE77 ) + { + Hue = 0x3B2; + Movable = false; + } + + public TrashBarrel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Items.Count > 0 ) + { + m_Timer = new EmptyTimer( this ); + m_Timer.Start(); + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( !base.OnDragDrop( from, dropped ) ) + return false; + + if ( TotalItems >= 50 ) + { + Empty( 501478 ); // The trash is full! Emptying! + } + else + { + SendLocalizedMessageTo( from, 1010442 ); // The item will be deleted in three minutes + + if ( m_Timer != null ) + m_Timer.Stop(); + else + m_Timer = new EmptyTimer( this ); + + m_Timer.Start(); + } + + return true; + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( !base.OnDragDropInto( from, item, p ) ) + return false; + + if ( TotalItems >= 50 ) + { + Empty( 501478 ); // The trash is full! Emptying! + } + else + { + SendLocalizedMessageTo( from, 1010442 ); // The item will be deleted in three minutes + + if ( m_Timer != null ) + m_Timer.Stop(); + else + m_Timer = new EmptyTimer( this ); + + m_Timer.Start(); + } + + return true; + } + + public void OnChop( Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsCoOwner( from ) ) + { + Effects.PlaySound( Location, Map, 0x3B3 ); + from.SendLocalizedMessage( 500461 ); // You destroy the item. + Destroy(); + } + } + + public void Empty( int message ) + { + List items = this.Items; + + if ( items.Count > 0 ) + { + PublicOverheadMessage( Network.MessageType.Regular, 0x3B2, message, "" ); + + for ( int i = items.Count - 1; i >= 0; --i ) + { + if ( i >= items.Count ) + continue; + + items[i].Delete(); + } + } + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + + private Timer m_Timer; + + private class EmptyTimer : Timer + { + private TrashBarrel m_Barrel; + + public EmptyTimer( TrashBarrel barrel ) : base( TimeSpan.FromMinutes( 3.0 ) ) + { + m_Barrel = barrel; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Barrel.Empty( 501479 ); // Emptying the trashcan! + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/TrashChest.cs b/Scripts/Items/Misc/TrashChest.cs new file mode 100644 index 0000000..3b13ea2 --- /dev/null +++ b/Scripts/Items/Misc/TrashChest.cs @@ -0,0 +1,61 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute( 0xE41, 0xE40 )] + public class TrashChest : Container + { + public override int DefaultMaxWeight{ get{ return 0; } } // A value of 0 signals unlimited weight + + public override bool IsDecoContainer + { + get{ return false; } + } + + [Constructable] + public TrashChest() : base( 0xE41 ) + { + Movable = false; + } + + public TrashChest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( !base.OnDragDrop( from, dropped ) ) + return false; + + PublicOverheadMessage( Network.MessageType.Regular, 0x3B2, Utility.Random( 1042891, 8 ) ); + dropped.Delete(); + + return true; + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( !base.OnDragDropInto( from, item, p ) ) + return false; + + PublicOverheadMessage( Network.MessageType.Regular, 0x3B2, Utility.Random( 1042891, 8 ) ); + item.Delete(); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/TribalBerry.cs b/Scripts/Items/Misc/TribalBerry.cs new file mode 100644 index 0000000..1b6331f --- /dev/null +++ b/Scripts/Items/Misc/TribalBerry.cs @@ -0,0 +1,46 @@ +using System; + +namespace Server.Items +{ + public class TribalBerry : Item + { + public override int LabelNumber{ get{ return 1040001; } } // tribal berry + + [Constructable] + public TribalBerry() : this( 1 ) + { + } + + [Constructable] + public TribalBerry( int amount ) : base( 0x9D0 ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + Hue = 6; + } + + public TribalBerry( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 4 ) + Hue = 6; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/TribalPaint.cs b/Scripts/Items/Misc/TribalPaint.cs new file mode 100644 index 0000000..c803540 --- /dev/null +++ b/Scripts/Items/Misc/TribalPaint.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Items +{ + public class TribalPaint : Item + { + public override int LabelNumber{ get{ return 1040000; } } // savage kin paint + + [Constructable] + public TribalPaint() : base( 0x9EC ) + { + Hue = 2101; + Weight = 2.0; + Stackable = Core.ML; + } + + public TribalPaint( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + if ( Factions.Sigil.ExistsOn( from ) ) + { + from.SendLocalizedMessage( 1010465 ); // You cannot disguise yourself while holding a sigil. + } + else if ( !from.CanBeginAction( typeof( Spells.Fifth.IncognitoSpell ) ) ) + { + from.SendLocalizedMessage( 501698 ); // You cannot disguise yourself while incognitoed. + } + else if ( !from.CanBeginAction( typeof( Spells.Seventh.PolymorphSpell ) ) ) + { + from.SendLocalizedMessage( 501699 ); // You cannot disguise yourself while polymorphed. + } + else if( TransformationSpellHelper.UnderTransformation( from ) ) + { + from.SendLocalizedMessage( 501699 ); // You cannot disguise yourself while polymorphed. + } + else if ( Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) ) + { + from.SendLocalizedMessage( 1061634 ); // You cannot disguise yourself while in that form. + } + else if ( from.IsBodyMod || from.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + { + from.SendLocalizedMessage( 501605 ); // You are already disguised. + } + else + { + from.BodyMod = ( from.Female ? 184 : 183 ); + from.HueMod = 0; + + if ( from is PlayerMobile ) + ((PlayerMobile)from).SavagePaintExpiration = TimeSpan.FromDays( 7.0 ); + + from.SendLocalizedMessage( 1042537 ); // You now bear the markings of the savage tribe. Your body paint will last about a week or you can remove it with an oil cloth. + + Consume(); + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Twisted Weald/HornOfTheDreadhorn.cs b/Scripts/Items/Misc/Twisted Weald/HornOfTheDreadhorn.cs new file mode 100644 index 0000000..928525d --- /dev/null +++ b/Scripts/Items/Misc/Twisted Weald/HornOfTheDreadhorn.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + [Flipable(0x315C, 0x315D)] + public class HornOfTheDreadhorn : Item + { + public override int LabelNumber{ get{ return 1072089; } } // Horn of the Dread + + [Constructable] + public HornOfTheDreadhorn() : base( 0x315C ) + { + } + + public HornOfTheDreadhorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Twisted Weald/MangledHeadOfDreadhorn.cs b/Scripts/Items/Misc/Twisted Weald/MangledHeadOfDreadhorn.cs new file mode 100644 index 0000000..f2d9a39 --- /dev/null +++ b/Scripts/Items/Misc/Twisted Weald/MangledHeadOfDreadhorn.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + [Flipable(0x3156, 0x3157)] + public class MangledHeadOfDreadhorn : Item + { + public override int LabelNumber{ get{ return 1072088; } } // The Mangled Head of Dread Horn + + [Constructable] + public MangledHeadOfDreadhorn() : base( 0x3156 ) + { + } + + public MangledHeadOfDreadhorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/Twisted Weald/TaintedMushroom.cs b/Scripts/Items/Misc/Twisted Weald/TaintedMushroom.cs new file mode 100644 index 0000000..2a9d9a4 --- /dev/null +++ b/Scripts/Items/Misc/Twisted Weald/TaintedMushroom.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class TaintedMushroom : Item + { + public override int LabelNumber{ get{ return 1075088; } } // Dread Horn Tainted Mushroom + public override bool ForceShowProperties{ get{ return true; } } + + [Constructable] + public TaintedMushroom() : base( Utility.RandomMinMax( 0x222E, 0x2231 ) ) + { + } + + public TaintedMushroom( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Misc/UnholyBone.cs b/Scripts/Items/Misc/UnholyBone.cs new file mode 100644 index 0000000..eb813e7 --- /dev/null +++ b/Scripts/Items/Misc/UnholyBone.cs @@ -0,0 +1,117 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class UnholyBone : Item, ICarvable + { + private SpawnTimer m_Timer; + + public override string DefaultName + { + get { return "unholy bone"; } + } + + [Constructable] + public UnholyBone() : base( 0xF7E ) + { + Movable = false; + Hue = 0x497; + + m_Timer = new SpawnTimer( this ); + m_Timer.Start(); + } + + public void Carve( Mobile from, Item item ) + { + Effects.PlaySound( GetWorldLocation(), Map, 0x48F ); + Effects.SendLocationEffect( GetWorldLocation(), Map, 0x3728, 10, 10, 0, 0 ); + + if ( 0.3 > Utility.RandomDouble() ) + { + if ( ItemID == 0xF7E ) + from.SendMessage( "You destroy the bone." ); + else + from.SendMessage( "You destroy the bone pile." ); + + Gold gold = new Gold( 25, 100 ); + + gold.MoveToWorld( GetWorldLocation(), Map ); + + Delete(); + + m_Timer.Stop(); + } + else + { + if ( ItemID == 0xF7E ) + from.SendMessage( "You damage the bone." ); + else + from.SendMessage( "You damage the bone pile." ); + } + } + + public UnholyBone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Timer = new SpawnTimer( this ); + m_Timer.Start(); + } + + private class SpawnTimer : Timer + { + private Item m_Item; + + public SpawnTimer( Item item ) : base( TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 10 ) ) ) + { + Priority = TimerPriority.FiftyMS; + + m_Item = item; + } + + protected override void OnTick() + { + if ( m_Item.Deleted ) + return; + + Mobile spawn; + + switch ( Utility.Random( 12 ) ) + { + default: + case 0: spawn = new Skeleton(); break; + case 1: spawn = new Zombie(); break; + case 2: spawn = new Wraith(); break; + case 3: spawn = new Spectre(); break; + case 4: spawn = new Ghoul(); break; + case 5: spawn = new Mummy(); break; + case 6: spawn = new Bogle(); break; + case 7: spawn = new RottingCorpse(); break; + case 8: spawn = new BoneKnight(); break; + case 9: spawn = new SkeletalKnight(); break; + case 10: spawn = new Lich(); break; + case 11: spawn = new LichLord(); break; + } + + spawn.MoveToWorld( m_Item.Location, m_Item.Map ); + + m_Item.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/WarningItem.cs b/Scripts/Items/Misc/WarningItem.cs new file mode 100644 index 0000000..a4075fb --- /dev/null +++ b/Scripts/Items/Misc/WarningItem.cs @@ -0,0 +1,242 @@ +using System; +using Server; +using Server.Network; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Items +{ + public class WarningItem : Item + { + private string m_WarningString; + private int m_WarningNumber; + private int m_Range; + private TimeSpan m_ResetDelay; + + [CommandProperty( AccessLevel.GameMaster )] + public string WarningString + { + get{ return m_WarningString; } + set{ m_WarningString = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int WarningNumber + { + get{ return m_WarningNumber; } + set{ m_WarningNumber = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Range + { + get{ return m_Range; } + set{ if ( value > 18 ) value = 18; m_Range = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan ResetDelay + { + get{ return m_ResetDelay; } + set{ m_ResetDelay = value; } + } + + [Constructable] + public WarningItem( int itemID, int range, int warning ) : base( itemID ) + { + if ( range > 18 ) + range = 18; + + Movable = false; + + m_WarningNumber = warning; + m_Range = range; + } + + [Constructable] + public WarningItem( int itemID, int range, string warning ) : base( itemID ) + { + if ( range > 18 ) + range = 18; + + Movable = false; + + m_WarningString = warning; + m_Range = range; + } + + public WarningItem( Serial serial ) : base( serial ) + { + } + + private bool m_Broadcasting; + + private DateTime m_LastBroadcast; + + public virtual void SendMessage( Mobile triggerer, bool onlyToTriggerer, string messageString, int messageNumber ) + { + if ( onlyToTriggerer ) + { + if ( messageString != null ) + triggerer.SendMessage( messageString ); + else + triggerer.SendLocalizedMessage( messageNumber ); + } + else + { + if ( messageString != null ) + PublicOverheadMessage( MessageType.Regular, 0x3B2, false, messageString ); + else + PublicOverheadMessage( MessageType.Regular, 0x3B2, messageNumber ); + } + } + + public virtual bool OnlyToTriggerer{ get{ return false; } } + public virtual int NeighborRange { get { return 5; } } + + public virtual void Broadcast( Mobile triggerer ) + { + if ( m_Broadcasting || (DateTime.Now < (m_LastBroadcast + m_ResetDelay)) ) + return; + + m_LastBroadcast = DateTime.Now; + + m_Broadcasting = true; + + SendMessage( triggerer, this.OnlyToTriggerer, m_WarningString, m_WarningNumber ); + + if ( NeighborRange >= 0 ) + { + List list = new List(); + + foreach ( Item item in GetItemsInRange( NeighborRange ) ) + { + if ( item != this && item is WarningItem ) + list.Add( (WarningItem)item ); + } + + for ( int i = 0; i < list.Count; i++ ) + list[i].Broadcast( triggerer ); + } + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( InternalCallback ) ); + } + + private void InternalCallback() + { + m_Broadcasting = false; + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m.Player && Utility.InRange( m.Location, Location, m_Range ) && !Utility.InRange( oldLocation, Location, m_Range ) ) + Broadcast( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (string) m_WarningString ); + writer.Write( (int) m_WarningNumber ); + writer.Write( (int) m_Range ); + + writer.Write( (TimeSpan) m_ResetDelay ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_WarningString = reader.ReadString(); + m_WarningNumber = reader.ReadInt(); + m_Range = reader.ReadInt(); + m_ResetDelay = reader.ReadTimeSpan(); + + break; + } + } + } + } + + public class HintItem : WarningItem + { + private string m_HintString; + private int m_HintNumber; + + [CommandProperty( AccessLevel.GameMaster )] + public string HintString + { + get{ return m_HintString; } + set{ m_HintString = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int HintNumber + { + get{ return m_HintNumber; } + set{ m_HintNumber = value; } + } + + public override bool OnlyToTriggerer{ get{ return true; } } + + [Constructable] + public HintItem( int itemID, int range, int warning, int hint ) : base( itemID, range, warning ) + { + m_HintNumber = hint; + } + + [Constructable] + public HintItem( int itemID, int range, string warning, string hint ) : base( itemID, range, warning ) + { + m_HintString = hint; + } + + public HintItem( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + SendMessage( from, true, m_HintString, m_HintNumber ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (string) m_HintString ); + writer.Write( (int) m_HintNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_HintString = reader.ReadString(); + m_HintNumber = reader.ReadInt(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Misc/Waypoint.cs b/Scripts/Items/Misc/Waypoint.cs new file mode 100644 index 0000000..72daf8c --- /dev/null +++ b/Scripts/Items/Misc/Waypoint.cs @@ -0,0 +1,161 @@ +using System; +using Server; +using Server.Targeting; +using Server.Commands; + +namespace Server.Items +{ + [FlipableAttribute( 0x1f14, 0x1f15, 0x1f16, 0x1f17 )] + public class WayPoint : Item + { + public static void Initialize() + { + CommandSystem.Register( "WayPointSeq", AccessLevel.GameMaster, new CommandEventHandler( WayPointSeq_OnCommand ) ); + } + + public static void WayPointSeq_OnCommand( CommandEventArgs arg ) + { + arg.Mobile.SendMessage( "Target the position of the first way point." ); + arg.Mobile.Target = new WayPointSeqTarget( null ); + } + + private WayPoint m_Next; + + public override string DefaultName + { + get { return "AI Way Point"; } + } + + [Constructable] + public WayPoint() : base( 0x1f14 ) + { + this.Hue = 0x498; + this.Visible = false; + //this.Movable = false; + } + + public WayPoint( WayPoint prev ) : this() + { + if ( prev != null ) + prev.NextPoint = this; + } + + [CommandProperty( AccessLevel.GameMaster )] + public WayPoint NextPoint + { + get + { + return m_Next; + } + set + { + if ( m_Next != this ) + m_Next = value; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.SendMessage( "Target the next way point in the sequence." ); + + from.Target = new NextPointTarget( this ); + } + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( m_Next == null ) + LabelTo( from, "(Unlinked)" ); + else + LabelTo( from, "(Linked: {0})", m_Next.Location ); + } + + public WayPoint( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_Next = reader.ReadItem() as WayPoint; + break; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_Next ); + } + } + + public class NextPointTarget : Target + { + private WayPoint m_Point; + + public NextPointTarget( WayPoint pt ) : base( -1, false, TargetFlags.None ) + { + m_Point = pt; + } + + protected override void OnTarget( Mobile from, object target ) + { + if ( target is WayPoint && m_Point != null ) + { + m_Point.NextPoint = (WayPoint)target; + } + else + { + from.SendMessage( "Target a way point." ); + } + } + } + + public class WayPointSeqTarget : Target + { + private WayPoint m_Last; + + public WayPointSeqTarget( WayPoint last ) : base( -1, true, TargetFlags.None ) + { + m_Last = last; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is WayPoint ) + { + if ( m_Last != null ) + m_Last.NextPoint = (WayPoint)targeted; + } + else if ( targeted is IPoint3D ) + { + Point3D p = new Point3D( (IPoint3D)targeted ); + + WayPoint point = new WayPoint( m_Last ); + point.MoveToWorld( p, from.Map ); + + from.Target = new WayPointSeqTarget( point ); + from.SendMessage( "Target the position of the next way point in the sequence, or target a way point link the newest way point to." ); + } + else + { + from.SendMessage( "Target a position, or another way point." ); + } + } + } +} diff --git a/Scripts/Items/Misc/WindChimes.cs b/Scripts/Items/Misc/WindChimes.cs new file mode 100644 index 0000000..03afa31 --- /dev/null +++ b/Scripts/Items/Misc/WindChimes.cs @@ -0,0 +1,189 @@ +using System; +using Server; +using Server.Multis; +using Server.Gumps; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseWindChimes : Item + { + private bool m_TurnedOn; + + [CommandProperty( AccessLevel.GameMaster )] + public bool TurnedOn + { + get{ return m_TurnedOn; } + set{ m_TurnedOn = value; InvalidateProperties(); } + } + + public BaseWindChimes( int itemID ) : base( itemID ) + { + } + + private static int[] m_Sounds = new int[] { 0x505, 0x506, 0x507 }; + + public static int[] Sounds + { + get{ return m_Sounds; } + } + + public override bool HandlesOnMovement{ get{ return m_TurnedOn && IsLockedDown; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) && Utility.InRange( m.Location, this.Location, 2 ) && !Utility.InRange( oldLocation, this.Location, 2 ) ) + Effects.PlaySound( this.Location, this.Map, m_Sounds[Utility.Random( m_Sounds.Length )] ); + + base.OnMovement( m, oldLocation ); + } + + public BaseWindChimes( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_TurnedOn ) + list.Add( 502695 ); // turned on + else + list.Add( 502696 ); // turned off + } + + public bool IsOwner( Mobile mob ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + return ( house != null && house.IsOwner( mob ) ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsOwner( from ) ) + { + OnOffGump onOffGump = new OnOffGump( this ); + from.SendGump( onOffGump ); + } + else + { + from.SendLocalizedMessage( 502691 ); // You must be the owner to use this. + } + } + + private class OnOffGump : Gump + { + private BaseWindChimes m_Chimes; + + public OnOffGump( BaseWindChimes chimes ) : base( 150, 200 ) + { + m_Chimes = chimes; + + AddBackground( 0, 0, 300, 150, 0xA28 ); + AddHtmlLocalized( 45, 20, 300, 35, chimes.TurnedOn ? 1011035 : 1011034, false, false ); // [De]Activate this item + AddButton( 40, 53, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 55, 65, 35, 1011036, false, false ); // OKAY + AddButton( 150, 53, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 190, 55, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 1 ) + { + bool newValue = !m_Chimes.TurnedOn; + + m_Chimes.TurnedOn = newValue; + + if ( newValue && !m_Chimes.IsLockedDown ) + from.SendLocalizedMessage( 502693 ); // Remember, this only works when locked down. + } + else + { + from.SendLocalizedMessage( 502694 ); // Cancelled action. + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (bool) m_TurnedOn ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_TurnedOn = reader.ReadBool(); + break; + } + } + } + } + + public class WindChimes : BaseWindChimes + { + public override int LabelNumber{ get{ return 1030290; } } + + [Constructable] + public WindChimes() : base( 0x2832 ) + { + } + + public WindChimes( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class FancyWindChimes : BaseWindChimes + { + public override int LabelNumber{ get{ return 1030291; } } + + [Constructable] + public FancyWindChimes() : base( 0x2833 ) + { + } + + public FancyWindChimes( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/New Haven Quest Rewards/AmeliasToolbox.cs b/Scripts/Items/New Haven Quest Rewards/AmeliasToolbox.cs new file mode 100644 index 0000000..3c207e7 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/AmeliasToolbox.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AmeliasToolbox : TinkerTools + { + public override int LabelNumber{ get{ return 1077749; } } // Amelias Toolbox + + [Constructable] + public AmeliasToolbox() : base( 500 ) + { + LootType = LootType.Blessed; + Hue = 1895; // TODO check + } + + public AmeliasToolbox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs b/Scripts/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs new file mode 100644 index 0000000..9533f1c --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/ArmsOfArmstrong.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArmsOfArmstrong : LeatherArms + { + public override int LabelNumber{ get{ return 1077675; } } // Arms of Armstrong + + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + [Constructable] + public ArmsOfArmstrong() + { + LootType = LootType.Blessed; + + Attributes.BonusStr = 3; + Attributes.RegenHits = 1; + } + + public ArmsOfArmstrong( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs b/Scripts/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs new file mode 100644 index 0000000..640e405 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/BagOfNecromancerReagents.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BagOfNecromancerReagents : Bag + { + [Constructable] + public BagOfNecromancerReagents() : this( 50 ) + { + } + + [Constructable] + public BagOfNecromancerReagents( int amount ) + { + DropItem( new BatWing ( amount ) ); + DropItem( new GraveDust ( amount ) ); + DropItem( new DaemonBlood( amount ) ); + DropItem( new NoxCrystal ( amount ) ); + DropItem( new PigIron ( amount ) ); + } + + public BagOfNecromancerReagents( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs b/Scripts/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs new file mode 100644 index 0000000..a84d364 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/BagOfSmokeBombs.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BagOfSmokeBombs : Bag + { + [Constructable] + public BagOfSmokeBombs() : this( 20 ) + { + } + + [Constructable] + public BagOfSmokeBombs( int amount ) + { + for ( int i = 0; i < amount; ++i ) + DropItem( new SmokeBomb() ); + } + + public BagOfSmokeBombs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/BraceletOfResilience.cs b/Scripts/Items/New Haven Quest Rewards/BraceletOfResilience.cs new file mode 100644 index 0000000..7da47b4 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/BraceletOfResilience.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BraceletOfResilience : GoldBracelet + { + public override int LabelNumber{ get{ return 1077627; } } // Bracelet of Resilience + + [Constructable] + public BraceletOfResilience() + { + LootType = LootType.Blessed; + + Attributes.DefendChance = 5; + Resistances.Fire = 5; + Resistances.Cold = 5; + Resistances.Poison = 5; + Resistances.Energy = 5; + } + + public BraceletOfResilience( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/BulwarkLeggings.cs b/Scripts/Items/New Haven Quest Rewards/BulwarkLeggings.cs new file mode 100644 index 0000000..5e2ff87 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/BulwarkLeggings.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BulwarkLeggings : RingmailLegs + { + public override int LabelNumber{ get{ return 1077727; } } // Bulwark Leggings + + public override int BasePhysicalResistance{ get{ return 9; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + [Constructable] + public BulwarkLeggings() + { + LootType = LootType.Blessed; + + Attributes.RegenStam = 1; + Attributes.RegenMana = 1; + } + + public BulwarkLeggings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/ChurchillsWarMace.cs b/Scripts/Items/New Haven Quest Rewards/ChurchillsWarMace.cs new file mode 100644 index 0000000..d39ccea --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/ChurchillsWarMace.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ChurchillsWarMace : WarMace + { + public override int LabelNumber{ get{ return 1078062; } } // Churchill's War Mace + + [Constructable] + public ChurchillsWarMace() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + WeaponAttributes.LowerStatReq = 70; + } + + public ChurchillsWarMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/ClaspOfConcentration.cs b/Scripts/Items/New Haven Quest Rewards/ClaspOfConcentration.cs new file mode 100644 index 0000000..6531fe8 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/ClaspOfConcentration.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ClaspOfConcentration : SilverBracelet + { + public override int LabelNumber{ get{ return 1077695; } } // Clasp of Concentration + + [Constructable] + public ClaspOfConcentration() + { + LootType = LootType.Blessed; + + Attributes.RegenStam = 2; + Attributes.RegenMana = 1; + Resistances.Fire = 5; + Resistances.Cold = 5; + } + + public ClaspOfConcentration( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/EmberStaff.cs b/Scripts/Items/New Haven Quest Rewards/EmberStaff.cs new file mode 100644 index 0000000..87c8dd3 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/EmberStaff.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class EmberStaff : QuarterStaff + { + public override int LabelNumber{ get{ return 1077582; } } // Ember Staff + + [Constructable] + public EmberStaff() + { + LootType = LootType.Blessed; + + WeaponAttributes.HitFireball = 15; + WeaponAttributes.MageWeapon = 10; + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + WeaponAttributes.LowerStatReq = 50; + } + + public EmberStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs b/Scripts/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs new file mode 100644 index 0000000..5cdfb08 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/EscutcheonDeAriadne.cs @@ -0,0 +1,44 @@ +using System; +using Server; + +namespace Server.Items +{ + public class EscutcheonDeAriadne : MetalKiteShield + { + public override int LabelNumber{ get{ return 1077694; } } // Escutcheon de Ariadne + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 1; } } + + public override int AosStrReq{ get{ return 14; } } + + [Constructable] + public EscutcheonDeAriadne() + { + LootType = LootType.Blessed; + Hue = 0x8A5; + + ArmorAttributes.DurabilityBonus = 49; + Attributes.ReflectPhysical = 5; + Attributes.DefendChance = 5; + } + + public EscutcheonDeAriadne( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs b/Scripts/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs new file mode 100644 index 0000000..b2edac6 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/GlovesOfSafeguarding.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GlovesOfSafeguarding : LeatherGloves + { + public override int LabelNumber{ get{ return 1077614; } } // Gloves of Safeguarding + + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + [Constructable] + public GlovesOfSafeguarding() + { + LootType = LootType.Blessed; + + Attributes.BonusStam = 3; + Attributes.RegenHits = 1; + } + + public GlovesOfSafeguarding( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/HallowedSpellbook.cs b/Scripts/Items/New Haven Quest Rewards/HallowedSpellbook.cs new file mode 100644 index 0000000..145a822 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/HallowedSpellbook.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HallowedSpellbook : Spellbook + { + public override int LabelNumber { get { return 1077620; } } // Hallowed Spellbook + + [Constructable] + public HallowedSpellbook() : base( 0x3FFFFFFFF ) + { + LootType = LootType.Blessed; + + Slayer = SlayerName.Silver; + } + + public HallowedSpellbook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/HammerOfHephaestus.cs b/Scripts/Items/New Haven Quest Rewards/HammerOfHephaestus.cs new file mode 100644 index 0000000..a27d11c --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/HammerOfHephaestus.cs @@ -0,0 +1,74 @@ +using System; +using Server.Mobiles; + +namespace Server.Items +{ + [FlipableAttribute( 0x13E3, 0x13E4 )] + public class HammerOfHephaestus : SmithHammer + { + public override int LabelNumber{ get{ return 1077740; } } // Hammer of Hephaestus + + public static readonly TimeSpan RechargeDelay = TimeSpan.FromMinutes( 5 ); + + [Constructable] + public HammerOfHephaestus() + { + UsesRemaining = 20; + LootType = LootType.Blessed; + + // TODO: Blacksmith +10 bonus when equipped + + StartRechargeTimer(); + } + + public override bool BreakOnDepletion { get { return false; } } + /* Note: + * On EA, it also leaves the crafting gump open when it reaches 0 charges. + * When crafting again, only then the crafting gump closes with the 1072306 system message. + */ + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) && Parent != from ) // TODO: These checks don't match EA, but they match BaseTool for now + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + else if ( UsesRemaining <= 0 ) + from.SendLocalizedMessage( 1072306 ); // You must wait a moment for it to recharge. + else + base.OnDoubleClick( from ); + } + + private void StartRechargeTimer() + { + // TODO: Needs work + //Timer.DelayCall( RechargeDelay, RechargeDelay, new TimerCallback( Recharge ) ); + } + + public void Recharge() + { + // TODO: Stop timer at 20? Count downtime? Something more generic so we can use it for JacobsPickaxe too (both are IUsesRemaining)? + if ( UsesRemaining < 20 ) + ++UsesRemaining; + } + + public HammerOfHephaestus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + StartRechargeTimer(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/HealersTouch.cs b/Scripts/Items/New Haven Quest Rewards/HealersTouch.cs new file mode 100644 index 0000000..9cc3497 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/HealersTouch.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HealersTouch : LeatherGloves + { + public override int LabelNumber{ get{ return 1077684; } } // Healer's Touch + + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + [Constructable] + public HealersTouch() + { + LootType = LootType.Blessed; + + Attributes.BonusStam = 3; + Attributes.ReflectPhysical = 5; + } + + public HealersTouch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/Heartseeker.cs b/Scripts/Items/New Haven Quest Rewards/Heartseeker.cs new file mode 100644 index 0000000..a83696f --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/Heartseeker.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Heartseeker : CompositeBow + { + public override int LabelNumber{ get{ return 1078210; } } // Heartseeker + + [Constructable] + public Heartseeker() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + WeaponAttributes.LowerStatReq = 70; + } + + public Heartseeker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/JacobsPickaxe.cs b/Scripts/Items/New Haven Quest Rewards/JacobsPickaxe.cs new file mode 100644 index 0000000..23ce662 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/JacobsPickaxe.cs @@ -0,0 +1,40 @@ +using System; +using Server.Mobiles; + +namespace Server.Items +{ + public class JacobsPickaxe : Pickaxe + { + public override int LabelNumber{ get{ return 1077758; } } // Jacob's Pickaxe + + // TODO: Recharges 1 use every 5 minutes. Doesn't break when it reaches 0, you get a system message "You must wait a moment for it to recharge" 1072306 if you attempt to use it with no uses remaining. + + [Constructable] + public JacobsPickaxe() + { + UsesRemaining = 20; + LootType = LootType.Blessed; + + SkillBonuses.SetValues( 0, SkillName.Mining, 10.0 ); + } + + public JacobsPickaxe( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/JocklesQuicksword.cs b/Scripts/Items/New Haven Quest Rewards/JocklesQuicksword.cs new file mode 100644 index 0000000..af4fc28 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/JocklesQuicksword.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class JocklesQuicksword : Longsword + { + public override int LabelNumber{ get{ return 1077666; } } // Jockles' Quicksword + + [Constructable] + public JocklesQuicksword() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public JocklesQuicksword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/PhilosophersHat.cs b/Scripts/Items/New Haven Quest Rewards/PhilosophersHat.cs new file mode 100644 index 0000000..fe0b1a0 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/PhilosophersHat.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PhilosophersHat : WizardsHat + { + public override int LabelNumber{ get{ return 1077602; } } // Philosopher's Hat + + public override int BasePhysicalResistance{ get{ return 5; } } + public override int BaseFireResistance{ get{ return 5; } } + public override int BaseColdResistance{ get{ return 9; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + [Constructable] + public PhilosophersHat() + { + LootType = LootType.Blessed; + + Attributes.RegenMana = 1; + Attributes.LowerRegCost = 7; + } + + public PhilosophersHat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/RecarosRiposte.cs b/Scripts/Items/New Haven Quest Rewards/RecarosRiposte.cs new file mode 100644 index 0000000..364a4cf --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/RecarosRiposte.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RecarosRiposte : WarFork + { + public override int LabelNumber{ get{ return 1078195; } } // Recaro's Riposte + + [Constructable] + public RecarosRiposte() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public RecarosRiposte( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/RingOfTheSavant.cs b/Scripts/Items/New Haven Quest Rewards/RingOfTheSavant.cs new file mode 100644 index 0000000..485b0b9 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/RingOfTheSavant.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RingOfTheSavant : GoldRing + { + public override int LabelNumber{ get{ return 1077608; } } // Ring of the Savant + + [Constructable] + public RingOfTheSavant() + { + LootType = LootType.Blessed; + + Attributes.BonusInt = 3; + Attributes.CastRecovery = 1; + Attributes.CastSpeed = 1; + } + + public RingOfTheSavant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/SilverSerpentBlade.cs b/Scripts/Items/New Haven Quest Rewards/SilverSerpentBlade.cs new file mode 100644 index 0000000..306cf03 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/SilverSerpentBlade.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SilverSerpentBlade : Kryss + { + public override int LabelNumber{ get{ return 1078163; } } // Silver Serpent Blade + + [Constructable] + public SilverSerpentBlade() + { + LootType = LootType.Blessed; + + Attributes.AttackChance = 5; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public SilverSerpentBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/TheDragonsTail.cs b/Scripts/Items/New Haven Quest Rewards/TheDragonsTail.cs new file mode 100644 index 0000000..e2a1b9b --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/TheDragonsTail.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheDragonsTail : NoDachi + { + public override int LabelNumber { get { return 1078015; } } // The Dragon's Tail + + public override int InitMinHits{ get{ return 80; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public TheDragonsTail() + { + LootType = LootType.Blessed; + + WeaponAttributes.HitLeechStam = 16; + Attributes.WeaponSpeed = 10; + Attributes.WeaponDamage = 25; + } + + public TheDragonsTail( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/TunicOfGuarding.cs b/Scripts/Items/New Haven Quest Rewards/TunicOfGuarding.cs new file mode 100644 index 0000000..2d045af --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/TunicOfGuarding.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TunicOfGuarding : LeatherChest + { + public override int LabelNumber{ get{ return 1077693; } } // Tunic of Guarding + + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 5; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 5; } } + + [Constructable] + public TunicOfGuarding() + { + LootType = LootType.Blessed; + + Attributes.BonusHits = 2; + Attributes.ReflectPhysical = 5; + } + + public TunicOfGuarding( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/TwilightJacket.cs b/Scripts/Items/New Haven Quest Rewards/TwilightJacket.cs new file mode 100644 index 0000000..1ecd025 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/TwilightJacket.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TwilightJacket : LeatherNinjaJacket + { + public override int LabelNumber{ get{ return 1078183; } } // Twilight Jacket + + public override int BasePhysicalResistance{ get{ return 6; } } + public override int BaseFireResistance{ get{ return 12; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + [Constructable] + public TwilightJacket() + { + LootType = LootType.Blessed; + + Attributes.ReflectPhysical = 5; + } + + public TwilightJacket( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/New Haven Quest Rewards/WalkersLeggings.cs b/Scripts/Items/New Haven Quest Rewards/WalkersLeggings.cs new file mode 100644 index 0000000..b2fe5b0 --- /dev/null +++ b/Scripts/Items/New Haven Quest Rewards/WalkersLeggings.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WalkersLeggings : LeatherNinjaPants + { + public override int LabelNumber{ get{ return 1078222; } } // Walker's Leggings + + public override int BasePhysicalResistance{ get{ return 10; } } + public override int BaseFireResistance{ get{ return 6; } } + public override int BaseColdResistance{ get{ return 6; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + [Constructable] + public WalkersLeggings() + { + LootType = LootType.Blessed; + } + + public WalkersLeggings( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/PlantsFlowers/Potted/EmptyPots.cs b/Scripts/Items/PlantsFlowers/Potted/EmptyPots.cs new file mode 100644 index 0000000..6a6aca2 --- /dev/null +++ b/Scripts/Items/PlantsFlowers/Potted/EmptyPots.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Items +{ + public class SmallEmptyPot : Item + { + [Constructable] + public SmallEmptyPot() : base(0x11C6) + { + Weight = 100; + } + + public SmallEmptyPot(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class LargeEmptyPot : Item + { + [Constructable] + public LargeEmptyPot() : base(0x11C7) + { + Weight = 6; + } + + public LargeEmptyPot(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/PlantsFlowers/Potted/PottedCactus.cs b/Scripts/Items/PlantsFlowers/Potted/PottedCactus.cs new file mode 100644 index 0000000..c4312a7 --- /dev/null +++ b/Scripts/Items/PlantsFlowers/Potted/PottedCactus.cs @@ -0,0 +1,166 @@ +using System; + +namespace Server.Items +{ + public class PottedCactus : Item + { + [Constructable] + public PottedCactus() : base(0x1E0F) + { + Weight = 100; + } + + public PottedCactus(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus1 : Item + { + [Constructable] + public PottedCactus1() : base(0x1E10) + { + Weight = 100; + } + + public PottedCactus1(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus2 : Item + { + [Constructable] + public PottedCactus2() : base(0x1E11) + { + Weight = 100; + } + + public PottedCactus2(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus3 : Item + { + [Constructable] + public PottedCactus3() : base(0x1E12) + { + Weight = 100; + } + + public PottedCactus3(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus4 : Item + { + [Constructable] + public PottedCactus4() : base(0x1E13) + { + Weight = 100; + } + + public PottedCactus4(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedCactus5 : Item + { + [Constructable] + public PottedCactus5() : base(0x1E14) + { + Weight = 100; + } + + public PottedCactus5(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/PlantsFlowers/Potted/PottedPlants.cs b/Scripts/Items/PlantsFlowers/Potted/PottedPlants.cs new file mode 100644 index 0000000..5e476c0 --- /dev/null +++ b/Scripts/Items/PlantsFlowers/Potted/PottedPlants.cs @@ -0,0 +1,85 @@ +using System; + +namespace Server.Items +{ + public class PottedPlant : Item + { + [Constructable] + public PottedPlant() : base(0x11CA) + { + Weight = 100; + } + + public PottedPlant(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedPlant1 : Item + { + [Constructable] + public PottedPlant1() : base(0x11CB) + { + Weight = 100; + } + + public PottedPlant1(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedPlant2 : Item + { + [Constructable] + public PottedPlant2() : base(0x11CC) + { + Weight = 100; + } + + public PottedPlant2(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/PlantsFlowers/Potted/PottedTrees.cs b/Scripts/Items/PlantsFlowers/Potted/PottedTrees.cs new file mode 100644 index 0000000..bcb3943 --- /dev/null +++ b/Scripts/Items/PlantsFlowers/Potted/PottedTrees.cs @@ -0,0 +1,58 @@ +using System; + +namespace Server.Items +{ + public class PottedTree : Item + { + [Constructable] + public PottedTree() : base(0x11C8) + { + Weight = 100; + } + + public PottedTree(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PottedTree1 : Item + { + [Constructable] + public PottedTree1() : base(0x11C9) + { + Weight = 100; + } + + public PottedTree1(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Quivers/BaseQuiver.cs b/Scripts/Items/Quivers/BaseQuiver.cs new file mode 100644 index 0000000..6db6c28 --- /dev/null +++ b/Scripts/Items/Quivers/BaseQuiver.cs @@ -0,0 +1,469 @@ +using System; +using Server.Network; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class BaseQuiver : Container, ICraftable + { + public override int DefaultGumpID{ get{ return 0x108; } } + public override int DefaultMaxItems{ get{ return 1; } } + public override int DefaultMaxWeight{ get{ return 50; } } + public override double DefaultWeight{ get{ return 2.0; } } + + private AosAttributes m_Attributes; + private int m_Capacity; + private int m_LowerAmmoCost; + private int m_WeightReduction; + private int m_DamageIncrease; + + [CommandProperty( AccessLevel.GameMaster)] + public AosAttributes Attributes + { + get{ return m_Attributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster)] + public int Capacity + { + get{ return m_Capacity; } + set{ m_Capacity = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster)] + public int LowerAmmoCost + { + get{ return m_LowerAmmoCost; } + set{ m_LowerAmmoCost = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster)] + public int WeightReduction + { + get{ return m_WeightReduction; } + set{ m_WeightReduction = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster)] + public int DamageIncrease + { + get{ return m_DamageIncrease; } + set{ m_DamageIncrease = value; InvalidateProperties(); } + } + + private Mobile m_Crafter; + private ClothingQuality m_Quality; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ClothingQuality Quality + { + get{ return m_Quality; } + set{ m_Quality = value; InvalidateProperties(); } + } + + public Item Ammo + { + get{ return Items.Count > 0 ? Items[ 0 ] : null; } + } + + public BaseQuiver() : this( 0x2FB7 ) + { + } + + public BaseQuiver( int itemID ) : base( itemID ) + { + Weight = 2.0; + Capacity = 500; + Layer = Layer.Cloak; + + m_Attributes = new AosAttributes( this ); + DamageIncrease = 10; + } + + public BaseQuiver( Serial serial ) : base( serial ) + { + } + + public override void OnAfterDuped( Item newItem ) + { + BaseQuiver quiver = newItem as BaseQuiver; + + if ( quiver == null ) + return; + + quiver.m_Attributes = new AosAttributes( newItem, m_Attributes ); + } + + public override void UpdateTotal( Item sender, TotalType type, int delta ) + { + InvalidateProperties(); + + base.UpdateTotal(sender, type, delta); + } + + public override int GetTotal( TotalType type ) + { + int total = base.GetTotal( type ); + + if ( type == TotalType.Weight ) + total -= total * m_WeightReduction / 100; + + return total; + } + + private static Type[] m_Ammo = new Type[] + { + typeof( Arrow ), typeof( Bolt ) + }; + + public bool CheckType( Item item ) + { + Type type = item.GetType(); + Item ammo = Ammo; + + if ( ammo != null ) + { + if ( ammo.GetType() == type ) + return true; + } + else + { + for ( int i = 0; i < m_Ammo.Length; i++ ) + { + if ( type == m_Ammo[ i ] ) + return true; + } + } + + return false; + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + if ( !CheckType( item ) ) + { + if ( message ) + m.SendLocalizedMessage( 1074836 ); // The container can not hold that type of object. + + return false; + } + + if ( Items.Count < DefaultMaxItems ) + { + if ( item.Amount <= m_Capacity ) + return base.CheckHold( m, item, message, checkItems, plusItems, plusWeight ); + + return false; + } + else if ( checkItems ) + return false; + + Item ammo = Ammo; + + if ( ammo == null || ammo.Deleted ) + return false; + + if ( ammo.Amount + item.Amount <= m_Capacity ) + return true; + + return false; + } + + public override void AddItem( Item dropped ) + { + base.AddItem( dropped ); + + InvalidateWeight(); + } + + public override void RemoveItem( Item dropped ) + { + base.RemoveItem( dropped ); + + InvalidateWeight(); + } + + public override void OnAdded( object parent ) + { + if ( parent is Mobile ) + { + Mobile mob = (Mobile) parent; + + m_Attributes.AddStatBonuses( mob ); + } + } + + public override void OnRemoved( object parent ) + { + if ( parent is Mobile ) + { + Mobile mob = (Mobile) parent; + + m_Attributes.RemoveStatBonuses( mob ); + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if ( m_Quality == ClothingQuality.Exceptional ) + list.Add( 1063341 ); // exceptional + + Item ammo = Ammo; + + if ( ammo != null ) + { + if ( ammo is Arrow ) + list.Add( 1075265, "{0}\t{1}", ammo.Amount, Capacity ); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows + else if ( ammo is Bolt ) + list.Add( 1075266, "{0}\t{1}", ammo.Amount, Capacity ); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ bolts + } + else + list.Add( 1075265, "{0}\t{1}", 0, Capacity ); // Ammo: ~1_QUANTITY~/~2_CAPACITY~ arrows + + int prop; + + if ( (prop = m_DamageIncrease) != 0 ) + list.Add( 1074762, prop.ToString() ); // Damage modifier: ~1_PERCENT~% + + int phys, fire, cold, pois, nrgy, chaos, direct; + phys = fire = cold = pois = nrgy = chaos = direct = 0; + + AlterBowDamage( ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct ); + + if ( phys != 0 ) + list.Add( 1060403, phys.ToString() ); // physical damage ~1_val~% + + if ( fire != 0 ) + list.Add( 1060405, fire.ToString() ); // fire damage ~1_val~% + + if ( cold != 0 ) + list.Add( 1060404, cold.ToString() ); // cold damage ~1_val~% + + if ( pois != 0 ) + list.Add( 1060406, pois.ToString() ); // poison damage ~1_val~% + + if ( nrgy != 0 ) + list.Add( 1060407, nrgy.ToString() ); // energy damage ~1_val + + if ( chaos != 0 ) + list.Add( 1072846, chaos.ToString() ); // chaos damage ~1_val~% + + if ( direct != 0 ) + list.Add( 1079978, direct.ToString() ); // Direct Damage: ~1_PERCENT~% + + list.Add( 1075085 ); // Requirement: Mondain's Legacy + + if ( (prop = m_Attributes.DefendChance) != 0 ) + list.Add( 1060408, prop.ToString() ); // defense chance increase ~1_val~% + + if ( (prop = m_Attributes.BonusDex) != 0 ) + list.Add( 1060409, prop.ToString() ); // dexterity bonus ~1_val~ + + if ( (prop = m_Attributes.EnhancePotions) != 0 ) + list.Add( 1060411, prop.ToString() ); // enhance potions ~1_val~% + + if ( (prop = m_Attributes.CastRecovery) != 0 ) + list.Add( 1060412, prop.ToString() ); // faster cast recovery ~1_val~ + + if ( (prop = m_Attributes.CastSpeed) != 0 ) + list.Add( 1060413, prop.ToString() ); // faster casting ~1_val~ + + if ( (prop = m_Attributes.AttackChance) != 0 ) + list.Add( 1060415, prop.ToString() ); // hit chance increase ~1_val~% + + if ( (prop = m_Attributes.BonusHits) != 0 ) + list.Add( 1060431, prop.ToString() ); // hit point increase ~1_val~ + + if ( (prop = m_Attributes.BonusInt) != 0 ) + list.Add( 1060432, prop.ToString() ); // intelligence bonus ~1_val~ + + if ( (prop = m_Attributes.LowerManaCost) != 0 ) + list.Add( 1060433, prop.ToString() ); // lower mana cost ~1_val~% + + if ( (prop = m_Attributes.LowerRegCost) != 0 ) + list.Add( 1060434, prop.ToString() ); // lower reagent cost ~1_val~% + + if ( (prop = m_Attributes.Luck) != 0 ) + list.Add( 1060436, prop.ToString() ); // luck ~1_val~ + + if ( (prop = m_Attributes.BonusMana) != 0 ) + list.Add( 1060439, prop.ToString() ); // mana increase ~1_val~ + + if ( (prop = m_Attributes.RegenMana) != 0 ) + list.Add( 1060440, prop.ToString() ); // mana regeneration ~1_val~ + + if ( (prop = m_Attributes.NightSight) != 0 ) + list.Add( 1060441 ); // night sight + + if ( (prop = m_Attributes.ReflectPhysical) != 0 ) + list.Add( 1060442, prop.ToString() ); // reflect physical damage ~1_val~% + + if ( (prop = m_Attributes.RegenStam) != 0 ) + list.Add( 1060443, prop.ToString() ); // stamina regeneration ~1_val~ + + if ( (prop = m_Attributes.RegenHits) != 0 ) + list.Add( 1060444, prop.ToString() ); // hit point regeneration ~1_val~ + + if ( (prop = m_Attributes.SpellDamage) != 0 ) + list.Add( 1060483, prop.ToString() ); // spell damage increase ~1_val~% + + if ( (prop = m_Attributes.BonusStam) != 0 ) + list.Add( 1060484, prop.ToString() ); // stamina increase ~1_val~ + + if ( (prop = m_Attributes.BonusStr) != 0 ) + list.Add( 1060485, prop.ToString() ); // strength bonus ~1_val~ + + if ( (prop = m_Attributes.WeaponSpeed) != 0 ) + list.Add( 1060486, prop.ToString() ); // swing speed increase ~1_val~% + + if ( (prop = m_LowerAmmoCost) > 0 ) + list.Add( 1075208, prop.ToString() ); // Lower Ammo Cost ~1_Percentage~% + + double weight = 0; + + if ( ammo != null ) + weight = ammo.Weight * ammo.Amount; + + list.Add( 1072241, "{0}\t{1}\t{2}\t{3}", Items.Count, DefaultMaxItems, (int) weight, DefaultMaxWeight ); // Contents: ~1_COUNT~/~2_MAXCOUNT items, ~3_WEIGHT~/~4_MAXWEIGHT~ stones + + if ( (prop = m_WeightReduction) != 0 ) + list.Add( 1072210, prop.ToString() ); // Weight reduction: ~1_PERCENTAGE~% + } + + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Attributes = 0x00000001, + DamageModifier = 0x00000002, + LowerAmmoCost = 0x00000004, + WeightReduction = 0x00000008, + Crafter = 0x00000010, + Quality = 0x00000020, + Capacity = 0x00000040, + DamageIncrease = 0x00000080 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( 0 ); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag( ref flags, SaveFlag.Attributes, !m_Attributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.LowerAmmoCost, m_LowerAmmoCost != 0 ); + SetSaveFlag( ref flags, SaveFlag.WeightReduction, m_WeightReduction != 0 ); + SetSaveFlag( ref flags, SaveFlag.DamageIncrease, m_DamageIncrease != 0 ); + SetSaveFlag( ref flags, SaveFlag.Crafter, m_Crafter != null ); + SetSaveFlag( ref flags, SaveFlag.Quality, true ); + SetSaveFlag( ref flags, SaveFlag.Capacity, m_Capacity > 0 ); + + writer.WriteEncodedInt( (int) flags ); + + if ( GetSaveFlag( flags, SaveFlag.Attributes ) ) + m_Attributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.LowerAmmoCost ) ) + writer.Write( (int) m_LowerAmmoCost ); + + if ( GetSaveFlag( flags, SaveFlag.WeightReduction ) ) + writer.Write( (int) m_WeightReduction ); + + if ( GetSaveFlag( flags, SaveFlag.DamageIncrease ) ) + writer.Write( (int) m_DamageIncrease ); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + writer.Write( (Mobile) m_Crafter ); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + writer.Write( (int) m_Quality ); + + if ( GetSaveFlag( flags, SaveFlag.Capacity ) ) + writer.Write( (int) m_Capacity ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + SaveFlag flags = (SaveFlag) reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Attributes ) ) + m_Attributes = new AosAttributes( this, reader ); + else + m_Attributes = new AosAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.LowerAmmoCost ) ) + m_LowerAmmoCost = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.WeightReduction ) ) + m_WeightReduction = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.DamageIncrease ) ) + m_DamageIncrease = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + m_Crafter = reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + m_Quality = (ClothingQuality) reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Capacity ) ) + m_Capacity = reader.ReadInt(); + } + + public virtual void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + } + + public void InvalidateWeight() + { + if ( RootParent is Mobile ) + { + Mobile m = (Mobile) RootParent; + + m.UpdateTotals(); + } + } + + #region ICraftable + public virtual int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (ClothingQuality) quality; + + if ( makersMark ) + Crafter = from; + + return quality; + } + #endregion + } +} diff --git a/Scripts/Items/Quivers/ElvenQuiver.cs b/Scripts/Items/Quivers/ElvenQuiver.cs new file mode 100644 index 0000000..c42e92d --- /dev/null +++ b/Scripts/Items/Quivers/ElvenQuiver.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x2FB7, 0x3171 )] + public class ElvenQuiver : BaseQuiver + { + public override int LabelNumber{ get{ return 1032657; } } // elven quiver + + [Constructable] + public ElvenQuiver() : base() + { + WeightReduction = 30; + } + + public ElvenQuiver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Quivers/QuiverOfBlight.cs b/Scripts/Items/Quivers/QuiverOfBlight.cs new file mode 100644 index 0000000..ef14547 --- /dev/null +++ b/Scripts/Items/Quivers/QuiverOfBlight.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class QuiverOfBlight : ElvenQuiver + { + public override int LabelNumber{ get{ return 1073111; } } // Quiver of Blight + + [Constructable] + public QuiverOfBlight() : base() + { + Hue = 0x4F3; + } + + public QuiverOfBlight( Serial serial ) : base( serial ) + { + } + + public override void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + phys = fire = nrgy = chaos = direct = 0; + cold = pois = 50; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Quivers/QuiverOfFire.cs b/Scripts/Items/Quivers/QuiverOfFire.cs new file mode 100644 index 0000000..2b70c24 --- /dev/null +++ b/Scripts/Items/Quivers/QuiverOfFire.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class QuiverOfFire : ElvenQuiver + { + public override int LabelNumber{ get{ return 1073109; } } // quiver of fire + + [Constructable] + public QuiverOfFire() : base() + { + Hue = 0x4E7; + } + + public QuiverOfFire( Serial serial ) : base( serial ) + { + } + + public override void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + cold = pois = nrgy = chaos = direct = 0; + phys = fire = 50; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Quivers/QuiverOfIce.cs b/Scripts/Items/Quivers/QuiverOfIce.cs new file mode 100644 index 0000000..e49706d --- /dev/null +++ b/Scripts/Items/Quivers/QuiverOfIce.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class QuiverOfIce : ElvenQuiver + { + public override int LabelNumber{ get{ return 1073110; } } // quiver of ice + + [Constructable] + public QuiverOfIce() : base() + { + Hue = 0x4ED; + } + + public QuiverOfIce( Serial serial ) : base( serial ) + { + } + + public override void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + fire = pois = nrgy = chaos = direct = 0; + phys = cold = 50; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Quivers/QuiverOfLightning.cs b/Scripts/Items/Quivers/QuiverOfLightning.cs new file mode 100644 index 0000000..02ba45f --- /dev/null +++ b/Scripts/Items/Quivers/QuiverOfLightning.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class QuiverOfLightning : ElvenQuiver + { + public override int LabelNumber{ get{ return 1073112; } } // Quiver of Lightning + + [Constructable] + public QuiverOfLightning() : base() + { + Hue = 0x4F9; + } + + public QuiverOfLightning( Serial serial ) : base( serial ) + { + } + + public override void AlterBowDamage( ref int phys, ref int fire, ref int cold, ref int pois, ref int nrgy, ref int chaos, ref int direct ) + { + fire = cold = pois = chaos = direct = 0; + phys = nrgy = 50; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Resources/Arrows/Arrow.cs b/Scripts/Items/Resources/Arrows/Arrow.cs new file mode 100644 index 0000000..12aadb8 --- /dev/null +++ b/Scripts/Items/Resources/Arrows/Arrow.cs @@ -0,0 +1,47 @@ +using System; + +namespace Server.Items +{ + public class Arrow : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Arrow() : this( 1 ) + { + } + + [Constructable] + public Arrow( int amount ) : base( 0xF3F ) + { + Stackable = true; + Amount = amount; + } + + public Arrow( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Arrows/Bolt.cs b/Scripts/Items/Resources/Arrows/Bolt.cs new file mode 100644 index 0000000..1c461aa --- /dev/null +++ b/Scripts/Items/Resources/Arrows/Bolt.cs @@ -0,0 +1,47 @@ +using System; + +namespace Server.Items +{ + public class Bolt : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Bolt() : this( 1 ) + { + } + + [Constructable] + public Bolt( int amount ) : base( 0x1BFB ) + { + Stackable = true; + Amount = amount; + } + + public Bolt( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Arrows/Feather.cs b/Scripts/Items/Resources/Arrows/Feather.cs new file mode 100644 index 0000000..429ec78 --- /dev/null +++ b/Scripts/Items/Resources/Arrows/Feather.cs @@ -0,0 +1,48 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class Feather : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Feather() : this( 1 ) + { + } + + [Constructable] + public Feather( int amount ) : base( 0x1BD1 ) + { + Stackable = true; + Amount = amount; + } + + public Feather( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Arrows/Shaft.cs b/Scripts/Items/Resources/Arrows/Shaft.cs new file mode 100644 index 0000000..bd72a9c --- /dev/null +++ b/Scripts/Items/Resources/Arrows/Shaft.cs @@ -0,0 +1,48 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class Shaft : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Shaft() : this( 1 ) + { + } + + [Constructable] + public Shaft( int amount ) : base( 0x1BD4 ) + { + Stackable = true; + Amount = amount; + } + + public Shaft( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Blacksmithing/Ingots.cs b/Scripts/Items/Resources/Blacksmithing/Ingots.cs new file mode 100644 index 0000000..c27b07d --- /dev/null +++ b/Scripts/Items/Resources/Blacksmithing/Ingots.cs @@ -0,0 +1,1209 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseIngot : Item, ICommodity + { + private CraftResource m_Resource; + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get{ return m_Resource; } + set{ m_Resource = value; InvalidateProperties(); } + } + + public override double DefaultWeight + { + get { return 0.1; } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + + + bool ICommodity.IsDeedable { get { return true; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Resource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + OreInfo info; + + switch ( reader.ReadInt() ) + { + case 0: info = OreInfo.MIron; break; + case 1: info = OreInfo.MBronze; break; + case 2: info = OreInfo.MGold; break; + case 3: info = OreInfo.MCopper; break; + case 4: info = OreInfo.MOldcopper; break; + case 5: info = OreInfo.MDullcopper; break; + case 6: info = OreInfo.MSilver; break; + case 7: info = OreInfo.MShadow; break; + case 8: info = OreInfo.MBloodrock; break; + case 9: info = OreInfo.MBlackrock; break; + case 10: info = OreInfo.MMytheril; break; + case 11: info = OreInfo.MRose; break; + case 12: info = OreInfo.MVerite; break; + case 13: info = OreInfo.MAgapite; break; + case 14: info = OreInfo.MRusty; break; + case 15: info = OreInfo.MValorite; break; + case 16: info = OreInfo.MDragon; break; + case 17: info = OreInfo.MTitan; break; + case 18: info = OreInfo.MCrystaline; break; + case 19: info = OreInfo.MKrynite; break; + case 20: info = OreInfo.MVulcan; break; + case 21: info = OreInfo.MBloodcrest; break; + case 22: info = OreInfo.MElvin; break; + case 23: info = OreInfo.MAcid; break; + case 24: info = OreInfo.MAqua; break; + case 25: info = OreInfo.MEldar; break; + case 26: info = OreInfo.MGlowing; break; + case 27: info = OreInfo.MGorgan; break; + case 28: info = OreInfo.MSandrock; break; + case 29: info = OreInfo.MSteel; break; + default: info = null; break; + } + + m_Resource = CraftResources.GetFromOreInfo( info ); + break; + } + } + } + + public BaseIngot( CraftResource resource ) : this( resource, 1 ) + { + } + + public BaseIngot( CraftResource resource, int amount ) : base( 0x1BF2 ) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue( resource ); + m_Resource = resource; + } + + public BaseIngot( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( Amount > 1 ) + list.Add( 1050039, "{0}\t#{1}", Amount, 1027154 ); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add( 1027154 ); // ingots + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( !CraftResources.IsStandard( m_Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( m_Resource ); + + if ( num > 0 ) + list.Add( num ); + else + list.Add( CraftResources.GetName( m_Resource ) ); + } + } + + /*public override int LabelNumber + { + get + { + if (m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite) + return 1042684 + (int)(m_Resource - CraftResource.DullCopper); + + return 1042692; + } + }*/ + + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class IronIngot : BaseIngot + { + [Constructable] + public IronIngot() : this( 1 ) + { + } + + [Constructable] + public IronIngot( int amount ) : base( CraftResource.MIron, amount ) + { + } + + public IronIngot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class BronzeIngot : BaseIngot + { + [Constructable] + public BronzeIngot() : this( 1 ) + { + } + + [Constructable] + public BronzeIngot( int amount ) : base( CraftResource.MBronze, amount ) + { + } + + public BronzeIngot(Serial serial) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class GoldIngot : BaseIngot + { + [Constructable] + public GoldIngot() : this(1) + { + } + + [Constructable] + public GoldIngot( int amount ) : base( CraftResource.MGold, amount ) + { + } + + public GoldIngot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class CopperIngot : BaseIngot + { + [Constructable] + public CopperIngot() : this( 1 ) + { + } + + [Constructable] + public CopperIngot( int amount ) : base( CraftResource.MCopper, amount ) + { + } + + public CopperIngot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class OldcopperIngot : BaseIngot + { + [Constructable] + public OldcopperIngot() : this( 1 ) + { + } + + [Constructable] + public OldcopperIngot(int amount) + : base(CraftResource.MOldcopper, amount) + { + } + + public OldcopperIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class DullcopperIngot : BaseIngot + { + [Constructable] + public DullcopperIngot() : this( 1 ) + { + } + + [Constructable] + public DullcopperIngot( int amount ) : base( CraftResource.MDullcopper, amount ) + { + } + + public DullcopperIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class SilverIngot : BaseIngot + { + [Constructable] + public SilverIngot() : this( 1 ) + { + } + + [Constructable] + public SilverIngot( int amount ) : base( CraftResource.MSilver, amount ) + { + } + + public SilverIngot(Serial serial) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class ShadowIngot : BaseIngot + { + [Constructable] + public ShadowIngot() : this( 1 ) + { + } + + [Constructable] + public ShadowIngot( int amount ) : base( CraftResource.MShadow, amount ) + { + } + + public ShadowIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1BF2, 0x1BEF )] + public class BloodrockIngot : BaseIngot + { + [Constructable] + public BloodrockIngot() : this( 1 ) + { + } + + [Constructable] + public BloodrockIngot( int amount ) : base( CraftResource.MBloodrock, amount ) + { + } + + public BloodrockIngot(Serial serial) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class BlackrockIngot : BaseIngot + { + [Constructable] + public BlackrockIngot() : this(1) + { + } + + [Constructable] + public BlackrockIngot(int amount) + : base(CraftResource.MBlackrock, amount) + { + } + + public BlackrockIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class MytherilIngot : BaseIngot + { + [Constructable] + public MytherilIngot() + : this(1) + { + } + + [Constructable] + public MytherilIngot(int amount) + : base(CraftResource.MMytheril, amount) + { + } + + public MytherilIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class RoseIngot : BaseIngot + { + [Constructable] + public RoseIngot() + : this(1) + { + } + + [Constructable] + public RoseIngot(int amount) + : base(CraftResource.MRose, amount) + { + } + + public RoseIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class VeriteIngot : BaseIngot + { + [Constructable] + public VeriteIngot() + : this(1) + { + } + + [Constructable] + public VeriteIngot(int amount) + : base(CraftResource.MVerite, amount) + { + } + + public VeriteIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class AgapiteIngot : BaseIngot + { + [Constructable] + public AgapiteIngot() + : this(1) + { + } + + [Constructable] + public AgapiteIngot(int amount) + : base(CraftResource.MAgapite, amount) + { + } + + public AgapiteIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class RustyIngot : BaseIngot + { + [Constructable] + public RustyIngot() + : this(1) + { + } + + [Constructable] + public RustyIngot(int amount) + : base(CraftResource.MRusty, amount) + { + } + + public RustyIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class ValoriteIngot : BaseIngot + { + [Constructable] + public ValoriteIngot() + : this(1) + { + } + + [Constructable] + public ValoriteIngot(int amount) + : base(CraftResource.MValorite, amount) + { + } + + public ValoriteIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class DragonIngot : BaseIngot + { + [Constructable] + public DragonIngot() + : this(1) + { + } + + [Constructable] + public DragonIngot(int amount) + : base(CraftResource.MDragon, amount) + { + } + + public DragonIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class TitanIngot : BaseIngot + { + [Constructable] + public TitanIngot() + : this(1) + { + } + + [Constructable] + public TitanIngot(int amount) + : base(CraftResource.MTitan, amount) + { + } + + public TitanIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class CrystalineIngot : BaseIngot + { + [Constructable] + public CrystalineIngot() + : this(1) + { + } + + [Constructable] + public CrystalineIngot(int amount) + : base(CraftResource.MCrystaline, amount) + { + } + + public CrystalineIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class KryniteIngot : BaseIngot + { + [Constructable] + public KryniteIngot() + : this(1) + { + } + + [Constructable] + public KryniteIngot(int amount) + : base(CraftResource.MKrynite, amount) + { + } + + public KryniteIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class VulcanIngot : BaseIngot + { + [Constructable] + public VulcanIngot() + : this(1) + { + } + + [Constructable] + public VulcanIngot(int amount) + : base(CraftResource.MVulcan, amount) + { + } + + public VulcanIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class BloodcrestIngot : BaseIngot + { + [Constructable] + public BloodcrestIngot() + : this(1) + { + } + + [Constructable] + public BloodcrestIngot(int amount) + : base(CraftResource.MBloodcrest, amount) + { + } + + public BloodcrestIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class ElvinIngot : BaseIngot + { + [Constructable] + public ElvinIngot() + : this(1) + { + } + + [Constructable] + public ElvinIngot(int amount) + : base(CraftResource.MElvin, amount) + { + } + + public ElvinIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class AcidIngot : BaseIngot + { + [Constructable] + public AcidIngot() + : this(1) + { + } + + [Constructable] + public AcidIngot(int amount) + : base(CraftResource.MAcid, amount) + { + } + + public AcidIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class AquaIngot : BaseIngot + { + [Constructable] + public AquaIngot() + : this(1) + { + } + + [Constructable] + public AquaIngot(int amount) + : base(CraftResource.MAqua, amount) + { + } + + public AquaIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class EldarIngot : BaseIngot + { + [Constructable] + public EldarIngot() + : this(1) + { + } + + [Constructable] + public EldarIngot(int amount) + : base(CraftResource.MEldar, amount) + { + } + + public EldarIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class GlowingIngot : BaseIngot + { + [Constructable] + public GlowingIngot() + : this(1) + { + } + + [Constructable] + public GlowingIngot(int amount) + : base(CraftResource.MGlowing, amount) + { + } + + public GlowingIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class GorganIngot : BaseIngot + { + [Constructable] + public GorganIngot() + : this(1) + { + } + + [Constructable] + public GorganIngot(int amount) + : base(CraftResource.MGorgan, amount) + { + } + + public GorganIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class SandrockIngot : BaseIngot + { + [Constructable] + public SandrockIngot() + : this(1) + { + } + + [Constructable] + public SandrockIngot(int amount) + : base(CraftResource.MSandrock, amount) + { + } + + public SandrockIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x1BF2, 0x1BEF)] + public class SteelIngot : BaseIngot + { + [Constructable] + public SteelIngot() + : this(1) + { + } + + [Constructable] + public SteelIngot(int amount) + : base(CraftResource.MSteel, amount) + { + } + + public SteelIngot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Blacksmithing/Ore.cs b/Scripts/Items/Resources/Blacksmithing/Ore.cs new file mode 100644 index 0000000..70aace6 --- /dev/null +++ b/Scripts/Items/Resources/Blacksmithing/Ore.cs @@ -0,0 +1,1884 @@ + +using System; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Engines.Craft; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Items +{ + public abstract class BaseOre : Item + { + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; InvalidateProperties(); } + } + + public abstract BaseIngot GetIngot(); + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + OreInfo info; + + switch (reader.ReadInt()) + { + case 0: info = OreInfo.MIron; break; + case 1: info = OreInfo.MBronze; break; + case 2: info = OreInfo.MGold; break; + case 3: info = OreInfo.MCopper; break; + case 4: info = OreInfo.MOldcopper; break; + case 5: info = OreInfo.MDullcopper; break; + case 6: info = OreInfo.MSilver; break; + case 7: info = OreInfo.MShadow; break; + case 8: info = OreInfo.MBloodrock; break; + case 9: info = OreInfo.MBlackrock; break; + case 10: info = OreInfo.MMytheril; break; + case 11: info = OreInfo.MRose; break; + case 12: info = OreInfo.MVerite; break; + case 13: info = OreInfo.MAgapite; break; + case 14: info = OreInfo.MRusty; break; + case 15: info = OreInfo.MValorite; break; + case 16: info = OreInfo.MDragon; break; + case 17: info = OreInfo.MTitan; break; + case 18: info = OreInfo.MCrystaline; break; + case 19: info = OreInfo.MKrynite; break; + case 20: info = OreInfo.MVulcan; break; + case 21: info = OreInfo.MBloodcrest; break; + case 22: info = OreInfo.MElvin; break; + case 23: info = OreInfo.MAcid; break; + case 24: info = OreInfo.MAqua; break; + case 25: info = OreInfo.MEldar; break; + case 26: info = OreInfo.MGlowing; break; + case 27: info = OreInfo.MGorgan; break; + case 28: info = OreInfo.MSandrock; break; + case 29: info = OreInfo.MSteel; break; + default: info = null; break; + } + + m_Resource = CraftResources.GetFromOreInfo(info); + break; + } + } + } + + private static int RandomSize() + { + double rand = Utility.RandomDouble(); + + if (rand < 0.12) + return 0x19B7; + else if (rand < 0.18) + return 0x19B8; + else if (rand < 0.25) + return 0x19BA; + else + return 0x19B9; + } + + public BaseOre(CraftResource resource) + : this(resource, 1) + { + } + + public BaseOre(CraftResource resource, int amount) + : base(RandomSize()) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue(resource); + + m_Resource = resource; + } + + public BaseOre(Serial serial) + : base(serial) + { + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (Amount > 1) + list.Add(1050039, "{0}\t#{1}", Amount, 1026583); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add(1026583); // ore + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + + /*public override int LabelNumber + { + get + { + if ( m_Resource >= CraftResource.DullCopper && m_Resource <= CraftResource.Valorite ) + return 1042845 + (int)(m_Resource - CraftResource.DullCopper); + + return 1042853; // iron ore; + } + }*/ + + public override void OnDoubleClick(Mobile from) + { + if (!Movable) + return; + + if (RootParent is BaseCreature) + { + from.SendLocalizedMessage(500447); // That is not accessible + return; + } + else if (from.InRange(this.GetWorldLocation(), 2)) + { + from.SendLocalizedMessage(501971); // Select the forge on which to smelt the ore, or another pile of ore with which to combine it. + from.Target = new InternalTarget(this); + } + else + { + from.SendLocalizedMessage(501976); // The ore is too far away. + } + } + + private class InternalTarget : Target + { + private BaseOre m_Ore; + + public InternalTarget(BaseOre ore) + : base(2, false, TargetFlags.None) + { + m_Ore = ore; + } + + private bool IsForge(object obj) + { + if (Core.ML && obj is Mobile && ((Mobile)obj).IsDeadBondedPet) + return false; + + if (obj.GetType().IsDefined(typeof(ForgeAttribute), false)) + return true; + + int itemID = 0; + + if (obj is Item) + itemID = ((Item)obj).ItemID; + else if (obj is StaticTarget) + itemID = ((StaticTarget)obj).ItemID; + + return (itemID == 4017 || (itemID >= 6522 && itemID <= 6569)); + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Ore.Deleted) + return; + + if (!from.InRange(m_Ore.GetWorldLocation(), 2)) + { + from.SendLocalizedMessage(501976); // The ore is too far away. + return; + } + + #region Combine Ore + if (targeted is BaseOre) + { + BaseOre ore = (BaseOre)targeted; + if (!ore.Movable) + return; + if (!ore.Stackable || !m_Ore.Stackable) + return; + else if (m_Ore == ore) + { + from.SendLocalizedMessage(501972); // Select another pile or ore with which to combine this. + from.Target = new InternalTarget(ore); + return; + } + else if (ore.Resource != m_Ore.Resource) + { + from.SendLocalizedMessage(501979); // You cannot combine ores of different metals. + return; + } + + int worth = ore.Amount; + if (ore.ItemID == 0x19B9) + worth *= 8; + else if (ore.ItemID == 0x19B7) + worth *= 2; + else + worth *= 4; + int sourceWorth = m_Ore.Amount; + if (m_Ore.ItemID == 0x19B9) + sourceWorth *= 8; + else if (m_Ore.ItemID == 0x19B7) + sourceWorth *= 2; + else + sourceWorth *= 4; + worth += sourceWorth; + + int plusWeight = 0; + int newID = ore.ItemID; + if (ore.DefaultWeight != m_Ore.DefaultWeight) + { + if (ore.ItemID == 0x19B7 || m_Ore.ItemID == 0x19B7) + { + newID = 0x19B7; + } + else if (ore.ItemID == 0x19B9) + { + newID = m_Ore.ItemID; + plusWeight = ore.Amount * 2; + } + else + { + plusWeight = m_Ore.Amount * 2; + } + } + + if ((ore.ItemID == 0x19B9 && worth > 120000) || ((ore.ItemID == 0x19B8 || ore.ItemID == 0x19BA) && worth > 60000) || (ore.ItemID == 0x19B7 && worth > 30000)) + { + from.SendLocalizedMessage(1062844); // There is too much ore to combine. + return; + } + else if (ore.RootParent is Mobile && (plusWeight + ((Mobile)ore.RootParent).Backpack.TotalWeight) > ((Mobile)ore.RootParent).Backpack.MaxWeight) + { + from.SendLocalizedMessage(501978); // The weight is too great to combine in a container. + return; + } + + ore.ItemID = newID; + + if (ore.ItemID == 0x19B9) + ore.Amount = worth / 8; + else if (ore.ItemID == 0x19B7) + ore.Amount = worth / 2; + else + ore.Amount = worth / 4; + + m_Ore.Delete(); + return; + } + #endregion + + if (IsForge(targeted)) + { + double difficulty; + + switch (m_Ore.Resource) + { + default: difficulty = 50.0; break; + case CraftResource.MRusty: difficulty = 25.0; break; + case CraftResource.MOldcopper: difficulty = 30.0; break; + case CraftResource.MDullcopper: difficulty = 40.0; break; + case CraftResource.MShadow: difficulty = 60.0; break; + case CraftResource.MCopper: difficulty = 50.0; break; + case CraftResource.MBronze: difficulty = 55.0; break; + case CraftResource.MGold: difficulty = 65.0; break; + case CraftResource.MRose: difficulty = 45.0; break; + case CraftResource.MAgapite: difficulty = 70.0; break; + case CraftResource.MValorite: difficulty = 90.0; break; + case CraftResource.MBloodrock: difficulty = 93.0; break; + case CraftResource.MVerite: difficulty = 95.0; break; + case CraftResource.MSilver: difficulty = 85.0; break; + case CraftResource.MDragon: difficulty = 82.0; break; + case CraftResource.MTitan: difficulty = 75.0; break; + case CraftResource.MCrystaline: difficulty = 95.0; break; + case CraftResource.MKrynite: difficulty = 95.0; break; + case CraftResource.MVulcan: difficulty = 0; break; + case CraftResource.MBloodcrest: difficulty = 95.0; break; + case CraftResource.MElvin: difficulty = 95.0; break; + case CraftResource.MAcid: difficulty = 95.0; break; + case CraftResource.MAqua: difficulty = 95.0; break; + case CraftResource.MEldar: difficulty = 75.0; break; + case CraftResource.MGlowing: difficulty = 0.0; break; + case CraftResource.MGorgan: difficulty = 95.0; break; + case CraftResource.MSteel: difficulty = 95.5; break; + case CraftResource.MSandrock: difficulty = 95.0; break; + case CraftResource.MMytheril: difficulty = 97.5; break; + case CraftResource.MBlackrock: difficulty = 98.0; break; + } + + double minSkill = difficulty - 25.0; + double maxSkill = difficulty + 25.0; + + if (difficulty > 50.0 && difficulty > from.Skills[SkillName.Mining].Value) + { + from.SendLocalizedMessage(501986); // You have no idea how to smelt this strange ore! + return; + } + + if (m_Ore.ItemID == 0x19B7 && m_Ore.Amount < 2) + { + from.SendLocalizedMessage(501987); // There is not enough metal-bearing ore in this pile to make an ingot. + return; + } + + if (from.CheckTargetSkill(SkillName.Mining, targeted, minSkill, maxSkill)) + { + int toConsume = m_Ore.Amount; + + if (toConsume <= 0) + { + from.SendLocalizedMessage(501987); // There is not enough metal-bearing ore in this pile to make an ingot. + } + else + { + if (toConsume > 30000) + toConsume = 30000; + + int ingotAmount; + + if (m_Ore.Resource == CraftResource.MTitan) + { + int helper = 0; + foreach (Mobile m in from.GetMobilesInRange(1)) + { + // Scriptiz : v�rifions qu'il s'agit bien d'un playermobile + PlayerMobile pm = m as PlayerMobile; + if (pm == null) continue; + + if (pm.Skills[SkillName.ItemID].Value > 60 && pm != from) + helper++; + } + if (helper == 0) + { + from.SendMessage("Il faudrait un identificateur avis� pour vous assister dans ce travail minutieux"); + return; + } + } + if (m_Ore.Resource == CraftResource.MSilver || m_Ore.Resource == CraftResource.MGlowing || m_Ore.Resource == CraftResource.MVulcan) + { + if (!(targeted is SpecialForge)) + { + from.SendMessage("Il vous faut trouver la forge appropri�e pour ce m�tal"); + return; + } + SpecialForge targ = (SpecialForge)targeted; + + if (m_Ore.Resource == CraftResource.MSilver && targ.Resource != CraftResource.MShadow) + { + from.SendMessage("Il vous faut trouver une forge d'ombre"); + return; + } + + if (m_Ore.Resource == CraftResource.MGlowing) + { + if(targ.Resource != CraftResource.MGlowing) + { + from.SendMessage("Il vous faut trouver une forge c�leste"); + return; + } + else + { + +int hours = 0; + int minutes = 0; + + Clock.GetTime( from.Map, from.Location.X, from.Location.Y, out hours, out minutes ); + + if ( hours > 18 && hours <7) + { + from.SendMessage("Le ciel n'est pas assez d�gag�"); + return; + } + else + { + from.BeginTarget(2, false, TargetFlags.None, new TargetStateCallback(TransformGlowingTarget), m_Ore); + from.SendMessage("Ce m�tal devrait scintiller comme un millier de pierres tr�s pr�cieuses!"); + return; + } + } + } + + if (m_Ore.Resource == CraftResource.MVulcan) + { + if (targ.Resource != CraftResource.MVulcan) + { + from.SendMessage("Il vous faut trouver une forge c�leste"); + return; + } + else if (from.FireResistance <= 48) + { + from.SendMessage("Vous risqueriez de p�rir br�ler par l'intensit� des flammes."); + return; + } + else + { + from.BeginTarget(2, false, TargetFlags.None, new TargetStateCallback(TransformVulcanTarget), m_Ore); + from.SendMessage("Ce m�tal devrait bruler comme un millier de pierres ardentes!"); + return; + } + + } + + + } + + if (m_Ore.Resource == CraftResource.MVerite) + { + if (from.Karma <= 2000) + { + from.SendMessage("Il vous faut devenir un forgeron plus vertueux!"); + return; + } + } + + if (m_Ore.Resource == CraftResource.MDragon) + { + if (from.Region is Regions.HouseRegion || from.Region is Regions.TownRegion) + { + from.SendMessage("Il ne serait pas ad�quat de tenter cela ici"); + return; + } + + BaseCreature Surprise = null; + int type = Utility.Random(100); + + if (type == 33 ) + Surprise = new AngryGreaterDragon(); + else if (type < 15) + Surprise = new AngryDragon(); + else if (type >= 50) + Surprise = new AngryDrake(); + + if (Surprise != null) + { + Surprise.SummonMaster = from; // to know who invoked it ! + Surprise.MoveToWorld(from.Location, from.Map); + Surprise.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "*La b�te atterri pr�s de vous, l'air furieuse*"); + } + } + + if (m_Ore.Resource == CraftResource.MRose) + { + if (!from.Female) + { + from.SendMessage("Vous n'avez pas les mains assez douces et tendres pour un m�tal aussi joli"); + + if (Utility.RandomBool()) + m_Ore.Consume(1); + + return; + + } + } + + if (m_Ore.Resource == CraftResource.MEldar) + { + if((DateTime.Now - from.CreationTime).TotalDays < 35) + { + from.SendMessage("Vous �tes trop jeune pour fondre ce m�tal"); + return; + } + } + if (m_Ore.ItemID == 0x19B7) + { + ingotAmount = toConsume / 2; + + if (toConsume % 2 != 0) + --toConsume; + } + else if (m_Ore.ItemID == 0x19B9) + { + ingotAmount = toConsume * 2; + } + else + { + ingotAmount = toConsume; + } + + BaseIngot ingot = m_Ore.GetIngot(); + ingot.Amount = ingotAmount; + + m_Ore.Consume(toConsume); + from.AddToBackpack(ingot); + + from.SendLocalizedMessage(501988); // You smelt the ore removing the impurities and put the metal in your backpack. + } + } + else + { + if (m_Ore.Amount < 2) + { + if (m_Ore.ItemID == 0x19B9) + m_Ore.ItemID = 0x19B8; + else + m_Ore.ItemID = 0x19B7; + } + else + { + m_Ore.Amount /= 2; + } + + from.SendLocalizedMessage(501990); // You burn away the impurities but are left with less useable metal. + } + } + } + public void TransformGlowingTarget(Mobile from, object obj, object state) + { + BaseOre ore = state as BaseOre; + + if (!(obj is BlueDiamond)) + { + from.SendMessage("Cela n'est pas assez �clatant"); + return; + } + + BlueDiamond targ = (BlueDiamond)obj; + + int chance = Math.Min(targ.Amount, 30)+((int)from.Skills[SkillName.Mining].Value/5); + + if (Utility.Random(0,50) < chance) + { + ore.Consume(Math.Min(ore.Amount, 50) / 2); + targ.Consume(Utility.Random(Math.Min(targ.Amount, 30)) / 2); + from.SendMessage("Vous n'arrivez pas � le rendre plus �clatant", chance); + return; + } + else + { + GlowingIngot success = new GlowingIngot(); + success.Amount = Math.Min(ore.Amount, 50) * 2; + from.AddToBackpack(success); + from.SendMessage("Le m�tal brille de milles �clats!"); + ore.Consume(Math.Min(ore.Amount, 50)); + targ.Consume(Math.Min(targ.Amount, 30)); + return; + } + } + public void TransformVulcanTarget(Mobile from, object obj, object state) + { + BaseOre ore = state as BaseOre; + + if (!(obj is FireRuby)) + { + from.SendMessage("Cela n'est pas assez ardent"); + return; + } + + FireRuby targ = (FireRuby)obj; + + int chance = Math.Min(targ.Amount, 30) + ((int)from.Skills[SkillName.Mining].Value / 5); + + if (Utility.Random(0, 50) < chance) + { + ore.Consume(Math.Min(ore.Amount, 50) / 2); + targ.Consume(Utility.Random(Math.Min(targ.Amount, 30)) / 2); + from.SendMessage("Vous n'arrivez pas � le rendre plus ardent", chance); + return; + } + else + { + VulcanIngot success = new VulcanIngot(); + success.Amount = Math.Min(ore.Amount, 50) * 2; + from.AddToBackpack(success); + from.SendMessage("Le m�tal brule de milles feux!"); + ore.Consume(Math.Min(ore.Amount, 50)); + targ.Consume(Math.Min(targ.Amount, 30)); + return; + } + } + } + } + + public class IronOre : BaseOre + { + [Constructable] + public IronOre() + : this(1) + { + } + + [Constructable] + public IronOre(int amount) + : base(CraftResource.MIron, amount) + { + } + + public IronOre(bool fixedSize) + : this(1) + { + if (fixedSize) + ItemID = 0x19B8; + } + + public IronOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new IronIngot(); + } + + } + + + public class BronzeOre : BaseOre + { + [Constructable] + public BronzeOre() + : this(1) + { + } + + [Constructable] + public BronzeOre(int amount) + : base(CraftResource.MBronze, amount) + { + } + + public BronzeOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new BronzeIngot(); + } + } + + + public class GoldOre : BaseOre + { + [Constructable] + public GoldOre() + : this(1) + { + } + + [Constructable] + public GoldOre(int amount) + : base(CraftResource.MGold, amount) + { + } + + public GoldOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new GoldIngot(); + } + } + + + public class CopperOre : BaseOre + { + [Constructable] + public CopperOre() + : this(1) + { + } + + [Constructable] + public CopperOre(int amount) + : base(CraftResource.MCopper, amount) + { + } + + public CopperOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new CopperIngot(); + } + + } + + + public class OldcopperOre : BaseOre + { + [Constructable] + public OldcopperOre() + : this(1) + { + } + + [Constructable] + public OldcopperOre(int amount) + : base(CraftResource.MOldcopper, amount) + { + } + + public OldcopperOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new OldcopperIngot(); + } + + + } + + + public class DullcopperOre : BaseOre + { + [Constructable] + public DullcopperOre() + : this(1) + { + } + + [Constructable] + public DullcopperOre(int amount) + : base(CraftResource.MDullcopper, amount) + { + } + + public DullcopperOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new DullcopperIngot(); + } + + + } + + + + public class SilverOre : BaseOre + { + [Constructable] + public SilverOre() + : this(1) + { + } + + [Constructable] + public SilverOre(int amount) + : base(CraftResource.MSilver, amount) + { + } + + public SilverOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new SilverIngot(); + } + + } + + + public class ShadowOre : BaseOre + { + [Constructable] + public ShadowOre() + : this(1) + { + } + + [Constructable] + public ShadowOre(int amount) + : base(CraftResource.MShadow, amount) + { + } + + public ShadowOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new ShadowIngot(); + } + + + } + + + public class BloodrockOre : BaseOre + { + [Constructable] + public BloodrockOre() + : this(1) + { + } + + [Constructable] + public BloodrockOre(int amount) + : base(CraftResource.MBloodrock, amount) + { + } + + public BloodrockOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new BloodrockIngot(); + } + } + + + public class BlackrockOre : BaseOre + { + [Constructable] + public BlackrockOre() + : this(1) + { + } + + [Constructable] + public BlackrockOre(int amount) + : base(CraftResource.MBlackrock, amount) + { + } + + public BlackrockOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new BlackrockIngot(); + } + } + + + public class MytherilOre : BaseOre + { + [Constructable] + public MytherilOre() + : this(1) + { + } + + [Constructable] + public MytherilOre(int amount) + : base(CraftResource.MMytheril, amount) + { + } + + public MytherilOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new MytherilIngot(); + } + } + + + public class RoseOre : BaseOre + { + [Constructable] + public RoseOre() + : this(1) + { + } + + [Constructable] + public RoseOre(int amount) + : base(CraftResource.MRose, amount) + { + } + + public RoseOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new RoseIngot(); + } + + + } + + + public class VeriteOre : BaseOre + { + [Constructable] + public VeriteOre() + : this(1) + { + } + + [Constructable] + public VeriteOre(int amount) + : base(CraftResource.MVerite, amount) + { + } + + public VeriteOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new VeriteIngot(); + } + } + + + public class AgapiteOre : BaseOre + { + [Constructable] + public AgapiteOre() + : this(1) + { + } + + [Constructable] + public AgapiteOre(int amount) + : base(CraftResource.MAgapite, amount) + { + } + + public AgapiteOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new AgapiteIngot(); + } + } + + + public class RustyOre : BaseOre + { + [Constructable] + public RustyOre() + : this(1) + { + } + + [Constructable] + public RustyOre(int amount) + : base(CraftResource.MRusty, amount) + { + } + + public RustyOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new RustyIngot(); + } + + } + + + public class ValoriteOre : BaseOre + { + [Constructable] + public ValoriteOre() + : this(1) + { + } + + [Constructable] + public ValoriteOre(int amount) + : base(CraftResource.MValorite, amount) + { + } + + public ValoriteOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new ValoriteIngot(); + } + + } + + + public class DragonOre : BaseOre + { + [Constructable] + public DragonOre() + : this(1) + { + } + + [Constructable] + public DragonOre(int amount) + : base(CraftResource.MDragon, amount) + { + } + + public DragonOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new DragonIngot(); + } + + + } + + + + public class TitanOre : BaseOre + { + [Constructable] + public TitanOre() + : this(1) + { + } + + [Constructable] + public TitanOre(int amount) + : base(CraftResource.MTitan, amount) + { + } + + public TitanOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new TitanIngot(); + } + + + } + + + public class CrystalineOre : BaseOre + { + [Constructable] + public CrystalineOre() + : this(1) + { + } + + [Constructable] + public CrystalineOre(int amount) + : base(CraftResource.MCrystaline, amount) + { + } + + public CrystalineOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new CrystalineIngot(); + } + + + } + + + public class KryniteOre : BaseOre + { + [Constructable] + public KryniteOre() + : this(1) + { + } + + [Constructable] + public KryniteOre(int amount) + : base(CraftResource.MKrynite, amount) + { + } + + public KryniteOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new KryniteIngot(); + } + } + + + public class VulcanOre : BaseOre + { + [Constructable] + public VulcanOre() + : this(1) + { + } + + [Constructable] + public VulcanOre(int amount) + : base(CraftResource.MVulcan, amount) + { + } + + public VulcanOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new VulcanIngot(); + } + } + + + public class BloodcrestOre : BaseOre + { + [Constructable] + public BloodcrestOre() + : this(1) + { + } + + [Constructable] + public BloodcrestOre(int amount) + : base(CraftResource.MBloodcrest, amount) + { + } + + public BloodcrestOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new BloodcrestIngot(); + } + } + + + public class ElvinOre : BaseOre + { + [Constructable] + public ElvinOre() + : this(1) + { + } + + [Constructable] + public ElvinOre(int amount) + : base(CraftResource.MElvin, amount) + { + } + + public ElvinOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + public override BaseIngot GetIngot() + { + return new ElvinIngot(); + } + + + } + + + public class AcidOre : BaseOre + { + [Constructable] + public AcidOre() + : this(1) + { + } + + [Constructable] + public AcidOre(int amount) + : base(CraftResource.MAcid, amount) + { + } + + public AcidOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new AcidIngot(); + } + + + } + + + public class AquaOre : BaseOre + { + [Constructable] + public AquaOre() + : this(1) + { + } + + [Constructable] + public AquaOre(int amount) + : base(CraftResource.MAqua, amount) + { + } + + public AquaOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new AquaIngot(); + } + + } + + + + public class EldarOre : BaseOre + { + private DateTime m_MinedDate; + private bool m_Ready; + [CommandProperty(AccessLevel.GameMaster)] + public DateTime MinedDate + { + get { return m_MinedDate; } + set { m_MinedDate = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool Ready + { + get { return m_Ready; } + set { m_Ready = value; } + } + + [Constructable] + public EldarOre() + : this(1) + { + MinedDate = DateTime.Now; + Stackable = false; + } + + [Constructable] + public EldarOre(int amount) + : base(CraftResource.MRose, amount) + { + MinedDate = DateTime.Now; + Stackable = false; + } + + public override void OnDoubleClick(Mobile from) + { + if (!Ready && (DateTime.Now - MinedDate).TotalDays >= 7) + { + from.SendMessage("� l'instant o� vous prenez ce m�tal, sa couleur prend de l'�clat."); + Resource = CraftResource.MEldar; + Hue = 0x4DD; + m_Ready = true; + Stackable = true; + } + else if (!Ready) + from.SendMessage("L'�ge rend meilleur � ce qu'on dit..."); + + base.OnDoubleClick(from); + } + + public EldarOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.Write((DateTime)m_MinedDate); + writer.Write((bool)m_Ready); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_MinedDate = reader.ReadDateTime(); + m_Ready = reader.ReadBool(); + } + + public override BaseIngot GetIngot() + { + if(Ready) + return new EldarIngot(); + else + return new RoseIngot(); + } + + + } + + + public class GlowingOre : BaseOre + { + [Constructable] + public GlowingOre() + : this(1) + { + } + + [Constructable] + public GlowingOre(int amount) + : base(CraftResource.MGlowing, amount) + { + } + + public GlowingOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new GlowingIngot(); + } + + + } + + + public class GorganOre : BaseOre + { + [Constructable] + public GorganOre() + : this(1) + { + } + + [Constructable] + public GorganOre(int amount) + : base(CraftResource.MGorgan, amount) + { + } + + public GorganOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new GorganIngot(); + } + } + + + public class SandrockOre : BaseOre + { + [Constructable] + public SandrockOre() + : this(1) + { + } + + [Constructable] + public SandrockOre(int amount) + : base(CraftResource.MSandrock, amount) + { + } + + public SandrockOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new SandrockIngot(); + } + } + + + public class SteelOre : BaseOre + { + [Constructable] + public SteelOre() + : this(1) + { + } + + [Constructable] + public SteelOre(int amount) + : base(CraftResource.MSteel, amount) + { + } + + public SteelOre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override BaseIngot GetIngot() + { + return new SteelIngot(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Blacksmithing/Scales.cs b/Scripts/Items/Resources/Blacksmithing/Scales.cs new file mode 100644 index 0000000..808506a --- /dev/null +++ b/Scripts/Items/Resources/Blacksmithing/Scales.cs @@ -0,0 +1,386 @@ +using System; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class BaseScales : Item, ICommodity + { + public override int LabelNumber { get { return 1053139; } } // dragon scales + + private CraftResource m_Resource; + + private bool m_Harvested; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Harvested + { + get { return m_Harvested; } + set { m_Harvested = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; InvalidateProperties(); } + } + + public override double DefaultWeight + { + get { return 0.1; } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_Harvested) + { + from.SendMessage("Vous ne d�celez rien sous ces �cailles"); + return; + } + + from.SendMessage("Vous d�notez certains gravats sur les �cailles"); + from.SendMessage("Peut-�tre qu'un liquide ennemi pourrait les faire partir?"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + } + + public void OnTarget(Mobile from, object obj) + { + if (!(obj is AlchemyVial)) + { + from.SendMessage("Cela ne servira � rien"); + return; + } + + AlchemyVial targ = (AlchemyVial)obj; + + if (targ.AlchemyLiquidType != LiquidType.OgreBlood && targ.AlchemyLiquidType != LiquidType.OrcBlood && targ.AlchemyLiquidType != LiquidType.TrollBlood) + { + from.SendMessage("Vous versez le sang, mais rien ne se passe"); + targ.AlchemyLiquidType = LiquidType.None; + return; + } + + if (!from.CheckTargetSkill(SkillName.Alchemy, targ, 50, 95)) + { + from.SendMessage("Vous versez le sang, mais �chouez � faire tomber les gravats"); + targ.AlchemyLiquidType = LiquidType.None; + return; + } + + int rarete = 0; + + switch (Resource) + { + case CraftResource.BlackScales: rarete = 2; break; + case CraftResource.WhiteScales: rarete = 3; break; + case CraftResource.GreenScales: rarete = 4; break; + case CraftResource.BlueScales: rarete = 4; break; + default: rarete = 6; break; + } + if (this.Amount >= rarete) + { + from.SendMessage("Vous recueillez des gravats"); + this.m_Harvested = true; + DragonOre ore = new DragonOre(); + ore.ItemID = 0x19B8; + ore.Amount = (int)Math.Floor(this.Amount / (double)rarete); + from.AddToBackpack(ore); + targ.AlchemyLiquidType = LiquidType.None; + } + else + from.SendMessage("Il n'y en a malheureusement pas assez pour constituer des gravats convenables"); + } + + + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write((bool)m_Harvested); + writer.Write((int)m_Resource); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Harvested = reader.ReadBool(); + goto case 0; + } + case 0: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + } + + public override bool StackWith(Mobile from, Item dropped, bool playSound) + { + if(!(dropped is BaseScales)) + return false; + if (((BaseScales)dropped).Harvested != Harvested) + return false; + return base.StackWith(from, dropped, playSound); + } + + public BaseScales(CraftResource resource) + : this(resource, 1) + { + } + + public BaseScales(CraftResource resource, int amount) + : base(0x26B4) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue(resource); + m_Resource = resource; + } + + + public BaseScales(CraftResource resource, int amount, bool harvested) + : base(0x26B4) + { + Stackable = true; + Amount = amount; + Hue = CraftResources.GetHue(resource); + m_Resource = resource; + } + public BaseScales(Serial serial) + : base(serial) + { + } + } + + public class RedScales : BaseScales + { + [Constructable] + public RedScales() + : this(1) + { + } + + [Constructable] + public RedScales(int amount) + : base(CraftResource.RedScales, amount) + { + } + + public RedScales(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + public class YellowScales : BaseScales + { + [Constructable] + public YellowScales() + : this(1) + { + } + + [Constructable] + public YellowScales(int amount) + : base(CraftResource.YellowScales, amount) + { + } + + public YellowScales(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + public class BlackScales : BaseScales + { + [Constructable] + public BlackScales() + : this(1) + { + } + + [Constructable] + public BlackScales(int amount) + : base(CraftResource.BlackScales, amount) + { + } + + public BlackScales(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + public class GreenScales : BaseScales + { + [Constructable] + public GreenScales() + : this(1) + { + } + + [Constructable] + public GreenScales(int amount) + : base(CraftResource.GreenScales, amount) + { + } + + public GreenScales(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + public class WhiteScales : BaseScales + { + [Constructable] + public WhiteScales() + : this(1) + { + } + + [Constructable] + public WhiteScales(int amount) + : base(CraftResource.WhiteScales, amount) + { + } + + public WhiteScales(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + public class BlueScales : BaseScales + { + public override int LabelNumber { get { return 1053140; } } // sea serpent scales + + [Constructable] + public BlueScales() + : this(1) + { + } + + [Constructable] + public BlueScales(int amount) + : base(CraftResource.BlueScales, amount) + { + } + + public BlueScales(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Fishing/BigFish.cs b/Scripts/Items/Resources/Fishing/BigFish.cs new file mode 100644 index 0000000..38a877c --- /dev/null +++ b/Scripts/Items/Resources/Fishing/BigFish.cs @@ -0,0 +1,79 @@ +using System; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class BigFish : Item, ICarvable + { + private Mobile m_Fisher; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Fisher + { + get{ return m_Fisher; } + set{ m_Fisher = value; InvalidateProperties(); } + } + + public void Carve( Mobile from, Item item ) + { + base.ScissorHelper( from, new RawFishSteak(), Math.Max( 16, (int)Weight ) / 4 , false ); + } + + public override int LabelNumber{ get{ return 1041112; } } // a big fish + + [Constructable] + public BigFish() : base( 0x09CC ) + { + Weight = Utility.RandomMinMax( 3, 200 ); //TODO: Find correct formula. max on OSI currently 200, OSI dev says it's not 200 as max, and ~ 1/1,000,000 chance to get highest + Hue = Utility.RandomBool() ? 0x847 : 0x58C; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Weight >= 20 ) + { + if ( m_Fisher != null ) + list.Add( 1070857, m_Fisher.Name ); // Caught by ~1_fisherman~ + + list.Add( 1070858, ((int)Weight).ToString() ); // ~1_weight~ stones + } + } + + public BigFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (Mobile) m_Fisher ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Fisher = reader.ReadMobile(); + break; + } + case 0: + { + Weight = Utility.RandomMinMax( 3, 200 ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Fishing/Fish.cs b/Scripts/Items/Resources/Fishing/Fish.cs new file mode 100644 index 0000000..14b5098 --- /dev/null +++ b/Scripts/Items/Resources/Fishing/Fish.cs @@ -0,0 +1,47 @@ +using System; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class Fish : Item, ICarvable + { + public void Carve( Mobile from, Item item ) + { + base.ScissorHelper( from, new RawFishSteak(), 4 ); + } + + [Constructable] + public Fish() : this( 1 ) + { + } + + [Constructable] + public Fish( int amount ) : base( Utility.Random( 0x09CC, 4 ) ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + + + public Fish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Resources/Fishing/MagicFish.cs b/Scripts/Items/Resources/Fishing/MagicFish.cs new file mode 100644 index 0000000..8da72e0 --- /dev/null +++ b/Scripts/Items/Resources/Fishing/MagicFish.cs @@ -0,0 +1,203 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseMagicFish : Item + { + public virtual int Bonus{ get{ return 0; } } + public virtual StatType Type{ get{ return StatType.Str; } } + + public override double DefaultWeight + { + get { return 1.0; } + } + + public BaseMagicFish( int hue ) : base( 0xDD6 ) + { + Hue = hue; + } + + public BaseMagicFish( Serial serial ) : base( serial ) + { + } + + public virtual bool Apply( Mobile from ) + { + bool applied = Spells.SpellHelper.AddStatOffset( from, Type, Bonus, TimeSpan.FromMinutes( 1.0 ) ); + + if ( !applied ) + from.SendLocalizedMessage( 502173 ); // You are already under a similar effect. + + return applied; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( Apply( from ) ) + { + from.FixedEffect( 0x375A, 10, 15 ); + from.PlaySound( 0x1E7 ); + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501774 ); // You swallow the fish whole! + Delete(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PrizedFish : BaseMagicFish + { + public override int Bonus{ get{ return 5; } } + public override StatType Type{ get{ return StatType.Int; } } + + public override int LabelNumber{ get{ return 1041073; } } // prized fish + + [Constructable] + public PrizedFish() : base( 51 ) + { + } + + public PrizedFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 151 ) + Hue = 51; + } + } + + public class WondrousFish : BaseMagicFish + { + public override int Bonus{ get{ return 5; } } + public override StatType Type{ get{ return StatType.Dex; } } + + public override int LabelNumber{ get{ return 1041074; } } // wondrous fish + + [Constructable] + public WondrousFish() : base( 86 ) + { + } + + public WondrousFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 286 ) + Hue = 86; + } + } + + public class TrulyRareFish : BaseMagicFish + { + public override int Bonus{ get{ return 5; } } + public override StatType Type{ get{ return StatType.Str; } } + + public override int LabelNumber{ get{ return 1041075; } } // truly rare fish + + [Constructable] + public TrulyRareFish() : base( 76 ) + { + } + + public TrulyRareFish( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 376 ) + Hue = 76; + } + } + + public class PeculiarFish : BaseMagicFish + { + public override int LabelNumber{ get{ return 1041076; } } // highly peculiar fish + + [Constructable] + public PeculiarFish() : base( 66 ) + { + } + + public PeculiarFish( Serial serial ) : base( serial ) + { + } + + public override bool Apply( Mobile from ) + { + from.Stam += 10; + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 266 ) + Hue = 66; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Masonry/Granite.cs b/Scripts/Items/Resources/Masonry/Granite.cs new file mode 100644 index 0000000..92bbde4 --- /dev/null +++ b/Scripts/Items/Resources/Masonry/Granite.cs @@ -0,0 +1,984 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseGranite : Item + { + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; InvalidateProperties(); } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + case 0: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + + if (version < 1) + Stackable = Core.ML; + } + + public override double DefaultWeight + { + get { return Core.ML ? 1.0 : 10.0; } // Pub 57 + } + + public BaseGranite(CraftResource resource) + : base(0x1779) + { + Hue = CraftResources.GetHue(resource); + Stackable = Core.ML; + + m_Resource = resource; + } + + public BaseGranite(Serial serial) + : base(serial) + { + } + + public override int LabelNumber { get { return 1044607; } } // high quality granite + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + } + + public class Granite : BaseGranite + { + [Constructable] + public Granite() + : base(CraftResource.MIron) + { + } + + public Granite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class BronzeGranite : BaseGranite + { + [Constructable] + public BronzeGranite() + : base(CraftResource.MBronze) + { + } + + public BronzeGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class GoldGranite : BaseGranite + { + [Constructable] + public GoldGranite() + : base(CraftResource.MGold) + { + } + + public GoldGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class CopperGranite : BaseGranite + { + [Constructable] + public CopperGranite() + : base(CraftResource.MCopper) + { + } + + public CopperGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class OldcopperGranite : BaseGranite + { + [Constructable] + public OldcopperGranite() + : base(CraftResource.MOldcopper) + { + } + + public OldcopperGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class DullcopperGranite : BaseGranite + { + [Constructable] + public DullcopperGranite() + : base(CraftResource.MDullcopper) + { + } + + public DullcopperGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + + public class SilverGranite : BaseGranite + { + [Constructable] + public SilverGranite() + : base(CraftResource.MSilver) + { + } + + public SilverGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class ShadowGranite : BaseGranite + { + [Constructable] + public ShadowGranite() + : base(CraftResource.MShadow) + { + } + + public ShadowGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class BloodrockGranite : BaseGranite + { + [Constructable] + public BloodrockGranite() + : base(CraftResource.MBloodrock) + { + } + + public BloodrockGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class BlackrockGranite : BaseGranite + { + [Constructable] + public BlackrockGranite() + : base(CraftResource.MBlackrock) + { + } + + public BlackrockGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class MytherilGranite : BaseGranite + { + [Constructable] + public MytherilGranite() + : base(CraftResource.MMytheril) + { + } + + public MytherilGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class RoseGranite : BaseGranite + { + [Constructable] + public RoseGranite() + : base(CraftResource.MRose) + { + } + + public RoseGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class VeriteGranite : BaseGranite + { + [Constructable] + public VeriteGranite() + : base(CraftResource.MVerite) + { + } + + public VeriteGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class AgapiteGranite : BaseGranite + { + [Constructable] + public AgapiteGranite() + : base(CraftResource.MAgapite) + { + } + + public AgapiteGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class RustyGranite : BaseGranite + { + [Constructable] + public RustyGranite() + : base(CraftResource.MRusty) + { + } + + public RustyGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class ValoriteGranite : BaseGranite + { + [Constructable] + public ValoriteGranite() + : base(CraftResource.MValorite) + { + } + + public ValoriteGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class DragonGranite : BaseGranite + { + [Constructable] + public DragonGranite() + : base(CraftResource.MDragon) + { + } + + public DragonGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + + public class TitanGranite : BaseGranite + { + [Constructable] + public TitanGranite() + : base(CraftResource.MTitan) + { + } + + public TitanGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class CrystalineGranite : BaseGranite + { + [Constructable] + public CrystalineGranite() + : base(CraftResource.MCrystaline) + { + } + + public CrystalineGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class KryniteGranite : BaseGranite + { + [Constructable] + public KryniteGranite() + : base(CraftResource.MKrynite) + { + } + + public KryniteGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class VulcanGranite : BaseGranite + { + [Constructable] + public VulcanGranite() + : base(CraftResource.MVulcan) + { + } + + public VulcanGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class BloodcrestGranite : BaseGranite + { + [Constructable] + public BloodcrestGranite() + : base(CraftResource.MBloodcrest) + { + } + + public BloodcrestGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class ElvinGranite : BaseGranite + { + [Constructable] + public ElvinGranite() + : base(CraftResource.MElvin) + { + } + + public ElvinGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class AcidGranite : BaseGranite + { + [Constructable] + public AcidGranite() + : base(CraftResource.MAcid) + { + } + + public AcidGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class AquaGranite : BaseGranite + { + [Constructable] + public AquaGranite() + : base(CraftResource.MAqua) + { + } + + public AquaGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + + public class EldarGranite : BaseGranite + { + [Constructable] + public EldarGranite() + : base(CraftResource.MEldar) + { + } + + public EldarGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class GlowingGranite : BaseGranite + { + [Constructable] + public GlowingGranite() + : base(CraftResource.MGlowing) + { + } + + public GlowingGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } + + + public class GorganGranite : BaseGranite + { + [Constructable] + public GorganGranite() + : base(CraftResource.MGorgan) + { + } + + public GorganGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class SandrockGranite : BaseGranite + { + [Constructable] + public SandrockGranite() + : base(CraftResource.MSandrock) + { + } + + public SandrockGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class SteelGranite : BaseGranite + { + [Constructable] + public SteelGranite() + : base(CraftResource.MSteel) + { + } + + public SteelGranite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/MiscMLResources.cs b/Scripts/Items/Resources/MiscMLResources.cs new file mode 100644 index 0000000..25b5dbb --- /dev/null +++ b/Scripts/Items/Resources/MiscMLResources.cs @@ -0,0 +1,1048 @@ +using System; + +namespace Server.Items +{ + public class Blight : Item + { + [Constructable] + public Blight() + : this( 1 ) + { + } + + [Constructable] + public Blight( int amount ) + : base( 0x3183 ) + { + Stackable = true; + Amount = amount; + } + + public Blight( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LuminescentFungi : Item + { + [Constructable] + public LuminescentFungi() + : this( 1 ) + { + } + + [Constructable] + public LuminescentFungi( int amount ) + : base( 0x3191 ) + { + Stackable = true; + Amount = amount; + } + + public LuminescentFungi( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class CapturedEssence : Item + { + [Constructable] + public CapturedEssence() + : this( 1 ) + { + } + + [Constructable] + public CapturedEssence( int amount ) + : base( 0x318E ) + { + Stackable = true; + Amount = amount; + } + + public CapturedEssence( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class EyeOfTheTravesty : Item + { + [Constructable] + public EyeOfTheTravesty() + : this( 1 ) + { + } + + [Constructable] + public EyeOfTheTravesty( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public EyeOfTheTravesty( int amount ) + : base( 0x318D ) + { + Stackable = true; + Amount = amount; + } + + public EyeOfTheTravesty( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class Corruption : Item + { + [Constructable] + public Corruption() + : this( 1 ) + { + } + + [Constructable] + public Corruption( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Corruption( int amount ) + : base( 0x3184 ) + { + Stackable = true; + Amount = amount; + } + + public Corruption( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class DreadHornMane : Item + { + [Constructable] + public DreadHornMane() + : this( 1 ) + { + } + + [Constructable] + public DreadHornMane( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public DreadHornMane( int amount ) + : base( 0x318A ) + { + Stackable = true; + Amount = amount; + } + + public DreadHornMane( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class ParasiticPlant : Item + { + [Constructable] + public ParasiticPlant() + : this( 1 ) + { + } + + [Constructable] + public ParasiticPlant( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public ParasiticPlant( int amount ) + : base( 0x3190 ) + { + Stackable = true; + Amount = amount; + } + + public ParasiticPlant( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class Muculent : Item + { + [Constructable] + public Muculent() + : this( 1 ) + { + } + + [Constructable] + public Muculent( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Muculent( int amount ) + : base( 0x3188 ) + { + Stackable = true; + Amount = amount; + } + + public Muculent( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class DiseasedBark : Item + { + [Constructable] + public DiseasedBark() + : this( 1 ) + { + } + + [Constructable] + public DiseasedBark( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public DiseasedBark( int amount ) + : base( 0x318B ) + { + Stackable = true; + Amount = amount; + } + + public DiseasedBark( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class BarkFragment : Item + { + [Constructable] + public BarkFragment() + : this( 1 ) + { + } + + [Constructable] + public BarkFragment( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public BarkFragment( int amount ) + : base( 0x318F ) + { + Stackable = true; + Amount = amount; + } + + public BarkFragment( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class GrizzledBones : Item + { + [Constructable] + public GrizzledBones() + : this( 1 ) + { + } + + [Constructable] + public GrizzledBones( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public GrizzledBones( int amount ) + : base( 0x318C ) + { + Stackable = true; + Amount = amount; + } + + public GrizzledBones( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version <= 0 && ItemID == 0x318F ) + ItemID = 0x318C; + } + } + + + public class LardOfParoxysmus : Item + { + [Constructable] + public LardOfParoxysmus() + : this( 1 ) + { + } + + [Constructable] + public LardOfParoxysmus( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public LardOfParoxysmus( int amount ) + : base( 0x3189 ) + { + Stackable = true; + Amount = amount; + } + + public LardOfParoxysmus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PerfectEmerald : Item + { + [Constructable] + public PerfectEmerald() + : this( 1 ) + { + } + + [Constructable] + public PerfectEmerald( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public PerfectEmerald( int amount ) + : base( 0x3194 ) + { + Stackable = true; + Amount = amount; + } + + public PerfectEmerald( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DarkSapphire : Item + { + [Constructable] + public DarkSapphire() + : this( 1 ) + { + } + + [Constructable] + public DarkSapphire( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public DarkSapphire( int amount ) + : base( 0x3192 ) + { + Stackable = true; + Amount = amount; + } + + public DarkSapphire( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class Turquoise : Item + { + [Constructable] + public Turquoise() + : this( 1 ) + { + } + + [Constructable] + public Turquoise( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Turquoise( int amount ) + : base( 0x3193 ) + { + Stackable = true; + Amount = amount; + } + + public Turquoise( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class EcruCitrine : Item + { + [Constructable] + public EcruCitrine() + : this( 1 ) + { + } + + [Constructable] + public EcruCitrine( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public EcruCitrine( int amount ) + : base( 0x3195 ) + { + Stackable = true; + Amount = amount; + } + + public EcruCitrine( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class WhitePearl : Item + { + [Constructable] + public WhitePearl() + : this( 1 ) + { + } + + [Constructable] + public WhitePearl( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public WhitePearl( int amount ) + : base( 0x3196 ) + { + Stackable = true; + Amount = amount; + } + + public WhitePearl( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class FireRuby : Item + { + [Constructable] + public FireRuby() + : this( 1 ) + { + } + + [Constructable] + public FireRuby( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public FireRuby( int amount ) + : base( 0x3197 ) + { + Stackable = true; + Amount = amount; + } + + public FireRuby( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class BlueDiamond : Item + { + [Constructable] + public BlueDiamond() + : this( 1 ) + { + } + + [Constructable] + public BlueDiamond( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public BlueDiamond( int amount ) + : base( 0x3198 ) + { + Stackable = true; + Amount = amount; + } + + public BlueDiamond( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class BrilliantAmber : Item + { + [Constructable] + public BrilliantAmber() + : this( 1 ) + { + } + + [Constructable] + public BrilliantAmber( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public BrilliantAmber( int amount ) + : base( 0x3199 ) + { + Stackable = true; + Amount = amount; + } + + public BrilliantAmber( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Scourge : Item + { + [Constructable] + public Scourge() + : this( 1 ) + { + } + + [Constructable] + public Scourge( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Scourge( int amount ) + : base( 0x3185 ) + { + Stackable = true; + Amount = amount; + Hue = 150; + } + + public Scourge( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class Putrefication : Item + { + [Constructable] + public Putrefication() + : this( 1 ) + { + } + + [Constructable] + public Putrefication( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Putrefication( int amount ) + : base( 0x3186 ) + { + Stackable = true; + Amount = amount; + Hue = 883; + } + + public Putrefication( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + public class Taint : Item + { + [Constructable] + public Taint() + : this( 1 ) + { + } + + [Constructable] + public Taint( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public Taint( int amount ) + : base( 0x3187 ) + { + Stackable = true; + Amount = amount; + Hue = 731; + } + + public Taint( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x315A, 0x315B )] + public class PristineDreadHorn : Item + { + [Constructable] + public PristineDreadHorn() + : base( 0x315A ) + { + + } + + public PristineDreadHorn( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SwitchItem : Item + { + [Constructable] + public SwitchItem() + : this( 1 ) + { + } + + [Constructable] + public SwitchItem( int amountFrom, int amountTo ) + : this( Utility.RandomMinMax( amountFrom, amountTo ) ) + { + } + + [Constructable] + public SwitchItem( int amount ) + : base( 0x2F5F ) + { + Stackable = true; + Amount = amount; + } + + public SwitchItem( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Resources/Reagents/BagOfAllReagents.cs b/Scripts/Items/Resources/Reagents/BagOfAllReagents.cs new file mode 100644 index 0000000..914fad7 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/BagOfAllReagents.cs @@ -0,0 +1,50 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BagOfAllReagents : Bag + { + [Constructable] + public BagOfAllReagents() : this( 50 ) + { + } + + [Constructable] + public BagOfAllReagents( int amount ) + { + DropItem( new BlackPearl ( amount ) ); + DropItem( new Bloodmoss ( amount ) ); + DropItem( new Garlic ( amount ) ); + DropItem( new Ginseng ( amount ) ); + DropItem( new MandrakeRoot ( amount ) ); + DropItem( new Nightshade ( amount ) ); + DropItem( new SulfurousAsh ( amount ) ); + DropItem( new SpidersSilk ( amount ) ); + DropItem( new BatWing ( amount ) ); + DropItem( new GraveDust ( amount ) ); + DropItem( new DaemonBlood ( amount ) ); + DropItem( new NoxCrystal ( amount ) ); + DropItem( new PigIron ( amount ) ); + } + + public BagOfAllReagents( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/BagOfNecroReagents.cs b/Scripts/Items/Resources/Reagents/BagOfNecroReagents.cs new file mode 100644 index 0000000..c9e1218 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/BagOfNecroReagents.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BagOfNecroReagents : Bag + { + [Constructable] + public BagOfNecroReagents() : this( 50 ) + { + } + + [Constructable] + public BagOfNecroReagents( int amount ) + { + DropItem( new BatWing ( amount ) ); + DropItem( new GraveDust ( amount ) ); + DropItem( new DaemonBlood( amount ) ); + DropItem( new NoxCrystal ( amount ) ); + DropItem( new PigIron ( amount ) ); + } + + public BagOfNecroReagents( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/BagOfReagents.cs b/Scripts/Items/Resources/Reagents/BagOfReagents.cs new file mode 100644 index 0000000..7782b84 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/BagOfReagents.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BagOfReagents : Bag + { + [Constructable] + public BagOfReagents() : this( 50 ) + { + } + + [Constructable] + public BagOfReagents( int amount ) + { + DropItem( new BlackPearl ( amount ) ); + DropItem( new Bloodmoss ( amount ) ); + DropItem( new Garlic ( amount ) ); + DropItem( new Ginseng ( amount ) ); + DropItem( new MandrakeRoot ( amount ) ); + DropItem( new Nightshade ( amount ) ); + DropItem( new SulfurousAsh ( amount ) ); + DropItem( new SpidersSilk ( amount ) ); + } + + public BagOfReagents( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/BaseReagent.cs b/Scripts/Items/Resources/Reagents/BaseReagent.cs new file mode 100644 index 0000000..0786ae3 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/BaseReagent.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BaseReagent : Item + { + public override double DefaultWeight + { + get { return 0.1; } + } + + public BaseReagent( int itemID ) : this( itemID, 1 ) + { + } + + public BaseReagent( int itemID, int amount ) : base( itemID ) + { + Stackable = true; + Amount = amount; + } + + public BaseReagent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/BatWing.cs b/Scripts/Items/Resources/Reagents/BatWing.cs new file mode 100644 index 0000000..d1b3a1b --- /dev/null +++ b/Scripts/Items/Resources/Reagents/BatWing.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BatWing : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public BatWing() : this( 1 ) + { + } + + [Constructable] + public BatWing( int amount ) : base( 0xF78, amount ) + { + } + + public BatWing( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/BlackPearl.cs b/Scripts/Items/Resources/Reagents/BlackPearl.cs new file mode 100644 index 0000000..e93ea9f --- /dev/null +++ b/Scripts/Items/Resources/Reagents/BlackPearl.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BlackPearl : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public BlackPearl() : this( 1 ) + { + } + + [Constructable] + public BlackPearl( int amount ) : base( 0xF7A, amount ) + { + } + + public BlackPearl( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/Bloodmoss.cs b/Scripts/Items/Resources/Reagents/Bloodmoss.cs new file mode 100644 index 0000000..000e4a5 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/Bloodmoss.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Bloodmoss : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Bloodmoss() : this( 1 ) + { + } + + [Constructable] + public Bloodmoss( int amount ) : base( 0xF7B, amount ) + { + } + + public Bloodmoss( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/DaemonBlood.cs b/Scripts/Items/Resources/Reagents/DaemonBlood.cs new file mode 100644 index 0000000..cc3e5f9 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/DaemonBlood.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DaemonBlood : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public DaemonBlood() : this( 1 ) + { + } + + [Constructable] + public DaemonBlood( int amount ) : base( 0xF7D, amount ) + { + } + + public DaemonBlood( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/DaemonBone.cs b/Scripts/Items/Resources/Reagents/DaemonBone.cs new file mode 100644 index 0000000..0d42562 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/DaemonBone.cs @@ -0,0 +1,57 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + // Scriptiz : Ajout du ICommodity + public class DaemonBone : BaseReagent, ICommodity + { + // Scriptiz : Ajout du ICommodity + string Description + { + get + { + return String.Format("{0} daemon's bone", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 1.0; } + } + + [Constructable] + public DaemonBone() : this( 1 ) + { + } + + [Constructable] + public DaemonBone( int amount ) : base( 0xF80, amount ) + { + } + + public DaemonBone( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/DeadWood.cs b/Scripts/Items/Resources/Reagents/DeadWood.cs new file mode 100644 index 0000000..6284f2b --- /dev/null +++ b/Scripts/Items/Resources/Reagents/DeadWood.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DeadWood : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public DeadWood() : this( 1 ) + { + } + + [Constructable] + public DeadWood( int amount ) : base( 0xF90, amount ) + { + } + + public DeadWood( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/Garlic.cs b/Scripts/Items/Resources/Reagents/Garlic.cs new file mode 100644 index 0000000..b1a623e --- /dev/null +++ b/Scripts/Items/Resources/Reagents/Garlic.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Garlic : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Garlic() : this( 1 ) + { + } + + [Constructable] + public Garlic( int amount ) : base( 0xF84, amount ) + { + } + + public Garlic( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/Ginseng.cs b/Scripts/Items/Resources/Reagents/Ginseng.cs new file mode 100644 index 0000000..d7f8fe8 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/Ginseng.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Ginseng : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Ginseng() : this( 1 ) + { + } + + [Constructable] + public Ginseng( int amount ) : base( 0xF85, amount ) + { + } + + public Ginseng( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/GraveDust.cs b/Scripts/Items/Resources/Reagents/GraveDust.cs new file mode 100644 index 0000000..e5c28e8 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/GraveDust.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class GraveDust : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public GraveDust() : this( 1 ) + { + } + + [Constructable] + public GraveDust( int amount ) : base( 0xF8F, amount ) + { + } + + public GraveDust( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/MandrakeRoot.cs b/Scripts/Items/Resources/Reagents/MandrakeRoot.cs new file mode 100644 index 0000000..ce9c288 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/MandrakeRoot.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MandrakeRoot : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public MandrakeRoot() : this( 1 ) + { + } + + [Constructable] + public MandrakeRoot( int amount ) : base( 0xF86, amount ) + { + } + + public MandrakeRoot( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/Nightshade.cs b/Scripts/Items/Resources/Reagents/Nightshade.cs new file mode 100644 index 0000000..fd8f1d7 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/Nightshade.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Nightshade : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Nightshade() : this( 1 ) + { + } + + [Constructable] + public Nightshade( int amount ) : base( 0xF88, amount ) + { + } + + public Nightshade( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/NoxCrystal.cs b/Scripts/Items/Resources/Reagents/NoxCrystal.cs new file mode 100644 index 0000000..ece0a62 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/NoxCrystal.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class NoxCrystal : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public NoxCrystal() : this( 1 ) + { + } + + [Constructable] + public NoxCrystal( int amount ) : base( 0xF8E, amount ) + { + } + + public NoxCrystal( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/PigIron.cs b/Scripts/Items/Resources/Reagents/PigIron.cs new file mode 100644 index 0000000..71b18a9 --- /dev/null +++ b/Scripts/Items/Resources/Reagents/PigIron.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PigIron : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public PigIron() : this( 1 ) + { + } + + [Constructable] + public PigIron( int amount ) : base( 0xF8A, amount ) + { + } + + public PigIron( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/SpidersSilk.cs b/Scripts/Items/Resources/Reagents/SpidersSilk.cs new file mode 100644 index 0000000..0703adb --- /dev/null +++ b/Scripts/Items/Resources/Reagents/SpidersSilk.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SpidersSilk : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public SpidersSilk() : this( 1 ) + { + } + + [Constructable] + public SpidersSilk( int amount ) : base( 0xF8D, amount ) + { + } + + public SpidersSilk( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Reagents/SulfurousAsh.cs b/Scripts/Items/Resources/Reagents/SulfurousAsh.cs new file mode 100644 index 0000000..523b87f --- /dev/null +++ b/Scripts/Items/Resources/Reagents/SulfurousAsh.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SulfurousAsh : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public SulfurousAsh() : this( 1 ) + { + } + + [Constructable] + public SulfurousAsh( int amount ) : base( 0xF8C, amount ) + { + } + + public SulfurousAsh( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/BoltOfCloth.cs b/Scripts/Items/Resources/Tailor/BoltOfCloth.cs new file mode 100644 index 0000000..d10b6a8 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/BoltOfCloth.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xF95, 0xF96, 0xF97, 0xF98, 0xF99, 0xF9A, 0xF9B, 0xF9C )] + public class BoltOfCloth : Item, IScissorable, IDyable, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public BoltOfCloth() : this( 1 ) + { + } + + [Constructable] + public BoltOfCloth( int amount ) : base( 0xF95 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + public BoltOfCloth( Serial serial ) : base( serial ) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) return false; + + Hue = sender.DyedHue; + + return true; + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + base.ScissorHelper( from, new Cloth(), 50 ); + + return true; + } + + public override void OnSingleClick( Mobile from ) + { + int number = (Amount == 1) ? 1049122 : 1049121; + + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Label, 0x3B2, 3, number, "", (Amount * 50).ToString() ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Bone.cs b/Scripts/Items/Resources/Tailor/Bone.cs new file mode 100644 index 0000000..5bf73fd --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Bone.cs @@ -0,0 +1,54 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + // Scriptiz : on le transforme en r�actif + // public class Bone : Item, ICommodity + public class Bone : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format(Amount == 1 ? "{0} bone" : "{0} bones", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Bone() : this( 1 ) + { + } + + [Constructable] + public Bone( int amount ) : base( 0xf7e ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Bone( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Cloth.cs b/Scripts/Items/Resources/Tailor/Cloth.cs new file mode 100644 index 0000000..81d0d51 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Cloth.cs @@ -0,0 +1,74 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x1766, 0x1768 )] + public class Cloth : Item, IScissorable, IDyable, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Cloth() : this( 1 ) + { + } + + [Constructable] + public Cloth( int amount ) : base( 0x1766 ) + { + Stackable = true; + Amount = amount; + } + + public Cloth( Serial serial ) : base( serial ) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick( Mobile from ) + { + int number = (Amount == 1) ? 1049124 : 1049123; + + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString() ) ); + } + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + base.ScissorHelper( from, new Bandage(), 1 ); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Cotton.cs b/Scripts/Items/Resources/Tailor/Cotton.cs new file mode 100644 index 0000000..96a8849 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Cotton.cs @@ -0,0 +1,115 @@ +using System; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class Cotton : Item, IDyable + { + [Constructable] + public Cotton() : this( 1 ) + { + } + + [Constructable] + public Cotton( int amount ) : base( 0xDF9 ) + { + Stackable = true; + Weight = 4.0; + Amount = amount; + } + + public Cotton( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 502655 ); // What spinning wheel do you wish to spin this on? + from.Target = new PickWheelTarget( this ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public static void OnSpun( ISpinningWheel wheel, Mobile from, int hue ) + { + Item item = new SpoolOfThread( 6 ); + item.Hue = hue; + + from.AddToBackpack( item ); + from.SendLocalizedMessage( 1010577 ); // You put the spools of thread in your backpack. + } + + private class PickWheelTarget : Target + { + private Cotton m_Cotton; + + public PickWheelTarget( Cotton cotton ) : base( 3, false, TargetFlags.None ) + { + m_Cotton = cotton; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Cotton.Deleted ) + return; + + ISpinningWheel wheel = targeted as ISpinningWheel; + + if ( wheel == null && targeted is AddonComponent ) + wheel = ((AddonComponent)targeted).Addon as ISpinningWheel; + + if ( wheel is Item ) + { + Item item = (Item)wheel; + + if ( !m_Cotton.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( wheel.Spinning ) + { + from.SendLocalizedMessage( 502656 ); // That spinning wheel is being used. + } + else + { + m_Cotton.Consume(); + wheel.BeginSpin( new SpinCallback( Cotton.OnSpun ), from, m_Cotton.Hue ); + } + } + else + { + from.SendLocalizedMessage( 502658 ); // Use that on a spinning wheel. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Flax.cs b/Scripts/Items/Resources/Tailor/Flax.cs new file mode 100644 index 0000000..9934ac8 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Flax.cs @@ -0,0 +1,105 @@ +using System; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class Flax : Item + { + [Constructable] + public Flax() : this( 1 ) + { + } + + [Constructable] + public Flax( int amount ) : base( 0x1A9C ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public Flax( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 502655 ); // What spinning wheel do you wish to spin this on? + from.Target = new PickWheelTarget( this ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public static void OnSpun( ISpinningWheel wheel, Mobile from, int hue ) + { + Item item = new SpoolOfThread( 6 ); + item.Hue = hue; + + from.AddToBackpack( item ); + from.SendLocalizedMessage( 1010577 ); // You put the spools of thread in your backpack. + } + + private class PickWheelTarget : Target + { + private Flax m_Flax; + + public PickWheelTarget( Flax flax ) : base( 3, false, TargetFlags.None ) + { + m_Flax = flax; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Flax.Deleted ) + return; + + ISpinningWheel wheel = targeted as ISpinningWheel; + + if ( wheel == null && targeted is AddonComponent ) + wheel = ((AddonComponent)targeted).Addon as ISpinningWheel; + + if ( wheel is Item ) + { + Item item = (Item)wheel; + + if ( !m_Flax.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( wheel.Spinning ) + { + from.SendLocalizedMessage( 502656 ); // That spinning wheel is being used. + } + else + { + m_Flax.Consume(); + wheel.BeginSpin( new SpinCallback( Flax.OnSpun ), from, m_Flax.Hue ); + } + } + else + { + from.SendLocalizedMessage( 502658 ); // Use that on a spinning wheel. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Hides.cs b/Scripts/Items/Resources/Tailor/Hides.cs new file mode 100644 index 0000000..6fc3df3 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Hides.cs @@ -0,0 +1,382 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseHides : Item, ICommodity + { + private CraftResource m_Resource; + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get{ return m_Resource; } + set{ m_Resource = value; InvalidateProperties(); } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Resource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + OreInfo info = new OreInfo( reader.ReadInt(), reader.ReadInt(), reader.ReadString() ); + + m_Resource = CraftResources.GetFromOreInfo( info ); + break; + } + } + } + + public BaseHides( CraftResource resource ) : this( resource, 1 ) + { + } + + public BaseHides( CraftResource resource, int amount ) : base( 0x1079 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + Hue = CraftResources.GetHue( resource ); + + m_Resource = resource; + } + + public BaseHides(CraftResource resource, int amount, int hue) + : base(0x1079) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + Hue = hue; + + m_Resource = resource; + } + + public BaseHides( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( Amount > 1 ) + list.Add( 1050039, "{0}\t#{1}", Amount, 1024216 ); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add( 1024216 ); // pile of hides + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( !CraftResources.IsStandard( m_Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( m_Resource ); + + if ( num > 0 ) + list.Add( num ); + else + list.Add( CraftResources.GetName( m_Resource ) ); + } + } + + public override int LabelNumber + { + get + { + if ( m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.DaemonLeather ) + return 1049687 + (int)(m_Resource - CraftResource.SpinedLeather); + + return 1047023; + } + } + } + + [FlipableAttribute( 0x1079, 0x1078 )] + public class Hides : BaseHides, IScissorable + { + [Constructable] + public Hides() : this( 1 ) + { + } + + [Constructable] + public Hides( int amount ) : base( CraftResource.RegularLeather, amount ) + { + } + + public Hides( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage ( 502437 ); // Items you wish to cut must be in your backpack + return false; + } + base.ScissorHelper( from, new Leather(), 1 ); + + return true; + } + } + + [FlipableAttribute( 0x1079, 0x1078 )] + public class SpinedHides : BaseHides, IScissorable + { + [Constructable] + public SpinedHides() : this( 1 ) + { + } + + [Constructable] + public SpinedHides( int amount ) : base( CraftResource.SpinedLeather, amount ) + { + } + + [Constructable] + public SpinedHides(int amount, int hue) + : base(CraftResource.SpinedLeather, amount, hue) + { + + } + + public SpinedHides( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage ( 502437 ); // Items you wish to cut must be in your backpack + return false; + } + + base.ScissorHelper( from, new SpinedLeather(), 1 ); + + return true; + } + } + + [FlipableAttribute( 0x1079, 0x1078 )] + public class HornedHides : BaseHides, IScissorable + { + [Constructable] + public HornedHides() : this( 1 ) + { + } + + [Constructable] + public HornedHides( int amount ) : base( CraftResource.HornedLeather, amount ) + { + } + + [Constructable] + public HornedHides(int amount, int hue) + : base(CraftResource.HornedLeather, amount, hue) + { + } + + + public HornedHides( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage ( 502437 ); // Items you wish to cut must be in your backpack + return false; + } + + base.ScissorHelper( from, new HornedLeather(), 1 ); + + return true; + } + } + + [FlipableAttribute( 0x1079, 0x1078 )] + public class BarbedHides : BaseHides, IScissorable + { + [Constructable] + public BarbedHides() : this( 1 ) + { + } + + [Constructable] + public BarbedHides( int amount ) : base( CraftResource.BarbedLeather, amount ) + { + } + + [Constructable] + public BarbedHides(int amount, int hue) + : base(CraftResource.BarbedLeather, amount, hue) + { + } + + public BarbedHides( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage ( 502437 ); // Items you wish to cut must be in your backpack + return false; + } + + base.ScissorHelper( from, new BarbedLeather(), 1 ); + + return true; + } + } + + //viking : ajout des hides pour le Daemon + [FlipableAttribute(0x1079, 0x1078)] + public class DaemonHides : BaseHides, IScissorable + { + [Constructable] + public DaemonHides() : this(1) + { + } + + [Constructable] + public DaemonHides(int amount) : base(CraftResource.DaemonLeather, amount) + { + } + + public DaemonHides(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + + public bool Scissor(Mobile from, Scissors scissors) + { + if (Deleted || !from.CanSee(this)) return false; + + if (Core.AOS && !IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(502437); // Items you wish to cut must be in your backpack + return false; + } + + base.ScissorHelper(from, new DaemonLeather(), 1); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Leathers.cs b/Scripts/Items/Resources/Tailor/Leathers.cs new file mode 100644 index 0000000..1dbda53 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Leathers.cs @@ -0,0 +1,305 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseLeather : Item, ICommodity + { + private CraftResource m_Resource; + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get{ return m_Resource; } + set{ m_Resource = value; InvalidateProperties(); } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Resource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + case 0: + { + OreInfo info = new OreInfo( reader.ReadInt(), reader.ReadInt(), reader.ReadString() ); + + m_Resource = CraftResources.GetFromOreInfo( info ); + break; + } + } + } + + public BaseLeather( CraftResource resource ) : this( resource, 1 ) + { + } + + public BaseLeather( CraftResource resource, int amount ) : base( 0x1081 ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + Hue = CraftResources.GetHue( resource ); + m_Resource = resource; + } + + public BaseLeather(CraftResource resource, int amount, int hue) + : base(0x1081) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + + Hue = hue; + m_Resource = resource; + } + + public BaseLeather( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( Amount > 1 ) + list.Add( 1050039, "{0}\t#{1}", Amount, 1024199 ); // ~1_NUMBER~ ~2_ITEMNAME~ + else + list.Add( 1024199 ); // cut leather + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( !CraftResources.IsStandard( m_Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( m_Resource ); + + if ( num > 0 ) + list.Add( num ); + else + list.Add( CraftResources.GetName( m_Resource ) ); + } + } + + public override int LabelNumber + { + get + { + if ( m_Resource >= CraftResource.SpinedLeather && m_Resource <= CraftResource.DaemonLeather ) + return 1049684 + (int)(m_Resource - CraftResource.SpinedLeather); + + return 1047022; + } + } + } + + [FlipableAttribute( 0x1081, 0x1082 )] + public class Leather : BaseLeather + { + [Constructable] + public Leather() : this( 1 ) + { + } + + [Constructable] + public Leather( int amount ) : base( CraftResource.RegularLeather, amount ) + { + } + + public Leather( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1081, 0x1082 )] + public class SpinedLeather : BaseLeather + { + [Constructable] + public SpinedLeather() : this( 1 ) + { + } + + [Constructable] + public SpinedLeather( int amount ) : base( CraftResource.SpinedLeather, amount ) + { + } + + [Constructable] + public SpinedLeather(int amount, int hue) : base(CraftResource.SpinedLeather, amount, hue) + { + } + + public SpinedLeather( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1081, 0x1082 )] + public class HornedLeather : BaseLeather + { + [Constructable] + public HornedLeather() : this( 1 ) + { + } + + [Constructable] + public HornedLeather( int amount ) : base( CraftResource.HornedLeather, amount ) + { + } + + [Constructable] + public HornedLeather(int amount, int hue) : base(CraftResource.HornedLeather, amount, hue) + { + this.Hue = hue; + } + + public HornedLeather( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + [FlipableAttribute( 0x1081, 0x1082 )] + public class BarbedLeather : BaseLeather + { + [Constructable] + public BarbedLeather() : this( 1 ) + { + } + + [Constructable] + public BarbedLeather( int amount ) : base( CraftResource.BarbedLeather, amount ) + { + } + + [Constructable] + public BarbedLeather(int amount, int hue) + : base(CraftResource.BarbedLeather, amount, hue) + { + } + + public BarbedLeather( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } + + //viking ajout du daemonLeather + [FlipableAttribute(0x1081, 0x1082)] + public class DaemonLeather : BaseLeather + { + [Constructable] + public DaemonLeather() : this(1) + { + } + + [Constructable] + public DaemonLeather(int amount) + : base(CraftResource.DaemonLeather, amount) + { + } + + public DaemonLeather(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/UncutCloth.cs b/Scripts/Items/Resources/Tailor/UncutCloth.cs new file mode 100644 index 0000000..0610f00 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/UncutCloth.cs @@ -0,0 +1,73 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x1765, 0x1767 )] + public class UncutCloth : Item, IScissorable, IDyable, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public UncutCloth() : this( 1 ) + { + } + + [Constructable] + public UncutCloth( int amount ) : base( 0x1767 ) + { + Stackable = true; + Amount = amount; + } + + public UncutCloth( Serial serial ) : base( serial ) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick( Mobile from ) + { + int number = (Amount == 1) ? 1049124 : 1049123; + + from.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", Amount.ToString() ) ); + } + public bool Scissor( Mobile from, Scissors scissors ) + { + if ( Deleted || !from.CanSee( this ) ) return false; + + base.ScissorHelper( from, new Bandage(), 1 ); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/Wool.cs b/Scripts/Items/Resources/Tailor/Wool.cs new file mode 100644 index 0000000..1b2ada7 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/Wool.cs @@ -0,0 +1,158 @@ +using System; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class Wool : Item, IDyable + { + [Constructable] + public Wool() : this( 1 ) + { + } + + [Constructable] + public Wool( int amount ) : base( 0xDF8 ) + { + Stackable = true; + Weight = 4.0; + Amount = amount; + } + + public Wool( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 502655 ); // What spinning wheel do you wish to spin this on? + from.Target = new PickWheelTarget( this ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public static void OnSpun( ISpinningWheel wheel, Mobile from, int hue ) + { + Item item = new DarkYarn( 3 ); + item.Hue = hue; + + from.AddToBackpack( item ); + from.SendLocalizedMessage( 1010576 ); // You put the balls of yarn in your backpack. + } + + private class PickWheelTarget : Target + { + private Wool m_Wool; + + public PickWheelTarget( Wool wool ) : base( 3, false, TargetFlags.None ) + { + m_Wool = wool; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Wool.Deleted ) + return; + + ISpinningWheel wheel = targeted as ISpinningWheel; + + if ( wheel == null && targeted is AddonComponent ) + wheel = ((AddonComponent)targeted).Addon as ISpinningWheel; + + if ( wheel is Item ) + { + Item item = (Item)wheel; + + if ( !m_Wool.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( wheel.Spinning ) + { + from.SendLocalizedMessage( 502656 ); // That spinning wheel is being used. + } + else + { + m_Wool.Consume(); + if ( m_Wool is TaintedWool ) wheel.BeginSpin( new SpinCallback( TaintedWool.OnSpun ), from, m_Wool.Hue ); + else wheel.BeginSpin( new SpinCallback( Wool.OnSpun ), from, m_Wool.Hue ); + } + } + else + { + from.SendLocalizedMessage( 502658 ); // Use that on a spinning wheel. + } + } + } + } + public class TaintedWool : Wool + { + [Constructable] + public TaintedWool() : this( 1 ) + { + } + + [Constructable] + public TaintedWool( int amount ) : base( 0x101F ) + { + Stackable = true; + Weight = 4.0; + Amount = amount; + } + + public TaintedWool( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + new public static void OnSpun( ISpinningWheel wheel, Mobile from, int hue ) + { + Item item = new DarkYarn( 1 ); + item.Hue = hue; + + from.AddToBackpack( item ); + from.SendLocalizedMessage( 1010574 ); // You put a ball of yarn in your backpack. + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Resources/Tailor/YarnsAndThreads.cs b/Scripts/Items/Resources/Tailor/YarnsAndThreads.cs new file mode 100644 index 0000000..e1a1965 --- /dev/null +++ b/Scripts/Items/Resources/Tailor/YarnsAndThreads.cs @@ -0,0 +1,235 @@ +using System; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public abstract class BaseClothMaterial : Item, IDyable + { + public BaseClothMaterial( int itemID ) : this( itemID, 1 ) + { + } + + public BaseClothMaterial( int itemID, int amount ) : base( itemID ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public BaseClothMaterial( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 500366 ); // Select a loom to use that on. + from.Target = new PickLoomTarget( this ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + private class PickLoomTarget : Target + { + private BaseClothMaterial m_Material; + + public PickLoomTarget( BaseClothMaterial material ) : base( 3, false, TargetFlags.None ) + { + m_Material = material; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Material.Deleted ) + return; + + ILoom loom = targeted as ILoom; + + if ( loom == null && targeted is AddonComponent ) + loom = ((AddonComponent)targeted).Addon as ILoom; + + if ( loom != null ) + { + if ( !m_Material.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( loom.Phase < 4 ) + { + m_Material.Consume(); + + if ( targeted is Item ) + ((Item)targeted).SendLocalizedMessageTo( from, 1010001 + loom.Phase++ ); + } + else + { + Item create = new BoltOfCloth(); + create.Hue = m_Material.Hue; + + m_Material.Consume(); + loom.Phase = 0; + from.SendLocalizedMessage( 500368 ); // You create some cloth and put it in your backpack. + from.AddToBackpack( create ); + } + } + else + { + from.SendLocalizedMessage( 500367 ); // Try using that on a loom. + } + } + } + } + + public class DarkYarn : BaseClothMaterial + { + [Constructable] + public DarkYarn() : this( 1 ) + { + } + + [Constructable] + public DarkYarn( int amount ) : base( 0xE1D, amount ) + { + } + + public DarkYarn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightYarn : BaseClothMaterial + { + [Constructable] + public LightYarn() : this( 1 ) + { + } + + [Constructable] + public LightYarn( int amount ) : base( 0xE1E, amount ) + { + } + + public LightYarn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LightYarnUnraveled : BaseClothMaterial + { + [Constructable] + public LightYarnUnraveled() : this( 1 ) + { + } + + [Constructable] + public LightYarnUnraveled( int amount ) : base( 0xE1F, amount ) + { + } + + public LightYarnUnraveled( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SpoolOfThread : BaseClothMaterial + { + [Constructable] + public SpoolOfThread() : this( 1 ) + { + } + + [Constructable] + public SpoolOfThread( int amount ) : base( 0xFA0, amount ) + { + } + + public SpoolOfThread( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Shields/Artifacts/Aegis.cs b/Scripts/Items/Shields/Artifacts/Aegis.cs new file mode 100644 index 0000000..a02229e --- /dev/null +++ b/Scripts/Items/Shields/Artifacts/Aegis.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Aegis : HeaterShield + { + public override int LabelNumber{ get{ return 1061602; } } // �gis + public override int ArtifactRarity{ get{ return 11; } } + + public override int BasePhysicalResistance{ get{ return 15; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public Aegis() + { + Hue = 0x47E; + ArmorAttributes.SelfRepair = 5; + Attributes.ReflectPhysical = 15; + Attributes.DefendChance = 15; + Attributes.LowerManaCost = 8; + } + + public Aegis( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + PhysicalBonus = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Shields/Artifacts/ArcaneShield.cs b/Scripts/Items/Shields/Artifacts/ArcaneShield.cs new file mode 100644 index 0000000..ddd178d --- /dev/null +++ b/Scripts/Items/Shields/Artifacts/ArcaneShield.cs @@ -0,0 +1,46 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcaneShield : WoodenKiteShield + { + public override int LabelNumber{ get{ return 1061101; } } // Arcane Shield + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ArcaneShield() + { + ItemID = 0x1B78; + Hue = 0x556; + Attributes.NightSight = 1; + Attributes.SpellChanneling = 1; + Attributes.DefendChance = 15; + Attributes.CastSpeed = 1; + } + + public ArcaneShield( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Attributes.NightSight == 0 ) + Attributes.NightSight = 1; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Shields/BaseShield.cs b/Scripts/Items/Shields/BaseShield.cs new file mode 100644 index 0000000..a327205 --- /dev/null +++ b/Scripts/Items/Shields/BaseShield.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class BaseShield : BaseArmor + { + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + public BaseShield( int itemID ) : base( itemID ) + { + } + + public BaseShield( Serial serial ) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + { + if ( this is Aegis ) + return; + + // The 15 bonus points to resistances are not applied to shields on OSI. + PhysicalBonus = 0; + FireBonus = 0; + ColdBonus = 0; + PoisonBonus = 0; + EnergyBonus = 0; + } + } + + public override double ArmorRating + { + get + { + Mobile m = this.Parent as Mobile; + double ar = base.ArmorRating; + + if ( m != null ) + return ( ( m.Skills[SkillName.Parry].Value * ar ) / 200.0 ) + 1.0; + else + return ar; + } + } + + public override int OnHit( BaseWeapon weapon, int damage ) + { + if( Core.AOS ) + { + if( ArmorAttributes.SelfRepair > Utility.Random( 10 ) ) + { + HitPoints += 2; + } + else + { + double halfArmor = ArmorRating / 2.0; + int absorbed = (int)(halfArmor + (halfArmor*Utility.RandomDouble())); + + if( absorbed < 2 ) + absorbed = 2; + + int wear; + + if( weapon.Type == WeaponType.Bashing ) + wear = (absorbed / 2); + else + wear = Utility.Random( 2 ); + + if( wear > 0 && MaxHitPoints > 0 ) + { + if( HitPoints >= wear ) + { + HitPoints -= wear; + wear = 0; + } + else + { + wear -= HitPoints; + HitPoints = 0; + } + + if( wear > 0 ) + { + if( MaxHitPoints > wear ) + { + MaxHitPoints -= wear; + + if( Parent is Mobile ) + ((Mobile)Parent).LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061121 ); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + } + + return 0; + } + else + { + Mobile owner = this.Parent as Mobile; + if( owner == null ) + return damage; + + double ar = this.ArmorRating; + double chance = (owner.Skills[SkillName.Parry].Value - (ar * 2.0)) / 100.0; + + if( chance < 0.01 ) + chance = 0.01; + /* + FORMULA: Displayed AR = ((Parrying Skill * Base AR of Shield) � 200) + 1 + + FORMULA: % Chance of Blocking = parry skill - (shieldAR * 2) + + FORMULA: Melee Damage Absorbed = (AR of Shield) / 2 | Archery Damage Absorbed = AR of Shield + */ + if (owner.CheckSkill(SkillName.Parry, chance)) + { + if (weapon.Skill == SkillName.Archery) + damage -= (int)ar; + else + damage -= (int)(ar / 2.0); + + if (damage < 0) + damage = 0; + + owner.FixedEffect(0x37B9, 10, 16); + + if (25 > Utility.Random(100)) // 25% chance to lower durability + { + int wear = Utility.Random(2); + + if (wear > 0 && MaxHitPoints > 0) + { + if (HitPoints >= wear) + { + HitPoints -= wear; + wear = 0; + } + else + { + wear -= HitPoints; + HitPoints = 0; + } + + if (wear > 0) + { + if (MaxHitPoints > wear) + { + MaxHitPoints -= wear; + + if (Parent is Mobile) + ((Mobile)Parent).LocalOverheadMessage(MessageType.Regular, 0x3B2, 1061121); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + } + } + + return damage; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Shields/BronzeShield.cs b/Scripts/Items/Shields/BronzeShield.cs new file mode 100644 index 0000000..4f57536 --- /dev/null +++ b/Scripts/Items/Shields/BronzeShield.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BronzeShield : BaseShield + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 1; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 30; } } + + public override int AosStrReq{ get{ return 35; } } + + public override int ArmorBase{ get{ return 10; } } + + [Constructable] + public BronzeShield() : base( 0x1B72 ) + { + Weight = 6.0; + } + + public BronzeShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Shields/Buckler.cs b/Scripts/Items/Shields/Buckler.cs new file mode 100644 index 0000000..d0eb2d1 --- /dev/null +++ b/Scripts/Items/Shields/Buckler.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Buckler : BaseShield + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 1; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 7; } } + + [Constructable] + public Buckler() : base( 0x1B73 ) + { + Weight = 5.0; + } + + public Buckler( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Shields/ChaosShield.cs b/Scripts/Items/Shields/ChaosShield.cs new file mode 100644 index 0000000..6bff471 --- /dev/null +++ b/Scripts/Items/Shields/ChaosShield.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Guilds; + +namespace Server.Items +{ + public class ChaosShield : BaseShield + { + public override int BasePhysicalResistance{ get{ return 1; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 100; } } + public override int InitMaxHits{ get{ return 125; } } + + public override int AosStrReq{ get{ return 95; } } + + public override int ArmorBase{ get{ return 32; } } + + [Constructable] + public ChaosShield() : base( 0x1BC3 ) + { + if ( !Core.AOS ) + LootType = LootType.Newbied; + + Weight = 5.0; + } + + public ChaosShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + + public override bool OnEquip( Mobile from ) + { + return Validate( from ) && base.OnEquip( from ); + } + + public override void OnSingleClick( Mobile from ) + { + if ( Validate( Parent as Mobile ) ) + base.OnSingleClick( from ); + } + + public virtual bool Validate( Mobile m ) + { + if ( m == null || !m.Player || m.AccessLevel != AccessLevel.Player || Core.AOS ) + return true; + + Guild g = m.Guild as Guild; + + if ( g == null || g.Type != GuildType.Chaos ) + { + m.FixedEffect( 0x3728, 10, 13 ); + Delete(); + + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Shields/HeaterShield.cs b/Scripts/Items/Shields/HeaterShield.cs new file mode 100644 index 0000000..57377fa --- /dev/null +++ b/Scripts/Items/Shields/HeaterShield.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HeaterShield : BaseShield + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 90; } } + + public override int ArmorBase{ get{ return 23; } } + + [Constructable] + public HeaterShield() : base( 0x1B76 ) + { + Weight = 8.0; + } + + public HeaterShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Shields/MetalKiteShield.cs b/Scripts/Items/Shields/MetalKiteShield.cs new file mode 100644 index 0000000..47c991b --- /dev/null +++ b/Scripts/Items/Shields/MetalKiteShield.cs @@ -0,0 +1,58 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MetalKiteShield : BaseShield, IDyable + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 1; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 60; } } + + public override int AosStrReq{ get{ return 45; } } + + public override int ArmorBase{ get{ return 16; } } + + [Constructable] + public MetalKiteShield() : base( 0x1B74 ) + { + Weight = 7.0; + } + + public MetalKiteShield( Serial serial ) : base(serial) + { + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 5.0 ) + Weight = 7.0; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Shields/MetalShield.cs b/Scripts/Items/Shields/MetalShield.cs new file mode 100644 index 0000000..20170d2 --- /dev/null +++ b/Scripts/Items/Shields/MetalShield.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MetalShield : BaseShield + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 1; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 45; } } + + public override int ArmorBase{ get{ return 11; } } + + [Constructable] + public MetalShield() : base( 0x1B7B ) + { + Weight = 6.0; + } + + public MetalShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Shields/OrderShield.cs b/Scripts/Items/Shields/OrderShield.cs new file mode 100644 index 0000000..584b227 --- /dev/null +++ b/Scripts/Items/Shields/OrderShield.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Guilds; + +namespace Server.Items +{ + public class OrderShield : BaseShield + { + public override int BasePhysicalResistance{ get{ return 1; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 0; } } + + public override int InitMinHits{ get{ return 100; } } + public override int InitMaxHits{ get{ return 125; } } + + public override int AosStrReq{ get{ return 95; } } + + public override int ArmorBase{ get{ return 30; } } + + [Constructable] + public OrderShield() : base( 0x1BC4 ) + { + if ( !Core.AOS ) + LootType = LootType.Newbied; + + Weight = 7.0; + } + + public OrderShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 7.0; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + + public override bool OnEquip( Mobile from ) + { + return Validate( from ) && base.OnEquip( from ); + } + + public override void OnSingleClick( Mobile from ) + { + if ( Validate( Parent as Mobile ) ) + base.OnSingleClick( from ); + } + + public virtual bool Validate( Mobile m ) + { + if ( Core.AOS || m == null || !m.Player || m.AccessLevel != AccessLevel.Player ) + return true; + + Guild g = m.Guild as Guild; + + if ( g == null || g.Type != GuildType.Order ) + { + m.FixedEffect( 0x3728, 10, 13 ); + Delete(); + + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Shields/WoodenKiteShield.cs b/Scripts/Items/Shields/WoodenKiteShield.cs new file mode 100644 index 0000000..9ee5c90 --- /dev/null +++ b/Scripts/Items/Shields/WoodenKiteShield.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WoodenKiteShield : BaseShield + { + public override int BasePhysicalResistance{ get{ return 0; } } + public override int BaseFireResistance{ get{ return 0; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 0; } } + public override int BaseEnergyResistance{ get{ return 1; } } + + public override int InitMinHits{ get{ return 50; } } + public override int InitMaxHits{ get{ return 65; } } + + public override int AosStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 12; } } + + [Constructable] + public WoodenKiteShield() : base( 0x1B79 ) + { + Weight = 5.0; + } + + public WoodenKiteShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 7.0 ) + Weight = 5.0; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Shields/WoodenShield.cs b/Scripts/Items/Shields/WoodenShield.cs new file mode 100644 index 0000000..3752735 --- /dev/null +++ b/Scripts/Items/Shields/WoodenShield.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WoodenShield : BaseShield + { + #region Mondain's Legacy + public override int PhysicalResistance { get { return BasePhysicalResistance + GetProtOffset() + GetResourceAttrs().ShieldPhysicalResist + PhysicalBonus; } } + public override int FireResistance { get { return BaseFireResistance + GetProtOffset() + GetResourceAttrs().ShieldFireResist + FireBonus ; } } + public override int ColdResistance { get { return BaseColdResistance + GetProtOffset() + GetResourceAttrs().ShieldColdResist + ColdBonus ; } } + public override int PoisonResistance { get { return BasePoisonResistance + GetProtOffset() + GetResourceAttrs().ShieldPoisonResist + PoisonBonus ; } } + public override int EnergyResistance { get { return BaseEnergyResistance + GetProtOffset() + GetResourceAttrs().ShieldEnergyResist + EnergyBonus; } } + #endregion + + public override int InitMinHits{ get{ return 20; } } + public override int InitMaxHits{ get{ return 25; } } + + public override int AosStrReq{ get{ return 20; } } + + public override int ArmorBase{ get{ return 8; } } + + [Constructable] + public WoodenShield() : base( 0x1B7A ) + { + Weight = 5.0; + } + + public WoodenShield( Serial serial ) : base(serial) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 );//version + } + } +} diff --git a/Scripts/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs b/Scripts/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs new file mode 100644 index 0000000..b75a68e --- /dev/null +++ b/Scripts/Items/Skill Items/Blacksmith Items/Misc/AnvilForge.cs @@ -0,0 +1,61 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute( 0xFAF, 0xFB0 )] + [Server.Engines.Craft.Anvil] + public class Anvil : Item + { + [Constructable] + public Anvil() : base( 0xFAF ) + { + Movable = false; + } + + public Anvil( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Server.Engines.Craft.Forge] + public class Forge : Item + { + [Constructable] + public Forge() : base( 0xFB1 ) + { + Movable = false; + } + + public Forge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs b/Scripts/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs new file mode 100644 index 0000000..fb61315 --- /dev/null +++ b/Scripts/Items/Skill Items/Blacksmith Items/Misc/LargeForge.cs @@ -0,0 +1,357 @@ +using System; +using Server; + +namespace Server.Items +{ + [Server.Engines.Craft.Forge] + public class LargeForgeWest : Item + { + private InternalItem m_Item; + private InternalItem2 m_Item2; + + [Constructable] + public LargeForgeWest() : base( 0x199A ) + { + Movable = false; + + m_Item = new InternalItem( this ); + m_Item2 = new InternalItem2( this ); + } + + public LargeForgeWest( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X, Y + 1, Z ); + if ( m_Item2 != null ) + m_Item2.Location = new Point3D( X, Y + 2, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + if ( m_Item2 != null ) + m_Item2.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + if ( m_Item2 != null ) + m_Item2.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + writer.Write( m_Item2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + m_Item2 = reader.ReadItem() as InternalItem2; + } + + [Server.Engines.Craft.Forge] + private class InternalItem : Item + { + private LargeForgeWest m_Item; + + public InternalItem( LargeForgeWest item ) : base( 0x1996 ) + { + Movable = false; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X, Y - 1, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeWest; + } + } + + [Server.Engines.Craft.Forge] + private class InternalItem2 : Item + { + private LargeForgeWest m_Item; + + public InternalItem2( LargeForgeWest item ) : base( 0x1992 ) + { + Movable = false; + + m_Item = item; + } + + public InternalItem2( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X, Y - 2, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeWest; + } + } + } + + [Server.Engines.Craft.Forge] + public class LargeForgeEast : Item + { + private InternalItem m_Item; + private InternalItem2 m_Item2; + + [Constructable] + public LargeForgeEast() : base( 0x197A ) + { + Movable = false; + + m_Item = new InternalItem( this ); + m_Item2 = new InternalItem2( this ); + } + + public LargeForgeEast( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X + 1, Y, Z ); + if ( m_Item2 != null ) + m_Item2.Location = new Point3D( X + 2, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + if ( m_Item2 != null ) + m_Item2.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + if ( m_Item2 != null ) + m_Item2.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + writer.Write( m_Item2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as InternalItem; + m_Item2 = reader.ReadItem() as InternalItem2; + } + + [Server.Engines.Craft.Forge] + private class InternalItem : Item + { + private LargeForgeEast m_Item; + + public InternalItem( LargeForgeEast item ) : base( 0x197E ) + { + Movable = false; + + m_Item = item; + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 1, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeEast; + } + } + + [Server.Engines.Craft.Forge] + private class InternalItem2 : Item + { + private LargeForgeEast m_Item; + + public InternalItem2( LargeForgeEast item ) : base( 0x1982 ) + { + Movable = false; + + m_Item = item; + } + + public InternalItem2( Serial serial ) : base( serial ) + { + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_Item != null ) + m_Item.Location = new Point3D( X - 2, Y, Z ); + } + + public override void OnMapChange() + { + if ( m_Item != null ) + m_Item.Map = Map; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Item != null ) + m_Item.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Item ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Item = reader.ReadItem() as LargeForgeEast; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Camping/Bedroll.cs b/Scripts/Items/Skill Items/Camping/Bedroll.cs new file mode 100644 index 0000000..416ee83 --- /dev/null +++ b/Scripts/Items/Skill Items/Camping/Bedroll.cs @@ -0,0 +1,131 @@ +using System; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Items +{ + [FlipableAttribute( 0xA57, 0xA58, 0xA59 )] + public class Bedroll : Item + { + [Constructable] + public Bedroll() : base( 0xA57 ) + { + Weight = 5.0; + } + + public Bedroll( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( this.Parent != null || !this.VerifyMove( from ) ) + return; + + if ( !from.InRange( this, 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + if ( this.ItemID == 0xA57 ) // rolled + { + Direction dir = PlayerMobile.GetDirection4( from.Location, this.Location ); + + if ( dir == Direction.North || dir == Direction.South ) + this.ItemID = 0xA55; + else + this.ItemID = 0xA56; + } + else // unrolled + { + this.ItemID = 0xA57; + + if ( !from.HasGump( typeof( LogoutGump ) ) ) + { + CampfireEntry entry = Campfire.GetEntry( from ); + + if ( entry != null && entry.Safe ) + from.SendGump( new LogoutGump( entry, this ) ); + } + } + } + + private class LogoutGump : Gump + { + private Timer m_CloseTimer; + + private CampfireEntry m_Entry; + private Bedroll m_Bedroll; + + public LogoutGump( CampfireEntry entry, Bedroll bedroll ) : base( 100, 0 ) + { + m_Entry = entry; + m_Bedroll = bedroll; + + m_CloseTimer = Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( CloseGump ) ); + + AddBackground( 0, 0, 400, 350, 0xA28 ); + + AddHtmlLocalized( 100, 20, 200, 35, 1011015, false, false ); //
Logging out via camping
+ + /* Using a bedroll in the safety of a camp will log you out of the game safely. + * If this is what you wish to do choose CONTINUE and you will be logged out. + * Otherwise, select the CANCEL button to avoid logging out at this time. + * The camp will remain secure for 10 seconds at which time this window will close + * and you not be logged out. + */ + AddHtmlLocalized( 50, 55, 300, 140, 1011016, true, true ); + + AddButton( 45, 298, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 300, 110, 35, 1011011, false, false ); // CONTINUE + + AddButton( 200, 298, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 235, 300, 110, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile pm = m_Entry.Player; + + m_CloseTimer.Stop(); + + if ( Campfire.GetEntry( pm ) != m_Entry ) + return; + + if ( info.ButtonID == 1 && m_Entry.Safe && m_Bedroll.Parent == null && m_Bedroll.IsAccessibleTo( pm ) + && m_Bedroll.VerifyMove( pm ) && m_Bedroll.Map == pm.Map && pm.InRange( m_Bedroll, 2 ) ) + { + pm.PlaceInBackpack( m_Bedroll ); + + pm.BedrollLogout = true; + sender.Dispose(); + } + + Campfire.RemoveEntry( m_Entry ); + } + + private void CloseGump() + { + Campfire.RemoveEntry( m_Entry ); + m_Entry.Player.CloseGump( typeof( LogoutGump ) ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Camping/Campfire.cs b/Scripts/Items/Skill Items/Camping/Campfire.cs new file mode 100644 index 0000000..a3088fe --- /dev/null +++ b/Scripts/Items/Skill Items/Camping/Campfire.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Mobiles; + +namespace Server.Items +{ + public enum CampfireStatus + { + Burning, + Extinguishing, + Off + } + + public class Campfire : Item + { + public static readonly int SecureRange = 7; + + private static readonly Hashtable m_Table = new Hashtable(); + + public static CampfireEntry GetEntry( Mobile player ) + { + return (CampfireEntry) m_Table[player]; + } + + public static void RemoveEntry( CampfireEntry entry ) + { + m_Table.Remove( entry.Player ); + entry.Fire.m_Entries.Remove( entry ); + } + + private Timer m_Timer; + private DateTime m_Created; + + private ArrayList m_Entries; + + public Campfire() : base( 0xDE3 ) + { + Movable = false; + Light = LightType.Circle300; + + m_Entries = new ArrayList(); + + m_Created = DateTime.Now; + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), new TimerCallback( OnTick ) ); + } + + public Campfire( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime Created + { + get{ return m_Created; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public CampfireStatus Status + { + get + { + switch ( this.ItemID ) + { + case 0xDE3: + return CampfireStatus.Burning; + + case 0xDE9: + return CampfireStatus.Extinguishing; + + default: + return CampfireStatus.Off; + } + } + set + { + if ( this.Status == value ) + return; + + switch ( value ) + { + case CampfireStatus.Burning: + this.ItemID = 0xDE3; + this.Light = LightType.Circle300; + break; + + case CampfireStatus.Extinguishing: + this.ItemID = 0xDE9; + this.Light = LightType.Circle150; + break; + + default: + this.ItemID = 0xDEA; + this.Light = LightType.ArchedWindowEast; + ClearEntries(); + break; + } + } + } + + private void OnTick() + { + DateTime now = DateTime.Now; + TimeSpan age = now - this.Created; + + if ( age >= TimeSpan.FromSeconds( 100.0 ) ) + this.Delete(); + else if ( age >= TimeSpan.FromSeconds( 90.0 ) ) + this.Status = CampfireStatus.Off; + else if ( age >= TimeSpan.FromSeconds( 60.0 ) ) + this.Status = CampfireStatus.Extinguishing; + + if ( this.Status == CampfireStatus.Off || this.Deleted ) + return; + + foreach ( CampfireEntry entry in new ArrayList( m_Entries ) ) + { + if ( !entry.Valid || entry.Player.NetState == null ) + { + RemoveEntry( entry ); + } + else if ( !entry.Safe && now - entry.Start >= TimeSpan.FromSeconds( 30.0 ) ) + { + entry.Safe = true; + entry.Player.SendLocalizedMessage( 500621 ); // The camp is now secure. + } + } + + IPooledEnumerable eable = this.GetClientsInRange( SecureRange ); + + foreach ( NetState state in eable ) + { + PlayerMobile pm = state.Mobile as PlayerMobile; + + if ( pm != null && GetEntry( pm ) == null ) + { + CampfireEntry entry = new CampfireEntry( pm, this ); + + m_Table[pm] = entry; + m_Entries.Add( entry ); + + pm.SendLocalizedMessage( 500620 ); // You feel it would take a few moments to secure your camp. + } + } + + eable.Free(); + } + + private void ClearEntries() + { + if ( m_Entries == null ) + return; + + foreach ( CampfireEntry entry in new ArrayList( m_Entries ) ) + { + RemoveEntry( entry ); + } + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + ClearEntries(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + this.Delete(); + } + } + + public class CampfireEntry + { + private PlayerMobile m_Player; + private Campfire m_Fire; + private DateTime m_Start; + private bool m_Safe; + + public PlayerMobile Player{ get{ return m_Player; } } + public Campfire Fire{ get{ return m_Fire; } } + public DateTime Start{ get{ return m_Start; } } + + public bool Valid + { + get{ return !Fire.Deleted && Fire.Status != CampfireStatus.Off && Player.Map == Fire.Map && Player.InRange( Fire, Campfire.SecureRange ); } + } + + public bool Safe + { + get{ return Valid && m_Safe; } + set{ m_Safe = value; } + } + + public CampfireEntry( PlayerMobile player, Campfire fire ) + { + m_Player = player; + m_Fire = fire; + m_Start = DateTime.Now; + m_Safe = false; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Camping/Kindling.cs b/Scripts/Items/Skill Items/Camping/Kindling.cs new file mode 100644 index 0000000..1d1384f --- /dev/null +++ b/Scripts/Items/Skill Items/Camping/Kindling.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + public class Kindling : Item + { + [Constructable] + public Kindling() : this( 1 ) + { + } + + [Constructable] + public Kindling( int amount ) : base( 0xDE1 ) + { + Stackable = true; + Weight = 5.0; + Amount = amount; + } + + public Kindling( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !this.VerifyMove( from ) ) + return; + + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + Point3D fireLocation = GetFireLocation( from ); + + if ( fireLocation == Point3D.Zero ) + { + from.SendLocalizedMessage( 501695 ); // There is not a spot nearby to place your campfire. + } + else if ( !from.CheckSkill( SkillName.Camping, 0.0, 100.0 ) ) + { + from.SendLocalizedMessage( 501696 ); // You fail to ignite the campfire. + } + else + { + Consume(); + + if ( !this.Deleted && this.Parent == null ) + from.PlaceInBackpack( this ); + + new Campfire().MoveToWorld( fireLocation, from.Map ); + } + } + + private Point3D GetFireLocation( Mobile from ) + { + if ( from.Region.IsPartOf( typeof( DungeonRegion ) ) ) + return Point3D.Zero; + + if ( this.Parent == null ) + return this.Location; + + ArrayList list = new ArrayList( 4 ); + + AddOffsetLocation( from, 0, -1, list ); + AddOffsetLocation( from, -1, 0, list ); + AddOffsetLocation( from, 0, 1, list ); + AddOffsetLocation( from, 1, 0, list ); + + if ( list.Count == 0 ) + return Point3D.Zero; + + int idx = Utility.Random( list.Count ); + return (Point3D) list[idx]; + } + + private void AddOffsetLocation( Mobile from, int offsetX, int offsetY, ArrayList list ) + { + Map map = from.Map; + + int x = from.X + offsetX; + int y = from.Y + offsetY; + + Point3D loc = new Point3D( x, y, from.Z ); + + if ( map.CanFit( loc, 1 ) && from.InLOS( loc ) ) + { + list.Add( loc ); + } + else + { + loc = new Point3D( x, y, map.GetAverageZ( x, y ) ); + + if ( map.CanFit( loc, 1 ) && from.InLOS( loc ) ) + list.Add( loc ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Carpenter Items/Board.cs b/Scripts/Items/Skill Items/Carpenter Items/Board.cs new file mode 100644 index 0000000..d379125 --- /dev/null +++ b/Scripts/Items/Skill Items/Carpenter Items/Board.cs @@ -0,0 +1,353 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute( 0x1BD7, 0x1BDA )] + public class BaseWoodBoard : Item, ICommodity + { + private CraftResource m_Resource; + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; InvalidateProperties(); } + } + + int ICommodity.DescriptionNumber + { + get + { + if ( m_Resource >= CraftResource.OakWood && m_Resource <= CraftResource.YewWood ) + return 1075052 + ( (int)m_Resource - (int)CraftResource.OakWood ); + + switch ( m_Resource ) + { + case CraftResource.Bloodwood: return 1075055; + case CraftResource.Frostwood: return 1075056; + case CraftResource.Heartwood: return 1075062; //WHY Osi. Why? + } + + return LabelNumber; + } + } + + bool ICommodity.IsDeedable { get { return true; } } + + + public BaseWoodBoard(): this(1) + { + } + + + public BaseWoodBoard( int amount ) + : this( CraftResource.RegularWood, amount ) + { + } + + public BaseWoodBoard( CraftResource resource ) : this( resource, 1 ) + { + } + + + public BaseWoodBoard(CraftResource resource, int amount) + : base( 0x1BD7 ) + { + Stackable = true; + Amount = amount; + + m_Resource = resource; + Hue = CraftResources.GetHue( resource ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( !CraftResources.IsStandard( m_Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( m_Resource ); + + if ( num > 0 ) + list.Add( num ); + else + list.Add( CraftResources.GetName( m_Resource ) ); + } + } + + public BaseWoodBoard(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); + + writer.Write( (int)m_Resource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + case 2: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + + if ( (version == 0 && Weight == 0.1) || ( version <= 2 && Weight == 2 ) ) + Weight = -1; + + if ( version <= 1 ) + m_Resource = CraftResource.RegularWood; + } + } + + public class Board : BaseWoodBoard + { + [Constructable] + public Board() + : this(1) + { + } + + [Constructable] + public Board(int amount) + : base(CraftResource.RegularWood, amount) + { + } + + public Board(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class HeartwoodBoard : BaseWoodBoard + { + [Constructable] + public HeartwoodBoard() + : this( 1 ) + { + } + + [Constructable] + public HeartwoodBoard( int amount ) + : base( CraftResource.Heartwood, amount ) + { + } + + public HeartwoodBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BloodwoodBoard : BaseWoodBoard + { + [Constructable] + public BloodwoodBoard() + : this( 1 ) + { + } + + [Constructable] + public BloodwoodBoard( int amount ) + : base( CraftResource.Bloodwood, amount ) + { + } + + public BloodwoodBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FrostwoodBoard : BaseWoodBoard + { + [Constructable] + public FrostwoodBoard() + : this( 1 ) + { + } + + [Constructable] + public FrostwoodBoard( int amount ) + : base( CraftResource.Frostwood, amount ) + { + } + + public FrostwoodBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class OakBoard : BaseWoodBoard + { + [Constructable] + public OakBoard() + : this( 1 ) + { + } + + [Constructable] + public OakBoard( int amount ) + : base( CraftResource.OakWood, amount ) + { + } + + public OakBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AshBoard : BaseWoodBoard + { + [Constructable] + public AshBoard() + : this( 1 ) + { + } + + [Constructable] + public AshBoard( int amount ) + : base( CraftResource.AshWood, amount ) + { + } + + public AshBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class YewBoard : BaseWoodBoard + { + [Constructable] + public YewBoard() + : this( 1 ) + { + } + + [Constructable] + public YewBoard( int amount ) + : base( CraftResource.YewWood, amount ) + { + } + + public YewBoard( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs b/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs new file mode 100644 index 0000000..7cc1a49 --- /dev/null +++ b/Scripts/Items/Skill Items/Carpenter Items/TaxidermyKit.cs @@ -0,0 +1,503 @@ +using System; +using Server; +using Server.Multis; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + [FlipableAttribute( 0x1EBA, 0x1EBB )] + public class TaxidermyKit : Item + { + public override int LabelNumber{ get{ return 1041279; } } // a taxidermy kit + + [Constructable] + public TaxidermyKit() : base( 0x1EBA ) + { + Weight = 1.0; + } + + public TaxidermyKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.Skills[SkillName.Carpentry].Base < 90.0 ) + { + from.SendLocalizedMessage( 1042594 ); // You do not understand how to use this. + } + else + { + from.SendLocalizedMessage( 1042595 ); // Target the corpse to make a trophy out of. + from.Target = new CorpseTarget( this ); + } + } + + private static TrophyInfo[] m_Table = new TrophyInfo[] + { + new TrophyInfo( typeof( BrownBear ), 0x1E60, 1041093, 1041107 ), + new TrophyInfo( typeof( GreatHart ), 0x1E61, 1041095, 1041109 ), + new TrophyInfo( typeof( BigFish ), 0x1E62, 1041096, 1041110 ), + new TrophyInfo( typeof( Gorilla ), 0x1E63, 1041091, 1041105 ), + new TrophyInfo( typeof( Orc ), 0x1E64, 1041090, 1041104 ), + new TrophyInfo( typeof( PolarBear ), 0x1E65, 1041094, 1041108 ), + new TrophyInfo( typeof( Troll ), 0x1E66, 1041092, 1041106 ) + }; + + public class TrophyInfo + { + public TrophyInfo( Type type, int id, int deedNum, int addonNum ) + { + m_CreatureType = type; + m_NorthID = id; + m_DeedNumber = deedNum; + m_AddonNumber = addonNum; + } + + private Type m_CreatureType; + private int m_NorthID; + private int m_DeedNumber; + private int m_AddonNumber; + + public Type CreatureType { get { return m_CreatureType; } } + public int NorthID { get { return m_NorthID; } } + public int DeedNumber { get { return m_DeedNumber; } } + public int AddonNumber { get { return m_AddonNumber; } } + } + + + private class CorpseTarget : Target + { + private TaxidermyKit m_Kit; + + public CorpseTarget( TaxidermyKit kit ) : base( 3, false, TargetFlags.None ) + { + m_Kit = kit; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Kit.Deleted ) + return; + + if ( !(targeted is Corpse) && !(targeted is BigFish) ) + { + from.SendLocalizedMessage( 1042600 ); // That is not a corpse! + } + else if ( targeted is Corpse && ((Corpse)targeted).VisitedByTaxidermist ) + { + from.SendLocalizedMessage( 1042596 ); // That corpse seems to have been visited by a taxidermist already. + } + else if ( !m_Kit.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.Skills[SkillName.Carpentry].Base < 90.0 ) + { + from.SendLocalizedMessage( 1042603 ); // You would not understand how to use the kit. + } + else + { + object obj = targeted; + + if ( obj is Corpse ) + obj = ((Corpse)obj).Owner; + + if ( obj != null ) + { + for ( int i = 0; i < m_Table.Length; i++ ) + { + if ( m_Table[i].CreatureType == obj.GetType() ) + { + Container pack = from.Backpack; + + if ( pack != null && pack.ConsumeTotal( typeof( Board ), 10 ) ) + { + from.SendLocalizedMessage( 1042278 ); // You review the corpse and find it worthy of a trophy. + from.SendLocalizedMessage( 1042602 ); // You use your kit up making the trophy. + + Mobile hunter = null; + int weight = 0; + + if ( targeted is BigFish ) + { + BigFish fish = targeted as BigFish; + + hunter = fish.Fisher; + weight = (int)fish.Weight; + + fish.Consume(); + } + + + from.AddToBackpack( new TrophyDeed( m_Table[i], hunter, weight ) ); + + if ( targeted is Corpse ) + ((Corpse)targeted).VisitedByTaxidermist = true; + + m_Kit.Delete(); + return; + } + else + { + from.SendLocalizedMessage( 1042598 ); // You do not have enough boards. + return; + } + } + } + } + + from.SendLocalizedMessage( 1042599 ); // That does not look like something you want hanging on a wall. + } + } + } + } + + public class TrophyAddon : Item, IAddon + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + private int m_WestID; + private int m_NorthID; + private int m_DeedNumber; + private int m_AddonNumber; + + private Mobile m_Hunter; + private int m_AnimalWeight; + + [CommandProperty( AccessLevel.GameMaster )] + public int WestID{ get{ return m_WestID; } set{ m_WestID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int NorthID{ get{ return m_NorthID; } set{ m_NorthID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DeedNumber{ get{ return m_DeedNumber; } set{ m_DeedNumber = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int AddonNumber{ get{ return m_AddonNumber; } set{ m_AddonNumber = value; InvalidateProperties(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Hunter { get { return m_Hunter; } set { m_Hunter = value; InvalidateProperties(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int AnimalWeight { get { return m_AnimalWeight; } set { m_AnimalWeight = value; InvalidateProperties(); } } + + public override int LabelNumber{ get{ return m_AddonNumber; } } + + [Constructable] + public TrophyAddon( Mobile from, int itemID, int westID, int northID, int deedNumber, int addonNumber ) : this( from, itemID, westID, northID, deedNumber, addonNumber, null, 0 ) + { + } + + public TrophyAddon( Mobile from, int itemID, int westID, int northID, int deedNumber, int addonNumber, Mobile hunter, int animalWeight ) : base( itemID ) + { + m_WestID = westID; + m_NorthID = northID; + m_DeedNumber = deedNumber; + m_AddonNumber = addonNumber; + + m_Hunter = hunter; + m_AnimalWeight = animalWeight; + + Movable = false; + + MoveToWorld( from.Location, from.Map ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_AnimalWeight >= 20 ) + { + if ( m_Hunter != null ) + list.Add( 1070857, m_Hunter.Name ); // Caught by ~1_fisherman~ + + list.Add( 1070858, m_AnimalWeight.ToString() ); // ~1_weight~ stones + } + } + + public TrophyAddon( Serial serial ) : base( serial ) + { + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( !map.CanFit( p.X, p.Y, p.Z, this.ItemData.Height ) ) + return false; + + if ( this.ItemID == m_NorthID ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // North wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // West wall + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (Mobile) m_Hunter ); + writer.Write( (int) m_AnimalWeight ); + + writer.Write( (int) m_WestID ); + writer.Write( (int) m_NorthID ); + writer.Write( (int) m_DeedNumber ); + writer.Write( (int) m_AddonNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Hunter = reader.ReadMobile(); + m_AnimalWeight = reader.ReadInt(); + goto case 0; + } + case 0: + { + m_WestID = reader.ReadInt(); + m_NorthID = reader.ReadInt(); + m_DeedNumber = reader.ReadInt(); + m_AddonNumber = reader.ReadInt(); + break; + } + } + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixMovingCrate ) ); + } + + private void FixMovingCrate() + { + if ( this.Deleted ) + return; + + if ( this.Movable || this.IsLockedDown ) + { + Item deed = this.Deed; + + if ( this.Parent is Item ) + { + ((Item)this.Parent).AddItem( deed ); + deed.Location = this.Location; + } + else + { + deed.MoveToWorld( this.Location, this.Map ); + } + + Delete(); + } + } + + public Item Deed + { + get{ return new TrophyDeed( m_WestID, m_NorthID, m_DeedNumber, m_AddonNumber, m_Hunter, m_AnimalWeight ); } + } + + public override void OnDoubleClick( Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsCoOwner( from ) ) + { + if ( from.InRange( GetWorldLocation(), 1 ) ) + { + from.AddToBackpack( this.Deed ); + Delete(); + } + else + { + from.SendLocalizedMessage( 500295 ); // You are too far away to do that. + } + } + } + } + + [Flipable( 0x14F0, 0x14EF )] + public class TrophyDeed : Item + { + private int m_WestID; + private int m_NorthID; + private int m_DeedNumber; + private int m_AddonNumber; + + private Mobile m_Hunter; + private int m_AnimalWeight; + + [CommandProperty( AccessLevel.GameMaster )] + public int WestID{ get{ return m_WestID; } set{ m_WestID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int NorthID{ get{ return m_NorthID; } set{ m_NorthID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DeedNumber{ get{ return m_DeedNumber; } set{ m_DeedNumber = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int AddonNumber{ get{ return m_AddonNumber; } set{ m_AddonNumber = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Hunter{ get{ return m_Hunter; } set{ m_Hunter = value; InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int AnimalWeight{ get{ return m_AnimalWeight; } set{ m_AnimalWeight = value; InvalidateProperties(); } } + + public override int LabelNumber{ get{ return m_DeedNumber; } } + + [Constructable] + public TrophyDeed( int westID, int northID, int deedNumber, int addonNumber ) : this( westID, northID, deedNumber, addonNumber, null, 0 ) + { + } + + public TrophyDeed( int westID, int northID, int deedNumber, int addonNumber, Mobile hunter, int animalWeight ) : base( 0x14F0 ) + { + m_WestID = westID; + m_NorthID = northID; + m_DeedNumber = deedNumber; + m_AddonNumber = addonNumber; + m_Hunter = hunter; + m_AnimalWeight = animalWeight; + } + + public TrophyDeed( TaxidermyKit.TrophyInfo info, Mobile hunter, int animalWeight ) + : this( info.NorthID + 7, info.NorthID, info.DeedNumber, info.AddonNumber ) + { + } + + public TrophyDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_AnimalWeight >= 20 ) + { + if ( m_Hunter != null ) + list.Add( 1070857, m_Hunter.Name ); // Caught by ~1_fisherman~ + + list.Add( 1070858, m_AnimalWeight.ToString() ); // ~1_weight~ stones + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (Mobile) m_Hunter ); + writer.Write( (int) m_AnimalWeight ); + + writer.Write( (int) m_WestID ); + writer.Write( (int) m_NorthID ); + writer.Write( (int) m_DeedNumber ); + writer.Write( (int) m_AddonNumber ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Hunter = reader.ReadMobile(); + m_AnimalWeight = reader.ReadInt(); + goto case 0; + } + case 0: + { + m_WestID = reader.ReadInt(); + m_NorthID = reader.ReadInt(); + m_DeedNumber = reader.ReadInt(); + m_AddonNumber = reader.ReadInt(); + break; + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsCoOwner( from ) ) + { + bool northWall = BaseAddon.IsWall( from.X, from.Y - 1, from.Z, from.Map ); + bool westWall = BaseAddon.IsWall( from.X - 1, from.Y, from.Z, from.Map ); + + if ( northWall && westWall ) + { + switch ( from.Direction & Direction.Mask ) + { + case Direction.North: + case Direction.South: northWall = true; westWall = false; break; + + case Direction.East: + case Direction.West: northWall = false; westWall = true; break; + + default: from.SendMessage( "Turn to face the wall on which to hang this trophy." ); return; + } + } + + int itemID = 0; + + if ( northWall ) + itemID = m_NorthID; + else if ( westWall ) + itemID = m_WestID; + else + from.SendLocalizedMessage( 1042626 ); // The trophy must be placed next to a wall. + + if ( itemID > 0 ) + { + house.Addons.Add( new TrophyAddon( from, itemID, m_WestID, m_NorthID, m_DeedNumber, m_AddonNumber, m_Hunter, m_AnimalWeight ) ); + Delete(); + } + } + else + { + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Fishing/FishingPole.cs b/Scripts/Items/Skill Items/Fishing/FishingPole.cs new file mode 100644 index 0000000..6e34acb --- /dev/null +++ b/Scripts/Items/Skill Items/Fishing/FishingPole.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Items; +using Server.Engines.Harvest; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Network; + +namespace Server.Items +{ + public class FishingPole : Item + { + [Constructable] + public FishingPole() : base( 0x0DC0 ) + { + Layer = Layer.TwoHanded; + Weight = 8.0; + } + + public override void OnDoubleClick( Mobile from ) + { + Point3D loc = GetWorldLocation(); + + if (!from.InLOS(loc) || !from.InRange(loc, 2)) + from.LocalOverheadMessage(MessageType.Regular, 0x3E9, 1019045); // I can't reach that + else + Fishing.System.BeginHarvesting(from, this); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + BaseHarvestTool.AddContextMenuEntries( from, this, list, Fishing.System ); + } + + public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer) + { + if (base.CheckConflictingLayer(m, item, layer)) + return true; + + if (layer == Layer.OneHanded) + { + m.SendLocalizedMessage(500214); // You already have something in both hands. + return true; + } + + return false; + } + + public FishingPole( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if (version < 1 && Layer == Layer.OneHanded) + Layer = Layer.TwoHanded; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Fishing/Misc/MessageInABottle.cs b/Scripts/Items/Skill Items/Fishing/Misc/MessageInABottle.cs new file mode 100644 index 0000000..67d5abd --- /dev/null +++ b/Scripts/Items/Skill Items/Fishing/Misc/MessageInABottle.cs @@ -0,0 +1,115 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class MessageInABottle : Item + { + public static int GetRandomLevel() + { + if ( Core.AOS && 1 > Utility.Random( 25 ) ) + return 4; // ancient + + return Utility.RandomMinMax( 1, 3 ); + } + + public override int LabelNumber{ get{ return 1041080; } } // a message in a bottle + + private Map m_TargetMap; + private int m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public Map TargetMap + { + get{ return m_TargetMap; } + set{ m_TargetMap = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Level + { + get{ return m_Level; } + set{ m_Level = Math.Max( 1, Math.Min( value, 4 ) ); } + } + + [Constructable] + public MessageInABottle() : this( Map.Trammel ) + { + } + + public MessageInABottle( Map map ) : this( map, GetRandomLevel() ) + { + } + + [Constructable] + public MessageInABottle( Map map, int level ) : base( 0x099F ) + { + Weight = 1.0; + m_TargetMap = map; + m_Level = level; + } + + public MessageInABottle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); // version + + writer.Write( (int) m_Level ); + + writer.Write( m_TargetMap ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + case 2: + { + m_Level = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_TargetMap = reader.ReadMap(); + break; + } + case 0: + { + m_TargetMap = Map.Trammel; + break; + } + } + + if ( version < 2 ) + m_Level = GetRandomLevel(); + + if( version < 3 && m_TargetMap == Map.Tokuno ) + m_TargetMap = Map.Trammel; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + Consume(); + from.AddToBackpack( new SOS( m_TargetMap, m_Level ) ); + from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 501891 ); // You extract the message from the bottle. + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs b/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs new file mode 100644 index 0000000..e5487e6 --- /dev/null +++ b/Scripts/Items/Skill Items/Fishing/Misc/SOS.cs @@ -0,0 +1,342 @@ +using System; +using Server.Network; +using Server.Gumps; + +namespace Server.Items +{ + public class SOS : Item + { + public override int LabelNumber + { + get + { + if ( IsAncient ) + return 1063450; // an ancient SOS + + return 1041081; // a waterstained SOS + } + } + + private int m_Level; + private Map m_TargetMap; + private Point3D m_TargetLocation; + private int m_MessageIndex; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsAncient + { + get{ return ( m_Level >= 4 ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Level + { + get{ return m_Level; } + set + { + m_Level = Math.Max( 1, Math.Min( value, 4 ) ); + UpdateHue(); + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Map TargetMap + { + get{ return m_TargetMap; } + set{ m_TargetMap = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D TargetLocation + { + get{ return m_TargetLocation; } + set{ m_TargetLocation = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MessageIndex + { + get{ return m_MessageIndex; } + set{ m_MessageIndex = value; } + } + + public void UpdateHue() + { + if ( IsAncient ) + Hue = 0x481; + else + Hue = 0; + } + + [Constructable] + public SOS() : this( Map.Trammel ) + { + } + + [Constructable] + public SOS( Map map ) : this( map, MessageInABottle.GetRandomLevel() ) + { + } + + [Constructable] + public SOS( Map map, int level ) : base( 0x14ED ) + { + Weight = 1.0; + + m_Level = level; + m_MessageIndex = Utility.Random( MessageEntry.Entries.Length ); + m_TargetMap = map; + m_TargetLocation = FindLocation( m_TargetMap ); + + UpdateHue(); + } + + public SOS( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 4 ); // version + + writer.Write( m_Level ); + + writer.Write( m_TargetMap ); + writer.Write( m_TargetLocation ); + writer.Write( m_MessageIndex ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 4: + case 3: + case 2: + { + m_Level = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_TargetMap = reader.ReadMap(); + m_TargetLocation = reader.ReadPoint3D(); + m_MessageIndex = reader.ReadInt(); + + break; + } + case 0: + { + m_TargetMap = this.Map; + + if ( m_TargetMap == null || m_TargetMap == Map.Internal ) + m_TargetMap = Map.Trammel; + + m_TargetLocation = FindLocation( m_TargetMap ); + m_MessageIndex = Utility.Random( MessageEntry.Entries.Length ); + + break; + } + } + + if ( version < 2 ) + m_Level = MessageInABottle.GetRandomLevel(); + + if ( version < 3 ) + UpdateHue(); + + if( version < 4 && m_TargetMap == Map.Tokuno ) + m_TargetMap = Map.Trammel; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + MessageEntry entry; + + if ( m_MessageIndex >= 0 && m_MessageIndex < MessageEntry.Entries.Length ) + entry = MessageEntry.Entries[m_MessageIndex]; + else + entry = MessageEntry.Entries[m_MessageIndex = Utility.Random( MessageEntry.Entries.Length )]; + + from.CloseGump( typeof( MessageGump ) ); + from.SendGump( new MessageGump( entry, m_TargetMap, m_TargetLocation ) ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + private static int[] m_WaterTiles = new int[] + { + 0x00A8, 0x00AB, + 0x0136, 0x0137 + }; + + // Scriptiz : zones accessibles pour l'instant + private static Rectangle2D[] m_BritRegions = new Rectangle2D[] { new Rectangle2D(2286, 1633, 4999, 4049) }; + //private static Rectangle2D[] m_BritRegions = new Rectangle2D[]{ new Rectangle2D( 0, 0, 5120, 4096 ) }; + private static Rectangle2D[] m_IlshRegions = new Rectangle2D[]{ new Rectangle2D( 1472, 272, 304, 240 ), new Rectangle2D( 1240, 1000, 312, 160 ) }; + private static Rectangle2D[] m_MalasRegions = new Rectangle2D[]{ new Rectangle2D( 1376, 1520, 464, 280 ) }; + + public static Point3D FindLocation( Map map ) + { + if ( map == null || map == Map.Internal ) + return Point3D.Zero; + + Rectangle2D[] regions; + + if ( map == Map.Felucca || map == Map.Trammel ) + regions = m_BritRegions; + else if ( map == Map.Ilshenar ) + regions = m_IlshRegions; + else if ( map == Map.Malas ) + regions = m_MalasRegions; + else + regions = new Rectangle2D[]{ new Rectangle2D( 0, 0, map.Width, map.Height ) }; + + if ( regions.Length == 0 ) + return Point3D.Zero; + + for ( int i = 0; i < 50; ++i ) + { + Rectangle2D reg = regions[Utility.Random( regions.Length )]; + int x = Utility.Random( reg.X, reg.Width ); + int y = Utility.Random( reg.Y, reg.Height ); + + if ( !ValidateDeepWater( map, x, y ) ) + continue; + + bool valid = true; + + for ( int j = 1, offset = 5; valid && j <= 5; ++j, offset += 5 ) + { + if ( !ValidateDeepWater( map, x + offset, y + offset ) ) + valid = false; + else if ( !ValidateDeepWater( map, x + offset, y - offset ) ) + valid = false; + else if ( !ValidateDeepWater( map, x - offset, y + offset ) ) + valid = false; + else if ( !ValidateDeepWater( map, x - offset, y - offset ) ) + valid = false; + } + + if ( valid ) + return new Point3D( x, y, 0 ); + } + + return Point3D.Zero; + } + + private static bool ValidateDeepWater( Map map, int x, int y ) + { + int tileID = map.Tiles.GetLandTile( x, y ).ID; + bool water = false; + + for ( int i = 0; !water && i < m_WaterTiles.Length; i += 2 ) + water = ( tileID >= m_WaterTiles[i] && tileID <= m_WaterTiles[i + 1] ); + + return water; + } + +#if false + private class MessageGump : Gump + { + public MessageGump( MessageEntry entry, Map map, Point3D loc ) : base( (640 - entry.Width) / 2, (480 - entry.Height) / 2 ) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + string fmt; + + if ( Sextant.Format( loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + fmt = String.Format( "{0}°{1}'{2},{3}°{4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + else + fmt = "?????"; + + AddPage( 0 ); + AddBackground( 0, 0, entry.Width, entry.Height, 2520 ); + AddHtml( 38, 38, entry.Width - 83, entry.Height - 86, String.Format( entry.Message, fmt ), false, false ); + } + } +#else + private class MessageGump : Gump + { + public MessageGump( MessageEntry entry, Map map, Point3D loc ) : base( 150, 50 ) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + string fmt; + + if ( Sextant.Format( loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + fmt = String.Format( "{0}°{1}'{2},{3}°{4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + else + fmt = "?????"; + + AddPage( 0 ); + + AddBackground( 0, 40, 350, 300, 2520 ); + + AddHtmlLocalized( 30, 80, 285, 160, 1018326, true, true ); /* This is a message hastily scribbled by a passenger aboard a sinking ship. + * While it is probably too late to save the passengers and crew, + * perhaps some treasure went down with the ship! + * The message gives the ship's last known sextant co-ordinates. + */ + + AddHtml( 35, 240, 230, 20, fmt, false, false ); + + AddButton( 35, 265, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 70, 265, 100, 20, 1011036, false, false ); // OKAY + } + } +#endif + + private class MessageEntry + { + private int m_Width, m_Height; + private string m_Message; + + public int Width{ get{ return m_Width; } } + public int Height{ get{ return m_Height; } } + public string Message{ get{ return m_Message; } } + + public MessageEntry( int width, int height, string message ) + { + m_Width = width; + m_Height = height; + m_Message = message; + } + + private static MessageEntry[] m_Entries = new MessageEntry[] + { + new MessageEntry( 280, 180, "...Ar! {0} and a fair wind! No chance... storms, though--ar! Is that a sea serp...

uh oh." ), + new MessageEntry( 280, 215, "...been inside this whale for three days now. I've run out of food I can pick out of his teeth. I took a sextant reading through the blowhole: {0}. I'll never see my treasure again..." ), + new MessageEntry( 280, 285, "...grand adventure! Captain Quacklebush had me swab down the decks daily...
...pirates came, I was in the rigging practicing with my sextant. {0} if I am not mistaken...
....scuttled the ship, and our precious cargo went with her and the screaming pirates, down to the bottom of the sea..." ), + new MessageEntry( 280, 180, "Help! Ship going dow...n heavy storms...precious cargo...st reach dest...current coordinates {0}...ve any survivors... ease!" ), + new MessageEntry( 280, 215, "...know that the wreck is near {0} but have not found it. Could the message passed down in my family for generations be wrong? No... I swear on the soul of my grandfather, I will find..." ), + new MessageEntry( 280, 195, "...never expected an iceberg...silly woman on bow crushed instantly...send help to {0}...ey'll never forget the tragedy of the sinking of the Miniscule..." ), + new MessageEntry( 280, 265, "...nobody knew I was a girl. They just assumed I was another sailor...then we met the undine. {0}. It was demanded sacrifice...I was youngset, they figured...
...grabbed the captain's treasure, screamed, 'It'll go down with me!'
...they took me up on it." ), + new MessageEntry( 280, 230, "...so I threw the treasure overboard, before the curse could get me too. But I was too late. Now I am doomed to wander these seas, a ghost forever. Join me: seek ye at {0} if thou wishest my company..." ), + new MessageEntry( 280, 285, "...then the ship exploded. A dragon swooped by. The slime swallowed Bertie whole--he screamed, it was amazing. The sky glowed orange. A sextant reading put us at {0}. Norma was chattering about sailing over the edge of the world. I looked at my hands and saw through them..." ), + new MessageEntry( 280, 285, "...trapped on a deserted island, with a magic fountain supplying wood, fresh water springs, gorgeous scenery, and my lovely young wife. I know the ship with all our life's earnings sank at {0} but I don't know what our coordinates are... someone has GOT to rescue me before Sunday's finals game or I'll go mad..." ), + new MessageEntry( 280, 160, "WANTED: divers exp...d in shipwre...overy. Must have own vess...pply at {0}
...good benefits, flexible hours..." ), + new MessageEntry( 280, 250, "...was a cad and a boor, no matter what momma s...rew him overboard! Oh, Anna, 'twas so exciting!
Unfort...y he grabbe...est, and all his riches went with him!
...sked the captain, and he says we're at {0}
...so maybe..." ) + }; + + public static MessageEntry[] Entries + { + get{ return m_Entries; } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Fishing/Misc/Sextant.cs b/Scripts/Items/Skill Items/Fishing/Misc/Sextant.cs new file mode 100644 index 0000000..3cf6553 --- /dev/null +++ b/Scripts/Items/Skill Items/Fishing/Misc/Sextant.cs @@ -0,0 +1,159 @@ +using System; +using Server.Network; + +namespace Server.Items +{ + public class Sextant : Item + { + [Constructable] + public Sextant() : base( 0x1058 ) + { + Weight = 2.0; + } + + public Sextant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if ( Sextant.Format( from.Location, from.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ) ) + { + string location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + from.LocalOverheadMessage( MessageType.Regular, from.SpeechHue, false, location ); + } + } + + public static bool ComputeMapDetails( Map map, int x, int y, out int xCenter, out int yCenter, out int xWidth, out int yHeight ) + { + xWidth = 5120; yHeight = 4096; + + if ( map == Map.Trammel || map == Map.Felucca ) + { + if ( x >= 0 && y >= 0 && x < 5120 && y < 4096 ) + { + xCenter = 1323; yCenter = 1624; + } + else if ( x >= 5120 && y >= 2304 && x < 6144 && y < 4096 ) + { + xCenter = 5936; yCenter = 3112; + } + else + { + xCenter = 0; yCenter = 0; + return false; + } + } + else if ( x >= 0 && y >= 0 && x < map.Width && y < map.Height ) + { + xCenter = 1323; yCenter = 1624; + } + else + { + xCenter = 0; yCenter = 0; + return false; + } + + return true; + } + + public static Point3D ReverseLookup( Map map, int xLong, int yLat, int xMins, int yMins, bool xEast, bool ySouth ) + { + if ( map == null || map == Map.Internal ) + return Point3D.Zero; + + int xCenter, yCenter; + int xWidth, yHeight; + + if ( !ComputeMapDetails( map, 0, 0, out xCenter, out yCenter, out xWidth, out yHeight ) ) + return Point3D.Zero; + + double absLong = xLong + ((double)xMins / 60); + double absLat = yLat + ((double)yMins / 60); + + if ( !xEast ) + absLong = 360.0 - absLong; + + if ( !ySouth ) + absLat = 360.0 - absLat; + + int x, y, z; + + x = xCenter + (int)((absLong * xWidth) / 360); + y = yCenter + (int)((absLat * yHeight) / 360); + + if ( x < 0 ) + x += xWidth; + else if ( x >= xWidth ) + x -= xWidth; + + if ( y < 0 ) + y += yHeight; + else if ( y >= yHeight ) + y -= yHeight; + + z = map.GetAverageZ( x, y ); + + return new Point3D( x, y, z ); + } + + public static bool Format( Point3D p, Map map, ref int xLong, ref int yLat, ref int xMins, ref int yMins, ref bool xEast, ref bool ySouth ) + { + if ( map == null || map == Map.Internal ) + return false; + + int x = p.X, y = p.Y; + int xCenter, yCenter; + int xWidth, yHeight; + + if ( !ComputeMapDetails( map, x, y, out xCenter, out yCenter, out xWidth, out yHeight ) ) + return false; + + double absLong = (double)((x - xCenter) * 360) / xWidth; + double absLat = (double)((y - yCenter) * 360) / yHeight; + + if ( absLong > 180.0 ) + absLong = -180.0 + (absLong % 180.0); + + if ( absLat > 180.0 ) + absLat = -180.0 + (absLat % 180.0); + + bool east = ( absLong >= 0 ), south = ( absLat >= 0 ); + + if ( absLong < 0.0 ) + absLong = -absLong; + + if ( absLat < 0.0 ) + absLat = -absLat; + + xLong = (int)absLong; + yLat = (int)absLat; + + xMins = (int)((absLong % 1.0) * 60); + yMins = (int)((absLat % 1.0) * 60); + + xEast = east; + ySouth = south; + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs b/Scripts/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs new file mode 100644 index 0000000..736ccad --- /dev/null +++ b/Scripts/Items/Skill Items/Fishing/Misc/ShipwreckedItem.cs @@ -0,0 +1,81 @@ +using System; + +namespace Server.Items +{ + public interface IShipwreckedItem + { + bool IsShipwreckedItem { get; set; } + } + + public class ShipwreckedItem : Item, IDyable, IShipwreckedItem + { + public ShipwreckedItem( int itemID ) : base( itemID ) + { + int weight = this.ItemData.Weight; + + if ( weight >= 255 ) + weight = 1; + + this.Weight = weight; + } + + public override void OnSingleClick( Mobile from ) + { + this.LabelTo( from, 1050039, String.Format( "#{0}\t#1041645", LabelNumber ) ); + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + list.Add( 1041645 ); // recovered from a shipwreck + } + + public ShipwreckedItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + if ( ItemID >= 0x13A4 && ItemID <= 0x13AE ) + { + Hue = sender.DyedHue; + return true; + } + + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + #region IShipwreckedItem Members + + public bool IsShipwreckedItem + { + get + { + return true; //It's a ShipwreckedItem item. 'Course it's gonna be a Shipwreckeditem + } + set + { + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs b/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs new file mode 100644 index 0000000..57e2fee --- /dev/null +++ b/Scripts/Items/Skill Items/Fishing/Misc/SpecialFishingNet.cs @@ -0,0 +1,412 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Multis; +using Server.Spells; +using Server.Targeting; + +namespace Server.Items +{ + public class SpecialFishingNet : Item + { + public override int LabelNumber { get { return 1041079; } } // a special fishing net + + private bool m_InUse; + + [CommandProperty(AccessLevel.GameMaster)] + public bool InUse + { + get { return m_InUse; } + set { m_InUse = value; } + } + + [Constructable] + public SpecialFishingNet() + : base(0x0DCA) + { + Weight = 1.0; + + if (0.01 > Utility.RandomDouble()) + Hue = Utility.RandomList(m_Hues); + else + Hue = 0x8A0; + } + + private static int[] m_Hues = new int[] + { + 0x09B, + 0x0CD, + 0x0D3, + 0x14D, + 0x1DD, + 0x1E9, + 0x1F4, + 0x373, + 0x451, + 0x47F, + 0x489, + 0x492, + 0x4B5, + 0x8AA + }; + + public SpecialFishingNet(Serial serial) + : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + AddNetProperties(list); + } + + protected virtual void AddNetProperties(ObjectPropertyList list) + { + // as if the name wasn't enough.. + list.Add(1017410); // Special Fishing Net + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write(m_InUse); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_InUse = reader.ReadBool(); + + if (m_InUse) + Delete(); + + break; + } + } + + Stackable = false; + } + + public override void OnDoubleClick(Mobile from) + { + if (m_InUse) + { + from.SendLocalizedMessage(1010483); // Someone is already using that net! + } + else if (IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1010484); // Where do you wish to use the net? + from.BeginTarget(-1, true, TargetFlags.None, new TargetCallback(OnTarget)); + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + + public virtual bool RequireDeepWater { get { return true; } } + + public void OnTarget(Mobile from, object obj) + { + if (Deleted || m_InUse) + return; + + IPoint3D p3D = obj as IPoint3D; + + if (p3D == null) + return; + + Map map = from.Map; + + if (map == null || map == Map.Internal) + return; + + int x = p3D.X, y = p3D.Y, z = map.GetAverageZ(x, y); // OSI just takes the targeted Z + + if (!from.InRange(p3D, 6)) + { + from.SendLocalizedMessage(500976); // You need to be closer to the water to fish! + } + else if (!from.InLOS(obj)) + { + from.SendLocalizedMessage(500979); // You cannot see that location. + } + else if (RequireDeepWater ? FullValidation(map, x, y) : (ValidateDeepWater(map, x, y) || ValidateUndeepWater(map, obj, ref z))) + { + Point3D p = new Point3D(x, y, z); + + if (GetType() == typeof(SpecialFishingNet)) + { + for (int i = 1; i < Amount; ++i) // these were stackable before, doh + from.AddToBackpack(new SpecialFishingNet()); + } + + m_InUse = true; + Movable = false; + MoveToWorld(p, map); + + SpellHelper.Turn(from, p); + from.Animate(12, 5, 1, true, false, 0); + + Effects.SendLocationEffect(p, map, 0x352D, 16, 4); + Effects.PlaySound(p, map, 0x364); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.25), 14, new TimerStateCallback(DoEffect), new object[] { p, 0, from }); + + from.SendLocalizedMessage(RequireDeepWater ? 1010487 : 1074492); // You plunge the net into the sea... / You plunge the net into the water... + } + else + { + from.SendLocalizedMessage(RequireDeepWater ? 1010485 : 1074491); // You can only use this net in deep water! / You can only use this net in water! + } + } + + private void DoEffect(object state) + { + if (Deleted) + return; + + object[] states = (object[])state; + + Point3D p = (Point3D)states[0]; + int index = (int)states[1]; + Mobile from = (Mobile)states[2]; + + states[1] = ++index; + + if (index == 1) + { + Effects.SendLocationEffect(p, Map, 0x352D, 16, 4); + Effects.PlaySound(p, Map, 0x364); + } + else if (index <= 7 || index == 14) + { + if (RequireDeepWater) + { + for (int i = 0; i < 3; ++i) + { + int x, y; + + switch (Utility.Random(8)) + { + default: + case 0: x = -1; y = -1; break; + case 1: x = -1; y = 0; break; + case 2: x = -1; y = +1; break; + case 3: x = 0; y = -1; break; + case 4: x = 0; y = +1; break; + case 5: x = +1; y = -1; break; + case 6: x = +1; y = 0; break; + case 7: x = +1; y = +1; break; + } + + Effects.SendLocationEffect(new Point3D(p.X + x, p.Y + y, p.Z), Map, 0x352D, 16, 4); + } + } + else + { + Effects.SendLocationEffect(p, Map, 0x352D, 16, 4); + } + + if (Utility.RandomBool()) + Effects.PlaySound(p, Map, 0x364); + + if (index == 14) + FinishEffect(p, Map, from); + else + this.Z -= 1; + } + } + + protected virtual int GetSpawnCount() + { + int count = Utility.RandomMinMax(1, 3); + + if (Hue != 0x8A0) + count += Utility.RandomMinMax(1, 2); + + return count; + } + + protected void Spawn(Point3D p, Map map, BaseCreature spawn) + { + if (map == null) + { + spawn.Delete(); + return; + } + + int x = p.X, y = p.Y; + + for (int j = 0; j < 20; ++j) + { + int tx = p.X - 2 + Utility.Random(5); + int ty = p.Y - 2 + Utility.Random(5); + + LandTile t = map.Tiles.GetLandTile(tx, ty); + + if (t.Z == p.Z && ((t.ID >= 0xA8 && t.ID <= 0xAB) || (t.ID >= 0x136 && t.ID <= 0x137)) && !Spells.SpellHelper.CheckMulti(new Point3D(tx, ty, p.Z), map)) + { + x = tx; + y = ty; + break; + } + } + + spawn.MoveToWorld(new Point3D(x, y, p.Z), map); + + if (spawn is Kraken && 0.2 > Utility.RandomDouble()) + spawn.PackItem(new MessageInABottle(map == Map.Felucca ? Map.Felucca : Map.Trammel)); + } + + protected virtual void FinishEffect(Point3D p, Map map, Mobile from) + { + from.RevealingAction(); + + int count = GetSpawnCount(); + + for (int i = 0; map != null && i < count; ++i) + { + BaseCreature spawn; + + switch (Utility.Random(4)) + { + default: + case 0: spawn = new SeaSerpent(); break; + case 1: spawn = new DeepSeaSerpent(); break; + case 2: spawn = new WaterElemental(); break; + case 3: spawn = new Kraken(); break; + } + + Spawn(p, map, spawn); + + spawn.Combatant = from; + } + + Delete(); + } + + public static bool FullValidation(Map map, int x, int y) + { + bool valid = ValidateDeepWater(map, x, y); + + for (int j = 1, offset = 5; valid && j <= 5; ++j, offset += 5) + { + if (!ValidateDeepWater(map, x + offset, y + offset)) + valid = false; + else if (!ValidateDeepWater(map, x + offset, y - offset)) + valid = false; + else if (!ValidateDeepWater(map, x - offset, y + offset)) + valid = false; + else if (!ValidateDeepWater(map, x - offset, y - offset)) + valid = false; + } + + return valid; + } + + private static int[] m_WaterTiles = new int[] + { + 0x00A8, 0x00AB, + 0x0136, 0x0137 + }; + + private static bool ValidateDeepWater(Map map, int x, int y) + { + int tileID = map.Tiles.GetLandTile(x, y).ID; + bool water = false; + + for (int i = 0; !water && i < m_WaterTiles.Length; i += 2) + water = (tileID >= m_WaterTiles[i] && tileID <= m_WaterTiles[i + 1]); + + return water; + } + + private static int[] m_UndeepWaterTiles = new int[] + { + 0x1797, 0x179C + }; + + private static bool ValidateUndeepWater(Map map, object obj, ref int z) + { + if (!(obj is StaticTarget)) + return false; + + StaticTarget target = (StaticTarget)obj; + + if (BaseHouse.FindHouseAt(target.Location, map, 0) != null) + return false; + + int itemID = target.ItemID; + + for (int i = 0; i < m_UndeepWaterTiles.Length; i += 2) + { + if (itemID >= m_UndeepWaterTiles[i] && itemID <= m_UndeepWaterTiles[i + 1]) + { + z = target.Z; + return true; + } + } + + return false; + } + } + + public class FabledFishingNet : SpecialFishingNet + { + public override int LabelNumber { get { return 1063451; } } // a fabled fishing net + + [Constructable] + public FabledFishingNet() + { + Hue = 0x481; + } + + protected override void AddNetProperties(ObjectPropertyList list) + { + } + + protected override int GetSpawnCount() + { + return base.GetSpawnCount() + 4; + } + + protected override void FinishEffect(Point3D p, Map map, Mobile from) + { + Spawn(p, map, new Leviathan(from)); + + base.FinishEffect(p, map, from); + } + + public FabledFishingNet(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs b/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs new file mode 100644 index 0000000..5c3ae71 --- /dev/null +++ b/Scripts/Items/Skill Items/Harvest Tools/BaseHarvestTool.cs @@ -0,0 +1,242 @@ +using System; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Network; +using Server.Engines.Craft; +using Server.Engines.Harvest; +using Server.ContextMenus; + +namespace Server.Items +{ + public interface IUsesRemaining + { + int UsesRemaining{ get; set; } + bool ShowUsesRemaining{ get; set; } + } + + public abstract class BaseHarvestTool : Item, IUsesRemaining, ICraftable + { + private Mobile m_Crafter; + private ToolQuality m_Quality; + private int m_UsesRemaining; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ToolQuality Quality + { + get{ return m_Quality; } + set{ UnscaleUses(); m_Quality = value; InvalidateProperties(); ScaleUses(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + public void ScaleUses() + { + m_UsesRemaining = (m_UsesRemaining * GetUsesScalar()) / 100; + InvalidateProperties(); + } + + public void UnscaleUses() + { + m_UsesRemaining = (m_UsesRemaining * 100) / GetUsesScalar(); + } + + public int GetUsesScalar() + { + if ( m_Quality == ToolQuality.Exceptional ) + return 200; + + return 100; + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + public abstract HarvestSystem HarvestSystem{ get; } + + public BaseHarvestTool( int itemID ) : this( 50, itemID ) + { + } + + public BaseHarvestTool( int usesRemaining, int itemID ) : base( itemID ) + { + m_UsesRemaining = usesRemaining; + m_Quality = ToolQuality.Regular; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + // Makers mark not displayed on OSI + //if ( m_Crafter != null ) + // list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if ( m_Quality == ToolQuality.Exceptional ) + list.Add( 1060636 ); // exceptional + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + public virtual void DisplayDurabilityTo( Mobile m ) + { + LabelToAffix( m, 1017323, AffixType.Append, ": " + m_UsesRemaining.ToString() ); // Durability + } + + public override void OnSingleClick( Mobile from ) + { + DisplayDurabilityTo( from ); + + base.OnSingleClick( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) || Parent == from ) + HarvestSystem.BeginHarvesting( from, this ); + else + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + AddContextMenuEntries( from, this, list, HarvestSystem ); + } + + public static void AddContextMenuEntries( Mobile from, Item item, List list, HarvestSystem system ) + { + if ( system != Mining.System ) + return; + + if ( !item.IsChildOf( from.Backpack ) && item.Parent != from ) + return; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + ContextMenuEntry miningEntry = new ContextMenuEntry( pm.ToggleMiningStone ? 6179 : 6178 ); + miningEntry.Color = 0x421F; + list.Add( miningEntry ); + + list.Add( new ToggleMiningStoneEntry( pm, false, 6176 ) ); + list.Add( new ToggleMiningStoneEntry( pm, true, 6177 ) ); + } + + private class ToggleMiningStoneEntry : ContextMenuEntry + { + private PlayerMobile m_Mobile; + private bool m_Value; + + public ToggleMiningStoneEntry( PlayerMobile mobile, bool value, int number ) : base( number ) + { + m_Mobile = mobile; + m_Value = value; + + bool stoneMining = ( mobile.StoneMining && mobile.Skills[SkillName.Mining].Base >= 100.0 ); + + if ( mobile.ToggleMiningStone == value || ( value && !stoneMining ) ) + this.Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + bool oldValue = m_Mobile.ToggleMiningStone; + + if ( m_Value ) + { + if ( oldValue ) + { + m_Mobile.SendLocalizedMessage( 1054023 ); // You are already set to mine both ore and stone! + } + else if ( !m_Mobile.StoneMining || m_Mobile.Skills[SkillName.Mining].Base < 100.0 ) + { + m_Mobile.SendLocalizedMessage( 1054024 ); // You have not learned how to mine stone or you do not have enough skill! + } + else + { + m_Mobile.ToggleMiningStone = true; + m_Mobile.SendLocalizedMessage( 1054022 ); // You are now set to mine both ore and stone. + } + } + else + { + if ( oldValue ) + { + m_Mobile.ToggleMiningStone = false; + m_Mobile.SendLocalizedMessage( 1054020 ); // You are now set to mine only ore. + } + else + { + m_Mobile.SendLocalizedMessage( 1054021 ); // You are already set to mine only ore! + } + } + } + } + + public BaseHarvestTool( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (Mobile) m_Crafter ); + writer.Write( (int) m_Quality ); + + writer.Write( (int) m_UsesRemaining ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Crafter = reader.ReadMobile(); + m_Quality = (ToolQuality) reader.ReadInt(); + goto case 0; + } + case 0: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } + + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (ToolQuality)quality; + + if ( makersMark ) + Crafter = from; + + return quality; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs b/Scripts/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs new file mode 100644 index 0000000..02f767e --- /dev/null +++ b/Scripts/Items/Skill Items/Harvest Tools/GargoylesPickaxe.cs @@ -0,0 +1,65 @@ +using System; +using Server; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class GargoylesPickaxe : BaseAxe, IUsesRemaining + { + public override int LabelNumber{ get{ return 1041281; } } // a gargoyle's pickaxe + public override HarvestSystem HarvestSystem{ get{ return Mining.System; } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 35; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 1; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 35; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 60; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } } + + [Constructable] + public GargoylesPickaxe() : this( Utility.RandomMinMax( 101, 125 )) + { + } + + [Constructable] + public GargoylesPickaxe( int uses ) : base( 0xE85 + Utility.Random( 2 )) + { + Weight = 11.0; + UsesRemaining = uses; + ShowUsesRemaining = true; + } + + public GargoylesPickaxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 0x973 ) + Hue = 0x0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Harvest Tools/ProspectorsTool.cs b/Scripts/Items/Skill Items/Harvest Tools/ProspectorsTool.cs new file mode 100644 index 0000000..1d3938c --- /dev/null +++ b/Scripts/Items/Skill Items/Harvest Tools/ProspectorsTool.cs @@ -0,0 +1,173 @@ +using System; +using Server; +using Server.Targeting; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class ProspectorsTool : BaseBashing, IUsesRemaining + { + private int m_UsesRemaining; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + public override int LabelNumber{ get{ return 1049065; } } // prospector's tool + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 33; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 8; } } + public override int OldSpeed{ get{ return 33; } } + + [Constructable] + public ProspectorsTool() : base( 0xFB4 ) + { + Weight = 9.0; + UsesRemaining = 50; + } + + public ProspectorsTool( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) || Parent == from ) + from.Target = new InternalTarget( this ); + else + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + + public void Prospect( Mobile from, object toProspect ) + { + if ( !IsChildOf( from.Backpack ) && Parent != from ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + + HarvestSystem system = Mining.System; + + int tileID; + Map map; + Point3D loc; + + if ( !system.GetHarvestDetails( from, this, toProspect, out tileID, out map, out loc ) ) + { + from.SendLocalizedMessage( 1049048 ); // You cannot use your prospector tool on that. + return; + } + + HarvestDefinition def = system.GetDefinition( tileID ); + + if ( def == null || def.Veins.Length <= 1 ) + { + from.SendLocalizedMessage( 1049048 ); // You cannot use your prospector tool on that. + return; + } + + HarvestBank bank = def.GetBank( map, loc.X, loc.Y ); + + if ( bank == null ) + { + from.SendLocalizedMessage( 1049048 ); // You cannot use your prospector tool on that. + return; + } + + HarvestVein vein = bank.Vein, defaultVein = bank.DefaultVein; + + if ( vein == null || defaultVein == null ) + { + from.SendLocalizedMessage( 1049048 ); // You cannot use your prospector tool on that. + return; + } + else if ( vein != defaultVein ) + { + from.SendLocalizedMessage( 1049049 ); // That ore looks to be prospected already. + return; + } + + int veinIndex = Array.IndexOf( def.Veins, vein ); + + if ( veinIndex < 0 ) + { + from.SendLocalizedMessage( 1049048 ); // You cannot use your prospector tool on that. + } + else if ( veinIndex >= (def.Veins.Length - 1) ) + { + from.SendLocalizedMessage( 1049061 ); // You cannot improve valorite ore through prospecting. + } + else + { + bank.Vein = def.Veins[veinIndex + 1]; + from.SendLocalizedMessage( 1049050 + veinIndex ); + + --UsesRemaining; + + if ( UsesRemaining <= 0 ) + { + from.SendLocalizedMessage( 1049062 ); // You have used up your prospector's tool. + Delete(); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + writer.Write( (int) m_UsesRemaining ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + case 0: + { + m_UsesRemaining = 50; + break; + } + } + } + + private class InternalTarget : Target + { + private ProspectorsTool m_Tool; + + public InternalTarget( ProspectorsTool tool ) : base( 2, true, TargetFlags.None ) + { + m_Tool = tool; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + m_Tool.Prospect( from, targeted ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Harvest Tools/Shovel.cs b/Scripts/Items/Skill Items/Harvest Tools/Shovel.cs new file mode 100644 index 0000000..44a270a --- /dev/null +++ b/Scripts/Items/Skill Items/Harvest Tools/Shovel.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class Shovel : BaseHarvestTool + { + public override HarvestSystem HarvestSystem{ get{ return Mining.System; } } + + [Constructable] + public Shovel() : this( 50 ) + { + } + + [Constructable] + public Shovel( int uses ) : base( uses, 0xF39 ) + { + Weight = 5.0; + } + + public Shovel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs b/Scripts/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs new file mode 100644 index 0000000..077d4de --- /dev/null +++ b/Scripts/Items/Skill Items/Harvest Tools/SturdyPickaxe.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class SturdyPickaxe : BaseAxe, IUsesRemaining + { + public override int LabelNumber{ get{ return 1045126; } } // sturdy pickaxe + public override HarvestSystem HarvestSystem{ get{ return Mining.System; } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 35; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 1; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 35; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } } + + [Constructable] + public SturdyPickaxe() : this( 180 ) + { + } + + [Constructable] + public SturdyPickaxe( int uses ) : base( 0xE86 ) + { + Weight = 11.0; + Hue = 0x973; + UsesRemaining = uses; + ShowUsesRemaining = true; + } + + public SturdyPickaxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Harvest Tools/SturdyShovel.cs b/Scripts/Items/Skill Items/Harvest Tools/SturdyShovel.cs new file mode 100644 index 0000000..17451fb --- /dev/null +++ b/Scripts/Items/Skill Items/Harvest Tools/SturdyShovel.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class SturdyShovel : BaseHarvestTool + { + public override int LabelNumber{ get{ return 1045125; } } // sturdy shovel + public override HarvestSystem HarvestSystem{ get{ return Mining.System; } } + + [Constructable] + public SturdyShovel() : this( 180 ) + { + } + + [Constructable] + public SturdyShovel( int uses ) : base( uses, 0xF39 ) + { + Weight = 5.0; + Hue = 0x973; + } + + public SturdyShovel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Lumberjack/Log.cs b/Scripts/Items/Skill Items/Lumberjack/Log.cs new file mode 100644 index 0000000..5be984a --- /dev/null +++ b/Scripts/Items/Skill Items/Lumberjack/Log.cs @@ -0,0 +1,395 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute(0x1bdd, 0x1be0)] + public class BaseLog : Item, ICommodity, IAxe + { + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; InvalidateProperties(); } + } + + int ICommodity.DescriptionNumber { get { return CraftResources.IsStandard(m_Resource) ? LabelNumber : 1075062 + ((int)m_Resource - (int)CraftResource.RegularWood); } } + bool ICommodity.IsDeedable { get { return true; } } + + public BaseLog() + : this(1) + { + } + + public BaseLog(int amount) + : this(CraftResource.RegularWood, amount) + { + } + + public BaseLog(CraftResource resource) + : this(resource, 1) + { + } + + public BaseLog(CraftResource resource, int amount) + : base(0x1BDD) + { + Stackable = true; + Weight = 2.0; + Amount = amount; + + m_Resource = resource; + Hue = CraftResources.GetHue(resource); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!CraftResources.IsStandard(m_Resource)) + { + int num = CraftResources.GetLocalizationNumber(m_Resource); + + if (num > 0) + list.Add(num); + else + list.Add(CraftResources.GetName(m_Resource)); + } + } + public BaseLog(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write((int)m_Resource); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Resource = (CraftResource)reader.ReadInt(); + break; + } + } + + if (version == 0) + m_Resource = CraftResource.RegularWood; + } + + public virtual bool TryCreateBoards(Mobile from, double skill, Item item) + { + if (Deleted || !from.CanSee(this)) + return false; + else if (from.Skills.Carpentry.Value < skill && + from.Skills.Lumberjacking.Value < skill) + { + item.Delete(); + from.SendLocalizedMessage(1072652); // You cannot work this strange and unusual wood. + return false; + } + base.ScissorHelper(from, item, 1, false); + return true; + } + + public virtual bool Axe(Mobile from, BaseAxe axe) + { + if (!TryCreateBoards(from, 0, new Board())) + return false; + + return true; + } + } + + public class Log : BaseLog + { + [Constructable] + public Log() : this( 1 ) + { + } + [Constructable] + public Log( int amount ) + : base( CraftResource.RegularWood, amount ) + { + } + public Log(Serial serial) + : base(serial) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)2 ); // version + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 20, new Board() ) ) + return false; + + return true; + } + } + public class HeartwoodLog : BaseLog + { + [Constructable] + public HeartwoodLog() : this( 1 ) + { + } + [Constructable] + public HeartwoodLog( int amount ) + : base( CraftResource.Heartwood, amount ) + { + } + public HeartwoodLog( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 100, new HeartwoodBoard() ) ) + return false; + + return true; + } + } + + public class BloodwoodLog : BaseLog + { + [Constructable] + public BloodwoodLog() + : this( 1 ) + { + } + [Constructable] + public BloodwoodLog( int amount ) + : base( CraftResource.Bloodwood, amount ) + { + } + public BloodwoodLog( Serial serial ) + : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 100, new BloodwoodBoard() ) ) + return false; + + return true; + } + } + + public class FrostwoodLog : BaseLog + { + [Constructable] + public FrostwoodLog() + : this( 1 ) + { + } + + [Constructable] + public FrostwoodLog( int amount ) + : base( CraftResource.Frostwood, amount ) + { + } + + public FrostwoodLog( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 100, new FrostwoodBoard() ) ) + return false; + + return true; + } + } + + public class OakLog : BaseLog + { + [Constructable] + public OakLog() + : this( 1 ) + { + } + + [Constructable] + public OakLog( int amount ) + : base( CraftResource.OakWood, amount ) + { + } + + public OakLog( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 65, new OakBoard() ) ) + return false; + + return true; + } + } + + public class AshLog : BaseLog + { + [Constructable] + public AshLog() + : this( 1 ) + { + } + + [Constructable] + public AshLog( int amount ) + : base( CraftResource.AshWood, amount ) + { + } + + public AshLog( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 80, new AshBoard() ) ) + return false; + + return true; + } + } + + public class YewLog : BaseLog + { + [Constructable] + public YewLog() + : this( 1 ) + { + } + + [Constructable] + public YewLog( int amount ) + : base( CraftResource.YewWood, amount ) + { + } + + public YewLog( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool Axe( Mobile from, BaseAxe axe ) + { + if ( !TryCreateBoards( from , 95, new YewBoard() ) ) + return false; + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/BookOfBushido.cs b/Scripts/Items/Skill Items/Magical/BookOfBushido.cs new file mode 100644 index 0000000..3fba8f0 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/BookOfBushido.cs @@ -0,0 +1,56 @@ +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class BookOfBushido : Spellbook + { + public override SpellbookType SpellbookType{ get{ return SpellbookType.Samurai; } } + public override int BookOffset{ get{ return 400; } } + public override int BookCount{ get{ return 6; } } + + [Constructable] + public BookOfBushido() : this( (ulong)0x00) + { + } + + [Constructable] + public BookOfBushido( ulong content ) : base( content, 0x238C ) + { + Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid); + Lootable = false; + Stealable = false; + } + + public BookOfBushido( Serial serial ) : base( serial ) + { + } + + // Scriptiz : le livre de bushi ne peut pas quitter le sac ou le joueur + public override bool Nontransferable + { + get { return true; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 0 && Core.ML ) + Layer = Layer.OneHanded; + + if (ItemID == 0) + ItemID = 0x238C; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/BookOfChivalry.cs b/Scripts/Items/Skill Items/Magical/BookOfChivalry.cs new file mode 100644 index 0000000..3ae3b06 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/BookOfChivalry.cs @@ -0,0 +1,53 @@ +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class BookOfChivalry : Spellbook + { + public override SpellbookType SpellbookType{ get{ return SpellbookType.Paladin; } } + public override int BookOffset{ get{ return 200; } } + public override int BookCount{ get{ return 10; } } + + [Constructable] + public BookOfChivalry() : this( (ulong)0 ) + { + } + + [Constructable] + public BookOfChivalry( ulong content ) : base( content, 0x2252 ) + { + Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid); + Lootable = false; + Stealable = false; + } + + public BookOfChivalry( Serial serial ) : base( serial ) + { + } + + // Scriptiz : le livre de palouf ne peut pas quitter le sac ou le joueur + public override bool Nontransferable + { + get { return true; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 0 && Core.ML ) + Layer = Layer.OneHanded; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/BookOfNinjitsu.cs b/Scripts/Items/Skill Items/Magical/BookOfNinjitsu.cs new file mode 100644 index 0000000..183cd95 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/BookOfNinjitsu.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class BookOfNinjitsu : Spellbook + { + public override SpellbookType SpellbookType{ get{ return SpellbookType.Ninja; } } + public override int BookOffset{ get{ return 500; } } + public override int BookCount{ get{ return 8; } } + + + [Constructable] + public BookOfNinjitsu() : this( (ulong)0x00 ) + { + } + + [Constructable] + public BookOfNinjitsu(ulong content) : base(content, 0x23A0) + { + Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid); + Lootable = false; + Stealable = false; + } + + public BookOfNinjitsu( Serial serial ) : base( serial ) + { + } + + // Scriptiz : le livre de ninji ne peut pas quitter le sac ou le joueur + public override bool Nontransferable + { + get { return true; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 0 && Core.ML ) + Layer = Layer.OneHanded; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Misc/BlankScroll.cs b/Scripts/Items/Skill Items/Magical/Misc/BlankScroll.cs new file mode 100644 index 0000000..c13ad56 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Misc/BlankScroll.cs @@ -0,0 +1,51 @@ +using System; +using Server.Engines.Craft; +using Server.Mobiles; + +namespace Server.Items +{ + public class BlankScroll : Item, ICommodity, ICraftable + { + [Constructable] + public BlankScroll() : this( 1 ) + { + } + + [Constructable] + public BlankScroll( int amount ) : base( 0xEF3 ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return (Core.ML); } } + + // Scriptiz : on en craft 10 par 10 + public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue) + { + Amount = 10; + + return quality; + } + + public BlankScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Misc/Bottle.cs b/Scripts/Items/Skill Items/Magical/Misc/Bottle.cs new file mode 100644 index 0000000..cdec3c3 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Misc/Bottle.cs @@ -0,0 +1,43 @@ +using System; + +namespace Server.Items +{ + public class Bottle : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return (Core.ML); } } + + [Constructable] + public Bottle() : this( 1 ) + { + } + + [Constructable] + public Bottle( int amount ) : base( 0xF0E ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + } + + public Bottle( Serial serial ) : base( serial ) + { + } + + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs b/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs new file mode 100644 index 0000000..e712034 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Misc/Moongate.cs @@ -0,0 +1,464 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Gumps; +using Server.Regions; + +namespace Server.Items +{ + [DispellableFieldAttribute] + public class Moongate : Item + { + private Point3D m_Target; + private Map m_TargetMap; + private bool m_bDispellable; + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Target + { + get + { + return m_Target; + } + set + { + m_Target = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Map TargetMap + { + get + { + return m_TargetMap; + } + set + { + m_TargetMap = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Dispellable + { + get + { + return m_bDispellable; + } + set + { + m_bDispellable = value; + } + } + + public virtual bool ShowFeluccaWarning{ get{ return false; } } + + [Constructable] + public Moongate() : this( Point3D.Zero, null ) + { + m_bDispellable = true; + } + + [Constructable] + public Moongate(bool bDispellable) : this( Point3D.Zero, null ) + { + m_bDispellable = bDispellable; + } + + [Constructable] + public Moongate( Point3D target, Map targetMap ) : base( 0xF6C ) + { + Movable = false; + Light = LightType.Circle300; + + m_Target = target; + m_TargetMap = targetMap; + } + + public Moongate( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.Player ) + return; + + if ( from.InRange( GetWorldLocation(), 1 ) ) + CheckGate( from, 1 ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m.Player ) + CheckGate( m, 0 ); + + return true; + } + + public virtual void CheckGate( Mobile m, int range ) + { + #region Mondain's Legacy + if (m.Hidden && m.AccessLevel == AccessLevel.Player && Core.ML) + m.RevealingAction(); + #endregion + + new DelayTimer( m, this, range ).Start(); + } + + public virtual void OnGateUsed( Mobile m ) + { + } + + public virtual void UseGate( Mobile m ) + { + ClientFlags flags = m.NetState == null ? ClientFlags.None : m.NetState.Flags; + + if ( Factions.Sigil.ExistsOn( m ) ) + { + m.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( m_TargetMap == Map.Felucca && m is PlayerMobile && ((PlayerMobile)m).Young ) + { + m.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young. + } + else if ( (m.Kills >= 5 && m_TargetMap != Map.Felucca) || ( m_TargetMap == Map.Tokuno && (flags & ClientFlags.Tokuno) == 0 ) || ( m_TargetMap == Map.Malas && (flags & ClientFlags.Malas) == 0 ) || ( m_TargetMap == Map.Ilshenar && (flags & ClientFlags.Ilshenar) == 0 ) ) + { + m.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( m.Spell != null ) + { + m.SendLocalizedMessage( 1049616 ); // You are too busy to do that at the moment. + } + else if ( m_TargetMap != null && m_TargetMap != Map.Internal ) + { + BaseCreature.TeleportPets( m, m_Target, m_TargetMap ); + + m.MoveToWorld( m_Target, m_TargetMap ); + + if ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) + m.PlaySound( 0x1FE ); + + OnGateUsed( m ); + } + else + { + m.SendMessage( "This moongate does not seem to go anywhere." ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Target ); + writer.Write( m_TargetMap ); + + // Version 1 + writer.Write( m_bDispellable ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Target = reader.ReadPoint3D(); + m_TargetMap = reader.ReadMap(); + + if ( version >= 1 ) + m_bDispellable = reader.ReadBool(); + } + + public virtual bool ValidateUse( Mobile from, bool message ) + { + if ( from.Deleted || this.Deleted ) + return false; + + if ( from.Map != this.Map || !from.InRange( this, 1 ) ) + { + if ( message ) + from.SendLocalizedMessage( 500446 ); // That is too far away. + + return false; + } + + return true; + } + + public virtual void BeginConfirmation( Mobile from ) + { + if ( IsInTown( from.Location, from.Map ) && !IsInTown( m_Target, m_TargetMap ) || (from.Map != Map.Felucca && TargetMap == Map.Felucca && ShowFeluccaWarning) ) + { + if ( from.AccessLevel == AccessLevel.Player || !from.Hidden ) + from.Send( new PlaySound( 0x20E, from.Location ) ); + from.CloseGump( typeof( MoongateConfirmGump ) ); + from.SendGump( new MoongateConfirmGump( from, this ) ); + } + else + { + EndConfirmation( from ); + } + } + + public virtual void EndConfirmation( Mobile from ) + { + if ( !ValidateUse( from, true ) ) + return; + + UseGate( from ); + } + + public virtual void DelayCallback( Mobile from, int range ) + { + if ( !ValidateUse( from, false ) || !from.InRange( this, range ) ) + return; + + if ( m_TargetMap != null ) + BeginConfirmation( from ); + else + from.SendMessage( "This moongate does not seem to go anywhere." ); + } + + public static bool IsInTown( Point3D p, Map map ) + { + if ( map == null ) + return false; + + GuardedRegion reg = (GuardedRegion) Region.Find( p, map ).GetRegion( typeof( GuardedRegion ) ); + + return ( reg != null && !reg.IsDisabled() ); + } + + private class DelayTimer : Timer + { + private Mobile m_From; + private Moongate m_Gate; + private int m_Range; + + public DelayTimer( Mobile from, Moongate gate, int range ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_From = from; + m_Gate = gate; + m_Range = range; + } + + protected override void OnTick() + { + m_Gate.DelayCallback( m_From, m_Range ); + } + } + } + + public class ConfirmationMoongate : Moongate + { + private int m_GumpWidth; + private int m_GumpHeight; + + private int m_TitleColor; + private int m_MessageColor; + + private int m_TitleNumber; + private int m_MessageNumber; + + private string m_MessageString; + + [CommandProperty( AccessLevel.GameMaster )] + public int GumpWidth + { + get{ return m_GumpWidth; } + set{ m_GumpWidth = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int GumpHeight + { + get{ return m_GumpHeight; } + set{ m_GumpHeight = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TitleColor + { + get{ return m_TitleColor; } + set{ m_TitleColor = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MessageColor + { + get{ return m_MessageColor; } + set{ m_MessageColor = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TitleNumber + { + get{ return m_TitleNumber; } + set{ m_TitleNumber = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MessageNumber + { + get{ return m_MessageNumber; } + set{ m_MessageNumber = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string MessageString + { + get{ return m_MessageString; } + set{ m_MessageString = value; } + } + + [Constructable] + public ConfirmationMoongate() : this( Point3D.Zero, null ) + { + } + + [Constructable] + public ConfirmationMoongate( Point3D target, Map targetMap ) : base( target, targetMap ) + { + } + + public ConfirmationMoongate( Serial serial ) : base( serial ) + { + } + + public virtual void Warning_Callback( Mobile from, bool okay, object state ) + { + if ( okay ) + EndConfirmation( from ); + } + + public override void BeginConfirmation( Mobile from ) + { + if ( m_GumpWidth > 0 && m_GumpHeight > 0 && m_TitleNumber > 0 && (m_MessageNumber > 0 || m_MessageString != null) ) + { + from.CloseGump( typeof( WarningGump ) ); + from.SendGump( new WarningGump( m_TitleNumber, m_TitleColor, m_MessageString == null ? (object)m_MessageNumber : (object)m_MessageString, m_MessageColor, m_GumpWidth, m_GumpHeight, new WarningGumpCallback( Warning_Callback ), from ) ); + } + else + { + base.BeginConfirmation( from ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteEncodedInt( m_GumpWidth ); + writer.WriteEncodedInt( m_GumpHeight ); + + writer.WriteEncodedInt( m_TitleColor ); + writer.WriteEncodedInt( m_MessageColor ); + + writer.WriteEncodedInt( m_TitleNumber ); + writer.WriteEncodedInt( m_MessageNumber ); + + writer.Write( m_MessageString ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_GumpWidth = reader.ReadEncodedInt(); + m_GumpHeight = reader.ReadEncodedInt(); + + m_TitleColor = reader.ReadEncodedInt(); + m_MessageColor = reader.ReadEncodedInt(); + + m_TitleNumber = reader.ReadEncodedInt(); + m_MessageNumber = reader.ReadEncodedInt(); + + m_MessageString = reader.ReadString(); + + break; + } + } + } + } + + public class MoongateConfirmGump : Gump + { + private Mobile m_From; + private Moongate m_Gate; + + public MoongateConfirmGump( Mobile from, Moongate gate ) : base( Core.AOS ? 110 : 20, Core.AOS ? 100 : 30 ) + { + m_From = from; + m_Gate = gate; + + if ( Core.AOS ) + { + Closable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 280, 5054 ); + + AddImageTiled( 10, 10, 400, 20, 2624 ); + AddAlphaRegion( 10, 10, 400, 20 ); + + AddHtmlLocalized( 10, 10, 400, 20, 1062051, 30720, false, false ); // Gate Warning + + AddImageTiled( 10, 40, 400, 200, 2624 ); + AddAlphaRegion( 10, 40, 400, 200 ); + + if ( from.Map != Map.Felucca && gate.TargetMap == Map.Felucca && gate.ShowFeluccaWarning ) + AddHtmlLocalized( 10, 40, 400, 200, 1062050, 32512, false, true ); // This Gate goes to Felucca... Continue to enter the gate, Cancel to stay here + else + AddHtmlLocalized( 10, 40, 400, 200, 1062049, 32512, false, true ); // Dost thou wish to step into the moongate? Continue to enter the gate, Cancel to stay here + + AddImageTiled( 10, 250, 400, 20, 2624 ); + AddAlphaRegion( 10, 250, 400, 20 ); + + AddButton( 10, 250, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 250, 170, 20, 1011036, 32767, false, false ); // OKAY + + AddButton( 210, 250, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 240, 250, 170, 20, 1011012, 32767, false, false ); // CANCEL + } + else + { + AddPage( 0 ); + + AddBackground( 0, 0, 420, 400, 5054 ); + AddBackground( 10, 10, 400, 380, 3000 ); + + AddHtml( 20, 40, 380, 60, @"Dost thou wish to step into the moongate? Continue to enter the gate, Cancel to stay here", false, false ); + + AddHtmlLocalized( 55, 110, 290, 20, 1011012, false, false ); // CANCEL + AddButton( 20, 110, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 140, 290, 40, 1011011, false, false ); // CONTINUE + AddButton( 20, 140, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + m_Gate.EndConfirmation( m_From ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Misc/PotionKeg.cs b/Scripts/Items/Skill Items/Magical/Misc/PotionKeg.cs new file mode 100644 index 0000000..f412f18 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Misc/PotionKeg.cs @@ -0,0 +1,361 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PotionKeg : Item + { + private PotionEffect m_Type; + private int m_Held; + + [CommandProperty( AccessLevel.GameMaster )] + public int Held + { + get + { + return m_Held; + } + set + { + if ( m_Held != value ) + { + m_Held = value; + UpdateWeight(); + InvalidateProperties(); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public PotionEffect Type + { + get + { + return m_Type; + } + set + { + m_Type = value; + InvalidateProperties(); + } + } + + [Constructable] + public PotionKeg() : base( 0x1940 ) + { + UpdateWeight(); + } + + public virtual void UpdateWeight() + { + int held = Math.Max( 0, Math.Min( m_Held, 100 ) ); + + this.Weight = 20 + ((held * 80) / 100); + } + + public PotionKeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Type ); + writer.Write( (int) m_Held ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_Type = (PotionEffect)reader.ReadInt(); + m_Held = reader.ReadInt(); + + break; + } + } + + if ( version < 1 ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( UpdateWeight ) ); + } + + public override int LabelNumber + { + get + { + if( m_Held > 0 && ( int )m_Type >= ( int )PotionEffect.Conflagration ) + { + return 1072658 + ( int )m_Type - ( int )PotionEffect.Conflagration; + } + + return (m_Held > 0 ? 1041620 + (int)m_Type : 1041641); + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + int number; + + if ( m_Held <= 0 ) + number = 502246; // The keg is empty. + else if ( m_Held < 5 ) + number = 502248; // The keg is nearly empty. + else if ( m_Held < 20 ) + number = 502249; // The keg is not very full. + else if ( m_Held < 30 ) + number = 502250; // The keg is about one quarter full. + else if ( m_Held < 40 ) + number = 502251; // The keg is about one third full. + else if ( m_Held < 47 ) + number = 502252; // The keg is almost half full. + else if ( m_Held < 54 ) + number = 502254; // The keg is approximately half full. + else if ( m_Held < 70 ) + number = 502253; // The keg is more than half full. + else if ( m_Held < 80 ) + number = 502255; // The keg is about three quarters full. + else if ( m_Held < 96 ) + number = 502256; // The keg is very full. + else if ( m_Held < 100 ) + number = 502257; // The liquid is almost to the top of the keg. + else + number = 502258; // The keg is completely full. + + list.Add( number ); + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + int number; + + if ( m_Held <= 0 ) + number = 502246; // The keg is empty. + else if ( m_Held < 5 ) + number = 502248; // The keg is nearly empty. + else if ( m_Held < 20 ) + number = 502249; // The keg is not very full. + else if ( m_Held < 30 ) + number = 502250; // The keg is about one quarter full. + else if ( m_Held < 40 ) + number = 502251; // The keg is about one third full. + else if ( m_Held < 47 ) + number = 502252; // The keg is almost half full. + else if ( m_Held < 54 ) + number = 502254; // The keg is approximately half full. + else if ( m_Held < 70 ) + number = 502253; // The keg is more than half full. + else if ( m_Held < 80 ) + number = 502255; // The keg is about three quarters full. + else if ( m_Held < 96 ) + number = 502256; // The keg is very full. + else if ( m_Held < 100 ) + number = 502257; // The liquid is almost to the top of the keg. + else + number = 502258; // The keg is completely full. + + this.LabelTo( from, number ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + { + if ( m_Held > 0 ) + { + Container pack = from.Backpack; + + if ( pack != null && pack.ConsumeTotal( typeof( Bottle ), 1 ) ) + { + from.SendLocalizedMessage( 502242 ); // You pour some of the keg's contents into an empty bottle... + + BasePotion pot = FillBottle(); + + if ( pack.TryDropItem( from, pot, false ) ) + { + from.SendLocalizedMessage( 502243 ); // ...and place it into your backpack. + from.PlaySound( 0x240 ); + + if ( --Held == 0 ) + from.SendLocalizedMessage( 502245 ); // The keg is now empty. + } + else + { + from.SendLocalizedMessage( 502244 ); // ...but there is no room for the bottle in your backpack. + pot.Delete(); + } + } + else + { + // TODO: Target a bottle + } + } + else + { + from.SendLocalizedMessage( 502246 ); // The keg is empty. + } + } + else + { + from.LocalOverheadMessage( Network.MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( item is BasePotion ) + { + BasePotion pot = (BasePotion)item; + int toHold = Math.Min( 100 - m_Held, pot.Amount ); + + + if ( toHold <= 0 ) + { + from.SendLocalizedMessage( 502233 ); // The keg will not hold any more! + return false; + } + else if ( m_Held == 0 ) + { + #region Mondain's Legacy + if ((int)pot.PotionEffect >= (int)PotionEffect.Invisibility) + { + from.SendLocalizedMessage(502232); // The keg is not designed to hold that type of object. + return false; + } + #endregion + + + if ( GiveBottle( from, toHold ) ) + { + m_Type = pot.PotionEffect; + Held = toHold; + + from.PlaySound( 0x240 ); + + from.SendLocalizedMessage( 502237 ); // You place the empty bottle in your backpack. + + item.Consume( toHold ); + + if( !item.Deleted ) + item.Bounce( from ); + + return true; + } + else + { + from.SendLocalizedMessage( 502238 ); // You don't have room for the empty bottle in your backpack. + return false; + } + } + else if ( pot.PotionEffect != m_Type ) + { + from.SendLocalizedMessage( 502236 ); // You decide that it would be a bad idea to mix different types of potions. + return false; + } + else + { + if ( GiveBottle( from, toHold ) ) + { + Held += toHold; + + from.PlaySound( 0x240 ); + + from.SendLocalizedMessage( 502237 ); // You place the empty bottle in your backpack. + + item.Consume( toHold ); + + if( !item.Deleted ) + item.Bounce( from ); + + return true; + } + else + { + from.SendLocalizedMessage( 502238 ); // You don't have room for the empty bottle in your backpack. + return false; + } + } + } + else + { + from.SendLocalizedMessage( 502232 ); // The keg is not designed to hold that type of object. + return false; + } + } + + public bool GiveBottle( Mobile m, int amount ) + { + Container pack = m.Backpack; + + Bottle bottle = new Bottle( amount ); + + if ( pack == null || !pack.TryDropItem( m, bottle, false ) ) + { + bottle.Delete(); + return false; + } + + return true; + } + + public BasePotion FillBottle() + { + switch ( m_Type ) + { + default: + case PotionEffect.Nightsight: return new NightSightPotion(); + + case PotionEffect.CureLesser: return new LesserCurePotion(); + case PotionEffect.Cure: return new CurePotion(); + case PotionEffect.CureGreater: return new GreaterCurePotion(); + + case PotionEffect.Agility: return new AgilityPotion(); + case PotionEffect.AgilityGreater: return new GreaterAgilityPotion(); + + case PotionEffect.Strength: return new StrengthPotion(); + case PotionEffect.StrengthGreater: return new GreaterStrengthPotion(); + + case PotionEffect.PoisonLesser: return new LesserPoisonPotion(); + case PotionEffect.Poison: return new PoisonPotion(); + case PotionEffect.PoisonGreater: return new GreaterPoisonPotion(); + case PotionEffect.PoisonDeadly: return new DeadlyPoisonPotion(); + + case PotionEffect.Refresh: return new RefreshPotion(); + case PotionEffect.RefreshTotal: return new TotalRefreshPotion(); + + case PotionEffect.HealLesser: return new LesserHealPotion(); + case PotionEffect.Heal: return new HealPotion(); + case PotionEffect.HealGreater: return new GreaterHealPotion(); + + case PotionEffect.ExplosionLesser: return new LesserExplosionPotion(); + case PotionEffect.Explosion: return new ExplosionPotion(); + case PotionEffect.ExplosionGreater: return new GreaterExplosionPotion(); + + case PotionEffect.Conflagration: return new ConflagrationPotion(); + case PotionEffect.ConflagrationGreater: return new GreaterConflagrationPotion(); + + case PotionEffect.ConfusionBlast: return new ConfusionBlastPotion(); + case PotionEffect.ConfusionBlastGreater: return new GreaterConfusionBlastPotion(); + } + } + + public static void Initialize() + { + TileData.ItemTable[0x1940].Height = 4; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs b/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs new file mode 100644 index 0000000..59dfd22 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Misc/RecallRune.cs @@ -0,0 +1,321 @@ +using System; +using Server.Network; +using Server.Prompts; +using Server.Multis; +using Server.Regions; + +namespace Server.Items +{ + [FlipableAttribute( 0x1f14, 0x1f15, 0x1f16, 0x1f17 )] + public class RecallRune : Item + { + private string m_Description; + private bool m_Marked; + private Point3D m_Target; + private Map m_TargetMap; + private BaseHouse m_House; + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + if ( m_House != null && !m_House.Deleted ) + { + writer.Write( (int) 1 ); // version + + writer.Write( (Item) m_House ); + } + else + { + writer.Write( (int) 0 ); // version + } + + writer.Write( (string) m_Description ); + writer.Write( (bool) m_Marked ); + writer.Write( (Point3D) m_Target ); + writer.Write( (Map) m_TargetMap ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_House = reader.ReadItem() as BaseHouse; + goto case 0; + } + case 0: + { + m_Description = reader.ReadString(); + m_Marked = reader.ReadBool(); + m_Target = reader.ReadPoint3D(); + m_TargetMap = reader.ReadMap(); + + CalculateHue(); + + break; + } + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public BaseHouse House + { + get + { + if ( m_House != null && m_House.Deleted ) + House = null; + + return m_House; + } + set{ m_House = value; CalculateHue(); InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public string Description + { + get + { + return m_Description; + } + set + { + m_Description = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public bool Marked + { + get + { + return m_Marked; + } + set + { + if ( m_Marked != value ) + { + m_Marked = value; + CalculateHue(); + InvalidateProperties(); + } + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Point3D Target + { + get + { + return m_Target; + } + set + { + m_Target = value; + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Map TargetMap + { + get + { + return m_TargetMap; + } + set + { + if ( m_TargetMap != value ) + { + m_TargetMap = value; + CalculateHue(); + InvalidateProperties(); + } + } + } + + private void CalculateHue() + { + if ( !m_Marked ) + Hue = 0; + else if ( m_TargetMap == Map.Trammel ) + Hue = (House != null ? 0x47F : 50); + else if ( m_TargetMap == Map.Felucca ) + Hue = (House != null ? 0x66D : 0); + else if ( m_TargetMap == Map.Ilshenar ) + Hue = (House != null ? 0x55F : 1102); + else if ( m_TargetMap == Map.Malas ) + Hue = (House != null ? 0x55F : 1102); + else if ( m_TargetMap == Map.Tokuno ) + Hue = (House != null ? 0x47F : 1154); + } + + public void Mark( Mobile m ) + { + m_Marked = true; + + bool setDesc = false; + if ( Core.AOS ) + { + m_House = BaseHouse.FindHouseAt( m ); + + if ( m_House == null ) + { + m_Target = m.Location; + m_TargetMap = m.Map; + } + else + { + HouseSign sign = m_House.Sign; + + if ( sign != null ) + m_Description = sign.Name; + else + m_Description = null; + + if ( m_Description == null || (m_Description = m_Description.Trim()).Length == 0 ) + m_Description = "an unnamed house"; + + setDesc = true; + + int x = m_House.BanLocation.X; + int y = m_House.BanLocation.Y + 2; + int z = m_House.BanLocation.Z; + + Map map = m_House.Map; + + if ( map != null && !map.CanFit( x, y, z, 16, false, false ) ) + z = map.GetAverageZ( x, y ); + + m_Target = new Point3D( x, y, z ); + m_TargetMap = map; + } + } + else + { + m_House = null; + m_Target = m.Location; + m_TargetMap = m.Map; + } + + if( !setDesc ) + m_Description = BaseRegion.GetRuneNameFor( Region.Find( m_Target, m_TargetMap ) ); + + CalculateHue(); + InvalidateProperties(); + } + + private const string RuneFormat = "a recall rune for {0}"; + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Marked ) + { + string desc; + + if ( (desc = m_Description) == null || (desc = desc.Trim()).Length == 0 ) + desc = "an unknown location"; + + if ( m_TargetMap == Map.Tokuno ) + list.Add( (House != null ? 1063260 : 1063259), RuneFormat, desc ); // ~1_val~ (Tokuno Islands)[(House)] + else if ( m_TargetMap == Map.Malas ) + list.Add( (House != null ? 1062454 : 1060804), RuneFormat, desc ); // ~1_val~ (Malas)[(House)] + else if ( m_TargetMap == Map.Felucca ) + list.Add( (House != null ? 1062452 : 1060805), RuneFormat, desc ); // ~1_val~ (Felucca)[(House)] + else if ( m_TargetMap == Map.Trammel ) + list.Add( (House != null ? 1062453 : 1060806), RuneFormat, desc ); // ~1_val~ (Trammel)[(House)] + else + list.Add( (House != null ? "{0} ({1})(House)" : "{0} ({1})"), String.Format( RuneFormat, desc ), m_TargetMap ); + } + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Marked ) + { + string desc; + + if ( (desc = m_Description) == null || (desc = desc.Trim()).Length == 0 ) + desc = "an unknown location"; + + if ( m_TargetMap == Map.Tokuno ) + LabelTo( from, (House != null ? 1063260 : 1063259), String.Format( RuneFormat, desc ) ); // ~1_val~ (Tokuno Islands)[(House)] + else if ( m_TargetMap == Map.Malas ) + LabelTo( from, (House != null ? 1062454 : 1060804), String.Format( RuneFormat, desc ) ); // ~1_val~ (Malas)[(House)] + else if ( m_TargetMap == Map.Felucca ) + LabelTo( from, (House != null ? 1062452 : 1060805), String.Format( RuneFormat, desc ) ); // ~1_val~ (Felucca)[(House)] + else if ( m_TargetMap == Map.Trammel ) + LabelTo( from, (House != null ? 1062453 : 1060806), String.Format( RuneFormat, desc ) ); // ~1_val~ (Trammel)[(House)] + else + LabelTo( from, (House != null ? "{0} ({1})(House)" : "{0} ({1})"), String.Format( RuneFormat, desc ), m_TargetMap ); + } + else + { + LabelTo( from, "an unmarked recall rune" ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + int number; + + if ( !IsChildOf( from.Backpack ) ) + { + number = 1042001; // That must be in your pack for you to use it. + } + else if ( House != null ) + { + number = 1062399; // You cannot edit the description for this rune. + } + else if ( m_Marked ) + { + number = 501804; // Please enter a description for this marked object. + + from.Prompt = new RenamePrompt( this ); + } + else + { + number = 501805; // That rune is not yet marked. + } + + from.SendLocalizedMessage( number ); + } + + private class RenamePrompt : Prompt + { + private RecallRune m_Rune; + + public RenamePrompt( RecallRune rune ) + { + m_Rune = rune; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Rune.House == null && m_Rune.Marked ) + { + m_Rune.Description = text; + from.SendLocalizedMessage( 1010474 ); // The etching on the rune has been changed. + } + } + } + + [Constructable] + public RecallRune() : base( 0x1F14 ) + { + Weight = 1.0; + CalculateHue(); + } + + public RecallRune( Serial serial ) : base( serial ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs b/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs new file mode 100644 index 0000000..aadf1e8 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/NecromancerSpellbook.cs @@ -0,0 +1,53 @@ +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class NecromancerSpellbook : Spellbook + { + public override SpellbookType SpellbookType{ get{ return SpellbookType.Necromancer; } } + public override int BookOffset{ get{ return 100; } } + public override int BookCount{ get{ return ((Core.SE) ? 17 : 16); } } + + [Constructable] + public NecromancerSpellbook() : this( (ulong)0 ) + { + } + + [Constructable] + public NecromancerSpellbook( ulong content ) : base( content, 0x2253 ) + { + Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid); + Lootable = false; + Stealable = false; + } + + public NecromancerSpellbook( Serial serial ) : base( serial ) + { + } + + // Scriptiz : le livre de n�cro ne peut pas quitter le sac ou le joueur + public override bool Nontransferable + { + get { return true; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 0 && Core.ML ) + Layer = Layer.OneHanded; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs new file mode 100644 index 0000000..9eee43c --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/AgilityPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AgilityPotion : BaseAgilityPotion + { + public override int DexOffset { get { return IntensifiedStrength ? 14 : 8; } } + public override TimeSpan Duration{ get{ return TimeSpan.FromMinutes( IntensifiedTime ? 2.5:1.5); } } + + [Constructable] + public AgilityPotion() : base( PotionEffect.Agility ) + { + } + + public AgilityPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs new file mode 100644 index 0000000..be64b28 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/BaseAgilityPotion.cs @@ -0,0 +1,90 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class BaseAgilityPotion : BasePotion + { + public override bool CIT { get { return true; } } + public override bool CIS { get { return true; } } + + public abstract int DexOffset { get; } + public abstract TimeSpan Duration { get; } + + public BaseAgilityPotion(PotionEffect effect) + : base(0xF08, effect) + { + } + + public BaseAgilityPotion(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public bool DoAgility(Mobile from) + { + //Plume : Addiction + if (from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + + double CurrentAddiction = drinker.CalculateAgilityAddiction(this)[0]; + double GlobalAddiction = drinker.CalculateAgilityAddiction(this)[1]; + int DexScalar = (int)Math.Floor(Math.Sqrt(CurrentAddiction)); + double DurationScalar = GlobalAddiction * 0.95; + + if (GlobalAddiction > 100) + { + drinker.SendMessage("Votre corps ne supporte plus ce traitement"); + drinker.Dex --; + this.Consume(); + return false; + } + + if ( Spells.SpellHelper.AddStatOffset( from, StatType.Dex, Scale( from, DexOffset-Math.Min(DexOffset,DexScalar)),Duration- TimeSpan.FromSeconds(DurationScalar )) ) + { + from.FixedEffect( 0x375A, 10, 15 ); + from.PlaySound( 0x1E7 ); + return true; + } + drinker.IncAddiction(this); + } + + if ( Spells.SpellHelper.AddStatOffset( from, StatType.Dex, Scale( from, DexOffset), Duration ) ) + { + from.FixedEffect( 0x375A, 10, 15 ); + from.PlaySound( 0x1E7 ); + return true; + } + + from.SendLocalizedMessage( 502173 ); // You are already under a similar effect. + return false; + } + + public override void Drink(Mobile from) + { + if (DoAgility(from)) + { + BasePotion.PlayDrinkEffect(from); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs new file mode 100644 index 0000000..2a35d86 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Agility Potions/GreaterAgilityPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterAgilityPotion : BaseAgilityPotion + { + public override int DexOffset{ get{ return IntensifiedStrength?23:17; } } + public override TimeSpan Duration{ get{ return TimeSpan.FromMinutes( IntensifiedTime?2.5:1.5 ); } } + + [Constructable] + public GreaterAgilityPotion() : base( PotionEffect.AgilityGreater ) + { + } + + public GreaterAgilityPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs b/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs new file mode 100644 index 0000000..9f30e14 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/BasePotion.cs @@ -0,0 +1,326 @@ +using System; +using Server; +using Server.Engines.Craft; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Items +{ + public enum PotionEffect + { + Nightsight, // 0 + CureLesser, // 1 + Cure, // 2 + CureGreater, // 3 + Agility, // 4 + AgilityGreater, // 5 + Strength, // 6 + StrengthGreater, // 7 + PoisonLesser, // 8 + Poison, // 9 + PoisonGreater, // 10 + PoisonDeadly, // 11 + Refresh, // 12 + RefreshTotal, // 13 + HealLesser, // 14 + Heal, // 15 + HealGreater, // 16 + ExplosionLesser, // 17 + Explosion, // 18 + ExplosionGreater, // 19 + Conflagration, // 20 + ConflagrationGreater, // 21 + MaskOfDeath, // 22 // Mask of Death is not available in OSI but does exist in cliloc files + MaskOfDeathGreater, // 23 // included in enumeration for compatability if later enabled by OSI + ConfusionBlast, // 24 + ConfusionBlastGreater, // 25 + //Ajout Myron Gender Potion + GenderSwap, // 26 + FrogMorph, // 27 + Invisibility, // 28 + Parasitic, // 29 + Darkglow, // 30 + Hallucinogen, //31 + Clumsy, + ClumsyGreater + } + + public abstract class BasePotion : Item, ICraftable, ICommodity + { + public virtual bool CIT { get { return false; } } + public virtual bool CIS { get { return false; } } + + private bool m_IntensifiedTime; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IntensifiedTime + { + get + { + return m_IntensifiedTime; + } + set + { + m_IntensifiedTime = value; + } + } + + private bool m_IntensifiedStrength; + [CommandProperty(AccessLevel.GameMaster)] + public bool IntensifiedStrength + { + get + { + return m_IntensifiedStrength; + } + set + { + m_IntensifiedStrength = value; + } + } + + private PotionEffect m_PotionEffect; + + public PotionEffect PotionEffect + { + get + { + return m_PotionEffect; + } + set + { + m_PotionEffect = value; + InvalidateProperties(); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return (Core.ML); } } + + public override int LabelNumber{ get{ return 1041314 + (int)m_PotionEffect; } } + + public BasePotion( int itemID, PotionEffect effect ) : base( itemID ) + { + m_PotionEffect = effect; + + Stackable = Core.ML; + Weight = 1.0; + } + + public BasePotion( Serial serial ) : base( serial ) + { + } + + public virtual bool RequireFreeHand{ get{ return true; } } + + public static bool HasFreeHand( Mobile m ) + { + Item handOne = m.FindItemOnLayer( Layer.OneHanded ); + Item handTwo = m.FindItemOnLayer( Layer.TwoHanded ); + + if ( handTwo is BaseWeapon ) + handOne = handTwo; + + if (handTwo is BaseRanged) + { + BaseRanged ranged = (BaseRanged)handTwo; + + if ( ranged.Balanced ) + return true; + } + + return ( handOne == null || handTwo == null ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + if (!RequireFreeHand || HasFreeHand(from)) + { + if (this is BaseExplosionPotion && Amount > 1) + { + BasePotion pot = (BasePotion)Activator.CreateInstance(this.GetType()); + + if (pot != null) + { + Amount--; + + if (from.Backpack != null && !from.Backpack.Deleted) + { + from.Backpack.DropItem(pot); + } + else + { + pot.MoveToWorld(from.Location, from.Map); + } + pot.Drink( from ); + } + } + else + { + this.Drink( from ); + } + } + else + { + from.SendLocalizedMessage(502172); // You must have a free hand to drink a potion. + } + } + else + { + from.SendLocalizedMessage( 502138 ); // That is too far away for you to use + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write((bool)m_IntensifiedTime); + writer.Write((bool)m_IntensifiedStrength); + writer.Write( (int) m_PotionEffect ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_IntensifiedTime = reader.ReadBool(); + m_IntensifiedStrength = reader.ReadBool(); + + goto case 1; + } + case 1: + case 0: + { + m_PotionEffect = (PotionEffect)reader.ReadInt(); + break; + } + } + + if( version == 0 ) + Stackable = Core.ML; + } + + public abstract void Drink(Mobile from); + + public static void PlayDrinkEffect( Mobile m ) + { + m.RevealingAction(); + + m.PlaySound( 0x2D6 ); + + #region Dueling + if (!Engines.ConPVP.DuelContext.IsFreeConsume(m)) + m.AddToBackpack(new Bottle()); + #endregion + + //m.AddToBackpack( new Bottle() ); + + if ( m.Body.IsHuman && !m.Mounted ) + m.Animate( 34, 5, 1, true, false, 0 ); + } + + public static int EnhancePotions( Mobile m ) + { + int EP = AosAttributes.GetValue( m, AosAttribute.EnhancePotions ); + int skillBonus = m.Skills.Alchemy.Fixed / 330 * 10; + + if ( Core.ML && EP > 50 && m.AccessLevel <= AccessLevel.Player ) + EP = 50; + + return ( EP + skillBonus ); + } + + public static TimeSpan Scale( Mobile m, TimeSpan v ) + { + if ( !Core.AOS ) + return v; + + double scalar = 1.0 + ( 0.01 * EnhancePotions( m ) ); + + return TimeSpan.FromSeconds( v.TotalSeconds * scalar ); + } + + public static double Scale( Mobile m, double v ) + { + if ( !Core.AOS ) + return v; + + double scalar = 1.0 + ( 0.01 * EnhancePotions( m ) ); + + return v * scalar; + } + + public static int Scale( Mobile m, int v ) + { + if ( !Core.AOS ) + return v; + + return AOS.Scale( v, 100 + EnhancePotions( m ) ); + } + + public override bool StackWith( Mobile from, Item dropped, bool playSound ) + { + if( dropped is BasePotion && ((BasePotion)dropped).m_PotionEffect == m_PotionEffect ) + return base.StackWith( from, dropped, playSound ); + + return false; + } + + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + if ( craftSystem is DefAlchemy ) + { + Container pack = from.Backpack; + + if ( pack != null ) + { + if ((int)PotionEffect >= (int)PotionEffect.Invisibility) + return 1; + + List kegs = pack.FindItemsByType(); + + for ( int i = 0; i < kegs.Count; ++i ) + { + PotionKeg keg = kegs[i]; + + if ( keg == null ) + continue; + + if ( keg.Held <= 0 || keg.Held >= 100 ) + continue; + + if ( keg.Type != PotionEffect ) + continue; + + ++keg.Held; + + Consume(); + from.AddToBackpack( new Bottle() ); + + return -1; // signal placed in keg + } + } + } + + return 1; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs new file mode 100644 index 0000000..09f578c --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/BaseConflagrationPotion.cs @@ -0,0 +1,347 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Spells; + +namespace Server.Items +{ + public abstract class BaseConflagrationPotion : BasePotion + { + public abstract int MinDamage{ get; } + public abstract int MaxDamage{ get; } + + public override bool RequireFreeHand{ get{ return false; } } + + public BaseConflagrationPotion( PotionEffect effect ) : base( 0xF06, effect ) + { + Hue = 0x489; + } + + public BaseConflagrationPotion( Serial serial ) : base( serial ) + { + } + + public override void Drink( Mobile from ) + { + if ( Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting)) ) + { + from.SendLocalizedMessage( 1062725 ); // You can not use that potion while paralyzed. + return; + } + + int delay = GetDelay( from ); + + if ( delay > 0 ) + { + from.SendLocalizedMessage( 1072529, String.Format( "{0}\t{1}", delay, delay > 1 ? "seconds." : "second." ) ); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ + return; + } + + ThrowTarget targ = from.Target as ThrowTarget; + + if ( targ != null && targ.Potion == this ) + return; + + from.RevealingAction(); + + if ( !m_Users.Contains( from ) ) + m_Users.Add( from ); + + from.Target = new ThrowTarget( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private List m_Users = new List(); + + public void Explode_Callback( object state ) + { + object[] states = (object[]) state; + + Explode( (Mobile) states[ 0 ], (Point3D) states[ 1 ], (Map) states[ 2 ] ); + } + + public virtual void Explode( Mobile from, Point3D loc, Map map ) + { + if ( Deleted || map == null ) + return; + + Consume(); + + // Check if any other players are using this potion + for ( int i = 0; i < m_Users.Count; i ++ ) + { + ThrowTarget targ = m_Users[ i ].Target as ThrowTarget; + + if ( targ != null && targ.Potion == this ) + Target.Cancel( from ); + } + + // Effects + Effects.PlaySound( loc, map, 0x20C ); + + for ( int i = -2; i <= 2; i ++ ) + { + for ( int j = -2; j <= 2; j ++ ) + { + Point3D p = new Point3D( loc.X + i, loc.Y + j, loc.Z ); + + if ( map.CanFit( p, 12, true, false ) && from.InLOS( p ) ) + new InternalItem( from, p, map, MinDamage, MaxDamage ); + } + } + } + + #region Delay + private static Hashtable m_Delay = new Hashtable(); + + public static void AddDelay( Mobile m ) + { + Timer timer = m_Delay[ m ] as Timer; + + if ( timer != null ) + timer.Stop(); + + m_Delay[ m ] = Timer.DelayCall( TimeSpan.FromSeconds( 30 ), new TimerStateCallback( EndDelay_Callback ), m ); + } + + public static int GetDelay( Mobile m ) + { + Timer timer = m_Delay[ m ] as Timer; + + if ( timer != null && timer.Next > DateTime.Now ) + return (int) (timer.Next - DateTime.Now).TotalSeconds; + + return 0; + } + + private static void EndDelay_Callback( object obj ) + { + if ( obj is Mobile ) + EndDelay( (Mobile) obj ); + } + + public static void EndDelay( Mobile m ) + { + Timer timer = m_Delay[ m ] as Timer; + + if ( timer != null ) + { + timer.Stop(); + m_Delay.Remove( m ); + } + } + #endregion + + private class ThrowTarget : Target + { + private BaseConflagrationPotion m_Potion; + + public BaseConflagrationPotion Potion + { + get{ return m_Potion; } + } + + public ThrowTarget( BaseConflagrationPotion potion ) : base( 12, true, TargetFlags.None ) + { + m_Potion = potion; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Potion.Deleted || m_Potion.Map == Map.Internal ) + return; + + IPoint3D p = targeted as IPoint3D; + + if ( p == null || from.Map == null ) + return; + + // Add delay + BaseConflagrationPotion.AddDelay( from ); + + SpellHelper.GetSurfaceTop( ref p ); + + from.RevealingAction(); + + IEntity to; + + if ( p is Mobile ) + to = (Mobile)p; + else + to = new Entity( Serial.Zero, new Point3D( p ), from.Map ); + + Effects.SendMovingEffect( from, to, 0xF0D, 7, 0, false, false, m_Potion.Hue, 0 ); + Timer.DelayCall( TimeSpan.FromSeconds( 1.5 ), new TimerStateCallback( m_Potion.Explode_Callback ), new object[] { from, new Point3D( p ), from.Map } ); + } + } + + public class InternalItem : Item + { + private Mobile m_From; + private int m_MinDamage; + private int m_MaxDamage; + private DateTime m_End; + private Timer m_Timer; + + public Mobile From{ get{ return m_From; } } + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Mobile from, Point3D loc, Map map, int min, int max ) : base( 0x398C ) + { + Movable = false; + Light = LightType.Circle300; + + MoveToWorld( loc, map ); + + m_From = from; + m_End = DateTime.Now + TimeSpan.FromSeconds( 10 ); + + SetDamage( min, max ); + + m_Timer = new InternalTimer( this, m_End ); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public int GetDamage(){ return Utility.RandomMinMax( m_MinDamage, m_MaxDamage ); } + + private void SetDamage( int min, int max ) + { + /* new way to apply alchemy bonus according to Stratics' calculator. + this gives a mean to values 25, 50, 75 and 100. Stratics' calculator is outdated. + Those goals will give 2 to alchemy bonus. It's not really OSI-like but it's an approximation. */ + + m_MinDamage = min; + m_MaxDamage = max; + + if( m_From == null ) + return; + + int alchemySkill = m_From.Skills.Alchemy.Fixed; + int alchemyBonus = alchemySkill / 125 + alchemySkill / 250 ; + + m_MinDamage = Scale( m_From, m_MinDamage + alchemyBonus ); + m_MaxDamage = Scale( m_From, m_MaxDamage + alchemyBonus ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_From ); + writer.Write( (DateTime) m_End ); + writer.Write( (int) m_MinDamage ); + writer.Write( (int) m_MaxDamage ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_From = reader.ReadMobile(); + m_End = reader.ReadDateTime(); + m_MinDamage = reader.ReadInt(); + m_MaxDamage = reader.ReadInt(); + + m_Timer = new InternalTimer( this, m_End ); + m_Timer.Start(); + } + + public override bool OnMoveOver( Mobile m ) + { + if ( Visible && m_From != null && (!Core.AOS || m != m_From) && SpellHelper.ValidIndirectTarget( m_From, m ) && m_From.CanBeHarmful( m, false ) ) + { + m_From.DoHarmful( m ); + + AOS.Damage( m, m_From, GetDamage(), 0, 100, 0, 0, 0 ); + m.PlaySound( 0x208 ); + } + + return true; + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + private DateTime m_End; + + public InternalTimer( InternalItem item, DateTime end ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) ) + { + m_Item = item; + m_End = end; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Item.Deleted ) + return; + + if ( DateTime.Now > m_End ) + { + m_Item.Delete(); + Stop(); + return; + } + + Mobile from = m_Item.From; + + if ( m_Item.Map == null || from == null ) + return; + + List mobiles = new List(); + + foreach( Mobile mobile in m_Item.GetMobilesInRange( 0 ) ) + mobiles.Add( mobile ); + + for( int i = 0; i < mobiles.Count; i++ ) + { + Mobile m = mobiles[i]; + + if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && (!Core.AOS || m != from) && SpellHelper.ValidIndirectTarget( from, m ) && from.CanBeHarmful( m, false ) ) + { + if ( from != null ) + from.DoHarmful( m ); + + AOS.Damage( m, from, m_Item.GetDamage(), 0, 100, 0, 0, 0 ); + m.PlaySound( 0x208 ); + } + } + } + } + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs new file mode 100644 index 0000000..3b0e069 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/ConflagrationPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ConflagrationPotion : BaseConflagrationPotion + { + public override int MinDamage{ get{ return 2; } } + public override int MaxDamage{ get{ return 4; } } + + public override int LabelNumber{ get{ return 1072095; } } // a Conflagration potion + + [Constructable] + public ConflagrationPotion() : base( PotionEffect.Conflagration ) + { + } + + public ConflagrationPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs new file mode 100644 index 0000000..46bbf06 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Conflagration Potions/GreaterConflagrationPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterConflagrationPotion : BaseConflagrationPotion + { + public override int MinDamage{ get{ return 4; } } + public override int MaxDamage{ get{ return 8; } } + + public override int LabelNumber{ get{ return 1072098; } } // a Greater Conflagration potion + + [Constructable] + public GreaterConflagrationPotion() : base( PotionEffect.ConflagrationGreater ) + { + } + + public GreaterConflagrationPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs new file mode 100644 index 0000000..e4a97ce --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/BaseConfusionBlastPotion.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Spells; +using Server.Mobiles; +using Server.Misc; + +namespace Server.Items +{ + public abstract class BaseConfusionBlastPotion : BasePotion + { + public abstract int Radius{ get; } + + public override bool RequireFreeHand{ get{ return false; } } + + public BaseConfusionBlastPotion( PotionEffect effect ) : base( 0xF06, effect ) + { + Hue = 0x48D; + } + + public BaseConfusionBlastPotion( Serial serial ) : base( serial ) + { + } + + public override void Drink( Mobile from ) + { + if ( Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting)) ) + { + from.SendLocalizedMessage( 1062725 ); // You can not use that potion while paralyzed. + return; + } + + int delay = GetDelay( from ); + + if ( delay > 0 ) + { + from.SendLocalizedMessage( 1072529, String.Format( "{0}\t{1}", delay, delay > 1 ? "seconds." : "second." ) ); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ + return; + } + + ThrowTarget targ = from.Target as ThrowTarget; + + if ( targ != null && targ.Potion == this ) + return; + + from.RevealingAction(); + + if ( !m_Users.Contains( from ) ) + m_Users.Add( from ); + + from.Target = new ThrowTarget( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private List m_Users = new List(); + + public void Explode_Callback( object state ) + { + object[] states = (object[]) state; + + Explode( (Mobile) states[ 0 ], (Point3D) states[ 1 ], (Map) states[ 2 ] ); + } + + public virtual void Explode( Mobile from, Point3D loc, Map map ) + { + if ( Deleted || map == null ) + return; + + Consume(); + + // Check if any other players are using this potion + for ( int i = 0; i < m_Users.Count; i ++ ) + { + ThrowTarget targ = m_Users[ i ].Target as ThrowTarget; + + if ( targ != null && targ.Potion == this ) + Target.Cancel( from ); + } + + // Effects + Effects.PlaySound( loc, map, 0x207 ); + + Geometry.Circle2D( loc, map, Radius, new DoEffect_Callback( BlastEffect ), 270, 90 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 0.3 ), new TimerStateCallback( CircleEffect2 ), new object[] { loc, map } ); + + foreach ( Mobile mobile in map.GetMobilesInRange( loc, Radius ) ) + { + if (mobile is BaseCreature) + { + BaseCreature mon = (BaseCreature) mobile; + + if (mon.Controlled || mon.Summoned) + continue; + + mon.Pacify( from, DateTime.Now + TimeSpan.FromSeconds( 5.0 ) ); // TODO check + } + } + } + + #region Effects + public virtual void BlastEffect( Point3D p, Map map ) + { + if ( map.CanFit( p, 12, true, false ) ) + Effects.SendLocationEffect( p, map, 0x376A, 4, 9 ); + } + + public void CircleEffect2( object state ) + { + object[] states = (object[]) state; + + Geometry.Circle2D( (Point3D)states[0], (Map)states[1], Radius, new DoEffect_Callback( BlastEffect ), 90, 270 ); + } + #endregion + + #region Delay + private static Hashtable m_Delay = new Hashtable(); + + public static void AddDelay( Mobile m ) + { + Timer timer = m_Delay[ m ] as Timer; + + if ( timer != null ) + timer.Stop(); + + m_Delay[ m ] = Timer.DelayCall( TimeSpan.FromSeconds( 60 ), new TimerStateCallback( EndDelay_Callback ), m ); + } + + public static int GetDelay( Mobile m ) + { + Timer timer = m_Delay[ m ] as Timer; + + if ( timer != null && timer.Next > DateTime.Now ) + return (int) (timer.Next - DateTime.Now).TotalSeconds; + + return 0; + } + + private static void EndDelay_Callback( object obj ) + { + if ( obj is Mobile ) + EndDelay( (Mobile) obj ); + } + + public static void EndDelay( Mobile m ) + { + Timer timer = m_Delay[ m ] as Timer; + + if ( timer != null ) + { + timer.Stop(); + m_Delay.Remove( m ); + } + } + #endregion + + private class ThrowTarget : Target + { + private BaseConfusionBlastPotion m_Potion; + + public BaseConfusionBlastPotion Potion + { + get{ return m_Potion; } + } + + public ThrowTarget( BaseConfusionBlastPotion potion ) : base( 12, true, TargetFlags.None ) + { + m_Potion = potion; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Potion.Deleted || m_Potion.Map == Map.Internal ) + return; + + IPoint3D p = targeted as IPoint3D; + + if ( p == null || from.Map == null ) + return; + + // Add delay + BaseConfusionBlastPotion.AddDelay( from ); + + SpellHelper.GetSurfaceTop( ref p ); + + from.RevealingAction(); + + IEntity to; + + if ( p is Mobile ) + to = (Mobile)p; + else + to = new Entity( Serial.Zero, new Point3D( p ), from.Map ); + + Effects.SendMovingEffect( from, to, 0xF0D, 7, 0, false, false, m_Potion.Hue, 0 ); + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( m_Potion.Explode_Callback ), new object[] { from, new Point3D( p ), from.Map } ); + } + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs new file mode 100644 index 0000000..bd8ddb8 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/ConfusionBlastPotion.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ConfusionBlastPotion : BaseConfusionBlastPotion + { + public override int Radius{ get{ return 5; } } + + public override int LabelNumber{ get{ return 1072105; } } // a Confusion Blast potion + + [Constructable] + public ConfusionBlastPotion() : base( PotionEffect.ConfusionBlast ) + { + } + + public ConfusionBlastPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs new file mode 100644 index 0000000..6e36986 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Confusion Blast Potions/GreaterConfusionBlastPotion.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterConfusionBlastPotion : BaseConfusionBlastPotion + { + public override int Radius{ get{ return 7; } } + + public override int LabelNumber{ get{ return 1072108; } } // a Greater Confusion Blast potion + + [Constructable] + public GreaterConfusionBlastPotion() : base( PotionEffect.ConfusionBlastGreater ) + { + } + + public GreaterConfusionBlastPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs new file mode 100644 index 0000000..bc07390 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/BaseCurePotion.cs @@ -0,0 +1,164 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Items +{ + public class CureLevelInfo + { + private Poison m_Poison; + private double m_Chance; + + public Poison Poison + { + get{ return m_Poison; } + } + + public double Chance + { + get{ return m_Chance; } + } + + public CureLevelInfo( Poison poison, double chance ) + { + m_Poison = poison; + m_Chance = chance; + } + } + + public abstract class BaseCurePotion : BasePotion + { + public override bool CIT { get { return false; } } + public override bool CIS { get { return true; } } + + public abstract CureLevelInfo[] LevelInfo{ get; } + + public BaseCurePotion( PotionEffect effect ) : base( 0xF07, effect ) + { + } + + public BaseCurePotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public void DoCure(Mobile from, double scalar) + { + bool cure = false; + + CureLevelInfo[] info = LevelInfo; + + for (int i = 0; i < info.Length; ++i) + { + CureLevelInfo li = info[i]; + + if (li.Poison == from.Poison && Scale(from, li.Chance - (int)Math.Floor(li.Chance * scalar) + (IntensifiedStrength ? 0.1 : 0)) > Utility.RandomDouble()) + { + cure = true; + break; + } + } + + if (cure && from.CurePoison(from)) + { + from.SendLocalizedMessage(500231); // You feel cured of poison! + + from.FixedEffect(0x373A, 10, 15); + from.PlaySound(0x1E0); + } + else if (!cure) + { + from.SendLocalizedMessage(500232); // That potion was not strong enough to cure your ailment! + } + } + + public void DoCure( Mobile from ) + { + bool cure = false; + + CureLevelInfo[] info = LevelInfo; + + for ( int i = 0; i < info.Length; ++i ) + { + CureLevelInfo li = info[i]; + + if (li.Poison == from.Poison && Scale(from, li.Chance + (IntensifiedStrength ? 0.1 : 0)) > Utility.RandomDouble()) + { + cure = true; + break; + } + } + + if ( cure && from.CurePoison( from ) ) + { + from.SendLocalizedMessage( 500231 ); // You feel cured of poison! + + from.FixedEffect( 0x373A, 10, 15 ); + from.PlaySound( 0x1E0 ); + } + else if ( !cure ) + { + from.SendLocalizedMessage( 500232 ); // That potion was not strong enough to cure your ailment! + } + } + + public override void Drink( Mobile from ) + { + if ( TransformationSpellHelper.UnderTransformation( from, typeof( Spells.Necromancy.VampiricEmbraceSpell ) ) ) + { + from.SendLocalizedMessage( 1061652 ); // The garlic in the potion would surely kill you. + } + else if ( from.Poisoned ) + { + + //Plume : Addiction + if (from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + + double Addiction = drinker.CalculateCureAddiction(this); + + if (Addiction > 100) + { + drinker.SendMessage("Votre corps ne supporte plus ce traitement"); + AOS.Damage(drinker,15, true,0,0,0,100,0); + } + else + { + double CureScalar = Addiction / 100 * 0.95; + DoCure(from, CureScalar); + } + drinker.IncAddiction(this); + } + else + DoCure( from ); + + BasePotion.PlayDrinkEffect( from ); + + from.FixedParticles( 0x373A, 10, 15, 5012, EffectLayer.Waist ); + from.PlaySound( 0x1E0 ); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + } + else + { + from.SendLocalizedMessage( 1042000 ); // You are not poisoned. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs new file mode 100644 index 0000000..8c17e7e --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/CurePotion.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CurePotion : BaseCurePotion + { + private static CureLevelInfo[] m_OldLevelInfo = new CureLevelInfo[] + { + new CureLevelInfo( Poison.Lesser, 1.00 ), // 100% chance to cure lesser poison + new CureLevelInfo( Poison.Regular, 0.75 ), // 75% chance to cure regular poison + new CureLevelInfo( Poison.Greater, 0.50 ), // 50% chance to cure greater poison + new CureLevelInfo( Poison.Deadly, 0.15 ) // 15% chance to cure deadly poison + }; + + private static CureLevelInfo[] m_AosLevelInfo = new CureLevelInfo[] + { + new CureLevelInfo( Poison.Lesser, 0.95 ), + new CureLevelInfo( Poison.Regular, 0.75 ), + new CureLevelInfo( Poison.Greater, 0.55 ), + new CureLevelInfo( Poison.Deadly, 0.35 ), + new CureLevelInfo( Poison.Lethal, 0.05 ) + }; + + public override CureLevelInfo[] LevelInfo{ get{ return Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; } } + + [Constructable] + public CurePotion() : base( PotionEffect.Cure ) + { + } + + public CurePotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs new file mode 100644 index 0000000..7640e0a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/GreaterCurePotion.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterCurePotion : BaseCurePotion + { + private static CureLevelInfo[] m_OldLevelInfo = new CureLevelInfo[] + { + new CureLevelInfo( Poison.Lesser, 1.00 ), // 100% chance to cure lesser poison + new CureLevelInfo( Poison.Regular, 1.00 ), // 100% chance to cure regular poison + new CureLevelInfo( Poison.Greater, 1.00 ), // 100% chance to cure greater poison + new CureLevelInfo( Poison.Deadly, 0.75 ), // 75% chance to cure deadly poison + new CureLevelInfo( Poison.Lethal, 0.25 ) // 25% chance to cure lethal poison + }; + + private static CureLevelInfo[] m_AosLevelInfo = new CureLevelInfo[] + { + new CureLevelInfo( Poison.Lesser, 0.95 ), + new CureLevelInfo( Poison.Regular, 0.95 ), + new CureLevelInfo( Poison.Greater, 0.95 ), + new CureLevelInfo( Poison.Deadly, 0.70 ), + new CureLevelInfo( Poison.Lethal, 0.50 ) + }; + + public override CureLevelInfo[] LevelInfo{ get{ return Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; } } + + [Constructable] + public GreaterCurePotion() : base( PotionEffect.CureGreater ) + { + } + + public GreaterCurePotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs new file mode 100644 index 0000000..c7f6a18 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Cure Potions/LesserCurePotion.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LesserCurePotion : BaseCurePotion + { + private static CureLevelInfo[] m_OldLevelInfo = new CureLevelInfo[] + { + new CureLevelInfo( Poison.Lesser, 0.75 ), // 75% chance to cure lesser poison + new CureLevelInfo( Poison.Regular, 0.50 ), // 50% chance to cure regular poison + new CureLevelInfo( Poison.Greater, 0.15 ) // 15% chance to cure greater poison + }; + + private static CureLevelInfo[] m_AosLevelInfo = new CureLevelInfo[] + { + new CureLevelInfo( Poison.Lesser, 0.70 ), + new CureLevelInfo( Poison.Regular, 0.40 ), + new CureLevelInfo( Poison.Greater, 0.10 ), + new CureLevelInfo( Poison.Deadly, 0.00 ), + }; + + public override CureLevelInfo[] LevelInfo{ get{ return Core.AOS ? m_AosLevelInfo : m_OldLevelInfo; } } + + [Constructable] + public LesserCurePotion() : base( PotionEffect.CureLesser ) + { + } + + public LesserCurePotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/DarkglowPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/DarkglowPotion.cs new file mode 100644 index 0000000..9ccbcde --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/DarkglowPotion.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DarkglowPotion : BasePoisonPotion + { + public override Poison Poison{ get{ return Poison.Greater; } } /* MUST be restored when prerequisites are done */ + + public override double MinPoisoningSkill{ get{ return 95.0; } } + public override double MaxPoisoningSkill{ get{ return 100.0; } } + + public override int LabelNumber{ get{ return 1072849; } } // Darkglow Poison + + [Constructable] + public DarkglowPotion() : base( PotionEffect.Darkglow ) + { + Hue = 0x96; + } + + public DarkglowPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs new file mode 100644 index 0000000..7e5d032 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Spells; + +namespace Server.Items +{ + public abstract class BaseExplosionPotion : BasePotion + { + public abstract int MinDamage { get; } + public abstract int MaxDamage { get; } + + public override bool RequireFreeHand{ get{ return false; } } + + //Explosion en ligne activ�e + private static bool LeveledExplosion = true; // Should explosion potions explode other nearby potions? + private static bool InstantExplosion = false; // Should explosion potions explode on impact? + private static bool RelativeLocation = false; // Is the explosion target location relative for mobiles? + private const int ExplosionRange = 2; // How long is the blast radius? + + public BaseExplosionPotion( PotionEffect effect ) : base( 0xF0D, effect ) + { + } + + public BaseExplosionPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public virtual object FindParent( Mobile from ) + { + Mobile m = this.HeldBy; + + if ( m != null && m.Holding == this ) + return m; + + object obj = this.RootParent; + + if ( obj != null ) + return obj; + + if ( Map == Map.Internal ) + return from; + + return this; + } + + private Timer m_Timer; + + private ArrayList m_Users; + + public override void Drink( Mobile from ) + { + if ( Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting)) ) + { + from.SendLocalizedMessage( 1062725 ); // You can not use a purple potion while paralyzed. + return; + } + + ThrowTarget targ = from.Target as ThrowTarget; + this.Stackable = false; // Scavenged explosion potions won't stack with those ones in backpack, and still will explode. + + if ( targ != null && targ.Potion == this ) + return; + + from.RevealingAction(); + + if ( m_Users == null ) + m_Users = new ArrayList(); + + if ( !m_Users.Contains( from ) ) + m_Users.Add( from ); + + from.Target = new ThrowTarget( this ); + + if ( m_Timer == null ) + { + from.SendLocalizedMessage( 500236 ); // You should throw it now! + + if( Core.ML ) + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.25 ), 5, new TimerStateCallback( Detonate_OnTick ), new object[]{ from, 3 } ); // 3.6 seconds explosion delay + else + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 0.75 ), TimeSpan.FromSeconds( 1.0 ), 4, new TimerStateCallback( Detonate_OnTick ), new object[]{ from, 3 } ); // 2.6 seconds explosion delay + } + } + + private void Detonate_OnTick( object state ) + { + if ( Deleted ) + return; + + object[] states = (object[])state; + Mobile from = (Mobile)states[0]; + int timer = (int)states[1]; + + object parent = FindParent( from ); + + if ( timer == 0 ) + { + Point3D loc; + Map map; + + if ( parent is Item ) + { + Item item = (Item)parent; + + loc = item.GetWorldLocation(); + map = item.Map; + } + else if ( parent is Mobile ) + { + Mobile m = (Mobile)parent; + + loc = m.Location; + map = m.Map; + } + else + { + return; + } + + Explode( from, true, loc, map ); + m_Timer = null; + } + else + { + if ( parent is Item ) + ((Item)parent).PublicOverheadMessage( MessageType.Regular, 0x22, false, timer.ToString() ); + else if ( parent is Mobile ) + ((Mobile)parent).PublicOverheadMessage( MessageType.Regular, 0x22, false, timer.ToString() ); + + states[1] = timer - 1; + } + } + + private void Reposition_OnTick( object state ) + { + if ( Deleted ) + return; + + object[] states = (object[])state; + Mobile from = (Mobile)states[0]; + IPoint3D p = (IPoint3D)states[1]; + Map map = (Map)states[2]; + + Point3D loc = new Point3D( p ); + + if ( InstantExplosion ) + Explode( from, true, loc, map ); + else + MoveToWorld( loc, map ); + } + + private class ThrowTarget : Target + { + private BaseExplosionPotion m_Potion; + + public BaseExplosionPotion Potion + { + get{ return m_Potion; } + } + + public ThrowTarget( BaseExplosionPotion potion ) : base( 12, true, TargetFlags.None ) + { + m_Potion = potion; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Potion.Deleted || m_Potion.Map == Map.Internal ) + return; + + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + + Map map = from.Map; + + if ( map == null ) + return; + + SpellHelper.GetSurfaceTop( ref p ); + + from.RevealingAction(); + + IEntity to; + + to = new Entity( Serial.Zero, new Point3D( p ), map ); + + if( p is Mobile ) + { + if( !RelativeLocation ) // explosion location = current mob location. + p = ((Mobile)p).Location; + else + to = (Mobile)p; + } + + Effects.SendMovingEffect( from, to, m_Potion.ItemID, 7, 0, false, false, m_Potion.Hue, 0 ); + + if( m_Potion.Amount > 1 ) + { + Mobile.LiftItemDupe( m_Potion, 1 ); + } + + m_Potion.Internalize(); + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( m_Potion.Reposition_OnTick ), new object[]{ from, p, map } ); + } + } + + public void Explode( Mobile from, bool direct, Point3D loc, Map map ) + { + if ( Deleted ) + return; + + Consume(); + + for ( int i = 0; m_Users != null && i < m_Users.Count; ++i ) + { + Mobile m = (Mobile)m_Users[i]; + ThrowTarget targ = m.Target as ThrowTarget; + + if ( targ != null && targ.Potion == this ) + Target.Cancel( m ); + } + + if ( map == null ) + return; + + Effects.PlaySound(loc, map, 0x307); + + Effects.SendLocationEffect(loc, map, 0x36B0, 9, 10, 0, 0); + int alchemyBonus = 0; + + if ( direct ) + alchemyBonus = (int)(from.Skills.Alchemy.Value / (Core.AOS ? 5 : 10)); + + IPooledEnumerable eable = LeveledExplosion ? map.GetObjectsInRange( loc, ExplosionRange ) : map.GetMobilesInRange( loc, ExplosionRange ); + ArrayList toExplode = new ArrayList(); + + int toDamage = 0; + + foreach ( object o in eable ) + { + //Plume : Les joueurs peuvent se blesser + if (o is Mobile && (from == null || (((Mobile)o).AccessLevel <= from.AccessLevel && from.CanBeHarmful((Mobile)o, false)))) + { + toExplode.Add( o ); + ++toDamage; + } + else if ( o is BaseExplosionPotion && o != this ) + { + toExplode.Add( o ); + } + } + + eable.Free(); + + int min = Scale( from, MinDamage ); + int max = Scale( from, MaxDamage ); + + for ( int i = 0; i < toExplode.Count; ++i ) + { + object o = toExplode[i]; + + if ( o is Mobile ) + { + Mobile m = (Mobile)o; + + if ( from != null ) + from.DoHarmful( m ); + + int damage = Utility.RandomMinMax( min, max ); + + damage += alchemyBonus; + + if ( !Core.AOS && damage > 40 ) + damage = 40; + else if ( Core.AOS && toDamage > 2 ) + damage /= toDamage - 1; + + AOS.Damage( m, from, damage, 0, 100, 0, 0, 0 ); + } + else if ( o is BaseExplosionPotion ) + { + BaseExplosionPotion pot = (BaseExplosionPotion)o; + + pot.Explode( from, false, pot.GetWorldLocation(), pot.Map ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs new file mode 100644 index 0000000..f119b1f --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/ExplosionPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ExplosionPotion : BaseExplosionPotion + { + public override int MinDamage { get { return 10; } } + public override int MaxDamage { get { return 20; } } + + [Constructable] + public ExplosionPotion() : base( PotionEffect.Explosion ) + { + } + + public ExplosionPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs new file mode 100644 index 0000000..450cfe3 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/GreaterExplosionPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterExplosionPotion : BaseExplosionPotion + { + public override int MinDamage { get { return Core.AOS ? 20 : 15; } } + public override int MaxDamage { get { return Core.AOS ? 40 : 30; } } + + [Constructable] + public GreaterExplosionPotion() : base( PotionEffect.ExplosionGreater ) + { + } + + public GreaterExplosionPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs new file mode 100644 index 0000000..c954073 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Explosion Potions/LesserExplosionPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LesserExplosionPotion : BaseExplosionPotion + { + public override int MinDamage { get { return 5; } } + public override int MaxDamage { get { return 10; } } + + [Constructable] + public LesserExplosionPotion() : base( PotionEffect.ExplosionLesser ) + { + } + + public LesserExplosionPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs new file mode 100644 index 0000000..10644b0 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/BaseHealPotion.cs @@ -0,0 +1,115 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseHealPotion : BasePotion + { + public override bool CIT { get { return false; } } + public override bool CIS { get { return true; } } + + public abstract int MinHeal { get; } + public abstract int MaxHeal { get; } + public abstract double Delay { get; } + + public BaseHealPotion(PotionEffect effect) + : base(0xF0C, effect) + { + } + + public BaseHealPotion(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public void DoHeal(Mobile from) + { + int min = Scale(from, MinHeal); + int max = Scale(from, MaxHeal); + + from.Heal(Utility.RandomMinMax(min, max) + (IntensifiedStrength ? 5 : 0)); + } + + public void DoHeal(Mobile from, double scalar) + { + int min = Scale(from, MinHeal - (int)Math.Floor(MinHeal * scalar)); + int max = Scale(from, MaxHeal - (int)Math.Floor(MaxHeal * scalar)); + + from.Heal(Utility.RandomMinMax(min, max)+(IntensifiedStrength?5:0)); + } + + public override void Drink(Mobile from) + { + if (from.Hits < from.HitsMax) + { + if (from.Poisoned || MortalStrike.IsWounded(from)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x22, 1005000); // You can not heal yourself in your current state. + } + else + { + if (from.BeginAction(typeof(BaseHealPotion))) + { + //Plume : Addiction + if (from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + + double Addiction = drinker.CalculateHealAddiction(this); + + if(Addiction > 100) + { + drinker.SendMessage("Votre corps ne supporte plus ce traitement"); + drinker.Poison = Poison.Lesser; + } + else + { + double HealScalar = Addiction/100 * 0.95; + DoHeal(from, HealScalar); + } + drinker.IncAddiction(this); + } + else + DoHeal(from); + + BasePotion.PlayDrinkEffect(from); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + + Timer.DelayCall(TimeSpan.FromSeconds(Delay), new TimerStateCallback(ReleaseHealLock), from); + } + else + { + from.LocalOverheadMessage(MessageType.Regular, 0x22, 500235); // You must wait 10 seconds before using another healing potion. + } + } + } + else + { + from.SendLocalizedMessage(1049547); // You decide against drinking this potion, as you are already at full health. + } + } + + private static void ReleaseHealLock(object state) + { + ((Mobile)state).EndAction(typeof(BaseHealPotion)); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs new file mode 100644 index 0000000..320d880 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/GreaterHealPotion.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterHealPotion : BaseHealPotion + { + public override int MinHeal { get { return (Core.AOS ? 20 : 9); } } + public override int MaxHeal { get { return (Core.AOS ? 25 : 30); } } + public override double Delay{ get{ return 10.0; } } + + [Constructable] + public GreaterHealPotion() : base( PotionEffect.HealGreater ) + { + } + + public GreaterHealPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs new file mode 100644 index 0000000..7cab6da --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/HealPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HealPotion : BaseHealPotion + { + + public override int MinHeal { get { return (Core.AOS ? 13 : 6); } } + public override int MaxHeal { get { return (Core.AOS ? 16 : 20); } } + public override double Delay{ get{ return (Core.AOS ? 8.0 : 10.0); } } + + [Constructable] + public HealPotion() : base( PotionEffect.Heal ) + { + } + + public HealPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs new file mode 100644 index 0000000..634a033 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Heal Potions/LesserHealPotion.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LesserHealPotion : BaseHealPotion + { + public override int MinHeal { get { return (Core.AOS ? 6 : 3); } } + public override int MaxHeal { get { return (Core.AOS ? 8 : 10); } } + public override double Delay{ get{ return (Core.AOS ? 3.0 : 10.0); } } + + [Constructable] + public LesserHealPotion() : base( PotionEffect.HealLesser ) + { + } + + public LesserHealPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs new file mode 100644 index 0000000..0ef1c50 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/InvisibilityPotion.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Items +{ + public class InvisibilityPotion : BasePotion + { + public override int LabelNumber{ get{ return 1072941; } } // Potion of Invisibility + + [Constructable] + public InvisibilityPotion() : base( 0xF0A, PotionEffect.Invisibility ) + { + Hue = 0x48D; + } + + public InvisibilityPotion( Serial serial ) : base( serial ) + { + } + + public override void Drink( Mobile from ) + { + if ( from.Hidden ) + { + from.SendLocalizedMessage( 1073185 ); // You are already unseen. + return; + } + + if ( HasTimer( from ) ) + { + from.SendLocalizedMessage( 1073186 ); // An invisibility potion is already taking effect on your person. + return; + } + + Consume(); + m_Table[ from ] = Timer.DelayCall( TimeSpan.FromSeconds( 2 ), new TimerStateCallback( Hide_Callback ), from ); + PlayDrinkEffect( from ); + } + + private static void Hide_Callback( object obj ) + { + if ( obj is Mobile ) + Hide( (Mobile) obj ); + } + + public static void Hide( Mobile m ) + { + Effects.SendLocationParticles( EffectItem.Create( new Point3D( m.X, m.Y, m.Z + 16 ), m.Map, EffectItem.DefaultDuration ), 0x376A, 10, 15, 5045 ); + m.PlaySound( 0x3C4 ); + + m.Hidden = true; + + BuffInfo.RemoveBuff( m, BuffIcon.HidingAndOrStealth ); + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Invisibility, 1075825 ) ); //Invisibility/Invisible + + RemoveTimer( m ); + + Timer.DelayCall( TimeSpan.FromSeconds( 30 ), new TimerStateCallback( EndHide_Callback ), m ); + } + + private static void EndHide_Callback( object obj ) + { + if ( obj is Mobile ) + EndHide( (Mobile) obj ); + } + + public static void EndHide( Mobile m ) + { + m.RevealingAction(); + RemoveTimer( m ); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool HasTimer( Mobile m ) + { + return m_Table[ m ] != null; + } + + public static void RemoveTimer( Mobile m ) + { + Timer t = (Timer) m_Table[ m ]; + + if ( t != null ) + { + t.Stop(); + m_Table.Remove( m ); + } + } + + public static void Iterrupt( Mobile m ) + { + m.SendLocalizedMessage( 1073187 ); // The invisibility effect is interrupted. + RemoveTimer( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs b/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs new file mode 100644 index 0000000..8eb9928 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/NightSight.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class NightSightPotion : BasePotion + { + public override bool CIT { get { return true; } } + + private double m_Time; + + public double Time + { + get + { + return m_Time; + } + } + + [Constructable] + public NightSightPotion() + : base(0xF06, PotionEffect.Nightsight) + { + } + + public NightSightPotion(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Drink(Mobile from) + { + if (from.BeginAction(typeof(LightCycle))) + { + m_Time = IntensifiedTime ? 45 : 20; + //Plume : Addiction + if (from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + + double Addiction = drinker.CalculateHealAddiction(this); + + if (Addiction > 100) + { + drinker.SendMessage("Votre corps ne supporte plus ce traitement"); + drinker.Poison = Poison.Lesser; + drinker.Hunger = 0; + } + + m_Time -= drinker.CalculateNightSightAddiction(this); + } + new LightCycle.PotionNightSightTimer(from, this).Start(); + from.LightLevel = LightCycle.DungeonLevel / 2; + + from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); + from.PlaySound(0x1E3); + + BasePotion.PlayDrinkEffect(from); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + } + else + { + from.SendMessage("You already have nightsight."); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/ParasiticPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/ParasiticPotion.cs new file mode 100644 index 0000000..e5d5204 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/ParasiticPotion.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ParasiticPotion : BasePoisonPotion + { + public override Poison Poison{ get{ return Poison.Greater; } } /* public override Poison Poison{ get{ return Poison.Darkglow; } } MUST be restored when prerequisites are done */ + + public override double MinPoisoningSkill{ get{ return 95.0; } } + public override double MaxPoisoningSkill{ get{ return 100.0; } } + + public override int LabelNumber{ get{ return 1072848; } } // Parasitic Poison + + [Constructable] + public ParasiticPotion() : base( PotionEffect.Parasitic ) + { + Hue = 0x17C; + } + + public ParasiticPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs new file mode 100644 index 0000000..4a2f33a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/BasePoisonPotion.cs @@ -0,0 +1,50 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BasePoisonPotion : BasePotion + { + public abstract Poison Poison{ get; } + + public abstract double MinPoisoningSkill{ get; } + public abstract double MaxPoisoningSkill{ get; } + + public BasePoisonPotion( PotionEffect effect ) : base( 0xF0A, effect ) + { + } + + public BasePoisonPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public void DoPoison( Mobile from ) + { + from.ApplyPoison( from, Poison ); + } + + public override void Drink( Mobile from ) + { + DoPoison( from ); + + BasePotion.PlayDrinkEffect( from ); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs new file mode 100644 index 0000000..b8d17bb --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/DeadlyPoisonPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DeadlyPoisonPotion : BasePoisonPotion + { + public override Poison Poison{ get{ return Poison.Deadly; } } + + public override double MinPoisoningSkill{ get{ return 95.0; } } + public override double MaxPoisoningSkill{ get{ return 100.0; } } + + [Constructable] + public DeadlyPoisonPotion() : base( PotionEffect.PoisonDeadly ) + { + } + + public DeadlyPoisonPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs new file mode 100644 index 0000000..b7c116b --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/GreaterPoisonPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterPoisonPotion : BasePoisonPotion + { + public override Poison Poison{ get{ return Poison.Greater; } } + + public override double MinPoisoningSkill{ get{ return 60.0; } } + public override double MaxPoisoningSkill{ get{ return 100.0; } } + + [Constructable] + public GreaterPoisonPotion() : base( PotionEffect.PoisonGreater ) + { + } + + public GreaterPoisonPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs new file mode 100644 index 0000000..7ab4b33 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/LesserPoisonPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LesserPoisonPotion : BasePoisonPotion + { + public override Poison Poison{ get{ return Poison.Lesser; } } + + public override double MinPoisoningSkill{ get{ return 0.0; } } + public override double MaxPoisoningSkill{ get{ return 60.0; } } + + [Constructable] + public LesserPoisonPotion() : base( PotionEffect.PoisonLesser ) + { + } + + public LesserPoisonPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs new file mode 100644 index 0000000..c94e28a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Poison Potions/PoisonPotion.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PoisonPotion : BasePoisonPotion + { + public override Poison Poison{ get{ return Poison.Regular; } } + + public override double MinPoisoningSkill{ get{ return 30.0; } } + public override double MaxPoisoningSkill{ get{ return 70.0; } } + + [Constructable] + public PoisonPotion() : base( PotionEffect.Poison ) + { + } + + public PoisonPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs new file mode 100644 index 0000000..e82e2a2 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/BaseRefreshPotion.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BaseRefreshPotion : BasePotion + { + public abstract double Refresh{ get; } + + public BaseRefreshPotion( PotionEffect effect ) : base( 0xF0B, effect ) + { + } + + public BaseRefreshPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Drink( Mobile from ) + { + if ( from.Stam < from.StamMax ) + { + from.Stam += Scale( from, (int)(Refresh * from.StamMax) ); + + BasePotion.PlayDrinkEffect( from ); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + } + else + { + from.SendMessage( "You decide against drinking this potion, as you are already at full stamina." ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs new file mode 100644 index 0000000..8a2b4e8 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/RefreshPotion.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RefreshPotion : BaseRefreshPotion + { + public override double Refresh{ get{ return 0.25; } } + + [Constructable] + public RefreshPotion() : base( PotionEffect.Refresh ) + { + } + + public RefreshPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs new file mode 100644 index 0000000..8be1114 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Refresh Potions/TotalRefreshPotion.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TotalRefreshPotion : BaseRefreshPotion + { + public override double Refresh{ get{ return 1.0; } } + + [Constructable] + public TotalRefreshPotion() : base( PotionEffect.RefreshTotal ) + { + } + + public TotalRefreshPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs new file mode 100644 index 0000000..1f13012 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/BaseStrengthPotion.cs @@ -0,0 +1,88 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class BaseStrengthPotion : BasePotion + { + public override bool CIT { get { return true; } } + public override bool CIS { get { return true; } } + + public abstract int StrOffset{ get; } + public abstract TimeSpan Duration{ get; } + + public BaseStrengthPotion( PotionEffect effect ) : base( 0xF09, effect ) + { + } + + public BaseStrengthPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool DoStrength( Mobile from ) + { + //Plume : Addiction + if (from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + + double CurrentAddiction = drinker.CalculateStrengthAddiction(this)[0]; + double GlobalAddiction = drinker.CalculateStrengthAddiction(this)[1]; + int StrScalar = (int)Math.Floor(Math.Sqrt(CurrentAddiction)); + double DurationScalar = GlobalAddiction * 0.95; + + if (GlobalAddiction > 100) + { + drinker.SendMessage("Votre corps ne supporte plus ce traitement"); + drinker.Str--; + this.Consume(); + return false; + } + + if (Spells.SpellHelper.AddStatOffset(from, StatType.Str, Scale(from, StrOffset - Math.Min(StrOffset, StrScalar)), Duration - TimeSpan.FromSeconds(DurationScalar))) + { + from.FixedEffect(0x375A, 10, 15); + from.PlaySound(0x1E7); + return true; + } + drinker.IncAddiction(this); + } + + if (Spells.SpellHelper.AddStatOffset(from, StatType.Dex, Scale(from, StrOffset), Duration)) + { + from.FixedEffect(0x375A, 10, 15); + from.PlaySound(0x1E7); + return true; + } + + from.SendLocalizedMessage( 502173 ); // You are already under a similar effect. + return false; + } + + public override void Drink( Mobile from ) + { + if ( DoStrength( from ) ) + { + BasePotion.PlayDrinkEffect( from ); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + this.Consume(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs new file mode 100644 index 0000000..fec6b51 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/GreaterStrengthPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterStrengthPotion : BaseStrengthPotion + { + public override int StrOffset { get { return IntensifiedStrength ? 23 : 17; } } + public override TimeSpan Duration { get { return TimeSpan.FromMinutes(IntensifiedTime ? 2.5 : 1.5); } } + + [Constructable] + public GreaterStrengthPotion() : base( PotionEffect.StrengthGreater ) + { + } + + public GreaterStrengthPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs b/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs new file mode 100644 index 0000000..e3d1929 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Potions/Strength Potions/StrengthPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StrengthPotion : BaseStrengthPotion + { + public override int StrOffset { get { return IntensifiedStrength ? 14 : 8; } } + public override TimeSpan Duration { get { return TimeSpan.FromMinutes(IntensifiedTime ? 2.5 : 1.5); } } + + [Constructable] + public StrengthPotion() : base( PotionEffect.Strength ) + { + } + + public StrengthPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Runebook.cs b/Scripts/Items/Skill Items/Magical/Runebook.cs new file mode 100644 index 0000000..89b5f12 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Runebook.cs @@ -0,0 +1,558 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Multis; +using Server.Engines.Craft; +using Server.ContextMenus; + +namespace Server.Items +{ + public class Runebook : Item, ISecurable, ICraftable + { + public static readonly TimeSpan UseDelay = TimeSpan.FromSeconds( 7.0 ); + + private BookQuality m_Quality; + + [CommandProperty(AccessLevel.GameMaster)] + public BookQuality Quality + { + get { return m_Quality; } + set { m_Quality = value; InvalidateProperties(); } + } + + private List m_Entries; + private string m_Description; + private int m_CurCharges, m_MaxCharges; + private int m_DefaultIndex; + private SecureLevel m_Level; + private Mobile m_Crafter; + + private DateTime m_NextUse; + + private List m_Openers = new List(); + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextUse + { + get{ return m_NextUse; } + set{ m_NextUse = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Description + { + get + { + return m_Description; + } + set + { + m_Description = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int CurCharges + { + get + { + return m_CurCharges; + } + set + { + m_CurCharges = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxCharges + { + get + { + return m_MaxCharges; + } + set + { + m_MaxCharges = value; + } + } + + public List Openers + { + get + { + return m_Openers; + } + set + { + m_Openers = value; + } + } + + public override int LabelNumber{ get{ return 1041267; } } // runebook + + [Constructable] + public Runebook( int maxCharges ) : base( Core.AOS ? 0x22C5 : 0xEFA ) + { + Weight = (Core.SE ? 1.0 : 3.0); + LootType = LootType.Blessed; + Hue = 0x461; + + Layer = (Core.AOS ? Layer.Invalid : Layer.OneHanded); + + m_Entries = new List(); + + m_MaxCharges = maxCharges; + + m_DefaultIndex = -1; + + m_Level = SecureLevel.CoOwners; + } + + [Constructable] + public Runebook() : this( Core.SE ? 12 : 6 ) + { + } + + public List Entries + { + get + { + return m_Entries; + } + } + + public RunebookEntry Default + { + get + { + if ( m_DefaultIndex >= 0 && m_DefaultIndex < m_Entries.Count ) + return m_Entries[m_DefaultIndex]; + + return null; + } + set + { + if ( value == null ) + m_DefaultIndex = -1; + else + m_DefaultIndex = m_Entries.IndexOf( value ); + } + } + + public Runebook( Serial serial ) : base( serial ) + { + } + + public override bool AllowEquipedCast( Mobile from ) + { + return true; + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write((int)3); + + writer.Write((byte)m_Quality); + + writer.Write( m_Crafter ); + + writer.Write( (int) m_Level ); + + writer.Write( m_Entries.Count ); + + for ( int i = 0; i < m_Entries.Count; ++i ) + m_Entries[i].Serialize( writer ); + + writer.Write( m_Description ); + writer.Write( m_CurCharges ); + writer.Write( m_MaxCharges ); + writer.Write( m_DefaultIndex ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + LootType = LootType.Blessed; + + if( Core.SE && Weight == 3.0 ) + Weight = 1.0; + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + { + m_Quality = (BookQuality)reader.ReadByte(); + goto case 2; + } + case 2: + { + m_Crafter = reader.ReadMobile(); + goto case 1; + } + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + int count = reader.ReadInt(); + + m_Entries = new List( count ); + + for ( int i = 0; i < count; ++i ) + m_Entries.Add( new RunebookEntry( reader ) ); + + m_Description = reader.ReadString(); + m_CurCharges = reader.ReadInt(); + m_MaxCharges = reader.ReadInt(); + m_DefaultIndex = reader.ReadInt(); + + break; + } + } + } + + public void DropRune( Mobile from, RunebookEntry e, int index ) + { + if ( m_DefaultIndex > index ) + m_DefaultIndex -= 1; + else if ( m_DefaultIndex == index ) + m_DefaultIndex = -1; + + m_Entries.RemoveAt( index ); + + RecallRune rune = new RecallRune(); + + rune.Target = e.Location; + rune.TargetMap = e.Map; + rune.Description = e.Description; + rune.House = e.House; + rune.Marked = true; + + from.AddToBackpack( rune ); + + from.SendLocalizedMessage( 502421 ); // You have removed the rune. + } + + public bool IsOpen( Mobile toCheck ) + { + NetState ns = toCheck.NetState; + + if ( ns != null ) { + foreach ( Gump gump in ns.Gumps ) { + RunebookGump bookGump = gump as RunebookGump; + + if ( bookGump != null && bookGump.Book == this ) { + return true; + } + } + } + + return false; + } + + public override bool DisplayLootType{ get{ return Core.AOS; } } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if (m_Quality == BookQuality.Exceptional) + list.Add(1063341); // exceptional + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if ( m_Description != null && m_Description.Length > 0 ) + list.Add( m_Description ); + } + + public override bool OnDragLift( Mobile from ) + { + if ( from.HasGump( typeof( RunebookGump ) ) ) + { + from.SendMessage("Fermez tous vos livre de runes avant d'en ramasser un."); + return false; + } + + foreach ( Mobile m in m_Openers ) + if ( IsOpen( m ) ) + m.CloseGump( typeof( RunebookGump ) ); + + m_Openers.Clear(); + + return true; + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Description != null && m_Description.Length > 0 ) + LabelTo( from, m_Description ); + + base.OnSingleClick( from ); + + if ( m_Crafter != null ) + LabelTo( from, 1050043, m_Crafter.Name ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), (Core.ML ? 3 : 1) ) && CheckAccess( from ) ) + { + if ( RootParent is BaseCreature ) + { + from.SendLocalizedMessage( 502402 ); // That is inaccessible. + return; + } + + if ( DateTime.Now < m_NextUse ) + { + from.SendLocalizedMessage( 502406 ); // This book needs time to recharge. + return; + } + + from.CloseGump( typeof( RunebookGump ) ); + from.SendGump( new RunebookGump( from, this ) ); + + m_Openers.Add( from ); + } + } + + public virtual void OnTravel() + { + if (!Core.SA) + m_NextUse = DateTime.Now + UseDelay; + } + + public override void OnAfterDuped( Item newItem ) + { + Runebook book = newItem as Runebook; + + if ( book == null ) + return; + + book.m_Entries = new List(); + + for ( int i = 0; i < m_Entries.Count; i++ ) + { + RunebookEntry entry = m_Entries[i]; + + book.m_Entries.Add( new RunebookEntry( entry.Location, entry.Map, entry.Description, entry.House ) ); + } + } + + public bool CheckAccess( Mobile m ) + { + if ( !IsLockedDown || m.AccessLevel >= AccessLevel.GameMaster ) + return true; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsAosRules && (house.Public ? house.IsBanned( m ) : !house.HasAccess( m )) ) + return false; + + return ( house != null && house.HasSecureAccess( m, m_Level ) ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is RecallRune ) + { + if ( IsLockedDown && from.AccessLevel < AccessLevel.GameMaster ) + { + from.SendLocalizedMessage( 502413, null, 0x35 ); // That cannot be done while the book is locked down. + } + else if ( IsOpen( from ) ) + { + from.SendLocalizedMessage( 1005571 ); // You cannot place objects in the book while viewing the contents. + } + else if ( m_Entries.Count < 16 ) + { + RecallRune rune = (RecallRune)dropped; + + if ( rune.Marked && rune.TargetMap != null ) + { + m_Entries.Add( new RunebookEntry( rune.Target, rune.TargetMap, rune.Description, rune.House ) ); + + dropped.Delete(); + + from.Send( new PlaySound( 0x42, GetWorldLocation() ) ); + + string desc = rune.Description; + + if ( desc == null || (desc = desc.Trim()).Length == 0 ) + desc = "(indescript)"; + + from.SendMessage( desc ); + + return true; + } + else + { + from.SendLocalizedMessage( 502409 ); // This rune does not have a marked location. + } + } + else + { + from.SendLocalizedMessage( 502401 ); // This runebook is full. + } + } + else if ( dropped is RecallScroll ) + { + if ( m_CurCharges < m_MaxCharges ) + { + from.Send( new PlaySound( 0x249, GetWorldLocation() ) ); + + int amount = dropped.Amount; + + if ( amount > (m_MaxCharges - m_CurCharges) ) + { + dropped.Consume( m_MaxCharges - m_CurCharges ); + m_CurCharges = m_MaxCharges; + } + else + { + m_CurCharges += amount; + dropped.Delete(); + + return true; + } + } + else + { + from.SendLocalizedMessage( 502410 ); // This book already has the maximum amount of charges. + } + } + + return false; + } + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + int charges = 5 + quality + (int)(from.Skills[SkillName.Inscribe].Value / 30); + + if ( charges > 10 ) + charges = 10; + + MaxCharges = (Core.SE ? charges * 2 : charges); + + if ( makersMark ) + Crafter = from; + + m_Quality = (BookQuality)(quality - 1); + + return quality; + } + + #endregion + } + + public class RunebookEntry + { + private Point3D m_Location; + private Map m_Map; + private string m_Description; + private BaseHouse m_House; + + public Point3D Location + { + get{ return m_Location; } + } + + public Map Map + { + get{ return m_Map; } + } + + public string Description + { + get{ return m_Description; } + } + + public BaseHouse House + { + get{ return m_House; } + } + + public RunebookEntry( Point3D loc, Map map, string desc, BaseHouse house ) + { + m_Location = loc; + m_Map = map; + m_Description = desc; + m_House = house; + } + + public RunebookEntry( GenericReader reader ) + { + int version = reader.ReadByte(); + + switch ( version ) + { + case 1: + { + m_House = reader.ReadItem() as BaseHouse; + goto case 0; + } + case 0: + { + m_Location = reader.ReadPoint3D(); + m_Map = reader.ReadMap(); + m_Description = reader.ReadString(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + if ( m_House != null && !m_House.Deleted ) + { + writer.Write( (byte) 1 ); // version + + writer.Write( m_House ); + } + else + { + writer.Write( (byte) 0 ); // version + } + + writer.Write( m_Location ); + writer.Write( m_Map ); + writer.Write( m_Description ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs new file mode 100644 index 0000000..a401032 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/EarthquakeScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EarthquakeScroll : SpellScroll + { + [Constructable] + public EarthquakeScroll() : this( 1 ) + { + } + + [Constructable] + public EarthquakeScroll( int amount ) : base( 56, 0x1F65, amount ) + { + } + + public EarthquakeScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs new file mode 100644 index 0000000..97e092b --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/EnergyVortexScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EnergyVortexScroll : SpellScroll + { + [Constructable] + public EnergyVortexScroll() : this( 1 ) + { + } + + [Constructable] + public EnergyVortexScroll( int amount ) : base( 57, 0x1F66, amount ) + { + } + + public EnergyVortexScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs new file mode 100644 index 0000000..e8b4918 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/ResurrectionScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ResurrectionScroll : SpellScroll + { + [Constructable] + public ResurrectionScroll() : this( 1 ) + { + } + + [Constructable] + public ResurrectionScroll( int amount ) : base( 58, 0x1F67, amount ) + { + } + + public ResurrectionScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs new file mode 100644 index 0000000..3545b71 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonAirElementalScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonAirElementalScroll : SpellScroll + { + [Constructable] + public SummonAirElementalScroll() : this( 1 ) + { + } + + [Constructable] + public SummonAirElementalScroll( int amount ) : base( 59, 0x1F68, amount ) + { + } + + public SummonAirElementalScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs new file mode 100644 index 0000000..7d455bd --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonDaemonScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonDaemonScroll : SpellScroll + { + [Constructable] + public SummonDaemonScroll() : this( 1 ) + { + } + + [Constructable] + public SummonDaemonScroll( int amount ) : base( 60, 0x1F69, amount ) + { + } + + public SummonDaemonScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs new file mode 100644 index 0000000..8057ca2 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonEarthElementalScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonEarthElementalScroll : SpellScroll + { + [Constructable] + public SummonEarthElementalScroll() : this( 1 ) + { + } + + [Constructable] + public SummonEarthElementalScroll( int amount ) : base( 61, 0x1F6A, amount ) + { + } + + public SummonEarthElementalScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs new file mode 100644 index 0000000..a666e88 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonFireElementalScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonFireElementalScroll : SpellScroll + { + [Constructable] + public SummonFireElementalScroll() : this( 1 ) + { + } + + [Constructable] + public SummonFireElementalScroll( int amount ) : base( 62, 0x1F6B, amount ) + { + } + + public SummonFireElementalScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs new file mode 100644 index 0000000..8b486a4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Eighth Circle/SummonWaterElementalScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonWaterElementalScroll : SpellScroll + { + [Constructable] + public SummonWaterElementalScroll() : this( 1 ) + { + } + + [Constructable] + public SummonWaterElementalScroll( int amount ) : base( 63, 0x1F6C, amount ) + { + } + + public SummonWaterElementalScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs new file mode 100644 index 0000000..e6acda4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/BladeSpiritsScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BladeSpiritsScroll : SpellScroll + { + [Constructable] + public BladeSpiritsScroll() : this( 1 ) + { + } + + [Constructable] + public BladeSpiritsScroll( int amount ) : base( 32, 0x1F4D, amount ) + { + } + + public BladeSpiritsScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs new file mode 100644 index 0000000..6e927d4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/DispelFieldScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DispelFieldScroll : SpellScroll + { + [Constructable] + public DispelFieldScroll() : this( 1 ) + { + } + + [Constructable] + public DispelFieldScroll( int amount ) : base( 33, 0x1F4E, amount ) + { + } + + public DispelFieldScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs new file mode 100644 index 0000000..5d80b75 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/IncognitoScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class IncognitoScroll : SpellScroll + { + [Constructable] + public IncognitoScroll() : this( 1 ) + { + } + + [Constructable] + public IncognitoScroll( int amount ) : base( 34, 0x1F4F, amount ) + { + } + + public IncognitoScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs new file mode 100644 index 0000000..cf57924 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/MagicReflectScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MagicReflectScroll : SpellScroll + { + [Constructable] + public MagicReflectScroll() : this( 1 ) + { + } + + [Constructable] + public MagicReflectScroll( int amount ) : base( 35, 0x1F50, amount ) + { + } + + public MagicReflectScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs new file mode 100644 index 0000000..8d42ac4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/MindBlastScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MindBlastScroll : SpellScroll + { + [Constructable] + public MindBlastScroll() : this( 1 ) + { + } + + [Constructable] + public MindBlastScroll( int amount ) : base( 36, 0x1F51, amount ) + { + } + + public MindBlastScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs new file mode 100644 index 0000000..ce02adb --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/ParalyzeScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ParalyzeScroll : SpellScroll + { + [Constructable] + public ParalyzeScroll() : this( 1 ) + { + } + + [Constructable] + public ParalyzeScroll( int amount ) : base( 37, 0x1F52, amount ) + { + } + + public ParalyzeScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs new file mode 100644 index 0000000..ce98523 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/PoisonFieldScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PoisonFieldScroll : SpellScroll + { + [Constructable] + public PoisonFieldScroll() : this( 1 ) + { + } + + [Constructable] + public PoisonFieldScroll( int amount ) : base( 38, 0x1F53, amount ) + { + } + + public PoisonFieldScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs new file mode 100644 index 0000000..04e05fb --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fifth Circle/SummonCreatureScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonCreatureScroll : SpellScroll + { + [Constructable] + public SummonCreatureScroll() : this( 1 ) + { + } + + [Constructable] + public SummonCreatureScroll( int amount ) : base( 39, 0x1F54, amount ) + { + } + + public SummonCreatureScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs new file mode 100644 index 0000000..4122869 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/ClumsyScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ClumsyScroll : SpellScroll + { + [Constructable] + public ClumsyScroll() : this( 1 ) + { + } + + [Constructable] + public ClumsyScroll( int amount ) : base( 0, 0x1F2E, amount ) + { + } + + public ClumsyScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs new file mode 100644 index 0000000..9ce590c --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/CreateFoodScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CreateFoodScroll : SpellScroll + { + [Constructable] + public CreateFoodScroll() : this( 1 ) + { + } + + [Constructable] + public CreateFoodScroll( int amount ) : base( 1, 0x1F2F, amount ) + { + } + + public CreateFoodScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs new file mode 100644 index 0000000..a1a4e9a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/FeeblemindScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class FeeblemindScroll : SpellScroll + { + [Constructable] + public FeeblemindScroll() : this( 1 ) + { + } + + [Constructable] + public FeeblemindScroll( int amount ) : base( 2, 0x1F30, amount ) + { + } + + public FeeblemindScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs new file mode 100644 index 0000000..b11b2ee --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/HealScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class HealScroll : SpellScroll + { + [Constructable] + public HealScroll() : this( 1 ) + { + } + + [Constructable] + public HealScroll( int amount ) : base( 3, 0x1F31, amount ) + { + } + + public HealScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs new file mode 100644 index 0000000..23d5e18 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/MagicArrowScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MagicArrowScroll : SpellScroll + { + [Constructable] + public MagicArrowScroll() : this( 1 ) + { + } + + [Constructable] + public MagicArrowScroll( int amount ) : base( 4, 0x1F32, amount ) + { + } + + public MagicArrowScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs new file mode 100644 index 0000000..c514f8c --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/NightSightScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class NightSightScroll : SpellScroll + { + [Constructable] + public NightSightScroll() : this( 1 ) + { + } + + [Constructable] + public NightSightScroll( int amount ) : base( 5, 0x1F33, amount ) + { + } + + public NightSightScroll( Serial ser ) : base(ser) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs new file mode 100644 index 0000000..85f562e --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/ReactiveArmorScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ReactiveArmorScroll : SpellScroll + { + [Constructable] + public ReactiveArmorScroll() : this( 1 ) + { + } + + [Constructable] + public ReactiveArmorScroll( int amount ) : base( 6, 0x1F2D, amount ) + { + } + + public ReactiveArmorScroll( Serial ser ) : base(ser) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs new file mode 100644 index 0000000..610ca87 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/First Circle/WeakenScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class WeakenScroll : SpellScroll + { + [Constructable] + public WeakenScroll() : this( 1 ) + { + } + + [Constructable] + public WeakenScroll( int amount ) : base( 7, 0x1F34, amount ) + { + } + + public WeakenScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs new file mode 100644 index 0000000..b2f051f --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchProtectionScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ArchProtectionScroll : SpellScroll + { + [Constructable] + public ArchProtectionScroll() : this( 1 ) + { + } + + [Constructable] + public ArchProtectionScroll( int amount ) : base( 25, 0x1F46, amount ) + { + } + + public ArchProtectionScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs new file mode 100644 index 0000000..27b950a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ArchcureScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ArchCureScroll : SpellScroll + { + [Constructable] + public ArchCureScroll() : this( 1 ) + { + } + + [Constructable] + public ArchCureScroll( int amount ) : base( 24, 0x1F45, amount ) + { + } + + public ArchCureScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs new file mode 100644 index 0000000..9242cf7 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/CurseScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CurseScroll : SpellScroll + { + [Constructable] + public CurseScroll() : this( 1 ) + { + } + + [Constructable] + public CurseScroll( int amount ) : base( 26, 0x1F47, amount ) + { + } + + public CurseScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs new file mode 100644 index 0000000..ccef500 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/FireFieldScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class FireFieldScroll : SpellScroll + { + [Constructable] + public FireFieldScroll() : this( 1 ) + { + } + + [Constructable] + public FireFieldScroll( int amount ) : base( 27, 0x1F48, amount ) + { + } + + public FireFieldScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs new file mode 100644 index 0000000..7f951bd --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/GreaterHealScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class GreaterHealScroll : SpellScroll + { + [Constructable] + public GreaterHealScroll() : this( 1 ) + { + } + + [Constructable] + public GreaterHealScroll( int amount ) : base( 28, 0x1F49, amount ) + { + } + + public GreaterHealScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs new file mode 100644 index 0000000..826eb8a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/LightningScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class LightningScroll : SpellScroll + { + [Constructable] + public LightningScroll() : this( 1 ) + { + } + + [Constructable] + public LightningScroll( int amount ) : base( 29, 0x1F4A, amount ) + { + } + + public LightningScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs new file mode 100644 index 0000000..486bf20 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/ManaDrainScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ManaDrainScroll : SpellScroll + { + [Constructable] + public ManaDrainScroll() : this( 1 ) + { + } + + [Constructable] + public ManaDrainScroll( int amount ) : base( 30, 0x1F4B, amount ) + { + } + + public ManaDrainScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs new file mode 100644 index 0000000..3e2ed8d --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Fourth Circle/RecallScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class RecallScroll : SpellScroll + { + [Constructable] + public RecallScroll() : this( 1 ) + { + } + + [Constructable] + public RecallScroll( int amount ) : base( 31, 0x1F4C, amount ) + { + } + + public RecallScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs new file mode 100644 index 0000000..b46d685 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/AnimateDeadScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AnimateDeadScroll : SpellScroll + { + [Constructable] + public AnimateDeadScroll() : this( 1 ) + { + } + + [Constructable] + public AnimateDeadScroll( int amount ) : base( 100, 0x2260, amount ) + { + } + + public AnimateDeadScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs new file mode 100644 index 0000000..9da7a61 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/BloodOathScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BloodOathScroll : SpellScroll + { + [Constructable] + public BloodOathScroll() : this( 1 ) + { + } + + [Constructable] + public BloodOathScroll( int amount ) : base( 101, 0x2261, amount ) + { + } + + public BloodOathScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs new file mode 100644 index 0000000..e9da3e4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/CorpseSkinScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CorpseSkinScroll : SpellScroll + { + [Constructable] + public CorpseSkinScroll() : this( 1 ) + { + } + + [Constructable] + public CorpseSkinScroll( int amount ) : base( 102, 0x2262, amount ) + { + } + + public CorpseSkinScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs new file mode 100644 index 0000000..69c27b5 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/CurseWeaponScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CurseWeaponScroll : SpellScroll + { + [Constructable] + public CurseWeaponScroll() : this( 1 ) + { + } + + [Constructable] + public CurseWeaponScroll( int amount ) : base( 103, 0x2263, amount ) + { + } + + public CurseWeaponScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs new file mode 100644 index 0000000..8b1beb6 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/EvilOmenScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EvilOmenScroll : SpellScroll + { + [Constructable] + public EvilOmenScroll() : this( 1 ) + { + } + + [Constructable] + public EvilOmenScroll( int amount ) : base( 104, 0x2264, amount ) + { + } + + public EvilOmenScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs new file mode 100644 index 0000000..6025d7e --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/ExorcismScroll.cs @@ -0,0 +1,37 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ExorcismScroll : SpellScroll + { + [Constructable] + public ExorcismScroll() : this( 1 ) + { + } + + [Constructable] + public ExorcismScroll( int amount ) : base( 116, 0x2270, amount ) + { + } + + public ExorcismScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs new file mode 100644 index 0000000..69f9c8b --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/HorrificBeastScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class HorrificBeastScroll : SpellScroll + { + [Constructable] + public HorrificBeastScroll() : this( 1 ) + { + } + + [Constructable] + public HorrificBeastScroll( int amount ) : base( 105, 0x2265, amount ) + { + } + + public HorrificBeastScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs new file mode 100644 index 0000000..c86895f --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/LichFormScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class LichFormScroll : SpellScroll + { + [Constructable] + public LichFormScroll() : this( 1 ) + { + } + + [Constructable] + public LichFormScroll( int amount ) : base( 106, 0x2266, amount ) + { + } + + public LichFormScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs new file mode 100644 index 0000000..f888717 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/MindRotScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MindRotScroll : SpellScroll + { + [Constructable] + public MindRotScroll() : this( 1 ) + { + } + + [Constructable] + public MindRotScroll( int amount ) : base( 107, 0x2267, amount ) + { + } + + public MindRotScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs new file mode 100644 index 0000000..87e6139 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/PainSpikeScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PainSpikeScroll : SpellScroll + { + [Constructable] + public PainSpikeScroll() : this( 1 ) + { + } + + [Constructable] + public PainSpikeScroll( int amount ) : base( 108, 0x2268, amount ) + { + } + + public PainSpikeScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs new file mode 100644 index 0000000..dbbafbf --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/PoisonStrikeScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PoisonStrikeScroll : SpellScroll + { + [Constructable] + public PoisonStrikeScroll() : this( 1 ) + { + } + + [Constructable] + public PoisonStrikeScroll( int amount ) : base( 109, 0x2269, amount ) + { + } + + public PoisonStrikeScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs new file mode 100644 index 0000000..1e1645b --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/StrangleScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class StrangleScroll : SpellScroll + { + [Constructable] + public StrangleScroll() : this( 1 ) + { + } + + [Constructable] + public StrangleScroll( int amount ) : base( 110, 0x226A, amount ) + { + } + + public StrangleScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs new file mode 100644 index 0000000..80b08e4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/SummonFamiliarScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonFamiliarScroll : SpellScroll + { + [Constructable] + public SummonFamiliarScroll() : this( 1 ) + { + } + + [Constructable] + public SummonFamiliarScroll( int amount ) : base( 111, 0x226B, amount ) + { + } + + public SummonFamiliarScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs new file mode 100644 index 0000000..4a7fba1 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/VampiricEmbraceScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class VampiricEmbraceScroll : SpellScroll + { + [Constructable] + public VampiricEmbraceScroll() : this( 1 ) + { + } + + [Constructable] + public VampiricEmbraceScroll( int amount ) : base( 112, 0x226C, amount ) + { + } + + public VampiricEmbraceScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs new file mode 100644 index 0000000..2048f02 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/VengefulSpiritScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class VengefulSpiritScroll : SpellScroll + { + [Constructable] + public VengefulSpiritScroll() : this( 1 ) + { + } + + [Constructable] + public VengefulSpiritScroll( int amount ) : base( 113, 0x226D, amount ) + { + } + + public VengefulSpiritScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs new file mode 100644 index 0000000..751b411 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/WitherScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class WitherScroll : SpellScroll + { + [Constructable] + public WitherScroll() : this( 1 ) + { + } + + [Constructable] + public WitherScroll( int amount ) : base( 114, 0x226E, amount ) + { + } + + public WitherScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs new file mode 100644 index 0000000..cc04c6e --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Necromancy/WraithFormScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class WraithFormScroll : SpellScroll + { + [Constructable] + public WraithFormScroll() : this( 1 ) + { + } + + [Constructable] + public WraithFormScroll( int amount ) : base( 115, 0x226F, amount ) + { + } + + public WraithFormScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs new file mode 100644 index 0000000..879780c --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/AgilityScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AgilityScroll : SpellScroll + { + [Constructable] + public AgilityScroll() : this( 1 ) + { + } + + [Constructable] + public AgilityScroll( int amount ) : base( 8, 0x1F35, amount ) + { + } + + public AgilityScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs new file mode 100644 index 0000000..4fbad5e --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/CunningScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CunningScroll : SpellScroll + { + [Constructable] + public CunningScroll() : this( 1 ) + { + } + + [Constructable] + public CunningScroll( int amount ) : base( 9, 0x1F36, amount ) + { + } + + public CunningScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs new file mode 100644 index 0000000..3b64d33 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/CureScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CureScroll : SpellScroll + { + [Constructable] + public CureScroll() : this( 1 ) + { + } + + [Constructable] + public CureScroll( int amount ) : base( 10, 0x1F37, amount ) + { + } + + public CureScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs new file mode 100644 index 0000000..3031bd9 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/HarmScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class HarmScroll : SpellScroll + { + [Constructable] + public HarmScroll() : this( 1 ) + { + } + + [Constructable] + public HarmScroll( int amount ) : base( 11, 0x1F38, amount ) + { + } + + public HarmScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs new file mode 100644 index 0000000..eb63038 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/MagicTrapScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MagicTrapScroll : SpellScroll + { + [Constructable] + public MagicTrapScroll() : this( 1 ) + { + } + + [Constructable] + public MagicTrapScroll( int amount ) : base( 12, 0x1F39, amount ) + { + } + + public MagicTrapScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs new file mode 100644 index 0000000..2f6367d --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/MagicUnTrapScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MagicUnTrapScroll : SpellScroll + { + [Constructable] + public MagicUnTrapScroll() : this( 1 ) + { + } + + [Constructable] + public MagicUnTrapScroll( int amount ) : base( 13, 0x1F3A, amount ) + { + } + + public MagicUnTrapScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs new file mode 100644 index 0000000..3be022a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/ProtectionScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ProtectionScroll : SpellScroll + { + [Constructable] + public ProtectionScroll() : this( 1 ) + { + } + + [Constructable] + public ProtectionScroll( int amount ) : base( 14, 0x1F3B, amount ) + { + } + + public ProtectionScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs new file mode 100644 index 0000000..fee20a3 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Second Circle/StrengthScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class StrengthScroll : SpellScroll + { + [Constructable] + public StrengthScroll() : this( 1 ) + { + } + + [Constructable] + public StrengthScroll( int amount ) : base( 15, 0x1F3C, amount ) + { + } + + public StrengthScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs new file mode 100644 index 0000000..02787b4 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/ChainLightningScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ChainLightningScroll : SpellScroll + { + [Constructable] + public ChainLightningScroll() : this( 1 ) + { + } + + [Constructable] + public ChainLightningScroll( int amount ) : base( 48, 0x1F5D, amount ) + { + } + + public ChainLightningScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs new file mode 100644 index 0000000..9743b16 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/EnergyFieldScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EnergyFieldScroll : SpellScroll + { + [Constructable] + public EnergyFieldScroll() : this( 1 ) + { + } + + [Constructable] + public EnergyFieldScroll( int amount ) : base( 49, 0x1F5E, amount ) + { + } + + public EnergyFieldScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs new file mode 100644 index 0000000..7aac303 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/FlamestrikeScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class FlamestrikeScroll : SpellScroll + { + [Constructable] + public FlamestrikeScroll() : this( 1 ) + { + } + + [Constructable] + public FlamestrikeScroll( int amount ) : base( 50, 0x1F5F, amount ) + { + } + + public FlamestrikeScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs new file mode 100644 index 0000000..ebdac5e --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/GateTravelScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class GateTravelScroll : SpellScroll + { + [Constructable] + public GateTravelScroll() : this( 1 ) + { + } + + [Constructable] + public GateTravelScroll( int amount ) : base( 51, 0x1F60, amount ) + { + } + + public GateTravelScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs new file mode 100644 index 0000000..cbaafa3 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/ManaVampireScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ManaVampireScroll : SpellScroll + { + [Constructable] + public ManaVampireScroll() : this( 1 ) + { + } + + [Constructable] + public ManaVampireScroll( int amount ) : base( 52, 0x1F61, amount ) + { + } + + public ManaVampireScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs new file mode 100644 index 0000000..f5e0edb --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/MassDispelScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MassDispelScroll : SpellScroll + { + [Constructable] + public MassDispelScroll() : this( 1 ) + { + } + + [Constructable] + public MassDispelScroll( int amount ) : base( 53, 0x1F62, amount ) + { + } + + public MassDispelScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs new file mode 100644 index 0000000..fa244d5 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/MeteorStormScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MeteorSwarmScroll : SpellScroll + { + [Constructable] + public MeteorSwarmScroll() : this( 1 ) + { + } + + [Constructable] + public MeteorSwarmScroll( int amount ) : base( 54, 0x1F63, amount ) + { + } + + public MeteorSwarmScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs new file mode 100644 index 0000000..911edc9 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Seventh Circle/PolymorphScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PolymorphScroll : SpellScroll + { + [Constructable] + public PolymorphScroll() : this( 1 ) + { + } + + [Constructable] + public PolymorphScroll( int amount ) : base( 55, 0x1F64, amount ) + { + } + + public PolymorphScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs new file mode 100644 index 0000000..823ccb3 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/DispelScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DispelScroll : SpellScroll + { + [Constructable] + public DispelScroll() : this( 1 ) + { + } + + [Constructable] + public DispelScroll( int amount ) : base( 40, 0x1F55, amount ) + { + } + + public DispelScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs new file mode 100644 index 0000000..776fc18 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/EnergyBoltScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EnergyBoltScroll : SpellScroll + { + [Constructable] + public EnergyBoltScroll() : this( 1 ) + { + } + + [Constructable] + public EnergyBoltScroll( int amount ) : base( 41, 0x1F56, amount ) + { + } + + public EnergyBoltScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs new file mode 100644 index 0000000..1beab72 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/ExplosionScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ExplosionScroll : SpellScroll + { + [Constructable] + public ExplosionScroll() : this( 1 ) + { + } + + [Constructable] + public ExplosionScroll( int amount ) : base( 42, 0x1F57, amount ) + { + } + + public ExplosionScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs new file mode 100644 index 0000000..a567ef1 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/InvisibilityScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class InvisibilityScroll : SpellScroll + { + [Constructable] + public InvisibilityScroll() : this( 1 ) + { + } + + [Constructable] + public InvisibilityScroll( int amount ) : base( 43, 0x1F58, amount ) + { + } + + public InvisibilityScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs new file mode 100644 index 0000000..7babb6b --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/MarkScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MarkScroll : SpellScroll + { + [Constructable] + public MarkScroll() : this( 1 ) + { + } + + [Constructable] + public MarkScroll( int amount ) : base( 44, 0x1F59, amount ) + { + } + + public MarkScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs new file mode 100644 index 0000000..9fd9d20 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/MassCurseScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MassCurseScroll : SpellScroll + { + [Constructable] + public MassCurseScroll() : this( 1 ) + { + } + + [Constructable] + public MassCurseScroll( int amount ) : base( 45, 0x1F5A, amount ) + { + } + + public MassCurseScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs new file mode 100644 index 0000000..8b67224 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/ParalyzeFieldSpell.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ParalyzeFieldScroll : SpellScroll + { + [Constructable] + public ParalyzeFieldScroll() : this( 1 ) + { + } + + [Constructable] + public ParalyzeFieldScroll( int amount ) : base( 46, 0x1F5B, amount ) + { + } + + public ParalyzeFieldScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs new file mode 100644 index 0000000..4b0359d --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Sixth Circle/RevealScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class RevealScroll : SpellScroll + { + [Constructable] + public RevealScroll() : this( 1 ) + { + } + + [Constructable] + public RevealScroll( int amount ) : base( 47, 0x1F5C, amount ) + { + } + + public RevealScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/SpellScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/SpellScroll.cs new file mode 100644 index 0000000..1c5e196 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/SpellScroll.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Spells; +using Server.ContextMenus; + +namespace Server.Items +{ + public class SpellScroll : Item, ICommodity + { + private int m_SpellID; + + public int SpellID + { + get + { + return m_SpellID; + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return (Core.ML); } } + + public SpellScroll( Serial serial ) : base( serial ) + { + } + + [Constructable] + public SpellScroll( int spellID, int itemID ) : this( spellID, itemID, 1 ) + { + } + + [Constructable] + public SpellScroll( int spellID, int itemID, int amount ) : base( itemID ) + { + Stackable = true; + Weight = 1.0; + Amount = amount; + + m_SpellID = spellID; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_SpellID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_SpellID = reader.ReadInt(); + + break; + } + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive && this.Movable ) + list.Add( new ContextMenus.AddToSpellbookEntry() ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Multis.DesignContext.Check( from ) ) + return; // They are customizing + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + return; + } + + Spell spell = SpellRegistry.NewSpell( m_SpellID, from, this ); + + if ( spell != null ) + spell.Cast(); + else + from.SendLocalizedMessage( 502345 ); // This spell has been temporarily disabled. + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs b/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs new file mode 100644 index 0000000..db86493 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/SpellweavingScrolls.cs @@ -0,0 +1,566 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ArcaneCircleScroll : SpellScroll + { + [Constructable] + public ArcaneCircleScroll() + : this( 1 ) + { + } + + [Constructable] + public ArcaneCircleScroll( int amount ) + : base( 600, 0x2D51, amount ) + { + Hue = 0x8FD; + } + + public ArcaneCircleScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GiftOfRenewalScroll : SpellScroll + { + [Constructable] + public GiftOfRenewalScroll() + : this( 1 ) + { + } + + [Constructable] + public GiftOfRenewalScroll( int amount ) + : base( 601, 0x2D52, amount ) + { + Hue = 0x8FD; + } + + public GiftOfRenewalScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ImmolatingWeaponScroll : SpellScroll + { + [Constructable] + public ImmolatingWeaponScroll() + : this( 1 ) + { + } + + [Constructable] + public ImmolatingWeaponScroll( int amount ) + : base( 602, 0x2D53, amount ) + { + Hue = 0x8FD; + } + + public ImmolatingWeaponScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class AttuneWeaponScroll : SpellScroll + { + [Constructable] + public AttuneWeaponScroll() + : this( 1 ) + { + } + + [Constructable] + public AttuneWeaponScroll( int amount ) + : base( 603, 0x2D54, amount ) + { + Hue = 0x8FD; + } + + public AttuneWeaponScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ThunderstormScroll : SpellScroll + { + [Constructable] + public ThunderstormScroll() + : this( 1 ) + { + } + + [Constructable] + public ThunderstormScroll( int amount ) + : base( 604, 0x2D55, amount ) + { + Hue = 0x8FD; + } + + public ThunderstormScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class NatureFuryScroll : SpellScroll + { + [Constructable] + public NatureFuryScroll() + : this( 1 ) + { + } + + [Constructable] + public NatureFuryScroll( int amount ) + : base( 605, 0x2D56, amount ) + { + Hue = 0x8FD; + } + + public NatureFuryScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SummonFeyScroll : SpellScroll + { + [Constructable] + public SummonFeyScroll() + : this( 1 ) + { + } + + [Constructable] + public SummonFeyScroll( int amount ) + : base( 606, 0x2D57, amount ) + { + Hue = 0x8FD; + } + + public SummonFeyScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SummonFiendScroll : SpellScroll + { + [Constructable] + public SummonFiendScroll() + : this( 1 ) + { + } + + [Constructable] + public SummonFiendScroll( int amount ) + : base( 607, 0x2D58, amount ) + { + Hue = 0x8FD; + } + + public SummonFiendScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ReaperFormScroll : SpellScroll + { + [Constructable] + public ReaperFormScroll() + : this( 1 ) + { + } + + [Constructable] + public ReaperFormScroll( int amount ) + : base( 608, 0x2D59, amount ) + { + Hue = 0x8FD; + } + + public ReaperFormScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WildfireScroll : SpellScroll + { + [Constructable] + public WildfireScroll() + : this( 1 ) + { + } + + [Constructable] + public WildfireScroll( int amount ) + : base( 609, 0x2D5A, amount ) + { + Hue = 0x8FD; + } + + public WildfireScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EssenceOfWindScroll : SpellScroll + { + [Constructable] + public EssenceOfWindScroll() + : this( 1 ) + { + } + + [Constructable] + public EssenceOfWindScroll( int amount ) + : base( 610, 0x2D5B, amount ) + { + Hue = 0x8FD; + } + + public EssenceOfWindScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DryadAllureScroll : SpellScroll + { + [Constructable] + public DryadAllureScroll() + : this( 1 ) + { + } + + [Constructable] + public DryadAllureScroll( int amount ) + : base( 611, 0x2D5C, amount ) + { + Hue = 0x8FD; + } + + public DryadAllureScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EtherealVoyageScroll : SpellScroll + { + [Constructable] + public EtherealVoyageScroll() + : this( 1 ) + { + } + + [Constructable] + public EtherealVoyageScroll( int amount ) + : base( 612, 0x2D5D, amount ) + { + Hue = 0x8FD; + } + + public EtherealVoyageScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WordOfDeathScroll : SpellScroll + { + [Constructable] + public WordOfDeathScroll() + : this( 1 ) + { + } + + [Constructable] + public WordOfDeathScroll( int amount ) + : base( 613, 0x2D5E, amount ) + { + Hue = 0x8FD; + } + + public WordOfDeathScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GiftOfLifeScroll : SpellScroll + { + [Constructable] + public GiftOfLifeScroll() + : this( 1 ) + { + } + + [Constructable] + public GiftOfLifeScroll( int amount ) + : base( 614, 0x2D5F, amount ) + { + Hue = 0x8FD; + } + + public GiftOfLifeScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ArcaneEmpowermentScroll : SpellScroll + { + [Constructable] + public ArcaneEmpowermentScroll() + : this( 1 ) + { + } + + [Constructable] + public ArcaneEmpowermentScroll( int amount ) + : base( 615, 0x2D60, amount ) + { + Hue = 0x8FD; + } + + public ArcaneEmpowermentScroll( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs new file mode 100644 index 0000000..cee15bc --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/BlessScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BlessScroll : SpellScroll + { + [Constructable] + public BlessScroll() : this( 1 ) + { + } + + [Constructable] + public BlessScroll( int amount ) : base( 16, 0x1F3D, amount ) + { + } + + public BlessScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs new file mode 100644 index 0000000..8b54595 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/FireballScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class FireballScroll : SpellScroll + { + [Constructable] + public FireballScroll() : this( 1 ) + { + } + + [Constructable] + public FireballScroll( int amount ) : base( 17, 0x1F3E, amount ) + { + } + + public FireballScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs new file mode 100644 index 0000000..50c766a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/MagicLockScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MagicLockScroll : SpellScroll + { + [Constructable] + public MagicLockScroll() : this( 1 ) + { + } + + [Constructable] + public MagicLockScroll( int amount ) : base( 18, 0x1F3F, amount ) + { + } + + public MagicLockScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs new file mode 100644 index 0000000..ea57b27 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/PoisonScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PoisonScroll : SpellScroll + { + [Constructable] + public PoisonScroll() : this( 1 ) + { + } + + [Constructable] + public PoisonScroll( int amount ) : base( 19, 0x1F40, amount ) + { + } + + public PoisonScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinisisScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinisisScroll.cs new file mode 100644 index 0000000..4ba7e89 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/TelekinisisScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class TelekinisisScroll : SpellScroll + { + [Constructable] + public TelekinisisScroll() : this( 1 ) + { + } + + [Constructable] + public TelekinisisScroll( int amount ) : base( 20, 0x1F41, amount ) + { + } + + public TelekinisisScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs new file mode 100644 index 0000000..d7efe85 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/TeleportScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class TeleportScroll : SpellScroll + { + [Constructable] + public TeleportScroll() : this( 1 ) + { + } + + [Constructable] + public TeleportScroll( int amount ) : base( 21, 0x1F42, amount ) + { + } + + public TeleportScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs new file mode 100644 index 0000000..6f9815a --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/UnlockScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class UnlockScroll : SpellScroll + { + [Constructable] + public UnlockScroll() : this( 1 ) + { + } + + [Constructable] + public UnlockScroll( int amount ) : base( 22, 0x1F43, amount ) + { + } + + public UnlockScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs new file mode 100644 index 0000000..c45c437 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Scrolls/Third Circle/WallOfStoneScroll.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class WallOfStoneScroll : SpellScroll + { + [Constructable] + public WallOfStoneScroll() : this( 1 ) + { + } + + [Constructable] + public WallOfStoneScroll( int amount ) : base( 23, 0x1F44, amount ) + { + } + + public WallOfStoneScroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/Spellbook.cs b/Scripts/Items/Skill Items/Magical/Spellbook.cs new file mode 100644 index 0000000..383bf16 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/Spellbook.cs @@ -0,0 +1,1032 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Commands; +using Server.Engines.Craft; +using Server.Network; +using Server.Spells; +using Server.Targeting; +using Server.Mobiles; +namespace Server.Items +{ + public enum SpellbookType + { + Invalid = -1, + Regular, + Necromancer, + Paladin, + Ninja, + Samurai, + Druidic, + Arcanist + } + + public enum BookQuality + { + Regular, + Exceptional, + } + + public class Spellbook : Item, ICraftable, ISlayer + { + private string m_EngravedText; + private BookQuality m_Quality; + + [CommandProperty(AccessLevel.GameMaster)] + public string EngravedText + { + get { return m_EngravedText; } + set { m_EngravedText = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public BookQuality Quality + { + get { return m_Quality; } + set { m_Quality = value; InvalidateProperties(); } + } + + public static void Initialize() + { + EventSink.OpenSpellbookRequest += new OpenSpellbookRequestEventHandler( EventSink_OpenSpellbookRequest ); + EventSink.CastSpellRequest += new CastSpellRequestEventHandler( EventSink_CastSpellRequest ); + + CommandSystem.Register( "AllSpells", AccessLevel.GameMaster, new CommandEventHandler( AllSpells_OnCommand ) ); + } + + [Usage( "AllSpells" )] + [Description( "Completely fills a targeted spellbook with scrolls." )] + private static void AllSpells_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( AllSpells_OnTarget ) ); + e.Mobile.SendMessage( "Target the spellbook to fill." ); + } + + private static void AllSpells_OnTarget( Mobile from, object obj ) + { + if ( obj is Spellbook ) + { + Spellbook book = (Spellbook)obj; + + if ( book.BookCount == 64 ) + book.Content = ulong.MaxValue; + else + book.Content = (1ul << book.BookCount) - 1; + + from.SendMessage( "The spellbook has been filled." ); + + CommandLogging.WriteLine( from, "{0} {1} filling spellbook {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( book ) ); + } + else + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( AllSpells_OnTarget ) ); + from.SendMessage( "That is not a spellbook. Try again." ); + } + } + + private static void EventSink_OpenSpellbookRequest( OpenSpellbookRequestEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !Multis.DesignContext.Check( from ) ) + return; // They are customizing + + SpellbookType type; + + switch ( e.Type ) + { + default: + case 1: type = SpellbookType.Regular; break; + case 2: type = SpellbookType.Necromancer; break; + case 3: type = SpellbookType.Paladin; break; + case 4: type = SpellbookType.Ninja; break; + case 5: type = SpellbookType.Samurai; break; + case 6: type = SpellbookType.Arcanist; break; + case 7: type = SpellbookType.Druidic; break; + } + + Spellbook book = Spellbook.Find( from, -1, type ); + + if ( book != null ) + book.DisplayTo( from ); + } + + private static void EventSink_CastSpellRequest( CastSpellRequestEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !Multis.DesignContext.Check( from ) ) + return; // They are customizing + + Spellbook book = e.Spellbook as Spellbook; + int spellID = e.SpellID; + + if ( book == null || !book.HasSpell( spellID ) ) + book = Find( from, spellID ); + + if ( book != null && book.HasSpell( spellID ) ) + { + SpecialMove move = SpellRegistry.GetSpecialMove( spellID ); + + if ( move != null ) + { + SpecialMove.SetCurrentMove( from, move ); + } + else + { + Spell spell = SpellRegistry.NewSpell( spellID, from, null ); + + if ( spell != null ) + spell.Cast(); + else + from.SendLocalizedMessage( 502345 ); // This spell has been temporarily disabled. + } + } + else + { + from.SendLocalizedMessage( 500015 ); // You do not have that spell! + } + } + + private static Dictionary> m_Table = new Dictionary>(); + + public static SpellbookType GetTypeForSpell(int spellID) + { + if (spellID >= 0 && spellID < 64) + return SpellbookType.Regular; + else if (spellID >= 100 && spellID < 117) + return SpellbookType.Necromancer; + else if (spellID >= 200 && spellID < 210) + return SpellbookType.Paladin; + else if (spellID >= 400 && spellID < 406) + return SpellbookType.Samurai; + else if (spellID >= 500 && spellID < 508) + return SpellbookType.Ninja; + else if (spellID >= 600 && spellID < 617) + return SpellbookType.Arcanist; + else if (spellID >= 300 && spellID < 317) + return SpellbookType.Druidic; + + return SpellbookType.Invalid; + } + + public static Spellbook FindRegular( Mobile from ) + { + return Find( from, -1, SpellbookType.Regular ); + } + + public static Spellbook FindNecromancer( Mobile from ) + { + return Find( from, -1, SpellbookType.Necromancer ); + } + + public static Spellbook FindPaladin( Mobile from ) + { + return Find( from, -1, SpellbookType.Paladin ); + } + + public static Spellbook FindSamurai( Mobile from ) + { + return Find( from, -1, SpellbookType.Samurai ); + } + + public static Spellbook FindNinja( Mobile from ) + { + return Find( from, -1, SpellbookType.Ninja ); + } + + public static Spellbook FindArcanist( Mobile from ) + { + return Find( from, -1, SpellbookType.Arcanist ); + } + public static Spellbook FindDruidic(Mobile from) + { + return Find(from, -1, SpellbookType.Druidic); + } + + public static Spellbook Find( Mobile from, int spellID ) + { + return Find( from, spellID, GetTypeForSpell( spellID ) ); + } + + public static Spellbook Find( Mobile from, int spellID, SpellbookType type ) + { + if ( from == null ) + return null; + + if ( from.Deleted ) + { + m_Table.Remove( from ); + return null; + } + + List list = null; + + m_Table.TryGetValue( from, out list ); + + bool searchAgain = false; + + if ( list == null ) + m_Table[from] = list = FindAllSpellbooks( from ); + else + searchAgain = true; + + Spellbook book = FindSpellbookInList( list, from, spellID, type ); + + // Scriptiz : Si le bouquin contenant le sort n'est pas le bouquin �quipp�, on refait une recherche ! + // Ajout : || (GetTypeForSpell(spellID) != SpellbookType.Regular && book != FindEquippedSpellbook(from)) + // Scriptiz edit 24/04/12 : on retire les modifs d�gueu + if ((book == null && searchAgain))// || (GetTypeForSpell(spellID) != SpellbookType.Regular && book != FindEquippedSpellbook(from))) + { + m_Table[from] = list = FindAllSpellbooks( from ); + + book = FindSpellbookInList( list, from, spellID, type ); + } + + return book; + } + + public static Spellbook FindSpellbookInList( List list, Mobile from, int spellID, SpellbookType type ) + { + // Scriptiz 25/04/12 : on fait un check propre pour voir si il y a un spellbook �quipp�, si oui, et s'il s'agit + // d'un spellbook du m�me type que le sort cast�, il faut trouv� le sort uniquement dans ce livre �quipp� ! + Spellbook sb = FindEquippedSpellbook(from); + if (sb != null && sb.SpellbookType == GetTypeForSpell(spellID)) + return sb; + + Container pack = from.Backpack; + + for ( int i = list.Count - 1; i >= 0; --i ) + { + if ( i >= list.Count ) + continue; + + Spellbook book = list[i]; + + if ( !book.Deleted && (book.Parent == from || (pack != null && book.Parent == pack)) && ValidateSpellbook( book, spellID, type ) ) + return book; + + list.RemoveAt( i ); + } + + return null; + } + + public static List FindAllSpellbooks( Mobile from ) + { + List list = new List(); + + Item item = from.FindItemOnLayer( Layer.OneHanded ); + + if ( item is Spellbook ) + list.Add( (Spellbook)item ); + + // Scriptiz : s'il y a un livre �quip�, le sort doit venir de ce livre et pas d'un autre dans le sac ! + // Scriptiz edit 24/04/12 : on retire les modifs d�gueu + //if (list.Count > 0 && ((Spellbook)item).SpellbookType == SpellbookType.Regular) + // return list; + // Scriptiz : cette m�thode doit retourner tous les spellbooks, pas bien de l'alt�rer :p + + Container pack = from.Backpack; + + if ( pack == null ) + return list; + + for ( int i = 0; i < pack.Items.Count; ++i ) + { + item = pack.Items[i]; + + if ( item is Spellbook ) + list.Add( (Spellbook)item ); + } + + return list; + } + + public static Spellbook FindEquippedSpellbook( Mobile from ) + { + return (from.FindItemOnLayer( Layer.OneHanded ) as Spellbook); + } + + public static bool ValidateSpellbook( Spellbook book, int spellID, SpellbookType type ) + { + return ( book.SpellbookType == type && ( spellID == -1 || book.HasSpell( spellID ) ) ); + } + + public override bool DisplayWeight { get { return false; } } + + private AosAttributes m_AosAttributes; + private AosSkillBonuses m_AosSkillBonuses; + + [CommandProperty( AccessLevel.GameMaster )] + public AosAttributes Attributes + { + get{ return m_AosAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosSkillBonuses SkillBonuses + { + get{ return m_AosSkillBonuses; } + set{} + } + + public virtual SpellbookType SpellbookType{ get{ return SpellbookType.Regular; } } + public virtual int BookOffset{ get{ return 0; } } + public virtual int BookCount{ get{ return 64; } } + + private ulong m_Content; + private int m_Count; + + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) + { + if (!Ethics.Ethic.CheckTrade(from, to, newOwner, this)) + return false; + + if (to.AccessLevel != AccessLevel.Player) + return base.AllowSecureTrade(from, to, newOwner, accepted); + + /* Scriptiz : plus besoin de ne pas pouvoir �quiper un livre si on on poss�de plusieurs */ + //if (this.SpellbookType == SpellbookType.Regular) + //{ + // Item item = to.FindItemOnLayer(Layer.OneHanded); + // if (item is Spellbook && ((Spellbook)item).SpellbookType == SpellbookType.Regular) + // { + // to.PlaceInBackpack(item); + // to.SendMessage("Vous posez votre livre dans votre sac"); + // } + //} + + return base.AllowSecureTrade(from, to, newOwner, accepted); + } + + /* Scriptiz : plus besoin de ne pas pouvoir �quiper un livre si on on poss�de plusieurs */ + //public override bool DropToItem(Mobile from, Item target, Point3D p) + //{ + // if (from.AccessLevel != AccessLevel.Player) + // return base.DropToItem(from, target, p); + + // if (this.SpellbookType == SpellbookType.Regular) + // { + // Item item = from.FindItemOnLayer(Layer.OneHanded); + // if (item is Spellbook && ((Spellbook)item).SpellbookType == SpellbookType.Regular) + // { + // from.PlaceInBackpack(item); + // from.SendMessage("Vous posez votre livre dans votre sac"); + // } + // } + // return base.DropToItem(from, target, p); + //} + + //public override bool OnDroppedInto(Mobile from, Container target, Point3D p) + //{ + // if (from.AccessLevel != AccessLevel.Player) + // return base.OnDroppedInto(from, target, p); + + // if(this.SpellbookType == SpellbookType.Regular) + // { + // Item item = from.FindItemOnLayer(Layer.OneHanded); + // if (item is Spellbook && ((Spellbook)item).SpellbookType == SpellbookType.Regular) + // { + // from.PlaceInBackpack(item); + // from.SendMessage("Vous posez votre livre dans votre sac"); + // } + // } + // return base.OnDroppedInto(from, target, p); + //} + + //public override bool OnDroppedToMobile(Mobile from, Mobile target) + //{ + // if (from.AccessLevel != AccessLevel.Player) + // return base.OnDroppedToMobile(from, target); + + // if (this.SpellbookType == SpellbookType.Regular) + // { + // Item item = from.FindItemOnLayer(Layer.OneHanded); + // if (item is Spellbook && ((Spellbook)item).SpellbookType == SpellbookType.Regular) + // { + // from.PlaceInBackpack(item); + // from.SendMessage("Vous posez votre livre dans votre sac"); + // } + // } + // return base.OnDroppedToMobile(from, target); + //} + + public override bool CanEquip( Mobile from ) + { + if (!Ethics.Ethic.CheckEquip(from, this)) + { + return false; + } + else if (!from.CanBeginAction(typeof(BaseWeapon))) + { + return false; + } + /* Scriptiz : plus besoin de ne pas pouvoir �quiper un livre si on on poss�de plusieurs */ + //else if (from.AccessLevel != AccessLevel.Player) + // return true; + //else if (this.SpellbookType == SpellbookType.Regular) + //{ + // Container c = from.Backpack; + // if (c == null) + // return base.CanEquip(from); + // int count = 0; + // Item[] found = c.FindItemsByType(typeof(Spellbook), true); + + // for (int i = 0; i < found.Length; ++i) + // { + // Spellbook book = (Spellbook)found[i]; + // if (book.SpellbookType == SpellbookType.Regular) + // count++; + // } + + // if (count > 0) + // { + // from.SendMessage("Vous ne pouvez �quiper un livre en en tenant autant dans votre sac"); + // return false; + // } + //} + + return base.CanEquip( from ); + } + + public override bool AllowEquipedCast( Mobile from ) + { + return true; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is SpellScroll && dropped.Amount == 1 ) + { + SpellScroll scroll = (SpellScroll)dropped; + + SpellbookType type = GetTypeForSpell( scroll.SpellID ); + + if ( type != this.SpellbookType ) + { + return false; + } + else if ( HasSpell( scroll.SpellID ) ) + { + from.SendLocalizedMessage( 500179 ); // That spell is already present in that spellbook. + return false; + } + else + { + int val = scroll.SpellID - BookOffset; + + if ( val >= 0 && val < BookCount ) + { + m_Content |= (ulong)1 << val; + ++m_Count; + + InvalidateProperties(); + + scroll.Delete(); + + from.Send( new PlaySound( 0x249, GetWorldLocation() ) ); + return true; + } + + return false; + } + } + else + { + return false; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ulong Content + { + get + { + return m_Content; + } + set + { + if ( m_Content != value ) + { + m_Content = value; + + m_Count = 0; + + while ( value > 0 ) + { + m_Count += (int)(value & 0x1); + value >>= 1; + } + + InvalidateProperties(); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpellCount + { + get + { + return m_Count; + } + } + + [Constructable] + public Spellbook() : this( (ulong)0 ) + { + } + + [Constructable] + public Spellbook( ulong content ) : this( content, 0xEFA ) + { + } + + public Spellbook( ulong content, int itemID ) : base( itemID ) + { + m_AosAttributes = new AosAttributes( this ); + m_AosSkillBonuses = new AosSkillBonuses( this ); + + Weight = 3.0; + Layer = Layer.OneHanded; + LootType = LootType.Blessed; + + Content = content; + } + + public override void OnAfterDuped( Item newItem ) + { + Spellbook book = newItem as Spellbook; + + if ( book == null ) + return; + + book.m_AosAttributes = new AosAttributes( newItem, m_AosAttributes ); + book.m_AosSkillBonuses = new AosSkillBonuses( newItem, m_AosSkillBonuses ); + } + + public override void OnAdded( object parent ) + { + if ( Core.AOS && parent is Mobile ) + { + Mobile from = (Mobile)parent; + + m_AosSkillBonuses.AddTo( from ); + + int strBonus = m_AosAttributes.BonusStr; + int dexBonus = m_AosAttributes.BonusDex; + int intBonus = m_AosAttributes.BonusInt; + + if ( strBonus != 0 || dexBonus != 0 || intBonus != 0 ) + { + string modName = this.Serial.ToString(); + + if ( strBonus != 0 ) + from.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + from.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + from.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + from.CheckStatTimers(); + } + } + + public override void OnRemoved( object parent ) + { + if ( Core.AOS && parent is Mobile ) + { + Mobile from = (Mobile)parent; + + m_AosSkillBonuses.Remove(); + + string modName = this.Serial.ToString(); + + from.RemoveStatMod( modName + "Str" ); + from.RemoveStatMod( modName + "Dex" ); + from.RemoveStatMod( modName + "Int" ); + + from.CheckStatTimers(); + } + } + + public bool HasSpell( int spellID ) + { + spellID -= BookOffset; + + return ( spellID >= 0 && spellID < BookCount && (m_Content & ((ulong)1 << spellID)) != 0 ); + } + + public Spellbook( Serial serial ) : base( serial ) + { + } + + public void DisplayTo( Mobile to ) + { + // The client must know about the spellbook or it will crash! + + NetState ns = to.NetState; + + if ( ns == null ) + return; + + if ( Parent == null ) + { + to.Send( this.WorldPacket ); + } + else if ( Parent is Item ) + { + // What will happen if the client doesn't know about our parent? + if ( ns.ContainerGridLines ) + to.Send( new ContainerContentUpdate6017( this ) ); + else + to.Send( new ContainerContentUpdate( this ) ); + } + else if ( Parent is Mobile ) + { + // What will happen if the client doesn't know about our parent? + to.Send( new EquipUpdate( this ) ); + } + + if ( ns.HighSeas ) + to.Send( new DisplaySpellbookHS( this ) ); + else + to.Send( new DisplaySpellbook( this ) ); + + if ( Core.AOS ) { + if ( ns.NewSpellbook ) { + to.Send( new NewSpellbookContent( this, ItemID, BookOffset + 1, m_Content ) ); + } else { + to.Send( new SpellbookContent( m_Count, BookOffset + 1, m_Content, this ) ); + } + } + else { + if ( ns.ContainerGridLines ) { + to.Send( new SpellbookContent6017( m_Count, BookOffset + 1, m_Content, this ) ); + } else { + to.Send( new SpellbookContent( m_Count, BookOffset + 1, m_Content, this ) ); + } + } + } + + private Mobile m_Crafter; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + public override bool DisplayLootType{ get{ return Core.AOS; } } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if (m_Quality == BookQuality.Exceptional) + list.Add(1063341); // exceptional + + if (m_EngravedText != null) + list.Add(1072305, m_EngravedText); // Engraved: ~1_INSCRIPTION~ + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + m_AosSkillBonuses.GetProperties( list ); + + if( m_Slayer != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer ); + if( entry != null ) + list.Add( entry.Title ); + } + + if( m_Slayer2 != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 ); + if( entry != null ) + list.Add( entry.Title ); + } + + int prop; + + if ( (prop = m_AosAttributes.WeaponDamage) != 0 ) + list.Add( 1060401, prop.ToString() ); // damage increase ~1_val~% + + if ( (prop = m_AosAttributes.DefendChance) != 0 ) + list.Add( 1060408, prop.ToString() ); // defense chance increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusDex) != 0 ) + list.Add( 1060409, prop.ToString() ); // dexterity bonus ~1_val~ + + if ( (prop = m_AosAttributes.EnhancePotions) != 0 ) + list.Add( 1060411, prop.ToString() ); // enhance potions ~1_val~% + + if ( (prop = m_AosAttributes.CastRecovery) != 0 ) + list.Add( 1060412, prop.ToString() ); // faster cast recovery ~1_val~ + + if ( (prop = m_AosAttributes.CastSpeed) != 0 ) + list.Add( 1060413, prop.ToString() ); // faster casting ~1_val~ + + if ( (prop = m_AosAttributes.AttackChance) != 0 ) + list.Add( 1060415, prop.ToString() ); // hit chance increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusHits) != 0 ) + list.Add( 1060431, prop.ToString() ); // hit point increase ~1_val~ + + if ( (prop = m_AosAttributes.BonusInt) != 0 ) + list.Add( 1060432, prop.ToString() ); // intelligence bonus ~1_val~ + + if ( (prop = m_AosAttributes.LowerManaCost) != 0 ) + list.Add( 1060433, prop.ToString() ); // lower mana cost ~1_val~% + + if ( (prop = m_AosAttributes.LowerRegCost) != 0 ) + list.Add( 1060434, prop.ToString() ); // lower reagent cost ~1_val~% + + if ( (prop = m_AosAttributes.Luck) != 0 ) + list.Add( 1060436, prop.ToString() ); // luck ~1_val~ + + if ( (prop = m_AosAttributes.BonusMana) != 0 ) + list.Add( 1060439, prop.ToString() ); // mana increase ~1_val~ + + if ( (prop = m_AosAttributes.RegenMana) != 0 ) + list.Add( 1060440, prop.ToString() ); // mana regeneration ~1_val~ + + if ( (prop = m_AosAttributes.NightSight) != 0 ) + list.Add( 1060441 ); // night sight + + if ( (prop = m_AosAttributes.ReflectPhysical) != 0 ) + list.Add( 1060442, prop.ToString() ); // reflect physical damage ~1_val~% + + if ( (prop = m_AosAttributes.RegenStam) != 0 ) + list.Add( 1060443, prop.ToString() ); // stamina regeneration ~1_val~ + + if ( (prop = m_AosAttributes.RegenHits) != 0 ) + list.Add( 1060444, prop.ToString() ); // hit point regeneration ~1_val~ + + if ( (prop = m_AosAttributes.SpellChanneling) != 0 ) + list.Add( 1060482 ); // spell channeling + + if ( (prop = m_AosAttributes.SpellDamage) != 0 ) + list.Add( 1060483, prop.ToString() ); // spell damage increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusStam) != 0 ) + list.Add( 1060484, prop.ToString() ); // stamina increase ~1_val~ + + if ( (prop = m_AosAttributes.BonusStr) != 0 ) + list.Add( 1060485, prop.ToString() ); // strength bonus ~1_val~ + + if ( (prop = m_AosAttributes.WeaponSpeed) != 0 ) + list.Add( 1060486, prop.ToString() ); // swing speed increase ~1_val~% + + if (Core.ML && (prop = m_AosAttributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + list.Add( 1042886, m_Count.ToString() ); // ~1_NUMBERS_OF_SPELLS~ Spells + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( m_Crafter != null ) + this.LabelTo( from, 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + this.LabelTo( from, 1042886, m_Count.ToString() ); + } + + public override void OnDoubleClick( Mobile from ) + { + Container pack = from.Backpack; + + if ( Parent == from || ( pack != null && Parent == pack ) ) + DisplayTo( from ); + else + from.SendLocalizedMessage( 500207 ); // The spellbook must be in your backpack (and not in a container within) to open. + } + + + private SlayerName m_Slayer; + private SlayerName m_Slayer2; + //Currently though there are no dual slayer spellbooks, OSI has a habit of putting dual slayer stuff in later + + [CommandProperty( AccessLevel.GameMaster )] + public SlayerName Slayer + { + get { return m_Slayer; } + set { m_Slayer = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SlayerName Slayer2 + { + get { return m_Slayer2; } + set { m_Slayer2 = value; InvalidateProperties(); } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write((int)6); // version + + writer.Write((byte)m_Quality); + + writer.Write((string)m_EngravedText); + + writer.Write( m_Crafter ); + + writer.Write( (int)m_Slayer ); + writer.Write( (int)m_Slayer2 ); + + m_AosAttributes.Serialize( writer ); + m_AosSkillBonuses.Serialize( writer ); + + writer.Write( m_Content ); + writer.Write( m_Count ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 6: + { + m_Quality = (BookQuality)reader.ReadByte(); + + goto case 5; + } + case 5: + { + m_EngravedText = reader.ReadString(); + + goto case 4; + } + case 4: + { + goto case 3; + } + case 3: + { + m_Crafter = reader.ReadMobile(); + goto case 2; + } + case 2: + { + m_Slayer = (SlayerName)reader.ReadInt(); + m_Slayer2 = (SlayerName)reader.ReadInt(); + goto case 1; + } + case 1: + { + m_AosAttributes = new AosAttributes( this, reader ); + m_AosSkillBonuses = new AosSkillBonuses( this, reader ); + + goto case 0; + } + case 0: + { + m_Content = reader.ReadULong(); + m_Count = reader.ReadInt(); + + break; + } + } + + // Scriptiz : on retire les deux slayers de tous les livres + if (version == 3) + { + m_Slayer = SlayerName.None; + m_Slayer2 = SlayerName.None; + } + + if ( m_AosAttributes == null ) + m_AosAttributes = new AosAttributes( this ); + + if ( m_AosSkillBonuses == null ) + m_AosSkillBonuses = new AosSkillBonuses( this ); + + if ( Core.AOS && Parent is Mobile ) + m_AosSkillBonuses.AddTo( (Mobile) Parent ); + + int strBonus = m_AosAttributes.BonusStr; + int dexBonus = m_AosAttributes.BonusDex; + int intBonus = m_AosAttributes.BonusInt; + + if ( Parent is Mobile && (strBonus != 0 || dexBonus != 0 || intBonus != 0) ) + { + Mobile m = (Mobile)Parent; + + string modName = Serial.ToString(); + + if ( strBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + if ( Parent is Mobile ) + ((Mobile)Parent).CheckStatTimers(); + } + + private static int[] m_LegendPropertyCounts = new int[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 21/52 : 40% + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 15/52 : 29% + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2 properties : 10/52 : 19% + 3, 3, 3, 3, 3, 3 // 3 properties : 6/52 : 12% + + }; + + private static int[] m_ElderPropertyCounts = new int[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,// 0 properties : 15/34 : 44% + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 10/34 : 29% + 2, 2, 2, 2, 2, 2, // 2 properties : 6/34 : 18% + 3, 3, 3 // 3 properties : 3/34 : 9% + }; + + private static int[] m_GrandPropertyCounts = new int[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 10/20 : 50% + 1, 1, 1, 1, 1, 1, // 1 property : 6/20 : 30% + 2, 2, 2, // 2 properties : 3/20 : 15% + 3 // 3 properties : 1/20 : 5% + }; + + private static int[] m_MasterPropertyCounts = new int[] + { + 0, 0, 0, 0, 0, 0, // 0 properties : 6/10 : 60% + 1, 1, 1, // 1 property : 3/10 : 30% + 2 // 2 properties : 1/10 : 10% + }; + + private static int[] m_AdeptPropertyCounts = new int[] + { + 0, 0, 0, // 0 properties : 3/4 : 75% + 1 // 1 property : 1/4 : 25% + }; + + public virtual int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + int magery = from.Skills.Magery.BaseFixedPoint; + + if ( magery >= 800 ) + { + int[] propertyCounts; + int minIntensity; + int maxIntensity; + + if ( magery >= 1000 ) + { + if( magery >= 1200 ) + propertyCounts = m_LegendPropertyCounts; + else if( magery >= 1100 ) + propertyCounts = m_ElderPropertyCounts; + else + propertyCounts = m_GrandPropertyCounts; + + minIntensity = 55; + maxIntensity = 75; + } + else if ( magery >= 900 ) + { + propertyCounts = m_MasterPropertyCounts; + minIntensity = 25; + maxIntensity = 45; + } + else + { + propertyCounts = m_AdeptPropertyCounts; + minIntensity = 0; + maxIntensity = 15; + } + + int propertyCount = propertyCounts[Utility.Random( propertyCounts.Length )]; + + BaseRunicTool.ApplyAttributesTo( this, true, 0, propertyCount, minIntensity, maxIntensity ); + } + + if ( makersMark ) + Crafter = from; + + m_Quality = (BookQuality)(quality - 1); + + return quality; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Magical/SpellweavingBook.cs b/Scripts/Items/Skill Items/Magical/SpellweavingBook.cs new file mode 100644 index 0000000..2bf4194 --- /dev/null +++ b/Scripts/Items/Skill Items/Magical/SpellweavingBook.cs @@ -0,0 +1,44 @@ +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class SpellweavingBook : Spellbook + { + public override SpellbookType SpellbookType{ get{ return SpellbookType.Arcanist; } } + public override int BookOffset{ get{ return 600; } } + public override int BookCount{ get{ return 16; } } + + [Constructable] + public SpellweavingBook() : this( (ulong)0 ) + { + } + + [Constructable] + public SpellweavingBook( ulong content ) : base( content, 0x2D50 ) + { + Hue = 0x8A2; + + Layer = Layer.OneHanded; + } + + public SpellweavingBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Misc/Bandage.cs b/Scripts/Items/Skill Items/Misc/Bandage.cs new file mode 100644 index 0000000..c26fb20 --- /dev/null +++ b/Scripts/Items/Skill Items/Misc/Bandage.cs @@ -0,0 +1,540 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class Bandage : Item, IDyable + { + public static int Range = ( Core.AOS ? 2 : 1 ); + + public override double DefaultWeight + { + get { return 0.1; } + } + + [Constructable] + public Bandage() : this( 1 ) + { + } + + [Constructable] + public Bandage( int amount ) : base( 0xE21 ) + { + Stackable = true; + Amount = amount; + } + + public Bandage( Serial serial ) : base( serial ) + { + } + + public virtual bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + // Scriptiz : ajout d'une m�thode pour la commande .bandself + public static void BandSelfCommandCall(Mobile from, Item m_Bandage) + { + from.RevealingAction(); + + if (BandageContext.BeginHeal(from, from) != null && !Engines.ConPVP.DuelContext.IsFreeConsume(from)) + m_Bandage.Consume(); + + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), Range ) ) + { + from.RevealingAction(); + + from.SendLocalizedMessage( 500948 ); // Who will you use the bandages on? + + from.Target = new InternalTarget( this ); + } + else + { + from.SendLocalizedMessage( 500295 ); // You are too far away to do that. + } + } + + private class InternalTarget : Target + { + private Bandage m_Bandage; + + public InternalTarget( Bandage bandage ) : base( Bandage.Range, false, TargetFlags.Beneficial ) + { + m_Bandage = bandage; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Bandage.Deleted ) + return; + + if ( targeted is Mobile ) + { + if ( from.InRange( m_Bandage.GetWorldLocation(), Bandage.Range ) ) + { + if ( BandageContext.BeginHeal( from, (Mobile)targeted ) != null ) + { + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + m_Bandage.Consume(); + } + } + else + { + from.SendLocalizedMessage( 500295 ); // You are too far away to do that. + } + } + else if ( targeted is PlagueBeastInnard ) + { + if ( ((PlagueBeastInnard) targeted).OnBandage( from ) ) + m_Bandage.Consume(); + } + else + { + from.SendLocalizedMessage( 500970 ); // Bandages can not be used on that. + } + } + + protected override void OnNonlocalTarget( Mobile from, object targeted ) + { + if ( targeted is PlagueBeastInnard ) + { + if ( ((PlagueBeastInnard) targeted).OnBandage( from ) ) + m_Bandage.Consume(); + } + else + base.OnNonlocalTarget( from, targeted ); + } + } + } + + public class BandageContext + { + private Mobile m_Healer; + private Mobile m_Patient; + private int m_Slips; + private Timer m_Timer; + + public Mobile Healer{ get{ return m_Healer; } } + public Mobile Patient{ get{ return m_Patient; } } + public int Slips{ get{ return m_Slips; } set{ m_Slips = value; } } + public Timer Timer{ get{ return m_Timer; } } + + public void Slip() + { + m_Healer.SendLocalizedMessage( 500961 ); // Your fingers slip! + ++m_Slips; + } + + public BandageContext( Mobile healer, Mobile patient, TimeSpan delay ) + { + m_Healer = healer; + m_Patient = patient; + + m_Timer = new InternalTimer( this, delay ); + m_Timer.Start(); + } + + public void StopHeal() + { + m_Table.Remove( m_Healer ); + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + + private static Dictionary m_Table = new Dictionary(); + + public static BandageContext GetContext( Mobile healer ) + { + BandageContext bc = null; + m_Table.TryGetValue( healer, out bc ); + return bc; + } + + public static SkillName GetPrimarySkill( Mobile m ) + { + if ( !m.Player && (m.Body.IsMonster || m.Body.IsAnimal) ) + return SkillName.Veterinary; + else + return SkillName.Healing; + } + + public static SkillName GetSecondarySkill( Mobile m ) + { + if ( !m.Player && (m.Body.IsMonster || m.Body.IsAnimal) ) + return SkillName.AnimalLore; + else + return SkillName.Anatomy; + } + + public void EndHeal() + { + StopHeal(); + + int healerNumber = -1, patientNumber = -1; + bool playSound = true; + bool checkSkills = false; + + // Scriptiz : ajout pour le bloody bandage system + switch (Utility.Random(4)) + { + case 0: m_Healer.AddToBackpack(new BloodyBandage(1)); + m_Healer.SendMessage("You were able to recover a bloody bandage from what you used."); break; + } + + SkillName primarySkill = GetPrimarySkill( m_Patient ); + SkillName secondarySkill = GetSecondarySkill( m_Patient ); + + BaseCreature petPatient = m_Patient as BaseCreature; + + if ( !m_Healer.Alive ) + { + healerNumber = 500962; // You were unable to finish your work before you died. + patientNumber = -1; + playSound = false; + } + else if ( !m_Healer.InRange( m_Patient, Bandage.Range ) ) + { + healerNumber = 500963; // You did not stay close enough to heal your target. + patientNumber = -1; + playSound = false; + } + else if ( !m_Patient.Alive || (petPatient != null && petPatient.IsDeadPet) ) + { + double healing = m_Healer.Skills[primarySkill].Value; + double anatomy = m_Healer.Skills[secondarySkill].Value; + double chance = ((healing - 68.0) / 50.0) - (m_Slips * 0.02); + + if (( (checkSkills = (healing >= 80.0 && anatomy >= 80.0)) && chance > Utility.RandomDouble() ) + || ( Core.SE && petPatient is Factions.FactionWarHorse && petPatient.ControlMaster == m_Healer) ) //TODO: Dbl check doesn't check for faction of the horse here? + { + if ( m_Patient.Map == null || !m_Patient.Map.CanFit( m_Patient.Location, 16, false, false ) ) + { + healerNumber = 501042; // Target can not be resurrected at that location. + patientNumber = 502391; // Thou can not be resurrected there! + } + else if ( m_Patient.Region != null && m_Patient.Region.IsPartOf( "Khaldun" ) ) + { + healerNumber = 1010395; // The veil of death in this area is too strong and resists thy efforts to restore life. + patientNumber = -1; + } + else + { + healerNumber = 500965; // You are able to resurrect your patient. + patientNumber = -1; + + m_Patient.PlaySound( 0x214 ); + m_Patient.FixedEffect( 0x376A, 10, 16 ); + + if ( petPatient != null && petPatient.IsDeadPet ) + { + Mobile master = petPatient.ControlMaster; + + if( master != null && m_Healer == master ) + { + petPatient.ResurrectPet(); + + int Penalty = petPatient.CalculatePenalty(m_Healer); + + for ( int i = 0; i < Penalty ; ++i ) + { + petPatient.Skills[Utility.RandomList(1,16,25,26,27,30,43,46)].Base -= 0.1; + } + } + else if ( master != null && master.InRange( petPatient, 3 ) ) + { + healerNumber = 503255; // You are able to resurrect the creature. + + master.CloseGump( typeof( PetResurrectGump ) ); + master.SendGump( new PetResurrectGump( m_Healer, petPatient ) ); + } + else + { + bool found = false; + + List friends = petPatient.Friends; + + for ( int i = 0; friends != null && i < friends.Count; ++i ) + { + Mobile friend = friends[i]; + + if ( friend.InRange( petPatient, 3 ) ) + { + healerNumber = 503255; // You are able to resurrect the creature. + + friend.CloseGump( typeof( PetResurrectGump ) ); + friend.SendGump( new PetResurrectGump( m_Healer, petPatient ) ); + + found = true; + break; + } + } + + if ( !found ) + healerNumber = 1049670; // The pet's owner must be nearby to attempt resurrection. + } + } + else + { + m_Patient.CloseGump( typeof( ResurrectGump ) ); + m_Patient.SendGump( new ResurrectGump( m_Patient, m_Healer ) ); + } + } + } + else + { + if ( petPatient != null && petPatient.IsDeadPet ) + healerNumber = 503256; // You fail to resurrect the creature. + else + healerNumber = 500966; // You are unable to resurrect your patient. + + patientNumber = -1; + } + } + else if ( m_Patient.Poisoned ) + { + m_Healer.SendLocalizedMessage( 500969 ); // You finish applying the bandages. + + double healing = m_Healer.Skills[primarySkill].Value; + double anatomy = m_Healer.Skills[secondarySkill].Value; + double chance = ((healing - 30.0) / 50.0) - (m_Patient.Poison.Level * 0.1) - (m_Slips * 0.02); + + if ( (checkSkills = (healing >= 60.0 && anatomy >= 60.0)) && chance > Utility.RandomDouble() ) + { + if ( m_Patient.CurePoison( m_Healer ) ) + { + healerNumber = (m_Healer == m_Patient) ? -1 : 1010058; // You have cured the target of all poisons. + patientNumber = 1010059; // You have been cured of all poisons. + } + else + { + healerNumber = -1; + patientNumber = -1; + } + } + else + { + healerNumber = 1010060; // You have failed to cure your target! + patientNumber = -1; + } + } + else if ( BleedAttack.IsBleeding( m_Patient ) ) + { + healerNumber = 1060088; // You bind the wound and stop the bleeding + patientNumber = 1060167; // The bleeding wounds have healed, you are no longer bleeding! + + BleedAttack.EndBleed( m_Patient, false ); + } + else if ( MortalStrike.IsWounded( m_Patient ) ) + { + healerNumber = ( m_Healer == m_Patient ? 1005000 : 1010398 ); + patientNumber = -1; + playSound = false; + } + else if ( m_Patient.Hits == m_Patient.HitsMax ) + { + healerNumber = 500967; // You heal what little damage your patient had. + patientNumber = -1; + } + else + { + checkSkills = true; + patientNumber = -1; + + double healing = m_Healer.Skills[primarySkill].Value; + double anatomy = m_Healer.Skills[secondarySkill].Value; + double chance = ((healing + 10.0) / 100.0) - (m_Slips * 0.02); + + if ( chance > Utility.RandomDouble() ) + { + healerNumber = 500969; // You finish applying the bandages. + + double min, max; + + if ( Core.AOS ) + { + min = (anatomy / 8.0) + (healing / 5.0) + 4.0; + max = (anatomy / 6.0) + (healing / 2.5) + 4.0; + } + else + { + min = (anatomy / 5.0) + (healing / 5.0) + 3.0; + max = (anatomy / 5.0) + (healing / 2.0) + 10.0; + } + + double toHeal = min + (Utility.RandomDouble() * (max - min)); + + if ( m_Patient.Body.IsMonster || m_Patient.Body.IsAnimal ) + toHeal += m_Patient.HitsMax / 100; + + if ( Core.AOS ) + toHeal -= toHeal * m_Slips * 0.35; // TODO: Verify algorithm + else + toHeal -= m_Slips * 4; + + if ( toHeal < 1 ) + { + toHeal = 1; + healerNumber = 500968; // You apply the bandages, but they barely help. + } + + m_Patient.Heal( (int) toHeal, m_Healer, false ); + } + else + { + healerNumber = 500968; // You apply the bandages, but they barely help. + playSound = false; + } + } + + if ( healerNumber != -1 ) + m_Healer.SendLocalizedMessage( healerNumber ); + + if ( patientNumber != -1 ) + m_Patient.SendLocalizedMessage( patientNumber ); + + if ( playSound ) + m_Patient.PlaySound( 0x57 ); + + if ( checkSkills ) + { + m_Healer.CheckSkill( secondarySkill, 0.0, 120.0 ); + m_Healer.CheckSkill( primarySkill, 0.0, 120.0 ); + } + } + + private class InternalTimer : Timer + { + private BandageContext m_Context; + + public InternalTimer( BandageContext context, TimeSpan delay ) : base( delay ) + { + m_Context = context; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Context.EndHeal(); + } + } + + public static BandageContext BeginHeal( Mobile healer, Mobile patient ) + { + bool isDeadPet = ( patient is BaseCreature && ((BaseCreature)patient).IsDeadPet ); + + if ( patient is Golem ) + { + healer.SendLocalizedMessage( 500970 ); // Bandages cannot be used on that. + } + else if ( patient is BaseCreature && ((BaseCreature)patient).IsAnimatedDead ) + { + healer.SendLocalizedMessage( 500951 ); // You cannot heal that. + } + else if ( !patient.Poisoned && patient.Hits == patient.HitsMax && !BleedAttack.IsBleeding( patient ) && !isDeadPet ) + { + healer.SendLocalizedMessage( 500955 ); // That being is not damaged! + } + else if ( !patient.Alive && (patient.Map == null || !patient.Map.CanFit( patient.Location, 16, false, false )) ) + { + healer.SendLocalizedMessage( 501042 ); // Target cannot be resurrected at that location. + } + else if ( healer.CanBeBeneficial( patient, true, true ) ) + { + healer.DoBeneficial( patient ); + + bool onSelf = ( healer == patient ); + int dex = healer.Dex; + + double seconds; + double resDelay = ( patient.Alive ? 0.0 : 5.0 ); + + if ( onSelf ) + { + if ( Core.AOS ) + seconds = 5.0 + (0.5 * ((double)(120 - dex) / 10)); // TODO: Verify algorithm + else + seconds = 9.4 + (0.6 * ((double)(120 - dex) / 10)); + } + else + { + if ( Core.AOS && GetPrimarySkill( patient ) == SkillName.Veterinary ) + { + seconds = 2.0; + } + else if ( Core.AOS ) + { + if (dex < 204) + { + seconds = 3.2-(Math.Sin((double)dex/130)*2.5) + resDelay; + } + else + { + seconds = 0.7 + resDelay; + } + } + else + { + if ( dex >= 100 ) + seconds = 3.0 + resDelay; + else if ( dex >= 40 ) + seconds = 4.0 + resDelay; + else + seconds = 5.0 + resDelay; + } + } + + BandageContext context = GetContext( healer ); + + if ( context != null ) + context.StopHeal(); + seconds *= 1000; + + context = new BandageContext( healer, patient, TimeSpan.FromMilliseconds( seconds ) ); + + m_Table[healer] = context; + + if ( !onSelf ) + patient.SendLocalizedMessage( 1008078, false, healer.Name ); // : Attempting to heal you. + + + healer.SendLocalizedMessage( 500956 ); // You begin applying the bandages. + return context; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Misc/FireHorn.cs b/Scripts/Items/Skill Items/Misc/FireHorn.cs new file mode 100644 index 0000000..52f9b37 --- /dev/null +++ b/Scripts/Items/Skill Items/Misc/FireHorn.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Spells; + +namespace Server.Items +{ + public class FireHorn : Item + { + public override int LabelNumber{ get{ return 1060456; } } // fire horn + + [Constructable] + public FireHorn() : base( 0xFC7 ) + { + Hue = 0x466; + Weight = 1.0; + } + + public FireHorn( Serial serial ) : base( serial ) + { + } + + private bool CheckUse( Mobile from ) + { + if ( !this.IsAccessibleTo( from ) ) + return false; + + if ( from.Map != this.Map || !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return false; + } + + if ( !from.CanBeginAction( typeof( FireHorn ) ) ) + { + from.SendLocalizedMessage( 1049615 ); // You must take a moment to catch your breath. + return false; + } + + int sulfAsh = Core.AOS ? 4 : 15; + if ( from.Backpack == null || from.Backpack.GetAmount( typeof( SulfurousAsh ) ) < sulfAsh ) + { + from.SendLocalizedMessage( 1049617 ); // You do not have enough sulfurous ash. + return false; + } + + return true; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( CheckUse( from ) ) + { + from.SendLocalizedMessage( 1049620 ); // Select an area to incinerate. + from.Target = new InternalTarget( this ); + } + } + + public void Use( Mobile from, IPoint3D loc ) + { + if ( !CheckUse( from ) ) + return; + + from.BeginAction( typeof( FireHorn ) ); + Timer.DelayCall( Core.AOS ? TimeSpan.FromSeconds( 6.0 ) : TimeSpan.FromSeconds( 12.0 ), new TimerStateCallback( EndAction ), from ); + + int music = from.Skills[SkillName.Musicianship].Fixed; + + int sucChance = 500 + ( music - 775 ) * 2; + double dSucChance = ((double)sucChance) / 1000.0; + + if ( !from.CheckSkill( SkillName.Musicianship, dSucChance ) ) + { + from.SendLocalizedMessage( 1049618 ); // The horn emits a pathetic squeak. + from.PlaySound( 0x18A ); + return; + } + + int sulfAsh = Core.AOS ? 4 : 15; + from.Backpack.ConsumeUpTo( typeof( SulfurousAsh ), sulfAsh ); + + from.PlaySound( 0x15F ); + Effects.SendPacket( from, from.Map, new HuedEffect( EffectType.Moving, from.Serial, Serial.Zero, 0x36D4, from.Location, loc, 5, 0, false, true, 0, 0 ) ); + + ArrayList targets = new ArrayList(); + bool playerVsPlayer = false; + + IPooledEnumerable eable = from.Map.GetMobilesInRange( new Point3D( loc ), 2 ); + + foreach ( Mobile m in eable ) + { + if ( from != m && SpellHelper.ValidIndirectTarget( from, m ) && from.CanBeHarmful( m, false ) ) + { + if ( Core.AOS && !from.InLOS( m ) ) + continue; + + targets.Add( m ); + + if ( m.Player ) + playerVsPlayer = true; + } + } + + eable.Free(); + + if ( targets.Count > 0 ) + { + int prov = from.Skills[SkillName.Provocation].Fixed; + int disc = from.Skills[SkillName.Discordance].Fixed; + int peace = from.Skills[SkillName.Peacemaking].Fixed; + + int minDamage, maxDamage; + + if ( Core.AOS ) + { + int musicScaled = music + Math.Max( 0, music - 900 ) * 2; + int provScaled = prov + Math.Max( 0, prov - 900 ) * 2; + int discScaled = disc + Math.Max( 0, disc - 900 ) * 2; + int peaceScaled = peace + Math.Max( 0, peace - 900 ) * 2; + + int weightAvg = ( musicScaled + provScaled * 3 + discScaled * 3 + peaceScaled ) / 80; + + int avgDamage; + if ( playerVsPlayer ) + avgDamage = weightAvg / 3; + else + avgDamage = weightAvg / 2; + + minDamage = ( avgDamage * 9 ) / 10; + maxDamage = ( avgDamage * 10 ) / 9; + } + else + { + int total = prov + disc / 5 + peace / 5; + + if ( playerVsPlayer ) + total /= 3; + + maxDamage = ( total * 2 ) / 30; + minDamage = ( maxDamage * 7 ) / 10; + } + + double damage = Utility.RandomMinMax( minDamage, maxDamage ); + + if ( Core.AOS && targets.Count > 1 ) + damage = (damage * 2) / targets.Count; + else if ( !Core.AOS ) + damage /= targets.Count; + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + double toDeal = damage; + + if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ) ) + { + toDeal *= 0.5; + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + from.DoHarmful( m ); + SpellHelper.Damage( TimeSpan.Zero, m, from, toDeal, 0, 100, 0, 0, 0 ); + + Effects.SendTargetEffect( m, 0x3709, 10, 30 ); + } + } + + double breakChance = Core.AOS ? 0.01 : 0.16; + if ( Utility.RandomDouble() < breakChance ) + { + from.SendLocalizedMessage( 1049619 ); // The fire horn crumbles in your hands. + this.Delete(); + } + } + + private static void EndAction( object state ) + { + Mobile m = (Mobile) state; + + m.EndAction( typeof( FireHorn ) ); + m.SendLocalizedMessage( 1049621 ); // You catch your breath. + } + + private class InternalTarget : Target + { + private FireHorn m_Horn; + + public InternalTarget( FireHorn horn ) : base( Core.AOS ? 3 : 2, true, TargetFlags.Harmful ) + { + m_Horn = horn; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Horn.Deleted ) + return; + + IPoint3D loc; + if ( targeted is Item ) + loc = ((Item)targeted).GetWorldLocation(); + else + loc = targeted as IPoint3D; + + m_Horn.Use( from, loc ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Misc/RecipeScroll.cs b/Scripts/Items/Skill Items/Misc/RecipeScroll.cs new file mode 100644 index 0000000..dd486ae --- /dev/null +++ b/Scripts/Items/Skill Items/Misc/RecipeScroll.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Engines.Craft; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class RecipeScroll : Item + { + public override int LabelNumber { get { return 1074560; } } // recipe scroll + + private int m_RecipeID; + + [CommandProperty( AccessLevel.GameMaster )] + public int RecipeID + { + get { return m_RecipeID; } + set { m_RecipeID = value; InvalidateProperties(); } + } + + public Recipe Recipe + { + get + { + if( Recipe.Recipes.ContainsKey( m_RecipeID ) ) + return Recipe.Recipes[m_RecipeID]; + + return null; + } + } + + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + Recipe r = this.Recipe; + + if( r != null ) + list.Add( 1049644, r.TextDefinition.ToString() ); // [~1_stuff~] + } + + public RecipeScroll( Recipe r ) + : this( r.ID ) + { + } + + [Constructable] + public RecipeScroll( int recipeID ) + : base( 0x2831 ) + { + m_RecipeID = recipeID; + } + + public RecipeScroll( Serial serial ) + : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if( !from.InRange( this.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return; + } + + Recipe r = this.Recipe; + + if( r != null && from is PlayerMobile ) + { + PlayerMobile pm = from as PlayerMobile; + + if( !pm.HasRecipe( r ) ) + { + bool allRequiredSkills = true; + double chance = r.CraftItem.GetSuccessChance( from, null, r.CraftSystem, false, ref allRequiredSkills ); + + if ( allRequiredSkills && chance >= 0.0 ) + { + pm.SendLocalizedMessage( 1073451, r.TextDefinition.ToString() ); // You have learned a new recipe: ~1_RECIPE~ + pm.AcquireRecipe( r ); + this.Delete(); + } + else + { + pm.SendLocalizedMessage( 1044153 ); // You don't have the required skills to attempt this item. + } + } + else + { + pm.SendLocalizedMessage( 1073427 ); // You already know this recipe. + } + + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (int)m_RecipeID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_RecipeID = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Scripts/Items/Skill Items/Misc/RepairDeed.cs b/Scripts/Items/Skill Items/Misc/RepairDeed.cs new file mode 100644 index 0000000..c567792 --- /dev/null +++ b/Scripts/Items/Skill Items/Misc/RepairDeed.cs @@ -0,0 +1,246 @@ +using System; +using Server; +using Server.Targeting; +using Server.Engines.Craft; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Items +{ + public class RepairDeed : Item + { + private class RepairSkillInfo + { + private CraftSystem m_System; + private Type[] m_NearbyTypes; + private TextDefinition m_NotNearbyMessage, m_Name; + + public TextDefinition NotNearbyMessage{ get { return m_NotNearbyMessage; } } + public TextDefinition Name { get { return m_Name; } } + + + public CraftSystem System { get { return m_System; } } + public Type[] NearbyTypes { get { return m_NearbyTypes; } } + + public RepairSkillInfo( CraftSystem system, Type[] nearbyTypes, TextDefinition notNearbyMessage, TextDefinition name ) + { + m_System = system; + m_NearbyTypes = nearbyTypes; + m_NotNearbyMessage = notNearbyMessage; + m_Name = name; + } + + public RepairSkillInfo( CraftSystem system, Type nearbyType, TextDefinition notNearbyMessage, TextDefinition name ) + : this( system, new Type[] { nearbyType }, notNearbyMessage, name ) + { + } + + public static RepairSkillInfo[] Table { get { return m_Table; } } + private static RepairSkillInfo[] m_Table = new RepairSkillInfo[] + { + new RepairSkillInfo( DefBlacksmithy.CraftSystem, typeof( Blacksmith ), 1047013, 1023015 ), + new RepairSkillInfo( DefTailoring.CraftSystem, typeof( Tailor ), 1061132, 1022981 ), + new RepairSkillInfo( DefTinkering.CraftSystem, typeof( Tinker ), 1061166, 1022983 ), + new RepairSkillInfo( DefCarpentry.CraftSystem, typeof( Carpenter ), 1061135, 1060774 ), + new RepairSkillInfo( DefBowFletching.CraftSystem, typeof( Bowyer ), 1061134, 1023005 ) + }; + + public static RepairSkillInfo GetInfo( RepairSkillType type ) + { + int v = (int)type; + + if( v < 0 || v >= m_Table.Length ) + v = 0; + + return m_Table[v]; + } + } + public enum RepairSkillType + { + Smithing, + Tailoring, + Tinkering, + Carpentry, + Fletching + } + + public override bool DisplayLootType { get { return false; } } + + private RepairSkillType m_Skill; + private double m_SkillLevel; + + private Mobile m_Crafter; + + [CommandProperty( AccessLevel.GameMaster )] + public RepairSkillType RepairSkill + { + get { return m_Skill; } + set { m_Skill = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public double SkillLevel + { + get { return m_SkillLevel; } + set { m_SkillLevel = Math.Max( Math.Min( value, 120.0 ), 0 ) ; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get { return m_Crafter; } + set { m_Crafter = value; InvalidateProperties(); } + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1061133, String.Format( "{0}\t{1}", GetSkillTitle( m_SkillLevel ).ToString(), RepairSkillInfo.GetInfo( m_Skill ).Name ) ); // A repair service contract from ~1_SKILL_TITLE~ ~2_SKILL_NAME~. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + //On OSI it says it's exceptional. Intentional difference. + } + + public override void OnSingleClick(Mobile from) + { + if (Deleted || !from.CanSee(this)) + return; + + this.LabelTo(from, 1061133, String.Format("{0}\t{1}", GetSkillTitle(m_SkillLevel).ToString(), RepairSkillInfo.GetInfo(m_Skill).Name)); // A repair service contract from ~1_SKILL_TITLE~ ~2_SKILL_NAME~. + + if (m_Crafter != null) + this.LabelTo(from, 1050043, m_Crafter.Name); // crafted by ~1_NAME~ + } + + [Constructable] + public RepairDeed() : this( RepairSkillType.Smithing, 100.0, null, true ) + { + } + + [Constructable] + public RepairDeed( RepairSkillType skill, double level ) : this( skill, level, null, true ) + { + } + + [Constructable] + public RepairDeed( RepairSkillType skill, double level, bool normalizeLevel ) : this( skill, level, null, normalizeLevel ) + { + } + + public RepairDeed( RepairSkillType skill, double level, Mobile crafter ) : this( skill, level, crafter, true ) + { + } + + public RepairDeed( RepairSkillType skill, double level, Mobile crafter, bool normalizeLevel ) : base( 0x14F0 ) + { + if( normalizeLevel ) + SkillLevel = (int)(level/10)*10; + else + SkillLevel = level; + + m_Skill = skill; + m_Crafter = crafter; + Hue = 0x1BC; + LootType = LootType.Blessed; + } + + public RepairDeed( Serial serial ) : base( serial ) + { + } + + private static TextDefinition GetSkillTitle( double skillLevel ) + { + int skill = (int)(skillLevel/10); + + if( skill >= 11 ) + return (1062008 + skill-11); + else if( skill >=5 ) + return (1061123 + skill-5); + + switch( skill ) + { + case 4: + return "a Novice"; + case 3: + return "a Neophyte"; + default: + return "a Newbie"; //On OSI, it shouldn't go below 50, but, this is for 'custom' support. + } + } + + public static RepairSkillType GetTypeFor( CraftSystem s ) + { + for( int i = 0; i < RepairSkillInfo.Table.Length; i++ ) + { + if( RepairSkillInfo.Table[i].System == s ) + return (RepairSkillType)i; + } + + return RepairSkillType.Smithing; + } + + public override void OnDoubleClick( Mobile from ) + { + if( Check( from ) ) + Repair.Do( from, RepairSkillInfo.GetInfo( m_Skill ).System, this ); + } + + public bool Check( Mobile from ) + { + if( !IsChildOf( from.Backpack ) ) + from.SendLocalizedMessage( 1047012 ); // The contract must be in your backpack to use it. + else if( !VerifyRegion( from ) ) + TextDefinition.SendMessageTo( from, RepairSkillInfo.GetInfo( m_Skill ).NotNearbyMessage ); + else + return true; + + return false; + } + + public bool VerifyRegion( Mobile m ) + { + //TODO: When the entire region system data is in, convert to that instead of a proximity thing. + + if( !m.Region.IsPartOf( typeof( TownRegion ) ) ) + return false; + + return Server.Factions.Faction.IsNearType( m, RepairSkillInfo.GetInfo( m_Skill ).NearbyTypes, 6 ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (int)m_Skill ); + writer.Write( m_SkillLevel ); + writer.Write( m_Crafter ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_Skill = (RepairSkillType)reader.ReadInt(); + m_SkillLevel = reader.ReadDouble(); + m_Crafter = reader.ReadMobile(); + + break; + } + } + } + } +} diff --git a/Scripts/Items/Skill Items/Musical Instruments/BambooFlute.cs b/Scripts/Items/Skill Items/Musical Instruments/BambooFlute.cs new file mode 100644 index 0000000..41d0ce7 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/BambooFlute.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class BambooFlute : BaseInstrument + { + [Constructable] + public BambooFlute() : base( 0x2805, 0x504, 0x503 ) + { + Weight = 2.0; + } + + public BambooFlute( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs b/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs new file mode 100644 index 0000000..5dd7914 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/BaseInstrument.cs @@ -0,0 +1,587 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Engines.Craft; + +namespace Server.Items +{ + public delegate void InstrumentPickedCallback( Mobile from, BaseInstrument instrument ); + + public enum InstrumentQuality + { + Low, + Regular, + Exceptional + } + + public abstract class BaseInstrument : Item, ICraftable, ISlayer + { + private int m_WellSound, m_BadlySound; + private SlayerName m_Slayer, m_Slayer2; + private InstrumentQuality m_Quality; + private Mobile m_Crafter; + private int m_UsesRemaining; + + [CommandProperty( AccessLevel.GameMaster )] + public int SuccessSound + { + get{ return m_WellSound; } + set{ m_WellSound = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int FailureSound + { + get{ return m_BadlySound; } + set{ m_BadlySound = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SlayerName Slayer + { + get{ return m_Slayer; } + set{ m_Slayer = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SlayerName Slayer2 + { + get{ return m_Slayer2; } + set{ m_Slayer2 = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public InstrumentQuality Quality + { + get{ return m_Quality; } + set{ UnscaleUses(); m_Quality = value; InvalidateProperties(); ScaleUses(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + public virtual int InitMinUses{ get{ return 350; } } + public virtual int InitMaxUses{ get{ return 450; } } + + public virtual TimeSpan ChargeReplenishRate { get { return TimeSpan.FromMinutes( 5.0 ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get{ CheckReplenishUses(); return m_UsesRemaining; } + set{ m_UsesRemaining = value; InvalidateProperties(); } + } + + private DateTime m_LastReplenished; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastReplenished + { + get { return m_LastReplenished; } + set { m_LastReplenished = value; CheckReplenishUses(); } + } + + private bool m_ReplenishesCharges; + [CommandProperty( AccessLevel.GameMaster )] + public bool ReplenishesCharges + { + get { return m_ReplenishesCharges; } + set + { + if( value != m_ReplenishesCharges && value ) + m_LastReplenished = DateTime.Now; + + m_ReplenishesCharges = value; + } + } + + public void CheckReplenishUses() + { + CheckReplenishUses( true ); + } + + public void CheckReplenishUses( bool invalidate ) + { + if( !m_ReplenishesCharges || m_UsesRemaining >= InitMaxUses ) + return; + + if( m_LastReplenished + ChargeReplenishRate < DateTime.Now ) + { + TimeSpan timeDifference = DateTime.Now - m_LastReplenished; + + m_UsesRemaining = Math.Min( m_UsesRemaining + (int)( timeDifference.Ticks / ChargeReplenishRate.Ticks), InitMaxUses ); //How rude of TimeSpan to not allow timespan division. + m_LastReplenished = DateTime.Now; + + if( invalidate ) + InvalidateProperties(); + + } + } + + public void ScaleUses() + { + UsesRemaining = (UsesRemaining * GetUsesScalar()) / 100; + //InvalidateProperties(); + } + + public void UnscaleUses() + { + UsesRemaining = (UsesRemaining * 100) / GetUsesScalar(); + } + + public int GetUsesScalar() + { + if ( m_Quality == InstrumentQuality.Exceptional ) + return 200; + + return 100; + } + + public void ConsumeUse( Mobile from ) + { + // TODO: Confirm what must happen here? + + if ( UsesRemaining > 1 ) + { + --UsesRemaining; + } + else + { + if ( from != null ) + from.SendLocalizedMessage( 502079 ); // The instrument played its last tune. + + Delete(); + } + } + + private static Hashtable m_Instruments = new Hashtable(); + + public static BaseInstrument GetInstrument( Mobile from ) + { + BaseInstrument item = m_Instruments[from] as BaseInstrument; + + if ( item == null ) + return null; + + if ( !item.IsChildOf( from.Backpack ) ) + { + m_Instruments.Remove( from ); + return null; + } + + return item; + } + + public static int GetBardRange( Mobile bard, SkillName skill ) + { + return 8 + (int)(bard.Skills[skill].Value / 15); + } + + public static void PickInstrument( Mobile from, InstrumentPickedCallback callback ) + { + BaseInstrument instrument = GetInstrument( from ); + + if ( instrument != null ) + { + if ( callback != null ) + callback( from, instrument ); + } + else + { + from.SendLocalizedMessage( 500617 ); // What instrument shall you play? + from.BeginTarget( 1, false, TargetFlags.None, new TargetStateCallback( OnPickedInstrument ), callback ); + } + } + + public static void OnPickedInstrument( Mobile from, object targeted, object state ) + { + BaseInstrument instrument = targeted as BaseInstrument; + + if ( instrument == null ) + { + from.SendLocalizedMessage( 500619 ); // That is not a musical instrument. + } + else + { + SetInstrument( from, instrument ); + + InstrumentPickedCallback callback = state as InstrumentPickedCallback; + + if ( callback != null ) + callback( from, instrument ); + } + } + + public static bool IsMageryCreature( BaseCreature bc ) + { + return ( bc != null && bc.AI == AIType.AI_Mage && bc.Skills[SkillName.Magery].Base > 5.0 ); + } + + public static bool IsFireBreathingCreature( BaseCreature bc ) + { + if ( bc == null ) + return false; + + return bc.HasBreath; + } + + public static bool IsPoisonImmune( BaseCreature bc ) + { + return ( bc != null && bc.PoisonImmune != null ); + } + + public static int GetPoisonLevel( BaseCreature bc ) + { + if ( bc == null ) + return 0; + + Poison p = bc.HitPoison; + + if ( p == null ) + return 0; + + return p.Level + 1; + } + + public static double GetBaseDifficulty( Mobile targ ) + { + /* Difficulty TODO: Add another 100 points for each of the following abilities: + - Radiation or Aura Damage (Heat, Cold etc.) + - Summoning Undead + */ + + double val = (targ.HitsMax * 1.6) + targ.StamMax + targ.ManaMax; + + val += targ.SkillsTotal / 10; + + if ( val > 700 ) + val = 700 + (int)((val - 700) * (3.0 / 11)); + + BaseCreature bc = targ as BaseCreature; + + if ( IsMageryCreature( bc ) ) + val += 100; + + if ( IsFireBreathingCreature( bc ) ) + val += 100; + + if ( IsPoisonImmune( bc ) ) + val += 100; + + if ( targ is VampireBat || targ is VampireBatFamiliar ) + val += 100; + + val += GetPoisonLevel( bc ) * 20; + + val /= 10; + + if ( bc != null && bc.IsParagon ) + val += 40.0; + + if ( Core.SE && val > 160.0 ) + val = 160.0; + + return val; + } + + public double GetDifficultyFor( Mobile targ ) + { + double val = GetBaseDifficulty( targ ); + + if ( m_Quality == InstrumentQuality.Exceptional ) + val -= 5.0; // 10% + + if ( m_Slayer != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer ); + + if ( entry != null ) + { + if ( entry.Slays( targ ) ) + val -= 10.0; // 20% + else if ( entry.Group.OppositionSuperSlays( targ ) ) + val += 10.0; // -20% + } + } + + if ( m_Slayer2 != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 ); + + if ( entry != null ) + { + if ( entry.Slays( targ ) ) + val -= 10.0; // 20% + else if ( entry.Group.OppositionSuperSlays( targ ) ) + val += 10.0; // -20% + } + } + + return val; + } + + public static void SetInstrument( Mobile from, BaseInstrument item ) + { + m_Instruments[from] = item; + } + + public BaseInstrument( int itemID, int wellSound, int badlySound ) : base( itemID ) + { + m_WellSound = wellSound; + m_BadlySound = badlySound; + UsesRemaining = Utility.RandomMinMax( InitMinUses, InitMaxUses ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + int oldUses = m_UsesRemaining; + CheckReplenishUses( false ); + + base.GetProperties( list ); + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if ( m_Quality == InstrumentQuality.Exceptional ) + list.Add( 1060636 ); // exceptional + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + if( m_ReplenishesCharges ) + list.Add( 1070928 ); // Replenish Charges + + if( m_Slayer != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer ); + if( entry != null ) + list.Add( entry.Title ); + } + + if( m_Slayer2 != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 ); + if( entry != null ) + list.Add( entry.Title ); + } + + if( m_UsesRemaining != oldUses ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( InvalidateProperties ) ); + } + + public override void OnSingleClick( Mobile from ) + { + ArrayList attrs = new ArrayList(); + + if ( DisplayLootType ) + { + if ( LootType == LootType.Blessed ) + attrs.Add( new EquipInfoAttribute( 1038021 ) ); // blessed + else if ( LootType == LootType.Cursed ) + attrs.Add( new EquipInfoAttribute( 1049643 ) ); // cursed + } + + if ( m_Quality == InstrumentQuality.Exceptional ) + attrs.Add( new EquipInfoAttribute( 1018305 - (int)m_Quality ) ); + + if( m_ReplenishesCharges ) + attrs.Add( new EquipInfoAttribute( 1070928 ) ); // Replenish Charges + + // TODO: Must this support item identification? + if( m_Slayer != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer ); + if( entry != null ) + attrs.Add( new EquipInfoAttribute( entry.Title ) ); + } + + if( m_Slayer2 != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 ); + if( entry != null ) + attrs.Add( new EquipInfoAttribute( entry.Title ) ); + } + + int number; + + if ( Name == null ) + { + number = LabelNumber; + } + else + { + this.LabelTo( from, Name ); + number = 1041000; + } + + if ( attrs.Count == 0 && Crafter == null && Name != null ) + return; + + EquipmentInfo eqInfo = new EquipmentInfo( number, m_Crafter, false, (EquipInfoAttribute[])attrs.ToArray( typeof( EquipInfoAttribute ) ) ); + + from.Send( new DisplayEquipmentInfo( this, eqInfo ) ); + } + + public BaseInstrument( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); // version + + writer.Write( m_ReplenishesCharges ); + if( m_ReplenishesCharges ) + writer.Write( m_LastReplenished ); + + + writer.Write( m_Crafter ); + + writer.WriteEncodedInt( (int) m_Quality ); + writer.WriteEncodedInt( (int) m_Slayer ); + writer.WriteEncodedInt( (int) m_Slayer2 ); + + writer.WriteEncodedInt( (int)UsesRemaining ); + + writer.WriteEncodedInt( (int) m_WellSound ); + writer.WriteEncodedInt( (int) m_BadlySound ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + { + m_ReplenishesCharges = reader.ReadBool(); + + if( m_ReplenishesCharges ) + m_LastReplenished = reader.ReadDateTime(); + + goto case 2; + } + case 2: + { + m_Crafter = reader.ReadMobile(); + + m_Quality = (InstrumentQuality)reader.ReadEncodedInt(); + m_Slayer = (SlayerName)reader.ReadEncodedInt(); + m_Slayer2 = (SlayerName)reader.ReadEncodedInt(); + + UsesRemaining = reader.ReadEncodedInt(); + + m_WellSound = reader.ReadEncodedInt(); + m_BadlySound = reader.ReadEncodedInt(); + + break; + } + case 1: + { + m_Crafter = reader.ReadMobile(); + + m_Quality = (InstrumentQuality)reader.ReadEncodedInt(); + m_Slayer = (SlayerName)reader.ReadEncodedInt(); + + UsesRemaining = reader.ReadEncodedInt(); + + m_WellSound = reader.ReadEncodedInt(); + m_BadlySound = reader.ReadEncodedInt(); + + break; + } + case 0: + { + m_WellSound = reader.ReadInt(); + m_BadlySound = reader.ReadInt(); + UsesRemaining = Utility.RandomMinMax( InitMinUses, InitMaxUses ); + + break; + } + } + + CheckReplenishUses(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( from.BeginAction( typeof( BaseInstrument ) ) ) + { + SetInstrument( from, this ); + + // Delay of 7 second before beign able to play another instrument again + new InternalTimer( from ).Start(); + + if ( CheckMusicianship( from ) ) + PlayInstrumentWell( from ); + else + PlayInstrumentBadly( from ); + } + else + { + from.SendLocalizedMessage( 500119 ); // You must wait to perform another action + } + } + + public static bool CheckMusicianship( Mobile m ) + { + m.CheckSkill( SkillName.Musicianship, 0.0, 120.0 ); + + return ( (m.Skills[SkillName.Musicianship].Value / 100) > Utility.RandomDouble() ); + } + + public void PlayInstrumentWell( Mobile from ) + { + from.PlaySound( m_WellSound ); + } + + public void PlayInstrumentBadly( Mobile from ) + { + from.PlaySound( m_BadlySound ); + } + + private class InternalTimer : Timer + { + private Mobile m_From; + + public InternalTimer( Mobile from ) : base( TimeSpan.FromSeconds( 6.0 ) ) + { + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_From.EndAction( typeof( BaseInstrument ) ); + } + } + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (InstrumentQuality)quality; + + if ( makersMark ) + Crafter = from; + + return quality; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/Drums.cs b/Scripts/Items/Skill Items/Musical Instruments/Drums.cs new file mode 100644 index 0000000..7d38a40 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/Drums.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class Drums : BaseInstrument + { + [Constructable] + public Drums() : base( 0xE9C, 0x38, 0x39 ) + { + Weight = 4.0; + } + + public Drums( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 4.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/Harp.cs b/Scripts/Items/Skill Items/Musical Instruments/Harp.cs new file mode 100644 index 0000000..c34af75 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/Harp.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class Harp : BaseInstrument + { + [Constructable] + public Harp() : base( 0xEB1, 0x43, 0x44 ) + { + Weight = 35.0; + } + + public Harp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 35.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/LapHarp.cs b/Scripts/Items/Skill Items/Musical Instruments/LapHarp.cs new file mode 100644 index 0000000..b4288c4 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/LapHarp.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class LapHarp : BaseInstrument + { + [Constructable] + public LapHarp() : base( 0xEB2, 0x45, 0x46 ) + { + Weight = 10.0; + } + + public LapHarp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 10.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/Lute.cs b/Scripts/Items/Skill Items/Musical Instruments/Lute.cs new file mode 100644 index 0000000..fb851b6 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/Lute.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class Lute : BaseInstrument + { + [Constructable] + public Lute() : base( 0xEB3, 0x4C, 0x4D ) + { + Weight = 5.0; + } + + public Lute( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 3.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/Tambourine.cs b/Scripts/Items/Skill Items/Musical Instruments/Tambourine.cs new file mode 100644 index 0000000..b34236f --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/Tambourine.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class Tambourine : BaseInstrument + { + [Constructable] + public Tambourine() : base( 0xE9D, 0x52, 0x53 ) + { + Weight = 1.0; + } + + public Tambourine( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Musical Instruments/TambourineTassel.cs b/Scripts/Items/Skill Items/Musical Instruments/TambourineTassel.cs new file mode 100644 index 0000000..62ef4d6 --- /dev/null +++ b/Scripts/Items/Skill Items/Musical Instruments/TambourineTassel.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class TambourineTassel : BaseInstrument + { + [Constructable] + public TambourineTassel() : base( 0xE9E, 0x52, 0x53 ) + { + Weight = 1.0; + } + + public TambourineTassel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs b/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs new file mode 100644 index 0000000..802d477 --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/EggBomb.cs @@ -0,0 +1,82 @@ +using System; +using Server; + +namespace Server.Items +{ + public class EggBomb : Item + { + public override int LabelNumber + { + get { return 1030249; } + } + + [Constructable] + public EggBomb() : base( 0x2808 ) + { + // Item ID should be 0x2809 - Temporary solution for clients 7.0.0.0 and up + Stackable = Core.ML; + Weight = 1.0; + } + + public EggBomb( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + // The item must be in your backpack to use it. + from.SendLocalizedMessage( 1060640 ); + } + else if ( from.Skills.Ninjitsu.Value < 50.0 ) + { + // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + from.SendLocalizedMessage( 1063013, "50\tNinjitsu" ); + } + else if ( from.NextSkillTime > DateTime.Now ) + { + // You must wait a few seconds before you can use that item. + from.SendLocalizedMessage( 1070772 ); + } + else if ( from.Mana < 10 ) + { + // You don't have enough mana to do that. + from.SendLocalizedMessage( 1049456 ); + } + else + { + SkillHandlers.Hiding.CombatOverride = true; + + if ( from.UseSkill( SkillName.Hiding ) ) + { + from.Mana -= 10; + + from.FixedParticles( 0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot ); + from.PlaySound( 0x22F ); + + Consume(); + } + + SkillHandlers.Hiding.CombatOverride = false; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ItemID == 0x2809 ) // Temporary solution for clients 7.0.0.0 and up + ItemID = 0x2808; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/Fukiya.cs b/Scripts/Items/Skill Items/Ninjitsu/Fukiya.cs new file mode 100644 index 0000000..ce9e82f --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/Fukiya.cs @@ -0,0 +1,134 @@ +using System; +using Server; +using Server.Targeting; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Mobiles; + +namespace Server.Items +{ + [FlipableAttribute( 0x27AA, 0x27F5 )] + public class Fukiya : Item, INinjaWeapon + { + public virtual int WrongAmmoMessage { get { return 1063329; } } //You can only load fukiya darts + public virtual int NoFreeHandMessage { get { return 1063327; } } //You must have a free hand to use a fukiya. + public virtual int EmptyWeaponMessage { get { return 1063325; } } //You have no fukiya darts! + public virtual int RecentlyUsedMessage { get { return 1063326; } } //You are already using that fukiya. + public virtual int FullWeaponMessage { get { return 1063330; } } //You can only load fukiya darts + + public virtual int WeaponMinRange { get { return 0; } } + public virtual int WeaponMaxRange { get { return 6; } } + + public virtual int WeaponDamage { get { return Utility.RandomMinMax(4, 6); } } + + public Type AmmoType{ get { return typeof(FukiyaDarts); } } + + private int m_UsesRemaining; + private Poison m_Poison; + private int m_PoisonCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get{ return m_Poison; } + set{ m_Poison = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PoisonCharges + { + get { return m_PoisonCharges; } + set { m_PoisonCharges = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + [Constructable] + public Fukiya() : base( 0x27AA ) + { + Weight = 4.0; + Layer = Layer.OneHanded; + } + + public Fukiya( Serial serial ) : base( serial ) + { + } + + public void AttackAnimation(Mobile from, Mobile to) + { + if (from.Body.IsHuman && !from.Mounted) + { + from.Animate(33, 2, 1, true, true, 0); + } + + from.PlaySound(0x223); + from.MovingEffect(to, 0x2804, 5, 0, false, false); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + if ( m_Poison != null && m_PoisonCharges > 0 ) + list.Add( 1062412 + m_Poison.Level, m_PoisonCharges.ToString() ); + } + + public override void OnDoubleClick( Mobile from ) + { + NinjaWeapon.AttemptShoot((PlayerMobile)from, this); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( IsChildOf( from ) ) + { + list.Add(new NinjaWeapon.LoadEntry(this, 6224)); + list.Add(new NinjaWeapon.UnloadEntry(this, 6225)); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (int) m_UsesRemaining ); + + Poison.Serialize( m_Poison, writer ); + writer.Write( (int) m_PoisonCharges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize( reader ); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/FukiyaDarts.cs b/Scripts/Items/Skill Items/Ninjitsu/FukiyaDarts.cs new file mode 100644 index 0000000..2d7d930 --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/FukiyaDarts.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class FukiyaDarts : Item, ICraftable, INinjaAmmo + { + private int m_UsesRemaining; + + private Poison m_Poison; + private int m_PoisonCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get{ return m_Poison; } + set{ m_Poison = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PoisonCharges + { + get { return m_PoisonCharges; } + set { m_PoisonCharges = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + [Constructable] + public FukiyaDarts() : this( 1 ) + { + } + + [Constructable] + public FukiyaDarts( int amount ) : base( 0x2806 ) + { + Weight = 1.0; + + m_UsesRemaining = amount; + } + + public FukiyaDarts( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + if ( m_Poison != null && m_PoisonCharges > 0 ) + list.Add( 1062412 + m_Poison.Level, m_PoisonCharges.ToString() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_UsesRemaining ); + + Poison.Serialize( m_Poison, writer ); + writer.Write( (int) m_PoisonCharges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize( reader ); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + if ( quality == 2 ) + UsesRemaining *= 2; + + return quality; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs b/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs new file mode 100644 index 0000000..427ace1 --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/LeatherNinjaBelt.cs @@ -0,0 +1,147 @@ +using System; +using Server; +using Server.Targeting; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Mobiles; + +namespace Server.Items +{ + [FlipableAttribute( 0x2790, 0x27DB )] + public class LeatherNinjaBelt : BaseWaist, IDyable, INinjaWeapon + { + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public virtual int WrongAmmoMessage { get { return 1063301; } } //You can only place shuriken in a ninja belt. + public virtual int NoFreeHandMessage { get { return 1063299; } } //You must have a free hand to throw shuriken. + public virtual int EmptyWeaponMessage { get { return 1063297; } } //You have no shuriken in your ninja belt! + public virtual int RecentlyUsedMessage { get { return 1063298; } } //You cannot throw another shuriken yet. + public virtual int FullWeaponMessage { get { return 1063302; } } //You cannot add any more shuriken. + + public virtual int WeaponMinRange { get { return 2; } } + public virtual int WeaponMaxRange { get { return 10; } } + + public virtual int WeaponDamage { get { return Utility.RandomMinMax(3, 5); } } + + public virtual Type AmmoType { get { return typeof(Shuriken); } } + + private int m_UsesRemaining; + private Poison m_Poison; + private int m_PoisonCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get{ return m_Poison; } + set{ m_Poison = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PoisonCharges + { + get { return m_PoisonCharges; } + set { m_PoisonCharges = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + [Constructable] + public LeatherNinjaBelt() : base( 0x2790 ) + + { + Weight = 1.0; + Layer = Layer.Waist; + } + + public LeatherNinjaBelt( Serial serial ) : base( serial ) + { + } + + public void AttackAnimation(Mobile from, Mobile to) + { + if (from.Body.IsHuman) + { + from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); + } + + from.PlaySound(0x23A); + from.MovingEffect(to, 0x27AC, 1, 0, false, false); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + if ( m_Poison != null && m_PoisonCharges > 0 ) + list.Add( 1062412 + m_Poison.Level, m_PoisonCharges.ToString() ); + } + + public override bool OnEquip( Mobile from ) + { + if (base.OnEquip(from)) + { + from.SendLocalizedMessage(1070785); // Double click this item each time you wish to throw a shuriken. + return true; + } + return false; + } + + public override void OnDoubleClick(Mobile from) + { + NinjaWeapon.AttemptShoot((PlayerMobile)from, this); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( IsChildOf( from ) ) + { + list.Add(new NinjaWeapon.LoadEntry(this, 6222)); + list.Add(new NinjaWeapon.UnloadEntry(this, 6223)); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( (int) m_UsesRemaining ); + + Poison.Serialize( m_Poison, writer ); + writer.Write( (int) m_PoisonCharges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize( reader ); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/NinjaWeapons.cs b/Scripts/Items/Skill Items/Ninjitsu/NinjaWeapons.cs new file mode 100644 index 0000000..434d3a6 --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/NinjaWeapons.cs @@ -0,0 +1,385 @@ +using System; +using Server.ContextMenus; +using Server.Mobiles; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Targeting; + +/* + * There really was no prettier way to do this, other than the one + * suggestion to make a rigged baseninjaweapon class that bypasses its + * own serialization, due to the way these weapons were originaly coded. + */ + +namespace Server.Items +{ + public interface INinjaAmmo : IUsesRemaining + { + int PoisonCharges { get; set; } + Poison Poison { get; set; } + } + + public interface INinjaWeapon : IUsesRemaining + { + int NoFreeHandMessage { get; } + int EmptyWeaponMessage { get; } + int RecentlyUsedMessage { get; } + int FullWeaponMessage { get; } + int WrongAmmoMessage { get; } + Type AmmoType { get; } + int PoisonCharges { get; set; } + Poison Poison { get; set; } + int WeaponDamage { get; } + int WeaponMinRange { get; } + int WeaponMaxRange { get; } + + void AttackAnimation(Mobile from, Mobile to); + } + + public class NinjaWeapon + { + private const int MaxUses = 10; + + public static void AttemptShoot(PlayerMobile from, INinjaWeapon weapon) + { + if (CanUseWeapon(from, weapon)) + { + from.BeginTarget(weapon.WeaponMaxRange, false, TargetFlags.Harmful, new TargetStateCallback(OnTarget), weapon); + } + } + + private static void Shoot(PlayerMobile from, Mobile target, INinjaWeapon weapon) + { + if (from != target && CanUseWeapon(from, weapon) && from.CanBeHarmful(target)) + { + if (weapon.WeaponMinRange == 0 || !from.InRange(target, weapon.WeaponMinRange)) + { + from.NinjaWepCooldown = true; + + from.Direction = from.GetDirectionTo(target); + + from.RevealingAction(); + + weapon.AttackAnimation(from, target); + + ConsumeUse(weapon); + + if (CombatCheck(from, target)) + { + Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(OnHit), new object[] { from, target, weapon }); + } + + Timer.DelayCall(TimeSpan.FromSeconds(2.5), new TimerStateCallback(ResetUsing), from); + } + else + { + from.SendLocalizedMessage(1063303); // Your target is too close! + } + } + } + + private static void ResetUsing(PlayerMobile from) + { + from.NinjaWepCooldown = false; + } + + private static void Unload(Mobile from, INinjaWeapon weapon) + { + if (weapon.UsesRemaining > 0) + { + INinjaAmmo ammo = Activator.CreateInstance(weapon.AmmoType, new object[] { weapon.UsesRemaining }) as INinjaAmmo; + + ammo.Poison = weapon.Poison; + ammo.PoisonCharges = weapon.PoisonCharges; + + from.AddToBackpack((Item)ammo); + + weapon.UsesRemaining = 0; + weapon.PoisonCharges = 0; + weapon.Poison = null; + } + } + + private static void Reload(PlayerMobile from, INinjaWeapon weapon, INinjaAmmo ammo) + { + if (weapon.UsesRemaining < MaxUses) + { + int need = Math.Min((MaxUses - weapon.UsesRemaining), ammo.UsesRemaining); + + if (need > 0) + { + if (weapon.Poison != null && (ammo.Poison == null || weapon.Poison.Level > ammo.Poison.Level)) + { + from.SendLocalizedMessage(1070767); // Loaded projectile is stronger, unload it first + } + else + { + if (weapon.UsesRemaining > 0) + { + if ((weapon.Poison == null && ammo.Poison != null) + || ((weapon.Poison != null && ammo.Poison != null) && weapon.Poison.Level != ammo.Poison.Level)) + { + Unload(from, weapon); + need = Math.Min(MaxUses, ammo.UsesRemaining); + } + } + int poisonneeded = Math.Min((MaxUses - weapon.PoisonCharges), ammo.PoisonCharges); + + weapon.UsesRemaining += need; + weapon.PoisonCharges += poisonneeded; + + if (weapon.PoisonCharges > 0) + { + weapon.Poison = ammo.Poison; + } + + ammo.PoisonCharges -= poisonneeded; + ammo.UsesRemaining -= need; + + if (ammo.UsesRemaining < 1) + { + ((Item)ammo).Delete(); + } + else if (ammo.PoisonCharges < 1) + { + ammo.Poison = null; + } + } + } // "else" here would mean they targeted "ammo" with 0 uses. undefined behavior. + } + else + { + from.SendLocalizedMessage(weapon.FullWeaponMessage); + } + } + + private static void ConsumeUse(INinjaWeapon weapon) + { + if (weapon.UsesRemaining > 0) + { + weapon.UsesRemaining--; + + if (weapon.UsesRemaining < 1) + { + weapon.PoisonCharges = 0; + weapon.Poison = null; + } + } + } + + private static bool CanUseWeapon(PlayerMobile from, INinjaWeapon weapon) + { + if (WeaponIsValid(weapon, from)) + { + if (weapon.UsesRemaining > 0) + { + if (!from.NinjaWepCooldown) + { + if (BasePotion.HasFreeHand(from)) + { + return true; + } + else + { + from.SendLocalizedMessage(weapon.NoFreeHandMessage); + } + } + else + { + from.SendLocalizedMessage(weapon.RecentlyUsedMessage); + } + } + else + { + from.SendLocalizedMessage(weapon.EmptyWeaponMessage); + } + } + return false; + } + + private static bool CombatCheck(Mobile attacker, Mobile defender) /* mod'd from baseweapon */ + { + BaseWeapon defWeapon = defender.Weapon as BaseWeapon; + + Skill atkSkill = defender.Skills.Ninjitsu; + Skill defSkill = defender.Skills[defWeapon.Skill]; + + double atSkillValue = attacker.Skills.Ninjitsu.Value; + double defSkillValue = defWeapon.GetDefendSkillValue(attacker, defender); + + double attackValue = AosAttributes.GetValue(attacker, AosAttribute.AttackChance); + + if (defSkillValue <= -20.0) + { + defSkillValue = -19.9; + } + + if (Spells.Chivalry.DivineFurySpell.UnderEffect(attacker)) + { + attackValue += 10; + } + + if (AnimalForm.UnderTransformation(attacker, typeof(GreyWolf)) || AnimalForm.UnderTransformation(attacker, typeof(BakeKitsune))) + { + attackValue += 20; + } + + if (HitLower.IsUnderAttackEffect(attacker)) + { + attackValue -= 25; + } + + if (attackValue > 45) + { + attackValue = 45; + } + + attackValue = (atSkillValue + 20.0) * (100 + attackValue); + + double defenseValue = AosAttributes.GetValue(defender, AosAttribute.DefendChance); + + if (Spells.Chivalry.DivineFurySpell.UnderEffect(defender)) + { + defenseValue -= 20; + } + + if (HitLower.IsUnderDefenseEffect(defender)) + { + defenseValue -= 25; + } + + int refBonus = 0; + + if (Block.GetBonus(defender, ref refBonus)) + { + defenseValue += refBonus; + } + + if (SkillHandlers.Discordance.GetEffect(attacker, ref refBonus)) + { + defenseValue -= refBonus; + } + + if (defenseValue > 45) + { + defenseValue = 45; + } + + defenseValue = (defSkillValue + 20.0) * (100 + defenseValue); + + double chance = attackValue / (defenseValue * 2.0); + + if (chance < 0.02) + { + chance = 0.02; + } + + return attacker.CheckSkill(atkSkill.SkillName, chance); + } + + private static void OnHit(object[] states) + { + Mobile from = states[0] as Mobile; + Mobile target = states[1] as Mobile; + INinjaWeapon weapon = states[2] as INinjaWeapon; + + if (from.CanBeHarmful(target)) + { + from.DoHarmful(target); + + AOS.Damage(target, from, weapon.WeaponDamage, 100, 0, 0, 0, 0); + + if (weapon.Poison != null && weapon.PoisonCharges > 0) + { + if (EvilOmenSpell.TryEndEffect(target)) + { + target.ApplyPoison(from, Poison.GetPoison(weapon.Poison.Level + 1)); + } + else + { + target.ApplyPoison(from, weapon.Poison); + } + + weapon.PoisonCharges--; + + if (weapon.PoisonCharges < 1) + { + weapon.Poison = null; + } + } + } + } + + private static void OnTarget(Mobile from, object targeted, INinjaWeapon weapon) + { + PlayerMobile player = from as PlayerMobile; + + if (WeaponIsValid(weapon, from)) + { + if (targeted is Mobile) + { + Shoot(player, (Mobile)targeted, weapon); + } + else if (targeted.GetType() == weapon.AmmoType) + { + Reload(player, weapon, (INinjaAmmo)targeted); + } + else + { + player.SendLocalizedMessage(weapon.WrongAmmoMessage); + } + } + } + + private static bool WeaponIsValid(INinjaWeapon weapon, Mobile from) + { + Item item = weapon as Item; + + if (!item.Deleted && item.RootParent == from) + { + return true; + } + return false; + } + + public class LoadEntry : ContextMenuEntry + { + private INinjaWeapon weapon; + + public LoadEntry(INinjaWeapon wep, int entry) + : base(entry, 0) + { + weapon = wep; + } + + public override void OnClick() + { + if (WeaponIsValid(weapon, Owner.From)) + { + Owner.From.BeginTarget(10, false, TargetFlags.Harmful, new TargetStateCallback(OnTarget), weapon); + } + } + } + + public class UnloadEntry : ContextMenuEntry + { + private INinjaWeapon weapon; + + public UnloadEntry(INinjaWeapon wep, int entry) + : base(entry, 0) + { + weapon = wep; + + Enabled = (weapon.UsesRemaining > 0); + } + + public override void OnClick() + { + if (WeaponIsValid(weapon, Owner.From)) + { + Unload(Owner.From, weapon); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/Shuriken.cs b/Scripts/Items/Skill Items/Ninjitsu/Shuriken.cs new file mode 100644 index 0000000..d93e0c4 --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/Shuriken.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x27AC, 0x27F7 )] + public class Shuriken : Item, ICraftable, INinjaAmmo + { + private int m_UsesRemaining; + + private Poison m_Poison; + private int m_PoisonCharges; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get{ return m_Poison; } + set{ m_Poison = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PoisonCharges + { + get { return m_PoisonCharges; } + set { m_PoisonCharges = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + [Constructable] + public Shuriken() : this( 1 ) + { + } + + [Constructable] + public Shuriken( int amount ) : base( 0x27AC ) + { + Weight = 1.0; + + m_UsesRemaining = amount; + } + + public Shuriken( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + if ( m_Poison != null && m_PoisonCharges > 0 ) + list.Add( 1062412 + m_Poison.Level, m_PoisonCharges.ToString() ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_UsesRemaining ); + + Poison.Serialize( m_Poison, writer ); + writer.Write( (int) m_PoisonCharges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + + m_Poison = Poison.Deserialize( reader ); + m_PoisonCharges = reader.ReadInt(); + + break; + } + } + } + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + if ( quality == 2 ) + UsesRemaining *= 2; + + return quality; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs b/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs new file mode 100644 index 0000000..ade1a2c --- /dev/null +++ b/Scripts/Items/Skill Items/Ninjitsu/SmokeBomb.cs @@ -0,0 +1,73 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SmokeBomb : Item + { + [Constructable] + public SmokeBomb() : base( 0x2808 ) + { + Stackable = Core.ML; + Weight = 1.0; + } + + public SmokeBomb( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + // The item must be in your backpack to use it. + from.SendLocalizedMessage( 1060640 ); + } + else if ( from.Skills.Ninjitsu.Value < 50.0 ) + { + // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + from.SendLocalizedMessage( 1063013, "50\tNinjitsu" ); + } + else if ( from.NextSkillTime > DateTime.Now ) + { + // You must wait a few seconds before you can use that item. + from.SendLocalizedMessage( 1070772 ); + } + else if ( from.Mana < 10 ) + { + // You don't have enough mana to do that. + from.SendLocalizedMessage( 1049456 ); + } + else + { + SkillHandlers.Hiding.CombatOverride = true; + + if ( from.UseSkill( SkillName.Hiding ) ) + { + from.Mana -= 10; + + from.FixedParticles( 0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot ); + from.PlaySound( 0x22F ); + + Consume(); + } + + SkillHandlers.Hiding.CombatOverride = false; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Specialized/GlassblowingBook.cs b/Scripts/Items/Skill Items/Specialized/GlassblowingBook.cs new file mode 100644 index 0000000..ff72ec5 --- /dev/null +++ b/Scripts/Items/Skill Items/Specialized/GlassblowingBook.cs @@ -0,0 +1,64 @@ +//Myron - Traduction. +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class GlassblowingBook : Item + { + public override string DefaultName + { + get { return "Guide illustr� du souffleur de verre"; } + } + + [Constructable] + public GlassblowingBook() : base( 0xFF4 ) + { + Weight = 1.0; + } + + public GlassblowingBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + //Myron - Suppression de condition pour permettre de les mettre dans une biblio. + /*if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else */ + if ( pm == null || from.Skills[SkillName.Alchemy].Base < 100.0 ) + { + pm.SendMessage( "Seul un grand maitre alchimistre comprendrait cet ouvrage." ); + } + else if ( pm.Glassblowing ) + { + pm.SendMessage( "Vous connaissez d�j� le contenu de l'ouvrage." ); + } + else + { + pm.Glassblowing = true; + pm.SendMessage( "Vous pouvez d�sormais souffler le verre avec du sable fin." ); + //Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Specialized/MasonryBook.cs b/Scripts/Items/Skill Items/Specialized/MasonryBook.cs new file mode 100644 index 0000000..a8b034e --- /dev/null +++ b/Scripts/Items/Skill Items/Specialized/MasonryBook.cs @@ -0,0 +1,63 @@ +//Myron - Traduction +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class MasonryBook : Item + { + public override string DefaultName + { + get { return "Sculpter la pierre : Un passe temps passionnant"; } + } + + [Constructable] + public MasonryBook() : base( 0xFBE ) + { + Weight = 1.0; + } + + public MasonryBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + //Myron - Suppression de condition pour permettre de les mettre dans une biblio. + /*if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else */if ( pm == null || from.Skills[SkillName.Carpentry].Base < 100.0 ) + { + pm.SendMessage( "Seul un grand maitre charpentier comprendrait cet ouvrage." ); + } + else if ( pm.Masonry ) + { + pm.SendMessage( "Ce livre est exceptionnellement bien illustr� mais le lire une deuxi�me fois ne vous apportera rien de plus." ); + } + else + { + pm.Masonry = true; + pm.SendMessage( "Vous pouvez d�sormais sculpter la pierre." ); + //Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Specialized/Sand.cs b/Scripts/Items/Skill Items/Specialized/Sand.cs new file mode 100644 index 0000000..b9e5aeb --- /dev/null +++ b/Scripts/Items/Skill Items/Specialized/Sand.cs @@ -0,0 +1,47 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x11EA, 0x11EB )] + public class Sand : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + public override int LabelNumber{ get{ return 1044626; } } // sand + + [Constructable] + public Sand() : this( 1 ) + { + } + + [Constructable] + public Sand( int amount ) : base( 0x11EA ) + { + Stackable = Core.ML; + Weight = 1.0; + } + + public Sand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && this.Name == "sand" ) + this.Name = null; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Specialized/SandMiningBook.cs b/Scripts/Items/Skill Items/Specialized/SandMiningBook.cs new file mode 100644 index 0000000..6c5dffb --- /dev/null +++ b/Scripts/Items/Skill Items/Specialized/SandMiningBook.cs @@ -0,0 +1,64 @@ +//Myron - Traduction. +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class SandMiningBook : Item + { + public override string DefaultName + { + get { return "Les plus belles plages de sable fin"; } + } + + [Constructable] + public SandMiningBook() : base( 0xFF4 ) + { + Weight = 1.0; + } + + public SandMiningBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + //Myron - Suppression de condition pour permettre de les mettre dans une biblio. + /*if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else*/ + if ( pm == null || from.Skills[SkillName.Mining].Base < 100.0 ) + { + pm.SendMessage( "Seul un grand maitre mineur comprendrait cet ouvrage." ); + } + else if ( pm.SandMining ) + { + pm.SendMessage( "Vous avez d�j� lu cet ouvrage." ); + } + else + { + pm.SandMining = true; + pm.SendMessage( "Vous avez appris � r�colter du sable fin sur les plages." ); + //Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Specialized/StoneMiningBook.cs b/Scripts/Items/Skill Items/Specialized/StoneMiningBook.cs new file mode 100644 index 0000000..6d3ee85 --- /dev/null +++ b/Scripts/Items/Skill Items/Specialized/StoneMiningBook.cs @@ -0,0 +1,63 @@ +//Myron - Traduction +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class StoneMiningBook : Item + { + public override string DefaultName + { + get { return "Faire carri�re dans la pierre"; } + } + + [Constructable] + public StoneMiningBook() : base( 0xFBE ) + { + Weight = 1.0; + } + + public StoneMiningBook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + //Myron - Suppression de condition pour permettre de les mettre dans une biblio. + /*if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else */if ( pm == null || from.Skills[SkillName.Mining].Base < 100.0 ) + { + from.SendMessage( "Seul un grand maitre mineur comprendrait cet ouvrage." ); + } + else if ( pm.StoneMining ) + { + pm.SendMessage( "Vous n'avez plus rien � apprendre de cet ouvrage." ); + } + else + { + pm.StoneMining = true; + pm.SendMessage( "Vous avez appris � r�colter de bonnes pierres." ); + //Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs new file mode 100644 index 0000000..44545e6 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/BlackDyeTub.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Items +{ + public class BlackDyeTub : DyeTub + { + [Constructable] + public BlackDyeTub() + { + Hue = DyedHue = 0x0001; + Redyable = false; + } + + public BlackDyeTub( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs new file mode 100644 index 0000000..25e04c5 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/BlazeDyeTub.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BlazeDyeTub : DyeTub + { + [Constructable] + public BlazeDyeTub() + { + Hue = DyedHue = 0x489; + Redyable = false; + } + + public BlazeDyeTub( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs new file mode 100644 index 0000000..5966343 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/CustomHuePicker.cs @@ -0,0 +1,224 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class CustomHueGroup + { + private int m_Name; + private string m_NameString; + private int[] m_Hues; + + public int Name{ get{ return m_Name; } } + public string NameString{ get{ return m_NameString; } } + + public int[] Hues{ get{ return m_Hues; } } + + public CustomHueGroup( int name, int[] hues ) + { + m_Name = name; + m_Hues = hues; + } + + public CustomHueGroup( string name, int[] hues ) + { + m_NameString = name; + m_Hues = hues; + } + } + + public class CustomHuePicker + { + private CustomHueGroup[] m_Groups; + private bool m_DefaultSupported; + private int m_Title; + private string m_TitleString; + + public bool DefaultSupported{ get{ return m_DefaultSupported; } } + public CustomHueGroup[] Groups{ get{ return m_Groups; } } + public int Title{ get{ return m_Title; } } + public string TitleString{ get{ return m_TitleString; } } + + public CustomHuePicker( CustomHueGroup[] groups, bool defaultSupported ) + { + m_Groups = groups; + m_DefaultSupported = defaultSupported; + } + + public CustomHuePicker( CustomHueGroup[] groups, bool defaultSupported, int title ) + { + m_Groups = groups; + m_DefaultSupported = defaultSupported; + m_Title = title; + } + + public CustomHuePicker( CustomHueGroup[] groups, bool defaultSupported, string title ) + { + m_Groups = groups; + m_DefaultSupported = defaultSupported; + m_TitleString = title; + } + + public static readonly CustomHuePicker SpecialDyeTub = new CustomHuePicker( new CustomHueGroup[] + { + /* Violet */ + new CustomHueGroup( 1018345, new int[]{ 1230, 1231, 1232, 1233, 1234, 1235 } ), + /* Tan */ + new CustomHueGroup( 1018346, new int[]{ 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508 } ), + /* Brown */ + new CustomHueGroup( 1018347, new int[]{ 2012, 2013, 2014, 2015, 2016, 2017 } ), + /* Dark Blue */ + new CustomHueGroup( 1018348, new int[]{ 1303, 1304, 1305, 1306, 1307, 1308 } ), + /* Forest Green */ + new CustomHueGroup( 1018349, new int[]{ 1420, 1421, 1422, 1423, 1424, 1425, 1426 } ), + /* Pink */ + new CustomHueGroup( 1018350, new int[]{ 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1626 } ), + /* Red */ + new CustomHueGroup( 1018351, new int[]{ 1640, 1641, 1642, 1643, 1644 } ), + /* Olive */ + new CustomHueGroup( 1018352, new int[]{ 2001, 2002, 2003, 2004, 2005 } ) + }, false, 1018344 ); + + public static readonly CustomHuePicker LeatherDyeTub = new CustomHuePicker( new CustomHueGroup[] + { + /* Dull Copper */ + new CustomHueGroup( 1018332, new int[]{ 2419, 2420, 2421, 2422, 2423, 2424 } ), + /* Shadow Iron */ + new CustomHueGroup( 1018333, new int[]{ 2406, 2407, 2408, 2409, 2410, 2411, 2412 } ), + /* Copper */ + new CustomHueGroup( 1018334, new int[]{ 2413, 2414, 2415, 2416, 2417, 2418 } ), + /* Bronze */ + new CustomHueGroup( 1018335, new int[]{ 2414, 2415, 2416, 2417, 2418 } ), + /* Glden */ + new CustomHueGroup( 1018336, new int[]{ 2213, 2214, 2215, 2216, 2217, 2218 } ), + /* Agapite */ + new CustomHueGroup( 1018337, new int[]{ 2425, 2426, 2427, 2428, 2429, 2430 } ), + /* Verite */ + new CustomHueGroup( 1018338, new int[]{ 2207, 2208, 2209, 2210, 2211, 2212 } ), + /* Valorite */ + new CustomHueGroup( 1018339, new int[]{ 2219, 2220, 2221, 2222, 2223, 2224 } ), + /* Reds */ + new CustomHueGroup( 1018340, new int[]{ 2113, 2114, 2115, 2116, 2117, 2118 } ), + /* Blues */ + new CustomHueGroup( 1018341, new int[]{ 2119, 2120, 2121, 2122, 2123, 2124 } ), + /* Greens */ + new CustomHueGroup( 1018342, new int[]{ 2126, 2127, 2128, 2129, 2130 } ), + /* Yellows */ + new CustomHueGroup( 1018343, new int[]{ 2213, 2214, 2215, 2216, 2217, 2218 } ) + }, true ); + } + + public delegate void CustomHuePickerCallback( Mobile from, object state, int hue ); + + public class CustomHuePickerGump : Gump + { + private Mobile m_From; + private CustomHuePicker m_Definition; + private CustomHuePickerCallback m_Callback; + private object m_State; + + private int GetRadioID( int group, int index ) + { + return (index * m_Definition.Groups.Length) + group; + } + + private void RenderBackground() + { + AddPage( 0 ); + + AddBackground( 0, 0, 450, 450, 5054 ); + AddBackground( 10, 10, 430, 430, 3000 ); + + if ( m_Definition.TitleString != null ) + AddHtml( 20, 30, 400, 25, m_Definition.TitleString, false, false ); + else if ( m_Definition.Title > 0 ) + AddHtmlLocalized( 20, 30, 400, 25, m_Definition.Title, false, false ); + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 400, 200, 25, 1011036, false, false ); // OKAY + + if ( m_Definition.DefaultSupported ) + { + AddButton( 200, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddLabel( 235, 400, 0, "DEFAULT" ); + } + } + + private void RenderCategories() + { + CustomHueGroup[] groups = m_Definition.Groups; + + for ( int i = 0; i < groups.Length; ++i ) + { + AddButton( 30, 85 + (i * 25), 5224, 5224, 0, GumpButtonType.Page, 1 + i ); + + if ( groups[i].NameString != null ) + AddHtml( 55, 85 + (i * 25), 200, 25, groups[i].NameString, false, false ); + else + AddHtmlLocalized( 55, 85 + (i * 25), 200, 25, groups[i].Name, false, false ); + } + + for ( int i = 0; i < groups.Length; ++i ) + { + AddPage( 1 + i ); + + int[] hues = groups[i].Hues; + + for ( int j = 0; j < hues.Length; ++j ) + { + AddRadio( 260, 90 + (j * 25), 210, 211, false, GetRadioID( i, j ) ); + AddLabel( 278, 90 + (j * 25), hues[j] - 1, "*****" ); + } + } + } + + public CustomHuePickerGump( Mobile from, CustomHuePicker definition, CustomHuePickerCallback callback, object state ) : base( 50, 50 ) + { + m_From = from; + m_Definition = definition; + m_Callback = callback; + m_State = state; + + RenderBackground(); + RenderCategories(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch ( info.ButtonID ) + { + case 1: // Okay + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + int group = index % m_Definition.Groups.Length; + index /= m_Definition.Groups.Length; + + if ( group >= 0 && group < m_Definition.Groups.Length ) + { + int[] hues = m_Definition.Groups[group].Hues; + + if ( index >= 0 && index < hues.Length ) + m_Callback( m_From, m_State, hues[index] ); + } + } + + break; + } + case 2: // Default + { + if ( m_Definition.DefaultSupported ) + m_Callback( m_From, m_State, 0 ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs new file mode 100644 index 0000000..ade5211 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/DyeTub.cs @@ -0,0 +1,347 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Targeting; +using Server.ContextMenus; +using Server.Gumps; + +namespace Server.Items +{ + + + public interface IDyable + { + bool Dye( Mobile from, DyeTub sender ); + } + + public class DyeTub : Item, ISecurable + { + private bool m_Redyable; + private int m_DyedHue; + private SecureLevel m_SecureLevel; + + //Ajout Charges + private int m_Charges; + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get + { + return m_Charges; + } + set + { + m_Charges = value; + } + } + + public virtual CustomHuePicker CustomHuePicker{ get{ return null; } } + + + + public virtual bool AllowRunebooks + { + get{ return false; } + } + + public virtual bool AllowFurniture + { + get{ return false; } + } + + public virtual bool AllowStatuettes + { + get{ return false; } + } + + public virtual bool AllowLeather + { + get{ return false; } + } + + public virtual bool AllowDyables + { + get{ return true; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + writer.Write((int)m_Charges); + writer.Write( (int)m_SecureLevel ); + writer.Write( (bool) m_Redyable ); + writer.Write( (int) m_DyedHue ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_Charges = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_SecureLevel = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_Redyable = reader.ReadBool(); + m_DyedHue = reader.ReadInt(); + + break; + } + } + + if (version < 2) + m_Charges = 10; + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool Redyable + { + get + { + return m_Redyable; + } + set + { + m_Redyable = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DyedHue + { + get + { + return m_DyedHue; + } + set + { + if ( m_Redyable ) + { + m_DyedHue = value; + Hue = value; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get + { + return m_SecureLevel; + } + set + { + m_SecureLevel = value; + } + } + + [Constructable] + public DyeTub() : base( 0xFAB ) + { + Weight = 10.0; + Charges = 10; + m_Redyable = true; + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public DyeTub( Serial serial ) : base( serial ) + { + } + + // Three metallic tubs now. + public virtual bool MetallicHues { get { return false; } } + + // Select the clothing to dye. + public virtual int TargetMessage{ get{ return 500859; } } + + // You can not dye that. + public virtual int FailMessage{ get{ return 1042083; } } + + public override void OnDoubleClick( Mobile from ) + { + if (Charges <= 0) + { + from.SendMessage("Ce bac est vide"); + return; + } + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( TargetMessage ); + from.Target = new InternalTarget( this ); + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + + public void CheckEmpty() + { + if (Charges<=0) + { + DyedHue = 0; + } + } + + private class InternalTarget : Target + { + private DyeTub m_Tub; + + public InternalTarget( DyeTub tub ) : base( 1, false, TargetFlags.None ) + { + m_Tub = tub; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Item ) + { + Item item = (Item)targeted; + + if (item.QuestItem) + { + from.SendLocalizedMessage(1151836); // You may not dye toggled quest items. + } + else if (item is IDyable && m_Tub.AllowDyables) + { + if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) ) + from.SendLocalizedMessage( 500446 ); // That is too far away. + else if ( item.Parent is Mobile ) + from.SendLocalizedMessage( 500861 ); // Can't Dye clothing that is being worn. + else if ( ((IDyable)item).Dye( from, m_Tub ) ) + { + from.PlaySound( 0x23E ); + m_Tub.Charges--; + m_Tub.CheckEmpty(); + } + } + else if ( (FurnitureAttribute.Check( item ) || (item is PotionKeg)) && m_Tub.AllowFurniture ) + { + if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else + { + bool okay = ( item.IsChildOf( from.Backpack ) ); + + if ( !okay ) + { + if ( item.Parent == null ) + { + BaseHouse house = BaseHouse.FindHouseAt( item ); + + // Scriptiz : ajout pour rendre les addon furniture dyable && !(item is AddonComponent) + if ( house == null || ( !house.IsLockedDown( item ) && !house.IsSecure( item ) && !(item is AddonComponent) ) ) + from.SendLocalizedMessage( 501022 ); // Furniture must be locked down to paint it. + else if ( !house.IsCoOwner( from ) ) + from.SendLocalizedMessage( 501023 ); // You must be the owner to use this item. + else + okay = true; + } + else + { + from.SendLocalizedMessage( 1048135 ); // The furniture must be in your backpack to be painted. + } + } + + if ( okay ) + { + item.Hue = m_Tub.DyedHue; + from.PlaySound( 0x23E ); + m_Tub.Charges--; + m_Tub.CheckEmpty(); + } + } + } + else if ( (item is Runebook || item is RecallRune ) && m_Tub.AllowRunebooks ) + { + if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( !item.Movable ) + { + from.SendLocalizedMessage( 1049776 ); // You cannot dye runes or runebooks that are locked down. + } + else + { + item.Hue = m_Tub.DyedHue; + from.PlaySound( 0x23E ); + m_Tub.Charges--; + m_Tub.CheckEmpty(); + } + } + else if ( item is MonsterStatuette && m_Tub.AllowStatuettes ) + { + if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( !item.Movable ) + { + from.SendLocalizedMessage( 1049779 ); // You cannot dye statuettes that are locked down. + } + else + { + item.Hue = m_Tub.DyedHue; + from.PlaySound( 0x23E ); + m_Tub.Charges--; + m_Tub.CheckEmpty(); + } + } + else if ( (item is BaseArmor && (((BaseArmor)item).MaterialType == ArmorMaterialType.Leather || ((BaseArmor)item).MaterialType == ArmorMaterialType.Studded) || item is ElvenBoots || item is WoodlandBelt) && m_Tub.AllowLeather ) + { + if ( !from.InRange( m_Tub.GetWorldLocation(), 1 ) || !from.InRange( item.GetWorldLocation(), 1 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( !item.Movable ) + { + from.SendLocalizedMessage( 1042419 ); // You may not dye leather items which are locked down. + } + else if ( item.Parent is Mobile ) + { + from.SendLocalizedMessage( 500861 ); // Can't Dye clothing that is being worn. + } + else + { + item.Hue = m_Tub.DyedHue; + from.PlaySound( 0x23E ); + m_Tub.Charges--; + m_Tub.CheckEmpty(); + } + } + else + { + from.SendLocalizedMessage( m_Tub.FailMessage ); + } + } + else + { + from.SendLocalizedMessage( m_Tub.FailMessage ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs new file mode 100644 index 0000000..f12b2e5 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/FurnitureDyeTub.cs @@ -0,0 +1,76 @@ +using System; + +namespace Server.Items +{ + public class FurnitureDyeTub : DyeTub, Engines.VeteranRewards.IRewardItem + { + public override bool AllowDyables{ get{ return false; } } + public override bool AllowFurniture{ get{ return true; } } + public override int TargetMessage{ get{ return 501019; } } // Select the furniture to dye. + public override int FailMessage{ get{ return 501021; } } // That is not a piece of furniture. + public override int LabelNumber{ get{ return 1041246; } } // Furniture Dye Tub + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [Constructable] + public FurnitureDyeTub() + { + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + base.OnDoubleClick( from ); + } + + public FurnitureDyeTub( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076217 ); // 1st Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + + if ( LootType == LootType.Regular ) + LootType = LootType.Blessed; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs new file mode 100644 index 0000000..d143a42 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/LeatherDyeTub.cs @@ -0,0 +1,74 @@ +using System; + +namespace Server.Items +{ + public class LeatherDyeTub : DyeTub, Engines.VeteranRewards.IRewardItem + { + public override bool AllowDyables{ get{ return false; } } + public override bool AllowLeather{ get{ return true; } } + public override int TargetMessage{ get{ return 1042416; } } // Select the leather item to dye. + public override int FailMessage{ get{ return 1042418; } } // You can only dye leather with this tub. + public override int LabelNumber{ get{ return 1041284; } } // Leather Dye Tub + public override CustomHuePicker CustomHuePicker { get { return CustomHuePicker.LeatherDyeTub; } } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [Constructable] + public LeatherDyeTub() + { + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + base.OnDoubleClick( from ); + } + + public LeatherDyeTub( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076218 ); // 2nd Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs new file mode 100644 index 0000000..7a69268 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicClothDyetub.cs @@ -0,0 +1,36 @@ +using System; + +namespace Server.Items +{ + public class MetallicClothDyetub : DyeTub + { + public override int LabelNumber { get { return 1152920; } } // Metallic Cloth ... + + public override bool MetallicHues { get { return true; } } + + [Constructable] + public MetallicClothDyetub() + { + LootType = LootType.Blessed; + } + + public MetallicClothDyetub( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs new file mode 100644 index 0000000..35f46c0 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicHuePicker.cs @@ -0,0 +1,82 @@ +using Server; +using Server.Gumps; +using Server.Network; +using System; + +namespace Server.Items +{ + public class MetallicHuePicker : Gump + { + public delegate void MetallicHuePickerCallback( Mobile from, object state, int hue ); + + private Mobile m_From; + private MetallicHuePickerCallback m_Callback; + private object m_State; + + public void Render() + { + AddPage( 0 ); + + AddBackground( 0, 0, 450, 450, 0x13BE ); + AddBackground( 10, 10, 430, 430, 0xBB8 ); + + AddHtmlLocalized( 55, 400, 200, 25, 1011036, false, false ); // OKAY + + AddButton( 20, 400, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddButton( 200, 400, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddLabel( 235, 400, 0, "DEFAULT" ); + + AddHtmlLocalized( 55, 25, 200, 25, 1150063, false, false ); // Base/Shadow Color + AddHtmlLocalized( 260, 25, 200, 25, 1150064, false, false ); // Highlight Color + + for( int row = 0; row < 13; row++ ) + { + AddButton( 30, ( 65 + ( row * 25 ) ), 0x1467, 0x1468, row + 1, GumpButtonType.Page, row + 1 ); + AddItem( 50, ( 65 + ( row * 25 ) ), 0x1412, 2501 + ( row * 12 ) + ( ( row == 12 ) ? 6 : 0 ) ); + } + + for( int page = 1; page < 14; page++ ) + { + AddPage( page ); + + for( int row = 0; row < 12; row++ ) + { + int hue = ( 2501 + ( ( page == 13 ) ? 6 : 0 ) + ( row + ( 12 * ( page - 1 ) ) ) ); /* OSI just had to skip 6 unused hues, didnt they */ + AddRadio( 260, ( 65 + ( row * 25 ) ), 0xd2, 0xd3, false, hue ); + AddItem( 280, ( 65 + ( row * 25 ) ), 0x1412, hue ); + } + } + } + + public MetallicHuePicker( Mobile from, MetallicHuePickerCallback callback, object state ) + : base( 450, 450 ) + { + m_From = from; + m_Callback = callback; + m_State = state; + + Render(); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + switch( info.ButtonID ) + { + case 1: // Okay + { + if( info.Switches.Length > 0 ) + { + m_Callback( m_From, m_State, info.Switches[ 0 ] ); + } + break; + } + case 2: // Default + { + m_Callback( m_From, m_State, 0 ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs new file mode 100644 index 0000000..4744849 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/MetallicLeatherDyeTub.cs @@ -0,0 +1,46 @@ +using System; + +namespace Server.Items +{ + public class MetallicLeatherDyeTub : LeatherDyeTub + { + public override CustomHuePicker CustomHuePicker{ get{ return null; } } + + public override int LabelNumber { get { return 1153495; } } // Metallic Leather ... + + public override bool MetallicHues { get { return true; } } + + [Constructable] + public MetallicLeatherDyeTub() + { + LootType = LootType.Blessed; + } + + public MetallicLeatherDyeTub( Serial serial ) + : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && IsRewardItem ) + list.Add( 1076221 ); // 5th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs new file mode 100644 index 0000000..bc60a9e --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/RewardBlackDyeTub.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class RewardBlackDyeTub : DyeTub, Engines.VeteranRewards.IRewardItem + { + public override int LabelNumber{ get{ return 1006008; } } // Black Dye Tub + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [Constructable] + public RewardBlackDyeTub() + { + Hue = DyedHue = 0x0001; + Redyable = false; + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + base.OnDoubleClick( from ); + } + + public RewardBlackDyeTub( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076217 ); // 1st Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs new file mode 100644 index 0000000..c1b32e5 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/RunebookDyeTub.cs @@ -0,0 +1,74 @@ +using System; + +namespace Server.Items +{ + public class RunebookDyeTub : DyeTub, Engines.VeteranRewards.IRewardItem + { + public override bool AllowDyables{ get{ return false; } } + public override bool AllowRunebooks{ get{ return true; } } + public override int TargetMessage{ get{ return 1049774; } } // Target the runebook or runestone to dye + public override int FailMessage{ get{ return 1049775; } } // You can only dye runestones or runebooks with this tub. + public override int LabelNumber{ get{ return 1049740; } } // Runebook Dye Tub + public override CustomHuePicker CustomHuePicker{ get{ return CustomHuePicker.LeatherDyeTub; } } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [Constructable] + public RunebookDyeTub() + { + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + base.OnDoubleClick( from ); + } + + public RunebookDyeTub( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076220 ); // 4th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs new file mode 100644 index 0000000..c0dac17 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/SpecialDyeTub.cs @@ -0,0 +1,85 @@ +using System; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class SpecialDyeTub : DyeTub, IRewardItem + { + public override CustomHuePicker CustomHuePicker{ get{ return CustomHuePicker.SpecialDyeTub; } } + public override int LabelNumber{ get{ return 1041285; } } // Special Dye Tub + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [Constructable] + public SpecialDyeTub() + { + // Scriptiz : blessed uniquement si item reward + if (Core.ML && m_IsRewardItem) + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + + if ( m_IsRewardItem && !Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if (Charges <= 0) + { + from.SendMessage("Ce bac est vide"); + return; + } + if (!from.CheckSkill(SkillName.Tailoring, -5, 50)) + { + from.SendMessage("Vous ratez votre essais"); + Charges--; + } + + base.OnDoubleClick( from ); + } + + public SpecialDyeTub( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076217 ); // 1st Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs new file mode 100644 index 0000000..49ac24e --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/StatuetteDyeTub.cs @@ -0,0 +1,74 @@ +using System; + +namespace Server.Items +{ + public class StatuetteDyeTub : DyeTub, Engines.VeteranRewards.IRewardItem + { + public override bool AllowDyables{ get{ return false; } } + public override bool AllowStatuettes{ get{ return true; } } + public override int TargetMessage{ get{ return 1049777; } } // Target the statuette to dye + public override int FailMessage{ get{ return 1049778; } } // You can only dye veteran reward statuettes with this tub. + public override int LabelNumber{ get{ return 1049741; } } // Reward Statuette Dye Tub + public override CustomHuePicker CustomHuePicker{ get{ return CustomHuePicker.LeatherDyeTub; } } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [Constructable] + public StatuetteDyeTub() + { + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !Engines.VeteranRewards.RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + base.OnDoubleClick( from ); + } + + public StatuetteDyeTub( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076221 ); // 5th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs new file mode 100644 index 0000000..0bb97d1 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/WhiteClothDyeTub.cs @@ -0,0 +1,37 @@ +using Server; +using System; + +namespace Server.Items /* High seas, loot from merchant ship's hold, also a "uncommon" loot item */ +{ + public class WhiteClothDyeTub : DyeTub + { + public override int LabelNumber { get { return 1149984; } } // White Cloth Dye Tub + + public override bool Redyable { get { return false; } } + + [Constructable] + public WhiteClothDyeTub() + { + DyedHue = Hue = 0x9C2; + } + + public WhiteClothDyeTub( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs new file mode 100644 index 0000000..4af6154 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Dyetubs/WhiteLeatherDyeTub.cs @@ -0,0 +1,39 @@ +using Server; +using System; + +namespace Server.Items +{ + public class WhiteLeatherDyeTub : LeatherDyeTub /* OSI UO 13th anniv gift, from redeemable gift tickets */ + { + public override int LabelNumber { get { return 1149900; } } // White Leather Dye Tub + + public override bool Redyable { get { return false; } } + + [Constructable] + public WhiteLeatherDyeTub() + { + DyedHue = Hue = 0x9C2; + LootType = LootType.Blessed; + } + + + public WhiteLeatherDyeTub( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( ( int )1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Misc/Dressform.cs b/Scripts/Items/Skill Items/Tailor Items/Misc/Dressform.cs new file mode 100644 index 0000000..ce92762 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Misc/Dressform.cs @@ -0,0 +1,32 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute(0xec6, 0xec7)] + public class Dressform : Item + { + [Constructable] + public Dressform() : base(0xec6) + { + Weight = 10; + } + + public Dressform(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs b/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs new file mode 100644 index 0000000..992c157 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Misc/Dyes.cs @@ -0,0 +1,131 @@ +using System; +using Server.Targeting; +using Server.HuePickers; + +namespace Server.Items +{ + public class Dyes : Item /* , IUsesRemaining */ /* TODO complete usesremaing */ + { + /* + public bool ShowUsesRemaining { get { return false; } set { } } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int UsesRemaining { get { return m_UsesRemaining; } set { m_UsesRemaining = value; } } + + private int m_UsesRemaining; + */ + + [Constructable] + public Dyes() : base( 0xFA9 ) + { + Weight = 3.0; + /* m_UsesRemaining = 25; */ + } + + public Dyes( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write((int)1); // version + + /* writer.Write( ( int )m_UsesRemaining ); */ + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 0.0 ) + Weight = 3.0; + /* m_UsesRemaining = ( version == 0 ) ? 25 : reader.ReadInt(); */ + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 500856 ); // Select the dye tub to use the dyes on. + from.Target = new InternalTarget(); + } + + private class InternalTarget : Target + { + public InternalTarget() : base( 1, false, TargetFlags.None ) + { + } + + private class InternalPicker : HuePicker + { + private DyeTub m_Tub; + + public InternalPicker( DyeTub tub ) : base( tub.ItemID ) + { + m_Tub = tub; + } + + public override void OnResponse( int hue ) + { + m_Tub.DyedHue = hue; + + m_Tub.Charges = 10; + m_Tub.Redyable = false; + + } + } + + public virtual void SetTubHue(Mobile from, object state, int hue) + { + if (state is DyeTub) + { + DyeTub tub = state as DyeTub; + + tub.DyedHue = hue; + + /* dyes.m_UsesRemaining--; let this change ride till the overhaul */ + } + ((DyeTub)state).Charges = 10; + ((DyeTub)state).Redyable = false; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is DyeTub ) + { + DyeTub tub = (DyeTub) targeted; + + if (tub.Redyable) + { + if (tub.MetallicHues) /* OSI has three metallic tubs now */ + { + from.SendGump(new MetallicHuePicker(from, new MetallicHuePicker.MetallicHuePickerCallback(SetTubHue), tub)); + } + else if (tub.CustomHuePicker != null) + { + from.SendGump(new CustomHuePickerGump(from, tub.CustomHuePicker, new CustomHuePickerCallback(SetTubHue), tub)); + } + else + { + from.SendHuePicker(new InternalPicker(tub)); + } + } + else if ( tub is BlackDyeTub ) + { + from.SendLocalizedMessage( 1010092 ); // You can not use this on a black dye tub. + } + else + { + from.SendMessage( "That dye tub may not be redyed." ); + } + } + else + { + from.SendLocalizedMessage( 500857 ); // Use this on a dye tub. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs b/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs new file mode 100644 index 0000000..f7ee6e1 --- /dev/null +++ b/Scripts/Items/Skill Items/Tailor Items/Misc/Scissors.cs @@ -0,0 +1,164 @@ +using System; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Items +{ + public interface IScissorable + { + bool Scissor( Mobile from, Scissors scissors ); + } + + [FlipableAttribute( 0xf9f, 0xf9e )] + public class Scissors : Item + { + [Constructable] + public Scissors() : base( 0xF9F ) + { + Weight = 1.0; + } + + public Scissors( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 502434 ); // What should I use these scissors on? + + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private static void CutHair(object[] states) + { + Mobile from = states[0] as Mobile; + PlayerMobile target = states[1] as PlayerMobile; + + if (!target.InRange(from.Location, 2)) + { + from.SendMessage("Votre cible est trop loin pour que vous r�ussissiez � lui couper les cheveux"); + return; + } + + if (target.FindItemOnLayer(Layer.Helm) is BaseArmor) + { + from.SendMessage("Couper un casque serait trop difficile"); + return; + } + from.Say("*Coupe une m�che de cheveux � " + target.Name + "*"); + HairStrand meche = new HairStrand(); + meche.HairOwner = target; + from.AddToBackpack(meche); + } + + private Scissors m_Item; + + public InternalTarget( Scissors item ) : base( 2, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) + return; + + /*if ( targeted is Item && !((Item)targeted).IsStandardLoot() ) + { + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + } + else */ + if( Core.AOS && targeted == from ) + { + from.SendLocalizedMessage( 1062845 + Utility.Random( 3 ) ); //"That doesn't seem like the smartest thing to do." / "That was an encounter you don't wish to repeat." / "Ha! You missed!" + } + else if( Core.SE && Utility.RandomDouble() > .20 && (from.Direction & Direction.Running) != 0 && ( DateTime.Now - from.LastMoveTime ) < from.ComputeMovementSpeed( from.Direction ) ) + { + from.SendLocalizedMessage( 1063305 ); // Didn't your parents ever tell you not to run with scissors in your hand?! + } + else if( targeted is Item && !((Item)targeted).Movable ) + { + if( targeted is IScissorable && ( targeted is PlagueBeastInnard || targeted is PlagueBeastMutationCore ) ) + { + IScissorable obj = (IScissorable) targeted; + + if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) + from.PlaySound(0x248); + } + } + else if (targeted is PlayerMobile) + { + PlayerMobile hair = (PlayerMobile)targeted; + + if(hair.HairItemID == 0) + { + from.SendMessage("Cette personne est chauve"); + return; + } + + int delay = 4; + if (from.Dex > 80) + delay--; + if (from.Skills[SkillName.Stealing].Value > 50) + delay--; + + from.Say("*Approche discr�tement, ciseaux � la main*"); + Timer.DelayCall(TimeSpan.FromSeconds(delay), new TimerStateCallback(CutHair), new object[] { from, hair }); + } + else if( targeted is IScissorable ) + { + IScissorable obj = (IScissorable)targeted; + + if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) + from.PlaySound(0x248); + } + else + { + from.SendLocalizedMessage( 502440 ); // Scissors can not be used on that to produce anything. + } + } + + protected override void OnNonlocalTarget( Mobile from, object targeted ) + { + if ( targeted is IScissorable && ( targeted is PlagueBeastInnard || targeted is PlagueBeastMutationCore ) ) + { + IScissorable obj = (IScissorable) targeted; + + if (CanScissor(from, obj) && obj.Scissor(from, m_Item)) + from.PlaySound(0x248); + } + else + base.OnNonlocalTarget( from, targeted ); + } + } + public static bool CanScissor(Mobile from, IScissorable obj) + { + if (obj is Item && ((Item)obj).Nontransferable) + { + from.SendLocalizedMessage(502440); // Scissors can not be used on that to produce anything. + return false; + } + + // TODO: Move other general checks from the different implementations here + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Thief/DisguiseKit.cs b/Scripts/Items/Skill Items/Thief/DisguiseKit.cs new file mode 100644 index 0000000..918d318 --- /dev/null +++ b/Scripts/Items/Skill Items/Thief/DisguiseKit.cs @@ -0,0 +1,372 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.Seventh; +using Server.Spells.Necromancy; +using Server.Mobiles; +using Server.Network; +using Server.SkillHandlers; + +namespace Server.Items +{ + public class DisguiseKit : Item + { + public override int LabelNumber{ get{ return 1041078; } } // a disguise kit + + [Constructable] + public DisguiseKit() : base( 0xE05 ) + { + Weight = 1.0; + } + + public DisguiseKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public bool ValidateUse( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( !IsChildOf( from.Backpack ) ) + { + // That must be in your pack for you to use it. + from.SendLocalizedMessage( 1042001 ); + } + else if ( pm == null || pm.NpcGuild != NpcGuild.ThievesGuild ) + { + // Only Members of the thieves guild are trained to use this item. + from.SendLocalizedMessage( 501702 ); + } + else if ( Stealing.SuspendOnMurder && pm.Kills > 0 ) + { + // You are currently suspended from the thieves guild. They would frown upon your actions. + from.SendLocalizedMessage( 501703 ); + } + else if ( !from.CanBeginAction( typeof( IncognitoSpell ) ) ) + { + // You cannot disguise yourself while incognitoed. + from.SendLocalizedMessage( 501704 ); + } + else if ( Factions.Sigil.ExistsOn( from ) ) + { + from.SendLocalizedMessage( 1010465 ); // You cannot disguise yourself while holding a sigil + } + else if ( TransformationSpellHelper.UnderTransformation( from ) ) + { + // You cannot disguise yourself while in that form. + from.SendLocalizedMessage( 1061634 ); + } + else if ( from.BodyMod == 183 || from.BodyMod == 184 ) + { + // You cannot disguise yourself while wearing body paint + from.SendLocalizedMessage( 1040002 ); + } + else if ( !from.CanBeginAction( typeof( PolymorphSpell ) ) || from.IsBodyMod ) + { + // You cannot disguise yourself while polymorphed. + from.SendLocalizedMessage( 501705 ); + } + else + { + return true; + } + + return false; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( ValidateUse( from ) ) + from.SendGump( new DisguiseGump( from, this, true, false ) ); + } + } + + public class DisguiseGump : Gump + { + private Mobile m_From; + private DisguiseKit m_Kit; + private bool m_Used; + + public DisguiseGump( Mobile from, DisguiseKit kit, bool startAtHair, bool used ) : base( 50, 50 ) + { + m_From = from; + m_Kit = kit; + m_Used = used; + + from.CloseGump( typeof( DisguiseGump ) ); + + AddPage( 0 ); + + AddBackground( 100, 10, 400, 385, 2600 ); + + //
THIEF DISGUISE KIT
+ AddHtmlLocalized( 100, 25, 400, 35, 1011045, false, false ); + + AddButton( 140, 353, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 172, 355, 90, 35, 1011036, false, false ); // OKAY + + AddButton( 257, 353, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 289, 355, 90, 35, 1011046, false, false ); // APPLY + + if ( from.Female || from.Body.IsFemale ) + { + DrawEntries( 0, 1, -1, m_HairEntries, -1 ); + } + else if ( startAtHair ) + { + DrawEntries( 0, 1, 2, m_HairEntries, 1011056 ); + DrawEntries( 1, 2, 1, m_BeardEntries, 1011059 ); + } + else + { + DrawEntries( 1, 1, 2, m_BeardEntries, 1011059 ); + DrawEntries( 0, 2, 1, m_HairEntries, 1011056 ); + } + } + + private void DrawEntries( int index, int page, int nextPage, DisguiseEntry[] entries, int nextNumber ) + { + AddPage( page ); + + if ( nextPage != -1 ) + { + AddButton( 155, 320, 250 + (index*2), 251 + (index*2), 0, GumpButtonType.Page, nextPage ); + AddHtmlLocalized( 180, 320, 150, 35, nextNumber, false, false ); + } + + for ( int i = 0; i < entries.Length; ++i ) + { + DisguiseEntry entry = entries[i]; + + if ( entry == null ) + continue; + + int x = (i % 2) * 205; + int y = (i / 2) * 55; + + if ( entry.m_GumpID != 0 ) + { + AddBackground( 220 + x, 60 + y, 50, 50, 2620 ); + AddImage( 153 + x + entry.m_OffsetX, 15 + y + entry.m_OffsetY, entry.m_GumpID ); + } + + AddHtmlLocalized( 140 + x, 72 + y, 80, 35, entry.m_Number, false, false ); + AddRadio( 118 + x, 73 + y, 208, 209, false, (i * 2) + index ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 ) + { + if ( m_Used ) + m_From.SendLocalizedMessage( 501706 ); // Disguises wear off after 2 hours. + else + m_From.SendLocalizedMessage( 501707 ); // You're looking good. + + return; + } + + int[] switches = info.Switches; + + if ( switches.Length == 0 ) + return; + + int switched = switches[0]; + int type = switched % 2; + int index = switched / 2; + + bool hair = ( type == 0 ); + + DisguiseEntry[] entries = ( hair ? m_HairEntries : m_BeardEntries ); + + if ( index >= 0 && index < entries.Length ) + { + DisguiseEntry entry = entries[index]; + + if ( entry == null ) + return; + + if ( !m_Kit.ValidateUse( m_From ) ) + return; + + if ( !hair && (m_From.Female || m_From.Body.IsFemale) ) + return; + + m_From.NameMod = NameList.RandomName( m_From.Female ? "female" : "male" ); + + if ( m_From is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m_From; + + if ( hair ) + pm.SetHairMods( entry.m_ItemID, -2 ); + else + pm.SetHairMods( -2, entry.m_ItemID ); + } + + m_From.SendGump( new DisguiseGump( m_From, m_Kit, hair, true ) ); + + DisguiseTimers.RemoveTimer( m_From ); + + DisguiseTimers.CreateTimer( m_From, TimeSpan.FromHours( 2.0 ) ); + DisguiseTimers.StartTimer( m_From ); + } + } + + private static DisguiseEntry[] m_HairEntries = new DisguiseEntry[] + { + new DisguiseEntry( 8251, 50700, 0, 5, 1011052 ), // Short + new DisguiseEntry( 8261, 60710, 0, 3, 1011047 ), // Pageboy + new DisguiseEntry( 8252, 60708, 0,- 5, 1011053 ), // Long + new DisguiseEntry( 8264, 60901, 0, 5, 1011048 ), // Receding + new DisguiseEntry( 8253, 60702, 0,- 5, 1011054 ), // Ponytail + new DisguiseEntry( 8265, 60707, 0,- 5, 1011049 ), // 2-tails + new DisguiseEntry( 8260, 50703, 0, 5, 1011055 ), // Mohawk + new DisguiseEntry( 8266, 60713, 0, 10, 1011050 ), // Topknot + null, + new DisguiseEntry( 0, 0, 0, 0, 1011051 ) // None + }; + + private static DisguiseEntry[] m_BeardEntries = new DisguiseEntry[] + { + new DisguiseEntry( 8269, 50906, 0, 0, 1011401 ), // Vandyke + new DisguiseEntry( 8257, 50808, 0,- 2, 1011062 ), // Mustache + new DisguiseEntry( 8255, 50802, 0, 0, 1011060 ), // Short beard + new DisguiseEntry( 8268, 50905, 0,-10, 1011061 ), // Long beard + new DisguiseEntry( 8267, 50904, 0, 0, 1011060 ), // Short beard + new DisguiseEntry( 8254, 50801, 0,-10, 1011061 ), // Long beard + null, + new DisguiseEntry( 0, 0, 0, 0, 1011051 ) // None + }; + + private class DisguiseEntry + { + public int m_Number; + public int m_ItemID; + public int m_GumpID; + public int m_OffsetX; + public int m_OffsetY; + + public DisguiseEntry( int itemID, int gumpID, int ox, int oy, int name ) + { + m_ItemID = itemID; + m_GumpID = gumpID; + m_OffsetX = ox; + m_OffsetY = oy; + m_Number = name; + } + } + } + + public class DisguiseTimers + { + public static void Initialize() + { + new DisguisePersistance(); + } + + private class InternalTimer : Timer + { + private Mobile m_Player; + + public InternalTimer( Mobile m, TimeSpan delay ) : base( delay ) + { + m_Player = m; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Player.NameMod = null; + + if ( m_Player is PlayerMobile ) + ((PlayerMobile)m_Player).SetHairMods( -1, -1 ); + + DisguiseTimers.RemoveTimer( m_Player ); + } + } + + public static void CreateTimer( Mobile m, TimeSpan delay ) + { + if ( m != null ) + if ( !m_Timers.Contains( m ) ) + m_Timers[m] = new InternalTimer( m, delay ); + } + + public static void StartTimer( Mobile m ) + { + Timer t = (Timer)m_Timers[m]; + + if ( t != null ) + t.Start(); + } + + public static bool IsDisguised( Mobile m ) + { + return m_Timers.Contains( m ); + } + + public static bool StopTimer( Mobile m ) + { + Timer t = (Timer)m_Timers[m]; + + if ( t != null ) + { + t.Delay = t.Next - DateTime.Now; + t.Stop(); + } + + return ( t != null ); + } + + public static bool RemoveTimer( Mobile m ) + { + Timer t = (Timer)m_Timers[m]; + + if ( t != null ) + { + t.Stop(); + m_Timers.Remove( m ); + } + + return ( t != null ); + } + + public static TimeSpan TimeRemaining( Mobile m ) + { + Timer t = (Timer)m_Timers[m]; + + if ( t != null ) + { + return t.Next - DateTime.Now; + } + + return TimeSpan.Zero; + } + + private static Hashtable m_Timers = new Hashtable(); + + public static Hashtable Timers + { + get { return m_Timers; } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs b/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs new file mode 100644 index 0000000..0a4ef81 --- /dev/null +++ b/Scripts/Items/Skill Items/Thief/DisguisePersistance.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class DisguisePersistance : Item + { + private static DisguisePersistance m_Instance; + + public static DisguisePersistance Instance{ get{ return m_Instance; } } + + public override string DefaultName + { + get { return "Disguise Persistance - Internal"; } + } + + public DisguisePersistance() : base( 1 ) + { + Movable = false; + + if ( m_Instance == null || m_Instance.Deleted ) + m_Instance = this; + else + base.Delete(); + } + + public DisguisePersistance( Serial serial ) : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + int timerCount = DisguiseTimers.Timers.Count; + + writer.Write( timerCount ); + + foreach ( DictionaryEntry entry in DisguiseTimers.Timers ) + { + Mobile m = (Mobile)entry.Key; + + writer.Write( m ); + writer.Write( ((Timer)entry.Value).Next - DateTime.Now ); + writer.Write( m.NameMod ); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + int count = reader.ReadInt(); + + for ( int i = 0; i < count; ++i ) + { + Mobile m = reader.ReadMobile(); + DisguiseTimers.CreateTimer( m, reader.ReadTimeSpan() ); + m.NameMod = reader.ReadString(); + } + + break; + } + } + } + + public override void Delete() + { + } + } +} diff --git a/Scripts/Items/Skill Items/Thief/LockPick.cs b/Scripts/Items/Skill Items/Thief/LockPick.cs new file mode 100644 index 0000000..3b73e24 --- /dev/null +++ b/Scripts/Items/Skill Items/Thief/LockPick.cs @@ -0,0 +1,171 @@ +using System; +using Server.Network; +using Server.Targeting; +using Server.Items; + +namespace Server.Items +{ + public interface ILockpickable : IPoint2D + { + int LockLevel{ get; set; } + bool Locked{ get; set; } + Mobile Picker{ get; set; } + int MaxLockLevel{ get; set; } + int RequiredSkill{ get; set; } + + void LockPick( Mobile from ); + } + + + + [FlipableAttribute( 0x14fc, 0x14fb )] + public class Lockpick : Item + { + [Constructable] + public Lockpick() : this( 1 ) + { + } + + [Constructable] + public Lockpick( int amount ) : base( 0x14FC ) + { + Stackable = true; + Amount = amount; + } + + public Lockpick( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 && Weight == 0.1 ) + Weight = -1; + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 502068 ); // What do you want to pick? + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private Lockpick m_Item; + + public InternalTarget( Lockpick item ) : base( 1, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) + return; + + if ( targeted is ILockpickable ) + { + Item item = (Item)targeted; + from.Direction = from.GetDirectionTo( item ); + + if ( ((ILockpickable)targeted).Locked ) + { + from.PlaySound( 0x241 ); + + new InternalTimer( from, (ILockpickable)targeted, m_Item ).Start(); + } + else + { + // The door is not locked + from.SendLocalizedMessage( 502069 ); // This does not appear to be locked + } + } + else + { + from.SendLocalizedMessage( 501666 ); // You can't unlock that! + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private ILockpickable m_Item; + private Lockpick m_Lockpick; + + public InternalTimer( Mobile from, ILockpickable item, Lockpick lockpick ) : base( TimeSpan.FromSeconds( 3.0 ) ) + { + m_From = from; + m_Item = item; + m_Lockpick = lockpick; + Priority = TimerPriority.TwoFiftyMS; + } + + protected void BrokeLockPickTest() + { + // When failed, a 25% chance to break the lockpick + if ( Utility.Random( 4 ) == 0 ) + { + Item item = (Item)m_Item; + + // You broke the lockpick. + item.SendLocalizedMessageTo( m_From, 502074 ); + + m_From.PlaySound( 0x3A4 ); + m_Lockpick.Consume(); + } + } + + protected override void OnTick() + { + Item item = (Item)m_Item; + + if ( !m_From.InRange( item.GetWorldLocation(), 1 ) ) + return; + + if ( m_Item.LockLevel == 0 || m_Item.LockLevel == -255 ) + { + // LockLevel of 0 means that the door can't be picklocked + // LockLevel of -255 means it's magic locked + item.SendLocalizedMessageTo( m_From, 502073 ); // This lock cannot be picked by normal means + return; + } + + if ( m_From.Skills[SkillName.Lockpicking].Value < m_Item.RequiredSkill ) + { + /* + // Do some training to gain skills + m_From.CheckSkill( SkillName.Lockpicking, 0, m_Item.LockLevel );*/ + + // The LockLevel is higher thant the LockPicking of the player + item.SendLocalizedMessageTo( m_From, 502072 ); // You don't see how that lock can be manipulated. + return; + } + + if ( m_From.CheckTargetSkill( SkillName.Lockpicking, m_Item, m_Item.LockLevel, m_Item.MaxLockLevel ) ) + { + // Success! Pick the lock! + item.SendLocalizedMessageTo( m_From, 502076 ); // The lock quickly yields to your skill. + m_From.PlaySound( 0x4A ); + m_Item.LockPick( m_From ); + } + else + { + // The player failed to pick the lock + BrokeLockPickTest(); + item.SendLocalizedMessageTo( m_From, 502075 ); // You are unable to pick the lock. + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Axle.cs b/Scripts/Items/Skill Items/Tinkering/Axle.cs new file mode 100644 index 0000000..f7c81f5 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Axle.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x105B, 0x105C )] + public class Axle : Item + { + [Constructable] + public Axle() : this( 1 ) + { + } + + [Constructable] + public Axle( int amount ) : base( 0x105B ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Axle( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/AxleGears.cs b/Scripts/Items/Skill Items/Tinkering/AxleGears.cs new file mode 100644 index 0000000..b72cc78 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/AxleGears.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1051, 0x1052 )] + public class AxleGears : Item + { + [Constructable] + public AxleGears() : this( 1 ) + { + } + + [Constructable] + public AxleGears( int amount ) : base( 0x1051 ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public AxleGears( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/ClockFrame.cs b/Scripts/Items/Skill Items/Tinkering/ClockFrame.cs new file mode 100644 index 0000000..3780c49 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/ClockFrame.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x104D, 0x104E )] + public class ClockFrame : Item + { + [Constructable] + public ClockFrame() : this( 1 ) + { + } + + [Constructable] + public ClockFrame( int amount ) : base( 0x104D ) + { + Stackable = true; + Amount = amount; + Weight = 2.0; + } + + public ClockFrame( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/ClockParts.cs b/Scripts/Items/Skill Items/Tinkering/ClockParts.cs new file mode 100644 index 0000000..74d16b7 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/ClockParts.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x104F, 0x1050 )] + public class ClockParts : Item + { + [Constructable] + public ClockParts() : this( 1 ) + { + } + + [Constructable] + public ClockParts( int amount ) : base( 0x104F ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public ClockParts( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Clocks.cs b/Scripts/Items/Skill Items/Tinkering/Clocks.cs new file mode 100644 index 0000000..3327002 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Clocks.cs @@ -0,0 +1,220 @@ +using System; +using Server; + +namespace Server.Items +{ + public enum MoonPhase + { + NewMoon, + WaxingCrescentMoon, + FirstQuarter, + WaxingGibbous, + FullMoon, + WaningGibbous, + LastQuarter, + WaningCrescent + } + + [Flipable( 0x104B, 0x104C )] + public class Clock : Item + { + private static DateTime m_ServerStart; + + public static DateTime ServerStart + { + get{ return m_ServerStart; } + } + + public static void Initialize() + { + m_ServerStart = DateTime.Now; + } + + [Constructable] + public Clock() : this( 0x104B ) + { + } + + [Constructable] + public Clock( int itemID ) : base( itemID ) + { + Weight = 3.0; + } + + public Clock( Serial serial ) : base( serial ) + { + } + + public const double SecondsPerUOMinute = 5.0; + public const double MinutesPerUODay = SecondsPerUOMinute * 24; + + private static DateTime WorldStart = new DateTime( 1997, 9, 1 ); + + public static MoonPhase GetMoonPhase( Map map, int x, int y ) + { + int hours, minutes, totalMinutes; + + GetTime( map, x, y, out hours, out minutes, out totalMinutes ); + + if ( map != null ) + totalMinutes /= 10 + (map.MapIndex * 20); + + return (MoonPhase)(totalMinutes % 8); + } + + public static void GetTime( Map map, int x, int y, out int hours, out int minutes ) + { + int totalMinutes; + + GetTime( map, x, y, out hours, out minutes, out totalMinutes ); + } + + public static void GetTime( Map map, int x, int y, out int hours, out int minutes, out int totalMinutes ) + { + TimeSpan timeSpan = DateTime.Now - WorldStart; + + totalMinutes = (int)(timeSpan.TotalSeconds / SecondsPerUOMinute); + + if ( map != null ) + totalMinutes += map.MapIndex * 320; + + // Really on OSI this must be by subserver + totalMinutes += x / 16; + + hours = (totalMinutes / 60) % 24; + minutes = totalMinutes % 60; + } + + public static void GetTime( out int generalNumber, out string exactTime ) + { + GetTime( null, 0, 0, out generalNumber, out exactTime ); + } + + public static void GetTime( Mobile from, out int generalNumber, out string exactTime ) + { + GetTime( from.Map, from.X, from.Y, out generalNumber, out exactTime ); + } + + public static void GetTime( Map map, int x, int y, out int generalNumber, out string exactTime ) + { + int hours, minutes; + + GetTime( map, x, y, out hours, out minutes ); + + // 00:00 AM - 00:59 AM : Witching hour + // 01:00 AM - 03:59 AM : Middle of night + // 04:00 AM - 07:59 AM : Early morning + // 08:00 AM - 11:59 AM : Late morning + // 12:00 PM - 12:59 PM : Noon + // 01:00 PM - 03:59 PM : Afternoon + // 04:00 PM - 07:59 PM : Early evening + // 08:00 PM - 11:59 AM : Late at night + + if ( hours >= 20 ) + generalNumber = 1042957; // It's late at night + else if ( hours >= 16 ) + generalNumber = 1042956; // It's early in the evening + else if ( hours >= 13 ) + generalNumber = 1042955; // It's the afternoon + else if ( hours >= 12 ) + generalNumber = 1042954; // It's around noon + else if ( hours >= 08 ) + generalNumber = 1042953; // It's late in the morning + else if ( hours >= 04 ) + generalNumber = 1042952; // It's early in the morning + else if ( hours >= 01 ) + generalNumber = 1042951; // It's the middle of the night + else + generalNumber = 1042950; // 'Tis the witching hour. 12 Midnight. + + hours %= 12; + + if ( hours == 0 ) + hours = 12; + + exactTime = String.Format( "{0}:{1:D2}", hours, minutes ); + } + + public override void OnDoubleClick( Mobile from ) + { + int genericNumber; + string exactTime; + + GetTime( from, out genericNumber, out exactTime ); + + SendLocalizedMessageTo( from, genericNumber ); + SendLocalizedMessageTo( from, 1042958, exactTime ); // ~1_TIME~ to be exact + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 3.0; + } + } + + [Flipable( 0x104B, 0x104C )] + public class ClockRight : Clock + { + [Constructable] + public ClockRight() : base( 0x104B ) + { + } + + public ClockRight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x104B, 0x104C )] + public class ClockLeft : Clock + { + [Constructable] + public ClockLeft() : base( 0x104C ) + { + } + + public ClockLeft( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Gears.cs b/Scripts/Items/Skill Items/Tinkering/Gears.cs new file mode 100644 index 0000000..71230e1 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Gears.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1053, 0x1054 )] + public class Gears : Item + { + [Constructable] + public Gears() : this( 1 ) + { + } + + [Constructable] + public Gears( int amount ) : base( 0x1053 ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Gears( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Globe.cs b/Scripts/Items/Skill Items/Tinkering/Globe.cs new file mode 100644 index 0000000..26dd31f --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Globe.cs @@ -0,0 +1,32 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Globe : Item + { + [Constructable] + public Globe() : base( 0x1047 ) // It isn't flipable + { + Weight = 3.0; + } + + public Globe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Hinge.cs b/Scripts/Items/Skill Items/Tinkering/Hinge.cs new file mode 100644 index 0000000..47dc7af --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Hinge.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1055, 0x1056 )] + public class Hinge : Item + { + [Constructable] + public Hinge() : this( 1 ) + { + } + + [Constructable] + public Hinge( int amount ) : base( 0x1055 ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Hinge( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/SextantParts.cs b/Scripts/Items/Skill Items/Tinkering/SextantParts.cs new file mode 100644 index 0000000..43a2221 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/SextantParts.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x1059, 0x105A )] + public class SextantParts : Item + { + [Constructable] + public SextantParts() : this( 1 ) + { + } + + [Constructable] + public SextantParts( int amount ) : base( 0x1059 ) + { + Stackable = true; + Amount = amount; + Weight = 2.0; + } + + public SextantParts( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Springs.cs b/Scripts/Items/Skill Items/Tinkering/Springs.cs new file mode 100644 index 0000000..4ebf44f --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Springs.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x105D, 0x105E )] + public class Springs : Item + { + [Constructable] + public Springs() : this( 1 ) + { + } + + [Constructable] + public Springs( int amount ) : base( 0x105D ) + { + Stackable = true; + Amount = amount; + Weight = 1.0; + } + + public Springs( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Spyglass.cs b/Scripts/Items/Skill Items/Tinkering/Spyglass.cs new file mode 100644 index 0000000..aeea724 --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Spyglass.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Engines.Quests; +using Server.Engines.Quests.Hag; +using Server.Multis; // Scriptiz : syst�me de track des bateaux +using Server.SkillHandlers; // Scriptiz : fl�che pour traquer + +namespace Server.Items +{ + [Flipable( 0x14F5, 0x14F6 )] + public class Spyglass : Item + { + [Constructable] + public Spyglass() : base( 0x14F5 ) + { + Weight = 3.0; + } + + public override void OnDoubleClick( Mobile from ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1008155 ); // You peer into the heavens, seeking the moons... + + from.Send( new MessageLocalizedAffix( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 1008146 + (int)Clock.GetMoonPhase( Map.Trammel, from.X, from.Y ), "", AffixType.Prepend, "Trammel : ", "" ) ); + + // Scriptiz : on ne joue pas sur felucca + //from.Send( new MessageLocalizedAffix( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 1008146 + (int)Clock.GetMoonPhase( Map.Felucca, from.X, from.Y ), "", AffixType.Prepend, "Felucca : ", "" ) ); + + PlayerMobile player = from as PlayerMobile; + + /* Scriptiz : Code pour rep�rer les autres bateaux (source : Alambik) */ + // Get the maximum range the player can see + // A cartograph master with a tracking master experience lead to see to 125 tiles: A true captain! + int MinimumRange = 25; //Regular 800x600 screen + "normal" extra + int MaximumExtraRange = 100; + int ExtraRange = MaximumExtraRange * + ((int)(from.Skills[SkillName.Cartography].Value) + + (int)(from.Skills[SkillName.Tracking].Value)) / 200; + int range = MinimumRange + ExtraRange; + + foreach (Item item in from.GetItemsInRange(range)) + { + if (item is BaseBoat) + { + // Player can see the boat + BaseBoat baseboat = (BaseBoat)item; + if (!(baseboat.Contains(from))) // On va �viter de r�peter qu'on voit son propre bateau + { + /* Scriptiz : impl�mentation du tracking */ + // If the player is good at tracking, let him track a mobile on the boat + if(from.Skills[SkillName.Tracking].Value * 2 >= from.GetDistanceToSqrt(baseboat.Location)) + { + foreach (Mobile m in baseboat.GetMobilesInRange(15)) + { + if (m == null) continue; + if (baseboat.Contains(m)) + { + from.QuestArrow = new TrackArrow(from, m, range); + break; + } + } + } + + // Get the name if not too far + string name = "un navire"; + if (from.InRange(item.Location, MinimumRange + MaximumExtraRange / 5)) + if (baseboat.ShipName != null) + name = "le" + baseboat.ShipName; + + // Is it far? + string distance = "� l'horizon"; + if (from.InRange(item.Location, MinimumRange + MaximumExtraRange * 1 / 5)) + distance = "� c�t�"; + else if (from.InRange(item.Location, MinimumRange + MaximumExtraRange * 2 / 5)) + distance = "proche"; + else if (from.InRange(item.Location, MinimumRange + MaximumExtraRange * 3 / 5)) + distance = "loin"; + else if (from.InRange(item.Location, MinimumRange + MaximumExtraRange * 4 / 5)) + distance = "tr�s loin"; + + // Get the relative direction of the seen boat + string direction; + // north/south + if (from.Y < baseboat.Y) + direction = "Sud"; + else + direction = "Nord"; + // east/west (Scriptiz : correction est <> ouest) + if (from.X < baseboat.X) + direction = direction + " Est"; + else + direction = direction + " Ouest"; + + //Does the boat is moving? + string mobility = "est immobile"; + if (baseboat.IsMoving) + { + mobility = "bouge vers "; + switch (baseboat.Moving) + { + case Direction.North: mobility += "le nord"; break; + case Direction.South: mobility += "le sud"; break; + case Direction.East: mobility += "l'est"; break; + case Direction.West: mobility += "l'ouest"; break; + case Direction.Up: mobility += "le nord-ouest"; break; + case Direction.Down: mobility += "le sud-est"; break; + case Direction.Left: mobility += "le sud-ouest"; break; + case Direction.Right: mobility += "le nord-est"; break; + default: break; + } + } + from.SendMessage("Vous voyez {0} au {1}. Il est {2} et {3}.", name, direction, distance, mobility); + } + } + } + /* Scriptiz : fin du code de Alambik */ + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + FindIngredientObjective obj = qs.FindObjective( typeof( FindIngredientObjective ) ) as FindIngredientObjective; + + if ( obj != null && !obj.Completed && obj.Ingredient == Ingredient.StarChart ) + { + int hours, minutes; + Clock.GetTime( from.Map, from.X, from.Y, out hours, out minutes ); + + if ( hours < 5 || hours > 17 ) + { + player.SendLocalizedMessage( 1055040 ); // You gaze up into the glittering night sky. With great care, you compose a chart of the most prominent star patterns. + + obj.Complete(); + } + else + { + player.SendLocalizedMessage( 1055039 ); // You gaze up into the sky, but it is not dark enough to see any stars. + } + } + } + } + } + + public Spyglass( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tinkering/Utensils.cs b/Scripts/Items/Skill Items/Tinkering/Utensils.cs new file mode 100644 index 0000000..033576c --- /dev/null +++ b/Scripts/Items/Skill Items/Tinkering/Utensils.cs @@ -0,0 +1,277 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x9F4, 0x9F5, 0x9A3, 0x9A4 )] + public class Fork : Item + { + [Constructable] + public Fork() : base( 0x9F4 ) + { + Weight = 1.0; + } + + public Fork( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ForkLeft : Item + { + [Constructable] + public ForkLeft() : base( 0x9F4 ) + { + Weight = 1.0; + } + + public ForkLeft( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ForkRight : Item + { + [Constructable] + public ForkRight() : base( 0x9F5 ) + { + Weight = 1.0; + } + + public ForkRight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x9F8, 0x9F9, 0x9C2, 0x9C3 )] + public class Spoon : Item + { + [Constructable] + public Spoon() : base( 0x9F8 ) + { + Weight = 1.0; + } + + public Spoon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SpoonLeft : Item + { + [Constructable] + public SpoonLeft() : base( 0x9F8 ) + { + Weight = 1.0; + } + + public SpoonLeft( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SpoonRight : Item + { + [Constructable] + public SpoonRight() : base( 0x9F9 ) + { + Weight = 1.0; + } + + public SpoonRight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [Flipable( 0x9F6, 0x9F7, 0x9A5, 0x9A6 )] + public class Knife : Item + { + [Constructable] + public Knife() : base( 0x9F6 ) + { + Weight = 1.0; + } + + public Knife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class KnifeLeft : Item + { + [Constructable] + public KnifeLeft() : base( 0x9F6 ) + { + Weight = 1.0; + } + + public KnifeLeft( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class KnifeRight : Item + { + [Constructable] + public KnifeRight() : base( 0x9F7 ) + { + Weight = 1.0; + } + + public KnifeRight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class Plate : Item + { + [Constructable] + public Plate() : base( 0x9D7 ) + { + Weight = 1.0; + } + + public Plate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs b/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs new file mode 100644 index 0000000..e1238d1 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/BaseRunicTool.cs @@ -0,0 +1,673 @@ +using System; +using System.Collections; + +namespace Server.Items +{ + public abstract class BaseRunicTool : BaseTool + { + + public BaseRunicTool( CraftResource resource, int itemID ) : base( itemID ) + { + this.Resource = resource; + } + + public BaseRunicTool( CraftResource resource, int uses, int itemID ) : base( uses, itemID ) + { + this.Resource = resource; + } + + public BaseRunicTool( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private static bool m_IsRunicTool; + private static int m_LuckChance; + + private static int Scale( int min, int max, int low, int high ) + { + int percent; + + if ( m_IsRunicTool ) + { + percent = Utility.RandomMinMax( min, max ); + } + else + { + // Behold, the worst system ever! + int v = Utility.RandomMinMax( 0, 10000 ); + + v = (int) Math.Sqrt( v ); + v = 100 - v; + + if ( LootPack.CheckLuck( m_LuckChance ) ) + v += 10; + + if ( v < min ) + v = min; + else if ( v > max ) + v = max; + + percent = v; + } + + int scaledBy = Math.Abs( high - low ) + 1; + + if ( scaledBy != 0 ) + scaledBy = 10000 / scaledBy; + + percent *= (10000 + scaledBy); + + return low + (((high - low) * percent) / 1000001); + } + + private static void ApplyAttribute( AosAttributes attrs, int min, int max, AosAttribute attr, int low, int high ) + { + ApplyAttribute( attrs, min, max, attr, low, high, 1 ); + } + + private static void ApplyAttribute( AosAttributes attrs, int min, int max, AosAttribute attr, int low, int high, int scale ) + { + if ( attr == AosAttribute.CastSpeed ) + attrs[attr] += Scale( min, max, low / scale, high / scale ) * scale; + else + attrs[attr] = Scale( min, max, low / scale, high / scale ) * scale; + + if ( attr == AosAttribute.SpellChanneling ) + attrs[AosAttribute.CastSpeed] -= 1; + } + + private static void ApplyAttribute( AosArmorAttributes attrs, int min, int max, AosArmorAttribute attr, int low, int high ) + { + attrs[attr] = Scale( min, max, low, high ); + } + + private static void ApplyAttribute( AosArmorAttributes attrs, int min, int max, AosArmorAttribute attr, int low, int high, int scale ) + { + attrs[attr] = Scale( min, max, low / scale, high / scale ) * scale; + } + + private static void ApplyAttribute( AosWeaponAttributes attrs, int min, int max, AosWeaponAttribute attr, int low, int high ) + { + attrs[attr] = Scale( min, max, low, high ); + } + + private static void ApplyAttribute( AosWeaponAttributes attrs, int min, int max, AosWeaponAttribute attr, int low, int high, int scale ) + { + attrs[attr] = Scale( min, max, low / scale, high / scale ) * scale; + } + + private static void ApplyAttribute( AosElementAttributes attrs, int min, int max, AosElementAttribute attr, int low, int high ) + { + attrs[attr] = Scale( min, max, low, high ); + } + + private static void ApplyAttribute( AosElementAttributes attrs, int min, int max, AosElementAttribute attr, int low, int high, int scale ) + { + attrs[attr] = Scale( min, max, low / scale, high / scale ) * scale; + } + + private static SkillName[] m_PossibleBonusSkills = new SkillName[] + { + SkillName.Swords, + SkillName.Fencing, + SkillName.Macing, + SkillName.Archery, + SkillName.Wrestling, + SkillName.Parry, + SkillName.Tactics, + SkillName.Anatomy, + SkillName.Healing, + SkillName.Magery, + SkillName.Meditation, + SkillName.EvalInt, + SkillName.MagicResist, + SkillName.AnimalTaming, + SkillName.AnimalLore, + SkillName.Veterinary, + SkillName.Musicianship, + SkillName.Provocation, + SkillName.Discordance, + SkillName.Peacemaking, + SkillName.Chivalry, + SkillName.Focus, + SkillName.Necromancy, + SkillName.Stealing, + SkillName.Stealth, + SkillName.SpiritSpeak, + SkillName.Bushido, + SkillName.Ninjitsu + }; + + private static SkillName[] m_PossibleSpellbookSkills = new SkillName[] + { + SkillName.Magery, + SkillName.Meditation, + SkillName.EvalInt, + SkillName.MagicResist + }; + + private static void ApplySkillBonus( AosSkillBonuses attrs, int min, int max, int index, int low, int high ) + { + SkillName[] possibleSkills = ( attrs.Owner is Spellbook ? m_PossibleSpellbookSkills : m_PossibleBonusSkills ); + int count = ( Core.SE ? possibleSkills.Length : possibleSkills.Length - 2 ); + + SkillName sk, check; + double bonus; + bool found; + + do + { + found = false; + sk = possibleSkills[Utility.Random( count )]; + + for ( int i = 0; !found && i < 5; ++i ) + found = ( attrs.GetValues( i, out check, out bonus ) && check == sk ); + } while ( found ); + + attrs.SetValues( index, sk, Scale( min, max, low, high ) ); + } + + private static void ApplyResistance( BaseArmor ar, int min, int max, ResistanceType res, int low, int high ) + { + switch ( res ) + { + case ResistanceType.Physical: ar.PhysicalBonus += Scale( min, max, low, high ); break; + case ResistanceType.Fire: ar.FireBonus += Scale( min, max, low, high ); break; + case ResistanceType.Cold: ar.ColdBonus += Scale( min, max, low, high ); break; + case ResistanceType.Poison: ar.PoisonBonus += Scale( min, max, low, high ); break; + case ResistanceType.Energy: ar.EnergyBonus += Scale( min, max, low, high ); break; + } + } + + private const int MaxProperties = 32; + private static BitArray m_Props = new BitArray( MaxProperties ); + private static int[] m_Possible = new int[MaxProperties]; + + public static int GetUniqueRandom( int count ) + { + int avail = 0; + + for ( int i = 0; i < count; ++i ) + { + if ( !m_Props[i] ) + m_Possible[avail++] = i; + } + + if ( avail == 0 ) + return -1; + + int v = m_Possible[Utility.Random( avail )]; + + m_Props.Set( v, true ); + + return v; + } + + public void ApplyAttributesTo( BaseWeapon weapon ) + { + CraftResourceInfo resInfo = CraftResources.GetInfo( Resource ); + + if ( resInfo == null ) + return; + + CraftAttributeInfo attrs = resInfo.AttributeInfo; + + if ( attrs == null ) + return; + + int attributeCount = Utility.RandomMinMax( attrs.RunicMinAttributes, attrs.RunicMaxAttributes ); + int min = attrs.RunicMinIntensity; + int max = attrs.RunicMaxIntensity; + + ApplyAttributesTo( weapon, true, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( BaseWeapon weapon, int attributeCount, int min, int max ) + { + ApplyAttributesTo( weapon, false, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( BaseWeapon weapon, bool isRunicTool, int luckChance, int attributeCount, int min, int max ) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = weapon.Attributes; + AosWeaponAttributes secondary = weapon.WeaponAttributes; + + m_Props.SetAll( false ); + + if ( weapon is BaseRanged ) + m_Props.Set( 2, true ); // ranged weapons cannot be ubws or mageweapon + + for ( int i = 0; i < attributeCount; ++i ) + { + int random = GetUniqueRandom( 25 ); + + if ( random == -1 ) + break; + + switch ( random ) + { + case 0: + { + switch ( Utility.Random( 5 ) ) + { + case 0: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitPhysicalArea,2, 50, 2 ); break; + case 1: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitFireArea, 2, 50, 2 ); break; + case 2: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitColdArea, 2, 50, 2 ); break; + case 3: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitPoisonArea, 2, 50, 2 ); break; + case 4: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitEnergyArea, 2, 50, 2 ); break; + } + + break; + } + case 1: + { + switch ( Utility.Random( 4 ) ) + { + case 0: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitMagicArrow, 2, 50, 2 ); break; + case 1: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitHarm, 2, 50, 2 ); break; + case 2: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitFireball, 2, 50, 2 ); break; + case 3: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLightning, 2, 50, 2 ); break; + } + + break; + } + case 2: + { + switch ( Utility.Random( 2 ) ) + { + case 0: ApplyAttribute( secondary, min, max, AosWeaponAttribute.UseBestSkill, 1, 1 ); break; + case 1: ApplyAttribute( secondary, min, max, AosWeaponAttribute.MageWeapon, 1, 10 ); break; + } + + break; + } + case 3: ApplyAttribute( primary, min, max, AosAttribute.WeaponDamage, 1, 50 ); break; + case 4: ApplyAttribute( primary, min, max, AosAttribute.DefendChance, 1, 15 ); break; + case 5: ApplyAttribute( primary, min, max, AosAttribute.CastSpeed, 1, 1 ); break; + case 6: ApplyAttribute( primary, min, max, AosAttribute.AttackChance, 1, 15 ); break; + case 7: ApplyAttribute( primary, min, max, AosAttribute.Luck, 1, 100 ); break; + case 8: ApplyAttribute( primary, min, max, AosAttribute.WeaponSpeed, 5, 30, 5 ); break; + case 9: ApplyAttribute( primary, min, max, AosAttribute.SpellChanneling, 1, 1 ); break; + case 10: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitDispel, 2, 50, 2 ); break; + case 11: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLeechHits, 2, 50, 2 ); break; + case 12: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLowerAttack, 2, 50, 2 ); break; + case 13: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLowerDefend, 2, 50, 2 ); break; + case 14: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLeechMana, 2, 50, 2 ); break; + case 15: ApplyAttribute( secondary, min, max, AosWeaponAttribute.HitLeechStam, 2, 50, 2 ); break; + case 16: ApplyAttribute(secondary, min, max, AosWeaponAttribute.LowerStatReq, 10, 100, 10); break; + case 17: ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPhysicalBonus, 1, 15); break; + case 18: ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistFireBonus, 1, 15); break; + case 19: ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistColdBonus, 1, 15); break; + case 20: ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistPoisonBonus, 1, 15); break; + case 21: ApplyAttribute(secondary, min, max, AosWeaponAttribute.ResistEnergyBonus, 1, 15); break; + case 22: ApplyAttribute(secondary, min, max, AosWeaponAttribute.DurabilityBonus, 10, 100, 10); break; + // Scriptiz : pas d'armes slayers sans la slayer forge + //case 23: weapon.Slayer = GetRandomSlayer(); break; + case 24: GetElementalDamages(weapon); break; + } + } + } + + public static void GetElementalDamages( BaseWeapon weapon ) + { + GetElementalDamages( weapon, true ); + } + + public static void GetElementalDamages( BaseWeapon weapon, bool randomizeOrder ) + { + int fire, phys, cold, nrgy, pois, chaos, direct; + + weapon.GetDamageTypes( null, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct ); + + int totalDamage = phys; + + AosElementAttribute[] attrs = new AosElementAttribute[] + { + AosElementAttribute.Cold, + AosElementAttribute.Energy, + AosElementAttribute.Fire, + AosElementAttribute.Poison + }; + + if( randomizeOrder ) + { + for( int i = 0; i < attrs.Length; i++ ) + { + int rand = Utility.Random( attrs.Length ); + AosElementAttribute temp = attrs[i]; + + attrs[i] = attrs[rand]; + attrs[rand] = temp; + } + } + + + /* + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Cold, totalDamage ); + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Energy, totalDamage ); + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Fire, totalDamage ); + totalDamage = AssignElementalDamage( weapon, AosElementAttribute.Poison, totalDamage ); + + weapon.AosElementDamages[AosElementAttribute.Physical] = 100 - totalDamage; + * */ + + for( int i = 0; i < attrs.Length; i++ ) + totalDamage = AssignElementalDamage( weapon, attrs[i], totalDamage ); + + + //Order is Cold, Energy, Fire, Poison -> Physical left + //Cannot be looped, AoselementAttribute is 'out of order' + + weapon.Hue = weapon.GetElementalDamageHue(); + } + + private static int AssignElementalDamage( BaseWeapon weapon, AosElementAttribute attr, int totalDamage ) + { + if( totalDamage <= 0 ) + return 0; + + int random = Utility.Random( (int)(totalDamage/10) + 1 ) * 10; + weapon.AosElementDamages[attr] = random; + + return (totalDamage - random); + } + + public static SlayerName GetRandomSlayer() + { + // TODO: Check random algorithm on OSI + + SlayerGroup[] groups = SlayerGroup.Groups; + + if ( groups.Length == 0 ) + return SlayerName.None; + + SlayerGroup group = groups[Utility.Random( groups.Length -1 )]; //-1 To Exclude the Fey Slayer which appears ONLY on a certain artifact. + SlayerEntry entry; + + if ( 10 > Utility.Random( 100 ) ) // 10% chance to do super slayer + { + entry = group.Super; + } + else + { + SlayerEntry[] entries = group.Entries; + + if ( entries.Length == 0 ) + return SlayerName.None; + + entry = entries[Utility.Random( entries.Length )]; + } + + return entry.Name; + } + + public void ApplyAttributesTo( BaseArmor armor ) + { + CraftResourceInfo resInfo = CraftResources.GetInfo( Resource ); + + if ( resInfo == null ) + return; + + CraftAttributeInfo attrs = resInfo.AttributeInfo; + + if ( attrs == null ) + return; + + int attributeCount = Utility.RandomMinMax( attrs.RunicMinAttributes, attrs.RunicMaxAttributes ); + int min = attrs.RunicMinIntensity; + int max = attrs.RunicMaxIntensity; + + ApplyAttributesTo( armor, true, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( BaseArmor armor, int attributeCount, int min, int max ) + { + ApplyAttributesTo( armor, false, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( BaseArmor armor, bool isRunicTool, int luckChance, int attributeCount, int min, int max ) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = armor.Attributes; + AosArmorAttributes secondary = armor.ArmorAttributes; + + m_Props.SetAll( false ); + + bool isShield = ( armor is BaseShield ); + int baseCount = ( isShield ? 7 : 20 ); + int baseOffset = ( isShield ? 0 : 4 ); + + if (!isShield && armor.MeditationAllowance == ArmorMeditationAllowance.All) + m_Props.Set(3, true); // remove mage armor from possible properties + if (armor.Resource >= CraftResource.RegularLeather && armor.Resource <= CraftResource.DaemonLeather) + { + m_Props.Set(0, true); // remove lower requirements from possible properties for leather armor + m_Props.Set(2, true); // remove durability bonus from possible properties + } + if ( armor.RequiredRace == Race.Elf ) + m_Props.Set( 7, true ); // elves inherently have night sight and elf only armor doesn't get night sight as a mod + + for ( int i = 0; i < attributeCount; ++i ) + { + int random = GetUniqueRandom( baseCount ); + + if ( random == -1 ) + break; + + random += baseOffset; + + switch ( random ) + { + /* Begin Sheilds */ + case 0: ApplyAttribute( primary, min, max, AosAttribute.SpellChanneling, 1, 1 ); break; + case 1: ApplyAttribute( primary, min, max, AosAttribute.DefendChance, 1, 15 ); break; + case 2: + if (Core.ML) { + ApplyAttribute( primary, min, max, AosAttribute.ReflectPhysical, 1, 15 ); + } else { + ApplyAttribute( primary, min, max, AosAttribute.AttackChance, 1, 15 ); + } + break; + case 3: ApplyAttribute( primary, min, max, AosAttribute.CastSpeed, 1, 1 ); break; + /* Begin Armor */ + case 4: ApplyAttribute( secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10 ); break; + case 5: ApplyAttribute( secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5 ); break; + case 6: ApplyAttribute( secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10 ); break; + /* End Shields */ + case 7: ApplyAttribute( secondary, min, max, AosArmorAttribute.MageArmor, 1, 1 ); break; + case 8: ApplyAttribute( primary, min, max, AosAttribute.RegenHits, 1, 2 ); break; + case 9: ApplyAttribute( primary, min, max, AosAttribute.RegenStam, 1, 3 ); break; + case 10: ApplyAttribute( primary, min, max, AosAttribute.RegenMana, 1, 2 ); break; + case 11: ApplyAttribute( primary, min, max, AosAttribute.NightSight, 1, 1 ); break; + case 12: ApplyAttribute( primary, min, max, AosAttribute.BonusHits, 1, 5 ); break; + case 13: ApplyAttribute( primary, min, max, AosAttribute.BonusStam, 1, 8 ); break; + case 14: ApplyAttribute( primary, min, max, AosAttribute.BonusMana, 1, 8 ); break; + case 15: ApplyAttribute( primary, min, max, AosAttribute.LowerManaCost, 1, 8 ); break; + case 16: ApplyAttribute( primary, min, max, AosAttribute.LowerRegCost, 1, 20 ); break; + case 17: ApplyAttribute( primary, min, max, AosAttribute.Luck, 1, 100 ); break; + case 18: ApplyAttribute( primary, min, max, AosAttribute.ReflectPhysical, 1, 15 ); break; + case 19: ApplyResistance( armor, min, max, ResistanceType.Physical, 1, 15 ); break; + case 20: ApplyResistance( armor, min, max, ResistanceType.Fire, 1, 15 ); break; + case 21: ApplyResistance( armor, min, max, ResistanceType.Cold, 1, 15 ); break; + case 22: ApplyResistance( armor, min, max, ResistanceType.Poison, 1, 15 ); break; + case 23: ApplyResistance( armor, min, max, ResistanceType.Energy, 1, 15 ); break; + /* End Armor */ + } + } + } + + public static void ApplyAttributesTo( BaseHat hat, int attributeCount, int min, int max ) + { + ApplyAttributesTo( hat, false, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( BaseHat hat, bool isRunicTool, int luckChance, int attributeCount, int min, int max ) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = hat.Attributes; + AosArmorAttributes secondary = hat.ClothingAttributes; + AosElementAttributes resists = hat.Resistances; + + m_Props.SetAll( false ); + + for (int i = 0; i < attributeCount; ++i) + { + int random = GetUniqueRandom(19); + + if ( random == -1 ) + break; + + switch ( random ) + { + case 0: ApplyAttribute( primary, min, max, AosAttribute.ReflectPhysical, 1, 15 ); break; + case 1: ApplyAttribute( primary, min, max, AosAttribute.RegenHits, 1, 2 ); break; + case 2: ApplyAttribute( primary, min, max, AosAttribute.RegenStam, 1, 3 ); break; + case 3: ApplyAttribute( primary, min, max, AosAttribute.RegenMana, 1, 2 ); break; + case 4: ApplyAttribute( primary, min, max, AosAttribute.NightSight, 1, 1 ); break; + case 5: ApplyAttribute( primary, min, max, AosAttribute.BonusHits, 1, 5 ); break; + case 6: ApplyAttribute( primary, min, max, AosAttribute.BonusStam, 1, 8 ); break; + case 7: ApplyAttribute( primary, min, max, AosAttribute.BonusMana, 1, 8 ); break; + case 8: ApplyAttribute( primary, min, max, AosAttribute.LowerManaCost, 1, 8 ); break; + case 9: ApplyAttribute( primary, min, max, AosAttribute.LowerRegCost, 1, 20 ); break; + case 10: ApplyAttribute( primary, min, max, AosAttribute.Luck, 1, 100 ); break; + case 11: ApplyAttribute(secondary, min, max, AosArmorAttribute.LowerStatReq, 10, 100, 10); break; + case 12: ApplyAttribute(secondary, min, max, AosArmorAttribute.SelfRepair, 1, 5); break; + case 13: ApplyAttribute(secondary, min, max, AosArmorAttribute.DurabilityBonus, 10, 100, 10); break; + case 14: ApplyAttribute(resists, min, max, AosElementAttribute.Physical, 1, 15); break; + case 15: ApplyAttribute(resists, min, max, AosElementAttribute.Fire, 1, 15); break; + case 16: ApplyAttribute(resists, min, max, AosElementAttribute.Cold, 1, 15); break; + case 17: ApplyAttribute(resists, min, max, AosElementAttribute.Poison, 1, 15); break; + case 18: ApplyAttribute(resists, min, max, AosElementAttribute.Energy, 1, 15); break; + } + } + } + + public static void ApplyAttributesTo( BaseJewel jewelry, int attributeCount, int min, int max ) + { + ApplyAttributesTo( jewelry, false, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( BaseJewel jewelry, bool isRunicTool, int luckChance, int attributeCount, int min, int max ) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = jewelry.Attributes; + AosElementAttributes resists = jewelry.Resistances; + AosSkillBonuses skills = jewelry.SkillBonuses; + + m_Props.SetAll( false ); + + for ( int i = 0; i < attributeCount; ++i ) + { + int random = GetUniqueRandom( 24 ); + + if ( random == -1 ) + break; + + switch ( random ) + { + case 0: ApplyAttribute( resists, min, max, AosElementAttribute.Physical, 1, 15 ); break; + case 1: ApplyAttribute( resists, min, max, AosElementAttribute.Fire, 1, 15 ); break; + case 2: ApplyAttribute( resists, min, max, AosElementAttribute.Cold, 1, 15 ); break; + case 3: ApplyAttribute( resists, min, max, AosElementAttribute.Poison, 1, 15 ); break; + case 4: ApplyAttribute( resists, min, max, AosElementAttribute.Energy, 1, 15 ); break; + case 5: ApplyAttribute( primary, min, max, AosAttribute.WeaponDamage, 1, 25 ); break; + case 6: ApplyAttribute( primary, min, max, AosAttribute.DefendChance, 1, 15 ); break; + case 7: ApplyAttribute( primary, min, max, AosAttribute.AttackChance, 1, 15 ); break; + case 8: ApplyAttribute( primary, min, max, AosAttribute.BonusStr, 1, 8 ); break; + case 9: ApplyAttribute( primary, min, max, AosAttribute.BonusDex, 1, 8 ); break; + case 10: ApplyAttribute( primary, min, max, AosAttribute.BonusInt, 1, 8 ); break; + case 11: ApplyAttribute( primary, min, max, AosAttribute.EnhancePotions, 5, 25, 5 ); break; + case 12: ApplyAttribute( primary, min, max, AosAttribute.CastSpeed, 1, 1 ); break; + case 13: ApplyAttribute( primary, min, max, AosAttribute.CastRecovery, 1, 3 ); break; + case 14: ApplyAttribute( primary, min, max, AosAttribute.LowerManaCost, 1, 8 ); break; + case 15: ApplyAttribute( primary, min, max, AosAttribute.LowerRegCost, 1, 20 ); break; + case 16: ApplyAttribute( primary, min, max, AosAttribute.Luck, 1, 100 ); break; + case 17: ApplyAttribute( primary, min, max, AosAttribute.SpellDamage, 1, 12 ); break; + case 18: ApplyAttribute( primary, min, max, AosAttribute.NightSight, 1, 1 ); break; + case 19: ApplySkillBonus( skills, min, max, 0, 1, 15 ); break; + case 20: ApplySkillBonus( skills, min, max, 1, 1, 15 ); break; + case 21: ApplySkillBonus( skills, min, max, 2, 1, 15 ); break; + case 22: ApplySkillBonus( skills, min, max, 3, 1, 15 ); break; + case 23: ApplySkillBonus( skills, min, max, 4, 1, 15 ); break; + } + } + } + + public static void ApplyAttributesTo( Spellbook spellbook, int attributeCount, int min, int max ) + { + ApplyAttributesTo( spellbook, false, 0, attributeCount, min, max ); + } + + public static void ApplyAttributesTo( Spellbook spellbook, bool isRunicTool, int luckChance, int attributeCount, int min, int max ) + { + m_IsRunicTool = isRunicTool; + m_LuckChance = luckChance; + + AosAttributes primary = spellbook.Attributes; + AosSkillBonuses skills = spellbook.SkillBonuses; + + m_Props.SetAll( false ); + m_Props.Set(0, true); // no lower stat requirements for weapons + + for ( int i = 0; i < attributeCount; ++i ) + { + int random = GetUniqueRandom( 20 ); // Scriptiz : par d�faut 16, on rend plus dur en augmentant petit � petit + + if ( random == -1 ) + break; + + switch ( random ) + { + case 0: + case 1: + case 2: + case 3: + { + ApplyAttribute( primary, min, max, AosAttribute.BonusInt, 1, 8 ); + + for ( int j = 0; j < 4; ++j ) + m_Props.Set( j, true ); + + break; + } + case 4: ApplyAttribute( primary, min, max, AosAttribute.BonusMana, 1, 8 ); break; + case 5: ApplyAttribute( primary, min, max, AosAttribute.CastSpeed, 1, 1 ); break; + case 6: ApplyAttribute( primary, min, max, AosAttribute.CastRecovery, 1, 3 ); break; + case 7: ApplyAttribute( primary, min, max, AosAttribute.SpellDamage, 1, 12 ); break; + case 8: ApplySkillBonus( skills, min, max, 0, 1, 15 ); break; + case 9: ApplySkillBonus( skills, min, max, 1, 1, 15 ); break; + case 10: ApplySkillBonus( skills, min, max, 2, 1, 15 ); break; + case 11: ApplySkillBonus( skills, min, max, 3, 1, 15 ); break; + case 12: ApplyAttribute( primary, min, max, AosAttribute.LowerRegCost, 1, 20 ); break; + case 13: ApplyAttribute( primary, min, max, AosAttribute.LowerManaCost, 1, 8 ); break; + case 14: ApplyAttribute( primary, min, max, AosAttribute.RegenMana, 1, 2 ); break; + // Scriptiz : pas de livres slayers + //case 15: spellbook.Slayer = GetRandomSlayer(); break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/BaseTool.cs b/Scripts/Items/Skill Items/Tools/BaseTool.cs new file mode 100644 index 0000000..e1e6825 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/BaseTool.cs @@ -0,0 +1,225 @@ +using System; +using Server; +using Server.Network; +using Server.Engines.Craft; + +namespace Server.Items +{ + public enum ToolQuality + { + Low, + Regular, + Exceptional + } + + public abstract class BaseTool : Item, IUsesRemaining, ICraftable + { + private Mobile m_Crafter; + private ToolQuality m_Quality; + private int m_UsesRemaining; + private CraftResource m_Resource; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public ToolQuality Quality + { + get{ return m_Quality; } + set{ UnscaleUses(); m_Quality = value; InvalidateProperties(); ScaleUses(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + public virtual bool BreakOnDepletion { get { return true; } } + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; Hue = CraftResources.GetHue(m_Resource); InvalidateProperties();} + } + + public void ScaleUses() + { + m_UsesRemaining = (m_UsesRemaining * GetUsesScalar()) / 100; + InvalidateProperties(); + } + + public void UnscaleUses() + { + m_UsesRemaining = (m_UsesRemaining * 100) / GetUsesScalar(); + } + + public int GetUsesScalar() + { + if ( m_Quality == ToolQuality.Exceptional ) + return 200; + + return 100; + } + + public bool ShowUsesRemaining{ get{ return true; } set{} } + + public abstract CraftSystem CraftSystem{ get; } + + public BaseTool( int itemID ) : this( Utility.RandomMinMax( 25, 75 ), itemID ) + { + } + + public BaseTool( int uses, int itemID ) : base( itemID ) + { + m_UsesRemaining = uses; + m_Quality = ToolQuality.Regular; + } + + public BaseTool( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + // Makers mark not displayed on OSI + //if ( m_Crafter != null ) + // list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if ( m_Quality == ToolQuality.Exceptional ) + list.Add( 1060636 ); // exceptional + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + public virtual void DisplayDurabilityTo( Mobile m ) + { + LabelToAffix( m, 1017323, AffixType.Append, ": " + m_UsesRemaining.ToString() ); // Durability + } + + public static bool CheckAccessible( Item tool, Mobile m ) + { + return ( tool.IsChildOf( m ) || tool.Parent == m ); + } + + public static bool CheckTool( Item tool, Mobile m ) + { + Item check = m.FindItemOnLayer( Layer.OneHanded ); + + if ( check is BaseTool && check != tool && !(check is AncientSmithyHammer) ) + return false; + + check = m.FindItemOnLayer( Layer.TwoHanded ); + + if ( check is BaseTool && check != tool && !(check is AncientSmithyHammer) ) + return false; + + return true; + } + + public override void OnSingleClick( Mobile from ) + { + DisplayDurabilityTo( from ); + + base.OnSingleClick( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) || Parent == from ) + { + CraftSystem system = this.CraftSystem; + + int num = system.CanCraft( from, this, null ); + + if ( num > 0 && ( num != 1044267 || !Core.SE ) ) // Blacksmithing shows the gump regardless of proximity of an anvil and forge after SE + { + from.SendLocalizedMessage( num ); + } + else + { + CraftContext context = system.GetContext( from ); + + from.SendGump( new CraftGump( from, system, this, null ) ); + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write((int)m_Resource); + + writer.Write( (Mobile) m_Crafter ); + writer.Write( (int) m_Quality ); + + writer.Write( (int) m_UsesRemaining ); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_Resource = (CraftResource)reader.ReadInt(); + goto case 1; + } + case 1: + { + m_Crafter = reader.ReadMobile(); + m_Quality = (ToolQuality) reader.ReadInt(); + goto case 0; + } + case 0: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Type resourceType = typeRes; + + if (resourceType == null) + resourceType = craftItem.Resources.GetAt(0).ItemType; + + Resource = CraftResources.GetFromType(resourceType); + + if(Resource == CraftResource.MAgapite) + UsesRemaining += 20; + + Quality = (ToolQuality)quality; + + if ( makersMark ) + Crafter = from; + + return quality; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Blowpipe.cs b/Scripts/Items/Skill Items/Tools/Blowpipe.cs new file mode 100644 index 0000000..2ea4eac --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Blowpipe.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0xE8A, 0xE89 )] + public class Blowpipe : BaseTool + { + public override CraftSystem CraftSystem { get { return DefGlassblowing.CraftSystem; } } + + public override int LabelNumber{ get{ return 1044608; } } // blow pipe + + [Constructable] + public Blowpipe() : base( 0xE8A ) + { + Weight = 4.0; + Hue = 0x3B9; + } + + [Constructable] + public Blowpipe( int uses ) : base( uses, 0xE8A ) + { + Weight = 4.0; + Hue = 0x3B9; + } + + public Blowpipe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 4.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/DovetailSaw.cs b/Scripts/Items/Skill Items/Tools/DovetailSaw.cs new file mode 100644 index 0000000..0061daf --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/DovetailSaw.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x1028, 0x1029 )] + public class DovetailSaw : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public DovetailSaw() : base( 0x1028 ) + { + Weight = 2.0; + } + + [Constructable] + public DovetailSaw( int uses ) : base( uses, 0x1028 ) + { + Weight = 2.0; + } + + public DovetailSaw( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/DrawKnife.cs b/Scripts/Items/Skill Items/Tools/DrawKnife.cs new file mode 100644 index 0000000..7dcff6e --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/DrawKnife.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class DrawKnife : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public DrawKnife() : base( 0x10E4 ) + { + Weight = 1.0; + } + + [Constructable] + public DrawKnife( int uses ) : base( uses, 0x10E4 ) + { + Weight = 1.0; + } + + public DrawKnife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/FletcherTools.cs b/Scripts/Items/Skill Items/Tools/FletcherTools.cs new file mode 100644 index 0000000..c98bb6a --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/FletcherTools.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x1022, 0x1023 )] + public class FletcherTools : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefBowFletching.CraftSystem; } } + + [Constructable] + public FletcherTools() : base( 0x1022 ) + { + Weight = 2.0; + } + + [Constructable] + public FletcherTools( int uses ) : base( uses, 0x1022 ) + { + Weight = 2.0; + } + + public FletcherTools( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/FlourSifter.cs b/Scripts/Items/Skill Items/Tools/FlourSifter.cs new file mode 100644 index 0000000..ffe60d3 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/FlourSifter.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class FlourSifter : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCooking.CraftSystem; } } + + [Constructable] + public FlourSifter() : base( 0x103E ) + { + Weight = 1.0; + } + + [Constructable] + public FlourSifter( int uses ) : base( uses, 0x103E ) + { + Weight = 1.0; + } + + public FlourSifter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Froe.cs b/Scripts/Items/Skill Items/Tools/Froe.cs new file mode 100644 index 0000000..2aca00d --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Froe.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Froe : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public Froe() : base( 0x10E5 ) + { + Weight = 1.0; + } + + [Constructable] + public Froe( int uses ) : base( uses, 0x10E5 ) + { + Weight = 1.0; + } + + public Froe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Hammer.cs b/Scripts/Items/Skill Items/Tools/Hammer.cs new file mode 100644 index 0000000..06d2636 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Hammer.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Hammer : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public Hammer() : base( 0x102A ) + { + Weight = 2.0; + } + + [Constructable] + public Hammer( int uses ) : base( uses, 0x102A ) + { + Weight = 2.0; + } + + public Hammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Inshave.cs b/Scripts/Items/Skill Items/Tools/Inshave.cs new file mode 100644 index 0000000..fde0136 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Inshave.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Inshave : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public Inshave() : base( 0x10E6 ) + { + Weight = 1.0; + } + + [Constructable] + public Inshave( int uses ) : base( uses, 0x10E6 ) + { + Weight = 1.0; + } + + public Inshave( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/JointingPlane.cs b/Scripts/Items/Skill Items/Tools/JointingPlane.cs new file mode 100644 index 0000000..5c5a292 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/JointingPlane.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x1030, 0x1031 )] + public class JointingPlane : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public JointingPlane() : base( 0x1030 ) + { + Weight = 2.0; + } + + [Constructable] + public JointingPlane( int uses ) : base( uses, 0x1030 ) + { + Weight = 2.0; + } + + public JointingPlane( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/MalletAndChisel.cs b/Scripts/Items/Skill Items/Tools/MalletAndChisel.cs new file mode 100644 index 0000000..162cc8b --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/MalletAndChisel.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class MalletAndChisel : BaseTool + { + public override CraftSystem CraftSystem { get { return DefMasonry.CraftSystem; } } + + [Constructable] + public MalletAndChisel() : base( 0x12B3 ) + { + Weight = 1.0; + } + + [Constructable] + public MalletAndChisel( int uses ) : base( uses, 0x12B3 ) + { + Weight = 1.0; + } + + public MalletAndChisel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/MapmakersPen.cs b/Scripts/Items/Skill Items/Tools/MapmakersPen.cs new file mode 100644 index 0000000..bacec4c --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/MapmakersPen.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x0FBF, 0x0FC0 )] + public class MapmakersPen : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCartography.CraftSystem; } } + + public override int LabelNumber{ get{ return 1044167; } } // mapmaker's pen + + [Constructable] + public MapmakersPen() : base( 0x0FBF ) + { + Weight = 1.0; + } + + [Constructable] + public MapmakersPen( int uses ) : base( uses, 0x0FBF ) + { + Weight = 1.0; + } + + public MapmakersPen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/MortarPestle.cs b/Scripts/Items/Skill Items/Tools/MortarPestle.cs new file mode 100644 index 0000000..bb7ee55 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/MortarPestle.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class MortarPestle : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefAlchemy.CraftSystem; } } + + [Constructable] + public MortarPestle() : base( 0xE9B ) + { + Weight = 1.0; + } + + [Constructable] + public MortarPestle( int uses ) : base( uses, 0xE9B ) + { + Weight = 1.0; + } + + public MortarPestle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/MouldingPlane.cs b/Scripts/Items/Skill Items/Tools/MouldingPlane.cs new file mode 100644 index 0000000..793d6bd --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/MouldingPlane.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x102C, 0x102D )] + public class MouldingPlane : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public MouldingPlane() : base( 0x102C ) + { + Weight = 2.0; + } + + [Constructable] + public MouldingPlane( int uses ) : base( uses, 0x102C ) + { + Weight = 2.0; + } + + public MouldingPlane( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Nails.cs b/Scripts/Items/Skill Items/Tools/Nails.cs new file mode 100644 index 0000000..bbd4101 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Nails.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x102E, 0x102F )] + public class Nails : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public Nails() : base( 0x102E ) + { + Weight = 2.0; + } + + [Constructable] + public Nails( int uses ) : base( uses, 0x102C ) + { + Weight = 2.0; + } + + public Nails( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/RollingPin.cs b/Scripts/Items/Skill Items/Tools/RollingPin.cs new file mode 100644 index 0000000..5916545 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/RollingPin.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RollingPin : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCooking.CraftSystem; } } + + [Constructable] + public RollingPin() : base( 0x1043 ) + { + Weight = 1.0; + } + + [Constructable] + public RollingPin( int uses ) : base( uses, 0x1043 ) + { + Weight = 1.0; + } + + public RollingPin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/RunicDovetailSaw.cs b/Scripts/Items/Skill Items/Tools/RunicDovetailSaw.cs new file mode 100644 index 0000000..6ea9492 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/RunicDovetailSaw.cs @@ -0,0 +1,59 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RunicDovetailSaw : BaseRunicTool + { + public override CraftSystem CraftSystem { get { return DefCarpentry.CraftSystem; } } + + public override int LabelNumber + { + get + { + int index = CraftResources.GetIndex(Resource); + + if (index >= 1 && index <= 6) + return 1072633 + index; + + return 1024137; // dovetail saw + } + } + + [Constructable] + public RunicDovetailSaw(CraftResource resource) + : base(resource, 0x1028) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + [Constructable] + public RunicDovetailSaw(CraftResource resource, int uses) + : base(resource, uses, 0x1028) + { + Weight = 2.0; + Hue = CraftResources.GetHue(resource); + } + + public RunicDovetailSaw(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/RunicFletcherTool.cs b/Scripts/Items/Skill Items/Tools/RunicFletcherTool.cs new file mode 100644 index 0000000..e00578a --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/RunicFletcherTool.cs @@ -0,0 +1,56 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RunicFletcherTool : BaseRunicTool + { + public override CraftSystem CraftSystem{ get{ return DefBowFletching.CraftSystem; } } + + public override int LabelNumber + { + get + { + int index = CraftResources.GetIndex( Resource ); + + if ( index >= 1 && index <= 6 ) + return 1072627 + index; + + return 1044559; // Fletcher's Tools + } + } + + [Constructable] + public RunicFletcherTool( CraftResource resource ) : base( resource, 0x1022 ) + { + Weight = 2.0; + Hue = CraftResources.GetHue( resource ); + } + + [Constructable] + public RunicFletcherTool( CraftResource resource, int uses ) : base( resource, uses, 0x1022 ) + { + Weight = 2.0; + Hue = CraftResources.GetHue( resource ); + } + + public RunicFletcherTool( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Tools/RunicHammer.cs b/Scripts/Items/Skill Items/Tools/RunicHammer.cs new file mode 100644 index 0000000..ac8d103 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/RunicHammer.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x13E4, 0x13E3 )] + public class RunicHammer : BaseRunicTool + { + public override CraftSystem CraftSystem{ get{ return DefBlacksmithy.CraftSystem; } } + + public override int LabelNumber + { + get + { + int index = CraftResources.GetIndex( Resource ); + + if ( index >= 1 && index <= 8 ) + return 1049019 + index; + + return 1045128; // runic smithy hammer + } + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + int index = CraftResources.GetIndex( Resource ); + + if ( index >= 1 && index <= 8 ) + return; + + if ( !CraftResources.IsStandard( Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( Resource ); + + if ( num > 0 ) + list.Add( num ); + else + list.Add( CraftResources.GetName( Resource ) ); + } + } + + [Constructable] + public RunicHammer( CraftResource resource ) : base( resource, 0x13E3 ) + { + Weight = 8.0; + Layer = Layer.OneHanded; + Hue = CraftResources.GetHue( resource ); + } + + [Constructable] + public RunicHammer( CraftResource resource, int uses ) : base( resource, uses, 0x13E3 ) + { + Weight = 8.0; + Layer = Layer.OneHanded; + Hue = CraftResources.GetHue( resource ); + } + + public RunicHammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/RunicSewingKit.cs b/Scripts/Items/Skill Items/Tools/RunicSewingKit.cs new file mode 100644 index 0000000..a11c5cf --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/RunicSewingKit.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class RunicSewingKit : BaseRunicTool + { + public override CraftSystem CraftSystem{ get{ return DefTailoring.CraftSystem; } } + + public override void AddNameProperty( ObjectPropertyList list ) + { + string v = " "; + + if ( !CraftResources.IsStandard( Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( Resource ); + + if ( num > 0 ) + v = String.Format( "#{0}", num ); + else + v = CraftResources.GetName( Resource ); + } + + list.Add( 1061119, v ); // ~1_LEATHER_TYPE~ runic sewing kit + } + + public override void OnSingleClick( Mobile from ) + { + string v = " "; + + if ( !CraftResources.IsStandard( Resource ) ) + { + int num = CraftResources.GetLocalizationNumber( Resource ); + + if ( num > 0 ) + v = String.Format( "#{0}", num ); + else + v = CraftResources.GetName( Resource ); + } + + LabelTo( from, 1061119, v ); // ~1_LEATHER_TYPE~ runic sewing kit + } + + [Constructable] + public RunicSewingKit( CraftResource resource ) : base( resource, 0xF9D ) + { + Weight = 2.0; + Hue = CraftResources.GetHue( resource ); + } + + [Constructable] + public RunicSewingKit( CraftResource resource, int uses ) : base( resource, uses, 0xF9D ) + { + Weight = 2.0; + Hue = CraftResources.GetHue( resource ); + } + + public RunicSewingKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ItemID == 0x13E4 || ItemID == 0x13E3 ) + ItemID = 0xF9D; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Saw.cs b/Scripts/Items/Skill Items/Tools/Saw.cs new file mode 100644 index 0000000..ca16b53 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Saw.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x1034, 0x1035 )] + public class Saw : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public Saw() : base( 0x1034 ) + { + Weight = 2.0; + } + + [Constructable] + public Saw( int uses ) : base( uses, 0x1034 ) + { + Weight = 2.0; + } + + public Saw( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Scorp.cs b/Scripts/Items/Skill Items/Tools/Scorp.cs new file mode 100644 index 0000000..a9366a9 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Scorp.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Scorp : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public Scorp() : base( 0x10E7 ) + { + Weight = 1.0; + } + + [Constructable] + public Scorp( int uses ) : base( uses, 0x10E7 ) + { + Weight = 1.0; + } + + public Scorp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/ScribesPen.cs b/Scripts/Items/Skill Items/Tools/ScribesPen.cs new file mode 100644 index 0000000..70b0c4e --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/ScribesPen.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x0FBF, 0x0FC0 )] + public class ScribesPen : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefInscription.CraftSystem; } } + + public override int LabelNumber{ get{ return 1044168; } } // scribe's pen + + [Constructable] + public ScribesPen() : base( 0x0FBF ) + { + Weight = 1.0; + } + + [Constructable] + public ScribesPen( int uses ) : base( uses, 0x0FBF ) + { + Weight = 1.0; + } + + public ScribesPen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/SewingKit.cs b/Scripts/Items/Skill Items/Tools/SewingKit.cs new file mode 100644 index 0000000..cfff26a --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/SewingKit.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class SewingKit : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefTailoring.CraftSystem; } } + + [Constructable] + public SewingKit() : base( 0xF9D ) + { + Weight = 2.0; + } + + [Constructable] + public SewingKit( int uses ) : base( uses, 0xF9D ) + { + Weight = 2.0; + } + + public SewingKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Skillet.cs b/Scripts/Items/Skill Items/Tools/Skillet.cs new file mode 100644 index 0000000..3802133 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Skillet.cs @@ -0,0 +1,43 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class Skillet : BaseTool + { + public override int LabelNumber{ get{ return 1044567; } } // skillet + + public override CraftSystem CraftSystem{ get{ return DefCooking.CraftSystem; } } + + [Constructable] + public Skillet() : base( 0x97F ) + { + Weight = 1.0; + } + + [Constructable] + public Skillet( int uses ) : base( uses, 0x97F ) + { + Weight = 1.0; + } + + public Skillet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/SledgeHammer.cs b/Scripts/Items/Skill Items/Tools/SledgeHammer.cs new file mode 100644 index 0000000..396505b --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/SledgeHammer.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0xFB5, 0xFB4 )] + public class SledgeHammer : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefBlacksmithy.CraftSystem; } } + + [Constructable] + public SledgeHammer() : base( 0xFB5 ) + { + Layer = Layer.OneHanded; + } + + [Constructable] + public SledgeHammer( int uses ) : base( uses, 0xFB5 ) + { + Layer = Layer.OneHanded; + } + + public SledgeHammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Skill Items/Tools/SmithHammer.cs b/Scripts/Items/Skill Items/Tools/SmithHammer.cs new file mode 100644 index 0000000..07c7ab9 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/SmithHammer.cs @@ -0,0 +1,44 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x13E3, 0x13E4 )] + public class SmithHammer : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefBlacksmithy.CraftSystem; } } + + [Constructable] + public SmithHammer() : base( 0x13E3 ) + { + Weight = 8.0; + Layer = Layer.OneHanded; + } + + [Constructable] + public SmithHammer( int uses ) : base( uses, 0x13E3 ) + { + Weight = 8.0; + Layer = Layer.OneHanded; + } + + public SmithHammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/SmoothingPlane.cs b/Scripts/Items/Skill Items/Tools/SmoothingPlane.cs new file mode 100644 index 0000000..527f0c1 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/SmoothingPlane.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x1032, 0x1033 )] + public class SmoothingPlane : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefCarpentry.CraftSystem; } } + + [Constructable] + public SmoothingPlane() : base( 0x1032 ) + { + Weight = 1.0; + } + + [Constructable] + public SmoothingPlane( int uses ) : base( uses, 0x1032 ) + { + Weight = 1.0; + } + + public SmoothingPlane( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/TinkerTools.cs b/Scripts/Items/Skill Items/Tools/TinkerTools.cs new file mode 100644 index 0000000..309eec2 --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/TinkerTools.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Flipable( 0x1EB8, 0x1EB9 )] + public class TinkerTools : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefTinkering.CraftSystem; } } + + [Constructable] + public TinkerTools() : base( 0x1EB8 ) + { + Weight = 1.0; + } + + [Constructable] + public TinkerTools( int uses ) : base( uses, 0x1EB8 ) + { + Weight = 1.0; + } + + public TinkerTools( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + + } + } + public class TinkersTools : BaseTool + { + public override CraftSystem CraftSystem { get { return DefTinkering.CraftSystem; } } + + [Constructable] + public TinkersTools() + : base(0x1EBC) + { + Weight = 1.0; + } + + [Constructable] + public TinkersTools(int uses) + : base(uses, 0x1EBC) + { + Weight = 1.0; + } + + public TinkersTools(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Skill Items/Tools/Tongs.cs b/Scripts/Items/Skill Items/Tools/Tongs.cs new file mode 100644 index 0000000..df1f30d --- /dev/null +++ b/Scripts/Items/Skill Items/Tools/Tongs.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0xfbb, 0xfbc )] + public class Tongs : BaseTool + { + public override CraftSystem CraftSystem{ get{ return DefBlacksmithy.CraftSystem; } } + + [Constructable] + public Tongs() : base( 0xFBB ) + { + Weight = 2.0; + } + + [Constructable] + public Tongs( int uses ) : base( uses, 0xFBB ) + { + Weight = 2.0; + } + + public Tongs( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/11th Year promo/EarringsOfProtection.cs b/Scripts/Items/Special/11th Year promo/EarringsOfProtection.cs new file mode 100644 index 0000000..0c939ca --- /dev/null +++ b/Scripts/Items/Special/11th Year promo/EarringsOfProtection.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Items +{ + public class EarringBoxSet : RedVelvetGiftBox + { + [Constructable] + public EarringBoxSet() + : base() + { + DropItem( new EarringsOfProtection( AosElementAttribute.Physical ) ); + DropItem( new EarringsOfProtection( AosElementAttribute.Fire ) ); + DropItem( new EarringsOfProtection( AosElementAttribute.Cold ) ); + DropItem( new EarringsOfProtection( AosElementAttribute.Poison ) ); + DropItem( new EarringsOfProtection( AosElementAttribute.Energy ) ); + } + + public EarringBoxSet( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class EarringsOfProtection : BaseJewel + { + [CommandProperty( AccessLevel.GameMaster )] + public virtual AosElementAttribute Attribute + { + get + { + return m_Attribute; + } + } + + public override int LabelNumber + { + get + { + return GetItemData( m_Attribute, true ); + } + } + + public override int Hue + { + get + { + return GetItemData( m_Attribute, false ); + } + } + + private AosElementAttribute m_Attribute; + + [Constructable] + public EarringsOfProtection() : this( RandomType() ) + { + } + + [Constructable] + public EarringsOfProtection( AosElementAttribute element ) + : base( 0x1087, Layer.Earrings ) + { + Resistances[ ( (AosElementAttribute)element ) ] = 2; + + m_Attribute = element; + LootType = LootType.Blessed; + } + + public EarringsOfProtection( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + writer.Write( (int)m_Attribute ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + m_Attribute = (AosElementAttribute)reader.ReadInt(); + } + + public static AosElementAttribute RandomType() + { + return GetTypes( Utility.Random( 5 ) ); + } + + public static AosElementAttribute GetTypes( int value ) + { + switch( value ) + { + case 0: return AosElementAttribute.Physical; + case 1: return AosElementAttribute.Fire; + case 2: return AosElementAttribute.Cold; + case 3: return AosElementAttribute.Poison; + default: return AosElementAttribute.Energy; + } + } + + public static int GetItemData( AosElementAttribute element, bool label ) + { + switch( element ) + { + case AosElementAttribute.Physical: return ( label ) ? 1071091 : 0; // Earring of Protection (Physical) 1071091 + case AosElementAttribute.Fire: return ( label ) ? 1071092 : 0x4ec; // Earring of Protection (Fire) 1071092 + case AosElementAttribute.Cold: return ( label ) ? 1071093 : 0x4f2; // Earring of Protection (Cold) 1071093 + case AosElementAttribute.Poison: return ( label ) ? 1071094 : 0x4f8; // Earring of Protection (Poison) 1071094 + case AosElementAttribute.Energy: return ( label ) ? 1071095 : 0x4fe; // Earring of Protection (Energy) 1071095 + + default: return -1; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs b/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs new file mode 100644 index 0000000..51fcd42 --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicBox.cs @@ -0,0 +1,315 @@ +using System; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public sealed class StopMusic : Packet + { + public static readonly Packet Instance = Packet.SetStatic( new StopMusic() ); + + public StopMusic() : base( 0x6D, 3 ) + { + m_Stream.Write( (short) 0x1FFF ); + } + } + + [Flipable( 0x2AF9, 0x2AFD )] + public class DawnsMusicBox : Item, ISecurable + { + public override int LabelNumber { get { return 1075198; } } // Dawn�s Music Box + + private List m_Tracks; + + public List Tracks + { + get { return m_Tracks; } + } + + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get { return m_Level; } + set { m_Level = value; } + } + + [Constructable] + public DawnsMusicBox() : base( 0x2AF9 ) + { + Weight = 1.0; + + m_Tracks = new List(); + + while ( m_Tracks.Count < 4 ) + { + MusicName name = RandomTrack( DawnsMusicRarity.Common ); + + if ( !m_Tracks.Contains( name ) ) + m_Tracks.Add( name ); + } + } + + public DawnsMusicBox( Serial serial ) : base( serial ) + { + } + + public override void OnAfterDuped( Item newItem ) + { + DawnsMusicBox box = newItem as DawnsMusicBox; + + if ( box == null ) + return; + + box.m_Tracks = new List(); + box.m_Tracks.AddRange( m_Tracks ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + int commonSongs = 0; + int uncommonSongs = 0; + int rareSongs = 0; + + for ( int i = 0; i < m_Tracks.Count; i++ ) + { + DawnsMusicInfo info = GetInfo( m_Tracks[ i ] ); + + switch ( info.Rarity ) + { + case DawnsMusicRarity.Common: commonSongs++; break; + case DawnsMusicRarity.Uncommon: uncommonSongs++; break; + case DawnsMusicRarity.Rare: rareSongs++; break; + } + } + + if ( commonSongs > 0 ) + list.Add( 1075234, commonSongs.ToString() ); // ~1_NUMBER~ Common Tracks + if ( uncommonSongs > 0 ) + list.Add( 1075235, uncommonSongs.ToString() ); // ~1_NUMBER~ Uncommon Tracks + if ( rareSongs > 0 ) + list.Add( 1075236, rareSongs.ToString() ); // ~1_NUMBER~ Rare Tracks + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + SetSecureLevelEntry.AddTo( from, this, list ); // Set secure level + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) && !IsLockedDown ) + from.SendLocalizedMessage( 1061856 ); // You must have the item in your backpack or locked down in order to use it. + else if ( IsLockedDown && !HasAccces( from ) ) + from.SendLocalizedMessage( 502436 ); // That is not accessible. + else + { + from.CloseGump( typeof( DawnsMusicBoxGump ) ); + from.SendGump( new DawnsMusicBoxGump( this ) ); + } + } + + public bool HasAccces( Mobile m ) + { + if ( m.AccessLevel >= AccessLevel.GameMaster ) + return true; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + return ( house != null && house.HasAccess( m ) ); + } + + private Timer m_Timer; + private int m_ItemID = 0; + private int m_Count = 0; + + public void PlayMusic( Mobile m, MusicName music ) + { + if ( m_Timer != null && m_Timer.Running ) + EndMusic( m ); + else + m_ItemID = ItemID; + + m.Send( new PlayMusic( music ) ); + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 4, new TimerCallback( Animate ) ); + } + + public void EndMusic( Mobile m ) + { + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + + m.Send( StopMusic.Instance ); + + if ( m_Count > 0 ) + ItemID = m_ItemID; + + m_Count = 0; + } + + private void Animate() + { + m_Count++; + + if ( m_Count >= 4 ) + { + m_Count = 0; + ItemID = m_ItemID; + } + else + ItemID++; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_Tracks.Count ); + + for ( int i = 0; i < m_Tracks.Count; i++ ) + writer.Write( (int) m_Tracks[ i ] ); + + writer.Write( (int) m_Level ); + writer.Write( (int) m_ItemID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + int count = reader.ReadInt(); + m_Tracks = new List(); + + for ( int i = 0; i < count; i++ ) + m_Tracks.Add( (MusicName) reader.ReadInt() ); + + m_Level = (SecureLevel) reader.ReadInt(); + m_ItemID = reader.ReadInt(); + } + + private static Dictionary m_Info = new Dictionary(); + + public static void Initialize() + { + m_Info.Add( MusicName.Samlethe, new DawnsMusicInfo( 1075152, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Sailing, new DawnsMusicInfo( 1075163, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Britain2, new DawnsMusicInfo( 1075145, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Britain1, new DawnsMusicInfo( 1075144, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Bucsden, new DawnsMusicInfo( 1075146, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Forest_a, new DawnsMusicInfo( 1075161, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Cove, new DawnsMusicInfo( 1075176, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Death, new DawnsMusicInfo( 1075171, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Dungeon9, new DawnsMusicInfo( 1075160, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Dungeon2, new DawnsMusicInfo( 1075175, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Cave01, new DawnsMusicInfo( 1075159, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Combat3, new DawnsMusicInfo( 1075170, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Combat1, new DawnsMusicInfo( 1075168, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Combat2, new DawnsMusicInfo( 1075169, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Jhelom, new DawnsMusicInfo( 1075147, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Linelle, new DawnsMusicInfo( 1075185, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.LBCastle, new DawnsMusicInfo( 1075148, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Minoc, new DawnsMusicInfo( 1075150, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Moonglow, new DawnsMusicInfo( 1075177, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Magincia, new DawnsMusicInfo( 1075149, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Nujelm, new DawnsMusicInfo( 1075174, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.BTCastle, new DawnsMusicInfo( 1075173, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Tavern04, new DawnsMusicInfo( 1075167, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Skarabra, new DawnsMusicInfo( 1075154, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Stones2, new DawnsMusicInfo( 1075143, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Serpents, new DawnsMusicInfo( 1075153, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Taiko, new DawnsMusicInfo( 1075180, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Tavern01, new DawnsMusicInfo( 1075164, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Tavern02, new DawnsMusicInfo( 1075165, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Tavern03, new DawnsMusicInfo( 1075166, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.TokunoDungeon, new DawnsMusicInfo( 1075179, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Trinsic, new DawnsMusicInfo( 1075155, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.OldUlt01, new DawnsMusicInfo( 1075142, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Ocllo, new DawnsMusicInfo( 1075151, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Vesper, new DawnsMusicInfo( 1075156, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Victory, new DawnsMusicInfo( 1075172, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Mountn_a, new DawnsMusicInfo( 1075162, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Wind, new DawnsMusicInfo( 1075157, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Yew, new DawnsMusicInfo( 1075158, DawnsMusicRarity.Common ) ); + m_Info.Add( MusicName.Zento, new DawnsMusicInfo( 1075178, DawnsMusicRarity.Common ) ); + + m_Info.Add( MusicName.GwennoConversation, new DawnsMusicInfo( 1075131, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.DreadHornArea, new DawnsMusicInfo( 1075181, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.ElfCity, new DawnsMusicInfo( 1075182, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.GoodEndGame, new DawnsMusicInfo( 1075132, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.GoodVsEvil, new DawnsMusicInfo( 1075133, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.GreatEarthSerpents, new DawnsMusicInfo( 1075134, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.GrizzleDungeon, new DawnsMusicInfo( 1075186, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.Humanoids_U9, new DawnsMusicInfo( 1075135, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.MelisandesLair, new DawnsMusicInfo( 1075183, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.MinocNegative, new DawnsMusicInfo( 1075136, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.ParoxysmusLair, new DawnsMusicInfo( 1075184, DawnsMusicRarity.Uncommon ) ); + m_Info.Add( MusicName.Paws, new DawnsMusicInfo( 1075137, DawnsMusicRarity.Uncommon ) ); + + m_Info.Add( MusicName.SelimsBar, new DawnsMusicInfo( 1075138, DawnsMusicRarity.Rare ) ); + m_Info.Add( MusicName.SerpentIsleCombat_U7, new DawnsMusicInfo( 1075139, DawnsMusicRarity.Rare ) ); + m_Info.Add( MusicName.ValoriaShips, new DawnsMusicInfo( 1075140, DawnsMusicRarity.Rare ) ); + } + + public static MusicName[] m_CommonTracks = new MusicName[] + { + MusicName.Samlethe, MusicName.Sailing, MusicName.Britain2, MusicName.Britain1, + MusicName.Bucsden, MusicName.Forest_a, MusicName.Cove, MusicName.Death, + MusicName.Dungeon9, MusicName.Dungeon2, MusicName.Cave01, MusicName.Combat3, + MusicName.Combat1, MusicName.Combat2, MusicName.Jhelom, MusicName.Linelle, + MusicName.LBCastle, MusicName.Minoc, MusicName.Moonglow, MusicName.Magincia, + MusicName.Nujelm, MusicName.BTCastle, MusicName.Tavern04, MusicName.Skarabra, + MusicName.Stones2, MusicName.Serpents, MusicName.Taiko, MusicName.Tavern01, + MusicName.Tavern02, MusicName.Tavern03, MusicName.TokunoDungeon, MusicName.Trinsic, + MusicName.OldUlt01, MusicName.Ocllo, MusicName.Vesper, MusicName.Victory, + MusicName.Mountn_a, MusicName.Wind, MusicName.Yew, MusicName.Zento + }; + + public static MusicName[] m_UncommonTracks = new MusicName[] + { + MusicName.GwennoConversation, MusicName.DreadHornArea, MusicName.ElfCity, + MusicName.GoodEndGame, MusicName.GoodVsEvil, MusicName.GreatEarthSerpents, + MusicName.GrizzleDungeon, MusicName.Humanoids_U9, MusicName.MelisandesLair, + MusicName.MinocNegative, MusicName.ParoxysmusLair, MusicName.Paws + }; + + public static MusicName[] m_RareTracks = new MusicName[] + { + MusicName.SelimsBar, MusicName.SerpentIsleCombat_U7, MusicName.ValoriaShips + }; + + public static DawnsMusicInfo GetInfo( MusicName name ) + { + if ( m_Info.ContainsKey( name ) ) + return m_Info[ name ]; + + return null; + } + + public static MusicName RandomTrack( DawnsMusicRarity rarity ) + { + MusicName[] list = null; + + switch ( rarity ) + { + default: + case DawnsMusicRarity.Common: list = m_CommonTracks; break; + case DawnsMusicRarity.Uncommon: list = m_UncommonTracks; break; + case DawnsMusicRarity.Rare: list = m_RareTracks; break; + } + + return list[ Utility.Random( list.Length ) ]; + } + } +} diff --git a/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs b/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs new file mode 100644 index 0000000..9d1913f --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicGear.cs @@ -0,0 +1,149 @@ +using System; +using Server.Targeting; + +namespace Server.Items +{ + [Flipable( 0x1053, 0x1054 )] + public class DawnsMusicGear : Item + { + public static DawnsMusicGear RandomCommon + { + get { return new DawnsMusicGear( DawnsMusicBox.RandomTrack( DawnsMusicRarity.Common ) ); } + } + + public static DawnsMusicGear RandomUncommon + { + get { return new DawnsMusicGear( DawnsMusicBox.RandomTrack( DawnsMusicRarity.Uncommon ) ); } + } + + public static DawnsMusicGear RandomRare + { + get { return new DawnsMusicGear( DawnsMusicBox.RandomTrack( DawnsMusicRarity.Rare ) ); } + } + + private MusicName m_Music; + + [CommandProperty( AccessLevel.GameMaster )] + public MusicName Music + { + get { return m_Music; } + set { m_Music = value; } + } + + [Constructable] + public DawnsMusicGear() : this( DawnsMusicBox.RandomTrack( DawnsMusicRarity.Common ) ) + { + } + + [Constructable] + public DawnsMusicGear( MusicName music ) : base( 0x1053 ) + { + m_Music = music; + + Weight = 1.0; + } + + public DawnsMusicGear( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + DawnsMusicInfo info = DawnsMusicBox.GetInfo( m_Music ); + + if ( info != null ) + { + if ( info.Rarity == DawnsMusicRarity.Common ) + list.Add( 1075204 ); // Gear for Dawn's Music Box (Common) + else if ( info.Rarity == DawnsMusicRarity.Uncommon ) + list.Add( 1075205 ); // Gear for Dawn's Music Box (Uncommon) + else if ( info.Rarity == DawnsMusicRarity.Rare ) + list.Add( 1075206 ); // Gear for Dawn's Music Box (Rare) + + list.Add( info.Name ); + } + else + base.AddNameProperty( list ); + } + + public override void OnDoubleClick( Mobile from ) + { + from.Target = new InternalTarget( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt((int)1); // version + + writer.Write((int)m_Music); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + switch (version) + { + case 1: + { + m_Music = (MusicName)reader.ReadInt(); + break; + } + } + + if (version == 0) // Music wasn't serialized in version 0, pick a new track of random rarity + { + DawnsMusicRarity rarity; + double rand = Utility.RandomDouble(); + + if (rand < 0.025) + rarity = DawnsMusicRarity.Rare; + else if (rand < 0.225) + rarity = DawnsMusicRarity.Uncommon; + else + rarity = DawnsMusicRarity.Common; + + m_Music = DawnsMusicBox.RandomTrack(rarity); + } + } + + public class InternalTarget : Target + { + private DawnsMusicGear m_Gear; + + public InternalTarget( DawnsMusicGear gear ) : base( 2, false, TargetFlags.None ) + { + m_Gear = gear; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Gear == null || m_Gear.Deleted ) + return; + + DawnsMusicBox box = targeted as DawnsMusicBox; + + if ( box != null ) + { + if ( !box.Tracks.Contains( m_Gear.Music ) ) + { + box.Tracks.Add( m_Gear.Music ); + box.InvalidateProperties(); + + m_Gear.Delete(); + + from.SendLocalizedMessage( 1071961 ); // This song has been added to the musicbox. + } + else + from.SendLocalizedMessage( 1071962 ); // This song track is already in the musicbox. + } + else + from.SendLocalizedMessage( 1071964 ); // Gears can only be put into a musicbox. + } + } + } +} diff --git a/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs b/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs new file mode 100644 index 0000000..1185baf --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/Dawn's Music Box/DawnsMusicInfo.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public enum DawnsMusicRarity + { + Common, + Uncommon, + Rare, + } + + public class DawnsMusicInfo + { + private int m_Name; + + public int Name + { + get { return m_Name; } + } + + private DawnsMusicRarity m_Rarity; + + public DawnsMusicRarity Rarity + { + get { return m_Rarity; } + } + + public DawnsMusicInfo( int name, DawnsMusicRarity rarity ) + { + m_Name = name; + m_Rarity = rarity; + } + } +} diff --git a/Scripts/Items/Special/8th Anniversary Items/DupresShield.cs b/Scripts/Items/Special/8th Anniversary Items/DupresShield.cs new file mode 100644 index 0000000..4b02012 --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/DupresShield.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DupresShield : BaseShield, ITokunoDyable + { + public override int LabelNumber { get { return 1075196; } } // Dupre�s Shield + + public override int BasePhysicalResistance { get { return 1; } } + public override int BaseFireResistance { get { return 0; } } + public override int BaseColdResistance { get { return 0; } } + public override int BasePoisonResistance { get { return 0; } } + public override int BaseEnergyResistance { get { return 1; } } + + public override int InitMinHits { get { return 255; } } + public override int InitMaxHits { get { return 255; } } + + public override int AosStrReq { get { return 50; } } + + public override int ArmorBase { get { return 15; } } + + [Constructable] + public DupresShield() : base( 0x2B01 ) + { + LootType = LootType.Blessed; + Weight = 6.0; + + Attributes.BonusHits = 5; + Attributes.RegenHits = 1; + + SkillBonuses.SetValues( 0, SkillName.Parry, 5 ); + } + + public DupresShield( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/8th Anniversary Items/FountainOfLife.cs b/Scripts/Items/Special/8th Anniversary Items/FountainOfLife.cs new file mode 100644 index 0000000..f71d947 --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/FountainOfLife.cs @@ -0,0 +1,274 @@ +using System; +using Server.Multis; +using System.Collections.Generic; +using Server.Gumps; + +namespace Server.Items +{ + public class EnhancedBandage : Bandage + { + public static int HealingBonus { get { return 10; } } + + public override int LabelNumber { get { return 1152441; } } // enhanced bandage + + [Constructable] + public EnhancedBandage() : this( 1 ) + { + } + + [Constructable] + public EnhancedBandage( int amount ) : base( amount ) + { + Hue = 0x8A5; + } + + public EnhancedBandage( Serial serial ) : base( serial ) + { + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + return false; + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + list.Add(1075216); // these bandages have been enhanced + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [FlipableAttribute( 0x2AC0, 0x2AC3 )] + public class FountainOfLife : BaseAddonContainer + { + public override BaseAddonContainerDeed Deed + { + get { return new FountainOfLifeDeed( m_Charges ); } + } + + public override bool OnDragLift(Mobile from) + { + return false; + } + + public virtual TimeSpan RechargeTime { get { return TimeSpan.FromDays( 1 ); } } + + public override int LabelNumber { get { return 1075197; } } // Fountain of Life + public override int DefaultGumpID { get { return 0x484; } } + public override int DefaultDropSound { get { return 66; } } + public override int DefaultMaxItems { get { return 125; } } + + private int m_Charges; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get { return m_Charges; } + set { m_Charges = Math.Min( value, 10 ); InvalidateProperties(); } + } + + private Timer m_Timer; + + [Constructable] + public FountainOfLife() : this( 10 ) + { + } + + [Constructable] + public FountainOfLife( int charges ) : base( 0x2AC0 ) + { + m_Charges = charges; + + m_Timer = Timer.DelayCall( RechargeTime, RechargeTime, new TimerCallback( Recharge ) ); + } + + public FountainOfLife( Serial serial ) : base( serial ) + { + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is Bandage ) + { + bool allow = base.OnDragDrop( from, dropped ); + + if ( allow ) + Enhance(from); + + return allow; + } + else + { + from.SendLocalizedMessage( 1075209 ); // Only bandages may be dropped into the fountain. + return false; + } + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( item is Bandage ) + { + bool allow = base.OnDragDropInto( from, item, p ); + + if ( allow ) + Enhance(from); + + return allow; + } + else + { + from.SendLocalizedMessage( 1075209 ); // Only bandages may be dropped into the fountain. + return false; + } + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1075217, m_Charges.ToString() ); // ~1_val~ charges remaining + } + + public override void OnDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + base.OnDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + + writer.Write( m_Charges ); + writer.Write( (DateTime) m_Timer.Next ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadInt(); + + DateTime next = reader.ReadDateTime(); + + if ( next < DateTime.Now ) + m_Timer = Timer.DelayCall( TimeSpan.Zero, RechargeTime, new TimerCallback( Recharge ) ); + else + m_Timer = Timer.DelayCall( next - DateTime.Now, RechargeTime, new TimerCallback( Recharge ) ); + } + + public void Recharge() + { + m_Charges = 10; + + Enhance(null); + } + + public void Enhance(Mobile from) + { + for (int i = Items.Count - 1; i >= 0 && m_Charges > 0; --i) + { + if (Items[i] is EnhancedBandage) + continue; + + Bandage bandage = Items[i] as Bandage; + + if (bandage != null) + { + Item enhanced; + + if (bandage.Amount > m_Charges) + { + bandage.Amount -= m_Charges; + enhanced = new EnhancedBandage(m_Charges); + m_Charges = 0; + } + else + { + enhanced = new EnhancedBandage(bandage.Amount); + m_Charges -= bandage.Amount; + bandage.Delete(); + } + + if (from == null || !TryDropItem(from, enhanced, false)) // try stacking first + DropItem(enhanced); + } + } + + InvalidateProperties(); + } + } + + public class FountainOfLifeDeed : BaseAddonContainerDeed + { + public override int LabelNumber { get { return 1075197; } } // Fountain of Life + public override BaseAddonContainer Addon { get { return new FountainOfLife(m_Charges); } } + + private int m_Charges; + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get { return m_Charges; } + set { m_Charges = Math.Min(value, 10); InvalidateProperties(); } + } + + [Constructable] + public FountainOfLifeDeed() + : this(10) + { + } + + [Constructable] + public FountainOfLifeDeed(int charges) + : base() + { + LootType = LootType.Blessed; + m_Charges = charges; + } + + public FountainOfLifeDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); //version + + writer.Write(m_Charges); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/8th Anniversary Items/OssianGrimoire.cs b/Scripts/Items/Special/8th Anniversary Items/OssianGrimoire.cs new file mode 100644 index 0000000..051d856 --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/OssianGrimoire.cs @@ -0,0 +1,41 @@ +using System; + +namespace Server.Items +{ + public class OssianGrimoire : NecromancerSpellbook, ITokunoDyable + { + public override int LabelNumber { get { return 1078148; } } // Ossian Grimoire + + [Constructable] + public OssianGrimoire() : base() + { + LootType = LootType.Blessed; + + SkillBonuses.SetValues( 0, SkillName.Necromancy, 10.0 ); + Attributes.RegenMana = 1; + Attributes.CastSpeed = 1; + Attributes.IncreasedKarmaLoss = 5; + } + + public OssianGrimoire( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); //version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0) + Attributes.IncreasedKarmaLoss = 5; + } + } +} diff --git a/Scripts/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs b/Scripts/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs new file mode 100644 index 0000000..a70ba0e --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/QuiverOfInfinity.cs @@ -0,0 +1,47 @@ +using System; + +namespace Server.Items +{ + public class QuiverOfInfinity : BaseQuiver, ITokunoDyable + { + public override int LabelNumber { get { return 1075201; } } // Quiver of Infinity + + [Constructable] + public QuiverOfInfinity() + : base(0x2B02) + { + LootType = LootType.Blessed; + Weight = 8.0; + + WeightReduction = 30; + LowerAmmoCost = 20; + + Attributes.DefendChance = 5; + } + + public QuiverOfInfinity(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(2); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version < 1 && DamageIncrease == 0) + DamageIncrease = 10; + + if (version < 2 && Attributes.WeaponDamage == 10) + Attributes.WeaponDamage = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/8th Anniversary Items/Talismans.cs b/Scripts/Items/Special/8th Anniversary Items/Talismans.cs new file mode 100644 index 0000000..7685115 --- /dev/null +++ b/Scripts/Items/Special/8th Anniversary Items/Talismans.cs @@ -0,0 +1,187 @@ +using System; +using Server.Mobiles; +using Server.Spells.Ninjitsu; + +namespace Server.Items +{ + public enum TalismanForm + { + Ferret = 1031672, + Squirrel = 1031671, + CuSidhe = 1031670, + Reptalon = 1075202 + } + + public class BaseFormTalisman : Item, ITokunoDyable + { + public virtual TalismanForm Form { get { return TalismanForm.Squirrel; } } + + public BaseFormTalisman() : base( 0x2F59 ) + { + LootType = LootType.Blessed; + Layer = Layer.Talisman; + Weight = 1.0; + } + + public BaseFormTalisman( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1075200, String.Format( "#{0}", (int) Form ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + public override void OnRemoved( object parent ) + { + base.OnRemoved( parent ); + + if ( parent is Mobile ) + { + Mobile m = (Mobile) parent; + + AnimalForm.RemoveContext( m, true ); + } + } + + public static bool EntryEnabled( Mobile m, Type type ) + { + if ( type == typeof( Squirrel ) ) + return m.Talisman is SquirrelFormTalisman; + else if ( type == typeof( Ferret ) ) + return m.Talisman is FerretFormTalisman; + else if ( type == typeof( CuSidhe ) ) + return m.Talisman is CuSidheFormTalisman; + else if ( type == typeof( Reptalon ) ) + return m.Talisman is ReptalonFormTalisman; + + return true; + } + } + + public class FerretFormTalisman : BaseFormTalisman + { + public override TalismanForm Form { get { return TalismanForm.Ferret; } } + + [Constructable] + public FerretFormTalisman() : base() + { + } + + public FerretFormTalisman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SquirrelFormTalisman : BaseFormTalisman + { + public override TalismanForm Form { get { return TalismanForm.Squirrel; } } + + [Constructable] + public SquirrelFormTalisman () : base() + { + } + + public SquirrelFormTalisman ( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class CuSidheFormTalisman : BaseFormTalisman + { + public override TalismanForm Form { get { return TalismanForm.CuSidhe; } } + + [Constructable] + public CuSidheFormTalisman() : base() + { + } + + public CuSidheFormTalisman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ReptalonFormTalisman : BaseFormTalisman + { + public override TalismanForm Form { get { return TalismanForm.Reptalon; } } + + [Constructable] + public ReptalonFormTalisman() : base() + { + } + + public ReptalonFormTalisman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); //version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs b/Scripts/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs new file mode 100644 index 0000000..2a92948 --- /dev/null +++ b/Scripts/Items/Special/AoS Promotional/HoodedShroudOfShadows.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x2684, 0x2683 )] + public class HoodedShroudOfShadows : BaseOuterTorso + { + [Constructable] + public HoodedShroudOfShadows() : this( 0x455 ) + { + } + + [Constructable] + public HoodedShroudOfShadows( int hue ) : base( 0x2684, hue ) + { + LootType = LootType.Blessed; + Weight = 3.0; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public HoodedShroudOfShadows( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/AoS Promotional/LuckyNecklace.cs b/Scripts/Items/Special/AoS Promotional/LuckyNecklace.cs new file mode 100644 index 0000000..855f893 --- /dev/null +++ b/Scripts/Items/Special/AoS Promotional/LuckyNecklace.cs @@ -0,0 +1,37 @@ +using System; +using Server.Mobiles; + +namespace Server.Items +{ + public class LuckyNecklace : BaseJewel + { + public override int Hue{ get { return 1150; } } + public override int LabelNumber{ get { return 1075239; } } //Lucky Necklace 1075239 + + [Constructable] + public LuckyNecklace( ) + : base( 0x1088, Layer.Neck ) + { + base.Attributes.Luck = 200; + LootType = LootType.Blessed; + } + + public LuckyNecklace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + reader.ReadInt(); /* int version = reader.ReadInt(); Why? Just to have an unused var? */ + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenArmoire.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenArmoire.cs new file mode 100644 index 0000000..4eb500f --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenArmoire.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0xC12, 0xC13 )] + public class BrokenArmoireComponent : AddonComponent + { + public override int LabelNumber { get { return 1076262; } } // Broken Armoire + + public BrokenArmoireComponent() : base( 0xC12 ) + { + } + + public BrokenArmoireComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenArmoireAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenArmoireDeed(); } } + + [Constructable] + public BrokenArmoireAddon() : base() + { + AddComponent( new BrokenArmoireComponent(), 0, 0, 0 ); + } + + public BrokenArmoireAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenArmoireDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenArmoireAddon(); } } + public override int LabelNumber { get { return 1076262; } } // Broken Armoire + + [Constructable] + public BrokenArmoireDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenArmoireDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenBed.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenBed.cs new file mode 100644 index 0000000..3d5238d --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenBed.cs @@ -0,0 +1,134 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class BrokenBedAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenBedDeed(); } } + + [Constructable] + public BrokenBedAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new LocalizedAddonComponent( 0x1895, 1076263 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1894, 1076263 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1897, 1076263 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1896, 1076263 ), 1, 1, 0 ); + } + else // south + { + AddComponent( new LocalizedAddonComponent( 0x1899, 1076263 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1898, 1076263 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x189B, 1076263 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0x189A, 1076263 ), 1, 1, 0 ); + } + } + + public BrokenBedAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenBedDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenBedAddon( m_East ); } } + public override int LabelNumber { get { return 1076263; } } // Broken Bed + + private bool m_East; + + [Constructable] + public BrokenBedDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenBedDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private BrokenBedDeed m_Deed; + + public InternalGump( BrokenBedDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076749, 0x7FFF, false, false ); // Please select your broken bed position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenBookcase.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenBookcase.cs new file mode 100644 index 0000000..1fea461 --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenBookcase.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0xC14, 0xC15 )] + public class BrokenBookcaseComponent : AddonComponent + { + public override int LabelNumber { get { return 1076258; } } // Broken Bookcase + + public BrokenBookcaseComponent() : base( 0xC14 ) + { + } + + public BrokenBookcaseComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenBookcaseAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenBookcaseDeed(); } } + + [Constructable] + public BrokenBookcaseAddon() : base() + { + AddComponent( new BrokenBookcaseComponent(), 0, 0, 0 ); + } + + public BrokenBookcaseAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenBookcaseDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenBookcaseAddon(); } } + public override int LabelNumber { get { return 1076258; } } // Broken Bookcase + + [Constructable] + public BrokenBookcaseDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenBookcaseDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs new file mode 100644 index 0000000..d120dbf --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenChestOfDrawers.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0xC24, 0xC25 )] + public class BrokenChestOfDrawersComponent : AddonComponent + { + public override int LabelNumber { get { return 1076261; } } // Broken Chest of Drawers + + public BrokenChestOfDrawersComponent() : base( 0xC24 ) + { + } + + public BrokenChestOfDrawersComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenChestOfDrawersAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenChestOfDrawersDeed(); } } + + [Constructable] + public BrokenChestOfDrawersAddon() : base() + { + AddComponent( new BrokenChestOfDrawersComponent(), 0, 0, 0 ); + } + + public BrokenChestOfDrawersAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenChestOfDrawersDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenChestOfDrawersAddon(); } } + public override int LabelNumber { get { return 1076261; } } // Broken Chest of Drawers + + [Constructable] + public BrokenChestOfDrawersDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenChestOfDrawersDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs new file mode 100644 index 0000000..c4edaba --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenCoveredChair.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0xC17, 0xC18 )] + public class BrokenCoveredChairComponent : AddonComponent + { + public override int LabelNumber { get { return 1076257; } } // Broken Covered Chair + + public BrokenCoveredChairComponent() : base( 0xC17 ) + { + } + + public BrokenCoveredChairComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenCoveredChairAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenCoveredChairDeed(); } } + + [Constructable] + public BrokenCoveredChairAddon() : base() + { + AddComponent( new BrokenCoveredChairComponent(), 0, 0, 0 ); + } + + public BrokenCoveredChairAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenCoveredChairDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenCoveredChairAddon(); } } + public override int LabelNumber { get { return 1076257; } } // Broken Covered Chair + + [Constructable] + public BrokenCoveredChairDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenCoveredChairDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs new file mode 100644 index 0000000..7759b20 --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenFallenChair.cs @@ -0,0 +1,92 @@ +using System; + +namespace Server.Items +{ + [Flipable(0xC19, 0xC1a)] + public class BrokenFallenChairComponent : AddonComponent + { + public override int LabelNumber { get { return 1076264; } } // Broken Fallen Chair + + public BrokenFallenChairComponent() + : base(0xC19) + { + } + + public BrokenFallenChairComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenFallenChairAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenFallenChairDeed(); } } + + [Constructable] + public BrokenFallenChairAddon() : base() + { + AddComponent( new BrokenFallenChairComponent(), 0, 0, 0 ); + } + + public BrokenFallenChairAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenFallenChairDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenFallenChairAddon(); } } + public override int LabelNumber { get { return 1076264; } } // Broken Fallen Chair + + [Constructable] + public BrokenFallenChairDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenFallenChairDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/BrokenVanity.cs b/Scripts/Items/Special/Broken Furniture Collection/BrokenVanity.cs new file mode 100644 index 0000000..ed65e3f --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/BrokenVanity.cs @@ -0,0 +1,130 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class BrokenVanityAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BrokenVanityDeed(); } } + + [Constructable] + public BrokenVanityAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new LocalizedAddonComponent( 0xC20, 1076260 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xC21, 1076260 ), 0, -1, 0 ); + } + else // south + { + AddComponent( new LocalizedAddonComponent( 0xC22, 1076260 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xC23, 1076260 ), -1, 0, 0 ); + } + } + + public BrokenVanityAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BrokenVanityDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BrokenVanityAddon( m_East ); } } + public override int LabelNumber { get { return 1076260; } } // Broken Vanity + + private bool m_East; + + [Constructable] + public BrokenVanityDeed() : base() + { + LootType = LootType.Blessed; + } + + public BrokenVanityDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private BrokenVanityDeed m_Deed; + + public InternalGump( BrokenVanityDeed deed ) : base( 60, 63 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076747, 0x7FFF, false, false ); // Please select your broken vanity position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs b/Scripts/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs new file mode 100644 index 0000000..de96a0e --- /dev/null +++ b/Scripts/Items/Special/Broken Furniture Collection/StandingBrokenChair.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0xC1B, 0xC1C, 0xC1E, 0xC1D )] + public class StandingBrokenChairComponent : AddonComponent + { + public override int LabelNumber { get { return 1076259; } } // Standing Broken Chair + + public StandingBrokenChairComponent() : base( 0xC1B ) + { + } + + public StandingBrokenChairComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class StandingBrokenChairAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new StandingBrokenChairDeed(); } } + + [Constructable] + public StandingBrokenChairAddon() : base() + { + AddComponent( new StandingBrokenChairComponent(), 0, 0, 0 ); + } + + public StandingBrokenChairAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class StandingBrokenChairDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new StandingBrokenChairAddon(); } } + public override int LabelNumber { get { return 1076259; } } // Standing Broken Chair + + [Constructable] + public StandingBrokenChairDeed() : base() + { + LootType = LootType.Blessed; + } + + public StandingBrokenChairDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs new file mode 100644 index 0000000..5a73426 --- /dev/null +++ b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/AncientSmithyHammer.cs @@ -0,0 +1,134 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [FlipableAttribute( 0x13E4, 0x13E3 )] + public class AncientSmithyHammer : BaseTool + { + private int m_Bonus; + private SkillMod m_SkillMod; + + [CommandProperty( AccessLevel.GameMaster )] + public int Bonus + { + get + { + return m_Bonus; + } + set + { + m_Bonus = value; + InvalidateProperties(); + + if ( m_Bonus == 0 ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = null; + } + else if ( m_SkillMod == null && Parent is Mobile ) + { + m_SkillMod = new DefaultSkillMod( SkillName.Blacksmith, true, m_Bonus ); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + else if ( m_SkillMod != null ) + { + m_SkillMod.Value = m_Bonus; + } + } + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( m_Bonus != 0 && parent is Mobile ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = new DefaultSkillMod( SkillName.Blacksmith, true, m_Bonus ); + ((Mobile)parent).AddSkillMod( m_SkillMod ); + } + } + + public override void OnRemoved( object parent ) + { + base.OnRemoved( parent ); + + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = null; + } + + public override CraftSystem CraftSystem{ get{ return DefBlacksmithy.CraftSystem; } } + public override int LabelNumber{ get{ return 1045127; } } // ancient smithy hammer + + [Constructable] + public AncientSmithyHammer( int bonus ) : this( bonus, 600 ) + { + } + + [Constructable] + public AncientSmithyHammer( int bonus, int uses ) : base( uses, 0x13E4 ) + { + m_Bonus = bonus; + Weight = 8.0; + Layer = Layer.OneHanded; + Hue = 0x482; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Bonus != 0 ) + list.Add( 1060451, "#1042354\t{0}", m_Bonus.ToString() ); // ~1_skillname~ +~2_val~ + } + + public AncientSmithyHammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Bonus ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Bonus = reader.ReadInt(); + break; + } + } + + if ( m_Bonus != 0 && Parent is Mobile ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = new DefaultSkillMod( SkillName.Blacksmith, true, m_Bonus ); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + + if ( Hue == 0 ) + Hue = 0x482; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs new file mode 100644 index 0000000..7d97ca0 --- /dev/null +++ b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/ColoredAnvil.cs @@ -0,0 +1,38 @@ +using System; +using Server; +using Server.Engines.Craft; + +namespace Server.Items +{ + [Anvil, Flipable( 0xFAF, 0xFB0 )] + public class ColoredAnvil : Item + { + [Constructable] + public ColoredAnvil() : this( CraftResources.GetHue( (CraftResource)Utility.RandomMinMax( (int)CraftResource.MBronze, (int)CraftResource.MSteel ) ) ) + { + } + + [Constructable] + public ColoredAnvil( int hue ) : base( 0xFAF ) + { + Hue = hue; + Weight = 20; + } + + public ColoredAnvil( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs new file mode 100644 index 0000000..48f1eed --- /dev/null +++ b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/GlovesOfMining.cs @@ -0,0 +1,256 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute( 0x13c6, 0x13ce )] + public class LeatherGlovesOfMining : BaseGlovesOfMining + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 40; } } + + public override int AosStrReq{ get{ return 20; } } + public override int OldStrReq{ get{ return 10; } } + + public override int ArmorBase{ get{ return 13; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance{ get{ return ArmorMeditationAllowance.All; } } + + public override int LabelNumber{ get{ return 1045122; } } // leather blacksmith gloves of mining + + [Constructable] + public LeatherGlovesOfMining( int bonus ) : base( bonus, 0x13C6 ) + { + Weight = 1; + } + + public LeatherGlovesOfMining( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x13d5, 0x13dd )] + public class StuddedGlovesOfMining : BaseGlovesOfMining + { + public override int BasePhysicalResistance{ get{ return 2; } } + public override int BaseFireResistance{ get{ return 4; } } + public override int BaseColdResistance{ get{ return 3; } } + public override int BasePoisonResistance{ get{ return 3; } } + public override int BaseEnergyResistance{ get{ return 4; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 45; } } + + public override int AosStrReq{ get{ return 25; } } + public override int OldStrReq{ get{ return 25; } } + + public override int ArmorBase{ get{ return 16; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Studded; } } + public override CraftResource DefaultResource{ get{ return CraftResource.RegularLeather; } } + + public override int LabelNumber{ get{ return 1045123; } } // studded leather blacksmith gloves of mining + + [Constructable] + public StuddedGlovesOfMining( int bonus ) : base( bonus, 0x13D5 ) + { + Weight = 2; + } + + public StuddedGlovesOfMining( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x13eb, 0x13f2 )] + public class RingmailGlovesOfMining : BaseGlovesOfMining + { + public override int BasePhysicalResistance{ get{ return 3; } } + public override int BaseFireResistance{ get{ return 3; } } + public override int BaseColdResistance{ get{ return 1; } } + public override int BasePoisonResistance{ get{ return 5; } } + public override int BaseEnergyResistance{ get{ return 3; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 50; } } + + public override int AosStrReq{ get{ return 40; } } + public override int OldStrReq{ get{ return 20; } } + + public override int OldDexBonus{ get{ return -1; } } + + public override int ArmorBase{ get{ return 22; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Ringmail; } } + + public override int LabelNumber{ get{ return 1045124; } } // ringmail blacksmith gloves of mining + + [Constructable] + public RingmailGlovesOfMining( int bonus ) : base( bonus, 0x13EB ) + { + Weight = 1; + } + + public RingmailGlovesOfMining( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public abstract class BaseGlovesOfMining : BaseArmor + { + private int m_Bonus; + private SkillMod m_SkillMod; + + [CommandProperty( AccessLevel.GameMaster )] + public int Bonus + { + get + { + return m_Bonus; + } + set + { + m_Bonus = value; + InvalidateProperties(); + + if ( m_Bonus == 0 ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = null; + } + else if ( m_SkillMod == null && Parent is Mobile ) + { + m_SkillMod = new DefaultSkillMod( SkillName.Mining, true, m_Bonus ); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + else if ( m_SkillMod != null ) + { + m_SkillMod.Value = m_Bonus; + } + } + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( m_Bonus != 0 && parent is Mobile ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = new DefaultSkillMod( SkillName.Mining, true, m_Bonus ); + ((Mobile)parent).AddSkillMod( m_SkillMod ); + } + } + + public override void OnRemoved( object parent ) + { + base.OnRemoved( parent ); + + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = null; + } + + public BaseGlovesOfMining( int bonus, int itemID ) : base( itemID ) + { + m_Bonus = bonus; + + this.Hue = CraftResources.GetHue( (CraftResource)Utility.RandomMinMax( (int)CraftResource.MBronze, (int)CraftResource.MSteel ) ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Bonus != 0 ) + list.Add( 1062005, m_Bonus.ToString() ); // mining bonus +~1_val~ + } + + public BaseGlovesOfMining( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Bonus ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Bonus = reader.ReadInt(); + break; + } + } + + if ( m_Bonus != 0 && Parent is Mobile ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = new DefaultSkillMod( SkillName.Mining, true, m_Bonus ); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs new file mode 100644 index 0000000..00fd77b --- /dev/null +++ b/Scripts/Items/Special/Bulk Order Rewards/Blacksmithy/PowderOfTemperament.cs @@ -0,0 +1,192 @@ +using Server; +using Server.Targeting; +using Server.Engines.Craft; +using Server.Network; + +namespace Server.Items +{ + public class PowderOfTemperament : Item, IUsesRemaining + { + private int m_UsesRemaining; + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + public bool ShowUsesRemaining { get { return true; } set { } } + + public override int LabelNumber { get { return 1049082; } } // powder of fortifying + + [Constructable] + public PowderOfTemperament() + : this(10) + { + } + + [Constructable] + public PowderOfTemperament(int charges) + : base(4102) + { + Weight = 1.0; + Hue = 2419; + UsesRemaining = charges; + } + + public PowderOfTemperament(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + writer.Write((int)m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt(); + break; + } + } + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, m_UsesRemaining.ToString()); // uses remaining: ~1_val~ + } + + public virtual void DisplayDurabilityTo(Mobile m) + { + LabelToAffix(m, 1017323, AffixType.Append, ": " + m_UsesRemaining.ToString()); // Durability + } + + public override void OnSingleClick(Mobile from) + { + DisplayDurabilityTo(from); + + base.OnSingleClick(from); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) + from.Target = new InternalTarget(this); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + private class InternalTarget : Target + { + private PowderOfTemperament m_Powder; + + public InternalTarget(PowderOfTemperament powder) + : base(2, false, TargetFlags.None) + { + m_Powder = powder; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Powder.Deleted || m_Powder.UsesRemaining <= 0) + { + from.SendLocalizedMessage(1049086); // You have used up your powder of temperament. + return; + } + + if (targeted is IDurability && targeted is Item) + { + IDurability wearable = (IDurability)targeted; + Item item = (Item)targeted; + + if (!wearable.CanFortify) + { + from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. + return; + } + + if ((item.IsChildOf(from.Backpack) || (Core.ML && item.Parent == from)) && m_Powder.IsChildOf(from.Backpack)) + { + int origMaxHP = wearable.MaxHitPoints; + int origCurHP = wearable.HitPoints; + + if (origMaxHP > 0) + { + int initMaxHP = Core.AOS ? 255 : wearable.InitMaxHits; + + wearable.UnscaleDurability(); + + if (wearable.MaxHitPoints < initMaxHP) + { + int bonus = initMaxHP - wearable.MaxHitPoints; + + if (bonus > 10) + bonus = 10; + + wearable.MaxHitPoints += bonus; + wearable.HitPoints += bonus; + + wearable.ScaleDurability(); + + if (wearable.MaxHitPoints > 255) wearable.MaxHitPoints = 255; + if (wearable.HitPoints > 255) wearable.HitPoints = 255; + + if (wearable.MaxHitPoints > origMaxHP) + { + from.SendLocalizedMessage(1049084); // You successfully use the powder on the item. + from.PlaySound(0x247); + + --m_Powder.UsesRemaining; + + if (m_Powder.UsesRemaining <= 0) + { + from.SendLocalizedMessage(1049086); // You have used up your powder of fortifying. + m_Powder.Delete(); + } + } + else + { + wearable.MaxHitPoints = origMaxHP; + wearable.HitPoints = origCurHP; + from.SendLocalizedMessage(1049085); // The item cannot be improved any further. + } + } + else + { + from.SendLocalizedMessage(1049085); // The item cannot be improved any further. + wearable.ScaleDurability(); + } + } + else + { + from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. + } + } + else + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + } + else + { + from.SendLocalizedMessage(1049083); // You cannot use the powder on that item. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Community Collection/JesterHatofChuckles.cs b/Scripts/Items/Special/Community Collection/JesterHatofChuckles.cs new file mode 100644 index 0000000..994ed52 --- /dev/null +++ b/Scripts/Items/Special/Community Collection/JesterHatofChuckles.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Items +{ + public class JesterHatofChuckles : BaseHat, ITokunoDyable + { + public override int LabelNumber { get { return 1073256; } } //Jester Hat of Chuckles - Museum of Vesper Replica 1073256 + + public override int BasePhysicalResistance { get { return 12; } } + public override int BaseFireResistance { get { return 12; } } + public override int BaseColdResistance { get { return 12; } } + public override int BasePoisonResistance { get { return 12; } } + public override int BaseEnergyResistance { get { return 12; } } + + public override int InitMinHits{ get{ return 100; } } + public override int InitMaxHits{ get{ return 100; } } + + [Constructable] + public JesterHatofChuckles() : this( Utility.RandomList( 0x13e, 0x03, 0x172, 0x3f ) ) + { + } + + [Constructable] + public JesterHatofChuckles( int hue ) : base( 0x171C, hue ) + { + Attributes.Luck = 150; + Weight = 1.0; + } + + public JesterHatofChuckles( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs b/Scripts/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs new file mode 100644 index 0000000..fe64344 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/AwesomeDisturbingPortrait.cs @@ -0,0 +1,188 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A5D, 0x2A61 )] + public class AwesomeDisturbingPortraitComponent : AddonComponent + { + public override int LabelNumber { get { return 1074479; } } // Disturbing portrait + public bool FacingSouth { get { return ItemID < 0x2A61; } } + + private InternalTimer m_Timer; + + public AwesomeDisturbingPortraitComponent() : base( 0x2A5D ) + { + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 1 ) ); + m_Timer.Start(); + } + + public AwesomeDisturbingPortraitComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + { + int hours; + int minutes; + + Clock.GetTime( Map, X, Y, out hours, out minutes ); + + if ( hours < 4 || hours > 20 ) + Effects.PlaySound( Location, Map, 0x569 ); + + UpdateImage(); + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Timer = new InternalTimer( this, TimeSpan.Zero ); + m_Timer.Start(); + } + + private void UpdateImage() + { + int hours; + int minutes; + + Clock.GetTime( Map, X, Y, out hours, out minutes ); + + if ( FacingSouth ) + { + if ( hours < 4 ) + ItemID = 0x2A60; + else if ( hours < 6 ) + ItemID = 0x2A5F; + else if ( hours < 8 ) + ItemID = 0x2A5E; + else if ( hours < 16 ) + ItemID = 0x2A5D; + else if ( hours < 18 ) + ItemID = 0x2A5E; + else if ( hours < 20 ) + ItemID = 0x2A5F; + else + ItemID = 0x2A60; + } + else + { + if ( hours < 4 ) + ItemID = 0x2A64; + else if ( hours < 6 ) + ItemID = 0x2A63; + else if ( hours < 8 ) + ItemID = 0x2A62; + else if ( hours < 16 ) + ItemID = 0x2A61; + else if ( hours < 18 ) + ItemID = 0x2A62; + else if ( hours < 20 ) + ItemID = 0x2A63; + else + ItemID = 0x2A64; + } + } + + private class InternalTimer : Timer + { + private AwesomeDisturbingPortraitComponent m_Component; + + public InternalTimer( AwesomeDisturbingPortraitComponent c, TimeSpan delay ) : base( delay, TimeSpan.FromMinutes( 10 ) ) + { + m_Component = c; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + if ( m_Component != null && !m_Component.Deleted ) + m_Component.UpdateImage(); + } + } + } + + public class AwesomeDisturbingPortraitAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new AwesomeDisturbingPortraitDeed(); } } + + [Constructable] + public AwesomeDisturbingPortraitAddon() : base() + { + AddComponent( new AwesomeDisturbingPortraitComponent(), 0, 0, 0 ); + } + + public AwesomeDisturbingPortraitAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class AwesomeDisturbingPortraitDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new AwesomeDisturbingPortraitAddon(); } } + public override int LabelNumber { get { return 1074479; } } // Disturbing portrait + + [Constructable] + public AwesomeDisturbingPortraitDeed() : base() + { + LootType = LootType.Blessed; + } + + public AwesomeDisturbingPortraitDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/BedOfNails.cs b/Scripts/Items/Special/Evil Home Decor Collection/BedOfNails.cs new file mode 100644 index 0000000..0bde44a --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/BedOfNails.cs @@ -0,0 +1,195 @@ +using System; + +namespace Server.Items +{ + public class BedOfNailsComponent : AddonComponent + { + public override int LabelNumber { get { return 1074801; } } // Bed of Nails + + public BedOfNailsComponent(int itemID) + : base(itemID) + { + } + + public BedOfNailsComponent(Serial serial) + : base(serial) + { + } + + public override bool OnMoveOver(Mobile m) + { + bool allow = base.OnMoveOver(m); + + if (allow && Addon is BedOfNailsAddon) + ((BedOfNailsAddon)Addon).OnMoveOver(m); + + return allow; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + [FlipableAddon(Direction.South, Direction.East)] + public class BedOfNailsAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BedOfNailsDeed(); } } + + private InternalTimer m_Timer; + + [Constructable] + public BedOfNailsAddon() + : base() + { + Direction = Direction.South; + + AddComponent(new BedOfNailsComponent(0x2A81), 0, 0, 0); + AddComponent(new BedOfNailsComponent(0x2A82), 0, -1, 0); + } + + public BedOfNailsAddon(Serial serial) + : base(serial) + { + } + + public override bool OnMoveOver(Mobile m) + { + if (m.Alive && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + { + if (m.Player) + { + if (m.Female) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x53B, 0x53D)); + else + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x53E, 0x540)); + } + + if (m_Timer == null || !m_Timer.Running) + (m_Timer = new InternalTimer(m)).Start(); + } + + return true; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + public virtual void Flip(Mobile from, Direction direction) + { + switch (direction) + { + case Direction.East: + AddComponent(new BedOfNailsComponent(0x2A89), 0, 0, 0); + AddComponent(new BedOfNailsComponent(0x2A8A), -1, 0, 0); + break; + case Direction.South: + AddComponent(new BedOfNailsComponent(0x2A81), 0, 0, 0); + AddComponent(new BedOfNailsComponent(0x2A82), 0, -1, 0); + break; + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + private Point3D m_Location; + + public InternalTimer(Mobile m) + : base(TimeSpan.Zero, TimeSpan.FromSeconds(1), 5) + { + m_Mobile = m; + m_Location = Point3D.Zero; + } + + protected override void OnTick() + { + if (m_Mobile == null || m_Mobile.Map == null || m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Map == Map.Internal) + { + Stop(); + } + else + { + if (m_Location != m_Mobile.Location) + { + int amount = Utility.RandomMinMax(0, 7); + + for (int i = 0; i < amount; i++) + { + int x = m_Mobile.X + Utility.RandomMinMax(-1, 1); + int y = m_Mobile.Y + Utility.RandomMinMax(-1, 1); + int z = m_Mobile.Z; + + if (!m_Mobile.Map.CanFit(x, y, z, 1, false, false, true)) + { + z = m_Mobile.Map.GetAverageZ(x, y); + + if (!m_Mobile.Map.CanFit(x, y, z, 1, false, false, true)) + { + continue; + } + } + + Blood blood = new Blood(Utility.RandomMinMax(0x122C, 0x122F)); + blood.MoveToWorld(new Point3D(x, y, z), m_Mobile.Map); + } + m_Location = m_Mobile.Location; + } + } + } + } + } + + public class BedOfNailsDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BedOfNailsAddon(); } } + public override int LabelNumber { get { return 1074801; } } // Bed of Nails + + [Constructable] + public BedOfNailsDeed() + : base() + { + LootType = LootType.Blessed; + } + + public BedOfNailsDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Evil Home Decor Collection/BoneCouch.cs b/Scripts/Items/Special/Evil Home Decor Collection/BoneCouch.cs new file mode 100644 index 0000000..33cde8b --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/BoneCouch.cs @@ -0,0 +1,119 @@ +using System; + +namespace Server.Items +{ + public class BoneCouchComponent : AddonComponent + { + public override int LabelNumber { get { return 1074477; } } // Bone couch + + public BoneCouchComponent( int itemID ) : base( itemID ) + { + } + + public BoneCouchComponent( Serial serial ) : base( serial ) + { + } + + public override bool OnMoveOver( Mobile m ) + { + bool allow = base.OnMoveOver( m ); + + if ( allow && m.Alive && m.Player && ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x547, 0x54A ) ); + + return allow; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [FlipableAddon( Direction.South, Direction.East )] + public class BoneCouchAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BoneCouchDeed(); } } + + [Constructable] + public BoneCouchAddon() : base() + { + Direction = Direction.South; + + AddComponent( new BoneCouchComponent( 0x2A5A ), 0, 0, 0 ); + AddComponent( new BoneCouchComponent( 0x2A5B ), -1, 0, 0 ); + } + + public BoneCouchAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + public virtual void Flip( Mobile from, Direction direction ) + { + switch ( direction ) + { + case Direction.East: + AddComponent( new BoneCouchComponent( 0x2A80 ), 0, 0, 0 ); + AddComponent( new BoneCouchComponent( 0x2A7F ), 0, 1, 0 ); + break; + case Direction.South: + AddComponent( new BoneCouchComponent( 0x2A5A ), 0, 0, 0 ); + AddComponent( new BoneCouchComponent( 0x2A5B ), -1, 0, 0 ); + break; + } + } + } + + public class BoneCouchDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BoneCouchAddon(); } } + public override int LabelNumber { get { return 1074477; } } // Bone couch + + [Constructable] + public BoneCouchDeed() : base() + { + LootType = LootType.Blessed; + } + + public BoneCouchDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/BoneTable.cs b/Scripts/Items/Special/Evil Home Decor Collection/BoneTable.cs new file mode 100644 index 0000000..7d015a3 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/BoneTable.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class BoneTableAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BoneTableDeed(); } } + + [Constructable] + public BoneTableAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x2A5C, 1074478 ), 0, 0, 0 ); + } + + public BoneTableAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoneTableDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BoneTableAddon(); } } + public override int LabelNumber { get { return 1074478; } } // Bone table + + [Constructable] + public BoneTableDeed() : base() + { + LootType = LootType.Blessed; + } + + public BoneTableDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/BoneThrone.cs b/Scripts/Items/Special/Evil Home Decor Collection/BoneThrone.cs new file mode 100644 index 0000000..8165d7b --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/BoneThrone.cs @@ -0,0 +1,101 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x2A58, 0x2A59 )] + public class BoneThroneComponent : AddonComponent + { + public override int LabelNumber { get { return 1074476; } } // Bone throne + + public BoneThroneComponent() : base( 0x2A58 ) + { + } + + public BoneThroneComponent( Serial serial ) : base( serial ) + { + } + + public override bool OnMoveOver( Mobile m ) + { + bool allow = base.OnMoveOver( m ); + + if ( allow && m.Alive && m.Player && ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x54B, 0x54D ) ); + + return allow; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoneThroneAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BoneThroneDeed(); } } + + [Constructable] + public BoneThroneAddon() : base() + { + AddComponent( new BoneThroneComponent(), 0, 0, 0 ); + } + + public BoneThroneAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoneThroneDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BoneThroneAddon(); } } + public override int LabelNumber { get { return 1074476; } } // Bone throne + + [Constructable] + public BoneThroneDeed() : base() + { + LootType = LootType.Blessed; + } + + public BoneThroneDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs b/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs new file mode 100644 index 0000000..34aee93 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/CreepyPortrait.cs @@ -0,0 +1,144 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable(0x2A69, 0x2A6D)] + public class CreepyPortraitComponent : AddonComponent + { + public override int LabelNumber { get { return 1074481; } } // Creepy portrait + public override bool HandlesOnMovement { get { return true; } } + + public CreepyPortraitComponent() + : base(0x2A69) + { + } + + public CreepyPortraitComponent(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (Utility.InRange(Location, from.Location, 2)) + Effects.PlaySound(Location, Map, Utility.RandomMinMax(0x565, 0x566)); + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void OnMovement(Mobile m, Point3D old) + { + if (m.Alive && m.Player && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + { + if (!Utility.InRange(old, Location, 2) && Utility.InRange(m.Location, Location, 2)) + { + if (ItemID == 0x2A69 || ItemID == 0x2A6D) + { + Up(); + Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, new TimerCallback(Up)); + } + } + else if (Utility.InRange(old, Location, 2) && !Utility.InRange(m.Location, Location, 2)) + { + if (ItemID == 0x2A6C || ItemID == 0x2A70) + { + Down(); + Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(0.5), 2, new TimerCallback(Down)); + } + } + } + } + + private void Up() + { + ItemID += 1; + } + + private void Down() + { + ItemID -= 1; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + if (version == 0 && ItemID != 0x2A69 && ItemID != 0x2A6D) + ItemID = 0x2A69; + } + } + + public class CreepyPortraitAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new CreepyPortraitDeed(); } } + + [Constructable] + public CreepyPortraitAddon() + : base() + { + AddComponent(new CreepyPortraitComponent(), 0, 0, 0); + } + + public CreepyPortraitAddon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class CreepyPortraitDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new CreepyPortraitAddon(); } } + public override int LabelNumber { get { return 1074481; } } // Creepy portrait + + [Constructable] + public CreepyPortraitDeed() + : base() + { + LootType = LootType.Blessed; + } + + public CreepyPortraitDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs b/Scripts/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs new file mode 100644 index 0000000..6c8ad52 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/DisturbingPortrait.cs @@ -0,0 +1,122 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A5D, 0x2A61 )] + public class DisturbingPortraitComponent : AddonComponent + { + public override int LabelNumber { get { return 1074479; } } // Disturbing portrait + + private Timer m_Timer; + + public DisturbingPortraitComponent() : base( 0x2A5D ) + { + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), TimeSpan.FromMinutes( 3 ), new TimerCallback( Change ) ); + } + + public DisturbingPortraitComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x567, 0x568 ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), TimeSpan.FromMinutes( 3 ), new TimerCallback( Change ) ); + } + + private void Change() + { + if ( ItemID < 0x2A61 ) + ItemID = Utility.RandomMinMax( 0x2A5D, 0x2A60 ); + else + ItemID = Utility.RandomMinMax( 0x2A61, 0x2A64 ); + } + } + + public class DisturbingPortraitAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new DisturbingPortraitDeed(); } } + + [Constructable] + public DisturbingPortraitAddon() : base() + { + AddComponent( new DisturbingPortraitComponent(), 0, 0, 0 ); + } + + public DisturbingPortraitAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class DisturbingPortraitDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new DisturbingPortraitAddon(); } } + public override int LabelNumber { get { return 1074479; } } // Disturbing portrait + + [Constructable] + public DisturbingPortraitDeed() : base() + { + LootType = LootType.Blessed; + } + + public DisturbingPortraitDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/HauntedMirror.cs b/Scripts/Items/Special/Evil Home Decor Collection/HauntedMirror.cs new file mode 100644 index 0000000..bdf690c --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/HauntedMirror.cs @@ -0,0 +1,114 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x2A7B, 0x2A7D )] + public class HaunterMirrorComponent : AddonComponent + { + public override int LabelNumber { get { return 1074800; } } // Haunted Mirror + public override bool HandlesOnMovement { get { return true; } } + + public HaunterMirrorComponent() : base( 0x2A7B ) + { + } + + public HaunterMirrorComponent( Serial serial ) : base( serial ) + { + } + + public override void OnMovement( Mobile m, Point3D old ) + { + base.OnMovement( m, old ); + + if ( m.Alive && m.Player && ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) ) + { + if ( !Utility.InRange( old, Location, 2 ) && Utility.InRange( m.Location, Location, 2 ) ) + { + if ( ItemID == 0x2A7B || ItemID == 0x2A7D ) + { + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x551, 0x553 ) ); + ItemID += 1; + } + } + else if ( Utility.InRange( old, Location, 2 ) && !Utility.InRange( m.Location, Location, 2 ) ) + { + if ( ItemID == 0x2A7C || ItemID == 0x2A7E ) + ItemID -= 1; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class HaunterMirrorAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new HaunterMirrorDeed(); } } + + [Constructable] + public HaunterMirrorAddon() : base() + { + AddComponent( new HaunterMirrorComponent(), 0, 0, 0 ); + } + + public HaunterMirrorAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class HaunterMirrorDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new HaunterMirrorAddon(); } } + public override int LabelNumber { get { return 1074800; } } // Haunted Mirror + + [Constructable] + public HaunterMirrorDeed() : base() + { + LootType = LootType.Blessed; + } + + public HaunterMirrorDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs new file mode 100644 index 0000000..f20ca97 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieBlue.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A75, 0x2A76 )] + public class MountedPixieBlueComponent : AddonComponent + { + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + public MountedPixieBlueComponent() : base( 0x2A75 ) + { + } + + public MountedPixieBlueComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x55C, 0x55E ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieBlueAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new MountedPixieBlueDeed(); } } + + public MountedPixieBlueAddon() : base() + { + AddComponent( new MountedPixieBlueComponent(), 0, 0, 0 ); + } + + public MountedPixieBlueAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieBlueDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new MountedPixieBlueAddon(); } } + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + [Constructable] + public MountedPixieBlueDeed() : base() + { + LootType = LootType.Blessed; + } + + public MountedPixieBlueDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs new file mode 100644 index 0000000..7f51a32 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieGreen.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A71, 0x2A72 )] + public class MountedPixieGreenComponent : AddonComponent + { + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + public MountedPixieGreenComponent() : base( 0x2A71 ) + { + } + + public MountedPixieGreenComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x554, 0x557 ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieGreenAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new MountedPixieGreenDeed(); } } + + public MountedPixieGreenAddon() : base() + { + AddComponent( new MountedPixieGreenComponent(), 0, 0, 0 ); + } + + public MountedPixieGreenAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieGreenDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new MountedPixieGreenAddon(); } } + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + [Constructable] + public MountedPixieGreenDeed() : base() + { + LootType = LootType.Blessed; + } + + public MountedPixieGreenDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs new file mode 100644 index 0000000..3cd6361 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieLime.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A77, 0x2A78 )] + public class MountedPixieLimeComponent : AddonComponent + { + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + public MountedPixieLimeComponent() : base( 0x2A77 ) + { + } + + public MountedPixieLimeComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x55F, 0x561 ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieLimeAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new MountedPixieLimeDeed(); } } + + public MountedPixieLimeAddon() : base() + { + AddComponent( new MountedPixieLimeComponent(), 0, 0, 0 ); + } + + public MountedPixieLimeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieLimeDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new MountedPixieLimeAddon(); } } + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + [Constructable] + public MountedPixieLimeDeed() : base() + { + LootType = LootType.Blessed; + } + + public MountedPixieLimeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs new file mode 100644 index 0000000..26efa26 --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieOrange.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A73, 0x2A74 )] + public class MountedPixieOrangeComponent : AddonComponent + { + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + public MountedPixieOrangeComponent() : base( 0x2A73 ) + { + } + + public MountedPixieOrangeComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x558, 0x55B ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieOrangeAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new MountedPixieOrangeDeed(); } } + + public MountedPixieOrangeAddon() : base() + { + AddComponent( new MountedPixieOrangeComponent(), 0, 0, 0 ); + } + + public MountedPixieOrangeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieOrangeDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new MountedPixieOrangeAddon(); } } + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + [Constructable] + public MountedPixieOrangeDeed() : base() + { + LootType = LootType.Blessed; + } + + public MountedPixieOrangeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs new file mode 100644 index 0000000..23154ac --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/MountedPixieWhite.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A79, 0x2A7A )] + public class MountedPixieWhiteComponent : AddonComponent + { + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + public MountedPixieWhiteComponent() : base( 0x2A79 ) + { + } + + public MountedPixieWhiteComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x562, 0x564 ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieWhiteAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new MountedPixieWhiteDeed(); } } + + public MountedPixieWhiteAddon() : base() + { + AddComponent( new MountedPixieWhiteComponent(), 0, 0, 0 ); + } + + public MountedPixieWhiteAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class MountedPixieWhiteDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new MountedPixieWhiteAddon(); } } + public override int LabelNumber { get { return 1074482; } } // Mounted pixie + + [Constructable] + public MountedPixieWhiteDeed() : base() + { + LootType = LootType.Blessed; + } + + public MountedPixieWhiteDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs b/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs new file mode 100644 index 0000000..f4b2c2f --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/SacrificialAltar.cs @@ -0,0 +1,164 @@ +using System; + +namespace Server.Items +{ + [FlipableAddon( Direction.South, Direction.East )] + public class SacrificialAltarAddon : BaseAddonContainer + { + public override BaseAddonContainerDeed Deed { get { return new SacrificialAltarDeed(); } } + public override int LabelNumber { get { return 1074818; } } // Sacrificial Altar + public override int DefaultMaxWeight { get { return 0; } } + public override int DefaultGumpID { get { return 0x107; } } + public override int DefaultDropSound { get { return 0x42; } } + + private Timer m_Timer; + + [Constructable] + public SacrificialAltarAddon() : base( 0x2A9B ) + { + Direction = Direction.South; + + AddComponent( new LocalizedContainerComponent( 0x2A9A, 1074818 ), 1, 0, 0 ); + } + + public SacrificialAltarAddon( Serial serial ) : base( serial ) + { + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( !base.OnDragDrop( from, dropped ) ) + return false; + + if ( TotalItems >= 50 ) + { + SendLocalizedMessageTo( from, 501478 ); // The trash is full! Emptying! + Empty(); + } + else + { + SendLocalizedMessageTo( from, 1010442 ); // The item will be deleted in three minutes + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), new TimerCallback( Empty ) ); + } + + return true; + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( !base.OnDragDropInto( from, item, p ) ) + return false; + + if ( TotalItems >= 50 ) + { + SendLocalizedMessageTo( from, 501478 ); // The trash is full! Emptying! + Empty(); + } + else + { + SendLocalizedMessageTo( from, 1010442 ); // The item will be deleted in three minutes + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), new TimerCallback( Empty ) ); + } + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + if ( Items.Count > 0 ) + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), new TimerCallback( Empty ) ); + } + + public virtual void Flip( Mobile from, Direction direction ) + { + switch ( direction ) + { + case Direction.East: + ItemID = 0x2A9C; + AddComponent( new LocalizedContainerComponent( 0x2A9D, 1074818 ), 0, -1, 0 ); + break; + case Direction.South: + ItemID = 0x2A9B; + AddComponent( new LocalizedContainerComponent( 0x2A9A, 1074818 ), 1, 0, 0 ); + break; + } + } + + public virtual void Empty() + { + if ( Items.Count > 0 ) + { + Point3D location = Location; + location.Z += 10; + + Effects.SendLocationEffect( location, Map, 0x3709, 10, 10, 0x356, 0 ); + Effects.PlaySound( location, Map, 0x32E ); + + if ( Items.Count > 0 ) + { + for ( int i = Items.Count - 1; i >= 0; --i ) + { + if ( i >= Items.Count ) + continue; + + Items[ i ].Delete(); + } + } + } + + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + } + + public class SacrificialAltarDeed : BaseAddonContainerDeed + { + public override BaseAddonContainer Addon { get { return new SacrificialAltarAddon(); } } + public override int LabelNumber { get { return 1074818; } } // Sacrificial Altar + + [Constructable] + public SacrificialAltarDeed() : base() + { + LootType = LootType.Blessed; + } + + public SacrificialAltarDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs b/Scripts/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs new file mode 100644 index 0000000..1edfb6d --- /dev/null +++ b/Scripts/Items/Special/Evil Home Decor Collection/UnsettlingPortrait.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2A65, 0x2A67 )] + public class UnsettlingPortraitComponent : AddonComponent + { + public override int LabelNumber { get { return 1074480; } } // Unsettling portrait + + private Timer m_Timer; + + public UnsettlingPortraitComponent() : base( 0x2A65 ) + { + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), TimeSpan.FromMinutes( 3 ), new TimerCallback( ChangeDirection ) ); + } + + public UnsettlingPortraitComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Utility.InRange( Location, from.Location, 2 ) ) + Effects.PlaySound( Location, Map, Utility.RandomMinMax( 0x567, 0x568 ) ); + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Timer = Timer.DelayCall( TimeSpan.FromMinutes( 3 ), TimeSpan.FromMinutes( 3 ), new TimerCallback( ChangeDirection ) ); + } + + private void ChangeDirection() + { + if ( ItemID == 0x2A65 ) + ItemID += 1; + else if ( ItemID == 0x2A66 ) + ItemID -= 1; + else if ( ItemID == 0x2A67 ) + ItemID += 1; + else if ( ItemID == 0x2A68 ) + ItemID -= 1; + } + } + + public class UnsettlingPortraitAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new UnsettlingPortraitDeed(); } } + + [Constructable] + public UnsettlingPortraitAddon() : base() + { + AddComponent( new UnsettlingPortraitComponent(), 0, 0, 0 ); + } + + public UnsettlingPortraitAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class UnsettlingPortraitDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new UnsettlingPortraitAddon(); } } + public override int LabelNumber { get { return 1074480; } } // Unsettling portrait + + [Constructable] + public UnsettlingPortraitDeed() : base() + { + LootType = LootType.Blessed; + } + + public UnsettlingPortraitDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Gifts/HearthOfHomeFire.cs b/Scripts/Items/Special/Gifts/HearthOfHomeFire.cs new file mode 100644 index 0000000..f1e8022 --- /dev/null +++ b/Scripts/Items/Special/Gifts/HearthOfHomeFire.cs @@ -0,0 +1,132 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HearthOfHomeFire : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new HearthOfHomeFireDeed(); } } + + [Constructable] + public HearthOfHomeFire( bool east ) + { + if ( east ) + { + AddLightComponent( new AddonComponent( 0x2352 ), 0, 0, 0 ); + AddLightComponent( new AddonComponent( 0x2358 ), 0, -1, 0 ); + } + else + { + AddLightComponent( new AddonComponent( 0x2360 ), 0, 0, 0 ); + AddLightComponent( new AddonComponent( 0x2366 ), -1, 0, 0 ); + } + } + + private void AddLightComponent( AddonComponent component, int x, int y, int z ) + { + component.Light = LightType.Circle150; + + AddComponent( component, x, y, z ); + } + + public HearthOfHomeFire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class HearthOfHomeFireDeed : BaseAddonDeed + { + private bool m_East; + + public override BaseAddon Addon{ get{ return new HearthOfHomeFire( m_East ); } } + + public override int LabelNumber{ get{ return 1062919; } } // Hearth of the Home Fire + + [Constructable] + public HearthOfHomeFireDeed() + { + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + private class InternalGump : Gump + { + private HearthOfHomeFireDeed m_Deed; + + public InternalGump( HearthOfHomeFireDeed deed ) : base( 150, 50 ) + { + m_Deed = deed; + + AddBackground( 0, 0, 350, 250, 0xA28 ); + + AddItem( 90, 52, 0x2367 ); + AddItem( 112, 35, 0x2360 ); + AddButton( 70, 35, 0x868, 0x869, 1, GumpButtonType.Reply, 0 ); // South + + AddItem( 220, 35, 0x2352 ); + AddItem( 242, 52, 0x2358 ); + AddButton( 185, 35, 0x868, 0x869, 2, GumpButtonType.Reply, 0 ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = (info.ButtonID != 1); + m_Deed.SendTarget( sender.Mobile ); + } + } + + public HearthOfHomeFireDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Gifts/HolySword.cs b/Scripts/Items/Special/Gifts/HolySword.cs new file mode 100644 index 0000000..3f3184f --- /dev/null +++ b/Scripts/Items/Special/Gifts/HolySword.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HolySword : Longsword + { + public override int LabelNumber{ get{ return 1062921; } } // The Holy Sword + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public HolySword() + { + Hue = 0x482; + LootType = LootType.Blessed; + + Slayer = SlayerName.Silver; + + Attributes.WeaponDamage = 40; + WeaponAttributes.SelfRepair = 10; + WeaponAttributes.LowerStatReq = 100; + WeaponAttributes.UseBestSkill = 1; + } + + public HolySword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Gifts/LeggingsOfEmbers.cs b/Scripts/Items/Special/Gifts/LeggingsOfEmbers.cs new file mode 100644 index 0000000..8ef404f --- /dev/null +++ b/Scripts/Items/Special/Gifts/LeggingsOfEmbers.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LeggingsOfEmbers : PlateLegs + { + public override int LabelNumber{ get{ return 1062911; } } // Royal Leggings of Embers + + public override int BasePhysicalResistance{ get{ return 15; } } + public override int BaseFireResistance{ get{ return 25; } } + public override int BaseColdResistance{ get{ return 0; } } + public override int BasePoisonResistance{ get{ return 15; } } + public override int BaseEnergyResistance{ get{ return 15; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public LeggingsOfEmbers() + { + Hue = 0x2C; + LootType = LootType.Blessed; + + ArmorAttributes.SelfRepair = 10; + ArmorAttributes.MageArmor = 1; + ArmorAttributes.LowerStatReq = 100; + } + + public LeggingsOfEmbers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Gifts/RoseOfTrinsic.cs b/Scripts/Items/Special/Gifts/RoseOfTrinsic.cs new file mode 100644 index 0000000..888b67c --- /dev/null +++ b/Scripts/Items/Special/Gifts/RoseOfTrinsic.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Gumps; +using Server.Multis; +using Server.ContextMenus; + +namespace Server.Items +{ + [FlipableAttribute( 0x234C, 0x234D )] + public class RoseOfTrinsic : Item, ISecurable + { + private static readonly TimeSpan m_SpawnTime = TimeSpan.FromHours( 4.0 ); + + private int m_Petals; + private DateTime m_NextSpawnTime; + private SpawnTimer m_SpawnTimer; + + private SecureLevel m_Level; + + public override int LabelNumber{ get{ return 1062913; } } // Rose of Trinsic + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Petals + { + get{ return m_Petals; } + set + { + if ( value >= 10 ) + { + m_Petals = 10; + + StopSpawnTimer(); + } + else + { + if ( value <= 0 ) + m_Petals = 0; + else + m_Petals = value; + + StartSpawnTimer( m_SpawnTime ); + } + + InvalidateProperties(); + } + } + + [Constructable] + public RoseOfTrinsic() : base( 0x234D ) + { + Weight = 1.0; + LootType = LootType.Blessed; + + m_Petals = 0; + StartSpawnTimer( TimeSpan.FromMinutes( 1.0 ) ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1062925, Petals.ToString() ); // Petals: ~1_COUNT~ + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + SetSecureLevelEntry.AddTo( from, this, list ); + } + + private void StartSpawnTimer( TimeSpan delay ) + { + StopSpawnTimer(); + + m_SpawnTimer = new SpawnTimer( this, delay ); + m_SpawnTimer.Start(); + + m_NextSpawnTime = DateTime.Now + delay; + } + + private void StopSpawnTimer() + { + if ( m_SpawnTimer != null ) + { + m_SpawnTimer.Stop(); + m_SpawnTimer = null; + } + } + + private class SpawnTimer : Timer + { + private RoseOfTrinsic m_Rose; + + public SpawnTimer( RoseOfTrinsic rose, TimeSpan delay ) : base( delay ) + { + m_Rose = rose; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + if ( m_Rose.Deleted ) + return; + + m_Rose.m_SpawnTimer = null; + m_Rose.Petals++; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + else if ( Petals > 0 ) + { + from.AddToBackpack( new RoseOfTrinsicPetal( Petals ) ); + Petals = 0; + } + } + + public RoseOfTrinsic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Petals ); + writer.WriteDeltaTime( (DateTime) m_NextSpawnTime ); + writer.WriteEncodedInt( (int) m_Level ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Petals = reader.ReadEncodedInt(); + m_NextSpawnTime = reader.ReadDeltaTime(); + m_Level = (SecureLevel) reader.ReadEncodedInt(); + + if ( m_Petals < 10 ) + StartSpawnTimer( m_NextSpawnTime - DateTime.Now ); + } + } + + public class RoseOfTrinsicPetal : Item + { + public override int LabelNumber{ get{ return 1062926; } } // Petal of the Rose of Trinsic + + [Constructable] + public RoseOfTrinsicPetal() : this( 1 ) + { + } + + [Constructable] + public RoseOfTrinsicPetal( int amount ) : base( 0x1021 ) + { + Stackable = true; + Amount = amount; + + Weight = 1.0; + Hue = 0xE; + } + + + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + else if ( from.GetStatMod( "RoseOfTrinsicPetal" ) != null ) + { + from.SendLocalizedMessage( 1062927 ); // You have eaten one of these recently and eating another would provide no benefit. + } + else + { + from.PlaySound( 0x1EE ); + from.AddStatMod( new StatMod( StatType.Str, "RoseOfTrinsicPetal", 5, TimeSpan.FromMinutes( 5.0 ) ) ); + + Consume(); + } + } + + public RoseOfTrinsicPetal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Gifts/SamuraiHelm.cs b/Scripts/Items/Special/Gifts/SamuraiHelm.cs new file mode 100644 index 0000000..4353eef --- /dev/null +++ b/Scripts/Items/Special/Gifts/SamuraiHelm.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + [FlipableAttribute( 0x236C, 0x236D )] + public class SamuraiHelm : BaseArmor + { + public override int LabelNumber{ get{ return 1062923; } } // Ancient Samurai Helm + + public override int BasePhysicalResistance{ get{ return 15; } } + public override int BaseFireResistance{ get{ return 10; } } + public override int BaseColdResistance{ get{ return 10; } } + public override int BasePoisonResistance{ get{ return 15; } } + public override int BaseEnergyResistance{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + public override ArmorMaterialType MaterialType{ get{ return ArmorMaterialType.Plate; } } + + [Constructable] + public SamuraiHelm() : base( 0x236C ) + { + Weight = 5.0; + LootType = LootType.Blessed; + + Attributes.DefendChance = 15; + ArmorAttributes.SelfRepair = 10; + ArmorAttributes.LowerStatReq = 100; + ArmorAttributes.MageArmor = 1; + } + + public SamuraiHelm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Gifts/ShaminoCrossbow.cs b/Scripts/Items/Special/Gifts/ShaminoCrossbow.cs new file mode 100644 index 0000000..654d0fc --- /dev/null +++ b/Scripts/Items/Special/Gifts/ShaminoCrossbow.cs @@ -0,0 +1,43 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ShaminoCrossbow : RepeatingCrossbow + { + public override int LabelNumber{ get{ return 1062915; } } // Shamino�s Best Crossbow + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ShaminoCrossbow() + { + Hue = 0x504; + LootType = LootType.Blessed; + + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 40; + WeaponAttributes.SelfRepair = 10; + WeaponAttributes.LowerStatReq = 100; + } + + public ShaminoCrossbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Gifts/TapestryOfSosaria.cs b/Scripts/Items/Special/Gifts/TapestryOfSosaria.cs new file mode 100644 index 0000000..1bf377f --- /dev/null +++ b/Scripts/Items/Special/Gifts/TapestryOfSosaria.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Multis; +using Server.ContextMenus; + +namespace Server.Items +{ + [FlipableAttribute( 0x234E, 0x234F )] + public class TapestryOfSosaria : Item, ISecurable + { + private SecureLevel m_Level; + + public override int LabelNumber{ get{ return 1062917; } } // The Tapestry of Sosaria + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + [Constructable] + public TapestryOfSosaria() : base( 0x234E ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump() ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + + private class InternalGump : Gump + { + public InternalGump() : base( 50, 50 ) + { + AddImage( 0, 0, 0x2C95 ); + } + } + + public TapestryOfSosaria( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Level ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Level = (SecureLevel) reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Heritage Items/AppleTrunk.cs b/Scripts/Items/Special/Heritage Items/AppleTrunk.cs new file mode 100644 index 0000000..ae538e2 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/AppleTrunk.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class AppleTrunkAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new AppleTrunkDeed(); } } + + [Constructable] + public AppleTrunkAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xD98, 1076785 ), 0, 0, 0 ); + } + + public AppleTrunkAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class AppleTrunkDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new AppleTrunkAddon(); } } + public override int LabelNumber { get { return 1076785; } } // Apple Trunk + + [Constructable] + public AppleTrunkDeed() : base() + { + LootType = LootType.Blessed; + } + + public AppleTrunkDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/BlueDecorativeRug.cs b/Scripts/Items/Special/Heritage Items/BlueDecorativeRug.cs new file mode 100644 index 0000000..5fa75d7 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/BlueDecorativeRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class BlueDecorativeRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BlueDecorativeRugDeed(); } } + + [Constructable] + public BlueDecorativeRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xAD2, 1076589 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD3, 1076589 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD4, 1076589 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD5, 1076589 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD6, 1076589 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD7, 1076589 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD8, 1076589 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD9, 1076589 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD1, 1076589 ), 0, 0, 0 ); + } + + public BlueDecorativeRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BlueDecorativeRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BlueDecorativeRugAddon(); } } + public override int LabelNumber { get { return 1076589; } } // Blue decorative rug + + [Constructable] + public BlueDecorativeRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public BlueDecorativeRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/BlueFancyRug.cs b/Scripts/Items/Special/Heritage Items/BlueFancyRug.cs new file mode 100644 index 0000000..bffdc82 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/BlueFancyRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class BlueFancyRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BlueFancyRugDeed(); } } + + [Constructable] + public BlueFancyRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xAC2, 1076273 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC3, 1076273 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC4, 1076273 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC5, 1076273 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF6, 1076273 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF7, 1076273 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF8, 1076273 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF9, 1076273 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAFA, 1076273 ), 0, 0, 0 ); + } + + public BlueFancyRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BlueFancyRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BlueFancyRugAddon(); } } + public override int LabelNumber { get { return 1076273; } } // Blue fancy rug + + [Constructable] + public BlueFancyRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public BlueFancyRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/BluePlainRug.cs b/Scripts/Items/Special/Heritage Items/BluePlainRug.cs new file mode 100644 index 0000000..862fcc9 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/BluePlainRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class BluePlainRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new BluePlainRugDeed(); } } + + [Constructable] + public BluePlainRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xAC2, 1076585 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC3, 1076585 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC4, 1076585 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC5, 1076585 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF6, 1076585 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF7, 1076585 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF8, 1076585 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF9, 1076585 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC0, 1076585 ), 0, 0, 0 ); + } + + public BluePlainRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BluePlainRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new BluePlainRugAddon(); } } + public override int LabelNumber { get { return 1076585; } } // Blue plain rug + + [Constructable] + public BluePlainRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public BluePlainRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/BoilingCauldron.cs b/Scripts/Items/Special/Heritage Items/BoilingCauldron.cs new file mode 100644 index 0000000..cab7e86 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/BoilingCauldron.cs @@ -0,0 +1,68 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x2068, 0x207A )] + public class BoilingCauldronAddon : BaseAddonContainer + { + public override BaseAddonContainerDeed Deed { get { return new BoilingCauldronDeed(); } } + public override int LabelNumber { get { return 1076267; } } // Boiling Cauldron + public override int DefaultGumpID { get { return 0x9; } } + public override int DefaultDropSound { get { return 0x42; } } + + [Constructable] + public BoilingCauldronAddon() : base( 0x2068 ) + { + AddComponent( new LocalizedContainerComponent( 0xFAC, 1076267 ), 0, 0, 0 ); + AddComponent( new LocalizedContainerComponent( 0x970, 1076267 ), 0, 0, 8 ); + } + + public BoilingCauldronAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BoilingCauldronDeed : BaseAddonContainerDeed + { + public override BaseAddonContainer Addon { get { return new BoilingCauldronAddon(); } } + public override int LabelNumber { get { return 1076267; } } // Boiling Cauldron + + [Constructable] + public BoilingCauldronDeed() : base() + { + LootType = LootType.Blessed; + } + + public BoilingCauldronDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/CherryBlossomTree.cs b/Scripts/Items/Special/Heritage Items/CherryBlossomTree.cs new file mode 100644 index 0000000..fd25781 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/CherryBlossomTree.cs @@ -0,0 +1,64 @@ +using System; + +namespace Server.Items +{ + public class CherryBlossomTreeAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new CherryBlossomTreeDeed(); } } + + [Constructable] + public CherryBlossomTreeAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x26EE, 1076268 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3122, 1076268 ), 0, 0, 0 ); + } + + public CherryBlossomTreeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class CherryBlossomTreeDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new CherryBlossomTreeAddon(); } } + public override int LabelNumber { get { return 1076268; } } // Cherry Blossom Tree + + [Constructable] + public CherryBlossomTreeDeed() : base() + { + LootType = LootType.Blessed; + } + + public CherryBlossomTreeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/CherryBlossomTrunk.cs b/Scripts/Items/Special/Heritage Items/CherryBlossomTrunk.cs new file mode 100644 index 0000000..baeb7a9 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/CherryBlossomTrunk.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class CherryBlossomTrunkAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new CherryBlossomTrunkDeed(); } } + + [Constructable] + public CherryBlossomTrunkAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x26EE, 1076784 ), 0, 0, 0 ); + } + + public CherryBlossomTrunkAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class CherryBlossomTrunkDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new CherryBlossomTrunkAddon(); } } + public override int LabelNumber { get { return 1076784; } } // Cherry Blossom Trunk + + [Constructable] + public CherryBlossomTrunkDeed() : base() + { + LootType = LootType.Blessed; + } + + public CherryBlossomTrunkDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/CinnamonFancyRug.cs b/Scripts/Items/Special/Heritage Items/CinnamonFancyRug.cs new file mode 100644 index 0000000..6267014 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/CinnamonFancyRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class CinnamonFancyRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new CinnamonFancyRugDeed(); } } + + [Constructable] + public CinnamonFancyRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xAE3, 1076587 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE4, 1076587 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE5, 1076587 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE6, 1076587 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE7, 1076587 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE8, 1076587 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE9, 1076587 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAEA, 1076587 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAEB, 1076587 ), 0, 0, 0 ); + } + + public CinnamonFancyRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class CinnamonFancyRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new CinnamonFancyRugAddon(); } } + public override int LabelNumber { get { return 1076587; } } // Cinnamon fancy rug + + [Constructable] + public CinnamonFancyRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public CinnamonFancyRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/Curtains.cs b/Scripts/Items/Special/Heritage Items/Curtains.cs new file mode 100644 index 0000000..41cb974 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/Curtains.cs @@ -0,0 +1,213 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class CurtainsComponent : AddonComponent, IDyable + { + public override int LabelNumber { get { return 1076280; } } // Curtains + public override bool DisplayWeight { get { return false; } } + + private int m_ClosedID; + + [CommandProperty( AccessLevel.GameMaster )] + public int ClosedID + { + get { return m_ClosedID; } + set { m_ClosedID = value; } + } + + public CurtainsComponent( int itemID, int closedID ) : base( itemID ) + { + m_ClosedID = closedID; + } + + public CurtainsComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + base.OnDoubleClick( from ); + + if ( Addon != null ) + { + if ( from.InRange( Location, 1 ) ) + { + foreach ( AddonComponent c in Addon.Components ) + { + if ( c is CurtainsComponent ) + { + CurtainsComponent curtain = (CurtainsComponent) c; + + int temp = curtain.ItemID; + curtain.ItemID = curtain.ClosedID; + curtain.ClosedID = temp; + } + } + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_ClosedID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_ClosedID = reader.ReadInt(); + } + + #region IDyable + public virtual bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + return true; + } + #endregion + } + + public class CurtainsAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new CurtainsDeed(); } } + public override bool RetainDeedHue { get { return true; } } + + [Constructable] + public CurtainsAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new CurtainsComponent( 0x3D9E, 0x3DA8 ), 0, -1, 0 ); + AddComponent( new CurtainsComponent( 0x3DAC, 0x3DAE ), 0, 0, 0 ); + AddComponent( new CurtainsComponent( 0x3DA0, 0x3DA6 ), 0, 2, 0 ); + AddComponent( new CurtainsComponent( 0x3D9F, 0x3DA7 ), 0, 1, 0 ); + } + else // south + { + AddComponent( new CurtainsComponent( 0x3D9C, 0x3DAD ), 0, 0, 0 ); + AddComponent( new CurtainsComponent( 0x3D9D, 0x3DA3 ), -1, 0, 0 ); + AddComponent( new CurtainsComponent( 0x3DA1, 0x3DA5 ), 2, 0, 0 ); + AddComponent( new CurtainsComponent( 0x3DAB, 0x3DA4 ), 1, 0, 0 ); + } + } + + public CurtainsAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class CurtainsDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new CurtainsAddon( m_East ); } } + public override int LabelNumber { get { return 1076280; } } // Curtains + + private bool m_East; + + [Constructable] + public CurtainsDeed() : base() + { + LootType = LootType.Blessed; + } + + public CurtainsDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private CurtainsDeed m_Deed; + + public InternalGump( CurtainsDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076581, 0x7FFF, false, false ); // Please select your curtain position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/Fountain.cs b/Scripts/Items/Special/Heritage Items/Fountain.cs new file mode 100644 index 0000000..02ff151 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/Fountain.cs @@ -0,0 +1,62 @@ +using System; + +namespace Server.Items +{ + public class FountainAddon : StoneFountainAddon + { + public override BaseAddonDeed Deed { get { return new FountainDeed(); } } + + [Constructable] + public FountainAddon() : base() + { + } + + public FountainAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class FountainDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new FountainAddon(); } } + public override int LabelNumber { get { return 1076283; } } // Fountain + + [Constructable] + public FountainDeed() : base() + { + LootType = LootType.Blessed; + } + + public FountainDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/FruitTrees.cs b/Scripts/Items/Special/Heritage Items/FruitTrees.cs new file mode 100644 index 0000000..b835e80 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/FruitTrees.cs @@ -0,0 +1,215 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public abstract class BaseFruitTreeAddon : BaseAddon + { + public override abstract BaseAddonDeed Deed { get; } + public abstract Item Fruit { get; } + + private int m_Fruits; + + [CommandProperty( AccessLevel.GameMaster )] + public int Fruits + { + get { return m_Fruits; } + set + { + if ( value < 0 ) + m_Fruits = 0; + else + m_Fruits = value; + } + } + + public BaseFruitTreeAddon() : base() + { + Timer.DelayCall( TimeSpan.FromMinutes( 5 ), new TimerCallback( Respawn ) ); + } + + public BaseFruitTreeAddon( Serial serial ) : base( serial ) + { + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + if ( from.InRange( c.Location, 2 ) ) + { + if ( m_Fruits > 0 ) + { + Item fruit = Fruit; + + if ( fruit == null ) + return; + + if ( !from.PlaceInBackpack( fruit ) ) + { + fruit.Delete(); + from.SendLocalizedMessage( 501015 ); // There is no room in your backpack for the fruit. + } + else + { + if ( --m_Fruits == 0 ) + Timer.DelayCall( TimeSpan.FromMinutes( 30 ), new TimerCallback( Respawn ) ); + + from.SendLocalizedMessage( 501016 ); // You pick some fruit and put it in your backpack. + } + } + else + from.SendLocalizedMessage( 501017 ); // There is no more fruit on this tree + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + private void Respawn() + { + m_Fruits = Utility.RandomMinMax( 1, 4 ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_Fruits ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Fruits = reader.ReadInt(); + + if ( m_Fruits == 0 ) + Respawn(); + } + } + + public class AppleTreeAddon : BaseFruitTreeAddon + { + public override BaseAddonDeed Deed { get { return new AppleTreeDeed(); } } + public override Item Fruit { get { return new Apple(); } } + + [Constructable] + public AppleTreeAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xD98, 1076269 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3124, 1076269 ), 0, 0, 0 ); + } + + public AppleTreeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class AppleTreeDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new AppleTreeAddon(); } } + public override int LabelNumber { get { return 1076269; } } // Apple Tree + + [Constructable] + public AppleTreeDeed() : base() + { + LootType = LootType.Blessed; + } + + public AppleTreeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PeachTreeAddon : BaseFruitTreeAddon + { + public override BaseAddonDeed Deed { get { return new PeachTreeDeed(); } } + public override Item Fruit { get { return new Peach(); } } + + [Constructable] + public PeachTreeAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xD9C, 1076270 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3123, 1076270 ), 0, 0, 0 ); + } + + public PeachTreeAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PeachTreeDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new PeachTreeAddon(); } } + public override int LabelNumber { get { return 1076270; } } // Peach Tree + + [Constructable] + public PeachTreeDeed() : base() + { + LootType = LootType.Blessed; + } + + public PeachTreeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/GoldenDecorativeRug.cs b/Scripts/Items/Special/Heritage Items/GoldenDecorativeRug.cs new file mode 100644 index 0000000..aad21a6 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/GoldenDecorativeRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class GoldenDecorativeRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new GoldenDecorativeRugDeed(); } } + + [Constructable] + public GoldenDecorativeRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xADB, 1076586 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xADC, 1076586 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xADD, 1076586 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xADE, 1076586 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xADF, 1076586 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE0, 1076586 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE1, 1076586 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAE2, 1076586 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xADA, 1076586 ), 0, 0, 0 ); + } + + public GoldenDecorativeRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class GoldenDecorativeRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new GoldenDecorativeRugAddon(); } } + public override int LabelNumber { get { return 1076586; } } // Golden decorative rug + + [Constructable] + public GoldenDecorativeRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public GoldenDecorativeRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/Guillotine.cs b/Scripts/Items/Special/Heritage Items/Guillotine.cs new file mode 100644 index 0000000..4f15b97 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/Guillotine.cs @@ -0,0 +1,177 @@ +using System; +using Server; +using Server.Spells; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x125E, 0x1230 )] + public class GuillotineComponent : AddonComponent + { + public override int LabelNumber { get { return 1024656; } } // Guillotine + + public GuillotineComponent() : base( 0x125E ) + { + } + + public GuillotineComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + + public class GuillotineAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new GuillotineDeed(); } } + + [Constructable] + public GuillotineAddon() : base() + { + AddComponent( new GuillotineComponent(), 0, 0, 0 ); + } + + public GuillotineAddon( Serial serial ) : base( serial ) + { + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + if ( Utility.RandomBool() ) + { + from.Location = Location; + + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), new TimerStateCallback( Activate ), new object[] { c, from } ); + } + else + from.LocalOverheadMessage( MessageType.Regular, 0, 501777 ); // Hmm... you suspect that if you used this again, it might hurt. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private void Activate( object obj ) + { + object[] param = (object[]) obj; + + if ( param[ 0 ] is AddonComponent && param[ 1 ] is Mobile ) + Activate( (AddonComponent) param[ 0 ], (Mobile) param[ 1 ] ); + } + + public virtual void Activate( AddonComponent c, Mobile from ) + { + if (c.ItemID == 0x125E || c.ItemID == 0x1269 || c.ItemID == 0x1260) + c.ItemID = 0x1269; + else + c.ItemID = 0x1247; + + // blood + int amount = Utility.RandomMinMax( 3, 7 ); + + for ( int i = 0; i < amount; i++ ) + { + int x = c.X + Utility.RandomMinMax( -1, 1 ); + int y = c.Y + Utility.RandomMinMax( -1, 1 ); + int z = c.Z; + + if ( !c.Map.CanFit( x, y, z, 1, false, false, true ) ) + { + z = c.Map.GetAverageZ( x, y ); + + if ( !c.Map.CanFit( x, y, z, 1, false, false, true ) ) + continue; + } + + Blood blood = new Blood( Utility.RandomMinMax( 0x122C, 0x122F ) ); + blood.MoveToWorld( new Point3D( x, y, z ), c.Map ); + } + + if ( from.Female ) + from.PlaySound( Utility.RandomMinMax( 0x150, 0x153 ) ); + else + from.PlaySound( Utility.RandomMinMax( 0x15A, 0x15D ) ); + + from.LocalOverheadMessage( MessageType.Regular, 0, 501777 ); // Hmm... you suspect that if you used this again, it might hurt. + SpellHelper.Damage( TimeSpan.Zero, from, Utility.Dice( 2, 10, 5 ) ); + + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 2, new TimerStateCallback( Deactivate ), c ); + } + + private void Deactivate( object obj ) + { + if ( obj is AddonComponent ) + { + AddonComponent c = (AddonComponent) obj; + + if ( c.ItemID == 0x1269 ) + c.ItemID = 0x1260; + else if ( c.ItemID == 0x1260 ) + c.ItemID = 0x125E; + else if ( c.ItemID == 0x1247 ) + c.ItemID = 0x1246; + else if ( c.ItemID == 0x1246 ) + c.ItemID = 0x1230; + } + } + } + + + public class GuillotineDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new GuillotineAddon(); } } + public override int LabelNumber { get { return 1024656; } } // Guillotine + + [Constructable] + public GuillotineDeed() : base() + { + LootType = LootType.Blessed; + } + + public GuillotineDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/HangingAxes.cs b/Scripts/Items/Special/Heritage Items/HangingAxes.cs new file mode 100644 index 0000000..102bbb2 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/HangingAxes.cs @@ -0,0 +1,130 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HangingAxesAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new HangingAxesDeed(); } } + + [Constructable] + public HangingAxesAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new LocalizedAddonComponent( 0x156A, 1076271 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x156B, 1076271 ), 0, -1, 0 ); + } + else // south + { + AddComponent( new LocalizedAddonComponent( 0x1568, 1076271 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1569, 1076271 ), 1, 0, 0 ); + } + } + + public HangingAxesAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class HangingAxesDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new HangingAxesAddon( m_East ); } } + public override int LabelNumber { get { return 1076271; } } // Hanging Axes + + private bool m_East; + + [Constructable] + public HangingAxesDeed() : base() + { + LootType = LootType.Blessed; + } + + public HangingAxesDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private HangingAxesDeed m_Deed; + + public InternalGump( HangingAxesDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076745, 0x7FFF, false, false ); // Please select your hanging axe position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/HangingSwords.cs b/Scripts/Items/Special/Heritage Items/HangingSwords.cs new file mode 100644 index 0000000..a19a66f --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/HangingSwords.cs @@ -0,0 +1,130 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HangingSwordsAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new HangingSwordsDeed(); } } + + [Constructable] + public HangingSwordsAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new LocalizedAddonComponent( 0x1566, 1076272 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1567, 1076272 ), 0, -1, 0 ); + } + else // south + { + AddComponent( new LocalizedAddonComponent( 0x1564, 1076272 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1565, 1076272 ), 1, 0, 0 ); + } + } + + public HangingSwordsAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class HangingSwordsDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new HangingSwordsAddon( m_East ); } } + public override int LabelNumber { get { return 1076272; } } // Hanging Swords + + private bool m_East; + + [Constructable] + public HangingSwordsDeed() : base() + { + LootType = LootType.Blessed; + } + + public HangingSwordsDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private HangingSwordsDeed m_Deed; + + public InternalGump( HangingSwordsDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076746, 0x7FFF, false, false ); // Please select your hanging sword position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/HouseLadder.cs b/Scripts/Items/Special/Heritage Items/HouseLadder.cs new file mode 100644 index 0000000..3269c70 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/HouseLadder.cs @@ -0,0 +1,170 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HouseLadderAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new HouseLadderDeed(); } } + + [Constructable] + public HouseLadderAddon( int type ) : base() + { + switch ( type ) + { + case 0: // castle south + AddComponent( new LocalizedAddonComponent( 0x3DB2, 1076791 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3F28, 1076791 ), 0, 1, 28 ); + AddComponent( new LocalizedAddonComponent( 0x3DB4, 1076791 ), 0, 2, 20 ); + break; + case 1: // castle east + AddComponent( new LocalizedAddonComponent( 0x3DB3, 1076791 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3F28, 1076791 ), 1, 0, 28 ); + AddComponent( new LocalizedAddonComponent( 0x3DB5, 1076791 ), 2, 0, 20 ); + break; + case 2: // castle north + AddComponent( new LocalizedAddonComponent( 0x2FDF, 1076791 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3F28, 1076791 ), 0, -1, 28 ); + AddComponent( new LocalizedAddonComponent( 0x3DB6, 1076791 ), 0, -2, 20 ); + break; + case 3: // castle west + AddComponent( new LocalizedAddonComponent( 0x2FDE, 1076791 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x3F28, 1076791 ), -1, 0, 28 ); + AddComponent( new LocalizedAddonComponent( 0x3DB7, 1076791 ), -2, 0, 20 ); + break; + case 4: // south + AddComponent( new LocalizedAddonComponent( 0x3DB2, 1076287 ), 0, 0, 0 ); + break; + case 5: // east + AddComponent( new LocalizedAddonComponent( 0x3DB3, 1076287 ), 0, 0, 0 ); + break; + case 6: // north + AddComponent( new LocalizedAddonComponent( 0x2FDF, 1076287 ), 0, 0, 0 ); + break; + case 7: // west + AddComponent( new LocalizedAddonComponent( 0x2FDE, 1076287 ), 0, 0, 0 ); + break; + } + } + + public HouseLadderAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class HouseLadderDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new HouseLadderAddon( m_Type ); } } + public override int LabelNumber { get { return 1076287; } } // Ladder + + private int m_Type; + + [Constructable] + public HouseLadderDeed() : base() + { + LootType = LootType.Blessed; + } + + public HouseLadderDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private HouseLadderDeed m_Deed; + + public InternalGump( HouseLadderDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076780, 0x7FFF, false, false ); // Please select your ladder position.
Use the ladders marked (castle)
for accessing the tops of keeps
and castles. + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1076794, 0x7FFF, false, false ); // South (Castle) + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1076795, 0x7FFF, false, false ); // East (Castle) + AddButton( 19, 97, 0x845, 0x846, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 95, 213, 20, 1076792, 0x7FFF, false, false ); // North (Castle) + AddButton( 19, 121, 0x845, 0x846, 4, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 119, 213, 20, 1076793, 0x7FFF, false, false ); // West (Castle) + AddButton( 19, 145, 0x845, 0x846, 5, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 143, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 169, 0x845, 0x846, 6, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 167, 213, 20, 1075387, 0x7FFF, false, false ); // East + AddButton( 19, 193, 0x845, 0x846, 7, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 191, 213, 20, 1075389, 0x7FFF, false, false ); // North + AddButton( 19, 217, 0x845, 0x846, 8, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 215, 213, 20, 1075390, 0x7FFF, false, false ); // West + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + if ( info.ButtonID >= 1 && info.ButtonID <= 8 ) + { + m_Deed.m_Type = info.ButtonID - 1; + m_Deed.SendTarget( sender.Mobile ); + } + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/IronMaiden.cs b/Scripts/Items/Special/Heritage Items/IronMaiden.cs new file mode 100644 index 0000000..5e9ac2d --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/IronMaiden.cs @@ -0,0 +1,137 @@ +using System; +using Server; +using Server.Spells; +using Server.Network; + +namespace Server.Items +{ + public class IronMaidenAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new IronMaidenDeed(); } } + + [Constructable] + public IronMaidenAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x1249, 1076288 ), 0, 0, 0 ); + } + + public IronMaidenAddon( Serial serial ) : base( serial ) + { + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + if ( Utility.RandomBool() ) + { + from.Location = Location; + c.ItemID = 0x124A; + + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ), 3, new TimerStateCallback( Activate ), new object[] { c, from } ); + } + else + from.LocalOverheadMessage( MessageType.Regular, 0, 501777 ); // Hmm... you suspect that if you used this again, it might hurt. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private void Activate( object obj ) + { + object[] param = (object[]) obj; + + if ( param[ 0 ] is AddonComponent && param[ 1 ] is Mobile ) + Activate( (AddonComponent) param[ 0 ], (Mobile) param[ 1 ] ); + } + + public virtual void Activate( AddonComponent c, Mobile from ) + { + c.ItemID += 1; + + if ( c.ItemID >= 0x124D ) + { + // blood + int amount = Utility.RandomMinMax( 3, 7 ); + + for ( int i = 0; i < amount; i++ ) + { + int x = c.X + Utility.RandomMinMax( -1, 1 ); + int y = c.Y + Utility.RandomMinMax( -1, 1 ); + int z = c.Z; + + if ( !c.Map.CanFit( x, y, z, 1, false, false, true ) ) + { + z = c.Map.GetAverageZ( x, y ); + + if ( !c.Map.CanFit( x, y, z, 1, false, false, true ) ) + continue; + } + + Blood blood = new Blood( Utility.RandomMinMax( 0x122C, 0x122F ) ); + blood.MoveToWorld( new Point3D( x, y, z ), c.Map ); + } + + if ( from.Female ) + from.PlaySound( Utility.RandomMinMax( 0x150, 0x153 ) ); + else + from.PlaySound( Utility.RandomMinMax( 0x15A, 0x15D ) ); + + from.LocalOverheadMessage( MessageType.Regular, 0, 501777 ); // Hmm... you suspect that if you used this again, it might hurt. + SpellHelper.Damage( TimeSpan.Zero, from, Utility.Dice( 2, 10, 5 ) ); + + Timer.DelayCall( TimeSpan.FromSeconds( 1 ), new TimerStateCallback( Deactivate ), c ); + } + } + + private void Deactivate( object obj ) + { + if ( obj is AddonComponent ) + ( (AddonComponent) obj ).ItemID = 0x1249; + } + } + + public class IronMaidenDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new IronMaidenAddon(); } } + public override int LabelNumber { get { return 1076288; } } // Iron Maiden + + [Constructable] + public IronMaidenDeed() : base() + { + LootType = LootType.Blessed; + } + + public IronMaidenDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/LargeFishingNet.cs b/Scripts/Items/Special/Heritage Items/LargeFishingNet.cs new file mode 100644 index 0000000..c94033f --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/LargeFishingNet.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x3D8E, 0x3D8F )] + public class LargeFishingNetComponent : AddonComponent + { + public override int LabelNumber { get { return 1076285; } } // Large Fish Net + + public LargeFishingNetComponent() : base( 0x3D8E ) + { + } + + public LargeFishingNetComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LargeFishingNetAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new LargeFishingNetDeed(); } } + + [Constructable] + public LargeFishingNetAddon() : base() + { + AddComponent( new LargeFishingNetComponent(), 0, 0, 0 ); + } + + public LargeFishingNetAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class LargeFishingNetDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new LargeFishingNetAddon(); } } + public override int LabelNumber { get { return 1076285; } } // Large Fish Net + + [Constructable] + public LargeFishingNetDeed() : base() + { + LootType = LootType.Blessed; + } + + public LargeFishingNetDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/PeachTrunk.cs b/Scripts/Items/Special/Heritage Items/PeachTrunk.cs new file mode 100644 index 0000000..2e50ff0 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/PeachTrunk.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class PeachTrunkAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new PeachTrunkDeed(); } } + + [Constructable] + public PeachTrunkAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xD9C, 1076786 ), 0, 0, 0 ); + } + + public PeachTrunkAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PeachTrunkDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new PeachTrunkAddon(); } } + public override int LabelNumber { get { return 1076786; } } // Peach Trunk + + [Constructable] + public PeachTrunkDeed() : base() + { + LootType = LootType.Blessed; + } + + public PeachTrunkDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/PinkFancyRug.cs b/Scripts/Items/Special/Heritage Items/PinkFancyRug.cs new file mode 100644 index 0000000..59a82d5 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/PinkFancyRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class PinkFancyRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new PinkFancyRugDeed(); } } + + [Constructable] + public PinkFancyRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xAEE, 1076590 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAEF, 1076590 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF0, 1076590 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF1, 1076590 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF2, 1076590 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF3, 1076590 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF4, 1076590 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAF5, 1076590 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAEC, 1076590 ), 0, 0, 0 ); + } + + public PinkFancyRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PinkFancyRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new PinkFancyRugAddon(); } } + public override int LabelNumber { get { return 1076590; } } // Pink fancy rug + + [Constructable] + public PinkFancyRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public PinkFancyRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/RedPlainRug.cs b/Scripts/Items/Special/Heritage Items/RedPlainRug.cs new file mode 100644 index 0000000..e5b4861 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/RedPlainRug.cs @@ -0,0 +1,71 @@ +using System; + +namespace Server.Items +{ + public class RedPlainRugAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new RedPlainRugDeed(); } } + + [Constructable] + public RedPlainRugAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0xAC9, 1076588 ), 1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xACA, 1076588 ), -1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xACB, 1076588 ), -1, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xACC, 1076588 ), 1, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xACD, 1076588 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xACE, 1076588 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xACF, 1076588 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAD0, 1076588 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xAC6, 1076588 ), 0, 0, 0 ); + } + + public RedPlainRugAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class RedPlainRugDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new RedPlainRugAddon(); } } + public override int LabelNumber { get { return 1076588; } } // Red plain rug + + [Constructable] + public RedPlainRugDeed() : base() + { + LootType = LootType.Blessed; + } + + public RedPlainRugDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/Scarecrow.cs b/Scripts/Items/Special/Heritage Items/Scarecrow.cs new file mode 100644 index 0000000..9c16c53 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/Scarecrow.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x1E34, 0x1E35 )] + public class ScarecrowComponent : AddonComponent + { + public override int LabelNumber { get { return 1076608; } } // Scarecrow + + public ScarecrowComponent() : base( 0x1E34 ) + { + } + + public ScarecrowComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ScarecrowAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new ScarecrowDeed(); } } + + [Constructable] + public ScarecrowAddon() : base() + { + AddComponent( new ScarecrowComponent(), 0, 0, 0 ); + } + + public ScarecrowAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class ScarecrowDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new ScarecrowAddon(); } } + public override int LabelNumber { get { return 1076608; } } // Scarecrow + + [Constructable] + public ScarecrowDeed() : base() + { + LootType = LootType.Blessed; + } + + public ScarecrowDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/SmallFishingNet.cs b/Scripts/Items/Special/Heritage Items/SmallFishingNet.cs new file mode 100644 index 0000000..ecfd42f --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/SmallFishingNet.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x1EA3, 0x1EA4 )] + public class SmallFishingNetComponent : AddonComponent + { + public override int LabelNumber { get { return 1076286; } } // Small Fish Net + + public SmallFishingNetComponent() : base( 0x1EA3 ) + { + } + + public SmallFishingNetComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SmallFishingNetAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new SmallFishingNetDeed(); } } + + [Constructable] + public SmallFishingNetAddon() : base() + { + AddComponent( new SmallFishingNetComponent(), 0, 0, 0 ); + } + + public SmallFishingNetAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SmallFishingNetDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new SmallFishingNetAddon(); } } + public override int LabelNumber { get { return 1076286; } } // Small Fish Net + + [Constructable] + public SmallFishingNetDeed() : base() + { + LootType = LootType.Blessed; + } + + public SmallFishingNetDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/Statue.cs b/Scripts/Items/Special/Heritage Items/Statue.cs new file mode 100644 index 0000000..28c36b9 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/Statue.cs @@ -0,0 +1,132 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class StoneStatueAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new StoneStatueDeed(); } } + + [Constructable] + public StoneStatueAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new LocalizedAddonComponent( 0x139E, 1076284 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x139F, 1076284 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x13A0, 1076284 ), 0, -1, 0 ); + } + else // south + { + AddComponent( new LocalizedAddonComponent( 0x129F, 1076284 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x12A0, 1076284 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0x12A1, 1076284 ), -1, 0, 0 ); + } + } + + public StoneStatueAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class StoneStatueDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new StoneStatueAddon( m_East ); } } + public override int LabelNumber { get { return 1076284; } } // Statue + + private bool m_East; + + [Constructable] + public StoneStatueDeed() : base() + { + LootType = LootType.Blessed; + } + + public StoneStatueDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private StoneStatueDeed m_Deed; + + public InternalGump( StoneStatueDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076579, 0x7FFF, false, false ); // Please select your statue position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/SuitOfGoldArmor.cs b/Scripts/Items/Special/Heritage Items/SuitOfGoldArmor.cs new file mode 100644 index 0000000..0389bb5 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/SuitOfGoldArmor.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x3DAA, 0x3DA9 )] + public class SuitOfGoldArmorComponent : AddonComponent + { + public override int LabelNumber { get { return 1076265; } } // Suit of Gold Armor + + public SuitOfGoldArmorComponent() : base( 0x3DAA ) + { + } + + public SuitOfGoldArmorComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfGoldArmorAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new SuitOfGoldArmorDeed(); } } + + [Constructable] + public SuitOfGoldArmorAddon() : base() + { + AddComponent( new SuitOfGoldArmorComponent(), 0, 0, 0 ); + } + + public SuitOfGoldArmorAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfGoldArmorDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new SuitOfGoldArmorAddon(); } } + public override int LabelNumber { get { return 1076265; } } // Suit of Gold Armor + + [Constructable] + public SuitOfGoldArmorDeed() : base() + { + LootType = LootType.Blessed; + } + + public SuitOfGoldArmorDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/SuitOfSilverArmor.cs b/Scripts/Items/Special/Heritage Items/SuitOfSilverArmor.cs new file mode 100644 index 0000000..99e07fc --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/SuitOfSilverArmor.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + [Flipable( 0x3D86, 0x3D87 )] + public class SuitOfSilverArmorComponent : AddonComponent + { + public override int LabelNumber { get { return 1076266; } } // Suit of Silver Armor + + public SuitOfSilverArmorComponent() : base( 0x3D86 ) + { + } + + public SuitOfSilverArmorComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfSilverArmorAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new SuitOfSilverArmorDeed(); } } + + [Constructable] + public SuitOfSilverArmorAddon() : base() + { + AddComponent( new SuitOfSilverArmorComponent(), 0, 0, 0 ); + } + + public SuitOfSilverArmorAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SuitOfSilverArmorDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new SuitOfSilverArmorAddon(); } } + public override int LabelNumber { get { return 1076266; } } // Suit of Silver Armor + + [Constructable] + public SuitOfSilverArmorDeed() : base() + { + LootType = LootType.Blessed; + } + + public SuitOfSilverArmorDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/TableWithBlueCloth.cs b/Scripts/Items/Special/Heritage Items/TableWithBlueCloth.cs new file mode 100644 index 0000000..60a035f --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/TableWithBlueCloth.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class TableWithBlueClothAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new TableWithBlueClothDeed(); } } + + [Constructable] + public TableWithBlueClothAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x118C, 1076276 ), 0, 0, 0 ); + } + + public TableWithBlueClothAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithBlueClothDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new TableWithBlueClothAddon(); } } + public override int LabelNumber { get { return 1076276; } } // Table With A Blue Tablecloth + + [Constructable] + public TableWithBlueClothDeed() : base() + { + LootType = LootType.Blessed; + } + + public TableWithBlueClothDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/TableWithOrangeCloth.cs b/Scripts/Items/Special/Heritage Items/TableWithOrangeCloth.cs new file mode 100644 index 0000000..4b9775e --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/TableWithOrangeCloth.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class TableWithOrangeClothAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new TableWithOrangeClothDeed(); } } + + [Constructable] + public TableWithOrangeClothAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x118E, 1076278 ), 0, 0, 0 ); + } + + public TableWithOrangeClothAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithOrangeClothDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new TableWithOrangeClothAddon(); } } + public override int LabelNumber { get { return 1076278; } } // Table With An Orange Tablecloth + + [Constructable] + public TableWithOrangeClothDeed() : base() + { + LootType = LootType.Blessed; + } + + public TableWithOrangeClothDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/TableWithPurpleCloth.cs b/Scripts/Items/Special/Heritage Items/TableWithPurpleCloth.cs new file mode 100644 index 0000000..ec86822 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/TableWithPurpleCloth.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class TableWithPurpleClothAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new TableWithPurpleClothDeed(); } } + + [Constructable] + public TableWithPurpleClothAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x118B, 1076275 ), 0, 0, 0 ); + } + + public TableWithPurpleClothAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithPurpleClothDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new TableWithPurpleClothAddon(); } } + public override int LabelNumber { get { return 1076275; } } // Table With A Purple Tablecloth + + [Constructable] + public TableWithPurpleClothDeed() : base() + { + LootType = LootType.Blessed; + } + + public TableWithPurpleClothDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/TableWithRedCloth.cs b/Scripts/Items/Special/Heritage Items/TableWithRedCloth.cs new file mode 100644 index 0000000..0979d98 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/TableWithRedCloth.cs @@ -0,0 +1,63 @@ +using System; + +namespace Server.Items +{ + public class TableWithRedClothAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new TableWithRedClothDeed(); } } + + [Constructable] + public TableWithRedClothAddon() : base() + { + AddComponent( new LocalizedAddonComponent( 0x118D, 1076277 ), 0, 0, 0 ); + } + + public TableWithRedClothAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class TableWithRedClothDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new TableWithRedClothAddon(); } } + public override int LabelNumber { get { return 1076277; } } // Table With A Red Tablecloth + + [Constructable] + public TableWithRedClothDeed() : base() + { + LootType = LootType.Blessed; + } + + public TableWithRedClothDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/UnmadeBed.cs b/Scripts/Items/Special/Heritage Items/UnmadeBed.cs new file mode 100644 index 0000000..b2bd6d0 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/UnmadeBed.cs @@ -0,0 +1,142 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class UnmadeBedAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new UnmadeBedDeed(); } } + + public override bool RetainDeedHue { get { return true; } } + + [Constructable] + public UnmadeBedAddon(bool east) + : this(east, 0) + { + } + + public UnmadeBedAddon( bool east, int hue ) : base() + { + if ( east ) // east + { + AddComponent( new LocalizedAddonComponent( 0xA8C, 1076279 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xA8D, 1076279 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xA90, 1076279 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xA91, 1076279 ), -1, -1, 0 ); + } + else // south + { + AddComponent( new LocalizedAddonComponent( 0xDB0, 1076279 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xDB1, 1076279 ), -1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0xDB4, 1076279 ), 0, -1, 0 ); + AddComponent( new LocalizedAddonComponent( 0xDB5, 1076279 ), -1, -1, 0 ); + } + Hue = hue; + } + + public UnmadeBedAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class UnmadeBedDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new UnmadeBedAddon( m_East, this.Hue ); } } + public override int LabelNumber { get { return 1076279; } } // Unmade Bed + + private bool m_East; + + [Constructable] + public UnmadeBedDeed() : base() + { + LootType = LootType.Blessed; + } + + public UnmadeBedDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private UnmadeBedDeed m_Deed; + + public InternalGump( UnmadeBedDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076580, 0x7FFF, false, false ); // Pleae select your unmade bed position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/Vanity.cs b/Scripts/Items/Special/Heritage Items/Vanity.cs new file mode 100644 index 0000000..dd2dabd --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/Vanity.cs @@ -0,0 +1,131 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class VanityAddon : BaseAddonContainer + { + public override BaseAddonContainerDeed Deed { get { return new VanityDeed(); } } + public override int LabelNumber { get { return 1074027; } } // Vanity + public override int DefaultGumpID { get { return 0x51; } } + public override int DefaultDropSound { get { return 0x42; } } + + [Constructable] + public VanityAddon( bool east ) : base( east ? 0xA44 : 0xA3C ) + { + if ( east ) // east + { + AddComponent( new AddonContainerComponent( 0xA45 ), 0, -1, 0 ); + } + else // south + { + AddComponent( new AddonContainerComponent( 0xA3D ), -1, 0, 0 ); + } + } + + public VanityAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class VanityDeed : BaseAddonContainerDeed + { + public override BaseAddonContainer Addon { get { return new VanityAddon( m_East ); } } + public override int LabelNumber { get { return 1074027; } } // Vanity + + private bool m_East; + + [Constructable] + public VanityDeed() : base() + { + LootType = LootType.Blessed; + } + + public VanityDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private VanityDeed m_Deed; + + public InternalGump( VanityDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076744, 0x7FFF, false, false ); // Please select your vanity position. + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/WallTorch.cs b/Scripts/Items/Special/Heritage Items/WallTorch.cs new file mode 100644 index 0000000..554a4f5 --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/WallTorch.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Spells; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x3D98, 0x3D94 )] + public class WallTorchComponent : AddonComponent + { + public override int LabelNumber { get { return 1076282; } } // Wall Torch + + public WallTorchComponent() : base( 0x3D98 ) + { + } + + public WallTorchComponent( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + switch ( ItemID ) + { + case 0x3D98: ItemID = 0x3D9B; break; + case 0x3D9B: ItemID = 0x3D98; break; + case 0x3D94: ItemID = 0x3D97; break; + case 0x3D97: ItemID = 0x3D94; break; + } + + Effects.PlaySound( Location, Map, 0x3BE ); + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + + public class WallTorchAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new WallTorchDeed(); } } + + public WallTorchAddon() : base() + { + AddComponent( new WallTorchComponent(), 0, 0, 0 ); + } + + public WallTorchAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class WallTorchDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new WallTorchAddon(); } } + public override int LabelNumber { get { return 1076282; } } // Wall Torch + + [Constructable] + public WallTorchDeed() : base() + { + LootType = LootType.Blessed; + } + + public WallTorchDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Heritage Items/WoodenCoffin.cs b/Scripts/Items/Special/Heritage Items/WoodenCoffin.cs new file mode 100644 index 0000000..36a791b --- /dev/null +++ b/Scripts/Items/Special/Heritage Items/WoodenCoffin.cs @@ -0,0 +1,159 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class WoodenCoffinComponent : AddonComponent + { + public override int LabelNumber { get { return 1076274; } } // Coffin + + public WoodenCoffinComponent( int itemID ) : base( itemID ) + { + } + + public WoodenCoffinComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class WoodenCoffinAddon : BaseAddon + { + public override BaseAddonDeed Deed { get { return new WoodenCoffinDeed(); } } + + [Constructable] + public WoodenCoffinAddon( bool east ) : base() + { + if ( east ) // east + { + AddComponent( new WoodenCoffinComponent( 0x1C41 ), 0, 0, 0 ); + AddComponent( new WoodenCoffinComponent( 0x1C42 ), 1, 0, 0 ); + AddComponent( new WoodenCoffinComponent( 0x1C43 ), 2, 0, 0 ); + } + else // south + { + AddComponent( new WoodenCoffinComponent( 0x1C4F ), 0, 0, 0 ); + AddComponent( new WoodenCoffinComponent( 0x1C50 ), 0, 1, 0 ); + AddComponent( new WoodenCoffinComponent( 0x1C51 ), 0, 2, 0 ); + } + } + + public WoodenCoffinAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class WoodenCoffinDeed : BaseAddonDeed + { + public override BaseAddon Addon { get { return new WoodenCoffinAddon( m_East ); } } + public override int LabelNumber { get { return 1076274; } } // Coffin + + private bool m_East; + + [Constructable] + public WoodenCoffinDeed() : base() + { + LootType = LootType.Blessed; + } + + public WoodenCoffinDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + private void SendTarget( Mobile m ) + { + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private WoodenCoffinDeed m_Deed; + + public InternalGump( WoodenCoffinDeed deed ) : base( 60, 36 ) + { + m_Deed = deed; + + AddPage( 0 ); + + AddBackground( 0, 0, 273, 324, 0x13BE ); + AddImageTiled( 10, 10, 253, 20, 0xA40 ); + AddImageTiled( 10, 40, 253, 244, 0xA40 ); + AddImageTiled( 10, 294, 253, 20, 0xA40 ); + AddAlphaRegion( 10, 10, 253, 304 ); + AddButton( 10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 296, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + AddHtmlLocalized( 14, 12, 273, 20, 1076748, 0x7FFF, false, false ); // Please select your coffin position + + AddPage( 1 ); + + AddButton( 19, 49, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 47, 213, 20, 1075386, 0x7FFF, false, false ); // South + AddButton( 19, 73, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 44, 71, 213, 20, 1075387, 0x7FFF, false, false ); // East + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted || info.ButtonID == 0 ) + return; + + m_Deed.m_East = ( info.ButtonID != 1 ); + m_Deed.SendTarget( sender.Mobile ); + } + } + } +} diff --git a/Scripts/Items/Special/HeritageToken.cs b/Scripts/Items/Special/HeritageToken.cs new file mode 100644 index 0000000..1a513e9 --- /dev/null +++ b/Scripts/Items/Special/HeritageToken.cs @@ -0,0 +1,58 @@ +using System; +using Server; +using Server.Gumps; + +namespace Server.Items +{ + public interface ITokunoDyable + { + } + + public class HeritageToken : Item + { + public override int LabelNumber { get { return 1076596; } } // A Heritage Token + + [Constructable] + public HeritageToken() : base( 0x367A ) + { + LootType = LootType.Blessed; + Weight = 5.0; + } + + public HeritageToken( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( HeritageTokenGump ) ); + from.SendGump( new HeritageTokenGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070998, String.Format( "#{0}", 1076595 ) ); // Use this to redeem
Your Heritage Items + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Holiday/AngelDecoration.cs b/Scripts/Items/Special/Holiday/AngelDecoration.cs new file mode 100644 index 0000000..bcdf73f --- /dev/null +++ b/Scripts/Items/Special/Holiday/AngelDecoration.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x46FA, 0x46FB )] + public class AngelDecoration : Item + { + [Constructable] + public AngelDecoration() : base( 0x46FA ) + { + LootType = LootType.Blessed; + } + + public AngelDecoration( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs b/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs new file mode 100644 index 0000000..ff134c8 --- /dev/null +++ b/Scripts/Items/Special/Holiday/Christmas/HolidayTree.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Multis; + +namespace Server.Items +{ + public enum HolidayTreeType + { + Classic, + Modern + } + + public class HolidayTree : Item, IAddon + { + private ArrayList m_Components; + private Mobile m_Placer; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Placer + { + get{ return m_Placer; } + set{ m_Placer = value; } + } + + private class Ornament : Item + { + public override int LabelNumber{ get{ return 1041118; } } // a tree ornament + + public Ornament( int itemID ) : base( itemID ) + { + Movable = false; + } + + public Ornament( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + private class TreeTrunk : Item + { + private HolidayTree m_Tree; + + public override int LabelNumber{ get{ return 1041117; } } // a tree for the holidays + + public TreeTrunk( HolidayTree tree, int itemID ) : base( itemID ) + { + Movable = false; + MoveToWorld( tree.Location, tree.Map ); + + m_Tree = tree; + } + + public TreeTrunk( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Tree != null && !m_Tree.Deleted ) + m_Tree.OnDoubleClick( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Tree ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Tree = reader.ReadItem() as HolidayTree; + + if ( m_Tree == null ) + Delete(); + + break; + } + } + } + } + + public override int LabelNumber{ get{ return 1041117; } } // a tree for the holidays + + public HolidayTree( Mobile from, HolidayTreeType type, Point3D loc ) : base( 1 ) + { + Movable = false; + MoveToWorld( loc, from.Map ); + + m_Placer = from; + m_Components = new ArrayList(); + + switch ( type ) + { + case HolidayTreeType.Classic: + { + ItemID = 0xCD7; + + AddItem( 0, 0, 0, new TreeTrunk( this, 0xCD6 ) ); + + AddOrnament( 0, 0, 2, 0xF22 ); + AddOrnament( 0, 0, 9, 0xF18 ); + AddOrnament( 0, 0, 15, 0xF20 ); + AddOrnament( 0, 0, 19, 0xF17 ); + AddOrnament( 0, 0, 20, 0xF24 ); + AddOrnament( 0, 0, 20, 0xF1F ); + AddOrnament( 0, 0, 20, 0xF19 ); + AddOrnament( 0, 0, 21, 0xF1B ); + AddOrnament( 0, 0, 28, 0xF2F ); + AddOrnament( 0, 0, 30, 0xF23 ); + AddOrnament( 0, 0, 32, 0xF2A ); + AddOrnament( 0, 0, 33, 0xF30 ); + AddOrnament( 0, 0, 34, 0xF29 ); + AddOrnament( 0, 1, 7, 0xF16 ); + AddOrnament( 0, 1, 7, 0xF1E ); + AddOrnament( 0, 1, 12, 0xF0F ); + AddOrnament( 0, 1, 13, 0xF13 ); + AddOrnament( 0, 1, 18, 0xF12 ); + AddOrnament( 0, 1, 19, 0xF15 ); + AddOrnament( 0, 1, 25, 0xF28 ); + AddOrnament( 0, 1, 29, 0xF1A ); + AddOrnament( 0, 1, 37, 0xF2B ); + AddOrnament( 1, 0, 13, 0xF10 ); + AddOrnament( 1, 0, 14, 0xF1C ); + AddOrnament( 1, 0, 16, 0xF14 ); + AddOrnament( 1, 0, 17, 0xF26 ); + AddOrnament( 1, 0, 22, 0xF27 ); + + break; + } + case HolidayTreeType.Modern: + { + ItemID = 0x1B7E; + + AddOrnament( 0, 0, 2, 0xF2F ); + AddOrnament( 0, 0, 2, 0xF20 ); + AddOrnament( 0, 0, 2, 0xF22 ); + AddOrnament( 0, 0, 5, 0xF30 ); + AddOrnament( 0, 0, 5, 0xF15 ); + AddOrnament( 0, 0, 5, 0xF1F ); + AddOrnament( 0, 0, 5, 0xF2B ); + AddOrnament( 0, 0, 6, 0xF0F ); + AddOrnament( 0, 0, 7, 0xF1E ); + AddOrnament( 0, 0, 7, 0xF24 ); + AddOrnament( 0, 0, 8, 0xF29 ); + AddOrnament( 0, 0, 9, 0xF18 ); + AddOrnament( 0, 0, 14, 0xF1C ); + AddOrnament( 0, 0, 15, 0xF13 ); + AddOrnament( 0, 0, 15, 0xF20 ); + AddOrnament( 0, 0, 16, 0xF26 ); + AddOrnament( 0, 0, 17, 0xF12 ); + AddOrnament( 0, 0, 18, 0xF17 ); + AddOrnament( 0, 0, 20, 0xF1B ); + AddOrnament( 0, 0, 23, 0xF28 ); + AddOrnament( 0, 0, 25, 0xF18 ); + AddOrnament( 0, 0, 25, 0xF2A ); + AddOrnament( 0, 1, 7, 0xF16 ); + + break; + } + } + } + + public override void OnAfterDelete() + { + for ( int i = 0; i < m_Components.Count; ++i ) + ((Item)m_Components[i]).Delete(); + } + + private void AddOrnament( int x, int y, int z, int itemID ) + { + AddItem( x + 1, y + 1, z + 11, new Ornament( itemID ) ); + } + + private void AddItem( int x, int y, int z, Item item ) + { + item.MoveToWorld( new Point3D( this.Location.X + x, this.Location.Y + y, this.Location.Z + z ), this.Map ); + + m_Components.Add( item ); + } + + public HolidayTree( Serial serial ) : base( serial ) + { + } + + public bool CouldFit( IPoint3D p, Map map ) + { + return map.CanFit( (Point3D)p, 20 ); + } + + Item IAddon.Deed + { + get{ return new HolidayTreeDeed(); } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Placer ); + + writer.Write( (int) m_Components.Count ); + + for ( int i = 0; i < m_Components.Count; ++i ) + writer.Write( (Item)m_Components[i] ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Placer = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + int count = reader.ReadInt(); + + m_Components = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + Item item = reader.ReadItem(); + + if ( item != null ) + m_Components.Add( item ); + } + + break; + } + } + + Timer.DelayCall( TimeSpan.Zero, ValidatePlacement ); + } + + public void ValidatePlacement() + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house == null ) + { + HolidayTreeDeed deed = new HolidayTreeDeed(); + deed.MoveToWorld( Location, Map ); + Delete(); + } + } + + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + { + if ( m_Placer == null || from == m_Placer || from.AccessLevel >= AccessLevel.GameMaster ) + { + from.AddToBackpack( new HolidayTreeDeed() ); + + this.Delete(); + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.Addons.Contains( this ) ) + { + house.Addons.Remove( this ); + } + + from.SendLocalizedMessage( 503393 ); // A deed for the tree has been placed in your backpack. + } + else + { + from.SendLocalizedMessage( 503396 ); // You cannot take this tree down. + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/GiftBox.cs b/Scripts/Items/Special/Holiday/GiftBox.cs new file mode 100644 index 0000000..d7c9180 --- /dev/null +++ b/Scripts/Items/Special/Holiday/GiftBox.cs @@ -0,0 +1,41 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [Furniture] + [Flipable( 0x232A, 0x232B )] + public class GiftBox : BaseContainer + { + [Constructable] + public GiftBox() : this( Utility.RandomDyedHue() ) + { + } + + [Constructable] + public GiftBox( int hue ) : base( Utility.Random( 0x232A, 2 ) ) + { + Weight = 2.0; + Hue = hue; + } + + public GiftBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/GingerBreadHouseDeed.cs b/Scripts/Items/Special/Holiday/GingerBreadHouseDeed.cs new file mode 100644 index 0000000..ce76b71 --- /dev/null +++ b/Scripts/Items/Special/Holiday/GingerBreadHouseDeed.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GingerBreadHouseAddon : BaseAddon + { + public override BaseAddonDeed Deed{ get{ return new GingerBreadHouseDeed(); } } + + public GingerBreadHouseAddon() + { + for( int i=0x2be5; i<0x2be8; i++ ) + { + LocalizedAddonComponent laoc = new LocalizedAddonComponent( i, 1077395 ); // Gingerbread House + laoc.Light = LightType.SouthSmall; + AddComponent( laoc, (i==0x2be5) ? -1 : 0, (i==0x2be7) ? -1 : 0, 0 ); + } + } + + public GingerBreadHouseAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class GingerBreadHouseDeed : BaseAddonDeed + { + public override int LabelNumber{ get{ return 1077394; } } //a Gingerbread House Deed + public override BaseAddon Addon{ get{ return new GingerBreadHouseAddon(); } } + + [Constructable] + public GingerBreadHouseDeed() + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public GingerBreadHouseDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Special/Holiday/HolidayBell.cs b/Scripts/Items/Special/Holiday/HolidayBell.cs new file mode 100644 index 0000000..10d5195 --- /dev/null +++ b/Scripts/Items/Special/Holiday/HolidayBell.cs @@ -0,0 +1,109 @@ +using System; + +namespace Server.Items +{ + public class HolidayBell : Item + { + private static string[] m_StaffNames = new string[] + { + "Adrick", + "Alai", + "Bulldoz", + "Evocare", + "FierY-iCe", + "Greyburn", + "Hanse", + "Ignatz", + "Jalek", + "LadyMOI", + "Lord Krum", + "Malantus", + "Nimrond", + "Oaks", + "Prophet", + "Runesabre", + "Sage", + "Stellerex", + "T-Bone", + "Tajima", + "Tyrant", + "Vex" + }; + private static int[] m_Hues = new int[] + { + 0xA, 0x24, 0x42, 0x56, 0x1A, 0x4C, 0x3C, 0x60, 0x2E, 0x55, 0x23, 0x38, 0x482, 0x6, 0x10 + }; + + [CommandProperty(AccessLevel.GameMaster)] + public int SoundID + { + get { return m_SoundID; } + set { m_SoundID = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string Giver { get { return m_Maker; } set { m_Maker = value; } } + + public override string DefaultName + { + get { return String.Format("A Holiday Bell From {0}", Giver); } + } + + private string m_Maker; + private int m_SoundID; + + [Constructable] + public HolidayBell() + : this(m_StaffNames[Utility.Random(m_StaffNames.Length)]) + { + } + + [Constructable] + public HolidayBell(string maker) + : base(0x1C12) + { + m_Maker = maker; + + LootType = LootType.Blessed; + Hue = m_Hues[Utility.Random(m_Hues.Length)]; + SoundID = 0x0F5 + Utility.Random(14); + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + { + from.SendLocalizedMessage(500446); // That is too far away. + } + else from.PlaySound(m_SoundID); + } + + public HolidayBell(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write((string)m_Maker); + + writer.WriteEncodedInt((int)m_SoundID); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Maker = reader.ReadString(); + m_SoundID = reader.ReadEncodedInt(); + + Utility.Intern(ref m_Maker); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/HolidayFoods.cs b/Scripts/Items/Special/Holiday/HolidayFoods.cs new file mode 100644 index 0000000..d6876c9 --- /dev/null +++ b/Scripts/Items/Special/Holiday/HolidayFoods.cs @@ -0,0 +1,304 @@ +using System; +using Server.Mobiles; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Items +{ + public class BaseCandyCane : Food + { + private static Dictionary m_ToothAches; + + public static Dictionary ToothAches + { + get { return m_ToothAches; } + set { m_ToothAches = value; } + } + + public static void Initialize() + { + m_ToothAches = new Dictionary(); + } + + public class CandyCaneTimer : Timer + { + private int m_Eaten; + private Mobile m_Eater; + + public Mobile Eater { get { return m_Eater; } } + public int Eaten { get { return m_Eaten; } set { m_Eaten = value; } } + + public CandyCaneTimer( Mobile eater ) + : base( TimeSpan.FromSeconds( 30 ), TimeSpan.FromSeconds( 30 ) ) + { + m_Eater = eater; + Priority = TimerPriority.FiveSeconds; + Start(); + } + + private string ToothAchesMsg() + { + int msg = Utility.Random(5); + + switch (msg) + { + case 0: return "ARRGH! Ma dent me fait mal!"; + case 1: return "Y a-t-il un dentiste parmis vous?"; + case 2: return "Ma dent!!!"; + case 3: return "�a fait trop mal, Maman!"; + case 4: return "Qu'on m'arrache cette foutue dent!"; + } + return "ARRGH! Ma dent me fait mal!"; + } + protected override void OnTick() + { + --m_Eaten; + + if (m_Eater == null || m_Eater.Deleted || m_Eaten <= 0) + { + Stop(); + m_ToothAches.Remove(m_Eater); + } + else if (m_Eater.Map != Map.Internal && m_Eater.Alive) + { + if (m_Eaten > 60) + { + m_Eater.Say(1077388 + Utility.Random(5)); + /* ARRGH! My tooth hurts sooo much! + * You just can't find a good Britannian dentist these days... + * My teeth! + * MAKE IT STOP! + * AAAH! It feels like someone kicked me in the teeth! + */ + + if (Utility.RandomBool() && m_Eater.Body.IsHuman && !m_Eater.Mounted) + m_Eater.Animate(32, 5, 1, true, false, 0); + } + else if (m_Eaten == 60) + { + m_Eater.SendMessage("La douleur s'estompe"); // The extreme pain in your teeth subsides. + } + } + } + } + + private static CandyCaneTimer EnsureTimer(Mobile from) + { + CandyCaneTimer timer; + + if (!m_ToothAches.TryGetValue(from, out timer)) + m_ToothAches[from] = timer = new CandyCaneTimer(from); + + return timer; + } + + public static int GetToothAche(Mobile from) + { + CandyCaneTimer timer; + + if (m_ToothAches.TryGetValue(from, out timer)) + return timer.Eaten; + + return 0; + } + + public static void SetToothAche(Mobile from, int value) + { + EnsureTimer(from).Eaten = value; + } + + + public BaseCandyCane( int itemID ) : this( 1, itemID ) + { + } + + public BaseCandyCane(int amount, int itemID) + : base(itemID) + { + Stackable = false; + } + + public override void OnDoubleClick( Mobile from ) + { + if( IsChildOf( from.Backpack ) || from.InRange(this, 1) ) + { + from.PlaySound( 0x3a + Utility.Random(3) ); + from.Animate( 34, 5, 1, true, false, 0 ); + + if ( !ToothAches.ContainsKey( from ) ) + { + ToothAches.Add( from, new CandyCaneTimer( from ) ); + } + + ToothAches[from].Eaten += 32; + + from.SendMessage( "Ceci est si bon que vous pourriez en manger � l'infini" ); // You feel as if you could eat as much as you wanted! + Delete(); + } + } + + public BaseCandyCane(Serial serial) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class RedCandyCane : BaseCandyCane + { + + [Constructable] + public RedCandyCane() : this( 1 ) + { + } + + [Constructable] + public RedCandyCane(int amount) : base(amount, 0x2bdd) + { + ItemID = 0x2bdd + Utility.Random(1); + Name = "Canne aux fruits"; + } + + public RedCandyCane(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GreenCandyCane : BaseCandyCane + { + [Constructable] + public GreenCandyCane() + : this(1) + { + } + + [Constructable] + public GreenCandyCane(int amount) + : base(amount, 0x2bdf) + { + ItemID = 0x2bdf + Utility.Random(1); + Name = "Canne � la limette"; + } + + public GreenCandyCane(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class GingerBreadCookie : Food + { + private readonly int[] m_Messages = + { + 0, + 1077396, // Noooo! + 1077397, // Please don't eat me... *whimper* + 1077405, // etc etc etc .. + 1077406, + 1077407, + 1077408, + 1077409 + }; + + private string GingerBreadMsg() + { + int msg = Utility.Random(7); + + switch (msg) + { + case 0: return "Noooooooon!"; + case 1: return "Je t'en supplie ne me mange pas! *G�mit*"; + case 2: return "Pas la t�te! Pas la t�te!"; + case 3: return "Ahhh! Mon pied! �a fait mal!"; + case 4: return "S'il vous plait, j'ai des enfants biscuits!"; + case 5: return "Je suis empoisonn�! Vraiment..."; + case 6: return "Je me sauverai! Je suis Super�pice!"; + } + return "Noooooooon!"; + } + + [Constructable] + public GingerBreadCookie() : base( 0x2be1 ) + { + ItemID = Utility.RandomBool() ? 0x2be1 : 0x2be2; + Stackable = false; + Name = Utility.RandomBool() ? "Homme en pain d'epices" : "Femme en pain d'epices"; + } + + public GingerBreadCookie( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if( IsChildOf( from.Backpack ) || from.InRange(this, 1) ) + { + if (Utility.Random(8) == 7) + base.OnDoubleClick( from ); + else + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, GingerBreadMsg()); ; + /*int result; + if ((result = m_Messages[Utility.Random(0,m_Messages.Length)]) == 0) + { + base.OnDoubleClick( from ); + } + else + { + this.SendLocalizedMessageTo( from, result ); + }*/ + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Special/Holiday/HolidayGiftBoxes.cs b/Scripts/Items/Special/Holiday/HolidayGiftBoxes.cs new file mode 100644 index 0000000..3b238bf --- /dev/null +++ b/Scripts/Items/Special/Holiday/HolidayGiftBoxes.cs @@ -0,0 +1,221 @@ +using System; + +namespace Server.Items +{ + public class GiftBoxHues + { + public static int RandomGiftBoxHue{ get { return m_NormalHues[Utility.Random(m_NormalHues.Length)]; }} + public static int RandomNeonBoxHue{ get { return m_NeonHues[Utility.Random(m_NeonHues.Length)]; }} + + /* there's possibly a couple more, but this is what we could verify on OSI */ + + private static readonly int[] m_NormalHues = + { + 0x672, + 0x454, + 0x507, + 0x4ac, + 0x504, + 0x84b, + 0x495, + 0x97c, + 0x493, + 0x4a8, + 0x494, + 0x4aa, + 0xb8b, + 0x84f, + 0x491, + 0x851, + 0x503, + 0xb8c, + 0x4ab, + 0x84B + }; + private static readonly int[] m_NeonHues = + { + 0x438, + 0x424, + 0x433, + 0x445, + 0x42b, + 0x448 + }; + } + + [FlipableAttribute(0x46A5, 0x46A6)] + public class GiftBoxRectangle : BaseContainer + { + public override int DefaultGumpID { get { return 0x11E; } } + + [Constructable] + public GiftBoxRectangle() + : base(Utility.RandomBool() ? 0x46A5 : 0x46A6) + { + Hue = GiftBoxHues.RandomGiftBoxHue; + } + + public GiftBoxRectangle(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxCube : BaseContainer + { + public override int DefaultGumpID { get { return 0x11B; } } + + [Constructable] + public GiftBoxCube() + : base(0x46A2) + { + Hue = GiftBoxHues.RandomGiftBoxHue; + } + + public GiftBoxCube(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxCylinder : BaseContainer + { + public override int DefaultGumpID { get { return 0x11C; } } + + [Constructable] + public GiftBoxCylinder() + : base(0x46A3) + { + Hue = GiftBoxHues.RandomGiftBoxHue; + } + + public GiftBoxCylinder(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxOctogon : BaseContainer + { + public override int DefaultGumpID { get { return 0x11D; } } + + [Constructable] + public GiftBoxOctogon() + : base(0x46A4) + { + Hue = GiftBoxHues.RandomGiftBoxHue; + } + + public GiftBoxOctogon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + public class GiftBoxAngel : BaseContainer + { + public override int DefaultGumpID { get { return 0x11F; } } + + [Constructable] + public GiftBoxAngel() + : base(0x46A7) + { + Hue = GiftBoxHues.RandomGiftBoxHue; + } + + public GiftBoxAngel(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [Flipable(0x232A, 0x232B)] + public class GiftBoxNeon : BaseContainer + { + [Constructable] + public GiftBoxNeon() + : base(Utility.RandomBool() ? 0x232A : 0x232B) + { + Hue = GiftBoxHues.RandomNeonBoxHue; + } + + public GiftBoxNeon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/HolidayPottedPlant.cs b/Scripts/Items/Special/Holiday/HolidayPottedPlant.cs new file mode 100644 index 0000000..e0773f9 --- /dev/null +++ b/Scripts/Items/Special/Holiday/HolidayPottedPlant.cs @@ -0,0 +1,155 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class HolidayPottedPlant : Item + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + [Constructable] + public HolidayPottedPlant() + : this( Utility.RandomMinMax( 0x11C8, 0x11CC ) ) + { + } + + [Constructable] + public HolidayPottedPlant( int itemID ) + : base( itemID ) + { + } + + public HolidayPottedPlant( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PottedPlantDeed : Item + { + public override int LabelNumber { get { return 1041114; } } // A deed for a potted plant. + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public PottedPlantDeed() + : base( 0x14F0 ) + { + LootType = LootType.Blessed; + } + + public PottedPlantDeed( Serial serial ) + : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + { + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private PottedPlantDeed m_Deed; + + public InternalGump( PottedPlantDeed deed ) : base( 100, 200 ) + { + m_Deed = deed; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 360, 195, 0xA28 ); + + AddPage( 1 ); + AddLabel( 45, 15, 0, "Choose a Potted Plant:" ); + + AddItem( 45, 75, 0x11C8 ); + AddButton( 55, 50, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + + AddItem( 100, 75, 0x11C9 ); + AddButton( 115, 50, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + + AddItem( 160, 75, 0x11CA ); + AddButton( 175, 50, 0x845, 0x846, 3, GumpButtonType.Reply, 0 ); + + AddItem( 225, 75, 0x11CB ); + AddButton( 235, 50, 0x845, 0x846, 4, GumpButtonType.Reply, 0 ); + + AddItem( 280, 75, 0x11CC ); + AddButton( 295, 50, 0x845, 0x846, 5, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted ) + return; + + Mobile from = sender.Mobile; + + if ( !m_Deed.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it + return; + } + + int index = info.ButtonID - 1; + + if ( index >= 0 && index <= 4 ) + { + HolidayPottedPlant plant = new HolidayPottedPlant( 0x11C8 + index ); + + if ( !from.PlaceInBackpack( plant ) ) + { + plant.Delete(); + from.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + { + m_Deed.Delete(); + } + } + } + } + } +} diff --git a/Scripts/Items/Special/Holiday/HolidayTimepiece.cs b/Scripts/Items/Special/Holiday/HolidayTimepiece.cs new file mode 100644 index 0000000..f9922a0 --- /dev/null +++ b/Scripts/Items/Special/Holiday/HolidayTimepiece.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class HolidayTimepiece : Clock + { + public override int LabelNumber { get { return 1041113; } } // a holiday timepiece + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public HolidayTimepiece() + : base( 0x1086 ) + { + Weight = DefaultWeight; + LootType = LootType.Blessed; + Layer = Layer.Bracelet; + } + + public HolidayTimepiece( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Holiday/Icecicles.cs b/Scripts/Items/Special/Holiday/Icecicles.cs new file mode 100644 index 0000000..ef7aace --- /dev/null +++ b/Scripts/Items/Special/Holiday/Icecicles.cs @@ -0,0 +1,167 @@ +using System; + +namespace Server.Items +{ + public class IcicleLargeSouth : Item + { + [Constructable] + public IcicleLargeSouth() + : base(0x4572) + { + } + + public IcicleLargeSouth(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + public class IcicleMedSouth : Item + { + [Constructable] + public IcicleMedSouth () + : base(0x4573) + { + } + + public IcicleMedSouth (Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + public class IcicleSmallSouth : Item + { + [Constructable] + public IcicleSmallSouth () + : base(0x4574) + { + } + + public IcicleSmallSouth (Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + public class IcicleLargeEast : Item + { + [Constructable] + public IcicleLargeEast () + : base(0x4575) + { + } + + public IcicleLargeEast (Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + public class IcicleMedEast : Item + { + [Constructable] + public IcicleMedEast () + : base(0x4576) + { + } + + public IcicleMedEast (Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + public class IcicleSmallEast : Item + { + [Constructable] + public IcicleSmallEast () + : base(0x4577) + { + } + + public IcicleSmallEast(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/IcyPatch.cs b/Scripts/Items/Special/Holiday/IcyPatch.cs new file mode 100644 index 0000000..ce92685 --- /dev/null +++ b/Scripts/Items/Special/Holiday/IcyPatch.cs @@ -0,0 +1,125 @@ +using System; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Items +{ + public class IcyPatch : Item + { + public override int LabelNumber { get { return 1095159; } } //An Icy Patch + public override double DefaultWeight { get { return 5.0; } } + + /* On OSI, the iceypatch with itemid 0x122a is "rarer", so we will give it 1:10 chance of creating it that way */ + + [Constructable] + public IcyPatch() + : this((Utility.Random(10) == 0) ? 0x122A : 0x122F) + { + } + + public IcyPatch(int itemid) + : base (itemid) + { + Hue = 0x481; + } + + public IcyPatch(Serial serial) + : base(serial) + { + } + + public override bool OnMoveOver(Mobile m) + { + if (m is PlayerMobile && m.Alive && m.AccessLevel == AccessLevel.Player) + { + switch (Utility.Random(3)) + { + case 0: RunSequence(m, 1095160, false); break; //You steadily walk over the slippery surface. + case 1: RunSequence(m, 1095161, true); break; //You skillfully manage to maintain your balance. + default: RunSequence(m, 1095162, true); break; //You lose your footing and ungracefully splatter on the ground. + } + } + return base.OnMoveOver(m); + } + + public virtual void RunSequence(Mobile m, int message, bool freeze) + { + object[] arg = null; + + if (freeze) + { + m.Frozen = freeze; + Timer.DelayCall(TimeSpan.FromSeconds((message==1095162) ? 2.0 : 1.25), new TimerStateCallback(EndFall_Callback), m); + } + + m.SendLocalizedMessage(message); + + if (message == 1095162) + { + if (m.Mounted) + { + m.Mount.Rider = null; + } + + Point3D p = new Point3D(Location); + + if (SpellHelper.FindValidSpawnLocation(Map, ref p, true)) + { + Timer.DelayCall(TimeSpan.FromSeconds(0), new TimerStateCallback(Relocate_Callback), new object[] { m, p }); + } + + arg = new object[] { m, (21 + Utility.Random(2)), !m.Female ? 0x426 : 0x317 }; + } + else if (message == 1095161) + { + arg = new object[] { m, 17, !m.Female ? 0x429 : 0x319 }; + } + if (arg != null) + { + Timer.DelayCall(TimeSpan.FromSeconds(.4), new TimerStateCallback(BeginFall_Callback), arg); + } + } + + private static void Relocate_Callback(object state) + { + object[] states = (object[])state; + Mobile m = (Mobile)states[0]; + Point3D to = (Point3D)states[1]; + + m.MoveToWorld(to, m.Map); + } + + private static void BeginFall_Callback(object state) + { + object[] states = (object[])state; + + Mobile m = (Mobile)states[0]; + int action = (int)states[1]; + int sound = (int)states[2]; + if (!m.Mounted) + { + m.Animate(action, 1, 1, false, true, 0); + } + m.PlaySound(sound); + } + + private static void EndFall_Callback(object state) + { + ((Mobile)state).Frozen = false; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/PKHolidayStuff.cs b/Scripts/Items/Special/Holiday/PKHolidayStuff.cs new file mode 100644 index 0000000..277433a --- /dev/null +++ b/Scripts/Items/Special/Holiday/PKHolidayStuff.cs @@ -0,0 +1,93 @@ +using System; +using Server.Mobiles; +using Server.Network; +using System.Collections.Generic; + +namespace Server.Items +{ + public class Coal : Item + { + public override string DefaultName{ get { return "Coal"; }} + + [Constructable] + public Coal() : base( 0x19b9 ) + { + Stackable = false; + LootType=LootType.Blessed; + Hue = 0x965; + } + + public Coal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class BadCard : Item + { + public override int LabelNumber{ get { return 1041428; }} // Maybe next year youll get a better... + + [Constructable] + public BadCard() : base( 0x14ef ) + { + int[] m_CardHues=new int[]{ 0x45, 0x27, 0x3d0 }; + Hue = m_CardHues[Utility.Random(m_CardHues.Length)]; + Stackable = false; + LootType=LootType.Blessed; + Movable=true; + } + + public BadCard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class Spam : Food + { + [Constructable] + public Spam() : base( 0x1044 ) + { + Stackable = false; + LootType=LootType.Blessed; + } + + public Spam( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Holiday/Poinsettias.cs b/Scripts/Items/Special/Holiday/Poinsettias.cs new file mode 100644 index 0000000..e6448d5 --- /dev/null +++ b/Scripts/Items/Special/Holiday/Poinsettias.cs @@ -0,0 +1,62 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class RedPoinsettia : Item + { + [Constructable] + public RedPoinsettia() : base( 0x2330 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public RedPoinsettia( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WhitePoinsettia : Item + { + [Constructable] + public WhitePoinsettia() : base( 0x2331 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public WhitePoinsettia( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/RockingHorse.cs b/Scripts/Items/Special/Holiday/RockingHorse.cs new file mode 100644 index 0000000..502e5e2 --- /dev/null +++ b/Scripts/Items/Special/Holiday/RockingHorse.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable( 0x4214, 0x4215 )] + public class RockingHorse : Item + { + public override double DefaultWeight { get { return 30.0; } } + + [Constructable] + public RockingHorse() : base( 0x4214 ) + { + LootType = LootType.Blessed; + } + + public RockingHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Holiday/SnowGlobes.cs b/Scripts/Items/Special/Holiday/SnowGlobes.cs new file mode 100644 index 0000000..e3cc4f5 --- /dev/null +++ b/Scripts/Items/Special/Holiday/SnowGlobes.cs @@ -0,0 +1,311 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SnowGlobe : Item + { + public override double DefaultWeight { get { return 1.0; } } + + public SnowGlobe() + : base( 0xE2F ) + { + LootType = LootType.Blessed; + Light = LightType.Circle150; + } + + public SnowGlobe( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public enum SnowGlobeTypeOne + { + Britain, + Moonglow, + Minoc, + Magincia, + BuccaneersDen, + Trinsic, + Yew, + SkaraBrae, + Jhelom, + Nujelm, + Papua, + Delucia, + Cove, + Ocllo, + SerpentsHold, + EmpathAbbey, + TheLycaeum, + Vesper, + Wind + } + + public class SnowGlobeOne : SnowGlobe + { + private SnowGlobeTypeOne m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public SnowGlobeTypeOne Place + { + get { return m_Type; } + set { m_Type = value; InvalidateProperties(); } + } + + public override int LabelNumber { get { return 1041454 + (int) m_Type; } } + + [Constructable] + public SnowGlobeOne() + : this( (SnowGlobeTypeOne) Utility.Random( 19 ) ) + { + } + + [Constructable] + public SnowGlobeOne( SnowGlobeTypeOne type ) + { + m_Type = type; + } + + public SnowGlobeOne( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.WriteEncodedInt( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (SnowGlobeTypeOne) reader.ReadEncodedInt(); + break; + } + } + } + } + + public enum SnowGlobeTypeTwo + { + AncientCitadel, + BlackthornesCastle, + CityofMontor, + CityofMistas, + ExodusLair, + LakeofFire, + Lakeshire, + PassofKarnaugh, + TheEtherealFortress, + TwinOaksTavern, + ChaosShrine, + ShrineofHumility, + ShrineofSacrifice, + ShrineofCompassion, + ShrineofHonor, + ShrineofHonesty, + ShrineofSpirituality, + ShrineofJustice, + ShrineofValor + } + + public class SnowGlobeTwo : SnowGlobe + { + /* Oddly, these are not localized. */ + private static readonly string[] m_PlaceNames = new string[] + { + /* AncientCitadel */ "Ancient Citadel", + /* BlackthornesCastle */ "Blackthorne's Castle", + /* CityofMontor */ "City of Montor", + /* CityofMistas */ "City of Mistas", + /* ExodusLair */ "Exodus' Lair", + /* LakeofFire */ "Lake of Fire", + /* Lakeshire */ "Lakeshire", + /* PassofKarnaugh */ "Pass of Karnaugh", + /* TheEtherealFortress */ "The Etheral Fortress", + /* TwinOaksTavern */ "Twin Oaks Tavern", + /* ChaosShrine */ "Chaos Shrine", + /* ShrineofHumility */ "Shrine of Humility", + /* ShrineofSacrifice */ "Shrine of Sacrifice", + /* ShrineofCompassion */ "Shrine of Compassion", + /* ShrineofHonor */ "Shrine of Honor", + /* ShrineofHonesty */ "Shrine of Honesty", + /* ShrineofSpirituality */ "Shrine of Spirituality", + /* ShrineofJustice */ "Shrine of Justice", + /* ShrineofValor */ "Shrine of Valor" + }; + + private SnowGlobeTypeTwo m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public SnowGlobeTypeTwo Place + { + get { return m_Type; } + set { m_Type = value; InvalidateProperties(); } + } + + public override string DefaultName + { + get + { + int idx = (int) m_Type; + + if ( idx < 0 || idx >= m_PlaceNames.Length ) + return "a snowy scene"; + + return String.Format( "a snowy scene of {0}", m_PlaceNames[idx] ); + } + } + + [Constructable] + public SnowGlobeTwo() + : this( (SnowGlobeTypeTwo) Utility.Random( 19 ) ) + { + } + + [Constructable] + public SnowGlobeTwo( SnowGlobeTypeTwo type ) + { + m_Type = type; + } + + public SnowGlobeTwo( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.WriteEncodedInt( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (SnowGlobeTypeTwo) reader.ReadEncodedInt(); + break; + } + } + } + } + + public enum SnowGlobeTypeThree + { + Luna, + Umbra, + Zento, + Heartwood, + Covetous, + Deceit, + Destard, + Hythloth, + Khaldun, + Shame, + Wrong, + Doom, + TheCitadel, + ThePalaceofParoxysmus, + TheBlightedGrove, + ThePrismofLight + } + + public class SnowGlobeThree : SnowGlobe + { + private SnowGlobeTypeThree m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public SnowGlobeTypeThree Place + { + get { return m_Type; } + set { m_Type = value; InvalidateProperties(); } + } + + public override int LabelNumber + { + get + { + if ( m_Type >= SnowGlobeTypeThree.Covetous ) + return 1075440 + ( (int) m_Type - 4 ); + + return 1075294 + (int) m_Type; + } + } + + [Constructable] + public SnowGlobeThree() + : this( (SnowGlobeTypeThree) Utility.Random( 16 ) ) + { + } + + [Constructable] + public SnowGlobeThree( SnowGlobeTypeThree type ) + { + m_Type = type; + } + + public SnowGlobeThree( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.WriteEncodedInt( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (SnowGlobeTypeThree) reader.ReadEncodedInt(); + break; + } + } + } + } +} diff --git a/Scripts/Items/Special/Holiday/SnowPiles.cs b/Scripts/Items/Special/Holiday/SnowPiles.cs new file mode 100644 index 0000000..a52f3d4 --- /dev/null +++ b/Scripts/Items/Special/Holiday/SnowPiles.cs @@ -0,0 +1,42 @@ +namespace Server.Items +{ + public class SnowPileDeco : Item + { + public override string DefaultName{ get { return "Snow Pile"; } } + public override double DefaultWeight{ get { return 2.0; } } + + private static readonly int[] m_Types = new int[] { 0x8E2, 0x8E0, 0x8E6, 0x8E5, 0x8E3 }; + + [Constructable] + public SnowPileDeco() + : this(m_Types[Utility.Random(m_Types.Length)]) + { + } + + [Constructable] + public SnowPileDeco( int itemid ) + : base(itemid) + { + Hue = 0x481; + } + + public SnowPileDeco(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/SnowStatue.cs b/Scripts/Items/Special/Holiday/SnowStatue.cs new file mode 100644 index 0000000..93fa08b --- /dev/null +++ b/Scripts/Items/Special/Holiday/SnowStatue.cs @@ -0,0 +1,246 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x456E, 0x456F )] + public class SnowStatuePegasus : Item + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + [Constructable] + public SnowStatuePegasus() + : base( 0x456E ) + { + } + + public SnowStatuePegasus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [Flipable( 0x4578, 0x4579 )] + public class SnowStatueSeahorse : Item + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + [Constructable] + public SnowStatueSeahorse() + : base( 0x4578 ) + { + } + + public SnowStatueSeahorse( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [Flipable( 0x457A, 0x457B )] + public class SnowStatueMermaid : Item + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + [Constructable] + public SnowStatueMermaid() + : base( 0x457A ) + { + } + + public SnowStatueMermaid( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + [Flipable( 0x457C, 0x457D )] + public class SnowStatueGriffon : Item + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + [Constructable] + public SnowStatueGriffon() + : base( 0x457C ) + { + } + + public SnowStatueGriffon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SnowStatueDeed : Item + { + public override int LabelNumber { get { return 1114296; } } // snow statue deed + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public SnowStatueDeed() + : base( 0x14F0 ) + { + LootType = LootType.Blessed; + } + + public SnowStatueDeed( Serial serial ) + : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + { + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class InternalGump : Gump + { + private SnowStatueDeed m_Deed; + + public InternalGump( SnowStatueDeed deed ) : base( 100, 200 ) + { + m_Deed = deed; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 360, 225, 0xA28 ); + + AddPage( 1 ); + AddLabel( 45, 15, 0, "Select One:" ); + + AddItem( 35, 75, 0x456E ); + AddButton( 65, 50, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + + AddItem( 120, 75, 0x4578 ); + AddButton( 135, 50, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + + AddItem( 190, 75, 0x457A ); + AddButton( 205, 50, 0x845, 0x846, 3, GumpButtonType.Reply, 0 ); + + AddItem( 250, 75, 0x457C ); + AddButton( 275, 50, 0x845, 0x846, 4, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed == null || m_Deed.Deleted ) + return; + + Mobile from = sender.Mobile; + + if ( !m_Deed.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it + return; + } + + Item statue = null; + + switch ( info.ButtonID ) + { + case 1: statue = new SnowStatuePegasus(); break; + case 2: statue = new SnowStatueSeahorse(); break; + case 3: statue = new SnowStatueMermaid(); break; + case 4: statue = new SnowStatueGriffon(); break; + } + + if ( statue == null ) + return; + + if ( !from.PlaceInBackpack( statue ) ) + { + statue.Delete(); + from.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + { + m_Deed.Delete(); + } + } + } + } +} diff --git a/Scripts/Items/Special/Holiday/Snowflakes.cs b/Scripts/Items/Special/Holiday/Snowflakes.cs new file mode 100644 index 0000000..2c8492a --- /dev/null +++ b/Scripts/Items/Special/Holiday/Snowflakes.cs @@ -0,0 +1,62 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class BlueSnowflake : Item + { + [Constructable] + public BlueSnowflake() : base( 0x232E ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public BlueSnowflake( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WhiteSnowflake : Item + { + [Constructable] + public WhiteSnowflake() : base( 0x232F ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public WhiteSnowflake( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/Snowman.cs b/Scripts/Items/Special/Holiday/Snowman.cs new file mode 100644 index 0000000..e186bde --- /dev/null +++ b/Scripts/Items/Special/Holiday/Snowman.cs @@ -0,0 +1,159 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x2328, 0x2329 )] + public class Snowman : Item, IDyable + { + public static string GetRandomTitle() + { + // All hail OSI staff + string[] titles = new string[] + { + /* 1 */ "Backflash", + /* 2 */ "Carbon", + /* 3 */ "Colbalistic", + /* 4 */ "Comforl", + /* 5 */ "Coppacchia", + /* 6 */ "Cyrus", + /* 7 */ "DannyB", + /* 8 */ "DJSoul", + /* 9 */ "DraconisRex", + /* 10 */ "Earia", + /* 11 */ "Foster", + /* 12 */ "Gonzo", + /* 13 */ "Haan", + /* 14 */ "Halona", + /* 15 */ "Hugo", + /* 16 */ "Hyacinth", + /* 17 */ "Imirian", + /* 18 */ "Jinsol", + /* 19 */ "Liciatia", + /* 20 */ "Loewen", + /* 21 */ "Loke", + /* 22 */ "Magnus", + /* 23 */ "Maleki", + /* 24 */ "Morpheus", + /* 25 */ "Obberron", + /* 26 */ "Odee", + /* 27 */ "Orbeus", + /* 28 */ "Pax", + /* 29 */ "Phields", + /* 30 */ "Pigpen", + /* 31 */ "Platinum", + /* 32 */ "Polpol", + /* 33 */ "Prume", + /* 34 */ "Quinnly", + /* 35 */ "Ragnarok", + /* 36 */ "Rend", + /* 37 */ "Roland", + /* 38 */ "RyanM", + /* 39 */ "Screach", + /* 40 */ "Seraph", + /* 41 */ "Silvani", + /* 42 */ "Sherbear", + /* 43 */ "SkyWalker", + /* 44 */ "Snark", + /* 45 */ "Sowl", + /* 46 */ "Spada", + /* 47 */ "Starblade", + /* 48 */ "Tenacious", + /* 49 */ "Tnez", + /* 50 */ "Wasia", + /* 51 */ "Zilo", + /* 52 */ "Zippy", + /* 53 */ "Zoer" + }; + + if ( titles.Length > 0 ) + return titles[Utility.Random( titles.Length )]; + + return null; + } + + private string m_Title; + + [CommandProperty( AccessLevel.GameMaster )] + public string Title + { + get{ return m_Title; } + set{ m_Title = value; InvalidateProperties(); } + } + + [Constructable] + public Snowman() : this( Utility.RandomDyedHue(), GetRandomTitle() ) + { + } + + [Constructable] + public Snowman( int hue ) : this( hue, GetRandomTitle() ) + { + } + + [Constructable] + public Snowman( string title ) : this( Utility.RandomDyedHue(), title ) + { + } + + [Constructable] + public Snowman( int hue, string title ) : base( Utility.Random( 0x2328, 2 ) ) + { + Weight = 10.0; + Hue = hue; + LootType = LootType.Blessed; + + m_Title = title; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Title != null ) + list.Add( 1062841, m_Title ); // ~1_NAME~ the Snowman + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public Snowman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (string) m_Title ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Title = reader.ReadString(); + break; + } + } + + Utility.Intern( ref m_Title ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/Stockings.cs b/Scripts/Items/Special/Holiday/Stockings.cs new file mode 100644 index 0000000..5d41e67 --- /dev/null +++ b/Scripts/Items/Special/Holiday/Stockings.cs @@ -0,0 +1,67 @@ +using System; +using Server; + +namespace Server.Items +{ + [Furniture] + [FlipableAttribute(0x2bd9, 0x2bda)] + public class GreenStocking : BaseContainer + { + public override int DefaultGumpID { get { return 0x103; } } + public override int DefaultDropSound { get { return 0x42; } } + + [Constructable] + public GreenStocking() + : base(Utility.Random(0x2BD9, 2)) + { + } + + public GreenStocking(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [Furniture] + [FlipableAttribute(0x2bdb, 0x2bdc)] + public class RedStocking : BaseContainer + { + public override int DefaultGumpID { get { return 0x103; } } + public override int DefaultDropSound { get { return 0x42; } } + + [Constructable] + public RedStocking() + : base(Utility.Random(0x2BDB, 2)) + { + } + + public RedStocking(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/WinterGiftPackage2003.cs b/Scripts/Items/Special/Holiday/WinterGiftPackage2003.cs new file mode 100644 index 0000000..32fa938 --- /dev/null +++ b/Scripts/Items/Special/Holiday/WinterGiftPackage2003.cs @@ -0,0 +1,37 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [Flipable( 0x232A, 0x232B )] + public class WinterGiftPackage2003 : GiftBox + { + [Constructable] + public WinterGiftPackage2003() + { + DropItem( new Snowman() ); + DropItem( new WreathDeed() ); + DropItem( new BlueSnowflake() ); + DropItem( new RedPoinsettia() ); + } + + public WinterGiftPackage2003( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/Wreath.cs b/Scripts/Items/Special/Holiday/Wreath.cs new file mode 100644 index 0000000..994182f --- /dev/null +++ b/Scripts/Items/Special/Holiday/Wreath.cs @@ -0,0 +1,328 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class WreathAddon : Item, IDyable, IAddon + { + [Constructable] + public WreathAddon() : this( Utility.RandomDyedHue() ) + { + } + + [Constructable] + public WreathAddon( int hue ) : base( 0x232C ) + { + Hue = hue; + Movable = false; + } + + public WreathAddon( Serial serial ) : base( serial ) + { + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( !map.CanFit( p.X, p.Y, p.Z, this.ItemData.Height ) ) + return false; + + if ( this.ItemID == 0x232C ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // North wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // West wall + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixMovingCrate ) ); + } + + private void FixMovingCrate() + { + if ( this.Deleted ) + return; + + if ( this.Movable || this.IsLockedDown ) + { + Item deed = this.Deed; + + if ( this.Parent is Item ) + { + ((Item)this.Parent).AddItem( deed ); + deed.Location = this.Location; + } + else + { + deed.MoveToWorld( this.Location, this.Map ); + } + + Delete(); + } + } + + public Item Deed + { + get{ return new WreathDeed( this.Hue ); } + } + + public override void OnDoubleClick( Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsCoOwner( from ) ) + { + if ( from.InRange( this.GetWorldLocation(), 3 ) ) + { + from.CloseGump( typeof( WreathAddonGump ) ); + from.SendGump( new WreathAddonGump( from, this ) ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + } + + public virtual bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsCoOwner( from ) ) + { + if ( from.InRange( GetWorldLocation(), 1 ) ) + { + Hue = sender.DyedHue; + return true; + } + else + { + from.SendLocalizedMessage( 500295 ); // You are too far away to do that. + return false; + } + } + else + { + return false; + } + } + + private class WreathAddonGump : Gump + { + private Mobile m_From; + private WreathAddon m_Addon; + + public WreathAddonGump( Mobile from, WreathAddon addon ) : base( 150, 50 ) + { + m_From = from; + m_Addon = addon; + + AddPage( 0 ); + + AddBackground( 0, 0, 220, 170, 0x13BE ); + AddBackground( 10, 10, 200, 150, 0xBB8 ); + AddHtmlLocalized( 20, 30, 180, 60, 1062839, false, false ); // Do you wish to re-deed this decoration? + AddHtmlLocalized( 55, 100, 160, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 100, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 125, 160, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 125, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Addon.Deleted ) + return; + + if ( info.ButtonID == 1 ) + { + if ( m_From.InRange( m_Addon.GetWorldLocation(), 3 ) ) + { + m_From.AddToBackpack( m_Addon.Deed ); + m_Addon.Delete(); + } + else + { + m_From.SendLocalizedMessage( 500295 ); // You are too far away to do that. + } + } + } + } + } + + [Flipable( 0x14F0, 0x14EF )] + public class WreathDeed : Item + { + public override int LabelNumber{ get{ return 1062837; } } // holiday wreath deed + + [Constructable] + public WreathDeed() : this( Utility.RandomDyedHue() ) + { + } + + [Constructable] + public WreathDeed( int hue ) : base( 0x14F0 ) + { + Weight = 1.0; + Hue = hue; + LootType = LootType.Blessed; + } + + public WreathDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsCoOwner( from ) ) + { + from.SendLocalizedMessage( 1062838 ); // Where would you like to place this decoration? + from.BeginTarget( -1, true, TargetFlags.None, new TargetStateCallback( Placement_OnTarget ), null ); + } + else + { + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public void Placement_OnTarget( Mobile from, object targeted, object state ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + + Point3D loc = new Point3D( p ); + + BaseHouse house = BaseHouse.FindHouseAt( loc, from.Map, 16 ); + + if ( house != null && house.IsCoOwner( from ) ) + { + bool northWall = BaseAddon.IsWall( loc.X, loc.Y - 1, loc.Z, from.Map ); + bool westWall = BaseAddon.IsWall( loc.X - 1, loc.Y, loc.Z, from.Map ); + + if ( northWall && westWall ) + from.SendGump( new WreathDeedGump( from, loc, this ) ); + else + PlaceAddon( from, loc, northWall, westWall ); + } + else + { + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + } + + private void PlaceAddon( Mobile from, Point3D loc, bool northWall, bool westWall ) + { + if ( Deleted ) + return; + + BaseHouse house = BaseHouse.FindHouseAt( loc, from.Map, 16 ); + + if ( house == null || !house.IsCoOwner( from ) ) + { + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + return; + } + + int itemID = 0; + + if ( northWall ) + itemID = 0x232C; + else if ( westWall ) + itemID = 0x232D; + else + from.SendLocalizedMessage( 1062840 ); // The decoration must be placed next to a wall. + + if ( itemID > 0 ) + { + Item addon = new WreathAddon( this.Hue ); + + addon.ItemID = itemID; + addon.MoveToWorld( loc, from.Map ); + + house.Addons.Add( addon ); + Delete(); + } + } + + private class WreathDeedGump : Gump + { + private Mobile m_From; + private Point3D m_Loc; + private WreathDeed m_Deed; + + public WreathDeedGump( Mobile from, Point3D loc, WreathDeed deed ) : base( 150, 50 ) + { + m_From = from; + m_Loc = loc; + m_Deed = deed; + + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddPage( 0 ); + + AddItem( 90, 30, 0x232D ); + AddItem( 180, 30, 0x232C ); + AddButton( 50, 35, 0x868, 0x869, 1, GumpButtonType.Reply, 0 ); + AddButton( 145, 35, 0x868, 0x869, 2, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed.Deleted ) + return; + + switch( info.ButtonID ) + { + case 1: + m_Deed.PlaceAddon( m_From, m_Loc, false, true ); + break; + case 2: + m_Deed.PlaceAddon( m_From, m_Loc, true, false ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Holiday/WristWatch.cs b/Scripts/Items/Special/Holiday/WristWatch.cs new file mode 100644 index 0000000..1e9509e --- /dev/null +++ b/Scripts/Items/Special/Holiday/WristWatch.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Items +{ + public class WristWatch : Clock + { + public override int LabelNumber { get { return 1041421; } } // a wrist watch + public override double DefaultWeight { get { return 1.0; } } + + [Constructable] + public WristWatch() + : base( 0x1086 ) + { + Weight = DefaultWeight; + LootType = LootType.Blessed; + Layer = Layer.Bracelet; + } + + public WristWatch( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/House Raffle/HouseRaffleDeed.cs b/Scripts/Items/Special/House Raffle/HouseRaffleDeed.cs new file mode 100644 index 0000000..62a6f9f --- /dev/null +++ b/Scripts/Items/Special/House Raffle/HouseRaffleDeed.cs @@ -0,0 +1,234 @@ +using System; +using Server; +using Server.Gumps; +using Server.Misc; + +namespace Server.Items +{ + public class HouseRaffleDeed : Item + { + private HouseRaffleStone m_Stone; + private Point3D m_PlotLocation; + private Map m_Facet; + private Mobile m_AwardedTo; + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Seer )] + public HouseRaffleStone Stone + { + get { return m_Stone; } + set { m_Stone = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Seer )] + public Point3D PlotLocation + { + get { return m_PlotLocation; } + set { m_PlotLocation = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Seer )] + public Map PlotFacet + { + get { return m_Facet; } + set { m_Facet = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Seer )] + public Mobile AwardedTo + { + get { return m_AwardedTo; } + set { m_AwardedTo = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Seer )] + public bool IsExpired + { + get { return ( m_Stone == null || m_Stone.Deleted || m_Stone.IsExpired ); } + } + + public override string DefaultName + { + get { return "a writ of lease"; } + } + + public override double DefaultWeight + { + get { return 1.0; } + } + + [Constructable] + public HouseRaffleDeed() + : this ( null, null ) + { + } + + public HouseRaffleDeed( HouseRaffleStone stone, Mobile m ) : base( 0x2830 ) + { + m_Stone = stone; + + if ( stone != null ) + { + m_PlotLocation = stone.GetPlotCenter(); + m_Facet = stone.PlotFacet; + } + + m_AwardedTo = m; + + LootType = LootType.Blessed; + Hue = 0x501; + } + + public HouseRaffleDeed( Serial serial ) + : base( serial ) + { + } + + public bool ValidLocation() + { + return ( m_PlotLocation != Point3D.Zero && m_Facet != null && m_Facet != Map.Internal ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( ValidLocation() ) + { + list.Add( 1060658, "location\t{0}", HouseRaffleStone.FormatLocation( m_PlotLocation, m_Facet, false ) ); // ~1_val~: ~2_val~ + list.Add( 1060659, "facet\t{0}", m_Facet ); // ~1_val~: ~2_val~ + list.Add( 1150486 ); // [Marked Item] + } + + if ( IsExpired ) + list.Add( 1150487 ); // [Expired] + + //list.Add( 1060660, "shard\t{0}", ServerList.ServerName ); // ~1_val~: ~2_val~ + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !ValidLocation() ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( WritOfLeaseGump ) ); + from.SendGump( new WritOfLeaseGump( this ) ); + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Stone ); + writer.Write( m_PlotLocation ); + writer.Write( m_Facet ); + writer.Write( m_AwardedTo ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Stone = reader.ReadItem(); + + goto case 0; + } + case 0: + { + m_PlotLocation = reader.ReadPoint3D(); + m_Facet = reader.ReadMap(); + m_AwardedTo = reader.ReadMobile(); + + break; + } + } + } + + private class WritOfLeaseGump : Gump + { + public WritOfLeaseGump( HouseRaffleDeed deed ) : base( 150, 50 ) + { + AddPage( 0 ); + + AddImage( 0, 0, 9380 ); + AddImage( 114, 0, 9381 ); + AddImage( 171, 0, 9382 ); + AddImage( 0, 140, 9383 ); + AddImage( 114, 140, 9384 ); + AddImage( 171, 140, 9385 ); + AddImage( 0, 182, 9383 ); + AddImage( 114, 182, 9384 ); + AddImage( 171, 182, 9385 ); + AddImage( 0, 224, 9383 ); + AddImage( 114, 224, 9384 ); + AddImage( 171, 224, 9385 ); + AddImage( 0, 266, 9386 ); + AddImage( 114, 266, 9387 ); + AddImage( 171, 266, 9388 ); + + AddHtmlLocalized( 30, 48, 229, 20, 1150484, 200, false, false ); // WRIT OF LEASE + AddHtml( 28, 75, 231, 280, FormatDescription( deed ), false, true ); + } + + private static string FormatDescription( HouseRaffleDeed deed ) + { + if ( deed == null ) + return String.Empty; + + if ( deed.IsExpired ) + { + return String.Format( + "" + + "This deed once entitled the bearer to build a house on the plot of land " + + "located at {0} on the {1} facet.

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

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

" + + + "The deed will expire after {2} more day{3} have passed, and at that time the right to place " + + "a house reverts to normal house construction rules.

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

" + + + "To place a house on the deeded plot, you must simply have this deed in your backpack " + + "or bank box when using a House Placement Tool there." + + "
", + HouseRaffleStone.FormatLocation( deed.PlotLocation, deed.PlotFacet, false ), + deed.PlotFacet, + daysLeft, + ( daysLeft == 1 ) ? "" : "s" + ); + } + } + } + } +} diff --git a/Scripts/Items/Special/House Raffle/HouseRaffleManagementGump.cs b/Scripts/Items/Special/House Raffle/HouseRaffleManagementGump.cs new file mode 100644 index 0000000..bbaa031 --- /dev/null +++ b/Scripts/Items/Special/House Raffle/HouseRaffleManagementGump.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Accounting; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Gumps +{ + public class HouseRaffleManagementGump : Gump + { + public enum SortMethod + { + Default, + Name, + Account, + Address + } + + public string Right( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + public const int LabelColor = 0xFFFFFF; + public const int HighlightColor = 0x11EE11; + + private HouseRaffleStone m_Stone; + private int m_Page; + private List m_List; + private SortMethod m_Sort; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + int buttonId = info.ButtonID; + + switch ( buttonId ) + { + case 1: // Previous + { + if ( m_Page > 0 ) + m_Page--; + + from.SendGump( new HouseRaffleManagementGump( m_Stone, m_Sort, m_Page ) ); + + break; + } + case 2: // Next + { + if ( (m_Page + 1) * 10 < m_Stone.Entries.Count ) + m_Page++; + + from.SendGump( new HouseRaffleManagementGump( m_Stone, m_Sort, m_Page ) ); + + break; + } + case 3: // Sort by name + { + from.SendGump( new HouseRaffleManagementGump( m_Stone, SortMethod.Name, 0 ) ); + + break; + } + case 4: // Sort by account + { + from.SendGump( new HouseRaffleManagementGump( m_Stone, SortMethod.Account, 0 ) ); + + break; + } + case 5: // Sort by address + { + from.SendGump( new HouseRaffleManagementGump( m_Stone, SortMethod.Address, 0 ) ); + + break; + } + default: // Delete + { + buttonId -= 6; + + if ( buttonId >= 0 && buttonId < m_List.Count ) + { + m_Stone.Entries.Remove( m_List[buttonId] ); + + if ( m_Page > 0 && m_Page * 10 >= m_List.Count - 1 ) + m_Page--; + + from.SendGump( new HouseRaffleManagementGump( m_Stone, m_Sort, m_Page ) ); + } + + break; + } + } + } + + public HouseRaffleManagementGump( HouseRaffleStone stone ) + : this( stone, SortMethod.Default, 0 ) + { + } + + public HouseRaffleManagementGump( HouseRaffleStone stone, SortMethod sort, int page ) : base( 40, 40 ) + { + m_Stone = stone; + m_Page = page; + + m_List = new List( m_Stone.Entries ); + m_Sort = sort; + + switch ( m_Sort ) + { + case SortMethod.Name: + { + m_List.Sort( NameComparer.Instance ); + + break; + } + case SortMethod.Account: + { + m_List.Sort( AccountComparer.Instance ); + + break; + } + case SortMethod.Address: + { + m_List.Sort( AddressComparer.Instance ); + + break; + } + } + + AddPage( 0 ); + + AddBackground( 0, 0, 618, 354, 9270 ); + AddAlphaRegion( 10, 10, 598, 334 ); + + AddHtml( 10, 10, 598, 20, Color( Center( "Raffle Management" ), LabelColor ), false, false ); + + AddHtml( 45, 35, 100, 20, Color( "Location:", LabelColor ), false, false ); + AddHtml( 145, 35, 250, 20, Color( m_Stone.FormatLocation(), LabelColor ), false, false ); + + AddHtml( 45, 55, 100, 20, Color( "Ticket Price:", LabelColor ), false, false ); + AddHtml( 145, 55, 250, 20, Color( m_Stone.FormatPrice(), LabelColor ), false, false ); + + AddHtml( 45, 75, 100, 20, Color( "Total Entries:", LabelColor ), false, false ); + AddHtml( 145, 75, 250, 20, Color( m_Stone.Entries.Count.ToString(), LabelColor ), false, false ); + + AddButton( 440, 33, 0xFA5, 0xFA7, 3, GumpButtonType.Reply, 0 ); + AddHtml( 474, 35, 120, 20, Color( "Sort by name", LabelColor ), false, false ); + + AddButton( 440, 53, 0xFA5, 0xFA7, 4, GumpButtonType.Reply, 0 ); + AddHtml( 474, 55, 120, 20, Color( "Sort by account", LabelColor ), false, false ); + + AddButton( 440, 73, 0xFA5, 0xFA7, 5, GumpButtonType.Reply, 0 ); + AddHtml( 474, 75, 120, 20, Color( "Sort by address", LabelColor ), false, false ); + + AddImageTiled( 13, 99, 592, 242, 9264 ); + AddImageTiled( 14, 100, 590, 240, 9274 ); + AddAlphaRegion( 14, 100, 590, 240 ); + + AddHtml( 14, 100, 590, 20, Color( Center( "Entries" ), LabelColor ), false, false ); + + if ( page > 0 ) + AddButton( 567, 104, 0x15E3, 0x15E7, 1, GumpButtonType.Reply, 0 ); + else + AddImage( 567, 104, 0x25EA ); + + if ( (page + 1) * 10 < m_List.Count ) + AddButton( 584, 104, 0x15E1, 0x15E5, 2, GumpButtonType.Reply, 0 ); + else + AddImage( 584, 104, 0x25E6 ); + + AddHtml( 14, 120, 30, 20, Color( Center( "DEL" ), LabelColor ), false, false ); + AddHtml( 47, 120, 250, 20, Color( "Name", LabelColor ), false, false ); + AddHtml( 295, 120, 100, 20, Color( Center( "Address" ), LabelColor ), false, false ); + AddHtml( 395, 120, 150, 20, Color( Center( "Date" ), LabelColor ), false, false ); + AddHtml( 545, 120, 60, 20, Color( Center( "Num" ), LabelColor ), false, false ); + + int idx = 0; + Mobile winner = m_Stone.Winner; + + for ( int i = page * 10; i >= 0 && i < m_List.Count && i < (page + 1) * 10; ++i, ++idx ) + { + RaffleEntry entry = m_List[i]; + + if ( entry == null ) + continue; + + AddButton( 13, 138 + (idx * 20), 4002, 4004, 6 + i, GumpButtonType.Reply, 0 ); + + int x = 45; + int color = ( winner != null && entry.From == winner ) ? HighlightColor : LabelColor; + + string name = null; + + if ( entry.From != null ) + { + Account acc = entry.From.Account as Account; + + if ( acc != null ) + name = String.Format( "{0} ({1})", entry.From.Name, acc ); + else + name = entry.From.Name; + } + + if ( name != null ) + AddHtml( x + 2, 140 + (idx * 20), 250, 20, Color( name, color ), false, false ); + + x += 250; + + if ( entry.Address != null ) + AddHtml( x, 140 + (idx * 20), 100, 20, Color( Center( entry.Address.ToString() ), color ), false, false ); + + x += 100; + + AddHtml( x, 140 + (idx * 20), 150, 20, Color( Center( entry.Date.ToString() ), color ), false, false ); + x += 150; + + AddHtml( x, 140 + (idx * 20), 60, 20, Color( Center( "1" ), color ), false, false ); + x += 60; + } + } + + private class NameComparer : IComparer + { + public static readonly IComparer Instance = new NameComparer(); + + public NameComparer() + { + } + + public int Compare( RaffleEntry x, RaffleEntry y ) + { + bool xIsNull = ( x == null || x.From == null ); + bool yIsNull = ( y == null || y.From == null ); + + if ( xIsNull && yIsNull ) + return 0; + else if ( xIsNull ) + return -1; + else if ( yIsNull ) + return 1; + + int result = Insensitive.Compare( x.From.Name, y.From.Name ); + + if ( result == 0 ) + return x.Date.CompareTo( y.Date ); + else + return result; + } + } + + private class AccountComparer : IComparer + { + public static readonly IComparer Instance = new AccountComparer(); + + public AccountComparer() + { + } + + public int Compare( RaffleEntry x, RaffleEntry y ) + { + bool xIsNull = ( x == null || x.From == null ); + bool yIsNull = ( y == null || y.From == null ); + + if ( xIsNull && yIsNull ) + return 0; + else if ( xIsNull ) + return -1; + else if ( yIsNull ) + return 1; + + Account a = x.From.Account as Account; + Account b = y.From.Account as Account; + + if ( a == null && b == null ) + return 0; + else if ( a == null ) + return -1; + else if ( b == null ) + return 1; + + int result = Insensitive.Compare( a.Username, b.Username ); + + if ( result == 0 ) + return x.Date.CompareTo( y.Date ); + else + return result; + } + } + + private class AddressComparer : IComparer + { + public static readonly IComparer Instance = new AddressComparer(); + + public AddressComparer() + { + } + + public int Compare( RaffleEntry x, RaffleEntry y ) + { + bool xIsNull = ( x == null || x.Address == null ); + bool yIsNull = ( y == null || y.Address == null ); + + if ( xIsNull && yIsNull ) + return 0; + else if ( xIsNull ) + return -1; + else if ( yIsNull ) + return 1; + + byte[] a = x.Address.GetAddressBytes(); + byte[] b = y.Address.GetAddressBytes(); + + for ( int i = 0; i < a.Length && i < b.Length; i++ ) + { + int compare = a[i].CompareTo( b[i] ); + + if ( compare != 0 ) + return compare; + } + + return x.Date.CompareTo( y.Date ); + } + } + } +} diff --git a/Scripts/Items/Special/House Raffle/HouseRaffleRegion.cs b/Scripts/Items/Special/House Raffle/HouseRaffleRegion.cs new file mode 100644 index 0000000..dc70c3f --- /dev/null +++ b/Scripts/Items/Special/House Raffle/HouseRaffleRegion.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Accounting; +using Server.Items; +using Server.Spells.Sixth; +using Server.Targeting; + +namespace Server.Regions +{ + public class HouseRaffleRegion : BaseRegion + { + private HouseRaffleStone m_Stone; + + public HouseRaffleRegion( HouseRaffleStone stone ) + : base( null, stone.PlotFacet, Region.DefaultPriority, stone.PlotBounds ) + { + m_Stone = stone; + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + if ( m_Stone == null ) + return false; + + if ( m_Stone.IsExpired ) + return true; + + if ( m_Stone.Deed == null ) + return false; + + Container pack = from.Backpack; + + if ( pack != null && ContainsDeed( pack ) ) + return true; + + BankBox bank = from.FindBankNoCreate(); + + if ( bank != null && ContainsDeed( bank ) ) + return true; + + return false; + } + + private bool ContainsDeed( Container cont ) + { + List deeds = cont.FindItemsByType(); + + for ( int i = 0; i < deeds.Count; ++i ) + { + if ( deeds[i] == m_Stone.Deed ) + return true; + } + + return false; + } + + public override bool OnTarget( Mobile m, Target t, object o ) + { + if ( m.Spell != null && m.Spell is MarkSpell && m.AccessLevel == AccessLevel.Player ) + { + m.SendLocalizedMessage( 501800 ); // You cannot mark an object at that location. + return false; + } + + return base.OnTarget( m, t, o ); + } + } +} diff --git a/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs b/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs new file mode 100644 index 0000000..b81f0e4 --- /dev/null +++ b/Scripts/Items/Special/House Raffle/HouseRaffleStone.cs @@ -0,0 +1,728 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; +using Server; +using Server.Accounting; +using Server.ContextMenus; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + public class RaffleEntry + { + private Mobile m_From; + private IPAddress m_Address; + private DateTime m_Date; + + public Mobile From + { + get { return m_From; } + } + + public IPAddress Address + { + get { return m_Address; } + } + + public DateTime Date + { + get { return m_Date; } + } + + public RaffleEntry(Mobile from) + { + m_From = from; + + if (m_From.NetState != null) + m_Address = m_From.NetState.Address; + else + m_Address = IPAddress.None; + + m_Date = DateTime.Now; + } + + public void Serialize(GenericWriter writer) + { + writer.Write(m_From); + writer.Write(m_Address); + writer.Write(m_Date); + } + + public RaffleEntry(GenericReader reader, int version) + { + switch (version) + { + case 3: // HouseRaffleStone version changes + case 2: + case 1: + case 0: + { + m_From = reader.ReadMobile(); + m_Address = Utility.Intern(reader.ReadIPAddress()); + m_Date = reader.ReadDateTime(); + + break; + } + } + } + } + + public enum HouseRaffleState + { + Inactive, + Active, + Completed + } + + public enum HouseRaffleExpireAction + { + None, + HideStone, + DeleteStone + } + + [FlipableAttribute(0xEDD, 0xEDE)] + public class HouseRaffleStone : Item + { + private const int EntryLimitPerIP = 4; + private const int DefaultTicketPrice = 5000; + private const int MessageHue = 1153; + + public static readonly TimeSpan DefaultDuration = TimeSpan.FromDays(7.0); + public static readonly TimeSpan ExpirationTime = TimeSpan.FromDays(30.0); + + private HouseRaffleRegion m_Region; + private Rectangle2D m_Bounds; + private Map m_Facet; + + private Mobile m_Winner; + private HouseRaffleDeed m_Deed; + + private HouseRaffleState m_State; + private DateTime m_Started; + private TimeSpan m_Duration; + private HouseRaffleExpireAction m_ExpireAction; + private int m_TicketPrice; + + private List m_Entries; + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleState CurrentState + { + get { return m_State; } + set + { + if (m_State != value) + { + if (value == HouseRaffleState.Active) + { + m_Entries.Clear(); + m_Winner = null; + m_Deed = null; + m_Started = DateTime.Now; + } + + m_State = value; + InvalidateProperties(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Rectangle2D PlotBounds + { + get { return m_Bounds; } + set + { + m_Bounds = value; + + InvalidateRegion(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Map PlotFacet + { + get { return m_Facet; } + set + { + m_Facet = value; + + InvalidateRegion(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public Mobile Winner + { + get { return m_Winner; } + set { m_Winner = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleDeed Deed + { + get { return m_Deed; } + set { m_Deed = value; } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public DateTime Started + { + get { return m_Started; } + set { m_Started = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public TimeSpan Duration + { + get { return m_Duration; } + set { m_Duration = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsExpired + { + get + { + if (m_State != HouseRaffleState.Completed) + return false; + + return (m_Started + m_Duration + ExpirationTime <= DateTime.Now); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public HouseRaffleExpireAction ExpireAction + { + get { return m_ExpireAction; } + set { m_ExpireAction = value; } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Seer)] + public int TicketPrice + { + get { return m_TicketPrice; } + set + { + m_TicketPrice = Math.Max(0, value); + InvalidateProperties(); + } + } + + public List Entries + { + get { return m_Entries; } + } + + public override string DefaultName + { + get { return "a house raffle stone"; } + } + + public override bool DisplayWeight + { + get { return false; } + } + + private static List m_AllStones = new List(); + + public static void CheckEnd_OnTick() + { + for (int i = 0; i < m_AllStones.Count; i++) + m_AllStones[i].CheckEnd(); + } + + public static void Initialize() + { + for (int i = m_AllStones.Count - 1; i >= 0; i--) + { + HouseRaffleStone stone = m_AllStones[i]; + + if (stone.IsExpired) + { + switch (stone.ExpireAction) + { + case HouseRaffleExpireAction.HideStone: + { + if (stone.Visible) + { + stone.Visible = false; + stone.ItemID = 0x1B7B; // Non-blocking ItemID + } + + break; + } + case HouseRaffleExpireAction.DeleteStone: + { + stone.Delete(); + break; + } + } + } + } + + Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0), new TimerCallback(CheckEnd_OnTick)); + } + + [Constructable] + public HouseRaffleStone() + : base(0xEDD) + { + m_Region = null; + m_Bounds = new Rectangle2D(); + m_Facet = null; + + m_Winner = null; + m_Deed = null; + + m_State = HouseRaffleState.Inactive; + m_Started = DateTime.MinValue; + m_Duration = DefaultDuration; + m_ExpireAction = HouseRaffleExpireAction.None; + m_TicketPrice = DefaultTicketPrice; + + m_Entries = new List(); + + Movable = false; + + m_AllStones.Add(this); + } + + public HouseRaffleStone(Serial serial) + : base(serial) + { + } + + public bool ValidLocation() + { + return (m_Bounds.Start != Point2D.Zero && m_Bounds.End != Point2D.Zero && m_Facet != null && m_Facet != Map.Internal); + } + + private void InvalidateRegion() + { + if (m_Region != null) + { + m_Region.Unregister(); + m_Region = null; + } + + if (ValidLocation()) + { + m_Region = new HouseRaffleRegion(this); + m_Region.Register(); + } + } + + private bool HasEntered(Mobile from) + { + Account acc = from.Account as Account; + + if (acc == null) + return false; + + foreach (RaffleEntry entry in m_Entries) + { + if (entry.From != null) + { + Account entryAcc = entry.From.Account as Account; + + if (entryAcc == acc) + return true; + } + } + + return false; + } + + private bool IsAtIPLimit(Mobile from) + { + if (from.NetState == null) + return false; + + IPAddress address = from.NetState.Address; + int tickets = 0; + + foreach (RaffleEntry entry in m_Entries) + { + if (Utility.IPMatchClassC(entry.Address, address)) + { + if (++tickets >= EntryLimitPerIP) + return true; + } + } + + return false; + } + + public static string FormatLocation(Point3D loc, Map map, bool displayMap) + { + StringBuilder result = new StringBuilder(); + + int xLong = 0, yLat = 0; + int xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + if (Sextant.Format(loc, map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth)) + result.AppendFormat("{0}�{1}'{2},{3}�{4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W"); + else + result.AppendFormat("{0},{1}", loc.X, loc.Y); + + if (displayMap) + result.AppendFormat(" ({0})", map); + + return result.ToString(); + } + + public Point3D GetPlotCenter() + { + int x = m_Bounds.X + m_Bounds.Width / 2; + int y = m_Bounds.Y + m_Bounds.Height / 2; + int z = (m_Facet == null) ? 0 : m_Facet.GetAverageZ(x, y); + + return new Point3D(x, y, z); + } + + public string FormatLocation() + { + if (!ValidLocation()) + return "no location set"; + + return FormatLocation(GetPlotCenter(), m_Facet, true); + } + + public string FormatPrice() + { + if (m_TicketPrice == 0) + return "FREE"; + else + return String.Format("{0} gold", m_TicketPrice); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (ValidLocation()) + list.Add(FormatLocation()); + + switch (m_State) + { + case HouseRaffleState.Active: + { + list.Add(1060658, "ticket price\t{0}", FormatPrice()); // ~1_val~: ~2_val~ + list.Add(1060659, "ends\t{0}", m_Started + m_Duration); // ~1_val~: ~2_val~ + break; + } + case HouseRaffleState.Completed: + { + list.Add(1060658, "winner\t{0}", (m_Winner == null) ? "unknown" : m_Winner.Name); // ~1_val~: ~2_val~ + break; + } + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + switch (m_State) + { + case HouseRaffleState.Active: + { + LabelTo(from, 1060658, String.Format("Ends\t{0}", m_Started + m_Duration)); // ~1_val~: ~2_val~ + break; + } + case HouseRaffleState.Completed: + { + LabelTo(from, 1060658, String.Format("Winner\t{0}", (m_Winner == null) ? "Unknown" : m_Winner.Name)); // ~1_val~: ~2_val~ + break; + } + } + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.AccessLevel >= AccessLevel.Seer) + { + list.Add(new EditEntry(from, this)); + + if (m_State == HouseRaffleState.Inactive) + list.Add(new ActivateEntry(from, this)); + else + list.Add(new ManagementEntry(from, this)); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (m_State != HouseRaffleState.Active || !from.CheckAlive()) + return; + + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return; + } + + if (HasEntered(from)) + { + from.SendMessage(MessageHue, "You have already entered this plot's raffle."); + } + else if (IsAtIPLimit(from)) + { + from.SendMessage(MessageHue, "You may not enter this plot's raffle."); + } + else + { + from.SendGump(new WarningGump(1150470, 0x7F00, String.Format("You are about to purchase a raffle ticket for the house plot located at {0}. The ticket price is {1}. Tickets are non-refundable and you can only purchase one ticket per account. Do you wish to continue?", FormatLocation(), FormatPrice()), 0xFFFFFF, 420, 280, new WarningGumpCallback(Purchase_Callback), null)); // CONFIRM TICKET PURCHASE + } + } + + public void Purchase_Callback(Mobile from, bool okay, object state) + { + if (Deleted || m_State != HouseRaffleState.Active || !from.CheckAlive() || HasEntered(from) || IsAtIPLimit(from)) + return; + + Account acc = from.Account as Account; + + if (acc == null) + return; + + if (okay) + { + Container bank = from.FindBankNoCreate(); + + if (m_TicketPrice == 0 || (from.Backpack != null && from.Backpack.ConsumeTotal(typeof(Gold), m_TicketPrice)) || (bank != null && bank.ConsumeTotal(typeof(Gold), m_TicketPrice))) + { + m_Entries.Add(new RaffleEntry(from)); + + from.SendMessage(MessageHue, "You have successfully entered the plot's raffle."); + } + else + { + from.SendMessage(MessageHue, "You do not have the {0} required to enter the raffle.", FormatPrice()); + } + } + else + { + from.SendMessage(MessageHue, "You have chosen not to enter the raffle."); + } + } + + public void CheckEnd() + { + if (m_State != HouseRaffleState.Active || m_Started + m_Duration > DateTime.Now) + return; + + m_State = HouseRaffleState.Completed; + + if (m_Region != null && m_Entries.Count != 0) + { + int winner = Utility.Random(m_Entries.Count); + + m_Winner = m_Entries[winner].From; + + if (m_Winner != null) + { + m_Deed = new HouseRaffleDeed(this, m_Winner); + + m_Winner.SendMessage(MessageHue, "Congratulations, {0}! You have won the raffle for the plot located at {1}.", m_Winner.Name, FormatLocation()); + + if (m_Winner.AddToBackpack(m_Deed)) + { + m_Winner.SendMessage(MessageHue, "The writ of lease has been placed in your backpack."); + } + else + { + m_Winner.BankBox.DropItem(m_Deed); + m_Winner.SendMessage(MessageHue, "As your backpack is full, the writ of lease has been placed in your bank box."); + } + } + } + + InvalidateProperties(); + } + + public override void OnDelete() + { + if (m_Region != null) + { + m_Region.Unregister(); + m_Region = null; + } + + m_AllStones.Remove(this); + + base.OnDelete(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)3); // version + + writer.WriteEncodedInt((int)m_State); + writer.WriteEncodedInt((int)m_ExpireAction); + + writer.Write(m_Deed); + + writer.Write(m_Bounds); + writer.Write(m_Facet); + + writer.Write(m_Winner); + + writer.Write(m_TicketPrice); + writer.Write(m_Started); + writer.Write(m_Duration); + + writer.Write(m_Entries.Count); + + foreach (RaffleEntry entry in m_Entries) + entry.Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_State = (HouseRaffleState)reader.ReadEncodedInt(); + + goto case 2; + } + case 2: + { + m_ExpireAction = (HouseRaffleExpireAction)reader.ReadEncodedInt(); + + goto case 1; + } + case 1: + { + m_Deed = reader.ReadItem(); + + goto case 0; + } + case 0: + { + bool oldActive = (version < 3) ? reader.ReadBool() : false; + + m_Bounds = reader.ReadRect2D(); + m_Facet = reader.ReadMap(); + + m_Winner = reader.ReadMobile(); + + m_TicketPrice = reader.ReadInt(); + m_Started = reader.ReadDateTime(); + m_Duration = reader.ReadTimeSpan(); + + int entryCount = reader.ReadInt(); + m_Entries = new List(entryCount); + + for (int i = 0; i < entryCount; i++) + { + RaffleEntry entry = new RaffleEntry(reader, version); + + if (entry.From == null) + continue; // Character was deleted + + m_Entries.Add(entry); + } + + InvalidateRegion(); + + m_AllStones.Add(this); + + if (version < 3) + { + if (oldActive) + m_State = HouseRaffleState.Active; + else if (m_Winner != null) + m_State = HouseRaffleState.Completed; + else + m_State = HouseRaffleState.Inactive; + } + + break; + } + } + } + + private class RaffleContextMenuEntry : ContextMenuEntry + { + protected Mobile m_From; + protected HouseRaffleStone m_Stone; + + public RaffleContextMenuEntry(Mobile from, HouseRaffleStone stone, int label) + : base(label) + { + m_From = from; + m_Stone = stone; + } + } + + private class EditEntry : RaffleContextMenuEntry + { + public EditEntry(Mobile from, HouseRaffleStone stone) + : base(from, stone, 5101) // Edit + { + } + + public override void OnClick() + { + if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer) + return; + + m_From.SendGump(new PropertiesGump(m_From, m_Stone)); + } + } + + private class ActivateEntry : RaffleContextMenuEntry + { + public ActivateEntry(Mobile from, HouseRaffleStone stone) + : base(from, stone, 5113) // Start + { + if (!stone.ValidLocation()) + Flags |= Network.CMEFlags.Disabled; + } + + public override void OnClick() + { + if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer || !m_Stone.ValidLocation()) + return; + + m_Stone.CurrentState = HouseRaffleState.Active; + } + } + + private class ManagementEntry : RaffleContextMenuEntry + { + public ManagementEntry(Mobile from, HouseRaffleStone stone) + : base(from, stone, 5032) // Game Monitor + { + } + + public override void OnClick() + { + if (m_Stone.Deleted || m_From.AccessLevel < AccessLevel.Seer) + return; + + m_From.SendGump(new HouseRaffleManagementGump(m_Stone)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/ML/BaseImprisonedMobile.cs b/Scripts/Items/Special/ML/BaseImprisonedMobile.cs new file mode 100644 index 0000000..cf61a3d --- /dev/null +++ b/Scripts/Items/Special/ML/BaseImprisonedMobile.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Items +{ + public abstract class BaseImprisonedMobile : Item + { + public abstract BaseCreature Summon{ get; } + + [Constructable] + public BaseImprisonedMobile( int itemID ) : base( itemID ) + { + } + + public BaseImprisonedMobile( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + from.SendGump( new ConfirmBreakCrystalGump( this ) ); + else + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public virtual void Release( Mobile from, BaseCreature summon ) + { + } + } +} + diff --git a/Scripts/Items/Special/ML/GrizzledMareStatuette.cs b/Scripts/Items/Special/ML/GrizzledMareStatuette.cs new file mode 100644 index 0000000..545521a --- /dev/null +++ b/Scripts/Items/Special/ML/GrizzledMareStatuette.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class GrizzledMareStatuette : BaseImprisonedMobile + { + public override int LabelNumber { get { return 1074475; } } // Grizzled Mare Statuette + public override BaseCreature Summon { get { return new GrizzledMare(); } } + + [Constructable] + public GrizzledMareStatuette() + : base(0x2617) + { + Weight = 1.0; + } + + public GrizzledMareStatuette(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} + +namespace Server.Mobiles +{ + public class GrizzledMare : HellSteed + { + public override bool DeleteOnRelease { get { return true; } } + + private static readonly string m_Myname = "a grizzled mare"; + + [Constructable] + public GrizzledMare() + : base(m_Myname) + { + } + + public virtual void OnAfterDeserialize_Callback() + { + HellSteed.SetStats(this); + + Name = m_Myname; + } + + public GrizzledMare(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1) + { + Timer.DelayCall(TimeSpan.FromSeconds(0), new TimerCallback(OnAfterDeserialize_Callback)); + } + } + } +} diff --git a/Scripts/Items/Special/ML/MinotaurHedge.cs b/Scripts/Items/Special/ML/MinotaurHedge.cs new file mode 100644 index 0000000..6f135e1 --- /dev/null +++ b/Scripts/Items/Special/ML/MinotaurHedge.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MinotaurHedge : Item + { + + [Constructable] + public MinotaurHedge() : base( Utility.Random( 3215, 4 ) ) + { + Name = "minotaur hedge"; + Weight = 1.0; + } + + public MinotaurHedge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Special/ML/TormentedChains.cs b/Scripts/Items/Special/ML/TormentedChains.cs new file mode 100644 index 0000000..363fb83 --- /dev/null +++ b/Scripts/Items/Special/ML/TormentedChains.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TormentedChains : Item + { + + [Constructable] + public TormentedChains() : base( Utility.Random( 6663, 2 ) ) + { + Name = "chains of the tormented"; + Weight = 1.0; + } + + public TormentedChains( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Special/MiniHouses.cs b/Scripts/Items/Special/MiniHouses.cs new file mode 100644 index 0000000..f1e49d8 --- /dev/null +++ b/Scripts/Items/Special/MiniHouses.cs @@ -0,0 +1,237 @@ +using System; +using Server; + +namespace Server.Items +{ + public class MiniHouseAddon : BaseAddon + { + private MiniHouseType m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public MiniHouseType Type + { + get{ return m_Type; } + set{ m_Type = value; Construct(); } + } + + public override BaseAddonDeed Deed{ get{ return new MiniHouseDeed( m_Type ); } } + + [Constructable] + public MiniHouseAddon() : this( MiniHouseType.StoneAndPlaster ) + { + } + + [Constructable] + public MiniHouseAddon( MiniHouseType type ) + { + m_Type = type; + + Construct(); + } + + public void Construct() + { + foreach ( AddonComponent c in Components ) + { + c.Addon = null; + c.Delete(); + } + + Components.Clear(); + + MiniHouseInfo info = MiniHouseInfo.GetInfo( m_Type ); + + int size = (int)Math.Sqrt( info.Graphics.Length ); + int num = 0; + + for ( int y = 0; y < size; ++y ) + for ( int x = 0; x < size; ++x ) + if ( info.Graphics[num] != 0x1 ) // Veteran Rewards Mod + AddComponent( new AddonComponent( info.Graphics[num++] ), size - x - 1, size - y - 1, 0 ); + } + + public MiniHouseAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (MiniHouseType)reader.ReadInt(); + break; + } + } + } + } + + public class MiniHouseDeed : BaseAddonDeed + { + private MiniHouseType m_Type; + + [CommandProperty( AccessLevel.GameMaster )] + public MiniHouseType Type + { + get{ return m_Type; } + set{ m_Type = value; InvalidateProperties(); } + } + + public override BaseAddon Addon{ get{ return new MiniHouseAddon( m_Type ); } } + public override int LabelNumber{ get{ return 1062096; } } // a mini house deed + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( MiniHouseInfo.GetInfo( m_Type ).LabelNumber ); + } + + [Constructable] + public MiniHouseDeed() : this( MiniHouseType.StoneAndPlaster ) + { + } + + [Constructable] + public MiniHouseDeed( MiniHouseType type ) + { + m_Type = type; + + Weight = 1.0; + LootType = LootType.Blessed; + } + + public MiniHouseDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Type ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (MiniHouseType)reader.ReadInt(); + break; + } + } + + if ( Weight == 0.0 ) + Weight = 1.0; + } + } + + public enum MiniHouseType + { + StoneAndPlaster, + FieldStone, + SmallBrick, + Wooden, + WoodAndPlaster, + ThatchedRoof, + Brick, + TwoStoryWoodAndPlaster, + TwoStoryStoneAndPlaster, + Tower, + SmallStoneKeep, + Castle, + LargeHouseWithPatio, + MarbleHouseWithPatio, + SmallStoneTower, + TwoStoryLogCabin, + TwoStoryVilla, + SandstoneHouseWithPatio, + SmallStoneWorkshop, + SmallMarbleWorkshop, + MalasMountainPass, //Veteran reward house + ChurchAtNight //Veteran reward house + } + + public class MiniHouseInfo + { + private int[] m_Graphics; + private int m_LabelNumber; + + public int[] Graphics{ get{ return m_Graphics; } } + public int LabelNumber{ get{ return m_LabelNumber; } } + + public MiniHouseInfo( int start, int count, int labelNumber ) + { + m_Graphics = new int[count]; + + for ( int i = 0; i < count; ++i ) + m_Graphics[i] = start + i; + + m_LabelNumber = labelNumber; + } + + public MiniHouseInfo( int labelNumber, params int[] graphics ) + { + m_LabelNumber = labelNumber; + m_Graphics = graphics; + } + + private static MiniHouseInfo[] m_Info = new MiniHouseInfo[] + { + /* Stone and plaster house */ new MiniHouseInfo( 0x22C4, 1, 1011303 ), + /* Field stone house */ new MiniHouseInfo( 0x22DE, 1, 1011304 ), + /* Small brick house */ new MiniHouseInfo( 0x22DF, 1, 1011305 ), + /* Wooden house */ new MiniHouseInfo( 0x22C9, 1, 1011306 ), + /* Wood and plaster house */ new MiniHouseInfo( 0x22E0, 1, 1011307 ), + /* Thatched-roof cottage */ new MiniHouseInfo( 0x22E1, 1, 1011308 ), + /* Brick house */ new MiniHouseInfo( 1011309, 0x22CD, 0x22CB, 0x22CC, 0x22CA ), + /* Two-story wood and plaster house */ new MiniHouseInfo( 1011310, 0x2301, 0x2302, 0x2304, 0x2303 ), + /* Two-story stone and plaster house */ new MiniHouseInfo( 1011311, 0x22FC, 0x22FD, 0x22FF, 0x22FE ), + /* Tower */ new MiniHouseInfo( 1011312, 0x22F7, 0x22F8, 0x22FA, 0x22F9 ), + /* Small stone keep */ new MiniHouseInfo( 0x22E6, 9, 1011313 ), + /* Castle */ new MiniHouseInfo( 1011314, 0x22CE, 0x22D0, 0x22D2, 0x22D7, 0x22CF, 0x22D1, 0x22D4, 0x22D9, 0x22D3, 0x22D5, 0x22D6, 0x22DB, 0x22D8, 0x22DA, 0x22DC, 0x22DD ), + /* Large house with patio */ new MiniHouseInfo( 0x22E2, 4, 1011315 ), + /* Marble house with patio */ new MiniHouseInfo( 0x22EF, 4, 1011316 ), + /* Small stone tower */ new MiniHouseInfo( 0x22F5, 1, 1011317 ), + /* Two-story log cabin */ new MiniHouseInfo( 0x22FB, 1, 1011318 ), + /* Two-story villa */ new MiniHouseInfo( 0x2300, 1, 1011319 ), + /* Sandstone house with patio */ new MiniHouseInfo( 0x22F3, 1, 1011320 ), + /* Small stone workshop */ new MiniHouseInfo( 0x22F6, 1, 1011321 ), + /* Small marble workshop */ new MiniHouseInfo( 0x22F4, 1, 1011322 ), + /* Malas Mountain Pass */ new MiniHouseInfo( 1062692, 0x2316, 0x2315, 0x2314, 0x2313 ), + /* Church At Night */ new MiniHouseInfo( 1072215, 0x2318, 0x2317, 0x2319, 0x1 ) + }; + + public static MiniHouseInfo GetInfo( MiniHouseType type ) + { + int v = (int)type; + + if ( v < 0 || v >= m_Info.Length ) + v = 0; + + return m_Info[v]; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/MonsterStatuette.cs b/Scripts/Items/Special/MonsterStatuette.cs new file mode 100644 index 0000000..cbdf0a9 --- /dev/null +++ b/Scripts/Items/Special/MonsterStatuette.cs @@ -0,0 +1,323 @@ +using System; +using Server; +using Server.Multis; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public enum MonsterStatuetteType + { + Crocodile, + Daemon, + Dragon, + EarthElemental, + Ettin, + Gargoyle, + Gorilla, + Lich, + Lizardman, + Ogre, + Orc, + Ratman, + Skeleton, + Troll, + Cow, + Zombie, + Llama, + Ophidian, + Reaper, + Mongbat, + Gazer, + FireElemental, + Wolf, + PhillipsWoodenSteed, + Seahorse, + Harrower, + Efreet, + Slime, + PlagueBeast, + RedDeath, + Spider, + OphidianArchMage, + OphidianWarrior, + OphidianKnight, + OphidianMage, + DreadHorn, + Minotaur, + BlackCat, + HalloweenGhoul, + Santa + } + + public class MonsterStatuetteInfo + { + private int m_LabelNumber; + private int m_ItemID; + private int[] m_Sounds; + + public int LabelNumber{ get{ return m_LabelNumber; } } + public int ItemID{ get{ return m_ItemID; } } + public int[] Sounds{ get{ return m_Sounds; } } + + public MonsterStatuetteInfo( int labelNumber, int itemID, int baseSoundID ) + { + m_LabelNumber = labelNumber; + m_ItemID = itemID; + m_Sounds = new int[]{ baseSoundID, baseSoundID + 1, baseSoundID + 2, baseSoundID + 3, baseSoundID + 4 }; + } + + public MonsterStatuetteInfo( int labelNumber, int itemID, int[] sounds ) + { + m_LabelNumber = labelNumber; + m_ItemID = itemID; + m_Sounds = sounds; + } + + private static MonsterStatuetteInfo[] m_Table = new MonsterStatuetteInfo[] + { + /* Crocodile */ new MonsterStatuetteInfo( 1041249, 0x20DA, 660 ), + /* Daemon */ new MonsterStatuetteInfo( 1041250, 0x20D3, 357 ), + /* Dragon */ new MonsterStatuetteInfo( 1041251, 0x20D6, 362 ), + /* EarthElemental */ new MonsterStatuetteInfo( 1041252, 0x20D7, 268 ), + /* Ettin */ new MonsterStatuetteInfo( 1041253, 0x20D8, 367 ), + /* Gargoyle */ new MonsterStatuetteInfo( 1041254, 0x20D9, 372 ), + /* Gorilla */ new MonsterStatuetteInfo( 1041255, 0x20F5, 158 ), + /* Lich */ new MonsterStatuetteInfo( 1041256, 0x20F8, 1001 ), + /* Lizardman */ new MonsterStatuetteInfo( 1041257, 0x20DE, 417 ), + /* Ogre */ new MonsterStatuetteInfo( 1041258, 0x20DF, 427 ), + /* Orc */ new MonsterStatuetteInfo( 1041259, 0x20E0, 1114 ), + /* Ratman */ new MonsterStatuetteInfo( 1041260, 0x20E3, 437 ), + /* Skeleton */ new MonsterStatuetteInfo( 1041261, 0x20E7, 1165 ), + /* Troll */ new MonsterStatuetteInfo( 1041262, 0x20E9, 461 ), + /* Cow */ new MonsterStatuetteInfo( 1041263, 0x2103, 120 ), + /* Zombie */ new MonsterStatuetteInfo( 1041264, 0x20EC, 471 ), + /* Llama */ new MonsterStatuetteInfo( 1041265, 0x20F6, 1011 ), + /* Ophidian */ new MonsterStatuetteInfo( 1049742, 0x2133, 634 ), + /* Reaper */ new MonsterStatuetteInfo( 1049743, 0x20FA, 442 ), + /* Mongbat */ new MonsterStatuetteInfo( 1049744, 0x20F9, 422 ), + /* Gazer */ new MonsterStatuetteInfo( 1049768, 0x20F4, 377 ), + /* FireElemental */ new MonsterStatuetteInfo( 1049769, 0x20F3, 838 ), + /* Wolf */ new MonsterStatuetteInfo( 1049770, 0x2122, 229 ), + /* Phillip's Steed */ new MonsterStatuetteInfo( 1063488, 0x3FFE, 168 ), + /* Seahorse */ new MonsterStatuetteInfo( 1070819, 0x25BA, 138 ), + /* Harrower */ new MonsterStatuetteInfo( 1080520, 0x25BB, new int[] { 0x289, 0x28A, 0x28B } ), + /* Efreet */ new MonsterStatuetteInfo( 1080521, 0x2590, 0x300 ), + /* Slime */ new MonsterStatuetteInfo( 1015246, 0x20E8, 456 ), + /* PlagueBeast */ new MonsterStatuetteInfo( 1029747, 0x2613, 0x1BF ), + /* RedDeath */ new MonsterStatuetteInfo( 1094932, 0x2617, new int[] { } ), + /* Spider */ new MonsterStatuetteInfo( 1029668, 0x25C4, 1170 ), + /* OphidianArchMage */ new MonsterStatuetteInfo( 1029641, 0x25A9, 639 ), + /* OphidianWarrior */ new MonsterStatuetteInfo( 1029645, 0x25AD, 634 ), + /* OphidianKnight */ new MonsterStatuetteInfo( 1029642, 0x25aa, 634 ), + /* OphidianMage */ new MonsterStatuetteInfo( 1029643, 0x25ab, 639 ), + /* DreadHorn */ new MonsterStatuetteInfo( 1031651, 0x2D83, 0xA8 ), + /* Minotaur */ new MonsterStatuetteInfo( 1031657, 0x2D89, 0x596 ), + /* Black Cat */ new MonsterStatuetteInfo( 1096928, 0x4688, 0x69 ), + /* HalloweenGhoul */ new MonsterStatuetteInfo( 1076782, 0x2109, 0x482 ), + /* Santa */ new MonsterStatuetteInfo( 1097968, 0x4A98, 0x669 ) + }; + + public static MonsterStatuetteInfo GetInfo( MonsterStatuetteType type ) + { + int v = (int)type; + + if ( v < 0 || v >= m_Table.Length ) + v = 0; + + return m_Table[v]; + } + } + + public class MonsterStatuette : Item, IRewardItem + { + private MonsterStatuetteType m_Type; + private bool m_TurnedOn; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool TurnedOn + { + get{ return m_TurnedOn; } + set{ m_TurnedOn = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public MonsterStatuetteType Type + { + get{ return m_Type; } + set + { + m_Type = value; + ItemID = MonsterStatuetteInfo.GetInfo( m_Type ).ItemID; + + if( m_Type == MonsterStatuetteType.Slime ) + Hue = Utility.RandomSlimeHue(); + else if( m_Type == MonsterStatuetteType.RedDeath ) + Hue = 0x21; + else + Hue = 0; + + InvalidateProperties(); + } + } + + public override int LabelNumber + { + get{ return MonsterStatuetteInfo.GetInfo( m_Type ).LabelNumber; } + } + + public override double DefaultWeight + { + get { return 1.0; } + } + + [Constructable] + public MonsterStatuette() : this( MonsterStatuetteType.Crocodile ) + { + } + + [Constructable] + public MonsterStatuette( MonsterStatuetteType type ) : base( MonsterStatuetteInfo.GetInfo( type ).ItemID ) + { + LootType = LootType.Blessed; + + m_Type = type; + + if( m_Type == MonsterStatuetteType.Slime ) + Hue = Utility.RandomSlimeHue(); + else if( m_Type == MonsterStatuetteType.RedDeath ) + Hue = 0x21; + else if (m_Type == MonsterStatuetteType.HalloweenGhoul) + Hue = 0xF4; + } + + public override bool HandlesOnMovement{ get{ return m_TurnedOn && IsLockedDown; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m_TurnedOn && IsLockedDown && (!m.Hidden || m.AccessLevel == AccessLevel.Player) && Utility.InRange( m.Location, this.Location, 2 ) && !Utility.InRange( oldLocation, this.Location, 2 ) ) + { + int[] sounds = MonsterStatuetteInfo.GetInfo( m_Type ).Sounds; + + if( sounds.Length > 0 ) + Effects.PlaySound( this.Location, this.Map, sounds[Utility.Random( sounds.Length )] ); + } + + base.OnMovement( m, oldLocation ); + } + + public MonsterStatuette( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( RewardSystem.GetRewardYearLabel( this, new object[]{ m_Type } ) ); // X Year Veteran Reward + + if ( m_TurnedOn ) + list.Add( 502695 ); // turned on + else + list.Add( 502696 ); // turned off + } + + public bool IsOwner( Mobile mob ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + return ( house != null && house.IsOwner( mob ) ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsOwner( from ) ) + { + OnOffGump onOffGump = new OnOffGump( this ); + from.SendGump( onOffGump ); + } + else + { + from.SendLocalizedMessage( 502691 ); // You must be the owner to use this. + } + } + + private class OnOffGump : Gump + { + private MonsterStatuette m_Statuette; + + public OnOffGump( MonsterStatuette statuette ) : base( 150, 200 ) + { + m_Statuette = statuette; + + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddHtmlLocalized( 45, 20, 300, 35, statuette.TurnedOn ? 1011035 : 1011034, false, false ); // [De]Activate this item + + AddButton( 40, 53, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 80, 55, 65, 35, 1011036, false, false ); // OKAY + + AddButton( 150, 53, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 190, 55, 100, 35, 1011012, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + if ( info.ButtonID == 1 ) + { + bool newValue = !m_Statuette.TurnedOn; + m_Statuette.TurnedOn = newValue; + + if ( newValue && !m_Statuette.IsLockedDown ) + from.SendLocalizedMessage( 502693 ); // Remember, this only works when locked down. + } + else + { + from.SendLocalizedMessage( 502694 ); // Cancelled action. + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteEncodedInt( (int) m_Type ); + writer.Write( (bool) m_TurnedOn ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Type = (MonsterStatuetteType)reader.ReadEncodedInt(); + m_TurnedOn = reader.ReadBool(); + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastBackpack.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastBackpack.cs new file mode 100644 index 0000000..831a79f --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastBackpack.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Items +{ + public class PlagueBeastBackpack : BaseContainer + { + public override int DefaultMaxWeight { get { return 0; } } + public override int DefaultMaxItems { get { return 0; } } + public override int DefaultGumpID { get { return 0x2A63; } } + public override int DefaultDropSound { get { return 0x23F; } } + + private static int[,,] m_Positions = new int[,,] + { + { { 275, 85 }, { 360, 111 }, { 375, 184 }, { 332, 228 }, { 141, 105 }, { 189, 75 } }, + { { 274, 34 }, { 327, 89 }, { 354, 168 }, { 304, 225 }, { 113, 86 }, { 189, 75 } }, + { { 276, 79 }, { 369, 117 }, { 372, 192 }, { 336, 230 }, { 141, 116 }, { 189, 75 } }, + }; + + private static int[] m_BrainHues = new int[] + { + 0x2B, 0x42, 0x54, 0x60 + }; + + public PlagueBeastBackpack() : base( 0x261B ) + { + Layer = Layer.Backpack; + } + + public void Initialize() + { + AddInnard( 0x1CF6, 0x0, 227, 128 ); + AddInnard( 0x1D10, 0x0, 251, 128 ); + AddInnard( 0x1FBE, 0x21, 240, 83 ); + + AddInnard( new PlagueBeastHeart(), 229, 104 ); + + AddInnard( 0x1D06, 0x0, 283, 91 ); + AddInnard( 0x1FAF, 0x21, 315, 107 ); + AddInnard( 0x1FB9, 0x21, 289, 87 ); + AddInnard( 0x9E7, 0x21, 304, 96 ); + AddInnard( 0x1B1A, 0x66D, 335, 102 ); + AddInnard( 0x1D10, 0x0, 338, 146 ); + AddInnard( 0x1FB3, 0x21, 358, 167 ); + AddInnard( 0x1D0B, 0x0, 357, 155 ); + AddInnard( 0x9E7, 0x21, 339, 184 ); + AddInnard( 0x1B1A, 0x66D, 157, 172 ); + AddInnard( 0x1D11, 0x0, 147, 157 ); + AddInnard( 0x1FB9, 0x21, 121, 131 ); + AddInnard( 0x9E7, 0x21, 166, 176 ); + AddInnard( 0x1D0B, 0x0, 122, 138 ); + AddInnard( 0x1D0D, 0x0, 118, 150 ); + AddInnard( 0x1FB3, 0x21, 97, 123 ); + AddInnard( 0x1D08, 0x0, 115, 113 ); + AddInnard( 0x9E7, 0x21, 109, 109 ); + AddInnard( 0x9E7, 0x21, 91, 122 ); + AddInnard( 0x9E7, 0x21, 94, 160 ); + AddInnard( 0x1B19, 0x66D, 170, 121 ); + AddInnard( 0x1FAF, 0x21, 161, 111 ); + AddInnard( 0x1D0B, 0x0, 158, 112 ); + AddInnard( 0x9E7, 0x21, 159, 101 ); + AddInnard( 0x1D10, 0x0, 132, 177 ); + AddInnard( 0x1D0E, 0x0, 110, 178 ); + AddInnard( 0x1FB3, 0x21, 95, 194 ); + AddInnard( 0x1FAF, 0x21, 154, 203 ); + AddInnard( 0x1B1A, 0x66D, 110, 237 ); + AddInnard( 0x9E7, 0x21, 111, 171 ); + AddInnard( 0x9E7, 0x21, 90, 197 ); + AddInnard( 0x9E7, 0x21, 166, 205 ); + AddInnard( 0x9E7, 0x21, 96, 242 ); + AddInnard( 0x1D10, 0x0, 334, 196 ); + AddInnard( 0x1D0B, 0x0, 322, 270 ); + + List organs = new List(); + PlagueBeastOrgan organ; + + for ( int i = 0; i < 6; i++ ) + { + int random = Utility.Random( 3 ); + + if ( i == 5 ) + random = 0; + + switch ( random ) + { + default: + case 0: organ = new PlagueBeastRockOrgan(); break; + case 1: organ = new PlagueBeastMaidenOrgan(); break; + case 2: organ = new PlagueBeastRubbleOrgan(); break; + } + + organs.Add( organ ); + AddInnard( organ, m_Positions[ random, i, 0 ], m_Positions[ random, i, 1 ] ); + } + + organ = new PlagueBeastBackupOrgan(); + organs.Add( organ ); + AddInnard( organ, 129, 214 ); + + for ( int i = 0; i < m_BrainHues.Length; i++ ) + { + int random = Utility.Random( organs.Count ); + organ = organs[ random ]; + organ.BrainHue = m_BrainHues[ i ]; + organs.RemoveAt( random ); + } + + organs.Clear(); + + AddInnard( new PlagueBeastMainOrgan(), 240, 161 ); + } + + public override bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + if ( dropped is PlagueBeastInnard || dropped is PlagueBeastGland ) + return base.TryDropItem( from, dropped, sendFullMessage ); + + return false; + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( IsAccessibleTo( from ) && ( item is PlagueBeastInnard || item is PlagueBeastGland ) ) + { + Rectangle2D ir = ItemBounds.Table[ item.ItemID ]; + int x, y; + int cx = p.X + ir.X + ir.Width / 2; + int cy = p.Y + ir.Y + ir.Height / 2; + + for ( int i = Items.Count - 1; i >= 0; i-- ) + { + PlagueBeastComponent innard = Items[ i ] as PlagueBeastComponent; + + if ( innard != null ) + { + Rectangle2D r = ItemBounds.Table[ innard.ItemID ]; + + x = innard.X + r.X; + y = innard.Y + r.Y; + + if ( cx >= x && cx <= x + r.Width && cy >= y && cy <= y + r.Height ) + { + innard.OnDragDrop( from, item ); + break; + } + } + } + + return base.OnDragDropInto( from, item, p ); + } + + return false; + } + + public void AddInnard( int itemID, int hue, int x, int y ) + { + AddInnard( new PlagueBeastInnard( itemID, hue ), x, y ); + } + + public void AddInnard( PlagueBeastInnard innard, int x, int y ) + { + AddItem( innard ); + innard.Location = new Point3D( x, y, 0 ); + innard.Map = Map; + } + + public PlagueBeastBackpack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastBlood.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastBlood.cs new file mode 100644 index 0000000..d64074a --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastBlood.cs @@ -0,0 +1,127 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastBlood : PlagueBeastComponent + { + public bool Patched + { + get { return ItemID == 0x1765; } + } + + public bool Starting + { + get { return ItemID == 0x122C; } + } + + private Timer m_Timer; + + public PlagueBeastBlood() : base( 0x122C, 0 ) + { + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1.5 ), TimeSpan.FromSeconds( 1.5 ), 3, new TimerCallback( Hemorrhage ) ); + } + + public override void OnAfterDelete() + { + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + public override bool OnBandage( Mobile from ) + { + if ( IsAccessibleTo( from ) && !Patched ) + { + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + + if ( Starting ) + { + X += 2; + Y -= 9; + + if ( Organ is PlagueBeastRubbleOrgan ) + Y -= 5; + else if ( Organ is PlagueBeastBackupOrgan ) + X += 7; + } + else + { + X -= 4; + Y -= 2; + } + + ItemID = 0x1765; + + if ( Owner != null ) + { + Container pack = Owner.Backpack; + + if ( pack != null ) + { + for ( int i = 0; i < pack.Items.Count; i++ ) + { + PlagueBeastMainOrgan main = pack.Items[ i ] as PlagueBeastMainOrgan; + + if ( main != null && main.Complete ) + main.FinishOpening( from ); + } + } + } + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071916 ); // * You patch up the wound with a bandage * + + return true; + } + + return false; + } + + private void Hemorrhage() + { + if ( Patched ) + return; + + if ( Owner != null ) + Owner.PlaySound( 0x25 ); + + if ( ItemID == 0x122A ) + { + if ( Owner != null ) + { + Owner.Unfreeze(); + Owner.Kill(); + } + } + else + { + if ( Starting ) + { + X += 8; + Y -= 10; + } + + ItemID--; + } + } + + public PlagueBeastBlood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastGland.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastGland.cs new file mode 100644 index 0000000..91ca3c8 --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastGland.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PlagueBeastGland : Item + { + [Constructable] + public PlagueBeastGland() : base( 0x1CEF ) + { + Name = "A Healthy Gland"; + Weight = 1.0; + Hue = 0x6; + } + + public PlagueBeastGland( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastHeart.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastHeart.cs new file mode 100644 index 0000000..ae16ab4 --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastHeart.cs @@ -0,0 +1,80 @@ +using System; +using Server; + +namespace Server.Items +{ + public class PlagueBeastHeart : PlagueBeastInnard + { + private Timer m_Timer; + + public PlagueBeastHeart() : base( 0x1363, 0x21 ) + { + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + public PlagueBeastHeart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + private PlagueBeastHeart m_Heart; + private bool m_Delay; + + public InternalTimer( PlagueBeastHeart heart ) : base( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 0.5 ) ) + { + m_Heart = heart; + } + + protected override void OnTick() + { + if ( m_Heart == null || m_Heart.Deleted || m_Heart.Owner == null || !m_Heart.Owner.Alive ) + { + Stop(); + return; + } + + if ( m_Heart.ItemID == 0x1363 ) + { + if ( m_Delay ) + { + m_Heart.ItemID = 0x1367; + m_Heart.Owner.PlaySound( 0x11F ); + } + + m_Delay = !m_Delay; + } + else + { + m_Heart.ItemID = 0x1363; + m_Heart.Owner.PlaySound( 0x120 ); + m_Delay = false; + } + } + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastInnard.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastInnard.cs new file mode 100644 index 0000000..f1ed4d5 --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastInnard.cs @@ -0,0 +1,192 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastInnard : Item, IScissorable, ICarvable + { + public PlagueBeastLord Owner + { + get { return RootParent as PlagueBeastLord; } + } + + public PlagueBeastInnard( int itemID, int hue ) : base( itemID ) + { + Name = "plague beast innards"; + Hue = hue; + Movable = false; + Weight = 1.0; + } + + public virtual bool Scissor( Mobile from, Scissors scissors ) + { + return false; + } + + public virtual void Carve( Mobile from, Item with ) + { + } + + public virtual bool OnBandage( Mobile from ) + { + return false; + } + + public override bool IsAccessibleTo( Mobile check ) + { + if ( (int) check.AccessLevel >= (int) AccessLevel.GameMaster ) + return true; + + PlagueBeastLord owner = Owner; + + if ( owner == null ) + return false; + + if ( !owner.InRange( check, 2 ) ) + owner.PrivateOverheadMessage( MessageType.Label, 0x3B2, 500446, check.NetState ); // That is too far away. + else if ( owner.OpenedBy != null && owner.OpenedBy != check ) // TODO check + owner.PrivateOverheadMessage( MessageType.Label, 0x3B2, 500365, check.NetState ); // That is being used by someone else + else if ( owner.Frozen ) + return true; + + return false; + } + + public PlagueBeastInnard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + PlagueBeastLord owner = Owner; + + if ( owner == null || !owner.Alive ) + Delete(); + } + } + + public class PlagueBeastComponent : PlagueBeastInnard + { + private PlagueBeastOrgan m_Organ; + + public PlagueBeastOrgan Organ + { + get { return m_Organ; } + set { m_Organ = value; } + } + + public bool IsBrain + { + get { return ItemID == 0x1CF0; } + } + + public bool IsGland + { + get { return ItemID == 0x1CEF; } + } + + public bool IsReceptacle + { + get { return ItemID == 0x9DF; } + } + + public PlagueBeastComponent( int itemID, int hue ) : this( itemID, hue, false ) + { + } + + public PlagueBeastComponent( int itemID, int hue, bool movable ) : base( itemID, hue ) + { + Movable = movable; + } + + public override bool DropToItem( Mobile from, Item target, Point3D p ) + { + if ( target is PlagueBeastBackpack ) + return base.DropToItem( from, target, p ); + + return false; + } + + public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + return false; + } + + public override bool DropToMobile( Mobile from, Mobile target, Point3D p ) + { + return false; + } + + public override bool DropToWorld( Mobile from, Point3D p ) + { + return false; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( m_Organ != null && m_Organ.OnDropped( from, dropped, this ) ) + { + if ( dropped is PlagueBeastComponent ) + m_Organ.Components.Add( (PlagueBeastComponent) dropped ); + } + + return true; + } + + public override bool OnDragLift( Mobile from ) + { + if ( IsAccessibleTo( from ) ) + { + if ( m_Organ != null && m_Organ.OnLifted( from, this ) ) + { + from.SendLocalizedMessage( IsGland ? 1071895 : 1071914, null, 0x3B2 ); // * You rip the organ out of the plague beast's flesh * + + if ( m_Organ.Components.Contains( this ) ) + m_Organ.Components.Remove( this ); + + m_Organ = null; + from.PlaySound( 0x1CA ); + } + + return true; + } + + return false; + } + + public PlagueBeastComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteItem( m_Organ ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Organ = reader.ReadItem(); + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastMutationCore.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastMutationCore.cs new file mode 100644 index 0000000..0242923 --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastMutationCore.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastMutationCore : Item, IScissorable + { + private bool m_Cut; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Cut + { + get { return m_Cut; } + set { m_Cut = value; } + } + + [Constructable] + public PlagueBeastMutationCore() : base( 0x1CF0 ) + { + m_Cut = true; + + Name = "a plague beast mutation core"; + Weight = 1.0; + Hue = 0x480; + } + + public virtual bool Scissor( Mobile from, Scissors scissors ) + { + if ( !m_Cut ) + { + PlagueBeastLord owner = RootParent as PlagueBeastLord; + + m_Cut = true; + Movable = true; + + from.AddToBackpack( this ); + from.LocalOverheadMessage( MessageType.Regular, 0x34, 1071906 ); // * You remove the plague mutation core from the plague beast, causing it to dissolve into a pile of goo * + + if ( owner != null ) + Timer.DelayCall( TimeSpan.FromSeconds( 1 ), new TimerStateCallback( KillParent ), owner ); + + return true; + } + + return false; + } + + private void KillParent( PlagueBeastLord parent ) + { + parent.Unfreeze(); + parent.Kill(); + } + + public PlagueBeastMutationCore( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_Cut ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Cut = reader.ReadBool(); + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastOrgans.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastOrgans.cs new file mode 100644 index 0000000..aa8e74f --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastOrgans.cs @@ -0,0 +1,586 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastOrgan : PlagueBeastInnard + { + public virtual bool IsCuttable { get { return false; } } + + private List m_Components; + + public List Components + { + get { return m_Components; } + } + + private int m_BrainHue; + + public int BrainHue + { + get { return m_BrainHue; } + set { m_BrainHue = value; } + } + + private bool m_Opened; + + public bool Opened + { + get { return m_Opened; } + set { m_Opened = value; } + } + + private Timer m_Timer; + + public PlagueBeastOrgan() : this( 1, 0 ) + { + Visible = false; + } + + public PlagueBeastOrgan( int itemID, int hue ) : base( itemID, hue ) + { + m_Components = new List(); + m_Opened = false; + + Movable = false; + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Initialize ) ); + } + + public virtual void Initialize() + { + } + + public void AddComponent( PlagueBeastComponent c, int x, int y ) + { + Container pack = Parent as Container; + + if ( pack != null ) + pack.DropItem( c ); + + c.Organ = this; + c.Location = new Point3D( X + x, Y + y, Z ); + c.Map = Map; + + m_Components.Add( c ); + } + + public override bool Scissor( Mobile from, Scissors scissors ) + { + if ( IsCuttable && IsAccessibleTo( from ) ) + { + if ( !m_Opened && m_Timer == null ) + { + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 3 ), new TimerStateCallback( FinishOpening ), from ); + scissors.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071897 ); // You carefully cut into the organ. + return true; + } + else + scissors.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071898 ); // You have already cut this organ open. + } + + return false; + } + + public override void OnAfterDelete() + { + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + public virtual bool OnLifted( Mobile from, PlagueBeastComponent c ) + { + return c.IsGland || c.IsBrain; + } + + public virtual bool OnDropped( Mobile from, Item item, PlagueBeastComponent to ) + { + return false; + } + + public virtual void FinishOpening( Mobile from ) + { + m_Opened = true; + + if ( Owner != null ) + Owner.PlaySound( 0x50 ); + } + + public PlagueBeastOrgan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteItemList( m_Components ); + writer.Write( (int) m_BrainHue ); + writer.Write( (bool) m_Opened ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Components = reader.ReadStrongItemList(); + m_BrainHue = reader.ReadInt(); + m_Opened = reader.ReadBool(); + } + } + + public class PlagueBeastMaidenOrgan : PlagueBeastOrgan + { + public PlagueBeastMaidenOrgan() : base( 0x124D, 0x0 ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !Opened ) + FinishOpening( from ); + } + + public override void FinishOpening( Mobile from ) + { + ItemID = 0x1249; + + if ( Owner != null ) + Owner.PlaySound( 0x187 ); + + AddComponent( new PlagueBeastComponent( 0x1D0D, 0x0 ), 22, 3 ); + AddComponent( new PlagueBeastComponent( 0x1D12, 0x0 ), 15, 18 ); + AddComponent( new PlagueBeastComponent( 0x1DA3, 0x21 ), 26, 46 ); + + if ( BrainHue > 0 ) + AddComponent( new PlagueBeastComponent( 0x1CF0, BrainHue, true ), 22, 29 ); + + Opened = true; + } + + public PlagueBeastMaidenOrgan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PlagueBeastRockOrgan : PlagueBeastOrgan + { + public override bool IsCuttable { get { return true; } } + + public PlagueBeastRockOrgan() : base( 0x177A, 0x60 ) + { + } + + public override void Carve( Mobile from, Item with ) + { + if ( IsAccessibleTo( from ) ) + with.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071896 ); // This is too crude an implement for such a procedure. + } + + public override bool OnLifted( Mobile from, PlagueBeastComponent c ) + { + base.OnLifted( from, c ); + + if ( c.IsBrain ) + { + AddComponent( new PlagueBeastBlood(), -7, 24 ); + return true; + } + + return false; + } + + public override void FinishOpening( Mobile from ) + { + base.FinishOpening( from ); + + AddComponent( new PlagueBeastComponent( 0x1775, 0x60 ), 3, 5 ); + AddComponent( new PlagueBeastComponent( 0x1777, 0x1 ), 10, 14 ); + + if ( BrainHue > 0 ) + AddComponent( new PlagueBeastComponent( 0x1CF0, BrainHue, true ), 1, 24 ); // 22, 29 + else + AddComponent( new PlagueBeastBlood(), -7, 24 ); + } + + public PlagueBeastRockOrgan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class PlagueBeastRubbleOrgan : PlagueBeastOrgan + { + private int m_Veins; + + public PlagueBeastRubbleOrgan() : base() + { + m_Veins = 3; + } + + public override void Initialize() + { + Hue = Utility.RandomList( m_Hues ); + + AddComponent( new PlagueBeastComponent( 0x3BB, Hue ), 0, 0 ); + AddComponent( new PlagueBeastComponent( 0x3BA, Hue ), 4, 6 ); + AddComponent( new PlagueBeastComponent( 0x3BA, Hue ), -6, 17 ); + + int v = Utility.Random( 4 ); + + AddComponent( new PlagueBeastVein( 0x1B1B, v == 0 ? Hue : RandomHue( Hue ) ), -23, -3 ); + AddComponent( new PlagueBeastVein( 0x1B1C, v == 1 ? Hue : RandomHue( Hue ) ), 19, 4 ); + AddComponent( new PlagueBeastVein( 0x1B1B, v == 2 ? Hue : RandomHue( Hue ) ), 21, 27 ); + AddComponent( new PlagueBeastVein( 0x1B1B, v == 3 ? Hue : RandomHue( Hue ) ), 10, 40 ); + } + + public override bool OnLifted( Mobile from, PlagueBeastComponent c ) + { + if ( c.IsBrain ) + { + AddComponent( new PlagueBeastBlood(), -13, 25 ); + return true; + } + + return false; + } + + public override void FinishOpening( Mobile from ) + { + AddComponent( new PlagueBeastComponent( 0x1777, 0x1 ), 5, 14 ); + + if ( BrainHue > 0 ) + AddComponent( new PlagueBeastComponent( 0x1CF0, BrainHue, true ), -5, 22 ); + else + AddComponent( new PlagueBeastBlood(), -13, 25 ); + + Opened = true; + } + + private static int[] m_Hues = new int[] + { + 0xD, 0x17, 0x2B, 0x42, 0x54, 0x5D + }; + + private static int RandomHue( int exculde ) + { + for ( int i = 0; i < 20; i++ ) + { + int hue = Utility.RandomList( m_Hues ); + + if ( hue != exculde ) + return hue; + } + + return 0xD; + } + + public virtual void OnVeinCut( Mobile from, PlagueBeastVein vein ) + { + if ( vein.Hue != Hue ) + { + if ( !Opened && m_Veins > 0 && --m_Veins == 0 ) + FinishOpening( from ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1071901 ); // * As you cut the vein, a cloud of poison is expelled from the plague beast's organ, and the plague beast dissolves into a puddle of goo * + from.ApplyPoison( from, Poison.Greater ); + from.PlaySound( 0x22F ); + + if ( Owner != null ) + { + Owner.Unfreeze(); + Owner.Kill(); + } + } + } + + public PlagueBeastRubbleOrgan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_Veins ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Veins = reader.ReadInt(); + } + } + + public class PlagueBeastBackupOrgan : PlagueBeastOrgan + { + public override bool IsCuttable { get { return true; } } + + private Timer m_Timer; + private Item m_Gland; + + public PlagueBeastBackupOrgan() : base( 0x1362, 0x6 ) + { + } + + public override void Initialize() + { + AddComponent( new PlagueBeastComponent( 0x1B1B, 0x42 ), 16, 39 ); + AddComponent( new PlagueBeastComponent( 0x1B1B, 0x42 ), 39, 49 ); + AddComponent( new PlagueBeastComponent( 0x1B1B, 0x42 ), 39, 48 ); + AddComponent( new PlagueBeastComponent( 0x1B1B, 0x42 ), 44, 42 ); + AddComponent( new PlagueBeastComponent( 0x1CF2, 0x42 ), 20, 34 ); + AddComponent( new PlagueBeastComponent( 0x135F, 0x42 ), 47, 58 ); + AddComponent( new PlagueBeastComponent( 0x1360, 0x42 ), 70, 68 ); + } + + public override void Carve( Mobile from, Item with ) + { + if ( IsAccessibleTo( from ) ) + with.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071896 ); // This is too crude an implement for such a procedure. + } + + public override bool OnLifted( Mobile from, PlagueBeastComponent c ) + { + if ( c.IsBrain ) + { + AddComponent( new PlagueBeastBlood(), 47, 72 ); + return true; + } + else if ( c.IsGland ) + { + m_Gland = null; + return true; + } + + return c.IsGland; + } + + public override bool OnDropped( Mobile from, Item item, PlagueBeastComponent to ) + { + if ( to.Hue == 0x1 && m_Gland == null && item is PlagueBeastGland ) + { + m_Gland = item; + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 3 ), new TimerCallback( FinishHealing ) ); + from.SendAsciiMessage( 0x3B2, "* You place the healthy gland inside the organ sac *" ); + item.Movable = false; + + if ( Owner != null ) + Owner.PlaySound( 0x20 ); + + return true; + } + + return false; + } + + public override void FinishOpening( Mobile from ) + { + base.FinishOpening( from ); + + AddComponent( new PlagueBeastComponent( 0x1363, 0xF ), -3, 3 ); + AddComponent( new PlagueBeastComponent( 0x1365, 0x1 ), -3, 10 ); + + m_Gland = new PlagueBeastComponent( 0x1CEF, 0x3F, true ); + AddComponent( (PlagueBeastComponent) m_Gland, -4, 16 ); + } + + public void FinishHealing() + { + for ( int i = 0; i < 7 && i < Components.Count; i++ ) + Components[ i ].Hue = 0x6; + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 2 ), new TimerCallback( OpenOrgan ) ); + } + + public void OpenOrgan() + { + AddComponent( new PlagueBeastComponent( 0x1367, 0xF ), 55, 61 ); + AddComponent( new PlagueBeastComponent( 0x1366, 0x1 ), 57, 66 ); + + if ( BrainHue > 0 ) + AddComponent( new PlagueBeastComponent( 0x1CF0, BrainHue, true ), 55, 69 ); + } + + public PlagueBeastBackupOrgan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (Item) m_Gland ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Gland = reader.ReadItem(); + } + } + + public class PlagueBeastMainOrgan : PlagueBeastOrgan + { + private int m_Brains; + + public bool Complete + { + get { return m_Brains >= 4; } + } + + public PlagueBeastMainOrgan() : base() + { + m_Brains = 0; + } + + public override void Initialize() + { + // receptacles + AddComponent( new PlagueBeastComponent( 0x1B1B, 0x42 ), -36, -2 ); + AddComponent( new PlagueBeastComponent( 0x1FB3, 0x42 ), -42, 0 ); + AddComponent( new PlagueBeastComponent( 0x9DF, 0x42 ), -53, -7 ); + + AddComponent( new PlagueBeastComponent( 0x1B1C, 0x54 ), 29, 9 ); + AddComponent( new PlagueBeastComponent( 0x1D06, 0x54 ), 18, -2 ); + AddComponent( new PlagueBeastComponent( 0x9DF, 0x54 ), 36, -1 ); + + AddComponent( new PlagueBeastComponent( 0x1D10, 0x2B ), -36, 47 ); + AddComponent( new PlagueBeastComponent( 0x1B1C, 0x2B ), -24, 62 ); + AddComponent( new PlagueBeastComponent( 0x9DF, 0x2B ), -41, 74 ); + + AddComponent( new PlagueBeastComponent( 0x1B1B, 0x60 ), 39, 56 ); + AddComponent( new PlagueBeastComponent( 0x1FB4, 0x60 ), 34, 52 ); + AddComponent( new PlagueBeastComponent( 0x9DF, 0x60 ), 45, 71 ); + + // main part + AddComponent( new PlagueBeastComponent( 0x1351, 0x15 ), 23, 0 ); + AddComponent( new PlagueBeastComponent( 0x134F, 0x15 ), -22, 0 ); + AddComponent( new PlagueBeastComponent( 0x1350, 0x15 ), 0, 0 ); + } + + public override bool OnLifted( Mobile from, PlagueBeastComponent c ) + { + if ( c.IsBrain ) + m_Brains--; + + return true; + } + + public override bool OnDropped( Mobile from, Item item, PlagueBeastComponent to ) + { + if ( !Opened && to.IsReceptacle && item.Hue == to.Hue ) + { + to.Organ = this; + m_Brains++; + from.LocalOverheadMessage( MessageType.Regular, 0x34, 1071913 ); // You place the organ in the fleshy receptacle near the core. + + if ( Owner != null ) + { + Owner.PlaySound( 0x1BA ); + + if ( Owner.IsBleeding ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x34, 1071922 ); // The plague beast is still bleeding from open wounds. You must seal any bleeding wounds before the core will open! + return true; + } + } + + if ( m_Brains == 4 ) + FinishOpening( from ); + + return true; + } + + return false; + } + + public override void FinishOpening( Mobile from ) + { + AddComponent( new PlagueBeastComponent( 0x1363, 0x1 ), 0, 22 ); + AddComponent( new PlagueBeastComponent( 0x1D04, 0xD ), 0, 22 ); + + if ( Owner != null && Owner.Backpack != null ) + { + PlagueBeastMutationCore core = new PlagueBeastMutationCore(); + Owner.Backpack.AddItem( core ); + core.Movable = false; + core.Cut = false; + core.X = X; + core.Y = Y + 34; + + Owner.PlaySound( 0x21 ); + Owner.PlaySound( 0x166 ); + } + + Opened = true; + } + + public PlagueBeastMainOrgan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_Brains ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Brains = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Mutation Core/PlagueBeastVein.cs b/Scripts/Items/Special/Mutation Core/PlagueBeastVein.cs new file mode 100644 index 0000000..39a0b9b --- /dev/null +++ b/Scripts/Items/Special/Mutation Core/PlagueBeastVein.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class PlagueBeastVein : PlagueBeastComponent + { + private bool m_Cut; + + public bool Cut + { + get { return m_Cut; } + } + + private Timer m_Timer; + + public PlagueBeastVein( int itemID, int hue ) : base( itemID, hue ) + { + m_Cut = false; + } + + public override bool Scissor( Mobile from, Scissors scissors ) + { + if ( IsAccessibleTo( from ) ) + { + if ( !m_Cut && m_Timer == null ) + { + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 3 ), new TimerStateCallback( CuttingDone ), from ); + scissors.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071899 ); // You begin cutting through the vein. + return true; + } + else + scissors.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071900 ); // // This vein has already been cut. + } + + return false; + } + + public override void OnAfterDelete() + { + if ( m_Timer != null && m_Timer.Running ) + m_Timer.Stop(); + } + + private void CuttingDone( Mobile from ) + { + m_Cut = true; + + if ( ItemID == 0x1B1C ) + ItemID = 0x1B1B; + else + ItemID = 0x1B1C; + + if ( Owner != null ) + Owner.PlaySound( 0x199 ); + + PlagueBeastRubbleOrgan organ = Organ as PlagueBeastRubbleOrgan; + + if ( organ != null ) + organ.OnVeinCut( from, this ); + } + + public PlagueBeastVein( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_Cut ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Cut = reader.ReadBool(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Containers/BaseWaterContainer.cs b/Scripts/Items/Special/Rares/Containers/BaseWaterContainer.cs new file mode 100644 index 0000000..a6807aa --- /dev/null +++ b/Scripts/Items/Special/Rares/Containers/BaseWaterContainer.cs @@ -0,0 +1,132 @@ +namespace Server.Items +{ + public abstract class BaseWaterContainer : Container, IHasQuantity + { + public abstract int voidItem_ID { get; } + public abstract int fullItem_ID { get; } + public abstract int MaxQuantity { get; } + + public override int DefaultGumpID { get { return 0x3e; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsEmpty { get { return (m_Quantity <= 0); } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool IsFull { get { return (m_Quantity >= MaxQuantity); } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int Quantity + { + get + { + return m_Quantity; + } + set + { + if (value != m_Quantity) + { + m_Quantity = (value < 1) ? 0 : (value > MaxQuantity) ? MaxQuantity : value; + + Movable = (!IsLockedDown) ? IsEmpty : false; + + ItemID = (IsEmpty) ? voidItem_ID : fullItem_ID; + + if (!IsEmpty) + { + IEntity rootParent = RootParentEntity; + + if (rootParent != null && rootParent.Map != null && rootParent.Map != Map.Internal) + MoveToWorld(rootParent.Location, rootParent.Map); + } + + InvalidateProperties(); + } + } + } + + private int m_Quantity; + + public BaseWaterContainer(int Item_Id, bool filled) + : base(Item_Id) + { + m_Quantity = (filled) ? MaxQuantity : 0; + } + + public override void OnDoubleClick(Mobile from) + { + if (IsEmpty) + { + base.OnDoubleClick(from); + } + } + + public override void OnSingleClick(Mobile from) + { + if (IsEmpty) + { + base.OnSingleClick(from); + } + else + { + if (Name == null) + LabelTo(from, LabelNumber); + else + LabelTo(from, Name); + } + } + + public override void OnAosSingleClick(Mobile from) + { + if (IsEmpty) + { + base.OnAosSingleClick(from); + } + else + { + if (Name == null) + LabelTo(from, LabelNumber); + else + LabelTo(from, Name); + } + } + + public override void GetProperties(ObjectPropertyList list) + { + if (IsEmpty) + { + base.GetProperties(list); + } + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (!IsEmpty) + { + return false; + } + + return base.OnDragDropInto(from, item, p); + } + + public BaseWaterContainer(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.Write((int)m_Quantity); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Quantity = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Containers/Bucket.cs b/Scripts/Items/Special/Rares/Containers/Bucket.cs new file mode 100644 index 0000000..8d59718 --- /dev/null +++ b/Scripts/Items/Special/Rares/Containers/Bucket.cs @@ -0,0 +1,43 @@ +namespace Server.Items +{ + class Bucket : BaseWaterContainer + { + public override int voidItem_ID { get { return vItemID; } } + public override int fullItem_ID { get { return fItemID; } } + public override int MaxQuantity { get { return 25; } } + + private static int vItemID = 0x14e0; + private static int fItemID = 0x2004; + + [Constructable] + public Bucket() + : this( false ) + { + } + + [Constructable] + public Bucket( bool filled ) + : base( ( filled ) ? Bucket.fItemID : Bucket.vItemID, filled ) + { + } + + public Bucket( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Containers/ClosedBarrel.cs b/Scripts/Items/Special/Rares/Containers/ClosedBarrel.cs new file mode 100644 index 0000000..674cd98 --- /dev/null +++ b/Scripts/Items/Special/Rares/Containers/ClosedBarrel.cs @@ -0,0 +1,32 @@ +namespace Server.Items +{ + class ClosedBarrel : TrapableContainer + { + public override int DefaultGumpID{ get { return 0x3e; } } + + [Constructable] + public ClosedBarrel() + : base( 0x0FAE ) + { + } + + public ClosedBarrel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Containers/UnfinishedBarrel.cs b/Scripts/Items/Special/Rares/Containers/UnfinishedBarrel.cs new file mode 100644 index 0000000..7a94da7 --- /dev/null +++ b/Scripts/Items/Special/Rares/Containers/UnfinishedBarrel.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class UnfinishedBarrel : Item + { + + [Constructable] + public UnfinishedBarrel() : base( 0x1EB5 ) + { + Movable = true; + Stackable = false; + } + + public UnfinishedBarrel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Containers/WaterBarrel.cs b/Scripts/Items/Special/Rares/Containers/WaterBarrel.cs new file mode 100644 index 0000000..b173deb --- /dev/null +++ b/Scripts/Items/Special/Rares/Containers/WaterBarrel.cs @@ -0,0 +1,45 @@ +namespace Server.Items +{ + class WaterBarrel : BaseWaterContainer + { + public override int LabelNumber { get { return 1025453; } } /* water barrel */ + + public override int voidItem_ID { get { return vItemID; } } + public override int fullItem_ID { get { return fItemID; } } + public override int MaxQuantity { get { return 100; } } + + private static int vItemID = 0xe77; + private static int fItemID = 0x154d; + + [Constructable] + public WaterBarrel() + : this( false ) + { + } + + [Constructable] + public WaterBarrel( bool filled ) + : base( ( filled ) ? WaterBarrel.fItemID : WaterBarrel.vItemID, filled ) + { + } + + public WaterBarrel( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Containers/WaterTub.cs b/Scripts/Items/Special/Rares/Containers/WaterTub.cs new file mode 100644 index 0000000..1bd78ec --- /dev/null +++ b/Scripts/Items/Special/Rares/Containers/WaterTub.cs @@ -0,0 +1,43 @@ +namespace Server.Items +{ + class Tub : BaseWaterContainer + { + public override int voidItem_ID { get { return vItemID; } } + public override int fullItem_ID { get { return fItemID; } } + public override int MaxQuantity { get { return 50; } } + + private static int vItemID = 0xe83; + private static int fItemID = 0xe7b; + + [Constructable] + public Tub() + : this( false ) + { + } + + [Constructable] + public Tub( bool filled ) + : base( ( filled ) ? Tub.fItemID : Tub.vItemID, filled ) + { + } + + public Tub( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Daily/DecoRock.cs b/Scripts/Items/Special/Rares/Daily/DecoRock.cs new file mode 100644 index 0000000..1d135f4 --- /dev/null +++ b/Scripts/Items/Special/Rares/Daily/DecoRock.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRock : Item + { + + [Constructable] + public DecoRock() : base( 0x1778 ) + { + Movable = true; + Stackable = false; + } + + public DecoRock( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Daily/DecoRock2.cs b/Scripts/Items/Special/Rares/Daily/DecoRock2.cs new file mode 100644 index 0000000..51e4222 --- /dev/null +++ b/Scripts/Items/Special/Rares/Daily/DecoRock2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRock2 : Item + { + + [Constructable] + public DecoRock2() : base( 0x1363 ) + { + Movable = true; + Stackable = false; + } + + public DecoRock2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Daily/DecoRocks.cs b/Scripts/Items/Special/Rares/Daily/DecoRocks.cs new file mode 100644 index 0000000..100865c --- /dev/null +++ b/Scripts/Items/Special/Rares/Daily/DecoRocks.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRocks : Item + { + + [Constructable] + public DecoRocks() : base( 0x1367 ) + { + Movable = true; + Stackable = false; + } + + public DecoRocks( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Daily/DecoRocks2.cs b/Scripts/Items/Special/Rares/Daily/DecoRocks2.cs new file mode 100644 index 0000000..4bbac56 --- /dev/null +++ b/Scripts/Items/Special/Rares/Daily/DecoRocks2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRocks2 : Item + { + + [Constructable] + public DecoRocks2() : base( 0x136D ) + { + Movable = true; + Stackable = false; + } + + public DecoRocks2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Flowers/DecoFlower.cs b/Scripts/Items/Special/Rares/Flowers/DecoFlower.cs new file mode 100644 index 0000000..ca8436b --- /dev/null +++ b/Scripts/Items/Special/Rares/Flowers/DecoFlower.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoFlower : Item + { + + [Constructable] + public DecoFlower() : base( 0x18DA ) + { + Movable = true; + Stackable = false; + } + + public DecoFlower( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Flowers/DecoFlower2.cs b/Scripts/Items/Special/Rares/Flowers/DecoFlower2.cs new file mode 100644 index 0000000..f97aca2 --- /dev/null +++ b/Scripts/Items/Special/Rares/Flowers/DecoFlower2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoFlower2 : Item + { + + [Constructable] + public DecoFlower2() : base( 0x18D9 ) + { + Movable = true; + Stackable = false; + } + + public DecoFlower2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs b/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs new file mode 100644 index 0000000..c161555 --- /dev/null +++ b/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRoseOfTrinsic : Item + { + + [Constructable] + public DecoRoseOfTrinsic() : base( 0x234C ) + { + Movable = true; + Stackable = false; + } + + public DecoRoseOfTrinsic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs b/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs new file mode 100644 index 0000000..6e916d3 --- /dev/null +++ b/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRoseOfTrinsic2 : Item + { + + [Constructable] + public DecoRoseOfTrinsic2() : base( 0x234D ) + { + Movable = true; + Stackable = false; + } + + public DecoRoseOfTrinsic2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs b/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs new file mode 100644 index 0000000..13bfcc8 --- /dev/null +++ b/Scripts/Items/Special/Rares/Flowers/DecoRoseOfTrinsic3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoRoseOfTrinsic3 : Item + { + + [Constructable] + public DecoRoseOfTrinsic3() : base( 0x234B ) + { + Movable = true; + Stackable = false; + } + + public DecoRoseOfTrinsic3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Food/BottlesOfLiquor.cs b/Scripts/Items/Special/Rares/Food/BottlesOfLiquor.cs new file mode 100644 index 0000000..a24b82e --- /dev/null +++ b/Scripts/Items/Special/Rares/Food/BottlesOfLiquor.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoBottlesOfLiquor : Item + { + + [Constructable] + public DecoBottlesOfLiquor() : base( 0x99E ) + { + Movable = true; + Stackable = false; + } + + public DecoBottlesOfLiquor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Food/Tray2.cs b/Scripts/Items/Special/Rares/Food/Tray2.cs new file mode 100644 index 0000000..1d77be8 --- /dev/null +++ b/Scripts/Items/Special/Rares/Food/Tray2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTray2 : Item + { + + [Constructable] + public DecoTray2() : base( 0x991 ) + { + Movable = true; + Stackable = false; + } + + public DecoTray2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Food/Trays.cs b/Scripts/Items/Special/Rares/Food/Trays.cs new file mode 100644 index 0000000..fc1e283 --- /dev/null +++ b/Scripts/Items/Special/Rares/Food/Trays.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTray : Item + { + + [Constructable] + public DecoTray() : base( Utility.Random(2) + 0x991 ) + { + Movable = true; + Stackable = false; + } + + public DecoTray( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Furniture/BrokenChair.cs b/Scripts/Items/Special/Rares/Furniture/BrokenChair.cs new file mode 100644 index 0000000..57048d1 --- /dev/null +++ b/Scripts/Items/Special/Rares/Furniture/BrokenChair.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class BrokenChair : Item + { + + [Constructable] + public BrokenChair() : base( Utility.Random(2) + 0xC19 ) + { + Movable = true; + Stackable = false; + } + + public BrokenChair( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/GamePieces/Checkers.cs b/Scripts/Items/Special/Rares/GamePieces/Checkers.cs new file mode 100644 index 0000000..47798a9 --- /dev/null +++ b/Scripts/Items/Special/Rares/GamePieces/Checkers.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Checkers : Item + { + + [Constructable] + public Checkers() : base( 0xE1A ) + { + Movable = true; + Stackable = false; + } + + public Checkers( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/GamePieces/Checkers2.cs b/Scripts/Items/Special/Rares/GamePieces/Checkers2.cs new file mode 100644 index 0000000..fd4ef35 --- /dev/null +++ b/Scripts/Items/Special/Rares/GamePieces/Checkers2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Checkers2 : Item + { + + [Constructable] + public Checkers2() : base( 0xE1B ) + { + Movable = true; + Stackable = false; + } + + public Checkers2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/GamePieces/Chessmen.cs b/Scripts/Items/Special/Rares/GamePieces/Chessmen.cs new file mode 100644 index 0000000..9392e46 --- /dev/null +++ b/Scripts/Items/Special/Rares/GamePieces/Chessmen.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Chessmen : Item + { + + [Constructable] + public Chessmen() : base( 0xE13 ) + { + Movable = true; + Stackable = false; + } + + public Chessmen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/GamePieces/Chessmen2.cs b/Scripts/Items/Special/Rares/GamePieces/Chessmen2.cs new file mode 100644 index 0000000..b224ea8 --- /dev/null +++ b/Scripts/Items/Special/Rares/GamePieces/Chessmen2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Chessmen2 : Item + { + + [Constructable] + public Chessmen2() : base( 0xE12 ) + { + Movable = true; + Stackable = false; + } + + public Chessmen2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/GamePieces/Chessmen3.cs b/Scripts/Items/Special/Rares/GamePieces/Chessmen3.cs new file mode 100644 index 0000000..7a8523b --- /dev/null +++ b/Scripts/Items/Special/Rares/GamePieces/Chessmen3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Chessmen3 : Item + { + + [Constructable] + public Chessmen3() : base( 0xE14 ) + { + Movable = true; + Stackable = false; + } + + public Chessmen3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoGoldIngot.cs b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngot.cs new file mode 100644 index 0000000..8eee598 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGoldIngot : Item + { + + [Constructable] + public DecoGoldIngot() : base( 0x1BE9 ) + { + Movable = true; + Stackable = true; + } + + public DecoGoldIngot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoGoldIngot2.cs b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngot2.cs new file mode 100644 index 0000000..1090956 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGoldIngot2 : Item + { + + [Constructable] + public DecoGoldIngot2() : base( 0x1BEC ) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots.cs b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots.cs new file mode 100644 index 0000000..2241dd4 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGoldIngots : Item + { + + [Constructable] + public DecoGoldIngots() : base( 0x1BEA ) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots2.cs b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots2.cs new file mode 100644 index 0000000..b018998 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGoldIngots2 : Item + { + + [Constructable] + public DecoGoldIngots2() : base( 0x1BEB ) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots3.cs b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots3.cs new file mode 100644 index 0000000..a1c57c4 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGoldIngots3 : Item + { + + [Constructable] + public DecoGoldIngots3() : base( 0x1BED ) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots4.cs b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots4.cs new file mode 100644 index 0000000..ff3a8d8 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoGoldIngots4.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGoldIngots4 : Item + { + + [Constructable] + public DecoGoldIngots4() : base( 0x1BEE ) + { + Movable = true; + Stackable = false; + } + + public DecoGoldIngots4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngot.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngot.cs new file mode 100644 index 0000000..82e0419 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngot : Item + { + + [Constructable] + public DecoIronIngot() : base( 0x1BEF ) + { + Movable = true; + Stackable = true; + } + + public DecoIronIngot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngot2.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngot2.cs new file mode 100644 index 0000000..ad72e76 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngot2 : Item + { + + [Constructable] + public DecoIronIngot2() : base( 0x1BEF ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngots.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots.cs new file mode 100644 index 0000000..628c0b5 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngots : Item + { + + [Constructable] + public DecoIronIngots() : base( 0x1BF1 ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngots2.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots2.cs new file mode 100644 index 0000000..deb71a3 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngots2 : Item + { + + [Constructable] + public DecoIronIngots2() : base( 0x1BF0 ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngots3.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots3.cs new file mode 100644 index 0000000..7a0d8a7 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngots3 : Item + { + + [Constructable] + public DecoIronIngots3() : base( 0x1BF0 ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngots4.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots4.cs new file mode 100644 index 0000000..e92e445 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots4.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngots4 : Item + { + + [Constructable] + public DecoIronIngots4() : base( 0x1BF1 ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngots5.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots5.cs new file mode 100644 index 0000000..ba07b7e --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots5.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngots5 : Item + { + + [Constructable] + public DecoIronIngots5() : base( 0x1BF3 ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots5( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoIronIngots6.cs b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots6.cs new file mode 100644 index 0000000..f9e321e --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoIronIngots6.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoIronIngots6 : Item + { + + [Constructable] + public DecoIronIngots6() : base( 0x1BF4 ) + { + Movable = true; + Stackable = false; + } + + public DecoIronIngots6( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngot.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngot.cs new file mode 100644 index 0000000..dc8e0d6 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngot : Item + { + + [Constructable] + public DecoSilverIngot() : base( 0x1BF5 ) + { + Movable = true; + Stackable = true; + } + + public DecoSilverIngot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngot2.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngot2.cs new file mode 100644 index 0000000..5dee7e9 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngot2 : Item + { + + [Constructable] + public DecoSilverIngot2() : base( 0x1BF8 ) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots.cs new file mode 100644 index 0000000..2af746a --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngots : Item + { + + [Constructable] + public DecoSilverIngots() : base( 0x1BFA ) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots2.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots2.cs new file mode 100644 index 0000000..515e38d --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngots2 : Item + { + + [Constructable] + public DecoSilverIngots2() : base( 0x1BF6 ) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots3.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots3.cs new file mode 100644 index 0000000..9946de4 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngots3 : Item + { + + [Constructable] + public DecoSilverIngots3() : base( 0x1BF7 ) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots4.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots4.cs new file mode 100644 index 0000000..aa2ecb8 --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots4.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngots4 : Item + { + + [Constructable] + public DecoSilverIngots4() : base( 0x1BF9 ) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots5.cs b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots5.cs new file mode 100644 index 0000000..b1d503f --- /dev/null +++ b/Scripts/Items/Special/Rares/Ingots/DecoSilverIngots5.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSilverIngots5 : Item + { + + [Constructable] + public DecoSilverIngots5() : base( 0x1BFA ) + { + Movable = true; + Stackable = false; + } + + public DecoSilverIngots5( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Jars/EmptyJars.cs b/Scripts/Items/Special/Rares/Jars/EmptyJars.cs new file mode 100644 index 0000000..0cab8fc --- /dev/null +++ b/Scripts/Items/Special/Rares/Jars/EmptyJars.cs @@ -0,0 +1,155 @@ +using System; + +namespace Server.Items +{ + public class EmptyJar : Item + { + [Constructable] + public EmptyJar() + : base(0x1005) + { + Movable = true; + Stackable = false; + } + + public EmptyJar(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars : Item + { + [Constructable] + public EmptyJars() + : base(0xe44) + { + Movable = true; + Stackable = false; + } + + public EmptyJars(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars2 : Item + { + [Constructable] + public EmptyJars2() + : base(0xe45) + { + Movable = true; + Stackable = false; + } + + public EmptyJars2(Serial serial) + + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars3 : Item + { + [Constructable] + public EmptyJars3() + : base(0xe46) + { + Movable = true; + Stackable = false; + } + + public EmptyJars3(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EmptyJars4 : Item + { + [Constructable] + public EmptyJars4() + : base(0xe47) + { + Movable = true; + Stackable = false; + } + + public EmptyJars4(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Jars/FullJars.cs b/Scripts/Items/Special/Rares/Jars/FullJars.cs new file mode 100644 index 0000000..5ade39f --- /dev/null +++ b/Scripts/Items/Special/Rares/Jars/FullJars.cs @@ -0,0 +1,94 @@ +using System; + +namespace Server.Items +{ + public class DecoFullJar : Item + { + [Constructable] + public DecoFullJar() + : base(0x1006) + { + Movable = true; + Stackable = false; + } + + public DecoFullJar(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DecoFullJars3 : Item + { + [Constructable] + public DecoFullJars3() + : base(0xE4a) + { + Movable = true; + Stackable = false; + } + + public DecoFullJars3(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class DecoFullJars4 : Item + { + [Constructable] + public DecoFullJars4() + : base(0xE4b) + { + Movable = true; + Stackable = false; + } + + public DecoFullJars4(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Jars/HalfEmptyJars.cs b/Scripts/Items/Special/Rares/Jars/HalfEmptyJars.cs new file mode 100644 index 0000000..0f01c9e --- /dev/null +++ b/Scripts/Items/Special/Rares/Jars/HalfEmptyJars.cs @@ -0,0 +1,154 @@ +using System; + +namespace Server.Items +{ + public class HalfEmptyJar : Item + { + [Constructable] + public HalfEmptyJar() + : base(0x1007) + { + Movable = true; + Stackable = false; + } + + public HalfEmptyJar(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class HalfEmptyJars : Item + { + [Constructable] + public HalfEmptyJars() + : base(0xe4c) + { + Movable = true; + Stackable = false; + } + + public HalfEmptyJars(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Jars2 : Item + { + [Constructable] + public Jars2() + : base(0xE4d) + { + Movable = true; + Stackable = false; + } + + public Jars2(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Jars3 : Item + { + [Constructable] + public Jars3() + : base(0xE4e) + { + Movable = true; + Stackable = false; + } + + public Jars3(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class Jars4 : Item + { + [Constructable] + public Jars4() + : base(0xE4f) + { + Movable = true; + Stackable = false; + } + + public Jars4(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Rares/Magic/DecoCrystalBall.cs b/Scripts/Items/Special/Rares/Magic/DecoCrystalBall.cs new file mode 100644 index 0000000..7af3592 --- /dev/null +++ b/Scripts/Items/Special/Rares/Magic/DecoCrystalBall.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoCrystalBall : Item + { + + [Constructable] + public DecoCrystalBall() : base( 0xE2E ) + { + Movable = true; + Stackable = false; + } + + public DecoCrystalBall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Magic/DecoMagicalCrystal.cs b/Scripts/Items/Special/Rares/Magic/DecoMagicalCrystal.cs new file mode 100644 index 0000000..1ce3e86 --- /dev/null +++ b/Scripts/Items/Special/Rares/Magic/DecoMagicalCrystal.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoMagicalCrystal : Item + { + + [Constructable] + public DecoMagicalCrystal() : base( 0x1F19 ) + { + Movable = true; + Stackable = false; + } + + public DecoMagicalCrystal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Misc/DecoSpittoon.cs b/Scripts/Items/Special/Rares/Misc/DecoSpittoon.cs new file mode 100644 index 0000000..e048ddf --- /dev/null +++ b/Scripts/Items/Special/Rares/Misc/DecoSpittoon.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoSpittoon : Item + { + + [Constructable] + public DecoSpittoon() : base( 0x1003 ) + { + Movable = true; + Stackable = false; + } + + public DecoSpittoon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs new file mode 100644 index 0000000..478ba71 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoBlackmoor.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoBlackmoor : Item + { + + [Constructable] + public DecoBlackmoor() : base( 0xF79 ) + { + Movable = true; + Stackable = false; + } + + public DecoBlackmoor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs new file mode 100644 index 0000000..92cc401 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoBloodspawn.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoBloodspawn : Item + { + + [Constructable] + public DecoBloodspawn() : base( 0xF7C ) + { + Movable = true; + Stackable = false; + } + + public DecoBloodspawn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoBrimstone.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoBrimstone.cs new file mode 100644 index 0000000..a14f7a9 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoBrimstone.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoBrimstone : Item + { + + [Constructable] + public DecoBrimstone() : base( 0xF7F ) + { + Movable = true; + Stackable = false; + } + + public DecoBrimstone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs new file mode 100644 index 0000000..59829eb --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoDragonsBlood.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoDragonsBlood : Item + { + + [Constructable] + public DecoDragonsBlood() : base( 0x4077 ) + { + Movable = true; + Stackable = false; + } + + public DecoDragonsBlood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs new file mode 100644 index 0000000..36175cc --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoDragonsBlood2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoDragonsBlood2 : Item + { + + [Constructable] + public DecoDragonsBlood2() : base( 0xF82 ) + { + Movable = true; + Stackable = false; + } + + public DecoDragonsBlood2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs new file mode 100644 index 0000000..4c5d333 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoEyeOfNewt.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoEyeOfNewt : Item + { + + [Constructable] + public DecoEyeOfNewt() : base( 0xF87 ) + { + Movable = true; + Stackable = false; + } + + public DecoEyeOfNewt( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGarlic.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlic.cs new file mode 100644 index 0000000..6ce2141 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlic.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGarlic : Item + { + + [Constructable] + public DecoGarlic() : base( 0x18E1 ) + { + Movable = true; + Stackable = false; + } + + public DecoGarlic( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGarlic2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlic2.cs new file mode 100644 index 0000000..6739a92 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlic2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGarlic2 : Item + { + + [Constructable] + public DecoGarlic2() : base( 0x18E2 ) + { + Movable = true; + Stackable = false; + } + + public DecoGarlic2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs new file mode 100644 index 0000000..1d16731 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlicBulb.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGarlicBulb : Item + { + + [Constructable] + public DecoGarlicBulb() : base( 0x18E3 ) + { + Movable = true; + Stackable = false; + } + + public DecoGarlicBulb( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs new file mode 100644 index 0000000..4238dae --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGarlicBulb2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGarlicBulb2 : Item + { + + [Constructable] + public DecoGarlicBulb2() : base( 0x18E4 ) + { + Movable = true; + Stackable = false; + } + + public DecoGarlicBulb2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGinseng.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGinseng.cs new file mode 100644 index 0000000..6ead231 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGinseng.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGinseng : Item + { + + [Constructable] + public DecoGinseng() : base( 0x18E9 ) + { + Movable = true; + Stackable = false; + } + + public DecoGinseng( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGinseng2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGinseng2.cs new file mode 100644 index 0000000..7fa2dac --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGinseng2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGinseng2 : Item + { + + [Constructable] + public DecoGinseng2() : base( 0x18EA ) + { + Movable = true; + Stackable = false; + } + + public DecoGinseng2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs new file mode 100644 index 0000000..296771d --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGinsengRoot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGinsengRoot : Item + { + + [Constructable] + public DecoGinsengRoot() : base( 0x18EB ) + { + Movable = true; + Stackable = false; + } + + public DecoGinsengRoot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs new file mode 100644 index 0000000..e69658b --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoGinsengRoot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoGinsengRoot2 : Item + { + + [Constructable] + public DecoGinsengRoot2() : base( 0x18EC ) + { + Movable = true; + Stackable = false; + } + + public DecoGinsengRoot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake.cs new file mode 100644 index 0000000..cea514c --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoMandrake : Item + { + + [Constructable] + public DecoMandrake() : base( 0x18DF ) + { + Movable = true; + Stackable = false; + } + + public DecoMandrake( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake2.cs new file mode 100644 index 0000000..4735ef7 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoMandrake2 : Item + { + + [Constructable] + public DecoMandrake2() : base( 0x18E0 ) + { + Movable = true; + Stackable = false; + } + + public DecoMandrake2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake3.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake3.cs new file mode 100644 index 0000000..59c0d62 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrake3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoMandrake3 : Item + { + + [Constructable] + public DecoMandrake3() : base( 0x18DF ) + { + Movable = true; + Stackable = false; + } + + public DecoMandrake3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs new file mode 100644 index 0000000..e31a1b6 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrakeRoot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoMandrakeRoot : Item + { + + [Constructable] + public DecoMandrakeRoot() : base( 0x18DE ) + { + Movable = true; + Stackable = false; + } + + public DecoMandrakeRoot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs new file mode 100644 index 0000000..ced90f7 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoMandrakeRoot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoMandrakeRoot2 : Item + { + + [Constructable] + public DecoMandrakeRoot2() : base( 0x18DD ) + { + Movable = true; + Stackable = false; + } + + public DecoMandrakeRoot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade.cs new file mode 100644 index 0000000..f210cc5 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoNightshade : Item + { + + [Constructable] + public DecoNightshade() : base( 0x18E7 ) + { + Movable = true; + Stackable = false; + } + + public DecoNightshade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade2.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade2.cs new file mode 100644 index 0000000..8f9823e --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoNightshade2 : Item + { + + [Constructable] + public DecoNightshade2() : base( 0x18E5 ) + { + Movable = true; + Stackable = false; + } + + public DecoNightshade2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade3.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade3.cs new file mode 100644 index 0000000..cfe47e7 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoNightshade3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoNightshade3 : Item + { + + [Constructable] + public DecoNightshade3() : base( 0x18E6 ) + { + Movable = true; + Stackable = false; + } + + public DecoNightshade3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoObsidian.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoObsidian.cs new file mode 100644 index 0000000..beb4cf1 --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoObsidian.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoObsidian : Item + { + + [Constructable] + public DecoObsidian() : base( 0xF89 ) + { + Movable = true; + Stackable = false; + } + + public DecoObsidian( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoPumice.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoPumice.cs new file mode 100644 index 0000000..211b5eb --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoPumice.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoPumice : Item + { + + [Constructable] + public DecoPumice() : base( 0xF8B ) + { + Movable = true; + Stackable = false; + } + + public DecoPumice( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs b/Scripts/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs new file mode 100644 index 0000000..815729a --- /dev/null +++ b/Scripts/Items/Special/Rares/PaganReagents/DecoWyrmsHeart.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoWyrmsHeart : Item + { + + [Constructable] + public DecoWyrmsHeart() : base( 0xF91 ) + { + Movable = true; + Stackable = false; + } + + public DecoWyrmsHeart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/Cards.cs b/Scripts/Items/Special/Rares/PlayingCards/Cards.cs new file mode 100644 index 0000000..efa7921 --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/Cards.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Cards : Item + { + + [Constructable] + public Cards() : base( 0xE19 ) + { + Movable = true; + Stackable = false; + } + + public Cards( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/Cards2.cs b/Scripts/Items/Special/Rares/PlayingCards/Cards2.cs new file mode 100644 index 0000000..ad610c4 --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/Cards2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Cards2 : Item + { + + [Constructable] + public Cards2() : base( 0xE16 ) + { + Movable = true; + Stackable = false; + } + + public Cards2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/Cards3.cs b/Scripts/Items/Special/Rares/PlayingCards/Cards3.cs new file mode 100644 index 0000000..beec0e9 --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/Cards3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Cards3 : Item + { + + [Constructable] + public Cards3() : base( 0xE15 ) + { + Movable = true; + Stackable = false; + } + + public Cards3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/Cards4.cs b/Scripts/Items/Special/Rares/PlayingCards/Cards4.cs new file mode 100644 index 0000000..ebef62c --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/Cards4.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Cards4 : Item + { + + [Constructable] + public Cards4() : base( 0xE17 ) + { + Movable = true; + Stackable = false; + } + + public Cards4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/Cards5.cs b/Scripts/Items/Special/Rares/PlayingCards/Cards5.cs new file mode 100644 index 0000000..79e3987 --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/Cards5.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoCards5 : Item + { + + [Constructable] + public DecoCards5() : base( 0xE18 ) + { + Movable = true; + Stackable = false; + } + + public DecoCards5( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/PlayingCards.cs b/Scripts/Items/Special/Rares/PlayingCards/PlayingCards.cs new file mode 100644 index 0000000..a3af6d2 --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/PlayingCards.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class PlayingCards : Item + { + + [Constructable] + public PlayingCards() : base( 0xFA3 ) + { + Movable = true; + Stackable = false; + } + + public PlayingCards( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/PlayingCards/PlayingCards2.cs b/Scripts/Items/Special/Rares/PlayingCards/PlayingCards2.cs new file mode 100644 index 0000000..48660eb --- /dev/null +++ b/Scripts/Items/Special/Rares/PlayingCards/PlayingCards2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class PlayingCards2 : Item + { + + [Constructable] + public PlayingCards2() : base( 0xFA2 ) + { + Movable = true; + Stackable = false; + } + + public PlayingCards2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Stables/Bridle.cs b/Scripts/Items/Special/Rares/Stables/Bridle.cs new file mode 100644 index 0000000..b11fda3 --- /dev/null +++ b/Scripts/Items/Special/Rares/Stables/Bridle.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoBridle : Item + { + + [Constructable] + public DecoBridle() : base( 0x1374 ) + { + Movable = true; + Stackable = false; + } + + public DecoBridle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Stables/Bridle2.cs b/Scripts/Items/Special/Rares/Stables/Bridle2.cs new file mode 100644 index 0000000..fc860d7 --- /dev/null +++ b/Scripts/Items/Special/Rares/Stables/Bridle2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoBridle2 : Item + { + + [Constructable] + public DecoBridle2() : base( 0x1375 ) + { + Movable = true; + Stackable = false; + } + + public DecoBridle2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Stables/DecoHay.cs b/Scripts/Items/Special/Rares/Stables/DecoHay.cs new file mode 100644 index 0000000..d5c0a64 --- /dev/null +++ b/Scripts/Items/Special/Rares/Stables/DecoHay.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoHay : Item + { + + [Constructable] + public DecoHay() : base( 0xF35 ) + { + Movable = true; + Stackable = false; + } + + public DecoHay( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Stables/DecoHay2.cs b/Scripts/Items/Special/Rares/Stables/DecoHay2.cs new file mode 100644 index 0000000..08eb644 --- /dev/null +++ b/Scripts/Items/Special/Rares/Stables/DecoHay2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoHay2 : Item + { + + [Constructable] + public DecoHay2() : base( 0xF34 ) + { + Movable = true; + Stackable = false; + } + + public DecoHay2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Stables/DecoHorseDung.cs b/Scripts/Items/Special/Rares/Stables/DecoHorseDung.cs new file mode 100644 index 0000000..03ef630 --- /dev/null +++ b/Scripts/Items/Special/Rares/Stables/DecoHorseDung.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoHorseDung : Item + { + + [Constructable] + public DecoHorseDung() : base( 0xF3B ) + { + Movable = true; + Stackable = false; + } + + public DecoHorseDung( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs b/Scripts/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs new file mode 100644 index 0000000..6936bc5 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoDeckOfTarot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoDeckOfTarot : Item + { + + [Constructable] + public DecoDeckOfTarot() : base( 0x12AB ) + { + Movable = true; + Stackable = false; + } + + public DecoDeckOfTarot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs b/Scripts/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs new file mode 100644 index 0000000..e5eed00 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoDeckOfTarot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoDeckOfTarot2 : Item + { + + [Constructable] + public DecoDeckOfTarot2() : base( 0x12Ac ) + { + Movable = true; + Stackable = false; + } + + public DecoDeckOfTarot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot.cs new file mode 100644 index 0000000..8635985 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot : Item + { + + [Constructable] + public DecoTarot() : base( 0x12A5 ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot2.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot2.cs new file mode 100644 index 0000000..b9bb2c7 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot2 : Item + { + + [Constructable] + public DecoTarot2() : base( 0x12A6 ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot3.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot3.cs new file mode 100644 index 0000000..998a05f --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot3.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot3 : Item + { + + [Constructable] + public DecoTarot3() : base( 0x12A7 ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot3( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot4.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot4.cs new file mode 100644 index 0000000..a799916 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot4.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot4 : Item + { + + [Constructable] + public DecoTarot4() : base( 0x12A8 ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot4( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot5.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot5.cs new file mode 100644 index 0000000..5f0db27 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot5.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot5 : Item + { + + [Constructable] + public DecoTarot5() : base( 0x12A9 ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot5( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot6.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot6.cs new file mode 100644 index 0000000..4f9e571 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot6.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot6 : Item + { + + [Constructable] + public DecoTarot6() : base( 0x12AA ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot6( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/TarotCards/DecoTarot7.cs b/Scripts/Items/Special/Rares/TarotCards/DecoTarot7.cs new file mode 100644 index 0000000..b518a97 --- /dev/null +++ b/Scripts/Items/Special/Rares/TarotCards/DecoTarot7.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoTarot7 : Item + { + + [Constructable] + public DecoTarot7() : base( 0x12A5 ) + { + Movable = true; + Stackable = false; + } + + public DecoTarot7( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Tinker/ArrowShafts.cs b/Scripts/Items/Special/Rares/Tinker/ArrowShafts.cs new file mode 100644 index 0000000..fae71ee --- /dev/null +++ b/Scripts/Items/Special/Rares/Tinker/ArrowShafts.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class DecoArrowShafts : Item + { + + [Constructable] + public DecoArrowShafts() : base( Utility.Random(2) + 0x1024 ) + { + Movable = true; + Stackable = false; + } + + public DecoArrowShafts( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Tinker/CrossbowBolts.cs b/Scripts/Items/Special/Rares/Tinker/CrossbowBolts.cs new file mode 100644 index 0000000..d1c3f9a --- /dev/null +++ b/Scripts/Items/Special/Rares/Tinker/CrossbowBolts.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class CrossbowBolts : Item + { + + [Constructable] + public CrossbowBolts() : base( 0x1BFC ) + { + Movable = true; + Stackable = false; + } + + public CrossbowBolts( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Tinker/EmptyToolKit.cs b/Scripts/Items/Special/Rares/Tinker/EmptyToolKit.cs new file mode 100644 index 0000000..53774b3 --- /dev/null +++ b/Scripts/Items/Special/Rares/Tinker/EmptyToolKit.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class EmptyToolKit : Item + { + + [Constructable] + public EmptyToolKit() : base( 0x1EB6 ) + { + Movable = true; + Stackable = false; + } + + public EmptyToolKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Tinker/EmptyToolKit2.cs b/Scripts/Items/Special/Rares/Tinker/EmptyToolKit2.cs new file mode 100644 index 0000000..ad740f3 --- /dev/null +++ b/Scripts/Items/Special/Rares/Tinker/EmptyToolKit2.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class EmptyToolKit2 : Item + { + + [Constructable] + public EmptyToolKit2() : base( 0x1EB7 ) + { + Movable = true; + Stackable = false; + } + + public EmptyToolKit2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Tinker/Lockpicks.cs b/Scripts/Items/Special/Rares/Tinker/Lockpicks.cs new file mode 100644 index 0000000..8f2056f --- /dev/null +++ b/Scripts/Items/Special/Rares/Tinker/Lockpicks.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class Lockpicks : Item + { + + [Constructable] + public Lockpicks() : base( Utility.Random(2) + 0x14FD ) + { + Movable = true; + Stackable = false; + } + + public Lockpicks( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/Rares/Tinker/ToolKit.cs b/Scripts/Items/Special/Rares/Tinker/ToolKit.cs new file mode 100644 index 0000000..9070537 --- /dev/null +++ b/Scripts/Items/Special/Rares/Tinker/ToolKit.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class ToolKit : Item + { + + [Constructable] + public ToolKit() : base( Utility.Random(2) + 0x1EBA ) + { + Movable = true; + Stackable = false; + } + + public ToolKit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Special/RewardCake.cs b/Scripts/Items/Special/RewardCake.cs new file mode 100644 index 0000000..12eff76 --- /dev/null +++ b/Scripts/Items/Special/RewardCake.cs @@ -0,0 +1,49 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class RewardCake : Item + { + public override int LabelNumber{ get{ return 1049786; } } // Happy Birthday! ... + + [Constructable] + public RewardCake() : base( 0x9e9 ) + { + Stackable = false; + Weight = 1.0; + Hue = Utility.RandomList(0x135, 0xcd, 0x38, 0x3b, 0x42, 0x4f, 0x11e, 0x60, 0x317, 0x10, 0x136, 0x1f9, 0x1a, 0xeb, 0x86, 0x2e); + LootType = LootType.Blessed; + } + + public RewardCake( Serial serial ) : base( serial ) + { + } + + public override bool DisplayLootType{ get{ return false; } } + + public override void OnDoubleClick( Mobile from ) + { + if (! from.InRange( this.GetWorldLocation(), 1 )) + { + from.LocalOverheadMessage( MessageType.Regular, 906, 1019045 ); // I can't reach that. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Solen Items/BagOfSending.cs b/Scripts/Items/Special/Solen Items/BagOfSending.cs new file mode 100644 index 0000000..44680fb --- /dev/null +++ b/Scripts/Items/Special/Solen Items/BagOfSending.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Targeting; +using Server.Network; + +namespace Server.Items +{ + public enum BagOfSendingHue + { + Yellow, + Blue, + Red + } + + public class BagOfSending : Item, TranslocationItem + { + public static BagOfSendingHue RandomHue() + { + switch ( Utility.Random( 3 ) ) + { + case 0: return BagOfSendingHue.Yellow; + case 1: return BagOfSendingHue.Blue; + default: return BagOfSendingHue.Red; + } + } + + private int m_Charges; + private int m_Recharges; + private BagOfSendingHue m_BagOfSendingHue; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set + { + if ( value > this.MaxCharges ) + m_Charges = this.MaxCharges; + else if ( value < 0 ) + m_Charges = 0; + else + m_Charges = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Recharges + { + get{ return m_Recharges; } + set + { + if ( value > this.MaxRecharges ) + m_Recharges = this.MaxRecharges; + else if ( value < 0 ) + m_Recharges = 0; + else + m_Recharges = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxCharges{ get{ return 30; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxRecharges{ get{ return 255; } } + + public string TranslocationItemName{ get{ return "bag of sending"; } } + + public override int LabelNumber{ get{ return 1054104; } } // a bag of sending + + [CommandProperty( AccessLevel.GameMaster )] + public BagOfSendingHue BagOfSendingHue + { + get{ return m_BagOfSendingHue; } + set + { + m_BagOfSendingHue = value; + + switch ( value ) + { + case BagOfSendingHue.Yellow: this.Hue = 0x8A5; break; + case BagOfSendingHue.Blue: this.Hue = 0x8AD; break; + case BagOfSendingHue.Red: this.Hue = 0x89B; break; + } + } + } + + [Constructable] + public BagOfSending() : this( RandomHue() ) + { + } + + [Constructable] + public BagOfSending( BagOfSendingHue hue ) : base( 0xE76 ) + { + Weight = 2.0; + + this.BagOfSendingHue = hue; + + m_Charges = Utility.RandomMinMax( 3, 9 ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060741, m_Charges.ToString() ); // charges: ~1_val~ + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1060741, m_Charges.ToString() ); // charges: ~1_val~ + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive ) + list.Add( new UseBagEntry( this, Charges > 0 && IsChildOf( from.Backpack ) ) ); + } + + private class UseBagEntry : ContextMenuEntry + { + private BagOfSending m_Bag; + + public UseBagEntry( BagOfSending bag, bool enabled ) : base( 6189 ) + { + m_Bag = bag; + + if ( !enabled ) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + if ( m_Bag.Deleted ) + return; + + Mobile from = Owner.From; + + if ( from.CheckAlive() ) + m_Bag.OnDoubleClick( from ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + if( from.Region.IsPartOf( typeof( Regions.Jail ) ) ) + { + from.SendMessage( "You may not do that in jail." ); + } + else if( !this.IsChildOf( from.Backpack ) ) + { + MessageHelper.SendLocalizedMessageTo(this, from, 1062334, 0x59); // The bag of sending must be in your backpack. + } + else if( this.Charges == 0 ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1042544, 0x59 ); // This item is out of charges. + } + else + { + from.Target = new SendTarget( this ); + } + } + + private class SendTarget : Target + { + private BagOfSending m_Bag; + + public SendTarget( BagOfSending bag ) : base( -1, false, TargetFlags.None ) + { + m_Bag = bag; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Bag.Deleted ) + return; + + if( from.Region.IsPartOf( typeof( Regions.Jail ) ) ) + { + from.SendMessage( "You may not do that in jail." ); + } + else if( !m_Bag.IsChildOf( from.Backpack ) ) + { + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054107, 0x59 ); // The bag of sending must be in your backpack. + } + else if ( m_Bag.Charges == 0 ) + { + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1042544, 0x59 ); // This item is out of charges. + } + else if ( targeted is Item ) + { + Item item = (Item)targeted; + int reqCharges = (int)Math.Max( 1, Math.Ceiling( item.TotalWeight / 10.0 ) ); + + if ( !item.IsChildOf( from.Backpack ) ) + { + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054152, 0x59 ); // You may only send items from your backpack to your bank box. + } + else if ( item is BagOfSending || item is Container ) + { + from.Send( new AsciiMessage( m_Bag.Serial, m_Bag.ItemID, MessageType.Regular, 0x3B2, 3, "", "You cannot send a container through the bag of sending." ) ); + } + else if ( item.LootType == LootType.Cursed ) + { + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054108, 0x59 ); // The bag of sending rejects the cursed item. + } + else if (!item.VerifyMove(from) || item is Server.Engines.Quests.QuestItem || item.Nontransferable) + { + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054109, 0x59 ); // The bag of sending rejects that item. + } + else if ( Spells.SpellHelper.IsDoomGauntlet( from.Map, from.Location ) ) + { + from.SendLocalizedMessage( 1062089 ); // You cannot use that here. + } + else if ( !from.BankBox.TryDropItem( from, item, false ) ) + { + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054110, 0x59 ); // Your bank box is full. + } + else if ( Core.ML && reqCharges > m_Bag.Charges ) + { + from.SendLocalizedMessage( 1079932 ); //You don't have enough charges to send that much weight + } + else + { + m_Bag.Charges -= (Core.ML ? reqCharges : 1); + + MessageHelper.SendLocalizedMessageTo( m_Bag, from, 1054150, 0x59 ); // The item was placed in your bank box. + } + } + } + } + + public BagOfSending( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 1 ); // version + + writer.WriteEncodedInt( (int) m_Recharges ); + + writer.WriteEncodedInt( (int) m_Charges ); + writer.WriteEncodedInt( (int) m_BagOfSendingHue ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_Recharges = reader.ReadEncodedInt(); + goto case 0; + } + case 0: + { + m_Charges = Math.Min( reader.ReadEncodedInt(), MaxCharges ); + m_BagOfSendingHue = (BagOfSendingHue) reader.ReadEncodedInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Solen Items/BallOfSummoning.cs b/Scripts/Items/Special/Solen Items/BallOfSummoning.cs new file mode 100644 index 0000000..9968586 --- /dev/null +++ b/Scripts/Items/Special/Solen Items/BallOfSummoning.cs @@ -0,0 +1,471 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.ContextMenus; +using Server.Network; +using Server.Regions; +using Server.Spells; +using Server.Spells.Ninjitsu; + +namespace Server.Items +{ + public class BallOfSummoning : Item, TranslocationItem + { + private int m_Charges; + private int m_Recharges; + private BaseCreature m_Pet; + private string m_PetName; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set + { + if ( value > this.MaxCharges ) + m_Charges = this.MaxCharges; + else if ( value < 0 ) + m_Charges = 0; + else + m_Charges = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Recharges + { + get{ return m_Recharges; } + set + { + if ( value > this.MaxRecharges ) + m_Recharges = this.MaxRecharges; + else if ( value < 0 ) + m_Recharges = 0; + else + m_Recharges = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxCharges{ get{ return 20; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxRecharges{ get{ return 255; } } + + public string TranslocationItemName{ get{ return "crystal ball of pet summoning"; } } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseCreature Pet + { + get + { + if ( m_Pet != null && m_Pet.Deleted ) + { + m_Pet = null; + InternalUpdatePetName(); + } + + return m_Pet; + } + set + { + m_Pet = value; + InternalUpdatePetName(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string PetName{ get{ return m_PetName; } } + + [Constructable] + public BallOfSummoning() : base( 0xE2E ) + { + Weight = 10.0; + Light = LightType.Circle150; + + m_Charges = Utility.RandomMinMax( 3, 9 ); + + m_PetName = ""; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1054131, m_Charges.ToString() + ( m_PetName.Length == 0 ? "\t " : "\t" + m_PetName ) ); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~] + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, 1054131, m_Charges.ToString() + ( m_PetName.Length == 0 ? "\t " : "\t" + m_PetName ) ); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~] + } + + private delegate void BallCallback( Mobile from ); + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive && this.RootParent == from ) + { + if ( Pet == null ) + { + list.Add( new BallEntry( new BallCallback( LinkPet ), 6180 ) ); + } + else + { + list.Add(new BallEntry(new BallCallback( CastSummonPet ), 6181 )); + list.Add( new BallEntry( new BallCallback( UpdatePetName ), 6183 ) ); + list.Add( new BallEntry( new BallCallback( UnlinkPet ), 6182 ) ); + } + } + } + + private class BallEntry : ContextMenuEntry + { + private BallCallback m_Callback; + + public BallEntry( BallCallback callback, int number ) : base( number, 2 ) + { + m_Callback = callback; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( from.CheckAlive() ) + m_Callback( from ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( this.RootParent != from ) // TODO: Previous implementation allowed use on ground, without house protection checks. What is the correct behavior? + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042001 ); // That must be in your pack for you to use it. + return; + } + + AnimalFormContext animalContext = AnimalForm.GetContext( from ); + + if( Core.ML && animalContext != null ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1080073 ); // You cannot use a Crystal Ball of Pet Summoning while in animal form. + return; + } + + if ( Pet == null ) + { + LinkPet( from ); + } + else + { + CastSummonPet( from ); + } + } + + public void LinkPet( Mobile from ) + { + BaseCreature pet = this.Pet; + + if ( Deleted || pet != null || this.RootParent != from ) + return; + + from.SendLocalizedMessage( 1054114 ); // Target your pet that you wish to link to this Crystal Ball of Pet Summoning. + from.Target = new PetLinkTarget( this ); + } + + private class PetLinkTarget : Target + { + private BallOfSummoning m_Ball; + + public PetLinkTarget( BallOfSummoning ball ) : base( -1, false, TargetFlags.None ) + { + m_Ball = ball; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Ball.Deleted || m_Ball.Pet != null ) + return; + + if ( m_Ball.RootParent != from ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042001 ); // That must be in your pack for you to use it. + } + else if ( targeted is BaseCreature ) + { + BaseCreature creature = (BaseCreature)targeted; + + if ( !creature.Controlled || creature.ControlMaster != from ) + { + MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054117, 0x59 ); // You may only link your own pets to a Crystal Ball of Pet Summoning. + } + else if ( !creature.IsBonded ) + { + MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054118, 0x59 ); // You must bond with your pet before it can be linked to a Crystal Ball of Pet Summoning. + } + else + { + MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054119, 0x59 ); // Your pet is now linked to this Crystal Ball of Pet Summoning. + + m_Ball.Pet = creature; + } + } + else if ( targeted == m_Ball ) + { + MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054115, 0x59 ); // The Crystal Ball of Pet Summoning cannot summon itself. + } + else + { + MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054116, 0x59 ); // Only pets can be linked to this Crystal Ball of Pet Summoning. + } + } + } + + public void CastSummonPet( Mobile from ) + { + BaseCreature pet = this.Pet; + + if ( Deleted || pet == null || this.RootParent != from ) + return; + + if ( Charges == 0 ) + { + SendLocalizedMessageTo( from, 1054122 ); // The Crystal Ball darkens. It must be charged before it can be used again. + } + else if ( pet is BaseMount && ((BaseMount)pet).Rider == from ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1054124, 0x36 ); // The Crystal Ball fills with a yellow mist. Why would you summon your pet while riding it? + } + else if ( pet.Map == Map.Internal && ( !pet.IsStabled || (from.Followers + pet.ControlSlots) > from.FollowersMax ) ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1054125, 0x5 ); // The Crystal Ball fills with a blue mist. Your pet is not responding to the summons. + } + else if ( ( !pet.Controlled || pet.ControlMaster != from ) && !from.Stabled.Contains( pet ) ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1054126, 0x8FD ); // The Crystal Ball fills with a grey mist. You are not the owner of the pet you are attempting to summon. + } + else if ( !pet.IsBonded ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1054127, 0x22 ); // The Crystal Ball fills with a red mist. You appear to have let your bond to your pet deteriorate. + } + else if (from.Map == Map.Ilshenar || from.Region.IsPartOf(typeof(DungeonRegion)) || from.Region.IsPartOf(typeof(Jail)) || from.Region.IsPartOf(typeof(Server.Engines.ConPVP.SafeZone))) + { + from.Send( new AsciiMessage( this.Serial, this.ItemID, MessageType.Regular, 0x22, 3, "", "You cannot summon your pet to this location." ) ); + } + else if ( Core.ML && from is PlayerMobile && DateTime.Now < ((PlayerMobile)from).LastPetBallTime.AddSeconds( 15.0 ) ) + { + MessageHelper.SendLocalizedMessageTo( this, from, 1080072, 0x22 ); // You must wait a few seconds before you can summon your pet. + } + else + { + if( Core.ML ) + new PetSummoningSpell( this, from ).Cast(); + else + SummonPet( from ); + } + + } + + + public void SummonPet( Mobile from ) + { + BaseCreature pet = this.Pet; + + if (pet == null) + return; + + Charges--; + + if ( pet.IsStabled ) + { + pet.SetControlMaster( from ); + + if ( pet.Summoned ) + pet.SummonMaster = from; + + pet.ControlTarget = from; + pet.ControlOrder = OrderType.Follow; + + pet.IsStabled = false; + pet.StabledBy = null; + from.Stabled.Remove( pet ); + + if (from is PlayerMobile) + ((PlayerMobile)from).AutoStabled.Remove(pet); + } + + pet.MoveToWorld( from.Location, from.Map ); + + MessageHelper.SendLocalizedMessageTo( this, from, 1054128, 0x43 ); // The Crystal Ball fills with a green mist. Your pet has been summoned. + + if ( from is PlayerMobile ) + { + ((PlayerMobile)from).LastPetBallTime = DateTime.Now; + } + } + + public void UnlinkPet( Mobile from ) + { + if ( !Deleted && Pet != null && this.RootParent == from ) + { + Pet = null; + + SendLocalizedMessageTo( from, 1054120 ); // This crystal ball is no longer linked to a pet. + } + } + + public void UpdatePetName( Mobile from ) + { + InternalUpdatePetName(); + } + + private void InternalUpdatePetName() + { + BaseCreature pet = this.Pet; + + if ( pet == null ) + m_PetName = ""; + else + m_PetName = pet.Name; + + InvalidateProperties(); + } + + public BallOfSummoning( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 1 ); // version + + writer.WriteEncodedInt( (int) m_Recharges ); + + writer.WriteEncodedInt( (int) m_Charges ); + writer.Write( (Mobile) this.Pet ); + writer.Write( (string) m_PetName ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_Recharges = reader.ReadEncodedInt(); + goto case 0; + } + case 0: + { + m_Charges = Math.Min( reader.ReadEncodedInt(), MaxCharges ); + this.Pet = (BaseCreature) reader.ReadMobile(); + m_PetName = reader.ReadString(); + break; + } + } + } + + private class PetSummoningSpell : Spell + { + private static SpellInfo m_Info = new SpellInfo( "Ball Of Summoning", "", 230 ); + + private BallOfSummoning m_Ball; + private Mobile m_Caster; + + public PetSummoningSpell( BallOfSummoning ball, Mobile caster ) + : base( caster, null, m_Info ) + { + m_Caster = caster; + m_Ball = ball; + } + + public override bool ClearHandsOnCast { get { return false; } } + public override bool RevealOnCast { get { return true; } } + + public override TimeSpan GetCastRecovery() + { + return TimeSpan.Zero; + } + + public override double CastDelayFastScalar { get { return 0; } } + + public override TimeSpan CastDelayBase + { + get + { + return TimeSpan.FromSeconds( 2.0 ); + } + } + + public override int GetMana() + { + return 0; + } + + public override bool ConsumeReagents() + { + return true; + } + + public override bool CheckFizzle() + { + return true; + } + + private bool m_Stop; + + public void Stop() + { + m_Stop = true; + Disturb( DisturbType.Hurt, false, false ); + } + + public override bool CheckDisturb( DisturbType type, bool checkFirst, bool resistable ) + { + if( type == DisturbType.EquipRequest || type == DisturbType.UseRequest/* || type == DisturbType.Hurt*/ ) + return false; + + return true; + } + + public override void DoHurtFizzle() + { + if( !m_Stop ) + base.DoHurtFizzle(); + } + + public override void DoFizzle() + { + if( !m_Stop ) + base.DoFizzle(); + } + + public override void OnDisturb( DisturbType type, bool message ) + { + if( message && !m_Stop ) + Caster.SendLocalizedMessage( 1080074 ); // You have been disrupted while attempting to summon your pet! + } + + public override void OnCast() + { + m_Ball.SummonPet( m_Caster ); + + FinishSequence(); + } + } + } +} diff --git a/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs b/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs new file mode 100644 index 0000000..dc391bf --- /dev/null +++ b/Scripts/Items/Special/Solen Items/BraceletOfBinding.cs @@ -0,0 +1,474 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Network; +using Server.Prompts; +using Server.Targeting; +using Server.Spells; +using Server.Mobiles; + +namespace Server.Items +{ + public class BraceletOfBinding : BaseBracelet, TranslocationItem + { + private int m_Charges; + private int m_Recharges; + private string m_Inscription; + private BraceletOfBinding m_Bound; + private TransportTimer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set + { + if ( value > this.MaxCharges ) + m_Charges = this.MaxCharges; + else if ( value < 0 ) + m_Charges = 0; + else + m_Charges = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Recharges + { + get{ return m_Recharges; } + set + { + if ( value > this.MaxRecharges ) + m_Recharges = this.MaxRecharges; + else if ( value < 0 ) + m_Recharges = 0; + else + m_Recharges = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxCharges{ get{ return 20; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxRecharges{ get{ return 255; } } + + public string TranslocationItemName{ get{ return "bracelet of binding"; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string Inscription + { + get{ return m_Inscription; } + set + { + m_Inscription = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BraceletOfBinding Bound + { + get + { + if ( m_Bound != null && m_Bound.Deleted ) + m_Bound = null; + + return m_Bound; + } + set{ m_Bound = value; } + } + + [Constructable] + public BraceletOfBinding() : base( 0x1086 ) + { + Hue = 0x489; + Weight = 1.0; + + m_Inscription = ""; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( 1054000, m_Charges.ToString() + ( m_Inscription.Length == 0 ? "\t " : " :\t" + m_Inscription ) ); // a bracelet of binding : ~1_val~ ~2_val~ + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, 1054000, m_Charges.ToString() + ( m_Inscription.Length == 0 ? "\t " : " :\t" + m_Inscription ) ); // a bracelet of binding : ~1_val~ ~2_val~ + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive && this.IsChildOf( from ) ) + { + BraceletOfBinding bound = this.Bound; + + list.Add( new BraceletEntry( new BraceletCallback( Activate ), 6170, bound != null ) ); + list.Add( new BraceletEntry( new BraceletCallback( Search ), 6171, bound != null ) ); + list.Add( new BraceletEntry( new BraceletCallback( Bind ), bound == null ? 6173 : 6174, true ) ); + list.Add( new BraceletEntry( new BraceletCallback( Inscribe ), 6175, true ) ); + } + } + + private delegate void BraceletCallback( Mobile from ); + + private class BraceletEntry : ContextMenuEntry + { + private BraceletCallback m_Callback; + + public BraceletEntry( BraceletCallback callback, int number, bool enabled ) : base( number ) + { + m_Callback = callback; + + if ( !enabled ) + Flags |= CMEFlags.Disabled; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( from.CheckAlive() ) + m_Callback( from ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + BraceletOfBinding bound = this.Bound; + + if ( Bound == null ) + { + Bind( from ); + } + else + { + Activate( from ); + } + } + + public void Activate( Mobile from ) + { + BraceletOfBinding bound = this.Bound; + + if ( Deleted || bound == null ) + return; + + if ( !this.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else if ( m_Timer != null ) + { + from.SendLocalizedMessage( 1054013 ); // The bracelet is already attempting contact. You decide to wait a moment. + } + else + { + from.PlaySound( 0xF9 ); + from.LocalOverheadMessage( MessageType.Regular, 0x5D, true, "* You concentrate on the bracelet to summon its power *" ); + + from.Frozen = true; + + m_Timer = new TransportTimer( this, from ); + m_Timer.Start(); + } + } + + private class TransportTimer : Timer + { + private BraceletOfBinding m_Bracelet; + private Mobile m_From; + + public TransportTimer( BraceletOfBinding bracelet, Mobile from ) : base( TimeSpan.FromSeconds( 2.0 ) ) + { + m_Bracelet = bracelet; + m_From = from; + } + + protected override void OnTick() + { + m_Bracelet.m_Timer = null; + m_From.Frozen = false; + + if ( m_Bracelet.Deleted || m_From.Deleted ) + return; + + if ( m_Bracelet.CheckUse( m_From, false ) ) + { + Mobile boundRoot = m_Bracelet.Bound.RootParent as Mobile; + + if ( boundRoot != null ) + { + m_Bracelet.Charges--; + + BaseCreature.TeleportPets( m_From, boundRoot.Location, boundRoot.Map, true ); + + m_From.PlaySound( 0x1FC ); + m_From.MoveToWorld( boundRoot.Location, boundRoot.Map ); + m_From.PlaySound( 0x1FC ); + } + } + } + } + + public void Search( Mobile from ) + { + BraceletOfBinding bound = this.Bound; + + if ( Deleted || bound == null ) + return; + + if ( !this.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else + { + CheckUse( from, true ); + } + } + + private bool CheckUse( Mobile from, bool successMessage ) + { + BraceletOfBinding bound = this.Bound; + + if ( bound == null ) + return false; + + Mobile boundRoot = bound.RootParent as Mobile; + + if ( Charges == 0 ) + { + from.SendLocalizedMessage( 1054005 ); // The bracelet glows black. It must be charged before it can be used again. + return false; + } + else if ( from.FindItemOnLayer( Layer.Bracelet ) != this ) + { + from.SendLocalizedMessage( 1054004 ); // You must equip the bracelet in order to use its power. + return false; + } + else if ( boundRoot == null || boundRoot.NetState == null || boundRoot.FindItemOnLayer( Layer.Bracelet ) != bound ) + { + from.SendLocalizedMessage( 1054006 ); // The bracelet emits a red glow. The bracelet's twin is not available for transport. + return false; + } + else if ( !Core.AOS && from.Map != boundRoot.Map ) + { + from.SendLocalizedMessage( 1054014 ); // The bracelet glows black. The bracelet's target is on another facet. + return false; + } + else if ( Factions.Sigil.ExistsOn( from ) ) + { + from.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return false; + } + else if ( !SpellHelper.CheckTravel( from, TravelCheckType.RecallFrom ) ) + { + return false; + } + else if ( !SpellHelper.CheckTravel( from, boundRoot.Map, boundRoot.Location, TravelCheckType.RecallTo ) ) + { + return false; + } + else if ( boundRoot.Map == Map.Felucca && from is PlayerMobile && ((PlayerMobile)from).Young ) + { + from.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young. + return false; + } + else if ( from.Kills >= 5 && boundRoot.Map != Map.Felucca ) + { + from.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + return false; + } + else if ( from.Criminal ) + { + from.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( from ) ) + { + from.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + return false; + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( from ) ) + { + from.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + return false; + } + else if (from.Region.IsPartOf(typeof(Server.Regions.Jail))) + { + from.SendLocalizedMessage(1114345, "", 0x35); // You'll need a better jailbreak plan then that! + return false; + } + else if ( boundRoot.Region.IsPartOf( typeof( Server.Regions.Jail ) ) ) + { + from.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + return false; + } + else + { + if ( successMessage ) + from.SendLocalizedMessage( 1054015 ); // The bracelet's twin is available for transport. + + return true; + } + } + + public void Bind( Mobile from ) + { + if ( Deleted ) + return; + + if ( !this.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage( 1054001 ); // Target the bracelet of binding you wish to bind this bracelet to. + from.Target = new BindTarget( this ); + } + } + + private class BindTarget : Target + { + private BraceletOfBinding m_Bracelet; + + public BindTarget( BraceletOfBinding bracelet ) : base( -1, false, TargetFlags.None ) + { + m_Bracelet = bracelet; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Bracelet.Deleted ) + return; + + if ( !m_Bracelet.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else if ( targeted is BraceletOfBinding ) + { + BraceletOfBinding bindBracelet = (BraceletOfBinding)targeted; + + if ( bindBracelet == m_Bracelet ) + { + from.SendLocalizedMessage( 1054012 ); // You cannot bind a bracelet of binding to itself! + } + else if ( !bindBracelet.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage( 1054003 ); // You bind the bracelet to its counterpart. The bracelets glow with power. + from.PlaySound( 0x1FA ); + + m_Bracelet.Bound = bindBracelet; + } + } + else + { + from.SendLocalizedMessage( 1054002 ); // You can only bind this bracelet to another bracelet of binding! + } + } + } + + public void Inscribe( Mobile from ) + { + if ( Deleted ) + return; + + if ( !this.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage( 1054009 ); // Enter the text to inscribe upon the bracelet : + from.Prompt = new InscribePrompt( this ); + } + } + + private class InscribePrompt : Prompt + { + private BraceletOfBinding m_Bracelet; + + public InscribePrompt( BraceletOfBinding bracelet ) + { + m_Bracelet = bracelet; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Bracelet.Deleted ) + return; + + if ( !m_Bracelet.IsChildOf( from ) ) + { + from.SendLocalizedMessage( 1042664 ); // You must have the object in your backpack to use it. + } + else + { + from.SendLocalizedMessage( 1054011 ); // You mark the bracelet with your inscription. + m_Bracelet.Inscription = text; + } + } + + public override void OnCancel( Mobile from ) + { + from.SendLocalizedMessage( 1054010 ); // You decide not to inscribe the bracelet at this time. + } + } + + public BraceletOfBinding( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 1 ); // version + + writer.WriteEncodedInt( (int) m_Recharges ); + + writer.WriteEncodedInt( (int) m_Charges ); + writer.Write( (string) m_Inscription ); + writer.Write( (Item) this.Bound ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + { + m_Recharges = reader.ReadEncodedInt(); + goto case 0; + } + case 0: + { + m_Charges = Math.Min( reader.ReadEncodedInt(), MaxCharges ); + m_Inscription = reader.ReadString(); + this.Bound = (BraceletOfBinding) reader.ReadItem(); + break; + } + } + } + } +} diff --git a/Scripts/Items/Special/Solen Items/MessageHelper.cs b/Scripts/Items/Special/Solen Items/MessageHelper.cs new file mode 100644 index 0000000..4c65428 --- /dev/null +++ b/Scripts/Items/Special/Solen Items/MessageHelper.cs @@ -0,0 +1,23 @@ +using System; +using Server.Network; + +namespace Server +{ + public class MessageHelper + { + public static void SendLocalizedMessageTo(Item from, Mobile to, int number, int hue) + { + SendLocalizedMessageTo(from, to, number, "", hue); + } + + public static void SendLocalizedMessageTo(Item from, Mobile to, int number, string args, int hue) + { + to.Send(new MessageLocalized(from.Serial, from.ItemID, MessageType.Regular, hue, 3, number, "", args)); + } + + public static void SendMessageTo(Item from, Mobile to, string text, int hue) + { + to.Send(new UnicodeMessage(from.Serial, from.ItemID, MessageType.Regular, hue, 3, "ENU", "", text)); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Solen Items/PowderOfTranslocation.cs b/Scripts/Items/Special/Solen Items/PowderOfTranslocation.cs new file mode 100644 index 0000000..087c0f2 --- /dev/null +++ b/Scripts/Items/Special/Solen Items/PowderOfTranslocation.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public interface TranslocationItem + { + int Charges{ get; set; } + int Recharges{ get; set; } + int MaxCharges{ get; } + int MaxRecharges{ get; } + string TranslocationItemName{ get; } + } + + public class PowderOfTranslocation : Item + { + [Constructable] + public PowderOfTranslocation() : this( 1 ) + { + } + + [Constructable] + public PowderOfTranslocation( int amount ) : base( 0x26B8 ) + { + Stackable = true; + Weight = 0.1; + Amount = amount; + } + + + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + from.Target = new InternalTarget( this ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + + private class InternalTarget : Target + { + private PowderOfTranslocation m_Powder; + + public InternalTarget( PowderOfTranslocation powder ) : base( -1, false, TargetFlags.None ) + { + m_Powder = powder; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Powder.Deleted ) + return; + + if ( !from.InRange( m_Powder.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + else if ( targeted is TranslocationItem ) + { + TranslocationItem transItem = (TranslocationItem)targeted; + + if ( transItem.Charges >= transItem.MaxCharges ) + { + MessageHelper.SendLocalizedMessageTo( m_Powder, from, 1054137, 0x59 ); // This item cannot absorb any more powder of translocation. + } + else if ( transItem.Recharges >= transItem.MaxRecharges ) + { + MessageHelper.SendLocalizedMessageTo( m_Powder, from, 1054138, 0x59 ); // This item has been oversaturated with powder of translocation and can no longer be recharged. + } + else + { + if ( transItem.Charges + m_Powder.Amount > transItem.MaxCharges ) + { + int delta = transItem.MaxCharges - transItem.Charges; + + m_Powder.Amount -= delta; + transItem.Charges = transItem.MaxCharges; + transItem.Recharges += delta; + } + else + { + transItem.Charges += m_Powder.Amount; + transItem.Recharges += m_Powder.Amount; + m_Powder.Delete(); + } + + if ( transItem is Item ) + { + // The ~1_translocationItem~ glows with green energy and absorbs magical power from the powder. + MessageHelper.SendLocalizedMessageTo( (Item)transItem, from, 1054139, transItem.TranslocationItemName, 0x43 ); + } + } + } + else + { + MessageHelper.SendLocalizedMessageTo( m_Powder, from, 1054140, 0x59 ); // Powder of translocation has no effect on this item. + } + } + } + + public PowderOfTranslocation( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Solen Items/ZoogiFungus.cs b/Scripts/Items/Special/Solen Items/ZoogiFungus.cs new file mode 100644 index 0000000..a58533d --- /dev/null +++ b/Scripts/Items/Special/Solen Items/ZoogiFungus.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ZoogiFungus : Item, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return (Core.ML); } } + + [Constructable] + public ZoogiFungus() : this( 1 ) + { + } + + [Constructable] + public ZoogiFungus( int amount ) : base( 0x26B7 ) + { + Stackable = true; + Weight = 0.1; + Amount = amount; + } + + public ZoogiFungus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/SoulStone.cs b/Scripts/Items/Special/SoulStone.cs new file mode 100644 index 0000000..1688c41 --- /dev/null +++ b/Scripts/Items/Special/SoulStone.cs @@ -0,0 +1,1033 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Accounting; +using Server.Engines.VeteranRewards; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Items +{ + public class SoulStone : Item, ISecurable + { + public override int LabelNumber { get { return 1030899; } } // soulstone + + private int m_ActiveItemID; + private int m_InactiveItemID; + + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int ActiveItemID + { + get { return m_ActiveItemID; } + set + { + m_ActiveItemID = value; + + if( !IsEmpty ) + this.ItemID = m_ActiveItemID; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int InactiveItemID + { + get { return m_InactiveItemID; } + set + { + m_InactiveItemID = value; + + if( IsEmpty ) + this.ItemID = m_InactiveItemID; + } + } + + private string m_Account, m_LastUserName; + private DateTime m_NextUse; // TODO: unused, it's here not to break serialize/deserialize + + private SkillName m_Skill; + private double m_SkillValue; + + [CommandProperty( AccessLevel.GameMaster )] + public string Account + { + get{ return m_Account; } + set{ m_Account = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string LastUserName + { + get{ return m_LastUserName; } + set{ m_LastUserName = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill + { + get{ return m_Skill; } + set{ m_Skill = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public double SkillValue + { + get{ return m_SkillValue; } + set + { + m_SkillValue = value; + + if ( !IsEmpty ) + this.ItemID = m_ActiveItemID; + else + this.ItemID = m_InactiveItemID; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsEmpty + { + get{ return m_SkillValue <= 0.0; } + } + + [Constructable] + public SoulStone() : this( null ) + { + } + + [Constructable] + public SoulStone( string account ) + : this( account, 0x2A93, 0x2A94 ) + { + } + + public SoulStone( string account, int itemID ) + : this( account, itemID, itemID ) + { + } + + public SoulStone( string account, int inactiveItemID, int activeItemID ) : base( inactiveItemID ) + { + Light = LightType.Circle300; + LootType = LootType.Blessed; + + m_InactiveItemID = inactiveItemID; + m_ActiveItemID = activeItemID; + + m_Account = account; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (!IsEmpty) + list.Add(1070721, "#{0}\t{1:0.0}", AosSkillBonuses.GetLabel(Skill), SkillValue); // Skill stored: ~1_skillname~ ~2_skillamount~ + + string name = this.LastUserName; + + if (name == null) + name = String.Format("#{0}", 1074235); // Unknown + + list.Add(1041602, "{0}", name); // Owner: ~1_val~ + } + + private static bool CheckCombat( Mobile m, TimeSpan time ) + { + for ( int i = 0; i < m.Aggressed.Count; ++i ) + { + AggressorInfo info = m.Aggressed[i]; + + if ( DateTime.Now - info.LastCombatTime < time ) + return true; + } + + return false; + } + + protected virtual bool CheckUse( Mobile from ) + { + DateTime now = DateTime.Now; + + PlayerMobile pm = from as PlayerMobile; + + if ( this.Deleted || !this.IsAccessibleTo( from ) ) + { + return false; + } + else if ( from.Map != this.Map || !from.InRange( GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return false; + } + else if ( this.Account != null && ( !(from.Account is Account) || from.Account.Username != this.Account ) ) + { + from.SendLocalizedMessage( 1070714 ); // This is an Account Bound Soulstone, and your character is not bound to it. You cannot use this Soulstone. + return false; + } + else if ( CheckCombat( from, TimeSpan.FromMinutes( 2.0 ) ) ) + { + from.SendLocalizedMessage( 1070727 ); // You must wait two minutes after engaging in combat before you can use a Soulstone. + return false; + } + else if ( from.Criminal ) + { + from.SendLocalizedMessage( 1070728 ); // You must wait two minutes after committing a criminal act before you can use a Soulstone. + return false; + } + else if ( from.Region.GetLogoutDelay( from ) > TimeSpan.Zero ) + { + from.SendLocalizedMessage( 1070729 ); // In order to use your Soulstone, you must be in a safe log-out location. + return false; + } + else if ( !from.Alive ) + { + from.SendLocalizedMessage( 1070730 ); // You may not use a Soulstone while your character is dead. + return false; + } + else if ( Factions.Sigil.ExistsOn( from ) ) + { + from.SendLocalizedMessage( 1070731 ); // You may not use a Soulstone while your character has a faction town sigil. + return false; + } + else if ( from.Spell != null && from.Spell.IsCasting ) + { + from.SendLocalizedMessage( 1070733 ); // You may not use a Soulstone while your character is casting a spell. + return false; + } + else if ( from.Poisoned ) + { + from.SendLocalizedMessage( 1070734 ); // You may not use a Soulstone while your character is poisoned. + return false; + } + else if ( from.Paralyzed ) + { + from.SendLocalizedMessage( 1070735 ); // You may not use a Soulstone while your character is paralyzed. + return false; + } + + #region Scroll of Alacrity + if ( pm.AcceleratedStart > DateTime.Now ) + { + from.SendLocalizedMessage(1078115); // You may not use a soulstone while your character is under the effects of a Scroll of Alacrity. + return false; + } + #endregion + + else + { + return true; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !CheckUse( from ) ) + return; + + from.CloseGump( typeof( SelectSkillGump ) ); + from.CloseGump( typeof( ConfirmSkillGump ) ); + from.CloseGump( typeof( ConfirmTransferGump ) ); + from.CloseGump( typeof( ConfirmRemovalGump ) ); + from.CloseGump( typeof( ErrorGump ) ); + + if ( this.IsEmpty ) + from.SendGump( new SelectSkillGump( this, from ) ); + else + from.SendGump( new ConfirmTransferGump( this, from ) ); + } + + private class SelectSkillGump : Gump + { + private SoulStone m_Stone; + + public SelectSkillGump( SoulStone stone, Mobile from ) : base( 50, 50 ) + { + m_Stone = stone; + + AddPage( 0 ); + + AddBackground( 0, 0, 520, 440, 0x13BE ); + + AddImageTiled( 10, 10, 500, 20, 0xA40 ); + AddImageTiled( 10, 40, 500, 360, 0xA40 ); + AddImageTiled( 10, 410, 500, 20, 0xA40 ); + + AddAlphaRegion( 10, 10, 500, 420 ); + + AddHtmlLocalized( 10, 12, 500, 20, 1061087, 0x7FFF, false, false ); // Which skill do you wish to transfer to the Soulstone? + + AddButton( 10, 410, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 412, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + + for ( int i = 0, n = 0; i < from.Skills.Length; i++ ) + { + Skill skill = from.Skills[i]; + + if ( skill.Base > 0.0 ) + { + int p = n % 30; + + if ( p == 0 ) + { + int page = n / 30; + + if ( page > 0 ) + { + AddButton( 260, 380, 0xFA5, 0xFA6, 0, GumpButtonType.Page, page + 1 ); + AddHtmlLocalized( 305, 382, 200, 20, 1011066, 0x7FFF, false, false ); // Next page + } + + AddPage( page + 1 ); + + if ( page > 0 ) + { + AddButton( 10, 380, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page ); + AddHtmlLocalized( 55, 382, 200, 20, 1011067, 0x7FFF, false, false ); // Previous page + } + } + + int x = ( p % 2 == 0 ) ? 10 : 260; + int y = ( p / 2 ) * 20 + 40; + + AddButton( x, y, 0xFA5, 0xFA6, i + 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized(x + 45, y + 2, 200, 20, AosSkillBonuses.GetLabel(skill.SkillName), 0x7FFF, false, false); + + n++; + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 || !m_Stone.IsEmpty ) + return; + + Mobile from = sender.Mobile; + + int iSkill = info.ButtonID - 1; + if ( iSkill < 0 || iSkill >= from.Skills.Length ) + return; + + Skill skill = from.Skills[iSkill]; + if ( skill.Base <= 0.0 ) + return; + + if ( !m_Stone.CheckUse( from ) ) + return; + + from.SendGump( new ConfirmSkillGump( m_Stone, skill ) ); + } + } + + private class ConfirmSkillGump : Gump + { + private SoulStone m_Stone; + private Skill m_Skill; + + public ConfirmSkillGump( SoulStone stone, Skill skill ) : base( 50, 50 ) + { + m_Stone = stone; + m_Skill = skill; + + AddBackground( 0, 0, 520, 440, 0x13BE ); + + AddImageTiled( 10, 10, 500, 20, 0xA40 ); + AddImageTiled( 10, 40, 500, 360, 0xA40 ); + AddImageTiled( 10, 410, 500, 20, 0xA40 ); + + AddAlphaRegion( 10, 10, 500, 420 ); + + AddHtmlLocalized( 10, 12, 500, 20, 1070709, 0x7FFF, false, false ); //
Confirm Soulstone Transfer
+ + /*
Soulstone

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

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

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

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

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

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

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

+ * + * Are you sure you wish to do this? If not, press the Cancel button. + */ + AddHtmlLocalized( 10, 42, 500, 110, 1070724, 0x7FFF, false, true ); + + AddButton( 10, 380, 0xFA5, 0xFA6, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 382, 450, 20, 1052072, 0x7FFF, false, false ); // Continue + + AddButton( 10, 410, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 412, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 || m_Stone.IsEmpty ) + return; + + Mobile from = sender.Mobile; + + if ( !m_Stone.CheckUse( from ) ) + return; + + m_Stone.SkillValue = 0.0; + from.SendLocalizedMessage( 1070726 ); // You have successfully deleted the Soulstone's skill points. + } + } + + private class ErrorGump : Gump + { + private SoulStone m_Stone; + + public ErrorGump( SoulStone stone, int title, int message ) : base( 50, 50 ) + { + m_Stone = stone; + + AddBackground( 0, 0, 520, 440, 0x13BE ); + + AddImageTiled( 10, 10, 500, 20, 0xA40 ); + AddImageTiled( 10, 40, 500, 360, 0xA40 ); + AddImageTiled( 10, 410, 500, 20, 0xA40 ); + + AddAlphaRegion( 10, 10, 500, 420 ); + + AddHtmlLocalized( 10, 12, 500, 20, title, 0x7FFF, false, false ); + + AddHtmlLocalized( 10, 42, 500, 110, message, 0x7FFF, false, true ); + + AddButton( 10, 380, 0xFA5, 0xFA6, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 382, 450, 20, 1052072, 0x7FFF, false, false ); // Continue + + AddButton( 10, 410, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 412, 450, 20, 1060051, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 0 ) + return; + + Mobile from = sender.Mobile; + + if ( !m_Stone.CheckUse( from ) ) + return; + + if ( m_Stone.IsEmpty ) + from.SendGump( new SelectSkillGump( m_Stone, from ) ); + else + from.SendGump( new ConfirmTransferGump( m_Stone, from ) ); + } + } + + public SoulStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 3 ); // version + + //version 3 + writer.Write( (string) m_LastUserName ); + + //version 2 + writer.Write( (int)m_Level ); + + writer.Write( m_ActiveItemID ); + writer.Write( m_InactiveItemID ); + + writer.Write( (string) m_Account ); + writer.Write( (DateTime) m_NextUse ); //TODO: delete it in a harmless way + + writer.WriteEncodedInt( (int) m_Skill ); + writer.Write( (double) m_SkillValue ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch( version ) + { + case 3: + { + m_LastUserName = reader.ReadString(); + goto case 2; + } + case 2: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 1; + } + case 1: + { + m_ActiveItemID = reader.ReadInt(); + m_InactiveItemID = reader.ReadInt(); + + goto case 0; + } + case 0: + { + m_Account = reader.ReadString(); + m_NextUse = reader.ReadDateTime(); //TODO: delete it in a harmless way + + m_Skill = (SkillName)reader.ReadEncodedInt(); + m_SkillValue = reader.ReadDouble(); + break; + } + } + + if( version == 0 ) + { + m_ActiveItemID = 0x2A94; + m_InactiveItemID = 0x2A93; + } + } + } + + public class SoulstoneFragment : SoulStone, IUsesRemaining + { + private int m_UsesRemaining; + + public override int LabelNumber { get { return 1071000; } } // soulstone fragment + + [Constructable] + public SoulstoneFragment() : this( 5, null ) + { + } + + [Constructable] + public SoulstoneFragment( int usesRemaining ) : this( usesRemaining, null ) + { + } + + [Constructable] + public SoulstoneFragment( string account ) : this( 5, account ) + { + } + + [Constructable] + public SoulstoneFragment( int usesRemaining, string account ) : base( account, Utility.Random( 0x2AA1, 9 ) ) + { + m_UsesRemaining = usesRemaining; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get + { + return m_UsesRemaining; + } + set + { + m_UsesRemaining = value; InvalidateProperties(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 2 ); // version + + writer.WriteEncodedInt( m_UsesRemaining ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_UsesRemaining = reader.ReadEncodedInt(); + + if( version <= 1 ) + { + if( ItemID == 0x2A93 || ItemID == 0x2A94 ) + { + ActiveItemID = Utility.Random( 0x2AA1, 9 ); + } + else + { + ActiveItemID = ItemID; + } + + InactiveItemID = ActiveItemID; + } + + if ( version == 0 && Weight == 1 ) + Weight = -1; + } + + public SoulstoneFragment( Serial serial ) : base( serial ) + { + } + + protected override bool CheckUse( Mobile from ) + { + bool canUse = base.CheckUse( from ); + + if( canUse ) + { + if( m_UsesRemaining <= 0 ) + { + from.SendLocalizedMessage( 1070975 ); // That soulstone fragment has no more uses. + return false; + } + } + + return canUse; + } + + + public bool ShowUsesRemaining{ get{ return true; } set{} } + } + + [Flipable] + public class BlueSoulstone : SoulStone + { + [Constructable] + public BlueSoulstone() + : this( null ) + { + } + + [Constructable] + public BlueSoulstone( string account ) + : base( account, 0x2ADC, 0x2ADD ) + { + + } + + public BlueSoulstone( Serial serial ) + : base( serial ) + { + } + + public void Flip() + { + switch( ItemID ) + { + case 0x2ADC: ItemID = 0x2AEC; break; + case 0x2ADD: ItemID = 0x2AED; break; + case 0x2AEC: ItemID = 0x2ADC; break; + case 0x2AED: ItemID = 0x2ADD; break; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class RedSoulstone : SoulStone, IRewardItem + { + [Constructable] + public RedSoulstone() + : this( null ) + { + } + + [Constructable] + public RedSoulstone( string account ) + : base( account, 0x32F3, 0x32F4 ) + { + + } + + public RedSoulstone( Serial serial ) + : base( serial ) + { + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076217 ); // 1st Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_IsRewardItem = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Special Scrolls/PowerScroll.cs b/Scripts/Items/Special/Special Scrolls/PowerScroll.cs new file mode 100644 index 0000000..5cb8952 --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/PowerScroll.cs @@ -0,0 +1,257 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Items +{ + public class PowerScroll : SpecialScroll + { + public override int Message { get { return 1049469; } } /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. + * When used, the effect is not immediately seen without a gain of points with that skill or statistics. + * You can view your maximum skill values in your skills window. + * You can view your maximum statistic value in your statistics window. */ + public override int Title + { + get + { + double level = ( Value - 105.0 ) / 5.0; + + if ( level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0 ) + return 1049635 + (int)level; /* Wonderous Scroll (105 Skill): OR + * Exalted Scroll (110 Skill): OR + * Mythical Scroll (115 Skill): OR + * Legendary Scroll (120 Skill): */ + + return 0; + } + } + + public override string DefaultTitle{ get{ return String.Format( "Power Scroll ({0} Skill):", Value ); } } + + private static SkillName[] m_Skills = new SkillName[] + { + SkillName.Blacksmith, + SkillName.Tailoring, + SkillName.Swords, + SkillName.Fencing, + SkillName.Macing, + SkillName.Archery, + SkillName.Wrestling, + SkillName.Parry, + SkillName.Tactics, + SkillName.Anatomy, + SkillName.Healing, + SkillName.Magery, + SkillName.Meditation, + SkillName.EvalInt, + SkillName.MagicResist, + SkillName.AnimalTaming, + SkillName.AnimalLore, + SkillName.Veterinary, + SkillName.Musicianship, + SkillName.Provocation, + SkillName.Discordance, + SkillName.Peacemaking + }; + + private static SkillName[] m_AOSSkills = new SkillName[] + { + SkillName.Chivalry, + SkillName.Focus, + SkillName.Necromancy, + SkillName.Stealing, + SkillName.Stealth, + SkillName.SpiritSpeak + }; + + private static SkillName[] m_SESkills = new SkillName[] + { + SkillName.Ninjitsu, + SkillName.Bushido + }; + + private static SkillName[] m_MLSkills = new SkillName[] + { + SkillName.Spellweaving + }; + + /* + private static SkillName[] m_SASkills = new SkillName[] + { + SkillName.Throwing, + SkillName.Mysticism, + SkillName.Imbuing + }; + + private static SkillName[] m_HSSkills = new SkillName[] + { + SkillName.Fishing + }; + */ + + private static List _Skills = new List(); + + public static List Skills + { + get + { + if ( _Skills.Count == 0 ) + { + _Skills.AddRange(m_Skills); + if (Core.AOS) + { + _Skills.AddRange(m_AOSSkills); + if (Core.SE) + { + _Skills.AddRange(m_SESkills); + if (Core.ML) + { + _Skills.AddRange(m_MLSkills); + /* + if (Core.SA) + { + _Skills.AddRange( m_SASkills ); + if (Core.HS) + _Skills.AddRange( m_HSSkills ); + } + */ + } + } + } + } + + return _Skills; + } + } + + public static PowerScroll CreateRandom( int min, int max ) + { + min /= 5; + max /= 5; + + return new PowerScroll( Skills[Utility.Random( Skills.Count )], 100 + ( Utility.RandomMinMax( min, max ) * 5 ) ); + } + + public static PowerScroll CreateRandomNoCraft( int min, int max ) + { + min /= 5; + max /= 5; + + SkillName skillName; + + do + { + skillName = Skills[Utility.Random( Skills.Count )]; + } while ( skillName == SkillName.Blacksmith || skillName == SkillName.Tailoring ); + + return new PowerScroll( skillName, 100 + (Utility.RandomMinMax( min, max ) * 5)); + } + + public PowerScroll() : this( SkillName.Alchemy, 0.0 ) + { + } + + [Constructable] + public PowerScroll( SkillName skill, double value ) : base( skill, value ) + { + Hue = 0x481; + + if (Value == 105.0 || skill == Server.SkillName.Blacksmith || skill == Server.SkillName.Tailoring ) + LootType = LootType.Regular; + } + + public PowerScroll( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + double level = ( Value - 105.0 ) / 5.0; + + if ( level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0 ) + list.Add( 1049639 + (int)level, GetNameLocalized() ); /* a wonderous scroll of ~1_type~ (105 Skill) OR + * an exalted scroll of ~1_type~ (110 Skill) OR + * a mythical scroll of ~1_type~ (115 Skill) OR + * a legendary scroll of ~1_type~ (120 Skill) */ + else + list.Add( "a power scroll of {0} ({1} Skill)", GetName(), Value ); + } + + public override void OnSingleClick( Mobile from ) + { + double level = ( Value - 105.0 ) / 5.0; + + if ( level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0 ) + base.LabelTo( from, 1049639 + (int)level, GetNameLocalized() ); + else + base.LabelTo( from, "a power scroll of {0} ({1} Skill)", GetName(), Value ); + } + + public override bool CanUse( Mobile from ) + { + if ( !base.CanUse( from ) ) + return false; + + Skill skill = from.Skills[Skill]; + + if ( skill == null ) + return false; + + if ( skill.Cap >= Value ) + { + from.SendLocalizedMessage( 1049511, GetNameLocalized() ); // Your ~1_type~ is too high for this power scroll. + return false; + } + + return true; + } + + public override void Use( Mobile from ) + { + if ( !CanUse( from ) ) + return; + + from.SendLocalizedMessage( 1049513, GetNameLocalized() ); // You feel a surge of magic as the scroll enhances your ~1_type~! + + from.Skills[Skill].Cap = Value; + + Effects.SendLocationParticles( EffectItem.Create( from.Location, from.Map, EffectItem.DefaultDuration ), 0, 0, 0, 0, 0, 5060, 0 ); + Effects.PlaySound( from.Location, from.Map, 0x243 ); + + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( from.X - 6, from.Y - 6, from.Z + 15 ), from.Map ), from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( from.X - 4, from.Y - 6, from.Z + 15 ), from.Map ), from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( from.X - 6, from.Y - 4, from.Z + 15 ), from.Map ), from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + + Effects.SendTargetParticles( from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 ); + + Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); //Required for SpecialScroll insertion + + if (Value == 105.0 || Skill == SkillName.Blacksmith || Skill == SkillName.Tailoring) + { + LootType = LootType.Regular; + } + else + { + LootType = LootType.Cursed; + Insured = false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs b/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs new file mode 100644 index 0000000..9ef0903 --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/ScrollofAlacrity.cs @@ -0,0 +1,173 @@ +/*************************************************************************** +* ScrollofAlacrity.cs +* ------------------- +* begin : June 1, 2009 +* copyright : (C) Shai'Tan Malkier aka Callandor2k +* email : ShaiTanMalkier@gmail.com +* +* $Id: ScrollofAlacrity.cs 1 2009-06-1 04:28:39Z Callandor2k $ +* +***************************************************************************/ + +/*************************************************************************** +* +* This Script/File is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +***************************************************************************/ + +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using System.Collections; +using Server.Engines.Quests; +using System.Collections.Generic; + +namespace Server.Items +{ + public class ScrollofAlacrity : SpecialScroll + { + public override int LabelNumber { get { return 1078604; } } // Scroll of Alacrity + + public override int Message { get { return 1078602; } } /*Using a Scroll of Transcendence for a given skill will permanently increase your current + *level in that skill by the amount of points displayed on the scroll. + *As you may not gain skills beyond your maximum skill cap, any excess points will be lost.*/ + + public override string DefaultTitle { get { return String.Format( "Scroll of Alacrity:" ); } } + + public ScrollofAlacrity() : this( SkillName.Alchemy ) + { + } + + [Constructable] + public ScrollofAlacrity( SkillName skill ) : base( skill, 0.0 ) + { + ItemID = 0x14EF; + Hue = 0x4AB; + } + + public ScrollofAlacrity(Serial serial) : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1071345, "{0} 15 Minutes", GetName()); // Skill: ~1_val~ + } + + public override bool CanUse( Mobile from ) + { + if ( !base.CanUse( from ) ) + return false; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + #region Mondain's Legacy + /* to add when skillgain quests will be implemented + + for (int i = pm.Quests.Count - 1; i >= 0; i--) + { + BaseQuest quest = pm.Quests[i]; + + for (int j = quest.Objectives.Count - 1; j >= 0; j--) + { + BaseObjective objective = quest.Objectives[j]; + + if (objective is ApprenticeObjective) + { + from.SendMessage("You are already under the effect of an enhanced skillgain quest."); + return false; + } + } + } + + */ + #endregion + + #region Scroll of Alacrity + if (pm.AcceleratedStart > DateTime.Now) + { + from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. + return false; + } + #endregion + + return true; + } + + public override void Use( Mobile from ) + { + if ( !CanUse( from ) ) + return; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return; + + double tskill = from.Skills[Skill].Base; + double tcap = from.Skills[Skill].Cap; + + if ( tskill >= tcap || from.Skills[Skill].Lock != SkillLock.Up ) + { + from.SendLocalizedMessage( 1094935 ); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ + return; + } + + from.SendLocalizedMessage( 1077956 ); // You are infused with intense energy. You are under the effects of an accelerated skillgain scroll. + + Effects.PlaySound( from.Location, from.Map, 0x1E9 ); + Effects.SendTargetParticles( from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 ); + + pm.AcceleratedStart = DateTime.Now + TimeSpan.FromMinutes(15); + + Timer t = (Timer)m_Table[from]; + + m_Table[from] = Timer.DelayCall( TimeSpan.FromMinutes( 15 ), new TimerStateCallback( Expire_Callback ), from ); + + pm.AcceleratedSkill = Skill; + + Delete(); + } + + private static Hashtable m_Table = new Hashtable(); + + private static void Expire_Callback(object state) + { + Mobile m = (Mobile)state; + + m_Table.Remove(m); + + m.PlaySound(0x1F8); + + m.SendLocalizedMessage(1077957);// The intense energy dissipates. You are no longer under the effects of an accelerated skillgain scroll. + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); //Required for SpecialScroll insertion + + LootType = LootType.Cursed; + Insured = false; + } + } +} diff --git a/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs b/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs new file mode 100644 index 0000000..e77e1c0 --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/ScrollofTranscendence.cs @@ -0,0 +1,168 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Mobiles; +using Server.Engines.Quests; + +namespace Server.Items +{ + public class ScrollofTranscendence : SpecialScroll + { + public override int LabelNumber { get { return 1094934; } } // Scroll of Transcendence + + public override int Message { get { return 1094933; } } /*Using a Scroll of Transcendence for a given skill will permanently increase your current + *level in that skill by the amount of points displayed on the scroll. + *As you may not gain skills beyond your maximum skill cap, any excess points will be lost.*/ + + public override string DefaultTitle { get { return String.Format( "Scroll of Transcendence ({0} Skill):", Value ); } } + + public static ScrollofTranscendence CreateRandom( int min, int max ) + { + SkillName skill = (SkillName)Utility.Random( SkillInfo.Table.Length ); + + return new ScrollofTranscendence(skill, Utility.RandomMinMax(min, max) * 0.1); + } + + public ScrollofTranscendence() : this( SkillName.Alchemy, 0.0 ) + { + } + + [Constructable] + public ScrollofTranscendence( SkillName skill, double value ) : base( skill, value ) + { + ItemID = 0x14EF; + Hue = 0x490; + } + + public ScrollofTranscendence(Serial serial) : base(serial) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties(list); + + if ( Value == 1 ) + list.Add(1076759, "{0}\t{1}.0 Skill Points", GetName(), Value); + else + list.Add(1076759, "{0}\t{1} Skill Points", GetName(), Value); + } + + public override bool CanUse( Mobile from ) + { + if ( !base.CanUse( from ) ) + return false; + + PlayerMobile pm = from as PlayerMobile; + + if ( pm == null ) + return false; + + #region Mondain's Legacy + /* to add when skillgain quests will be implemented + + for (int i = pm.Quests.Count - 1; i >= 0; i--) + { + BaseQuest quest = pm.Quests[i]; + + for (int j = quest.Objectives.Count - 1; j >= 0; j--) + { + BaseObjective objective = quest.Objectives[j]; + + if (objective is ApprenticeObjective) + { + from.SendMessage("You are already under the effect of an enhanced skillgain quest."); + return false; + } + } + } + + */ + #endregion + + #region Scroll of Alacrity + if (pm.AcceleratedStart > DateTime.Now) + { + from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll. + return false; + } + #endregion + + return true; + } + + public override void Use( Mobile from ) + { + if ( !CanUse( from ) ) + return; + + double tskill = from.Skills[Skill].Base; // value of skill without item bonuses etc + double tcap = from.Skills[Skill].Cap; // maximum value permitted + bool canGain = false; + + double newValue = Value; + + if ( ( tskill + newValue ) > tcap ) + newValue = tcap - tskill; + + if ( tskill < tcap && from.Skills[Skill].Lock == SkillLock.Up ) + { + if ( ( from.SkillsTotal + newValue * 10 ) > from.SkillsCap ) + { + int ns = from.Skills.Length; // number of items in from.Skills[] + + for ( int i = 0; i < ns; i++ ) + { + // skill must point down and its value must be enough + if ( from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= newValue ) + { + from.Skills[i].Base -= newValue; + canGain = true; + break; + } + } + } + else + canGain = true; + } + + if ( !canGain ) + { + from.SendLocalizedMessage( 1094935 ); /*You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. + *If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap.*/ + return; + } + + from.SendLocalizedMessage( 1049513, GetNameLocalized() ); // You feel a surge of magic as the scroll enhances your ~1_type~! + + from.Skills[Skill].Base += newValue; + + Effects.PlaySound( from.Location, from.Map, 0x1F7 ); + Effects.SendTargetParticles( from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 ); + Effects.SendTargetParticles( from, 0x376A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 ); + + Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize(reader); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); //Required for SpecialScroll insertion + + LootType = LootType.Cursed; + Insured = false; + + if (Hue == 0x7E) + Hue = 0x490; + } + } +} diff --git a/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs b/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs new file mode 100644 index 0000000..4a1b86b --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/SpecialScroll.cs @@ -0,0 +1,190 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public abstract class SpecialScroll : Item + { + private SkillName m_Skill; + private double m_Value; + + #region Old Item Serialization Vars + /* DO NOT USE! Only used in serialization of special scrolls that originally derived from Item */ + private bool m_InheritsItem; + + protected bool InheritsItem + { + get { return m_InheritsItem; } + } + #endregion + + public abstract int Message { get; } + public virtual int Title { get { return 0; } } + public abstract string DefaultTitle { get; } + + public SpecialScroll(SkillName skill, double value) + : base(0x14F0) + { + LootType = LootType.Cursed; + Weight = 1.0; + + m_Skill = skill; + m_Value = value; + } + + public SpecialScroll(Serial serial) + : base(serial) + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get { return m_Skill; } + set { m_Skill = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double Value + { + get { return m_Value; } + set { m_Value = value; } + } + + public virtual string GetNameLocalized() + { + return String.Concat("#", AosSkillBonuses.GetLabel(m_Skill).ToString()); + } + + public virtual string GetName() + { + int index = (int)m_Skill; + SkillInfo[] table = SkillInfo.Table; + + if (index >= 0 && index < table.Length) + return table[index].Name.ToLower(); + else + return "???"; + } + + public virtual bool CanUse(Mobile from) + { + if (Deleted) + return false; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + return false; + } + + return true; + } + + public virtual void Use(Mobile from) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!CanUse(from)) + return; + + from.CloseGump(typeof(SpecialScroll.InternalGump)); + from.SendGump(new InternalGump(from, this)); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write((int)m_Skill); + writer.Write((double)m_Value); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_Skill = (SkillName)reader.ReadInt(); + m_Value = reader.ReadDouble(); + break; + } + case 0: + { + m_InheritsItem = true; + + if (!(this is StatCapScroll)) + m_Skill = (SkillName)reader.ReadInt(); + else + m_Skill = SkillName.Alchemy; + + if (this is ScrollofAlacrity) + m_Value = 0.0; + else if (this is StatCapScroll) + m_Value = (double)reader.ReadInt(); + else + m_Value = reader.ReadDouble(); + + break; + } + } + } + + public class InternalGump : Gump + { + private Mobile m_Mobile; + private SpecialScroll m_Scroll; + + public InternalGump(Mobile mobile, SpecialScroll scroll) + : base(25, 50) + { + m_Mobile = mobile; + m_Scroll = scroll; + + AddPage(0); + + AddBackground(25, 10, 420, 200, 5054); + + AddImageTiled(33, 20, 401, 181, 2624); + AddAlphaRegion(33, 20, 401, 181); + + AddHtmlLocalized(40, 48, 387, 100, m_Scroll.Message, true, true); + + AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF, false, false); // Do you wish to use this scroll? + + AddButton(100, 172, 4005, 4007, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF, false, false); // Yes + + AddButton(275, 172, 4005, 4007, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF, false, false); // No + + if (m_Scroll.Title != 0) + AddHtmlLocalized(40, 20, 260, 20, m_Scroll.Title, 0xFFFFFF, false, false); + else + AddHtml(40, 20, 260, 20, m_Scroll.DefaultTitle, false, false); + + if (m_Scroll is StatCapScroll) + AddHtmlLocalized(310, 20, 120, 20, 1038019, 0xFFFFFF, false, false); // Power + else + AddHtmlLocalized(310, 20, 120, 20, AosSkillBonuses.GetLabel(m_Scroll.Skill), 0xFFFFFF, false, false); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info.ButtonID == 1) + m_Scroll.Use(m_Mobile); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Special Scrolls/StatScroll.cs b/Scripts/Items/Special/Special Scrolls/StatScroll.cs new file mode 100644 index 0000000..d24cc05 --- /dev/null +++ b/Scripts/Items/Special/Special Scrolls/StatScroll.cs @@ -0,0 +1,132 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + public class StatCapScroll : SpecialScroll + { + public override int Message { get { return 1049469; } } /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. + * When used, the effect is not immediately seen without a gain of points with that skill or statistics. + * You can view your maximum skill values in your skills window. + * You can view your maximum statistic value in your statistics window. */ + public override int Title + { + get + { + int level = ( (int)Value - 230 ) / 5; + + if ( level >= 0 && level <= 4 && Value % 5 == 0 ) + return 1049458 + level; /* Wonderous Scroll (+5 Maximum Stats): OR + * Exalted Scroll (+10 Maximum Stats): OR + * Mythical Scroll (+15 Maximum Stats): OR + * Legendary Scroll (+20 Maximum Stats): OR + * Ultimate Scroll (+25 Maximum Stats): */ + + return 0; + } + } + + public override string DefaultTitle { get { return String.Format( "Power Scroll ({0}{1} Maximum Stats):", ( (int)Value - 225 ) >= 0 ? "+" : "", (int)Value - 225 ); } } + + public StatCapScroll() : this( 105 ) + { + } + + [Constructable] + public StatCapScroll( int value ) : base( SkillName.Alchemy, value ) + { + Hue = 0x481; + } + + public StatCapScroll( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperty(ObjectPropertyList list) + { + int level = ( (int)Value - 230 ) / 5; + + if ( level >= 0 && level <= 4 && (int)Value % 5 == 0 ) + list.Add( 1049463 + level, "#1049476" ); /* a wonderous scroll of ~1_type~ (+5 Maximum Stats) OR + * an exalted scroll of ~1_type~ (+10 Maximum Stats) OR + * a mythical scroll of ~1_type~ (+15 Maximum Stats) OR + * a legendary scroll of ~1_type~ (+20 Maximum Stats) OR + * an ultimate scroll of ~1_type~ (+25 Maximum Stats) */ + else + list.Add( "a scroll of power ({0}{1} Maximum Stats)", (Value - 225) >= 0 ? "+" : "", Value - 225 ); + } + + public override void OnSingleClick( Mobile from ) + { + int level = ( (int)Value - 230 ) / 5; + + if ( level >= 0 && level <= 4 && (int)Value % 5 == 0 ) + base.LabelTo( from, 1049463 + level, "#1049476" ); + else + base.LabelTo( from, "a scroll of power ({0}{1} Maximum Stats)", (Value - 225) >= 0 ? "+" : "", Value - 225 ); + } + + public override bool CanUse( Mobile from ) + { + if ( !base.CanUse( from ) ) + return false; + + int newValue = (int)Value; + + if ( from is PlayerMobile && ((PlayerMobile)from).HasStatReward ) + newValue += 5; + + if ( from.StatCap >= newValue ) + { + from.SendLocalizedMessage( 1049510 ); // Your stats are too high for this power scroll. + return false; + } + + return true; + } + + public override void Use( Mobile from ) + { + if ( !CanUse( from ) ) + return; + + from.SendLocalizedMessage( 1049512 ); // You feel a surge of magic as the scroll enhances your powers! + + if ( from is PlayerMobile && ((PlayerMobile)from).HasStatReward ) + from.StatCap = (int)Value + 5; + else + from.StatCap = (int)Value; + + Effects.SendLocationParticles( EffectItem.Create( from.Location, from.Map, EffectItem.DefaultDuration ), 0, 0, 0, 0, 0, 5060, 0 ); + Effects.PlaySound( from.Location, from.Map, 0x243 ); + + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( from.X - 6, from.Y - 6, from.Z + 15 ), from.Map ), from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( from.X - 4, from.Y - 6, from.Z + 15 ), from.Map ), from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( from.X - 6, from.Y - 4, from.Z + 15 ), from.Map ), from, 0x36D4, 7, 0, false, true, 0x497, 0, 9502, 1, 0, (EffectLayer)255, 0x100 ); + + Effects.SendTargetParticles( from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100 ); + + Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = ( InheritsItem ? 0 : reader.ReadInt() ); //Required for SpecialScroll insertion + + LootType = LootType.Cursed; + Insured = false; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Valentines/2007/RedVelvetGiftBox.cs b/Scripts/Items/Special/Valentines/2007/RedVelvetGiftBox.cs new file mode 100644 index 0000000..bb56024 --- /dev/null +++ b/Scripts/Items/Special/Valentines/2007/RedVelvetGiftBox.cs @@ -0,0 +1,65 @@ +using System; +using Server; + +/* + * Simply add this box with param true to create the entire valentine's 2007 package. + * Adding it with no params or false will create an empty box. + */ + +namespace Server.Items +{ + public class RedVelvetGiftBox : BaseContainer + { + public override int DefaultGumpID { get { return 0x3f; } } + public override int LabelNumber { get { return 1077596; } } // A Red Velvet Box + + [Constructable] + public RedVelvetGiftBox() + : this( false ) + { + } + + [Constructable] + public RedVelvetGiftBox( bool fill ) + : base( 0xE7A ) + { + Hue = 0x20; + + if (fill) + { + for (int i = 0; i < 5; i++) + { + AddToBox(new ValentinesCardSouth(), new Point3D(60 + (i * 10), 47, 0)); + AddToBox(new ValentinesCardEast(), new Point3D(20 + (i * 10), 72, 0)); + } + AddToBox(new Bacon(), new Point3D(90, 85, 0)); + AddToBox(new RoseInAVase(), new Point3D(130, 55, 0)); + } + } + + public virtual void AddToBox(Item item, Point3D loc) + { + DropItem(item); + item.Location = loc; + } + + public RedVelvetGiftBox( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Valentines/2007/RoseInAVase.cs b/Scripts/Items/Special/Valentines/2007/RoseInAVase.cs new file mode 100644 index 0000000..a90076c --- /dev/null +++ b/Scripts/Items/Special/Valentines/2007/RoseInAVase.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RoseInAVase : Item /* TODO: when dye tub changes are implemented, furny dyable this */ + { + public override int LabelNumber { get { return 1023760; } } // A Rose in a Vase 1023760 + + [Constructable] + public RoseInAVase( ) + : base( 0x0EB0 ) + { + Hue = 0x20; + LootType = LootType.Blessed; + } + + public RoseInAVase( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Valentines/2007/ValentinesCard.cs b/Scripts/Items/Special/Valentines/2007/ValentinesCard.cs new file mode 100644 index 0000000..986e2b6 --- /dev/null +++ b/Scripts/Items/Special/Valentines/2007/ValentinesCard.cs @@ -0,0 +1,190 @@ +using System; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class ValentinesCard : Item + { + public override string DefaultName { get { return "a Valentine's card"; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual string From { get { return m_From; } set { m_From = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual string To { get { return m_To; } set { m_To = value; } } + + private static string Unsigned = "___"; + + private int m_LabelNumber; + private string m_From; + private string m_To; + + [Constructable] + public ValentinesCard( int itemid ) + : base(itemid) + { + LootType = LootType.Blessed; + Hue = Utility.RandomDouble() < .001 ? 0x47E : 0xE8; + m_LabelNumber = Utility.Random(1077589, 5); + } + + /* + * Five possible messages to be signed: + * + * To my one true love, ~1_target_player~. Signed: ~2_player~ 1077589 + * You’ve pwnd my heart, ~1_target_player~. Signed: ~2_player~ 1077590 + * Happy Valentine’s Day, ~1_target_player~. Signed: ~2_player~ 1077591 + * Blackrock has driven me crazy... for ~1_target_player~! Signed: ~2_player~ 1077592 + * You light my Candle of Love, ~1_target_player~! Signed: ~2_player~ 1077593 + * + */ + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add(m_LabelNumber, String.Format("{0}\t{1}", (m_To != null) ? m_To : Unsigned, (m_From != null) ? m_From : Unsigned)); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, m_LabelNumber, String.Format("{0}\t{1}", (m_To != null) ? m_To : Unsigned, (m_From != null) ? m_From : Unsigned)); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_To == null) + { + if (this.IsChildOf(from)) + { + from.BeginTarget(10, false, TargetFlags.None, new TargetCallback(OnTarget)); + + from.SendLocalizedMessage(1077497); //To whom do you wish to give this card? + } + else + { + from.SendLocalizedMessage(1080063); // This must be in your backpack to use it. + } + } + } + + public virtual void OnTarget(Mobile from, object targeted) + { + if (!Deleted) + { + if (targeted != null && targeted is Mobile) + { + Mobile to = targeted as Mobile; + + if (to is PlayerMobile) + { + if (to != from) + { + m_From = from.Name; + m_To = to.Name; + from.SendLocalizedMessage(1077498); //You fill out the card. Hopefully the other person actually likes you... + InvalidateProperties(); + } + else + { + from.SendLocalizedMessage(1077495); //You can't give yourself a card, silly! + } + } + else + { + from.SendLocalizedMessage(1077496); //You can't possibly be THAT lonely! + } + } + else + { + from.SendLocalizedMessage(1077488); //That's not another player! + } + } + } + + public ValentinesCard(Serial serial) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + writer.Write((int)m_LabelNumber); + writer.Write((string)m_From); + writer.Write((string)m_To); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + m_LabelNumber = reader.ReadInt(); + m_From = reader.ReadString(); + m_To = reader.ReadString(); + + Utility.Intern(ref m_From); + Utility.Intern(ref m_To); + } + } + + public class ValentinesCardSouth : ValentinesCard + { + [Constructable] + public ValentinesCardSouth() + : base(0x0EBD) + { + } + + public ValentinesCardSouth(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class ValentinesCardEast : ValentinesCard + { + [Constructable] + public ValentinesCardEast() + : base(0x0EBE) + { + } + + public ValentinesCardEast(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs b/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs new file mode 100644 index 0000000..21b6079 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/AnkhOfSacrifice.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class AnkhOfSacrificeComponent : AddonComponent + { + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + public override int LabelNumber{ get{ return 1027772; } } // Ankh of Sacrifice + + public AnkhOfSacrificeComponent( int itemID ) : base( itemID ) + { + } + + public AnkhOfSacrificeComponent( Serial serial ) : base( serial ) + { + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from is PlayerMobile ) + list.Add( new LockKarmaEntry( (PlayerMobile)from, Addon as AnkhOfSacrificeAddon ) ); + + list.Add( new ResurrectEntry( from, Addon as AnkhOfSacrificeAddon ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public static void Resurrect( PlayerMobile m, AnkhOfSacrificeAddon ankh ) + { + if ( m == null ) + { + } + else if ( !m.InRange( ankh.GetWorldLocation(), 2 ) ) + { + m.SendLocalizedMessage( 500446 ); // That is too far away. + } + else if ( m.Alive ) + { + m.SendLocalizedMessage( 1060197 ); // You are not dead, and thus cannot be resurrected! + } + else if ( m.AnkhNextUse > DateTime.Now ) + { + TimeSpan delay = m.AnkhNextUse - DateTime.Now; + + if ( delay.TotalMinutes > 0 ) + m.SendLocalizedMessage( 1079265, Math.Round( delay.TotalMinutes ).ToString() ); // You must wait ~1_minutes~ minutes before you can use this item. + else + m.SendLocalizedMessage( 1079263, Math.Round( delay.TotalSeconds ).ToString() ); // You must wait ~1_seconds~ seconds before you can use this item. + } + else + { + m.CloseGump( typeof( AnkhResurrectGump ) ); + m.SendGump( new AnkhResurrectGump( m, ResurrectMessage.VirtueShrine ) ); + } + } + + private class ResurrectEntry : ContextMenuEntry + { + private Mobile m_Mobile; + private AnkhOfSacrificeAddon m_Ankh; + + public ResurrectEntry( Mobile mobile, AnkhOfSacrificeAddon ankh ) : base( 6195, 2 ) + { + m_Mobile = mobile; + m_Ankh = ankh; + } + + public override void OnClick() + { + if ( m_Ankh == null || m_Ankh.Deleted ) + return; + + Resurrect( m_Mobile as PlayerMobile, m_Ankh ); + } + } + + private class LockKarmaEntry : ContextMenuEntry + { + private PlayerMobile m_Mobile; + private AnkhOfSacrificeAddon m_Ankh; + + public LockKarmaEntry( PlayerMobile mobile, AnkhOfSacrificeAddon ankh ) : base( mobile.KarmaLocked ? 6197 : 6196, 2 ) + { + m_Mobile = mobile; + m_Ankh = ankh; + } + + public override void OnClick() + { + if ( !m_Mobile.InRange( m_Ankh.GetWorldLocation(), 2 ) ) + m_Mobile.SendLocalizedMessage( 500446 ); // That is too far away. + else + { + m_Mobile.KarmaLocked = !m_Mobile.KarmaLocked; + + if ( m_Mobile.KarmaLocked ) + m_Mobile.SendLocalizedMessage( 1060192 ); // Your karma has been locked. Your karma can no longer be raised. + else + m_Mobile.SendLocalizedMessage( 1060191 ); // Your karma has been unlocked. Your karma can be raised again. + } + } + } + + private class AnkhResurrectGump : ResurrectGump + { + public AnkhResurrectGump( Mobile owner, ResurrectMessage msg ) : base( owner, owner, msg, false ) + { + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if( info.ButtonID == 1 || info.ButtonID == 2 ) + { + if( from.Map == null || !from.Map.CanFit( from.Location, 16, false, false ) ) + { + from.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + return; + } + + if ( from is PlayerMobile ) + { + ((PlayerMobile) from).AnkhNextUse = DateTime.Now + TimeSpan.FromHours( 1 ); + } + + base.OnResponse( state, info ); + } + } + } + } + public class AnkhOfSacrificeAddon : BaseAddon, IRewardItem + { + public override bool HandlesOnMovement{ get{ return true; } } + + public override BaseAddonDeed Deed + { + get + { + AnkhOfSacrificeDeed deed = new AnkhOfSacrificeDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public AnkhOfSacrificeAddon( bool east ) : base() + { + if ( east ) + { + AddComponent( new AnkhOfSacrificeComponent( 0x1D98 ), 0, 0, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1D97 ), 0, 1, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CD6 ), 1, 0, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CD4 ), 1, 1, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CD0 ), 2, 0, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CCE ), 2, 1, 0 ); + } + else + { + AddComponent( new AnkhOfSacrificeComponent( 0x1E5D ), 0, 0, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1E5C ), 1, 0, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CD2 ), 0, 1, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CD8 ), 1, 1, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CCD ), 0, 2, 0 ); + AddComponent( new AnkhOfSacrificeComponent( 0x1CCE ), 1, 2, 0 ); + } + } + + public AnkhOfSacrificeAddon( Serial serial ) : base( serial ) + { + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( !m.Alive && Utility.InRange( Location, m.Location, 1 ) && !Utility.InRange( Location, oldLocation, 1 ) ) + AnkhOfSacrificeComponent.Resurrect( m as PlayerMobile, this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class AnkhOfSacrificeDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + public override int LabelNumber{ get{ return 1080397; } } // Deed For An Ankh Of Sacrifice + + public override BaseAddon Addon + { + get + { + AnkhOfSacrificeAddon addon = new AnkhOfSacrificeAddon( m_East ); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + private bool m_East; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public AnkhOfSacrificeDeed() : this( false ) + { + } + + [Constructable] + public AnkhOfSacrificeDeed( bool isRewardItem ) : base() + { + LootType = LootType.Blessed; + + m_IsRewardItem = isRewardItem; + } + + public AnkhOfSacrificeDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( RewardOptionGump ) ); + from.SendGump( new RewardOptionGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1080457 ); // 10th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public void GetOptions( RewardOptionList list ) + { + list.Add( 1, 1080398 ); // Ankh of Sacrifice South + list.Add( 2, 1080399 ); // Ankh of Sacrifice East + } + + public void OnOptionSelected( Mobile from, int option ) + { + switch ( option ) + { + case 1: m_East = false; break; + case 2: m_East = true; break; + } + + if ( !Deleted ) + base.OnDoubleClick( from ); + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/Banner.cs b/Scripts/Items/Special/Veteran Rewards/Banner.cs new file mode 100644 index 0000000..12b495e --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/Banner.cs @@ -0,0 +1,386 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class Banner : Item, IAddon, IDyable, IRewardItem + { + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public Item Deed + { + get + { + BannerDeed deed = new BannerDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + public bool FacingSouth + { + get{ return ( ItemID & 0x1 ) == 0; } + } + + [Constructable] + public Banner( int itemID ) : base( itemID ) + { + LootType = LootType.Blessed; + Movable = false; + } + + public Banner( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076218 ); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( RewardDemolitionGump ) ); + from.SendGump( new RewardDemolitionGump( this, 1018318 ) ); // Do you wish to re-deed this banner? + } + else + from.SendLocalizedMessage( 1018330 ); // You can only re-deed a banner if you placed it or you are the owner of the house. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( map == null || !map.CanFit( p.X, p.Y, p.Z, ItemData.Height ) ) + return false; + + if ( FacingSouth ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // north wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // west wall + } + } + + public class BannerDeed : Item, IRewardItem + { + public override int LabelNumber{ get{ return 1041007; } } // a banner deed + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + [Constructable] + public BannerDeed() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public BannerDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076218 ); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + public const int Start = 0x15AE; + public const int End = 0x15F4; + + private BannerDeed m_Banner; + + public InternalGump( BannerDeed banner ) : base( 100, 200 ) + { + m_Banner = banner; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 25, 0, 520, 230, 0xA28 ); + AddLabel( 70, 12, 0x3E3, "Choose a Banner:" ); + + + int itemID = Start; + + for ( int i = 1; i <= 4; i++ ) + { + AddPage( i ); + + for ( int j = 0; j < 8; j++, itemID += 2 ) + { + AddItem( 50 + 60 * j, 70, itemID ); + AddButton( 50 + 60 * j, 50, 0x845, 0x846, itemID, GumpButtonType.Reply, 0 ); + } + + if ( i > 1 ) + AddButton( 75, 198, 0x8AF, 0x8AF, 0, GumpButtonType.Page, i - 1 ); + + if ( i < 4 ) + AddButton( 475, 198, 0x8B0, 0x8B0, 0, GumpButtonType.Page, i + 1 ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Banner == null | m_Banner.Deleted ) + return; + + Mobile m = sender.Mobile; + + if ( info.ButtonID >= Start && info.ButtonID <= End ) + { + if ( ( info.ButtonID & 0x1 ) == 0 ) + { + m.SendLocalizedMessage( 1042037 ); // Where would you like to place this banner? + m.Target = new InternalTarget( m_Banner, info.ButtonID ); + } + } + } + } + + private class InternalTarget : Target + { + private BannerDeed m_Banner; + private int m_ItemID; + + public InternalTarget( BannerDeed banner, int itemID ) : base( -1, true, TargetFlags.None ) + { + m_Banner = banner; + m_ItemID = itemID; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Banner == null || m_Banner.Deleted ) + return; + + if ( m_Banner.IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if ( p == null || map == null ) + return; + + Point3D p3d = new Point3D( p ); + ItemData id = TileData.ItemTable[ m_ItemID & TileData.MaxItemValue ]; + + if ( map.CanFit( p3d, id.Height ) ) + { + house = BaseHouse.FindHouseAt( p3d, map, id.Height ); + + if ( house != null && house.IsOwner( from ) ) + { + bool north = BaseAddon.IsWall( p3d.X, p3d.Y - 1, p3d.Z, map ); + bool west = BaseAddon.IsWall( p3d.X - 1, p3d.Y, p3d.Z, map ); + + if ( north && west ) + { + from.CloseGump( typeof( FacingGump ) ); + from.SendGump( new FacingGump( m_Banner, m_ItemID, p3d, house ) ); + } + else if ( north || west ) + { + Banner banner = null; + + if ( north ) + banner = new Banner( m_ItemID ); + else if ( west ) + banner = new Banner( m_ItemID + 1 ); + + house.Addons.Add( banner ); + + banner.IsRewardItem = m_Banner.IsRewardItem; + banner.MoveToWorld( p3d, map ); + + m_Banner.Delete(); + } + else + from.SendLocalizedMessage( 1042039 ); // The banner must be placed next to a wall. + } + else + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + else + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + private class FacingGump : Gump + { + private BannerDeed m_Banner; + private int m_ItemID; + private Point3D m_Location; + private BaseHouse m_House; + + private enum Buttons + { + Cancel, + East, + South + } + + public FacingGump( BannerDeed banner, int itemID, Point3D location, BaseHouse house ) : base( 150, 50 ) + { + m_Banner = banner; + m_ItemID = itemID; + m_Location = location; + m_House = house; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddItem( 90, 30, itemID + 1 ); + AddItem( 180, 30, itemID ); + + AddButton( 50, 35, 0x868, 0x869, (int) Buttons.East, GumpButtonType.Reply, 0 ); + AddButton( 145, 35, 0x868, 0x869, (int) Buttons.South, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Banner == null || m_Banner.Deleted || m_House == null ) + return; + + Banner banner = null; + + if ( info.ButtonID == (int) Buttons.East ) + banner = new Banner( m_ItemID + 1 ); + if ( info.ButtonID == (int) Buttons.South ) + banner = new Banner( m_ItemID ); + + if ( banner != null ) + { + m_House.Addons.Add( banner ); + + banner.IsRewardItem = m_Banner.IsRewardItem; + banner.MoveToWorld( m_Location, sender.Mobile.Map ); + + m_Banner.Delete(); + } + } + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/BloodyPentagram.cs b/Scripts/Items/Special/Veteran Rewards/BloodyPentagram.cs new file mode 100644 index 0000000..d2dd3d5 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/BloodyPentagram.cs @@ -0,0 +1,194 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class BloodyPentagramComponent : AddonComponent + { + public override bool DisplayWeight{ get{ return false; } } + public override int LabelNumber{ get{ return 1080279; } } // Bloody Pentagram + + public BloodyPentagramComponent( int itemID ) : base( itemID ) + { + } + + public BloodyPentagramComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class BloodyPentagramAddon : BaseAddon, IRewardItem + { + public override BaseAddonDeed Deed + { + get + { + BloodyPentagramDeed deed = new BloodyPentagramDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public BloodyPentagramAddon() : base() + { + AddComponent( new BloodyPentagramComponent( 0x1CF9 ), 0, 1, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF8 ), 0, 2, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF7 ), 0, 3, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF6 ), 0, 4, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF5 ), 0, 5, 0 ); + + AddComponent( new BloodyPentagramComponent( 0x1CFB ), 1, 0, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CFA ), 1, 1, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D09 ), 1, 2, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D08 ), 1, 3, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D07 ), 1, 4, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF4 ), 1, 5, 0 ); + + AddComponent( new BloodyPentagramComponent( 0x1CFC ), 2, 0, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D0A ), 2, 1, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D11 ), 2, 2, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D10 ), 2, 3, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D06 ), 2, 4, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF3 ), 2, 5, 0 ); + + AddComponent( new BloodyPentagramComponent( 0x1CFD ), 3, 0, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D0B ), 3, 1, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D12 ), 3, 2, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D0F ), 3, 3, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D05 ), 3, 4, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF2 ), 3, 5, 0 ); + + AddComponent( new BloodyPentagramComponent( 0x1CFE ), 4, 0, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D0C ), 4, 1, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D0D ), 4, 2, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D0E ), 4, 3, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D04 ), 4, 4, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1CF1 ), 4, 5, 0 ); + + AddComponent( new BloodyPentagramComponent( 0x1CFF ), 5, 0, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D00 ), 5, 1, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D01 ), 5, 2, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D02 ), 5, 3, 0 ); + AddComponent( new BloodyPentagramComponent( 0x1D03 ), 5, 4, 0 ); + } + + public BloodyPentagramAddon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class BloodyPentagramDeed : BaseAddonDeed, IRewardItem + { + public override int LabelNumber{ get{ return 1080384; } } // Bloody Pentagram + + public override BaseAddon Addon + { + get + { + BloodyPentagramAddon addon = new BloodyPentagramAddon(); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public BloodyPentagramDeed() : base() + { + LootType = LootType.Blessed; + } + + public BloodyPentagramDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + base.OnDoubleClick( from ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076221 ); // 5th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/Brazier.cs b/Scripts/Items/Special/Veteran Rewards/Brazier.cs new file mode 100644 index 0000000..9bc2294 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/Brazier.cs @@ -0,0 +1,244 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class RewardBrazier : Item, IRewardItem + { + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + private Item m_Fire; + + public override void OnDelete() + { + TurnOff(); + + base.OnDelete(); + } + + private static int[] m_Art = new int[] + { + 0x19AA, 0x19BB + }; + + [Constructable] + public RewardBrazier() : this( Utility.RandomList( m_Art ) ) + { + } + + [Constructable] + public RewardBrazier( int itemID ) : base( itemID ) + { + LootType = LootType.Blessed; + Weight = 10.0; + } + + public RewardBrazier( Serial serial ) : base( serial ) + { + } + + public void TurnOff() + { + if ( m_Fire != null ) + { + m_Fire.Delete(); + m_Fire = null; + } + } + + public void TurnOn() + { + if ( m_Fire == null ) + m_Fire = new Item(); + + m_Fire.ItemID = 0x19AB; + m_Fire.Movable = false; + m_Fire.MoveToWorld( new Point3D( X, Y, Z + ItemData.Height + 2 ), Map ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !from.InRange( this.GetWorldLocation(), 2 ) ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + else if ( IsLockedDown ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsCoOwner( from ) ) + { + if ( m_Fire != null ) + TurnOff(); + else + TurnOn(); + } + else + from.SendLocalizedMessage( 502436 ); // That is not accessible. + } + else + from.SendLocalizedMessage( 502692 ); // This must be in a house and be locked down to work. + } + + public override void OnLocationChange( Point3D old ) + { + if ( m_Fire != null ) + m_Fire.MoveToWorld( new Point3D( X, Y, Z + ItemData.Height ), Map ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076222 ); // 6th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + writer.Write( (Item) m_Fire ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Fire = reader.ReadItem(); + } + } + + public class RewardBrazierDeed : Item, IRewardItem + { + public override int LabelNumber{ get{ return 1080527; } } // Brazier Deed + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public RewardBrazierDeed() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public RewardBrazierDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076222 ); // 6th Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private RewardBrazierDeed m_Brazier; + + public InternalGump( RewardBrazierDeed brazier ) : base( 100, 200 ) + { + m_Brazier = brazier; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 200, 200, 2600 ); + + AddPage( 1 ); + AddLabel( 45, 15, 0, "Choose a Brazier:" ); + + AddItem( 40, 75, 0x19AA ); + AddButton( 55, 50, 0x845, 0x846, 0x19AA, GumpButtonType.Reply, 0 ); + + AddItem( 100, 75, 0x19BB ); + AddButton( 115, 50, 0x845, 0x846, 0x19BB, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Brazier == null | m_Brazier.Deleted ) + return; + + Mobile m = sender.Mobile; + + if ( info.ButtonID == 0x19AA || info.ButtonID == 0x19BB ) + { + RewardBrazier brazier = new RewardBrazier( info.ButtonID ); + brazier.IsRewardItem = m_Brazier.IsRewardItem; + + if ( !m.PlaceInBackpack( brazier ) ) + { + brazier.Delete(); + m.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + m_Brazier.Delete(); + } + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/Cannon.cs b/Scripts/Items/Special/Veteran Rewards/Cannon.cs new file mode 100644 index 0000000..a5bbd71 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/Cannon.cs @@ -0,0 +1,469 @@ +using System; +using Server; +using Server.Gumps; +using Server.Targeting; +using Server.Mobiles; +using Server.Network; +using Server.Engines.Quests.Haven; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class CannonAddonComponent : AddonComponent + { + public override int LabelNumber{ get{ return 1076157; } } // Decorative Cannon + + public CannonAddonComponent( int itemID ) : base( itemID ) + { + LootType = LootType.Blessed; + } + + public CannonAddonComponent( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Addon is CannonAddon ) + { + if ( ((CannonAddon) Addon).IsRewardItem ) + list.Add( 1076223 ); // 7th Year Veteran Reward + + list.Add( 1076207, ((CannonAddon) Addon).Charges.ToString() ); // Remaining Charges: ~1_val~ + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CannonAddon : BaseAddon + { + public override BaseAddonDeed Deed + { + get + { + CannonDeed deed = new CannonDeed(); + deed.Charges = m_Charges; + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private CannonDirection m_CannonDirection; + private int m_Charges; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public CannonDirection CannonDirection + { + get{ return m_CannonDirection; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set + { + m_Charges = value; + + foreach ( AddonComponent c in Components ) + c.InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set + { + m_IsRewardItem = value; + + foreach ( AddonComponent c in Components ) + c.InvalidateProperties(); + } + } + + [Constructable] + public CannonAddon( CannonDirection direction ) + { + m_CannonDirection = direction; + + switch ( direction ) + { + case CannonDirection.North: + { + AddComponent( new CannonAddonComponent( 0xE8D ), 0, 0, 0 ); + AddComponent( new CannonAddonComponent( 0xE8C ), 0, 1, 0 ); + AddComponent( new CannonAddonComponent( 0xE8B ), 0, 2, 0 ); + + break; + } + case CannonDirection.East: + { + AddComponent( new CannonAddonComponent( 0xE96 ), 0, 0, 0 ); + AddComponent( new CannonAddonComponent( 0xE95 ), -1, 0, 0 ); + AddComponent( new CannonAddonComponent( 0xE94 ), -2, 0, 0 ); + + break; + } + case CannonDirection.South: + { + AddComponent( new CannonAddonComponent( 0xE91 ), 0, 0, 0 ); + AddComponent( new CannonAddonComponent( 0xE92 ), 0, -1, 0 ); + AddComponent( new CannonAddonComponent( 0xE93 ), 0, -2, 0 ); + + break; + } + default: + { + AddComponent( new CannonAddonComponent( 0xE8E ), 0, 0, 0 ); + AddComponent( new CannonAddonComponent( 0xE8F ), 1, 0, 0 ); + AddComponent( new CannonAddonComponent( 0xE90 ), 2, 0, 0 ); + + break; + } + } + } + + public CannonAddon( Serial serial ) : base( serial ) + { + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + if ( m_Charges > 0 ) + { + from.Target = new InternalTarget( this ); + } + else + { + if ( from.Backpack != null ) + { + PotionKeg keg = from.Backpack.FindItemByType( typeof( PotionKeg ) ) as PotionKeg; + + if ( Validate( keg ) > 0 ) + from.SendGump( new InternalGump( this, keg ) ); + else + from.SendLocalizedMessage( 1076198 ); // You do not have a full keg of explosion potions needed to recharge the cannon. + } + } + } + else + from.SendLocalizedMessage( 1076766 ); // That is too far away. + } + + public int Validate( PotionKeg keg ) + { + if ( keg != null && !keg.Deleted && keg.Held == 100 ) + { + if ( keg.Type == PotionEffect.ExplosionLesser ) + return 5; + else if ( keg.Type == PotionEffect.Explosion ) + return 10; + else if ( keg.Type == PotionEffect.ExplosionGreater ) + return 15; + } + + return 0; + } + + public void Fill( Mobile from, PotionKeg keg ) + { + Charges = Validate( keg ); + + if ( Charges > 0 ) + { + keg.Delete(); + from.SendLocalizedMessage( 1076199 ); // Your cannon is recharged. + } + else + from.SendLocalizedMessage( 1076198 ); // You do not have a full keg of explosion potions needed to recharge the cannon. + } + + private static int[] m_Effects = new int[] + { + 0x36B0, 0x3728, 0x3709, 0x36FE + }; + + public void DoFireEffect( IPoint3D target ) + { + Map map = Map; + + if ( target == null || map == null ) + return; + + Effects.PlaySound( target, map, Utility.RandomList( 0x11B, 0x11C, 0x11D ) ); + Effects.SendLocationEffect( target, map, Utility.RandomList( m_Effects ), 16, 1 ); + + for ( int count = Utility.Random( 3 ); count > 0; count-- ) + { + IPoint3D location = new Point3D( target.X + Utility.RandomMinMax( -1, 1 ), target.Y + Utility.RandomMinMax( -1, 1 ), target.Z ); + int effect = Utility.RandomList( m_Effects ); + Effects.SendLocationEffect( location, map, effect, 16, 1 ); + } + + Charges -= 1; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_CannonDirection ); + writer.Write( (int) m_Charges ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_CannonDirection = (CannonDirection) reader.ReadInt(); + m_Charges = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalTarget : Target + { + private CannonAddon m_Cannon; + + public InternalTarget( CannonAddon cannon ) : base( 12, true, TargetFlags.None ) + { + m_Cannon = cannon; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Cannon == null || m_Cannon.Deleted ) + return; + + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + + if ( from.InLOS( new Point3D( p ) ) ) + { + if ( !Utility.InRange( new Point3D( p ), m_Cannon.Location, 2 ) ) + { + bool allow = false; + + int x = p.X - m_Cannon.X; + int y = p.Y - m_Cannon.Y; + + switch ( m_Cannon.CannonDirection ) + { + case CannonDirection.North: + if ( y < 0 && Math.Abs( x ) <= -y / 3 ) + allow = true; + + break; + case CannonDirection.East: + if ( x > 0 && Math.Abs( y ) <= x / 3 ) + allow = true; + + break; + case CannonDirection.South: + if ( y > 0 && Math.Abs( x ) <= y / 3 ) + allow = true; + + break; + case CannonDirection.West: + if ( x < 0 && Math.Abs( y ) <= -x / 3 ) + allow = true; + + break; + } + + if ( allow && Utility.InRange( new Point3D( p ), m_Cannon.Location, 14 ) ) + m_Cannon.DoFireEffect( p ); + else + from.SendLocalizedMessage( 1076203 ); // Target out of range. + } + else + from.SendLocalizedMessage( 1076215 ); // Cannon must be aimed farther away. + } + else + from.SendLocalizedMessage( 1049630 ); // You cannot see that target! + } + + protected override void OnTargetOutOfRange( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 1076203 ); // Target out of range. + } + } + + private class InternalGump : Gump + { + private CannonAddon m_Cannon; + private PotionKeg m_Keg; + + private enum Buttons + { + Cancel, + Recharge + } + + public InternalGump( CannonAddon cannon, PotionKeg keg ) : base( 50, 50 ) + { + m_Cannon = cannon; + m_Keg = keg; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 291, 133, 0x13BE ); + AddImageTiled( 5, 5, 280, 100, 0xA40 ); + + AddHtmlLocalized( 9, 9, 272, 100, 1076196, cannon.Validate( keg ).ToString(), 0x7FFF, false, false ); // You will need a full keg of explosion potions to recharge the cannon. Your keg will provide ~1_CHARGES~ charges. + + AddButton( 5, 107, 0xFB1, 0xFB2, (int) Buttons.Cancel, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 109, 100, 20, 1060051, 0x7FFF, false, false ); // CANCEL + + AddButton( 160, 107, 0xFB7, 0xFB8, (int) Buttons.Recharge, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 195, 109, 120, 20, 1076197, 0x7FFF, false, false ); // Recharge + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( m_Cannon == null || m_Cannon.Deleted ) + return; + + if ( info.ButtonID == (int) Buttons.Recharge ) + m_Cannon.Fill( state.Mobile, m_Keg ); + } + } + } + + public class CannonDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + public override int LabelNumber{ get{ return 1076195; } } // A deed for a cannon + + public override BaseAddon Addon + { + get + { + CannonAddon addon = new CannonAddon( m_Direction ); + addon.Charges = m_Charges; + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + private CannonDirection m_Direction; + private int m_Charges; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set{ m_Charges = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public CannonDeed() : base() + { + LootType = LootType.Blessed; + } + + public CannonDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076223 ); // 7th Year Veteran Reward + + list.Add( 1076207, m_Charges.ToString() ); // Remaining Charges: ~1_val~ + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( RewardOptionGump ) ); + from.SendGump( new RewardOptionGump( this ) ); + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) m_Charges ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Charges = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + } + + public void GetOptions( RewardOptionList list ) + { + list.Add( (int) CannonDirection.South, 1075386 ); // South + list.Add( (int) CannonDirection.East, 1075387 ); // East + list.Add( (int) CannonDirection.North, 1075389 ); // North + list.Add( (int) CannonDirection.West, 1075390 ); // West + } + + public void OnOptionSelected( Mobile from, int option ) + { + m_Direction = (CannonDirection) option; + + if ( !Deleted ) + base.OnDoubleClick( from ); + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/CommodityDeedBox.cs b/Scripts/Items/Special/Veteran Rewards/CommodityDeedBox.cs new file mode 100644 index 0000000..caf0b20 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/CommodityDeedBox.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class CommodityDeedBox : BaseContainer, IRewardItem + { + public override int LabelNumber{ get { return 1080523; } } // Commodity Deed Box + public override int DefaultGumpID{ get{ return 0x43; } } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public CommodityDeedBox() : base( 0x9AA ) + { + Hue = 0x47; + Weight = 4.0; + } + + public CommodityDeedBox( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076217 ); // 1st Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public static CommodityDeedBox Find( Item deed ) + { + Item parent = deed; + + while ( parent != null && !( parent is CommodityDeedBox ) ) + parent = parent.Parent as Item; + + return parent as CommodityDeedBox; + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/ContestMiniHouse.cs b/Scripts/Items/Special/Veteran Rewards/ContestMiniHouse.cs new file mode 100644 index 0000000..df996dc --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/ContestMiniHouse.cs @@ -0,0 +1,132 @@ +using System; +using Server; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class ContestMiniHouse : MiniHouseAddon + { + public override BaseAddonDeed Deed + { + get + { + ContestMiniHouseDeed deed = new ContestMiniHouseDeed( Type ); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public ContestMiniHouse() : base( MiniHouseType.MalasMountainPass ) + { + } + + [Constructable] + public ContestMiniHouse( MiniHouseType type ) : base( type ) + { + } + + public ContestMiniHouse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class ContestMiniHouseDeed : MiniHouseDeed, IRewardItem + { + public override BaseAddon Addon + { + get + { + ContestMiniHouse addon = new ContestMiniHouse( Type ); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public ContestMiniHouseDeed() : base( MiniHouseType.MalasMountainPass ) + { + } + + [Constructable] + public ContestMiniHouseDeed( MiniHouseType type ) : base( type ) + { + } + + public ContestMiniHouseDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, new object[] { Type } ) ) + return; + + base.OnDoubleClick( from ); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076217 ); // 1st Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/DecorativeShield.cs b/Scripts/Items/Special/Veteran Rewards/DecorativeShield.cs new file mode 100644 index 0000000..298dc72 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/DecorativeShield.cs @@ -0,0 +1,400 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class DecorativeShield : Item, IAddon, IRewardItem + { + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public Item Deed + { + get + { + DecorativeShieldDeed deed = new DecorativeShieldDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + public bool FacingSouth + { + get + { + if ( ItemID < 0x1582 ) + return ( ItemID & 0x1 ) == 0; + + return ItemID <= 0x1585; + } + } + + [Constructable] + public DecorativeShield() : this( 0x156C ) + { + } + + [Constructable] + public DecorativeShield( int itemID ) : base( itemID ) + { + Movable = false; + } + + public DecorativeShield( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076220 ); // 4th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( RewardDemolitionGump ) ); + from.SendGump( new RewardDemolitionGump( this, 1049783 ) ); // Do you wish to re-deed this decoration? + } + else + from.SendLocalizedMessage( 1049784 ); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( map == null || !map.CanFit( p.X, p.Y, p.Z, ItemData.Height ) ) + return false; + + if ( FacingSouth ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // north wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // west wall + } + } + + public class DecorativeShieldDeed : Item, IRewardItem + { + public override int LabelNumber{ get{ return 1049771; } } // deed for a decorative shield wall hanging + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public DecorativeShieldDeed() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public DecorativeShieldDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076220 ); // 4th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public static int GetWestItemID( int east ) + { + switch ( east ) + { + case 0x1582: return 0x1635; + case 0x1583: return 0x1634; + case 0x1584: return 0x1637; + case 0x1585: return 0x1636; + default: return east + 1; + } + } + + private class InternalGump : Gump + { + public const int Start = 0x156C; + public const int End = 0x1585; + + private DecorativeShieldDeed m_Shield; + private int m_Page; + + public InternalGump( DecorativeShieldDeed shield ) : this( shield, 1 ) + { + } + + public InternalGump( DecorativeShieldDeed shield, int page ) : base( 150, 50 ) + { + m_Shield = shield; + m_Page = page; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 25, 0, 500, 230, 0xA28 ); + + int itemID = Start; + + for ( int i = 1; i <= 2; i++ ) + { + AddPage( i ); + + for ( int j = 0; j < 9 - i; j++ ) + { + AddItem( 40 + j * 60, 70, itemID ); + AddButton( 60 + j * 60, 50, 0x845, 0x846, itemID, GumpButtonType.Reply, 0 ); + + if ( itemID < 0x1582 ) + itemID += 2; + else + itemID += 1; + } + + switch ( i ) + { + case 1: AddButton( 455, 198, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 2 ); break; + case 2: AddButton( 70, 198, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 1 ); break; + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Shield == null | m_Shield.Deleted ) + return; + + Mobile m = sender.Mobile; + + if ( info.ButtonID >= Start && info.ButtonID <= End ) + { + if ( ( info.ButtonID & 0x1 ) == 0 && info.ButtonID < 0x1582 || info.ButtonID >= 0x1582 && info.ButtonID <= 0x1585 ) + { + m.SendLocalizedMessage( 1049780 ); // Where would you like to place this decoration? + m.Target = new InternalTarget( m_Shield, info.ButtonID ); + } + } + } + } + + private class InternalTarget : Target + { + private DecorativeShieldDeed m_Shield; + private int m_ItemID; + + public InternalTarget( DecorativeShieldDeed shield, int itemID ) : base( -1, true, TargetFlags.None ) + { + m_Shield = shield; + m_ItemID = itemID; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Shield == null || m_Shield.Deleted ) + return; + + if ( m_Shield.IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if ( p == null || map == null ) + return; + + Point3D p3d = new Point3D( p ); + ItemData id = TileData.ItemTable[ m_ItemID & TileData.MaxItemValue ]; + + if ( map.CanFit( p3d, id.Height ) ) + { + house = BaseHouse.FindHouseAt( p3d, map, id.Height ); + + if ( house != null && house.IsOwner( from ) ) + { + bool north = BaseAddon.IsWall( p3d.X, p3d.Y - 1, p3d.Z, map ); + bool west = BaseAddon.IsWall( p3d.X - 1, p3d.Y, p3d.Z, map ); + + if ( north && west ) + { + from.CloseGump( typeof( FacingGump ) ); + from.SendGump( new FacingGump( m_Shield, m_ItemID, p3d, house ) ); + } + else if ( north || west ) + { + DecorativeShield shield = null; + + if ( north ) + shield = new DecorativeShield( m_ItemID ); + else if ( west ) + shield = new DecorativeShield( GetWestItemID( m_ItemID ) ); + + house.Addons.Add( shield ); + + shield.IsRewardItem = m_Shield.IsRewardItem; + shield.MoveToWorld( p3d, map ); + + m_Shield.Delete(); + } + else + from.SendLocalizedMessage( 1049781 ); // This decoration must be placed next to a wall. + } + else + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + else + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + private class FacingGump : Gump + { + private DecorativeShieldDeed m_Shield; + private int m_ItemID; + private Point3D m_Location; + private BaseHouse m_House; + + private enum Buttons + { + Cancel, + South, + East + } + + public FacingGump( DecorativeShieldDeed shield, int itemID, Point3D location, BaseHouse house ) : base( 150, 50 ) + { + m_Shield = shield; + m_ItemID = itemID; + m_Location = location; + m_House = house; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddItem( 90, 30, GetWestItemID( itemID ) ); + AddItem( 180, 30, itemID ); + + AddButton( 50, 35, 0x867, 0x869, (int) Buttons.East, GumpButtonType.Reply, 0 ); + AddButton( 145, 35, 0x867, 0x869, (int) Buttons.South, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Shield == null || m_Shield.Deleted || m_House == null ) + return; + + DecorativeShield shield = null; + + if ( info.ButtonID == (int) Buttons.East ) + shield = new DecorativeShield( GetWestItemID( m_ItemID ) ); + if ( info.ButtonID == (int) Buttons.South ) + shield = new DecorativeShield( m_ItemID ); + + if ( shield != null ) + { + m_House.Addons.Add( shield ); + + shield.IsRewardItem = m_Shield.IsRewardItem; + shield.MoveToWorld( m_Location, sender.Mobile.Map ); + + m_Shield.Delete(); + } + } + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/FlamingHead.cs b/Scripts/Items/Special/Veteran Rewards/FlamingHead.cs new file mode 100644 index 0000000..05f165e --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/FlamingHead.cs @@ -0,0 +1,257 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class FlamingHead : StoneFaceTrapNoDamage, IAddon, IRewardItem + { + public override int LabelNumber{ get{ return 1041266; } } // Flaming Head + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public Item Deed + { + get + { + FlamingHeadDeed deed = new FlamingHeadDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public FlamingHead() : this( StoneFaceTrapType.NorthWall ) + { + } + + [Constructable] + public FlamingHead( StoneFaceTrapType type ) : base() + { + LootType = LootType.Blessed; + Movable = false; + Type = type; + } + + public FlamingHead( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076218 ); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( Location, 2 ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( RewardDemolitionGump ) ); + from.SendGump( new RewardDemolitionGump( this, 1018329 ) ); // Do you wish to re-deed this skull? + } + else + from.SendLocalizedMessage( 1018328 ); // You can only re-deed a skull if you placed it or you are the owner of the house. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( map == null || !map.CanFit( p.X, p.Y, p.Z, ItemData.Height ) ) + return false; + + if ( Type == StoneFaceTrapType.NorthWestWall ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ) && BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // north and west wall + else if ( Type == StoneFaceTrapType.NorthWall ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // north wall + else if ( Type == StoneFaceTrapType.WestWall ) + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // west wall + + return false; + } + } + + public class FlamingHeadDeed : Item, IRewardItem + { + public override int LabelNumber{ get{ return 1041050; } } // a flaming head deed + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public FlamingHeadDeed() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public FlamingHeadDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076218 ); // 2nd Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + from.SendLocalizedMessage( 1042264 ); // Where would you like to place this head? + from.Target = new InternalTarget( this ); + } + else + from.SendLocalizedMessage( 502115 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalTarget : Target + { + private FlamingHeadDeed m_Head; + + public InternalTarget( FlamingHeadDeed head ) : base( -1, true, TargetFlags.None ) + { + m_Head = head; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Head == null || m_Head.Deleted ) + return; + + if ( m_Head.IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if ( p == null || map == null ) + return; + + Point3D p3d = new Point3D( p ); + ItemData id = TileData.ItemTable[ 0x10F5 ]; + + house = BaseHouse.FindHouseAt( p3d, map, id.Height ); + + if ( house != null && house.IsOwner( from ) ) + { + if ( map.CanFit( p3d, id.Height ) ) + { + bool north = BaseAddon.IsWall( p3d.X, p3d.Y - 1, p3d.Z, map ); + bool west = BaseAddon.IsWall( p3d.X - 1, p3d.Y, p3d.Z, map ); + + FlamingHead head = null; + + if ( north && west ) + head = new FlamingHead( StoneFaceTrapType.NorthWestWall ); + else if ( north ) + head = new FlamingHead( StoneFaceTrapType.NorthWall ); + else if ( west ) + head = new FlamingHead( StoneFaceTrapType.WestWall ); + + if ( north || west ) + { + house.Addons.Add( head ); + + head.IsRewardItem = m_Head.IsRewardItem; + head.MoveToWorld( p3d, map ); + + m_Head.Delete(); + } + else + from.SendLocalizedMessage( 1042266 ); // The head must be placed next to a wall. + } + else + from.SendLocalizedMessage( 1042266 ); // The head must be placed next to a wall. + } + else + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + else + from.SendLocalizedMessage( 502115 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/HangingSkeleton.cs b/Scripts/Items/Special/Veteran Rewards/HangingSkeleton.cs new file mode 100644 index 0000000..25ea959 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/HangingSkeleton.cs @@ -0,0 +1,390 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class HangingSkeleton : Item, IAddon, IRewardItem + { + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + public Item Deed + { + get + { + HangingSkeletonDeed deed = new HangingSkeletonDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + public bool FacingSouth + { + get + { + if ( ItemID == 0x1A03 || ItemID == 0x1A05 || ItemID == 0x1A09 || + ItemID == 0x1B1E || ItemID == 0x1B7F ) + return true; + + return false; + } + } + + [Constructable] + public HangingSkeleton() : this( 0x1596 ) + { + } + + [Constructable] + public HangingSkeleton( int itemID ) : base( itemID ) + { + LootType = LootType.Blessed; + Movable = false; + } + + public HangingSkeleton( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Core.ML && m_IsRewardItem ) + list.Add( 1076220 ); // 4th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.InRange( Location, 3 ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( RewardDemolitionGump ) ); + from.SendGump( new RewardDemolitionGump( this, 1049783 ) ); // Do you wish to re-deed this decoration? + } + else + from.SendLocalizedMessage( 1049784 ); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( map == null || !map.CanFit( p.X, p.Y, p.Z, ItemData.Height ) ) + return false; + + if ( FacingSouth ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // north wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // west wall + } + } + + public class HangingSkeletonDeed : Item, IRewardItem + { + public override int LabelNumber{ get{ return 1049772; } } // deed for a hanging skeleton decoration + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public HangingSkeletonDeed() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public HangingSkeletonDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076220 ); // 4th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public static int GetWestItemID( int south ) + { + switch ( south ) + { + case 0x1B1E: return 0x1B1D; + case 0x1B7F: return 0x1B7C; + default: return south + 1; + } + } + + private class InternalGump : Gump + { + private HangingSkeletonDeed m_Skeleton; + + public InternalGump( HangingSkeletonDeed skeleton ) : base( 100, 200 ) + { + m_Skeleton = skeleton; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 25, 0, 500, 230, 0xA28 ); + + AddPage( 1 ); + + AddItem( 130, 70, 0x1A03 ); + AddButton( 150, 50, 0x845, 0x846, 0x1A03, GumpButtonType.Reply, 0 ); + + AddItem( 190, 70, 0x1A05 ); + AddButton( 210, 50, 0x845, 0x846, 0x1A05, GumpButtonType.Reply, 0 ); + + AddItem( 250, 70, 0x1A09 ); + AddButton( 270, 50, 0x845, 0x846, 0x1A09, GumpButtonType.Reply, 0 ); + + AddItem( 310, 70, 0x1B1E ); + AddButton( 330, 50, 0x845, 0x846, 0x1B1E, GumpButtonType.Reply, 0 ); + + AddItem( 370, 70, 0x1B7F ); + AddButton( 390, 50, 0x845, 0x846, 0x1B7F, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Skeleton == null | m_Skeleton.Deleted ) + return; + + Mobile m = sender.Mobile; + + if ( info.ButtonID == 0x1A03 || info.ButtonID == 0x1A05 || info.ButtonID == 0x1A09 || + info.ButtonID == 0x1B1E || info.ButtonID == 0x1B7F ) + { + m.SendLocalizedMessage( 1049780 ); // Where would you like to place this decoration? + m.Target = new InternalTarget( m_Skeleton, info.ButtonID ); + } + } + } + + private class InternalTarget : Target + { + private HangingSkeletonDeed m_Skeleton; + private int m_ItemID; + + public InternalTarget( HangingSkeletonDeed banner, int itemID ) : base( -1, true, TargetFlags.None ) + { + m_Skeleton = banner; + m_ItemID = itemID; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Skeleton == null || m_Skeleton.Deleted ) + return; + + if ( m_Skeleton.IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsOwner( from ) ) + { + IPoint3D p = targeted as IPoint3D; + Map map = from.Map; + + if ( p == null || map == null ) + return; + + Point3D p3d = new Point3D( p ); + ItemData id = TileData.ItemTable[ m_ItemID & TileData.MaxItemValue ]; + + if ( map.CanFit( p3d, id.Height ) ) + { + house = BaseHouse.FindHouseAt( p3d, map, id.Height ); + + if ( house != null && house.IsOwner( from ) ) + { + bool north = BaseAddon.IsWall( p3d.X, p3d.Y - 1, p3d.Z, map ); + bool west = BaseAddon.IsWall( p3d.X - 1, p3d.Y, p3d.Z, map ); + + if ( north && west ) + { + from.CloseGump( typeof( FacingGump ) ); + from.SendGump( new FacingGump( m_Skeleton, m_ItemID, p3d, house ) ); + } + else if ( north || west ) + { + HangingSkeleton banner = null; + + if ( north ) + banner = new HangingSkeleton( m_ItemID ); + else if ( west ) + banner = new HangingSkeleton( GetWestItemID( m_ItemID ) ); + + house.Addons.Add( banner ); + + banner.IsRewardItem = m_Skeleton.IsRewardItem; + banner.MoveToWorld( p3d, map ); + + m_Skeleton.Delete(); + } + else + from.SendLocalizedMessage( 1042039 ); // The banner must be placed next to a wall. + } + else + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + else + from.SendLocalizedMessage( 500269 ); // You cannot build that there. + } + else + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + private class FacingGump : Gump + { + private HangingSkeletonDeed m_Skeleton; + private int m_ItemID; + private Point3D m_Location; + private BaseHouse m_House; + + private enum Buttons + { + Cancel, + South, + East + } + + public FacingGump( HangingSkeletonDeed banner, int itemID, Point3D location, BaseHouse house ) : base( 150, 50 ) + { + m_Skeleton = banner; + m_ItemID = itemID; + m_Location = location; + m_House = house; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddItem( 90, 30, GetWestItemID( itemID ) ); + AddItem( 180, 30, itemID ); + + AddButton( 50, 35, 0x868, 0x869, (int) Buttons.East, GumpButtonType.Reply, 0 ); + AddButton( 145, 35, 0x868, 0x869, (int) Buttons.South, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Skeleton == null || m_Skeleton.Deleted || m_House == null ) + return; + + HangingSkeleton banner = null; + + if ( info.ButtonID == (int) Buttons.East ) + banner = new HangingSkeleton( GetWestItemID( m_ItemID ) ); + if ( info.ButtonID == (int) Buttons.South ) + banner = new HangingSkeleton( m_ItemID ); + + if ( banner != null ) + { + m_House.Addons.Add( banner ); + + banner.IsRewardItem = m_Skeleton.IsRewardItem; + banner.MoveToWorld( m_Location, sender.Mobile.Map ); + + m_Skeleton.Delete(); + } + } + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/MiningCart.cs b/Scripts/Items/Special/Veteran Rewards/MiningCart.cs new file mode 100644 index 0000000..14c4bdd --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/MiningCart.cs @@ -0,0 +1,422 @@ +using System; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public enum MiningCartType + { + OreSouth = 100, + OreEast = 101, + GemSouth = 102, + GemEast = 103 + } + + public class MiningCart : BaseAddon, IRewardItem + { + public override BaseAddonDeed Deed + { + get + { + MiningCartDeed deed = new MiningCartDeed(); + deed.IsRewardItem = m_IsRewardItem; + deed.Gems = m_Gems; + deed.Ore = m_Ore; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; } + } + + private MiningCartType m_CartType; + + [CommandProperty( AccessLevel.GameMaster )] + public MiningCartType CartType + { + get{ return m_CartType; } + } + + private int m_Gems; + + [CommandProperty( AccessLevel.GameMaster )] + public int Gems + { + get{ return m_Gems; } + set{ m_Gems = value; } + } + + private int m_Ore; + + [CommandProperty( AccessLevel.GameMaster )] + public int Ore + { + get{ return m_Ore; } + set{ m_Ore = value; } + } + + private Timer m_Timer; + + [Constructable] + public MiningCart( MiningCartType type ) : base() + { + m_CartType = type; + + switch ( type ) + { + case MiningCartType.OreSouth: + AddComponent( new AddonComponent( 0x1A83 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1A82 ), 0, 1, 0 ); + AddComponent( new AddonComponent( 0x1A86 ), 0, -1, 0 ); + break; + case MiningCartType.OreEast: + AddComponent( new AddonComponent( 0x1A88 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x1A87 ), 1, 0, 0 ); + AddComponent( new AddonComponent( 0x1A8B ), -1, 0, 0 ); + break; + case MiningCartType.GemSouth: + AddComponent( new LocalizedAddonComponent( 0x1A83, 1080388 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1A82, 1080388 ), 0, 1, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1A86, 1080388 ), 0, -1, 0 ); + + AddComponent( new AddonComponent( 0xF2C ), 0, 0, 6 ); + AddComponent( new AddonComponent( 0xF1D ), 0, 0, 5 ); + AddComponent( new AddonComponent( 0xF2B ), 0, 0, 2 ); + AddComponent( new AddonComponent( 0xF21 ), 0, 0, 1 ); + AddComponent( new AddonComponent( 0xF22 ), 0, 0, 4 ); + AddComponent( new AddonComponent( 0xF2F ), 0, 0, 5 ); + AddComponent( new AddonComponent( 0xF26 ), 0, 0, 6 ); + AddComponent( new AddonComponent( 0xF27 ), 0, 0, 3 ); + AddComponent( new AddonComponent( 0xF29 ), 0, 0, 0 ); + break; + case MiningCartType.GemEast: + AddComponent( new LocalizedAddonComponent( 0x1A88, 1080388 ), 0, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1A87, 1080388 ), 1, 0, 0 ); + AddComponent( new LocalizedAddonComponent( 0x1A8B, 1080388 ), -1, 0, 0 ); + + AddComponent( new AddonComponent( 0xF2E ), 0, 0, 6 ); + AddComponent( new AddonComponent( 0xF12 ), 0, 0, 3 ); + AddComponent( new AddonComponent( 0xF29 ), 0, 0, 1 ); + AddComponent( new AddonComponent( 0xF24 ), 0, 0, 5 ); + AddComponent( new AddonComponent( 0xF21 ), 0, 0, 1 ); + AddComponent( new AddonComponent( 0xF2B ), 0, 0, 3 ); + AddComponent( new AddonComponent( 0xF2F ), 0, 0, 4 ); + AddComponent( new AddonComponent( 0xF23 ), 0, 0, 3 ); + AddComponent( new AddonComponent( 0xF27 ), 0, 0, 3 ); + break; + } + + m_Timer = Timer.DelayCall( TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 1 ), new TimerCallback( GiveResources ) ); + } + + public MiningCart( Serial serial ) : base( serial ) + { + } + + private void GiveResources() + { + switch ( m_CartType ) + { + case MiningCartType.OreSouth: + case MiningCartType.OreEast: + m_Ore = Math.Min( 100, m_Ore + 10 ); + break; + case MiningCartType.GemSouth: + case MiningCartType.GemEast: + m_Gems = Math.Min( 50, m_Gems + 5 ); + break; + } + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + /* + * Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts + * due to the fact that they have only a miniscule fraction of the number of 10 year vets that a + * typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem), + * and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid) + * accounts not gaining veteran time. + * + * The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking + * behavior of these things all but impossible, so either way its just an estimation. + * + * If youd like your shard's carts/stumps to work the way they did before, simply replace the check + * below with this line of code: + * + * if (!from.InRange(GetWorldLocation(), 2) + * + * However, I am sure these checks are more accurate to OSI than the former version was. + * + */ + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !((from.Z - Z) > -3 && (from.Z - Z) < 3)) + { + from.LocalOverheadMessage(Network.MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + else if ( house != null && house.HasSecureAccess( from, SecureLevel.Friends ) ) + { + switch ( m_CartType ) + { + case MiningCartType.OreSouth: + case MiningCartType.OreEast: + if ( m_Ore > 0 ) + { + Item ingots = null; + + switch ( Utility.Random( 9 ) ) + { + case 0: ingots = new IronIngot(); break; + case 1: ingots = new DullcopperIngot(); break; + case 2: ingots = new ShadowIngot(); break; + case 3: ingots = new CopperIngot(); break; + case 4: ingots = new BronzeIngot(); break; + case 5: ingots = new GoldIngot(); break; + case 6: ingots = new AgapiteIngot(); break; + case 7: ingots = new VeriteIngot(); break; + case 8: ingots = new ValoriteIngot(); break; + } + + int amount = Math.Min( 10, m_Ore ); + ingots.Amount = amount; + + if ( !from.PlaceInBackpack( ingots ) ) + { + ingots.Delete(); + from.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + { + PublicOverheadMessage(MessageType.Regular, 0, 1094724, amount.ToString() ); // Ore: ~1_COUNT~ + m_Ore -= amount; + } + } + else + from.SendLocalizedMessage( 1094725 ); // There are no more resources available at this time. + + break; + case MiningCartType.GemSouth: + case MiningCartType.GemEast: + if ( m_Gems > 0 ) + { + Item gems = null; + + switch ( Utility.Random( 15 ) ) + { + case 0: gems = new Amber(); break; + case 1: gems = new Amethyst(); break; + case 2: gems = new Citrine(); break; + case 3: gems = new Diamond(); break; + case 4: gems = new Emerald(); break; + case 5: gems = new Ruby(); break; + case 6: gems = new Sapphire(); break; + case 7: gems = new StarSapphire(); break; + case 8: gems = new Tourmaline(); break; + + // Mondain's Legacy gems + case 9: gems = new PerfectEmerald(); break; + case 10: gems = new DarkSapphire(); break; + case 11: gems = new Turquoise(); break; + case 12: gems = new EcruCitrine(); break; + case 13: gems = new FireRuby(); break; + case 14: gems = new BlueDiamond(); break; + } + + int amount = Math.Min( 5, m_Gems ); + gems.Amount = amount; + + if ( !from.PlaceInBackpack( gems ) ) + { + gems.Delete(); + from.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + { + PublicOverheadMessage( MessageType.Regular, 0, 1094723, amount.ToString() ); // Gems: ~1_COUNT~ + m_Gems -= amount; + } + } + else + from.SendLocalizedMessage( 1094725 ); // There are no more resources available at this time. + + break; + } + } + else + from.SendLocalizedMessage( 1061637 ); // You are not allowed to access this. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + + #region version 1 + writer.Write( (int) m_CartType ); + #endregion + + writer.Write( (bool) m_IsRewardItem ); + writer.Write( (int) m_Gems ); + writer.Write( (int) m_Ore ); + + if ( m_Timer != null ) + writer.Write( (DateTime) m_Timer.Next ); + else + writer.Write( (DateTime) DateTime.Now + TimeSpan.FromDays( 1 ) ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + m_CartType = (MiningCartType) reader.ReadInt(); + goto case 0; + case 0: + m_IsRewardItem = reader.ReadBool(); + m_Gems = reader.ReadInt(); + m_Ore = reader.ReadInt(); + + DateTime next = reader.ReadDateTime(); + + if ( next < DateTime.Now ) + next = DateTime.Now; + + m_Timer = Timer.DelayCall( next - DateTime.Now, TimeSpan.FromDays( 1 ), new TimerCallback( GiveResources ) ); + break; + } + } + } + + public class MiningCartDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + public override int LabelNumber{ get{ return 1080385; } } // deed for a mining cart decoration + + public override BaseAddon Addon + { + get + { + MiningCart addon = new MiningCart( m_CartType ); + addon.IsRewardItem = m_IsRewardItem; + addon.Gems = m_Gems; + addon.Ore = m_Ore; + + return addon; + } + } + + private MiningCartType m_CartType; + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + private int m_Gems; + + [CommandProperty( AccessLevel.GameMaster )] + public int Gems + { + get{ return m_Gems; } + set{ m_Gems = value; } + } + + private int m_Ore; + + [CommandProperty( AccessLevel.GameMaster )] + public int Ore + { + get{ return m_Ore; } + set{ m_Ore = value; } + } + + [Constructable] + public MiningCartDeed() : base() + { + LootType = LootType.Blessed; + } + + public MiningCartDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1080457 ); // 10th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( RewardOptionGump ) ); + from.SendGump( new RewardOptionGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + writer.Write( (int) m_Gems ); + writer.Write( (int) m_Ore ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Gems = reader.ReadInt(); + m_Ore = reader.ReadInt(); + } + + public void GetOptions( RewardOptionList list ) + { + list.Add( (int) MiningCartType.OreSouth, 1080391 ); + list.Add( (int) MiningCartType.OreEast, 1080390 ); + list.Add( (int) MiningCartType.GemSouth, 1080500 ); + list.Add( (int) MiningCartType.GemEast, 1080499 ); + } + + public void OnOptionSelected( Mobile from, int choice ) + { + m_CartType = (MiningCartType) choice; + + if ( !Deleted ) + base.OnDoubleClick( from ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Veteran Rewards/MinotaurStatue.cs b/Scripts/Items/Special/Veteran Rewards/MinotaurStatue.cs new file mode 100644 index 0000000..37eaffb --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/MinotaurStatue.cs @@ -0,0 +1,180 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public enum MinotaurStatueType + { + AttackSouth = 100, + AttackEast = 101, + DefendSouth = 102, + DefendEast = 103 + } + + public class MinotaurStatue : BaseAddon, IRewardItem + { + public override BaseAddonDeed Deed + { + get + { + MinotaurStatueDeed deed = new MinotaurStatueDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public MinotaurStatue( MinotaurStatueType type ) : base() + { + switch ( type ) + { + case MinotaurStatueType.AttackSouth: + AddComponent( new AddonComponent( 0x306C ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x306D ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x306E ), 0, -1, 0 ); + break; + case MinotaurStatueType.AttackEast: + AddComponent( new AddonComponent( 0x3074 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3075 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x3076 ), 0, -1, 0 ); + break; + case MinotaurStatueType.DefendSouth: + AddComponent( new AddonComponent( 0x3072 ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3073 ), 0, -1, 0 ); + break; + case MinotaurStatueType.DefendEast: + AddComponent( new AddonComponent( 0x306F ), 0, 0, 0 ); + AddComponent( new AddonComponent( 0x3070 ), -1, 0, 0 ); + AddComponent( new AddonComponent( 0x3071 ), 0, -1, 0 ); + break; + } + } + + public MinotaurStatue( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class MinotaurStatueDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + public override int LabelNumber{ get{ return 1080409; } } // Minotaur Statue Deed + + public override BaseAddon Addon + { + get + { + MinotaurStatue addon = new MinotaurStatue( m_StatueType ); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + private MinotaurStatueType m_StatueType; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public MinotaurStatueDeed() : base() + { + LootType = LootType.Blessed; + } + + public MinotaurStatueDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( RewardOptionGump ) ); + from.SendGump( new RewardOptionGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076218 ); // 2nd Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + public void GetOptions( RewardOptionList list ) + { + list.Add( (int) MinotaurStatueType.AttackSouth, 1080410 ); // Minotaur Attack South + list.Add( (int) MinotaurStatueType.AttackEast, 1080411 ); // Minotaur Attack East + list.Add( (int) MinotaurStatueType.DefendSouth, 1080412 ); // Minotaur Defend South + list.Add( (int) MinotaurStatueType.DefendEast, 1080413 ); // Minotaur Defend East + } + + public void OnOptionSelected( Mobile from, int option ) + { + m_StatueType = (MinotaurStatueType) option; + + if ( !Deleted ) + base.OnDoubleClick( from ); + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/PottedCactus.cs b/Scripts/Items/Special/Veteran Rewards/PottedCactus.cs new file mode 100644 index 0000000..2c8e96f --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/PottedCactus.cs @@ -0,0 +1,188 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class RewardPottedCactus : Item, IRewardItem + { + public override bool ForceShowProperties{ get { return ObjectPropertyList.Enabled; } } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public RewardPottedCactus() : this( Utility.RandomMinMax( 0x1E0F, 0x1E14 ) ) + { + } + + [Constructable] + public RewardPottedCactus( int itemID ) : base( itemID ) + { + Weight = 5.0; + } + + public RewardPottedCactus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + switch ( version ) + { + case 1: + m_IsRewardItem = reader.ReadBool(); + break; + } + + } + } + + public class PottedCactusDeed : Item, IRewardItem + { + public override int LabelNumber{ get{ return 1080407; } } // Potted Cactus Deed + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public PottedCactusDeed() : base( 0x14F0 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + } + + public PottedCactusDeed( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076219 ); // 3rd Year Veteran Reward + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private PottedCactusDeed m_Cactus; + + public InternalGump( PottedCactusDeed cactus ) : base( 100, 200 ) + { + m_Cactus = cactus; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + AddBackground( 0, 0, 425, 250, 0xA28 ); + + AddPage( 1 ); + AddLabel( 45, 15, 0, "Choose a Potted Cactus:" ); + + AddItem( 45, 75, 0x1E0F ); + AddButton( 55, 50, 0x845, 0x846, 0x1E0F, GumpButtonType.Reply, 0 ); + + AddItem( 105, 75, 0x1E10 ); + AddButton( 115, 50, 0x845, 0x846, 0x1E10, GumpButtonType.Reply, 0 ); + + AddItem( 160, 75, 0x1E14 ); + AddButton( 175, 50, 0x845, 0x846, 0x1E14, GumpButtonType.Reply, 0 ); + + AddItem( 220, 75, 0x1E11 ); + AddButton( 235, 50, 0x845, 0x846, 0x1E11, GumpButtonType.Reply, 0 ); + + AddItem( 280, 75, 0x1E12 ); + AddButton( 295, 50, 0x845, 0x846, 0x1E12, GumpButtonType.Reply, 0 ); + + AddItem( 340, 75, 0x1E13 ); + AddButton( 355, 50, 0x845, 0x846, 0x1E13, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Cactus == null | m_Cactus.Deleted ) + return; + + Mobile m = sender.Mobile; + + if ( info.ButtonID >= 0x1E0F && info.ButtonID <= 0x1E14 ) + { + RewardPottedCactus cactus = new RewardPottedCactus( info.ButtonID ); + cactus.IsRewardItem = m_Cactus.IsRewardItem; + + if ( !m.PlaceInBackpack( cactus ) ) + { + cactus.Delete(); + m.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + m_Cactus.Delete(); + } + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/StoneAnkh.cs b/Scripts/Items/Special/Veteran Rewards/StoneAnkh.cs new file mode 100644 index 0000000..d949906 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/StoneAnkh.cs @@ -0,0 +1,277 @@ +using System; +using Server; +using Server.Multis; +using Server.Gumps; +using Server.Network; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class StoneAnkhComponent : AddonComponent + { + public override bool ForceShowProperties { get { return ObjectPropertyList.Enabled; } } + + public StoneAnkhComponent(int itemID) + : base(itemID) + { + Weight = 1.0; + } + + public StoneAnkhComponent(Serial serial) + : base(serial) + { + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Addon is StoneAnkh && ((StoneAnkh)Addon).IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class StoneAnkh : BaseAddon, IRewardItem + { + public override BaseAddonDeed Deed + { + get + { + StoneAnkhDeed deed = new StoneAnkhDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public StoneAnkh() + : this(true) + { + } + + [Constructable] + public StoneAnkh(bool east) + : base() + { + if (east) + { + AddComponent(new StoneAnkhComponent(0x2), 0, 0, 0); + AddComponent(new StoneAnkhComponent(0x3), 0, -1, 0); + } + else + { + AddComponent(new StoneAnkhComponent(0x5), 0, 0, 0); + AddComponent(new StoneAnkhComponent(0x4), -1, 0, 0); + } + } + + public StoneAnkh(Serial serial) + : base(serial) + { + } + + public override void OnChop(Mobile from) + { + from.SendLocalizedMessage(500489); // You can't use an axe on that. + return; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Core.ML && m_IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void OnComponentUsed(AddonComponent c, Mobile from) + { + if (from.InRange(Location, 2)) + { + BaseHouse house = BaseHouse.FindHouseAt(this); + + if (house != null && house.IsOwner(from)) + { + from.CloseGump(typeof(RewardDemolitionGump)); + from.SendGump(new RewardDemolitionGump(this, 1049783)); // Do you wish to re-deed this decoration? + } + else + from.SendLocalizedMessage(1049784); // You can only re-deed this decoration if you are the house owner or originally placed the decoration. + } + else + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write((bool)m_IsRewardItem); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + } + + public class StoneAnkhDeed : BaseAddonDeed, IRewardItem + { + public override int LabelNumber { get { return 1049773; } } // deed for a stone ankh + + private bool m_East; + private bool m_IsRewardItem; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; InvalidateProperties(); } + } + + public override BaseAddon Addon + { + get + { + StoneAnkh addon = new StoneAnkh(m_East); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + [Constructable] + public StoneAnkhDeed() + : base() + { + LootType = LootType.Blessed; + } + + public StoneAnkhDeed(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this, null)) + return; + + if (IsChildOf(from.Backpack)) + { + from.CloseGump(typeof(InternalGump)); + from.SendGump(new InternalGump(this)); + } + else + from.SendLocalizedMessage(1042038); // You must have the object in your backpack to use it. + } + + private void SendTarget(Mobile m) + { + base.OnDoubleClick(m); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsRewardItem) + list.Add(1076221); // 5th Year Veteran Reward + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + + writer.Write((bool)m_IsRewardItem); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private StoneAnkhDeed m_Deed; + + private enum Buttons + { + Cancel, + South, + East + } + + public InternalGump(StoneAnkhDeed deed) + : base(150, 50) + { + m_Deed = deed; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage(0); + + AddBackground(0, 0, 300, 150, 0xA28); + + AddItem(90, 30, 0x4); + AddItem(112, 30, 0x5); + AddButton(50, 35, 0x867, 0x869, (int)Buttons.South, GumpButtonType.Reply, 0); // South + + AddItem(170, 30, 0x2); + AddItem(192, 30, 0x3); + AddButton(145, 35, 0x867, 0x869, (int)Buttons.East, GumpButtonType.Reply, 0); // East + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_Deed == null || m_Deed.Deleted) + return; + + if (info.ButtonID != (int)Buttons.Cancel) + { + m_Deed.m_East = (info.ButtonID == (int)Buttons.East); + m_Deed.SendTarget(sender.Mobile); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Veteran Rewards/TreeStump.cs b/Scripts/Items/Special/Veteran Rewards/TreeStump.cs new file mode 100644 index 0000000..2883eef --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/TreeStump.cs @@ -0,0 +1,267 @@ +using System; +using Server.Engines.VeteranRewards; +using Server.Gumps; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class TreeStump : BaseAddon, IRewardItem + { + public override BaseAddonDeed Deed + { + get + { + TreeStumpDeed deed = new TreeStumpDeed(); + deed.IsRewardItem = m_IsRewardItem; + deed.Logs = m_Logs; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + private int m_Logs; + + [CommandProperty( AccessLevel.GameMaster )] + public int Logs + { + get{ return m_Logs; } + set{ m_Logs = value; InvalidateProperties(); } + } + + private Timer m_Timer; + + [Constructable] + public TreeStump( int itemID ) : base() + { + AddComponent( new AddonComponent( itemID ), 0, 0, 0 ); + + m_Timer = Timer.DelayCall( TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 1 ), new TimerCallback( GiveLogs ) ); + } + + public TreeStump( Serial serial ) : base( serial ) + { + } + + private void GiveLogs() + { + m_Logs = Math.Min( 100, m_Logs + 10 ); + } + + public override void OnComponentUsed( AddonComponent c, Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + /* + * Unique problems have unique solutions. OSI does not have a problem with 1000s of mining carts + * due to the fact that they have only a miniscule fraction of the number of 10 year vets that a + * typical RunUO shard will have (RunUO's scaled down account aging system makes this a unique problem), + * and the "freeness" of free accounts. We also dont have mitigating factors like inactive (unpaid) + * accounts not gaining veteran time. + * + * The lack of high end vets and vet rewards on OSI has made testing the *exact* ranging/stacking + * behavior of these things all but impossible, so either way its just an estimation. + * + * If youd like your shard's carts/stumps to work the way they did before, simply replace the check + * below with this line of code: + * + * if (!from.InRange(GetWorldLocation(), 2) + * + * However, I am sure these checks are more accurate to OSI than the former version was. + * + */ + + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this) || !((from.Z - Z) > -3 && (from.Z - Z) < 3)) + { + from.LocalOverheadMessage(Network.MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + } + else if ( house != null && house.HasSecureAccess( from, SecureLevel.Friends ) ) + { + if ( m_Logs > 0 ) + { + Item logs = null; + + switch ( Utility.Random( 7 ) ) + { + case 0: logs = new Log(); break; + case 1: logs = new AshLog(); break; + case 2: logs = new OakLog(); break; + case 3: logs = new YewLog(); break; + case 4: logs = new HeartwoodLog(); break; + case 5: logs = new BloodwoodLog(); break; + case 6: logs = new FrostwoodLog(); break; + } + + int amount = Math.Min( 10, m_Logs ); + logs.Amount = amount; + + if ( !from.PlaceInBackpack( logs ) ) + { + logs.Delete(); + from.SendLocalizedMessage( 1078837 ); // Your backpack is full! Please make room and try again. + } + else + { + m_Logs -= amount; + PublicOverheadMessage( MessageType.Regular, 0, 1094719, m_Logs.ToString() ); // Logs: ~1_COUNT~ + } + } + else + from.SendLocalizedMessage( 1094720 ); // There are no more logs available. + } + else + from.SendLocalizedMessage( 1061637 ); // You are not allowed to access this. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + writer.Write( (int) m_Logs ); + + if ( m_Timer != null ) + writer.Write( (DateTime) m_Timer.Next ); + else + writer.Write( (DateTime) DateTime.Now + TimeSpan.FromDays( 1 ) ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Logs = reader.ReadInt(); + + DateTime next = reader.ReadDateTime(); + + if ( next < DateTime.Now ) + next = DateTime.Now; + + m_Timer = Timer.DelayCall( next - DateTime.Now, TimeSpan.FromDays( 1 ), new TimerCallback( GiveLogs ) ); + } + } + + public class TreeStumpDeed : BaseAddonDeed, IRewardItem, IRewardOption + { + public override int LabelNumber{ get{ return 1080406; } } // a deed for a tree stump decoration + + public override BaseAddon Addon + { + get + { + TreeStump addon = new TreeStump( m_ItemID ); + addon.IsRewardItem = m_IsRewardItem; + addon.Logs = m_Logs; + + return addon; + } + } + + private int m_ItemID; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + private int m_Logs; + + [CommandProperty( AccessLevel.GameMaster )] + public int Logs + { + get{ return m_Logs; } + set{ m_Logs = value; InvalidateProperties(); } + } + + [Constructable] + public TreeStumpDeed() : base() + { + LootType = LootType.Blessed; + } + + public TreeStumpDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076223 ); // 7th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( RewardOptionGump ) ); + from.SendGump( new RewardOptionGump( this ) ); + } + else + from.SendLocalizedMessage( 1062334 ); // This item must be in your backpack to be used. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + writer.Write( (int) m_Logs ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + m_Logs = reader.ReadInt(); + } + + public void GetOptions( RewardOptionList list ) + { + list.Add( 1, 1080403 ); // Tree Stump with Axe West + list.Add( 2, 1080404 ); // Tree Stump with Axe North + list.Add( 3, 1080401 ); // Tree Stump East + list.Add( 4, 1080402 ); // Tree Stump South + } + + public void OnOptionSelected( Mobile from, int option ) + { + switch ( option ) + { + case 1: m_ItemID = 0xE56; break; + case 2: m_ItemID = 0xE58; break; + case 3: m_ItemID = 0xE57; break; + case 4: m_ItemID = 0xE59; break; + } + + if ( !Deleted ) + base.OnDoubleClick( from ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Special/Veteran Rewards/WallBanner.cs b/Scripts/Items/Special/Veteran Rewards/WallBanner.cs new file mode 100644 index 0000000..d0aac9c --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/WallBanner.cs @@ -0,0 +1,500 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class WallBannerComponent : AddonComponent, IDyable + { + public override bool NeedsWall{ get{ return true; } } + public override Point3D WallPosition{ get{ return this.East ? new Point3D( -1, 0, 0 ) : new Point3D( 0, -1, 0 ); } } + + public bool East{ get { return ((WallBanner)Addon).East; } } + + public WallBannerComponent( int itemID ) : base( itemID ) + { + } + + public WallBannerComponent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + public bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + if ( Addon != null ) + Addon.Hue = sender.DyedHue; + + return true; + } + } + + public class WallBanner : BaseAddon, IRewardItem + { + public override BaseAddonDeed Deed + { + get + { + WallBannerDeed deed = new WallBannerDeed(); + deed.IsRewardItem = m_IsRewardItem; + + return deed; + } + } + + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + private bool m_East; + + [CommandProperty( AccessLevel.GameMaster )] + public bool East + { + get{ return m_East; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public WallBanner( int bannerID ) : base() + { + m_East = ((bannerID % 2) == 1 ); + + switch ( bannerID ) + { + case 1: + AddComponent( new WallBannerComponent( 0x161F ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x161E ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x161D ), 0, 2, 0 ); + break; + case 2: + AddComponent( new WallBannerComponent( 0x1586 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1587 ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1588 ), 2, 0, 0 ); + break; + case 3: + AddComponent( new WallBannerComponent( 0x1622 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1621 ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x1620 ), 0, 2, 0 ); + break; + case 4: + AddComponent( new WallBannerComponent( 0x1589 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x158A ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x158B ), 2, 0, 0 ); + break; + case 5: + AddComponent( new WallBannerComponent( 0x1625 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1624 ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x1623 ), 0, 2, 0 ); + break; + case 6: + AddComponent( new WallBannerComponent( 0x158C ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x158D ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x158E ), 2, 0, 0 ); + break; + case 7: + AddComponent( new WallBannerComponent( 0x1628 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1627 ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x1626 ), 0, 2, 0 ); + break; + case 8: + AddComponent( new WallBannerComponent( 0x1590 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1591 ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x158F ), 2, 0, 0 ); + break; + case 9: + AddComponent( new WallBannerComponent( 0x162A ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1629 ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x1626 ), 0, 2, 0 ); + break; + case 10: + AddComponent( new WallBannerComponent( 0x1592 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1593 ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x158F ), 2, 0, 0 ); + break; + case 11: + AddComponent( new WallBannerComponent( 0x162D ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x162C ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x162B ), 0, 2, 0 ); + break; + case 12: + AddComponent( new WallBannerComponent( 0x1594 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1595 ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1596 ), 2, 0, 0 ); + break; + case 13: + AddComponent( new WallBannerComponent( 0x1632 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1631 ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x162E ), 0, 2, 0 ); + break; + case 14: + AddComponent( new WallBannerComponent( 0x1598 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x159B ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x159C ), 2, 0, 0 ); + break; + case 15: + AddComponent( new WallBannerComponent( 0x1633 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1630 ), 0, 1, 0 ); + AddComponent( new WallBannerComponent( 0x162F ), 0, 2, 0 ); + break; + case 16: + AddComponent( new WallBannerComponent( 0x1599 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x159A ), 1, 0, 0 ); + AddComponent( new WallBannerComponent( 0x159D ), 2, 0, 0 ); + break; + + + case 17: + AddComponent( new WallBannerComponent( 0x1610 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x160F ), 0, 1, 0 ); + break; + case 18: + AddComponent( new WallBannerComponent( 0x15A0 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15A1 ), 1, 0, 0 ); + break; + + case 19: + AddComponent( new WallBannerComponent( 0x1612 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1611 ), 0, 1, 0 ); + break; + case 20: + AddComponent( new WallBannerComponent( 0x15A2 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15A3 ), 1, 0, 0 ); + break; + + case 21: + AddComponent( new WallBannerComponent( 0x1614 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1613 ), 0, 1, 0 ); + break; + case 22: + AddComponent( new WallBannerComponent( 0x15A4 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15A5 ), 1, 0, 0 ); + break; + + case 23: + AddComponent( new WallBannerComponent( 0x1616 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1615 ), 0, 1, 0 ); + break; + case 24: + AddComponent( new WallBannerComponent( 0x15A6 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15A7 ), 1, 0, 0 ); + break; + + case 25: + AddComponent( new WallBannerComponent( 0x1618 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1617 ), 0, 1, 0 ); + break; + case 26: + AddComponent( new WallBannerComponent( 0x15A8 ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15A9 ), 1, 0, 0 ); + break; + + case 27: + AddComponent( new WallBannerComponent( 0x161A ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x1619 ), 0, 1, 0 ); + break; + case 28: + AddComponent( new WallBannerComponent( 0x15AA ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15AB ), 1, 0, 0 ); + break; + + case 29: + AddComponent( new WallBannerComponent( 0x161C ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x161B ), 0, 1, 0 ); + break; + case 30: + AddComponent( new WallBannerComponent( 0x15AC ), 0, 0, 0 ); + AddComponent( new WallBannerComponent( 0x15AD ), 1, 0, 0 ); + break; + } + } + + public WallBanner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_East ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_East = reader.ReadBool(); + m_IsRewardItem = reader.ReadBool(); + } + } + + public class WallBannerDeed : BaseAddonDeed, IRewardItem + { + public override int LabelNumber{ get{ return 1080549; } } // Wall Banner Deed + + public override BaseAddon Addon + { + get + { + WallBanner addon = new WallBanner( m_BannerID ); + addon.IsRewardItem = m_IsRewardItem; + + return addon; + } + } + + private int m_BannerID; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public WallBannerDeed() : base() + { + LootType = LootType.Blessed; + } + + public WallBannerDeed( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076225 ); // 9th Year Veteran Reward + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( IsChildOf( from.Backpack ) ) + { + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( this ) ); + } + else + from.SendLocalizedMessage( 1042038 ); // You must have the object in your backpack to use it. + } + + public void Use( Mobile m, int bannerID ) + { + m_BannerID = bannerID; + + base.OnDoubleClick( m ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_IsRewardItem = reader.ReadBool(); + } + + private class InternalGump : Gump + { + private WallBannerDeed m_WallBanner; + + public InternalGump( WallBannerDeed WallBanner ) : base( 150, 50 ) + { + m_WallBanner = WallBanner; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddBackground( 25, 0, 500, 265, 0xA28 ); + AddLabel( 70, 12, 0x3E3, "Choose a Wall Banner:" ); + + AddPage( 1 ); + + AddItem( 55, 110, 0x161D ); + AddItem( 75, 90, 0x161E ); + AddItem( 95, 70, 0x161F ); + AddButton( 70, 50, 0x845, 0x846, 1, GumpButtonType.Reply, 0 ); + AddItem( 105, 70, 0x1586 ); + AddItem( 125, 90, 0x1587 ); + AddItem( 145, 110, 0x1588 ); + AddButton( 145, 50, 0x845, 0x846, 2, GumpButtonType.Reply, 0 ); + AddItem( 200, 110, 0x1620 ); + AddItem( 220, 90, 0x1621 ); + AddItem( 240, 70, 0x1622 ); + AddButton( 220, 50, 0x845, 0x846, 3, GumpButtonType.Reply, 0 ); + AddItem( 250, 70, 0x1589 ); + AddItem( 270, 90, 0x158A ); + AddItem( 290, 110, 0x158B ); + AddButton( 300, 50, 0x845, 0x846, 4, GumpButtonType.Reply, 0 ); + AddItem( 350, 110, 0x1623 ); + AddItem( 370, 90, 0x1624 ); + AddItem( 390, 70, 0x1625 ); + AddButton( 365, 50, 0x845, 0x846, 5, GumpButtonType.Reply, 0 ); + AddItem( 400, 70, 0x158C ); + AddItem( 420, 90, 0x158D ); + AddItem( 440, 110, 0x158E ); + AddButton( 445, 50, 0x845, 0x846, 6, GumpButtonType.Reply, 0 ); + AddButton( 455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 2 ); + + AddPage( 2 ); + + AddItem( 52, 110, 0x1626 ); + AddItem( 72, 90, 0x1627 ); + AddItem( 95, 70, 0x1628 ); + AddButton( 70, 50, 0x845, 0x846, 7, GumpButtonType.Reply, 0 ); + AddItem( 105, 70, 0x1590 ); + AddItem( 125, 90, 0x1591 ); + AddItem( 145, 110, 0x158F ); + AddButton( 145, 50, 0x845, 0x846, 8, GumpButtonType.Reply, 0 ); + AddItem( 197, 110, 0x1626 ); + AddItem( 217, 90, 0x1629 ); + AddItem( 240, 70, 0x162A ); + AddButton( 220, 50, 0x845, 0x846, 9, GumpButtonType.Reply, 0 ); + AddItem( 250, 70, 0x1592 ); + AddItem( 270, 90, 0x1593 ); + AddItem( 290, 110, 0x158F ); + AddButton( 300, 50, 0x845, 0x846, 10, GumpButtonType.Reply, 0 ); + AddItem( 340, 110, 0x162B ); + AddItem( 363, 90, 0x162C ); + AddItem( 385, 70, 0x162D ); + AddButton( 365, 50, 0x845, 0x846, 11, GumpButtonType.Reply, 0 ); + AddItem( 395, 70, 0x1594 ); + AddItem( 417, 90, 0x1595 ); + AddItem( 439, 111, 0x1596 ); + AddButton( 445, 50, 0x845, 0x846, 12, GumpButtonType.Reply, 0 ); + AddButton( 70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 1 ); + AddButton( 455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 3 ); + + AddPage( 3 ); + + AddItem( 55, 110, 0x162E ); + AddItem( 75, 93, 0x1631 ); + AddItem( 95, 70, 0x1632 ); + AddButton( 70, 50, 0x845, 0x846, 13, GumpButtonType.Reply, 0 ); + AddItem( 118, 70, 0x1598 ); + AddItem( 138, 94, 0x159B ); + AddItem( 159, 113, 0x159C ); + AddButton( 160, 50, 0x845, 0x846, 14, GumpButtonType.Reply, 0 ); + AddItem( 219, 111, 0x162F ); + AddItem( 238, 94, 0x1630 ); + AddItem( 258, 70, 0x1633 ); + AddButton( 240, 50, 0x845, 0x846, 15, GumpButtonType.Reply, 0 ); + AddItem( 279, 70, 0x1599 ); + AddItem( 298, 93, 0x159A ); + AddItem( 319, 113, 0x159D ); + AddButton( 320, 50, 0x845, 0x846, 16, GumpButtonType.Reply, 0 ); + AddItem( 380, 90, 0x160F ); + AddItem( 400, 70, 0x1610 ); + AddButton( 390, 50, 0x845, 0x846, 17, GumpButtonType.Reply, 0 ); + AddItem( 420, 70, 0x15A0 ); + AddItem( 440, 90, 0x15A1 ); + AddButton( 455, 50, 0x845, 0x846, 18, GumpButtonType.Reply, 0 ); + AddButton( 70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 2 ); + AddButton( 455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 4 ); + + AddPage( 4 ); + + AddItem( 55, 90, 0x1611 ); + AddItem( 75, 70, 0x1612 ); + AddButton( 70, 50, 0x845, 0x846, 19, GumpButtonType.Reply, 0 ); + AddItem( 105, 70, 0x15A2 ); + AddItem( 125, 90, 0x15A3 ); + AddButton( 145, 50, 0x845, 0x846, 20, GumpButtonType.Reply, 0 ); + AddItem( 200, 84, 0x1613 ); + AddItem( 220, 70, 0x1614 ); + AddButton( 215, 50, 0x845, 0x846, 21, GumpButtonType.Reply, 0 ); + AddItem( 250, 70, 0x15A4 ); + AddItem( 270, 84, 0x15A5 ); + AddButton( 290, 50, 0x845, 0x846, 22, GumpButtonType.Reply, 0 ); + AddItem( 350, 90, 0x1615 ); + AddItem( 370, 70, 0x1616 ); + AddButton( 365, 50, 0x845, 0x846, 23, GumpButtonType.Reply, 0 ); + AddItem( 400, 70, 0x15A6 ); + AddItem( 420, 90, 0x15A7 ); + AddButton( 445, 50, 0x845, 0x846, 24, GumpButtonType.Reply, 0 ); + AddButton( 70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 3 ); + AddButton( 455, 205, 0x8B0, 0x8B0, 0, GumpButtonType.Page, 5 ); + + AddPage( 5 ); + + AddItem( 55, 90, 0x1617 ); + AddItem( 77, 70, 0x1618 ); + AddButton( 70, 50, 0x845, 0x846, 25, GumpButtonType.Reply, 0 ); + AddItem( 105, 70, 0x15A8 ); + AddItem( 127, 90, 0x15A9 ); + AddButton( 145, 50, 0x845, 0x846, 26, GumpButtonType.Reply, 0 ); + AddItem( 200, 90, 0x1619 ); + AddItem( 222, 70, 0x161A ); + AddButton( 220, 50, 0x845, 0x846, 27, GumpButtonType.Reply, 0 ); + AddItem( 250, 70, 0x15AA ); + AddItem( 272, 90, 0x15AB ); + AddButton( 300, 50, 0x845, 0x846, 28, GumpButtonType.Reply, 0 ); + AddItem( 350, 90, 0x161B ); + AddItem( 372, 70, 0x161C ); + AddButton( 365, 50, 0x845, 0x846, 29, GumpButtonType.Reply, 0 ); + AddItem( 400, 70, 0x15AC ); + AddItem( 422, 90, 0x15AD ); + AddButton( 445, 50, 0x845, 0x846, 30, GumpButtonType.Reply, 0 ); + AddButton( 70, 205, 0x8AF, 0x8AF, 0, GumpButtonType.Page, 4 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_WallBanner == null || m_WallBanner.Deleted ) + return; + + if ( info.ButtonID > 0 && info.ButtonID < 31 ) + m_WallBanner.Use( sender.Mobile, info.ButtonID ); + } + } + } +} diff --git a/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs b/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs new file mode 100644 index 0000000..d7049b6 --- /dev/null +++ b/Scripts/Items/Special/Veteran Rewards/WeaponEngravingTool.cs @@ -0,0 +1,330 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Gumps; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class WeaponEngravingTool : Item, IUsesRemaining, IRewardItem + { + public override int LabelNumber{ get{ return 1076158; } } // Weapon Engraving Tool + + private int m_UsesRemaining; + private bool m_IsRewardItem; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get{ return m_UsesRemaining; } + set{ m_UsesRemaining = value; InvalidateProperties(); } + } + + public virtual bool ShowUsesRemaining + { + get{ return true; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsRewardItem + { + get{ return m_IsRewardItem; } + set{ m_IsRewardItem = value; InvalidateProperties(); } + } + + [Constructable] + public WeaponEngravingTool() : this( 10 ) + { + } + + [Constructable] + public WeaponEngravingTool( int uses ) : base( 0x32F8 ) + { + LootType = LootType.Blessed; + Weight = 1.0; + + m_UsesRemaining = uses; + } + + public WeaponEngravingTool( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_IsRewardItem && !RewardSystem.CheckIsUsableBy( from, this, null ) ) + return; + + if ( m_UsesRemaining > 0 ) + { + from.SendLocalizedMessage( 1072357 ); // Select an object to engrave. + from.Target = new TargetWeapon( this ); + } + else + { + if ( from.Skills.Tinkering.Value == 0 ) + { + from.SendLocalizedMessage( 1076179 ); // Since you have no tinkering skill, you will need to find an NPC tinkerer to repair this for you. + } + else if ( from.Skills.Tinkering.Value < 75.0 ) + { + from.SendLocalizedMessage( 1076178 ); // Your tinkering skill is too low to fix this yourself. An NPC tinkerer can help you repair this for a fee. + } + else + { + Item diamond = from.Backpack.FindItemByType( typeof( BlueDiamond ) ); + + if ( diamond != null ) + from.SendGump( new ConfirmGump( this, null ) ); + else + from.SendLocalizedMessage( 1076166 ); // You do not have a blue diamond needed to recharge the engraving tool. + } + + from.SendLocalizedMessage( 1076163 ); // There are no charges left on this engraving tool. + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_IsRewardItem ) + list.Add( 1076224 ); // 8th Year Veteran Reward + + if ( ShowUsesRemaining ) + list.Add( 1060584, m_UsesRemaining.ToString() ); // uses remaining: ~1_val~ + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_UsesRemaining ); + writer.Write( (bool) m_IsRewardItem ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_UsesRemaining = reader.ReadInt(); + m_IsRewardItem = reader.ReadBool(); + } + + public virtual void Recharge( Mobile from, Mobile guildmaster ) + { + if ( from.Backpack != null ) + { + Item diamond = from.Backpack.FindItemByType( typeof( BlueDiamond ) ); + + if ( guildmaster != null ) + { + if ( m_UsesRemaining <= 0 ) + { + if ( diamond != null && Banker.Withdraw( from, 100000 ) ) + { + diamond.Consume(); + UsesRemaining = 10; + guildmaster.Say( 1076165 ); // Your weapon engraver should be good as new! + } + else + guildmaster.Say( 1076167 ); // You need a 100,000 gold and a blue diamond to recharge the weapon engraver. + } + else + guildmaster.Say( 1076164 ); // I can only help with this if you are carrying an engraving tool that needs repair. + } + else + { + if ( from.Skills.Tinkering.Value == 0 ) + { + from.SendLocalizedMessage( 1076179 ); // Since you have no tinkering skill, you will need to find an NPC tinkerer to repair this for you. + } + else if ( from.Skills.Tinkering.Value < 75.0 ) + { + from.SendLocalizedMessage( 1076178 ); // Your tinkering skill is too low to fix this yourself. An NPC tinkerer can help you repair this for a fee. + } + else if ( diamond != null ) + { + diamond.Consume(); + + if ( Utility.RandomDouble() < from.Skills.Tinkering.Value / 100 ) + { + UsesRemaining = 10; + from.SendLocalizedMessage( 1076165 ); // Your weapon engraver should be good as new! ????? + } + else + from.SendLocalizedMessage( 1076175 ); // You cracked the diamond attempting to fix the weapon engraver. + } + else + from.SendLocalizedMessage( 1076166 ); // You do not have a blue diamond needed to recharge the engraving tool. + } + } + } + + public static WeaponEngravingTool Find( Mobile from ) + { + if ( from.Backpack != null ) + return from.Backpack.FindItemByType( typeof( WeaponEngravingTool ) ) as WeaponEngravingTool; + + return null; + } + + private class TargetWeapon : Target + { + private WeaponEngravingTool m_Tool; + + public TargetWeapon( WeaponEngravingTool tool ) : base( -1, true, TargetFlags.None ) + { + m_Tool = tool; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Tool == null || m_Tool.Deleted ) + return; + + if ( targeted is BaseWeapon ) + { + BaseWeapon item = (BaseWeapon) targeted; + + from.CloseGump( typeof( InternalGump ) ); + from.SendGump( new InternalGump( m_Tool, item ) ); + } + else + from.SendLocalizedMessage( 1072309 ); // The selected item cannot be engraved by this engraving tool. + } + } + + private class InternalGump : Gump + { + private WeaponEngravingTool m_Tool; + private BaseWeapon m_Target; + + private enum Buttons + { + Cancel, + Okay, + Text + } + + public InternalGump( WeaponEngravingTool tool, BaseWeapon target ) : base( 0, 0 ) + { + m_Tool = tool; + m_Target = target; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddBackground( 50, 50, 400, 300, 0xA28 ); + + AddPage( 0 ); + + AddHtmlLocalized( 50, 70, 400, 20, 1072359, 0x0, false, false ); //
Engraving Tool
+ AddHtmlLocalized( 75, 95, 350, 145, 1076229, 0x0, true, true ); // Please enter the text to add to the selected object. Leave the text area blank to remove any existing text. Removing text does not use a charge. + AddButton( 125, 300, 0x81A, 0x81B, (int) Buttons.Okay, GumpButtonType.Reply, 0 ); + AddButton( 320, 300, 0x819, 0x818, (int) Buttons.Cancel, GumpButtonType.Reply, 0 ); + AddImageTiled( 75, 245, 350, 40, 0xDB0 ); + AddImageTiled( 76, 245, 350, 2, 0x23C5 ); + AddImageTiled( 75, 245, 2, 40, 0x23C3 ); + AddImageTiled( 75, 285, 350, 2, 0x23C5 ); + AddImageTiled( 425, 245, 2, 42, 0x23C3 ); + + AddTextEntry( 75, 245, 350, 40, 0x0, (int) Buttons.Text, "" ); + } + + public override void OnResponse( Server.Network.NetState state, RelayInfo info ) + { + if ( m_Tool == null || m_Tool.Deleted || m_Target == null || m_Target.Deleted ) + return; + + if ( info.ButtonID == (int) Buttons.Okay ) + { + TextRelay relay = info.GetTextEntry( (int) Buttons.Text ); + + if ( relay != null ) + { + if ( String.IsNullOrEmpty( relay.Text ) ) + { + m_Target.EngravedText = null; + state.Mobile.SendLocalizedMessage( 1072362 ); // You remove the engraving from the object. + } + else + { + if (relay.Text.Length > 64) + m_Target.EngravedText = Utility.FixHtml(relay.Text.Substring(0, 64)); + else + m_Target.EngravedText = Utility.FixHtml(relay.Text); + + state.Mobile.SendLocalizedMessage( 1072361 ); // You engraved the object. + m_Target.InvalidateProperties(); + m_Tool.UsesRemaining -= 1; + m_Tool.InvalidateProperties(); + } + } + } + else + state.Mobile.SendLocalizedMessage( 1072363 ); // The object was not engraved. + } + } + + public class ConfirmGump : Gump + { + private WeaponEngravingTool m_Engraver; + private Mobile m_Guildmaster; + + private enum Buttons + { + Cancel, + Confirm + } + + public ConfirmGump( WeaponEngravingTool engraver, Mobile guildmaster ) : base( 200, 200 ) + { + m_Engraver = engraver; + m_Guildmaster = guildmaster; + + Closable = false; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddBackground( 0, 0, 291, 133, 0x13BE ); + AddImageTiled( 5, 5, 280, 100, 0xA40 ); + + if ( guildmaster != null ) + { + AddHtmlLocalized( 9, 9, 272, 100, 1076169, 0x7FFF, false, false ); // It will cost you 100,000 gold and a blue diamond to recharge your weapon engraver with 10 charges. + AddHtmlLocalized( 195, 109, 120, 20, 1076172, 0x7FFF, false, false ); // Recharge it + } + else + { + AddHtmlLocalized( 9, 9, 272, 100, 1076176, 0x7FFF, false, false ); // You will need a blue diamond to repair the tip of the engraver. A successful repair will give the engraver 10 charges. + AddHtmlLocalized( 195, 109, 120, 20, 1076177, 0x7FFF, false, false ); // Replace the tip. + } + + AddButton( 160, 107, 0xFB7, 0xFB8, (int) Buttons.Confirm, GumpButtonType.Reply, 0 ); + AddButton( 5, 107, 0xFB1, 0xFB2, (int) Buttons.Cancel, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 40, 109, 100, 20, 1060051, 0x7FFF, false, false ); // CANCEL + } + + public override void OnResponse( Server.Network.NetState state, RelayInfo info ) + { + if ( m_Engraver == null || m_Engraver.Deleted ) + return; + + if ( info.ButtonID == (int) Buttons.Confirm ) + m_Engraver.Recharge( state.Mobile, m_Guildmaster ); + } + } + } +} diff --git a/Scripts/Items/Suits/AdminRobe.cs b/Scripts/Items/Suits/AdminRobe.cs new file mode 100644 index 0000000..bdc3573 --- /dev/null +++ b/Scripts/Items/Suits/AdminRobe.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AdminRobe : BaseSuit + { + [Constructable] + public AdminRobe() : base( AccessLevel.Administrator, 0x0, 0x204F ) // Blank hue + { + } + + public AdminRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/BaseSuit.cs b/Scripts/Items/Suits/BaseSuit.cs new file mode 100644 index 0000000..c76a4c9 --- /dev/null +++ b/Scripts/Items/Suits/BaseSuit.cs @@ -0,0 +1,91 @@ +using System; +using Server; + +namespace Server.Items +{ + public abstract class BaseSuit : Item + { + private AccessLevel m_AccessLevel; + + [CommandProperty( AccessLevel.Administrator )] + public AccessLevel AccessLevel{ get{ return m_AccessLevel; } set{ m_AccessLevel = value; } } + + public BaseSuit( AccessLevel level, int hue, int itemID ) : base( itemID ) + { + Hue = hue; + Weight = 1.0; + Movable = false; + LootType = LootType.Newbied; + Layer = Layer.OuterTorso; + + m_AccessLevel = level; + } + + public BaseSuit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_AccessLevel ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_AccessLevel = (AccessLevel)reader.ReadInt(); + break; + } + } + } + + public bool Validate() + { + object root = RootParent; + + if ( root is Mobile && ((Mobile)root).AccessLevel < m_AccessLevel ) + { + Delete(); + return false; + } + + return true; + } + + public override void OnSingleClick( Mobile from ) + { + if ( Validate() ) + base.OnSingleClick( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( Validate() ) + base.OnDoubleClick( from ); + } + + public override bool VerifyMove( Mobile from ) + { + return ( from.AccessLevel >= m_AccessLevel ); + } + + public override bool OnEquip( Mobile from ) + { + if ( from.AccessLevel < m_AccessLevel ) + from.SendMessage( "You may not wear this." ); + + return ( from.AccessLevel >= m_AccessLevel ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/CounselorRobe.cs b/Scripts/Items/Suits/CounselorRobe.cs new file mode 100644 index 0000000..247359a --- /dev/null +++ b/Scripts/Items/Suits/CounselorRobe.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class CounselorRobe : BaseSuit + { + [Constructable] + public CounselorRobe() : base( AccessLevel.Counselor, 0x3, 0x204F ) + { + } + + public CounselorRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/DeathShroud.cs b/Scripts/Items/Suits/DeathShroud.cs new file mode 100644 index 0000000..35fa651 --- /dev/null +++ b/Scripts/Items/Suits/DeathShroud.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DeathShroud : BaseSuit + { + [Constructable] + public DeathShroud() : base( AccessLevel.GameMaster, 0x0, 0x204E ) + { + } + + public DeathShroud( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/DupreSuit.cs b/Scripts/Items/Suits/DupreSuit.cs new file mode 100644 index 0000000..14e61bf --- /dev/null +++ b/Scripts/Items/Suits/DupreSuit.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class DupreSuit : BaseSuit + { + [Constructable] + public DupreSuit() : base( AccessLevel.GameMaster, 0x0, 0x2050 ) + { + } + + public DupreSuit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/GMRobe.cs b/Scripts/Items/Suits/GMRobe.cs new file mode 100644 index 0000000..05071d2 --- /dev/null +++ b/Scripts/Items/Suits/GMRobe.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GMRobe : BaseSuit + { + [Constructable] + public GMRobe() : base( AccessLevel.GameMaster, 0x26, 0x204F ) + { + } + + public GMRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/LordBlackthorneSuit.cs b/Scripts/Items/Suits/LordBlackthorneSuit.cs new file mode 100644 index 0000000..bba4dd4 --- /dev/null +++ b/Scripts/Items/Suits/LordBlackthorneSuit.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LordBlackthorneSuit : BaseSuit + { + [Constructable] + public LordBlackthorneSuit() : base( AccessLevel.GameMaster, 0x0, 0x2043 ) + { + } + + public LordBlackthorneSuit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/LordBritishSuit.cs b/Scripts/Items/Suits/LordBritishSuit.cs new file mode 100644 index 0000000..465dc24 --- /dev/null +++ b/Scripts/Items/Suits/LordBritishSuit.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LordBritishSuit : BaseSuit + { + [Constructable] + public LordBritishSuit() : base( AccessLevel.GameMaster, 0x0, 0x2042 ) + { + } + + public LordBritishSuit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Suits/SeerRobe.cs b/Scripts/Items/Suits/SeerRobe.cs new file mode 100644 index 0000000..a2f44f0 --- /dev/null +++ b/Scripts/Items/Suits/SeerRobe.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SeerRobe : BaseSuit + { + [Constructable] + public SeerRobe() : base( AccessLevel.Seer, 0x1D3, 0x204F ) + { + } + + public SeerRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Talismans/BaseTalisman.cs b/Scripts/Items/Talismans/BaseTalisman.cs new file mode 100644 index 0000000..46e8321 --- /dev/null +++ b/Scripts/Items/Talismans/BaseTalisman.cs @@ -0,0 +1,1094 @@ +using System; +using Server.Commands; +using Server.Mobiles; +using Server.Spells.Fifth; +using Server.Spells.First; +using Server.Spells.Fourth; +using Server.Spells.Necromancy; +using Server.Spells.Second; +using Server.Targeting; + +namespace Server.Items +{ + public enum TalismanRemoval + { + None = 0, + Ward = 390, + Damage = 404, + Curse = 407, + Wildfire = 2843 + } + + public class BaseTalisman : Item + { + public static void Initialize() + { + CommandSystem.Register("RandomTalisman", AccessLevel.GameMaster, new CommandEventHandler(RandomTalisman_OnCommand)); + } + + [Usage("RandomTalisman ")] + [Description("Generates random talismans in your backback.")] + public static void RandomTalisman_OnCommand(CommandEventArgs e) + { + Mobile m = e.Mobile; + int count = e.GetInt32(0); + + for (int i = 0; i < count; i++) + { + m.AddToBackpack(Loot.RandomTalisman()); + } + } + + public override int LabelNumber { get { return 1071023; } } // Talisman + public virtual bool ForceShowName { get { return false; } } // used to override default summoner/removal name + + private int m_MaxCharges; + private int m_Charges; + private int m_MaxChargeTime; + private int m_ChargeTime; + private bool m_Blessed; + + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCharges + { + get { return m_MaxCharges; } + set { m_MaxCharges = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get { return m_Charges; } + set + { + m_Charges = value; + + if (m_ChargeTime > 0) + StartTimer(); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxChargeTime + { + get { return m_MaxChargeTime; } + set { m_MaxChargeTime = value; InvalidateProperties(); } + } + + public int ChargeTime + { + get { return m_ChargeTime; } + set { m_ChargeTime = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Blessed + { + get { return m_Blessed; } + set { m_Blessed = value; InvalidateProperties(); } + } + + #region Slayer + private TalismanSlayerName m_Slayer; + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanSlayerName Slayer + { + get { return m_Slayer; } + set { m_Slayer = value; InvalidateProperties(); } + } + #endregion + + #region Summoner/Removal + private TalismanAttribute m_Summoner; + private TalismanRemoval m_Removal; + private Mobile m_Creature; + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanAttribute Summoner + { + get { return m_Summoner; } + set { m_Summoner = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanRemoval Removal + { + get { return m_Removal; } + set { m_Removal = value; InvalidateProperties(); } + } + #endregion + + #region Protection/Killer + private TalismanAttribute m_Protection; + private TalismanAttribute m_Killer; + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanAttribute Protection + { + get { return m_Protection; } + set { m_Protection = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TalismanAttribute Killer + { + get { return m_Killer; } + set { m_Killer = value; InvalidateProperties(); } + } + #endregion + + #region Craft bonuses + private SkillName m_Skill; + private int m_SuccessBonus; + private int m_ExceptionalBonus; + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName Skill + { + get { return m_Skill; } + set { m_Skill = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SuccessBonus + { + get { return m_SuccessBonus; } + set { m_SuccessBonus = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ExceptionalBonus + { + get { return m_ExceptionalBonus; } + set { m_ExceptionalBonus = value; InvalidateProperties(); } + } + #endregion + + #region AOS bonuses + private AosAttributes m_AosAttributes; + private AosSkillBonuses m_AosSkillBonuses; + + [CommandProperty(AccessLevel.GameMaster)] + public AosAttributes Attributes + { + get { return m_AosAttributes; } + set { } + } + + [CommandProperty(AccessLevel.GameMaster)] + public AosSkillBonuses SkillBonuses + { + get { return m_AosSkillBonuses; } + set { } + } + #endregion + + public BaseTalisman() + : this(GetRandomItemID()) + { + } + + public BaseTalisman(int itemID) + : base(itemID) + { + Layer = Layer.Talisman; + Weight = 1.0; + + m_Protection = new TalismanAttribute(); + m_Killer = new TalismanAttribute(); + m_Summoner = new TalismanAttribute(); + m_AosAttributes = new AosAttributes(this); + m_AosSkillBonuses = new AosSkillBonuses(this); + } + + public BaseTalisman(Serial serial) + : base(serial) + { + } + + public override void OnAfterDuped(Item newItem) + { + BaseTalisman talisman = newItem as BaseTalisman; + + if (talisman == null) + return; + + talisman.m_Summoner = new TalismanAttribute(m_Summoner); + talisman.m_Protection = new TalismanAttribute(m_Protection); + talisman.m_Killer = new TalismanAttribute(m_Killer); + talisman.m_AosAttributes = new AosAttributes(newItem, m_AosAttributes); + talisman.m_AosSkillBonuses = new AosSkillBonuses(newItem, m_AosSkillBonuses); + } + + public override bool CanEquip(Mobile from) + { + if (BlessedFor != null && BlessedFor != from) + { + from.SendLocalizedMessage(1010437); // You are not the owner. + return false; + } + + return base.CanEquip(from); + } + + public override void OnAdded(object parent) + { + if (parent is Mobile) + { + Mobile from = (Mobile)parent; + + m_AosSkillBonuses.AddTo(from); + m_AosAttributes.AddStatBonuses(from); + + if (m_Blessed && BlessedFor == null) + { + BlessedFor = from; + LootType = LootType.Blessed; + } + + if (m_ChargeTime > 0) + { + m_ChargeTime = m_MaxChargeTime; + StartTimer(); + } + } + + InvalidateProperties(); + } + + public override void OnRemoved(object parent) + { + if (parent is Mobile) + { + Mobile from = (Mobile)parent; + + m_AosSkillBonuses.Remove(); + m_AosAttributes.RemoveStatBonuses(from); + + if (m_Creature != null && !m_Creature.Deleted) + { + Effects.SendLocationParticles(EffectItem.Create(m_Creature.Location, m_Creature.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042); + Effects.PlaySound(m_Creature, m_Creature.Map, 0x201); + + m_Creature.Delete(); + } + + StopTimer(); + } + + InvalidateProperties(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Talisman != this) + from.SendLocalizedMessage(502641); // You must equip this item to use it. + else if (m_ChargeTime > 0) + from.SendLocalizedMessage(1074882, m_ChargeTime.ToString()); // You must wait ~1_val~ seconds for this to recharge. + else if (m_Charges == 0 && m_MaxCharges > 0) + from.SendLocalizedMessage(1042544); // This item is out of charges. + else + { + Type type = GetSummoner(); + + if (m_Summoner != null && !m_Summoner.IsEmpty) + type = m_Summoner.Type; + + if (type != null) + { + object obj; + + try { obj = Activator.CreateInstance(type); } + catch { obj = null; } + + if (obj is Item) + { + Item item = (Item)obj; + int count = 1; + + if (m_Summoner != null && m_Summoner.Amount > 1) + { + if (item.Stackable) + item.Amount = m_Summoner.Amount; + else + count = m_Summoner.Amount; + } + + if (from.Backpack == null || count * item.Weight > from.Backpack.MaxWeight || + from.Backpack.Items.Count + count > from.Backpack.MaxItems) + { + from.SendLocalizedMessage(500720); // You don't have enough room in your backpack! + item.Delete(); + item = null; + return; + } + + for (int i = 0; i < count; i++) + { + from.PlaceInBackpack(item); + + if (i + 1 < count) + item = Activator.CreateInstance(type) as Item; + } + + if (item is Board) + from.SendLocalizedMessage(1075000); // You have been given some wooden boards. + else if (item is IronIngot) + from.SendLocalizedMessage(1075001); // You have been given some ingots. + else if (item is Bandage) + from.SendLocalizedMessage(1075002); // You have been given some clean bandages. + else if (m_Summoner != null && m_Summoner.Name != null) + from.SendLocalizedMessage(1074853, m_Summoner.Name.ToString()); // You have been given ~1_name~ + } + else if (obj is BaseCreature) + { + BaseCreature mob = (BaseCreature)obj; + + if ((m_Creature != null && !m_Creature.Deleted) || from.Followers + mob.ControlSlots > from.FollowersMax) + { + from.SendLocalizedMessage(1074270); // You have too many followers to summon another one. + mob.Delete(); + return; + } + + BaseCreature.Summon(mob, from, from.Location, mob.BaseSoundID, TimeSpan.FromMinutes(10)); + Effects.SendLocationParticles(EffectItem.Create(mob.Location, mob.Map, EffectItem.DefaultDuration), 0x3728, 1, 10, 0x26B6); + + mob.Summoned = false; + mob.ControlOrder = OrderType.Friend; + + m_Creature = mob; + } + + OnAfterUse(from); + } + + if (m_Removal != TalismanRemoval.None) + { + from.Target = new TalismanTarget(this); + } + } + } + + public override void AddNameProperty(ObjectPropertyList list) + { + if (ForceShowName) + base.AddNameProperty(list); + else if (m_Summoner != null && !m_Summoner.IsEmpty) + list.Add(1072400, m_Summoner.Name != null ? m_Summoner.Name.ToString() : "Unknown"); // Talisman of ~1_name~ Summoning + else if (m_Removal != TalismanRemoval.None) + list.Add(1072389, "#" + (1072000 + (int)m_Removal)); // Talisman of ~1_name~ + else + base.AddNameProperty(list); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (Blessed) + { + if (BlessedFor != null) + list.Add(1072304, !String.IsNullOrEmpty(BlessedFor.Name) ? BlessedFor.Name : "Unnamed Warrior"); // Owned by ~1_name~ + else + list.Add(1072304, "Nobody"); // Owned by ~1_name~ + } + + if (Parent is Mobile && m_MaxChargeTime > 0) + { + if (m_ChargeTime > 0) + list.Add(1074884, m_ChargeTime.ToString()); // Charge time left: ~1_val~ + else + list.Add(1074883); // Fully Charged + } + + list.Add(1075085); // Requirement: Mondain's Legacy + + if (m_Killer != null && !m_Killer.IsEmpty && m_Killer.Amount > 0) + list.Add(1072388, "{0}\t{1}", m_Killer.Name != null ? m_Killer.Name.ToString() : "Unknown", m_Killer.Amount); // ~1_NAME~ Killer: +~2_val~% + + if (m_Protection != null && !m_Protection.IsEmpty && m_Protection.Amount > 0) + list.Add(1072387, "{0}\t{1}", m_Protection.Name != null ? m_Protection.Name.ToString() : "Unknown", m_Protection.Amount); // ~1_NAME~ Protection: +~2_val~% + + if (m_ExceptionalBonus != 0) + list.Add(1072395, "#{0}\t{1}", AosSkillBonuses.GetLabel(m_Skill), m_ExceptionalBonus); // ~1_NAME~ Exceptional Bonus: ~2_val~% + + if (m_SuccessBonus != 0) + list.Add(1072394, "#{0}\t{1}", AosSkillBonuses.GetLabel(m_Skill), m_SuccessBonus); // ~1_NAME~ Bonus: ~2_val~% + + m_AosSkillBonuses.GetProperties(list); + + int prop; + + if ((prop = m_AosAttributes.WeaponDamage) != 0) + list.Add(1060401, prop.ToString()); // damage increase ~1_val~% + + if ((prop = m_AosAttributes.DefendChance) != 0) + list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~% + + if ((prop = m_AosAttributes.BonusDex) != 0) + list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~ + + if ((prop = m_AosAttributes.EnhancePotions) != 0) + list.Add(1060411, prop.ToString()); // enhance potions ~1_val~% + + if ((prop = m_AosAttributes.CastRecovery) != 0) + list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~ + + if ((prop = m_AosAttributes.CastSpeed) != 0) + list.Add(1060413, prop.ToString()); // faster casting ~1_val~ + + if ((prop = m_AosAttributes.AttackChance) != 0) + list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~% + + if ((prop = m_AosAttributes.BonusHits) != 0) + list.Add(1060431, prop.ToString()); // hit point increase ~1_val~ + + if ((prop = m_AosAttributes.BonusInt) != 0) + list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~ + + if ((prop = m_AosAttributes.LowerManaCost) != 0) + list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~% + + if ((prop = m_AosAttributes.LowerRegCost) != 0) + list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~% + + if ((prop = m_AosAttributes.Luck) != 0) + list.Add(1060436, prop.ToString()); // luck ~1_val~ + + if ((prop = m_AosAttributes.BonusMana) != 0) + list.Add(1060439, prop.ToString()); // mana increase ~1_val~ + + if ((prop = m_AosAttributes.RegenMana) != 0) + list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ + + if ((prop = m_AosAttributes.NightSight) != 0) + list.Add(1060441); // night sight + + if ((prop = m_AosAttributes.ReflectPhysical) != 0) + list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~% + + if ((prop = m_AosAttributes.RegenStam) != 0) + list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~ + + if ((prop = m_AosAttributes.RegenHits) != 0) + list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ + + if ((prop = m_AosAttributes.SpellChanneling) != 0) + list.Add(1060482); // spell channeling + + if ((prop = m_AosAttributes.SpellDamage) != 0) + list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~% + + if ((prop = m_AosAttributes.BonusStam) != 0) + list.Add(1060484, prop.ToString()); // stamina increase ~1_val~ + + if ((prop = m_AosAttributes.BonusStr) != 0) + list.Add(1060485, prop.ToString()); // strength bonus ~1_val~ + + if ((prop = m_AosAttributes.WeaponSpeed) != 0) + list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~% + + if (Core.ML && (prop = m_AosAttributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + if (m_MaxCharges > 0) + list.Add(1060741, m_Charges.ToString()); // charges: ~1_val~ + + if (m_Slayer != TalismanSlayerName.None) + list.Add(1072503 + (int)m_Slayer); + } + + private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) + { + if (setIf) + flags |= toSet; + } + + private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) + { + return ((flags & toGet) != 0); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Attributes = 0x00000001, + SkillBonuses = 0x00000002, + Owner = 0x00000004, + Protection = 0x00000008, + Killer = 0x00000010, + Summoner = 0x00000020, + Removal = 0x00000040, + OldKarmaLoss = 0x00000080, + Skill = 0x00000100, + SuccessBonus = 0x00000200, + ExceptionalBonus = 0x00000400, + MaxCharges = 0x00000800, + Charges = 0x00001000, + MaxChargeTime = 0x00002000, + ChargeTime = 0x00004000, + Blessed = 0x00008000, + Slayer = 0x00010000, + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag(ref flags, SaveFlag.Attributes, !m_AosAttributes.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !m_AosSkillBonuses.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.Protection, m_Protection != null && !m_Protection.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.Killer, m_Killer != null && !m_Killer.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.Summoner, m_Summoner != null && !m_Summoner.IsEmpty); + SetSaveFlag(ref flags, SaveFlag.Removal, m_Removal != TalismanRemoval.None); + SetSaveFlag(ref flags, SaveFlag.Skill, (int)m_Skill != 0); + SetSaveFlag(ref flags, SaveFlag.SuccessBonus, m_SuccessBonus != 0); + SetSaveFlag(ref flags, SaveFlag.ExceptionalBonus, m_ExceptionalBonus != 0); + SetSaveFlag(ref flags, SaveFlag.MaxCharges, m_MaxCharges != 0); + SetSaveFlag(ref flags, SaveFlag.Charges, m_Charges != 0); + SetSaveFlag(ref flags, SaveFlag.MaxChargeTime, m_MaxChargeTime != 0); + SetSaveFlag(ref flags, SaveFlag.ChargeTime, m_ChargeTime != 0); + SetSaveFlag(ref flags, SaveFlag.Blessed, m_Blessed); + SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != TalismanSlayerName.None); + + writer.WriteEncodedInt((int)flags); + + if (GetSaveFlag(flags, SaveFlag.Attributes)) + m_AosAttributes.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) + m_AosSkillBonuses.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Protection)) + m_Protection.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Killer)) + m_Killer.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Summoner)) + m_Summoner.Serialize(writer); + + if (GetSaveFlag(flags, SaveFlag.Removal)) + writer.WriteEncodedInt((int)m_Removal); + + if (GetSaveFlag(flags, SaveFlag.Skill)) + writer.WriteEncodedInt((int)m_Skill); + + if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) + writer.WriteEncodedInt(m_SuccessBonus); + + if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) + writer.WriteEncodedInt(m_ExceptionalBonus); + + if (GetSaveFlag(flags, SaveFlag.MaxCharges)) + writer.WriteEncodedInt(m_MaxCharges); + + if (GetSaveFlag(flags, SaveFlag.Charges)) + writer.WriteEncodedInt(m_Charges); + + if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) + writer.WriteEncodedInt(m_MaxChargeTime); + + if (GetSaveFlag(flags, SaveFlag.ChargeTime)) + writer.WriteEncodedInt(m_ChargeTime); + + if (GetSaveFlag(flags, SaveFlag.Slayer)) + writer.WriteEncodedInt((int)m_Slayer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + SaveFlag flags = (SaveFlag)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Attributes)) + m_AosAttributes = new AosAttributes(this, reader); + else + m_AosAttributes = new AosAttributes(this); + + if (GetSaveFlag(flags, SaveFlag.SkillBonuses)) + m_AosSkillBonuses = new AosSkillBonuses(this, reader); + else + m_AosSkillBonuses = new AosSkillBonuses(this); + + // Backward compatibility + if (GetSaveFlag(flags, SaveFlag.Owner)) + BlessedFor = reader.ReadMobile(); + + if (GetSaveFlag(flags, SaveFlag.Protection)) + m_Protection = new TalismanAttribute(reader); + else + m_Protection = new TalismanAttribute(); + + if (GetSaveFlag(flags, SaveFlag.Killer)) + m_Killer = new TalismanAttribute(reader); + else + m_Killer = new TalismanAttribute(); + + if (GetSaveFlag(flags, SaveFlag.Summoner)) + m_Summoner = new TalismanAttribute(reader); + else + m_Summoner = new TalismanAttribute(); + + if (GetSaveFlag(flags, SaveFlag.Removal)) + m_Removal = (TalismanRemoval)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.OldKarmaLoss)) + m_AosAttributes.IncreasedKarmaLoss = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Skill)) + m_Skill = (SkillName)reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.SuccessBonus)) + m_SuccessBonus = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.ExceptionalBonus)) + m_ExceptionalBonus = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.MaxCharges)) + m_MaxCharges = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Charges)) + m_Charges = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.MaxChargeTime)) + m_MaxChargeTime = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.ChargeTime)) + m_ChargeTime = reader.ReadEncodedInt(); + + if (GetSaveFlag(flags, SaveFlag.Slayer)) + m_Slayer = (TalismanSlayerName)reader.ReadEncodedInt(); + + m_Blessed = GetSaveFlag(flags, SaveFlag.Blessed); + + break; + } + } + + if (Parent is Mobile) + { + Mobile m = (Mobile)Parent; + + m_AosAttributes.AddStatBonuses(m); + m_AosSkillBonuses.AddTo(m); + + if (m_ChargeTime > 0) + StartTimer(); + } + } + + public virtual void OnAfterUse(Mobile m) + { + m_ChargeTime = m_MaxChargeTime; + + if (m_Charges > 0 && m_MaxCharges > 0) + m_Charges -= 1; + + if (m_ChargeTime > 0) + StartTimer(); + + InvalidateProperties(); + } + + public virtual Type GetSummoner() + { + return null; + } + + public virtual void SetSummoner(Type type, TextDefinition name) + { + m_Summoner = new TalismanAttribute(type, name); + } + + public virtual void SetProtection(Type type, TextDefinition name, int amount) + { + m_Protection = new TalismanAttribute(type, name, amount); + } + + public virtual void SetKiller(Type type, TextDefinition name, int amount) + { + m_Killer = new TalismanAttribute(type, name, amount); + } + + #region Timer + private Timer m_Timer; + + public virtual void StartTimer() + { + if (m_Timer == null || !m_Timer.Running) + m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10), new TimerCallback(Slice)); + } + + public virtual void StopTimer() + { + if (m_Timer != null) + m_Timer.Stop(); + + m_Timer = null; + } + + public virtual void Slice() + { + if (m_ChargeTime - 10 > 0) + m_ChargeTime -= 10; + else + { + m_ChargeTime = 0; + + StopTimer(); + } + + InvalidateProperties(); + } + #endregion + + #region Randomize + private static int[] m_ItemIDs = new int[] + { + 0x2F58, 0x2F59, 0x2F5A, 0x2F5B + }; + + public static int GetRandomItemID() + { + return Utility.RandomList(m_ItemIDs); + } + + private static Type[] m_Summons = new Type[] + { + typeof( SummonedAntLion ), + typeof( SummonedCow ), + typeof( SummonedLavaSerpent ), + typeof( SummonedOrcBrute ), + typeof( SummonedFrostSpider ), + typeof( SummonedPanther ), + typeof( SummonedDoppleganger ), + typeof( SummonedGreatHart ), + typeof( SummonedBullFrog ), + typeof( SummonedArcticOgreLord ), + typeof( SummonedBogling ), + typeof( SummonedBakeKitsune ), + typeof( SummonedSheep ), + typeof( SummonedSkeletalKnight ), + typeof( SummonedWailingBanshee ), + typeof( SummonedChicken ), + typeof( SummonedVorpalBunny ), + + typeof( Board ), + typeof( IronIngot ), + typeof( Bandage ), + }; + + private static int[] m_SummonLabels = new int[] + { + 1075211, // Ant Lion + 1072494, // Cow + 1072434, // Lava Serpent + 1072414, // Orc Brute + 1072476, // Frost Spider + 1029653, // Panther + 1029741, // Doppleganger + 1018292, // great hart + 1028496, // bullfrog + 1018227, // arctic ogre lord + 1029735, // Bogling + 1030083, // bake-kitsune + 1018285, // sheep + 1018239, // skeletal knight + 1072399, // Wailing Banshee + 1072459, // Chicken + 1072401, // Vorpal Bunny + + 1015101, // Boards + 1044036, // Ingots + 1023817, // clean bandage + }; + + public static Type GetRandomSummonType() + { + return m_Summons[Utility.Random(m_Summons.Length)]; + } + + public static TalismanAttribute GetRandomSummoner() + { + if (0.025 > Utility.RandomDouble()) + { + int num = Utility.Random(m_Summons.Length); + + if (num > 14) + return new TalismanAttribute(m_Summons[num], m_SummonLabels[num], 10); + else + return new TalismanAttribute(m_Summons[num], m_SummonLabels[num]); + } + + return new TalismanAttribute(); + } + + public static TalismanRemoval GetRandomRemoval() + { + if (0.65 > Utility.RandomDouble()) + return (TalismanRemoval)Utility.RandomList(390, 404, 407); + + return TalismanRemoval.None; + } + + private static Type[] m_Killers = new Type[] + { + typeof( OrcBomber ), typeof( OrcBrute ), typeof( Sewerrat ), typeof( Rat ), typeof( GiantRat ), + typeof( Ratman ), typeof( RatmanArcher ), typeof( GiantSpider ), typeof( FrostSpider ), typeof( GiantBlackWidow ), + typeof( DreadSpider ), typeof( SilverSerpent ), typeof( DeepSeaSerpent ), typeof( GiantSerpent ), typeof( Snake ), + typeof( IceSnake ), typeof( IceSerpent ), typeof( LavaSerpent ), typeof( LavaSnake ), typeof( Yamandon ), + typeof( StrongMongbat ),typeof( Mongbat ), typeof( VampireBat ), typeof( Lich ), typeof( EvilMage ), + typeof( LichLord ), typeof( EvilMageLord ), typeof( SkeletalMage ), typeof( KhaldunZealot ), typeof( AncientLich ), + typeof( JukaMage ), typeof( MeerMage ), typeof( Beetle ), typeof( DeathwatchBeetle ), typeof( RuneBeetle ), + typeof( FireBeetle ), typeof( DeathwatchBeetleHatchling), typeof( Bird ), typeof( Chicken ), typeof( Eagle ), + typeof( TropicalBird ), typeof( Phoenix ), typeof( DesertOstard ), typeof( FrenziedOstard ), typeof( ForestOstard ), + typeof( Crane ), typeof( SnowLeopard ), typeof( IceFiend ), typeof( FrostOoze ), typeof( FrostTroll ), + typeof( IceElemental ), typeof( SnowElemental ), typeof( GiantIceWorm ), typeof( LadyOfTheSnow ), typeof( FireElemental ), + typeof( FireSteed ), typeof( HellHound ), typeof( HellCat ), typeof( PredatorHellCat ), typeof( LavaLizard ), + typeof( FireBeetle ), typeof( Cow ), typeof( Bull ), typeof( Gaman )//, typeof( Minotaur) + // TODO Meraktus, Tormented Minotaur, Minotaur + }; + + private static int[] m_KillerLabels = new int[] + { + 1072413, 1072414, 1072418, 1072419, 1072420, + 1072421, 1072423, 1072424, 1072425, 1072426, + 1072427, 1072428, 1072429, 1072430, 1072431, + 1072432, 1072433, 1072434, 1072435, 1072438, + 1072440, 1072441, 1072443, 1072444, 1072445, + 1072446, 1072447, 1072448, 1072449, 1072450, + 1072451, 1072452, 1072453, 1072454, 1072455, + 1072456, 1072457, 1072458, 1072459, 1072461, + 1072462, 1072465, 1072468, 1072469, 1072470, + 1072473, 1072474, 1072477, 1072478, 1072479, + 1072480, 1072481, 1072483, 1072485, 1072486, + 1072487, 1072489, 1072490, 1072491, 1072492, + 1072493, 1072494, 1072495, 1072498, + }; + + public static TalismanAttribute GetRandomKiller() + { + return GetRandomKiller(true); + } + + public static TalismanAttribute GetRandomKiller(bool includingNone) + { + if (includingNone && Utility.RandomBool()) + return new TalismanAttribute(); + + int num = Utility.Random(m_Killers.Length); + + return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(10, 100)); + } + + public static TalismanAttribute GetRandomProtection() + { + return GetRandomProtection(true); + } + + public static TalismanAttribute GetRandomProtection(bool includingNone) + { + if (includingNone && Utility.RandomBool()) + return new TalismanAttribute(); + + int num = Utility.Random(m_Killers.Length); + + return new TalismanAttribute(m_Killers[num], m_KillerLabels[num], Utility.RandomMinMax(5, 60)); + } + + private static SkillName[] m_Skills = new SkillName[] + { + SkillName.Alchemy, + SkillName.Blacksmith, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.Fletching, + SkillName.Inscribe, + SkillName.Tailoring, + SkillName.Tinkering, + }; + + public static SkillName GetRandomSkill() + { + return m_Skills[Utility.Random(m_Skills.Length)]; + } + + public static int GetRandomExceptional() + { + if (0.3 > Utility.RandomDouble()) + { + double num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; + + return (int)Math.Round(num); + } + + return 0; + } + + public static int GetRandomSuccessful() + { + if (0.75 > Utility.RandomDouble()) + { + double num = 40 - Math.Log(Utility.RandomMinMax(7, 403)) * 5; + + return (int)Math.Round(num); + } + + return 0; + } + + public static bool GetRandomBlessed() + { + if (0.02 > Utility.RandomDouble()) + return true; + + return false; + } + + public static TalismanSlayerName GetRandomSlayer() + { + if (0.01 > Utility.RandomDouble()) + return (TalismanSlayerName)Utility.RandomMinMax(1, 9); + + return TalismanSlayerName.None; + } + + public static int GetRandomCharges() + { + if (0.5 > Utility.RandomDouble()) + return Utility.RandomMinMax(10, 50); + + return 0; + } + #endregion + + private class TalismanTarget : Target + { + private BaseTalisman m_Talisman; + + public TalismanTarget(BaseTalisman talisman) + : base(12, false, TargetFlags.Beneficial) + { + m_Talisman = talisman; + } + + protected override void OnTarget(Mobile from, object o) + { + if (m_Talisman == null || m_Talisman.Deleted) + return; + + Mobile target = o as Mobile; + + if (from.Talisman != m_Talisman) + from.SendLocalizedMessage(502641); // You must equip this item to use it. + else if (target == null) + from.SendLocalizedMessage(1046439); // That is not a valid target. + else if (m_Talisman.ChargeTime > 0) + from.SendLocalizedMessage(1074882, m_Talisman.ChargeTime.ToString()); // You must wait ~1_val~ seconds for this to recharge. + else if (m_Talisman.Charges == 0 && m_Talisman.MaxCharges > 0) + from.SendLocalizedMessage(1042544); // This item is out of charges. + else + { + switch (m_Talisman.Removal) + { + case TalismanRemoval.Curse: + target.PlaySound(0xF6); + target.PlaySound(0x1F7); + target.FixedParticles(0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head); + + IEntity mfrom = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z - 10), from.Map); + IEntity mto = new Entity(Serial.Zero, new Point3D(target.X, target.Y, target.Z + 50), from.Map); + Effects.SendMovingParticles(mfrom, mto, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, 0x100); + + StatMod mod; + + mod = target.GetStatMod("[Magic] Str Offset"); + if (mod != null && mod.Offset < 0) + target.RemoveStatMod("[Magic] Str Offset"); + + mod = target.GetStatMod("[Magic] Dex Offset"); + if (mod != null && mod.Offset < 0) + target.RemoveStatMod("[Magic] Dex Offset"); + + mod = target.GetStatMod("[Magic] Int Offset"); + if (mod != null && mod.Offset < 0) + target.RemoveStatMod("[Magic] Int Offset"); + + target.Paralyzed = false; + + EvilOmenSpell.TryEndEffect(target); + StrangleSpell.RemoveCurse(target); + CorpseSkinSpell.RemoveCurse(target); + CurseSpell.RemoveEffect(target); + + BuffInfo.RemoveBuff(target, BuffIcon.Clumsy); + BuffInfo.RemoveBuff(target, BuffIcon.FeebleMind); + BuffInfo.RemoveBuff(target, BuffIcon.Weaken); + BuffInfo.RemoveBuff(target, BuffIcon.MassCurse); + + target.SendLocalizedMessage(1072408); // Any curses on you have been lifted + + if (target != from) + from.SendLocalizedMessage(1072409); // Your targets curses have been lifted + + break; + case TalismanRemoval.Damage: + target.PlaySound(0x201); + Effects.SendLocationParticles(EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, 0x834, 0, 0x13B2, 0); + + BleedAttack.EndBleed(target, true); + MortalStrike.EndWound(target); + + BuffInfo.RemoveBuff(target, BuffIcon.Bleed); + BuffInfo.RemoveBuff(target, BuffIcon.MortalStrike); + + target.SendLocalizedMessage(1072405); // Your lasting damage effects have been removed! + + if (target != from) + from.SendLocalizedMessage(1072406); // Your Targets lasting damage effects have been removed! + + break; + case TalismanRemoval.Ward: + target.PlaySound(0x201); + Effects.SendLocationParticles(EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), 0x3728, 1, 13, 0x834, 0, 0x13B2, 0); + + MagicReflectSpell.EndReflect(target); + ReactiveArmorSpell.EndArmor(target); + ProtectionSpell.EndProtection(target); + + target.SendLocalizedMessage(1072402); // Your wards have been removed! + + if (target != from) + from.SendLocalizedMessage(1072403); // Your target's wards have been removed! + + break; + case TalismanRemoval.Wildfire: + // TODO + break; + } + + m_Talisman.OnAfterUse(from); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Talismans/Items/EnchantedSwitch.cs b/Scripts/Items/Talismans/Items/EnchantedSwitch.cs new file mode 100644 index 0000000..cd1de0d --- /dev/null +++ b/Scripts/Items/Talismans/Items/EnchantedSwitch.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + public class EnchantedSwitch : Item + { + public override int LabelNumber{ get{ return 1072893; } } // enchanted switch + + [Constructable] + public EnchantedSwitch() : base( 0x2F5C ) + { + Weight = 1.0; + } + + public EnchantedSwitch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Talismans/Items/HollowPrism.cs b/Scripts/Items/Talismans/Items/HollowPrism.cs new file mode 100644 index 0000000..925928f --- /dev/null +++ b/Scripts/Items/Talismans/Items/HollowPrism.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class HollowPrism : Item + { + public override int LabelNumber{ get{ return 1072895; } } // hollow prism + + [Constructable] + public HollowPrism() : base( 0x2F5D ) + { + Weight = 1.0; + } + + public HollowPrism( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Talismans/Items/JeweledFiligree.cs b/Scripts/Items/Talismans/Items/JeweledFiligree.cs new file mode 100644 index 0000000..c6e121f --- /dev/null +++ b/Scripts/Items/Talismans/Items/JeweledFiligree.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class JeweledFiligree : Item + { + public override int LabelNumber{ get{ return 1072894; } } // jeweled filigree + + [Constructable] + public JeweledFiligree() : base( 0x2F5E ) + { + Weight = 1.0; + } + + public JeweledFiligree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Talismans/Items/RunedPrism.cs b/Scripts/Items/Talismans/Items/RunedPrism.cs new file mode 100644 index 0000000..4d6bb4e --- /dev/null +++ b/Scripts/Items/Talismans/Items/RunedPrism.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + public class RunedPrism : Item + { + public override int LabelNumber{ get{ return 1073465; } } // runed prism + + [Constructable] + public RunedPrism() : base( 0x2F57 ) + { + Weight = 1.0; + } + + public RunedPrism( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Items/Talismans/Items/RunedSwitch.cs b/Scripts/Items/Talismans/Items/RunedSwitch.cs new file mode 100644 index 0000000..73f4054 --- /dev/null +++ b/Scripts/Items/Talismans/Items/RunedSwitch.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Items +{ + public class RunedSwitch : Item + { + public override int LabelNumber{ get{ return 1072896; } } // runed switch + + [Constructable] + public RunedSwitch() : base( 0x2F61 ) + { + Weight = 1.0; + } + + public RunedSwitch( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1075101 ); // Please select an item to recharge. + from.Target = new InternalTarget( this ); + } + else + from.SendLocalizedMessage( 1060640 ); // The item must be in your backpack to use it. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private class InternalTarget : Target + { + private RunedSwitch m_Item; + + public InternalTarget( RunedSwitch item ) : base( 0, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( m_Item == null || m_Item.Deleted ) + return; + + if ( o is BaseTalisman ) + { + BaseTalisman talisman = (BaseTalisman) o; + + if ( talisman.Charges == 0 ) + { + // Scriptiz : les talismans ne sont pas �ternels + if (talisman.MaxCharges > 0) // si c'est un talisman avec des charges (pas infini) + { + talisman.MaxCharges /= 2; // on perd la moiti� des charges max + if (talisman.MaxCharges == 0) // s'il n'en reste plus il faut delete le talisman + { + from.SendMessage("Cet objet �tait trop vieux pour �tre recharg�, il s'est cass�."); + talisman.Delete(); + return; + } + } + + talisman.Charges = talisman.MaxCharges; + m_Item.Delete(); + from.SendLocalizedMessage( 1075100 ); // The item has been recharged. + } + else + from.SendLocalizedMessage( 1075099 ); // You cannot recharge that item until all of its current charges have been used. + } + else + from.SendLocalizedMessage( 1046439 ); // That is not a valid target. + } + } + } +} + diff --git a/Scripts/Items/Talismans/RandomTalisman.cs b/Scripts/Items/Talismans/RandomTalisman.cs new file mode 100644 index 0000000..822274d --- /dev/null +++ b/Scripts/Items/Talismans/RandomTalisman.cs @@ -0,0 +1,63 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; + +namespace Server.Items +{ + public class RandomTalisman : BaseTalisman + { + [Constructable] + public RandomTalisman() : base( GetRandomItemID() ) + { + Summoner = BaseTalisman.GetRandomSummoner(); + + if ( Summoner.IsEmpty ) + { + Removal = BaseTalisman.GetRandomRemoval(); + + if ( Removal != TalismanRemoval.None ) + { + MaxCharges = BaseTalisman.GetRandomCharges(); + MaxChargeTime = 300; // 1200 + } + } + else + { + MaxCharges = Utility.RandomMinMax( 10, 50 ); + + if ( Summoner.IsItem ) + MaxChargeTime = 60; + else + MaxChargeTime = 600; // 1800 + } + + Blessed = BaseTalisman.GetRandomBlessed(); + Slayer = BaseTalisman.GetRandomSlayer(); + Protection = BaseTalisman.GetRandomProtection(); + Killer = BaseTalisman.GetRandomKiller(); + Skill = BaseTalisman.GetRandomSkill(); + ExceptionalBonus = BaseTalisman.GetRandomExceptional(); + SuccessBonus = BaseTalisman.GetRandomSuccessful(); + Charges = MaxCharges; + } + + public RandomTalisman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Talismans/TalismanAttribute.cs b/Scripts/Items/Talismans/TalismanAttribute.cs new file mode 100644 index 0000000..713a6d4 --- /dev/null +++ b/Scripts/Items/Talismans/TalismanAttribute.cs @@ -0,0 +1,145 @@ +using System; +using Server; + +namespace Server.Items +{ + [PropertyObject] + public class TalismanAttribute + { + private Type m_Type; + private TextDefinition m_Name; + private int m_Amount; + + [CommandProperty( AccessLevel.GameMaster )] + public Type Type + { + get{ return m_Type; } + set{ m_Type = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TextDefinition Name + { + get{ return m_Name; } + set{ m_Name = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Amount + { + get { return m_Amount; } + set { m_Amount = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsEmpty + { + get { return m_Type == null; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsItem + { + get { return m_Type != null && m_Type.Namespace.Equals( "Server.Items" ); } + } + + public TalismanAttribute() : this( null, 0, 0 ) + { + } + + public TalismanAttribute( TalismanAttribute copy ) + { + if ( copy != null ) + { + m_Type = copy.Type; + m_Name = copy.Name; + m_Amount = copy.Amount; + } + } + + public TalismanAttribute( Type type, TextDefinition name ) : this( type, name, 0 ) + { + } + + public TalismanAttribute( Type type, TextDefinition name, int amount ) + { + m_Type = type; + m_Name = name; + m_Amount = amount; + } + + public TalismanAttribute( GenericReader reader ) + { + int version = reader.ReadInt(); + + SaveFlag flags = (SaveFlag) reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Type ) ) + m_Type = ScriptCompiler.FindTypeByFullName( reader.ReadString(), false ); + + if ( GetSaveFlag( flags, SaveFlag.Name ) ) + m_Name = TextDefinition.Deserialize(reader); + + if ( GetSaveFlag( flags, SaveFlag.Amount ) ) + m_Amount = reader.ReadEncodedInt(); + } + + public override string ToString() + { + if ( m_Type != null ) + return m_Type.Name; + + return "None"; + } + + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Type = 0x00000001, + Name = 0x00000002, + Amount = 0x00000004, + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag( ref flags, SaveFlag.Type, m_Type != null ); + SetSaveFlag( ref flags, SaveFlag.Name, m_Name != null ); + SetSaveFlag( ref flags, SaveFlag.Amount, m_Amount != 0 ); + + writer.WriteEncodedInt( (int) flags ); + + if ( GetSaveFlag( flags, SaveFlag.Type ) ) + writer.Write( m_Type.FullName ); + + if ( GetSaveFlag( flags, SaveFlag.Name ) ) + TextDefinition.Serialize(writer, m_Name); + + if ( GetSaveFlag( flags, SaveFlag.Amount ) ) + writer.WriteEncodedInt( m_Amount ); + } + + public int DamageBonus( Mobile to ) + { + if (to != null && to.GetType() == m_Type) // Verified: only works on the exact type + return m_Amount; + + return 0; + } + } +} diff --git a/Scripts/Items/Talismans/TalismanSlayer.cs b/Scripts/Items/Talismans/TalismanSlayer.cs new file mode 100644 index 0000000..2fccb6e --- /dev/null +++ b/Scripts/Items/Talismans/TalismanSlayer.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public enum TalismanSlayerName + { + None, + Bear, + Vermin, + Bat, + Mage, + Beetle, + Bird, + Ice, + Flame, + Bovine + } + + public static class TalismanSlayer + { + private static Dictionary m_Table = new Dictionary(); + + public static void Initialize() + { + m_Table[ TalismanSlayerName.Bear ] = new Type[] + { + typeof( GrizzlyBear ), typeof( BlackBear ), typeof( BrownBear ), typeof( PolarBear ) //, typeof( Grobu ) + }; + + m_Table[ TalismanSlayerName.Vermin ] = new Type[] + { + typeof( RatmanMage ), typeof( RatmanMage ), typeof( RatmanArcher ), typeof( Barracoon), + typeof( Ratman ), typeof( Sewerrat ), typeof( Rat ), typeof( GiantRat ) //, typeof( Chiikkaha ) + }; + + m_Table[ TalismanSlayerName.Bat ] = new Type[] + { + typeof( Mongbat ), typeof( StrongMongbat ), typeof( VampireBat ) + }; + + m_Table[ TalismanSlayerName.Mage ] = new Type[] + { + typeof( EvilMage ), typeof( EvilMageLord ), typeof( AncientLich ), typeof( Lich ), typeof( LichLord ), + typeof( SkeletalMage ), typeof( BoneMagi ), typeof( OrcishMage ), typeof( KhaldunZealot ), typeof( JukaMage ), + }; + + m_Table[ TalismanSlayerName.Beetle ] = new Type[] + { + typeof( Beetle ), typeof( RuneBeetle ), typeof( FireBeetle ), typeof( DeathwatchBeetle ), + typeof( DeathwatchBeetleHatchling ) + }; + + m_Table[ TalismanSlayerName.Bird ] = new Type[] + { + typeof( Bird ), typeof( TropicalBird ), typeof( Chicken ), typeof( Crane ), + typeof( DesertOstard ), typeof( Eagle ), typeof( ForestOstard ), typeof( FrenziedOstard ), + typeof( Phoenix ), /*typeof( Pyre ), typeof( Swoop ), typeof( Saliva ),*/ typeof( Harpy ), + typeof( StoneHarpy ) // ????? + }; + + m_Table[ TalismanSlayerName.Ice ] = new Type[] + { + typeof( ArcticOgreLord ), typeof( IceElemental ), typeof( SnowElemental ), typeof( FrostOoze ), + typeof( IceFiend ), /*typeof( UnfrozenMummy ),*/ typeof( FrostSpider ), typeof( LadyOfTheSnow ), + typeof( FrostTroll ), + + // TODO WinterReaper, check + typeof( IceSnake ), typeof( SnowLeopard ), typeof( PolarBear ), typeof( IceSerpent ), typeof( GiantIceWorm ) + }; + + m_Table[ TalismanSlayerName.Flame ] = new Type[] + { + typeof( FireBeetle ), typeof( HellHound ), typeof( LavaSerpent ), typeof( FireElemental ), + typeof( PredatorHellCat ), typeof( Phoenix ), typeof( FireGargoyle ), typeof( HellCat ), + /*typeof( Pyre ),*/ typeof( FireSteed ), typeof( LavaLizard ), + + // TODO check + typeof( LavaSnake ), + }; + + m_Table[ TalismanSlayerName.Bovine ] = new Type[] + { + typeof( Cow ), typeof( Bull ), typeof( Gaman ) /*, typeof( MinotaurCaptain ), + typeof( MinotaurScout ), typeof( Minotaur )*/ + + // TODO TormentedMinotaur + }; + } + + public static bool Slays( TalismanSlayerName name, Mobile m ) + { + if ( !m_Table.ContainsKey( name ) ) + return false; + + Type[] types = m_Table[ name ]; + + if ( types == null || m == null ) + return false; + + Type type = m.GetType(); + + for ( int i = 0; i < types.Length; i++ ) + { + if (types[i].IsAssignableFrom(type)) + return true; + } + + return false; + } + } +} diff --git a/Scripts/Items/Talismans/TalismanSummons.cs b/Scripts/Items/Talismans/TalismanSummons.cs new file mode 100644 index 0000000..ea0c048 --- /dev/null +++ b/Scripts/Items/Talismans/TalismanSummons.cs @@ -0,0 +1,621 @@ +using System; +using System.Collections.Generic; + +using Server.ContextMenus; +using Server.Regions; +using Server.Items; + +using BunnyHole = Server.Mobiles.VorpalBunny.BunnyHole; + +namespace Server.Mobiles +{ + public class BaseTalismanSummon : BaseCreature + { + public override bool Commandable{ get{ return false; } } + public override bool InitialInnocent{ get{ return true; } } + //public override bool IsInvulnerable{ get{ return true; } } // TODO: Wailing banshees are NOT invulnerable, are any of the others? + + public BaseTalismanSummon() : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 ) + { + // TODO: Stats/skills + } + + public BaseTalismanSummon( Serial serial ) : base( serial ) + { + } + + public override void AddCustomContextEntries( Mobile from, List list ) + { + if ( from.Alive && ControlMaster == from ) + list.Add( new TalismanReleaseEntry( this ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + private class TalismanReleaseEntry : ContextMenuEntry + { + private Mobile m_Mobile; + + public TalismanReleaseEntry( Mobile m ) : base( 6118, 3 ) + { + m_Mobile = m; + } + + public override void OnClick() + { + Effects.SendLocationParticles( EffectItem.Create( m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 ); + Effects.PlaySound( m_Mobile, m_Mobile.Map, 0x201 ); + + m_Mobile.Delete(); + } + } + } + + public class SummonedAntLion : BaseTalismanSummon + { + [Constructable] + public SummonedAntLion() : base() + { + Name = "an ant lion"; + Body = 787; + BaseSoundID = 1006; + } + + public SummonedAntLion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedArcticOgreLord : BaseTalismanSummon + { + [Constructable] + public SummonedArcticOgreLord() : base() + { + Name = "an arctic ogre lord"; + Body = 135; + BaseSoundID = 427; + } + + public SummonedArcticOgreLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedBakeKitsune : BaseTalismanSummon + { + [Constructable] + public SummonedBakeKitsune() : base() + { + Name = "a bake kitsune"; + Body = 246; + BaseSoundID = 0x4DD; + } + + public SummonedBakeKitsune( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedBogling : BaseTalismanSummon + { + [Constructable] + public SummonedBogling() : base() + { + Name = "a bogling"; + Body = 779; + BaseSoundID = 422; + } + + public SummonedBogling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedBullFrog : BaseTalismanSummon + { + [Constructable] + public SummonedBullFrog() : base() + { + Name = "a bull frog"; + Body = 81; + Hue = Utility.RandomList( 0x5AC, 0x5A3, 0x59A, 0x591, 0x588, 0x57F ); + BaseSoundID = 0x266; + } + + public SummonedBullFrog( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedChicken : BaseTalismanSummon + { + [Constructable] + public SummonedChicken() : base() + { + Name = "a chicken"; + Body = 0xD0; + BaseSoundID = 0x6E; + } + + public SummonedChicken( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedCow : BaseTalismanSummon + { + [Constructable] + public SummonedCow() : base() + { + Name = "a cow"; + Body = Utility.RandomList( 0xD8, 0xE7 ); + BaseSoundID = 0x78; + } + + public SummonedCow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + public class SummonedDoppleganger : BaseTalismanSummon + { + [Constructable] + public SummonedDoppleganger() : base() + { + Name = "a doppleganger"; + Body = 0x309; + BaseSoundID = 0x451; + } + + public SummonedDoppleganger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedFrostSpider : BaseTalismanSummon + { + [Constructable] + public SummonedFrostSpider() : base() + { + Name = "a frost spider"; + Body = 20; + BaseSoundID = 0x388; + } + + public SummonedFrostSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedGreatHart : BaseTalismanSummon + { + [Constructable] + public SummonedGreatHart() : base() + { + Name = "a great hart"; + Body = 0xEA; + BaseSoundID = 0x82; + } + + public SummonedGreatHart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedLavaSerpent : BaseTalismanSummon + { + [Constructable] + public SummonedLavaSerpent() : base() + { + Name = "a lava serpent"; + Body = 90; + BaseSoundID = 219; + } + + public SummonedLavaSerpent( Serial serial ) : base( serial ) + { + } + + public override void OnThink() + { + /* + if ( m_NextWave < DateTime.Now ) + AreaHeatDamage(); + */ + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + + /* + // An area attack that only damages staff, wtf? + + private DateTime m_NextWave; + + public void AreaHeatDamage() + { + Mobile mob = ControlMaster; + + if ( mob != null ) + { + if ( mob.InRange( Location, 2 ) ) + { + if ( mob.AccessLevel != AccessLevel.Player ) + { + AOS.Damage( mob, Utility.Random( 2, 3 ), 0, 100, 0, 0, 0 ); + mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! + } + } + + GuardedRegion r = Region as GuardedRegion; + + if ( r != null && mob.Alive ) + { + foreach ( Mobile m in GetMobilesInRange( 2 ) ) + { + if ( !mob.CanBeHarmful( m ) ) + mob.CriminalAction( false ); + } + } + } + + m_NextWave = DateTime.Now + TimeSpan.FromSeconds( 3 ); + } + */ + } + + public class SummonedOrcBrute : BaseTalismanSummon + { + [Constructable] + public SummonedOrcBrute() : base() + { + Body = 189; + Name = "an orc brute"; + BaseSoundID = 0x45A; + } + + public SummonedOrcBrute( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedPanther : BaseTalismanSummon + { + [Constructable] + public SummonedPanther() : base() + { + Name = "a panther"; + Body = 0xD6; + Hue = 0x901; + BaseSoundID = 0x462; + } + + public SummonedPanther( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedSheep : BaseTalismanSummon + { + [Constructable] + public SummonedSheep() : base() + { + Name = "a sheep"; + Body = 0xCF; + BaseSoundID = 0xD6; + } + + public SummonedSheep( Serial serial ) : base( serial ) + { + } + + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedSkeletalKnight : BaseTalismanSummon + { + [Constructable] + public SummonedSkeletalKnight() : base() + { + Name = "a skeletal knight"; + Body = 147; + BaseSoundID = 451; + } + + public SummonedSkeletalKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedVorpalBunny : BaseTalismanSummon + { + [Constructable] + public SummonedVorpalBunny() : base() + { + Name = "a vorpal bunny"; + Body = 205; + Hue = 0x480; + BaseSoundID = 0xC9; + + Timer.DelayCall( TimeSpan.FromMinutes( 30.0 ), new TimerCallback( BeginTunnel ) ); + } + + public SummonedVorpalBunny( Serial serial ) : base( serial ) + { + } + + public virtual void BeginTunnel() + { + if ( Deleted ) + return; + + new BunnyHole().MoveToWorld( Location, Map ); + + Frozen = true; + Say( "* The bunny begins to dig a tunnel back to its underground lair *" ); + PlaySound( 0x247 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( Delete ) ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } + + public class SummonedWailingBanshee : BaseTalismanSummon + { + [Constructable] + public SummonedWailingBanshee() : base() + { + Name = "a wailing banshee"; + Body = 310; + BaseSoundID = 0x482; + } + + public SummonedWailingBanshee( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Traps/BaseTrap.cs b/Scripts/Items/Traps/BaseTrap.cs new file mode 100644 index 0000000..2897837 --- /dev/null +++ b/Scripts/Items/Traps/BaseTrap.cs @@ -0,0 +1,85 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseTrap : Item + { + public virtual bool PassivelyTriggered{ get{ return false; } } + public virtual TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public virtual int PassiveTriggerRange{ get{ return -1; } } + public virtual TimeSpan ResetDelay{ get{ return TimeSpan.Zero; } } + + private DateTime m_NextPassiveTrigger, m_NextActiveTrigger; + + public virtual void OnTrigger( Mobile from ) + { + } + + public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public virtual int GetEffectHue() + { + int hue = this.Hue & 0x3FFF; + + if ( hue < 2 ) + return 0; + + return hue - 1; + } + + public bool CheckRange( Point3D loc, Point3D oldLoc, int range ) + { + return CheckRange( loc, range ) && !CheckRange( oldLoc, range ); + } + + public bool CheckRange( Point3D loc, int range ) + { + return ( (this.Z + 8) >= loc.Z && (loc.Z + 16) > this.Z ) + && Utility.InRange( GetWorldLocation(), loc, range ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m.Location == oldLocation ) + return; + + if ( CheckRange( m.Location, oldLocation, 0 ) && DateTime.Now >= m_NextActiveTrigger ) + { + m_NextActiveTrigger = m_NextPassiveTrigger = DateTime.Now + ResetDelay; + + OnTrigger( m ); + } + else if ( PassivelyTriggered && CheckRange( m.Location, oldLocation, PassiveTriggerRange ) && DateTime.Now >= m_NextPassiveTrigger ) + { + m_NextPassiveTrigger = DateTime.Now + PassiveTriggerDelay; + + OnTrigger( m ); + } + } + + public BaseTrap( int itemID ) : base( itemID ) + { + Movable = false; + } + + public BaseTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/FireColumnTrap.cs b/Scripts/Items/Traps/FireColumnTrap.cs new file mode 100644 index 0000000..9f28dbf --- /dev/null +++ b/Scripts/Items/Traps/FireColumnTrap.cs @@ -0,0 +1,111 @@ +using System; + +namespace Server.Items +{ + public class FireColumnTrap : BaseTrap + { + [Constructable] + public FireColumnTrap() : base( 0x1B71 ) + { + m_MinDamage = 10; + m_MaxDamage = 40; + + m_WarningFlame = true; + } + + public override bool PassivelyTriggered{ get{ return true; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.FromSeconds( 2.0 ); } } + public override int PassiveTriggerRange{ get{ return 3; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.FromSeconds( 0.5 ); } } + + private int m_MinDamage; + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int MinDamage + { + get { return m_MinDamage; } + set { m_MinDamage = value; } + } + + private int m_MaxDamage; + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int MaxDamage + { + get { return m_MaxDamage; } + set { m_MaxDamage = value; } + } + + private bool m_WarningFlame; + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool WarningFlame + { + get { return m_WarningFlame; } + set { m_WarningFlame = value; } + } + + public override void OnTrigger( Mobile from ) + { + if ( from.AccessLevel > AccessLevel.Player ) + return; + + if ( WarningFlame ) + DoEffect(); + + if ( from.Alive && CheckRange( from.Location, 0 ) ) + { + Spells.SpellHelper.Damage( TimeSpan.FromSeconds( 0.5 ), from, from, Utility.RandomMinMax( MinDamage, MaxDamage ), 0, 100, 0, 0, 0 ); + + if ( !WarningFlame ) + DoEffect(); + } + } + + private void DoEffect() + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3709, 10, 30, 5052 ); + Effects.PlaySound( Location, Map, 0x225 ); + } + + public FireColumnTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_WarningFlame ); + writer.Write( m_MinDamage ); + writer.Write( m_MaxDamage ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_WarningFlame = reader.ReadBool(); + m_MinDamage = reader.ReadInt(); + m_MaxDamage = reader.ReadInt(); + break; + } + } + + if ( version == 0 ) + { + m_WarningFlame = true; + m_MinDamage = 10; + m_MaxDamage = 40; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/FlameSpurtTrap.cs b/Scripts/Items/Traps/FlameSpurtTrap.cs new file mode 100644 index 0000000..d3eec05 --- /dev/null +++ b/Scripts/Items/Traps/FlameSpurtTrap.cs @@ -0,0 +1,181 @@ +using System; + +namespace Server.Items +{ + public class FlameSpurtTrap : BaseTrap + { + private Item m_Spurt; + private Timer m_Timer; + + [Constructable] + public FlameSpurtTrap() : base( 0x1B71 ) + { + Visible = false; + } + + public virtual void StartTimer() + { + if ( m_Timer == null ) + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ), new TimerCallback( Refresh ) ); + } + + public virtual void StopTimer() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + } + + public virtual void CheckTimer() + { + Map map = this.Map; + + if ( map != null && map.GetSector( GetWorldLocation() ).Active ) + StartTimer(); + else + StopTimer(); + } + + public override void OnLocationChange( Point3D oldLocation ) + { + base.OnLocationChange( oldLocation ); + + CheckTimer(); + } + + public override void OnMapChange() + { + base.OnMapChange(); + + CheckTimer(); + } + + public override void OnSectorActivate() + { + base.OnSectorActivate(); + + StartTimer(); + } + + public override void OnSectorDeactivate() + { + base.OnSectorDeactivate(); + + StopTimer(); + } + + public override void OnDelete() + { + base.OnDelete(); + + if ( m_Spurt != null ) + m_Spurt.Delete(); + } + + public virtual void Refresh() + { + if ( Deleted ) + return; + + bool foundPlayer = false; + + foreach ( Mobile mob in GetMobilesInRange( 3 ) ) + { + if ( !mob.Player || !mob.Alive || mob.AccessLevel > AccessLevel.Player ) + continue; + + if ( ( (this.Z + 8) >= mob.Z && (mob.Z + 16) > this.Z ) ) + { + foundPlayer = true; + break; + } + } + + if ( !foundPlayer ) + { + if ( m_Spurt != null ) + m_Spurt.Delete(); + + m_Spurt = null; + } + else if ( m_Spurt == null || m_Spurt.Deleted ) + { + m_Spurt = new Static( 0x3709 ); + m_Spurt.MoveToWorld( this.Location, this.Map ); + + Effects.PlaySound( GetWorldLocation(), Map, 0x309 ); + } + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m.AccessLevel > AccessLevel.Player ) + return true; + + if ( m.Player && m.Alive ) + { + CheckTimer(); + + Spells.SpellHelper.Damage( TimeSpan.FromTicks( 1 ), m, m, Utility.RandomMinMax( 1, 30 ) ); + m.PlaySound( m.Female ? 0x327 : 0x437 ); + } + + return false; + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m.Location == oldLocation || !m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player ) + return; + + if ( CheckRange( m.Location, oldLocation, 1 ) ) + { + CheckTimer(); + + Spells.SpellHelper.Damage( TimeSpan.FromTicks( 1 ), m, m, Utility.RandomMinMax( 1, 10 ) ); + m.PlaySound( m.Female ? 0x327 : 0x437 ); + + if ( m.Body.IsHuman ) + m.Animate( 20, 1, 1, true, false, 0 ); + } + } + + public FlameSpurtTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Item) m_Spurt ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + Item item = reader.ReadItem(); + + if ( item != null ) + item.Delete(); + + CheckTimer(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/GasTrap.cs b/Scripts/Items/Traps/GasTrap.cs new file mode 100644 index 0000000..9676aa2 --- /dev/null +++ b/Scripts/Items/Traps/GasTrap.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public enum GasTrapType + { + NorthWall, + WestWall, + Floor + } + + public class GasTrap : BaseTrap + { + private Poison m_Poison; + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get{ return m_Poison; } + set{ m_Poison = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public GasTrapType Type + { + get + { + switch ( ItemID ) + { + case 0x113C: return GasTrapType.NorthWall; + case 0x1147: return GasTrapType.WestWall; + case 0x11A8: return GasTrapType.Floor; + } + + return GasTrapType.WestWall; + } + set + { + ItemID = GetBaseID( value ); + } + } + + public static int GetBaseID( GasTrapType type ) + { + switch ( type ) + { + case GasTrapType.NorthWall: return 0x113C; + case GasTrapType.WestWall: return 0x1147; + case GasTrapType.Floor: return 0x11A8; + } + + return 0; + } + + [Constructable] + public GasTrap() : this( GasTrapType.Floor ) + { + } + + [Constructable] + public GasTrap( GasTrapType type ) : this( type, Poison.Lesser ) + { + } + + [Constructable] + public GasTrap( Poison poison ) : this( GasTrapType.Floor, Poison.Lesser ) + { + } + + [Constructable] + public GasTrap( GasTrapType type, Poison poison ) : base( GetBaseID( type ) ) + { + m_Poison = poison; + } + + public override bool PassivelyTriggered{ get{ return false; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public override int PassiveTriggerRange{ get{ return 0; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.FromSeconds( 0.0 ); } } + + public override void OnTrigger( Mobile from ) + { + if ( m_Poison == null || !from.Player || !from.Alive || from.AccessLevel > AccessLevel.Player ) + return; + + Effects.SendLocationEffect( Location, Map, GetBaseID( this.Type ) - 2, 16, 3, GetEffectHue(), 0 ); + Effects.PlaySound( Location, Map, 0x231 ); + + from.ApplyPoison( from, m_Poison ); + + from.LocalOverheadMessage( MessageType.Regular, 0x22, 500855 ); // You are enveloped by a noxious gas cloud! + } + + public GasTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + Poison.Serialize( m_Poison, writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Poison = Poison.Deserialize( reader ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/GiantSpikeTrap.cs b/Scripts/Items/Traps/GiantSpikeTrap.cs new file mode 100644 index 0000000..276bdcc --- /dev/null +++ b/Scripts/Items/Traps/GiantSpikeTrap.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class GiantSpikeTrap : BaseTrap + { + [Constructable] + public GiantSpikeTrap() : base( 1 ) + { + } + + public override bool PassivelyTriggered{ get{ return true; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public override int PassiveTriggerRange{ get{ return 3; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.FromSeconds( 0.0 ); } } + + public override void OnTrigger( Mobile from ) + { + if ( from.AccessLevel > AccessLevel.Player ) + return; + + Effects.SendLocationEffect( Location, Map, 0x1D99, 48, 2, GetEffectHue(), 0 ); + + if ( from.Alive && CheckRange( from.Location, 0 ) ) + Spells.SpellHelper.Damage( TimeSpan.FromTicks( 1 ), from, from, Utility.Dice( 10, 7, 0 ) ); + } + + public GiantSpikeTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/MushroomTrap.cs b/Scripts/Items/Traps/MushroomTrap.cs new file mode 100644 index 0000000..a36cb6d --- /dev/null +++ b/Scripts/Items/Traps/MushroomTrap.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Network; +using Server.Regions; + +namespace Server.Items +{ + public class MushroomTrap : BaseTrap + { + [Constructable] + public MushroomTrap() : base( 0x1125 ) + { + } + + public override bool PassivelyTriggered{ get{ return true; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public override int PassiveTriggerRange{ get{ return 2; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.Zero; } } + + public override void OnTrigger( Mobile from ) + { + if ( !from.Alive || ItemID != 0x1125 || from.AccessLevel > AccessLevel.Player ) + return; + + ItemID = 0x1126; + Effects.PlaySound( Location, Map, 0x306 ); + + Spells.SpellHelper.Damage( TimeSpan.FromSeconds( 0.5 ), from, from, Utility.Dice( 2, 4, 0 ) ); + + Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerCallback( OnMushroomReset ) ); + } + + public virtual void OnMushroomReset() + { + if ( Region.Find( Location, Map ).IsPartOf( typeof( DungeonRegion ) ) ) + ItemID = 0x1125; // reset + else + Delete(); + } + + public MushroomTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ItemID == 0x1126 ) + OnMushroomReset(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/SawTrap.cs b/Scripts/Items/Traps/SawTrap.cs new file mode 100644 index 0000000..e5c3c7a --- /dev/null +++ b/Scripts/Items/Traps/SawTrap.cs @@ -0,0 +1,97 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public enum SawTrapType + { + WestWall, + NorthWall, + WestFloor, + NorthFloor + } + + public class SawTrap : BaseTrap + { + [CommandProperty( AccessLevel.GameMaster )] + public SawTrapType Type + { + get + { + switch ( ItemID ) + { + case 0x1103: return SawTrapType.NorthWall; + case 0x1116: return SawTrapType.WestWall; + case 0x11AC: return SawTrapType.NorthFloor; + case 0x11B1: return SawTrapType.WestFloor; + } + + return SawTrapType.NorthWall; + } + set + { + ItemID = GetBaseID( value ); + } + } + + public static int GetBaseID( SawTrapType type ) + { + switch ( type ) + { + case SawTrapType.NorthWall: return 0x1103; + case SawTrapType.WestWall: return 0x1116; + case SawTrapType.NorthFloor: return 0x11AC; + case SawTrapType.WestFloor: return 0x11B1; + } + + return 0; + } + + [Constructable] + public SawTrap() : this( SawTrapType.NorthFloor ) + { + } + + [Constructable] + public SawTrap( SawTrapType type ) : base( GetBaseID( type ) ) + { + } + + public override bool PassivelyTriggered{ get{ return false; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public override int PassiveTriggerRange{ get{ return 0; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.FromSeconds( 0.0 ); } } + + public override void OnTrigger( Mobile from ) + { + if ( !from.Alive || from.AccessLevel > AccessLevel.Player ) + return; + + Effects.SendLocationEffect( Location, Map, GetBaseID( this.Type ) + 1, 6, 3, GetEffectHue(), 0 ); + Effects.PlaySound( Location, Map, 0x21C ); + + Spells.SpellHelper.Damage( TimeSpan.FromTicks( 1 ), from, from, Utility.RandomMinMax( 5, 15 ) ); + + from.LocalOverheadMessage( MessageType.Regular, 0x22, 500853 ); // You stepped onto a blade trap! + } + + public SawTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/SpikeTrap.cs b/Scripts/Items/Traps/SpikeTrap.cs new file mode 100644 index 0000000..7eddf78 --- /dev/null +++ b/Scripts/Items/Traps/SpikeTrap.cs @@ -0,0 +1,150 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public enum SpikeTrapType + { + WestWall, + NorthWall, + WestFloor, + NorthFloor + } + + public class SpikeTrap : BaseTrap + { + [CommandProperty( AccessLevel.GameMaster )] + public SpikeTrapType Type + { + get + { + switch ( ItemID ) + { + case 4360: case 4361: case 4366: return SpikeTrapType.WestWall; + case 4379: case 4380: case 4385: return SpikeTrapType.NorthWall; + case 4506: case 4507: case 4511: return SpikeTrapType.WestFloor; + case 4512: case 4513: case 4517: return SpikeTrapType.NorthFloor; + } + + return SpikeTrapType.WestWall; + } + set + { + bool extended = this.Extended; + + ItemID = ( extended ? GetExtendedID( value ) : GetBaseID( value ) ); + } + } + + public bool Extended + { + get{ return ( ItemID == GetExtendedID( this.Type ) ); } + set + { + if ( value ) + ItemID = GetExtendedID( this.Type ); + else + ItemID = GetBaseID( this.Type ); + } + } + + public static int GetBaseID( SpikeTrapType type ) + { + switch ( type ) + { + case SpikeTrapType.WestWall: return 4360; + case SpikeTrapType.NorthWall: return 4379; + case SpikeTrapType.WestFloor: return 4506; + case SpikeTrapType.NorthFloor: return 4512; + } + + return 0; + } + + public static int GetExtendedID( SpikeTrapType type ) + { + return GetBaseID( type ) + GetExtendedOffset( type ); + } + + public static int GetExtendedOffset( SpikeTrapType type ) + { + switch ( type ) + { + case SpikeTrapType.WestWall: return 6; + case SpikeTrapType.NorthWall: return 6; + + case SpikeTrapType.WestFloor: return 5; + case SpikeTrapType.NorthFloor: return 5; + } + + return 0; + } + + [Constructable] + public SpikeTrap() : this( SpikeTrapType.WestFloor ) + { + } + + [Constructable] + public SpikeTrap( SpikeTrapType type ) : base( GetBaseID( type ) ) + { + } + + public override bool PassivelyTriggered{ get{ return false; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public override int PassiveTriggerRange{ get{ return 0; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.FromSeconds( 6.0 ); } } + + public override void OnTrigger( Mobile from ) + { + if ( !from.Alive || from.AccessLevel > AccessLevel.Player ) + return; + + Effects.SendLocationEffect( Location, Map, GetBaseID( this.Type ) + 1, 18, 3, GetEffectHue(), 0 ); + Effects.PlaySound( Location, Map, 0x22C ); + + foreach ( Mobile mob in GetMobilesInRange( 0 ) ) + { + if ( mob.Alive && !mob.IsDeadBondedPet ) + Spells.SpellHelper.Damage( TimeSpan.FromTicks( 1 ), mob, mob, Utility.RandomMinMax( 1, 6 ) * 6 ); + } + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerCallback( OnSpikeExtended ) ); + + from.LocalOverheadMessage( MessageType.Regular, 0x22, 500852 ); // You stepped onto a spike trap! + } + + public virtual void OnSpikeExtended() + { + Extended = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( OnSpikeRetracted ) ); + } + + public virtual void OnSpikeRetracted() + { + Extended = false; + Effects.SendLocationEffect( Location, Map, GetExtendedID( this.Type ) - 1, 6, 3, GetEffectHue(), 0 ); + } + + public SpikeTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Extended = false; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Traps/StoneFaceTrap.cs b/Scripts/Items/Traps/StoneFaceTrap.cs new file mode 100644 index 0000000..b1ce3b8 --- /dev/null +++ b/Scripts/Items/Traps/StoneFaceTrap.cs @@ -0,0 +1,163 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public enum StoneFaceTrapType + { + NorthWestWall, + NorthWall, + WestWall + } + + public class StoneFaceTrap : BaseTrap + { + [CommandProperty( AccessLevel.GameMaster )] + public StoneFaceTrapType Type + { + get + { + switch ( ItemID ) + { + case 0x10F5: case 0x10F6: case 0x10F7: return StoneFaceTrapType.NorthWestWall; + case 0x10FC: case 0x10FD: case 0x10FE: return StoneFaceTrapType.NorthWall; + case 0x110F: case 0x1110: case 0x1111: return StoneFaceTrapType.WestWall; + } + + return StoneFaceTrapType.NorthWestWall; + } + set + { + bool breathing = this.Breathing; + + ItemID = ( breathing ? GetFireID( value ) : GetBaseID( value ) ); + } + } + + public bool Breathing + { + get{ return ( ItemID == GetFireID( this.Type ) ); } + set + { + if ( value ) + ItemID = GetFireID( this.Type ); + else + ItemID = GetBaseID( this.Type ); + } + } + + public static int GetBaseID( StoneFaceTrapType type ) + { + switch ( type ) + { + case StoneFaceTrapType.NorthWestWall: return 0x10F5; + case StoneFaceTrapType.NorthWall: return 0x10FC; + case StoneFaceTrapType.WestWall: return 0x110F; + } + + return 0; + } + + public static int GetFireID( StoneFaceTrapType type ) + { + switch ( type ) + { + case StoneFaceTrapType.NorthWestWall: return 0x10F7; + case StoneFaceTrapType.NorthWall: return 0x10FE; + case StoneFaceTrapType.WestWall: return 0x1111; + } + + return 0; + } + + [Constructable] + public StoneFaceTrap() : base( 0x10FC ) + { + Light = LightType.Circle225; + } + + public override bool PassivelyTriggered{ get{ return true; } } + public override TimeSpan PassiveTriggerDelay{ get{ return TimeSpan.Zero; } } + public override int PassiveTriggerRange{ get{ return 2; } } + public override TimeSpan ResetDelay{ get{ return TimeSpan.Zero; } } + + public override void OnTrigger( Mobile from ) + { + if ( !from.Alive || from.AccessLevel > AccessLevel.Player ) + return; + + Effects.PlaySound( Location, Map, 0x359 ); + + Breathing = true; + + Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerCallback( FinishBreath ) ); + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerCallback( TriggerDamage ) ); + } + + public virtual void FinishBreath() + { + Breathing = false; + } + + public virtual void TriggerDamage() + { + foreach ( Mobile mob in GetMobilesInRange( 1 ) ) + { + if ( mob.Alive && !mob.IsDeadBondedPet && mob.AccessLevel == AccessLevel.Player ) + Spells.SpellHelper.Damage( TimeSpan.FromTicks( 1 ), mob, mob, Utility.Dice( 3, 15, 0 ) ); + } + } + + public StoneFaceTrap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Breathing = false; + } + } + + public class StoneFaceTrapNoDamage : StoneFaceTrap + { + [Constructable] + public StoneFaceTrapNoDamage() + { + } + + public StoneFaceTrapNoDamage( Serial serial ) : base( serial ) + { + } + + public override void TriggerDamage() + { + // nothing.. + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/TreasureChests/TreasureChestLevel1.cs b/Scripts/Items/TreasureChests/TreasureChestLevel1.cs new file mode 100644 index 0000000..5c201c1 --- /dev/null +++ b/Scripts/Items/TreasureChests/TreasureChestLevel1.cs @@ -0,0 +1,119 @@ +using System; + +namespace Server.Items +{ + public class TreasureChestLevel1 : LockableContainer + { + private const int m_Level = 1; + + public override bool Decays { get { return true; } } + + public override bool IsDecoContainer { get { return false; } } + + public override TimeSpan DecayTime { get { return TimeSpan.FromMinutes( Utility.Random( 15, 60 ) ); } } + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch( Utility.RandomList( 0, 1, 2 ) ) + { + case 0:// Large Crate + this.ItemID = ( UseFirstItemId ? 0xe3c : 0xe3d ); + this.GumpID = 0x44; + break; + + case 1:// Medium Crate + this.ItemID = ( UseFirstItemId ? 0xe3e : 0xe3f ); + this.GumpID = 0x44; + break; + + case 2:// Small Crate + this.ItemID = ( UseFirstItemId ? 0x9a9 : 0xe7e ); + this.GumpID = 0x44; + break; + } + } + + public override int DefaultGumpID { get { return 0x42; } } + + public override int DefaultDropSound { get { return 0x42; } } + + public override Rectangle2D Bounds + { + get { return new Rectangle2D( 18, 105, 144, 73 ); } + } + + [Constructable] + public TreasureChestLevel1() + : base( 0xE41 ) + { + this.SetChestAppearance(); + Movable = false; + + TrapType = TrapType.DartTrap; + TrapPower = m_Level * Utility.Random( 1, 25 ); + Locked = true; + + RequiredSkill = 57; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill + Utility.Random( 1, 10 ); + + // According to OSI, loot in level 1 chest is: + // Gold 25 - 50 + // Bolts 10 + // Gems + // Normal weapon + // Normal armour + // Normal clothing + // Normal jewelry + + // Gold + DropItem( new Gold( Utility.Random( 30, 100 ) ) ); + + // Drop bolts + //DropItem( new Bolt( 10 ) ); + + // Gems + if( Utility.RandomBool() == true ) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = Utility.Random( 1, 3 ); + DropItem( GemLoot ); + } + + // Weapon + if( Utility.RandomBool() == true ) + DropItem( Loot.RandomWeapon() ); + + // Armour + if( Utility.RandomBool() == true ) + DropItem( Loot.RandomArmorOrShield() ); + + // Clothing + if( Utility.RandomBool() == true ) + DropItem( Loot.RandomClothing() ); + + // Jewelry + if( Utility.RandomBool() == true ) + DropItem( Loot.RandomJewelry() ); + } + + public TreasureChestLevel1( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/TreasureChests/TreasureChestLevel2.cs b/Scripts/Items/TreasureChests/TreasureChestLevel2.cs new file mode 100644 index 0000000..073d322 --- /dev/null +++ b/Scripts/Items/TreasureChests/TreasureChestLevel2.cs @@ -0,0 +1,150 @@ +using System; + +namespace Server.Items +{ + public class TreasureChestLevel2 : LockableContainer + { + private const int m_Level = 2; + + public override bool Decays { get { return true; } } + + public override bool IsDecoContainer { get { return false; } } + + public override TimeSpan DecayTime { get { return TimeSpan.FromMinutes( Utility.Random( 15, 60 ) ); } } + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch( Utility.RandomList( 0, 1, 2, 3, 4, 5, 6, 7 ) ) + { + case 0:// Large Crate + this.ItemID = ( UseFirstItemId ? 0xe3c : 0xe3d ); + this.GumpID = 0x44; + break; + + case 1:// Medium Crate + this.ItemID = ( UseFirstItemId ? 0xe3e : 0xe3f ); + this.GumpID = 0x44; + break; + + case 2:// Small Crate + this.ItemID = ( UseFirstItemId ? 0x9a9 : 0xe7e ); + this.GumpID = 0x44; + break; + + case 3:// Wooden Chest + this.ItemID = ( UseFirstItemId ? 0xe42 : 0xe43 ); + this.GumpID = 0x49; + break; + + case 4:// Metal Chest + this.ItemID = ( UseFirstItemId ? 0x9ab : 0xe7c ); + this.GumpID = 0x4A; + break; + + case 5:// Metal Golden Chest + this.ItemID = ( UseFirstItemId ? 0xe40 : 0xe41 ); + this.GumpID = 0x42; + break; + + case 6:// Keg + this.ItemID = ( UseFirstItemId ? 0xe7f : 0xe7f ); + this.GumpID = 0x3e; + break; + + case 7:// Barrel + this.ItemID = ( UseFirstItemId ? 0xe77 : 0xe77 ); + this.GumpID = 0x3e; + break; + } + } + + public override int DefaultGumpID { get { return 0x42; } } + + public override int DefaultDropSound { get { return 0x42; } } + + public override Rectangle2D Bounds + { + get { return new Rectangle2D( 18, 105, 144, 73 ); } + } + + [Constructable] + public TreasureChestLevel2() + : base( 0xE41 ) + { + this.SetChestAppearance(); + Movable = false; + + TrapType = TrapType.ExplosionTrap; + TrapPower = m_Level * Utility.Random( 1, 25 ); + Locked = true; + + RequiredSkill = 72; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill + Utility.Random( 1, 10 ); ; + + // According to OSI, loot in level 2 chest is: + // Gold 80 - 150 + // Arrows 10 + // Reagents + // Scrolls + // Potions + // Gems + + // Gold + DropItem( new Gold( Utility.Random( 70, 100 ) ) ); + + // Drop bolts + //DropItem( new Arrow( 10 ) ); + + // Reagents + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random( 1, m_Level ); + DropItem( ReagentLoot ); + } + + // Scrolls + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item ScrollLoot = Loot.RandomScroll( 0, 39, SpellbookType.Regular ); + ScrollLoot.Amount = Utility.Random( 1, 8 ); + DropItem( ScrollLoot ); + } + + // Potions + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item PotionLoot = Loot.RandomPotion(); + DropItem( PotionLoot ); + } + + // Gems + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = Utility.Random( 1, 6 ); + DropItem( GemLoot ); + } + } + + public TreasureChestLevel2( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/TreasureChests/TreasureChestLevel3.cs b/Scripts/Items/TreasureChests/TreasureChestLevel3.cs new file mode 100644 index 0000000..35bb4ce --- /dev/null +++ b/Scripts/Items/TreasureChests/TreasureChestLevel3.cs @@ -0,0 +1,165 @@ +using System; + +namespace Server.Items +{ + public class TreasureChestLevel3 : LockableContainer + { + private const int m_Level = 3; + + public override bool Decays { get { return true; } } + + public override bool IsDecoContainer { get { return false; } } + + public override TimeSpan DecayTime { get { return TimeSpan.FromMinutes( Utility.Random( 15, 60 ) ); } } + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + switch( Utility.RandomList( 0, 1, 2 ) ) + { + case 0:// Wooden Chest + this.ItemID = ( UseFirstItemId ? 0xe42 : 0xe43 ); + this.GumpID = 0x49; + break; + + case 1:// Metal Chest + this.ItemID = ( UseFirstItemId ? 0x9ab : 0xe7c ); + this.GumpID = 0x4A; + break; + + case 2:// Metal Golden Chest + this.ItemID = ( UseFirstItemId ? 0xe40 : 0xe41 ); + this.GumpID = 0x42; + break; + } + } + + public override int DefaultGumpID { get { return 0x42; } } + + public override int DefaultDropSound { get { return 0x42; } } + + public override Rectangle2D Bounds + { + get { return new Rectangle2D( 18, 105, 144, 73 ); } + } + + [Constructable] + public TreasureChestLevel3() + : base( 0xE41 ) + { + this.SetChestAppearance(); + Movable = false; + + TrapType = TrapType.PoisonTrap; + TrapPower = m_Level * Utility.Random( 1, 25 ); + Locked = true; + + RequiredSkill = 84; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill + Utility.Random( 1, 10 ); ; + + // According to OSI, loot in level 3 chest is: + // Gold 250 - 350 + // Arrows 10 + // Reagents + // Scrolls + // Potions + // Gems + // Magic Wand + // Magic weapon + // Magic armour + // Magic clothing (not implemented) + // Magic jewelry (not implemented) + + // Gold + DropItem( new Gold( Utility.Random( 180, 240 ) ) ); + + // Drop bolts + //DropItem( new Arrow( 10 ) ); + + // Reagents + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = Utility.Random( 1, 9 ); + DropItem( ReagentLoot ); + } + + // Scrolls + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item ScrollLoot = Loot.RandomScroll( 0, 47, SpellbookType.Regular ); + ScrollLoot.Amount = Utility.Random( 1, 12 ); + DropItem( ScrollLoot ); + } + + // Potions + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item PotionLoot = Loot.RandomPotion(); + DropItem( PotionLoot ); + } + + // Gems + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = Utility.Random( 1, 9 ); + DropItem( GemLoot ); + } + + // Magic Wand + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + DropItem( Loot.RandomWand() ); + + // Equipment + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item item = Loot.RandomArmorOrShieldOrWeapon(); + + if( item is BaseWeapon ) + { + BaseWeapon weapon = ( BaseWeapon )item; + weapon.DamageLevel = ( WeaponDamageLevel )Utility.Random( m_Level ); + weapon.AccuracyLevel = ( WeaponAccuracyLevel )Utility.Random( m_Level ); + weapon.DurabilityLevel = ( WeaponDurabilityLevel )Utility.Random( m_Level ); + weapon.Quality = WeaponQuality.Regular; + } + else if( item is BaseArmor ) + { + BaseArmor armor = ( BaseArmor )item; + armor.ProtectionLevel = ( ArmorProtectionLevel )Utility.Random( m_Level ); + armor.Durability = ( ArmorDurabilityLevel )Utility.Random( m_Level ); + armor.Quality = ArmorQuality.Regular; + } + + DropItem( item ); + } + + // Clothing + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomClothing() ); + + // Jewelry + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomJewelry() ); + } + + public TreasureChestLevel3( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/TreasureChests/TreasureChestLevel4.cs b/Scripts/Items/TreasureChests/TreasureChestLevel4.cs new file mode 100644 index 0000000..214c0f9 --- /dev/null +++ b/Scripts/Items/TreasureChests/TreasureChestLevel4.cs @@ -0,0 +1,174 @@ +using System; + +namespace Server.Items +{ + public class TreasureChestLevel4 : LockableContainer + { + private const int m_Level = 4; + + public override bool Decays { get { return true; } } + + public override bool IsDecoContainer { get { return false; } } + + public override TimeSpan DecayTime { get { return TimeSpan.FromMinutes(Utility.Random(15, 60)); } } + + private void SetChestAppearance() + { + bool UseFirstItemId = Utility.RandomBool(); + + switch (Utility.Random(4)) + { + case 0:// Wooden Chest + this.ItemID = (UseFirstItemId ? 0xe42 : 0xe43); + this.GumpID = 0x49; + break; + + case 1:// Metal Chest + this.ItemID = (UseFirstItemId ? 0x9ab : 0xe7c); + this.GumpID = 0x4A; + break; + + case 2:// Metal Golden Chest + this.ItemID = (UseFirstItemId ? 0xe40 : 0xe41); + this.GumpID = 0x42; + break; + + case 3:// Keg + this.ItemID = 0xe7f; + this.GumpID = 0x3e; + break; + } + } + + public override int DefaultGumpID { get { return 0x42; } } + + public override int DefaultDropSound { get { return 0x42; } } + + public override Rectangle2D Bounds + { + get { return new Rectangle2D( 18, 105, 144, 73 ); } + } + + [Constructable] + public TreasureChestLevel4() + : base( 0xE41 ) + { + this.SetChestAppearance(); + Movable = false; + + TrapType = TrapType.ExplosionTrap; + TrapPower = m_Level * Utility.Random( 10, 25 ); + Locked = true; + + RequiredSkill = 92; + LockLevel = this.RequiredSkill - Utility.Random( 1, 10 ); + MaxLockLevel = this.RequiredSkill + Utility.Random( 1, 10 ); ; + + // According to OSI, loot in level 4 chest is: + // Gold 500 - 900 + // Reagents + // Scrolls + // Blank scrolls + // Potions + // Gems + // Magic Wand + // Magic weapon + // Magic armour + // Magic clothing (not implemented) + // Magic jewelry (not implemented) + // Crystal ball (not implemented) + + // Gold + DropItem( new Gold( Utility.Random( 200, 400 ) ) ); + + // Reagents + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item ReagentLoot = Loot.RandomReagent(); + ReagentLoot.Amount = 12; + DropItem( ReagentLoot ); + } + + // Scrolls + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item ScrollLoot = Loot.RandomScroll( 0, 47, SpellbookType.Regular ); + ScrollLoot.Amount = 16; + DropItem( ScrollLoot ); + } + + // Drop blank scrolls + DropItem( new BlankScroll( Utility.Random( 1, m_Level ) ) ); + + // Potions + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item PotionLoot = Loot.RandomPotion(); + DropItem( PotionLoot ); + } + + // Gems + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item GemLoot = Loot.RandomGem(); + GemLoot.Amount = 12; + DropItem( GemLoot ); + } + + // Magic Wand + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + DropItem( Loot.RandomWand() ); + + // Equipment + for( int i = Utility.Random( 1, m_Level ); i > 1; i-- ) + { + Item item = Loot.RandomArmorOrShieldOrWeapon(); + + if( item is BaseWeapon ) + { + BaseWeapon weapon = ( BaseWeapon )item; + weapon.DamageLevel = ( WeaponDamageLevel )Utility.Random( m_Level ); + weapon.AccuracyLevel = ( WeaponAccuracyLevel )Utility.Random( m_Level ); + weapon.DurabilityLevel = ( WeaponDurabilityLevel )Utility.Random( m_Level ); + weapon.Quality = WeaponQuality.Regular; + } + else if( item is BaseArmor ) + { + BaseArmor armor = ( BaseArmor )item; + armor.ProtectionLevel = ( ArmorProtectionLevel )Utility.Random( m_Level ); + armor.Durability = ( ArmorDurabilityLevel )Utility.Random( m_Level ); + armor.Quality = ArmorQuality.Regular; + } + + DropItem( item ); + } + + // Clothing + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomClothing() ); + + // Jewelry + for( int i = Utility.Random( 1, 2 ); i > 1; i-- ) + DropItem( Loot.RandomJewelry() ); + + // Crystal ball (not implemented) + } + + public TreasureChestLevel4( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( ( int )1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/BaseWand.cs b/Scripts/Items/Wands/BaseWand.cs new file mode 100644 index 0000000..587c35a --- /dev/null +++ b/Scripts/Items/Wands/BaseWand.cs @@ -0,0 +1,254 @@ +using System; +using System.Text; +using System.Collections; +using Server.Network; +using Server.Targeting; +using Server.Spells; + +namespace Server.Items +{ + public enum WandEffect + { + Clumsiness, + Identification, + Healing, + Feeblemindedness, + Weakness, + MagicArrow, + Harming, + Fireball, + GreaterHealing, + Lightning, + ManaDraining + } + + public abstract class BaseWand : BaseBashing, ITokunoDyable + { + public override WeaponAbility PrimaryAbility { get { return WeaponAbility.Dismount; } } + public override WeaponAbility SecondaryAbility { get { return WeaponAbility.Disarm; } } + + public override int AosStrengthReq { get { return 5; } } + public override int AosMinDamage { get { return 9; } } + public override int AosMaxDamage { get { return 11; } } + public override int AosSpeed { get { return 40; } } + public override float MlSpeed { get { return 2.75f; } } + + public override int OldStrengthReq { get { return 0; } } + public override int OldMinDamage { get { return 2; } } + public override int OldMaxDamage { get { return 6; } } + public override int OldSpeed { get { return 35; } } + + public override int InitMinHits { get { return 31; } } + public override int InitMaxHits { get { return 110; } } + + private WandEffect m_WandEffect; + private int m_Charges; + + public virtual TimeSpan GetUseDelay{ get{ return TimeSpan.FromSeconds( 4.0 ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public WandEffect Effect + { + get{ return m_WandEffect; } + set{ m_WandEffect = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set{ m_Charges = value; InvalidateProperties(); } + } + + public BaseWand( WandEffect effect, int minCharges, int maxCharges ) : base( Utility.RandomList( 0xDF2, 0xDF3, 0xDF4, 0xDF5 ) ) + { + Weight = 1.0; + Effect = effect; + Charges = Utility.RandomMinMax( minCharges, maxCharges ); + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + WeaponAttributes.MageWeapon = Utility.RandomMinMax(1, 10); + } + + public void ConsumeCharge( Mobile from ) + { + --Charges; + + if ( Charges == 0 ) + from.SendLocalizedMessage( 1019073 ); // This item is out of charges. + + ApplyDelayTo( from ); + } + + public BaseWand( Serial serial ) : base( serial ) + { + } + + public virtual void ApplyDelayTo( Mobile from ) + { + from.BeginAction( typeof( BaseWand ) ); + Timer.DelayCall( GetUseDelay, new TimerStateCallback( ReleaseWandLock_Callback ), from ); + } + + public virtual void ReleaseWandLock_Callback( object state ) + { + ((Mobile)state).EndAction( typeof( BaseWand ) ); + } + + public override void OnDoubleClick( Mobile from ) + { + if (!from.CanBeginAction(typeof(BaseWand))) + { + from.SendLocalizedMessage(1070860); // You must wait a moment for the wand to recharge. + return; + } + + if ( Parent == from ) + { + if ( Charges > 0 ) + OnWandUse( from ); + else + from.SendLocalizedMessage( 1019073 ); // This item is out of charges. + } + else + { + from.SendLocalizedMessage( 502641 ); // You must equip this item to use it. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_WandEffect ); + writer.Write( (int) m_Charges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_WandEffect = (WandEffect)reader.ReadInt(); + m_Charges = (int)reader.ReadInt(); + + break; + } + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + switch ( m_WandEffect ) + { + case WandEffect.Clumsiness: list.Add( 1017326, m_Charges.ToString() ); break; // clumsiness charges: ~1_val~ + case WandEffect.Identification: list.Add( 1017350, m_Charges.ToString() ); break; // identification charges: ~1_val~ + case WandEffect.Healing: list.Add( 1017329, m_Charges.ToString() ); break; // healing charges: ~1_val~ + case WandEffect.Feeblemindedness: list.Add( 1017327, m_Charges.ToString() ); break; // feeblemind charges: ~1_val~ + case WandEffect.Weakness: list.Add( 1017328, m_Charges.ToString() ); break; // weakness charges: ~1_val~ + case WandEffect.MagicArrow: list.Add( 1060492, m_Charges.ToString() ); break; // magic arrow charges: ~1_val~ + case WandEffect.Harming: list.Add( 1017334, m_Charges.ToString() ); break; // harm charges: ~1_val~ + case WandEffect.Fireball: list.Add( 1060487, m_Charges.ToString() ); break; // fireball charges: ~1_val~ + case WandEffect.GreaterHealing: list.Add( 1017330, m_Charges.ToString() ); break; // greater healing charges: ~1_val~ + case WandEffect.Lightning: list.Add( 1060491, m_Charges.ToString() ); break; // lightning charges: ~1_val~ + case WandEffect.ManaDraining: list.Add( 1017339, m_Charges.ToString() ); break; // mana drain charges: ~1_val~ + } + } + + public override void OnSingleClick( Mobile from ) + { + ArrayList attrs = new ArrayList(); + + if ( DisplayLootType ) + { + if ( LootType == LootType.Blessed ) + attrs.Add( new EquipInfoAttribute( 1038021 ) ); // blessed + else if ( LootType == LootType.Cursed ) + attrs.Add( new EquipInfoAttribute( 1049643 ) ); // cursed + } + + if ( !Identified ) + { + attrs.Add( new EquipInfoAttribute( 1038000 ) ); // Unidentified + } + else + { + int num = 0; + + switch ( m_WandEffect ) + { + case WandEffect.Clumsiness: num = 3002011; break; + case WandEffect.Identification: num = 1044063; break; + case WandEffect.Healing: num = 3002014; break; + case WandEffect.Feeblemindedness: num = 3002013; break; + case WandEffect.Weakness: num = 3002018; break; + case WandEffect.MagicArrow: num = 3002015; break; + case WandEffect.Harming: num = 3002022; break; + case WandEffect.Fireball: num = 3002028; break; + case WandEffect.GreaterHealing: num = 3002039; break; + case WandEffect.Lightning: num = 3002040; break; + case WandEffect.ManaDraining: num = 3002041; break; + } + + if ( num > 0 ) + attrs.Add( new EquipInfoAttribute( num, m_Charges ) ); + } + + int number; + + if ( Name == null ) + { + number = 1017085; + } + else + { + this.LabelTo( from, Name ); + number = 1041000; + } + + if ( attrs.Count == 0 && Crafter == null && Name != null ) + return; + + EquipmentInfo eqInfo = new EquipmentInfo( number, Crafter, false, (EquipInfoAttribute[])attrs.ToArray( typeof( EquipInfoAttribute ) ) ); + + from.Send( new DisplayEquipmentInfo( this, eqInfo ) ); + } + + public void Cast( Spell spell ) + { + bool m = Movable; + + Movable = false; + spell.Cast(); + Movable = m; + } + + public virtual void OnWandUse( Mobile from ) + { + from.Target = new WandTarget( this ); + } + + public virtual void DoWandTarget( Mobile from, object o ) + { + if ( Deleted || Charges <= 0 || Parent != from || o is StaticTarget || o is LandTarget ) + return; + + if ( OnWandTarget( from, o ) ) + ConsumeCharge( from ); + } + + public virtual bool OnWandTarget( Mobile from, object o ) + { + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/ClumsyWand.cs b/Scripts/Items/Wands/ClumsyWand.cs new file mode 100644 index 0000000..56ee6a0 --- /dev/null +++ b/Scripts/Items/Wands/ClumsyWand.cs @@ -0,0 +1,38 @@ +using System; +using Server; +using Server.Spells.First; +using Server.Targeting; + +namespace Server.Items +{ + public class ClumsyWand : BaseWand + { + [Constructable] + public ClumsyWand() : base( WandEffect.Clumsiness, 5, 30 ) + { + } + + public ClumsyWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new ClumsySpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/FeebleWand.cs b/Scripts/Items/Wands/FeebleWand.cs new file mode 100644 index 0000000..5030532 --- /dev/null +++ b/Scripts/Items/Wands/FeebleWand.cs @@ -0,0 +1,38 @@ +using System; +using Server; +using Server.Spells.First; +using Server.Targeting; + +namespace Server.Items +{ + public class FeebleWand : BaseWand + { + [Constructable] + public FeebleWand() : base( WandEffect.Feeblemindedness, 5, 30 ) + { + } + + public FeebleWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new FeeblemindSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/FireballWand.cs b/Scripts/Items/Wands/FireballWand.cs new file mode 100644 index 0000000..ca41b0c --- /dev/null +++ b/Scripts/Items/Wands/FireballWand.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Spells.Third; +using Server.Targeting; + +namespace Server.Items +{ + public class FireballWand : BaseWand + { + [Constructable] + public FireballWand() + : base(WandEffect.Fireball, 5, Core.ML ? 109 : 15) + { + } + + public FireballWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new FireballSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/GreaterHealWand.cs b/Scripts/Items/Wands/GreaterHealWand.cs new file mode 100644 index 0000000..6126f72 --- /dev/null +++ b/Scripts/Items/Wands/GreaterHealWand.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Spells.Fourth; +using Server.Targeting; + +namespace Server.Items +{ + public class GreaterHealWand : BaseWand + { + [Constructable] + public GreaterHealWand() + : base(WandEffect.GreaterHealing, 1, Core.ML ? 109 : 5) + { + } + + public GreaterHealWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new GreaterHealSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/HarmWand.cs b/Scripts/Items/Wands/HarmWand.cs new file mode 100644 index 0000000..22921ea --- /dev/null +++ b/Scripts/Items/Wands/HarmWand.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Spells.Second; +using Server.Targeting; + +namespace Server.Items +{ + public class HarmWand : BaseWand + { + [Constructable] + public HarmWand() + : base(WandEffect.Harming, 5, Core.ML ? 109 : 30) + { + } + + public HarmWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new HarmSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/HealWand.cs b/Scripts/Items/Wands/HealWand.cs new file mode 100644 index 0000000..4722f2c --- /dev/null +++ b/Scripts/Items/Wands/HealWand.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Spells.First; +using Server.Targeting; + +namespace Server.Items +{ + public class HealWand : BaseWand + { + [Constructable] + public HealWand() + : base(WandEffect.Healing, 10, Core.ML ? 109 : 25) + { + } + + public HealWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new HealSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/IDWand.cs b/Scripts/Items/Wands/IDWand.cs new file mode 100644 index 0000000..7358289 --- /dev/null +++ b/Scripts/Items/Wands/IDWand.cs @@ -0,0 +1,472 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Items +{ + public class IDWand : BaseWand + { + public override TimeSpan GetUseDelay { get { return TimeSpan.Zero; } } + + [Constructable] + public IDWand() + : base(WandEffect.Identification, 25, 50) + { + Name = "Baguette d'identification"; + } + + public IDWand(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override bool OnWandTarget(Mobile from, object o) + { + int difficulty = 0; + #region BaseWeapon + if (o is BaseWeapon && !((BaseWeapon)o).Identified) + { + BaseWeapon idarme = (BaseWeapon)o; + + if (idarme.Attributes.AttackChance != 0) + difficulty++; + if (idarme.Attributes.BonusDex != 0) + difficulty++; + if (idarme.Attributes.BonusHits != 0) + difficulty++; + if (idarme.Attributes.BonusInt != 0) + difficulty++; + if (idarme.Attributes.BonusMana != 0) + difficulty++; + if (idarme.Attributes.BonusStam != 0) + difficulty++; + if (idarme.Attributes.BonusStr != 0) + difficulty++; + if (idarme.Attributes.CastRecovery != 0) + difficulty++; + if (idarme.Attributes.CastSpeed != 0) + difficulty++; + if (idarme.Attributes.DefendChance != 0) + difficulty++; + if (idarme.Attributes.EnhancePotions != 0) + difficulty++; + if (idarme.Attributes.LowerManaCost != 0) + difficulty++; + if (idarme.Attributes.LowerRegCost != 0) + difficulty++; + if (idarme.Attributes.Luck != 0) + difficulty++; + if (idarme.Attributes.NightSight != 0) + difficulty++; + if (idarme.Attributes.ReflectPhysical != 0) + difficulty++; + if (idarme.Attributes.RegenHits != 0) + difficulty++; + if (idarme.Attributes.RegenMana != 0) + difficulty++; + if (idarme.Attributes.RegenStam != 0) + difficulty++; + if (idarme.Attributes.SpellChanneling != 0) + difficulty++; + if (idarme.Attributes.SpellDamage != 0) + difficulty++; + if (idarme.Attributes.WeaponDamage != 0) + difficulty++; + if (idarme.Attributes.WeaponSpeed != 0) + difficulty++; + if (idarme.WeaponAttributes.DurabilityBonus != 0) + difficulty++; + if (idarme.WeaponAttributes.HitColdArea != 0) + difficulty++; + if (idarme.WeaponAttributes.HitDispel != 0) + difficulty++; + if (idarme.WeaponAttributes.HitEnergyArea != 0) + difficulty++; + if (idarme.WeaponAttributes.HitFireArea != 0) + difficulty++; + if (idarme.WeaponAttributes.HitFireball != 0) + difficulty++; + if (idarme.WeaponAttributes.HitHarm != 0) + difficulty++; + if (idarme.WeaponAttributes.HitLeechHits != 0) + difficulty++; + if (idarme.WeaponAttributes.HitLeechMana != 0) + difficulty++; + if (idarme.WeaponAttributes.HitLeechStam != 0) + difficulty++; + if (idarme.WeaponAttributes.HitLightning != 0) + difficulty++; + if (idarme.WeaponAttributes.HitLowerAttack != 0) + difficulty++; + if (idarme.WeaponAttributes.HitLowerDefend != 0) + difficulty++; + if (idarme.WeaponAttributes.HitMagicArrow != 0) + difficulty++; + if (idarme.WeaponAttributes.HitPhysicalArea != 0) + difficulty++; + if (idarme.WeaponAttributes.HitPoisonArea != 0) + difficulty++; + if (idarme.WeaponAttributes.LowerStatReq != 0) + difficulty++; + if (idarme.WeaponAttributes.MageWeapon != 0) + difficulty++; + if (idarme.WeaponAttributes.ResistColdBonus != 0) + difficulty++; + if (idarme.WeaponAttributes.ResistEnergyBonus != 0) + difficulty++; + if (idarme.WeaponAttributes.ResistFireBonus != 0) + difficulty++; + if (idarme.WeaponAttributes.ResistPhysicalBonus != 0) + difficulty++; + if (idarme.WeaponAttributes.ResistPoisonBonus != 0) + difficulty++; + if (idarme.WeaponAttributes.SelfRepair != 0) + difficulty++; + if (idarme.WeaponAttributes.UseBestSkill != 0) + difficulty++; + if (idarme.Slayer != SlayerName.None) + difficulty++; + if (idarme.Slayer2 != SlayerName.None ) + difficulty++; + if (idarme.SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (idarme.SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (idarme.SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (idarme.SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (idarme.SkillBonuses.Skill_5_Value != 0) + difficulty++; + + difficulty -= 2; + + if (difficulty > 5) + difficulty = 5; + + if (difficulty < 4) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s de l'arme"); + idarme.Identified = true; + } + else + { + from.SendMessage("Cette arme renferme trop de magie pour �tre ainsi identifi�e"); + } + } + #endregion + #region BaseArmor + else if (o is BaseArmor && !((BaseArmor)o).Identified) + { + BaseArmor idarmure = (BaseArmor)o; + + if (idarmure.Attributes.AttackChance != 0) + difficulty++; + if (idarmure.Attributes.BonusDex != 0) + difficulty++; + if (idarmure.Attributes.BonusHits != 0) + difficulty++; + if (idarmure.Attributes.BonusInt != 0) + difficulty++; + if (idarmure.Attributes.BonusMana != 0) + difficulty++; + if (idarmure.Attributes.BonusStam != 0) + difficulty++; + if (idarmure.Attributes.BonusStr != 0) + difficulty++; + if (idarmure.Attributes.CastRecovery != 0) + difficulty++; + if (idarmure.Attributes.CastSpeed != 0) + difficulty++; + if (idarmure.Attributes.DefendChance != 0) + difficulty++; + if (idarmure.Attributes.EnhancePotions != 0) + difficulty++; + if (idarmure.Attributes.LowerManaCost != 0) + difficulty++; + if (idarmure.Attributes.LowerRegCost != 0) + difficulty++; + if (idarmure.Attributes.Luck != 0) + difficulty++; + if (idarmure.Attributes.NightSight != 0) + difficulty++; + if (idarmure.Attributes.ReflectPhysical != 0) + difficulty++; + if (idarmure.Attributes.RegenHits != 0) + difficulty++; + if (idarmure.Attributes.RegenMana != 0) + difficulty++; + if (idarmure.Attributes.RegenStam != 0) + difficulty++; + if (idarmure.Attributes.SpellChanneling != 0) + difficulty++; + if (idarmure.Attributes.SpellDamage != 0) + difficulty++; + if (idarmure.Attributes.WeaponDamage != 0) + difficulty++; + if (idarmure.Attributes.WeaponSpeed != 0) + difficulty++; + if (idarmure.ArmorAttributes.DurabilityBonus != 0) + difficulty++; + if (idarmure.ArmorAttributes.LowerStatReq != 0) + difficulty++; + if (idarmure.ArmorAttributes.MageArmor != 0) + difficulty++; + if (idarmure.SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (idarmure.SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (idarmure.SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (idarmure.SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (idarmure.SkillBonuses.Skill_5_Value != 0) + difficulty++; + if (idarmure.ColdBonus != 0) + difficulty++; + if (idarmure.PhysicalBonus != 0) + difficulty++; + if (idarmure.FireBonus != 0) + difficulty++; + if (idarmure.PoisonBonus != 0) + difficulty++; + if (idarmure.EnergyBonus != 0) + difficulty++; + + if (difficulty > 5) + difficulty = 5; + + if (difficulty <= 3) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s de l'armure"); + idarmure.Identified = true; + } + else + { + from.SendMessage("Cette armure renferme trop de magie pour �tre ainsi identifi�e"); + } + } + #endregion + #region BaseClothing + else if (o is BaseClothing && !((BaseClothing)o).Identified) + { + BaseClothing idclothing = (BaseClothing)o; + + if (idclothing.Attributes.AttackChance != 0) + difficulty++; + if (idclothing.Attributes.BonusDex != 0) + difficulty++; + if (idclothing.Attributes.BonusHits != 0) + difficulty++; + if (idclothing.Attributes.BonusInt != 0) + difficulty++; + if (idclothing.Attributes.BonusMana != 0) + difficulty++; + if (idclothing.Attributes.BonusStam != 0) + difficulty++; + if (idclothing.Attributes.BonusStr != 0) + difficulty++; + if (idclothing.Attributes.CastRecovery != 0) + difficulty++; + if (idclothing.Attributes.CastSpeed != 0) + difficulty++; + if (idclothing.Attributes.DefendChance != 0) + difficulty++; + if (idclothing.Attributes.EnhancePotions != 0) + difficulty++; + if (idclothing.Attributes.LowerManaCost != 0) + difficulty++; + if (idclothing.Attributes.LowerRegCost != 0) + difficulty++; + if (idclothing.Attributes.Luck != 0) + difficulty++; + if (idclothing.Attributes.NightSight != 0) + difficulty++; + if (idclothing.Attributes.ReflectPhysical != 0) + difficulty++; + if (idclothing.Attributes.RegenHits != 0) + difficulty++; + if (idclothing.Attributes.RegenMana != 0) + difficulty++; + if (idclothing.Attributes.RegenStam != 0) + difficulty++; + if (idclothing.Attributes.SpellChanneling != 0) + difficulty++; + if (idclothing.Attributes.SpellDamage != 0) + difficulty++; + if (idclothing.Attributes.WeaponDamage != 0) + difficulty++; + if (idclothing.Attributes.WeaponSpeed != 0) + difficulty++; + if (idclothing.ClothingAttributes.DurabilityBonus != 0) + difficulty++; + if (idclothing.ClothingAttributes.LowerStatReq != 0) + difficulty++; + if (idclothing.ClothingAttributes.MageArmor != 0) + difficulty++; + if (idclothing.ClothingAttributes.SelfRepair != 0) + difficulty++; + if (idclothing.SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (idclothing.SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (idclothing.SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (idclothing.SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (idclothing.SkillBonuses.Skill_5_Value != 0) + difficulty++; + if (!(idclothing is BaseHat)) + { + if (idclothing.Resistances.Chaos != 0) + difficulty++; + if (idclothing.Resistances.Cold != 0) + difficulty++; + if (idclothing.Resistances.Direct != 0) + difficulty++; + if (idclothing.Resistances.Energy != 0) + difficulty++; + if (idclothing.Resistances.Fire != 0) + difficulty++; + if (idclothing.Resistances.Physical != 0) + difficulty++; + if (idclothing.Resistances.Poison != 0) + difficulty++; + } + + if (difficulty > 5) + difficulty = 5; + + if (difficulty <= 3) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s du v�tement"); + idclothing.Identified = true; + } + else + { + from.SendMessage("Ce v�tement renferme trop de magie pour �tre ainsi identifi�e"); + } + } + #endregion + #region BaseJewel + else if (o is BaseJewel && !((BaseJewel)o).Identified) + { + BaseJewel idjewel = (BaseJewel)o; + + if (idjewel.Attributes.AttackChance != 0) + difficulty++; + if (idjewel.Attributes.BonusDex != 0) + difficulty++; + if (idjewel.Attributes.BonusHits != 0) + difficulty++; + if (idjewel.Attributes.BonusInt != 0) + difficulty++; + if (idjewel.Attributes.BonusMana != 0) + difficulty++; + if (idjewel.Attributes.BonusStam != 0) + difficulty++; + if (idjewel.Attributes.BonusStr != 0) + difficulty++; + if (idjewel.Attributes.CastRecovery != 0) + difficulty++; + if (idjewel.Attributes.CastSpeed != 0) + difficulty++; + if (idjewel.Attributes.DefendChance != 0) + difficulty++; + if (idjewel.Attributes.EnhancePotions != 0) + difficulty++; + if (idjewel.Attributes.LowerManaCost != 0) + difficulty++; + if (idjewel.Attributes.LowerRegCost != 0) + difficulty++; + if (idjewel.Attributes.Luck != 0) + difficulty++; + if (idjewel.Attributes.NightSight != 0) + difficulty++; + if (idjewel.Attributes.ReflectPhysical != 0) + difficulty++; + if (idjewel.Attributes.RegenHits != 0) + difficulty++; + if (idjewel.Attributes.RegenMana != 0) + difficulty++; + if (idjewel.Attributes.RegenStam != 0) + difficulty++; + if (idjewel.Attributes.SpellChanneling != 0) + difficulty++; + if (idjewel.Attributes.SpellDamage != 0) + difficulty++; + if (idjewel.Attributes.WeaponDamage != 0) + difficulty++; + if (idjewel.Attributes.WeaponSpeed != 0) + difficulty++; + if (idjewel.Resistances.Chaos != 0) + difficulty++; + if (idjewel.Resistances.Cold != 0) + difficulty++; + if (idjewel.Resistances.Direct != 0) + difficulty++; + if (idjewel.Resistances.Energy != 0) + difficulty++; + if (idjewel.Resistances.Fire != 0) + difficulty++; + if (idjewel.Resistances.Physical != 0) + difficulty++; + if (idjewel.Resistances.Poison != 0) + difficulty++; + if (idjewel.SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (idjewel.SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (idjewel.SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (idjewel.SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (idjewel.SkillBonuses.Skill_5_Value != 0) + difficulty++; + + if (difficulty > 5) + difficulty = 5; + + if (difficulty <= 3) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s du bijou"); + idjewel.Identified = true; + } + else + { + from.SendMessage("Ce bjou renferme trop de magie pour �tre ainsi identifi�e"); + } + } + else + { + from.SendMessage("Cet objet est d�j� identifi�"); + } + #endregion + + if (!Core.AOS && o is Item) + ((Item)o).OnSingleClick(from); + + return (o is Item); + } + } +} + + + + + + \ No newline at end of file diff --git a/Scripts/Items/Wands/LightningWand.cs b/Scripts/Items/Wands/LightningWand.cs new file mode 100644 index 0000000..f3b7915 --- /dev/null +++ b/Scripts/Items/Wands/LightningWand.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Spells.Fourth; +using Server.Targeting; + +namespace Server.Items +{ + public class LightningWand : BaseWand + { + [Constructable] + public LightningWand() + : base(WandEffect.Lightning, 5, Core.ML ? 109 : 20) + { + } + + public LightningWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new LightningSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/MagicArrowWand.cs b/Scripts/Items/Wands/MagicArrowWand.cs new file mode 100644 index 0000000..f465f77 --- /dev/null +++ b/Scripts/Items/Wands/MagicArrowWand.cs @@ -0,0 +1,39 @@ +using System; +using Server; +using Server.Spells.First; +using Server.Targeting; + +namespace Server.Items +{ + public class MagicArrowWand : BaseWand + { + [Constructable] + public MagicArrowWand() + : base(WandEffect.MagicArrow, 5, Core.ML ? 109 : 30) + { + } + + public MagicArrowWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new MagicArrowSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/ManaDrainWand.cs b/Scripts/Items/Wands/ManaDrainWand.cs new file mode 100644 index 0000000..4ba70fa --- /dev/null +++ b/Scripts/Items/Wands/ManaDrainWand.cs @@ -0,0 +1,38 @@ +using System; +using Server; +using Server.Spells.Fourth; +using Server.Targeting; + +namespace Server.Items +{ + public class ManaDrainWand : BaseWand + { + [Constructable] + public ManaDrainWand() : base( WandEffect.ManaDraining, 5, 30 ) + { + } + + public ManaDrainWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new ManaDrainSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/RandomWand.cs b/Scripts/Items/Wands/RandomWand.cs new file mode 100644 index 0000000..662377e --- /dev/null +++ b/Scripts/Items/Wands/RandomWand.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Items +{ + public class RandomWand + { + public static BaseWand CreateWand() + { + return CreateRandomWand(); + } + + public static BaseWand CreateRandomWand() + { + return Loot.RandomWand(); + + /* + switch ( Utility.Random( 11 ) ) + { + default: + case 0: return new ClumsyWand(); + case 1: return new FeebleWand(); + case 2: return new FireballWand(); + case 3: return new GreaterHealWand(); + case 4: return new HarmWand(); + case 5: return new HealWand(); + case 6: return new IDWand(); + case 7: return new LightningWand(); + case 8: return new MagicArrowWand(); + case 9: return new ManaDrainWand(); + case 10: return new WeaknessWand(); + } + */ + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/WandTarget.cs b/Scripts/Items/Wands/WandTarget.cs new file mode 100644 index 0000000..2808f60 --- /dev/null +++ b/Scripts/Items/Wands/WandTarget.cs @@ -0,0 +1,26 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Targeting +{ + public class WandTarget : Target + { + private BaseWand m_Item; + + public WandTarget( BaseWand item ) : base( 6, false, TargetFlags.None ) + { + m_Item = item; + } + + private static int GetOffset( Mobile caster ) + { + return 5 + (int)(caster.Skills[SkillName.Magery].Value * 0.02 ); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + m_Item.DoWandTarget( from, targeted ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Wands/WeaknessWand.cs b/Scripts/Items/Wands/WeaknessWand.cs new file mode 100644 index 0000000..89f38a3 --- /dev/null +++ b/Scripts/Items/Wands/WeaknessWand.cs @@ -0,0 +1,38 @@ +using System; +using Server; +using Server.Spells.First; +using Server.Targeting; + +namespace Server.Items +{ + public class WeaknessWand : BaseWand + { + [Constructable] + public WeaknessWand() : base( WandEffect.Weakness, 5, 30 ) + { + } + + public WeaknessWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnWandUse( Mobile from ) + { + Cast( new WeakenSpell( from, this ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/ArmorIgnore.cs b/Scripts/Items/Weapons/Abilities/ArmorIgnore.cs new file mode 100644 index 0000000..2ca62a2 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/ArmorIgnore.cs @@ -0,0 +1,33 @@ +using System; + +namespace Server.Items +{ + /// + /// This special move allows the skilled warrior to bypass his target's physical resistance, for one shot only. + /// The Armor Ignore shot does slightly less damage than normal. + /// Against a heavily armored opponent, this ability is a big win, but when used against a very lightly armored foe, it might be better to use a standard strike! + /// + public class ArmorIgnore : WeaponAbility + { + public ArmorIgnore() + { + } + + public override int BaseMana{ get{ return 30; } } + public override double DamageScalar{ get{ return 0.9; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060076 ); // Your attack penetrates their armor! + defender.SendLocalizedMessage( 1060077 ); // The blow penetrated your armor! + + defender.PlaySound( 0x56 ); + defender.FixedParticles( 0x3728, 200, 25, 9942, EffectLayer.Waist ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/ArmorPierce.cs b/Scripts/Items/Weapons/Abilities/ArmorPierce.cs new file mode 100644 index 0000000..8466fc2 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/ArmorPierce.cs @@ -0,0 +1,44 @@ +using System; +using Server; + +namespace Server.Items +{ + /// + /// Strike your opponent with great force, partially bypassing their armor and inflicting greater damage. Requires either Bushido or Ninjitsu skill + /// + public class ArmorPierce : WeaponAbility + { + public ArmorPierce() + { + } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override int BaseMana{ get{ return 30; } } + public override double DamageScalar{ get{ return 1.5; } } + + public override bool RequiresSE { get { return true; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063350 ); // You pierce your opponent's armor! + defender.SendLocalizedMessage( 1063351 ); // Your attacker pierced your armor! + + defender.FixedParticles( 0x3728, 1, 26, 0x26D6, 0, 0, EffectLayer.Waist ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/BleedAttack.cs b/Scripts/Items/Weapons/Abilities/BleedAttack.cs new file mode 100644 index 0000000..c961272 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/BleedAttack.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections; +using Server.Mobiles; +using Server.Spells.Necromancy; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + /// + /// Make your opponent bleed profusely with this wicked use of your weapon. + /// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds. + /// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages. + /// + public class BleedAttack : WeaponAbility + { + public BleedAttack() + { + } + + public override int BaseMana{ get{ return 30; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + // Necromancers under Lich or Wraith Form are immune to Bleed Attacks. + TransformContext context = TransformationSpellHelper.GetContext( defender ); + + if ( (context != null && ( context.Type == typeof( LichFormSpell ) || context.Type == typeof( WraithFormSpell ))) || + (defender is BaseCreature && ((BaseCreature)defender).BleedImmune) ) + { + attacker.SendLocalizedMessage( 1062052 ); // Your target is not affected by the bleed attack! + return; + } + + attacker.SendLocalizedMessage( 1060159 ); // Your target is bleeding! + defender.SendLocalizedMessage( 1060160 ); // You are bleeding! + + if ( defender is PlayerMobile ) + { + defender.LocalOverheadMessage( MessageType.Regular, 0x21, 1060757 ); // You are bleeding profusely + defender.NonlocalOverheadMessage( MessageType.Regular, 0x21, 1060758, defender.Name ); // ~1_NAME~ is bleeding profusely + } + + defender.PlaySound( 0x133 ); + defender.FixedParticles( 0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist ); + + BeginBleed( defender, attacker ); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsBleeding( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static void BeginBleed( Mobile m, Mobile from ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + t = new InternalTimer( from, m ); + m_Table[m] = t; + + t.Start(); + } + + public static void DoBleed( Mobile m, Mobile from, int level ) + { + if ( m.Alive ) + { + int damage = Utility.RandomMinMax( level, level * 2 ); + + if ( !m.Player ) + damage *= 2; + + m.PlaySound( 0x133 ); + m.Damage( damage, from ); + + Blood blood = new Blood(); + + blood.ItemID = Utility.Random( 0x122A, 5 ); + + blood.MoveToWorld( m.Location, m.Map ); + } + else + { + EndBleed( m, false ); + } + } + + public static void EndBleed( Mobile m, bool message ) + { + Timer t = (Timer)m_Table[m]; + + if ( t == null ) + return; + + t.Stop(); + m_Table.Remove( m ); + + if ( message ) + m.SendLocalizedMessage( 1060167 ); // The bleeding wounds have healed, you are no longer bleeding! + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private Mobile m_Mobile; + private int m_Count; + + public InternalTimer( Mobile from, Mobile m ) : base( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.0 ) ) + { + m_From = from; + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + DoBleed( m_Mobile, m_From, 5 - m_Count ); + + if ( ++m_Count == 5 ) + EndBleed( m_Mobile, true ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/Block.cs b/Scripts/Items/Weapons/Abilities/Block.cs new file mode 100644 index 0000000..d910294 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/Block.cs @@ -0,0 +1,111 @@ +using System; +using Server; +using System.Collections; + +namespace Server.Items +{ + /// + /// Raises your defenses for a short time. Requires Bushido or Ninjitsu skill. + /// + public class Block : WeaponAbility + { + public Block() + { + } + + public override int BaseMana{ get{ return 30; } } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063345 ); // You block an attack! + defender.SendLocalizedMessage( 1063346 ); // Your attack was blocked! + + attacker.FixedParticles( 0x37C4, 1, 16, 0x251D, 0x39D, 0x3, EffectLayer.RightHand ); + + int bonus = (int)(10.0 * ((Math.Max( attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value ) - 50.0) / 70.0 + 5)); + + BeginBlock( attacker, bonus ); + } + + private class BlockInfo + { + public Mobile m_Target; + public Timer m_Timer; + public int m_Bonus; + + public BlockInfo( Mobile target, int bonus ) + { + m_Target = target; + m_Bonus = bonus; + } + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool GetBonus( Mobile targ, ref int bonus ) + { + BlockInfo info = m_Table[targ] as BlockInfo; + + if ( info == null ) + return false; + + bonus = info.m_Bonus; + return true; + } + + public static void BeginBlock( Mobile m, int bonus ) + { + EndBlock( m ); + + BlockInfo info = new BlockInfo( m, bonus ); + info.m_Timer = new InternalTimer( m ); + + m_Table[m] = info; + } + + public static void EndBlock( Mobile m ) + { + BlockInfo info = m_Table[m] as BlockInfo; + + if ( info != null ) + { + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + m_Table.Remove( m ); + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 6.0 ) ) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndBlock( m_Mobile ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/ConcussionBlow.cs b/Scripts/Items/Weapons/Abilities/ConcussionBlow.cs new file mode 100644 index 0000000..639efc2 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/ConcussionBlow.cs @@ -0,0 +1,52 @@ +using System; + +namespace Server.Items +{ + /// + /// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or vice versa. + /// + public class ConcussionBlow : WeaponAbility + { + public ConcussionBlow() + { + } + + public override int BaseMana{ get{ return 25; } } + + public override bool OnBeforeDamage( Mobile attacker, Mobile defender ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return false; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060165 ); // You have delivered a concussion! + defender.SendLocalizedMessage( 1060166 ); // You feel disoriented! + + defender.PlaySound( 0x213 ); + defender.FixedParticles( 0x377A, 1, 32, 9949, 1153, 0, EffectLayer.Head ); + + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 10 ), defender.Map ), new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 20 ), defender.Map ), 0x36FE, 1, 0, false, false, 1133, 3, 9501, 1, 0, EffectLayer.Waist, 0x100 ); + + int damage = 10; // Base damage is 10. + + if ( defender.HitsMax > 0 ) + { + double hitsPercent = ( (double)defender.Hits / (double)defender.HitsMax ) * 100.0; + + double manaPercent = 0; + + if ( defender.ManaMax > 0 ) + manaPercent = ( (double)defender.Mana / (double)defender.ManaMax ) * 100.0; + + damage += Math.Min( (int)(Math.Abs( hitsPercent - manaPercent ) / 4), 20 ); + } + + // Total damage is 10 + (0~20) = 10~30, physical, non-resistable. + + defender.Damage( damage, attacker ); + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/CrushingBlow.cs b/Scripts/Items/Weapons/Abilities/CrushingBlow.cs new file mode 100644 index 0000000..13efe00 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/CrushingBlow.cs @@ -0,0 +1,34 @@ +using System; + +namespace Server.Items +{ + /// + /// Also known as the Haymaker, this attack dramatically increases the damage done by a weapon reaching its mark. + /// + public class CrushingBlow : WeaponAbility + { + public CrushingBlow() + { + } + + public override int BaseMana{ get{ return 25; } } + public override double DamageScalar{ get{ return 1.5; } } + + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060090 ); // You have delivered a crushing blow! + defender.SendLocalizedMessage( 1060091 ); // You take extra damage from the crushing attack! + + defender.PlaySound( 0x1E1 ); + defender.FixedParticles( 0, 1, 0, 9946, EffectLayer.Head ); + + Effects.SendMovingParticles( new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 50 ), defender.Map ), new Entity( Serial.Zero, new Point3D( defender.X, defender.Y, defender.Z + 20 ), defender.Map ), 0xFB4, 1, 0, false, false, 0, 3, 9501, 1, 0, EffectLayer.Head, 0x100 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/DefenseMastery.cs b/Scripts/Items/Weapons/Abilities/DefenseMastery.cs new file mode 100644 index 0000000..ca76dfb --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/DefenseMastery.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using System.Collections; + +namespace Server.Items +{ + /// + /// Raises your physical resistance for a short time while lowering your ability to inflict damage. Requires Bushido or Ninjitsu skill. + /// + public class DefenseMastery : WeaponAbility + { + public DefenseMastery() + { + } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override int BaseMana { get { return 30; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063353 ); // You perform a masterful defense! + + attacker.FixedParticles( 0x375A, 1, 17, 0x7F2, 0x3E8, 0x3, EffectLayer.Waist ); + + int modifier = (int)(30.0 * ((Math.Max( attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value ) - 50.0) / 70.0)); + + DefenseMasteryInfo info = m_Table[attacker] as DefenseMasteryInfo; + + if( info != null ) + EndDefense( (object)info ); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Physical, 50 + modifier ); + attacker.AddResistanceMod( mod ); + + info = new DefenseMasteryInfo( attacker, 80 - modifier, mod ); + info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( EndDefense ), info ); + + m_Table[attacker] = info; + + attacker.Delta( MobileDelta.WeaponDamage ); + } + + private class DefenseMasteryInfo + { + public Mobile m_From; + public Timer m_Timer; + public int m_DamageMalus; + public ResistanceMod m_Mod; + + public DefenseMasteryInfo( Mobile from, int damageMalus, ResistanceMod mod ) + { + m_From = from; + m_DamageMalus = damageMalus; + m_Mod = mod; + } + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool GetMalus( Mobile targ, ref int damageMalus ) + { + DefenseMasteryInfo info = m_Table[targ] as DefenseMasteryInfo; + + if( info == null ) + return false; + + damageMalus = info.m_DamageMalus; + return true; + } + + private static void EndDefense( object state ) + { + DefenseMasteryInfo info = (DefenseMasteryInfo)state; + + if( info.m_Mod != null ) + info.m_From.RemoveResistanceMod( info.m_Mod ); + + if( info.m_Timer != null ) + info.m_Timer.Stop(); + + // No message is sent to the player. + + m_Table.Remove( info.m_From ); + + info.m_From.Delta( MobileDelta.WeaponDamage ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/Disarm.cs b/Scripts/Items/Weapons/Abilities/Disarm.cs new file mode 100644 index 0000000..5b106a4 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/Disarm.cs @@ -0,0 +1,84 @@ +using System; + +namespace Server.Items +{ + /// + /// This attack allows you to disarm your foe. + /// Now in Age of Shadows, a successful Disarm leaves the victim unable to re-arm another weapon for several seconds. + /// + public class Disarm : WeaponAbility + { + public Disarm() + { + } + + public override int BaseMana{ get{ return 20; } } + + // No longer active in pub21: + /*public override bool CheckSkills( Mobile from ) + { + if ( !base.CheckSkills( from ) ) + return false; + + if ( !(from.Weapon is Fists) ) + return true; + + Skill skill = from.Skills[SkillName.ArmsLore]; + + if ( skill != null && skill.Base >= 80.0 ) + return true; + + from.SendLocalizedMessage( 1061812 ); // You lack the required skill in armslore to perform that attack! + + return false; + }*/ + + public override bool RequiresTactics( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon == null ) + return false; + + return weapon.Skill != SkillName.Wrestling; + } + + public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds( 5.0 ); + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) ) + return; + + ClearCurrentAbility( attacker ); + + Item toDisarm = defender.FindItemOnLayer( Layer.OneHanded ); + + if ( toDisarm == null || !toDisarm.Movable ) + toDisarm = defender.FindItemOnLayer( Layer.TwoHanded ); + + Container pack = defender.Backpack; + + if ( pack == null || (toDisarm != null && !toDisarm.Movable) ) + { + attacker.SendLocalizedMessage( 1004001 ); // You cannot disarm your opponent. + } + else if (toDisarm == null || toDisarm is BaseShield || toDisarm is Spellbook && !Core.ML ) + { + attacker.SendLocalizedMessage( 1060849 ); // Your target is already unarmed! + } + else if ( CheckMana( attacker, true ) ) + { + attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon! + defender.SendLocalizedMessage( 1060093 ); // Your weapon has been disarmed! + + defender.PlaySound( 0x3B9 ); + defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.LeftHand ); + + pack.DropItem( toDisarm ); + + BaseWeapon.BlockEquip( defender, BlockEquipDuration ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/Dismount.cs b/Scripts/Items/Weapons/Abilities/Dismount.cs new file mode 100644 index 0000000..76675e9 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/Dismount.cs @@ -0,0 +1,113 @@ +using System; +using Server.Mobiles; + +namespace Server.Items +{ + /// + /// Perfect for the foot-soldier, the Dismount special attack can unseat a mounted opponent. + /// The fighter using this ability must be on his own two feet and not in the saddle of a steed + /// (with one exception: players may use a lance to dismount other players while mounted). + /// If it works, the target will be knocked off his own mount and will take some extra damage from the fall! + /// + public class Dismount : WeaponAbility + { + public Dismount() + { + } + + public override int BaseMana { get { return 20; } } + + public override bool Validate(Mobile from) + { + if (!base.Validate(from)) + return false; + + if (from.Mounted && !(from.Weapon is Lance)) + { + from.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted! + return false; + } + + return true; + } + + public static readonly TimeSpan RemountDelay = TimeSpan.FromSeconds(10.0); + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker)) + return; + + if (defender is ChaosDragoon || defender is ChaosDragoonElite) + return; + + if (attacker.Mounted && (!(attacker.Weapon is Lance) || !(defender.Weapon is Lance))) // TODO: Should there be a message here? + return; + + ClearCurrentAbility(attacker); + + IMount mount = defender.Mount; + + if (mount == null && !Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(defender)) + { + attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets + return; + } + + if (!CheckMana(attacker, true)) + return; + + if (Core.ML && attacker is LesserHiryu && 0.8 >= Utility.RandomDouble()) + { + return; //Lesser Hiryu have an 80% chance of missing this attack + } + + attacker.SendLocalizedMessage(1060082); // The force of your attack has dislodged them from their mount! + + if (attacker.Mounted) + defender.SendLocalizedMessage(1062315); // You fall off your mount! + else + defender.SendLocalizedMessage(1060083); // You fall off of your mount and take damage! + + defender.PlaySound(0x140); + defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist); + + if (defender is PlayerMobile) + { + if (Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(defender)) + { + defender.SendLocalizedMessage(1114066, attacker.Name); // ~1_NAME~ knocked you out of animal form! + } + else if (defender.Mounted) + { + defender.SendLocalizedMessage(1040023); // You have been knocked off of your mount! + } + + (defender as PlayerMobile).SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true); + } + else + { + defender.Mount.Rider = null; + } + + if (attacker is PlayerMobile) + { + (attacker as PlayerMobile).SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, true); + } + else if (Core.ML && attacker is BaseCreature) + { + BaseCreature bc = attacker as BaseCreature; + + if (bc.ControlMaster is PlayerMobile) + { + PlayerMobile pm = bc.ControlMaster as PlayerMobile; + + pm.SetMountBlock(BlockMountType.DismountRecovery, RemountDelay, false); + } + } + + if (!attacker.Mounted) + AOS.Damage(defender, attacker, Utility.RandomMinMax(15, 25), 100, 0, 0, 0, 0); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/Disrobe.cs b/Scripts/Items/Weapons/Abilities/Disrobe.cs new file mode 100644 index 0000000..9f883e1 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/Disrobe.cs @@ -0,0 +1,49 @@ +using System; + +namespace Server.Items +{ + /// + /// This attack allows you to disrobe your foe. + /// + public class Disrobe : WeaponAbility + { + public Disrobe() + { + } + + public override int BaseMana{ get{ return 20; } } // Not Sure what amount of mana a creature uses. + + public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds( 5.0 ); + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) ) + return; + + ClearCurrentAbility( attacker ); + Item toDisrobe = defender.FindItemOnLayer(Layer.InnerTorso); + + if ( toDisrobe == null || !toDisrobe.Movable ) + toDisrobe = defender.FindItemOnLayer( Layer.OuterTorso ); + + Container pack = defender.Backpack; + + if ( pack == null || toDisrobe == null || !toDisrobe.Movable ) + { + attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent. + } + else if ( CheckMana( attacker, true ) ) + { + //attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon! + defender.SendLocalizedMessage(1062002); // You can no longer wear your ~1_ARMOR~ + + defender.PlaySound( 0x3B9 ); + //defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.InnerTorso ); + + pack.DropItem( toDisrobe ); + + BaseWeapon.BlockEquip( defender, BlockEquipDuration ); + } + } + } +} diff --git a/Scripts/Items/Weapons/Abilities/DoubleShot.cs b/Scripts/Items/Weapons/Abilities/DoubleShot.cs new file mode 100644 index 0000000..a1b280d --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/DoubleShot.cs @@ -0,0 +1,69 @@ +using System; +using Server; + +namespace Server.Items +{ + /// + /// Send two arrows flying at your opponent if you're mounted. Requires Bushido or Ninjitsu skill. + /// + public class DoubleShot : WeaponAbility + { + public DoubleShot() + { + } + + public override int BaseMana { get { return 30; } } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + Use( attacker, defender ); + } + + public override void OnMiss( Mobile attacker, Mobile defender ) + { + Use( attacker, defender ); + } + + public override bool Validate( Mobile from ) + { + if( base.Validate( from ) ) + { + if( from.Mounted ) + return true; + else + { + from.SendLocalizedMessage( 1070770 ); // You can only execute this attack while mounted! + ClearCurrentAbility( from ); + } + } + + return false; + } + + public void Use( Mobile attacker, Mobile defender ) + { + if( !Validate( attacker ) || !CheckMana( attacker, true ) || attacker.Weapon == null ) //sanity + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063348 ); // You launch two shots at once! + defender.SendLocalizedMessage( 1063349 ); // You're attacked with a barrage of shots! + + defender.FixedParticles( 0x37B9, 1, 19, 0x251D, EffectLayer.Waist ); + + attacker.Weapon.OnSwing( attacker, defender ); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/DoubleStrike.cs b/Scripts/Items/Weapons/Abilities/DoubleStrike.cs new file mode 100644 index 0000000..b7d0969 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/DoubleStrike.cs @@ -0,0 +1,57 @@ +using System; + +namespace Server.Items +{ + /// + /// The highly skilled warrior can use this special attack to make two quick swings in succession. + /// Landing both blows would be devastating! + /// + public class DoubleStrike : WeaponAbility + { + public DoubleStrike() + { + } + + public override int BaseMana{ get{ return 30; } } + public override double DamageScalar{ get{ return 0.9; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060084 ); // You attack with lightning speed! + defender.SendLocalizedMessage( 1060085 ); // Your attacker strikes with lightning speed! + + defender.PlaySound( 0x3BB ); + defender.FixedEffect( 0x37B9, 244, 25 ); + + // Swing again: + + // If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat + if ( defender == null || defender.Deleted || attacker.Deleted || defender.Map != attacker.Map || !defender.Alive || !attacker.Alive || !attacker.CanSee( defender ) ) + { + attacker.Combatant = null; + return; + } + + IWeapon weapon = attacker.Weapon; + + if ( weapon == null ) + return; + + if ( !attacker.InRange( defender, weapon.MaxRange ) ) + return; + + if ( attacker.InLOS( defender ) ) + { + BaseWeapon.InDoubleStrike = true; + attacker.RevealingAction(); + attacker.NextCombatTime = DateTime.Now + weapon.OnSwing( attacker, defender ); + BaseWeapon.InDoubleStrike = false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/DualWield.cs b/Scripts/Items/Weapons/Abilities/DualWield.cs new file mode 100644 index 0000000..a04a32c --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/DualWield.cs @@ -0,0 +1,78 @@ + +using System; +using Server; +using System.Collections; + +namespace Server.Items +{ + /// + /// Attack faster as you swing with both weapons. + /// + public class DualWield : WeaponAbility + { + private static Hashtable m_Registry = new Hashtable(); + public static Hashtable Registry { get { return m_Registry; } } + + public DualWield() + { + } + + public override int BaseMana { get { return 30; } } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 ) + { + from.SendLocalizedMessage( 1063352, "50" ); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + if( Registry.Contains( attacker ) ) + { + DualWieldTimer existingtimer = (DualWieldTimer)Registry[attacker]; + existingtimer.Stop(); + Registry.Remove( attacker ); + } + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063362 ); // You dually wield for increased speed! + + attacker.FixedParticles( 0x3779, 1, 15, 0x7F6, 0x3E8, 3, EffectLayer.LeftHand ); + + Timer t = new DualWieldTimer( attacker, (int)(20.0 + 3.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 7.0) ); //20-50 % increase + + t.Start(); + Registry.Add( attacker, t ); + } + + public class DualWieldTimer : Timer + { + private Mobile m_Owner; + private int m_BonusSwingSpeed; + + public int BonusSwingSpeed { get { return m_BonusSwingSpeed; } } + + public DualWieldTimer( Mobile owner, int bonusSwingSpeed ) + : base( TimeSpan.FromSeconds( 6.0 ) ) + { + m_Owner = owner; + m_BonusSwingSpeed = bonusSwingSpeed; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + Registry.Remove( m_Owner ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/Feint.cs b/Scripts/Items/Weapons/Abilities/Feint.cs new file mode 100644 index 0000000..5eafbf3 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/Feint.cs @@ -0,0 +1,79 @@ + +using System; +using System.Collections; +using Server.Items; + +namespace Server.Items +{ + /// + /// Gain a defensive advantage over your primary opponent for a short time. + /// + public class Feint : WeaponAbility + { + private static Hashtable m_Registry = new Hashtable(); + public static Hashtable Registry { get { return m_Registry; } } + + public Feint() + { + } + + public override int BaseMana { get { return 30; } } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + if( Registry.Contains( defender ) ) + { + FeintTimer existingtimer = (FeintTimer)Registry[defender]; + existingtimer.Stop(); + Registry.Remove( defender ); + } + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063360 ); // You baffle your target with a feint! + defender.SendLocalizedMessage( 1063361 ); // You were deceived by an attacker's feint! + + attacker.FixedParticles( 0x3728, 1, 13, 0x7F3, 0x962, 0, EffectLayer.Waist ); + + Timer t = new FeintTimer( defender, (int)(20.0 + 3.0 * (Math.Max( attacker.Skills[SkillName.Ninjitsu].Value, attacker.Skills[SkillName.Bushido].Value ) - 50.0) / 7.0) ); //20-50 % decrease + + t.Start(); + Registry.Add( defender, t ); + } + + public class FeintTimer : Timer + { + private Mobile m_Defender; + private int m_SwingSpeedReduction; + + public int SwingSpeedReduction { get { return m_SwingSpeedReduction; } } + + public FeintTimer( Mobile defender, int swingSpeedReduction ) + : base( TimeSpan.FromSeconds( 6.0 ) ) + { + m_Defender = defender; + m_SwingSpeedReduction = swingSpeedReduction; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + Registry.Remove( m_Defender ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/FrenziedWhirlwind.cs b/Scripts/Items/Weapons/Abilities/FrenziedWhirlwind.cs new file mode 100644 index 0000000..0bef06d --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/FrenziedWhirlwind.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections; +using Server; +using Server.Spells; +using Server.Engines.PartySystem; + +namespace Server.Items +{ + /// + /// A quick attack to all enemies in range of your weapon that causes damage over time. Requires Bushido or Ninjitsu skill. + /// + public class FrenziedWhirlwind : WeaponAbility + { + public FrenziedWhirlwind() + { + } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 && GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1063347, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override int BaseMana { get { return 30; } } + + private static Hashtable m_Registry = new Hashtable(); + public static Hashtable Registry { get { return m_Registry; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !Validate( attacker ) ) //Mana check after check that there are targets + return; + + ClearCurrentAbility( attacker ); + + Map map = attacker.Map; + + if( map == null ) + return; + + BaseWeapon weapon = attacker.Weapon as BaseWeapon; + + if( weapon == null ) + return; + + ArrayList list = new ArrayList(); + + foreach( Mobile m in attacker.GetMobilesInRange( 1 ) ) + list.Add( m ); + + ArrayList targets = new ArrayList(); + + for( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + if( m != defender && m != attacker && SpellHelper.ValidIndirectTarget( attacker, m ) ) + { + if( m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee( m ) || !attacker.CanBeHarmful( m ) ) + continue; + + if( !attacker.InRange( m, weapon.MaxRange ) ) + continue; + + if( attacker.InLOS( m ) ) + targets.Add( m ); + } + } + + if( targets.Count > 0 ) + { + if( !CheckMana( attacker, true ) ) + return; + + attacker.FixedEffect( 0x3728, 10, 15 ); + attacker.PlaySound( 0x2A1 ); + + // 5-15 damage + int amount = (int)(10.0 * ((Math.Max( attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value ) - 50.0) / 70.0 + 5)); + + for( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + attacker.DoHarmful( m, true ); + + Timer t = Registry[m] as Timer; + + if( t != null ) + { + t.Stop(); + Registry.Remove( m ); + } + + t = new InternalTimer( attacker, m, amount ); + t.Start(); + Registry.Add( m, t ); + } + + Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( RepeatEffect ), attacker ); + } + } + + private void RepeatEffect( object state ) + { + Mobile attacker = (Mobile)state; + + attacker.FixedEffect( 0x3728, 10, 15 ); + attacker.PlaySound( 0x2A1 ); + } + + private class InternalTimer : Timer + { + private Mobile m_Attacker; + private Mobile m_Defender; + private double m_DamageRemaining; + private double m_DamageToDo; + + private readonly double DamagePerTick; + + public InternalTimer( Mobile attacker, Mobile defender, int totalDamage ) + : base( TimeSpan.Zero, TimeSpan.FromSeconds( 0.25 ), 12 ) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each. + { + m_Attacker = attacker; + m_Defender = defender; + + m_DamageRemaining = (double)totalDamage; + DamagePerTick = (double)totalDamage / 12 + 0.01; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if( !m_Defender.Alive || m_DamageRemaining <= 0 ) + { + Stop(); + Server.Items.FrenziedWhirlwind.Registry.Remove( m_Defender ); + return; + } + + m_DamageRemaining -= DamagePerTick; + m_DamageToDo += DamagePerTick; + + if( m_DamageRemaining <= 0 && m_DamageToDo < 1 ) + m_DamageToDo = 1.0; //Confirm this 'round up' at the end + + int damage = (int)m_DamageToDo; + + if( damage > 0 ) + { + m_Defender.Damage( damage, m_Attacker ); + m_DamageToDo -= damage; + } + + if( !m_Defender.Alive || m_DamageRemaining <= 0 ) + { + Stop(); + Server.Items.FrenziedWhirlwind.Registry.Remove( m_Defender ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs b/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs new file mode 100644 index 0000000..0dff616 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/InfectiousStrike.cs @@ -0,0 +1,82 @@ +using System; + +namespace Server.Items +{ + /// + /// This special move represents a significant change to the use of poisons in Age of Shadows. + /// Now, only certain weapon types � those that have Infectious Strike as an available special move � will be able to be poisoned. + /// Targets will no longer be poisoned at random when hit by poisoned weapons. + /// Instead, the wielder must use this ability to deliver the venom. + /// While no skill in Poisoning is directly required to use this ability, being knowledgeable in the application and use of toxins + /// will allow a character to use Infectious Strike at reduced mana cost and with a chance to inflict more deadly poison on his victim. + /// With this change, weapons will no longer be corroded by poison. + /// Level 5 poison will be possible when using this special move. + /// + public class InfectiousStrike : WeaponAbility + { + public InfectiousStrike() + { + } + + public override int BaseMana{ get{ return 15; } } + + public override bool RequiresTactics( Mobile from ) + { + return false; + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) ) + return; + + ClearCurrentAbility( attacker ); + + BaseWeapon weapon = attacker.Weapon as BaseWeapon; + + if ( weapon == null ) + return; + + Poison p = weapon.Poison; + + if ( p == null || weapon.PoisonCharges <= 0 ) + { + attacker.SendLocalizedMessage( 1061141 ); // Your weapon must have a dose of poison to perform an infectious strike! + return; + } + + if ( !CheckMana( attacker, true ) ) + return; + + --weapon.PoisonCharges; + + // Infectious strike special move now uses poisoning skill to help determine potency + int maxLevel = attacker.Skills[SkillName.Poisoning].Fixed / 200; + if ( maxLevel < 0 ) maxLevel = 0; + if ( p.Level > maxLevel ) p = Poison.GetPoison( maxLevel ); + + if ( (attacker.Skills[SkillName.Poisoning].Value / 100.0) > Utility.RandomDouble() ) + { + int level = p.Level + 1; + Poison newPoison = Poison.GetPoison( level ); + + if ( newPoison != null ) + { + p = newPoison; + + attacker.SendLocalizedMessage( 1060080 ); // Your precise strike has increased the level of the poison by 1 + defender.SendLocalizedMessage( 1060081 ); // The poison seems extra effective! + } + } + + defender.PlaySound( 0xDD ); + defender.FixedParticles( 0x3728, 244, 25, 9941, 1266, 0, EffectLayer.Waist ); + + if ( defender.ApplyPoison( attacker, p ) != ApplyPoisonResult.Immune ) + { + attacker.SendLocalizedMessage( 1008096, true, defender.Name ); // You have poisoned your target : + defender.SendLocalizedMessage( 1008097, false, attacker.Name ); // : poisoned you! + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/MortalStrike.cs b/Scripts/Items/Weapons/Abilities/MortalStrike.cs new file mode 100644 index 0000000..aad9cbc --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/MortalStrike.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections; +using Server.Mobiles; + +namespace Server.Items +{ + /// + /// The assassin's friend. + /// A successful Mortal Strike will render its victim unable to heal any damage for several seconds. + /// Use a gruesome follow-up to finish off your foe. + /// + public class MortalStrike : WeaponAbility + { + public MortalStrike() + { + } + + public override int BaseMana { get { return 30; } } + + public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds(6.0); + public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds(12.0); + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + { + return; + } + + ClearCurrentAbility(attacker); + + attacker.SendLocalizedMessage(1060086); // You deliver a mortal wound! + defender.SendLocalizedMessage(1060087); // You have been mortally wounded! + + defender.PlaySound(0x1E1); + defender.FixedParticles(0x37B9, 244, 25, 9944, 31, 0, EffectLayer.Waist); + + // Do not reset timer if one is already in place. + if (!IsWounded(defender)) + BeginWound(defender, defender.Player ? PlayerDuration : NPCDuration); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsWounded(Mobile m) + { + return m_Table.Contains(m); + } + + public static void BeginWound(Mobile m, TimeSpan duration) + { + Timer t = (Timer)m_Table[m]; + + if (t != null) + t.Stop(); + + t = new InternalTimer(m, duration); + m_Table[m] = t; + + t.Start(); + + m.YellowHealthbar = true; + } + + public static void EndWound(Mobile m) + { + if (!IsWounded(m)) + return; + + Timer t = (Timer)m_Table[m]; + + if (t != null) + t.Stop(); + + m_Table.Remove(m); + + m.YellowHealthbar = false; + m.SendLocalizedMessage(1060208); // You are no longer mortally wounded. + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer(Mobile m, TimeSpan duration) + : base(duration) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndWound(m_Mobile); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/MovingShot.cs b/Scripts/Items/Weapons/Abilities/MovingShot.cs new file mode 100644 index 0000000..1dbfa1a --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/MovingShot.cs @@ -0,0 +1,43 @@ +using System; + +namespace Server.Items +{ + /// + /// Available on some crossbows, this special move allows archers to fire while on the move. + /// This shot is somewhat less accurate than normal, but the ability to fire while running is a clear advantage. + /// + public class MovingShot : WeaponAbility + { + public MovingShot() + { + } + + public override int BaseMana{ get{ return 15; } } + public override int AccuracyBonus{ get{ return -25; } } + + public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + return ( Validate( attacker ) && CheckMana( attacker, true ) ); + } + + public override void OnMiss( Mobile attacker, Mobile defender ) + { + //Validates in OnSwing for accuracy scalar + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060089 ); // You fail to execute your special move + } + + public override bool ValidatesDuringHit { get { return false; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + //Validates in OnSwing for accuracy scalar + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060216 ); // Your shot was successful + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/NerveStrike.cs b/Scripts/Items/Weapons/Abilities/NerveStrike.cs new file mode 100644 index 0000000..3656b09 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/NerveStrike.cs @@ -0,0 +1,81 @@ +using System; +using Server; + +namespace Server.Items +{ + /// + /// Does damage and paralyses your opponent for a short time. + /// + public class NerveStrike : WeaponAbility + { + public NerveStrike() + { + } + + public override int BaseMana { get { return 30; } } + + public override bool CheckSkills(Mobile from) + { + if (GetSkill(from, SkillName.Bushido) < 50.0) + { + from.SendLocalizedMessage(1070768, "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! + return false; + } + + return base.CheckSkills(from); + } + + public override bool OnBeforeSwing(Mobile attacker, Mobile defender) + { + if (defender.Paralyzed) + { + attacker.SendLocalizedMessage(1061923); // The target is already frozen. + return false; + } + + return true; + } + + public override void OnHit(Mobile attacker, Mobile defender, int damage) + { + if (!Validate(attacker) || !CheckMana(attacker, true)) + return; + + ClearCurrentAbility(attacker); + + bool cantpara = Server.Items.ParalyzingBlow.IsImmune(defender); + + if (cantpara) + { + attacker.SendLocalizedMessage(1070804); // Your target resists paralysis. + defender.SendLocalizedMessage(1070813); // You resist paralysis. + } + else + { + attacker.SendLocalizedMessage(1063356); // You cripple your target with a nerve strike! + defender.SendLocalizedMessage(1063357); // Your attacker dealt a crippling nerve strike! + } + + attacker.PlaySound(0x204); + defender.FixedEffect(0x376A, 9, 32); + defender.FixedParticles(0x37C4, 1, 8, 0x13AF, 0, 0, EffectLayer.Waist); + + if (Core.ML) + { + AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + Utility.Random(10)), true, 100, 0, 0, 0, 0); //0-25 + + if (!cantpara && ((150.0 / 7.0 + (4.0 * attacker.Skills[SkillName.Bushido].Value) / 7.0) / 100.0) > Utility.RandomDouble()) + { + defender.Paralyze(TimeSpan.FromSeconds(2.0)); + Server.Items.ParalyzingBlow.BeginImmunity(defender, Server.Items.ParalyzingBlow.FreezeDelayDuration); + } + } + else if (!cantpara) + { + AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 10), true, 100, 0, 0, 0, 0); //10-25 + defender.Freeze(TimeSpan.FromSeconds(2.0)); + Server.Items.ParalyzingBlow.BeginImmunity(defender, Server.Items.ParalyzingBlow.FreezeDelayDuration); + } + } + } +} diff --git a/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs b/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs new file mode 100644 index 0000000..1ab3181 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/ParalyzingBlow.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections; + +namespace Server.Items +{ + /// + /// A successful Paralyzing Blow will leave the target stunned, unable to move, attack, or cast spells, for a few seconds. + /// + public class ParalyzingBlow : WeaponAbility + { + public ParalyzingBlow() + { + } + + public override int BaseMana{ get{ return 30; } } + + public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds( 3.0 ); + public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds( 6.0 ); + + public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds( 8.0 ); + + // No longer active in pub21: + /*public override bool CheckSkills( Mobile from ) + { + if ( !base.CheckSkills( from ) ) + return false; + + if ( !(from.Weapon is Fists) ) + return true; + + Skill skill = from.Skills[SkillName.Anatomy]; + + if ( skill != null && skill.Base >= 80.0 ) + return true; + + from.SendLocalizedMessage( 1061811 ); // You lack the required anatomy skill to perform that attack! + + return false; + }*/ + + public override bool RequiresTactics( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon == null ) + return true; + + return weapon.Skill != SkillName.Wrestling; + } + + public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + if( defender.Paralyzed ) + { + attacker.SendLocalizedMessage( 1061923 ); // The target is already frozen. + return false; + } + + return true; + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + if( IsImmune( defender ) ) //Intentionally going after Mana consumption + { + attacker.SendLocalizedMessage( 1070804 ); // Your target resists paralysis. + defender.SendLocalizedMessage( 1070813 ); // You resist paralysis. + return; + } + + defender.FixedEffect( 0x376A, 9, 32 ); + defender.PlaySound( 0x204 ); + + attacker.SendLocalizedMessage( 1060163 ); // You deliver a paralyzing blow! + defender.SendLocalizedMessage( 1060164 ); // The attack has temporarily paralyzed you! + + TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration; + + // Treat it as paralyze not as freeze, effect must be removed when damaged. + defender.Paralyze( duration ); + + BeginImmunity( defender, duration + FreezeDelayDuration ); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsImmune( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static void BeginImmunity( Mobile m, TimeSpan duration ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + t = new InternalTimer( m, duration ); + m_Table[m] = t; + + t.Start(); + } + + public static void EndImmunity( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + m_Table.Remove( m ); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m, TimeSpan duration ) : base( duration ) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndImmunity( m_Mobile ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/RidingSwipe.cs b/Scripts/Items/Weapons/Abilities/RidingSwipe.cs new file mode 100644 index 0000000..58fc2b7 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/RidingSwipe.cs @@ -0,0 +1,81 @@ + +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + /// + /// If you are on foot, dismounts your opponent and damage the ethereal's rider or the + /// living mount(which must be healed before ridden again). If you are mounted, damages + /// and stuns the mounted opponent. + /// + public class RidingSwipe : WeaponAbility + { + public RidingSwipe() + { + } + + public override int BaseMana { get { return 30; } } + + public override bool RequiresSE { get { return true; } } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Bushido ) < 50.0 ) + { + from.SendLocalizedMessage( 1070768, "50" ); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !defender.Mounted ) + { + attacker.SendLocalizedMessage( 1060848 ); // This attack only works on mounted targets + ClearCurrentAbility( attacker ); + return; + } + + if( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + if( !attacker.Mounted ) + { + Mobile mount = defender.Mount as Mobile; + BaseMount.Dismount( defender ); + + if( mount != null ) //Ethy mounts don't take damage + { + int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5); + + AOS.Damage( mount, null, amount, 100, 0, 0, 0, 0 ); //The mount just takes damage, there's no flagging as if it was attacking the mount directly + + //TODO: Mount prevention until mount healed + } + } + else + { + int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5); + + AOS.Damage( defender, attacker, amount, 100, 0, 0, 0, 0 ); + + if( Server.Items.ParalyzingBlow.IsImmune( defender ) ) //Does it still do damage? + { + attacker.SendLocalizedMessage( 1070804 ); // Your target resists paralysis. + defender.SendLocalizedMessage( 1070813 ); // You resist paralysis. + } + else + { + defender.Paralyze( TimeSpan.FromSeconds( 3.0 ) ); + Server.Items.ParalyzingBlow.BeginImmunity( defender, Server.Items.ParalyzingBlow.FreezeDelayDuration ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/ShadowStrike.cs b/Scripts/Items/Weapons/Abilities/ShadowStrike.cs new file mode 100644 index 0000000..667f9ee --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/ShadowStrike.cs @@ -0,0 +1,59 @@ +using System; + +namespace Server.Items +{ + /// + /// This powerful ability requires secondary skills to activate. + /// Successful use of Shadowstrike deals extra damage to the target � and renders the attacker invisible! + /// Only those who are adept at the art of stealth will be able to use this ability. + /// + public class ShadowStrike : WeaponAbility + { + public ShadowStrike() + { + } + + public override int BaseMana{ get{ return 20; } } + public override double DamageScalar{ get{ return 1.25; } } + + public override bool RequiresTactics( Mobile from ) + { + return false; + } + + public override bool CheckSkills( Mobile from ) + { + if ( !base.CheckSkills( from ) ) + return false; + + Skill skill = from.Skills[SkillName.Stealth]; + + if ( skill != null && skill.Value >= 80.0 ) + return true; + + from.SendLocalizedMessage( 1060183 ); // You lack the required stealth to perform that attack + + return false; + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1060078 ); // You strike and hide in the shadows! + defender.SendLocalizedMessage( 1060079 ); // You are dazed by the attack and your attacker vanishes! + + Effects.SendLocationParticles( EffectItem.Create( attacker.Location, attacker.Map, EffectItem.DefaultDuration ), 0x376A, 8, 12, 9943 ); + attacker.PlaySound( 0x482 ); + + defender.FixedEffect( 0x37BE, 20, 25 ); + + attacker.Combatant = null; + attacker.Warmode = false; + attacker.Hidden = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/TalonStrike.cs b/Scripts/Items/Weapons/Abilities/TalonStrike.cs new file mode 100644 index 0000000..4c0a7dd --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/TalonStrike.cs @@ -0,0 +1,106 @@ + +using System; +using Server; +using System.Collections; + +namespace Server.Items +{ + /// + /// Attack with increased damage with additional damage over time. + /// + public class TalonStrike : WeaponAbility + { + private static Hashtable m_Registry = new Hashtable(); + public static Hashtable Registry { get { return m_Registry; } } + + public TalonStrike() + { + } + + public override int BaseMana { get { return 30; } } + public override double DamageScalar { get { return 1.2; } } + + public override bool CheckSkills( Mobile from ) + { + if( GetSkill( from, SkillName.Ninjitsu ) < 50.0 ) + { + from.SendLocalizedMessage( 1063352, "50" ); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! + return false; + } + + return base.CheckSkills( from ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( Registry.Contains( defender ) || !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1063358 ); // You deliver a talon strike! + defender.SendLocalizedMessage( 1063359 ); // Your attacker delivers a talon strike! + + defender.FixedParticles( 0x373A, 1, 17, 0x26BC, 0x662, 0, EffectLayer.Waist ); + + Timer t = new InternalTimer( defender, (int)(10.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 70.0 + 5), attacker ); //5 - 15 damage + + t.Start(); + + Registry.Add( defender, t ); + } + + private class InternalTimer : Timer + { + private Mobile m_Defender; + private double m_DamageRemaining; + private double m_DamageToDo; + private Mobile m_Attacker; + + private readonly double DamagePerTick; + + public InternalTimer( Mobile defender, int totalDamage, Mobile attacker ) + : base( TimeSpan.Zero, TimeSpan.FromSeconds( 0.25 ), 12 ) // 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each. + { + m_Defender = defender; + m_DamageRemaining = (double)totalDamage; + Priority = TimerPriority.TwentyFiveMS; + + m_Attacker = attacker; + + DamagePerTick = (double)totalDamage / 12+.01; + } + + protected override void OnTick() + { + if( !m_Defender.Alive || m_DamageRemaining <= 0 ) + { + Stop(); + Server.Items.TalonStrike.Registry.Remove( m_Defender ); + return; + } + + m_DamageRemaining -= DamagePerTick; + m_DamageToDo += DamagePerTick; + + if( m_DamageRemaining <= 0 && m_DamageToDo < 1 ) + m_DamageToDo = 1.0; //Confirm this 'round up' at the end + + int damage = (int)m_DamageToDo; + + if( damage > 0 ) + { + //m_Defender.Damage( damage, m_Attacker, false ); + m_Defender.Hits -= damage; //Don't show damage, don't disrupt + m_DamageToDo -= damage; + } + + if( !m_Defender.Alive || m_DamageRemaining <= 0 ) + { + Stop(); + Server.Items.TalonStrike.Registry.Remove( m_Defender ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/WeaponAbility.cs b/Scripts/Items/Weapons/Abilities/WeaponAbility.cs new file mode 100644 index 0000000..10d0c86 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/WeaponAbility.cs @@ -0,0 +1,489 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Spells; +using Server.Mobiles; + + +namespace Server.Items +{ + public abstract class WeaponAbility + { + public virtual int BaseMana{ get{ return 0; } } + + public virtual int AccuracyBonus{ get{ return 0; } } + public virtual double DamageScalar{ get{ return 1.0; } } + + public virtual bool RequiresSE { get { return false; } } + + public virtual void OnHit( Mobile attacker, Mobile defender, int damage ) + { + } + + public virtual void OnMiss( Mobile attacker, Mobile defender ) + { + } + + public virtual bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + // Here because you must be sure you can use the skill before calling CheckHit if the ability has a HCI bonus for example + return true; + } + + public virtual bool OnBeforeDamage( Mobile attacker, Mobile defender ) + { + return true; + } + + public virtual bool RequiresTactics( Mobile from ) + { + return true; + } + + public virtual double GetRequiredSkill( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon != null && weapon.PrimaryAbility == this ) + return 70.0; + else if ( weapon != null && weapon.SecondaryAbility == this ) + return 90.0; + + return 200.0; + } + + public virtual int CalculateMana( Mobile from ) + { + int mana = BaseMana; + + double skillTotal = GetSkill( from, SkillName.Swords ) + GetSkill( from, SkillName.Macing ) + + GetSkill( from, SkillName.Fencing ) + GetSkill( from, SkillName.Archery ) + GetSkill( from, SkillName.Parry ) + + GetSkill( from, SkillName.Lumberjacking ) + GetSkill( from, SkillName.Stealth ) + + GetSkill( from, SkillName.Poisoning ) + GetSkill( from, SkillName.Bushido ) + GetSkill( from, SkillName.Ninjitsu ); + + if ( skillTotal >= 300.0 ) + mana -= 10; + else if ( skillTotal >= 200.0 ) + mana -= 5; + + double scalar = 1.0; + if ( !Server.Spells.Necromancy.MindRotSpell.GetMindRotScalar( from, ref scalar ) ) + scalar = 1.0; + + // Lower Mana Cost = 40% + int lmc = Math.Min( AosAttributes.GetValue( from, AosAttribute.LowerManaCost ), 40 ); + + scalar -= (double)lmc / 100; + mana = (int)(mana * scalar); + + // Using a special move within 3 seconds of the previous special move costs double mana + if ( GetContext( from ) != null ) + mana *= 2; + + return mana; + } + + public virtual bool CheckWeaponSkill( Mobile from ) + { + BaseWeapon weapon = from.Weapon as BaseWeapon; + + if ( weapon == null ) + return false; + + Skill skill = from.Skills[weapon.Skill]; + double reqSkill = GetRequiredSkill( from ); + bool reqTactics = Core.ML && RequiresTactics( from ); + + if ( Core.ML && reqTactics && from.Skills[SkillName.Tactics].Base < reqSkill ) + { + from.SendLocalizedMessage( 1079308, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack + return false; + } + + if ( skill != null && skill.Base >= reqSkill ) + return true; + + /* */ + if ( weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills[SkillName.Swords].Base >= reqSkill || from.Skills[SkillName.Macing].Base >= reqSkill || from.Skills[SkillName.Fencing].Base >= reqSkill) ) + return true; + /* */ + + if ( reqTactics ) + { + from.SendLocalizedMessage( 1079308, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack + } + else + { + from.SendLocalizedMessage( 1060182, reqSkill.ToString() ); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack + } + + return false; + } + + public virtual bool CheckSkills( Mobile from ) + { + return CheckWeaponSkill( from ); + } + + public virtual double GetSkill( Mobile from, SkillName skillName ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return 0.0; + + return skill.Value; + } + + public virtual bool CheckMana( Mobile from, bool consume ) + { + int mana = CalculateMana( from ); + + if ( from.Mana < mana ) + { + if ((from is BaseCreature) && (from as BaseCreature).HasManaOveride) + { + return true; + } + from.SendLocalizedMessage( 1060181, mana.ToString() ); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack + return false; + } + + if ( consume ) + { + if ( GetContext( from ) == null ) + { + Timer timer = new WeaponAbilityTimer( from ); + timer.Start(); + + AddContext( from, new WeaponAbilityContext( timer ) ); + } + + from.Mana -= mana; + } + + return true; + } + + public virtual bool Validate( Mobile from ) + { + if ( !from.Player ) + return true; + + NetState state = from.NetState; + + if ( state == null ) + return false; + + if( RequiresSE && !state.SupportsExpansion( Expansion.SE ) ) + { + from.SendLocalizedMessage( 1063456 ); // You must upgrade to Samurai Empire in order to use that ability. + return false; + } + + if ( Spells.Bushido.HonorableExecution.IsUnderPenalty( from ) || Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) ) + { + from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now. + return false; + } + + if ( Core.ML && from.Spell != null ) + { + from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now. + return false; + } + + #region Dueling + string option = null; + + if (this is ArmorIgnore) + option = "Armor Ignore"; + else if (this is BleedAttack) + option = "Bleed Attack"; + else if (this is ConcussionBlow) + option = "Concussion Blow"; + else if (this is CrushingBlow) + option = "Crushing Blow"; + else if (this is Disarm) + option = "Disarm"; + else if (this is Dismount) + option = "Dismount"; + else if (this is DoubleStrike) + option = "Double Strike"; + else if (this is InfectiousStrike) + option = "Infectious Strike"; + else if (this is MortalStrike) + option = "Mortal Strike"; + else if (this is MovingShot) + option = "Moving Shot"; + else if (this is ParalyzingBlow) + option = "Paralyzing Blow"; + else if (this is ShadowStrike) + option = "Shadow Strike"; + else if (this is WhirlwindAttack) + option = "Whirlwind Attack"; + else if (this is RidingSwipe) + option = "Riding Swipe"; + else if (this is FrenziedWhirlwind) + option = "Frenzied Whirlwind"; + else if (this is Block) + option = "Block"; + else if (this is DefenseMastery) + option = "Defense Mastery"; + else if (this is NerveStrike) + option = "Nerve Strike"; + else if (this is TalonStrike) + option = "Talon Strike"; + else if (this is Feint) + option = "Feint"; + else if (this is DualWield) + option = "Dual Wield"; + else if (this is DoubleShot) + option = "Double Shot"; + else if (this is ArmorPierce) + option = "Armor Pierce"; + + + if (option != null && !Engines.ConPVP.DuelContext.AllowSpecialAbility(from, option, true)) + return false; + #endregion + + return CheckSkills( from ) && CheckMana( from, false ); + } + + private static WeaponAbility[] m_Abilities = new WeaponAbility[31] + { + null, + new ArmorIgnore(), + new BleedAttack(), + new ConcussionBlow(), + new CrushingBlow(), + new Disarm(), + new Dismount(), + new DoubleStrike(), + new InfectiousStrike(), + new MortalStrike(), + new MovingShot(), + new ParalyzingBlow(), + new ShadowStrike(), + new WhirlwindAttack(), + + new RidingSwipe(), + new FrenziedWhirlwind(), + new Block(), + new DefenseMastery(), + new NerveStrike(), + new TalonStrike(), + new Feint(), + new DualWield(), + new DoubleShot(), + new ArmorPierce(), + null, + null, + null, + null, + null, + null, + new Disrobe() + }; + + public static WeaponAbility[] Abilities{ get{ return m_Abilities; } } + + private static Hashtable m_Table = new Hashtable(); + + public static Hashtable Table{ get{ return m_Table; } } + + public static readonly WeaponAbility ArmorIgnore = m_Abilities[ 1]; + public static readonly WeaponAbility BleedAttack = m_Abilities[ 2]; + public static readonly WeaponAbility ConcussionBlow = m_Abilities[ 3]; + public static readonly WeaponAbility CrushingBlow = m_Abilities[ 4]; + public static readonly WeaponAbility Disarm = m_Abilities[ 5]; + public static readonly WeaponAbility Dismount = m_Abilities[ 6]; + public static readonly WeaponAbility DoubleStrike = m_Abilities[ 7]; + public static readonly WeaponAbility InfectiousStrike = m_Abilities[ 8]; + public static readonly WeaponAbility MortalStrike = m_Abilities[ 9]; + public static readonly WeaponAbility MovingShot = m_Abilities[10]; + public static readonly WeaponAbility ParalyzingBlow = m_Abilities[11]; + public static readonly WeaponAbility ShadowStrike = m_Abilities[12]; + public static readonly WeaponAbility WhirlwindAttack = m_Abilities[13]; + + public static readonly WeaponAbility RidingSwipe = m_Abilities[14]; + public static readonly WeaponAbility FrenziedWhirlwind = m_Abilities[15]; + public static readonly WeaponAbility Block = m_Abilities[16]; + public static readonly WeaponAbility DefenseMastery = m_Abilities[17]; + public static readonly WeaponAbility NerveStrike = m_Abilities[18]; + public static readonly WeaponAbility TalonStrike = m_Abilities[19]; + public static readonly WeaponAbility Feint = m_Abilities[20]; + public static readonly WeaponAbility DualWield = m_Abilities[21]; + public static readonly WeaponAbility DoubleShot = m_Abilities[22]; + public static readonly WeaponAbility ArmorPierce = m_Abilities[23]; + + public static readonly WeaponAbility Bladeweave = m_Abilities[24]; + public static readonly WeaponAbility ForceArrow = m_Abilities[25]; + public static readonly WeaponAbility LightningArrow = m_Abilities[26]; + public static readonly WeaponAbility PsychicAttack = m_Abilities[27]; + public static readonly WeaponAbility SerpentArrow = m_Abilities[28]; + public static readonly WeaponAbility ForceOfNature = m_Abilities[29]; + + public static readonly WeaponAbility Disrobe = m_Abilities[30]; + + public static bool IsWeaponAbility( Mobile m, WeaponAbility a ) + { + if ( a == null ) + return true; + + if ( !m.Player ) + return true; + + BaseWeapon weapon = m.Weapon as BaseWeapon; + + return ( weapon != null && (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a) ); + } + + public virtual bool ValidatesDuringHit{ get { return true; } } + + public static WeaponAbility GetCurrentAbility( Mobile m ) + { + if ( !Core.AOS ) + { + ClearCurrentAbility( m ); + return null; + } + + WeaponAbility a = (WeaponAbility)m_Table[m]; + + if ( !IsWeaponAbility( m, a ) ) + { + ClearCurrentAbility( m ); + return null; + } + + if ( a != null && a.ValidatesDuringHit && !a.Validate( m ) ) + { + ClearCurrentAbility( m ); + return null; + } + + return a; + } + + public static bool SetCurrentAbility( Mobile m, WeaponAbility a ) + { + if ( !Core.AOS ) + { + ClearCurrentAbility( m ); + return false; + } + + if ( !IsWeaponAbility( m, a ) ) + { + ClearCurrentAbility( m ); + return false; + } + + if ( a != null && !a.Validate( m ) ) + { + ClearCurrentAbility( m ); + return false; + } + + if ( a == null ) + { + m_Table.Remove( m ); + } + else + { + SpecialMove.ClearCurrentMove( m ); + + m_Table[m] = a; + } + + return true; + } + + public static void ClearCurrentAbility( Mobile m ) + { + m_Table.Remove( m ); + + if ( Core.AOS && m.NetState != null ) + m.Send( ClearWeaponAbility.Instance ); + } + + public static void Initialize() + { + EventSink.SetAbility += new SetAbilityEventHandler( EventSink_SetAbility ); + } + + public WeaponAbility() + { + } + + private static void EventSink_SetAbility( SetAbilityEventArgs e ) + { + int index = e.Index; + + if ( index == 0 ) + ClearCurrentAbility( e.Mobile ); + else if ( index >= 1 && index < m_Abilities.Length ) + SetCurrentAbility( e.Mobile, m_Abilities[index] ); + } + + + private static Hashtable m_PlayersTable = new Hashtable(); + + private static void AddContext( Mobile m, WeaponAbilityContext context ) + { + m_PlayersTable[m] = context; + } + + private static void RemoveContext( Mobile m ) + { + WeaponAbilityContext context = GetContext( m ); + + if ( context != null ) + RemoveContext( m, context ); + } + + private static void RemoveContext( Mobile m, WeaponAbilityContext context ) + { + m_PlayersTable.Remove( m ); + + context.Timer.Stop(); + } + + private static WeaponAbilityContext GetContext( Mobile m ) + { + return ( m_PlayersTable[m] as WeaponAbilityContext ); + } + + private class WeaponAbilityTimer : Timer + { + private Mobile m_Mobile; + + public WeaponAbilityTimer( Mobile from ) : base ( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Mobile = from; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + RemoveContext( m_Mobile ); + } + } + + private class WeaponAbilityContext + { + private Timer m_Timer; + + public Timer Timer{ get{ return m_Timer; } } + + public WeaponAbilityContext( Timer timer ) + { + m_Timer = timer; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Abilities/WhirlwindAttack.cs b/Scripts/Items/Weapons/Abilities/WhirlwindAttack.cs new file mode 100644 index 0000000..2d218d6 --- /dev/null +++ b/Scripts/Items/Weapons/Abilities/WhirlwindAttack.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using Server; +using Server.Spells; + +namespace Server.Items +{ + /// + /// A godsend to a warrior surrounded, the Whirlwind Attack allows the fighter to strike at all nearby targets in one mighty spinning swing. + /// + public class WhirlwindAttack : WeaponAbility + { + public WhirlwindAttack() + { + } + + public override int BaseMana{ get{ return 15; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) ) + return; + + ClearCurrentAbility( attacker ); + + Map map = attacker.Map; + + if ( map == null ) + return; + + BaseWeapon weapon = attacker.Weapon as BaseWeapon; + + if ( weapon == null ) + return; + + if ( !CheckMana( attacker, true ) ) + return; + + attacker.FixedEffect( 0x3728, 10, 15 ); + attacker.PlaySound( 0x2A1 ); + + ArrayList list = new ArrayList(); + + foreach ( Mobile m in attacker.GetMobilesInRange( 1 ) ) + list.Add( m ); + + ArrayList targets = new ArrayList(); + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + if ( m != defender && m != attacker && SpellHelper.ValidIndirectTarget( attacker, m ) ) + { + if ( m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee( m ) || !attacker.CanBeHarmful( m ) ) + continue; + + if ( !attacker.InRange( m, weapon.MaxRange ) ) + continue; + + if ( attacker.InLOS( m ) ) + targets.Add( m ); + } + } + + if ( targets.Count > 0 ) + { + double bushido = attacker.Skills.Bushido.Value; + double damageBonus = 1.0 + Math.Pow( (targets.Count * bushido) / 60, 2 ) / 100; + + if ( damageBonus > 2.0 ) + damageBonus = 2.0; + + attacker.RevealingAction(); + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + attacker.SendLocalizedMessage( 1060161 ); // The whirling attack strikes a target! + m.SendLocalizedMessage( 1060162 ); // You are struck by the whirling attack and take damage! + + weapon.OnHit( attacker, m, damageBonus ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/AxeOfTheHeavens.cs b/Scripts/Items/Weapons/Artifacts/AxeOfTheHeavens.cs new file mode 100644 index 0000000..bd02e3e --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/AxeOfTheHeavens.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class AxeOfTheHeavens : DoubleAxe + { + public override int LabelNumber{ get{ return 1061106; } } // Axe of the Heavens + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public AxeOfTheHeavens() + { + Hue = 0x4D5; + WeaponAttributes.HitLightning = 50; + Attributes.AttackChance = 15; + Attributes.DefendChance = 15; + Attributes.WeaponDamage = 50; + } + + public AxeOfTheHeavens( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/BladeOfInsanity.cs b/Scripts/Items/Weapons/Artifacts/BladeOfInsanity.cs new file mode 100644 index 0000000..2ad03e5 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/BladeOfInsanity.cs @@ -0,0 +1,45 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BladeOfInsanity : Katana + { + public override int LabelNumber{ get{ return 1061088; } } // Blade of Insanity + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BladeOfInsanity() + { + Hue = 0x76D; + WeaponAttributes.HitLeechStam = 100; + Attributes.RegenStam = 2; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 50; + } + + public BladeOfInsanity( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 0x44F ) + Hue = 0x76D; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/BladeOfTheRighteous.cs b/Scripts/Items/Weapons/Artifacts/BladeOfTheRighteous.cs new file mode 100644 index 0000000..4026589 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/BladeOfTheRighteous.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BladeOfTheRighteous : Longsword + { + public override int LabelNumber{ get{ return 1061107; } } // Blade of the Righteous + public override int ArtifactRarity{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BladeOfTheRighteous() + { + Hue = 0x47E; + //Slayer = SlayerName.DaemonDismissal; + Slayer = SlayerName.Exorcism; + WeaponAttributes.HitLeechHits = 50; + WeaponAttributes.UseBestSkill = 1; + Attributes.BonusHits = 10; + Attributes.WeaponDamage = 50; + } + + public BladeOfTheRighteous( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Slayer == SlayerName.None ) + Slayer = SlayerName.Exorcism; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/BoneCrusher.cs b/Scripts/Items/Weapons/Artifacts/BoneCrusher.cs new file mode 100644 index 0000000..2b6c1e2 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/BoneCrusher.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BoneCrusher : WarMace + { + public override int LabelNumber{ get{ return 1061596; } } // Bone Crusher + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BoneCrusher() + { + ItemID = 0x1406; + Hue = 0x60C; + WeaponAttributes.HitLowerDefend = 50; + Attributes.BonusStr = 10; + Attributes.WeaponDamage = 75; + } + + public BoneCrusher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 0x604 ) + Hue = 0x60C; + + if ( ItemID == 0x1407 ) + ItemID = 0x1406; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/BreathOfTheDead.cs b/Scripts/Items/Weapons/Artifacts/BreathOfTheDead.cs new file mode 100644 index 0000000..042baac --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/BreathOfTheDead.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class BreathOfTheDead : BoneHarvester + { + public override int LabelNumber{ get{ return 1061109; } } // Breath of the Dead + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public BreathOfTheDead() + { + Hue = 0x455; + WeaponAttributes.HitLeechHits = 100; + WeaponAttributes.HitHarm = 25; + Attributes.SpellDamage = 5; + Attributes.WeaponDamage = 50; + } + + public BreathOfTheDead( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/Frostbringer.cs b/Scripts/Items/Weapons/Artifacts/Frostbringer.cs new file mode 100644 index 0000000..3ed6568 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/Frostbringer.cs @@ -0,0 +1,47 @@ +using System; +using Server; + +namespace Server.Items +{ + public class Frostbringer : Bow + { + public override int LabelNumber{ get{ return 1061111; } } // Frostbringer + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public Frostbringer() + { + Hue = 0x4F2; + WeaponAttributes.HitDispel = 50; + Attributes.RegenStam = 10; + Attributes.WeaponDamage = 50; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = pois = nrgy = chaos = direct = 0; + cold = 100; + } + + public Frostbringer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs b/Scripts/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs new file mode 100644 index 0000000..f983e6c --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/LegacyOfTheDreadLord.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class LegacyOfTheDreadLord : Bardiche + { + public override int LabelNumber{ get{ return 1060860; } } // Legacy of the Dread Lord + public override int ArtifactRarity{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public LegacyOfTheDreadLord() + { + Hue = 0x676; + Attributes.SpellChanneling = 1; + Attributes.CastRecovery = 3; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 50; + } + + public LegacyOfTheDreadLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Attributes.CastSpeed == 3 ) + Attributes.CastRecovery = 3; + + if ( Hue == 0x4B9 ) + Hue = 0x676; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/SerpentsFang.cs b/Scripts/Items/Weapons/Artifacts/SerpentsFang.cs new file mode 100644 index 0000000..0236fc8 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/SerpentsFang.cs @@ -0,0 +1,53 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SerpentsFang : Kryss + { + public override int LabelNumber{ get{ return 1061601; } } // Serpent's Fang + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public SerpentsFang() + { + ItemID = 0x1400; + Hue = 0x488; + WeaponAttributes.HitPoisonArea = 100; + WeaponAttributes.ResistPoisonBonus = 20; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 50; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + fire = cold = nrgy = chaos = direct = 0; + phys = 25; + pois = 75; + } + + public SerpentsFang( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( ItemID == 0x1401 ) + ItemID = 0x1400; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/StaffOfTheMagi.cs b/Scripts/Items/Weapons/Artifacts/StaffOfTheMagi.cs new file mode 100644 index 0000000..94ccfa9 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/StaffOfTheMagi.cs @@ -0,0 +1,54 @@ +using System; +using Server; + +namespace Server.Items +{ + public class StaffOfTheMagi : BlackStaff + { + public override int LabelNumber{ get{ return 1061600; } } // Staff of the Magi + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public StaffOfTheMagi() + { + Hue = 0x481; + WeaponAttributes.MageWeapon = 30; + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = 1; + Attributes.WeaponDamage = 50; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public StaffOfTheMagi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( WeaponAttributes.MageWeapon == 0 ) + WeaponAttributes.MageWeapon = 30; + + if ( ItemID == 0xDF1 ) + ItemID = 0xDF0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/TheBeserkersMaul.cs b/Scripts/Items/Weapons/Artifacts/TheBeserkersMaul.cs new file mode 100644 index 0000000..8259eba --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/TheBeserkersMaul.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheBeserkersMaul : Maul + { + public override int LabelNumber{ get{ return 1061108; } } // The Berserker's Maul + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TheBeserkersMaul() + { + Hue = 0x21; + Attributes.WeaponSpeed = 75; + Attributes.WeaponDamage = 50; + } + + public TheBeserkersMaul( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/TheDragonSlayer.cs b/Scripts/Items/Weapons/Artifacts/TheDragonSlayer.cs new file mode 100644 index 0000000..db87c33 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/TheDragonSlayer.cs @@ -0,0 +1,52 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheDragonSlayer : Lance + { + public override int LabelNumber{ get{ return 1061248; } } // The Dragon Slayer + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TheDragonSlayer() + { + Hue = 0x530; + Slayer = SlayerName.DragonSlaying; + Attributes.Luck = 110; + Attributes.WeaponDamage = 50; + WeaponAttributes.ResistFireBonus = 20; + WeaponAttributes.UseBestSkill = 1; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public TheDragonSlayer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Slayer == SlayerName.None ) + Slayer = SlayerName.DragonSlaying; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/TheDryadBow.cs b/Scripts/Items/Weapons/Artifacts/TheDryadBow.cs new file mode 100644 index 0000000..00dd789 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/TheDryadBow.cs @@ -0,0 +1,57 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheDryadBow : Bow + { + public override int LabelNumber{ get{ return 1061090; } } // The Dryad Bow + public override int ArtifactRarity{ get{ return 11; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TheDryadBow() + { + ItemID = 0x13B1; + Hue = 0x48F; + SkillBonuses.SetValues( 0, m_PossibleBonusSkills[Utility.Random(m_PossibleBonusSkills.Length)], (Utility.Random( 4 ) == 0 ? 10.0 : 5.0) ); + WeaponAttributes.SelfRepair = 5; + Attributes.WeaponSpeed = 50; + Attributes.WeaponDamage = 35; + WeaponAttributes.ResistPoisonBonus = 15; + } + + private static SkillName[] m_PossibleBonusSkills = new SkillName[] + { + SkillName.Archery, + SkillName.Healing, + SkillName.MagicResist, + SkillName.Peacemaking, + SkillName.Chivalry, + SkillName.Ninjitsu + }; + + public TheDryadBow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 ) + SkillBonuses.SetValues( 0, m_PossibleBonusSkills[Utility.Random(m_PossibleBonusSkills.Length)], (Utility.Random( 4 ) == 0 ? 10.0 : 5.0) ); + } + } +} diff --git a/Scripts/Items/Weapons/Artifacts/TheTaskmaster.cs b/Scripts/Items/Weapons/Artifacts/TheTaskmaster.cs new file mode 100644 index 0000000..9e1cd5e --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/TheTaskmaster.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TheTaskmaster : WarFork + { + public override int LabelNumber{ get{ return 1061110; } } // The Taskmaster + public override int ArtifactRarity{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TheTaskmaster() + { + Hue = 0x4F8; + WeaponAttributes.HitPoisonArea = 100; + Attributes.BonusDex = 5; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 50; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = nrgy = chaos = direct = 0; + pois = 100; + } + + public TheTaskmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/TitansHammer.cs b/Scripts/Items/Weapons/Artifacts/TitansHammer.cs new file mode 100644 index 0000000..d2b1cac --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/TitansHammer.cs @@ -0,0 +1,42 @@ +using System; +using Server; + +namespace Server.Items +{ + public class TitansHammer : WarHammer + { + public override int LabelNumber{ get{ return 1060024; } } // Titan's Hammer + public override int ArtifactRarity{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public TitansHammer() + { + Hue = 0x482; + WeaponAttributes.HitEnergyArea = 100; + Attributes.BonusStr = 15; + Attributes.AttackChance = 15; + Attributes.WeaponDamage = 50; + } + + public TitansHammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Artifacts/ZyronicClaw.cs b/Scripts/Items/Weapons/Artifacts/ZyronicClaw.cs new file mode 100644 index 0000000..1bc73e7 --- /dev/null +++ b/Scripts/Items/Weapons/Artifacts/ZyronicClaw.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ZyronicClaw : ExecutionersAxe + { + public override int LabelNumber{ get{ return 1061593; } } // Zyronic Claw + public override int ArtifactRarity{ get{ return 10; } } + + public override int InitMinHits{ get{ return 255; } } + public override int InitMaxHits{ get{ return 255; } } + + [Constructable] + public ZyronicClaw() + { + Hue = 0x485; + Slayer = SlayerName.ElementalBan; + WeaponAttributes.HitLeechMana = 50; + Attributes.AttackChance = 30; + Attributes.WeaponDamage = 50; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + chaos = direct = 0; + phys = fire = cold = pois = nrgy = 20; + } + + public ZyronicClaw( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Slayer == SlayerName.None ) + Slayer = SlayerName.ElementalBan; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/Axe.cs b/Scripts/Items/Weapons/Axes/Axe.cs new file mode 100644 index 0000000..75c0b22 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/Axe.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xF49, 0xF4a )] + public class Axe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Dismount; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 37; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 37; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public Axe() : base( 0xF49 ) + { + Weight = 4.0; + } + + public Axe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/BaseAxe.cs b/Scripts/Items/Weapons/Axes/BaseAxe.cs new file mode 100644 index 0000000..b17ec28 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/BaseAxe.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Engines.Harvest; +using Server.ContextMenus; +using Server.Network; + +namespace Server.Items +{ + public interface IAxe + { + bool Axe( Mobile from, BaseAxe axe ); + } + + public abstract class BaseAxe : BaseMeleeWeapon + { + public override int DefHitSound{ get{ return 0x232; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override SkillName DefSkill{ get{ return SkillName.Swords; } } + public override WeaponType DefType{ get{ return WeaponType.Axe; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash2H; } } + + public virtual HarvestSystem HarvestSystem{ get{ return Lumberjacking.System; } } + + private int m_UsesRemaining; + private bool m_ShowUsesRemaining; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ShowUsesRemaining + { + get { return m_ShowUsesRemaining; } + set { m_ShowUsesRemaining = value; InvalidateProperties(); } + } + + public virtual int GetUsesScalar() + { + if ( Quality == WeaponQuality.Exceptional ) + return 200; + + return 100; + } + + public override void UnscaleDurability() + { + base.UnscaleDurability(); + + int scale = GetUsesScalar(); + + m_UsesRemaining = ((m_UsesRemaining * 100) + (scale - 1)) / scale; + InvalidateProperties(); + } + + public override void ScaleDurability() + { + base.ScaleDurability(); + + int scale = GetUsesScalar(); + + m_UsesRemaining = ((m_UsesRemaining * scale) + 99) / 100; + InvalidateProperties(); + } + + public BaseAxe( int itemID ) : base( itemID ) + { + m_UsesRemaining = 150; + } + + public BaseAxe( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick(Mobile from) + { + // Scriptiz : gestion du double clic pour �quipper un objet + if (from.FindItemOnLayer(this.Layer) != this) + { + base.OnDoubleClick(from); + return; + } + + if (HarvestSystem == null || Deleted) + return; + + Point3D loc = GetWorldLocation(); + + if (!from.InLOS(loc) || !from.InRange(loc, 2)) + { + from.LocalOverheadMessage(Server.Network.MessageType.Regular, 0x3E9, 1019045); // I can't reach that + return; + } + else if (!this.IsAccessibleTo(from)) + { + this.PublicOverheadMessage(MessageType.Regular, 0x3E9, 1061637); // You are not allowed to access this. + return; + } + + if (!(this.HarvestSystem is Mining)) + from.SendLocalizedMessage(1010018); // What do you want to use this item on? + + HarvestSystem.BeginHarvesting(from, this); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( HarvestSystem != null ) + BaseHarvestTool.AddContextMenuEntries( from, this, list, HarvestSystem ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (bool) m_ShowUsesRemaining ); + + writer.Write( (int) m_UsesRemaining ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_ShowUsesRemaining = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_UsesRemaining = reader.ReadInt(); + goto case 0; + } + case 0: + { + if ( m_UsesRemaining < 1 ) + m_UsesRemaining = 150; + + break; + } + } + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && (attacker.Skills[SkillName.Anatomy].Value / 400.0) >= Utility.RandomDouble() && Engines.ConPVP.DuelContext.AllowSpecialAbility(attacker, "Concussion Blow", false)) + { + StatMod mod = defender.GetStatMod( "Concussion" ); + + if ( mod == null ) + { + defender.SendMessage( "You receive a concussion blow!" ); + defender.AddStatMod( new StatMod( StatType.Int, "Concussion", -(defender.RawInt / 2), TimeSpan.FromSeconds( 30.0 ) ) ); + + attacker.SendMessage( "You deliver a concussion blow!" ); + attacker.PlaySound( 0x308 ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/BattleAxe.cs b/Scripts/Items/Weapons/Axes/BattleAxe.cs new file mode 100644 index 0000000..06ca255 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/BattleAxe.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xF47, 0xF48 )] + public class BattleAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 31; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 38; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public BattleAxe() : base( 0xF47 ) + { + Weight = 4.0; + Layer = Layer.TwoHanded; + } + + public BattleAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/DoubleAxe.cs b/Scripts/Items/Weapons/Axes/DoubleAxe.cs new file mode 100644 index 0000000..2e91f54 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/DoubleAxe.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xf4b, 0xf4c )] + public class DoubleAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 33; } } + public override float MlSpeed{ get{ return 3.25f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 35; } } + public override int OldSpeed{ get{ return 37; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public DoubleAxe() : base( 0xF4B ) + { + Weight = 8.0; + } + + public DoubleAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/ExecutionersAxe.cs b/Scripts/Items/Weapons/Axes/ExecutionersAxe.cs new file mode 100644 index 0000000..01b5077 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/ExecutionersAxe.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xf45, 0xf46 )] + public class ExecutionersAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 33; } } + public override float MlSpeed{ get{ return 3.25f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 37; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public ExecutionersAxe() : base( 0xF45 ) + { + Weight = 8.0; + } + + public ExecutionersAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/GuardianAxe.cs b/Scripts/Items/Weapons/Axes/GuardianAxe.cs new file mode 100644 index 0000000..5e347c2 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/GuardianAxe.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class GuardianAxe : OrnateAxe + { + public override int LabelNumber{ get{ return 1073545; } } // guardian axe + + [Constructable] + public GuardianAxe() + { + Attributes.BonusHits = 4; + Attributes.RegenHits = 1; + } + + public GuardianAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Axes/Hatchet.cs b/Scripts/Items/Weapons/Axes/Hatchet.cs new file mode 100644 index 0000000..2132c8e --- /dev/null +++ b/Scripts/Items/Weapons/Axes/Hatchet.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xF43, 0xF44 )] + public class Hatchet : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 41; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 2; } } + public override int OldMaxDamage{ get{ return 17; } } + public override int OldSpeed{ get{ return 40; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public Hatchet() : base( 0xF43 ) + { + Weight = 4.0; + } + + public Hatchet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/HeavyOrnateAxe.cs b/Scripts/Items/Weapons/Axes/HeavyOrnateAxe.cs new file mode 100644 index 0000000..ab20786 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/HeavyOrnateAxe.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class HeavyOrnateAxe : OrnateAxe + { + public override int LabelNumber{ get{ return 1073548; } } // heavy ornate axe + + [Constructable] + public HeavyOrnateAxe() + { + Attributes.WeaponDamage = 8; + } + + public HeavyOrnateAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Axes/LargeBattleAxe.cs b/Scripts/Items/Weapons/Axes/LargeBattleAxe.cs new file mode 100644 index 0000000..784c709 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/LargeBattleAxe.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x13FB, 0x13FA )] + public class LargeBattleAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.BleedAttack; } } + + public override int AosStrengthReq{ get{ return 80; } } + public override int AosMinDamage{ get{ return 16; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 29; } } + public override float MlSpeed{ get{ return 3.75f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 38; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public LargeBattleAxe() : base( 0x13FB ) + { + Weight = 6.0; + } + + public LargeBattleAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/Pickaxe.cs b/Scripts/Items/Weapons/Axes/Pickaxe.cs new file mode 100644 index 0000000..4927791 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/Pickaxe.cs @@ -0,0 +1,59 @@ +using System; +using Server.Items; +using Server.Network; +using Server.Engines.Harvest; + +namespace Server.Items +{ + [FlipableAttribute( 0xE86, 0xE85 )] + public class Pickaxe : BaseAxe, IUsesRemaining + { + public override HarvestSystem HarvestSystem{ get{ return Mining.System; } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 35; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 1; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 35; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 60; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } } + + [Constructable] + public Pickaxe() : base( 0xE86 ) + { + Weight = 11.0; + UsesRemaining = 50; + ShowUsesRemaining = true; + } + + public Pickaxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + ShowUsesRemaining = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/SingingAxe.cs b/Scripts/Items/Weapons/Axes/SingingAxe.cs new file mode 100644 index 0000000..3af6bc8 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/SingingAxe.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SingingAxe : OrnateAxe + { + public override int LabelNumber{ get{ return 1073546; } } // singing axe + + [Constructable] + public SingingAxe() + { + SkillBonuses.SetValues( 0, SkillName.Musicianship, 5 ); + } + + public SingingAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Axes/ThunderingAxe.cs b/Scripts/Items/Weapons/Axes/ThunderingAxe.cs new file mode 100644 index 0000000..c1f97db --- /dev/null +++ b/Scripts/Items/Weapons/Axes/ThunderingAxe.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ThunderingAxe : OrnateAxe + { + public override int LabelNumber{ get{ return 1073547; } } // thundering axe + + [Constructable] + public ThunderingAxe() + { + WeaponAttributes.HitLightning = 10; + } + + public ThunderingAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Axes/TwoHandedAxe.cs b/Scripts/Items/Weapons/Axes/TwoHandedAxe.cs new file mode 100644 index 0000000..277dc8b --- /dev/null +++ b/Scripts/Items/Weapons/Axes/TwoHandedAxe.cs @@ -0,0 +1,51 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x1443, 0x1442 )] + public class TwoHandedAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 16; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 31; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 39; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 90; } } + + [Constructable] + public TwoHandedAxe() : base( 0x1443 ) + { + Weight = 8.0; + } + + public TwoHandedAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Axes/WarAxe.cs b/Scripts/Items/Weapons/Axes/WarAxe.cs new file mode 100644 index 0000000..e355530 --- /dev/null +++ b/Scripts/Items/Weapons/Axes/WarAxe.cs @@ -0,0 +1,61 @@ +using System; +using Server.Items; +using Server.Network; +using Server.Engines.Harvest; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B0, 0x13AF )] + public class WarAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.BleedAttack; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 33; } } + public override float MlSpeed{ get{ return 3.25f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 27; } } + public override int OldSpeed{ get{ return 40; } } + + public override int DefHitSound{ get{ return 0x233; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + public override SkillName DefSkill{ get{ return SkillName.Macing; } } + public override WeaponType DefType{ get{ return WeaponType.Bashing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Bash1H; } } + + public override HarvestSystem HarvestSystem{ get{ return null; } } + + [Constructable] + public WarAxe() : base( 0x13B0 ) + { + Weight = 8.0; + } + + public WarAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/BaseMeleeWeapon.cs b/Scripts/Items/Weapons/BaseMeleeWeapon.cs new file mode 100644 index 0000000..eb13e49 --- /dev/null +++ b/Scripts/Items/Weapons/BaseMeleeWeapon.cs @@ -0,0 +1,66 @@ +using System; +using Server; +using Server.Spells.Spellweaving; + +namespace Server.Items +{ + public abstract class BaseMeleeWeapon : BaseWeapon + { + public BaseMeleeWeapon( int itemID ) : base( itemID ) + { + } + + public BaseMeleeWeapon( Serial serial ) : base( serial ) + { + } + + public override int AbsorbDamage( Mobile attacker, Mobile defender, int damage ) + { + damage = base.AbsorbDamage( attacker, defender, damage ); + + AttuneWeaponSpell.TryAbsorb( defender, ref damage ); + + if ( Core.AOS ) + return damage; + + int absorb = defender.MeleeDamageAbsorb; + + if ( absorb > 0 ) + { + if ( absorb > damage ) + { + int react = damage / 5; + + if ( react <= 0 ) + react = 1; + + defender.MeleeDamageAbsorb -= damage; + damage = 0; + + attacker.Damage( react, defender ); + + attacker.PlaySound( 0x1F1 ); + attacker.FixedEffect( 0x374A, 10, 16 ); + } + else + { + defender.MeleeDamageAbsorb = 0; + defender.SendLocalizedMessage( 1005556 ); // Your reactive armor spell has been nullified. + DefensiveSpell.Nullify( defender ); + } + } + + return damage; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + } + } +} diff --git a/Scripts/Items/Weapons/BaseWeapon.cs b/Scripts/Items/Weapons/BaseWeapon.cs new file mode 100644 index 0000000..b69560e --- /dev/null +++ b/Scripts/Items/Weapons/BaseWeapon.cs @@ -0,0 +1,4229 @@ +using System; +using System.Text; +using System.Collections; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Bushido; +using Server.Spells.Ninjitsu; +using Server.Factions; +using Server.Engines.Craft; +using System.Collections.Generic; +using Server.Spells.Spellweaving; + +namespace Server.Items +{ + public interface ISlayer + { + SlayerName Slayer { get; set; } + SlayerName Slayer2 { get; set; } + } + + public abstract class BaseWeapon : BaseWearable, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability + { + private string m_EngravedText; + + [CommandProperty( AccessLevel.GameMaster )] + public string EngravedText + { + get{ return m_EngravedText; } + set{ m_EngravedText = value; InvalidateProperties(); } + } + + #region Factions + private FactionItem m_FactionState; + + public FactionItem FactionItemState + { + get{ return m_FactionState; } + set + { + m_FactionState = value; + + if ( m_FactionState == null ) + Hue = CraftResources.GetHue( Resource ); + + LootType = ( m_FactionState == null ? LootType.Regular : LootType.Blessed ); + } + } + #endregion + + /* Weapon internals work differently now (Mar 13 2003) + * + * The attributes defined below default to -1. + * If the value is -1, the corresponding virtual 'Aos/Old' property is used. + * If not, the attribute value itself is used. Here's the list: + * - MinDamage + * - MaxDamage + * - Speed + * - HitSound + * - MissSound + * - StrRequirement, DexRequirement, IntRequirement + * - WeaponType + * - WeaponAnimation + * - MaxRange + */ + + #region Var declarations + + // Instance values. These values are unique to each weapon. + private WeaponDamageLevel m_DamageLevel; + private WeaponAccuracyLevel m_AccuracyLevel; + private WeaponDurabilityLevel m_DurabilityLevel; + private WeaponQuality m_Quality; + private Mobile m_Crafter; + private Poison m_Poison; + private int m_PoisonCharges; + private bool m_Identified; + private int m_Hits; + private int m_MaxHits; + private SlayerName m_Slayer; + private SlayerName m_Slayer2; + private SkillMod m_SkillMod, m_MageMod; + private CraftResource m_Resource; + private bool m_PlayerConstructed; + + private bool m_Cursed; // Is this weapon cursed via Curse Weapon necromancer spell? Temporary; not serialized. + private bool m_Consecrated; // Is this weapon blessed via Consecrate Weapon paladin ability? Temporary; not serialized. + + private AosAttributes m_AosAttributes; + private AosWeaponAttributes m_AosWeaponAttributes; + private AosSkillBonuses m_AosSkillBonuses; + private AosElementAttributes m_AosElementDamages; + + // Overridable values. These values are provided to override the defaults which get defined in the individual weapon scripts. + private int m_StrReq, m_DexReq, m_IntReq; + private int m_MinDamage, m_MaxDamage; + private int m_HitSound, m_MissSound; + private float m_Speed; + private int m_MaxRange; + private SkillName m_Skill; + private WeaponType m_Type; + private WeaponAnimation m_Animation; + #endregion + + #region Virtual Properties + public virtual WeaponAbility PrimaryAbility{ get{ return null; } } + public virtual WeaponAbility SecondaryAbility{ get{ return null; } } + + public virtual int DefMaxRange{ get{ return 1; } } + public virtual int DefHitSound{ get{ return 0; } } + public virtual int DefMissSound{ get{ return 0; } } + public virtual SkillName DefSkill{ get{ return SkillName.Swords; } } + public virtual WeaponType DefType{ get{ return WeaponType.Slashing; } } + public virtual WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } } + + public virtual int AosStrengthReq{ get{ return 0; } } + public virtual int AosDexterityReq{ get{ return 0; } } + public virtual int AosIntelligenceReq{ get{ return 0; } } + public virtual int AosMinDamage{ get{ return 0; } } + public virtual int AosMaxDamage{ get{ return 0; } } + public virtual int AosSpeed{ get{ return 0; } } + public virtual float MlSpeed{ get{ return 0.0f; } } + public virtual int AosMaxRange{ get{ return DefMaxRange; } } + public virtual int AosHitSound{ get{ return DefHitSound; } } + public virtual int AosMissSound{ get{ return DefMissSound; } } + public virtual SkillName AosSkill{ get{ return DefSkill; } } + public virtual WeaponType AosType{ get{ return DefType; } } + public virtual WeaponAnimation AosAnimation{ get{ return DefAnimation; } } + + public virtual int OldStrengthReq{ get{ return 0; } } + public virtual int OldDexterityReq{ get{ return 0; } } + public virtual int OldIntelligenceReq{ get{ return 0; } } + public virtual int OldMinDamage{ get{ return 0; } } + public virtual int OldMaxDamage{ get{ return 0; } } + public virtual int OldSpeed{ get{ return 0; } } + public virtual int OldMaxRange{ get{ return DefMaxRange; } } + public virtual int OldHitSound{ get{ return DefHitSound; } } + public virtual int OldMissSound{ get{ return DefMissSound; } } + public virtual SkillName OldSkill{ get{ return DefSkill; } } + public virtual WeaponType OldType{ get{ return DefType; } } + public virtual WeaponAnimation OldAnimation{ get{ return DefAnimation; } } + + public virtual int InitMinHits{ get{ return 0; } } + public virtual int InitMaxHits{ get{ return 0; } } + + public virtual bool CanFortify{ get{ return true; } } + + public override int PhysicalResistance{ get{ return m_AosWeaponAttributes.ResistPhysicalBonus; } } + public override int FireResistance{ get{ return m_AosWeaponAttributes.ResistFireBonus; } } + public override int ColdResistance{ get{ return m_AosWeaponAttributes.ResistColdBonus; } } + public override int PoisonResistance{ get{ return m_AosWeaponAttributes.ResistPoisonBonus; } } + public override int EnergyResistance{ get{ return m_AosWeaponAttributes.ResistEnergyBonus; } } + + public virtual SkillName AccuracySkill { get { return SkillName.Tactics; } } + #endregion + + #region Getters & Setters + [CommandProperty( AccessLevel.GameMaster )] + public AosAttributes Attributes + { + get{ return m_AosAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosWeaponAttributes WeaponAttributes + { + get{ return m_AosWeaponAttributes; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosSkillBonuses SkillBonuses + { + get{ return m_AosSkillBonuses; } + set{} + } + + [CommandProperty( AccessLevel.GameMaster )] + public AosElementAttributes AosElementDamages + { + get { return m_AosElementDamages; } + set { } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Cursed + { + get{ return m_Cursed; } + set{ m_Cursed = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Consecrated + { + get{ return m_Consecrated; } + set{ m_Consecrated = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Identified + { + get{ return m_Identified; } + set{ m_Identified = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitPoints + { + get{ return m_Hits; } + set + { + if ( m_Hits == value ) + return; + + if ( value > m_MaxHits ) + value = m_MaxHits; + + m_Hits = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxHitPoints + { + get{ return m_MaxHits; } + set{ m_MaxHits = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int PoisonCharges + { + get{ return m_PoisonCharges; } + set{ m_PoisonCharges = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get{ return m_Poison; } + set{ m_Poison = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public WeaponQuality Quality + { + get{ return m_Quality; } + set{ UnscaleDurability(); m_Quality = value; ScaleDurability(); InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Crafter + { + get{ return m_Crafter; } + set{ m_Crafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SlayerName Slayer + { + get{ return m_Slayer; } + set{ m_Slayer = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SlayerName Slayer2 + { + get { return m_Slayer2; } + set { m_Slayer2 = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource Resource + { + get{ return m_Resource; } + set{ UnscaleDurability(); m_Resource = value; Hue = CraftResources.GetHue( m_Resource ); InvalidateProperties(); ScaleDurability(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public WeaponDamageLevel DamageLevel + { + get{ return m_DamageLevel; } + set{ m_DamageLevel = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public WeaponDurabilityLevel DurabilityLevel + { + get{ return m_DurabilityLevel; } + set{ UnscaleDurability(); m_DurabilityLevel = value; InvalidateProperties(); ScaleDurability(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool PlayerConstructed + { + get{ return m_PlayerConstructed; } + set{ m_PlayerConstructed = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxRange + { + get{ return ( m_MaxRange == -1 ? Core.AOS ? AosMaxRange : OldMaxRange : m_MaxRange ); } + set{ m_MaxRange = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public WeaponAnimation Animation + { + get{ return ( m_Animation == (WeaponAnimation)(-1) ? Core.AOS ? AosAnimation : OldAnimation : m_Animation ); } + set{ m_Animation = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public WeaponType Type + { + get{ return ( m_Type == (WeaponType)(-1) ? Core.AOS ? AosType : OldType : m_Type ); } + set{ m_Type = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill + { + get{ return ( m_Skill == (SkillName)(-1) ? Core.AOS ? AosSkill : OldSkill : m_Skill ); } + set{ m_Skill = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitSound + { + get{ return ( m_HitSound == -1 ? Core.AOS ? AosHitSound : OldHitSound : m_HitSound ); } + set{ m_HitSound = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MissSound + { + get{ return ( m_MissSound == -1 ? Core.AOS ? AosMissSound : OldMissSound : m_MissSound ); } + set{ m_MissSound = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MinDamage + { + get{ return ( m_MinDamage == -1 ? Core.AOS ? AosMinDamage : OldMinDamage : m_MinDamage ); } + set{ m_MinDamage = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxDamage + { + get{ return ( m_MaxDamage == -1 ? Core.AOS ? AosMaxDamage : OldMaxDamage : m_MaxDamage ); } + set{ m_MaxDamage = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public float Speed + { + get + { + if ( m_Speed != -1 ) + return m_Speed; + + if ( Core.ML ) + return MlSpeed; + else if ( Core.AOS ) + return AosSpeed; + + return OldSpeed; + } + set{ m_Speed = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int StrRequirement + { + get{ return ( m_StrReq == -1 ? Core.AOS ? AosStrengthReq : OldStrengthReq : m_StrReq ); } + set{ m_StrReq = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DexRequirement + { + get{ return ( m_DexReq == -1 ? Core.AOS ? AosDexterityReq : OldDexterityReq : m_DexReq ); } + set{ m_DexReq = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int IntRequirement + { + get{ return ( m_IntReq == -1 ? Core.AOS ? AosIntelligenceReq : OldIntelligenceReq : m_IntReq ); } + set{ m_IntReq = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public WeaponAccuracyLevel AccuracyLevel + { + get + { + return m_AccuracyLevel; + } + set + { + if ( m_AccuracyLevel != value ) + { + m_AccuracyLevel = value; + + if ( UseSkillMod ) + { + if ( m_AccuracyLevel == WeaponAccuracyLevel.Regular ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = null; + } + else if ( m_SkillMod == null && Parent is Mobile ) + { + m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 ); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + else if ( m_SkillMod != null ) + { + m_SkillMod.Value = (int)m_AccuracyLevel * 5; + } + } + + InvalidateProperties(); + } + } + } + + //Plume ajout de la difficult� + [CommandProperty(AccessLevel.GameMaster)] + public int WeaponDifficulty + { + get { + int difficulty = 0; + + if (Attributes.AttackChance != 0) + difficulty++; + if (Attributes.BonusDex != 0) + difficulty++; + if (Attributes.BonusHits != 0) + difficulty++; + if (Attributes.BonusInt != 0) + difficulty++; + if (Attributes.BonusMana != 0) + difficulty++; + if (Attributes.BonusStam != 0) + difficulty++; + if (Attributes.BonusStr != 0) + difficulty++; + if (Attributes.CastRecovery != 0) + difficulty++; + if (Attributes.CastSpeed != 0) + difficulty++; + if (Attributes.DefendChance != 0) + difficulty++; + if (Attributes.EnhancePotions != 0) + difficulty++; + if (Attributes.LowerManaCost != 0) + difficulty++; + if (Attributes.LowerRegCost != 0) + difficulty++; + if (Attributes.Luck != 0) + difficulty++; + if (Attributes.NightSight != 0) + difficulty++; + if (Attributes.ReflectPhysical != 0) + difficulty++; + if (Attributes.RegenHits != 0) + difficulty++; + if (Attributes.RegenMana != 0) + difficulty++; + if (Attributes.RegenStam != 0) + difficulty++; + if (Attributes.SpellChanneling != 0) + difficulty++; + if (Attributes.SpellDamage != 0) + difficulty++; + if (Attributes.WeaponDamage != 0) + difficulty++; + if (Attributes.WeaponSpeed != 0) + difficulty++; + if (WeaponAttributes.DurabilityBonus != 0) + difficulty++; + if (WeaponAttributes.HitColdArea != 0) + difficulty++; + if (WeaponAttributes.HitDispel != 0) + difficulty++; + if (WeaponAttributes.HitEnergyArea != 0) + difficulty++; + if (WeaponAttributes.HitFireArea != 0) + difficulty++; + if (WeaponAttributes.HitFireball != 0) + difficulty++; + if (WeaponAttributes.HitHarm != 0) + difficulty++; + if (WeaponAttributes.HitLeechHits != 0) + difficulty++; + if (WeaponAttributes.HitLeechMana != 0) + difficulty++; + if (WeaponAttributes.HitLeechStam != 0) + difficulty++; + if (WeaponAttributes.HitLightning != 0) + difficulty++; + if (WeaponAttributes.HitLowerAttack != 0) + difficulty++; + if (WeaponAttributes.HitLowerDefend != 0) + difficulty++; + if (WeaponAttributes.HitMagicArrow != 0) + difficulty++; + if (WeaponAttributes.HitPhysicalArea != 0) + difficulty++; + if (WeaponAttributes.HitPoisonArea != 0) + difficulty++; + if (WeaponAttributes.LowerStatReq != 0) + difficulty++; + if (WeaponAttributes.MageWeapon != 0) + difficulty++; + if (WeaponAttributes.ResistColdBonus != 0) + difficulty++; + if (WeaponAttributes.ResistEnergyBonus != 0) + difficulty++; + if (WeaponAttributes.ResistFireBonus != 0) + difficulty++; + if (WeaponAttributes.ResistPhysicalBonus != 0) + difficulty++; + if (WeaponAttributes.ResistPoisonBonus != 0) + difficulty++; + if (WeaponAttributes.SelfRepair != 0) + difficulty++; + if (WeaponAttributes.UseBestSkill != 0) + difficulty++; + if (Slayer != SlayerName.None) + difficulty++; + if (Slayer2 != SlayerName.None) + difficulty++; + if (SkillBonuses.Skill_1_Value != 0) + difficulty++; + if (SkillBonuses.Skill_2_Value != 0) + difficulty++; + if (SkillBonuses.Skill_3_Value != 0) + difficulty++; + if (SkillBonuses.Skill_4_Value != 0) + difficulty++; + if (SkillBonuses.Skill_5_Value != 0) + difficulty++; + + if (difficulty > 5) + difficulty = 5; + + return difficulty; + } + } + + #endregion + + public override void OnAfterDuped( Item newItem ) + { + BaseWeapon weap = newItem as BaseWeapon; + + if ( weap == null ) + return; + + weap.m_AosAttributes = new AosAttributes( newItem, m_AosAttributes ); + weap.m_AosElementDamages = new AosElementAttributes( newItem, m_AosElementDamages ); + weap.m_AosSkillBonuses = new AosSkillBonuses( newItem, m_AosSkillBonuses ); + weap.m_AosWeaponAttributes = new AosWeaponAttributes( newItem, m_AosWeaponAttributes ); + } + + public virtual void UnscaleDurability() + { + int scale = 100 + GetDurabilityBonus(); + + m_Hits = ((m_Hits * 100) + (scale - 1)) / scale; + m_MaxHits = ((m_MaxHits * 100) + (scale - 1)) / scale; + InvalidateProperties(); + } + + public virtual void ScaleDurability() + { + int scale = 100 + GetDurabilityBonus(); + + m_Hits = ((m_Hits * scale) + 99) / 100; + m_MaxHits = ((m_MaxHits * scale) + 99) / 100; + InvalidateProperties(); + } + + public int GetDurabilityBonus() + { + int bonus = 0; + + if ( m_Quality == WeaponQuality.Exceptional ) + bonus += 20; + + switch ( m_DurabilityLevel ) + { + case WeaponDurabilityLevel.Durable: bonus += 10; break; + case WeaponDurabilityLevel.Substantial: bonus +=20; break; + case WeaponDurabilityLevel.Massive: bonus += 30; break; + case WeaponDurabilityLevel.Fortified: bonus += 45; break; + case WeaponDurabilityLevel.Indestructible: bonus += 60; break; + } + + if ( Core.AOS ) + { + bonus += m_AosWeaponAttributes.DurabilityBonus; + + CraftResourceInfo resInfo = CraftResources.GetInfo( m_Resource ); + CraftAttributeInfo attrInfo = null; + + if ( resInfo != null ) + attrInfo = resInfo.AttributeInfo; + + if ( attrInfo != null ) + bonus += attrInfo.WeaponDurability; + } + + return bonus; + } + + public int GetLowerStatReq() + { + if ( !Core.AOS ) + return 0; + + int v = m_AosWeaponAttributes.LowerStatReq; + + CraftResourceInfo info = CraftResources.GetInfo( m_Resource ); + + if ( info != null ) + { + CraftAttributeInfo attrInfo = info.AttributeInfo; + + if ( attrInfo != null ) + v += attrInfo.WeaponLowerRequirements; + } + + if ( v > 100 ) + v = 100; + + return v; + } + + public static void BlockEquip( Mobile m, TimeSpan duration ) + { + if ( m.BeginAction( typeof( BaseWeapon ) ) ) + new ResetEquipTimer( m, duration ).Start(); + } + + private class ResetEquipTimer : Timer + { + private Mobile m_Mobile; + + public ResetEquipTimer( Mobile m, TimeSpan duration ) : base( duration ) + { + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.EndAction( typeof( BaseWeapon ) ); + } + } + + public override bool CheckConflictingLayer( Mobile m, Item item, Layer layer ) + { + if ( base.CheckConflictingLayer( m, item, layer ) ) + return true; + + if ( this.Layer == Layer.TwoHanded && layer == Layer.OneHanded ) + { + m.SendLocalizedMessage( 500214 ); // You already have something in both hands. + return true; + } + else if ( this.Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) && !(item is BaseEquipableLight) ) + { + m.SendLocalizedMessage( 500215 ); // You can only wield one weapon at a time. + return true; + } + + return false; + } + + public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if ( !Ethics.Ethic.CheckTrade( from, to, newOwner, this ) ) + return false; + + return base.AllowSecureTrade( from, to, newOwner, accepted ); + } + + public virtual Race RequiredRace { get { return null; } } //On OSI, there are no weapons with race requirements, this is for custom stuff + + public override bool CanEquip( Mobile from ) + { + if ( !Ethics.Ethic.CheckEquip( from, this ) ) + return false; + + else if (!m_Identified) + { + from.SendMessage("Cette arme vous semble inconnue"); + return false; + } + + if( RequiredRace != null && from.Race != RequiredRace ) + { + if( RequiredRace == Race.Elf ) + from.SendLocalizedMessage( 1072203 ); // Only Elves may use this. + else + from.SendMessage( "Only {0} may use this.", RequiredRace.PluralName ); + + return false; + } + else if ( from.Dex < DexRequirement ) + { + from.SendMessage( "You are not nimble enough to equip that." ); + return false; + } + else if ( from.Str < AOS.Scale( StrRequirement, 100 - GetLowerStatReq() ) ) + { + from.SendLocalizedMessage( 500213 ); // You are not strong enough to equip that. + return false; + } + else if ( from.Int < IntRequirement ) + { + from.SendMessage( "You are not smart enough to equip that." ); + return false; + } + else if ( !from.CanBeginAction( typeof( BaseWeapon ) ) ) + { + return false; + } + else + { + return base.CanEquip( from ); + } + } + + public virtual bool UseSkillMod{ get{ return !Core.AOS; } } + + public override bool OnEquip( Mobile from ) + { + int strBonus = m_AosAttributes.BonusStr; + int dexBonus = m_AosAttributes.BonusDex; + int intBonus = m_AosAttributes.BonusInt; + + if ( (strBonus != 0 || dexBonus != 0 || intBonus != 0) ) + { + Mobile m = from; + + string modName = this.Serial.ToString(); + + if ( strBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + from.NextCombatTime = DateTime.Now + GetDelay( from ); + + if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular ) + { + if ( m_SkillMod != null ) + m_SkillMod.Remove(); + + m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 ); + from.AddSkillMod( m_SkillMod ); + } + + if ( Core.AOS && m_AosWeaponAttributes.MageWeapon != 0 && m_AosWeaponAttributes.MageWeapon != 30 ) + { + if ( m_MageMod != null ) + m_MageMod.Remove(); + + m_MageMod = new DefaultSkillMod( SkillName.Magery, true, -30 + m_AosWeaponAttributes.MageWeapon ); + from.AddSkillMod( m_MageMod ); + } + + + return true; + } + + public override void OnAdded( object parent ) + { + base.OnAdded( parent ); + + if ( parent is Mobile ) + { + Mobile from = (Mobile)parent; + + if ( Core.AOS ) + m_AosSkillBonuses.AddTo( from ); + + from.CheckStatTimers(); + from.Delta( MobileDelta.WeaponDamage ); + } + } + + public override void OnRemoved( object parent ) + { + if ( parent is Mobile ) + { + Mobile m = (Mobile)parent; + BaseWeapon weapon = m.Weapon as BaseWeapon; + + string modName = this.Serial.ToString(); + + m.RemoveStatMod( modName + "Str" ); + m.RemoveStatMod( modName + "Dex" ); + m.RemoveStatMod( modName + "Int" ); + + if ( weapon != null ) + m.NextCombatTime = DateTime.Now + weapon.GetDelay( m ); + + if ( UseSkillMod && m_SkillMod != null ) + { + m_SkillMod.Remove(); + m_SkillMod = null; + } + + if ( m_MageMod != null ) + { + m_MageMod.Remove(); + m_MageMod = null; + } + + if ( Core.AOS ) + m_AosSkillBonuses.Remove(); + + ImmolatingWeaponSpell.StopImmolating(this); + + m.CheckStatTimers(); + + m.Delta( MobileDelta.WeaponDamage ); + } + } + + public virtual SkillName GetUsedSkill( Mobile m, bool checkSkillAttrs ) + { + SkillName sk; + + if ( checkSkillAttrs && m_AosWeaponAttributes.UseBestSkill != 0 ) + { + double swrd = m.Skills[SkillName.Swords].Value; + double fenc = m.Skills[SkillName.Fencing].Value; + double mcng = m.Skills[SkillName.Macing].Value; + double val; + + sk = SkillName.Swords; + val = swrd; + + if ( fenc > val ){ sk = SkillName.Fencing; val = fenc; } + if ( mcng > val ){ sk = SkillName.Macing; val = mcng; } + } + else if ( m_AosWeaponAttributes.MageWeapon != 0 ) + { + if ( m.Skills[SkillName.Magery].Value > m.Skills[Skill].Value ) + sk = SkillName.Magery; + else + sk = Skill; + } + else + { + sk = Skill; + + if ( sk != SkillName.Wrestling && !m.Player && !m.Body.IsHuman && m.Skills[SkillName.Wrestling].Value > m.Skills[sk].Value ) + sk = SkillName.Wrestling; + } + + return sk; + } + + public virtual double GetAttackSkillValue( Mobile attacker, Mobile defender ) + { + return attacker.Skills[GetUsedSkill( attacker, true )].Value; + } + + public virtual double GetDefendSkillValue( Mobile attacker, Mobile defender ) + { + return defender.Skills[GetUsedSkill( defender, true )].Value; + } + + private static bool CheckAnimal( Mobile m, Type type ) + { + return AnimalForm.UnderTransformation( m, type ); + } + + public virtual bool CheckHit( Mobile attacker, Mobile defender ) + { + BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon; + BaseWeapon defWeapon = defender.Weapon as BaseWeapon; + + Skill atkSkill = attacker.Skills[atkWeapon.Skill]; + Skill defSkill = defender.Skills[defWeapon.Skill]; + + double atkValue = atkWeapon.GetAttackSkillValue( attacker, defender ); + double defValue = defWeapon.GetDefendSkillValue( attacker, defender ); + + double ourValue, theirValue; + + int bonus = GetHitChanceBonus(); + + TransformContext context = TransformationSpellHelper.GetContext(defender); + //Ajout de attack chance silver vs necro + if (Resource == CraftResource.MSilver && context != null && context.Spell is NecromancerSpell) + bonus += 5; + + //Plume : Ajout de hit hance pour les filles sur les hommes si Arme en Rose + if (Resource == CraftResource.MRose && attacker.Female && (!defender.Female)) + { + bonus += 10; + } + + if ( Core.AOS ) + { + if ( atkValue <= -20.0 ) + atkValue = -19.9; + + if ( defValue <= -20.0 ) + defValue = -19.9; + + bonus += AosAttributes.GetValue( attacker, AosAttribute.AttackChance ); + + if ( Spells.Chivalry.DivineFurySpell.UnderEffect( attacker ) ) + bonus += 10; // attacker gets 10% bonus when they're under divine fury + + if ( CheckAnimal( attacker, typeof( GreyWolf ) ) || CheckAnimal( attacker, typeof( BakeKitsune ) ) ) + bonus += 20; // attacker gets 20% bonus when under Wolf or Bake Kitsune form + + if ( HitLower.IsUnderAttackEffect( attacker ) ) + bonus -= 25; // Under Hit Lower Attack effect -> 25% malus + + WeaponAbility ability = WeaponAbility.GetCurrentAbility( attacker ); + + if ( ability != null ) + bonus += ability.AccuracyBonus; + + SpecialMove move = SpecialMove.GetCurrentMove( attacker ); + + if ( move != null ) + bonus += move.GetAccuracyBonus( attacker ); + + // Max Hit Chance Increase = 45% + if ( bonus > 45 ) + bonus = 45; + + ourValue = (atkValue + 20.0) * (100 + bonus); + + bonus = AosAttributes.GetValue( defender, AosAttribute.DefendChance ); + + if ( Spells.Chivalry.DivineFurySpell.UnderEffect( defender ) ) + bonus -= 20; // defender loses 20% bonus when they're under divine fury + + if ( HitLower.IsUnderDefenseEffect( defender ) ) + bonus -= 25; // Under Hit Lower Defense effect -> 25% malus + + int blockBonus = 0; + + if ( Block.GetBonus( defender, ref blockBonus ) ) + bonus += blockBonus; + + int surpriseMalus = 0; + + if ( SurpriseAttack.GetMalus( defender, ref surpriseMalus ) ) + bonus -= surpriseMalus; + + int discordanceEffect = 0; + + // Defender loses -0/-28% if under the effect of Discordance. + if ( SkillHandlers.Discordance.GetEffect( attacker, ref discordanceEffect ) ) + bonus -= discordanceEffect; + + // Defense Chance Increase = 45% + if ( bonus > 45 ) + bonus = 45; + + theirValue = (defValue + 20.0) * (100 + bonus); + + bonus = 0; + } + else + { + if ( atkValue <= -50.0 ) + atkValue = -49.9; + + if ( defValue <= -50.0 ) + defValue = -49.9; + + ourValue = (atkValue + 50.0); + theirValue = (defValue + 50.0); + } + + double chance = ourValue / (theirValue * 2.0); + + chance *= 1.0 + ((double)bonus / 100); + + if ( Core.AOS && chance < 0.02 ) + chance = 0.02; + + return attacker.CheckSkill( atkSkill.SkillName, chance ); + } + + public virtual TimeSpan GetDelay( Mobile m ) + { + double speed = this.Speed; + + if ( speed == 0 ) + return TimeSpan.FromHours( 1.0 ); + + double delayInSeconds; + + if ( Core.SE ) + { + /* + * This is likely true for Core.AOS as well... both guides report the same + * formula, and both are wrong. + * The old formula left in for AOS for legacy & because we aren't quite 100% + * Sure that AOS has THIS formula + */ + int bonus = AosAttributes.GetValue( m, AosAttribute.WeaponSpeed ); + + if ( Spells.Chivalry.DivineFurySpell.UnderEffect( m ) ) + bonus += 10; + + // Bonus granted by successful use of Honorable Execution. + bonus += HonorableExecution.GetSwingBonus( m ); + + if( DualWield.Registry.Contains( m ) ) + bonus += ((DualWield.DualWieldTimer)DualWield.Registry[m]).BonusSwingSpeed; + + if( Feint.Registry.Contains( m ) ) + bonus -= ((Feint.FeintTimer)Feint.Registry[m]).SwingSpeedReduction; + + TransformContext context = TransformationSpellHelper.GetContext( m ); + + if( context != null && context.Spell is ReaperFormSpell ) + bonus += ((ReaperFormSpell)context.Spell).SwingSpeedBonus; + + int discordanceEffect = 0; + + // Discordance gives a malus of -0/-28% to swing speed. + if ( SkillHandlers.Discordance.GetEffect( m, ref discordanceEffect ) ) + bonus -= discordanceEffect; + + if( EssenceOfWindSpell.IsDebuffed( m ) ) + bonus -= EssenceOfWindSpell.GetSSIMalus( m ); + + if ( bonus > 60 ) + bonus = 60; + + double ticks; + + if ( Core.ML ) + { + int stamTicks = m.Stam / 30; + + ticks = speed * 4; + ticks = Math.Floor( ( ticks - stamTicks ) * ( 100.0 / ( 100 + bonus ) ) ); + } + else + { + speed = Math.Floor( speed * ( bonus + 100.0 ) / 100.0 ); + + if ( speed <= 0 ) + speed = 1; + + ticks = Math.Floor( ( 80000.0 / ( ( m.Stam + 100 ) * speed ) ) - 2 ); + } + + // Swing speed currently capped at one swing every 1.25 seconds (5 ticks). + if ( ticks < 5 ) + ticks = 5; + + delayInSeconds = ticks * 0.25; + } + else if ( Core.AOS ) + { + int v = (m.Stam + 100) * (int) speed; + + int bonus = AosAttributes.GetValue( m, AosAttribute.WeaponSpeed ); + + if ( Spells.Chivalry.DivineFurySpell.UnderEffect( m ) ) + bonus += 10; + + int discordanceEffect = 0; + + // Discordance gives a malus of -0/-28% to swing speed. + if ( SkillHandlers.Discordance.GetEffect( m, ref discordanceEffect ) ) + bonus -= discordanceEffect; + + v += AOS.Scale( v, bonus ); + + if ( v <= 0 ) + v = 1; + + delayInSeconds = Math.Floor( 40000.0 / v ) * 0.5; + + // Maximum swing rate capped at one swing per second + // OSI dev said that it has and is supposed to be 1.25 + if ( delayInSeconds < 1.25 ) + delayInSeconds = 1.25; + } + else + { + int v = (m.Stam + 100) * (int) speed; + + if ( v <= 0 ) + v = 1; + + delayInSeconds = 15000.0 / v; + } + + return TimeSpan.FromSeconds( delayInSeconds ); + } + + public virtual void OnBeforeSwing( Mobile attacker, Mobile defender ) + { + WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker ); + + if( a != null && !a.OnBeforeSwing( attacker, defender ) ) + WeaponAbility.ClearCurrentAbility( attacker ); + + SpecialMove move = SpecialMove.GetCurrentMove( attacker ); + + if( move != null && !move.OnBeforeSwing( attacker, defender ) ) + SpecialMove.ClearCurrentMove( attacker ); + } + + public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender ) + { + return OnSwing( attacker, defender, 1.0 ); + } + + public virtual TimeSpan OnSwing( Mobile attacker, Mobile defender, double damageBonus ) + { + bool canSwing = true; + + if ( Core.AOS ) + { + canSwing = ( !attacker.Paralyzed && !attacker.Frozen ); + + if ( canSwing ) + { + Spell sp = attacker.Spell as Spell; + + canSwing = ( sp == null || !sp.IsCasting || !sp.BlocksMovement ); + } + + if (canSwing) + { + PlayerMobile p = attacker as PlayerMobile; + + canSwing = (p == null || p.PeacedUntil <= DateTime.Now); + } + } + + #region Dueling + if (attacker is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)attacker; + + if (pm.DuelContext != null && !pm.DuelContext.CheckItemEquip(attacker, this)) + canSwing = false; + } + #endregion + + if ( canSwing && attacker.HarmfulCheck( defender ) ) + { + attacker.DisruptiveAction(); + + if ( attacker.NetState != null ) + attacker.Send( new Swing( 0, attacker, defender ) ); + + if ( attacker is BaseCreature ) + { + BaseCreature bc = (BaseCreature)attacker; + WeaponAbility ab = bc.GetWeaponAbility(); + + if ( ab != null ) + { + if ( bc.WeaponAbilityChance > Utility.RandomDouble() ) + WeaponAbility.SetCurrentAbility( bc, ab ); + else + WeaponAbility.ClearCurrentAbility( bc ); + } + } + + if ( CheckHit( attacker, defender ) ) + OnHit( attacker, defender, damageBonus ); + else + OnMiss( attacker, defender ); + } + + return GetDelay( attacker ); + } + + #region Sounds + public virtual int GetHitAttackSound( Mobile attacker, Mobile defender ) + { + int sound = attacker.GetAttackSound(); + + if ( sound == -1 ) + sound = HitSound; + + return sound; + } + + public virtual int GetHitDefendSound( Mobile attacker, Mobile defender ) + { + return defender.GetHurtSound(); + } + + public virtual int GetMissAttackSound( Mobile attacker, Mobile defender ) + { + if ( attacker.GetAttackSound() == -1 ) + return MissSound; + else + return -1; + } + + public virtual int GetMissDefendSound( Mobile attacker, Mobile defender ) + { + return -1; + } + #endregion + + public static bool CheckParry( Mobile defender ) + { + if ( defender == null ) + return false; + + BaseShield shield = defender.FindItemOnLayer( Layer.TwoHanded ) as BaseShield; + + double parry = defender.Skills[SkillName.Parry].Value; + double bushidoNonRacial = defender.Skills[SkillName.Bushido].NonRacialValue; + double bushido = defender.Skills[SkillName.Bushido].Value; + + if ( shield != null ) + { + double chance = (parry - bushidoNonRacial) / 400.0; // As per OSI, no negitive effect from the Racial stuffs, ie, 120 parry and '0' bushido with humans + + if ( chance < 0 ) // chance shouldn't go below 0 + chance = 0; + + // Parry/Bushido over 100 grants a 5% bonus. + if ( parry >= 100.0 || bushido >= 100.0) + chance += 0.05; + + // Evasion grants a variable bonus post ML. 50% prior. + if ( Evasion.IsEvading( defender ) ) + chance *= Evasion.GetParryScalar( defender ); + + // Low dexterity lowers the chance. + if ( defender.Dex < 80 ) + chance = chance * (20 + defender.Dex) / 100; + + // Ajout defense silver vs necro + + if (shield.Resource == CraftResource.MSilver) + chance += 0.05; + + return defender.CheckSkill( SkillName.Parry, chance ); + } + else if ( !(defender.Weapon is Fists) && !(defender.Weapon is BaseRanged) ) + { + BaseWeapon weapon = defender.Weapon as BaseWeapon; + + double divisor = (weapon.Layer == Layer.OneHanded) ? 48000.0 : 41140.0; + + double chance = (parry * bushido) / divisor; + + double aosChance = parry / 800.0; + + // Parry or Bushido over 100 grant a 5% bonus. + if( parry >= 100.0 ) + { + chance += 0.05; + aosChance += 0.05; + } + else if( bushido >= 100.0 ) + { + chance += 0.05; + } + + // Evasion grants a variable bonus post ML. 50% prior. + if( Evasion.IsEvading( defender ) ) + chance *= Evasion.GetParryScalar( defender ); + + // Low dexterity lowers the chance. + if( defender.Dex < 80 ) + chance = chance * (20 + defender.Dex) / 100; + + if ( chance > aosChance ) + return defender.CheckSkill( SkillName.Parry, chance ); + else + return (aosChance > Utility.RandomDouble()); // Only skillcheck if wielding a shield & there's no effect from Bushido + } + + return false; + } + + public virtual int AbsorbDamageAOS( Mobile attacker, Mobile defender, int damage ) + { + bool blocked = false; + + if ( defender.Player || defender.Body.IsHuman ) + { + blocked = CheckParry( defender ); + //Plume : 2e chance pour les filles si le bouclier est en rose + BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield; + + if (!blocked && shield != null && shield.Resource == CraftResource.MRose && defender.Female && !(attacker.Female)) + { + blocked = Utility.RandomDouble() > 0.10 ? false : true; + } + + if ( blocked ) + { + defender.FixedEffect( 0x37B9, 10, 16 ); + damage = 0; + + // Successful block removes the Honorable Execution penalty. + HonorableExecution.RemovePenalty( defender ); + + if ( CounterAttack.IsCountering( defender ) ) + { + BaseWeapon weapon = defender.Weapon as BaseWeapon; + + if ( weapon != null ) + { + defender.FixedParticles(0x3779, 1, 15, 0x158B, 0x0, 0x3, EffectLayer.Waist); + weapon.OnSwing( defender, attacker ); + } + + CounterAttack.StopCountering( defender ); + } + + if ( Confidence.IsConfident( defender ) ) + { + defender.SendLocalizedMessage( 1063117 ); // Your confidence reassures you as you successfully block your opponent's blow. + + double bushido = defender.Skills.Bushido.Value; + + defender.Hits += Utility.RandomMinMax( 1, (int)(bushido / 12) ); + defender.Stam += Utility.RandomMinMax( 1, (int)(bushido / 5) ); + } + + if ( shield != null ) + { + shield.OnHit( this, damage ); + } + } + } + + if ( !blocked ) + { + double positionChance = Utility.RandomDouble(); + + Item armorItem; + + if( positionChance < 0.07 ) + armorItem = defender.NeckArmor; + else if( positionChance < 0.14 ) + armorItem = defender.HandArmor; + else if( positionChance < 0.28 ) + armorItem = defender.ArmsArmor; + else if( positionChance < 0.43 ) + armorItem = defender.HeadArmor; + else if( positionChance < 0.65 ) + armorItem = defender.LegsArmor; + else + armorItem = defender.ChestArmor; + + IWearableDurability armor = armorItem as IWearableDurability; + + if ( armor != null ) + armor.OnHit( this, damage ); // call OnHit to lose durability + } + + return damage; + } + + public virtual int AbsorbDamage( Mobile attacker, Mobile defender, int damage ) + { + if ( Core.AOS ) + return AbsorbDamageAOS( attacker, defender, damage ); + + BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield; + if (shield != null) + damage = shield.OnHit(this, damage); + + double chance = Utility.RandomDouble(); + + Item armorItem; + + if( chance < 0.07 ) + armorItem = defender.NeckArmor; + else if( chance < 0.14 ) + armorItem = defender.HandArmor; + else if( chance < 0.28 ) + armorItem = defender.ArmsArmor; + else if( chance < 0.43 ) + armorItem = defender.HeadArmor; + else if( chance < 0.65 ) + armorItem = defender.LegsArmor; + else + armorItem = defender.ChestArmor; + + IWearableDurability armor = armorItem as IWearableDurability; + + if ( armor != null ) + damage = armor.OnHit( this, damage ); + + int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod; + + if ( virtualArmor > 0 ) + { + double scalar; + + if ( chance < 0.14 ) + scalar = 0.07; + else if ( chance < 0.28 ) + scalar = 0.14; + else if ( chance < 0.43 ) + scalar = 0.15; + else if ( chance < 0.65 ) + scalar = 0.22; + else + scalar = 0.35; + + int from = (int)(virtualArmor * scalar) / 2; + int to = (int)(virtualArmor * scalar); + + damage -= Utility.Random( from, (to - from) + 1 ); + } + + return damage; + } + + public virtual int GetPackInstinctBonus( Mobile attacker, Mobile defender ) + { + if ( attacker.Player || defender.Player ) + return 0; + + BaseCreature bc = attacker as BaseCreature; + + if ( bc == null || bc.PackInstinct == PackInstinct.None || (!bc.Controlled && !bc.Summoned) ) + return 0; + + Mobile master = bc.ControlMaster; + + if ( master == null ) + master = bc.SummonMaster; + + if ( master == null ) + return 0; + + int inPack = 1; + + foreach ( Mobile m in defender.GetMobilesInRange( 1 ) ) + { + if ( m != attacker && m is BaseCreature ) + { + BaseCreature tc = (BaseCreature)m; + + if ( (tc.PackInstinct & bc.PackInstinct) == 0 || (!tc.Controlled && !tc.Summoned) ) + continue; + + Mobile theirMaster = tc.ControlMaster; + + if ( theirMaster == null ) + theirMaster = tc.SummonMaster; + + if ( master == theirMaster && tc.Combatant == defender ) + ++inPack; + } + } + + if ( inPack >= 5 ) + return 100; + else if ( inPack >= 4 ) + return 75; + else if ( inPack >= 3 ) + return 50; + else if ( inPack >= 2 ) + return 25; + + return 0; + } + + private static bool m_InDoubleStrike; + + public static bool InDoubleStrike + { + get{ return m_InDoubleStrike; } + set{ m_InDoubleStrike = value; } + } + + public void OnHit( Mobile attacker, Mobile defender ) + { + OnHit( attacker, defender, 1.0 ); + } + + public virtual void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + if ( MirrorImage.HasClone( defender ) && (defender.Skills.Ninjitsu.Value / 150.0) > Utility.RandomDouble() ) + { + Clone bc; + + foreach ( Mobile m in defender.GetMobilesInRange( 4 ) ) + { + bc = m as Clone; + + if ( bc != null && bc.Summoned && bc.SummonMaster == defender ) + { + attacker.SendLocalizedMessage( 1063141 ); // Your attack has been diverted to a nearby mirror image of your target! + defender.SendLocalizedMessage( 1063140 ); // You manage to divert the attack onto one of your nearby mirror images. + + /* + * TODO: What happens if the Clone parries a blow? + * And what about if the attacker is using Honorable Execution + * and kills it? + */ + + defender = m; + break; + } + } + } + + PlaySwingAnimation( attacker ); + PlayHurtAnimation( defender ); + + attacker.PlaySound( GetHitAttackSound( attacker, defender ) ); + defender.PlaySound( GetHitDefendSound( attacker, defender ) ); + + int damage = ComputeDamage( attacker, defender ); + + #region Damage Multipliers + /* + * The following damage bonuses multiply damage by a factor. + * Capped at x3 (300%). + */ + //double factor = 1.0; + int percentageBonus = 0; + + WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker ); + SpecialMove move = SpecialMove.GetCurrentMove( attacker ); + + if( a != null ) + { + percentageBonus += (int)(a.DamageScalar * 100) - 100; + } + + if( move != null ) + { + percentageBonus += (int)(move.GetDamageScalar( attacker, defender ) * 100) - 100; + } + + percentageBonus += (int)(damageBonus * 100) - 100; + + CheckSlayerResult cs = CheckSlayers( attacker, defender ); + + if ( cs != CheckSlayerResult.None ) + { + if ( cs == CheckSlayerResult.Slayer ) + defender.FixedEffect( 0x37B9, 10, 5 ); + + percentageBonus += 100; + } + + if ( !attacker.Player ) + { + if ( defender is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)defender; + + if( pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType() ) + { + percentageBonus += 100; + } + } + } + else if ( !defender.Player ) + { + if ( attacker is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)attacker; + + if ( pm.WaitingForEnemy ) + { + pm.EnemyOfOneType = defender.GetType(); + pm.WaitingForEnemy = false; + } + + if ( pm.EnemyOfOneType == defender.GetType() ) + { + defender.FixedEffect( 0x37B9, 10, 5, 1160, 0 ); + percentageBonus += 50; + } + } + } + + int packInstinctBonus = GetPackInstinctBonus( attacker, defender ); + + if( packInstinctBonus != 0 ) + { + percentageBonus += packInstinctBonus; + } + + if( m_InDoubleStrike ) + { + percentageBonus -= 10; + } + + TransformContext context = TransformationSpellHelper.GetContext( defender ); + // Ajout d�gats contre n�cro avec silver + if (Resource == CraftResource.MSilver && context != null && context.Spell is NecromancerSpell) + percentageBonus += 15; + + if( (m_Slayer == SlayerName.Silver || m_Slayer2 == SlayerName.Silver) && context != null && context.Spell is NecromancerSpell && context.Type != typeof( HorrificBeastSpell ) ) + { + percentageBonus += 25; + } + + if ( attacker is PlayerMobile && !(Core.ML && defender is PlayerMobile )) + { + PlayerMobile pmAttacker = (PlayerMobile) attacker; + + if( pmAttacker.HonorActive && pmAttacker.InRange( defender, 1 ) ) + { + percentageBonus += 25; + } + + if( pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender ) + { + //pmAttacker.SentHonorContext.ApplyPerfectionDamageBonus( ref factor ); + percentageBonus += pmAttacker.SentHonorContext.PerfectionDamageBonus; + } + } + + BaseTalisman talisman = attacker.Talisman as BaseTalisman; + + if (talisman != null && talisman.Killer != null) + percentageBonus += talisman.Killer.DamageBonus(defender); + + percentageBonus = Math.Min( percentageBonus, 300 ); + + //damage = (int)(damage * factor); + damage = AOS.Scale( damage, 100 + percentageBonus ); + #endregion + + if ( attacker is BaseCreature ) + ((BaseCreature)attacker).AlterMeleeDamageTo( defender, ref damage ); + + if ( defender is BaseCreature ) + ((BaseCreature)defender).AlterMeleeDamageFrom( attacker, ref damage ); + + damage = AbsorbDamage( attacker, defender, damage ); + + if ( !Core.AOS && damage < 1 ) + damage = 1; + else if ( Core.AOS && damage == 0 ) // parried + { + if ( a != null && a.Validate( attacker ) /*&& a.CheckMana( attacker, true )*/ ) // Parried special moves have no mana cost + { + a = null; + WeaponAbility.ClearCurrentAbility( attacker ); + + attacker.SendLocalizedMessage( 1061140 ); // Your attack was parried! + } + } + + AddBlood( attacker, defender, damage ); + + int phys, fire, cold, pois, nrgy, chaos, direct; + + GetDamageTypes( attacker, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct ); + + if ( Core.ML && this is BaseRanged ) + { + BaseQuiver quiver = attacker.FindItemOnLayer( Layer.Cloak ) as BaseQuiver; + + if ( quiver != null ) + quiver.AlterBowDamage( ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct ); + } + + if ( m_Consecrated ) + { + phys = defender.PhysicalResistance; + fire = defender.FireResistance; + cold = defender.ColdResistance; + pois = defender.PoisonResistance; + nrgy = defender.EnergyResistance; + + int low = phys, type = 0; + + if ( fire < low ){ low = fire; type = 1; } + if ( cold < low ){ low = cold; type = 2; } + if ( pois < low ){ low = pois; type = 3; } + if ( nrgy < low ){ low = nrgy; type = 4; } + + phys = fire = cold = pois = nrgy = chaos = direct = 0; + + if ( type == 0 ) phys = 100; + else if ( type == 1 ) fire = 100; + else if ( type == 2 ) cold = 100; + else if ( type == 3 ) pois = 100; + else if ( type == 4 ) nrgy = 100; + } + + // TODO: Scale damage, alongside the leech effects below, to weapon speed. + if (ImmolatingWeaponSpell.IsImmolating(this) && damage > 0) + ImmolatingWeaponSpell.DoEffect(this, defender); + + int damageGiven = damage; + + if ( a != null && !a.OnBeforeDamage( attacker, defender ) ) + { + WeaponAbility.ClearCurrentAbility( attacker ); + a = null; + } + + if ( move != null && !move.OnBeforeDamage( attacker, defender ) ) + { + SpecialMove.ClearCurrentMove( attacker ); + move = null; + } + + bool ignoreArmor = ( a is ArmorIgnore || (move != null && move.IgnoreArmor( attacker )) ); + + damageGiven = AOS.Damage(defender, attacker, damage, ignoreArmor, phys, fire, cold, pois, nrgy, chaos, direct, false, this is BaseRanged, false); + + double propertyBonus = ( move == null ) ? 1.0 : move.GetPropertyBonus( attacker ); + + if ( Core.AOS ) + { + int lifeLeech = 0; + int stamLeech = 0; + int manaLeech = 0; + int wraithLeech = 0; + + if ( (int)(m_AosWeaponAttributes.HitLeechHits * propertyBonus) > Utility.Random( 100 ) ) + lifeLeech += 30; // HitLeechHits% chance to leech 30% of damage as hit points + + if ( (int)(m_AosWeaponAttributes.HitLeechStam * propertyBonus) > Utility.Random( 100 ) ) + stamLeech += 100; // HitLeechStam% chance to leech 100% of damage as stamina + + if ( (int)(m_AosWeaponAttributes.HitLeechMana * propertyBonus) > Utility.Random( 100 ) ) + manaLeech += 40; // HitLeechMana% chance to leech 40% of damage as mana + + if ( m_Cursed ) + lifeLeech += 50; // Additional 50% life leech for cursed weapons (necro spell) + + context = TransformationSpellHelper.GetContext( attacker ); + + if ( context != null && context.Type == typeof( VampiricEmbraceSpell ) ) + lifeLeech += 20; // Vampiric embrace gives an additional 20% life leech + + if ( context != null && context.Type == typeof( WraithFormSpell ) ) + { + wraithLeech = (5 + (int)((15 * attacker.Skills.SpiritSpeak.Value) / 100)); // Wraith form gives an additional 5-20% mana leech + + // Mana leeched by the Wraith Form spell is actually stolen, not just leeched. + defender.Mana -= AOS.Scale( damageGiven, wraithLeech ); + + manaLeech += wraithLeech; + } + + if ( lifeLeech != 0 ) + attacker.Hits += AOS.Scale( damageGiven, lifeLeech ); + + if ( stamLeech != 0 ) + attacker.Stam += AOS.Scale( damageGiven, stamLeech ); + + if ( manaLeech != 0 ) + attacker.Mana += AOS.Scale( damageGiven, manaLeech ); + + if ( lifeLeech != 0 || stamLeech != 0 || manaLeech != 0 ) + attacker.PlaySound( 0x44D ); + } + + if ( m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) || Utility.Random( 25 ) == 0) ) // Stratics says 50% chance, seems more like 4%.. + { + if (MaxRange <= 1 && (defender is Slime || defender is AcidElemental)) + attacker.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500263 ); // *Acid blood scars your weapon!* + + if ( Core.AOS && m_AosWeaponAttributes.SelfRepair > Utility.Random( 10 ) ) + { + HitPoints += 2; + } + else + { + if ( m_Hits > 0 ) + { + --HitPoints; + } + else if ( m_MaxHits > 1 ) + { + --MaxHitPoints; + + if ( Parent is Mobile ) + ((Mobile)Parent).LocalOverheadMessage( MessageType.Regular, 0x3B2, 1061121 ); // Your equipment is severely damaged. + } + else + { + Delete(); + } + } + } + + if ( attacker is VampireBatFamiliar ) + { + BaseCreature bc = (BaseCreature)attacker; + Mobile caster = bc.ControlMaster; + + if ( caster == null ) + caster = bc.SummonMaster; + + if ( caster != null && caster.Map == bc.Map && caster.InRange( bc, 2 ) ) + caster.Hits += damage; + else + bc.Hits += damage; + } + + if ( Core.AOS ) + { + int physChance = (int)(m_AosWeaponAttributes.HitPhysicalArea * propertyBonus); + int fireChance = (int)(m_AosWeaponAttributes.HitFireArea * propertyBonus); + int coldChance = (int)(m_AosWeaponAttributes.HitColdArea * propertyBonus); + int poisChance = (int)(m_AosWeaponAttributes.HitPoisonArea * propertyBonus); + int nrgyChance = (int)(m_AosWeaponAttributes.HitEnergyArea * propertyBonus); + + if ( physChance != 0 && physChance > Utility.Random( 100 ) ) + DoAreaAttack( attacker, defender, 0x10E, 50, 100, 0, 0, 0, 0 ); + + if ( fireChance != 0 && fireChance > Utility.Random( 100 ) ) + DoAreaAttack( attacker, defender, 0x11D, 1160, 0, 100, 0, 0, 0 ); + + if ( coldChance != 0 && coldChance > Utility.Random( 100 ) ) + DoAreaAttack( attacker, defender, 0x0FC, 2100, 0, 0, 100, 0, 0 ); + + if ( poisChance != 0 && poisChance > Utility.Random( 100 ) ) + DoAreaAttack( attacker, defender, 0x205, 1166, 0, 0, 0, 100, 0 ); + + if ( nrgyChance != 0 && nrgyChance > Utility.Random( 100 ) ) + DoAreaAttack( attacker, defender, 0x1F1, 120, 0, 0, 0, 0, 100 ); + + int maChance = (int)(m_AosWeaponAttributes.HitMagicArrow * propertyBonus); + int harmChance = (int)(m_AosWeaponAttributes.HitHarm * propertyBonus); + int fireballChance = (int)(m_AosWeaponAttributes.HitFireball * propertyBonus); + int lightningChance = (int)(m_AosWeaponAttributes.HitLightning * propertyBonus); + int dispelChance = (int)(m_AosWeaponAttributes.HitDispel * propertyBonus); + + if ( maChance != 0 && maChance > Utility.Random( 100 ) ) + DoMagicArrow( attacker, defender ); + + if ( harmChance != 0 && harmChance > Utility.Random( 100 ) ) + DoHarm( attacker, defender ); + + if ( fireballChance != 0 && fireballChance > Utility.Random( 100 ) ) + DoFireball( attacker, defender ); + + if ( lightningChance != 0 && lightningChance > Utility.Random( 100 ) ) + DoLightning( attacker, defender ); + + if ( dispelChance != 0 && dispelChance > Utility.Random( 100 ) ) + DoDispel( attacker, defender ); + + int laChance = (int)(m_AosWeaponAttributes.HitLowerAttack * propertyBonus); + int ldChance = (int)(m_AosWeaponAttributes.HitLowerDefend * propertyBonus); + + if ( laChance != 0 && laChance > Utility.Random( 100 ) ) + DoLowerAttack( attacker, defender ); + + if ( ldChance != 0 && ldChance > Utility.Random( 100 ) ) + DoLowerDefense( attacker, defender ); + } + + if ( attacker is BaseCreature ) + ((BaseCreature)attacker).OnGaveMeleeAttack( defender ); + + if ( defender is BaseCreature ) + ((BaseCreature)defender).OnGotMeleeAttack( attacker ); + + if ( a != null ) + a.OnHit( attacker, defender, damage ); + // hook for attachment OnWeaponHit method + Server.Engines.XmlSpawner2.XmlAttach.OnWeaponHit(this, attacker, defender, damageGiven); + + if ( move != null ) + move.OnHit( attacker, defender, damage ); + + if ( defender is IHonorTarget && ((IHonorTarget)defender).ReceivedHonorContext != null ) + ((IHonorTarget)defender).ReceivedHonorContext.OnTargetHit( attacker ); + + if ( !(this is BaseRanged) ) + { + if ( AnimalForm.UnderTransformation( attacker, typeof( GiantSerpent ) ) ) + defender.ApplyPoison( attacker, Poison.Lesser ); + + if ( AnimalForm.UnderTransformation( defender, typeof( BullFrog ) ) ) + attacker.ApplyPoison( defender, Poison.Regular ); + } + } + + public virtual double GetAosDamage( Mobile attacker, int bonus, int dice, int sides ) + { + int damage = Utility.Dice( dice, sides, bonus ) * 100; + int damageBonus = 0; + + // Inscription bonus + int inscribeSkill = attacker.Skills[SkillName.Inscribe].Fixed; + + damageBonus += inscribeSkill / 200; + + if ( inscribeSkill >= 1000 ) + damageBonus += 5; + + if ( attacker.Player ) + { + // Int bonus + damageBonus += (attacker.Int / 10); + + // SDI bonus + damageBonus += AosAttributes.GetValue( attacker, AosAttribute.SpellDamage ); + + TransformContext context = TransformationSpellHelper.GetContext( attacker ); + + if( context != null && context.Spell is ReaperFormSpell ) + damageBonus += ((ReaperFormSpell)context.Spell).SpellDamageBonus; + } + + damage = AOS.Scale( damage, 100 + damageBonus ); + + return damage / 100; + } + + #region Do + public virtual void DoMagicArrow( Mobile attacker, Mobile defender ) + { + if ( !attacker.CanBeHarmful( defender, false ) ) + return; + + attacker.DoHarmful( defender ); + + double damage = GetAosDamage( attacker, 10, 1, 4 ); + + attacker.MovingParticles( defender, 0x36E4, 5, 0, false, true, 3006, 4006, 0 ); + attacker.PlaySound( 0x1E5 ); + + SpellHelper.Damage( TimeSpan.FromSeconds( 1.0 ), defender, attacker, damage, 0, 100, 0, 0, 0 ); + } + + public virtual void DoHarm( Mobile attacker, Mobile defender ) + { + if ( !attacker.CanBeHarmful( defender, false ) ) + return; + + attacker.DoHarmful( defender ); + + double damage = GetAosDamage( attacker, 17, 1, 5 ); + + if ( !defender.InRange( attacker, 2 ) ) + damage *= 0.25; // 1/4 damage at > 2 tile range + else if ( !defender.InRange( attacker, 1 ) ) + damage *= 0.50; // 1/2 damage at 2 tile range + + defender.FixedParticles( 0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist ); + defender.PlaySound( 0x0FC ); + + SpellHelper.Damage( TimeSpan.Zero, defender, attacker, damage, 0, 0, 100, 0, 0 ); + } + + public virtual void DoFireball( Mobile attacker, Mobile defender ) + { + if ( !attacker.CanBeHarmful( defender, false ) ) + return; + + attacker.DoHarmful( defender ); + + double damage = GetAosDamage( attacker, 19, 1, 5 ); + + attacker.MovingParticles( defender, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160 ); + attacker.PlaySound( 0x15E ); + + SpellHelper.Damage( TimeSpan.FromSeconds( 1.0 ), defender, attacker, damage, 0, 100, 0, 0, 0 ); + } + + public virtual void DoLightning( Mobile attacker, Mobile defender ) + { + if ( !attacker.CanBeHarmful( defender, false ) ) + return; + + attacker.DoHarmful( defender ); + + double damage = GetAosDamage( attacker, 23, 1, 4 ); + + defender.BoltEffect( 0 ); + + SpellHelper.Damage( TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100 ); + } + + public virtual void DoDispel( Mobile attacker, Mobile defender ) + { + bool dispellable = false; + + if ( defender is BaseCreature ) + dispellable = ((BaseCreature)defender).Summoned && !((BaseCreature)defender).IsAnimatedDead; + + if ( !dispellable ) + return; + + if ( !attacker.CanBeHarmful( defender, false ) ) + return; + + attacker.DoHarmful( defender ); + + Spells.MagerySpell sp = new Spells.Sixth.DispelSpell( attacker, null ); + + if ( sp.CheckResisted( defender ) ) + { + defender.FixedEffect( 0x3779, 10, 20 ); + } + else + { + Effects.SendLocationParticles( EffectItem.Create( defender.Location, defender.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 ); + Effects.PlaySound( defender, defender.Map, 0x201 ); + + defender.Delete(); + } + } + + public virtual void DoLowerAttack( Mobile from, Mobile defender ) + { + if ( HitLower.ApplyAttack( defender ) ) + { + defender.PlaySound( 0x28E ); + Effects.SendTargetEffect( defender, 0x37BE, 1, 4, 0xA, 3 ); + } + } + + public virtual void DoLowerDefense( Mobile from, Mobile defender ) + { + if ( HitLower.ApplyDefense( defender ) ) + { + defender.PlaySound( 0x28E ); + Effects.SendTargetEffect( defender, 0x37BE, 1, 4, 0x23, 3 ); + } + } + + public virtual void DoAreaAttack( Mobile from, Mobile defender, int sound, int hue, int phys, int fire, int cold, int pois, int nrgy ) + { + Map map = from.Map; + + if ( map == null ) + return; + + List list = new List(); + + int range = Core.ML ? 5 : 10; + + foreach (Mobile m in from.GetMobilesInRange(range)) + { + if ( from != m && defender != m && SpellHelper.ValidIndirectTarget( from, m ) && from.CanBeHarmful( m, false ) && ( !Core.ML || from.InLOS( m ) ) ) + list.Add( m ); + } + + if ( list.Count == 0 ) + return; + + Effects.PlaySound( from.Location, map, sound ); + + for (int i = 0; i < list.Count; ++i) + { + Mobile m = list[i]; + + double scalar = Core.ML ? 1.0 : (11 - from.GetDistanceToSqrt(m)) / 10; + double damage = GetBaseDamage(from); + + if (scalar <= 0) + { + continue; + } + else if (scalar < 1.0) + { + damage *= (11 - from.GetDistanceToSqrt(m)) / 10; + } + + from.DoHarmful(m, true); + m.FixedEffect(0x3779, 1, 15, hue, 0); + AOS.Damage(m, from, (int)damage, phys, fire, cold, pois, nrgy); + } + } + #endregion + + public virtual CheckSlayerResult CheckSlayers( Mobile attacker, Mobile defender ) + { + BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon; + SlayerEntry atkSlayer = SlayerGroup.GetEntryByName( atkWeapon.Slayer ); + SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName( atkWeapon.Slayer2 ); + + if (atkWeapon is ButchersWarCleaver && TalismanSlayer.Slays(TalismanSlayerName.Bovine, defender)) + return CheckSlayerResult.Slayer; + + if ( atkSlayer != null && atkSlayer.Slays( defender ) || atkSlayer2 != null && atkSlayer2.Slays( defender ) ) + return CheckSlayerResult.Slayer; + + if ( !Core.SE ) + { + ISlayer defISlayer = Spellbook.FindEquippedSpellbook( defender ); + + if( defISlayer == null ) + defISlayer = defender.Weapon as ISlayer; + + if( defISlayer != null ) + { + SlayerEntry defSlayer = SlayerGroup.GetEntryByName( defISlayer.Slayer ); + SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName( defISlayer.Slayer2 ); + + if( defSlayer != null && defSlayer.Group.OppositionSuperSlays( attacker ) || defSlayer2 != null && defSlayer2.Group.OppositionSuperSlays( attacker ) ) + return CheckSlayerResult.Opposition; + } + } + + return CheckSlayerResult.None; + } + + public virtual void AddBlood( Mobile attacker, Mobile defender, int damage ) + { + if ( damage > 0 ) + { + new Blood().MoveToWorld( defender.Location, defender.Map ); + + int extraBlood = (Core.SE ? Utility.RandomMinMax( 3, 4 ) : Utility.RandomMinMax( 0, 1 ) ); + + for( int i = 0; i < extraBlood; i++ ) + { + new Blood().MoveToWorld( new Point3D( + defender.X + Utility.RandomMinMax( -1, 1 ), + defender.Y + Utility.RandomMinMax( -1, 1 ), + defender.Z ), defender.Map ); + } + } + } + + public virtual void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + if( wielder is BaseCreature ) + { + BaseCreature bc = (BaseCreature)wielder; + + phys = bc.PhysicalDamage; + fire = bc.FireDamage; + cold = bc.ColdDamage; + pois = bc.PoisonDamage; + nrgy = bc.EnergyDamage; + chaos = bc.ChaosDamage; + direct = bc.DirectDamage; + } + else + { + fire = m_AosElementDamages.Fire; + cold = m_AosElementDamages.Cold; + pois = m_AosElementDamages.Poison; + nrgy = m_AosElementDamages.Energy; + chaos = m_AosElementDamages.Chaos; + direct = m_AosElementDamages.Direct; + + phys = 100 - fire - cold - pois - nrgy - chaos - direct; + + CraftResourceInfo resInfo = CraftResources.GetInfo( m_Resource ); + + if( resInfo != null ) + { + CraftAttributeInfo attrInfo = resInfo.AttributeInfo; + + if( attrInfo != null ) + { + int left = phys; + + left = ApplyCraftAttributeElementDamage( attrInfo.WeaponColdDamage, ref cold, left ); + left = ApplyCraftAttributeElementDamage( attrInfo.WeaponEnergyDamage, ref nrgy, left ); + left = ApplyCraftAttributeElementDamage( attrInfo.WeaponFireDamage, ref fire, left ); + left = ApplyCraftAttributeElementDamage( attrInfo.WeaponPoisonDamage, ref pois, left ); + left = ApplyCraftAttributeElementDamage( attrInfo.WeaponChaosDamage, ref chaos, left ); + left = ApplyCraftAttributeElementDamage( attrInfo.WeaponDirectDamage, ref direct, left ); + + phys = left; + } + } + } + } + + private int ApplyCraftAttributeElementDamage( int attrDamage, ref int element, int totalRemaining ) + { + if( totalRemaining <= 0 ) + return 0; + + if ( attrDamage <= 0 ) + return totalRemaining; + + int appliedDamage = attrDamage; + + if ( (appliedDamage + element) > 100 ) + appliedDamage = 100 - element; + + if( appliedDamage > totalRemaining ) + appliedDamage = totalRemaining; + + element += appliedDamage; + + return totalRemaining - appliedDamage; + } + + public virtual void OnMiss( Mobile attacker, Mobile defender ) + { + PlaySwingAnimation( attacker ); + attacker.PlaySound( GetMissAttackSound( attacker, defender ) ); + defender.PlaySound( GetMissDefendSound( attacker, defender ) ); + + WeaponAbility ability = WeaponAbility.GetCurrentAbility( attacker ); + + if ( ability != null ) + ability.OnMiss( attacker, defender ); + + SpecialMove move = SpecialMove.GetCurrentMove( attacker ); + + if ( move != null ) + move.OnMiss( attacker, defender ); + + if ( defender is IHonorTarget && ((IHonorTarget)defender).ReceivedHonorContext != null ) + ((IHonorTarget)defender).ReceivedHonorContext.OnTargetMissed( attacker ); + } + + public virtual void GetBaseDamageRange( Mobile attacker, out int min, out int max ) + { + if ( attacker is BaseCreature ) + { + BaseCreature c = (BaseCreature)attacker; + + if ( c.DamageMin >= 0 ) + { + min = c.DamageMin; + max = c.DamageMax; + return; + } + + if ( this is Fists && !attacker.Body.IsHuman ) + { + min = attacker.Str / 28; + max = attacker.Str / 28; + return; + } + } + + min = MinDamage; + max = MaxDamage; + } + + public virtual double GetBaseDamage( Mobile attacker ) + { + int min, max; + + GetBaseDamageRange( attacker, out min, out max ); + + int damage = Utility.RandomMinMax(min, max); + + if (Core.AOS) return damage; + + /* Apply damage level offset + * : Regular : 0 + * : Ruin : 1 + * : Might : 3 + * : Force : 5 + * : Power : 7 + * : Vanq : 9 + */ + if (m_DamageLevel != WeaponDamageLevel.Regular) + damage += (2 * (int)m_DamageLevel) - 1; + + return damage; + } + + public virtual double GetBonus( double value, double scalar, double threshold, double offset ) + { + double bonus = value * scalar; + + if ( value >= threshold ) + bonus += offset; + + return bonus / 100; + } + + public virtual int GetHitChanceBonus() + { + if ( !Core.AOS ) + return 0; + + int bonus = 0; + if (m_Quality == WeaponQuality.Low) + bonus -= 5; + + switch ( m_AccuracyLevel ) + { + case WeaponAccuracyLevel.Accurate: bonus += 02; break; + case WeaponAccuracyLevel.Surpassingly: bonus += 04; break; + case WeaponAccuracyLevel.Eminently: bonus += 06; break; + case WeaponAccuracyLevel.Exceedingly: bonus += 08; break; + case WeaponAccuracyLevel.Supremely: bonus += 10; break; + } + + return bonus; + } + + public virtual int GetDamageBonus() + { + int bonus = VirtualDamageBonus; + + switch ( m_Quality ) + { + case WeaponQuality.Low: bonus -= 20; break; + case WeaponQuality.Exceptional: bonus += 15; break; + } + + switch ( m_DamageLevel ) + { + case WeaponDamageLevel.Ruin: bonus += 5; break; + case WeaponDamageLevel.Might: bonus += 10; break; + case WeaponDamageLevel.Force: bonus += 15; break; + case WeaponDamageLevel.Power: bonus += 20; break; + case WeaponDamageLevel.Vanq: bonus += 25; break; + } + + return bonus; + } + + public virtual void GetStatusDamage( Mobile from, out int min, out int max ) + { + int baseMin, baseMax; + + GetBaseDamageRange( from, out baseMin, out baseMax ); + + if ( Core.AOS ) + { + min = Math.Max( (int)ScaleDamageAOS( from, baseMin, false ), 1 ); + max = Math.Max( (int)ScaleDamageAOS( from, baseMax, false ), 1 ); + } + else + { + min = Math.Max( (int)ScaleDamageOld( from, baseMin, false ), 1 ); + max = Math.Max( (int)ScaleDamageOld( from, baseMax, false ), 1 ); + } + } + + public virtual double ScaleDamageAOS( Mobile attacker, double damage, bool checkSkills ) + { + if ( checkSkills ) + { + attacker.CheckSkill( SkillName.Tactics, 0.0, attacker.Skills[SkillName.Tactics].Cap ); // Passively check tactics for gain + attacker.CheckSkill( SkillName.Anatomy, 0.0, attacker.Skills[SkillName.Anatomy].Cap ); // Passively check Anatomy for gain + + if ( Type == WeaponType.Axe ) + attacker.CheckSkill( SkillName.Lumberjacking, 0.0, 100.0 ); // Passively check Lumberjacking for gain + } + + #region Physical bonuses + /* + * These are the bonuses given by the physical characteristics of the mobile. + * No caps apply. + */ + double strengthBonus = GetBonus( attacker.Str, 0.300, 100.0, 5.00 ); + double anatomyBonus = GetBonus( attacker.Skills[SkillName.Anatomy].Value, 0.500, 100.0, 5.00 ); + double tacticsBonus = GetBonus( attacker.Skills[SkillName.Tactics].Value, 0.625, 100.0, 6.25 ); + double lumberBonus = GetBonus( attacker.Skills[SkillName.Lumberjacking].Value, 0.200, 100.0, 10.00 ); + + if ( Type != WeaponType.Axe ) + lumberBonus = 0.0; + #endregion + + #region Modifiers + /* + * The following are damage modifiers whose effect shows on the status bar. + * Capped at 100% total. + */ + int damageBonus = AosAttributes.GetValue( attacker, AosAttribute.WeaponDamage ); + + // Horrific Beast transformation gives a +25% bonus to damage. + if( TransformationSpellHelper.UnderTransformation( attacker, typeof( HorrificBeastSpell ) ) ) + damageBonus += 25; + + // Divine Fury gives a +10% bonus to damage. + if ( Spells.Chivalry.DivineFurySpell.UnderEffect( attacker ) ) + damageBonus += 10; + + int defenseMasteryMalus = 0; + + // Defense Mastery gives a -50%/-80% malus to damage. + if ( Server.Items.DefenseMastery.GetMalus( attacker, ref defenseMasteryMalus ) ) + damageBonus -= defenseMasteryMalus; + + int discordanceEffect = 0; + + // Discordance gives a -2%/-48% malus to damage. + if ( SkillHandlers.Discordance.GetEffect( attacker, ref discordanceEffect ) ) + damageBonus -= discordanceEffect * 2; + + if ( damageBonus > 100 ) + damageBonus = 100; + #endregion + + double totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus + ((double)(GetDamageBonus() + damageBonus) / 100.0); + + return damage + (int)(damage * totalBonus); + } + + public virtual int VirtualDamageBonus{ get{ return 0; } } + + public virtual int ComputeDamageAOS( Mobile attacker, Mobile defender ) + { + return (int)ScaleDamageAOS( attacker, GetBaseDamage( attacker ), true ); + } + + public virtual double ScaleDamageOld( Mobile attacker, double damage, bool checkSkills ) + { + if ( checkSkills ) + { + attacker.CheckSkill( SkillName.Tactics, 0.0, attacker.Skills[SkillName.Tactics].Cap ); // Passively check tactics for gain + attacker.CheckSkill( SkillName.Anatomy, 0.0, attacker.Skills[SkillName.Anatomy].Cap ); // Passively check Anatomy for gain + + if ( Type == WeaponType.Axe ) + attacker.CheckSkill( SkillName.Lumberjacking, 0.0, 100.0 ); // Passively check Lumberjacking for gain + } + + /* Compute tactics modifier + * : 0.0 = 50% loss + * : 50.0 = unchanged + * : 100.0 = 50% bonus + */ + damage += (damage * ((attacker.Skills[SkillName.Tactics].Value - 50.0) / 100.0)); + + + /* Compute strength modifier + * : 1% bonus for every 5 strength + */ + double modifiers = (attacker.Str / 5.0) / 100.0; + + /* Compute anatomy modifier + * : 1% bonus for every 5 points of anatomy + * : +10% bonus at Grandmaster or higher + */ + double anatomyValue = attacker.Skills[SkillName.Anatomy].Value; + modifiers += ((anatomyValue / 5.0) / 100.0); + + if (anatomyValue >= 100.0) + modifiers += 0.1; + + /* Compute lumberjacking bonus + * : 1% bonus for every 5 points of lumberjacking + * : +10% bonus at Grandmaster or higher + */ + if (Type == WeaponType.Axe) + { + double lumberValue = attacker.Skills[SkillName.Lumberjacking].Value; + + modifiers += ((lumberValue / 5.0) / 100.0); + + if (lumberValue >= 100.0) + modifiers += 0.1; + } + + // New quality bonus: + if (m_Quality != WeaponQuality.Regular) + modifiers += (((int)m_Quality - 1) * 0.2); + + // Virtual damage bonus: + if (VirtualDamageBonus != 0) + modifiers += (VirtualDamageBonus / 100.0); + + // Apply bonuses + damage += (damage * modifiers); + + return ScaleDamageByDurability((int)damage); + } + + public virtual int ScaleDamageByDurability( int damage ) + { + int scale = 100; + + if ( m_MaxHits > 0 && m_Hits < m_MaxHits ) + scale = 50 + ((50 * m_Hits) / m_MaxHits); + + return AOS.Scale( damage, scale ); + } + + public virtual int ComputeDamage( Mobile attacker, Mobile defender ) + { + if ( Core.AOS ) + return ComputeDamageAOS( attacker, defender ); + + int damage = (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true); + + // pre-AOS, halve damage if the defender is a player or the attacker is not a player + if (defender is PlayerMobile || !(attacker is PlayerMobile)) + damage = (int)(damage / 2.0); + + return damage; + } + + public virtual void PlayHurtAnimation( Mobile from ) + { + int action; + int frames; + + switch ( from.Body.Type ) + { + case BodyType.Sea: + case BodyType.Animal: + { + action = 7; + frames = 5; + break; + } + case BodyType.Monster: + { + action = 10; + frames = 4; + break; + } + case BodyType.Human: + { + action = 20; + frames = 5; + break; + } + default: return; + } + + if ( from.Mounted ) + return; + + from.Animate(action, frames, 1, true, false, 0); + } + + public virtual void PlaySwingAnimation( Mobile from ) + { + int action; + + switch ( from.Body.Type ) + { + case BodyType.Sea: + case BodyType.Animal: + { + action = Utility.Random( 5, 2 ); + break; + } + case BodyType.Monster: + { + switch ( Animation ) + { + default: + case WeaponAnimation.Wrestle: + case WeaponAnimation.Bash1H: + case WeaponAnimation.Pierce1H: + case WeaponAnimation.Slash1H: + case WeaponAnimation.Bash2H: + case WeaponAnimation.Pierce2H: + case WeaponAnimation.Slash2H: action = Utility.Random( 4, 3 ); break; + case WeaponAnimation.ShootBow: return; // 7 + case WeaponAnimation.ShootXBow: return; // 8 + } + + break; + } + case BodyType.Human: + { + if ( !from.Mounted ) + { + action = (int)Animation; + } + else + { + switch ( Animation ) + { + default: + case WeaponAnimation.Wrestle: + case WeaponAnimation.Bash1H: + case WeaponAnimation.Pierce1H: + case WeaponAnimation.Slash1H: action = 26; break; + case WeaponAnimation.Bash2H: + case WeaponAnimation.Pierce2H: + case WeaponAnimation.Slash2H: action = 29; break; + case WeaponAnimation.ShootBow: action = 27; break; + case WeaponAnimation.ShootXBow: action = 28; break; + } + } + + break; + } + default: return; + } + + from.Animate( action, 7, 1, true, false, 0 ); + } + + #region Serialization/Deserialization + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 10 ); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag( ref flags, SaveFlag.DamageLevel, m_DamageLevel != WeaponDamageLevel.Regular ); + SetSaveFlag( ref flags, SaveFlag.AccuracyLevel, m_AccuracyLevel != WeaponAccuracyLevel.Regular ); + SetSaveFlag( ref flags, SaveFlag.DurabilityLevel, m_DurabilityLevel != WeaponDurabilityLevel.Regular ); + SetSaveFlag( ref flags, SaveFlag.Quality, m_Quality != WeaponQuality.Regular ); + SetSaveFlag( ref flags, SaveFlag.Hits, m_Hits != 0 ); + SetSaveFlag( ref flags, SaveFlag.MaxHits, m_MaxHits != 0 ); + SetSaveFlag( ref flags, SaveFlag.Slayer, m_Slayer != SlayerName.None ); + SetSaveFlag( ref flags, SaveFlag.Poison, m_Poison != null ); + SetSaveFlag( ref flags, SaveFlag.PoisonCharges, m_PoisonCharges != 0 ); + SetSaveFlag( ref flags, SaveFlag.Crafter, m_Crafter != null ); + SetSaveFlag( ref flags, SaveFlag.Identified, m_Identified != false ); + SetSaveFlag( ref flags, SaveFlag.StrReq, m_StrReq != -1 ); + SetSaveFlag( ref flags, SaveFlag.DexReq, m_DexReq != -1 ); + SetSaveFlag( ref flags, SaveFlag.IntReq, m_IntReq != -1 ); + SetSaveFlag( ref flags, SaveFlag.MinDamage, m_MinDamage != -1 ); + SetSaveFlag( ref flags, SaveFlag.MaxDamage, m_MaxDamage != -1 ); + SetSaveFlag( ref flags, SaveFlag.HitSound, m_HitSound != -1 ); + SetSaveFlag( ref flags, SaveFlag.MissSound, m_MissSound != -1 ); + SetSaveFlag( ref flags, SaveFlag.Speed, m_Speed != -1 ); + SetSaveFlag( ref flags, SaveFlag.MaxRange, m_MaxRange != -1 ); + SetSaveFlag( ref flags, SaveFlag.Skill, m_Skill != (SkillName)(-1) ); + SetSaveFlag( ref flags, SaveFlag.Type, m_Type != (WeaponType)(-1) ); + SetSaveFlag( ref flags, SaveFlag.Animation, m_Animation != (WeaponAnimation)(-1) ); + SetSaveFlag( ref flags, SaveFlag.Resource, m_Resource != CraftResource.MIron ); + SetSaveFlag( ref flags, SaveFlag.xAttributes, !m_AosAttributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.xWeaponAttributes, !m_AosWeaponAttributes.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.PlayerConstructed, m_PlayerConstructed ); + SetSaveFlag( ref flags, SaveFlag.SkillBonuses, !m_AosSkillBonuses.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.Slayer2, m_Slayer2 != SlayerName.None ); + SetSaveFlag( ref flags, SaveFlag.ElementalDamages, !m_AosElementDamages.IsEmpty ); + SetSaveFlag( ref flags, SaveFlag.EngravedText, !String.IsNullOrEmpty( m_EngravedText ) ); + + writer.Write( (int) flags ); + + if ( GetSaveFlag( flags, SaveFlag.DamageLevel ) ) + writer.Write( (int) m_DamageLevel ); + + if ( GetSaveFlag( flags, SaveFlag.AccuracyLevel ) ) + writer.Write( (int) m_AccuracyLevel ); + + if ( GetSaveFlag( flags, SaveFlag.DurabilityLevel ) ) + writer.Write( (int) m_DurabilityLevel ); + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + writer.Write( (int) m_Quality ); + + if ( GetSaveFlag( flags, SaveFlag.Hits ) ) + writer.Write( (int) m_Hits ); + + if ( GetSaveFlag( flags, SaveFlag.MaxHits ) ) + writer.Write( (int) m_MaxHits ); + + if ( GetSaveFlag( flags, SaveFlag.Slayer ) ) + writer.Write( (int) m_Slayer ); + + if ( GetSaveFlag( flags, SaveFlag.Poison ) ) + Poison.Serialize( m_Poison, writer ); + + if ( GetSaveFlag( flags, SaveFlag.PoisonCharges ) ) + writer.Write( (int) m_PoisonCharges ); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + writer.Write( (Mobile) m_Crafter ); + + if ( GetSaveFlag( flags, SaveFlag.StrReq ) ) + writer.Write( (int) m_StrReq ); + + if ( GetSaveFlag( flags, SaveFlag.DexReq ) ) + writer.Write( (int) m_DexReq ); + + if ( GetSaveFlag( flags, SaveFlag.IntReq ) ) + writer.Write( (int) m_IntReq ); + + if ( GetSaveFlag( flags, SaveFlag.MinDamage ) ) + writer.Write( (int) m_MinDamage ); + + if ( GetSaveFlag( flags, SaveFlag.MaxDamage ) ) + writer.Write( (int) m_MaxDamage ); + + if ( GetSaveFlag( flags, SaveFlag.HitSound ) ) + writer.Write( (int) m_HitSound ); + + if ( GetSaveFlag( flags, SaveFlag.MissSound ) ) + writer.Write( (int) m_MissSound ); + + if ( GetSaveFlag( flags, SaveFlag.Speed ) ) + writer.Write( (float) m_Speed ); + + if ( GetSaveFlag( flags, SaveFlag.MaxRange ) ) + writer.Write( (int) m_MaxRange ); + + if ( GetSaveFlag( flags, SaveFlag.Skill ) ) + writer.Write( (int) m_Skill ); + + if ( GetSaveFlag( flags, SaveFlag.Type ) ) + writer.Write( (int) m_Type ); + + if ( GetSaveFlag( flags, SaveFlag.Animation ) ) + writer.Write( (int) m_Animation ); + + if ( GetSaveFlag( flags, SaveFlag.Resource ) ) + writer.Write( (int) m_Resource ); + + if ( GetSaveFlag( flags, SaveFlag.xAttributes ) ) + m_AosAttributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.xWeaponAttributes ) ) + m_AosWeaponAttributes.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.SkillBonuses ) ) + m_AosSkillBonuses.Serialize( writer ); + + if ( GetSaveFlag( flags, SaveFlag.Slayer2 ) ) + writer.Write( (int)m_Slayer2 ); + + if( GetSaveFlag( flags, SaveFlag.ElementalDamages ) ) + m_AosElementDamages.Serialize( writer ); + + if( GetSaveFlag( flags, SaveFlag.EngravedText ) ) + writer.Write( (string) m_EngravedText ); + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + DamageLevel = 0x00000001, + AccuracyLevel = 0x00000002, + DurabilityLevel = 0x00000004, + Quality = 0x00000008, + Hits = 0x00000010, + MaxHits = 0x00000020, + Slayer = 0x00000040, + Poison = 0x00000080, + PoisonCharges = 0x00000100, + Crafter = 0x00000200, + Identified = 0x00000400, + StrReq = 0x00000800, + DexReq = 0x00001000, + IntReq = 0x00002000, + MinDamage = 0x00004000, + MaxDamage = 0x00008000, + HitSound = 0x00010000, + MissSound = 0x00020000, + Speed = 0x00040000, + MaxRange = 0x00080000, + Skill = 0x00100000, + Type = 0x00200000, + Animation = 0x00400000, + Resource = 0x00800000, + xAttributes = 0x01000000, + xWeaponAttributes = 0x02000000, + PlayerConstructed = 0x04000000, + SkillBonuses = 0x08000000, + Slayer2 = 0x10000000, + ElementalDamages = 0x20000000, + EngravedText = 0x40000000 + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 10: + case 9: + case 8: + case 7: + case 6: + case 5: + { + SaveFlag flags = (SaveFlag)reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.DamageLevel ) ) + { + m_DamageLevel = (WeaponDamageLevel)reader.ReadInt(); + + if ( m_DamageLevel > WeaponDamageLevel.Vanq ) + m_DamageLevel = WeaponDamageLevel.Ruin; + } + + if ( GetSaveFlag( flags, SaveFlag.AccuracyLevel ) ) + { + m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt(); + + if ( m_AccuracyLevel > WeaponAccuracyLevel.Supremely ) + m_AccuracyLevel = WeaponAccuracyLevel.Accurate; + } + + if ( GetSaveFlag( flags, SaveFlag.DurabilityLevel ) ) + { + m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt(); + + if ( m_DurabilityLevel > WeaponDurabilityLevel.Indestructible ) + m_DurabilityLevel = WeaponDurabilityLevel.Durable; + } + + if ( GetSaveFlag( flags, SaveFlag.Quality ) ) + m_Quality = (WeaponQuality)reader.ReadInt(); + else + m_Quality = WeaponQuality.Regular; + + if ( GetSaveFlag( flags, SaveFlag.Hits ) ) + m_Hits = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.MaxHits ) ) + m_MaxHits = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Slayer ) ) + m_Slayer = (SlayerName)reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Poison ) ) + m_Poison = Poison.Deserialize( reader ); + + if ( GetSaveFlag( flags, SaveFlag.PoisonCharges ) ) + m_PoisonCharges = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Crafter ) ) + m_Crafter = reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.Identified ) ) + m_Identified = ( version >= 6 || reader.ReadBool() ); + + if ( GetSaveFlag( flags, SaveFlag.StrReq ) ) + m_StrReq = reader.ReadInt(); + else + m_StrReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.DexReq ) ) + m_DexReq = reader.ReadInt(); + else + m_DexReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.IntReq ) ) + m_IntReq = reader.ReadInt(); + else + m_IntReq = -1; + + if ( GetSaveFlag( flags, SaveFlag.MinDamage ) ) + m_MinDamage = reader.ReadInt(); + else + m_MinDamage = -1; + + if ( GetSaveFlag( flags, SaveFlag.MaxDamage ) ) + m_MaxDamage = reader.ReadInt(); + else + m_MaxDamage = -1; + + if ( GetSaveFlag( flags, SaveFlag.HitSound ) ) + m_HitSound = reader.ReadInt(); + else + m_HitSound = -1; + + if ( GetSaveFlag( flags, SaveFlag.MissSound ) ) + m_MissSound = reader.ReadInt(); + else + m_MissSound = -1; + + if ( GetSaveFlag( flags, SaveFlag.Speed ) ) + { + if ( version < 9 ) + m_Speed = reader.ReadInt(); + else + m_Speed = reader.ReadFloat(); + } + else + m_Speed = -1; + + if ( GetSaveFlag( flags, SaveFlag.MaxRange ) ) + m_MaxRange = reader.ReadInt(); + else + m_MaxRange = -1; + + if ( GetSaveFlag( flags, SaveFlag.Skill ) ) + m_Skill = (SkillName)reader.ReadInt(); + else + m_Skill = (SkillName)(-1); + + if ( GetSaveFlag( flags, SaveFlag.Type ) ) + m_Type = (WeaponType)reader.ReadInt(); + else + m_Type = (WeaponType)(-1); + + if ( GetSaveFlag( flags, SaveFlag.Animation ) ) + m_Animation = (WeaponAnimation)reader.ReadInt(); + else + m_Animation = (WeaponAnimation)(-1); + + if ( GetSaveFlag( flags, SaveFlag.Resource ) ) + m_Resource = (CraftResource)reader.ReadInt(); + else + m_Resource = CraftResource.MIron; + + if ( GetSaveFlag( flags, SaveFlag.xAttributes ) ) + m_AosAttributes = new AosAttributes( this, reader ); + else + m_AosAttributes = new AosAttributes( this ); + + if ( GetSaveFlag( flags, SaveFlag.xWeaponAttributes ) ) + m_AosWeaponAttributes = new AosWeaponAttributes( this, reader ); + else + m_AosWeaponAttributes = new AosWeaponAttributes( this ); + + if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && Parent is Mobile ) + { + m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5 ); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + + if ( version < 7 && m_AosWeaponAttributes.MageWeapon != 0 ) + m_AosWeaponAttributes.MageWeapon = 30 - m_AosWeaponAttributes.MageWeapon; + + if ( Core.AOS && m_AosWeaponAttributes.MageWeapon != 0 && m_AosWeaponAttributes.MageWeapon != 30 && Parent is Mobile ) + { + m_MageMod = new DefaultSkillMod( SkillName.Magery, true, -30 + m_AosWeaponAttributes.MageWeapon ); + ((Mobile)Parent).AddSkillMod( m_MageMod ); + } + + if ( GetSaveFlag( flags, SaveFlag.PlayerConstructed ) ) + m_PlayerConstructed = true; + + if( GetSaveFlag( flags, SaveFlag.SkillBonuses ) ) + m_AosSkillBonuses = new AosSkillBonuses( this, reader ); + else + m_AosSkillBonuses = new AosSkillBonuses( this ); + + if( GetSaveFlag( flags, SaveFlag.Slayer2 ) ) + m_Slayer2 = (SlayerName)reader.ReadInt(); + + if( GetSaveFlag( flags, SaveFlag.ElementalDamages ) ) + m_AosElementDamages = new AosElementAttributes( this, reader ); + else + m_AosElementDamages = new AosElementAttributes( this ); + + if( GetSaveFlag( flags, SaveFlag.EngravedText ) ) + m_EngravedText = reader.ReadString(); + + break; + } + case 4: + { + m_Slayer = (SlayerName)reader.ReadInt(); + + goto case 3; + } + case 3: + { + m_StrReq = reader.ReadInt(); + m_DexReq = reader.ReadInt(); + m_IntReq = reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_Identified = reader.ReadBool(); + + goto case 1; + } + case 1: + { + m_MaxRange = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if ( version == 0 ) + m_MaxRange = 1; // default + + if ( version < 5 ) + { + m_Resource = CraftResource.MIron; + m_AosAttributes = new AosAttributes( this ); + m_AosWeaponAttributes = new AosWeaponAttributes( this ); + m_AosElementDamages = new AosElementAttributes( this ); + m_AosSkillBonuses = new AosSkillBonuses( this ); + } + + m_MinDamage = reader.ReadInt(); + m_MaxDamage = reader.ReadInt(); + + m_Speed = reader.ReadInt(); + + m_HitSound = reader.ReadInt(); + m_MissSound = reader.ReadInt(); + + m_Skill = (SkillName)reader.ReadInt(); + m_Type = (WeaponType)reader.ReadInt(); + m_Animation = (WeaponAnimation)reader.ReadInt(); + m_DamageLevel = (WeaponDamageLevel)reader.ReadInt(); + m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt(); + m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt(); + m_Quality = (WeaponQuality)reader.ReadInt(); + + m_Crafter = reader.ReadMobile(); + + m_Poison = Poison.Deserialize( reader ); + m_PoisonCharges = reader.ReadInt(); + + if ( m_StrReq == OldStrengthReq ) + m_StrReq = -1; + + if ( m_DexReq == OldDexterityReq ) + m_DexReq = -1; + + if ( m_IntReq == OldIntelligenceReq ) + m_IntReq = -1; + + if ( m_MinDamage == OldMinDamage ) + m_MinDamage = -1; + + if ( m_MaxDamage == OldMaxDamage ) + m_MaxDamage = -1; + + if ( m_HitSound == OldHitSound ) + m_HitSound = -1; + + if ( m_MissSound == OldMissSound ) + m_MissSound = -1; + + if ( m_Speed == OldSpeed ) + m_Speed = -1; + + if ( m_MaxRange == OldMaxRange ) + m_MaxRange = -1; + + if ( m_Skill == OldSkill ) + m_Skill = (SkillName)(-1); + + if ( m_Type == OldType ) + m_Type = (WeaponType)(-1); + + if ( m_Animation == OldAnimation ) + m_Animation = (WeaponAnimation)(-1); + + if ( UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && Parent is Mobile ) + { + m_SkillMod = new DefaultSkillMod( AccuracySkill, true, (int)m_AccuracyLevel * 5); + ((Mobile)Parent).AddSkillMod( m_SkillMod ); + } + + break; + } + } + + if ( Core.AOS && Parent is Mobile ) + m_AosSkillBonuses.AddTo( (Mobile)Parent ); + + int strBonus = m_AosAttributes.BonusStr; + int dexBonus = m_AosAttributes.BonusDex; + int intBonus = m_AosAttributes.BonusInt; + + if ( this.Parent is Mobile && (strBonus != 0 || dexBonus != 0 || intBonus != 0) ) + { + Mobile m = (Mobile)this.Parent; + + string modName = this.Serial.ToString(); + + if ( strBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + m.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + if ( Parent is Mobile ) + ((Mobile)Parent).CheckStatTimers(); + + if ( m_Hits <= 0 && m_MaxHits <= 0 ) + { + m_Hits = m_MaxHits = Utility.RandomMinMax( InitMinHits, InitMaxHits ); + } + + if ( version < 6 ) + m_PlayerConstructed = true; // we don't know, so, assume it's crafted + if (version < 10) + m_Identified = true; // we don't know, so, assume it's identified + } + #endregion + + public BaseWeapon( int itemID ) : base( itemID ) + { + Layer = (Layer)ItemData.Quality; + m_Identified = true; + m_Quality = WeaponQuality.Regular; + m_StrReq = -1; + m_DexReq = -1; + m_IntReq = -1; + m_MinDamage = -1; + m_MaxDamage = -1; + m_HitSound = -1; + m_MissSound = -1; + m_Speed = -1; + m_MaxRange = -1; + m_Skill = (SkillName)(-1); + m_Type = (WeaponType)(-1); + m_Animation = (WeaponAnimation)(-1); + + m_Hits = m_MaxHits = Utility.RandomMinMax( InitMinHits, InitMaxHits ); + + m_Resource = CraftResource.MIron; + + m_AosAttributes = new AosAttributes( this ); + m_AosWeaponAttributes = new AosWeaponAttributes( this ); + m_AosSkillBonuses = new AosSkillBonuses( this ); + m_AosElementDamages = new AosElementAttributes( this ); + } + + public BaseWeapon( Serial serial ) : base( serial ) + { + } + + private string GetNameString() + { + string name = this.Name; + + if ( name == null ) + name = String.Format( "#{0}", LabelNumber ); + + return name; + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public override int Hue + { + get{ return base.Hue; } + set{ base.Hue = value; InvalidateProperties(); } + } + + public int GetElementalDamageHue() + { + int phys, fire, cold, pois, nrgy, chaos, direct; + GetDamageTypes( null, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct ); + //Order is Cold, Energy, Fire, Poison, Physical left + + int currentMax = 50; + int hue = 0; + + if( pois >= currentMax ) + { + hue = 1267 + (pois - 50) / 10; + currentMax = pois; + } + + if( fire >= currentMax ) + { + hue = 1255 + (fire - 50) / 10; + currentMax = fire; + } + + if( nrgy >= currentMax ) + { + hue = 1273 + (nrgy - 50) / 10; + currentMax = nrgy; + } + + if( cold >= currentMax ) + { + hue = 1261 + (cold - 50) / 10; + currentMax = cold; + } + + return hue; + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + //Plume: On affiche que le nom de l'item + + //string oreType; + + //switch ( m_Resource ) + //{ + // case CraftResource.MBronze: oreType = "Bronze"; break; // dull copper + // case CraftResource.MGold: oreType = "Or"; break; // shadow iron + // case CraftResource.MCopper: oreType = "Cuivre"; break; // copper + // case CraftResource.MOldcopper: oreType = "Vieux cuivre"; break; // bronze + // case CraftResource.MDullcopper: oreType = "Cuivre terni"; break; // golden + // case CraftResource.MSilver: oreType = "Silver"; break; // agapite + // case CraftResource.MShadow: oreType = "Sombrine"; break; // verite + // case CraftResource.MBloodrock: oreType = "Pierre de sang"; break; // valorite + // case CraftResource.MBlackrock: oreType = "Pierre noire"; break; // dull copper + // case CraftResource.MMytheril: oreType = "Mytheril"; break; // shadow iron + // case CraftResource.MRose: oreType = "Rose"; break; // copper + // case CraftResource.MVerite: oreType = "Verite"; break; // bronze + // case CraftResource.MAgapite: oreType = "Agapite"; break; // golden + // case CraftResource.MRusty: oreType = "Rouille"; break; // agapite + // case CraftResource.MValorite: oreType = "Valorite"; break; // verite + // case CraftResource.MDragon: oreType = "Dragon"; break; // valorite + // case CraftResource.MTitan: oreType = "Titan"; break; // dull copper + // case CraftResource.MCrystaline: oreType = "Crystaline"; break; // shadow iron + // case CraftResource.MKrynite: oreType = "Krynite"; break; // copper + // case CraftResource.MVulcan: oreType = "Vulcan"; break; // bronze + // case CraftResource.MBloodcrest: oreType = "Craie de sang"; break; // golden + // case CraftResource.MElvin: oreType = "Elvin"; break; // agapite + // case CraftResource.MAcid: oreType = "Acid"; break; // valorite + // case CraftResource.MAqua: oreType = "Aqua"; break; // copper + // case CraftResource.MEldar: oreType = "Eldar"; break; // bronze + // case CraftResource.MGlowing: oreType = "Glowing"; break; // golden + // case CraftResource.MGorgan: oreType = "Gorgan"; break; // agapite + // case CraftResource.MSandrock: oreType = "Pierre de sable"; break; // verite + // case CraftResource.MSteel: oreType = "Acier"; break; // valorite + // case CraftResource.SpinedLeather: oreType = "spined"; break; // spined + // case CraftResource.HornedLeather: oreType = "horned"; break; // horned + // case CraftResource.BarbedLeather: oreType = "barbed"; break; // barbed + // case CraftResource.RedScales: oreType = "red"; break; // red + // case CraftResource.YellowScales: oreType = "yellow"; break; // yellow + // case CraftResource.BlackScales: oreType = "black"; break; // black + // case CraftResource.GreenScales: oreType = "green"; break; // green + // case CraftResource.WhiteScales: oreType = "white"; break; // white + // case CraftResource.BlueScales: oreType = "blue"; break; // blue + // case CraftResource.OakWood: oreType = "Oak"; break; // red + // case CraftResource.YewWood: oreType = "Yew"; break; // yellow + // case CraftResource.Bloodwood: oreType = "Bloodwood"; break; // black + // case CraftResource.Frostwood: oreType = "Frostwood"; break; // green + // case CraftResource.Heartwood: oreType = "Heartwood"; break; // white + // default: oreType = null; break; + //} + + //if ( oreType != null ) + // list.Add( 1053099, "{0}\t{1}", oreType, GetNameString() ); // ~1_oretype~ ~2_armortype~ + //else + if ( Name == null ) + list.Add( LabelNumber ); + else + list.Add( Name ); + + /* + * Want to move this to the engraving tool, let the non-harmful + * formatting show, and remove CLILOCs embedded: more like OSI + * did with the books that had markup, etc. + * + * This will have a negative effect on a few event things imgame + * as is. + * + * If we cant find a more OSI-ish way to clean it up, we can + * easily put this back, and use it in the deserialize + * method and engraving tool, to make it perm cleaned up. + */ + + if ( !String.IsNullOrEmpty( m_EngravedText ) ) + list.Add( 1062613, m_EngravedText ); + + /* list.Add( 1062613, Utility.FixHtml( m_EngravedText ) ); */ + + } + + public override bool AllowEquipedCast( Mobile from ) + { + if ( base.AllowEquipedCast( from ) ) + return true; + + return ( m_AosAttributes.SpellChanneling != 0 ); + } + + public virtual int ArtifactRarity + { + get{ return 0; } + } + + public virtual int GetLuckBonus() + { + CraftResourceInfo resInfo = CraftResources.GetInfo( m_Resource ); + + if ( resInfo == null ) + return 0; + + CraftAttributeInfo attrInfo = resInfo.AttributeInfo; + + if ( attrInfo == null ) + return 0; + + return attrInfo.WeaponLuck; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if (m_Hits <= 0) + list.Add("Endommag�e"); + + if ( m_Crafter != null ) + list.Add( 1050043, m_Crafter.Name ); // crafted by ~1_NAME~ + + if (RequiredRace == Race.Elf) + list.Add(1075086); // Elves Only + + if (m_Identified) + { + #region Factions + if ( m_FactionState != null ) + list.Add( 1041350 ); // faction item + #endregion + + if ( m_AosSkillBonuses != null ) + m_AosSkillBonuses.GetProperties( list ); + + // Plume : Qualit� dans le ArmLore + //if ( m_Quality == WeaponQuality.Exceptional ) + // list.Add( 1060636 ); // exceptional + + if ( ArtifactRarity > 0 ) + list.Add( 1061078, ArtifactRarity.ToString() ); // artifact rarity ~1_val~ + + if ( this is IUsesRemaining && ((IUsesRemaining)this).ShowUsesRemaining ) + list.Add( 1060584, ((IUsesRemaining)this).UsesRemaining.ToString() ); // uses remaining: ~1_val~ + + if ( m_Poison != null && m_PoisonCharges > 0 ) + list.Add( 1062412 + m_Poison.Level, m_PoisonCharges.ToString() ); + + if( m_Slayer != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer ); + if( entry != null ) + list.Add( entry.Title ); + } + + if( m_Slayer2 != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 ); + if( entry != null ) + list.Add( entry.Title ); + } + + + base.AddResistanceProperties( list ); + + int prop; + + + if ( Core.ML && this is BaseRanged && ( (BaseRanged) this ).Balanced ) + list.Add( 1072792 ); // Balanced + + if ( (prop = m_AosWeaponAttributes.UseBestSkill) != 0 ) + list.Add( 1060400 ); // use best weapon skill + + if ( (prop = (GetDamageBonus() + m_AosAttributes.WeaponDamage)) != 0 ) + list.Add( 1060401, prop.ToString() ); // damage increase ~1_val~% + + if ( (prop = m_AosAttributes.DefendChance) != 0 ) + list.Add( 1060408, prop.ToString() ); // defense chance increase ~1_val~% + + if ( (prop = m_AosAttributes.EnhancePotions) != 0 ) + list.Add( 1060411, prop.ToString() ); // enhance potions ~1_val~% + + if ( (prop = m_AosAttributes.CastRecovery) != 0 ) + list.Add( 1060412, prop.ToString() ); // faster cast recovery ~1_val~ + + if ( (prop = m_AosAttributes.CastSpeed) != 0 ) + list.Add( 1060413, prop.ToString() ); // faster casting ~1_val~ + + if ( (prop = (GetHitChanceBonus() + m_AosAttributes.AttackChance)) != 0 ) + list.Add( 1060415, prop.ToString() ); // hit chance increase ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitColdArea) != 0 ) + list.Add( 1060416, prop.ToString() ); // hit cold area ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitDispel) != 0 ) + list.Add( 1060417, prop.ToString() ); // hit dispel ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitEnergyArea) != 0 ) + list.Add( 1060418, prop.ToString() ); // hit energy area ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitFireArea) != 0 ) + list.Add( 1060419, prop.ToString() ); // hit fire area ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitFireball) != 0 ) + list.Add( 1060420, prop.ToString() ); // hit fireball ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitHarm) != 0 ) + list.Add( 1060421, prop.ToString() ); // hit harm ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitLeechHits) != 0 ) + list.Add( 1060422, prop.ToString() ); // hit life leech ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitLightning) != 0 ) + list.Add( 1060423, prop.ToString() ); // hit lightning ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitLowerAttack) != 0 ) + list.Add( 1060424, prop.ToString() ); // hit lower attack ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitLowerDefend) != 0 ) + list.Add( 1060425, prop.ToString() ); // hit lower defense ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitMagicArrow) != 0 ) + list.Add( 1060426, prop.ToString() ); // hit magic arrow ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitLeechMana) != 0 ) + list.Add( 1060427, prop.ToString() ); // hit mana leech ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitPhysicalArea) != 0 ) + list.Add( 1060428, prop.ToString() ); // hit physical area ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitPoisonArea) != 0 ) + list.Add( 1060429, prop.ToString() ); // hit poison area ~1_val~% + + if ( (prop = m_AosWeaponAttributes.HitLeechStam) != 0 ) + list.Add( 1060430, prop.ToString() ); // hit stamina leech ~1_val~% + + if ( Core.ML && this is BaseRanged && ( prop = ( (BaseRanged) this ).Velocity ) != 0 ) + list.Add( 1072793, prop.ToString() ); // Velocity ~1_val~% + + if ( (prop = m_AosAttributes.BonusDex) != 0 ) + list.Add( 1060409, prop.ToString() ); // dexterity bonus ~1_val~ + + if ( (prop = m_AosAttributes.BonusHits) != 0 ) + list.Add( 1060431, prop.ToString() ); // hit point increase ~1_val~ + + if ( (prop = m_AosAttributes.BonusInt) != 0 ) + list.Add( 1060432, prop.ToString() ); // intelligence bonus ~1_val~ + + if ( (prop = m_AosAttributes.LowerManaCost) != 0 ) + list.Add( 1060433, prop.ToString() ); // lower mana cost ~1_val~% + + if ( (prop = m_AosAttributes.LowerRegCost) != 0 ) + list.Add( 1060434, prop.ToString() ); // lower reagent cost ~1_val~% + + if ( (prop = GetLowerStatReq()) != 0 ) + list.Add( 1060435, prop.ToString() ); // lower requirements ~1_val~% + + if ( (prop = (GetLuckBonus() + m_AosAttributes.Luck)) != 0 ) + list.Add( 1060436, prop.ToString() ); // luck ~1_val~ + + if ( (prop = m_AosWeaponAttributes.MageWeapon) != 0 ) + list.Add( 1060438, (30 - prop).ToString() ); // mage weapon -~1_val~ skill + + if ( (prop = m_AosAttributes.BonusMana) != 0 ) + list.Add( 1060439, prop.ToString() ); // mana increase ~1_val~ + + if ( (prop = m_AosAttributes.RegenMana) != 0 ) + list.Add( 1060440, prop.ToString() ); // mana regeneration ~1_val~ + + if ( (prop = m_AosAttributes.NightSight) != 0 ) + list.Add( 1060441 ); // night sight + + if ( (prop = m_AosAttributes.ReflectPhysical) != 0 ) + list.Add( 1060442, prop.ToString() ); // reflect physical damage ~1_val~% + + if ( (prop = m_AosAttributes.RegenStam) != 0 ) + list.Add( 1060443, prop.ToString() ); // stamina regeneration ~1_val~ + + if ( (prop = m_AosAttributes.RegenHits) != 0 ) + list.Add( 1060444, prop.ToString() ); // hit point regeneration ~1_val~ + + if ( (prop = m_AosWeaponAttributes.SelfRepair) != 0 ) + list.Add( 1060450, prop.ToString() ); // self repair ~1_val~ + + if ( (prop = m_AosAttributes.SpellChanneling) != 0 ) + list.Add( 1060482 ); // spell channeling + + if ( (prop = m_AosAttributes.SpellDamage) != 0 ) + list.Add( 1060483, prop.ToString() ); // spell damage increase ~1_val~% + + if ( (prop = m_AosAttributes.BonusStam) != 0 ) + list.Add( 1060484, prop.ToString() ); // stamina increase ~1_val~ + + if ( (prop = m_AosAttributes.BonusStr) != 0 ) + list.Add( 1060485, prop.ToString() ); // strength bonus ~1_val~ + + if ( (prop = m_AosAttributes.WeaponSpeed) != 0 ) + list.Add( 1060486, prop.ToString() ); // swing speed increase ~1_val~% + + if (Core.ML && (prop = m_AosAttributes.IncreasedKarmaLoss) != 0) + list.Add(1075210, prop.ToString()); // Increased Karma Loss ~1val~% + + int phys, fire, cold, pois, nrgy, chaos, direct; + + GetDamageTypes( null, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct ); + + if ( phys != 0 ) + list.Add( 1060403, phys.ToString() ); // physical damage ~1_val~% + + if ( fire != 0 ) + list.Add( 1060405, fire.ToString() ); // fire damage ~1_val~% + + if ( cold != 0 ) + list.Add( 1060404, cold.ToString() ); // cold damage ~1_val~% + + if ( pois != 0 ) + list.Add( 1060406, pois.ToString() ); // poison damage ~1_val~% + + if ( nrgy != 0 ) + list.Add( 1060407, nrgy.ToString() ); // energy damage ~1_val + + if ( Core.ML && chaos != 0 ) + list.Add( 1072846, chaos.ToString() ); // chaos damage ~1_val~% + + if ( Core.ML && direct != 0 ) + list.Add( 1079978, direct.ToString() ); // Direct Damage: ~1_PERCENT~% + + list.Add( 1061168, "{0}\t{1}", MinDamage.ToString(), MaxDamage.ToString() ); // weapon damage ~1_val~ - ~2_val~ + + if ( Core.ML ) + list.Add( 1061167, String.Format( "{0}s", Speed ) ); // weapon speed ~1_val~ + else + list.Add( 1061167, Speed.ToString() ); + + if ( MaxRange > 1 ) + list.Add( 1061169, MaxRange.ToString() ); // range ~1_val~ + + int strReq = AOS.Scale( StrRequirement, 100 - GetLowerStatReq() ); + + if ( strReq > 0 ) + list.Add( 1061170, strReq.ToString() ); // strength requirement ~1_val~ + + if ( Layer == Layer.TwoHanded ) + list.Add( 1061171 ); // two-handed weapon + else + list.Add( 1061824 ); // one-handed weapon + + if ( Core.SE || m_AosWeaponAttributes.UseBestSkill == 0 ) + { + switch ( Skill ) + { + case SkillName.Swords: list.Add( 1061172 ); break; // skill required: swordsmanship + case SkillName.Macing: list.Add( 1061173 ); break; // skill required: mace fighting + case SkillName.Fencing: list.Add( 1061174 ); break; // skill required: fencing + case SkillName.Archery: list.Add( 1061175 ); break; // skill required: archery + } + } + //Hits via ArmsLore + //if ( m_Hits >= 0 && m_MaxHits > 0 ) + // list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~ + } + if (!m_Identified) + list.Add("Non identifi�"); + } + + public override void OnSingleClick( Mobile from ) + { + List attrs = new List(); + + if ( DisplayLootType ) + { + if ( LootType == LootType.Blessed ) + attrs.Add( new EquipInfoAttribute( 1038021 ) ); // blessed + else if ( LootType == LootType.Cursed ) + attrs.Add( new EquipInfoAttribute( 1049643 ) ); // cursed + } + + #region Factions + if ( m_FactionState != null ) + attrs.Add( new EquipInfoAttribute( 1041350 ) ); // faction item + #endregion + + if ( m_Quality == WeaponQuality.Exceptional ) + attrs.Add( new EquipInfoAttribute( 1018305 - (int)m_Quality ) ); + + if ( m_Identified || from.AccessLevel >= AccessLevel.GameMaster ) + { + if( m_Slayer != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer ); + if( entry != null ) + attrs.Add( new EquipInfoAttribute( entry.Title ) ); + } + + if( m_Slayer2 != SlayerName.None ) + { + SlayerEntry entry = SlayerGroup.GetEntryByName( m_Slayer2 ); + if( entry != null ) + attrs.Add( new EquipInfoAttribute( entry.Title ) ); + } + /* + if ( m_DurabilityLevel != WeaponDurabilityLevel.Regular ) + attrs.Add( new EquipInfoAttribute( 1038000 + (int)m_DurabilityLevel ) ); + + if ( m_DamageLevel != WeaponDamageLevel.Regular ) + attrs.Add( new EquipInfoAttribute( 1038015 + (int)m_DamageLevel )); + + if ( m_AccuracyLevel != WeaponAccuracyLevel.Regular ) + attrs.Add(new EquipInfoAttribute(1038010 + (int)m_AccuracyLevel )); + */ + } + else if( m_Slayer != SlayerName.None || m_Slayer2 != SlayerName.None || m_DurabilityLevel != WeaponDurabilityLevel.Regular || m_DamageLevel != WeaponDamageLevel.Regular || m_AccuracyLevel != WeaponAccuracyLevel.Regular ) + attrs.Add( new EquipInfoAttribute( 1038000 ) ); // Unidentified + + if ( m_Poison != null && m_PoisonCharges > 0 ) + attrs.Add( new EquipInfoAttribute( 1017383, m_PoisonCharges ) ); + + int number; + + if ( Name == null ) + { + number = LabelNumber; + } + else + { + this.LabelTo( from, Name ); + number = 1041000; + } + + if ( attrs.Count == 0 && Crafter == null && Name != null ) + return; + + EquipmentInfo eqInfo = new EquipmentInfo( number, m_Crafter, false, attrs.ToArray() ); + + from.Send( new DisplayEquipmentInfo( this, eqInfo ) ); + } + + private static BaseWeapon m_Fists; // This value holds the default--fist--weapon + + public static BaseWeapon Fists + { + get{ return m_Fists; } + set{ m_Fists = value; } + } + + #region ICraftable Members + + public int OnCraft( int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue ) + { + Quality = (WeaponQuality)quality; + + if ( makersMark ) + Crafter = from; + + PlayerConstructed = true; + Identified = true; + + Type resourceType = typeRes; + + if ( resourceType == null ) + resourceType = craftItem.Resources.GetAt( 0 ).ItemType; + + if ( Core.AOS ) + { + Resource = CraftResources.GetFromType( resourceType ); + + CraftContext context = craftSystem.GetContext( from ); + + if ( context != null && context.DoNotColor ) + Hue = 0; + + if ( tool is BaseRunicTool ) + ((BaseRunicTool)tool).ApplyAttributesTo( this ); + + if ( Quality == WeaponQuality.Exceptional ) + { + if ( Attributes.WeaponDamage > 35 ) + Attributes.WeaponDamage -= 20; + else + Attributes.WeaponDamage = 15; + + if( Core.ML ) + { + Attributes.WeaponDamage += (int)(from.Skills.ArmsLore.Value / 20); + + if ( Attributes.WeaponDamage > 50 ) + Attributes.WeaponDamage = 50; + + from.CheckSkill( SkillName.ArmsLore, 0, 100 ); + } + } + //Ajout d'un scalar pour chaque m�tal pour les diff�rents types de durabilit�/d�gats/accuit�s + double DurScalar = 1; + double DmgScalar = 1; + double AccScalar = 1; + bool Daylight = false; + if(Resource == CraftResource.MGlowing) + { + + int hours = 0; + int minutes = 0; + + Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + + if (hours < 18 && hours > 7) + { + + Daylight = true; + } + } + switch (Resource) + { + case CraftResource.MBronze: + { + DurScalar = 0.99; + DmgScalar = 0.99; + AccScalar = 0.99; + break; + } + case CraftResource.MGold: + { + DmgScalar = 0.95; + AccScalar = 0.95; + break; + } + case CraftResource.MCopper: + { + DurScalar = 0.98; + DmgScalar = 0.98; + AccScalar = 0.99; + break; + } + case CraftResource.MOldcopper: + { + DmgScalar = 0.99; + AccScalar = 1.01; + break; + } + case CraftResource.MDullcopper: + { + DurScalar = 1.01; + break; + } + case CraftResource.MSilver: + { + DurScalar = 1.05; + AccScalar = 1.02; + break; + } + case CraftResource.MShadow: + { + DmgScalar = 0.95; + AccScalar = 1.05; + break; + } + case CraftResource.MBloodrock: + { + break; + } + case CraftResource.MBlackrock: + { + break; + } + case CraftResource.MMytheril: + { + break; + } + case CraftResource.MRose: + { + AccScalar = 1.03; + break; + } + case CraftResource.MVerite: + { + DurScalar = 1.05; + DmgScalar = 1.05; + AccScalar = 1.05; + break; + } + case CraftResource.MAgapite: + { + + break; + } + case CraftResource.MRusty: + { + DurScalar = 0.90; + DmgScalar = 0.95; + AccScalar = 0.80; + break; + } + case CraftResource.MValorite: + { + DurScalar = 0.95; + DmgScalar = 1.1; + AccScalar = 1.05; + break; + } + case CraftResource.MDragon: + { + DurScalar = 1.02; + DmgScalar = 1.03; + AccScalar = 0.95; + break; + } + case CraftResource.MTitan: + { + DurScalar = 1.25; + DmgScalar = 1.15; + AccScalar = 0.7; + break; + } + case CraftResource.MCrystaline: + { + + break; + } + case CraftResource.MKrynite: + { + + break; + } + case CraftResource.MVulcan: + { + + break; + } + case CraftResource.MBloodcrest: + { + + break; + } + case CraftResource.MElvin: + { + + break; + } + case CraftResource.MAcid: + { + + break; + } + case CraftResource.MAqua: + { + + break; + } + case CraftResource.MEldar: + { + DurScalar = 1.02; + DmgScalar = 1.03; + AccScalar = 1.15; + break; + } + case CraftResource.MGlowing: + { + DurScalar = Daylight? 1.04:0.80; + DmgScalar = Daylight? 1.04 : 0.80; + AccScalar = Daylight? 1.04 : 0.80; + break; + } + case CraftResource.MGorgan: + { + + break; + } + case CraftResource.MSandrock: + { + + break; + } + case CraftResource.MSteel: + { + + break; + } + } + + double BonusStr = Math.Sqrt(from.Str); + double BonusSkills = Math.Sqrt(from.Skills[SkillName.ArmsLore].Value + from.Skills[SkillName.Blacksmith].Value); + int BonusVulcan = Math.Max(0,(int)from.FireResistance-from.ColdResistance/30); + double DurChance = (BonusStr + BonusSkills) * Math.Pow(DurScalar,2); + double DmgChance = (BonusStr + BonusSkills) * Math.Pow(DmgScalar, 2); + double AccChance = (Math.Sqrt(from.Dex) + BonusSkills) * Math.Pow(AccScalar, 2); + int DurRetry = (int)(Math.Min(1.08,DurScalar) * 100 - 100) + 2 + BonusVulcan; + int AccRetry = (int)(Math.Min(1.08, AccScalar) * 100 - 100) + 2 + BonusVulcan; + int DmgRetry = (int)(Math.Min(1.08, DmgScalar) * 100 - 100) + 2 + BonusVulcan; + int a = 0; + int b = 0; + int c = 0; + for ( int i = 0; i < DurRetry;) + { + if ((DurChance-a*3) > Utility.Random(100+(a*15))) + { + //Console.WriteLine("Dur : {0} sur {1} : {2} ", i, DurRetry, DurabilityLevel); + DurabilityLevel += 1; + a++; + } + else + i++; + + if (DurabilityLevel == WeaponDurabilityLevel.Indestructible) + break; + } + for (int f = 0; f < DmgRetry; ) + { + if ((DmgChance-b*3) > Utility.Random(100+(b*15))) + { + //Console.WriteLine("Dmg: {0} sur {1} : {2} ", f, DmgRetry, DamageLevel); + DamageLevel += 1; + b++; + } + else + f++; + + if (DamageLevel == WeaponDamageLevel.Vanq) + break; + } + for (int e = 0; e < AccRetry; ) + { + //Console.WriteLine("Accu: {0} sur {1} : {2} ", e, DmgRetry, AccuracyLevel); + if ((AccChance-c*3) > Utility.Random(100+ (c*15))) + { + AccuracyLevel += 1; + c++; + } + else + e++; + + if (AccuracyLevel == WeaponAccuracyLevel.Supremely) + break; + } + + } + else if ( tool is BaseRunicTool ) + { + CraftResource thisResource = CraftResources.GetFromType( resourceType ); + + if ( thisResource == ((BaseRunicTool)tool).Resource ) + { + Resource = thisResource; + + CraftContext context = craftSystem.GetContext( from ); + + if ( context != null && context.DoNotColor ) + Hue = 0; + + + + switch ( thisResource ) + { + case CraftResource.MBronze: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MGold: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MCopper: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MOldcopper: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MDullcopper: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MSilver: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MShadow: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MBloodrock: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MBlackrock: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MMytheril: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MRose: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MVerite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MAgapite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MRusty: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MValorite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MDragon: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MTitan: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MCrystaline: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MKrynite: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MVulcan: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MBloodcrest: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MElvin: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MAcid: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MAqua: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MEldar: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MGlowing: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MGorgan: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MSandrock: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + case CraftResource.MSteel: + { + Identified = true; + DurabilityLevel = WeaponDurabilityLevel.Regular; + DamageLevel = WeaponDamageLevel.Regular; + AccuracyLevel = WeaponAccuracyLevel.Regular; + break; + } + } + } + } + + #region Mondain's Legacy + + CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource); + + if (resInfo == null) + return quality; + + CraftAttributeInfo attrInfo = resInfo.AttributeInfo; + + if (attrInfo == null) + return quality; + + + m_AosAttributes.WeaponDamage += attrInfo.WeaponDamage; + m_AosAttributes.WeaponSpeed += attrInfo.WeaponSwingSpeed; + m_AosAttributes.AttackChance += attrInfo.WeaponHitChance; + m_AosAttributes.RegenHits += attrInfo.WeaponRegenHits; + m_AosWeaponAttributes.HitLeechHits += attrInfo.WeaponHitLifeLeech; + + + #endregion + + return quality; + } + + #endregion + } + + public enum CheckSlayerResult + { + None, + Slayer, + Opposition + } +} diff --git a/Scripts/Items/Weapons/Fists.cs b/Scripts/Items/Weapons/Fists.cs new file mode 100644 index 0000000..c75e2a9 --- /dev/null +++ b/Scripts/Items/Weapons/Fists.cs @@ -0,0 +1,312 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class Fists : BaseMeleeWeapon + { + public static void Initialize() + { + Mobile.DefaultWeapon = new Fists(); + + EventSink.DisarmRequest += new DisarmRequestEventHandler( EventSink_DisarmRequest ); + EventSink.StunRequest += new StunRequestEventHandler( EventSink_StunRequest ); + } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Disarm; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 0; } } + public override int AosMinDamage{ get{ return 1; } } + public override int AosMaxDamage{ get{ return 4; } } + public override int AosSpeed{ get{ return 50; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 0; } } + public override int OldMinDamage{ get{ return 1; } } + public override int OldMaxDamage{ get{ return 8; } } + public override int OldSpeed{ get{ return 30; } } + + public override int DefHitSound{ get{ return -1; } } + public override int DefMissSound{ get{ return -1; } } + + public override SkillName DefSkill{ get{ return SkillName.Wrestling; } } + public override WeaponType DefType{ get{ return WeaponType.Fists; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Wrestle; } } + + public Fists() : base( 0 ) + { + Visible = false; + Movable = false; + Quality = WeaponQuality.Regular; + } + + public Fists( Serial serial ) : base( serial ) + { + } + + public override double GetDefendSkillValue( Mobile attacker, Mobile defender ) + { + double wresValue = defender.Skills[SkillName.Wrestling].Value; + double anatValue = defender.Skills[SkillName.Anatomy].Value; + double evalValue = defender.Skills[SkillName.EvalInt].Value; + double incrValue = (anatValue + evalValue + 20.0) * 0.5; + + if ( incrValue > 120.0 ) + incrValue = 120.0; + + if ( wresValue > incrValue ) + return wresValue; + else + return incrValue; + } + + private void CheckPreAOSMoves( Mobile attacker, Mobile defender ) + { + if ( attacker.StunReady ) + { + if ( attacker.CanBeginAction( typeof( Fists ) ) ) + { + if ( attacker.Skills[SkillName.Anatomy].Value >= 80.0 && attacker.Skills[SkillName.Wrestling].Value >= 80.0 ) + { + if ( attacker.Stam >= 15 ) + { + attacker.Stam -= 15; + + if ( CheckMove( attacker, SkillName.Anatomy ) ) + { + StartMoveDelay( attacker ); + + attacker.StunReady = false; + + attacker.SendLocalizedMessage( 1004013 ); // You successfully stun your opponent! + defender.SendLocalizedMessage( 1004014 ); // You have been stunned! + + defender.Freeze( TimeSpan.FromSeconds( 4.0 ) ); + } + else + { + attacker.SendLocalizedMessage( 1004010 ); // You failed in your attempt to stun. + defender.SendLocalizedMessage( 1004011 ); // Your opponent tried to stun you and failed. + } + } + else + { + attacker.SendLocalizedMessage( 1004009 ); // You are too fatigued to attempt anything. + } + } + else + { + attacker.SendLocalizedMessage( 1004008 ); // You are not skilled enough to stun your opponent. + attacker.StunReady = false; + } + } + } + else if ( attacker.DisarmReady ) + { + if ( attacker.CanBeginAction( typeof( Fists ) ) ) + { + if ( defender.Player || defender.Body.IsHuman ) + { + if ( attacker.Skills[SkillName.ArmsLore].Value >= 80.0 && attacker.Skills[SkillName.Wrestling].Value >= 80.0 ) + { + if ( attacker.Stam >= 15 ) + { + Item toDisarm = defender.FindItemOnLayer( Layer.OneHanded ); + + if ( toDisarm == null || !toDisarm.Movable ) + toDisarm = defender.FindItemOnLayer( Layer.TwoHanded ); + + Container pack = defender.Backpack; + + if ( pack == null || toDisarm == null || !toDisarm.Movable ) + { + attacker.SendLocalizedMessage( 1004001 ); // You cannot disarm your opponent. + } + else if ( CheckMove( attacker, SkillName.ArmsLore ) ) + { + StartMoveDelay( attacker ); + + attacker.Stam -= 15; + attacker.DisarmReady = false; + + attacker.SendLocalizedMessage( 1004006 ); // You successfully disarm your opponent! + defender.SendLocalizedMessage( 1004007 ); // You have been disarmed! + + pack.DropItem( toDisarm ); + } + else + { + attacker.Stam -= 15; + + attacker.SendLocalizedMessage( 1004004 ); // You failed in your attempt to disarm. + defender.SendLocalizedMessage( 1004005 ); // Your opponent tried to disarm you but failed. + } + } + else + { + attacker.SendLocalizedMessage( 1004003 ); // You are too fatigued to attempt anything. + } + } + else + { + attacker.SendLocalizedMessage( 1004002 ); // You are not skilled enough to disarm your opponent. + attacker.DisarmReady = false; + } + } + else + { + attacker.SendLocalizedMessage( 1004001 ); // You cannot disarm your opponent. + } + } + } + } + + public override TimeSpan OnSwing(Mobile attacker, Mobile defender) + { + if (!Core.AOS) + CheckPreAOSMoves(attacker, defender); + + return base.OnSwing( attacker, defender ); + } + + /*public override void OnMiss( Mobile attacker, Mobile defender ) + { + base.PlaySwingAnimation( attacker ); + }*/ + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + + /* Wrestling moves */ + + private static bool CheckMove( Mobile m, SkillName other ) + { + double wresValue = m.Skills[SkillName.Wrestling].Value; + double scndValue = m.Skills[other].Value; + + /* 40% chance at 80, 80 + * 50% chance at 100, 100 + * 60% chance at 120, 120 + */ + + double chance = (wresValue + scndValue) / 400.0; + + return ( chance >= Utility.RandomDouble() ); + } + + private static bool HasFreeHands( Mobile m ) + { + Item item = m.FindItemOnLayer( Layer.OneHanded ); + + if ( item != null && !(item is Spellbook) ) + return false; + + return m.FindItemOnLayer( Layer.TwoHanded ) == null; + } + + private static void EventSink_DisarmRequest( DisarmRequestEventArgs e ) + { + if (Core.AOS) + return; + + Mobile m = e.Mobile; + + #region Dueling + if (!Engines.ConPVP.DuelContext.AllowSpecialAbility(m, "Disarm", true)) + return; + #endregion + + double armsValue = m.Skills[SkillName.ArmsLore].Value; + double wresValue = m.Skills[SkillName.Wrestling].Value; + + if ( !HasFreeHands( m ) ) + { + m.SendLocalizedMessage( 1004029 ); // You must have your hands free to attempt to disarm your opponent. + m.DisarmReady = false; + } + else if ( armsValue >= 80.0 && wresValue >= 80.0 ) + { + m.DisruptiveAction(); + m.DisarmReady = !m.DisarmReady; + m.SendLocalizedMessage( m.DisarmReady ? 1019013 : 1019014 ); + } + else + { + m.SendLocalizedMessage( 1004002 ); // You are not skilled enough to disarm your opponent. + m.DisarmReady = false; + } + } + + private static void EventSink_StunRequest( StunRequestEventArgs e ) + { + if (Core.AOS) + return; + + Mobile m = e.Mobile; + + #region Dueling + if (!Engines.ConPVP.DuelContext.AllowSpecialAbility(m, "Stun", true)) + return; + #endregion + + double anatValue = m.Skills[SkillName.Anatomy].Value; + double wresValue = m.Skills[SkillName.Wrestling].Value; + + if ( !HasFreeHands( m ) ) + { + m.SendLocalizedMessage( 1004031 ); // You must have your hands free to attempt to stun your opponent. + m.StunReady = false; + } + else if ( anatValue >= 80.0 && wresValue >= 80.0 ) + { + m.DisruptiveAction(); + m.StunReady = !m.StunReady; + m.SendLocalizedMessage( m.StunReady ? 1019011 : 1019012 ); + } + else + { + m.SendLocalizedMessage( 1004008 ); // You are not skilled enough to stun your opponent. + m.StunReady = false; + } + } + + private class MoveDelayTimer : Timer + { + private Mobile m_Mobile; + + public MoveDelayTimer( Mobile m ) : base( TimeSpan.FromSeconds( 10.0 ) ) + { + m_Mobile = m; + + Priority = TimerPriority.TwoFiftyMS; + + m_Mobile.BeginAction( typeof( Fists ) ); + } + + protected override void OnTick() + { + m_Mobile.EndAction( typeof( Fists ) ); + } + } + + private static void StartMoveDelay( Mobile m ) + { + new MoveDelayTimer( m ).Start(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/HitLower.cs b/Scripts/Items/Weapons/HitLower.cs new file mode 100644 index 0000000..0a3da23 --- /dev/null +++ b/Scripts/Items/Weapons/HitLower.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Items +{ + public class HitLower + { + public static readonly TimeSpan AttackEffectDuration = TimeSpan.FromSeconds( 10.0 ); + public static readonly TimeSpan DefenseEffectDuration = TimeSpan.FromSeconds( 8.0 ); + + private static Hashtable m_AttackTable = new Hashtable(); + + public static bool IsUnderAttackEffect( Mobile m ) + { + return m_AttackTable.Contains( m ); + } + + public static bool ApplyAttack( Mobile m ) + { + if ( IsUnderAttackEffect( m ) ) + return false; + + m_AttackTable[m] = new AttackTimer( m ); + m.SendLocalizedMessage( 1062319 ); // Your attack chance has been reduced! + return true; + } + + private static void RemoveAttack( Mobile m ) + { + m_AttackTable.Remove( m ); + m.SendLocalizedMessage( 1062320 ); // Your attack chance has returned to normal. + } + + private class AttackTimer : Timer + { + private Mobile m_Player; + + public AttackTimer( Mobile player ) : base( AttackEffectDuration ) + { + m_Player = player; + + Priority = TimerPriority.TwoFiftyMS; + + Start(); + } + + protected override void OnTick() + { + RemoveAttack( m_Player ); + } + } + + private static Hashtable m_DefenseTable = new Hashtable(); + + public static bool IsUnderDefenseEffect( Mobile m ) + { + return m_DefenseTable.Contains( m ); + } + + public static bool ApplyDefense( Mobile m ) + { + if ( IsUnderDefenseEffect( m ) ) + return false; + + m_DefenseTable[m] = new DefenseTimer( m ); + m.SendLocalizedMessage( 1062318 ); // Your defense chance has been reduced! + return true; + } + + private static void RemoveDefense( Mobile m ) + { + m_DefenseTable.Remove( m ); + m.SendLocalizedMessage( 1062321 ); // Your defense chance has returned to normal. + } + + private class DefenseTimer : Timer + { + private Mobile m_Player; + + public DefenseTimer( Mobile player ) : base( DefenseEffectDuration ) + { + m_Player = player; + + Priority = TimerPriority.TwoFiftyMS; + + Start(); + } + + protected override void OnTick() + { + RemoveDefense( m_Player ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Knives/BaseKnife.cs b/Scripts/Items/Weapons/Knives/BaseKnife.cs new file mode 100644 index 0000000..2ef1982 --- /dev/null +++ b/Scripts/Items/Weapons/Knives/BaseKnife.cs @@ -0,0 +1,66 @@ +using System; +using Server; +using Server.Items; +using Server.Targets; + +namespace Server.Items +{ + public abstract class BaseKnife : BaseMeleeWeapon + { + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override SkillName DefSkill{ get{ return SkillName.Swords; } } + public override WeaponType DefType{ get{ return WeaponType.Slashing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } } + + public BaseKnife( int itemID ) : base( itemID ) + { + } + + public BaseKnife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + // Scriptiz : gestion du double clic pour �quipper un objet + if (from.FindItemOnLayer(this.Layer) != this) + { + base.OnDoubleClick(from); + return; + } + + from.SendLocalizedMessage(1010018); // What do you want to use this item on? + + from.Target = new BladedItemTarget(this); + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + if ( !Core.AOS && Poison != null && PoisonCharges > 0 ) + { + --PoisonCharges; + + if ( Utility.RandomDouble() >= 0.5 ) // 50% chance to poison + defender.ApplyPoison( attacker, Poison ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Knives/ButcherKnife.cs b/Scripts/Items/Weapons/Knives/ButcherKnife.cs new file mode 100644 index 0000000..8682916 --- /dev/null +++ b/Scripts/Items/Weapons/Knives/ButcherKnife.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13F6, 0x13F7 )] + public class ButcherKnife : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 5; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 49; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 5; } } + public override int OldMinDamage{ get{ return 2; } } + public override int OldMaxDamage{ get{ return 14; } } + public override int OldSpeed{ get{ return 40; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 40; } } + + [Constructable] + public ButcherKnife() : base( 0x13F6 ) + { + Weight = 1.0; + } + + public ButcherKnife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Knives/Cleaver.cs b/Scripts/Items/Weapons/Knives/Cleaver.cs new file mode 100644 index 0000000..5117409 --- /dev/null +++ b/Scripts/Items/Weapons/Knives/Cleaver.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xEC3, 0xEC2 )] + public class Cleaver : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + + public override int AosStrengthReq{ get{ return 10; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 46; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 2; } } + public override int OldMaxDamage{ get{ return 13; } } + public override int OldSpeed{ get{ return 40; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 50; } } + + [Constructable] + public Cleaver() : base( 0xEC3 ) + { + Weight = 2.0; + } + + public Cleaver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Knives/Dagger.cs b/Scripts/Items/Weapons/Knives/Dagger.cs new file mode 100644 index 0000000..9481818 --- /dev/null +++ b/Scripts/Items/Weapons/Knives/Dagger.cs @@ -0,0 +1,56 @@ +using System; +using Server.Network; +using Server.Targeting; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF52, 0xF51 )] + public class Dagger : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + + public override int AosStrengthReq{ get{ return 10; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 56; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 1; } } + public override int OldMinDamage{ get{ return 3; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 55; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 40; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Dagger() : base( 0xF52 ) + { + Weight = 1.0; + } + + public Dagger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Knives/SkinningKnife.cs b/Scripts/Items/Weapons/Knives/SkinningKnife.cs new file mode 100644 index 0000000..f254a1d --- /dev/null +++ b/Scripts/Items/Weapons/Knives/SkinningKnife.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xEC4, 0xEC5 )] + public class SkinningKnife : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 5; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 49; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 5; } } + public override int OldMinDamage{ get{ return 1; } } + public override int OldMaxDamage{ get{ return 10; } } + public override int OldSpeed{ get{ return 40; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 40; } } + + [Constructable] + public SkinningKnife() : base( 0xEC4 ) + { + Weight = 1.0; + } + + public SkinningKnife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs new file mode 100644 index 0000000..1f1bb29 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/BlightGrippedLongbow.cs @@ -0,0 +1,40 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class BlightGrippedLongbow : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1072907; } } // Blight Gripped Longbow + + [Constructable] + public BlightGrippedLongbow() + { + Hue = 0x8A4; + + WeaponAttributes.HitPoisonArea = 20; + Attributes.RegenStam = 3; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 35; + } + + public BlightGrippedLongbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs new file mode 100644 index 0000000..549da2c --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/ColdForgedBlade.cs @@ -0,0 +1,47 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class ColdForgedBlade : ElvenSpellblade + { + public override int LabelNumber{ get{ return 1072916; } } // Cold Forged Blade + + [Constructable] + public ColdForgedBlade() + { + WeaponAttributes.HitHarm = 40; + Attributes.SpellChanneling = 1; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 50; + + Hue = this.GetElementalDamageHue(); + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = pois = nrgy = chaos = direct = 0; + cold = 100; + } + + public ColdForgedBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs new file mode 100644 index 0000000..32188bd --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/LuminousRuneBlade.cs @@ -0,0 +1,47 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class LuminousRuneBlade : RuneBlade + { + public override int LabelNumber{ get{ return 1072922; } } // Luminous Rune Blade + + [Constructable] + public LuminousRuneBlade() + { + WeaponAttributes.HitLightning = 40; + WeaponAttributes.SelfRepair = 5; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 55; + + Hue = this.GetElementalDamageHue(); + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public LuminousRuneBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs new file mode 100644 index 0000000..bac6969 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/OverseerSunderedBlade.cs @@ -0,0 +1,49 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class OverseerSunderedBlade : RadiantScimitar + { + public override int LabelNumber{ get{ return 1072920; } } // Overseer Sundered Blade + + [Constructable] + public OverseerSunderedBlade() + { + ItemID = 0x2D27; + Hue = 0x485; + + Attributes.RegenStam = 2; + Attributes.AttackChance = 10; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 45; + + Hue = this.GetElementalDamageHue(); + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = cold = pois = nrgy = chaos = direct = 0; + fire = 100; + } + + public OverseerSunderedBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs new file mode 100644 index 0000000..458bbe8 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/PhantomStaff.cs @@ -0,0 +1,45 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class PhantomStaff : WildStaff + { + public override int LabelNumber{ get{ return 1072919; } } // Phantom Staff + + [Constructable] + public PhantomStaff() + { + Hue = 0x1; + Attributes.RegenHits = 2; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 20; + Attributes.WeaponDamage = 60; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = nrgy = chaos = direct = 0; + cold = pois = 50; + } + + public PhantomStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs new file mode 100644 index 0000000..debb516 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/RuneCarvingKnife.cs @@ -0,0 +1,41 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class RuneCarvingKnife : AssassinSpike + { + public override int LabelNumber{ get{ return 1072915; } } // Rune Carving Knife + + [Constructable] + public RuneCarvingKnife() + { + Hue = 0x48D; + + WeaponAttributes.HitLeechMana = 40; + Attributes.RegenStam = 2; + Attributes.LowerManaCost = 10; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 30; + } + + public RuneCarvingKnife( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs new file mode 100644 index 0000000..f5c6e22 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/ShardTrasher.cs @@ -0,0 +1,41 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class ShardThrasher : DiamondMace + { + public override int LabelNumber{ get{ return 1072918; } } // Shard Thrasher + + [Constructable] + public ShardThrasher() + { + Hue = 0x4F2; + + WeaponAttributes.HitPhysicalArea = 30; + Attributes.BonusStam = 8; + Attributes.AttackChance = 10; + Attributes.WeaponSpeed = 35; + Attributes.WeaponDamage = 40; + } + + public ShardThrasher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs new file mode 100644 index 0000000..63904f4 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/SilvanisFeywoodBow.cs @@ -0,0 +1,46 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class SilvanisFeywoodBow : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1072955; } } // Silvani's Feywood Bow + + [Constructable] + public SilvanisFeywoodBow() + { + Hue = 0x1A; + + Attributes.SpellChanneling = 1; + Attributes.AttackChance = 12; + Attributes.WeaponSpeed = 30; + Attributes.WeaponDamage = 35; + } + + public override void GetDamageTypes( Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct ) + { + phys = fire = cold = pois = chaos = direct = 0; + nrgy = 100; + } + + public SilvanisFeywoodBow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs b/Scripts/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs new file mode 100644 index 0000000..3116baa --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Artifacts/TheNightReaper.cs @@ -0,0 +1,41 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class TheNightReaper : RepeatingCrossbow + { + public override int LabelNumber{ get{ return 1072912; } } // The Night Reaper + + [Constructable] + public TheNightReaper() + { + ItemID = 0x26CD; + Hue = 0x41C; + + Slayer = SlayerName.Exorcism; + Attributes.NightSight = 1; + Attributes.WeaponSpeed = 25; + Attributes.WeaponDamage = 55; + } + + public TheNightReaper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/AssassinSpike.cs b/Scripts/Items/Weapons/ML Weapons/AssassinSpike.cs new file mode 100644 index 0000000..d267216 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/AssassinSpike.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D21, 0x2D2D )] + public class AssassinSpike : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 12; } } + public override int AosSpeed{ get{ return 50; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 12; } } + public override int OldSpeed{ get{ return 50; } } + + public override int DefMissSound{ get{ return 0x239; } } + public override SkillName DefSkill { get { return SkillName.Fencing; } } + + public override int InitMinHits{ get{ return 30; } } // TODO + public override int InitMaxHits{ get{ return 60; } } // TODO + + [Constructable] + public AssassinSpike() : base( 0x2D21 ) + { + Weight = 4.0; + } + + public AssassinSpike( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/ButchersWarCleaver.cs b/Scripts/Items/Weapons/ML Weapons/ButchersWarCleaver.cs new file mode 100644 index 0000000..54957aa --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/ButchersWarCleaver.cs @@ -0,0 +1,42 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ButchersWarCleaver : WarCleaver + { + public override int LabelNumber { get { return 1073526; } } // butcher's war cleaver + + [Constructable] + public ButchersWarCleaver() + : base() + { + } + + public ButchersWarCleaver(Serial serial) + : base(serial) + { + } + + public override void AppendChildNameProperties(ObjectPropertyList list) + { + base.AppendChildNameProperties(list); + + list.Add(1072512); // Bovine Slayer + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/DiamondMace.cs b/Scripts/Items/Weapons/ML Weapons/DiamondMace.cs new file mode 100644 index 0000000..4f70ac7 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/DiamondMace.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D24, 0x2D30 )] + public class DiamondMace : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 37; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 14; } } + public override int OldMaxDamage{ get{ return 17; } } + public override int OldSpeed{ get{ return 37; } } + + public override int InitMinHits{ get{ return 30; } } // TODO + public override int InitMaxHits{ get{ return 60; } } // TODO + + [Constructable] + public DiamondMace() : base( 0x2D24 ) + { + Weight = 10.0; + } + + public DiamondMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs b/Scripts/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs new file mode 100644 index 0000000..621cb33 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/ElvenCompositeLongbow.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D1E, 0x2D2A )] + public class ElvenCompositeLongbow : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ForceArrow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.SerpentArrow; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 27; } } + public override float MlSpeed{ get{ return 4.00f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 12; } } + public override int OldMaxDamage{ get{ return 16; } } + public override int OldSpeed{ get{ return 27; } } + + public override int DefMaxRange{ get{ return 10; } } + + public override int InitMinHits{ get{ return 41; } } + public override int InitMaxHits{ get{ return 90; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } } + + [Constructable] + public ElvenCompositeLongbow() : base( 0x2D1E ) + { + Weight = 8.0; + } + + public ElvenCompositeLongbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/ElvenMachete.cs b/Scripts/Items/Weapons/ML Weapons/ElvenMachete.cs new file mode 100644 index 0000000..991709a --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/ElvenMachete.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D35, 0x2D29 )] + public class ElvenMachete : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DefenseMastery; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Bladeweave; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 41; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 13; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 41; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public ElvenMachete() : base( 0x2D35 ) + { + Weight = 6.0; + } + + public ElvenMachete( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/ElvenSpellblade.cs b/Scripts/Items/Weapons/ML Weapons/ElvenSpellblade.cs new file mode 100644 index 0000000..7464476 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/ElvenSpellblade.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D20, 0x2D2C )] + public class ElvenSpellblade : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.PsychicAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.BleedAttack; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 44; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 12; } } + public override int OldMaxDamage{ get{ return 14; } } + public override int OldSpeed{ get{ return 44; } } + + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } // TODO + public override int InitMaxHits{ get{ return 60; } } // TODO + + [Constructable] + public ElvenSpellblade() : base( 0x2D20 ) + { + Weight = 5.0; + Layer = Layer.TwoHanded; + } + + public ElvenSpellblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/Leafblade.cs b/Scripts/Items/Weapons/ML Weapons/Leafblade.cs new file mode 100644 index 0000000..e8c59df --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/Leafblade.cs @@ -0,0 +1,53 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D22, 0x2D2E )] + public class Leafblade : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Feint; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 42; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 13; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 42; } } + + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } // TODO + public override int InitMaxHits{ get{ return 60; } } // TODO + + [Constructable] + public Leafblade() : base( 0x2D22 ) + { + Weight = 8.0; + } + + public Leafblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/MagicalShortbow.cs b/Scripts/Items/Weapons/ML Weapons/MagicalShortbow.cs new file mode 100644 index 0000000..119775d --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/MagicalShortbow.cs @@ -0,0 +1,57 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D2B, 0x2D1F )] + public class MagicalShortbow : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.LightningArrow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.PsychicAttack; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 38; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 13; } } + public override int OldSpeed{ get{ return 38; } } + + public override int DefMaxRange{ get{ return 10; } } + + public override int InitMinHits{ get{ return 41; } } + public override int InitMaxHits{ get{ return 90; } } + + [Constructable] + public MagicalShortbow() : base( 0x2D2B ) + { + Weight = 6.0; + } + + public MagicalShortbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/OrnateAxe.cs b/Scripts/Items/Weapons/ML Weapons/OrnateAxe.cs new file mode 100644 index 0000000..343d2d3 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/OrnateAxe.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D28, 0x2D34 )] + public class OrnateAxe : BaseAxe + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Disarm; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 18; } } + public override int AosMaxDamage{ get{ return 20; } } + public override int AosSpeed{ get{ return 26; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 18; } } + public override int OldMaxDamage{ get{ return 20; } } + public override int OldSpeed{ get{ return 26; } } + + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public OrnateAxe() : base( 0x2D28 ) + { + Weight = 12.0; + Layer = Layer.TwoHanded; + } + + public OrnateAxe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/RadiantScimitar.cs b/Scripts/Items/Weapons/ML Weapons/RadiantScimitar.cs new file mode 100644 index 0000000..f1d10aa --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/RadiantScimitar.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D33, 0x2D27 )] + public class RadiantScimitar : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Bladeweave; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 43; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 12; } } + public override int OldMaxDamage{ get{ return 14; } } + public override int OldSpeed{ get{ return 43; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public RadiantScimitar() : base( 0x2D33 ) + { + Weight = 9.0; + } + + public RadiantScimitar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/RuneBlade.cs b/Scripts/Items/Weapons/ML Weapons/RuneBlade.cs new file mode 100644 index 0000000..43e942b --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/RuneBlade.cs @@ -0,0 +1,55 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D32, 0x2D26 )] + public class RuneBlade : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Disarm; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Bladeweave; } } + + public override int AosStrengthReq{ get{ return 30; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 35; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 15; } } + public override int OldMaxDamage{ get{ return 17; } } + public override int OldSpeed{ get{ return 35; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public RuneBlade() : base( 0x2D32 ) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public RuneBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/WarCleaver.cs b/Scripts/Items/Weapons/ML Weapons/WarCleaver.cs new file mode 100644 index 0000000..b0fcc26 --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/WarCleaver.cs @@ -0,0 +1,58 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D2F, 0x2D23 )] + public class WarCleaver : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Disarm; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Bladeweave; } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 48; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 11; } } + public override int OldSpeed{ get{ return 48; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 30; } } // TODO + public override int InitMaxHits{ get{ return 60; } } // TODO + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public WarCleaver() : base( 0x2D2F ) + { + Weight = 10.0; + } + + public WarCleaver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/ML Weapons/WildStaff.cs b/Scripts/Items/Weapons/ML Weapons/WildStaff.cs new file mode 100644 index 0000000..61a712a --- /dev/null +++ b/Scripts/Items/Weapons/ML Weapons/WildStaff.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x2D25, 0x2D31 )] + public class WildStaff : BaseStaff + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Block; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ForceOfNature; } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 12; } } + public override int AosSpeed{ get{ return 48; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 12; } } + public override int OldSpeed{ get{ return 48; } } + + public override int InitMinHits{ get{ return 30; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public WildStaff() : base( 0x2D25 ) + { + Weight = 8.0; + } + + public WildStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/BaseBashing.cs b/Scripts/Items/Weapons/Maces/BaseBashing.cs new file mode 100644 index 0000000..b7e9b49 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/BaseBashing.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public abstract class BaseBashing : BaseMeleeWeapon + { + public override int DefHitSound{ get{ return 0x233; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override SkillName DefSkill{ get{ return SkillName.Macing; } } + public override WeaponType DefType{ get{ return WeaponType.Bashing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Bash1H; } } + + public BaseBashing( int itemID ) : base( itemID ) + { + } + + public BaseBashing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + defender.Stam -= Utility.Random( 3, 3 ); // 3-5 points of stamina loss + } + + public override double GetBaseDamage( Mobile attacker ) + { + double damage = base.GetBaseDamage( attacker ); + + if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && (attacker.Skills[SkillName.Anatomy].Value / 400.0) >= Utility.RandomDouble() && Engines.ConPVP.DuelContext.AllowSpecialAbility(attacker, "Crushing Blow", false)) + { + damage *= 1.5; + + attacker.SendMessage( "You deliver a crushing blow!" ); // Is this not localized? + attacker.PlaySound( 0x11C ); + } + + return damage; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/Club.cs b/Scripts/Items/Weapons/Maces/Club.cs new file mode 100644 index 0000000..0e4d038 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/Club.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13b4, 0x13b3 )] + public class Club : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Dismount; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 44; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 24; } } + public override int OldSpeed{ get{ return 40; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 40; } } + + [Constructable] + public Club() : base( 0x13B4 ) + { + Weight = 9.0; + } + + public Club( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/EmeraldMace.cs b/Scripts/Items/Weapons/Maces/EmeraldMace.cs new file mode 100644 index 0000000..bf941bc --- /dev/null +++ b/Scripts/Items/Weapons/Maces/EmeraldMace.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class EmeraldMace : DiamondMace + { + public override int LabelNumber{ get{ return 1073530; } } // emerald mace + + [Constructable] + public EmeraldMace() + { + WeaponAttributes.ResistPoisonBonus = 5; + } + + public EmeraldMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Maces/FireworksWand.cs b/Scripts/Items/Weapons/Maces/FireworksWand.cs new file mode 100644 index 0000000..eaee430 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/FireworksWand.cs @@ -0,0 +1,138 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class FireworksWand : MagicWand + { + public override int LabelNumber{ get{ return 1041424; } } // a fireworks wand + + private int m_Charges; + + [CommandProperty( AccessLevel.GameMaster )] + public int Charges + { + get{ return m_Charges; } + set{ m_Charges = value; InvalidateProperties(); } + } + + [Constructable] + public FireworksWand() : this( 100 ) + { + } + + [Constructable] + public FireworksWand( int charges ) + { + m_Charges = charges; + LootType = LootType.Blessed; + } + + public FireworksWand( Serial serial ) : base( serial ) + { + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1060741, m_Charges.ToString() ); // charges: ~1_val~ + } + + public override void OnDoubleClick( Mobile from ) + { + BeginLaunch( from, true ); + } + + public void BeginLaunch( Mobile from, bool useCharges ) + { + Map map = from.Map; + + if ( map == null || map == Map.Internal ) + return; + + if ( useCharges ) + { + if ( Charges > 0 ) + { + --Charges; + } + else + { + from.SendLocalizedMessage( 502412 ); // There are no charges left on that item. + return; + } + } + + from.SendLocalizedMessage( 502615 ); // You launch a firework! + + Point3D ourLoc = GetWorldLocation(); + + Point3D startLoc = new Point3D( ourLoc.X, ourLoc.Y, ourLoc.Z + 10 ); + Point3D endLoc = new Point3D( startLoc.X + Utility.RandomMinMax( -2, 2 ), startLoc.Y + Utility.RandomMinMax( -2, 2 ), startLoc.Z + 32 ); + + Effects.SendMovingEffect( new Entity( Serial.Zero, startLoc, map ), new Entity( Serial.Zero, endLoc, map ), + 0x36E4, 5, 0, false, false ); + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( FinishLaunch ), new object[]{ from, endLoc, map } ); + } + + private void FinishLaunch( object state ) + { + object[] states = (object[])state; + + Mobile from = (Mobile)states[0]; + Point3D endLoc = (Point3D)states[1]; + Map map = (Map)states[2]; + + int hue = Utility.Random( 40 ); + + if ( hue < 8 ) + hue = 0x66D; + else if ( hue < 10 ) + hue = 0x482; + else if ( hue < 12 ) + hue = 0x47E; + else if ( hue < 16 ) + hue = 0x480; + else if ( hue < 20 ) + hue = 0x47F; + else + hue = 0; + + if ( Utility.RandomBool() ) + hue = Utility.RandomList( 0x47E, 0x47F, 0x480, 0x482, 0x66D ); + + int renderMode = Utility.RandomList( 0, 2, 3, 4, 5, 7 ); + + Effects.PlaySound( endLoc, map, Utility.Random( 0x11B, 4 ) ); + Effects.SendLocationEffect( endLoc, map, 0x373A + (0x10 * Utility.Random( 4 )), 16, 10, hue, renderMode ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Charges ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Charges = reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/HammerPick.cs b/Scripts/Items/Weapons/Maces/HammerPick.cs new file mode 100644 index 0000000..51ab148 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/HammerPick.cs @@ -0,0 +1,52 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x143D, 0x143C )] + public class HammerPick : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 28; } } + public override float MlSpeed{ get{ return 3.75f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public HammerPick() : base( 0x143D ) + { + Weight = 9.0; + Layer = Layer.OneHanded; + } + + public HammerPick( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/Mace.cs b/Scripts/Items/Weapons/Maces/Mace.cs new file mode 100644 index 0000000..9b0a27f --- /dev/null +++ b/Scripts/Items/Weapons/Maces/Mace.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF5C, 0xF5D )] + public class Mace : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 40; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 32; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public Mace() : base( 0xF5C ) + { + Weight = 14.0; + } + + public Mace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/MagicWand.cs b/Scripts/Items/Weapons/Maces/MagicWand.cs new file mode 100644 index 0000000..387bf46 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/MagicWand.cs @@ -0,0 +1,50 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class MagicWand : BaseBashing + { + public override WeaponAbility PrimaryAbility { get { return WeaponAbility.Dismount; } } + public override WeaponAbility SecondaryAbility { get { return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 5; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 40; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 0; } } + public override int OldMinDamage{ get{ return 2; } } + public override int OldMaxDamage{ get{ return 6; } } + public override int OldSpeed{ get{ return 35; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public MagicWand() : base( 0xDF2 ) + { + Weight = 1.0; + } + + public MagicWand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/Maul.cs b/Scripts/Items/Weapons/Maces/Maul.cs new file mode 100644 index 0000000..08f6292 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/Maul.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x143B, 0x143A )] + public class Maul : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 32; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 30; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public Maul() : base( 0x143B ) + { + Weight = 10.0; + } + + public Maul( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 14.0 ) + Weight = 10.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/RubyMace.cs b/Scripts/Items/Weapons/Maces/RubyMace.cs new file mode 100644 index 0000000..1910fe9 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/RubyMace.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class RubyMace : DiamondMace + { + public override int LabelNumber{ get{ return 1073529; } } // ruby mace + + [Constructable] + public RubyMace() + { + Attributes.WeaponDamage = 5; + } + + public RubyMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Maces/SapphireMace.cs b/Scripts/Items/Weapons/Maces/SapphireMace.cs new file mode 100644 index 0000000..5415c2f --- /dev/null +++ b/Scripts/Items/Weapons/Maces/SapphireMace.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SapphireMace : DiamondMace + { + public override int LabelNumber{ get{ return 1073531; } } // sapphire mace + + [Constructable] + public SapphireMace() + { + WeaponAttributes.ResistEnergyBonus = 5; + } + + public SapphireMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Maces/Scepter.cs b/Scripts/Items/Weapons/Maces/Scepter.cs new file mode 100644 index 0000000..e1aa764 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/Scepter.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26BC, 0x26C6 )] + public class Scepter : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 30; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 14; } } + public override int OldMaxDamage{ get{ return 17; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public Scepter() : base( 0x26BC ) + { + Weight = 8.0; + } + + public Scepter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/SilverEtchedMace.cs b/Scripts/Items/Weapons/Maces/SilverEtchedMace.cs new file mode 100644 index 0000000..9da7875 --- /dev/null +++ b/Scripts/Items/Weapons/Maces/SilverEtchedMace.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SilverEtchedMace : DiamondMace + { + public override int LabelNumber { get { return 1073532; } } // silver-etched mace + + [Constructable] + public SilverEtchedMace() + { + Slayer = SlayerName.Exorcism; + } + + public SilverEtchedMace(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Maces/WarHammer.cs b/Scripts/Items/Weapons/Maces/WarHammer.cs new file mode 100644 index 0000000..a926cbe --- /dev/null +++ b/Scripts/Items/Weapons/Maces/WarHammer.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1439, 0x1438 )] + public class WarHammer : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + + public override int AosStrengthReq{ get{ return 95; } } + public override int AosMinDamage{ get{ return 17; } } + public override int AosMaxDamage{ get{ return 18; } } + public override int AosSpeed{ get{ return 28; } } + public override float MlSpeed{ get{ return 3.75f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 36; } } + public override int OldSpeed{ get{ return 31; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Bash2H; } } + + [Constructable] + public WarHammer() : base( 0x1439 ) + { + Weight = 10.0; + Layer = Layer.TwoHanded; + } + + public WarHammer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Maces/WarMace.cs b/Scripts/Items/Weapons/Maces/WarMace.cs new file mode 100644 index 0000000..8c0368d --- /dev/null +++ b/Scripts/Items/Weapons/Maces/WarMace.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1407, 0x1406 )] + public class WarMace : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 80; } } + public override int AosMinDamage{ get{ return 16; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 26; } } + public override float MlSpeed{ get{ return 4.00f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 30; } } + public override int OldSpeed{ get{ return 32; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public WarMace() : base( 0x1407 ) + { + Weight = 17.0; + } + + public WarMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/PoleArms/Bardiche.cs b/Scripts/Items/Weapons/PoleArms/Bardiche.cs new file mode 100644 index 0000000..3f8ea2d --- /dev/null +++ b/Scripts/Items/Weapons/PoleArms/Bardiche.cs @@ -0,0 +1,75 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF4D, 0xF4E )] + public class Bardiche : BasePoleArm + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Dismount; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 17; } } + public override int AosMaxDamage{ get{ return 18; } } + public override int AosSpeed{ get{ return 28; } } + public override float MlSpeed{ get{ return 3.75f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 43; } } + public override int OldSpeed{ get{ return 26; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 100; } } + + [Constructable] + public Bardiche() : base( 0xF4D ) + { + Weight = 7.0; + } + + public Bardiche( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + /*** ADDED ***/ + // ALAMBIK + // Modification implementation of mounted chivalry + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus) + { + Skill skill = attacker.Skills[SkillName.Chivalry]; + if (attacker.Mounted // attaquant sur un cheval + && !(defender.Mounted) // d�fenseur pas sur un cheval + && ((attacker.Direction & Direction.Running) != 0) // cours + && (skill != null && (Utility.Random(120) <= ((int)(skill.Value) + 10))) + && attacker.CheckTargetSkill(SkillName.Chivalry, defender, 0.0, 120.0) + ) + { + attacker.SendMessage("Votre attaque mont�e disloque votre adversaire!"); + defender.PlaySound(1308); + base.OnHit(attacker, defender, 1.20); // bonus 1/5 au lieu de 1/4 + } + else + { + base.OnHit(attacker, defender, 1.0); + } + } + /*** END ***/ + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/PoleArms/BasePoleArm.cs b/Scripts/Items/Weapons/PoleArms/BasePoleArm.cs new file mode 100644 index 0000000..f1688a3 --- /dev/null +++ b/Scripts/Items/Weapons/PoleArms/BasePoleArm.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Engines.Harvest; +using Server.ContextMenus; + +namespace Server.Items +{ + public abstract class BasePoleArm : BaseMeleeWeapon, IUsesRemaining + { + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override SkillName DefSkill{ get{ return SkillName.Swords; } } + public override WeaponType DefType{ get{ return WeaponType.Polearm; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash2H; } } + + public virtual HarvestSystem HarvestSystem{ get{ return Lumberjacking.System; } } + + private int m_UsesRemaining; + private bool m_ShowUsesRemaining; + + [CommandProperty( AccessLevel.GameMaster )] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ShowUsesRemaining + { + get { return m_ShowUsesRemaining; } + set { m_ShowUsesRemaining = value; InvalidateProperties(); } + } + + public BasePoleArm( int itemID ) : base( itemID ) + { + m_UsesRemaining = 150; + } + + public BasePoleArm( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick(Mobile from) + { + // Scriptiz : gestion du double clic pour �quipper un objet + if (from.FindItemOnLayer(this.Layer) != this) + { + base.OnDoubleClick(from); + return; + } + + if (HarvestSystem == null) + return; + + if (IsChildOf(from.Backpack) || Parent == from) + HarvestSystem.BeginHarvesting(from, this); + else + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( HarvestSystem != null ) + BaseHarvestTool.AddContextMenuEntries( from, this, list, HarvestSystem ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( (bool) m_ShowUsesRemaining ); + + writer.Write( (int) m_UsesRemaining ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_ShowUsesRemaining = reader.ReadBool(); + goto case 1; + } + case 1: + { + m_UsesRemaining = reader.ReadInt(); + goto case 0; + } + case 0: + { + if ( m_UsesRemaining < 1 ) + m_UsesRemaining = 150; + + break; + } + } + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + if (!Core.AOS && (attacker.Player || attacker.Body.IsHuman) && Layer == Layer.TwoHanded && (attacker.Skills[SkillName.Anatomy].Value / 400.0) >= Utility.RandomDouble() && Engines.ConPVP.DuelContext.AllowSpecialAbility(attacker, "Concussion Blow", false)) + { + StatMod mod = defender.GetStatMod( "Concussion" ); + + if ( mod == null ) + { + defender.SendMessage( "You receive a concussion blow!" ); + defender.AddStatMod( new StatMod( StatType.Int, "Concussion", -(defender.RawInt / 2), TimeSpan.FromSeconds( 30.0 ) ) ); + + attacker.SendMessage( "You deliver a concussion blow!" ); + attacker.PlaySound( 0x11C ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/PoleArms/Halberd.cs b/Scripts/Items/Weapons/PoleArms/Halberd.cs new file mode 100644 index 0000000..b8d0228 --- /dev/null +++ b/Scripts/Items/Weapons/PoleArms/Halberd.cs @@ -0,0 +1,75 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x143E, 0x143F )] + public class Halberd : BasePoleArm + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + + public override int AosStrengthReq{ get{ return 95; } } + public override int AosMinDamage{ get{ return 18; } } + public override int AosMaxDamage{ get{ return 19; } } + public override int AosSpeed{ get{ return 25; } } + public override float MlSpeed{ get{ return 4.25f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 49; } } + public override int OldSpeed{ get{ return 25; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public Halberd() : base( 0x143E ) + { + Weight = 16.0; + } + + public Halberd( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + /*** ADDED ***/ + // ALAMBIK + // Modification implementation of mounted chivalry + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus) + { + Skill skill = attacker.Skills[SkillName.Chivalry]; + if (attacker.Mounted // attaquant sur un cheval + && !(defender.Mounted) // d�fenseur pas sur un cheval + && ((attacker.Direction & Direction.Running) != 0) // cours + && (skill != null && (Utility.Random(120) <= ((int)(skill.Value) + 10))) + && attacker.CheckTargetSkill(SkillName.Chivalry, defender, 0.0, 120.0) + ) + { + attacker.SendMessage("Votre attaque mont�e disloque votre adversaire!"); + defender.PlaySound(1308); + base.OnHit(attacker, defender, 1.20); // bonus 1/5 au lieu de 1/4 + } + else + { + base.OnHit(attacker, defender, 1.0); + } + } + /*** END ***/ + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/PoleArms/Scythe.cs b/Scripts/Items/Weapons/PoleArms/Scythe.cs new file mode 100644 index 0000000..736bfad --- /dev/null +++ b/Scripts/Items/Weapons/PoleArms/Scythe.cs @@ -0,0 +1,57 @@ +using System; +using Server.Network; +using Server.Items; +using Server.Engines.Harvest; + +namespace Server.Items +{ + [FlipableAttribute( 0x26BA, 0x26C4 )] + public class Scythe : BasePoleArm + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 18; } } + public override int AosSpeed{ get{ return 32; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 15; } } + public override int OldMaxDamage{ get{ return 18; } } + public override int OldSpeed{ get{ return 32; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 100; } } + + public override HarvestSystem HarvestSystem{ get{ return null; } } + + [Constructable] + public Scythe() : base( 0x26BA ) + { + Weight = 5.0; + } + + public Scythe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 15.0 ) + Weight = 5.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/AssassinsShortbow.cs b/Scripts/Items/Weapons/Ranged/AssassinsShortbow.cs new file mode 100644 index 0000000..f0d4930 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/AssassinsShortbow.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class AssassinsShortbow : MagicalShortbow + { + public override int LabelNumber{ get{ return 1073512; } } // assassin's shortbow + + [Constructable] + public AssassinsShortbow() + { + Attributes.AttackChance = 3; + Attributes.WeaponDamage = 4; + } + + public AssassinsShortbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/BarbedLongbow.cs b/Scripts/Items/Weapons/Ranged/BarbedLongbow.cs new file mode 100644 index 0000000..a9a7df2 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/BarbedLongbow.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class BarbedLongbow : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1073505; } } // barbed longbow + + [Constructable] + public BarbedLongbow() + { + Attributes.ReflectPhysical = 12; + } + + public BarbedLongbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/BaseRanged.cs b/Scripts/Items/Weapons/Ranged/BaseRanged.cs new file mode 100644 index 0000000..ee9339d --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/BaseRanged.cs @@ -0,0 +1,237 @@ +using System; +using Server.Items; +using Server.Network; +using Server.Spells; +using Server.Mobiles; + +namespace Server.Items +{ + public abstract class BaseRanged : BaseMeleeWeapon + { + public abstract int EffectID{ get; } + public abstract Type AmmoType{ get; } + public abstract Item Ammo{ get; } + + public override int DefHitSound{ get{ return 0x234; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override SkillName DefSkill{ get{ return SkillName.Archery; } } + public override WeaponType DefType{ get{ return WeaponType.Ranged; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootXBow; } } + + public override SkillName AccuracySkill{ get{ return SkillName.Archery; } } + + private Timer m_RecoveryTimer; // so we don't start too many timers + private bool m_Balanced; + private int m_Velocity; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Balanced + { + get{ return m_Balanced; } + set{ m_Balanced = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Velocity + { + get{ return m_Velocity; } + set{ m_Velocity = value; InvalidateProperties(); } + } + + public BaseRanged( int itemID ) : base( itemID ) + { + } + + public BaseRanged( Serial serial ) : base( serial ) + { + } + + public override TimeSpan OnSwing( Mobile attacker, Mobile defender ) + { + WeaponAbility a = WeaponAbility.GetCurrentAbility( attacker ); + + // Make sure we've been standing still for .25/.5/1 second depending on Era + if ( DateTime.Now > (attacker.LastMoveTime + TimeSpan.FromSeconds( Core.SE ? 0.25 : (Core.AOS ? 0.5 : 1.0) )) || (Core.AOS && WeaponAbility.GetCurrentAbility( attacker ) is MovingShot) ) + { + bool canSwing = true; + + if ( Core.AOS ) + { + canSwing = ( !attacker.Paralyzed && !attacker.Frozen ); + + if ( canSwing ) + { + Spell sp = attacker.Spell as Spell; + + canSwing = ( sp == null || !sp.IsCasting || !sp.BlocksMovement ); + } + } + + #region Dueling + if (attacker is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)attacker; + + if (pm.DuelContext != null && !pm.DuelContext.CheckItemEquip(attacker, this)) + canSwing = false; + } + #endregion + + + if ( canSwing && attacker.HarmfulCheck( defender ) ) + { + attacker.DisruptiveAction(); + attacker.Send( new Swing( 0, attacker, defender ) ); + + if ( OnFired( attacker, defender ) ) + { + if ( CheckHit( attacker, defender ) ) + OnHit( attacker, defender ); + else + OnMiss( attacker, defender ); + } + } + + attacker.RevealingAction(); + + return GetDelay( attacker ); + } + else + { + attacker.RevealingAction(); + + return TimeSpan.FromSeconds( 0.25 ); + } + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + if ( attacker.Player && !defender.Player && (defender.Body.IsAnimal || defender.Body.IsMonster) && 0.4 >= Utility.RandomDouble() ) + defender.AddToBackpack( Ammo ); + + if ( Core.ML && m_Velocity > 0 ) + { + int bonus = (int) attacker.GetDistanceToSqrt( defender ); + + if ( bonus > 0 && m_Velocity > Utility.Random( 100 ) ) + { + AOS.Damage( defender, attacker, bonus * 3, 100, 0, 0, 0, 0 ); + + if ( attacker.Player ) + attacker.SendLocalizedMessage( 1072794 ); // Your arrow hits its mark with velocity! + + if ( defender.Player ) + defender.SendLocalizedMessage( 1072795 ); // You have been hit by an arrow with velocity! + } + } + + base.OnHit( attacker, defender, damageBonus ); + } + + public override void OnMiss( Mobile attacker, Mobile defender ) + { + if ( attacker.Player && 0.4 >= Utility.RandomDouble() ) + { + if ( Core.SE ) + { + PlayerMobile p = attacker as PlayerMobile; + + if ( p != null ) + { + Type ammo = AmmoType; + + if ( p.RecoverableAmmo.ContainsKey( ammo ) ) + p.RecoverableAmmo[ ammo ]++; + else + p.RecoverableAmmo.Add( ammo, 1 ); + + if ( !p.Warmode ) + { + if ( m_RecoveryTimer == null ) + m_RecoveryTimer = Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( p.RecoverAmmo ) ); + + if ( !m_RecoveryTimer.Running ) + m_RecoveryTimer.Start(); + } + } + } else { + Ammo.MoveToWorld( new Point3D( defender.X + Utility.RandomMinMax( -1, 1 ), defender.Y + Utility.RandomMinMax( -1, 1 ), defender.Z ), defender.Map ); + } + } + + base.OnMiss( attacker, defender ); + } + + public virtual bool OnFired( Mobile attacker, Mobile defender ) + { + if (attacker.Player) + { + BaseQuiver quiver = attacker.FindItemOnLayer(Layer.Cloak) as BaseQuiver; + Container pack = attacker.Backpack; + + if (quiver == null || Utility.Random(100) >= quiver.LowerAmmoCost) + { + // consume ammo + if (quiver != null && quiver.ConsumeTotal(AmmoType, 1)) + quiver.InvalidateWeight(); + else if (pack == null || !pack.ConsumeTotal(AmmoType, 1)) + return false; + } + else if (quiver.FindItemByType(AmmoType) == null && (pack == null || pack.FindItemByType(AmmoType) == null)) + { + // lower ammo cost should not work when we have no ammo at all + return false; + } + } + + attacker.MovingEffect( defender, EffectID, 18, 1, false, false ); + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); // version + + writer.Write( (bool) m_Balanced ); + writer.Write( (int) m_Velocity ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + { + m_Balanced = reader.ReadBool(); + m_Velocity = reader.ReadInt(); + + goto case 2; + } + case 2: + case 1: + { + break; + } + case 0: + { + /*m_EffectID =*/ reader.ReadInt(); + break; + } + } + + if ( version < 2 ) + { + WeaponAttributes.MageWeapon = 0; + WeaponAttributes.UseBestSkill = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/Bow.cs b/Scripts/Items/Weapons/Ranged/Bow.cs new file mode 100644 index 0000000..c1cd2f5 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/Bow.cs @@ -0,0 +1,63 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B2, 0x13B1 )] + public class Bow : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 30; } } + public override int AosMinDamage{ get{ return Core.ML ? 15 : 16; } } + public override int AosMaxDamage{ get{ return Core.ML ? 19 : 18; } } + public override int AosSpeed{ get{ return 25; } } + public override float MlSpeed{ get{ return 4.25f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 41; } } + public override int OldSpeed{ get{ return 20; } } + + public override int DefMaxRange{ get{ return 10; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 60; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } } + + [Constructable] + public Bow() : base( 0x13B2 ) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + } + + public Bow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 7.0 ) + Weight = 6.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/CompositeBow.cs b/Scripts/Items/Weapons/Ranged/CompositeBow.cs new file mode 100644 index 0000000..bb315fa --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/CompositeBow.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26C2, 0x26CC )] + public class CompositeBow : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MovingShot; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return Core.ML ? 13 : 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 25; } } + public override float MlSpeed{ get{ return 4.00f; } } + + public override int OldStrengthReq{ get{ return 45; } } + public override int OldMinDamage{ get{ return 15; } } + public override int OldMaxDamage{ get{ return 17; } } + public override int OldSpeed{ get{ return 25; } } + + public override int DefMaxRange{ get{ return 10; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } } + + [Constructable] + public CompositeBow() : base( 0x26C2 ) + { + Weight = 5.0; + } + + public CompositeBow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/Crossbow.cs b/Scripts/Items/Weapons/Ranged/Crossbow.cs new file mode 100644 index 0000000..af800c5 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/Crossbow.cs @@ -0,0 +1,58 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF50, 0xF4F )] + public class Crossbow : BaseRanged + { + public override int EffectID{ get{ return 0x1BFE; } } + public override Type AmmoType{ get{ return typeof( Bolt ); } } + public override Item Ammo{ get{ return new Bolt(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 18; } } + public override int AosMaxDamage{ get{ return Core.ML ? 22 : 20; } } + public override int AosSpeed{ get{ return 24; } } + public override float MlSpeed{ get{ return 4.50f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 43; } } + public override int OldSpeed{ get{ return 18; } } + + public override int DefMaxRange{ get{ return 8; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public Crossbow() : base( 0xF50 ) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public Crossbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/FrozenLongbow.cs b/Scripts/Items/Weapons/Ranged/FrozenLongbow.cs new file mode 100644 index 0000000..b572df7 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/FrozenLongbow.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class FrozenLongbow : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1073507; } } // frozen longbow + + [Constructable] + public FrozenLongbow() + { + Attributes.WeaponSpeed = -5; + Attributes.DefendChance = 10; + } + + public FrozenLongbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/HeavyCrossbow.cs b/Scripts/Items/Weapons/Ranged/HeavyCrossbow.cs new file mode 100644 index 0000000..e40fb03 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/HeavyCrossbow.cs @@ -0,0 +1,58 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13FD, 0x13FC )] + public class HeavyCrossbow : BaseRanged + { + public override int EffectID{ get{ return 0x1BFE; } } + public override Type AmmoType{ get{ return typeof( Bolt ); } } + public override Item Ammo{ get{ return new Bolt(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.MovingShot; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Dismount; } } + + public override int AosStrengthReq{ get{ return 80; } } + public override int AosMinDamage{ get{ return Core.ML ? 20 : 19; } } + public override int AosMaxDamage{ get{ return Core.ML ? 24 : 20; } } + public override int AosSpeed{ get{ return 22; } } + public override float MlSpeed{ get{ return 5.00f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 11; } } + public override int OldMaxDamage{ get{ return 56; } } + public override int OldSpeed{ get{ return 10; } } + + public override int DefMaxRange{ get{ return 8; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 100; } } + + [Constructable] + public HeavyCrossbow() : base( 0x13FD ) + { + Weight = 9.0; + Layer = Layer.TwoHanded; + } + + public HeavyCrossbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/JukaBow.cs b/Scripts/Items/Weapons/Ranged/JukaBow.cs new file mode 100644 index 0000000..9fb79ff --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/JukaBow.cs @@ -0,0 +1,97 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B2, 0x13B1 )] + public class JukaBow : Bow + { + public override int AosStrengthReq{ get{ return 80; } } + public override int AosDexterityReq{ get{ return 80; } } + + public override int OldStrengthReq{ get{ return 80; } } + public override int OldDexterityReq{ get{ return 80; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsModified + { + get{ return ( Hue == 0x453 ); } + } + + [Constructable] + public JukaBow() + { + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsModified ) + { + from.SendMessage( "That has already been modified." ); + } + else if ( !IsChildOf( from.Backpack ) ) + { + from.SendMessage( "This must be in your backpack to modify it." ); + } + else if ( from.Skills[SkillName.Fletching].Base < 100.0 ) + { + from.SendMessage( "Only a grandmaster bowcrafter can modify this weapon." ); + } + else + { + from.BeginTarget( 2, false, Targeting.TargetFlags.None, new TargetCallback( OnTargetGears ) ); + from.SendMessage( "Select the gears you wish to use." ); + } + } + + public void OnTargetGears( Mobile from, object targ ) + { + Gears g = targ as Gears; + + if ( g == null || !g.IsChildOf( from.Backpack ) ) + { + from.SendMessage( "Those are not gears." ); // Apparently gears that aren't in your backpack aren't really gears at all. :-( + } + else if ( IsModified ) + { + from.SendMessage( "That has already been modified." ); + } + else if ( !IsChildOf( from.Backpack ) ) + { + from.SendMessage( "This must be in your backpack to modify it." ); + } + else if ( from.Skills[SkillName.Fletching].Base < 100.0 ) + { + from.SendMessage( "Only a grandmaster bowcrafter can modify this weapon." ); + } + else + { + g.Consume(); + + Hue = 0x453; + Slayer = (SlayerName)Utility.Random( 2, 25 ); + + from.SendMessage( "You modify it." ); + } + } + + public JukaBow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/LightweightShortbow.cs b/Scripts/Items/Weapons/Ranged/LightweightShortbow.cs new file mode 100644 index 0000000..c5e6f42 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/LightweightShortbow.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LightweightShortbow : MagicalShortbow + { + public override int LabelNumber{ get{ return 1073510; } } // lightweight shortbow + + [Constructable] + public LightweightShortbow() + { + Balanced = true; + } + + public LightweightShortbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/LongbowOfMight.cs b/Scripts/Items/Weapons/Ranged/LongbowOfMight.cs new file mode 100644 index 0000000..48ea114 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/LongbowOfMight.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LongbowOfMight : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1073508; } } // longbow of might + + [Constructable] + public LongbowOfMight() + { + Attributes.WeaponDamage = 5; + } + + public LongbowOfMight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/MysticalShortbow.cs b/Scripts/Items/Weapons/Ranged/MysticalShortbow.cs new file mode 100644 index 0000000..717c1ee --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/MysticalShortbow.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class MysticalShortbow : MagicalShortbow + { + public override int LabelNumber{ get{ return 1073511; } } // mystical shortbow + + [Constructable] + public MysticalShortbow() + { + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + } + + public MysticalShortbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/RangersShortbow.cs b/Scripts/Items/Weapons/Ranged/RangersShortbow.cs new file mode 100644 index 0000000..55ef706 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/RangersShortbow.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class RangersShortbow : MagicalShortbow + { + public override int LabelNumber{ get{ return 1073509; } } // ranger's shortbow + + [Constructable] + public RangersShortbow() + { + Attributes.WeaponSpeed = 5; + } + + public RangersShortbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Ranged/RepeatingCrossbow.cs b/Scripts/Items/Weapons/Ranged/RepeatingCrossbow.cs new file mode 100644 index 0000000..23822e8 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/RepeatingCrossbow.cs @@ -0,0 +1,57 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26C3, 0x26CD )] + public class RepeatingCrossbow : BaseRanged + { + public override int EffectID{ get{ return 0x1BFE; } } + public override Type AmmoType{ get{ return typeof( Bolt ); } } + public override Item Ammo{ get{ return new Bolt(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MovingShot; } } + + public override int AosStrengthReq{ get{ return 30; } } + public override int AosMinDamage{ get{ return Core.ML ? 8 : 10; } } + public override int AosMaxDamage{ get{ return 12; } } + public override int AosSpeed{ get{ return 41; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 12; } } + public override int OldSpeed{ get{ return 41; } } + + public override int DefMaxRange{ get{ return 7; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public RepeatingCrossbow() : base( 0x26C3 ) + { + Weight = 6.0; + } + + public RepeatingCrossbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Ranged/SlayerLongbow.cs b/Scripts/Items/Weapons/Ranged/SlayerLongbow.cs new file mode 100644 index 0000000..a0cb672 --- /dev/null +++ b/Scripts/Items/Weapons/Ranged/SlayerLongbow.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SlayerLongbow : ElvenCompositeLongbow + { + public override int LabelNumber{ get{ return 1073506; } } // slayer longbow + + [Constructable] + public SlayerLongbow() + { + Slayer2 = (SlayerName) Utility.RandomMinMax( 1, 27 ); + } + + public SlayerLongbow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/SE Weapons/Bokuto.cs b/Scripts/Items/Weapons/SE Weapons/Bokuto.cs new file mode 100644 index 0000000..8dd96de --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Bokuto.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A8, 0x27F3 )] + public class Bokuto : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Feint; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.NerveStrike; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 53; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 11; } } + public override int OldSpeed{ get{ return 53; } } + + public override int DefHitSound{ get{ return 0x536; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 25; } } + public override int InitMaxHits{ get{ return 50; } } + + [Constructable] + public Bokuto() : base( 0x27A8 ) + { + Weight = 7.0; + } + + public Bokuto( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Daisho.cs b/Scripts/Items/Weapons/SE Weapons/Daisho.cs new file mode 100644 index 0000000..07f8504 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Daisho.cs @@ -0,0 +1,55 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A9, 0x27F4 )] + public class Daisho : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Feint; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 40; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 13; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 40; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 65; } } + + [Constructable] + public Daisho() : base( 0x27A9 ) + { + Weight = 8.0; + Layer = Layer.TwoHanded; + } + + public Daisho( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Kama.cs b/Scripts/Items/Weapons/SE Weapons/Kama.cs new file mode 100644 index 0000000..78d04b6 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Kama.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27AD, 0x27F8 )] + public class Kama : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.DefenseMastery; } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 55; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 11; } } + public override int OldSpeed{ get{ return 55; } } + + public override int DefHitSound{ get{ return 0x232; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 60; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Kama() : base( 0x27AD ) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public Kama( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Lajatang.cs b/Scripts/Items/Weapons/SE Weapons/Lajatang.cs new file mode 100644 index 0000000..ce9cddb --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Lajatang.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A7, 0x27F2 )] + public class Lajatang : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DefenseMastery; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.FrenziedWhirlwind; } } + + public override int AosStrengthReq{ get{ return 65; } } + public override int AosMinDamage{ get{ return 16; } } + public override int AosMaxDamage{ get{ return 18; } } + public override int AosSpeed{ get{ return 32; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 65; } } + public override int OldMinDamage{ get{ return 16; } } + public override int OldMaxDamage{ get{ return 18; } } + public override int OldSpeed{ get{ return 55; } } + + public override int DefHitSound{ get{ return 0x232; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 90; } } + public override int InitMaxHits{ get{ return 95; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Lajatang() : base( 0x27A7 ) + { + Weight = 12.0; + Layer = Layer.TwoHanded; + } + + public Lajatang( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/NoDachi.cs b/Scripts/Items/Weapons/SE Weapons/NoDachi.cs new file mode 100644 index 0000000..c4ea2a5 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/NoDachi.cs @@ -0,0 +1,55 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A2, 0x27ED )] + public class NoDachi : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.RidingSwipe; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 16; } } + public override int AosMaxDamage{ get{ return 18; } } + public override int AosSpeed{ get{ return 35; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 16; } } + public override int OldMaxDamage{ get{ return 18; } } + public override int OldSpeed{ get{ return 35; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 90; } } + + [Constructable] + public NoDachi() : base( 0x27A2 ) + { + Weight = 10.0; + Layer = Layer.TwoHanded; + } + + public NoDachi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Nunchaku.cs b/Scripts/Items/Weapons/SE Weapons/Nunchaku.cs new file mode 100644 index 0000000..a59b203 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Nunchaku.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27AE, 0x27F9 )] + public class Nunchaku : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Block; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Feint; } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 47; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 11; } } + public override int OldMaxDamage{ get{ return 13; } } + public override int OldSpeed{ get{ return 47; } } + + public override int DefHitSound{ get{ return 0x535; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override int InitMinHits{ get{ return 40; } } + public override int InitMaxHits{ get{ return 55; } } + + [Constructable] + public Nunchaku() : base( 0x27AE ) + { + Weight = 5.0; + } + + public Nunchaku( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Sai.cs b/Scripts/Items/Weapons/SE Weapons/Sai.cs new file mode 100644 index 0000000..a200c47 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Sai.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27AF, 0x27FA )] + public class Sai : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Block; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ArmorPierce; } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 9; } } + public override int AosMaxDamage{ get{ return 11; } } + public override int AosSpeed{ get{ return 55; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 11; } } + public override int OldSpeed{ get{ return 55; } } + + public override int DefHitSound{ get{ return 0x23C; } } + public override int DefMissSound{ get{ return 0x232; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 60; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Sai() : base( 0x27AF ) + { + Weight = 7.0; + Layer = Layer.TwoHanded; + } + + public Sai( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Tekagi.cs b/Scripts/Items/Weapons/SE Weapons/Tekagi.cs new file mode 100644 index 0000000..8b1f40f --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Tekagi.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27Ab, 0x27F6 )] + public class Tekagi : BaseKnife + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DualWield; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.TalonStrike; } } + + public override int AosStrengthReq{ get{ return 10; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 12; } } + public override int AosSpeed{ get{ return 53; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 12; } } + public override int OldSpeed{ get{ return 53; } } + + public override int DefHitSound{ get{ return 0x238; } } + public override int DefMissSound{ get{ return 0x232; } } + + public override int InitMinHits{ get{ return 35; } } + public override int InitMaxHits{ get{ return 60; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Tekagi() : base( 0x27AB ) + { + Weight = 5.0; + Layer = Layer.TwoHanded; + } + + public Tekagi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Tessen.cs b/Scripts/Items/Weapons/SE Weapons/Tessen.cs new file mode 100644 index 0000000..320696d --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Tessen.cs @@ -0,0 +1,57 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A3, 0x27EE )] + public class Tessen : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Feint; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Block; } } + + public override int AosStrengthReq{ get{ return 10; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 12; } } + public override int AosSpeed{ get{ return 50; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 12; } } + public override int OldSpeed{ get{ return 50; } } + + public override int DefHitSound{ get{ return 0x232; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 60; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Bash2H; } } + + [Constructable] + public Tessen() : base( 0x27A3 ) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + } + + public Tessen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Tetsubo.cs b/Scripts/Items/Weapons/SE Weapons/Tetsubo.cs new file mode 100644 index 0000000..c9d334e --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Tetsubo.cs @@ -0,0 +1,57 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A6, 0x27F1 )] + public class Tetsubo : BaseBashing + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.FrenziedWhirlwind; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 45; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 12; } } + public override int OldMaxDamage{ get{ return 14; } } + public override int OldSpeed{ get{ return 45; } } + + public override int DefHitSound{ get{ return 0x233; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 60; } } + public override int InitMaxHits{ get{ return 65; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Bash2H; } } + + [Constructable] + public Tetsubo() : base( 0x27A6 ) + { + Weight = 8.0; + Layer = Layer.TwoHanded; + } + + public Tetsubo( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Wakizashi.cs b/Scripts/Items/Weapons/SE Weapons/Wakizashi.cs new file mode 100644 index 0000000..be38932 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Wakizashi.cs @@ -0,0 +1,55 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A4, 0x27EF )] + public class Wakizashi : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.FrenziedWhirlwind; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 44; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 11; } } + public override int OldMaxDamage{ get{ return 13; } } + public override int OldSpeed{ get{ return 44; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 45; } } + public override int InitMaxHits{ get{ return 50; } } + + [Constructable] + public Wakizashi() : base( 0x27A4 ) + { + Weight = 5.0; + Layer = Layer.OneHanded; + } + + public Wakizashi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SE Weapons/Yumi.cs b/Scripts/Items/Weapons/SE Weapons/Yumi.cs new file mode 100644 index 0000000..ecd9015 --- /dev/null +++ b/Scripts/Items/Weapons/SE Weapons/Yumi.cs @@ -0,0 +1,63 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x27A5, 0x27F0 )] + public class Yumi : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorPierce; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.DoubleShot; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return Core.ML ? 16 : 18; } } + public override int AosMaxDamage{ get{ return 20; } } + public override int AosSpeed{ get{ return 25; } } + public override float MlSpeed{ get{ return 4.5f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 18; } } + public override int OldMaxDamage{ get{ return 20; } } + public override int OldSpeed{ get{ return 25; } } + + public override int DefMaxRange{ get{ return 10; } } + + public override int InitMinHits{ get{ return 55; } } + public override int InitMaxHits{ get{ return 60; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } } + + [Constructable] + public Yumi() : base( 0x27A5 ) + { + Weight = 9.0; + Layer = Layer.TwoHanded; + } + + public Yumi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 7.0 ) + Weight = 6.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SlayerEntry.cs b/Scripts/Items/Weapons/SlayerEntry.cs new file mode 100644 index 0000000..4d72afa --- /dev/null +++ b/Scripts/Items/Weapons/SlayerEntry.cs @@ -0,0 +1,108 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class SlayerEntry + { + private SlayerGroup m_Group; + private SlayerName m_Name; + private Type[] m_Types; + + public SlayerGroup Group{ get{ return m_Group; } set{ m_Group = value; } } + public SlayerName Name{ get{ return m_Name; } } + public Type[] Types{ get{ return m_Types; } } + + private static int[] m_AosTitles = new int[] + { + 1060479, // undead slayer + 1060470, // orc slayer + 1060480, // troll slayer + 1060468, // ogre slayer + 1060472, // repond slayer + 1060462, // dragon slayer + 1060478, // terathan slayer + 1060475, // snake slayer + 1060467, // lizardman slayer + 1060473, // reptile slayer + 1060460, // demon slayer + 1060466, // gargoyle slayer + 1017396, // Balron Damnation + 1060461, // demon slayer + 1060469, // ophidian slayer + 1060477, // spider slayer + 1060474, // scorpion slayer + 1060458, // arachnid slayer + 1060465, // fire elemental slayer + 1060481, // water elemental slayer + 1060457, // air elemental slayer + 1060471, // poison elemental slayer + 1060463, // earth elemental slayer + 1060459, // blood elemental slayer + 1060476, // snow elemental slayer + 1060464, // elemental slayer + 1070855 // fey slayer + }; + + private static int[] m_OldTitles = new int[] + { + 1017384, // Silver + 1017385, // Orc Slaying + 1017386, // Troll Slaughter + 1017387, // Ogre Thrashing + 1017388, // Repond + 1017389, // Dragon Slaying + 1017390, // Terathan + 1017391, // Snake's Bane + 1017392, // Lizardman Slaughter + 1017393, // Reptilian Death + 1017394, // Daemon Dismissal + 1017395, // Gargoyle's Foe + 1017396, // Balron Damnation + 1017397, // Exorcism + 1017398, // Ophidian + 1017399, // Spider's Death + 1017400, // Scorpion's Bane + 1017401, // Arachnid Doom + 1017402, // Flame Dousing + 1017403, // Water Dissipation + 1017404, // Vacuum + 1017405, // Elemental Health + 1017406, // Earth Shatter + 1017407, // Blood Drinking + 1017408, // Summer Wind + 1017409, // Elemental Ban + 1070855 // fey slayer + }; + + public int Title + { + get + { + int[] titles = ( Core.AOS ? m_AosTitles : m_OldTitles ); + + return titles[(int)m_Name - 1]; + } + } + + public SlayerEntry( SlayerName name, params Type[] types ) + { + m_Name = name; + m_Types = types; + } + + public bool Slays( Mobile m ) + { + Type t = m.GetType(); + + for ( int i = 0; i < m_Types.Length; ++i ) + { + if (m_Types[i].IsAssignableFrom(t)) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SlayerGroup.cs b/Scripts/Items/Weapons/SlayerGroup.cs new file mode 100644 index 0000000..a3c32ae --- /dev/null +++ b/Scripts/Items/Weapons/SlayerGroup.cs @@ -0,0 +1,207 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class SlayerGroup + { + private static SlayerEntry[] m_TotalEntries; + private static SlayerGroup[] m_Groups; + + public static SlayerEntry[] TotalEntries + { + get{ return m_TotalEntries; } + } + + public static SlayerGroup[] Groups + { + get{ return m_Groups; } + } + + public static SlayerEntry GetEntryByName( SlayerName name ) + { + int v = (int)name; + + if ( v >= 0 && v < m_TotalEntries.Length ) + return m_TotalEntries[v]; + + return null; + } + + public static SlayerName GetLootSlayerType( Type type ) + { + for ( int i = 0; i < m_Groups.Length; ++i ) + { + SlayerGroup group = m_Groups[i]; + Type[] foundOn = group.FoundOn; + + bool inGroup = false; + + for ( int j = 0; foundOn != null && !inGroup && j < foundOn.Length; ++j ) + inGroup = ( foundOn[j] == type ); + + if ( inGroup ) + { + int index = Utility.Random( 1 + group.Entries.Length ); + + if ( index == 0 ) + return group.m_Super.Name; + + return group.Entries[index - 1].Name; + } + } + + return SlayerName.Silver; + } + + static SlayerGroup() + { + SlayerGroup humanoid = new SlayerGroup(); + SlayerGroup undead = new SlayerGroup(); + SlayerGroup elemental = new SlayerGroup(); + SlayerGroup abyss = new SlayerGroup(); + SlayerGroup arachnid = new SlayerGroup(); + SlayerGroup reptilian = new SlayerGroup(); + SlayerGroup fey = new SlayerGroup(); + + humanoid.Opposition = new SlayerGroup[]{ undead }; + humanoid.FoundOn = new Type[]{ typeof( BoneKnight ), typeof( Lich ), typeof( LichLord ) }; + humanoid.Super = new SlayerEntry(SlayerName.Repond, typeof(ArcticOgreLord), typeof(Cyclops), typeof(Ettin), typeof(EvilMage), typeof(EvilMageLord), typeof(FrostTroll), typeof(MeerCaptain), typeof(MeerEternal), typeof(MeerMage), typeof(MeerWarrior), typeof(Ogre), typeof(OgreLord), typeof(Orc), typeof(OrcBomber), typeof(OrcBrute), typeof(OrcCaptain), /*typeof( OrcChopper ), typeof( OrcScout ),*/ typeof(OrcishLord), typeof(OrcishMage), typeof(Ratman), typeof(RatmanArcher), typeof(RatmanMage), typeof(SavageRider), typeof(SavageShaman), typeof(Savage), typeof(Titan), typeof(Troglodyte), typeof(Troll)); + humanoid.Entries = new SlayerEntry[] + { + new SlayerEntry( SlayerName.OgreTrashing, typeof( Ogre ), typeof( OgreLord ), typeof( ArcticOgreLord ) ), + new SlayerEntry( SlayerName.OrcSlaying, typeof( Orc ), typeof( OrcBomber ), typeof( OrcBrute ), typeof( OrcCaptain ),/* typeof( OrcChopper ), typeof( OrcScout ),*/ typeof( OrcishLord ), typeof( OrcishMage ) ), + new SlayerEntry( SlayerName.TrollSlaughter, typeof( Troll ), typeof( FrostTroll ) ) + }; + + undead.Opposition = new SlayerGroup[]{ humanoid }; + undead.Super = new SlayerEntry( SlayerName.Silver, typeof( AncientLich ), typeof( Bogle ), typeof( BoneKnight ), typeof( BoneMagi ),/* typeof( DarkGuardian ), */typeof( DarknightCreeper ), typeof( FleshGolem ), typeof( Ghoul ), typeof( GoreFiend ), typeof( HellSteed ), typeof( LadyOfTheSnow ), typeof( Lich ), typeof( LichLord ), typeof( Mummy ), typeof( PestilentBandage ), typeof( Revenant ), typeof( RevenantLion ), typeof( RottingCorpse ), typeof( Shade ), typeof( ShadowKnight ), typeof( SkeletalKnight ), typeof( SkeletalMage ), typeof( SkeletalMount ), typeof( Skeleton ), typeof( Spectre ), typeof( Wraith ), typeof( Zombie ) ); + undead.Entries = new SlayerEntry[0]; + + fey.Opposition = new SlayerGroup[]{ abyss }; + fey.Super = new SlayerEntry(SlayerName.Fey, typeof(Centaur), typeof(CuSidhe), typeof(EtherealWarrior), typeof(Kirin), typeof(LordOaks), typeof(Pixie), typeof(Silvani), typeof(Treefellow), typeof(Unicorn), typeof(Wisp), typeof(MLDryad), typeof(Satyr)); + fey.Entries = new SlayerEntry[0]; + + elemental.Opposition = new SlayerGroup[]{ abyss }; + elemental.FoundOn = new Type[]{ typeof( Balron ), typeof( Daemon ) }; + elemental.Super = new SlayerEntry( SlayerName.ElementalBan, typeof( AcidElemental ), typeof( AgapiteElemental ), typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( BloodElemental ), typeof( BronzeElemental ), typeof( CopperElemental ), typeof( CrystalElemental ), typeof( DullCopperElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ), typeof( Efreet ), typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( GoldenElemental ), typeof( IceElemental ), typeof( KazeKemono ), typeof( PoisonElemental ), typeof( RaiJu ), typeof( SandVortex ), typeof( ShadowIronElemental ), typeof( SnowElemental ), typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( WaterElemental ), typeof( SummonedWaterElemental ) ); + elemental.Entries = new SlayerEntry[] + { + new SlayerEntry( SlayerName.BloodDrinking, typeof( BloodElemental ) ), + new SlayerEntry( SlayerName.EarthShatter, typeof( AgapiteElemental ), typeof( BronzeElemental ), typeof( CopperElemental ), typeof( DullCopperElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ), typeof( GoldenElemental ), typeof( ShadowIronElemental ), typeof( ValoriteElemental ), typeof( VeriteElemental ) ), + new SlayerEntry( SlayerName.ElementalHealth, typeof( PoisonElemental ) ), + new SlayerEntry( SlayerName.FlameDousing, typeof( FireElemental ), typeof( SummonedFireElemental ) ), + new SlayerEntry( SlayerName.SummerWind, typeof( SnowElemental ), typeof( IceElemental ) ), + new SlayerEntry( SlayerName.Vacuum, typeof( AirElemental ), typeof( SummonedAirElemental ) ), + new SlayerEntry( SlayerName.WaterDissipation, typeof( WaterElemental ), typeof( SummonedWaterElemental ) ) + }; + + abyss.Opposition = new SlayerGroup[]{ elemental, fey }; + abyss.FoundOn = new Type[]{ typeof( BloodElemental ) }; + + if( Core.AOS ) + { + abyss.Super = new SlayerEntry( SlayerName.Exorcism, typeof( AbysmalHorror ), typeof( ArcaneDaemon ), typeof( Balron ), typeof( BoneDemon ), typeof( ChaosDaemon ), typeof( Daemon ), typeof( SummonedDaemon ), typeof( DemonKnight ), typeof( Devourer ), typeof( EnslavedGargoyle ), typeof( FanDancer ), typeof( FireGargoyle ), typeof( Gargoyle ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ), typeof( Gibberling ), typeof( HordeMinion ), typeof( IceFiend ), typeof( Imp ), typeof( Impaler ), typeof( Moloch ), typeof( Oni ), typeof( Ravager ), typeof( Semidar ), typeof( StoneGargoyle ), typeof( Succubus ), typeof( TsukiWolf ) ); + + abyss.Entries = new SlayerEntry[] + { + // Daemon Dismissal & Balron Damnation have been removed and moved up to super slayer on OSI. + new SlayerEntry( SlayerName.GargoylesFoe, typeof( EnslavedGargoyle ), typeof( FireGargoyle ), typeof( Gargoyle ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ), typeof( StoneGargoyle ) ), + }; + } + else + { + abyss.Super = new SlayerEntry( SlayerName.Exorcism, typeof( AbysmalHorror ), typeof( Balron ), typeof( BoneDemon ), typeof( ChaosDaemon ), typeof( Daemon ), typeof( SummonedDaemon ), typeof( DemonKnight ), typeof( Devourer ), typeof( Gargoyle ), typeof( FireGargoyle ), typeof( Gibberling ), typeof( HordeMinion ), typeof( IceFiend ), typeof( Imp ), typeof( Impaler ), typeof( Ravager ), typeof( StoneGargoyle ), typeof( ArcaneDaemon ), typeof( EnslavedGargoyle ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ), typeof( Moloch ) ); + + abyss.Entries = new SlayerEntry[] + { + new SlayerEntry( SlayerName.DaemonDismissal, typeof( AbysmalHorror ), typeof( Balron ), typeof( BoneDemon ), typeof( ChaosDaemon ), typeof( Daemon ), typeof( SummonedDaemon ), typeof( DemonKnight ), typeof( Devourer ), typeof( Gibberling ), typeof( HordeMinion ), typeof( IceFiend ), typeof( Imp ), typeof( Impaler ), typeof( Ravager ), typeof( ArcaneDaemon ), typeof( Moloch ) ), + new SlayerEntry( SlayerName.GargoylesFoe, typeof( FireGargoyle ), typeof( Gargoyle ), typeof( StoneGargoyle ), typeof( EnslavedGargoyle ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ) ), + new SlayerEntry( SlayerName.BalronDamnation, typeof( Balron ) ) + }; + } + + arachnid.Opposition = new SlayerGroup[]{ reptilian }; + arachnid.FoundOn = new Type[]{ typeof( AncientWyrm ), typeof( GreaterDragon ), typeof( Dragon ), typeof( OphidianMatriarch ), typeof( ShadowWyrm ) }; + arachnid.Super = new SlayerEntry( SlayerName.ArachnidDoom, typeof( DreadSpider ), typeof( FrostSpider ), typeof( GiantBlackWidow ), typeof( GiantSpider ), typeof( Mephitis ), typeof( Scorpion ), typeof( TerathanAvenger ), typeof( TerathanDrone ), typeof( TerathanMatriarch ), typeof( TerathanWarrior ) ); + arachnid.Entries = new SlayerEntry[] + { + new SlayerEntry( SlayerName.ScorpionsBane, typeof( Scorpion ) ), + new SlayerEntry( SlayerName.SpidersDeath, typeof( DreadSpider ), typeof( FrostSpider ), typeof( GiantBlackWidow ), typeof( GiantSpider ), typeof( Mephitis ) ), + new SlayerEntry( SlayerName.Terathan, typeof( TerathanAvenger ), typeof( TerathanDrone ), typeof( TerathanMatriarch ), typeof( TerathanWarrior ) ) + }; + + reptilian.Opposition = new SlayerGroup[]{ arachnid }; + reptilian.FoundOn = new Type[]{ typeof( TerathanAvenger ), typeof( TerathanMatriarch ) }; + reptilian.Super = new SlayerEntry(SlayerName.ReptilianDeath, typeof(AncientWyrm), typeof(DeepSeaSerpent), typeof(GreaterDragon), typeof(Dragon), typeof(Drake), typeof(GiantIceWorm), typeof(IceSerpent), typeof(GiantSerpent), typeof(Hiryu), typeof(IceSnake), typeof(JukaLord), typeof(JukaMage), typeof(JukaWarrior), typeof(LavaSerpent), typeof(LavaSnake), typeof(LesserHiryu), typeof(Lizardman), typeof(OphidianArchmage), typeof(OphidianKnight), typeof(OphidianMage), typeof(OphidianMatriarch), typeof(OphidianWarrior), typeof(Reptalon), typeof(SeaSerpent), typeof(Serado), typeof(SerpentineDragon), typeof(ShadowWyrm), typeof(SilverSerpent), typeof(SkeletalDragon), typeof(Snake), typeof(SwampDragon), typeof(WhiteWyrm), typeof(Wyvern), typeof(Yamandon)); + reptilian.Entries = new SlayerEntry[] + { + new SlayerEntry( SlayerName.DragonSlaying, typeof( AncientWyrm ), typeof( GreaterDragon ), typeof( Dragon ), typeof( Drake ), typeof( Hiryu ), typeof( LesserHiryu ), typeof( Reptalon ), typeof( SerpentineDragon ), typeof( ShadowWyrm ), typeof( SkeletalDragon ), typeof( SwampDragon ), typeof( WhiteWyrm ), typeof( Wyvern ) ), + new SlayerEntry( SlayerName.LizardmanSlaughter, typeof( Lizardman ) ), + new SlayerEntry( SlayerName.Ophidian, typeof( OphidianArchmage ), typeof( OphidianKnight ), typeof( OphidianMage ), typeof( OphidianMatriarch ), typeof( OphidianWarrior ) ), + new SlayerEntry( SlayerName.SnakesBane, typeof( DeepSeaSerpent ), typeof( GiantIceWorm ), typeof( GiantSerpent ), typeof( IceSerpent ), typeof( IceSnake ), typeof( LavaSerpent ), typeof( LavaSnake ), typeof( SeaSerpent ), typeof( Serado ), typeof( SilverSerpent ), typeof( Snake ), typeof( Yamandon ) ) + }; + + m_Groups = new SlayerGroup[] + { + humanoid, + undead, + elemental, + abyss, + arachnid, + reptilian, + fey + }; + + m_TotalEntries = CompileEntries( m_Groups ); + } + + private static SlayerEntry[] CompileEntries( SlayerGroup[] groups ) + { + SlayerEntry[] entries = new SlayerEntry[28]; + + for ( int i = 0; i < groups.Length; ++i ) + { + SlayerGroup g = groups[i]; + + g.Super.Group = g; + + entries[(int)g.Super.Name] = g.Super; + + for ( int j = 0; j < g.Entries.Length; ++j ) + { + g.Entries[j].Group = g; + entries[(int)g.Entries[j].Name] = g.Entries[j]; + } + } + + return entries; + } + + private SlayerGroup[] m_Opposition; + private SlayerEntry m_Super; + private SlayerEntry[] m_Entries; + private Type[] m_FoundOn; + + public SlayerGroup[] Opposition{ get{ return m_Opposition; } set{ m_Opposition = value; } } + public SlayerEntry Super{ get{ return m_Super; } set{ m_Super = value; } } + public SlayerEntry[] Entries{ get{ return m_Entries; } set{ m_Entries = value; } } + public Type[] FoundOn{ get{ return m_FoundOn; } set{ m_FoundOn = value; } } + + public bool OppositionSuperSlays( Mobile m ) + { + for( int i = 0; i < Opposition.Length; i++ ) + { + if ( Opposition[i].Super.Slays( m ) ) + return true; + } + + return false; + } + + public SlayerGroup() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SlayerName.cs b/Scripts/Items/Weapons/SlayerName.cs new file mode 100644 index 0000000..64ca1f6 --- /dev/null +++ b/Scripts/Items/Weapons/SlayerName.cs @@ -0,0 +1,36 @@ +using System; + +namespace Server.Items +{ + public enum SlayerName + { + None, + Silver, + OrcSlaying, + TrollSlaughter, + OgreTrashing, + Repond, + DragonSlaying, + Terathan, + SnakesBane, + LizardmanSlaughter, + ReptilianDeath, + DaemonDismissal, + GargoylesFoe, + BalronDamnation, + Exorcism, + Ophidian, + SpidersDeath, + ScorpionsBane, + ArachnidDoom, + FlameDousing, + WaterDissipation, + Vacuum, + ElementalHealth, + EarthShatter, + BloodDrinking, + SummerWind, + ElementalBan, // Bane? + Fey + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/BaseSpear.cs b/Scripts/Items/Weapons/SpearsAndForks/BaseSpear.cs new file mode 100644 index 0000000..5b0e2db --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/BaseSpear.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public abstract class BaseSpear : BaseMeleeWeapon + { + public override int DefHitSound{ get{ return 0x23C; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce2H; } } + + public BaseSpear( int itemID ) : base( itemID ) + { + } + + public BaseSpear( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + if (!Core.AOS && Layer == Layer.TwoHanded && (attacker.Skills[SkillName.Anatomy].Value / 400.0) >= Utility.RandomDouble() && Engines.ConPVP.DuelContext.AllowSpecialAbility(attacker, "Paralyzing Blow", false)) + { + defender.SendMessage( "You receive a paralyzing blow!" ); // Is this not localized? + defender.Freeze( TimeSpan.FromSeconds( 2.0 ) ); + + attacker.SendMessage( "You deliver a paralyzing blow!" ); // Is this not localized? + attacker.PlaySound( 0x11C ); + } + + if ( !Core.AOS && Poison != null && PoisonCharges > 0 ) + { + --PoisonCharges; + + if ( Utility.RandomDouble() >= 0.5 ) // 50% chance to poison + defender.ApplyPoison( attacker, Poison ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/BladedStaff.cs b/Scripts/Items/Weapons/SpearsAndForks/BladedStaff.cs new file mode 100644 index 0000000..87d77c2 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/BladedStaff.cs @@ -0,0 +1,53 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26BD, 0x26C7 )] + public class BladedStaff : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Dismount; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 37; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 14; } } + public override int OldMaxDamage{ get{ return 16; } } + public override int OldSpeed{ get{ return 37; } } + + public override int InitMinHits{ get{ return 21; } } + public override int InitMaxHits{ get{ return 110; } } + + public override SkillName DefSkill{ get{ return SkillName.Swords; } } + + [Constructable] + public BladedStaff() : base( 0x26BD ) + { + Weight = 4.0; + } + + public BladedStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs b/Scripts/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs new file mode 100644 index 0000000..a163879 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/DoubleBladedStaff.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26BF, 0x26C9 )] + public class DoubleBladedStaff : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 49; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 50; } } + public override int OldMinDamage{ get{ return 12; } } + public override int OldMaxDamage{ get{ return 13; } } + public override int OldSpeed{ get{ return 49; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public DoubleBladedStaff() : base( 0x26BF ) + { + Weight = 2.0; + } + + public DoubleBladedStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/Pike.cs b/Scripts/Items/Weapons/SpearsAndForks/Pike.cs new file mode 100644 index 0000000..1844516 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/Pike.cs @@ -0,0 +1,75 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26BE, 0x26C8 )] + public class Pike : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 37; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 50; } } + public override int OldMinDamage{ get{ return 14; } } + public override int OldMaxDamage{ get{ return 16; } } + public override int OldSpeed{ get{ return 37; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public Pike() : base( 0x26BE ) + { + Weight = 8.0; + } + + public Pike( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + /*** ADDED ***/ + // ALAMBIK + // Modification implementation of mounted chivalry + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus) + { + Skill skill = attacker.Skills[SkillName.Chivalry]; + if (attacker.Mounted // attaquant sur un cheval + && !(defender.Mounted) // d�fenseur pas sur un cheval + && ((attacker.Direction & Direction.Running) != 0) // cours + && (skill != null && (Utility.Random(120) <= ((int)(skill.Value) + 10))) + && attacker.CheckTargetSkill(SkillName.Chivalry, defender, 0.0, 120.0) + ) + { + attacker.SendMessage("Votre attaque mont�e disloque votre adversaire!"); + defender.PlaySound(1308); + base.OnHit(attacker, defender, 1.20); // bonus 1/5 au lieu de 1/4 + } + else + { + base.OnHit(attacker, defender, 1.0); + } + } + /*** END ***/ + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/Pitchfork.cs b/Scripts/Items/Weapons/SpearsAndForks/Pitchfork.cs new file mode 100644 index 0000000..c4bd680 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/Pitchfork.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xE87, 0xE88 )] + public class Pitchfork : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Dismount; } } + + public override int AosStrengthReq{ get{ return 55; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 43; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 4; } } + public override int OldMaxDamage{ get{ return 16; } } + public override int OldSpeed{ get{ return 45; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public Pitchfork() : base( 0xE87 ) + { + Weight = 11.0; + } + + public Pitchfork( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 10.0 ) + Weight = 11.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/ShortSpear.cs b/Scripts/Items/Weapons/SpearsAndForks/ShortSpear.cs new file mode 100644 index 0000000..513dbf3 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/ShortSpear.cs @@ -0,0 +1,53 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1403, 0x1402 )] + public class ShortSpear : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 55; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 15; } } + public override int OldMinDamage{ get{ return 4; } } + public override int OldMaxDamage{ get{ return 32; } } + public override int OldSpeed{ get{ return 50; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public ShortSpear() : base( 0x1403 ) + { + Weight = 4.0; + } + + public ShortSpear( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/Spear.cs b/Scripts/Items/Weapons/SpearsAndForks/Spear.cs new file mode 100644 index 0000000..b714a1c --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/Spear.cs @@ -0,0 +1,75 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF62, 0xF63 )] + public class Spear : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 42; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 2; } } + public override int OldMaxDamage{ get{ return 36; } } + public override int OldSpeed{ get{ return 46; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public Spear() : base( 0xF62 ) + { + Weight = 7.0; + } + + public Spear( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + /*** ADDED ***/ + // ALAMBIK + // Modification implementation of mounted chivalry + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus) + { + Skill skill = attacker.Skills[SkillName.Chivalry]; + if (attacker.Mounted // attaquant sur un cheval + && !(defender.Mounted) // d�fenseur pas sur un cheval + && ((attacker.Direction & Direction.Running) != 0) // cours + && (skill != null && (Utility.Random(120) <= ((int)(skill.Value) + 10))) + && attacker.CheckTargetSkill(SkillName.Chivalry, defender, 0.0, 120.0) + ) + { + attacker.SendMessage("Votre attaque mont�e disloque votre adversaire!"); + defender.PlaySound(1308); + base.OnHit(attacker, defender, 1.20); // bonus 1/5 au lieu de 1/4 + } + else + { + base.OnHit(attacker, defender, 1.0); + } + } + /*** END ***/ + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/TribalSpear.cs b/Scripts/Items/Weapons/SpearsAndForks/TribalSpear.cs new file mode 100644 index 0000000..0b99aa7 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/TribalSpear.cs @@ -0,0 +1,59 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF62, 0xF63 )] + public class TribalSpear : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 50; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 42; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 2; } } + public override int OldMaxDamage{ get{ return 36; } } + public override int OldSpeed{ get{ return 46; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 80; } } + + public override int VirtualDamageBonus{ get{ return 25; } } + + public override string DefaultName + { + get { return "a tribal spear"; } + } + + [Constructable] + public TribalSpear() : base( 0xF62 ) + { + Weight = 7.0; + Hue = 837; + } + + public TribalSpear( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/SpearsAndForks/WarFork.cs b/Scripts/Items/Weapons/SpearsAndForks/WarFork.cs new file mode 100644 index 0000000..e503c50 --- /dev/null +++ b/Scripts/Items/Weapons/SpearsAndForks/WarFork.cs @@ -0,0 +1,56 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1405, 0x1404 )] + public class WarFork : BaseSpear + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 45; } } + public override int AosMinDamage{ get{ return 12; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 43; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 4; } } + public override int OldMaxDamage{ get{ return 32; } } + public override int OldSpeed{ get{ return 45; } } + + public override int DefHitSound{ get{ return 0x236; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public WarFork() : base( 0x1405 ) + { + Weight = 9.0; + } + + public WarFork( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Staves/BaseStaff.cs b/Scripts/Items/Weapons/Staves/BaseStaff.cs new file mode 100644 index 0000000..a756659 --- /dev/null +++ b/Scripts/Items/Weapons/Staves/BaseStaff.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public abstract class BaseStaff : BaseMeleeWeapon + { + public override int DefHitSound{ get{ return 0x233; } } + public override int DefMissSound{ get{ return 0x239; } } + + public override SkillName DefSkill{ get{ return SkillName.Macing; } } + public override WeaponType DefType{ get{ return WeaponType.Staff; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Bash2H; } } + + public BaseStaff( int itemID ) : base( itemID ) + { + } + + public BaseStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + defender.Stam -= Utility.Random( 3, 3 ); // 3-5 points of stamina loss + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Staves/BlackStaff.cs b/Scripts/Items/Weapons/Staves/BlackStaff.cs new file mode 100644 index 0000000..307d0b0 --- /dev/null +++ b/Scripts/Items/Weapons/Staves/BlackStaff.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xDF1, 0xDF0 )] + public class BlackStaff : BaseStaff + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 39; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 35; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 35; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public BlackStaff() : base( 0xDF0 ) + { + Weight = 6.0; + } + + public BlackStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Staves/GlacialStaff.cs b/Scripts/Items/Weapons/Staves/GlacialStaff.cs new file mode 100644 index 0000000..cb0698b --- /dev/null +++ b/Scripts/Items/Weapons/Staves/GlacialStaff.cs @@ -0,0 +1,41 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class GlacialStaff : BlackStaff + { + //TODO: Pre-AoS stuff + public override int LabelNumber{ get{ return 1017413; } } // Glacial Staff + + [Constructable] + public GlacialStaff() + { + Hue = 0x480; + WeaponAttributes.HitHarm = 5 * Utility.RandomMinMax( 1, 5 ); + WeaponAttributes.MageWeapon = Utility.RandomMinMax( 5, 10 ); + + AosElementDamages[AosElementAttribute.Cold] = 20 + (5 * Utility.RandomMinMax( 0, 6 )); + + } + + public GlacialStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Staves/GnarledStaff.cs b/Scripts/Items/Weapons/Staves/GnarledStaff.cs new file mode 100644 index 0000000..4f43742 --- /dev/null +++ b/Scripts/Items/Weapons/Staves/GnarledStaff.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13F8, 0x13F9 )] + public class GnarledStaff : BaseStaff + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 33; } } + public override float MlSpeed{ get{ return 3.25f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 10; } } + public override int OldMaxDamage{ get{ return 30; } } + public override int OldSpeed{ get{ return 33; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 50; } } + + [Constructable] + public GnarledStaff() : base( 0x13F8 ) + { + Weight = 3.0; + } + + public GnarledStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Staves/QuarterStaff.cs b/Scripts/Items/Weapons/Staves/QuarterStaff.cs new file mode 100644 index 0000000..5522cb4 --- /dev/null +++ b/Scripts/Items/Weapons/Staves/QuarterStaff.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xE89, 0xE8a )] + public class QuarterStaff : BaseStaff + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + + public override int AosStrengthReq{ get{ return 30; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 48; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 30; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 28; } } + public override int OldSpeed{ get{ return 48; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 60; } } + + [Constructable] + public QuarterStaff() : base( 0xE89 ) + { + Weight = 4.0; + } + + public QuarterStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs b/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs new file mode 100644 index 0000000..bb5d02c --- /dev/null +++ b/Scripts/Items/Weapons/Staves/ShepherdsCrook.cs @@ -0,0 +1,174 @@ +using System; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; +using Server.Engines.CannedEvil; + +namespace Server.Items +{ + [FlipableAttribute( 0xE81, 0xE82 )] + public class ShepherdsCrook : BaseStaff + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 40; } } + public override float MlSpeed{ get{ return 2.75f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 3; } } + public override int OldMaxDamage{ get{ return 12; } } + public override int OldSpeed{ get{ return 30; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 50; } } + + [Constructable] + public ShepherdsCrook() : base( 0xE81 ) + { + Weight = 4.0; + } + + public ShepherdsCrook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 2.0 ) + Weight = 4.0; + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 502464 ); // Target the animal you wish to herd. + from.Target = new HerdingTarget(); + } + + private class HerdingTarget : Target + { + public HerdingTarget() : base( 10, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targ ) + { + if ( targ is BaseCreature ) + { + BaseCreature bc = (BaseCreature)targ; + + if ( IsHerdable( bc ) ) + { + if ( bc.Controlled ) + { + bc.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 502467, from.NetState ); // That animal looks tame already. + } + else + { + from.SendLocalizedMessage( 502475 ); // Click where you wish the animal to go. + from.Target = new InternalTarget( bc ); + } + } + else + { + from.SendLocalizedMessage( 502468 ); // That is not a herdable animal. + } + } + else + { + from.SendLocalizedMessage( 502472 ); // You don't seem to be able to persuade that to move. + } + } + + private static Type[] m_ChampTamables = new Type[] + { + typeof( StrongMongbat ), typeof( Imp ), typeof( Scorpion ), typeof( GiantSpider ), + typeof( Snake ), typeof( LavaLizard ), typeof( Drake ), typeof( Dragon ), + typeof( Kirin ), typeof( Unicorn ), typeof( GiantRat ), typeof( Slime ), + typeof( DireWolf ), typeof( HellHound ), typeof( DeathwatchBeetle ), + typeof( LesserHiryu ), typeof( Hiryu ) + }; + + private bool IsHerdable( BaseCreature bc ) + { + if ( bc.IsParagon ) + return false; + + if ( bc.Tamable ) + return true; + + Map map = bc.Map; + + ChampionSpawnRegion region = Region.Find( bc.Home, map ) as ChampionSpawnRegion; + + if ( region != null ) + { + ChampionSpawn spawn = region.ChampionSpawn; + + if ( spawn != null && spawn.IsChampionSpawn( bc ) ) + { + Type t = bc.GetType(); + + foreach ( Type type in m_ChampTamables ) + if ( type == t ) + return true; + } + } + + return false; + } + + private class InternalTarget : Target + { + private BaseCreature m_Creature; + + public InternalTarget( BaseCreature c ) : base( 10, true, TargetFlags.None ) + { + m_Creature = c; + } + + protected override void OnTarget( Mobile from, object targ ) + { + if ( targ is IPoint2D ) + { + double min = m_Creature.MinTameSkill - 30; + double max = m_Creature.MinTameSkill + 30 + Utility.Random( 10 ); + + if ( max <= from.Skills[ SkillName.Herding ].Value ) + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 502471, from.NetState ); // That wasn't even challenging. + + if ( from.CheckTargetSkill( SkillName.Herding, m_Creature, min, max ) ) + { + IPoint2D p = (IPoint2D) targ; + + if ( targ != from ) + p = new Point2D( p.X, p.Y ); + + m_Creature.TargetLocation = p; + from.SendLocalizedMessage( 502479 ); // The animal walks where it was instructed to. + } + else + { + from.SendLocalizedMessage( 502472 ); // You don't seem to be able to persuade that to move. + } + } + } + } + } + } +} diff --git a/Scripts/Items/Weapons/Swords/AdventurersMachete.cs b/Scripts/Items/Weapons/Swords/AdventurersMachete.cs new file mode 100644 index 0000000..210a017 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/AdventurersMachete.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class AdventurersMachete : ElvenMachete + { + public override int LabelNumber{ get{ return 1073533; } } // adventurer's machete + + [Constructable] + public AdventurersMachete() + { + Attributes.Luck = 20; + } + + public AdventurersMachete( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/BaseSword.cs b/Scripts/Items/Weapons/Swords/BaseSword.cs new file mode 100644 index 0000000..2165304 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/BaseSword.cs @@ -0,0 +1,63 @@ +using System; +using Server; +using Server.Items; +using Server.Targets; + +namespace Server.Items +{ + public abstract class BaseSword : BaseMeleeWeapon + { + public override SkillName DefSkill{ get{ return SkillName.Swords; } } + public override WeaponType DefType{ get{ return WeaponType.Slashing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Slash1H; } } + + public BaseSword( int itemID ) : base( itemID ) + { + } + + public BaseSword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + // Scriptiz : gestion du double clic pour �quipper un objet + if (from.FindItemOnLayer(this.Layer) != this) + { + base.OnDoubleClick(from); + return; + } + + from.SendLocalizedMessage(1010018); // What do you want to use this item on? + + from.Target = new BladedItemTarget(this); + } + + public override void OnHit( Mobile attacker, Mobile defender, double damageBonus ) + { + base.OnHit( attacker, defender, damageBonus ); + + if ( !Core.AOS && Poison != null && PoisonCharges > 0 ) + { + --PoisonCharges; + + if ( Utility.RandomDouble() >= 0.5 ) // 50% chance to poison + defender.ApplyPoison( attacker, Poison ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/BoneHarvester.cs b/Scripts/Items/Weapons/Swords/BoneHarvester.cs new file mode 100644 index 0000000..c5632a0 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/BoneHarvester.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26BB, 0x26C5 )] + public class BoneHarvester : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 25; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 36; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 13; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 36; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public BoneHarvester() : base( 0x26BB ) + { + Weight = 3.0; + } + + public BoneHarvester( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/BoneMachete.cs b/Scripts/Items/Weapons/Swords/BoneMachete.cs new file mode 100644 index 0000000..ae70e00 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/BoneMachete.cs @@ -0,0 +1,63 @@ +using System; +using Server.Items; +using Server.Engines.MLQuests.Items; + +namespace Server.Items +{ + public class BoneMachete : ElvenMachete, ITicket + { + public override WeaponAbility PrimaryAbility { get { return null; } } + public override WeaponAbility SecondaryAbility { get { return null; } } + + public override int PhysicalResistance { get { return 1; } } + public override int FireResistance { get { return 1; } } + public override int ColdResistance { get { return 1; } } + public override int PoisonResistance { get { return 1; } } + public override int EnergyResistance { get { return 1; } } + + public override int InitMinHits { get { return 5; } } + public override int InitMaxHits { get { return 5; } } + + [Constructable] + public BoneMachete() + { + ItemID = 0x20E; + } + + public BoneMachete(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + + #region ITicket Members + + public void OnTicketUsed(Mobile from) + { + if (Utility.RandomDouble() < 0.25) + { + from.SendLocalizedMessage(1075007); // Your bone handled machete snaps in half as you force your way through the poisonous undergrowth. + Delete(); + } + else + { + from.SendLocalizedMessage(1075008); // Your bone handled machete has grown dull but you still manage to force your way past the venomous branches. + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/Broadsword.cs b/Scripts/Items/Weapons/Swords/Broadsword.cs new file mode 100644 index 0000000..c5a27f2 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Broadsword.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF5E, 0xF5F )] + public class Broadsword : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + + public override int AosStrengthReq{ get{ return 30; } } + public override int AosMinDamage{ get{ return 14; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 33; } } + public override float MlSpeed{ get{ return 3.25f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 29; } } + public override int OldSpeed{ get{ return 45; } } + + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 100; } } + + [Constructable] + public Broadsword() : base( 0xF5E ) + { + Weight = 6.0; + } + + public Broadsword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/ChargedAssassinSpike.cs b/Scripts/Items/Weapons/Swords/ChargedAssassinSpike.cs new file mode 100644 index 0000000..847c1b0 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/ChargedAssassinSpike.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ChargedAssassinSpike : AssassinSpike + { + public override int LabelNumber{ get{ return 1073518; } } // charged assassin spike + + [Constructable] + public ChargedAssassinSpike() + { + WeaponAttributes.HitLightning = 10; + } + + public ChargedAssassinSpike( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/CorruptedRuneBlade.cs b/Scripts/Items/Weapons/Swords/CorruptedRuneBlade.cs new file mode 100644 index 0000000..3ceb3a2 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/CorruptedRuneBlade.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class CorruptedRuneBlade : RuneBlade + { + public override int LabelNumber{ get{ return 1073540; } } // Corrupted Rune Blade + + [Constructable] + public CorruptedRuneBlade() + { + WeaponAttributes.ResistPhysicalBonus = -5; + WeaponAttributes.ResistPoisonBonus = 12; + } + + public CorruptedRuneBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/CrescentBlade.cs b/Scripts/Items/Weapons/Swords/CrescentBlade.cs new file mode 100644 index 0000000..3e92ba9 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/CrescentBlade.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26C1, 0x26CB )] + public class CrescentBlade : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } } + + public override int AosStrengthReq{ get{ return 55; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 14; } } + public override int AosSpeed{ get{ return 47; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 55; } } + public override int OldMinDamage{ get{ return 11; } } + public override int OldMaxDamage{ get{ return 14; } } + public override int OldSpeed{ get{ return 47; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 51; } } + public override int InitMaxHits{ get{ return 80; } } + + [Constructable] + public CrescentBlade() : base( 0x26C1 ) + { + Weight = 1.0; + } + + public CrescentBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/Cutlass.cs b/Scripts/Items/Weapons/Swords/Cutlass.cs new file mode 100644 index 0000000..d31882d --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Cutlass.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1441, 0x1440 )] + public class Cutlass : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.BleedAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + + public override int AosStrengthReq{ get{ return 25; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 44; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 28; } } + public override int OldSpeed{ get{ return 45; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 70; } } + + [Constructable] + public Cutlass() : base( 0x1441 ) + { + Weight = 8.0; + } + + public Cutlass( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/DarkglowScimitar.cs b/Scripts/Items/Weapons/Swords/DarkglowScimitar.cs new file mode 100644 index 0000000..db096fb --- /dev/null +++ b/Scripts/Items/Weapons/Swords/DarkglowScimitar.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class DarkglowScimitar : RadiantScimitar + { + public override int LabelNumber{ get{ return 1073542; } } // darkglow scimitar + + [Constructable] + public DarkglowScimitar() + { + WeaponAttributes.HitDispel = 10; + } + + public DarkglowScimitar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/DiseasedMachete.cs b/Scripts/Items/Weapons/Swords/DiseasedMachete.cs new file mode 100644 index 0000000..5555baa --- /dev/null +++ b/Scripts/Items/Weapons/Swords/DiseasedMachete.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class DiseasedMachete : ElvenMachete + { + public override int LabelNumber{ get{ return 1073536; } } // Diseased Machete + + [Constructable] + public DiseasedMachete() + { + WeaponAttributes.HitPoisonArea = 25; + } + + public DiseasedMachete( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/FierySpellblade.cs b/Scripts/Items/Weapons/Swords/FierySpellblade.cs new file mode 100644 index 0000000..ad5d9b1 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/FierySpellblade.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class FierySpellblade : ElvenSpellblade + { + public override int LabelNumber{ get{ return 1073515; } } // fiery spellblade + + [Constructable] + public FierySpellblade() + { + WeaponAttributes.ResistFireBonus = 5; + } + + public FierySpellblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/IcyScimitar.cs b/Scripts/Items/Weapons/Swords/IcyScimitar.cs new file mode 100644 index 0000000..1444dde --- /dev/null +++ b/Scripts/Items/Weapons/Swords/IcyScimitar.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class IcyScimitar : RadiantScimitar + { + public override int LabelNumber{ get{ return 1073543; } } // icy scimitar + + [Constructable] + public IcyScimitar() + { + WeaponAttributes.HitHarm = 15; + } + + public IcyScimitar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/IcySpellblade.cs b/Scripts/Items/Weapons/Swords/IcySpellblade.cs new file mode 100644 index 0000000..c969d60 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/IcySpellblade.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class IcySpellblade : ElvenSpellblade + { + public override int LabelNumber{ get{ return 1073514; } } // icy spellblade + + [Constructable] + public IcySpellblade() + { + WeaponAttributes.ResistColdBonus = 5; + } + + public IcySpellblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/Katana.cs b/Scripts/Items/Weapons/Swords/Katana.cs new file mode 100644 index 0000000..6649e30 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Katana.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13FF, 0x13FE )] + public class Katana : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + + public override int AosStrengthReq{ get{ return 25; } } + public override int AosMinDamage{ get{ return 11; } } + public override int AosMaxDamage{ get{ return 13; } } + public override int AosSpeed{ get{ return 46; } } + public override float MlSpeed{ get{ return 2.50f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 26; } } + public override int OldSpeed{ get{ return 58; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 90; } } + + [Constructable] + public Katana() : base( 0x13FF ) + { + Weight = 6.0; + } + + public Katana( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/KnightsWarCleaver.cs b/Scripts/Items/Weapons/Swords/KnightsWarCleaver.cs new file mode 100644 index 0000000..148cd14 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/KnightsWarCleaver.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class KnightsWarCleaver : WarCleaver + { + public override int LabelNumber{ get{ return 1073525; } } // knight's war cleaver + + [Constructable] + public KnightsWarCleaver() + { + Attributes.RegenHits = 3; + } + + public KnightsWarCleaver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/Kryss.cs b/Scripts/Items/Weapons/Swords/Kryss.cs new file mode 100644 index 0000000..3fedb5c --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Kryss.cs @@ -0,0 +1,61 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x1401, 0x1400 )] + public class Kryss : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + + public override int AosStrengthReq{ get{ return 10; } } + public override int AosMinDamage{ get{ return 10; } } + public override int AosMaxDamage{ get{ return 12; } } + public override int AosSpeed{ get{ return 53; } } + public override float MlSpeed{ get{ return 2.00f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 3; } } + public override int OldMaxDamage{ get{ return 28; } } + public override int OldSpeed{ get{ return 53; } } + + public override int DefHitSound{ get{ return 0x23C; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 90; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Kryss() : base( 0x1401 ) + { + Weight = 2.0; + } + + public Kryss( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 1.0 ) + Weight = 2.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/Lance.cs b/Scripts/Items/Weapons/Swords/Lance.cs new file mode 100644 index 0000000..f8acf46 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Lance.cs @@ -0,0 +1,82 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x26C0, 0x26CA )] + public class Lance : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.Dismount; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + + public override int AosStrengthReq{ get{ return 95; } } + public override int AosMinDamage{ get{ return 17; } } + public override int AosMaxDamage{ get{ return 18; } } + public override int AosSpeed{ get{ return 24; } } + public override float MlSpeed{ get{ return 4.50f; } } + + public override int OldStrengthReq{ get{ return 95; } } + public override int OldMinDamage{ get{ return 17; } } + public override int OldMaxDamage{ get{ return 18; } } + public override int OldSpeed{ get{ return 24; } } + + public override int DefHitSound{ get{ return 0x23C; } } + public override int DefMissSound{ get{ return 0x238; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public Lance() : base( 0x26C0 ) + { + Weight = 12.0; + } + + public Lance( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + /*** ADDED ***/ + // ALAMBIK + // Modification implementation of mounted chivalry + public override void OnHit(Mobile attacker, Mobile defender, double damageBonus) + { + Skill skill = attacker.Skills[SkillName.Chivalry]; + if (attacker.Mounted // attaquant sur un cheval + && !(defender.Mounted) // d�fenseur pas sur un cheval + && ((attacker.Direction & Direction.Running) != 0) // cours + && (skill != null && (Utility.Random(120) <= ((int)(skill.Value) + 10))) + && attacker.CheckTargetSkill(SkillName.Chivalry, defender, 0.0, 120.0) + ) + { + attacker.SendMessage("Votre attaque mont�e disloque votre adversaire!"); + defender.PlaySound(1308); + base.OnHit(attacker, defender, 1.20); // bonus 1/5 au lieu de 1/4 + } + else + { + base.OnHit(attacker, defender, 1.0); + } + } + /*** END ***/ + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/LeafbladeOfEase.cs b/Scripts/Items/Weapons/Swords/LeafbladeOfEase.cs new file mode 100644 index 0000000..e2fd06b --- /dev/null +++ b/Scripts/Items/Weapons/Swords/LeafbladeOfEase.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class LeafbladeOfEase : Leafblade + { + public override int LabelNumber{ get{ return 1073524; } } // leafblade of ease + + [Constructable] + public LeafbladeOfEase() + { + WeaponAttributes.UseBestSkill = 1; + } + + public LeafbladeOfEase( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/Longsword.cs b/Scripts/Items/Weapons/Swords/Longsword.cs new file mode 100644 index 0000000..184f9eb --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Longsword.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF61, 0xF60 )] + public class Longsword : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ConcussionBlow; } } + + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 30; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 35; } } + + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public Longsword() : base( 0xF61 ) + { + Weight = 7.0; + } + + public Longsword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/Luckblade.cs b/Scripts/Items/Weapons/Swords/Luckblade.cs new file mode 100644 index 0000000..49ff033 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Luckblade.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class Luckblade : Leafblade + { + public override int LabelNumber{ get{ return 1073522; } } // luckblade + + [Constructable] + public Luckblade() + { + Attributes.Luck = 20; + } + + public Luckblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/MacheteOfDefense.cs b/Scripts/Items/Weapons/Swords/MacheteOfDefense.cs new file mode 100644 index 0000000..3452cae --- /dev/null +++ b/Scripts/Items/Weapons/Swords/MacheteOfDefense.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class MacheteOfDefense : ElvenMachete + { + public override int LabelNumber{ get{ return 1073535; } } // machete of defense + + [Constructable] + public MacheteOfDefense() + { + Attributes.DefendChance = 5; + } + + public MacheteOfDefense( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/MagekillerAssassinSpike.cs b/Scripts/Items/Weapons/Swords/MagekillerAssassinSpike.cs new file mode 100644 index 0000000..8337bf2 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/MagekillerAssassinSpike.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class MagekillerAssassinSpike : AssassinSpike + { + public override int LabelNumber{ get{ return 1073519; } } // magekiller assassin spike + + [Constructable] + public MagekillerAssassinSpike() + { + WeaponAttributes.HitLeechMana = 16; + } + + public MagekillerAssassinSpike( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/MagekillerLeafblade.cs b/Scripts/Items/Weapons/Swords/MagekillerLeafblade.cs new file mode 100644 index 0000000..475a2b4 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/MagekillerLeafblade.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class MagekillerLeafblade : Leafblade + { + public override int LabelNumber{ get{ return 1073523; } } // maagekiller leafblade + + [Constructable] + public MagekillerLeafblade() + { + WeaponAttributes.HitLeechMana = 16; + } + + public MagekillerLeafblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/MagesRuneBlade.cs b/Scripts/Items/Weapons/Swords/MagesRuneBlade.cs new file mode 100644 index 0000000..9532a3c --- /dev/null +++ b/Scripts/Items/Weapons/Swords/MagesRuneBlade.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class MagesRuneBlade : RuneBlade + { + public override int LabelNumber{ get{ return 1073538; } } // mage's rune blade + + [Constructable] + public MagesRuneBlade() + { + Attributes.CastSpeed = 1; + } + + public MagesRuneBlade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/OrcishMachete.cs b/Scripts/Items/Weapons/Swords/OrcishMachete.cs new file mode 100644 index 0000000..15519ff --- /dev/null +++ b/Scripts/Items/Weapons/Swords/OrcishMachete.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class OrcishMachete : ElvenMachete + { + public override int LabelNumber{ get{ return 1073534; } } // Orcish Machete + + [Constructable] + public OrcishMachete() + { + Attributes.BonusInt = -5; + Attributes.WeaponDamage = 10; + } + + public OrcishMachete( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/RuneBladeOfKnowledge.cs b/Scripts/Items/Weapons/Swords/RuneBladeOfKnowledge.cs new file mode 100644 index 0000000..68f3398 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/RuneBladeOfKnowledge.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class RuneBladeOfKnowledge : RuneBlade + { + public override int LabelNumber{ get{ return 1073539; } } // rune blade of knowledge + + [Constructable] + public RuneBladeOfKnowledge() + { + Attributes.SpellDamage = 5; + } + + public RuneBladeOfKnowledge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/Runesabre.cs b/Scripts/Items/Weapons/Swords/Runesabre.cs new file mode 100644 index 0000000..55442f5 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Runesabre.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class Runesabre : RuneBlade + { + public override int LabelNumber{ get{ return 1073537; } } // runesabre + + [Constructable] + public Runesabre() + { + SkillBonuses.SetValues( 0, SkillName.MagicResist, 5.0 ); + WeaponAttributes.MageWeapon = -29; + } + + public Runesabre( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/Scimitar.cs b/Scripts/Items/Weapons/Swords/Scimitar.cs new file mode 100644 index 0000000..7ae7465 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/Scimitar.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B6, 0x13B5 )] + public class Scimitar : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.DoubleStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 25; } } + public override int AosMinDamage{ get{ return 13; } } + public override int AosMaxDamage{ get{ return 15; } } + public override int AosSpeed{ get{ return 37; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 4; } } + public override int OldMaxDamage{ get{ return 30; } } + public override int OldSpeed{ get{ return 43; } } + + public override int DefHitSound{ get{ return 0x23B; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 90; } } + + [Constructable] + public Scimitar() : base( 0x13B6 ) + { + Weight = 5.0; + } + + public Scimitar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/SerratedWarCleaver.cs b/Scripts/Items/Weapons/Swords/SerratedWarCleaver.cs new file mode 100644 index 0000000..94426d9 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/SerratedWarCleaver.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SerratedWarCleaver : WarCleaver + { + public override int LabelNumber{ get{ return 1073527; } } // serrated war cleaver + + [Constructable] + public SerratedWarCleaver() + { + Attributes.WeaponDamage = 7; + } + + public SerratedWarCleaver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/SpellbladeOfDefense.cs b/Scripts/Items/Weapons/Swords/SpellbladeOfDefense.cs new file mode 100644 index 0000000..fe7dc36 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/SpellbladeOfDefense.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SpellbladeOfDefense : ElvenSpellblade + { + public override int LabelNumber{ get{ return 1073516; } } // spellblade of defense + + [Constructable] + public SpellbladeOfDefense() + { + Attributes.DefendChance = 5; + } + + public SpellbladeOfDefense( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/ThinLongsword.cs b/Scripts/Items/Weapons/Swords/ThinLongsword.cs new file mode 100644 index 0000000..5900c54 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/ThinLongsword.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B8, 0x13B7 )] + public class ThinLongsword : BaseSword + { + public override int AosStrengthReq{ get{ return 35; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 16; } } + public override int AosSpeed{ get{ return 30; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 35; } } + + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 110; } } + + [Constructable] + public ThinLongsword() : base( 0x13B8 ) + { + Weight = 1.0; + } + + public ThinLongsword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/TrueAssassinSpike.cs b/Scripts/Items/Weapons/Swords/TrueAssassinSpike.cs new file mode 100644 index 0000000..e231ed3 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/TrueAssassinSpike.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TrueAssassinSpike : AssassinSpike + { + public override int LabelNumber{ get{ return 1073517; } } // true assassin spike + + [Constructable] + public TrueAssassinSpike() + { + Attributes.AttackChance = 4; + Attributes.WeaponDamage = 4; + } + + public TrueAssassinSpike( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/TrueLeafblade.cs b/Scripts/Items/Weapons/Swords/TrueLeafblade.cs new file mode 100644 index 0000000..f249f6c --- /dev/null +++ b/Scripts/Items/Weapons/Swords/TrueLeafblade.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TrueLeafblade : Leafblade + { + public override int LabelNumber{ get{ return 1073521; } } // true leafblade + + [Constructable] + public TrueLeafblade() + { + WeaponAttributes.ResistPoisonBonus = 5; + } + + public TrueLeafblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/TrueRadiantScimitar.cs b/Scripts/Items/Weapons/Swords/TrueRadiantScimitar.cs new file mode 100644 index 0000000..f67beca --- /dev/null +++ b/Scripts/Items/Weapons/Swords/TrueRadiantScimitar.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TrueRadiantScimitar : RadiantScimitar + { + public override int LabelNumber{ get{ return 1073541; } } // true radiant scimitar + + [Constructable] + public TrueRadiantScimitar() + { + Attributes.NightSight = 1; + } + + public TrueRadiantScimitar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/TrueSpellblade.cs b/Scripts/Items/Weapons/Swords/TrueSpellblade.cs new file mode 100644 index 0000000..d65789c --- /dev/null +++ b/Scripts/Items/Weapons/Swords/TrueSpellblade.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TrueSpellblade : ElvenSpellblade + { + public override int LabelNumber{ get{ return 1073513; } } // true spellblade + + [Constructable] + public TrueSpellblade() + { + Attributes.SpellChanneling = 1; + Attributes.CastSpeed = -1; + } + + public TrueSpellblade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/TrueWarCleaver.cs b/Scripts/Items/Weapons/Swords/TrueWarCleaver.cs new file mode 100644 index 0000000..79a0733 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/TrueWarCleaver.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TrueWarCleaver : WarCleaver + { + public override int LabelNumber{ get{ return 1073528; } } // true war cleaver + + [Constructable] + public TrueWarCleaver() + { + Attributes.WeaponDamage = 4; + Attributes.RegenHits = 2; + } + + public TrueWarCleaver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/TwinklingScimitar.cs b/Scripts/Items/Weapons/Swords/TwinklingScimitar.cs new file mode 100644 index 0000000..60daec7 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/TwinklingScimitar.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TwinklingScimitar : RadiantScimitar + { + public override int LabelNumber{ get{ return 1073544; } } // twinkling scimitar + + [Constructable] + public TwinklingScimitar() + { + Attributes.DefendChance = 6; + } + + public TwinklingScimitar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Swords/VikingSword.cs b/Scripts/Items/Weapons/Swords/VikingSword.cs new file mode 100644 index 0000000..185d585 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/VikingSword.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B9, 0x13Ba )] + public class VikingSword : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.CrushingBlow; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } } + + public override int AosStrengthReq{ get{ return 40; } } + public override int AosMinDamage{ get{ return 15; } } + public override int AosMaxDamage{ get{ return 17; } } + public override int AosSpeed{ get{ return 28; } } + public override float MlSpeed{ get{ return 3.75f; } } + + public override int OldStrengthReq{ get{ return 40; } } + public override int OldMinDamage{ get{ return 6; } } + public override int OldMaxDamage{ get{ return 34; } } + public override int OldSpeed{ get{ return 30; } } + + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 100; } } + + [Constructable] + public VikingSword() : base( 0x13B9 ) + { + Weight = 6.0; + } + + public VikingSword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Swords/WoundingAssassinSpike.cs b/Scripts/Items/Weapons/Swords/WoundingAssassinSpike.cs new file mode 100644 index 0000000..b848681 --- /dev/null +++ b/Scripts/Items/Weapons/Swords/WoundingAssassinSpike.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class WoundingAssassinSpike : AssassinSpike + { + public override int LabelNumber{ get{ return 1073520; } } // wounding assassin spike + + [Constructable] + public WoundingAssassinSpike() + { + WeaponAttributes.HitHarm = 15; + } + + public WoundingAssassinSpike( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Throwing/ThrowingAxe.cs b/Scripts/Items/Weapons/Throwing/ThrowingAxe.cs new file mode 100644 index 0000000..32ccebb --- /dev/null +++ b/Scripts/Items/Weapons/Throwing/ThrowingAxe.cs @@ -0,0 +1,179 @@ +using System; +using Server.Targeting; + +namespace Server.Items +{ + [FlipableAttribute(0xF43, 0xF44)] + public class ThrowingAxe : BaseWeapon + { + public override WeaponAbility PrimaryAbility { get { return WeaponAbility.ArmorIgnore; } } + public override WeaponAbility SecondaryAbility { get { return WeaponAbility.Disarm; } } + + public override int AosStrengthReq { get { return 20; } } + public override int AosDexterityReq { get { return 30; } } + public override int AosMinDamage { get { return 9; } } + public override int AosMaxDamage { get { return 13; } } + public override int AosSpeed { get { return 41; } } + public override float MlSpeed { get { return 3.00f; } } + + public override int OldStrengthReq { get { return 15; } } + public override int OldMinDamage { get { return 2; } } + public override int OldMaxDamage { get { return 17; } } + public override int OldSpeed { get { return 40; } } + + public override int InitMinHits { get { return 31; } } + public override int InitMaxHits { get { return 50; } } + + public override int DefHitSound { get { return 0x232; } } + public override int DefMissSound { get { return 0x23A; } } + + public override SkillName DefSkill { get { return SkillName.Swords; } } + public override WeaponType DefType { get { return WeaponType.Axe; } } + public override WeaponAnimation DefAnimation { get { return WeaponAnimation.Slash2H; } } + + + [Constructable] + public ThrowingAxe() + : base(0xF43) + { + Weight = 4.0; + Name = "Une hache de jet"; + Layer = Layer.OneHanded; + } + + public ThrowingAxe(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + // Scriptiz : gestion du double clic pour �quipper un objet + if (from.FindItemOnLayer(this.Layer) != this) + { + base.OnDoubleClick(from); + return; + } + if (from.Skills[SkillName.Throwing].Value <= 41) + { + from.SendMessage("Vous seriez incapable de toucher votre cible, mieux vaut renoncer"); + return; + } + from.SendMessage("O� voulez-vous la lancer?"); + InternalTarget t = new InternalTarget(this); + from.Target = t; + return; + + } + + private class InternalTarget : Target + { + private ThrowingAxe m_Axe; + + public InternalTarget(ThrowingAxe axe) + : base(10, false, TargetFlags.Harmful) + { + m_Axe = axe; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Axe.Deleted) + { + return; + } + + else if (!from.Items.Contains(m_Axe)) + { + from.SendMessage("You must be holding that weapon to use it."); + } + + + else if (targeted is Mobile) + { + Mobile m = (Mobile)targeted; + + if (m != from && from.HarmfulCheck(m)) + { + Direction to = from.GetDirectionTo(m); + + from.Direction = to; + + from.Animate(from.Mounted ? 26 : 9, 7, 1, true, false, 0); + + if (from.CheckTargetSkill(SkillName.Throwing, m, 40.0, 100.0)) + { + from.MovingEffect(m, 0x1BFE, 7, 1, false, false, 0x481, 0); + + int distance = (int)from.GetDistanceToSqrt(m.Location); + + int mindamage = m_Axe.MinDamage; + if (from.Dex > 100) + mindamage += 2; + + distance -= (int)from.Skills[SkillName.Tactics].Value / 20; + if (distance < 0) + distance = 0; + + int count = (int)from.Skills[SkillName.Throwing].Value / 10; + count += (int)from.Skills[SkillName.Anatomy].Value / 20; + if (distance > 6) + count -= distance - 5; + + AOS.Damage(m, from,Utility.Random(mindamage,count) - distance/2, true,0,0,0,0,0,0,100,false,false,false); + + m_Axe.MoveToWorld(m.Location, m.Map); + } + else + { + int x = 0, y = 0; + + switch (to & Direction.Mask) + { + case Direction.North: --y; break; + case Direction.South: ++y; break; + case Direction.West: --x; break; + case Direction.East: ++x; break; + case Direction.Up: --x; --y; break; + case Direction.Down: ++x; ++y; break; + case Direction.Left: --x; ++y; break; + case Direction.Right: ++x; --y; break; + } + + x += Utility.Random(-1, 3); + y += Utility.Random(-1, 3); + + x += m.X; + y += m.Y; + + m_Axe.MoveToWorld(new Point3D(x, y, m.Z), m.Map); + + from.MovingEffect(m_Axe, 0x1BFE, 7, 1, false, false, 0x481, 0); + + + + + from.SendMessage("You miss."); + } + m_Axe.HitPoints -= 1; + } + + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Throwing/ThrowingDagger.cs b/Scripts/Items/Weapons/Throwing/ThrowingDagger.cs new file mode 100644 index 0000000..39e4557 --- /dev/null +++ b/Scripts/Items/Weapons/Throwing/ThrowingDagger.cs @@ -0,0 +1,174 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0xF52, 0xF51 )] + public class ThrowingDagger : BaseWeapon + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.InfectiousStrike; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.ShadowStrike; } } + + public override int AosStrengthReq{ get{ return 10; } } + public override int AosDexterityReq { get { return 30; } } + public override int AosMinDamage{ get{ return 6; } } + public override int AosMaxDamage { get { return 8; } } + public override int AosSpeed{ get{ return 56; } } + public override float MlSpeed{ get{ return 2.25f; } } + + public override int OldStrengthReq{ get{ return 1; } } + public override int OldMinDamage{ get{ return 3; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 55; } } + + public override int InitMinHits{ get{ return 31; } } + public override int InitMaxHits{ get{ return 40; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + public override int DefHitSound { get { return 0x23B; } } + public override int DefMissSound { get { return 0x238; } } + + + public override string DefaultName + { + get { return "Une dague de jet"; } + } + + [Constructable] + public ThrowingDagger() : base( 0xF52 ) + { + Weight = 1.0; + Layer = Layer.OneHanded; + } + + public ThrowingDagger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + // Scriptiz : gestion du double clic pour �quipper un objet + if (from.FindItemOnLayer(this.Layer) != this) + { + base.OnDoubleClick(from); + return; + } + from.SendMessage("O� voulez-vous la lancer?"); + InternalTarget t = new InternalTarget( this ); + from.Target = t; + return; + + } + + private class InternalTarget : Target + { + private ThrowingDagger m_Dagger; + + public InternalTarget( ThrowingDagger dagger ) : base( 10, false, TargetFlags.Harmful ) + { + m_Dagger = dagger; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Dagger.Deleted ) + { + return; + } + else if ( !from.Items.Contains( m_Dagger ) ) + { + from.SendMessage( "You must be holding that weapon to use it." ); + } + + + else if ( targeted is Mobile ) + { + Mobile m = (Mobile)targeted; + + if ( m != from && from.HarmfulCheck( m ) ) + { + Direction to = from.GetDirectionTo( m ); + + from.Direction = to; + + from.Animate( from.Mounted ? 26 : 9, 7, 1, true, false, 0 ); + + + if ( from.CheckTargetSkill( SkillName.Throwing, m, 0.0, 60.00 ) ) + { + from.MovingEffect( m, 0x1BFE, 7, 1, false, false, 0x481, 0 ); + + int distance = (int)from.GetDistanceToSqrt(m.Location); + + int mindamage = m_Dagger.MinDamage; + if (from.Dex > 100) + mindamage += 2; + + distance -= (int)from.Skills[SkillName.Tactics].Value / 20; + if (distance < 0) + distance = 0; + + int count = (int)from.Skills[SkillName.Throwing].Value / 10; + count += (int)from.Skills[SkillName.Anatomy].Value / 20; + if (distance > 6) + count -= distance - 5; + + AOS.Damage(m, from, Utility.Random(mindamage, count) - distance / 2, true, 0, 0, 0, 0, 0, 0, 100, false, false, false); + + m_Dagger.MoveToWorld( m.Location, m.Map ); + } + else + { + int x = 0, y = 0; + + switch ( to & Direction.Mask ) + { + case Direction.North: --y; break; + case Direction.South: ++y; break; + case Direction.West: --x; break; + case Direction.East: ++x; break; + case Direction.Up: --x; --y; break; + case Direction.Down: ++x; ++y; break; + case Direction.Left: --x; ++y; break; + case Direction.Right: ++x; --y; break; + } + + x += Utility.Random( -1, 3 ); + y += Utility.Random( -1, 3 ); + + x += m.X; + y += m.Y; + + m_Dagger.MoveToWorld( new Point3D( x, y, m.Z ), m.Map ); + + from.MovingEffect( m_Dagger, 0x1BFE, 7, 1, false, false, 0x481, 0 ); + + m_Dagger.HitPoints -= 1; + + from.SendMessage( "You miss." ); + } + m_Dagger.HitPoints -= 1; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/WeaponEnums.cs b/Scripts/Items/Weapons/WeaponEnums.cs new file mode 100644 index 0000000..1656274 --- /dev/null +++ b/Scripts/Items/Weapons/WeaponEnums.cs @@ -0,0 +1,66 @@ +using System; + +namespace Server.Items +{ + public enum WeaponQuality + { + Low, + Regular, + Exceptional + } + + public enum WeaponType + { + Axe, // Axes, Hatches, etc. These can give concussion blows + Slashing, // Katana, Broadsword, Longsword, etc. Slashing weapons are poisonable + Staff, // Staves + Bashing, // War Hammers, Maces, Mauls, etc. Two-handed bashing delivers crushing blows + Piercing, // Spears, Warforks, Daggers, etc. Two-handed piercing delivers paralyzing blows + Polearm, // Halberd, Bardiche + Ranged, // Bow, Crossbows + Fists // Fists + } + + public enum WeaponDamageLevel + { + Regular, + Ruin, + Might, + Force, + Power, + Vanq + } + + public enum WeaponAccuracyLevel + { + Regular, + Accurate, + Surpassingly, + Eminently, + Exceedingly, + Supremely + } + + public enum WeaponDurabilityLevel + { + Regular, + Durable, + Substantial, + Massive, + Fortified, + Indestructible + } + + public enum WeaponAnimation + { + Slash1H = 9, + Pierce1H = 10, + Bash1H = 11, + Bash2H = 12, + Slash2H = 13, + Pierce2H = 14, + ShootBow = 18, + ShootXBow = 19, + Wrestle = 31 + } +} \ No newline at end of file diff --git a/Scripts/Items/Weapons/Wooden/AncientWildStaff.cs b/Scripts/Items/Weapons/Wooden/AncientWildStaff.cs new file mode 100644 index 0000000..cb2aaeb --- /dev/null +++ b/Scripts/Items/Weapons/Wooden/AncientWildStaff.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class AncientWildStaff : WildStaff + { + public override int LabelNumber{ get{ return 1073550; } } // ancient wild staff + + [Constructable] + public AncientWildStaff() + { + WeaponAttributes.ResistPoisonBonus = 5; + } + + public AncientWildStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Wooden/ArcanistsWildStaff.cs b/Scripts/Items/Weapons/Wooden/ArcanistsWildStaff.cs new file mode 100644 index 0000000..885fb11 --- /dev/null +++ b/Scripts/Items/Weapons/Wooden/ArcanistsWildStaff.cs @@ -0,0 +1,35 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ArcanistsWildStaff : WildStaff + { + public override int LabelNumber{ get{ return 1073549; } } // arcanist's wild staff + + [Constructable] + public ArcanistsWildStaff() + { + Attributes.BonusMana = 3; + Attributes.WeaponDamage = 3; + } + + public ArcanistsWildStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Wooden/HardenedWildStaff.cs b/Scripts/Items/Weapons/Wooden/HardenedWildStaff.cs new file mode 100644 index 0000000..f65ce57 --- /dev/null +++ b/Scripts/Items/Weapons/Wooden/HardenedWildStaff.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class HardenedWildStaff : WildStaff + { + public override int LabelNumber{ get{ return 1073552; } } // hardened wild staff + + [Constructable] + public HardenedWildStaff() + { + Attributes.WeaponDamage = 5; + } + + public HardenedWildStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Items/Weapons/Wooden/ThornedWildStaff.cs b/Scripts/Items/Weapons/Wooden/ThornedWildStaff.cs new file mode 100644 index 0000000..d36192e --- /dev/null +++ b/Scripts/Items/Weapons/Wooden/ThornedWildStaff.cs @@ -0,0 +1,34 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ThornedWildStaff : WildStaff + { + public override int LabelNumber{ get{ return 1073551; } } // thorned wild staff + + [Constructable] + public ThornedWildStaff() + { + Attributes.ReflectPhysical = 12; + } + + public ThornedWildStaff( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Misc/AOS.cs b/Scripts/Misc/AOS.cs new file mode 100644 index 0000000..86a84f9 --- /dev/null +++ b/Scripts/Misc/AOS.cs @@ -0,0 +1,1225 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.Seventh; +using Server.Spells.Ninjitsu; + +namespace Server +{ + public class AOS + { + public static void DisableStatInfluences() + { + for( int i = 0; i < SkillInfo.Table.Length; ++i ) + { + SkillInfo info = SkillInfo.Table[i]; + + info.StrScale = 0.0; + info.DexScale = 0.0; + info.IntScale = 0.0; + info.StatTotal = 0.0; + } + } + + public static int Damage( Mobile m, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, int nrgy ) + { + return Damage( m, null, damage, ignoreArmor, phys, fire, cold, pois, nrgy ); + } + + public static int Damage( Mobile m, int damage, int phys, int fire, int cold, int pois, int nrgy ) + { + return Damage( m, null, damage, phys, fire, cold, pois, nrgy ); + } + + public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy) + { + return Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, 0, 0, false, false, false); + } + + public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, int chaos) + { + return Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, chaos, 0, false, false, false); + } + + public static int Damage(Mobile m, Mobile from, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, int nrgy) + { + return Damage(m, from, damage, ignoreArmor, phys, fire, cold, pois, nrgy, 0, 0, false, false, false); + } + + public static int Damage(Mobile m, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, bool keepAlive) + { + return Damage(m, from, damage, false, phys, fire, cold, pois, nrgy, 0, 0, keepAlive, false, false); + } + + public static int Damage(Mobile m, Mobile from, int damage, bool ignoreArmor, int phys, int fire, int cold, int pois, int nrgy, int chaos, int direct, bool keepAlive, bool archer, bool deathStrike) + { + if( m == null || m.Deleted || !m.Alive || damage <= 0 ) + return 0; + + if( phys == 0 && fire == 100 && cold == 0 && pois == 0 && nrgy == 0 ) + Mobiles.MeerMage.StopEffect( m, true ); + + if( !Core.AOS ) + { + m.Damage( damage, from ); + return damage; + } + + Fix( ref phys ); + Fix( ref fire ); + Fix( ref cold ); + Fix( ref pois ); + Fix( ref nrgy ); + Fix( ref chaos ); + Fix( ref direct ); + + if ( Core.ML && chaos > 0 ) + { + switch ( Utility.Random( 5 ) ) + { + case 0: phys += chaos; break; + case 1: fire += chaos; break; + case 2: cold += chaos; break; + case 3: pois += chaos; break; + case 4: nrgy += chaos; break; + } + } + + BaseQuiver quiver = null; + + if ( archer && from != null ) + quiver = from.FindItemOnLayer( Layer.Cloak ) as BaseQuiver; + + int totalDamage; + + if( !ignoreArmor ) + { + // Armor Ignore on OSI ignores all defenses, not just physical. + int resPhys = m.PhysicalResistance; + int resFire = m.FireResistance; + int resCold = m.ColdResistance; + int resPois = m.PoisonResistance; + int resNrgy = m.EnergyResistance; + + totalDamage = damage * phys * (100 - resPhys); + totalDamage += damage * fire * (100 - resFire); + totalDamage += damage * cold * (100 - resCold); + totalDamage += damage * pois * (100 - resPois); + totalDamage += damage * nrgy * (100 - resNrgy); + + totalDamage /= 10000; + + if ( Core.ML ) + { + totalDamage += damage * direct / 100; + + if ( quiver != null ) + totalDamage += totalDamage * quiver.DamageIncrease / 100; + } + + if( totalDamage < 1 ) + totalDamage = 1; + } + else if( Core.ML && m is PlayerMobile && from is PlayerMobile ) + { + if ( quiver != null ) + damage += damage * quiver.DamageIncrease / 100; + + if (!deathStrike) + totalDamage = Math.Min(damage, 35); // Direct Damage cap of 35 + else + totalDamage = Math.Min(damage, 70); // Direct Damage cap of 70 + } + else + { + totalDamage = damage; + + if ( Core.ML && quiver != null ) + totalDamage += totalDamage * quiver.DamageIncrease / 100; + } + + #region Dragon Barding + if( (from == null || !from.Player) && m.Player && m.Mount is SwampDragon ) + { + SwampDragon pet = m.Mount as SwampDragon; + + if( pet != null && pet.HasBarding ) + { + int percent = (pet.BardingExceptional ? 20 : 10); + int absorbed = Scale( totalDamage, percent ); + + totalDamage -= absorbed; + pet.BardingHP -= absorbed; + + if( pet.BardingHP < 0 ) + { + pet.HasBarding = false; + pet.BardingHP = 0; + + m.SendLocalizedMessage( 1053031 ); // Your dragon's barding has been destroyed! + } + } + } + #endregion + + if( keepAlive && totalDamage > m.Hits ) + totalDamage = m.Hits; + + if( from != null && !from.Deleted && from.Alive ) + { + int reflectPhys = AosAttributes.GetValue( m, AosAttribute.ReflectPhysical ); + + if( reflectPhys != 0 ) + { + if( from is ExodusMinion && ((ExodusMinion)from).FieldActive || from is ExodusOverseer && ((ExodusOverseer)from).FieldActive ) + { + from.FixedParticles( 0x376A, 20, 10, 0x2530, EffectLayer.Waist ); + from.PlaySound( 0x2F4 ); + m.SendAsciiMessage( "Your weapon cannot penetrate the creature's magical barrier" ); + } + else + { + from.Damage( Scale( (damage * phys * (100 - (ignoreArmor ? 0 : m.PhysicalResistance))) / 10000, reflectPhys ), m ); + } + } + } + + m.Damage( totalDamage, from ); + return totalDamage; + } + + public static void Fix( ref int val ) + { + if( val < 0 ) + val = 0; + } + + public static int Scale( int input, int percent ) + { + return (input * percent) / 100; + } + + public static int GetStatus(Mobile from, int index) + { + switch (index) + { + // TODO: Account for buffs/debuffs + case 0: return from.GetMaxResistance(ResistanceType.Physical); + case 1: return from.GetMaxResistance(ResistanceType.Fire); + case 2: return from.GetMaxResistance(ResistanceType.Cold); + case 3: return from.GetMaxResistance(ResistanceType.Poison); + case 4: return from.GetMaxResistance(ResistanceType.Energy); + case 5: return AosAttributes.GetValue(from, AosAttribute.DefendChance); + case 6: return 45; + case 7: return AosAttributes.GetValue(from, AosAttribute.AttackChance); + case 8: return AosAttributes.GetValue(from, AosAttribute.WeaponSpeed); + case 9: return AosAttributes.GetValue(from, AosAttribute.WeaponDamage); + case 10: return AosAttributes.GetValue(from, AosAttribute.LowerRegCost); + case 11: return AosAttributes.GetValue(from, AosAttribute.SpellDamage); + case 12: return AosAttributes.GetValue(from, AosAttribute.CastRecovery); + case 13: return AosAttributes.GetValue(from, AosAttribute.CastSpeed); + case 14: return AosAttributes.GetValue(from, AosAttribute.LowerManaCost); + default: return 0; + } + } + } + + [Flags] + public enum AosAttribute + { + RegenHits=0x00000001, + RegenStam=0x00000002, + RegenMana=0x00000004, + DefendChance=0x00000008, + AttackChance=0x00000010, + BonusStr=0x00000020, + BonusDex=0x00000040, + BonusInt=0x00000080, + BonusHits=0x00000100, + BonusStam=0x00000200, + BonusMana=0x00000400, + WeaponDamage=0x00000800, + WeaponSpeed=0x00001000, + SpellDamage=0x00002000, + CastRecovery=0x00004000, + CastSpeed=0x00008000, + LowerManaCost=0x00010000, + LowerRegCost=0x00020000, + ReflectPhysical=0x00040000, + EnhancePotions=0x00080000, + Luck=0x00100000, + SpellChanneling=0x00200000, + NightSight = 0x00400000, + IncreasedKarmaLoss = 0x00800000 + } + + public sealed class AosAttributes : BaseAttributes + { + public AosAttributes( Item owner ) + : base( owner ) + { + } + + public AosAttributes( Item owner, AosAttributes other ) + : base( owner, other ) + { + } + + public AosAttributes( Item owner, GenericReader reader ) + : base( owner, reader ) + { + } + + public static int GetValue( Mobile m, AosAttribute attribute ) + { + if( !Core.AOS ) + return 0; + + List items = m.Items; + int value = 0; + + for( int i = 0; i < items.Count; ++i ) + { + Item obj = items[i]; + + if( obj is BaseWeapon ) + { + AosAttributes attrs = ((BaseWeapon)obj).Attributes; + + if( attrs != null ) + value += attrs[attribute]; + + if( attribute == AosAttribute.Luck ) + value += ((BaseWeapon)obj).GetLuckBonus(); + } + else if( obj is BaseArmor ) + { + AosAttributes attrs = ((BaseArmor)obj).Attributes; + + if( attrs != null ) + value += attrs[attribute]; + + if( attribute == AosAttribute.Luck ) + value += ((BaseArmor)obj).GetLuckBonus(); + } + else if( obj is BaseJewel ) + { + AosAttributes attrs = ((BaseJewel)obj).Attributes; + + if( attrs != null ) + value += attrs[attribute]; + } + else if( obj is BaseClothing ) + { + AosAttributes attrs = ((BaseClothing)obj).Attributes; + + if( attrs != null ) + value += attrs[attribute]; + } + else if( obj is Spellbook ) + { + AosAttributes attrs = ((Spellbook)obj).Attributes; + + if( attrs != null ) + value += attrs[attribute]; + } + else if( obj is BaseQuiver ) + { + AosAttributes attrs = ((BaseQuiver)obj).Attributes; + + if( attrs != null ) + value += attrs[attribute]; + } + else if (obj is BaseTalisman) + { + AosAttributes attrs = ((BaseTalisman)obj).Attributes; + + if (attrs != null) + value += attrs[attribute]; + } + } + + return value; + } + + public int this[AosAttribute attribute] + { + get { return GetValue( (int)attribute ); } + set { SetValue( (int)attribute, value ); } + } + + public override string ToString() + { + return "..."; + } + + public void AddStatBonuses( Mobile to ) + { + int strBonus = BonusStr; + int dexBonus = BonusDex; + int intBonus = BonusInt; + + if ( strBonus != 0 || dexBonus != 0 || intBonus != 0 ) + { + string modName = Owner.Serial.ToString(); + + if ( strBonus != 0 ) + to.AddStatMod( new StatMod( StatType.Str, modName + "Str", strBonus, TimeSpan.Zero ) ); + + if ( dexBonus != 0 ) + to.AddStatMod( new StatMod( StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero ) ); + + if ( intBonus != 0 ) + to.AddStatMod( new StatMod( StatType.Int, modName + "Int", intBonus, TimeSpan.Zero ) ); + } + + to.CheckStatTimers(); + } + + public void RemoveStatBonuses( Mobile from ) + { + string modName = Owner.Serial.ToString(); + + from.RemoveStatMod( modName + "Str" ); + from.RemoveStatMod( modName + "Dex" ); + from.RemoveStatMod( modName + "Int" ); + + from.CheckStatTimers(); + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RegenHits { get { return this[AosAttribute.RegenHits]; } set { this[AosAttribute.RegenHits] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int RegenStam { get { return this[AosAttribute.RegenStam]; } set { this[AosAttribute.RegenStam] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int RegenMana { get { return this[AosAttribute.RegenMana]; } set { this[AosAttribute.RegenMana] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DefendChance { get { return this[AosAttribute.DefendChance]; } set { this[AosAttribute.DefendChance] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int AttackChance { get { return this[AosAttribute.AttackChance]; } set { this[AosAttribute.AttackChance] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int BonusStr { get { return this[AosAttribute.BonusStr]; } set { this[AosAttribute.BonusStr] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int BonusDex { get { return this[AosAttribute.BonusDex]; } set { this[AosAttribute.BonusDex] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int BonusInt { get { return this[AosAttribute.BonusInt]; } set { this[AosAttribute.BonusInt] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int BonusHits { get { return this[AosAttribute.BonusHits]; } set { this[AosAttribute.BonusHits] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int BonusStam { get { return this[AosAttribute.BonusStam]; } set { this[AosAttribute.BonusStam] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int BonusMana { get { return this[AosAttribute.BonusMana]; } set { this[AosAttribute.BonusMana] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int WeaponDamage { get { return this[AosAttribute.WeaponDamage]; } set { this[AosAttribute.WeaponDamage] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int WeaponSpeed { get { return this[AosAttribute.WeaponSpeed]; } set { this[AosAttribute.WeaponSpeed] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpellDamage { get { return this[AosAttribute.SpellDamage]; } set { this[AosAttribute.SpellDamage] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int CastRecovery { get { return this[AosAttribute.CastRecovery]; } set { this[AosAttribute.CastRecovery] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int CastSpeed { get { return this[AosAttribute.CastSpeed]; } set { this[AosAttribute.CastSpeed] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int LowerManaCost { get { return this[AosAttribute.LowerManaCost]; } set { this[AosAttribute.LowerManaCost] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int LowerRegCost { get { return this[AosAttribute.LowerRegCost]; } set { this[AosAttribute.LowerRegCost] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ReflectPhysical { get { return this[AosAttribute.ReflectPhysical]; } set { this[AosAttribute.ReflectPhysical] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int EnhancePotions { get { return this[AosAttribute.EnhancePotions]; } set { this[AosAttribute.EnhancePotions] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Luck { get { return this[AosAttribute.Luck]; } set { this[AosAttribute.Luck] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpellChanneling { get { return this[AosAttribute.SpellChanneling]; } set { this[AosAttribute.SpellChanneling] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int NightSight { get { return this[AosAttribute.NightSight]; } set { this[AosAttribute.NightSight] = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int IncreasedKarmaLoss { get { return this[AosAttribute.IncreasedKarmaLoss]; } set { this[AosAttribute.IncreasedKarmaLoss] = value; } } + } + + [Flags] + public enum AosWeaponAttribute + { + LowerStatReq=0x00000001, + SelfRepair=0x00000002, + HitLeechHits=0x00000004, + HitLeechStam=0x00000008, + HitLeechMana=0x00000010, + HitLowerAttack=0x00000020, + HitLowerDefend=0x00000040, + HitMagicArrow=0x00000080, + HitHarm=0x00000100, + HitFireball=0x00000200, + HitLightning=0x00000400, + HitDispel=0x00000800, + HitColdArea=0x00001000, + HitFireArea=0x00002000, + HitPoisonArea=0x00004000, + HitEnergyArea=0x00008000, + HitPhysicalArea=0x00010000, + ResistPhysicalBonus=0x00020000, + ResistFireBonus=0x00040000, + ResistColdBonus=0x00080000, + ResistPoisonBonus=0x00100000, + ResistEnergyBonus=0x00200000, + UseBestSkill=0x00400000, + MageWeapon=0x00800000, + DurabilityBonus=0x01000000 + } + + public sealed class AosWeaponAttributes : BaseAttributes + { + public AosWeaponAttributes( Item owner ) + : base( owner ) + { + } + + public AosWeaponAttributes( Item owner, AosWeaponAttributes other ) + : base( owner, other ) + { + } + + public AosWeaponAttributes( Item owner, GenericReader reader ) + : base( owner, reader ) + { + } + + public static int GetValue( Mobile m, AosWeaponAttribute attribute ) + { + if( !Core.AOS ) + return 0; + + List items = m.Items; + int value = 0; + + for( int i = 0; i < items.Count; ++i ) + { + Item obj = items[i]; + + if( obj is BaseWeapon ) + { + AosWeaponAttributes attrs = ((BaseWeapon)obj).WeaponAttributes; + + if( attrs != null ) + value += attrs[attribute]; + } + else if (obj is ElvenGlasses) + { + AosWeaponAttributes attrs = ((ElvenGlasses)obj).WeaponAttributes; + + if (attrs != null) + value += attrs[attribute]; + } + } + + return value; + } + + public int this[AosWeaponAttribute attribute] + { + get { return GetValue( (int)attribute ); } + set { SetValue( (int)attribute, value ); } + } + + public override string ToString() + { + return "..."; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int LowerStatReq { get { return this[AosWeaponAttribute.LowerStatReq]; } set { this[AosWeaponAttribute.LowerStatReq] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SelfRepair { get { return this[AosWeaponAttribute.SelfRepair]; } set { this[AosWeaponAttribute.SelfRepair] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitLeechHits { get { return this[AosWeaponAttribute.HitLeechHits]; } set { this[AosWeaponAttribute.HitLeechHits] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitLeechStam { get { return this[AosWeaponAttribute.HitLeechStam]; } set { this[AosWeaponAttribute.HitLeechStam] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitLeechMana { get { return this[AosWeaponAttribute.HitLeechMana]; } set { this[AosWeaponAttribute.HitLeechMana] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitLowerAttack { get { return this[AosWeaponAttribute.HitLowerAttack]; } set { this[AosWeaponAttribute.HitLowerAttack] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitLowerDefend { get { return this[AosWeaponAttribute.HitLowerDefend]; } set { this[AosWeaponAttribute.HitLowerDefend] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitMagicArrow { get { return this[AosWeaponAttribute.HitMagicArrow]; } set { this[AosWeaponAttribute.HitMagicArrow] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitHarm { get { return this[AosWeaponAttribute.HitHarm]; } set { this[AosWeaponAttribute.HitHarm] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitFireball { get { return this[AosWeaponAttribute.HitFireball]; } set { this[AosWeaponAttribute.HitFireball] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitLightning { get { return this[AosWeaponAttribute.HitLightning]; } set { this[AosWeaponAttribute.HitLightning] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitDispel { get { return this[AosWeaponAttribute.HitDispel]; } set { this[AosWeaponAttribute.HitDispel] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitColdArea { get { return this[AosWeaponAttribute.HitColdArea]; } set { this[AosWeaponAttribute.HitColdArea] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitFireArea { get { return this[AosWeaponAttribute.HitFireArea]; } set { this[AosWeaponAttribute.HitFireArea] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitPoisonArea { get { return this[AosWeaponAttribute.HitPoisonArea]; } set { this[AosWeaponAttribute.HitPoisonArea] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitEnergyArea { get { return this[AosWeaponAttribute.HitEnergyArea]; } set { this[AosWeaponAttribute.HitEnergyArea] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HitPhysicalArea { get { return this[AosWeaponAttribute.HitPhysicalArea]; } set { this[AosWeaponAttribute.HitPhysicalArea] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ResistPhysicalBonus { get { return this[AosWeaponAttribute.ResistPhysicalBonus]; } set { this[AosWeaponAttribute.ResistPhysicalBonus] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ResistFireBonus { get { return this[AosWeaponAttribute.ResistFireBonus]; } set { this[AosWeaponAttribute.ResistFireBonus] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ResistColdBonus { get { return this[AosWeaponAttribute.ResistColdBonus]; } set { this[AosWeaponAttribute.ResistColdBonus] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ResistPoisonBonus { get { return this[AosWeaponAttribute.ResistPoisonBonus]; } set { this[AosWeaponAttribute.ResistPoisonBonus] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ResistEnergyBonus { get { return this[AosWeaponAttribute.ResistEnergyBonus]; } set { this[AosWeaponAttribute.ResistEnergyBonus] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int UseBestSkill { get { return this[AosWeaponAttribute.UseBestSkill]; } set { this[AosWeaponAttribute.UseBestSkill] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int MageWeapon { get { return this[AosWeaponAttribute.MageWeapon]; } set { this[AosWeaponAttribute.MageWeapon] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DurabilityBonus { get { return this[AosWeaponAttribute.DurabilityBonus]; } set { this[AosWeaponAttribute.DurabilityBonus] = value; } } + } + + [Flags] + public enum AosArmorAttribute + { + LowerStatReq=0x00000001, + SelfRepair=0x00000002, + MageArmor=0x00000004, + DurabilityBonus=0x00000008 + } + + public sealed class AosArmorAttributes : BaseAttributes + { + public AosArmorAttributes( Item owner ) + : base( owner ) + { + } + + public AosArmorAttributes( Item owner, GenericReader reader ) + : base( owner, reader ) + { + } + + public AosArmorAttributes( Item owner, AosArmorAttributes other ) + : base( owner, other ) + { + } + + public static int GetValue( Mobile m, AosArmorAttribute attribute ) + { + if( !Core.AOS ) + return 0; + + List items = m.Items; + int value = 0; + + for( int i = 0; i < items.Count; ++i ) + { + Item obj = items[i]; + + if( obj is BaseArmor ) + { + AosArmorAttributes attrs = ((BaseArmor)obj).ArmorAttributes; + + if( attrs != null ) + value += attrs[attribute]; + } + else if( obj is BaseClothing ) + { + AosArmorAttributes attrs = ((BaseClothing)obj).ClothingAttributes; + + if( attrs != null ) + value += attrs[attribute]; + } + } + + return value; + } + + public int this[AosArmorAttribute attribute] + { + get { return GetValue( (int)attribute ); } + set { SetValue( (int)attribute, value ); } + } + + public override string ToString() + { + return "..."; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int LowerStatReq { get { return this[AosArmorAttribute.LowerStatReq]; } set { this[AosArmorAttribute.LowerStatReq] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SelfRepair { get { return this[AosArmorAttribute.SelfRepair]; } set { this[AosArmorAttribute.SelfRepair] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int MageArmor { get { return this[AosArmorAttribute.MageArmor]; } set { this[AosArmorAttribute.MageArmor] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DurabilityBonus { get { return this[AosArmorAttribute.DurabilityBonus]; } set { this[AosArmorAttribute.DurabilityBonus] = value; } } + } + + public sealed class AosSkillBonuses : BaseAttributes + { + private List m_Mods; + + public AosSkillBonuses( Item owner ) + : base( owner ) + { + } + + public AosSkillBonuses( Item owner, GenericReader reader ) + : base( owner, reader ) + { + } + + public AosSkillBonuses( Item owner, AosSkillBonuses other ) + : base( owner, other ) + { + } + + public void GetProperties( ObjectPropertyList list ) + { + for( int i = 0; i < 5; ++i ) + { + SkillName skill; + double bonus; + + if( !GetValues( i, out skill, out bonus ) ) + continue; + list.Add(1060451 + i, "#{0}\t{1}", GetLabel(skill), bonus); + } + } + + public static int GetLabel(SkillName skill) + { + switch (skill) + { + case SkillName.EvalInt: return 1002070; // Evaluate Intelligence + case SkillName.Forensics: return 1002078; // Forensic Evaluation + case SkillName.Lockpicking: return 1002097; // Lockpicking + default: return 1044060 + (int)skill; + } + } + + public void AddTo( Mobile m ) + { + Remove(); + + for( int i = 0; i < 5; ++i ) + { + SkillName skill; + double bonus; + + if( !GetValues( i, out skill, out bonus ) ) + continue; + + if( m_Mods == null ) + m_Mods = new List(); + + SkillMod sk = new DefaultSkillMod( skill, true, bonus ); + sk.ObeyCap = true; + m.AddSkillMod( sk ); + m_Mods.Add( sk ); + } + } + + public void Remove() + { + if( m_Mods == null ) + return; + + for( int i = 0; i < m_Mods.Count; ++i ) { + + Mobile m = m_Mods[i].Owner; + m_Mods[i].Remove(); + + if ( Core.ML ) + CheckCancelMorph ( m ); + } + m_Mods = null; + } + + public bool GetValues( int index, out SkillName skill, out double bonus ) + { + int v = GetValue( 1 << index ); + int vSkill = 0; + int vBonus = 0; + + for( int i = 0; i < 16; ++i ) + { + vSkill <<= 1; + vSkill |= (v & 1); + v >>= 1; + + vBonus <<= 1; + vBonus |= (v & 1); + v >>= 1; + } + + skill = (SkillName)vSkill; + bonus = (double)vBonus / 10; + + return (bonus != 0); + } + + public void SetValues( int index, SkillName skill, double bonus ) + { + int v = 0; + int vSkill = (int)skill; + int vBonus = (int)(bonus * 10); + + for( int i = 0; i < 16; ++i ) + { + v <<= 1; + v |= (vBonus & 1); + vBonus >>= 1; + + v <<= 1; + v |= (vSkill & 1); + vSkill >>= 1; + } + + SetValue( 1 << index, v ); + } + + public SkillName GetSkill( int index ) + { + SkillName skill; + double bonus; + + GetValues( index, out skill, out bonus ); + + return skill; + } + + public void SetSkill( int index, SkillName skill ) + { + SetValues( index, skill, GetBonus( index ) ); + } + + public double GetBonus( int index ) + { + SkillName skill; + double bonus; + + GetValues( index, out skill, out bonus ); + + return bonus; + } + + public void SetBonus( int index, double bonus ) + { + SetValues( index, GetSkill( index ), bonus ); + } + + public override string ToString() + { + return "..."; + } + + public void CheckCancelMorph ( Mobile m ) + { + if ( m == null ) + return; + + double minSkill, maxSkill; + + AnimalFormContext acontext = AnimalForm.GetContext( m ); + TransformContext context = TransformationSpellHelper.GetContext( m ); + + if ( context != null ) { + Spell spell = context.Spell as Spell; + spell.GetCastSkills ( out minSkill, out maxSkill ); + if ( m.Skills[spell.CastSkill].Value < minSkill ) + TransformationSpellHelper.RemoveContext( m, context, true ); + } + if ( acontext != null ) { + int i; + for ( i = 0; i < AnimalForm.Entries.Length; ++i ) + if ( AnimalForm.Entries[i].Type == acontext.Type ) + break; + if ( m.Skills[SkillName.Ninjitsu].Value < AnimalForm.Entries[i].ReqSkill ) + AnimalForm.RemoveContext( m, true ); + } + if ( !m.CanBeginAction ( typeof ( PolymorphSpell ) ) && m.Skills[SkillName.Magery].Value < 66.1 ) { + m.BodyMod = 0; + m.HueMod = -1; + m.NameMod = null; + m.EndAction( typeof( PolymorphSpell ) ); + BaseArmor.ValidateMobile( m ); + BaseClothing.ValidateMobile( m ); + } + if ( !m.CanBeginAction ( typeof ( IncognitoSpell ) ) && m.Skills[SkillName.Magery].Value < 38.1 ) { + if ( m is PlayerMobile ) + ((PlayerMobile)m).SetHairMods( -1, -1 ); + m.BodyMod = 0; + m.HueMod = -1; + m.NameMod = null; + m.EndAction( typeof( IncognitoSpell ) ); + BaseArmor.ValidateMobile( m ); + BaseClothing.ValidateMobile( m ); + BuffInfo.RemoveBuff( m, BuffIcon.Incognito ); + } + return; + } + + + [CommandProperty( AccessLevel.GameMaster )] + public double Skill_1_Value { get { return GetBonus( 0 ); } set { SetBonus( 0, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill_1_Name { get { return GetSkill( 0 ); } set { SetSkill( 0, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public double Skill_2_Value { get { return GetBonus( 1 ); } set { SetBonus( 1, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill_2_Name { get { return GetSkill( 1 ); } set { SetSkill( 1, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public double Skill_3_Value { get { return GetBonus( 2 ); } set { SetBonus( 2, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill_3_Name { get { return GetSkill( 2 ); } set { SetSkill( 2, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public double Skill_4_Value { get { return GetBonus( 3 ); } set { SetBonus( 3, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill_4_Name { get { return GetSkill( 3 ); } set { SetSkill( 3, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public double Skill_5_Value { get { return GetBonus( 4 ); } set { SetBonus( 4, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public SkillName Skill_5_Name { get { return GetSkill( 4 ); } set { SetSkill( 4, value ); } } + } + + [Flags] + public enum AosElementAttribute + { + Physical=0x00000001, + Fire=0x00000002, + Cold=0x00000004, + Poison=0x00000008, + Energy=0x00000010, + Chaos=0x00000020, + Direct=0x00000040 + } + + public sealed class AosElementAttributes : BaseAttributes + { + public AosElementAttributes( Item owner ) + : base( owner ) + { + } + + public AosElementAttributes( Item owner, AosElementAttributes other ) + : base( owner, other ) + { + } + + public AosElementAttributes( Item owner, GenericReader reader ) + : base( owner, reader ) + { + } + + public int this[AosElementAttribute attribute] + { + get { return GetValue( (int)attribute ); } + set { SetValue( (int)attribute, value ); } + } + + public override string ToString() + { + return "..."; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Physical { get { return this[AosElementAttribute.Physical]; } set { this[AosElementAttribute.Physical] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Fire { get { return this[AosElementAttribute.Fire]; } set { this[AosElementAttribute.Fire] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Cold { get { return this[AosElementAttribute.Cold]; } set { this[AosElementAttribute.Cold] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Poison { get { return this[AosElementAttribute.Poison]; } set { this[AosElementAttribute.Poison] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Energy { get { return this[AosElementAttribute.Energy]; } set { this[AosElementAttribute.Energy] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Chaos { get { return this[AosElementAttribute.Chaos]; } set { this[AosElementAttribute.Chaos] = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Direct { get { return this[AosElementAttribute.Direct]; } set { this[AosElementAttribute.Direct] = value; } } + } + + [PropertyObject] + public abstract class BaseAttributes + { + private Item m_Owner; + private uint m_Names; + private int[] m_Values; + + private static int[] m_Empty = new int[0]; + + public bool IsEmpty { get { return (m_Names == 0); } } + public Item Owner { get { return m_Owner; } } + + public BaseAttributes( Item owner ) + { + m_Owner = owner; + m_Values = m_Empty; + } + + public BaseAttributes( Item owner, BaseAttributes other ) + { + m_Owner = owner; + m_Values = new int[other.m_Values.Length]; + other.m_Values.CopyTo( m_Values, 0 ); + m_Names = other.m_Names; + } + + public BaseAttributes( Item owner, GenericReader reader ) + { + m_Owner = owner; + + int version = reader.ReadByte(); + + switch( version ) + { + case 1: + { + m_Names = reader.ReadUInt(); + m_Values = new int[reader.ReadEncodedInt()]; + + for( int i = 0; i < m_Values.Length; ++i ) + m_Values[i] = reader.ReadEncodedInt(); + + break; + } + case 0: + { + m_Names = reader.ReadUInt(); + m_Values = new int[reader.ReadInt()]; + + for( int i = 0; i < m_Values.Length; ++i ) + m_Values[i] = reader.ReadInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (byte)1 ); // version; + + writer.Write( (uint)m_Names ); + writer.WriteEncodedInt( (int)m_Values.Length ); + + for( int i = 0; i < m_Values.Length; ++i ) + writer.WriteEncodedInt( (int)m_Values[i] ); + } + + public int GetValue( int bitmask ) + { + if( !Core.AOS ) + return 0; + + uint mask = (uint)bitmask; + + if( (m_Names & mask) == 0 ) + return 0; + + int index = GetIndex( mask ); + + if( index >= 0 && index < m_Values.Length ) + return m_Values[index]; + + return 0; + } + + public void SetValue( int bitmask, int value ) + { + if( (bitmask == (int)AosWeaponAttribute.DurabilityBonus) && (this is AosWeaponAttributes) ) + { + if( m_Owner is BaseWeapon ) + ((BaseWeapon)m_Owner).UnscaleDurability(); + } + else if( (bitmask == (int)AosArmorAttribute.DurabilityBonus) && (this is AosArmorAttributes) ) + { + if( m_Owner is BaseArmor ) + ((BaseArmor)m_Owner).UnscaleDurability(); + else if( m_Owner is BaseClothing ) + ((BaseClothing)m_Owner).UnscaleDurability(); + } + + uint mask = (uint)bitmask; + + if( value != 0 ) + { + if( (m_Names & mask) != 0 ) + { + int index = GetIndex( mask ); + + if( index >= 0 && index < m_Values.Length ) + m_Values[index] = value; + } + else + { + int index = GetIndex( mask ); + + if( index >= 0 && index <= m_Values.Length ) + { + int[] old = m_Values; + m_Values = new int[old.Length + 1]; + + for( int i = 0; i < index; ++i ) + m_Values[i] = old[i]; + + m_Values[index] = value; + + for( int i = index; i < old.Length; ++i ) + m_Values[i + 1] = old[i]; + + m_Names |= mask; + } + } + } + else if( (m_Names & mask) != 0 ) + { + int index = GetIndex( mask ); + + if( index >= 0 && index < m_Values.Length ) + { + m_Names &= ~mask; + + if( m_Values.Length == 1 ) + { + m_Values = m_Empty; + } + else + { + int[] old = m_Values; + m_Values = new int[old.Length - 1]; + + for( int i = 0; i < index; ++i ) + m_Values[i] = old[i]; + + for( int i = index + 1; i < old.Length; ++i ) + m_Values[i - 1] = old[i]; + } + } + } + + if( (bitmask == (int)AosWeaponAttribute.DurabilityBonus) && (this is AosWeaponAttributes) ) + { + if( m_Owner is BaseWeapon ) + ((BaseWeapon)m_Owner).ScaleDurability(); + } + else if( (bitmask == (int)AosArmorAttribute.DurabilityBonus) && (this is AosArmorAttributes) ) + { + if( m_Owner is BaseArmor ) + ((BaseArmor)m_Owner).ScaleDurability(); + else if( m_Owner is BaseClothing ) + ((BaseClothing)m_Owner).ScaleDurability(); + } + + if( m_Owner.Parent is Mobile ) + { + Mobile m = (Mobile)m_Owner.Parent; + + m.CheckStatTimers(); + m.UpdateResistances(); + m.Delta( MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana ); + + if( this is AosSkillBonuses ) + { + ((AosSkillBonuses)this).Remove(); + ((AosSkillBonuses)this).AddTo( m ); + } + } + + m_Owner.InvalidateProperties(); + } + + private int GetIndex( uint mask ) + { + int index = 0; + uint ourNames = m_Names; + uint currentBit = 1; + + while( currentBit != mask ) + { + if( (ourNames & currentBit) != 0 ) + ++index; + + if( currentBit == 0x80000000 ) + return -1; + + currentBit <<= 1; + } + + return index; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/AccountPrompt.cs b/Scripts/Misc/AccountPrompt.cs new file mode 100644 index 0000000..9fde920 --- /dev/null +++ b/Scripts/Misc/AccountPrompt.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Accounting; + +namespace Server.Misc +{ + public class AccountPrompt + { + public static void Initialize() + { + if ( Accounts.Count == 0 && !Core.Service ) + { + Console.WriteLine( "This server has no accounts." ); + Console.Write( "Do you want to create the owner account now? (y/n)" ); + + if( Console.ReadKey( true ).Key == ConsoleKey.Y ) + { + Console.WriteLine(); + + Console.Write( "Username: " ); + string username = Console.ReadLine(); + + Console.Write( "Password: " ); + string password = Console.ReadLine(); + + Account a = new Account( username, password ); + a.AccessLevel = AccessLevel.Owner; + + Console.WriteLine( "Account created." ); + } + else + { + Console.WriteLine(); + + Console.WriteLine( "Account not created." ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Animations.cs b/Scripts/Misc/Animations.cs new file mode 100644 index 0000000..8086a40 --- /dev/null +++ b/Scripts/Misc/Animations.cs @@ -0,0 +1,30 @@ +using System; +using Server; + +namespace Server.Misc +{ + public class Animations + { + public static void Initialize() + { + EventSink.AnimateRequest += new AnimateRequestEventHandler( EventSink_AnimateRequest ); + } + + private static void EventSink_AnimateRequest( AnimateRequestEventArgs e ) + { + Mobile from = e.Mobile; + + int action; + + switch ( e.Action ) + { + case "bow": action = 32; break; + case "salute": action = 33; break; + default: return; + } + + if ( from.Alive && !from.Mounted && from.Body.IsHuman ) + from.Animate( action, 5, 1, true, false, 0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Assistants.cs b/Scripts/Misc/Assistants.cs new file mode 100644 index 0000000..b694a51 --- /dev/null +++ b/Scripts/Misc/Assistants.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Gumps; + +namespace Server.Misc +{ + public static partial class Assistants + { + private static class Settings + { + public const bool Enabled = false; + public const bool KickOnFailure = true; // It will also kick clients running without assistants + + public static readonly TimeSpan HandshakeTimeout = TimeSpan.FromSeconds(30.0); + public static readonly TimeSpan DisconnectDelay = TimeSpan.FromSeconds(15.0); + + public const string WarningMessage = "The server was unable to negotiate features with your assistant. " + + "You must download and run an updated version of AssistUO" + + " or Razor." + + "

Make sure you've checked the option Negotiate features with server, " + + "once you have this box checked you may log in and play normally." + + "

You will be disconnected shortly."; + + public static void Configure() + { + //DisallowFeature( Features.FilterWeather ); + } + + [Flags] + public enum Features : ulong + { + None = 0, + + FilterWeather = 1 << 0, // Weather Filter + FilterLight = 1 << 1, // Light Filter + SmartTarget = 1 << 2, // Smart Last Target + RangedTarget = 1 << 3, // Range Check Last Target + AutoOpenDoors = 1 << 4, // Automatically Open Doors + DequipOnCast = 1 << 5, // Unequip Weapon on spell cast + AutoPotionEquip = 1 << 6, // Un/re-equip weapon on potion use + PoisonedChecks = 1 << 7, // Block heal If poisoned/Macro If Poisoned condition/Heal or Cure self + LoopedMacros = 1 << 8, // Disallow looping or recursive macros + UseOnceAgent = 1 << 9, // The use once agent + RestockAgent = 1 << 10, // The restock agent + SellAgent = 1 << 11, // The sell agent + BuyAgent = 1 << 12, // The buy agent + PotionHotkeys = 1 << 13, // All potion hotkeys + RandomTargets = 1 << 14, // All random target hotkeys (not target next, last target, target self) + ClosestTargets = 1 << 15, // All closest target hotkeys + OverheadHealth = 1 << 16, // Health and Mana/Stam messages shown over player's heads + AutolootAgent = 1 << 17, // The autoloot agent + BoneCutterAgent = 1 << 18, // The bone cutter agent + AdvancedMacros = 1 << 19, // Advanced macro engine + AutoRemount = 1 << 20, // Auto remount after dismount + AutoBandage = 1 << 21, // Auto bandage friends, self, last and mount option + EnemyTargetShare = 1 << 22, // Enemy target share on guild, party or alliance chat + FilterSeason = 1 << 23, // Season Filter + SpellTargetShare = 1 << 24, // Spell target share on guild, party or alliance chat + + All = ulong.MaxValue + } + + private static Features m_DisallowedFeatures = Features.None; + + public static void DisallowFeature(Features feature) + { + SetDisallowed(feature, true); + } + + public static void AllowFeature(Features feature) + { + SetDisallowed(feature, false); + } + + public static void SetDisallowed(Features feature, bool value) + { + if (value) + m_DisallowedFeatures |= feature; + else + m_DisallowedFeatures &= ~feature; + } + + public static Features DisallowedFeatures { get { return m_DisallowedFeatures; } } + } + + private static class Negotiator + { + private static Dictionary m_Dictionary = new Dictionary(); + + private static TimerStateCallback OnHandshakeTimeout_Callback = new TimerStateCallback(OnHandshakeTimeout); + private static TimerStateCallback OnForceDisconnect_Callback = new TimerStateCallback(OnForceDisconnect); + + public static void Initialize() + { + if (Settings.Enabled) + { + EventSink.Login += new LoginEventHandler(EventSink_Login); + ProtocolExtensions.Register(0xFF, true, new OnPacketReceive(OnHandshakeResponse)); + } + } + + private static void EventSink_Login(LoginEventArgs e) + { + Mobile m = e.Mobile; + + if (m != null && m.NetState != null && m.NetState.Running) + { + Timer t; + m.Send(new BeginHandshake()); + + if (Settings.KickOnFailure) + m.Send(new BeginHandshake()); + + if (m_Dictionary.TryGetValue(m, out t) && t != null) + t.Stop(); + + m_Dictionary[m] = t = Timer.DelayCall(Settings.HandshakeTimeout, OnHandshakeTimeout_Callback, m); + t.Start(); + } + } + + private static void OnHandshakeResponse(NetState state, PacketReader pvSrc) + { + pvSrc.Trace(state); + + if (state == null || state.Mobile == null || !state.Running) + return; + + Timer t; + Mobile m = state.Mobile; + + if (m_Dictionary.TryGetValue(m, out t)) + { + if (t != null) + t.Stop(); + + m_Dictionary.Remove(m); + } + } + + private static void OnHandshakeTimeout(object state) + { + Timer t = null; + Mobile m = state as Mobile; + + if (m == null) + return; + + m_Dictionary.Remove(m); + + if (!Settings.KickOnFailure) + { + Console.WriteLine("Player '{0}' failed to negotiate features.", m); + } + else if (m.NetState != null && m.NetState.Running) + { + m.SendGump(new Gumps.WarningGump(1060635, 30720, Settings.WarningMessage, 0xFFC000, 420, 250, null, null)); + + if (m.AccessLevel <= AccessLevel.Player) + { + m_Dictionary[m] = t = Timer.DelayCall(Settings.DisconnectDelay, OnForceDisconnect_Callback, m); + t.Start(); + } + } + } + + private static void OnForceDisconnect(object state) + { + if (state is Mobile) + { + Mobile m = (Mobile)state; + + if (m.NetState != null && m.NetState.Running) + m.NetState.Dispose(); + + m_Dictionary.Remove(m); + + Console.WriteLine("Player {0} kicked (Failed assistant handshake)", m); + } + } + + private sealed class BeginHandshake : ProtocolExtension + { + public BeginHandshake() + : base(0xFE, 8) + { + m_Stream.Write((uint)((ulong)Settings.DisallowedFeatures >> 32)); + m_Stream.Write((uint)((ulong)Settings.DisallowedFeatures & 0xFFFFFFFF)); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/AttackMessage.cs b/Scripts/Misc/AttackMessage.cs new file mode 100644 index 0000000..6eb3da2 --- /dev/null +++ b/Scripts/Misc/AttackMessage.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Network; + +namespace Server.Misc +{ + public class AttackMessage + { + private const string AggressorFormat = "Vous attaquez {0}!"; + private const string AggressedFormat = "{0} vous attaque!"; + private const int Hue = 0x22; + + private static TimeSpan Delay = TimeSpan.FromMinutes( 1.0 ); + + public static void Initialize() + { + EventSink.AggressiveAction += new AggressiveActionEventHandler( EventSink_AggressiveAction ); + } + + public static void EventSink_AggressiveAction( AggressiveActionEventArgs e ) + { + Mobile aggressor = e.Aggressor; + Mobile aggressed = e.Aggressed; + + if ( !aggressor.Player || !aggressed.Player ) + return; + + if ( !CheckAggressions( aggressor, aggressed ) ) + { + aggressor.LocalOverheadMessage( MessageType.Regular, Hue, true, String.Format( AggressorFormat, aggressed.Name ) ); + aggressed.LocalOverheadMessage( MessageType.Regular, Hue, true, String.Format( AggressedFormat, aggressor.Name ) ); + } + } + + public static bool CheckAggressions( Mobile m1, Mobile m2 ) + { + List list = m1.Aggressors; + + for ( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if ( info.Attacker == m2 && DateTime.Now < (info.LastCombatTime + Delay) ) + return true; + } + + list = m2.Aggressors; + + for ( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if ( info.Attacker == m1 && DateTime.Now < (info.LastCombatTime + Delay) ) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/AutoRestart.cs b/Scripts/Misc/AutoRestart.cs new file mode 100644 index 0000000..b27ee72 --- /dev/null +++ b/Scripts/Misc/AutoRestart.cs @@ -0,0 +1,90 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text; +using Server; +using Server.Commands; + +namespace Server.Misc +{ + public class AutoRestart : Timer + { + public static bool Enabled = false; // is the script enabled? + + private static TimeSpan RestartTime = TimeSpan.FromHours( 2.0 ); // time of day at which to restart + private static TimeSpan RestartDelay = TimeSpan.Zero; // how long the server should remain active before restart (period of 'server wars') + + private static TimeSpan WarningDelay = TimeSpan.FromMinutes( 1.0 ); // at what interval should the shutdown message be displayed? + + private static bool m_Restarting; + private static DateTime m_RestartTime; + + public static bool Restarting + { + get{ return m_Restarting; } + } + + public static void Initialize() + { + CommandSystem.Register( "Restart", AccessLevel.Administrator, new CommandEventHandler( Restart_OnCommand ) ); + new AutoRestart().Start(); + } + + public static void Restart_OnCommand( CommandEventArgs e ) + { + if ( m_Restarting ) + { + e.Mobile.SendMessage( "The server is already restarting." ); + } + else + { + e.Mobile.SendMessage( "You have initiated server shutdown." ); + Enabled = true; + m_RestartTime = DateTime.Now; + } + } + + public AutoRestart() : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + Priority = TimerPriority.FiveSeconds; + + m_RestartTime = DateTime.Now.Date + RestartTime; + + if ( m_RestartTime < DateTime.Now ) + m_RestartTime += TimeSpan.FromDays( 1.0 ); + } + + private void Warning_Callback() + { + World.Broadcast( 0x22, true, "The server is going down shortly." ); + } + + private void Restart_Callback() + { + Logging.RestartLog("AutoRestart.Restart_Callback()"); + + Core.Kill( true ); + } + + protected override void OnTick() + { + if ( m_Restarting || !Enabled ) + return; + + if ( DateTime.Now < m_RestartTime ) + return; + + if ( WarningDelay > TimeSpan.Zero ) + { + Warning_Callback(); + Timer.DelayCall( WarningDelay, WarningDelay, new TimerCallback( Warning_Callback ) ); + } + + AutoSave.Save(); + + m_Restarting = true; + + Timer.DelayCall( RestartDelay, new TimerCallback( Restart_Callback ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/AutoSave.cs b/Scripts/Misc/AutoSave.cs new file mode 100644 index 0000000..d81cd4f --- /dev/null +++ b/Scripts/Misc/AutoSave.cs @@ -0,0 +1,271 @@ +using System; +using System.IO; +using Server; +using Server.Commands; + +namespace Server.Misc +{ + public class AutoSave : Timer + { + private static TimeSpan m_Delay = TimeSpan.FromMinutes(15.0); // Scriptiz : default is 5 minutes + private static TimeSpan m_Warning = TimeSpan.Zero; + //private static TimeSpan m_Warning = TimeSpan.FromSeconds( 15.0 ); + + public static void Initialize() + { + new AutoSave().Start(); + CommandSystem.Register("SetSaves", AccessLevel.Administrator, new CommandEventHandler(SetSaves_OnCommand)); + } + + private static bool m_SavesEnabled = true; + + public static bool SavesEnabled + { + get { return m_SavesEnabled; } + set { m_SavesEnabled = value; } + } + + [Usage("SetSaves ")] + [Description("Enables or disables automatic shard saving.")] + public static void SetSaves_OnCommand(CommandEventArgs e) + { + if (e.Length == 1) + { + m_SavesEnabled = e.GetBoolean(0); + e.Mobile.SendMessage("Saves have been {0}.", m_SavesEnabled ? "enabled" : "disabled"); + } + else + { + e.Mobile.SendMessage("Format: SetSaves "); + } + } + + public AutoSave() + : base(m_Delay - m_Warning, m_Delay) + { + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + if (!m_SavesEnabled || AutoRestart.Restarting) + return; + + if (m_Warning == TimeSpan.Zero) + { + Save(true); + } + else + { + int s = (int)m_Warning.TotalSeconds; + int m = s / 60; + s %= 60; + + if (m > 0 && s > 0) + World.Broadcast(0x35, true, "Sauvegarde du monde dans {0} minute{1} et {2} seconde{3}.", m, m != 1 ? "s" : "", s, s != 1 ? "s" : ""); + else if (m > 0) + World.Broadcast(0x35, true, "Sauvegarde du monde dans {0} minute{1}.", m, m != 1 ? "s" : ""); + else + World.Broadcast(0x35, true, "Savegarde du monde dans {0} seconde{1}.", s, s != 1 ? "s" : ""); + + Timer.DelayCall(m_Warning, new TimerCallback(Save)); + } + } + + public static void Save() + { + AutoSave.Save(false); + } + + public static void Save(bool permitBackgroundWrite) + { + if (AutoRestart.Restarting) + return; + + World.WaitForWriteCompletion(); + + try { Backup(); } + catch (Exception e) { Console.WriteLine("WARNING: Automatic backup FAILED: {0}", e); } + + World.Save(true, permitBackgroundWrite); + } + + private static string[] m_Backups = new string[] + { + // Scriptiz : more backup (12 * 15minutes = 3 hours) + "Twelfth Backup", + "Eleventh Backup", + "Tenth Backup", + "Ninth Backup", + "Eighth Backup", + "Seventh Backup", + "Sixth Backup", + "Fifth Backup", + "Fourth Backup", + + "Third Backup", + "Second Backup", + "Most Recent" + }; + + private static void Backup() + { + // Scriptiz : two backups a day (AM & PM) + DailyBackup(); + + if (m_Backups.Length == 0) + return; + + string root = Path.Combine(Core.BaseDirectory, "Backups/Automatic"); + + if (!Directory.Exists(root)) + Directory.CreateDirectory(root); + + string[] existing = Directory.GetDirectories(root); + + for (int i = 0; i < m_Backups.Length; ++i) + { + DirectoryInfo dir = Match(existing, m_Backups[i]); + + if (dir == null) + continue; + + if (i > 0) + { + string timeStamp = FindTimeStamp(dir.Name); + + if (timeStamp != null) + { + try { dir.MoveTo(FormatDirectory(root, m_Backups[i - 1], timeStamp)); } + catch { } + } + } + else + { + try { dir.Delete(true); } + catch { } + } + } + + string saves = Path.Combine(Core.BaseDirectory, "Saves"); + + if (Directory.Exists(saves)) + Directory.Move(saves, FormatDirectory(root, m_Backups[m_Backups.Length - 1], GetTimeStamp())); + } + + + // Scriptiz : daily backup (AM & PM) + private static void DailyBackup() + { + string saves = Path.Combine(Core.BaseDirectory, "Saves"); + + if (!Directory.Exists(saves)) + return; + + string dailyDir = Path.Combine(Core.BaseDirectory, "Backups/Daily"); + + if (!Directory.Exists(dailyDir)) + Directory.CreateDirectory(dailyDir); + + // Creating daily backup + DateTime now = DateTime.Now; + string todayStr = String.Format("{0}-{1}-{2}-{3}", now.Year, now.Month, now.Day, (now.Hour < 12 ? "AM" : "PM")); + string todayDir = Path.Combine(dailyDir, todayStr); + + if (!Directory.Exists(todayDir)) + { + Console.WriteLine("Creating daily backup {0}", todayStr); + Directory.CreateDirectory(todayDir); + + CopyAll(new DirectoryInfo(saves), new DirectoryInfo(todayDir)); + } + + // Deleting old backup + DateTime del = now.Subtract(TimeSpan.FromDays(8)); + string delStr = String.Format("{0}-{1}-{2}-{3}", del.Year, del.Month, del.Day, (del.Hour < 12 ? "AM" : "PM")); + string delDir = Path.Combine(dailyDir, delStr); + + if (Directory.Exists(delDir)) + { + // Scriptiz : on garde les saves des lundis matin + if (del.DayOfWeek == DayOfWeek.Monday && del.Hour < 12) + return; + + Console.WriteLine("Deleting old daily backup {0}", delStr); + + Directory.Delete(delDir, true); + } + } + + // Scriptiz : Copy Directory And Its Content To Another Directory + private static void CopyAll(DirectoryInfo source, DirectoryInfo target) + { + // Check if the target directory exists, if not, create it. + if (Directory.Exists(target.FullName) == false) + { + Directory.CreateDirectory(target.FullName); + } + + // Copy each file into it�s new directory. + foreach (FileInfo fi in source.GetFiles()) + { + fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true); + } + + // Copy each subdirectory using recursion. + foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) + { + DirectoryInfo nextTargetSubDir = + target.CreateSubdirectory(diSourceSubDir.Name); + CopyAll(diSourceSubDir, nextTargetSubDir); + } + } + + private static DirectoryInfo Match(string[] paths, string match) + { + for (int i = 0; i < paths.Length; ++i) + { + DirectoryInfo info = new DirectoryInfo(paths[i]); + + if (info.Name.StartsWith(match)) + return info; + } + + return null; + } + + private static string FormatDirectory(string root, string name, string timeStamp) + { + return Path.Combine(root, String.Format("{0} ({1})", name, timeStamp)); + } + + private static string FindTimeStamp(string input) + { + int start = input.IndexOf('('); + + if (start >= 0) + { + int end = input.IndexOf(')', ++start); + + if (end >= start) + return input.Substring(start, end - start); + } + + return null; + } + + private static string GetTimeStamp() + { + DateTime now = DateTime.Now; + + return String.Format("{0}-{1}-{2} {3}-{4:D2}-{5:D2}", + now.Day, + now.Month, + now.Year, + now.Hour, + now.Minute, + now.Second + ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Broadcasts.cs b/Scripts/Misc/Broadcasts.cs new file mode 100644 index 0000000..e072d35 --- /dev/null +++ b/Scripts/Misc/Broadcasts.cs @@ -0,0 +1,36 @@ +using System; +using Server; + +namespace Server.Misc +{ + public class Broadcasts + { + public static void Initialize() + { + EventSink.Crashed += new CrashedEventHandler( EventSink_Crashed ); + EventSink.Shutdown += new ShutdownEventHandler( EventSink_Shutdown ); + } + + public static void EventSink_Crashed( CrashedEventArgs e ) + { + try + { + World.Broadcast( 0x35, false, "Le serveur s'est brusquement coup�." ); + } + catch + { + } + } + + public static void EventSink_Shutdown( ShutdownEventArgs e ) + { + try + { + World.Broadcast( 0x35, false, "Le serveur s'est �teint." ); + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/BuffIcons.cs b/Scripts/Misc/BuffIcons.cs new file mode 100644 index 0000000..5d7f8b2 --- /dev/null +++ b/Scripts/Misc/BuffIcons.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Network; + +namespace Server +{ + public class BuffInfo + { + public static bool Enabled { get { return Core.ML; } } + + public static void Initialize() + { + if( Enabled ) + { + EventSink.ClientVersionReceived += new ClientVersionReceivedHandler( delegate( ClientVersionReceivedArgs args ) + { + PlayerMobile pm = args.State.Mobile as PlayerMobile; + + if( pm != null ) + Timer.DelayCall( TimeSpan.Zero, pm.ResendBuffs ); + } ); + } + } + + #region Properties + private BuffIcon m_ID; + public BuffIcon ID { get { return m_ID; } } + + private int m_TitleCliloc; + public int TitleCliloc { get { return m_TitleCliloc; } } + + private int m_SecondaryCliloc; + public int SecondaryCliloc { get { return m_SecondaryCliloc; } } + + private TimeSpan m_TimeLength; + public TimeSpan TimeLength { get { return m_TimeLength; } } + + private DateTime m_TimeStart; + public DateTime TimeStart { get { return m_TimeStart; } } + + private Timer m_Timer; + public Timer Timer { get { return m_Timer; } } + + private bool m_RetainThroughDeath; + public bool RetainThroughDeath { get { return m_RetainThroughDeath; } } + + private TextDefinition m_Args; + public TextDefinition Args { get { return m_Args; } } + + #endregion + + #region Constructors + public BuffInfo( BuffIcon iconID, int titleCliloc ) + : this( iconID, titleCliloc, titleCliloc + 1 ) + { + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc ) + { + m_ID = iconID; + m_TitleCliloc = titleCliloc; + m_SecondaryCliloc = secondaryCliloc; + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m ) + : this( iconID, titleCliloc, titleCliloc + 1, length, m ) + { + } + + //Only the timed one needs to Mobile to know when to automagically remove it. + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m ) + : this( iconID, titleCliloc, secondaryCliloc ) + { + m_TimeLength = length; + m_TimeStart = DateTime.Now; + + m_Timer = Timer.DelayCall( length, new TimerCallback( + delegate + { + PlayerMobile pm = m as PlayerMobile; + + if( pm == null ) + return; + + pm.RemoveBuff( this ); + } ) ); + } + + + public BuffInfo( BuffIcon iconID, int titleCliloc, TextDefinition args ) + : this( iconID, titleCliloc, titleCliloc + 1, args ) + { + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args ) + : this( iconID, titleCliloc, secondaryCliloc ) + { + m_Args = args; + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, bool retainThroughDeath ) + : this( iconID, titleCliloc, titleCliloc + 1, retainThroughDeath ) + { + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc, bool retainThroughDeath ) + : this( iconID, titleCliloc, secondaryCliloc ) + { + m_RetainThroughDeath = retainThroughDeath; + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, TextDefinition args, bool retainThroughDeath ) + : this( iconID, titleCliloc, titleCliloc + 1, args, retainThroughDeath ) + { + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, bool retainThroughDeath ) + : this( iconID, titleCliloc, secondaryCliloc, args ) + { + m_RetainThroughDeath = retainThroughDeath; + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args ) + : this( iconID, titleCliloc, titleCliloc + 1, length, m, args ) + { + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, TextDefinition args ) + : this( iconID, titleCliloc, secondaryCliloc, length, m ) + { + m_Args = args; + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, TimeSpan length, Mobile m, TextDefinition args, bool retainThroughDeath ) + : this( iconID, titleCliloc, titleCliloc + 1, length, m, args, retainThroughDeath ) + { + } + + public BuffInfo( BuffIcon iconID, int titleCliloc, int secondaryCliloc, TimeSpan length, Mobile m, TextDefinition args, bool retainThroughDeath ) + : this( iconID, titleCliloc, secondaryCliloc, length, m ) + { + m_Args = args; + m_RetainThroughDeath = retainThroughDeath; + } + + #endregion + + #region Convenience Methods + public static void AddBuff( Mobile m, BuffInfo b ) + { + PlayerMobile pm = m as PlayerMobile; + + if( pm != null ) + pm.AddBuff( b ); + } + + public static void RemoveBuff( Mobile m, BuffInfo b ) + { + PlayerMobile pm = m as PlayerMobile; + + if( pm != null ) + pm.RemoveBuff( b ); + } + + public static void RemoveBuff( Mobile m, BuffIcon b ) + { + PlayerMobile pm = m as PlayerMobile; + + if( pm != null ) + pm.RemoveBuff( b ); + } + #endregion + } + + public enum BuffIcon : short + { + DismountPrevention=0x3E9, + NoRearm=0x3EA, + //Currently, no 0x3EB or 0x3EC + NightSight=0x3ED, //* + DeathStrike, + EvilOmen, + UnknownStandingSwirl, //Which is healing throttle & Stamina throttle? + UnknownKneelingSword, + DivineFury, //* + EnemyOfOne, //* + HidingAndOrStealth, //* + ActiveMeditation, //* + BloodOathCaster, //* + BloodOathCurse, //* + CorpseSkin, //* + Mindrot, //* + PainSpike, //* + Strangle, + GiftOfRenewal, //* + AttuneWeapon, //* + Thunderstorm, //* + EssenceOfWind, //* + EtherealVoyage, //* + GiftOfLife, //* + ArcaneEmpowerment, //* + MortalStrike, + ReactiveArmor, //* + Protection, //* + ArchProtection, + MagicReflection, //* + Incognito, //* + Disguised, + AnimalForm, + Polymorph, + Invisibility, //* + Paralyze, //* + Poison, + Bleed, + Clumsy, //* + FeebleMind, //* + Weaken, //* + Curse, //* + MassCurse, + Agility, //* + Cunning, //* + Strength, //* + Bless //* + } + + public sealed class AddBuffPacket : Packet + { + public AddBuffPacket( Mobile m, BuffInfo info ) + : this( m, info.ID, info.TitleCliloc, info.SecondaryCliloc, info.Args, (info.TimeStart != DateTime.MinValue) ? ((info.TimeStart + info.TimeLength) - DateTime.Now) : TimeSpan.Zero ) + { + } + public AddBuffPacket( Mobile mob, BuffIcon iconID, int titleCliloc, int secondaryCliloc, TextDefinition args, TimeSpan length ) + : base( 0xDF ) + { + bool hasArgs = (args != null); + + this.EnsureCapacity( (hasArgs ? (48 + args.ToString().Length * 2): 44) ); + m_Stream.Write( (int)mob.Serial ); + + + m_Stream.Write( (short)iconID ); //ID + m_Stream.Write( (short)0x1 ); //Type 0 for removal. 1 for add 2 for Data + + m_Stream.Fill( 4 ); + + m_Stream.Write( (short)iconID ); //ID + m_Stream.Write( (short)0x01 ); //Type 0 for removal. 1 for add 2 for Data + + m_Stream.Fill( 4 ); + + if( length < TimeSpan.Zero ) + length = TimeSpan.Zero; + + m_Stream.Write( (short)length.TotalSeconds ); //Time in seconds + + m_Stream.Fill( 3 ); + m_Stream.Write( (int)titleCliloc ); + m_Stream.Write( (int)secondaryCliloc ); + + if( !hasArgs ) + { + //m_Stream.Fill( 2 ); + m_Stream.Fill( 10 ); + } + else + { + m_Stream.Fill( 4 ); + m_Stream.Write( (short)0x1 ); //Unknown -> Possibly something saying 'hey, I have more data!'? + m_Stream.Fill( 2 ); + + //m_Stream.WriteLittleUniNull( "\t#1018280" ); + m_Stream.WriteLittleUniNull( String.Format( "\t{0}", args.ToString() ) ); + + m_Stream.Write( (short)0x1 ); //Even more Unknown -> Possibly something saying 'hey, I have more data!'? + m_Stream.Fill( 2 ); + } + } + } + + public sealed class RemoveBuffPacket : Packet + { + public RemoveBuffPacket( Mobile mob, BuffInfo info ) + : this( mob, info.ID ) + { + } + + public RemoveBuffPacket( Mobile mob, BuffIcon iconID ) + : base( 0xDF ) + { + this.EnsureCapacity( 13 ); + m_Stream.Write( (int)mob.Serial ); + + + m_Stream.Write( (short)iconID ); //ID + m_Stream.Write( (short)0x0 ); //Type 0 for removal. 1 for add 2 for Data + + m_Stream.Fill( 4 ); + } + } + +} diff --git a/Scripts/Misc/CharacterCreation.cs b/Scripts/Misc/CharacterCreation.cs new file mode 100644 index 0000000..03e3c28 --- /dev/null +++ b/Scripts/Misc/CharacterCreation.cs @@ -0,0 +1,1719 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Accounting; + +namespace Server.Misc +{ + public class CharacterCreation + { + public static void Initialize() + { + // Register our event handler + EventSink.CharacterCreated += new CharacterCreatedEventHandler( EventSink_CharacterCreated ); + } + + private static void AddBackpack( Mobile m ) + { + Container pack = m.Backpack; + + if ( pack == null ) + { + pack = new Backpack(); + pack.Movable = false; + + m.AddItem( pack ); + } + + PackItem( new RedBook( "a book", m.Name, 20, true ) ); + PackItem( new Gold( 1000 ) ); // Starting gold can be customized here + PackItem( new Dagger() ); + PackItem( new Candle() ); + } + + private static Item MakeNewbie( Item item ) + { + if ( !Core.AOS ) + item.LootType = LootType.Newbied; + + return item; + } + + private static void PlaceItemIn( Container parent, int x, int y, Item item ) + { + parent.AddItem( item ); + item.Location = new Point3D( x, y, 0 ); + } + + private static Item MakePotionKeg( PotionEffect type, int hue ) + { + PotionKeg keg = new PotionKeg(); + + keg.Held = 100; + keg.Type = type; + keg.Hue = hue; + + return MakeNewbie( keg ); + } + + private static void FillBankAOS( Mobile m ) + { + BankBox bank = m.BankBox; + + // The new AOS bankboxes don't have powerscrolls, they are automatically 'applied': + + for ( int i = 0; i < PowerScroll.Skills.Count; ++i ) + m.Skills[PowerScroll.Skills[ i ]].Cap = 120.0; + + m.StatCap = 250; + + + Container cont; + + + // Begin box of money + cont = new WoodenBox(); + cont.ItemID = 0xE7D; + cont.Hue = 0x489; + + PlaceItemIn( cont, 16, 51, new BankCheck( 500000 ) ); + PlaceItemIn( cont, 28, 51, new BankCheck( 250000 ) ); + PlaceItemIn( cont, 40, 51, new BankCheck( 100000 ) ); + PlaceItemIn( cont, 52, 51, new BankCheck( 100000 ) ); + PlaceItemIn( cont, 64, 51, new BankCheck( 50000 ) ); + + PlaceItemIn( cont, 16, 115, new Factions.Silver( 9000 ) ); + PlaceItemIn( cont, 34, 115, new Gold( 60000 ) ); + + PlaceItemIn( bank, 18, 169, cont ); + // End box of money + + + // Begin bag of potion kegs + cont = new Backpack(); + cont.Name = "Various Potion Kegs"; + + PlaceItemIn( cont, 45, 149, MakePotionKeg( PotionEffect.CureGreater, 0x2D ) ); + PlaceItemIn( cont, 69, 149, MakePotionKeg( PotionEffect.HealGreater, 0x499 ) ); + PlaceItemIn( cont, 93, 149, MakePotionKeg( PotionEffect.PoisonDeadly, 0x46 ) ); + PlaceItemIn( cont, 117, 149, MakePotionKeg( PotionEffect.RefreshTotal, 0x21 ) ); + PlaceItemIn( cont, 141, 149, MakePotionKeg( PotionEffect.ExplosionGreater, 0x74 ) ); + + PlaceItemIn( cont, 93, 82, new Bottle( 1000 ) ); + + PlaceItemIn( bank, 53, 169, cont ); + // End bag of potion kegs + + + // Begin bag of tools + cont = new Bag(); + cont.Name = "Tool Bag"; + + PlaceItemIn( cont, 30, 35, new TinkerTools( 1000 ) ); + PlaceItemIn( cont, 60, 35, new HousePlacementTool() ); + PlaceItemIn( cont, 90, 35, new DovetailSaw( 1000 ) ); + PlaceItemIn( cont, 30, 68, new Scissors() ); + PlaceItemIn( cont, 45, 68, new MortarPestle( 1000 ) ); + PlaceItemIn( cont, 75, 68, new ScribesPen( 1000 ) ); + PlaceItemIn( cont, 90, 68, new SmithHammer( 1000 ) ); + PlaceItemIn( cont, 30, 118, new TwoHandedAxe() ); + PlaceItemIn( cont, 60, 118, new FletcherTools( 1000 ) ); + PlaceItemIn( cont, 90, 118, new SewingKit( 1000 ) ); + + PlaceItemIn( cont, 36, 51, new RunicHammer( CraftResource.MDullcopper, 1000 ) ); + PlaceItemIn( cont, 42, 51, new RunicHammer( CraftResource.MShadow, 1000 ) ); + PlaceItemIn( cont, 48, 51, new RunicHammer( CraftResource.MCopper, 1000 ) ); + PlaceItemIn( cont, 54, 51, new RunicHammer( CraftResource.MBronze, 1000 ) ); + PlaceItemIn( cont, 61, 51, new RunicHammer( CraftResource.MGold, 1000 ) ); + PlaceItemIn( cont, 67, 51, new RunicHammer( CraftResource.MAgapite, 1000 ) ); + PlaceItemIn( cont, 73, 51, new RunicHammer( CraftResource.MVerite, 1000 ) ); + PlaceItemIn( cont, 79, 51, new RunicHammer( CraftResource.MValorite, 1000 ) ); + + PlaceItemIn( cont, 36, 55, new RunicSewingKit( CraftResource.SpinedLeather, 1000 ) ); + PlaceItemIn( cont, 42, 55, new RunicSewingKit( CraftResource.HornedLeather, 1000 ) ); + PlaceItemIn( cont, 48, 55, new RunicSewingKit( CraftResource.BarbedLeather, 1000 ) ); + + PlaceItemIn( bank, 118, 169, cont ); + // End bag of tools + + + // Begin bag of archery ammo + cont = new Bag(); + cont.Name = "Bag Of Archery Ammo"; + + PlaceItemIn( cont, 48, 76, new Arrow( 5000 ) ); + PlaceItemIn( cont, 72, 76, new Bolt( 5000 ) ); + + PlaceItemIn( bank, 118, 124, cont ); + // End bag of archery ammo + + + // Begin bag of treasure maps + cont = new Bag(); + cont.Name = "Bag Of Treasure Maps"; + + PlaceItemIn( cont, 30, 35, new TreasureMap( 1, Map.Trammel ) ); + PlaceItemIn( cont, 45, 35, new TreasureMap( 2, Map.Trammel ) ); + PlaceItemIn( cont, 60, 35, new TreasureMap( 3, Map.Trammel ) ); + PlaceItemIn( cont, 75, 35, new TreasureMap( 4, Map.Trammel ) ); + PlaceItemIn( cont, 90, 35, new TreasureMap( 5, Map.Trammel ) ); + PlaceItemIn( cont, 90, 35, new TreasureMap( 6, Map.Trammel ) ); + + PlaceItemIn( cont, 30, 50, new TreasureMap( 1, Map.Trammel ) ); + PlaceItemIn( cont, 45, 50, new TreasureMap( 2, Map.Trammel ) ); + PlaceItemIn( cont, 60, 50, new TreasureMap( 3, Map.Trammel ) ); + PlaceItemIn( cont, 75, 50, new TreasureMap( 4, Map.Trammel ) ); + PlaceItemIn( cont, 90, 50, new TreasureMap( 5, Map.Trammel ) ); + PlaceItemIn( cont, 90, 50, new TreasureMap( 6, Map.Trammel ) ); + + PlaceItemIn( cont, 55, 100, new Lockpick( 30 ) ); + PlaceItemIn( cont, 60, 100, new Pickaxe() ); + + PlaceItemIn( bank, 98, 124, cont ); + // End bag of treasure maps + + + // Begin bag of raw materials + cont = new Bag(); + cont.Hue = 0x835; + cont.Name = "Raw Materials Bag"; + + PlaceItemIn( cont, 92, 60, new BarbedLeather( 5000 ) ); + PlaceItemIn( cont, 92, 68, new HornedLeather( 5000 ) ); + PlaceItemIn( cont, 92, 76, new SpinedLeather( 5000 ) ); + PlaceItemIn( cont, 92, 84, new Leather( 5000 ) ); + + PlaceItemIn( cont, 30, 118, new Cloth( 5000 ) ); + PlaceItemIn( cont, 30, 84, new Board( 5000 ) ); + PlaceItemIn( cont, 57, 80, new BlankScroll( 500 ) ); + + PlaceItemIn( cont, 30, 35, new DullcopperIngot( 5000 ) ); + PlaceItemIn( cont, 37, 35, new ShadowIngot( 5000 ) ); + PlaceItemIn( cont, 44, 35, new CopperIngot( 5000 ) ); + PlaceItemIn( cont, 51, 35, new BronzeIngot( 5000 ) ); + PlaceItemIn( cont, 58, 35, new GoldIngot( 5000 ) ); + PlaceItemIn( cont, 65, 35, new AgapiteIngot( 5000 ) ); + PlaceItemIn( cont, 72, 35, new VeriteIngot( 5000 ) ); + PlaceItemIn( cont, 79, 35, new ValoriteIngot( 5000 ) ); + PlaceItemIn( cont, 86, 35, new IronIngot( 5000 ) ); + + PlaceItemIn( cont, 30, 59, new RedScales( 5000 ) ); + PlaceItemIn( cont, 36, 59, new YellowScales( 5000 ) ); + PlaceItemIn( cont, 42, 59, new BlackScales( 5000 ) ); + PlaceItemIn( cont, 48, 59, new GreenScales( 5000 ) ); + PlaceItemIn( cont, 54, 59, new WhiteScales( 5000 ) ); + PlaceItemIn( cont, 60, 59, new BlueScales( 5000 ) ); + + PlaceItemIn( bank, 98, 169, cont ); + // End bag of raw materials + + + // Begin bag of spell casting stuff + cont = new Backpack(); + cont.Hue = 0x480; + cont.Name = "Spell Casting Stuff"; + + PlaceItemIn( cont, 45, 105, new Spellbook( UInt64.MaxValue ) ); + PlaceItemIn( cont, 65, 105, new NecromancerSpellbook( (UInt64)0xFFFF ) ); + PlaceItemIn( cont, 85, 105, new BookOfChivalry( (UInt64)0x3FF ) ); + PlaceItemIn( cont, 105, 105, new BookOfBushido() ); //Default ctor = full + PlaceItemIn( cont, 125, 105, new BookOfNinjitsu() ); //Default ctor = full + + Runebook runebook = new Runebook( 10 ); + runebook.CurCharges = runebook.MaxCharges; + PlaceItemIn( cont, 145, 105, runebook ); + + Item toHue = new BagOfReagents( 150 ); + toHue.Hue = 0x2D; + PlaceItemIn( cont, 45, 150, toHue ); + + toHue = new BagOfNecroReagents( 150 ); + toHue.Hue = 0x488; + PlaceItemIn( cont, 65, 150, toHue ); + + PlaceItemIn( cont, 140, 150, new BagOfAllReagents( 500 ) ); + + for ( int i = 0; i < 9; ++i ) + PlaceItemIn( cont, 45 + (i * 10), 75, new RecallRune() ); + + PlaceItemIn( cont, 141, 74, new FireHorn() ); + + PlaceItemIn( bank, 78, 169, cont ); + // End bag of spell casting stuff + + + // Begin bag of ethereals + cont = new Backpack(); + cont.Hue = 0x490; + cont.Name = "Bag Of Ethy's!"; + + PlaceItemIn( cont, 45, 66, new EtherealHorse() ); + PlaceItemIn( cont, 69, 82, new EtherealOstard() ); + PlaceItemIn( cont, 93, 99, new EtherealLlama() ); + PlaceItemIn( cont, 117, 115, new EtherealKirin() ); + PlaceItemIn( cont, 45, 132, new EtherealUnicorn() ); + PlaceItemIn( cont, 69, 66, new EtherealRidgeback() ); + PlaceItemIn( cont, 93, 82, new EtherealSwampDragon() ); + PlaceItemIn( cont, 117, 99, new EtherealBeetle() ); + + PlaceItemIn( bank, 38, 124, cont ); + // End bag of ethereals + + + // Begin first bag of artifacts + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Artifacts"; + + PlaceItemIn( cont, 45, 66, new TitansHammer() ); + PlaceItemIn( cont, 69, 82, new InquisitorsResolution() ); + PlaceItemIn( cont, 93, 99, new BladeOfTheRighteous() ); + PlaceItemIn( cont, 117, 115, new ZyronicClaw() ); + + PlaceItemIn( bank, 58, 124, cont ); + // End first bag of artifacts + + + // Begin second bag of artifacts + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Artifacts"; + + PlaceItemIn( cont, 45, 66, new GauntletsOfNobility() ); + PlaceItemIn( cont, 69, 82, new MidnightBracers() ); + PlaceItemIn( cont, 93, 99, new VoiceOfTheFallenKing() ); + PlaceItemIn( cont, 117, 115, new OrnateCrownOfTheHarrower() ); + PlaceItemIn( cont, 45, 132, new HelmOfInsight() ); + PlaceItemIn( cont, 69, 66, new HolyKnightsBreastplate() ); + PlaceItemIn( cont, 93, 82, new ArmorOfFortune() ); + PlaceItemIn( cont, 117, 99, new TunicOfFire() ); + PlaceItemIn( cont, 45, 115, new LeggingsOfBane() ); + PlaceItemIn( cont, 69, 132, new ArcaneShield() ); + PlaceItemIn( cont, 93, 66, new Aegis() ); + PlaceItemIn( cont, 117, 82, new RingOfTheVile() ); + PlaceItemIn( cont, 45, 99, new BraceletOfHealth() ); + PlaceItemIn( cont, 69, 115, new RingOfTheElements() ); + PlaceItemIn( cont, 93, 132, new OrnamentOfTheMagician() ); + PlaceItemIn( cont, 117, 66, new DivineCountenance() ); + PlaceItemIn( cont, 45, 82, new JackalsCollar() ); + PlaceItemIn( cont, 69, 99, new HuntersHeaddress() ); + PlaceItemIn( cont, 93, 115, new HatOfTheMagi() ); + PlaceItemIn( cont, 117, 132, new ShadowDancerLeggings() ); + PlaceItemIn( cont, 45, 66, new SpiritOfTheTotem() ); + PlaceItemIn( cont, 69, 82, new BladeOfInsanity() ); + PlaceItemIn( cont, 93, 99, new AxeOfTheHeavens() ); + PlaceItemIn( cont, 117, 115, new TheBeserkersMaul() ); + PlaceItemIn( cont, 45, 132, new Frostbringer() ); + PlaceItemIn( cont, 69, 66, new BreathOfTheDead() ); + PlaceItemIn( cont, 93, 82, new TheDragonSlayer() ); + PlaceItemIn( cont, 117, 99, new BoneCrusher() ); + PlaceItemIn( cont, 45, 115, new StaffOfTheMagi() ); + PlaceItemIn( cont, 69, 132, new SerpentsFang() ); + PlaceItemIn( cont, 93, 66, new LegacyOfTheDreadLord() ); + PlaceItemIn( cont, 117, 82, new TheTaskmaster() ); + PlaceItemIn( cont, 45, 99, new TheDryadBow() ); + + PlaceItemIn( bank, 78, 124, cont ); + // End second bag of artifacts + + // Begin bag of minor artifacts + cont = new Backpack(); + cont.Hue = 0x48F; + cont.Name = "Bag of Minor Artifacts"; + + + PlaceItemIn( cont, 45, 66, new LunaLance() ); + PlaceItemIn( cont, 69, 82, new VioletCourage() ); + PlaceItemIn( cont, 93, 99, new CavortingClub() ); + PlaceItemIn( cont, 117, 115, new CaptainQuacklebushsCutlass() ); + PlaceItemIn( cont, 45, 132, new NightsKiss() ); + PlaceItemIn( cont, 69, 66, new ShipModelOfTheHMSCape() ); + PlaceItemIn( cont, 93, 82, new AdmiralsHeartyRum() ); + PlaceItemIn( cont, 117, 99, new CandelabraOfSouls() ); + PlaceItemIn( cont, 45, 115, new IolosLute() ); + PlaceItemIn( cont, 69, 132, new GwennosHarp() ); + PlaceItemIn( cont, 93, 66, new ArcticDeathDealer() ); + PlaceItemIn( cont, 117, 82, new EnchantedTitanLegBone() ); + PlaceItemIn( cont, 45, 99, new NoxRangersHeavyCrossbow() ); + PlaceItemIn( cont, 69, 115, new BlazeOfDeath() ); + PlaceItemIn( cont, 93, 132, new DreadPirateHat() ); + PlaceItemIn( cont, 117, 66, new BurglarsBandana() ); + PlaceItemIn( cont, 45, 82, new GoldBricks() ); + PlaceItemIn( cont, 69, 99, new AlchemistsBauble() ); + PlaceItemIn( cont, 93, 115, new PhillipsWoodenSteed() ); + PlaceItemIn( cont, 117, 132, new PolarBearMask() ); + PlaceItemIn( cont, 45, 66, new BowOfTheJukaKing() ); + PlaceItemIn( cont, 69, 82, new GlovesOfThePugilist() ); + PlaceItemIn( cont, 93, 99, new OrcishVisage() ); + PlaceItemIn( cont, 117, 115, new StaffOfPower() ); + PlaceItemIn( cont, 45, 132, new ShieldOfInvulnerability() ); + PlaceItemIn( cont, 69, 66, new HeartOfTheLion() ); + PlaceItemIn( cont, 93, 82, new ColdBlood() ); + PlaceItemIn( cont, 117, 99, new GhostShipAnchor() ); + PlaceItemIn( cont, 45, 115, new SeahorseStatuette() ); + PlaceItemIn( cont, 69, 132, new WrathOfTheDryad() ); + PlaceItemIn( cont, 93, 66, new PixieSwatter() ); + + for( int i = 0; i < 10; i++ ) + PlaceItemIn( cont, 117, 128, new MessageInABottle( Utility.RandomBool() ? Map.Trammel : Map.Felucca, 4 ) ); + + PlaceItemIn( bank, 18, 124, cont ); + + if( Core.SE ) + { + cont = new Bag(); + cont.Hue = 0x501; + cont.Name = "Tokuno Minor Artifacts"; + + PlaceItemIn( cont, 42, 70, new Exiler() ); + PlaceItemIn( cont, 38, 53, new HanzosBow() ); + PlaceItemIn( cont, 45, 40, new TheDestroyer() ); + PlaceItemIn( cont, 92, 80, new DragonNunchaku() ); + PlaceItemIn( cont, 42, 56, new PeasantsBokuto() ); + PlaceItemIn( cont, 44, 71, new TomeOfEnlightenment() ); + PlaceItemIn( cont, 35, 35, new ChestOfHeirlooms() ); + PlaceItemIn( cont, 29, 0, new HonorableSwords() ); + PlaceItemIn( cont, 49, 85, new AncientUrn() ); + PlaceItemIn( cont, 51, 58, new FluteOfRenewal() ); + PlaceItemIn( cont, 70, 51, new PigmentsOfTokuno() ); + PlaceItemIn( cont, 40, 79, new AncientSamuraiDo() ); + PlaceItemIn( cont, 51, 61, new LegsOfStability() ); + PlaceItemIn( cont, 88, 78, new GlovesOfTheSun() ); + PlaceItemIn( cont, 55, 62, new AncientFarmersKasa() ); + PlaceItemIn( cont, 55, 83, new ArmsOfTacticalExcellence() ); + PlaceItemIn( cont, 50, 85, new DaimyosHelm() ); + PlaceItemIn( cont, 52, 78, new BlackLotusHood() ); + PlaceItemIn( cont, 52, 79, new DemonForks() ); + PlaceItemIn( cont, 33, 49, new PilferedDancerFans() ); + + PlaceItemIn( bank, 58, 124, cont ); + } + + if( Core.SE ) //This bag came only after SE. + { + cont = new Bag(); + cont.Name = "Bag of Bows"; + + PlaceItemIn( cont, 31, 84, new Bow() ); + PlaceItemIn( cont, 78, 74, new CompositeBow() ); + PlaceItemIn( cont, 53, 71, new Crossbow() ); + PlaceItemIn( cont, 56, 39, new HeavyCrossbow() ); + PlaceItemIn( cont, 82, 72, new RepeatingCrossbow() ); + PlaceItemIn( cont, 49, 45, new Yumi() ); + + for( int i = 0; i < cont.Items.Count; i++ ) + { + BaseRanged bow = cont.Items[i] as BaseRanged; + + if( bow != null ) + { + bow.Attributes.WeaponSpeed = 35; + bow.Attributes.WeaponDamage = 35; + } + } + + PlaceItemIn( bank, 108, 135, cont ); + } + } + + private static void FillBankbox( Mobile m ) + { + if ( Core.AOS ) + { + FillBankAOS( m ); + return; + } + + BankBox bank = m.BankBox; + + bank.DropItem( new BankCheck( 1000000 ) ); + + // Full spellbook + Spellbook book = new Spellbook(); + + book.Content = ulong.MaxValue; + + bank.DropItem( book ); + + Bag bag = new Bag(); + + for ( int i = 0; i < 5; ++i ) + bag.DropItem( new Moonstone( MoonstoneType.Felucca ) ); + + // Felucca moonstones + bank.DropItem( bag ); + + bag = new Bag(); + + for ( int i = 0; i < 5; ++i ) + bag.DropItem( new Moonstone( MoonstoneType.Trammel ) ); + + // Trammel moonstones + bank.DropItem( bag ); + + // Treasure maps + bank.DropItem( new TreasureMap( 1, Map.Trammel ) ); + bank.DropItem( new TreasureMap( 2, Map.Trammel ) ); + bank.DropItem( new TreasureMap( 3, Map.Trammel ) ); + bank.DropItem( new TreasureMap( 4, Map.Trammel ) ); + bank.DropItem( new TreasureMap( 5, Map.Trammel ) ); + + // Bag containing 50 of each reagent + bank.DropItem( new BagOfReagents( 50 ) ); + + // Craft tools + bank.DropItem( MakeNewbie( new Scissors() ) ); + bank.DropItem( MakeNewbie( new SewingKit( 1000 ) ) ); + bank.DropItem( MakeNewbie( new SmithHammer( 1000 ) ) ); + bank.DropItem( MakeNewbie( new FletcherTools( 1000 ) ) ); + bank.DropItem( MakeNewbie( new DovetailSaw( 1000 ) ) ); + bank.DropItem( MakeNewbie( new MortarPestle( 1000 ) ) ); + bank.DropItem( MakeNewbie( new ScribesPen( 1000 ) ) ); + bank.DropItem( MakeNewbie( new TinkerTools( 1000 ) ) ); + + // A few dye tubs + bank.DropItem( new Dyes() ); + bank.DropItem( new DyeTub() ); + bank.DropItem( new DyeTub() ); + bank.DropItem( new BlackDyeTub() ); + + DyeTub darkRedTub = new DyeTub(); + + darkRedTub.DyedHue = 0x485; + darkRedTub.Redyable = false; + + bank.DropItem( darkRedTub ); + + // Some food + bank.DropItem( MakeNewbie( new Apple( 1000 ) ) ); + + // Resources + bank.DropItem( MakeNewbie( new Feather( 1000 ) ) ); + bank.DropItem( MakeNewbie( new BoltOfCloth( 1000 ) ) ); + bank.DropItem( MakeNewbie( new BlankScroll( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Hides( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Bandage( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Bottle( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Log( 1000 ) ) ); + + bank.DropItem( MakeNewbie( new IronIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new DullcopperIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new ShadowIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new CopperIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new BronzeIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new GoldIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new AgapiteIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new VeriteIngot( 5000 ) ) ); + bank.DropItem( MakeNewbie( new ValoriteIngot( 5000 ) ) ); + + // Reagents + bank.DropItem( MakeNewbie( new BlackPearl( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Bloodmoss( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Garlic( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Ginseng( 1000 ) ) ); + bank.DropItem( MakeNewbie( new MandrakeRoot( 1000 ) ) ); + bank.DropItem( MakeNewbie( new Nightshade( 1000 ) ) ); + bank.DropItem( MakeNewbie( new SulfurousAsh( 1000 ) ) ); + bank.DropItem( MakeNewbie( new SpidersSilk( 1000 ) ) ); + + // Some extra starting gold + bank.DropItem( MakeNewbie( new Gold( 9000 ) ) ); + + // 5 blank recall runes + for ( int i = 0; i < 5; ++i ) + bank.DropItem( MakeNewbie( new RecallRune() ) ); + + AddPowerScrolls( bank ); + } + + private static void AddPowerScrolls( BankBox bank ) + { + Bag bag = new Bag(); + + for ( int i = 0; i < PowerScroll.Skills.Count; ++i ) + bag.DropItem( new PowerScroll( PowerScroll.Skills[i], 120.0 ) ); + + bag.DropItem( new StatCapScroll( 250 ) ); + + bank.DropItem( bag ); + } + + private static void AddShirt( Mobile m, int shirtHue ) + { + int hue = Utility.ClipDyedHue( shirtHue & 0x3FFF ); + + if ( m.Race == Race.Elf ) + { + EquipItem( new ElvenShirt( hue ), true ); + } + else + { + switch ( Utility.Random( 3 ) ) + { + case 0: EquipItem( new Shirt( hue ), true ); break; + case 1: EquipItem( new FancyShirt( hue ), true ); break; + case 2: EquipItem( new Doublet( hue ), true ); break; + } + } + } + + private static void AddPants( Mobile m, int pantsHue ) + { + int hue = Utility.ClipDyedHue( pantsHue & 0x3FFF ); + + if ( m.Race == Race.Elf ) + { + EquipItem( new ElvenPants( hue ), true ); + } + else + { + if ( m.Female ) + { + switch ( Utility.Random( 2 ) ) + { + case 0: EquipItem( new Skirt( hue ), true ); break; + case 1: EquipItem( new Kilt( hue ), true ); break; + } + } + else + { + switch ( Utility.Random( 2 ) ) + { + case 0: EquipItem( new LongPants( hue ), true ); break; + case 1: EquipItem( new ShortPants( hue ), true ); break; + } + } + } + } + + private static void AddShoes( Mobile m ) + { + if( m.Race == Race.Elf ) + EquipItem( new ElvenBoots(), true ); + else + EquipItem( new Shoes( Utility.RandomYellowHue() ), true ); + } + + private static Mobile CreateMobile( Account a ) + { + if ( a.Count >= a.Limit ) + return null; + + for ( int i = 0; i < a.Length; ++i ) + { + if ( a[i] == null ) + return (a[i] = new PlayerMobile()); + } + + return null; + } + + private static void EventSink_CharacterCreated( CharacterCreatedEventArgs args ) + { + if ( !VerifyProfession( args.Profession ) ) + args.Profession = 0; + + NetState state = args.State; + + if (state == null) + return; + + Mobile newChar = CreateMobile(args.Account as Account); + + if (newChar == null) + { + Console.WriteLine("Login: {0}: Character creation failed, account full", state); + return; + } + + args.Mobile = newChar; + m_Mobile = newChar; + + newChar.Player = true; + newChar.AccessLevel = args.Account.AccessLevel; + newChar.Female = args.Female; + newChar.Body = newChar.Female ? 0x191 : 0x190; + + /*if( Core.Expansion >= args.Race.RequiredExpansion ) + newChar.Race = args.Race; //Sets body + else + newChar.Race = Race.DefaultRace;*/ + newChar.Race = args.Race; + if (newChar.Race != Race.Human) + newChar.Race = Race.Human; + + //newChar.Hue = Utility.ClipSkinHue( args.Hue & 0x3FFF ) | 0x8000; + newChar.Hue = newChar.Race.ClipSkinHue( args.Hue & 0x3FFF ) | 0x8000; + + newChar.Hunger = 20; + + bool young = false; + + if ( newChar is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile) newChar; + + pm.Profession = args.Profession; + + if ( pm.AccessLevel == AccessLevel.Player && ((Account)pm.Account).Young ) + young = pm.Young = false ; + } + + SetName( newChar, args.Name ); + + AddBackpack( newChar ); + + SetStats( newChar, state, args.Str, args.Dex, args.Int ); + SetSkills( newChar, args.Skills, args.Profession ); + + Race race = newChar.Race; + + if( race.ValidateHair( newChar, args.HairID ) ) + { + newChar.HairItemID = args.HairID; + newChar.HairHue = race.ClipHairHue( args.HairHue & 0x3FFF ); + } + + if( race.ValidateFacialHair( newChar, args.BeardID ) ) + { + newChar.FacialHairItemID = args.BeardID; + newChar.FacialHairHue = race.ClipHairHue( args.BeardHue & 0x3FFF ); + } + + if ( args.Profession <= 3 ) + { + AddShirt( newChar, args.ShirtHue ); + AddPants( newChar, args.PantsHue ); + AddShoes( newChar ); + } + + if( TestCenter.Enabled ) + FillBankbox( newChar ); + + if ( young ) + { + NewPlayerTicket ticket = new NewPlayerTicket(); + ticket.Owner = newChar; + newChar.BankBox.DropItem( ticket ); + } + + CityInfo city = GetStartLocation( args, young ); + + newChar.MoveToWorld( city.Location, city.Map ); + + Console.WriteLine( "Login: {0}: New character being created (account={1})", state, args.Account.Username ); + Console.WriteLine( " - Character: {0} (serial={1})", newChar.Name, newChar.Serial ); + Console.WriteLine( " - Started: {0} {1} in {2}", city.City, city.Location, city.Map.ToString() ); + + new WelcomeTimer( newChar ).Start(); + } + + public static bool VerifyProfession( int profession ) + { + if ( profession < 0 ) + return false; + else if ( profession < 4 ) + return true; + else if ( Core.AOS && profession < 6 ) + return true; + else if ( Core.SE && profession < 8 ) + return true; + else + return false; + } + + private class BadStartMessage : Timer + { + Mobile m_Mobile; + int m_Message; + public BadStartMessage( Mobile m, int message ) : base( TimeSpan.FromSeconds ( 3.5 ) ) + { + m_Mobile = m; + m_Message = message; + this.Start(); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( m_Message ); + } + } + + private static readonly CityInfo m_NewHavenInfo = new CityInfo( "New Haven", "The Bountiful Harvest Inn", 3503, 2574, 14, Map.Trammel ); + + private static CityInfo GetStartLocation( CharacterCreatedEventArgs args, bool isYoung ) + { + + if (Core.ML) + { + //if( args.State != null && args.State.NewHaven ) + return m_NewHavenInfo; //We don't get the client Version until AFTER Character creation + + //return args.City; TODO: Uncomment when the old quest system is actually phased out + } + + bool useHaven = isYoung; + + ClientFlags flags = args.State == null ? ClientFlags.None : args.State.Flags; + Mobile m = args.Mobile; + + switch ( args.Profession ) + { + case 4: //Necro + { + if ( (flags & ClientFlags.Malas) != 0 ) + { + return new CityInfo( "Umbra", "Mardoth's Tower", 2114, 1301, -50, Map.Malas ); + } + else + { + useHaven = true; + + new BadStartMessage( m, 1062205 ); + /* + * Unfortunately you are playing on a *NON-Age-Of-Shadows* game + * installation and cannot be transported to Malas. + * You will not be able to take your new player quest in Malas + * without an AOS client. You are now being taken to the city of + * Haven on the Trammel facet. + * */ + } + + break; + } + case 5: //Paladin + { + return m_NewHavenInfo; + } + case 6: //Samurai + { + if ( (flags & ClientFlags.Tokuno) != 0 ) + { + return new CityInfo( "Samurai DE", "Haoti's Grounds", 368, 780, -1, Map.Malas ); + } + else + { + useHaven = true; + + new BadStartMessage( m, 1063487 ); + /* + * Unfortunately you are playing on a *NON-Samurai-Empire* game + * installation and cannot be transported to Tokuno. + * You will not be able to take your new player quest in Tokuno + * without an SE client. You are now being taken to the city of + * Haven on the Trammel facet. + * */ + } + + break; + } + case 7: //Ninja + { + if ( (flags & ClientFlags.Tokuno) != 0 ) + { + return new CityInfo( "Ninja DE", "Enimo's Residence", 414, 823, -1, Map.Malas ); + } + else + { + useHaven = true; + + new BadStartMessage( m, 1063487 ); + /* + * Unfortunately you are playing on a *NON-Samurai-Empire* game + * installation and cannot be transported to Tokuno. + * You will not be able to take your new player quest in Tokuno + * without an SE client. You are now being taken to the city of + * Haven on the Trammel facet. + * */ + } + + break; + } + } + + if (useHaven) + return m_NewHavenInfo; + else + //Plume Modif here + return m_NewHavenInfo; + //return args.City; + } + + private static void FixStats(ref int str, ref int dex, ref int intel, int max) + { + int vMax = max - 30; + + int vStr = str - 10; + int vDex = dex - 10; + int vInt = intel - 10; + + if (vStr < 0) + vStr = 0; + + if (vDex < 0) + vDex = 0; + + if (vInt < 0) + vInt = 0; + + int total = vStr + vDex + vInt; + + if (total == 0 || total == vMax) + return; + + double scalar = vMax / (double)total; + + vStr = (int)(vStr * scalar); + vDex = (int)(vDex * scalar); + vInt = (int)(vInt * scalar); + + FixStat(ref vStr, (vStr + vDex + vInt) - vMax, vMax); + FixStat(ref vDex, (vStr + vDex + vInt) - vMax, vMax); + FixStat(ref vInt, (vStr + vDex + vInt) - vMax, vMax); + + str = vStr + 10; + dex = vDex + 10; + intel = vInt + 10; + } + + private static void FixStat(ref int stat, int diff, int max) + { + stat += diff; + + if (stat < 0) + stat = 0; + else if (stat > max) + stat = max; + } + + private static void SetStats(Mobile m, NetState state, int str, int dex, int intel) + { + int max = state.NewCharacterCreation ? 90 : 80; + + FixStats(ref str, ref dex, ref intel, max); + + if (str < 10 || str > 60 || dex < 10 || dex > 60 || intel < 10 || intel > 60 || (str + dex + intel) != max) + { + str = 10; + dex = 10; + intel = 10; + } + + m.InitStats(str, dex, intel); + } + + private static void SetName(Mobile m, string name) + { + name = name.Trim(); + + if (!NameVerification.Validate(name, 2, 16, true, false, true, 1, NameVerification.SpaceDashPeriodQuote)) + name = "Generic Player"; + + m.Name = name; + } + + private static bool ValidSkills(SkillNameValue[] skills) + { + int total = 0; + + for (int i = 0; i < skills.Length; ++i) + { + if (skills[i].Value < 0 || skills[i].Value > 50) + return false; + + total += skills[i].Value; + + for (int j = i + 1; j < skills.Length; ++j) + { + if (skills[j].Value > 0 && skills[j].Name == skills[i].Name) + return false; + } + } + + return (total == 100 || total == 120); + } + + private static Mobile m_Mobile; + + private static void SetSkills( Mobile m, SkillNameValue[] skills, int prof ) + { + switch ( prof ) + { + case 1: // Warrior + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.Anatomy, 30 ), + new SkillNameValue( SkillName.Healing, 45 ), + new SkillNameValue( SkillName.Swords, 35 ), + new SkillNameValue( SkillName.Tactics, 50 ) + }; + + break; + } + case 2: // Magician + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.EvalInt, 30 ), + new SkillNameValue( SkillName.Wrestling, 30 ), + new SkillNameValue( SkillName.Magery, 50 ), + new SkillNameValue( SkillName.Meditation, 50 ) + }; + + break; + } + case 3: // Blacksmith + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.Mining, 30 ), + new SkillNameValue( SkillName.ArmsLore, 30 ), + new SkillNameValue( SkillName.Blacksmith, 50 ), + new SkillNameValue( SkillName.Tinkering, 50 ) + }; + + break; + } + case 4: // Necromancer + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.Necromancy, 50 ), + new SkillNameValue( SkillName.Focus, 30 ), + new SkillNameValue( SkillName.SpiritSpeak, 30 ), + new SkillNameValue( SkillName.Swords, 30 ), + new SkillNameValue( SkillName.Tactics, 20 ) + }; + + break; + } + case 5: // Paladin + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.Chivalry, 51 ), + new SkillNameValue( SkillName.Swords, 49 ), + new SkillNameValue( SkillName.Focus, 30 ), + new SkillNameValue( SkillName.Tactics, 30 ) + }; + + break; + } + case 6: //Samurai + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.Bushido, 50 ), + new SkillNameValue( SkillName.Swords, 50 ), + new SkillNameValue( SkillName.Anatomy, 30 ), + new SkillNameValue( SkillName.Healing, 30 ) + }; + break; + } + case 7: //Ninja + { + skills = new SkillNameValue[] + { + new SkillNameValue( SkillName.Ninjitsu, 50 ), + new SkillNameValue( SkillName.Hiding, 50 ), + new SkillNameValue( SkillName.Fencing, 30 ), + new SkillNameValue( SkillName.Stealth, 30 ) + }; + break; + } + default: + { + if ( !ValidSkills( skills ) ) + return; + + break; + } + } + + bool addSkillItems = true; + bool elf = (m.Race == Race.Elf); + + switch ( prof ) + { + case 1: // Warrior + { + if ( elf ) + EquipItem( new LeafChest() ); + else + EquipItem( new LeatherChest() ); + break; + } + case 4: // Necromancer + { + /*Container regs = new BagOfNecroReagents( 50 ); + + if ( !Core.AOS ) + { + foreach ( Item item in regs.Items ) + item.LootType = LootType.Newbied; + } + + PackItem( regs ); + + regs.LootType = LootType.Regular;*/ + + + EquipItem( new BoneHelm() ); + + if ( elf ) + { + EquipItem( new ElvenMachete() ); + EquipItem( NecroHue( new LeafChest() ) ); + EquipItem( NecroHue( new LeafArms() ) ); + EquipItem( NecroHue( new LeafGloves() ) ); + EquipItem( NecroHue( new LeafGorget() ) ); + EquipItem( NecroHue( new LeafGorget() ) ); + EquipItem( NecroHue( new ElvenPants() ) ); //TODO: Verify the pants + EquipItem( new ElvenBoots() ); + } + else + { + EquipItem( new BoneHarvester() ); + EquipItem( NecroHue( new LeatherChest() ) ); + EquipItem( NecroHue( new LeatherArms() ) ); + EquipItem( NecroHue( new LeatherGloves() ) ); + EquipItem( NecroHue( new LeatherGorget() ) ); + EquipItem( NecroHue( new LeatherLegs() ) ); + EquipItem( NecroHue( new Skirt() ) ); + EquipItem( new Sandals( 0x8FD ) ); + } + + /*Spellbook book = new NecromancerSpellbook( (ulong)0x8981 ); // animate dead, evil omen, pain spike, summon familiar, wraith form + + PackItem( book ); + + book.LootType = LootType.Blessed;*/ + + addSkillItems = false; + + break; + } + case 5: // Paladin + { + if ( elf ) + { + EquipItem( new ElvenMachete() ); + EquipItem( new WingedHelm() ); + EquipItem( new LeafGorget() ); + EquipItem( new LeafArms() ); + EquipItem( new LeafChest() ); + EquipItem( new LeafLegs() ); + EquipItem( new ElvenBoots() ); //Verify hue + } + else + { + EquipItem( new Broadsword() ); + EquipItem( new Helmet() ); + EquipItem( new PlateGorget() ); + EquipItem( new RingmailArms() ); + EquipItem( new RingmailChest() ); + EquipItem( new RingmailLegs() ); + EquipItem( new ThighBoots( 0x748 ) ); + EquipItem( new Cloak( 0xCF ) ); + EquipItem( new BodySash( 0xCF ) ); + } + + /*Spellbook book = new BookOfChivalry( (ulong)0x3FF ); + + PackItem( book ); + + book.LootType = LootType.Blessed;*/ + + addSkillItems = false; + + break; + } + + case 6: // Samurai + { + addSkillItems = false; + EquipItem( new HakamaShita( 0x2C3 ) ); + EquipItem( new Hakama( 0x2C3 ) ); + EquipItem( new SamuraiTabi( 0x2C3 ) ); + EquipItem( new TattsukeHakama( 0x22D ) ); + EquipItem( new Bokuto() ); + + if ( elf ) + EquipItem( new RavenHelm() ); + else + EquipItem( new LeatherJingasa() ); + + PackItem( new Scissors() ); + PackItem( new Bandage( 50 ) ); + + /*Spellbook book = new BookOfBushido(); + PackItem( book );*/ + + break; + } + case 7: // Ninja + { + addSkillItems = false; + EquipItem( new Kasa() ); + + int[] hues = new int[] { 0x1A8, 0xEC, 0x99, 0x90, 0xB5, 0x336, 0x89 }; + //TODO: Verify that's ALL the hues for that above. + + EquipItem( new TattsukeHakama( hues[Utility.Random(hues.Length)] ) ); + + EquipItem( new HakamaShita( 0x2C3 ) ); + EquipItem( new NinjaTabi( 0x2C3 ) ); + + if ( elf ) + EquipItem( new AssassinSpike() ); + else + EquipItem( new Tekagi() ); + + PackItem( new SmokeBomb() ); + + /*Spellbook book = new BookOfNinjitsu(); + PackItem( book );*/ + + break; + } + } + + for ( int i = 0; i < skills.Length; ++i ) + { + SkillNameValue snv = skills[i]; + + if ( snv.Value > 0 && ( snv.Name != SkillName.Stealth || prof == 7 ) && snv.Name != SkillName.RemoveTrap && snv.Name != SkillName.Spellweaving ) + { + Skill skill = m.Skills[snv.Name]; + + if ( skill != null ) + { + skill.BaseFixedPoint = snv.Value * 10; + + if ( addSkillItems ) + AddSkillItems( snv.Name, m ); + } + } + } + } + + private static void EquipItem( Item item ) + { + EquipItem( item, false ); + } + + private static void EquipItem( Item item, bool mustEquip ) + { + if ( !Core.AOS ) + item.LootType = LootType.Newbied; + + if ( m_Mobile != null && m_Mobile.EquipItem( item ) ) + return; + + Container pack = m_Mobile.Backpack; + + if ( !mustEquip && pack != null ) + pack.DropItem( item ); + else + item.Delete(); + } + + private static void PackItem( Item item ) + { + if ( !Core.AOS ) + item.LootType = LootType.Newbied; + + Container pack = m_Mobile.Backpack; + + if ( pack != null ) + pack.DropItem( item ); + else + item.Delete(); + } + + private static void PackInstrument() + { + switch ( Utility.Random( 6 ) ) + { + case 0: PackItem( new Drums() ); break; + case 1: PackItem( new Harp() ); break; + case 2: PackItem( new LapHarp() ); break; + case 3: PackItem( new Lute() ); break; + case 4: PackItem( new Tambourine() ); break; + case 5: PackItem( new TambourineTassel() ); break; + } + } + + private static void PackScroll( int circle ) + { + switch ( Utility.Random( 8 ) * ( circle + 1 ) ) + { + case 0: PackItem( new ClumsyScroll() ); break; + case 1: PackItem( new CreateFoodScroll() ); break; + case 2: PackItem( new FeeblemindScroll() ); break; + case 3: PackItem( new HealScroll() ); break; + case 4: PackItem( new MagicArrowScroll() ); break; + case 5: PackItem( new NightSightScroll() ); break; + case 6: PackItem( new ReactiveArmorScroll() ); break; + case 7: PackItem( new WeakenScroll() ); break; + case 8: PackItem( new AgilityScroll() ); break; + case 9: PackItem( new CunningScroll() ); break; + case 10: PackItem( new CureScroll() ); break; + case 11: PackItem( new HarmScroll() ); break; + case 12: PackItem( new MagicTrapScroll() ); break; + case 13: PackItem( new MagicUnTrapScroll() ); break; + case 14: PackItem( new ProtectionScroll() ); break; + case 15: PackItem( new StrengthScroll() ); break; + case 16: PackItem( new BlessScroll() ); break; + case 17: PackItem( new FireballScroll() ); break; + case 18: PackItem( new MagicLockScroll() ); break; + case 19: PackItem( new PoisonScroll() ); break; + case 20: PackItem( new TelekinisisScroll() ); break; + case 21: PackItem( new TeleportScroll() ); break; + case 22: PackItem( new UnlockScroll() ); break; + case 23: PackItem( new WallOfStoneScroll() ); break; + } + } + + private static Item NecroHue( Item item ) + { + item.Hue = 0x2C3; + + return item; + } + + private static void AddSkillItems( SkillName skill, Mobile m ) + { + bool elf = (m.Race == Race.Elf); + + switch ( skill ) + { + case SkillName.Alchemy: + { + PackItem( new Bottle( 4 ) ); + PackItem( new MortarPestle() ); + + int hue = Utility.RandomPinkHue(); + + if ( elf ) + { + if ( m.Female ) + EquipItem( new FemaleElvenRobe( hue ) ); + else + EquipItem( new MaleElvenRobe( hue ) ); + } + else + { + EquipItem( new Robe( Utility.RandomPinkHue() ) ); + } + break; + } + case SkillName.Anatomy: + { + PackItem( new Bandage( 3 ) ); + + int hue = Utility.RandomYellowHue(); + + if ( elf ) + { + if ( m.Female ) + EquipItem( new FemaleElvenRobe( hue ) ); + else + EquipItem( new MaleElvenRobe( hue ) ); + } + else + { + EquipItem(new Robe(hue)); + } + break; + } + case SkillName.AnimalLore: + { + + + int hue = Utility.RandomBlueHue(); + + if ( elf ) + { + EquipItem( new WildStaff() ); + + if ( m.Female ) + EquipItem( new FemaleElvenRobe( hue ) ); + else + EquipItem( new MaleElvenRobe( hue ) ); + } + else + { + EquipItem( new ShepherdsCrook() ); + EquipItem( new Robe( hue ) ); + } + break; + } + case SkillName.Archery: + { + PackItem( new Arrow( 25 ) ); + + if ( elf ) + EquipItem( new ElvenCompositeLongbow() ); + else + EquipItem( new Bow() ); + + break; + } + case SkillName.ArmsLore: + { + if ( elf ) + { + switch ( Utility.Random( 3 ) ) + { + case 0: EquipItem( new Leafblade() ); break; + case 1: EquipItem( new RuneBlade() ); break; + case 2: EquipItem( new DiamondMace() ); break; + } + } + else + { + switch ( Utility.Random( 3 ) ) + { + case 0: EquipItem( new Kryss() ); break; + case 1: EquipItem( new Katana() ); break; + case 2: EquipItem( new Club() ); break; + } + } + + break; + } + case SkillName.Begging: + { + if ( elf ) + EquipItem( new WildStaff() ); + else + EquipItem( new GnarledStaff() ); + break; + } + case SkillName.Blacksmith: + { + PackItem( new Tongs() ); + PackItem( new Pickaxe() ); + PackItem( new Pickaxe() ); + PackItem( new IronIngot( 50 ) ); + EquipItem( new HalfApron( Utility.RandomYellowHue() ) ); + break; + } + case SkillName.Bushido: + { + EquipItem( new Hakama() ); + EquipItem( new Kasa() ); + //EquipItem( new BookOfBushido() ); + break; + } + case SkillName.Fletching: + { + PackItem( new Board( 14 ) ); + PackItem( new Feather( 5 ) ); + PackItem( new Shaft( 5 ) ); + break; + } + case SkillName.Camping: + { + PackItem( new Bedroll() ); + PackItem( new Kindling( 5 ) ); + break; + } + case SkillName.Carpentry: + { + PackItem( new Board( 10 ) ); + PackItem( new Saw() ); + EquipItem( new HalfApron( Utility.RandomYellowHue() ) ); + break; + } + case SkillName.Cartography: + { + PackItem( new BlankMap() ); + PackItem( new BlankMap() ); + PackItem( new BlankMap() ); + PackItem( new BlankMap() ); + PackItem( new Sextant() ); + break; + } + case SkillName.Cooking: + { + PackItem( new Kindling( 2 ) ); + PackItem( new RawLambLeg() ); + PackItem( new RawChickenLeg() ); + PackItem( new RawFishSteak() ); + PackItem( new SackFlour() ); + PackItem( new Pitcher( BeverageType.Water ) ); + break; + } + case SkillName.Chivalry: + { + /*if( Core.ML ) + PackItem( new BookOfChivalry( (ulong)0x3FF ) );*/ + + break; + } + case SkillName.DetectHidden: + { + EquipItem( new Cloak( 0x455 ) ); + break; + } + case SkillName.Discordance: + { + PackInstrument(); + break; + } + case SkillName.Fencing: + { + if ( elf ) + EquipItem( new Leafblade() ); + else + EquipItem( new Kryss() ); + + break; + } + case SkillName.Fishing: + { + EquipItem( new FishingPole() ); + + int hue = Utility.RandomYellowHue(); + + if ( elf ) + { + Item i = new Circlet(); + i.Hue = hue; + EquipItem( i ); + } + else + { + EquipItem(new Robe(hue)); + } + + break; + } + case SkillName.Healing: + { + PackItem( new Bandage( 50 ) ); + PackItem( new Scissors() ); + break; + } + case SkillName.Herding: + { + if ( elf ) + EquipItem( new WildStaff() ); + else + EquipItem( new ShepherdsCrook() ); + + break; + } + case SkillName.Hiding: + { + EquipItem( new Cloak( 0x455 ) ); + break; + } + case SkillName.Inscribe: + { + PackItem( new BlankScroll( 2 ) ); + PackItem( new BlueBook() ); + break; + } + case SkillName.ItemID: + { + if ( elf ) + EquipItem( new WildStaff() ); + else + EquipItem( new GnarledStaff() ); + break; + } + case SkillName.Lockpicking: + { + PackItem( new Lockpick( 20 ) ); + break; + } + case SkillName.Lumberjacking: + { + EquipItem( new Hatchet() ); + break; + } + case SkillName.Macing: + { + if ( elf ) + EquipItem( new DiamondMace() ); + else + EquipItem( new Club() ); + + break; + } + case SkillName.Magery: + { + /*BagOfReagents regs = new BagOfReagents( 30 ); + + if ( !Core.AOS ) + { + foreach ( Item item in regs.Items ) + item.LootType = LootType.Newbied; + } + + PackItem( regs ); + + regs.LootType = LootType.Regular; + + PackScroll( 0 ); + PackScroll( 1 ); + PackScroll( 2 ); + + Spellbook book = new Spellbook( (ulong)0x382A8C38 ); + + EquipItem( book ); + + book.LootType = LootType.Blessed;*/ + + if ( elf ) + { + EquipItem( new Circlet() ); + + if( m.Female ) + EquipItem( new FemaleElvenRobe( Utility.RandomBlueHue() ) ); + else + EquipItem( new MaleElvenRobe( Utility.RandomBlueHue() ) ); + } + else + { + EquipItem( new WizardsHat() ); + EquipItem( new Robe( Utility.RandomBlueHue() ) ); + } + + break; + } + case SkillName.Mining: + { + PackItem( new Pickaxe() ); + break; + } + case SkillName.Musicianship: + { + PackInstrument(); + break; + } + case SkillName.Necromancy: + { + /*if( Core.ML ) + { + Container regs = new BagOfNecroReagents( 50 ); + + PackItem( regs ); + + regs.LootType = LootType.Regular; + }*/ + + break; + } + case SkillName.Ninjitsu: + { + EquipItem( new Hakama( 0x2C3 ) ); //Only ninjas get the hued one. + EquipItem( new Kasa() ); + //EquipItem( new BookOfNinjitsu() ); + break; + } + case SkillName.Parry: + { + EquipItem( new WoodenShield() ); + break; + } + case SkillName.Peacemaking: + { + PackInstrument(); + break; + } + case SkillName.Poisoning: + { + PackItem( new LesserPoisonPotion() ); + PackItem( new LesserPoisonPotion() ); + break; + } + case SkillName.Provocation: + { + PackInstrument(); + break; + } + case SkillName.Snooping: + { + PackItem( new Lockpick( 20 ) ); + break; + } + case SkillName.SpiritSpeak: + { + EquipItem( new Cloak( 0x455 ) ); + break; + } + case SkillName.Stealing: + { + PackItem( new Lockpick( 20 ) ); + break; + } + case SkillName.Swords: + { + if ( elf ) + EquipItem( new RuneBlade() ); + else + EquipItem( new Katana() ); + + break; + } + case SkillName.Tactics: + { + if ( elf ) + EquipItem( new RuneBlade() ); + else + EquipItem( new Katana() ); + + break; + } + case SkillName.Tailoring: + { + PackItem( new BoltOfCloth() ); + PackItem( new SewingKit() ); + break; + } + case SkillName.Tracking: + { + if ( m_Mobile != null ) + { + Item shoes = m_Mobile.FindItemOnLayer( Layer.Shoes ); + + if ( shoes != null ) + shoes.Delete(); + } + + int hue = Utility.RandomYellowHue(); + + if ( elf ) + EquipItem( new ElvenBoots( hue ) ); + else + EquipItem( new Boots( hue ) ); + + EquipItem( new SkinningKnife() ); + break; + } + case SkillName.Veterinary: + { + PackItem( new Bandage( 5 ) ); + PackItem( new Scissors() ); + break; + } + case SkillName.Wrestling: + { + if ( elf ) + EquipItem( new LeafGloves() ); + else + EquipItem( new LeatherGloves() ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Cleanup.cs b/Scripts/Misc/Cleanup.cs new file mode 100644 index 0000000..4baff17 --- /dev/null +++ b/Scripts/Misc/Cleanup.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Misc +{ + public class Cleanup + { + public static void Initialize() + { + Timer.DelayCall( TimeSpan.FromSeconds( 2.5 ), new TimerCallback( Run ) ); + } + + public static void Run() + { + List items = new List(); + List validItems = new List(); + List hairCleanup = new List(); + + int boxes = 0; + + foreach ( Item item in World.Items.Values ) + { + if ( item.Map == null ) + { + items.Add( item ); + continue; + } + else if ( item is CommodityDeed ) + { + CommodityDeed deed = (CommodityDeed)item; + + if ( deed.Commodity != null ) + validItems.Add( deed.Commodity ); + + continue; + } + else if ( item is BaseHouse ) + { + BaseHouse house = (BaseHouse)item; + + foreach ( RelocatedEntity relEntity in house.RelocatedEntities ) + { + if ( relEntity.Entity is Item ) + validItems.Add( (Item)relEntity.Entity ); + } + + foreach ( VendorInventory inventory in house.VendorInventories ) + { + foreach ( Item subItem in inventory.Items ) + validItems.Add( subItem ); + } + } + else if ( item is BankBox ) + { + BankBox box = (BankBox)item; + Mobile owner = box.Owner; + + if ( owner == null ) + { + items.Add( box ); + ++boxes; + } + else if ( box.Items.Count == 0 ) + { + items.Add( box ); + ++boxes; + } + + continue; + } + else if ( (item.Layer == Layer.Hair || item.Layer == Layer.FacialHair) ) + { + object rootParent = item.RootParent; + + if ( rootParent is Mobile ) + { + Mobile rootMobile = (Mobile)rootParent; + if ( item.Parent != rootMobile && rootMobile.AccessLevel == AccessLevel.Player ) + { + items.Add( item ); + continue; + } + else if( item.Parent == rootMobile ) + { + hairCleanup.Add( rootMobile ); + continue; + } + } + } + + if ( item.Parent != null || item.Map != Map.Internal || item.HeldBy != null ) + continue; + + if ( item.Location != Point3D.Zero ) + continue; + + if ( !IsBuggable( item ) ) + continue; + + items.Add( item ); + } + + for ( int i = 0; i < validItems.Count; ++i ) + items.Remove( validItems[i] ); + + if ( items.Count > 0 ) + { + if ( boxes > 0 ) + Console.WriteLine( "Cleanup: Detected {0} inaccessible items, including {1} bank boxes, removing..", items.Count, boxes ); + else + Console.WriteLine( "Cleanup: Detected {0} inaccessible items, removing..", items.Count ); + + for ( int i = 0; i < items.Count; ++i ) + items[i].Delete(); + } + + if ( hairCleanup.Count > 0 ) + { + Console.WriteLine( "Cleanup: Detected {0} hair and facial hair items being worn, converting to their virtual counterparts..", hairCleanup.Count ); + + for ( int i = 0; i < hairCleanup.Count; i++ ) + hairCleanup[i].ConvertHair(); + } + } + + public static bool IsBuggable( Item item ) + { + if ( item is Fists ) + return false; + + if (item is ICommodity || item is Multis.BaseBoat + || item is Fish || item is BigFish + || item is BasePotion || item is Food || item is CookableFood + || item is SpecialFishingNet || item is BaseMagicFish + || item is Shoes || item is Sandals + || item is Boots || item is ThighBoots + || item is TreasureMap || item is MessageInABottle + || item is BaseArmor || item is BaseWeapon + || item is BaseClothing + || (item is BaseJewel && Core.AOS) + || (item is BasePotion && Core.ML) + #region Champion artifacts + || item is SkullPole + || item is EvilIdolSkull + || item is MonsterStatuette + || item is Pier + || item is ArtifactLargeVase + || item is ArtifactVase + || item is MinotaurStatueDeed + || item is SwampTile + || item is WallBlood + || item is TatteredAncientMummyWrapping + || item is LavaTile + || item is DemonSkull + || item is Web + || item is WaterTile + || item is WindSpirit + || item is DirtPatch + || item is Futon) + #endregion + return true; + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ClientVerification.cs b/Scripts/Misc/ClientVerification.cs new file mode 100644 index 0000000..1e02c8b --- /dev/null +++ b/Scripts/Misc/ClientVerification.cs @@ -0,0 +1,225 @@ +using System; +using Server; +using System.Diagnostics; +using System.IO; +using Server.Network; +using Server.Gumps; +using Server.Mobiles; + +namespace Server.Misc +{ + public class ClientVerification + { + private enum OldClientResponse + { + Ignore, + Warn, + Annoy, + LenientKick, + Kick + } + + private static bool m_DetectClientRequirement = true; + private static OldClientResponse m_OldClientResponse = OldClientResponse.Annoy; //OldClientResponse.LenientKick; + + private static ClientVersion m_Required; + private static bool m_AllowRegular = true, m_AllowUOTD = true, m_AllowGod = true; + + private static TimeSpan m_AgeLeniency = TimeSpan.FromDays( 10 ); + private static TimeSpan m_GameTimeLeniency = TimeSpan.FromHours( 25 ); + + private static TimeSpan m_KickDelay = TimeSpan.FromSeconds( 20.0 ); + + public static ClientVersion Required + { + get + { + return m_Required; + } + set + { + m_Required = value; + } + } + + public static bool AllowRegular + { + get + { + return m_AllowRegular; + } + set + { + m_AllowRegular = value; + } + } + + public static bool AllowUOTD + { + get + { + return m_AllowUOTD; + } + set + { + m_AllowUOTD = value; + } + } + + public static bool AllowGod + { + get + { + return m_AllowGod; + } + set + { + m_AllowGod = value; + } + } + + public static TimeSpan KickDelay + { + get + { + return m_KickDelay; + } + set + { + m_KickDelay = value; + } + } + + public static void Initialize() + { + EventSink.ClientVersionReceived += new ClientVersionReceivedHandler( EventSink_ClientVersionReceived ); + + //ClientVersion.Required = null; + //Required = new ClientVersion( "6.0.0.0" ); + + if( m_DetectClientRequirement ) + { + string path = Core.FindDataFile( "client.exe" ); + + if( File.Exists( path ) ) + { + FileVersionInfo info = FileVersionInfo.GetVersionInfo( path ); + + if ( info.FileMajorPart != 0 || info.FileMinorPart != 0 || info.FileBuildPart != 0 || info.FilePrivatePart != 0 ) + { + Required = new ClientVersion( info.FileMajorPart, info.FileMinorPart, info.FileBuildPart, info.FilePrivatePart ); + } + } + } + + if( Required != null ) + { + Utility.PushColor( ConsoleColor.White ); + Console.WriteLine( "Restricting client version to {0}. Action to be taken: {1}", Required, m_OldClientResponse ); + Utility.PopColor(); + } + } + + private static void EventSink_ClientVersionReceived( ClientVersionReceivedArgs e ) + { + string kickMessage = null; + NetState state = e.State; + ClientVersion version = e.Version; + + if (state.Mobile == null || state.Mobile.AccessLevel > AccessLevel.Player) + return; + + if( Required != null && version < Required && ( m_OldClientResponse == OldClientResponse.Kick ||( m_OldClientResponse == OldClientResponse.LenientKick && (DateTime.Now - state.Mobile.CreationTime) > m_AgeLeniency && state.Mobile is PlayerMobile && ((PlayerMobile)state.Mobile).GameTime > m_GameTimeLeniency ))) + { + kickMessage = String.Format( "This server requires your client version be at least {0}.", Required ); + } + else if( !AllowGod || !AllowRegular || !AllowUOTD ) + { + if( !AllowGod && version.Type == ClientType.God ) + kickMessage = "This server does not allow god clients to connect."; + else if( !AllowRegular && version.Type == ClientType.Regular ) + kickMessage = "This server does not allow regular clients to connect."; + else if( !AllowUOTD && state.IsUOTDClient ) + kickMessage = "This server does not allow UO:TD clients to connect."; + + if( !AllowGod && !AllowRegular && !AllowUOTD ) + { + kickMessage = "This server does not allow any clients to connect."; + } + else if( AllowGod && !AllowRegular && !AllowUOTD && version.Type != ClientType.God ) + { + kickMessage = "This server requires you to use the god client."; + } + else if( kickMessage != null ) + { + if( AllowRegular && AllowUOTD ) + kickMessage += " You can use regular or UO:TD clients."; + else if( AllowRegular ) + kickMessage += " You can use regular clients."; + else if( AllowUOTD ) + kickMessage += " You can use UO:TD clients."; + } + } + + if( kickMessage != null ) + { + state.Mobile.SendMessage( 0x22, kickMessage ); + state.Mobile.SendMessage( 0x22, "You will be disconnected in {0} seconds.", KickDelay.TotalSeconds ); + + Timer.DelayCall( KickDelay, delegate + { + if( state.Socket != null ) + { + Console.WriteLine( "Client: {0}: Disconnecting, bad version", state ); + state.Dispose(); + } + } ); + } + else if( Required != null && version < Required ) + { + switch( m_OldClientResponse ) + { + case OldClientResponse.Warn: + { + state.Mobile.SendMessage( 0x22, "Your client is out of date. Please update your client.", Required ); + state.Mobile.SendMessage(0x22, "This server recommends that your client version be at least {0}.", Required); + break; + } + case OldClientResponse.LenientKick: + case OldClientResponse.Annoy: + { + SendAnnoyGump( state.Mobile ); + break; + } + } + } + } + + private static void SendAnnoyGump( Mobile m ) + { + if( m.NetState != null && m.NetState.Version < Required ) + { + // Scriptiz : on change UOPatch.exe en UO.exe et on traduit + //Gump g = new WarningGump( 1060637, 30720, String.Format( "Your client is out of date. Please update your client.
This server recommends that your client version be at least {0}.

You are currently using version {1}.

To patch, run UO.exe inside your Ultima Online folder.", Required, m.NetState.Version ), 0xFFC000, 480, 360, + Gump g = new WarningGump(1060637, 30720, String.Format("Votre client n'est pas � jour. Merci d'effectuer les mises � jour.
Ce serveur recommande que vous utilisiez au moins la version {0} du client.

Votre version actuelle est la version {1}.

Pour mettre � jour, lancez UO.exe � partir du dossier Ultima Online.", Required, m.NetState.Version), 0xFFC000, 480, 360, + delegate( Mobile mob, bool selection, object o ) + { + //m.SendMessage( "You will be reminded of this again." ); + m.SendMessage("Vous serez averti � nouveau."); + + if ( m_OldClientResponse == OldClientResponse.LenientKick ) + m.SendMessage( "Old clients will be kicked after {0} days of character age and {1} hours of play time", m_AgeLeniency, m_GameTimeLeniency ); + + // Scriptiz : une fois suffit :) + //Timer.DelayCall( TimeSpan.FromMinutes( Utility.Random( 5, 15 ) ), delegate { SendAnnoyGump( m ); } ); + }, null, false ); + + g.Dragable = false; + g.Closable = false; + g.Resizable = false; + + m.SendGump( g ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/CrashGuard.cs b/Scripts/Misc/CrashGuard.cs new file mode 100644 index 0000000..8b6250d --- /dev/null +++ b/Scripts/Misc/CrashGuard.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net.Mail; +using Server; +using Server.Accounting; +using Server.Network; + +namespace Server.Misc +{ + public class CrashGuard + { + private static bool Enabled = true; + private static bool SaveBackup = true; + private static bool RestartServer = false; // Scriptiz en attendant pour �viter le restart too many ! + private static bool GenerateReport = true; + + public static void Initialize() + { + if ( Enabled ) // If enabled, register our crash event handler + EventSink.Crashed += new CrashedEventHandler( CrashGuard_OnCrash ); + } + + public static void CrashGuard_OnCrash( CrashedEventArgs e ) + { + if ( GenerateReport ) + GenerateCrashReport( e ); + + World.WaitForWriteCompletion(); + + if ( SaveBackup ) + Backup(); + + + /*if ( Core.Service ) + e.Close = true; + else */ if ( RestartServer ) + Restart( e ); + } + + private static void SendEmail( string filePath ) + { + Console.Write( "Crash: Sending email..." ); + + MailMessage message = new MailMessage(Email.FromAddress, Email.CrashAddresses); // Scriptiz : email valide ! + + message.Subject = "Automated RunUO Crash Report"; + + message.Body = "Automated RunUO Crash Report. See attachment for details."; + + message.Attachments.Add( new Attachment( filePath ) ); + + if ( Email.Send( message ) ) + Console.WriteLine( "done" ); + else + Console.WriteLine( "failed" ); + } + + private static string GetRoot() + { + try + { + return Path.GetDirectoryName( Environment.GetCommandLineArgs()[0] ); + } + catch + { + return ""; + } + } + + private static string Combine( string path1, string path2 ) + { + if ( path1.Length == 0 ) + return path2; + + return Path.Combine( path1, path2 ); + } + + private static void Restart( CrashedEventArgs e ) + { + string root = GetRoot(); + + Console.Write( "Crash: Restarting..." ); + + try + { + Process.Start( Core.ExePath, Core.Arguments ); + Console.WriteLine( "done" ); + + e.Close = true; + } + catch + { + Console.WriteLine( "failed" ); + } + } + + private static void CreateDirectory( string path ) + { + if ( !Directory.Exists( path ) ) + Directory.CreateDirectory( path ); + } + + private static void CreateDirectory( string path1, string path2 ) + { + CreateDirectory( Combine( path1, path2 ) ); + } + + private static void CopyFile( string rootOrigin, string rootBackup, string path ) + { + string originPath = Combine( rootOrigin, path ); + string backupPath = Combine( rootBackup, path ); + + try + { + if ( File.Exists( originPath ) ) + File.Copy( originPath, backupPath ); + } + catch + { + } + } + + private static void Backup() + { + Console.Write( "Crash: Backing up..." ); + + try + { + string timeStamp = GetTimeStamp(); + + string root = GetRoot(); + string rootBackup = Combine( root, String.Format( "Backups/Crashed/{0}/", timeStamp ) ); + string rootOrigin = Combine( root, String.Format( "Saves/" ) ); + + // Create new directories + CreateDirectory( rootBackup ); + CreateDirectory( rootBackup, "Accounts/" ); + CreateDirectory( rootBackup, "Items/" ); + CreateDirectory( rootBackup, "Mobiles/" ); + CreateDirectory( rootBackup, "Guilds/" ); + CreateDirectory( rootBackup, "Regions/" ); + + // Copy files + CopyFile( rootOrigin, rootBackup, "Accounts/Accounts.xml" ); + + CopyFile( rootOrigin, rootBackup, "Items/Items.bin" ); + CopyFile( rootOrigin, rootBackup, "Items/Items.idx" ); + CopyFile( rootOrigin, rootBackup, "Items/Items.tdb" ); + + CopyFile( rootOrigin, rootBackup, "Mobiles/Mobiles.bin" ); + CopyFile( rootOrigin, rootBackup, "Mobiles/Mobiles.idx" ); + CopyFile( rootOrigin, rootBackup, "Mobiles/Mobiles.tdb" ); + + CopyFile( rootOrigin, rootBackup, "Guilds/Guilds.bin" ); + CopyFile( rootOrigin, rootBackup, "Guilds/Guilds.idx" ); + + CopyFile( rootOrigin, rootBackup, "Regions/Regions.bin" ); + CopyFile( rootOrigin, rootBackup, "Regions/Regions.idx" ); + + Console.WriteLine( "done" ); + } + catch + { + Console.WriteLine( "failed" ); + } + } + + private static void GenerateCrashReport( CrashedEventArgs e ) + { + Console.Write( "Crash: Generating report..." ); + + try + { + string timeStamp = GetTimeStamp(); + string fileName = String.Format( "Crash {0}.log", timeStamp ); + + string root = GetRoot(); + string filePath = Combine( root, fileName ); + + using ( StreamWriter op = new StreamWriter( filePath ) ) + { + Version ver = Core.Assembly.GetName().Version; + + op.WriteLine( "Server Crash Report" ); + op.WriteLine( "===================" ); + op.WriteLine(); + op.WriteLine( "RunUO Version {0}.{1}, Build {2}.{3}", ver.Major, ver.Minor, ver.Build, ver.Revision ); + op.WriteLine( "Operating System: {0}", Environment.OSVersion ); + op.WriteLine( ".NET Framework: {0}", Environment.Version ); + op.WriteLine( "Time: {0}", DateTime.Now ); + + try { op.WriteLine( "Mobiles: {0}", World.Mobiles.Count ); } + catch {} + + try { op.WriteLine( "Items: {0}", World.Items.Count ); } + catch {} + + op.WriteLine( "Exception:" ); + op.WriteLine( e.Exception ); + op.WriteLine(); + + op.WriteLine( "Clients:" ); + + try + { + List states = NetState.Instances; + + op.WriteLine( "- Count: {0}", states.Count ); + + for ( int i = 0; i < states.Count; ++i ) + { + NetState state = states[i]; + + op.Write( "+ {0}:", state ); + + Account a = state.Account as Account; + + if ( a != null ) + op.Write( " (account = {0})", a.Username ); + + Mobile m = state.Mobile; + + if ( m != null ) + op.Write( " (mobile = 0x{0:X} '{1}')", m.Serial.Value, m.Name ); + + op.WriteLine(); + } + } + catch + { + op.WriteLine( "- Failed" ); + } + } + + Console.WriteLine( "done" ); + + if (Email.FromAddress != null && Email.CrashAddresses != null) + SendEmail( filePath ); + } + catch + { + Console.WriteLine( "failed" ); + } + } + + private static string GetTimeStamp() + { + DateTime now = DateTime.Now; + + return String.Format( "{0}-{1}-{2}-{3}-{4}-{5}", + now.Day, + now.Month, + now.Year, + now.Hour, + now.Minute, + now.Second + ); + } + } +} diff --git a/Scripts/Misc/CurrentExpansion.cs b/Scripts/Misc/CurrentExpansion.cs new file mode 100644 index 0000000..6efbdae --- /dev/null +++ b/Scripts/Misc/CurrentExpansion.cs @@ -0,0 +1,34 @@ +using System; +using Server.Network; + +namespace Server +{ + public class CurrentExpansion + { + private static readonly Expansion Expansion = Expansion.HS; + + public static void Configure() + { + Core.Expansion = Expansion; + + bool Enabled = Core.AOS; + + Mobile.InsuranceEnabled = Enabled; // Scriptiz : on retire le ! pour activer le syst�me d'assurance + ObjectPropertyList.Enabled = Enabled; + Mobile.VisibleDamageType = !Enabled ? VisibleDamageType.Related : VisibleDamageType.None; + Mobile.GuildClickMessage = !Enabled; + Mobile.AsciiClickMessage = !Enabled; + + if ( Enabled ) + { + AOS.DisableStatInfluences(); + + if ( ObjectPropertyList.Enabled ) + PacketHandlers.SingleClickProps = true; // single click for everything is overriden to check object property list + + Mobile.ActionDelay = TimeSpan.FromSeconds(1.0); + Mobile.AOSStatusHandler = new AOSStatusHandler(AOS.GetStatus); + } + } + } +} diff --git a/Scripts/Misc/DataPath.cs b/Scripts/Misc/DataPath.cs new file mode 100644 index 0000000..b5b1865 --- /dev/null +++ b/Scripts/Misc/DataPath.cs @@ -0,0 +1,113 @@ +using System; +using System.IO; +using Microsoft.Win32; +using Server; + +namespace Server.Misc +{ + public class DataPath + { + /* If you have not installed Ultima Online, + * or wish the server to use a separate set of datafiles, + * change the 'CustomPath' value. + * Example: + * private static string CustomPath = @"C:\Program Files\Ultima Online"; + */ + private static string CustomPath = null; + + /* The following is a list of files which a required for proper execution: + * + * Multi.idx + * Multi.mul + * VerData.mul + * TileData.mul + * Map*.mul or Map*LegacyMUL.uop + * StaIdx*.mul + * Statics*.mul + * MapDif*.mul + * MapDifL*.mul + * StaDif*.mul + * StaDifL*.mul + * StaDifI*.mul + */ + + public static void Configure() + { + string pathUO = GetPath( @"Origin Worlds Online\Ultima Online\1.0", "ExePath" ); + string pathTD = GetPath( @"Origin Worlds Online\Ultima Online Third Dawn\1.0", "ExePath" ); //These refer to 2D & 3D, not the Third Dawn expansion + string pathKR = GetPath( @"Origin Worlds Online\Ultima Online\KR Legacy Beta", "ExePath" ); //After KR, This is the new registry key for the 2D client + string pathSA = GetPath( @"Electronic Arts\EA Games\Ultima Online Stygian Abyss Classic", "InstallDir" ); + string pathHS = GetPath(@"Electronic Arts\EA Games\Ultima Online Classic", "InstallDir"); + + string pathClassic = GetPath(@"Electronic Arts\EA Games\Ultima Online Classic", "InstallDir"); // Scriptiz : dernier client en date (7.0.1x.x) + + if ( CustomPath != null ) + Core.DataDirectories.Add( CustomPath ); + + if ( pathUO != null ) + Core.DataDirectories.Add( pathUO ); + + if ( pathTD != null ) + Core.DataDirectories.Add( pathTD ); + + if ( pathKR != null ) + Core.DataDirectories.Add( pathKR ); + + if ( pathSA != null ) + Core.DataDirectories.Add( pathSA ); + + if (pathHS != null) + Core.DataDirectories.Add(pathHS); + + // Scriptiz : d�tection du dossier d'installation de la derni�re version d'UO (7.0.1x.x) + if (pathClassic != null) + Core.DataDirectories.Add(pathClassic); + + if ( Core.DataDirectories.Count == 0 && !Core.Service ) + { + Console.WriteLine( "Enter the Ultima Online directory:" ); + Console.Write( "> " ); + + Core.DataDirectories.Add( Console.ReadLine() ); + } + } + + private static string GetPath( string subName, string keyName ) + { + try + { + string keyString; + + if( Core.Is64Bit ) + keyString = @"SOFTWARE\Wow6432Node\{0}"; + else + keyString = @"SOFTWARE\{0}"; + + using( RegistryKey key = Registry.LocalMachine.OpenSubKey( String.Format( keyString, subName ) ) ) + { + if( key == null ) + return null; + + string v = key.GetValue( keyName ) as string; + + if( String.IsNullOrEmpty( v ) ) + return null; + + if ( keyName == "InstallDir" ) + v = v + @"\"; + + v = Path.GetDirectoryName( v ); + + if ( String.IsNullOrEmpty( v ) ) + return null; + + return v; + } + } + catch + { + return null; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/DispellableAttribute.cs b/Scripts/Misc/DispellableAttribute.cs new file mode 100644 index 0000000..3f6a5a7 --- /dev/null +++ b/Scripts/Misc/DispellableAttribute.cs @@ -0,0 +1,10 @@ +using System; +using Server; + +namespace Server.Misc +{ + [AttributeUsage( AttributeTargets.Class )] + public class DispellableAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Scripts/Misc/DispellableFieldAttribute.cs b/Scripts/Misc/DispellableFieldAttribute.cs new file mode 100644 index 0000000..62fffed --- /dev/null +++ b/Scripts/Misc/DispellableFieldAttribute.cs @@ -0,0 +1,10 @@ +using System; +using Server; + +namespace Server.Misc +{ + [AttributeUsage( AttributeTargets.Class )] + public class DispellableFieldAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Scripts/Misc/DoorGenerator.cs b/Scripts/Misc/DoorGenerator.cs new file mode 100644 index 0000000..3ca4fd3 --- /dev/null +++ b/Scripts/Misc/DoorGenerator.cs @@ -0,0 +1,564 @@ +using System; +using Server; +using Server.Items; +using Server.Commands; + +namespace Server +{ + public class DoorGenerator + { + private static Rectangle2D[] m_BritRegions = new Rectangle2D[] + { + new Rectangle2D( new Point2D( 250, 750 ), new Point2D( 775, 1330 ) ), + new Rectangle2D( new Point2D( 525, 2095 ), new Point2D( 925, 2430 ) ), + new Rectangle2D( new Point2D( 1025, 2155 ), new Point2D( 1265, 2310 ) ), + new Rectangle2D( new Point2D( 1635, 2430 ), new Point2D( 1705, 2508 ) ), + new Rectangle2D( new Point2D( 1775, 2605 ), new Point2D( 2165, 2975 ) ), + new Rectangle2D( new Point2D( 1055, 3520 ), new Point2D( 1570, 4075 ) ), + new Rectangle2D( new Point2D( 2860, 3310 ), new Point2D( 3120, 3630 ) ), + new Rectangle2D( new Point2D( 2470, 1855 ), new Point2D( 3950, 3045 ) ), + new Rectangle2D( new Point2D( 3425, 990 ), new Point2D( 3900, 1455 ) ), + new Rectangle2D( new Point2D( 4175, 735 ), new Point2D( 4840, 1600 ) ), + new Rectangle2D( new Point2D( 2375, 330 ), new Point2D( 3100, 1045 ) ), + new Rectangle2D( new Point2D( 2100, 1090 ), new Point2D( 2310, 1450 ) ), + new Rectangle2D( new Point2D( 1495, 1400 ), new Point2D( 1550, 1475 ) ), + new Rectangle2D( new Point2D( 1085, 1520 ), new Point2D( 1415, 1910 ) ), + new Rectangle2D( new Point2D( 1410, 1500 ), new Point2D( 1745, 1795 ) ), + new Rectangle2D( new Point2D( 5120, 2300 ), new Point2D( 6143, 4095 ) ) + }; + + private static Rectangle2D[] m_IlshRegions = new Rectangle2D[] + { + new Rectangle2D( new Point2D( 0, 0 ), new Point2D( 288*8, 200*8 ) ) + }; + + private static Rectangle2D[] m_MalasRegions = new Rectangle2D[] + { + new Rectangle2D( new Point2D( 0, 0 ), new Point2D( 320*8, 256*8 ) ) + }; + + private static int[] m_SouthFrames = new int[] + { + 0x0006, + 0x0008, + 0x000B, + 0x001A, + 0x001B, + 0x001F, + 0x0038, + 0x0057, + 0x0059, + 0x005B, + 0x005D, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0091, + 0x0094, + 0x0096, + 0x0099, + 0x00A6, + 0x00A7, + 0x00AA, + 0x00AE, + 0x00B0, + 0x00B3, + 0x00C7, + 0x00C9, + 0x00F8, + 0x00FA, + 0x00FD, + 0x00FE, + 0x0100, + 0x0103, + 0x0104, + 0x0106, + 0x0109, + 0x0127, + 0x0129, + 0x012B, + 0x012D, + 0x012F, + 0x0131, + 0x0132, + 0x0134, + 0x0135, + 0x0137, + 0x0139, + 0x013B, + 0x014C, + 0x014E, + 0x014F, + 0x0151, + 0x0153, + 0x0155, + 0x0157, + 0x0158, + 0x015A, + 0x015D, + 0x015E, + 0x015F, + 0x0162, + 0x01CF, + 0x01D1, + 0x01D4, + 0x01FF, + 0x0204, + 0x0206, + 0x0208, + 0x020A + }; + + private static int[] m_NorthFrames = new int[] + { + 0x0006, + 0x0008, + 0x000D, + 0x001A, + 0x001B, + 0x0020, + 0x003A, + 0x0057, + 0x0059, + 0x005B, + 0x005D, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0091, + 0x0094, + 0x0096, + 0x0099, + 0x00A6, + 0x00A7, + 0x00AC, + 0x00AE, + 0x00B0, + 0x00C7, + 0x00C9, + 0x00F8, + 0x00FA, + 0x00FD, + 0x00FE, + 0x0100, + 0x0103, + 0x0104, + 0x0106, + 0x0109, + 0x0127, + 0x0129, + 0x012B, + 0x012D, + 0x012F, + 0x0131, + 0x0132, + 0x0134, + 0x0135, + 0x0137, + 0x0139, + 0x013B, + 0x014C, + 0x014E, + 0x014F, + 0x0151, + 0x0153, + 0x0155, + 0x0157, + 0x0158, + 0x015A, + 0x015D, + 0x015E, + 0x015F, + 0x0162, + 0x01CF, + 0x01D1, + 0x01D4, + 0x01FF, + 0x0201, + 0x0204, + 0x0208, + 0x020A + }; + + private static int[] m_EastFrames = new int[] + { + 0x0007, + 0x000A, + 0x001A, + 0x001C, + 0x001E, + 0x0037, + 0x0058, + 0x0059, + 0x005C, + 0x005E, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0092, + 0x0095, + 0x0097, + 0x0098, + 0x00A6, + 0x00A8, + 0x00AB, + 0x00AE, + 0x00AF, + 0x00B2, + 0x00C7, + 0x00C8, + 0x00EA, + 0x00F8, + 0x00F9, + 0x00FC, + 0x00FE, + 0x00FF, + 0x0102, + 0x0104, + 0x0105, + 0x0108, + 0x0127, + 0x0128, + 0x012B, + 0x012C, + 0x012E, + 0x0130, + 0x0132, + 0x0133, + 0x0135, + 0x0136, + 0x0138, + 0x013A, + 0x014C, + 0x014D, + 0x014F, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x0159, + 0x015C, + 0x015E, + 0x0160, + 0x0163, + 0x01CF, + 0x01D0, + 0x01D3, + 0x01FF, + 0x0203, + 0x0205, + 0x0207, + 0x0209 + }; + + private static int[] m_WestFrames = new int[] + { + 0x0007, + 0x000C, + 0x001A, + 0x001C, + 0x0021, + 0x0039, + 0x0058, + 0x0059, + 0x005C, + 0x005E, + 0x0080, + 0x0081, + 0x0082, + 0x0084, + 0x0090, + 0x0092, + 0x0095, + 0x0097, + 0x0098, + 0x00A6, + 0x00A8, + 0x00AD, + 0x00AE, + 0x00AF, + 0x00B5, + 0x00C7, + 0x00C8, + 0x00EA, + 0x00F8, + 0x00F9, + 0x00FC, + 0x00FE, + 0x00FF, + 0x0102, + 0x0104, + 0x0105, + 0x0108, + 0x0127, + 0x0128, + 0x012C, + 0x012E, + 0x0130, + 0x0132, + 0x0133, + 0x0135, + 0x0136, + 0x0138, + 0x013A, + 0x014C, + 0x014D, + 0x014F, + 0x0150, + 0x0152, + 0x0154, + 0x0156, + 0x0158, + 0x0159, + 0x015C, + 0x015E, + 0x0160, + 0x0163, + 0x01CF, + 0x01D0, + 0x01D3, + 0x01FF, + 0x0200, + 0x0203, + 0x0207, + 0x0209 + }; + + public static void Initialize() + { + CommandSystem.Register( "DoorGen", AccessLevel.Administrator, new CommandEventHandler( DoorGen_OnCommand ) ); + } + + [Usage( "DoorGen" )] + [Description( "Generates doors by analyzing the map. Slow." )] + public static void DoorGen_OnCommand( CommandEventArgs e ) + { + Generate(); + } + + private static Map m_Map; + private static int m_Count; + + public static void Generate() + { + World.Broadcast( 0x35, true, "Generating doors, please wait." ); + + Network.NetState.FlushAll(); + Network.NetState.Pause(); + + m_Map = Map.Trammel; + m_Count = 0; + + for ( int i = 0; i < m_BritRegions.Length; ++i ) + Generate( m_BritRegions[i] ); + + int trammelCount = m_Count; + + m_Map = Map.Felucca; + m_Count = 0; + + for ( int i = 0; i < m_BritRegions.Length; ++i ) + Generate( m_BritRegions[i] ); + + int feluccaCount = m_Count; + + m_Map = Map.Ilshenar; + m_Count = 0; + + for ( int i = 0; i < m_IlshRegions.Length; ++i ) + Generate( m_IlshRegions[i] ); + + int ilshenarCount = m_Count; + + m_Map = Map.Malas; + m_Count = 0; + + for ( int i = 0; i < m_MalasRegions.Length; ++i ) + Generate( m_MalasRegions[i] ); + + int malasCount = m_Count; + + Network.NetState.Resume(); + + World.Broadcast( 0x35, true, "Door generation complete. Trammel: {0}; Felucca: {1}; Ilshenar: {2}; Malas: {3};", trammelCount, feluccaCount, ilshenarCount, malasCount ); + } + + public static bool IsFrame( int id, int[] list ) + { + if ( id > list[list.Length - 1] ) + return false; + + for ( int i = 0; i < list.Length; ++i ) + { + int delta = id - list[i]; + + if ( delta < 0 ) + return false; + else if ( delta == 0 ) + return true; + } + + return false; + } + + public static bool IsNorthFrame( int id ) + { + return IsFrame( id, m_NorthFrames ); + } + + public static bool IsSouthFrame( int id ) + { + return IsFrame( id, m_SouthFrames ); + } + + public static bool IsWestFrame( int id ) + { + return IsFrame( id, m_WestFrames ); + } + + public static bool IsEastFrame( int id ) + { + return IsFrame( id, m_EastFrames ); + } + + public static bool IsEastFrame( int x, int y, int z ) + { + StaticTile[] tiles = m_Map.Tiles.GetStaticTiles( x, y ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if ( tile.Z == z && IsEastFrame( tile.ID ) ) + return true; + } + + return false; + } + + public static bool IsSouthFrame( int x, int y, int z ) + { + StaticTile[] tiles = m_Map.Tiles.GetStaticTiles( x, y ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if ( tile.Z == z && IsSouthFrame( tile.ID ) ) + return true; + } + + return false; + } + + public static BaseDoor AddDoor( int x, int y, int z, DoorFacing facing ) + { + int doorZ = z; + int doorTop = doorZ + 20; + + if ( !m_Map.CanFit( x, y, z, 16, false, false ) ) + return null; + + if ( y == 1743 && x >= 1343 && x <= 1344 ) + return null; + + if ( y == 1679 && x >= 1392 && x <= 1393 ) + return null; + + if ( x == 1320 && y >= 1618 && y <= 1640 ) + return null; + + if ( x == 1383 && y >= 1642 && y <= 1643 ) + return null; + + BaseDoor door = new DarkWoodDoor( facing ); + door.MoveToWorld( new Point3D( x, y, z ), m_Map ); + + ++m_Count; + + return door; + } + + public static void Generate( Rectangle2D region ) + { + for ( int rx = 0; rx < region.Width; ++rx ) + { + for ( int ry = 0; ry < region.Height; ++ry ) + { + int vx = rx + region.X; + int vy = ry + region.Y; + + StaticTile[] tiles = m_Map.Tiles.GetStaticTiles( vx, vy ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + int id = tile.ID; + int z = tile.Z; + + if ( IsWestFrame( id ) ) + { + if ( IsEastFrame( vx + 2, vy, z ) ) + { + AddDoor( vx + 1, vy, z, DoorFacing.WestCW ); + } + else if ( IsEastFrame( vx + 3, vy, z ) ) + { + BaseDoor first = AddDoor( vx + 1, vy, z, DoorFacing.WestCW ); + BaseDoor second = AddDoor( vx + 2, vy, z, DoorFacing.EastCCW ); + + if ( first != null && second != null ) + { + first.Link = second; + second.Link = first; + } + else + { + if ( first != null ) + first.Delete(); + + if ( second != null ) + second.Delete(); + } + } + } + else if ( IsNorthFrame( id ) ) + { + if ( IsSouthFrame( vx, vy + 2, z ) ) + { + AddDoor( vx, vy + 1, z, DoorFacing.SouthCW ); + } + else if ( IsSouthFrame( vx, vy + 3, z ) ) + { + BaseDoor first = AddDoor( vx, vy + 1, z, DoorFacing.NorthCCW ); + BaseDoor second = AddDoor( vx, vy + 2, z, DoorFacing.SouthCW ); + + if ( first != null && second != null ) + { + first.Link = second; + second.Link = first; + } + else + { + if ( first != null ) + first.Delete(); + + if ( second != null ) + second.Delete(); + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Email.cs b/Scripts/Misc/Email.cs new file mode 100644 index 0000000..604ebf2 --- /dev/null +++ b/Scripts/Misc/Email.cs @@ -0,0 +1,92 @@ +using System; +using System.Net.Mail; +using System.Text.RegularExpressions; +using System.Threading; +using System.Net; +using Server; + +namespace Server.Misc +{ + public class Email + { + /* In order to support emailing, fill in EmailServer and FromAddress: + * Example: + * public static readonly string EmailServer = "mail.domain.com"; + * * public static readonly string FromAddress = "runuo@domain.com"; + * + * If you want to add crash reporting emailing, fill in CrashAddresses: + * Example: + * public static readonly string CrashAddresses = "first@email.here,second@email.here,third@email.here"; + * + * If you want to add speech log page emailing, fill in SpeechLogPageAddresses: + * Example: + * public static readonly string SpeechLogPageAddresses = "first@email.here,second@email.here,third@email.here"; + */ + + public static readonly string EmailServer = "smtp.gmail.com"; + + public static readonly string FromAddress = "vivrestaff@gmail.com"; + + public static readonly string CrashAddresses = "maeliguul@hotmail.com,tommy.maloteaux@gmail.com,erona1990@gmail.com,johnnylegend@free.fr"; + public static readonly string SpeechLogPageAddresses = "maeliguul@hotmail.com,erona1990@gmail.com,johnnylegend@free.fr,nidal.iguer@gmail.com"; + + private static Regex _pattern = new Regex(@"^[a-z0-9.+_-]+@([a-z0-9-]+\.)+[a-z]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + public static bool IsValid( string address ) + { + if ( address == null || address.Length > 320 ) + return false; + + return _pattern.IsMatch( address ); + } + + private static SmtpClient _Client; + + public static void Configure() + { + if (EmailServer != null) + { + _Client = new SmtpClient(EmailServer); + + // Scriptiz : configuration pour gmail ! + _Client.Port = 587; + _Client.EnableSsl = true; + _Client.DeliveryMethod = SmtpDeliveryMethod.Network; + _Client.UseDefaultCredentials = false; + _Client.Credentials = new NetworkCredential("vivrestaff@gmail.com", "vkC42r42"); // Identification + } + } + + public static bool Send( MailMessage message ) + { + try + { + lock ( _Client ) { + _Client.Send( message ); + } + } + catch + { + return false; + } + + return true; + } + + public static void AsyncSend( MailMessage message ) + { + Console.WriteLine("Sending Async Email !"); + ThreadPool.QueueUserWorkItem( new WaitCallback( SendCallback ), message ); + } + + private static void SendCallback( object state ) + { + MailMessage message = (MailMessage) state; + + if ( Send( message ) ) + Console.WriteLine( "Sent e-mail '{0}' to '{1}'.", message.Subject, message.To ); + else + Console.WriteLine( "Failure sending e-mail '{0}' to '{1}'.", message.Subject, message.To ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Emitter.cs b/Scripts/Misc/Emitter.cs new file mode 100644 index 0000000..36da04c --- /dev/null +++ b/Scripts/Misc/Emitter.cs @@ -0,0 +1,740 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Reflection.Emit; +using Emit = System.Reflection.Emit; + +namespace Server +{ + public class AssemblyEmitter + { + private string m_AssemblyName; + + private AppDomain m_AppDomain; + private AssemblyBuilder m_AssemblyBuilder; + private ModuleBuilder m_ModuleBuilder; + + public AssemblyEmitter( string assemblyName, bool canSave ) + { + m_AssemblyName = assemblyName; + + m_AppDomain = AppDomain.CurrentDomain; + + m_AssemblyBuilder = m_AppDomain.DefineDynamicAssembly( + new AssemblyName( assemblyName ), + canSave ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run + ); + + if ( canSave ) + { + m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule( + assemblyName, + String.Format( "{0}.dll", assemblyName.ToLower() ), + false + ); + } + else + { + m_ModuleBuilder = m_AssemblyBuilder.DefineDynamicModule( + assemblyName, + false + ); + } + } + + public TypeBuilder DefineType( string typeName, TypeAttributes attrs, Type parentType ) + { + return m_ModuleBuilder.DefineType( typeName, attrs, parentType ); + } + + public void Save() + { + m_AssemblyBuilder.Save( + String.Format( "{0}.dll", m_AssemblyName.ToLower() ) + ); + } + } + + public class MethodEmitter + { + private TypeBuilder m_TypeBuilder; + + private MethodBuilder m_Builder; + private ILGenerator m_Generator; + + private Type[] m_ArgumentTypes; + + public TypeBuilder Type + { + get { return m_TypeBuilder; } + } + + public ILGenerator Generator + { + get { return m_Generator; } + } + + private class CallInfo + { + public Type type; + public MethodInfo method; + + public int index; + public ParameterInfo[] parms; + + public CallInfo( Type type, MethodInfo method ) + { + this.type = type; + this.method = method; + + this.parms = method.GetParameters(); + } + } + + private Stack m_Stack; + private Stack m_Calls; + + private Dictionary> m_Temps; + + public MethodBuilder Method + { + get { return m_Builder; } + } + + public MethodEmitter( TypeBuilder typeBuilder ) + { + m_TypeBuilder = typeBuilder; + + m_Temps = new Dictionary>(); + + m_Stack = new Stack(); + m_Calls = new Stack(); + } + + public void Define( string name, MethodAttributes attr, Type returnType, Type[] parms ) + { + m_Builder = m_TypeBuilder.DefineMethod( name, attr, returnType, parms ); + m_Generator = m_Builder.GetILGenerator(); + + m_ArgumentTypes = parms; + } + + public LocalBuilder CreateLocal( Type localType ) + { + return m_Generator.DeclareLocal( localType ); + } + + public LocalBuilder AcquireTemp( Type localType ) + { + Queue list; + + if ( !m_Temps.TryGetValue( localType, out list ) ) + m_Temps[localType] = list = new Queue(); + + if ( list.Count > 0 ) + return list.Dequeue(); + + return CreateLocal( localType ); + } + + public void ReleaseTemp( LocalBuilder local ) + { + Queue list; + + if ( !m_Temps.TryGetValue( local.LocalType, out list ) ) + m_Temps[local.LocalType] = list = new Queue(); + + list.Enqueue( local ); + } + + public void Branch( Label label ) + { + m_Generator.Emit( OpCodes.Br, label ); + } + + public void BranchIfFalse( Label label ) + { + Pop( typeof( object ) ); + + m_Generator.Emit( OpCodes.Brfalse, label ); + } + + public void BranchIfTrue( Label label ) + { + Pop( typeof( object ) ); + + m_Generator.Emit( OpCodes.Brtrue, label ); + } + + public Label CreateLabel() + { + return m_Generator.DefineLabel(); + } + + public void MarkLabel( Label label ) + { + m_Generator.MarkLabel( label ); + } + + public void Pop() + { + m_Stack.Pop(); + } + + public void Pop( Type expected ) + { + if ( expected == null ) + throw new InvalidOperationException( "Expected type cannot be null." ); + + Type onStack = m_Stack.Pop(); + + if ( expected == typeof( bool ) ) + expected = typeof( int ); + + if ( onStack == typeof( bool ) ) + onStack = typeof( int ); + + if ( !expected.IsAssignableFrom( onStack ) ) + throw new InvalidOperationException( "Unexpected stack state." ); + } + + public void Push( Type type ) + { + m_Stack.Push( type ); + } + + public void Return() + { + if ( m_Stack.Count != ( m_Builder.ReturnType == typeof( void ) ? 0 : 1 ) ) + throw new InvalidOperationException( "Stack return mismatch." ); + + m_Generator.Emit( OpCodes.Ret ); + } + + public void LoadNull() + { + LoadNull( typeof( object ) ); + } + + public void LoadNull( Type type ) + { + Push( type ); + + m_Generator.Emit( OpCodes.Ldnull ); + } + + public void Load( string value ) + { + Push( typeof( string ) ); + + if ( value != null ) + m_Generator.Emit( OpCodes.Ldstr, value ); + else + m_Generator.Emit( OpCodes.Ldnull ); + } + + public void Load( Enum value ) + { + int toLoad = ((IConvertible)value).ToInt32( null ); + Load( toLoad ); + + Pop(); + Push( value.GetType() ); + } + + public void Load( long value ) + { + Push( typeof( long ) ); + + m_Generator.Emit( OpCodes.Ldc_I8, value ); + } + + public void Load( float value ) + { + Push( typeof( float ) ); + + m_Generator.Emit( OpCodes.Ldc_R4, value ); + } + + public void Load( double value ) + { + Push( typeof( double ) ); + + m_Generator.Emit( OpCodes.Ldc_R8, value ); + } + + public void Load( char value ) + { + Load( (int) value ); + + Pop(); + Push( typeof( char ) ); + } + + public void Load( bool value ) + { + Push( typeof( bool ) ); + + if ( value ) + m_Generator.Emit( OpCodes.Ldc_I4_1 ); + else + m_Generator.Emit( OpCodes.Ldc_I4_0 ); + } + + public void Load( int value ) + { + Push( typeof( int ) ); + + switch ( value ) + { + case -1: + m_Generator.Emit( OpCodes.Ldc_I4_M1 ); + break; + + case 0: + m_Generator.Emit( OpCodes.Ldc_I4_0 ); + break; + + case 1: + m_Generator.Emit( OpCodes.Ldc_I4_1 ); + break; + + case 2: + m_Generator.Emit( OpCodes.Ldc_I4_2 ); + break; + + case 3: + m_Generator.Emit( OpCodes.Ldc_I4_3 ); + break; + + case 4: + m_Generator.Emit( OpCodes.Ldc_I4_4 ); + break; + + case 5: + m_Generator.Emit( OpCodes.Ldc_I4_5 ); + break; + + case 6: + m_Generator.Emit( OpCodes.Ldc_I4_6 ); + break; + + case 7: + m_Generator.Emit( OpCodes.Ldc_I4_7 ); + break; + + case 8: + m_Generator.Emit( OpCodes.Ldc_I4_8 ); + break; + + default: + if ( value >= sbyte.MinValue && value <= sbyte.MaxValue ) + m_Generator.Emit( OpCodes.Ldc_I4_S, (sbyte) value ); + else + m_Generator.Emit( OpCodes.Ldc_I4, value ); + + break; + } + } + + public void LoadField( FieldInfo field ) + { + Pop( field.DeclaringType ); + + Push( field.FieldType ); + + m_Generator.Emit( OpCodes.Ldfld, field ); + } + + public void LoadLocal( LocalBuilder local ) + { + Push( local.LocalType ); + + int index = local.LocalIndex; + + switch ( index ) + { + case 0: + m_Generator.Emit( OpCodes.Ldloc_0 ); + break; + + case 1: + m_Generator.Emit( OpCodes.Ldloc_1 ); + break; + + case 2: + m_Generator.Emit( OpCodes.Ldloc_2 ); + break; + + case 3: + m_Generator.Emit( OpCodes.Ldloc_3 ); + break; + + default: + if ( index >= byte.MinValue && index <= byte.MinValue ) + m_Generator.Emit( OpCodes.Ldloc_S, (byte) index ); + else + m_Generator.Emit( OpCodes.Ldloc, (short) index ); + + break; + } + } + + public void StoreLocal( LocalBuilder local ) + { + Pop( local.LocalType ); + + m_Generator.Emit( OpCodes.Stloc, local ); + } + + public void LoadArgument( int index ) + { + if ( index > 0 ) + Push( m_ArgumentTypes[index - 1] ); + else + Push( m_TypeBuilder ); + + switch ( index ) + { + case 0: + m_Generator.Emit( OpCodes.Ldarg_0 ); + break; + + case 1: + m_Generator.Emit( OpCodes.Ldarg_1 ); + break; + + case 2: + m_Generator.Emit( OpCodes.Ldarg_2 ); + break; + + case 3: + m_Generator.Emit( OpCodes.Ldarg_3 ); + break; + + default: + if ( index >= byte.MinValue && index <= byte.MaxValue ) + m_Generator.Emit( OpCodes.Ldarg_S, (byte) index ); + else + m_Generator.Emit( OpCodes.Ldarg, (short) index ); + + break; + } + } + + public void CastAs( Type type ) + { + Pop( typeof( object ) ); + Push( type ); + + m_Generator.Emit( OpCodes.Isinst, type ); + } + + public void Neg() + { + Pop( typeof( int ) ); + + Push( typeof( int ) ); + + m_Generator.Emit( OpCodes.Neg ); + } + + public void Compare( OpCode opCode ) + { + Pop(); + Pop(); + + Push( typeof( int ) ); + + m_Generator.Emit( opCode ); + } + + public void LogicalNot() + { + Pop( typeof( int ) ); + + Push( typeof( int ) ); + + m_Generator.Emit( OpCodes.Ldc_I4_0 ); + m_Generator.Emit( OpCodes.Ceq ); + } + + public void Xor() + { + Pop( typeof( int ) ); + Pop( typeof( int ) ); + + Push( typeof( int ) ); + + m_Generator.Emit( OpCodes.Xor ); + } + + public Type Active + { + get { return m_Stack.Peek(); } + } + + public void Chain( Property prop ) + { + for ( int i = 0; i < prop.Chain.Length; ++i ) + Call( prop.Chain[i].GetGetMethod() ); + } + + public void Call( MethodInfo method ) + { + BeginCall( method ); + + CallInfo call = m_Calls.Peek(); + + if ( call.parms.Length > 0 ) + throw new InvalidOperationException( "Method requires parameters." ); + + FinishCall(); + } + + public delegate void Callback(); + +#if MONO + private static bool GenericComparator( Type type, object obj ) + { + return ( type.IsGenericType ) + && ( type.GetGenericTypeDefinition() == typeof( IComparable<> ) ) + && ( type.GetGenericArguments()[0].IsAssignableFrom(obj as Type) ); + } +#endif + + public bool CompareTo( int sign, Callback argGenerator ) + { + Type active = this.Active; + + MethodInfo compareTo = active.GetMethod( "CompareTo", new Type[] { active } ); + + if ( compareTo == null ) + { + /* This gets a little tricky... + * + * There's a scenario where we might be trying to use CompareTo on an interface + * which, while it doesn't explicitly implement CompareTo itself, is said to + * extend IComparable indirectly. The implementation is implicitly passed off + * to implementers... + * + * interface ISomeInterface : IComparable + * { + * void SomeMethod(); + * } + * + * class SomeClass : ISomeInterface + * { + * void SomeMethod() { ... } + * int CompareTo( object other ) { ... } + * } + * + * In this case, calling ISomeInterface.GetMethod( "CompareTo" ) will return null. + * + * Bleh. + */ + +#if MONO + Type[] ifaces = active.FindInterfaces( GenericComparator, active ); +#else + Type[] ifaces = active.FindInterfaces( delegate( Type type, object obj ) + { + return ( type.IsGenericType ) + && ( type.GetGenericTypeDefinition() == typeof( IComparable<> ) ) + && ( type.GetGenericArguments()[0].IsAssignableFrom( active ) ); + }, null ); +#endif + + if ( ifaces.Length > 0 ) + { + compareTo = ifaces[0].GetMethod( "CompareTo", new Type[] { active } ); + } + else + { + ifaces = active.FindInterfaces( delegate( Type type, object obj ) + { + return ( type == typeof( IComparable ) ); + }, null ); + + if ( ifaces.Length > 0 ) + compareTo = ifaces[0].GetMethod( "CompareTo", new Type[] { active } ); + } + } + + if ( compareTo == null ) + return false; + + if ( !active.IsValueType ) + { + /* This object is a reference type, so we have to make it behave + * + * null.CompareTo( null ) = 0 + * real.CompareTo( null ) = -1 + * null.CompareTo( real ) = +1 + * + */ + + LocalBuilder aValue = AcquireTemp( active ); + LocalBuilder bValue = AcquireTemp( active ); + + StoreLocal( aValue ); + + argGenerator(); + + StoreLocal( bValue ); + + /* if ( aValue == null ) + * { + * if ( bValue == null ) + * v = 0; + * else + * v = +1; + * } + * else if ( bValue == null ) + * { + * v = -1; + * } + * else + * { + * v = aValue.CompareTo( bValue ); + * } + */ + + Label store = CreateLabel(); + + Label aNotNull = CreateLabel(); + + LoadLocal( aValue ); + BranchIfTrue( aNotNull ); + // if ( aValue == null ) + { + Label bNotNull = CreateLabel(); + + LoadLocal( bValue ); + BranchIfTrue( bNotNull ); + // if ( bValue == null ) + { + Load( 0 ); + Pop( typeof( int ) ); + Branch( store ); + } + MarkLabel( bNotNull ); + // else + { + Load( sign ); + Pop( typeof( int ) ); + Branch( store ); + } + } + MarkLabel( aNotNull ); + // else + { + Label bNotNull = CreateLabel(); + + LoadLocal( bValue ); + BranchIfTrue( bNotNull ); + // bValue == null + { + Load( -sign ); + Pop( typeof( int ) ); + Branch( store ); + } + MarkLabel( bNotNull ); + // else + { + LoadLocal( aValue ); + BeginCall( compareTo ); + + LoadLocal( bValue ); + ArgumentPushed(); + + FinishCall(); + + if ( sign == -1 ) + Neg(); + } + } + + MarkLabel( store ); + + ReleaseTemp( aValue ); + ReleaseTemp( bValue ); + } + else + { + BeginCall( compareTo ); + + argGenerator(); + + ArgumentPushed(); + + FinishCall(); + + if ( sign == -1 ) + Neg(); + } + + return true; + } + + public void BeginCall( MethodInfo method ) + { + Type type; + + if ( ( method.CallingConvention & CallingConventions.HasThis ) != 0 ) + type = m_Stack.Peek(); + else + type = method.DeclaringType; + + m_Calls.Push( new CallInfo( type, method ) ); + + if ( type.IsValueType ) + { + LocalBuilder temp = AcquireTemp( type ); + + m_Generator.Emit( OpCodes.Stloc, temp ); + m_Generator.Emit( OpCodes.Ldloca, temp ); + + ReleaseTemp( temp ); + } + } + + public void FinishCall() + { + CallInfo call = m_Calls.Pop(); + + if ( ( call.type.IsValueType || call.type.IsByRef ) && call.method.DeclaringType != call.type ) + m_Generator.Emit( OpCodes.Constrained, call.type ); + + if ( call.method.DeclaringType.IsValueType || call.method.IsStatic ) + m_Generator.Emit( OpCodes.Call, call.method ); + else + m_Generator.Emit( OpCodes.Callvirt, call.method ); + + for ( int i = call.parms.Length - 1; i >= 0; --i ) + Pop( call.parms[i].ParameterType ); + + if ( ( call.method.CallingConvention & CallingConventions.HasThis ) != 0 ) + Pop( call.method.DeclaringType ); + + if ( call.method.ReturnType != typeof( void ) ) + Push( call.method.ReturnType ); + } + + public void ArgumentPushed() + { + CallInfo call = m_Calls.Peek(); + + ParameterInfo parm = call.parms[call.index++]; + + Type argumentType = m_Stack.Peek(); + + if ( !parm.ParameterType.IsAssignableFrom( argumentType ) ) + throw new InvalidOperationException( "Parameter type mismatch." ); + + if ( argumentType.IsValueType && !parm.ParameterType.IsValueType ) + m_Generator.Emit( OpCodes.Box, argumentType ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Fastwalk.cs b/Scripts/Misc/Fastwalk.cs new file mode 100644 index 0000000..1562310 --- /dev/null +++ b/Scripts/Misc/Fastwalk.cs @@ -0,0 +1,32 @@ +using System; +using Server; + +namespace Server.Misc +{ + // This fastwalk detection is no longer required + // As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds + public class Fastwalk + { + private static int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected + private static bool Enabled = false; // Is fastwalk detection enabled? + private static bool UOTDOverride = false; // Should UO:TD clients not be checked for fastwalk? + private static AccessLevel AccessOverride = AccessLevel.GameMaster; // Anyone with this or higher access level is not checked for fastwalk + + public static void Initialize() + { + Mobile.FwdMaxSteps = MaxSteps; + Mobile.FwdEnabled = Enabled; + Mobile.FwdUOTDOverride = UOTDOverride; + Mobile.FwdAccessOverride = AccessOverride; + + if ( Enabled ) + EventSink.FastWalk += new FastWalkEventHandler( OnFastWalk ); + } + + public static void OnFastWalk( FastWalkEventArgs e ) + { + e.Blocked = true;//disallow this fastwalk + Console.WriteLine( "Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name ); + } + } +} diff --git a/Scripts/Misc/FoodDecay.cs b/Scripts/Misc/FoodDecay.cs new file mode 100644 index 0000000..b75f4d9 --- /dev/null +++ b/Scripts/Misc/FoodDecay.cs @@ -0,0 +1,62 @@ +using System; +using Server.Network; +using Server; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Misc +{ + public class FoodDecayTimer : Timer + { + public static void Initialize() + { + new FoodDecayTimer().Start(); + } + + // Scriptiz : le temps de decay passe de 5 � 20 minutes + public FoodDecayTimer() : base( TimeSpan.FromMinutes( 20 ), TimeSpan.FromMinutes( 20 ) ) + { + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + FoodDecay(); + } + + public static void FoodDecay() + { + foreach ( NetState state in NetState.Instances ) + { + if (state.Mobile == null) continue; // Scriptiz : sert � rien de traiter les null + + // Scriptiz : les Young et les prisonniers ne subissent pas la faim et la soif + if (state.Mobile is PlayerMobile && (((PlayerMobile)state.Mobile).Young || state.Mobile.Region.IsPartOf(typeof(Jail)))) continue; + + HungerDecay(state.Mobile); + ThirstDecay(state.Mobile); + + // Scriptiz : Mise � jour du gump d'alimentation + if (state.Mobile != null) Alimentation.UpdateGump(state.Mobile); + } + } + + public static void HungerDecay( Mobile m ) + { + if ( m != null && m.Hunger >= 1 ) + m.Hunger -= 1; + + // Scriptiz : Ajout du syst�me de faim + if (m != null) Alimentation.CheckHunger(m); + } + + public static void ThirstDecay( Mobile m ) + { + if ( m != null && m.Thirst >= 1 ) + m.Thirst -= 1; + + // Scriptiz : Ajout du syst�me de soif + if (m != null) Alimentation.CheckThirst(m); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Geometry.cs b/Scripts/Misc/Geometry.cs new file mode 100644 index 0000000..42127cf --- /dev/null +++ b/Scripts/Misc/Geometry.cs @@ -0,0 +1,224 @@ +using System; +using Server; + +namespace Server.Misc +{ + public delegate void DoEffect_Callback( Point3D p, Map map ); + + public static class Geometry + { + public static void Swap( ref T a, ref T b ) + { + T temp = a; + a = b; + b = temp; + } + + public static double RadiansToDegrees( double angle ) + { + return angle * (180.0 / Math.PI); + } + + public static double DegreesToRadians( double angle ) + { + return angle * ( Math.PI / 180.0 ); + } + + public class CirclePoint + { + private Point2D point; + private int angle; + private int quadrant; + + public Point2D Point{ get{ return point; } } + public int Angle{ get{ return angle; } } + public int Quadrant{ get{ return quadrant; } } + + public CirclePoint( Point2D point, int angle, int quadrant ) + { + this.point = point; + this.angle = angle; + this.quadrant = quadrant; + } + } + + public static Point2D ArcPoint( Point3D loc, int radius, int angle ) + { + int sideA, sideB; + + if ( angle < 0 ) + angle = 0; + + if ( angle > 90 ) + angle = 90; + + sideA = (int) Math.Round( radius * Math.Sin( DegreesToRadians( angle ) ) ); + sideB = (int) Math.Round( radius * Math.Cos( DegreesToRadians( angle ) ) ); + + return new Point2D( loc.X - sideB, loc.Y - sideA ); + } + + public static void Circle2D( Point3D loc, Map map, int radius, DoEffect_Callback effect ) + { + Circle2D( loc, map, radius, effect, 0, 360 ); + } + + public static void Circle2D( Point3D loc, Map map, int radius, DoEffect_Callback effect, int angleStart, int angleEnd ) + { + if ( angleStart < 0 || angleStart > 360 ) + angleStart = 0; + + if ( angleEnd > 360 || angleEnd < 0 ) + angleEnd = 360; + + if ( angleStart == angleEnd ) + return; + + bool opposite = angleStart > angleEnd; + + int startQuadrant = angleStart / 90; + int endQuadrant = angleEnd / 90; + + Point2D start = ArcPoint( loc, radius, angleStart % 90 ); + Point2D end = ArcPoint( loc, radius, angleEnd % 90 ); + + if ( opposite ) + { + Swap( ref start, ref end ); + Swap( ref startQuadrant, ref endQuadrant ); + } + + CirclePoint startPoint = new CirclePoint( start, angleStart, startQuadrant ); + CirclePoint endPoint = new CirclePoint( end, angleEnd, endQuadrant ); + + int error = -radius; + int x = radius; + int y = 0; + + while (x > y) + { + plot4points( loc, map, x, y, startPoint, endPoint, effect, opposite ); + plot4points( loc, map, y, x, startPoint, endPoint, effect, opposite ); + + error += ( y * 2 ) + 1; + ++y; + + if (error >= 0) + { + --x; + error -= x * 2; + } + } + + plot4points( loc, map, x, y, startPoint, endPoint, effect, opposite ); + } + + public static void plot4points( Point3D loc, Map map, int x, int y, CirclePoint start, CirclePoint end, DoEffect_Callback effect, bool opposite ) + { + Point2D pointA = new Point2D( loc.X - x, loc.Y - y ); + Point2D pointB = new Point2D( loc.X - y, loc.Y - x ); + + int quadrant = 2; + + if ( x == 0 && start.Quadrant == 3 ) + quadrant = 3; + + if ( WithinCircleBounds( quadrant == 3 ? pointB : pointA, quadrant, loc, start, end, opposite ) ) + effect( new Point3D( loc.X + x, loc.Y + y, loc.Z ), map ); + + quadrant = 3; + + if ( y == 0 && start.Quadrant == 0 ) + quadrant = 0; + + if ( x != 0 && WithinCircleBounds( quadrant == 0 ? pointA : pointB, quadrant, loc, start, end, opposite ) ) + effect( new Point3D( loc.X - x, loc.Y + y, loc.Z ), map ); + if ( y != 0 && WithinCircleBounds( pointB, 1, loc, start, end, opposite ) ) + effect( new Point3D( loc.X + x, loc.Y - y, loc.Z ), map ); + if ( x != 0 && y != 0 && WithinCircleBounds( pointA, 0, loc, start, end, opposite ) ) + effect( new Point3D( loc.X - x, loc.Y - y, loc.Z ), map ); + } + + public static bool WithinCircleBounds( Point2D pointLoc, int pointQuadrant, Point3D center, CirclePoint start, CirclePoint end, bool opposite ) + { + if ( start.Angle == 0 && end.Angle == 360 ) + return true; + + int startX = start.Point.X; + int startY = start.Point.Y; + int endX = end.Point.X; + int endY = end.Point.Y; + + int x = pointLoc.X; + int y = pointLoc.Y; + + if ( pointQuadrant < start.Quadrant || pointQuadrant > end.Quadrant ) + return opposite; + + if ( pointQuadrant > start.Quadrant && pointQuadrant < end.Quadrant ) + return !opposite; + + bool withinBounds = true; + + if ( start.Quadrant == end.Quadrant ) + { + if ( startX == endX && ( x > startX || y > startY || y < endY ) ) + withinBounds = false; + else if ( startY == endY && ( y < startY || x < startX || x > endX ) ) + withinBounds = false; + else if ( x < startX || x > endX || y > startY || y < endY ) + withinBounds = false; + } + else if ( pointQuadrant == start.Quadrant && ( x < startX || y > startY ) ) + withinBounds = false; + else if ( pointQuadrant == end.Quadrant && ( x > endX || y < endY ) ) + withinBounds = false; + + return opposite ? !withinBounds : withinBounds; + } + + public static void Line2D( Point3D start, Point3D end, Map map, DoEffect_Callback effect ) + { + bool steep = Math.Abs( end.Y - start.Y ) > Math.Abs( end.X - start.X ); + + int x0 = start.X; + int x1 = end.X; + int y0 = start.Y; + int y1 = end.Y; + + if ( steep ) + { + Swap( ref x0, ref y0 ); + Swap( ref x1, ref y1 ); + } + + if ( x0 > x1 ) + { + Swap( ref x0, ref x1 ); + Swap( ref y0, ref y1 ); + } + + int deltax = x1 - x0; + int deltay = Math.Abs( y1 - y0 ); + int error = deltax / 2; + int ystep = y0 < y1 ? 1 : -1; + int y = y0; + + for ( int x = x0; x <= x1; x++ ) + { + if ( steep ) + effect( new Point3D( y, x, start.Z ), map ); + else + effect( new Point3D( x, y, start.Z ), map ); + + error -= deltay; + + if ( error < 0 ) + { + y += ystep; + error += deltax; + } + } + } + } +} diff --git a/Scripts/Misc/Gifts/Winter2004/DecorativeTopiary.cs b/Scripts/Misc/Gifts/Winter2004/DecorativeTopiary.cs new file mode 100644 index 0000000..bb351c3 --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/DecorativeTopiary.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class DecorativeTopiary : Item + { + [Constructable] + public DecorativeTopiary() : base( 0x2378 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public DecorativeTopiary( Serial serial ) : base( serial ) + { + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1070880 ); // Winter 2004 + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070880 ); // Winter 2004 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/FestiveCactus.cs b/Scripts/Misc/Gifts/Winter2004/FestiveCactus.cs new file mode 100644 index 0000000..6cad8f7 --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/FestiveCactus.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class FestiveCactus : Item + { + [Constructable] + public FestiveCactus() : base( 0x2376 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public FestiveCactus( Serial serial ) : base( serial ) + { + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1070880 ); // Winter 2004 + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070880 ); // Winter 2004 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs b/Scripts/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs new file mode 100644 index 0000000..8aadd92 --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/LightOfTheWinterSolstice.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 0x236E, 0x2371 )] + public class LightOfTheWinterSolstice : Item + { + private static string[] m_StaffNames = new string[] + { + "Aenima", + "Alkiser", + "ASayre", + "David", + "Krrios", + "Mark", + "Merlin", + "Merlix", //LordMerlix + "Phantom", + "Phenos", + "psz", + "Ryan", + "Quantos", + "Outkast", //TheOutkastDev + "V", //Admin_V + "Zippy" + }; + + private string m_Dipper; + + [CommandProperty( AccessLevel.GameMaster )] + public string Dipper{ get{ return m_Dipper; } set{ m_Dipper = value; } } + + [Constructable] + public LightOfTheWinterSolstice() : this( m_StaffNames[Utility.Random( m_StaffNames.Length )] ) + { + } + + [Constructable] + public LightOfTheWinterSolstice( string dipper ) : base( 0x236E ) + { + m_Dipper = dipper; + + Weight = 1.0; + LootType = LootType.Blessed; + Light = LightType.Circle300; + Hue = Utility.RandomDyedHue(); + } + + public LightOfTheWinterSolstice( Serial serial ) : base( serial ) + { + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1070881, m_Dipper ); // Hand Dipped by ~1_name~ + LabelTo( from, 1070880 ); // Winter 2004 + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070881, m_Dipper ); // Hand Dipped by ~1_name~ + list.Add( 1070880 ); // Winter 2004 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (string) m_Dipper ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Dipper = reader.ReadString(); + break; + } + case 0: + { + m_Dipper = m_StaffNames[Utility.Random( m_StaffNames.Length )]; + break; + } + } + + if (m_Dipper != null) + m_Dipper = String.Intern(m_Dipper); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/Mistletoe.cs b/Scripts/Misc/Gifts/Winter2004/Mistletoe.cs new file mode 100644 index 0000000..8a64ed8 --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/Mistletoe.cs @@ -0,0 +1,342 @@ +using System; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class MistletoeAddon : Item, IDyable, IAddon + { + [Constructable] + public MistletoeAddon() : this( Utility.RandomDyedHue() ) + { + } + + [Constructable] + public MistletoeAddon( int hue ) : base( 0x2375 ) + { + Hue = hue; + Movable = false; + } + + public MistletoeAddon( Serial serial ) : base( serial ) + { + } + + public bool CouldFit( IPoint3D p, Map map ) + { + if ( !map.CanFit( p.X, p.Y, p.Z, this.ItemData.Height ) ) + return false; + + if ( this.ItemID == 0x2375 ) + return BaseAddon.IsWall( p.X, p.Y - 1, p.Z, map ); // North wall + else + return BaseAddon.IsWall( p.X - 1, p.Y, p.Z, map ); // West wall + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixMovingCrate ) ); + } + + private void FixMovingCrate() + { + if ( this.Deleted ) + return; + + if ( this.Movable || this.IsLockedDown ) + { + Item deed = this.Deed; + + if ( this.Parent is Item ) + { + ((Item)this.Parent).AddItem( deed ); + deed.Location = this.Location; + } + else + { + deed.MoveToWorld( this.Location, this.Map ); + } + + Delete(); + } + } + + public Item Deed + { + get{ return new MistletoeDeed( this.Hue ); } + } + + public override void OnDoubleClick( Mobile from ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsCoOwner( from ) ) + { + if ( from.InRange( this.GetWorldLocation(), 3 ) ) + { + from.CloseGump( typeof( MistletoeAddonGump ) ); + from.SendGump( new MistletoeAddonGump( from, this ) ); + } + else + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + } + } + } + + public virtual bool Dye( Mobile from, DyeTub sender ) + { + if ( Deleted ) + return false; + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && house.IsCoOwner( from ) ) + { + if ( from.InRange( GetWorldLocation(), 1 ) ) + { + Hue = sender.DyedHue; + return true; + } + else + { + from.SendLocalizedMessage( 500295 ); // You are too far away to do that. + return false; + } + } + else + { + return false; + } + } + + private class MistletoeAddonGump : Gump + { + private Mobile m_From; + private MistletoeAddon m_Addon; + + public MistletoeAddonGump( Mobile from, MistletoeAddon addon ) : base( 150, 50 ) + { + m_From = from; + m_Addon = addon; + + AddPage( 0 ); + + AddBackground( 0, 0, 220, 170, 0x13BE ); + AddBackground( 10, 10, 200, 150, 0xBB8 ); + AddHtmlLocalized( 20, 30, 180, 60, 1062839, false, false ); // Do you wish to re-deed this decoration? + AddHtmlLocalized( 55, 100, 160, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 100, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 55, 125, 160, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 125, 0xFA5, 0xFA7, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Addon.Deleted ) + return; + + if ( info.ButtonID == 1 ) + { + if ( m_From.InRange( m_Addon.GetWorldLocation(), 3 ) ) + { + m_From.AddToBackpack( m_Addon.Deed ); + m_Addon.Delete(); + } + else + { + m_From.SendLocalizedMessage( 500295 ); // You are too far away to do that. + } + } + } + } + } + + [Flipable( 0x14F0, 0x14EF )] + public class MistletoeDeed : Item + { + public override int LabelNumber{ get{ return 1070882; } } // Mistletoe Deed + + [Constructable] + public MistletoeDeed() : this( 0 ) + { + } + + [Constructable] + public MistletoeDeed( int hue ) : base( 0x14F0 ) + { + Hue = hue; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public MistletoeDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1070880 ); // Winter 2004 + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070880 ); // Winter 2004 + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + { + BaseHouse house = BaseHouse.FindHouseAt( from ); + + if ( house != null && house.IsCoOwner( from ) ) + { + from.SendLocalizedMessage( 1062838 ); // Where would you like to place this decoration? + from.BeginTarget( -1, true, TargetFlags.None, new TargetStateCallback( Placement_OnTarget ), null ); + } + else + { + from.SendLocalizedMessage( 502092 ); // You must be in your house to do this. + } + } + else + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + } + + public void Placement_OnTarget( Mobile from, object targeted, object state ) + { + IPoint3D p = targeted as IPoint3D; + + if ( p == null ) + return; + + Point3D loc = new Point3D( p ); + + BaseHouse house = BaseHouse.FindHouseAt( loc, from.Map, 16 ); + + if ( house != null && house.IsCoOwner( from ) ) + { + bool northWall = BaseAddon.IsWall( loc.X, loc.Y - 1, loc.Z, from.Map ); + bool westWall = BaseAddon.IsWall( loc.X - 1, loc.Y, loc.Z, from.Map ); + + if ( northWall && westWall ) + from.SendGump( new MistletoeDeedGump( from, loc, this ) ); + else + PlaceAddon( from, loc, northWall, westWall ); + } + else + { + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + } + } + + private void PlaceAddon( Mobile from, Point3D loc, bool northWall, bool westWall ) + { + if ( Deleted ) + return; + + BaseHouse house = BaseHouse.FindHouseAt( loc, from.Map, 16 ); + + if ( house == null || !house.IsCoOwner( from ) ) + { + from.SendLocalizedMessage( 1042036 ); // That location is not in your house. + return; + } + + int itemID = 0; + + if ( northWall ) + itemID = 0x2374; + else if ( westWall ) + itemID = 0x2375; + else + from.SendLocalizedMessage( 1070883 ); // The mistletoe must be placed next to a wall. + + if ( itemID > 0 ) + { + Item addon = new MistletoeAddon( this.Hue ); + + addon.ItemID = itemID; + addon.MoveToWorld( loc, from.Map ); + + house.Addons.Add( addon ); + Delete(); + } + } + + private class MistletoeDeedGump : Gump + { + private Mobile m_From; + private Point3D m_Loc; + private MistletoeDeed m_Deed; + + public MistletoeDeedGump( Mobile from, Point3D loc, MistletoeDeed deed ) : base( 150, 50 ) + { + m_From = from; + m_Loc = loc; + m_Deed = deed; + + AddBackground( 0, 0, 300, 150, 0xA28 ); + + AddPage( 0 ); + + AddItem( 90, 30, 0x2375 ); + AddItem( 180, 30, 0x2374 ); + AddButton( 50, 35, 0x868, 0x869, 1, GumpButtonType.Reply, 0 ); + AddButton( 145, 35, 0x868, 0x869, 2, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Deed.Deleted ) + return; + + switch( info.ButtonID ) + { + case 1: + m_Deed.PlaceAddon( m_From, m_Loc, false, true ); + break; + case 2: + m_Deed.PlaceAddon( m_From, m_Loc, true, false ); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs b/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs new file mode 100644 index 0000000..f853ee1 --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/PileOfGlacialSnow.cs @@ -0,0 +1,151 @@ +using System; +using Server; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class PileOfGlacialSnow : Item + { + [Constructable] + public PileOfGlacialSnow() : base( 0x913 ) + { + Hue = 0x480; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public override int LabelNumber{ get{ return 1070874; } } // a Pile of Glacial Snow + + public PileOfGlacialSnow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1070880 ); // Winter 2004 + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070880 ); // Winter 2004 + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); // You must have the object in your backpack to use it. + } + else if ( from.Mounted ) + from.SendLocalizedMessage ( 1010097 ); // You cannot use this while mounted. + + else if ( from.CanBeginAction( typeof( SnowPile ) ) ) + { + from.SendLocalizedMessage( 1005575 ); // You carefully pack the snow into a ball... + from.Target = new SnowTarget( from, this ); + } + else + { + from.SendLocalizedMessage( 1005574 ); // The snow is not ready to be packed yet. Keep trying. + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + + public InternalTimer( Mobile from ) : base( TimeSpan.FromSeconds( 5.0 ) ) + { + m_From = from; + } + + protected override void OnTick() + { + m_From.EndAction( typeof( SnowPile ) ); + } + } + + private class SnowTarget : Target + { + private Mobile m_Thrower; + private Item m_Snow; + + public SnowTarget( Mobile thrower, Item snow ) : base ( 10, false, TargetFlags.None ) + { + m_Thrower = thrower; + m_Snow = snow; + } + + protected override void OnTarget( Mobile from, object target ) + { + if ( target == from ) + { + from.SendLocalizedMessage( 1005576 ); // You can't throw this at yourself. + } + else if ( target is Mobile ) + { + Mobile targ = (Mobile) target; + Container pack = targ.Backpack; + + if (from.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone)) || targ.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) + { + from.SendMessage("You may not throw snow here."); + } + else if (pack != null && pack.FindItemByType(new Type[] { typeof(SnowPile), typeof(PileOfGlacialSnow) }) != null) + { + if ( from.BeginAction( typeof( SnowPile ) ) ) + { + new InternalTimer( from ).Start(); + + from.PlaySound( 0x145 ); + + from.Animate( 9, 1, 1, true, false, 0 ); + + targ.SendLocalizedMessage( 1010572 ); // You have just been hit by a snowball! + from.SendLocalizedMessage( 1010573 ); // You throw the snowball and hit the target! + + Effects.SendMovingEffect( from, targ, 0x36E4, 7, 0, false, true, 0x47F, 0 ); + } + else + { + from.SendLocalizedMessage( 1005574 ); // The snow is not ready to be packed yet. Keep trying. + } + } + else + { + from.SendLocalizedMessage( 1005577 ); // You can only throw a snowball at something that can throw one back. + } + } + else + { + from.SendLocalizedMessage( 1005577 ); // You can only throw a snowball at something that can throw one back. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/SnowPile.cs b/Scripts/Misc/Gifts/Winter2004/SnowPile.cs new file mode 100644 index 0000000..2c3defc --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/SnowPile.cs @@ -0,0 +1,137 @@ +using System; +using Server; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class SnowPile : Item + { + [Constructable] + public SnowPile() : base( 0x913 ) + { + Hue = 0x481; + Weight = 1.0; + LootType = LootType.Blessed; + } + + public override int LabelNumber{ get{ return 1005578; } } // a pile of snow + + public SnowPile( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); // You must have the object in your backpack to use it. + } + else if ( from.Mounted ) + from.SendLocalizedMessage ( 1010097 ); // You cannot use this while mounted. + + else if ( from.CanBeginAction( typeof( SnowPile ) ) ) + { + from.SendLocalizedMessage( 1005575 ); // You carefully pack the snow into a ball... + from.Target = new SnowTarget( from, this ); + } + else + { + from.SendLocalizedMessage( 1005574 ); // The snow is not ready to be packed yet. Keep trying. + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + + public InternalTimer( Mobile from ) : base( TimeSpan.FromSeconds( 5.0 ) ) + { + m_From = from; + } + + protected override void OnTick() + { + m_From.EndAction( typeof( SnowPile ) ); + } + } + + private class SnowTarget : Target + { + private Mobile m_Thrower; + private Item m_Snow; + + public SnowTarget( Mobile thrower, Item snow ) : base ( 10, false, TargetFlags.None ) + { + m_Thrower = thrower; + m_Snow = snow; + } + + protected override void OnTarget( Mobile from, object target ) + { + if ( target == from ) + { + from.SendLocalizedMessage( 1005576 ); // You can't throw this at yourself. + } + else if ( target is Mobile ) + { + Mobile targ = (Mobile) target; + Container pack = targ.Backpack; + + if (from.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone)) || targ.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) + { + from.SendMessage("You may not throw snow here."); + } + else if (pack != null && pack.FindItemByType(new Type[] { typeof(SnowPile), typeof(PileOfGlacialSnow) }) != null) + { + if ( from.BeginAction( typeof( SnowPile ) ) ) + { + new InternalTimer( from ).Start(); + + from.PlaySound( 0x145 ); + + from.Animate( 9, 1, 1, true, false, 0 ); + + targ.SendLocalizedMessage( 1010572 ); // You have just been hit by a snowball! + from.SendLocalizedMessage( 1010573 ); // You throw the snowball and hit the target! + + Effects.SendMovingEffect( from, targ, 0x36E4, 7, 0, false, true, 0x480, 0 ); + } + else + { + from.SendLocalizedMessage( 1005574 ); // The snow is not ready to be packed yet. Keep trying. + } + } + else + { + from.SendLocalizedMessage( 1005577 ); // You can only throw a snowball at something that can throw one back. + } + } + else + { + from.SendLocalizedMessage( 1005577 ); // You can only throw a snowball at something that can throw one back. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/SnowyTree.cs b/Scripts/Misc/Gifts/Winter2004/SnowyTree.cs new file mode 100644 index 0000000..971394b --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/SnowyTree.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Items +{ + public class SnowyTree : Item + { + [Constructable] + public SnowyTree() : base( 0x2377 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + } + + public SnowyTree( Serial serial ) : base( serial ) + { + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + LabelTo( from, 1070880 ); // Winter 2004 + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1070880 ); // Winter 2004 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Gifts/Winter2004/Winter2004.cs b/Scripts/Misc/Gifts/Winter2004/Winter2004.cs new file mode 100644 index 0000000..c21e25d --- /dev/null +++ b/Scripts/Misc/Gifts/Winter2004/Winter2004.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Misc +{ + public class WinterGiftGiver2004 : GiftGiver + { + public static void Initialize() + { + GiftGiving.Register( new WinterGiftGiver2004() ); + } + + public override DateTime Start{ get{ return new DateTime( 2004, 12, 24 ); } } + public override DateTime Finish{ get{ return new DateTime( 2005, 1, 1 ); } } + + public override void GiveGift( Mobile mob ) + { + GiftBox box = new GiftBox(); + + box.DropItem( new MistletoeDeed() ); + box.DropItem( new PileOfGlacialSnow() ); + box.DropItem( new LightOfTheWinterSolstice() ); + + int random = Utility.Random( 100 ); + + if ( random < 60 ) + box.DropItem( new DecorativeTopiary() ); + else if ( random < 84 ) + box.DropItem( new FestiveCactus() ); + else + box.DropItem( new SnowyTree() ); + + switch ( GiveGift( mob, box ) ) + { + case GiftResult.Backpack: + mob.SendMessage( 0x482, "Happy Holidays from the team! Gift items have been placed in your backpack." ); + break; + case GiftResult.BankBox: + mob.SendMessage( 0x482, "Happy Holidays from the team! Gift items have been placed in your bank box." ); + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Guild.cs b/Scripts/Misc/Guild.cs new file mode 100644 index 0000000..1325479 --- /dev/null +++ b/Scripts/Misc/Guild.cs @@ -0,0 +1,1881 @@ +using System; +using Server; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Guilds +{ + #region Ranks + [Flags] + public enum RankFlags + { + None = 0x00000000, + CanInvitePlayer = 0x00000001, + AccessGuildItems = 0x00000002, + RemoveLowestRank = 0x00000004, + RemovePlayers = 0x00000008, + CanPromoteDemote = 0x00000010, + ControlWarStatus = 0x00000020, + AllianceControl = 0x00000040, + CanSetGuildTitle = 0x00000080, + CanVote = 0x00000100, + + All = Member | CanInvitePlayer | RemovePlayers | CanPromoteDemote | ControlWarStatus | AllianceControl | CanSetGuildTitle, + Member = RemoveLowestRank | AccessGuildItems | CanVote + } + + public class RankDefinition + { + public static RankDefinition[] Ranks = new RankDefinition[] + { + new RankDefinition( 1062963, 0, RankFlags.None ), //Ronin + new RankDefinition( 1062962, 1, RankFlags.Member ), //Member + new RankDefinition( 1062961, 2, RankFlags.Member | RankFlags.RemovePlayers | RankFlags.CanInvitePlayer | RankFlags.CanSetGuildTitle | RankFlags.CanPromoteDemote ), //Emmissary + new RankDefinition( 1062960, 3, RankFlags.Member | RankFlags.ControlWarStatus ), //Warlord + new RankDefinition( 1062959, 4, RankFlags.All ) //Leader + }; + public static RankDefinition Leader{ get{ return Ranks[4]; } } + public static RankDefinition Member{ get{ return Ranks[1]; } } + public static RankDefinition Lowest{ get{ return Ranks[0]; } } + + private TextDefinition m_Name; + private int m_Rank; + private RankFlags m_Flags; + + public TextDefinition Name{ get{ return m_Name; } } + public int Rank{ get{ return m_Rank; } } + public RankFlags Flags{ get{ return m_Flags; } } + + public RankDefinition( TextDefinition name, int rank, RankFlags flags ) + { + m_Name = name; + m_Rank = rank; + m_Flags = flags; + } + + public bool GetFlag( RankFlags flag ) + { + return ( (m_Flags & flag) != 0 ); + } + + public void SetFlag( RankFlags flag, bool value ) + { + if ( value ) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + } + + #endregion + + #region Alliances + public class AllianceInfo + { + private static Dictionary m_Alliances = new Dictionary(); + + public static Dictionary Alliances + { + get{ return m_Alliances; } + } + + private string m_Name; + private Guild m_Leader; + private List m_Members; + private List m_PendingMembers; + + public string Name + { + get{ return m_Name; } + } + + public void CalculateAllianceLeader() + { + m_Leader = ((m_Members.Count >= 2) ? m_Members[Utility.Random( m_Members.Count )] : null); + } + + public void CheckLeader() + { + if( m_Leader == null || m_Leader.Disbanded ) + { + CalculateAllianceLeader(); + + if( m_Leader == null ) + Disband(); + } + } + + public Guild Leader + { + get + { + CheckLeader(); + return m_Leader; + } + set + { + if( m_Leader != value && value != null ) + AllianceMessage( 1070765, value.Name ); // Your Alliance is now led by ~1_GUILDNAME~ + + m_Leader = value; + + if( m_Leader == null ) + CalculateAllianceLeader(); + } + } + + public bool IsPendingMember( Guild g ) + { + if( g.Alliance != this ) + return false; + + return m_PendingMembers.Contains( g ); + } + + public bool IsMember( Guild g ) + { + if( g.Alliance != this ) + return false; + + return m_Members.Contains( g ); + } + + public AllianceInfo( Guild leader, string name, Guild partner ) + { + m_Leader = leader; + m_Name = name; + + m_Members = new List(); + m_PendingMembers = new List(); + + leader.Alliance = this; + partner.Alliance = this; + + if( !m_Alliances.ContainsKey( m_Name.ToLower() ) ) + m_Alliances.Add( m_Name.ToLower(), this ); + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (int)0 ); //Version + + writer.Write( m_Name ); + writer.Write( m_Leader ); + + writer.WriteGuildList( m_Members, true ); + writer.WriteGuildList( m_PendingMembers, true ); + + if( !m_Alliances.ContainsKey( m_Name.ToLower() ) ) + m_Alliances.Add( m_Name.ToLower(), this ); + } + + public AllianceInfo( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_Name = reader.ReadString(); + m_Leader = reader.ReadGuild() as Guild; + + m_Members = reader.ReadStrongGuildList(); + m_PendingMembers = reader.ReadStrongGuildList(); + + break; + } + } + } + + public void AddPendingGuild( Guild g ) + { + if( g.Alliance != this || m_PendingMembers.Contains( g ) || m_Members.Contains( g ) ) + return; + + m_PendingMembers.Add( g ); + } + + public void TurnToMember( Guild g ) + { + if( g.Alliance != this || !m_PendingMembers.Contains( g ) || m_Members.Contains( g ) ) + return; + + g.GuildMessage( 1070760, this.Name ); // Your Guild has joined the ~1_ALLIANCENAME~ Alliance. + AllianceMessage( 1070761, g.Name ); // A new Guild has joined your Alliance: ~1_GUILDNAME~ + + m_PendingMembers.Remove( g ); + m_Members.Add( g ); + g.Alliance.InvalidateMemberProperties(); + } + + public void RemoveGuild( Guild g ) + { + if( m_PendingMembers.Contains( g ) ) + { + m_PendingMembers.Remove( g ); + } + + if( m_Members.Contains( g ) ) //Sanity, just incase someone with a custom script adds a character to BOTH arrays + { + m_Members.Remove( g ); + g.InvalidateMemberProperties(); + + g.GuildMessage( 1070763, this.Name ); // Your Guild has been removed from the ~1_ALLIANCENAME~ Alliance. + AllianceMessage( 1070764, g.Name ); // A Guild has left your Alliance: ~1_GUILDNAME~ + } + + //g.Alliance = null; //NO G.Alliance call here. Set the Guild's Alliance to null, if you JUST use RemoveGuild, it removes it from the alliance, but doesn't remove the link from the guild to the alliance. setting g.Alliance will call this method. + //to check on OSI: have 3 guilds, make 2 of them a member, one pending. remove one of the memebers. alliance still exist? + //ANSWER: NO + + if( g == m_Leader ) + { + CalculateAllianceLeader(); + + /* + if( m_Leader == null ) //only when m_members.count < 2 + Disband(); + else + AllianceMessage( 1070765, m_Leader.Name ); // Your Alliance is now led by ~1_GUILDNAME~ + */ + } + + if( m_Members.Count < 2 ) + Disband(); + } + + public void Disband() + { + AllianceMessage( 1070762 ); // Your Alliance has dissolved. + + for( int i = 0; i < m_PendingMembers.Count; i++ ) + m_PendingMembers[i].Alliance = null; + + for( int i = 0; i < m_Members.Count; i++ ) + m_Members[i].Alliance = null; + + + AllianceInfo aInfo = null; + + m_Alliances.TryGetValue( m_Name.ToLower(), out aInfo ); + + if( aInfo == this ) + m_Alliances.Remove( m_Name.ToLower() ); + } + + public void InvalidateMemberProperties() + { + InvalidateMemberProperties( false ); + } + + public void InvalidateMemberProperties( bool onlyOPL ) + { + for ( int i = 0; i < m_Members.Count; i++ ) + { + Guild g = m_Members[i]; + + g.InvalidateMemberProperties( onlyOPL ); + } + } + + public void InvalidateMemberNotoriety() + { + for ( int i = 0; i < m_Members.Count; i++ ) + m_Members[i].InvalidateMemberNotoriety(); + } + + #region Alliance[Text]Message(...) + public void AllianceMessage( int num, bool append, string format, params object[] args ) + { + AllianceMessage( num, append, String.Format( format, args) ); + } + public void AllianceMessage( int number ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].GuildMessage( number ); + } + public void AllianceMessage( int number, string args ) + { + AllianceMessage( number, args, 0x3B2 ); + } + public void AllianceMessage( int number, string args, int hue ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].GuildMessage( number, args, hue ); + } + public void AllianceMessage( int number, bool append, string affix ) + { + AllianceMessage( number, append, affix, "", 0x3B2 ); + } + public void AllianceMessage( int number, bool append, string affix, string args ) + { + AllianceMessage( number, append, affix, args, 0x3B2 ); + } + public void AllianceMessage( int number, bool append, string affix, string args, int hue ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].GuildMessage( number, append, affix, args, hue ); + } + + public void AllianceTextMessage( string text ) + { + AllianceTextMessage( 0x3B2, text ); + } + public void AllianceTextMessage( string format, params object[] args ) + { + AllianceTextMessage( 0x3B2, String.Format( format, args ) ); + } + public void AllianceTextMessage( int hue, string text ) + { + for( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].GuildTextMessage( hue, text ); + } + public void AllianceTextMessage( int hue, string format, params object[] args ) + { + AllianceTextMessage( hue, String.Format( format, args ) ); + } + + public void AllianceChat( Mobile from, int hue, string text ) + { + Packet p = null; + for( int i = 0; i < m_Members.Count; i++ ) + { + Guild g = m_Members[i]; + + for( int j = 0; j < g.Members.Count; j++ ) + { + Mobile m = g.Members[j]; + + NetState state = m.NetState; + + if( state != null ) + { + if( p == null ) + p = Packet.Acquire( new UnicodeMessage( from.Serial, from.Body, MessageType.Alliance, hue, 3, from.Language, from.Name, text ) ); + + state.Send( p ); + } + } + } + + Packet.Release( p ); + } + + public void AllianceChat( Mobile from, string text ) + { + PlayerMobile pm = from as PlayerMobile; + + AllianceChat( from, (pm == null) ? 0x3B2 : pm.AllianceMessageHue, text ); + } + #endregion + + public class AllianceRosterGump : GuildDiplomacyGump + { + protected override bool AllowAdvancedSearch{ get{ return false; } } + + private AllianceInfo m_Alliance; + + public AllianceRosterGump( PlayerMobile pm, Guild g, AllianceInfo alliance ): base( pm, g, true, "", 0, alliance.m_Members, alliance.Name ) + { + m_Alliance = alliance; + } + + public AllianceRosterGump( PlayerMobile pm, Guild g, AllianceInfo alliance, IComparer currentComparer, bool ascending, string filter, int startNumber ) : base( pm, g, currentComparer, ascending, filter, startNumber, alliance.m_Members, alliance.Name ) + { + m_Alliance = alliance; + } + + public override Gump GetResentGump( PlayerMobile pm, Guild g, IComparer comparer, bool ascending, string filter, int startNumber ) + { + return new AllianceRosterGump( pm, g, m_Alliance, comparer, ascending, filter, startNumber ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if( info.ButtonID != 8 ) //So that they can't get to the AdvancedSearch button + base.OnResponse( sender, info ); + } + } + } + #endregion + + #region Wars + public enum WarStatus + { + InProgress = -1, + Win, + Lose, + Draw, + Pending + } + + public class WarDeclaration + { + private int m_Kills; + private int m_MaxKills; + + private TimeSpan m_WarLength; + private DateTime m_WarBeginning; + + private Guild m_Guild; + private Guild m_Opponent; + + private bool m_WarRequester; + + public int Kills + { + get{ return m_Kills; } + set{ m_Kills = value; } + } + public int MaxKills + { + get{ return m_MaxKills; } + set{ m_MaxKills = value; } + } + public TimeSpan WarLength + { + get{ return m_WarLength; } + set{ m_WarLength = value; } + } + public Guild Opponent + { + get{ return m_Opponent; } + } + public Guild Guild + { + get{ return m_Guild; } + } + public DateTime WarBeginning + { + get{ return m_WarBeginning; } + set{ m_WarBeginning = value; } + } + public bool WarRequester + { + get{ return m_WarRequester; } + set{ m_WarRequester = value; } + } + + public WarDeclaration( Guild g, Guild opponent, int maxKills, TimeSpan warLength, bool warRequester ) + { + m_Guild = g; + m_MaxKills = maxKills; + m_Opponent = opponent; + m_WarLength = warLength; + m_WarRequester = warRequester; + } + + public WarDeclaration( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Kills = reader.ReadInt(); + m_MaxKills = reader.ReadInt(); + + m_WarLength = reader.ReadTimeSpan(); + m_WarBeginning = reader.ReadDateTime(); + + m_Guild = reader.ReadGuild() as Guild; + m_Opponent = reader.ReadGuild() as Guild; + + m_WarRequester = reader.ReadBool(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (int)0 ); //version + + writer.Write( m_Kills ); + writer.Write( m_MaxKills ); + + writer.Write( m_WarLength ); + writer.Write( m_WarBeginning ); + + writer.Write( m_Guild ); + writer.Write( m_Opponent ); + + writer.Write( m_WarRequester ); + } + + public WarStatus Status + { + get + { + if( m_Opponent == null || m_Opponent.Disbanded ) + return WarStatus.Win; + + if( m_Guild == null || m_Guild.Disbanded ) + return WarStatus.Lose; + + WarDeclaration w = m_Opponent.FindActiveWar( m_Guild ); + + if( m_Opponent.FindPendingWar( m_Guild ) != null && m_Guild.FindPendingWar( m_Opponent ) != null ) + return WarStatus.Pending; + + if( w == null ) + return WarStatus.Win; + + if( m_WarLength != TimeSpan.Zero && (m_WarBeginning + m_WarLength) < DateTime.Now ) + { + if( m_Kills > w.m_Kills ) + return WarStatus.Win; + else if( m_Kills < w.m_Kills ) + return WarStatus.Lose; + else + return WarStatus.Draw; + } + else if( m_MaxKills > 0 ) + { + if( m_Kills >= m_MaxKills ) + return WarStatus.Win; + else if( w.m_Kills >= w.MaxKills ) + return WarStatus.Lose; + } + + return WarStatus.InProgress; + } + } + } + + public class WarTimer : Timer + { + private static TimeSpan InternalDelay = TimeSpan.FromMinutes( 1.0 ); + + public static void Initialize() + { + if( Guild.NewGuildSystem ) + new WarTimer().Start(); + } + + public WarTimer() : base( InternalDelay, InternalDelay ) + { + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + foreach( Guild g in Guild.List.Values ) + g.CheckExpiredWars(); + } + } + + #endregion + + public class Guild : BaseGuild + { + public static void Configure() + { + EventSink.CreateGuild += new CreateGuildHandler( EventSink_CreateGuild ); + EventSink.GuildGumpRequest += new GuildGumpRequestHandler( EventSink_GuildGumpRequest ); + + CommandSystem.Register( "GuildProps", AccessLevel.Counselor, new CommandEventHandler( GuildProps_OnCommand ) ); + } + + #region GuildProps + [Usage( "GuildProps" )] + [Description( "Opens a menu where you can view and edit guild properties of a targeted player or guild stone. If the new Guild system is active, also brings up the guild gump." )] + private static void GuildProps_OnCommand( CommandEventArgs e ) + { + string arg = e.ArgString.Trim(); + Mobile from = e.Mobile; + + if( arg.Length == 0 ) + { + e.Mobile.Target = new GuildPropsTarget(); + } + else + { + Guild g = null; + + int id; + + if( int.TryParse( arg, out id ) ) + g = Guild.Find( id ) as Guild; + + if( g == null ) + { + g = Guild.FindByAbbrev( arg ) as Guild; + + if( g == null ) + g = Guild.FindByName( arg ) as Guild; + } + + if ( g != null ) + { + from.SendGump( new PropertiesGump( from, g ) ); + + if ( NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile ) + from.SendGump( new GuildInfoGump( (PlayerMobile)from, g ) ); + } + } + + } + + private class GuildPropsTarget : Target + { + public GuildPropsTarget() : base( -1, true, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object o ) + { + if( !BaseCommand.IsAccessible( from, o ) ) + { + from.SendMessage( "That is not accessible." ); + return; + } + + Guild g = null; + + if( o is Guildstone ) + { + Guildstone stone = o as Guildstone; + if( stone.Guild == null || stone.Guild.Disbanded ) + { + from.SendMessage( "The guild associated with that Guildstone no longer exists" ); + return; + } + else + g = stone.Guild; + } + else if( o is Mobile ) + { + g = ((Mobile)o).Guild as Guild; + } + + if( g != null ) + { + from.SendGump( new PropertiesGump( from, g ) ); + + if( NewGuildSystem && from.AccessLevel >= AccessLevel.GameMaster && from is PlayerMobile ) + from.SendGump( new GuildInfoGump( (PlayerMobile)from, g ) ); + } + else + { + from.SendMessage( "That is not in a guild!" ); + } + } + } + #endregion + + #region EventSinks + public static void EventSink_GuildGumpRequest( GuildGumpRequestArgs args ) + { + PlayerMobile pm = args.Mobile as PlayerMobile; + if( !NewGuildSystem || pm == null ) + return; + + if( pm.Guild == null ) + pm.SendGump( new CreateGuildGump( pm ) ); + else + pm.SendGump( new GuildInfoGump( pm, pm.Guild as Guild ) ); + } + + public static BaseGuild EventSink_CreateGuild( CreateGuildEventArgs args ) + { + return (BaseGuild)(new Guild( args.Id )); + } + #endregion + + public static bool NewGuildSystem { get { return Core.SE; } } + public static bool OrderChaos { get { return !Core.SE; } } + + + public static readonly int RegistrationFee = 25000; + public static readonly int AbbrevLimit = 4; + public static readonly int NameLimit = 40; + public static readonly int MajorityPercentage = 66; + public static readonly TimeSpan InactiveTime = TimeSpan.FromDays( 30 ); + + + #region New Alliances + + public AllianceInfo Alliance + { + get{ + if( m_AllianceInfo != null ) + return m_AllianceInfo; + else if ( m_AllianceLeader != null ) + return m_AllianceLeader.m_AllianceInfo; + else + return null; + } + set + { + AllianceInfo current = this.Alliance; + + if( value == current ) + return; + + if( current != null ) + { + current.RemoveGuild( this ); + } + + if( value != null ) + { + + if( value.Leader == this ) + m_AllianceInfo = value; + else + m_AllianceLeader = value.Leader; + + value.AddPendingGuild( this ); + } + else + { + m_AllianceInfo = null; + m_AllianceLeader = null; + } + } + } + + [CommandProperty( AccessLevel.Counselor )] + public string AllianceName + { + get + { + AllianceInfo al = this.Alliance; + if( al != null ) + return al.Name; + + return null; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public Guild AllianceLeader + { + get + { + AllianceInfo al = this.Alliance; + + if( al != null ) + return al.Leader; + + return null; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public bool IsAllianceMember + { + get + { + AllianceInfo al = this.Alliance; + + if( al != null ) + return al.IsMember( this ); + + return false; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public bool IsAlliancePendingMember + { + get + { + AllianceInfo al = this.Alliance; + + if( al != null ) + return al.IsPendingMember( this ); + + return false; + } + } + + public static Guild GetAllianceLeader( Guild g ) + { + AllianceInfo alliance = g.Alliance; + + if ( alliance != null && alliance.Leader != null && alliance.IsMember( g ) ) + return alliance.Leader; + + return g; + } + + #endregion + + #region New Wars + + public List PendingWars + { + get{ return m_PendingWars; } + } + public List AcceptedWars + { + get{ return m_AcceptedWars; } + } + + + public WarDeclaration FindPendingWar( Guild g ) + { + for( int i = 0; i < PendingWars.Count; i++ ) + { + WarDeclaration w = PendingWars[i]; + + if( w.Opponent == g ) + return w; + } + + return null; + } + + public WarDeclaration FindActiveWar( Guild g ) + { + for( int i = 0; i < AcceptedWars.Count; i++ ) + { + WarDeclaration w = AcceptedWars[i]; + + if( w.Opponent == g ) + return w; + } + + return null; + } + + public void CheckExpiredWars() + { + for( int i = 0; i < AcceptedWars.Count; i++ ) + { + WarDeclaration w = AcceptedWars[i]; + Guild g = w.Opponent; + + WarStatus status = w.Status; + + if( status != WarStatus.InProgress ) + { + AllianceInfo myAlliance = this.Alliance; + bool inAlliance = ( myAlliance != null && myAlliance.IsMember( this ) ); + + AllianceInfo otherAlliance = ((g != null) ? g.Alliance : null); + bool otherInAlliance = ( otherAlliance != null && otherAlliance.IsMember( this ) ); + + if( inAlliance ) + { + myAlliance.AllianceMessage( 1070739 + (int)status, (g == null) ? "a deleted opponent" : (otherInAlliance ? otherAlliance.Name : g.Name) ); + myAlliance.InvalidateMemberProperties(); + } + else + { + GuildMessage( 1070739 + (int)status, (g == null) ? "a deleted opponent" : (otherInAlliance ? otherAlliance.Name : g.Name) ); + InvalidateMemberProperties(); + } + + this.AcceptedWars.Remove( w ); + + if( g != null ) + { + if( status != WarStatus.Draw ) + status = (WarStatus)((int)status + 1 % 2); + + if( otherInAlliance ) + { + otherAlliance.AllianceMessage( 1070739 + (int)status, ( inAlliance ? this.Alliance.Name : this.Name ) ); + otherAlliance.InvalidateMemberProperties(); + } + else + { + g.GuildMessage( 1070739 + (int)status, (inAlliance ? this.Alliance.Name : this.Name) ); + g.InvalidateMemberProperties(); + } + + g.AcceptedWars.Remove( g.FindActiveWar( this ) ); + } + } + } + + for( int i = 0; i < PendingWars.Count; i++ ) + { + WarDeclaration w = PendingWars[i]; + Guild g = w.Opponent; + + if( w.Status != WarStatus.Pending ) + { + //All sanity in here + this.PendingWars.Remove( w ); + + if( g != null ) + { + g.PendingWars.Remove( g.FindPendingWar( this ) ); + } + } + } + } + + public static void HandleDeath( Mobile victim ) + { + HandleDeath( victim, null ); + } + + public static void HandleDeath( Mobile victim, Mobile killer ) + { + if( !NewGuildSystem ) + return; + + if ( killer == null ) + killer = victim.FindMostRecentDamager( false ); + + if( killer == null || victim.Guild == null || killer.Guild == null ) + return; + + Guild victimGuild = GetAllianceLeader( victim.Guild as Guild ); + Guild killerGuild = GetAllianceLeader( killer.Guild as Guild ); + + WarDeclaration war = killerGuild.FindActiveWar( victimGuild ); + + if( war == null ) + return; + + war.Kills++; + + if ( war.Opponent == victimGuild ) + killerGuild.CheckExpiredWars(); + else + victimGuild.CheckExpiredWars(); + } + #endregion + + #region Var declarations + private Mobile m_Leader; + + private string m_Name; + private string m_Abbreviation; + + private List m_Allies; + private List m_Enemies; + + private List m_Members; + + private Item m_Guildstone; + private Item m_Teleporter; + + private string m_Charter; + private string m_Website; + + private DateTime m_LastFealty; + + private GuildType m_Type; + private DateTime m_TypeLastChange; + + private List m_AllyDeclarations, m_AllyInvitations; + + private List m_WarDeclarations, m_WarInvitations; + private List m_Candidates, m_Accepted; + + private List m_PendingWars, m_AcceptedWars; + + private AllianceInfo m_AllianceInfo; + private Guild m_AllianceLeader; + #endregion + + public Guild( Mobile leader, string name, string abbreviation ) + { + #region Ctor mumbo-jumbo + m_Leader = leader; + + m_Members = new List(); + m_Allies = new List(); + m_Enemies = new List(); + m_WarDeclarations = new List(); + m_WarInvitations = new List(); + m_AllyDeclarations = new List(); + m_AllyInvitations = new List(); + m_Candidates = new List(); + m_Accepted = new List(); + + m_LastFealty = DateTime.Now; + + m_Name = name; + m_Abbreviation = abbreviation; + + m_TypeLastChange = DateTime.MinValue; + + AddMember( m_Leader ); + + if( m_Leader is PlayerMobile ) + ((PlayerMobile)m_Leader).GuildRank = RankDefinition.Leader; + + m_AcceptedWars = new List(); + m_PendingWars = new List(); + #endregion + } + + public Guild( int id ) : base( id )//serialization ctor + { + } + + public void InvalidateMemberProperties() + { + InvalidateMemberProperties( false ); + } + + public void InvalidateMemberProperties( bool onlyOPL ) + { + if ( m_Members != null ) + { + for ( int i = 0; i < m_Members.Count; i++ ) + { + Mobile m = m_Members[i]; + m.InvalidateProperties(); + + if ( !onlyOPL ) + m.Delta( MobileDelta.Noto ); + } + } + } + + public void InvalidateMemberNotoriety() + { + if ( m_Members != null ) + { + for (int i=0;i= 0; --i ) + if ( i < m_Allies.Count ) + RemoveAlly( m_Allies[i] ); + + for ( int i = m_Enemies.Count - 1; i >= 0; --i ) + if ( i < m_Enemies.Count ) + RemoveEnemy( m_Enemies[i] ); + + if ( !NewGuildSystem && m_Guildstone != null ) + m_Guildstone.Delete(); + + m_Guildstone = null; + + CheckExpiredWars(); + + Alliance = null; + } + + #region Is(...) + public bool IsMember( Mobile m ) + { + return m_Members.Contains( m ); + } + + public bool IsAlly( Guild g ) + { + if( NewGuildSystem ) + { + return (Alliance != null && Alliance.IsMember( this ) && Alliance.IsMember( g )); + } + + return m_Allies.Contains( g ); + } + + public bool IsEnemy(Guild g) + { + if (Type != GuildType.Regular && g.Type != GuildType.Regular && Type != g.Type) + return true; + + return IsWar(g); + } + + public bool IsWar( Guild g ) + { + if( g == null ) + return false; + + if( NewGuildSystem ) + { + Guild guild = GetAllianceLeader( this ); + Guild otherGuild = GetAllianceLeader( g ); + + if ( guild.FindActiveWar( otherGuild ) != null ) + return true; + + return false; + } + + + return m_Enemies.Contains( g ); + } + #endregion + + #region Serialization + public override void Serialize( GenericWriter writer ) + { + if ( this.LastFealty+TimeSpan.FromDays( 1.0 ) < DateTime.Now ) + this.CalculateGuildmaster(); + + CheckExpiredWars(); + + if( Alliance != null ) + Alliance.CheckLeader(); + + writer.Write( (int) 5 );//version + + #region War Serialization + writer.Write( m_PendingWars.Count ); + + for( int i = 0; i < m_PendingWars.Count; i++ ) + { + m_PendingWars[i].Serialize( writer ); + } + + writer.Write( m_AcceptedWars.Count ); + + for( int i = 0; i < m_AcceptedWars.Count; i++ ) + { + m_AcceptedWars[i].Serialize( writer ); + } + #endregion + + #region Alliances + + bool isAllianceLeader = (m_AllianceLeader == null && m_AllianceInfo != null ); + writer.Write( isAllianceLeader ); + + if( isAllianceLeader ) + m_AllianceInfo.Serialize( writer ); + else + writer.Write( m_AllianceLeader ); + + #endregion + + // + + writer.WriteGuildList( m_AllyDeclarations, true ); + writer.WriteGuildList( m_AllyInvitations, true ); + + writer.Write( m_TypeLastChange ); + + writer.Write( (int)m_Type ); + + writer.Write( m_LastFealty ); + + writer.Write( m_Leader ); + writer.Write( m_Name ); + writer.Write( m_Abbreviation ); + + writer.WriteGuildList( m_Allies, true ); + writer.WriteGuildList( m_Enemies, true ); + writer.WriteGuildList( m_WarDeclarations, true ); + writer.WriteGuildList( m_WarInvitations, true ); + + writer.Write( m_Members, true ); + writer.Write( m_Candidates, true ); + writer.Write( m_Accepted, true ); + + writer.Write( m_Guildstone ); + writer.Write( m_Teleporter ); + + writer.Write( m_Charter ); + writer.Write( m_Website ); + } + + public override void Deserialize( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch ( version ) + { + case 5: + { + int count = reader.ReadInt(); + + m_PendingWars = new List(); + for( int i = 0; i < count; i++ ) + { + m_PendingWars.Add( new WarDeclaration( reader ) ); + } + + count = reader.ReadInt(); + m_AcceptedWars = new List(); + for( int i = 0; i < count; i++ ) + { + m_AcceptedWars.Add( new WarDeclaration( reader ) ); + } + + bool isAllianceLeader = reader.ReadBool(); + + if( isAllianceLeader ) + m_AllianceInfo = new AllianceInfo( reader ); + else + m_AllianceLeader = reader.ReadGuild() as Guild; + + + goto case 4; + } + case 4: + { + m_AllyDeclarations = reader.ReadStrongGuildList(); + m_AllyInvitations = reader.ReadStrongGuildList(); + + goto case 3; + } + case 3: + { + m_TypeLastChange = reader.ReadDateTime(); + + goto case 2; + } + case 2: + { + m_Type = (GuildType)reader.ReadInt(); + + goto case 1; + } + case 1: + { + m_LastFealty = reader.ReadDateTime(); + + goto case 0; + } + case 0: + { + m_Leader = reader.ReadMobile(); + + if( m_Leader is PlayerMobile ) + ((PlayerMobile)m_Leader).GuildRank = RankDefinition.Leader; + + m_Name = reader.ReadString(); + m_Abbreviation = reader.ReadString(); + + m_Allies = reader.ReadStrongGuildList(); + m_Enemies = reader.ReadStrongGuildList(); + m_WarDeclarations = reader.ReadStrongGuildList(); + m_WarInvitations = reader.ReadStrongGuildList(); + + m_Members = reader.ReadStrongMobileList(); + m_Candidates = reader.ReadStrongMobileList(); + m_Accepted = reader.ReadStrongMobileList(); + + m_Guildstone = reader.ReadItem(); + m_Teleporter = reader.ReadItem(); + + m_Charter = reader.ReadString(); + m_Website = reader.ReadString(); + + break; + } + } + + if ( m_AllyDeclarations == null ) + m_AllyDeclarations = new List(); + + if ( m_AllyInvitations == null ) + m_AllyInvitations = new List(); + + + if ( m_AcceptedWars == null ) + m_AcceptedWars = new List(); + + if ( m_PendingWars == null ) + m_PendingWars = new List(); + + + /* + if ( ( !NewGuildSystem && m_Guildstone == null )|| m_Members.Count == 0 ) + Disband(); + */ + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( VerifyGuild_Callback ) ); + } + + private void VerifyGuild_Callback() + { + if( (!NewGuildSystem && m_Guildstone == null) || m_Members.Count == 0 ) + Disband(); + + CheckExpiredWars(); + + AllianceInfo alliance = this.Alliance; + + if( alliance != null ) + alliance.CheckLeader(); + + alliance = this.Alliance; //CheckLeader could possibly change the value of this.Alliance + + if( alliance != null && !alliance.IsMember( this ) && !alliance.IsPendingMember( this ) ) //This block is there to fix a bug in the code in an older version. + this.Alliance = null; //Will call Alliance.RemoveGuild which will set it null & perform all the pertient checks as far as alliacne disbanding + + } + + #endregion + + #region Add/Remove Member/Old Ally/Old Enemy + public void AddMember( Mobile m ) + { + if ( !m_Members.Contains( m ) ) + { + if ( m.Guild != null && m.Guild != this ) + ((Guild)m.Guild).RemoveMember( m ); + + m_Members.Add( m ); + m.Guild = this; + + if( !NewGuildSystem ) + m.GuildFealty = m_Leader; + else + m.GuildFealty = null; + + if( m is PlayerMobile ) + ((PlayerMobile)m).GuildRank = RankDefinition.Lowest; + + Guild guild = m.Guild as Guild; + + if ( guild != null ) + guild.InvalidateWarNotoriety(); + } + } + + public void RemoveMember( Mobile m ) + { + RemoveMember( m, 1018028 ); // You have been dismissed from your guild. + } + public void RemoveMember( Mobile m, int message ) + { + if ( m_Members.Contains( m ) ) + { + m_Members.Remove( m ); + + Guild guild = m.Guild as Guild; + + m.Guild = null; + + if( m is PlayerMobile ) + ((PlayerMobile)m).GuildRank = RankDefinition.Lowest; + + if( message > 0 ) + m.SendLocalizedMessage( message ); + + if ( m == m_Leader ) + { + CalculateGuildmaster(); + + if ( m_Leader == null ) + Disband(); + } + + if ( m_Members.Count == 0 ) + Disband(); + + if ( guild != null ) + guild.InvalidateWarNotoriety(); + + m.Delta( MobileDelta.Noto ); + } + } + + public void AddAlly( Guild g ) + { + if ( !m_Allies.Contains( g ) ) + { + m_Allies.Add( g ); + + g.AddAlly( this ); + } + } + + public void RemoveAlly( Guild g ) + { + if ( m_Allies.Contains( g ) ) + { + m_Allies.Remove( g ); + + g.RemoveAlly( this ); + } + } + + public void AddEnemy( Guild g ) + { + if ( !m_Enemies.Contains( g ) ) + { + m_Enemies.Add( g ); + + g.AddEnemy( this ); + } + } + + public void RemoveEnemy( Guild g ) + { + if ( m_Enemies != null && m_Enemies.Contains( g ) ) + { + m_Enemies.Remove( g ); + + g.RemoveEnemy( this ); + } + } + + #endregion + + #region Guild[Text]Message(...) + public void GuildMessage( int num, bool append, string format, params object[] args ) + { + GuildMessage( num, append, String.Format( format, args) ); + } + public void GuildMessage( int number ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].SendLocalizedMessage( number ); + } + public void GuildMessage( int number, string args ) + { + GuildMessage( number, args, 0x3B2 ); + } + public void GuildMessage( int number, string args, int hue ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].SendLocalizedMessage( number, args, hue ); + } + public void GuildMessage( int number, bool append, string affix ) + { + GuildMessage( number, append, affix, "", 0x3B2 ); + } + public void GuildMessage( int number, bool append, string affix, string args ) + { + GuildMessage( number, append, affix, args, 0x3B2 ); + } + public void GuildMessage( int number, bool append, string affix, string args, int hue ) + { + for ( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].SendLocalizedMessage( number, append, affix, args, hue ); + } + + public void GuildTextMessage( string text ) + { + GuildTextMessage( 0x3B2, text ); + } + public void GuildTextMessage( string format, params object[] args ) + { + GuildTextMessage( 0x3B2, String.Format( format, args ) ); + } + public void GuildTextMessage( int hue, string text ) + { + for( int i = 0; i < m_Members.Count; ++i ) + m_Members[i].SendMessage( hue, text ); + } + public void GuildTextMessage( int hue, string format, params object[] args ) + { + GuildTextMessage( hue, String.Format( format, args ) ); + } + + public void GuildChat( Mobile from, int hue, string text ) + { + Packet p = null; + for( int i = 0; i < m_Members.Count; i++ ) + { + Mobile m = m_Members[i]; + + NetState state = m.NetState; + + if( state != null ) + { + if( p == null ) + p = Packet.Acquire( new UnicodeMessage( from.Serial, from.Body, MessageType.Guild, hue, 3, from.Language, from.Name, text ) ); + + state.Send( p ); + } + } + + Packet.Release( p ); + } + + public void GuildChat( Mobile from, string text ) + { + PlayerMobile pm = from as PlayerMobile; + + GuildChat( from, (pm == null) ? 0x3B2 : pm.GuildMessageHue, text ); + } + #endregion + + #region Voting + public bool CanVote( Mobile m ) + { + if( NewGuildSystem ) + { + PlayerMobile pm = m as PlayerMobile; + if( pm == null || !pm.GuildRank.GetFlag( RankFlags.CanVote ) ) + return false; + } + + return ( m != null && !m.Deleted && m.Guild == this ); + } + public bool CanBeVotedFor( Mobile m ) + { + if( NewGuildSystem ) + { + PlayerMobile pm = m as PlayerMobile; + if( pm == null || pm.LastOnline + InactiveTime < DateTime.Now ) + return false; + } + + return ( m != null && !m.Deleted && m.Guild == this ); + } + + public void CalculateGuildmaster() + { + Dictionary votes = new Dictionary(); + + int votingMembers = 0; + + for ( int i = 0; m_Members != null && i < m_Members.Count; ++i ) + { + Mobile memb = m_Members[i]; + + if ( !CanVote( memb ) ) + continue; + + Mobile m = memb.GuildFealty; + + if( !CanBeVotedFor( m ) ) + { + if ( m_Leader != null && !m_Leader.Deleted && m_Leader.Guild == this ) + m = m_Leader; + else + m = memb; + } + + if ( m == null ) + continue; + + int v; + + if( !votes.TryGetValue( m, out v ) ) + votes[m] = 1; + else + votes[m] = v + 1; + + votingMembers++; + } + + Mobile winner = null; + int highVotes = 0; + + foreach ( KeyValuePair kvp in votes ) + { + Mobile m = (Mobile)kvp.Key; + int val = (int)kvp.Value; + + if ( winner == null || val > highVotes ) + { + winner = m; + highVotes = val; + } + } + + if( NewGuildSystem && (highVotes * 100) / Math.Max( votingMembers, 1 ) < MajorityPercentage && m_Leader != null && winner != m_Leader && !m_Leader.Deleted && m_Leader.Guild == this ) + winner = m_Leader; + + if ( m_Leader != winner && winner != null ) + GuildMessage( 1018015, true, winner.Name ); // Guild Message: Guildmaster changed to: + + Leader = winner; + m_LastFealty = DateTime.Now; + } + + #endregion + + #region Getters & Setters + [CommandProperty( AccessLevel.GameMaster )] + public Item Guildstone + { + get + { + return m_Guildstone; + } + set + { + m_Guildstone = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Item Teleporter + { + get + { + return m_Teleporter; + } + set + { + m_Teleporter = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override string Name + { + get + { + return m_Name; + } + set + { + m_Name = value; + + InvalidateMemberProperties( true ); + + if ( m_Guildstone != null ) + m_Guildstone.InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Website + { + get + { + return m_Website; + } + set + { + m_Website = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override string Abbreviation + { + get + { + return m_Abbreviation; + } + set + { + m_Abbreviation = value; + + InvalidateMemberProperties( true ); + + if( m_Guildstone != null ) + m_Guildstone.InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Charter + { + get + { + return m_Charter; + } + set + { + m_Charter = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override GuildType Type + { + get + { + return OrderChaos ? m_Type : GuildType.Regular; + } + set + { + if ( m_Type != value ) + { + m_Type = value; + m_TypeLastChange = DateTime.Now; + + InvalidateMemberProperties(); + } + } + } + + + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastFealty + { + get + { + return m_LastFealty; + } + set + { + m_LastFealty = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime TypeLastChange + { + get + { + return m_TypeLastChange; + } + } + + + public List Allies + { + get + { + return m_Allies; + } + } + + public List Enemies + { + get + { + return m_Enemies; + } + } + + public List AllyDeclarations + { + get + { + return m_AllyDeclarations; + } + } + + public List AllyInvitations + { + get + { + return m_AllyInvitations; + } + } + + public List WarDeclarations + { + get + { + return m_WarDeclarations; + } + } + + public List WarInvitations + { + get + { + return m_WarInvitations; + } + } + + public List Candidates + { + get + { + return m_Candidates; + } + } + + public List Accepted + { + get + { + return m_Accepted; + } + } + + public List Members + { + get + { + return m_Members; + } + } + + #endregion + + } +} diff --git a/Scripts/Misc/HardwareInfo.cs b/Scripts/Misc/HardwareInfo.cs new file mode 100644 index 0000000..dca5dbd --- /dev/null +++ b/Scripts/Misc/HardwareInfo.cs @@ -0,0 +1,189 @@ +using System; +using Server; +using Server.Commands; +using Server.Accounting; +using Server.Network; +using Server.Targeting; + +namespace Server +{ + public class HardwareInfo + { + private int m_InstanceID; + private int m_OSMajor, m_OSMinor, m_OSRevision; + private int m_CpuManufacturer, m_CpuFamily, m_CpuModel, m_CpuClockSpeed, m_CpuQuantity; + private int m_PhysicalMemory; + private int m_ScreenWidth, m_ScreenHeight, m_ScreenDepth; + private int m_DXMajor, m_DXMinor; + private int m_VCVendorID, m_VCDeviceID, m_VCMemory; + private int m_Distribution, m_ClientsRunning, m_ClientsInstalled, m_PartialInstalled; + private string m_VCDescription; + private string m_Language; + private string m_Unknown; + private DateTime m_TimeReceived; + + [CommandProperty( AccessLevel.GameMaster )] + public int CpuModel{ get{ return m_CpuModel; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int CpuClockSpeed{ get{ return m_CpuClockSpeed; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int CpuQuantity{ get{ return m_CpuQuantity; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int OSMajor{ get{ return m_OSMajor; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int OSMinor{ get{ return m_OSMinor; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int OSRevision{ get{ return m_OSRevision; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int InstanceID{ get{ return m_InstanceID; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ScreenWidth{ get{ return m_ScreenWidth; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ScreenHeight{ get{ return m_ScreenHeight; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ScreenDepth{ get{ return m_ScreenDepth; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int PhysicalMemory{ get{ return m_PhysicalMemory; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int CpuManufacturer{ get{ return m_CpuManufacturer; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int CpuFamily{ get{ return m_CpuFamily; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int VCVendorID{ get{ return m_VCVendorID; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int VCDeviceID{ get{ return m_VCDeviceID; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int VCMemory{ get{ return m_VCMemory; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DXMajor{ get{ return m_DXMajor; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int DXMinor{ get{ return m_DXMinor; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string VCDescription{ get{ return m_VCDescription; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string Language{ get{ return m_Language; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Distribution{ get{ return m_Distribution; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ClientsRunning{ get{ return m_ClientsRunning; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ClientsInstalled{ get{ return m_ClientsInstalled; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int PartialInstalled{ get{ return m_PartialInstalled; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string Unknown{ get{ return m_Unknown; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime TimeReceived { get { return m_TimeReceived; } } + + public static void Initialize() + { + PacketHandlers.Register( 0xD9, 0x10C, false, new OnPacketReceive( OnReceive ) ); + + CommandSystem.Register( "HWInfo", AccessLevel.GameMaster, new CommandEventHandler( HWInfo_OnCommand ) ); + } + + [Usage( "HWInfo" )] + [Description( "Displays information about a targeted player's hardware." )] + public static void HWInfo_OnCommand( CommandEventArgs e ) + { + e.Mobile.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( HWInfo_OnTarget ) ); + e.Mobile.SendMessage( "Target a player to view their hardware information." ); + } + + public static void HWInfo_OnTarget( Mobile from, object obj ) + { + if ( obj is Mobile && ((Mobile)obj).Player ) + { + Mobile m = (Mobile)obj; + Account acct = m.Account as Account; + + if ( acct != null ) + { + HardwareInfo hwInfo = acct.HardwareInfo; + + if ( hwInfo != null ) + CommandLogging.WriteLine( from, "{0} {1} viewing hardware info of {2}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( m ) ); + + if ( hwInfo != null ) + from.SendGump( new Gumps.PropertiesGump( from, hwInfo ) ); + else + from.SendMessage( "No hardware information for that account was found." ); + } + else + { + from.SendMessage( "No account has been attached to that player." ); + } + } + else + { + from.BeginTarget( -1, false, TargetFlags.None, new TargetCallback( HWInfo_OnTarget ) ); + from.SendMessage( "That is not a player. Try again." ); + } + } + + public static void OnReceive( NetState state, PacketReader pvSrc ) + { + pvSrc.ReadByte(); // 1: <4.0.1a, 2>=4.0.1a + + HardwareInfo info = new HardwareInfo(); + + info.m_InstanceID = pvSrc.ReadInt32(); + info.m_OSMajor = pvSrc.ReadInt32(); + info.m_OSMinor = pvSrc.ReadInt32(); + info.m_OSRevision = pvSrc.ReadInt32(); + info.m_CpuManufacturer = pvSrc.ReadByte(); + info.m_CpuFamily = pvSrc.ReadInt32(); + info.m_CpuModel = pvSrc.ReadInt32(); + info.m_CpuClockSpeed = pvSrc.ReadInt32(); + info.m_CpuQuantity = pvSrc.ReadByte(); + info.m_PhysicalMemory = pvSrc.ReadInt32(); + info.m_ScreenWidth = pvSrc.ReadInt32(); + info.m_ScreenHeight = pvSrc.ReadInt32(); + info.m_ScreenDepth = pvSrc.ReadInt32(); + info.m_DXMajor = pvSrc.ReadInt16(); + info.m_DXMinor = pvSrc.ReadInt16(); + info.m_VCDescription = pvSrc.ReadUnicodeStringLESafe( 64 ); + info.m_VCVendorID = pvSrc.ReadInt32(); + info.m_VCDeviceID = pvSrc.ReadInt32(); + info.m_VCMemory = pvSrc.ReadInt32(); + info.m_Distribution = pvSrc.ReadByte(); + info.m_ClientsRunning = pvSrc.ReadByte(); + info.m_ClientsInstalled = pvSrc.ReadByte(); + info.m_PartialInstalled = pvSrc.ReadByte(); + info.m_Language = pvSrc.ReadUnicodeStringLESafe( 4 ); + info.m_Unknown = pvSrc.ReadStringSafe( 64 ); + + info.m_TimeReceived = DateTime.Now; + + Account acct = state.Account as Account; + + if ( acct != null ) + acct.HardwareInfo = info; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/InhumanSpeech.cs b/Scripts/Misc/InhumanSpeech.cs new file mode 100644 index 0000000..aae4709 --- /dev/null +++ b/Scripts/Misc/InhumanSpeech.cs @@ -0,0 +1,595 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; + +namespace Server.Misc +{ + [Flags] + public enum IHSFlags + { + None = 0x00, + OnDamaged = 0x01, + OnDeath = 0x02, + OnMovement = 0x04, + OnSpeech = 0x08, + All = OnDamaged | OnDeath | OnMovement + } // NOTE: To enable monster conversations, add " | OnSpeech" to the "All" line + + public class InhumanSpeech + { + private static InhumanSpeech m_RatmanSpeech; + + public static InhumanSpeech Ratman + { + get + { + if ( m_RatmanSpeech == null ) + { + m_RatmanSpeech = new InhumanSpeech(); + + m_RatmanSpeech.Hue = 149; + m_RatmanSpeech.Sound = 438; + + m_RatmanSpeech.Flags = IHSFlags.All; + + m_RatmanSpeech.Keywords = new string[] + { + "meat", "gold", "kill", "killing", "slay", + "sword", "axe", "spell", "magic", "spells", + "swords", "axes", "mace", "maces", "monster", + "monsters", "food", "run", "escape", "away", + "help", "dead", "die", "dying", "lose", + "losing", "life", "lives", "death", "ghost", + "ghosts", "british", "blackthorn", "guild", + "guilds", "dragon", "dragons", "game", "games", + "ultima", "silly", "stupid", "dumb", "idiot", + "idiots", "cheesy", "cheezy", "crazy", "dork", + "jerk", "fool", "foolish", "ugly", "insult", "scum" + }; + + m_RatmanSpeech.Responses = new string[] + { + "meat", "kill", "pound", "crush", "yum yum", + "crunch", "destroy", "murder", "eat", "munch", + "massacre", "food", "monster", "evil", "run", + "die", "lose", "dumb", "idiot", "fool", "crazy", + "dinner", "lunch", "breakfast", "fight", "battle", + "doomed", "rip apart", "tear apart", "smash", + "edible?", "shred", "disembowel", "ugly", "smelly", + "stupid", "hideous", "smell", "tasty", "invader", + "attack", "raid", "plunder", "pillage", "treasure", + "loser", "lose", "scum" + }; + + m_RatmanSpeech.Syllables = new string[] + { + "skrit", + + "ch", "ch", + "it", "ti", "it", "ti", + + "ak", "ek", "ik", "ok", "uk", "yk", + "ka", "ke", "ki", "ko", "ku", "ky", + "at", "et", "it", "ot", "ut", "yt", + + "cha", "che", "chi", "cho", "chu", "chy", + "ach", "ech", "ich", "och", "uch", "ych", + "att", "ett", "itt", "ott", "utt", "ytt", + "tat", "tet", "tit", "tot", "tut", "tyt", + "tta", "tte", "tti", "tto", "ttu", "tty", + "tak", "tek", "tik", "tok", "tuk", "tyk", + "ack", "eck", "ick", "ock", "uck", "yck", + "cka", "cke", "cki", "cko", "cku", "cky", + "rak", "rek", "rik", "rok", "ruk", "ryk", + + "tcha", "tche", "tchi", "tcho", "tchu", "tchy", + "rach", "rech", "rich", "roch", "ruch", "rych", + "rrap", "rrep", "rrip", "rrop", "rrup", "rryp", + "ccka", "ccke", "ccki", "ccko", "ccku", "ccky" + }; + } + + return m_RatmanSpeech; + } + } + + private static InhumanSpeech m_OrcSpeech; + + public static InhumanSpeech Orc + { + get + { + if ( m_OrcSpeech == null ) + { + m_OrcSpeech = new InhumanSpeech(); + + m_OrcSpeech.Hue = 34; + m_OrcSpeech.Sound = 432; + + m_OrcSpeech.Flags = IHSFlags.All; + + m_OrcSpeech.Keywords = new string[] + { + "meat", "gold", "kill", "killing", "slay", + "sword", "axe", "spell", "magic", "spells", + "swords", "axes", "mace", "maces", "monster", + "monsters", "food", "run", "escape", "away", + "help", "dead", "die", "dying", "lose", + "losing", "life", "lives", "death", "ghost", + "ghosts", "british", "blackthorn", "guild", + "guilds", "dragon", "dragons", "game", "games", + "ultima", "silly", "stupid", "dumb", "idiot", + "idiots", "cheesy", "cheezy", "crazy", "dork", + "jerk", "fool", "foolish", "ugly", "insult", "scum" + }; + + m_OrcSpeech.Responses = new string[] + { + "meat", "kill", "pound", "crush", "yum yum", + "crunch", "destroy", "murder", "eat", "munch", + "massacre", "food", "monster", "evil", "run", + "die", "lose", "dumb", "idiot", "fool", "crazy", + "dinner", "lunch", "breakfast", "fight", "battle", + "doomed", "rip apart", "tear apart", "smash", + "edible?", "shred", "disembowel", "ugly", "smelly", + "stupid", "hideous", "smell", "tasty", "invader", + "attack", "raid", "plunder", "pillage", "treasure", + "loser", "lose", "scum" + }; + + m_OrcSpeech.Syllables = new string[] + { + "bu", "du", "fu", "ju", "gu", + "ulg", "gug", "gub", "gur", "oog", + "gub", "log", "ru", "stu", "glu", + "ug", "ud", "og", "log", "ro", "flu", + "bo", "duf", "fun", "nog", "dun", "bog", + "dug", "gh", "ghu", "gho", "nug", "ig", + "igh", "ihg", "luh", "duh", "bug", "dug", + "dru", "urd", "gurt", "grut", "grunt", + "snarf", "urgle", "igg", "glu", "glug", + "foo", "bar", "baz", "ghat", "ab", "ad", + "gugh", "guk", "ag", "alm", "thu", "log", + "bilge", "augh", "gha", "gig", "goth", + "zug", "pig", "auh", "gan", "azh", "bag", + "hig", "oth", "dagh", "gulg", "ugh", "ba", + "bid", "gug", "bug", "rug", "hat", "brui", + "gagh", "buad", "buil", "buim", "bum", + "hug", "hug", "buo", "ma", "buor", "ghed", + "buu", "ca", "guk", "clog", "thurg", "car", + "cro", "thu", "da", "cuk", "gil", "cur", "dak", + "dar", "deak", "der", "dil", "dit", "at", "ag", + "dor", "gar", "dre", "tk", "dri", "gka", "rim", + "eag", "egg", "ha", "rod", "eg", "lat", "eichel", + "ek", "ep", "ka", "it", "ut", "ewk", "ba", "dagh", + "faugh", "foz", "fog", "fid", "fruk", "gag", "fub", + "fud", "fur", "bog", "fup", "hagh", "gaa", "kt", + "rekk", "lub", "lug", "tug", "gna", "urg", "l", + "gno", "gnu", "gol", "gom", "kug", "ukk", "jak", + "jek", "rukk", "jja", "akt", "nuk", "hok", "hrol", + "olm", "natz", "i", "i", "o", "u", "ikk", "ign", + "juk", "kh", "kgh", "ka", "hig", "ke", "ki", "klap", + "klu", "knod", "kod", "knu", "thnu", "krug", "nug", + "nar", "nag", "neg", "neh", "oag", "ob", "ogh", "oh", + "om", "dud", "oo", "pa", "hrak", "qo", "quad", "quil", + "ghig", "rur", "sag", "sah", "sg" + }; + } + + return m_OrcSpeech; + } + } + + private static InhumanSpeech m_LizardmanSpeech; + + public static InhumanSpeech Lizardman + { + get + { + if ( m_LizardmanSpeech == null ) + { + m_LizardmanSpeech = new InhumanSpeech(); + + m_LizardmanSpeech.Hue = 58; + m_LizardmanSpeech.Sound = 418; + + m_LizardmanSpeech.Flags = IHSFlags.All; + + m_LizardmanSpeech.Keywords = new string[] + { + "meat", "gold", "kill", "killing", "slay", + "sword", "axe", "spell", "magic", "spells", + "swords", "axes", "mace", "maces", "monster", + "monsters", "food", "run", "escape", "away", + "help", "dead", "die", "dying", "lose", + "losing", "life", "lives", "death", "ghost", + "ghosts", "british", "blackthorn", "guild", + "guilds", "dragon", "dragons", "game", "games", + "ultima", "silly", "stupid", "dumb", "idiot", + "idiots", "cheesy", "cheezy", "crazy", "dork", + "jerk", "fool", "foolish", "ugly", "insult", "scum" + }; + + m_LizardmanSpeech.Responses = new string[] + { + "meat", "kill", "pound", "crush", "yum yum", + "crunch", "destroy", "murder", "eat", "munch", + "massacre", "food", "monster", "evil", "run", + "die", "lose", "dumb", "idiot", "fool", "crazy", + "dinner", "lunch", "breakfast", "fight", "battle", + "doomed", "rip apart", "tear apart", "smash", + "edible?", "shred", "disembowel", "ugly", "smelly", + "stupid", "hideous", "smell", "tasty", "invader", + "attack", "raid", "plunder", "pillage", "treasure", + "loser", "lose", "scum" + }; + + m_LizardmanSpeech.Syllables = new string[] + { + "ss", "sth", "iss", "is", "ith", "kth", + "sith", "this", "its", "sit", "tis", "tsi", + "ssi", "sil", "lis", "sis", "lil", "thil", + "lith", "sthi", "lish", "shi", "shash", "sal", + "miss", "ra", "tha", "thes", "ses", "sas", "las", + "les", "sath", "sia", "ais", "isa", "asi", "asth", + "stha", "sthi", "isth", "asa", "ath", "tha", "als", + "sla", "thth", "ci", "ce", "cy", "yss", "ys", "yth", + "syth", "thys", "yts", "syt", "tys", "tsy", "ssy", + "syl", "lys", "sys", "lyl", "thyl", "lyth", "sthy", + "lysh", "shy", "myss", "ysa", "sthy", "ysth" + }; + } + + return m_LizardmanSpeech; + } + } + + private static InhumanSpeech m_WispSpeech; + + public static InhumanSpeech Wisp + { + get + { + if ( m_WispSpeech == null ) + { + m_WispSpeech = new InhumanSpeech(); + + m_WispSpeech.Hue = 89; + m_WispSpeech.Sound = 466; + + m_WispSpeech.Flags = IHSFlags.OnMovement; + + m_WispSpeech.Syllables = new string[] + { + "b", "c", "d", "f", "g", "h", "i", + "j", "k", "l", "m", "n", "p", "r", + "s", "t", "v", "w", "x", "z", "c", + "c", "x", "x", "x", "x", "x", "y", + "y", "y", "y", "t", "t", "k", "k", + "l", "l", "m", "m", "m", "m", "z" + }; + } + + return m_WispSpeech; + } + } + + private string[] m_Syllables; + private string[] m_Keywords; + private string[] m_Responses; + + private Dictionary m_KeywordHash; + + private int m_Hue; + private int m_Sound; + + private IHSFlags m_Flags; + + public string[] Syllables + { + get{ return m_Syllables; } + set{ m_Syllables = value; } + } + + public string[] Keywords + { + get{ return m_Keywords; } + set + { + m_Keywords = value; + m_KeywordHash = new Dictionary( m_Keywords.Length, StringComparer.OrdinalIgnoreCase ); + for ( int i = 0; i < m_Keywords.Length; ++i ) + m_KeywordHash[m_Keywords[i]] = m_Keywords[i]; + } + } + + public string[] Responses + { + get{ return m_Responses; } + set{ m_Responses = value; } + } + + public int Hue + { + get{ return m_Hue; } + set{ m_Hue = value; } + } + + public int Sound + { + get{ return m_Sound; } + set{ m_Sound = value; } + } + + public IHSFlags Flags + { + get{ return m_Flags; } + set{ m_Flags = value; } + } + + public string GetRandomSyllable() + { + return m_Syllables[Utility.Random( m_Syllables.Length )]; + } + + public string ConstructWord( int syllableCount ) + { + string[] syllables = new string[syllableCount]; + + for ( int i = 0; i < syllableCount; ++i ) + syllables[i] = GetRandomSyllable(); + + return String.Concat( syllables ); + } + + public string ConstructSentance( int wordCount ) + { + StringBuilder sentance = new StringBuilder(); + + bool needUpperCase = true; + + for ( int i = 0; i < wordCount; ++i ) + { + if ( i > 0 ) // not first word ) + { + int random = Utility.RandomMinMax( 1, 15 ); + + if ( random < 11 ) + { + sentance.Append( ' ' ); + } + else + { + needUpperCase = true; + + if ( random > 13 ) + sentance.Append( "! " ); + else + sentance.Append( ". " ); + } + } + + int syllableCount; + + if ( 30 > Utility.Random( 100 ) ) + syllableCount = Utility.Random( 1, 5 ); + else + syllableCount = Utility.Random( 1, 3 ); + + string word = ConstructWord( syllableCount ); + + sentance.Append( word ); + + if ( needUpperCase ) + sentance.Replace( word[0], Char.ToUpper( word[0] ), sentance.Length - word.Length, 1 ); + + needUpperCase = false; + } + + if ( Utility.RandomMinMax( 1, 5 ) == 1 ) + sentance.Append( '!' ); + else + sentance.Append( '.' ); + + return sentance.ToString(); + } + + public void SayRandomTranslate( Mobile mob, params string[] sentancesInEnglish ) + { + SaySentance( mob, Utility.RandomMinMax( 2, 3 ) ); + mob.Say( sentancesInEnglish[Utility.Random( sentancesInEnglish.Length )] ); + } + + private string GetRandomResponseWord( List keywordsFound ) + { + int random = Utility.Random( keywordsFound.Count + m_Responses.Length ); + + if ( random < keywordsFound.Count ) + return keywordsFound[random]; + + return m_Responses[random - keywordsFound.Count]; + } + + public bool OnSpeech( Mobile mob, Mobile speaker, string text ) + { + if ( (m_Flags & IHSFlags.OnSpeech) == 0 || m_Keywords == null || m_Responses == null || m_KeywordHash == null ) + return false; // not enabled + + if ( !speaker.Alive ) + return false; + + if ( !speaker.InRange( mob, 3 ) ) + return false; + + if ( (speaker.Direction & Direction.Mask) != speaker.GetDirectionTo( mob ) ) + return false; + + if ( (mob.Direction & Direction.Mask) != mob.GetDirectionTo( speaker ) ) + return false; + + string[] split = text.Split( ' ' ); + List keywordsFound = new List(); + + for ( int i = 0; i < split.Length; ++i ) + { + string keyword; + m_KeywordHash.TryGetValue( split[i], out keyword ); + + if ( keyword != null ) + keywordsFound.Add( keyword ); + } + + if ( keywordsFound.Count > 0 ) + { + string responseWord; + + if ( Utility.RandomBool() ) + responseWord = GetRandomResponseWord( keywordsFound ); + else + responseWord = keywordsFound[Utility.Random( keywordsFound.Count )]; + + string secondResponseWord = GetRandomResponseWord( keywordsFound ); + + StringBuilder response = new StringBuilder(); + + switch ( Utility.Random( 6 ) ) + { + default: + case 0: + { + response.Append( "Me " ).Append( responseWord ).Append( '?' ); + break; + } + case 1: + { + response.Append( responseWord ).Append( " thee!" ); + response.Replace( responseWord[0], Char.ToUpper( responseWord[0] ), 0, 1 ); + break; + } + case 2: + { + response.Append( responseWord ).Append( '?' ); + response.Replace( responseWord[0], Char.ToUpper( responseWord[0] ), 0, 1 ); + break; + } + case 3: + { + response.Append( responseWord ).Append( "! " ).Append( secondResponseWord ).Append( '.' ); + response.Replace( responseWord[0], Char.ToUpper( responseWord[0] ), 0, 1 ); + response.Replace( secondResponseWord[0], Char.ToUpper( secondResponseWord[0] ), responseWord.Length + 2, 1 ); + break; + } + case 4: + { + response.Append( responseWord ).Append( '.' ); + response.Replace( responseWord[0], Char.ToUpper( responseWord[0] ), 0, 1 ); + break; + } + case 5: + { + response.Append( responseWord ).Append( "? " ).Append( secondResponseWord ).Append( '.' ); + response.Replace( responseWord[0], Char.ToUpper( responseWord[0] ), 0, 1 ); + response.Replace( secondResponseWord[0], Char.ToUpper( secondResponseWord[0] ), responseWord.Length + 2, 1 ); + break; + } + } + + int maxWords = (split.Length / 2) + 1; + + if ( maxWords < 2 ) + maxWords = 2; + else if ( maxWords > 6 ) + maxWords = 6; + + SaySentance( mob, Utility.RandomMinMax( 2, maxWords ) ); + mob.Say( response.ToString() ); + + return true; + } + + return false; + } + + public void OnDeath( Mobile mob ) + { + if ( (m_Flags & IHSFlags.OnDeath) == 0 ) + return; // not enabled + + if ( 90 > Utility.Random( 100 ) ) + return; // 90% chance to do nothing; 10% chance to talk + + SayRandomTranslate( mob, + "Revenge!", + "NOOooo!", + "I... I...", + "Me no die!", + "Me die!", + "Must... not die...", + "Oooh, me hurt...", + "Me dying?" ); + } + + public void OnMovement( Mobile mob, Mobile mover, Point3D oldLocation ) + { + if ( (m_Flags & IHSFlags.OnMovement) == 0 ) + return; // not enabled + + if ( !mover.Player || (mover.Hidden && mover.AccessLevel > AccessLevel.Player) ) + return; + + if ( !mob.InRange( mover, 5 ) || mob.InRange( oldLocation, 5 ) ) + return; // only talk when they enter 5 tile range + + if ( 90 > Utility.Random( 100 ) ) + return; // 90% chance to do nothing; 10% chance to talk + + SaySentance( mob, 6 ); + } + + public void OnDamage( Mobile mob, int amount ) + { + if ( (m_Flags & IHSFlags.OnDamaged) == 0 ) + return; // not enabled + + if ( 90 > Utility.Random( 100 ) ) + return; // 90% chance to do nothing; 10% chance to talk + + if ( amount < 5 ) + { + SayRandomTranslate( mob, + "Ouch!", + "Me not hurt bad!", + "Thou fight bad.", + "Thy blows soft!", + "You bad with weapon!" ); + } + else + { + SayRandomTranslate( mob, + "Ouch! Me hurt!", + "No, kill me not!", + "Me hurt!", + "Away with thee!", + "Oof! That hurt!", + "Aaah! That hurt...", + "Good blow!" ); + } + } + + public void OnConstruct( Mobile mob ) + { + mob.SpeechHue = m_Hue; + } + + public void SaySentance( Mobile mob, int wordCount ) + { + mob.Say( ConstructSentance( wordCount ) ); + mob.PlaySound( m_Sound ); + } + + public InhumanSpeech() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Keywords.cs b/Scripts/Misc/Keywords.cs new file mode 100644 index 0000000..cd8c5d4 --- /dev/null +++ b/Scripts/Misc/Keywords.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Items; +using Server.Guilds; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Misc +{ + public class Keywords + { + public static void Initialize() + { + // Register our speech handler + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + } + + public static void EventSink_Speech( SpeechEventArgs args ) + { + Mobile from = args.Mobile; + int[] keywords = args.Keywords; + + for ( int i = 0; i < keywords.Length; ++i ) + { + switch ( keywords[i] ) + { + case 0x002A: // *i resign from my guild* + { + if ( from.Guild != null ) + ((Guild)from.Guild).RemoveMember( from ); + + break; + } + case 0x0032: // *i must consider my sins* + { + if( !Core.SE ) + { + from.SendMessage( "Short Term Murders : {0}", from.ShortTermMurders ); + from.SendMessage( "Long Term Murders : {0}", from.Kills ); + } + else + { + from.SendMessage( 0x3B2, "Short Term Murders: {0} Long Term Murders: {1}", from.ShortTermMurders, from.Kills ); + } + break; + } + case 0x0035: // i renounce my young player status* + { + if ( from is PlayerMobile && ((PlayerMobile)from).Young && !from.HasGump( typeof( RenounceYoungGump ) ) ) + { + from.SendGump( new RenounceYoungGump() ); + } + + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/LanguageStatistics.cs b/Scripts/Misc/LanguageStatistics.cs new file mode 100644 index 0000000..bc44bba --- /dev/null +++ b/Scripts/Misc/LanguageStatistics.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server; +using Server.Accounting; +using Server.Commands; +using Server.Mobiles; + +namespace Server.Misc +{ + /** + * This file requires to be saved in a Unicode + * compatible format. + * + * Warning: if you change String.Format methods, + * please note that the following character + * is suggested before any left-to-right text + * in order to prevent undesired formatting + * resulting from mixing LR and RL text: ‎ + * + * Use this one if you need to force RL: ‏ + * + * If you do not see the above chars, please + * enable showing of unicode control chars + **/ + + public class LanguageStatistics + { + struct InternationalCode + { + string m_Code; + string m_Language; + string m_Country; + string m_Language_LocalName; + string m_Country_LocalName; + bool m_HasLocalInfo; + + public string Code{ get{ return m_Code; } } + public string Language{ get{ return m_Language; } } + public string Country{ get{ return m_Country; } } + public string Language_LocalName{ get{ return m_Language_LocalName; } } + public string Country_LocalName{ get{ return m_Country_LocalName; } } + + public InternationalCode( string code, string language, string country ) : this( code, language, country, null, null ) + { + m_HasLocalInfo = false; + } + + public InternationalCode( string code, string language, string country, string language_localname, string country_localname ) + { + m_Code = code; + m_Language = language; + m_Country = country; + m_Language_LocalName = language_localname; + m_Country_LocalName = country_localname; + m_HasLocalInfo = true; + } + + public string GetName() + { + string s; + + if ( m_HasLocalInfo ) + { + s = String.Format( "{0}‎ - {1}", DefaultLocalNames ? m_Language_LocalName : m_Language, DefaultLocalNames ? m_Country_LocalName : m_Country ); + + if ( ShowAlternatives ) + s += String.Format( "‎ 【{0}‎ - {1}‎】", DefaultLocalNames ? m_Language : m_Language_LocalName, DefaultLocalNames ? m_Country : m_Country_LocalName ); + } + else + { + s = String.Format( "{0}‎ - {1}", m_Language, m_Country ); + } + + return s; + } + } + + private static InternationalCode[] InternationalCodes = + { + new InternationalCode( "ARA", "Arabic", "Saudi Arabia", "العربية", "السعودية" ), + new InternationalCode( "ARI", "Arabic", "Iraq", "العربية", "العراق" ), + new InternationalCode( "ARE", "Arabic", "Egypt", "العربية", "مصر" ), + new InternationalCode( "ARL", "Arabic", "Libya", "العربية", "ليبيا" ), + new InternationalCode( "ARG", "Arabic", "Algeria", "العربية", "الجزائر" ), + new InternationalCode( "ARM", "Arabic", "Morocco", "العربية", "المغرب" ), + new InternationalCode( "ART", "Arabic", "Tunisia", "العربية", "تونس" ), + new InternationalCode( "ARO", "Arabic", "Oman", "العربية", "عمان" ), + new InternationalCode( "ARY", "Arabic", "Yemen", "العربية", "اليمن" ), + new InternationalCode( "ARS", "Arabic", "Syria", "العربية", "سورية" ), + new InternationalCode( "ARJ", "Arabic", "Jordan", "العربية", "الأردن" ), + new InternationalCode( "ARB", "Arabic", "Lebanon", "العربية", "لبنان" ), + new InternationalCode( "ARK", "Arabic", "Kuwait", "العربية", "الكويت" ), + new InternationalCode( "ARU", "Arabic", "U.A.E.", "العربية", "الامارات" ), + new InternationalCode( "ARH", "Arabic", "Bahrain", "العربية", "البحرين" ), + new InternationalCode( "ARQ", "Arabic", "Qatar", "العربية", "قطر" ), + new InternationalCode( "BGR", "Bulgarian", "Bulgaria", "Български", "България" ), + new InternationalCode( "CAT", "Catalan", "Spain", "Català", "Espanya" ), + new InternationalCode( "CHT", "Chinese", "Taiwan", "台語", "臺灣" ), + new InternationalCode( "CHS", "Chinese", "PRC", "中文", "中国" ), + new InternationalCode( "ZHH", "Chinese", "Hong Kong", "中文", "香港" ), + new InternationalCode( "ZHI", "Chinese", "Singapore", "中文", "新加坡" ), + new InternationalCode( "ZHM", "Chinese", "Macau", "中文", "澳門" ), + new InternationalCode( "CSY", "Czech", "Czech Republic", "Čeština", "Česká republika" ), + new InternationalCode( "DAN", "Danish", "Denmark", "Dansk", "Danmark" ), + new InternationalCode( "DEU", "German", "Germany", "Deutsch", "Deutschland" ), + new InternationalCode( "DES", "German", "Switzerland", "Deutsch", "der Schweiz" ), + new InternationalCode( "DEA", "German", "Austria", "Deutsch", "Österreich" ), + new InternationalCode( "DEL", "German", "Luxembourg", "Deutsch", "Luxembourg" ), + new InternationalCode( "DEC", "German", "Liechtenstein", "Deutsch", "Liechtenstein" ), + new InternationalCode( "ELL", "Greek", "Greece", "Ελληνικά", "Ελλάδα" ), + new InternationalCode( "ENU", "English", "United States" ), + new InternationalCode( "ENG", "English", "United Kingdom" ), + new InternationalCode( "ENA", "English", "Australia" ), + new InternationalCode( "ENC", "English", "Canada" ), + new InternationalCode( "ENZ", "English", "New Zealand" ), + new InternationalCode( "ENI", "English", "Ireland" ), + new InternationalCode( "ENS", "English", "South Africa" ), + new InternationalCode( "ENJ", "English", "Jamaica" ), + new InternationalCode( "ENB", "English", "Caribbean" ), + new InternationalCode( "ENL", "English", "Belize" ), + new InternationalCode( "ENT", "English", "Trinidad" ), + new InternationalCode( "ENW", "English", "Zimbabwe" ), + new InternationalCode( "ENP", "English", "Philippines" ), + new InternationalCode( "ESP", "Spanish", "Spain (Traditional Sort)", "Español", "España (tipo tradicional)" ), + new InternationalCode( "ESM", "Spanish", "Mexico", "Español", "México" ), + new InternationalCode( "ESN", "Spanish", "Spain (International Sort)", "Español", "España (tipo internacional)" ), + new InternationalCode( "ESG", "Spanish", "Guatemala", "Español", "Guatemala" ), + new InternationalCode( "ESC", "Spanish", "Costa Rica", "Español", "Costa Rica" ), + new InternationalCode( "ESA", "Spanish", "Panama", "Español", "Panama" ), + new InternationalCode( "ESD", "Spanish", "Dominican Republic", "Español", "Republica Dominicana" ), + new InternationalCode( "ESV", "Spanish", "Venezuela", "Español", "Venezuela" ), + new InternationalCode( "ESO", "Spanish", "Colombia", "Español", "Colombia" ), + new InternationalCode( "ESR", "Spanish", "Peru", "Español", "Peru" ), + new InternationalCode( "ESS", "Spanish", "Argentina", "Español", "Argentina" ), + new InternationalCode( "ESF", "Spanish", "Ecuador", "Español", "Ecuador" ), + new InternationalCode( "ESL", "Spanish", "Chile", "Español", "Chile" ), + new InternationalCode( "ESY", "Spanish", "Uruguay", "Español", "Uruguay" ), + new InternationalCode( "ESZ", "Spanish", "Paraguay", "Español", "Paraguay" ), + new InternationalCode( "ESB", "Spanish", "Bolivia", "Español", "Bolivia" ), + new InternationalCode( "ESE", "Spanish", "El Salvador", "Español", "El Salvador" ), + new InternationalCode( "ESH", "Spanish", "Honduras", "Español", "Honduras" ), + new InternationalCode( "ESI", "Spanish", "Nicaragua", "Español", "Nicaragua" ), + new InternationalCode( "ESU", "Spanish", "Puerto Rico", "Español", "Puerto Rico" ), + new InternationalCode( "FIN", "Finnish", "Finland", "Suomi", "Suomi" ), + new InternationalCode( "FRA", "French", "France", "Français", "France" ), + new InternationalCode( "FRB", "French", "Belgium", "Français", "Belgique" ), + new InternationalCode( "FRC", "French", "Canada", "Français", "Canada" ), + new InternationalCode( "FRS", "French", "Switzerland", "Français", "Suisse" ), + new InternationalCode( "FRL", "French", "Luxembourg", "Français", "Luxembourg" ), + new InternationalCode( "FRM", "French", "Monaco", "Français", "Monaco" ), + new InternationalCode( "HEB", "Hebrew", "Israel", "עִבְרִית", "ישׂראל" ), + new InternationalCode( "HUN", "Hungarian", "Hungary", "Magyar", "Magyarország" ), + new InternationalCode( "ISL", "Icelandic", "Iceland", "Íslenska", "Ísland" ), + new InternationalCode( "ITA", "Italian", "Italy", "Italiano", "Italia" ), + new InternationalCode( "ITS", "Italian", "Switzerland", "Italiano", "Svizzera" ), + new InternationalCode( "JPN", "Japanese", "Japan", "日本語", "日本" ), + new InternationalCode( "KOR", "Korean (Extended Wansung)", "Korea", "한국어", "한국" ), + new InternationalCode( "NLD", "Dutch", "Netherlands", "Nederlands", "Nederland" ), + new InternationalCode( "NLB", "Dutch", "Belgium", "Nederlands", "België" ), + new InternationalCode( "NOR", "Norwegian", "Norway (Bokmål)", "Norsk", "Norge (Bokmål)" ), + new InternationalCode( "NON", "Norwegian", "Norway (Nynorsk)", "Norsk", "Norge (Nynorsk)" ), + new InternationalCode( "PLK", "Polish", "Poland", "Polski", "Polska" ), + new InternationalCode( "PTB", "Portuguese", "Brazil", "Português", "Brasil" ), + new InternationalCode( "PTG", "Portuguese", "Portugal", "Português", "Brasil" ), + new InternationalCode( "ROM", "Romanian", "Romania", "Limba Română", "România" ), + new InternationalCode( "RUS", "Russian", "Russia", "Русский", "Россия" ), + new InternationalCode( "HRV", "Croatian", "Croatia", "Hrvatski", "Hrvatska" ), + new InternationalCode( "SRL", "Serbian", "Serbia (Latin)", "Srpski", "Srbija i Crna Gora" ), + new InternationalCode( "SRB", "Serbian", "Serbia (Cyrillic)", "Српски", "Србија и Црна Гора" ), + new InternationalCode( "SKY", "Slovak", "Slovakia", "Slovenčina", "Slovensko" ), + new InternationalCode( "SQI", "Albanian", "Albania", "Shqip", "Shqipëria" ), + new InternationalCode( "SVE", "Swedish", "Sweden", "Svenska", "Sverige" ), + new InternationalCode( "SVF", "Swedish", "Finland", "Svenska", "Finland" ), + new InternationalCode( "THA", "Thai", "Thailand", "ภาษาไทย", "ประเทศไทย" ), + new InternationalCode( "TRK", "Turkish", "Turkey", "Türkçe", "Türkiye" ), + new InternationalCode( "URP", "Urdu", "Pakistan", "اردو", "پاکستان" ), + new InternationalCode( "IND", "Indonesian", "Indonesia", "Bahasa Indonesia", "Indonesia" ), + new InternationalCode( "UKR", "Ukrainian", "Ukraine", "Українська", "Украина" ), + new InternationalCode( "BEL", "Belarusian", "Belarus", "Беларускі", "Беларусь" ), + new InternationalCode( "SLV", "Slovene", "Slovenia", "Slovenščina", "Slovenija" ), + new InternationalCode( "ETI", "Estonian", "Estonia", "Eesti", "Eesti" ), + new InternationalCode( "LVI", "Latvian", "Latvia", "Latviešu", "Latvija" ), + new InternationalCode( "LTH", "Lithuanian", "Lithuania", "Lietuvių", "Lietuva" ), + new InternationalCode( "LTC", "Classic Lithuanian", "Lithuania", "Lietuviškai", "Lietuva" ), + new InternationalCode( "FAR", "Farsi", "Iran", "فارسى", "ايران" ), + new InternationalCode( "VIT", "Vietnamese", "Viet Nam", "tiếng Việt", "Việt Nam" ), + new InternationalCode( "HYE", "Armenian", "Armenia", "Հայերէն", "Հայաստան" ), + new InternationalCode( "AZE", "Azeri", "Azerbaijan (Latin)", "Azərbaycanca", "Azərbaycan" ), + new InternationalCode( "AZE", "Azeri", "Azerbaijan (Cyrillic)", "Азәрбајҹанҹа", "Азәрбајҹан" ), + new InternationalCode( "EUQ", "Basque", "Spain", "Euskera", "Espainia" ), + new InternationalCode( "MKI", "Macedonian", "Macedonia", "Македонски", "Македонија" ), + new InternationalCode( "AFK", "Afrikaans", "South Africa", "Afrikaans", "Republiek van Suid-Afrika" ), + new InternationalCode( "KAT", "Georgian", "Georgia", "ქართული", "საკარტველო" ), + new InternationalCode( "FOS", "Faeroese", "Faeroe Islands", "Føroyska", "Føroya" ), + new InternationalCode( "HIN", "Hindi", "India", "हिन्दी", "भारत" ), + new InternationalCode( "MSL", "Malay", "Malaysia", "Bahasa melayu", "Malaysia" ), + new InternationalCode( "MSB", "Malay", "Brunei Darussalam", "Bahasa melayu", "Negara Brunei Darussalam" ), + new InternationalCode( "KAZ", "Kazak", "Kazakstan", "Қазақ", "Қазақстан" ), + new InternationalCode( "SWK", "Swahili", "Kenya", "Kiswahili", "Kenya" ), + new InternationalCode( "UZB", "Uzbek", "Uzbekistan (Latin)", "O'zbek", "O'zbekiston" ), + new InternationalCode( "UZB", "Uzbek", "Uzbekistan (Cyrillic)", "Ўзбек", "Ўзбекистон" ), + new InternationalCode( "TAT", "Tatar", "Tatarstan", "Татарча", "Татарстан" ), + new InternationalCode( "BEN", "Bengali", "India", "বাংলা", "ভারত" ), + new InternationalCode( "PAN", "Punjabi", "India", "ਪੰਜਾਬੀ", "ਭਾਰਤ" ), + new InternationalCode( "GUJ", "Gujarati", "India", "ગુજરાતી", "ભારત" ), + new InternationalCode( "ORI", "Oriya", "India", "ଓଡ଼ିଆ", "ଭାରତ" ), + new InternationalCode( "TAM", "Tamil", "India", "தமிழ்", "இந்தியா" ), + new InternationalCode( "TEL", "Telugu", "India", "తెలుగు", "భారత" ), + new InternationalCode( "KAN", "Kannada", "India", "ಕನ್ನಡ", "ಭಾರತ" ), + new InternationalCode( "MAL", "Malayalam", "India", "മലയാളം", "ഭാരത" ), + new InternationalCode( "ASM", "Assamese", "India", "অসমিয়া", "Bhārat" ), // missing correct country name + new InternationalCode( "MAR", "Marathi", "India", "मराठी", "भारत" ), + new InternationalCode( "SAN", "Sanskrit", "India", "संस्कृत", "भारतम्" ), + new InternationalCode( "KOK", "Konkani", "India", "कोंकणी", "भारत" ) + }; + + private static string GetFormattedInfo( string code ) + { + if ( code == null || code.Length != 3 ) + return String.Format( "Unknown code {0}", code ); + + for ( int i = 0; i < InternationalCodes.Length; i++ ) + { + if ( code == InternationalCodes[i].Code ) + { + return String.Format( "{0}", InternationalCodes[i].GetName() ); + } + } + + return String.Format( "Unknown code {0}", code ); + } + + private static bool DefaultLocalNames = false; + private static bool ShowAlternatives = true; + private static bool CountAccounts = true; // will consider only first character's valid language + + public static void Initialize() + { + CommandSystem.Register( "LanguageStatistics", AccessLevel.Administrator, new CommandEventHandler( LanguageStatistics_OnCommand ) ); + } + + [Usage( "LanguageStatistics" )] + [Description( "Generate a file containing the list of languages for each PlayerMobile." )] + public static void LanguageStatistics_OnCommand( CommandEventArgs e ) + { + Dictionary ht = new Dictionary(); + + using ( StreamWriter writer = new StreamWriter( "languages.txt" ) ) + { + if ( CountAccounts ) + { + // count accounts + foreach ( Account acc in Accounts.GetAccounts() ) + { + for ( int i = 0; i < acc.Length; i++ ) + { + Mobile mob = acc[i]; + + if ( mob == null ) + continue; + + string lang = mob.Language; + + if ( lang != null ) + { + lang = lang.ToUpper(); + + if ( !ht.ContainsKey( lang ) ) + ht[lang] = new InternationalCodeCounter( lang ); + else + ht[lang].Increase(); + + break; + } + } + } + } + else + { + // count playermobiles + foreach( Mobile mob in World.Mobiles.Values ) + { + if ( mob.Player ) + { + string lang = mob.Language; + + if ( lang != null ) + { + lang = lang.ToUpper(); + + if ( !ht.ContainsKey( lang ) ) + ht[lang] = new InternationalCodeCounter( lang ); + else + ht[lang].Increase(); + } + } + } + } + + writer.WriteLine( String.Format( "Language statistics. Numbers show how many {0} use the specified language.", CountAccounts ? "accounts" : "playermobile" ) ); + writer.WriteLine( "====================================================================================================" ); + writer.WriteLine(); + + // sort the list + List list = new List( ht.Values ); + list.Sort( InternationalCodeComparer.Instance ); + + foreach ( InternationalCodeCounter c in list ) + writer.WriteLine( String.Format( "{0}‎ : {1}", GetFormattedInfo( c.Code ), c.Count ) ); + + e.Mobile.SendMessage( "Languages list generated." ); + } + } + + private class InternationalCodeCounter + { + private string m_Code; + private int m_Count; + + public string Code{ get{ return m_Code; } } + public int Count{ get{ return m_Count; } } + + public InternationalCodeCounter( string code ) + { + m_Code = code; + m_Count = 1; + } + + public void Increase() + { + m_Count++; + } + } + + private class InternationalCodeComparer : IComparer + { + public static readonly InternationalCodeComparer Instance = new InternationalCodeComparer(); + + public InternationalCodeComparer() + { + } + + public int Compare( InternationalCodeCounter x, InternationalCodeCounter y ) + { + string a = null, b = null; + int ca = 0, cb = 0; + + a = x.Code; + ca = x.Count; + b = y.Code; + cb = y.Count; + + + if ( ca > cb ) + return -1; + + if ( ca < cb ) + return 1; + + if ( a == null && b == null ) + return 0; + + if ( a == null ) + return 1; + + if ( b == null ) + return -1; + + return a.CompareTo( b ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/LightCycle.cs b/Scripts/Misc/LightCycle.cs new file mode 100644 index 0000000..016d0bf --- /dev/null +++ b/Scripts/Misc/LightCycle.cs @@ -0,0 +1,163 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Commands; + +namespace Server +{ + public class LightCycle + { + public const int DayLevel = 0; + public const int NightLevel = 12; + public const int DungeonLevel = 26; + public const int JailLevel = 9; + + private static int m_LevelOverride = int.MinValue; + + public static int LevelOverride + { + get{ return m_LevelOverride; } + set + { + m_LevelOverride = value; + + for ( int i = 0; i < NetState.Instances.Count; ++i ) + { + NetState ns = NetState.Instances[i]; + Mobile m = ns.Mobile; + + if ( m != null ) + m.CheckLightLevels( false ); + } + } + } + + public static void Initialize() + { + new LightCycleTimer().Start(); + EventSink.Login += new LoginEventHandler( OnLogin ); + + CommandSystem.Register( "GlobalLight", AccessLevel.GameMaster, new CommandEventHandler( Light_OnCommand ) ); + } + + [Usage( "GlobalLight " )] + [Description( "Sets the current global light level." )] + private static void Light_OnCommand( CommandEventArgs e ) + { + if ( e.Length >= 1 ) + { + LevelOverride = e.GetInt32( 0 ); + e.Mobile.SendMessage( "Global light level override has been changed to {0}.", m_LevelOverride ); + } + else + { + LevelOverride = int.MinValue; + e.Mobile.SendMessage( "Global light level override has been cleared." ); + } + } + + public static void OnLogin( LoginEventArgs args ) + { + Mobile m = args.Mobile; + + m.CheckLightLevels( true ); + } + + public static int ComputeLevelFor( Mobile from ) + { + if ( m_LevelOverride > int.MinValue ) + return m_LevelOverride; + + int hours, minutes; + + Server.Items.Clock.GetTime( from.Map, from.X, from.Y, out hours, out minutes ); + + /* OSI times: + * + * Midnight -> 3:59 AM : Night + * 4:00 AM -> 11:59 PM : Day + * + * RunUO times: + * + * 10:00 PM -> 11:59 PM : Scale to night + * Midnight -> 3:59 AM : Night + * 4:00 AM -> 5:59 AM : Scale to day + * 6:00 AM -> 9:59 PM : Day + */ + + if ( hours < 4 ) + return NightLevel; + + if ( hours < 6 ) + return NightLevel + (((((hours - 4) * 60) + minutes) * (DayLevel - NightLevel)) / 120); + + if ( hours < 22 ) + return DayLevel; + + if ( hours < 24 ) + return DayLevel + (((((hours - 22) * 60) + minutes) * (NightLevel - DayLevel)) / 120); + + return NightLevel; // should never be + } + + private class LightCycleTimer : Timer + { + public LightCycleTimer() : base( TimeSpan.FromSeconds( 0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + for ( int i = 0; i < NetState.Instances.Count; ++i ) + { + NetState ns = NetState.Instances[i]; + Mobile m = ns.Mobile; + + if ( m != null ) + m.CheckLightLevels( false ); + } + } + } + + public class NightSightTimer : Timer + { + private Mobile m_Owner; + + public NightSightTimer( Mobile owner ) : base( TimeSpan.FromMinutes( Utility.Random( 15, 25 ) ) ) + { + m_Owner = owner; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Owner.EndAction( typeof( LightCycle ) ); + m_Owner.LightLevel = 0; + BuffInfo.RemoveBuff( m_Owner, BuffIcon.NightSight ); + } + } + + public class PotionNightSightTimer : Timer + { + private Mobile m_Owner; + private NightSightPotion m_Potion; + + public PotionNightSightTimer(Mobile owner, NightSightPotion potion) + : base(TimeSpan.FromMinutes(potion.Time)) + { + m_Owner = owner; + m_Potion = potion; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Owner.EndAction(typeof(LightCycle)); + m_Owner.LightLevel = 0; + BuffInfo.RemoveBuff(m_Owner, BuffIcon.NightSight); + } + } + } +} diff --git a/Scripts/Misc/LoginStats.cs b/Scripts/Misc/LoginStats.cs new file mode 100644 index 0000000..6437745 --- /dev/null +++ b/Scripts/Misc/LoginStats.cs @@ -0,0 +1,30 @@ +using System; +using Server.Network; + +namespace Server.Misc +{ + public class LoginStats + { + public static void Initialize() + { + // Register our event handler + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static void EventSink_Login( LoginEventArgs args ) + { + int userCount = NetState.Instances.Count; + int itemCount = World.Items.Count; + int mobileCount = World.Mobiles.Count; + + Mobile m = args.Mobile; + + m.SendMessage( "Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.", + args.Mobile.Name, + userCount == 1 ? "is" : "are", + userCount, userCount == 1 ? "" : "s", + itemCount, itemCount == 1 ? "" : "s", + mobileCount, mobileCount == 1 ? "" : "s" ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Loot.cs b/Scripts/Misc/Loot.cs new file mode 100644 index 0000000..5865e60 --- /dev/null +++ b/Scripts/Misc/Loot.cs @@ -0,0 +1,839 @@ +using System; +using System.IO; +using System.Reflection; +using Server; +using Server.Items; + +namespace Server +{ + public class Loot + { + #region List definitions + + #region Mondain's Legacy + private static Type[] m_MLWeaponTypes = new Type[] + { + typeof( AssassinSpike ), typeof( DiamondMace ), typeof( ElvenMachete ), + typeof( ElvenSpellblade ), typeof( Leafblade ), typeof( OrnateAxe ), + typeof( RadiantScimitar ), typeof( RuneBlade ), typeof( WarCleaver ), + typeof( WildStaff ) + }; + + public static Type[] MLWeaponTypes { get { return m_MLWeaponTypes; } } + + private static Type[] m_MLRangedWeaponTypes = new Type[] + { + typeof( ElvenCompositeLongbow ), typeof( MagicalShortbow ) + }; + + public static Type[] MLRangedWeaponTypes { get { return m_MLRangedWeaponTypes; } } + + private static Type[] m_MLArmorTypes = new Type[] + { + typeof( Circlet ), typeof( GemmedCirclet ), typeof( LeafTonlet ), + typeof( RavenHelm ), typeof( RoyalCirclet ), typeof( VultureHelm ), + typeof( WingedHelm ), typeof( LeafArms ), typeof( LeafChest ), + typeof( LeafGloves ), typeof( LeafGorget ), typeof( LeafLegs ), + typeof( WoodlandArms ), typeof( WoodlandChest ), typeof( WoodlandGloves ), + typeof( WoodlandGorget ), typeof( WoodlandLegs ), typeof( HideChest ), + typeof( HideGloves ), typeof( HideGorget ), typeof( HidePants ), + typeof( HidePauldrons ) + }; + + public static Type[] MLArmorTypes { get { return m_MLArmorTypes; } } + + private static Type[] m_MLClothingTypes = new Type[] + { + typeof( MaleElvenRobe ), typeof( FemaleElvenRobe ), typeof( ElvenPants ), + typeof( ElvenShirt ), typeof( ElvenDarkShirt ), typeof( ElvenBoots ), + typeof( VultureHelm ), typeof( WoodlandBelt ) + }; + + public static Type[] MLClothingTypes { get { return m_MLClothingTypes; } } + #endregion + + private static Type[] m_SEWeaponTypes = new Type[] + { + typeof( Bokuto ), typeof( Daisho ), typeof( Kama ), + typeof( Lajatang ), typeof( NoDachi ), typeof( Nunchaku ), + typeof( Sai ), typeof( Tekagi ), typeof( Tessen ), + typeof( Tetsubo ), typeof( Wakizashi ) + }; + + public static Type[] SEWeaponTypes{ get{ return m_SEWeaponTypes; } } + + private static Type[] m_AosWeaponTypes = new Type[] + { + typeof( Scythe ), typeof( BoneHarvester ), typeof( Scepter ), + typeof( BladedStaff ), typeof( Pike ), typeof( DoubleBladedStaff ), + typeof( Lance ), typeof( CrescentBlade ) + }; + + public static Type[] AosWeaponTypes{ get{ return m_AosWeaponTypes; } } + + private static Type[] m_WeaponTypes = new Type[] + { + typeof( Axe ), typeof( BattleAxe ), typeof( DoubleAxe ), + typeof( ExecutionersAxe ), typeof( Hatchet ), typeof( LargeBattleAxe ), + typeof( TwoHandedAxe ), typeof( WarAxe ), typeof( Club ), + typeof( Mace ), typeof( Maul ), typeof( WarHammer ), + typeof( WarMace ), typeof( Bardiche ), typeof( Halberd ), + typeof( Spear ), typeof( ShortSpear ), typeof( Pitchfork ), + typeof( WarFork ), typeof( BlackStaff ), typeof( GnarledStaff ), + typeof( QuarterStaff ), typeof( Broadsword ), typeof( Cutlass ), + typeof( Katana ), typeof( Kryss ), typeof( Longsword ), + typeof( Scimitar ), typeof( VikingSword ), typeof( Pickaxe ), + typeof( HammerPick ), typeof( ButcherKnife ), typeof( Cleaver ), + typeof( Dagger ), typeof( SkinningKnife ), typeof( ShepherdsCrook ) + }; + + public static Type[] WeaponTypes{ get{ return m_WeaponTypes; } } + + private static Type[] m_SERangedWeaponTypes = new Type[] + { + typeof( Yumi ) + }; + + public static Type[] SERangedWeaponTypes{ get{ return m_SERangedWeaponTypes; } } + + private static Type[] m_AosRangedWeaponTypes = new Type[] + { + typeof( CompositeBow ), typeof( RepeatingCrossbow ) + }; + + public static Type[] AosRangedWeaponTypes{ get{ return m_AosRangedWeaponTypes; } } + + private static Type[] m_RangedWeaponTypes = new Type[] + { + typeof( Bow ), typeof( Crossbow ), typeof( HeavyCrossbow ) + }; + + public static Type[] RangedWeaponTypes{ get{ return m_RangedWeaponTypes; } } + + private static Type[] m_SEArmorTypes = new Type[] + { + typeof( ChainHatsuburi ), typeof( LeatherDo ), typeof( LeatherHaidate ), + typeof( LeatherHiroSode ), typeof( LeatherJingasa ), typeof( LeatherMempo ), + typeof( LeatherNinjaHood ), typeof( LeatherNinjaJacket ), typeof( LeatherNinjaMitts ), + typeof( LeatherNinjaPants ), typeof( LeatherSuneate ), typeof( DecorativePlateKabuto ), + typeof( HeavyPlateJingasa ), typeof( LightPlateJingasa ), typeof( PlateBattleKabuto ), + typeof( PlateDo ), typeof( PlateHaidate ), typeof( PlateHatsuburi ), + typeof( PlateHiroSode ), typeof( PlateMempo ), typeof( PlateSuneate ), + typeof( SmallPlateJingasa ), typeof( StandardPlateKabuto ), typeof( StuddedDo ), + typeof( StuddedHaidate ), typeof( StuddedHiroSode ), typeof( StuddedMempo ), + typeof( StuddedSuneate ) + }; + + public static Type[] SEArmorTypes{ get{ return m_SEArmorTypes; } } + + private static Type[] m_ArmorTypes = new Type[] + { + typeof( BoneArms ), typeof( BoneChest ), typeof( BoneGloves ), + typeof( BoneLegs ), typeof( BoneHelm ), typeof( ChainChest ), + typeof( ChainLegs ), typeof( ChainCoif ), typeof( Bascinet ), + typeof( CloseHelm ), typeof( Helmet ), typeof( NorseHelm ), + typeof( OrcHelm ), typeof( FemaleLeatherChest ), typeof( LeatherArms ), + typeof( LeatherBustierArms ), typeof( LeatherChest ), typeof( LeatherGloves ), + typeof( LeatherGorget ), typeof( LeatherLegs ), typeof( LeatherShorts ), + typeof( LeatherSkirt ), typeof( LeatherCap ), typeof( FemalePlateChest ), + typeof( PlateArms ), typeof( PlateChest ), typeof( PlateGloves ), + typeof( PlateGorget ), typeof( PlateHelm ), typeof( PlateLegs ), + typeof( RingmailArms ), typeof( RingmailChest ), typeof( RingmailGloves ), + typeof( RingmailLegs ), typeof( FemaleStuddedChest ), typeof( StuddedArms ), + typeof( StuddedBustierArms ), typeof( StuddedChest ), typeof( StuddedGloves ), + typeof( StuddedGorget ), typeof( StuddedLegs ) + }; + + public static Type[] ArmorTypes{ get{ return m_ArmorTypes; } } + + private static Type[] m_AosShieldTypes = new Type[] + { + typeof( ChaosShield ), typeof( OrderShield ) + }; + + public static Type[] AosShieldTypes{ get{ return m_AosShieldTypes; } } + + private static Type[] m_ShieldTypes = new Type[] + { + typeof( BronzeShield ), typeof( Buckler ), typeof( HeaterShield ), + typeof( MetalShield ), typeof( MetalKiteShield ), typeof( WoodenKiteShield ), + typeof( WoodenShield ) + }; + + public static Type[] ShieldTypes{ get{ return m_ShieldTypes; } } + + private static Type[] m_GemTypes = new Type[] + { + typeof( Amber ), typeof( Amethyst ), typeof( Citrine ), + typeof( Diamond ), typeof( Emerald ), typeof( Ruby ), + typeof( Sapphire ), typeof( StarSapphire ), typeof( Tourmaline ) + }; + + public static Type[] GemTypes{ get{ return m_GemTypes; } } + + private static Type[] m_JewelryTypes = new Type[] + { + typeof( GoldRing ), typeof( GoldBracelet ), + typeof( SilverRing ), typeof( SilverBracelet ) + }; + + public static Type[] JewelryTypes{ get{ return m_JewelryTypes; } } + + private static Type[] m_RegTypes = new Type[] + { + typeof( BlackPearl ), typeof( Bloodmoss ), typeof( Garlic ), + typeof( Ginseng ), typeof( MandrakeRoot ), typeof( Nightshade ), + typeof( SulfurousAsh ), typeof( SpidersSilk ) + }; + + public static Type[] RegTypes{ get{ return m_RegTypes; } } + + private static Type[] m_NecroRegTypes = new Type[] + { + typeof( BatWing ), typeof( GraveDust ), typeof( DaemonBlood ), + typeof( NoxCrystal ), typeof( PigIron ) + }; + + public static Type[] NecroRegTypes{ get{ return m_NecroRegTypes; } } + + private static Type[] m_PotionTypes = new Type[] + { + typeof( AgilityPotion ), typeof( StrengthPotion ), typeof( RefreshPotion ), + typeof( LesserCurePotion ), typeof( LesserHealPotion ), typeof( LesserPoisonPotion ) + }; + + public static Type[] PotionTypes{ get{ return m_PotionTypes; } } + + private static Type[] m_SEInstrumentTypes = new Type[] + { + typeof( BambooFlute ) + }; + + public static Type[] SEInstrumentTypes{ get{ return m_SEInstrumentTypes; } } + + private static Type[] m_InstrumentTypes = new Type[] + { + typeof( Drums ), typeof( Harp ), typeof( LapHarp ), + typeof( Lute ), typeof( Tambourine ), typeof( TambourineTassel ) + }; + + public static Type[] InstrumentTypes{ get{ return m_InstrumentTypes; } } + + private static Type[] m_StatueTypes = new Type[] + { + typeof( StatueSouth ), typeof( StatueSouth2 ), typeof( StatueNorth ), + typeof( StatueWest ), typeof( StatueEast ), typeof( StatueEast2 ), + typeof( StatueSouthEast ), typeof( BustSouth ), typeof( BustEast ) + }; + + public static Type[] StatueTypes{ get{ return m_StatueTypes; } } + + private static Type[] m_RegularScrollTypes = new Type[] + { + typeof( ReactiveArmorScroll ), typeof( ClumsyScroll ), typeof( CreateFoodScroll ), typeof( FeeblemindScroll ), + typeof( HealScroll ), typeof( MagicArrowScroll ), typeof( NightSightScroll ), typeof( WeakenScroll ), + typeof( AgilityScroll ), typeof( CunningScroll ), typeof( CureScroll ), typeof( HarmScroll ), + typeof( MagicTrapScroll ), typeof( MagicUnTrapScroll ), typeof( ProtectionScroll ), typeof( StrengthScroll ), + typeof( BlessScroll ), typeof( FireballScroll ), typeof( MagicLockScroll ), typeof( PoisonScroll ), + typeof( TelekinisisScroll ), typeof( TeleportScroll ), typeof( UnlockScroll ), typeof( WallOfStoneScroll ), + typeof( ArchCureScroll ), typeof( ArchProtectionScroll ), typeof( CurseScroll ), typeof( FireFieldScroll ), + typeof( GreaterHealScroll ), typeof( LightningScroll ), typeof( ManaDrainScroll ), typeof( RecallScroll ), + typeof( BladeSpiritsScroll ), typeof( DispelFieldScroll ), typeof( IncognitoScroll ), typeof( MagicReflectScroll ), + typeof( MindBlastScroll ), typeof( ParalyzeScroll ), typeof( PoisonFieldScroll ), typeof( SummonCreatureScroll ), + typeof( DispelScroll ), typeof( EnergyBoltScroll ), typeof( ExplosionScroll ), typeof( InvisibilityScroll ), + typeof( MarkScroll ), typeof( MassCurseScroll ), typeof( ParalyzeFieldScroll ), typeof( RevealScroll ), + typeof( ChainLightningScroll ), typeof( EnergyFieldScroll ), typeof( FlamestrikeScroll ), typeof( GateTravelScroll ), + typeof( ManaVampireScroll ), typeof( MassDispelScroll ), typeof( MeteorSwarmScroll ), typeof( PolymorphScroll ), + typeof( EarthquakeScroll ), typeof( EnergyVortexScroll ), typeof( ResurrectionScroll ), typeof( SummonAirElementalScroll ), + typeof( SummonDaemonScroll ), typeof( SummonEarthElementalScroll ), typeof( SummonFireElementalScroll ), typeof( SummonWaterElementalScroll ) + }; + + private static Type[] m_NecromancyScrollTypes = new Type[] + { + typeof( AnimateDeadScroll ), typeof( BloodOathScroll ), typeof( CorpseSkinScroll ), typeof( CurseWeaponScroll ), + typeof( EvilOmenScroll ), typeof( HorrificBeastScroll ), typeof( LichFormScroll ), typeof( MindRotScroll ), + typeof( PainSpikeScroll ), typeof( PoisonStrikeScroll ), typeof( StrangleScroll ), typeof( SummonFamiliarScroll ), + typeof( VampiricEmbraceScroll ), typeof( VengefulSpiritScroll ), typeof( WitherScroll ), typeof( WraithFormScroll ) + }; + + private static Type[] m_SENecromancyScrollTypes = new Type[] + { + typeof( AnimateDeadScroll ), typeof( BloodOathScroll ), typeof( CorpseSkinScroll ), typeof( CurseWeaponScroll ), + typeof( EvilOmenScroll ), typeof( HorrificBeastScroll ), typeof( LichFormScroll ), typeof( MindRotScroll ), + typeof( PainSpikeScroll ), typeof( PoisonStrikeScroll ), typeof( StrangleScroll ), typeof( SummonFamiliarScroll ), + typeof( VampiricEmbraceScroll ), typeof( VengefulSpiritScroll ), typeof( WitherScroll ), typeof( WraithFormScroll ), + typeof( ExorcismScroll ) + }; + + private static Type[] m_PaladinScrollTypes = new Type[0]; + + #region Mondain's Legacy + private static Type[] m_ArcanistScrollTypes = new Type[] + { + typeof( ArcaneCircleScroll ), typeof( GiftOfRenewalScroll ), typeof( ImmolatingWeaponScroll ), typeof( AttuneWeaponScroll ), + typeof( ThunderstormScroll ), typeof( NatureFuryScroll ), /*typeof( SummonFeyScroll ), typeof( SummonFiendScroll ),*/ + typeof( ReaperFormScroll ), typeof( WildfireScroll ), typeof( EssenceOfWindScroll ), typeof( DryadAllureScroll ), + typeof( EtherealVoyageScroll ), typeof( WordOfDeathScroll ), typeof( GiftOfLifeScroll ), typeof( ArcaneEmpowermentScroll ) + }; + #endregion + + public static Type[] RegularScrollTypes { get { return m_RegularScrollTypes; } } + public static Type[] NecromancyScrollTypes { get { return m_NecromancyScrollTypes; } } + public static Type[] SENecromancyScrollTypes { get { return m_SENecromancyScrollTypes; } } + public static Type[] PaladinScrollTypes { get { return m_PaladinScrollTypes; } } + #region Mondain's Legacy + public static Type[] ArcanistScrollTypes { get { return m_ArcanistScrollTypes; } } + #endregion + + private static Type[] m_GrimmochJournalTypes = new Type[] + { + typeof( GrimmochJournal1 ), typeof( GrimmochJournal2 ), typeof( GrimmochJournal3 ), + typeof( GrimmochJournal6 ), typeof( GrimmochJournal7 ), typeof( GrimmochJournal11 ), + typeof( GrimmochJournal14 ), typeof( GrimmochJournal17 ), typeof( GrimmochJournal23 ) + }; + + public static Type[] GrimmochJournalTypes{ get{ return m_GrimmochJournalTypes; } } + + private static Type[] m_LysanderNotebookTypes = new Type[] + { + typeof( LysanderNotebook1 ), typeof( LysanderNotebook2 ), typeof( LysanderNotebook3 ), + typeof( LysanderNotebook7 ), typeof( LysanderNotebook8 ), typeof( LysanderNotebook11 ) + }; + + public static Type[] LysanderNotebookTypes{ get{ return m_LysanderNotebookTypes; } } + + private static Type[] m_TavarasJournalTypes = new Type[] + { + typeof( TavarasJournal1 ), typeof( TavarasJournal2 ), typeof( TavarasJournal3 ), + typeof( TavarasJournal6 ), typeof( TavarasJournal7 ), typeof( TavarasJournal8 ), + typeof( TavarasJournal9 ), typeof( TavarasJournal11 ), typeof( TavarasJournal14 ), + typeof( TavarasJournal16 ), typeof( TavarasJournal16b ), typeof( TavarasJournal17 ), + typeof( TavarasJournal19 ) + }; + + public static Type[] TavarasJournalTypes{ get{ return m_TavarasJournalTypes; } } + + + + private static Type[] m_NewWandTypes = new Type[] + { + typeof( FireballWand ), typeof( LightningWand ), typeof( MagicArrowWand ), + typeof( GreaterHealWand ), typeof( HarmWand ), typeof( HealWand ) + }; + public static Type[] NewWandTypes { get { return m_NewWandTypes; } } + + private static Type[] m_WandTypes = new Type[] + { + typeof( ClumsyWand ), typeof( FeebleWand ), + typeof( ManaDrainWand ), typeof( WeaknessWand ) + }; + public static Type[] WandTypes { get { return m_WandTypes; } } + + private static Type[] m_OldWandTypes = new Type[] + { + typeof( IDWand ) + }; + public static Type[] OldWandTypes { get { return m_OldWandTypes; } } + + + private static Type[] m_SEClothingTypes = new Type[] + { + typeof( ClothNinjaJacket ), typeof( FemaleKimono ), typeof( Hakama ), + typeof( HakamaShita ), typeof( JinBaori ), typeof( Kamishimo ), + typeof( MaleKimono ), typeof( NinjaTabi ), typeof( Obi ), + typeof( SamuraiTabi ), typeof( TattsukeHakama ), typeof( Waraji ) + }; + + public static Type[] SEClothingTypes{ get{ return m_SEClothingTypes; } } + + private static Type[] m_AosClothingTypes = new Type[] + { + typeof( FurSarong ), typeof( FurCape ), typeof( FlowerGarland ), + typeof( GildedDress ), typeof( FurBoots ), typeof( FormalShirt ), + }; + + public static Type[] AosClothingTypes{ get{ return m_AosClothingTypes; } } + + private static Type[] m_ClothingTypes = new Type[] + { + typeof( Cloak ), + typeof( Bonnet ), typeof( Cap ), typeof( FeatheredHat ), + typeof( FloppyHat ), typeof( JesterHat ), typeof( Surcoat ), + typeof( SkullCap ), typeof( StrawHat ), typeof( TallStrawHat ), + typeof( TricorneHat ), typeof( WideBrimHat ), typeof( WizardsHat ), + typeof( BodySash ), typeof( Doublet ), typeof( Boots ), + typeof( FullApron ), typeof( JesterSuit ), typeof( Sandals ), + typeof( Tunic ), typeof( Shoes ), typeof( Shirt ), + typeof( Kilt ), typeof( Skirt ), typeof( FancyShirt ), + typeof( FancyDress ), typeof( ThighBoots ), typeof( LongPants ), + typeof( PlainDress ), typeof( Robe ), typeof( ShortPants ), + typeof( HalfApron ) + }; + public static Type[] ClothingTypes{ get{ return m_ClothingTypes; } } + + private static Type[] m_SEHatTypes = new Type[] + { + typeof( ClothNinjaHood ), typeof( Kasa ) + }; + + public static Type[] SEHatTypes{ get{ return m_SEHatTypes; } } + + private static Type[] m_AosHatTypes = new Type[] + { + typeof( FlowerGarland ), typeof( BearMask ), typeof( DeerMask ) //Are Bear& Deer mask inside the Pre-AoS loottables too? + }; + + public static Type[] AosHatTypes{ get{ return m_AosHatTypes; } } + + private static Type[] m_HatTypes = new Type[] + { + typeof( SkullCap ), typeof( Bandana ), typeof( FloppyHat ), + typeof( Cap ), typeof( WideBrimHat ), typeof( StrawHat ), + typeof( TallStrawHat ), typeof( WizardsHat ), typeof( Bonnet ), + typeof( FeatheredHat ), typeof( TricorneHat ), typeof( JesterHat ) + }; + + public static Type[] HatTypes{ get{ return m_HatTypes; } } + + private static Type[] m_LibraryBookTypes = new Type[] + { + typeof( GrammarOfOrcish ), typeof( CallToAnarchy ), typeof( ArmsAndWeaponsPrimer ), + typeof( SongOfSamlethe ), typeof( TaleOfThreeTribes ), typeof( GuideToGuilds ), + typeof( BirdsOfBritannia ), typeof( BritannianFlora ), typeof( ChildrenTalesVol2 ), + typeof( TalesOfVesperVol1 ), typeof( DeceitDungeonOfHorror ), typeof( DimensionalTravel ), + typeof( EthicalHedonism ), typeof( MyStory ), typeof( DiversityOfOurLand ), + typeof( QuestOfVirtues ), typeof( RegardingLlamas ), typeof( TalkingToWisps ), + typeof( TamingDragons ), typeof( BoldStranger ), typeof( BurningOfTrinsic ), + typeof( TheFight ), typeof( LifeOfATravellingMinstrel ), typeof( MajorTradeAssociation ), + typeof( RankingsOfTrades ), typeof( WildGirlOfTheForest ), typeof( TreatiseOnAlchemy ), + typeof( VirtueBook ) + }; + + public static Type[] LibraryBookTypes{ get{ return m_LibraryBookTypes; } } + + #endregion + + #region Accessors + + public static BaseWand RandomWand() + { + if (Core.ML) + return Construct(m_NewWandTypes) as BaseWand; + else if (Core.AOS) + return Construct(m_WandTypes, m_NewWandTypes) as BaseWand; + else + return Construct(m_OldWandTypes, m_WandTypes, m_NewWandTypes) as BaseWand; + } + + public static BaseClothing RandomClothing() + { + return RandomClothing(false, false); + } + + public static BaseClothing RandomClothing(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLClothingTypes, m_AosClothingTypes, m_ClothingTypes) as BaseClothing; + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEClothingTypes, m_AosClothingTypes, m_ClothingTypes) as BaseClothing; + + if (Core.AOS) + return Construct(m_AosClothingTypes, m_ClothingTypes) as BaseClothing; + + return Construct(m_ClothingTypes) as BaseClothing; + } + + public static BaseWeapon RandomRangedWeapon() + { + return RandomRangedWeapon(false, false); + } + + public static BaseWeapon RandomRangedWeapon(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLRangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes) as BaseWeapon; + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SERangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes) as BaseWeapon; + + if (Core.AOS) + return Construct(m_AosRangedWeaponTypes, m_RangedWeaponTypes) as BaseWeapon; + + return Construct(m_RangedWeaponTypes) as BaseWeapon; + } + + public static BaseWeapon RandomWeapon() + { + return RandomWeapon(false, false); + } + + public static BaseWeapon RandomWeapon(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes) as BaseWeapon; + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes) as BaseWeapon; + + if (Core.AOS) + return Construct(m_AosWeaponTypes, m_WeaponTypes) as BaseWeapon; + + return Construct(m_WeaponTypes) as BaseWeapon; + } + + public static Item RandomWeaponOrJewelry() + { + return RandomWeaponOrJewelry(false, false); + } + + public static Item RandomWeaponOrJewelry(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_JewelryTypes); + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_JewelryTypes); + + if (Core.AOS) + return Construct(m_AosWeaponTypes, m_WeaponTypes, m_JewelryTypes); + + return Construct(m_WeaponTypes, m_JewelryTypes); + } + + public static BaseJewel RandomJewelry() + { + return Construct(m_JewelryTypes) as BaseJewel; + } + + public static BaseArmor RandomArmor() + { + return RandomArmor(false, false); + } + + public static BaseArmor RandomArmor(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLArmorTypes, m_ArmorTypes) as BaseArmor; + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEArmorTypes, m_ArmorTypes) as BaseArmor; + + return Construct(m_ArmorTypes) as BaseArmor; + } + + public static BaseHat RandomHat() + { + return RandomHat(false); + } + + public static BaseHat RandomHat(bool inTokuno) + { + if (Core.SE && inTokuno) + return Construct(m_SEHatTypes, m_AosHatTypes, m_HatTypes) as BaseHat; + + if (Core.AOS) + return Construct(m_AosHatTypes, m_HatTypes) as BaseHat; + + return Construct(m_HatTypes) as BaseHat; + } + + public static Item RandomArmorOrHat() + { + return RandomArmorOrHat(false, false); + } + + public static Item RandomArmorOrHat(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes); + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes); + + if (Core.AOS) + return Construct(m_ArmorTypes, m_AosHatTypes, m_HatTypes); + + return Construct(m_ArmorTypes, m_HatTypes); + } + + public static BaseShield RandomShield() + { + if (Core.AOS) + return Construct(m_AosShieldTypes, m_ShieldTypes) as BaseShield; + + return Construct(m_ShieldTypes) as BaseShield; + } + + public static BaseArmor RandomArmorOrShield() + { + return RandomArmorOrShield(false, false); + } + + public static BaseArmor RandomArmorOrShield(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLArmorTypes, m_ArmorTypes, m_AosShieldTypes, m_ShieldTypes) as BaseArmor; + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEArmorTypes, m_ArmorTypes, m_AosShieldTypes, m_ShieldTypes) as BaseArmor; + + if (Core.AOS) + return Construct(m_ArmorTypes, m_AosShieldTypes, m_ShieldTypes) as BaseArmor; + + return Construct(m_ArmorTypes, m_ShieldTypes) as BaseArmor; + } + + public static Item RandomArmorOrShieldOrJewelry() + { + return RandomArmorOrShieldOrJewelry(false, false); + } + + public static Item RandomArmorOrShieldOrJewelry(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes); + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes); + + if (Core.AOS) + return Construct(m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes); + + return Construct(m_ArmorTypes, m_HatTypes, m_ShieldTypes, m_JewelryTypes); + } + + public static Item RandomArmorOrShieldOrWeapon() + { + return RandomArmorOrShieldOrWeapon(false, false); + } + + public static Item RandomArmorOrShieldOrWeapon(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_MLRangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes); + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_SERangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes); + + if (Core.AOS) + return Construct(m_AosWeaponTypes, m_WeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes); + + return Construct(m_WeaponTypes, m_RangedWeaponTypes, m_ArmorTypes, m_HatTypes, m_ShieldTypes); + } + + public static Item RandomArmorOrShieldOrWeaponOrJewelry() + { + return RandomArmorOrShieldOrWeaponOrJewelry(false, false); + } + + public static Item RandomArmorOrShieldOrWeaponOrJewelry(bool inTokuno, bool isMondain) + { + #region Mondain's Legacy + if (Core.ML && isMondain) + return Construct(m_MLWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_MLRangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_MLArmorTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes); + #endregion + + if (Core.SE && inTokuno) + return Construct(m_SEWeaponTypes, m_AosWeaponTypes, m_WeaponTypes, m_SERangedWeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_SEArmorTypes, m_ArmorTypes, m_SEHatTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes); + + if (Core.AOS) + return Construct(m_AosWeaponTypes, m_WeaponTypes, m_AosRangedWeaponTypes, m_RangedWeaponTypes, m_ArmorTypes, m_AosHatTypes, m_HatTypes, m_AosShieldTypes, m_ShieldTypes, m_JewelryTypes); + + return Construct(m_WeaponTypes, m_RangedWeaponTypes, m_ArmorTypes, m_HatTypes, m_ShieldTypes, m_JewelryTypes); + } + + #region Chest of Heirlooms + public static Item ChestOfHeirloomsContains() + { + return Construct( m_SEArmorTypes, m_SEHatTypes, m_SEWeaponTypes, m_SERangedWeaponTypes, m_JewelryTypes ); + } + #endregion + + public static Item RandomGem() + { + return Construct( m_GemTypes ); + } + + public static Item RandomReagent() + { + return Construct( m_RegTypes ); + } + + public static Item RandomNecromancyReagent() + { + return Construct( m_NecroRegTypes ); + } + + public static Item RandomPossibleReagent() + { + if ( Core.AOS ) + return Construct( m_RegTypes, m_NecroRegTypes ); + + return Construct( m_RegTypes ); + } + + public static Item RandomPotion() + { + return Construct( m_PotionTypes ); + } + + public static BaseInstrument RandomInstrument() + { + if ( Core.SE ) + return Construct( m_InstrumentTypes, m_SEInstrumentTypes ) as BaseInstrument; + + return Construct( m_InstrumentTypes ) as BaseInstrument; + } + + public static Item RandomStatue() + { + return Construct( m_StatueTypes ); + } + + public static SpellScroll RandomScroll( int minIndex, int maxIndex, SpellbookType type ) + { + Type[] types; + + switch ( type ) + { + default: + case SpellbookType.Regular: types = m_RegularScrollTypes; break; + case SpellbookType.Necromancer: types = (Core.SE ? m_SENecromancyScrollTypes : m_NecromancyScrollTypes ); break; + case SpellbookType.Paladin: types = m_PaladinScrollTypes; break; + case SpellbookType.Arcanist: types = m_ArcanistScrollTypes; break; + } + + return Construct( types, Utility.RandomMinMax( minIndex, maxIndex ) ) as SpellScroll; + } + + public static BaseBook RandomGrimmochJournal() + { + return Construct( m_GrimmochJournalTypes ) as BaseBook; + } + + public static BaseBook RandomLysanderNotebook() + { + return Construct( m_LysanderNotebookTypes ) as BaseBook; + } + + public static BaseBook RandomTavarasJournal() + { + return Construct( m_TavarasJournalTypes ) as BaseBook; + } + + public static BaseBook RandomLibraryBook() + { + return Construct( m_LibraryBookTypes ) as BaseBook; + } + public static BaseTalisman RandomTalisman() + { + BaseTalisman talisman = new BaseTalisman(BaseTalisman.GetRandomItemID()); + + talisman.Summoner = BaseTalisman.GetRandomSummoner(); + + if (talisman.Summoner.IsEmpty) + { + talisman.Removal = BaseTalisman.GetRandomRemoval(); + + if (talisman.Removal != TalismanRemoval.None) + { + talisman.MaxCharges = BaseTalisman.GetRandomCharges(); + talisman.MaxChargeTime = 1200; + } + } + else + { + talisman.MaxCharges = Utility.RandomMinMax(10, 50); + + if (talisman.Summoner.IsItem) + talisman.MaxChargeTime = 60; + else + talisman.MaxChargeTime = 1800; + } + + talisman.Blessed = BaseTalisman.GetRandomBlessed(); + talisman.Slayer = BaseTalisman.GetRandomSlayer(); + talisman.Protection = BaseTalisman.GetRandomProtection(); + talisman.Killer = BaseTalisman.GetRandomKiller(); + talisman.Skill = BaseTalisman.GetRandomSkill(); + talisman.ExceptionalBonus = BaseTalisman.GetRandomExceptional(); + talisman.SuccessBonus = BaseTalisman.GetRandomSuccessful(); + talisman.Charges = talisman.MaxCharges; + + return talisman; + } + + #endregion + + #region Construction methods + public static Item Construct( Type type ) + { + try + { + return Activator.CreateInstance( type ) as Item; + } + catch + { + return null; + } + } + + public static Item Construct( Type[] types ) + { + if ( types.Length > 0 ) + return Construct( types, Utility.Random( types.Length ) ); + + return null; + } + + public static Item Construct( Type[] types, int index ) + { + if ( index >= 0 && index < types.Length ) + return Construct( types[index] ); + + return null; + } + + public static Item Construct( params Type[][] types ) + { + int totalLength = 0; + + for ( int i = 0; i < types.Length; ++i ) + totalLength += types[i].Length; + + if ( totalLength > 0 ) + { + int index = Utility.Random( totalLength ); + + for ( int i = 0; i < types.Length; ++i ) + { + if ( index >= 0 && index < types[i].Length ) + return Construct( types[i][index] ); + + index -= types[i].Length; + } + } + return null; + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Misc/LootPack.cs b/Scripts/Misc/LootPack.cs new file mode 100644 index 0000000..ea0e503 --- /dev/null +++ b/Scripts/Misc/LootPack.cs @@ -0,0 +1,1057 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; + + +namespace Server +{ + public class LootPack + { + public static int GetLuckChance(Mobile killer, Mobile victim) + { + if (!Core.AOS) + return 0; + + int luck = killer.Luck; + + PlayerMobile pmKiller = killer as PlayerMobile; + if (pmKiller != null && pmKiller.SentHonorContext != null && pmKiller.SentHonorContext.Target == victim) + luck += pmKiller.SentHonorContext.PerfectionLuckBonus; + + if (luck < 0) + return 0; + + if (!Core.SE && luck > 1200) + luck = 1200; + + return (int)(Math.Pow(luck, 1 / 1.8) * 100); + } + + public static int GetLuckChanceForKiller(Mobile dead) + { + List list = BaseCreature.GetLootingRights(dead.DamageEntries, dead.HitsMax); + + DamageStore highest = null; + + for (int i = 0; i < list.Count; ++i) + { + DamageStore ds = list[i]; + + if (ds.m_HasRight && (highest == null || ds.m_Damage > highest.m_Damage)) + highest = ds; + } + + if (highest == null) + return 0; + + return GetLuckChance(highest.m_Mobile, dead); + } + + public static bool CheckLuck(int chance) + { + return (chance > Utility.Random(10000)); + } + + private LootPackEntry[] m_Entries; + + public LootPack(LootPackEntry[] entries) + { + m_Entries = entries; + } + + public void Generate(Mobile from, Container cont, bool spawning, int luckChance) + { + if (cont == null) + return; + + bool checkLuck = Core.AOS; + + for (int i = 0; i < m_Entries.Length; ++i) + { + LootPackEntry entry = m_Entries[i]; + + bool shouldAdd = (entry.Chance > Utility.Random(10000)); + + if (!shouldAdd && checkLuck) + { + checkLuck = false; + + if (LootPack.CheckLuck(luckChance)) + shouldAdd = (entry.Chance > Utility.Random(10000)); + } + + if (!shouldAdd) + continue; + + Item item = entry.Construct(from, luckChance, spawning); + + // Plume begin check Identification + if (item is BaseWeapon || item is BaseArmor || item is BaseClothing || item is BaseJewel) + { + + bool IsID = true; + + int bonusProps = entry.GetBonusProperties(); + double min = (double)entry.MinIntensity; + double max = (double)entry.MaxIntensity; + + if (bonusProps < entry.MaxProps && LootPack.CheckLuck(luckChance)) + ++bonusProps; + + int props = 1 + bonusProps; + + double dblID = (((min / max) + (min / 5.0) + (max / 10.0)) * (props + props / 10.0)) / 100.0; + + if (props >= 5 && Utility.Random(0, 100) > 1) + IsID = false; + else if (dblID > Utility.RandomDouble()) + IsID = false; + + if (!IsID) + { + if (item is BaseWeapon) + ((BaseWeapon)item).Identified = false; + else if (item is BaseArmor) + ((BaseArmor)item).Identified = false; + else if (item is BaseClothing) + ((BaseClothing)item).Identified = false; + else if (item is BaseJewel) + ((BaseJewel)item).Identified = false; + } + } + // End + if (item != null) + { + if (!item.Stackable || !cont.TryDropItem(from, item, false)) + cont.DropItem(item); + } + } + } + + public static readonly LootPackItem[] Gold = new LootPackItem[] + { + new LootPackItem( typeof( Gold ), 1 ) + }; + + public static readonly LootPackItem[] Instruments = new LootPackItem[] + { + new LootPackItem( typeof( BaseInstrument ), 1 ) + }; + + + public static readonly LootPackItem[] LowScrollItems = new LootPackItem[] + { + new LootPackItem( typeof( ClumsyScroll ), 1 ) + }; + + public static readonly LootPackItem[] MedScrollItems = new LootPackItem[] + { + new LootPackItem( typeof( ArchCureScroll ), 1 ) + }; + + public static readonly LootPackItem[] HighScrollItems = new LootPackItem[] + { + new LootPackItem( typeof( SummonAirElementalScroll ), 1 ) + }; + + public static readonly LootPackItem[] GemItems = new LootPackItem[] + { + new LootPackItem( typeof( Amber ), 1 ) + }; + + public static readonly LootPackItem[] PotionItems = new LootPackItem[] + { + new LootPackItem( typeof( AgilityPotion ), 1 ), + new LootPackItem( typeof( StrengthPotion ), 1 ), + new LootPackItem( typeof( RefreshPotion ), 1 ), + new LootPackItem( typeof( LesserCurePotion ), 1 ), + new LootPackItem( typeof( LesserHealPotion ), 1 ), + new LootPackItem( typeof( LesserPoisonPotion ), 1 ) + }; + + #region Old Magic Items + public static readonly LootPackItem[] OldMagicItems = new LootPackItem[] + { + new LootPackItem( typeof( BaseJewel ), 1 ), + new LootPackItem( typeof( BaseArmor ), 4 ), + new LootPackItem( typeof( BaseWeapon ), 3 ), + new LootPackItem( typeof( BaseRanged ), 1 ), + new LootPackItem( typeof( BaseShield ), 1 ) + }; + #endregion + + #region AOS Magic Items + public static readonly LootPackItem[] AosMagicItemsPoor = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 3 ), + new LootPackItem( typeof( BaseRanged ), 1 ), + new LootPackItem( typeof( BaseArmor ), 4 ), + new LootPackItem( typeof( BaseShield ), 1 ), + new LootPackItem( typeof( BaseJewel ), 2 ) + }; + + public static readonly LootPackItem[] AosMagicItemsMeagerType1 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 56 ), + new LootPackItem( typeof( BaseRanged ), 14 ), + new LootPackItem( typeof( BaseArmor ), 81 ), + new LootPackItem( typeof( BaseShield ), 11 ), + new LootPackItem( typeof( BaseJewel ), 42 ) + }; + + public static readonly LootPackItem[] AosMagicItemsMeagerType2 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 28 ), + new LootPackItem( typeof( BaseRanged ), 7 ), + new LootPackItem( typeof( BaseArmor ), 40 ), + new LootPackItem( typeof( BaseShield ), 5 ), + new LootPackItem( typeof( BaseJewel ), 21 ) + }; + + public static readonly LootPackItem[] AosMagicItemsAverageType1 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 90 ), + new LootPackItem( typeof( BaseRanged ), 23 ), + new LootPackItem( typeof( BaseArmor ), 130 ), + new LootPackItem( typeof( BaseShield ), 17 ), + new LootPackItem( typeof( BaseJewel ), 68 ) + }; + + public static readonly LootPackItem[] AosMagicItemsAverageType2 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 54 ), + new LootPackItem( typeof( BaseRanged ), 13 ), + new LootPackItem( typeof( BaseArmor ), 77 ), + new LootPackItem( typeof( BaseShield ), 10 ), + new LootPackItem( typeof( BaseJewel ), 40 ) + }; + + public static readonly LootPackItem[] AosMagicItemsRichType1 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 211 ), + new LootPackItem( typeof( BaseRanged ), 53 ), + new LootPackItem( typeof( BaseArmor ), 303 ), + new LootPackItem( typeof( BaseShield ), 39 ), + new LootPackItem( typeof( BaseJewel ), 158 ) + }; + + public static readonly LootPackItem[] AosMagicItemsRichType2 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 170 ), + new LootPackItem( typeof( BaseRanged ), 43 ), + new LootPackItem( typeof( BaseArmor ), 245 ), + new LootPackItem( typeof( BaseShield ), 32 ), + new LootPackItem( typeof( BaseJewel ), 128 ) + }; + + public static readonly LootPackItem[] AosMagicItemsFilthyRichType1 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 219 ), + new LootPackItem( typeof( BaseRanged ), 55 ), + new LootPackItem( typeof( BaseArmor ), 315 ), + new LootPackItem( typeof( BaseShield ), 41 ), + new LootPackItem( typeof( BaseJewel ), 164 ) + }; + + public static readonly LootPackItem[] AosMagicItemsFilthyRichType2 = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 239 ), + new LootPackItem( typeof( BaseRanged ), 60 ), + new LootPackItem( typeof( BaseArmor ), 343 ), + new LootPackItem( typeof( BaseShield ), 90 ), + new LootPackItem( typeof( BaseJewel ), 45 ) + }; + + public static readonly LootPackItem[] AosMagicItemsUltraRich = new LootPackItem[] + { + new LootPackItem( typeof( BaseWeapon ), 276 ), + new LootPackItem( typeof( BaseRanged ), 69 ), + new LootPackItem( typeof( BaseArmor ), 397 ), + new LootPackItem( typeof( BaseShield ), 52 ), + new LootPackItem( typeof( BaseJewel ), 207 ) + }; + #endregion + + #region ML definitions + public static readonly LootPack MlRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "2d50+225" ), + new LootPackEntry( true, AosMagicItemsRichType1, 50.00, 1, 3, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType1, 30.00, 1, 5, 0, 100 ), + /* new LootPackEntry( true, Gold, 100.00, "4d50+450" ), + new LootPackEntry( false, AosMagicItemsRichType1, 100.00, 1, 3, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType1, 80.00, 1, 3, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType1, 60.00, 1, 5, 0, 100 ),*/ + new LootPackEntry( false, Instruments, 1.00, 1 ) + }); + #endregion + + #region SE definitions + public static readonly LootPack SePoor = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "1d10+10" ), + new LootPackEntry( true, AosMagicItemsPoor, 0.50, 1, 5, 0, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "2d10+20" ), + new LootPackEntry( false, AosMagicItemsPoor, 1.00, 1, 5, 0, 100 ),*/ + new LootPackEntry( false, Instruments, 0.02, 1 ) + }); + + public static readonly LootPack SeMeager = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "2d10+20" ), + new LootPackEntry( true, AosMagicItemsMeagerType1, 10.20, 1, 2, 0, 50 ), + new LootPackEntry( false, AosMagicItemsMeagerType2, 5.6, 1, 5, 0, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "4d10+40" ), + new LootPackEntry( false, AosMagicItemsMeagerType1, 20.40, 1, 2, 0, 50 ), + new LootPackEntry( false, AosMagicItemsMeagerType2, 10.20, 1, 5, 0, 100 ),*/ + new LootPackEntry( false, Instruments, 0.10, 1 ) + }); + + public static readonly LootPack SeAverage = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "4d10+50" ), + new LootPackEntry( true, AosMagicItemsAverageType1, 9.75, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsAverageType2, 9.75, 1, 5, 0, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "8d10+100" ), + new LootPackEntry( false, AosMagicItemsAverageType1, 32.80, 1, 3, 0, 50 ), + new LootPackEntry( false, AosMagicItemsAverageType1, 32.80, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsAverageType2, 19.50, 1, 5, 0, 100 ),*/ + new LootPackEntry( false, Instruments, 0.40, 1 ) + }); + + public static readonly LootPack SeRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "8d10+112" ), + new LootPackEntry( true, AosMagicItemsRichType1, 38.15, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType2, 30.85, 1, 5, 0, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "15d10+225" ), + new LootPackEntry( false, AosMagicItemsRichType1, 76.30, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType1, 76.30, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType2, 61.70, 1, 5, 0, 100 ),*/ + new LootPackEntry( false, Instruments, 1.00, 1 ) + }); + + public static readonly LootPack SeFilthyRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "2d100+150" ), + new LootPackEntry( true, AosMagicItemsFilthyRichType1, 39.75, 1, 5, 0, 100 ), + new LootPackEntry( false, AosMagicItemsFilthyRichType2, 38.8, 1, 5, 25, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "3d100+400" ), + new LootPackEntry( false, AosMagicItemsFilthyRichType1, 79.50, 1, 5, 0, 100 ), + new LootPackEntry( false, AosMagicItemsFilthyRichType1, 79.50, 1, 5, 0, 100 ), + new LootPackEntry( false, AosMagicItemsFilthyRichType2, 77.60, 1, 5, 25, 100 ),*/ + new LootPackEntry( false, Instruments, 2.00, 1 ) + }); + + public static readonly LootPack SeUltraRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "3d100+300" ), + new LootPackEntry( true, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 33, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "6d100+600" ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100 ),*/ + new LootPackEntry( false, Instruments, 2.00, 1 ) + }); + + public static readonly LootPack SeSuperBoss = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "5d100+400" ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 50, 100 ), + /*new LootPackEntry( true, Gold, 100.00, "10d100+800" ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 100.00, 1, 5, 50, 100 ),*/ + new LootPackEntry( false, Instruments, 2.00, 1 ) + }); + #endregion + + #region AOS definitions + public static readonly LootPack AosPoor = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "1d10+10" ), + new LootPackEntry( false, AosMagicItemsPoor, 0.50, 1, 5, 0, 100 ), + new LootPackEntry( false, Instruments, 0.02, 1 ) + }); + + public static readonly LootPack AosMeager = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "2d10+20" ), + new LootPackEntry( true, AosMagicItemsMeagerType1, 10.20, 1, 2, 0, 50 ), + new LootPackEntry( false, AosMagicItemsMeagerType2, 5.6, 1, 5, 0, 100 ), + new LootPackEntry( false, Instruments, 0.10, 1 ) + }); + + public static readonly LootPack AosAverage = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "4d10+50" ), + new LootPackEntry( true, AosMagicItemsAverageType1, 16.40, 1, 3, 0, 50 ), + new LootPackEntry( false, AosMagicItemsAverageType1, 9.75, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsAverageType2, 9.75, 1, 5, 0, 100 ), + new LootPackEntry( false, Instruments, 0.40, 1 ) + }); + + public static readonly LootPack AosRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "8d10+112" ), + new LootPackEntry( false, AosMagicItemsRichType1, 38.15, 1, 4, 0, 75 ), + new LootPackEntry( false, AosMagicItemsRichType2, 30.85, 1, 5, 0, 100 ), + new LootPackEntry( false, Instruments, 1.00, 1 ) + }); + + public static readonly LootPack AosFilthyRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "2d100+150" ), + new LootPackEntry( false, AosMagicItemsFilthyRichType1, 39.75, 1, 5, 0, 100 ), + new LootPackEntry( false, AosMagicItemsFilthyRichType2, 38.8, 1, 5, 25, 100 ), + new LootPackEntry( false, Instruments, 2.00, 1 ) + }); + + public static readonly LootPack AosUltraRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "3d100+300" ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 33, 100 ), + new LootPackEntry( false, Instruments, 2.00, 1 ) + }); + + public static readonly LootPack AosSuperBoss = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 70.00, "5d100+400" ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 25, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 33, 100 ), + new LootPackEntry( false, AosMagicItemsUltraRich, 50.00, 1, 5, 50, 100 ), + new LootPackEntry( false, Instruments, 2.00, 1 ) + }); + #endregion + + #region Pre-AOS definitions + public static readonly LootPack OldPoor = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "1d25" ), + new LootPackEntry( false, Instruments, 0.02, 1 ) + }); + + public static readonly LootPack OldMeager = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "5d10+25" ), + new LootPackEntry( false, Instruments, 0.10, 1 ), + new LootPackEntry( false, OldMagicItems, 1.00, 1, 1, 0, 60 ), + new LootPackEntry( false, OldMagicItems, 0.20, 1, 1, 10, 70 ) + }); + + public static readonly LootPack OldAverage = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "10d10+50" ), + new LootPackEntry( false, Instruments, 0.40, 1 ), + new LootPackEntry( false, OldMagicItems, 5.00, 1, 1, 20, 80 ), + new LootPackEntry( false, OldMagicItems, 2.00, 1, 1, 30, 90 ), + new LootPackEntry( false, OldMagicItems, 0.50, 1, 1, 40, 100 ) + }); + + public static readonly LootPack OldRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "10d10+250" ), + new LootPackEntry( false, Instruments, 1.00, 1 ), + new LootPackEntry( false, OldMagicItems, 20.00, 1, 1, 60, 100 ), + new LootPackEntry( false, OldMagicItems, 10.00, 1, 1, 65, 100 ), + new LootPackEntry( false, OldMagicItems, 1.00, 1, 1, 70, 100 ) + }); + + public static readonly LootPack OldFilthyRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "2d125+400" ), + new LootPackEntry( false, Instruments, 2.00, 1 ), + new LootPackEntry( false, OldMagicItems, 33.00, 1, 1, 50, 100 ), + new LootPackEntry( false, OldMagicItems, 33.00, 1, 1, 60, 100 ), + new LootPackEntry( false, OldMagicItems, 20.00, 1, 1, 70, 100 ), + new LootPackEntry( false, OldMagicItems, 5.00, 1, 1, 80, 100 ) + }); + + public static readonly LootPack OldUltraRich = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "5d100+500" ), + new LootPackEntry( false, Instruments, 2.00, 1 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 40, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 40, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 50, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 50, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 60, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 60, 100 ) + }); + + public static readonly LootPack OldSuperBoss = new LootPack(new LootPackEntry[] + { + new LootPackEntry( true, Gold, 100.00, "5d100+500" ), + new LootPackEntry( false, Instruments, 2.00, 1 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 40, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 40, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 40, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 50, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 50, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 50, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 60, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 60, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 60, 100 ), + new LootPackEntry( false, OldMagicItems, 100.00, 1, 1, 70, 100 ) + }); + #endregion + + #region Generic accessors + public static LootPack Poor { get { return Core.SE ? SePoor : Core.AOS ? AosPoor : OldPoor; } } + public static LootPack Meager { get { return Core.SE ? SeMeager : Core.AOS ? AosMeager : OldMeager; } } + public static LootPack Average { get { return Core.SE ? SeAverage : Core.AOS ? AosAverage : OldAverage; } } + public static LootPack Rich { get { return Core.SE ? SeRich : Core.AOS ? AosRich : OldRich; } } + public static LootPack FilthyRich { get { return Core.SE ? SeFilthyRich : Core.AOS ? AosFilthyRich : OldFilthyRich; } } + public static LootPack UltraRich { get { return Core.SE ? SeUltraRich : Core.AOS ? AosUltraRich : OldUltraRich; } } + public static LootPack SuperBoss { get { return Core.SE ? SeSuperBoss : Core.AOS ? AosSuperBoss : OldSuperBoss; } } + #endregion + + public static readonly LootPack LowScrolls = new LootPack(new LootPackEntry[] + { + new LootPackEntry( false, LowScrollItems, 50.00, 1 ) + //new LootPackEntry( false, LowScrollItems, 100.00, 1 ) + }); + + public static readonly LootPack MedScrolls = new LootPack(new LootPackEntry[] + { + new LootPackEntry( false, MedScrollItems, 40.00, 1 ) + //new LootPackEntry( false, MedScrollItems, 100.00, 1 ) + }); + + public static readonly LootPack HighScrolls = new LootPack(new LootPackEntry[] + { + new LootPackEntry( false, HighScrollItems, 30.00, 1 ) + //new LootPackEntry( false, HighScrollItems, 100.00, 1 ) + }); + + public static readonly LootPack Gems = new LootPack(new LootPackEntry[] + { + new LootPackEntry( false, GemItems, 100.00, 1 ) + }); + + public static readonly LootPack Potions = new LootPack(new LootPackEntry[] + { + new LootPackEntry( false, PotionItems, 100.00, 1 ) + }); + + /* + // TODO: Uncomment once added + #region Mondain's Legacy + public static readonly LootPackItem[] ParrotItem = new LootPackItem[] + { + new LootPackItem( typeof( ParrotItem ), 1 ) + }; + + public static readonly LootPack Parrot = new LootPack( new LootPackEntry[] + { + new LootPackEntry( false, ParrotItem, 10.00, 1 ) + } ); + #endregion + */ + } + + public class LootPackEntry + { + private int m_Chance; + private LootPackDice m_Quantity; + + private int m_MaxProps, m_MinIntensity, m_MaxIntensity; + + private bool m_AtSpawnTime; + + private LootPackItem[] m_Items; + + public int Chance + { + get { return m_Chance; } + set { m_Chance = value; } + } + + public LootPackDice Quantity + { + get { return m_Quantity; } + set { m_Quantity = value; } + } + + public int MaxProps + { + get { return m_MaxProps; } + set { m_MaxProps = value; } + } + + public int MinIntensity + { + get { return m_MinIntensity; } + set { m_MinIntensity = value; } + } + + public int MaxIntensity + { + get { return m_MaxIntensity; } + set { m_MaxIntensity = value; } + } + + public LootPackItem[] Items + { + get { return m_Items; } + set { m_Items = value; } + } + + private static bool IsInTokuno(Mobile m) + { + if (m.Region.IsPartOf("Fan Dancer's Dojo")) + return true; + + if (m.Region.IsPartOf("Yomotsu Mines")) + return true; + + return (m.Map == Map.Tokuno); + } + + #region Mondain's Legacy + private static bool IsMondain(Mobile m) + { + return MondainsLegacy.IsMLRegion(m.Region); + } + #endregion + + public Item Construct(Mobile from, int luckChance, bool spawning) + { + if (m_AtSpawnTime != spawning) + return null; + + int totalChance = 0; + + for (int i = 0; i < m_Items.Length; ++i) + totalChance += m_Items[i].Chance; + + int rnd = Utility.Random(totalChance); + + for (int i = 0; i < m_Items.Length; ++i) + { + LootPackItem item = m_Items[i]; + + if (rnd < item.Chance) + return Mutate(from, luckChance, item.Construct(IsInTokuno(from), IsMondain(from))); + + rnd -= item.Chance; + } + + return null; + } + + private int GetRandomOldBonus() + { + int rnd = Utility.RandomMinMax(m_MinIntensity, m_MaxIntensity); + + if (50 > rnd) + return 1; + else + rnd -= 50; + + if (25 > rnd) + return 2; + else + rnd -= 25; + + if (14 > rnd) + return 3; + else + rnd -= 14; + + if (8 > rnd) + return 4; + + return 5; + } + + public Item Mutate(Mobile from, int luckChance, Item item) + { + if (item != null) + { + if (item is BaseWeapon && 1 > Utility.Random(100)) + { + item.Delete(); + item = new FireHorn(); + return item; + } + + if (item is BaseWeapon || item is BaseArmor || item is BaseJewel || item is BaseHat) + { + if (Core.AOS) + { + int bonusProps = GetBonusProperties(); + int min = m_MinIntensity; + int max = m_MaxIntensity; + + if (bonusProps < m_MaxProps && LootPack.CheckLuck(luckChance)) + ++bonusProps; + + int props = 1 + bonusProps; + + // Make sure we're not spawning items with 6 properties. + if (props > m_MaxProps) + props = m_MaxProps; + + if (item is BaseWeapon) + BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, false, luckChance, props, m_MinIntensity, m_MaxIntensity); + else if (item is BaseArmor) + BaseRunicTool.ApplyAttributesTo((BaseArmor)item, false, luckChance, props, m_MinIntensity, m_MaxIntensity); + else if (item is BaseJewel) + BaseRunicTool.ApplyAttributesTo((BaseJewel)item, false, luckChance, props, m_MinIntensity, m_MaxIntensity); + else if (item is BaseHat) + BaseRunicTool.ApplyAttributesTo((BaseHat)item, false, luckChance, props, m_MinIntensity, m_MaxIntensity); + } + else // not aos + { + if (item is BaseWeapon) + { + BaseWeapon weapon = (BaseWeapon)item; + + if (80 > Utility.Random(100)) + weapon.AccuracyLevel = (WeaponAccuracyLevel)GetRandomOldBonus(); + + if (60 > Utility.Random(100)) + weapon.DamageLevel = (WeaponDamageLevel)GetRandomOldBonus(); + + if (40 > Utility.Random(100)) + weapon.DurabilityLevel = (WeaponDurabilityLevel)GetRandomOldBonus(); + + if (5 > Utility.Random(100)) + weapon.Slayer = SlayerName.Silver; + + if (from != null && weapon.AccuracyLevel == 0 && weapon.DamageLevel == 0 && weapon.DurabilityLevel == 0 && weapon.Slayer == SlayerName.None && 5 > Utility.Random(100)) + weapon.Slayer = SlayerGroup.GetLootSlayerType(from.GetType()); + } + else if (item is BaseArmor) + { + BaseArmor armor = (BaseArmor)item; + + if (80 > Utility.Random(100)) + armor.ProtectionLevel = (ArmorProtectionLevel)GetRandomOldBonus(); + + if (40 > Utility.Random(100)) + armor.Durability = (ArmorDurabilityLevel)GetRandomOldBonus(); + } + } + } + else if (item is BaseInstrument) + { + SlayerName slayer = SlayerName.None; + + if (Core.AOS) + slayer = BaseRunicTool.GetRandomSlayer(); + else + slayer = SlayerGroup.GetLootSlayerType(from.GetType()); + + if (slayer == SlayerName.None) + { + item.Delete(); + return null; + } + + BaseInstrument instr = (BaseInstrument)item; + + instr.Quality = InstrumentQuality.Regular; + instr.Slayer = slayer; + } + + if (item.Stackable) + item.Amount = m_Quantity.Roll(); + } + + return item; + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, string quantity) + : this(atSpawnTime, items, chance, new LootPackDice(quantity), 0, 0, 0) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, int quantity) + : this(atSpawnTime, items, chance, new LootPackDice(0, 0, quantity), 0, 0, 0) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, string quantity, int maxProps, int minIntensity, int maxIntensity) + : this(atSpawnTime, items, chance, new LootPackDice(quantity), maxProps, minIntensity, maxIntensity) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, int quantity, int maxProps, int minIntensity, int maxIntensity) + : this(atSpawnTime, items, chance, new LootPackDice(0, 0, quantity), maxProps, minIntensity, maxIntensity) + { + } + + public LootPackEntry(bool atSpawnTime, LootPackItem[] items, double chance, LootPackDice quantity, int maxProps, int minIntensity, int maxIntensity) + { + m_AtSpawnTime = atSpawnTime; + m_Items = items; + m_Chance = (int)(100 * chance); + m_Quantity = quantity; + m_MaxProps = maxProps; + m_MinIntensity = minIntensity; + m_MaxIntensity = maxIntensity; + } + + public int GetBonusProperties() + { + int p0 = 0, p1 = 0, p2 = 0, p3 = 0, p4 = 0, p5 = 0; + + switch (m_MaxProps) + { + case 1: p0 = 3; p1 = 1; break; + case 2: p0 = 6; p1 = 3; p2 = 1; break; + case 3: p0 = 10; p1 = 6; p2 = 3; p3 = 1; break; + case 4: p0 = 16; p1 = 12; p2 = 6; p3 = 5; p4 = 1; break; + case 5: p0 = 30; p1 = 25; p2 = 20; p3 = 15; p4 = 9; p5 = 1; break; + } + + int pc = p0 + p1 + p2 + p3 + p4 + p5; + + int rnd = Utility.Random(pc); + + if (rnd < p5) + return 5; + else + rnd -= p5; + + if (rnd < p4) + return 4; + else + rnd -= p4; + + if (rnd < p3) + return 3; + else + rnd -= p3; + + if (rnd < p2) + return 2; + else + rnd -= p2; + + if (rnd < p1) + return 1; + + return 0; + } + } + + public class LootPackItem + { + private Type m_Type; + private int m_Chance; + + public Type Type + { + get { return m_Type; } + set { m_Type = value; } + } + + public int Chance + { + get { return m_Chance; } + set { m_Chance = value; } + } + + private static Type[] m_BlankTypes = new Type[] { typeof(BlankScroll) }; + private static Type[][] m_NecroTypes = new Type[][] + { + new Type[] // low + { + typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ) + /*typeof( AnimateDeadScroll ), typeof( BloodOathScroll ), typeof( CorpseSkinScroll ), typeof( CurseWeaponScroll ), + typeof( EvilOmenScroll ), typeof( HorrificBeastScroll ), typeof( MindRotScroll ), typeof( PainSpikeScroll ), + typeof( SummonFamiliarScroll ), typeof( WraithFormScroll )*/ + }, + new Type[] // med + { + typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ),typeof( BlankScroll ) + //typeof( LichFormScroll ), typeof( PoisonStrikeScroll ), typeof( StrangleScroll ), typeof( WitherScroll ) + }, + + ((Core.SE) ? + new Type[] // high + { + typeof( VengefulSpiritScroll ), typeof( VampiricEmbraceScroll ), typeof( ExorcismScroll ) + } : + new Type[] // high + { + typeof( VengefulSpiritScroll ), typeof( VampiricEmbraceScroll ) + }) + }; + + public static Item RandomScroll(int index, int minCircle, int maxCircle) + { + --minCircle; + --maxCircle; + + int scrollCount = ((maxCircle - minCircle) + 1) * 8; + + if (index == 0) + scrollCount += m_BlankTypes.Length; + + if (Core.AOS) + scrollCount += m_NecroTypes[index].Length; + + int rnd = Utility.Random(scrollCount); + + if (index == 0 && rnd < m_BlankTypes.Length) + return Loot.Construct(m_BlankTypes); + else if (index == 0) + rnd -= m_BlankTypes.Length; + + if (Core.AOS && rnd < m_NecroTypes.Length) + return Loot.Construct(m_NecroTypes[index]); + else if (Core.AOS) + rnd -= m_NecroTypes[index].Length; + + return Loot.RandomScroll(minCircle * 8, (maxCircle * 8) + 7, SpellbookType.Regular); + } + + public Item Construct(bool inTokuno, bool isMondain) + { + try + { + Item item; + + if (m_Type == typeof(BaseRanged)) + item = Loot.RandomRangedWeapon(inTokuno, isMondain); + else if (m_Type == typeof(BaseWeapon)) + item = Loot.RandomWeapon(inTokuno, isMondain); + else if (m_Type == typeof(BaseArmor)) + item = Loot.RandomArmorOrHat(inTokuno, isMondain); + else if (m_Type == typeof(BaseShield)) + item = Loot.RandomShield(); + else if (m_Type == typeof(BaseJewel)) + item = Core.AOS ? Loot.RandomJewelry() : Loot.RandomArmorOrShieldOrWeapon(); + else if (m_Type == typeof(BaseInstrument)) + item = Loot.RandomInstrument(); + else if (m_Type == typeof(Amber)) // gem + item = Loot.RandomGem(); + else if (m_Type == typeof(ClumsyScroll)) // low scroll + item = RandomScroll(0, 1, 3); + else if (m_Type == typeof(ArchCureScroll)) // med scroll + item = RandomScroll(1, 4, 7); + else if (m_Type == typeof(SummonAirElementalScroll)) // high scroll + item = RandomScroll(2, 8, 8); + else + item = Activator.CreateInstance(m_Type) as Item; + + return item; + } + catch + { + } + + return null; + } + + public LootPackItem(Type type, int chance) + { + m_Type = type; + m_Chance = chance; + } + } + + public class LootPackDice + { + private int m_Count, m_Sides, m_Bonus; + + public int Count + { + get { return m_Count; } + set { m_Count = value; } + } + + public int Sides + { + get { return m_Sides; } + set { m_Sides = value; } + } + + public int Bonus + { + get { return m_Bonus; } + set { m_Bonus = value; } + } + + public int Roll() + { + int v = m_Bonus; + + for (int i = 0; i < m_Count; ++i) + v += Utility.Random(1, m_Sides); + + return v; + } + + public LootPackDice(string str) + { + int start = 0; + int index = str.IndexOf('d', start); + + if (index < start) + return; + + m_Count = Utility.ToInt32(str.Substring(start, index - start)); + + bool negative; + + start = index + 1; + index = str.IndexOf('+', start); + + if (negative = (index < start)) + index = str.IndexOf('-', start); + + if (index < start) + index = str.Length; + + m_Sides = Utility.ToInt32(str.Substring(start, index - start)); + + if (index == str.Length) + return; + + start = index + 1; + index = str.Length; + + m_Bonus = Utility.ToInt32(str.Substring(start, index - start)); + + if (negative) + m_Bonus *= -1; + } + + public LootPackDice(int count, int sides, int bonus) + { + m_Count = count; + m_Sides = sides; + m_Bonus = bonus; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/MapDefinitions.cs b/Scripts/Misc/MapDefinitions.cs new file mode 100644 index 0000000..1d4434a --- /dev/null +++ b/Scripts/Misc/MapDefinitions.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Misc +{ + public class MapDefinitions + { + public static void Configure() + { + /* Here we configure all maps. Some notes: + * + * 1) The first 32 maps are reserved for core use. + * 2) Map 0x7F is reserved for core use. + * 3) Map 0xFF is reserved for core use. + * 4) Changing or removing any predefined maps may cause server instability. + */ + + RegisterMap( 0, 0, 0, 7168, 4096, 4, "Felucca", MapRules.FeluccaRules ); + RegisterMap(1, 1, 1, 7168, 4096, 0, "Trammel", MapRules.FeluccaRules ); // Scriptiz : on retire les r�gles de Trammel ! + RegisterMap( 2, 2, 2, 2304, 1600, 1, "Ilshenar", MapRules.FeluccaRules ); // Scriptiz : on retire les r�gles de Trammel ! + RegisterMap( 3, 3, 3, 2560, 2048, 1, "Malas", MapRules.FeluccaRules ); // Scriptiz : on retire les r�gles de Trammel ! + RegisterMap( 4, 4, 4, 1448, 1448, 1, "Tokuno", MapRules.FeluccaRules ); // Scriptiz : on retire les r�gles de Trammel ! + RegisterMap( 5, 5, 5, 1280, 4096, 1, "TerMur", MapRules.FeluccaRules ); // Scriptiz : on retire les r�gles de Trammel ! + + // Scriptiz : Ajout de 5 copies de Felucca + for (int i = 6; i <= 10; i++) + { + RegisterMap(i, 0, 0, 7168, 4096, 4, "Felucca" + (i - 4), MapRules.FeluccaRules); + } + + // Scriptiz : Ajout de 5 copies de Trammel + for (int i = 11; i <= 15; i++) + { + RegisterMap(i, 1, 1, 7168, 4096, 0, "Trammel" + (i - 9), MapRules.FeluccaRules); + } + + RegisterMap( 0x7F, 0x7F, 0x7F, Map.SectorSize, Map.SectorSize, 1, "Internal", MapRules.Internal ); + + /* Example of registering a custom map: + * RegisterMap( 32, 0, 0, 6144, 4096, 3, "Iceland", MapRules.FeluccaRules ); + * + * Defined: + * RegisterMap( , , , , , , , ); + * - : An unreserved unique index for this map + * - : An identification number used in client communications. For any visible maps, this value must be from 0-5 + * - : A file identification number. For any visible maps, this value must be from 0-5 + * - , : Size of the map (in tiles) + * - : Season of the map. 0 = Spring, 1 = Summer, 2 = Fall, 3 = Winter, 4 = Desolation + * - : Reference name for the map, used in props gump, get/set commands, region loading, etc + * - : Rules and restrictions associated with the map. See documentation for details + */ + + TileMatrixPatch.Enabled = false; // OSI Client Patch 6.0.0.0 + + MultiComponentList.PostHSFormat = true; // OSI Client Patch 7.0.9.0 + } + + public static void RegisterMap( int mapIndex, int mapID, int fileIndex, int width, int height, int season, string name, MapRules rules ) + { + Map newMap = new Map( mapID, mapIndex, fileIndex, width, height, season, name, rules ); + + Map.Maps[mapIndex] = newMap; + Map.AllMaps.Add( newMap ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/MapUO.cs b/Scripts/Misc/MapUO.cs new file mode 100644 index 0000000..bc6328c --- /dev/null +++ b/Scripts/Misc/MapUO.cs @@ -0,0 +1,133 @@ +using System; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Engines.PartySystem; +using Server.Guilds; + +namespace Server.Misc +{ + public static partial class MapUO + { + private static class Settings + { + public const bool PartyTrack = true; + public const bool GuildTrack = true; + public const bool GuildHitsPercent = true; + } + + public static void Initialize() + { + if (Settings.PartyTrack) + ProtocolExtensions.Register(0x00, true, new OnPacketReceive(OnPartyTrack)); + + if (Settings.GuildTrack) + ProtocolExtensions.Register(0x01, true, new OnPacketReceive(OnGuildTrack)); + } + + private static void OnPartyTrack(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + Party party = Party.Get(from); + + if (party != null) + { + Packets.PartyTrack packet = new Packets.PartyTrack(from, party); + + if (packet.UnderlyingStream.Length > 8) + state.Send(packet); + } + } + + private static void OnGuildTrack(NetState state, PacketReader pvSrc) + { + Mobile from = state.Mobile; + Guild guild = from.Guild as Guild; + + if (guild != null) + { + bool locations = pvSrc.ReadByte() != 0; + + Packets.GuildTrack packet = new Packets.GuildTrack(from, guild, locations); + + if (packet.UnderlyingStream.Length > (locations ? 9 : 5)) + state.Send(packet); + } + else + state.Send(new Packets.GuildTrack()); + } + + private static class Packets + { + public sealed class PartyTrack : ProtocolExtension + { + public PartyTrack(Mobile from, Party party) + : base(0x01, ((party.Members.Count - 1) * 9) + 4) + { + for (int i = 0; i < party.Members.Count; ++i) + { + PartyMemberInfo pmi = (PartyMemberInfo)party.Members[i]; + + if (pmi == null || pmi.Mobile == from) + continue; + + Mobile mob = pmi.Mobile; + + if (Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + continue; + + m_Stream.Write((int)mob.Serial); + m_Stream.Write((short)mob.X); + m_Stream.Write((short)mob.Y); + m_Stream.Write((byte)(mob.Map == null ? 0 : mob.Map.MapID)); + } + + m_Stream.Write((int)0); + } + } + + public sealed class GuildTrack : ProtocolExtension + { + public GuildTrack() + : base(0x02, 5) + { + m_Stream.Write((byte)0); + m_Stream.Write((int)0); + } + + public GuildTrack(Mobile from, Guild guild, bool locations) + : base(0x02, ((guild.Members.Count - 1) * (locations ? 10 : 4)) + 5) + { + m_Stream.Write((byte)(locations ? 1 : 0)); + + for (int i = 0; i < guild.Members.Count; ++i) + { + Mobile mob = guild.Members[i]; + + if (mob == null || mob == from || mob.NetState == null) + continue; + + if (locations && Utility.InUpdateRange(from, mob) && from.CanSee(mob)) + continue; + + m_Stream.Write((int)mob.Serial); + + if (locations) + { + m_Stream.Write((short)mob.X); + m_Stream.Write((short)mob.Y); + m_Stream.Write((byte)(mob.Map == null ? 0 : mob.Map.MapID)); + + if (Settings.GuildHitsPercent && mob.Alive) + m_Stream.Write((byte)(mob.Hits / Math.Max(mob.HitsMax, 1.0) * 100)); + else + m_Stream.Write((byte)0); + } + } + + m_Stream.Write((int)0); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/MondainsLegacy.cs b/Scripts/Misc/MondainsLegacy.cs new file mode 100644 index 0000000..fa643a7 --- /dev/null +++ b/Scripts/Misc/MondainsLegacy.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server +{ + public static class MondainsLegacy + { + public static Type[] Artifacts { get { return m_Artifacts; } } + + private static Type[] m_Artifacts = new Type[] + { + typeof( AegisOfGrace ), typeof( BladeDance ), typeof( BloodwoodSpirit ), typeof( Bonesmasher ), + typeof( Boomstick ), typeof( BrightsightLenses ), typeof( FeyLeggings ), typeof( FleshRipper ), + typeof( HelmOfSwiftness ), typeof( PadsOfTheCuSidhe ), typeof( QuiverOfRage ), typeof( QuiverOfElements ), + typeof( RaedsGlory ), typeof( RighteousAnger ), typeof( RobeOfTheEclipse ), typeof( RobeOfTheEquinox ), + typeof( SoulSeeker ), typeof( TalonBite ), typeof( TotemOfVoid ), typeof( WildfireBow ), + typeof( Windsong ) + }; + + public static bool CheckArtifactChance(Mobile m, BaseCreature bc) + { + if (!Core.ML) + return false; + + return Paragon.CheckArtifactChance(m, bc); + } + + public static void GiveArtifactTo(Mobile m) + { + Item item = Activator.CreateInstance(m_Artifacts[Utility.Random(m_Artifacts.Length)]) as Item; + + if (item == null) + return; + + if (m.AddToBackpack(item)) + { + m.SendLocalizedMessage(1072223); // An item has been placed in your backpack. + m.SendLocalizedMessage(1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + else if (m.BankBox.TryDropItem(m, item, false)) + { + m.SendLocalizedMessage(1072224); // An item has been placed in your bank box. + m.SendLocalizedMessage(1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + else + { + // Item was placed at feet by m.AddToBackpack + m.SendLocalizedMessage(1072523); // You find an artifact, but your backpack and bank are too full to hold it. + } + } + + public static bool CheckML( Mobile from ) + { + return CheckML( from, true ); + } + + public static bool CheckML( Mobile from, bool message ) + { + if ( from == null || from.NetState == null ) + return false; + + if ( from.NetState.SupportsExpansion( Expansion.ML ) ) + return true; + + if ( message ) + from.SendLocalizedMessage( 1072791 ); // You must upgrade to Mondain's Legacy in order to use that item. + + return false; + } + + public static bool IsMLRegion(Region region) + { + return region.IsPartOf("Twisted Weald") + || region.IsPartOf("Sanctuary") + || region.IsPartOf("The Prism of Light") + || region.IsPartOf("The Citadel") + || region.IsPartOf("Bedlam") + || region.IsPartOf("Blighted Grove") + || region.IsPartOf("The Painted Caves") + || region.IsPartOf("The Palace of Paroxysmus") + || region.IsPartOf("Labyrinth"); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/NameList.cs b/Scripts/Misc/NameList.cs new file mode 100644 index 0000000..bbf3273 --- /dev/null +++ b/Scripts/Misc/NameList.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Server; + +namespace Server +{ + public class NameList + { + private string m_Type; + private string[] m_List; + + public string Type{ get{ return m_Type; } } + public string[] List{ get{ return m_List; } } + + public bool ContainsName( string name ) + { + for ( int i = 0; i < m_List.Length; i++ ) + if ( name == m_List[i] ) + return true; + + return false; + } + + public NameList( string type, XmlElement xml ) + { + m_Type = type; + m_List = xml.InnerText.Split( ',' ); + + for ( int i = 0; i < m_List.Length; ++i ) + m_List[i] = Utility.Intern( m_List[i].Trim() ); + } + + public string GetRandomName() + { + if ( m_List.Length > 0 ) + return m_List[Utility.Random( m_List.Length )]; + + return ""; + } + + public static NameList GetNameList( string type ) + { + NameList n = null; + m_Table.TryGetValue( type, out n ); + return n; + } + + public static string RandomName( string type ) + { + NameList list = GetNameList( type ); + + if ( list != null ) + return list.GetRandomName(); + + return ""; + } + + private static Dictionary m_Table; + + static NameList() + { + m_Table = new Dictionary( StringComparer.OrdinalIgnoreCase ); + + string filePath = Path.Combine( Core.BaseDirectory, "Data/names.xml" ); + + if ( !File.Exists( filePath ) ) + return; + + try + { + Load( filePath ); + } + catch ( Exception e ) + { + Console.WriteLine( "Warning: Exception caught loading name lists:" ); + Console.WriteLine( e ); + } + } + + private static void Load( string filePath ) + { + XmlDocument doc = new XmlDocument(); + doc.Load( filePath ); + + XmlElement root = doc["names"]; + + foreach ( XmlElement element in root.GetElementsByTagName( "namelist" ) ) + { + string type = element.GetAttribute( "type" ); + + if ( String.IsNullOrEmpty( type ) ) + continue; + + try + { + NameList list = new NameList( type, element ); + + m_Table[type] = list; + } + catch + { + } + } + } + } +} diff --git a/Scripts/Misc/NameVerification.cs b/Scripts/Misc/NameVerification.cs new file mode 100644 index 0000000..abe66db --- /dev/null +++ b/Scripts/Misc/NameVerification.cs @@ -0,0 +1,207 @@ +using System; +using Server; +using Server.Commands; + +namespace Server.Misc +{ + public class NameVerification + { + public static readonly char[] SpaceDashPeriodQuote = new char[] + { + ' ', '-', '.', '\'' + }; + + public static readonly char[] Empty = new char[0]; + + public static void Initialize() + { + CommandSystem.Register( "ValidateName", AccessLevel.Administrator, new CommandEventHandler( ValidateName_OnCommand ) ); + } + + [Usage( "ValidateName" )] + [Description( "Checks the result of NameValidation on the specified name." )] + public static void ValidateName_OnCommand( CommandEventArgs e ) + { + if ( Validate( e.ArgString, 2, 16, true, false, true, 1, SpaceDashPeriodQuote ) ) + e.Mobile.SendMessage( 0x59, "That name is considered valid." ); + else + e.Mobile.SendMessage( 0x22, "That name is considered invalid." ); + } + + public static bool Validate( string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, bool noExceptionsAtStart, int maxExceptions, char[] exceptions ) + { + return Validate( name, minLength, maxLength, allowLetters, allowDigits, noExceptionsAtStart, maxExceptions, exceptions, m_Disallowed, m_StartDisallowed ); + } + + public static bool Validate( string name, int minLength, int maxLength, bool allowLetters, bool allowDigits, bool noExceptionsAtStart, int maxExceptions, char[] exceptions, string[] disallowed, string[] startDisallowed ) + { + if ( name == null || name.Length < minLength || name.Length > maxLength ) + return false; + + int exceptCount = 0; + + name = name.ToLower(); + + if ( !allowLetters || !allowDigits || (exceptions.Length > 0 && (noExceptionsAtStart || maxExceptions < int.MaxValue)) ) + { + for ( int i = 0; i < name.Length; ++i ) + { + char c = name[i]; + + if ( c >= 'a' && c <= 'z' ) + { + if ( !allowLetters ) + return false; + + exceptCount = 0; + } + else if ( c >= '0' && c <= '9' ) + { + if ( !allowDigits ) + return false; + + exceptCount = 0; + } + else + { + bool except = false; + + for ( int j = 0; !except && j < exceptions.Length; ++j ) + if ( c == exceptions[j] ) + except = true; + + if ( !except || (i == 0 && noExceptionsAtStart) ) + return false; + + if ( exceptCount++ == maxExceptions ) + return false; + } + } + } + + for ( int i = 0; i < disallowed.Length; ++i ) + { + int indexOf = name.IndexOf( disallowed[i] ); + + if ( indexOf == -1 ) + continue; + + bool badPrefix = ( indexOf == 0 ); + + for ( int j = 0; !badPrefix && j < exceptions.Length; ++j ) + badPrefix = ( name[indexOf - 1] == exceptions[j] ); + + if ( !badPrefix ) + continue; + + bool badSuffix = ( (indexOf + disallowed[i].Length) >= name.Length ); + + for ( int j = 0; !badSuffix && j < exceptions.Length; ++j ) + badSuffix = ( name[indexOf + disallowed[i].Length] == exceptions[j] ); + + if ( badSuffix ) + return false; + } + + for ( int i = 0; i < startDisallowed.Length; ++i ) + { + if ( name.StartsWith( startDisallowed[i] ) ) + return false; + } + + return true; + } + + public static string[] StartDisallowed { get { return m_StartDisallowed; } } + public static string[] Disallowed { get { return m_Disallowed; } } + + private static string[] m_StartDisallowed = new string[] + { + "seer", + "counselor", + "gm", + "admin", + "lady", + "lord" + }; + + private static string[] m_Disallowed = new string[] + { + "jigaboo", + "chigaboo", + "wop", + "kyke", + "kike", + "tit", + "spic", + "prick", + "piss", + "lezbo", + "lesbo", + "felatio", + "dyke", + "dildo", + "chinc", + "chink", + "cunnilingus", + "cum", + "cocksucker", + "cock", + "clitoris", + "clit", + "ass", + "hitler", + "penis", + "nigga", + "nigger", + "klit", + "kunt", + "jiz", + "jism", + "jerkoff", + "jackoff", + "goddamn", + "fag", + "blowjob", + "bitch", + "asshole", + "dick", + "pussy", + "snatch", + "cunt", + "twat", + "shit", + "fuck", + "tailor", + "smith", + "scholar", + "rogue", + "novice", + "neophyte", + "merchant", + "medium", + "master", + "mage", + "lb", + "journeyman", + "grandmaster", + "fisherman", + "expert", + "chef", + "carpenter", + "british", + "blackthorne", + "blackthorn", + "beggar", + "archer", + "apprentice", + "adept", + "gamemaster", + "frozen", + "squelched", + "invulnerable", + "osi", + "origin" + }; + } +} \ No newline at end of file diff --git a/Scripts/Misc/Notoriety.cs b/Scripts/Misc/Notoriety.cs new file mode 100644 index 0000000..9f7e4fc --- /dev/null +++ b/Scripts/Misc/Notoriety.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Guilds; +using Server.Multis; +using Server.Mobiles; +using Server.Engines.PartySystem; +using Server.Factions; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells; + +namespace Server.Misc +{ + public class NotorietyHandlers + { + public static void Initialize() + { + Notoriety.Hues[Notoriety.Innocent] = 0x59; + Notoriety.Hues[Notoriety.Ally] = 0x3F; + Notoriety.Hues[Notoriety.CanBeAttacked] = 0x3B2; + Notoriety.Hues[Notoriety.Criminal] = 0x3B2; + Notoriety.Hues[Notoriety.Enemy] = 0x90; + Notoriety.Hues[Notoriety.Murderer] = 0x22; + Notoriety.Hues[Notoriety.Invulnerable] = 0x35; + + Notoriety.Handler = new NotorietyHandler( MobileNotoriety ); + + Mobile.AllowBeneficialHandler = new AllowBeneficialHandler( Mobile_AllowBeneficial ); + Mobile.AllowHarmfulHandler = new AllowHarmfulHandler( Mobile_AllowHarmful ); + } + + private enum GuildStatus { None, Peaceful, Waring } + + private static GuildStatus GetGuildStatus( Mobile m ) + { + if( m.Guild == null ) + return GuildStatus.None; + else if( ((Guild)m.Guild).Enemies.Count == 0 && m.Guild.Type == GuildType.Regular ) + return GuildStatus.Peaceful; + + return GuildStatus.Waring; + } + + private static bool CheckBeneficialStatus( GuildStatus from, GuildStatus target ) + { + if( from == GuildStatus.Waring || target == GuildStatus.Waring ) + return false; + + return true; + } + + /*private static bool CheckHarmfulStatus( GuildStatus from, GuildStatus target ) + { + if ( from == GuildStatus.Waring && target == GuildStatus.Waring ) + return true; + + return false; + }*/ + + public static bool Mobile_AllowBeneficial( Mobile from, Mobile target ) + { + if( from == null || target == null || from.AccessLevel > AccessLevel.Player || target.AccessLevel > AccessLevel.Player ) + return true; + + #region Dueling + PlayerMobile pmFrom = from as PlayerMobile; + PlayerMobile pmTarg = target as PlayerMobile; + + if (pmFrom == null && from is BaseCreature) + { + BaseCreature bcFrom = (BaseCreature)from; + + if (bcFrom.Summoned) + pmFrom = bcFrom.SummonMaster as PlayerMobile; + } + + if (pmTarg == null && target is BaseCreature) + { + BaseCreature bcTarg = (BaseCreature)target; + + if (bcTarg.Summoned) + pmTarg = bcTarg.SummonMaster as PlayerMobile; + } + + if (pmFrom != null && pmTarg != null) + { + if (pmFrom.DuelContext != pmTarg.DuelContext && ((pmFrom.DuelContext != null && pmFrom.DuelContext.Started) || (pmTarg.DuelContext != null && pmTarg.DuelContext.Started))) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && ((pmFrom.DuelContext.StartedReadyCountdown && !pmFrom.DuelContext.Started) || pmFrom.DuelContext.Tied || pmFrom.DuelPlayer.Eliminated || pmTarg.DuelPlayer.Eliminated)) + return false; + + if (pmFrom.DuelPlayer != null && !pmFrom.DuelPlayer.Eliminated && pmFrom.DuelContext != null && pmFrom.DuelContext.IsSuddenDeath) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && pmFrom.DuelContext.m_Tournament != null && pmFrom.DuelContext.m_Tournament.IsNotoRestricted && pmFrom.DuelPlayer != null && pmTarg.DuelPlayer != null && pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant) + return false; + + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && pmFrom.DuelContext.Started) + return true; + } + + if ((pmFrom != null && pmFrom.DuelContext != null && pmFrom.DuelContext.Started) || (pmTarg != null && pmTarg.DuelContext != null && pmTarg.DuelContext.Started)) + return false; + + Engines.ConPVP.SafeZone sz = from.Region.GetRegion(typeof(Engines.ConPVP.SafeZone)) as Engines.ConPVP.SafeZone; + + if (sz != null /*&& sz.IsDisabled()*/ ) + return false; + + sz = target.Region.GetRegion(typeof(Engines.ConPVP.SafeZone)) as Engines.ConPVP.SafeZone; + + if (sz != null /*&& sz.IsDisabled()*/ ) + return false; + #endregion + + Map map = from.Map; + + #region Factions + Faction targetFaction = Faction.Find( target, true ); + + if( (!Core.ML || map == Faction.Facet) && targetFaction != null ) + { + if( Faction.Find( from, true ) != targetFaction ) + return false; + } + #endregion + + + if( map != null && (map.Rules & MapRules.BeneficialRestrictions) == 0 ) + return true; // In felucca, anything goes + + if( !from.Player ) + return true; // NPCs have no restrictions + + if( target is BaseCreature && !((BaseCreature)target).Controlled ) + return false; // Players cannot heal uncontrolled mobiles + + if( from is PlayerMobile && ((PlayerMobile)from).Young && (!(target is PlayerMobile) || !((PlayerMobile)target).Young) ) + return false; // Young players cannot perform beneficial actions towards older players + + Guild fromGuild = from.Guild as Guild; + Guild targetGuild = target.Guild as Guild; + + if( fromGuild != null && targetGuild != null && (targetGuild == fromGuild || fromGuild.IsAlly( targetGuild )) ) + return true; // Guild members can be beneficial + + return CheckBeneficialStatus( GetGuildStatus( from ), GetGuildStatus( target ) ); + } + + public static bool Mobile_AllowHarmful( Mobile from, Mobile target ) + { + if( from == null || target == null || from.AccessLevel > AccessLevel.Player || target.AccessLevel > AccessLevel.Player ) + return true; + + Map map = from.Map; + + if( map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0 ) + return true; // In felucca, anything goes + + BaseCreature bc = from as BaseCreature; + + if( !from.Player && !(bc != null && bc.GetMaster() != null && bc.GetMaster().AccessLevel == AccessLevel.Player ) ) + { + if( !CheckAggressor( from.Aggressors, target ) && !CheckAggressed( from.Aggressed, target ) && target is PlayerMobile && ((PlayerMobile)target).CheckYoungProtection( from ) ) + return false; + + return true; // Uncontrolled NPCs are only restricted by the young system + } + + Guild fromGuild = GetGuildFor( from.Guild as Guild, from ); + Guild targetGuild = GetGuildFor( target.Guild as Guild, target ); + + if( fromGuild != null && targetGuild != null && (fromGuild == targetGuild || fromGuild.IsAlly( targetGuild ) || fromGuild.IsEnemy( targetGuild )) ) + return true; // Guild allies or enemies can be harmful + + if( target is BaseCreature && (((BaseCreature)target).Controlled || (((BaseCreature)target).Summoned && from != ((BaseCreature)target).SummonMaster)) ) + return false; // Cannot harm other controlled mobiles + + if( target.Player ) + return false; // Cannot harm other players + + if( !(target is BaseCreature && ((BaseCreature)target).InitialInnocent) ) + { + if( Notoriety.Compute( from, target ) == Notoriety.Innocent ) + return false; // Cannot harm innocent mobiles + } + + return true; + } + + public static Guild GetGuildFor( Guild def, Mobile m ) + { + Guild g = def; + + BaseCreature c = m as BaseCreature; + + if( c != null && c.Controlled && c.ControlMaster != null ) + { + c.DisplayGuildTitle = false; + + if( c.Map != Map.Internal && (Core.AOS || Guild.NewGuildSystem || c.ControlOrder == OrderType.Attack || c.ControlOrder == OrderType.Guard) ) + g = (Guild)(c.Guild = c.ControlMaster.Guild); + else if( c.Map == Map.Internal || c.ControlMaster.Guild == null ) + g = (Guild)(c.Guild = null); + } + + return g; + } + + public static int CorpseNotoriety( Mobile source, Corpse target ) + { + if( target.AccessLevel > AccessLevel.Player ) + return Notoriety.CanBeAttacked; + + Body body = (Body)target.Amount; + + BaseCreature cretOwner = target.Owner as BaseCreature; + + if( cretOwner != null ) + { + Guild sourceGuild = GetGuildFor( source.Guild as Guild, source ); + Guild targetGuild = GetGuildFor( target.Guild as Guild, target.Owner ); + + if( sourceGuild != null && targetGuild != null ) + { + if( sourceGuild == targetGuild || sourceGuild.IsAlly( targetGuild ) ) + return Notoriety.Ally; + else if( sourceGuild.IsEnemy( targetGuild ) ) + return Notoriety.Enemy; + } + + Faction srcFaction = Faction.Find( source, true, true ); + Faction trgFaction = Faction.Find( target.Owner, true, true ); + + if( srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet ) + return Notoriety.Enemy; + + if( CheckHouseFlag( source, target.Owner, target.Location, target.Map ) ) + return Notoriety.CanBeAttacked; + + int actual = Notoriety.CanBeAttacked; + + if( target.Kills >= 5 || (body.IsMonster && IsSummoned( target.Owner as BaseCreature )) || (target.Owner is BaseCreature && (((BaseCreature)target.Owner).AlwaysMurderer || ((BaseCreature)target.Owner).IsAnimatedDead)) ) + actual = Notoriety.Murderer; + + if( DateTime.Now >= (target.TimeOfDeath + Corpse.MonsterLootRightSacrifice) ) + return actual; + + Party sourceParty = Party.Get( source ); + + List list = target.Aggressors; + + for( int i = 0; i < list.Count; ++i ) + { + if( list[i] == source || (sourceParty != null && Party.Get( list[i] ) == sourceParty) ) + return actual; + } + + return Notoriety.Innocent; + } + else + { + if( target.Kills >= 5 || (body.IsMonster && IsSummoned( target.Owner as BaseCreature )) || (target.Owner is BaseCreature && (((BaseCreature)target.Owner).AlwaysMurderer || ((BaseCreature)target.Owner).IsAnimatedDead)) ) + return Notoriety.Murderer; + + if (target.Criminal && target.Map != null && ((target.Map.Rules & MapRules.HarmfulRestrictions) == 0)) + return Notoriety.Criminal; + + Guild sourceGuild = GetGuildFor( source.Guild as Guild, source ); + Guild targetGuild = GetGuildFor( target.Guild as Guild, target.Owner ); + + if( sourceGuild != null && targetGuild != null ) + { + if( sourceGuild == targetGuild || sourceGuild.IsAlly( targetGuild ) ) + return Notoriety.Ally; + else if( sourceGuild.IsEnemy( targetGuild ) ) + return Notoriety.Enemy; + } + + Faction srcFaction = Faction.Find( source, true, true ); + Faction trgFaction = Faction.Find( target.Owner, true, true ); + + if( srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet ) + { + List secondList = target.Aggressors; + + for( int i = 0; i < secondList.Count; ++i ) + { + if( secondList[i] == source || secondList[i] is BaseFactionGuard ) + return Notoriety.Enemy; + } + } + + if( target.Owner != null && target.Owner is BaseCreature && ((BaseCreature)target.Owner).AlwaysAttackable ) + return Notoriety.CanBeAttacked; + + if( CheckHouseFlag( source, target.Owner, target.Location, target.Map ) ) + return Notoriety.CanBeAttacked; + + if( !(target.Owner is PlayerMobile) && !IsPet( target.Owner as BaseCreature ) ) + return Notoriety.CanBeAttacked; + + List list = target.Aggressors; + + for( int i = 0; i < list.Count; ++i ) + { + if( list[i] == source ) + return Notoriety.CanBeAttacked; + } + + return Notoriety.Innocent; + } + } + + public static int MobileNotoriety( Mobile source, Mobile target ) + { + if (Core.AOS && (target.Blessed || (target is BaseCreature && ((BaseCreature)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier)) + return Notoriety.Invulnerable; + + if( target.AccessLevel > AccessLevel.Player ) + return Notoriety.CanBeAttacked; + + if( source.Player && !target.Player && source is PlayerMobile && target is BaseCreature ) + { + BaseCreature bc = (BaseCreature)target; + + Mobile master = bc.GetMaster(); + + if ( master != null && master.AccessLevel > AccessLevel.Player ) + return Notoriety.CanBeAttacked; + + master = bc.ControlMaster; + + if ( Core.ML && master != null ) + { + if ( ( source == master && CheckAggressor( target.Aggressors, source ) ) || ( CheckAggressor( source.Aggressors, bc ) ) ) + return Notoriety.CanBeAttacked; + else + return MobileNotoriety( source, master ); + } + + if( !bc.Summoned && !bc.Controlled && ((PlayerMobile)source).EnemyOfOneType == target.GetType() ) + return Notoriety.Enemy; + } + + if ( target.Kills >= 5 || ( target.Body.IsMonster && IsSummoned( target as BaseCreature ) && !( target is BaseFamiliar ) && !( target is ArcaneFey ) && !( target is Golem ) ) || ( target is BaseCreature && ( ( (BaseCreature)target ).AlwaysMurderer || ( (BaseCreature)target ).IsAnimatedDead ) ) ) + return Notoriety.Murderer; + + if( target.Criminal ) + return Notoriety.Criminal; + + Guild sourceGuild = GetGuildFor( source.Guild as Guild, source ); + Guild targetGuild = GetGuildFor( target.Guild as Guild, target ); + + if( sourceGuild != null && targetGuild != null ) + { + if( sourceGuild == targetGuild || sourceGuild.IsAlly( targetGuild ) ) + return Notoriety.Ally; + else if( sourceGuild.IsEnemy( targetGuild ) ) + return Notoriety.Enemy; + } + + Faction srcFaction = Faction.Find( source, true, true ); + Faction trgFaction = Faction.Find( target, true, true ); + + if( srcFaction != null && trgFaction != null && srcFaction != trgFaction && source.Map == Faction.Facet ) + return Notoriety.Enemy; + + if( SkillHandlers.Stealing.ClassicMode && target is PlayerMobile && ((PlayerMobile)target).PermaFlags.Contains( source ) ) + return Notoriety.CanBeAttacked; + + if( target is BaseCreature && ((BaseCreature)target).AlwaysAttackable ) + return Notoriety.CanBeAttacked; + + if( CheckHouseFlag( source, target, target.Location, target.Map ) ) + return Notoriety.CanBeAttacked; + + if( !(target is BaseCreature && ((BaseCreature)target).InitialInnocent) ) //If Target is NOT A baseCreature, OR it's a BC and the BC is initial innocent... + { + if( !target.Body.IsHuman && !target.Body.IsGhost && !IsPet( target as BaseCreature ) && !(target is PlayerMobile) || !Core.ML && !target.CanBeginAction( typeof( Server.Spells.Seventh.PolymorphSpell ) ) ) + return Notoriety.CanBeAttacked; + } + + if( CheckAggressor( source.Aggressors, target ) ) + return Notoriety.CanBeAttacked; + + if( CheckAggressed( source.Aggressed, target ) ) + return Notoriety.CanBeAttacked; + + if( target is BaseCreature ) + { + BaseCreature bc = (BaseCreature)target; + + if( bc.Controlled && bc.ControlOrder == OrderType.Guard && bc.ControlTarget == source ) + return Notoriety.CanBeAttacked; + } + + if (source is BaseCreature) + { + BaseCreature bc = (BaseCreature)source; + Mobile master = bc.GetMaster(); + + if (master != null) + if (CheckAggressor(master.Aggressors, target) || MobileNotoriety(master, target) == Notoriety.CanBeAttacked || target is BaseCreature) + return Notoriety.CanBeAttacked; + } + + return Notoriety.Innocent; + } + + public static bool CheckHouseFlag( Mobile from, Mobile m, Point3D p, Map map ) + { + BaseHouse house = BaseHouse.FindHouseAt( p, map, 16 ); + + if( house == null || house.Public || !house.IsFriend( from ) ) + return false; + + if( m != null && house.IsFriend( m ) ) + return false; + + BaseCreature c = m as BaseCreature; + + if( c != null && !c.Deleted && c.Controlled && c.ControlMaster != null ) + return !house.IsFriend( c.ControlMaster ); + + return true; + } + + public static bool IsPet( BaseCreature c ) + { + return (c != null && c.Controlled); + } + + public static bool IsSummoned( BaseCreature c ) + { + return (c != null && /*c.Controlled &&*/ c.Summoned); + } + + public static bool CheckAggressor( List list, Mobile target ) + { + for( int i = 0; i < list.Count; ++i ) + if( list[i].Attacker == target ) + return true; + + return false; + } + + public static bool CheckAggressed( List list, Mobile target ) + { + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( !info.CriminalAggression && info.Defender == target ) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Paperdoll.cs b/Scripts/Misc/Paperdoll.cs new file mode 100644 index 0000000..ceff233 --- /dev/null +++ b/Scripts/Misc/Paperdoll.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Network; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Misc +{ + public class Paperdoll + { + public static void Initialize() + { + EventSink.PaperdollRequest += new PaperdollRequestEventHandler( EventSink_PaperdollRequest ); + } + + public static void EventSink_PaperdollRequest( PaperdollRequestEventArgs e ) + { + Mobile beholder = e.Beholder; + Mobile beheld = e.Beheld; + + beholder.Send( new DisplayPaperdoll( beheld, Titles.ComputeTitle( beholder, beheld ), beheld.AllowEquipFrom( beholder ) ) ); + + if ( ObjectPropertyList.Enabled ) + { + List items = beheld.Items; + + for ( int i = 0; i < items.Count; ++i ) + beholder.Send( items[i].OPLPacket ); + + // NOTE: OSI sends MobileUpdate when opening your own paperdoll. + // It has a very bad rubber-banding affect. What positive affects does it have? + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Poison.cs b/Scripts/Misc/Poison.cs new file mode 100644 index 0000000..b0ff2be --- /dev/null +++ b/Scripts/Misc/Poison.cs @@ -0,0 +1,156 @@ +using System; +using Server; +using Server.Items; +using Server.Network; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server +{ + public class PoisonImpl : Poison + { + [CallPriority( 10 )] + public static void Configure() + { + if ( Core.AOS ) + { + Register( new PoisonImpl( "Lesser", 0, 4, 16, 7.5, 3.0, 2.25, 10, 4 ) ); + Register( new PoisonImpl( "Regular", 1, 8, 18, 10.0, 3.0, 3.25, 10, 3 ) ); + Register( new PoisonImpl( "Greater", 2, 12, 20, 15.0, 3.0, 4.25, 10, 2 ) ); + Register( new PoisonImpl( "Deadly", 3, 16, 30, 30.0, 3.0, 5.25, 15, 2 ) ); + Register( new PoisonImpl( "Lethal", 4, 20, 50, 35.0, 3.0, 5.25, 20, 2 ) ); + } + else + { + Register( new PoisonImpl( "Lesser", 0, 4, 26, 2.500, 3.5, 3.0, 10, 2 ) ); + Register( new PoisonImpl( "Regular", 1, 5, 26, 3.125, 3.5, 3.0, 10, 2 ) ); + Register( new PoisonImpl( "Greater", 2, 6, 26, 6.250, 3.5, 3.0, 10, 2 ) ); + Register( new PoisonImpl( "Deadly", 3, 7, 26, 12.500, 3.5, 4.0, 10, 2 ) ); + Register( new PoisonImpl( "Lethal", 4, 9, 26, 25.000, 3.5, 5.0, 10, 2 ) ); + } + } + + public static Poison IncreaseLevel( Poison oldPoison ) + { + Poison newPoison = ( oldPoison == null ? null : GetPoison( oldPoison.Level + 1 ) ); + + return ( newPoison == null ? oldPoison : newPoison ); + } + + // Info + private string m_Name; + private int m_Level; + + // Damage + private int m_Minimum, m_Maximum; + private double m_Scalar; + + // Timers + private TimeSpan m_Delay; + private TimeSpan m_Interval; + private int m_Count, m_MessageInterval; + + public PoisonImpl( string name, int level, int min, int max, double percent, double delay, double interval, int count, int messageInterval ) + { + m_Name = name; + m_Level = level; + m_Minimum = min; + m_Maximum = max; + m_Scalar = percent * 0.01; + m_Delay = TimeSpan.FromSeconds( delay ); + m_Interval = TimeSpan.FromSeconds( interval ); + m_Count = count; + m_MessageInterval = messageInterval; + } + + public override string Name{ get{ return m_Name; } } + public override int Level{ get{ return m_Level; } } + + public class PoisonTimer : Timer + { + private PoisonImpl m_Poison; + private Mobile m_Mobile; + private Mobile m_From; + private int m_LastDamage; + private int m_Index; + + public Mobile From{ get{ return m_From; } set{ m_From = value; } } + + public PoisonTimer( Mobile m, PoisonImpl p ) : base( p.m_Delay, p.m_Interval ) + { + m_From = m; + m_Mobile = m; + m_Poison = p; + } + + protected override void OnTick() + { + if ( (Core.AOS && m_Poison.Level < 4 && TransformationSpellHelper.UnderTransformation( m_Mobile, typeof( VampiricEmbraceSpell ) )) || + (m_Poison.Level < 3 && OrangePetals.UnderEffect( m_Mobile )) || + AnimalForm.UnderTransformation( m_Mobile, typeof( Unicorn ) ) ) + { + if ( m_Mobile.CurePoison( m_Mobile ) ) + { + m_Mobile.LocalOverheadMessage( MessageType.Emote, 0x3F, false, + "* Vous r�sistez les effets du poison *" ); + + m_Mobile.NonlocalOverheadMessage( MessageType.Emote, 0x3F, true, + String.Format( "* {0} r�siste au poison *", m_Mobile.Name ) ); + + Stop(); + return; + } + } + + if ( m_Index++ == m_Poison.m_Count ) + { + m_Mobile.SendMessage( "Les effets du poison s'att�nuent" ); // The poison seems to have worn off. + m_Mobile.Poison = null; + + Stop(); + return; + } + + int damage; + + if ( !Core.AOS && m_LastDamage != 0 && Utility.RandomBool() ) + { + damage = m_LastDamage; + } + else + { + damage = 1 + (int)(m_Mobile.Hits * m_Poison.m_Scalar); + + if ( damage < m_Poison.m_Minimum ) + damage = m_Poison.m_Minimum; + else if ( damage > m_Poison.m_Maximum ) + damage = m_Poison.m_Maximum; + + m_LastDamage = damage; + } + + if ( m_From != null ) + m_From.DoHarmful( m_Mobile, true ); + + IHonorTarget honorTarget = m_Mobile as IHonorTarget; + if ( honorTarget != null && honorTarget.ReceivedHonorContext != null ) + honorTarget.ReceivedHonorContext.OnTargetPoisoned(); + + AOS.Damage( m_Mobile, m_From, damage, 0, 0, 0, 100, 0 ); + + if (0.60 <= Utility.RandomDouble()) // OSI: randomly revealed between first and third damage tick, guessing 60% chance + m_Mobile.RevealingAction(); + + if ( (m_Index % m_Poison.m_MessageInterval) == 0 ) + m_Mobile.OnPoisoned( m_From, m_Poison, m_Poison ); + } + } + + public override Timer ConstructTimer( Mobile m ) + { + return new PoisonTimer( m, this ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ProfanityProtection.cs b/Scripts/Misc/ProfanityProtection.cs new file mode 100644 index 0000000..62928ae --- /dev/null +++ b/Scripts/Misc/ProfanityProtection.cs @@ -0,0 +1,124 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Misc +{ + public enum ProfanityAction + { + None, // no action taken + Disallow, // speech is not displayed + Criminal, // makes the player criminal, not killable by guards + CriminalAction, // makes the player criminal, can be killed by guards + Disconnect, // player is kicked + Other // some other implementation + } + + public class ProfanityProtection + { + private static bool Enabled = false; + private static ProfanityAction Action = ProfanityAction.Disallow; // change here what to do when profanity is detected + + public static void Initialize() + { + if ( Enabled ) + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + } + + private static bool OnProfanityDetected( Mobile from, string speech ) + { + switch ( Action ) + { + case ProfanityAction.None: return true; + case ProfanityAction.Disallow: return false; + case ProfanityAction.Criminal: from.Criminal = true; return true; + case ProfanityAction.CriminalAction: from.CriminalAction( false ); return true; + case ProfanityAction.Disconnect: + { + NetState ns = from.NetState; + + if ( ns != null ) + ns.Dispose(); + + return false; + } + default: + case ProfanityAction.Other: // TODO: Provide custom implementation if this is chosen + { + return true; + } + } + } + + private static void EventSink_Speech( SpeechEventArgs e ) + { + Mobile from = e.Mobile; + + if ( from.AccessLevel > AccessLevel.Player ) + return; + + if ( !NameVerification.Validate( e.Speech, 0, int.MaxValue, true, true, false, int.MaxValue, m_Exceptions, m_Disallowed, m_StartDisallowed ) ) + e.Blocked = !OnProfanityDetected( from, e.Speech ); + } + + public static char[] Exceptions{ get{ return m_Exceptions; } } + public static string[] StartDisallowed{ get{ return m_StartDisallowed; } } + public static string[] Disallowed{ get{ return m_Disallowed; } } + + private static char[] m_Exceptions = new char[] + { + ' ', '-', '.', '\'', '"', ',', '_', '+', '=', '~', '`', '!', '^', '*', '\\', '/', ';', ':', '<', '>', '[', ']', '{', '}', '?', '|', '(', ')', '%', '$', '&', '#', '@' + }; + + private static string[] m_StartDisallowed = new string[]{}; + + private static string[] m_Disallowed = new string[] + { + "jigaboo", + "chigaboo", + "wop", + "kyke", + "kike", + "tit", + "spic", + "prick", + "piss", + "lezbo", + "lesbo", + "felatio", + "dyke", + "dildo", + "chinc", + "chink", + "cunnilingus", + "cum", + "cocksucker", + "cock", + "clitoris", + "clit", + "ass", + "hitler", + "penis", + "nigga", + "nigger", + "klit", + "kunt", + "jiz", + "jism", + "jerkoff", + "jackoff", + "goddamn", + "fag", + "blowjob", + "bitch", + "asshole", + "dick", + "pussy", + "snatch", + "cunt", + "twat", + "shit", + "fuck" + }; + } +} \ No newline at end of file diff --git a/Scripts/Misc/Profile.cs b/Scripts/Misc/Profile.cs new file mode 100644 index 0000000..54b42e0 --- /dev/null +++ b/Scripts/Misc/Profile.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Network; +using Server.Accounting; + +namespace Server.Misc +{ + public class Profile + { + public static void Initialize() + { + EventSink.ProfileRequest += new ProfileRequestEventHandler( EventSink_ProfileRequest ); + EventSink.ChangeProfileRequest += new ChangeProfileRequestEventHandler( EventSink_ChangeProfileRequest ); + } + + public static void EventSink_ChangeProfileRequest( ChangeProfileRequestEventArgs e ) + { + Mobile from = e.Beholder; + + if ( from.ProfileLocked ) + from.SendMessage( "Your profile is locked. You may not change it." ); + else + from.Profile = e.Text; + } + + public static void EventSink_ProfileRequest( ProfileRequestEventArgs e ) + { + Mobile beholder = e.Beholder; + Mobile beheld = e.Beheld; + + if ( !beheld.Player ) + return; + + if ( beholder.Map != beheld.Map || !beholder.InRange( beheld, 12 ) || !beholder.CanSee( beheld ) ) + return; + + string header = Titles.ComputeTitle( beholder, beheld ); + + string footer = ""; + + if ( beheld.ProfileLocked ) + { + if ( beholder == beheld ) + footer = "Your profile has been locked."; + else if ( beholder.AccessLevel >= AccessLevel.Counselor ) + footer = "This profile has been locked."; + } + + if ( footer.Length == 0 && beholder == beheld ) + footer = GetAccountDuration( beheld ); + + string body = beheld.Profile; + + if ( body == null || body.Length <= 0 ) + body = ""; + + beholder.Send( new DisplayProfile( beholder != beheld || !beheld.ProfileLocked, beheld, header, body, footer ) ); + } + + private static string GetAccountDuration( Mobile m ) + { + Account a = m.Account as Account; + + if ( a == null ) + return ""; + + TimeSpan ts = DateTime.Now - a.Created; + + string v; + + if ( Format( ts.TotalDays, "This account is {0} day{1} old.", out v ) ) + return v; + + if ( Format( ts.TotalHours, "This account is {0} hour{1} old.", out v ) ) + return v; + + if ( Format( ts.TotalMinutes, "This account is {0} minute{1} old.", out v ) ) + return v; + + if ( Format( ts.TotalSeconds, "This account is {0} second{1} old.", out v ) ) + return v; + + return ""; + } + + public static bool Format( double value, string format, out string op ) + { + if ( value >= 1.0 ) + { + op = String.Format( format, (int)value, (int)value != 1 ? "s" : "" ); + return true; + } + + op = null; + return false; + } + } +} diff --git a/Scripts/Misc/ProtocolExtensions.cs b/Scripts/Misc/ProtocolExtensions.cs new file mode 100644 index 0000000..fa1d08f --- /dev/null +++ b/Scripts/Misc/ProtocolExtensions.cs @@ -0,0 +1,65 @@ +using System; +using Server; +using Server.Network; +using Server.Mobiles; +using Server.Engines.PartySystem; + +namespace Server.Misc +{ + public class ProtocolExtensions + { + private static PacketHandler[] m_Handlers = new PacketHandler[0x100]; + + public static void Initialize() + { + PacketHandlers.Register( 0xF0, 0, false, new OnPacketReceive( DecodeBundledPacket ) ); + } + + public static void Register( int packetID, bool ingame, OnPacketReceive onReceive ) + { + m_Handlers[packetID] = new PacketHandler( packetID, 0, ingame, onReceive ); + } + + public static PacketHandler GetHandler( int packetID ) + { + if ( packetID >= 0 && packetID < m_Handlers.Length ) + return m_Handlers[packetID]; + + return null; + } + + public static void DecodeBundledPacket( NetState state, PacketReader pvSrc ) + { + int packetID = pvSrc.ReadByte(); + + PacketHandler ph = GetHandler( packetID ); + + if ( ph != null ) + { + if ( ph.Ingame && state.Mobile == null ) + { + Console.WriteLine( "Client: {0}: Sent ingame packet (0xF0x{1:X2}) before having been attached to a mobile", state, packetID ); + state.Dispose(); + } + else if ( ph.Ingame && state.Mobile.Deleted ) + { + state.Dispose(); + } + else + { + ph.OnReceive( state, pvSrc ); + } + } + } + } + + public abstract class ProtocolExtension : Packet + { + public ProtocolExtension( int packetID, int capacity ) : base( 0xF0 ) + { + EnsureCapacity( 4 + capacity ); + + m_Stream.Write( (byte) packetID ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/RaceDefinitions.cs b/Scripts/Misc/RaceDefinitions.cs new file mode 100644 index 0000000..3ec660a --- /dev/null +++ b/Scripts/Misc/RaceDefinitions.cs @@ -0,0 +1,223 @@ +using System; +using Server; + +namespace Server.Misc +{ + public class RaceDefinitions + { + public static void Configure() + { + /* Here we configure all races. Some notes: + * + * 1) The first 32 races are reserved for core use. + * 2) Race 0x7F is reserved for core use. + * 3) Race 0xFF is reserved for core use. + * 4) Changing or removing any predefined races may cause server instability. + */ + + RegisterRace( new Human ( 0, 0 ) ); + RegisterRace( new Elf ( 1, 1 ) ); + } + + public static void RegisterRace( Race race ) + { + Race.Races[race.RaceIndex] = race; + Race.AllRaces.Add( race ); + } + + private class Human : Race + { + public Human( int raceID, int raceIndex ) + : base( raceID, raceIndex, "Human", "Humans", 400, 401, 402, 403, Expansion.None ) + { + } + + public override bool ValidateHair( bool female, int itemID ) + { + if( itemID == 0 ) + return true; + + if( (female && itemID == 0x2048) || (!female && itemID == 0x2046 ) ) + return false; //Buns & Receeding Hair + + if( itemID >= 0x203B && itemID <= 0x203D ) + return true; + + if( itemID >= 0x2044 && itemID <= 0x204A ) + return true; + + return false; + } + + public override int RandomHair( bool female ) //Random hair doesn't include baldness + { + switch( Utility.Random( 9 ) ) + { + case 0: return 0x203B; //Short + case 1: return 0x203C; //Long + case 2: return 0x203D; //Pony Tail + case 3: return 0x2044; //Mohawk + case 4: return 0x2045; //Pageboy + case 5: return 0x2047; //Afro + case 6: return 0x2049; //Pig tails + case 7: return 0x204A; //Krisna + default: return (female ? 0x2046 : 0x2048); //Buns or Receeding Hair + } + } + + public override bool ValidateFacialHair( bool female, int itemID ) + { + if( itemID == 0 ) + return true; + + if( female ) + return false; + + if( itemID >= 0x203E && itemID <= 0x2041 ) + return true; + + if( itemID >= 0x204B && itemID <= 0x204D ) + return true; + + return false; + } + + public override int RandomFacialHair( bool female ) + { + if( female ) + return 0; + + int rand = Utility.Random( 7 ); + + return ((rand < 4) ? 0x203E : 0x2047) + rand; + } + + public override int ClipSkinHue( int hue ) + { + if( hue < 1002 ) + return 1002; + else if( hue > 1058 ) + return 1058; + else + return hue; + } + + public override int RandomSkinHue() + { + return Utility.Random( 1002, 57 ) | 0x8000; + } + + public override int ClipHairHue( int hue ) + { + if( hue < 1102 ) + return 1102; + else if( hue > 1149 ) + return 1149; + else + return hue; + } + + public override int RandomHairHue() + { + return Utility.Random( 1102, 48 ); + } + } + + private class Elf : Race + { + private static int[] m_SkinHues = new int[] + { + 0x0BF, 0x24D, 0x24E, 0x24F, 0x353, 0x361, 0x367, 0x374, + 0x375, 0x376, 0x381, 0x382, 0x383, 0x384, 0x385, 0x389, + 0x3DE, 0x3E5, 0x3E6, 0x3E8, 0x3E9, 0x430, 0x4A7, 0x4DE, + 0x51D, 0x53F, 0x579, 0x76B, 0x76C, 0x76D, 0x835, 0x903 + }; + + private static int[] m_HairHues = new int[] + { + 0x034, 0x035, 0x036, 0x037, 0x038, 0x039, 0x058, 0x08E, + 0x08F, 0x090, 0x091, 0x092, 0x101, 0x159, 0x15A, 0x15B, + 0x15C, 0x15D, 0x15E, 0x128, 0x12F, 0x1BD, 0x1E4, 0x1F3, + 0x207, 0x211, 0x239, 0x251, 0x26C, 0x2C3, 0x2C9, 0x31D, + 0x31E, 0x31F, 0x320, 0x321, 0x322, 0x323, 0x324, 0x325, + 0x326, 0x369, 0x386, 0x387, 0x388, 0x389, 0x38A, 0x59D, + 0x6B8, 0x725, 0x853 + }; + + public Elf( int raceID, int raceIndex ) + : base( raceID, raceIndex, "Elf", "Elves", 605, 606, 607, 608, Expansion.ML ) + { + } + + public override bool ValidateHair( bool female, int itemID ) + { + if( itemID == 0 ) + return true; + + if( (female && (itemID == 0x2FCD || itemID == 0x2FBF)) || (!female && (itemID == 0x2FCC || itemID == 0x2FD0)) ) + return false; + + if( itemID >= 0x2FBF && itemID <= 0x2FC2 ) + return true; + + if( itemID >= 0x2FCC && itemID <= 0x2FD1 ) + return true; + + return false; + } + + public override int RandomHair( bool female ) //Random hair doesn't include baldness + { + switch( Utility.Random( 8 ) ) + { + case 0: return 0x2FC0; //Long Feather + case 1: return 0x2FC1; //Short + case 2: return 0x2FC2; //Mullet + case 3: return 0x2FCE; //Knob + case 4: return 0x2FCF; //Braided + case 5: return 0x2FD1; //Spiked + case 6: return (female ? 0x2FCC : 0x2FBF); //Flower or Mid-long + default: return (female ? 0x2FD0 : 0x2FCD); //Bun or Long + } + } + + public override bool ValidateFacialHair( bool female, int itemID ) + { + return (itemID == 0); + } + + public override int RandomFacialHair( bool female ) + { + return 0; + } + + public override int ClipSkinHue( int hue ) + { + for( int i = 0; i < m_SkinHues.Length; i++ ) + if( m_SkinHues[i] == hue ) + return hue; + + return m_SkinHues[0]; + } + + public override int RandomSkinHue() + { + return m_SkinHues[Utility.Random( m_SkinHues.Length )] | 0x8000; + } + + public override int ClipHairHue( int hue ) + { + for( int i = 0; i < m_HairHues.Length; i++ ) + if( m_HairHues[i] == hue ) + return hue; + + return m_HairHues[0]; + } + + public override int RandomHairHue() + { + return m_HairHues[Utility.Random( m_HairHues.Length )]; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/RegenRates.cs b/Scripts/Misc/RegenRates.cs new file mode 100644 index 0000000..6873134 --- /dev/null +++ b/Scripts/Misc/RegenRates.cs @@ -0,0 +1,219 @@ +using System; +using Server; +using Server.Items; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Mobiles; + +namespace Server.Misc +{ + public class RegenRates + { + [CallPriority( 10 )] + public static void Configure() + { + Mobile.DefaultHitsRate = TimeSpan.FromSeconds( 11.0 ); + Mobile.DefaultStamRate = TimeSpan.FromSeconds( 7.0 ); + Mobile.DefaultManaRate = TimeSpan.FromSeconds( 7.0 ); + + Mobile.ManaRegenRateHandler = new RegenRateHandler( Mobile_ManaRegenRate ); + + if ( Core.AOS ) + { + Mobile.StamRegenRateHandler = new RegenRateHandler( Mobile_StamRegenRate ); + Mobile.HitsRegenRateHandler = new RegenRateHandler( Mobile_HitsRegenRate ); + } + } + + private static void CheckBonusSkill( Mobile m, int cur, int max, SkillName skill ) + { + if ( !m.Alive ) + return; + + double n = (double)cur / max; + double v = Math.Sqrt( m.Skills[skill].Value * 0.005 ); + + n *= (1.0 - v); + n += v; + + m.CheckSkill( skill, n ); + } + + private static bool CheckTransform( Mobile m, Type type ) + { + return TransformationSpellHelper.UnderTransformation( m, type ); + } + + private static bool CheckAnimal( Mobile m, Type type ) + { + return AnimalForm.UnderTransformation( m, type ); + } + + private static TimeSpan Mobile_HitsRegenRate( Mobile from ) + { + int points = AosAttributes.GetValue( from, AosAttribute.RegenHits ); + + if ( from is BaseCreature && !((BaseCreature)from).IsAnimatedDead ) + points += 4; + + if ( (from is BaseCreature && ((BaseCreature)from).IsParagon) || from is Leviathan ) + points += 40; + + if( Core.ML && from.Race == Race.Human ) //Is this affected by the cap? + points += 2; + + if ( points < 0 ) + points = 0; + + if( Core.ML && from is PlayerMobile ) //does racial bonus go before/after? + points = Math.Min( points, 18 ); + + if ( CheckTransform( from, typeof( HorrificBeastSpell ) ) ) + points += 20; + + if ( CheckAnimal( from, typeof( Dog ) ) || CheckAnimal( from, typeof( Cat ) ) ) + points += from.Skills[SkillName.Ninjitsu].Fixed / 30; + + return TimeSpan.FromSeconds( 1.0 / (0.1 * (1 + points)) ); + } + + private static TimeSpan Mobile_StamRegenRate( Mobile from ) + { + if ( from.Skills == null ) + return Mobile.DefaultStamRate; + + CheckBonusSkill( from, from.Stam, from.StamMax, SkillName.Focus ); + + int points =(int)(from.Skills[SkillName.Focus].Value * 0.1); + + if( (from is BaseCreature && ((BaseCreature)from).IsParagon) || from is Leviathan ) + points += 40; + + int cappedPoints = AosAttributes.GetValue( from, AosAttribute.RegenStam ); + + if ( CheckTransform( from, typeof( VampiricEmbraceSpell ) ) ) + cappedPoints += 15; + + if ( CheckAnimal( from, typeof( Kirin ) ) ) + cappedPoints += 20; + + if( Core.ML && from is PlayerMobile ) + cappedPoints = Math.Min( cappedPoints, 24 ); + + points += cappedPoints; + + if ( points < -1 ) + points = -1; + + return TimeSpan.FromSeconds( 1.0 / (0.1 * (2 + points)) ); + } + + private static TimeSpan Mobile_ManaRegenRate( Mobile from ) + { + if ( from.Skills == null ) + return Mobile.DefaultManaRate; + + if ( !from.Meditating ) + CheckBonusSkill( from, from.Mana, from.ManaMax, SkillName.Meditation ); + + double rate; + double armorPenalty = GetArmorOffset( from ); + + if ( Core.AOS ) + { + double medPoints = from.Int + (from.Skills[SkillName.Meditation].Value * 3); + + medPoints *= ( from.Skills[SkillName.Meditation].Value < 100.0 ) ? 0.025 : 0.0275; + + CheckBonusSkill( from, from.Mana, from.ManaMax, SkillName.Focus ); + + double focusPoints = (from.Skills[SkillName.Focus].Value * 0.05); + + if ( armorPenalty > 0 ) + medPoints = 0; // In AOS, wearing any meditation-blocking armor completely removes meditation bonus + + double totalPoints = focusPoints + medPoints + (from.Meditating ? (medPoints > 13.0 ? 13.0 : medPoints) : 0.0); + + if( (from is BaseCreature && ((BaseCreature)from).IsParagon) || from is Leviathan ) + totalPoints += 40; + + int cappedPoints = AosAttributes.GetValue( from, AosAttribute.RegenMana ); + + if ( CheckTransform( from, typeof( VampiricEmbraceSpell ) ) ) + cappedPoints += 3; + else if ( CheckTransform( from, typeof( LichFormSpell ) ) ) + cappedPoints += 13; + + if( Core.ML && from is PlayerMobile ) + cappedPoints = Math.Min( cappedPoints, 18 ); + + totalPoints += cappedPoints; + + if ( totalPoints < -1 ) + totalPoints = -1; + + if ( Core.ML ) + totalPoints = Math.Floor( totalPoints ); + + rate = 1.0 / (0.1 * (2 + totalPoints)); + } + else + { + double medPoints = (from.Int + from.Skills[SkillName.Meditation].Value) * 0.5; + + if ( medPoints <= 0 ) + rate = 7.0; + else if ( medPoints <= 100 ) + rate = 7.0 - (239*medPoints/2400) + (19*medPoints*medPoints/48000); + else if ( medPoints < 120 ) + rate = 1.0; + else + rate = 0.75; + + rate += armorPenalty; + + if ( from.Meditating ) + rate *= 0.5; + + if ( rate < 0.5 ) + rate = 0.5; + else if ( rate > 7.0 ) + rate = 7.0; + } + + return TimeSpan.FromSeconds( rate ); + } + + public static double GetArmorOffset( Mobile from ) + { + double rating = 0.0; + + if ( !Core.AOS ) + rating += GetArmorMeditationValue( from.ShieldArmor as BaseArmor ); + + rating += GetArmorMeditationValue( from.NeckArmor as BaseArmor ); + rating += GetArmorMeditationValue( from.HandArmor as BaseArmor ); + rating += GetArmorMeditationValue( from.HeadArmor as BaseArmor ); + rating += GetArmorMeditationValue( from.ArmsArmor as BaseArmor ); + rating += GetArmorMeditationValue( from.LegsArmor as BaseArmor ); + rating += GetArmorMeditationValue( from.ChestArmor as BaseArmor ); + + return rating / 4; + } + + private static double GetArmorMeditationValue( BaseArmor ar ) + { + if ( ar == null || ar.ArmorAttributes.MageArmor != 0 || ar.Attributes.SpellChanneling != 0 ) + return 0.0; + + switch ( ar.MeditationAllowance ) + { + default: + case ArmorMeditationAllowance.None: return ar.BaseArmorRatingScaled; + case ArmorMeditationAllowance.Half: return ar.BaseArmorRatingScaled / 2.0; + case ArmorMeditationAllowance.All: return 0.0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/RenameRequests.cs b/Scripts/Misc/RenameRequests.cs new file mode 100644 index 0000000..2d8782b --- /dev/null +++ b/Scripts/Misc/RenameRequests.cs @@ -0,0 +1,51 @@ +using System; +using Server; + +namespace Server.Misc +{ + public class RenameRequests + { + public static void Initialize() + { + EventSink.RenameRequest += new RenameRequestEventHandler( EventSink_RenameRequest ); + } + + private static void EventSink_RenameRequest( RenameRequestEventArgs e ) + { + Mobile from = e.From; + Mobile targ = e.Target; + string name = e.Name; + + if ( from.CanSee( targ ) && from.InRange( targ, 12 ) && targ.CanBeRenamedBy( from ) ) + { + name = name.Trim(); + + if( NameVerification.Validate( name, 1, 16, true, false, true, 0, NameVerification.Empty, NameVerification.StartDisallowed, ( Core.ML ? NameVerification.Disallowed : new string[]{} ) ) ) + { + + if( Core.ML ) + { + string[] disallowed = ProfanityProtection.Disallowed; + + for( int i = 0; i < disallowed.Length; i++ ) + { + if( name.IndexOf( disallowed[i] ) != -1 ) + { + from.SendLocalizedMessage( 1072622 ); // That name isn't very polite. + return; + } + } + + from.SendLocalizedMessage( 1072623, String.Format( "{0}\t{1}", targ.Name, name ) ); // Pet ~1_OLDPETNAME~ renamed to ~2_NEWPETNAME~. + } + + targ.Name = name; + } + else + { + from.SendMessage( "That name is unacceptable." ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ResourceInfo.cs b/Scripts/Misc/ResourceInfo.cs new file mode 100644 index 0000000..05cb5a3 --- /dev/null +++ b/Scripts/Misc/ResourceInfo.cs @@ -0,0 +1,1098 @@ +using System; +using System.Collections; + +namespace Server.Items +{ + public enum CraftResource + { + None = 0, + MIron = 1, + MBronze, + MGold, + MCopper, + MOldcopper, + MDullcopper, + MSilver, + MShadow, + MBloodrock, + MBlackrock, + MMytheril, + MRose, + MVerite, + MAgapite, + MRusty, + MValorite, + MDragon, + MTitan, + MCrystaline, + MKrynite, + MVulcan, + MBloodcrest, + MElvin, + MAcid, + MAqua, + MEldar, + MGlowing, + MGorgan, + MSandrock, + MSteel, + + RegularLeather = 101, + SpinedLeather, + HornedLeather, + BarbedLeather, + DaemonLeather, + + RedScales = 201, + YellowScales, + BlackScales, + GreenScales, + WhiteScales, + BlueScales, + + RegularWood = 301, + OakWood, + AshWood, + YewWood, + Heartwood, + Bloodwood, + Frostwood + } + + public enum CraftResourceType + { + None, + Metal, + Leather, + Scales, + Wood + } + + public class CraftAttributeInfo + { + private int m_WeaponFireDamage; + private int m_WeaponColdDamage; + private int m_WeaponPoisonDamage; + private int m_WeaponEnergyDamage; + private int m_WeaponChaosDamage; + private int m_WeaponDirectDamage; + private int m_WeaponDurability; + private int m_WeaponLuck; + private int m_WeaponGoldIncrease; + private int m_WeaponLowerRequirements; + + private int m_ArmorPhysicalResist; + private int m_ArmorFireResist; + private int m_ArmorColdResist; + private int m_ArmorPoisonResist; + private int m_ArmorEnergyResist; + private int m_ArmorDurability; + private int m_ArmorLuck; + private int m_ArmorGoldIncrease; + private int m_ArmorLowerRequirements; + + private int m_RunicMinAttributes; + private int m_RunicMaxAttributes; + private int m_RunicMinIntensity; + private int m_RunicMaxIntensity; + + public int WeaponFireDamage { get { return m_WeaponFireDamage; } set { m_WeaponFireDamage = value; } } + public int WeaponColdDamage { get { return m_WeaponColdDamage; } set { m_WeaponColdDamage = value; } } + public int WeaponPoisonDamage { get { return m_WeaponPoisonDamage; } set { m_WeaponPoisonDamage = value; } } + public int WeaponEnergyDamage { get { return m_WeaponEnergyDamage; } set { m_WeaponEnergyDamage = value; } } + public int WeaponChaosDamage { get { return m_WeaponChaosDamage; } set { m_WeaponChaosDamage = value; } } + public int WeaponDirectDamage { get { return m_WeaponDirectDamage; } set { m_WeaponDirectDamage = value; } } + public int WeaponDurability { get { return m_WeaponDurability; } set { m_WeaponDurability = value; } } + public int WeaponLuck { get { return m_WeaponLuck; } set { m_WeaponLuck = value; } } + public int WeaponGoldIncrease { get { return m_WeaponGoldIncrease; } set { m_WeaponGoldIncrease = value; } } + public int WeaponLowerRequirements { get { return m_WeaponLowerRequirements; } set { m_WeaponLowerRequirements = value; } } + + public int ArmorPhysicalResist { get { return m_ArmorPhysicalResist; } set { m_ArmorPhysicalResist = value; } } + public int ArmorFireResist { get { return m_ArmorFireResist; } set { m_ArmorFireResist = value; } } + public int ArmorColdResist { get { return m_ArmorColdResist; } set { m_ArmorColdResist = value; } } + public int ArmorPoisonResist { get { return m_ArmorPoisonResist; } set { m_ArmorPoisonResist = value; } } + public int ArmorEnergyResist { get { return m_ArmorEnergyResist; } set { m_ArmorEnergyResist = value; } } + public int ArmorDurability { get { return m_ArmorDurability; } set { m_ArmorDurability = value; } } + public int ArmorLuck { get { return m_ArmorLuck; } set { m_ArmorLuck = value; } } + public int ArmorGoldIncrease { get { return m_ArmorGoldIncrease; } set { m_ArmorGoldIncrease = value; } } + public int ArmorLowerRequirements { get { return m_ArmorLowerRequirements; } set { m_ArmorLowerRequirements = value; } } + + public int RunicMinAttributes { get { return m_RunicMinAttributes; } set { m_RunicMinAttributes = value; } } + public int RunicMaxAttributes { get { return m_RunicMaxAttributes; } set { m_RunicMaxAttributes = value; } } + public int RunicMinIntensity { get { return m_RunicMinIntensity; } set { m_RunicMinIntensity = value; } } + public int RunicMaxIntensity { get { return m_RunicMaxIntensity; } set { m_RunicMaxIntensity = value; } } + + #region Mondain's Legacy + private int m_WeaponDamage; + private int m_WeaponHitChance; + private int m_WeaponHitLifeLeech; + private int m_WeaponRegenHits; + private int m_WeaponSwingSpeed; + + private int m_ArmorDamage; + private int m_ArmorHitChance; + private int m_ArmorRegenHits; + private int m_ArmorMage; + + private int m_ShieldPhysicalResist; + private int m_ShieldFireResist; + private int m_ShieldColdResist; + private int m_ShieldPoisonResist; + private int m_ShieldEnergyResist; + + public int WeaponDamage { get { return m_WeaponDamage; } set { m_WeaponDamage = value; } } + public int WeaponHitChance { get { return m_WeaponHitChance; } set { m_WeaponHitChance = value; } } + public int WeaponHitLifeLeech { get { return m_WeaponHitLifeLeech; } set { m_WeaponHitLifeLeech = value; } } + public int WeaponRegenHits { get { return m_WeaponRegenHits; } set { m_WeaponRegenHits = value; } } + public int WeaponSwingSpeed { get { return m_WeaponSwingSpeed; } set { m_WeaponSwingSpeed = value; } } + + public int ArmorDamage { get { return m_ArmorDamage; } set { m_ArmorDamage = value; } } + public int ArmorHitChance { get { return m_ArmorHitChance; } set { m_ArmorHitChance = value; } } + public int ArmorRegenHits { get { return m_ArmorRegenHits; } set { m_ArmorRegenHits = value; } } + public int ArmorMage { get { return m_ArmorMage; } set { m_ArmorMage = value; } } + + public int ShieldPhysicalResist { get { return m_ShieldPhysicalResist; } set { m_ShieldPhysicalResist = value; } } + public int ShieldFireResist { get { return m_ShieldFireResist; } set { m_ShieldFireResist = value; } } + public int ShieldColdResist { get { return m_ShieldColdResist; } set { m_ShieldColdResist = value; } } + public int ShieldPoisonResist { get { return m_ShieldPoisonResist; } set { m_ShieldPoisonResist = value; } } + public int ShieldEnergyResist { get { return m_ShieldEnergyResist; } set { m_ShieldEnergyResist = value; } } + #endregion + + + public CraftAttributeInfo() + { + } + + public static readonly CraftAttributeInfo Blank; + #region Metal + public static readonly CraftAttributeInfo + MIron, + MBronze, + MGold, + MCopper, + MOldcopper, + MDullcopper, + MSilver, + MShadow, + MBloodrock, + MBlackrock, + MMytheril, + MRose, + MVerite, + MAgapite, + MRusty, + MValorite, + MDragon, + MTitan, + MCrystaline, + MKrynite, + MVulcan, + MBloodcrest, + MElvin, + MAcid, + MAqua, + MEldar, + MGlowing, + MGorgan, + MSandrock, + MSteel; + #endregion + public static readonly CraftAttributeInfo Spined, Horned, Barbed, Daemon; + public static readonly CraftAttributeInfo RedScales, YellowScales, BlackScales, GreenScales, WhiteScales, BlueScales; + public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood; + + static CraftAttributeInfo() + { + Blank = new CraftAttributeInfo(); + + CraftAttributeInfo miron = MIron = new CraftAttributeInfo(); + CraftAttributeInfo mbronze = MBronze = new CraftAttributeInfo(); + mbronze.WeaponFireDamage = 20; + mbronze.WeaponEnergyDamage = 20; + mbronze.ArmorPhysicalResist = 2; + mbronze.ArmorFireResist = 1; + mbronze.ArmorEnergyResist = 1; + + CraftAttributeInfo mgold = MGold = new CraftAttributeInfo(); + + mgold.WeaponDurability = -5; + mgold.WeaponLuck = 30; + mgold.WeaponGoldIncrease = 15; + + mgold.ArmorColdResist = 2; + mgold.ArmorFireResist = 3; + + mgold.ArmorDurability = 10; + mgold.ArmorLuck = 30; + mgold.ArmorGoldIncrease = 2000; + CraftAttributeInfo mcopper = MCopper = new CraftAttributeInfo(); + mcopper.WeaponEnergyDamage = 25; + mcopper.ArmorPhysicalResist = 2; + mcopper.ArmorEnergyResist = 4; + + CraftAttributeInfo moldcopper = MOldcopper = new CraftAttributeInfo(); + moldcopper.WeaponPoisonDamage = 20; + moldcopper.WeaponEnergyDamage = 30; + moldcopper.WeaponDurability = -15; + moldcopper.ArmorPhysicalResist = 2; + moldcopper.ArmorFireResist = 1; + moldcopper.ArmorPoisonResist = 2; + moldcopper.ArmorEnergyResist = 3; + moldcopper.ArmorDurability = -15; + CraftAttributeInfo mdullcopper = MDullcopper = new CraftAttributeInfo(); + mdullcopper.WeaponFireDamage = 5; + mdullcopper.WeaponColdDamage = 10; + mdullcopper.WeaponEnergyDamage = 15; + + mdullcopper.ArmorPhysicalResist = 1; + mdullcopper.ArmorFireResist = 1; + mdullcopper.ArmorColdResist = 1; + mdullcopper.ArmorPoisonResist = 1; + mdullcopper.ArmorEnergyResist = 2; + + CraftAttributeInfo msilver = MSilver = new CraftAttributeInfo(); + msilver.WeaponEnergyDamage = 15; + msilver.WeaponDurability = 50; + msilver.WeaponHitLifeLeech = 10; + + msilver.ArmorPhysicalResist = 4; + msilver.ArmorPoisonResist = 3; + msilver.ArmorRegenHits = 1; + + msilver.ShieldColdResist = 3; + + CraftAttributeInfo mshadow = MShadow = new CraftAttributeInfo(); + + mshadow.WeaponColdDamage = 30; + mshadow.WeaponPoisonDamage = 10; + mshadow.ArmorPhysicalResist = 1; + mshadow.ArmorFireResist = -1; + mshadow.ArmorColdResist = 2; + mshadow.ArmorPoisonResist = 2; + + CraftAttributeInfo mbloodrock = MBloodrock = new CraftAttributeInfo(); + CraftAttributeInfo mblackrock = MBlackrock = new CraftAttributeInfo(); + mblackrock.WeaponChaosDamage = 30; + mblackrock.WeaponPoisonDamage = 20; + mblackrock.WeaponColdDamage = 10; + mblackrock.WeaponHitChance = 10; + mblackrock.WeaponSwingSpeed = 10; + + mblackrock.ArmorPhysicalResist = 2; + mblackrock.ArmorFireResist = 2; + mblackrock.ArmorEnergyResist = -2; + mblackrock.ArmorPoisonResist = 2; + + CraftAttributeInfo mmytheril = MMytheril = new CraftAttributeInfo(); + + CraftAttributeInfo mrose = MRose = new CraftAttributeInfo(); + mrose.WeaponColdDamage = 10; + mrose.WeaponEnergyDamage = 20; + mrose.WeaponLowerRequirements = 20; + mrose.WeaponDurability = -5; + + mrose.ArmorEnergyResist = 2; + mrose.ArmorColdResist = 2; + mrose.ArmorLowerRequirements = 20; + mrose.ArmorDurability = -5; + + CraftAttributeInfo mverite = MVerite = new CraftAttributeInfo(); + mverite.WeaponFireDamage = 50; + mverite.WeaponHitChance = 5; + + mverite.ArmorPhysicalResist = -1; + mverite.ArmorColdResist = 3; + mverite.ArmorFireResist = 5; + mverite.ArmorPoisonResist = 7; + + CraftAttributeInfo magapite = MAgapite = new CraftAttributeInfo(); + + magapite.WeaponDurability = 70; + magapite.WeaponLowerRequirements = 10; + + magapite.ArmorDurability = 40; + magapite.ArmorLowerRequirements = 10; + CraftAttributeInfo mrusty = MRusty = new CraftAttributeInfo(); + mrusty.WeaponPoisonDamage = 40; + mrusty.WeaponDurability = -50; + mrusty.WeaponLowerRequirements = 30; + mrusty.ArmorDurability = -50; + mrusty.ArmorLowerRequirements = 30; + CraftAttributeInfo mvalorite = MValorite = new CraftAttributeInfo(); + mvalorite.WeaponFireDamage = 15; + mvalorite.WeaponColdDamage = 20; + mvalorite.WeaponPoisonDamage = 10; + mvalorite.WeaponEnergyDamage = 30; + mvalorite.WeaponDurability = 40; + + mvalorite.ArmorPhysicalResist = 3; + mvalorite.ArmorFireResist = 2; + mvalorite.ArmorColdResist = 4; + mvalorite.ArmorEnergyResist = 4; + mvalorite.ArmorDurability = 40; + + CraftAttributeInfo mdragon = MDragon = new CraftAttributeInfo(); + mdragon.WeaponFireDamage = 70; + mdragon.WeaponChaosDamage = 5; + mdragon.ArmorDurability = 50; + + mdragon.ArmorFireResist = 8; + mdragon.ArmorColdResist = -2; + mdragon.ArmorPhysicalResist = 5; + mdragon.ArmorPoisonResist = -2; + mdragon.ArmorGoldIncrease = 40; + mdragon.ArmorDurability = 20; + + CraftAttributeInfo mtitan = MTitan = new CraftAttributeInfo(); + mtitan.WeaponChaosDamage = 40; + mtitan.WeaponDurability = 50; + + mtitan.ArmorPhysicalResist = 6; + mtitan.ArmorFireResist = 5; + mtitan.ArmorPoisonResist = 2; + mtitan.ArmorEnergyResist = 2; + mtitan.ArmorDurability = 50; + + mtitan.WeaponDamage = 20; + + mtitan.WeaponSwingSpeed = -15; + + mtitan.ArmorMage = 1; + + mtitan.ShieldPhysicalResist = 2; + mtitan.ShieldEnergyResist = 2; + + CraftAttributeInfo mcrystaline = MCrystaline = new CraftAttributeInfo(); + mcrystaline.WeaponDurability = -25; + mcrystaline.WeaponLuck = 40; + mcrystaline.WeaponGoldIncrease = 50; + mcrystaline.WeaponLowerRequirements = 20; + + mcrystaline.ArmorPhysicalResist = 2; + mcrystaline.ArmorFireResist = 2; + mcrystaline.ArmorDurability = -25; + mcrystaline.ArmorLuck = 40; + mcrystaline.ArmorGoldIncrease = 45; + mcrystaline.ArmorLowerRequirements = 20; + + CraftAttributeInfo mkrynite = MKrynite = new CraftAttributeInfo(); + mkrynite.WeaponFireDamage = 30; + mkrynite.WeaponColdDamage = 30; + mkrynite.WeaponLowerRequirements = 10; + + mkrynite.ArmorPhysicalResist = 3; + mkrynite.ArmorFireResist = 3; + mkrynite.ArmorColdResist = 3; + mkrynite.ArmorPoisonResist = 2; + mkrynite.ArmorEnergyResist = 4; + mkrynite.ArmorLowerRequirements = 2; + + CraftAttributeInfo mvulcan = MVulcan = new CraftAttributeInfo(); + mvulcan.WeaponFireDamage = 60; + mvulcan.WeaponChaosDamage = 20; + mvulcan.WeaponDamage = 10; + + mvulcan.ArmorPhysicalResist = 3; + mvulcan.ArmorFireResist = 5; + mvulcan.ArmorPoisonResist = 3; + mvulcan.ArmorEnergyResist = 2; + mvulcan.ShieldFireResist = 6; + + CraftAttributeInfo mbloodcrest = MBloodcrest = new CraftAttributeInfo(); + mbloodcrest.WeaponFireDamage = 20; + mbloodcrest.WeaponPoisonDamage = 20; + mbloodcrest.WeaponChaosDamage = 40; + + mbloodcrest.ArmorPhysicalResist = 3; + mbloodcrest.ArmorFireResist = 4; + mbloodcrest.ArmorColdResist = 2; + mbloodcrest.ArmorPoisonResist = 3; + mbloodcrest.ArmorEnergyResist = 2; + + CraftAttributeInfo melvin = MElvin = new CraftAttributeInfo(); + melvin.WeaponFireDamage = 20; + melvin.WeaponColdDamage = 10; + melvin.WeaponPoisonDamage = 30; + melvin.WeaponDurability = 20; + + melvin.ArmorPhysicalResist = 3; + melvin.ArmorFireResist = 4; + melvin.ArmorColdResist = 3; + melvin.ArmorPoisonResist = 1; + melvin.ArmorEnergyResist = 1; + melvin.ArmorDurability = 15; + + CraftAttributeInfo macid = MAcid = new CraftAttributeInfo(); + + macid.WeaponPoisonDamage = 75; + + macid.ArmorFireResist = 3; + macid.ArmorColdResist = 1; + macid.ArmorPoisonResist = 5; + macid.ArmorEnergyResist = 3; + + + + CraftAttributeInfo maqua = MAqua = new CraftAttributeInfo(); + + maqua.WeaponColdDamage = 75; + + maqua.ArmorPhysicalResist = 1; + maqua.ArmorFireResist = 5; + maqua.ArmorColdResist = 3; + maqua.ArmorPoisonResist = 2; + + CraftAttributeInfo meldar = MEldar = new CraftAttributeInfo(); + meldar.WeaponFireDamage = 20; + meldar.WeaponColdDamage = 20; + meldar.WeaponPoisonDamage = 20; + meldar.WeaponEnergyDamage = 40; + meldar.WeaponDurability = -25; + + meldar.ArmorPhysicalResist = -1; + meldar.ArmorPoisonResist = 2; + meldar.ArmorFireResist = 2; + meldar.ArmorColdResist = 2; + meldar.ArmorEnergyResist = 7; + meldar.ArmorDurability = -25; + meldar.ShieldEnergyResist = 4; + CraftAttributeInfo mglowing = MGlowing = new CraftAttributeInfo(); + mglowing.WeaponFireDamage = 40; + mglowing.WeaponEnergyDamage = 40; + mglowing.WeaponLuck = 5; + mglowing.ShieldEnergyResist = 5; + mglowing.ArmorPhysicalResist = 1; + mglowing.ArmorFireResist = 4; + mglowing.ArmorColdResist = 2; + mglowing.ArmorPoisonResist = 2; + mglowing.ArmorEnergyResist = 4; + mglowing.ArmorLuck = 5; + + CraftAttributeInfo mgorgan = MGorgan = new CraftAttributeInfo(); + mgorgan.WeaponPoisonDamage = 40; + mgorgan.WeaponChaosDamage = 60; + mgorgan.WeaponDurability = 40; + mgorgan.WeaponLowerRequirements = -5; + mgorgan.ArmorPhysicalResist = 4; + mgorgan.ArmorFireResist = 2; + mgorgan.ArmorColdResist = 2; + mgorgan.ArmorPoisonResist = 3; + mgorgan.ArmorEnergyResist = 2; + mgorgan.ArmorDurability = 30; + mgorgan.ArmorLowerRequirements = -5; + + CraftAttributeInfo msandrock = MSandrock = new CraftAttributeInfo(); + msandrock.WeaponFireDamage = 30; + msandrock.WeaponPoisonDamage = 10; + msandrock.WeaponGoldIncrease = 15; + msandrock.ArmorPhysicalResist = 1; + msandrock.ArmorFireResist = 3; + msandrock.ArmorPoisonResist = 2; + msandrock.ArmorEnergyResist = 3; + msandrock.ArmorGoldIncrease = 10; + + CraftAttributeInfo msteel = MSteel = new CraftAttributeInfo(); + msteel.WeaponDirectDamage = 60; + msteel.WeaponDurability = 100; + msteel.WeaponLowerRequirements = -40; + msteel.ArmorPhysicalResist = 4; + msteel.ArmorFireResist = 5; + msteel.ArmorColdResist = -1; + msteel.ArmorPoisonResist = 2; + msteel.ArmorEnergyResist = 3; + msteel.ArmorDurability = 80; + msteel.ArmorLowerRequirements = -40; + + + CraftAttributeInfo spined = Spined = new CraftAttributeInfo(); + + spined.ArmorPhysicalResist = 5; + spined.ArmorLuck = 40; + spined.RunicMinAttributes = 1; + spined.RunicMaxAttributes = 3; + if (Core.ML) + { + spined.RunicMinIntensity = 40; + spined.RunicMaxIntensity = 100; + } + else + { + spined.RunicMinIntensity = 20; + spined.RunicMaxIntensity = 40; + } + + CraftAttributeInfo horned = Horned = new CraftAttributeInfo(); + + horned.ArmorPhysicalResist = 2; + horned.ArmorFireResist = 3; + horned.ArmorColdResist = 2; + horned.ArmorPoisonResist = 2; + horned.ArmorEnergyResist = 2; + horned.RunicMinAttributes = 3; + horned.RunicMaxAttributes = 4; + if (Core.ML) + { + horned.RunicMinIntensity = 45; + horned.RunicMaxIntensity = 100; + } + else + { + horned.RunicMinIntensity = 30; + horned.RunicMaxIntensity = 70; + } + + CraftAttributeInfo barbed = Barbed = new CraftAttributeInfo(); + + barbed.ArmorPhysicalResist = 2; + barbed.ArmorFireResist = 1; + barbed.ArmorColdResist = 2; + barbed.ArmorPoisonResist = 3; + barbed.ArmorEnergyResist = 4; + barbed.RunicMinAttributes = 4; + barbed.RunicMaxAttributes = 5; + if (Core.ML) + { + barbed.RunicMinIntensity = 50; + barbed.RunicMaxIntensity = 100; + } + else + { + barbed.RunicMinIntensity = 40; + barbed.RunicMaxIntensity = 100; + } + + //viking : ajout du daemon + CraftAttributeInfo daemon = Daemon = new CraftAttributeInfo(); + + daemon.ArmorPhysicalResist = 3; + daemon.ArmorFireResist = 4; + daemon.ArmorColdResist = 0; + daemon.ArmorPoisonResist = 3; + daemon.ArmorEnergyResist = 4; + daemon.RunicMinAttributes = 3; + daemon.RunicMaxAttributes = 7; + if (Core.ML) + { + daemon.RunicMinIntensity = 50; + daemon.RunicMaxIntensity = 100; + } + else + { + daemon.RunicMinIntensity = 40; + daemon.RunicMaxIntensity = 100; + } + + CraftAttributeInfo red = RedScales = new CraftAttributeInfo(); + + red.ArmorFireResist = 10; + red.ArmorColdResist = -3; + + CraftAttributeInfo yellow = YellowScales = new CraftAttributeInfo(); + + yellow.ArmorPhysicalResist = -3; + yellow.ArmorLuck = 20; + + CraftAttributeInfo black = BlackScales = new CraftAttributeInfo(); + + black.ArmorPhysicalResist = 10; + black.ArmorEnergyResist = -3; + + CraftAttributeInfo green = GreenScales = new CraftAttributeInfo(); + + green.ArmorFireResist = -3; + green.ArmorPoisonResist = 10; + + CraftAttributeInfo white = WhiteScales = new CraftAttributeInfo(); + + white.ArmorPhysicalResist = -3; + white.ArmorColdResist = 10; + + CraftAttributeInfo blue = BlueScales = new CraftAttributeInfo(); + + blue.ArmorPoisonResist = -3; + blue.ArmorEnergyResist = 10; + + //public static readonly CraftAttributeInfo OakWood, AshWood, YewWood, Heartwood, Bloodwood, Frostwood; + + CraftAttributeInfo oak = OakWood = new CraftAttributeInfo(); + oak.ShieldEnergyResist = 4; + oak.ShieldPhysicalResist = 1; + oak.WeaponDamage = 5; + oak.WeaponHitChance = 5; + + CraftAttributeInfo ash = AshWood = new CraftAttributeInfo(); + ash.ShieldPoisonResist = 3; + ash.ShieldEnergyResist = 2; + + ash.WeaponLuck = 40; + ash.WeaponPoisonDamage = 20; + ash.WeaponGoldIncrease = 25; + + CraftAttributeInfo yew = YewWood = new CraftAttributeInfo(); + yew.WeaponHitChance = 10; + yew.WeaponSwingSpeed = 15; + yew.WeaponDamage = -5; + + yew.ShieldFireResist = 2; + yew.ShieldPoisonResist = 2; + yew.ShieldPhysicalResist = 1; + + CraftAttributeInfo heart = Heartwood = new CraftAttributeInfo(); + heart.WeaponFireDamage = 40; + heart.WeaponEnergyDamage = 20; + heart.WeaponLowerRequirements = 15; + + heart.ShieldColdResist = 1; + heart.ShieldEnergyResist = 1; + heart.ShieldFireResist = 2; + heart.ShieldPoisonResist = 1; + heart.ShieldPhysicalResist = 2; + + + CraftAttributeInfo blood = Bloodwood = new CraftAttributeInfo(); + blood.WeaponHitLifeLeech = 10; + blood.WeaponRegenHits = 1; + blood.WeaponLowerRequirements = -15; + + blood.ShieldPoisonResist = 3; + blood.ShieldFireResist = 3; + + CraftAttributeInfo frost = Frostwood = new CraftAttributeInfo(); + frost.WeaponColdDamage = 75; + frost.WeaponSwingSpeed = -5; + frost.WeaponDamage = 10; + frost.WeaponHitChance = 5; + + frost.ShieldColdResist = 4; + frost.ShieldFireResist = -1; + frost.ShieldEnergyResist = -1; + frost.ShieldPhysicalResist = 3; + frost.ShieldPoisonResist = 2; + } + } + + public class CraftResourceInfo + { + private int m_Hue; + private int m_Number; + private string m_Name; + private CraftAttributeInfo m_AttributeInfo; + private CraftResource m_Resource; + private Type[] m_ResourceTypes; + + public int Hue { get { return m_Hue; } set { m_Hue = value; } } + public int Number { get { return m_Number; } } + public string Name { get { return m_Name; } } + public CraftAttributeInfo AttributeInfo { get { return m_AttributeInfo; } } + public CraftResource Resource { get { return m_Resource; } } + public Type[] ResourceTypes { get { return m_ResourceTypes; } } + + public CraftResourceInfo(int hue, int number, string name, CraftAttributeInfo attributeInfo, CraftResource resource, params Type[] resourceTypes) + { + m_Hue = hue; + m_Number = number; + m_Name = name; + m_AttributeInfo = attributeInfo; + m_Resource = resource; + m_ResourceTypes = resourceTypes; + + for (int i = 0; i < resourceTypes.Length; ++i) + CraftResources.RegisterType(resourceTypes[i], resource); + } + } + + public class CraftResources + { + private static CraftResourceInfo[] m_MetalInfo = new CraftResourceInfo[] + { + new CraftResourceInfo( 0x000, 0, "Fer", CraftAttributeInfo.MIron, CraftResource.MIron, typeof( IronIngot ), typeof( IronOre ), typeof( Granite ) ), + new CraftResourceInfo( 0x6D6, 0, "Bronze", CraftAttributeInfo.MBronze, CraftResource.MBronze, typeof( BronzeIngot ), typeof( BronzeOre ), typeof( BronzeGranite ) ), + new CraftResourceInfo( 0x45E, 0, "Or", CraftAttributeInfo.MGold, CraftResource.MGold, typeof( GoldIngot ), typeof( GoldOre ), typeof( GoldGranite ) ), + new CraftResourceInfo( 0x641, 0, "Cuivre", CraftAttributeInfo.MCopper, CraftResource.MCopper, typeof( CopperIngot ), typeof( CopperOre ), typeof( CopperGranite ) ), + new CraftResourceInfo( 0x590, 0, "Vieux cuivre", CraftAttributeInfo.MOldcopper, CraftResource.MOldcopper, typeof( OldcopperIngot ), typeof( OldcopperOre ), typeof( OldcopperGranite ) ), + new CraftResourceInfo( 0x60A, 0, "Cuivre terni", CraftAttributeInfo.MDullcopper, CraftResource.MDullcopper, typeof( DullcopperIngot ), typeof( DullcopperOre ), typeof( DullcopperGranite ) ), + new CraftResourceInfo( 0x231, 0, "Argent", CraftAttributeInfo.MSilver, CraftResource.MSilver, typeof( SilverIngot ), typeof( SilverOre ), typeof( SilverGranite ) ), + new CraftResourceInfo( 0x770, 0, "Sombrine", CraftAttributeInfo.MShadow, CraftResource.MShadow, typeof( ShadowIngot ), typeof( ShadowOre ), typeof( ShadowGranite ) ), + new CraftResourceInfo( 0x4C2, 0, "Pierre de sang", CraftAttributeInfo.MBloodrock, CraftResource.MBloodrock, typeof( BloodrockIngot ), typeof( BloodrockOre ), typeof( BloodrockGranite ) ), + new CraftResourceInfo( 0x455, 0, "Pierre noire", CraftAttributeInfo.MBlackrock, CraftResource.MBlackrock, typeof( BlackrockIngot ), typeof( BlackrockOre ), typeof( BlackrockGranite ) ), + new CraftResourceInfo( 0x52D, 0, "Mytheril", CraftAttributeInfo.MMytheril, CraftResource.MMytheril, typeof( MytherilIngot ), typeof( MytherilOre ), typeof( MytherilGranite ) ), + new CraftResourceInfo( 0x665, 0, "Rose", CraftAttributeInfo.MRose, CraftResource.MRose, typeof( RoseIngot ), typeof( RoseOre ), typeof( RoseGranite ) ), + new CraftResourceInfo( 0x7D1, 0, "Verite", CraftAttributeInfo.MVerite, CraftResource.MVerite, typeof( VeriteIngot ), typeof( VeriteOre ), typeof( VeriteGranite ) ), + new CraftResourceInfo( 0x400, 0, "Agapite", CraftAttributeInfo.MAgapite, CraftResource.MAgapite, typeof( AgapiteIngot ), typeof( AgapiteOre ), typeof( AgapiteGranite ) ), + new CraftResourceInfo( 0x750, 0, "Rouille", CraftAttributeInfo.MRusty, CraftResource.MRusty, typeof( RustyIngot ), typeof( RustyOre ), typeof( RustyGranite ) ), + new CraftResourceInfo( 0x515, 0, "Valorite", CraftAttributeInfo.MValorite, CraftResource.MValorite, typeof( ValoriteIngot ), typeof( ValoriteOre ), typeof( ValoriteGranite ) ), + new CraftResourceInfo( 0x66A, 0, "Dragon", CraftAttributeInfo.MDragon, CraftResource.MDragon, typeof( DragonIngot ), typeof( DragonOre ), typeof( DragonGranite ) ), + new CraftResourceInfo( 0x8A5, 0, "Titan", CraftAttributeInfo.MTitan, CraftResource.MTitan, typeof( TitanIngot ), typeof( TitanOre ), typeof( TitanGranite ) ), + new CraftResourceInfo( 0x4D5, 0, "Crystaline", CraftAttributeInfo.MCrystaline, CraftResource.MCrystaline, typeof( CrystalineIngot ), typeof( CrystalineOre ), typeof( CrystalineGranite ) ), + new CraftResourceInfo( 0x9C/*0x84E*/, 0, "Krynite", CraftAttributeInfo.MKrynite, CraftResource.MKrynite, typeof( KryniteIngot ), typeof( KryniteOre ), typeof( KryniteGranite ) ), + new CraftResourceInfo( 0x4E9/*0x977*/, 0, "Vulcan", CraftAttributeInfo.MVulcan, CraftResource.MVulcan, typeof( VulcanIngot ), typeof( VulcanOre ), typeof( VulcanGranite ) ), + new CraftResourceInfo( 0x846, 0, "Craie de sang", CraftAttributeInfo.MBloodcrest, CraftResource.MBloodcrest, typeof( BloodcrestIngot ), typeof( BloodcrestOre ), typeof( BloodcrestGranite ) ), + new CraftResourceInfo( 0x8A4, 0, "Elvin", CraftAttributeInfo.MElvin, CraftResource.MElvin, typeof( ElvinIngot ), typeof( ElvinOre ), typeof( ElvinGranite ) ), + new CraftResourceInfo( 0x84F, 0, "Acid", CraftAttributeInfo.MAcid, CraftResource.MAcid, typeof( AcidIngot ), typeof( AcidOre ), typeof( AcidGranite ) ), + new CraftResourceInfo( 0x48D, 0, "Aqua", CraftAttributeInfo.MAqua, CraftResource.MAqua, typeof( AquaIngot ), typeof( AquaOre ), typeof( AquaGranite ) ), + new CraftResourceInfo( 0x4DD, 0, "Eldar", CraftAttributeInfo.MEldar, CraftResource.MEldar, typeof( EldarIngot ), typeof( EldarOre ), typeof( EldarGranite ) ), + new CraftResourceInfo( 0x482, 0, "Glowing", CraftAttributeInfo.MGlowing, CraftResource.MGlowing, typeof( GlowingIngot ), typeof( GlowingOre ), typeof( GlowingGranite ) ), + new CraftResourceInfo( 0x844, 0, "Gorgan", CraftAttributeInfo.MGorgan, CraftResource.MGorgan, typeof( GorganIngot ), typeof( GorganOre ), typeof( GorganGranite ) ), + new CraftResourceInfo( 0x92/*0x8F*/, 0, "Pierre de sable", CraftAttributeInfo.MSandrock, CraftResource.MSandrock, typeof( SandrockIngot ), typeof( SandrockOre ), typeof( SandrockGranite ) ), + new CraftResourceInfo( 0x977/*0x100*/, 0, "Acier", CraftAttributeInfo.MSteel, CraftResource.MSteel, typeof( SteelIngot ), typeof( SteelOre ), typeof( SteelGranite ) ), + + }; + + private static CraftResourceInfo[] m_ScaleInfo = new CraftResourceInfo[] + { + new CraftResourceInfo( 0x66D, 1053129, "Red Scales", CraftAttributeInfo.RedScales, CraftResource.RedScales, typeof( RedScales ) ), + new CraftResourceInfo( 0x8A8, 1053130, "Yellow Scales", CraftAttributeInfo.YellowScales, CraftResource.YellowScales, typeof( YellowScales ) ), + new CraftResourceInfo( 0x455, 1053131, "Black Scales", CraftAttributeInfo.BlackScales, CraftResource.BlackScales, typeof( BlackScales ) ), + new CraftResourceInfo( 0x851, 1053132, "Green Scales", CraftAttributeInfo.GreenScales, CraftResource.GreenScales, typeof( GreenScales ) ), + new CraftResourceInfo( 0x8FD, 1053133, "White Scales", CraftAttributeInfo.WhiteScales, CraftResource.WhiteScales, typeof( WhiteScales ) ), + new CraftResourceInfo( 0x8B0, 1053134, "Blue Scales", CraftAttributeInfo.BlueScales, CraftResource.BlueScales, typeof( BlueScales ) ) + }; + + private static CraftResourceInfo[] m_LeatherInfo = new CraftResourceInfo[] + { + new CraftResourceInfo( 0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof( Leather ), typeof( Hides ) ), + new CraftResourceInfo( 0x283, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof( SpinedLeather ), typeof( SpinedHides ) ), + new CraftResourceInfo( 0x227, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof( HornedLeather ), typeof( HornedHides ) ), + new CraftResourceInfo( 0x1C1, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof( BarbedLeather ), typeof( BarbedHides ) ), + new CraftResourceInfo( 0x25, 0, "Daemon", CraftAttributeInfo.Daemon, CraftResource.DaemonLeather, typeof( DaemonLeather ), typeof( DaemonHides ) ) + }; + + private static CraftResourceInfo[] m_AOSLeatherInfo = new CraftResourceInfo[] + { + new CraftResourceInfo( 0x000, 1049353, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularLeather, typeof( Leather ), typeof( Hides ) ), + new CraftResourceInfo( 0x8AC, 1049354, "Spined", CraftAttributeInfo.Spined, CraftResource.SpinedLeather, typeof( SpinedLeather ), typeof( SpinedHides ) ), + new CraftResourceInfo( 0x845, 1049355, "Horned", CraftAttributeInfo.Horned, CraftResource.HornedLeather, typeof( HornedLeather ), typeof( HornedHides ) ), + new CraftResourceInfo( 0x851, 1049356, "Barbed", CraftAttributeInfo.Barbed, CraftResource.BarbedLeather, typeof( BarbedLeather ), typeof( BarbedHides ) ), + new CraftResourceInfo( 0x25, 0, "Daemon", CraftAttributeInfo.Daemon, CraftResource.DaemonLeather, typeof( DaemonLeather ), typeof( DaemonHides ) ) + }; + + private static CraftResourceInfo[] m_WoodInfo = new CraftResourceInfo[] + { + new CraftResourceInfo( 0x000, 1011542, "Normal", CraftAttributeInfo.Blank, CraftResource.RegularWood, typeof( Log ), typeof( Board ) ), + new CraftResourceInfo( 0x7DA, 1072533, "Oak", CraftAttributeInfo.OakWood, CraftResource.OakWood, typeof( OakLog ), typeof( OakBoard ) ), + new CraftResourceInfo( 0x4A7, 1072534, "Ash", CraftAttributeInfo.AshWood, CraftResource.AshWood, typeof( AshLog ), typeof( AshBoard ) ), + new CraftResourceInfo( 0x4A8, 1072535, "Yew", CraftAttributeInfo.YewWood, CraftResource.YewWood, typeof( YewLog ), typeof( YewBoard ) ), + new CraftResourceInfo( 0x4A9, 1072536, "Heartwood", CraftAttributeInfo.Heartwood, CraftResource.Heartwood, typeof( HeartwoodLog ), typeof( HeartwoodBoard ) ), + new CraftResourceInfo( 0x4AA, 1072538, "Bloodwood", CraftAttributeInfo.Bloodwood, CraftResource.Bloodwood, typeof( BloodwoodLog ), typeof( BloodwoodBoard ) ), + new CraftResourceInfo( 0x47F, 1072539, "Frostwood", CraftAttributeInfo.Frostwood, CraftResource.Frostwood, typeof( FrostwoodLog ), typeof( FrostwoodBoard ) ) + }; + + /// + /// Returns true if '' is None, Iron, RegularLeather or RegularWood. False if otherwise. + /// + public static bool IsStandard(CraftResource resource) + { + return (resource == CraftResource.None || resource == CraftResource.MIron || resource == CraftResource.RegularLeather || resource == CraftResource.RegularWood); + } + + private static Hashtable m_TypeTable; + + /// + /// Registers that '' uses '' so that it can later be queried by + /// + public static void RegisterType(Type resourceType, CraftResource resource) + { + if (m_TypeTable == null) + m_TypeTable = new Hashtable(); + + m_TypeTable[resourceType] = resource; + } + + /// + /// Returns the value for which '' uses -or- CraftResource.None if an unregistered type was specified. + /// + public static CraftResource GetFromType(Type resourceType) + { + if (m_TypeTable == null) + return CraftResource.None; + + object obj = m_TypeTable[resourceType]; + + if (!(obj is CraftResource)) + return CraftResource.None; + + return (CraftResource)obj; + } + + /// + /// Returns a instance describing '' -or- null if an invalid resource was specified. + /// + public static CraftResourceInfo GetInfo(CraftResource resource) + { + CraftResourceInfo[] list = null; + + switch (GetType(resource)) + { + case CraftResourceType.Metal: list = m_MetalInfo; break; + case CraftResourceType.Leather: list = Core.AOS ? m_AOSLeatherInfo : m_LeatherInfo; break; + case CraftResourceType.Scales: list = m_ScaleInfo; break; + case CraftResourceType.Wood: list = m_WoodInfo; break; + } + + if (list != null) + { + int index = GetIndex(resource); + + if (index >= 0 && index < list.Length) + return list[index]; + } + + return null; + } + + /// + /// Returns a value indiciating the type of ''. + /// + public static CraftResourceType GetType(CraftResource resource) + { + if (resource >= CraftResource.MIron && resource <= CraftResource.MSteel) + return CraftResourceType.Metal; + + if (resource >= CraftResource.RegularLeather && resource <= CraftResource.DaemonLeather) + return CraftResourceType.Leather; + + if (resource >= CraftResource.RedScales && resource <= CraftResource.BlueScales) + return CraftResourceType.Scales; + + if (resource >= CraftResource.RegularWood && resource <= CraftResource.Frostwood) + return CraftResourceType.Wood; + + return CraftResourceType.None; + } + + /// + /// Returns the first in the series of resources for which '' belongs. + /// + public static CraftResource GetStart(CraftResource resource) + { + switch (GetType(resource)) + { + case CraftResourceType.Metal: return CraftResource.MIron; + case CraftResourceType.Leather: return CraftResource.RegularLeather; + case CraftResourceType.Scales: return CraftResource.RedScales; + case CraftResourceType.Wood: return CraftResource.RegularWood; + } + + return CraftResource.None; + } + + /// + /// Returns the index of '' in the seriest of resources for which it belongs. + /// + public static int GetIndex(CraftResource resource) + { + CraftResource start = GetStart(resource); + + if (start == CraftResource.None) + return 0; + + return (int)(resource - start); + } + + /// + /// Returns the property of '' -or- 0 if an invalid resource was specified. + /// + public static int GetLocalizationNumber(CraftResource resource) + { + CraftResourceInfo info = GetInfo(resource); + + return (info == null ? 0 : info.Number); + } + + /// + /// Returns the property of '' -or- 0 if an invalid resource was specified. + /// + public static int GetHue(CraftResource resource) + { + CraftResourceInfo info = GetInfo(resource); + + return (info == null ? 0 : info.Hue); + } + + /// + /// Returns the property of '' -or- an empty string if the resource specified was invalid. + /// + public static string GetName(CraftResource resource) + { + CraftResourceInfo info = GetInfo(resource); + + return (info == null ? String.Empty : info.Name); + } + + /// + /// Returns the value which represents '' -or- CraftResource.None if unable to convert. + /// + public static CraftResource GetFromOreInfo(OreInfo info) + { + if (info.Name.IndexOf("Spined") >= 0) + return CraftResource.SpinedLeather; + else if (info.Name.IndexOf("Horned") >= 0) + return CraftResource.HornedLeather; + else if (info.Name.IndexOf("Barbed") >= 0) + return CraftResource.BarbedLeather; + else if (info.Name.IndexOf("Leather") >= 0) + return CraftResource.RegularLeather; + else if (info.Name.IndexOf("Daemon") >= 0) + return CraftResource.DaemonLeather; + + if (info.Level == 0) + return CraftResource.MIron; + else if (info.Level == 1) + return CraftResource.MBronze; + else if (info.Level == 2) + return CraftResource.MGold; + else if (info.Level == 3) + return CraftResource.MCopper; + else if (info.Level == 4) + return CraftResource.MOldcopper; + else if (info.Level == 5) + return CraftResource.MDullcopper; + else if (info.Level == 6) + return CraftResource.MSilver; + else if (info.Level == 7) + return CraftResource.MShadow; + else if (info.Level == 8) + return CraftResource.MBloodrock; + else if (info.Level == 9) + return CraftResource.MBlackrock; + else if (info.Level == 10) + return CraftResource.MMytheril; + else if (info.Level == 11) + return CraftResource.MRose; + else if (info.Level == 12) + return CraftResource.MVerite; + else if (info.Level == 13) + return CraftResource.MAgapite; + else if (info.Level == 14) + return CraftResource.MRusty; + else if (info.Level == 15) + return CraftResource.MValorite; + else if (info.Level == 16) + return CraftResource.MDragon; + else if (info.Level == 17) + return CraftResource.MTitan; + else if (info.Level == 18) + return CraftResource.MCrystaline; + else if (info.Level == 19) + return CraftResource.MKrynite; + else if (info.Level == 20) + return CraftResource.MVulcan; + else if (info.Level == 21) + return CraftResource.MBloodcrest; + else if (info.Level == 22) + return CraftResource.MElvin; + else if (info.Level == 23) + return CraftResource.MAcid; + else if (info.Level == 24) + return CraftResource.MAqua; + else if (info.Level == 25) + return CraftResource.MEldar; + else if (info.Level == 26) + return CraftResource.MGlowing; + else if (info.Level == 27) + return CraftResource.MGorgan; + else if (info.Level == 28) + return CraftResource.MSandrock; + else if (info.Level == 29) + return CraftResource.MSteel; + + return CraftResource.None; + } + + /// + /// Returns the value which represents '', using '' to help resolve leather OreInfo instances. + /// + public static CraftResource GetFromOreInfo(OreInfo info, ArmorMaterialType material) + { + if (material == ArmorMaterialType.Studded || material == ArmorMaterialType.Leather || material == ArmorMaterialType.Spined || + material == ArmorMaterialType.Horned || material == ArmorMaterialType.Barbed || material == ArmorMaterialType.Daemon) + { + if (info.Level == 0) + return CraftResource.RegularLeather; + else if (info.Level == 1) + return CraftResource.SpinedLeather; + else if (info.Level == 2) + return CraftResource.HornedLeather; + else if (info.Level == 3) + return CraftResource.BarbedLeather; + else if (info.Level == 4) + return CraftResource.DaemonLeather; + + return CraftResource.None; + } + + return GetFromOreInfo(info); + } + } + + // NOTE: This class is only for compatability with very old RunUO versions. + // No changes to it should be required for custom resources. + public class OreInfo + { + public static readonly OreInfo MIron = new OreInfo(0, 0x000, "Fer"); + public static readonly OreInfo MBronze = new OreInfo(1, 0x973, "Bronze"); + public static readonly OreInfo MGold = new OreInfo(2, 0x966, "Or"); + public static readonly OreInfo MCopper = new OreInfo(3, 0x96D, "Cuivre"); + public static readonly OreInfo MOldcopper = new OreInfo(4, 0x972, "Vieux cuivre"); + public static readonly OreInfo MDullcopper = new OreInfo(5, 0x8A5, "Cuivre terni"); + public static readonly OreInfo MSilver = new OreInfo(6, 0x979, "Argent"); + public static readonly OreInfo MShadow = new OreInfo(7, 0x89F, "Sombrine"); + public static readonly OreInfo MBloodrock = new OreInfo(8, 0x8AB, "Pierre de sang"); + public static readonly OreInfo MBlackrock = new OreInfo(9, 0x000, "Pierre noire"); + public static readonly OreInfo MMytheril = new OreInfo(10, 0x973, "Mytheril"); + public static readonly OreInfo MRose = new OreInfo(11, 0x966, "Rose"); + public static readonly OreInfo MVerite = new OreInfo(12, 0x96D, "Verite"); + public static readonly OreInfo MAgapite = new OreInfo(13, 0x972, "Agapite"); + public static readonly OreInfo MRusty = new OreInfo(14, 0x8A5, "Rouille"); + public static readonly OreInfo MValorite = new OreInfo(15, 0x979, "Valorite"); + public static readonly OreInfo MDragon = new OreInfo(16, 0x89F, "Dragon"); + public static readonly OreInfo MTitan = new OreInfo(17, 0x8AB, "Titan"); + public static readonly OreInfo MCrystaline = new OreInfo(18, 0x000, "Crystaline"); + public static readonly OreInfo MKrynite = new OreInfo(19, 0x973, "Krynite"); + public static readonly OreInfo MVulcan = new OreInfo(20, 0x966, "Vulcan"); + public static readonly OreInfo MBloodcrest = new OreInfo(21, 0x96D, "Craie de sang"); + public static readonly OreInfo MElvin = new OreInfo(22, 0x972, "Elvin"); + public static readonly OreInfo MAcid = new OreInfo(23, 0x8A5, "Acid"); + public static readonly OreInfo MAqua = new OreInfo(24, 0x979, "Aqua"); + public static readonly OreInfo MEldar = new OreInfo(25, 0x89F, "Eldar"); + public static readonly OreInfo MGlowing = new OreInfo(26, 0x8AB, "Glowing"); + public static readonly OreInfo MGorgan = new OreInfo(27, 0x979, "Gorgan"); + public static readonly OreInfo MSandrock = new OreInfo(28, 0x89F, "Pierre de sable"); + public static readonly OreInfo MSteel = new OreInfo(29, 0x8AB, "Acier"); + + private int m_Level; + private int m_Hue; + private string m_Name; + + public OreInfo(int level, int hue, string name) + { + m_Level = level; + m_Hue = hue; + m_Name = name; + } + + public int Level + { + get + { + return m_Level; + } + } + + public int Hue + { + get + { + return m_Hue; + } + } + + public string Name + { + get + { + return m_Name; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ServerList.cs b/Scripts/Misc/ServerList.cs new file mode 100644 index 0000000..7ce5286 --- /dev/null +++ b/Scripts/Misc/ServerList.cs @@ -0,0 +1,195 @@ +using System; +using System.IO; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using Server; +using Server.Network; + +namespace Server.Misc +{ + public class ServerList + { + /* + * The default setting for Address, a value of 'null', will use your local IP address. If all of your local IP addresses + * are private network addresses and AutoDetect is 'true' then RunUO will attempt to discover your public IP address + * for you automatically. + * + * If you do not plan on allowing clients outside of your LAN to connect, you can set AutoDetect to 'false' and leave + * Address set to 'null'. + * + * If your public IP address cannot be determined, you must change the value of Address to your public IP address + * manually to allow clients outside of your LAN to connect to your server. Address can be either an IP address or + * a hostname that will be resolved when RunUO starts. + * + * If you want players outside your LAN to be able to connect to your server and you are behind a router, you must also + * forward TCP port 2593 to your private IP address. The procedure for doing this varies by manufacturer but generally + * involves configuration of the router through your web browser. + * + * ServerList will direct connecting clients depending on both the address they are connecting from and the address and + * port they are connecting to. If it is determined that both ends of a connection are private IP addresses, ServerList + * will direct the client to the local private IP address. If a client is connecting to a local public IP address, they + * will be directed to whichever address and port they initially connected to. This allows multihomed servers to function + * properly and fully supports listening on multiple ports. If a client with a public IP address is connecting to a + * locally private address, the server will direct the client to either the AutoDetected IP address or the manually entered + * IP address or hostname, whichever is applicable. Loopback clients will be directed to loopback. + * + * If you would like to listen on additional ports (i.e. 22, 23, 80, for clients behind highly restrictive egress + * firewalls) or specific IP adddresses you can do so by modifying the file SocketOptions.cs found in this directory. + */ + + public static readonly string Address = "runuo.vivre-uo.fr"; + public static readonly string ServerName = "Vivre"; + + public static readonly bool AutoDetect = true; + + public static void Initialize() + { + if ( Address == null ) { + if ( AutoDetect ) + AutoDetection(); + } + else { + Resolve( Address, out m_PublicAddress ); + } + + EventSink.ServerList += new ServerListEventHandler( EventSink_ServerList ); + } + + private static IPAddress m_PublicAddress; + + private static void EventSink_ServerList( ServerListEventArgs e ) + { + try + { + NetState ns = e.State; + Socket s = ns.Socket; + + IPEndPoint ipep = (IPEndPoint)s.LocalEndPoint; + + IPAddress localAddress = ipep.Address; + int localPort = ipep.Port; + + if ( IsPrivateNetwork( localAddress ) ) { + ipep = (IPEndPoint)s.RemoteEndPoint; + if ( !IsPrivateNetwork( ipep.Address ) && m_PublicAddress != null ) + localAddress = m_PublicAddress; + } + + e.AddServer( ServerName, new IPEndPoint( localAddress, localPort ) ); + } + catch + { + e.Rejected = true; + } + } + + private static void AutoDetection() + { + if ( !HasPublicIPAddress() ) { + Console.Write( "ServerList: Auto-detecting public IP address..." ); + m_PublicAddress = FindPublicAddress(); + + if ( m_PublicAddress != null ) + Console.WriteLine( "done ({0})", m_PublicAddress.ToString() ); + else + Console.WriteLine( "failed" ); + } + } + + private static void Resolve( string addr, out IPAddress outValue ) + { + if ( IPAddress.TryParse( addr, out outValue ) ) + return; + + try { + IPHostEntry iphe = Dns.GetHostEntry( addr ); + + if ( iphe.AddressList.Length > 0 ) + outValue = iphe.AddressList[iphe.AddressList.Length - 1]; + } + catch { + } + } + + private static bool HasPublicIPAddress() + { + NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); + + foreach ( NetworkInterface adapter in adapters ) { + IPInterfaceProperties properties = adapter.GetIPProperties(); + + foreach ( IPAddressInformation unicast in properties.UnicastAddresses ) { + IPAddress ip = unicast.Address; + + if ( !IPAddress.IsLoopback( ip ) && ip.AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork( ip ) ) + return true; + } + } + + return false; + + + /* + IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() ); + + IPAddress[] ips = iphe.AddressList; + + for ( int i = 0; i < ips.Length; ++i ) + { + if ( ips[i].AddressFamily != AddressFamily.InterNetworkV6 && !IsPrivateNetwork( ips[i] ) ) + return true; + } + + return false; + */ + } + + private static bool IsPrivateNetwork( IPAddress ip ) + { + // 10.0.0.0/8 + // 172.16.0.0/12 + // 192.168.0.0/16 + + if ( ip.AddressFamily == AddressFamily.InterNetworkV6 ) + return false; + + // Scriptiz : Fix for Windows Azure VM's Internal IP Address + if (Utility.IPMatch("100.90.*", ip)) + return true; + + if ( Utility.IPMatch( "192.168.*", ip ) ) + return true; + else if ( Utility.IPMatch( "10.*", ip ) ) + return true; + else if ( Utility.IPMatch( "172.16-31.*", ip ) ) + return true; + else + return false; + } + + public static IPAddress FindPublicAddress() + { + try { + WebRequest req = HttpWebRequest.Create( "http://www.runuo.com/ip.php" ); + req.Timeout = 15000; + + WebResponse res = req.GetResponse(); + + Stream s = res.GetResponseStream(); + + StreamReader sr = new StreamReader( s ); + + IPAddress ip = IPAddress.Parse( sr.ReadLine() ); + + sr.Close(); + s.Close(); + res.Close(); + + return ip; + } catch { + return null; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ShardPoller.cs b/Scripts/Misc/ShardPoller.cs new file mode 100644 index 0000000..659f4f4 --- /dev/null +++ b/Scripts/Misc/ShardPoller.cs @@ -0,0 +1,643 @@ +using System; +using System.Net; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Prompts; + +namespace Server.Misc +{ + public class ShardPoller : Item + { + private string m_Title; + + private ShardPollOption[] m_Options; + private IPAddress[] m_Addresses; + + private TimeSpan m_Duration; + private DateTime m_StartTime; + + private bool m_Active; + + public ShardPollOption[] Options + { + get{ return m_Options; } + set{ m_Options = value; } + } + + public IPAddress[] Addresses + { + get{ return m_Addresses; } + set{ m_Addresses = value; } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public string Title + { + get{ return m_Title; } + set{ m_Title = ShardPollPrompt.UrlToHref( value ); } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public TimeSpan Duration + { + get{ return m_Duration; } + set{ m_Duration = value; } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public DateTime StartTime + { + get{ return m_StartTime; } + set{ m_StartTime = value; } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public TimeSpan TimeRemaining + { + get + { + if ( m_StartTime == DateTime.MinValue || !m_Active ) + return TimeSpan.Zero; + + try + { + TimeSpan ts = (m_StartTime + m_Duration) - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + return TimeSpan.Zero; + + return ts; + } + catch + { + return TimeSpan.Zero; + } + } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public bool Active + { + get{ return m_Active; } + set + { + if ( m_Active == value ) + return; + + m_Active = value; + + if ( m_Active ) + { + m_StartTime = DateTime.Now; + m_ActivePollers.Add( this ); + } + else + { + m_ActivePollers.Remove( this ); + } + } + } + + public bool HasAlreadyVoted( NetState ns ) + { + for ( int i = 0; i < m_Options.Length; ++i ) + { + if ( m_Options[i].HasAlreadyVoted( ns ) ) + return true; + } + + return false; + } + + public void AddVote( NetState ns, ShardPollOption option ) + { + option.AddVote( ns ); + } + + public void RemoveOption( ShardPollOption option ) + { + int index = Array.IndexOf( m_Options, option ); + + if ( index < 0 ) + return; + + ShardPollOption[] old = m_Options; + m_Options = new ShardPollOption[old.Length - 1]; + + for ( int i = 0; i < index; ++i ) + m_Options[i] = old[i]; + + for ( int i = index; i < m_Options.Length; ++i ) + m_Options[i] = old[i + 1]; + } + + public void AddOption( ShardPollOption option ) + { + ShardPollOption[] old = m_Options; + m_Options = new ShardPollOption[old.Length + 1]; + + for ( int i = 0; i < old.Length; ++i ) + m_Options[i] = old[i]; + + m_Options[old.Length] = option; + } + + public override string DefaultName + { + get { return "shard poller"; } + } + + [Constructable( AccessLevel.Administrator )] + public ShardPoller() : base( 0x1047 ) + { + m_Duration = TimeSpan.FromHours( 24.0 ); + m_Options = new ShardPollOption[0]; + m_Addresses = new IPAddress[0]; + + Movable = false; + } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static List m_ActivePollers = new List(); + + private static void EventSink_Login( LoginEventArgs e ) + { + if ( m_ActivePollers.Count == 0 ) + return; + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( EventSink_Login_Callback ), e.Mobile ); + } + + private static void EventSink_Login_Callback( object state ) + { + Mobile from = (Mobile)state; + NetState ns = from.NetState; + + if ( ns == null ) + return; + + ShardPollGump spg = null; + + for ( int i = 0; i < m_ActivePollers.Count; ++i ) + { + ShardPoller poller = m_ActivePollers[i]; + + if ( poller.Deleted || !poller.Active ) + continue; + + if ( poller.TimeRemaining > TimeSpan.Zero ) + { + if ( poller.HasAlreadyVoted( ns ) ) + continue; + + if ( spg == null ) + { + spg = new ShardPollGump( from, poller, false, null ); + from.SendGump( spg ); + } + else + { + spg.QueuePoll( poller ); + } + } + else + { + poller.Active = false; + } + } + } + + public void SendQueuedPoll_Callback( object state ) + { + object[] states = (object[])state; + Mobile from = (Mobile)states[0]; + Queue queue = (Queue)states[1]; + + from.SendGump( new ShardPollGump( from, this, false, queue ) ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.Administrator ) + from.SendGump( new ShardPollGump( from, this, true, null ) ); + } + + public ShardPoller( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Title ); + writer.Write( m_Duration ); + writer.Write( m_StartTime ); + writer.Write( m_Active ); + + writer.Write( m_Options.Length ); + + for ( int i = 0; i < m_Options.Length; ++i ) + m_Options[i].Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Title = reader.ReadString(); + m_Duration = reader.ReadTimeSpan(); + m_StartTime = reader.ReadDateTime(); + m_Active = reader.ReadBool(); + + m_Options = new ShardPollOption[reader.ReadInt()]; + + for ( int i = 0; i < m_Options.Length; ++i ) + m_Options[i] = new ShardPollOption( reader ); + + if ( m_Active ) + m_ActivePollers.Add( this ); + + break; + } + } + } + + public override void OnDelete() + { + base.OnDelete(); + + Active = false; + } + } + + public class ShardPollOption + { + private string m_Title; + private int m_LineBreaks; + private IPAddress[] m_Voters; + + public string Title{ get{ return m_Title; } set{ m_Title = value; m_LineBreaks = GetBreaks( m_Title ); } } + public int LineBreaks{ get{ return m_LineBreaks; } } + + public int Votes{ get{ return m_Voters.Length; } } + public IPAddress[] Voters{ get{ return m_Voters; } set{ m_Voters = value; } } + + public ShardPollOption( string title ) + { + m_Title = title; + m_LineBreaks = GetBreaks( m_Title ); + m_Voters = new IPAddress[0]; + } + + public bool HasAlreadyVoted( NetState ns ) + { + if ( ns == null ) + return false; + + IPAddress ipAddress = ns.Address; + + for ( int i = 0; i < m_Voters.Length; ++i ) + { + if ( Utility.IPMatchClassC( m_Voters[i], ipAddress ) ) + return true; + } + + return false; + } + + public void AddVote( NetState ns ) + { + if ( ns == null ) + return; + + IPAddress[] old = m_Voters; + m_Voters = new IPAddress[old.Length + 1]; + + for ( int i = 0; i < old.Length; ++i ) + m_Voters[i] = old[i]; + + m_Voters[old.Length] = ns.Address; + } + + public int ComputeHeight() + { + int height = m_LineBreaks * 18; + + if ( height > 30 ) + return height; + + return 30; + } + + public int GetBreaks( string title ) + { + if ( title == null ) + return 1; + + int count = 0; + int index = -1; + + do + { + ++count; + index = title.IndexOf( "
", index + 1 ); + } while ( index >= 0 ); + + return count; + } + + public ShardPollOption( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Title = reader.ReadString(); + m_LineBreaks = GetBreaks( m_Title ); + + m_Voters = new IPAddress[reader.ReadInt()]; + + for ( int i = 0; i < m_Voters.Length; ++i ) + m_Voters[i] = Utility.Intern( reader.ReadIPAddress() ); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (int) 0 ); // version + + writer.Write( m_Title ); + + writer.Write( m_Voters.Length ); + + for ( int i = 0; i < m_Voters.Length; ++i ) + writer.Write( m_Voters[i] ); + } + } + + public class ShardPollGump : Gump + { + private Mobile m_From; + private ShardPoller m_Poller; + private bool m_Editing; + private Queue m_Polls; + + public bool Editing{ get{ return m_Editing; } } + + public void QueuePoll( ShardPoller poller ) + { + if ( m_Polls == null ) + m_Polls = new Queue( 4 ); + + m_Polls.Enqueue( poller ); + } + + public string Center( string text ) + { + return String.Format( "
{0}
", text ); + } + + public string Color( string text, int color ) + { + return String.Format( "{1}", color, text ); + } + + private const int LabelColor32 = 0xFFFFFF; + + public ShardPollGump( Mobile from, ShardPoller poller, bool editing, Queue polls ) : base( 50, 50 ) + { + m_From = from; + m_Poller = poller; + m_Editing = editing; + m_Polls = polls; + + Closable = false; + + AddPage( 0 ); + + int totalVotes = 0; + int totalOptionHeight = 0; + + for ( int i = 0; i < poller.Options.Length; ++i ) + { + totalVotes += poller.Options[i].Votes; + totalOptionHeight += poller.Options[i].ComputeHeight() + 5; + } + + bool isViewingResults = editing && poller.Active; + bool isCompleted = totalVotes > 0 && !poller.Active; + + if ( editing && !isViewingResults ) + totalOptionHeight += 35; + + int height = 115 + totalOptionHeight; + + AddBackground( 1, 1, 398, height - 2, 3600 ); + AddAlphaRegion( 16, 15, 369, height - 31 ); + + AddItem( 308, 30, 0x1E5E ); + + string title; + + if ( editing ) + title = ( isCompleted ? "Poll Completed" : "Poll Editor" ); + else + title = "Shard Poll"; + + AddHtml( 22, 22, 294, 20, Color( Center( title ), LabelColor32 ), false, false ); + + if ( editing ) + { + AddHtml( 22, 22, 294, 20, Color( String.Format( "{0} total", totalVotes ), LabelColor32 ), false, false ); + AddButton( 287, 23, 0x2622, 0x2623, 2, GumpButtonType.Reply, 0 ); + } + + AddHtml( 22, 50, 294, 40, Color( poller.Title, 0x99CC66 ), false, false ); + + AddImageTiled( 32, 88, 264, 1, 9107 ); + AddImageTiled( 42, 90, 264, 1, 9157 ); + + int y = 100; + + for ( int i = 0; i < poller.Options.Length; ++i ) + { + ShardPollOption option = poller.Options[i]; + string text = option.Title; + + if ( editing && totalVotes > 0 ) + { + double perc = option.Votes / (double)totalVotes; + + text = String.Format( "[{1}: {2}%] {0}", text, option.Votes, (int)(perc*100) ); + } + + int optHeight = option.ComputeHeight(); + + y += optHeight/2; + + if ( isViewingResults ) + AddImage( 24, y - 15, 0x25FE ); + else + AddRadio( 24, y - 15, 0x25F9, 0x25FC, false, 1 + i ); + + AddHtml( 60, y - (9 * option.LineBreaks), 250, 18 * option.LineBreaks, Color( text, LabelColor32 ), false, false ); + + y += optHeight/2; + y += 5; + } + + if ( editing && !isViewingResults ) + { + AddRadio( 24, y + 15 - 15, 0x25F9, 0x25FC, false, 1 + poller.Options.Length ); + AddHtml( 60, y + 15 - 9, 250, 18, Color( "Create new option.", 0x99CC66 ), false, false ); + } + + AddButton( 314, height - 73, 247, 248, 1, GumpButtonType.Reply, 0 ); + AddButton( 314, height - 47, 242, 241, 0, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_Polls != null && m_Polls.Count > 0 ) + { + ShardPoller poller = m_Polls.Dequeue(); + + if ( poller != null ) + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( poller.SendQueuedPoll_Callback ), new object[]{ m_From, m_Polls } ); + } + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length == 0 ) + return; + + int switched = switches[0] - 1; + ShardPollOption opt = null; + + if ( switched >= 0 && switched < m_Poller.Options.Length ) + opt = m_Poller.Options[switched]; + + if ( opt == null && !m_Editing ) + return; + + if ( m_Editing ) + { + if ( !m_Poller.Active ) + { + m_From.SendMessage( "Enter a title for the option. Escape to cancel.{0}", opt == null ? "" : " Use \"DEL\" to delete." ); + m_From.Prompt = new ShardPollPrompt( m_Poller, opt ); + } + else + { + m_From.SendMessage( "You may not edit an active poll. Deactivate it first." ); + m_From.SendGump( new ShardPollGump( m_From, m_Poller, m_Editing, m_Polls ) ); + } + } + else + { + if ( !m_Poller.Active ) + m_From.SendMessage( "The poll has been deactivated." ); + else if ( m_Poller.HasAlreadyVoted( sender ) ) + m_From.SendMessage( "You have already voted on this poll." ); + else + m_Poller.AddVote( sender, opt ); + } + } + else if ( info.ButtonID == 2 && m_Editing ) + { + m_From.SendGump( new ShardPollGump( m_From, m_Poller, m_Editing, m_Polls ) ); + m_From.SendGump( new PropertiesGump( m_From, m_Poller ) ); + } + } + } + + public class ShardPollPrompt : Prompt + { + private ShardPoller m_Poller; + private ShardPollOption m_Option; + + public ShardPollPrompt( ShardPoller poller, ShardPollOption opt ) + { + m_Poller = poller; + m_Option = opt; + } + + public override void OnCancel( Mobile from ) + { + from.SendGump( new ShardPollGump( from, m_Poller, true, null ) ); + } + + private static Regex m_UrlRegex = new Regex( @"\[url(?:=(.*?))?\](.*?)\[/url\]", RegexOptions.IgnoreCase | RegexOptions.Compiled ); + + private static string UrlRegex_Match( Match m ) + { + if ( m.Groups[1].Success ) + { + if ( m.Groups[2].Success ) + return String.Format( "{1}", m.Groups[1].Value, m.Groups[2].Value ); + } + else if ( m.Groups[2].Success ) + { + return String.Format( "{0}", m.Groups[2].Value ); + } + + return m.Value; + } + + public static string UrlToHref( string text ) + { + if ( text == null ) + return null; + + return m_UrlRegex.Replace( text, new MatchEvaluator( UrlRegex_Match ) ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( m_Poller.Active ) + { + from.SendMessage( "You may not edit an active poll. Deactivate it first." ); + } + else if ( text == "DEL" ) + { + if ( m_Option != null ) + m_Poller.RemoveOption( m_Option ); + } + else + { + text = UrlToHref( text ); + + if ( m_Option == null ) + m_Poller.AddOption( new ShardPollOption( text ) ); + else + m_Option.Title = text; + } + + from.SendGump( new ShardPollGump( from, m_Poller, true, null ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ShrinkTable.cs b/Scripts/Misc/ShrinkTable.cs new file mode 100644 index 0000000..9b46274 --- /dev/null +++ b/Scripts/Misc/ShrinkTable.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; + +namespace Server +{ + public class ShrinkTable + { + public const int DefaultItemID = 0x1870; // Yellow virtue stone + + private static int[] m_Table; + + public static int Lookup( Mobile m ) + { + return Lookup( m.Body.BodyID, DefaultItemID ); + } + + public static int Lookup( int body ) + { + return Lookup( body, DefaultItemID ); + } + + public static int Lookup( Mobile m, int defaultValue ) + { + return Lookup( m.Body.BodyID, defaultValue ); + } + + public static int Lookup( int body, int defaultValue ) + { + if ( m_Table == null ) + Load(); + + int val = 0; + + if ( body >= 0 && body < m_Table.Length ) + val = m_Table[body]; + + if ( val == 0 ) + val = defaultValue; + + return val; + } + + private static void Load() + { + string path = Path.Combine( Core.BaseDirectory, "Data/shrink.cfg" ); + + if ( !File.Exists( path ) ) + { + m_Table = new int[0]; + return; + } + + m_Table = new int[1000]; + + using ( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + try + { + string[] split = line.Split( '\t' ); + + if ( split.Length >= 2 ) + { + int body = Utility.ToInt32( split[0] ); + int item = Utility.ToInt32( split[1] ); + + if ( body >= 0 && body < m_Table.Length ) + m_Table[body] = item; + } + } + catch + { + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/SkillCheck.cs b/Scripts/Misc/SkillCheck.cs new file mode 100644 index 0000000..56a77ab --- /dev/null +++ b/Scripts/Misc/SkillCheck.cs @@ -0,0 +1,391 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Factions; + +namespace Server.Misc +{ + public class SkillCheck + { + private static readonly bool AntiMacroCode = false;//!Core.ML; //Change this to false to disable anti-macro code + + public static TimeSpan AntiMacroExpire = TimeSpan.FromMinutes( 5.0 ); //How long do we remember targets/locations? + public const int Allowance = 3; //How many times may we use the same location/target for gain + private const int LocationSize = 5; //The size of eeach location, make this smaller so players dont have to move as far + private static bool[] UseAntiMacro = new bool[] + { + // true if this skill uses the anti-macro code, false if it does not + false,// Alchemy = 0, + true,// Anatomy = 1, + true,// AnimalLore = 2, + true,// ItemID = 3, + true,// ArmsLore = 4, + false,// Parry = 5, + true,// Begging = 6, + false,// Blacksmith = 7, + false,// Fletching = 8, + true,// Peacemaking = 9, + true,// Camping = 10, + false,// Carpentry = 11, + false,// Cartography = 12, + false,// Cooking = 13, + true,// DetectHidden = 14, + true,// Discordance = 15, + true,// EvalInt = 16, + true,// Healing = 17, + true,// Fishing = 18, + true,// Forensics = 19, + true,// Herding = 20, + true,// Hiding = 21, + true,// Provocation = 22, + false,// Inscribe = 23, + true,// Lockpicking = 24, + true,// Magery = 25, + true,// MagicResist = 26, + false,// Tactics = 27, + true,// Snooping = 28, + true,// Musicianship = 29, + true,// Poisoning = 30, + false,// Archery = 31, + true,// SpiritSpeak = 32, + true,// Stealing = 33, + false,// Tailoring = 34, + true,// AnimalTaming = 35, + true,// TasteID = 36, + false,// Tinkering = 37, + true,// Tracking = 38, + true,// Veterinary = 39, + false,// Swords = 40, + false,// Macing = 41, + false,// Fencing = 42, + false,// Wrestling = 43, + true,// Lumberjacking = 44, + true,// Mining = 45, + true,// Meditation = 46, + true,// Stealth = 47, + true,// RemoveTrap = 48, + true,// Necromancy = 49, + false,// Focus = 50, + true,// Chivalry = 51 + true,// Bushido = 52 + true,//Ninjitsu = 53 + true // Spellweaving + }; + + public static void Initialize() + { + // Begin mod to enable XmlSpawner skill triggering + Mobile.SkillCheckLocationHandler = new SkillCheckLocationHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckLocation ); + Mobile.SkillCheckDirectLocationHandler = new SkillCheckDirectLocationHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckDirectLocation ); + + Mobile.SkillCheckTargetHandler = new SkillCheckTargetHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckTarget ); + Mobile.SkillCheckDirectTargetHandler = new SkillCheckDirectTargetHandler( XmlSpawnerSkillCheck.Mobile_SkillCheckDirectTarget ); + // End mod to enable XmlSpawner skill triggering + } + + public static bool Mobile_SkillCheckLocation( Mobile from, SkillName skillName, double minSkill, double maxSkill ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + double value = skill.Value; + + if ( value < minSkill ) + return false; // Too difficult + else if ( value >= maxSkill ) + return true; // No challenge + + double chance = (value - minSkill) / (maxSkill - minSkill); + + Point2D loc = new Point2D( from.Location.X / LocationSize, from.Location.Y / LocationSize ); + return CheckSkill( from, skill, loc, chance ); + } + + public static bool Mobile_SkillCheckDirectLocation( Mobile from, SkillName skillName, double chance ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + if ( chance < 0.0 ) + return false; // Too difficult + else if ( chance >= 1.0 ) + return true; // No challenge + + Point2D loc = new Point2D( from.Location.X / LocationSize, from.Location.Y / LocationSize ); + return CheckSkill( from, skill, loc, chance ); + } + + public static bool CheckSkill( Mobile from, Skill skill, object amObj, double chance ) + { + if ( from.Skills.Cap == 0 ) + return false; + + bool success = ( chance >= Utility.RandomDouble() ); + double gc = (double)(from.Skills.Cap - from.Skills.Total) / from.Skills.Cap; + gc += ( skill.Cap - skill.Base ) / skill.Cap; + gc /= 2; + + gc += ( 1.0 - chance ) * ( success ? 0.5 : (Core.AOS ? 0.0 : 0.2) ); + gc /= 2; + + gc *= skill.Info.GainFactor; + + if ( gc < 0.01 ) + gc = 0.01; + + if ( from is BaseCreature && ((BaseCreature)from).Controlled ) + gc *= 2; + + if ( from.Alive && ( ( gc >= Utility.RandomDouble() && AllowGain( from, skill, amObj ) ) || skill.Base < 10.0 ) ) + Gain( from, skill ); + + return success; + } + + public static bool Mobile_SkillCheckTarget( Mobile from, SkillName skillName, object target, double minSkill, double maxSkill ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + double value = skill.Value; + + if ( value < minSkill ) + return false; // Too difficult + else if ( value >= maxSkill ) + return true; // No challenge + + double chance = (value - minSkill) / (maxSkill - minSkill); + + return CheckSkill( from, skill, target, chance ); + } + + public static bool Mobile_SkillCheckDirectTarget( Mobile from, SkillName skillName, object target, double chance ) + { + Skill skill = from.Skills[skillName]; + + if ( skill == null ) + return false; + + if ( chance < 0.0 ) + return false; // Too difficult + else if ( chance >= 1.0 ) + return true; // No challenge + + return CheckSkill( from, skill, target, chance ); + } + + private static bool AllowGain( Mobile from, Skill skill, object obj ) + { + if ( Core.AOS && Faction.InSkillLoss( from ) ) //Changed some time between the introduction of AoS and SE. + return false; + + if ( AntiMacroCode && from is PlayerMobile && UseAntiMacro[skill.Info.SkillID] ) + return ((PlayerMobile)from).AntiMacroCheck( skill, obj ); + else + return true; + } + + public enum Stat { Str, Dex, Int } + + public static void Gain( Mobile from, Skill skill ) + { + if ( from.Region.IsPartOf( typeof( Regions.Jail ) ) ) + return; + + if ( from is BaseCreature && ((BaseCreature)from).IsDeadPet ) + return; + + if ( skill.SkillName == SkillName.Focus && from is BaseCreature ) + return; + + if ( skill.Base < skill.Cap && skill.Lock == SkillLock.Up ) + { + int toGain = 1; + + if ( skill.Base <= 10.0 ) + toGain = Utility.Random( 4 ) + 1; + + Skills skills = from.Skills; + + if ( from.Player && ( skills.Total / skills.Cap ) >= Utility.RandomDouble() )//( skills.Total >= skills.Cap ) + { + for ( int i = 0; i < skills.Length; ++i ) + { + Skill toLower = skills[i]; + + if ( toLower != skill && toLower.Lock == SkillLock.Down && toLower.BaseFixedPoint >= toGain ) + { + toLower.BaseFixedPoint -= toGain; + break; + } + } + } + + #region Scroll of Alacrity + PlayerMobile pm = from as PlayerMobile; + + if (pm != null && skill.SkillName == pm.AcceleratedSkill && pm.AcceleratedStart > DateTime.Now) + toGain *= Utility.RandomMinMax(2, 5); + #endregion + + if ( !from.Player || (skills.Total + toGain) <= skills.Cap ) + { + skill.BaseFixedPoint += toGain; + } + } + + if ( skill.Lock == SkillLock.Up ) + { + SkillInfo info = skill.Info; + + if ( from.StrLock == StatLockType.Up && (info.StrGain / 33.3) > Utility.RandomDouble() ) + GainStat( from, Stat.Str ); + else if ( from.DexLock == StatLockType.Up && (info.DexGain / 33.3) > Utility.RandomDouble() ) + GainStat( from, Stat.Dex ); + else if ( from.IntLock == StatLockType.Up && (info.IntGain / 33.3) > Utility.RandomDouble() ) + GainStat( from, Stat.Int ); + } + } + + public static bool CanLower( Mobile from, Stat stat ) + { + switch ( stat ) + { + case Stat.Str: return ( from.StrLock == StatLockType.Down && from.RawStr > 10 ); + case Stat.Dex: return ( from.DexLock == StatLockType.Down && from.RawDex > 10 ); + case Stat.Int: return ( from.IntLock == StatLockType.Down && from.RawInt > 10 ); + } + + return false; + } + + public static bool CanRaise( Mobile from, Stat stat ) + { + if ( !(from is BaseCreature && ((BaseCreature)from).Controlled) ) + { + if ( from.RawStatTotal >= from.StatCap ) + return false; + } + + switch ( stat ) + { + case Stat.Str: return ( from.StrLock == StatLockType.Up && from.RawStr < 125 ); + case Stat.Dex: return ( from.DexLock == StatLockType.Up && from.RawDex < 125 ); + case Stat.Int: return ( from.IntLock == StatLockType.Up && from.RawInt < 125 ); + } + + return false; + } + + public static void IncreaseStat( Mobile from, Stat stat, bool atrophy ) + { + atrophy = atrophy || (from.RawStatTotal >= from.StatCap); + + switch ( stat ) + { + case Stat.Str: + { + if ( atrophy ) + { + if ( CanLower( from, Stat.Dex ) && (from.RawDex < from.RawInt || !CanLower( from, Stat.Int )) ) + --from.RawDex; + else if ( CanLower( from, Stat.Int ) ) + --from.RawInt; + } + + if ( CanRaise( from, Stat.Str ) ) + ++from.RawStr; + + break; + } + case Stat.Dex: + { + if ( atrophy ) + { + if ( CanLower( from, Stat.Str ) && (from.RawStr < from.RawInt || !CanLower( from, Stat.Int )) ) + --from.RawStr; + else if ( CanLower( from, Stat.Int ) ) + --from.RawInt; + } + + if ( CanRaise( from, Stat.Dex ) ) + ++from.RawDex; + + break; + } + case Stat.Int: + { + if ( atrophy ) + { + if ( CanLower( from, Stat.Str ) && (from.RawStr < from.RawDex || !CanLower( from, Stat.Dex )) ) + --from.RawStr; + else if ( CanLower( from, Stat.Dex ) ) + --from.RawDex; + } + + if ( CanRaise( from, Stat.Int ) ) + ++from.RawInt; + + break; + } + } + } + + private static TimeSpan m_StatGainDelay = TimeSpan.FromMinutes((Core.ML) ? 0.05 : 15); + private static TimeSpan m_PetStatGainDelay = TimeSpan.FromMinutes(5.0); + + public static void GainStat( Mobile from, Stat stat ) + { + switch( stat ) + { + case Stat.Str: + { + if ( from is BaseCreature && ((BaseCreature)from).Controlled ) { + if ( (from.LastStrGain + m_PetStatGainDelay) >= DateTime.Now ) + return; + } + else if( (from.LastStrGain + m_StatGainDelay) >= DateTime.Now ) + return; + + from.LastStrGain = DateTime.Now; + break; + } + case Stat.Dex: + { + if ( from is BaseCreature && ((BaseCreature)from).Controlled ) { + if ( (from.LastDexGain + m_PetStatGainDelay) >= DateTime.Now ) + return; + } + else if( (from.LastDexGain + m_StatGainDelay) >= DateTime.Now ) + return; + + from.LastDexGain = DateTime.Now; + break; + } + case Stat.Int: + { + if ( from is BaseCreature && ((BaseCreature)from).Controlled ) { + if ( (from.LastIntGain + m_PetStatGainDelay) >= DateTime.Now ) + return; + } + + else if( (from.LastIntGain + m_StatGainDelay) >= DateTime.Now ) + return; + + from.LastIntGain = DateTime.Now; + break; + } + } + + bool atrophy = ( (from.RawStatTotal / (double)from.StatCap) >= Utility.RandomDouble() ); + + IncreaseStat( from, stat, atrophy ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/SocketOptions.cs b/Scripts/Misc/SocketOptions.cs new file mode 100644 index 0000000..fe53a3c --- /dev/null +++ b/Scripts/Misc/SocketOptions.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using Server; +using Server.Misc; +using Server.Network; + +namespace Server +{ + public class SocketOptions + { + private const bool NagleEnabled = false; // Should the Nagle algorithm be enabled? This may reduce performance + private const int CoalesceBufferSize = 512; // MSS that the core will use when buffering packets + + private static IPEndPoint[] m_ListenerEndPoints = new IPEndPoint[] { + new IPEndPoint( IPAddress.Any, 2593 ), // Default: Listen on port 2593 on all IP addresses + new IPEndPoint( IPAddress.Any, 7775 ), + new IPEndPoint( IPAddress.Any, 7776 ), + // Examples: + // new IPEndPoint( IPAddress.Any, 80 ), // Listen on port 80 on all IP addresses + // new IPEndPoint( IPAddress.Parse( "1.2.3.4" ), 2593 ), // Listen on port 2593 on IP address 1.2.3.4 + }; + + public static void Initialize() + { + SendQueue.CoalesceBufferSize = CoalesceBufferSize; + + EventSink.SocketConnect += new SocketConnectEventHandler( EventSink_SocketConnect ); + + Listener.EndPoints = m_ListenerEndPoints; + } + + private static void EventSink_SocketConnect( SocketConnectEventArgs e ) + { + if ( !e.AllowConnection ) + return; + + if ( !NagleEnabled ) + e.Socket.SetSocketOption( SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1 ); // RunUO uses its own algorithm + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/TextDefinition.cs b/Scripts/Misc/TextDefinition.cs new file mode 100644 index 0000000..5e74f43 --- /dev/null +++ b/Scripts/Misc/TextDefinition.cs @@ -0,0 +1,227 @@ +using System; +using System.Globalization; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server +{ + [Parsable] + public class TextDefinition + { + private int m_Number; + private string m_String; + + public int Number { get { return m_Number; } } + public string String { get { return m_String; } } + + public bool IsEmpty { get { return (m_Number <= 0 && m_String == null); } } + + public TextDefinition() + : this(0, null) + { + } + + public TextDefinition(int number) + : this(number, null) + { + } + + public TextDefinition(string text) + : this(0, text) + { + } + + public TextDefinition(int number, string text) + { + m_Number = number; + m_String = text; + } + + public override string ToString() + { + if (m_Number > 0) + return String.Concat("#", m_Number.ToString()); + else if (m_String != null) + return m_String; + + return ""; + } + + public string Format(bool propsGump) + { + if (m_Number > 0) + return String.Format("{0} (0x{0:X})", m_Number); + else if (m_String != null) + return String.Format("\"{0}\"", m_String); + + return propsGump ? "-empty-" : "empty"; + } + + public string GetValue() + { + if (m_Number > 0) + return m_Number.ToString(); + else if (m_String != null) + return m_String; + + return ""; + } + + public static void Serialize(GenericWriter writer, TextDefinition def) + { + if (def == null) + { + writer.WriteEncodedInt(3); + } + else if (def.m_Number > 0) + { + writer.WriteEncodedInt(1); + writer.WriteEncodedInt(def.m_Number); + } + else if (def.m_String != null) + { + writer.WriteEncodedInt(2); + writer.Write(def.m_String); + } + else + { + writer.WriteEncodedInt(0); + } + } + + public static TextDefinition Deserialize(GenericReader reader) + { + int type = reader.ReadEncodedInt(); + + switch (type) + { + case 0: return new TextDefinition(); + case 1: return new TextDefinition(reader.ReadEncodedInt()); + case 2: return new TextDefinition(reader.ReadString()); + } + + return null; + } + + public static void AddTo(ObjectPropertyList list, TextDefinition def) + { + if (def == null) + return; + + if (def.m_Number > 0) + list.Add(def.m_Number); + else if (def.m_String != null) + list.Add(def.m_String); + } + + public static implicit operator TextDefinition(int v) + { + return new TextDefinition(v); + } + + public static implicit operator TextDefinition(string s) + { + return new TextDefinition(s); + } + + public static implicit operator int(TextDefinition m) + { + if (m == null) + return 0; + + return m.m_Number; + } + + public static implicit operator string(TextDefinition m) + { + if (m == null) + return null; + + return m.m_String; + } + + public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, bool scroll, int numberColor, int stringColor) + { + if (def == null) + return; + + if (def.m_Number > 0) + { + if (numberColor >= 0) // 5 bits per RGB component (15 bit RGB) + g.AddHtmlLocalized(x, y, width, height, def.m_Number, numberColor, back, scroll); + else + g.AddHtmlLocalized(x, y, width, height, def.m_Number, back, scroll); + } + else if (def.m_String != null) + { + if (stringColor >= 0) // 8 bits per RGB component (24 bit RGB) + g.AddHtml(x, y, width, height, String.Format("{1}", stringColor, def.m_String), back, scroll); + else + g.AddHtml(x, y, width, height, def.m_String, back, scroll); + } + } + + public static void AddHtmlText(Gump g, int x, int y, int width, int height, TextDefinition def, bool back, bool scroll) + { + AddHtmlText(g, x, y, width, height, def, back, scroll, -1, -1); + } + + public static void SendMessageTo(Mobile m, TextDefinition def) + { + if (def == null) + return; + + if (def.m_Number > 0) + m.SendLocalizedMessage(def.m_Number); + else if (def.m_String != null) + m.SendMessage(def.m_String); + } + + public static void SendMessageTo(Mobile m, TextDefinition def, int hue) + { + if (def == null) + return; + + if (def.m_Number > 0) + m.SendLocalizedMessage(def.m_Number, "", hue); + else if (def.m_String != null) + m.SendMessage(hue, def.m_String); + } + + public static void PublicOverheadMessage(Mobile m, MessageType messageType, int hue, TextDefinition def) + { + if (def == null) + return; + + if (def.m_Number > 0) + m.PublicOverheadMessage(messageType, hue, def.m_Number); + else if (def.m_String != null) + m.PublicOverheadMessage(messageType, hue, false, def.m_String); + } + + public static TextDefinition Parse(string value) + { + if (value == null) + return null; + + int i; + bool isInteger; + + if (value.StartsWith("0x")) + isInteger = int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i); + else + isInteger = int.TryParse(value, out i); + + if (isInteger) + return new TextDefinition(i); + else + return new TextDefinition(value); + } + + public static bool IsNullOrEmpty(TextDefinition def) + { + return (def == null || def.IsEmpty); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Titles.cs b/Scripts/Misc/Titles.cs new file mode 100644 index 0000000..29da337 --- /dev/null +++ b/Scripts/Misc/Titles.cs @@ -0,0 +1,423 @@ +using System; +using System.Text; +using Server; +using Server.Mobiles; +using Server.Engines.CannedEvil; + +namespace Server.Misc +{ + public class Titles + { + public const int MinFame = 0; + public const int MaxFame = 15000; + + public static void AwardFame( Mobile m, int offset, bool message ) + { + if ( offset > 0 ) + { + if ( m.Fame >= MaxFame ) + return; + + offset -= m.Fame / 100; + + if ( offset < 0 ) + offset = 0; + } + else if ( offset < 0 ) + { + if ( m.Fame <= MinFame ) + return; + + offset -= m.Fame / 100; + + if ( offset > 0 ) + offset = 0; + } + + if ( (m.Fame + offset) > MaxFame ) + offset = MaxFame - m.Fame; + else if ( (m.Fame + offset) < MinFame ) + offset = MinFame - m.Fame; + + m.Fame += offset; + + if ( message ) + { + if ( offset > 40 ) + m.SendLocalizedMessage( 1019054 ); // You have gained a lot of fame. + else if ( offset > 20 ) + m.SendLocalizedMessage( 1019053 ); // You have gained a good amount of fame. + else if ( offset > 10 ) + m.SendLocalizedMessage( 1019052 ); // You have gained some fame. + else if ( offset > 0 ) + m.SendLocalizedMessage( 1019051 ); // You have gained a little fame. + else if ( offset < -40 ) + m.SendLocalizedMessage( 1019058 ); // You have lost a lot of fame. + else if ( offset < -20 ) + m.SendLocalizedMessage( 1019057 ); // You have lost a good amount of fame. + else if ( offset < -10 ) + m.SendLocalizedMessage( 1019056 ); // You have lost some fame. + else if ( offset < 0 ) + m.SendLocalizedMessage( 1019055 ); // You have lost a little fame. + } + } + + public const int MinKarma = -15000; + public const int MaxKarma = 15000; + + public static void AwardKarma( Mobile m, int offset, bool message ) + { + if ( offset > 0 ) + { + if ( m is PlayerMobile && ((PlayerMobile)m).KarmaLocked ) + return; + + if ( m.Karma >= MaxKarma ) + return; + + offset -= m.Karma / 100; + + if ( offset < 0 ) + offset = 0; + } + else if ( offset < 0 ) + { + if ( m.Karma <= MinKarma ) + return; + + offset -= m.Karma / 100; + + if ( offset > 0 ) + offset = 0; + } + + if ( (m.Karma + offset) > MaxKarma ) + offset = MaxKarma - m.Karma; + else if ( (m.Karma + offset) < MinKarma ) + offset = MinKarma - m.Karma; + + bool wasPositiveKarma = ( m.Karma >= 0 ); + + m.Karma += offset; + + if ( message ) + { + if ( offset > 40 ) + m.SendLocalizedMessage( 1019062 ); // You have gained a lot of karma. + else if ( offset > 20 ) + m.SendLocalizedMessage( 1019061 ); // You have gained a good amount of karma. + else if ( offset > 10 ) + m.SendLocalizedMessage( 1019060 ); // You have gained some karma. + else if ( offset > 0 ) + m.SendLocalizedMessage( 1019059 ); // You have gained a little karma. + else if ( offset < -40 ) + m.SendLocalizedMessage( 1019066 ); // You have lost a lot of karma. + else if ( offset < -20 ) + m.SendLocalizedMessage( 1019065 ); // You have lost a good amount of karma. + else if ( offset < -10 ) + m.SendLocalizedMessage( 1019064 ); // You have lost some karma. + else if ( offset < 0 ) + m.SendLocalizedMessage( 1019063 ); // You have lost a little karma. + } + + if ( !Core.AOS && wasPositiveKarma && m.Karma < 0 && m is PlayerMobile && !((PlayerMobile)m).KarmaLocked ) + { + ((PlayerMobile)m).KarmaLocked = true; + m.SendLocalizedMessage( 1042511, "", 0x22 ); // Karma is locked. A mantra spoken at a shrine will unlock it again. + } + } + + public static string[] HarrowerTitles = new string[] { "Spite", "Opponent", "Hunter", "Venom", "Executioner", "Annihilator", "Champion", "Assailant", "Purifier", "Nullifier" }; + + public static string ComputeTitle( Mobile beholder, Mobile beheld ) + { + StringBuilder title = new StringBuilder(); + + int fame = beheld.Fame; + int karma = beheld.Karma; + + bool showSkillTitle = beheld.ShowFameTitle && ( (beholder == beheld) || (fame >= 5000) ); + + /*if ( beheld.Kills >= 5 ) + { + title.AppendFormat( beheld.Fame >= 10000 ? "The Murderer {1} {0}" : "The Murderer {0}", beheld.Name, beheld.Female ? "Lady" : "Lord" ); + } + else*/if ( beheld.ShowFameTitle || (beholder == beheld) ) + { + for ( int i = 0; i < m_FameEntries.Length; ++i ) + { + FameEntry fe = m_FameEntries[i]; + + if ( fame <= fe.m_Fame || i == (m_FameEntries.Length - 1) ) + { + KarmaEntry[] karmaEntries = fe.m_Karma; + + for ( int j = 0; j < karmaEntries.Length; ++j ) + { + KarmaEntry ke = karmaEntries[j]; + + if ( karma <= ke.m_Karma || j == (karmaEntries.Length - 1) ) + { + title.AppendFormat( beheld.Female? ke.m_FTitle : ke.m_Title, beheld.Name, beheld.Female ? "La Grande" : "Le Grand" ); + break; + } + } + + break; + } + } + } + else + { + title.Append( beheld.Name ); + } + + if( beheld is PlayerMobile && ((PlayerMobile)beheld).DisplayChampionTitle ) + { + PlayerMobile.ChampionTitleInfo info = ((PlayerMobile)beheld).ChampionTitles; + + if( info.Harrower > 0 ) + title.AppendFormat( ": {0} of Evil", HarrowerTitles[Math.Min( HarrowerTitles.Length, info.Harrower )-1] ); + else + { + int highestValue = 0, highestType = 0; + for( int i = 0; i < ChampionSpawnInfo.Table.Length; i++ ) + { + int v = info.GetValue( i ); + + if( v > highestValue ) + { + highestValue = v; + highestType = i; + } + } + + int offset = 0; + if( highestValue > 800 ) + offset = 3; + else if( highestValue > 300 ) + offset = (int)(highestValue/300); + + if( offset > 0 ) + { + ChampionSpawnInfo champInfo = ChampionSpawnInfo.GetInfo( (ChampionSpawnType)highestType ); + title.AppendFormat( ": {0} of the {1}", champInfo.LevelNames[Math.Min( offset, champInfo.LevelNames.Length ) -1], champInfo.Name ); + } + } + } + + string customTitle = beheld.Title; + + if ( customTitle != null && (customTitle = customTitle.Trim()).Length > 0 ) + { + title.AppendFormat( " {0}", customTitle ); + } + else if ( showSkillTitle && beheld.Player ) + { + string skillTitle = GetSkillTitle( beheld ); + + if ( skillTitle != null ) { + title.Append( ", " ).Append( skillTitle ); + } + } + + return title.ToString(); + } + + public static string GetSkillTitle( Mobile mob ) { + Skill highest = GetHighestSkill( mob );// beheld.Skills.Highest; + + if (highest != null && highest.BaseFixedPoint >= 300) + { + + //string skillLevel = GetSkillLevel(highest); + string skillLevel = (mob.Female ? FGetSkillLevel(highest) : GetSkillLevel(highest)); + string skillTitle = (mob.Female ? highest.Info.FTitle : highest.Info.Title); + /*if ( mob.Female && skillTitle.EndsWith( "man" ) ) + skillTitle = skillTitle.Substring( 0, skillTitle.Length - 3 ) + "woman";*/ + + if(skillLevel != null && skillTitle != null) + return String.Concat(skillLevel, " ", skillTitle); + } + + return null; + } + + private static Skill GetHighestSkill( Mobile m ) + { + Skills skills = m.Skills; + + if ( !Core.AOS ) + return skills.Highest; + + Skill highest = null; + + for ( int i = 0; i < m.Skills.Length; ++i ) + { + Skill check = m.Skills[i]; + + if ( highest == null || check.BaseFixedPoint > highest.BaseFixedPoint ) + highest = check; + else if ( highest != null && highest.Lock != SkillLock.Up && check.Lock == SkillLock.Up && check.BaseFixedPoint == highest.BaseFixedPoint ) + highest = check; + } + + return highest; + } + + private static string[,] m_Levels = new string[,] + { + { "Neophite", "Neophite", "Neophite" }, + { "Novice", "Novice", "Novice" }, + { "Apprenti", "Apprenti", "Apprenti" }, + { "Compagnon", "Compagnon", "Compagnon" }, + { "Expert", "Expert", "Expert" }, + { "Adepte", "Adepte", "Adepte" }, + { "Maitre", "Maitre", "Maitre" }, + { "Grand Maitre", "Grand Maitre", "Grand Maitre" }, + { "Ancien", "Ancien", "Ancien" }, + { "Legendaire", "Legendaire", "Legendaire" } + }; + + private static string[,] m_FLevels = new string[,] + { + { "Neophite", "Neophite", "Neophite" }, + { "Novice", "Novice", "Novice" }, + { "Apprentie", "Apprentie", "Apprentie" }, + { "Compagnon", "Compagnon", "Compagnon" }, + { "Experte", "Experte", "Experte" }, + { "Adepte", "Adepte", "Adepte" }, + { "Maitre", "Maitre", "Maitre" }, + { "Grande Maitre", "Grande Maitre", "Grande Maitre" }, + { "Ancienne", "Ancienne", "Ancienne" }, + { "Legendaire", "Legendaire", "Legendaire" } + }; + + private static string GetSkillLevel( Skill skill ) + { + return m_Levels[GetTableIndex( skill ), GetTableType( skill )]; + } + + private static string FGetSkillLevel(Skill skill) + { + return m_FLevels[GetTableIndex(skill), GetTableType(skill)]; + } + + private static int GetTableType( Skill skill ) + { + switch ( skill.SkillName ) + { + default: return 0; + case SkillName.Bushido: return 1; + case SkillName.Ninjitsu: return 2; + } + } + + private static int GetTableIndex( Skill skill ) + { + int fp = Math.Min( skill.BaseFixedPoint, 1200 ); + + return (fp - 300) / 100; + } + + private static FameEntry[] m_FameEntries = new FameEntry[] + { + new FameEntry( 1249, new KarmaEntry[] + { + new KarmaEntry( -10000, "{0} le Proscrit", "{0} la Proscrite" ), + new KarmaEntry( -5000, "{0} le Meprisable", "{0} la Meprisable" ), + new KarmaEntry( -2500, "{0} le Scelerat", "{0} la Scelerate" ), + new KarmaEntry( -1250, "{0} le Repugnant", "{0} la Repugnante" ), + new KarmaEntry( -625, "{0} le Rude", "{0} la Rude" ), + new KarmaEntry( 624, "{0}", "{0}" ), + new KarmaEntry( 1249, "{0} le Juste", "{0} la Juste" ), + new KarmaEntry( 2499, "{0} l'Aimable", "{0} l'Aimable" ), + new KarmaEntry( 4999, "{0} le Brave", "{0} la Brave"), + new KarmaEntry( 9999, "{0} l'Honnete", "{0} l'Honnete" ), + new KarmaEntry( 10000, "{0} le Fiable", "{0} la Fiable" ) + } ), + new FameEntry( 2499, new KarmaEntry[] + { + new KarmaEntry( -10000, "{0} le Miserable", "{0} la Miserable" ), + new KarmaEntry( -5000, "{0} le Lache", "{0} la Lache" ), + new KarmaEntry( -2500, "{0} le Malicieux", "{0} la Malicieuse" ), + new KarmaEntry( -1250, "{0} le Deshonorable", "{0} la Deshonorable" ), + new KarmaEntry( -625, "{0} le Minable", "{0} la Minable" ), + new KarmaEntry( 624, "{0} le Notable", "{0} la Notable" ), + new KarmaEntry( 1249, "{0} le Droit", "{0} la Droite" ), + new KarmaEntry( 2499, "{0} le Respectable", "{0} la Respectable" ), + new KarmaEntry( 4999, "{0} l'Honorable", "{0} l'Honorable" ), + new KarmaEntry( 9999, "{0} le Louable", "{0} la Louable" ), + new KarmaEntry( 10000, "{0} l'Estimable", "{0} l'Estimable" ) + } ), + new FameEntry( 4999, new KarmaEntry[] + { + new KarmaEntry( -10000, "{0} l'Infame", "{0} l'Infame" ), + new KarmaEntry( -5000, "{0} le Cruel", "{0} la Cruelle" ), + new KarmaEntry( -2500, "{0} le Vil", "{0} la Vile" ), + new KarmaEntry( -1250, "{0} l'Ignoble", "{0} l'Ignoble" ), + new KarmaEntry( -625, "{0} le Connu", "{0} la Connue" ), + new KarmaEntry( 624, "{0} le Hautain", "{0} la Hautaine" ), + new KarmaEntry( 1249, "{0} le Repute", "{0} la Reputee" ), + new KarmaEntry( 2499, "{0} le Digne", "{0} la Digne" ), + new KarmaEntry( 4999, "{0} l'Admirable", "{0} l'Admirable" ), + new KarmaEntry( 9999, "{0} le Celebre", "{0} la Celebre" ), + new KarmaEntry( 10000, "{0} le Grand", "{0} la Grande" ) + } ), + new FameEntry( 9999, new KarmaEntry[] + { + new KarmaEntry( -10000, "{0} le Terrible", "{0} la Terrible" ), + new KarmaEntry( -5000, "{0} le Malfaisant", "{0} la Malfaisante" ), + new KarmaEntry( -2500, "{0} le Sordide", "{0} la Sordide" ), + new KarmaEntry( -1250, "{0} le Tenebreux", "{0} la Tenebreuse" ), + new KarmaEntry( -625, "{0} le Sadique", "{0} la Sadique" ), + new KarmaEntry( 624, "{0} le Fameux", "{0} la Fameuse" ), + new KarmaEntry( 1249, "{0} le Distingue", "{0} la Distinguee" ), + new KarmaEntry( 2499, "{0} l'Eminent", "{0} l'Eminente" ), + new KarmaEntry( 4999, "{0} le Noble", "{0} la Noble" ), + new KarmaEntry( 9999, "{0} l'Illustre", "{0} l'Illustre" ), + new KarmaEntry( 10000, "{0} le Glorieux", "{0} la Glorieuse" ) + } ), + new FameEntry( 10000, new KarmaEntry[] + { + new KarmaEntry( -10000, "{1} {0} le Terrible", "{1} {0} la Terrible" ), + new KarmaEntry( -5000, "{1} {0} le Malfaisant", "{1} {0} la Malfaisante" ), + new KarmaEntry( -2500, "{1} {0} le Sombre", "{1} {0} la Sombre"), + new KarmaEntry( -1250, "{1} {0} le Tenebreux", "{1} {0} la Tenebreuse"), + new KarmaEntry( -625, "{1} {0} le Dechu", "{1} {0} la Dechue" ), + new KarmaEntry( 624, "{1} {0}", "{1} {0}" ), + new KarmaEntry( 1249, "{1} {0} le Distingue", "{1} {0} la Distinguee" ), + new KarmaEntry( 2499, "{1} {0} l'Eminent", "{1} {0} l'Eminente" ), + new KarmaEntry( 4999, "{1} {0} le Noble", "{1} {0} la Noble" ), + new KarmaEntry( 9999, "{1} {0} l'Illustre", "{1} {0} l'Illustre" ), + new KarmaEntry( 10000, "{1} {0} le Glorieux", "{1} {0} la Glorieuse" ) + } ) + }; + } + + public class FameEntry + { + public int m_Fame; + public KarmaEntry[] m_Karma; + + public FameEntry( int fame, KarmaEntry[] karma ) + { + m_Fame = fame; + m_Karma = karma; + } + } + + public class KarmaEntry + { + public int m_Karma; + public string m_Title; + public string m_FTitle; + + public KarmaEntry( int karma, string title, string ftitle ) + { + m_Karma = karma; + m_Title = title; + m_FTitle = ftitle; + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ToggleItem.cs b/Scripts/Misc/ToggleItem.cs new file mode 100644 index 0000000..9376084 --- /dev/null +++ b/Scripts/Misc/ToggleItem.cs @@ -0,0 +1,131 @@ +using System; +using Server; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Items +{ + public class ToggleItem : Item + { + public class ToggleCommand : BaseCommand + { + public ToggleCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllItems; + Commands = new string[]{ "Toggle" }; + ObjectTypes = ObjectTypes.Items; + Usage = "Toggle"; + Description = "Toggles a targeted ToggleItem."; + } + + public override void Execute( CommandEventArgs e, object obj ) + { + if ( obj is ToggleItem ) + { + ((ToggleItem)obj).Toggle(); + AddResponse( "The item has been toggled." ); + } + else + { + LogFailure( "That is not a ToggleItem." ); + } + } + } + + public static void Initialize() + { + TargetCommands.Register( new ToggleCommand() ); + } + + private int m_InactiveItemID; + private int m_ActiveItemID; + private bool m_PlayersCanToggle; + + [CommandProperty( AccessLevel.GameMaster )] + public int InactiveItemID + { + get { return m_InactiveItemID; } + set { m_InactiveItemID = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ActiveItemID + { + get { return m_ActiveItemID; } + set { m_ActiveItemID = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool PlayersCanToggle + { + get { return m_PlayersCanToggle; } + set { m_PlayersCanToggle = value; } + } + + [Constructable] + public ToggleItem( int inactiveItemID, int activeItemID ) + : this( inactiveItemID, activeItemID, false ) + { + } + + [Constructable] + public ToggleItem( int inactiveItemID, int activeItemID, bool playersCanToggle ) + : base( inactiveItemID ) + { + Movable = false; + + m_InactiveItemID = inactiveItemID; + m_ActiveItemID = activeItemID; + m_PlayersCanToggle = playersCanToggle; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + Toggle(); + } + else if ( m_PlayersCanToggle ) + { + if ( from.InRange( GetWorldLocation(), 1 ) ) + Toggle(); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + + public void Toggle() + { + ItemID = ( ItemID == m_ActiveItemID ) ? m_InactiveItemID : m_ActiveItemID; + Visible = ( ItemID != 0x1 ); + } + + public ToggleItem( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_InactiveItemID ); + writer.Write( m_ActiveItemID ); + writer.Write( m_PlayersCanToggle ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_InactiveItemID = reader.ReadInt(); + m_ActiveItemID = reader.ReadInt(); + m_PlayersCanToggle = reader.ReadBool(); + } + } +} diff --git a/Scripts/Misc/TreasureMapProtection.cs b/Scripts/Misc/TreasureMapProtection.cs new file mode 100644 index 0000000..2e33e21 --- /dev/null +++ b/Scripts/Misc/TreasureMapProtection.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Regions; + +namespace Server +{ + public class TreasureRegion : BaseRegion + { + private const int Range = 5; // No house may be placed within 5 tiles of the treasure + + public TreasureRegion( int x, int y, Map map ): base( null, map, Region.DefaultPriority, new Rectangle2D( x - Range, y - Range, 1 + (Range * 2), 1 + (Range * 2) ) ) + { + GoLocation = new Point3D( x, y, map.GetAverageZ( x, y ) ); + + Register(); + } + + public static void Initialize() + { + string filePath = Path.Combine( Core.BaseDirectory, "Data/treasure.cfg" ); + int i = 0, x = 0, y = 0; + + if ( File.Exists( filePath ) ) + { + using ( StreamReader ip = new StreamReader( filePath ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + i++; + + try + { + string[] split = line.Split( ' ' ); + + x = Convert.ToInt32( split[0] ); + y = Convert.ToInt32( split[1] ); + + try + { + new TreasureRegion( x, y, Map.Felucca ); + new TreasureRegion( x, y, Map.Trammel ); + } + catch ( Exception e ) + { + Console.WriteLine( "{0} {1} {2} {3}", i, x, y, e ); + } + } + catch + { + Console.WriteLine( "Warning: Error in Line '{0}' of Data/treasure.cfg", line ); + } + } + } + } + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + return false; + } + + public override void OnEnter( Mobile m ) + { + if ( m.AccessLevel > AccessLevel.Player ) + m.SendMessage( "You have entered a protected treasure map area." ); + } + + public override void OnExit( Mobile m ) + { + if ( m.AccessLevel > AccessLevel.Player ) + m.SendMessage( "You have left a protected treasure map area." ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/ValidationQueue.cs b/Scripts/Misc/ValidationQueue.cs new file mode 100644 index 0000000..bceb957 --- /dev/null +++ b/Scripts/Misc/ValidationQueue.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Server; + +namespace Server +{ + public delegate void ValidationEventHandler(); + + public static class ValidationQueue + { + public static event ValidationEventHandler StartValidation; + + public static void Initialize() + { + if ( StartValidation != null ) + StartValidation(); + + StartValidation = null; + } + } + + public static class ValidationQueue + { + private static List m_Queue; + + static ValidationQueue() + { + m_Queue = new List(); + ValidationQueue.StartValidation += new ValidationEventHandler( ValidateAll ); + } + + public static void Add( T obj ) + { + m_Queue.Add( obj ); + } + + private static void ValidateAll() + { + Type type = typeof( T ); + + if ( type != null ) + { + MethodInfo m = type.GetMethod( "Validate", BindingFlags.Instance | BindingFlags.Public ); + + if ( m != null ) + { + for ( int i = 0; i < m_Queue.Count; ++i ) + m.Invoke( m_Queue[i], null ); + } + } + + m_Queue.Clear(); + m_Queue = null; + } + } +} diff --git a/Scripts/Misc/VendorGenerator.cs b/Scripts/Misc/VendorGenerator.cs new file mode 100644 index 0000000..f2ac251 --- /dev/null +++ b/Scripts/Misc/VendorGenerator.cs @@ -0,0 +1,532 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Commands; +using Server.Mobiles; + +namespace Server +{ + public class VendorGenerator + { + public static void Initialize() + { + CommandSystem.Register( "VendorGen", AccessLevel.Administrator, new CommandEventHandler( VendorGenerator.VendorGen_OnCommand ) ); + } + + private static Rectangle2D[] m_BritRegions = new Rectangle2D[] + { + new Rectangle2D( new Point2D( 250, 750 ), new Point2D( 775, 1330 ) ), + new Rectangle2D( new Point2D( 525, 2095 ), new Point2D( 925, 2430 ) ), + new Rectangle2D( new Point2D( 1025, 2155 ), new Point2D( 1265, 2310 ) ), + new Rectangle2D( new Point2D( 1635, 2430 ), new Point2D( 1705, 2508 ) ), + new Rectangle2D( new Point2D( 1775, 2605 ), new Point2D( 2165, 2975 ) ), + new Rectangle2D( new Point2D( 1055, 3520 ), new Point2D( 1570, 4075 ) ), + new Rectangle2D( new Point2D( 2860, 3310 ), new Point2D( 3120, 3630 ) ), + new Rectangle2D( new Point2D( 2470, 1855 ), new Point2D( 3950, 3045 ) ), + new Rectangle2D( new Point2D( 3425, 990 ), new Point2D( 3900, 1455 ) ), + new Rectangle2D( new Point2D( 4175, 735 ), new Point2D( 4840, 1600 ) ), + new Rectangle2D( new Point2D( 2375, 330 ), new Point2D( 3100, 1045 ) ), + new Rectangle2D( new Point2D( 2100, 1090 ), new Point2D( 2310, 1450 ) ), + new Rectangle2D( new Point2D( 1495, 1400 ), new Point2D( 1550, 1475 ) ), + new Rectangle2D( new Point2D( 1085, 1520 ), new Point2D( 1415, 1910 ) ), + new Rectangle2D( new Point2D( 1410, 1500 ), new Point2D( 1745, 1795 ) ), + new Rectangle2D( new Point2D( 5120, 2300 ), new Point2D( 6143, 4095 ) ) + }; + + private static Rectangle2D[] m_IlshRegions = new Rectangle2D[] + { + new Rectangle2D( new Point2D( 0, 0 ), new Point2D( 288*8, 200*8 ) ) + }; + + [Usage( "VendorGen" )] + [Description( "Generates vendors based on display cases and floor plans. Analyzes the map files, slow." )] + private static void VendorGen_OnCommand( CommandEventArgs e ) + { + Process( Map.Trammel, m_BritRegions ); + Process( Map.Felucca, m_BritRegions ); + Process( Map.Ilshenar, m_IlshRegions ); + } + + private static bool GetFloorZ( Map map, int x, int y, out int z ) + { + LandTile lt = map.Tiles.GetLandTile( x, y ); + + if ( IsFloor( lt.ID ) && map.CanFit( x, y, lt.Z, 16, false, false ) ) + { + z = lt.Z; + return true; + } + + StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + if ( IsStaticFloor( t.ID ) && map.CanFit( x, y, t.Z + (id.Surface ? id.CalcHeight : 0), 16, false, false ) ) + { + z = t.Z + (id.Surface ? id.CalcHeight : 0); + return true; + } + } + + z = 0; + return false; + } + + private static bool IsFloor( Map map, int x, int y, bool canFit ) + { + LandTile lt = map.Tiles.GetLandTile( x, y ); + + if ( IsFloor( lt.ID ) && (canFit||CanFit( map, x, y, lt.Z )) ) + return true; + + StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + if ( IsStaticFloor( t.ID ) && (canFit||CanFit( map, x, y, t.Z + (id.Surface ? id.CalcHeight : 0) )) ) + return true; + } + + return false; + } + + private static bool IsFloor( int itemID ) + { + itemID &= TileData.MaxLandValue; + + return ( itemID >= 0x406 && itemID <= 0x51A ); + } + + private static bool IsStaticFloor( int itemID ) + { + return ( itemID >= 0x495 && itemID <= 0x514 ) + || ( itemID >= 0x519 && itemID <= 0x53A ); + } + + private static bool IsDisplayCase( int itemID ) + { + return ( itemID >= 0xB00 && itemID <= 0xB02 ) + || ( itemID >= 0xB06 && itemID <= 0xB0A ) + || ( itemID >= 0xB0D && itemID <= 0xB17 ); + } + + private static void Process( Map map, Rectangle2D[] regions ) + { + m_ShopTable = new Hashtable(); + m_ShopList = new ArrayList(); + + World.Broadcast( 0x35, true, "Generating vendor spawns for {0}, please wait.", map ); + + for ( int i = 0; i < regions.Length; ++i ) + for ( int x = 0; x < map.Width; ++x ) + for ( int y = 0; y < map.Height; ++y ) + CheckPoint( map, regions[i].X + x, regions[i].Y + y ); + + for ( int i = 0; i < m_ShopList.Count; ++i ) + { + ShopInfo si = (ShopInfo)m_ShopList[i]; + + int xTotal = 0; + int yTotal = 0; + + bool hasSpawner = false; + + for ( int j = 0; !hasSpawner && j < si.m_Floor.Count; ++j ) + { + Point2D fp = (Point2D)si.m_Floor[j]; + + xTotal += fp.X; + yTotal += fp.Y; + + IPooledEnumerable eable = map.GetItemsInRange( new Point3D( fp.X, fp.Y, 0 ), 0 ); + + foreach ( Item item in eable ) + { + if ( item is Spawner ) + { + hasSpawner = true; + break; + } + } + + eable.Free(); + + if ( hasSpawner ) + break; + } + + if ( hasSpawner ) + continue; + + int xAvg = xTotal / si.m_Floor.Count; + int yAvg = yTotal / si.m_Floor.Count; + + ArrayList names = new ArrayList(); + ShopFlags flags = si.m_Flags; + + if ( (flags & ShopFlags.Armor) != 0 ) + names.Add( "armurier" ); + + if ( (flags & ShopFlags.MetalWeapon) != 0 ) + names.Add( "forgeron" ); + + if ( (flags & ShopFlags.ArcheryWeapon) != 0 ) + names.Add( "archer" ); + + if ( (flags & ShopFlags.Scroll) != 0 ) + names.Add( "mage" ); + + if ( (flags & ShopFlags.Spellbook) != 0 ) + names.Add( "mage" ); + + if ( (flags & ShopFlags.Bread) != 0 ) + names.Add( "baker" ); + + if ( (flags & ShopFlags.Jewel) != 0 ) + names.Add( "joaillier" ); + + if ( (flags & ShopFlags.Potion) != 0 ) + { + names.Add( "herboriste" ); + names.Add( "alchimiste" ); + names.Add( "mage" ); + } + + if ( (flags & ShopFlags.Reagent) != 0 ) + { + names.Add( "mage" ); + names.Add( "herboriste" ); + } + + if ( (flags & ShopFlags.Clothes) != 0 ) + { + names.Add( "tailleur" ); + names.Add( "tisseur" ); + } + + for ( int j = 0; j < names.Count; ++j ) + { + Point2D cp = Point2D.Zero; + int dist = 100000; + int tz; + + for ( int k = 0; k < si.m_Floor.Count; ++k ) + { + Point2D fp = (Point2D)si.m_Floor[k]; + + int rx = fp.X - xAvg; + int ry = fp.Y - yAvg; + int fd = (int)Math.Sqrt( rx*rx + ry*ry ); + + if ( fd > 0 && fd < 5 ) + fd -= Utility.Random( 10 ); + + if ( fd < dist && GetFloorZ( map, fp.X, fp.Y, out tz ) ) + { + dist = fd; + cp = fp; + } + } + + if ( cp == Point2D.Zero ) + continue; + + int z; + + if ( !GetFloorZ( map, cp.X, cp.Y, out z ) ) + continue; + + new Spawner( 1, 1, 1, 0, 4, (string)names[j] ).MoveToWorld( new Point3D( cp.X, cp.Y, z ), map ); + } + } + + World.Broadcast( 0x35, true, "Generation complete. {0} spawners generated.", m_ShopList.Count ); + } + + private static void CheckPoint( Map map, int x, int y ) + { + if ( IsFloor( map, x, y, true ) ) + CheckFloor( map, x, y ); + } + + private static void CheckFloor( Map map, int x, int y ) + { + StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + if ( IsDisplayCase( tiles[i].ID ) ) + { + ProcessDisplayCase( map, tiles, x, y ); + break; + } + } + } + + [Flags] + private enum ShopFlags + { + None = 0x000, + Armor = 0x001, + MetalWeapon = 0x002, + Jewel = 0x004, + Reagent = 0x008, + Potion = 0x010, + Bread = 0x020, + Clothes = 0x040, + ArcheryWeapon = 0x080, + Scroll = 0x100, + Spellbook = 0x200 + } + + private static bool IsClothes( int itemID ) + { + if ( itemID >= 0x1515 && itemID <= 0x1518 ) + return true; + + if ( itemID >= 0x152E && itemID <= 0x1531 ) + return true; + + if ( itemID >= 0x1537 && itemID <= 0x154C ) + return true; + + if ( itemID >= 0x1EFD && itemID <= 0x1F04 ) + return true; + + if ( itemID >= 0x170B && itemID <= 0x171C ) + return true; + + return false; + } + + private static bool IsArmor( int itemID ) + { + if ( itemID >= 0x13BB && itemID <= 0x13E2 ) + return true; + + if ( itemID >= 0x13E5 && itemID <= 0x13F2 ) + return true; + + if ( itemID >= 0x1408 && itemID <= 0x141A ) + return true; + + if ( itemID >= 0x144E && itemID <= 0x1457 ) + return true; + + return false; + } + + private static bool IsMetalWeapon( int itemID ) + { + if ( itemID >= 0xF43 && itemID <= 0xF4E ) + return true; + + if ( itemID >= 0xF51 && itemID <= 0xF52 ) + return true; + + if ( itemID >= 0xF5C && itemID <= 0xF63 ) + return true; + + if ( itemID >= 0x13AF && itemID <= 0x13B0 ) + return true; + + if ( itemID >= 0x13B5 && itemID <= 0x13BA ) + return true; + + if ( itemID >= 0x13FA && itemID <= 0x13FB ) + return true; + + if ( itemID >= 0x13FE && itemID <= 0x1407 ) + return true; + + if ( itemID >= 0x1438 && itemID <= 0x1443 ) + return true; + + return false; + } + + private static bool IsArcheryWeapon( int itemID ) + { + if ( itemID >= 0xF4F && itemID <= 0xF50 ) + return true; + + if ( itemID >= 0x13B1 && itemID <= 0x13B2 ) + return true; + + if ( itemID >= 0x13FC && itemID <= 0x13FD ) + return true; + + return false; + } + + private static ShopFlags ProcessDisplayedItem( int itemID ) + { + itemID &= TileData.MaxItemValue; + + ShopFlags res = ShopFlags.None; + + ItemData id = TileData.ItemTable[itemID]; + TileFlag flags = id.Flags; + + if ( (flags & TileFlag.Wearable) != 0 ) + { + if ( IsClothes( itemID ) ) + res |= ShopFlags.Clothes; + else if ( IsArmor( itemID ) ) + res |= ShopFlags.Armor; + else if ( IsMetalWeapon( itemID ) ) + res |= ShopFlags.MetalWeapon; + else if ( IsArcheryWeapon( itemID ) ) + res |= ShopFlags.ArcheryWeapon; + } + + if ( itemID == 0x98C || itemID == 0x103B || itemID == 0x103C ) + res |= ShopFlags.Bread; + + if ( itemID >= 0xF0F && itemID <= 0xF30 ) + res |= ShopFlags.Jewel; + + if ( itemID >= 0xEFB && itemID <= 0xF0D ) + res |= ShopFlags.Potion; + + if ( itemID >= 0xF78 && itemID <= 0xF91 ) + res |= ShopFlags.Reagent; + + if ( (itemID >= 0xE35 && itemID <= 0xE3A) || (itemID >= 0xEF4 && itemID <= 0xEF9) || (itemID >= 0x1F2D && itemID <= 0x1F72) ) + res |= ShopFlags.Scroll; + + if ( itemID == 0xE38 || itemID == 0xEFA ) + res |= ShopFlags.Spellbook; + + return res; + } + + private static void ProcessDisplayCase( Map map, StaticTile[] tiles, int x, int y ) + { + ShopFlags flags = ShopFlags.None; + + for ( int i = 0; i < tiles.Length; ++i ) + flags |= ProcessDisplayedItem( tiles[i].ID ); + + if ( flags != ShopFlags.None ) + { + Point2D p = new Point2D( x, y ); + ShopInfo si = (ShopInfo)m_ShopTable[p]; + + if ( si == null ) + { + ArrayList floor = new ArrayList(); + + RecurseFindFloor( map, x, y, floor ); + + if ( floor.Count == 0 ) + return; + + si = new ShopInfo(); + si.m_Flags = flags; + si.m_Floor = floor; + m_ShopList.Add( si ); + + for ( int i = 0; i < floor.Count; ++i ) + m_ShopTable[(Point2D)floor[i]] = si; + } + else + { + si.m_Flags |= flags; + } + } + } + + private static Hashtable m_ShopTable; + private static ArrayList m_ShopList; + + private class ShopInfo + { + public ShopFlags m_Flags; + public ArrayList m_Floor; + } + + private static bool CanFit( Map map, int x, int y, int z ) + { + bool hasSurface = false; + + LandTile lt = map.Tiles.GetLandTile( x, y ); + int lowZ = 0, avgZ = 0, topZ = 0; + + map.GetAverageZ( x, y, ref lowZ, ref avgZ, ref topZ ); + TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + + if ( (landFlags & TileFlag.Impassable) != 0 && topZ > z && (z + 16) > lowZ ) + return false; + else if ( (landFlags & TileFlag.Impassable) == 0 && z == avgZ && !lt.Ignored ) + hasSurface = true; + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles( x, y ); + + bool surface, impassable; + + for ( int i = 0; i < staticTiles.Length; ++i ) + { + if ( IsDisplayCase( staticTiles[i].ID ) ) + continue; + + ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + + surface = id.Surface; + impassable = id.Impassable; + + if ( (surface || impassable) && (staticTiles[i].Z + id.CalcHeight) > z && (z + 16) > staticTiles[i].Z ) + return false; + else if ( surface && !impassable && z == (staticTiles[i].Z + id.CalcHeight) ) + hasSurface = true; + } + + Sector sector = map.GetSector( x, y ); + List items = sector.Items; + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if ( item.AtWorldPoint( x, y ) ) + { + ItemData id = item.ItemData; + surface = id.Surface; + impassable = id.Impassable; + + if ( (surface || impassable) && (item.Z + id.CalcHeight) > z && (z + 16) > item.Z ) + return false; + else if ( surface && !impassable && z == (item.Z + id.CalcHeight) ) + hasSurface = true; + } + } + + return hasSurface; + } + + private static void RecurseFindFloor( Map map, int x, int y, ArrayList floor ) + { + Point2D p = new Point2D( x, y ); + + if ( floor.Contains( p ) ) + return; + + floor.Add( p ); + + for ( int xo = -1; xo <= 1; ++xo ) + { + for ( int yo = -1; yo <= 1; ++yo ) + { + if ( (xo != 0 || yo != 0) && IsFloor( map, x + xo, y + yo, false ) ) + RecurseFindFloor( map, x + xo, y + yo, floor ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/Weather.cs b/Scripts/Misc/Weather.cs new file mode 100644 index 0000000..75eda8a --- /dev/null +++ b/Scripts/Misc/Weather.cs @@ -0,0 +1,394 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Misc +{ + public class Weather + { + private static Map[] m_Facets; + private static Dictionary> m_WeatherByFacet = new Dictionary>(); + + public static void Initialize() + { + m_Facets = new Map[]{ Map.Felucca, Map.Trammel }; + + /* Static weather: + * + * Format: + * AddWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, ); + */ + + // ice island + AddWeather( -15, 100, 5, new Rectangle2D( 3850, 160, 390, 320 ), new Rectangle2D( 3900, 480, 380, 180 ), new Rectangle2D( 4160, 660, 150, 110 ) ); + + // covetous entrance, around vesper and minoc + AddWeather( +15, 50, 5, new Rectangle2D( 2425, 725, 250, 250 ) ); + + // despise entrance, north of britain + AddWeather( +15, 50, 5, new Rectangle2D( 1245, 1045, 250, 250 ) ); + + + /* Dynamic weather: + * + * Format: + * AddDynamicWeather( temperature, chanceOfPercipitation, chanceOfExtremeTemperature, moveSpeed, width, height, bounds ); + */ + + for ( int i = 0; i < 15; ++i ) + AddDynamicWeather( +15, 100, 5, 8, 400, 400, new Rectangle2D( 0, 0, 5120, 4096 ) ); + } + + public static List GetWeatherList( Map facet ) + { + if ( facet == null ) + return null; + + List list = null; + m_WeatherByFacet.TryGetValue( facet, out list ); + + if ( list == null ) + m_WeatherByFacet[facet] = list = new List(); + + return list; + } + + public static void AddDynamicWeather( int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, int moveSpeed, int width, int height, Rectangle2D bounds ) + { + for ( int i = 0; i < m_Facets.Length; ++i ) + { + Rectangle2D area = new Rectangle2D(); + bool isValid = false; + + for ( int j = 0; j < 10; ++j ) + { + area = new Rectangle2D( bounds.X + Utility.Random( bounds.Width - width ), bounds.Y + Utility.Random( bounds.Height - height ), width, height ); + + if ( !CheckWeatherConflict( m_Facets[i], null, area ) ) + isValid = true; + + if ( isValid ) + break; + } + + if ( !isValid ) + continue; + + Weather w = new Weather( m_Facets[i], new Rectangle2D[]{ area }, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, TimeSpan.FromSeconds( 30.0 ) ); + + w.m_Bounds = bounds; + w.m_MoveSpeed = moveSpeed; + } + } + + public static void AddWeather( int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, params Rectangle2D[] area ) + { + for ( int i = 0; i < m_Facets.Length; ++i ) + new Weather( m_Facets[i], area, temperature, chanceOfPercipitation, chanceOfExtremeTemperature, TimeSpan.FromSeconds( 30.0 ) ); + } + + public static bool CheckWeatherConflict( Map facet, Weather exclude, Rectangle2D area ) + { + List list = GetWeatherList( facet ); + + if ( list == null ) + return false; + + for ( int i = 0; i < list.Count; ++i ) + { + Weather w = list[i]; + + if ( w != exclude && w.IntersectsWith( area ) ) + return true; + } + + return false; + } + + private Map m_Facet; + private Rectangle2D[] m_Area; + private int m_Temperature; + private int m_ChanceOfPercipitation; + private int m_ChanceOfExtremeTemperature; + + public Map Facet{ get{ return m_Facet; } } + public Rectangle2D[] Area{ get{ return m_Area; } set{ m_Area = value; } } + public int Temperature{ get{ return m_Temperature; } set{ m_Temperature = value; } } + public int ChanceOfPercipitation{ get{ return m_ChanceOfPercipitation; } set{ m_ChanceOfPercipitation = value; } } + public int ChanceOfExtremeTemperature{ get{ return m_ChanceOfExtremeTemperature; } set{ m_ChanceOfExtremeTemperature = value; } } + + // For dynamic weather: + private Rectangle2D m_Bounds; + private int m_MoveSpeed; + private int m_MoveAngleX, m_MoveAngleY; + + public Rectangle2D Bounds{ get{ return m_Bounds; } set{ m_Bounds = value; } } + public int MoveSpeed{ get{ return m_MoveSpeed; } set{ m_MoveSpeed = value; } } + public int MoveAngleX{ get{ return m_MoveAngleX; } set{ m_MoveAngleX = value; } } + public int MoveAngleY{ get{ return m_MoveAngleY; } set{ m_MoveAngleY = value; } } + + public static bool CheckIntersection( Rectangle2D r1, Rectangle2D r2 ) + { + if ( r1.X >= (r2.X + r2.Width) ) + return false; + + if ( r2.X >= (r1.X + r1.Width) ) + return false; + + if ( r1.Y >= (r2.Y + r2.Height) ) + return false; + + if ( r2.Y >= (r1.Y + r1.Height) ) + return false; + + return true; + } + + public static bool CheckContains( Rectangle2D big, Rectangle2D small ) + { + if ( small.X < big.X ) + return false; + + if ( small.Y < big.Y ) + return false; + + if ( (small.X + small.Width) > (big.X + big.Width) ) + return false; + + if ( (small.Y + small.Height) > (big.Y + big.Height) ) + return false; + + return true; + } + + public virtual bool IntersectsWith( Rectangle2D area ) + { + for ( int i = 0; i < m_Area.Length; ++i ) + { + if ( CheckIntersection( area, m_Area[i] ) ) + return true; + } + + return false; + } + + public Weather( Map facet, Rectangle2D[] area, int temperature, int chanceOfPercipitation, int chanceOfExtremeTemperature, TimeSpan interval ) + { + m_Facet = facet; + m_Area = area; + m_Temperature = temperature; + m_ChanceOfPercipitation = chanceOfPercipitation; + m_ChanceOfExtremeTemperature = chanceOfExtremeTemperature; + + List list = GetWeatherList( facet ); + + if ( list != null ) + list.Add( this ); + + Timer.DelayCall( TimeSpan.FromSeconds( (0.2+(Utility.RandomDouble()*0.8)) * interval.TotalSeconds ), interval, new TimerCallback( OnTick ) ); + } + + public virtual void Reposition() + { + if ( m_Area.Length == 0 ) + return; + + int width = m_Area[0].Width; + int height = m_Area[0].Height; + + Rectangle2D area = new Rectangle2D(); + bool isValid = false; + + for ( int j = 0; j < 10; ++j ) + { + area = new Rectangle2D( m_Bounds.X + Utility.Random( m_Bounds.Width - width ), m_Bounds.Y + Utility.Random( m_Bounds.Height - height ), width, height ); + + if ( !CheckWeatherConflict( m_Facet, this, area ) ) + isValid = true; + + if ( isValid ) + break; + } + + if ( !isValid ) + return; + + m_Area[0] = area; + } + + public virtual void RecalculateMovementAngle() + { + double angle = Utility.RandomDouble() * Math.PI * 2.0; + + double cos = Math.Cos( angle ); + double sin = Math.Sin( angle ); + + m_MoveAngleX = (int)(100 * cos); + m_MoveAngleY = (int)(100 * sin); + } + + public virtual void MoveForward() + { + if ( m_Area.Length == 0 ) + return; + + for ( int i = 0; i < 5; ++i ) // try 5 times to find a valid spot + { + int xOffset = (m_MoveSpeed * m_MoveAngleX) / 100; + int yOffset = (m_MoveSpeed * m_MoveAngleY) / 100; + + Rectangle2D oldArea = m_Area[0]; + Rectangle2D newArea = new Rectangle2D( oldArea.X + xOffset, oldArea.Y + yOffset, oldArea.Width, oldArea.Height ); + + if ( !CheckWeatherConflict( m_Facet, this, newArea ) && CheckContains( m_Bounds, newArea ) ) + { + m_Area[0] = newArea; + break; + } + + RecalculateMovementAngle(); + } + } + + private int m_Stage; + private bool m_Active; + private bool m_ExtremeTemperature; + + public virtual void OnTick() + { + if ( m_Stage == 0 ) + { + m_Active = ( m_ChanceOfPercipitation > Utility.Random( 100 ) ); + m_ExtremeTemperature = ( m_ChanceOfExtremeTemperature > Utility.Random( 100 ) ); + + if ( m_MoveSpeed > 0 ) + { + Reposition(); + RecalculateMovementAngle(); + } + } + + if ( m_Active ) + { + if ( m_Stage > 0 && m_MoveSpeed > 0 ) + MoveForward(); + + int type, density, temperature; + + temperature = m_Temperature; + + if ( m_ExtremeTemperature ) + temperature *= -1; + + if ( m_Stage < 15 ) + { + density = m_Stage * 5; + } + else + { + density = 150 - (m_Stage * 5); + + if ( density < 10 ) + density = 10; + else if ( density > 70 ) + density = 70; + } + + if ( density == 0 ) + type = 0xFE; + else if ( temperature > 0 ) + type = 0; + else + type = 2; + + List states = NetState.Instances; + + Packet weatherPacket = null; + + for ( int i = 0; i < states.Count; ++i ) + { + NetState ns = states[i]; + Mobile mob = ns.Mobile; + + if ( mob == null || mob.Map != m_Facet ) + continue; + + bool contains = ( m_Area.Length == 0 ); + + for ( int j = 0; !contains && j < m_Area.Length; ++j ) + contains = m_Area[j].Contains( mob.Location ); + + if ( !contains ) + continue; + + if ( weatherPacket == null ) + weatherPacket = Packet.Acquire( new Server.Network.Weather( type, density, temperature ) ); + + ns.Send( weatherPacket ); + } + + Packet.Release( weatherPacket ); + } + + m_Stage++; + m_Stage %= 30; + } + } + + public class WeatherMap : MapItem + { + public override string DefaultName + { + get { return "weather map"; } + } + + [Constructable] + public WeatherMap() + { + SetDisplay( 0, 0, 5119, 4095, 400, 400 ); + } + + public override void OnDoubleClick( Mobile from ) + { + Map facet = from.Map; + + if ( facet == null ) + return; + + List list = Weather.GetWeatherList( facet ); + + ClearPins(); + + for ( int i = 0; i < list.Count; ++i ) + { + Weather w = list[i]; + + for ( int j = 0; j < w.Area.Length; ++j ) + AddWorldPin( w.Area[j].X + (w.Area[j].Width/2), w.Area[j].Y + (w.Area[j].Height/2) ); + } + + base.OnDoubleClick( from ); + } + + public WeatherMap( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/WebStatus.cs b/Scripts/Misc/WebStatus.cs new file mode 100644 index 0000000..67376d8 --- /dev/null +++ b/Scripts/Misc/WebStatus.cs @@ -0,0 +1,220 @@ +using System; +using System.IO; +using System.Text; +using Server; +using Server.Network; +using Server.Guilds; +using Server.Mobiles; +using Server.Items; +using System.Globalization; + +namespace Server.Misc +{ + public class StatusPage : Timer + { + public static bool Enabled = true; + + public static void Initialize() + { + if ( Enabled ) + new StatusPage().Start(); + } + + public StatusPage() : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 60.0 ) ) + { + Priority = TimerPriority.FiveSeconds; + } + + private static string Encode( string input ) + { + StringBuilder sb = new StringBuilder( input ); + + sb.Replace( "&", "&" ); + sb.Replace( "<", "<" ); + sb.Replace( ">", ">" ); + sb.Replace( "\"", """ ); + sb.Replace( "'", "'" ); + + return sb.ToString(); + } + + public static string FormatTimeSpan(TimeSpan ts) + { + StringBuilder sb = new StringBuilder(); + int days = ts.Days; + int hours = ts.Hours % 24; + int minutes = ts.Minutes % 60; + int seconds = ts.Seconds % 60; + + if (days > 0) sb.Append(days + " jour" + (days > 1 ? "s " : " ")); + if (hours > 0) sb.Append(hours + " heure" + (hours > 1 ? "s " : " ")); + if (minutes > 0) sb.Append(minutes + " minute" + (minutes > 1 ? "s " : " ")); + if (seconds > 0) sb.Append(seconds + " seconde" + (seconds > 1 ? "s " : " ")); + + return sb.ToString(); + } + + protected override void OnTick() + { + if (!Directory.Exists("web")) + Directory.CreateDirectory("web"); + + using (StreamWriter op = new StreamWriter("web/index.html")) + { + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine("Vivre Server Status"); + op.WriteLine(""); + op.WriteLine(" "); + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine("

Vivre Server Status

"); + + op.WriteLine("

Serveur en ligne depuis : " +FormatTimeSpan(DateTime.Now - Clock.ServerStart) + "
"); + op.WriteLine("Nombre de mobiles : " + World.Mobiles.Count + "
"); + op.WriteLine("Nombre d'objets : " + World.Items.Count + "

"); + + // Scriptiz : ne comptons pas les GM connect�s et cach�s du statut + int hidden = 0; + foreach (NetState ns in Network.NetState.Instances) + { + if (ns != null && ns.Mobile != null) + { + PlayerMobile pm = ns.Mobile as PlayerMobile; + if (pm != null && pm.AccessLevel > AccessLevel.Player && !pm.ShowInStatus) + hidden++; + } + } + op.WriteLine("Joueurs en ligne : " + (Network.NetState.Instances.Count - hidden) + "

"); + //op.WriteLine("Joueurs en ligne : " + Network.NetState.Instances.Count + "

"); + + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine(""); + + bool alter = false; + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + + if (m != null) + { + PlayerMobile pm = m as PlayerMobile; + if (pm != null && !pm.ShowInStatus) + continue; + + Guild g = m.Guild as Guild; + + string cssClass = (alter ? "lightRow" : "darkRow"); + alter = !alter; + op.Write(" "); + } + } + + //op.WriteLine(" "); + op.WriteLine("
NomRégionTemps connecté
"); + + if (g != null) + { + op.Write(Encode(m.Name)); + op.Write(" ["); + + string title = m.GuildTitle; + + if (title != null) + title = title.Trim(); + else + title = ""; + + if (title.Length > 0) + { + op.Write(Encode(title)); + op.Write(", "); + } + + op.Write(Encode(g.Abbreviation)); + + op.Write(']'); + } + else + { + op.Write(Encode(m.Name)); + } + + op.Write(""); + + // Scriptiz : on affiche la r�gion et non la position si c'est un joueur + if (m.AccessLevel == AccessLevel.Player && m.Region != null) + if (m.Region.Name != "") op.Write(Encode(m.Region.Name)); + else op.Write(Encode(m.Map.Name)); + else + { + switch (Utility.Random(7)) + { + case 0: case 1: case 2: + op.Write("Inconnue"); + break; + case 3: case 4: case 5: + op.Write("Green Acres"); + break; + case 6: + op.Write("Dans ton dos"); + break; + } + } + + op.WriteLine(""); + + // Scriptiz : affichage du temps connect� + if(pm != null) + { + TimeSpan sessionTime = DateTime.Now.Subtract(pm.SessionStart); + + string time = ""; + if (sessionTime.TotalMinutes < 60) + { + int minutes = (int)sessionTime.TotalMinutes; + time = minutes + (minutes > 1 ? " minutes" : " minute"); + } + else + { + int hours = (int)sessionTime.TotalHours; + time = hours + (hours > 1 ? " heures" : " heure"); + } + + op.Write(time); + } + + op.WriteLine("
"); + + // Scriptiz : on affiche l'heure QC et FR + DateTime quebecTime = DateTime.UtcNow.Subtract(TimeSpan.FromHours(5)); + DateTime franceTime = DateTime.UtcNow.AddHours(1); + + // Scriptiz : Heure d'�t� + if (TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now)) + { + quebecTime = quebecTime.AddHours(1); + franceTime = franceTime.AddHours(1); + } + + op.WriteLine("

"); + op.Write("Généré le " + quebecTime.ToShortDateString() + " à " + quebecTime.ToShortTimeString()); + op.Write(" (Québec)"); + op.WriteLine("
"); + op.Write("Généré le " + franceTime.ToShortDateString() + " à " + franceTime.ToShortTimeString()); + op.Write(" (France)"); + op.WriteLine("

"); + + // Scriptiz : graphe indiquant les clients connect�s sur le temps + op.WriteLine("


"); + op.WriteLine("\"clients_ot\"

"); + op.WriteLine(" "); + op.WriteLine(""); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/WeightOverloading.cs b/Scripts/Misc/WeightOverloading.cs new file mode 100644 index 0000000..74f1bfc --- /dev/null +++ b/Scripts/Misc/WeightOverloading.cs @@ -0,0 +1,136 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Misc +{ + public enum DFAlgorithm + { + Standard, + PainSpike + } + + public class WeightOverloading + { + public static void Initialize() + { + EventSink.Movement += new MovementEventHandler( EventSink_Movement ); + } + + private static DFAlgorithm m_DFA; + + public static DFAlgorithm DFA + { + get{ return m_DFA; } + set{ m_DFA = value; } + } + + public static void FatigueOnDamage( Mobile m, int damage ) + { + double fatigue = 0.0; + + switch ( m_DFA ) + { + case DFAlgorithm.Standard: + { + fatigue = (damage * (100.0 / m.Hits) * ((double)m.Stam / 100)) - 5.0; + break; + } + case DFAlgorithm.PainSpike: + { + fatigue = (damage * ((100.0 / m.Hits) + ((50.0 + m.Stam) / 100) - 1.0)) - 5.0; + break; + } + } + + if ( fatigue > 0 ) + m.Stam -= (int)fatigue; + } + + public const int OverloadAllowance = 4; // We can be four stones overweight without getting fatigued + + public static int GetMaxWeight( Mobile m ) + { + //return ((( Core.ML && m.Race == Race.Human) ? 100 : 40 ) + (int)(3.5 * m.Str)); + //Moved to core virtual method for use there + + return m.MaxWeight; + } + + public static void EventSink_Movement( MovementEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !from.Alive || from.AccessLevel > AccessLevel.Player ) + return; + + if ( !from.Player ) + { + // Else it won't work on monsters. + Spells.Ninjitsu.DeathStrike.AddStep( from ); + return; + } + + int maxWeight = GetMaxWeight( from ) + OverloadAllowance; + int overWeight = (Mobile.BodyWeight + from.TotalWeight) - maxWeight; + + if ( overWeight > 0 ) + { + from.Stam -= GetStamLoss( from, overWeight, (e.Direction & Direction.Running) != 0 ); + + if ( from.Stam == 0 ) + { + from.SendLocalizedMessage( 500109 ); // You are too fatigued to move, because you are carrying too much weight! + e.Blocked = true; + return; + } + } + + if ( ((from.Stam * 100) / Math.Max( from.StamMax, 1 )) < 10 ) + --from.Stam; + + if ( from.Stam == 0 ) + { + if (from.Female) + from.SendMessage("Vous �tes trop fatigu�e pour bouger"); + else + from.SendMessage("Vous �tes trop fatigu� pour bouger"); + //from.SendLocalizedMessage( 500110 ); // You are too fatigued to move. + e.Blocked = true; + return; + } + + if ( from is PlayerMobile ) + { + int amt = ( from.Mounted ? 48 : 16 ); + PlayerMobile pm = (PlayerMobile)from; + + if ( (++pm.StepsTaken % amt) == 0 ) + --from.Stam; + } + + Spells.Ninjitsu.DeathStrike.AddStep( from ); + } + + public static int GetStamLoss( Mobile from, int overWeight, bool running ) + { + int loss = 5 + (overWeight / 25); + + if ( from.Mounted ) + loss /= 3; + + if ( running ) + loss *= 2; + + return loss; + } + + public static bool IsOverloaded( Mobile m ) + { + if ( !m.Player || !m.Alive || m.AccessLevel > AccessLevel.Player ) + return false; + + return ( (Mobile.BodyWeight + m.TotalWeight) > (GetMaxWeight( m ) + OverloadAllowance) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/WelcomeTimer.cs b/Scripts/Misc/WelcomeTimer.cs new file mode 100644 index 0000000..266d758 --- /dev/null +++ b/Scripts/Misc/WelcomeTimer.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; + +namespace Server.Misc +{ + /// + /// This timer spouts some welcome messages to a user at a set interval. It is used on character creation and login. + /// + public class WelcomeTimer : Timer + { + private Mobile m_Mobile; + private int m_State, m_Count; + + private static string[] m_Messages = ( TestCenter.Enabled ? + new string[] + { + "Welcome to this test shard. You are able to customize your character's stats and skills at anytime to anything you wish. To see the commands to do this just say 'help'.", + "You will find a bank check worth 1,000,000 gold in your bank!", + "A spellbook and a bag of reagents has been placed into your bank box.", + "Various tools have been placed into your bank.", + "Various raw materials like ingots, logs, feathers, hides, bottles, etc, have been placed into your bank.", + "5 unmarked recall runes, 5 Felucca moonstones and 5 Trammel moonstones have been placed into your bank box.", + "One of each level of treasure map has been placed in your bank box.", + "You will find 9000 silver pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", + "You will find 9000 gold pieces deposited into your bank box. Spend it as you see fit and enjoy yourself!", + "A bag of PowerScrolls has been placed in your bank box." + } : + new string[] + { //Yes, this message is a pathetic message, It's suggested that you change it. + "Bienvenue sur Vivre : La Renaissance.", + "Toute l'�quipe vous souhaite une exp�rience agr�able.", + "N'h�sitez pas � utiliser le chat (.c) ou le forum pour toutes questions.", + } ); + + public WelcomeTimer( Mobile m ) : this( m, m_Messages.Length ) + { + } + + public WelcomeTimer( Mobile m, int count ) : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 10.0 ) ) + { + m_Mobile = m; + m_Count = count; + } + + protected override void OnTick() + { + if ( m_State < m_Count ) + m_Mobile.SendMessage( 0x35, m_Messages[m_State++] ); + + if ( m_State == m_Count ) + Stop(); + } + } +} \ No newline at end of file diff --git a/Scripts/Misc/uoamVendors.cs b/Scripts/Misc/uoamVendors.cs new file mode 100644 index 0000000..1c6821d --- /dev/null +++ b/Scripts/Misc/uoamVendors.cs @@ -0,0 +1,353 @@ +using System; +using System.Collections; +using System.IO; +using Server.Mobiles; +using Server.Items; +using Server.Commands; + +// Version 0.8 + +namespace Server +{ + public class UOAMVendorGenerator + { + private static int m_Count; + + //configuration + private const int NPCCount = 2;//2 npcs per type (so a mage spawner will spawn 2 npcs, a alchemist and herbalist spawner will spawn 4 npcs total) + private const int HomeRange = 5;//How far should they wander? + private const bool TotalRespawn = true;//Should we spawn them up right away? + private static TimeSpan MinTime = TimeSpan.FromMinutes( 2.5 );//min spawn time + private static TimeSpan MaxTime = TimeSpan.FromMinutes( 10.0 );//max spawn time + private const int Team = 0;//"team" the npcs are on + + public static void Initialize() + { + CommandSystem.Register( "UOAMVendors", AccessLevel.Administrator, new CommandEventHandler( Generate_OnCommand ) ); + } + + [Usage( "UOAMVendors" )] + [Description( "Generates vendor spawners from Data/Common.MAP (taken from UOAutoMap)" )] + private static void Generate_OnCommand( CommandEventArgs e ) + { + Parse( e.Mobile ); + } + + public static void Parse( Mobile from ) + { + string vendor_path = Path.Combine( Core.BaseDirectory, "Data/Common.map" ); + m_Count = 0; + + if ( File.Exists( vendor_path ) ) + { + ArrayList list = new ArrayList(); + from.SendMessage( "Generating Vendors..." ); + + using ( StreamReader ip = new StreamReader( vendor_path ) ) + { + string line; + + while ( (line = ip.ReadLine()) != null ) + { + int indexOf = line.IndexOf( ':' ); + + if ( indexOf == -1 ) + continue; + + string type = line.Substring( 0, ++indexOf ).Trim(); + string sub = line.Substring( indexOf ).Trim(); + + string[] split = sub.Split( ' ' ); + + if ( split.Length < 3 ) + continue; + + split = new string[]{ type, split[0], split[1], split[2] }; + + switch(split[0].ToLower()) + { + case "-healer:": + PlaceNPC( split[1], split[2], split[3], "Healer", "HealerGuildmaster" ); + break; + case "-baker:": + PlaceNPC( split[1], split[2], split[3], "Baker" ); + break; + case "-vet:": + PlaceNPC( split[1], split[2], split[3], "Veterinarian" ); + break; + case "-gypsymaiden:": + PlaceNPC( split[1], split[2], split[3], "GypsyMaiden" ); + break; + case "-gypsybank:": + PlaceNPC( split[1], split[2], split[3], "GypsyBanker" ); + break; + case "-bank:": + PlaceNPC( split[1], split[2], split[3], "Banker", "Minter" ); + break; + case "-inn:": + PlaceNPC( split[1], split[2], split[3], "Innkeeper" ); + break; + case "-provisioner:": + PlaceNPC( split[1], split[2], split[3], "Provisioner", "Cobbler" ); + break; + case "-tailor:": + PlaceNPC( split[1], split[2], split[3], "Tailor", "Weaver", "TailorGuildmaster" ); + break; + case "-tavern:": + PlaceNPC( split[1], split[2], split[3], "Tavernkeeper", "Waiter", "Cook", "Barkeeper" ); + break; + case "-reagents:": + PlaceNPC( split[1], split[2], split[3], "Herbalist", "Alchemist", "CustomHairstylist" ); + break; + case "-fortuneteller:": + PlaceNPC( split[1], split[2], split[3], "FortuneTeller" ); + break; + case "-holymage:": + PlaceNPC( split[1], split[2], split[3], "HolyMage" ); + break; + case "-chivalrykeeper:": + PlaceNPC( split[1], split[2], split[3], "KeeperOfChivalry" ); + break; + case "-mage:": + PlaceNPC( split[1], split[2], split[3], "Mage", "Alchemist", "MageGuildmaster" ); + break; + case "-arms:": + PlaceNPC( split[1], split[2], split[3], "Armorer", "Weaponsmith" ); + break; + case "-tinker:": + PlaceNPC( split[1], split[2], split[3], "Tinker", "TinkerGuildmaster" ); + break; + case "-gypsystable:": + PlaceNPC( split[1], split[2], split[3], "GypsyAnimalTrainer" ); + break; + case "-stable:": + PlaceNPC( split[1], split[2], split[3], "AnimalTrainer" ); + break; + case "-blacksmith:": + PlaceNPC( split[1], split[2], split[3], "Blacksmith", "BlacksmithGuildmaster" ); + break; + case "-bowyer:": + case "-fletcher:": + PlaceNPC( split[1], split[2], split[3], "Bowyer" ); + break; + case "-carpenter:": + PlaceNPC( split[1], split[2], split[3], "Carpenter", "Architect", "RealEstateBroker" ); + break; + case "-butcher:": + PlaceNPC( split[1], split[2], split[3], "Butcher" ); + break; + case "-jeweler:": + PlaceNPC( split[1], split[2], split[3], "Jeweler" ); + break; + case "-tanner:": + PlaceNPC( split[1], split[2], split[3], "Tanner", "Furtrader" ); + break; + case "-bard:": + PlaceNPC( split[1], split[2], split[3], "Bard", "BardGuildmaster" ); + break; + case "-market:": + PlaceNPC( split[1], split[2], split[3], "Butcher", "Farmer" ); + break; + case "-library:": + PlaceNPC( split[1], split[2], split[3], "Scribe" ); + break; + case "-shipwright:": + PlaceNPC( split[1], split[2], split[3], "Shipwright", "Mapmaker" ); + break; + case "-docks:": + PlaceNPC( split[1], split[2], split[3], "Fisherman" ); + break; + + case "-beekeeper:": + PlaceNPC( split[1], split[2], split[3], "Beekeeper" ); + break; + + + // Guilds & Misc + case "-tinkers guild:": + PlaceNPC( split[1], split[2], split[3], "TinkerGuildmaster" ); + break; + case "-blacksmiths guild:": + PlaceNPC( split[1], split[2], split[3], "BlacksmithGuildmaster" ); + break; + case "-sorcerors guild:": + PlaceNPC( split[1], split[2], split[3], "MageGuildmaster" ); + break; + case "-customs:": break; + case "-painter:": break; + case "-theater:": break; + case "-warriors guild:": + PlaceNPC( split[1], split[2], split[3], "WarriorGuildmaster" ); + break; + case "-archers guild:": + PlaceNPC( split[1], split[2], split[3], "RangerGuildmaster" ); + break; + case "-thieves guild:": + PlaceNPC( split[1], split[2], split[3], "ThiefGuildmaster" ); + break; + case "-miners guild:": + PlaceNPC( split[1], split[2], split[3], "MinerGuildmaster" ); + break; + case "-fishermans guild:": + PlaceNPC( split[1], split[2], split[3], "FisherGuildmaster" ); + break; + case "-merchants guild:": + PlaceNPC( split[1], split[2], split[3], "MerchantGuildmaster" ); + break; + case "-illusionists guild:": break; + case "-armourers guild:": break; + case "-sorcerers guild:": break; + case "-mages guild:": + PlaceNPC( split[1], split[2], split[3], "MageGuildmaster" ); + break; + case "-weapons guild:": break; + case "-bardic guild:": + PlaceNPC( split[1], split[2], split[3], "BardGuildmaster" ); + break; + case "-rogues guild:": + break; + + // Skip + case "+landmark:": + case "-point of interest:": + case "+shrine:": + case "+moongate:": + case "+dungeon:": + case "+scenic:": + case "-gate:": + case "+Body of Water:": + case "+ruins:": + case "+teleporter:": + case "+Terrain:": + case "-exit:": + case "-bridge:": + case "-other:": + case "+champion:": + case "-stairs:": + case "-guild:": + case "+graveyard:": + case "+Island:": + case "+town:": + break; + /*default: + Console.WriteLine(split[0]); + break;*/ + } + } + } + from.SendMessage( "Done, added {0} spawners",m_Count ); + } + else + { + from.SendMessage( "{0} not found!", vendor_path ); + } + } + + public static void PlaceNPC( string sx, string sy, string sm, params string[] types ) + { + if ( types.Length == 0 ) + return; + + int x = Utility.ToInt32( sx ); + int y = Utility.ToInt32( sy ); + int map = Utility.ToInt32( sm ); + + switch ( map ) + { + case 0://Trammel and Felucca + MakeSpawner( types, x, y, Map.Felucca ); + MakeSpawner( types, x, y, Map.Trammel ); + break; + case 1://Felucca + MakeSpawner( types, x, y, Map.Felucca ); + break; + case 2: + MakeSpawner( types, x, y, Map.Trammel ); + break; + case 3: + MakeSpawner( types, x, y, Map.Ilshenar ); + break; + case 4: + MakeSpawner( types, x, y, Map.Malas ); + break; + default: + Console.WriteLine( "UOAM Vendor Parser: Warning, unknown map {0}", map ); + break; + } + } + + public static int GetSpawnerZ( int x, int y, Map map ) + { + int z = map.GetAverageZ( x, y ); + + if ( map.CanFit( x, y, z, 16, false, false, true ) ) + return z; + + for ( int i = 1; i <= 20; ++i ) + { + if ( map.CanFit( x, y, z + i, 16, false, false, true ) ) + return z + i; + + if ( map.CanFit( x, y, z - i, 16, false, false, true ) ) + return z - i; + } + + return z; + } + + private static Queue m_ToDelete = new Queue(); + + public static void ClearSpawners( int x, int y, int z, Map map ) + { + IPooledEnumerable eable = map.GetItemsInRange( new Point3D( x, y, z ), 0 ); + + foreach ( Item item in eable ) + { + if ( item is Spawner && item.Z == z ) + m_ToDelete.Enqueue( item ); + } + + eable.Free(); + + while ( m_ToDelete.Count > 0 ) + ((Item)m_ToDelete.Dequeue()).Delete(); + } + + private static void MakeSpawner( string[] types, int x, int y, Map map ) + { + if ( types.Length == 0 ) + return; + + int z = GetSpawnerZ( x, y, map ); + + ClearSpawners( x, y, z, map ); + + for ( int i = 0; i < types.Length; ++i ) + { + bool isGuildmaster = ( types[i].EndsWith( "Guildmaster" ) ); + + Spawner sp = new Spawner( types[i] ); + + if ( isGuildmaster ) + sp.Count = 1; + else + sp.Count = NPCCount; + + sp.MinDelay = MinTime; + sp.MaxDelay = MaxTime; + sp.Team = Team; + sp.HomeRange = HomeRange; + + sp.MoveToWorld( new Point3D( x, y, z ), map ); + + if ( TotalRespawn ) + { + sp.Respawn(); + sp.BringToHome(); + } + + ++m_Count; + } + } + } +} diff --git a/Scripts/Mobiles/AI/AIControlMobileTarget.cs b/Scripts/Mobiles/AI/AIControlMobileTarget.cs new file mode 100644 index 0000000..82745ec --- /dev/null +++ b/Scripts/Mobiles/AI/AIControlMobileTarget.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Targets +{ + public class AIControlMobileTarget : Target + { + private List m_List; + private OrderType m_Order; + + public OrderType Order { + get { + return m_Order; + } + } + + public AIControlMobileTarget( BaseAI ai, OrderType order ) : base( -1, false, ( order == OrderType.Attack ? TargetFlags.Harmful : TargetFlags.None ) ) + { + m_List = new List(); + m_Order = order; + + AddAI( ai ); + } + + public void AddAI( BaseAI ai ) + { + if ( !m_List.Contains( ai ) ) + m_List.Add( ai ); + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) { + Mobile m = (Mobile)o; + for ( int i = 0; i < m_List.Count; ++i ) + m_List[i].EndPickTarget( from, m, m_Order ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/AnimalAI.cs b/Scripts/Mobiles/AI/AnimalAI.cs new file mode 100644 index 0000000..ed59530 --- /dev/null +++ b/Scripts/Mobiles/AI/AnimalAI.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +// Ideas +// When you run on animals the panic +// When if ( distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills[SkillName.AnimalTaming].Value ) +// More your close, the more it can panic +/* + * AnimalHunterAI, AnimalHidingAI, AnimalDomesticAI... + * + */ + +namespace Server.Mobiles +{ + public class AnimalAI : BaseAI + { + public AnimalAI(BaseCreature m) + : base(m) + { + } + + public override bool DoActionWander() + { + // Old: +#if false + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true)) + { + m_Mobile.DebugSay( "There is something near, I go away" ); + Action = ActionType.Backoff; + } + else if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null ) + { + m_Mobile.DebugSay( "I am hurt or being attacked, I flee" ); + Action = ActionType.Flee; + } + else + { + base.DoActionWander(); + } + + return true; +#endif + + // New, only flee @ 10% + + double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health + { + m_Mobile.DebugSay("I am low on health!"); + Action = ActionType.Flee; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone.."); + + Action = ActionType.Wander; + + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else + { + if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I cannot find {0}", combatant.Name); + + Action = ActionType.Wander; + + return true; + } + else + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + { + double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (hitPercent < 0.1) + { + m_Mobile.DebugSay("I am low on health!"); + Action = ActionType.Flee; + } + } + + return true; + } + + public override bool DoActionBackoff() + { + double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax; + + if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health + { + Action = ActionType.Flee; + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) + { + if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) + { + m_Mobile.DebugSay("Well, here I am safe"); + Action = ActionType.Wander; + } + } + else + { + m_Mobile.DebugSay("I have lost my focus, lets relax"); + Action = ActionType.Wander; + } + } + + return true; + } + + public override bool DoActionFlee() + { + AcquireFocusMob(m_Mobile.RangePerception * 2, m_Mobile.FightMode, true, false, true); + + if (m_Mobile.FocusMob == null) + m_Mobile.FocusMob = m_Mobile.Combatant; + + return base.DoActionFlee(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/ArcherAI.cs b/Scripts/Mobiles/AI/ArcherAI.cs new file mode 100644 index 0000000..24d6289 --- /dev/null +++ b/Scripts/Mobiles/AI/ArcherAI.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Items; + +namespace Server.Mobiles +{ + public class ArcherAI : BaseAI + { + public ArcherAI(BaseCreature m) + : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0} and I will attack", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + return base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + if (m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted || !m_Mobile.Combatant.Alive || m_Mobile.Combatant.IsDeadBondedPet) + { + m_Mobile.DebugSay("My combatant is deleted"); + Action = ActionType.Guard; + return true; + } + + if ((m_Mobile.LastMoveTime + TimeSpan.FromSeconds(1.0)) < DateTime.Now) + { + if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.Weapon.MaxRange)) + { + // Be sure to face the combatant + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location); + } + else + { + if (m_Mobile.Combatant != null) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I am still not in range of {0}", m_Mobile.Combatant.Name); + + if ((int)m_Mobile.GetDistanceToSqrt(m_Mobile.Combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have lost {0}", m_Mobile.Combatant.Name); + + m_Mobile.Combatant = null; + Action = ActionType.Guard; + return true; + } + } + } + } + + // When we have no ammo, we flee + Container pack = m_Mobile.Backpack; + + if (pack == null || pack.FindItemByType(typeof(Arrow)) == null) + { + Action = ActionType.Flee; + return true; + } + + + // At 20% we should check if we must leave + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100 && m_Mobile.CanFlee) + { + bool bFlee = false; + // if my current hits are more than my opponent, i don't care + if (m_Mobile.Combatant != null && m_Mobile.Hits < m_Mobile.Combatant.Hits) + { + int iDiff = m_Mobile.Combatant.Hits - m_Mobile.Hits; + + if (Utility.Random(0, 100) > 10 + iDiff) // 10% to flee + the diff of hits + { + bFlee = true; + } + } + else if (m_Mobile.Combatant != null && m_Mobile.Hits >= m_Mobile.Combatant.Hits) + { + if (Utility.Random(0, 100) > 10) // 10% to flee + { + bFlee = true; + } + } + + if (bFlee) + { + Action = ActionType.Flee; + } + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/BaseAI.cs b/Scripts/Mobiles/AI/BaseAI.cs new file mode 100644 index 0000000..cb7586e --- /dev/null +++ b/Scripts/Mobiles/AI/BaseAI.cs @@ -0,0 +1,2968 @@ +// Search for >>> to find Nerun's changes +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Targets; +using Server.Network; +using Server.Regions; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; +using MoveImpl=Server.Movement.MovementImpl; +using Server.Spells; +using Server.Spells.Spellweaving; + +namespace Server.Mobiles +{ + public enum AIType + { + AI_Use_Default, + AI_Melee, + AI_Animal, + AI_Archer, + AI_Healer, + AI_Vendor, + AI_Mage, + AI_Berserk, + AI_Predator, +// >>> [1st change of 12] + AI_Thief, + AI_OrcScout, // ERICA'S + AI_Ninja, // ERICA'S + AI_Spellbinder, // PAPPA SMURF's +// end 1st + AI_None, + AI_Pomi, + // Myron : AI pour gardes PNJ + AI_VivreGuard, + //Vinds : AI pour assassins paranos. tr�s perfectible, mais a tester en r�el. + AI_Assassin + } + + public enum ActionType + { + Wander, + Combat, + Guard, + Flee, + Backoff, + Interact + } + + public abstract class BaseAI + { + public Timer m_Timer; + protected ActionType m_Action; + private DateTime m_NextStopGuard; + + public BaseCreature m_Mobile; + + public BaseAI( BaseCreature m ) + { + m_Mobile = m; + + m_Timer = new AITimer( this ); + + bool activate; + + if( !m.PlayerRangeSensitive ) + activate = true; + else if( World.Loading ) + activate = false; + else if( m.Map == null || m.Map == Map.Internal || !m.Map.GetSector( m ).Active ) + activate = false; + else + activate = true; + + if( activate ) + m_Timer.Start(); + + Action = ActionType.Wander; + } + + public ActionType Action + { + get + { + return m_Action; + } + set + { + m_Action = value; + OnActionChanged(); + } + } + + public virtual bool WasNamed( string speech ) + { + string name = m_Mobile.Name; + + return (name != null && Insensitive.StartsWith( speech, name )); + } + + private class InternalEntry : ContextMenuEntry + { + private Mobile m_From; + private BaseCreature m_Mobile; + private BaseAI m_AI; + private OrderType m_Order; + + public InternalEntry( Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order ) + : base( number, range ) + { + m_From = from; + m_Mobile = mobile; + m_AI = ai; + m_Order = order; + + if( mobile.IsDeadPet && (order == OrderType.Guard || order == OrderType.Attack || order == OrderType.Transfer || order == OrderType.Drop) ) + Enabled = false; + } + + public override void OnClick() + { + if( !m_Mobile.Deleted && m_Mobile.Controlled && m_From.CheckAlive() ) + { + if( m_Mobile.IsDeadPet && (m_Order == OrderType.Guard || m_Order == OrderType.Attack || m_Order == OrderType.Transfer || m_Order == OrderType.Drop) ) + return; + + bool isOwner = (m_From == m_Mobile.ControlMaster); + bool isFriend = (!isOwner && m_Mobile.IsPetFriend( m_From )); + + if( !isOwner && !isFriend ) + return; + else if( isFriend && m_Order != OrderType.Follow && m_Order != OrderType.Stay && m_Order != OrderType.Stop ) + return; + + switch( m_Order ) + { + case OrderType.Follow: + case OrderType.Attack: + case OrderType.Transfer: + case OrderType.Friend: + case OrderType.Unfriend: + { + if( m_Order == OrderType.Transfer && m_From.HasTrade ) + m_From.SendLocalizedMessage( 1010507 ); // You cannot transfer a pet with a trade pending + else if( m_Order == OrderType.Friend && m_From.HasTrade ) + m_From.SendLocalizedMessage( 1070947 ); // You cannot friend a pet with a trade pending + else + m_AI.BeginPickTarget( m_From, m_Order ); + + break; + } + case OrderType.Release: + { + if( m_Mobile.Summoned ) + goto default; + else + m_From.SendGump( new Gumps.ConfirmReleaseGump( m_From, m_Mobile ) ); + + break; + } +// >>> [2nd change of 12] + case OrderType.Dismiss: + { + if( m_Mobile.Summoned ) + goto default; + else + m_From.SendGump( new Gumps.ConfirmReleaseGump( m_From, m_Mobile ) ); + + break; + } +// end 2nd + default: + { + if( m_Mobile.CheckControlChance( m_From ) ) + m_Mobile.ControlOrder = m_Order; + + break; + } + } + } + } + } + + public virtual void GetContextMenuEntries( Mobile from, List list ) + { + if( from.Alive && m_Mobile.Controlled && from.InRange( m_Mobile, 14 ) ) + { + if( from == m_Mobile.ControlMaster ) + { + // >>> [3rd change of 12] + // In OSI, the right order is Kill-Follow-Guard not Guard-Follow-Kill for both Hire and Pet + list.Add(new InternalEntry(from, 6111, 14, m_Mobile, this, OrderType.Attack)); // Command: Kill + list.Add(new InternalEntry(from, 6108, 14, m_Mobile, this, OrderType.Follow)); // Command: Follow + list.Add(new InternalEntry(from, 6107, 14, m_Mobile, this, OrderType.Guard)); // Command: Guard + // list.Add( new InternalEntry( from, 6107, 14, m_Mobile, this, OrderType.Guard ) ); // Command: Guard + // list.Add( new InternalEntry( from, 6108, 14, m_Mobile, this, OrderType.Follow ) ); // Command: Follow + + if (m_Mobile.CanDrop) + list.Add(new InternalEntry(from, 6109, 14, m_Mobile, this, OrderType.Drop)); // Command: Drop + + // list.Add( new InternalEntry( from, 6111, 14, m_Mobile, this, OrderType.Attack ) ); // Command: Kill + // end 3rd + list.Add( new InternalEntry( from, 6112, 14, m_Mobile, this, OrderType.Stop ) ); // Command: Stop + list.Add( new InternalEntry( from, 6114, 14, m_Mobile, this, OrderType.Stay ) ); // Command: Stay + + if( !m_Mobile.Summoned && !( m_Mobile is GrizzledMare ) ) + { + list.Add( new InternalEntry( from, 6110, 14, m_Mobile, this, OrderType.Friend ) ); // Add Friend + list.Add( new InternalEntry( from, 6099, 14, m_Mobile, this, OrderType.Unfriend ) ); // Remove Friend + list.Add( new InternalEntry( from, 6113, 14, m_Mobile, this, OrderType.Transfer ) ); // Transfer + } + // >>> [4th change of 12] + if (m_Mobile is BaseHire) + {//Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order + //6129 = CliLoc 3006129 + list.Add(new InternalEntry(from, 6129, 14, m_Mobile, this, OrderType.Dismiss)); // Dismiss + } + else + { + list.Add(new InternalEntry(from, 6118, 14, m_Mobile, this, OrderType.Release)); // Release + } + + // list.Add( new InternalEntry( from, 6118, 14, m_Mobile, this, OrderType.Release ) ); + // end 4th + } + else if( m_Mobile.IsPetFriend( from ) ) + { + list.Add( new InternalEntry( from, 6108, 14, m_Mobile, this, OrderType.Follow ) ); // Command: Follow + list.Add( new InternalEntry( from, 6112, 14, m_Mobile, this, OrderType.Stop ) ); // Command: Stop + list.Add( new InternalEntry( from, 6114, 14, m_Mobile, this, OrderType.Stay ) ); // Command: Stay + } + } + } + + public virtual void BeginPickTarget( Mobile from, OrderType order ) + { + if( m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange( m_Mobile, 14 ) || from.Map != m_Mobile.Map ) + return; + + bool isOwner = (from == m_Mobile.ControlMaster); + bool isFriend = (!isOwner && m_Mobile.IsPetFriend( from )); + + if( !isOwner && !isFriend ) + return; + else if( isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop ) + return; + + if( from.Target == null ) + { + // >>> [5th change of 12] + if (order == OrderType.Transfer) + { + if (m_Mobile is BaseHire) + m_Mobile.Say(502037); // Whom do you wish me to work for? + else + from.SendLocalizedMessage(502038); // Click on the person to transfer ownership to. + } + else if (order == OrderType.Friend) + { + if (m_Mobile is BaseHire) + m_Mobile.Say(1005480); // From whom do you wish me to accept orders? + else + from.SendLocalizedMessage(502020); // Click on the player whom you wish to make a co-owner. + } + else if (order == OrderType.Unfriend) + { + if (m_Mobile is BaseHire) + m_Mobile.Say(1070949); // From whom do you wish me to ignore orders? + else + from.SendLocalizedMessage(1070948); // Click on the player whom you wish to remove as a co-owner. + } + else if (order == OrderType.Follow && m_Mobile is BaseHire) + m_Mobile.Say(502026); // Who shall i follow? + /* + if( order == OrderType.Transfer ) + from.SendLocalizedMessage( 502038 ); // Click on the person to transfer ownership to. + else if( order == OrderType.Friend ) + from.SendLocalizedMessage( 502020 ); // Click on the player whom you wish to make a co-owner. + else if( order == OrderType.Unfriend ) + from.SendLocalizedMessage( 1070948 ); // Click on the player whom you wish to remove as a co-owner. + */ + // end 5th + from.Target = new AIControlMobileTarget( this, order ); + } + else if( from.Target is AIControlMobileTarget ) + { + AIControlMobileTarget t = (AIControlMobileTarget)from.Target; + + if( t.Order == order ) + t.AddAI( this ); + } + } + + public virtual void OnAggressiveAction( Mobile aggressor ) + { + Mobile currentCombat = m_Mobile.Combatant; + + if( currentCombat != null && !aggressor.Hidden && currentCombat != aggressor && m_Mobile.GetDistanceToSqrt( currentCombat ) > m_Mobile.GetDistanceToSqrt( aggressor ) ) + m_Mobile.Combatant = aggressor; + } + + public virtual void EndPickTarget( Mobile from, Mobile target, OrderType order ) + { + if( m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange( m_Mobile, 14 ) || from.Map != m_Mobile.Map || !from.CheckAlive() ) + return; + + bool isOwner = (from == m_Mobile.ControlMaster); + bool isFriend = (!isOwner && m_Mobile.IsPetFriend( from )); + + if( !isOwner && !isFriend ) + return; + else if( isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop ) + return; + // >>> [6th change of 12] + if (order == OrderType.Follow && m_Mobile is BaseHire) + m_Mobile.Say(502002); // Very well. + + if (order == OrderType.Transfer) // This MSG is send by Hires and Pets in OSI + from.SendLocalizedMessage(502054); // That's a silly thing to do. + // end 6th + if( order == OrderType.Attack ) + { + if( target is BaseCreature && ((BaseCreature)target).IsScaryToPets && m_Mobile.IsScaredOfScaryThings ) + { + m_Mobile.SayTo( from, "Your pet refuses to attack this creature!" ); + return; + } + + if( (SolenHelper.CheckRedFriendship( from ) && + (target is RedSolenInfiltratorQueen + || target is RedSolenInfiltratorWarrior + || target is RedSolenQueen + || target is RedSolenWarrior + || target is RedSolenWorker)) + || (SolenHelper.CheckBlackFriendship( from ) && + (target is BlackSolenInfiltratorQueen + || target is BlackSolenInfiltratorWarrior + || target is BlackSolenQueen + || target is BlackSolenWarrior + || target is BlackSolenWorker)) ) + { + from.SendAsciiMessage( "You can not force your pet to attack a creature you are protected from." ); + return; + } + + if( target is Factions.BaseFactionGuard ) + { + m_Mobile.SayTo( from, "Your pet refuses to attack the guard." ); + return; + } + } + + if( m_Mobile.CheckControlChance( from ) ) + { + m_Mobile.ControlTarget = target; + m_Mobile.ControlOrder = order; + } + } + + public virtual bool HandlesOnSpeech( Mobile from ) + { + if( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if( from.Alive && m_Mobile.Controlled && m_Mobile.Commandable && (from == m_Mobile.ControlMaster || m_Mobile.IsPetFriend( from )) ) + return true; + + return (from.Alive && from.InRange( m_Mobile.Location, 3 ) && m_Mobile.IsHumanInTown()); + } + + private static SkillName[] m_KeywordTable = new SkillName[] + { + SkillName.Parry, + SkillName.Healing, + SkillName.Hiding, + SkillName.Stealing, + SkillName.Alchemy, + SkillName.AnimalLore, + SkillName.ItemID, + SkillName.ArmsLore, + SkillName.Begging, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Peacemaking, + SkillName.Camping, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.DetectHidden, + SkillName.Discordance,//?? + SkillName.EvalInt, + SkillName.Fishing, + SkillName.Provocation, + SkillName.Lockpicking, + SkillName.Magery, + SkillName.MagicResist, + SkillName.Tactics, + SkillName.Snooping, + SkillName.RemoveTrap, + SkillName.Musicianship, + SkillName.Poisoning, + SkillName.Archery, + SkillName.SpiritSpeak, + SkillName.Tailoring, + SkillName.AnimalTaming, + SkillName.TasteID, + SkillName.Tinkering, + SkillName.Veterinary, + SkillName.Forensics, + SkillName.Herding, + SkillName.Tracking, + SkillName.Stealth, + SkillName.Inscribe, + SkillName.Swords, + SkillName.Macing, + SkillName.Fencing, + SkillName.Wrestling, + SkillName.Lumberjacking, + SkillName.Mining, + SkillName.Meditation + }; + + public virtual void OnSpeech( SpeechEventArgs e ) + { + if( e.Mobile.Alive && e.Mobile.InRange( m_Mobile.Location, 3 ) && m_Mobile.IsHumanInTown() ) + { + if( e.HasKeyword( 0x9D ) && WasNamed( e.Speech ) ) // *move* + { + if( m_Mobile.Combatant != null ) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); + } + else + { + // Excuse me? + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501516 ); + WalkRandomInHome( 2, 2, 1 ); + } + } + else if( e.HasKeyword( 0x9E ) && WasNamed( e.Speech ) ) // *time* + { + if( m_Mobile.Combatant != null ) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); + } + else + { + int generalNumber; + string exactTime; + + Clock.GetTime( m_Mobile, out generalNumber, out exactTime ); + + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, generalNumber ); + } + } + else if( e.HasKeyword( 0x6C ) && WasNamed( e.Speech ) ) // *train + { + if( m_Mobile.Combatant != null ) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); + } + else + { + bool foundSomething = false; + + Skills ourSkills = m_Mobile.Skills; + Skills theirSkills = e.Mobile.Skills; + + for( int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i ) + { + Skill skill = ourSkills[i]; + Skill theirSkill = theirSkills[i]; + + if( skill != null && theirSkill != null && skill.Base >= 60.0 && m_Mobile.CheckTeach( skill.SkillName, e.Mobile ) ) + { + double toTeach = skill.Base / 3.0; + + if( toTeach > 42.0 ) + toTeach = 42.0; + + if( toTeach > theirSkill.Base ) + { + int number = 1043059 + i; + + if( number > 1043107 ) + continue; + + if( !foundSomething ) + m_Mobile.Say( 1043058 ); // I can train the following: + + m_Mobile.Say( number ); + + foundSomething = true; + } + } + } + + if( !foundSomething ) + m_Mobile.Say( 501505 ); // Alas, I cannot teach thee anything. + } + } + else + { + SkillName toTrain = (SkillName)(-1); + + for( int i = 0; toTrain == (SkillName)(-1) && i < e.Keywords.Length; ++i ) + { + int keyword = e.Keywords[i]; + + if( keyword == 0x154 ) + { + toTrain = SkillName.Anatomy; + } + else if( keyword >= 0x6D && keyword <= 0x9C ) + { + int index = keyword - 0x6D; + + if( index >= 0 && index < m_KeywordTable.Length ) + toTrain = m_KeywordTable[index]; + } + } + + if( toTrain != (SkillName)(-1) && WasNamed( e.Speech ) ) + { + if( m_Mobile.Combatant != null ) + { + // I am too busy fighting to deal with thee! + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); + } + else + { + Skills skills = m_Mobile.Skills; + Skill skill = skills[toTrain]; + + if( skill == null || skill.Base < 60.0 || !m_Mobile.CheckTeach( toTrain, e.Mobile ) ) + { + m_Mobile.Say( 501507 ); // 'Tis not something I can teach thee of. + } + else + { + m_Mobile.Teach( toTrain, e.Mobile, 0, false ); + } + } + } + } + } + + if( m_Mobile.Controlled && m_Mobile.Commandable ) + { + m_Mobile.DebugSay( "Listening..." ); + + bool isOwner = (e.Mobile == m_Mobile.ControlMaster); + bool isFriend = (!isOwner && m_Mobile.IsPetFriend( e.Mobile )); + + if( e.Mobile.Alive && (isOwner || isFriend) ) + { + m_Mobile.DebugSay( "It's from my master" ); + + int[] keywords = e.Keywords; + string speech = e.Speech; + + // First, check the all* + for( int i = 0; i < keywords.Length; ++i ) + { + int keyword = keywords[i]; + + switch( keyword ) + { + case 0x164: // all come + { + if( !isOwner ) + break; + + if( m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Come; + } + + return; + } + case 0x165: // all follow + { + BeginPickTarget( e.Mobile, OrderType.Follow ); + return; + } + case 0x166: // all guard + case 0x16B: // all guard me + { + if( !isOwner ) + break; + + if( m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Guard; + } + return; + } + case 0x167: // all stop + { + if( m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stop; + } + return; + } + case 0x168: // all kill + case 0x169: // all attack + { + if( !isOwner ) + break; + + BeginPickTarget( e.Mobile, OrderType.Attack ); + return; + } + case 0x16C: // all follow me + { + if( m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = e.Mobile; + m_Mobile.ControlOrder = OrderType.Follow; + } + return; + } + case 0x170: // all stay + { + if( m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stay; + } + return; + } + } + } + + // No all*, so check *command + for( int i = 0; i < keywords.Length; ++i ) + { + int keyword = keywords[i]; + + switch( keyword ) + { + case 0x155: // *come + { + if( !isOwner ) + break; + + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Come; + } + + return; + } + case 0x156: // *drop + { + if( !isOwner ) + break; + + if( !m_Mobile.IsDeadPet && !m_Mobile.Summoned && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Drop; + } + + return; + } + case 0x15A: // *follow + { + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + BeginPickTarget( e.Mobile, OrderType.Follow ); + + return; + } + case 0x15B: // *friend + { + if( !isOwner ) + break; + + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + if( m_Mobile.Summoned || ( m_Mobile is GrizzledMare ) ) + e.Mobile.SendLocalizedMessage( 1005481 ); // Summoned creatures are loyal only to their summoners. + else if( e.Mobile.HasTrade ) + e.Mobile.SendLocalizedMessage( 1070947 ); // You cannot friend a pet with a trade pending + else + BeginPickTarget( e.Mobile, OrderType.Friend ); + } + + return; + } + case 0x15C: // *guard + { + if( !isOwner ) + break; + + if( !m_Mobile.IsDeadPet && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Guard; + } + + return; + } + case 0x15D: // *kill + case 0x15E: // *attack + { + if( !isOwner ) + break; + + if( !m_Mobile.IsDeadPet && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + BeginPickTarget( e.Mobile, OrderType.Attack ); + + return; + } + case 0x15F: // *patrol + { + if( !isOwner ) + break; + + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Patrol; + } + + return; + } + case 0x161: // *stop + { + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stop; + } + + return; + } + case 0x163: // *follow me + { + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = e.Mobile; + m_Mobile.ControlOrder = OrderType.Follow; + } + + return; + } + case 0x16D: // *release + { + if( !isOwner ) + break; + + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + if( !m_Mobile.Summoned ) + { + e.Mobile.SendGump( new Gumps.ConfirmReleaseGump( e.Mobile, m_Mobile ) ); + } + else + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Release; + } + } + + return; + } + // >>> [7th change of 12] + // 0x175 > 0x1 is default > 75 is the hex number of Speech n. 117, *dismiss + case 0x175: // *dismiss + { + if (!isOwner) + break; + + if (WasNamed(speech) && m_Mobile.CheckControlChance(e.Mobile)) + { + if (!m_Mobile.Summoned) + { + e.Mobile.SendGump(new Gumps.ConfirmReleaseGump(e.Mobile, m_Mobile)); + } + else + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Dismiss; + } + } + + return; + } + // end 7th + case 0x16E: // *transfer + { + if( !isOwner ) + break; + + if( !m_Mobile.IsDeadPet && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + if( m_Mobile.Summoned || ( m_Mobile is GrizzledMare ) ) + e.Mobile.SendLocalizedMessage( 1005487 ); // You cannot transfer ownership of a summoned creature. + else if( e.Mobile.HasTrade ) + e.Mobile.SendLocalizedMessage( 1010507 ); // You cannot transfer a pet with a trade pending + else + BeginPickTarget( e.Mobile, OrderType.Transfer ); + } + + return; + } + case 0x16F: // *stay + { + if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stay; + } + + return; + } + } + } + } + } + else + { + if( e.Mobile.AccessLevel >= AccessLevel.GameMaster ) + { + m_Mobile.DebugSay( "It's from a GM" ); + + if( m_Mobile.FindMyName( e.Speech, true ) ) + { + string[] str = e.Speech.Split( ' ' ); + int i; + + for( i=0; i < str.Length; i++ ) + { + string word = str[i]; + + if( Insensitive.Equals( word, "obey" ) ) + { + m_Mobile.SetControlMaster( e.Mobile ); + + if( m_Mobile.Summoned ) + m_Mobile.SummonMaster = e.Mobile; + + return; + } + } + } + } + } + } + + public virtual bool Think() + { + if( m_Mobile.Deleted ) + return false; + + if( CheckFlee() ) + return true; + + switch( Action ) + { + case ActionType.Wander: + m_Mobile.OnActionWander(); + return DoActionWander(); + + case ActionType.Combat: + m_Mobile.OnActionCombat(); + return DoActionCombat(); + + case ActionType.Guard: + m_Mobile.OnActionGuard(); + return DoActionGuard(); + + case ActionType.Flee: + m_Mobile.OnActionFlee(); + return DoActionFlee(); + + case ActionType.Interact: + m_Mobile.OnActionInteract(); + return DoActionInteract(); + + case ActionType.Backoff: + m_Mobile.OnActionBackoff(); + return DoActionBackoff(); + + default: + return false; + } + } + + public virtual void OnActionChanged() + { + switch( Action ) + { + case ActionType.Wander: + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + m_Mobile.FocusMob = null; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + break; + + case ActionType.Combat: + m_Mobile.Warmode = true; + m_Mobile.FocusMob = null; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + break; + + case ActionType.Guard: + m_Mobile.Warmode = true; + m_Mobile.FocusMob = null; + m_Mobile.Combatant = null; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_NextStopGuard = DateTime.Now + TimeSpan.FromSeconds( 10 ); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + break; + + case ActionType.Flee: + m_Mobile.Warmode = true; + m_Mobile.FocusMob = null; + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + break; + + case ActionType.Interact: + m_Mobile.Warmode = false; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + break; + + case ActionType.Backoff: + m_Mobile.Warmode = false; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + break; + } + } + + public virtual bool OnAtWayPoint() + { + return true; + } + + public virtual bool DoActionWander() + { + if( CheckHerding() ) + { + m_Mobile.DebugSay( "Praise the shepherd!" ); + } + else if( m_Mobile.CurrentWayPoint != null ) + { + WayPoint point = m_Mobile.CurrentWayPoint; + if( (point.X != m_Mobile.Location.X || point.Y != m_Mobile.Location.Y) && point.Map == m_Mobile.Map && point.Parent == null && !point.Deleted ) + { + m_Mobile.DebugSay( "I will move towards my waypoint." ); + DoMove( m_Mobile.GetDirectionTo( m_Mobile.CurrentWayPoint ) ); + } + else if( OnAtWayPoint() ) + { + m_Mobile.DebugSay( "I will go to the next waypoint" ); + m_Mobile.CurrentWayPoint = point.NextPoint; + if( point.NextPoint != null && point.NextPoint.Deleted ) + m_Mobile.CurrentWayPoint = point.NextPoint = point.NextPoint.NextPoint; + } + } + else if( m_Mobile.IsAnimatedDead ) + { + // animated dead follow their master + Mobile master = m_Mobile.SummonMaster; + + if( master != null && master.Map == m_Mobile.Map && master.InRange( m_Mobile, m_Mobile.RangePerception ) ) + MoveTo( master, false, 1 ); + else + WalkRandomInHome( 2, 2, 1 ); + } + else if( CheckMove() ) + { + if( !m_Mobile.CheckIdle() ) + WalkRandomInHome( 2, 2, 1 ); + } + + if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); + } + + return true; + } + + public virtual bool DoActionCombat() + { + if (Core.AOS && CheckHerding()) + { + m_Mobile.DebugSay( "Praise the shepherd!" ); + } + else + { + Mobile c = m_Mobile.Combatant; + + if ( c == null || c.Deleted || c.Map != m_Mobile.Map || !c.Alive || c.IsDeadBondedPet ) + Action = ActionType.Wander; + else + m_Mobile.Direction = m_Mobile.GetDirectionTo( c ); + } + + return true; + } + + public virtual bool DoActionGuard() + { + if (Core.AOS && CheckHerding()) + { + m_Mobile.DebugSay( "Praise the shepherd!" ); + } + else if( DateTime.Now < m_NextStopGuard ) + { + m_Mobile.DebugSay( "I am on guard" ); + //m_Mobile.Turn( Utility.Random(0, 2) - 1 ); + } + else + { + m_Mobile.DebugSay( "I stopped being on guard" ); + Action = ActionType.Wander; + } + + return true; + } + + public virtual bool DoActionFlee() + { + Mobile from = m_Mobile.FocusMob; + + if( from == null || from.Deleted || from.Map != m_Mobile.Map ) + { + m_Mobile.DebugSay( "I have lost him" ); + Action = ActionType.Guard; + return true; + } + + if( WalkMobileRange( from, 1, true, m_Mobile.RangePerception*2, m_Mobile.RangePerception*3 ) ) + { + m_Mobile.DebugSay( "I have fled" ); + Action = ActionType.Guard; + return true; + } + else + { + m_Mobile.DebugSay( "I am fleeing!" ); + } + + return true; + } + + public virtual bool DoActionInteract() + { + return true; + } + + public virtual bool DoActionBackoff() + { + return true; + } + + public virtual bool Obey() + { + if( m_Mobile.Deleted ) + return false; + + switch( m_Mobile.ControlOrder ) + { + case OrderType.None: + return DoOrderNone(); + + case OrderType.Come: + return DoOrderCome(); + + case OrderType.Drop: + return DoOrderDrop(); + + case OrderType.Friend: + return DoOrderFriend(); + + case OrderType.Unfriend: + return DoOrderUnfriend(); + + case OrderType.Guard: + return DoOrderGuard(); + + case OrderType.Attack: + return DoOrderAttack(); + + case OrderType.Patrol: + return DoOrderPatrol(); + + case OrderType.Release: + return DoOrderRelease(); + // >>> [8th change of 12] + case OrderType.Dismiss: + return DoOrderDismiss(); + // end 8th + case OrderType.Stay: + return DoOrderStay(); + + case OrderType.Stop: + return DoOrderStop(); + + case OrderType.Follow: + return DoOrderFollow(); + + case OrderType.Transfer: + return DoOrderTransfer(); + + default: + return false; + } + } + + public virtual void OnCurrentOrderChanged() + { + if( m_Mobile.Deleted || m_Mobile.ControlMaster == null || m_Mobile.ControlMaster.Deleted ) + return; + + switch( m_Mobile.ControlOrder ) + { + case OrderType.None: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.Home = m_Mobile.Location; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Come: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Drop: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = true; + m_Mobile.Combatant = null; + break; + + case OrderType.Friend: + case OrderType.Unfriend: + m_Mobile.ControlMaster.RevealingAction(); + break; + + case OrderType.Guard: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = true; + m_Mobile.Combatant = null; + string petname = String.Format( "{0}", m_Mobile.Name ); + // >>> [9th change of 12] + if (m_Mobile is BaseHire) + m_Mobile.Say(502002); // Very well. + else + m_Mobile.ControlMaster.SendLocalizedMessage(1049671, petname); //~1_PETNAME~ is now guarding you. + // m_Mobile.ControlMaster.SendLocalizedMessage ( 1049671, petname ); //~1_PETNAME~ is now guarding you. + // end 9th + break; + + case OrderType.Attack: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + + m_Mobile.Warmode = true; + m_Mobile.Combatant = null; + break; + + case OrderType.Patrol: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Release: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + // >>> [10th change of 12] + case OrderType.Dismiss: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound(m_Mobile.GetIdleSound()); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + // end 10th + case OrderType.Stay: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Stop: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.Home = m_Mobile.Location; + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + // >>> [11th change of 12] + if (m_Mobile is BaseHire) + m_Mobile.Say(502035); // Very well, I am no longer guarding or following. + // end 11th + break; + + case OrderType.Follow: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + + case OrderType.Transfer: + m_Mobile.ControlMaster.RevealingAction(); + m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; + m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); + + m_Mobile.Warmode = false; + m_Mobile.Combatant = null; + break; + } + } + + public virtual bool DoOrderNone() + { + m_Mobile.DebugSay( "I have no order" ); + + WalkRandomInHome( 3, 2, 1 ); + + if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); + } + else + { + m_Mobile.Warmode = false; + } + + return true; + } + + public virtual bool DoOrderCome() + { + if( m_Mobile.ControlMaster != null && !m_Mobile.ControlMaster.Deleted ) + { + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( m_Mobile.ControlMaster ); + + if( iCurrDist > m_Mobile.RangePerception ) + { + m_Mobile.DebugSay( "I have lost my master. I stay here" ); + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + } + else + { + m_Mobile.DebugSay( "My master told me come" ); + + // Not exactly OSI style, but better than nothing. + bool bRun = (iCurrDist > 5); + + if( WalkMobileRange( m_Mobile.ControlMaster, 1, bRun, 0, 1 ) ) + { + if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); + } + else + { + if (Core.AOS) + m_Mobile.CurrentSpeed = 0.1; + } + } + } + } + + return true; + } + + public virtual bool DoOrderDrop() + { + if( m_Mobile.IsDeadPet || !m_Mobile.CanDrop ) + return true; + + m_Mobile.DebugSay( "I drop my stuff for my master" ); + + Container pack = m_Mobile.Backpack; + + if( pack != null ) + { + List list = pack.Items; + + for( int i = list.Count - 1; i >= 0; --i ) + if( i < list.Count ) + list[i].MoveToWorld( m_Mobile.Location, m_Mobile.Map ); + } + + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + + return true; + } + + public virtual bool CheckHerding() + { + IPoint2D target = m_Mobile.TargetLocation; + + if ( target == null ) + return false; // Creature is not being herded + + double distance = m_Mobile.GetDistanceToSqrt( target ); + + if( distance < 1 || distance > 15 ) + { + if( distance < 1 && target.X == 1076 && target.Y == 450 && (m_Mobile is HordeMinionFamiliar) ) + { + PlayerMobile pm = m_Mobile.ControlMaster as PlayerMobile; + + if( pm != null ) + { + QuestSystem qs = pm.Quest; + + if( qs is DarkTidesQuest ) + { + QuestObjective obj = qs.FindObjective( typeof( FetchAbraxusScrollObjective ) ); + + if( obj != null && !obj.Completed ) + { + m_Mobile.AddToBackpack( new ScrollOfAbraxus() ); + obj.Complete(); + } + } + } + } + + m_Mobile.TargetLocation = null; + return false; // At the target or too far away + } + + DoMove( m_Mobile.GetDirectionTo( target ) ); + + return true; + } + + public virtual bool DoOrderFollow() + { + if( CheckHerding() ) + { + m_Mobile.DebugSay( "Praise the shepherd!" ); + } + else if( m_Mobile.ControlTarget != null && !m_Mobile.ControlTarget.Deleted && m_Mobile.ControlTarget != m_Mobile ) + { + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( m_Mobile.ControlTarget ); + + if( iCurrDist > m_Mobile.RangePerception ) + { + m_Mobile.DebugSay( "I have lost the one to follow. I stay here" ); + + if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); + } + else + { + m_Mobile.Warmode = false; + } + } + else + { + m_Mobile.DebugSay( "My master told me to follow: {0}", m_Mobile.ControlTarget.Name ); + + // Not exactly OSI style, but better than nothing. + bool bRun = (iCurrDist > 5); + + if( WalkMobileRange( m_Mobile.ControlTarget, 1, bRun, 0, 1 ) ) + { + if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) + { + m_Mobile.Warmode = true; + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); + } + else + { + m_Mobile.Warmode = false; + m_Mobile.CurrentSpeed = 0.1; + } + } + } + } + else + { + m_Mobile.DebugSay( "I have nobody to follow" ); + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + } + + return true; + } + + public virtual bool DoOrderFriend() + { + Mobile from = m_Mobile.ControlMaster; + Mobile to = m_Mobile.ControlTarget; + + if( from == null || to == null || from == to || from.Deleted || to.Deleted || !to.Player ) + { + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 502039 ); // *looks confused* + } + else + { + bool youngFrom = from is PlayerMobile ? ((PlayerMobile)from).Young : false; + bool youngTo = to is PlayerMobile ? ((PlayerMobile)to).Young : false; + + if( youngFrom && !youngTo ) + { + from.SendLocalizedMessage( 502040 ); // As a young player, you may not friend pets to older players. + } + else if( !youngFrom && youngTo ) + { + from.SendLocalizedMessage( 502041 ); // As an older player, you may not friend pets to young players. + } + else if( from.CanBeBeneficial( to, true ) ) + { + NetState fromState = from.NetState, toState = to.NetState; + + if( fromState != null && toState != null ) + { + if( from.HasTrade ) + { + from.SendLocalizedMessage( 1070947 ); // You cannot friend a pet with a trade pending + } + else if( to.HasTrade ) + { + to.SendLocalizedMessage( 1070947 ); // You cannot friend a pet with a trade pending + } + else if( m_Mobile.IsPetFriend( to ) ) + { + from.SendLocalizedMessage( 1049691 ); // That person is already a friend. + } + else if( !m_Mobile.AllowNewPetFriend ) + { + from.SendLocalizedMessage( 1005482 ); // Your pet does not seem to be interested in making new friends right now. + } + else + { + // ~1_NAME~ will now accept movement commands from ~2_NAME~. + from.SendLocalizedMessage( 1049676, String.Format( "{0}\t{1}", m_Mobile.Name, to.Name ) ); + + /* ~1_NAME~ has granted you the ability to give orders to their pet ~2_PET_NAME~. + * This creature will now consider you as a friend. + */ + to.SendLocalizedMessage( 1043246, String.Format( "{0}\t{1}", from.Name, m_Mobile.Name ) ); + + m_Mobile.AddPetFriend( to ); + + m_Mobile.ControlTarget = to; + m_Mobile.ControlOrder = OrderType.Follow; + + return true; + } + } + } + } + + m_Mobile.ControlTarget = from; + m_Mobile.ControlOrder = OrderType.Follow; + + return true; + } + + public virtual bool DoOrderUnfriend() + { + Mobile from = m_Mobile.ControlMaster; + Mobile to = m_Mobile.ControlTarget; + + if( from == null || to == null || from == to || from.Deleted || to.Deleted || !to.Player ) + { + m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 502039 ); // *looks confused* + } + else if( !m_Mobile.IsPetFriend( to ) ) + { + from.SendLocalizedMessage( 1070953 ); // That person is not a friend. + } + else + { + // ~1_NAME~ will no longer accept movement commands from ~2_NAME~. + from.SendLocalizedMessage( 1070951, String.Format( "{0}\t{1}", m_Mobile.Name, to.Name ) ); + + /* ~1_NAME~ has no longer granted you the ability to give orders to their pet ~2_PET_NAME~. + * This creature will no longer consider you as a friend. + */ + to.SendLocalizedMessage( 1070952, String.Format( "{0}\t{1}", from.Name, m_Mobile.Name ) ); + + m_Mobile.RemovePetFriend( to ); + } + + m_Mobile.ControlTarget = from; + m_Mobile.ControlOrder = OrderType.Follow; + + return true; + } + + public virtual bool DoOrderGuard() + { + if( m_Mobile.IsDeadPet ) + return true; + + Mobile controlMaster = m_Mobile.ControlMaster; + + if( controlMaster == null || controlMaster.Deleted ) + return true; + + Mobile combatant = m_Mobile.Combatant; + + List aggressors = controlMaster.Aggressors; + + if( aggressors.Count > 0 ) + { + for( int i = 0; i < aggressors.Count; ++i ) + { + AggressorInfo info = aggressors[i]; + Mobile attacker = info.Attacker; + + if( attacker != null && !attacker.Deleted && attacker.GetDistanceToSqrt( m_Mobile ) <= m_Mobile.RangePerception ) + { + if( combatant == null || attacker.GetDistanceToSqrt( controlMaster ) < combatant.GetDistanceToSqrt( controlMaster ) ) + combatant = attacker; + } + } + + if( combatant != null ) + m_Mobile.DebugSay( "Crap, my master has been attacked! I will attack one of those bastards!" ); + } + + if( combatant != null && combatant != m_Mobile && combatant != m_Mobile.ControlMaster && !combatant.Deleted && combatant.Alive && !combatant.IsDeadBondedPet && m_Mobile.CanSee( combatant ) && m_Mobile.CanBeHarmful( combatant, false ) && combatant.Map == m_Mobile.Map ) + { + m_Mobile.DebugSay( "Guarding from target..." ); + + m_Mobile.Combatant = combatant; + m_Mobile.FocusMob = combatant; + Action = ActionType.Combat; + + /* + * We need to call Think() here or spell casting monsters will not use + * spells when guarding because their target is never processed. + */ + Think(); + } + else + { + m_Mobile.DebugSay( "Nothing to guard from" ); + + m_Mobile.Warmode = false; + if (Core.AOS) + m_Mobile.CurrentSpeed = 0.1; + + WalkMobileRange( controlMaster, 1, false, 0, 1 ); + } + + return true; + } + + public virtual bool DoOrderAttack() + { + if( m_Mobile.IsDeadPet ) + return true; + + if( m_Mobile.ControlTarget == null || m_Mobile.ControlTarget.Deleted || m_Mobile.ControlTarget.Map != m_Mobile.Map || !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet ) + { + m_Mobile.DebugSay( "I think he might be dead. He's not anywhere around here at least. That's cool. I'm glad he's dead." ); + + if (Core.AOS) + { + m_Mobile.ControlTarget = m_Mobile.ControlMaster; + m_Mobile.ControlOrder = OrderType.Follow; + } + else + { + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.None; + } + + if( m_Mobile.FightMode == FightMode.Closest || m_Mobile.FightMode == FightMode.Aggressor ) + { + Mobile newCombatant = null; + double newScore = 0.0; + + foreach( Mobile aggr in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) ) + { + if( !m_Mobile.CanSee( aggr ) || aggr.Combatant != m_Mobile ) + continue; + + if( aggr.IsDeadBondedPet || !aggr.Alive ) + continue; + + double aggrScore = m_Mobile.GetFightModeRanking( aggr, FightMode.Closest, false ); + + if( (newCombatant == null || aggrScore > newScore) && m_Mobile.InLOS( aggr ) ) + { + newCombatant = aggr; + newScore = aggrScore; + } + } + + if( newCombatant != null ) + { + m_Mobile.ControlTarget = newCombatant; + m_Mobile.ControlOrder = OrderType.Attack; + m_Mobile.Combatant = newCombatant; + m_Mobile.DebugSay( "But -that- is not dead. Here we go again..." ); + Think(); + } + } + } + else + { + m_Mobile.DebugSay( "Attacking target..." ); + Think(); + } + + return true; + } + + public virtual bool DoOrderPatrol() + { + m_Mobile.DebugSay( "This order is not yet coded" ); + return true; + } + + public virtual bool DoOrderRelease() + { + m_Mobile.DebugSay( "I have been released" ); + + m_Mobile.PlaySound( m_Mobile.GetAngerSound() ); + + m_Mobile.SetControlMaster( null ); + m_Mobile.SummonMaster = null; + + m_Mobile.BondingBegin = DateTime.MinValue; + m_Mobile.OwnerAbandonTime = DateTime.MinValue; + m_Mobile.IsBonded = false; + + SpawnEntry se = m_Mobile.Spawner as SpawnEntry; + if( se != null && se.HomeLocation != Point3D.Zero ) + { + m_Mobile.Home = se.HomeLocation; + m_Mobile.RangeHome = se.HomeRange; + } + + if( m_Mobile.DeleteOnRelease || m_Mobile.IsDeadPet ) + m_Mobile.Delete(); + + m_Mobile.BeginDeleteTimer(); + m_Mobile.DropBackpack(); + + return true; + } + // >>> [12th change of 12] + public virtual bool DoOrderDismiss() + { + m_Mobile.DebugSay("I have been dismissed"); + + m_Mobile.PlaySound(m_Mobile.GetAngerSound()); + + m_Mobile.Say(502034); // I thank thee for thy kindness! + m_Mobile.Say(502005); // I quit. + + m_Mobile.SetControlMaster(null); + m_Mobile.SummonMaster = null; + + m_Mobile.BondingBegin = DateTime.MinValue; + m_Mobile.OwnerAbandonTime = DateTime.MinValue; + m_Mobile.IsBonded = false; + + SpawnEntry se = m_Mobile.Spawner as SpawnEntry; + if (se != null && se.HomeLocation != Point3D.Zero) + { + m_Mobile.Home = se.HomeLocation; + m_Mobile.RangeHome = se.HomeRange; + } + + if (m_Mobile.DeleteOnRelease || m_Mobile.IsDeadPet) + m_Mobile.Delete(); + + m_Mobile.BeginDeleteTimer(); + + return true; + } + // end 12th + public virtual bool DoOrderStay() + { + if( CheckHerding() ) + m_Mobile.DebugSay( "Praise the shepherd!" ); + else + m_Mobile.DebugSay( "My master told me to stay" ); + + //m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.ControlMaster ); + + return true; + } + + public virtual bool DoOrderStop() + { + if( m_Mobile.ControlMaster == null || m_Mobile.ControlMaster.Deleted ) + return true; + + m_Mobile.DebugSay( "My master told me to stop." ); + + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.ControlMaster ); + m_Mobile.Home = m_Mobile.Location; + + m_Mobile.ControlTarget = null; + + if( Core.ML ) + { + WalkRandomInHome( 3, 2, 1 ); + } + else + { + m_Mobile.ControlOrder = OrderType.None; + } + + return true; + } + + private class TransferItem : Item + { + public static bool IsInCombat( BaseCreature creature ) + { + return (creature != null && (creature.Aggressors.Count > 0 || creature.Aggressed.Count > 0)); + } + + private BaseCreature m_Creature; + + public TransferItem( BaseCreature creature ) + : base( ShrinkTable.Lookup( creature ) ) + { + m_Creature = creature; + + Movable = false; + + if( !Core.AOS ) + { + Name = creature.Name; + } + else if( this.ItemID == ShrinkTable.DefaultItemID || creature.GetType().IsDefined( typeof( FriendlyNameAttribute ), false ) || creature is Reptalon ) + Name = FriendlyNameAttribute.GetFriendlyNameFor( creature.GetType() ).ToString(); + + //(As Per OSI)No name. Normally, set by the ItemID of the Shrink Item unless we either explicitly set it with an Attribute, or, no lookup found + + Hue = creature.Hue & 0x0FFF; + } + + public TransferItem( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1041603 ); // This item represents a pet currently in consideration for trade + list.Add( 1041601, m_Creature.Name ); // Pet Name: ~1_val~ + + if ( m_Creature.ControlMaster != null ) + list.Add( 1041602, m_Creature.ControlMaster.Name ); // Owner: ~1_val~ + } + + public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if( !base.AllowSecureTrade( from, to, newOwner, accepted ) ) + return false; + + if( Deleted || m_Creature == null || m_Creature.Deleted || m_Creature.ControlMaster != from || !from.CheckAlive() || !to.CheckAlive() ) + return false; + + if( from.Map != m_Creature.Map || !from.InRange( m_Creature, 14 ) ) + return false; + + bool youngFrom = from is PlayerMobile ? ((PlayerMobile)from).Young : false; + bool youngTo = to is PlayerMobile ? ((PlayerMobile)to).Young : false; + + if( accepted && youngFrom && !youngTo ) + { + from.SendLocalizedMessage( 502051 ); // As a young player, you may not transfer pets to older players. + } + else if( accepted && !youngFrom && youngTo ) + { + from.SendLocalizedMessage( 502052 ); // As an older player, you may not transfer pets to young players. + } + else if( accepted && !m_Creature.CanBeControlledBy( to ) ) + { + string args = String.Format( "{0}\t{1}\t ", to.Name, from.Name ); + + from.SendLocalizedMessage( 1043248, args ); // The pet refuses to be transferred because it will not obey ~1_NAME~.~3_BLANK~ + to.SendLocalizedMessage( 1043249, args ); // The pet will not accept you as a master because it does not trust you.~3_BLANK~ + + return false; + } + else if( accepted && !m_Creature.CanBeControlledBy( from ) ) + { + string args = String.Format( "{0}\t{1}\t ", to.Name, from.Name ); + + from.SendLocalizedMessage( 1043250, args ); // The pet refuses to be transferred because it will not obey you sufficiently.~3_BLANK~ + to.SendLocalizedMessage( 1043251, args ); // The pet will not accept you as a master because it does not trust ~2_NAME~.~3_BLANK~ + } + else if( accepted && (to.Followers + m_Creature.ControlSlots) > to.FollowersMax ) + { + to.SendLocalizedMessage( 1049607 ); // You have too many followers to control that creature. + + return false; + } + else if( accepted && IsInCombat( m_Creature ) ) + { + from.SendMessage( "You may not transfer a pet that has recently been in combat." ); + to.SendMessage( "The pet may not be transfered to you because it has recently been in combat." ); + + return false; + } + + return true; + } + + public override void OnSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if( Deleted ) + return; + + Delete(); + + if( m_Creature == null || m_Creature.Deleted || m_Creature.ControlMaster != from || !from.CheckAlive() || !to.CheckAlive() ) + return; + + if( from.Map != m_Creature.Map || !from.InRange( m_Creature, 14 ) ) + return; + + if( accepted ) + { + if( m_Creature.SetControlMaster( to ) ) + { + if( m_Creature.Summoned ) + m_Creature.SummonMaster = to; + + m_Creature.ControlTarget = to; + m_Creature.ControlOrder = OrderType.Follow; + + m_Creature.BondingBegin = DateTime.MinValue; + m_Creature.OwnerAbandonTime = DateTime.MinValue; + m_Creature.IsBonded = false; + + m_Creature.PlaySound( m_Creature.GetIdleSound() ); + + string args = String.Format( "{0}\t{1}\t{2}", from.Name, m_Creature.Name, to.Name ); + + from.SendLocalizedMessage( 1043253, args ); // You have transferred your pet to ~3_GETTER~. + to.SendLocalizedMessage( 1043252, args ); // ~1_NAME~ has transferred the allegiance of ~2_PET_NAME~ to you. + } + } + } + } + + public virtual bool DoOrderTransfer() + { + if( m_Mobile.IsDeadPet ) + return true; + + Mobile from = m_Mobile.ControlMaster; + Mobile to = m_Mobile.ControlTarget; + + if( from != to && from != null && !from.Deleted && to != null && !to.Deleted && to.Player ) + { + m_Mobile.DebugSay( "Begin transfer with {0}", to.Name ); + + bool youngFrom = from is PlayerMobile ? ((PlayerMobile)from).Young : false; + bool youngTo = to is PlayerMobile ? ((PlayerMobile)to).Young : false; + + if( youngFrom && !youngTo ) + { + from.SendLocalizedMessage( 502051 ); // As a young player, you may not transfer pets to older players. + } + else if( !youngFrom && youngTo ) + { + from.SendLocalizedMessage( 502052 ); // As an older player, you may not transfer pets to young players. + } + else if( !m_Mobile.CanBeControlledBy( to ) ) + { + string args = String.Format( "{0}\t{1}\t ", to.Name, from.Name ); + + from.SendLocalizedMessage( 1043248, args ); // The pet refuses to be transferred because it will not obey ~1_NAME~.~3_BLANK~ + to.SendLocalizedMessage( 1043249, args ); // The pet will not accept you as a master because it does not trust you.~3_BLANK~ + } + else if( !m_Mobile.CanBeControlledBy( from ) ) + { + string args = String.Format( "{0}\t{1}\t ", to.Name, from.Name ); + + from.SendLocalizedMessage( 1043250, args ); // The pet refuses to be transferred because it will not obey you sufficiently.~3_BLANK~ + to.SendLocalizedMessage( 1043251, args ); // The pet will not accept you as a master because it does not trust ~2_NAME~.~3_BLANK~ + } + else if( TransferItem.IsInCombat( m_Mobile ) ) + { + from.SendMessage( "You may not transfer a pet that has recently been in combat." ); + to.SendMessage( "The pet may not be transfered to you because it has recently been in combat." ); + } + else + { + NetState fromState = from.NetState, toState = to.NetState; + + if( fromState != null && toState != null ) + { + if( from.HasTrade ) + { + from.SendLocalizedMessage( 1010507 ); // You cannot transfer a pet with a trade pending + } + else if( to.HasTrade ) + { + to.SendLocalizedMessage( 1010507 ); // You cannot transfer a pet with a trade pending + } + else + { + Container c = fromState.AddTrade( toState ); + c.DropItem( new TransferItem( m_Mobile ) ); + } + } + } + } + + m_Mobile.ControlTarget = null; + m_Mobile.ControlOrder = OrderType.Stay; + + return true; + } + + public virtual bool DoBardPacified() + { + if( DateTime.Now < m_Mobile.BardEndTime ) + { + m_Mobile.DebugSay( "I am pacified, I wait" ); + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + + } + else + { + m_Mobile.DebugSay( "I'm not pacified any longer" ); + m_Mobile.BardPacified = false; + } + + return true; + } + + public virtual bool DoBardProvoked() + { + if( DateTime.Now >= m_Mobile.BardEndTime && (m_Mobile.BardMaster == null || m_Mobile.BardMaster.Deleted || m_Mobile.BardMaster.Map != m_Mobile.Map || m_Mobile.GetDistanceToSqrt( m_Mobile.BardMaster ) > m_Mobile.RangePerception) ) + { + m_Mobile.DebugSay( "I have lost my provoker" ); + m_Mobile.BardProvoked = false; + m_Mobile.BardMaster = null; + m_Mobile.BardTarget = null; + + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + } + else + { + if( m_Mobile.BardTarget == null || m_Mobile.BardTarget.Deleted || m_Mobile.BardTarget.Map != m_Mobile.Map || m_Mobile.GetDistanceToSqrt( m_Mobile.BardTarget ) > m_Mobile.RangePerception ) + { + m_Mobile.DebugSay( "I have lost my provoke target" ); + m_Mobile.BardProvoked = false; + m_Mobile.BardMaster = null; + m_Mobile.BardTarget = null; + + m_Mobile.Combatant = null; + m_Mobile.Warmode = false; + } + else + { + m_Mobile.Combatant = m_Mobile.BardTarget; + m_Action = ActionType.Combat; + + m_Mobile.OnThink(); + Think(); + } + } + + return true; + } + + public virtual void WalkRandom( int iChanceToNotMove, int iChanceToDir, int iSteps ) + { + if( m_Mobile.Deleted || m_Mobile.DisallowAllMoves ) + return; + + for( int i=0; i 1.0 ) + offset = 1.0; + + offset = 1.0 - offset; + + delay += ( offset * 0.8 ); + } + + if( delay < 0.0 ) + delay = 0.0; + + if (double.IsNaN(delay)) + { + using (StreamWriter op = new StreamWriter("nan_transform.txt", true)) + { + op.WriteLine(String.Format("NaN in TransformMoveDelay: {0}, {1}, {2}, {3}", DateTime.Now, this.GetType().ToString(), m_Mobile == null ? "null" : m_Mobile.GetType().ToString(), m_Mobile.HitsMax)); + } + + return 1.0; + } + + return delay; + } + + private DateTime m_NextMove; + + public DateTime NextMove + { + get { return m_NextMove; } + set { m_NextMove = value; } + } + + public virtual bool CheckMove() + { + return (DateTime.Now >= m_NextMove); + } + + public virtual bool DoMove( Direction d ) + { + return DoMove( d, false ); + } + + public virtual bool DoMove( Direction d, bool badStateOk ) + { + MoveResult res = DoMoveImpl( d ); + + return (res == MoveResult.Success || res == MoveResult.SuccessAutoTurn || (badStateOk && res == MoveResult.BadState)); + } + + private static Queue m_Obstacles = new Queue(); + + public virtual MoveResult DoMoveImpl( Direction d ) + { + if( m_Mobile.Deleted || m_Mobile.Frozen || m_Mobile.Paralyzed || (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.DisallowAllMoves ) + return MoveResult.BadState; + else if( !CheckMove() ) + return MoveResult.BadState; + + // This makes them always move one step, never any direction changes + m_Mobile.Direction = d; + + TimeSpan delay = TimeSpan.FromSeconds( TransformMoveDelay( m_Mobile.CurrentSpeed ) ); + + m_NextMove += delay; + + if( m_NextMove < DateTime.Now ) + m_NextMove = DateTime.Now; + + m_Mobile.Pushing = false; + + MoveImpl.IgnoreMovableImpassables = (m_Mobile.CanMoveOverObstacles && !m_Mobile.CanDestroyObstacles); + + if( (m_Mobile.Direction & Direction.Mask) != (d & Direction.Mask) ) + { + bool v = m_Mobile.Move( d ); + + MoveImpl.IgnoreMovableImpassables = false; + return (v ? MoveResult.Success : MoveResult.Blocked); + } + else if( !m_Mobile.Move( d ) ) + { + bool wasPushing = m_Mobile.Pushing; + + bool blocked = true; + + bool canOpenDoors = m_Mobile.CanOpenDoors; + bool canDestroyObstacles = m_Mobile.CanDestroyObstacles; + + if( canOpenDoors || canDestroyObstacles ) + { + m_Mobile.DebugSay( "My movement was blocked, I will try to clear some obstacles." ); + + Map map = m_Mobile.Map; + + if( map != null ) + { + int x = m_Mobile.X, y = m_Mobile.Y; + Movement.Movement.Offset( d, ref x, ref y ); + + int destroyables = 0; + + IPooledEnumerable eable = map.GetItemsInRange( new Point3D( x, y, m_Mobile.Location.Z ), 1 ); + + foreach( Item item in eable ) + { + if( canOpenDoors && item is BaseDoor && (item.Z + item.ItemData.Height) > m_Mobile.Z && (m_Mobile.Z + 16) > item.Z ) + { + if( item.X != x || item.Y != y ) + continue; + + BaseDoor door = (BaseDoor)item; + + if( !door.Locked || !door.UseLocks() ) + m_Obstacles.Enqueue( door ); + + if( !canDestroyObstacles ) + break; + } + else if( canDestroyObstacles && item.Movable && item.ItemData.Impassable && (item.Z + item.ItemData.Height) > m_Mobile.Z && (m_Mobile.Z + 16) > item.Z ) + { + if( !m_Mobile.InRange( item.GetWorldLocation(), 1 ) ) + continue; + + m_Obstacles.Enqueue( item ); + ++destroyables; + } + } + + eable.Free(); + + if( destroyables > 0 ) + Effects.PlaySound( new Point3D( x, y, m_Mobile.Z ), m_Mobile.Map, 0x3B3 ); + + if( m_Obstacles.Count > 0 ) + blocked = false; // retry movement + + while( m_Obstacles.Count > 0 ) + { + Item item = (Item)m_Obstacles.Dequeue(); + + if( item is BaseDoor ) + { + m_Mobile.DebugSay( "Little do they expect, I've learned how to open doors. Didn't they read the script??" ); + m_Mobile.DebugSay( "*twist*" ); + + ((BaseDoor)item).Use( m_Mobile ); + } + else + { + m_Mobile.DebugSay( "Ugabooga. I'm so big and tough I can destroy it: {0}", item.GetType().Name ); + + if( item is Container ) + { + Container cont = (Container)item; + + for( int i = 0; i < cont.Items.Count; ++i ) + { + Item check = cont.Items[i]; + + if( check.Movable && check.ItemData.Impassable && (item.Z + check.ItemData.Height) > m_Mobile.Z ) + m_Obstacles.Enqueue( check ); + } + + cont.Destroy(); + } + else + { + item.Delete(); + } + } + } + + if( !blocked ) + blocked = !m_Mobile.Move( d ); + } + } + + if( blocked ) + { + int offset = (Utility.RandomDouble() >= 0.6 ? 1 : -1); + + for( int i = 0; i < 2; ++i ) + { + m_Mobile.TurnInternal( offset ); + + if( m_Mobile.Move( m_Mobile.Direction ) ) + { + MoveImpl.IgnoreMovableImpassables = false; + return MoveResult.SuccessAutoTurn; + } + } + + MoveImpl.IgnoreMovableImpassables = false; + return (wasPushing ? MoveResult.BadState : MoveResult.Blocked); + } + else + { + MoveImpl.IgnoreMovableImpassables = false; + return MoveResult.Success; + } + } + + MoveImpl.IgnoreMovableImpassables = false; + return MoveResult.Success; + } + + public virtual void WalkRandomInHome( int iChanceToNotMove, int iChanceToDir, int iSteps ) + { + if( m_Mobile.Deleted || m_Mobile.DisallowAllMoves ) + return; + + if( m_Mobile.Home == Point3D.Zero ) + { + if( m_Mobile.Spawner is SpawnEntry ) + { + Region region = ((SpawnEntry)m_Mobile.Spawner).Region; + + if( m_Mobile.Region.AcceptsSpawnsFrom( region ) ) + { + m_Mobile.WalkRegion = region; + WalkRandom( iChanceToNotMove, iChanceToDir, iSteps ); + m_Mobile.WalkRegion = null; + } + else + { + if( region.GoLocation != Point3D.Zero && Utility.Random( 10 ) > 5 ) + { + DoMove( m_Mobile.GetDirectionTo( region.GoLocation ) ); + } + else + { + WalkRandom( iChanceToNotMove, iChanceToDir, 1 ); + } + } + } + else + { + WalkRandom( iChanceToNotMove, iChanceToDir, iSteps ); + } + } + else + { + for( int i=0; i m_Mobile.RangeHome ) + { + DoMove( m_Mobile.GetDirectionTo( m_Mobile.Home ) ); + } + else + { + if( Utility.Random( 10 ) > 5 ) + { + DoMove( m_Mobile.GetDirectionTo( m_Mobile.Home ) ); + } + else + { + WalkRandom( iChanceToNotMove, iChanceToDir, 1 ); + } + } + } + else + { + if( m_Mobile.Location != m_Mobile.Home ) + { + DoMove( m_Mobile.GetDirectionTo( m_Mobile.Home ) ); + } + } + } + } + } + + public virtual bool CheckFlee() + { + if( m_Mobile.CheckFlee() ) + { + Mobile combatant = m_Mobile.Combatant; + + if( combatant == null ) + { + WalkRandom( 1, 2, 1 ); + } + else + { + Direction d = combatant.GetDirectionTo( m_Mobile ); + + d = (Direction)((int)d + Utility.RandomMinMax( -1, +1 )); + + m_Mobile.Direction = d; + m_Mobile.Move( d ); + } + + return true; + } + + return false; + } + + protected PathFollower m_Path; + + public virtual void OnTeleported() + { + if( m_Path != null ) + { + m_Mobile.DebugSay( "Teleported; repathing" ); + m_Path.ForceRepath(); + } + } + + public virtual bool MoveTo( Mobile m, bool run, int range ) + { + if( m_Mobile.Deleted || m_Mobile.DisallowAllMoves || m == null || m.Deleted ) + return false; + + if( m_Mobile.InRange( m, range ) ) + { + m_Path = null; + return true; + } + + if( m_Path != null && m_Path.Goal == m ) + { + if( m_Path.Follow( run, 1 ) ) + { + m_Path = null; + return true; + } + } + else if( !DoMove( m_Mobile.GetDirectionTo( m ), true ) ) + { + m_Path = new PathFollower( m_Mobile, m ); + m_Path.Mover = new MoveMethod( DoMoveImpl ); + + if( m_Path.Follow( run, 1 ) ) + { + m_Path = null; + return true; + } + } + else + { + m_Path = null; + return true; + } + + return false; + } + + /* + * Walk at range distance from mobile + * + * iSteps : Number of steps + * bRun : Do we run + * iWantDistMin : The minimum distance we want to be + * iWantDistMax : The maximum distance we want to be + * + */ + public virtual bool WalkMobileRange( Mobile m, int iSteps, bool bRun, int iWantDistMin, int iWantDistMax ) + { + if( m_Mobile.Deleted || m_Mobile.DisallowAllMoves ) + return false; + + if( m != null ) + { + for( int i=0; i iWantDistMax ) + { + bool needCloser = (iCurrDist > iWantDistMax); + bool needFurther = !needCloser; + + if( needCloser && m_Path != null && m_Path.Goal == m ) + { + if( m_Path.Follow( bRun, 1 ) ) + m_Path = null; + } + else + { + Direction dirTo; + + if( iCurrDist > iWantDistMax ) + dirTo = m_Mobile.GetDirectionTo( m ); + else + dirTo = m.GetDirectionTo( m_Mobile ); + + // Add the run flag + if( bRun ) + dirTo = dirTo | Direction.Running; + + if( !DoMove( dirTo, true ) && needCloser ) + { + m_Path = new PathFollower( m_Mobile, m ); + m_Path.Mover = new MoveMethod( DoMoveImpl ); + + if( m_Path.Follow( bRun, 1 ) ) + m_Path = null; + } + else + { + m_Path = null; + } + } + } + else + { + return true; + } + } + + // Get the curent distance + int iNewDist = (int)m_Mobile.GetDistanceToSqrt( m ); + + if( iNewDist >= iWantDistMin && iNewDist <= iWantDistMax ) + return true; + else + return false; + } + + return false; + } + + /* + * Here we check to acquire a target from our surronding + * + * iRange : The range + * acqType : A type of acquire we want (closest, strongest, etc) + * bPlayerOnly : Don't bother with other creatures or NPCs, want a player + * bFacFriend : Check people in my faction + * bFacFoe : Check people in other factions + * + */ + public virtual bool AcquireFocusMob( int iRange, FightMode acqType, bool bPlayerOnly, bool bFacFriend, bool bFacFoe ) + { + if( m_Mobile.Deleted ) + return false; + + if( m_Mobile.BardProvoked ) + { + if( m_Mobile.BardTarget == null || m_Mobile.BardTarget.Deleted ) + { + m_Mobile.FocusMob = null; + return false; + } + else + { + m_Mobile.FocusMob = m_Mobile.BardTarget; + return (m_Mobile.FocusMob != null); + } + } + else if( m_Mobile.Controlled ) + { + if( m_Mobile.ControlTarget == null || m_Mobile.ControlTarget.Deleted || m_Mobile.ControlTarget.Hidden || !m_Mobile.ControlTarget.Alive || m_Mobile.ControlTarget.IsDeadBondedPet || !m_Mobile.InRange( m_Mobile.ControlTarget, m_Mobile.RangePerception * 2 ) ) + { + if ( m_Mobile.ControlTarget != null && m_Mobile.ControlTarget != m_Mobile.ControlMaster ) + m_Mobile.ControlTarget = null; + + m_Mobile.FocusMob = null; + return false; + } + else + { + m_Mobile.FocusMob = m_Mobile.ControlTarget; + return (m_Mobile.FocusMob != null); + } + } + + if( m_Mobile.ConstantFocus != null ) + { + m_Mobile.DebugSay( "Acquired my constant focus" ); + m_Mobile.FocusMob = m_Mobile.ConstantFocus; + return true; + } + + if( acqType == FightMode.None ) + { + m_Mobile.FocusMob = null; + return false; + } + + if ( acqType == FightMode.Aggressor && m_Mobile.Aggressors.Count == 0 && m_Mobile.Aggressed.Count == 0 && m_Mobile.FactionAllegiance == null && m_Mobile.EthicAllegiance == null ) + { + m_Mobile.FocusMob = null; + return false; + } + + if( m_Mobile.NextReacquireTime > DateTime.Now ) + { + m_Mobile.FocusMob = null; + return false; + } + + m_Mobile.NextReacquireTime = DateTime.Now + m_Mobile.ReacquireDelay; + + m_Mobile.DebugSay( "Acquiring..." ); + + Map map = m_Mobile.Map; + + if( map != null ) + { + Mobile newFocusMob = null; + double val = double.MinValue; + double theirVal; + + IPooledEnumerable eable = map.GetMobilesInRange( m_Mobile.Location, iRange ); + // Scriptiz: this doesn't work so I'll keep the old version above + // IPooledEnumerable eable = map.GetMobilesInRange(m_Mobile.Location, iRange); + + foreach( Mobile m in eable ) + { + if ( m.Deleted || m.Blessed ) + continue; + + // Let's not target ourselves... + if (m == m_Mobile || m is BaseFamiliar) + continue; + + // Dead targets are invalid. + if ( !m.Alive || m.IsDeadBondedPet ) + continue; + + // Staff members cannot be targeted. + if ( m.AccessLevel > AccessLevel.Player ) + continue; + + // Does it have to be a player? + if ( bPlayerOnly && !m.Player ) + continue; + + // Can't acquire a target we can't see. + if ( !m_Mobile.CanSee( m ) ) + continue; + + if (Core.AOS && m is BaseCreature && (m as BaseCreature).Summoned && !(m as BaseCreature).Controlled) + continue; + + if ( m_Mobile.Summoned && m_Mobile.SummonMaster != null ) + { + // If this is a summon, it can't target its controller. + if ( m == m_Mobile.SummonMaster ) + continue; + + // It also must abide by harmful spell rules. + if ( !Server.Spells.SpellHelper.ValidIndirectTarget( m_Mobile.SummonMaster, m ) ) + continue; + + // Animated creatures cannot attack players directly. + if ( m is PlayerMobile && m_Mobile.IsAnimatedDead ) + continue; + } + + // If we only want faction friends, make sure it's one. + if ( bFacFriend && !m_Mobile.IsFriend( m ) ) + continue; + + //Ignore anyone under EtherealVoyage + if( TransformationSpellHelper.UnderTransformation( m, typeof( EtherealVoyageSpell ) ) ) + continue; + + // Ignore players with activated honor + if ( m is PlayerMobile && ( (PlayerMobile)m ).HonorActive && !( m_Mobile.Combatant == m )) + continue; + + if (acqType == FightMode.Aggressor || acqType == FightMode.Evil) + { + bool bValid = IsHostile(m); + + if (!bValid) + bValid = (m_Mobile.GetFactionAllegiance(m) == BaseCreature.Allegiance.Enemy || m_Mobile.GetEthicAllegiance(m) == BaseCreature.Allegiance.Enemy); + + if (acqType == FightMode.Evil && !bValid) + { + if (m is BaseCreature && ((BaseCreature)m).Controlled && ((BaseCreature)m).ControlMaster != null) + bValid = (((BaseCreature)m).ControlMaster.Karma < 0); + else + bValid = (m.Karma < 0); + } + + if ( !bValid ) + continue; + } else { + + + // Same goes for faction enemies. + if ( bFacFoe && !m_Mobile.IsEnemy( m ) ) + continue; + + // If it's an enemy factioned mobile, make sure we can be harmful to it. + if ( bFacFoe && !bFacFriend && !m_Mobile.CanBeHarmful( m, false ) ) + continue; + } + + theirVal = m_Mobile.GetFightModeRanking( m, acqType, bPlayerOnly ); + + if( theirVal > val && m_Mobile.InLOS( m ) ) + { + newFocusMob = m; + val = theirVal; + } + } + + eable.Free(); + + m_Mobile.FocusMob = newFocusMob; + } + + return (m_Mobile.FocusMob != null); + } + + private bool IsHostile(Mobile from) + { + int count = Math.Max(m_Mobile.Aggressors.Count, m_Mobile.Aggressed.Count); + + if (m_Mobile.Combatant == from || from.Combatant == m_Mobile) + { + return true; + } + + if (count > 0) + { + for (int a = 0; a < count; ++a) + { + if (a < m_Mobile.Aggressed.Count && m_Mobile.Aggressed[a].Attacker == from) + { + return true; + } + + if (a < m_Mobile.Aggressors.Count && m_Mobile.Aggressors[a].Defender == from) + { + return true; + } + } + } + + return false; + } + + public virtual void DetectHidden() + { + if( m_Mobile.Deleted || m_Mobile.Map == null ) + return; + + m_Mobile.DebugSay( "Checking for hidden players" ); + + double srcSkill = m_Mobile.Skills[SkillName.DetectHidden].Value; + + if( srcSkill <= 0 ) + return; + + foreach( Mobile trg in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) ) + { + if( trg != m_Mobile && trg.Player && trg.Alive && trg.Hidden && trg.AccessLevel == AccessLevel.Player && m_Mobile.InLOS( trg ) ) + { + m_Mobile.DebugSay( "Trying to detect {0}", trg.Name ); + + double trgHiding = trg.Skills[SkillName.Hiding].Value / 2.9; + double trgStealth = trg.Skills[SkillName.Stealth].Value / 1.8; + + double chance = srcSkill / 1.2 - Math.Min( trgHiding, trgStealth ); + + if( chance < srcSkill / 10 ) + chance = srcSkill / 10; + + chance /= 100; + + if( chance > Utility.RandomDouble() ) + { + trg.RevealingAction(); + trg.SendLocalizedMessage( 500814 ); // You have been revealed! + } + } + } + } + + public virtual void Deactivate() + { + if( m_Mobile.PlayerRangeSensitive ) + { + m_Timer.Stop(); + + SpawnEntry se = m_Mobile.Spawner as SpawnEntry; + + if( se != null && se.ReturnOnDeactivate && !m_Mobile.Controlled ) + { + if( se.HomeLocation == Point3D.Zero ) + { + if( !m_Mobile.Region.AcceptsSpawnsFrom( se.Region ) ) + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ReturnToHome ) ); + } + } + else if( !m_Mobile.InRange( se.HomeLocation, se.HomeRange ) ) + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ReturnToHome ) ); + } + } + } + } + + private void ReturnToHome() + { + SpawnEntry se = m_Mobile.Spawner as SpawnEntry; + + if( se != null ) + { + Point3D loc = se.RandomSpawnLocation( 16, !m_Mobile.CantWalk, m_Mobile.CanSwim ); + + if( loc != Point3D.Zero ) + { + m_Mobile.MoveToWorld( loc, se.Region.Map ); + return; + } + } + } + + public virtual void Activate() + { + if( !m_Timer.Running ) + { + m_Timer.Delay = TimeSpan.Zero; + m_Timer.Start(); + } + } + + /* + * The mobile changed it speed, we must ajust the timer + */ + public virtual void OnCurrentSpeedChanged() + { + m_Timer.Stop(); + m_Timer.Delay = TimeSpan.FromSeconds( Utility.RandomDouble() ); + m_Timer.Interval = TimeSpan.FromSeconds( Math.Max( 0.0, m_Mobile.CurrentSpeed ) ); + m_Timer.Start(); + } + + private DateTime m_NextDetectHidden; + + public virtual bool CanDetectHidden { get { return m_Mobile.Skills[SkillName.DetectHidden].Value > 0; } } + + /* + * The Timer object + */ + private class AITimer : Timer + { + private BaseAI m_Owner; + + public AITimer( BaseAI owner ) + : base( TimeSpan.FromSeconds( Utility.RandomDouble() ), TimeSpan.FromSeconds( Math.Max( 0.0, owner.m_Mobile.CurrentSpeed ) ) ) + { + m_Owner = owner; + + m_Owner.m_NextDetectHidden = DateTime.Now; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if( m_Owner.m_Mobile.Deleted ) + { + Stop(); + return; + } + else if( m_Owner.m_Mobile.Map == null || m_Owner.m_Mobile.Map == Map.Internal ) + { + return; + } + else if( m_Owner.m_Mobile.PlayerRangeSensitive )//have to check this in the timer.... + { + Sector sect = m_Owner.m_Mobile.Map.GetSector( m_Owner.m_Mobile ); + if( !sect.Active ) + { + m_Owner.Deactivate(); + return; + } + } + + m_Owner.m_Mobile.OnThink(); + + if( m_Owner.m_Mobile.Deleted ) + { + Stop(); + return; + } + else if( m_Owner.m_Mobile.Map == null || m_Owner.m_Mobile.Map == Map.Internal ) + { + return; + } + + if( m_Owner.m_Mobile.BardPacified ) + { + m_Owner.DoBardPacified(); + } + else if( m_Owner.m_Mobile.BardProvoked ) + { + m_Owner.DoBardProvoked(); + } + else + { + if( !m_Owner.m_Mobile.Controlled ) + { + if( !m_Owner.Think() ) + { + Stop(); + return; + } + } + else + { + if( !m_Owner.Obey() ) + { + Stop(); + return; + } + } + } + + if( m_Owner.CanDetectHidden && DateTime.Now > m_Owner.m_NextDetectHidden ) + { + m_Owner.DetectHidden(); + + // Not exactly OSI style, approximation. + int delay = (15000 / m_Owner.m_Mobile.Int); + + if( delay > 60 ) + delay = 60; + + int min = delay * (9 / 10); // 13s at 1000 int, 33s at 400 int, 54s at <250 int + int max = delay * (10 / 9); // 16s at 1000 int, 41s at 400 int, 66s at <250 int + + m_Owner.m_NextDetectHidden = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( min, max ) ); + } + } + } + } +} diff --git a/Scripts/Mobiles/AI/BerserkAI.cs b/Scripts/Mobiles/AI/BerserkAI.cs new file mode 100644 index 0000000..d1a5ca2 --- /dev/null +++ b/Scripts/Mobiles/AI/BerserkAI.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +namespace Server.Mobiles +{ + public class BerserkAI : BaseAI + { + public BerserkAI(BaseCreature m) : base (m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay( "I have No Combatant" ); + + if( AcquireFocusMob( m_Mobile.RangePerception, FightMode.Closest, false, true, true) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I have detected " + m_Mobile.FocusMob.Name + " and I will attack" ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + if( m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted ) + { + m_Mobile.DebugSay("My combatant is deleted"); + Action = ActionType.Guard; + return true; + } + + if( WalkMobileRange( m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) ) + { + // Be sure to face the combatant + m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant.Location ); + } + else + { + if( m_Mobile.Combatant != null ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay("I am still not in range of " + m_Mobile.Combatant.Name); + + if( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 1 ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I have lost " + m_Mobile.Combatant.Name ); + + Action = ActionType.Guard; + return true; + } + } + } + + return true; + } + + public override bool DoActionGuard() + { + if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, true, true ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name ); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + } +} diff --git a/Scripts/Mobiles/AI/HealerAI.cs b/Scripts/Mobiles/AI/HealerAI.cs new file mode 100644 index 0000000..cb2e706 --- /dev/null +++ b/Scripts/Mobiles/AI/HealerAI.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Spells; +using Server.Spells.First; +using Server.Spells.Second; +using Server.Spells.Fourth; + +namespace Server.Mobiles +{ + public class HealerAI : BaseAI + { + private static NeedDelegate m_Cure = new NeedDelegate( NeedCure ); + private static NeedDelegate m_GHeal = new NeedDelegate( NeedGHeal ); + private static NeedDelegate m_LHeal = new NeedDelegate( NeedLHeal ); + private static NeedDelegate[] m_ACure = new NeedDelegate[] { m_Cure }; + private static NeedDelegate[] m_AGHeal = new NeedDelegate[] { m_GHeal }; + private static NeedDelegate[] m_ALHeal = new NeedDelegate[] { m_LHeal }; + private static NeedDelegate[] m_All = new NeedDelegate[] { m_Cure, m_GHeal, m_LHeal }; + + public HealerAI( BaseCreature m ) : base( m ) + { + } + + public override bool Think() + { + if ( m_Mobile.Deleted ) + return false; + + Target targ = m_Mobile.Target; + + if ( targ != null ) + { + if ( targ is CureSpell.InternalTarget ) + { + ProcessTarget( targ, m_ACure ); + } + else if ( targ is GreaterHealSpell.InternalTarget ) + { + ProcessTarget( targ, m_AGHeal ); + } + else if ( targ is HealSpell.InternalTarget ) + { + ProcessTarget( targ, m_ALHeal ); + } + else + { + targ.Cancel( m_Mobile, TargetCancelType.Canceled ); + } + } + else + { + Mobile toHelp = Find( m_All ); + + if ( toHelp != null ) + { + if ( NeedCure( toHelp ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} needs a cure", toHelp.Name ); + + if ( !(new CureSpell( m_Mobile, null )).Cast() ) + new CureSpell( m_Mobile, null ).Cast(); + } + else if ( NeedGHeal( toHelp ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} needs a greater heal", toHelp.Name ); + + if ( !(new GreaterHealSpell( m_Mobile, null )).Cast() ) + new HealSpell( m_Mobile, null ).Cast(); + } + else if ( NeedLHeal( toHelp ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} needs a lesser heal", toHelp.Name ); + + new HealSpell( m_Mobile, null ).Cast(); + } + } + else + { + if ( AcquireFocusMob( m_Mobile.RangePerception, FightMode.Weakest, false, true, false ) ) + { + WalkMobileRange( m_Mobile.FocusMob, 1, false, 4, 7 ); + } + else + { + WalkRandomInHome( 3, 2, 1 ); + } + } + } + + return true; + } + + private delegate bool NeedDelegate( Mobile m ); + + private void ProcessTarget( Target targ, NeedDelegate[] func ) + { + Mobile toHelp = Find( func ); + + if ( toHelp != null ) + { + if ( targ.Range != -1 && !m_Mobile.InRange( toHelp, targ.Range ) ) + { + DoMove( m_Mobile.GetDirectionTo( toHelp ) | Direction.Running ); + } + else + { + targ.Invoke( m_Mobile, toHelp ); + } + } + else + { + targ.Cancel( m_Mobile, TargetCancelType.Canceled ); + } + } + + private Mobile Find( params NeedDelegate[] funcs ) + { + if ( m_Mobile.Deleted ) + return null; + + Map map = m_Mobile.Map; + + if ( map != null ) + { + double prio = 0.0; + Mobile found = null; + + foreach ( Mobile m in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) ) + { + if ( !m_Mobile.CanSee( m ) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team ) + continue; + + for ( int i = 0; i < funcs.Length; ++i ) + { + if ( funcs[i]( m ) ) + { + double val = -m_Mobile.GetDistanceToSqrt( m ); + + if ( found == null || val > prio ) + { + prio = val; + found = m; + } + + break; + } + } + } + + return found; + } + + return null; + } + + private static bool NeedCure( Mobile m ) + { + return m.Poisoned; + } + + private static bool NeedGHeal( Mobile m ) + { + return m.Hits < m.HitsMax - 40; + } + + private static bool NeedLHeal( Mobile m ) + { + return m.Hits < m.HitsMax - 10; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/MageAI.cs b/Scripts/Mobiles/AI/MageAI.cs new file mode 100644 index 0000000..66b1f26 --- /dev/null +++ b/Scripts/Mobiles/AI/MageAI.cs @@ -0,0 +1,1103 @@ +using System; +using System.Collections.Generic; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.First; +using Server.Spells.Fourth; +using Server.Spells.Necromancy; +using Server.Spells.Second; +using Server.Spells.Seventh; +using Server.Spells.Sixth; +using Server.Spells.Third; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class MageAI : BaseAI + { + private DateTime m_NextCastTime; + private DateTime m_NextHealTime; + + public MageAI(BaseCreature m) + : base(m) + { + } + + public override bool Think() + { + if (m_Mobile.Deleted) + return false; + + if (ProcessTarget()) + return true; + else + return base.Think(); + } + + public virtual bool SmartAI + { + get { return (m_Mobile is BaseVendor || m_Mobile is BaseEscortable || m_Mobile is Changeling); } + } + + public virtual bool IsNecromancer + { + get { return (Core.AOS && m_Mobile.Skills[SkillName.Necromancy].Value > 50); } + } + + private const double HealChance = 0.10; // 10% chance to heal at gm magery + private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery + private const double DispelChance = 0.75; // 75% chance to dispel at gm magery + + public virtual double ScaleBySkill(double v, SkillName skill) + { + return v * m_Mobile.Skills[skill].Value / 100; + } + + public override bool DoActionWander() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + m_NextCastTime = DateTime.Now; + } + else if (SmartAI && m_Mobile.Mana < m_Mobile.ManaMax && !m_Mobile.Meditating) + { + m_Mobile.DebugSay("I am going to meditate"); + + m_Mobile.UseSkill(SkillName.Meditation); + } + else + { + m_Mobile.DebugSay("I am wandering"); + + m_Mobile.Warmode = false; + + base.DoActionWander(); + + if (Utility.RandomDouble() < 0.05) + { + Spell spell = CheckCastHealingSpell(); + + if (spell != null) + spell.Cast(); + } + } + + return true; + } + + private Spell CheckCastHealingSpell() + { + // If I'm poisoned, always attempt to cure. + if (m_Mobile.Poisoned) + return new CureSpell(m_Mobile, null); + + // Summoned creatures never heal themselves. + if (m_Mobile.Summoned) + return null; + + if (m_Mobile.Controlled) + { + if (DateTime.Now < m_NextHealTime) + return null; + } + + if (!SmartAI) + { + if (ScaleBySkill(HealChance, SkillName.Magery) < Utility.RandomDouble()) + return null; + } + else + { + if (Utility.Random(0, 4 + (m_Mobile.Hits == 0 ? m_Mobile.HitsMax : (m_Mobile.HitsMax / m_Mobile.Hits))) < 3) + return null; + } + + Spell spell = null; + + if (m_Mobile.Hits < (m_Mobile.HitsMax - 50)) + { + if (UseNecromancy()) + { + m_Mobile.UseSkill(SkillName.SpiritSpeak); + } + else + { + spell = new GreaterHealSpell(m_Mobile, null); + + if (spell == null) + spell = new HealSpell(m_Mobile, null); + } + } + else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10)) + { + spell = new HealSpell(m_Mobile, null); + } + + double delay; + + if (m_Mobile.Int >= 500) + delay = Utility.RandomMinMax(7, 10); + else + delay = Math.Sqrt(600 - m_Mobile.Int); + + m_NextHealTime = DateTime.Now + TimeSpan.FromSeconds(delay); + + return spell; + } + + public void RunTo(Mobile m) + { + if (!SmartAI) + { + if (!MoveTo(m, true, m_Mobile.RangeFight)) + OnFailedMove(); + + return; + } + + if (m.Paralyzed || m.Frozen) + { + if (m_Mobile.InRange(m, 1)) + RunFrom(m); + else if (!m_Mobile.InRange(m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2) && !MoveTo(m, true, 1)) + OnFailedMove(); + } + else + { + if (!m_Mobile.InRange(m, m_Mobile.RangeFight)) + { + if (!MoveTo(m, true, 1)) + OnFailedMove(); + } + else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1)) + { + RunFrom(m); + } + } + } + + public void RunFrom(Mobile m) + { + Run((m_Mobile.GetDirectionTo(m) - 4) & Direction.Mask); + } + + public void OnFailedMove() + { + if (!m_Mobile.DisallowAllMoves && (SmartAI ? Utility.Random(4) == 0 : ScaleBySkill(TeleportChance, SkillName.Magery) > Utility.RandomDouble())) + { + if (m_Mobile.Target != null) + m_Mobile.Target.Cancel(m_Mobile, TargetCancelType.Canceled); + + new TeleportSpell(m_Mobile, null).Cast(); + + m_Mobile.DebugSay("I am stuck, I'm going to try teleporting away"); + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + m_Mobile.DebugSay("I am stuck"); + } + } + + public void Run(Direction d) + { + if ((m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.Paralyzed || m_Mobile.Frozen || m_Mobile.DisallowAllMoves) + return; + + m_Mobile.Direction = d | Direction.Running; + + if (!DoMove(m_Mobile.Direction, true)) + OnFailedMove(); + } + + public virtual bool UseNecromancy() + { + if (IsNecromancer) + return (Utility.Random(m_Mobile.Skills[SkillName.Magery].BaseFixedPoint + m_Mobile.Skills[SkillName.Necromancy].BaseFixedPoint) >= m_Mobile.Skills[SkillName.Magery].BaseFixedPoint); + + return false; + } + + public virtual Spell GetRandomDamageSpell() + { + return UseNecromancy() ? GetRandomDamageSpellNecro() : GetRandomDamageSpellMage(); + } + + public virtual Spell GetRandomDamageSpellNecro() + { + int bound = (m_Mobile.Skills[SkillName.Necromancy].Value >= 100) ? 5 : 3; + + switch (Utility.Random(bound)) + { + case 0: m_Mobile.DebugSay("Pain Spike"); return new PainSpikeSpell(m_Mobile, null); + case 1: m_Mobile.DebugSay("Poison Strike"); return new PoisonStrikeSpell(m_Mobile, null); + case 2: m_Mobile.DebugSay("Strangle"); return new StrangleSpell(m_Mobile, null); + case 3: m_Mobile.DebugSay("Wither"); return new WitherSpell(m_Mobile, null); + default: m_Mobile.DebugSay("Vengeful Spirit"); return new VengefulSpiritSpell(m_Mobile, null); + } + } + + public virtual Spell GetRandomDamageSpellMage() + { + int maxCircle = (int)((m_Mobile.Skills[SkillName.Magery].Value + 20.0) / (100.0 / 7.0)); + + if (maxCircle < 1) + maxCircle = 1; + else if (maxCircle > 8) + maxCircle = 8; + + switch (Utility.Random(maxCircle * 2)) + { + case 0: + case 1: return new MagicArrowSpell(m_Mobile, null); + case 2: + case 3: return new HarmSpell(m_Mobile, null); + case 4: + case 5: return new FireballSpell(m_Mobile, null); + case 6: + case 7: return new LightningSpell(m_Mobile, null); + case 8: + case 9: return new MindBlastSpell(m_Mobile, null); + case 10: return new EnergyBoltSpell(m_Mobile, null); + case 11: return new ExplosionSpell(m_Mobile, null); + default: return new FlameStrikeSpell(m_Mobile, null); + } + } + + public virtual Spell GetRandomCurseSpell() + { + return UseNecromancy() ? GetRandomCurseSpellNecro() : GetRandomCurseSpellMage(); + } + + public virtual Spell GetRandomCurseSpellNecro() + { + switch (Utility.Random(4)) + { + case 0: m_Mobile.DebugSay("Blood Oath"); return new BloodOathSpell(m_Mobile, null); + case 1: m_Mobile.DebugSay("Corpse Skin"); return new CorpseSkinSpell(m_Mobile, null); + case 2: m_Mobile.DebugSay("Evil Omen"); return new EvilOmenSpell(m_Mobile, null); + default: m_Mobile.DebugSay("Mind Rot"); return new MindRotSpell(m_Mobile, null); + } + } + + public virtual Spell GetRandomCurseSpellMage() + { + if (m_Mobile.Skills[SkillName.Magery].Value >= 40.0 && Utility.Random(4) == 0) + return new CurseSpell(m_Mobile, null); + + switch (Utility.Random(3)) + { + case 0: return new WeakenSpell(m_Mobile, null); + case 1: return new ClumsySpell(m_Mobile, null); + default: return new FeeblemindSpell(m_Mobile, null); + } + } + + public virtual Spell GetRandomManaDrainSpell() + { + if (m_Mobile.Skills[SkillName.Magery].Value >= 80.0 && Utility.RandomBool()) + return new ManaVampireSpell(m_Mobile, null); + + return new ManaDrainSpell(m_Mobile, null); + } + + public virtual Spell DoDispel(Mobile toDispel) + { + if (!SmartAI) + { + if (ScaleBySkill(DispelChance, SkillName.Magery) > Utility.RandomDouble()) + return new DispelSpell(m_Mobile, null); + + return ChooseSpell(toDispel); + } + + Spell spell = CheckCastHealingSpell(); + + if (spell == null) + { + if (!m_Mobile.DisallowAllMoves && Utility.Random((int)m_Mobile.GetDistanceToSqrt(toDispel)) == 0) + spell = new TeleportSpell(m_Mobile, null); + else if (Utility.Random(3) == 0 && !m_Mobile.InRange(toDispel, 3) && !toDispel.Paralyzed && !toDispel.Frozen) + spell = new ParalyzeSpell(m_Mobile, null); + else + spell = new DispelSpell(m_Mobile, null); + } + + return spell; + } + + public virtual Spell ChooseSpell(Mobile c) + { + Spell spell = null; + + if (!SmartAI) + { + spell = CheckCastHealingSpell(); + + if (spell != null) + return spell; + + if (IsNecromancer) + { + double psDamage = ((m_Mobile.Skills[SkillName.SpiritSpeak].Value - c.Skills[SkillName.MagicResist].Value) / 10) + (c.Player ? 18 : 30); + + if (psDamage > c.Hits) + return new PainSpikeSpell(m_Mobile, null); + } + + switch (Utility.Random(16)) + { + case 0: + case 1: // Poison them + { + if (c.Poisoned) + goto default; + + m_Mobile.DebugSay("Attempting to poison"); + + spell = new PoisonSpell(m_Mobile, null); + break; + } + case 2: // Bless ourselves + { + m_Mobile.DebugSay("Blessing myself"); + + spell = new BlessSpell(m_Mobile, null); + break; + } + case 3: + case 4: // Curse them + { + m_Mobile.DebugSay("Attempting to curse"); + + spell = GetRandomCurseSpell(); + break; + } + case 5: // Paralyze them + { + if (c.Paralyzed || m_Mobile.Skills[SkillName.Magery].Value <= 50.0) + goto default; + + m_Mobile.DebugSay("Attempting to paralyze"); + + spell = new ParalyzeSpell(m_Mobile, null); + break; + } + case 6: // Drain mana + { + m_Mobile.DebugSay("Attempting to drain mana"); + + spell = GetRandomManaDrainSpell(); + break; + } + case 7: // Invis ourselves + { + if (Utility.RandomBool()) + goto default; + + m_Mobile.DebugSay("Attempting to invis myself"); + + spell = new InvisibilitySpell(m_Mobile, null); + break; + } + default: // Damage them + { + m_Mobile.DebugSay("Just doing damage"); + + spell = GetRandomDamageSpell(); + break; + } + } + + return spell; + } + + spell = CheckCastHealingSpell(); + + if (spell != null) + return spell; + + switch (Utility.Random(3)) + { + case 0: // Poison them + { + if (c.Poisoned) + goto case 1; + + spell = new PoisonSpell(m_Mobile, null); + break; + } + case 1: // Deal some damage + { + spell = GetRandomDamageSpell(); + + break; + } + default: // Set up a combo + { + if (m_Mobile.Mana > 15 && m_Mobile.Mana < 40) + { + if (c.Paralyzed && !c.Poisoned && !m_Mobile.Meditating) + { + m_Mobile.DebugSay("I am going to meditate"); + + m_Mobile.UseSkill(SkillName.Meditation); + } + else if (!c.Poisoned) + { + spell = new ParalyzeSpell(m_Mobile, null); + } + } + else if (m_Mobile.Mana > 60) + { + if (Utility.RandomBool() && !c.Paralyzed && !c.Frozen && !c.Poisoned) + { + m_Combo = 0; + spell = new ParalyzeSpell(m_Mobile, null); + } + else + { + m_Combo = 1; + spell = new ExplosionSpell(m_Mobile, null); + } + } + + break; + } + } + + return spell; + } + + protected int m_Combo = -1; + + public virtual Spell DoCombo(Mobile c) + { + Spell spell = null; + + if (m_Combo == 0) + { + spell = new ExplosionSpell(m_Mobile, null); + ++m_Combo; // Move to next spell + } + else if (m_Combo == 1) + { + spell = new WeakenSpell(m_Mobile, null); + ++m_Combo; // Move to next spell + } + else if (m_Combo == 2) + { + if (!c.Poisoned) + spell = new PoisonSpell(m_Mobile, null); + else if (IsNecromancer) + spell = new StrangleSpell(m_Mobile, null); + + ++m_Combo; // Move to next spell + } + + if (m_Combo == 3 && spell == null) + { + switch (Utility.Random(IsNecromancer ? 4 : 3)) + { + case 0: + { + if (c.Int < c.Dex) + spell = new FeeblemindSpell(m_Mobile, null); + else + spell = new ClumsySpell(m_Mobile, null); + + ++m_Combo; // Move to next spell + + break; + } + case 1: + { + spell = new EnergyBoltSpell(m_Mobile, null); + m_Combo = -1; // Reset combo state + break; + } + case 2: + { + spell = new FlameStrikeSpell(m_Mobile, null); + m_Combo = -1; // Reset combo state + break; + } + default: + { + spell = new PainSpikeSpell(m_Mobile, null); + m_Combo = -1; // Reset combo state + break; + } + } + } + else if (m_Combo == 4 && spell == null) + { + spell = new MindBlastSpell(m_Mobile, null); + m_Combo = -1; + } + + return spell; + } + + private TimeSpan GetDelay(Spell spell) + { + if (SmartAI || (spell is DispelSpell)) + { + return TimeSpan.FromSeconds(m_Mobile.ActiveSpeed); + } + else + { + double del = ScaleBySkill(3.0, SkillName.Magery); + double min = 6.0 - (del * 0.75); + double max = 6.0 - (del * 1.25); + + return TimeSpan.FromSeconds(min + ((max - min) * Utility.RandomDouble())); + } + } + + private Mobile m_LastTarget; + private Point3D m_LastTargetLoc; + + public override bool DoActionCombat() + { + Mobile c = m_Mobile.Combatant; + m_Mobile.Warmode = true; + + if (c == null || c.Deleted || !c.Alive || c.IsDeadBondedPet || !m_Mobile.CanSee(c) || !m_Mobile.CanBeHarmful(c, false) || c.Map != m_Mobile.Map) + { + // Our combatant is deleted, dead, hidden, or we cannot hurt them + // Try to find another combatant + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = c = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else + { + m_Mobile.DebugSay("Something happened to my combatant, and nothing is around. I am on guard."); + Action = ActionType.Guard; + return true; + } + } + + if (!m_Mobile.InLOS(c)) + { + m_Mobile.DebugSay("I can't see my target"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I will switch to {0}", m_Mobile.FocusMob.Name); + m_Mobile.Combatant = c = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + } + + if (!Core.AOS && SmartAI && !m_Mobile.StunReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.Anatomy].Value >= 80.0) + EventSink.InvokeStunRequest(new StunRequestEventArgs(m_Mobile)); + + if (!m_Mobile.InRange(c, m_Mobile.RangePerception)) + { + // They are somewhat far away, can we find something else? + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3)) + { + m_Mobile.Combatant = null; + } + + c = m_Mobile.Combatant; + + if (c == null) + { + m_Mobile.DebugSay("My combatant has fled, so I am on guard"); + Action = ActionType.Guard; + + return true; + } + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + { + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) + { + // We are low on health, should we flee? + + bool flee = false; + + if (m_Mobile.Hits < c.Hits) + { + // We are more hurt than them + + int diff = c.Hits - m_Mobile.Hits; + + flee = (Utility.Random(0, 100) > (10 + diff)); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) > 10; // 10% chance to flee + } + + if (flee) + { + m_Mobile.DebugSay("I am going to flee from {0}", c.Name); + + Action = ActionType.Flee; + return true; + } + } + } + + if (m_Mobile.Spell == null && DateTime.Now > m_NextCastTime && m_Mobile.InRange(c, Core.ML ? 10 : 12)) + { + // We are ready to cast a spell + + Spell spell = null; + Mobile toDispel = FindDispelTarget(true); + + if (m_Mobile.Poisoned) // Top cast priority is cure + { + m_Mobile.DebugSay("I am going to cure myself"); + + spell = new CureSpell(m_Mobile, null); + } + else if (toDispel != null) // Something dispellable is attacking us + { + m_Mobile.DebugSay("I am going to dispel {0}", toDispel); + + spell = DoDispel(toDispel); + } + else if (SmartAI && m_Combo != -1) // We are doing a spell combo + { + spell = DoCombo(c); + } + else if (SmartAI && (c.Spell is HealSpell || c.Spell is GreaterHealSpell) && !c.Poisoned) // They have a heal spell out + { + spell = new PoisonSpell(m_Mobile, null); + } + else + { + spell = ChooseSpell(c); + } + + // Now we have a spell picked + // Move first before casting + + if (SmartAI && toDispel != null) + { + if (m_Mobile.InRange(toDispel, 10)) + RunFrom(toDispel); + else if (!m_Mobile.InRange(toDispel, Core.ML ? 10 : 12)) + RunTo(toDispel); + } + else + { + RunTo(c); + } + + if (spell != null) + spell.Cast(); + + m_NextCastTime = DateTime.Now + GetDelay(spell); + } + else if (m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting) + { + RunTo(c); + } + + m_LastTarget = c; + m_LastTargetLoc = c.Location; + + return true; + } + + private LandTarget m_RevealTarget; + + public override bool DoActionGuard() + { + if (m_LastTarget != null && m_LastTarget.Hidden) + { + Map map = m_Mobile.Map; + + if (map == null || !m_Mobile.InRange(m_LastTargetLoc, Core.ML ? 10 : 12)) + { + m_LastTarget = null; + } + else if (m_Mobile.Spell == null && DateTime.Now > m_NextCastTime) + { + m_Mobile.DebugSay("I am going to reveal my last target"); + + m_RevealTarget = new LandTarget(m_LastTargetLoc, map); + Spell spell = new RevealSpell(m_Mobile, null); + + if (spell.Cast()) + m_LastTarget = null; // only do it once + + m_NextCastTime = DateTime.Now + GetDelay(spell); + } + } + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + if (!m_Mobile.Controlled) + { + ProcessTarget(); + + Spell spell = CheckCastHealingSpell(); + + if (spell != null) + spell.Cast(); + } + + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + Mobile c = m_Mobile.Combatant; + + if ((m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > (m_Mobile.HitsMax / 2)) + { + m_Mobile.DebugSay("I am stronger now, my guard is up"); + Action = ActionType.Guard; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I am scared of {0}", m_Mobile.FocusMob.Name); + + RunFrom(m_Mobile.FocusMob); + m_Mobile.FocusMob = null; + + if (m_Mobile.Poisoned && Utility.Random(0, 5) == 0) + new CureSpell(m_Mobile, null).Cast(); + } + else + { + m_Mobile.DebugSay("Area seems clear, but my guard is up"); + + Action = ActionType.Guard; + m_Mobile.Warmode = true; + } + + return true; + } + + public Mobile FindDispelTarget(bool activeOnly) + { + if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel) + return null; + + if (activeOnly) + { + List aggressed = m_Mobile.Aggressed; + List aggressors = m_Mobile.Aggressors; + + Mobile active = null; + double activePrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if (comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange(comb, Core.ML ? 10 : 12) && CanDispel(comb)) + { + active = comb; + activePrio = m_Mobile.GetDistanceToSqrt(comb); + + if (activePrio <= 2) + return active; + } + + for (int i = 0; i < aggressed.Count; ++i) + { + AggressorInfo info = aggressed[i]; + Mobile m = info.Defender; + + if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, Core.ML ? 10 : 12) && CanDispel(m)) + { + double prio = m_Mobile.GetDistanceToSqrt(m); + + if (active == null || prio < activePrio) + { + active = m; + activePrio = prio; + + if (activePrio <= 2) + return active; + } + } + } + + for (int i = 0; i < aggressors.Count; ++i) + { + AggressorInfo info = aggressors[i]; + Mobile m = info.Attacker; + + if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, Core.ML ? 10 : 12) && CanDispel(m)) + { + double prio = m_Mobile.GetDistanceToSqrt(m); + + if (active == null || prio < activePrio) + { + active = m; + activePrio = prio; + + if (activePrio <= 2) + return active; + } + } + } + + return active; + } + else + { + Map map = m_Mobile.Map; + + if (map != null) + { + Mobile active = null, inactive = null; + double actPrio = 0.0, inactPrio = 0.0; + + Mobile comb = m_Mobile.Combatant; + + if (comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb)) + { + active = inactive = comb; + actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb); + } + + foreach (Mobile m in m_Mobile.GetMobilesInRange(Core.ML ? 10 : 12)) + { + if (m != m_Mobile && CanDispel(m)) + { + double prio = m_Mobile.GetDistanceToSqrt(m); + + if (!activeOnly && (inactive == null || prio < inactPrio)) + { + inactive = m; + inactPrio = prio; + } + + if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio)) + { + active = m; + actPrio = prio; + } + } + } + + return active != null ? active : inactive; + } + } + + return null; + } + + public bool CanDispel(Mobile m) + { + return (m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful(m, false) && !((BaseCreature)m).IsAnimatedDead); + } + + private static int[] m_Offsets = new int[] + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1, + + -2, -2, + -2, -1, + -2, 0, + -2, 1, + -2, 2, + -1, -2, + -1, 2, + 0, -2, + 0, 2, + 1, -2, + 1, 2, + 2, -2, + 2, -1, + 2, 0, + 2, 1, + 2, 2 + }; + + private bool ProcessTarget() + { + Target targ = m_Mobile.Target; + + if (targ == null) + return false; + + bool isReveal = (targ is RevealSpell.InternalTarget); + bool isDispel = (targ is DispelSpell.InternalTarget); + bool isParalyze = (targ is ParalyzeSpell.InternalTarget); + bool isTeleport = (targ is TeleportSpell.InternalTarget); + bool isInvisible = (targ is InvisibilitySpell.InternalTarget); + bool teleportAway = false; + + Mobile toTarget; + + if (isInvisible) + { + toTarget = m_Mobile; + } + else if (isDispel) + { + toTarget = FindDispelTarget(false); + + if (!SmartAI && toTarget != null) + RunTo(toTarget); + else if (toTarget != null && m_Mobile.InRange(toTarget, 10)) + RunFrom(toTarget); + } + else if (SmartAI && (isParalyze || isTeleport)) + { + toTarget = FindDispelTarget(true); + + if (toTarget == null) + { + toTarget = m_Mobile.Combatant; + + if (toTarget != null) + RunTo(toTarget); + } + else if (m_Mobile.InRange(toTarget, 10)) + { + RunFrom(toTarget); + teleportAway = true; + } + else + { + teleportAway = true; + } + } + else + { + toTarget = m_Mobile.Combatant; + + if (toTarget != null) + RunTo(toTarget); + } + + if ((targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null) + { + if ((targ.Range == -1 || m_Mobile.InRange(toTarget, targ.Range)) && m_Mobile.CanSee(toTarget) && m_Mobile.InLOS(toTarget)) + { + targ.Invoke(m_Mobile, toTarget); + } + else if (isDispel) + { + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + } + else if ((targ.Flags & TargetFlags.Beneficial) != 0) + { + targ.Invoke(m_Mobile, m_Mobile); + } + else if (isReveal && m_RevealTarget != null) + { + targ.Invoke(m_Mobile, m_RevealTarget); + } + else if (isTeleport && toTarget != null) + { + Map map = m_Mobile.Map; + + if (map == null) + { + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + return true; + } + + int px, py; + + if (teleportAway) + { + int rx = m_Mobile.X - toTarget.X; + int ry = m_Mobile.Y - toTarget.Y; + + double d = m_Mobile.GetDistanceToSqrt(toTarget); + + px = toTarget.X + (int)(rx * (10 / d)); + py = toTarget.Y + (int)(ry * (10 / d)); + } + else + { + px = toTarget.X; + py = toTarget.Y; + } + + for (int i = 0; i < m_Offsets.Length; i += 2) + { + int x = m_Offsets[i], y = m_Offsets[i + 1]; + + Point3D p = new Point3D(px + x, py + y, 0); + + LandTarget lt = new LandTarget(p, map); + + if ((targ.Range == -1 || m_Mobile.InRange(p, targ.Range)) && m_Mobile.InLOS(lt) && map.CanSpawnMobile(px + x, py + y, lt.Z) && !SpellHelper.CheckMulti(p, map)) + { + targ.Invoke(m_Mobile, lt); + return true; + } + } + + int teleRange = targ.Range; + + if (teleRange < 0) + teleRange = Core.ML ? 11 : 12; + + for (int i = 0; i < 10; ++i) + { + Point3D randomPoint = new Point3D(m_Mobile.X - teleRange + Utility.Random(teleRange * 2 + 1), m_Mobile.Y - teleRange + Utility.Random(teleRange * 2 + 1), 0); + + LandTarget lt = new LandTarget(randomPoint, map); + + if (m_Mobile.InLOS(lt) && map.CanSpawnMobile(lt.X, lt.Y, lt.Z) && !SpellHelper.CheckMulti(randomPoint, map)) + { + targ.Invoke(m_Mobile, new LandTarget(randomPoint, map)); + return true; + } + } + + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + else + { + targ.Cancel(m_Mobile, TargetCancelType.Canceled); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/MeleeAI.cs b/Scripts/Mobiles/AI/MeleeAI.cs new file mode 100644 index 0000000..fe3be7f --- /dev/null +++ b/Scripts/Mobiles/AI/MeleeAI.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +// +// This is a first simple AI +// +// + +namespace Server.Mobiles +{ + public class MeleeAI : BaseAI + { + public MeleeAI(BaseCreature m) + : base(m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + + Action = ActionType.Guard; + + return true; + } + + if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception)) + { + // They are somewhat far away, can we find something else? + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception * 3)) + { + m_Mobile.Combatant = null; + } + + combatant = m_Mobile.Combatant; + + if (combatant == null) + { + m_Mobile.DebugSay("My combatant has fled, so I am on guard"); + Action = ActionType.Guard; + + return true; + } + } + + /*if ( !m_Mobile.InLOS( combatant ) ) + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + }*/ + + if (MoveTo(combatant, true, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + + return true; + } + else if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I cannot find {0}, so my guard is up", combatant.Name); + + Action = ActionType.Guard; + + return true; + } + else + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + { + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) + { + // We are low on health, should we flee? + + bool flee = false; + + if (m_Mobile.Hits < combatant.Hits) + { + // We are more hurt than them + + int diff = combatant.Hits - m_Mobile.Hits; + + flee = (Utility.Random(0, 100) < (10 + diff)); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) < 10; // 10% chance to flee + } + + if (flee) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + + Action = ActionType.Flee; + } + } + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + if (m_Mobile.Hits > m_Mobile.HitsMax / 2) + { + m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); + Action = ActionType.Combat; + } + else + { + m_Mobile.FocusMob = m_Mobile.Combatant; + base.DoActionFlee(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/OppositionGroup.cs b/Scripts/Mobiles/AI/OppositionGroup.cs new file mode 100644 index 0000000..1ad5df0 --- /dev/null +++ b/Scripts/Mobiles/AI/OppositionGroup.cs @@ -0,0 +1,142 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server +{ + public class OppositionGroup + { + private Type[][] m_Types; + + public OppositionGroup( Type[][] types ) + { + m_Types = types; + } + + public bool IsEnemy( object from, object target ) + { + int fromGroup = IndexOf( from ); + int targGroup = IndexOf( target ); + + return ( fromGroup != -1 && targGroup != -1 && fromGroup != targGroup ); + } + + public int IndexOf( object obj ) + { + if ( obj == null ) + return -1; + + Type type = obj.GetType(); + + for ( int i = 0; i < m_Types.Length; ++i ) + { + Type[] group = m_Types[i]; + + bool contains = false; + + for ( int j = 0; !contains && j < group.Length; ++j ) + contains = group[j].IsAssignableFrom(type); + + if ( contains ) + return i; + } + + return -1; + } + + private static OppositionGroup m_TerathansAndOphidians = new OppositionGroup( new Type[][] + { + new Type[] + { + typeof( TerathanAvenger ), + typeof( TerathanDrone ), + typeof( TerathanMatriarch ), + typeof( TerathanWarrior ) + }, + new Type[] + { + typeof( OphidianArchmage ), + typeof( OphidianKnight ), + typeof( OphidianMage ), + typeof( OphidianMatriarch ), + typeof( OphidianWarrior ) + } + } ); + + public static OppositionGroup TerathansAndOphidians + { + get{ return m_TerathansAndOphidians; } + } + + private static OppositionGroup m_SavagesAndOrcs = new OppositionGroup( new Type[][] + { + new Type[] + { + typeof( Orc ), + typeof( OrcBomber ), + typeof( OrcBrute ), + typeof( OrcCaptain ), + typeof( OrcishLord ), + typeof( OrcishMage ), + typeof( SpawnedOrcishLord ) + }, + new Type[] + { + typeof( Savage ), + typeof( SavageRider ), + typeof( SavageRidgeback ), + typeof( SavageShaman ) + } + } ); + + public static OppositionGroup SavagesAndOrcs + { + get{ return m_SavagesAndOrcs; } + } + + private static OppositionGroup m_FeyAndUndead = new OppositionGroup( new Type[][] + { + new Type[] + { + typeof( Centaur ), + typeof( EtherealWarrior ), + typeof( Kirin ), + typeof( LordOaks ), + typeof( Pixie ), + typeof( Silvani ), + typeof( Unicorn ), + typeof( Wisp ), + typeof( Treefellow ), + typeof( MLDryad ), + typeof( Satyr ) + }, + new Type[] + { + typeof( AncientLich ), + typeof( Bogle ), + typeof( LichLord ), + typeof( Shade ), + typeof( Spectre ), + typeof( Wraith ), + typeof( BoneKnight ), + typeof( Ghoul ), + typeof( Mummy ), + typeof( SkeletalKnight ), + typeof( Skeleton ), + typeof( Zombie ), + typeof( ShadowKnight ), + typeof( DarknightCreeper ), + typeof( RevenantLion ), + typeof( LadyOfTheSnow ), + typeof( RottingCorpse ), + typeof( SkeletalDragon ), + typeof( Lich ) + } + } ); + + public static OppositionGroup FeyAndUndead + { + get{ return m_FeyAndUndead; } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/PredatorAI.cs b/Scripts/Mobiles/AI/PredatorAI.cs new file mode 100644 index 0000000..74e60a0 --- /dev/null +++ b/Scripts/Mobiles/AI/PredatorAI.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + + +/* + * PredatorAI, its an animal that can attack + * Dont flee but dont attack if not hurt or attacked + * + */ + +namespace Server.Mobiles +{ + public class PredatorAI : BaseAI + { + public PredatorAI(BaseCreature m) : base (m) + { + } + + public override bool DoActionWander() + { + if ( m_Mobile.Combatant != null ) + { + m_Mobile.DebugSay( "I am hurt or being attacked, I kill him" ); + Action = ActionType.Combat; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true)) + { + m_Mobile.DebugSay( "There is something near, I go away" ); + Action = ActionType.Backoff; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map ) + { + m_Mobile.DebugSay( "My combatant is gone, so my guard is up" ); + Action = ActionType.Wander; + return true; + } + + if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) ) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant ); + } + else + { + if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 ) + { + m_Mobile.DebugSay( "I cannot find {0}", combatant.Name ); + + Action = ActionType.Wander; + return true; + } + else + { + m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name ); + } + } + + return true; + } + + public override bool DoActionBackoff() + { + if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null ) + { + Action = ActionType.Combat; + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false , true)) + { + if ( WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2) ) + { + m_Mobile.DebugSay( "Well, here I am safe" ); + Action = ActionType.Wander; + } + } + else + { + m_Mobile.DebugSay( "I have lost my focus, lets relax" ); + Action = ActionType.Wander; + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/SpeedInfo.cs b/Scripts/Mobiles/AI/SpeedInfo.cs new file mode 100644 index 0000000..be4d8ec --- /dev/null +++ b/Scripts/Mobiles/AI/SpeedInfo.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Factions; + +namespace Server +{ + public class SpeedInfo + { + // Should we use the new method of speeds? + private static bool Enabled = true; + + private double m_ActiveSpeed; + private double m_PassiveSpeed; + private Type[] m_Types; + + public double ActiveSpeed + { + get{ return m_ActiveSpeed; } + set{ m_ActiveSpeed = value; } + } + + public double PassiveSpeed + { + get{ return m_PassiveSpeed; } + set{ m_PassiveSpeed = value; } + } + + public Type[] Types + { + get{ return m_Types; } + set{ m_Types = value; } + } + + public SpeedInfo( double activeSpeed, double passiveSpeed, Type[] types ) + { + m_ActiveSpeed = activeSpeed; + m_PassiveSpeed = passiveSpeed; + m_Types = types; + } + + public static bool Contains( object obj ) + { + if ( !Enabled ) + return false; + + if ( m_Table == null ) + LoadTable(); + + SpeedInfo sp = (SpeedInfo)m_Table[obj.GetType()]; + + return ( sp != null ); + } + + public static bool GetSpeeds( object obj, ref double activeSpeed, ref double passiveSpeed ) + { + if ( !Enabled ) + return false; + + if ( m_Table == null ) + LoadTable(); + + SpeedInfo sp = (SpeedInfo)m_Table[obj.GetType()]; + + if ( sp == null ) + return false; + + activeSpeed = sp.ActiveSpeed; + passiveSpeed = sp.PassiveSpeed; + + return true; + } + + private static void LoadTable() + { + m_Table = new Hashtable(); + + for ( int i = 0; i < m_Speeds.Length; ++i ) + { + SpeedInfo info = m_Speeds[i]; + Type[] types = info.Types; + + for ( int j = 0; j < types.Length; ++j ) + m_Table[types[j]] = info; + } + } + + private static Hashtable m_Table; + + private static SpeedInfo[] m_Speeds = new SpeedInfo[] + { + /* Slow */ + new SpeedInfo( 0.3, 0.6, new Type[] + { + typeof( AntLion ), typeof( ArcticOgreLord ), typeof( BogThing ), + typeof( Bogle ), typeof( BoneKnight ), typeof( EarthElemental ), + typeof( Ettin ), typeof( FrostOoze ), typeof( FrostTroll ), + typeof( GazerLarva ), typeof( Ghoul ), typeof( Golem ), + typeof( HeadlessOne ), typeof( Jwilson ), typeof( Mummy ), + typeof( Ogre ), typeof( OgreLord ), typeof( PlagueBeast ), + typeof( Quagmire ), typeof( Rat ), typeof( RottingCorpse ), + typeof( Sewerrat ), typeof( Skeleton ), typeof( Slime ), + typeof( Zombie ), typeof( Walrus ), typeof( RestlessSoul ), + typeof( CrystalElemental ), typeof( DarknightCreeper ), typeof( MoundOfMaggots ), + typeof( Juggernaut ), typeof( Yamandon ), typeof( Serado ) + } ), + /* Fast */ + new SpeedInfo( 0.2, 0.4, new Type[] + { + typeof( LordOaks ), typeof( Silvani ), typeof( AirElemental ), + typeof( AncientWyrm ), typeof( Balron ), typeof( BladeSpirits ), + typeof( DreadSpider ), typeof( Efreet ), typeof( EtherealWarrior ), + typeof( Lich ), typeof( Nightmare ), typeof( OphidianArchmage ), + typeof( OphidianMage ), typeof( OphidianWarrior ), typeof( OphidianMatriarch ), + typeof( OphidianKnight ), typeof( PoisonElemental ), typeof( Revenant ), + typeof( SandVortex ), typeof( SavageRider ), typeof( SavageShaman ), + typeof( SnowElemental ), typeof( WhiteWyrm ), typeof( Wisp ), + typeof( DemonKnight ), typeof( GiantBlackWidow ), typeof( SummonedAirElemental ), + typeof( LesserHiryu ), typeof( Hiryu ), typeof( LadyOfTheSnow ), + typeof( RaiJu ), typeof( Ronin ), typeof( RuneBeetle ), + typeof( Changeling ), + #region ML named mobs - before Paragon speedboost + typeof( LadyJennifyr ), typeof( LadyMarai ), typeof( MasterJonath ), + typeof( MasterMikael ), typeof( MasterTheophilus ), typeof( RedDeath ), + typeof( SirPatrick ), typeof( Miasma ), typeof( Rend ), + typeof( Grobu ), typeof( Gnaw ), typeof( Guile ), + typeof( Irk ), typeof( Spite ), typeof( LadyLissith ), + typeof( LadySabrix ), typeof( Malefic ), typeof( Silk ), + typeof( Virulent ) + // TODO: Where to put Lurg, Putrefier, Swoop and Pyre? They seem slower. + #endregion + } ), + /* Very Fast */ + new SpeedInfo( 0.175, 0.350, new Type[] + { + typeof( Barracoon ), typeof( Mephitis ), typeof( Neira ), + typeof( Rikktor ), typeof( Semidar ), typeof( EnergyVortex ), + typeof( EliteNinja ), typeof( Pixie ), typeof( SilverSerpent ), + typeof( VorpalBunny ), typeof( FleshRenderer ), typeof( KhaldunRevenant ), + typeof( FactionDragoon ), typeof( FactionKnight ), typeof( FactionPaladin ), + typeof( FactionHenchman ), typeof( FactionMercenary ), typeof( FactionNecromancer ), + typeof( FactionSorceress ), typeof( FactionWizard ), typeof( FactionBerserker ), + typeof( FactionPaladin ), typeof( Leviathan ), typeof( FireBeetle ), + typeof( FanDancer ), typeof( FactionDeathKnight ) + } ), + /* Medium */ + new SpeedInfo( 0.25, 0.5, new Type[] + { + typeof( AcidElemental ), typeof( AgapiteElemental ), typeof( Alligator ), + typeof( AncientLich ), typeof( Betrayer ), typeof( Bird ), + typeof( BlackBear ), typeof( BlackSolenInfiltratorQueen ), typeof( BlackSolenInfiltratorWarrior ), + typeof( BlackSolenQueen ), typeof( BlackSolenWarrior ), typeof( BlackSolenWorker ), + typeof( BloodElemental ), typeof( Boar ), typeof( Bogling ), + typeof( BoneMagi ), typeof( Brigand ), typeof( BronzeElemental ), + typeof( BrownBear ), typeof( Bull ), typeof( BullFrog ), + typeof( Cat ), typeof( Centaur ), typeof( ChaosDaemon ), + typeof( Chicken ), typeof( GolemController ), typeof( CopperElemental ), + typeof( CopperElemental ), typeof( Cougar ), typeof( Cow ), + typeof( Cyclops ), typeof( Daemon ), typeof( DeepSeaSerpent ), + typeof( DesertOstard ), typeof( DireWolf ), typeof( Dog ), + typeof( Dolphin ), typeof( Dragon ), typeof( Drake ), + typeof( DullCopperElemental ), typeof( Eagle ), typeof( ElderGazer ), + typeof( EvilMage ), typeof( EvilMageLord ), typeof( Executioner ), + typeof( Savage ), typeof( FireElemental ), typeof( FireGargoyle ), + typeof( FireSteed ), typeof( ForestOstard ), typeof( FrenziedOstard ), + typeof( FrostSpider ), typeof( Gargoyle ), typeof( Gazer ), + typeof( IceSerpent ), typeof( GiantRat ), typeof( GiantSerpent ), + typeof( GiantSpider ), typeof( GiantToad ), typeof( Goat ), + typeof( GoldenElemental ), typeof( Gorilla ), typeof( GreatHart ), + typeof( GreyWolf ), typeof( GrizzlyBear ), typeof( Guardian ), + typeof( Harpy ), typeof( Harrower ), typeof( HellHound ), + typeof( Hind ), typeof( HordeMinion ), typeof( Horse ), + typeof( Horse ), typeof( IceElemental ), typeof( IceFiend ), + typeof( IceSnake ), typeof( Imp ), typeof( JackRabbit ), + typeof( Kirin ), typeof( Kraken ), typeof( PredatorHellCat ), + typeof( LavaLizard ), typeof( LavaSerpent ), typeof( LavaSnake ), + typeof( Lizardman ), typeof( Llama ), typeof( Mongbat ), + typeof( StrongMongbat ), typeof( MountainGoat ), typeof( Orc ), + typeof( OrcBomber ), typeof( OrcBrute ), typeof( OrcCaptain ), + typeof( OrcishLord ), typeof( OrcishMage ), typeof( PackHorse ), + typeof( PackLlama ), typeof( Panther ), typeof( Pig ), + typeof( PlagueSpawn ), typeof( PolarBear ), typeof( Rabbit ), + typeof( Ratman ), typeof( RatmanArcher ), typeof( RatmanMage ), + typeof( RedSolenInfiltratorQueen ), typeof( RedSolenInfiltratorWarrior ), typeof( RedSolenQueen ), + typeof( RedSolenWarrior ), typeof( RedSolenWorker ), typeof( RidableLlama ), + typeof( Ridgeback ), typeof( Scorpion ), typeof( SeaSerpent ), + typeof( SerpentineDragon ), typeof( Shade ), typeof( ShadowIronElemental ), + typeof( ShadowWisp ), typeof( ShadowWyrm ), typeof( Sheep ), + typeof( SilverSteed ), typeof( SkeletalDragon ), typeof( SkeletalMage ), + typeof( SkeletalMount ), typeof( HellCat ), typeof( Snake ), + typeof( SnowLeopard ), typeof( SpectralArmour ), typeof( Spectre ), + typeof( StoneGargoyle ), typeof( StoneHarpy ), typeof( SwampDragon ), + typeof( ScaledSwampDragon ), typeof( SwampTentacle ), typeof( TerathanAvenger ), + typeof( TerathanDrone ), typeof( TerathanMatriarch ), typeof( TerathanWarrior ), + typeof( TimberWolf ), typeof( Titan ), typeof( Troll ), + typeof( Unicorn ), typeof( ValoriteElemental ), typeof( VeriteElemental ), + typeof( CoMWarHorse ), typeof( MinaxWarHorse ), typeof( SLWarHorse ), + typeof( TBWarHorse ), typeof( WaterElemental ), typeof( WhippingVine ), + typeof( WhiteWolf ), typeof( Wraith ), typeof( Wyvern ), + typeof( KhaldunZealot ), typeof( KhaldunSummoner ), typeof( SavageRidgeback ), + typeof( LichLord ), typeof( SkeletalKnight ), typeof( SummonedDaemon ), + typeof( SummonedEarthElemental ), typeof( SummonedWaterElemental ), typeof( SummonedFireElemental ), + typeof( MeerWarrior ), typeof( MeerEternal ), typeof( MeerMage ), + typeof( MeerCaptain ), typeof( JukaLord ), typeof( JukaMage ), + typeof( JukaWarrior ), typeof( AbysmalHorror ), typeof( BoneDemon ), + typeof( Devourer ), typeof( FleshGolem ), typeof( Gibberling ), + typeof( GoreFiend ), typeof( Impaler ), typeof( PatchworkSkeleton ), + typeof( Ravager ), typeof( ShadowKnight ), typeof( SkitteringHopper ), + typeof( Treefellow ), typeof( VampireBat ), typeof( WailingBanshee ), + typeof( WandererOfTheVoid ), typeof( Cursed ), typeof( GrimmochDrummel ), + typeof( LysanderGathenwale ), typeof( MorgBergen ), typeof( ShadowFiend ), + typeof( SpectralArmour ), typeof( TavaraSewel ), typeof( ArcaneDaemon ), + typeof( Doppleganger ), typeof( EnslavedGargoyle ), typeof( ExodusMinion ), + typeof( ExodusOverseer ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ), + typeof( Moloch ), typeof( BakeKitsune ), typeof( DeathwatchBeetleHatchling ), + typeof( Kappa ), typeof( KazeKemono ), typeof( DeathwatchBeetle ), + typeof( TsukiWolf ), typeof( YomotsuElder ), typeof( YomotsuPriest ), + typeof( YomotsuWarrior ), typeof( RevenantLion ), typeof( Oni ), + typeof( Gaman ), typeof( Crane ), typeof( Beetle ) + } ) + }; + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/ThiefAI.cs b/Scripts/Mobiles/AI/ThiefAI.cs new file mode 100644 index 0000000..36059f5 --- /dev/null +++ b/Scripts/Mobiles/AI/ThiefAI.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Items; + +// +// This is a first simple AI +// +// + +namespace Server.Mobiles +{ + public class ThiefAI : BaseAI + { + public ThiefAI(BaseCreature m) + : base(m) + { + } + + private Item m_toDisarm; + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + + Action = ActionType.Guard; + + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + if (m_toDisarm == null) + m_toDisarm = combatant.FindItemOnLayer(Layer.OneHanded); + + if (m_toDisarm == null) + m_toDisarm = combatant.FindItemOnLayer(Layer.TwoHanded); + + if (m_toDisarm != null && m_toDisarm.IsChildOf(m_Mobile.Backpack)) + { + m_toDisarm = combatant.FindItemOnLayer(Layer.OneHanded); + if (m_toDisarm == null) + m_toDisarm = combatant.FindItemOnLayer(Layer.TwoHanded); + } + if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.ArmsLore].Value >= 80.0 && m_toDisarm != null) + EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(m_Mobile)); + + if (m_toDisarm != null && m_toDisarm.IsChildOf(combatant.Backpack) && m_Mobile.NextSkillTime <= DateTime.Now && (m_toDisarm.LootType != LootType.Blessed && m_toDisarm.LootType != LootType.Newbied)) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + if (m_Mobile.Target != null) + m_Mobile.Target.Invoke(m_Mobile, m_toDisarm); + } + else if (m_toDisarm == null && m_Mobile.NextSkillTime <= DateTime.Now) + { + Container cpack = combatant.Backpack; + + if (cpack != null) + { + Item steala = cpack.FindItemByType(typeof(Bandage)); + if (steala != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + if (m_Mobile.Target != null) + m_Mobile.Target.Invoke(m_Mobile, steala); + } + Item stealb = cpack.FindItemByType(typeof(Nightshade)); + if (stealb != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + if (m_Mobile.Target != null) + m_Mobile.Target.Invoke(m_Mobile, stealb); + } + Item stealc = cpack.FindItemByType(typeof(BlackPearl)); + if (stealc != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + if (m_Mobile.Target != null) + m_Mobile.Target.Invoke(m_Mobile, stealc); + } + + Item steald = cpack.FindItemByType(typeof(MandrakeRoot)); + if (steald != null) + { + m_Mobile.DebugSay("Trying to steal from combatant."); + m_Mobile.UseSkill(SkillName.Stealing); + if (m_Mobile.Target != null) + m_Mobile.Target.Invoke(m_Mobile, steald); + } + else if (steala == null && stealb == null && stealc == null && steald == null) + { + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + + Action = ActionType.Flee; + } + } + } + } + else + { + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100 && m_Mobile.CanFlee) + { + // We are low on health, should we flee? + + bool flee = false; + + if (m_Mobile.Hits < combatant.Hits) + { + // We are more hurt than them + + int diff = combatant.Hits - m_Mobile.Hits; + + flee = (Utility.Random(0, 100) > (10 + diff)); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) > 10; // 10% chance to flee + } + + if (flee) + { + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + + Action = ActionType.Flee; + } + } + + return true; + } + + public override bool DoActionGuard() + { + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + public override bool DoActionFlee() + { + if (m_Mobile.Hits > m_Mobile.HitsMax / 2) + { + m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); + Action = ActionType.Combat; + } + else + { + m_Mobile.FocusMob = m_Mobile.Combatant; + base.DoActionFlee(); + } + + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/AI/VendorAI.cs b/Scripts/Mobiles/AI/VendorAI.cs new file mode 100644 index 0000000..35eaa26 --- /dev/null +++ b/Scripts/Mobiles/AI/VendorAI.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +// +// This is a first simple AI +// +// + +namespace Server.Mobiles +{ + public class VendorAI : BaseAI + { + public VendorAI(BaseCreature m) : base (m) + { + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay( "I'm fine" ); + + if ( m_Mobile.Combatant != null ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} is attacking me", m_Mobile.Combatant.Name ); + + m_Mobile.Say( Utility.RandomList( 1005305, 501603 ) ); + + Action = ActionType.Flee; + } + else + { + if ( m_Mobile.FocusMob != null ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} has talked to me", m_Mobile.FocusMob.Name ); + + Action = ActionType.Interact; + } + else + { + m_Mobile.Warmode = false; + + base.DoActionWander(); + } + } + + return true; + } + + public override bool DoActionInteract() + { + Mobile customer = m_Mobile.FocusMob; + + if ( m_Mobile.Combatant != null ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} is attacking me", m_Mobile.Combatant.Name ); + + m_Mobile.Say( Utility.RandomList( 1005305, 501603 ) ); + + Action = ActionType.Flee; + + return true; + } + + if ( customer == null || customer.Deleted || customer.Map != m_Mobile.Map ) + { + m_Mobile.DebugSay( "My customer have disapeared" ); + m_Mobile.FocusMob = null; + + Action = ActionType.Wander; + } + else + { + if ( customer.InRange( m_Mobile, m_Mobile.RangeFight ) ) + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "I am with {0}", customer.Name ); + + m_Mobile.Direction = m_Mobile.GetDirectionTo( customer ); + } + else + { + if ( m_Mobile.Debug ) + m_Mobile.DebugSay( "{0} is gone", customer.Name ); + + m_Mobile.FocusMob = null; + + Action = ActionType.Wander; + } + } + + return true; + } + + public override bool DoActionGuard() + { + m_Mobile.FocusMob = m_Mobile.Combatant; + return base.DoActionGuard(); + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.InRange( m_Mobile, 4 ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + // Temporary + public override void OnSpeech( SpeechEventArgs e ) + { + base.OnSpeech( e ); + + Mobile from = e.Mobile; + + if ( m_Mobile is BaseVendor && from.InRange( m_Mobile, Core.AOS ? 1 : 4 ) && !e.Handled ) + { + if ( e.HasKeyword( 0x14D ) ) // *vendor sell* + { + e.Handled = true; + + ((BaseVendor)m_Mobile).VendorSell( from ); + m_Mobile.FocusMob = from; + } + else if (e.HasKeyword(0x3C)) // *vendor buy* + { + e.Handled = true; + + ((BaseVendor)m_Mobile).VendorBuy(from); + m_Mobile.FocusMob = from; + } + else if (WasNamed(e.Speech)) + { + if (e.HasKeyword(0x177)) // *sell* + { + e.Handled = true; + + ((BaseVendor)m_Mobile).VendorSell(from); + } + else if (e.HasKeyword(0x171)) // *buy* + { + e.Handled = true; + + ((BaseVendor)m_Mobile).VendorBuy(from); + } + + m_Mobile.FocusMob = from; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Bears/BlackBear.cs b/Scripts/Mobiles/Animals/Bears/BlackBear.cs new file mode 100644 index 0000000..0dab468 --- /dev/null +++ b/Scripts/Mobiles/Animals/Bears/BlackBear.cs @@ -0,0 +1,69 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'ours" )] + [TypeAlias( "Server.Mobiles.Bear" )] + public class BlackBear : BaseCreature + { + [Constructable] + public BlackBear() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un ours noir"; + Body = 211; + BaseSoundID = 0xA3; + + SetStr( 76, 100 ); + SetDex( 56, 75 ); + SetInt( 11, 14 ); + + SetHits( 46, 60 ); + SetMana( 0 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + + SetSkill( SkillName.MagicResist, 20.1, 40.0 ); + SetSkill( SkillName.Tactics, 40.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.Meat | FoodType.FruitsAndVegies; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Bear; } } + + public BlackBear( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Bears/BrownBear.cs b/Scripts/Mobiles/Animals/Bears/BrownBear.cs new file mode 100644 index 0000000..e23f820 --- /dev/null +++ b/Scripts/Mobiles/Animals/Bears/BrownBear.cs @@ -0,0 +1,68 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps d'ours")] + public class BrownBear : BaseCreature + { + [Constructable] + public BrownBear() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un ours brun"; + Body = 167; + BaseSoundID = 0xA3; + + SetStr( 76, 100 ); + SetDex( 26, 45 ); + SetInt( 23, 47 ); + + SetHits( 46, 60 ); + SetMana( 0 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 30 ); + SetResistance( ResistanceType.Cold, 15, 20 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + + SetSkill( SkillName.MagicResist, 25.1, 35.0 ); + SetSkill( SkillName.Tactics, 40.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 41.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Bear; } } + + public BrownBear( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Bears/GrizzlyBear.cs b/Scripts/Mobiles/Animals/Bears/GrizzlyBear.cs new file mode 100644 index 0000000..3c5a17f --- /dev/null +++ b/Scripts/Mobiles/Animals/Bears/GrizzlyBear.cs @@ -0,0 +1,70 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de grizzly" )] + [TypeAlias( "Server.Mobiles.Grizzlybear" )] + public class GrizzlyBear : BaseCreature + { + [Constructable] + public GrizzlyBear() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un grizzly"; + Body = 212; + BaseSoundID = 0xA3; + + SetStr( 126, 155 ); + SetDex( 81, 105 ); + SetInt( 16, 40 ); + + SetHits( 76, 93 ); + SetMana( 0 ); + + SetDamage( 8, 13 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 70.1, 100.0 ); + SetSkill( SkillName.Wrestling, 45.1, 70.0 ); + + Fame = 1000; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + } + + public override int Meat{ get{ return 2; } } + public override int Hides{ get{ return 16; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Bear; } } + + public GrizzlyBear( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Bears/PolarBear.cs b/Scripts/Mobiles/Animals/Bears/PolarBear.cs new file mode 100644 index 0000000..39e0e80 --- /dev/null +++ b/Scripts/Mobiles/Animals/Bears/PolarBear.cs @@ -0,0 +1,70 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'ours polaire" )] + [TypeAlias( "Server.Mobiles.Polarbear" )] + public class PolarBear : BaseCreature + { + [Constructable] + public PolarBear() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un ours polaire"; + Body = 213; + BaseSoundID = 0xA3; + + SetStr( 116, 140 ); + SetDex( 81, 105 ); + SetInt( 26, 50 ); + + SetHits( 70, 84 ); + SetMana( 0 ); + + SetDamage( 7, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Cold, 60, 80 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 60.1, 90.0 ); + SetSkill( SkillName.Wrestling, 45.1, 70.0 ); + + Fame = 1500; + Karma = 0; + + VirtualArmor = 18; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public override int Meat{ get{ return 2; } } + public override int Hides{ get{ return 16; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.FruitsAndVegies | FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Bear; } } + + public PolarBear( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Birds/Chicken.cs b/Scripts/Mobiles/Animals/Birds/Chicken.cs new file mode 100644 index 0000000..f36c37e --- /dev/null +++ b/Scripts/Mobiles/Animals/Birds/Chicken.cs @@ -0,0 +1,68 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de poulet" )] + public class Chicken : BaseCreature + { + [Constructable] + public Chicken() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un poulet"; + Body = 0xD0; + BaseSoundID = 0x6E; + + SetStr( 5 ); + SetDex( 15 ); + SetInt( 5 ); + + SetHits( 3 ); + SetMana( 0 ); + + SetDamage( 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 1, 5 ); + + SetSkill( SkillName.MagicResist, 4.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 2; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public override bool CanFly { get { return true; } } + public override int Meat{ get{ return 1; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay; } } + + public override int Feathers{ get{ return 25; } } + + public Chicken(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Birds/Crane.cs b/Scripts/Mobiles/Animals/Birds/Crane.cs new file mode 100644 index 0000000..2830ab9 --- /dev/null +++ b/Scripts/Mobiles/Animals/Birds/Crane.cs @@ -0,0 +1,86 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de grue" )] + public class Crane : BaseCreature + { + [Constructable] + public Crane() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une grue"; + Body = 254; + BaseSoundID = 0x4D7; + + SetStr( 26, 35 ); + SetDex( 16, 25 ); + SetInt( 11, 15 ); + + SetHits( 26, 35 ); + SetMana( 0 ); + + SetDamage( 1, 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 5 ); + + SetSkill( SkillName.MagicResist, 4.1, 5.0 ); + SetSkill( SkillName.Tactics, 10.1, 11.0 ); + SetSkill( SkillName.Wrestling, 10.1, 11.0 ); + + Fame = 0; + Karma = 200; + + VirtualArmor = 5; + } + + public override int Meat{ get{ return 1; } } + public override int Feathers{ get{ return 25; } } + + + public override int GetAngerSound() + { + return 0x4D9; + } + + public override int GetIdleSound() + { + return 0x4D8; + } + + public override int GetAttackSound() + { + return 0x4D7; + } + + public override int GetHurtSound() + { + return 0x4DA; + } + + public override int GetDeathSound() + { + return 0x4D6; + } + + public Crane(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Birds/Eagle.cs b/Scripts/Mobiles/Animals/Birds/Eagle.cs new file mode 100644 index 0000000..15e0d80 --- /dev/null +++ b/Scripts/Mobiles/Animals/Birds/Eagle.cs @@ -0,0 +1,72 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'aigle" )] + public class Eagle : BaseCreature + { + [Constructable] + public Eagle() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un aigle"; + Body = 5; + BaseSoundID = 0x2EE; + + SetStr( 31, 47 ); + SetDex( 36, 60 ); + SetInt( 8, 20 ); + + SetHits( 20, 27 ); + SetMana( 0 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 15.3, 30.0 ); + SetSkill( SkillName.Tactics, 18.1, 37.0 ); + SetSkill( SkillName.Wrestling, 20.1, 30.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 22; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 17.1; + } + + public override bool CanFly { get { return true; } } + public override int Meat{ get{ return 1; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override int Feathers{ get{ return 36; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + + public Eagle(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Birds/Phoenix.cs b/Scripts/Mobiles/Animals/Birds/Phoenix.cs new file mode 100644 index 0000000..16899be --- /dev/null +++ b/Scripts/Mobiles/Animals/Birds/Phoenix.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de ph�nix" )] + public class Phoenix : BaseCreature + { + [Constructable] + public Phoenix() : base( AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un ph�nix"; + Body = 5; + Hue = 0x674; + BaseSoundID = 0x8F; + + SetStr( 504, 700 ); + SetDex( 202, 300 ); + SetInt( 504, 700 ); + + SetHits( 340, 383 ); + + SetDamage( 25 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 50 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 90.2, 100.0 ); + SetSkill( SkillName.Magery, 90.2, 100.0 ); + SetSkill( SkillName.Meditation, 75.1, 100.0 ); + SetSkill( SkillName.MagicResist, 86.0, 135.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = 0; + + VirtualArmor = 60; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + public override bool CanFly { get { return true; } } + public override int Meat{ get{ return 1; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override int Feathers{ get{ return 36; } } + + public Phoenix( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Canines/DireWolf.cs b/Scripts/Mobiles/Animals/Canines/DireWolf.cs new file mode 100644 index 0000000..ac70f0d --- /dev/null +++ b/Scripts/Mobiles/Animals/Canines/DireWolf.cs @@ -0,0 +1,72 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de loup sombre" )] + [TypeAlias( "Server.Mobiles.Direwolf" )] + public class DireWolf : BaseCreature + { + [Constructable] + public DireWolf() : base( AIType.AI_Melee,FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un loup sombre"; + Body = 23; + BaseSoundID = 0xE5; + + SetStr( 96, 120 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + SetMana( 0 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 57.6, 75.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 22; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 7; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public DireWolf(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Canines/GreyWolf.cs b/Scripts/Mobiles/Animals/Canines/GreyWolf.cs new file mode 100644 index 0000000..25ffca1 --- /dev/null +++ b/Scripts/Mobiles/Animals/Canines/GreyWolf.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de loup gris" )] + [TypeAlias( "Server.Mobiles.Greywolf" )] + public class GreyWolf : BaseCreature + { + [Constructable] + public GreyWolf() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un loup gris"; + Body = Utility.RandomList( 25, 27 ); + BaseSoundID = 0xE5; + + SetStr( 56, 80 ); + SetDex( 56, 75 ); + SetInt( 31, 55 ); + + SetHits( 34, 48 ); + SetMana( 0 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 20.1, 35.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 53.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public GreyWolf(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Canines/TimberWolf.cs b/Scripts/Mobiles/Animals/Canines/TimberWolf.cs new file mode 100644 index 0000000..acce34c --- /dev/null +++ b/Scripts/Mobiles/Animals/Canines/TimberWolf.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de loup des bois" )] + [TypeAlias( "Server.Mobiles.Timberwolf" )] + public class TimberWolf : BaseCreature + { + [Constructable] + public TimberWolf() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un loup des bois"; + Body = 225; + BaseSoundID = 0xE5; + + SetStr( 56, 80 ); + SetDex( 56, 75 ); + SetInt( 11, 25 ); + + SetHits( 34, 48 ); + SetMana( 0 ); + + SetDamage( 5, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 27.6, 45.0 ); + SetSkill( SkillName.Tactics, 30.1, 50.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 5; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public TimberWolf(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Canines/WhiteWolf.cs b/Scripts/Mobiles/Animals/Canines/WhiteWolf.cs new file mode 100644 index 0000000..b15858b --- /dev/null +++ b/Scripts/Mobiles/Animals/Canines/WhiteWolf.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de loup blanc" )] + [TypeAlias( "Server.Mobiles.Whitewolf" )] + public class WhiteWolf : BaseCreature + { + [Constructable] + public WhiteWolf() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un loup blanc"; + Body = Utility.RandomList( 34, 37 ); + BaseSoundID = 0xE5; + + SetStr( 56, 80 ); + SetDex( 56, 75 ); + SetInt( 31, 55 ); + + SetHits( 34, 48 ); + SetMana( 0 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 20.1, 35.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 65.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public WhiteWolf( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Cows/Bull.cs b/Scripts/Mobiles/Animals/Cows/Bull.cs new file mode 100644 index 0000000..a970d14 --- /dev/null +++ b/Scripts/Mobiles/Animals/Cows/Bull.cs @@ -0,0 +1,72 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de taureau" )] + public class Bull : BaseCreature + { + [Constructable] + public Bull() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un taureau"; + Body = Utility.RandomList( 0xE8, 0xE9 ); + BaseSoundID = 0x64; + + if ( 0.5 >= Utility.RandomDouble() ) + Hue = 0x901; + + SetStr( 77, 111 ); + SetDex( 56, 75 ); + SetInt( 47, 75 ); + + SetHits( 50, 64 ); + SetMana( 0 ); + + SetDamage( 4, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + + SetSkill( SkillName.MagicResist, 17.6, 25.0 ); + SetSkill( SkillName.Tactics, 67.6, 85.0 ); + SetSkill( SkillName.Wrestling, 40.1, 57.5 ); + + Fame = 600; + Karma = 0; + + VirtualArmor = 28; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 15; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Bull; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Bull(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Cows/Cow.cs b/Scripts/Mobiles/Animals/Cows/Cow.cs new file mode 100644 index 0000000..0d36fa0 --- /dev/null +++ b/Scripts/Mobiles/Animals/Cows/Cow.cs @@ -0,0 +1,154 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de vache" )] + public class Cow : BaseCreature + { + private DateTime m_MilkedOn; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime MilkedOn + { + get { return m_MilkedOn; } + set { m_MilkedOn = value; } + } + + private int m_Milk; + + [CommandProperty( AccessLevel.GameMaster )] + public int Milk + { + get { return m_Milk; } + set { m_Milk = value; } + } + + [Constructable] + public Cow() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une vache"; + Body = Utility.RandomList( 0xD8, 0xE7 ); + BaseSoundID = 0x78; + + SetStr( 30 ); + SetDex( 15 ); + SetInt( 5 ); + + SetHits( 18 ); + SetMana( 0 ); + + SetDamage( 1, 4 ); + + SetDamage( 1, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 15 ); + + SetSkill( SkillName.MagicResist, 5.5 ); + SetSkill( SkillName.Tactics, 5.5 ); + SetSkill( SkillName.Wrestling, 5.5 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + + if ( Core.AOS && Utility.Random( 1000 ) == 0 ) // 0.1% chance to have mad cows + FightMode = FightMode.Closest; + } + + public override int Meat{ get{ return 8; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public override void OnDoubleClick( Mobile from ) + { + base.OnDoubleClick( from ); + + int random = Utility.Random( 100 ); + + if ( random < 5 ) + Tip(); + else if ( random < 20 ) + PlaySound( 120 ); + else if ( random < 40 ) + PlaySound( 121 ); + } + + public void Tip() + { + PlaySound( 121 ); + Animate( 8, 0, 3, true, false, 0 ); + } + + public bool TryMilk( Mobile from ) + { + if ( !from.InLOS( this ) || !from.InRange( Location, 2 ) ) + from.SendMessage( "Vous ne pouvez traire la vache d'ici" ); // You can not milk the cow from this location. + else if ( Controlled && ControlMaster != from ) + from.SendMessage( "La vache �chappe agilement � votre tentative de la traire" ); // The cow nimbly escapes your attempts to milk it. + else if ( m_Milk == 0 && m_MilkedOn + TimeSpan.FromDays( 1 ) > DateTime.Now ) + from.SendMessage( "Cette vache n'a plus de lait, r�essayez demain" ); // This cow can not be milked now. Please wait for some time. + else + { + if ( m_Milk == 0 ) + m_Milk = 4; + + m_MilkedOn = DateTime.Now; + m_Milk--; + + // Scriptiz : s'il y a un taureau dans les environs, il est possible qu'il charge + if (Utility.Random(1, 10) == 1) // 1 chance sur 10 + { + foreach (Mobile m in this.GetMobilesInRange(10)) + { + if (m != null && m is Bull) + { + m.Emote("*Mugit et charge " + from.Name + "*"); + m.Attack(from); + } + } + } + + return true; + } + + return false; + } + + public Cow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.Write( (DateTime) m_MilkedOn ); + writer.Write( (int) m_Milk ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version > 0 ) + { + m_MilkedOn = reader.ReadDateTime(); + m_Milk = reader.ReadInt(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Felines/Cougar.cs b/Scripts/Mobiles/Animals/Felines/Cougar.cs new file mode 100644 index 0000000..4f35a07 --- /dev/null +++ b/Scripts/Mobiles/Animals/Felines/Cougar.cs @@ -0,0 +1,69 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cougar" )] + public class Cougar : BaseCreature + { + [Constructable] + public Cougar() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un cougar"; + Body = 63; + BaseSoundID = 0x73; + + SetStr( 56, 80 ); + SetDex( 66, 85 ); + SetInt( 26, 50 ); + + SetHits( 34, 48 ); + SetMana( 0 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + + SetSkill( SkillName.MagicResist, 15.1, 30.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 41.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 10; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Feline; } } + + public Cougar(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Felines/HellCat.cs b/Scripts/Mobiles/Animals/Felines/HellCat.cs new file mode 100644 index 0000000..0444791 --- /dev/null +++ b/Scripts/Mobiles/Animals/Felines/HellCat.cs @@ -0,0 +1,77 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de chat infernal" )] + [TypeAlias( "Server.Mobiles.Hellcat" )] + public class HellCat : BaseCreature + { + [Constructable] + public HellCat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un chat infernal"; + Body = 0xC9; + Hue = Utility.RandomList( 0x647, 0x650, 0x659, 0x662, 0x66B, 0x674); + BaseSoundID = 0x69; + + SetStr( 51, 100 ); + SetDex( 52, 150 ); + SetInt( 13, 85 ); + + SetHits( 48, 67 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Fire, 60 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 80, 90 ); + SetResistance( ResistanceType.Energy, 15, 20 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 40.1, 55.0 ); + SetSkill( SkillName.Wrestling, 30.1, 40.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Feline; } } + + public HellCat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Felines/Panther.cs b/Scripts/Mobiles/Animals/Felines/Panther.cs new file mode 100644 index 0000000..9a5c432 --- /dev/null +++ b/Scripts/Mobiles/Animals/Felines/Panther.cs @@ -0,0 +1,70 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de panth�re" )] + public class Panther : BaseCreature + { + [Constructable] + public Panther() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une panth�re"; + Body = 0xD6; + Hue = 0x901; + BaseSoundID = 0x462; + + SetStr( 61, 85 ); + SetDex( 86, 105 ); + SetInt( 26, 50 ); + + SetHits( 37, 51 ); + SetMana( 0 ); + + SetDamage( 4, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + + SetSkill( SkillName.MagicResist, 15.1, 30.0 ); + SetSkill( SkillName.Tactics, 50.1, 65.0 ); + SetSkill( SkillName.Wrestling, 50.1, 65.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 53.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 10; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Feline; } } + + public Panther(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Felines/PredatorHellCat.cs b/Scripts/Mobiles/Animals/Felines/PredatorHellCat.cs new file mode 100644 index 0000000..62c138b --- /dev/null +++ b/Scripts/Mobiles/Animals/Felines/PredatorHellCat.cs @@ -0,0 +1,75 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de chat infernal" )] + [TypeAlias( "Server.Mobiles.Preditorhellcat" )] + public class PredatorHellCat : BaseCreature + { + [Constructable] + public PredatorHellCat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un chat infernal"; + Body = 127; + BaseSoundID = 0xBA; + + SetStr( 161, 185 ); + SetDex( 96, 115 ); + SetInt( 76, 100 ); + + SetHits( 97, 131 ); + + SetDamage( 5, 17 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Fire, 25 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Energy, 5, 15 ); + + SetSkill( SkillName.MagicResist, 75.1, 90.0 ); + SetSkill( SkillName.Tactics, 50.1, 65.0 ); + SetSkill( SkillName.Wrestling, 50.1, 65.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 89.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Feline; } } + + public PredatorHellCat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Felines/SnowLeopard.cs b/Scripts/Mobiles/Animals/Felines/SnowLeopard.cs new file mode 100644 index 0000000..9e4afb1 --- /dev/null +++ b/Scripts/Mobiles/Animals/Felines/SnowLeopard.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de l�opard" )] + [TypeAlias( "Server.Mobiles.Snowleopard" )] + public class SnowLeopard : BaseCreature + { + [Constructable] + public SnowLeopard() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un l�opard des neiges"; + Body = Utility.RandomList( 64, 65 ); + BaseSoundID = 0x73; + + SetStr( 56, 80 ); + SetDex( 66, 85 ); + SetInt( 26, 50 ); + + SetHits( 34, 48 ); + SetMana( 0 ); + + SetDamage( 3, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 25.1, 35.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 50.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 53.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 8; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Feline; } } + + public SnowLeopard(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Boar.cs b/Scripts/Mobiles/Animals/Misc/Boar.cs new file mode 100644 index 0000000..18485b2 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Boar.cs @@ -0,0 +1,66 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de porc" )] + public class Boar : BaseCreature + { + [Constructable] + public Boar() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un porc"; + Body = 0x122; + BaseSoundID = 0xC4; + + SetStr( 25 ); + SetDex( 15 ); + SetInt( 5 ); + + SetHits( 15 ); + SetMana( 0 ); + + SetDamage( 3, 6 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + + SetSkill( SkillName.MagicResist, 9.0 ); + SetSkill( SkillName.Tactics, 9.0 ); + SetSkill( SkillName.Wrestling, 9.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override int Meat{ get{ return 2; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Boar(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/BullFrog.cs b/Scripts/Mobiles/Animals/Misc/BullFrog.cs new file mode 100644 index 0000000..7044976 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/BullFrog.cs @@ -0,0 +1,86 @@ +using System; +using Server.Mobiles; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de grenouille" )] + [TypeAlias( "Server.Mobiles.Bullfrog" )] + public class BullFrog : BaseCreature + { + [Constructable] + public BullFrog() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une grenouille taureau"; + Body = 81; + Hue = Utility.RandomList( 0x5AC,0x5A3,0x59A,0x591,0x588,0x57F ); + BaseSoundID = 0x266; + + SetStr( 46, 70 ); + SetDex( 6, 25 ); + SetInt( 11, 20 ); + + SetHits( 28, 42 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 40.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 350; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override void OnCarve(Mobile from, Items.Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (from.CheckSkill(SkillName.Forensics,10,40)) + { + corpse.DropItem(new BullFrogLard()); + } + base.OnCarve(from, corpse, with); + } + + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 4; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.Meat; } } + + public BullFrog(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Dolphin.cs b/Scripts/Mobiles/Animals/Misc/Dolphin.cs new file mode 100644 index 0000000..5f5df87 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Dolphin.cs @@ -0,0 +1,88 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de dauphin" )] + public class Dolphin : BaseCreature + { + [Constructable] + public Dolphin() + : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un dauphin"; + Body = 0x97; + BaseSoundID = 0x8A; + + SetStr( 21, 49 ); + SetDex( 66, 85 ); + SetInt( 96, 110 ); + + SetHits( 15, 27 ); + + SetDamage( 3, 6 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 25, 30 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.2, 29.0 ); + SetSkill( SkillName.Wrestling, 19.2, 29.0 ); + + Fame = 500; + Karma = 2000; + + VirtualArmor = 16; + CanSwim = true; + CantWalk = true; + } + + public override int Meat { get { return 1; } } + + public Dolphin( Serial serial ) + : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + if( from.AccessLevel >= AccessLevel.GameMaster ) + Jump(); + } + + public virtual void Jump() + { + if( Utility.RandomBool() ) + Animate( 3, 16, 1, true, false, 0 ); + else + Animate( 4, 20, 1, true, false, 0 ); + } + + public override void OnThink() + { + if( Utility.RandomDouble() < .005 ) // slim chance to jump + Jump(); + + base.OnThink(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Gaman.cs b/Scripts/Mobiles/Animals/Misc/Gaman.cs new file mode 100644 index 0000000..94b8513 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Gaman.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de Gaman" )] + public class Gaman : BaseCreature + { + [Constructable] + public Gaman() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un gaman"; + Body = 248; + + SetStr( 146, 175 ); + SetDex( 111, 150 ); + SetInt( 46, 60 ); + + SetHits( 131, 160 ); + SetMana( 0 ); + + SetDamage( 6, 11 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 70 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 30, 50 ); + + SetSkill( SkillName.MagicResist, 37.6, 42.5 ); + SetSkill( SkillName.Tactics, 70.6, 83.0 ); + SetSkill( SkillName.Wrestling, 50.1, 57.5 ); + + Fame = 2000; + Karma = -2000; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 68.7; + } + + public override int GetAngerSound() + { + return 0x4F8; + } + + public override int GetIdleSound() + { + return 0x4F7; + } + + public override int GetAttackSound() + { + return 0x4F6; + } + + public override int GetHurtSound() + { + return 0x4F9; + } + + public override int GetDeathSound() + { + return 0x4F5; + } + + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 15; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay; } } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + c.DropItem(new GamanHorns(Utility.RandomBool() ? 1 : 2)); + } + + public Gaman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Animals/Misc/GiantToad.cs b/Scripts/Mobiles/Animals/Misc/GiantToad.cs new file mode 100644 index 0000000..a001647 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/GiantToad.cs @@ -0,0 +1,91 @@ +using System; +using Server.Mobiles; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de crapaud" )] + [TypeAlias( "Server.Mobiles.Gianttoad" )] + public class GiantToad : BaseCreature + { + [Constructable] + public GiantToad() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un crapaud g�ant"; + Body = 80; + BaseSoundID = 0x26B; + + SetStr( 76, 100 ); + SetDex( 6, 25 ); + SetInt( 11, 20 ); + + SetHits( 46, 60 ); + SetMana( 0 ); + + SetDamage( 5, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 40.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 750; + Karma = -750; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 77.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override void OnCarve(Mobile from, Items.Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (from.CheckSkill(SkillName.Forensics, 10, 40)) + { + corpse.DropItem(new BullFrogLard()); + } + base.OnCarve(from, corpse, with); + } + + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.Meat; } } + + public GiantToad(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 1); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + if ( version < 1 ) + { + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Goat.cs b/Scripts/Mobiles/Animals/Misc/Goat.cs new file mode 100644 index 0000000..f1a3fc7 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Goat.cs @@ -0,0 +1,67 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de bouc" )] + public class Goat : BaseCreature + { + [Constructable] + public Goat() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un bouc"; + Body = 0xD1; + BaseSoundID = 0x99; + + SetStr( 19 ); + SetDex( 15 ); + SetInt( 5 ); + + SetHits( 12 ); + SetMana( 0 ); + + SetDamage( 3, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 15 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public override int Meat{ get{ return 2; } } + public override int Hides{ get{ return 8; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay | FoodType.FruitsAndVegies; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Goat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Gorilla.cs b/Scripts/Mobiles/Animals/Misc/Gorilla.cs new file mode 100644 index 0000000..bcd0526 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Gorilla.cs @@ -0,0 +1,67 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de gorille" )] + public class Gorilla : BaseCreature + { + [Constructable] + public Gorilla() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un gorille"; + Body = 0x1D; + BaseSoundID = 0x9E; + + SetStr( 53, 95 ); + SetDex( 36, 55 ); + SetInt( 36, 60 ); + + SetHits( 38, 51 ); + SetMana( 0 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 43.3, 58.0 ); + SetSkill( SkillName.Wrestling, 43.3, 58.0 ); + + Fame = 450; + Karma = 0; + + VirtualArmor = 20; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Gorilla(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/GreatHart.cs b/Scripts/Mobiles/Animals/Misc/GreatHart.cs new file mode 100644 index 0000000..e71be43 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/GreatHart.cs @@ -0,0 +1,81 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cerf" )] + [TypeAlias( "Server.Mobiles.Greathart" )] + public class GreatHart : BaseCreature + { + [Constructable] + public GreatHart() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un grand cerf"; + Body = 0xEA; + + SetStr( 41, 71 ); + SetDex( 47, 77 ); + SetInt( 27, 57 ); + + SetHits( 27, 41 ); + SetMana( 0 ); + + SetDamage( 5, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + + SetSkill( SkillName.MagicResist, 26.8, 44.5 ); + SetSkill( SkillName.Tactics, 29.8, 47.5 ); + SetSkill( SkillName.Wrestling, 29.8, 47.5 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 24; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + } + + public override int Meat{ get{ return 6; } } + public override int Hides{ get{ return 15; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public GreatHart(Serial serial) : base(serial) + { + } + + public override int GetAttackSound() + { + return 0x82; + } + + public override int GetHurtSound() + { + return 0x83; + } + + public override int GetDeathSound() + { + return 0x84; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Hind.cs b/Scripts/Mobiles/Animals/Misc/Hind.cs new file mode 100644 index 0000000..e0d2ae2 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Hind.cs @@ -0,0 +1,80 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cerf" )] + public class Hind : BaseCreature + { + [Constructable] + public Hind() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une biche"; + Body = 0xED; + + SetStr( 21, 51 ); + SetDex( 47, 77 ); + SetInt( 17, 47 ); + + SetHits( 15, 29 ); + SetMana( 0 ); + + SetDamage( 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 15 ); + SetResistance( ResistanceType.Cold, 5 ); + + SetSkill( SkillName.MagicResist, 15.0 ); + SetSkill( SkillName.Tactics, 19.0 ); + SetSkill( SkillName.Wrestling, 26.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public override int Meat{ get{ return 5; } } + public override int Hides{ get{ return 8; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Hind(Serial serial) : base(serial) + { + } + + public override int GetAttackSound() + { + return 0x82; + } + + public override int GetHurtSound() + { + return 0x83; + } + + public override int GetDeathSound() + { + return 0x84; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Llama.cs b/Scripts/Mobiles/Animals/Misc/Llama.cs new file mode 100644 index 0000000..4171d59 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Llama.cs @@ -0,0 +1,67 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de lama" )] + public class Llama : BaseCreature + { + [Constructable] + public Llama() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un lama"; + Body = 0xDC; + BaseSoundID = 0x3F3; + + SetStr( 21, 49 ); + SetDex( 36, 55 ); + SetInt( 16, 30 ); + + SetHits( 15, 27 ); + SetMana( 0 ); + + SetDamage( 3, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.2, 29.0 ); + SetSkill( SkillName.Wrestling, 19.2, 29.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Llama(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/MountainGoat.cs b/Scripts/Mobiles/Animals/Misc/MountainGoat.cs new file mode 100644 index 0000000..f541861 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/MountainGoat.cs @@ -0,0 +1,69 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de ch�vre des montagnes" )] + public class MountainGoat : BaseCreature + { + [Constructable] + public MountainGoat() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une ch�vre des montagnes"; + Body = 88; + BaseSoundID = 0x99; + + SetStr( 22, 64 ); + SetDex( 56, 75 ); + SetInt( 16, 30 ); + + SetHits( 20, 33 ); + SetMana( 0 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public override int Meat{ get{ return 2; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay | FoodType.FruitsAndVegies; } } + + public MountainGoat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/PackHorse.cs b/Scripts/Mobiles/Animals/Misc/PackHorse.cs new file mode 100644 index 0000000..a118bb8 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/PackHorse.cs @@ -0,0 +1,222 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Items; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cheval" )] + public class PackHorse : BaseCreature + { + [Constructable] + public PackHorse() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un cheval de trait"; + Body = 291; + BaseSoundID = 0xA8; + + SetStr( 44, 120 ); + SetDex( 36, 55 ); + SetInt( 6, 10 ); + + SetHits( 61, 80 ); + SetStam( 81, 100 ); + SetMana( 0 ); + + SetDamage( 5, 11 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 0; + Karma = 200; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + + Container pack = Backpack; + + if ( pack != null ) + pack.Delete(); + + pack = new StrongBackpack(); + pack.Movable = false; + + AddItem( pack ); + } + + public override int Meat{ get{ return 3; } } + public override int Hides{ get{ return 10; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public PackHorse( Serial serial ) : base( serial ) + { + } + + #region Pack Animal Methods + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + PackAnimal.CombineBackpacks( this ); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor( Item item ) + { + return DeathMoveResult.MoveToCorpse; + } + + public override bool IsSnoop( Mobile from ) + { + if ( PackAnimal.CheckAccess( this, from ) ) + return false; + + return base.IsSnoop( from ); + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( CheckFeed( from, item ) ) + return true; + + if ( PackAnimal.CheckAccess( this, from ) ) + { + AddToBackpack( item ); + return true; + } + + return base.OnDragDrop( from, item ); + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override bool CheckNonlocalLift( Mobile from, Item item ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override void OnDoubleClick( Mobile from ) + { + PackAnimal.TryPackOpen( this, from ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + PackAnimal.GetContextMenuEntries( this, from, list ); + } + #endregion + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PackAnimalBackpackEntry : ContextMenuEntry + { + private BaseCreature m_Animal; + private Mobile m_From; + + public PackAnimalBackpackEntry( BaseCreature animal, Mobile from ) : base( 6145, 3 ) + { + m_Animal = animal; + m_From = from; + + if ( animal.IsDeadPet ) + Enabled = false; + } + + public override void OnClick() + { + PackAnimal.TryPackOpen( m_Animal, m_From ); + } + } + + public class PackAnimal + { + public static void GetContextMenuEntries( BaseCreature animal, Mobile from, List list ) + { + if ( CheckAccess( animal, from ) ) + list.Add( new PackAnimalBackpackEntry( animal, from ) ); + } + + public static bool CheckAccess( BaseCreature animal, Mobile from ) + { + if ( from == animal || from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if (from.Alive && animal.Controlled && !animal.IsDeadPet && (from == animal.ControlMaster || from == animal.SummonMaster || animal.IsPetFriend(from))) + return true; + + return false; + } + + public static void CombineBackpacks( BaseCreature animal ) + { + if ( Core.AOS ) + return; + + if ( animal.IsBonded || animal.IsDeadPet ) + return; + + Container pack = animal.Backpack; + + if ( pack != null ) + { + Container newPack = new Backpack(); + + for ( int i = pack.Items.Count - 1; i >= 0; --i ) + { + if ( i >= pack.Items.Count ) + continue; + + newPack.DropItem( pack.Items[i] ); + } + + pack.DropItem( newPack ); + } + } + + public static void TryPackOpen( BaseCreature animal, Mobile from ) + { + if ( animal.IsDeadPet ) + return; + + Container item = animal.Backpack; + + if ( item != null ) + from.Use( item ); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/PackLlama.cs b/Scripts/Mobiles/Animals/Misc/PackLlama.cs new file mode 100644 index 0000000..69610d4 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/PackLlama.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Items; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de lama")] + public class PackLlama : BaseCreature + { + [Constructable] + public PackLlama() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un lama de trait"; + Body = 292; + BaseSoundID = 0x3F3; + + SetStr( 52, 80 ); + SetDex( 36, 55 ); + SetInt( 16, 30 ); + + SetHits( 50 ); + SetStam( 86, 105 ); + SetMana( 0 ); + + SetDamage( 2, 6 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.2, 29.0 ); + SetSkill( SkillName.Wrestling, 19.2, 29.0 ); + + Fame = 0; + Karma = 200; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + + Container pack = Backpack; + + if ( pack != null ) + pack.Delete(); + + pack = new StrongBackpack(); + pack.Movable = false; + + AddItem( pack ); + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public PackLlama( Serial serial ) : base( serial ) + { + } + + #region Pack Animal Methods + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + PackAnimal.CombineBackpacks( this ); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor( Item item ) + { + return DeathMoveResult.MoveToCorpse; + } + + public override bool IsSnoop( Mobile from ) + { + if ( PackAnimal.CheckAccess( this, from ) ) + return false; + + return base.IsSnoop( from ); + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( CheckFeed( from, item ) ) + return true; + + if ( PackAnimal.CheckAccess( this, from ) ) + { + AddToBackpack( item ); + return true; + } + + return base.OnDragDrop( from, item ); + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override bool CheckNonlocalLift( Mobile from, Item item ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override void OnDoubleClick( Mobile from ) + { + PackAnimal.TryPackOpen( this, from ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + PackAnimal.GetContextMenuEntries( this, from, list ); + } + #endregion + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Pig.cs b/Scripts/Mobiles/Animals/Misc/Pig.cs new file mode 100644 index 0000000..89ab781 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Pig.cs @@ -0,0 +1,66 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cochon" )] + public class Pig : BaseCreature + { + [Constructable] + public Pig() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un cochon"; + Body = 0xCB; + BaseSoundID = 0xC4; + + SetStr( 20 ); + SetDex( 20 ); + SetInt( 5 ); + + SetHits( 12 ); + SetMana( 0 ); + + SetDamage( 2, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 12; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Pig(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Sheep.cs b/Scripts/Mobiles/Animals/Misc/Sheep.cs new file mode 100644 index 0000000..efe0798 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Sheep.cs @@ -0,0 +1,112 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de mouton" )] + public class Sheep : BaseCreature, ICarvable + { + private DateTime m_NextWoolTime; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextWoolTime + { + get{ return m_NextWoolTime; } + set{ m_NextWoolTime = value; Body = ( DateTime.Now >= m_NextWoolTime ) ? 0xCF : 0xDF; } + } + + public void Carve( Mobile from, Item item ) + { + if ( DateTime.Now < m_NextWoolTime ) + { + // This sheep is not yet ready to be shorn. + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Ce mouton n'est pas pr�t pour la tonte", from.NetState ); + return; + } + + from.SendMessage( "Vous placez la laine tondue dans votre sac" ); // You place the gathered wool into your backpack. + from.AddToBackpack( new Wool( Map == Map.Felucca ? 2 : 1 ) ); + + NextWoolTime = DateTime.Now + TimeSpan.FromHours( 3.0 ); // TODO: Proper time delay + } + public override bool NoHouseRestrictions { get { return true; } } + + public override void OnThink() + { + base.OnThink(); + Body = ( DateTime.Now >= m_NextWoolTime ) ? 0xCF : 0xDF; + } + + [Constructable] + public Sheep() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un mouton"; + Body = 0xCF; + BaseSoundID = 0xD6; + + SetStr( 19 ); + SetDex( 25 ); + SetInt( 5 ); + + SetHits( 12 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 6.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public override int Meat{ get{ return 3; } } + public override MeatType MeatType{ get{ return MeatType.LambLeg; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override int Wool{ get{ return (Body == 0xCF ? 3 : 0); } } + + public Sheep( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.WriteDeltaTime( m_NextWoolTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + NextWoolTime = reader.ReadDeltaTime(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Misc/Walrus.cs b/Scripts/Mobiles/Animals/Misc/Walrus.cs new file mode 100644 index 0000000..8a84262 --- /dev/null +++ b/Scripts/Mobiles/Animals/Misc/Walrus.cs @@ -0,0 +1,69 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de morse" )] + public class Walrus : BaseCreature + { + [Constructable] + public Walrus() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un morse"; + Body = 0xDD; + BaseSoundID = 0xE0; + + SetStr( 21, 29 ); + SetDex( 46, 55 ); + SetInt( 16, 20 ); + + SetHits( 14, 17 ); + SetMana( 0 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.2, 29.0 ); + SetSkill( SkillName.Wrestling, 19.2, 29.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 18; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 35.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + public Walrus(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/BaseMount.cs b/Scripts/Mobiles/Animals/Mounts/BaseMount.cs new file mode 100644 index 0000000..289e436 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/BaseMount.cs @@ -0,0 +1,391 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + public abstract class BaseMount : BaseCreature, IMount + { + private Mobile m_Rider; + private Item m_InternalItem; + private DateTime m_NextMountAbility; + + public virtual TimeSpan MountAbilityDelay { get { return TimeSpan.Zero; } } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextMountAbility + { + get { return m_NextMountAbility; } + set { m_NextMountAbility = value; } + } + + protected Item InternalItem { get { return m_InternalItem; } } + + public virtual bool AllowMaleRider { get { return true; } } + public virtual bool AllowFemaleRider { get { return true; } } + + public BaseMount(string name, int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, int rangeFight, double activeSpeed, double passiveSpeed) + : base(aiType, fightMode, rangePerception, rangeFight, activeSpeed, passiveSpeed) + { + Name = name; + Body = bodyID; + + m_InternalItem = new MountItem(this, itemID); + } + + [Hue, CommandProperty(AccessLevel.GameMaster)] + public override int Hue + { + get + { + return base.Hue; + } + set + { + base.Hue = value; + + if (m_InternalItem != null) + m_InternalItem.Hue = value; + } + } + + public override bool OnBeforeDeath() + { + Rider = null; + + return base.OnBeforeDeath(); + } + + public override void OnAfterDelete() + { + if (m_InternalItem != null) + m_InternalItem.Delete(); + + m_InternalItem = null; + + base.OnAfterDelete(); + } + + public override void OnDelete() + { + Rider = null; + + base.OnDelete(); + } + + public BaseMount(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + writer.Write(m_NextMountAbility); + + writer.Write(m_Rider); + writer.Write(m_InternalItem); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + { + m_NextMountAbility = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_Rider = reader.ReadMobile(); + m_InternalItem = reader.ReadItem(); + + if (m_InternalItem == null) + Delete(); + + break; + } + } + } + + public virtual void OnDisallowedRider(Mobile m) + { + m.SendMessage("Cette monture refuse que vous la montiez"); + } + + public override void OnDoubleClick(Mobile from) + { + if (IsDeadPet) + return; + + if (from.IsBodyMod && !from.Body.IsHuman) + { + if (Core.AOS) // You cannot ride a mount in your current form. + PrivateOverheadMessage(Network.MessageType.Regular, 0x3B2, false, "Vous ne pouvez chevaucher sous cette forme", from.NetState); + else + from.SendMessage("Vous ne pouvez chevaucher sous une autre forme"); // You can't do that while polymorphed. + + return; + } + + if (!CheckMountAllowed(from)) + return; + + if (from.Mounted) + { + from.SendMessage("Descendez d'abord de votre monture"); // Please dismount first. + return; + } + + if (from.Female ? !AllowFemaleRider : !AllowMaleRider) + { + OnDisallowedRider(from); + return; + } + + if (!Multis.DesignContext.Check(from)) + return; + + if (from.HasTrade) + { + from.SendMessage("Vous ne pouvez chevaucher en ce moment", "", 0x41); // You may not ride at this time + return; + } + + if (from.InRange(this, 1)) + { + bool canAccess = (from.AccessLevel >= AccessLevel.GameMaster) + || (Controlled && ControlMaster == from) + || (Summoned && SummonMaster == from); + + if (canAccess) + { + if (this.Poisoned) + PrivateOverheadMessage(Network.MessageType.Regular, 0x3B2, false, "Cette monture est trop malade pour se laisser monter", from.NetState); // This mount is too ill to ride. + else + Rider = from; + } + else if (!Controlled && !Summoned) + { + // That mount does not look broken! You would have to tame it to ride it. + PrivateOverheadMessage(Network.MessageType.Regular, 0x3B2, false, "Cette monture est farouche! Il vous faudra d'abord l'apprivoiser", from.NetState); + } + else + { + // This isn't your mount; it refuses to let you ride. + PrivateOverheadMessage(Network.MessageType.Regular, 0x3B2, false, "Cette monture n'est pas la votre, elle refuse que vous la montiez", from.NetState); + } + } + else + { + from.SendMessage("Vous �tes trop loin pour chevaucher"); // That is too far away to ride. + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ItemID + { + get + { + if (m_InternalItem != null) + return m_InternalItem.ItemID; + else + return 0; + } + set + { + if (m_InternalItem != null) + m_InternalItem.ItemID = value; + } + } + + public static void Dismount(Mobile m) + { + IMount mount = m.Mount; + + if (mount != null) + mount.Rider = null; + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Rider + { + get + { + return m_Rider; + } + set + { + if (m_Rider != value) + { + if (value == null) + { + Point3D loc = m_Rider.Location; + Map map = m_Rider.Map; + + if (map == null || map == Map.Internal) + { + loc = m_Rider.LogoutLocation; + map = m_Rider.LogoutMap; + } + + Direction = m_Rider.Direction; + Location = loc; + Map = map; + + if (m_InternalItem != null) + m_InternalItem.Internalize(); + } + else + { + if (m_Rider != null) + Dismount(m_Rider); + + Dismount(value); + + if (m_InternalItem != null) + value.AddItem(m_InternalItem); + + value.Direction = this.Direction; + + Internalize(); + + if (value.Target is Bola.BolaTarget) + { + Target.Cancel(value); + } + } + + m_Rider = value; + } + } + } + + // 1040024 You are still too dazed from being knocked off your mount to ride! + // 1062910 You cannot mount while recovering from a bola throw. + // 1070859 You cannot mount while recovering from a dismount special maneuver. + + public static bool CheckMountAllowed(Mobile mob) + { + bool result = true; + + if ((mob is PlayerMobile) && (mob as PlayerMobile).MountBlockReason != BlockMountType.None) + { + mob.SendLocalizedMessage((int)(mob as PlayerMobile).MountBlockReason); + + result = false; + } + + return result; + } + + + public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill) + { + if (m_Rider == null) + return; + + Mobile attacker = from; + if (attacker == null) + attacker = m_Rider.FindMostRecentDamager(true); + + if (!(attacker == this || attacker == m_Rider || willKill || DateTime.Now < m_NextMountAbility)) + { + if (DoMountAbility(amount, from)) + m_NextMountAbility = DateTime.Now + MountAbilityDelay; + + } + } + + public virtual bool DoMountAbility(int damage, Mobile attacker) + { + return false; + } + } + + public class MountItem : Item, IMountItem + { + private BaseMount m_Mount; + + public override double DefaultWeight { get { return 0; } } + + public MountItem(BaseMount mount, int itemID) + : base(itemID) + { + Layer = Layer.Mount; + Movable = false; + + m_Mount = mount; + } + + public MountItem(Serial serial) + : base(serial) + { + } + + public override void OnAfterDelete() + { + if (m_Mount != null) + m_Mount.Delete(); + + m_Mount = null; + + base.OnAfterDelete(); + } + + public override DeathMoveResult OnParentDeath(Mobile parent) + { + if (m_Mount != null) + m_Mount.Rider = null; + + return DeathMoveResult.RemainEquiped; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Mount); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Mount = reader.ReadMobile() as BaseMount; + + if (m_Mount == null) + Delete(); + + break; + } + } + } + + public IMount Mount + { + get + { + return m_Mount; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/Beetle.cs b/Scripts/Mobiles/Animals/Mounts/Beetle.cs new file mode 100644 index 0000000..c534e4a --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Beetle.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de cafard g�ant")] + public class Beetle : BaseMount + { + public virtual double BoostedSpeed{ get{ return 0.1; } } + + [Constructable] + public Beetle() : this( "Un cafard g�ant" ) + { + } + + public override bool SubdueBeforeTame{ get{ return true; } } // Must be beaten into submission + public override bool ReduceSpeedWithDamage{ get{ return false; } } + + [Constructable] + public Beetle( string name ) : base( name, 0x317, 0x3EBC, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.25, 0.5 ) + { + SetStr( 300 ); + SetDex( 100 ); + SetInt( 500 ); + + SetHits( 200 ); + + SetDamage( 7, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 80.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 4000; + Karma = -4000; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 29.1; + + Container pack = Backpack; + + if ( pack != null ) + pack.Delete(); + + pack = new StrongBackpack(); + pack.Movable = false; + + AddItem( pack ); + } + + public override int GetAngerSound() + { + return 0x21D; + } + + public override int GetIdleSound() + { + return 0x21D; + } + + public override int GetAttackSound() + { + return 0x162; + } + + public override int GetHurtSound() + { + return 0x163; + } + + public override int GetDeathSound() + { + return 0x21D; + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + + + public Beetle( Serial serial ) : base( serial ) + { + } + + public override void OnHarmfulSpell( Mobile from ) + { + if ( !Controlled && ControlMaster == null ) + CurrentSpeed = BoostedSpeed; + } + + public override void OnCombatantChange() + { + if ( Combatant == null && !Controlled && ControlMaster == null ) + CurrentSpeed = PassiveSpeed; + } + + #region Pack Animal Methods + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + PackAnimal.CombineBackpacks( this ); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor( Item item ) + { + return DeathMoveResult.MoveToCorpse; + } + + public override bool IsSnoop( Mobile from ) + { + if ( PackAnimal.CheckAccess( this, from ) ) + return false; + + return base.IsSnoop( from ); + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( CheckFeed( from, item ) ) + return true; + + if ( PackAnimal.CheckAccess( this, from ) ) + { + AddToBackpack( item ); + return true; + } + + return base.OnDragDrop( from, item ); + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override bool CheckNonlocalLift( Mobile from, Item item ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + PackAnimal.GetContextMenuEntries( this, from, list ); + } + #endregion + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/DesertOstard.cs b/Scripts/Mobiles/Animals/Mounts/DesertOstard.cs new file mode 100644 index 0000000..f41715d --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/DesertOstard.cs @@ -0,0 +1,67 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'ostard" )] + public class DesertOstard : BaseMount + { + [Constructable] + public DesertOstard() : this( "Un ostard du d�sert" ) + { + } + + [Constructable] + public DesertOstard( string name ) : base( name, 0xD2, 0x3EA3, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x270; + + SetStr( 94, 170 ); + SetDex( 56, 75 ); + SetInt( 6, 10 ); + + SetHits( 71, 88 ); + SetMana( 0 ); + + SetDamage( 5, 11 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 15 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 25.3, 40.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 450; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override int Meat{ get{ return 3; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Ostard; } } + + public DesertOstard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/Ethereals.cs b/Scripts/Mobiles/Animals/Mounts/Ethereals.cs new file mode 100644 index 0000000..7b8c2bc --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Ethereals.cs @@ -0,0 +1,874 @@ +using System; +using Server.Mobiles; +using Server.Items; +using Server.Spells; +using Server.Engines.VeteranRewards; + +namespace Server.Mobiles +{ + public class EtherealMount : Item, IMount, IMountItem, Engines.VeteranRewards.IRewardItem + { + private int m_MountedID; + private int m_RegularID; + private Mobile m_Rider; + private bool m_IsRewardItem; + private bool m_IsDonationItem; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsRewardItem + { + get { return m_IsRewardItem; } + set { m_IsRewardItem = value; } + } + + public override double DefaultWeight + { + get { return 1.0; } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public bool IsDonationItem + { + get { return m_IsDonationItem; } + set { m_IsDonationItem = value; InvalidateProperties(); } + } + + [Constructable] + public EtherealMount(int itemID, int mountID) + : base(itemID) + { + m_MountedID = mountID; + m_RegularID = itemID; + m_Rider = null; + + Layer = Layer.Invalid; + + LootType = LootType.Blessed; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (m_IsDonationItem) + { + list.Add("Donation Ethereal"); + list.Add("7.5 sec slower cast time if not a 9mo. Veteran"); + } + if (Core.ML && m_IsRewardItem) + list.Add(RewardSystem.GetRewardYearLabel(this, new object[] { })); // X Year Veteran Reward + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MountedID + { + get + { + return m_MountedID; + } + set + { + if (m_MountedID != value) + { + m_MountedID = value; + + if (m_Rider != null) + ItemID = value; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RegularID + { + get + { + return m_RegularID; + } + set + { + if (m_RegularID != value) + { + m_RegularID = value; + + if (m_Rider == null) + ItemID = value; + } + } + } + + public EtherealMount(Serial serial) + : base(serial) + { + } + + public override bool DisplayLootType { get { return false; } } + + public virtual int FollowerSlots { get { return 1; } } + + public void RemoveFollowers() + { + if (m_Rider != null) + m_Rider.Followers -= FollowerSlots; + + if (m_Rider != null && m_Rider.Followers < 0) + m_Rider.Followers = 0; + } + + public void AddFollowers() + { + if (m_Rider != null) + m_Rider.Followers += FollowerSlots; + } + + public virtual bool Validate(Mobile from) + { + if (Parent == null) + { + from.SayTo(from, 1010095); // This must be on your person to use. + return false; + } + else if (m_IsRewardItem && !RewardSystem.CheckIsUsableBy(from, this, null)) + { + // CheckIsUsableBy sends the message + return false; + } + else if (!BaseMount.CheckMountAllowed(from)) + { + // CheckMountAllowed sends the message + return false; + } + else if (from.Mounted) + { + from.SendLocalizedMessage(1005583); // Please dismount first. + return false; + } + else if (from.IsBodyMod && !from.Body.IsHuman) + { + from.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + return false; + } + else if (from.HasTrade) + { + from.SendLocalizedMessage(1042317, "", 0x41); // You may not ride at this time + return false; + } + else if ((from.Followers + FollowerSlots) > from.FollowersMax) + { + from.SendLocalizedMessage(1049679); // You have too many followers to summon your mount. + return false; + } + else if (!Multis.DesignContext.Check(from)) + { + // Check sends the message + return false; + } + + return true; + } + + public override void OnDoubleClick(Mobile from) + { + if (Validate(from)) + new EtherealSpell(this, from).Cast(); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (m_IsDonationItem) + LabelTo(from, "Donation Ethereal"); + else + LabelTo(from, "Veteran Reward"); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)3); // version + + writer.Write(m_IsDonationItem); + writer.Write(m_IsRewardItem); + + writer.Write((int)m_MountedID); + writer.Write((int)m_RegularID); + writer.Write(m_Rider); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + LootType = LootType.Blessed; + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + { + m_IsDonationItem = reader.ReadBool(); + goto case 2; + } + case 2: + { + m_IsRewardItem = reader.ReadBool(); + goto case 0; + } + case 1: reader.ReadInt(); goto case 0; + case 0: + { + m_MountedID = reader.ReadInt(); + m_RegularID = reader.ReadInt(); + m_Rider = reader.ReadMobile(); + + if (m_MountedID == 0x3EA2) + m_MountedID = 0x3EAA; + + break; + } + } + + AddFollowers(); + + if (version < 3 && Weight == 0) + Weight = -1; + } + + public override DeathMoveResult OnParentDeath(Mobile parent) + { + Rider = null;//get off, move to pack + + return DeathMoveResult.RemainEquiped; + } + + public static void Dismount(Mobile m) + { + IMount mount = m.Mount; + + if (mount != null) + mount.Rider = null; + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Rider + { + get + { + return m_Rider; + } + set + { + if (value != m_Rider) + { + if (value == null) + { + Internalize(); + UnmountMe(); + + RemoveFollowers(); + m_Rider = value; + } + else + { + if (m_Rider != null) + Dismount(m_Rider); + + Dismount(value); + + RemoveFollowers(); + m_Rider = value; + AddFollowers(); + + MountMe(); + } + } + } + } + + public virtual int EtherealHue { get { return 0x4001; } } + + public void UnmountMe() + { + Container bp = m_Rider.Backpack; + + ItemID = m_RegularID; + Layer = Layer.Invalid; + Movable = true; + + if (Hue == EtherealHue) + Hue = 0; + + if (bp != null) + { + bp.DropItem(this); + } + else + { + Point3D loc = m_Rider.Location; + Map map = m_Rider.Map; + + if (map == null || map == Map.Internal) + { + loc = m_Rider.LogoutLocation; + map = m_Rider.LogoutMap; + } + + MoveToWorld(loc, map); + } + } + + public void MountMe() + { + ItemID = m_MountedID; + Layer = Layer.Mount; + Movable = false; + + if (Hue == 0) + Hue = EtherealHue; + + ProcessDelta(); + m_Rider.ProcessDelta(); + m_Rider.EquipItem(this); + m_Rider.ProcessDelta(); + ProcessDelta(); + } + + public IMount Mount + { + get + { + return this; + } + } + + public static void StopMounting(Mobile mob) + { + if (mob.Spell is EtherealSpell) + ((EtherealSpell)mob.Spell).Stop(); + } + + public void OnRiderDamaged(int amount, Mobile from, bool willKill) + { + } + + private class EtherealSpell : Spell + { + private static SpellInfo m_Info = new SpellInfo("Ethereal Mount", "", 230); + + private EtherealMount m_Mount; + private Mobile m_Rider; + + public EtherealSpell(EtherealMount mount, Mobile rider) + : base(rider, null, m_Info) + { + m_Rider = rider; + m_Mount = mount; + } + + public override bool ClearHandsOnCast { get { return false; } } + public override bool RevealOnCast { get { return false; } } + + public override TimeSpan GetCastRecovery() + { + return TimeSpan.Zero; + } + + public override double CastDelayFastScalar { get { return 0; } } + + public override TimeSpan CastDelayBase + { + get + { + return TimeSpan.FromSeconds(((m_Mount.IsDonationItem && RewardSystem.GetRewardLevel(m_Rider) < 3) ? (7.5 + (Core.AOS ? 3.0 : 2.0)) : (Core.AOS ? 3.0 : 2.0))); + } + } + + public override int GetMana() + { + return 0; + } + + public override bool ConsumeReagents() + { + return true; + } + + public override bool CheckFizzle() + { + return true; + } + + private bool m_Stop; + + public void Stop() + { + m_Stop = true; + Disturb(DisturbType.Hurt, false, false); + } + + public override bool CheckDisturb(DisturbType type, bool checkFirst, bool resistable) + { + if (type == DisturbType.EquipRequest || type == DisturbType.UseRequest/* || type == DisturbType.Hurt*/ ) + return false; + + return true; + } + + public override void DoHurtFizzle() + { + if (!m_Stop) + base.DoHurtFizzle(); + } + + public override void DoFizzle() + { + if (!m_Stop) + base.DoFizzle(); + } + + public override void OnDisturb(DisturbType type, bool message) + { + if (message && !m_Stop) + Caster.SendLocalizedMessage(1049455); // You have been disrupted while attempting to summon your ethereal mount! + + //m_Mount.UnmountMe(); + } + + public override void OnCast() + { + if (!m_Mount.Deleted && m_Mount.Rider == null && m_Mount.Validate(m_Rider)) + m_Mount.Rider = m_Rider; + + FinishSequence(); + } + } + } + + public class EtherealHorse : EtherealMount + { + public override int LabelNumber { get { return 1041298; } } // Ethereal Horse Statuette + + [Constructable] + public EtherealHorse() + : base(0x20DD, 0x3EAA) + { + } + + public EtherealHorse(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal horse") + Name = null; + + if (ItemID == 0x2124) + ItemID = 0x20DD; + } + } + + public class EtherealLlama : EtherealMount + { + public override int LabelNumber { get { return 1041300; } } // Ethereal Llama Statuette + + [Constructable] + public EtherealLlama() + : base(0x20F6, 0x3EAB) + { + } + + public EtherealLlama(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal llama") + Name = null; + } + } + + public class EtherealOstard : EtherealMount + { + public override int LabelNumber { get { return 1041299; } } // Ethereal Ostard Statuette + + [Constructable] + public EtherealOstard() + : base(0x2135, 0x3EAC) + { + } + + public EtherealOstard(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal ostard") + Name = null; + } + } + + public class EtherealRidgeback : EtherealMount + { + public override int LabelNumber { get { return 1049747; } } // Ethereal Ridgeback Statuette + + [Constructable] + public EtherealRidgeback() + : base(0x2615, 0x3E9A) + { + } + + public EtherealRidgeback(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal ridgeback") + Name = null; + } + } + + public class EtherealUnicorn : EtherealMount + { + public override int LabelNumber { get { return 1049745; } } // Ethereal Unicorn Statuette + + [Constructable] + public EtherealUnicorn() + : base(0x25CE, 0x3E9B) + { + } + + public EtherealUnicorn(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal unicorn") + Name = null; + } + } + + public class EtherealBeetle : EtherealMount + { + public override int LabelNumber { get { return 1049748; } } // Ethereal Beetle Statuette + + [Constructable] + public EtherealBeetle() + : base(0x260F, 0x3E97) + { + } + + public EtherealBeetle(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal beetle") + Name = null; + } + } + + public class EtherealKirin : EtherealMount + { + public override int LabelNumber { get { return 1049746; } } // Ethereal Ki-Rin Statuette + + [Constructable] + public EtherealKirin() + : base(0x25A0, 0x3E9C) + { + } + + public EtherealKirin(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal kirin") + Name = null; + } + } + + public class EtherealSwampDragon : EtherealMount + { + public override int LabelNumber { get { return 1049749; } } // Ethereal Swamp Dragon Statuette + + [Constructable] + public EtherealSwampDragon() + : base(0x2619, 0x3E98) + { + } + + public EtherealSwampDragon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == "an ethereal swamp dragon") + Name = null; + } + } + + public class RideablePolarBear : EtherealMount + { + public override int LabelNumber { get { return 1076159; } } // Rideable Polar Bear + public override int EtherealHue { get { return 0; } } + + [Constructable] + public RideablePolarBear() + : base(0x20E1, 0x3EC5) + { + } + + public RideablePolarBear(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class EtherealCuSidhe : EtherealMount + { + public override int LabelNumber { get { return 1080386; } } // Ethereal Cu Sidhe Statuette + + [Constructable] + public EtherealCuSidhe() + : base(0x2D96, 0x3E91) + { + } + + public EtherealCuSidhe(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class EtherealHiryu : EtherealMount + { + public override int LabelNumber { get { return 1113813; } } // Ethereal Hiryu Statuette + + + [Constructable] + public EtherealHiryu() + : base(0x276A, 0x3E94) + { + } + + public EtherealHiryu(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class EtherealReptalon : EtherealMount + { + public override int LabelNumber { get { return 1113813; } } // reptalon statuette + + [Constructable] + public EtherealReptalon() + : base(0x2d95, 0x3e90) + { + } + + public EtherealReptalon(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } + + public class ChargerOfTheFallen : EtherealMount + { + public override int LabelNumber { get { return 1074816; } } // Charger of the Fallen Statuette + + [Constructable] + public ChargerOfTheFallen() + : base(0x2D9C, 0x3E92) + { + } + + public override int EtherealHue { get { return 0; } } + + public ChargerOfTheFallen(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version <= 1 && Hue != 0) + { + Hue = 0; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/FireSteed.cs b/Scripts/Mobiles/Animals/Mounts/FireSteed.cs new file mode 100644 index 0000000..15c795d --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/FireSteed.cs @@ -0,0 +1,93 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'�talon de feu" )] + public class FireSteed : BaseMount + { + [Constructable] + public FireSteed() : this( "Un �talon de feu" ) + { + } + + [Constructable] + public FireSteed( string name ) : base( name, 0xBE, 0x3E9E, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0xA8; + + SetStr( 376, 400 ); + SetDex( 91, 120 ); + SetInt( 291, 300 ); + + SetHits( 226, 240 ); + + SetDamage( 11, 30 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 80 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 100.0, 120.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 20000; + Karma = -20000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 106.0; + } + + public override void GenerateLoot() + { + PackItem( new SulfurousAsh( Utility.RandomMinMax( 151, 300 ) ) ); + PackItem( new Ruby( Utility.RandomMinMax( 16, 30 ) ) ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Daemon | PackInstinct.Equine; } } + + public FireSteed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( BaseSoundID <= 0 ) + BaseSoundID = 0xA8; + + if( version < 1 ) + { + for ( int i = 0; i < Skills.Length; ++i ) + { + Skills[i].Cap = Math.Max( 100.0, Skills[i].Cap * 0.9 ); + + if ( Skills[i].Base > Skills[i].Cap ) + { + Skills[i].Base = Skills[i].Cap; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/ForestOstard.cs b/Scripts/Mobiles/Animals/Mounts/ForestOstard.cs new file mode 100644 index 0000000..e514734 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/ForestOstard.cs @@ -0,0 +1,68 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'ostard" )] + public class ForestOstard : BaseMount + { + [Constructable] + public ForestOstard() : this( "Un ostard des for�ts" ) + { + } + + [Constructable] + public ForestOstard( string name ) : base( name, 0xDB, 0x3EA5, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Hue = Utility.RandomSlimeHue() | 0x8000; + + BaseSoundID = 0x270; + + SetStr( 94, 170 ); + SetDex( 56, 75 ); + SetInt( 6, 10 ); + + SetHits( 71, 88 ); + SetMana( 0 ); + + SetDamage( 8, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + + SetSkill( SkillName.MagicResist, 27.1, 32.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 450; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override int Meat{ get{ return 3; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Ostard; } } + + public ForestOstard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/FrenziedOstard.cs b/Scripts/Mobiles/Animals/Mounts/FrenziedOstard.cs new file mode 100644 index 0000000..bf90c40 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/FrenziedOstard.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'ostard" )] + public class FrenziedOstard : BaseMount + { + [Constructable] + public FrenziedOstard() : this( "Un ostard fr�n�tique" ) + { + } + + [Constructable] + public FrenziedOstard( string name ) : base( name, 0xDA, 0x3EA4, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Hue = Utility.RandomHairHue() | 0x8000; + + BaseSoundID = 0x275; + + SetStr( 94, 170 ); + SetDex( 96, 115 ); + SetInt( 6, 10 ); + + SetHits( 71, 110 ); + SetMana( 0 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Poison, 20, 25 ); + SetResistance( ResistanceType.Energy, 20, 25 ); + + SetSkill( SkillName.MagicResist, 75.1, 80.0 ); + SetSkill( SkillName.Tactics, 79.3, 94.0 ); + SetSkill( SkillName.Wrestling, 79.3, 94.0 ); + + Fame = 1500; + Karma = -1500; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 77.1; + } + + public override int Meat{ get{ return 3; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.FruitsAndVegies; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Ostard; } } + + public FrenziedOstard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/HellSteed.cs b/Scripts/Mobiles/Animals/Mounts/HellSteed.cs new file mode 100644 index 0000000..8aef885 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/HellSteed.cs @@ -0,0 +1,70 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("a hellsteed corpse")] + public class HellSteed : BaseMount + { + public override bool HasBreath { get { return true; } } + public override int BreathChaosDamage { get { return 100; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + [Constructable] + public HellSteed() + : this("a hellsteed") + { + } + + [Constructable] + public HellSteed(string name) + : base(name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + SetStats(this); + } + + public static void SetStats(BaseCreature steed) + { + steed.SetStr(201, 210); + steed.SetDex(101, 110); + steed.SetInt(101, 115); + + steed.SetHits(201, 220); + + steed.SetDamage(20, 24); + + steed.SetDamageType(ResistanceType.Physical, 25); + steed.SetDamageType(ResistanceType.Fire, 75); + + steed.SetResistance(ResistanceType.Physical, 60, 70); + steed.SetResistance(ResistanceType.Fire, 90); + steed.SetResistance(ResistanceType.Poison, 100); + + steed.SetSkill(SkillName.MagicResist, 90.1, 110.0); + steed.SetSkill(SkillName.Tactics, 50.0); + steed.SetSkill(SkillName.Wrestling, 90.1, 110.0); + + steed.Fame = 0; + steed.Karma = 0; + } + + public HellSteed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/Hiryu.cs b/Scripts/Mobiles/Animals/Mounts/Hiryu.cs new file mode 100644 index 0000000..8fca382 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Hiryu.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'hiryu" )] + public class Hiryu : BaseMount + { + public override double WeaponAbilityChance { get { return 0.07; } } /* 1 in 15 chance of using per landed hit */ + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + public override bool StatLossAfterTame { get { return true; } } + + private static int GetHue() + { + int rand = Utility.Random( 1075 ); + + /* + 1000 1075 No Hue Color 93.02% 0x0 + * + 10 1075 Ice Green 0.93% 0x847F + 10 1075 Light Blue 0.93% 0x848D + 10 1075 Strong Cyan 0.93% 0x8495 + 10 1075 Agapite 0.93% 0x8899 + 10 1075 Gold 0.93% 0x8032 + * + 8 1075 Blue and Yellow 0.74% 0x8487 + * + 5 1075 Ice Blue 0.47% 0x8482 + * + 3 1075 Cyan 0.28% 0x8123 + 3 1075 Light Green 0.28% 0x8295 + * + 2 1075 Strong Yellow 0.19% 0x8037 + 2 1075 Green 0.19% 0x8030 //this one is an approximation + * + 1 1075 Strong Purple 0.09% 0x8490 + 1 1075 Strong Green 0.09% 0x855C + * */ + + if( rand <= 0 ) + return 0x855C; + else if( rand <= 1 ) + return 0x8490; + else if( rand <= 3 ) + return 0x8030; + else if( rand <= 5 ) + return 0x8037; + else if( rand <= 8 ) + return 0x8295; + else if( rand <= 11 ) + return 0x8123; + else if( rand <= 16 ) + return 0x8482; + else if( rand <= 24 ) + return 0x8487; + else if( rand <= 34 ) + return 0x8032; + else if( rand <= 44 ) + return 0x8899; + else if( rand <= 54 ) + return 0x8495; + else if( rand <= 64 ) + return 0x848D; + else if( rand <= 74 ) + return 0x847F; + + + return 0; + } + + [Constructable] + public Hiryu() + : base( "Un hiryu", 243, 0x3E94, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Hue = GetHue(); + + SetStr( 1201, 1410 ); + SetDex( 171, 270 ); + SetInt( 301, 325 ); + + SetHits( 901, 1100 ); + SetMana( 60 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 70 ); + SetResistance( ResistanceType.Fire, 70, 90 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 75.1, 80.0 ); + SetSkill( SkillName.MagicResist, 85.1, 100.0 ); + SetSkill( SkillName.Tactics, 100.1, 110.0 ); + SetSkill( SkillName.Wrestling, 100.1, 120.0 ); + + Fame = 18000; + Karma = -18000; + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 98.7; + + if( Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(3) ); + } + + + public override int GetAngerSound() + { + return 0x4FE; + } + + public override int GetIdleSound() + { + return 0x4FD; + } + + public override int GetAttackSound() + { + return 0x4FC; + } + + public override int GetHurtSound() + { + return 0x4FF; + } + + public override int GetDeathSound() + { + return 0x4FB; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + AddLoot( LootPack.Gems, 4 ); + } + + public override int TreasureMapLevel { get { return 5; } } + public override int Meat { get { return 16; } } + public override int Hides { get { return 60; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if( 0.1 > Utility.RandomDouble() ) + { + /* Grasping Claw + * Start cliloc: 1070836 + * Effect: Physical resistance -15% for 5 seconds + * End cliloc: 1070838 + * Effect: Type: "3" - From: "0x57D4F5B" (player) - To: "0x0" - ItemId: "0x37B9" - ItemIdName: "glow" - FromLocation: "(1149 808, 32)" - ToLocation: "(1149 808, 32)" - Speed: "10" - Duration: "5" - FixedDirection: "True" - Explode: "False" + */ + + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070837 ); // The creature lands another blow in your weakened state. + } + else + defender.SendLocalizedMessage( 1070836 ); // The blow from the creature's claws has made you more susceptible to physical attacks. + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Physical, effect ); + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.AddResistanceMod( mod ); + + timer = new ExpireTimer( defender, mod, TimeSpan.FromSeconds( 5.0 ) ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + + public ExpireTimer( Mobile m, ResistanceMod mod, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod( m_Mod ); + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1070838 ); // Your resistance to physical attacks has returned. + DoExpire(); + } + } + + public Hiryu( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if( version == 0 ) + Timer.DelayCall( TimeSpan.Zero, delegate { Hue = GetHue(); } ); + + if( version <= 1 ) + Timer.DelayCall( TimeSpan.Zero, delegate { if( InternalItem != null ) { InternalItem.Hue = this.Hue; } } ); + + if( version < 2 ) + { + for ( int i = 0; i < Skills.Length; ++i ) + { + Skills[i].Cap = Math.Max( 100.0, Skills[i].Cap * 0.9 ); + + if ( Skills[i].Base > Skills[i].Cap ) + { + Skills[i].Base = Skills[i].Cap; + } + } + } + } + } +} diff --git a/Scripts/Mobiles/Animals/Mounts/Horse.cs b/Scripts/Mobiles/Animals/Mounts/Horse.cs new file mode 100644 index 0000000..62bd19c --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Horse.cs @@ -0,0 +1,81 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cheval" )] + [TypeAlias( "Server.Mobiles.BrownHorse", "Server.Mobiles.DirtyHorse", "Server.Mobiles.GrayHorse", "Server.Mobiles.TanHorse" )] + public class Horse : BaseMount + { + private static int[] m_IDs = new int[] + { + 0xC8, 0x3E9F, + 0xE2, 0x3EA0, + 0xE4, 0x3EA1, + 0xCC, 0x3EA2 + }; + + [Constructable] + public Horse() : this( "Un cheval" ) + { + } + + [Constructable] + public Horse( string name ) : base( name, 0xE2, 0x3EA0, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + int random = Utility.Random( 4 ); + + Body = m_IDs[random * 2]; + ItemID = m_IDs[random * 2 + 1]; + BaseSoundID = 0xA8; + + SetStr( 22, 98 ); + SetDex( 56, 75 ); + SetInt( 6, 10 ); + + SetHits( 28, 45 ); + SetMana( 0 ); + + SetDamage( 3, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 300; + Karma = 300; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override int Meat{ get{ return 3; } } + public override int Hides{ get{ return 10; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Horse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/Kirin.cs b/Scripts/Mobiles/Animals/Mounts/Kirin.cs new file mode 100644 index 0000000..7ec3444 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Kirin.cs @@ -0,0 +1,133 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de ki-rin" )] + public class Kirin : BaseMount + { + public override bool AllowFemaleRider{ get{ return false; } } + public override bool AllowFemaleTamer{ get{ return false; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override TimeSpan MountAbilityDelay { get { return TimeSpan.FromHours( 1.0 ); } } + + public override void OnDisallowedRider( Mobile m ) + { + m.SendLocalizedMessage( 1042319 ); // The Ki-Rin refuses your attempts to mount it. + } + + public override bool DoMountAbility( int damage, Mobile attacker ) + { + if( Rider == null || attacker == null ) //sanity + return false; + + if( (Rider.Hits - damage) < 30 && Rider.Map == attacker.Map && Rider.InRange( attacker, 18 ) ) //Range and map checked here instead of other base fuction because of abiliites that don't need to check this + { + attacker.BoltEffect( 0 ); + // 35~100 damage, unresistable, by the Ki-rin. + attacker.Damage( Utility.RandomMinMax( 35, 100 ), this, false ); //Don't inform mount about this damage, Still unsure wether or not it's flagged as the mount doing damage or the player. If changed to player, without the extra bool it'd be an infinite loop + + Rider.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042534 ); // Your mount calls down the forces of nature on your opponent. + Rider.FixedParticles( 0, 0, 0, 0x13A7, EffectLayer.Waist ); + Rider.PlaySound( 0xA9 ); // Ki-rin's whinny. + return true; + } + + return false; + } + + [Constructable] + public Kirin() : this( "Un ki-rin" ) + { + } + + [Constructable] + public Kirin( string name ) : base( name, 132, 0x3EAD, AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x3C5; + + SetStr( 296, 325 ); + SetDex( 86, 105 ); + SetInt( 186, 225 ); + + SetHits( 191, 210 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Cold, 10 ); + SetDamageType( ResistanceType.Energy, 10 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.EvalInt, 80.1, 90.0 ); + SetSkill( SkillName.Magery, 60.4, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 85.3, 100.0 ); + SetSkill( SkillName.Tactics, 20.1, 22.5 ); + SetSkill( SkillName.Wrestling, 80.5, 92.5 ); + + Fame = 9000; + Karma = 9000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 95.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Potions ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.35) + c.DropItem(new KirinBrains()); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override int Meat{ get{ return 3; } } + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Kirin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) + AI = AIType.AI_Mage; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs b/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs new file mode 100644 index 0000000..5944537 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/LesserHiryu.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'hiryu" )] + public class LesserHiryu : BaseMount + { + public override double WeaponAbilityChance { get { return 0.07; } } /* 1 in 15 chance of using; 1 in 5 chance of success */ + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + public override bool StatLossAfterTame { get { return true; } } + + private static int GetHue() + { + int rand = Utility.Random( 527 ); + + /* + + 500 527 No Hue Color 94.88% 0 + 10 527 Green 1.90% 0x8295 + 10 527 Green 1.90% 0x8163 (Very Close to Above Green) //this one is an approximation + 5 527 Dark Green 0.95% 0x87D4 + 1 527 Valorite 0.19% 0x88AB + 1 527 Midnight Blue 0.19% 0x8258 + + * */ + + if( rand <= 0 ) + return 0x8258; + else if( rand <= 1 ) + return 0x88AB; + else if( rand <= 6 ) + return 0x87D4; + else if( rand <= 16 ) + return 0x8163; + else if( rand <= 26 ) + return 0x8295; + + + return 0; + } + + [Constructable] + public LesserHiryu() + : base( "Un jeune hyriu", 243, 0x3E94, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Hue = GetHue(); + + SetStr( 301, 410 ); + SetDex( 171, 270 ); + SetInt( 301, 325 ); + + SetHits( 401, 600 ); + SetMana( 60 ); + + SetDamage( 18, 23 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 70 ); + SetResistance( ResistanceType.Fire, 60, 80 ); + SetResistance( ResistanceType.Cold, 5, 15 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 75.1, 80.0 ); + SetSkill( SkillName.MagicResist, 85.1, 100.0 ); + SetSkill( SkillName.Tactics, 100.1, 110.0 ); + SetSkill( SkillName.Wrestling, 100.1, 120.0 ); + + Fame = 10000; + Karma = -10000; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 98.7; + + if( Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + } + + + public override bool OverrideBondingReqs() + { + if ( ControlMaster.Skills[SkillName.Bushido].Base >= 90.0 ) + return true; + return false; + } + + public override int GetAngerSound() + { + return 0x4FE; + } + + public override int GetIdleSound() + { + return 0x4FD; + } + + public override int GetAttackSound() + { + return 0x4FC; + } + + public override int GetHurtSound() + { + return 0x4FF; + } + + public override int GetDeathSound() + { + return 0x4FB; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Gems, 4 ); + } + + public override double GetControlChance( Mobile m, bool useBaseSkill ) + { + double tamingChance = base.GetControlChance( m, useBaseSkill ); + + if( tamingChance >= 0.95 ) + { + return tamingChance; + } + + double skill = (useBaseSkill? m.Skills.Bushido.Base : m.Skills.Bushido.Value); + + if( skill < 90.0 ) + { + return tamingChance; + } + + double bushidoChance = ( skill - 30.0 ) / 100; + + if( m.Skills.Bushido.Base >= 120 ) + bushidoChance += 0.05; + + return bushidoChance > tamingChance ? bushidoChance : tamingChance; + } + + public override int TreasureMapLevel { get { return 3; } } + public override int Meat { get { return 16; } } + public override int Hides { get { return 60; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if( 0.1 > Utility.RandomDouble() ) + { + /* Grasping Claw + * Start cliloc: 1070836 + * Effect: Physical resistance -15% for 5 seconds + * End cliloc: 1070838 + * Effect: Type: "3" - From: "0x57D4F5B" (player) - To: "0x0" - ItemId: "0x37B9" - ItemIdName: "glow" - FromLocation: "(1149 808, 32)" - ToLocation: "(1149 808, 32)" - Speed: "10" - Duration: "5" - FixedDirection: "True" - Explode: "False" + */ + + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070837 ); // The creature lands another blow in your weakened state. + } + else + defender.SendLocalizedMessage( 1070836 ); // The blow from the creature's claws has made you more susceptible to physical attacks. + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Physical, effect ); + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.AddResistanceMod( mod ); + + timer = new ExpireTimer( defender, mod, TimeSpan.FromSeconds( 5.0 ) ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + + public ExpireTimer( Mobile m, ResistanceMod mod, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod( m_Mod ); + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1070838 ); // Your resistance to physical attacks has returned. + DoExpire(); + } + } + + public LesserHiryu( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)2 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if( version == 0 ) + Timer.DelayCall( TimeSpan.Zero, delegate { Hue = GetHue(); } ); + + if( version <= 1 ) + Timer.DelayCall( TimeSpan.Zero, delegate { if( InternalItem != null ) { InternalItem.Hue = this.Hue; } } ); + + if( version < 2 ) + { + for ( int i = 0; i < Skills.Length; ++i ) + { + Skills[i].Cap = Math.Max( 100.0, Skills[i].Cap * 0.9 ); + + if ( Skills[i].Base > Skills[i].Cap ) + { + Skills[i].Base = Skills[i].Cap; + } + } + } + } + } +} diff --git a/Scripts/Mobiles/Animals/Mounts/Nightmare.cs b/Scripts/Mobiles/Animals/Mounts/Nightmare.cs new file mode 100644 index 0000000..ebee2ee --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Nightmare.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cauchemar" )] + public class Nightmare : BaseMount + { + [Constructable] + public Nightmare() : this( "Un cauchemar" ) + { + } + + [Constructable] + public Nightmare( string name ) : base( name, 0x74, 0x3EA7, AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = Core.AOS ? 0xA8 : 0x16A; + + SetStr( 496, 525 ); + SetDex( 86, 105 ); + SetInt( 86, 125 ); + + SetHits( 298, 315 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Fire, 40 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.EvalInt, 10.4, 50.0 ); + SetSkill( SkillName.Magery, 10.4, 50.0 ); + SetSkill( SkillName.MagicResist, 85.3, 100.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 80.5, 92.5 ); + + Fame = 14000; + Karma = -14000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 95.1; + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + BodyValue = 116; + ItemID = 16039; + break; + } + case 1: + { + BodyValue = 178; + ItemID = 16041; + break; + } + case 2: + { + BodyValue = 179; + ItemID = 16055; + break; + } + } + + PackItem( new SulfurousAsh( Utility.RandomMinMax( 3, 5 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Potions ); + } + + public override int GetAngerSound() + { + if ( !Controlled ) + return 0x16A; + + return base.GetAngerSound(); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 5; } } + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public Nightmare( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Core.AOS && BaseSoundID == 0x16A) + BaseSoundID = 0xA8; + else if (!Core.AOS && BaseSoundID == 0xA8) + BaseSoundID = 0x16A; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/RidableLlama.cs b/Scripts/Mobiles/Animals/Mounts/RidableLlama.cs new file mode 100644 index 0000000..d0d3099 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/RidableLlama.cs @@ -0,0 +1,72 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de lama" )] + public class RidableLlama : BaseMount + { + [Constructable] + public RidableLlama() : this( "Un lama de monte" ) + { + } + + [Constructable] + public RidableLlama( string name ) : base( name, 0xDC, 0x3EA6, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x3F3; + + SetStr( 21, 49 ); + SetDex( 56, 75 ); + SetInt( 16, 30 ); + + SetHits( 15, 27 ); + SetMana( 0 ); + + SetDamage( 3, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.2, 29.0 ); + SetSkill( SkillName.Wrestling, 19.2, 29.0 ); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public RidableLlama( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/Ridgeback.cs b/Scripts/Mobiles/Animals/Mounts/Ridgeback.cs new file mode 100644 index 0000000..a0a6676 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Ridgeback.cs @@ -0,0 +1,81 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de l�zard coureur" )] + public class Ridgeback : BaseMount + { + [Constructable] + public Ridgeback() : this( "Un l�zard coureur" ) + { + } + + [Constructable] + public Ridgeback( string name ) : base( name, 187, 0x3EBA, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x3F3; + + SetStr( 58, 100 ); + SetDex( 56, 75 ); + SetInt( 16, 30 ); + + SetHits( 41, 54 ); + SetMana( 0 ); + + SetDamage( 3, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 25.3, 40.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 35.1, 45.0 ); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public override bool OverrideBondingReqs() + { + return true; + } + + public override double GetControlChance( Mobile m, bool useBaseSkill ) + { + return 1.0; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Ridgeback( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/SavageRidgeback.cs b/Scripts/Mobiles/Animals/Mounts/SavageRidgeback.cs new file mode 100644 index 0000000..0051049 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/SavageRidgeback.cs @@ -0,0 +1,81 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de l�zard coureur" )] + public class SavageRidgeback : BaseMount + { + [Constructable] + public SavageRidgeback() : this( "Un l�zard coureur sauvage" ) + { + } + + [Constructable] + public SavageRidgeback( string name ) : base( name, 188, 0x3EB8, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x3F3; + + SetStr( 58, 100 ); + SetDex( 56, 75 ); + SetInt( 16, 30 ); + + SetHits( 41, 54 ); + SetMana( 0 ); + + SetDamage( 3, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 15, 20 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 25.3, 40.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 35.1, 45.0 ); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 83.1; + } + + public override bool OverrideBondingReqs() + { + return true; + } + + public override double GetControlChance( Mobile m, bool useBaseSkill ) + { + return 1.0; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public SavageRidgeback( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/ScaledSwampDragon.cs b/Scripts/Mobiles/Animals/Mounts/ScaledSwampDragon.cs new file mode 100644 index 0000000..a575bb4 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/ScaledSwampDragon.cs @@ -0,0 +1,78 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de dragon des marais" )] + public class ScaledSwampDragon : BaseMount + { + [Constructable] + public ScaledSwampDragon() : this( "Un dragon des marais" ) + { + } + + [Constructable] + public ScaledSwampDragon( string name ) : base( name, 0x31F, 0x3EBE, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + SetStr( 201, 300 ); + SetDex( 66, 85 ); + SetInt( 61, 100 ); + + SetHits( 121, 180 ); + + SetDamage( 3, 4 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Poison, 25 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 45.1, 55.0 ); + SetSkill( SkillName.MagicResist, 45.1, 55.0 ); + SetSkill( SkillName.Tactics, 45.1, 55.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 2000; + Karma = -2000; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 93.9; + } + + public override bool OverrideBondingReqs() + { + return true; + } + + public override double GetControlChance( Mobile m, bool useBaseSkill ) + { + return 1.0; + } + + public override bool AutoDispel{ get{ return !Controlled; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public ScaledSwampDragon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/SeaHorse.cs b/Scripts/Mobiles/Animals/Mounts/SeaHorse.cs new file mode 100644 index 0000000..5617044 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/SeaHorse.cs @@ -0,0 +1,59 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a sea horse corpse" )] + public class SeaHorse : BaseMount + { + [Constructable] + public SeaHorse() : this( "a sea horse" ) + { + CanSwim = true; + } + + // Scriptiz : on ne peut pas bond� ces animaux ! + public override bool IsBondable + { + get { return false; } + } + + // Scriptiz : il s'�nerve vite ! + public override bool CanAngerOnTame + { + get { return true; } + } + + [Constructable] + public SeaHorse( string name ) : base( name, 0x90, 0x3EB3, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + InitStats( Utility.Random( 50, 30 ), Utility.Random( 50, 30 ), 10 ); + Skills[SkillName.MagicResist].Base = 25.0 + (Utility.RandomDouble() * 5.0); + Skills[SkillName.Wrestling].Base = 35.0 + (Utility.RandomDouble() * 10.0); + Skills[SkillName.Tactics].Base = 30.0 + (Utility.RandomDouble() * 15.0); + + // Scriptiz : seahorse tamables + Tamable = true; + MinTameSkill = 96; + ControlSlots = 5; + } + + public SeaHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/SilverSteed.cs b/Scripts/Mobiles/Animals/Mounts/SilverSteed.cs new file mode 100644 index 0000000..333554d --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/SilverSteed.cs @@ -0,0 +1,45 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'�talon d'argent" )] + public class SilverSteed : BaseMount + { + [Constructable] + public SilverSteed() : this( "Un �talon d'argent" ) + { + } + + [Constructable] + public SilverSteed( string name ) : base( name, 0x75, 0x3EA8, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + InitStats( Utility.Random( 50, 30 ), Utility.Random( 50, 30 ), 10 ); + Skills[SkillName.MagicResist].Base = 25.0 + (Utility.RandomDouble() * 5.0); + Skills[SkillName.Wrestling].Base = 35.0 + (Utility.RandomDouble() * 10.0); + Skills[SkillName.Tactics].Base = 30.0 + (Utility.RandomDouble() * 15.0); + + ControlSlots = 1; + Tamable = true; + MinTameSkill = 103.1; + } + + public SilverSteed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/SkeletalMount.cs b/Scripts/Mobiles/Animals/Mounts/SkeletalMount.cs new file mode 100644 index 0000000..6b38357 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/SkeletalMount.cs @@ -0,0 +1,74 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cheval putr�fi�" )] + public class SkeletalMount : BaseMount + { + [Constructable] + public SkeletalMount() : this( "Un cheval putr�fi�" ) + { + } + + [Constructable] + public SkeletalMount( string name ) : base( name, 793, 0x3EBB, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + SetStr( 91, 100 ); + SetDex( 46, 55 ); + SetInt( 46, 60 ); + + SetHits( 41, 50 ); + + SetDamage( 5, 12 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Cold, 90, 95 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.MagicResist, 95.1, 100.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + SetSkill( SkillName.Wrestling, 70.1, 80.0 ); + + Fame = 0; + Karma = 0; + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override bool BleedImmune { get { return true; } } + + public SkeletalMount( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + Name = "a skeletal steed"; + Tamable = false; + MinTameSkill = 0.0; + ControlSlots = 0; + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/SwampDragon.cs b/Scripts/Mobiles/Animals/Mounts/SwampDragon.cs new file mode 100644 index 0000000..81625e0 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/SwampDragon.cs @@ -0,0 +1,215 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un dragon des marais" )] + public class SwampDragon : BaseMount + { + private bool m_BardingExceptional; + private Mobile m_BardingCrafter; + private int m_BardingHP; + private bool m_HasBarding; + private CraftResource m_BardingResource; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile BardingCrafter + { + get{ return m_BardingCrafter; } + set{ m_BardingCrafter = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool BardingExceptional + { + get{ return m_BardingExceptional; } + set{ m_BardingExceptional = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int BardingHP + { + get{ return m_BardingHP; } + set{ m_BardingHP = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasBarding + { + get{ return m_HasBarding; } + set + { + m_HasBarding = value; + + if ( m_HasBarding ) + { + Hue = CraftResources.GetHue( m_BardingResource ); + BodyValue = 0x31F; + ItemID = 0x3EBE; + } + else + { + Hue = 0x851; + BodyValue = 0x31A; + ItemID = 0x3EBD; + } + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public CraftResource BardingResource + { + get{ return m_BardingResource; } + set + { + m_BardingResource = value; + + if ( m_HasBarding ) + Hue = CraftResources.GetHue( value ); + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int BardingMaxHP + { + get{ return m_BardingExceptional ? 2500 : 1000; } + } + + [Constructable] + public SwampDragon() : this( "Un dragon des marais" ) + { + } + + [Constructable] + public SwampDragon( string name ) : base( name, 0x31A, 0x3EBD, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x16A; + + SetStr( 201, 300 ); + SetDex( 66, 85 ); + SetInt( 61, 100 ); + + SetHits( 121, 180 ); + + SetDamage( 3, 4 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Poison, 25 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 45.1, 55.0 ); + SetSkill( SkillName.MagicResist, 45.1, 55.0 ); + SetSkill( SkillName.Tactics, 45.1, 55.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 2000; + Karma = -2000; + + Hue = 0x851; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 93.9; + } + + public override bool OverrideBondingReqs() + { + return true; + } + + public override int GetIdleSound() + { + return 0x2CE; + } + + public override int GetDeathSound() + { + return 0x2CC; + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override int GetAttackSound() + { + return 0x2C8; + } + + public override double GetControlChance( Mobile m, bool useBaseSkill ) + { + return 1.0; + } + + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool AutoDispel{ get{ return !Controlled; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override int Meat{ get{ return 19; } } + public override int Hides{ get{ return 20; } } + public override int Scales{ get{ return 5; } } + public override ScaleType ScaleType{ get{ return ScaleType.Green; } } + public override bool CanAngerOnTame { get { return true; } } + + public SwampDragon( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_HasBarding && m_BardingExceptional && m_BardingCrafter != null ) + list.Add( 1060853, m_BardingCrafter.Name ); // armor exceptionally crafted by ~1_val~ + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) m_BardingExceptional ); + writer.Write( (Mobile) m_BardingCrafter ); + writer.Write( (bool) m_HasBarding ); + writer.Write( (int) m_BardingHP ); + writer.Write( (int) m_BardingResource ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_BardingExceptional = reader.ReadBool(); + m_BardingCrafter = reader.ReadMobile(); + m_HasBarding = reader.ReadBool(); + m_BardingHP = reader.ReadInt(); + m_BardingResource = (CraftResource) reader.ReadInt(); + break; + } + } + + if ( Hue == 0 && !m_HasBarding ) + Hue = 0x851; + + if ( BaseSoundID == -1 ) + BaseSoundID = 0x16A; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/Unicorn.cs b/Scripts/Mobiles/Animals/Mounts/Unicorn.cs new file mode 100644 index 0000000..8a96423 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/Unicorn.cs @@ -0,0 +1,141 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de licorne" )] + public class Unicorn : BaseMount + { + public override bool AllowMaleRider{ get{ return false; } } + public override bool AllowMaleTamer{ get{ return false; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override TimeSpan MountAbilityDelay { get { return TimeSpan.FromHours( 1.0 ); } } + + public override void OnDisallowedRider( Mobile m ) + { + m.SendLocalizedMessage( 1042318 ); // The unicorn refuses to allow you to ride it. + } + + public override bool DoMountAbility( int damage, Mobile attacker ) + { + if( Rider == null || attacker == null ) //sanity + return false; + + if( Rider.Poisoned && ((Rider.Hits - damage) < 40) ) + { + Poison p = Rider.Poison; + + if( p != null ) + { + int chanceToCure = 10000 + (int)(this.Skills[SkillName.Magery].Value * 75) - ((p.Level + 1) * (Core.AOS ? (p.Level < 4 ? 3300 : 3100) : 1750)); + chanceToCure /= 100; + + if( chanceToCure > Utility.Random( 100 ) ) + { + if( Rider.CurePoison( this ) ) //TODO: Confirm if mount is the one flagged for curing it or the rider is + { + Rider.LocalOverheadMessage( Server.Network.MessageType.Regular, 0x3B2, true, "Your mount senses you are in danger and aids you with magic." ); + Rider.FixedParticles( 0x373A, 10, 15, 5012, EffectLayer.Waist ); + Rider.PlaySound( 0x1E0 ); // Cure spell effect. + Rider.PlaySound( 0xA9 ); // Unicorn's whinny. + + return true; + } + } + } + } + + return false; + } + + [Constructable] + public Unicorn() : this( "Une licorne" ) + { + } + + [Constructable] + public Unicorn( string name ) : base( name, 0x7A, 0x3EB4, AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + BaseSoundID = 0x4BC; + + SetStr( 296, 325 ); + SetDex( 96, 115 ); + SetInt( 186, 225 ); + + SetHits( 191, 210 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 25, 40 ); + SetResistance( ResistanceType.Cold, 25, 40 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 25, 40 ); + + SetSkill( SkillName.EvalInt, 80.1, 90.0 ); + SetSkill( SkillName.Magery, 60.2, 80.0 ); + SetSkill( SkillName.Meditation, 50.1, 60.0 ); + SetSkill( SkillName.MagicResist, 75.3, 90.0 ); + SetSkill( SkillName.Tactics, 20.1, 22.5 ); + SetSkill( SkillName.Wrestling, 80.5, 92.5 ); + + Fame = 9000; + Karma = 9000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 95.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Potions ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.35) + c.DropItem(new UnicornRibs()); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int Meat{ get{ return 3; } } + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Unicorn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs b/Scripts/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs new file mode 100644 index 0000000..d36792a --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/War Horses/BaseWarHorse.cs @@ -0,0 +1,65 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de cheval de guerre" )] + public abstract class BaseWarHorse : BaseMount + { + public BaseWarHorse( int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, int rangeFight, double activeSpeed, double passiveSpeed ) : base ( "a war horse", bodyID, itemID, aiType, fightMode, rangePerception, rangeFight, activeSpeed, passiveSpeed ) + { + BaseSoundID = 0xA8; + + InitStats( Utility.Random( 300, 100 ), 125, 60 ); + + SetStr( 400 ); + SetDex( 125 ); + SetInt( 51, 55 ); + + SetHits( 240 ); + SetMana( 0 ); + + SetDamage( 5, 8 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 300; + Karma = 300; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public BaseWarHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs b/Scripts/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs new file mode 100644 index 0000000..7f45cbf --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/War Horses/CoMWarHorse.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class CoMWarHorse : BaseWarHorse + { + [Constructable] + public CoMWarHorse() : base( 0x77, 0x3EB1, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + } + + public CoMWarHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs b/Scripts/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs new file mode 100644 index 0000000..aedad69 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/War Horses/MinaxWarHorse.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MinaxWarHorse : BaseWarHorse + { + [Constructable] + public MinaxWarHorse() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + } + + public MinaxWarHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs b/Scripts/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs new file mode 100644 index 0000000..5c3bb6a --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/War Horses/SLWarHorse.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class SLWarHorse : BaseWarHorse + { + [Constructable] + public SLWarHorse() : base( 0x79, 0x3EB0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + } + + public SLWarHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs b/Scripts/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs new file mode 100644 index 0000000..3d52bc8 --- /dev/null +++ b/Scripts/Mobiles/Animals/Mounts/War Horses/TBWarHorse.cs @@ -0,0 +1,31 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class TBWarHorse : BaseWarHorse + { + [Constructable] + public TBWarHorse() : base( 0x76, 0x3EB2, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + } + + public TBWarHorse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/Alligator.cs b/Scripts/Mobiles/Animals/Reptiles/Alligator.cs new file mode 100644 index 0000000..4949386 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/Alligator.cs @@ -0,0 +1,72 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'alligator" )] + public class Alligator : BaseCreature + { + [Constructable] + public Alligator() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un alligator"; + Body = 0xCA; + BaseSoundID = 660; + + SetStr( 76, 100 ); + SetDex( 6, 25 ); + SetInt( 11, 20 ); + + SetHits( 46, 60 ); + SetStam( 46, 65 ); + SetMana( 0 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 40.1, 60.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 600; + Karma = -600; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 47.1; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + + public Alligator(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( BaseSoundID == 0x5A ) + BaseSoundID = 660; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/GiantSerpent.cs b/Scripts/Mobiles/Animals/Reptiles/GiantSerpent.cs new file mode 100644 index 0000000..a7101d5 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/GiantSerpent.cs @@ -0,0 +1,86 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de serpent g�ant" )] + [TypeAlias( "Server.Mobiles.Serpant" )] + public class GiantSerpent : BaseCreature + { + [Constructable] + public GiantSerpent() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un serpent g�ant"; + Body = 0x15; + Hue = Utility.RandomSnakeHue(); + BaseSoundID = 219; + + SetStr( 186, 215 ); + SetDex( 56, 80 ); + SetInt( 66, 85 ); + + SetHits( 112, 129 ); + SetMana( 0 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Poison, 60 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 70, 90 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Poisoning, 70.1, 100.0 ); + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 65.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 32; + + PackItem( new Bone() ); + // TODO: Body parts + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override Poison HitPoison{ get{ return (0.8 >= Utility.RandomDouble() ? Poison.Greater : Poison.Deadly); } } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override int Meat{ get{ return 4; } } + public override int Hides{ get{ return 15; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public GiantSerpent(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( BaseSoundID == -1 ) + BaseSoundID = 219; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/IceSerpent.cs b/Scripts/Mobiles/Animals/Reptiles/IceSerpent.cs new file mode 100644 index 0000000..b8ad7c6 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/IceSerpent.cs @@ -0,0 +1,97 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de serpent des glaces" )] + [TypeAlias( "Server.Mobiles.Iceserpant" )] + public class IceSerpent : BaseCreature + { + [Constructable] + public IceSerpent() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un serpent des glaces"; + Body = 89; + BaseSoundID = 219; + + SetStr( 216, 245 ); + SetDex( 26, 50 ); + SetInt( 66, 85 ); + + SetHits( 130, 147 ); + SetMana( 0 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Cold, 90 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Cold, 80, 90 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 27.5, 50.0 ); + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 75.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + + PackItem( Loot.RandomArmorOrShieldOrWeapon() ); + + switch ( Utility.Random( 10 )) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: PackItem( new RibCage() ); break; + case 6: PackItem( new BonePile() ); break; + case 7: PackItem( new BonePile() ); break; + case 8: PackItem( new BonePile() ); break; + case 9: PackItem( new BonePile() ); break; + } + + if ( 0.025 > Utility.RandomDouble() ) + PackItem( new GlacialStaff() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override int Meat{ get{ return 4; } } + public override int Hides{ get{ return 15; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public IceSerpent(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( BaseSoundID == -1 ) + BaseSoundID = 219; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/IceSnake.cs b/Scripts/Mobiles/Animals/Reptiles/IceSnake.cs new file mode 100644 index 0000000..9337db3 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/IceSnake.cs @@ -0,0 +1,72 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de vip�re des glaces" )] + [TypeAlias( "Server.Mobiles.Icesnake" )] + public class IceSnake : BaseCreature + { + [Constructable] + public IceSnake() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Une vip�re des glaces"; + Body = 52; + Hue = 0x480; + BaseSoundID = 0xDB; + + SetStr( 42, 54 ); + SetDex( 36, 45 ); + SetInt( 26, 30 ); + + SetMana( 0 ); + + SetDamage( 4, 12 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Cold, 25 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Cold, 80, 90 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 39.3, 54.0 ); + SetSkill( SkillName.Wrestling, 39.3, 54.0 ); + + Fame = 900; + Karma = -900; + + VirtualArmor = 30; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override int Meat{ get{ return 1; } } + + public IceSnake(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/LavaLizard.cs b/Scripts/Mobiles/Animals/Reptiles/LavaLizard.cs new file mode 100644 index 0000000..2d2f94e --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/LavaLizard.cs @@ -0,0 +1,78 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de l�zard des volcans" )] + [TypeAlias( "Server.Mobiles.Lavalizard" )] + public class LavaLizard : BaseCreature + { + [Constructable] + public LavaLizard() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un l�zard des volcans"; + Body = 0xCE; + Hue = Utility.RandomList( 0x647, 0x650, 0x659, 0x662, 0x66B, 0x674 ); + BaseSoundID = 0x5A; + + SetStr( 126, 150 ); + SetDex( 56, 75 ); + SetInt( 11, 20 ); + + SetHits( 76, 90 ); + SetMana( 0 ); + + SetDamage( 6, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 30, 45 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 60.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 80.7; + + PackItem( new SulfurousAsh( Utility.Random( 4, 10 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public LavaLizard(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/LavaSerpent.cs b/Scripts/Mobiles/Animals/Reptiles/LavaSerpent.cs new file mode 100644 index 0000000..eb5e251 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/LavaSerpent.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de serpent des volcans")] + [TypeAlias( "Server.Mobiles.Lavaserpant" )] + public class LavaSerpent : BaseCreature + { + [Constructable] + public LavaSerpent() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un serpent des volcans"; + Body = 90; + BaseSoundID = 219; + + SetStr( 386, 415 ); + SetDex( 56, 80 ); + SetInt( 66, 85 ); + + SetHits( 232, 249 ); + SetMana( 0 ); + + SetDamage( 10, 22 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 80 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 25.3, 70.0 ); + SetSkill( SkillName.Tactics, 65.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + + PackItem( new SulfurousAsh( 3 ) ); + PackItem( new Bone() ); + // TODO: body parts, armour + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 4; } } + public override int Hides{ get{ return 15; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public LavaSerpent(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( BaseSoundID == -1 ) + BaseSoundID = 219; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/LavaSnake.cs b/Scripts/Mobiles/Animals/Reptiles/LavaSnake.cs new file mode 100644 index 0000000..375d67c --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/LavaSnake.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de vip�re des volcans")] + [TypeAlias( "Server.Mobiles.Lavasnake" )] + public class LavaSnake : BaseCreature + { + [Constructable] + public LavaSnake() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un vip�re des volcans"; + Body = 52; + Hue = Utility.RandomList( 0x647, 0x650, 0x659, 0x662, 0x66B, 0x674 ); + BaseSoundID = 0xDB; + + SetStr( 43, 55 ); + SetDex( 16, 25 ); + SetInt( 6, 10 ); + + SetHits( 28, 32 ); + SetMana( 0 ); + + SetDamage( 1, 8 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.3, 34.0 ); + SetSkill( SkillName.Wrestling, 19.3, 34.0 ); + + Fame = 600; + Karma = -600; + + VirtualArmor = 24; + + PackItem( new SulfurousAsh() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 1; } } + + public LavaSnake(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/SilverSerpent.cs b/Scripts/Mobiles/Animals/Reptiles/SilverSerpent.cs new file mode 100644 index 0000000..cef1491 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/SilverSerpent.cs @@ -0,0 +1,82 @@ +using System; +using Server.Mobiles; +using Server.Factions; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de serpent d'argent")] + [TypeAlias( "Server.Mobiles.Silverserpant" )] + public class SilverSerpent : BaseCreature + { + public override Faction FactionAllegiance { get { return TrueBritannians.Instance; } } + public override Ethics.Ethic EthicAllegiance { get { return Ethics.Ethic.Hero; } } + + [Constructable] + public SilverSerpent() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 92; + Name = "Un serpent d'argent"; + BaseSoundID = 219; + + SetStr( 161, 360 ); + SetDex( 151, 300 ); + SetInt( 21, 40 ); + + SetHits( 97, 216 ); + + SetDamage( 5, 21 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.Poisoning, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 95.1, 100.0 ); + SetSkill( SkillName.Tactics, 80.1, 95.0 ); + SetSkill( SkillName.Wrestling, 85.1, 100.0 ); + + Fame = 7000; + Karma = -7000; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override int Meat{ get{ return 1; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + + public SilverSerpent(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( BaseSoundID == -1 ) + BaseSoundID = 219; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Reptiles/Snake.cs b/Scripts/Mobiles/Animals/Reptiles/Snake.cs new file mode 100644 index 0000000..ef19cd3 --- /dev/null +++ b/Scripts/Mobiles/Animals/Reptiles/Snake.cs @@ -0,0 +1,72 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de vip�re" )] + public class Snake : BaseCreature + { + [Constructable] + public Snake() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Une vip�re"; + Body = 52; + Hue = Utility.RandomSnakeHue(); + BaseSoundID = 0xDB; + + SetStr( 22, 34 ); + SetDex( 16, 25 ); + SetInt( 6, 10 ); + + SetHits( 15, 19 ); + SetMana( 0 ); + + SetDamage( 1, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + + SetSkill( SkillName.Poisoning, 50.1, 70.0 ); + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.3, 34.0 ); + SetSkill( SkillName.Wrestling, 19.3, 34.0 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + } + + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + public override Poison HitPoison{ get{ return Poison.Lesser; } } + + public override bool DeathAdderCharmable{ get{ return true; } } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Eggs; } } + + public Snake(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Rodents/GiantRat.cs b/Scripts/Mobiles/Animals/Rodents/GiantRat.cs new file mode 100644 index 0000000..ef9615c --- /dev/null +++ b/Scripts/Mobiles/Animals/Rodents/GiantRat.cs @@ -0,0 +1,73 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de rat g�ant")] + [TypeAlias( "Server.Mobiles.Giantrat" )] + public class GiantRat : BaseCreature + { + [Constructable] + public GiantRat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un rat g�ant"; + Body = 0xD7; + BaseSoundID = 0x188; + + SetStr( 32, 74 ); + SetDex( 46, 65 ); + SetInt( 16, 30 ); + + SetHits( 26, 39 ); + SetMana( 0 ); + + SetDamage( 4, 8 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 18; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 29.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish | FoodType.Meat | FoodType.FruitsAndVegies | FoodType.Eggs; } } + + public GiantRat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Rodents/JackRabbit.cs b/Scripts/Mobiles/Animals/Rodents/JackRabbit.cs new file mode 100644 index 0000000..61ea8a5 --- /dev/null +++ b/Scripts/Mobiles/Animals/Rodents/JackRabbit.cs @@ -0,0 +1,81 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de li�vre" )] + [TypeAlias( "Server.Mobiles.Jackrabbit" )] + public class JackRabbit : BaseCreature + { + [Constructable] + public JackRabbit() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un li�vre"; + Body = 0xCD; + Hue = 0x1BB; + + SetStr( 15 ); + SetDex( 25 ); + SetInt( 5 ); + + SetHits( 9 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 2, 5 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 4; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies; } } + + public JackRabbit(Serial serial) : base(serial) + { + } + + public override int GetAttackSound() + { + return 0xC9; + } + + public override int GetHurtSound() + { + return 0xCA; + } + + public override int GetDeathSound() + { + return 0xCB; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Rodents/Rabbit.cs b/Scripts/Mobiles/Animals/Rodents/Rabbit.cs new file mode 100644 index 0000000..2c4dff1 --- /dev/null +++ b/Scripts/Mobiles/Animals/Rodents/Rabbit.cs @@ -0,0 +1,82 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de lapin")] + public class Rabbit : BaseCreature + { + [Constructable] + public Rabbit() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un lapin"; + Body = 205; + + if ( 0.5 >= Utility.RandomDouble() ) + Hue = Utility.RandomAnimalHue(); + + SetStr( 6, 10 ); + SetDex( 26, 38 ); + SetInt( 6, 14 ); + + SetHits( 4, 6 ); + SetMana( 0 ); + + SetDamage( 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies; } } + + public Rabbit(Serial serial) : base(serial) + { + } + + public override int GetAttackSound() + { + return 0xC9; + } + + public override int GetHurtSound() + { + return 0xCA; + } + + public override int GetDeathSound() + { + return 0xCB; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Rodents/SewerRat.cs b/Scripts/Mobiles/Animals/Rodents/SewerRat.cs new file mode 100644 index 0000000..84780da --- /dev/null +++ b/Scripts/Mobiles/Animals/Rodents/SewerRat.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de rat d'�gouts")] + public class Sewerrat : BaseCreature + { + [Constructable] + public Sewerrat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un rat d'�gouts"; + Body = 238; + BaseSoundID = 0xCC; + + SetStr( 9 ); + SetDex( 25 ); + SetInt( 6, 10 ); + + SetHits( 6 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Eggs | FoodType.FruitsAndVegies; } } + + public Sewerrat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Slimes/Jwilson.cs b/Scripts/Mobiles/Animals/Slimes/Jwilson.cs new file mode 100644 index 0000000..0705d76 --- /dev/null +++ b/Scripts/Mobiles/Animals/Slimes/Jwilson.cs @@ -0,0 +1,71 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de schmu" )] + public class Jwilson : BaseCreature + { + [Constructable] + public Jwilson() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Hue = Utility.RandomList(0x89C,0x8A2,0x8A8,0x8AE); + this.Body = 0x33; + this.Name = ("Un schmu"); + this.VirtualArmor = 8; + + this.InitStats(Utility.Random(22,13),Utility.Random(16,6),Utility.Random(16,5)); + + this.Skills[SkillName.Wrestling].Base = Utility.Random(24,17); + this.Skills[SkillName.Tactics].Base = Utility.Random(18,14); + this.Skills[SkillName.MagicResist].Base = Utility.Random(15,6); + this.Skills[SkillName.Poisoning].Base = Utility.Random(31,20); + + this.Fame = Utility.Random(0,1249); + this.Karma = Utility.Random(0,-624); + } + + public Jwilson(Serial serial) : base(serial) + { + } + + public override int GetAngerSound() + { + return 0x1C8; + } + + public override int GetIdleSound() + { + return 0x1C9; + } + + public override int GetAttackSound() + { + return 0x1CA; + } + + public override int GetHurtSound() + { + return 0x1CB; + } + + public override int GetDeathSound() + { + return 0x1CC; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs b/Scripts/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs new file mode 100644 index 0000000..f82e52d --- /dev/null +++ b/Scripts/Mobiles/Animals/Town Critters/(UO 3D Only) Parrot.cs @@ -0,0 +1,73 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de perroquet")] + public class Parrot : BaseCreature + { + [Constructable] + public Parrot() : base(AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + this.Body = 831; + this.Name = ("Un perroquet"); + this.VirtualArmor = Utility.Random(0,6); + + this.InitStats((10),Utility.Random(25,16),(10)); + + this.Skills[SkillName.Wrestling].Base = (6); + this.Skills[SkillName.Tactics].Base = (6); + this.Skills[SkillName.MagicResist].Base = (5); + + this.Fame = Utility.Random(0,1249); + this.Karma = Utility.Random(0,-624); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 0.0; + } + + public Parrot(Serial serial) : base(serial) + { + } + + public override int GetAngerSound() + { + return 0x1B; + } + + public override int GetIdleSound() + { + return 0x1C; + } + + public override int GetAttackSound() + { + return 0x1D; + } + + public override int GetHurtSound() + { + return 0x1E; + } + + public override int GetDeathSound() + { + return 0x1F; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Town Critters/Bird.cs b/Scripts/Mobiles/Animals/Town Critters/Bird.cs new file mode 100644 index 0000000..19d7204 --- /dev/null +++ b/Scripts/Mobiles/Animals/Town Critters/Bird.cs @@ -0,0 +1,139 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps d'oiseau" )] + public class Bird : BaseCreature + { + [Constructable] + public Bird() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + if ( Utility.RandomBool() ) + { + Hue = 0x901; + + switch ( Utility.Random( 3 ) ) + { + case 0: Name = "Une corneille"; break; + case 2: Name = "Un corbeau"; break; + case 1: Name = "Une pie"; break; + } + } + else + { + Hue = Utility.RandomBirdHue(); + Name = NameList.RandomName( "bird" ); + } + + Body = 6; + BaseSoundID = 0x1B; + + VirtualArmor = Utility.RandomMinMax( 0, 6 ); + + SetStr( 10 ); + SetDex( 25, 35 ); + SetInt( 10 ); + + SetDamage( 0 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetSkill( SkillName.Wrestling, 4.2, 6.4 ); + SetSkill( SkillName.Tactics, 4.0, 6.0 ); + SetSkill( SkillName.MagicResist, 4.0, 5.0 ); + + Fame = 150; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -6.9; + } + + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override int Meat{ get{ return 1; } } + public override int Feathers{ get{ return 25; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public Bird( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Hue == 0 ) + Hue = Utility.RandomBirdHue(); + } + } + + [CorpseName( "Un corps d'oiseau" )] + public class TropicalBird : BaseCreature + { + [Constructable] + public TropicalBird() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Hue = Utility.RandomBirdHue(); + Name = "Un oiseau tropical"; + + Body = 6; + BaseSoundID = 0xBF; + + VirtualArmor = Utility.RandomMinMax( 0, 6 ); + + SetStr( 10 ); + SetDex( 25, 35 ); + SetInt( 10 ); + + SetDamage( 0 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetSkill( SkillName.Wrestling, 4.2, 6.4 ); + SetSkill( SkillName.Tactics, 4.0, 6.0 ); + SetSkill( SkillName.MagicResist, 4.0, 5.0 ); + + Fame = 150; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -6.9; + } + + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override int Meat{ get{ return 1; } } + public override int Feathers{ get{ return 25; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public TropicalBird( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Town Critters/Cat.cs b/Scripts/Mobiles/Animals/Town Critters/Cat.cs new file mode 100644 index 0000000..017adef --- /dev/null +++ b/Scripts/Mobiles/Animals/Town Critters/Cat.cs @@ -0,0 +1,69 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de chat" )] + [TypeAlias( "Server.Mobiles.Housecat" )] + public class Cat : BaseCreature + { + [Constructable] + public Cat() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un chat"; + Body = 0xC9; + Hue = Utility.RandomAnimalHue(); + BaseSoundID = 0x69; + + SetStr( 9 ); + SetDex( 35 ); + SetInt( 5 ); + + SetHits( 6 ); + SetMana( 0 ); + + SetDamage( 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 4.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 0; + Karma = 150; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Feline; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Cat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Town Critters/Dog.cs b/Scripts/Mobiles/Animals/Town Critters/Dog.cs new file mode 100644 index 0000000..d5d1d9b --- /dev/null +++ b/Scripts/Mobiles/Animals/Town Critters/Dog.cs @@ -0,0 +1,68 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de chien")] + public class Dog : BaseCreature + { + [Constructable] + public Dog() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un chien"; + Body = 0xD9; + Hue = Utility.RandomAnimalHue(); + BaseSoundID = 0x85; + + SetStr( 27, 37 ); + SetDex( 28, 43 ); + SetInt( 29, 37 ); + + SetHits( 17, 22 ); + SetMana( 0 ); + + SetDamage( 4, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + + SetSkill( SkillName.MagicResist, 22.1, 47.0 ); + SetSkill( SkillName.Tactics, 19.2, 31.0 ); + SetSkill( SkillName.Wrestling, 19.2, 31.0 ); + + Fame = 0; + Karma = 300; + + VirtualArmor = 12; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -15.3; + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public override bool NoHouseRestrictions { get { return true; } } + + public Dog(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Animals/Town Critters/Rat.cs b/Scripts/Mobiles/Animals/Town Critters/Rat.cs new file mode 100644 index 0000000..5c165cf --- /dev/null +++ b/Scripts/Mobiles/Animals/Town Critters/Rat.cs @@ -0,0 +1,70 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName("Un corps de rat")] + public class Rat : BaseCreature + { + [Constructable] + public Rat() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Un rat"; + Body = 238; + BaseSoundID = 0xCC; + + SetStr( 9 ); + SetDex( 35 ); + SetInt( 5 ); + + SetHits( 6 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + + SetSkill( SkillName.MagicResist, 4.0 ); + SetSkill( SkillName.Tactics, 4.0 ); + SetSkill( SkillName.Wrestling, 4.0 ); + + Fame = 150; + Karma = -150; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -0.9; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish | FoodType.Eggs | FoodType.GrainsAndHay; } } + + public Rat(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs new file mode 100644 index 0000000..86c7b56 --- /dev/null +++ b/Scripts/Mobiles/BaseCreature.cs @@ -0,0 +1,6011 @@ +// Nerun's Distro changes at lines 51-3; 2268-80. +using System; +using System.Collections.Generic; +using Server.Regions; +using Server.Targeting; +using Server.Network; +using Server.Multis; +using Server.Spells; +using Server.Misc; +using Server.Items; +using Server.ContextMenus; +using Server.Engines.Quests; +using Server.Engines.MLQuests; +using Server.Engines.PartySystem; +using Server.Factions; +using Server.SkillHandlers; +using Server.Spells.Bushido; +using Server.Spells.Spellweaving; +using Server.Spells.Necromancy; +using Server.Engines.XmlSpawner2; + +namespace Server.Mobiles +{ + #region Enums + /// + /// Summary description for MobileAI. + /// + /// + public enum FightMode + { + None, // Never focus on others + Aggressor, // Only attack aggressors + Strongest, // Attack the strongest + Weakest, // Attack the weakest + Closest, // Attack the closest + Evil // Only attack aggressor -or- negative karma + } + + public enum OrderType + { + None, //When no order, let's roam + Come, //"(All/Name) come" Summons all or one pet to your location. + Drop, //"(Name) drop" Drops its loot to the ground (if it carries any). + Follow, //"(Name) follow" Follows targeted being. + //"(All/Name) follow me" Makes all or one pet follow you. + Friend, //"(Name) friend" Allows targeted player to confirm resurrection. + Unfriend, // Remove a friend + Guard, //"(Name) guard" Makes the specified pet guard you. Pets can only guard their owner. + //"(All/Name) guard me" Makes all or one pet guard you. + Attack, //"(All/Name) kill", + //"(All/Name) attack" All or the specified pet(s) currently under your control attack the target. + Patrol, //"(Name) patrol" Roves between two or more guarded targets. + Release, //"(Name) release" Releases pet back into the wild (removes "tame" status). + // >>> [1st change of 2] + Dismiss, //"(Name) dismiss" Dismiss hireling (removes "tame" status). + // end 1st + Stay, //"(All/Name) stay" All or the specified pet(s) will stop and stay in current spot. + Stop, //"(All/Name) stop Cancels any current orders to attack, guard or follow. + Transfer //"(Name) transfer" Transfers complete ownership to targeted player. + } + + [Flags] + public enum FoodType + { + None = 0x0000, + Meat = 0x0001, + FruitsAndVegies = 0x0002, + GrainsAndHay = 0x0004, + Fish = 0x0008, + Eggs = 0x0010, + Gold = 0x0020 + } + + [Flags] + public enum PackInstinct + { + None = 0x0000, + Canine = 0x0001, + Ostard = 0x0002, + Feline = 0x0004, + Arachnid = 0x0008, + Daemon = 0x0010, + Bear = 0x0020, + Equine = 0x0040, + Bull = 0x0080 + } + + public enum ScaleType + { + Red, + Yellow, + Black, + Green, + White, + Blue, + All + } + + public enum MeatType + { + Ribs, + Bird, + LambLeg + } + + public enum HideType + { + Regular, + Spined, + Horned, + Barbed, + Daemon + } + + #endregion + + public class DamageStore : IComparable + { + public Mobile m_Mobile; + public int m_Damage; + public bool m_HasRight; + + public DamageStore(Mobile m, int damage) + { + m_Mobile = m; + m_Damage = damage; + } + + public int CompareTo(object obj) + { + DamageStore ds = (DamageStore)obj; + + return ds.m_Damage - m_Damage; + } + } + + [AttributeUsage(AttributeTargets.Class)] + public class FriendlyNameAttribute : Attribute + { + //future use: Talisman 'Protection/Bonus vs. Specific Creature + private TextDefinition m_FriendlyName; + + public TextDefinition FriendlyName + { + get + { + return m_FriendlyName; + } + } + + public FriendlyNameAttribute(TextDefinition friendlyName) + { + m_FriendlyName = friendlyName; + } + + public static TextDefinition GetFriendlyNameFor(Type t) + { + if (t.IsDefined(typeof(FriendlyNameAttribute), false)) + { + object[] objs = t.GetCustomAttributes(typeof(FriendlyNameAttribute), false); + + if (objs != null && objs.Length > 0) + { + FriendlyNameAttribute friendly = objs[0] as FriendlyNameAttribute; + + return friendly.FriendlyName; + } + } + + return t.Name; + } + } + + public partial class BaseCreature : Mobile, IHonorTarget, IQuestGiver + { + public const int MaxLoyalty = 100; + + #region Var declarations + private BaseAI m_AI; // THE AI + + private AIType m_CurrentAI; // The current AI + private AIType m_DefaultAI; // The default AI + + private Mobile m_FocusMob; // Use focus mob instead of combatant, maybe we don't whan to fight + private FightMode m_FightMode; // The style the mob uses + + private int m_iRangePerception; // The view area + private int m_iRangeFight; // The fight distance + + private bool m_bDebugAI; // Show debug AI messages + + private int m_iTeam; // Monster Team + + private double m_dActiveSpeed; // Timer speed when active + private double m_dPassiveSpeed; // Timer speed when not active + private double m_dCurrentSpeed; // The current speed, lets say it could be changed by something; + + private Point3D m_pHome; // The home position of the creature, used by some AI + private int m_iRangeHome = 10; // The home range of the creature + + List m_arSpellAttack; // List of attack spell/power + List m_arSpellDefense; // List of defensive spell/power + + private bool m_bControlled; // Is controlled + private Mobile m_ControlMaster; // My master + private Mobile m_ControlTarget; // My target mobile + private Point3D m_ControlDest; // My target destination (patrol) + private OrderType m_ControlOrder; // My order + + private int m_Loyalty; + + private double m_dMinTameSkill; + private bool m_bTamable; + + private bool m_bSummoned = false; + private DateTime m_SummonEnd; + private int m_iControlSlots = 1; + + private bool m_bBardProvoked = false; + private bool m_bBardPacified = false; + private Mobile m_bBardMaster = null; + private Mobile m_bBardTarget = null; + private DateTime m_timeBardEnd; + private WayPoint m_CurrentWayPoint = null; + private IPoint2D m_TargetLocation = null; + + private Mobile m_SummonMaster; + + private int m_HitsMax = -1; + private int m_StamMax = -1; + private int m_ManaMax = -1; + private int m_DamageMin = -1; + private int m_DamageMax = -1; + + private int m_PhysicalResistance, m_PhysicalDamage = 100; + private int m_FireResistance, m_FireDamage; + private int m_ColdResistance, m_ColdDamage; + private int m_PoisonResistance, m_PoisonDamage; + private int m_EnergyResistance, m_EnergyDamage; + private int m_ChaosDamage; + private int m_DirectDamage; + + private List m_Owners; + private List m_Friends; + + private bool m_IsStabled; + private Mobile m_StabledBy; + + private bool m_HasGeneratedLoot; // have we generated our loot yet? + + private bool m_Paragon; + private Int32 m_specificHue; + private bool m_hasSpecificHue = false; + private bool m_IsPrisoner; + + private string m_CorpseNameOverride; + + private int m_FailedReturnHome; /* return to home failure counter */ + + #endregion + + public virtual InhumanSpeech SpeechType { get { return null; } } + + /* Do not serialize this till the code is finalized */ + + private bool m_SeeksHome; + + [CommandProperty(AccessLevel.GameMaster)] + public bool SeeksHome + { + get + { + return m_SeeksHome; + } + set + { + m_SeeksHome = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string CorpseNameOverride + { + get { return m_CorpseNameOverride; } + set { m_CorpseNameOverride = value; } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public bool IsStabled + { + get { return m_IsStabled; } + set + { + m_IsStabled = value; + if (m_IsStabled) + StopDeleteTimer(); + } + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public Mobile StabledBy + { + get { return m_StabledBy; } + set { m_StabledBy = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsPrisoner + { + get { return m_IsPrisoner; } + set { m_IsPrisoner = value; } + } + + protected DateTime SummonEnd + { + get { return m_SummonEnd; } + set { m_SummonEnd = value; } + } + + public virtual Faction FactionAllegiance { get { return null; } } + public virtual int FactionSilverWorth { get { return 30; } } + + #region ML Quest System + + private List m_MLQuests; + + public List MLQuests + { + get + { + if (m_MLQuests == null) + { + if (StaticMLQuester) + m_MLQuests = MLQuestSystem.FindQuestList(GetType()); + else + m_MLQuests = ConstructQuestList(); + + if (m_MLQuests == null) + return MLQuestSystem.EmptyList; // return EmptyList, but don't cache it (run construction again next time) + } + + return m_MLQuests; + } + } + + public virtual bool CanGiveMLQuest { get { return (MLQuests.Count != 0); } } + public virtual bool StaticMLQuester { get { return true; } } + + protected virtual List ConstructQuestList() + { + return null; + } + + public virtual bool CanShout { get { return false; } } + + public const int ShoutRange = 8; + public static readonly TimeSpan ShoutDelay = TimeSpan.FromMinutes(1); + + private DateTime m_MLNextShout; + + private void CheckShout(PlayerMobile pm, Point3D oldLocation) + { + if (m_MLNextShout > DateTime.Now || pm.Hidden || !pm.Alive) + return; + + int shoutRange = ShoutRange; + + if (!InRange(pm.Location, shoutRange) || InRange(oldLocation, shoutRange) || !CanSee(pm) || !InLOS(pm)) + return; + + MLQuestContext context = MLQuestSystem.GetContext(pm); + + if (context != null && context.IsFull) + return; + + MLQuest quest = MLQuestSystem.RandomStarterQuest(this, pm, context); + + if (quest == null || !quest.Activated || (context != null && context.IsDoingQuest(quest))) + return; + + Shout(pm); + m_MLNextShout = DateTime.Now + ShoutDelay; + } + + public virtual void Shout(PlayerMobile pm) + { + } + + #endregion + + #region Bonding + public const bool BondingEnabled = true; + + public virtual bool IsBondable { get { return (BondingEnabled && !Summoned); } } + public virtual TimeSpan BondingDelay { get { return TimeSpan.FromDays(7.0); } } + public virtual TimeSpan BondingAbandonDelay { get { return TimeSpan.FromDays(1.0); } } + + public override bool CanRegenHits { get { return !m_IsDeadPet && base.CanRegenHits; } } + public override bool CanRegenStam { get { return !IsParagon && !m_IsDeadPet && base.CanRegenStam; } } + public override bool CanRegenMana { get { return !m_IsDeadPet && base.CanRegenMana; } } + + public override bool IsDeadBondedPet { get { return m_IsDeadPet; } } + + private bool m_IsBonded; + private bool m_IsDeadPet; + private DateTime m_BondingBegin; + private DateTime m_OwnerAbandonTime; + + [CommandProperty(AccessLevel.GameMaster)] + public Spawner MySpawner + { + get + { + if (Spawner is Spawner) + { + return (Spawner as Spawner); + } + + return null; + } + set + { + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile LastOwner + { + get + { + if (m_Owners == null || m_Owners.Count == 0) + return null; + + return m_Owners[m_Owners.Count - 1]; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsBonded + { + get { return m_IsBonded; } + set { m_IsBonded = value; InvalidateProperties(); } + } + + public bool IsDeadPet + { + get { return m_IsDeadPet; } + set { m_IsDeadPet = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime BondingBegin + { + get { return m_BondingBegin; } + set { m_BondingBegin = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime OwnerAbandonTime + { + get { return m_OwnerAbandonTime; } + set { m_OwnerAbandonTime = value; } + } + #endregion + + #region Delete Previously Tamed Timer + private DeleteTimer m_DeleteTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DeleteTimeLeft + { + get + { + if (m_DeleteTimer != null && m_DeleteTimer.Running) + return m_DeleteTimer.Next - DateTime.Now; + + return TimeSpan.Zero; + } + } + + private class DeleteTimer : Timer + { + private Mobile m; + + public DeleteTimer(Mobile creature, TimeSpan delay) + : base(delay) + { + m = creature; + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m.Delete(); + } + } + + public void BeginDeleteTimer() + { + if (!(this is BaseEscortable) && !Summoned && !Deleted && !IsStabled) + { + StopDeleteTimer(); + m_DeleteTimer = new DeleteTimer(this, TimeSpan.FromDays(3.0)); + m_DeleteTimer.Start(); + } + } + + public void StopDeleteTimer() + { + if (m_DeleteTimer != null) + { + m_DeleteTimer.Stop(); + m_DeleteTimer = null; + } + } + + #endregion + + public virtual double WeaponAbilityChance { get { return 0.4; } } + + public virtual WeaponAbility GetWeaponAbility() + { + // ARTEGORDONMOD + // allow creatures special attack ability to be specified by the xmlweaponability attachment + //return null; + XmlWeaponAbility a = (XmlWeaponAbility)XmlAttach.FindAttachment(this, typeof(XmlWeaponAbility)); + if (a != null) + { + return a.WeaponAbility; + } + else + { + return null; + } + + + } + + #region Elemental Resistance/Damage + + public override int BasePhysicalResistance { get { return m_PhysicalResistance; } } + public override int BaseFireResistance { get { return m_FireResistance; } } + public override int BaseColdResistance { get { return m_ColdResistance; } } + public override int BasePoisonResistance { get { return m_PoisonResistance; } } + public override int BaseEnergyResistance { get { return m_EnergyResistance; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int PhysicalResistanceSeed { get { return m_PhysicalResistance; } set { m_PhysicalResistance = value; UpdateResistances(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int FireResistSeed { get { return m_FireResistance; } set { m_FireResistance = value; UpdateResistances(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int ColdResistSeed { get { return m_ColdResistance; } set { m_ColdResistance = value; UpdateResistances(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonResistSeed { get { return m_PoisonResistance; } set { m_PoisonResistance = value; UpdateResistances(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int EnergyResistSeed { get { return m_EnergyResistance; } set { m_EnergyResistance = value; UpdateResistances(); } } + + [CommandProperty(AccessLevel.GameMaster)] + public int PhysicalDamage { get { return m_PhysicalDamage; } set { m_PhysicalDamage = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int FireDamage { get { return m_FireDamage; } set { m_FireDamage = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int ColdDamage { get { return m_ColdDamage; } set { m_ColdDamage = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int PoisonDamage { get { return m_PoisonDamage; } set { m_PoisonDamage = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int EnergyDamage { get { return m_EnergyDamage; } set { m_EnergyDamage = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int ChaosDamage { get { return m_ChaosDamage; } set { m_ChaosDamage = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int DirectDamage { get { return m_DirectDamage; } set { m_DirectDamage = value; } } + + #endregion + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsParagon + { + get { return m_Paragon; } + set + { + if (m_Paragon == value) + return; + else if (value) + Paragon.Convert(this); + else + Paragon.UnConvert(this); + + m_Paragon = value; + + InvalidateProperties(); + } + } + + public virtual Int32 SpecificHue + { + get + { + return m_specificHue; + } + set + { + m_hasSpecificHue = true; + m_specificHue = value; + } + } + public virtual bool HasManaOveride { get { return false; } } + public virtual bool HasSpecificHue { get { return m_hasSpecificHue; } } + public virtual FoodType FavoriteFood { get { return FoodType.Meat; } } + public virtual PackInstinct PackInstinct { get { return PackInstinct.None; } } + + public List Owners { get { return m_Owners; } } + + public virtual bool AllowMaleTamer { get { return true; } } + public virtual bool AllowFemaleTamer { get { return true; } } + public virtual bool SubdueBeforeTame { get { return false; } } + public virtual bool StatLossAfterTame { get { return SubdueBeforeTame; } } + public virtual bool ReduceSpeedWithDamage { get { return true; } } + public virtual bool IsSubdued { get { return SubdueBeforeTame && (Hits < (HitsMax / 10)); } } + + public virtual bool Commandable { get { return true; } } + + public virtual Poison HitPoison { get { return null; } } + public virtual double HitPoisonChance { get { return 0.5; } } + public virtual Poison PoisonImmune { get { return null; } } + + public virtual bool BardImmune { get { return false; } } + public virtual bool Unprovokable { get { return BardImmune || m_IsDeadPet; } } + public virtual bool Uncalmable { get { return BardImmune || m_IsDeadPet; } } + public virtual bool AreaPeaceImmune { get { return BardImmune || m_IsDeadPet; } } + + public virtual bool BleedImmune { get { return false; } } + public virtual double BonusPetDamageScalar { get { return 1.0; } } + + public virtual bool DeathAdderCharmable { get { return false; } } + + //TODO: Find the pub 31 tweaks to the DispelDifficulty and apply them of course. + public virtual double DispelDifficulty { get { return 0.0; } } // at this skill level we dispel 50% chance + public virtual double DispelFocus { get { return 20.0; } } // at difficulty - focus we have 0%, at difficulty + focus we have 100% + public virtual bool DisplayWeight { get { return Backpack is StrongBackpack; } } + + #region Breath ability, like dragon fire breath + private DateTime m_NextBreathTime; + + // Must be overriden in subclass to enable + public virtual bool HasBreath { get { return false; } } + + // Base damage given is: CurrentHitPoints * BreathDamageScalar + public virtual double BreathDamageScalar { get { return (Core.AOS ? 0.16 : 0.05); } } + + // Min/max seconds until next breath + public virtual double BreathMinDelay { get { return 30.0; } } + public virtual double BreathMaxDelay { get { return 45.0; } } + + // Creature stops moving for 1.0 seconds while breathing + public virtual double BreathStallTime { get { return 1.0; } } + + // Effect is sent 1.3 seconds after BreathAngerSound and BreathAngerAnimation is played + public virtual double BreathEffectDelay { get { return 1.3; } } + + // Damage is given 1.0 seconds after effect is sent + public virtual double BreathDamageDelay { get { return 1.0; } } + + public virtual int BreathRange { get { return RangePerception; } } + + // Damage types + public virtual int BreathChaosDamage { get { return 0; } } + public virtual int BreathPhysicalDamage { get { return 0; } } + public virtual int BreathFireDamage { get { return 100; } } + public virtual int BreathColdDamage { get { return 0; } } + public virtual int BreathPoisonDamage { get { return 0; } } + public virtual int BreathEnergyDamage { get { return 0; } } + + // Is immune to breath damages + public virtual bool BreathImmune { get { return false; } } + + // Effect details and sound + public virtual int BreathEffectItemID { get { return 0x36D4; } } + public virtual int BreathEffectSpeed { get { return 5; } } + public virtual int BreathEffectDuration { get { return 0; } } + public virtual bool BreathEffectExplodes { get { return false; } } + public virtual bool BreathEffectFixedDir { get { return false; } } + public virtual int BreathEffectHue { get { return 0; } } + public virtual int BreathEffectRenderMode { get { return 0; } } + + public virtual int BreathEffectSound { get { return 0x227; } } + + // Anger sound/animations + public virtual int BreathAngerSound { get { return GetAngerSound(); } } + public virtual int BreathAngerAnimation { get { return 12; } } + + public virtual void BreathStart(Mobile target) + { + BreathStallMovement(); + BreathPlayAngerSound(); + BreathPlayAngerAnimation(); + + this.Direction = this.GetDirectionTo(target); + + Timer.DelayCall(TimeSpan.FromSeconds(BreathEffectDelay), new TimerStateCallback(BreathEffect_Callback), target); + } + + public virtual void BreathStallMovement() + { + if (m_AI != null) + m_AI.NextMove = DateTime.Now + TimeSpan.FromSeconds(BreathStallTime); + } + + public virtual void BreathPlayAngerSound() + { + PlaySound(BreathAngerSound); + } + + public virtual void BreathPlayAngerAnimation() + { + Animate(BreathAngerAnimation, 5, 1, true, false, 0); + } + + public virtual void BreathEffect_Callback(object state) + { + Mobile target = (Mobile)state; + + if (!target.Alive || !CanBeHarmful(target)) + return; + + BreathPlayEffectSound(); + BreathPlayEffect(target); + + Timer.DelayCall(TimeSpan.FromSeconds(BreathDamageDelay), new TimerStateCallback(BreathDamage_Callback), target); + } + + public virtual void BreathPlayEffectSound() + { + PlaySound(BreathEffectSound); + } + + public virtual void BreathPlayEffect(Mobile target) + { + Effects.SendMovingEffect(this, target, BreathEffectItemID, + BreathEffectSpeed, BreathEffectDuration, BreathEffectFixedDir, + BreathEffectExplodes, BreathEffectHue, BreathEffectRenderMode); + } + + public virtual void BreathDamage_Callback(object state) + { + Mobile target = (Mobile)state; + + if (target is BaseCreature && ((BaseCreature)target).BreathImmune) + return; + + if (CanBeHarmful(target)) + { + DoHarmful(target); + BreathDealDamage(target); + } + } + + public virtual void BreathDealDamage(Mobile target) + { + if (!Evasion.CheckSpellEvasion(target)) + { + int physDamage = BreathPhysicalDamage; + int fireDamage = BreathFireDamage; + int coldDamage = BreathColdDamage; + int poisDamage = BreathPoisonDamage; + int nrgyDamage = BreathEnergyDamage; + + if (BreathChaosDamage > 0) + { + switch (Utility.Random(5)) + { + case 0: physDamage += BreathChaosDamage; break; + case 1: fireDamage += BreathChaosDamage; break; + case 2: coldDamage += BreathChaosDamage; break; + case 3: poisDamage += BreathChaosDamage; break; + case 4: nrgyDamage += BreathChaosDamage; break; + } + } + + if (physDamage == 0 && fireDamage == 0 && coldDamage == 0 && poisDamage == 0 && nrgyDamage == 0) + { + target.Damage(BreathComputeDamage(), this);// Unresistable damage even in AOS + } + else + { + AOS.Damage(target, this, BreathComputeDamage(), physDamage, fireDamage, coldDamage, poisDamage, nrgyDamage); + } + } + } + + public virtual int BreathComputeDamage() + { + int damage = (int)(Hits * BreathDamageScalar); + + if (IsParagon) + damage = (int)(damage / Paragon.HitsBuff); + + if (damage > 200) + damage = 200; + + return damage; + } + + #endregion + + public virtual bool CanFly { get { return false; } } + + #region Spill Acid + + public void SpillAcid(int Amount) + { + SpillAcid(null, Amount); + } + + public void SpillAcid(Mobile target, int Amount) + { + if ((target != null && target.Map == null) || this.Map == null) + return; + + for (int i = 0; i < Amount; ++i) + { + Point3D loc = this.Location; + Map map = this.Map; + Item acid = NewHarmfulItem(); + + if (target != null && target.Map != null && Amount == 1) + { + loc = target.Location; + map = target.Map; + } + else + { + bool validLocation = false; + for (int j = 0; !validLocation && j < 10; ++j) + { + loc = new Point3D( + loc.X + (Utility.Random(0, 3) - 2), + loc.Y + (Utility.Random(0, 3) - 2), + loc.Z); + loc.Z = map.GetAverageZ(loc.X, loc.Y); + validLocation = map.CanFit(loc, 16, false, false); + } + } + acid.MoveToWorld(loc, map); + } + } + + /* + Solen Style, override me for other mobiles/items: + kappa+acidslime, grizzles+whatever, etc. + */ + + public virtual Item NewHarmfulItem() + { + return new PoolOfAcid(TimeSpan.FromSeconds(10), 30, 30); + } + + #endregion + + #region Flee!!! + public virtual bool CanFlee { get { return !m_Paragon; } } + + private DateTime m_EndFlee; + + public DateTime EndFleeTime + { + get { return m_EndFlee; } + set { m_EndFlee = value; } + } + + public virtual void StopFlee() + { + m_EndFlee = DateTime.MinValue; + } + + public virtual bool CheckFlee() + { + if (m_EndFlee == DateTime.MinValue) + return false; + + if (DateTime.Now >= m_EndFlee) + { + StopFlee(); + return false; + } + + return true; + } + + public virtual void BeginFlee(TimeSpan maxDuration) + { + m_EndFlee = DateTime.Now + maxDuration; + } + + #endregion + + public virtual bool IsInvulnerable { get { return false; } } + + public BaseAI AIObject { get { return m_AI; } } + + public const int MaxOwners = 5; + + public virtual OppositionGroup OppositionGroup + { + get { return null; } + } + + #region Friends + public List Friends { get { return m_Friends; } } + + public virtual bool AllowNewPetFriend + { + get { return (m_Friends == null || m_Friends.Count < 5); } + } + + public virtual bool IsPetFriend(Mobile m) + { + return (m_Friends != null && m_Friends.Contains(m)); + } + + public virtual void AddPetFriend(Mobile m) + { + if (m_Friends == null) + m_Friends = new List(); + + m_Friends.Add(m); + } + + public virtual void RemovePetFriend(Mobile m) + { + if (m_Friends != null) + m_Friends.Remove(m); + } + + public virtual bool IsFriend(Mobile m) + { + OppositionGroup g = this.OppositionGroup; + + if (g != null && g.IsEnemy(this, m)) + return false; + + if (!(m is BaseCreature)) + return false; + + BaseCreature c = (BaseCreature)m; + + return (m_iTeam == c.m_iTeam && ((m_bSummoned || m_bControlled) == (c.m_bSummoned || c.m_bControlled))/* && c.Combatant != this */); + } + + #endregion + + #region Allegiance + public virtual Ethics.Ethic EthicAllegiance { get { return null; } } + + public enum Allegiance + { + None, + Ally, + Enemy + } + + public virtual Allegiance GetFactionAllegiance(Mobile mob) + { + if (mob == null || mob.Map != Faction.Facet || FactionAllegiance == null) + return Allegiance.None; + + Faction fac = Faction.Find(mob, true); + + if (fac == null) + return Allegiance.None; + + return (fac == FactionAllegiance ? Allegiance.Ally : Allegiance.Enemy); + } + + public virtual Allegiance GetEthicAllegiance(Mobile mob) + { + if (mob == null || mob.Map != Faction.Facet || EthicAllegiance == null) + return Allegiance.None; + + Ethics.Ethic ethic = Ethics.Ethic.Find(mob, true); + + if (ethic == null) + return Allegiance.None; + + return (ethic == EthicAllegiance ? Allegiance.Ally : Allegiance.Enemy); + } + + #endregion + + public virtual bool IsEnemy(Mobile m) + { + OppositionGroup g = this.OppositionGroup; + + if (g != null && g.IsEnemy(this, m)) + return true; + + if (m is BaseGuard) + return false; + + if (GetFactionAllegiance(m) == Allegiance.Ally) + return false; + + Ethics.Ethic ourEthic = EthicAllegiance; + Ethics.Player pl = Ethics.Player.Find(m, true); + + if (pl != null && pl.IsShielded && (ourEthic == null || ourEthic == pl.Ethic)) + return false; + + if (!(m is BaseCreature) || m is Server.Engines.Quests.Haven.MilitiaFighter) + return true; + + if (TransformationSpellHelper.UnderTransformation(m, typeof(EtherealVoyageSpell))) + return false; + + if (m is PlayerMobile && ((PlayerMobile)m).HonorActive) + return false; + + BaseCreature c = (BaseCreature)m; + + if ((FightMode == FightMode.Evil && m.Karma < 0) || (c.FightMode == FightMode.Evil && Karma < 0)) + return true; + + return (m_iTeam != c.m_iTeam || ((m_bSummoned || m_bControlled) != (c.m_bSummoned || c.m_bControlled))/* || c.Combatant == this*/ ); + } + + public override string ApplyNameSuffix(string suffix) + { + if (IsParagon && !GivesMLMinorArtifact) + { + if (suffix.Length == 0) + suffix = "(Paragon)"; + else + suffix = String.Concat(suffix, " (Paragon)"); + } + + return base.ApplyNameSuffix(suffix); + } + + public virtual bool CheckControlChance(Mobile m) + { + if (GetControlChance(m) > Utility.RandomDouble()) + { + Loyalty += 1; + return true; + } + + PlaySound(GetAngerSound()); + + if (Body.IsAnimal) + Animate(10, 5, 1, true, false, 0); + else if (Body.IsMonster) + Animate(18, 5, 1, true, false, 0); + + Loyalty -= 3; + return false; + } + + public virtual bool CanBeControlledBy(Mobile m) + { + return (GetControlChance(m) > 0.0); + } + + public double GetControlChance(Mobile m) + { + return GetControlChance(m, false); + } + + public virtual double GetControlChance(Mobile m, bool useBaseSkill) + { + if (m_dMinTameSkill <= 29.1 || m_bSummoned || m.AccessLevel >= AccessLevel.GameMaster) + return 1.0; + + double dMinTameSkill = m_dMinTameSkill; + + if (dMinTameSkill > -24.9 && Server.SkillHandlers.AnimalTaming.CheckMastery(m, this)) + dMinTameSkill = -24.9; + + int taming = (int)((useBaseSkill ? m.Skills[SkillName.AnimalTaming].Base : m.Skills[SkillName.AnimalTaming].Value) * 10); + int lore = (int)((useBaseSkill ? m.Skills[SkillName.AnimalLore].Base : m.Skills[SkillName.AnimalLore].Value) * 10); + int bonus = 0, chance = 700; + + if (Core.ML) + { + int SkillBonus = taming - (int)(dMinTameSkill * 10); + int LoreBonus = lore - (int)(dMinTameSkill * 10); + + int SkillMod = 6, LoreMod = 6; + + if (SkillBonus < 0) + SkillMod = 28; + if (LoreBonus < 0) + LoreMod = 14; + + SkillBonus *= SkillMod; + LoreBonus *= LoreMod; + + bonus = (SkillBonus + LoreBonus) / 2; + } + else + { + int difficulty = (int)(dMinTameSkill * 10); + int weighted = ((taming * 4) + lore) / 5; + bonus = weighted - difficulty; + + if (bonus <= 0) + bonus *= 14; + else + bonus *= 6; + } + + chance += bonus; + + if (chance >= 0 && chance < 200) + chance = 200; + else if (chance > 990) + chance = 990; + + chance -= (MaxLoyalty - m_Loyalty) * 10; + + return ((double)chance / 1000); + } + + private static Type[] m_AnimateDeadTypes = new Type[] + { + typeof( MoundOfMaggots ), typeof( HellSteed ), typeof( SkeletalMount ), + typeof( WailingBanshee ), typeof( Wraith ), typeof( SkeletalDragon ), + typeof( LichLord ), typeof( FleshGolem ), typeof( Lich ), + typeof( SkeletalKnight ), typeof( BoneKnight ), typeof( Mummy ), + typeof( SkeletalMage ), typeof( BoneMagi ), typeof( PatchworkSkeleton ) + }; + + public virtual bool IsAnimatedDead + { + get + { + if (!Summoned) + return false; + + Type type = this.GetType(); + + bool contains = false; + + for (int i = 0; !contains && i < m_AnimateDeadTypes.Length; ++i) + contains = (type == m_AnimateDeadTypes[i]); + + return contains; + } + } + + public virtual bool IsNecroFamiliar + { + get + { + if (!Summoned) + return false; + + if (m_ControlMaster != null && SummonFamiliarSpell.Table.Contains(m_ControlMaster)) + return SummonFamiliarSpell.Table[m_ControlMaster] == this; + + return false; + } + } + + public override void Damage(int amount, Mobile from) + { + int oldHits = this.Hits; + + if (Core.AOS && !this.Summoned && this.Controlled && 0.2 > Utility.RandomDouble()) + amount = (int)(amount * BonusPetDamageScalar); + + if (Spells.Necromancy.EvilOmenSpell.TryEndEffect(this)) + amount = (int)(amount * 1.25); + + Mobile oath = Spells.Necromancy.BloodOathSpell.GetBloodOath(from); + + if (oath == this) + { + amount = (int)(amount * 1.1); + from.Damage(amount, from); + } + + base.Damage(amount, from); + + if (SubdueBeforeTame && !Controlled) + { + if ((oldHits > (this.HitsMax / 10)) && (this.Hits <= (this.HitsMax / 10))) + PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "* The creature has been beaten into subjugation! *"); + } + } + + public virtual bool DeleteCorpseOnDeath + { + get + { + return !Core.AOS && m_bSummoned; + } + } + + public override void SetLocation(Point3D newLocation, bool isTeleport) + { + base.SetLocation(newLocation, isTeleport); + + if (isTeleport && m_AI != null) + m_AI.OnTeleported(); + } + + public override void OnBeforeSpawn(Point3D location, Map m) + { + if (Paragon.CheckConvert(this, location, m)) + IsParagon = true; + + base.OnBeforeSpawn(location, m); + } + + public override ApplyPoisonResult ApplyPoison(Mobile from, Poison poison) + { + if (!Alive || IsDeadPet) + return ApplyPoisonResult.Immune; + + if (Spells.Necromancy.EvilOmenSpell.TryEndEffect(this)) + poison = PoisonImpl.IncreaseLevel(poison); + + ApplyPoisonResult result = base.ApplyPoison(from, poison); + + if (from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer) + (PoisonTimer as PoisonImpl.PoisonTimer).From = from; + + return result; + } + + public override bool CheckPoisonImmunity(Mobile from, Poison poison) + { + if (base.CheckPoisonImmunity(from, poison)) + return true; + + Poison p = PoisonImmune; + + if (m_Paragon) + p = PoisonImpl.IncreaseLevel(p); + + return (p != null && p.Level >= poison.Level); + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Loyalty + { + get + { + return m_Loyalty; + } + set + { + m_Loyalty = Math.Min(Math.Max(value, 0), MaxLoyalty); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint CurrentWayPoint + { + get + { + return m_CurrentWayPoint; + } + set + { + m_CurrentWayPoint = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public IPoint2D TargetLocation + { + get + { + return m_TargetLocation; + } + set + { + m_TargetLocation = value; + } + } + + public virtual Mobile ConstantFocus { get { return null; } } + + public virtual bool DisallowAllMoves + { + get + { + return false; + } + } + + public virtual bool InitialInnocent + { + get + { + return false; + } + } + + public virtual bool AlwaysMurderer + { + get + { + return false; + } + } + + public virtual bool AlwaysAttackable + { + get + { + return false; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int DamageMin { get { return m_DamageMin; } set { m_DamageMin = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public virtual int DamageMax { get { return m_DamageMax; } set { m_DamageMax = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public override int HitsMax + { + get + { + if (m_HitsMax > 0) + { + int value = m_HitsMax + GetStatOffset(StatType.Str); + + if (value < 1) + value = 1; + else if (value > 65000) + value = 65000; + + return value; + } + + return Str; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitsMaxSeed + { + get { return m_HitsMax; } + set { m_HitsMax = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int StamMax + { + get + { + if (m_StamMax > 0) + { + int value = m_StamMax + GetStatOffset(StatType.Dex); + + if (value < 1) + value = 1; + else if (value > 65000) + value = 65000; + + return value; + } + + return Dex; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int StamMaxSeed + { + get { return m_StamMax; } + set { m_StamMax = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int ManaMax + { + get + { + if (m_ManaMax > 0) + { + int value = m_ManaMax + GetStatOffset(StatType.Int); + + if (value < 1) + value = 1; + else if (value > 65000) + value = 65000; + + return value; + } + + return Int; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ManaMaxSeed + { + get { return m_ManaMax; } + set { m_ManaMax = value; } + } + + public virtual bool CanOpenDoors + { + get + { + return !this.Body.IsAnimal && !this.Body.IsSea; + } + } + + public virtual bool CanMoveOverObstacles + { + get + { + return Core.AOS || this.Body.IsMonster; + } + } + + public virtual bool CanDestroyObstacles + { + get + { + // to enable breaking of furniture, 'return CanMoveOverObstacles;' + return false; + } + } + + public void Unpacify() + { + BardEndTime = DateTime.Now; + BardPacified = false; + } + + private HonorContext m_ReceivedHonorContext; + + public HonorContext ReceivedHonorContext { get { return m_ReceivedHonorContext; } set { m_ReceivedHonorContext = value; } } + + + /* + + Seems this actually was removed on OSI somewhere between the original bug report and now. + We will call it ML, until we can get better information. I suspect it was on the OSI TC when + originally it taken out of RunUO, and not implmented on OSIs production shards until more + recently. Either way, this is, or was, accurate OSI behavior, and just entirely + removing it was incorrect. OSI followers were distracted by being attacked well into + AoS, at very least. + + */ + + public virtual bool CanBeDistracted { get { return !Core.ML; } } + + + public virtual void CheckDistracted(Mobile from) + { + if (Utility.RandomDouble() < .10) + { + ControlTarget = from; + ControlOrder = OrderType.Attack; + Combatant = from; + Warmode = true; + } + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (BardPacified && (HitsMax - Hits) * 0.001 > Utility.RandomDouble()) + Unpacify(); + + int disruptThreshold; + //NPCs can use bandages too! + if (!Core.AOS) + disruptThreshold = 0; + else if (from != null && from.Player) + disruptThreshold = 18; + else + disruptThreshold = 25; + + if (amount > disruptThreshold) + { + BandageContext c = BandageContext.GetContext(this); + + if (c != null) + c.Slip(); + } + + if (Confidence.IsRegenerating(this)) + Confidence.StopRegenerating(this); + + WeightOverloading.FatigueOnDamage(this, amount); + + InhumanSpeech speechType = this.SpeechType; + + if (speechType != null && !willKill) + speechType.OnDamage(this, amount); + + if (m_ReceivedHonorContext != null) + m_ReceivedHonorContext.OnTargetDamaged(from, amount); + + if (!willKill) + { + if (CanBeDistracted && ControlOrder == OrderType.Follow) + { + CheckDistracted(from); + } + } + else if (from is PlayerMobile) + { + Timer.DelayCall(TimeSpan.FromSeconds(10), new TimerCallback(((PlayerMobile)from).RecoverAmmo)); + } + + base.OnDamage(amount, from, willKill); + } + + public virtual void OnDamagedBySpell(Mobile from) + { + if (CanBeDistracted && ControlOrder == OrderType.Follow) + { + CheckDistracted(from); + } + } + + public virtual void OnHarmfulSpell(Mobile from) + { + } + + #region Alter[...]Damage From/To + + public virtual void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + } + + public virtual void AlterDamageScalarTo(Mobile target, ref double scalar) + { + } + + public virtual void AlterSpellDamageFrom(Mobile from, ref int damage) + { + } + + public virtual void AlterSpellDamageTo(Mobile to, ref int damage) + { + } + + public virtual void AlterMeleeDamageFrom(Mobile from, ref int damage) + { + } + + public virtual void AlterMeleeDamageTo(Mobile to, ref int damage) + { + } + + #endregion + + public virtual void CheckReflect(Mobile caster, ref bool reflect) + { + } + + + + public virtual void OnCarve(Mobile from, Corpse corpse, Item with) + { + int feathers = Feathers; + int wool = Wool; + int meat = Meat; + int hides = Hides; + int scales = Scales; + + if ((feathers == 0 && wool == 0 && meat == 0 && hides == 0 && scales == 0) || Summoned || IsBonded || corpse.Animated) + { + if (corpse.Animated) + corpse.SendLocalizedMessageTo(from, 500464); // Use this on corpses to carve away meat and hide + else + from.SendLocalizedMessage(500485); // You see nothing useful to carve from the corpse. + } + else + { + if (Core.ML && from.Race == Race.Human) + hides = (int)Math.Ceiling(hides * 1.1); // 10% bonus only applies to hides, ore & logs + + if (corpse.Map == Map.Felucca) + { + feathers *= 2; + wool *= 2; + hides *= 2; + + if (Core.ML) + { + meat *= 2; + scales *= 2; + } + } + + new Blood(0x122D).MoveToWorld(corpse.Location, corpse.Map); + + if (feathers != 0) + { + corpse.AddCarvedItem(new Feather(feathers), from); + from.SendLocalizedMessage(500479); // You pluck the bird. The feathers are now on the corpse. + } + + if (wool != 0) + { + corpse.AddCarvedItem(new TaintedWool(wool), from); + from.SendLocalizedMessage(500483); // You shear it, and the wool is now on the corpse. + } + + if (meat != 0) + { + if (MeatType == MeatType.Ribs) + corpse.AddCarvedItem(new RawRibs(meat), from); + else if (MeatType == MeatType.Bird) + corpse.AddCarvedItem(new RawBird(meat), from); + else if (MeatType == MeatType.LambLeg) + corpse.AddCarvedItem(new RawLambLeg(meat), from); + + from.SendLocalizedMessage(500467); // You carve some meat, which remains on the corpse. + } + + if (hides != 0) + { + Item holding = from.Weapon as Item; + int color = 0; + if (Core.AOS && (holding is SkinningKnife /* TODO: || holding is ButcherWarCleaver || with is ButcherWarCleaver */ )) + { + Item leather = null; + + if (HasSpecificHue) + { + switch (HideType) + { + case HideType.Regular: leather = new Leather(hides); break; + case HideType.Spined: leather = new SpinedLeather(hides, SpecificHue); break; + case HideType.Horned: leather = new HornedLeather(hides, SpecificHue); break; + case HideType.Barbed: leather = new BarbedLeather(hides, SpecificHue); break; + case HideType.Daemon: leather = new DaemonLeather(hides); break; + + } + } + else + { + switch (HideType) + { + case HideType.Regular: leather = new Leather(hides); break; + case HideType.Spined: leather = new SpinedLeather(hides); break; + case HideType.Horned: leather = new HornedLeather(hides); break; + case HideType.Barbed: leather = new BarbedLeather(hides); break; + case HideType.Daemon: leather = new DaemonLeather(hides); break; + } + } + if (leather != null) + { + if (!from.PlaceInBackpack(leather)) + { + corpse.DropItem(leather); + from.SendLocalizedMessage(500471); // You skin it, and the hides are now in the corpse. + } + else + { + from.SendLocalizedMessage(1073555); // You skin it and place the cut-up hides in your backpack. + } + } + } + else + { + if (HasSpecificHue) + { + if (HideType == HideType.Regular) + corpse.DropItem(new Hides(hides)); + else if (HideType == HideType.Spined) + corpse.DropItem(new SpinedHides(hides, SpecificHue)); + else if (HideType == HideType.Horned) + corpse.DropItem(new HornedHides(hides, SpecificHue)); + else if (HideType == HideType.Barbed) + corpse.DropItem(new BarbedHides(hides, SpecificHue)); + else if (HideType == HideType.Daemon) + corpse.DropItem(new DaemonHides(hides)); + } + else + { + if (HideType == HideType.Regular) + corpse.DropItem(new Hides(hides)); + else if (HideType == HideType.Spined) + corpse.DropItem(new SpinedHides(hides)); + else if (HideType == HideType.Horned) + corpse.DropItem(new HornedHides(hides)); + else if (HideType == HideType.Barbed) + corpse.DropItem(new BarbedHides(hides)); + else if (HideType == HideType.Daemon) + corpse.DropItem(new DaemonHides(hides)); + } + + + from.SendLocalizedMessage(500471); // You skin it, and the hides are now in the corpse. + } + } + + if (scales != 0) + { + ScaleType sc = this.ScaleType; + + switch (sc) + { + case ScaleType.Red: corpse.AddCarvedItem(new RedScales(scales), from); break; + case ScaleType.Yellow: corpse.AddCarvedItem(new YellowScales(scales), from); break; + case ScaleType.Black: corpse.AddCarvedItem(new BlackScales(scales), from); break; + case ScaleType.Green: corpse.AddCarvedItem(new GreenScales(scales), from); break; + case ScaleType.White: corpse.AddCarvedItem(new WhiteScales(scales), from); break; + case ScaleType.Blue: corpse.AddCarvedItem(new BlueScales(scales), from); break; + case ScaleType.All: + { + corpse.AddCarvedItem(new RedScales(scales), from); + corpse.AddCarvedItem(new YellowScales(scales), from); + corpse.AddCarvedItem(new BlackScales(scales), from); + corpse.AddCarvedItem(new GreenScales(scales), from); + corpse.AddCarvedItem(new WhiteScales(scales), from); + corpse.AddCarvedItem(new BlueScales(scales), from); + break; + } + } + + from.SendMessage("You cut away some scales, but they remain on the corpse."); + } + + corpse.Carved = true; + + if (corpse.IsCriminalAction(from)) + from.CriminalAction(true); + } + } + + public const int DefaultRangePerception = 16; + public const int OldRangePerception = 10; + + public BaseCreature(AIType ai, + FightMode mode, + int iRangePerception, + int iRangeFight, + double dActiveSpeed, + double dPassiveSpeed) + { + if (iRangePerception == OldRangePerception) + iRangePerception = DefaultRangePerception; + + m_Loyalty = MaxLoyalty; // Wonderfully Happy + + m_CurrentAI = ai; + m_DefaultAI = ai; + + m_iRangePerception = iRangePerception; + m_iRangeFight = iRangeFight; + + m_FightMode = mode; + + m_iTeam = 0; + + SpeedInfo.GetSpeeds(this, ref dActiveSpeed, ref dPassiveSpeed); + + m_dActiveSpeed = dActiveSpeed; + m_dPassiveSpeed = dPassiveSpeed; + m_dCurrentSpeed = dPassiveSpeed; + + m_bDebugAI = false; + + m_arSpellAttack = new List(); + m_arSpellDefense = new List(); + + m_bControlled = false; + m_ControlMaster = null; + m_ControlTarget = null; + m_ControlOrder = OrderType.None; + + m_bTamable = false; + + m_Owners = new List(); + + m_NextReacquireTime = DateTime.Now + ReacquireDelay; + + ChangeAIType(AI); + + InhumanSpeech speechType = this.SpeechType; + + if (speechType != null) + speechType.OnConstruct(this); + + if (IsInvulnerable && !Core.AOS) + NameHue = 0x35; + + GenerateLoot(true); + } + + public BaseCreature(Serial serial) + : base(serial) + { + m_arSpellAttack = new List(); + m_arSpellDefense = new List(); + + m_bDebugAI = false; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)18); // version + + writer.Write((int)m_CurrentAI); + writer.Write((int)m_DefaultAI); + + writer.Write((int)m_iRangePerception); + writer.Write((int)m_iRangeFight); + + writer.Write((int)m_iTeam); + + writer.Write((double)m_dActiveSpeed); + writer.Write((double)m_dPassiveSpeed); + writer.Write((double)m_dCurrentSpeed); + + writer.Write((int)m_pHome.X); + writer.Write((int)m_pHome.Y); + writer.Write((int)m_pHome.Z); + + // Version 1 + writer.Write((int)m_iRangeHome); + + int i = 0; + + writer.Write((int)m_arSpellAttack.Count); + for (i = 0; i < m_arSpellAttack.Count; i++) + { + writer.Write(m_arSpellAttack[i].ToString()); + } + + writer.Write((int)m_arSpellDefense.Count); + for (i = 0; i < m_arSpellDefense.Count; i++) + { + writer.Write(m_arSpellDefense[i].ToString()); + } + + // Version 2 + writer.Write((int)m_FightMode); + + writer.Write((bool)m_bControlled); + writer.Write((Mobile)m_ControlMaster); + writer.Write((Mobile)m_ControlTarget); + writer.Write((Point3D)m_ControlDest); + writer.Write((int)m_ControlOrder); + writer.Write((double)m_dMinTameSkill); + // Removed in version 9 + //writer.Write( (double) m_dMaxTameSkill ); + writer.Write((bool)m_bTamable); + writer.Write((bool)m_bSummoned); + + if (m_bSummoned) + writer.WriteDeltaTime(m_SummonEnd); + + writer.Write((int)m_iControlSlots); + + // Version 3 + writer.Write((int)m_Loyalty); + + // Version 4 + writer.Write(m_CurrentWayPoint); + + // Verison 5 + writer.Write(m_SummonMaster); + + // Version 6 + writer.Write((int)m_HitsMax); + writer.Write((int)m_StamMax); + writer.Write((int)m_ManaMax); + writer.Write((int)m_DamageMin); + writer.Write((int)m_DamageMax); + + // Version 7 + writer.Write((int)m_PhysicalResistance); + writer.Write((int)m_PhysicalDamage); + + writer.Write((int)m_FireResistance); + writer.Write((int)m_FireDamage); + + writer.Write((int)m_ColdResistance); + writer.Write((int)m_ColdDamage); + + writer.Write((int)m_PoisonResistance); + writer.Write((int)m_PoisonDamage); + + writer.Write((int)m_EnergyResistance); + writer.Write((int)m_EnergyDamage); + + // Version 8 + writer.Write(m_Owners, true); + + // Version 10 + writer.Write((bool)m_IsDeadPet); + writer.Write((bool)m_IsBonded); + writer.Write((DateTime)m_BondingBegin); + writer.Write((DateTime)m_OwnerAbandonTime); + + // Version 11 + writer.Write((bool)m_HasGeneratedLoot); + + // Version 12 + writer.Write((bool)m_Paragon); + + // Version 13 + writer.Write((bool)(m_Friends != null && m_Friends.Count > 0)); + + if (m_Friends != null && m_Friends.Count > 0) + writer.Write(m_Friends, true); + + // Version 14 + writer.Write((bool)m_RemoveIfUntamed); + writer.Write((int)m_RemoveStep); + + // Version 17 + if (IsStabled || (Controlled && ControlMaster != null)) + writer.Write(TimeSpan.Zero); + else + writer.Write(DeleteTimeLeft); + + // Version 18 + writer.Write(m_CorpseNameOverride); + } + + private static double[] m_StandardActiveSpeeds = new double[] + { + 0.175, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5, 0.6, 0.8 + }; + + private static double[] m_StandardPassiveSpeeds = new double[] + { + 0.350, 0.2, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.6, 2.0 + }; + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_CurrentAI = (AIType)reader.ReadInt(); + m_DefaultAI = (AIType)reader.ReadInt(); + + m_iRangePerception = reader.ReadInt(); + m_iRangeFight = reader.ReadInt(); + + m_iTeam = reader.ReadInt(); + + m_dActiveSpeed = reader.ReadDouble(); + m_dPassiveSpeed = reader.ReadDouble(); + m_dCurrentSpeed = reader.ReadDouble(); + + if (m_iRangePerception == OldRangePerception) + m_iRangePerception = DefaultRangePerception; + + m_pHome.X = reader.ReadInt(); + m_pHome.Y = reader.ReadInt(); + m_pHome.Z = reader.ReadInt(); + + if (version >= 1) + { + m_iRangeHome = reader.ReadInt(); + + int i, iCount; + + iCount = reader.ReadInt(); + for (i = 0; i < iCount; i++) + { + string str = reader.ReadString(); + Type type = Type.GetType(str); + + if (type != null) + { + m_arSpellAttack.Add(type); + } + } + + iCount = reader.ReadInt(); + for (i = 0; i < iCount; i++) + { + string str = reader.ReadString(); + Type type = Type.GetType(str); + + if (type != null) + { + m_arSpellDefense.Add(type); + } + } + } + else + { + m_iRangeHome = 0; + } + + if (version >= 2) + { + m_FightMode = (FightMode)reader.ReadInt(); + + m_bControlled = reader.ReadBool(); + m_ControlMaster = reader.ReadMobile(); + m_ControlTarget = reader.ReadMobile(); + m_ControlDest = reader.ReadPoint3D(); + m_ControlOrder = (OrderType)reader.ReadInt(); + + m_dMinTameSkill = reader.ReadDouble(); + + if (version < 9) + reader.ReadDouble(); + + m_bTamable = reader.ReadBool(); + m_bSummoned = reader.ReadBool(); + + if (m_bSummoned) + { + m_SummonEnd = reader.ReadDeltaTime(); + new UnsummonTimer(m_ControlMaster, this, m_SummonEnd - DateTime.Now).Start(); + } + + m_iControlSlots = reader.ReadInt(); + } + else + { + m_FightMode = FightMode.Closest; + + m_bControlled = false; + m_ControlMaster = null; + m_ControlTarget = null; + m_ControlOrder = OrderType.None; + } + + if (version >= 3) + m_Loyalty = reader.ReadInt(); + else + m_Loyalty = MaxLoyalty; // Wonderfully Happy + + if (version >= 4) + m_CurrentWayPoint = reader.ReadItem() as WayPoint; + + if (version >= 5) + m_SummonMaster = reader.ReadMobile(); + + if (version >= 6) + { + m_HitsMax = reader.ReadInt(); + m_StamMax = reader.ReadInt(); + m_ManaMax = reader.ReadInt(); + m_DamageMin = reader.ReadInt(); + m_DamageMax = reader.ReadInt(); + } + + if (version >= 7) + { + m_PhysicalResistance = reader.ReadInt(); + m_PhysicalDamage = reader.ReadInt(); + + m_FireResistance = reader.ReadInt(); + m_FireDamage = reader.ReadInt(); + + m_ColdResistance = reader.ReadInt(); + m_ColdDamage = reader.ReadInt(); + + m_PoisonResistance = reader.ReadInt(); + m_PoisonDamage = reader.ReadInt(); + + m_EnergyResistance = reader.ReadInt(); + m_EnergyDamage = reader.ReadInt(); + } + + if (version >= 8) + m_Owners = reader.ReadStrongMobileList(); + else + m_Owners = new List(); + + if (version >= 10) + { + m_IsDeadPet = reader.ReadBool(); + m_IsBonded = reader.ReadBool(); + m_BondingBegin = reader.ReadDateTime(); + m_OwnerAbandonTime = reader.ReadDateTime(); + } + + if (version >= 11) + m_HasGeneratedLoot = reader.ReadBool(); + else + m_HasGeneratedLoot = true; + + if (version >= 12) + m_Paragon = reader.ReadBool(); + else + m_Paragon = false; + + if (version >= 13 && reader.ReadBool()) + m_Friends = reader.ReadStrongMobileList(); + else if (version < 13 && m_ControlOrder >= OrderType.Unfriend) + ++m_ControlOrder; + + if (version < 16 && Loyalty != MaxLoyalty) + Loyalty *= 10; + + double activeSpeed = m_dActiveSpeed; + double passiveSpeed = m_dPassiveSpeed; + + SpeedInfo.GetSpeeds(this, ref activeSpeed, ref passiveSpeed); + + bool isStandardActive = false; + for (int i = 0; !isStandardActive && i < m_StandardActiveSpeeds.Length; ++i) + isStandardActive = (m_dActiveSpeed == m_StandardActiveSpeeds[i]); + + bool isStandardPassive = false; + for (int i = 0; !isStandardPassive && i < m_StandardPassiveSpeeds.Length; ++i) + isStandardPassive = (m_dPassiveSpeed == m_StandardPassiveSpeeds[i]); + + if (isStandardActive && m_dCurrentSpeed == m_dActiveSpeed) + m_dCurrentSpeed = activeSpeed; + else if (isStandardPassive && m_dCurrentSpeed == m_dPassiveSpeed) + m_dCurrentSpeed = passiveSpeed; + + if (isStandardActive && !m_Paragon) + m_dActiveSpeed = activeSpeed; + + if (isStandardPassive && !m_Paragon) + m_dPassiveSpeed = passiveSpeed; + + if (version >= 14) + { + m_RemoveIfUntamed = reader.ReadBool(); + m_RemoveStep = reader.ReadInt(); + } + + TimeSpan deleteTime = TimeSpan.Zero; + + if (version >= 17) + deleteTime = reader.ReadTimeSpan(); + + if (deleteTime > TimeSpan.Zero || LastOwner != null && !Controlled && !IsStabled) + { + if (deleteTime == TimeSpan.Zero) + deleteTime = TimeSpan.FromDays(3.0); + + m_DeleteTimer = new DeleteTimer(this, deleteTime); + m_DeleteTimer.Start(); + } + + if (version >= 18) + m_CorpseNameOverride = reader.ReadString(); + + if (version <= 14 && m_Paragon && Hue == 0x31) + { + Hue = Paragon.Hue; //Paragon hue fixed, should now be 0x501. + } + + if (Core.AOS && NameHue == 0x35) + NameHue = -1; + + CheckStatTimers(); + + ChangeAIType(m_CurrentAI); + + AddFollowers(); + + if (IsAnimatedDead) + Spells.Necromancy.AnimateDeadSpell.Register(m_SummonMaster, this); + } + + public virtual bool IsHumanInTown() + { + return (Body.IsHuman && Region.IsPartOf(typeof(Regions.GuardedRegion))); + } + + public virtual bool CheckGold(Mobile from, Item dropped) + { + if (dropped is Gold) + return OnGoldGiven(from, (Gold)dropped); + + return false; + } + + public virtual bool OnGoldGiven(Mobile from, Gold dropped) + { + if (CheckTeachingMatch(from)) + { + if (Teach(m_Teaching, from, dropped.Amount, true)) + { + dropped.Delete(); + return true; + } + } + else if (IsHumanInTown()) + { + Direction = GetDirectionTo(from); + + int oldSpeechHue = this.SpeechHue; + + this.SpeechHue = 0x23F; + SayTo(from, "Thou art giving me gold?"); + + if (dropped.Amount >= 400) + SayTo(from, "'Tis a noble gift."); + else + SayTo(from, "Money is always welcome."); + + this.SpeechHue = 0x3B2; + SayTo(from, 501548); // I thank thee. + + this.SpeechHue = oldSpeechHue; + + dropped.Delete(); + return true; + } + + return false; + } + + public override bool ShouldCheckStatTimers { get { return false; } } + + #region Food + private static Type[] m_Eggs = new Type[] + { + typeof( FriedEggs ), typeof( Eggs ) + }; + + private static Type[] m_Fish = new Type[] + { + typeof( FishSteak ), typeof( RawFishSteak ) + }; + + private static Type[] m_GrainsAndHay = new Type[] + { + typeof( BreadLoaf ), typeof( FrenchBread ), typeof( SheafOfHay ) + }; + + private static Type[] m_Meat = new Type[] + { + /* Cooked */ + typeof( Bacon ), typeof( CookedBird ), typeof( Sausage ), + typeof( Ham ), typeof( Ribs ), typeof( LambLeg ), + typeof( ChickenLeg ), + + /* Uncooked */ + typeof( RawBird ), typeof( RawRibs ), typeof( RawLambLeg ), + typeof( RawChickenLeg ), + + /* Body Parts */ + typeof( Head ), typeof( LeftArm ), typeof( LeftLeg ), + typeof( Torso ), typeof( RightArm ), typeof( RightLeg ) + }; + + private static Type[] m_FruitsAndVegies = new Type[] + { + typeof( HoneydewMelon ), typeof( YellowGourd ), typeof( GreenGourd ), + typeof( Banana ), typeof( Bananas ), typeof( Lemon ), typeof( Lime ), + typeof( Dates ), typeof( Grapes ), typeof( Peach ), typeof( Pear ), + typeof( Apple ), typeof( Watermelon ), typeof( Squash ), + typeof( Cantaloupe ), typeof( Carrot ), typeof( Cabbage ), + typeof( Onion ), typeof( Lettuce ), typeof( Pumpkin ) + }; + + private static Type[] m_Gold = new Type[] + { + // white wyrms eat gold.. + typeof( Gold ) + }; + + public virtual bool CheckFoodPreference(Item f) + { + if (CheckFoodPreference(f, FoodType.Eggs, m_Eggs)) + return true; + + if (CheckFoodPreference(f, FoodType.Fish, m_Fish)) + return true; + + if (CheckFoodPreference(f, FoodType.GrainsAndHay, m_GrainsAndHay)) + return true; + + if (CheckFoodPreference(f, FoodType.Meat, m_Meat)) + return true; + + if (CheckFoodPreference(f, FoodType.FruitsAndVegies, m_FruitsAndVegies)) + return true; + + if (CheckFoodPreference(f, FoodType.Gold, m_Gold)) + return true; + + return false; + } + + public virtual bool CheckFoodPreference(Item fed, FoodType type, Type[] types) + { + if ((FavoriteFood & type) == 0) + return false; + + Type fedType = fed.GetType(); + bool contains = false; + + for (int i = 0; !contains && i < types.Length; ++i) + contains = (fedType == types[i]); + + return contains; + } + + public virtual bool CheckFeed(Mobile from, Item dropped) + { + if (!IsDeadPet && Controlled && (ControlMaster == from || IsPetFriend(from))) + { + Item f = dropped; + + if (CheckFoodPreference(f)) + { + int amount = f.Amount; + + if (amount > 0) + { + int stamGain; + + if (f is Gold) + stamGain = amount - 50; + else + stamGain = (amount * 15) - 50; + + if (stamGain > 0) + Stam += stamGain; + + if (Core.SE) + { + if (m_Loyalty < MaxLoyalty) + { + m_Loyalty = MaxLoyalty; + } + } + else + { + for (int i = 0; i < amount; ++i) + { + if (m_Loyalty < MaxLoyalty && 0.5 >= Utility.RandomDouble()) + { + m_Loyalty += 10; + } + } + } + + /* if ( happier )*/ + // looks like in OSI pets say they are happier even if they are at maximum loyalty + SayTo(from, 502060); // Your pet looks happier. + + if (Body.IsAnimal) + Animate(3, 5, 1, true, false, 0); + else if (Body.IsMonster) + Animate(17, 5, 1, true, false, 0); + + if (IsBondable && !IsBonded) + { + Mobile master = m_ControlMaster; + + if (master != null && master == from) //So friends can't start the bonding process + { + if (m_dMinTameSkill <= 29.1 || master.Skills[SkillName.AnimalTaming].Base >= m_dMinTameSkill || OverrideBondingReqs() || (Core.ML && master.Skills[SkillName.AnimalTaming].Value >= m_dMinTameSkill)) + { + if (BondingBegin == DateTime.MinValue) + { + BondingBegin = DateTime.Now; + } + else if ((BondingBegin + BondingDelay) <= DateTime.Now) + { + IsBonded = true; + BondingBegin = DateTime.MinValue; + from.SendLocalizedMessage(1049666); // Your pet has bonded with you! + } + } + else if (Core.ML) + { + from.SendLocalizedMessage(1075268); // Your pet cannot form a bond with you until your animal taming ability has risen. + } + } + } + + dropped.Delete(); + return true; + } + } + } + + return false; + } + + #endregion + + public virtual bool OverrideBondingReqs() + { + return false; + } + + public virtual bool CanAngerOnTame { get { return false; } } + + #region OnAction[...] + + public virtual void OnActionWander() + { + } + + public virtual void OnActionCombat() + { + } + + public virtual void OnActionGuard() + { + } + + public virtual void OnActionFlee() + { + } + + public virtual void OnActionInteract() + { + } + + public virtual void OnActionBackoff() + { + } + + #endregion + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (CheckFeed(from, dropped)) + return true; + else if (CheckGold(from, dropped)) + return true; + + // Note: Yes, this happens for all questers (regardless of type, e.g. escorts), + // even if they can't offer you anything at the moment + if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile) + { + MLQuestSystem.Tell(this, (PlayerMobile)from, 1074893); // You need to mark your quest items so I don't take the wrong object. Then speak to me. + return false; + } + + return base.OnDragDrop(from, dropped); + } + + protected virtual BaseAI ForcedAI { get { return null; } } + + public void ChangeAIType(AIType NewAI) + { + if (m_AI != null) + m_AI.m_Timer.Stop(); + + if (ForcedAI != null) + { + m_AI = ForcedAI; + return; + } + + m_AI = null; + + switch (NewAI) + { + case AIType.AI_Melee: + m_AI = new MeleeAI(this); + break; + case AIType.AI_Animal: + m_AI = new AnimalAI(this); + break; + case AIType.AI_Berserk: + m_AI = new BerserkAI(this); + break; + case AIType.AI_Archer: + m_AI = new ArcherAI(this); + break; + case AIType.AI_Healer: + m_AI = new HealerAI(this); + break; + case AIType.AI_Vendor: + m_AI = new VendorAI(this); + break; + case AIType.AI_Mage: + m_AI = new MageAI(this); + break; + case AIType.AI_Predator: + //m_AI = new PredatorAI(this); + m_AI = new MeleeAI(this); + break; + case AIType.AI_Thief: + m_AI = new ThiefAI(this); + break; + // >>> [2nd change of 2] + // ERICA'S ORC SCOUT and NINJA + case AIType.AI_OrcScout: + m_AI = new OrcScoutAI(this); + break; + case AIType.AI_Ninja: + m_AI = new NinjaAI(this); + break; + // PAPPA SMURF's Spellbinder + case AIType.AI_Spellbinder: + m_AI = new SpellbinderAI(this); + break; + // end 2nd + // Scriptiz : ajout de l'AI pour le POMI + case AIType.AI_Pomi: + m_AI = new PomiAI(this); + break; + //Myron : ajout de l'AI pour les gardes PNJ + case AIType.AI_VivreGuard: + m_AI = new VivreGuardAI(this); + break; + // Vinds : ajout de l'AI assassin + case AIType.AI_Assassin: + m_AI = new AssassinAI(this); + break; + } + + } + + public void ChangeAIToDefault() + { + ChangeAIType(m_DefaultAI); + } + + [CommandProperty(AccessLevel.GameMaster)] + public AIType AI + { + get + { + return m_CurrentAI; + } + set + { + m_CurrentAI = value; + + if (m_CurrentAI == AIType.AI_Use_Default) + { + m_CurrentAI = m_DefaultAI; + } + + ChangeAIType(m_CurrentAI); + } + } + + [CommandProperty(AccessLevel.Administrator)] + public bool Debug + { + get + { + return m_bDebugAI; + } + set + { + m_bDebugAI = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Team + { + get + { + return m_iTeam; + } + set + { + m_iTeam = value; + + OnTeamChange(); + } + } + + public virtual void OnTeamChange() + { + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile FocusMob + { + get + { + return m_FocusMob; + } + set + { + m_FocusMob = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public FightMode FightMode + { + get + { + return m_FightMode; + } + set + { + m_FightMode = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RangePerception + { + get + { + return m_iRangePerception; + } + set + { + m_iRangePerception = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RangeFight + { + get + { + return m_iRangeFight; + } + set + { + m_iRangeFight = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int RangeHome + { + get + { + return m_iRangeHome; + } + set + { + m_iRangeHome = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double ActiveSpeed + { + get + { + return m_dActiveSpeed; + } + set + { + m_dActiveSpeed = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double PassiveSpeed + { + get + { + return m_dPassiveSpeed; + } + set + { + m_dPassiveSpeed = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double CurrentSpeed + { + get + { + if (m_TargetLocation != null) + return 0.3; + + return m_dCurrentSpeed; + } + set + { + if (m_dCurrentSpeed != value) + { + m_dCurrentSpeed = value; + + if (m_AI != null) + m_AI.OnCurrentSpeedChanged(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D Home + { + get + { + return m_pHome; + } + set + { + m_pHome = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Controlled + { + get + { + return m_bControlled; + } + set + { + if (m_bControlled == value) + return; + + m_bControlled = value; + Delta(MobileDelta.Noto); + + InvalidateProperties(); + } + } + + public override void RevealingAction() + { + Spells.Sixth.InvisibilitySpell.RemoveTimer(this); + + base.RevealingAction(); + } + + public void RemoveFollowers() + { + if (m_ControlMaster != null) + { + m_ControlMaster.Followers -= ControlSlots; + if (m_ControlMaster is PlayerMobile) + { + ((PlayerMobile)m_ControlMaster).AllFollowers.Remove(this); + if (((PlayerMobile)m_ControlMaster).AutoStabled.Contains(this)) + ((PlayerMobile)m_ControlMaster).AutoStabled.Remove(this); + } + } + else if (m_SummonMaster != null) + { + m_SummonMaster.Followers -= ControlSlots; + if (m_SummonMaster is PlayerMobile) + { + ((PlayerMobile)m_SummonMaster).AllFollowers.Remove(this); + } + } + + if (m_ControlMaster != null && m_ControlMaster.Followers < 0) + m_ControlMaster.Followers = 0; + + if (m_SummonMaster != null && m_SummonMaster.Followers < 0) + m_SummonMaster.Followers = 0; + } + + public void AddFollowers() + { + if (m_ControlMaster != null) + { + m_ControlMaster.Followers += ControlSlots; + if (m_ControlMaster is PlayerMobile) + { + ((PlayerMobile)m_ControlMaster).AllFollowers.Add(this); + } + } + else if (m_SummonMaster != null) + { + m_SummonMaster.Followers += ControlSlots; + if (m_SummonMaster is PlayerMobile) + { + ((PlayerMobile)m_SummonMaster).AllFollowers.Add(this); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile ControlMaster + { + get + { + return m_ControlMaster; + } + set + { + if (m_ControlMaster == value || this == value) + return; + + RemoveFollowers(); + m_ControlMaster = value; + AddFollowers(); + if (m_ControlMaster != null) + StopDeleteTimer(); + + Delta(MobileDelta.Noto); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile SummonMaster + { + get + { + return m_SummonMaster; + } + set + { + if (m_SummonMaster == value || this == value) + return; + + RemoveFollowers(); + m_SummonMaster = value; + AddFollowers(); + + Delta(MobileDelta.Noto); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile ControlTarget + { + get + { + return m_ControlTarget; + } + set + { + m_ControlTarget = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D ControlDest + { + get + { + return m_ControlDest; + } + set + { + m_ControlDest = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public OrderType ControlOrder + { + get + { + return m_ControlOrder; + } + set + { + m_ControlOrder = value; + + if (m_AI != null) + m_AI.OnCurrentOrderChanged(); + + InvalidateProperties(); + + if (m_ControlMaster != null) + m_ControlMaster.InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool BardProvoked + { + get + { + return m_bBardProvoked; + } + set + { + m_bBardProvoked = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool BardPacified + { + get + { + return m_bBardPacified; + } + set + { + m_bBardPacified = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile BardMaster + { + get + { + return m_bBardMaster; + } + set + { + m_bBardMaster = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile BardTarget + { + get + { + return m_bBardTarget; + } + set + { + m_bBardTarget = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime BardEndTime + { + get + { + return m_timeBardEnd; + } + set + { + m_timeBardEnd = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double MinTameSkill + { + get + { + return m_dMinTameSkill; + } + set + { + m_dMinTameSkill = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Tamable + { + get + { + return m_bTamable && !m_Paragon; + } + set + { + m_bTamable = value; + } + } + + [CommandProperty(AccessLevel.Administrator)] + public bool Summoned + { + get + { + return m_bSummoned; + } + set + { + if (m_bSummoned == value) + return; + + m_NextReacquireTime = DateTime.Now; + + m_bSummoned = value; + Delta(MobileDelta.Noto); + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.Administrator)] + public int ControlSlots + { + get + { + return m_iControlSlots; + } + set + { + m_iControlSlots = value; + } + } + + public virtual bool NoHouseRestrictions { get { return false; } } + public virtual bool IsHouseSummonable { get { return false; } } + + #region Corpse Resources + public virtual int Feathers { get { return 0; } } + public virtual int Wool { get { return 0; } } + + public virtual MeatType MeatType { get { return MeatType.Ribs; } } + public virtual int Meat { get { return 0; } } + + public virtual int Hides { get { return 0; } } + public virtual HideType HideType { get { return HideType.Regular; } } + + public virtual int Scales { get { return 0; } } + public virtual ScaleType ScaleType { get { return ScaleType.Red; } } + #endregion + + public virtual bool AutoDispel { get { return false; } } + public virtual double AutoDispelChance { get { return ((Core.SE) ? .10 : 1.0); } } + + public virtual bool IsScaryToPets { get { return false; } } + public virtual bool IsScaredOfScaryThings { get { return true; } } + + public virtual bool CanRummageCorpses { get { return false; } } + + public virtual void OnGotMeleeAttack(Mobile attacker) + { + if (AutoDispel && attacker is BaseCreature && ((BaseCreature)attacker).IsDispellable && AutoDispelChance > Utility.RandomDouble()) + Dispel(attacker); + } + + public virtual void Dispel(Mobile m) + { + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042); + Effects.PlaySound(m, m.Map, 0x201); + + m.Delete(); + } + + public virtual bool DeleteOnRelease { get { return m_bSummoned; } } + + public virtual void OnGaveMeleeAttack(Mobile defender) + { + Poison p = HitPoison; + + if (m_Paragon) + p = PoisonImpl.IncreaseLevel(p); + + if (p != null && HitPoisonChance >= Utility.RandomDouble()) + { + defender.ApplyPoison(this, p); + + if (Controlled) + CheckSkill(SkillName.Poisoning, 0, Skills[SkillName.Poisoning].Cap); + } + + if (AutoDispel && defender is BaseCreature && ((BaseCreature)defender).IsDispellable && AutoDispelChance > Utility.RandomDouble()) + Dispel(defender); + } + + public override void OnAfterDelete() + { + if (m_AI != null) + { + if (m_AI.m_Timer != null) + m_AI.m_Timer.Stop(); + + m_AI = null; + } + + if (m_DeleteTimer != null) + { + m_DeleteTimer.Stop(); + m_DeleteTimer = null; + } + + FocusMob = null; + + if (IsAnimatedDead) + Spells.Necromancy.AnimateDeadSpell.Unregister(m_SummonMaster, this); + + if (MLQuestSystem.Enabled) + MLQuestSystem.HandleDeletion(this); + + base.OnAfterDelete(); + } + + public void DebugSay(string text) + { + if (m_bDebugAI) + this.PublicOverheadMessage(MessageType.Regular, 41, false, text); + } + + public void DebugSay(string format, params object[] args) + { + if (m_bDebugAI) + this.PublicOverheadMessage(MessageType.Regular, 41, false, String.Format(format, args)); + } + + /* + * This function can be overriden.. so a "Strongest" mobile, can have a different definition depending + * on who check for value + * -Could add a FightMode.Prefered + * + */ + + public virtual double GetFightModeRanking(Mobile m, FightMode acqType, bool bPlayerOnly) + { + if ((bPlayerOnly && m.Player) || !bPlayerOnly) + { + switch (acqType) + { + case FightMode.Strongest: + return (m.Skills[SkillName.Tactics].Value + m.Str); //returns strongest mobile + + case FightMode.Weakest: + return -m.Hits; // returns weakest mobile + + default: + return -GetDistanceToSqrt(m); // returns closest mobile + } + } + else + { + return double.MinValue; + } + } + + // Turn, - for left, + for right + // Basic for now, needs work + public virtual void Turn(int iTurnSteps) + { + int v = (int)Direction; + + Direction = (Direction)((((v & 0x7) + iTurnSteps) & 0x7) | (v & 0x80)); + } + + public virtual void TurnInternal(int iTurnSteps) + { + int v = (int)Direction; + + SetDirection((Direction)((((v & 0x7) + iTurnSteps) & 0x7) | (v & 0x80))); + } + + public bool IsHurt() + { + return (Hits != HitsMax); + } + + public double GetHomeDistance() + { + return GetDistanceToSqrt(m_pHome); + } + + public virtual int GetTeamSize(int iRange) + { + int iCount = 0; + + foreach (Mobile m in this.GetMobilesInRange(iRange)) + { + if (m is BaseCreature) + { + if (((BaseCreature)m).Team == Team) + { + if (!m.Deleted) + { + if (m != this) + { + if (CanSee(m)) + { + iCount++; + } + } + } + } + } + } + + return iCount; + } + + private class TameEntry : ContextMenuEntry + { + private BaseCreature m_Mobile; + + public TameEntry(Mobile from, BaseCreature creature) + : base(6130, 6) + { + m_Mobile = creature; + + Enabled = Enabled && (from.Female ? creature.AllowFemaleTamer : creature.AllowMaleTamer); + } + + public override void OnClick() + { + if (!Owner.From.CheckAlive()) + return; + + Owner.From.TargetLocked = true; + SkillHandlers.AnimalTaming.DisableMessage = true; + + if (Owner.From.UseSkill(SkillName.AnimalTaming)) + Owner.From.Target.Invoke(Owner.From, m_Mobile); + + SkillHandlers.AnimalTaming.DisableMessage = false; + Owner.From.TargetLocked = false; + } + } + + #region Teaching + public virtual bool CanTeach { get { return false; } } + + public virtual bool CheckTeach(SkillName skill, Mobile from) + { + if (!CanTeach) + return false; + + if (skill == SkillName.Stealth && from.Skills[SkillName.Hiding].Base < Stealth.HidingRequirement) + return false; + + if (skill == SkillName.RemoveTrap && (from.Skills[SkillName.Lockpicking].Base < 50.0 || from.Skills[SkillName.DetectHidden].Base < 50.0)) + return false; + + if (!Core.AOS && (skill == SkillName.Focus || skill == SkillName.Chivalry || skill == SkillName.Necromancy)) + return false; + + return true; + } + + public enum TeachResult + { + Success, + Failure, + KnowsMoreThanMe, + KnowsWhatIKnow, + SkillNotRaisable, + NotEnoughFreePoints + } + + public virtual TeachResult CheckTeachSkills(SkillName skill, Mobile m, int maxPointsToLearn, ref int pointsToLearn, bool doTeach) + { + if (!CheckTeach(skill, m) || !m.CheckAlive()) + return TeachResult.Failure; + + Skill ourSkill = Skills[skill]; + Skill theirSkill = m.Skills[skill]; + + if (ourSkill == null || theirSkill == null) + return TeachResult.Failure; + + int baseToSet = ourSkill.BaseFixedPoint / 3; + + if (baseToSet > 420) + baseToSet = 420; + else if (baseToSet < 200) + return TeachResult.Failure; + + if (baseToSet > theirSkill.CapFixedPoint) + baseToSet = theirSkill.CapFixedPoint; + + pointsToLearn = baseToSet - theirSkill.BaseFixedPoint; + + if (maxPointsToLearn > 0 && pointsToLearn > maxPointsToLearn) + { + pointsToLearn = maxPointsToLearn; + baseToSet = theirSkill.BaseFixedPoint + pointsToLearn; + } + + if (pointsToLearn < 0) + return TeachResult.KnowsMoreThanMe; + + if (pointsToLearn == 0) + return TeachResult.KnowsWhatIKnow; + + if (theirSkill.Lock != SkillLock.Up) + return TeachResult.SkillNotRaisable; + + int freePoints = m.Skills.Cap - m.Skills.Total; + int freeablePoints = 0; + + if (freePoints < 0) + freePoints = 0; + + for (int i = 0; (freePoints + freeablePoints) < pointsToLearn && i < m.Skills.Length; ++i) + { + Skill sk = m.Skills[i]; + + if (sk == theirSkill || sk.Lock != SkillLock.Down) + continue; + + freeablePoints += sk.BaseFixedPoint; + } + + if ((freePoints + freeablePoints) == 0) + return TeachResult.NotEnoughFreePoints; + + if ((freePoints + freeablePoints) < pointsToLearn) + { + pointsToLearn = freePoints + freeablePoints; + baseToSet = theirSkill.BaseFixedPoint + pointsToLearn; + } + + if (doTeach) + { + int need = pointsToLearn - freePoints; + + for (int i = 0; need > 0 && i < m.Skills.Length; ++i) + { + Skill sk = m.Skills[i]; + + if (sk == theirSkill || sk.Lock != SkillLock.Down) + continue; + + if (sk.BaseFixedPoint < need) + { + need -= sk.BaseFixedPoint; + sk.BaseFixedPoint = 0; + } + else + { + sk.BaseFixedPoint -= need; + need = 0; + } + } + + /* Sanity check */ + if (baseToSet > theirSkill.CapFixedPoint || (m.Skills.Total - theirSkill.BaseFixedPoint + baseToSet) > m.Skills.Cap) + return TeachResult.NotEnoughFreePoints; + + theirSkill.BaseFixedPoint = baseToSet; + } + + return TeachResult.Success; + } + + public virtual bool CheckTeachingMatch(Mobile m) + { + if (m_Teaching == (SkillName)(-1)) + return false; + + if (m is PlayerMobile) + return (((PlayerMobile)m).Learning == m_Teaching); + + return true; + } + + private SkillName m_Teaching = (SkillName)(-1); + + public virtual bool Teach(SkillName skill, Mobile m, int maxPointsToLearn, bool doTeach) + { + int pointsToLearn = 0; + TeachResult res = CheckTeachSkills(skill, m, maxPointsToLearn, ref pointsToLearn, doTeach); + + switch (res) + { + case TeachResult.KnowsMoreThanMe: + { + Say(501508); // I cannot teach thee, for thou knowest more than I! + break; + } + case TeachResult.KnowsWhatIKnow: + { + Say(501509); // I cannot teach thee, for thou knowest all I can teach! + break; + } + case TeachResult.NotEnoughFreePoints: + case TeachResult.SkillNotRaisable: + { + // Make sure this skill is marked to raise. If you are near the skill cap (700 points) you may need to lose some points in another skill first. + m.SendLocalizedMessage(501510, "", 0x22); + break; + } + case TeachResult.Success: + { + if (doTeach) + { + Say(501539); // Let me show thee something of how this is done. + m.SendLocalizedMessage(501540); // Your skill level increases. + + m_Teaching = (SkillName)(-1); + + if (m is PlayerMobile) + ((PlayerMobile)m).Learning = (SkillName)(-1); + } + else + { + // I will teach thee all I know, if paid the amount in full. The price is: + Say(1019077, AffixType.Append, String.Format(" {0}", pointsToLearn), ""); + Say(1043108); // For less I shall teach thee less. + + m_Teaching = skill; + + if (m is PlayerMobile) + ((PlayerMobile)m).Learning = skill; + } + + return true; + } + } + + return false; + } + + #endregion + + public override void AggressiveAction(Mobile aggressor, bool criminal) + { + base.AggressiveAction(aggressor, criminal); + + if (this.ControlMaster != null) + if (NotorietyHandlers.CheckAggressor(this.ControlMaster.Aggressors, aggressor)) + aggressor.Aggressors.Add(AggressorInfo.Create(this, aggressor, true)); + + OrderType ct = m_ControlOrder; + + if (m_AI != null) + { + if (!Core.ML || (ct != OrderType.Follow && ct != OrderType.Stop && ct != OrderType.Stay)) + { + m_AI.OnAggressiveAction(aggressor); + } + else + { + DebugSay("I'm being attacked but my master told me not to fight."); + Warmode = false; + return; + } + } + + StopFlee(); + + ForceReacquire(); + + if (!IsEnemy(aggressor)) + { + Ethics.Player pl = Ethics.Player.Find(aggressor, true); + + if (pl != null && pl.IsShielded) + pl.FinishShield(); + } + + if (aggressor.ChangingCombatant && (m_bControlled || m_bSummoned) && (ct == OrderType.Come || (!Core.ML && ct == OrderType.Stay) || ct == OrderType.Stop || ct == OrderType.None || ct == OrderType.Follow)) + { + ControlTarget = aggressor; + ControlOrder = OrderType.Attack; + } + else if (Combatant == null && !m_bBardPacified) + { + Warmode = true; + Combatant = aggressor; + } + } + + public override bool OnMoveOver(Mobile m) + { + if (m is BaseCreature && !((BaseCreature)m).Controlled) + return (!Alive || !m.Alive || IsDeadBondedPet || m.IsDeadBondedPet) || (Hidden && AccessLevel > AccessLevel.Player); + + #region Dueling + if (Region.IsPartOf(typeof(Engines.ConPVP.SafeZone)) && m is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)m; + + if (pm.DuelContext == null || pm.DuelPlayer == null || !pm.DuelContext.Started || pm.DuelContext.Finished || pm.DuelPlayer.Eliminated) + return true; + } + #endregion + + return base.OnMoveOver(m); + } + + public virtual void AddCustomContextEntries(Mobile from, List list) + { + } + + public virtual bool CanDrop { get { return IsBonded; } } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (m_AI != null && Commandable) + m_AI.GetContextMenuEntries(from, list); + + if (m_bTamable && !m_bControlled && from.Alive) + list.Add(new TameEntry(from, this)); + + AddCustomContextEntries(from, list); + + if (CanTeach && from.Alive) + { + Skills ourSkills = this.Skills; + Skills theirSkills = from.Skills; + + for (int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i) + { + Skill skill = ourSkills[i]; + Skill theirSkill = theirSkills[i]; + + if (skill != null && theirSkill != null && skill.Base >= 60.0 && CheckTeach(skill.SkillName, from)) + { + int toTeach = skill.BaseFixedPoint / 3; + + if (toTeach > 420) + toTeach = 420; + + list.Add(new TeachEntry((SkillName)i, this, from, (toTeach > theirSkill.BaseFixedPoint))); + } + } + } + } + + public override bool HandlesOnSpeech(Mobile from) + { + InhumanSpeech speechType = this.SpeechType; + + if (speechType != null && (speechType.Flags & IHSFlags.OnSpeech) != 0 && from.InRange(this, 3)) + return true; + + return (m_AI != null && m_AI.HandlesOnSpeech(from) && from.InRange(this, m_iRangePerception)); + } + + public override void OnSpeech(SpeechEventArgs e) + { + InhumanSpeech speechType = this.SpeechType; + + if (speechType != null && speechType.OnSpeech(this, e.Mobile, e.Speech)) + e.Handled = true; + else if (!e.Handled && m_AI != null && e.Mobile.InRange(this, m_iRangePerception)) + m_AI.OnSpeech(e); + } + + public override bool IsHarmfulCriminal(Mobile target) + { + if ((Controlled && target == m_ControlMaster) || (Summoned && target == m_SummonMaster)) + return false; + + if (target is BaseCreature && ((BaseCreature)target).InitialInnocent && !((BaseCreature)target).Controlled) + return false; + + if (target is PlayerMobile && ((PlayerMobile)target).PermaFlags.Count > 0) + return false; + + return base.IsHarmfulCriminal(target); + } + + public override void CriminalAction(bool message) + { + base.CriminalAction(message); + + if (Controlled || Summoned) + { + if (m_ControlMaster != null && m_ControlMaster.Player) + m_ControlMaster.CriminalAction(false); + else if (m_SummonMaster != null && m_SummonMaster.Player) + m_SummonMaster.CriminalAction(false); + } + } + + public override void DoHarmful(Mobile target, bool indirect) + { + base.DoHarmful(target, indirect); + + if (target == this || target == m_ControlMaster || target == m_SummonMaster || (!Controlled && !Summoned)) + return; + + List list = this.Aggressors; + + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo ai = list[i]; + + if (ai.Attacker == target) + return; + } + + list = this.Aggressed; + + for (int i = 0; i < list.Count; ++i) + { + AggressorInfo ai = list[i]; + + if (ai.Defender == target) + { + if (m_ControlMaster != null && m_ControlMaster.Player && m_ControlMaster.CanBeHarmful(target, false)) + m_ControlMaster.DoHarmful(target, true); + else if (m_SummonMaster != null && m_SummonMaster.Player && m_SummonMaster.CanBeHarmful(target, false)) + m_SummonMaster.DoHarmful(target, true); + + return; + } + } + } + + private static Mobile m_NoDupeGuards; + + public void ReleaseGuardDupeLock() + { + m_NoDupeGuards = null; + } + + public void ReleaseGuardLock() + { + EndAction(typeof(GuardedRegion)); + } + + private DateTime m_IdleReleaseTime; + + public virtual bool CheckIdle() + { + if (Combatant != null) + return false; // in combat.. not idling + + if (m_IdleReleaseTime > DateTime.MinValue) + { + // idling... + + if (DateTime.Now >= m_IdleReleaseTime) + { + m_IdleReleaseTime = DateTime.MinValue; + return false; // idle is over + } + + return true; // still idling + } + + if (95 > Utility.Random(100)) + return false; // not idling, but don't want to enter idle state + + m_IdleReleaseTime = DateTime.Now + TimeSpan.FromSeconds(Utility.RandomMinMax(15, 25)); + + if (Body.IsHuman) + { + switch (Utility.Random(2)) + { + case 0: CheckedAnimate(5, 5, 1, true, true, 1); break; + case 1: CheckedAnimate(6, 5, 1, true, false, 1); break; + } + } + else if (Body.IsAnimal) + { + switch (Utility.Random(3)) + { + case 0: CheckedAnimate(3, 3, 1, true, false, 1); break; + case 1: CheckedAnimate(9, 5, 1, true, false, 1); break; + case 2: CheckedAnimate(10, 5, 1, true, false, 1); break; + } + } + else if (Body.IsMonster) + { + switch (Utility.Random(2)) + { + case 0: CheckedAnimate(17, 5, 1, true, false, 1); break; + case 1: CheckedAnimate(18, 5, 1, true, false, 1); break; + } + } + + PlaySound(GetIdleSound()); + return true; // entered idle state + } + + /* + this way, due to the huge number of locations this will have to be changed + Perhaps we can change this in the future when fixing game play is not the + major issue. + */ + + public virtual void CheckedAnimate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) + { + if (!Mounted) + { + base.Animate(action, frameCount, repeatCount, forward, repeat, delay); + } + } + + public override void Animate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) + { + base.Animate(action, frameCount, repeatCount, forward, repeat, delay); + } + + private void CheckAIActive() + { + Map map = Map; + + if (PlayerRangeSensitive && m_AI != null && map != null && map.GetSector(Location).Active) + m_AI.Activate(); + } + + public override void OnCombatantChange() + { + base.OnCombatantChange(); + + Warmode = (Combatant != null && !Combatant.Deleted && Combatant.Alive); + + if (CanFly && Warmode) + { + Flying = false; + } + } + + protected override void OnMapChange(Map oldMap) + { + CheckAIActive(); + + base.OnMapChange(oldMap); + } + + protected override void OnLocationChange(Point3D oldLocation) + { + CheckAIActive(); + + base.OnLocationChange(oldLocation); + } + + public virtual void ForceReacquire() + { + m_NextReacquireTime = DateTime.MinValue; + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (AcquireOnApproach && (!Controlled && !Summoned) && FightMode != FightMode.Aggressor) + { + if (InRange(m.Location, AcquireOnApproachRange) && !InRange(oldLocation, AcquireOnApproachRange)) + { + if (CanBeHarmful(m) && IsEnemy(m)) + { + Combatant = FocusMob = m; + + if (AIObject != null) + { + AIObject.MoveTo(m, true, 1); + } + + DoHarmful(m); + } + } + } + else if (ReacquireOnMovement) + { + ForceReacquire(); + } + + InhumanSpeech speechType = this.SpeechType; + + if (speechType != null) + speechType.OnMovement(this, m, oldLocation); + + /* Begin notice sound */ + if ((!m.Hidden || m.AccessLevel == AccessLevel.Player) && m.Player && m_FightMode != FightMode.Aggressor && m_FightMode != FightMode.None && Combatant == null && !Controlled && !Summoned) + { + // If this creature defends itself but doesn't actively attack (animal) or + // doesn't fight at all (vendor) then no notice sounds are played.. + // So, players are only notified of aggressive monsters + + // Monsters that are currently fighting are ignored + + // Controlled or summoned creatures are ignored + + if (InRange(m.Location, 18) && !InRange(oldLocation, 18)) + { + if (Body.IsMonster) + Animate(11, 5, 1, true, false, 1); + + PlaySound(GetAngerSound()); + } + } + /* End notice sound */ + + if (MLQuestSystem.Enabled && CanShout && m is PlayerMobile) + CheckShout((PlayerMobile)m, oldLocation); + + if (m_NoDupeGuards == m) + return; + + if (!Body.IsHuman || Kills >= 5 || AlwaysMurderer || AlwaysAttackable || m.Kills < 5 || !m.InRange(Location, 12) || !m.Alive) + return; + + GuardedRegion guardedRegion = (GuardedRegion)this.Region.GetRegion(typeof(GuardedRegion)); + + if (guardedRegion != null) + { + if (!guardedRegion.IsDisabled() && guardedRegion.IsGuardCandidate(m) && BeginAction(typeof(GuardedRegion))) + { + Say(1013037 + Utility.Random(16)); + guardedRegion.CallGuards(this.Location); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(ReleaseGuardLock)); + + m_NoDupeGuards = m; + Timer.DelayCall(TimeSpan.Zero, new TimerCallback(ReleaseGuardDupeLock)); + } + } + } + + public void AddSpellAttack(Type type) + { + m_arSpellAttack.Add(type); + } + + public void AddSpellDefense(Type type) + { + m_arSpellDefense.Add(type); + } + + public Spell GetAttackSpellRandom() + { + if (m_arSpellAttack.Count > 0) + { + Type type = m_arSpellAttack[Utility.Random(m_arSpellAttack.Count)]; + + object[] args = { this, null }; + return Activator.CreateInstance(type, args) as Spell; + } + else + { + return null; + } + } + + public Spell GetDefenseSpellRandom() + { + if (m_arSpellDefense.Count > 0) + { + Type type = m_arSpellDefense[Utility.Random(m_arSpellDefense.Count)]; + + object[] args = { this, null }; + return Activator.CreateInstance(type, args) as Spell; + } + else + { + return null; + } + } + + public Spell GetSpellSpecific(Type type) + { + int i; + + for (i = 0; i < m_arSpellAttack.Count; i++) + { + if (m_arSpellAttack[i] == type) + { + object[] args = { this, null }; + return Activator.CreateInstance(type, args) as Spell; + } + } + + for (i = 0; i < m_arSpellDefense.Count; i++) + { + if (m_arSpellDefense[i] == type) + { + object[] args = { this, null }; + return Activator.CreateInstance(type, args) as Spell; + } + } + + return null; + } + + #region Set[...] + + public void SetDamage(int val) + { + m_DamageMin = val; + m_DamageMax = val; + } + + public void SetDamage(int min, int max) + { + m_DamageMin = min; + m_DamageMax = max; + } + + public void SetHits(int val) + { + if (val < 1000 && !Core.AOS) + val = (val * 100) / 60; + + m_HitsMax = val; + Hits = HitsMax; + } + + public void SetHits(int min, int max) + { + if (min < 1000 && !Core.AOS) + { + min = (min * 100) / 60; + max = (max * 100) / 60; + } + + m_HitsMax = Utility.RandomMinMax(min, max); + Hits = HitsMax; + } + + public void SetStam(int val) + { + m_StamMax = val; + Stam = StamMax; + } + + public void SetStam(int min, int max) + { + m_StamMax = Utility.RandomMinMax(min, max); + Stam = StamMax; + } + + public void SetMana(int val) + { + m_ManaMax = val; + Mana = ManaMax; + } + + public void SetMana(int min, int max) + { + m_ManaMax = Utility.RandomMinMax(min, max); + Mana = ManaMax; + } + + public void SetStr(int val) + { + RawStr = val; + Hits = HitsMax; + } + + public void SetStr(int min, int max) + { + RawStr = Utility.RandomMinMax(min, max); + Hits = HitsMax; + } + + public void SetDex(int val) + { + RawDex = val; + Stam = StamMax; + } + + public void SetDex(int min, int max) + { + RawDex = Utility.RandomMinMax(min, max); + Stam = StamMax; + } + + public void SetInt(int val) + { + RawInt = val; + Mana = ManaMax; + } + + public void SetInt(int min, int max) + { + RawInt = Utility.RandomMinMax(min, max); + Mana = ManaMax; + } + + public void SetDamageType(ResistanceType type, int min, int max) + { + SetDamageType(type, Utility.RandomMinMax(min, max)); + } + + public void SetDamageType(ResistanceType type, int val) + { + switch (type) + { + case ResistanceType.Physical: m_PhysicalDamage = val; break; + case ResistanceType.Fire: m_FireDamage = val; break; + case ResistanceType.Cold: m_ColdDamage = val; break; + case ResistanceType.Poison: m_PoisonDamage = val; break; + case ResistanceType.Energy: m_EnergyDamage = val; break; + } + } + + public void SetResistance(ResistanceType type, int min, int max) + { + SetResistance(type, Utility.RandomMinMax(min, max)); + } + + public void SetResistance(ResistanceType type, int val) + { + switch (type) + { + case ResistanceType.Physical: m_PhysicalResistance = val; break; + case ResistanceType.Fire: m_FireResistance = val; break; + case ResistanceType.Cold: m_ColdResistance = val; break; + case ResistanceType.Poison: m_PoisonResistance = val; break; + case ResistanceType.Energy: m_EnergyResistance = val; break; + } + + UpdateResistances(); + } + + public void SetSkill(SkillName name, double val) + { + Skills[name].BaseFixedPoint = (int)(val * 10); + + if (Skills[name].Base > Skills[name].Cap) + { + if (Core.SE) + this.SkillsCap += (Skills[name].BaseFixedPoint - Skills[name].CapFixedPoint); + + Skills[name].Cap = Skills[name].Base; + } + } + + public void SetSkill(SkillName name, double min, double max) + { + int minFixed = (int)(min * 10); + int maxFixed = (int)(max * 10); + + Skills[name].BaseFixedPoint = Utility.RandomMinMax(minFixed, maxFixed); + + if (Skills[name].Base > Skills[name].Cap) + { + if (Core.SE) + this.SkillsCap += (Skills[name].BaseFixedPoint - Skills[name].CapFixedPoint); + + Skills[name].Cap = Skills[name].Base; + } + } + + public void SetFameLevel(int level) + { + switch (level) + { + case 1: Fame = Utility.RandomMinMax(0, 1249); break; + case 2: Fame = Utility.RandomMinMax(1250, 2499); break; + case 3: Fame = Utility.RandomMinMax(2500, 4999); break; + case 4: Fame = Utility.RandomMinMax(5000, 9999); break; + case 5: Fame = Utility.RandomMinMax(10000, 10000); break; + } + } + + public void SetKarmaLevel(int level) + { + switch (level) + { + case 0: Karma = -Utility.RandomMinMax(0, 624); break; + case 1: Karma = -Utility.RandomMinMax(625, 1249); break; + case 2: Karma = -Utility.RandomMinMax(1250, 2499); break; + case 3: Karma = -Utility.RandomMinMax(2500, 4999); break; + case 4: Karma = -Utility.RandomMinMax(5000, 9999); break; + case 5: Karma = -Utility.RandomMinMax(10000, 10000); break; + } + } + + #endregion + + public static void Cap(ref int val, int min, int max) + { + if (val < min) + val = min; + else if (val > max) + val = max; + } + + #region Pack & Loot + + #region Mondain's Legacy + public void PackArcaneScroll(int min, int max) + { + PackArcaneScroll(Utility.RandomMinMax(min, max)); + } + + public void PackArcaneScroll(int amount) + { + for (int i = 0; i < amount; ++i) + PackArcaneScroll(); + } + + public void PackArcaneScroll() + { + if (!Core.ML) + return; + + PackItem(Loot.Construct(Loot.ArcanistScrollTypes)); + } + #endregion + + public void PackPotion() + { + PackItem(Loot.RandomPotion()); + } + + /*public void PackArcanceScroll( double chance ) + { + if ( !Core.ML || chance <= Utility.RandomDouble() ) + return; + + PackItem( Loot.Construct( Loot.ArcanistScrollTypes ) ); + } + + public void PackNecroScroll( int index ) + { + if ( !Core.AOS || 0.05 <= Utility.RandomDouble() ) + return; + + PackItem( Loot.Construct( Loot.NecromancyScrollTypes, index ) ); + }*/ + + public void PackScroll(int minCircle, int maxCircle) + { + PackScroll(Utility.RandomMinMax(minCircle, maxCircle)); + } + + public void PackScroll(int circle) + { + int min = (circle - 1) * 8; + + PackItem(Loot.RandomScroll(min, min + 7, SpellbookType.Regular)); + } + + public void PackMagicItems(int minLevel, int maxLevel) + { + PackMagicItems(minLevel, maxLevel, 0.30, 0.15); + } + + public void PackMagicItems(int minLevel, int maxLevel, double armorChance, double weaponChance) + { + if (!PackArmor(minLevel, maxLevel, armorChance)) + PackWeapon(minLevel, maxLevel, weaponChance); + } + + public virtual void DropBackpack() + { + if (Backpack != null) + { + if (Backpack.Items.Count > 0) + { + Backpack b = new CreatureBackpack(Name); + + List list = new List(Backpack.Items); + foreach (Item item in list) + { + b.DropItem(item); + } + + BaseHouse house = BaseHouse.FindHouseAt(this); + if (house != null) + b.MoveToWorld(house.BanLocation, house.Map); + else + b.MoveToWorld(Location, Map); + } + } + } + + protected bool m_Spawning; + protected int m_KillersLuck; + + public virtual void GenerateLoot(bool spawning) + { + m_Spawning = spawning; + + if (!spawning) + m_KillersLuck = LootPack.GetLuckChanceForKiller(this); + + GenerateLoot(); + + if (m_Paragon) + { + if (Fame < 1250) + AddLoot(LootPack.Meager); + else if (Fame < 2500) + AddLoot(LootPack.Average); + else if (Fame < 5000) + AddLoot(LootPack.Rich); + else if (Fame < 10000) + AddLoot(LootPack.FilthyRich); + else + AddLoot(LootPack.UltraRich); + } + + m_Spawning = false; + m_KillersLuck = 0; + } + + public virtual void GenerateLoot() + { + } + + public virtual void AddLoot(LootPack pack, int amount) + { + for (int i = 0; i < amount; ++i) + AddLoot(pack); + } + + public virtual void AddLoot(LootPack pack) + { + if (Summoned) + return; + + Container backpack = Backpack; + + if (backpack == null) + { + backpack = new Backpack(); + + backpack.Movable = false; + + AddItem(backpack); + } + + pack.Generate(this, backpack, m_Spawning, m_KillersLuck); + } + + public bool PackArmor(int minLevel, int maxLevel) + { + return PackArmor(minLevel, maxLevel, 1.0); + } + + public bool PackArmor(int minLevel, int maxLevel, double chance) + { + if (chance <= Utility.RandomDouble()) + return false; + + Cap(ref minLevel, 0, 5); + Cap(ref maxLevel, 0, 5); + + if (Core.AOS) + { + Item item = Loot.RandomArmorOrShieldOrJewelry(); + bool isQuality = Utility.RandomBool(); + + if (item == null) + return false; + + int attributeCount, min, max; + GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); + + if (item is BaseArmor) + BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max); + else if (item is BaseJewel) + BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); + + if (item is BaseWeapon) + { + if (isQuality == true) + ((BaseWeapon)item).Quality = WeaponQuality.Regular; + else + ((BaseWeapon)item).Quality = WeaponQuality.Low; + } + + PackItem(item); + } + else + { + BaseArmor armor = Loot.RandomArmorOrShield(); + + if (armor == null) + return false; + + armor.ProtectionLevel = (ArmorProtectionLevel)RandomMinMaxScaled(minLevel, maxLevel); + armor.Durability = (ArmorDurabilityLevel)RandomMinMaxScaled(minLevel, maxLevel); + + PackItem(armor); + } + + return true; + } + + public static void GetRandomAOSStats(int minLevel, int maxLevel, out int attributeCount, out int min, out int max) + { + int v = RandomMinMaxScaled(minLevel, maxLevel); + + if (v >= 5) + { + attributeCount = Utility.RandomMinMax(2, 6); + min = 20; max = 70; + } + else if (v == 4) + { + attributeCount = Utility.RandomMinMax(2, 4); + min = 20; max = 50; + } + else if (v == 3) + { + attributeCount = Utility.RandomMinMax(2, 3); + min = 20; max = 40; + } + else if (v == 2) + { + attributeCount = Utility.RandomMinMax(1, 2); + min = 10; max = 30; + } + else + { + attributeCount = 1; + min = 10; max = 20; + } + } + + public static int RandomMinMaxScaled(int min, int max) + { + if (min == max) + return min; + + if (min > max) + { + int hold = min; + min = max; + max = hold; + } + + /* Example: + * min: 1 + * max: 5 + * count: 5 + * + * total = (5*5) + (4*4) + (3*3) + (2*2) + (1*1) = 25 + 16 + 9 + 4 + 1 = 55 + * + * chance for min+0 : 25/55 : 45.45% + * chance for min+1 : 16/55 : 29.09% + * chance for min+2 : 9/55 : 16.36% + * chance for min+3 : 4/55 : 7.27% + * chance for min+4 : 1/55 : 1.81% + */ + + int count = max - min + 1; + int total = 0, toAdd = count; + + for (int i = 0; i < count; ++i, --toAdd) + total += toAdd * toAdd; + + int rand = Utility.Random(total); + toAdd = count; + + int val = min; + + for (int i = 0; i < count; ++i, --toAdd, ++val) + { + rand -= toAdd * toAdd; + + if (rand < 0) + break; + } + + return val; + } + + public bool PackSlayer() + { + return PackSlayer(0.05); + } + + public bool PackSlayer(double chance) + { + if (chance <= Utility.RandomDouble()) + return false; + + if (Utility.RandomBool()) + { + BaseInstrument instrument = Loot.RandomInstrument(); + + if (instrument != null) + { + instrument.Slayer = SlayerGroup.GetLootSlayerType(GetType()); + PackItem(instrument); + } + } + else if (!Core.AOS) + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if (weapon != null) + { + weapon.Slayer = SlayerGroup.GetLootSlayerType(GetType()); + PackItem(weapon); + } + } + + return true; + } + + public bool PackWeapon(int minLevel, int maxLevel) + { + return PackWeapon(minLevel, maxLevel, 1.0); + } + + public bool PackWeapon(int minLevel, int maxLevel, double chance) + { + if (chance <= Utility.RandomDouble()) + return false; + + Cap(ref minLevel, 0, 5); + Cap(ref maxLevel, 0, 5); + + if (Core.AOS) + { + Item item = Loot.RandomWeaponOrJewelry(); + + if (item == null) + return false; + + int attributeCount, min, max; + GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); + + if (item is BaseWeapon) + BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, attributeCount, min, max); + else if (item is BaseJewel) + BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); + + PackItem(item); + } + else + { + BaseWeapon weapon = Loot.RandomWeapon(); + + if (weapon == null) + return false; + + if (0.05 > Utility.RandomDouble()) + weapon.Slayer = SlayerName.Silver; + + weapon.DamageLevel = (WeaponDamageLevel)RandomMinMaxScaled(minLevel, maxLevel); + weapon.AccuracyLevel = (WeaponAccuracyLevel)RandomMinMaxScaled(minLevel, maxLevel); + weapon.DurabilityLevel = (WeaponDurabilityLevel)RandomMinMaxScaled(minLevel, maxLevel); + + PackItem(weapon); + } + + return true; + } + + public void PackGold(int amount) + { + if (amount > 0) + PackItem(new Gold(amount)); + } + + public void PackGold(int min, int max) + { + PackGold(Utility.RandomMinMax(min, max)); + } + + public void PackStatue(int min, int max) + { + PackStatue(Utility.RandomMinMax(min, max)); + } + + public void PackStatue(int amount) + { + for (int i = 0; i < amount; ++i) + PackStatue(); + } + + public void PackStatue() + { + PackItem(Loot.RandomStatue()); + } + + public void PackGem() + { + PackGem(1); + } + + public void PackGem(int min, int max) + { + PackGem(Utility.RandomMinMax(min, max)); + } + + public void PackGem(int amount) + { + if (amount <= 0) + return; + + Item gem = Loot.RandomGem(); + + gem.Amount = amount; + + PackItem(gem); + } + + public void PackNecroReg(int min, int max) + { + PackNecroReg(Utility.RandomMinMax(min, max)); + } + + public void PackNecroReg(int amount) + { + for (int i = 0; i < amount; ++i) + PackNecroReg(); + } + + public void PackNecroReg() + { + if (!Core.AOS) + return; + + PackItem(Loot.RandomNecromancyReagent()); + } + + public void PackReg(int min, int max) + { + PackReg(Utility.RandomMinMax(min, max)); + } + + public void PackReg(int amount) + { + if (amount <= 0) + return; + + Item reg = Loot.RandomReagent(); + + reg.Amount = amount; + + PackItem(reg); + } + + public void PackItem(Item item) + { + if (Summoned || item == null) + { + if (item != null) + item.Delete(); + + return; + } + + Container pack = Backpack; + + if (pack == null) + { + pack = new Backpack(); + + pack.Movable = false; + + AddItem(pack); + } + + if (!item.Stackable || !pack.TryDropItem(this, item, false)) // try stack + pack.DropItem(item); // failed, drop it anyway + } + + #endregion + + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster && !Body.IsHuman) + { + Container pack = this.Backpack; + + if (pack != null) + pack.DisplayTo(from); + } + + if (this.DeathAdderCharmable && from.CanBeHarmful(this, false)) + { + DeathAdder da = Spells.Necromancy.SummonFamiliarSpell.Table[from] as DeathAdder; + + if (da != null && !da.Deleted) + { + from.SendAsciiMessage("You charm the snake. Select a target to attack."); + from.Target = new DeathAdderCharmTarget(this); + } + } + + if (MLQuestSystem.Enabled && CanGiveMLQuest && from is PlayerMobile) + MLQuestSystem.OnDoubleClick(this, (PlayerMobile)from); + + base.OnDoubleClick(from); + } + + private class DeathAdderCharmTarget : Target + { + private BaseCreature m_Charmed; + + public DeathAdderCharmTarget(BaseCreature charmed) + : base(-1, false, TargetFlags.Harmful) + { + m_Charmed = charmed; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!m_Charmed.DeathAdderCharmable || m_Charmed.Combatant != null || !from.CanBeHarmful(m_Charmed, false)) + return; + + DeathAdder da = Spells.Necromancy.SummonFamiliarSpell.Table[from] as DeathAdder; + if (da == null || da.Deleted) + return; + + Mobile targ = targeted as Mobile; + if (targ == null || !from.CanBeHarmful(targ, false)) + return; + + from.RevealingAction(); + from.DoHarmful(targ, true); + + m_Charmed.Combatant = targ; + + if (m_Charmed.AIObject != null) + m_Charmed.AIObject.Action = ActionType.Combat; + } + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + if (MLQuestSystem.Enabled && CanGiveMLQuest) + list.Add(1072269); // Quest Giver + + if (Core.ML) + { + if (DisplayWeight) + list.Add(TotalWeight == 1 ? 1072788 : 1072789, TotalWeight.ToString()); // Weight: ~1_WEIGHT~ stones + + if (m_ControlOrder == OrderType.Guard) + list.Add(1080078); // guarding + } + + if (Summoned && !IsAnimatedDead && !IsNecroFamiliar && !(this is Clone)) + list.Add(1049646); // (summoned) + else if (Controlled && Commandable) + { + if (IsBonded) //Intentional difference (showing ONLY bonded when bonded instead of bonded & tame) + list.Add(1049608); // (bonded) + else + list.Add(502006); // (tame) + } + } + + public override void OnSingleClick(Mobile from) + { + if (Controlled && Commandable) + { + int number; + + if (Summoned) + number = 1049646; // (summoned) + else if (IsBonded) + number = 1049608; // (bonded) + else + number = 502006; // (tame) + + PrivateOverheadMessage(MessageType.Regular, 0x3B2, number, from.NetState); + } + + base.OnSingleClick(from); + } + + public virtual double TreasureMapChance { get { return TreasureMap.LootChance; } } + public virtual int TreasureMapLevel { get { return -1; } } + + public virtual bool IgnoreYoungProtection { get { return false; } } + + public override bool OnBeforeDeath() + { + int treasureLevel = TreasureMapLevel; + + if (treasureLevel == 1 && this.Map == Map.Trammel && TreasureMap.IsInHavenIsland(this)) + { + Mobile killer = this.LastKiller; + + if (killer is BaseCreature) + killer = ((BaseCreature)killer).GetMaster(); + + if (killer is PlayerMobile && ((PlayerMobile)killer).Young) + treasureLevel = 0; + } + + if (!Summoned && !NoKillAwards && !IsBonded && treasureLevel >= 0) + { + if (treasureLevel >= 0) + { + if (m_Paragon && Paragon.ChestChance > Utility.RandomDouble()) + PackItem(new ParagonChest(this.Name, treasureLevel)); + else if ((Map == Map.Felucca || Map == Map.Trammel) && TreasureMap.LootChance >= Utility.RandomDouble()) + PackItem(new TreasureMap(treasureLevel, Map)); + } + if (m_Paragon && Paragon.ChocolateIngredientChance > Utility.RandomDouble()) + { + switch (Utility.Random(4)) + { + case 0: PackItem(new CocoaButter()); break; + case 1: PackItem(new CocoaLiquor()); break; + case 2: PackItem(new SackOfSugar()); break; + case 3: PackItem(new Vanilla()); break; + } + } + } + + if (!Summoned && !NoKillAwards && !m_HasGeneratedLoot) + { + m_HasGeneratedLoot = true; + GenerateLoot(false); + } + + if (!NoKillAwards && Region.IsPartOf("Doom")) + { + int bones = Engines.Quests.Doom.TheSummoningQuest.GetDaemonBonesFor(this); + + if (bones > 0) + PackItem(new DaemonBone(bones)); + } + + if (IsAnimatedDead) + Effects.SendLocationEffect(Location, Map, 0x3728, 13, 1, 0x461, 4); + + InhumanSpeech speechType = this.SpeechType; + + if (speechType != null) + speechType.OnDeath(this); + + if (m_ReceivedHonorContext != null) + m_ReceivedHonorContext.OnTargetKilled(); + + return base.OnBeforeDeath(); + } + + private bool m_NoKillAwards; + + public bool NoKillAwards + { + get { return m_NoKillAwards; } + set { m_NoKillAwards = value; } + } + + public int ComputeBonusDamage(List list, Mobile m) + { + int bonus = 0; + + for (int i = list.Count - 1; i >= 0; --i) + { + DamageEntry de = list[i]; + + if (de.Damager == m || !(de.Damager is BaseCreature)) + continue; + + BaseCreature bc = (BaseCreature)de.Damager; + Mobile master = null; + + master = bc.GetMaster(); + + if (master == m) + bonus += de.DamageGiven; + } + + return bonus; + } + + public Mobile GetMaster() + { + if (Controlled && ControlMaster != null) + return ControlMaster; + else if (Summoned && SummonMaster != null) + return SummonMaster; + + return null; + } + + private class FKEntry + { + public Mobile m_Mobile; + public int m_Damage; + + public FKEntry(Mobile m, int damage) + { + m_Mobile = m; + m_Damage = damage; + } + } + + public static List GetLootingRights(List damageEntries, int hitsMax) + { + List rights = new List(); + + for (int i = damageEntries.Count - 1; i >= 0; --i) + { + if (i >= damageEntries.Count) + continue; + + DamageEntry de = damageEntries[i]; + + if (de.HasExpired) + { + damageEntries.RemoveAt(i); + continue; + } + + int damage = de.DamageGiven; + + List respList = de.Responsible; + + if (respList != null) + { + for (int j = 0; j < respList.Count; ++j) + { + DamageEntry subEntry = respList[j]; + Mobile master = subEntry.Damager; + + if (master == null || master.Deleted || !master.Player) + continue; + + bool needNewSubEntry = true; + + for (int k = 0; needNewSubEntry && k < rights.Count; ++k) + { + DamageStore ds = rights[k]; + + if (ds.m_Mobile == master) + { + ds.m_Damage += subEntry.DamageGiven; + needNewSubEntry = false; + } + } + + if (needNewSubEntry) + rights.Add(new DamageStore(master, subEntry.DamageGiven)); + + damage -= subEntry.DamageGiven; + } + } + + Mobile m = de.Damager; + + if (m == null || m.Deleted || !m.Player) + continue; + + if (damage <= 0) + continue; + + bool needNewEntry = true; + + for (int j = 0; needNewEntry && j < rights.Count; ++j) + { + DamageStore ds = rights[j]; + + if (ds.m_Mobile == m) + { + ds.m_Damage += damage; + needNewEntry = false; + } + } + + if (needNewEntry) + rights.Add(new DamageStore(m, damage)); + } + + if (rights.Count > 0) + { + rights[0].m_Damage = (int)(rights[0].m_Damage * 1.25); //This would be the first valid person attacking it. Gets a 25% bonus. Per 1/19/07 Five on Friday + + if (rights.Count > 1) + rights.Sort(); //Sort by damage + + int topDamage = rights[0].m_Damage; + int minDamage; + + if (hitsMax >= 3000) + minDamage = topDamage / 16; + else if (hitsMax >= 1000) + minDamage = topDamage / 8; + else if (hitsMax >= 200) + minDamage = topDamage / 4; + else + minDamage = topDamage / 2; + + for (int i = 0; i < rights.Count; ++i) + { + DamageStore ds = rights[i]; + + ds.m_HasRight = (ds.m_Damage >= minDamage); + } + } + + return rights; + } + + #region Mondain's Legacy + public virtual bool GivesMLMinorArtifact { get { return false; } } + #endregion + + public virtual void OnKilledBy(Mobile mob) + { + + XmlQuest.RegisterKill(this, mob);// Vinds : kill register pour xmlspawner + + #region Mondain's Legacy + if (GivesMLMinorArtifact) + { + if (MondainsLegacy.CheckArtifactChance(mob, this)) + MondainsLegacy.GiveArtifactTo(mob); + } + #endregion + else if (m_Paragon) + { + if (Paragon.CheckArtifactChance(mob, this)) + Paragon.GiveArtifactTo(mob); + } + + // Scriptiz : Malas counters + if (Map != Map.Malas) return; + PlayerMobile pm = mob as PlayerMobile; + if (pm == null || pm.AccessLevel > AccessLevel.Player) return; + Alignments.Instance.incKills(pm.Alignment, this.Player); + } + + public override void OnDeath(Container c) + { + MeerMage.StopEffect(this, false); + + if (IsBonded) + { + int sound = this.GetDeathSound(); + + if (sound >= 0) + Effects.PlaySound(this, this.Map, sound); + + Warmode = false; + + Poison = null; + Combatant = null; + + Hits = 0; + Stam = 0; + Mana = 0; + + IsDeadPet = true; + ControlTarget = ControlMaster; + ControlOrder = OrderType.Follow; + + ProcessDeltaQueue(); + SendIncomingPacket(); + SendIncomingPacket(); + + List aggressors = this.Aggressors; + + for (int i = 0; i < aggressors.Count; ++i) + { + AggressorInfo info = aggressors[i]; + + if (info.Attacker.Combatant == this) + info.Attacker.Combatant = null; + } + + List aggressed = this.Aggressed; + + for (int i = 0; i < aggressed.Count; ++i) + { + AggressorInfo info = aggressed[i]; + + if (info.Defender.Combatant == this) + info.Defender.Combatant = null; + } + + Mobile owner = this.ControlMaster; + + if (owner == null || owner.Deleted || owner.Map != this.Map || !owner.InRange(this, 12) || !this.CanSee(owner) || !this.InLOS(owner)) + { + if (this.OwnerAbandonTime == DateTime.MinValue) + this.OwnerAbandonTime = DateTime.Now; + } + else + { + this.OwnerAbandonTime = DateTime.MinValue; + } + + GiftOfLifeSpell.HandleDeath(this); + + CheckStatTimers(); + } + else + { + if (!Summoned && !m_NoKillAwards) + { + int totalFame = Fame / 100; + int totalKarma = -Karma / 100; + if (Map == Map.Felucca) + { + totalFame += ((totalFame / 10) * 3); + totalKarma += ((totalKarma / 10) * 3); + } + + List list = GetLootingRights(this.DamageEntries, this.HitsMax); + List titles = new List(); + List fame = new List(); + List karma = new List(); + + bool givenQuestKill = false; + bool givenFactionKill = false; + bool givenToTKill = false; + + for (int i = 0; i < list.Count; ++i) + { + DamageStore ds = list[i]; + + if (!ds.m_HasRight) + continue; + + Party party = Engines.PartySystem.Party.Get(ds.m_Mobile); + + if (party != null) + { + int divedFame = totalFame / party.Members.Count; + int divedKarma = totalKarma / party.Members.Count; + + for (int j = 0; j < party.Members.Count; ++j) + { + PartyMemberInfo info = party.Members[j] as PartyMemberInfo; + + if (info != null && info.Mobile != null) + { + int index = titles.IndexOf(info.Mobile); + + if (index == -1) + { + titles.Add(info.Mobile); + fame.Add(divedFame); + karma.Add(divedKarma); + } + else + { + fame[index] += divedFame; + karma[index] += divedKarma; + } + } + } + } + else + { + titles.Add(ds.m_Mobile); + fame.Add(totalFame); + karma.Add(totalKarma); + } + + OnKilledBy(ds.m_Mobile); + + if (!givenFactionKill) + { + givenFactionKill = true; + Faction.HandleDeath(this, ds.m_Mobile); + } + + Region region = ds.m_Mobile.Region; + + if (!givenToTKill && (Map == Map.Tokuno || region.IsPartOf("Yomotsu Mines") || region.IsPartOf("Fan Dancer's Dojo"))) + { + givenToTKill = true; + TreasuresOfTokuno.HandleKill(this, ds.m_Mobile); + } + + PlayerMobile pm = ds.m_Mobile as PlayerMobile; + + if (pm != null) + { + if (MLQuestSystem.Enabled) + { + MLQuestSystem.HandleKill(pm, this); + + // Kills are given to *everyone* with looting right in the ML quest system + //givenQuestKill = true; + } + + if (givenQuestKill) + continue; + + QuestSystem qs = pm.Quest; + + if (qs != null) + { + qs.OnKill(this, c); + givenQuestKill = true; + } + } + } + for (int i = 0; i < titles.Count; ++i) + { + Titles.AwardFame(titles[i], fame[i], true); + Titles.AwardKarma(titles[i], karma[i], true); + } + } + + base.OnDeath(c); + + if (DeleteCorpseOnDeath) + c.Delete(); + } + } + + /* To save on cpu usage, RunUO creatures only reacquire creatures under the following circumstances: + * - 10 seconds have elapsed since the last time it tried + * - The creature was attacked + * - Some creatures, like dragons, will reacquire when they see someone move + * + * This functionality appears to be implemented on OSI as well + */ + + private DateTime m_NextReacquireTime; + + public DateTime NextReacquireTime { get { return m_NextReacquireTime; } set { m_NextReacquireTime = value; } } + + public virtual TimeSpan ReacquireDelay { get { return TimeSpan.FromSeconds(10.0); } } + public virtual bool ReacquireOnMovement { get { return false; } } + public virtual bool AcquireOnApproach { get { return m_Paragon; } } + public virtual int AcquireOnApproachRange { get { return 10; } } + + public override void OnDelete() + { + Mobile m = m_ControlMaster; + + SetControlMaster(null); + SummonMaster = null; + + if (m_ReceivedHonorContext != null) + m_ReceivedHonorContext.Cancel(); + + base.OnDelete(); + + if (m != null) + m.InvalidateProperties(); + } + + public override bool CanBeHarmful(Mobile target, bool message, bool ignoreOurBlessedness) + { + if (target is BaseFactionGuard) + return false; + + if ((target is BaseCreature && ((BaseCreature)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier) + { + if (message) + { + if (target.Title == null) + SendMessage("{0} cannot be harmed.", target.Name); + else + SendMessage("{0} {1} cannot be harmed.", target.Name, target.Title); + } + + return false; + } + + return base.CanBeHarmful(target, message, ignoreOurBlessedness); + } + + public override bool CanBeRenamedBy(Mobile from) + { + bool ret = base.CanBeRenamedBy(from); + + if (Controlled && from == ControlMaster && !from.Region.IsPartOf(typeof(Jail))) + ret = true; + + return ret; + } + + public bool SetControlMaster(Mobile m) + { + if (m == null) + { + ControlMaster = null; + Controlled = false; + ControlTarget = null; + ControlOrder = OrderType.None; + Guild = null; + + Delta(MobileDelta.Noto); + } + else + { + ISpawner se = this.Spawner; + if (se != null && se.UnlinkOnTaming) + { + this.Spawner.Remove(this); + this.Spawner = null; + } + + if (m.Followers + ControlSlots > m.FollowersMax) + { + m.SendLocalizedMessage(1049607); // You have too many followers to control that creature. + return false; + } + + CurrentWayPoint = null;//so tamed animals don't try to go back + + Home = Point3D.Zero; + + ControlMaster = m; + Controlled = true; + ControlTarget = null; + ControlOrder = OrderType.Come; + Guild = null; + + if (m_DeleteTimer != null) + { + m_DeleteTimer.Stop(); + m_DeleteTimer = null; + } + + Delta(MobileDelta.Noto); + } + + InvalidateProperties(); + + return true; + } + + public override void OnRegionChange(Region Old, Region New) + { + base.OnRegionChange(Old, New); + + if (this.Controlled) + { + SpawnEntry se = this.Spawner as SpawnEntry; + + if (se != null && !se.UnlinkOnTaming && (New == null || !New.AcceptsSpawnsFrom(se.Region))) + { + this.Spawner.Remove(this); + this.Spawner = null; + } + } + } + + private static bool m_Summoning; + + public static bool Summoning + { + get { return m_Summoning; } + set { m_Summoning = value; } + } + + public static bool Summon(BaseCreature creature, Mobile caster, Point3D p, int sound, TimeSpan duration) + { + return Summon(creature, true, caster, p, sound, duration); + } + + public static bool Summon(BaseCreature creature, bool controlled, Mobile caster, Point3D p, int sound, TimeSpan duration) + { + if (caster.Followers + creature.ControlSlots > caster.FollowersMax) + { + caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature. + creature.Delete(); + return false; + } + + m_Summoning = true; + + if (controlled) + creature.SetControlMaster(caster); + + creature.RangeHome = 10; + creature.Summoned = true; + + creature.SummonMaster = caster; + + Container pack = creature.Backpack; + + if (pack != null) + { + for (int i = pack.Items.Count - 1; i >= 0; --i) + { + if (i >= pack.Items.Count) + continue; + + pack.Items[i].Delete(); + } + } + + new UnsummonTimer(caster, creature, duration).Start(); + creature.m_SummonEnd = DateTime.Now + duration; + + creature.MoveToWorld(p, caster.Map); + + Effects.PlaySound(p, creature.Map, sound); + + m_Summoning = false; + + return true; + } + + private static bool EnableRummaging = true; + + private const double ChanceToRummage = 0.5; // 50% + + private const double MinutesToNextRummageMin = 1.0; + private const double MinutesToNextRummageMax = 4.0; + + private const double MinutesToNextChanceMin = 0.25; + private const double MinutesToNextChanceMax = 0.75; + + private DateTime m_NextRummageTime; + + public virtual bool CanBreath { get { return HasBreath && !Summoned; } } + public virtual bool IsDispellable { get { return Summoned && !IsAnimatedDead; } } + + #region Healing + public virtual bool CanHeal { get { return false; } } + public virtual bool CanHealOwner { get { return false; } } + public virtual double HealScalar { get { return 1.0; } } + + public virtual int HealSound { get { return 0x57; } } + public virtual int HealStartRange { get { return 2; } } + public virtual int HealEndRange { get { return RangePerception; } } + public virtual double HealTrigger { get { return 0.78; } } + public virtual double HealDelay { get { return 6.5; } } + public virtual double HealInterval { get { return 0.0; } } + public virtual bool HealFully { get { return true; } } + public virtual double HealOwnerTrigger { get { return 0.78; } } + public virtual double HealOwnerDelay { get { return 6.5; } } + public virtual double HealOwnerInterval { get { return 30.0; } } + public virtual bool HealOwnerFully { get { return false; } } + + private DateTime m_NextHealTime = DateTime.Now; + private DateTime m_NextHealOwnerTime = DateTime.Now; + private Timer m_HealTimer = null; + + public bool IsHealing { get { return (m_HealTimer != null); } } + + public virtual void HealStart(Mobile patient) + { + bool onSelf = (patient == this); + + //DoBeneficial( patient ); + + RevealingAction(); + + if (!onSelf) + { + patient.RevealingAction(); + patient.SendLocalizedMessage(1008078, false, Name); // : Attempting to heal you. + } + + double seconds = (onSelf ? HealDelay : HealOwnerDelay) + (patient.Alive ? 0.0 : 5.0); + + m_HealTimer = Timer.DelayCall(TimeSpan.FromSeconds(seconds), new TimerStateCallback(Heal_Callback), patient); + } + + private void Heal_Callback(object state) + { + if (state is Mobile) + Heal((Mobile)state); + } + + public virtual void Heal(Mobile patient) + { + if (!Alive || this.Map == Map.Internal || !CanBeBeneficial(patient, true, true) || patient.Map != this.Map || !InRange(patient, HealEndRange)) + { + StopHeal(); + return; + } + + bool onSelf = (patient == this); + + if (!patient.Alive) + { + } + else if (patient.Poisoned) + { + int poisonLevel = patient.Poison.Level; + + double healing = Skills.Healing.Value; + double anatomy = Skills.Anatomy.Value; + double chance = (healing - 30.0) / 50.0 - poisonLevel * 0.1; + + if ((healing >= 60.0 && anatomy >= 60.0) && chance > Utility.RandomDouble()) + { + if (patient.CurePoison(this)) + { + patient.SendLocalizedMessage(1010059); // You have been cured of all poisons. + + CheckSkill(SkillName.Healing, 0.0, 60.0 + poisonLevel * 10.0); // TODO: Verify formula + CheckSkill(SkillName.Anatomy, 0.0, 100.0); + } + } + } + else if (BleedAttack.IsBleeding(patient)) + { + patient.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding! + BleedAttack.EndBleed(patient, false); + } + else + { + double healing = Skills.Healing.Value; + double anatomy = Skills.Anatomy.Value; + double chance = (healing + 10.0) / 100.0; + + if (chance > Utility.RandomDouble()) + { + double min, max; + + min = (anatomy / 10.0) + (healing / 6.0) + 4.0; + max = (anatomy / 8.0) + (healing / 3.0) + 4.0; + + if (onSelf) + max += 10; + + double toHeal = min + (Utility.RandomDouble() * (max - min)); + + toHeal *= HealScalar; + + patient.Heal((int)toHeal); + + CheckSkill(SkillName.Healing, 0.0, 90.0); + CheckSkill(SkillName.Anatomy, 0.0, 100.0); + } + } + + HealEffect(patient); + + StopHeal(); + + if ((onSelf && HealFully && Hits >= HealTrigger * HitsMax && Hits < HitsMax) || (!onSelf && HealOwnerFully && patient.Hits >= HealOwnerTrigger * patient.HitsMax && patient.Hits < patient.HitsMax)) + HealStart(patient); + } + + public virtual void StopHeal() + { + if (m_HealTimer != null) + m_HealTimer.Stop(); + + m_HealTimer = null; + } + + public virtual void HealEffect(Mobile patient) + { + patient.PlaySound(HealSound); + } + #endregion + + #region Damaging Aura + private DateTime m_NextAura; + + public virtual bool HasAura { get { return false; } } + public virtual TimeSpan AuraInterval { get { return TimeSpan.FromSeconds(5); } } + public virtual int AuraRange { get { return 4; } } + + public virtual int AuraBaseDamage { get { return 5; } } + public virtual int AuraPhysicalDamage { get { return 0; } } + public virtual int AuraFireDamage { get { return 100; } } + public virtual int AuraColdDamage { get { return 0; } } + public virtual int AuraPoisonDamage { get { return 0; } } + public virtual int AuraEnergyDamage { get { return 0; } } + public virtual int AuraChaosDamage { get { return 0; } } + + public virtual void AuraDamage() + { + if (!Alive || IsDeadBondedPet) + return; + + List list = new List(); + + foreach (Mobile m in GetMobilesInRange(AuraRange)) + { + if (m == this || !CanBeHarmful(m, false) || (Core.AOS && !InLOS(m))) + continue; + + if (m is BaseCreature) + { + BaseCreature bc = (BaseCreature)m; + + if (bc.Controlled || bc.Summoned || bc.Team != Team) + list.Add(m); + } + else if (m.Player) + { + list.Add(m); + } + } + + foreach (Mobile m in list) + { + AOS.Damage(m, this, AuraBaseDamage, AuraPhysicalDamage, AuraFireDamage, AuraColdDamage, AuraPoisonDamage, AuraEnergyDamage, AuraChaosDamage); + AuraEffect(m); + } + } + + public virtual void AuraEffect(Mobile m) + { + } + #endregion + + public virtual void OnThink() + { + if (EnableRummaging && CanRummageCorpses && !Summoned && !Controlled && DateTime.Now >= m_NextRummageTime) + { + double min, max; + + if (ChanceToRummage > Utility.RandomDouble() && Rummage()) + { + min = MinutesToNextRummageMin; + max = MinutesToNextRummageMax; + } + else + { + min = MinutesToNextChanceMin; + max = MinutesToNextChanceMax; + } + + double delay = min + (Utility.RandomDouble() * (max - min)); + m_NextRummageTime = DateTime.Now + TimeSpan.FromMinutes(delay); + } + + if (CanBreath && DateTime.Now >= m_NextBreathTime) // tested: controlled dragons do breath fire, what about summoned skeletal dragons? + { + Mobile target = this.Combatant; + + if (target != null && target.Alive && !target.IsDeadBondedPet && CanBeHarmful(target) && target.Map == this.Map && !IsDeadBondedPet && target.InRange(this, BreathRange) && InLOS(target) && !BardPacified) + { + if ((DateTime.Now - m_NextBreathTime) < TimeSpan.FromSeconds(30) && Utility.RandomBool()) + { + BreathStart(target); + } + + m_NextBreathTime = DateTime.Now + TimeSpan.FromSeconds(BreathMinDelay + ((Utility.RandomDouble() * (BreathMaxDelay - BreathMinDelay)))); + } + } + + if ((CanHeal || CanHealOwner) && Alive && !IsHealing && !BardPacified) + { + Mobile owner = this.ControlMaster; + + if (owner != null && CanHealOwner && DateTime.Now >= m_NextHealOwnerTime && CanBeBeneficial(owner, true, true) && owner.Map == this.Map && InRange(owner, HealStartRange) && InLOS(owner) && owner.Hits < HealOwnerTrigger * owner.HitsMax) + { + HealStart(owner); + + m_NextHealOwnerTime = DateTime.Now + TimeSpan.FromSeconds(HealOwnerInterval); + } + else if (CanHeal && DateTime.Now >= m_NextHealTime && CanBeBeneficial(this) && (Hits < HealTrigger * HitsMax || Poisoned)) + { + HealStart(this); + + m_NextHealTime = DateTime.Now + TimeSpan.FromSeconds(HealInterval); + } + } + + if (ReturnsToHome && this.IsSpawnerBound() && !this.InRange(Home, RangeHome)) + { + if ((Combatant == null) && (Warmode == false) && Utility.RandomDouble() < .10) /* some throttling */ + { + m_FailedReturnHome = !this.Move(GetDirectionTo(Home.X, Home.Y)) ? m_FailedReturnHome + 1 : 0; + + if (m_FailedReturnHome > 5) + { + this.SetLocation(this.Home, true); + + m_FailedReturnHome = 0; + } + } + } + else + { + m_FailedReturnHome = 0; + } + + if (HasAura && DateTime.Now >= m_NextAura) + { + AuraDamage(); + m_NextAura = DateTime.Now + AuraInterval; + } + } + + public virtual bool Rummage() + { + Corpse toRummage = null; + + foreach (Item item in this.GetItemsInRange(2)) + { + if (item is Corpse && item.Items.Count > 0) + { + toRummage = (Corpse)item; + break; + } + } + + if (toRummage == null) + return false; + + Container pack = this.Backpack; + + if (pack == null) + return false; + + List items = toRummage.Items; + + bool rejected; + LRReason reason; + + for (int i = 0; i < items.Count; ++i) + { + Item item = items[Utility.Random(items.Count)]; + + Lift(item, item.Amount, out rejected, out reason); + + if (!rejected && Drop(this, new Point3D(-1, -1, 0))) + { + // *rummages through a corpse and takes an item* + PublicOverheadMessage(MessageType.Emote, 0x3B2, 1008086); + //TODO: Instancing of Rummaged stuff. + return true; + } + } + + return false; + } + + public void Pacify(Mobile master, DateTime endtime) + { + BardPacified = true; + BardEndTime = endtime; + } + + public override Mobile GetDamageMaster(Mobile damagee) + { + if (m_bBardProvoked && damagee == m_bBardTarget) + return m_bBardMaster; + else if (m_bControlled && m_ControlMaster != null) + return m_ControlMaster; + else if (m_bSummoned && m_SummonMaster != null) + return m_SummonMaster; + + return base.GetDamageMaster(damagee); + } + + public void Provoke(Mobile master, Mobile target, bool bSuccess) + { + BardProvoked = true; + + if (!Core.ML) + { + this.PublicOverheadMessage(MessageType.Emote, EmoteHue, false, "*looks furious*"); + } + + if (bSuccess) + { + PlaySound(GetIdleSound()); + + BardMaster = master; + BardTarget = target; + Combatant = target; + BardEndTime = DateTime.Now + TimeSpan.FromSeconds(30.0); + + if (target is BaseCreature) + { + BaseCreature t = (BaseCreature)target; + + if (t.Unprovokable || (t.IsParagon && BaseInstrument.GetBaseDifficulty(t) >= 160.0)) + return; + + t.BardProvoked = true; + + t.BardMaster = master; + t.BardTarget = this; + t.Combatant = this; + t.BardEndTime = DateTime.Now + TimeSpan.FromSeconds(30.0); + } + } + else + { + PlaySound(GetAngerSound()); + + BardMaster = master; + BardTarget = target; + } + } + + public bool FindMyName(string str, bool bWithAll) + { + int i, j; + + string name = this.Name; + + if (name == null || str.Length < name.Length) + return false; + + string[] wordsString = str.Split(' '); + string[] wordsName = name.Split(' '); + + for (j = 0; j < wordsName.Length; j++) + { + string wordName = wordsName[j]; + + bool bFound = false; + for (i = 0; i < wordsString.Length; i++) + { + string word = wordsString[i]; + + if (Insensitive.Equals(word, wordName)) + bFound = true; + + if (bWithAll && Insensitive.Equals(word, "all")) + return true; + } + + if (!bFound) + return false; + } + + return true; + } + + public static void TeleportPets(Mobile master, Point3D loc, Map map) + { + TeleportPets(master, loc, map, false); + } + + public static void TeleportPets(Mobile master, Point3D loc, Map map, bool onlyBonded) + { + List move = new List(); + + foreach (Mobile m in master.GetMobilesInRange(3)) + { + if (m is BaseCreature) + { + BaseCreature pet = (BaseCreature)m; + + if (pet.Controlled && pet.ControlMaster == master) + { + if (!onlyBonded || pet.IsBonded) + { + if (pet.ControlOrder == OrderType.Guard || pet.ControlOrder == OrderType.Follow || pet.ControlOrder == OrderType.Come) + move.Add(pet); + } + } + } + } + + foreach (Mobile m in move) + m.MoveToWorld(loc, map); + } + + public int CalculatePenalty(Mobile healer) + { + int PenaltySkill = (int)Math.Ceiling(RawStr / 100.0) * (int)Math.Ceiling(Deaths / 2.0); + + PenaltySkill -= (int)(healer.Skills[SkillName.Veterinary].Value - 90); + + foreach (Item i in GetItemsInRange(5)) + { + if (!(i is Corpse)) continue; // si l'objet n'est pas un corps on ne traite pas cet objet mais on continue + Corpse c = i as Corpse; // on caste en corp + if (c.Owner == this) // si le owner du corp est le dragon on arr�te la boucle et on met le corps trouv� dans corp + { + PenaltySkill--; + break; + } + } + + if (PenaltySkill < 1) + PenaltySkill = 1; + + return PenaltySkill; + } + + public virtual void ResurrectPet() + { + if (!IsDeadPet) + return; + + OnBeforeResurrect(); + + Poison = null; + + Warmode = false; + + Hits = 10; + Stam = StamMax; + Mana = 0; + + ProcessDeltaQueue(); + + IsDeadPet = false; + + Effects.SendPacket(Location, Map, new BondedStatus(0, this.Serial, 0)); + + this.SendIncomingPacket(); + this.SendIncomingPacket(); + + OnAfterResurrect(); + + Mobile owner = this.ControlMaster; + + if (owner == null || owner.Deleted || owner.Map != this.Map || !owner.InRange(this, 12) || !this.CanSee(owner) || !this.InLOS(owner)) + { + if (this.OwnerAbandonTime == DateTime.MinValue) + this.OwnerAbandonTime = DateTime.Now; + } + else + { + this.OwnerAbandonTime = DateTime.MinValue; + } + + CheckStatTimers(); + } + + public override bool CanBeDamaged() + { + if (IsDeadPet || IsInvulnerable) + return false; + + return base.CanBeDamaged(); + } + + public virtual bool PlayerRangeSensitive { get { return (this.CurrentWayPoint == null); } } //If they are following a waypoint, they'll continue to follow it even if players aren't around + + private bool m_ReturnQueued; + + private bool IsSpawnerBound() + { + if ((Map != null) && (Map != Map.Internal)) + { + if (FightMode != FightMode.None && (RangeHome >= 0)) + { + if (!Controlled && !Summoned) + { + if (Spawner != null && Spawner is Spawner && ((Spawner as Spawner).Map) == Map) + { + return true; + } + } + } + } + + return false; + } + + public virtual bool ReturnsToHome + { + get + { + return (m_SeeksHome && (Home != Point3D.Zero) && !m_ReturnQueued && !Controlled && !Summoned); + } + } + + public override void OnSectorDeactivate() + { + if (!Deleted && ReturnsToHome && IsSpawnerBound() && !this.InRange(Home, (RangeHome + 5))) + { + Timer.DelayCall(TimeSpan.FromSeconds((Utility.Random(45) + 15)), new TimerCallback(GoHome_Callback)); + + m_ReturnQueued = true; + } + else if (PlayerRangeSensitive && m_AI != null) + { + m_AI.Deactivate(); + } + + base.OnSectorDeactivate(); + } + + public void GoHome_Callback() + { + if (m_ReturnQueued && IsSpawnerBound()) + { + if (!((Map.GetSector(X, Y)).Active)) + { + this.SetLocation(Home, true); + + if (!((Map.GetSector(X, Y)).Active) && m_AI != null) + { + m_AI.Deactivate(); + } + } + } + + m_ReturnQueued = false; + } + + public override void OnSectorActivate() + { + if (PlayerRangeSensitive && m_AI != null) + m_AI.Activate(); + + base.OnSectorActivate(); + } + + private bool m_RemoveIfUntamed; + + // used for deleting untamed creatures [in houses] + private int m_RemoveStep; + + [CommandProperty(AccessLevel.GameMaster)] + public bool RemoveIfUntamed { get { return m_RemoveIfUntamed; } set { m_RemoveIfUntamed = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int RemoveStep { get { return m_RemoveStep; } set { m_RemoveStep = value; } } + } + + public class LoyaltyTimer : Timer + { + private static TimeSpan InternalDelay = TimeSpan.FromMinutes(5.0); + + public static void Initialize() + { + new LoyaltyTimer().Start(); + } + + public LoyaltyTimer() + : base(InternalDelay, InternalDelay) + { + m_NextHourlyCheck = DateTime.Now + TimeSpan.FromHours(1.0); + Priority = TimerPriority.FiveSeconds; + } + + private DateTime m_NextHourlyCheck; + + protected override void OnTick() + { + int d = 0; + try + { + if (DateTime.Now >= m_NextHourlyCheck) + m_NextHourlyCheck = DateTime.Now + TimeSpan.FromHours(1.0); + else + return; + + List toRelease = new List(); + + // added array for wild creatures in house regions to be removed + List toRemove = new List(); + + d = 1; + foreach (Mobile m in World.Mobiles.Values) + { + d = 2; + //Plume : ajout pour poteaux + if (m == null) + continue; + + d = 3; + if (m is BaseMount && ((BaseMount)m).Rider != null) + { + ((BaseCreature)m).OwnerAbandonTime = DateTime.MinValue; + continue; + } + + d = 4; + if (m is BaseCreature) + { + BaseCreature c = (BaseCreature)m; + + if (c.IsDeadPet) + { + Mobile owner = c.ControlMaster; + + if (!c.IsStabled && (owner == null || owner.Deleted || owner.Map != c.Map || !owner.InRange(c, 12) || !c.CanSee(owner) || !c.InLOS(owner))) + { + if (c.OwnerAbandonTime == DateTime.MinValue) + c.OwnerAbandonTime = DateTime.Now; + else if ((c.OwnerAbandonTime + c.BondingAbandonDelay) <= DateTime.Now) + toRemove.Add(c); + } + else + { + c.OwnerAbandonTime = DateTime.MinValue; + } + } + else if (c.Controlled && c.Commandable) + { + c.OwnerAbandonTime = DateTime.MinValue; + + if (c.Map != Map.Internal && c.ControlMaster != null) + { + c.Loyalty -= (BaseCreature.MaxLoyalty / 10); + + // Scriptiz : les dragons perdent plus ! + Type type = this.GetType(); + if (type == typeof(Dragon) || type == typeof(Drake) || type == typeof(WhiteWyrm) || type == typeof(AncientWyrm) || type == typeof(ShadowWyrm) || type == typeof(GreaterDragon)) + { + c.Loyalty -= (BaseCreature.MaxLoyalty / 5); + } + + if (c.Loyalty < (BaseCreature.MaxLoyalty / 10)) + { + c.Say(1043270, c.Name); // * ~1_NAME~ looks around desperately * + c.PlaySound(c.GetIdleSound()); + } + + if (c.Loyalty <= 0) + toRelease.Add(c); + } + } + + // added lines to check if a wild creature in a house region has to be removed or not + if (!c.Controlled && !c.IsStabled && ((c.Region.IsPartOf(typeof(HouseRegion)) && c.CanBeDamaged()) || (c.RemoveIfUntamed && c.Spawner == null))) + { + c.RemoveStep++; + + if (c.RemoveStep >= 20) + toRemove.Add(c); + } + else + { + c.RemoveStep = 0; + } + } + } + + d = 5; + foreach (BaseCreature c in toRelease) + { + c.Say(1043255, c.Name); // ~1_NAME~ appears to have decided that is better off without a master! + c.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy + c.IsBonded = false; + c.BondingBegin = DateTime.MinValue; + c.OwnerAbandonTime = DateTime.MinValue; + c.ControlTarget = null; + //c.ControlOrder = OrderType.Release; + c.AIObject.DoOrderRelease(); // this will prevent no release of creatures left alone with AI disabled (and consequent bug of Followers) + c.DropBackpack(); + d = 6; + } + + d = 7; + // added code to handle removing of wild creatures in house regions + foreach (BaseCreature c in toRemove) + { + c.Delete(); + d = 8; + } + } + catch (Exception e) + { + Logging.DebugLog(String.Format("[BaseCreature] d = {0}\n\t{1}\n", d, e.Message)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Familiars/BaseFamiliar.cs b/Scripts/Mobiles/Familiars/BaseFamiliar.cs new file mode 100644 index 0000000..8ac6edf --- /dev/null +++ b/Scripts/Mobiles/Familiars/BaseFamiliar.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public abstract class BaseFamiliar : BaseCreature + { + public BaseFamiliar() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, .1, .1) + { + } + + public override bool BardImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override bool Commandable{ get{ return false; } } + + public override bool PlayerRangeSensitive { get { return false; } } + + private bool m_LastHidden; + + public virtual void RangeCheck() + { + if (!Deleted && ControlMaster != null && !ControlMaster.Deleted) + { + int range = (RangeHome - 2); + + if (!InRange(ControlMaster.Location, RangeHome)) + { + Mobile master = ControlMaster; + + Point3D m_Loc = Point3D.Zero; + + if (Map == master.Map) + { + int x = (X > master.X) ? (master.X + range) : (master.X - range); + int y = (Y > master.Y) ? (master.Y + range) : (master.Y - range); + + for (int i = 0; i < 10; i++) + { + m_Loc.X = x + Utility.RandomMinMax(-1, 1); + m_Loc.Y = y + Utility.RandomMinMax(-1, 1); + + m_Loc.Z = Map.GetAverageZ(m_Loc.X, m_Loc.Y); + + if (Map.CanSpawnMobile(m_Loc)) + { + break; + } + + m_Loc = master.Location; + } + + if (!Deleted) + { + SetLocation(m_Loc, true); + } + } + } + } + } + + public override void OnThink() + { + Mobile master = ControlMaster; + + if (Deleted) + { + return; + } + if (master == null || master.Deleted) + { + DropPackContents(); + EndRelease(null); + return; + } + + RangeCheck(); + + if (m_LastHidden != master.Hidden) + Hidden = m_LastHidden = master.Hidden; + + if (AIObject != null && AIObject.WalkMobileRange(master, 5, true, 1, 1)) + { + Warmode = master.Warmode; + Combatant = master.Combatant; + + CurrentSpeed = 0.10; + } + else + { + Warmode = false; + FocusMob = Combatant = null; + + CurrentSpeed = .01; + } + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( from.Alive && Controlled && from == ControlMaster && from.InRange( this, 14 ) ) + list.Add( new ReleaseEntry( from, this ) ); + } + + public virtual void BeginRelease( Mobile from ) + { + if ( !Deleted && Controlled && from == ControlMaster && from.CheckAlive() ) + EndRelease( from ); + } + + public virtual void EndRelease( Mobile from ) + { + if ( from == null || (!Deleted && Controlled && from == ControlMaster && from.CheckAlive()) ) + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 1, 13, 2100, 3, 5042, 0 ); + PlaySound( 0x201 ); + Delete(); + } + } + + public virtual void DropPackContents() + { + Map map = this.Map; + Container pack = this.Backpack; + + if ( map != null && map != Map.Internal && pack != null ) + { + List list = new List( pack.Items ); + + for ( int i = 0; i < list.Count; ++i ) + list[i].MoveToWorld( Location, map ); + } + } + + public BaseFamiliar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + ValidationQueue.Add(this); + } + + public void Validate() + { + DropPackContents(); + Delete(); + } + + private class ReleaseEntry : ContextMenuEntry + { + private Mobile m_From; + private BaseFamiliar m_Familiar; + + public ReleaseEntry( Mobile from, BaseFamiliar familiar ) : base( 6118, 14 ) + { + m_From = from; + m_Familiar = familiar; + } + + public override void OnClick() + { + if ( !m_Familiar.Deleted && m_Familiar.Controlled && m_From == m_Familiar.ControlMaster && m_From.CheckAlive() ) + m_Familiar.BeginRelease( m_From ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Familiars/DarkWolf.cs b/Scripts/Mobiles/Familiars/DarkWolf.cs new file mode 100644 index 0000000..dcbf18a --- /dev/null +++ b/Scripts/Mobiles/Familiars/DarkWolf.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de loup noir" )] + public class DarkWolfFamiliar : BaseFamiliar + { + public DarkWolfFamiliar() + { + Name = "Un loup noir"; + Body = 99; + Hue = 0x901; + BaseSoundID = 0xE5; + + SetStr( 100 ); + SetDex( 90 ); + SetInt( 90 ); + + SetHits( 60 ); + SetStam( 90 ); + SetMana( 0 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 25, 40 ); + SetResistance( ResistanceType.Cold, 25, 40 ); + SetResistance( ResistanceType.Poison, 25, 40 ); + SetResistance( ResistanceType.Energy, 25, 40 ); + + SetSkill( SkillName.Wrestling, 85.1, 90.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + + ControlSlots = 1; + } + + private DateTime m_NextRestore; + + public override void OnThink() + { + base.OnThink(); + + if ( DateTime.Now < m_NextRestore ) + return; + + m_NextRestore = DateTime.Now + TimeSpan.FromSeconds( 2.0 ); + + Mobile caster = ControlMaster; + + if ( caster == null ) + caster = SummonMaster; + + if ( caster != null ) + ++caster.Stam; + } + + public DarkWolfFamiliar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Familiars/DeathAdder.cs b/Scripts/Mobiles/Familiars/DeathAdder.cs new file mode 100644 index 0000000..fe285f3 --- /dev/null +++ b/Scripts/Mobiles/Familiars/DeathAdder.cs @@ -0,0 +1,58 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de vip�re des t�n�bres" )] + public class DeathAdder : BaseFamiliar + { + public DeathAdder() + { + Name = "Une vip�re des t�n�bres"; + Body = 0x15; + Hue = 0x455; + BaseSoundID = 219; + + SetStr( 70 ); + SetDex( 150 ); + SetInt( 100 ); + + SetHits( 50 ); + SetStam( 150 ); + SetMana( 0 ); + + SetDamage( 1, 4 ); + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10 ); + SetResistance( ResistanceType.Poison, 100 ); + + SetSkill( SkillName.Wrestling, 90.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + SetSkill( SkillName.MagicResist, 100.0 ); + SetSkill( SkillName.Poisoning, 150.0 ); + + ControlSlots = 1; + } + + public override Poison HitPoison{ get{ return (0.8 >= Utility.RandomDouble() ? Poison.Greater : Poison.Deadly); } } + + public DeathAdder( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Familiars/HordeMinion.cs b/Scripts/Mobiles/Familiars/HordeMinion.cs new file mode 100644 index 0000000..6fe79aa --- /dev/null +++ b/Scripts/Mobiles/Familiars/HordeMinion.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de serviteur de la horde" )] + public class HordeMinionFamiliar : BaseFamiliar + { + public override bool DisplayWeight{ get { return true; } } + + public HordeMinionFamiliar() + { + Name = "Un serviteur de la horde"; + Body = 776; + BaseSoundID = 0x39D; + + SetStr( 100 ); + SetDex( 110 ); + SetInt( 100 ); + + SetHits( 70 ); + SetStam( 110 ); + SetMana( 0 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 50, 55 ); + SetResistance( ResistanceType.Poison, 25, 30 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.Wrestling, 70.1, 75.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + + ControlSlots = 1; + + Container pack = Backpack; + + if ( pack != null ) + pack.Delete(); + + pack = new Backpack(); + pack.Movable = false; + pack.Weight = 13.0; + + AddItem( pack ); + } + + private DateTime m_NextPickup; + + public override void OnThink() + { + base.OnThink(); + + if ( DateTime.Now < m_NextPickup ) + return; + + m_NextPickup = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 10 ) ); + + Container pack = this.Backpack; + + if ( pack == null ) + return; + + ArrayList list = new ArrayList(); + + foreach ( Item item in this.GetItemsInRange( 2 ) ) + { + if ( item.Movable && item.Stackable ) + list.Add( item ); + } + + int pickedUp = 0; + + for ( int i = 0; i < list.Count; ++i ) + { + Item item = (Item)list[i]; + + if ( !pack.CheckHold( this, item, false, true ) ) + return; + + bool rejected; + LRReason reject; + + NextActionTime = DateTime.Now; + + Lift( item, item.Amount, out rejected, out reject ); + + if ( rejected ) + continue; + + Drop( this, Point3D.Zero ); + + if ( ++pickedUp == 3 ) + break; + } + } + + private void ConfirmRelease_Callback( Mobile from, bool okay, object state ) + { + if ( okay ) + EndRelease( from ); + } + + public override void BeginRelease( Mobile from ) + { + Container pack = this.Backpack; + + if ( pack != null && pack.Items.Count > 0 ) + from.SendGump( new WarningGump( 1060635, 30720, 1061672, 32512, 420, 280, new WarningGumpCallback( ConfirmRelease_Callback ), null ) ); + else + EndRelease( from ); + } + + #region Pack Animal Methods + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + PackAnimal.CombineBackpacks( this ); + + return true; + } + + public override DeathMoveResult GetInventoryMoveResultFor( Item item ) + { + return DeathMoveResult.MoveToCorpse; + } + + public override bool IsSnoop( Mobile from ) + { + if ( PackAnimal.CheckAccess( this, from ) ) + return false; + + return base.IsSnoop( from ); + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( CheckFeed( from, item ) ) + return true; + + if ( PackAnimal.CheckAccess( this, from ) ) + { + AddToBackpack( item ); + return true; + } + + return base.OnDragDrop( from, item ); + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override bool CheckNonlocalLift( Mobile from, Item item ) + { + return PackAnimal.CheckAccess( this, from ); + } + + public override void OnDoubleClick( Mobile from ) + { + PackAnimal.TryPackOpen( this, from ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + PackAnimal.GetContextMenuEntries( this, from, list ); + } + #endregion + + public HordeMinionFamiliar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Familiars/ShadowWisp.cs b/Scripts/Mobiles/Familiars/ShadowWisp.cs new file mode 100644 index 0000000..f9e5e72 --- /dev/null +++ b/Scripts/Mobiles/Familiars/ShadowWisp.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "Un cords d'�clat d'ombre" )] + public class ShadowWispFamiliar : BaseFamiliar + { + public ShadowWispFamiliar() + { + Name = "Un �clat d'ombre"; + Body = 165; + Hue = 0x901; + BaseSoundID = 466; + + SetStr( 50 ); + SetDex( 60 ); + SetInt( 100 ); + + SetHits( 50 ); + SetStam( 60 ); + SetMana( 0 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Energy, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 99 ); + + SetSkill( SkillName.Wrestling, 40.0 ); + SetSkill( SkillName.Tactics, 40.0 ); + + ControlSlots = 1; + } + + private DateTime m_NextFlare; + + public override void OnThink() + { + base.OnThink(); + + if ( DateTime.Now < m_NextFlare ) + return; + + m_NextFlare = DateTime.Now + TimeSpan.FromSeconds( 5.0 + (25.0 * Utility.RandomDouble()) ); + + this.FixedEffect( 0x37C4, 1, 12, 1109, 6 ); + this.PlaySound( 0x1D3 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), new TimerCallback( Flare ) ); + } + + private void Flare() + { + Mobile caster = this.ControlMaster; + + if ( caster == null ) + caster = this.SummonMaster; + + if ( caster == null ) + return; + + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 5 ) ) + { + if ( m.Player && m.Alive && !m.IsDeadBondedPet && m.Karma <= 0 && m.AccessLevel < AccessLevel.Counselor ) + list.Add( m ); + } + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + bool friendly = true; + + for ( int j = 0; friendly && j < caster.Aggressors.Count; ++j ) + friendly = ( caster.Aggressors[j].Attacker != m ); + + for ( int j = 0; friendly && j < caster.Aggressed.Count; ++j ) + friendly = ( caster.Aggressed[j].Defender != m ); + + if ( friendly ) + { + m.FixedEffect( 0x37C4, 1, 12, 1109, 3 ); // At player + m.Mana += 1 - (m.Karma / 1000); + } + } + } + + public ShadowWispFamiliar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Familiars/VampireBat.cs b/Scripts/Mobiles/Familiars/VampireBat.cs new file mode 100644 index 0000000..fc12748 --- /dev/null +++ b/Scripts/Mobiles/Familiars/VampireBat.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de chauve-souris vampire" )] + public class VampireBatFamiliar : BaseFamiliar + { + public VampireBatFamiliar() + { + Name = "Une chauve-souris vampire"; + Body = 317; + BaseSoundID = 0x270; + + SetStr( 120 ); + SetDex( 120 ); + SetInt( 100 ); + + SetHits( 90 ); + SetStam( 120 ); + SetMana( 0 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.Wrestling, 95.1, 100.0 ); + SetSkill( SkillName.Tactics, 50.0 ); + + ControlSlots = 1; + } + + public VampireBatFamiliar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Guards/ArcherGuard.cs b/Scripts/Mobiles/Guards/ArcherGuard.cs new file mode 100644 index 0000000..3aebf75 --- /dev/null +++ b/Scripts/Mobiles/Guards/ArcherGuard.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + public class ArcherGuard : BaseGuard + { + private Timer m_AttackTimer, m_IdleTimer; + + private Mobile m_Focus; + + [Constructable] + public ArcherGuard() : this( null ) + { + } + + public ArcherGuard( Mobile target ) : base( target ) + { + InitStats( 100, 125, 25 ); + + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + Title = "la garde"; + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + Title = "le garde"; + } + + new Horse().Rider = this; + + AddItem( new StuddedChest() ); + AddItem( new StuddedArms() ); + AddItem( new StuddedGloves() ); + AddItem( new StuddedGorget() ); + AddItem( new StuddedLegs() ); + AddItem( new Boots() ); + AddItem( new SkullCap() ); + + Bow bow = new Bow(); + + bow.Movable = false; + bow.Crafter = this; + bow.Quality = WeaponQuality.Exceptional; + + AddItem( bow ); + + Container pack = new Backpack(); + + pack.Movable = false; + + Arrow arrows = new Arrow( 250 ); + + arrows.LootType = LootType.Newbied; + + pack.DropItem( arrows ); + pack.DropItem( new Gold( 10, 25 ) ); + + AddItem( pack ); + + Skills[SkillName.Anatomy].Base = 120.0; + Skills[SkillName.Tactics].Base = 120.0; + Skills[SkillName.Archery].Base = 120.0; + Skills[SkillName.MagicResist].Base = 120.0; + Skills[SkillName.DetectHidden].Base = 100.0; + + this.NextCombatTime = DateTime.Now + TimeSpan.FromSeconds( 0.5 ); + this.Focus = target; + } + + public ArcherGuard( Serial serial ) : base( serial ) + { + } + + public override bool OnBeforeDeath() + { + if ( m_Focus != null && m_Focus.Alive ) + new AvengeTimer( m_Focus ).Start(); // If a guard dies, three more guards will spawn + + return base.OnBeforeDeath(); + } + + [CommandProperty( AccessLevel.GameMaster )] + public override Mobile Focus + { + get + { + return m_Focus; + } + set + { + if ( Deleted ) + return; + + Mobile oldFocus = m_Focus; + + if ( oldFocus != value ) + { + m_Focus = value; + + if ( value != null ) + this.AggressiveAction( value ); + + Combatant = value; + + if ( oldFocus != null && !oldFocus.Alive ) + Say( "Thou hast suffered thy punishment, scoundrel." ); + + if ( value != null ) + Say( 500131 ); // Thou wilt regret thine actions, swine! + + if ( m_AttackTimer != null ) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if ( m_IdleTimer != null ) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + if ( m_Focus != null ) + { + m_AttackTimer = new AttackTimer( this ); + m_AttackTimer.Start(); + ((AttackTimer)m_AttackTimer).DoOnTick(); + } + else + { + m_IdleTimer = new IdleTimer( this ); + m_IdleTimer.Start(); + } + } + else if ( m_Focus == null && m_IdleTimer == null ) + { + m_IdleTimer = new IdleTimer( this ); + m_IdleTimer.Start(); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Focus ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Focus = reader.ReadMobile(); + + if ( m_Focus != null ) + { + m_AttackTimer = new AttackTimer( this ); + m_AttackTimer.Start(); + } + else + { + m_IdleTimer = new IdleTimer( this ); + m_IdleTimer.Start(); + } + + break; + } + } + } + + public override void OnAfterDelete() + { + if ( m_AttackTimer != null ) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if ( m_IdleTimer != null ) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + base.OnAfterDelete(); + } + + private class AvengeTimer : Timer + { + private Mobile m_Focus; + + public AvengeTimer( Mobile focus ) : base( TimeSpan.FromSeconds( 2.5 ), TimeSpan.FromSeconds( 1.0 ), 3 ) // After 2.5 seconds, one guard will spawn every 1.0 second, three times + { + m_Focus = focus; + } + + protected override void OnTick() + { + BaseGuard.Spawn( m_Focus, m_Focus, 1, true ); + } + } + + private class AttackTimer : Timer + { + private ArcherGuard m_Owner; + // private bool m_Shooting; + + public AttackTimer( ArcherGuard owner ) : base( TimeSpan.FromSeconds( 0.25 ), TimeSpan.FromSeconds( 0.1 ) ) + { + m_Owner = owner; + } + + public void DoOnTick() + { + OnTick(); + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + m_Owner.Criminal = false; + m_Owner.Kills = 0; + m_Owner.Stam = m_Owner.StamMax; + + Mobile target = m_Owner.Focus; + + if ( target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful( target )) ) + { + m_Owner.Focus = null; + Stop(); + return; + } + else if ( m_Owner.Weapon is Fists ) + { + m_Owner.Kill(); + Stop(); + return; + } + + if ( target != null && m_Owner.Combatant != target ) + m_Owner.Combatant = target; + + if ( target == null ) + { + Stop(); + } + else + {// + TeleportTo( target ); + target.BoltEffect( 0 ); + + if ( target is BaseCreature ) + ((BaseCreature)target).NoKillAwards = true; + + target.Damage( target.HitsMax, m_Owner ); + target.Kill(); // just in case, maybe Damage is overriden on some shard + + if ( target.Corpse != null && !target.Player ) + target.Corpse.Delete(); + + m_Owner.Focus = null; + Stop(); + }// + /*else if ( !m_Owner.InRange( target, 20 ) ) + { + m_Shooting = false; + m_Owner.Focus = null; + } + else if ( !m_Owner.InLOS( target ) ) + { + m_Shooting = false; + TeleportTo( target ); + } + else if ( !m_Owner.CanSee( target ) ) + { + m_Shooting = false; + + if ( !m_Owner.InRange( target, 2 ) ) + { + if ( !m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ) ) + TeleportTo( target ); + } + else + { + if ( !m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0 ) + m_Owner.Say( "Reveal!" ); + } + } + else + { + if ( m_Shooting && (TimeToSpare() || OutOfMaxDistance( target )) ) + m_Shooting = false; + else if ( !m_Shooting && InMinDistance( target ) ) + m_Shooting = true; + + if ( !m_Shooting ) + { + if ( m_Owner.InRange( target, 1 ) ) + { + if ( !m_Owner.Move( (Direction)(m_Owner.GetDirectionTo( target ) - 4) | Direction.Running ) && OutOfMaxDistance( target ) ) // Too close, move away + TeleportTo( target ); + } + else if ( !m_Owner.InRange( target, 2 ) ) + { + if ( !m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ) ) + TeleportTo( target ); + } + } + }*/ + } + + private bool TimeToSpare() + { + return (m_Owner.NextCombatTime - DateTime.Now) > TimeSpan.FromSeconds( 1.0 ); + } + + private bool OutOfMaxDistance( Mobile target ) + { + return !m_Owner.InRange( target, m_Owner.Weapon.MaxRange ); + } + + private bool InMinDistance( Mobile target ) + { + return m_Owner.InRange( target, 4 ); + } + + private void TeleportTo( Mobile target ) + { + Point3D from = m_Owner.Location; + Point3D to = target.Location; + + m_Owner.Location = to; + + Effects.SendLocationParticles( EffectItem.Create( from, m_Owner.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + Effects.SendLocationParticles( EffectItem.Create( to, m_Owner.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + + m_Owner.PlaySound( 0x1FE ); + } + } + + private class IdleTimer : Timer + { + private ArcherGuard m_Owner; + private int m_Stage; + + public IdleTimer( ArcherGuard owner ) : base( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.5 ) ) + { + m_Owner = owner; + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + if ( (m_Stage++ % 4) == 0 || !m_Owner.Move( m_Owner.Direction ) ) + m_Owner.Direction = (Direction)Utility.Random( 8 ); + + if ( m_Stage > 16 ) + { + Effects.SendLocationParticles( EffectItem.Create( m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + m_Owner.PlaySound( 0x1FE ); + + m_Owner.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Guards/BaseGuard.cs b/Scripts/Mobiles/Guards/BaseGuard.cs new file mode 100644 index 0000000..05da1a7 --- /dev/null +++ b/Scripts/Mobiles/Guards/BaseGuard.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + public abstract class BaseGuard : Mobile + { + public static void Spawn( Mobile caller, Mobile target ) + { + Spawn( caller, target, 1, false ); + } + + public static void Spawn( Mobile caller, Mobile target, int amount, bool onlyAdditional ) + { + if ( target == null || target.Deleted ) + return; + + foreach ( Mobile m in target.GetMobilesInRange( 15 ) ) + { + if ( m is BaseGuard ) + { + BaseGuard g = (BaseGuard)m; + + if ( g.Focus == null ) // idling + { + g.Focus = target; + + --amount; + } + else if ( g.Focus == target && !onlyAdditional ) + { + --amount; + } + } + } + + while ( amount-- > 0 ) + caller.Region.MakeGuard( target ); + } + + public BaseGuard( Mobile target ) + { + if ( target != null ) + { + Location = target.Location; + Map = target.Map; + + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + } + } + + public BaseGuard( Serial serial ) : base( serial ) + { + } + + public override bool OnBeforeDeath() + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + + PlaySound( 0x1FE ); + + Delete(); + + return false; + } + + public abstract Mobile Focus{ get; set; } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Guards/WarriorGuard.cs b/Scripts/Mobiles/Guards/WarriorGuard.cs new file mode 100644 index 0000000..2ba9d31 --- /dev/null +++ b/Scripts/Mobiles/Guards/WarriorGuard.cs @@ -0,0 +1,371 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class WarriorGuard : BaseGuard + { + private Timer m_AttackTimer, m_IdleTimer; + + private Mobile m_Focus; + + [Constructable] + public WarriorGuard() : this( null ) + { + } + + public WarriorGuard( Mobile target ) : base( target ) + { + InitStats( 1000, 1000, 1000 ); + + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + Title = "la garde"; + + switch( Utility.Random( 2 ) ) + { + case 0: AddItem( new LeatherSkirt() ); break; + case 1: AddItem( new LeatherShorts() ); break; + } + + switch( Utility.Random( 5 ) ) + { + case 0: AddItem( new FemaleLeatherChest() ); break; + case 1: AddItem( new FemaleStuddedChest() ); break; + case 2: AddItem( new LeatherBustierArms() ); break; + case 3: AddItem( new StuddedBustierArms() ); break; + case 4: AddItem( new FemalePlateChest() ); break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + Title = "le garde"; + + AddItem( new PlateChest() ); + AddItem( new PlateArms() ); + AddItem( new PlateLegs() ); + + switch( Utility.Random( 3 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomNondyedHue() ) ); break; + case 1: AddItem( new Tunic( Utility.RandomNondyedHue() ) ); break; + case 2: AddItem( new BodySash( Utility.RandomNondyedHue() ) ); break; + } + } + Utility.AssignRandomHair( this ); + + if( Utility.RandomBool() ) + Utility.AssignRandomFacialHair( this, HairHue ); + + Halberd weapon = new Halberd(); + + weapon.Movable = false; + weapon.Crafter = this; + weapon.Quality = WeaponQuality.Exceptional; + + AddItem( weapon ); + + Container pack = new Backpack(); + + pack.Movable = false; + + pack.DropItem( new Gold( 10, 25 ) ); + + AddItem( pack ); + + Skills[SkillName.Anatomy].Base = 120.0; + Skills[SkillName.Tactics].Base = 120.0; + Skills[SkillName.Swords].Base = 120.0; + Skills[SkillName.MagicResist].Base = 120.0; + Skills[SkillName.DetectHidden].Base = 100.0; + + this.NextCombatTime = DateTime.Now + TimeSpan.FromSeconds( 0.5 ); + this.Focus = target; + } + + public WarriorGuard( Serial serial ) : base( serial ) + { + } + + public override bool OnBeforeDeath() + { + if ( m_Focus != null && m_Focus.Alive ) + new AvengeTimer( m_Focus ).Start(); // If a guard dies, three more guards will spawn + + return base.OnBeforeDeath(); + } + + [CommandProperty( AccessLevel.GameMaster )] + public override Mobile Focus + { + get + { + return m_Focus; + } + set + { + if ( Deleted ) + return; + + Mobile oldFocus = m_Focus; + + if ( oldFocus != value ) + { + m_Focus = value; + + if ( value != null ) + this.AggressiveAction( value ); + + Combatant = value; + + if ( oldFocus != null && !oldFocus.Alive ) + Say( "Thou hast suffered thy punishment, scoundrel." ); + + if ( value != null ) + Say( 500131 ); // Thou wilt regret thine actions, swine! + + if ( m_AttackTimer != null ) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if ( m_IdleTimer != null ) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + if ( m_Focus != null ) + { + m_AttackTimer = new AttackTimer( this ); + m_AttackTimer.Start(); + ((AttackTimer)m_AttackTimer).DoOnTick(); + } + else + { + m_IdleTimer = new IdleTimer( this ); + m_IdleTimer.Start(); + } + } + else if ( m_Focus == null && m_IdleTimer == null ) + { + m_IdleTimer = new IdleTimer( this ); + m_IdleTimer.Start(); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Focus ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Focus = reader.ReadMobile(); + + if ( m_Focus != null ) + { + m_AttackTimer = new AttackTimer( this ); + m_AttackTimer.Start(); + } + else + { + m_IdleTimer = new IdleTimer( this ); + m_IdleTimer.Start(); + } + + break; + } + } + } + + public override void OnAfterDelete() + { + if ( m_AttackTimer != null ) + { + m_AttackTimer.Stop(); + m_AttackTimer = null; + } + + if ( m_IdleTimer != null ) + { + m_IdleTimer.Stop(); + m_IdleTimer = null; + } + + base.OnAfterDelete(); + } + + private class AvengeTimer : Timer + { + private Mobile m_Focus; + + public AvengeTimer( Mobile focus ) : base( TimeSpan.FromSeconds( 2.5 ), TimeSpan.FromSeconds( 1.0 ), 3 ) + { + m_Focus = focus; + } + + protected override void OnTick() + { + BaseGuard.Spawn( m_Focus, m_Focus, 1, true ); + } + } + + private class AttackTimer : Timer + { + private WarriorGuard m_Owner; + + public AttackTimer( WarriorGuard owner ) : base( TimeSpan.FromSeconds( 0.25 ), TimeSpan.FromSeconds( 0.1 ) ) + { + m_Owner = owner; + } + + public void DoOnTick() + { + OnTick(); + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + m_Owner.Criminal = false; + m_Owner.Kills = 0; + m_Owner.Stam = m_Owner.StamMax; + + Mobile target = m_Owner.Focus; + + if ( target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful( target )) ) + { + m_Owner.Focus = null; + Stop(); + return; + } + else if ( m_Owner.Weapon is Fists ) + { + m_Owner.Kill(); + Stop(); + return; + } + + if ( target != null && m_Owner.Combatant != target ) + m_Owner.Combatant = target; + + if ( target == null ) + { + Stop(); + } + else + {// + TeleportTo( target ); + target.BoltEffect( 0 ); + + if ( target is BaseCreature ) + ((BaseCreature)target).NoKillAwards = true; + + target.Damage( target.HitsMax, m_Owner ); + target.Kill(); // just in case, maybe Damage is overriden on some shard + + if ( target.Corpse != null && !target.Player ) + target.Corpse.Delete(); + + m_Owner.Focus = null; + Stop(); + }// + /*else if ( !m_Owner.InRange( target, 20 ) ) + { + m_Owner.Focus = null; + } + else if ( !m_Owner.InRange( target, 10 ) || !m_Owner.InLOS( target ) ) + { + TeleportTo( target ); + } + else if ( !m_Owner.InRange( target, 1 ) ) + { + if ( !m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) ) + TeleportTo( target ); + } + else if ( !m_Owner.CanSee( target ) ) + { + if ( !m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0 ) + m_Owner.Say( "Reveal!" ); + }*/ + } + + private void TeleportTo( Mobile target ) + { + Point3D from = m_Owner.Location; + Point3D to = target.Location; + + m_Owner.Location = to; + + Effects.SendLocationParticles( EffectItem.Create( from, m_Owner.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + Effects.SendLocationParticles( EffectItem.Create( to, m_Owner.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + + m_Owner.PlaySound( 0x1FE ); + } + } + + private class IdleTimer : Timer + { + private WarriorGuard m_Owner; + private int m_Stage; + + public IdleTimer( WarriorGuard owner ) : base( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.5 ) ) + { + m_Owner = owner; + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + if ( (m_Stage++ % 4) == 0 || !m_Owner.Move( m_Owner.Direction ) ) + m_Owner.Direction = (Direction)Utility.Random( 8 ); + + if ( m_Stage > 16 ) + { + Effects.SendLocationParticles( EffectItem.Create( m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + m_Owner.PlaySound( 0x1FE ); + + m_Owner.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/BaseHealer.cs b/Scripts/Mobiles/Healers/BaseHealer.cs new file mode 100644 index 0000000..060ce44 --- /dev/null +++ b/Scripts/Mobiles/Healers/BaseHealer.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Misc; +using Server.Items; +using Server.Gumps; + +namespace Server.Mobiles +{ + public abstract class BaseHealer : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool IsActiveVendor{ get{ return false; } } + public override bool IsInvulnerable{ get{ return false; } } + + public override void InitSBInfo() + { + } + + public BaseHealer() : base( null ) + { + if ( !IsInvulnerable ) + { + AI = AIType.AI_Mage; + ActiveSpeed = 0.2; + PassiveSpeed = 0.8; + RangePerception = BaseCreature.DefaultRangePerception; + FightMode = FightMode.Aggressor; + } + + SpeechHue = 0; + + SetStr( 304, 400 ); + SetDex( 102, 150 ); + SetInt( 204, 300 ); + + SetDamage( 10, 23 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 75.0, 97.5 ); + SetSkill( SkillName.EvalInt, 82.0, 100.0 ); + SetSkill( SkillName.Healing, 75.0, 97.5 ); + SetSkill( SkillName.Magery, 82.0, 100.0 ); + SetSkill( SkillName.MagicResist, 82.0, 100.0 ); + SetSkill( SkillName.Tactics, 82.0, 100.0 ); + + Fame = 1000; + Karma = 10000; + + PackItem( new Bandage( Utility.RandomMinMax( 5, 10 ) ) ); + PackItem( new HealPotion() ); + PackItem( new CurePotion() ); + } + + public override VendorShoeType ShoeType{ get{ return VendorShoeType.Sandals; } } + + public virtual int GetRobeColor() + { + return Utility.RandomYellowHue(); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Robe( GetRobeColor() ) ); + } + + public virtual bool HealsYoungPlayers{ get{ return true; } } + + public virtual bool CheckResurrect( Mobile m ) + { + return true; + } + + private DateTime m_NextResurrect; + private static TimeSpan ResurrectDelay = TimeSpan.FromSeconds( 2.0 ); + + public virtual void OfferResurrection( Mobile m ) + { + Direction = GetDirectionTo( m ); + + m.PlaySound(0x1F2); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, ResurrectMessage.Healer ) ); + } + + public virtual void OfferHeal( PlayerMobile m ) + { + Direction = GetDirectionTo( m ); + + if ( m.CheckYoungHealTime() ) + { + Say( "Vous semblez avoir besoin de soin" ); // You look like you need some healing my child. + + m.PlaySound( 0x1F2 ); + m.FixedEffect( 0x376A, 9, 32 ); + + m.Hits = m.HitsMax; + } + else + { + Say( "Je ne peux rien faire de plus pour vous" ); // I can do no more for you at this time. + } + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( !m.Frozen && DateTime.Now >= m_NextResurrect && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && InLOS( m ) ) + { + if ( !m.Alive ) + { + m_NextResurrect = DateTime.Now + ResurrectDelay; + + if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + SayTo(m, "Vous ne pouvez �tre ramen� � la vie ici" ); // Thou can not be resurrected there! + } + else if ( CheckResurrect( m ) ) + { + OfferResurrection( m ); + } + } + else if ( this.HealsYoungPlayers && m.Hits < m.HitsMax && m is PlayerMobile && ((PlayerMobile)m).Young ) + { + OfferHeal( (PlayerMobile) m ); + } + } + } + + public BaseHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + if ( !IsInvulnerable ) + { + AI = AIType.AI_Mage; + ActiveSpeed = 0.2; + PassiveSpeed = 0.8; + RangePerception = BaseCreature.DefaultRangePerception; + FightMode = FightMode.Aggressor; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/EvilHealer.cs b/Scripts/Mobiles/Healers/EvilHealer.cs new file mode 100644 index 0000000..1affa79 --- /dev/null +++ b/Scripts/Mobiles/Healers/EvilHealer.cs @@ -0,0 +1,70 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class EvilHealer : BaseHealer + { + public override bool CanTeach{ get{ return true; } } + + public override bool CheckTeach( SkillName skill, Mobile from ) + { + if ( !base.CheckTeach( skill, from ) ) + return false; + + return ( skill == SkillName.Forensics ) + || ( skill == SkillName.Healing ) + || ( skill == SkillName.SpiritSpeak ) + || ( skill == SkillName.Swords ); + } + + [Constructable] + public EvilHealer() + { + Title = Female? "la soigneuse": "le soigneur"; + + Karma = -10000; + + SetSkill( SkillName.Forensics, 80.0, 100.0 ); + SetSkill( SkillName.SpiritSpeak, 80.0, 100.0 ); + SetSkill( SkillName.Swords, 80.0, 100.0 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool IsActiveVendor{ get{ return true; } } + + public override void InitSBInfo() + { + SBInfos.Add( new SBHealer() ); + } + + public override bool CheckResurrect( Mobile m ) + { + if ( Core.AOS && m.Criminal ) + { + Say( "Vous avez mal agit, je ne peux vous aider pour l'instant" ); // Thou art a criminal. I shall not resurrect thee. + return false; + } + + return true; + } + + public EvilHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/EvilWanderingHealer.cs b/Scripts/Mobiles/Healers/EvilWanderingHealer.cs new file mode 100644 index 0000000..2b97cc5 --- /dev/null +++ b/Scripts/Mobiles/Healers/EvilWanderingHealer.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class EvilWanderingHealer : BaseHealer + { + public override bool CanTeach{ get{ return true; } } + + public override bool CheckTeach( SkillName skill, Mobile from ) + { + if ( !base.CheckTeach( skill, from ) ) + return false; + + return ( skill == SkillName.Anatomy ) + || ( skill == SkillName.Camping ) + || ( skill == SkillName.Forensics ) + || ( skill == SkillName.Healing ) + || ( skill == SkillName.SpiritSpeak ); + } + + [Constructable] + public EvilWanderingHealer() + { + Title = Female? "la pr�tresse de Mondain" : "le pr�tre de Mondain" ; + Karma = -10000; + + AddItem( new GnarledStaff() ); + + SetSkill( SkillName.Camping, 80.0, 100.0 ); + SetSkill( SkillName.Forensics, 80.0, 100.0 ); + SetSkill( SkillName.SpiritSpeak, 80.0, 100.0 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display title in OnSingleClick + + public override bool CheckResurrect( Mobile m ) + { + if ( Core.AOS && m.Criminal ) + { + Say("Vous avez mal agit, je ne peux vous aider pour l'instant"); // Thou art a criminal. I shall not resurrect thee. + return false; + } + + return true; + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.5) + c.DropItem(new FragmentOfAMap()); + } + + public EvilWanderingHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version < 1 && Title == "the wandering healer" && Core.AOS ) + Title = "the priest of Mondain"; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/FortuneTeller.cs b/Scripts/Mobiles/Healers/FortuneTeller.cs new file mode 100644 index 0000000..9fc840a --- /dev/null +++ b/Scripts/Mobiles/Healers/FortuneTeller.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class FortuneTeller : BaseHealer + { + public override bool CanTeach{ get{ return true; } } + + public override bool CheckTeach( SkillName skill, Mobile from ) + { + if ( !base.CheckTeach( skill, from ) ) + return false; + + return ( skill == SkillName.Anatomy ) + || ( skill == SkillName.Healing ) + || ( skill == SkillName.Forensics ) + || ( skill == SkillName.SpiritSpeak ); + } + + [Constructable] + public FortuneTeller() + { + Title = Female? "la diseuse de bonne aventure" : "le diseur de bonne aventure"; + + SetSkill( SkillName.Anatomy, 85.0, 100.0 ); + SetSkill( SkillName.Healing, 90.0, 100.0 ); + SetSkill( SkillName.Forensics, 75.0, 98.0 ); + SetSkill( SkillName.SpiritSpeak, 65.0, 88.0 ); + } + + public override bool IsActiveVendor{ get{ return true; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + SBInfos.Add( new SBMage() ); + SBInfos.Add( new SBFortuneTeller() ); + } + + public override int GetRobeColor() + { + return Utility.RandomBrightHue(); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem(new SkullCap(Utility.RandomBrightHue())); break; + case 1: AddItem(new WizardsHat(Utility.RandomBrightHue())); break; + case 2: AddItem(new Bandana(Utility.RandomBrightHue())); break; + } + + AddItem( new Spellbook() ); + } + + public FortuneTeller( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/Healer.cs b/Scripts/Mobiles/Healers/Healer.cs new file mode 100644 index 0000000..f595854 --- /dev/null +++ b/Scripts/Mobiles/Healers/Healer.cs @@ -0,0 +1,83 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class Healer : BaseHealer + { + public override bool CanTeach{ get{ return true; } } + + public override bool CheckTeach( SkillName skill, Mobile from ) + { + if ( !base.CheckTeach( skill, from ) ) + return false; + + return ( skill == SkillName.Forensics ) + || ( skill == SkillName.Healing ) + || ( skill == SkillName.SpiritSpeak ) + || ( skill == SkillName.Swords ); + } + + [Constructable] + public Healer() + { + Title = Female ? "la soigneuse" : "le soigneur"; + + if ( !Core.AOS ) + NameHue = 0x35; + + SetSkill( SkillName.Forensics, 80.0, 100.0 ); + SetSkill( SkillName.SpiritSpeak, 80.0, 100.0 ); + SetSkill( SkillName.Swords, 80.0, 100.0 ); + } + + public override bool IsActiveVendor{ get{ return true; } } + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + SBInfos.Add( new SBHealer() ); + } + + public override bool CheckResurrect( Mobile m ) + { + if ( m.Criminal ) + { + Say("Vous avez mal agit, je ne peux vous aider pour l'instant"); // Thou art a criminal. I shall not resurrect thee. + return false; + } + else if ( m.Kills >= 5 ) + { + Say("Vous m'appaissez de mauvaise fr�quentation, je ne vous aiderai pas"); // Thou'rt not a decent and good person. I shall not resurrect thee. + return false; + } + else if ( m.Karma < 0 ) + { + Say("Vous vous �tes �loign� du droit chemin, mais vous m�ritez une seconde chance" ); // Thou hast strayed from the path of virtue, but thou still deservest a second chance. + } + + return true; + } + + public Healer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Core.AOS && NameHue == 0x35 ) + NameHue = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/PricedHealer.cs b/Scripts/Mobiles/Healers/PricedHealer.cs new file mode 100644 index 0000000..0fe0613 --- /dev/null +++ b/Scripts/Mobiles/Healers/PricedHealer.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Gumps; + +namespace Server.Mobiles +{ + public class PricedHealer : BaseHealer + { + private int m_Price; + + [CommandProperty( AccessLevel.GameMaster )] + public int Price + { + get{ return m_Price; } + set{ m_Price = value; } + } + + [Constructable] + public PricedHealer() : this( 5000 ) + { + } + + [Constructable] + public PricedHealer( int price ) + { + m_Price = price; + + if ( !Core.AOS ) + NameHue = 0x35; + } + + public override bool IsInvulnerable{ get{ return true; } } + + public override void InitSBInfo() + { + } + + public override bool HealsYoungPlayers{ get{ return false; } } + + public override void OfferResurrection( Mobile m ) + { + Direction = GetDirectionTo( m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, this, m_Price ) ); + } + + public override bool CheckResurrect( Mobile m ) + { + return true; + } + + public PricedHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (int) m_Price ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Price = reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Healers/WanderingHealer.cs b/Scripts/Mobiles/Healers/WanderingHealer.cs new file mode 100644 index 0000000..133701c --- /dev/null +++ b/Scripts/Mobiles/Healers/WanderingHealer.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class WanderingHealer : BaseHealer + { + public override bool CanTeach{ get{ return true; } } + + public override bool CheckTeach( SkillName skill, Mobile from ) + { + if ( !base.CheckTeach( skill, from ) ) + return false; + + return ( skill == SkillName.Anatomy ) + || ( skill == SkillName.Camping ) + || ( skill == SkillName.Forensics ) + || ( skill == SkillName.Healing ) + || ( skill == SkillName.SpiritSpeak ); + } + + [Constructable] + public WanderingHealer() + { + Title = Female ? "la soigneuse itin�rante" : "le soigneur itin�rant"; + + AddItem( new GnarledStaff() ); + + SetSkill( SkillName.Camping, 80.0, 100.0 ); + SetSkill( SkillName.Forensics, 80.0, 100.0 ); + SetSkill( SkillName.SpiritSpeak, 80.0, 100.0 ); + } + + public override bool ClickTitle{ get{ return false; } } // Do not display title in OnSingleClick + + public override bool CheckResurrect( Mobile m ) + { + if ( m.Criminal ) + { + Say("Vous avez mal agit, je ne peux vous aider pour l'instant"); // Thou art a criminal. I shall not resurrect thee. + return false; + } + else if ( m.Kills >= 5 ) + { + Say("Vous m'appaissez de mauvaise fr�quentation, je ne vous aiderai pas"); // Thou'rt not a decent and good person. I shall not resurrect thee. + return false; + } + else if ( m.Karma < 0 ) + { + Say("Vous vous �tes �loign� du droit chemin, mais vous m�ritez une seconde chance"); // Thou hast strayed from the path of virtue, but thou still deservest a second chance. + } + + return true; + } + + public WanderingHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs b/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs new file mode 100644 index 0000000..51b7841 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/AbysmalHorror.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an abyssmal horror corpse" )] + public class AbysmalHorror : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return Utility.RandomBool() ? WeaponAbility.MortalStrike : WeaponAbility.WhirlwindAttack; + } + + public override bool IgnoreYoungProtection { get { return Core.ML; } } + + [Constructable] + public AbysmalHorror() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an abyssmal horror"; + Body = 312; + BaseSoundID = 0x451; + + SetStr( 401, 420 ); + SetDex( 81, 90 ); + SetInt( 401, 420 ); + + SetHits( 6000 ); + + SetDamage( 13, 17 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 100 ); + SetResistance( ResistanceType.Cold, 50, 55 ); + SetResistance( ResistanceType.Poison, 60, 65 ); + SetResistance( ResistanceType.Energy, 77, 80 ); + + SetSkill( SkillName.EvalInt, 200.0 ); + SetSkill( SkillName.Magery, 112.6, 117.5 ); + SetSkill( SkillName.Meditation, 200.0 ); + SetSkill( SkillName.MagicResist, 117.6, 120.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 84.1, 88.0 ); + + Fame = 26000; + Karma = -26000; + + VirtualArmor = 54; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( !Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance( this ) ) + DemonKnight.DistributeArtifact( this ); + } + + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public AbysmalHorror( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 357 ) + BaseSoundID = 0x451; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs b/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs new file mode 100644 index 0000000..876ab86 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/BoneDemon.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a bone demon corpse" )] + public class BoneDemon : BaseCreature + { + [Constructable] + public BoneDemon() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bone demon"; + Body = 308; + BaseSoundID = 0x48D; + + SetStr( 1000 ); + SetDex( 151, 175 ); + SetInt( 171, 220 ); + + SetHits( 3600 ); + + SetDamage( 34, 36 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 75 ); + SetResistance( ResistanceType.Fire, 60 ); + SetResistance( ResistanceType.Cold, 90 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 60 ); + + SetSkill( SkillName.DetectHidden, 80.0 ); + SetSkill( SkillName.EvalInt, 77.6, 87.5 ); + SetSkill( SkillName.Magery, 77.6, 87.5 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 50.1, 75.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 20000; + Karma = -20000; + + VirtualArmor = 44; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 8 ); + } + + public override bool BardImmune { get { return !Core.SE; } } + public override bool Unprovokable { get { return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public BoneDemon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/CrystalElemental.cs b/Scripts/Mobiles/Monsters/AOS/CrystalElemental.cs new file mode 100644 index 0000000..7089298 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/CrystalElemental.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a crystal elemental corpse" )] + public class CrystalElemental : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + [Constructable] + public CrystalElemental() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a crystal elemental"; + Body = 300; + BaseSoundID = 278; + + SetStr( 136, 160 ); + SetDex( 51, 65 ); + SetInt( 86, 110 ); + + SetHits( 150 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 55, 70 ); + + SetSkill( SkillName.EvalInt, 70.1, 75.0 ); + SetSkill( SkillName.Magery, 70.1, 75.0 ); + SetSkill( SkillName.Meditation, 65.1, 75.0 ); + SetSkill( SkillName.MagicResist, 80.1, 90.0 ); + SetSkill( SkillName.Tactics, 75.1, 85.0 ); + SetSkill( SkillName.Wrestling, 65.1, 75.0 ); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 54; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public CrystalElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs b/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs new file mode 100644 index 0000000..ad26be6 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/DarknightCreeper.cs @@ -0,0 +1,94 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a darknight creeper corpse" )] + public class DarknightCreeper : BaseCreature + { + public override bool IgnoreYoungProtection { get { return Core.ML; } } + + [Constructable] + public DarknightCreeper() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "darknight creeper" ); + Body = 313; + BaseSoundID = 0xE0; + + SetStr( 301, 330 ); + SetDex( 101, 110 ); + SetInt( 301, 330 ); + + SetHits( 4000 ); + + SetDamage( 22, 26 ); + + SetDamageType( ResistanceType.Physical, 85 ); + SetDamageType( ResistanceType.Poison, 15 ); + + SetResistance( ResistanceType.Physical, 60 ); + SetResistance( ResistanceType.Fire, 60 ); + SetResistance( ResistanceType.Cold, 100 ); + SetResistance( ResistanceType.Poison, 90 ); + SetResistance( ResistanceType.Energy, 75 ); + + SetSkill( SkillName.DetectHidden, 80.0 ); + SetSkill( SkillName.EvalInt, 118.1, 120.0 ); + SetSkill( SkillName.Magery, 112.6, 120.0 ); + SetSkill( SkillName.Meditation, 150.0 ); + SetSkill( SkillName.Poisoning, 120.0 ); + SetSkill( SkillName.MagicResist, 90.1, 90.9 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 90.9 ); + SetSkill(SkillName.Necromancy, 120.1, 130.0); + SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); + + Fame = 22000; + Karma = -22000; + + VirtualArmor = 34; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( !Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance( this ) ) + DemonKnight.DistributeArtifact( this ); + } + + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public DarknightCreeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 471 ) + BaseSoundID = 0xE0; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs b/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs new file mode 100644 index 0000000..42cea5d --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/DemonKnight.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a demon knight corpse" )] + public class DemonKnight : BaseCreature + { + public override bool IgnoreYoungProtection { get { return Core.ML; } } + + public static Type[] ArtifactRarity10 { get { return m_ArtifactRarity10; } } + public static Type[] ArtifactRarity11 { get { return m_ArtifactRarity11; } } + private static Type[] m_ArtifactRarity10 = new Type[] + { + typeof( LegacyOfTheDreadLord ), + typeof( TheTaskmaster ) + }; + + private static Type[] m_ArtifactRarity11 = new Type[] + { + typeof( TheDragonSlayer ), + typeof( ArmorOfFortune ), + typeof( GauntletsOfNobility ), + typeof( HelmOfInsight ), + typeof( HolyKnightsBreastplate ), + typeof( JackalsCollar ), + typeof( LeggingsOfBane ), + typeof( MidnightBracers ), + typeof( OrnateCrownOfTheHarrower ), + typeof( ShadowDancerLeggings ), + typeof( TunicOfFire ), + typeof( VoiceOfTheFallenKing ), + typeof( BraceletOfHealth ), + typeof( OrnamentOfTheMagician ), + typeof( RingOfTheElements ), + typeof( RingOfTheVile ), + typeof( Aegis ), + typeof( ArcaneShield ), + typeof( AxeOfTheHeavens ), + typeof( BladeOfInsanity ), + typeof( BoneCrusher ), + typeof( BreathOfTheDead ), + typeof( Frostbringer ), + typeof( SerpentsFang ), + typeof( StaffOfTheMagi ), + typeof( TheBeserkersMaul ), + typeof( TheDryadBow ), + typeof( DivineCountenance ), + typeof( HatOfTheMagi ), + typeof( HuntersHeaddress ), + typeof( SpiritOfTheTotem ) + }; + + public static Item CreateRandomArtifact() + { + if ( !Core.AOS ) + return null; + + int count = ( m_ArtifactRarity10.Length * 5 ) + ( m_ArtifactRarity11.Length * 4 ); + int random = Utility.Random( count ); + Type type; + + if ( random < ( m_ArtifactRarity10.Length * 5 ) ) + { + type = m_ArtifactRarity10[random / 5]; + } + else + { + random -= m_ArtifactRarity10.Length * 5; + type = m_ArtifactRarity11[random / 4]; + } + + return Loot.Construct( type ); + } + + public static Mobile FindRandomPlayer( BaseCreature creature ) + { + List rights = BaseCreature.GetLootingRights( creature.DamageEntries, creature.HitsMax ); + + for ( int i = rights.Count - 1; i >= 0; --i ) + { + DamageStore ds = rights[i]; + + if ( !ds.m_HasRight ) + rights.RemoveAt( i ); + } + + if ( rights.Count > 0 ) + return rights[Utility.Random( rights.Count )].m_Mobile; + + return null; + } + + public static void DistributeArtifact( BaseCreature creature ) + { + DistributeArtifact( creature, CreateRandomArtifact() ); + } + + public static void DistributeArtifact( BaseCreature creature, Item artifact ) + { + DistributeArtifact( FindRandomPlayer( creature ), artifact ); + } + + public static void DistributeArtifact( Mobile to ) + { + DistributeArtifact( to, CreateRandomArtifact() ); + } + + public static void DistributeArtifact( Mobile to, Item artifact ) + { + if ( to == null || artifact == null ) + return; + + Container pack = to.Backpack; + + if ( pack == null || !pack.TryDropItem( to, artifact, false ) ) + to.BankBox.DropItem( artifact ); + + to.SendLocalizedMessage( 1062317 ); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + + public static int GetArtifactChance( Mobile boss ) + { + if ( !Core.AOS ) + return 0; + + int luck = LootPack.GetLuckChanceForKiller( boss ); + int chance; + + if ( boss is DemonKnight ) + chance = 1500 + (luck / 5); + else + chance = 750 + (luck / 10); + + return chance; + } + + public static bool CheckArtifactChance( Mobile boss ) + { + return GetArtifactChance( boss ) > Utility.Random( 100000 ); + } + + public override WeaponAbility GetWeaponAbility() + { + switch ( Utility.Random( 3 ) ) + { + default: + case 0: return WeaponAbility.DoubleStrike; + case 1: return WeaponAbility.WhirlwindAttack; + case 2: return WeaponAbility.CrushingBlow; + } + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( !Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance( this ) ) + DemonKnight.DistributeArtifact( this ); + } + + [Constructable] + public DemonKnight() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "demon knight" ); + Title = "the Dark Father"; + Body = 318; + BaseSoundID = 0x165; + + SetStr( 500 ); + SetDex( 100 ); + SetInt( 1000 ); + + SetHits( 30000 ); + SetMana( 5000 ); + + SetDamage( 17, 21 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 30 ); + SetResistance( ResistanceType.Fire, 30 ); + SetResistance( ResistanceType.Cold, 30 ); + SetResistance( ResistanceType.Poison, 30 ); + SetResistance( ResistanceType.Energy, 30 ); + + SetSkill(SkillName.Necromancy, 120, 120.0); + SetSkill(SkillName.SpiritSpeak, 120.0, 120.0); + + SetSkill( SkillName.DetectHidden, 80.0 ); + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Magery, 100.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.MagicResist, 150.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + + Fame = 28000; + Karma = -28000; + + VirtualArmor = 64; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 2 ); + AddLoot( LootPack.HighScrolls, Utility.RandomMinMax( 6, 60 ) ); + } + + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + private static bool m_InHere; + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if ( from != null && from != this && !m_InHere ) + { + m_InHere = true; + AOS.Damage( from, this, Utility.RandomMinMax( 8, 20 ), 100, 0, 0, 0, 0 ); + + MovingEffect( from, 0xECA, 10, 0, false, false, 0, 0 ); + PlaySound( 0x491 ); + + if ( 0.05 > Utility.RandomDouble() ) + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( CreateBones_Callback ), from ); + + m_InHere = false; + } + } + + public virtual void CreateBones_Callback( object state ) + { + Mobile from = (Mobile)state; + Map map = from.Map; + + if ( map == null ) + return; + + int count = Utility.RandomMinMax( 1, 3 ); + + for ( int i = 0; i < count; ++i ) + { + int x = from.X + Utility.RandomMinMax( -1, 1 ); + int y = from.Y + Utility.RandomMinMax( -1, 1 ); + int z = from.Z; + + if ( !map.CanFit( x, y, z, 16, false, true ) ) + { + z = map.GetAverageZ( x, y ); + + if ( z == from.Z || !map.CanFit( x, y, z, 16, false, true ) ) + continue; + } + + UnholyBone bone = new UnholyBone(); + + bone.Hue = 0; + bone.Name = "unholy bones"; + bone.ItemID = Utility.Random( 0xECA, 9 ); + + bone.MoveToWorld( new Point3D( x, y, z ), map ); + } + } + + public DemonKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/Devourer.cs b/Scripts/Mobiles/Monsters/AOS/Devourer.cs new file mode 100644 index 0000000..46086fc --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/Devourer.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a devourer of souls corpse" )] + public class Devourer : BaseCreature + { + [Constructable] + public Devourer() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a devourer of souls"; + Body = 303; + BaseSoundID = 357; + + SetStr( 801, 950 ); + SetDex( 126, 175 ); + SetInt( 201, 250 ); + + SetHits( 650 ); + + SetDamage( 22, 26 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 90.1, 105.0 ); + SetSkill( SkillName.Tactics, 75.1, 85.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + + Fame = 9500; + Karma = -9500; + + VirtualArmor = 44; + + PackNecroReg( 24, 45 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int Meat{ get{ return 3; } } + + public Devourer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/FleshGolem.cs b/Scripts/Mobiles/Monsters/AOS/FleshGolem.cs new file mode 100644 index 0000000..29e7ce4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/FleshGolem.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a flesh golem corpse" )] + public class FleshGolem : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + [Constructable] + public FleshGolem() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a flesh golem"; + Body = 304; + BaseSoundID = 684; + + SetStr( 176, 200 ); + SetDex( 51, 75 ); + SetInt( 46, 70 ); + + SetHits( 106, 120 ); + + SetDamage( 18, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 50.1, 75.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 70.0 ); + + Fame = 1000; + Karma = -1800; + + VirtualArmor = 34; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public FleshGolem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs b/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs new file mode 100644 index 0000000..4a1c3f3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/FleshRenderer.cs @@ -0,0 +1,117 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a fleshrenderer corpse" )] + public class FleshRenderer : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return Utility.RandomBool() ? WeaponAbility.Dismount : WeaponAbility.ParalyzingBlow; + } + + public override bool IgnoreYoungProtection { get { return Core.ML; } } + + [Constructable] + public FleshRenderer() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fleshrenderer"; + Body = 315; + + SetStr( 401, 460 ); + SetDex( 201, 210 ); + SetInt( 221, 260 ); + + SetHits( 4500 ); + + SetDamage( 16, 20 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 70, 80 ); + + SetSkill( SkillName.DetectHidden, 80.0 ); + SetSkill( SkillName.MagicResist, 155.1, 160.0 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 23000; + Karma = -23000; + + VirtualArmor = 24; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( !Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance( this ) ) + DemonKnight.DistributeArtifact( this ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune { get { return !Core.SE; } } + public override bool Unprovokable { get { return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public override int GetAttackSound() + { + return 0x34C; + } + + public override int GetHurtSound() + { + return 0x354; + } + + public override int GetAngerSound() + { + return 0x34C; + } + + public override int GetIdleSound() + { + return 0x34C; + } + + public override int GetDeathSound() + { + return 0x354; + } + + public FleshRenderer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 660 ) + BaseSoundID = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/Gibberling.cs b/Scripts/Mobiles/Monsters/AOS/Gibberling.cs new file mode 100644 index 0000000..3976297 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/Gibberling.cs @@ -0,0 +1,73 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gibberling corpse" )] + public class Gibberling : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public Gibberling() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gibberling"; + Body = 307; + BaseSoundID = 422; + + SetStr( 141, 165 ); + SetDex( 101, 125 ); + SetInt( 56, 80 ); + + SetHits( 85, 99 ); + + SetDamage( 12, 17 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Fire, 40 ); + SetDamageType( ResistanceType.Energy, 60 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 45.1, 70.0 ); + SetSkill( SkillName.Tactics, 67.6, 92.5 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 27; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int TreasureMapLevel{ get{ return 1; } } + + public Gibberling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/GoreFiend.cs b/Scripts/Mobiles/Monsters/AOS/GoreFiend.cs new file mode 100644 index 0000000..d69f5a9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/GoreFiend.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gore fiend corpse" )] + public class GoreFiend : BaseCreature + { + [Constructable] + public GoreFiend() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gore fiend"; + Body = 305; + BaseSoundID = 224; + + SetStr( 161, 185 ); + SetDex( 41, 65 ); + SetInt( 46, 70 ); + + SetHits( 97, 111 ); + + SetDamage( 15, 21 ); + + SetDamageType( ResistanceType.Physical, 85 ); + SetDamageType( ResistanceType.Poison, 15 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 5, 15 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 40.1, 55.0 ); + SetSkill( SkillName.Tactics, 45.1, 70.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 24; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override int GetDeathSound() + { + return 1218; + } + + public override bool BleedImmune{ get{ return true; } } + + public GoreFiend( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/Impaler.cs b/Scripts/Mobiles/Monsters/AOS/Impaler.cs new file mode 100644 index 0000000..5bafac6 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/Impaler.cs @@ -0,0 +1,94 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an impaler corpse" )] + public class Impaler : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return Utility.RandomBool() ? WeaponAbility.MortalStrike : WeaponAbility.BleedAttack; + } + + public override bool IgnoreYoungProtection { get { return Core.ML; } } + + [Constructable] + public Impaler() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "impaler" ); + Body = 306; + BaseSoundID = 0x2A7; + + SetStr( 190 ); + SetDex( 45 ); + SetInt( 190 ); + + SetHits( 5000 ); + + SetDamage( 31, 35 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 90 ); + SetResistance( ResistanceType.Fire, 60 ); + SetResistance( ResistanceType.Cold, 75 ); + SetResistance( ResistanceType.Poison, 60 ); + SetResistance( ResistanceType.Energy, 100 ); + + SetSkill( SkillName.DetectHidden, 80.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.Poisoning, 160.0 ); + SetSkill( SkillName.MagicResist, 100.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 49; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( !Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance( this ) ) + DemonKnight.DistributeArtifact( this ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune { get { return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return (0.8 >= Utility.RandomDouble() ? Poison.Greater : Poison.Deadly); } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public Impaler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 1200 ) + BaseSoundID = 0x2A7; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/MoundOfMaggots.cs b/Scripts/Mobiles/Monsters/AOS/MoundOfMaggots.cs new file mode 100644 index 0000000..7002565 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/MoundOfMaggots.cs @@ -0,0 +1,66 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a maggoty corpse" )] // TODO: Corpse name? + public class MoundOfMaggots : BaseCreature + { + [Constructable] + public MoundOfMaggots() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a mound of maggots"; + Body = 319; + BaseSoundID = 898; + + SetStr( 61, 70 ); + SetDex( 61, 70 ); + SetInt( 10 ); + + SetMana( 0 ); + + SetDamage( 3, 9 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 90 ); + SetResistance( ResistanceType.Poison, 100 ); + + SetSkill( SkillName.Tactics, 50.0 ); + SetSkill( SkillName.Wrestling, 50.1, 60.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 24; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Gems ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public MoundOfMaggots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/PatchworkSkeleton.cs b/Scripts/Mobiles/Monsters/AOS/PatchworkSkeleton.cs new file mode 100644 index 0000000..080b6df --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/PatchworkSkeleton.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a patchwork skeletal corpse" )] + public class PatchworkSkeleton : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public PatchworkSkeleton() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a patchwork skeleton"; + Body = 309; + BaseSoundID = 0x48D; + + SetStr( 96, 120 ); + SetDex( 71, 95 ); + SetInt( 16, 40 ); + + SetHits( 58, 72 ); + + SetDamage( 18, 22 ); + + SetDamageType( ResistanceType.Physical, 85 ); + SetDamageType( ResistanceType.Cold, 15 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 70.1, 95.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 500; + Karma = -500; + + VirtualArmor = 54; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public PatchworkSkeleton( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/Ravager.cs b/Scripts/Mobiles/Monsters/AOS/Ravager.cs new file mode 100644 index 0000000..fe06ab3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/Ravager.cs @@ -0,0 +1,69 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ravager corpse" )] + public class Ravager : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return Utility.RandomBool() ? WeaponAbility.Dismount : WeaponAbility.CrushingBlow; + } + + [Constructable] + public Ravager() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a ravager"; + Body = 314; + BaseSoundID = 357; + + SetStr( 251, 275 ); + SetDex( 101, 125 ); + SetInt( 66, 90 ); + + SetHits( 161, 175 ); + + SetDamage( 15, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 50.1, 75.0 ); + SetSkill( SkillName.Tactics, 75.1, 100.0 ); + SetSkill( SkillName.Wrestling, 70.1, 90.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 54; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public Ravager( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/Revenant.cs b/Scripts/Mobiles/Monsters/AOS/Revenant.cs new file mode 100644 index 0000000..fd74194 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/Revenant.cs @@ -0,0 +1,183 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class Revenant : BaseCreature + { + private Mobile m_Target; + private DateTime m_ExpireTime; + + public override void DisplayPaperdollTo( Mobile to ) + { + // Do nothing + } + + public override Mobile ConstantFocus{ get{ return m_Target; } } + public override bool NoHouseRestrictions{ get{ return true; } } + + public override double DispelDifficulty{ get{ return 80.0; } } + public override double DispelFocus{ get{ return 20.0; } } + + public Revenant( Mobile caster, Mobile target, TimeSpan duration ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.18, 0.36 ) + { + Name = "a revenant"; + Body = 400; + Hue = 1; + // TODO: Sound values? + + double scalar = caster.Skills[SkillName.SpiritSpeak].Value * 0.01; + + m_Target = target; + m_ExpireTime = DateTime.Now + duration; + + SetStr( 200 ); + SetDex( 150 ); + SetInt( 150 ); + + SetDamage( 16, 17 ); + + // Bestiary says 50 phys 50 cold, animal lore says differently + SetDamageType( ResistanceType.Physical, 100 ); + + SetSkill( SkillName.MagicResist, 100.0 * scalar ); // magic resist is absolute value of spiritspeak + SetSkill( SkillName.Tactics, 100.0 ); // always 100 + SetSkill( SkillName.Swords, 100.0 * scalar ); // not displayed in animal lore but tests clearly show this is influenced + SetSkill( SkillName.DetectHidden, 75.0 * scalar ); + + scalar /= 1.2; + + SetResistance( ResistanceType.Physical, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar) ); + SetResistance( ResistanceType.Cold, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar) ); + SetResistance( ResistanceType.Fire, (int)(20 * scalar) ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40 + (int)(20 * scalar), 50 + (int)(20 * scalar) ); + + Fame = 0; + Karma = 0; + + ControlSlots = 3; + + VirtualArmor = 32; + + Item shroud = new DeathShroud(); + + shroud.Hue = 0x455; + + shroud.Movable = false; + + AddItem( shroud ); + + Halberd weapon = new Halberd(); + + weapon.Hue = 1; + weapon.Movable = false; + + AddItem( weapon ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public override bool BleedImmune{ get{ return true; } } + public override bool BardImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override void OnThink() + { + if ( !m_Target.Alive || DateTime.Now > m_ExpireTime ) + { + Kill(); + return; + } + else if ( Map != m_Target.Map || !InRange( m_Target, 15 ) ) + { + Map fromMap = Map; + Point3D from = Location; + + Map toMap = m_Target.Map; + Point3D to = m_Target.Location; + + if ( toMap != null ) + { + for ( int i = 0; i < 5; ++i ) + { + Point3D loc = new Point3D( to.X - 4 + Utility.Random( 9 ), to.Y - 4 + Utility.Random( 9 ), to.Z ); + + if ( toMap.CanSpawnMobile( loc ) ) + { + to = loc; + break; + } + else + { + loc.Z = toMap.GetAverageZ( loc.X, loc.Y ); + + if ( toMap.CanSpawnMobile( loc ) ) + { + to = loc; + break; + } + } + } + } + + Map = toMap; + Location = to; + + ProcessDelta(); + + Effects.SendLocationParticles( EffectItem.Create( from, fromMap, EffectItem.DefaultDuration ), 0x3728, 1, 13, 37, 7, 5023, 0 ); + FixedParticles( 0x3728, 1, 13, 5023, 37, 7, EffectLayer.Waist ); + + PlaySound( 0x37D ); + } + + if ( m_Target.Hidden && InRange( m_Target, 3 ) && DateTime.Now >= this.NextSkillTime && UseSkill( SkillName.DetectHidden ) ) + { + Target targ = this.Target; + + if ( targ != null ) + targ.Invoke( this, this ); + } + + Combatant = m_Target; + FocusMob = m_Target; + + if ( AIObject != null ) + AIObject.Action = ActionType.Combat; + + base.OnThink(); + } + + public override bool OnBeforeDeath() + { + Effects.PlaySound( Location, Map, 0x10B ); + Effects.SendLocationParticles( EffectItem.Create( Location, Map, TimeSpan.FromSeconds( 10.0 ) ), 0x37CC, 1, 50, 2101, 7, 9909, 0 ); + + Delete(); + return false; + } + + public Revenant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs b/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs new file mode 100644 index 0000000..c920dd9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/ShadowKnight.cs @@ -0,0 +1,196 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a shadow knight corpse" )] + public class ShadowKnight : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return Utility.RandomBool() ? WeaponAbility.ConcussionBlow : WeaponAbility.CrushingBlow; + } + + public override bool IgnoreYoungProtection { get { return Core.ML; } } + + [Constructable] + public ShadowKnight() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "shadow knight" ); + Title = "the Shadow Knight"; + Body = 311; + + SetStr( 250 ); + SetDex( 100 ); + SetInt( 100 ); + + SetHits( 2000 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Cold, 40 ); + + SetResistance( ResistanceType.Physical, 90 ); + SetResistance( ResistanceType.Fire, 65 ); + SetResistance( ResistanceType.Cold, 75 ); + SetResistance( ResistanceType.Poison, 75 ); + SetResistance( ResistanceType.Energy, 55 ); + + SetSkill( SkillName.Chivalry, 120.0 ); + SetSkill( SkillName.DetectHidden, 80.0 ); + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Magery, 100.0 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 25000; + Karma = -25000; + + VirtualArmor = 54; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( !Summoned && !NoKillAwards && DemonKnight.CheckArtifactChance( this ) ) + DemonKnight.DistributeArtifact( this ); + } + + public override int GetIdleSound() + { + return 0x2CE; + } + + public override int GetDeathSound() + { + return 0x2C1; + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override int GetAttackSound() + { + return 0x2C8; + } + + private Timer m_SoundTimer; + private bool m_HasTeleportedAway; + + public override void OnCombatantChange() + { + base.OnCombatantChange(); + + if ( Hidden && Combatant != null ) + Combatant = null; + } + + public virtual void SendTrackingSound() + { + if ( Hidden ) + { + Effects.PlaySound( this.Location, this.Map, 0x2C8 ); + Combatant = null; + } + else + { + Frozen = false; + + if ( m_SoundTimer != null ) + m_SoundTimer.Stop(); + + m_SoundTimer = null; + } + } + + public override void OnThink() + { + if ( !m_HasTeleportedAway && Hits < (HitsMax / 2) ) + { + Map map = this.Map; + + if ( map != null ) + { + // try 10 times to find a teleport spot + for ( int i = 0; i < 10; ++i ) + { + int x = X + (Utility.RandomMinMax( 5, 10 ) * (Utility.RandomBool() ? 1 : -1)); + int y = Y + (Utility.RandomMinMax( 5, 10 ) * (Utility.RandomBool() ? 1 : -1)); + int z = Z; + + if ( !map.CanFit( x, y, z, 16, false, false ) ) + continue; + + Point3D from = this.Location; + Point3D to = new Point3D( x, y, z ); + + if ( !InLOS( to ) ) + continue; + + this.Location = to; + this.ProcessDelta(); + this.Hidden = true; + this.Combatant = null; + + Effects.SendLocationParticles( EffectItem.Create( from, map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + Effects.SendLocationParticles( EffectItem.Create( to, map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + + Effects.PlaySound( to, map, 0x1FE ); + + m_HasTeleportedAway = true; + m_SoundTimer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 2.5 ), new TimerCallback( SendTrackingSound ) ); + + Frozen = true; + + break; + } + } + } + + base.OnThink(); + } + + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool AreaPeaceImmune{ get{ return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int TreasureMapLevel{ get{ return 1; } } + + public ShadowKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 357 ) + BaseSoundID = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/SkitteringHopper.cs b/Scripts/Mobiles/Monsters/AOS/SkitteringHopper.cs new file mode 100644 index 0000000..c91aebf --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/SkitteringHopper.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a skittering hopper corpse" )] + public class SkitteringHopper : BaseCreature + { + [Constructable] + public SkitteringHopper() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a skittering hopper"; + Body = 302; + BaseSoundID = 959; + + SetStr( 41, 65 ); + SetDex( 91, 115 ); + SetInt( 26, 50 ); + + SetHits( 31, 45 ); + + SetDamage( 3, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 30.1, 45.0 ); + SetSkill( SkillName.Tactics, 45.1, 70.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 300; + Karma = 0; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -12.9; + + VirtualArmor = 12; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int TreasureMapLevel{ get{ return 1; } } + + public SkitteringHopper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/Treefellow.cs b/Scripts/Mobiles/Monsters/AOS/Treefellow.cs new file mode 100644 index 0000000..aae03fb --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/Treefellow.cs @@ -0,0 +1,93 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a treefellow corpse" )] + public class Treefellow : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public Treefellow() : base( AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a treefellow"; + Body = 301; + + SetStr( 196, 220 ); + SetDex( 31, 55 ); + SetInt( 66, 90 ); + + SetHits( 118, 132 ); + + SetDamage( 12, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 30, 35 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 40.1, 55.0 ); + SetSkill( SkillName.Tactics, 65.1, 90.0 ); + SetSkill( SkillName.Wrestling, 65.1, 85.0 ); + + Fame = 500; + Karma = 1500; + + VirtualArmor = 24; + PackItem( new Log( Utility.RandomMinMax( 23, 34 ) ) ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override int GetIdleSound() + { + return 443; + } + + public override int GetDeathSound() + { + return 31; + } + + public override int GetAttackSound() + { + return 672; + } + + public override bool BleedImmune{ get{ return true; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public Treefellow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 442 ) + BaseSoundID = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/VampireBat.cs b/Scripts/Mobiles/Monsters/AOS/VampireBat.cs new file mode 100644 index 0000000..326b54f --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/VampireBat.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a vampire bat corpse" )] + public class VampireBat : BaseCreature + { + [Constructable] + public VampireBat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a vampire bat"; + Body = 317; + BaseSoundID = 0x270; + + SetStr( 91, 110 ); + SetDex( 91, 115 ); + SetInt( 26, 50 ); + + SetHits( 55, 66 ); + + SetDamage( 7, 9 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 70.1, 95.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + SetSkill( SkillName.Wrestling, 30.1, 55.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 14; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int GetIdleSound() + { + return 0x29B; + } + + public VampireBat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/WailingBanshee.cs b/Scripts/Mobiles/Monsters/AOS/WailingBanshee.cs new file mode 100644 index 0000000..7986822 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/WailingBanshee.cs @@ -0,0 +1,73 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a wailing banshee corpse" )] + public class WailingBanshee : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.MortalStrike; + } + + [Constructable] + public WailingBanshee() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a wailing banshee"; + Body = 310; + BaseSoundID = 0x482; + + SetStr( 126, 150 ); + SetDex( 76, 100 ); + SetInt( 86, 110 ); + + SetHits( 76, 90 ); + + SetDamage( 10, 14 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 60 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 70.1, 95.0 ); + SetSkill( SkillName.Tactics, 45.1, 70.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 19; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public WailingBanshee( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/AOS/WandererOfTheVoid.cs b/Scripts/Mobiles/Monsters/AOS/WandererOfTheVoid.cs new file mode 100644 index 0000000..5152eb2 --- /dev/null +++ b/Scripts/Mobiles/Monsters/AOS/WandererOfTheVoid.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a wanderer of the void corpse" )] + public class WandererOfTheVoid : BaseCreature + { + [Constructable] + public WandererOfTheVoid() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a wanderer of the void"; + Body = 316; + BaseSoundID = 377; + + SetStr( 111, 200 ); + SetDex( 101, 125 ); + SetInt( 301, 390 ); + + SetHits( 351, 400 ); + + SetDamage( 11, 13 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 15 ); + SetDamageType( ResistanceType.Energy, 85 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 50, 75 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 60.1, 70.0 ); + SetSkill( SkillName.Magery, 60.1, 70.0 ); + SetSkill( SkillName.Meditation, 60.1, 70.0 ); + SetSkill( SkillName.MagicResist, 50.1, 75.0 ); + SetSkill( SkillName.Tactics, 60.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 70.0 ); + + Fame = 20000; + Karma = -20000; + + VirtualArmor = 44; + + int count = Utility.RandomMinMax( 2, 3 ); + + for ( int i = 0; i < count; ++i ) + PackItem( new TreasureMap( 3, Map.Trammel ) ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return Core.AOS ? 4 : 1; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + } + + public WandererOfTheVoid( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/AntLion.cs b/Scripts/Mobiles/Monsters/Ants/AntLion.cs new file mode 100644 index 0000000..c099bde --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/AntLion.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an ant lion corpse" )] + public class AntLion : BaseCreature + { + [Constructable] + public AntLion() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ant lion"; + Body = 787; + BaseSoundID = 1006; + + SetStr( 296, 320 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 151, 162 ); + + SetDamage( 7, 21 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 45, 60 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 30, 35 ); + + SetSkill( SkillName.MagicResist, 70.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 45; + + PackItem( new Bone( 3 ) ); + PackItem( new FertileDirt( Utility.RandomMinMax( 1, 10 ) ) ); // Scriptiz : par d�faut de 1 � 5 + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(2) ); + + Item orepile = null; /* no trust, no love :( */ + + switch (Utility.Random(4)) + { + case 0: orepile = new DullcopperOre(); break; + case 1: orepile = new ShadowOre(); break; + case 2: orepile = new CopperOre(); break; + default: orepile = new BronzeOre(); break; + } + orepile.Amount = Utility.RandomMinMax(1, 5); // Scriptiz : par d�faut de 1 � 10 + orepile.ItemID = 0x19B9; + PackItem(orepile); + + // TODO: skeleton + } + + public override int GetAngerSound() + { + return 0x5A; + } + + public override int GetIdleSound() + { + return 0x5A; + } + + public override int GetAttackSound() + { + return 0x164; + } + + public override int GetHurtSound() + { + return 0x187; + } + + public override int GetDeathSound() + { + return 0x1BA; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 1 ); // Scriptiz : par d�faut 2 + } + + + public AntLion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs b/Scripts/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs new file mode 100644 index 0000000..5d6c0ad --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/BlackSolenInfiltratorQueen.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a solen infiltrator corpse" )] // TODO: Corpse name? + public class BlackSolenInfiltratorQueen : BaseCreature + { + [Constructable] + public BlackSolenInfiltratorQueen() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a black solen infiltrator"; + Body = 807; + BaseSoundID = 959; + Hue = 0x453; + + SetStr( 326, 350 ); + SetDex( 141, 165 ); + SetInt( 96, 120 ); + + SetHits( 151, 162 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 35 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 40 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 90.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 50; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( 0.05 > Utility.RandomDouble() ) ? 16 : 4 ) ); + } + + public override int GetAngerSound() + { + return 0x259; + } + + public override int GetIdleSound() + { + return 0x259; + } + + public override int GetAttackSound() + { + return 0x195; + } + + public override int GetHurtSound() + { + return 0x250; + } + + public override int GetDeathSound() + { + return 0x25B; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckBlackFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnBlackDamage( from ); + + base.OnDamage( amount, from, willKill ); + } + + public BlackSolenInfiltratorQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs b/Scripts/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs new file mode 100644 index 0000000..cca6e3f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/BlackSolenInfiltratorWarrior.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a solen infiltrator corpse" )] + public class BlackSolenInfiltratorWarrior : BaseCreature + { + [Constructable] + public BlackSolenInfiltratorWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a black solen infiltrator"; + Body = 806; + BaseSoundID = 959; + Hue = 0x453; + + SetStr( 206, 230 ); + SetDex( 121, 145 ); + SetInt( 66, 90 ); + + SetHits( 96, 107 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 20, 35 ); + SetResistance( ResistanceType.Fire, 20, 35 ); + SetResistance( ResistanceType.Cold, 10, 25 ); + SetResistance( ResistanceType.Poison, 20, 35 ); + SetResistance( ResistanceType.Energy, 10, 25 ); + + SetSkill( SkillName.MagicResist, 80.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( 0.05 > Utility.RandomDouble() )? 13 : 3 ) ); + } + + public override int GetAngerSound() + { + return 0xB5; + } + + public override int GetIdleSound() + { + return 0xB5; + } + + public override int GetAttackSound() + { + return 0x289; + } + + public override int GetHurtSound() + { + return 0xBC; + } + + public override int GetDeathSound() + { + return 0xE4; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 4 ) ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckBlackFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnBlackDamage( from ); + + base.OnDamage( amount, from, willKill ); + } + + public BlackSolenInfiltratorWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/BlackSolenQueen.cs b/Scripts/Mobiles/Monsters/Ants/BlackSolenQueen.cs new file mode 100644 index 0000000..f6ba175 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/BlackSolenQueen.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a solen queen corpse" )] + public class BlackSolenQueen : BaseCreature + { + private bool m_BurstSac; + public bool BurstSac{ get{ return m_BurstSac; } } + + [Constructable] + public BlackSolenQueen() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a black solen queen"; + Body = 807; + BaseSoundID = 959; + Hue = 0x453; + + SetStr( 296, 320 ); + SetDex( 121, 145 ); + SetInt( 76, 100 ); + + SetHits( 151, 162 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 35 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 40 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 70.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 45; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( Utility.RandomDouble() > 0.05 )? 5 : 25 ) ); + + if ( Utility.RandomDouble() < 0.05 ) + PackItem( new BallOfSummoning() ); + } + + public override int GetAngerSound() + { + return 0x259; + } + + public override int GetIdleSound() + { + return 0x259; + } + + public override int GetAttackSound() + { + return 0x195; + } + + public override int GetHurtSound() + { + return 0x250; + } + + public override int GetDeathSound() + { + return 0x25B; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckBlackFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnBlackDamage( from ); + + if ( !willKill ) + { + if ( !BurstSac ) + { + if ( Hits < 50 ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *" ); + m_BurstSac = true; + } + } + else if ( from != null && from != this && InRange( from, 1 ) ) + { + SpillAcid( from, 1 ); + } + } + + base.OnDamage( amount, from, willKill ); + } + + public override bool OnBeforeDeath() + { + SpillAcid( 4 ); + + return base.OnBeforeDeath(); + } + + public BlackSolenQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_BurstSac ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch( version ) + { + case 1: + { + m_BurstSac = reader.ReadBool(); + break; + } + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/Ants/BlackSolenWarrior.cs b/Scripts/Mobiles/Monsters/Ants/BlackSolenWarrior.cs new file mode 100644 index 0000000..73d0dfd --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/BlackSolenWarrior.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a solen warrior corpse" )] + public class BlackSolenWarrior : BaseCreature + { + private bool m_BurstSac; + public bool BurstSac{ get{ return m_BurstSac; } } + + [Constructable] + public BlackSolenWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a black solen warrior"; + Body = 806; + BaseSoundID = 959; + Hue = 0x453; + + SetStr( 196, 220 ); + SetDex( 101, 125 ); + SetInt( 36, 60 ); + + SetHits( 96, 107 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 20, 35 ); + SetResistance( ResistanceType.Fire, 20, 35 ); + SetResistance( ResistanceType.Cold, 10, 25 ); + SetResistance( ResistanceType.Poison, 20, 35 ); + SetResistance( ResistanceType.Energy, 10, 25 ); + + SetSkill( SkillName.MagicResist, 60.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 35; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( 0.05 > Utility.RandomDouble() )? 13 : 3 ) ); + + if ( Utility.RandomDouble() < 0.05 ) + PackItem( new BraceletOfBinding() ); + } + + public override int GetAngerSound() + { + return 0xB5; + } + + public override int GetIdleSound() + { + return 0xB5; + } + + public override int GetAttackSound() + { + return 0x289; + } + + public override int GetHurtSound() + { + return 0xBC; + } + + public override int GetDeathSound() + { + return 0xE4; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 4 ) ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckBlackFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnBlackDamage( from ); + + if ( !willKill ) + { + if ( !BurstSac ) + { + if ( Hits < 50 ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *" ); + m_BurstSac = true; + } + } + else if ( from != null && from != this && InRange( from, 1 ) ) + { + SpillAcid( from, 1 ); + } + } + + base.OnDamage( amount, from, willKill ); + } + + public override bool OnBeforeDeath() + { + SpillAcid( 4 ); + + return base.OnBeforeDeath(); + } + + public BlackSolenWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_BurstSac ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch( version ) + { + case 1: + { + m_BurstSac = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/BlackSolenWorker.cs b/Scripts/Mobiles/Monsters/Ants/BlackSolenWorker.cs new file mode 100644 index 0000000..21f03f2 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/BlackSolenWorker.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a solen worker corpse" )] + public class BlackSolenWorker : BaseCreature + { + [Constructable] + public BlackSolenWorker() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a black solen worker"; + Body = 805; + BaseSoundID = 959; + Hue = 0x453; + + SetStr( 96, 120 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 60.0 ); + SetSkill( SkillName.Tactics, 65.0 ); + SetSkill( SkillName.Wrestling, 60.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + PackGold( Utility.Random( 100, 180 ) ); + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus() ); + } + + public override int GetAngerSound() + { + return 0x269; + } + + public override int GetIdleSound() + { + return 0x269; + } + + public override int GetAttackSound() + { + return 0x186; + } + + public override int GetHurtSound() + { + return 0x1BE; + } + + public override int GetDeathSound() + { + return 0x8E; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 2 ) ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckBlackFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnBlackDamage( from ); + + base.OnDamage( amount, from, willKill ); + } + + public BlackSolenWorker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs b/Scripts/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs new file mode 100644 index 0000000..20c3d27 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/RedSolenInfiltratorQueen.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a solen infiltrator corpse" )] // TODO: Corpse name? + public class RedSolenInfiltratorQueen : BaseCreature + { + [Constructable] + public RedSolenInfiltratorQueen() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a red solen infiltrator"; + Body = 783; + BaseSoundID = 959; + + SetStr( 326, 350 ); + SetDex( 141, 165 ); + SetInt( 96, 120 ); + + SetHits( 151, 162 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 35 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 40 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 90.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 50; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( 0.05 < Utility.RandomDouble() )? 4 : 16 ) ); + } + + public override int GetAngerSound() + { + return 0x259; + } + + public override int GetIdleSound() + { + return 0x259; + } + + public override int GetAttackSound() + { + return 0x195; + } + + public override int GetHurtSound() + { + return 0x250; + } + + public override int GetDeathSound() + { + return 0x25B; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckRedFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnRedDamage( from ); + + base.OnDamage( amount, from, willKill ); + } + + public RedSolenInfiltratorQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs b/Scripts/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs new file mode 100644 index 0000000..f8ad5d4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/RedSolenInfiltratorWarrior.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a solen infiltrator corpse" )] + public class RedSolenInfiltratorWarrior : BaseCreature + { + [Constructable] + public RedSolenInfiltratorWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a red solen infiltrator"; + Body = 782; + BaseSoundID = 959; + + SetStr( 206, 230 ); + SetDex( 121, 145 ); + SetInt( 66, 90 ); + + SetHits( 96, 107 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 20, 35 ); + SetResistance( ResistanceType.Fire, 20, 35 ); + SetResistance( ResistanceType.Cold, 10, 25 ); + SetResistance( ResistanceType.Poison, 20, 35 ); + SetResistance( ResistanceType.Energy, 10, 25 ); + + SetSkill( SkillName.MagicResist, 80.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( 0.05 < Utility.RandomDouble() )? 3 : 13 ) ); + + } + + public override int GetAngerSound() + { + return 0xB5; + } + + public override int GetIdleSound() + { + return 0xB5; + } + + public override int GetAttackSound() + { + return 0x289; + } + + public override int GetHurtSound() + { + return 0xBC; + } + + public override int GetDeathSound() + { + return 0xE4; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 4 ) ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckRedFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnRedDamage( from ); + + base.OnDamage( amount, from, willKill ); + } + + public RedSolenInfiltratorWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/RedSolenQueen.cs b/Scripts/Mobiles/Monsters/Ants/RedSolenQueen.cs new file mode 100644 index 0000000..87832a0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/RedSolenQueen.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a solen queen corpse" )] + public class RedSolenQueen : BaseCreature + { + private bool m_BurstSac; + public bool BurstSac{ get{ return m_BurstSac; } } + + [Constructable] + public RedSolenQueen() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a red solen queen"; + Body = 783; + BaseSoundID = 959; + + SetStr( 296, 320 ); + SetDex( 121, 145 ); + SetInt( 76, 100 ); + + SetHits( 151, 162 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 35 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 40 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 70.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 45; + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus( ( Utility.RandomDouble() > 0.05 )? 5 : 25 ) ); + + if( Utility.RandomDouble() < 0.05 ) + PackItem( new BallOfSummoning() ); + } + + public override int GetAngerSound() + { + return 0x259; + } + + public override int GetIdleSound() + { + return 0x259; + } + + public override int GetAttackSound() + { + return 0x195; + } + + public override int GetHurtSound() + { + return 0x250; + } + + public override int GetDeathSound() + { + return 0x25B; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckRedFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnRedDamage( from ); + + if ( !willKill ) + { + if ( !BurstSac ) + { + if ( Hits < 50 ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *" ); + m_BurstSac = true; + } + } + else if ( from != null && from != this && InRange( from, 1 ) ) + { + SpillAcid( from, 1 ); + } + } + + base.OnDamage( amount, from, willKill ); + } + + public override bool OnBeforeDeath() + { + SpillAcid( 4 ); + + return base.OnBeforeDeath(); + } + + public RedSolenQueen( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_BurstSac ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch( version ) + { + case 1: + { + m_BurstSac = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/RedSolenWarrior.cs b/Scripts/Mobiles/Monsters/Ants/RedSolenWarrior.cs new file mode 100644 index 0000000..7e8e8b5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/RedSolenWarrior.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a solen warrior corpse" )] + public class RedSolenWarrior : BaseCreature + { + private bool m_BurstSac; + public bool BurstSac{ get{ return m_BurstSac; } } + + [Constructable] + public RedSolenWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a red solen warrior"; + Body = 782; + BaseSoundID = 959; + + SetStr( 196, 220 ); + SetDex( 101, 125 ); + SetInt( 36, 60 ); + + SetHits( 96, 107 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 20, 35 ); + SetResistance( ResistanceType.Fire, 20, 35 ); + SetResistance( ResistanceType.Cold, 10, 25 ); + SetResistance( ResistanceType.Poison, 20, 35 ); + SetResistance( ResistanceType.Energy, 10, 25 ); + + SetSkill( SkillName.MagicResist, 60.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 35; + + SolenHelper.PackPicnicBasket( this ); + PackItem( new ZoogiFungus( ( 0.05 < Utility.RandomDouble() )? 3 : 13 ) ); + + if ( Utility.RandomDouble() < 0.05 ) + PackItem( new BraceletOfBinding() ); + + } + + public override int GetAngerSound() + { + return 0xB5; + } + + public override int GetIdleSound() + { + return 0xB5; + } + + public override int GetAttackSound() + { + return 0x289; + } + + public override int GetHurtSound() + { + return 0xBC; + } + + public override int GetDeathSound() + { + return 0xE4; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 4 ) ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckRedFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnRedDamage( from ); + + if ( !willKill ) + { + if ( !BurstSac ) + { + if ( Hits < 50 ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, true, "* The solen's acid sac is burst open! *" ); + m_BurstSac = true; + } + } + else if ( from != null && from != this && InRange( from, 1 ) ) + { + SpillAcid( from, 1 ); + } + } + + base.OnDamage( amount, from, willKill ); + } + + public override bool OnBeforeDeath() + { + SpillAcid( 4 ); + + return base.OnBeforeDeath(); + } + + public RedSolenWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_BurstSac ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch( version ) + { + case 1: + { + m_BurstSac = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/RedSolenWorker.cs b/Scripts/Mobiles/Monsters/Ants/RedSolenWorker.cs new file mode 100644 index 0000000..f8a2421 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/RedSolenWorker.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a solen worker corpse" )] + public class RedSolenWorker : BaseCreature + { + [Constructable] + public RedSolenWorker() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a red solen worker"; + Body = 781; + BaseSoundID = 959; + + SetStr( 96, 120 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 60.0 ); + SetSkill( SkillName.Tactics, 65.0 ); + SetSkill( SkillName.Wrestling, 60.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + PackGold( Utility.Random( 100, 180 ) ); + + SolenHelper.PackPicnicBasket( this ); + + PackItem( new ZoogiFungus() ); + } + + public override int GetAngerSound() + { + return 0x269; + } + + public override int GetIdleSound() + { + return 0x269; + } + + public override int GetAttackSound() + { + return 0x186; + } + + public override int GetHurtSound() + { + return 0x1BE; + } + + public override int GetDeathSound() + { + return 0x8E; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 2 ) ); + } + + public override bool IsEnemy( Mobile m ) + { + if ( SolenHelper.CheckRedFriendship( m ) ) + return false; + else + return base.IsEnemy( m ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + SolenHelper.OnRedDamage( from ); + + base.OnDamage( amount, from, willKill ); + } + + public RedSolenWorker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ants/SolenHelper.cs b/Scripts/Mobiles/Monsters/Ants/SolenHelper.cs new file mode 100644 index 0000000..768a176 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ants/SolenHelper.cs @@ -0,0 +1,101 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class SolenHelper + { + public static void PackPicnicBasket( BaseCreature solen ) + { + if ( 1 > Utility.Random( 100 ) ) + { + PicnicBasket basket = new PicnicBasket(); + + basket.DropItem( new BeverageBottle( BeverageType.Wine ) ); + basket.DropItem( new CheeseWedge() ); + + solen.PackItem( basket ); + } + } + + public static bool CheckRedFriendship( Mobile m ) + { + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( bc.Controlled && bc.ControlMaster is PlayerMobile ) + return CheckRedFriendship( bc.ControlMaster ); + else if ( bc.Summoned && bc.SummonMaster is PlayerMobile ) + return CheckRedFriendship( bc.SummonMaster ); + } + + PlayerMobile player = m as PlayerMobile; + + return player != null && player.SolenFriendship == SolenFriendship.Red; + } + + public static bool CheckBlackFriendship( Mobile m ) + { + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( bc.Controlled && bc.ControlMaster is PlayerMobile ) + return CheckBlackFriendship( bc.ControlMaster ); + else if ( bc.Summoned && bc.SummonMaster is PlayerMobile ) + return CheckBlackFriendship( bc.SummonMaster ); + } + + PlayerMobile player = m as PlayerMobile; + + return player != null && player.SolenFriendship == SolenFriendship.Black; + } + + public static void OnRedDamage( Mobile from ) + { + if ( from is BaseCreature ) + { + BaseCreature bc = (BaseCreature)from; + + if ( bc.Controlled && bc.ControlMaster is PlayerMobile ) + OnRedDamage( bc.ControlMaster ); + else if ( bc.Summoned && bc.SummonMaster is PlayerMobile ) + OnRedDamage( bc.SummonMaster ); + } + + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.SolenFriendship == SolenFriendship.Red ) + { + player.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1054103 ); // The solen revoke their friendship. You will now be considered an intruder. + + player.SolenFriendship = SolenFriendship.None; + } + } + + public static void OnBlackDamage( Mobile from ) + { + if ( from is BaseCreature ) + { + BaseCreature bc = (BaseCreature)from; + + if ( bc.Controlled && bc.ControlMaster is PlayerMobile ) + OnBlackDamage( bc.ControlMaster ); + else if ( bc.Summoned && bc.SummonMaster is PlayerMobile ) + OnBlackDamage( bc.SummonMaster ); + } + + PlayerMobile player = from as PlayerMobile; + + if ( player != null && player.SolenFriendship == SolenFriendship.Black ) + { + player.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1054103 ); // The solen revoke their friendship. You will now be considered an intruder. + + player.SolenFriendship = SolenFriendship.None; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs b/Scripts/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs new file mode 100644 index 0000000..07b196e --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Magic/DreadSpider.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dread spider corpse" )] + public class DreadSpider : BaseCreature + { + [Constructable] + public DreadSpider () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a dread spider"; + Body = 11; + BaseSoundID = 1170; + + SetStr( 196, 220 ); + SetDex( 126, 145 ); + SetInt( 286, 310 ); + + SetHits( 118, 132 ); + + SetDamage( 5, 17 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Poison, 80 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 90, 100 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.EvalInt, 65.1, 80.0 ); + SetSkill( SkillName.Magery, 65.1, 80.0 ); + SetSkill( SkillName.Meditation, 65.1, 80.0 ); + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 55.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 75.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 36; + + PackItem( new SpidersSilk( 8 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public DreadSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 1170; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs b/Scripts/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs new file mode 100644 index 0000000..e244415 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Magic/TerathanAvenger.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a terathan avenger corpse" )] + public class TerathanAvenger : BaseCreature + { + [Constructable] + public TerathanAvenger() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a terathan avenger"; + Body = 152; + BaseSoundID = 0x24D; + + SetStr( 467, 645 ); + SetDex( 77, 95 ); + SetInt( 126, 150 ); + + SetHits( 296, 372 ); + SetMana( 46, 70 ); + + SetDamage( 18, 22 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 90, 100 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.EvalInt, 70.3, 100.0 ); + SetSkill( SkillName.Magery, 70.3, 100.0 ); + SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 3; } } + public override int Meat{ get{ return 2; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public TerathanAvenger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 0x24D; + } + } +} diff --git a/Scripts/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs b/Scripts/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs new file mode 100644 index 0000000..feb0222 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Magic/TerathanMatriarch.cs @@ -0,0 +1,95 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a terathan matriarch corpse" )] + public class TerathanMatriarch : BaseCreature + { + [Constructable] + public TerathanMatriarch() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a terathan matriarch"; + Body = 72; + BaseSoundID = 599; + + SetStr( 316, 405 ); + SetDex( 96, 115 ); + SetInt( 366, 455 ); + + SetHits( 190, 243 ); + + SetDamage( 11, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 10000; + Karma = -10000; + + PackItem( new SpidersSilk( 5 ) ); + PackNecroReg( Utility.RandomMinMax( 4, 10 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + AddLoot( LootPack.Potions ); + } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.15) + { + if (from.CheckSkill(SkillName.Forensics,30,80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new ArachnidRelic()); + from.SendMessage("Vous arrachez une carapace � l'araign�e"); + } + } + base.OnCarve(from, corpse, with); + } + + public override int TreasureMapLevel{ get{ return 4; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public TerathanMatriarch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs b/Scripts/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs new file mode 100644 index 0000000..48bd611 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Melee/FrostSpider.cs @@ -0,0 +1,78 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a frost spider corpse" )] + public class FrostSpider : BaseCreature + { + [Constructable] + public FrostSpider() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a frost spider"; + Body = 20; + BaseSoundID = 0x388; + + SetStr( 76, 100 ); + SetDex( 126, 145 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + SetMana( 0 ); + + SetDamage( 6, 16 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 35.1, 50.0 ); + SetSkill( SkillName.Wrestling, 50.1, 65.0 ); + + Fame = 775; + Karma = -775; + + VirtualArmor = 28; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 74.7; + + PackItem( new SpidersSilk( 7 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Poor ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Arachnid; } } + + public FrostSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 387 ) + BaseSoundID = 0x388; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs b/Scripts/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs new file mode 100644 index 0000000..b8c6734 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Melee/GiantBlackWidow.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a giant black widow spider corpse" )] // stupid corpse name + public class GiantBlackWidow : BaseCreature + { + [Constructable] + public GiantBlackWidow() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a giant black widow"; + Body = 0x9D; + BaseSoundID = 0x388; // TODO: validate + + SetStr( 76, 100 ); + SetDex( 96, 115 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + + SetDamage( 5, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 30 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 30.3, 75.0 ); + SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 65.1, 80.0 ); + SetSkill( SkillName.Wrestling, 70.1, 85.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 24; + + PackItem( new SpidersSilk( 5 ) ); + PackItem( new LesserPoisonPotion() ); + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + + public GiantBlackWidow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs b/Scripts/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs new file mode 100644 index 0000000..564f48a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Melee/GiantSpider.cs @@ -0,0 +1,75 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a giant spider corpse" )] + public class GiantSpider : BaseCreature + { + [Constructable] + public GiantSpider() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a giant spider"; + Body = 28; + BaseSoundID = 0x388; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + SetMana( 0 ); + + SetDamage( 5, 13 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + + SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 35.1, 50.0 ); + SetSkill( SkillName.Wrestling, 50.1, 65.0 ); + + Fame = 600; + Karma = -600; + + VirtualArmor = 16; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 59.1; + + PackItem( new SpidersSilk( 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Arachnid; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override Poison HitPoison{ get{ return Poison.Regular; } } + + public GiantSpider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs b/Scripts/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs new file mode 100644 index 0000000..9c20578 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Melee/TerathanDrone.cs @@ -0,0 +1,80 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a terathan drone corpse" )] + public class TerathanDrone : BaseCreature + { + [Constructable] + public TerathanDrone() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a terathan drone"; + Body = 71; + BaseSoundID = 594; + + SetStr( 36, 65 ); + SetDex( 96, 145 ); + SetInt( 21, 45 ); + + SetHits( 22, 39 ); + SetMana( 0 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.Poisoning, 40.1, 60.0 ); + SetSkill( SkillName.MagicResist, 30.1, 45.0 ); + SetSkill( SkillName.Tactics, 30.1, 50.0 ); + SetSkill( SkillName.Wrestling, 40.1, 50.0 ); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 24; + + PackItem( new SpidersSilk( 2 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon? + } + + public override int Meat{ get{ return 4; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public TerathanDrone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 589 ) + BaseSoundID = 594; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs b/Scripts/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs new file mode 100644 index 0000000..6625347 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Arachnid/Melee/TerathanWarrior.cs @@ -0,0 +1,78 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a terathan warrior corpse" )] + public class TerathanWarrior : BaseCreature + { + [Constructable] + public TerathanWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a terathan warrior"; + Body = 70; + BaseSoundID = 589; + + SetStr( 166, 215 ); + SetDex( 96, 145 ); + SetInt( 41, 65 ); + + SetHits( 100, 129 ); + SetMana( 0 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 30; + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(3) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 4; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public TerathanWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs new file mode 100644 index 0000000..53e8583 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/AcidElemental.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an acid elemental corpse" )] + public class AcidElemental : BaseCreature + { + [Constructable] + public AcidElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an acid elemental"; + Body = 0x9E; + BaseSoundID = 278; + + SetStr( 326, 355 ); + SetDex( 66, 85 ); + SetInt( 271, 295 ); + + SetHits( 196, 213 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 50 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 30.3, 60.0 ); + SetSkill( SkillName.EvalInt, 70.1, 85.0 ); + SetSkill( SkillName.Magery, 70.1, 85.0 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 70.1, 90.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.6; } } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.15) + { + if (!from.CheckSkill(SkillName.Forensics, 30, 80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new ElementalRelic()); + from.SendMessage("L'�l�mental se crystallise"); + } + } + base.OnCarve(from, corpse, with); + } + + public override int TreasureMapLevel{ get{ return Core.AOS ? 2 : 3; } } + + public AcidElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 278; + + if ( Body == 13 ) + Body = 0x9E; + + if ( Hue == 0x4001 ) + Hue = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/AirElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/AirElemental.cs new file mode 100644 index 0000000..c27df42 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/AirElemental.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an air elemental corpse" )] + public class AirElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public AirElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an air elemental"; + Body = 13; + Hue = 0x4001; + BaseSoundID = 655; + + SetStr( 126, 155 ); + SetDex( 166, 185 ); + SetInt( 101, 125 ); + + SetHits( 76, 93 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 40 ); + SetDamageType( ResistanceType.Energy, 40 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.EvalInt, 60.1, 75.0 ); + SetSkill( SkillName.Magery, 60.1, 75.0 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 60.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 2; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public AirElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 655; + } + } +} diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs new file mode 100644 index 0000000..6394744 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/BloodElemental.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a blood elemental corpse" )] + public class BloodElemental : BaseCreature + { + [Constructable] + public BloodElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a blood elemental"; + Body = 159; + BaseSoundID = 278; + + SetStr( 526, 615 ); + SetDex( 66, 85 ); + SetInt( 226, 350 ); + + SetHits( 316, 369 ); + + SetDamage( 17, 27 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Poison, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 85.1, 100.0 ); + SetSkill( SkillName.Magery, 85.1, 100.0 ); + SetSkill( SkillName.Meditation, 10.4, 50.0 ); + SetSkill( SkillName.MagicResist, 80.1, 95.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 60; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + public override int TreasureMapLevel{ get{ return 5; } } + + public BloodElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/Efreet.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/Efreet.cs new file mode 100644 index 0000000..e78fbb9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/Efreet.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an efreet corpse" )] + public class Efreet : BaseCreature + { + [Constructable] + public Efreet () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an efreet"; + Body = 131; + BaseSoundID = 768; + + SetStr( 326, 355 ); + SetDex( 266, 285 ); + SetInt( 171, 195 ); + + SetHits( 196, 213 ); + + SetDamage( 11, 13 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Fire, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 60.1, 75.0 ); + SetSkill( SkillName.Magery, 60.1, 75.0 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 60.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 56; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems ); + + if ( 0.02 > Utility.RandomDouble() ) + { + switch ( Utility.Random( 5 ) ) + { + case 0: PackItem( new DaemonArms() ); break; + case 1: PackItem( new DaemonChest() ); break; + case 2: PackItem( new DaemonGloves() ); break; + case 3: PackItem( new DaemonLegs() ); break; + case 4: PackItem( new DaemonHelm() ); break; + } + } + } + + public override int TreasureMapLevel{ get{ return Core.AOS ? 4 : 5; } } + + public Efreet( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/FireElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/FireElemental.cs new file mode 100644 index 0000000..13abc9c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/FireElemental.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a fire elemental corpse" )] + public class FireElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public FireElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fire elemental"; + Body = 15; + BaseSoundID = 838; + + SetStr( 126, 155 ); + SetDex( 166, 185 ); + SetInt( 101, 125 ); + + SetHits( 76, 93 ); + + SetDamage( 7, 9 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 75 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 60, 80 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 60.1, 75.0 ); + SetSkill( SkillName.Magery, 60.1, 75.0 ); + SetSkill( SkillName.MagicResist, 75.2, 105.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 70.1, 100.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 4; + + PackItem( new SulfurousAsh( 3 ) ); + + AddItem( new LightSource() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Gems ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public FireElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 274 ) + BaseSoundID = 838; + } + } +} diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/IceElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/IceElemental.cs new file mode 100644 index 0000000..71e8a7a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/IceElemental.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ice elemental corpse" )] + public class IceElemental : BaseCreature + { + [Constructable] + public IceElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ice elemental"; + Body = 161; + BaseSoundID = 268; + + SetStr( 156, 185 ); + SetDex( 96, 115 ); + SetInt( 171, 192 ); + + SetHits( 94, 111 ); + + SetDamage( 10, 21 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Cold, 75 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.EvalInt, 10.5, 60.0 ); + SetSkill( SkillName.Magery, 10.5, 60.0 ); + SetSkill( SkillName.MagicResist, 30.1, 80.0 ); + SetSkill( SkillName.Tactics, 70.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 40; + + PackItem( new BlackPearl() ); + PackReg( 3 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.Gems, 2 ); + } + public override bool BleedImmune{ get{ return true; } } + + public IceElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs new file mode 100644 index 0000000..3cdf02c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/PoisonElemental.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a poison elementals corpse" )] + public class PoisonElemental : BaseCreature + { + [Constructable] + public PoisonElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a poison elemental"; + Body = 162; + BaseSoundID = 263; + + SetStr( 426, 515 ); + SetDex( 166, 185 ); + SetInt( 361, 435 ); + + SetHits( 256, 309 ); + + SetDamage( 12, 18 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Poison, 90 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 80.1, 95.0 ); + SetSkill( SkillName.Magery, 80.1, 95.0 ); + SetSkill( SkillName.Meditation, 80.2, 120.0 ); + SetSkill( SkillName.Poisoning, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 85.2, 115.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 70.1, 90.0 ); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 70; + + PackItem( new Nightshade( 4 ) ); + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.75; } } + + public override int TreasureMapLevel{ get{ return 5; } } + + public PoisonElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/ToxicElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/ToxicElemental.cs new file mode 100644 index 0000000..efb2744 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/ToxicElemental.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an acid elemental corpse" )] + public class ToxicElemental : BaseCreature + { + [Constructable] + public ToxicElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an acid elemental"; + Body = 0x9E; + BaseSoundID = 278; + + SetStr( 326, 355 ); + SetDex( 66, 85 ); + SetInt( 271, 295 ); + + SetHits( 196, 213 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 50 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 30.3, 60.0 ); + SetSkill( SkillName.EvalInt, 70.1, 85.0 ); + SetSkill( SkillName.Magery, 70.1, 85.0 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 70.1, 90.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.6; } } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.15) + { + if (!from.CheckSkill(SkillName.Forensics, 30, 80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new ElementalRelic()); + from.SendMessage("L'�l�mental se crystallise"); + } + } + base.OnCarve(from, corpse, with); + } + + public override int TreasureMapLevel{ get{ return Core.AOS ? 2 : 3; } } + + public ToxicElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 278; + + if ( Body == 13 ) + Body = 0x9E; + + if ( Hue == 0x4001 ) + Hue = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs new file mode 100644 index 0000000..70265a9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Magic/WaterElemental.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a water elemental corpse" )] + public class WaterElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public WaterElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a water elemental"; + Body = 16; + BaseSoundID = 278; + + SetStr( 126, 155 ); + SetDex( 66, 85 ); + SetInt( 101, 125 ); + + SetHits( 76, 93 ); + + SetDamage( 7, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 10, 25 ); + SetResistance( ResistanceType.Cold, 10, 25 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.EvalInt, 60.1, 75.0 ); + SetSkill( SkillName.Magery, 60.1, 75.0 ); + SetSkill( SkillName.MagicResist, 100.1, 115.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 40; + ControlSlots = 3; + CanSwim = true; + + PackItem( new BlackPearl( 3 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Potions ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public WaterElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs new file mode 100644 index 0000000..5b1e401 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Melee/EarthElemental.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an earth elemental corpse" )] + public class EarthElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public EarthElemental() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an earth elemental"; + Body = 14; + BaseSoundID = 268; + + SetStr( 126, 155 ); + SetDex( 66, 85 ); + SetInt( 71, 92 ); + + SetHits( 76, 93 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 34; + ControlSlots = 2; + + PackItem( new FertileDirt( Utility.RandomMinMax( 1, 4 ) ) ); + PackItem( new MandrakeRoot() ); + + Item ore = new IronOre( 5 ); + ore.ItemID = 0x19B7; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Gems ); + } + + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public EarthElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs b/Scripts/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs new file mode 100644 index 0000000..ccbf3b7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Elemental/Melee/SnowElemental.cs @@ -0,0 +1,73 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a snow elemental corpse" )] + public class SnowElemental : BaseCreature + { + [Constructable] + public SnowElemental() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a snow elemental"; + Body = 163; + BaseSoundID = 263; + + SetStr( 326, 355 ); + SetDex( 166, 185 ); + SetInt( 71, 95 ); + + SetHits( 196, 213 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 50.1, 65.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 50; + + PackItem( new BlackPearl( 3 ) ); + Item ore = new IronOre( 3 ); + ore.ItemID = 0x19B8; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override int TreasureMapLevel{ get{ return Utility.RandomList( 2, 3 ); } } + + public SnowElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs new file mode 100644 index 0000000..fd6fc39 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/AncientLich.cs @@ -0,0 +1,128 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ancient liche's corpse" )] + public class AncientLich : BaseCreature + { + [Constructable] + public AncientLich() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "ancient lich" ); + Body = 78; + BaseSoundID = 412; + + SetStr( 216, 305 ); + SetDex( 96, 115 ); + SetInt( 966, 1045 ); + + SetHits( 560, 595 ); + + SetDamage( 15, 27 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 40 ); + SetDamageType( ResistanceType.Energy, 40 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.EvalInt, 120.1, 130.0 ); + SetSkill( SkillName.Magery, 120.1, 130.0 ); + SetSkill( SkillName.Meditation, 100.1, 101.0 ); + SetSkill( SkillName.Poisoning, 100.1, 101.0 ); + SetSkill( SkillName.MagicResist, 175.2, 200.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 75.1, 100.0 ); + SetSkill(SkillName.Necromancy, 120.1, 130.0); + SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); + + Fame = 23000; + Karma = -23000; + + VirtualArmor = 60; + PackNecroReg( 30, 275 ); + + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.15) + { + if (!from.CheckSkill(SkillName.Forensics, 30, 80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new UndeadRelic()); + from.SendMessage("Vous arrachez un morceau de chair � la liche"); + } + } + base.OnCarve(from, corpse, with); + } + + public override int GetIdleSound() + { + return 0x19D; + } + + public override int GetAngerSound() + { + return 0x175; + } + + public override int GetDeathSound() + { + return 0x108; + } + + public override int GetAttackSound() + { + return 0xE2; + } + + public override int GetHurtSound() + { + return 0x28B; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool Unprovokable{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public AncientLich( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs new file mode 100644 index 0000000..fc0cca5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/ArcaneDaemon.cs @@ -0,0 +1,74 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an arcane daemon corpse" )] + public class ArcaneDaemon : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ConcussionBlow; + } + + [Constructable] + public ArcaneDaemon() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an arcane daemon"; + Body = 0x310; + BaseSoundID = 0x47D; + + SetStr( 131, 150 ); + SetDex( 126, 145 ); + SetInt( 301, 350 ); + + SetHits( 101, 115 ); + + SetDamage( 12, 16 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Fire, 20 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 85.1, 95.0 ); + SetSkill( SkillName.Tactics, 70.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + SetSkill( SkillName.Magery, 80.1, 90.0 ); + SetSkill( SkillName.EvalInt, 70.1, 80.0 ); + SetSkill( SkillName.Meditation, 70.1, 80.0 ); + + Fame = 7000; + Karma = -10000; + + VirtualArmor = 55; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + + public ArcaneDaemon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Balron.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Balron.cs new file mode 100644 index 0000000..fea575b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Balron.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a balron corpse" )] + public class Balron : BaseCreature + { + [Constructable] + public Balron () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "balron" ); + Body = 40; + BaseSoundID = 357; + + SetStr( 986, 1185 ); + SetDex( 177, 255 ); + SetInt( 151, 250 ); + + SetHits( 592, 711 ); + + SetDamage( 22, 29 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 65, 80 ); + SetResistance( ResistanceType.Fire, 60, 80 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 25.1, 50.0 ); + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 95.5, 100.0 ); + SetSkill( SkillName.Meditation, 25.1, 50.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 90; + + PackItem( new Longsword() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 5; } } + public override int Meat{ get{ return 1; } } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.15) + { + if (!from.CheckSkill(SkillName.Forensics, 30, 80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new DemonRelic()); + from.SendMessage("Vous coupez une main au d�mon"); + } + } + base.OnCarve(from, corpse, with); + } + + public override int Hides { get { return Utility.Random(1, 6); } } + public override HideType HideType { get { return HideType.Daemon; } } + + public Balron( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs new file mode 100644 index 0000000..841562b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Betrayer.cs @@ -0,0 +1,187 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a betrayer corpse" )] + public class Betrayer : BaseCreature + { + private bool m_Stunning; + + [Constructable] + public Betrayer() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a betrayer"; + Body = 767; + + + SetStr( 401, 500 ); + SetDex( 81, 100 ); + SetInt( 151, 200 ); + + SetHits( 241, 300 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.Anatomy, 90.1, 100.0 ); + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 50.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 120.1, 130.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 65; + SpeechHue = Utility.RandomDyedHue(); + + PackItem( new PowerCrystal() ); + + if ( 0.02 > Utility.RandomDouble() ) + PackItem( new BlackthornWelcomeBook() ); + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 30 ) ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (0.05 > Utility.RandomDouble()) + { + if (!IsParagon) + { + if (0.75 > Utility.RandomDouble()) + c.DropItem(DawnsMusicGear.RandomCommon); + else + c.DropItem(DawnsMusicGear.RandomUncommon); + } + else + c.DropItem(DawnsMusicGear.RandomRare); + } + } + + public override int GetDeathSound() + { + return 0x423; + } + + public override int GetAttackSound() + { + return 0x23B; + } + + public override int GetHurtSound() + { + return 0x140; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 1 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !m_Stunning && 0.3 > Utility.RandomDouble() ) + { + m_Stunning = true; + + defender.Animate( 21, 6, 1, true, false, 0 ); + this.PlaySound( 0xEE ); + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You have been stunned by a colossal blow!" ); + + BaseWeapon weapon = this.Weapon as BaseWeapon; + if ( weapon != null ) + weapon.OnHit( this, defender ); + + if ( defender.Alive ) + { + defender.Frozen = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( Recover_Callback ), defender ); + } + } + } + + private void Recover_Callback( object state ) + { + Mobile defender = state as Mobile; + + if ( defender != null ) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You recover your senses." ); + } + + m_Stunning = false; + } + + private DateTime m_NextAbilityTime; + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if ( DateTime.Now < m_NextAbilityTime || combatant == null || combatant.Deleted || combatant.Map != Map || !InRange( combatant, 3 ) || !CanBeHarmful( combatant ) || !InLOS( combatant ) ) + return; + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 30 ) ); + + if ( Utility.RandomBool() ) + { + this.FixedParticles( 0x376A, 9, 32, 0x2539, EffectLayer.LeftHand ); + this.PlaySound( 0x1DE ); + + foreach ( Mobile m in this.GetMobilesInRange( 2 ) ) + { + if ( m != this && IsEnemy( m ) ) + { + m.ApplyPoison( this, Poison.Deadly ); + } + } + } + } + + public Betrayer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Bogle.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Bogle.cs new file mode 100644 index 0000000..d4120dc --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Bogle.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class Bogle : BaseCreature + { + [Constructable] + public Bogle() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bogle"; + Body = 153; + BaseSoundID = 0x482; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + + SetDamage( 7, 11 ); + + SetSkill( SkillName.EvalInt, 55.1, 70.0 ); + SetSkill( SkillName.Magery, 55.1, 70.0 ); + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + PackItem( Loot.RandomWeapon() ); + PackItem( new Bone() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Bogle( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs new file mode 100644 index 0000000..836b1c0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/BoneMagi.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal corpse" )] + public class BoneMagi : BaseCreature + { + [Constructable] + public BoneMagi() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bone mage"; + Body = 148; + BaseSoundID = 451; + + SetStr( 76, 100 ); + SetDex( 56, 75 ); + SetInt( 186, 210 ); + + SetHits( 46, 60 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 60.1, 70.0 ); + SetSkill( SkillName.Magery, 60.1, 70.0 ); + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + SetSkill(SkillName.Necromancy, 89, 99.1); + SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 38; + + PackReg( 3 ); + PackNecroReg( 3, 10 ); + PackItem( new Bone() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Potions ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + + public BoneMagi( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Daemon.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Daemon.cs new file mode 100644 index 0000000..7703c98 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Daemon.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Items; +using Server.Factions; + +namespace Server.Mobiles +{ + [CorpseName( "a daemon corpse" )] + public class Daemon : BaseCreature + { + public override double DispelDifficulty{ get{ return 125.0; } } + public override double DispelFocus{ get{ return 45.0; } } + + public override Faction FactionAllegiance { get { return Shadowlords.Instance; } } + public override Ethics.Ethic EthicAllegiance { get { return Ethics.Ethic.Evil; } } + + [Constructable] + public Daemon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "daemon" ); + Body = 9; + BaseSoundID = 357; + + SetStr( 476, 505 ); + SetDex( 76, 95 ); + SetInt( 301, 325 ); + + SetHits( 286, 303 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 60 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 70.1, 80.0 ); + SetSkill( SkillName.Magery, 70.1, 80.0 ); + SetSkill( SkillName.MagicResist, 85.1, 95.0 ); + SetSkill( SkillName.Tactics, 70.1, 80.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 58; + ControlSlots = Core.SE ? 4 : 5; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanFly { get { return true; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override int TreasureMapLevel{ get{ return 4; } } + public override int Meat{ get{ return 1; } } + + public Daemon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public override void OnCarve(Mobile from, Items.Corpse corpse, Item with) + { + if (!corpse.Carved) + base.OnCarve(from, corpse, with); + } + + public override int Hides { get { return Utility.Random(1, 6 ); } } + public override HideType HideType{ get{ return HideType.Daemon; } } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs new file mode 100644 index 0000000..28ffe6f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/ElderGazer.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an elder gazer corpse" )] + public class ElderGazer : BaseCreature + { + [Constructable] + public ElderGazer () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an elder gazer"; + Body = 22; + BaseSoundID = 377; + + SetStr( 296, 325 ); + SetDex( 86, 105 ); + SetInt( 291, 385 ); + + SetHits( 178, 195 ); + + SetDamage( 8, 19 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 62.0, 100.0 ); + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 115.1, 130.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + + Fame = 12500; + Karma = -12500; + + VirtualArmor = 50; + } + + public override int TreasureMapLevel{ get{ return Core.AOS ? 4 : 0; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + } + + public ElderGazer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs new file mode 100644 index 0000000..08f6813 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/EvilMage.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an evil mage corpse" )] + public class EvilMage : BaseCreature + { + [Constructable] + public EvilMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "evil mage" ); + Title = "the evil mage"; + Body = 124; + + SetStr( 81, 105 ); + SetDex( 91, 115 ); + SetInt( 96, 120 ); + + SetHits( 49, 63 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.EvalInt, 75.1, 100.0 ); + SetSkill( SkillName.Magery, 75.1, 100.0 ); + SetSkill( SkillName.MagicResist, 75.0, 97.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 20.2, 60.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 16; + PackReg( 6 ); + PackItem( new Robe( Utility.RandomNeutralHue() ) ); // TODO: Proper hue + PackItem( new Sandals() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return Core.AOS ? 1 : 0; } } + + public EvilMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs new file mode 100644 index 0000000..453fe8a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/EvilMageLord.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an evil mage lord corpse" )] + public class EvilMageLord : BaseCreature + { + [Constructable] + public EvilMageLord() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "evil mage lord" ); + Body = Utility.RandomList( 125, 126 ); + + PackItem( new Robe( Utility.RandomMetalHue() ) ); + PackItem( new WizardsHat( Utility.RandomMetalHue() ) ); + + SetStr( 81, 105 ); + SetDex( 191, 215 ); + SetInt( 126, 150 ); + + SetHits( 49, 63 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 80.2, 100.0 ); + SetSkill( SkillName.Magery, 95.1, 100.0 ); + SetSkill( SkillName.Meditation, 27.5, 50.0 ); + SetSkill( SkillName.MagicResist, 77.5, 100.0 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 20.3, 80.0 ); + + Fame = 10500; + Karma = -10500; + + VirtualArmor = 16; + PackReg( 23 ); + if ( Utility.RandomBool() ) + PackItem( new Shoes() ); + else + PackItem( new Sandals() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return Core.AOS ? 2 : 0; } } + + public EvilMageLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs new file mode 100644 index 0000000..4e0a69c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/FireGargoyle.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a charred corpse" )] + public class FireGargoyle : BaseCreature + { + [Constructable] + public FireGargoyle() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "fire gargoyle" ); + Body = 130; + BaseSoundID = 0x174; + + SetStr( 351, 400 ); + SetDex( 126, 145 ); + SetInt( 226, 250 ); + + SetHits( 211, 240 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 80 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.Anatomy, 75.1, 85.0 ); + SetSkill( SkillName.EvalInt, 90.1, 105.0 ); + SetSkill( SkillName.Magery, 90.1, 105.0 ); + SetSkill( SkillName.Meditation, 90.1, 105.0 ); + SetSkill( SkillName.MagicResist, 90.1, 105.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 40.1, 80.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems ); + } + + public override bool CanFly { get { return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public FireGargoyle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs new file mode 100644 index 0000000..563c9b8 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Gargoyle.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gargoyle corpse" )] + public class Gargoyle : BaseCreature + { + [Constructable] + public Gargoyle() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gargoyle"; + Body = 4; + BaseSoundID = 372; + + SetStr( 146, 175 ); + SetDex( 76, 95 ); + SetInt( 81, 105 ); + + SetHits( 88, 105 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + + SetSkill( SkillName.EvalInt, 70.1, 85.0 ); + SetSkill( SkillName.Magery, 70.1, 85.0 ); + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 40.1, 80.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + + if ( 0.025 > Utility.RandomDouble() ) + PackItem( new GargoylesPickaxe() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.MedScrolls ); + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 4 ) ); + } + + public override bool CanFly { get { return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public Gargoyle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs new file mode 100644 index 0000000..18d557d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/GargoyleDestroyer.cs @@ -0,0 +1,104 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gargoyle corpse" )] + public class GargoyleDestroyer : BaseCreature + { + [Constructable] + public GargoyleDestroyer() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Gargoyle Destroyer"; + Body = 0x2F3; + BaseSoundID = 0x174; + + SetStr( 760, 850 ); + SetDex( 102, 150 ); + SetInt( 152, 200 ); + + SetHits( 482, 485 ); + + SetDamage( 7, 14 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 120.4, 160.0 ); + SetSkill( SkillName.Anatomy, 50.5, 100.0 ); + SetSkill( SkillName.Swords, 90.1, 100.0 ); + SetSkill( SkillName.Macing, 90.1, 100.0 ); + SetSkill( SkillName.Fencing, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 50; + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new GargoylesPickaxe() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool CanFly { get { return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override int Meat{ get{ return 1; } } + + public override void OnDamagedBySpell( Mobile from ) + { + if( from != null && from.Alive && 0.4 > Utility.RandomDouble() ) + { + ThrowHatchet( from ); + } + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if( attacker != null && attacker.Alive && attacker.Weapon is BaseRanged && 0.4 > Utility.RandomDouble() ) + { + ThrowHatchet( attacker ); + } + } + + public void ThrowHatchet( Mobile to ) + { + int damage = 50; + this.MovingEffect( to, 0xF43, 10, 0, false, false ); + this.DoHarmful( to ); + AOS.Damage( to, this, damage, 100, 0, 0, 0, 0 ); + } + + public GargoyleDestroyer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs new file mode 100644 index 0000000..52e5892 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/GargoyleEnforcer.cs @@ -0,0 +1,78 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gargoyle corpse" )] + public class GargoyleEnforcer : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.WhirlwindAttack; + } + + [Constructable] + public GargoyleEnforcer() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Gargoyle Enforcer"; + Body = 0x2F2; + BaseSoundID = 0x174; + + SetStr( 760, 850 ); + SetDex( 102, 150 ); + SetInt( 152, 200 ); + + SetHits( 482, 485 ); + + SetDamage( 7, 14 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.MagicResist, 120.1, 130.0 ); + SetSkill( SkillName.Tactics, 70.1, 80.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + SetSkill( SkillName.Swords, 80.1, 90.0 ); + SetSkill( SkillName.Anatomy, 70.1, 80.0 ); + SetSkill( SkillName.Magery, 80.1, 90.0 ); + SetSkill( SkillName.EvalInt, 70.3, 100.0 ); + SetSkill( SkillName.Meditation, 70.3, 100.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 50; + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new GargoylesPickaxe() ); + } + public override bool CanFly { get { return true; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls ); + } + + public override int Meat{ get{ return 1; } } + + public GargoyleEnforcer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Gazer.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Gazer.cs new file mode 100644 index 0000000..1750e9e --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Gazer.cs @@ -0,0 +1,72 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gazer corpse" )] + public class Gazer : BaseCreature + { + [Constructable] + public Gazer () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gazer"; + Body = 22; + BaseSoundID = 377; + + SetStr( 96, 125 ); + SetDex( 86, 105 ); + SetInt( 141, 165 ); + + SetHits( 58, 75 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.EvalInt, 50.1, 65.0 ); + SetSkill( SkillName.Magery, 50.1, 65.0 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 36; + + PackItem( new Nightshade( 4 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Potions ); + } + + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public Gazer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/GolemController.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/GolemController.cs new file mode 100644 index 0000000..57365fe --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/GolemController.cs @@ -0,0 +1,95 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a golem controller corpse" )] + public class GolemController : BaseCreature + { + [Constructable] + public GolemController() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "golem controller" ); + Title = "the controller"; + + Body = 400; + Hue = 0x455; + + AddArcane( new Robe() ); + AddArcane( new ThighBoots() ); + AddArcane( new LeatherGloves() ); + AddArcane( new Cloak() ); + + SetStr( 126, 150 ); + SetDex( 96, 120 ); + SetInt( 151, 175 ); + + SetHits( 76, 90 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 5, 15 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.EvalInt, 95.1, 100.0 ); + SetSkill( SkillName.Magery, 95.1, 100.0 ); + SetSkill( SkillName.Meditation, 95.1, 100.0 ); + SetSkill( SkillName.MagicResist, 102.5, 125.0 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 65.0, 87.5 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 16; + + if ( 0.7 > Utility.RandomDouble() ) + PackItem( new ArcaneGem() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public void AddArcane( Item item ) + { + if ( item is IArcaneEquip ) + { + IArcaneEquip eq = (IArcaneEquip)item; + eq.CurArcaneCharges = eq.MaxArcaneCharges = 20; + } + + item.Hue = ArcaneGem.DefaultArcaneHue; + item.LootType = LootType.Newbied; + + AddItem( item ); + } + + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool AlwaysMurderer{ get{ return true; } } + + public GolemController( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs new file mode 100644 index 0000000..f373e72 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/IceFiend.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ice fiend corpse" )] + public class IceFiend : BaseCreature + { + [Constructable] + public IceFiend () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ice fiend"; + Body = 43; + BaseSoundID = 357; + + SetStr( 376, 405 ); + SetDex( 176, 195 ); + SetInt( 201, 225 ); + + SetHits( 226, 243 ); + + SetDamage( 8, 19 ); + + SetSkill( SkillName.EvalInt, 80.1, 90.0 ); + SetSkill( SkillName.Magery, 80.1, 90.0 ); + SetSkill( SkillName.MagicResist, 75.1, 85.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 60; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanFly { get { return true; } } + public override int TreasureMapLevel{ get{ return 4; } } + public override int Meat{ get{ return 1; } } + + public IceFiend( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Imp.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Imp.cs new file mode 100644 index 0000000..00aa64c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Imp.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an imp corpse" )] + public class Imp : BaseCreature + { + [Constructable] + public Imp() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an imp"; + Body = 74; + BaseSoundID = 422; + + SetStr( 91, 115 ); + SetDex( 61, 80 ); + SetInt( 86, 105 ); + + SetHits( 55, 70 ); + + SetDamage( 10, 14 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Fire, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 20.1, 30.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 30.1, 50.0 ); + SetSkill( SkillName.Tactics, 42.1, 50.0 ); + SetSkill( SkillName.Wrestling, 40.1, 44.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 83.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanFly { get { return true; } } + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Daemon; } } + + public Imp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Lich.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Lich.cs new file mode 100644 index 0000000..e5b2085 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Lich.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a liche's corpse" )] + public class Lich : BaseCreature + { + [Constructable] + public Lich() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a lich"; + Body = 24; + BaseSoundID = 0x3E9; + + SetStr( 171, 200 ); + SetDex( 126, 145 ); + SetInt( 276, 305 ); + + SetHits( 103, 120 ); + + SetDamage( 24, 26 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Cold, 40 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill(SkillName.Necromancy, 89, 99.1); + SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); + + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Magery, 70.1, 80.0 ); + SetSkill( SkillName.Meditation, 85.1, 95.0 ); + SetSkill( SkillName.MagicResist, 80.1, 100.0 ); + SetSkill( SkillName.Tactics, 70.1, 90.0 ); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 50; + PackItem( new GnarledStaff() ); + PackNecroReg( 17, 24 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public Lich( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/LichLord.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/LichLord.cs new file mode 100644 index 0000000..fb35102 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/LichLord.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a liche's corpse" )] + public class LichLord : BaseCreature + { + [Constructable] + public LichLord() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a lich lord"; + Body = 79; + BaseSoundID = 412; + + SetStr( 416, 505 ); + SetDex( 146, 165 ); + SetInt( 566, 655 ); + + SetHits( 250, 303 ); + + SetDamage( 11, 13 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 60 ); + SetDamageType( ResistanceType.Energy, 40 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill(SkillName.Necromancy, 90, 110.0); + SetSkill(SkillName.SpiritSpeak, 90.0, 110.0); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 150.5, 200.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 50; + PackItem( new GnarledStaff() ); + PackNecroReg( 12, 40 ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 4; } } + + public LichLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs new file mode 100644 index 0000000..c6fde7d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/OrcishMage.cs @@ -0,0 +1,108 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a glowing orc corpse" )] + public class OrcishMage : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public OrcishMage () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an orcish mage"; + Body = 140; + BaseSoundID = 0x45A; + + SetStr( 116, 150 ); + SetDex( 91, 115 ); + SetInt( 161, 185 ); + + SetHits( 70, 90 ); + + SetDamage( 4, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 60.1, 72.5 ); + SetSkill( SkillName.Magery, 60.1, 72.5 ); + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 50.1, 65.0 ); + SetSkill( SkillName.Wrestling, 40.1, 50.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 30; + + + PackReg( 6 ); + + if ( 0.05 > Utility.RandomDouble() ) + PackItem( new OrcishKinMask() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.LowScrolls ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + public OrcishMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs new file mode 100644 index 0000000..218352f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/RatmanMage.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a glowing ratman corpse" )] + public class RatmanMage : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public RatmanMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "ratman" ); + Body = 0x8F; + BaseSoundID = 437; + + SetStr( 146, 180 ); + SetDex( 101, 130 ); + SetInt( 186, 210 ); + + SetHits( 88, 108 ); + + SetDamage( 7, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 45 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.EvalInt, 70.1, 80.0 ); + SetSkill( SkillName.Magery, 70.1, 80.0 ); + SetSkill( SkillName.MagicResist, 65.1, 90.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 7500; + Karma = -7500; + + VirtualArmor = 44; + + PackReg( 6 ); + + if ( 0.02 > Utility.RandomDouble() ) + PackStatue(); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.LowScrolls ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public RatmanMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Body == 42 ) + { + Body = 0x8F; + Hue = 0; + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs new file mode 100644 index 0000000..1a8e991 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/SavageShaman.cs @@ -0,0 +1,290 @@ +using System; +using System.Collections; +using Server; +using Server.Misc; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a savage corpse" )] + public class SavageShaman : BaseCreature + { + [Constructable] + public SavageShaman() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "savage shaman" ); + + if ( Utility.RandomBool() ) + Body = 184; + else + Body = 183; + + SetStr( 126, 145 ); + SetDex( 91, 110 ); + SetInt( 161, 185 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 77.5, 100.0 ); + SetSkill( SkillName.Fencing, 62.5, 85.0 ); + SetSkill( SkillName.Macing, 62.5, 85.0 ); + SetSkill( SkillName.Magery, 72.5, 95.0 ); + SetSkill( SkillName.Meditation, 77.5, 100.0 ); + SetSkill( SkillName.MagicResist, 77.5, 100.0 ); + SetSkill( SkillName.Swords, 62.5, 85.0 ); + SetSkill( SkillName.Tactics, 62.5, 85.0 ); + SetSkill( SkillName.Wrestling, 62.5, 85.0 ); + + Fame = 1000; + Karma = -1000; + + PackReg( 10, 15 ); + PackItem( new Bandage( Utility.RandomMinMax( 1, 15 ) ) ); + + if ( 0.1 > Utility.RandomDouble() ) + PackItem( new TribalBerry() ); + + AddItem( new BoneArms() ); + AddItem( new BoneLegs() ); + AddItem( new DeerMask() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + + } + + public override int Meat{ get{ return 1; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.BodyMod == 183 || m.BodyMod == 184 ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + if ( aggressor.BodyMod == 183 || aggressor.BodyMod == 184 ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + aggressor.BodyMod = 0; + aggressor.HueMod = -1; + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + aggressor.SendLocalizedMessage( 1040008 ); // Your skin is scorched as the tribal paint burns away! + + if ( aggressor is PlayerMobile ) + ((PlayerMobile)aggressor).SavagePaintExpiration = TimeSpan.Zero; + } + } + + public override void AlterMeleeDamageTo( Mobile to, ref int damage ) + { + if ( to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || to is LesserHiryu || to is Daemon ) + damage *= 3; + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.1 > Utility.RandomDouble() ) + BeginSavageDance(); + } + + public void BeginSavageDance() + { + if( this.Map == null ) + return; + + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 8 ) ) + { + if ( m != this && m is SavageShaman ) + list.Add( m ); + } + + Animate( 111, 5, 1, true, false, 0 ); // Do a little dance... + + if ( AIObject != null ) + AIObject.NextMove = DateTime.Now + TimeSpan.FromSeconds( 1.0 ); + + if ( list.Count >= 3 ) + { + for ( int i = 0; i < list.Count; ++i ) + { + SavageShaman dancer = (SavageShaman)list[i]; + + dancer.Animate( 111, 5, 1, true, false, 0 ); // Get down tonight... + + if ( dancer.AIObject != null ) + dancer.AIObject.NextMove = DateTime.Now + TimeSpan.FromSeconds( 1.0 ); + } + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerCallback( EndSavageDance ) ); + } + } + + public void EndSavageDance() + { + if ( Deleted ) + return; + + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 8 ) ) + list.Add( m ); + + if ( list.Count > 0 ) + { + switch ( Utility.Random( 3 ) ) + { + case 0: /* greater heal */ + { + foreach ( Mobile m in list ) + { + bool isFriendly = ( m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback ); + + if ( !isFriendly ) + continue; + + if ( m.Poisoned || MortalStrike.IsWounded( m ) || !CanBeBeneficial( m ) ) + continue; + + DoBeneficial( m ); + + // Algorithm: (40% of magery) + (1-10) + + int toHeal = (int)(Skills[SkillName.Magery].Value * 0.4); + toHeal += Utility.Random( 1, 10 ); + + m.Heal( toHeal, this ); + + m.FixedParticles( 0x376A, 9, 32, 5030, EffectLayer.Waist ); + m.PlaySound( 0x202 ); + } + + break; + } + case 1: /* lightning */ + { + foreach ( Mobile m in list ) + { + bool isFriendly = ( m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback ); + + if ( isFriendly ) + continue; + + if ( !CanBeHarmful( m ) ) + continue; + + DoHarmful( m ); + + double damage; + + if ( Core.AOS ) + { + int baseDamage = 6 + (int)(Skills[SkillName.EvalInt].Value / 5.0); + + damage = Utility.RandomMinMax( baseDamage, baseDamage + 3 ); + } + else + { + damage = Utility.Random( 12, 9 ); + } + + m.BoltEffect( 0 ); + + SpellHelper.Damage( TimeSpan.FromSeconds( 0.25 ), m, this, damage, 0, 0, 0, 0, 100 ); + } + + break; + } + case 2: /* poison */ + { + foreach ( Mobile m in list ) + { + bool isFriendly = ( m is Savage || m is SavageRider || m is SavageShaman || m is SavageRidgeback ); + + if ( isFriendly ) + continue; + + if ( !CanBeHarmful( m ) ) + continue; + + DoHarmful( m ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + double total = Skills[SkillName.Magery].Value + Skills[SkillName.Poisoning].Value; + + double dist = GetDistanceToSqrt( m ); + + if ( dist >= 3.0 ) + total -= (dist - 3.0) * 10.0; + + int level; + + if ( total >= 200.0 && Utility.Random( 1, 100 ) <= 10 ) + level = 3; + else if ( total > 170.0 ) + level = 2; + else if ( total > 130.0 ) + level = 1; + else + level = 0; + + m.ApplyPoison( this, Poison.GetPoison( level ) ); + + m.FixedParticles( 0x374A, 10, 15, 5021, EffectLayer.Waist ); + m.PlaySound( 0x474 ); + } + + break; + } + } + } + } + + public SavageShaman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Shade.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Shade.cs new file mode 100644 index 0000000..462e2bb --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Shade.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class Shade : BaseCreature + { + [Constructable] + public Shade() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a shade"; + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + + SetDamage( 7, 11 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + + SetSkill( SkillName.EvalInt, 55.1, 70.0 ); + SetSkill( SkillName.Magery, 55.1, 70.0 ); + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg( 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Shade( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs new file mode 100644 index 0000000..77d7358 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/SkeletalMage.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal corpse" )] + public class SkeletalMage : BaseCreature + { + [Constructable] + public SkeletalMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a skeletal mage"; + Body = 148; + BaseSoundID = 451; + + SetStr( 76, 100 ); + SetDex( 56, 75 ); + SetInt( 186, 210 ); + + SetHits( 46, 60 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 60.1, 70.0 ); + SetSkill( SkillName.Magery, 60.1, 70.0 ); + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + SetSkill(SkillName.Necromancy, 89, 99.1); + SetSkill(SkillName.SpiritSpeak, 90.0, 99.0); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 38; + PackReg( 3 ); + PackNecroReg( 3, 10 ); + PackItem( new Bone() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Potions ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + + public SkeletalMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Spectre.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Spectre.cs new file mode 100644 index 0000000..2f51408 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Spectre.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class Spectre : BaseCreature + { + [Constructable] + public Spectre() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a spectre"; + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + + SetDamage( 7, 11 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + + SetSkill( SkillName.EvalInt, 55.1, 70.0 ); + SetSkill( SkillName.Magery, 55.1, 70.0 ); + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg( 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Spectre( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Succubus.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Succubus.cs new file mode 100644 index 0000000..6b70d6f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Succubus.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a succubus corpse" )] + public class Succubus : BaseCreature + { + [Constructable] + public Succubus () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a succubus"; + Body = 149; + BaseSoundID = 0x4B0; + + SetStr( 488, 620 ); + SetDex( 121, 170 ); + SetInt( 498, 657 ); + + SetHits( 312, 353 ); + + SetDamage( 18, 28 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 99.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 80; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public void DrainLife() + { + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 2 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team) ) + list.Add( m ); + else if ( m.Player ) + list.Add( m ); + } + + foreach ( Mobile m in list ) + { + DoHarmful( m ); + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist ); + m.PlaySound( 0x231 ); + + //m.SendMessage( "You feel the life drain out of you!" ); + + int toDrain = Utility.RandomMinMax( 10, 40 ); + + Hits += toDrain; + m.Damage( toDrain, this ); + } + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 >= Utility.RandomDouble() ) + DrainLife(); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.1 >= Utility.RandomDouble() ) + DrainLife(); + } + + public Succubus( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Titan.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Titan.cs new file mode 100644 index 0000000..a261470 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Titan.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a titans corpse" )] + public class Titan : BaseCreature + { + [Constructable] + public Titan() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a titan"; + Body = 76; + BaseSoundID = 609; + + SetStr( 536, 585 ); + SetDex( 126, 145 ); + SetInt( 281, 305 ); + + SetHits( 322, 351 ); + + SetDamage( 13, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 85.1, 100.0 ); + SetSkill( SkillName.Magery, 85.1, 100.0 ); + SetSkill( SkillName.MagicResist, 80.2, 110.0 ); + SetSkill( SkillName.Tactics, 60.1, 80.0 ); + SetSkill( SkillName.Wrestling, 40.1, 50.0 ); + + Fame = 11500; + Karma = -11500; + + VirtualArmor = 40; + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(1) ); + } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (!corpse.Carved) + { + corpse.DropItem(new TitanTooth()); + from.SendMessage("Vous arrachez une dent au titan"); + } + + base.OnCarve(from, corpse, with); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.MedScrolls ); + } + + public override int Meat{ get{ return 4; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public Titan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Magic/Wraith.cs b/Scripts/Mobiles/Monsters/Humanoid/Magic/Wraith.cs new file mode 100644 index 0000000..70ca7d1 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Magic/Wraith.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class Wraith : BaseCreature + { + [Constructable] + public Wraith() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a wraith"; + Body = 26; + Hue = 0x4001; + BaseSoundID = 0x482; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + + SetDamage( 7, 11 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + + SetSkill( SkillName.EvalInt, 55.1, 70.0 ); + SetSkill( SkillName.Magery, 55.1, 70.0 ); + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 28; + + PackReg( 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Wraith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs new file mode 100644 index 0000000..d5b6c91 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/ArcticOgreLord.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a frozen ogre lord's corpse" )] + [TypeAlias( "Server.Mobiles.ArticOgreLord" )] + public class ArcticOgreLord : BaseCreature + { + [Constructable] + public ArcticOgreLord() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an arctic ogre lord"; + Body = 135; + BaseSoundID = 427; + + SetStr( 767, 945 ); + SetDex( 66, 75 ); + SetInt( 46, 70 ); + + SetHits( 476, 552 ); + + SetDamage( 20, 25 ); + + SetDamageType( ResistanceType.Physical, 30 ); + SetDamageType( ResistanceType.Cold, 70 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 125.1, 140.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + PackItem( new Club() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public ArcticOgreLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs new file mode 100644 index 0000000..f82dc11 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/BoneKnight.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal corpse" )] + public class BoneKnight : BaseCreature + { + [Constructable] + public BoneKnight() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bone knight"; + Body = 57; + BaseSoundID = 451; + + SetStr( 196, 250 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 118, 150 ); + + SetDamage( 8, 18 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 85.1, 100.0 ); + SetSkill( SkillName.Wrestling, 85.1, 95.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + switch ( Utility.Random( 6 ) ) + { + case 0: PackItem( new PlateArms() ); break; + case 1: PackItem( new PlateChest() ); break; + case 2: PackItem( new PlateGloves() ); break; + case 3: PackItem( new PlateGorget() ); break; + case 4: PackItem( new PlateLegs() ); break; + case 5: PackItem( new PlateHelm() ); break; + } + + PackSlayer(); + PackItem( new Scimitar() ); + PackItem( new WoodenShield() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public BoneKnight( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs new file mode 100644 index 0000000..047fc2b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Brigand.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class Brigand : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public Brigand() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "the brigand"; + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + AddItem( new Skirt( Utility.RandomNeutralHue() ) ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + + SetStr( 86, 100 ); + SetDex( 81, 95 ); + SetInt( 61, 75 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Fencing, 66.0, 97.5 ); + SetSkill( SkillName.Macing, 65.0, 87.5 ); + SetSkill( SkillName.MagicResist, 25.0, 47.5 ); + SetSkill( SkillName.Swords, 65.0, 87.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 15.0, 37.5 ); + + Fame = 1000; + Karma = -1000; + + AddItem( new Boots( Utility.RandomNeutralHue() ) ); + AddItem( new FancyShirt()); + AddItem( new Bandana()); + + switch ( Utility.Random( 7 )) + { + case 0: AddItem( new Longsword() ); break; + case 1: AddItem( new Cutlass() ); break; + case 2: AddItem( new Broadsword() ); break; + case 3: AddItem( new Axe() ); break; + case 4: AddItem( new Club() ); break; + case 5: AddItem( new Dagger() ); break; + case 6: AddItem( new Spear() ); break; + } + + Utility.AssignRandomHair( this ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.9) + c.DropItem(new SeveredHumanEars()); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public Brigand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs new file mode 100644 index 0000000..63d4a40 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/ChaosDaemon.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a chaos daemon corpse" )] + public class ChaosDaemon : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.CrushingBlow; + } + + [Constructable] + public ChaosDaemon() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a chaos daemon"; + Body = 792; + BaseSoundID = 0x3E9; + + SetStr( 106, 130 ); + SetDex( 171, 200 ); + SetInt( 56, 80 ); + + SetHits( 91, 110 ); + + SetDamage( 12, 17 ); + + SetDamageType( ResistanceType.Physical, 85 ); + SetDamageType( ResistanceType.Fire, 15 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 85.1, 95.0 ); + SetSkill( SkillName.Tactics, 70.1, 80.0 ); + SetSkill( SkillName.Wrestling, 95.1, 100.0 ); + + Fame = 3000; + Karma = -4000; + + VirtualArmor = 15; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + } + + public ChaosDaemon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Cursed.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Cursed.cs new file mode 100644 index 0000000..5b365e9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Cursed.cs @@ -0,0 +1,85 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an inhuman corpse" )] + public class Cursed : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + + [Constructable] + public Cursed() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Title = "the Cursed"; + + Hue = Utility.RandomMinMax( 0x8596, 0x8599 ); + Body = 0x190; + Name = NameList.RandomName( "male" ); + BaseSoundID = 471; + + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + AddItem( new Shirt( Utility.RandomNeutralHue() ) ); + + BaseWeapon weapon = Loot.RandomWeapon(); + weapon.Movable = false; + AddItem( weapon ); + + SetStr( 91, 100 ); + SetDex( 86, 95 ); + SetInt( 61, 70 ); + + SetHits( 91, 120 ); + + SetDamage( 5, 13 ); + + SetResistance( ResistanceType.Physical, 15, 25 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.Fencing, 46.0, 77.5 ); + SetSkill( SkillName.Macing, 35.0, 57.5 ); + SetSkill( SkillName.MagicResist, 53.5, 62.5 ); + SetSkill( SkillName.Swords, 55.0, 77.5 ); + SetSkill( SkillName.Tactics, 60.0, 82.5 ); + SetSkill( SkillName.Poisoning, 60.0, 82.5 ); + + Fame = 1000; + Karma = -2000; + } + + public override int GetAttackSound() + { + return -1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + //AddLoot( LootPack.Miscellaneous ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public Cursed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs new file mode 100644 index 0000000..5efc4f0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Cyclops.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a cyclopean corpse" )] + public class Cyclops : BaseCreature + { + [Constructable] + public Cyclops() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a cyclopean warrior"; + Body = 75; + BaseSoundID = 604; + + SetStr( 336, 385 ); + SetDex( 96, 115 ); + SetInt( 31, 55 ); + + SetHits( 202, 231 ); + SetMana( 0 ); + + SetDamage( 7, 23 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 60.3, 105.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 48; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override int Meat{ get{ return 4; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public Cyclops( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs new file mode 100644 index 0000000..cc20682 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Doppleganger.cs @@ -0,0 +1,64 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a doppleganger corpse" )] + public class Doppleganger : BaseCreature + { + [Constructable] + public Doppleganger() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a doppleganger"; + Body = 0x309; + BaseSoundID = 0x451; + + SetStr( 81, 110 ); + SetDex( 56, 75 ); + SetInt( 81, 105 ); + + SetHits( 101, 120 ); + + SetDamage( 8, 12 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 75.1, 85.0 ); + SetSkill( SkillName.Tactics, 70.1, 80.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 55; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override int Hides{ get{ return 6; } } + public override int Meat{ get{ return 1; } } + + public Doppleganger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs new file mode 100644 index 0000000..d8b7928 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/ElfBrigand.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + // TODO: Needs some Spellweaving abilities + public class ElfBrigand : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public ElfBrigand() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "the brigand"; + Race = Race.Elf; + Hue = Race.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x25E; + Name = NameList.RandomName( "female elf brigand" ); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Skirt( Utility.RandomNondyedHue() ) ); break; + case 1: AddItem( new Kilt( Utility.RandomNondyedHue() ) ); break; + } + } + else + { + Body = 0x25D; + Name = NameList.RandomName( "male elf brigand" ); + AddItem( new ShortPants( Utility.RandomNondyedHue() ) ); + } + + SetStr( 86, 100 ); + SetDex( 81, 95 ); + SetInt( 61, 75 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Fencing, 66.0, 97.5 ); + SetSkill( SkillName.Macing, 65.0, 87.5 ); + SetSkill( SkillName.MagicResist, 25.0, 47.5 ); + SetSkill( SkillName.Swords, 65.0, 87.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 15.0, 37.5 ); + + Fame = 1000; + Karma = -1000; + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new Boots() ); break; + case 1: AddItem( new ThighBoots() ); break; + case 2: AddItem( new Sandals() ); break; + case 3: AddItem( new Shoes() ); break; + } + + AddItem( new Shirt( Utility.RandomNondyedHue() ) ); + + switch ( Utility.Random( 7 ) ) + { + case 0: AddItem( new Longsword() ); break; + case 1: AddItem( new Cutlass() ); break; + case 2: AddItem( new Broadsword() ); break; + case 3: AddItem( new Axe() ); break; + case 4: AddItem( new Club() ); break; + case 5: AddItem( new Dagger() ); break; + case 6: AddItem( new Spear() ); break; + } + + Utility.AssignRandomHair( this, true ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.9 ) + c.DropItem( new SeveredElfEars() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public ElfBrigand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs new file mode 100644 index 0000000..357c02a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/EnslavedGargoyle.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an enslaved gargoyle corpse" )] + public class EnslavedGargoyle : BaseCreature + { + [Constructable] + public EnslavedGargoyle() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an enslaved gargoyle"; + Body = 0x2F1; + BaseSoundID = 0x174; + + SetStr( 302, 360 ); + SetDex( 76, 95 ); + SetInt( 81, 105 ); + + SetHits( 186,212 ); + + SetDamage( 7, 14 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 50, 70 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 25, 30 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 40.1, 80.0 ); + + Fame = 3500; + Karma = 0; + + VirtualArmor = 35; + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new GargoylesPickaxe() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.Gems ); + } + + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public EnslavedGargoyle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Ettin.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ettin.cs new file mode 100644 index 0000000..951130d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ettin.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an ettins corpse" )] + public class Ettin : BaseCreature + { + [Constructable] + public Ettin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ettin"; + Body = 18; + BaseSoundID = 367; + + SetStr( 136, 165 ); + SetDex( 56, 75 ); + SetInt( 31, 55 ); + + SetHits( 82, 99 ); + + SetDamage( 7, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.MagicResist, 40.1, 55.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 50.1, 60.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 38; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.Potions ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 4; } } + + public Ettin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Executioner.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Executioner.cs new file mode 100644 index 0000000..60b9ebb --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Executioner.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class Executioner : BaseCreature + { + [Constructable] + public Executioner() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomDyedHue(); + Title = "the executioner"; + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + AddItem( new Skirt( Utility.RandomRedHue() ) ); + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomRedHue() ) ); + } + + SetStr( 386, 400 ); + SetDex( 151, 165 ); + SetInt( 161, 175 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 25, 30 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 125.0 ); + SetSkill( SkillName.Fencing, 46.0, 77.5 ); + SetSkill( SkillName.Macing, 35.0, 57.5 ); + SetSkill( SkillName.Poisoning, 60.0, 82.5 ); + SetSkill( SkillName.MagicResist, 83.5, 92.5 ); + SetSkill( SkillName.Swords, 125.0 ); + SetSkill( SkillName.Tactics, 125.0 ); + SetSkill( SkillName.Lumberjacking, 125.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 40; + + AddItem( new ThighBoots( Utility.RandomRedHue() ) ); + AddItem( new Surcoat( Utility.RandomRedHue() ) ); + AddItem( new ExecutionersAxe()); + + Utility.AssignRandomHair( this ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Meager ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public Executioner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs new file mode 100644 index 0000000..4b4aa06 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/FrostTroll.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a frost troll corpse" )] + public class FrostTroll : BaseCreature + { + [Constructable] + public FrostTroll() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a frost troll"; + Body = 55; + BaseSoundID = 461; + + SetStr( 227, 265 ); + SetDex( 66, 85 ); + SetInt( 46, 70 ); + + SetHits( 140, 156 ); + + SetDamage( 14, 20 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Cold, 25 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 50; + + PackItem( new DoubleAxe() ); // TODO: Weapon?? + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems ); + } + + public override int Meat{ get{ return 2; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public FrostTroll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs new file mode 100644 index 0000000..900b686 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/GazerLarva.cs @@ -0,0 +1,64 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a gazer larva corpse" )] + public class GazerLarva : BaseCreature + { + [Constructable] + public GazerLarva () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a gazer larva"; + Body = 778; + BaseSoundID = 377; + + SetStr( 76, 100 ); + SetDex( 51, 75 ); + SetInt( 56, 80 ); + + SetHits( 36, 47 ); + + SetDamage( 2, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 25 ); + + SetSkill( SkillName.MagicResist, 70.0 ); + SetSkill( SkillName.Tactics, 70.0 ); + SetSkill( SkillName.Wrestling, 70.0 ); + + Fame = 900; + Karma = -900; + + VirtualArmor = 25; + + PackItem( new Nightshade( Utility.RandomMinMax( 2, 3 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + + public GazerLarva( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs new file mode 100644 index 0000000..32ccc02 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ghoul.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class Ghoul : BaseCreature + { + [Constructable] + public Ghoul() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a ghoul"; + Body = 153; + BaseSoundID = 0x482; + + SetStr( 76, 100 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 46, 60 ); + SetMana( 0 ); + + SetDamage( 7, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 28; + + PackItem( Loot.RandomWeapon() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + + public Ghoul( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs new file mode 100644 index 0000000..33368e9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/GreaterMongbat.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a mongbat corpse" )] + public class GreaterMongbat : BaseCreature + { + [Constructable] + public GreaterMongbat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a greater mongbat"; + Body = 39; + BaseSoundID = 422; + + SetStr( 56, 80 ); + SetDex( 61, 80 ); + SetInt( 26, 50 ); + + SetHits( 34, 48 ); + SetStam( 61, 80); + SetMana( 26, 50 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 25 ); + + SetSkill( SkillName.MagicResist, 15.1, 30.0 ); + SetSkill( SkillName.Tactics, 35.1, 50.0 ); + SetSkill( SkillName.Wrestling, 20.1, 35.0 ); + + Fame = 450; + Karma = -450; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public GreaterMongbat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Guardian.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Guardian.cs new file mode 100644 index 0000000..77979c9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Guardian.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + public class Guardian : BaseCreature + { + [Constructable] + public Guardian() : base( AIType.AI_Archer, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + InitStats( 100, 125, 25 ); + Title = "the guardian"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + new ForestOstard().Rider = this; + + PlateChest chest = new PlateChest(); + chest.Hue = 0x966; + AddItem( chest ); + PlateArms arms = new PlateArms(); + arms.Hue = 0x966; + AddItem( arms ); + PlateGloves gloves = new PlateGloves(); + gloves.Hue = 0x966; + AddItem( gloves ); + PlateGorget gorget = new PlateGorget(); + gorget.Hue = 0x966; + AddItem( gorget ); + PlateLegs legs = new PlateLegs(); + legs.Hue = 0x966; + AddItem( legs ); + PlateHelm helm = new PlateHelm(); + helm.Hue = 0x966; + AddItem( helm ); + + + Bow bow = new Bow(); + + bow.Movable = false; + bow.Crafter = this; + bow.Quality = WeaponQuality.Exceptional; + + AddItem( bow ); + + PackItem( new Arrow( 250 ) ); + PackGold( 250, 500 ); + + Skills[SkillName.Anatomy].Base = 120.0; + Skills[SkillName.Tactics].Base = 120.0; + Skills[SkillName.Archery].Base = 120.0; + Skills[SkillName.MagicResist].Base = 120.0; + Skills[SkillName.DetectHidden].Base = 100.0; + + } + + public Guardian( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs new file mode 100644 index 0000000..c4fa5e4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/HeadlessOne.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a headless corpse" )] + public class HeadlessOne : BaseCreature + { + [Constructable] + public HeadlessOne() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a headless one"; + Body = 31; + Hue = Utility.RandomSkinHue() & 0x7FFF; + BaseSoundID = 0x39D; + + SetStr( 26, 50 ); + SetDex( 36, 55 ); + SetInt( 16, 30 ); + + SetHits( 16, 30 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 25.1, 40.0 ); + SetSkill( SkillName.Wrestling, 25.1, 40.0 ); + + Fame = 450; + Karma = -450; + + VirtualArmor = 18; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + // TODO: body parts + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + + public HeadlessOne( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs new file mode 100644 index 0000000..303447a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/HordeMinion.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a horde minion corpse" )] + public class HordeMinion : BaseCreature + { + [Constructable] + public HordeMinion () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a horde minion"; + Body = 776; + BaseSoundID = 357; + + SetStr( 16, 40 ); + SetDex( 31, 60 ); + SetInt( 11, 25 ); + + SetHits( 10, 24 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + + SetSkill( SkillName.MagicResist, 10.0 ); + SetSkill( SkillName.Tactics, 0.1, 15.0 ); + SetSkill( SkillName.Wrestling, 25.1, 40.0 ); + + Fame = 500; + Karma = -500; + + VirtualArmor = 18; + + AddItem( new LightSource() ); + + PackItem( new Bone( 3 ) ); + // TODO: Body parts + } + + public override int GetIdleSound() + { + return 338; + } + + public override int GetAngerSound() + { + return 338; + } + + public override int GetDeathSound() + { + return 338; + } + + public override int GetAttackSound() + { + return 406; + } + + public override int GetHurtSound() + { + return 194; + } + + public HordeMinion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs new file mode 100644 index 0000000..96f572a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Juggernaut.cs @@ -0,0 +1,158 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a juggernaut corpse" )] + public class Juggernaut : BaseCreature + { + private bool m_Stunning; + + [Constructable] + public Juggernaut() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6 ) + { + Name = "a blackthorn juggernaut"; + Body = 768; + + + SetStr( 301, 400 ); + SetDex( 51, 70 ); + SetInt( 51, 100 ); + + SetHits( 181, 240 ); + + SetDamage( 12, 19 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 140.1, 150.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 12000; + Karma = -12000; + + VirtualArmor = 70; + + if ( 0.1 > Utility.RandomDouble() ) + PackItem( new PowerCrystal() ); + + if ( 0.4 > Utility.RandomDouble() ) + PackItem( new ClockworkAssembly() ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (0.05 > Utility.RandomDouble()) + { + if (!IsParagon) + { + if (0.75 > Utility.RandomDouble()) + c.DropItem(DawnsMusicGear.RandomCommon); + else + c.DropItem(DawnsMusicGear.RandomUncommon); + } + else + c.DropItem(DawnsMusicGear.RandomRare); + } + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 1 ); + } + + public override int GetDeathSound() + { + return 0x423; + } + + public override int GetAttackSound() + { + return 0x23B; + } + + public override int GetHurtSound() + { + return 0x140; + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !m_Stunning && 0.3 > Utility.RandomDouble() ) + { + m_Stunning = true; + + defender.Animate( 21, 6, 1, true, false, 0 ); + this.PlaySound( 0xEE ); + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You have been stunned by a colossal blow!" ); + + BaseWeapon weapon = this.Weapon as BaseWeapon; + if ( weapon != null ) + weapon.OnHit( this, defender ); + + if ( defender.Alive ) + { + defender.Frozen = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( Recover_Callback ), defender ); + } + } + } + + private void Recover_Callback( object state ) + { + Mobile defender = state as Mobile; + + if ( defender != null ) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You recover your senses." ); + } + + m_Stunning = false; + } + + public Juggernaut( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs new file mode 100644 index 0000000..584cca7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class KhaldunRevenant : BaseCreature + { + private static Hashtable m_Table = new Hashtable(); + + public static void Initialize() + { + EventSink.PlayerDeath += new PlayerDeathEventHandler( EventSink_PlayerDeath ); + } + + public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) + { + Mobile m = e.Mobile; + Mobile lastKiller = m.LastKiller; + + if ( lastKiller is BaseCreature ) + lastKiller = ((BaseCreature)lastKiller).GetMaster(); + + if ( IsInsideKhaldun( m ) && IsInsideKhaldun( lastKiller ) && lastKiller.Player && !m_Table.Contains( lastKiller ) ) + { + foreach ( AggressorInfo ai in m.Aggressors ) + { + if ( ai.Attacker == lastKiller && ai.CanReportMurder ) + { + SummonRevenant( m, lastKiller ); + break; + } + } + } + } + + public static void SummonRevenant( Mobile victim, Mobile killer ) + { + KhaldunRevenant revenant = new KhaldunRevenant( killer ); + + revenant.MoveToWorld( victim.Location, victim.Map ); + revenant.Combatant = killer; + revenant.FixedParticles( 0, 0, 0, 0x13A7, EffectLayer.Waist ); + Effects.PlaySound( revenant.Location, revenant.Map, 0x29 ); + + m_Table.Add( killer, null ); + } + + public static bool IsInsideKhaldun( Mobile from ) + { + return from != null && from.Region != null && from.Region.IsPartOf( "Khaldun" ); + } + + private Mobile m_Target; + private DateTime m_ExpireTime; + + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + public override void DisplayPaperdollTo( Mobile to ) + { + } + + public override Mobile ConstantFocus{ get{ return m_Target; } } + public override bool AlwaysAttackable{ get{ return true; } } + + public KhaldunRevenant( Mobile target ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.18, 0.36 ) + { + Name = "a revenant"; + Body = 0x3CA; + Hue = 0x41CE; + + m_Target = target; + m_ExpireTime = DateTime.Now + TimeSpan.FromMinutes( 10.0 ); + + SetStr( 401, 500 ); + SetDex( 296, 315 ); + SetInt( 101, 200 ); + + SetHits( 241, 300 ); + SetStam( 242, 280 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetSkill( SkillName.MagicResist, 100.1, 150.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Swords, 140.1, 150.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + Fame = 0; + Karma = 0; + + VirtualArmor = 60; + + Halberd weapon = new Halberd(); + weapon.Hue = 0x41CE; + weapon.Movable = false; + + AddItem( weapon ); + } + + public override int GetIdleSound() + { + return 0x1BF; + } + + public override int GetAngerSound() + { + return 0x107; + } + + public override int GetDeathSound() + { + return 0xFD; + } + + public override bool BardImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override void OnThink() + { + if ( !m_Target.Alive || DateTime.Now > m_ExpireTime ) + { + Delete(); + return; + } + + //Combatant = m_Target; + //FocusMob = m_Target; + + if ( AIObject != null ) + AIObject.Action = ActionType.Combat; + + base.OnThink(); + } + + public override bool OnBeforeDeath() + { + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public override void OnDelete() + { + if ( m_Target != null ) + m_Table.Remove( m_Target ); + + base.OnDelete(); + } + + public KhaldunRevenant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs new file mode 100644 index 0000000..aef444a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs @@ -0,0 +1,144 @@ +using System; +using Server.Misc; +using Server.Network; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class KhaldunSummoner : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + + [Constructable] + public KhaldunSummoner():base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 0x190; + Name = "Zealot of Khaldun"; + Title = "the Summoner"; + + SetStr( 351, 400 ); + SetDex( 101, 150 ); + SetInt( 502, 700 ); + + SetHits( 421, 480 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Cold, 25 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Meditation, 120.1, 130.0 ); + + VirtualArmor = 36; + Fame = 10000; + Karma = -10000; + + LeatherGloves gloves = new LeatherGloves(); + gloves.Hue = 0x66D; + AddItem( gloves ); + + BoneHelm helm = new BoneHelm(); + helm.Hue = 0x835; + AddItem( helm ); + + Necklace necklace = new Necklace(); + necklace.Hue = 0x66D; + AddItem( necklace ); + + Cloak cloak = new Cloak(); + cloak.Hue = 0x66D; + AddItem( cloak ); + + Kilt kilt = new Kilt(); + kilt.Hue = 0x66D; + AddItem( kilt ); + + Sandals sandals = new Sandals(); + sandals.Hue = 0x66D; + AddItem( sandals ); + } + + public override int GetIdleSound() + { + return 0x184; + } + + public override int GetAngerSound() + { + return 0x286; + } + + public override int GetDeathSound() + { + return 0x288; + } + + public override int GetHurtSound() + { + return 0x19F; + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool Unprovokable{ get{ return true; } } + + public KhaldunSummoner( Serial serial ) : base( serial ) + { + } + + public override bool OnBeforeDeath() + { + BoneMagi rm = new BoneMagi(); + rm.Team = this.Team; + rm.Combatant = this.Combatant; + rm.NoKillAwards = true; + + if ( rm.Backpack == null ) + { + Backpack pack = new Backpack(); + pack.Movable = false; + rm.AddItem( pack ); + } + + for ( int i = 0; i < 2; i++ ) + { + LootPack.FilthyRich.Generate( this, rm.Backpack, true, LootPack.GetLuckChanceForKiller( this ) ); + LootPack.FilthyRich.Generate( this, rm.Backpack, false, LootPack.GetLuckChanceForKiller( this ) ); + } + + Effects.PlaySound(this, Map, GetDeathSound()); + Effects.SendLocationEffect( Location, Map, 0x3709, 30, 10, 0x835, 0 ); + rm.MoveToWorld( Location, Map ); + + Delete(); + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs new file mode 100644 index 0000000..18229c0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs @@ -0,0 +1,153 @@ +using System; +using Server.Misc; +using Server.Network; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class KhaldunZealot : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + public override bool ShowFameTitle{ get{ return false; } } + + [Constructable] + public KhaldunZealot(): base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 0x190; + Name = "Zealot of Khaldun"; + Title = "the Knight"; + Hue = 0; + + SetStr( 351, 400 ); + SetDex( 151, 165 ); + SetInt( 76, 100 ); + + SetHits( 448, 470 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Cold, 25 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Wrestling, 70.1, 80.0 ); + SetSkill( SkillName.Swords, 120.1, 130.0 ); + SetSkill( SkillName.Anatomy, 120.1, 130.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + + Fame = 10000; + Karma = -10000; + VirtualArmor = 40; + + VikingSword weapon = new VikingSword(); + weapon.Hue = 0x835; + weapon.Movable = false; + AddItem( weapon ); + + MetalShield shield = new MetalShield(); + shield.Hue = 0x835; + shield.Movable = false; + AddItem( shield ); + + BoneHelm helm = new BoneHelm(); + helm.Hue = 0x835; + AddItem( helm ); + + BoneArms arms = new BoneArms(); + arms.Hue = 0x835; + AddItem( arms ); + + BoneGloves gloves = new BoneGloves(); + gloves.Hue = 0x835; + AddItem( gloves ); + + BoneChest tunic = new BoneChest(); + tunic.Hue = 0x835; + AddItem( tunic ); + + BoneLegs legs = new BoneLegs(); + legs.Hue = 0x835; + AddItem( legs ); + + AddItem( new Boots() ); + } + + public override int GetIdleSound() + { + return 0x184; + } + + public override int GetAngerSound() + { + return 0x286; + } + + public override int GetDeathSound() + { + return 0x288; + } + + public override int GetHurtSound() + { + return 0x19F; + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool Unprovokable{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + + public KhaldunZealot( Serial serial ) : base( serial ) + { + } + + public override bool OnBeforeDeath() + { + BoneKnight rm = new BoneKnight(); + rm.Team = this.Team; + rm.Combatant = this.Combatant; + rm.NoKillAwards = true; + + if ( rm.Backpack == null ) + { + Backpack pack = new Backpack(); + pack.Movable = false; + rm.AddItem( pack ); + } + + for ( int i = 0; i < 2; i++ ) + { + LootPack.FilthyRich.Generate( this, rm.Backpack, true, LootPack.GetLuckChanceForKiller( this ) ); + LootPack.FilthyRich.Generate( this, rm.Backpack, false, LootPack.GetLuckChanceForKiller( this ) ); + } + + Effects.PlaySound(this, Map, GetDeathSound()); + Effects.SendLocationEffect( Location, Map, 0x3709, 30, 10, 0x835, 0 ); + rm.MoveToWorld( Location, Map ); + + Delete(); + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Moloch.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Moloch.cs new file mode 100644 index 0000000..34d88ec --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Moloch.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a moloch corpse" )] + public class Moloch : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ConcussionBlow; + } + + [Constructable] + public Moloch() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a moloch"; + Body = 0x311; + BaseSoundID = 0x300; + + SetStr( 331, 360 ); + SetDex( 66, 85 ); + SetInt( 41, 65 ); + + SetHits( 171, 200 ); + + SetDamage( 15, 23 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 65.1, 75.0 ); + SetSkill( SkillName.Tactics, 75.1, 90.0 ); + SetSkill( SkillName.Wrestling, 70.1, 90.0 ); + + Fame = 7500; + Karma = -7500; + + VirtualArmor = 32; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + + public Moloch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs new file mode 100644 index 0000000..2d7e6d4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Mongbat.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a mongbat corpse" )] + public class Mongbat : BaseCreature + { + [Constructable] + public Mongbat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a mongbat"; + Body = 39; + BaseSoundID = 422; + + SetStr( 6, 10 ); + SetDex( 26, 38 ); + SetInt( 6, 14 ); + + SetHits( 4, 6 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.1, 14.0 ); + SetSkill( SkillName.Tactics, 5.1, 10.0 ); + SetSkill( SkillName.Wrestling, 5.1, 10.0 ); + + Fame = 150; + Karma = -150; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -18.9; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override bool CanFly { get { return true; } } + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public Mongbat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Mummy.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Mummy.cs new file mode 100644 index 0000000..e22225d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Mummy.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a mummy corpse" )] + public class Mummy : BaseCreature + { + [Constructable] + public Mummy() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8 ) + { + Name = "a mummy"; + Body = 154; + BaseSoundID = 471; + + SetStr( 346, 370 ); + SetDex( 71, 90 ); + SetInt( 26, 40 ); + + SetHits( 208, 222 ); + + SetDamage( 13, 23 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 15.1, 40.0 ); + SetSkill( SkillName.Tactics, 35.1, 50.0 ); + SetSkill( SkillName.Wrestling, 35.1, 50.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 50; + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(2) ); + + PackItem( new Garlic( 5 ) ); + PackItem( new Bandage( 10 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems ); + AddLoot( LootPack.Potions ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + + public Mummy( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Ogre.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ogre.cs new file mode 100644 index 0000000..1dbc14b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ogre.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an ogre corpse" )] + public class Ogre : BaseCreature + { + [Constructable] + public Ogre () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ogre"; + Body = 1; + BaseSoundID = 427; + + SetStr( 166, 195 ); + SetDex( 46, 65 ); + SetInt( 46, 70 ); + + SetHits( 100, 117 ); + SetMana( 0 ); + + SetDamage( 9, 11 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 25 ); + + SetSkill( SkillName.MagicResist, 55.1, 70.0 ); + SetSkill( SkillName.Tactics, 60.1, 70.0 ); + SetSkill( SkillName.Wrestling, 70.1, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 32; + + PackItem( new Club() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Potions ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 2; } } + + public Ogre( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs new file mode 100644 index 0000000..593917b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/OgreLord.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Factions; + +namespace Server.Mobiles +{ + [CorpseName( "an ogre lords corpse" )] + public class OgreLord : BaseCreature + { + public override Faction FactionAllegiance { get { return Minax.Instance; } } + public override Ethics.Ethic EthicAllegiance { get { return Ethics.Ethic.Evil; } } + + [Constructable] + public OgreLord () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ogre lord"; + Body = 83; + BaseSoundID = 427; + + SetStr( 767, 945 ); + SetDex( 66, 75 ); + SetInt( 46, 70 ); + + SetHits( 476, 552 ); + + SetDamage( 20, 25 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 125.1, 140.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + PackItem( new Club() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override int TreasureMapLevel{ get{ return 3; } } + public override int Meat{ get{ return 2; } } + + public OgreLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Orc.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Orc.cs new file mode 100644 index 0000000..01bd07d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Orc.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class Orc : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public Orc() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "orc" ); + Body = 17; + BaseSoundID = 0x45A; + + SetStr( 96, 120 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 50.1, 75.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + + switch ( Utility.Random( 20 ) ) + { + case 0: PackItem( new Scimitar() ); break; + case 1: PackItem( new Katana() ); break; + case 2: PackItem( new WarMace() ); break; + case 3: PackItem( new WarHammer() ); break; + case 4: PackItem( new Kryss() ); break; + case 5: PackItem( new Pitchfork() ); break; + } + + PackItem( new ThighBoots() ); + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( rib); break; + case 1: PackItem( new Shaft() ); break; + case 2: PackItem( new Candle() ); break; + } + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + public Orc( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs new file mode 100644 index 0000000..2277be3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcBomber.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class OrcBomber : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public OrcBomber() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 182; + + Name = "an orc bomber"; + BaseSoundID = 0x45A; + + SetStr( 147, 215 ); + SetDex( 91, 115 ); + SetInt( 61, 85 ); + + SetHits( 95, 123 ); + + SetDamage( 1, 8 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Fire, 25 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 15, 20 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Swords, 60.1, 85.0 ); + SetSkill( SkillName.Tactics, 75.1, 90.0 ); + SetSkill( SkillName.Wrestling, 60.1, 85.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 30; + + PackItem( new SulfurousAsh( Utility.RandomMinMax( 6, 10 ) ) ); + PackItem( new MandrakeRoot( Utility.RandomMinMax( 6, 10 ) ) ); + PackItem( new BlackPearl( Utility.RandomMinMax( 6, 10 ) ) ); + PackItem( new MortarPestle() ); + PackItem( new LesserExplosionPotion() ); + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + private DateTime m_NextBomb; + private int m_Thrown; + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != Map || !InRange( combatant, 12 ) || !CanBeHarmful( combatant ) || !InLOS( combatant ) ) + return; + + if ( DateTime.Now >= m_NextBomb ) + { + ThrowBomb( combatant ); + + m_Thrown++; + + if ( 0.75 >= Utility.RandomDouble() && (m_Thrown % 2) == 1 ) // 75% chance to quickly throw another bomb + m_NextBomb = DateTime.Now + TimeSpan.FromSeconds( 3.0 ); + else + m_NextBomb = DateTime.Now + TimeSpan.FromSeconds( 5.0 + (10.0 * Utility.RandomDouble()) ); // 5-15 seconds + } + } + + public void ThrowBomb( Mobile m ) + { + DoHarmful( m ); + + this.MovingParticles( m, 0x1C19, 1, 0, false, true, 0, 0, 9502, 6014, 0x11D, EffectLayer.Waist, 0 ); + + new InternalTimer( m, this ).Start(); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile, m_From; + + public InternalTimer( Mobile m, Mobile from ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound( 0x11D ); + AOS.Damage( m_Mobile, m_From, Utility.RandomMinMax( 10, 20 ), 0, 100, 0, 0, 0 ); + } + } + + public OrcBomber( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs new file mode 100644 index 0000000..a4ee300 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcBrute.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class OrcBrute : BaseCreature + { + [Constructable] + public OrcBrute() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 189; + + Name = "an orc brute"; + BaseSoundID = 0x45A; + + SetStr( 767, 945 ); + SetDex( 66, 75 ); + SetInt( 46, 70 ); + + SetHits( 476, 552 ); + + SetDamage( 20, 25 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Macing, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 125.1, 140.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + Item ore = new ShadowOre(25); + ore.ItemID = 0x19B9; + PackItem(ore); + PackItem( new IronIngot( 10 ) ); + + if ( 0.05 > Utility.RandomDouble() ) + PackItem( new OrcishKinMask() ); + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int Meat{ get{ return 2; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override bool AutoDispel{ get{ return true; } } + + public override void OnDamagedBySpell( Mobile caster ) + { + if ( caster == this ) + return; + + SpawnOrcLord( caster ); + } + + public void SpawnOrcLord( Mobile target ) + { + Map map = target.Map; + + if ( map == null ) + return; + + int orcs = 0; + + foreach ( Mobile m in this.GetMobilesInRange( 10 ) ) + { + if ( m is OrcishLord ) + ++orcs; + } + + if ( orcs < 10 ) + { + BaseCreature orc = new SpawnedOrcishLord(); + + orc.Team = this.Team; + + Point3D loc = target.Location; + bool validLocation = false; + + for ( int j = 0; !validLocation && j < 10; ++j ) + { + int x = target.X + Utility.Random( 3 ) - 1; + int y = target.Y + Utility.Random( 3 ) - 1; + int z = map.GetAverageZ( x, y ); + + if ( validLocation = map.CanFit( x, y, this.Z, 16, false, false ) ) + loc = new Point3D( x, y, Z ); + else if ( validLocation = map.CanFit( x, y, z, 16, false, false ) ) + loc = new Point3D( x, y, z ); + } + + orc.MoveToWorld( loc, map ); + + orc.Combatant = target; + } + } + + public OrcBrute( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs new file mode 100644 index 0000000..d5c12e4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcCaptain.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class OrcCaptain : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public OrcCaptain() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "orc" ); + Body = 7; + BaseSoundID = 0x45A; + + SetStr( 111, 145 ); + SetDex( 101, 135 ); + SetInt( 86, 110 ); + + SetHits( 67, 87 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Swords, 70.1, 95.0 ); + SetSkill( SkillName.Tactics, 85.1, 100.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 34; + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + // TODO: Skull? + switch ( Utility.Random( 7 ) ) + { + case 0: PackItem( new Arrow() ); break; + case 1: PackItem( new Lockpick() ); break; + case 2: PackItem( new Shaft() ); break; + case 3: PackItem( rib ); break; + case 4: PackItem( new Bandage() ); break; + case 5: PackItem( new BeverageBottle( BeverageType.Wine ) ); break; + case 6: PackItem( new Jug( BeverageType.Cider ) ); break; + } + + if ( Core.AOS ) + PackItem( Loot.RandomNecromancyReagent() ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + // TODO: Check drop rate + if (Utility.RandomDouble() < 0.05) + c.DropItem(new StoutWhip()); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + public OrcCaptain( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs new file mode 100644 index 0000000..666d473 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/OrcishLord.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class OrcishLord : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Orc; } } + + [Constructable] + public OrcishLord() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an orcish lord"; + Body = 138; + BaseSoundID = 0x45A; + + SetStr( 147, 215 ); + SetDex( 91, 115 ); + SetInt( 61, 85 ); + + SetHits( 95, 123 ); + + SetDamage( 4, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Swords, 60.1, 85.0 ); + SetSkill( SkillName.Tactics, 75.1, 90.0 ); + SetSkill( SkillName.Wrestling, 60.1, 85.0 ); + + Fame = 2500; + Karma = -2500; + + switch ( Utility.Random( 5 ) ) + { + case 0: PackItem( new Lockpick() ); break; + case 1: PackItem( new MortarPestle() ); break; + case 2: PackItem( new Bottle() ); break; + case 3: PackItem( new RawRibs() ); break; + case 4: PackItem( new Shovel() ); break; + } + + PackItem( new RingmailChest() ); + + if ( 0.3 > Utility.RandomDouble() ) + PackItem( Loot.RandomPossibleReagent() ); + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Average ); + // TODO: evil orc helm + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.Player && m.FindItemOnLayer( Layer.Helm ) is OrcishKinMask ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + Item item = aggressor.FindItemOnLayer( Layer.Helm ); + + if ( item is OrcishKinMask ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + item.Delete(); + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + } + } + + public OrcishLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Ratman.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ratman.cs new file mode 100644 index 0000000..6c0c70e --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Ratman.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman's corpse" )] + public class Ratman : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public Ratman() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "ratman" ); + Body = 42; + BaseSoundID = 437; + + SetStr( 96, 120 ); + SetDex( 81, 100 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + + SetDamage( 4, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 35.1, 60.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon, misc + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public Ratman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs new file mode 100644 index 0000000..9a547f4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/RatmanArcher.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a ratman archer corpse" )] + public class RatmanArcher : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Ratman; } } + + [Constructable] + public RatmanArcher() : base( AIType.AI_Archer, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "ratman" ); + Body = 0x8E; + BaseSoundID = 437; + + SetStr( 146, 180 ); + SetDex( 101, 130 ); + SetInt( 116, 140 ); + + SetHits( 88, 108 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 55 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 60.2, 100.0 ); + SetSkill( SkillName.Archery, 80.1, 90.0 ); + SetSkill( SkillName.MagicResist, 65.1, 90.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 6500; + Karma = -6500; + + VirtualArmor = 56; + + AddItem( new Bow() ); + PackItem( new Arrow( Utility.RandomMinMax( 50, 70 ) ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public RatmanArcher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( Body == 42 ) + { + Body = 0x8E; + Hue = 0; + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs new file mode 100644 index 0000000..f5ef96b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/RestlessSoul.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Targeting; +using Server.Engines.Quests; +using Server.Engines.Quests.Haven; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [CorpseName( "a ghostly corpse" )] + public class RestlessSoul : BaseCreature + { + [Constructable] + public RestlessSoul() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8 ) + { + Name = "restless soul"; + Body = 0x3CA; + Hue = 0x453; + + SetStr( 26, 40 ); + SetDex( 26, 40 ); + SetInt( 26, 40 ); + + SetHits( 16, 24 ); + + SetDamage( 1, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 25 ); + SetResistance( ResistanceType.Fire, 5, 15 ); + SetResistance( ResistanceType.Cold, 25, 40 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 20.1, 30.0 ); + SetSkill( SkillName.Swords, 20.1, 30.0 ); + SetSkill( SkillName.Tactics, 20.1, 30.0 ); + SetSkill( SkillName.Wrestling, 20.1, 30.0 ); + + Fame = 500; + Karma = -500; + + VirtualArmor = 6; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override bool AlwaysAttackable{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + + public override void DisplayPaperdollTo(Mobile to) + { + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + for ( int i = 0; i < list.Count; ++i ) + { + if ( list[i] is ContextMenus.PaperdollEntry ) + list.RemoveAt( i-- ); + } + } + + public override int GetIdleSound() + { + return 0x107; + } + + public override int GetAngerSound() + { + return 0x1BF; + } + + public override int GetDeathSound() + { + return 0xFD; + } + + public override bool IsEnemy( Mobile m ) + { + PlayerMobile player = m as PlayerMobile; + + if ( player != null && Map == Map.Trammel && X >= 5199 && X <= 5271 && Y >= 1812 && Y <= 1865 ) // Schmendrick's cave + { + QuestSystem qs = player.Quest; + + if ( qs is UzeraanTurmoilQuest && qs.IsObjectiveInProgress( typeof( FindSchmendrickObjective ) ) ) + { + return false; + } + } + + return base.IsEnemy( m ); + } + + public RestlessSoul( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs new file mode 100644 index 0000000..1b0005c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/RottingCorpse.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a rotting corpse" )] + public class RottingCorpse : BaseCreature + { + [Constructable] + public RottingCorpse() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a rotting corpse"; + Body = 155; + BaseSoundID = 471; + + SetStr( 301, 350 ); + SetDex( 75 ); + SetInt( 151, 200 ); + + SetHits( 1200 ); + SetStam( 150 ); + SetMana( 0 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 70 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.Poisoning, 120.0 ); + SetSkill( SkillName.MagicResist, 250.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public RottingCorpse( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Savage.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Savage.cs new file mode 100644 index 0000000..119f34b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Savage.cs @@ -0,0 +1,118 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a savage corpse" )] + public class Savage : BaseCreature + { + [Constructable] + public Savage() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "savage" ); + + if ( Female = Utility.RandomBool() ) + Body = 184; + else + Body = 183; + + SetStr( 96, 115 ); + SetDex( 86, 105 ); + SetInt( 51, 65 ); + + SetDamage( 23, 27 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetSkill( SkillName.Fencing, 60.0, 82.5 ); + SetSkill( SkillName.Macing, 60.0, 82.5 ); + SetSkill( SkillName.Poisoning, 60.0, 82.5 ); + SetSkill( SkillName.MagicResist, 57.5, 80.0 ); + SetSkill( SkillName.Swords, 60.0, 82.5 ); + SetSkill( SkillName.Tactics, 60.0, 82.5 ); + + Fame = 1000; + Karma = -1000; + + PackItem( new Bandage( Utility.RandomMinMax( 1, 15 ) ) ); + + if ( Female && 0.1 > Utility.RandomDouble() ) + PackItem( new TribalBerry() ); + else if ( !Female && 0.1 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + + AddItem( new Spear() ); + AddItem( new BoneArms() ); + AddItem( new BoneLegs() ); + + if ( 0.5 > Utility.RandomDouble() ) + AddItem( new SavageMask() ); + else if ( 0.1 > Utility.RandomDouble() ) + AddItem( new OrcishKinMask() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int Meat{ get{ return 1; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.BodyMod == 183 || m.BodyMod == 184 ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + if ( aggressor.BodyMod == 183 || aggressor.BodyMod == 184 ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + aggressor.BodyMod = 0; + aggressor.HueMod = -1; + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + aggressor.SendLocalizedMessage( 1040008 ); // Your skin is scorched as the tribal paint burns away! + + if ( aggressor is PlayerMobile ) + ((PlayerMobile)aggressor).SavagePaintExpiration = TimeSpan.Zero; + } + } + + public override void AlterMeleeDamageTo( Mobile to, ref int damage ) + { + if ( to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || to is LesserHiryu || to is Daemon ) + damage *= 3; + } + + public Savage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs new file mode 100644 index 0000000..6190da4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/SavageRider.cs @@ -0,0 +1,128 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a savage corpse" )] + public class SavageRider : BaseCreature + { + [Constructable] + public SavageRider() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.15, 0.4 ) + { + Name = NameList.RandomName( "savage rider" ); + + if ( Female = Utility.RandomBool() ) + Body = 186; + else + Body = 185; + + SetStr( 151, 170 ); + SetDex( 92, 130 ); + SetInt( 51, 65 ); + + SetDamage( 29, 34 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetSkill( SkillName.Fencing, 72.5, 95.0 ); + SetSkill( SkillName.Healing, 60.3, 90.0 ); + SetSkill( SkillName.Macing, 72.5, 95.0 ); + SetSkill( SkillName.Poisoning, 60.0, 82.5 ); + SetSkill( SkillName.MagicResist, 72.5, 95.0 ); + SetSkill( SkillName.Swords, 72.5, 95.0 ); + SetSkill( SkillName.Tactics, 72.5, 95.0 ); + + Fame = 1000; + Karma = -1000; + + PackItem( new Bandage( Utility.RandomMinMax( 1, 15 ) ) ); + + if ( 0.1 > Utility.RandomDouble() ) + PackItem( new BolaBall() ); + + AddItem( new TribalSpear() ); + AddItem( new BoneArms() ); + AddItem( new BoneLegs() ); + // TODO: BEAR MASK + + new SavageRidgeback().Rider = this; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override int Meat{ get{ return 1; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.SavagesAndOrcs; } + } + + public override bool OnBeforeDeath() + { + IMount mount = this.Mount; + + if ( mount != null ) + mount.Rider = null; + + if ( mount is Mobile ) + ((Mobile)mount).Delete(); + + return base.OnBeforeDeath(); + } + + public override bool IsEnemy( Mobile m ) + { + if ( m.BodyMod == 183 || m.BodyMod == 184 ) + return false; + + return base.IsEnemy( m ); + } + + public override void AggressiveAction( Mobile aggressor, bool criminal ) + { + base.AggressiveAction( aggressor, criminal ); + + if ( aggressor.BodyMod == 183 || aggressor.BodyMod == 184 ) + { + AOS.Damage( aggressor, 50, 0, 100, 0, 0, 0 ); + aggressor.BodyMod = 0; + aggressor.HueMod = -1; + aggressor.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + aggressor.PlaySound( 0x307 ); + aggressor.SendLocalizedMessage( 1040008 ); // Your skin is scorched as the tribal paint burns away! + + if ( aggressor is PlayerMobile ) + ((PlayerMobile)aggressor).SavagePaintExpiration = TimeSpan.Zero; + } + } + + public override void AlterMeleeDamageTo( Mobile to, ref int damage ) + { + if ( to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || to is LesserHiryu || to is Daemon ) + damage *= 3; + } + + public SavageRider( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs new file mode 100644 index 0000000..1c92f06 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/ShadowFiend.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + public class ShadowFiend : BaseCreature + { + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + private UnhideTimer m_Timer; + + [Constructable] + public ShadowFiend() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a shadow fiend"; + Body = 0xA8; + + // this to allow shadow fiend to loot from corpses + Backpack backpack = new Backpack(); + backpack.Movable = false; + AddItem( backpack ); + + SetStr( 46, 55 ); + SetDex( 121, 130 ); + SetInt( 46, 55 ); + + SetHits( 28, 33 ); + SetStam( 46, 55 ); + + SetDamage( 10, 22 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 20, 25 ); + SetResistance( ResistanceType.Cold, 40, 45 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 5, 10 ); + + SetSkill( SkillName.MagicResist, 20.1, 30.0 ); + SetSkill( SkillName.Tactics, 20.1, 30.0 ); + SetSkill( SkillName.Wrestling, 20.1, 30.0 ); + + Fame = 1000; + Karma = -1000; + + m_Timer = new UnhideTimer( this ); + m_Timer.Start(); + } + + public override int GetIdleSound() + { + return 0x37A; + } + + public override int GetAngerSound() + { + return 0x379; + } + + public override int GetDeathSound() + { + return 0x381; + } + + public override int GetAttackSound() + { + return 0x37F; + } + + public override int GetHurtSound() + { + return 0x380; + } + + public override bool CanRummageCorpses{ get{ return true; } } + + public override bool OnBeforeDeath() + { + if ( Backpack != null ) + Backpack.Destroy(); + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public ShadowFiend( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + m_Timer = new UnhideTimer( this ); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + base.OnAfterDelete(); + } + + private class UnhideTimer : Timer + { + private ShadowFiend m_Owner; + + public UnhideTimer( ShadowFiend owner ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Owner = owner; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + foreach ( Mobile m in m_Owner.GetMobilesInRange( 3 ) ) + { + if ( m != m_Owner && m.Player && m.Hidden && m_Owner.CanBeHarmful( m ) && m.AccessLevel == AccessLevel.Player ) + m.Hidden = false; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs new file mode 100644 index 0000000..461ce54 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/SkeletalKnight.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal corpse" )] + public class SkeletalKnight : BaseCreature + { + [Constructable] + public SkeletalKnight() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a skeletal knight"; + Body = 147; + BaseSoundID = 451; + + SetStr( 196, 250 ); + SetDex( 76, 95 ); + SetInt( 36, 60 ); + + SetHits( 118, 150 ); + + SetDamage( 8, 18 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 85.1, 100.0 ); + SetSkill( SkillName.Wrestling, 85.1, 95.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 40; + + switch ( Utility.Random( 6 ) ) + { + case 0: PackItem( new PlateArms() ); break; + case 1: PackItem( new PlateChest() ); break; + case 2: PackItem( new PlateGloves() ); break; + case 3: PackItem( new PlateGorget() ); break; + case 4: PackItem( new PlateLegs() ); break; + case 5: PackItem( new PlateHelm() ); break; + } + + PackItem( new Scimitar() ); + PackItem( new WoodenShield() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + } + + public override bool BleedImmune{ get{ return true; } } + + public SkeletalKnight( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs new file mode 100644 index 0000000..2e27b23 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Skeleton.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal corpse" )] + public class Skeleton : BaseCreature + { + [Constructable] + public Skeleton() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a skeleton"; + Body = Utility.RandomList( 50, 56 ); + BaseSoundID = 0x48D; + + SetStr( 56, 80 ); + SetDex( 56, 75 ); + SetInt( 16, 40 ); + + SetHits( 34, 48 ); + + SetDamage( 3, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 25, 40 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 5, 15 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 55.0 ); + + Fame = 450; + Karma = -450; + + VirtualArmor = 16; + + switch ( Utility.Random( 5 )) + { + case 0: PackItem( new BoneArms() ); break; + case 1: PackItem( new BoneChest() ); break; + case 2: PackItem( new BoneGloves() ); break; + case 3: PackItem( new BoneLegs() ); break; + case 4: PackItem( new BoneHelm() ); break; + } + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + + public Skeleton( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs new file mode 100644 index 0000000..ad7c52b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/SpawnedOrcishLord.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an orcish corpse" )] + public class SpawnedOrcishLord : OrcishLord + { + [Constructable] + public SpawnedOrcishLord() + { + Container pack = this.Backpack; + + if ( pack != null ) + pack.Delete(); + + NoKillAwards = true; + } + + public SpawnedOrcishLord( Serial serial ) : base( serial ) + { + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + NoKillAwards = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs new file mode 100644 index 0000000..28c8203 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/SpectralArmour.cs @@ -0,0 +1,97 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + + public class SpectralArmour : BaseCreature + { + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + [Constructable] + public SpectralArmour() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 637; + Hue = 0x8026; + Name = "spectral armour"; + + Buckler buckler = new Buckler(); + ChainCoif coif = new ChainCoif(); + PlateGloves gloves = new PlateGloves(); + + buckler.Hue = 0x835; buckler.Movable = false; + coif.Hue = 0x835; + gloves.Hue = 0x835; + + AddItem( buckler ); + AddItem( coif ); + AddItem( gloves ); + + SetStr( 101, 110 ); + SetDex( 101, 110 ); + SetInt( 101, 110 ); + + SetHits( 178, 201 ); + SetStam( 191, 200 ); + + SetDamage( 10, 22 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Cold, 25 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.Wrestling, 75.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100 ); + + VirtualArmor = 40; + Fame = 7000; + Karma = -7000; + } + + public override int GetIdleSound() + { + return 0x200; + } + + public override int GetAngerSound() + { + return 0x56; + } + + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + Gold gold = new Gold( Utility.RandomMinMax( 240, 375 ) ); + gold.MoveToWorld( Location, Map ); + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + + public SpectralArmour( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs new file mode 100644 index 0000000..32ca53f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/StoneGargoyle.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a gargoyle corpse" )] + public class StoneGargoyle : BaseCreature + { + [Constructable] + public StoneGargoyle() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a stone gargoyle"; + Body = 67; + BaseSoundID = 0x174; + + SetStr( 246, 275 ); + SetDex( 76, 95 ); + SetInt( 81, 105 ); + + SetHits( 148, 165 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 85.1, 100.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 50; + + PackItem( new IronIngot( 12 ) ); + + if ( 0.05 > Utility.RandomDouble() ) + PackItem( new GargoylesPickaxe() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.Gems, 1 ); + AddLoot( LootPack.Potions ); + } + + public override int TreasureMapLevel{ get{ return 2; } } + + public StoneGargoyle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs new file mode 100644 index 0000000..9808ee5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/StrongMongbat.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a mongbat corpse" )] + public class StrongMongbat : BaseCreature + { + [Constructable] + public StrongMongbat() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a mongbat"; + Body = 39; + BaseSoundID = 422; + + SetStr( 6, 10 ); + SetDex( 26, 38 ); + SetInt( 6, 14 ); + + SetHits( 4, 6 ); + SetMana( 0 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 25 ); + + SetSkill( SkillName.MagicResist, 15.1, 30.0 ); + SetSkill( SkillName.Tactics, 35.1, 50.0 ); + SetSkill( SkillName.Wrestling, 20.1, 35.0 ); + + Fame = 150; + Karma = -150; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 71.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 6; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public StrongMongbat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Troll.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Troll.cs new file mode 100644 index 0000000..affca72 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Troll.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a troll corpse" )] + public class Troll : BaseCreature + { + [Constructable] + public Troll () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a troll"; + Body = Utility.RandomList( 53, 54 ); + BaseSoundID = 461; + + SetStr( 176, 205 ); + SetDex( 46, 65 ); + SetInt( 46, 70 ); + + SetHits( 106, 123 ); + + SetDamage( 8, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 5, 15 ); + SetResistance( ResistanceType.Energy, 5, 15 ); + + SetSkill( SkillName.MagicResist, 45.1, 60.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 40; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override int Meat{ get{ return 2; } } + + public Troll( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Humanoid/Melee/Zombie.cs b/Scripts/Mobiles/Monsters/Humanoid/Melee/Zombie.cs new file mode 100644 index 0000000..fca12c4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Humanoid/Melee/Zombie.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName("a rotting corpse")] + public class Zombie : BaseCreature + { + [Constructable] + /*** OLD *** + public Zombie() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + *** ADDED ***/ + // Alambik Undead system + public Zombie() + : this(false) + { + } + + public Zombie(bool wasDead) + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + /*** END ***/ + { + Name = "a zombie"; + Body = 3; + BaseSoundID = 471; + + SetStr(46, 70); + SetDex(31, 50); + SetInt(26, 40); + + SetHits(28, 42); + + SetDamage(3, 7); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 15, 20); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 5, 10); + + SetSkill(SkillName.MagicResist, 15.1, 40.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Wrestling, 35.1, 50.0); + + Fame = 600; + Karma = -600; + + VirtualArmor = 18; + + /*** ADDED ***/ + // Alambik Undead system + if (!wasDead) + { + /*** END ***/ + switch (Utility.Random(10)) + { + case 0: PackItem(new LeftArm()); break; + case 1: PackItem(new RightArm()); break; + case 2: PackItem(new Torso()); break; + case 3: PackItem(new Bone()); break; + case 4: PackItem(new RibCage()); break; + case 5: PackItem(new RibCage()); break; + case 6: PackItem(new BonePile()); break; + case 7: PackItem(new BonePile()); break; + case 8: PackItem(new BonePile()); break; + case 9: PackItem(new BonePile()); break; + } + } // ADDED + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Meager); + } + + public override bool BleedImmune { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Regular; } } + + public Zombie(Serial serial) + : base(serial) + { + } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs b/Scripts/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs new file mode 100644 index 0000000..e7e0b24 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Exodus/ExodusMinion.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a minion's corpse" )] + public class ExodusMinion : BaseCreature + { + private bool m_FieldActive; + public bool FieldActive{ get{ return m_FieldActive; } } + public bool CanUseField{ get{ return Hits >= HitsMax * 9 / 10; } } // TODO: an OSI bug prevents to verify this + + public override bool IsScaredOfScaryThings{ get{ return false; } } + public override bool IsScaryToPets{ get{ return true; } } + + [Constructable] + public ExodusMinion() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "exodus minion"; + Body = 0x2F5; + + SetStr( 851, 950 ); + SetDex( 71, 80 ); + SetInt( 61, 90 ); + + SetHits( 511, 570 ); + + SetDamage( 16, 22 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 15, 25); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 18000; + Karma = -18000; + VirtualArmor = 65; + + PackItem( new PowerCrystal() ); + PackItem( new ArcaneGem() ); + PackItem( new ClockworkAssembly() ); + + switch( Utility.Random( 3 ) ) + { + case 0: PackItem( new PowerCrystal() ); break; + case 1: PackItem( new ArcaneGem() ); break; + case 2: PackItem( new ClockworkAssembly() ); break; + } + + m_FieldActive = CanUseField; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Rich ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int GetIdleSound() + { + return 0x218; + } + + public override int GetAngerSound() + { + return 0x26C; + } + + public override int GetDeathSound() + { + return 0x211; + } + + public override int GetAttackSound() + { + return 0x232; + } + + public override int GetHurtSound() + { + return 0x140; + } + + public override void AlterMeleeDamageFrom( Mobile from, ref int damage ) + { + if ( m_FieldActive ) + damage = 0; // no melee damage when the field is up + } + + public override void AlterSpellDamageFrom( Mobile from, ref int damage ) + { + if ( !m_FieldActive ) + damage = 0; // no spell damage when the field is down + } + + public override void OnDamagedBySpell( Mobile from ) + { + if( from != null && from.Alive && 0.4 > Utility.RandomDouble() ) + { + SendEBolt( from ); + } + + if ( !m_FieldActive ) + { + // should there be an effect when spells nullifying is on? + this.FixedParticles( 0, 10, 0, 0x2522, EffectLayer.Waist ); + } + else if ( m_FieldActive && !CanUseField ) + { + m_FieldActive = false; + + // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug + this.FixedParticles( 0x3735, 1, 30, 0x251F, EffectLayer.Waist ); + } + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( m_FieldActive ) + { + this.FixedParticles( 0x376A, 20, 10, 0x2530, EffectLayer.Waist ); + + PlaySound( 0x2F4 ); + + attacker.SendAsciiMessage( "Your weapon cannot penetrate the creature's magical barrier" ); + } + + if( attacker != null && attacker.Alive && attacker.Weapon is BaseRanged && 0.4 > Utility.RandomDouble() ) + { + SendEBolt( attacker ); + } + } + + public override void OnThink() + { + base.OnThink(); + + // TODO: an OSI bug prevents to verify if the field can regenerate or not + if ( !m_FieldActive && !IsHurt() ) + m_FieldActive = true; + } + + public override bool Move( Direction d ) + { + bool move = base.Move( d ); + + if ( move && m_FieldActive && this.Combatant != null ) + this.FixedParticles( 0, 10, 0, 0x2530, EffectLayer.Waist ); + + return move; + } + + public void SendEBolt( Mobile to ) + { + this.MovingParticles( to, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211 ); + to.PlaySound( 0x229 ); + this.DoHarmful( to ); + AOS.Damage( to, this, 50, 0, 0, 0, 0, 100 ); + } + + public ExodusMinion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + m_FieldActive = CanUseField; + + if( this.Name == "Exodus Minion" ) + this.Name = "exodus minion"; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs b/Scripts/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs new file mode 100644 index 0000000..e1bdc54 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Exodus/ExodusOverseer.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "an overseer's corpse" )] + public class ExodusOverseer : BaseCreature + { + private bool m_FieldActive; + public bool FieldActive{ get{ return m_FieldActive; } } + public bool CanUseField{ get{ return Hits >= HitsMax * 9 / 10; } } // TODO: an OSI bug prevents to verify this + + public override bool IsScaredOfScaryThings{ get{ return false; } } + public override bool IsScaryToPets{ get{ return true; } } + + [Constructable] + public ExodusOverseer() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "exodus overseer"; + Body = 0x2F4; + + SetStr( 561, 650 ); + SetDex( 76, 95 ); + SetInt( 61, 90 ); + + SetHits( 331, 390 ); + + SetDamage( 13, 19 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 80.2, 98.0 ); + SetSkill( SkillName.Tactics, 80.2, 98.0 ); + SetSkill( SkillName.Wrestling, 80.2, 98.0 ); + + Fame = 10000; + Karma = -10000; + VirtualArmor = 50; + + if ( Utility.Random( 2 ) == 0 ) + PackItem( new PowerCrystal() ); + else + PackItem( new ArcaneGem() ); + + m_FieldActive = CanUseField; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override int GetIdleSound() + { + return 0xFD; + } + + public override int GetAngerSound() + { + return 0x26C; + } + + public override int GetDeathSound() + { + return 0x211; + } + + public override int GetAttackSound() + { + return 0x23B; + } + + public override int GetHurtSound() + { + return 0x140; + } + + public override void AlterMeleeDamageFrom( Mobile from, ref int damage ) + { + if ( m_FieldActive ) + damage = 0; // no melee damage when the field is up + } + + public override void AlterSpellDamageFrom( Mobile caster, ref int damage ) + { + if ( !m_FieldActive ) + damage = 0; // no spell damage when the field is down + } + + public override void OnDamagedBySpell( Mobile from ) + { + if( from != null && from.Alive && 0.4 > Utility.RandomDouble() ) + { + SendEBolt( from ); + } + + if ( !m_FieldActive ) + { + // should there be an effect when spells nullifying is on? + this.FixedParticles( 0, 10, 0, 0x2522, EffectLayer.Waist ); + } + else if ( m_FieldActive && !CanUseField ) + { + m_FieldActive = false; + + // TODO: message and effect when field turns down; cannot be verified on OSI due to a bug + this.FixedParticles( 0x3735, 1, 30, 0x251F, EffectLayer.Waist ); + } + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( m_FieldActive ) + { + this.FixedParticles( 0x376A, 20, 10, 0x2530, EffectLayer.Waist ); + + PlaySound( 0x2F4 ); + + attacker.SendAsciiMessage( "Your weapon cannot penetrate the creature's magical barrier" ); + } + + if( attacker != null && attacker.Alive && attacker.Weapon is BaseRanged && 0.4 > Utility.RandomDouble() ) + { + SendEBolt( attacker ); + } + } + + public override void OnThink() + { + base.OnThink(); + + // TODO: an OSI bug prevents to verify if the field can regenerate or not + if ( !m_FieldActive && !IsHurt() ) + m_FieldActive = true; + } + + public override bool Move( Direction d ) + { + bool move = base.Move( d ); + + if ( move && m_FieldActive && this.Combatant != null ) + this.FixedParticles( 0, 10, 0, 0x2530, EffectLayer.Waist ); + + return move; + } + + public void SendEBolt( Mobile to ) + { + this.MovingParticles( to, 0x379F, 7, 0, false, true, 0xBE3, 0xFCB, 0x211 ); + to.PlaySound( 0x229 ); + this.DoHarmful( to ); + AOS.Damage( to, this, 50, 0, 0, 0, 0, 100 ); + } + + public ExodusOverseer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + m_FieldActive = CanUseField; + + if( this.Name == "Exodus Overseer" ) + this.Name = "exodus overseer"; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs b/Scripts/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs new file mode 100644 index 0000000..14b5034 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Jukas/ChaosDragoon.cs @@ -0,0 +1,184 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a chaos dragoon corpse" )] + public class ChaosDragoon : BaseCreature + { + [Constructable] + public ChaosDragoon() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.15, 0.4 ) + { + Name = "a chaos dragoon"; + Body = 0x190; + Hue = Utility.RandomSkinHue(); + + SetStr( 176, 225 ); + SetDex( 81, 95 ); + SetInt( 61, 85 ); + + SetHits( 176, 225 ); + + SetDamage( 24, 26 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Cold, 25 ); + SetDamageType( ResistanceType.Energy, 25 ); + + //SetResistance( ResistanceType.Physical, 25, 38 ); + //SetResistance( ResistanceType.Fire, 25, 38 ); + //SetResistance( ResistanceType.Cold, 25, 38 ); + //SetResistance( ResistanceType.Poison, 25, 38 ); + //SetResistance( ResistanceType.Energy, 25, 38 ); + + SetSkill( SkillName.Fencing, 77.6, 92.5 ); + SetSkill( SkillName.Healing, 60.3, 90.0 ); + SetSkill( SkillName.Macing, 77.6, 92.5 ); + SetSkill( SkillName.Anatomy, 77.6, 87.5 ); + SetSkill( SkillName.MagicResist, 77.6, 97.5 ); + SetSkill( SkillName.Swords, 77.6, 92.5 ); + SetSkill( SkillName.Tactics, 77.6, 87.5 ); + + Fame = 5000; + Karma = -5000; + + CraftResource res = CraftResource.None; + + switch (Utility.Random( 6 )) + { + case 0: res = CraftResource.BlackScales; break; + case 1: res = CraftResource.RedScales; break; + case 2: res = CraftResource.BlueScales; break; + case 3: res = CraftResource.YellowScales; break; + case 4: res = CraftResource.GreenScales; break; + case 5: res = CraftResource.WhiteScales; break; + } + + BaseWeapon melee = null; + + switch (Utility.Random( 3 )) + { + case 0: melee = new Kryss(); break; + case 1: melee = new Broadsword(); break; + case 2: melee = new Katana(); break; + } + + melee.Movable = false; + AddItem( melee ); + + DragonHelm helm = new DragonHelm(); + helm.Resource = res; + helm.Movable = false; + AddItem( helm ); + + DragonChest chest = new DragonChest(); + chest.Resource = res; + chest.Movable = false; + AddItem( chest ); + + DragonArms arms = new DragonArms(); + arms.Resource = res; + arms.Movable = false; + AddItem( arms ); + + DragonGloves gloves = new DragonGloves(); + gloves.Resource = res; + gloves.Movable = false; + AddItem( gloves ); + + DragonLegs legs = new DragonLegs(); + legs.Resource = res; + legs.Movable = false; + AddItem( legs ); + + ChaosShield shield = new ChaosShield(); + shield.Movable = false; + AddItem( shield ); + + AddItem( new Shirt() ); + AddItem( new Boots() ); + + int amount = Utility.RandomMinMax( 1, 3 ); + + switch ( res ) + { + case CraftResource.BlackScales: AddItem( new BlackScales( amount ) ); break; + case CraftResource.RedScales: AddItem( new RedScales( amount ) ); break; + case CraftResource.BlueScales: AddItem( new BlueScales( amount ) ); break; + case CraftResource.YellowScales: AddItem( new YellowScales( amount ) ); break; + case CraftResource.GreenScales: AddItem( new GreenScales( amount ) ); break; + case CraftResource.WhiteScales: AddItem( new WhiteScales( amount ) ); break; + } + + new SwampDragon().Rider = this; + } + + public override int GetIdleSound() + { + return 0x2CE; + } + + public override int GetDeathSound() + { + return 0x2CC; + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override int GetAttackSound() + { + return 0x2C8; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + //AddLoot( LootPack.Gems ); + } + + public override bool HasBreath{ get{ return true; } } + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override bool ShowFameTitle{ get{ return false; } } + + public override bool OnBeforeDeath() + { + IMount mount = this.Mount; + + if ( mount != null ) + mount.Rider = null; + + return base.OnBeforeDeath(); + } + + public override void AlterMeleeDamageTo( Mobile to, ref int damage ) + { + if ( to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || to is LesserHiryu || to is Daemon ) + damage *= 3; + } + + public ChaosDragoon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs b/Scripts/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs new file mode 100644 index 0000000..8db5e03 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Jukas/ChaosDragoonElite.cs @@ -0,0 +1,206 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("a chaos dragoon elite corpse")] + public class ChaosDragoonElite : BaseCreature + { + [Constructable] + public ChaosDragoonElite() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.15, 0.4) + { + Name = "a chaos dragoon elite"; + Body = 0x190; + Hue = Utility.RandomSkinHue(); + + SetStr(276, 350); + SetDex(66, 90); + SetInt(126, 150); + + SetHits(276, 350); + + SetDamage(29, 34); + + SetDamageType(ResistanceType.Physical, 100); + + /*SetResistance(ResistanceType.Physical, 45, 55); + SetResistance(ResistanceType.Fire, 15, 25); + SetResistance(ResistanceType.Cold, 50); + SetResistance(ResistanceType.Poison, 25, 35); + SetResistance(ResistanceType.Energy, 25, 35);*/ + + + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.MagicResist, 100.1, 110.0); + SetSkill(SkillName.Anatomy, 80.1, 100.0); + SetSkill(SkillName.Magery, 85.1, 100.0); + SetSkill(SkillName.EvalInt, 85.1, 100.0); + SetSkill(SkillName.Swords, 72.5, 95.0); + SetSkill(SkillName.Fencing, 85.1, 100); + SetSkill(SkillName.Macing, 85.1, 100); + + Fame = 8000; + Karma = -8000; + + CraftResource res = CraftResource.None;; + + switch (Utility.Random(6)) + { + case 0: res = CraftResource.BlackScales; break; + case 1: res = CraftResource.RedScales; break; + case 2: res = CraftResource.BlueScales; break; + case 3: res = CraftResource.YellowScales; break; + case 4: res = CraftResource.GreenScales; break; + case 5: res = CraftResource.WhiteScales; break; + } + + BaseWeapon melee = null; + + switch (Utility.Random(3)) + { + case 0: melee = new Kryss(); break; + case 1: melee = new Broadsword(); break; + case 2: melee = new Katana(); break; + } + + melee.Movable = false; + AddItem(melee); + + DragonChest Tunic = new DragonChest(); + Tunic.Resource = res; + Tunic.Movable = false; + AddItem(Tunic); + + DragonLegs Legs = new DragonLegs(); + Legs.Resource = res; + Legs.Movable = false; + AddItem(Legs); + + DragonArms Arms = new DragonArms(); + Arms.Resource = res; + Arms.Movable = false; + AddItem(Arms); + + DragonGloves Gloves = new DragonGloves(); + Gloves.Resource = res; + Gloves.Movable = false; + AddItem(Gloves); + + DragonHelm Helm = new DragonHelm(); + Helm.Resource = res; + Helm.Movable = false; + AddItem(Helm); + + ChaosShield shield = new ChaosShield(); + shield.Movable = false; + AddItem(shield); + + AddItem(new Boots(0x455)); + AddItem(new Shirt(Utility.RandomMetalHue())); + + int amount = Utility.RandomMinMax(1, 3); + + switch (res) + { + case CraftResource.BlackScales: AddItem(new BlackScales(amount)); break; + case CraftResource.RedScales: AddItem(new RedScales(amount)); break; + case CraftResource.BlueScales: AddItem(new BlueScales(amount)); break; + case CraftResource.YellowScales: AddItem(new YellowScales(amount)); break; + case CraftResource.GreenScales: AddItem(new GreenScales(amount)); break; + case CraftResource.WhiteScales: AddItem(new WhiteScales(amount)); break; + } + switch (Utility.Random(9)) + { + case 0: res = CraftResource.MDullcopper; break; + case 1: res = CraftResource.MShadow; break; + case 2: res = CraftResource.MCopper; break; + case 3: res = CraftResource.MBronze; break; + case 4: res = CraftResource.MGold; break; + case 5: res = CraftResource.MAgapite; break; + case 6: res = CraftResource.MVerite; break; + case 7: res = CraftResource.MValorite; break; + case 8: res = CraftResource.MIron; break; + } + + SwampDragon mt = new SwampDragon(); + mt.HasBarding = true; + mt.BardingResource = res; + mt.BardingHP = mt.BardingMaxHP; + mt.Rider = this; + } + + public override int GetIdleSound() + { + return 0x2CE; + } + + public override int GetDeathSound() + { + return 0x2CC; + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override int GetAttackSound() + { + return 0x2C8; + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.Gems); + } + + public override bool HasBreath { get { return true; } } + public override bool AutoDispel { get { return true; } } + public override bool BardImmune { get { return !Core.AOS; } } + public override bool CanRummageCorpses { get { return true; } } + public override bool AlwaysMurderer { get { return true; } } + public override bool ShowFameTitle { get { return false; } } + + public override bool OnBeforeDeath() + { + IMount mount = this.Mount; + + if ( mount != null ) + { + if ( mount is SwampDragon ) + ((SwampDragon)mount).HasBarding = false; + + mount.Rider = null; + } + + return base.OnBeforeDeath(); + } + + public override void AlterMeleeDamageTo(Mobile to, ref int damage) + { + if ( to is Dragon || to is WhiteWyrm || to is SwampDragon || to is Drake || to is Nightmare || to is Hiryu || to is LesserHiryu || to is Daemon ) + damage *= 3; + } + + public ChaosDragoonElite(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/LBR/Jukas/JukaLord.cs b/Scripts/Mobiles/Monsters/LBR/Jukas/JukaLord.cs new file mode 100644 index 0000000..a18d2a8 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Jukas/JukaLord.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a juka corpse" )] // Why is this 'juka' and warriors 'jukan' ? :-( + public class JukaLord : BaseCreature + { + [Constructable] + public JukaLord() : base( AIType.AI_Archer, FightMode.Closest, 10, 3, 0.2, 0.4 ) + { + Name = "a juka lord"; + Body = 766; + + SetStr( 401, 500 ); + SetDex( 81, 100 ); + SetInt( 151, 200 ); + + SetHits( 241, 300 ); + + SetDamage( 10, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 45, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 25 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 90.1, 100.0 ); + SetSkill( SkillName.Archery, 95.1, 100.0 ); + SetSkill( SkillName.Healing, 80.1, 100.0 ); + SetSkill( SkillName.MagicResist, 120.1, 130.0 ); + SetSkill( SkillName.Swords, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 95.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 28; + + Container pack = new Backpack(); + + pack.DropItem( new Arrow( Utility.RandomMinMax( 25, 35 ) ) ); + pack.DropItem( new Arrow( Utility.RandomMinMax( 25, 35 ) ) ); + pack.DropItem( new Bandage( Utility.RandomMinMax( 5, 15 ) ) ); + pack.DropItem( new Bandage( Utility.RandomMinMax( 5, 15 ) ) ); + pack.DropItem( Loot.RandomGem() ); + pack.DropItem( new ArcaneGem() ); + + PackItem( pack ); + + AddItem( new JukaBow() ); + + // TODO: Bandage self + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if ( from != null && !willKill && amount > 5 && from.Player && 5 > Utility.Random( 100 ) ) + { + string[] toSay = new string[] + { + "{0}!! You will have to do better than that!", + "{0}!! Prepare to meet your doom!", + "{0}!! My armies will crush you!", + "{0}!! You will pay for that!" + }; + + this.Say( true, String.Format( toSay[Utility.Random( toSay.Length )], from.Name ) ); + } + + base.OnDamage( amount, from, willKill ); + } + + public override int GetIdleSound() + { + return 0x262; + } + + public override int GetAngerSound() + { + return 0x263; + } + + public override int GetHurtSound() + { + return 0x1D0; + } + + public override int GetDeathSound() + { + return 0x28D; + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + + public JukaLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/LBR/Jukas/JukaMage.cs b/Scripts/Mobiles/Monsters/LBR/Jukas/JukaMage.cs new file mode 100644 index 0000000..e182fea --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Jukas/JukaMage.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a juka corpse" )] // Why is this 'juka' and warriors 'jukan' ? :-( + public class JukaMage : BaseCreature + { + [Constructable] + public JukaMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a juka mage"; + Body = 765; + + SetStr( 201, 300 ); + SetDex( 71, 90 ); + SetInt( 451, 500 ); + + SetHits( 121, 180 ); + + SetDamage( 4, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 30 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.Anatomy, 80.1, 90.0 ); + SetSkill( SkillName.EvalInt, 80.2, 100.0 ); + SetSkill( SkillName.Magery, 99.1, 100.0 ); + SetSkill( SkillName.Meditation, 80.2, 100.0 ); + SetSkill( SkillName.MagicResist, 140.1, 150.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 16; + + Container bag = new Bag(); + + int count = Utility.RandomMinMax( 10, 20 ); + + for ( int i = 0; i < count; ++i ) + { + Item item = Loot.RandomReagent(); + + if ( item == null ) + continue; + + if ( !bag.TryDropItem( this, item, false ) ) + item.Delete(); + } + + PackItem( bag ); + + PackItem( new ArcaneGem() ); + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(4) ); + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override int GetIdleSound() + { + return 0x1AC; + } + + public override int GetAngerSound() + { + return 0x1CD; + } + + public override int GetHurtSound() + { + return 0x1D0; + } + + public override int GetDeathSound() + { + return 0x28D; + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + + private DateTime m_NextAbilityTime; + + public override void OnThink() + { + if ( DateTime.Now >= m_NextAbilityTime ) + { + JukaLord toBuff = null; + + foreach ( Mobile m in this.GetMobilesInRange( 8 ) ) + { + if ( m is JukaLord && IsFriend( m ) && m.Combatant != null && CanBeBeneficial( m ) && m.CanBeginAction( typeof( JukaMage ) ) && InLOS( m ) ) + { + toBuff = (JukaLord)m; + break; + } + } + + if ( toBuff != null ) + { + if ( CanBeBeneficial( toBuff ) && toBuff.BeginAction( typeof( JukaMage ) ) ) + { + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 30, 60 ) ); + + toBuff.Say( true, "Give me the power to destroy my enemies!" ); + this.Say( true, "Fight well my lord!" ); + + DoBeneficial( toBuff ); + + object[] state = new object[]{ toBuff, toBuff.HitsMaxSeed, toBuff.RawStr, toBuff.RawDex }; + + SpellHelper.Turn( this, toBuff ); + + int toScale = toBuff.HitsMaxSeed; + + if ( toScale > 0 ) + { + toBuff.HitsMaxSeed += AOS.Scale( toScale, 75 ); + toBuff.Hits += AOS.Scale( toScale, 75 ); + } + + toScale = toBuff.RawStr; + + if ( toScale > 0 ) + toBuff.RawStr += AOS.Scale( toScale, 50 ); + + toScale = toBuff.RawDex; + + if ( toScale > 0 ) + { + toBuff.RawDex += AOS.Scale( toScale, 50 ); + toBuff.Stam += AOS.Scale( toScale, 50 ); + } + + toBuff.Hits = toBuff.Hits; + toBuff.Stam = toBuff.Stam; + + toBuff.FixedParticles( 0x375A, 10, 15, 5017, EffectLayer.Waist ); + toBuff.PlaySound( 0x1EE ); + + Timer.DelayCall( TimeSpan.FromSeconds( 20.0 ), new TimerStateCallback( Unbuff ), state ); + } + } + else + { + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 5 ) ); + } + } + + base.OnThink(); + } + + private void Unbuff( object state ) + { + object[] states = (object[])state; + + JukaLord toDebuff = (JukaLord)states[0]; + + toDebuff.EndAction( typeof( JukaMage ) ); + + if ( toDebuff.Deleted ) + return; + + toDebuff.HitsMaxSeed = (int)states[1]; + toDebuff.RawStr = (int)states[2]; + toDebuff.RawDex = (int)states[3]; + + toDebuff.Hits = toDebuff.Hits; + toDebuff.Stam = toDebuff.Stam; + } + + public JukaMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs b/Scripts/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs new file mode 100644 index 0000000..47e8742 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Jukas/JukaWarrior.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a jukan corpse" )] + public class JukaWarrior : BaseCreature + { + [Constructable] + public JukaWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a juka warrior"; + Body = 764; + + SetStr( 251, 350 ); + SetDex( 61, 80 ); + SetInt( 101, 150 ); + + SetHits( 151, 210 ); + + SetDamage( 7, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.Anatomy, 80.1, 90.0 ); + SetSkill( SkillName.Fencing, 80.1, 90.0 ); + SetSkill( SkillName.Macing, 80.1, 90.0 ); + SetSkill( SkillName.MagicResist, 120.1, 130.0 ); + SetSkill( SkillName.Swords, 80.1, 90.0 ); + SetSkill( SkillName.Tactics, 80.1, 90.0 ); + SetSkill( SkillName.Wrestling, 80.1, 90.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 22; + + if ( Utility.RandomDouble() < 0.1 ) + PackItem( new ArcaneGem() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Gems, 1 ); + } + + public override int GetIdleSound() + { + return 0x1AC; + } + + public override int GetAngerSound() + { + return 0x1CD; + } + + public override int GetHurtSound() + { + return 0x1D0; + } + + public override int GetDeathSound() + { + return 0x28D; + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.2 < Utility.RandomDouble() ) + return; + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + defender.SendLocalizedMessage( 1004014 ); // You have been stunned! + defender.Freeze( TimeSpan.FromSeconds( 4.0 ) ); + break; + } + case 1: + { + defender.SendAsciiMessage( "You have been hit by a paralyzing blow!" ); + defender.Freeze( TimeSpan.FromSeconds( 3.0 ) ); + break; + } + case 2: + { + AOS.Damage( defender, this, Utility.Random( 10, 5 ), 100, 0, 0, 0, 0 ); + defender.SendAsciiMessage( "You have been hit by a critical strike!" ); + break; + } + } + } + + public JukaWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs b/Scripts/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs new file mode 100644 index 0000000..8648bf0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Meers/EnragedCreatures.cs @@ -0,0 +1,296 @@ +using System; +using Server; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a hare corpse" )] + public class EnragedRabbit : BaseEnraged + { + public EnragedRabbit( Mobile summoner ) : base( summoner ) + { + Name = "a rabbit"; + Body = 0xcd; + } + + public override int GetAttackSound() + { + return 0xC9; + } + + public override int GetHurtSound() + { + return 0xCA; + } + + public override int GetDeathSound() + { + return 0xCB; + } + + public EnragedRabbit( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [CorpseName( "a deer corpse" )] + public class EnragedHart : BaseEnraged + { + public EnragedHart( Mobile summoner ) : base( summoner ) + { + Name = "a great hart"; + Body = 0xea; + } + + public override int GetAttackSound() + { + return 0x82; + } + + public override int GetHurtSound() + { + return 0x83; + } + + public override int GetDeathSound() + { + return 0x84; + } + + public EnragedHart( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [CorpseName( "a deer corpse" )] + public class EnragedHind : BaseEnraged + { + public EnragedHind( Mobile summoner ) : base( summoner ) + { + Name = "a hind"; + Body = 0xed; + } + public override int GetAttackSound() + { + return 0x82; + } + + public override int GetHurtSound() + { + return 0x83; + } + + public override int GetDeathSound() + { + return 0x84; + } + + public EnragedHind( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [CorpseName( "a bear corpse" )] + public class EnragedBlackBear : BaseEnraged + { + public EnragedBlackBear( Mobile summoner ) : base( summoner ) + { + Name = "a black bear"; + Body = 0xd3; + BaseSoundID = 0xa3; + } + public EnragedBlackBear( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [CorpseName( "an eagle corpse" )] + public class EnragedEagle : BaseEnraged + { + public EnragedEagle( Mobile summoner ) : base( summoner ) + { + Name = "an eagle"; + Body = 0x5; + BaseSoundID = 0x2ee; + } + public EnragedEagle( Serial serial ) : base( serial ) + { + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class BaseEnraged : BaseCreature + { + public BaseEnraged( Mobile summoner ) + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SetStr( 50, 200 ); + SetDex( 50, 200 ); + SetHits( 50, 200 ); + SetStam( 50, 200 ); + + /* + On OSI, all stats are random 50-200, but + str is never less than hits, and dex is never + less than stam. + */ + + if( Str < Hits ) + Str = Hits; + if( Dex < Stam ) + Dex = Stam; + + Karma = -1000; + Tamable = false; + + SummonMaster = summoner; + } + + public override void OnThink() + { + + if( SummonMaster == null || SummonMaster.Deleted ) + { + Delete(); + } + + /* + On OSI, without combatant, they behave as if they have been + given "come" command, ie they wander towards their summoner, + but never actually "follow". + */ + + else if( !Combat( this )) + { + if( AIObject != null ) + { + AIObject.MoveTo( SummonMaster, false , 5 ); + } + } + + /* + On OSI, if the summon attacks a mobile, the summoner meer also + attacks them, regardless of karma, etc. as long as the combatant + is a player or controlled/summoned, and the summoner is not already + engaged in combat. + */ + + else if( !Combat( SummonMaster )) + { + BaseCreature bc = null; + if( Combatant is BaseCreature ) + { + bc = (BaseCreature)Combatant; + } + if( Combatant.Player || ( bc != null && ( bc.Controlled || bc.SummonMaster != null ))) + { + SummonMaster.Combatant = Combatant; + } + } + else + { + base.OnThink(); + } + } + + private bool Combat( Mobile mobile ) + { + Mobile combatant = mobile.Combatant; + if( combatant == null || combatant.Deleted ) + { + return false; + } + else if ( combatant.IsDeadBondedPet || !combatant.Alive ) + { + return false; + } + return true; + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1060768, from.NetState ); // enraged + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + list.Add( 1060768 ); // enraged + } + + public BaseEnraged( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs b/Scripts/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs new file mode 100644 index 0000000..878e6c1 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Meers/MeerCaptain.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections; +using Server; +using Server.Misc; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a meer corpse" )] + public class MeerCaptain : BaseCreature + { + [Constructable] + public MeerCaptain() : base( AIType.AI_Archer, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a meer captain"; + Body = 773; + + SetStr( 96, 110 ); + SetDex( 186, 200 ); + SetInt( 96, 110 ); + + SetHits( 58, 66 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 35, 45 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.Archery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 91.0, 100.0 ); + SetSkill( SkillName.Swords, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 91.0, 100.0 ); + SetSkill( SkillName.Wrestling, 80.9, 89.9 ); + + Fame = 2000; + Karma = 5000; + + VirtualArmor = 28; + + Container pack = new Backpack(); + + pack.DropItem( new Bolt( Utility.RandomMinMax( 10, 20 ) ) ); + pack.DropItem( new Bolt( Utility.RandomMinMax( 10, 20 ) ) ); + + switch ( Utility.Random( 6 ) ) + { + case 0: pack.DropItem( new Broadsword() ); break; + case 1: pack.DropItem( new Cutlass() ); break; + case 2: pack.DropItem( new Katana() ); break; + case 3: pack.DropItem( new Longsword() ); break; + case 4: pack.DropItem( new Scimitar() ); break; + case 5: pack.DropItem( new VikingSword() ); break; + } + + Container bag = new Bag(); + + int count = Utility.RandomMinMax( 10, 20 ); + + for ( int i = 0; i < count; ++i ) + { + Item item = Loot.RandomReagent(); + + if ( item == null ) + continue; + + if ( !bag.TryDropItem( this, item, false ) ) + item.Delete(); + } + + pack.DropItem( bag ); + + AddItem( new Crossbow() ); + PackItem( pack ); + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override bool CanRummageCorpses{ get{ return true; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override int GetHurtSound() + { + return 0x14D; + } + + public override int GetDeathSound() + { + return 0x314; + } + + public override int GetAttackSound() + { + return 0x75; + } + + private DateTime m_NextAbilityTime; + + public override void OnThink() + { + if ( Combatant != null && this.MagicDamageAbsorb < 1 ) + { + this.MagicDamageAbsorb = Utility.RandomMinMax( 5, 7 ); + this.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist ); + this.PlaySound( 0x1E9 ); + } + + if ( DateTime.Now >= m_NextAbilityTime ) + { + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 10, 15 ) ); + + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 8 ) ) + { + if ( m is MeerWarrior && IsFriend( m ) && CanBeBeneficial( m ) && m.Hits < m.HitsMax && !m.Poisoned && !MortalStrike.IsWounded( m ) ) + list.Add( m ); + } + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + DoBeneficial( m ); + + int toHeal = Utility.RandomMinMax( 20, 30 ); + + SpellHelper.Turn( this, m ); + + m.Heal( toHeal, this ); + + m.FixedParticles( 0x376A, 9, 32, 5030, EffectLayer.Waist ); + m.PlaySound( 0x202 ); + } + } + + base.OnThink(); + } + + public MeerCaptain( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/LBR/Meers/MeerEternal.cs b/Scripts/Mobiles/Monsters/LBR/Meers/MeerEternal.cs new file mode 100644 index 0000000..9065908 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Meers/MeerEternal.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections; +using Server; +using Server.Misc; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a meer's corpse" )] + public class MeerEternal : BaseCreature + { + [Constructable] + public MeerEternal() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a meer eternal"; + Body = 772; + + SetStr( 416, 505 ); + SetDex( 146, 165 ); + SetInt( 566, 655 ); + + SetHits( 250, 303 ); + + SetDamage( 11, 13 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 45, 55 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 150.5, 200.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 18000; + Karma = 18000; + + VirtualArmor = 34; + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + AddLoot( LootPack.HighScrolls, 2 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return Core.AOS ? 5 : 4; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override int GetHurtSound() + { + return 0x167; + } + + public override int GetDeathSound() + { + return 0xBC; + } + + public override int GetAttackSound() + { + return 0x28B; + } + + private DateTime m_NextAbilityTime; + + private void DoAreaLeech() + { + m_NextAbilityTime += TimeSpan.FromSeconds( 2.5 ); + + this.Say( true, "Beware, mortals! You have provoked my wrath!" ); + this.FixedParticles( 0x376A, 10, 10, 9537, 33, 0, EffectLayer.Waist ); + + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( DoAreaLeech_Finish ) ); + } + + private void DoAreaLeech_Finish() + { + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 6 ) ) + { + if ( this.CanBeHarmful( m ) && this.IsEnemy( m ) ) + list.Add( m ); + } + + if ( list.Count == 0 ) + { + this.Say( true, "Bah! You have escaped my grasp this time, mortal!" ); + } + else + { + double scalar; + + if ( list.Count == 1 ) + scalar = 0.75; + else if ( list.Count == 2 ) + scalar = 0.50; + else + scalar = 0.25; + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + + int damage = (int)(m.Hits * scalar); + + damage += Utility.RandomMinMax( -5, 5 ); + + if ( damage < 1 ) + damage = 1; + + m.MovingParticles( this, 0x36F4, 1, 0, false, false, 32, 0, 9535, 1, 0, (EffectLayer)255, 0x100 ); + m.MovingParticles( this, 0x0001, 1, 0, false, true, 32, 0, 9535, 9536, 0, (EffectLayer)255, 0 ); + + this.DoHarmful( m ); + this.Hits += AOS.Damage( m, this, damage, 100, 0, 0, 0, 0 ); + } + + this.Say( true, "If I cannot cleanse thy soul, I will destroy it!" ); + } + } + + private void DoFocusedLeech( Mobile combatant, string message ) + { + this.Say( true, message ); + + Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), new TimerStateCallback( DoFocusedLeech_Stage1 ), combatant ); + } + + private void DoFocusedLeech_Stage1( object state ) + { + Mobile combatant = (Mobile)state; + + if ( this.CanBeHarmful( combatant ) ) + { + this.MovingParticles( combatant, 0x36FA, 1, 0, false, false, 1108, 0, 9533, 1, 0, (EffectLayer)255, 0x100 ); + this.MovingParticles( combatant, 0x0001, 1, 0, false, true, 1108, 0, 9533, 9534, 0, (EffectLayer)255, 0 ); + this.PlaySound( 0x1FB ); + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( DoFocusedLeech_Stage2 ), combatant ); + } + } + + private void DoFocusedLeech_Stage2( object state ) + { + Mobile combatant = (Mobile)state; + + if ( this.CanBeHarmful( combatant ) ) + { + combatant.MovingParticles( this, 0x36F4, 1, 0, false, false, 32, 0, 9535, 1, 0, (EffectLayer)255, 0x100 ); + combatant.MovingParticles( this, 0x0001, 1, 0, false, true, 32, 0, 9535, 9536, 0, (EffectLayer)255, 0 ); + + this.PlaySound( 0x209 ); + this.DoHarmful( combatant ); + this.Hits += AOS.Damage( combatant, this, Utility.RandomMinMax( 30, 40 ) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0 ); + } + } + + public override void OnThink() + { + if ( DateTime.Now >= m_NextAbilityTime ) + { + Mobile combatant = this.Combatant; + + if ( combatant != null && combatant.Map == this.Map && combatant.InRange( this, 12 ) ) + { + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 10, 15 ) ); + + int ability = Utility.Random( 4 ); + + switch ( ability ) + { + case 0: DoFocusedLeech( combatant, "Thine essence will fill my withering body with strength!" ); break; + case 1: DoFocusedLeech( combatant, "I rebuke thee, worm, and cleanse thy vile spirit of its tainted blood!" ); break; + case 2: DoFocusedLeech( combatant, "I devour your life's essence to strengthen my resolve!" ); break; + case 3: DoAreaLeech(); break; + // TODO: Resurrect ability + } + } + } + + base.OnThink(); + } + + public MeerEternal( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/LBR/Meers/MeerMage.cs b/Scripts/Mobiles/Monsters/LBR/Meers/MeerMage.cs new file mode 100644 index 0000000..9869e8d --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Meers/MeerMage.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections; +using Server; +using Server.Misc; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a meer's corpse" )] + public class MeerMage : BaseCreature + { + [Constructable] + public MeerMage() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a meer mage"; + Body = 770; + + SetStr( 171, 200 ); + SetDex( 126, 145 ); + SetInt( 276, 305 ); + + SetHits( 103, 120 ); + + SetDamage( 24, 26 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 50 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Magery, 70.1, 80.0 ); + SetSkill( SkillName.Meditation, 85.1, 95.0 ); + SetSkill( SkillName.MagicResist, 80.1, 100.0 ); + SetSkill( SkillName.Tactics, 70.1, 90.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 8000; + Karma = 8000; + + VirtualArmor = 16; + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.MedScrolls, 2 ); + // TODO: Daemon bone ... + } + + public override bool AutoDispel{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override int GetHurtSound() + { + return 0x14D; + } + + public override int GetDeathSound() + { + return 0x314; + } + + public override int GetAttackSound() + { + return 0x75; + } + + private DateTime m_NextAbilityTime; + + public override void OnThink() + { + if (DateTime.Now >= m_NextAbilityTime) + { + Mobile combatant = this.Combatant; + + if (combatant != null && combatant.Map == this.Map && combatant.InRange(this, 12) && IsEnemy(combatant) && !UnderEffect(combatant)) + { + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds(Utility.RandomMinMax(20, 30)); + + if (combatant is BaseCreature) + { + BaseCreature bc = (BaseCreature)combatant; + + if (bc.Controlled && bc.ControlMaster != null && !bc.ControlMaster.Deleted && bc.ControlMaster.Alive) + { + if (bc.ControlMaster.Map == this.Map && bc.ControlMaster.InRange(this, 12) && !UnderEffect(bc.ControlMaster)) + { + Combatant = combatant = bc.ControlMaster; + } + } + } + + if (Utility.RandomDouble() < .1) + { + int[][] coord = + { + new int[]{-4,-6}, new int[]{4,-6}, new int[]{0,-8}, new int[]{-5,5}, new int[]{5,5} + }; + + BaseCreature rabid; + + for (int i = 0; i < 5; i++) + { + int x = combatant.X + coord[i][0]; + int y = combatant.Y + coord[i][1]; + + Point3D loc = new Point3D(x, y, combatant.Map.GetAverageZ(x, y)); + + if (!combatant.Map.CanSpawnMobile(loc)) + continue; + + switch (i) + { + case 0: rabid = new EnragedRabbit(this); break; + case 1: rabid = new EnragedHind(this); break; + case 2: rabid = new EnragedHart(this); break; + case 3: rabid = new EnragedBlackBear(this); break; + default: rabid = new EnragedEagle(this); break; + } + + rabid.FocusMob = combatant; + rabid.MoveToWorld(loc, combatant.Map); + } + this.Say(1071932); //Creatures of the forest, I call to thee! Aid me in the fight against all that is evil! + } + else if (combatant.Player) + { + this.Say(true, "I call a plague of insects to sting your flesh!"); + m_Table[combatant] = Timer.DelayCall(TimeSpan.FromSeconds(0.5), TimeSpan.FromSeconds(7.0), new TimerStateCallback(DoEffect), new object[] { combatant, 0 }); + } + } + } + + base.OnThink(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool UnderEffect(Mobile m) + { + return m_Table.Contains(m); + } + + public static void StopEffect(Mobile m, bool message) + { + Timer t = (Timer)m_Table[m]; + + if (t != null) + { + if (message) + m.PublicOverheadMessage(Network.MessageType.Emote, m.SpeechHue, true, "* The open flame begins to scatter the swarm of insects *"); + + t.Stop(); + m_Table.Remove(m); + } + } + + public void DoEffect(object state) + { + object[] states = (object[])state; + + Mobile m = (Mobile)states[0]; + int count = (int)states[1]; + + if (!m.Alive) + { + StopEffect(m, false); + } + else + { + Torch torch = m.FindItemOnLayer(Layer.TwoHanded) as Torch; + + if (torch != null && torch.Burning) + { + StopEffect(m, true); + } + else + { + if ((count % 4) == 0) + { + m.LocalOverheadMessage(Network.MessageType.Emote, m.SpeechHue, true, "* The swarm of insects bites and stings your flesh! *"); + m.NonlocalOverheadMessage(Network.MessageType.Emote, m.SpeechHue, true, String.Format("* {0} is stung by a swarm of insects *", m.Name)); + } + + m.FixedParticles(0x91C, 10, 180, 9539, EffectLayer.Waist); + m.PlaySound(0x00E); + m.PlaySound(0x1BC); + + AOS.Damage(m, this, Utility.RandomMinMax(30, 40) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0); + + states[1] = count + 1; + + if (!m.Alive) + StopEffect(m, false); + } + } + } + + public MeerMage(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs b/Scripts/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs new file mode 100644 index 0000000..b60b547 --- /dev/null +++ b/Scripts/Mobiles/Monsters/LBR/Meers/MeerWarrior.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections; +using Server; +using Server.Misc; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a meer corpse" )] + public class MeerWarrior : BaseCreature + { + [Constructable] + public MeerWarrior() : base( AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a meer warrior"; + Body = 771; + + SetStr( 86, 100 ); + SetDex( 186, 200 ); + SetInt( 86, 100 ); + + SetHits( 52, 60 ); + + SetDamage( 12, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 5, 15 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 91.0, 100.0 ); + SetSkill( SkillName.Tactics, 91.0, 100.0 ); + SetSkill( SkillName.Wrestling, 91.0, 100.0 ); + + VirtualArmor = 22; + + Fame = 2000; + Karma = 5000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override bool CanRummageCorpses{ get{ return true; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if ( from != null && !willKill && amount > 3 && from != null && !InRange( from, 7 ) ) + { + this.MovingEffect( from, 0xF51, 10, 0, false, false ); + SpellHelper.Damage( TimeSpan.FromSeconds( 1.0 ), from, this, Utility.RandomMinMax( 30, 40 ) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0 ); + } + + base.OnDamage( amount, from, willKill ); + } + + public override int GetHurtSound() + { + return 0x156; + } + + public override int GetDeathSound() + { + return 0x15C; + } + + public MeerWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Animal/CuSidhe.cs b/Scripts/Mobiles/Monsters/ML/Animal/CuSidhe.cs new file mode 100644 index 0000000..25dfc8e --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Animal/CuSidhe.cs @@ -0,0 +1,136 @@ +using Server; +using System; +using Server.Items; +using Server.Gumps; + +namespace Server.Mobiles +{ + [CorpseName("a cu sidhe corpse")] + public class CuSidhe : BaseMount + { + [Constructable] + public CuSidhe() + : this("a cu sidhe") + { + } + + [Constructable] + public CuSidhe(string name) + : base(name, 277, 0x3E91, AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4) + { + double chance = Utility.RandomDouble() * 23301; + + if (chance <= 1) + Hue = 0x489; + else if (chance < 50) + Hue = Utility.RandomList(0x657, 0x515, 0x4B1, 0x481, 0x482, 0x455); + else if (chance < 500) + Hue = Utility.RandomList(0x97A, 0x978, 0x901, 0x8AC, 0x5A7, 0x527); + + SetStr(1200, 1225); + SetDex(150, 170); + SetInt(250, 285); + + SetHits(1010, 1275); + + SetDamage(21, 28); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 50); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 50, 65); + SetResistance(ResistanceType.Fire, 25, 45); + SetResistance(ResistanceType.Cold, 70, 85); + SetResistance(ResistanceType.Poison, 30, 50); + SetResistance(ResistanceType.Energy, 70, 85); + + SetSkill(SkillName.Wrestling, 90.1, 96.8); + SetSkill(SkillName.Tactics, 90.3, 99.3); + SetSkill(SkillName.MagicResist, 75.3, 90.0); + SetSkill(SkillName.Anatomy, 65.5, 69.4); + SetSkill(SkillName.Healing, 72.2, 98.9); + + Fame = 5000; //Guessing here + Karma = 5000; //Guessing here + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 101.1; + + if (Utility.RandomDouble() < 0.2) + PackItem(new TreasureMap(5, Map.Trammel)); + + //if ( Utility.RandomDouble() < 0.1 ) + //PackItem( new ParrotItem() ); + + PackGold(500, 800); + + // TODO 0-2 spellweaving scroll + } + + public override void GenerateLoot() + { + AddLoot(LootPack.AosFilthyRich, 5); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Race != Race.Elf && from == ControlMaster && from.AccessLevel == AccessLevel.Player) + { + Item pads = from.FindItemOnLayer(Layer.Shoes); + + if (pads is PadsOfTheCuSidhe) + from.SendLocalizedMessage(1071981); // Your boots allow you to mount the Cu Sidhe. + else + { + from.SendLocalizedMessage(1072203); // Only Elves may use this. + return; + } + } + + base.OnDoubleClick(from); + } + + public override bool CanHeal { get { return true; } } + public override bool CanHealOwner { get { return true; } } + public override FoodType FavoriteFood { get { return FoodType.FruitsAndVegies; } } + public override bool CanAngerOnTame { get { return true; } } + public override bool StatLossAfterTame { get { return true; } } + public override int Hides { get { return 10; } } + public override int Meat { get { return 3; } } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + public CuSidhe(Serial serial) + : base(serial) + { + } + + public override int GetIdleSound() { return 0x577; } + public override int GetAttackSound() { return 0x576; } + public override int GetAngerSound() { return 0x578; } + public override int GetHurtSound() { return 0x576; } + public override int GetDeathSound() { return 0x579; } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version < 1 && Name == "a Cu Sidhe") + Name = "a cu sidhe"; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Animal/Ferret.cs b/Scripts/Mobiles/Monsters/ML/Animal/Ferret.cs new file mode 100644 index 0000000..0837f85 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Animal/Ferret.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Engines.Quests; + +namespace Server.Mobiles +{ + [CorpseName( "a ferret corpse" )] + public class Ferret : BaseCreature + { + [Constructable] + public Ferret() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a ferret"; + Body = 0x117; + + SetStr( 41, 48 ); + SetDex( 55 ); + SetInt( 75 ); + + SetHits( 45, 50 ); + + SetDamage( 7, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 50 ); + SetResistance( ResistanceType.Fire, 10, 14 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 21, 25 ); + SetResistance( ResistanceType.Energy, 20, 25 ); + + SetSkill( SkillName.MagicResist, 4.0 ); + SetSkill( SkillName.Tactics, 4.0 ); + SetSkill( SkillName.Wrestling, 4.0 ); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -21.3; + + m_CanTalk = true; + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + public Ferret( Serial serial ) : base( serial ) + { + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( m is Ferret && m.InRange( this, 3 ) && m.Alive ) + Talk( (Ferret) m ); + } + + private static string[] m_Vocabulary = new string[] + { + "dook", + "dook dook", + "dook dook dook!" + }; + + private bool m_CanTalk; + + public void Talk() + { + Talk( null ); + } + + public void Talk( Ferret to ) + { + if ( m_CanTalk ) + { + if ( to != null ) + QuestSystem.FocusTo( this, to ); + + Say( m_Vocabulary[ Utility.Random( m_Vocabulary.Length ) ] ); + + if ( to != null && Utility.RandomBool() ) + Timer.DelayCall( TimeSpan.FromSeconds( Utility.RandomMinMax( 5, 8 ) ), new TimerCallback( delegate() { to.Talk(); } ) ); + + m_CanTalk = false; + + Timer.DelayCall( TimeSpan.FromSeconds( Utility.RandomMinMax( 20, 30 ) ), new TimerCallback( delegate() { m_CanTalk = true; } ) ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_CanTalk = true; + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs b/Scripts/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs new file mode 100644 index 0000000..8e53ca4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Animal/RagingGrizzlyBear.cs @@ -0,0 +1,69 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a grizzly bear corpse" )] + [TypeAlias( "Server.Mobiles.Grizzlybear" )] + public class RagingGrizzlyBear : BaseCreature + { + [Constructable] + public RagingGrizzlyBear() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a raging grizzly bear"; + Body = 212; + BaseSoundID = 0xA3; + + SetStr( 1251, 1550 ); + SetDex( 801, 1050 ); + SetInt( 151, 400 ); + + SetHits( 751, 930 ); + SetMana( 0 ); + + SetDamage( 18, 23 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 70 ); + SetResistance( ResistanceType.Cold, 30, 50 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill(SkillName.Wrestling, 73.4, 88.1); + SetSkill(SkillName.Tactics, 73.6, 110.5); + SetSkill(SkillName.MagicResist, 32.8, 54.6); + SetSkill(SkillName.Anatomy, 0, 0); + + Fame = 10000; //Guessing here + Karma = 10000; //Guessing here + + VirtualArmor = 24; + + Tamable = false; + + } + + public override int Meat { get { return 4; } } + public override int Hides { get { return 32; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Bear; } } + + public RagingGrizzlyBear( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Animal/Squirrel.cs b/Scripts/Mobiles/Monsters/ML/Animal/Squirrel.cs new file mode 100644 index 0000000..50c66eb --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Animal/Squirrel.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a squirrel corpse" )] + public class Squirrel : BaseCreature + { + [Constructable] + public Squirrel() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a squirrel"; + Body = 0x116; + + SetStr( 44, 50 ); + SetDex( 35 ); + SetInt( 5 ); + + SetHits( 42, 50 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 34 ); + SetResistance( ResistanceType.Fire, 10, 14 ); + SetResistance( ResistanceType.Cold, 30, 35 ); + SetResistance( ResistanceType.Poison, 20, 25 ); + SetResistance( ResistanceType.Energy, 20, 25 ); + + SetSkill( SkillName.MagicResist, 4.0 ); + SetSkill( SkillName.Tactics, 4.0 ); + SetSkill( SkillName.Wrestling, 4.0 ); + + Tamable = true; + ControlSlots = 1; + MinTameSkill = -21.3; + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies; } } + + public Squirrel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs new file mode 100644 index 0000000..3f7c7aa --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyJennifyr.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Lady Jennifyr corpse" )] + public class LadyJennifyr : SkeletalKnight + { + [Constructable] + public LadyJennifyr() + { + IsParagon = true; + + Name = "Lady Jennifyr"; + Hue = 0x76D; + + SetStr( 208, 309 ); + SetDex( 91, 118 ); + SetInt( 44, 101 ); + + SetHits( 1113, 1285 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 56, 65 ); + SetResistance( ResistanceType.Fire, 41, 49 ); + SetResistance( ResistanceType.Cold, 71, 80 ); + SetResistance( ResistanceType.Poison, 41, 50 ); + SetResistance( ResistanceType.Energy, 50, 58 ); + + SetSkill( SkillName.Wrestling, 127.9, 137.1 ); + SetSkill( SkillName.Tactics, 128.4, 141.9 ); + SetSkill( SkillName.MagicResist, 102.1, 119.5 ); + SetSkill( SkillName.Anatomy, 129.0, 137.5 ); + + Fame = 18000; + Karma = -18000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( Utility.RandomDouble() < 0.1 ) + { + ExpireTimer timer; + + if ( m_Table.TryGetValue( defender, out timer ) ) + timer.DoExpire(); + + defender.FixedParticles( 0x3709, 10, 30, 5052, EffectLayer.LeftFoot ); + defender.PlaySound( 0x208 ); + defender.SendLocalizedMessage( 1070833 ); // The creature fans you with fire, reducing your resistance to fire attacks. + + ResistanceMod mod = new ResistanceMod( ResistanceType.Fire, -10 ); + defender.AddResistanceMod( mod ); + + m_Table[defender] = timer = new ExpireTimer( defender, mod ); + timer.Start(); + } + } + + private static Dictionary m_Table = new Dictionary(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + + public ExpireTimer( Mobile m, ResistanceMod mod ) + : base( TimeSpan.FromSeconds( 10 ) ) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod( m_Mod ); + + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1070834 ); // Your resistance to fire attacks has returned. + DoExpire(); + } + } + + /* + // TODO: Uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public LadyJennifyr( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs new file mode 100644 index 0000000..cd37a88 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/LadyMarai.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Lady Marai corpse" )] + public class LadyMarai : SkeletalKnight + { + [Constructable] + public LadyMarai() + { + IsParagon = true; + + Name = "Lady Marai"; + Hue = 0x21; + + SetStr( 221, 304 ); + SetDex( 98, 138 ); + SetInt( 54, 99 ); + + SetHits( 694, 846 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 126.6, 137.2 ); + SetSkill( SkillName.Tactics, 128.7, 134.5 ); + SetSkill( SkillName.MagicResist, 102.1, 119.1 ); + SetSkill( SkillName.Anatomy, 126.2, 136.5 ); + + Fame = 18000; + Karma = -18000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.CrushingBlow; + } + + /* + // TODO: Uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public LadyMarai( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs new file mode 100644 index 0000000..001110a --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterJonath.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Master Jonath corpse" )] + public class MasterJonath : BoneMagi + { + [Constructable] + public MasterJonath() + { + IsParagon = true; + + Name = "Master Jonath"; + Hue = 0x455; + + SetStr( 109, 131 ); + SetDex( 98, 110 ); + SetInt( 232, 259 ); + + SetHits( 766, 920 ); + + SetDamage( 10, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 60 ); + SetResistance( ResistanceType.Fire, 43, 49 ); + SetResistance( ResistanceType.Cold, 45, 80 ); + SetResistance( ResistanceType.Poison, 41, 45 ); + SetResistance( ResistanceType.Energy, 54, 55 ); + + SetSkill( SkillName.Wrestling, 80.5, 88.6 ); + SetSkill( SkillName.Tactics, 88.5, 95.1 ); + SetSkill( SkillName.MagicResist, 102.7, 102.9 ); + SetSkill( SkillName.Magery, 100.0, 106.6 ); + SetSkill( SkillName.EvalInt, 99.6, 106.9 ); + SetSkill( SkillName.Necromancy, 100.0, 106.6 ); + SetSkill( SkillName.SpiritSpeak, 99.6, 106.9 ); + + Fame = 18000; + Karma = -18000; + + /*if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else*/ + PackScroll( 4, 7 ); + + PackReg( 7 ); + PackReg( 7 ); + PackReg( 8 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + // TODO: Special move? + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new ParrotItem() ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public MasterJonath( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs new file mode 100644 index 0000000..279da5d --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterMikael.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Master Mikael corpse" )] + public class MasterMikael : BoneMagi + { + [Constructable] + public MasterMikael() + { + IsParagon = true; + + Name = "Master Mikael"; + Hue = 0x8FD; + + SetStr( 93, 122 ); + SetDex( 91, 100 ); + SetInt( 252, 271 ); + + SetHits( 789, 1014 ); + + SetDamage( 11, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 59 ); + SetResistance( ResistanceType.Fire, 40, 46 ); + SetResistance( ResistanceType.Cold, 72, 80 ); + SetResistance( ResistanceType.Poison, 44, 49 ); + SetResistance( ResistanceType.Energy, 50, 57 ); + + SetSkill( SkillName.Wrestling, 80.1, 87.2 ); + SetSkill( SkillName.Tactics, 79.0, 90.9 ); + SetSkill( SkillName.MagicResist, 90.3, 106.9 ); + SetSkill( SkillName.Magery, 103.8, 108.0 ); + SetSkill( SkillName.EvalInt, 96.1, 105.3 ); + SetSkill( SkillName.Necromancy, 103.8, 108.0 ); + SetSkill( SkillName.SpiritSpeak, 96.1, 105.3 ); + + Fame = 18000; + Karma = -18000; + + /*if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else*/ + PackScroll( 4, 7 ); + + PackReg( 3 ); + PackNecroReg( 1, 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + // TODO: Special move? + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public MasterMikael( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs new file mode 100644 index 0000000..0430cb8 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/MasterTheophilus.cs @@ -0,0 +1,95 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Master Theophilus corpse" )] + public class MasterTheophilus : EvilMageLord + { + [Constructable] + public MasterTheophilus() + { + IsParagon = true; + + Name = "Master Theophilus"; + Title = "the necromancer"; + Hue = 0; + + SetStr( 137, 187 ); + SetDex( 253, 301 ); + SetInt( 393, 444 ); + + SetHits( 663, 876 ); + + SetDamage( 15, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 60 ); + SetResistance( ResistanceType.Fire, 50, 58 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 69.9, 105.3 ); + SetSkill( SkillName.Tactics, 113.0, 117.9 ); + SetSkill( SkillName.MagicResist, 127.0, 132.8 ); + SetSkill( SkillName.Magery, 138.1, 143.7 ); + SetSkill( SkillName.EvalInt, 125.6, 133.8 ); + SetSkill( SkillName.Necromancy, 125.6, 133.8 ); + SetSkill( SkillName.SpiritSpeak, 125.6, 133.8 ); + SetSkill( SkillName.Meditation, 128.8, 132.9 ); + + Fame = 18000; + Karma = -18000; + + AddItem( new Shoes( 0x537 ) ); + AddItem( new Robe( 0x452 ) ); + + for ( int i = 0; i < 2; ++i ) + { + /*if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else*/ + PackScroll( 4, 7 ); + } + + PackReg( 7 ); + PackReg( 7 ); + PackReg( 8 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public MasterTheophilus( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs new file mode 100644 index 0000000..4faae6d --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/RedDeath.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Red Death corpse" )] + public class RedDeath : SkeletalMount + { + [Constructable] + public RedDeath() + : base( "Red Death" ) + { + IsParagon = true; + + Hue = 0x21; + BaseSoundID = 0x1C3; + + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + + SetStr( 319, 324 ); + SetDex( 241, 244 ); + SetInt( 242, 255 ); + + SetHits( 1540, 1605 ); + + SetDamage( 25, 29 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 75 ); + SetDamageType( ResistanceType.Cold, 0 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 90 ); + SetResistance( ResistanceType.Cold, 0 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 0 ); + + SetSkill( SkillName.Wrestling, 121.4, 143.7 ); + SetSkill( SkillName.Tactics, 120.9, 142.2 ); + SetSkill( SkillName.MagicResist, 120.1, 142.3 ); + SetSkill( SkillName.Anatomy, 120.2, 144.0 ); + + Fame = 28000; + Karma = -28000; + + /*if ( Utility.RandomBool() ) + PackNecroScroll( Utility.RandomMinMax( 5, 9 ) ); + else*/ + PackScroll( 4, 7 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.WhirlwindAttack; + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new ResolvesBridle() ); + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override bool AlwaysMurderer{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } + public override int BreathChaosDamage{ get { return 100; } } + public override int BreathFireDamage{ get{ return 0; } } + + public RedDeath( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs b/Scripts/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs new file mode 100644 index 0000000..70a715a --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Bedlam/SirPatrick.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Sir Patrick corpse" )] + public class SirPatrick : SkeletalKnight + { + [Constructable] + public SirPatrick() + { + IsParagon = true; + + Name = "Sir Patrick"; + Hue = 0x47E; + + SetStr( 208, 319 ); + SetDex( 98, 132 ); + SetInt( 45, 91 ); + + SetHits( 616, 884 ); + + SetDamage( 15, 25 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 55, 62 ); + SetResistance( ResistanceType.Fire, 40, 48 ); + SetResistance( ResistanceType.Cold, 71, 80 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 126.3, 136.5 ); + SetSkill( SkillName.Tactics, 128.5, 143.8 ); + SetSkill( SkillName.MagicResist, 102.8, 117.9 ); + SetSkill( SkillName.Anatomy, 127.5, 137.2 ); + + Fame = 18000; + Karma = -18000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( Utility.RandomDouble() < 0.1 ) + DrainLife(); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( Utility.RandomDouble() < 0.1 ) + DrainLife(); + } + + public virtual void DrainLife() + { + List list = new List(); + + foreach ( Mobile m in GetMobilesInRange( 2 ) ) + { + if ( m == this || !CanBeHarmful( m, false ) || ( Core.AOS && !InLOS( m ) ) ) + continue; + + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( bc.Controlled || bc.Summoned || bc.Team != Team ) + list.Add( m ); + } + else if ( m.Player ) + { + list.Add( m ); + } + } + + foreach ( Mobile m in list ) + { + DoHarmful( m ); + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist ); + m.PlaySound( 0x1EA ); + + int drain = Utility.RandomMinMax( 14, 30 ); + + Hits += drain; + m.Damage( drain, this ); + } + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.15 ) + c.DropItem( new DisintegratingThesisNotes() ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new AssassinChest() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public SirPatrick( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs new file mode 100644 index 0000000..f92d46d --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Abscess.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an Abscess corpse" )] + public class Abscess : Hydra + { + [Constructable] + public Abscess() + { + IsParagon = true; + + Name = "Abscess"; + Hue = 0x8FD; + + SetStr( 845, 871 ); + SetDex( 121, 134 ); + SetInt( 124, 142 ); + + SetHits( 7470, 7540 ); + + SetDamage( 26, 31 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Cold, 10 ); + SetDamageType( ResistanceType.Poison, 10 ); + SetDamageType( ResistanceType.Energy, 10 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 45 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.Wrestling, 132.3, 143.8 ); + SetSkill( SkillName.Tactics, 121.0, 130.5 ); + SetSkill( SkillName.MagicResist, 102.9, 119.0 ); + SetSkill( SkillName.Anatomy, 91.8, 94.3 ); + + // TODO: Fame/Karma + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 4 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new AbscessTail() ); + } + + public override bool GivesMLMinorArtifact { get { return true; } } + + public Abscess( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Coil.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Coil.cs new file mode 100644 index 0000000..11505c5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Coil.cs @@ -0,0 +1,106 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Coil corpse" )] + public class Coil : SilverSerpent + { + // TODO: Check faction allegiance + + [Constructable] + public Coil() + { + IsParagon = true; + + Name = "Coil"; + Hue = 0x3F; + + SetStr( 205, 343 ); + SetDex( 202, 283 ); + SetInt( 88, 142 ); + + SetHits( 628, 1291 ); + + SetDamage( 19, 28 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 56, 62 ); + SetResistance( ResistanceType.Fire, 25, 30 ); + SetResistance( ResistanceType.Cold, 25, 30 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 25, 30 ); + + SetSkill( SkillName.Wrestling, 124.5, 141.3 ); + SetSkill( SkillName.Tactics, 130.2, 142.0 ); + SetSkill( SkillName.MagicResist, 102.3, 113.0 ); + SetSkill( SkillName.Anatomy, 120.8, 138.1 ); + SetSkill( SkillName.Poisoning, 110.1, 133.4 ); + + // TODO: Fame/Karma + + PackGem( 2 ); + PackItem( new Bone() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.MortalStrike; + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new CoilsFang() ); + + /* + // TODO: uncomment once added + if ( Utility.RandomDouble() < 0.025 ) + { + switch ( Utility.Random( 5 ) ) + { + case 0: c.DropItem( new AssassinChest() ); break; + case 1: c.DropItem( new DeathGloves() ); break; + case 2: c.DropItem( new LeafweaveLegs() ); break; + case 3: c.DropItem( new HunterLegs() ); break; + case 4: c.DropItem( new MyrmidonLegs() ); break; + } + } + */ + } + + public override Poison HitPoison { get { return Poison.Lethal; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + public override bool GivesMLMinorArtifact { get { return true; } } + public override int Hides { get { return 48; } } + public override int Meat { get { return 1; } } + + public Coil( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs new file mode 100644 index 0000000..d579eef --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/EnslavedSatyr.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an enslaved satyr corpse" )] + public class EnslavedSatyr : Satyr + { + [Constructable] + public EnslavedSatyr() + { + Name = "an enslaved satyr"; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public EnslavedSatyr( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs new file mode 100644 index 0000000..794a397 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Hydra.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a hydra corpse" )] + public class Hydra : BaseCreature + { + [Constructable] + public Hydra() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a hydra"; + Body = 0x109; + BaseSoundID = 0x16A; + + SetStr( 801, 828 ); + SetDex( 102, 118 ); + SetInt( 102, 120 ); + + SetHits( 1480, 1500 ); + + SetDamage( 21, 26 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Cold, 10 ); + SetDamageType( ResistanceType.Poison, 10 ); + SetDamageType( ResistanceType.Energy, 10 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 70, 85 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 43 ); + SetResistance( ResistanceType.Energy, 36, 45 ); + + SetSkill( SkillName.Wrestling, 103.5, 117.4 ); + SetSkill( SkillName.Tactics, 100.1, 109.8 ); + SetSkill( SkillName.MagicResist, 85.5, 98.5 ); + SetSkill( SkillName.Anatomy, 75.4, 79.8 ); + + // TODO: Fame/Karma + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new HydraScale() ); + + /* + // TODO: uncomment once added + if ( Utility.RandomDouble() < 0.2 ) + c.DropItem( new ParrotItem() ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new ThorvaldsMedallion() ); + */ + } + + public override bool HasBreath { get { return true; } } + public override int Hides { get { return 40; } } + public override int Meat { get { return 19; } } + public override int TreasureMapLevel { get { return 5; } } + + public Hydra( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs new file mode 100644 index 0000000..e1f88df --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/InsaneDryad.cs @@ -0,0 +1,50 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an insane dryad corpse" )] + public class InsaneDryad : MLDryad + { + public override bool InitialInnocent { get { return false; } } + + [Constructable] + public InsaneDryad() + { + Name = "an insane dryad"; + + // TODO: Perhaps these should have negative karma? + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public InsaneDryad( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs new file mode 100644 index 0000000..a4445f2 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Saliva.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Saliva corpse" )] + public class Saliva : Harpy + { + [Constructable] + public Saliva() + { + // TODO: Not a paragon? No ML arties? + // It moves like a paragon on OSI... + + Name = "Saliva"; + Hue = 0x11E; + + SetStr( 110, 206 ); + SetDex( 123, 222 ); + SetInt( 80, 127 ); + + SetHits( 409, 842 ); + + SetDamage( 20, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 46, 48 ); + SetResistance( ResistanceType.Fire, 32, 40 ); + SetResistance( ResistanceType.Cold, 34, 49 ); + SetResistance( ResistanceType.Poison, 40, 48 ); + SetResistance( ResistanceType.Energy, 35, 39 ); + + SetSkill( SkillName.Wrestling, 106.4, 128.8 ); + SetSkill( SkillName.Tactics, 129.9, 141.0 ); + SetSkill( SkillName.MagicResist, 84.3, 105.0 ); + + // TODO: Fame/Karma? + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new SalivasFeather() ); + + // TODO: uncomment once added + //if ( Utility.RandomDouble() < 0.1 ) + // c.DropItem( new ParrotItem() ); + } + + public Saliva( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs new file mode 100644 index 0000000..46c0294 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Tangle.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Tangle corpse" )] + public class Tangle : BogThing + { + [Constructable] + public Tangle() + { + // TODO: Not a paragon? No ML arties? + // It moves like a paragon on OSI... + + Name = "Tangle"; + Hue = 0x21; + + SetStr( 870, 940 ); + SetDex( 58, 74 ); + SetInt( 46, 58 ); + + SetHits( 2468, 2733 ); + SetMana( 8, 12 ); + + SetDamage( 15, 28 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 50, 57 ); + SetResistance( ResistanceType.Fire, 40, 43 ); + SetResistance( ResistanceType.Cold, 30, 35 ); + SetResistance( ResistanceType.Poison, 61, 69 ); + SetResistance( ResistanceType.Energy, 41, 45 ); + + SetSkill( SkillName.Wrestling, 77.8, 94.6 ); + SetSkill( SkillName.Tactics, 90.6, 100.4 ); + SetSkill( SkillName.MagicResist, 108.4, 114.0 ); + + // TODO: Fame/Karma? + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.3 ) + c.DropItem( new TaintedSeeds() ); + } + + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public Tangle( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs new file mode 100644 index 0000000..9761c9c --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Blighted Grove/Thrasher.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Thrasher corpse" )] + public class Thrasher : Alligator + { + [Constructable] + public Thrasher() + { + IsParagon = true; + + Name = "Thrasher"; + Hue = 0x497; + + SetStr( 93, 327 ); + SetDex( 7, 201 ); + SetInt( 15, 67 ); + + SetHits( 260, 984 ); + SetStam( 56, 75 ); + SetMana( 25, 30 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 55 ); + SetResistance( ResistanceType.Fire, 25, 29 ); + SetResistance( ResistanceType.Poison, 25, 28 ); + + SetSkill( SkillName.Wrestling, 101.2, 118.3 ); + SetSkill( SkillName.Tactics, 96.3, 117.3 ); + SetSkill( SkillName.MagicResist, 102.4, 118.6 ); + + // TODO: Fame/Karma + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 4 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ArmorIgnore; + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new ThrashersTail() ); + } + + public override bool GivesMLMinorArtifact { get { return true; } } + public override int Hides { get { return 48; } } + public override int Meat { get { return 1; } } + + public Thrasher( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs new file mode 100644 index 0000000..5be41aa --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/FetidEssence.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("a fetid essence corpse")] + public class FetidEssence : BaseCreature + { + [Constructable] + public FetidEssence () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fetid essence"; + Body = 273; + + SetStr( 101, 150 ); + SetDex( 210, 250 ); + SetInt( 451, 550 ); + + SetHits( 551, 650 ); + + SetDamage( 21, 25 ); + + SetDamageType( ResistanceType.Physical, 30 ); + SetDamageType( ResistanceType.Poison, 70 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 70, 90 ); + SetResistance( ResistanceType.Energy, 75, 80 ); + + SetSkill(SkillName.Meditation, 91.4, 99.4 ); + SetSkill(SkillName.EvalInt, 88.5, 92.3 ); + SetSkill(SkillName.Magery, 97.9, 101.7 ); + SetSkill(SkillName.Poisoning, 100 ); + SetSkill(SkillName.Anatomy, 0, 4.5 ); + SetSkill( SkillName.MagicResist, 103.5, 108.8 ); + SetSkill( SkillName.Tactics, 81.0, 84.6 ); + SetSkill( SkillName.Wrestling, 81.3, 83.9 ); + + Fame = 3700; // Guessed + Karma = -3700; // Guessed + } + + public override void GenerateLoot() // Need to verify + { + AddLoot(LootPack.FilthyRich); + } + + public override Poison HitPoison { get { return Poison.Deadly; } } + public override Poison PoisonImmune { get { return Poison.Deadly; } } + + public override int GetAngerSound() + { + return 0x56d; + } + + public override int GetIdleSound() + { + return 0x56b; + } + + public override int GetAttackSound() + { + return 0x56c; + } + + public override int GetHurtSound() + { + return 0x56c; + } + + public override int GetDeathSound() + { + return 0x56e; + } + + public FetidEssence ( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + /*private class InternalTimer : Timer + { + private Mobile m_From; + private Mobile m_Mobile; + private int m_Count; + + public InternalTimer( Mobile from, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_From = from; + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + }*/ + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs new file mode 100644 index 0000000..bb302c3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/InterredGrizzle .cs @@ -0,0 +1,179 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("an interred grizzle corpse")] + public class InterredGrizzle : BaseCreature + { + [Constructable] + public InterredGrizzle () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an interred grizzle"; + Body = 259; + + SetStr( 451, 500 ); + SetDex( 201, 250 ); + SetInt( 801, 850 ); + + SetHits( 1500 ); + SetStam( 150 ); + + SetDamage( 16, 19 ); + + SetDamageType( ResistanceType.Physical, 30 ); + SetDamageType( ResistanceType.Fire, 70 ); + + SetResistance( ResistanceType.Physical, 35, 55 ); + SetResistance( ResistanceType.Fire, 20, 65 ); + SetResistance( ResistanceType.Cold, 55, 80 ); + SetResistance( ResistanceType.Poison, 20, 35 ); + SetResistance( ResistanceType.Energy, 60, 80 ); + + SetSkill(SkillName.Meditation, 77.7, 84.0 ); + SetSkill(SkillName.EvalInt, 72.2, 79.6 ); + SetSkill(SkillName.Magery, 83.7, 89.6); + SetSkill(SkillName.Poisoning, 0 ); + SetSkill(SkillName.Anatomy, 0 ); + SetSkill( SkillName.MagicResist, 80.2, 87.3 ); + SetSkill( SkillName.Tactics, 104.5, 105.1 ); + SetSkill( SkillName.Wrestling, 105.1, 109.4 ); + + Fame = 3700; // Guessed + Karma = -3700; // Guessed + } + + public override void GenerateLoot() // -- Need to verify + { + AddLoot(LootPack.FilthyRich); + } + + // TODO: Acid Blood + /* + * Message: 1070820 + * Spits pool of acid (blood, hue 0x3F), hits lost 6-10 per second/step + * Damage is resistable (physical) + * Acid last 10 seconds + */ + + public override int GetAngerSound() + { + return 0x581; + } + + public override int GetIdleSound() + { + return 0x582; + } + + public override int GetAttackSound() + { + return 0x580; + } + + public override int GetHurtSound() + { + return 0x583; + } + + public override int GetDeathSound() + { + return 0x584; + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (Utility.RandomDouble() < 0.1) + DropOoze(); + + base.OnDamage(amount, from, willKill); + } + + private int RandomPoint(int mid) + { + return (mid + Utility.RandomMinMax(-2, 2)); + } + + public virtual Point3D GetSpawnPosition(int range) + { + return GetSpawnPosition(Location, Map, range); + } + + public virtual Point3D GetSpawnPosition(Point3D from, Map map, int range) + { + if (map == null) + return from; + + Point3D loc = new Point3D((RandomPoint(X)), (RandomPoint(Y)), Z); + + loc.Z = Map.GetAverageZ(loc.X, loc.Y); + + return loc; + } + + public virtual void DropOoze() + { + int amount = Utility.RandomMinMax(1, 3); + bool corrosive = Utility.RandomBool(); + + for (int i = 0; i < amount; i++) + { + Item ooze = new StainedOoze(corrosive); + Point3D p = new Point3D(Location); + + for (int j = 0; j < 5; j++) + { + p = GetSpawnPosition(2); + bool found = false; + + foreach (Item item in Map.GetItemsInRange(p, 0)) + if (item is StainedOoze) + { + found = true; + break; + } + + if (!found) + break; + } + + ooze.MoveToWorld(p, Map); + } + + if (Combatant != null) + { + if (corrosive) + Combatant.SendLocalizedMessage(1072071); // A corrosive gas seeps out of your enemy's skin! + else + Combatant.SendLocalizedMessage(1072072); // A poisonous gas seeps out of your enemy's skin! + } + } + + /* + public override bool OnBeforeDeath() + { + SpillAcid( 1, 4, 10, 6, 10 ); + + return base.OnBeforeDeath(); + } + */ + + public InterredGrizzle ( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs new file mode 100644 index 0000000..ddd61f3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/MLDryad.cs @@ -0,0 +1,161 @@ +using System; +using Server.Engines.Plants; + +namespace Server.Mobiles +{ + [CorpseName( "a dryad's corpse" )] + public class MLDryad : BaseCreature + { + public override bool InitialInnocent { get { return true; } } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + + [Constructable] + public MLDryad() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a dryad"; + Body = 266; + BaseSoundID = 0x57B; + + SetStr( 132, 149 ); + SetDex( 152, 168 ); + SetInt( 251, 280 ); + + SetHits( 304, 321 ); + + SetDamage( 11, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 40, 45 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Meditation, 80.0, 90.0 ); + SetSkill( SkillName.EvalInt, 70.0, 80.0 ); + SetSkill( SkillName.Magery, 70.0, 80.0 ); + SetSkill( SkillName.Anatomy, 0 ); + SetSkill( SkillName.MagicResist, 100.0, 120.0 ); + SetSkill( SkillName.Tactics, 70.0, 80.0 ); + SetSkill( SkillName.Wrestling, 70.0, 80.0 ); + + Fame = 5000; + Karma = 5000; + + VirtualArmor = 28; // Don't know what it should be + + if ( Core.ML && Utility.RandomDouble() < .60 ) + PackItem( Seed.RandomPeculiarSeed( 1 ) ); + + //PackArcanceScroll( 0.05 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.MlRich ); + } + + public override int Meat { get { return 1; } } + + public override void OnThink() + { + base.OnThink(); + + AreaPeace(); + AreaUndress(); + } + + #region Area Peace + private DateTime m_NextPeace; + + public void AreaPeace() + { + if ( Combatant == null || Deleted || !Alive || m_NextPeace > DateTime.Now || 0.1 < Utility.RandomDouble() ) + return; + + TimeSpan duration = TimeSpan.FromSeconds( Utility.RandomMinMax( 20, 80 ) ); + + foreach ( Mobile m in GetMobilesInRange( RangePerception ) ) + { + PlayerMobile p = m as PlayerMobile; + + if ( IsValidTarget( p ) ) + { + p.PeacedUntil = DateTime.Now + duration; + p.SendLocalizedMessage( 1072065 ); // You gaze upon the dryad's beauty, and forget to continue battling! + p.FixedParticles( 0x376A, 1, 20, 0x7F5, EffectLayer.Waist ); + p.Combatant = null; + } + } + + m_NextPeace = DateTime.Now + TimeSpan.FromSeconds( 10 ); + PlaySound( 0x1D3 ); + } + + public bool IsValidTarget( PlayerMobile m ) + { + if ( m != null && m.PeacedUntil < DateTime.Now && !m.Hidden && m.AccessLevel == AccessLevel.Player && CanBeHarmful( m ) ) + return true; + + return false; + } + #endregion + + #region Undress + private DateTime m_NextUndress; + + public void AreaUndress() + { + if ( Combatant == null || Deleted || !Alive || m_NextUndress > DateTime.Now || 0.005 < Utility.RandomDouble() ) + return; + + foreach ( Mobile m in GetMobilesInRange( RangePerception ) ) + { + if ( m != null && m.Player && !m.Female && !m.Hidden && m.AccessLevel == AccessLevel.Player && CanBeHarmful( m ) ) + { + UndressItem( m, Layer.OuterTorso ); + UndressItem( m, Layer.InnerTorso ); + UndressItem( m, Layer.MiddleTorso ); + UndressItem( m, Layer.Pants ); + UndressItem( m, Layer.Shirt ); + + m.SendLocalizedMessage( 1072197 ); // The dryad's beauty makes your blood race. Your clothing is too confining. + } + } + + m_NextUndress = DateTime.Now + TimeSpan.FromMinutes( 1 ); + } + + public void UndressItem( Mobile m, Layer layer ) + { + Item item = m.FindItemOnLayer( layer ); + + if ( item != null && item.Movable ) + m.PlaceInBackpack( item ); + } + #endregion + + public MLDryad( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs new file mode 100644 index 0000000..7f14f3f --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Magic/Satyr.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + [CorpseName( "a satyr's corpse" )] + public class Satyr : BaseCreature + { + [Constructable] + public Satyr() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a satyr"; + Body = 271; + BaseSoundID = 0x586; + + SetStr( 177, 195 ); + SetDex( 251, 269 ); + SetInt( 153, 170 ); + + SetHits( 350, 400 ); + + SetDamage( 13, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 60 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 55.0, 65.0 ); + SetSkill( SkillName.Tactics, 80.0, 100.0 ); + SetSkill( SkillName.Wrestling, 80.0, 100.0 ); + + Fame = 5000; + Karma = 0; + + VirtualArmor = 28; // Don't know what it should be + + //PackArcanceScroll( 0.05 ); + } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + + public override void GenerateLoot() + { + AddLoot( LootPack.MlRich ); + } + + public override void OnThink() + { + base.OnThink(); + + Peace( Combatant ); + Undress( Combatant ); + Suppress( Combatant ); + Provoke( Combatant ); + } + + #region Peace + private DateTime m_NextPeace; + + public void Peace( Mobile target ) + { + if ( target == null || Deleted || !Alive || m_NextPeace > DateTime.Now || 0.1 < Utility.RandomDouble() ) + return; + + PlayerMobile p = target as PlayerMobile; + + if ( p != null && p.PeacedUntil < DateTime.Now && !p.Hidden && CanBeHarmful( p ) ) + { + p.PeacedUntil = DateTime.Now + TimeSpan.FromMinutes( 1 ); + p.SendLocalizedMessage( 500616 ); // You hear lovely music, and forget to continue battling! + p.FixedParticles( 0x376A, 1, 32, 0x15BD, EffectLayer.Waist ); + p.Combatant = null; + + PlaySound( 0x58D ); + } + + m_NextPeace = DateTime.Now + TimeSpan.FromSeconds( 10 ); + } + #endregion + + #region Suppress + private static Dictionary m_Suppressed = new Dictionary(); + private DateTime m_NextSuppress; + + public void Suppress( Mobile target ) + { + if ( target == null || m_Suppressed.ContainsKey( target ) || Deleted || !Alive || m_NextSuppress > DateTime.Now || 0.1 < Utility.RandomDouble() ) + return; + + TimeSpan delay = TimeSpan.FromSeconds( Utility.RandomMinMax( 20, 80 ) ); + + if ( !target.Hidden && CanBeHarmful( target ) ) + { + target.SendLocalizedMessage( 1072061 ); // You hear jarring music, suppressing your strength. + + for ( int i = 0; i < target.Skills.Length; i++ ) + { + Skill s = target.Skills[ i ]; + + target.AddSkillMod( new TimedSkillMod( s.SkillName, true, s.Base * -0.28, delay ) ); + } + + int count = (int) Math.Round( delay.TotalSeconds / 1.25 ); + Timer timer = new AnimateTimer( target, count ); + m_Suppressed.Add( target, timer ); + timer.Start(); + + PlaySound( 0x58C ); + } + + m_NextSuppress = DateTime.Now + TimeSpan.FromSeconds( 10 ); + } + + public static void SuppressRemove( Mobile target ) + { + if ( target != null && m_Suppressed.ContainsKey( target ) ) + { + Timer timer = m_Suppressed[ target ]; + + if ( timer != null || timer.Running ) + timer.Stop(); + + m_Suppressed.Remove( target ); + } + } + + private class AnimateTimer : Timer + { + private Mobile m_Owner; + private int m_Count; + + public AnimateTimer( Mobile owner, int count ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.25 ) ) + { + m_Owner = owner; + m_Count = count; + } + + protected override void OnTick() + { + if ( m_Owner.Deleted || !m_Owner.Alive || m_Count-- < 0 ) + { + SuppressRemove( m_Owner ); + } + else + m_Owner.FixedParticles( 0x376A, 1, 32, 0x15BD, EffectLayer.Waist ); + } + } + #endregion + + #region Undress + private DateTime m_NextUndress; + + public void Undress( Mobile target ) + { + if ( target == null || Deleted || !Alive || m_NextUndress > DateTime.Now || 0.005 < Utility.RandomDouble() ) + return; + + if ( target.Player && target.Female && !target.Hidden && CanBeHarmful( target ) ) + { + UndressItem( target, Layer.OuterTorso ); + UndressItem( target, Layer.InnerTorso ); + UndressItem( target, Layer.MiddleTorso ); + UndressItem( target, Layer.Pants ); + UndressItem( target, Layer.Shirt ); + + target.SendLocalizedMessage( 1072196 ); // The satyr's music makes your blood race. Your clothing is too confining. + } + + m_NextUndress = DateTime.Now + TimeSpan.FromMinutes( 1 ); + } + + public void UndressItem( Mobile m, Layer layer ) + { + Item item = m.FindItemOnLayer( layer ); + + if ( item != null && item.Movable ) + m.PlaceInBackpack( item ); + } + #endregion + + #region Provoke + private DateTime m_NextProvoke; + + public void Provoke( Mobile target ) + { + if ( target == null || Deleted || !Alive || m_NextProvoke > DateTime.Now || 0.05 < Utility.RandomDouble() ) + return; + + foreach ( Mobile m in GetMobilesInRange( RangePerception ) ) + { + if ( m is BaseCreature ) + { + BaseCreature c = (BaseCreature) m; + + if ( c == this || c == target || c.Unprovokable || c.IsParagon || c.BardProvoked || c.AccessLevel != AccessLevel.Player || !c.CanBeHarmful( target ) ) + continue; + + c.Provoke( this, target, true ); + + if ( target.Player ) + target.SendLocalizedMessage( 1072062 ); // You hear angry music, and start to fight. + + PlaySound( 0x58A ); + break; + } + } + + m_NextProvoke = DateTime.Now + TimeSpan.FromSeconds( 10 ); + } + #endregion + + public override int Meat { get { return 1; } } + + public Satyr( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs new file mode 100644 index 0000000..7df86f0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/CorruptedSoul.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Targeting; +using Server.Engines.Quests; +using Server.Engines.Quests.Haven; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class CorruptedSoul : BaseCreature + { + public override bool DeleteCorpseOnDeath{ get{ return true; } } + + [Constructable] + public CorruptedSoul() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, .1, 5 ) + { + Name = "a corrupted soul"; + Body = 0x3CA; + Hue = 0x453; + + SetStr( 102, 115 ); + SetDex( 101, 115 ); + SetInt( 203, 215 ); + + SetHits( 61, 69 ); + + SetDamage( 4, 40 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 61, 74 ); + SetResistance( ResistanceType.Fire, 22, 48 ); + SetResistance( ResistanceType.Cold, 73, 100 ); + SetResistance( ResistanceType.Poison, 0 ); + SetResistance( ResistanceType.Energy, 51, 60 ); + + SetSkill( SkillName.MagicResist, 80.2, 89.4 ); + SetSkill( SkillName.Tactics, 81.3, 89.9 ); + SetSkill( SkillName.Wrestling, 80.1, 88.7 ); + + Fame = 5000; + Karma = -5000; + + // VirtualArmor = 6; Not sure + } + + public override bool AlwaysAttackable{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } // NEED TO VERIFY + + // NEED TO VERIFY SOUNDS! Known: No Idle Sound. + + /*public override int GetAngerSound() + { + return 0x0; + }*/ + + public override int GetAttackSound() + { + return 0x233; + } + + /*public override int GetDeathSound() + { + return 0x0; + }*/ + + public override bool AlwaysMurderer{ get{ return true; } } + + // TODO: Proper OnDeath Effect + + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + // 1 in 20 chance that a Thread of Fate will appear in the killer's pack + + Effects.SendLocationEffect( Location, Map, 0x376A, 10, 1 ); + return true; + } + + public CorruptedSoul( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs new file mode 100644 index 0000000..547fc9c --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/FerelTreefellow.cs @@ -0,0 +1,90 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a treefellow corpse" )] + public class FerelTreefellow : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public FerelTreefellow() : base( AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a ferel treefellow"; + Body = 301; + + SetStr( 1351, 1600 ); + SetDex( 301, 550 ); + SetInt( 651, 900 ); + + SetHits( 1170, 1320 ); + + SetDamage( 26, 35 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + + SetSkill( SkillName.MagicResist, 40.1, 55.0 );// Unknown + SetSkill( SkillName.Tactics, 65.1, 90.0 );// Unknown + SetSkill( SkillName.Wrestling, 65.1, 85.0 );// Unknown + + Fame = 12500; //Unknown + Karma = 12500; //Unknown + + VirtualArmor = 24; + PackItem( new Log( Utility.RandomMinMax( 23, 34 ) ) ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override int GetIdleSound() + { + return 443; + } + + public override int GetDeathSound() + { + return 31; + } + + public override int GetAttackSound() + { + return 672; + } + + public override bool BleedImmune{ get{ return true; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); //Unknown + } + + public FerelTreefellow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs new file mode 100644 index 0000000..145f5b7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Minotaur.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a minotaur corpse" )] + public class Minotaur : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + [Constructable] + public Minotaur() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) // NEED TO CHECK + { + Name = "a minotaur"; + Body = 263; + + SetStr( 301, 340 ); + SetDex( 91, 110 ); + SetInt( 31, 50 ); + + SetHits( 301, 340 ); + + SetDamage( 11, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Meditation, 0 ); + SetSkill( SkillName.EvalInt, 0 ); + SetSkill( SkillName.Magery, 0 ); + SetSkill( SkillName.Poisoning, 0 ); + SetSkill( SkillName.Anatomy, 0 ); + SetSkill( SkillName.MagicResist, 56.1, 64.0 ); + SetSkill( SkillName.Tactics, 93.3, 97.8 ); + SetSkill( SkillName.Wrestling, 90.4, 92.1 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 28; // Don't know what it should be + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); // Need to verify + } + + // Using Tormented Minotaur sounds - Need to veryfy + public override int GetAngerSound() + { + return 0x597; + } + + public override int GetIdleSound() + { + return 0x596; + } + + public override int GetAttackSound() + { + return 0x599; + } + + public override int GetHurtSound() + { + return 0x59a; + } + + public override int GetDeathSound() + { + return 0x59c; + } + + public Minotaur( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs new file mode 100644 index 0000000..ef21909 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurCaptain.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a minotaur corpse" )] + public class MinotaurCaptain : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + [Constructable] + public MinotaurCaptain() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) // NEED TO CHECK + { + Name = "a minotaur captain"; + Body = 280; + + SetStr( 401, 425 ); + SetDex( 91, 110 ); + SetInt( 31, 50 ); + + SetHits( 401, 440 ); + + SetDamage( 11, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Meditation, 0 ); + SetSkill( SkillName.EvalInt, 0 ); + SetSkill( SkillName.Magery, 0 ); + SetSkill( SkillName.Poisoning, 0 ); + SetSkill( SkillName.Anatomy, 0, 6.3 ); + SetSkill( SkillName.MagicResist, 66.1, 73.6 ); + SetSkill( SkillName.Tactics, 93.0, 109.9 ); + SetSkill( SkillName.Wrestling, 92.6, 107.2 ); + + Fame = 7000; + Karma = -7000; + + VirtualArmor = 28; // Don't know what it should be + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); // Need to verify + } + + // Using Tormented Minotaur sounds - Need to veryfy + public override int GetAngerSound() + { + return 0x597; + } + + public override int GetIdleSound() + { + return 0x596; + } + + public override int GetAttackSound() + { + return 0x599; + } + + public override int GetHurtSound() + { + return 0x59a; + } + + public override int GetDeathSound() + { + return 0x59c; + } + + public MinotaurCaptain( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs new file mode 100644 index 0000000..9ded046 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/MinotaurScout.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a minotaur corpse" )] + public class MinotaurScout : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + [Constructable] + public MinotaurScout() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) // NEED TO CHECK + { + Name = "a minotaur scout"; + Body = 281; + + SetStr( 353, 375 ); + SetDex( 111, 130 ); + SetInt( 34, 50 ); + + SetHits( 354, 383 ); + + SetDamage( 11, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + //SetSkill( SkillName.Meditation, Unknown ); + //SetSkill( SkillName.EvalInt, Unknown ); + //SetSkill( SkillName.Magery, Unknown ); + //SetSkill( SkillName.Poisoning, Unknown ); + SetSkill( SkillName.Anatomy, 0 ); + SetSkill( SkillName.MagicResist, 60.6, 67.5 ); + SetSkill( SkillName.Tactics, 86.9, 103.6 ); + SetSkill( SkillName.Wrestling, 85.6, 104.5 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 28; // Don't know what it should be + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); // Need to verify + } + + // Using Tormented Minotaur sounds - Need to veryfy + public override int GetAngerSound() + { + return 0x597; + } + + public override int GetIdleSound() + { + return 0x596; + } + + public override int GetAttackSound() + { + return 0x599; + } + + public override int GetHurtSound() + { + return 0x59a; + } + + public override int GetDeathSound() + { + return 0x59c; + } + + public MinotaurScout( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs new file mode 100644 index 0000000..b18485d --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/PestilentBandage.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName("a pestilent bandage corpse")] + public class PestilentBandage : BaseCreature + { + // Neither Stratics nor UOGuide have much description + // beyond being a "Grey Mummy". BodyValue, Sound and + // Hue are all guessed until they can be verified. + // Loot and Fame/Karma are also guesses at this point. + // + // They also apparently have a Poison Attack, which I've stolen from Yamandons. + [Constructable] + public PestilentBandage() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) // NEED TO CHECK + { + Name = "a pestilent bandage"; + Body = 154; + Hue = 0x515; + BaseSoundID = 471; + + SetStr( 691, 740 ); + SetDex( 141, 180 ); + SetInt( 51, 80 ); + + SetHits( 415, 445 ); + + SetDamage( 13, 23 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.Poisoning, 0.0, 10.0 ); + SetSkill( SkillName.Anatomy, 0 ); + SetSkill( SkillName.MagicResist, 75.0, 80.0 ); + SetSkill( SkillName.Tactics, 80.0, 85.0 ); + SetSkill( SkillName.Wrestling, 70.0, 75.0 ); + + Fame = 20000; + Karma = -20000; + + // VirtualArmor = 28; // Don't know what it should be + + PackItem( new Bandage( 5 ) ); // How many? + + } + + public override Poison HitPoison { get { return Poison.Lethal; } } + public override bool CanHeal { get { return true; } } + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); // Need to verify + } + + public PestilentBandage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs new file mode 100644 index 0000000..5db05f6 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Tormented Minotaur.cs @@ -0,0 +1,78 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a tormented minotaur corpse" )] + public class TormentedMinotaur : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public TormentedMinotaur() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Tormented Minotaur"; + Body = 262; + + SetStr( 822, 930 ); + SetDex( 401, 415 ); + SetInt( 128, 138 ); + + SetHits( 4000, 4200 ); + + SetDamage( 16, 30 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 62 ); + SetResistance( ResistanceType.Fire, 74 ); + SetResistance( ResistanceType.Cold, 54 ); + SetResistance( ResistanceType.Poison, 56 ); + SetResistance( ResistanceType.Energy, 54 ); + + SetSkill( SkillName.Wrestling, 110.1, 111.0 ); + SetSkill( SkillName.Tactics, 100.7, 102.8 ); + SetSkill( SkillName.MagicResist, 104.3, 116.3 ); + + + Fame = 20000; + Karma = -20000; + + } + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 10); + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public override int GetDeathSound() { return 0x596; } + public override int GetAttackSound() { return 0x597; } + public override int GetIdleSound() { return 0x598; } + public override int GetAngerSound() { return 0x599; } + public override int GetHurtSound() { return 0x59A; } + + public TormentedMinotaur( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs new file mode 100644 index 0000000..442b274 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Humanoid/Melee/Troglodyte.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a troglodyte corpse" )] + public class Troglodyte : BaseCreature + { + + [Constructable] + public Troglodyte() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) // NEED TO CHECK + { + Name = "a troglodyte"; + Body = 267; + BaseSoundID = 0x59F; + + SetStr( 148, 217 ); + SetDex( 91, 120 ); + SetInt( 51, 70 ); + + SetHits( 302, 340 ); + + SetDamage( 11, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 35 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 35, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Anatomy, 70.5, 94.8 ); + SetSkill( SkillName.MagicResist, 51.8, 65.0 ); + SetSkill( SkillName.Tactics, 80.4, 94.7 ); + SetSkill( SkillName.Wrestling, 70.2, 93.5 ); + SetSkill(SkillName.Healing, 70.0, 95.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 28; // Don't know what it should be + + Ribs rib = new Ribs(); + if (Utility.RandomDouble() <= 0.15) + rib.Poison = Poison.Regular; + + PackItem(new Bandage(5)); // How many? + PackItem(rib); + } + + public override bool CanHeal { get { return true; } } + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); // Need to verify + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.1) + c.DropItem(new PrimitiveFetish()); + } + + public Troglodyte(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Labyrinth/Miasma.cs b/Scripts/Mobiles/Monsters/ML/Labyrinth/Miasma.cs new file mode 100644 index 0000000..58a78c7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Labyrinth/Miasma.cs @@ -0,0 +1,114 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("a Miasma corpse")] + public class Miasma : Scorpion + { + [Constructable] + public Miasma() + { + IsParagon = true; + + Name = "Miasma"; + Hue = 0x8FD; + + SetStr(255, 847); + SetDex(145, 428); + SetInt(26, 380); + + SetHits(750, 2000); + SetMana(5, 60); + + SetDamage(20, 30); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Poison, 40); + + SetResistance(ResistanceType.Physical, 50, 54); + SetResistance(ResistanceType.Fire, 40, 45); + SetResistance(ResistanceType.Cold, 50, 55); + SetResistance(ResistanceType.Poison, 70, 80); + SetResistance(ResistanceType.Energy, 40, 45); + + SetSkill(SkillName.Wrestling, 84.9, 103.3); + SetSkill(SkillName.Tactics, 98.4, 110.6); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 74.4, 77.7); + SetSkill(SkillName.Poisoning, 128.5, 143.6); + + Fame = 21000; + Karma = -21000; + } + + /* yes, this is OSI style */ + public override double WeaponAbilityChance { get { return 0.75; } } + public override double HitPoisonChance { get { return 0.35; } } + public override Poison HitPoison { get { return (Poison.Lethal); } } + public override bool HasManaOveride { get { return true; } } + public override bool GivesMLMinorArtifact { get { return true; } } + public override int TreasureMapLevel { get { return 5; } } + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 4); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.MortalStrike; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.025 ) + { + switch ( Utility.Random( 16 ) ) + { + case 0: c.DropItem( new MyrmidonGloves() ); break; + case 1: c.DropItem( new MyrmidonGorget() ); break; + case 2: c.DropItem( new MyrmidonLegs() ); break; + case 3: c.DropItem( new MyrmidonArms() ); break; + case 4: c.DropItem( new PaladinArms() ); break; + case 5: c.DropItem( new PaladinGorget() ); break; + case 6: c.DropItem( new LeafweaveLegs() ); break; + case 7: c.DropItem( new DeathChest() ); break; + case 8: c.DropItem( new DeathGloves() ); break; + case 9: c.DropItem( new DeathLegs() ); break; + case 10: c.DropItem( new GreymistGloves() ); break; + case 11: c.DropItem( new GreymistArms() ); break; + case 12: c.DropItem( new AssassinChest() ); break; + case 13: c.DropItem( new AssassinArms() ); break; + case 14: c.DropItem( new HunterGloves() ); break; + case 15: c.DropItem( new HunterLegs() ); break; + } + } + } + */ + + public Miasma(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs b/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs new file mode 100644 index 0000000..36fb273 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Labyrinth/Pyre.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a Pyre corpse" )] + public class Pyre : Phoenix + { + [Constructable] + public Pyre() + { + IsParagon = true; + + Name = "Pyre"; + Hue = 0x489; + + FightMode = FightMode.Closest; + + SetStr( 605, 611 ); + SetDex( 391, 519 ); + SetInt( 669, 818 ); + + SetHits( 1783, 1939 ); + + SetDamage( 30 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 50 ); + + SetResistance( ResistanceType.Physical, 65 ); + SetResistance( ResistanceType.Fire, 72, 75 ); + SetResistance( ResistanceType.Poison, 36, 41 ); + SetResistance( ResistanceType.Energy, 50, 51 ); + + SetSkill( SkillName.Wrestling, 121.9, 130.6 ); + SetSkill( SkillName.Tactics, 114.4, 117.4 ); + SetSkill( SkillName.MagicResist, 147.7, 153.0 ); + SetSkill( SkillName.Poisoning, 122.8, 124.0 ); + SetSkill( SkillName.Magery, 121.8, 127.8 ); + SetSkill( SkillName.EvalInt, 103.6, 117.0 ); + SetSkill( SkillName.Meditation, 100.0, 110.0 ); + + Fame = 21000; + Karma = -21000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + if ( Utility.RandomBool() ) + return WeaponAbility.ParalyzingBlow; + else + return WeaponAbility.BleedAttack; + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + public override bool HasAura{ get{ return true; } } + + public Pyre( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs b/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs new file mode 100644 index 0000000..107716d --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Labyrinth/Rend.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Rend corpse" )] + public class Rend : Reptalon + { + [Constructable] + public Rend() + { + IsParagon = true; + + Name = "Rend"; + Hue = 0x455; + + SetStr( 1261, 1284 ); + SetDex( 363, 384 ); + SetInt( 601, 642 ); + + SetHits( 5176, 6100 ); + + SetDamage( 26, 33 ); + + SetDamageType( ResistanceType.Physical, 100 ); + SetDamageType( ResistanceType.Poison, 0 ); + SetDamageType( ResistanceType.Energy, 0 ); + + SetResistance( ResistanceType.Physical, 75, 85 ); + SetResistance( ResistanceType.Fire, 81, 94 ); + SetResistance( ResistanceType.Cold, 46, 55 ); + SetResistance( ResistanceType.Poison, 35, 44 ); + SetResistance( ResistanceType.Energy, 45, 52 ); + + SetSkill( SkillName.Wrestling, 136.3, 150.3 ); + SetSkill( SkillName.Tactics, 133.4, 141.4 ); + SetSkill( SkillName.MagicResist, 90.9, 110.0 ); + SetSkill( SkillName.Anatomy, 66.6, 72.0 ); + + Fame = 21000; + Karma = -21000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + if ( Utility.RandomBool() ) + return WeaponAbility.ParalyzingBlow; + else + return WeaponAbility.BleedAttack; + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public Rend( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs b/Scripts/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs new file mode 100644 index 0000000..f3ffbff --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Misc/Magic/GreaterDragon.cs @@ -0,0 +1,122 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class GreaterDragon : BaseCreature + { + public override bool StatLossAfterTame { get { return true; } } + + [Constructable] + public GreaterDragon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5 ) + { + Name = "a greater dragon"; + Body = Utility.RandomList( 12, 59 ); + BaseSoundID = 362; + + SetStr( 1025, 1425 ); + SetDex( 81, 148 ); + SetInt( 475, 675 ); + + SetHits( 1000, 2000 ); + SetStam( 120, 135 ); + + SetDamage( 24, 33 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60, 85 ); + SetResistance( ResistanceType.Fire, 65, 90 ); + SetResistance( ResistanceType.Cold, 40, 55 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 50, 75 ); + + SetSkill( SkillName.Meditation, 0 ); + SetSkill( SkillName.EvalInt, 110.0, 140.0 ); + SetSkill( SkillName.Magery, 110.0, 140.0 ); + SetSkill( SkillName.Poisoning, 0 ); + SetSkill( SkillName.Anatomy, 0 ); + SetSkill( SkillName.MagicResist, 110.0, 140.0 ); + SetSkill( SkillName.Tactics, 110.0, 140.0 ); + SetSkill( SkillName.Wrestling, 115.0, 145.0 ); + + Fame = 22000; + Karma = -15000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 5; + MinTameSkill = 104.7; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 4 ); + AddLoot( LootPack.Gems, 8 ); + } + + public override bool CanFly { get { return true; } } + public override bool ReacquireOnMovement{ get{ return !Controlled; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override bool AutoDispel{ get{ return !Controlled; } } + public override int TreasureMapLevel{ get{ return 5; } } + public override int Meat{ get{ return 19; } } + public override int Hides{ get{ return 30; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override int Scales{ get{ return 7; } } + public override ScaleType ScaleType{ get{ return ( Body == 12 ? ScaleType.Yellow : ScaleType.Red ); } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.15) + { + if (!from.CheckSkill(SkillName.Forensics, 30, 80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new ReptiledRelic()); + from.SendMessage("Un pan de cuir se d�tache du ventre de la b�te"); + } + } + base.OnCarve(from, corpse, with); + } + + public GreaterDragon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + SetDamage( 24, 33 ); + + if( version == 0 ) + { + Server.SkillHandlers.AnimalTaming.ScaleStats( this, 0.50 ); + Server.SkillHandlers.AnimalTaming.ScaleSkills( this, 0.80, 0.90 ); // 90% * 80% = 72% of original skills trainable to 90% + Skills[SkillName.Magery].Base = Skills[SkillName.Magery].Cap; // Greater dragons have a 90% cap reduction and 90% skill reduction on magery + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs b/Scripts/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs new file mode 100644 index 0000000..11ccb86 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Misc/Melee/CorrosiveSlime.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a slimey corpse" )] + public class CorrosiveSlime : BaseCreature + { + [Constructable] + public CorrosiveSlime() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a corrosive slime"; + Body = 51; + BaseSoundID = 456; + + Hue = Utility.RandomSlimeHue(); + + SetStr( 22, 34 ); + SetDex( 16, 21 ); + SetInt( 16, 20 ); + + SetHits( 15, 19 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Poison, 15, 20 ); + + SetSkill( SkillName.Poisoning, 36.0, 49.1 ); + SetSkill(SkillName.Anatomy, 0); + SetSkill( SkillName.MagicResist, 15.9, 18.9 ); + SetSkill( SkillName.Tactics, 24.6, 26.1 ); + SetSkill( SkillName.Wrestling, 24.9, 26.1 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + AddLoot( LootPack.Gems ); + } + + public override Poison PoisonImmune { get { return Poison.Regular; } } + public override Poison HitPoison { get { return Poison.Regular; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + //TODO: Damage weapon via acid + + public CorrosiveSlime( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs b/Scripts/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs new file mode 100644 index 0000000..03dd5f5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Misc/Melee/Reptalon.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a reptalon corpse" )] + public class Reptalon : BaseMount + { + [Constructable] + public Reptalon() : base( "a reptalon", 0x114, 0x3E90, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.35) + { + BaseSoundID = 0x16A; + + SetStr( 1001, 1025 ); + SetDex( 152, 164 ); + SetInt( 251, 289 ); + + SetHits( 833, 931 ); + + SetDamage( 21, 28 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Poison, 25 ); + SetDamageType( ResistanceType.Energy, 75 ); + + SetResistance( ResistanceType.Physical, 53, 64 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 36, 45 ); + SetResistance( ResistanceType.Poison, 52, 63 ); + SetResistance( ResistanceType.Energy, 71, 83 ); + + SetSkill( SkillName.Wrestling, 101.5, 118.2 ); + SetSkill( SkillName.Tactics, 101.7, 108.2 ); + SetSkill( SkillName.MagicResist, 76.4, 89.9 ); + SetSkill( SkillName.Anatomy, 56.4, 59.7 ); + + Tamable = true; + ControlSlots = 4; + MinTameSkill = 101.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosUltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + public override bool CanFly { get { return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + public override int Meat{ get{ return 5; } } + public override int Hides{ get{ return 10; } } + public override bool CanBreath{ get{ return true; } } + public override bool CanAngerOnTame{ get { return true; } } + public override bool StatLossAfterTame{ get{ return true; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public Reptalon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Painted Caves/Grobu.cs b/Scripts/Mobiles/Monsters/ML/Painted Caves/Grobu.cs new file mode 100644 index 0000000..ea29e5a --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Painted Caves/Grobu.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Grobu corpse" )] + public class Grobu : BlackBear + { + [Constructable] + public Grobu() + { + IsParagon = true; + + Name = "Grobu"; + Hue = 0x455; + + AI = AIType.AI_Melee; + FightMode = FightMode.Closest; + + SetStr( 192, 210 ); + SetDex( 132, 150 ); + SetInt( 50, 52 ); + + SetHits( 1235, 1299 ); + SetStam( 132, 150 ); + SetMana( 9 ); + + SetDamage( 15, 18 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 45 ); + SetResistance( ResistanceType.Fire, 20, 40 ); + SetResistance( ResistanceType.Cold, 32, 35 ); + SetResistance( ResistanceType.Poison, 25, 30 ); + SetResistance( ResistanceType.Energy, 22, 34 ); + + SetSkill( SkillName.Wrestling, 96.4, 119.0 ); + SetSkill( SkillName.Tactics, 96.2, 116.5 ); + SetSkill( SkillName.MagicResist, 66.2, 83.7 ); + + Fame = 1000; + Karma = 1000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new GrobusFur() ); + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public Grobu( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Painted Caves/Lurg.cs b/Scripts/Mobiles/Monsters/ML/Painted Caves/Lurg.cs new file mode 100644 index 0000000..fcf2e05 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Painted Caves/Lurg.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Lurg corpse" )] + public class Lurg : Troglodyte + { + [Constructable] + public Lurg() + { + IsParagon = true; + + Name = "Lurg"; + Hue = 0x455; + + SetStr( 584, 625 ); + SetDex( 163, 176 ); + SetInt( 90, 106 ); + + SetHits( 3034, 3189 ); + SetStam( 163, 176 ); + SetMana( 90, 106 ); + + SetDamage( 16, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 53 ); + SetResistance( ResistanceType.Fire, 45, 47 ); + SetResistance( ResistanceType.Cold, 56, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 41, 56 ); + + SetSkill( SkillName.Wrestling, 122.7, 130.5 ); + SetSkill( SkillName.Tactics, 109.3, 118.5 ); + SetSkill( SkillName.MagicResist, 72.9, 87.6 ); + SetSkill( SkillName.Anatomy, 110.5, 124.0 ); + SetSkill( SkillName.Healing, 84.1, 105.0 ); + + Fame = 10000; + Karma = -10000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.CrushingBlow; + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 4; } } + + public Lurg( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs b/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs new file mode 100644 index 0000000..1f5076d --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Palace of Paroxysmus/Putrefier.cs @@ -0,0 +1,94 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Putrefier corpse" )] + public class Putrefier : Balron + { + [Constructable] + public Putrefier() + { + IsParagon = true; + + Name = "Putrefier"; + Hue = 63; + + SetStr( 1057, 1400 ); + SetDex( 232, 560 ); + SetInt( 201, 440 ); + + SetHits( 3010, 4092 ); + + SetDamage( 27, 34 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 0 ); + SetDamageType( ResistanceType.Poison, 50 ); + SetDamageType( ResistanceType.Energy, 0 ); + + SetResistance( ResistanceType.Physical, 65, 80 ); + SetResistance( ResistanceType.Fire, 65, 80 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Wrestling, 111.2, 128.0 ); + SetSkill( SkillName.Tactics, 115.2, 125.2 ); + SetSkill( SkillName.MagicResist, 143.4, 170.0 ); + SetSkill( SkillName.Anatomy, 44.6, 67.0 ); + SetSkill( SkillName.Magery, 117.6, 118.8 ); + SetSkill( SkillName.EvalInt, 113.0, 128.8 ); + SetSkill( SkillName.Meditation, 41.4, 85.0 ); + SetSkill( SkillName.Poisoning, 45.0, 50.0 ); + + Fame = 24000; + Karma = -24000; + + PackScroll( 4, 7 ); + PackScroll( 4, 7 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + c.DropItem( new SpleenOfThePutrefier() ); + + if ( Utility.RandomDouble() < 0.6 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } // Becomes Lethal with Paragon bonus + public override int TreasureMapLevel{ get{ return 5; } } + + public Putrefier( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs new file mode 100644 index 0000000..db8f2da --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/CorporealBrume.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a corporeal brume corpse" )] + public class CorporealBrume : BaseCreature + { + [Constructable] + public CorporealBrume() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a corporeal brume"; + Body = 0x104; // TODO: Verify + BaseSoundID = 0x56B; + + SetStr( 400, 450 ); + SetDex( 100, 150 ); + SetInt( 50, 60 ); + + SetHits( 1150, 1250 ); + + SetDamage( 21, 25 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 100 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Wrestling, 110.0, 115.0 ); + SetSkill( SkillName.Tactics, 110.0, 115.0 ); + SetSkill( SkillName.MagicResist, 80.0, 95.0 ); + SetSkill( SkillName.Anatomy, 100.0, 110.0 ); + + Fame = 12000; + Karma = -12000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + // TODO: Verify area attack specifics + public override bool HasAura { get { return ( Combatant != null ); } } + public override TimeSpan AuraInterval { get { return TimeSpan.FromSeconds( 20 ); } } + public override int AuraRange { get { return 10; } } + + public override int AuraBaseDamage { get { return Utility.RandomMinMax( 25, 35 ); } } + public override int AuraFireDamage { get { return 0; } } + public override int AuraColdDamage { get { return 100; } } + + public override void AuraEffect( Mobile m ) + { + m.FixedParticles( 0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head ); + m.PlaySound( 0x213 ); + } + + public CorporealBrume( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs new file mode 100644 index 0000000..aa068c7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalDaemon.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a crystal daemon corpse" )] + public class CrystalDaemon : BaseCreature + { + [Constructable] + public CrystalDaemon() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a crystal daemon"; + Body = 0x310; + Hue = 0x3E8; + BaseSoundID = 0x47D; + + SetStr( 140, 200 ); + SetDex( 120, 150 ); + SetInt( 800, 850 ); + + SetHits( 200, 220 ); + + SetDamage( 16, 20 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 40 ); + SetDamageType( ResistanceType.Energy, 60 ); + + SetResistance( ResistanceType.Physical, 20, 40 ); + SetResistance( ResistanceType.Fire, 0, 20 ); + SetResistance( ResistanceType.Cold, 60, 80 ); + SetResistance( ResistanceType.Poison, 20, 40 ); + SetResistance( ResistanceType.Energy, 65, 75 ); + + SetSkill( SkillName.Wrestling, 60.0, 80.0 ); + SetSkill( SkillName.Tactics, 70.0, 80.0 ); + SetSkill( SkillName.MagicResist, 100.0, 110.0 ); + SetSkill( SkillName.Magery, 120.0, 130.0 ); + SetSkill( SkillName.EvalInt, 100.0, 110.0 ); + SetSkill( SkillName.Meditation, 100.0, 110.0 ); + + Fame = 15000; + Karma = -15000; + + PackArcaneScroll( 0, 1 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.4 ) + c.DropItem( new ScatteredCrystals() ); + } + */ + + public CrystalDaemon( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs new file mode 100644 index 0000000..974562c --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalLatticeSeeker.cs @@ -0,0 +1,153 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Crystal Lattice Seeker corpse" )] + public class CrystalLatticeSeeker : BaseCreature + { + [Constructable] + public CrystalLatticeSeeker() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Crystal Lattice Seeker"; + Body = 0x7B; + Hue = 0x47E; + + SetStr( 550, 850 ); + SetDex( 190, 250 ); + SetInt( 350, 450 ); + + SetHits( 350, 550 ); + + SetDamage( 13, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 50.0, 75.0 ); + SetSkill( SkillName.EvalInt, 90.0, 100.0 ); + SetSkill( SkillName.Magery, 100.0, 100.0 ); + SetSkill( SkillName.Meditation, 90.0, 100.0 ); + SetSkill( SkillName.MagicResist, 90.0, 100.0 ); + SetSkill( SkillName.Tactics, 90.0, 100.0 ); + SetSkill( SkillName.Wrestling, 90.0, 100.0 ); + + Fame = 17000; + Karma = -17000; + + PackArcaneScroll( 0, 2 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 4 ); + // TODO: uncomment once added + //AddLoot( LootPack.Parrot ); + AddLoot( LootPack.Gems ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( Utility.RandomDouble() < 0.1 ) + Drain( defender ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( Utility.RandomDouble() < 0.1 ) + Drain( attacker ); + } + + public virtual void Drain( Mobile m ) + { + int toDrain; + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + Say( 1042156 ); // I can grant life, and I can sap it as easily. + PlaySound( 0x1E6 ); + + toDrain = Utility.RandomMinMax( 3, 6 ); + Hits += toDrain; + m.Hits -= toDrain; + break; + } + case 1: + { + Say( 1042157 ); // You'll go nowhere, unless I deem it should be so. + PlaySound( 0x1DF ); + + toDrain = Utility.RandomMinMax( 10, 25 ); + Stam += toDrain; + m.Stam -= toDrain; + break; + } + case 2: + { + Say( 1042155 ); // Your power is mine to use as I will. + PlaySound( 0x1F8 ); + + toDrain = Utility.RandomMinMax( 15, 25 ); + Mana += toDrain; + m.Mana -= toDrain; + break; + } + } + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.75 ) + c.DropItem( new CrystallineFragments() ); + + if ( Utility.RandomDouble() < 0.07 ) + c.DropItem( new PiecesOfCrystal() ); + } + */ + + public override int Feathers { get { return 100; } } + public override int TreasureMapLevel { get { return 5; } } + + public override int GetAttackSound() { return 0x2F6; } + public override int GetDeathSound() { return 0x2F7; } + public override int GetAngerSound() { return 0x2F8; } + public override int GetHurtSound() { return 0x2F9; } + public override int GetIdleSound() { return 0x2FA; } + + public CrystalLatticeSeeker( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs new file mode 100644 index 0000000..c5d9a23 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalSeaSerpent.cs @@ -0,0 +1,71 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a crystal sea serpent corpse" )] + public class CrystalSeaSerpent : SeaSerpent + { + [Constructable] + public CrystalSeaSerpent() + { + Name = "a crystal sea serpent"; + Hue = 0x47E; + + SetStr( 250, 450 ); + SetDex( 100, 150 ); + SetInt( 90, 190 ); + + SetHits( 230, 330 ); + + SetDamage( 10, 18 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Cold, 45 ); + SetDamageType( ResistanceType.Energy, 45 ); + + SetResistance( ResistanceType.Physical, 50, 70 ); + SetResistance( ResistanceType.Fire, 0 ); + SetResistance( ResistanceType.Cold, 70, 90 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 60, 80 ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.05 ) + c.DropItem( new CrushedCrystals() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new IcyHeart() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new LuckyDagger() ); + } + */ + + public CrystalSeaSerpent( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs new file mode 100644 index 0000000..b5380f0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalVortex.cs @@ -0,0 +1,91 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a crystal vortex corpse" )] + public class CrystalVortex : BaseCreature + { + [Constructable] + public CrystalVortex() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a crystal vortex"; + Body = 0xD; + Hue = 0x2B2; + BaseSoundID = 0x107; + + SetStr( 800, 900 ); + SetDex( 500, 600 ); + SetInt( 200 ); + + SetHits( 350, 400 ); + SetMana( 0 ); + + SetDamage( 15, 20 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 60, 80 ); + SetResistance( ResistanceType.Fire, 0, 10 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 60, 90 ); + + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + + Fame = 17000; + Karma = -17000; + + PackArcaneScroll( 0, 2 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + // TODO: uncomment once added + //AddLoot( LootPack.Parrot ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.75 ) + c.DropItem( new CrystallineFragments() ); + + if ( Utility.RandomDouble() < 0.06 ) + c.DropItem( new JaggedCrystals() ); + } + */ + + public override int GetAngerSound() { return 0x15; } + public override int GetAttackSound() { return 0x28; } + + public CrystalVortex( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs new file mode 100644 index 0000000..edfd536 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/CrystalWisp.cs @@ -0,0 +1,37 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class CrystalWisp : Wisp + { + [Constructable] + public CrystalWisp() + { + Name = "a crystal wisp"; + Hue = 0x482; + + PackArcaneScroll( 0, 1 ); + } + + public CrystalWisp( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs new file mode 100644 index 0000000..c23a075 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/MantraEffervescence.cs @@ -0,0 +1,71 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a mantra effervescence corpse" )] + public class MantraEffervescence : BaseCreature + { + [Constructable] + public MantraEffervescence() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a mantra effervescence"; + Body = 0x111; + BaseSoundID = 0x56E; + + SetStr( 130, 150 ); + SetDex( 120, 130 ); + SetInt( 150, 230 ); + + SetHits( 150, 250 ); + + SetDamage( 21, 25 ); + + SetDamageType( ResistanceType.Physical, 30 ); + SetDamageType( ResistanceType.Energy, 70 ); + + SetResistance( ResistanceType.Physical, 60, 65 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 100 ); + + SetSkill( SkillName.Wrestling, 80.0, 85.0 ); + SetSkill( SkillName.Tactics, 80.0, 85.0 ); + SetSkill( SkillName.MagicResist, 105.0, 115.0 ); + SetSkill( SkillName.Magery, 90.0, 110.0 ); + SetSkill( SkillName.EvalInt, 80.0, 90.0 ); + SetSkill( SkillName.Meditation, 90.0, 100.0 ); + + Fame = 6500; + Karma = -6500; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + public MantraEffervescence( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/Protector.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/Protector.cs new file mode 100644 index 0000000..ad29b38 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/Protector.cs @@ -0,0 +1,108 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a human corpse" )] + public class Protector : BaseCreature + { + [Constructable] + public Protector() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Body = 401; + Female = true; + Hue = Race.Human.RandomSkinHue(); + HairItemID = Race.Human.RandomHair( this ); + HairHue = Race.Human.RandomHairHue(); + + Name = "a Protector"; + Title = "the mystic llamaherder"; + + SetStr( 700, 800 ); + SetDex( 100, 150 ); + SetInt( 50, 75 ); + + SetHits( 350, 450 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 35, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Wrestling, 70.0, 100.0 ); + SetSkill( SkillName.Tactics, 80.0, 100.0 ); + SetSkill( SkillName.MagicResist, 50.0, 70.0 ); + SetSkill( SkillName.Anatomy, 70.0, 100.0 ); + + Fame = 10000; + Karma = -10000; + + Item boots = new ThighBoots(); + boots.Movable = false; + boots.Hue = Utility.Random( 2 ); + + Item shroud = new Item( 0x204E ); + shroud.Layer = Layer.OuterTorso; + shroud.Movable = false; + shroud.Hue = Utility.Random(2); + + AddItem( boots ); + AddItem( shroud ); + } + + public override bool AlwaysMurderer { get { return true; } } + public override bool PropertyTitle { get { return false; } } + public override bool ShowFameTitle { get { return false; } } + + public Protector( Serial serial ) + : base( serial ) + { + } + + public override void GenerateLoot( bool spawning ) + { + if ( spawning ) + return; // No loot/backpack on spawn + + base.GenerateLoot( true ); + base.GenerateLoot( false ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.4 ) + c.DropItem( new ProtectorsEssence() ); + } + */ + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs b/Scripts/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs new file mode 100644 index 0000000..5cafd05 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Prism of Light/UnfrozenMummy.cs @@ -0,0 +1,90 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an unfrozen mummy corpse" )] + public class UnfrozenMummy : BaseCreature + { + [Constructable] + public UnfrozenMummy() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.4, 0.8 ) + { + Name = "an unfrozen mummy"; + Body = 0x9B; + Hue = 0x480; + BaseSoundID = 0x1D7; + + SetStr( 450, 500 ); + SetDex( 200, 250 ); + SetInt( 800, 850 ); + + SetHits( 1500 ); + + SetDamage( 16, 20 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Energy, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 60, 80 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 70, 80 ); + + SetSkill( SkillName.Wrestling, 90.0, 100.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.MagicResist, 250.0 ); + SetSkill( SkillName.Magery, 50.0, 60.0 ); + SetSkill( SkillName.EvalInt, 50.0, 60.0 ); + SetSkill( SkillName.Meditation, 80.0 ); + + Fame = 25000; + Karma = -25000; + + PackArcaneScroll( 0, 2 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + // TODO: uncomment once added + //AddLoot( LootPack.Parrot ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.6 ) + c.DropItem( new BrokenCrystals() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public UnfrozenMummy( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs b/Scripts/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs new file mode 100644 index 0000000..871f496 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Sanctuary/Chiikkaha.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a Chiikkaha the Toothed corpse" )] + public class Chiikkaha : RatmanMage + { + [Constructable] + public Chiikkaha() + { + Name = "Chiikkaha the Toothed"; + + SetStr( 450, 476 ); + SetDex( 157, 179 ); + SetInt( 251, 275 ); + + SetHits( 400, 425 ); + + SetDamage( 10, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 45 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 100 ); + + SetSkill( SkillName.EvalInt, 70.1, 80.0 ); + SetSkill( SkillName.Magery, 70.1, 90.0 ); + SetSkill( SkillName.MagicResist, 65.1, 96.0 ); + SetSkill( SkillName.Tactics, 50.1, 75.0 ); + SetSkill( SkillName.Wrestling, 50.1, 75.0 ); + + Fame = 7500; + Karma = -7500; + } + + public Chiikkaha( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs b/Scripts/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs new file mode 100644 index 0000000..8c0aafb --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Sanctuary/MougGuur.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a Moug-Guur corpse" )] + public class MougGuur : Ettin + { + [Constructable] + public MougGuur() + { + Name = "Moug-Guur"; + + SetStr( 556, 575 ); + SetDex( 84, 94 ); + SetInt( 59, 73 ); + + SetHits( 400, 415 ); + + SetDamage( 12, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 61, 65 ); + SetResistance( ResistanceType.Fire, 16, 19 ); + SetResistance( ResistanceType.Cold, 41, 46 ); + SetResistance( ResistanceType.Poison, 21, 24 ); + SetResistance( ResistanceType.Energy, 19, 25 ); + + SetSkill( SkillName.MagicResist, 70.2, 75.0 ); + SetSkill( SkillName.Tactics, 80.8, 81.7 ); + SetSkill( SkillName.Wrestling, 93.9, 99.4 ); + + Fame = 3000; + Karma = -3000; + } + + public MougGuur( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs b/Scripts/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs new file mode 100644 index 0000000..67e80e6 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Sanctuary/Szavetra.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Szavetra corpse" )] + public class Szavetra : Succubus + { + [Constructable] + public Szavetra() + { + Name = "Szavetra"; + + SetStr( 627, 655 ); + SetDex( 164, 193 ); + SetInt( 566, 595 ); + + SetHits( 312, 415 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 83, 90 ); + SetResistance( ResistanceType.Fire, 72, 80 ); + SetResistance( ResistanceType.Cold, 40, 49 ); + SetResistance( ResistanceType.Poison, 51, 60 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.EvalInt, 90.3, 99.8 ); + SetSkill( SkillName.Magery, 100.1, 100.6 ); // 10.1-10.6 on OSI, bug? + SetSkill( SkillName.Meditation, 90.1, 110.0 ); + SetSkill( SkillName.MagicResist, 112.2, 127.2 ); + SetSkill( SkillName.Tactics, 91.2, 92.8 ); + SetSkill( SkillName.Wrestling, 80.2, 86.4 ); + + Fame = 24000; + Karma = -24000; + } + + public Szavetra( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs b/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs new file mode 100644 index 0000000..008b632 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Special/Ilhenir.cs @@ -0,0 +1,451 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Spells; +using Server.Network; +using System.Collections.Generic; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + [CorpseName("a corpse of Ilhenir")] + public class Ilhenir : BaseChampion + { + public override ChampionSkullType SkullType { get { return ChampionSkullType.Pain; } } + + public override Type[] UniqueList { get { return new Type[] { }; } } + public override Type[] SharedList + { + get + { + return new Type[] { typeof( ANecromancerShroud ), + typeof( LieutenantOfTheBritannianRoyalGuard ), + typeof( OblivionsNeedle ), + typeof( TheRobeOfBritanniaAri ) }; + } + } + public override Type[] DecorativeList { get { return new Type[] { typeof(MonsterStatuette) }; } } + + public override MonsterStatuetteType[] StatueTypes + { + get + { + return new MonsterStatuetteType[] { MonsterStatuetteType.PlagueBeast, + MonsterStatuetteType.RedDeath }; + } + } + + [Constructable] + public Ilhenir() + : base(AIType.AI_Mage) + { + Name = "Ilhenir"; + Title = "the Stained"; + Body = 0x103; + + BaseSoundID = 589; + + SetStr(1105, 1350); + SetDex(82, 160); + SetInt(505, 750); + + SetHits(9000); + + SetDamage(21, 28); + + SetDamageType(ResistanceType.Physical, 60); + SetDamageType(ResistanceType.Fire, 20); + SetDamageType(ResistanceType.Poison, 20); + + SetResistance(ResistanceType.Physical, 55, 65); + SetResistance(ResistanceType.Fire, 50, 60); + SetResistance(ResistanceType.Cold, 55, 65); + SetResistance(ResistanceType.Poison, 70, 90); + SetResistance(ResistanceType.Energy, 65, 75); + + SetSkill(SkillName.EvalInt, 100); + SetSkill(SkillName.Magery, 100); + SetSkill(SkillName.Meditation, 0); + SetSkill(SkillName.Poisoning, 5.4); + SetSkill(SkillName.Anatomy, 117.5); + SetSkill(SkillName.MagicResist, 120.0); + SetSkill(SkillName.Tactics, 119.9); + SetSkill(SkillName.Wrestling, 119.9); + + Fame = 50000; + Karma = -50000; + + VirtualArmor = 44; + + if (Core.ML) + { + PackResources(8); + PackTalismans(5); + } + } + + public virtual void PackResources(int amount) + { + for (int i = 0; i < amount; i++) + switch (Utility.Random(6)) + { + case 0: PackItem(new Blight()); break; + case 1: PackItem(new Scourge()); break; + case 2: PackItem(new Taint()); break; + case 3: PackItem(new Putrefication()); break; + case 4: PackItem(new Corruption()); break; + case 5: PackItem(new Muculent()); break; + } + } + + public virtual void PackItems(Item item, int amount) + { + for (int i = 0; i < amount; i++) + PackItem(item); + } + + public virtual void PackTalismans(int amount) + { + int count = Utility.Random(amount); + + for (int i = 0; i < count; i++) + PackItem(new RandomTalisman()); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.FilthyRich, 8); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Core.ML) + { + c.DropItem(new GrizzledBones()); + + // TODO: Parrots + /*if ( Utility.RandomDouble() < 0.6 ) + c.DropItem( new ParrotItem() ); */ + + if (Utility.RandomDouble() < 0.05) + c.DropItem(new GrizzledMareStatuette()); + + if (Utility.RandomDouble() < 0.025) + c.DropItem(new CrimsonCincture()); + + // TODO: Armor sets + /*if ( Utility.RandomDouble() < 0.05 ) + { + switch ( Utility.Random(5) ) + { + case 0: c.DropItem( new GrizzleGauntlets() ); break; + case 1: c.DropItem( new GrizzleGreaves() ); break; + case 2: c.DropItem( new GrizzleHelm() ); break; + case 3: c.DropItem( new GrizzleTunic() ); break; + case 4: c.DropItem( new GrizzleVambraces() ); break; + } + }*/ + } + } + + public override bool Unprovokable { get { return true; } } + public override bool Uncalmable { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + //public override bool GivesMLMinorArtifact { get { return true; } } // TODO: Needs verification + public override int TreasureMapLevel { get { return 5; } } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + if (Utility.RandomDouble() < 0.25) + CacophonicAttack(defender); + } + + public override void OnDamage(int amount, Mobile from, bool willKill) + { + if (Utility.RandomDouble() < 0.1) + DropOoze(); + + base.OnDamage(amount, from, willKill); + } + + public override int GetAngerSound() + { + return 0x581; + } + + public override int GetIdleSound() + { + return 0x582; + } + + public override int GetAttackSound() + { + return 0x580; + } + + public override int GetHurtSound() + { + return 0x583; + } + + public override int GetDeathSound() + { + return 0x584; + } + + public Ilhenir(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private static Hashtable m_Table; + + public virtual void CacophonicAttack(Mobile to) + { + if (m_Table == null) + m_Table = new Hashtable(); + + if (to.Alive && to.Player && m_Table[to] == null) + { + to.Send(SpeedControl.WalkSpeed); + to.SendLocalizedMessage(1072069); // A cacophonic sound lambastes you, suppressing your ability to move. + to.PlaySound(0x584); + + m_Table[to] = Timer.DelayCall(TimeSpan.FromSeconds(30), new TimerStateCallback(EndCacophonic_Callback), to); + } + } + + private void EndCacophonic_Callback(object state) + { + if (state is Mobile) + CacophonicEnd((Mobile)state); + } + + public virtual void CacophonicEnd(Mobile from) + { + if (m_Table == null) + m_Table = new Hashtable(); + + m_Table[from] = null; + + from.Send(SpeedControl.Disable); + } + + public static bool UnderCacophonicAttack(Mobile from) + { + if (m_Table == null) + m_Table = new Hashtable(); + + return m_Table[from] != null; + } + + private DateTime m_NextDrop = DateTime.Now; + + public virtual void DropOoze() + { + int amount = Utility.RandomMinMax(1, 3); + bool corrosive = Utility.RandomBool(); + + for (int i = 0; i < amount; i++) + { + Item ooze = new StainedOoze(corrosive); + Point3D p = new Point3D(Location); + + for (int j = 0; j < 5; j++) + { + p = GetSpawnPosition(2); + bool found = false; + + foreach (Item item in Map.GetItemsInRange(p, 0)) + if (item is StainedOoze) + { + found = true; + break; + } + + if (!found) + break; + } + + ooze.MoveToWorld(p, Map); + } + + if (Combatant != null) + { + if (corrosive) + Combatant.SendLocalizedMessage(1072071); // A corrosive gas seeps out of your enemy's skin! + else + Combatant.SendLocalizedMessage(1072072); // A poisonous gas seeps out of your enemy's skin! + } + } + + private int RandomPoint(int mid) + { + return (mid + Utility.RandomMinMax(-2, 2)); + } + + public virtual Point3D GetSpawnPosition(int range) + { + return GetSpawnPosition(Location, Map, range); + } + + public virtual Point3D GetSpawnPosition(Point3D from, Map map, int range) + { + if (map == null) + return from; + + Point3D loc = new Point3D((RandomPoint(X)), (RandomPoint(Y)), Z); + + loc.Z = Map.GetAverageZ(loc.X, loc.Y); + + return loc; + } + } + + public class StainedOoze : Item + { + private bool m_Corrosive; + private Timer m_Timer; + private int m_Ticks; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Corrosive + { + get { return m_Corrosive; } + set { m_Corrosive = value; } + } + + [Constructable] + public StainedOoze() + : this(false) + { + } + + [Constructable] + public StainedOoze(bool corrosive) + : base(0x122A) + { + Movable = false; + Hue = 0x95; + + m_Corrosive = corrosive; + m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick); + m_Ticks = 0; + } + + public override void OnAfterDelete() + { + if (m_Timer != null) + { + m_Timer.Stop(); + m_Timer = null; + } + } + + private void OnTick() + { + List toDamage = new List(); + + foreach (Mobile m in GetMobilesInRange(0)) + { + if (m is BaseCreature) + { + BaseCreature bc = (BaseCreature)m; + + if (!bc.Controlled && !bc.Summoned) + continue; + } + else if (!m.Player) + { + continue; + } + + if (m.Alive && !m.IsDeadBondedPet && m.CanBeDamaged()) + toDamage.Add(m); + } + + for (int i = 0; i < toDamage.Count; ++i) + Damage(toDamage[i]); + + ++m_Ticks; + + if (m_Ticks >= 35) + Delete(); + else if (m_Ticks == 30) + ItemID = 0x122B; + } + + public void Damage(Mobile m) + { + if (m_Corrosive) + { + List items = m.Items; + bool damaged = false; + + for (int i = 0; i < items.Count; ++i) + { + IDurability wearable = items[i] as IDurability; + + if (wearable != null && wearable.HitPoints >= 10 && Utility.RandomDouble() < 0.25) + { + wearable.HitPoints -= (wearable.HitPoints == 10) ? Utility.Random(1, 5) : 10; + damaged = true; + } + } + + if (damaged) + { + m.LocalOverheadMessage(MessageType.Regular, 0x21, 1072070); // The infernal ooze scorches you, setting you and your equipment ablaze! + return; + } + } + + AOS.Damage(m, 40, 0, 0, 0, 100, 0); + } + + public StainedOoze(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Corrosive); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Corrosive = reader.ReadBool(); + + m_Timer = Timer.DelayCall(TimeSpan.Zero, TimeSpan.FromSeconds(1), OnTick); + m_Ticks = (ItemID == 0x122A) ? 0 : 30; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Special/Meraktus.cs b/Scripts/Mobiles/Monsters/ML/Special/Meraktus.cs new file mode 100644 index 0000000..3047b56 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Special/Meraktus.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Targeting; +using Server.Misc; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + [CorpseName("the remains of Meraktus")] + public class Meraktus : BaseChampion + { + public override ChampionSkullType SkullType { get { return ChampionSkullType.Pain; } } + + public override Type[] UniqueList { get { return new Type[] { typeof(Subdue) }; } } + public override Type[] SharedList { get { return new Type[] { }; } } + public override Type[] DecorativeList + { + get + { + return new Type[] { typeof( ArtifactLargeVase ), + typeof( ArtifactVase ), + typeof( MinotaurStatueDeed ) }; + } + } + + public override MonsterStatuetteType[] StatueTypes + { + get + { + return new MonsterStatuetteType[] { + MonsterStatuetteType.Minotaur }; + } + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + [Constructable] + public Meraktus() + : base(AIType.AI_Melee) + { + Name = "Meraktus"; + Title = "the Tormented"; + Body = 263; + BaseSoundID = 680; + Hue = 0x835; + + SetStr(1419, 1438); + SetDex(309, 413); + SetInt(129, 131); + + SetHits(4100, 4200); + + SetDamage(16, 30); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 90); + SetResistance(ResistanceType.Fire, 65, 70); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 40, 60); + SetResistance(ResistanceType.Energy, 50, 55); + + //SetSkill( SkillName.Meditation, Unknown ); + //SetSkill( SkillName.EvalInt, Unknown ); + //SetSkill( SkillName.Magery, Unknown ); + //SetSkill( SkillName.Poisoning, Unknown ); + SetSkill(SkillName.Anatomy, 0); + SetSkill(SkillName.MagicResist, 107.0, 111.3); + SetSkill(SkillName.Tactics, 107.0, 117.0); + SetSkill(SkillName.Wrestling, 100.0, 105.0); + + Fame = 70000; + Karma = -70000; + + VirtualArmor = 28; // Don't know what it should be + + if (Core.ML) + { + PackResources(8); + PackTalismans(5); + } + + Timer.DelayCall(TimeSpan.FromSeconds(1), new TimerCallback(SpawnTormented)); + } + + public virtual void PackResources(int amount) + { + for (int i = 0; i < amount; i++) + switch (Utility.Random(6)) + { + case 0: PackItem(new Blight()); break; + case 1: PackItem(new Scourge()); break; + case 2: PackItem(new Taint()); break; + case 3: PackItem(new Putrefication()); break; + case 4: PackItem(new Corruption()); break; + case 5: PackItem(new Muculent()); break; + } + } + + public virtual void PackTalismans(int amount) + { + int count = Utility.Random(amount); + + for (int i = 0; i < count; i++) + PackItem(new RandomTalisman()); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Core.ML) + { + c.DropItem(new MalletAndChisel()); + + switch (Utility.Random(3)) + { + case 0: c.DropItem(new MinotaurHedge()); break; + case 1: c.DropItem(new BonePile()); break; + case 2: c.DropItem(new LightYarn()); break; + } + + if (Utility.RandomBool()) + c.DropItem(new TormentedChains()); + + if (Utility.RandomDouble() < 0.025) + c.DropItem(new CrimsonCincture()); + } + } + + public override void GenerateLoot() + { + if (Core.ML) + { + AddLoot(LootPack.AosSuperBoss, 5); // Need to verify + } + } + + public override int GetAngerSound() + { + return 0x597; + } + + public override int GetIdleSound() + { + return 0x596; + } + + public override int GetAttackSound() + { + return 0x599; + } + + public override int GetHurtSound() + { + return 0x59a; + } + + public override int GetDeathSound() + { + return 0x59c; + } + + public override int Meat { get { return 2; } } + public override int Hides { get { return 10; } } + public override HideType HideType { get { return HideType.Regular; } } + public override Poison PoisonImmune { get { return Poison.Regular; } } + public override int TreasureMapLevel { get { return 3; } } + public override bool BardImmune { get { return true; } } + public override bool Unprovokable { get { return true; } } + public override bool Uncalmable { get { return true; } } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + if (0.2 >= Utility.RandomDouble()) + Earthquake(); + } + + public void Earthquake() + { + Map map = this.Map; + if (map == null) + return; + ArrayList targets = new ArrayList(); + foreach (Mobile m in this.GetMobilesInRange(8)) + { + if (m == this || !CanBeHarmful(m)) + continue; + if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team)) + targets.Add(m); + else if (m.Player) + targets.Add(m); + } + PlaySound(0x2F3); + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = (Mobile)targets[i]; + if (m != null && !m.Deleted && m is PlayerMobile) + { + PlayerMobile pm = m as PlayerMobile; + if (pm != null && pm.Mounted) + { + pm.Mount.Rider = null; + } + } + double damage = m.Hits * 0.6;//was .6 + if (damage < 10.0) + damage = 10.0; + else if (damage > 75.0) + damage = 75.0; + DoHarmful(m); + AOS.Damage(m, this, (int)damage, 100, 0, 0, 0, 0); + if (m.Alive && m.Body.IsHuman && !m.Mounted) + m.Animate(20, 7, 1, true, false, 0); // take hit + } + } + + public Meraktus(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + #region SpawnHelpers + public void SpawnTormented() + { + BaseCreature spawna = new TormentedMinotaur(); + spawna.MoveToWorld(Location, Map); + + BaseCreature spawnb = new TormentedMinotaur(); + spawnb.MoveToWorld(Location, Map); + + BaseCreature spawnc = new TormentedMinotaur(); + spawnc.MoveToWorld(Location, Map); + + BaseCreature spawnd = new TormentedMinotaur(); + spawnd.MoveToWorld(Location, Map); + } + #endregion + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Special/Twaulo.cs b/Scripts/Mobiles/Monsters/ML/Special/Twaulo.cs new file mode 100644 index 0000000..0759af7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Special/Twaulo.cs @@ -0,0 +1,162 @@ +using System; +using Server; +using System.Collections; +using Server.Items; +using Server.Targeting; +using System.Collections.Generic; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + [CorpseName("a corpse of Twaulo")] + public class Twaulo : BaseChampion + { + public override ChampionSkullType SkullType { get { return ChampionSkullType.Pain; } } + + public override Type[] UniqueList { get { return new Type[] { typeof(Quell) }; } } + public override Type[] SharedList { get { return new Type[] { typeof(TheMostKnowledgePerson), typeof(OblivionsNeedle) }; } } + public override Type[] DecorativeList { get { return new Type[] { typeof(Pier), typeof(MonsterStatuette) }; } } + + public override MonsterStatuetteType[] StatueTypes { get { return new MonsterStatuetteType[] { MonsterStatuetteType.DreadHorn }; } } + + [Constructable] + public Twaulo() + : base(AIType.AI_Melee) + { + Name = "Twaulo"; + Title = "of the Glade"; + Body = 101; + BaseSoundID = 679; + Hue = 0x455; + + SetStr(1751, 1950); + SetDex(251, 450); + SetInt(801, 1000); + + SetHits(7500); + + SetDamage(19, 24); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 65, 75); + SetResistance(ResistanceType.Fire, 45, 55); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 50, 60); + + SetSkill(SkillName.EvalInt, 0); // Per Stratics?!? + SetSkill(SkillName.Magery, 0); // Per Stratics?!? + SetSkill(SkillName.Meditation, 0); // Per Stratics?!? + SetSkill(SkillName.Anatomy, 95.1, 115.0); + SetSkill(SkillName.Archery, 95.1, 100.0); + SetSkill(SkillName.MagicResist, 50.3, 80.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 95.1, 100.0); + + Fame = 50000; + Karma = 50000; + + VirtualArmor = 50; + + AddItem(new Bow()); + PackItem(new Arrow(Utility.RandomMinMax(500, 700))); + } + + public override void GenerateLoot() + { + AddLoot(LootPack.UltraRich, 2); + AddLoot(LootPack.Average); + AddLoot(LootPack.Gems); + } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + + public override bool Unprovokable { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Regular; } } + public override int TreasureMapLevel { get { return 5; } } + public override int Meat { get { return 1; } } + public override int Hides { get { return 8; } } + public override HideType HideType { get { return HideType.Spined; } } + + public void SpawnPixies(Mobile target) + { + Map map = this.Map; + + if (map == null) + return; + + int newPixies = Utility.RandomMinMax(3, 6); + + for (int i = 0; i < newPixies; ++i) + { + Pixie pixie = new Pixie(); + + pixie.Team = this.Team; + pixie.FightMode = FightMode.Closest; + + bool validLocation = false; + Point3D loc = this.Location; + + for (int j = 0; !validLocation && j < 10; ++j) + { + int x = X + Utility.Random(3) - 1; + int y = Y + Utility.Random(3) - 1; + int z = map.GetAverageZ(x, y); + + if (validLocation = map.CanFit(x, y, this.Z, 16, false, false)) + loc = new Point3D(x, y, Z); + else if (validLocation = map.CanFit(x, y, z, 16, false, false)) + loc = new Point3D(x, y, z); + } + + pixie.MoveToWorld(loc, map); + pixie.Combatant = target; + } + } + + public override void AlterDamageScalarFrom(Mobile caster, ref double scalar) + { + if (0.1 >= Utility.RandomDouble()) + SpawnPixies(caster); + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + + defender.Damage(Utility.Random(20, 10), this); + defender.Stam -= Utility.Random(20, 10); + defender.Mana -= Utility.Random(20, 10); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (0.1 >= Utility.RandomDouble()) + SpawnPixies(attacker); + } + + public Twaulo(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs new file mode 100644 index 0000000..b57a62f --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Changeling.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Misc; +using Server.Spells; +using Server.Spells.Third; +using Server.Spells.Sixth; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a changeling corpse" )] + public class Changeling : BaseCreature + { + public virtual string DefaultName{ get{ return "a changeling"; } } + public virtual int DefaultHue{ get{ return 0; } } + + [Constructable] + public Changeling() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = DefaultName; + Body = 264; + Hue = DefaultHue; + + SetStr( 36, 105 ); + SetDex( 212, 262 ); + SetInt( 317, 399 ); + + SetHits( 201, 211 ); + SetStam( 212, 262 ); + SetMana( 317, 399 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 81, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 49 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 43, 50 ); + + SetSkill( SkillName.Wrestling, 10.4, 12.5 ); + SetSkill( SkillName.Tactics, 101.1, 108.3 ); + SetSkill( SkillName.MagicResist, 121.6, 132.2 ); + SetSkill( SkillName.Magery, 91.6, 99.5 ); + SetSkill( SkillName.EvalInt, 91.5, 98.8 ); + SetSkill( SkillName.Meditation, 91.7, 98.5 ); + + Fame = 15000; + Karma = -15000; + + PackScroll( 1, 7 ); + PackItem( new Arrow( 35 ) ); + PackItem( new Bolt( 25 ) ); + PackGem( 2 ); + + //PackArcaneScroll( 0, 1 ); + } + + public override bool ShowFameTitle{ get{ return false; } } + public override bool InitialInnocent{ get{ return ( m_MorphedInto != null ); } } + + public override void GenerateLoot() + { + AddLoot( LootPack.AosRich, 3 ); + } + + public override int GetAngerSound() { return 0x46E; } + public override int GetIdleSound() { return 0x470; } + public override int GetAttackSound() { return 0x46D; } + public override int GetHurtSound() { return 0x471; } + public override int GetDeathSound() { return 0x46F; } + + private Mobile m_MorphedInto; + private DateTime m_LastMorph; + private DateTime m_NextFireRing; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile MorphedInto + { + get { return m_MorphedInto; } + set + { + if ( value == this ) + value = null; + + if ( m_MorphedInto != value ) + { + Revert(); + + if ( value != null ) + { + Morph( value ); + m_LastMorph = DateTime.Now; + } + + m_MorphedInto = value; + Delta( MobileDelta.Noto ); + } + } + } + + public override void OnThink() + { + base.OnThink(); + + if ( Combatant != null ) + { + if ( m_NextFireRing <= DateTime.Now && Utility.RandomDouble() < 0.02 ) + { + FireRing(); + m_NextFireRing = DateTime.Now + TimeSpan.FromMinutes( 2 ); + } + + if ( Combatant.Player && m_MorphedInto != Combatant && Utility.RandomDouble() < 0.05 ) + MorphedInto = Combatant; + } + } + + public override bool CheckIdle() + { + bool idle = base.CheckIdle(); + + if ( idle && m_MorphedInto != null && DateTime.Now - m_LastMorph > TimeSpan.FromSeconds( 30 ) ) + MorphedInto = null; + + return idle; + } + + private void FireEffects( int itemID, int[] offsets ) + { + for ( int i = 0; i < offsets.Length; i += 2 ) + { + Point3D p = Location; + + p.X += offsets[i]; + p.Y += offsets[i + 1]; + + if ( SpellHelper.AdjustField( ref p, Map, 12, false ) ) + Effects.SendLocationEffect( p, Map, itemID, 50 ); + } + } + + private static readonly int[] m_FireNorth = new int[] + { + -1, -1, + 1, -1, + -1, 2, + 1, 2 + }; + + private static readonly int[] m_FireEast = new int[] + { + -1, 0, + 2, 0 + }; + + protected virtual void FireRing() + { + FireEffects( 0x3E27, m_FireNorth ); + FireEffects( 0x3E31, m_FireEast ); + } + + protected virtual void Morph( Mobile m ) + { + Body = m.Body; + Hue = m.Hue; + Female = m.Female; + Name = m.Name; + NameHue = m.NameHue; + Title = m.Title; + Kills = m.Kills; + HairItemID = m.HairItemID; + HairHue = m.HairHue; + FacialHairItemID = m.FacialHairItemID; + FacialHairHue = m.FacialHairHue; + + // TODO: Skills? + + foreach ( Item item in m.Items ) + { + if ( item.Layer != Layer.Backpack && item.Layer != Layer.Mount && item.Layer != Layer.Bank ) + AddItem( new ClonedItem( item ) ); // TODO: Clone weapon/armor attributes + } + + PlaySound( 0x511 ); + FixedParticles( 0x376A, 1, 14, 5045, EffectLayer.Waist ); + } + + protected virtual void Revert() + { + Body = 264; + Hue = ( IsParagon && DefaultHue == 0 ) ? Paragon.Hue : DefaultHue; + Female = false; + Name = DefaultName; + NameHue = -1; + Title = null; + Kills = 0; + HairItemID = 0; + HairHue = 0; + FacialHairItemID = 0; + FacialHairHue = 0; + + DeleteClonedItems(); + + PlaySound( 0x511 ); + FixedParticles( 0x376A, 1, 14, 5045, EffectLayer.Waist ); + } + + public void DeleteClonedItems() + { + for ( int i = Items.Count - 1; i >= 0; --i ) + { + Item item = Items[i]; + + if ( item is ClonedItem ) + item.Delete(); + } + + if ( Backpack != null ) + { + for ( int i = Backpack.Items.Count - 1; i >= 0; --i ) + { + Item item = Backpack.Items[i]; + + if ( item is ClonedItem ) + item.Delete(); + } + } + } + + public override void OnAfterDelete() + { + DeleteClonedItems(); + + base.OnAfterDelete(); + } + + public override void ClearHands() + { + } + + public Changeling( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.Write( ( m_MorphedInto != null ) ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( reader.ReadBool() ) + ValidationQueue.Add( this ); + } + + public void Validate() + { + Revert(); + } + + private class ClonedItem : Item + { + public ClonedItem( Item item ) + : base( item.ItemID ) + { + Name = item.Name; + Weight = item.Weight; + Hue = item.Hue; + Layer = item.Layer; + Movable = false; + } + + public ClonedItem( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs new file mode 100644 index 0000000..9e5bd05 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Gnaw.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Gnaw corpse" )] + public class Gnaw : DireWolf + { + [Constructable] + public Gnaw() + { + IsParagon = true; + + Name = "Gnaw"; + Hue = 0x130; + + SetStr( 151, 172 ); + SetDex( 124, 145 ); + SetInt( 60, 86 ); + + SetHits( 817, 857 ); + SetStam( 124, 145 ); + SetMana( 52, 86 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 64, 69 ); + SetResistance( ResistanceType.Fire, 53, 56 ); + SetResistance( ResistanceType.Cold, 22, 27 ); + SetResistance( ResistanceType.Poison, 27, 30 ); + SetResistance( ResistanceType.Energy, 21, 34 ); + + SetSkill( SkillName.Wrestling, 106.4, 116.5 ); + SetSkill( SkillName.Tactics, 84.1, 103.2 ); + SetSkill( SkillName.MagicResist, 96.8, 110.7 ); + + Fame = 17500; + Karma = -17500; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int Hides{ get{ return 28; } } + public override int Meat{ get{ return 4; } } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.3 ) + c.DropItem( new GnawsFang() ); + } + */ + + public Gnaw( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Guile.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Guile.cs new file mode 100644 index 0000000..bd26cca --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Guile.cs @@ -0,0 +1,90 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Guile corpse" )] + public class Guile : Changeling + { + public override string DefaultName{ get{ return "Guile"; } } + public override int DefaultHue{ get{ return 0x3F; } } + + [Constructable] + public Guile() + { + IsParagon = true; + + Hue = DefaultHue; + + SetStr( 53, 214 ); + SetDex( 243, 367 ); + SetInt( 369, 586 ); + + SetHits( 1013, 1058 ); + SetStam( 243, 367 ); + SetMana( 369, 586 ); + + SetDamage( 14, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 43, 46 ); + SetResistance( ResistanceType.Cold, 42, 44 ); + SetResistance( ResistanceType.Poison, 42, 50 ); + SetResistance( ResistanceType.Energy, 47, 50 ); + + SetSkill( SkillName.Wrestling, 12.8, 16.7 ); + SetSkill( SkillName.Tactics, 102.6, 131.0 ); + SetSkill( SkillName.MagicResist, 141.2, 161.6 ); + SetSkill( SkillName.Magery, 108.4, 120.0 ); + SetSkill( SkillName.EvalInt, 108.4, 120.0 ); + SetSkill( SkillName.Meditation, 109.2, 120.0 ); + + Fame = 21000; + Karma = -21000; + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( Utility.RandomBool() ) + { + if ( !Kappa.IsBeingDrained( defender ) && Mana > 14 ) + { + defender.SendLocalizedMessage( 1070848 ); // You feel your life force being stolen away. + Kappa.BeginLifeDrain( defender, this ); + Mana -= 15; + } + } + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public Guile( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Irk.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Irk.cs new file mode 100644 index 0000000..274da68 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Irk.cs @@ -0,0 +1,89 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an Irk corpse" )] + public class Irk : Changeling + { + public override string DefaultName{ get{ return "Irk"; } } + public override int DefaultHue{ get{ return 0x489; } } + + [Constructable] + public Irk() + { + IsParagon = true; + + Hue = DefaultHue; + + SetStr( 23, 183 ); + SetDex( 259, 360 ); + SetInt( 374, 600 ); + + SetHits( 1006, 1064 ); + SetStam( 259, 360 ); + SetMana( 374, 600 ); + + SetDamage( 14, 20 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 41, 50 ); + SetResistance( ResistanceType.Energy, 40, 49 ); + + SetSkill( SkillName.Wrestling, 120.3, 123.0 ); + SetSkill( SkillName.Tactics, 120.1, 131.8 ); + SetSkill( SkillName.MagicResist, 132.3, 165.8 ); + SetSkill( SkillName.Magery, 108.9, 119.7 ); + SetSkill( SkillName.EvalInt, 108.4, 120.0 ); + SetSkill( SkillName.Meditation, 108.9, 119.1 ); + + Fame = 21000; + Karma = -21000; + } + + // TODO: Angry fire + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.25 ) + c.DropItem( new IrksBrain() ); + + if ( Utility.RandomDouble() < 0.025 ) + c.DropItem( new PaladinGloves() ); + } + */ + + public Irk( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs new file mode 100644 index 0000000..5f73bb6 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/LadyLissith.cs @@ -0,0 +1,95 @@ +using System; +using Server.Items; +using Server.Targeting; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "a Lady Lissith corpse" )] + public class LadyLissith : GiantBlackWidow + { + [Constructable] + public LadyLissith() + { + IsParagon = true; + + Name = "Lady Lissith"; + Hue = 0x452; + + SetStr( 81, 130 ); + SetDex( 116, 152 ); + SetInt( 44, 100 ); + + SetHits( 245, 375 ); + SetStam( 116, 152 ); + SetMana( 44, 100 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 31, 39 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 71, 80 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Wrestling, 108.6, 123.0 ); + SetSkill( SkillName.Tactics, 102.7, 119.0 ); + SetSkill( SkillName.MagicResist, 78.8, 95.6 ); + SetSkill( SkillName.Anatomy, 68.6, 106.8 ); + SetSkill( SkillName.Poisoning, 96.6, 112.9 ); + + Fame = 18900; + Karma = -18900; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.025 ) + c.DropItem( new GreymistChest() ); + + if ( Utility.RandomDouble() < 0.45 ) + c.DropItem( new LissithsSilk() ); + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public LadyLissith( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs new file mode 100644 index 0000000..ba96ae1 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/LadySabrix.cs @@ -0,0 +1,100 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Lady Sabrix corpse" )] + public class LadySabrix : GiantBlackWidow + { + [Constructable] + public LadySabrix() + { + IsParagon = true; + + Name = "Lady Sabrix"; + Hue = 0x497; + + SetStr( 82, 130 ); + SetDex( 117, 146 ); + SetInt( 50, 98 ); + + SetHits( 233, 361 ); + SetStam( 117, 146 ); + SetMana( 50, 98 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 39 ); + SetResistance( ResistanceType.Poison, 70, 80 ); + SetResistance( ResistanceType.Energy, 35, 44 ); + + SetSkill( SkillName.Wrestling, 109.8, 122.8 ); + SetSkill( SkillName.Tactics, 102.8, 120.0 ); + SetSkill( SkillName.MagicResist, 79.4, 95.1 ); + SetSkill( SkillName.Anatomy, 68.8, 105.1 ); + SetSkill( SkillName.Poisoning, 97.8, 116.7 ); + + Fame = 18900; + Karma = -18900; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ArmorIgnore; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.2 ) + c.DropItem( new SabrixsEye() ); + + if ( Utility.RandomDouble() < 0.25 ) + { + switch ( Utility.Random( 2 ) ) + { + case 0: AddToBackpack( new PaladinArms() ); break; + case 1: AddToBackpack( new HunterLegs() ); break; + } + } + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public LadySabrix( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs new file mode 100644 index 0000000..fc3ad18 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Malefic.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Malefic corpse" )] + public class Malefic : DreadSpider + { + [Constructable] + public Malefic() + { + IsParagon = true; + + Name = "Malefic"; + Hue = 0x455; + + SetStr( 210, 284 ); + SetDex( 153, 197 ); + SetInt( 349, 390 ); + + SetHits( 600, 747 ); + SetStam( 153, 197 ); + SetMana( 349, 390 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Poison, 80 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 49 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 41, 48 ); + + SetSkill( SkillName.Wrestling, 96.9, 112.4 ); + SetSkill( SkillName.Tactics, 91.3, 105.4 ); + SetSkill( SkillName.MagicResist, 79.8, 95.1 ); + SetSkill( SkillName.Magery, 103.0, 118.6 ); + SetSkill( SkillName.EvalInt, 105.7, 119.6 ); + SetSkill( SkillName.Meditation, 0 ); + + Fame = 21000; + Karma = -21000; + + /* + // TODO: uncomment once added + if ( Utility.RandomDouble() < 0.1 ) + PackItem( new ParrotItem() ); + */ + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.Dismount; + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public Malefic( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Silk.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Silk.cs new file mode 100644 index 0000000..e5d0023 --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Silk.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Silk corpse" )] + public class Silk : GiantBlackWidow + { + [Constructable] + public Silk() + { + IsParagon = true; + + Name = "Silk"; + Hue = 0x47E; + + SetStr( 80, 131 ); + SetDex( 126, 156 ); + SetInt( 63, 102 ); + + SetHits( 279, 378 ); + SetStam( 126, 156 ); + SetMana( 63, 102 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 39 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 70, 76 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Wrestling, 114.1, 123.7 ); + SetSkill( SkillName.Tactics, 102.6, 118.3 ); + SetSkill( SkillName.MagicResist, 78.6, 94.8 ); + SetSkill( SkillName.Anatomy, 81.3, 105.7 ); + SetSkill( SkillName.Poisoning, 106.0, 119.2 ); + + Fame = 18900; + Karma = -18900; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public Silk( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Spite.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Spite.cs new file mode 100644 index 0000000..d0f56ae --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Spite.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Spite corpse" )] + public class Spite : Changeling + { + public override string DefaultName{ get{ return "Spite"; } } + public override int DefaultHue{ get{ return 0x21; } } + + [Constructable] + public Spite() + { + IsParagon = true; + + Hue = DefaultHue; + + SetStr( 53, 214 ); + SetDex( 243, 367 ); + SetInt( 369, 586 ); + + SetHits( 1013, 1052 ); + SetStam( 243, 367 ); + SetMana( 369, 586 ); + + SetDamage( 14, 20 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 85, 90 ); + SetResistance( ResistanceType.Fire, 41, 46 ); + SetResistance( ResistanceType.Cold, 40, 44 ); + SetResistance( ResistanceType.Poison, 42, 46 ); + SetResistance( ResistanceType.Energy, 45, 47 ); + + SetSkill( SkillName.Wrestling, 12.8, 16.7 ); + SetSkill( SkillName.Tactics, 102.6, 131.0 ); + SetSkill( SkillName.MagicResist, 141.2, 161.6 ); + SetSkill( SkillName.Magery, 108.4, 119.2 ); + SetSkill( SkillName.EvalInt, 108.4, 120.0 ); + SetSkill( SkillName.Meditation, 109.2, 120.0 ); + + Fame = 21000; + Karma = -21000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public Spite( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs new file mode 100644 index 0000000..5ca958b --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Swoop.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "a Swoop corpse" )] + public class Swoop : Eagle + { + [Constructable] + public Swoop() + { + IsParagon = true; + + Name = "Swoop"; + Hue = 0xE0; + + AI = AIType.AI_Melee; + + SetStr( 100, 150 ); + SetDex( 400, 500 ); + SetInt( 80, 90 ); + + SetHits( 1500, 2000 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 75, 90 ); + SetResistance( ResistanceType.Fire, 60, 77 ); + SetResistance( ResistanceType.Cold, 70, 85 ); + SetResistance( ResistanceType.Poison, 55, 85 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Wrestling, 120.0, 140.0 ); + SetSkill( SkillName.Tactics, 120.0, 140.0 ); + SetSkill( SkillName.MagicResist, 95.0, 105.0 ); + + Fame = 18000; + Karma = 0; + + PackReg( 4 ); + //PackArcaneScroll( 0, 1 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + // TODO: Put this attack shared with Hiryu and Lesser Hiryu in one place + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if( 0.1 > Utility.RandomDouble() ) + { + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070837 ); // The creature lands another blow in your weakened state. + } + else + defender.SendLocalizedMessage( 1070836 ); // The blow from the creature's claws has made you more susceptible to physical attacks. + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Physical, effect ); + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.AddResistanceMod( mod ); + + timer = new ExpireTimer( defender, mod, TimeSpan.FromSeconds( 5.0 ) ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + + public ExpireTimer( Mobile m, ResistanceMod mod, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod( m_Mod ); + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1070838 ); // Your resistance to physical attacks has returned. + DoExpire(); + } + } + + public override bool CanFly { get { return true; } } + public override bool GivesMLMinorArtifact{ get{ return true; } } + public override int Feathers{ get{ return 72; } } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.025 ) + { + switch ( Utility.Random( 18 ) ) + { + case 0: c.DropItem( new AssassinChest() ); break; + case 1: c.DropItem( new AssassinArms() ); break; + case 2: c.DropItem( new DeathChest() ); break; + case 3: c.DropItem( new MyrmidonArms() ); break; + case 4: c.DropItem( new MyrmidonLegs() ); break; + case 5: c.DropItem( new MyrmidonGorget() ); break; + case 6: c.DropItem( new LeafweaveGloves() ); break; + case 7: c.DropItem( new LeafweaveLegs() ); break; + case 8: c.DropItem( new LeafweavePauldrons() ); break; + case 9: c.DropItem( new PaladinGloves() ); break; + case 10: c.DropItem( new PaladinGorget() ); break; + case 11: c.DropItem( new PaladinArms() ); break; + case 12: c.DropItem( new HunterArms() ); break; + case 13: c.DropItem( new HunterGloves() ); break; + case 14: c.DropItem( new HunterLegs() ); break; + case 15: c.DropItem( new HunterChest() ); break; + case 16: c.DropItem( new GreymistArms() ); break; + case 17: c.DropItem( new GreymistGloves() ); break; + } + } + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public Swoop( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs new file mode 100644 index 0000000..a72af8b --- /dev/null +++ b/Scripts/Mobiles/Monsters/ML/Twisted Weald/Virulent.cs @@ -0,0 +1,99 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a Virulent corpse" )] + public class Virulent : DreadSpider + { + [Constructable] + public Virulent() + { + IsParagon = true; + + Name = "Virulent"; + Hue = 0x8FD; + + SetStr( 207, 252 ); + SetDex( 156, 194 ); + SetInt( 346, 398 ); + + SetHits( 616, 740 ); + SetStam( 156, 194 ); + SetMana( 346, 398 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Poison, 80 ); + + SetResistance( ResistanceType.Physical, 60, 68 ); + SetResistance( ResistanceType.Fire, 40, 49 ); + SetResistance( ResistanceType.Cold, 41, 50 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 40, 49 ); + + SetSkill( SkillName.Wrestling, 92.8, 111.7 ); + SetSkill( SkillName.Tactics, 91.6, 107.4 ); + SetSkill( SkillName.MagicResist, 78.1, 93.3 ); + SetSkill( SkillName.Poisoning, 120.0 ); + SetSkill( SkillName.Magery, 104.2, 119.8 ); + SetSkill( SkillName.EvalInt, 102.8, 117.8 ); + + Fame = 21000; + Karma = -21000; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.MortalStrike; + } + + /* + // TODO: uncomment once added + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( Utility.RandomDouble() < 0.025 ) + { + switch ( Utility.Random( 2 ) ) + { + case 0: c.DropItem( new HunterLegs() ); break; + case 1: c.DropItem( new MalekisHonor() ); break; + } + } + + if ( Utility.RandomDouble() < 0.1 ) + c.DropItem( new ParrotItem() ); + } + */ + + public override bool GivesMLMinorArtifact{ get{ return true; } } + + public Virulent( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Mammal/Melee/HellHound.cs b/Scripts/Mobiles/Monsters/Mammal/Melee/HellHound.cs new file mode 100644 index 0000000..71df567 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Mammal/Melee/HellHound.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a hell hound corpse" )] + public class HellHound : BaseCreature + { + [Constructable] + public HellHound() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a hell hound"; + Body = 98; + BaseSoundID = 229; + + SetStr( 102, 150 ); + SetDex( 81, 105 ); + SetInt( 36, 60 ); + + SetHits( 66, 125 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 80 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + Fame = 3400; + Karma = -3400; + + VirtualArmor = 30; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 85.5; + + PackItem( new SulfurousAsh( 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + } + + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Canine; } } + + public HellHound( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs b/Scripts/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs new file mode 100644 index 0000000..fe7fa3f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Mammal/Melee/VorpalBunny.cs @@ -0,0 +1,145 @@ +using System; +using Server.Mobiles; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a vorpal bunny corpse" )] + public class VorpalBunny : BaseCreature + { + [Constructable] + public VorpalBunny() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a vorpal bunny"; + Body = 205; + Hue = 0x480; + + SetStr( 15 ); + SetDex( 2000 ); + SetInt( 1000 ); + + SetHits( 2000 ); + SetStam( 500 ); + SetMana( 0 ); + + SetDamage( 1 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetSkill( SkillName.MagicResist, 200.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 1000; + Karma = 0; + + VirtualArmor = 4; + + int carrots = Utility.RandomMinMax( 5, 10 ); + PackItem( new Carrot( carrots ) ); + + if ( Utility.Random( 5 ) == 0 ) + PackItem( new BrightlyColoredEggs() ); + + PackStatue(); + + DelayBeginTunnel(); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich, 2 ); + } + + public class BunnyHole : Item + { + public BunnyHole() : base( 0x913 ) + { + Movable = false; + Hue = 1; + Name = "a mysterious rabbit hole"; + + Timer.DelayCall( TimeSpan.FromSeconds( 40.0 ), new TimerCallback( Delete ) ); + } + + public BunnyHole( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + } + + public virtual void DelayBeginTunnel() + { + Timer.DelayCall( TimeSpan.FromMinutes( 3.0 ), new TimerCallback( BeginTunnel ) ); + } + + public virtual void BeginTunnel() + { + if ( Deleted ) + return; + + new BunnyHole().MoveToWorld( Location, Map ); + + Frozen = true; + Say( "* The bunny begins to dig a tunnel back to its underground lair *" ); + PlaySound( 0x247 ); + + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerCallback( Delete ) ); + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 1; } } + public override bool BardImmune{ get{ return !Core.AOS; } } + + public VorpalBunny( Serial serial ) : base( serial ) + { + } + + public override int GetAttackSound() + { + return 0xC9; + } + + public override int GetHurtSound() + { + return 0xCA; + } + + public override int GetDeathSound() + { + return 0xCB; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize(writer); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + DelayBeginTunnel(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Magic/DarkWisp.cs b/Scripts/Mobiles/Monsters/Misc/Magic/DarkWisp.cs new file mode 100644 index 0000000..a3dade2 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Magic/DarkWisp.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Factions; + +namespace Server.Mobiles +{ + [CorpseName( "a wisp corpse" )] + public class DarkWisp : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Wisp; } } + + public override Ethics.Ethic EthicAllegiance { get { return Ethics.Ethic.Evil; } } + + public override TimeSpan ReacquireDelay { get { return TimeSpan.FromSeconds( 1.0 ); } } + + [Constructable] + public DarkWisp() : base( AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "a wisp"; + Body = 165; + BaseSoundID = 466; + + SetStr( 196, 225 ); + SetDex( 196, 225 ); + SetInt( 196, 225 ); + + SetHits( 118, 135 ); + + SetDamage( 17, 18 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 40 ); + SetResistance( ResistanceType.Cold, 10, 30 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 50, 70 ); + + SetSkill( SkillName.EvalInt, 80.0 ); + SetSkill( SkillName.Magery, 80.0 ); + SetSkill( SkillName.MagicResist, 80.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 40; + + AddItem( new LightSource() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public DarkWisp( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs b/Scripts/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs new file mode 100644 index 0000000..ac84cfe --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Magic/EtherealWarrior.cs @@ -0,0 +1,148 @@ +using System; +using Server; +using Server.Items; +using Server.Gumps; + +namespace Server.Mobiles +{ + [CorpseName( "an ethereal warrior corpse" )] + public class EtherealWarrior : BaseCreature + { + public override bool InitialInnocent{ get{ return true; } } + + [Constructable] + public EtherealWarrior() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "ethereal warrior" ); + Body = 123; + + SetStr( 586, 785 ); + SetDex( 177, 255 ); + SetInt( 351, 450 ); + + SetHits( 352, 471 ); + + SetDamage( 13, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Anatomy, 50.1, 75.0 ); + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 99.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 7000; + Karma = 7000; + + VirtualArmor = 120; + } + + public override int TreasureMapLevel{ get{ return Core.AOS ? 5 : 0; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 3 ); + AddLoot( LootPack.Gems ); + } + + private DateTime m_NextResurrect; + private static TimeSpan ResurrectDelay = TimeSpan.FromSeconds(2.0); + + public override void OnMovement(Mobile from, Point3D oldLocation) + { + if (!from.Alive && (from is PlayerMobile)) + { + if (!from.Frozen && (DateTime.Now >= m_NextResurrect) && InRange(from, 4) && !InRange(oldLocation, 4) && InLOS(from)) + { + m_NextResurrect = DateTime.Now + ResurrectDelay; + if (!from.Criminal && (from.Kills < 5) && (from.Karma > 0)) + { + if (from.Map != null && from.Map.CanFit(from.Location, 16, false, false)) + { + Direction = GetDirectionTo(from); + from.PlaySound(0x1F2); + from.FixedEffect(0x376A, 10, 16); + from.CloseGump(typeof(ResurrectGump)); + from.SendGump(new ResurrectGump(from, ResurrectMessage.Healer)); + } + } + } + } + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override int Feathers{ get{ return 100; } } + + public override int GetAngerSound() + { + return 0x2F8; + } + + public override int GetIdleSound() + { + return 0x2F8; + } + + public override int GetAttackSound() + { + return Utility.Random( 0x2F5, 2 ); + } + + public override int GetHurtSound() + { + return 0x2F9; + } + + public override int GetDeathSound() + { + return 0x2F7; + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + defender.Damage( Utility.Random( 10, 10 ), this ); + defender.Stam -= Utility.Random( 10, 10 ); + defender.Mana -= Utility.Random( 10, 10 ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + attacker.Damage( Utility.Random( 10, 10 ), this ); + attacker.Stam -= Utility.Random( 10, 10 ); + attacker.Mana -= Utility.Random( 10, 10 ); + } + + public EtherealWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Magic/Pixie.cs b/Scripts/Mobiles/Monsters/Misc/Magic/Pixie.cs new file mode 100644 index 0000000..2585874 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Magic/Pixie.cs @@ -0,0 +1,110 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a pixie corpse" )] + public class Pixie : BaseCreature + { + public override bool InitialInnocent{ get{ return true; } } + + [Constructable] + public Pixie() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "pixie" ); + Body = 128; + BaseSoundID = 0x467; + + SetStr( 21, 30 ); + SetDex( 301, 400 ); + SetInt( 201, 250 ); + + SetHits( 13, 18 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 10.1, 20.0 ); + SetSkill( SkillName.Wrestling, 10.1, 12.5 ); + + Fame = 7000; + Karma = 7000; + + VirtualArmor = 100; + if ( 0.02 > Utility.RandomDouble() ) + PackStatue(); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.Gems, 2 ); + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (Utility.RandomDouble() < 0.35) + c.DropItem(new PixieLeg()); + } + + public override HideType HideType{ get{ return HideType.Spined; } } + public override int Hides{ get{ return 5; } } + public override int Meat{ get{ return 1; } } + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + if (Utility.RandomDouble() < 0.3) + { + if (!from.CheckSkill(SkillName.Forensics, 30, 80)) + from.SendMessage("Vous auriez gagn� � mieux appr�hender les cadavres"); + else + { + corpse.DropItem(new FeyRelic()); + from.SendMessage("Vous arrachez une aile � la f�e"); + } + } + base.OnCarve(from, corpse, with); + } + + public Pixie( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs b/Scripts/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs new file mode 100644 index 0000000..c6aaf65 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Magic/ShadowWisp.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a wisp corpse" )] + public class ShadowWisp : BaseCreature + { + [Constructable] + public ShadowWisp() : base( AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.3, 0.6 ) + { + Name = "a shadow wisp"; + Body = 165; + BaseSoundID = 466; + + SetStr( 16, 40 ); + SetDex( 16, 45 ); + SetInt( 11, 25 ); + + SetHits( 10, 24 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 15, 20 ); + + SetSkill( SkillName.EvalInt, 40.0 ); + SetSkill( SkillName.Magery, 50.0 ); + SetSkill( SkillName.Meditation, 40.0 ); + SetSkill( SkillName.MagicResist, 10.0 ); + SetSkill( SkillName.Tactics, 0.1, 15.0 ); + SetSkill( SkillName.Wrestling, 25.1, 40.0 ); + + Fame = 500; + + VirtualArmor = 18; + + AddItem( new LightSource() ); + + switch ( Utility.Random( 10 )) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: PackItem( new RibCage() ); break; + case 6: PackItem( new BonePile() ); break; + case 7: PackItem( new BonePile() ); break; + case 8: PackItem( new BonePile() ); break; + case 9: PackItem( new BonePile() ); break; + } + } + + public ShadowWisp( Serial serial ) : base( serial ) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Magic/Wisp.cs b/Scripts/Mobiles/Monsters/Misc/Magic/Wisp.cs new file mode 100644 index 0000000..00a9d78 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Magic/Wisp.cs @@ -0,0 +1,109 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Factions; +using Server.Spells; +using Server.Spells.Necromancy; + +namespace Server.Mobiles +{ + [CorpseName( "a wisp corpse" )] + public class Wisp : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Wisp; } } + + public override Faction FactionAllegiance{ get{ return CouncilOfMages.Instance; } } + public override Ethics.Ethic EthicAllegiance { get { return Ethics.Ethic.Hero; } } + + public override TimeSpan ReacquireDelay { get { return TimeSpan.FromSeconds( 1.0 ); } } + + [Constructable] + public Wisp() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a wisp"; + Body = 58; + BaseSoundID = 466; + + SetStr( 196, 225 ); + SetDex( 196, 225 ); + SetInt( 196, 225 ); + + SetHits( 118, 135 ); + + SetDamage( 17, 18 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 20, 40 ); + SetResistance( ResistanceType.Cold, 10, 30 ); + SetResistance( ResistanceType.Poison, 5, 10 ); + SetResistance( ResistanceType.Energy, 50, 70 ); + + SetSkill( SkillName.EvalInt, 80.0 ); + SetSkill( SkillName.Magery, 80.0 ); + SetSkill( SkillName.MagicResist, 80.0 ); + SetSkill( SkillName.Tactics, 80.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 4000; + Karma = 5000; + + VirtualArmor = 40; + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(3) ); + + AddItem( new LightSource() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + } + + + public override void OnCarve(Mobile from, Corpse corpse, Item with) + { + if (corpse.Carved) + base.OnCarve(from, corpse, with); + + TransformContext context = TransformationSpellHelper.GetContext(from); + if (context != null && context.Spell is NecromancerSpell && Utility.RandomDouble() < 0.3) + { + corpse.DropItem(new GlowingOre(Utility.Random(2,3))); + from.SendMessage("Le Wisp se fige � votre toucher"); + } + else if (Utility.RandomDouble() < .1) + { + corpse.DropItem(new GlowingOre()); + from.SendMessage("Seulement une partie du wisp se fige. Vous ne deviez pas �tre assez effrayant..."); + } + base.OnCarve(from, corpse, with); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public Wisp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs b/Scripts/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs new file mode 100644 index 0000000..435c88d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/BladeSpirits.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a blade spirit corpse" )] + public class BladeSpirits : BaseCreature + { + public override bool DeleteCorpseOnDeath { get { return Core.AOS; } } + public override bool IsHouseSummonable { get { return true; } } + + public override double DispelDifficulty { get { return 0.0; } } + public override double DispelFocus { get { return 20.0; } } + + public override double GetFightModeRanking( Mobile m, FightMode acqType, bool bPlayerOnly ) + { + return ( m.Str + m.Skills[SkillName.Tactics].Value ) / Math.Max( GetDistanceToSqrt( m ), 1.0 ); + } + + [Constructable] + public BladeSpirits() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.3, 0.6 ) + { + Name = "a blade spirit"; + Body = 574; + + SetStr( 150 ); + SetDex( 150 ); + SetInt( 100 ); + + // Scriptiz : si summoned on descend la dex pour qu'il tape moins vite + if (Summoned) + SetDex(100); + + SetHits( ( Core.SE ) ? 160 : 80 ); + SetStam( 250 ); + SetMana( 0 ); + + SetDamage( 10, 14 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 70.0 ); + SetSkill( SkillName.Tactics, 90.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + Fame = 0; + Karma = 0; + + VirtualArmor = 40; + ControlSlots = ( Core.SE ) ? 2 : 1; + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public override int GetAngerSound() + { + return 0x23A; + } + + public override int GetAttackSound() + { + return 0x3B8; + } + + public override int GetHurtSound() + { + return 0x23A; + } + + public override void OnThink() + { + if ( Core.SE && Summoned ) + { + ArrayList spirtsOrVortexes = new ArrayList(); + + foreach ( Mobile m in GetMobilesInRange( 5 ) ) + { + if ( m is EnergyVortex || m is BladeSpirits ) + { + if ( ( (BaseCreature) m ).Summoned ) + spirtsOrVortexes.Add( m ); + } + } + + while ( spirtsOrVortexes.Count > 6 ) + { + int index = Utility.Random( spirtsOrVortexes.Count ); + Dispel( ( (Mobile) spirtsOrVortexes[index] ) ); + spirtsOrVortexes.RemoveAt( index ); + } + } + + base.OnThink(); + } + + public BladeSpirits( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/Centaur.cs b/Scripts/Mobiles/Monsters/Misc/Melee/Centaur.cs new file mode 100644 index 0000000..a903518 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/Centaur.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a centaur corpse" )] + public class Centaur : BaseCreature + { + [Constructable] + public Centaur() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "centaur" ); + Body = 101; + BaseSoundID = 679; + + SetStr( 202, 300 ); + SetDex( 104, 260 ); + SetInt( 91, 100 ); + + SetHits( 130, 172 ); + + SetDamage( 13, 24 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 45, 55 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.Anatomy, 95.1, 115.0 ); + SetSkill( SkillName.Archery, 95.1, 100.0 ); + SetSkill( SkillName.MagicResist, 50.3, 80.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 95.1, 100.0 ); + + Fame = 6500; + Karma = 0; + + VirtualArmor = 50; + AddItem( new Bow() ); + PackItem( new Arrow( Utility.RandomMinMax( 80, 90 ) ) ); // OSI it is different: in a sub backpack, this is probably just a limitation of their engine + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 8; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public Centaur( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 678 ) + BaseSoundID = 679; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs b/Scripts/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs new file mode 100644 index 0000000..6849ec3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/EnergyVortex.cs @@ -0,0 +1,134 @@ +using System; +using Server; +using Server.Items; +using System.Collections; + +namespace Server.Mobiles +{ + [CorpseName( "an energy vortex corpse" )] + public class EnergyVortex : BaseCreature + { + public override bool DeleteCorpseOnDeath { get { return Summoned; } } + public override bool AlwaysMurderer{ get{ return true; } } // Or Llama vortices will appear gray. + + public override double DispelDifficulty { get { return 80.0; } } + public override double DispelFocus { get { return 20.0; } } + + public override double GetFightModeRanking( Mobile m, FightMode acqType, bool bPlayerOnly ) + { + return ( m.Int + m.Skills[SkillName.Magery].Value ) / Math.Max( GetDistanceToSqrt( m ), 1.0 ); + } + + [Constructable] + public EnergyVortex() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an energy vortex"; + + //if( Core.SE && 0.002 > Utility.RandomDouble() ) // Per OSI FoF, it's a 1/500 chance. + if (Core.SE && 0.01 > Utility.RandomDouble()) // Scriptiz : 1/100 chance + { + // Llama vortex! + Name = "a powerful pink llama"; + Body = 0xDC; + Hue = 0x76; + } + else + { + Body = 164; + } + + SetStr( 200 ); + SetDex( 200 ); + SetInt( 100 ); + + SetHits( ( Core.SE ) ? 140 : 70 ); + SetStam( 250 ); + SetMana( 0 ); + + SetDamage( 14, 17 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Energy, 100 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 90, 100 ); + + SetSkill( SkillName.MagicResist, 99.9 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 120.0 ); + + Fame = 0; + Karma = 0; + + VirtualArmor = 40; + ControlSlots = ( Core.SE ) ? 2 : 1; + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public override int GetAngerSound() + { + return 0x15; + } + + public override int GetAttackSound() + { + return 0x28; + } + + public override void OnThink() + { + if ( Core.SE && Summoned ) + { + ArrayList spirtsOrVortexes = new ArrayList(); + + foreach ( Mobile m in GetMobilesInRange( 5 ) ) + { + if ( m is EnergyVortex || m is BladeSpirits ) + { + if ( ( (BaseCreature) m ).Summoned ) + spirtsOrVortexes.Add( m ); + } + } + + while ( spirtsOrVortexes.Count > 6 ) + { + int index = Utility.Random( spirtsOrVortexes.Count ); + //TODO: Confirm if it's the dispel with all the pretty effects or just a Deletion of it. + Dispel( ( (Mobile) spirtsOrVortexes[index] ) ); + spirtsOrVortexes.RemoveAt( index ); + } + } + + base.OnThink(); + } + + + public EnergyVortex( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/FrostOoze.cs b/Scripts/Mobiles/Monsters/Misc/Melee/FrostOoze.cs new file mode 100644 index 0000000..c508f0d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/FrostOoze.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a frost ooze corpse" )] + public class FrostOoze : BaseCreature + { + [Constructable] + public FrostOoze() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a frost ooze"; + Body = 94; + BaseSoundID = 456; + + SetStr( 18, 30 ); + SetDex( 16, 21 ); + SetInt( 16, 20 ); + + SetHits( 13, 17 ); + + SetDamage( 3, 9 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 5.1, 10.0 ); + SetSkill( SkillName.Tactics, 19.3, 34.0 ); + SetSkill( SkillName.Wrestling, 25.3, 40.0 ); + + Fame = 450; + Karma = -450; + + VirtualArmor = 38; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Gems, Utility.RandomMinMax( 1, 2 ) ); + } + + public FrostOoze( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs b/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs new file mode 100644 index 0000000..1386d54 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/Golem.cs @@ -0,0 +1,232 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a golem corpse" )] + public class Golem : BaseCreature + { + private bool m_Stunning; + + public override bool IsScaredOfScaryThings{ get{ return false; } } + public override bool IsScaryToPets{ get{ return true; } } + + public override bool IsBondable{ get{ return false; } } + + public override FoodType FavoriteFood { get { return FoodType.None; } } + + public override bool CanBeDistracted { get { return false; } } + + [Constructable] + public Golem() : this( false, 1.0 ) + { + } + + [Constructable] + public Golem( bool summoned, double scalar ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8 ) + { + Name = "a golem"; + Body = 752; + + if ( summoned ) + Hue = 2101; + + SetStr( (int)(251*scalar), (int)(350*scalar) ); + SetDex( (int)(76*scalar), (int)(100*scalar) ); + SetInt( (int)(101*scalar), (int)(150*scalar) ); + + SetHits( (int)(151*scalar), (int)(210*scalar) ); + + SetDamage( (int)(13*scalar), (int)(24*scalar) ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, (int)(35*scalar), (int)(55*scalar) ); + + if ( summoned ) + SetResistance( ResistanceType.Fire, (int)(50*scalar), (int)(60*scalar) ); + else + SetResistance( ResistanceType.Fire, (int)(100*scalar) ); + + SetResistance( ResistanceType.Cold, (int)(10*scalar), (int)(30*scalar) ); + SetResistance( ResistanceType.Poison, (int)(10*scalar), (int)(25*scalar) ); + SetResistance( ResistanceType.Energy, (int)(30*scalar), (int)(40*scalar) ); + + SetSkill( SkillName.MagicResist, (150.1*scalar), (190.0*scalar) ); + SetSkill( SkillName.Tactics, (60.1*scalar), (100.0*scalar) ); + SetSkill( SkillName.Wrestling, (60.1*scalar), (100.0*scalar) ); + + if ( summoned ) + { + Fame = 10; + Karma = 10; + } + else + { + Fame = 3500; + Karma = -3500; + } + + if ( !summoned ) + { + PackItem( new IronIngot( Utility.RandomMinMax( 13, 21 ) ) ); + + if ( 0.1 > Utility.RandomDouble() ) + PackItem( new PowerCrystal() ); + + if ( 0.15 > Utility.RandomDouble() ) + PackItem( new ClockworkAssembly() ); + + if ( 0.2 > Utility.RandomDouble() ) + PackItem( new ArcaneGem() ); + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( new Gears() ); + } + + ControlSlots = 3; + } + + public override void OnDeath(Container c) + { + base.OnDeath(c); + + if (0.05 > Utility.RandomDouble()) + { + if (!IsParagon) + { + if (0.75 > Utility.RandomDouble()) + c.DropItem(DawnsMusicGear.RandomCommon); + else + c.DropItem(DawnsMusicGear.RandomUncommon); + } + else + c.DropItem(DawnsMusicGear.RandomRare); + } + } + + public override bool DeleteOnRelease{ get{ return true; } } + + public override int GetAngerSound() + { + return 541; + } + + public override int GetIdleSound() + { + if ( !Controlled ) + return 542; + + return base.GetIdleSound(); + } + + public override int GetDeathSound() + { + if ( !Controlled ) + return 545; + + return base.GetDeathSound(); + } + + public override int GetAttackSound() + { + return 562; + } + + public override int GetHurtSound() + { + if ( Controlled ) + return 320; + + return base.GetHurtSound(); + } + + public override bool AutoDispel{ get{ return !Controlled; } } + public override bool BleedImmune{ get{ return true; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !m_Stunning && 0.3 > Utility.RandomDouble() ) + { + m_Stunning = true; + + defender.Animate( 21, 6, 1, true, false, 0 ); + this.PlaySound( 0xEE ); + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You have been stunned by a colossal blow!" ); + + BaseWeapon weapon = this.Weapon as BaseWeapon; + if ( weapon != null ) + weapon.OnHit( this, defender ); + + if ( defender.Alive ) + { + defender.Frozen = true; + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( Recover_Callback ), defender ); + } + } + } + + private void Recover_Callback( object state ) + { + Mobile defender = state as Mobile; + + if ( defender != null ) + { + defender.Frozen = false; + defender.Combatant = null; + defender.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "You recover your senses." ); + } + + m_Stunning = false; + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if ( Controlled || Summoned ) + { + Mobile master = ( this.ControlMaster ); + + if ( master == null ) + master = this.SummonMaster; + + if ( master != null && master.Player && master.Map == this.Map && master.InRange( Location, 20 ) ) + { + if ( master.Mana >= amount ) + { + master.Mana -= amount; + } + else + { + amount -= master.Mana; + master.Mana = 0; + master.Damage( amount ); + } + } + } + + base.OnDamage( amount, from, willKill ); + } + + public override bool BardImmune{ get{ return !Core.AOS || Controlled; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public Golem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs b/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs new file mode 100644 index 0000000..9c36d61 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeast.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a plague beast corpse" )] + public class PlagueBeast : BaseCreature, IDevourer + { + private int m_DevourTotal; + private int m_DevourGoal; + private bool m_HasMetalChest = false; + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalDevoured + { + get { return m_DevourTotal; } + set { m_DevourTotal = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DevourGoal + { + get { return ( IsParagon ? m_DevourGoal + 25 : m_DevourGoal ); } + set { m_DevourGoal = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasMetalChest + { + get { return m_HasMetalChest; } + } + + [Constructable] + public PlagueBeast() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a plague beast"; + Body = 775; + + SetStr( 302, 500 ); + SetDex( 80 ); + SetInt( 16, 20 ); + + SetHits( 318, 404 ); + + SetDamage( 20, 24 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 65, 75 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 35.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 13000; + Karma = -13000; + + VirtualArmor = 30; + PackArmor( 1, 5 ); + if ( Utility.RandomDouble() < 0.80 ) + PackItem( new PlagueBeastGland() ); + + if ( Core.ML && Utility.RandomDouble() < 0.33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(4) ); + + m_DevourTotal = 0; + m_DevourGoal = Utility.RandomMinMax( 15, 25 ); // How many corpses must be devoured before a metal chest is awarded + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Gems, Utility.Random( 1, 3 ) ); + // TODO: dungeon chest, healthy gland + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + defender.ApplyPoison( this, IsParagon ? Poison.Lethal : Poison.Deadly ); + defender.FixedParticles( 0x374A, 10, 15, 5021, EffectLayer.Waist ); + defender.PlaySound( 0x1CB ); + } + + public override void OnDamagedBySpell( Mobile caster ) + { + if ( this.Map != null && caster != this && 0.25 > Utility.RandomDouble() ) + { + BaseCreature spawn = new PlagueSpawn( this ); + + spawn.Team = this.Team; + spawn.MoveToWorld( this.Location, this.Map ); + spawn.Combatant = caster; + + Say( 1053034 ); // * The plague beast creates another beast from its flesh! * + } + + base.OnDamagedBySpell( caster ); + } + + public override bool AutoDispel{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + if ( this.Map != null && attacker != this && 0.25 > Utility.RandomDouble() ) + { + BaseCreature spawn = new PlagueSpawn( this ); + + spawn.Team = this.Team; + spawn.MoveToWorld( this.Location, this.Map ); + spawn.Combatant = attacker; + + Say( 1053034 ); // * The plague beast creates another beast from its flesh! * + } + + base.OnGotMeleeAttack( attacker ); + } + + public PlagueBeast( Serial serial ) : base( serial ) + { + } + + public override int GetIdleSound() + { + return 0x1BF; + } + + public override int GetAttackSound() + { + return 0x1C0; + } + + public override int GetHurtSound() + { + return 0x1C1; + } + + public override int GetDeathSound() + { + return 0x1C2; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + + writer.Write( m_HasMetalChest ); + writer.Write( m_DevourTotal ); + writer.Write( m_DevourGoal ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + switch( version ) + { + case 1: + { + m_HasMetalChest = reader.ReadBool(); + m_DevourTotal = reader.ReadInt(); + m_DevourGoal = reader.ReadInt(); + break; + } + } + } + + public override void OnThink() + { + base.OnThink(); + + // Check to see if we need to devour any corpses + IPooledEnumerable eable = GetItemsInRange( 3 ); // Get all corpses in range + + foreach( Item item in eable ) + { + if( item is Corpse ) // For each Corpse + { + Corpse corpse = item as Corpse; + + // Ensure that the corpse was killed by us + if( corpse != null && corpse.Killer == this && corpse.Owner != null ) + { + if( !corpse.DevourCorpse() && !corpse.Devoured ) + PublicOverheadMessage( MessageType.Emote, 0x3B2, 1053032 ); // * The plague beast attempts to absorb the remains, but cannot! * + } + } + } + eable.Free(); + } + + #region IDevourer Members + + public bool Devour( Corpse corpse ) + { + if( corpse == null || corpse.Owner == null ) // sorry we can't devour because the corpse's owner is null + return false; + + if( corpse.Owner.Body.IsHuman ) + corpse.TurnToBones(); // Not bones yet, and we are a human body therefore we turn to bones. + + IncreaseHits( (int)Math.Ceiling( (double)corpse.Owner.HitsMax * 0.75 ) ); + m_DevourTotal++; + + PublicOverheadMessage( MessageType.Emote, 0x3B2, 1053033 ); // * The plague beast absorbs the fleshy remains of the corpse * + + if( !m_HasMetalChest && m_DevourTotal >= DevourGoal ) + { + PackItem( new MetalChest() ); + m_HasMetalChest = true; + } + + return true; + } + + #endregion + + private void IncreaseHits( int hp ) + { + int maxhits = 2000; + + if ( this.IsParagon ) + maxhits = (int)(maxhits * Paragon.HitsBuff); + + if( hp < 1000 && !Core.AOS ) + hp = (hp * 100) / 60; + + if( HitsMaxSeed >= maxhits ) + { + HitsMaxSeed = maxhits; + + int newHits = this.Hits + hp + Utility.RandomMinMax( 10, 20 ); // increase the hp until it hits if it goes over it'll max at 2000 + + this.Hits = Math.Min( maxhits, newHits ); + // Also provide heal for each devour on top of the hp increase + } + else + { + int min = (hp / 2) + 10; + int max = hp + 20; + int hpToIncrease = Utility.RandomMinMax( min, max ); + + HitsMaxSeed += hpToIncrease; + Hits += hpToIncrease; + // Also provide heal for each devour + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs b/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs new file mode 100644 index 0000000..163f763 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/PlagueBeastLord.cs @@ -0,0 +1,365 @@ +using System; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a plague beast lord corpse" )] + public class PlagueBeastLord : BaseCreature, ICarvable, IScissorable + { + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + private Mobile m_OpenedBy; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile OpenedBy + { + get { return m_OpenedBy; } + set { m_OpenedBy = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsBleeding + { + get + { + Container pack = Backpack; + + if ( pack != null ) + { + for ( int i = 0; i < pack.Items.Count; i++ ) + { + PlagueBeastBlood blood = pack.Items[ i ] as PlagueBeastBlood; + + if ( blood != null && !blood.Patched ) + return true; + } + } + + return false; + } + } + + private DecayTimer m_Timer; + + [Constructable] + public PlagueBeastLord() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a plague beast lord"; + Body = 775; + BaseSoundID = 679; + SpeechHue = 0x3B2; + + SetStr( 500 ); + SetDex( 100 ); + SetInt( 30 ); + + SetHits( 1800 ); + + SetDamage( 20, 25 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Poison, 25 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 75, 85 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.Tactics, 100 ); + SetSkill( SkillName.Wrestling, 100 ); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 50; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsAccessibleTo( from ) ) + { + if ( m_OpenedBy != null && Backpack != null ) + Backpack.DisplayTo( from ); + else + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1071917, from.NetState ); // * You attempt to tear open the amorphous flesh, but it resists * + } + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( IsAccessibleTo( from ) && ( dropped is PlagueBeastInnard || dropped is PlagueBeastGland ) ) + return base.OnDragDrop( from, dropped ); + + return false; + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + for ( int i = c.Items.Count - 1; i >= 0; i-- ) + c.Items[ i ].Delete(); + } + + public override void OnDelete() + { + if ( m_OpenedBy != null && m_OpenedBy.Holding is PlagueBeastInnard ) + m_OpenedBy.Holding.Delete(); + + if ( Backpack != null ) + { + for ( int i = Backpack.Items.Count - 1; i >= 0; i-- ) + Backpack.Items[ i ].Delete(); + + Backpack.Delete(); + } + + base.OnDelete(); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( Backpack != null && IsAccessibleTo( m ) && m.InRange( oldLocation, 3 ) && !m.InRange( this, 3 ) ) + Backpack.SendRemovePacket(); + } + + public override bool CheckNonlocalLift( Mobile from, Item item ) + { + return true; + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + return true; + } + + public override bool IsSnoop( Mobile from ) + { + return false; + } + + public override int GetIdleSound() + { + return 0x1BF; + } + + public override int GetAttackSound() + { + return 0x1C0; + } + + public override int GetHurtSound() + { + return 0x1C1; + } + + public override int GetDeathSound() + { + return 0x1C2; + } + + public virtual void OnParalyzed( Mobile from ) + { + FightMode = FightMode.None; + Frozen = true; + Blessed = true; + Combatant = null; + Hue = 0x480; + from.Combatant = null; + from.Warmode = false; + + m_Timer = new DecayTimer( this ); + m_Timer.Start(); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( BroadcastMessage ) ); + } + + private void BroadcastMessage() + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071920 ); // * The plague beast's amorphous flesh hardens and becomes immobilized * + } + + public virtual bool IsAccessibleTo( Mobile check ) + { + if ( check.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if ( !InRange( check, 2 ) ) + PrivateOverheadMessage( MessageType.Label, 0x3B2, 500446, check.NetState ); // That is too far away. + else if ( m_OpenedBy != null && m_OpenedBy != check ) + PrivateOverheadMessage( MessageType.Label, 0x3B2, 500365, check.NetState ); // That is being used by someone else + else if ( Frozen ) + return true; + + return false; + } + + public virtual void Carve( Mobile from, Item item ) + { + if ( m_OpenedBy == null && IsAccessibleTo( from ) ) + { + m_OpenedBy = from; + + if ( m_Timer == null ) + m_Timer = new DecayTimer( this ); + + if ( !m_Timer.Running ) + m_Timer.Start(); + + m_Timer.StartDissolving(); + + PlagueBeastBackpack pack = new PlagueBeastBackpack(); + AddItem( pack ); + pack.Initialize(); + + foreach ( NetState state in GetClientsInRange( 12 ) ) + { + Mobile m = state.Mobile; + + if ( m != null && m.Player && m != from ) + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1071919, from.Name, m.NetState ); // * ~1_VAL~ slices through the plague beast's amorphous tissue * + } + + from.LocalOverheadMessage( MessageType.Regular, 0x21, 1071904 ); // * You slice through the plague beast's amorphous tissue * + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( pack.Open ), from ); + } + } + + public virtual bool Scissor( Mobile from, Scissors scissors ) + { + if ( IsAccessibleTo( from ) ) + scissors.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071918 ); // You can't cut through the plague beast's amorphous skin with scissors! + + return false; + } + + public void Unfreeze() + { + FightMode = FightMode.Closest; + Frozen = false; + Blessed = false; + + if ( m_OpenedBy == null ) + Hue = 0; + } + + public PlagueBeastLord( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_OpenedBy ); + + if ( m_Timer != null ) + { + writer.Write( (bool) true ); + writer.Write( (int) m_Timer.Count ); + writer.Write( (int) m_Timer.Deadline ); + } + else + writer.Write( (bool) false ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_OpenedBy = reader.ReadMobile(); + + if ( reader.ReadBool() ) + { + int count = reader.ReadInt(); + int deadline = reader.ReadInt(); + + m_Timer = new DecayTimer( this, count, deadline ); + m_Timer.Start(); + } + + if ( FightMode == FightMode.None ) + Frozen = true; + } + + private class DecayTimer : Timer + { + private PlagueBeastLord m_Lord; + private int m_Count; + private int m_Deadline; + + public int Count + { + get { return m_Count; } + } + + public int Deadline + { + get { return m_Deadline; } + } + + public DecayTimer( PlagueBeastLord lord ) : this( lord, 0, 120 ) + { + } + + public DecayTimer( PlagueBeastLord lord, int count, int deadline ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1 ) ) + { + m_Lord = lord; + m_Count = count; + m_Deadline = deadline; + } + + protected override void OnTick() + { + if ( m_Lord == null || m_Lord.Deleted ) + { + Stop(); + return; + } + + if ( m_Count + 15 == m_Deadline ) + { + if ( m_Lord.OpenedBy != null ) + m_Lord.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1071921 ); // * The plague beast begins to bubble and dissolve! * + + m_Lord.PlaySound( 0x103 ); + } + else if ( m_Count + 10 == m_Deadline ) + { + m_Lord.PlaySound( 0x21 ); + } + else if ( m_Count + 5 == m_Deadline ) + { + m_Lord.PlaySound( 0x1C2 ); + } + else if ( m_Count == m_Deadline ) + { + m_Lord.Unfreeze(); + + if ( m_Lord.OpenedBy != null ) + m_Lord.Kill(); + + Stop(); + } + else if ( m_Count % 15 == 0 ) + m_Lord.PlaySound( 0x1BF ); + + m_Count++; + } + + public void StartDissolving() + { + m_Deadline = Math.Min( m_Count + 60, m_Deadline ); + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs b/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs new file mode 100644 index 0000000..0f3d344 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/PlagueSpawn.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [CorpseName( "a plague spawn corpse" )] + public class PlagueSpawn : BaseCreature + { + private Mobile m_Owner; + private DateTime m_ExpireTime; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime ExpireTime + { + get{ return m_ExpireTime; } + set{ m_ExpireTime = value; } + } + + [Constructable] + public PlagueSpawn() : this( null ) + { + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public override void DisplayPaperdollTo(Mobile to) + { + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + for ( int i = 0; i < list.Count; ++i ) + { + if ( list[i] is ContextMenus.PaperdollEntry ) + list.RemoveAt( i-- ); + } + } + + public override void OnThink() + { + if ( m_Owner != null && ( DateTime.Now >= m_ExpireTime || m_Owner.Deleted || Map != m_Owner.Map || !InRange( m_Owner, 16 ) ) ) + { + PlaySound( GetIdleSound() ); + Delete(); + } + else + { + base.OnThink(); + } + } + + public PlagueSpawn( Mobile owner ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + m_Owner = owner; + m_ExpireTime = DateTime.Now + TimeSpan.FromMinutes( 1.0 ); + + Name = "a plague spawn"; + Hue = Utility.Random( 0x11, 15 ); + + switch ( Utility.Random( 12 ) ) + { + case 0: // earth elemental + Body = 14; + BaseSoundID = 268; + break; + case 1: // headless one + Body = 31; + BaseSoundID = 0x39D; + break; + case 2: // person + Body = Utility.RandomList( 400, 401 ); + break; + case 3: // gorilla + Body = 0x1D; + BaseSoundID = 0x9E; + break; + case 4: // serpent + Body = 0x15; + BaseSoundID = 0xDB; + break; + default: + case 5: // slime + Body = 51; + BaseSoundID = 456; + break; + } + + SetStr( 201, 300 ); + SetDex( 80 ); + SetInt( 16, 20 ); + + SetHits( 121, 180 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 65, 75 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 25.0 ); + SetSkill( SkillName.Tactics, 25.0 ); + SetSkill( SkillName.Wrestling, 50.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 20; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + AddLoot( LootPack.Gems ); + } + + public PlagueSpawn( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/SandVortex.cs b/Scripts/Mobiles/Monsters/Misc/Melee/SandVortex.cs new file mode 100644 index 0000000..d28cf0d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/SandVortex.cs @@ -0,0 +1,111 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a sand vortex corpse" )] + public class SandVortex : BaseCreature + { + [Constructable] + public SandVortex() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a sand vortex"; + Body = 790; + BaseSoundID = 263; + + SetStr( 96, 120 ); + SetDex( 171, 195 ); + SetInt( 76, 100 ); + + SetHits( 51, 62 ); + + SetDamage( 3, 16 ); + + SetDamageType( ResistanceType.Physical, 90 ); + SetDamageType( ResistanceType.Fire, 10 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 60, 70 ); + + SetSkill( SkillName.MagicResist, 150.0 ); + SetSkill( SkillName.Tactics, 70.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 28; + PackItem( new Bone() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager, 2 ); + } + + private DateTime m_NextAttack; + + public override void OnActionCombat() + { + Mobile combatant = Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != Map || !InRange( combatant, 12 ) || !CanBeHarmful( combatant ) || !InLOS( combatant ) ) + return; + + if ( DateTime.Now >= m_NextAttack ) + { + SandAttack( combatant ); + m_NextAttack = DateTime.Now + TimeSpan.FromSeconds( 10.0 + (10.0 * Utility.RandomDouble()) ); + } + } + + public void SandAttack( Mobile m ) + { + DoHarmful( m ); + + m.FixedParticles( 0x36B0, 10, 25, 9540, 2413, 0, EffectLayer.Waist ); + + new InternalTimer( m, this ).Start(); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile, m_From; + + public InternalTimer( Mobile m, Mobile from ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound( 0x4CF ); + AOS.Damage( m_Mobile, m_From, Utility.RandomMinMax( 1, 40 ), 90, 10, 0, 0, 0 ); + } + } + + public SandVortex( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Misc/Melee/Slime.cs b/Scripts/Mobiles/Monsters/Misc/Melee/Slime.cs new file mode 100644 index 0000000..fec686e --- /dev/null +++ b/Scripts/Mobiles/Monsters/Misc/Melee/Slime.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a slimey corpse" )] + public class Slime : BaseCreature + { + [Constructable] + public Slime() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a slime"; + Body = 51; + BaseSoundID = 456; + + Hue = Utility.RandomSlimeHue(); + + SetStr( 22, 34 ); + SetDex( 16, 21 ); + SetInt( 16, 20 ); + + SetHits( 15, 19 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + + SetSkill( SkillName.Poisoning, 30.1, 50.0 ); + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 19.3, 34.0 ); + SetSkill( SkillName.Wrestling, 19.3, 34.0 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 8; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 23.1; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + AddLoot( LootPack.Gems ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + public override Poison HitPoison{ get{ return Poison.Lesser; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish | FoodType.FruitsAndVegies | FoodType.GrainsAndHay | FoodType.Eggs; } } + + public Slime( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs new file mode 100644 index 0000000..a82dc58 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/AgapiteElemental.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class AgapiteElemental : BaseCreature + { + [Constructable] + public AgapiteElemental() : this( 2 ) + { + } + + [Constructable] + public AgapiteElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an agapite elemental"; + Body = 107; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 28 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 32; + + Item ore = new AgapiteOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool BleedImmune{ get{ return true; } } + public override bool AutoDispel{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public AgapiteElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs new file mode 100644 index 0000000..2592f45 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/BronzeElemental.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class BronzeElemental : BaseCreature + { + [Constructable] + public BronzeElemental() : this( 2 ) + { + } + + [Constructable] + public BronzeElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + // TODO: Gas attack + Name = "a bronze elemental"; + Body = 108; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 30 ); + SetDamageType( ResistanceType.Fire, 70 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 70, 80 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 29; + + Item ore = new BronzeOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool BleedImmune{ get{ return true; } } + public override bool AutoDispel{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public BronzeElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/CopperElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/CopperElemental.cs new file mode 100644 index 0000000..0c886f1 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/CopperElemental.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class CopperElemental : BaseCreature + { + [Constructable] + public CopperElemental() : this( 2 ) + { + } + + [Constructable] + public CopperElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a copper elemental"; + Body = 109; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 4800; + Karma = -4800; + + VirtualArmor = 26; + + Item ore = new CopperOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool BleedImmune{ get{ return true; } } + public override bool AutoDispel{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public override void CheckReflect( Mobile caster, ref bool reflect ) + { + reflect = true; // Every spell is reflected back to the caster + } + + public CopperElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs new file mode 100644 index 0000000..fdbe3e5 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/DullCopperElemental.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class DullCopperElemental : BaseCreature + { + [Constructable] + public DullCopperElemental() : this( 2 ) + { + } + + [Constructable] + public DullCopperElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a dull copper elemental"; + Body = 110; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 20; + + Item ore = new DullcopperOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public DullCopperElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs new file mode 100644 index 0000000..9cb9225 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/GoldenElemental.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class GoldenElemental : BaseCreature + { + [Constructable] + public GoldenElemental() : this( 2 ) + { + } + + [Constructable] + public GoldenElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a golden elemental"; + Body = 166; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60, 75 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 60; + + Item ore = new GoldOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public GoldenElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs new file mode 100644 index 0000000..e61d405 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/ShadowIronElemental.cs @@ -0,0 +1,101 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class ShadowIronElemental : BaseCreature + { + [Constructable] + public ShadowIronElemental() : this( 2 ) + { + } + + [Constructable] + public ShadowIronElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a shadow iron elemental"; + Body = 111; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 23; + + Item ore = new ShadowOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override bool BreathImmune{ get{ return true; } } + + public override void AlterMeleeDamageFrom( Mobile from, ref int damage ) + { + if ( from is BaseCreature ) + { + BaseCreature bc = (BaseCreature)from; + + if ( bc.Controlled || bc.BardTarget == this ) + damage = 0; // Immune to pets and provoked creatures + } + } + + public override void AlterDamageScalarFrom( Mobile caster, ref double scalar ) + { + scalar = 0.0; // Immune to magic + } + + public override void AlterSpellDamageFrom( Mobile from, ref int damage ) + { + damage = 0; + } + + public ShadowIronElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs new file mode 100644 index 0000000..aebc7e7 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/ValoriteElemental.cs @@ -0,0 +1,98 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class ValoriteElemental : BaseCreature + { + [Constructable] + public ValoriteElemental() : this( 2 ) + { + } + + [Constructable] + public ValoriteElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + // TODO: Gas attack + Name = "a valorite elemental"; + Body = 112; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 28 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 25 ); + SetDamageType( ResistanceType.Cold, 25 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 38; + + Item ore = new ValoriteOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Gems, 4 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public override void AlterMeleeDamageFrom( Mobile from, ref int damage ) + { + if ( from is BaseCreature ) + { + BaseCreature bc = (BaseCreature)from; + + if ( bc.Controlled || bc.BardTarget == this ) + damage = 0; // Immune to pets and provoked creatures + } + } + + public override void CheckReflect( Mobile caster, ref bool reflect ) + { + reflect = true; // Every spell is reflected back to the caster + } + + public ValoriteElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs b/Scripts/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs new file mode 100644 index 0000000..bbafd07 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Ore Elementals/VeriteElemental.cs @@ -0,0 +1,79 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ore elemental corpse" )] + public class VeriteElemental : BaseCreature + { + [Constructable] + public VeriteElemental() : this( 2 ) + { + } + + [Constructable] + public VeriteElemental( int oreAmount ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a verite elemental"; + Body = 113; + BaseSoundID = 268; + + SetStr( 226, 255 ); + SetDex( 126, 145 ); + SetInt( 71, 92 ); + + SetHits( 136, 153 ); + + SetDamage( 9, 16 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.MagicResist, 50.1, 95.0 ); + SetSkill( SkillName.Tactics, 60.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 100.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 35; + + Item ore = new VeriteOre( oreAmount ); + ore.ItemID = 0x19B9; + PackItem( ore ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool BleedImmune{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public VeriteElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Plant/Magic/Reaper.cs b/Scripts/Mobiles/Monsters/Plant/Magic/Reaper.cs new file mode 100644 index 0000000..028d7f1 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Magic/Reaper.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a reapers corpse" )] + public class Reaper : BaseCreature + { + [Constructable] + public Reaper() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a reaper"; + Body = 47; + BaseSoundID = 442; + + SetStr( 66, 215 ); + SetDex( 66, 75 ); + SetInt( 101, 250 ); + + SetHits( 40, 129 ); + SetStam( 0 ); + + SetDamage( 9, 11 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Poison, 20 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 100.1, 125.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 50.1, 60.0 ); + + Fame = 3500; + Karma = -3500; + + VirtualArmor = 40; + + PackItem( new Log( 10 ) ); + PackItem( new MandrakeRoot( 5 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override int TreasureMapLevel{ get{ return 2; } } + public override bool DisallowAllMoves{ get{ return true; } } + + public Reaper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Plant/Melee/BogThing.cs b/Scripts/Mobiles/Monsters/Plant/Melee/BogThing.cs new file mode 100644 index 0000000..0c9b146 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Melee/BogThing.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a plant corpse" )] + public class BogThing : BaseCreature + { + [Constructable] + public BogThing() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.6, 1.2 ) + { + Name = "a bog thing"; + Body = 780; + + SetStr( 801, 900 ); + SetDex( 46, 65 ); + SetInt( 36, 50 ); + + SetHits( 481, 540 ); + SetMana( 0 ); + + SetDamage( 10, 23 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 20, 25 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 20, 25 ); + + SetSkill( SkillName.MagicResist, 90.1, 95.0 ); + SetSkill( SkillName.Tactics, 70.1, 85.0 ); + SetSkill( SkillName.Wrestling, 65.1, 80.0 ); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 28; + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( new Board( 10 ) ); + else + PackItem( new Log( 10 ) ); + + PackReg( 3 ); + PackItem( new Engines.Plants.Seed() ); + PackItem( new Engines.Plants.Seed() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public BogThing( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public void SpawnBogling( Mobile m ) + { + Map map = this.Map; + + if ( map == null ) + return; + + Bogling spawned = new Bogling(); + + spawned.Team = this.Team; + + bool validLocation = false; + Point3D loc = this.Location; + + for ( int j = 0; !validLocation && j < 10; ++j ) + { + int x = X + Utility.Random( 3 ) - 1; + int y = Y + Utility.Random( 3 ) - 1; + int z = map.GetAverageZ( x, y ); + + if ( validLocation = map.CanFit( x, y, this.Z, 16, false, false ) ) + loc = new Point3D( x, y, Z ); + else if ( validLocation = map.CanFit( x, y, z, 16, false, false ) ) + loc = new Point3D( x, y, z ); + } + + spawned.MoveToWorld( loc, map ); + spawned.Combatant = m; + } + + public void EatBoglings() + { + ArrayList toEat = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 2 ) ) + { + if ( m is Bogling ) + toEat.Add( m ); + } + + if ( toEat.Count > 0 ) + { + PlaySound( Utility.Random( 0x3B, 2 ) ); // Eat sound + + foreach ( Mobile m in toEat ) + { + Hits += (m.Hits / 2); + m.Delete(); + } + } + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( this.Hits > (this.HitsMax / 4) ) + { + if ( 0.25 >= Utility.RandomDouble() ) + SpawnBogling( attacker ); + } + else if ( 0.25 >= Utility.RandomDouble() ) + { + EatBoglings(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Plant/Melee/Bogling.cs b/Scripts/Mobiles/Monsters/Plant/Melee/Bogling.cs new file mode 100644 index 0000000..0db0336 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Melee/Bogling.cs @@ -0,0 +1,69 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a plant corpse" )] + public class Bogling : BaseCreature + { + [Constructable] + public Bogling() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bogling"; + Body = 779; + BaseSoundID = 422; + + SetStr( 96, 120 ); + SetDex( 91, 115 ); + SetInt( 21, 45 ); + + SetHits( 58, 72 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 15, 25 ); + SetResistance( ResistanceType.Energy, 15, 25 ); + + SetSkill( SkillName.MagicResist, 75.1, 100.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + SetSkill( SkillName.Wrestling, 55.1, 75.0 ); + + Fame = 450; + Karma = -450; + + VirtualArmor = 28; + + PackItem( new Log( 4 ) ); + PackItem( new Engines.Plants.Seed() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int Hides{ get{ return 6; } } + public override int Meat{ get{ return 1; } } + + public Bogling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Plant/Melee/Corpser.cs b/Scripts/Mobiles/Monsters/Plant/Melee/Corpser.cs new file mode 100644 index 0000000..97f9e14 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Melee/Corpser.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a corpser corpse" )] + public class Corpser : BaseCreature + { + [Constructable] + public Corpser() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a corpser"; + Body = 8; + BaseSoundID = 684; + + SetStr( 156, 180 ); + SetDex( 26, 45 ); + SetInt( 26, 40 ); + + SetHits( 94, 108 ); + SetMana( 0 ); + + SetDamage( 10, 23 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 15, 20 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 18; + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( new Board( 10 ) ); + else + PackItem( new Log( 10 ) ); + + PackItem( new MandrakeRoot( 3 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + public override bool DisallowAllMoves{ get{ return true; } } + + public Corpser( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 352 ) + BaseSoundID = 684; + } + } +} diff --git a/Scripts/Mobiles/Monsters/Plant/Melee/Quagmire.cs b/Scripts/Mobiles/Monsters/Plant/Melee/Quagmire.cs new file mode 100644 index 0000000..5faba9d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Melee/Quagmire.cs @@ -0,0 +1,76 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a quagmire corpse" )] + public class Quagmire : BaseCreature + { + [Constructable] + public Quagmire() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.4, 0.8 ) + { + Name = "a quagmire"; + Body = 789; + BaseSoundID = 352; + + SetStr( 101, 130 ); + SetDex( 66, 85 ); + SetInt( 31, 55 ); + + SetHits( 91, 105 ); + + SetDamage( 10, 14 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 65.1, 75.0 ); + SetSkill( SkillName.Tactics, 50.1, 60.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 32; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override int GetAngerSound() + { + return 353; + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.1; } } + + public Quagmire( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == -1 ) + BaseSoundID = 352; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs b/Scripts/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs new file mode 100644 index 0000000..6c946d0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Melee/SwampTentacle.cs @@ -0,0 +1,69 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a swamp tentacle corpse" )] + public class SwampTentacle : BaseCreature + { + [Constructable] + public SwampTentacle() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a swamp tentacle"; + Body = 66; + BaseSoundID = 352; + + SetStr( 96, 120 ); + SetDex( 66, 85 ); + SetInt( 16, 30 ); + + SetHits( 58, 72 ); + SetMana( 0 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Poison, 60 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 60, 80 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 65.1, 80.0 ); + SetSkill( SkillName.Wrestling, 65.1, 80.0 ); + + Fame = 3000; + Karma = -3000; + + VirtualArmor = 28; + + PackReg( 3 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + + public SwampTentacle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Plant/Melee/WhippingVine.cs b/Scripts/Mobiles/Monsters/Plant/Melee/WhippingVine.cs new file mode 100644 index 0000000..5a293cd --- /dev/null +++ b/Scripts/Mobiles/Monsters/Plant/Melee/WhippingVine.cs @@ -0,0 +1,71 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a whipping vine corpse" )] + public class WhippingVine : BaseCreature + { + [Constructable] + public WhippingVine() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a whipping vine"; + Body = 8; + Hue = 0x851; + BaseSoundID = 352; + + SetStr( 251, 300 ); + SetDex( 76, 100 ); + SetInt( 26, 40 ); + + SetMana( 0 ); + + SetDamage( 7, 25 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 75, 85 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 15, 25 ); + SetResistance( ResistanceType.Poison, 75, 85 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.MagicResist, 70.0 ); + SetSkill( SkillName.Tactics, 70.0 ); + SetSkill( SkillName.Wrestling, 70.0 ); + + Fame = 1000; + Karma = -1000; + + VirtualArmor = 45; + + PackReg( 3 ); + PackItem( new FertileDirt( Utility.RandomMinMax( 1, 10 ) ) ); + + if ( 0.2 >= Utility.RandomDouble() ) + PackItem( new ExecutionersCap() ); + + PackItem( new Vines() ); + } + + public override bool BardImmune{ get{ return !Core.AOS; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public WhippingVine( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs new file mode 100644 index 0000000..c534916 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/AncientWyrm.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class AncientWyrm : BaseCreature + { + [Constructable] + public AncientWyrm () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ancient wyrm"; + Body = 46; + BaseSoundID = 362; + + SetStr( 1096, 1185 ); + SetDex( 86, 175 ); + SetInt( 686, 775 ); + + SetHits( 658, 711 ); + + SetDamage( 29, 35 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Fire, 25 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 80, 90 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 60, 70 ); + + SetSkill( SkillName.EvalInt, 80.1, 100.0 ); + SetSkill( SkillName.Magery, 80.1, 100.0 ); + SetSkill( SkillName.Meditation, 52.5, 75.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 70; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + AddLoot( LootPack.Gems, 5 ); + } + + public override int GetIdleSound() + { + return 0x2D3; + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override bool CanFly { get { return true; } } + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override bool AutoDispel{ get{ return true; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override int Hides{ get{ return 40; } } + public override int Meat{ get{ return 19; } } + public override int Scales{ get{ return 12; } } + public override ScaleType ScaleType{ get{ return (ScaleType)Utility.Random( 4 ); } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override Poison HitPoison{ get{ return Utility.RandomBool() ? Poison.Lesser : Poison.Regular; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public AncientWyrm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs new file mode 100644 index 0000000..c86cdc4 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/DeepSeaSerpent.cs @@ -0,0 +1,80 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a deep sea serpents corpse" )] + public class DeepSeaSerpent : BaseCreature + { + [Constructable] + public DeepSeaSerpent() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a deep sea serpent"; + Body = 150; + BaseSoundID = 447; + + Hue = Utility.Random( 0x8A0, 5 ); + + SetStr( 251, 425 ); + SetDex( 87, 135 ); + SetInt( 87, 155 ); + + SetHits( 151, 255 ); + + SetDamage( 6, 14 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 15, 20 ); + + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 60.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 70.0 ); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 60; + CanSwim = true; + CantWalk = true; + + if ( Utility.RandomBool() ) + PackItem( new SulfurousAsh( 4 ) ); + else + PackItem( new BlackPearl( 4 ) ); + + //PackItem( new SpecialFishingNet() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool HasBreath{ get{ return true; } } + public override int Meat{ get{ return 1; } } + public override int Scales{ get{ return 8; } } + public override ScaleType ScaleType{ get{ return ScaleType.Blue; } } + + public DeepSeaSerpent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/Dragon.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/Dragon.cs new file mode 100644 index 0000000..00403c3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/Dragon.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class Dragon : BaseCreature + { + [Constructable] + public Dragon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a dragon"; + Body = Utility.RandomList( 12, 59 ); + BaseSoundID = 362; + + SetStr( 796, 825 ); + SetDex( 86, 105 ); + SetInt( 436, 475 ); + + SetHits( 478, 495 ); + + SetDamage( 16, 22 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.EvalInt, 30.1, 40.0 ); + SetSkill( SkillName.Magery, 30.1, 40.0 ); + SetSkill( SkillName.MagicResist, 99.1, 100.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 92.5 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 60; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Gems, 8 ); + } + + public override bool CanFly { get { return true; } } + public override bool ReacquireOnMovement{ get{ return !Controlled; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override bool AutoDispel{ get{ return !Controlled; } } + public override int TreasureMapLevel{ get{ return 4; } } + public override int Meat{ get{ return 19; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override int Scales{ get{ return 7; } } + public override ScaleType ScaleType{ get{ return ( Body == 12 ? ScaleType.Yellow : ScaleType.Red ); } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override bool CanAngerOnTame { get { return true; } } + + public Dragon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/Leviathan.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/Leviathan.cs new file mode 100644 index 0000000..7973a7d --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/Leviathan.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a leviathan corpse" )] + public class Leviathan : BaseCreature + { + private Mobile m_Fisher; + + public Mobile Fisher + { + get{ return m_Fisher; } + set{ m_Fisher = value; } + } + + [Constructable] + public Leviathan() : this( null ) + { + } + + [Constructable] + public Leviathan( Mobile fisher ) : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + m_Fisher = fisher; + + // May not be OSI accurate; mostly copied from krakens + Name = "a leviathan"; + Body = 77; + BaseSoundID = 353; + + Hue = 0x481; + + SetStr( 1000 ); + SetDex( 501, 520 ); + SetInt( 501, 515 ); + + SetHits( 1500 ); + + SetDamage( 25, 33 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Cold, 30 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 45, 55 ); + SetResistance( ResistanceType.Cold, 45, 55 ); + SetResistance( ResistanceType.Poison, 35, 45 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.EvalInt, 97.6, 107.5 ); + SetSkill( SkillName.Magery, 97.6, 107.5 ); + SetSkill( SkillName.MagicResist, 97.6, 107.5 ); + SetSkill( SkillName.Meditation, 97.6, 107.5 ); + SetSkill( SkillName.Tactics, 97.6, 107.5 ); + SetSkill( SkillName.Wrestling, 97.6, 107.5 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 50; + + CanSwim = true; + CantWalk = true; + + PackItem( new MessageInABottle() ); + + Rope rope = new Rope(); + rope.ItemID = 0x14F8; + PackItem( rope ); + + rope = new Rope(); + rope.ItemID = 0x14FA; + PackItem( rope ); + } + + public override bool HasBreath{ get{ return true; } } + public override int BreathPhysicalDamage{ get{ return 70; } } // TODO: Verify damage type + public override int BreathColdDamage{ get{ return 30; } } + public override int BreathFireDamage{ get{ return 0; } } + public override int BreathEffectHue{ get{ return 0x1ED; } } + public override double BreathDamageScalar{ get{ return 0.05; } } + public override double BreathMinDelay{ get{ return 5.0; } } + public override double BreathMaxDelay{ get{ return 7.5; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 5 ); + } + + public override double TreasureMapChance{ get{ return 0.25; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public Leviathan( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public static Type[] Artifacts { get { return m_Artifacts; } } + + private static Type[] m_Artifacts = new Type[] + { + // Decorations + typeof( CandelabraOfSouls ), + typeof( GhostShipAnchor ), + typeof( GoldBricks ), + typeof( PhillipsWoodenSteed ), + typeof( SeahorseStatuette ), + typeof( ShipModelOfTheHMSCape ), + typeof( AdmiralsHeartyRum ), + + // Equipment + typeof( AlchemistsBauble ), + typeof( ArcticDeathDealer ), + typeof( BlazeOfDeath ), + typeof( BurglarsBandana ), + typeof( CaptainQuacklebushsCutlass ), + typeof( CavortingClub ), + typeof( DreadPirateHat ), + typeof( EnchantedTitanLegBone ), + typeof( GwennosHarp ), + typeof( IolosLute ), + typeof( LunaLance ), + typeof( NightsKiss ), + typeof( NoxRangersHeavyCrossbow ), + typeof( PolarBearMask ), + typeof( VioletCourage ) + }; + + public static void GiveArtifactTo( Mobile m ) + { + Item item = Loot.Construct( m_Artifacts ); + + if ( item == null ) + return; + + // TODO: Confirm messages + if ( m.AddToBackpack( item ) ) + m.SendMessage( "As a reward for slaying the mighty leviathan, an artifact has been placed in your backpack." ); + else + m.SendMessage( "As your backpack is full, your reward for destroying the legendary leviathan has been placed at your feet." ); + } + + public override void OnKilledBy( Mobile mob ) + { + base.OnKilledBy( mob ); + + if ( Paragon.CheckArtifactChance( mob, this ) ) + { + GiveArtifactTo( mob ); + + if ( mob == m_Fisher ) + m_Fisher = null; + } + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + + if ( m_Fisher != null && 25 > Utility.Random( 100 ) ) + GiveArtifactTo( m_Fisher ); + + m_Fisher = null; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs new file mode 100644 index 0000000..40ed11f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianArchmage.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ophidian corpse" )] + [TypeAlias( "Server.Mobiles.OphidianJusticar", "Server.Mobiles.OphidianZealot" )] + public class OphidianArchmage : BaseCreature + { + private static string[] m_Names = new string[] + { + "an ophidian justicar", + "an ophidian zealot" + }; + + [Constructable] + public OphidianArchmage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = m_Names[Utility.Random( m_Names.Length )]; + Body = 85; + BaseSoundID = 639; + + SetStr( 281, 305 ); + SetDex( 191, 215 ); + SetInt( 226, 250 ); + + SetHits( 169, 183 ); + SetStam( 36, 45 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 40, 45 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 35, 40 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.EvalInt, 95.1, 100.0 ); + SetSkill( SkillName.Magery, 95.1, 100.0 ); + SetSkill( SkillName.MagicResist, 75.0, 97.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 20.2, 60.0 ); + + Fame = 11500; + Karma = -11500; + + VirtualArmor = 44; + + PackReg( 5, 15 ); + PackNecroReg( 5, 15 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override int Meat{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public OphidianArchmage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs new file mode 100644 index 0000000..d5234ef --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianMage.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ophidian corpse" )] + [TypeAlias( "Server.Mobiles.OphidianShaman" )] + public class OphidianMage : BaseCreature + { + private static string[] m_Names = new string[] + { + "an ophidian apprentice mage", + "an ophidian shaman" + }; + + [Constructable] + public OphidianMage() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = m_Names[Utility.Random( m_Names.Length )]; + Body = 85; + BaseSoundID = 639; + + SetStr( 181, 205 ); + SetDex( 191, 215 ); + SetInt( 96, 120 ); + + SetHits( 109, 123 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.EvalInt, 85.1, 100.0 ); + SetSkill( SkillName.Magery, 85.1, 100.0 ); + SetSkill( SkillName.MagicResist, 75.0, 97.5 ); + SetSkill( SkillName.Tactics, 65.0, 87.5 ); + SetSkill( SkillName.Wrestling, 20.2, 60.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 30; + + PackReg( 10 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.LowScrolls ); + AddLoot( LootPack.MedScrolls ); + AddLoot( LootPack.Potions ); + } + + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public OphidianMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs new file mode 100644 index 0000000..e3fe5ca --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/OphidianMatriarch.cs @@ -0,0 +1,77 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an ophidian corpse" )] + public class OphidianMatriarch : BaseCreature + { + [Constructable] + public OphidianMatriarch() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an ophidian matriarch"; + Body = 87; + BaseSoundID = 644; + + SetStr( 416, 505 ); + SetDex( 96, 115 ); + SetInt( 366, 455 ); + + SetHits( 250, 303 ); + + SetDamage( 11, 13 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 5.4, 25.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 50.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 80.0 ); + + Fame = 16000; + Karma = -16000; + + VirtualArmor = 50; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override int TreasureMapLevel{ get{ return 4; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public OphidianMatriarch( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs new file mode 100644 index 0000000..f166468 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/SeaSerpent.cs @@ -0,0 +1,86 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a sea serpents corpse" )] + [TypeAlias( "Server.Mobiles.Seaserpant" )] + public class SeaSerpent : BaseCreature + { + [Constructable] + public SeaSerpent() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a sea serpent"; + Body = 150; + BaseSoundID = 447; + + Hue = Utility.Random( 0x530, 9 ); + + SetStr( 168, 225 ); + SetDex( 58, 85 ); + SetInt( 53, 95 ); + + SetHits( 110, 127 ); + + SetDamage( 7, 13 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 15, 20 ); + + SetSkill( SkillName.MagicResist, 60.1, 75.0 ); + SetSkill( SkillName.Tactics, 60.1, 70.0 ); + SetSkill( SkillName.Wrestling, 60.1, 70.0 ); + + Fame = 6000; + Karma = -6000; + + VirtualArmor = 30; + CanSwim = true; + CantWalk = true; + + if ( Utility.RandomBool() ) + PackItem( new SulfurousAsh( 4 ) ); + else + PackItem( new BlackPearl( 4 ) ); + + PackItem( new RawFishSteak() ); + + //PackItem( new SpecialFishingNet() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override bool HasBreath{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override int Scales{ get{ return 8; } } + public override ScaleType ScaleType{ get{ return ScaleType.Blue; } } + + public SeaSerpent( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs new file mode 100644 index 0000000..788ecd9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/SerpentineDragon.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class SerpentineDragon : BaseCreature + { + [Constructable] + public SerpentineDragon() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a serpentine dragon"; + Body = 103; + BaseSoundID = 362; + + SetStr( 111, 140 ); + SetDex( 201, 220 ); + SetInt( 1001, 1040 ); + + SetHits( 480 ); + + SetDamage( 5, 12 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Poison, 25 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 25, 35 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 25, 35 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.EvalInt, 100.1, 110.0 ); + SetSkill( SkillName.Magery, 110.1, 120.0 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 100.0 ); + SetSkill( SkillName.Tactics, 50.1, 60.0 ); + SetSkill( SkillName.Wrestling, 30.1, 100.0 ); + + Fame = 15000; + Karma = 15000; + + VirtualArmor = 36; + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(2) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Gems, 2 ); + } + + public override int GetIdleSound() + { + return 0x2C4; + } + + public override int GetAttackSound() + { + return 0x2C0; + } + + public override int GetDeathSound() + { + return 0x2C1; + } + + public override int GetAngerSound() + { + return 0x2C4; + } + + public override int GetHurtSound() + { + return 0x2C3; + } + + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override double BonusPetDamageScalar{ get{ return (Core.SE) ? 3.0 : 1.0; } } + + public override bool AutoDispel{ get{ return true; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override int Hides{ get{ return 20; } } + public override int Meat{ get{ return 19; } } + public override int Scales{ get{ return 6; } } + public override ScaleType ScaleType{ get{ return ( Utility.RandomBool() ? ScaleType.Black : ScaleType.White ); } } + public override int TreasureMapLevel{ get{ return 4; } } + + public SerpentineDragon( Serial serial ) : base( serial ) + { + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( !Core.SE && 0.2 > Utility.RandomDouble() && attacker is BaseCreature ) + { + BaseCreature c = (BaseCreature)attacker; + + if ( c.Controlled && c.ControlMaster != null ) + { + c.ControlTarget = c.ControlMaster; + c.ControlOrder = OrderType.Attack; + c.Combatant = c.ControlMaster; + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs new file mode 100644 index 0000000..d847cfd --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/ShadowWyrm.cs @@ -0,0 +1,93 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a shadow wyrm corpse" )] + public class ShadowWyrm : BaseCreature + { + [Constructable] + public ShadowWyrm() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a shadow wyrm"; + Body = 106; + BaseSoundID = 362; + + SetStr( 898, 1030 ); + SetDex( 68, 200 ); + SetInt( 488, 620 ); + + SetHits( 558, 599 ); + + SetDamage( 29, 35 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Cold, 25 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 45, 55 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.EvalInt, 80.1, 100.0 ); + SetSkill( SkillName.Magery, 80.1, 100.0 ); + SetSkill( SkillName.Meditation, 52.5, 75.0 ); + SetSkill( SkillName.MagicResist, 100.3, 130.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 70; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + AddLoot( LootPack.Gems, 5 ); + } + + public override int GetIdleSound() + { + return 0x2D5; + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override bool CanFly { get { return true; } } + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override bool AutoDispel{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public override int Meat{ get{ return 19; } } + public override int Hides{ get{ return 20; } } + public override int Scales{ get{ return 10; } } + public override ScaleType ScaleType{ get{ return ScaleType.Black; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + + public ShadowWyrm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs new file mode 100644 index 0000000..b7a3b9a --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/SkeletalDragon.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a skeletal dragon corpse" )] + public class SkeletalDragon : BaseCreature + { + [Constructable] + public SkeletalDragon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a skeletal dragon"; + Body = 104; + BaseSoundID = 0x488; + + SetStr( 898, 1030 ); + SetDex( 68, 200 ); + SetInt( 488, 620 ); + + SetHits( 558, 599 ); + + SetDamage( 29, 35 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Fire, 25 ); + + SetResistance( ResistanceType.Physical, 75, 80 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Poison, 70, 80 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + + SetSkill( SkillName.EvalInt, 80.1, 100.0 ); + SetSkill( SkillName.Magery, 80.1, 100.0 ); + SetSkill( SkillName.MagicResist, 100.3, 130.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + SetSkill(SkillName.Necromancy, 120.1, 130.0); + SetSkill(SkillName.SpiritSpeak, 120.1, 130.0); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 80; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 4 ); + AddLoot( LootPack.Gems, 5 ); + } + + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int BreathFireDamage{ get{ return 0; } } + public override int BreathColdDamage{ get{ return 100; } } + public override int BreathEffectHue{ get{ return 0x480; } } + public override double BonusPetDamageScalar{ get{ return (Core.SE)? 3.0 : 1.0; } } + // TODO: Undead summoning? + + public override bool AutoDispel{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override bool BleedImmune{ get{ return true; } } + public override int Meat{ get{ return 19; } } // where's it hiding these? :) + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + + public SkeletalDragon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs b/Scripts/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs new file mode 100644 index 0000000..1baf07c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Magic/WhiteWyrm.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a white wyrm corpse" )] + public class WhiteWyrm : BaseCreature + { + [Constructable] + public WhiteWyrm() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Body = Utility.RandomBool() ? 180 : 49; + Name = "a white wyrm"; + BaseSoundID = 362; + + SetStr( 721, 760 ); + SetDex( 101, 130 ); + SetInt( 386, 425 ); + + SetHits( 433, 456 ); + + SetDamage( 17, 25 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Cold, 50 ); + + SetResistance( ResistanceType.Physical, 55, 70 ); + SetResistance( ResistanceType.Fire, 15, 25 ); + SetResistance( ResistanceType.Cold, 80, 90 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 99.1, 100.0 ); + SetSkill( SkillName.Magery, 99.1, 100.0 ); + SetSkill( SkillName.MagicResist, 99.1, 100.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 64; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 96.3; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems, Utility.Random( 1, 5 ) ); + } + + public override bool CanFly { get { return true; } } + public override bool ReacquireOnMovement{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 4; } } + public override int Meat{ get{ return 19; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override int Scales{ get{ return 9; } } + public override ScaleType ScaleType{ get{ return ScaleType.White; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Gold; } } + public override bool CanAngerOnTame { get { return true; } } + + public WhiteWyrm( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/Drake.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/Drake.cs new file mode 100644 index 0000000..ecdd155 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/Drake.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a drake corpse" )] + public class Drake : BaseCreature + { + [Constructable] + public Drake () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a drake"; + Body = Utility.RandomList( 60, 61 ); + BaseSoundID = 362; + + SetStr( 401, 430 ); + SetDex( 133, 152 ); + SetInt( 101, 140 ); + + SetHits( 241, 258 ); + + SetDamage( 11, 17 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Fire, 20 ); + + SetResistance( ResistanceType.Physical, 45, 50 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 65.1, 90.0 ); + SetSkill( SkillName.Wrestling, 65.1, 80.0 ); + + Fame = 5500; + Karma = -5500; + + VirtualArmor = 46; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 84.3; + + PackReg( 3 ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override bool CanFly { get { return true; } } + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override int TreasureMapLevel{ get{ return 2; } } + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Horned; } } + public override int Scales{ get{ return 2; } } + public override ScaleType ScaleType{ get{ return ( Body == 60 ? ScaleType.Yellow : ScaleType.Red ); } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + + public Drake( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/Harpy.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/Harpy.cs new file mode 100644 index 0000000..470b60b --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/Harpy.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a harpy corpse" )] + public class Harpy : BaseCreature + { + [Constructable] + public Harpy() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a harpy"; + Body = 30; + BaseSoundID = 402; + + SetStr( 96, 120 ); + SetDex( 86, 110 ); + SetInt( 51, 75 ); + + SetHits( 58, 72 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 30 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 50.1, 65.0 ); + SetSkill( SkillName.Tactics, 70.1, 100.0 ); + SetSkill( SkillName.Wrestling, 60.1, 90.0 ); + + Fame = 2500; + Karma = -2500; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager, 2 ); + } + + public override int GetAttackSound() + { + return 916; + } + + public override int GetAngerSound() + { + return 916; + } + + public override int GetDeathSound() + { + return 917; + } + + public override int GetHurtSound() + { + return 919; + } + + public override int GetIdleSound() + { + return 918; + } + + public override bool CanFly { get { return true; } } + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 4; } } + public override MeatType MeatType{ get{ return MeatType.Bird; } } + public override int Feathers{ get{ return 50; } } + + public Harpy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/Kraken.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/Kraken.cs new file mode 100644 index 0000000..5ae518c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/Kraken.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a krakens corpse" )] + public class Kraken : BaseCreature + { + [Constructable] + public Kraken() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a kraken"; + Body = 77; + BaseSoundID = 353; + + SetStr( 756, 780 ); + SetDex( 226, 245 ); + SetInt( 26, 40 ); + + SetHits( 454, 468 ); + SetMana( 0 ); + + SetDamage( 19, 33 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Cold, 30 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 15.1, 20.0 ); + SetSkill( SkillName.Tactics, 45.1, 60.0 ); + SetSkill( SkillName.Wrestling, 45.1, 60.0 ); + + Fame = 11000; + Karma = -11000; + + VirtualArmor = 50; + + CanSwim = true; + CantWalk = true; + + Rope rope = new Rope(); + rope.ItemID = 0x14F8; + PackItem( rope ); + + if( Utility.RandomDouble() < .05 ) + PackItem( new MessageInABottle() ); + + PackItem( new SpecialFishingNet() ); //Confirm? + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich ); + } + + public override int TreasureMapLevel{ get{ return 4; } } + + public Kraken( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/Lizardman.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/Lizardman.cs new file mode 100644 index 0000000..6677823 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/Lizardman.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a lizardman corpse" )] + public class Lizardman : BaseCreature + { + public override InhumanSpeech SpeechType{ get{ return InhumanSpeech.Lizardman; } } + + [Constructable] + public Lizardman() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "lizardman" ); + Body = Utility.RandomList( 35, 36 ); + BaseSoundID = 417; + + SetStr( 96, 120 ); + SetDex( 86, 105 ); + SetInt( 36, 60 ); + + SetHits( 58, 72 ); + + SetDamage( 5, 7 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 5, 10 ); + SetResistance( ResistanceType.Cold, 5, 10 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + + SetSkill( SkillName.MagicResist, 35.1, 60.0 ); + SetSkill( SkillName.Tactics, 55.1, 80.0 ); + SetSkill( SkillName.Wrestling, 50.1, 70.0 ); + + Fame = 1500; + Karma = -1500; + + VirtualArmor = 28; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + // TODO: weapon + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + + public Lizardman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs new file mode 100644 index 0000000..fca3eaa --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/OphidianKnight.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an ophidian corpse" )] + [TypeAlias( "Server.Mobiles.OphidianAvenger" )] + public class OphidianKnight : BaseCreature + { + private static string[] m_Names = new string[] + { + "an ophidian knight-errant", + "an ophidian avenger" + }; + + [Constructable] + public OphidianKnight() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = m_Names[Utility.Random( m_Names.Length )]; + Body = 86; + BaseSoundID = 634; + + SetStr( 417, 595 ); + SetDex( 166, 175 ); + SetInt( 46, 70 ); + + SetHits( 266, 342 ); + SetMana( 0 ); + + SetDamage( 16, 19 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 90, 100 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 10000; + Karma = -10000; + + VirtualArmor = 40; + + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + } + + public override int Meat{ get{ return 2; } } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 3; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public OphidianKnight( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs new file mode 100644 index 0000000..c618af2 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/OphidianWarrior.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an ophidian corpse" )] + public class OphidianWarrior : BaseCreature + { + private static string[] m_Names = new string[] + { + "an ophidian warrior", + "an ophidian enforcer" + }; + + [Constructable] + public OphidianWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = m_Names[Utility.Random( m_Names.Length )]; + Body = 86; + BaseSoundID = 634; + + SetStr( 150, 320 ); + SetDex( 94, 190 ); + SetInt( 64, 160 ); + + SetHits( 128, 155 ); + SetMana( 0 ); + + SetDamage( 5, 11 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 25, 35 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 25, 35 ); + + SetSkill( SkillName.MagicResist, 70.1, 85.0 ); + SetSkill( SkillName.Swords, 60.1, 85.0 ); + SetSkill( SkillName.Tactics, 75.1, 90.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 36; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Average ); + AddLoot( LootPack.Gems ); + } + + public override int Meat{ get{ return 1; } } + public override int TreasureMapLevel{ get{ return 1; } } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.TerathansAndOphidians; } + } + + public OphidianWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/Scorpion.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/Scorpion.cs new file mode 100644 index 0000000..3ea8e7e --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/Scorpion.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a scorpion corpse" )] + public class Scorpion : BaseCreature + { + [Constructable] + public Scorpion() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a scorpion"; + Body = 48; + BaseSoundID = 397; + + SetStr( 73, 115 ); + SetDex( 76, 95 ); + SetInt( 16, 30 ); + + SetHits( 50, 63 ); + SetMana( 0 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 60 ); + SetDamageType( ResistanceType.Poison, 40 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 20, 25 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 10, 15 ); + + SetSkill( SkillName.Poisoning, 80.1, 100.0 ); + SetSkill( SkillName.MagicResist, 30.1, 35.0 ); + SetSkill( SkillName.Tactics, 60.3, 75.0 ); + SetSkill( SkillName.Wrestling, 50.3, 65.0 ); + + Fame = 2000; + Karma = -2000; + + VirtualArmor = 28; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 47.1; + + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + } + + public override int Meat{ get{ return 1; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + public override PackInstinct PackInstinct{ get{ return PackInstinct.Arachnid; } } + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override Poison HitPoison{ get{ return (0.8 >= Utility.RandomDouble() ? Poison.Greater : Poison.Deadly); } } + + public Scorpion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs new file mode 100644 index 0000000..8cc083f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/StoneHarpy.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a stone harpy corpse" )] + public class StoneHarpy : BaseCreature + { + [Constructable] + public StoneHarpy() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a stone harpy"; + Body = 73; + BaseSoundID = 402; + + SetStr( 296, 320 ); + SetDex( 86, 110 ); + SetInt( 51, 75 ); + + SetHits( 178, 192 ); + SetMana( 0 ); + + SetDamage( 8, 16 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Poison, 25 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.MagicResist, 50.1, 65.0 ); + SetSkill( SkillName.Tactics, 70.1, 100.0 ); + SetSkill( SkillName.Wrestling, 70.1, 100.0 ); + + Fame = 4500; + Karma = -4500; + + VirtualArmor = 50; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average, 2 ); + AddLoot( LootPack.Gems, 2 ); + } + + public override int GetAttackSound() + { + return 916; + } + + public override int GetAngerSound() + { + return 916; + } + + public override int GetDeathSound() + { + return 917; + } + + public override int GetHurtSound() + { + return 919; + } + + public override int GetIdleSound() + { + return 918; + } + + public override bool CanFly { get { return true; } } + public override int Meat{ get{ return 1; } } + public override int Feathers{ get{ return 50; } } + + public StoneHarpy( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Reptile/Melee/Wyvern.cs b/Scripts/Mobiles/Monsters/Reptile/Melee/Wyvern.cs new file mode 100644 index 0000000..370f96f --- /dev/null +++ b/Scripts/Mobiles/Monsters/Reptile/Melee/Wyvern.cs @@ -0,0 +1,104 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a wyvern corpse" )] + public class Wyvern : BaseCreature + { + [Constructable] + public Wyvern () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a wyvern"; + Body = 62; + BaseSoundID = 362; + + SetStr( 202, 240 ); + SetDex( 153, 172 ); + SetInt( 51, 90 ); + + SetHits( 125, 141 ); + + SetDamage( 8, 19 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 35, 45 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 90, 100 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.Poisoning, 60.1, 80.0 ); + SetSkill( SkillName.MagicResist, 65.1, 80.0 ); + SetSkill( SkillName.Tactics, 65.1, 90.0 ); + SetSkill( SkillName.Wrestling, 65.1, 80.0 ); + + Fame = 4000; + Karma = -4000; + + VirtualArmor = 40; + + PackItem( new LesserPoisonPotion() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Meager ); + AddLoot( LootPack.MedScrolls ); + } + + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool CanFly { get { return true; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 2; } } + + public override int Meat{ get{ return 10; } } + public override int Hides{ get{ return 20; } } + public override HideType HideType{ get{ return HideType.Horned; } } + + public override int GetAttackSound() + { + return 713; + } + + public override int GetAngerSound() + { + return 718; + } + + public override int GetDeathSound() + { + return 716; + } + + public override int GetHurtSound() + { + return 721; + } + + public override int GetIdleSound() + { + return 725; + } + + public Wyvern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/BakeKitsune.cs b/Scripts/Mobiles/Monsters/SE/BakeKitsune.cs new file mode 100644 index 0000000..c7ef9c3 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/BakeKitsune.cs @@ -0,0 +1,277 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a bake kitsune corpse" )] + public class BakeKitsune : BaseCreature + { + + [Constructable] + public BakeKitsune() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a bake kitsune"; + Body = 246; + + SetStr( 171, 220 ); + SetDex( 126, 145 ); + SetInt( 376, 425 ); + + SetHits( 301, 350 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Energy, 30 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 70, 90 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + + SetSkill( SkillName.EvalInt, 80.1, 90.0 ); + SetSkill( SkillName.Magery, 80.1, 90.0 ); + SetSkill( SkillName.MagicResist, 80.1, 100.0 ); + SetSkill( SkillName.Tactics, 70.1, 90.0 ); + SetSkill( SkillName.Wrestling, 50.1, 55.0 ); + + Fame = 8000; + Karma = -8000; + + Tamable = true; + ControlSlots = 2; + MinTameSkill = 80.7; + + + if ( Utility.RandomDouble() < .25 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.MedScrolls, 2 ); + } + + public override int Meat{ get{ return 5; } } + public override int Hides{ get{ return 10; } } + public override HideType HideType{ get{ return HideType.Barbed; } } + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool ClickTitle{ get{ return false; } } + public override bool PropertyTitle{ get{ return false; } } + + public override void OnCombatantChange() + { + if ( Combatant == null && !IsBodyMod && !Controlled && m_DisguiseTimer == null && Utility.RandomBool() ) + m_DisguiseTimer = Timer.DelayCall( TimeSpan.FromSeconds( Utility.RandomMinMax( 15, 30 ) ), new TimerCallback( Disguise ) ); + } + + public override bool OnBeforeDeath() + { + RemoveDisguise(); + + return base.OnBeforeDeath(); + } + + #region Disguise + private Timer m_DisguiseTimer; + + public void Disguise() + { + if ( Combatant != null || IsBodyMod || Controlled ) + return; + + FixedEffect( 0x376A, 8, 32 ); + PlaySound( 0x1FE ); + + Female = Utility.RandomBool(); + + if ( Female ) + { + BodyMod = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + BodyMod = 0x190; + Name = NameList.RandomName( "male" ); + } + + Title = "the mystic llama herder"; + Hue = Race.Human.RandomSkinHue(); + HairItemID = Race.Human.RandomHair( this ); + HairHue = Race.Human.RandomHairHue(); + FacialHairItemID = Race.Human.RandomFacialHair( this ); + FacialHairHue = HairHue; + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new Shoes( Utility.RandomNeutralHue() ) ); break; + case 1: AddItem( new Boots( Utility.RandomNeutralHue() ) ); break; + case 2: AddItem( new Sandals( Utility.RandomNeutralHue() ) ); break; + case 3: AddItem( new ThighBoots( Utility.RandomNeutralHue() ) ); break; + } + + AddItem( new Robe( Utility.RandomNondyedHue() ) ); + + m_DisguiseTimer = null; + m_DisguiseTimer = Timer.DelayCall( TimeSpan.FromSeconds( 75 ), new TimerCallback( RemoveDisguise ) ); + } + + public void RemoveDisguise() + { + if ( !IsBodyMod ) + return; + + Name = "a bake kitsune"; + Title = null; + BodyMod = 0; + Hue = 0; + HairItemID = 0; + HairHue = 0; + FacialHairItemID = 0; + FacialHairHue = 0; + + DeleteItemOnLayer( Layer.OuterTorso ); + DeleteItemOnLayer( Layer.Shoes ); + + m_DisguiseTimer = null; + } + + public void DeleteItemOnLayer( Layer layer ) + { + Item item = FindItemOnLayer( layer ); + + if ( item != null ) + item.Delete(); + } + #endregion + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 > Utility.RandomDouble() ) + { + /* Blood Bath + * Start cliloc 1070826 + * Sound: 0x52B + * 2-3 blood spots + * Damage: 2 hps per second for 5 seconds + * End cliloc: 1070824 + */ + + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if ( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070825 ); // The creature continues to rage! + } + else + defender.SendLocalizedMessage( 1070826 ); // The creature goes into a rage, inflicting heavy damage! + + timer = new ExpireTimer( defender, this ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private Mobile m_From; + private int m_Count; + + public ExpireTimer( Mobile m, Mobile from ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + Stop(); + m_Table.Remove( m_Mobile ); + } + + public void DrainLife() + { + if ( m_Mobile.Alive ) + m_Mobile.Damage( 2, m_From ); + else + DoExpire(); + } + + protected override void OnTick() + { + DrainLife(); + + if ( ++m_Count >= 5 ) + { + DoExpire(); + m_Mobile.SendLocalizedMessage( 1070824 ); // The creature's rage subsides. + } + } + } + + public override int GetAngerSound() + { + return 0x4DE; + } + + public override int GetIdleSound() + { + return 0x4DD; + } + + public override int GetAttackSound() + { + return 0x4DC; + } + + public override int GetHurtSound() + { + return 0x4DF; + } + + public override int GetDeathSound() + { + return 0x4DB; + } + + public BakeKitsune( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( version == 0 && PhysicalResistance > 60 ) + { + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 70, 90 ); + SetResistance( ResistanceType.Cold, 40, 60 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + } + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( RemoveDisguise ) ); + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs b/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs new file mode 100644 index 0000000..7214046 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/DeathWatchBeetle.cs @@ -0,0 +1,146 @@ +using System; +using Server; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName( "a deathwatchbeetle corpse" )] + [TypeAlias( "Server.Mobiles.DeathWatchBeetle" )] + public class DeathwatchBeetle : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.CrushingBlow; + } + [Constructable] + public DeathwatchBeetle() : base( AIType.AI_Melee, Core.ML ? FightMode.Aggressor : FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a deathwatch beetle"; + Body = 242; + + SetStr( 136, 160 ); + SetDex( 41, 52 ); + SetInt( 31, 40 ); + + SetHits( 121, 145 ); + SetMana( 20 ); + + SetDamage( 5, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 15, 30 ); + SetResistance( ResistanceType.Cold, 15, 30 ); + SetResistance( ResistanceType.Poison, 50, 80 ); + SetResistance( ResistanceType.Energy, 20, 35 ); + + SetSkill( SkillName.MagicResist, 50.1, 58.0 ); + SetSkill( SkillName.Tactics, 67.1, 77.0 ); + SetSkill( SkillName.Wrestling, 50.1, 60.0 ); + SetSkill( SkillName.Anatomy, 30.1, 34.0 ); + + Fame = 1400; + Karma = -1400; + + switch ( Utility.Random( 12 ) ) + { + case 0: PackItem( new LeatherGorget() ); break; + case 1: PackItem( new LeatherGloves() ); break; + case 2: PackItem( new LeatherArms() ); break; + case 3: PackItem( new LeatherLegs() ); break; + case 4: PackItem( new LeatherCap() ); break; + case 5: PackItem( new LeatherChest() ); break; + } + + if ( Utility.RandomDouble() < .5 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + Tamable = true; + MinTameSkill = 41.1; + ControlSlots = 1; + } + + public override int GetAngerSound() + { + return 0x4F3; + } + + public override int GetIdleSound() + { + return 0x4F2; + } + + public override int GetAttackSound() + { + return 0x4F1; + } + + public override int GetHurtSound() + { + return 0x4F4; + } + + public override int GetDeathSound() + { + return 0x4F0; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.LowScrolls, 1 ); + AddLoot( LootPack.Potions, 1 ); + } + + public override void AlterMeleeDamageTo( Mobile to, ref int damage ) + { + if ( Utility.RandomBool() && (this.Mana > 14) && to != null ) + { + damage = (damage + (damage / 2)); + to.SendLocalizedMessage( 1060091 ); // You take extra damage from the crushing attack! + to.PlaySound( 0x1E1 ); + to.FixedParticles( 0x377A, 1, 32, 0x26da, 0, 0, 0 ); + Mana -= 15; + } + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + Mobile combatant = Combatant; + + if ( combatant == null || combatant.Deleted || combatant.Map != Map || !InRange( combatant, 12 ) || !CanBeHarmful( combatant ) || !InLOS( combatant ) ) + return; + + if( Utility.Random( 10 ) == 0 ) + PoisonAttack( combatant ); + + base.OnDamage( amount, from, willKill ); + } + + public void PoisonAttack( Mobile m ) + { + DoHarmful( m ); + this.MovingParticles( m, 0x36D4, 1, 0, false, false, 0x3F, 0, 0x1F73, 1, 0, (EffectLayer)255, 0x100 ); + m.ApplyPoison( this, Poison.Regular ); + m.SendLocalizedMessage( 1070821, this.Name ); // %s spits a poisonous substance at you! + } + + public override int Hides{ get{ return 8; } } + public DeathwatchBeetle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs b/Scripts/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs new file mode 100644 index 0000000..c8048d8 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/DeathWatchBeetleHatchling.cs @@ -0,0 +1,108 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a deathwatchbeetle hatchling corpse" )] + [TypeAlias( "Server.Mobiles.DeathWatchBeetleHatchling" )] + public class DeathwatchBeetleHatchling : BaseCreature + { + [Constructable] + public DeathwatchBeetleHatchling() : base( AIType.AI_Melee, Core.ML ? FightMode.Aggressor : FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a deathwatch beetle hatchling"; + Body = 242; + + SetStr( 26, 50 ); + SetDex( 41, 52 ); + SetInt( 21, 30 ); + + SetHits( 51, 60 ); + SetMana( 20 ); + + SetDamage( 2, 8 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 40 ); + SetResistance( ResistanceType.Fire, 15, 30 ); + SetResistance( ResistanceType.Cold, 15, 30 ); + SetResistance( ResistanceType.Poison, 20, 40 ); + SetResistance( ResistanceType.Energy, 20, 35 ); + + SetSkill( SkillName.Wrestling, 30.1, 40.0 ); + SetSkill( SkillName.Tactics, 47.1, 57.0 ); + SetSkill( SkillName.MagicResist, 30.1, 38.0 ); + SetSkill( SkillName.Anatomy, 20.1, 24.0 ); + + Fame = 700; + Karma = -700; + + + if( Utility.RandomBool() ) + { + Item i = Loot.RandomReagent(); + i.Amount = 3; + PackItem( i ); + } + + switch ( Utility.Random( 12 ) ) + { + case 0: PackItem( new LeatherGorget() ); break; + case 1: PackItem( new LeatherGloves() ); break; + case 2: PackItem( new LeatherArms() ); break; + case 3: PackItem( new LeatherLegs() ); break; + case 4: PackItem( new LeatherCap() ); break; + case 5: PackItem( new LeatherChest() ); break; + } + } + + public override int GetAngerSound() + { + return 0x4F3; + } + + public override int GetIdleSound() + { + return 0x4F2; + } + + public override int GetAttackSound() + { + return 0x4F1; + } + + public override int GetHurtSound() + { + return 0x4F4; + } + + public override int GetDeathSound() + { + return 0x4F0; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.LowScrolls, 1 ); + AddLoot( LootPack.Potions, 1 ); + } + + public DeathwatchBeetleHatchling( Serial serial ) : base( serial ) + { + } + public override int Hides{ get{ return 8; } } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/EliteNinja.cs b/Scripts/Mobiles/Monsters/SE/EliteNinja.cs new file mode 100644 index 0000000..0fd8598 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/EliteNinja.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class EliteNinja : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public EliteNinja() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + Name = "an elite ninja"; + + Body = ( this.Female = Utility.RandomBool() ) ? 0x191 : 0x190; + + SetHits( 251, 350 ); + + SetStr( 126, 225 ); + SetDex( 81, 95 ); + SetInt( 151, 165 ); + + SetDamage( 12, 20 ); + + SetDamageType( ResistanceType.Physical, 65 ); + SetDamageType( ResistanceType.Fire, 15 ); + SetDamageType( ResistanceType.Poison, 15 ); + SetDamageType( ResistanceType.Energy, 5 ); + + SetResistance( ResistanceType.Physical, 35, 65 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 25, 45 ); + SetResistance( ResistanceType.Poison, 40, 60 ); + SetResistance( ResistanceType.Energy, 35, 55 ); + + SetSkill( SkillName.Anatomy, 105.0, 120.0 ); + SetSkill( SkillName.MagicResist, 80.0, 100.0 ); + SetSkill( SkillName.Tactics, 115.0, 130.0 ); + SetSkill( SkillName.Wrestling, 95.0, 120.0 ); + SetSkill( SkillName.Fencing, 95.0, 120.0 ); + SetSkill( SkillName.Macing, 95.0, 120.0 ); + SetSkill( SkillName.Swords, 95.0, 120.0 ); + SetSkill( SkillName.Ninjitsu, 95.0, 120.0 ); + + + Fame = 8500; + Karma = -8500; + + /* TODO: + Uses Smokebombs + Hides + Stealths + Can use Ninjitsu Abilities + Can change weapons during a fight + */ + + + AddItem( new NinjaTabi() ); + AddItem( new LeatherNinjaJacket()); + AddItem( new LeatherNinjaHood()); + AddItem( new LeatherNinjaPants()); + AddItem( new LeatherNinjaMitts()); + + if( Utility.RandomDouble() < 0.33 ) + AddItem( new SmokeBomb() ); + + switch ( Utility.Random( 8 )) + { + case 0: AddItem( new Tessen() ); break; + case 1: AddItem( new Wakizashi() ); break; + case 2: AddItem( new Nunchaku() ); break; + case 3: AddItem( new Daisho() ); break; + case 4: AddItem( new Sai() ); break; + case 5: AddItem( new Tekagi() ); break; + case 6: AddItem( new Kama() ); break; + case 7: AddItem( new Katana() ); break; + } + + Utility.AssignRandomHair( this ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + c.DropItem( new BookOfNinjitsu() ); + } + + public override bool BardImmune{ get{ return true; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public EliteNinja( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/FanDancer.cs b/Scripts/Mobiles/Monsters/SE/FanDancer.cs new file mode 100644 index 0000000..8244136 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/FanDancer.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a fan dancer corpse" )] + public class FanDancer : BaseCreature + { + [Constructable] + public FanDancer() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fan dancer"; + Body = 247; + BaseSoundID = 0x372; + + SetStr( 301, 375 ); + SetDex( 201, 255 ); + SetInt( 21, 25 ); + + SetHits( 351, 430 ); + + SetDamage( 12, 17 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Cold, 10 ); + SetDamageType( ResistanceType.Poison, 10 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 50, 70 ); + SetResistance( ResistanceType.Cold, 50, 70 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + + SetSkill( SkillName.MagicResist, 100.1, 110.0 ); + SetSkill( SkillName.Tactics, 85.1, 95.0 ); + SetSkill( SkillName.Wrestling, 85.1, 95.0 ); + SetSkill( SkillName.Anatomy, 85.1, 95.0 ); + + Fame = 9000; + Karma = -9000; + + if ( Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + AddItem( new Tessen() ); + + if ( 0.02 >= Utility.RandomDouble() ) + PackItem( new OrigamiPaper() ); + } + + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool Uncalmable{ get{ return true; } } + + /* TODO: Repel Magic + * 10% chance of repelling a melee attack (why did they call it repel magic anyway?) + * Cliloc: 1070844 + * Effect: damage is dealt to the attacker, no damage is taken by the fan dancer + */ + + public override void OnDamagedBySpell( Mobile attacker ) + { + base.OnDamagedBySpell( attacker ); + + if ( 0.8 > Utility.RandomDouble() && !attacker.InRange( this, 1 ) ) + { + /* Fan Throw + * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" + * Damage: 50-65 + */ + Effects.SendPacket( attacker, attacker.Map, new HuedEffect( EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, this.Location, attacker.Location, 10, 0, false, false, 0, 0 ) ); + AOS.Damage( attacker, this, Utility.RandomMinMax( 50, 65 ), 100, 0, 0, 0, 0 ); + } + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.8 > Utility.RandomDouble() && !attacker.InRange( this, 1 ) ) + { + /* Fan Throw + * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" + * Damage: 50-65 + */ + Effects.SendPacket( attacker, attacker.Map, new HuedEffect( EffectType.Moving, Serial.Zero, Serial.Zero, 0x27A3, this.Location, attacker.Location, 10, 0, false, false, 0, 0 ) ); + AOS.Damage( attacker, this, Utility.RandomMinMax( 50, 65 ), 100, 0, 0, 0, 0 ); + } + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( !IsFanned( defender ) && 0.05 > Utility.RandomDouble() ) + { + /* Fanning Fire + * Graphic: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x3709" ItemIdName: "fire column" FromLocation: "(994 325, 16)" ToLocation: "(994 325, 16)" Speed: "10" Duration: "30" FixedDirection: "True" Explode: "False" Hue: "0x0" RenderMode: "0x0" Effect: "0x34" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x57D4F5B" Layer: "5" Unknown: "0x0" + * Sound: 0x208 + * Start cliloc: 1070833 + * Effect: Fire res -10% for 10 seconds + * Damage: 35-45, 100% fire + * End cliloc: 1070834 + * Effect does not stack + */ + + defender.SendLocalizedMessage( 1070833 ); // The creature fans you with fire, reducing your resistance to fire attacks. + + int effect = -(defender.FireResistance / 10); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Fire, effect ); + + defender.FixedParticles( 0x37B9, 10, 30, 0x34, EffectLayer.RightFoot ); + defender.PlaySound( 0x208 ); + + // This should be done in place of the normal attack damage. + //AOS.Damage( defender, this, Utility.RandomMinMax( 35, 45 ), 0, 100, 0, 0, 0 ); + + defender.AddResistanceMod( mod ); + + ExpireTimer timer = new ExpireTimer( defender, mod, TimeSpan.FromSeconds( 10.0 ) ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + public bool IsFanned( Mobile m ) + { + return m_Table.Contains( m ); + } + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + + public ExpireTimer( Mobile m, ResistanceMod mod, TimeSpan delay ) : base( delay ) + { + m_Mobile = m; + m_Mod = mod; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1070834 ); // Your resistance to fire attacks has returned. + m_Mobile.RemoveResistanceMod( m_Mod ); + Stop(); + m_Table.Remove( m_Mobile ); + } + } + + public FanDancer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/FireBeetle.cs b/Scripts/Mobiles/Monsters/SE/FireBeetle.cs new file mode 100644 index 0000000..320b864 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/FireBeetle.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a fire beetle corpse" )] + [Server.Engines.Craft.Forge] + public class FireBeetle : BaseMount + { + public override bool SubdueBeforeTame{ get{ return true; } } // Must be beaten into submission + public override bool StatLossAfterTame{ get{ return true; } } + public virtual double BoostedSpeed { get { return 0.1; } } + public override bool ReduceSpeedWithDamage { get { return false; } } + + + [Constructable] + public FireBeetle() : base( "a fire beetle", 0xA9, 0x3E95, AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SetStr( 300 ); + SetDex( 100 ); + SetInt( 500 ); + + SetHits( 200 ); + + SetDamage( 7, 20 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Fire, 100 ); + + SetResistance( ResistanceType.Physical, 40 ); + SetResistance( ResistanceType.Fire, 70, 75 ); + SetResistance( ResistanceType.Cold, 10 ); + SetResistance( ResistanceType.Poison, 30 ); + SetResistance( ResistanceType.Energy, 30 ); + + SetSkill( SkillName.MagicResist, 90.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 4000; + Karma = -4000; + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + + PackItem( new SulfurousAsh( Utility.RandomMinMax( 16, 25 ) ) ); + PackItem( new IronIngot( 2 ) ); + + Hue = 0x489; + } + + public override void OnHarmfulSpell(Mobile from) + { + if (!Controlled && ControlMaster == null) + CurrentSpeed = BoostedSpeed; + } + + public override void OnCombatantChange() + { + if (Combatant == null && !Controlled && ControlMaster == null) + CurrentSpeed = PassiveSpeed; + } + + public override bool OverrideBondingReqs() + { + return true; + } + + public override int GetAngerSound() + { + return 0x21D; + } + + public override int GetIdleSound() + { + return 0x21D; + } + + public override int GetAttackSound() + { + return 0x162; + } + + public override int GetHurtSound() + { + return 0x163; + } + + public override int GetDeathSound() + { + return 0x21D; + } + + + public override int Meat{ get{ return 16; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat; } } + + public override double GetControlChance( Mobile m, bool useBaseSkill ) + { + return 1.0; + } + + public FireBeetle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if( version == 0 ) + Hue = 0x489; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/Kappa.cs b/Scripts/Mobiles/Monsters/SE/Kappa.cs new file mode 100644 index 0000000..e062e57 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/Kappa.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections; +using Server; +using Server.Network; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a kappa corpse" )] + public class Kappa : BaseCreature + { + + [Constructable] + public Kappa() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a kappa"; + Body = 240; + + SetStr( 186, 230 ); + SetDex( 51, 75 ); + SetInt( 41, 55 ); + + SetMana ( 30 ); + + SetHits( 151, 180 ); + + SetDamage( 6, 12 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 35, 50 ); + SetResistance( ResistanceType.Fire, 35, 50 ); + SetResistance( ResistanceType.Cold, 25, 50 ); + SetResistance( ResistanceType.Poison, 35, 50 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 60.1, 70.0 ); + SetSkill( SkillName.Tactics, 79.1, 89.0 ); + SetSkill( SkillName.Wrestling, 60.1, 70.0 ); + + Fame = 1700; + Karma = -1700; + + PackItem( new RawFishSteak( 3 ) ); + for( int i = 0; i < 2; i++ ) + { + switch ( Utility.Random( 6 ) ) + { + case 0: PackItem( new Gears() ); break; + case 1: PackItem( new Hinge() ); break; + case 2: PackItem( new Axle() ); break; + } + } + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(4) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Meager ); + AddLoot( LootPack.Average ); + } + + public override int GetAngerSound() + { + return 0x50B; + } + + public override int GetIdleSound() + { + return 0x50A; + } + + public override int GetAttackSound() + { + return 0x509; + } + + public override int GetHurtSound() + { + return 0x50C; + } + + public override int GetDeathSound() + { + return 0x508; + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack (defender); + + if ( Utility.RandomBool() ) + { + if ( !IsBeingDrained( defender ) && Mana > 14) + { + defender.SendLocalizedMessage( 1070848 ); // You feel your life force being stolen away. + BeginLifeDrain( defender, this ); + Mana-=15; + } + } + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsBeingDrained( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static void BeginLifeDrain( Mobile m, Mobile from ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + t = new InternalTimer( from, m ); + m_Table[m] = t; + + t.Start(); + } + + public static void DrainLife( Mobile m, Mobile from ) + { + if ( m.Alive ) + { + int damageGiven = AOS.Damage( m, from, 5, 0, 0, 0, 0, 100 ); + from.Hits += damageGiven; + } + else + { + EndLifeDrain( m ); + } + } + + public static void EndLifeDrain( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + m_Table.Remove( m ); + + m.SendLocalizedMessage( 1070849 ); // The drain on your life force is gone. + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + if ( from != null && from.Map != null ) + { + int amt=0; + Mobile target = this; + int rand = Utility.Random( 1, 100 ); + if ( willKill ) + { + amt = ((( rand % 5 ) >> 2 ) + 3); + } + if ( ( Hits < 100 ) && ( rand < 21 ) ) + { + target = ( rand % 2 ) < 1 ? this : from; + amt++; + } + if ( amt > 0 ) + { + SpillAcid( target, amt ); + from.SendLocalizedMessage( 1070820 ); + if ( Mana > 14) + Mana -= 15; + amt ^= amt; + } + } + base.OnDamage( amount, from, willKill ); + } + + public override Item NewHarmfulItem() + { + return new AcidSlime( TimeSpan.FromSeconds(10), 5, 10 ); + } + + public Kappa( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private Mobile m_Mobile; + private int m_Count; + + public InternalTimer( Mobile from, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_From = from; + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + DrainLife( m_Mobile, m_From ); + + if (Running && ++m_Count == 5) + EndLifeDrain( m_Mobile ); + } + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/KazeKemono.cs b/Scripts/Mobiles/Monsters/SE/KazeKemono.cs new file mode 100644 index 0000000..0f3a100 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/KazeKemono.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a kaze kemono corpse" )] + public class KazeKemono : BaseCreature + { + + [Constructable] + public KazeKemono() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a kaze kemono"; + Body = 196; + BaseSoundID = 655; + + SetStr( 201, 275 ); + SetDex( 101, 155 ); + SetInt( 101, 105 ); + + SetHits( 251, 330 ); + + SetDamage( 15, 20 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Cold, 10 ); + SetDamageType( ResistanceType.Poison, 10 ); + + SetResistance( ResistanceType.Physical, 50, 70 ); + SetResistance( ResistanceType.Fire, 30, 60 ); + SetResistance( ResistanceType.Cold, 30, 60 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 60, 80 ); + + SetSkill( SkillName.MagicResist, 110.1, 125.0 ); + SetSkill( SkillName.Tactics, 55.1, 65.0 ); + SetSkill( SkillName.Wrestling, 85.1, 95.0 ); + SetSkill( SkillName.Anatomy, 25.1, 35.0 ); + SetSkill( SkillName.Magery, 95.1, 105.0 ); + + Fame = 8000; + Karma = -8000; + } + + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 3 ); + } + + public override bool BleedImmune { get { return true; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if( 0.1 > Utility.RandomDouble() ) + { + /* Flurry of Twigs + * Start cliloc: 1070850 + * Effect: Physical resistance -15% for 5 seconds + * End cliloc: 1070852 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(1048 779, 6)" ToLocation: "(1048 779, 6)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + */ + + ExpireTimer timer = (ExpireTimer)m_FlurryOfTwigsTable[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070851 ); // The creature lands another blow in your weakened state. + } + else + defender.SendLocalizedMessage( 1070850 ); // The creature's flurry of twigs has made you more susceptible to physical attacks! + + int effect = -(defender.PhysicalResistance * 15 / 100); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Physical, effect ); + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.AddResistanceMod( mod ); + + timer = new ExpireTimer( defender, mod, m_FlurryOfTwigsTable, TimeSpan.FromSeconds( 5.0 ) ); + timer.Start(); + m_FlurryOfTwigsTable[defender] = timer; + } + else if( 0.05 > Utility.RandomDouble() ) + { + /* Chlorophyl Blast + * Start cliloc: 1070827 + * Effect: Energy resistance -50% for 10 seconds + * End cliloc: 1070829 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(1048 779, 6)" ToLocation: "(1048 779, 6)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + */ + + ExpireTimer timer = (ExpireTimer)m_ChlorophylBlastTable[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070828 ); // The creature continues to hinder your energy resistance! + } + else + defender.SendLocalizedMessage( 1070827 ); // The creature's attack has made you more susceptible to energy attacks! + + int effect = -(defender.EnergyResistance / 2); + + ResistanceMod mod = new ResistanceMod( ResistanceType.Energy, effect ); + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.AddResistanceMod( mod ); + + timer = new ExpireTimer( defender, mod, m_ChlorophylBlastTable, TimeSpan.FromSeconds( 10.0 ) ); + timer.Start(); + m_ChlorophylBlastTable[defender] = timer; + } + } + + private static Hashtable m_FlurryOfTwigsTable = new Hashtable(); + private static Hashtable m_ChlorophylBlastTable = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod m_Mod; + private Hashtable m_Table; + + public ExpireTimer( Mobile m, ResistanceMod mod, Hashtable table, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + m_Mod = mod; + m_Table = table; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.RemoveResistanceMod( m_Mod ); + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + if( m_Mod.Type == ResistanceType.Physical ) + m_Mobile.SendLocalizedMessage( 1070852 ); // Your resistance to physical attacks has returned. + else + m_Mobile.SendLocalizedMessage( 1070829 ); // Your resistance to energy attacks has returned. + + DoExpire(); + } + } + + public KazeKemono( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/LadyOfTheSnow.cs b/Scripts/Mobiles/Monsters/SE/LadyOfTheSnow.cs new file mode 100644 index 0000000..ccbdb3f --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/LadyOfTheSnow.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a lady of the snow corpse" )] + public class LadyOfTheSnow : BaseCreature + { + [Constructable] + public LadyOfTheSnow() + : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a lady of the snow"; + Body = 252; + BaseSoundID = 0x482; + + SetStr( 276, 305 ); + SetDex( 106, 125 ); + SetInt( 471, 495 ); + + SetHits( 596, 625 ); + + SetDamage( 13, 20 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 40, 55 ); + SetResistance( ResistanceType.Cold, 70, 90 ); + SetResistance( ResistanceType.Poison, 60, 70 ); + SetResistance( ResistanceType.Energy, 65, 85 ); + + SetSkill( SkillName.Magery, 95.1, 110.0 ); + SetSkill( SkillName.MagicResist, 90.1, 105.0 ); + SetSkill( SkillName.Tactics, 80.1, 100.0 ); + SetSkill( SkillName.Wrestling, 80.1, 100.0 ); + SetSkill(SkillName.Necromancy, 90, 110.0); + SetSkill(SkillName.SpiritSpeak, 90.0, 110.0); + + Fame = 15200; + Karma = -15200; + + + PackReg( 3 ); + PackItem( new Necklace() ); + + if ( 0.25 > Utility.RandomDouble() ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + } + + public override int GetDeathSound() + { + return 0x370; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + } + + public override bool BleedImmune { get { return true; } } + public override bool CanRummageCorpses { get { return true; } } + public override int TreasureMapLevel { get { return 4; } } + + // TODO: Snowball + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if( 0.1 > Utility.RandomDouble() ) + { + /* Cold Wind + * Graphics: Message - Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(928 164, 34)" ToLocation: "(928 164, 34)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Start cliloc: 1070832 + * Damage: 1hp per second for 5 seconds + * End cliloc: 1070830 + * Reset cliloc: 1070831 + */ + + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070831 ); // The freezing wind continues to blow! + } + else + defender.SendLocalizedMessage( 1070832 ); // An icy wind surrounds you, freezing your lungs as you breathe! + + timer = new ExpireTimer( defender, this ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private Mobile m_From; + private int m_Count; + + public ExpireTimer( Mobile m, Mobile from ) + : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + Stop(); + m_Table.Remove( m_Mobile ); + } + + public void DrainLife() + { + if( m_Mobile.Alive ) + m_Mobile.Damage( 2, m_From ); + else + DoExpire(); + } + + protected override void OnTick() + { + DrainLife(); + + if( ++m_Count >= 5 ) + { + DoExpire(); + m_Mobile.SendLocalizedMessage( 1070830 ); // The icy wind dissipates. + } + } + } + + public LadyOfTheSnow( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/Oni.cs b/Scripts/Mobiles/Monsters/SE/Oni.cs new file mode 100644 index 0000000..59534cf --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/Oni.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an oni corpse" )] + public class Oni : BaseCreature + { + [Constructable] + public Oni() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an oni"; + Body = 241; + + SetStr( 801, 910 ); + SetDex( 151, 300 ); + SetInt( 171, 195 ); + + SetHits( 401, 530 ); + + SetDamage( 14, 20 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 65, 80 ); + SetResistance( ResistanceType.Fire, 50, 70 ); + SetResistance( ResistanceType.Cold, 35, 50 ); + SetResistance( ResistanceType.Poison, 45, 70 ); + SetResistance( ResistanceType.Energy, 45, 65 ); + + SetSkill( SkillName.EvalInt, 100.1, 125.0 ); + SetSkill( SkillName.Magery, 96.1, 106.0 ); + SetSkill( SkillName.Anatomy, 85.1, 95.0 ); + SetSkill( SkillName.MagicResist, 85.1, 100.0 ); + SetSkill( SkillName.Tactics, 86.1, 101.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 12000; + Karma = -12000; + + if ( Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + // TODO: Brain (0x1CF0) or Skull (0x1AE3) or Body Part (0x1CE3) + } + + public override int GetAngerSound() + { + return 0x4E3; + } + + public override int GetIdleSound() + { + return 0x4E2; + } + + public override int GetAttackSound() + { + return 0x4E1; + } + + public override int GetHurtSound() + { + return 0x4E4; + } + + public override int GetDeathSound() + { + return 0x4E0; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 4; } } + + /* TODO: Angry Fire + * cliloc 1070823 + * Action: 4 4 1 true false 1 + * Damage: 50-85, 60 phys, 20 fire, 20 nrgy according to the guide + * With 45/49/70 res I got 48 + * 50: 30/10/10 -> 16 + 5 + 3 = 24 + * 85: 51/17/17 -> 28 + 8 + 5 = 41 + */ + + public Oni( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/RaiJu.cs b/Scripts/Mobiles/Monsters/SE/RaiJu.cs new file mode 100644 index 0000000..0db2223 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/RaiJu.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a rai-ju corpse" )] + public class RaiJu : BaseCreature + { + [Constructable] + public RaiJu() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Rai-Ju"; + Body = 199; + BaseSoundID = 0x346; + + SetStr( 151, 225 ); + SetDex( 81, 135 ); + SetInt( 176, 180 ); + + SetHits( 201, 280 ); + + SetDamage( 12, 15 ); + + SetDamageType( ResistanceType.Physical, 10 ); + SetDamageType( ResistanceType.Fire, 10 ); + SetDamageType( ResistanceType.Cold, 10 ); + SetDamageType( ResistanceType.Poison, 10 ); + SetDamageType( ResistanceType.Energy, 60 ); + + SetResistance( ResistanceType.Physical, 45, 65 ); + SetResistance( ResistanceType.Fire, 70, 85 ); + SetResistance( ResistanceType.Cold, 30, 60 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 60, 80 ); + + SetSkill( SkillName.Wrestling, 85.1, 95.0 ); + SetSkill( SkillName.Tactics, 55.1, 65.0 ); + SetSkill( SkillName.MagicResist, 110.1, 125.0 ); + SetSkill( SkillName.Anatomy, 25.1, 35.0 ); + + Fame = 8000; + Karma = -8000; + + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + AddLoot( LootPack.Gems, 2 ); + } + public override bool BleedImmune{ get{ return true; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 > Utility.RandomDouble() && !IsStunned( defender ) ) + { + /* Lightning Fist + * Cliloc: 1070839 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Damage: 35-65, 100% energy, resistable + * Freezes for 4 seconds + * Effect cannot stack + */ + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.SendLocalizedMessage( 1070839 ); // The creature attacks with stunning force! + + // This should be done in place of the normal attack damage. + //AOS.Damage( defender, this, Utility.RandomMinMax( 35, 65 ), 0, 0, 0, 0, 100 ); + + defender.Frozen = true; + + ExpireTimer timer = new ExpireTimer( defender, TimeSpan.FromSeconds( 4.0 ) ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + public bool IsStunned( Mobile m ) + { + return m_Table.Contains( m ); + } + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + + public ExpireTimer( Mobile m, TimeSpan delay ) : base( delay ) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + m_Mobile.Frozen = false; + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1005603 ); // You can move again! + DoExpire(); + } + } + + public RaiJu( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/RevenantLion.cs b/Scripts/Mobiles/Monsters/SE/RevenantLion.cs new file mode 100644 index 0000000..c6e67a0 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/RevenantLion.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a revenant lion corpse" )] + public class RevenantLion : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + [Constructable] + public RevenantLion() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a Revenant Lion"; + Body = 251; + + SetStr( 276, 325 ); + SetDex( 156, 175 ); + SetInt( 76, 105 ); + + SetHits( 251, 280 ); + + SetDamage( 18, 24 ); + + SetDamageType( ResistanceType.Physical, 30 ); + SetDamageType( ResistanceType.Cold, 30 ); + SetDamageType( ResistanceType.Poison, 10 ); + SetDamageType( ResistanceType.Energy, 30 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 55, 65 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 80.1, 90.0 ); + SetSkill( SkillName.Magery, 80.1, 90.0 ); + SetSkill( SkillName.Poisoning, 120.1, 130.0 ); + SetSkill( SkillName.MagicResist, 70.1, 90.0 ); + SetSkill( SkillName.Tactics, 60.1, 80.0 ); + SetSkill( SkillName.Wrestling, 80.1, 88.0 ); + + Fame = 4000; + Karma = -4000; + PackNecroReg( 6, 8 ); + + switch ( Utility.Random( 10 )) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: PackItem( new RibCage() ); break; + case 6: PackItem( new BonePile() ); break; + case 7: PackItem( new BonePile() ); break; + case 8: PackItem( new BonePile() ); break; + case 9: PackItem( new BonePile() ); break; + } + } + + public override int GetAngerSound() + { + return 0x518; + } + + public override int GetIdleSound() + { + return 0x517; + } + + public override int GetAttackSound() + { + return 0x516; + } + + public override int GetHurtSound() + { + return 0x519; + } + + public override int GetDeathSound() + { + return 0x515; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + AddLoot( LootPack.MedScrolls, 2 ); + + // TODO: Bone Pile + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override Poison HitPoison{ get{ return Poison.Greater; } } + + public RevenantLion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/Ronin.cs b/Scripts/Mobiles/Monsters/SE/Ronin.cs new file mode 100644 index 0000000..4c4b6ee --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/Ronin.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a ronin corpse" )] + public class Ronin : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public Ronin() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + Name = "a ronin"; + Body = (( this.Female = Utility.RandomBool() ) ? Body = 0x191 : Body = 0x190); + + Hue = Utility.RandomSkinHue(); + + SetStr( 326, 375 ); + SetDex( 31, 45 ); + SetInt( 101, 110 ); + + SetHits( 301, 400 ); + SetMana( 101, 110 ); + + SetDamage( 17, 25 ); + + SetDamageType( ResistanceType.Physical, 90 ); + SetDamageType( ResistanceType.Poison, 10 ); + + SetResistance( ResistanceType.Physical, 55, 75 ); + SetResistance( ResistanceType.Fire, 40, 60 ); + SetResistance( ResistanceType.Cold, 35, 55 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 55, 75 ); + + SetSkill( SkillName.MagicResist, 42.6, 57.5 ); + SetSkill( SkillName.Tactics, 115.1, 130.0 ); + SetSkill( SkillName.Wrestling, 92.6, 107.5 ); + SetSkill( SkillName.Anatomy, 110.1, 125.0 ); + + SetSkill( SkillName.Fencing, 92.6, 107.5 ); + SetSkill( SkillName.Macing, 92.6, 107.5 ); + SetSkill( SkillName.Swords, 92.6, 107.5 ); + + Fame = 8500; + Karma = -8500; + + AddItem( new SamuraiTabi() ); + AddItem( new LeatherHiroSode()); + AddItem( new LeatherDo()); + + switch ( Utility.Random( 4 )) + { + case 0: AddItem( new LightPlateJingasa()); break; + case 1: AddItem( new ChainHatsuburi() ); break; + case 2: AddItem( new DecorativePlateKabuto() ); break; + case 3: AddItem( new LeatherJingasa()); break; + } + + switch ( Utility.Random( 3 )) + { + case 0: AddItem( new StuddedHaidate()); break; + case 1: AddItem( new LeatherSuneate() ); break; + case 2: AddItem( new PlateSuneate() ); break; + } + + + + if( Utility.RandomDouble() > .2 ) + AddItem( new NoDachi() ); + else + AddItem( new Halberd() ); + + PackItem( new Wakizashi() ); + PackItem( new Longsword() ); + + Utility.AssignRandomHair( this ); + } + + public override void OnDeath( Container c ) + { + base.OnDeath( c ); + c.DropItem( new BookOfBushido() ); + } + + // TODO: Bushido abilities + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool BardImmune{ get{ return true; } } + public override bool CanRummageCorpses{ get{ return true; } } + + public Ronin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs b/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs new file mode 100644 index 0000000..0fe242a --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/RuneBeetle.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a rune beetle corpse" )] + public class RuneBeetle : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.BleedAttack; + } + + [Constructable] + public RuneBeetle() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a rune beetle"; + Body = 244; + + SetStr( 401, 460 ); + SetDex( 121, 170 ); + SetInt( 376, 450 ); + + SetHits( 301, 360 ); + + SetDamage( 15, 22 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Poison, 10 ); + SetDamageType( ResistanceType.Energy, 70 ); + + SetResistance( ResistanceType.Physical, 40, 65 ); + SetResistance( ResistanceType.Fire, 35, 50 ); + SetResistance( ResistanceType.Cold, 35, 50 ); + SetResistance( ResistanceType.Poison, 75, 95 ); + SetResistance( ResistanceType.Energy, 40, 60 ); + + SetSkill( SkillName.EvalInt, 100.1, 125.0 ); + SetSkill( SkillName.Magery, 100.1, 110.0 ); + SetSkill( SkillName.Poisoning, 120.1, 140.0 ); + SetSkill( SkillName.MagicResist, 95.1, 110.0 ); + SetSkill( SkillName.Tactics, 78.1, 93.0 ); + SetSkill( SkillName.Wrestling, 70.1, 77.5 ); + + Fame = 15000; + Karma = -15000; + + + if ( Utility.RandomDouble() < .25 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + switch ( Utility.Random( 10 )) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: PackItem( new RibCage() ); break; + case 6: PackItem( new BonePile() ); break; + case 7: PackItem( new BonePile() ); break; + case 8: PackItem( new BonePile() ); break; + case 9: PackItem( new BonePile() ); break; + } + + Tamable = true; + ControlSlots = 3; + MinTameSkill = 93.9; + + } + + public override int GetAngerSound() + { + return 0x4E8; + } + + public override int GetIdleSound() + { + return 0x4E7; + } + + public override int GetAttackSound() + { + return 0x4E6; + } + + public override int GetHurtSound() + { + return 0x4E9; + } + + public override int GetDeathSound() + { + return 0x4E5; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.MedScrolls, 1 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override Poison HitPoison{ get{ return Poison.Greater; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + public override bool CanAngerOnTame { get { return true; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.05 > Utility.RandomDouble() ) + { + /* Rune Corruption + * Start cliloc: 1070846 "The creature magically corrupts your armor!" + * Effect: All resistances -70 (lowest 0) for 5 seconds + * End ASCII: "The corruption of your armor has worn off" + */ + + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if ( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070845 ); // The creature continues to corrupt your armor! + } + else + defender.SendLocalizedMessage( 1070846 ); // The creature magically corrupts your armor! + + List mods = new List(); + + if ( Core.ML ) + { + if ( defender.PhysicalResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Physical, -(defender.PhysicalResistance / 2) ) ); + + if ( defender.FireResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Fire, -(defender.FireResistance / 2) ) ); + + if ( defender.ColdResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Cold, -(defender.ColdResistance / 2) ) ); + + if ( defender.PoisonResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Poison, -(defender.PoisonResistance / 2) ) ); + + if ( defender.EnergyResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Energy, -(defender.EnergyResistance / 2) ) ); + } + else + { + if ( defender.PhysicalResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Physical, (defender.PhysicalResistance > 70) ? -70 : -defender.PhysicalResistance ) ); + + if ( defender.FireResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Fire, (defender.FireResistance > 70) ? -70 : -defender.FireResistance ) ); + + if ( defender.ColdResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Cold, (defender.ColdResistance > 70) ? -70 : -defender.ColdResistance ) ); + + if ( defender.PoisonResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Poison, (defender.PoisonResistance > 70) ? -70 : -defender.PoisonResistance ) ); + + if ( defender.EnergyResistance > 0 ) + mods.Add( new ResistanceMod( ResistanceType.Energy, (defender.EnergyResistance > 70) ? -70 : -defender.EnergyResistance ) ); + } + + for ( int i = 0; i < mods.Count; ++i ) + defender.AddResistanceMod( mods[i] ); + + defender.FixedEffect( 0x37B9, 10, 5 ); + + timer = new ExpireTimer( defender, mods, TimeSpan.FromSeconds( 5.0 ) ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private List m_Mods; + + public ExpireTimer( Mobile m, List mods, TimeSpan delay ) : base( delay ) + { + m_Mobile = m; + m_Mods = mods; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + for ( int i = 0; i < m_Mods.Count; ++i ) + m_Mobile.RemoveResistanceMod( m_Mods[i] ); + + Stop(); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendMessage( "The corruption of your armor has worn off" ); + DoExpire(); + } + } + + public RuneBeetle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if( version < 1 ) + { + for ( int i = 0; i < Skills.Length; ++i ) + { + Skills[i].Cap = Math.Max( 100.0, Skills[i].Cap * 0.9 ); + + if ( Skills[i].Base > Skills[i].Cap ) + { + Skills[i].Base = Skills[i].Cap; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/TsukiWolf.cs b/Scripts/Mobiles/Monsters/SE/TsukiWolf.cs new file mode 100644 index 0000000..84fed55 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/TsukiWolf.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "a tsuki wolf corpse" )] + public class TsukiWolf : BaseCreature + { + [Constructable] + public TsukiWolf() + : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a tsuki wolf"; + Body = 250; + + switch( Utility.Random( 3 ) ) + { + case 0: Hue = Utility.RandomNeutralHue(); break; //No, this really isn't accurate ;-> + } + + SetStr( 401, 450 ); + SetDex( 151, 200 ); + SetInt( 66, 76 ); + + SetHits( 376, 450 ); + SetMana( 40 ); + + SetDamage( 14, 18 ); + + SetDamageType( ResistanceType.Physical, 90 ); + SetDamageType( ResistanceType.Cold, 5 ); + SetDamageType( ResistanceType.Energy, 5 ); + + SetResistance( ResistanceType.Physical, 40, 60 ); + SetResistance( ResistanceType.Fire, 50, 70 ); + SetResistance( ResistanceType.Cold, 50, 70 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 50, 70 ); + + SetSkill( SkillName.Anatomy, 65.1, 72.0 ); + SetSkill( SkillName.MagicResist, 65.1, 70.0 ); + SetSkill( SkillName.Tactics, 95.1, 110.0 ); + SetSkill( SkillName.Wrestling, 97.6, 107.5 ); + + Fame = 8500; + Karma = -8500; + + if ( Core.ML && Utility.RandomDouble() < .33 ) + PackItem( Engines.Plants.Seed.RandomPeculiarSeed(1) ); + + switch( Utility.Random( 10 ) ) + { + case 0: PackItem( new LeftArm() ); break; + case 1: PackItem( new RightArm() ); break; + case 2: PackItem( new Torso() ); break; + case 3: PackItem( new Bone() ); break; + case 4: PackItem( new RibCage() ); break; + case 5: PackItem( new RibCage() ); break; + case 6: PackItem( new BonePile() ); break; + case 7: PackItem( new BonePile() ); break; + case 8: PackItem( new BonePile() ); break; + case 9: PackItem( new BonePile() ); break; + } + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + AddLoot( LootPack.Rich ); + } + public override int Meat { get { return 4; } } + public override int Hides { get { return 25; } } + public override FoodType FavoriteFood { get { return FoodType.Meat; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if( 0.1 > Utility.RandomDouble() ) + { + /* Blood Bath + * Start cliloc 1070826 + * Sound: 0x52B + * 2-3 blood spots + * Damage: 2 hps per second for 5 seconds + * End cliloc: 1070824 + */ + + ExpireTimer timer = (ExpireTimer)m_Table[defender]; + + if( timer != null ) + { + timer.DoExpire(); + defender.SendLocalizedMessage( 1070825 ); // The creature continues to rage! + } + else + defender.SendLocalizedMessage( 1070826 ); // The creature goes into a rage, inflicting heavy damage! + + timer = new ExpireTimer( defender, this ); + timer.Start(); + m_Table[defender] = timer; + } + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private Mobile m_From; + private int m_Count; + + public ExpireTimer( Mobile m, Mobile from ) + : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_From = from; + Priority = TimerPriority.TwoFiftyMS; + } + + public void DoExpire() + { + Stop(); + m_Table.Remove( m_Mobile ); + } + + public void DrainLife() + { + if( m_Mobile.Alive ) + m_Mobile.Damage( 2, m_From ); + else + DoExpire(); + } + + protected override void OnTick() + { + DrainLife(); + + if( ++m_Count >= 5 ) + { + DoExpire(); + m_Mobile.SendLocalizedMessage( 1070824 ); // The creature's rage subsides. + } + } + } + + public TsukiWolf( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override int GetAngerSound() + { + return 0x52D; + } + + public override int GetIdleSound() + { + return 0x52C; + } + + public override int GetAttackSound() + { + return 0x52B; + } + + public override int GetHurtSound() + { + return 0x52E; + } + + public override int GetDeathSound() + { + return 0x52A; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/SE/Yamandon.cs b/Scripts/Mobiles/Monsters/SE/Yamandon.cs new file mode 100644 index 0000000..680e36e --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/Yamandon.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [TypeAlias( "Server.Mobiles.Yamadon" )] + [CorpseName( "a yamandon corpse" )] + public class Yamandon : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.DoubleStrike; + } + + [Constructable] + public Yamandon() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a yamandon"; + Body = 249; + + SetStr( 786, 930 ); + SetDex( 251, 365 ); + SetInt( 101, 115 ); + + SetHits( 1601, 1800 ); + + SetDamage( 19, 35 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 10 ); + + SetResistance( ResistanceType.Physical, 65, 85 ); + SetResistance( ResistanceType.Fire, 70, 90 ); + SetResistance( ResistanceType.Cold, 50, 70 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 50, 70 ); + + SetSkill( SkillName.Anatomy, 115.1, 130.0 ); + SetSkill( SkillName.MagicResist, 117.6, 132.5 ); + SetSkill( SkillName.Poisoning, 120.1, 140.0 ); + SetSkill( SkillName.Tactics, 117.1, 132.0 ); + SetSkill( SkillName.Wrestling, 112.6, 132.5 ); + + Fame = 22000; + Karma = -22000; + + if ( Utility.RandomDouble() < .50 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + PackItem( new Eggs( 2 ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich ); + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.Gems, 6 ); + } + + public override bool ReacquireOnMovement{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Utility.RandomBool() ? Poison.Deadly : Poison.Lethal; } } + public override int TreasureMapLevel{ get{ return 5; } } + public override int Hides{ get{ return 20; } } + + public override void OnDamagedBySpell( Mobile attacker ) + { + base.OnDamagedBySpell( attacker ); + + DoCounter( attacker ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + DoCounter( attacker ); + } + + private void DoCounter( Mobile attacker ) + { + if( this.Map == null ) + return; + + if ( attacker is BaseCreature && ((BaseCreature)attacker).BardProvoked ) + return; + + if ( 0.2 > Utility.RandomDouble() ) + { + /* Counterattack with Hit Poison Area + * 20-25 damage, unresistable + * Lethal poison, 100% of the time + * Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0" + * Doesn't work on provoked monsters + */ + + Mobile target = null; + + if ( attacker is BaseCreature ) + { + Mobile m = ((BaseCreature)attacker).GetMaster(); + + if( m != null ) + target = m; + } + + if ( target == null || !target.InRange( this, 18 ) ) + target = attacker; + + this.Animate( 10, 4, 1, true, false, 0 ); + + ArrayList targets = new ArrayList(); + + foreach ( Mobile m in target.GetMobilesInRange( 8 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team) ) + targets.Add( m ); + else if ( m.Player && m.Alive ) + targets.Add( m ); + } + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + DoHarmful( m ); + + AOS.Damage( m, this, Utility.RandomMinMax( 20, 25 ), true, 0, 0, 0, 100, 0 ); + + m.FixedParticles( 0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255 ); + m.ApplyPoison( this, Poison.Lethal ); + } + } + } + + public override int GetAttackSound() + { + return 1260; + } + + public override int GetAngerSound() + { + return 1262; + } + + public override int GetDeathSound() + { + return 1259; //Other Death sound is 1258... One for Yamadon, one for Serado? + } + + public override int GetHurtSound() + { + return 1263; + } + + public override int GetIdleSound() + { + return 1261; + } + + + public Yamandon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/YomotsuElder.cs b/Scripts/Mobiles/Monsters/SE/YomotsuElder.cs new file mode 100644 index 0000000..906b4a2 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/YomotsuElder.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a wrinkly yomotsu corpse" )] + public class YomotsuElder : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.DoubleStrike; + } + + [Constructable] + public YomotsuElder() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a yomotsu elder"; + Body = 255; + BaseSoundID = 0x452; + + SetStr( 686, 830 ); + SetDex( 251, 365 ); + SetInt( 17, 31 ); + + SetHits( 801, 900 ); + + SetDamage( 19, 27 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 65, 85 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 45, 65 ); + SetResistance( ResistanceType.Poison, 35, 55 ); + SetResistance( ResistanceType.Energy, 25, 50 ); + + SetSkill( SkillName.Anatomy, 115.1, 130.0 ); + SetSkill( SkillName.MagicResist, 100.1, 120.0 ); + SetSkill( SkillName.Tactics, 115.1, 130.0 ); + SetSkill( SkillName.Wrestling, 110.1, 130.0 ); + + Fame = 12000; + Karma = -12000; + + + PackItem( new GreenGourd() ); + PackItem( new ExecutionersAxe() ); + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( new LongPants() ); break; + case 1: PackItem( new ShortPants() ); break; + } + + switch ( Utility.Random( 6 ) ) + { + case 0: PackItem( new Shoes() ); break; + case 1: PackItem( new Sandals() ); break; + case 2: PackItem( new Boots() ); break; + case 3: PackItem( new ThighBoots() ); break; + } + + if ( Utility.RandomDouble() < .25 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + public override int Meat{ get{ return 1; } } + + + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 3 ); + AddLoot( LootPack.Gems, 2 ); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 5; } } + + // TODO: Axe Throw + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 > Utility.RandomDouble() ) + { + /* Maniacal laugh + * Cliloc: 1070840 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Paralyzes for 4 seconds, or until hit + */ + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.SendLocalizedMessage( 1070840 ); // You are frozen as the creature laughs maniacally. + + defender.Paralyze( TimeSpan.FromSeconds( 4.0 ) ); + } + } + + public YomotsuElder( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public override int GetIdleSound() + { + return 0x42A; + } + + public override int GetAttackSound() + { + return 0x435; + } + + public override int GetHurtSound() + { + return 0x436; + } + + public override int GetDeathSound() + { + return 0x43A; + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/YomotsuPriest.cs b/Scripts/Mobiles/Monsters/SE/YomotsuPriest.cs new file mode 100644 index 0000000..499d896 --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/YomotsuPriest.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a glowing yomotsu corpse" )] + public class YomotsuPriest : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.DoubleStrike; + } + + [Constructable] + public YomotsuPriest() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a yomotsu priest"; + Body = 253; + BaseSoundID = 0x452; + + SetStr( 486, 530 ); + SetDex( 101, 115 ); + SetInt( 601, 670 ); + + SetHits( 486, 530 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 65, 85 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 45, 65 ); + SetResistance( ResistanceType.Poison, 35, 55 ); + SetResistance( ResistanceType.Energy, 25, 50 ); + + SetSkill( SkillName.EvalInt, 92.6, 107.5 ); + SetSkill( SkillName.Magery, 105.1, 115.0 ); + SetSkill( SkillName.Meditation, 100.1, 110.0 ); + SetSkill( SkillName.MagicResist, 112.6, 122.5 ); + SetSkill( SkillName.Tactics, 55.1, 105.0 ); + SetSkill( SkillName.Wrestling, 47.6, 57.5 ); + + Fame = 9000; + Karma = -9000; + + + PackItem( new GreenGourd() ); + PackItem( new ExecutionersAxe() ); + + switch ( Utility.Random( 3 ) ) + { + case 0: PackItem( new LongPants() ); break; + case 1: PackItem( new ShortPants() ); break; + } + + switch ( Utility.Random( 6 ) ) + { + case 0: PackItem( new Shoes() ); break; + case 1: PackItem( new Sandals() ); break; + case 2: PackItem( new Boots() ); break; + case 3: PackItem( new ThighBoots() ); break; + } + + if ( Utility.RandomDouble() < .25 ) PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + } + + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + public override int Meat{ get{ return 1; } } + + + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Rich ); + AddLoot( LootPack.Gems, 4); + } + + public override bool CanRummageCorpses{ get{ return true; } } + + // TODO: Body Transformation + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 > Utility.RandomDouble() ) + { + /* Maniacal laugh + * Cliloc: 1070840 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Paralyzes for 4 seconds, or until hit + */ + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.SendLocalizedMessage( 1070840 ); // You are frozen as the creature laughs maniacally. + + defender.Paralyze( TimeSpan.FromSeconds( 4.0 ) ); + } + } + + public YomotsuPriest( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public override int GetIdleSound() + { + return 0x42A; + } + + public override int GetAttackSound() + { + return 0x435; + } + + public override int GetHurtSound() + { + return 0x436; + } + + public override int GetDeathSound() + { + return 0x43A; + } + } +} diff --git a/Scripts/Mobiles/Monsters/SE/YomotsuWarrior.cs b/Scripts/Mobiles/Monsters/SE/YomotsuWarrior.cs new file mode 100644 index 0000000..28f7d3e --- /dev/null +++ b/Scripts/Mobiles/Monsters/SE/YomotsuWarrior.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a yomotsu corpse" )] + public class YomotsuWarrior : BaseCreature + { + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.DoubleStrike; + } + + [Constructable] + public YomotsuWarrior() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a yomotsu warrior"; + Body = 245; + BaseSoundID = 0x452; + + SetStr( 486, 530 ); + SetDex( 151, 165 ); + SetInt( 17, 31 ); + + SetHits( 486, 530 ); + SetMana( 17, 31 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 65, 85 ); + SetResistance( ResistanceType.Fire, 30, 50 ); + SetResistance( ResistanceType.Cold, 45, 65 ); + SetResistance( ResistanceType.Poison, 35, 55 ); + SetResistance( ResistanceType.Energy, 25, 50 ); + + SetSkill( SkillName.Anatomy, 85.1, 95.0 ); + SetSkill( SkillName.MagicResist, 82.6, 90.5 ); + SetSkill( SkillName.Tactics, 95.1, 105.0 ); + SetSkill( SkillName.Wrestling, 97.6, 107.5 ); + + Fame = 4200; + Karma = -4200; + + PackItem( new GreenGourd() ); + PackItem( new ExecutionersAxe() ); + + if( Utility.RandomBool() ) + PackItem( new LongPants() ); + else + PackItem( new ShortPants() ); + + switch ( Utility.Random( 4 ) ) + { + case 0: PackItem( new Shoes() ); break; + case 1: PackItem( new Sandals() ); break; + case 2: PackItem( new Boots() ); break; + case 3: PackItem( new ThighBoots() ); break; + } + + if ( Utility.RandomDouble() < .25 ) + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + + } + + public override FoodType FavoriteFood{ get{ return FoodType.Fish; } } + + public override int Meat{ get{ return 1; } } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + AddLoot( LootPack.Gems,2); + } + + public override bool CanRummageCorpses{ get{ return true; } } + public override int TreasureMapLevel{ get{ return 3; } } + + // TODO: Throwing Dagger + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 > Utility.RandomDouble() ) + { + /* Maniacal laugh + * Cliloc: 1070840 + * Effect: Type: "3" From: "0x57D4F5B" To: "0x0" ItemId: "0x37B9" ItemIdName: "glow" FromLocation: "(884 715, 10)" ToLocation: "(884 715, 10)" Speed: "10" Duration: "5" FixedDirection: "True" Explode: "False" + * Paralyzes for 4 seconds, or until hit + */ + + defender.FixedEffect( 0x37B9, 10, 5 ); + defender.SendLocalizedMessage( 1070840 ); // You are frozen as the creature laughs maniacally. + + defender.Paralyze( TimeSpan.FromSeconds( 4.0 ) ); + } + } + + public YomotsuWarrior( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + + public override int GetIdleSound() + { + return 0x42A; + } + + public override int GetAttackSound() + { + return 0x435; + } + + public override int GetHurtSound() + { + return 0x436; + } + + public override int GetDeathSound() + { + return 0x43A; + } + } +} diff --git a/Scripts/Mobiles/Monsters/Summons/SummonedAirElemental.cs b/Scripts/Mobiles/Monsters/Summons/SummonedAirElemental.cs new file mode 100644 index 0000000..793f5b1 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Summons/SummonedAirElemental.cs @@ -0,0 +1,69 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an air elemental corpse" )] + public class SummonedAirElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public SummonedAirElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an air elemental"; + Body = 13; + Hue = 0x4001; + BaseSoundID = 655; + + SetStr( 200 ); + SetDex( 200 ); + SetInt( 100 ); + + SetHits( 150 ); + SetStam( 50 ); + + SetDamage( 6, 9 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 40, 50 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 70, 80 ); + + SetSkill( SkillName.Meditation, 90.0 ); + SetSkill( SkillName.EvalInt, 70.0 ); + SetSkill( SkillName.Magery, 70.0 ); + SetSkill( SkillName.MagicResist, 60.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 80.0 ); + + VirtualArmor = 40; + ControlSlots = 2; + } + + public SummonedAirElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + if ( BaseSoundID == 263 ) + BaseSoundID = 655; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Summons/SummonedDaemon.cs b/Scripts/Mobiles/Monsters/Summons/SummonedDaemon.cs new file mode 100644 index 0000000..28d47f9 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Summons/SummonedDaemon.cs @@ -0,0 +1,65 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a daemon corpse" )] + public class SummonedDaemon : BaseCreature + { + public override double DispelDifficulty{ get{ return 125.0; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public SummonedDaemon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "daemon" ); + Body = Core.AOS ? 10 : 9; + BaseSoundID = 357; + + SetStr( 200 ); + SetDex( 110 ); + SetInt( 150 ); + + SetDamage( 14, 21 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Poison, 100 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 70, 80 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 90.1, 100.0 ); + SetSkill( SkillName.Meditation, 90.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 100.0 ); + SetSkill( SkillName.MagicResist, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 98.1, 99.0 ); + + VirtualArmor = 58; + ControlSlots = Core.SE ? 4 : 5; + } + + public override bool CanFly { get { return true; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } // TODO: Immune to poison? + + public SummonedDaemon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Summons/SummonedEarthElemental.cs b/Scripts/Mobiles/Monsters/Summons/SummonedEarthElemental.cs new file mode 100644 index 0000000..74f859c --- /dev/null +++ b/Scripts/Mobiles/Monsters/Summons/SummonedEarthElemental.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "an earth elemental corpse" )] + public class SummonedEarthElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public SummonedEarthElemental() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an earth elemental"; + Body = 14; + BaseSoundID = 268; + + SetStr( 200 ); + SetDex( 70 ); + SetInt( 70 ); + + SetHits( 180 ); + + SetDamage( 14, 21 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 65, 75 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 65.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + VirtualArmor = 34; + ControlSlots = 2; + } + + public SummonedEarthElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Monsters/Summons/SummonedFireElemental.cs b/Scripts/Mobiles/Monsters/Summons/SummonedFireElemental.cs new file mode 100644 index 0000000..d56d781 --- /dev/null +++ b/Scripts/Mobiles/Monsters/Summons/SummonedFireElemental.cs @@ -0,0 +1,63 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a fire elemental corpse" )] + public class SummonedFireElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public SummonedFireElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a fire elemental"; + Body = 15; + BaseSoundID = 838; + + SetStr( 200 ); + SetDex( 200 ); + SetInt( 100 ); + + SetDamage( 9, 14 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Fire, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 70, 80 ); + SetResistance( ResistanceType.Cold, 0, 10 ); + SetResistance( ResistanceType.Poison, 50, 60 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.EvalInt, 90.0 ); + SetSkill( SkillName.Magery, 90.0 ); + SetSkill( SkillName.MagicResist, 85.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 92.0 ); + + VirtualArmor = 40; + ControlSlots = 4; + + AddItem( new LightSource() ); + } + + public SummonedFireElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Monsters/Summons/SummonedWaterElemental.cs b/Scripts/Mobiles/Monsters/Summons/SummonedWaterElemental.cs new file mode 100644 index 0000000..c413fae --- /dev/null +++ b/Scripts/Mobiles/Monsters/Summons/SummonedWaterElemental.cs @@ -0,0 +1,65 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a water elemental corpse" )] + public class SummonedWaterElemental : BaseCreature + { + public override double DispelDifficulty{ get{ return 117.5; } } + public override double DispelFocus{ get{ return 45.0; } } + + [Constructable] + public SummonedWaterElemental () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "a water elemental"; + Body = 16; + BaseSoundID = 278; + + SetStr( 200 ); + SetDex( 70 ); + SetInt( 100 ); + + SetHits( 165 ); + + SetDamage( 12, 16 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Cold, 100 ); + + SetResistance( ResistanceType.Physical, 50, 60 ); + SetResistance( ResistanceType.Fire, 20, 30 ); + SetResistance( ResistanceType.Cold, 70, 80 ); + SetResistance( ResistanceType.Poison, 45, 55 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.Meditation, 90.0 ); + SetSkill( SkillName.EvalInt, 80.0 ); + SetSkill( SkillName.Magery, 80.0 ); + SetSkill( SkillName.MagicResist, 75.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 85.0 ); + + VirtualArmor = 40; + ControlSlots = 3; + CanSwim = true; + } + + public SummonedWaterElemental( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/People.cs b/Scripts/Mobiles/People.cs new file mode 100644 index 0000000..7de7ff1 --- /dev/null +++ b/Scripts/Mobiles/People.cs @@ -0,0 +1,127 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class People : BaseCreature + { + [Constructable] + public People() : this(false) + { + } + + [Constructable] + public People (bool isFemale) : base( AIType.AI_None, FightMode.None, 10, 1, 0.2, 0.4 ) + { + + InitStats( 30, 30, 30 ); + + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if (Female = isFemale) // this.Female = Utility.RandomBool() + { + this.Body = 0x191; + this.Name = "une femme"; + AddItem( new Server.Items.Robe( Utility.RandomNeutralHue() ) ); + switch ( Utility.Random ( 2 ) ) + { + case 0: AddItem( new Skirt ( Utility.RandomNeutralHue() ) ); break; + case 1: AddItem( new Kilt ( Utility.RandomNeutralHue() ) ); break; + } + } + else + { + this.Body = 0x190; + this.Name = "un homme"; + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + AddItem( new Server.Items.Robe( Utility.RandomNeutralHue() ) ); + } + + AddItem( new Boots( Utility.RandomNeutralHue() ) ); + + Utility.AssignRandomHair( this ); + + Container pack = new Backpack(); + pack.Movable = false; + AddItem( pack ); + } + + + public override bool ClickTitle{ get{ return false; } } + + public People( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PeopleF : People + { + [Constructable] + public PeopleF() + : base(true) + { + } + + public PeopleF( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class PeopleM : People + { + [Constructable] + public PeopleM() + : base(false) + { + } + + public PeopleM( Serial serial ) : base( serial ) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs new file mode 100644 index 0000000..77de667 --- /dev/null +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -0,0 +1,5424 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Misc; +using Server.Items; +using Server.Gumps; +using Server.Multis; +using Server.Engines.Help; +using Server.Engines.ConPVP; +using Server.ContextMenus; +using Server.Network; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Spells.Seventh; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Bushido; +using Server.Targeting; +using Server.Engines.Quests; +using Server.Factions; +using Server.Regions; +using Server.Accounting; +using Server.Engines.CannedEvil; +using Server.Engines.Craft; +using Server.Spells.Spellweaving; +using Server.Engines.PartySystem; +using System.IO; +using Server.Commands; +using Server.Engines.MLQuests; + +namespace Server.Mobiles +{ + #region Enums + [Flags] + public enum PlayerFlag // First 16 bits are reserved for default-distro use, start custom flags at 0x00010000 + { + None = 0x00000000, + Glassblowing = 0x00000001, + Masonry = 0x00000002, + SandMining = 0x00000004, + StoneMining = 0x00000008, + ToggleMiningStone = 0x00000010, + KarmaLocked = 0x00000020, + AutoRenewInsurance = 0x00000040, + UseOwnFilter = 0x00000080, + PublicMyRunUO = 0x00000100, + PagingSquelched = 0x00000200, + Young = 0x00000400, + AcceptGuildInvites = 0x00000800, + DisplayChampionTitle = 0x00001000, + HasStatReward = 0x00002000, + RefuseTrades = 0x00004000, + // Scriptiz : ajouts de flags pour le syst�me de duels en ar�ne + isinchal = 0x00100001, + canbechal = 0x00100002, + TempMount = 0x00100003, + } + + public enum NpcGuild + { + None, + MagesGuild, + WarriorsGuild, + ThievesGuild, + RangersGuild, + HealersGuild, + MinersGuild, + MerchantsGuild, + TinkersGuild, + TailorsGuild, + FishermensGuild, + BardsGuild, + BlacksmithsGuild + } + + public enum SolenFriendship + { + None, + Red, + Black + } + + public enum BlockMountType + { + None = -1, + Dazed = 1040024, + BolaRecovery = 1062910, + DismountRecovery = 1070859 + } + + #endregion + + public partial class PlayerMobile : Mobile, IHonorTarget + { + #region Scriptiz : mise � jour du gump d'alimentation + [CommandProperty(AccessLevel.GameMaster)] + public override int Hunger + { + get { return base.Hunger; } + set + { + base.Hunger = value; + Alimentation.UpdateGump(this); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public override int Thirst + { + get { return base.Thirst; } + set + { + base.Thirst = value; + Alimentation.UpdateGump(this); + } + } + #endregion + + #region Scriptiz : ajout de l'alignement sur Malas + private Alignment m_Alignment = Alignment.Neutral; + + [CommandProperty(AccessLevel.GameMaster)] + public Alignment Alignment + { + get { return m_Alignment; } + set { m_Alignment = value; } + } + #endregion + + #region Vinds : ajout des chevaliers d'artedar + private bool m_IsArtedarKnight = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsArtedarKnight + { + get { return m_IsArtedarKnight; } + set { m_IsArtedarKnight = value; } + } + #endregion + + #region Scriptiz : Ajout pour le syst�me d'hallucinations + private bool m_Hallucinating; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Hallucinating + { + get { return m_Hallucinating; } + set + { + if (m_Hallucinating == value) + return; + + + if (value) //PRIMA INIZIALIZZIAMO + { + m_Hallucinating = value; // e poi settiamo la var.. + this.SendEverything(); + } + else //DEINIZIALIZZAZIONE + { + m_Hallucinating = value; // settiamo subito la var + this.SendEverything(); + } + + InvalidateProperties(); + } + } + + public override bool IsHallucinated + { + get { return m_Hallucinating; } + } + + public override short GetBody(Mobile toSend) + { + if (m_Hallucinating) + { + return (short)m_BodyArray[new Random(HalluRandomSeed + toSend.Serial.Value).Next(0, 59)]; + } + + return (short)toSend.Body; + } + + public override int GetHue(Mobile toSend) + { + if (m_Hallucinating) + { + return new Random(HalluRandomSeed + toSend.Serial.Value).Next(2, 1200); + } + + + return toSend.Hue; + } + + private static int HalluRandomSeed = Utility.Random(1073741822); + + private class ReseedTimer : Timer + { + public ReseedTimer() + : base(TimeSpan.FromSeconds(40), TimeSpan.FromSeconds(20)) + { + Priority = TimerPriority.FiveSeconds; + } + + + protected override void OnTick() + { + PlayerMobile.HalluRandomSeed = Utility.Random(1073741822); + } + } + + private static readonly int[] m_BodyArray = new int[60] { 1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15, 16, 21, 22, 24, 26, 28, 29, 30, 31, 33, 39, 42, 46, 47, 48, 50, 51, 52, 53, 58, 62, 64, 70, 72, 75, 80, 81, 85, 86, 88, 90, 97, 101, 104, 123, 134, 145, 149, 150, 151, 152, 154, 157, 400, 401, 605, 606 }; + #endregion + + #region Addiction + + private double[] Addiction; + + #endregion + + + private class CountAndTimeStamp + { + private int m_Count; + private DateTime m_Stamp; + + public CountAndTimeStamp() + { + } + + public DateTime TimeStamp { get{ return m_Stamp; } } + public int Count + { + get { return m_Count; } + set { m_Count = value; m_Stamp = DateTime.Now; } + } + } + + private DesignContext m_DesignContext; + + private NpcGuild m_NpcGuild; + private DateTime m_NpcGuildJoinTime; + private DateTime m_NextBODTurnInTime; + private TimeSpan m_NpcGuildGameTime; + private PlayerFlag m_Flags; + private int m_StepsTaken; + private int m_Profession; + private bool m_IsStealthing; // IsStealthing should be moved to Server.Mobiles + private bool m_IgnoreMobiles; // IgnoreMobiles should be moved to Server.Mobiles + private int m_NonAutoreinsuredItems; // number of items that could not be automatically reinsured because gold in bank was not enough + private bool m_NinjaWepCooldown; + /* + * a value of zero means, that the mobile is not executing the spell. Otherwise, + * the value should match the BaseMana required + */ + private int m_ExecutesLightningStrike; // move to Server.Mobiles?? + + private DateTime m_LastOnline; + private Server.Guilds.RankDefinition m_GuildRank; + + private int m_GuildMessageHue, m_AllianceMessageHue; + + private List m_AutoStabled; + private List m_AllFollowers; + private List m_RecentlyReported; + + #region Scriptiz : pour le syst�me de duels + private bool isinchal = false; + private bool canbechal = true; + private BaseMount m_TempMount; + + [CommandProperty(AccessLevel.GameMaster)] + public BaseMount TempMount + { + get { return m_TempMount; } + set { m_TempMount = value; } + } + + [CommandProperty(AccessLevel.Counselor)] + public bool IsInChallenge + { + get { return isinchal; } + set { isinchal = value; } + } + + [CommandProperty(AccessLevel.Counselor)] + public bool CanBeChallenged + { + get { return canbechal; } + set { canbechal = value; } + } + #endregion + + // Scriptiz : bool pour afficher ou cacher le GM + public bool ShowInStatus = true; + + // Scriptiz : bool pour les persos f�es + private bool m_IsFairy = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsFairy + { + get { return m_IsFairy; } + set { m_IsFairy = value; } + } + + // Scriptiz : bool pour nager sur un cheval + [CommandProperty(AccessLevel.GameMaster)] + public override bool CanSwim + { + // base sinon infini + get { return base.CanSwim || (Mount is SeaHorse); } + set { base.CanSwim = value; } + } + + // Scriptiz : les autres joueurs ne peuvent pas ouvrir le paperdoll d'une fille transform�e + public override bool CanPaperdollBeOpenedBy(Mobile from) + { + if (this.Female && this.BodyMod != 0 && from != this && from.AccessLevel == AccessLevel.Player) + { + from.SendMessage("Vous ne pouvez pas ouvrir ce paperdoll."); + return false; + } + + return base.CanPaperdollBeOpenedBy(from); + } + + #region Getters & Setters + + public List RecentlyReported + { + get + { + return m_RecentlyReported; + } + set + { + m_RecentlyReported = value; + } + } + + public List AutoStabled { get { return m_AutoStabled; } } + + public bool NinjaWepCooldown + { + get + { + return m_NinjaWepCooldown; + } + set + { + m_NinjaWepCooldown = value; + } + } + + public List AllFollowers + { + get + { + if( m_AllFollowers == null ) + m_AllFollowers = new List(); + return m_AllFollowers; + } + } + + public Server.Guilds.RankDefinition GuildRank + { + get + { + if( this.AccessLevel >= AccessLevel.GameMaster ) + return Server.Guilds.RankDefinition.Leader; + else + return m_GuildRank; + } + set{ m_GuildRank = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int GuildMessageHue + { + get{ return m_GuildMessageHue; } + set{ m_GuildMessageHue = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int AllianceMessageHue + { + get { return m_AllianceMessageHue; } + set { m_AllianceMessageHue = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Profession + { + get{ return m_Profession; } + set{ m_Profession = value; } + } + + public int StepsTaken + { + get{ return m_StepsTaken; } + set{ m_StepsTaken = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsStealthing // IsStealthing should be moved to Server.Mobiles + { + get { return m_IsStealthing; } + set { m_IsStealthing = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IgnoreMobiles // IgnoreMobiles should be moved to Server.Mobiles + { + get + { + return m_IgnoreMobiles; + } + set + { + if( m_IgnoreMobiles != value ) + { + m_IgnoreMobiles = value; + Delta( MobileDelta.Flags ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public NpcGuild NpcGuild + { + get{ return m_NpcGuild; } + set{ m_NpcGuild = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NpcGuildJoinTime + { + get{ return m_NpcGuildJoinTime; } + set{ m_NpcGuildJoinTime = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextBODTurnInTime + { + get{ return m_NextBODTurnInTime; } + set{ m_NextBODTurnInTime = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastMoved + { + get { return LastMoveTime; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastOnline + { + get{ return m_LastOnline; } + set{ m_LastOnline = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan NpcGuildGameTime + { + get{ return m_NpcGuildGameTime; } + set{ m_NpcGuildGameTime = value; } + } + + private int m_ToTItemsTurnedIn; + + [CommandProperty( AccessLevel.GameMaster )] + public int ToTItemsTurnedIn + { + get { return m_ToTItemsTurnedIn; } + set { m_ToTItemsTurnedIn = value; } + } + + private int m_ToTTotalMonsterFame; + + [CommandProperty( AccessLevel.GameMaster )] + public int ToTTotalMonsterFame + { + get { return m_ToTTotalMonsterFame; } + set { m_ToTTotalMonsterFame = value; } + } + + public int ExecutesLightningStrike + { + get { return m_ExecutesLightningStrike; } + set { m_ExecutesLightningStrike = value; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int ToothAche + { + get { return BaseCandyCane.GetToothAche(this); } + set { BaseCandyCane.SetToothAche(this, value); } + } + + #endregion + + #region PlayerFlags + public PlayerFlag Flags + { + get{ return m_Flags; } + set{ m_Flags = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool PagingSquelched + { + get{ return GetFlag( PlayerFlag.PagingSquelched ); } + set{ SetFlag( PlayerFlag.PagingSquelched, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Glassblowing + { + get{ return GetFlag( PlayerFlag.Glassblowing ); } + set{ SetFlag( PlayerFlag.Glassblowing, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Masonry + { + get{ return GetFlag( PlayerFlag.Masonry ); } + set{ SetFlag( PlayerFlag.Masonry, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool SandMining + { + get{ return GetFlag( PlayerFlag.SandMining ); } + set{ SetFlag( PlayerFlag.SandMining, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool StoneMining + { + get{ return GetFlag( PlayerFlag.StoneMining ); } + set{ SetFlag( PlayerFlag.StoneMining, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool ToggleMiningStone + { + get{ return GetFlag( PlayerFlag.ToggleMiningStone ); } + set{ SetFlag( PlayerFlag.ToggleMiningStone, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool KarmaLocked + { + get{ return GetFlag( PlayerFlag.KarmaLocked ); } + set{ SetFlag( PlayerFlag.KarmaLocked, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AutoRenewInsurance + { + get{ return GetFlag( PlayerFlag.AutoRenewInsurance ); } + set{ SetFlag( PlayerFlag.AutoRenewInsurance, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool UseOwnFilter + { + get{ return GetFlag( PlayerFlag.UseOwnFilter ); } + set{ SetFlag( PlayerFlag.UseOwnFilter, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool PublicMyRunUO + { + get{ return GetFlag( PlayerFlag.PublicMyRunUO ); } + set{ SetFlag( PlayerFlag.PublicMyRunUO, value ); InvalidateMyRunUO(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool AcceptGuildInvites + { + get{ return GetFlag( PlayerFlag.AcceptGuildInvites ); } + set{ SetFlag( PlayerFlag.AcceptGuildInvites, value ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool HasStatReward + { + get{ return GetFlag( PlayerFlag.HasStatReward ); } + set{ SetFlag( PlayerFlag.HasStatReward, value ); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool RefuseTrades + { + get { return GetFlag(PlayerFlag.RefuseTrades); } + set { SetFlag(PlayerFlag.RefuseTrades, value); } + } + #endregion + + #region Auto Arrow Recovery + private Dictionary m_RecoverableAmmo = new Dictionary(); + + public Dictionary RecoverableAmmo + { + get { return m_RecoverableAmmo; } + } + + public void RecoverAmmo() + { + if ( Core.SE && Alive ) + { + foreach ( KeyValuePair kvp in m_RecoverableAmmo ) + { + if ( kvp.Value > 0 ) + { + Item ammo = null; + + try + { + ammo = Activator.CreateInstance( kvp.Key ) as Item; + } + catch + { + } + + if ( ammo != null ) + { + string name = ammo.Name; + ammo.Amount = kvp.Value; + + if ( name == null ) + { + if ( ammo is Arrow ) + name = "arrow"; + else if ( ammo is Bolt ) + name = "bolt"; + } + + if ( name != null && ammo.Amount > 1 ) + name = String.Format( "{0}s", name ); + + if ( name == null ) + name = String.Format( "#{0}", ammo.LabelNumber ); + + PlaceInBackpack( ammo ); + SendLocalizedMessage( 1073504, String.Format( "{0}\t{1}", ammo.Amount, name ) ); // You recover ~1_NUM~ ~2_AMMO~. + } + } + } + + m_RecoverableAmmo.Clear(); + } + } + + #endregion + + private DateTime m_AnkhNextUse; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime AnkhNextUse + { + get{ return m_AnkhNextUse; } + set{ m_AnkhNextUse = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan DisguiseTimeLeft + { + get{ return DisguiseTimers.TimeRemaining( this ); } + } + + private DateTime m_PeacedUntil; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime PeacedUntil + { + get { return m_PeacedUntil; } + set { m_PeacedUntil = value; } + } + + #region Scroll of Alacrity + private DateTime m_AcceleratedStart; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime AcceleratedStart + { + get { return m_AcceleratedStart; } + set { m_AcceleratedStart = value; } + } + + private SkillName m_AcceleratedSkill; + + [CommandProperty(AccessLevel.GameMaster)] + public SkillName AcceleratedSkill + { + get { return m_AcceleratedSkill; } + set { m_AcceleratedSkill = value; } + } + #endregion + + public static Direction GetDirection4( Point3D from, Point3D to ) + { + int dx = from.X - to.X; + int dy = from.Y - to.Y; + + int rx = dx - dy; + int ry = dx + dy; + + Direction ret; + + if ( rx >= 0 && ry >= 0 ) + ret = Direction.West; + else if ( rx >= 0 && ry < 0 ) + ret = Direction.South; + else if ( rx < 0 && ry < 0 ) + ret = Direction.East; + else + ret = Direction.North; + + return ret; + } + + public override bool OnDroppedItemToWorld(Item item, Point3D location) + { + if (!base.OnDroppedItemToWorld(item, location)) + return false; + + if (Core.AOS) + { + IPooledEnumerable mobiles = Map.GetMobilesInRange(location, 0); + + foreach (Mobile m in mobiles) + { + if (m.Z >= location.Z && m.Z < location.Z + 16 && (!m.Hidden || m.AccessLevel == AccessLevel.Player)) + { + mobiles.Free(); + return false; + } + } + + mobiles.Free(); + } + + BounceInfo bi = item.GetBounce(); + + if ( bi != null ) + { + Type type = item.GetType(); + + if ( type.IsDefined( typeof( FurnitureAttribute ), true ) || type.IsDefined( typeof( DynamicFlipingAttribute ), true ) ) + { + object[] objs = type.GetCustomAttributes( typeof( FlipableAttribute ), true ); + + if ( objs != null && objs.Length > 0 ) + { + FlipableAttribute fp = objs[0] as FlipableAttribute; + + if ( fp != null ) + { + int[] itemIDs = fp.ItemIDs; + + Point3D oldWorldLoc = bi.m_WorldLoc; + Point3D newWorldLoc = location; + + if ( oldWorldLoc.X != newWorldLoc.X || oldWorldLoc.Y != newWorldLoc.Y ) + { + Direction dir = GetDirection4( oldWorldLoc, newWorldLoc ); + + if ( itemIDs.Length == 2 ) + { + switch ( dir ) + { + case Direction.North: + case Direction.South: item.ItemID = itemIDs[0]; break; + case Direction.East: + case Direction.West: item.ItemID = itemIDs[1]; break; + } + } + else if ( itemIDs.Length == 4 ) + { + switch ( dir ) + { + case Direction.South: item.ItemID = itemIDs[0]; break; + case Direction.East: item.ItemID = itemIDs[1]; break; + case Direction.North: item.ItemID = itemIDs[2]; break; + case Direction.West: item.ItemID = itemIDs[3]; break; + } + } + } + } + } + } + } + + return true; + } + + public override int GetPacketFlags() + { + int flags = base.GetPacketFlags(); + + if ( m_IgnoreMobiles ) + flags |= 0x10; + + return flags; + } + + public override int GetOldPacketFlags() + { + int flags = base.GetOldPacketFlags(); + + if ( m_IgnoreMobiles ) + flags |= 0x10; + + return flags; + } + + public bool GetFlag( PlayerFlag flag ) + { + return ( (m_Flags & flag) != 0 ); + } + + public void SetFlag( PlayerFlag flag, bool value ) + { + if ( value ) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + + public DesignContext DesignContext + { + get{ return m_DesignContext; } + set{ m_DesignContext = value; } + } + + public static void Initialize() + { + if ( FastwalkPrevention ) + PacketHandlers.RegisterThrottler( 0x02, new ThrottlePacketCallback( MovementThrottle_Callback ) ); + + EventSink.Login += new LoginEventHandler( OnLogin ); + EventSink.Logout += new LogoutEventHandler( OnLogout ); + EventSink.Connected += new ConnectedEventHandler( EventSink_Connected ); + EventSink.Disconnected += new DisconnectedEventHandler( EventSink_Disconnected ); + + if( Core.SE ) + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( CheckPets ) ); + } + } + + private static void CheckPets() + { + foreach( Mobile m in World.Mobiles.Values ) + { + if( m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + if((( !pm.Mounted || ( pm.Mount != null && pm.Mount is EtherealMount )) && ( pm.AllFollowers.Count > pm.AutoStabled.Count )) || + ( pm.Mounted && ( pm.AllFollowers.Count > ( pm.AutoStabled.Count +1 )))) + { + pm.AutoStablePets(); /* autostable checks summons, et al: no need here */ + } + } + } + } + + private MountBlock m_MountBlock; + + public BlockMountType MountBlockReason + { + get + { + return (CheckBlock(m_MountBlock)) ? m_MountBlock.m_Type : BlockMountType.None; + } + } + + private static bool CheckBlock(MountBlock block) + { + return ((block is MountBlock) && block.m_Timer.Running); + } + + private class MountBlock + { + public BlockMountType m_Type; + public Timer m_Timer; + + public MountBlock(TimeSpan duration, BlockMountType type, Mobile mobile) + { + m_Type = type; + + m_Timer = Timer.DelayCall(duration, new TimerStateCallback(RemoveBlock), mobile); + } + + private void RemoveBlock(Mobile mobile) + { + (mobile as PlayerMobile).m_MountBlock = null; + } + } + + public void SetMountBlock(BlockMountType type, TimeSpan duration, bool dismount) + { + if (dismount) + { + if (this.Mount != null) + { + this.Mount.Rider = null; + } + else if (AnimalForm.UnderTransformation(this)) + { + AnimalForm.RemoveContext(this, true); + } + } + + if ((m_MountBlock == null) || !m_MountBlock.m_Timer.Running || (m_MountBlock.m_Timer.Next < (DateTime.UtcNow + duration))) + { + m_MountBlock = new MountBlock(duration, type, this); + } + } + + public override void OnSkillInvalidated( Skill skill ) + { + if ( Core.AOS && skill.SkillName == SkillName.MagicResist ) + UpdateResistances(); + } + + public override int GetMaxResistance( ResistanceType type ) + { + if (AccessLevel > AccessLevel.Player) + return 100; + + int max = base.GetMaxResistance( type ); + + if ( type != ResistanceType.Physical && 60 < max && Spells.Fourth.CurseSpell.UnderEffect( this ) ) + max = 60; + + if( Core.ML && this.Race == Race.Elf && type == ResistanceType.Energy ) + max += 5; //Intended to go after the 60 max from curse + + return max; + } + + protected override void OnRaceChange( Race oldRace ) + { + ValidateEquipment(); + UpdateResistances(); + } + + public override int MaxWeight { get { return (((Core.ML && this.Race == Race.Human) ? 100 : 40) + (int)(3.5 * this.Str)); } } + + private int m_LastGlobalLight = -1, m_LastPersonalLight = -1; + + public override void OnNetStateChanged() + { + m_LastGlobalLight = -1; + m_LastPersonalLight = -1; + } + + public override void ComputeBaseLightLevels( out int global, out int personal ) + { + global = LightCycle.ComputeLevelFor( this ); + + bool racialNightSight = (Core.ML && this.Race == Race.Elf); + + if ( this.LightLevel < 21 && ( AosAttributes.GetValue( this, AosAttribute.NightSight ) > 0 || racialNightSight )) + personal = 21; + else + personal = this.LightLevel; + } + + public override void CheckLightLevels( bool forceResend ) + { + NetState ns = this.NetState; + + if ( ns == null ) + return; + + int global, personal; + + ComputeLightLevels( out global, out personal ); + + if ( !forceResend ) + forceResend = ( global != m_LastGlobalLight || personal != m_LastPersonalLight ); + + if ( !forceResend ) + return; + + m_LastGlobalLight = global; + m_LastPersonalLight = personal; + + ns.Send( GlobalLightLevel.Instantiate( global ) ); + ns.Send( new PersonalLightLevel( this, personal ) ); + } + + public override int GetMinResistance( ResistanceType type ) + { + int magicResist = (int)(Skills[SkillName.MagicResist].Value * 10); + int min = int.MinValue; + + if ( magicResist >= 1000 ) + min = 40 + ((magicResist - 1000) / 50); + else if ( magicResist >= 400 ) + min = (magicResist - 400) / 15; + + if ( min > MaxPlayerResistance ) + min = MaxPlayerResistance; + + int baseMin = base.GetMinResistance( type ); + + if ( min < baseMin ) + min = baseMin; + + return min; + } + + public override void OnManaChange(int oldValue) + { + base.OnManaChange(oldValue); + if (m_ExecutesLightningStrike > 0) + { + if (Mana < m_ExecutesLightningStrike) + { + LightningStrike.ClearCurrentMove(this); + } + } + } + + private static void OnLogin( LoginEventArgs e ) + { + Mobile from = e.Mobile; + + CheckAtrophies( from ); + + if ( AccountHandler.LockdownLevel > AccessLevel.Player ) + { + string notice; + + Accounting.Account acct = from.Account as Accounting.Account; + + if ( acct == null || !acct.HasAccess( from.NetState ) ) + { + if ( from.AccessLevel == AccessLevel.Player ) + notice = "The server is currently under lockdown. No players are allowed to log in at this time."; + else + notice = "The server is currently under lockdown. You do not have sufficient access level to connect."; + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), new TimerStateCallback( Disconnect ), from ); + } + else if ( from.AccessLevel >= AccessLevel.Administrator ) + { + notice = "The server is currently under lockdown. As you are an administrator, you may change this from the [Admin gump."; + } + else + { + notice = "The server is currently under lockdown. You have sufficient access level to connect."; + } + + from.SendGump( new NoticeGump( 1060637, 30720, notice, 0xFFC000, 300, 140, null, null ) ); + return; + } + + if( from is PlayerMobile ) + ((PlayerMobile)from).ClaimAutoStabledPets(); + + // Scriptiz : On evoie le gump d'alimentation lors de la connection + Alimentation.SendGump(from); + } + + private bool m_NoDeltaRecursion; + + public void ValidateEquipment() + { + if ( m_NoDeltaRecursion || Map == null || Map == Map.Internal ) + return; + + if ( this.Items == null ) + return; + + m_NoDeltaRecursion = true; + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ValidateEquipment_Sandbox ) ); + } + + private void ValidateEquipment_Sandbox() + { + try + { + if ( Map == null || Map == Map.Internal ) + return; + + List items = this.Items; + + if ( items == null ) + return; + + bool moved = false; + + int str = this.Str; + int dex = this.Dex; + int intel = this.Int; + + #region Factions + int factionItemCount = 0; + #endregion + + Mobile from = this; + + #region Ethics + Ethics.Ethic ethic = Ethics.Ethic.Find( from ); + #endregion + + for ( int i = items.Count - 1; i >= 0; --i ) + { + if ( i >= items.Count ) + continue; + + Item item = items[i]; + + #region Ethics + if ( ( item.SavedFlags & 0x100 ) != 0 ) + { + if ( item.Hue != Ethics.Ethic.Hero.Definition.PrimaryHue ) + { + item.SavedFlags &= ~0x100; + } + else if ( ethic != Ethics.Ethic.Hero ) + { + from.AddToBackpack( item ); + moved = true; + continue; + } + } + else if ( ( item.SavedFlags & 0x200 ) != 0 ) + { + if ( item.Hue != Ethics.Ethic.Evil.Definition.PrimaryHue ) + { + item.SavedFlags &= ~0x200; + } + else if ( ethic != Ethics.Ethic.Evil ) + { + from.AddToBackpack( item ); + moved = true; + continue; + } + } + #endregion + + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + bool drop = false; + + if( dex < weapon.DexRequirement ) + drop = true; + else if( str < AOS.Scale( weapon.StrRequirement, 100 - weapon.GetLowerStatReq() ) ) + drop = true; + else if( intel < weapon.IntRequirement ) + drop = true; + else if( weapon.RequiredRace != null && weapon.RequiredRace != this.Race ) + drop = true; + + if ( drop ) + { + string name = weapon.Name; + + if ( name == null ) + name = String.Format( "#{0}", weapon.LabelNumber ); + + from.SendLocalizedMessage( 1062001, name ); // You can no longer wield your ~1_WEAPON~ + from.AddToBackpack( weapon ); + moved = true; + } + } + else if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + bool drop = false; + + if ( !armor.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster ) + { + drop = true; + } + else if ( !armor.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster ) + { + drop = true; + } + else if( armor.RequiredRace != null && armor.RequiredRace != this.Race ) + { + drop = true; + } + else + { + int strBonus = armor.ComputeStatBonus( StatType.Str ), strReq = armor.ComputeStatReq( StatType.Str ); + int dexBonus = armor.ComputeStatBonus( StatType.Dex ), dexReq = armor.ComputeStatReq( StatType.Dex ); + int intBonus = armor.ComputeStatBonus( StatType.Int ), intReq = armor.ComputeStatReq( StatType.Int ); + + if( dex < dexReq || (dex + dexBonus) < 1 ) + drop = true; + else if( str < strReq || (str + strBonus) < 1 ) + drop = true; + else if( intel < intReq || (intel + intBonus) < 1 ) + drop = true; + } + + if ( drop ) + { + string name = armor.Name; + + if ( name == null ) + name = String.Format( "#{0}", armor.LabelNumber ); + + if ( armor is BaseShield ) + from.SendLocalizedMessage( 1062003, name ); // You can no longer equip your ~1_SHIELD~ + else + from.SendLocalizedMessage( 1062002, name ); // You can no longer wear your ~1_ARMOR~ + + from.AddToBackpack( armor ); + moved = true; + } + } + else if ( item is BaseClothing ) + { + BaseClothing clothing = (BaseClothing)item; + + bool drop = false; + + if ( !clothing.AllowMaleWearer && !from.Female && from.AccessLevel < AccessLevel.GameMaster ) + { + drop = true; + } + else if ( !clothing.AllowFemaleWearer && from.Female && from.AccessLevel < AccessLevel.GameMaster ) + { + drop = true; + } + else if( clothing.RequiredRace != null && clothing.RequiredRace != this.Race ) + { + drop = true; + } + else + { + int strBonus = clothing.ComputeStatBonus( StatType.Str ); + int strReq = clothing.ComputeStatReq( StatType.Str ); + + if( str < strReq || (str + strBonus) < 1 ) + drop = true; + } + + if ( drop ) + { + string name = clothing.Name; + + if ( name == null ) + name = String.Format( "#{0}", clothing.LabelNumber ); + + from.SendLocalizedMessage( 1062002, name ); // You can no longer wear your ~1_ARMOR~ + + from.AddToBackpack( clothing ); + moved = true; + } + } + + FactionItem factionItem = FactionItem.Find( item ); + + if ( factionItem != null ) + { + bool drop = false; + + Faction ourFaction = Faction.Find( this ); + + if ( ourFaction == null || ourFaction != factionItem.Faction ) + drop = true; + else if ( ++factionItemCount > FactionItem.GetMaxWearables( this ) ) + drop = true; + + if ( drop ) + { + from.AddToBackpack( item ); + moved = true; + } + } + } + + if ( moved ) + from.SendLocalizedMessage( 500647 ); // Some equipment has been moved to your backpack. + } + catch ( Exception e ) + { + Console.WriteLine( e ); + } + finally + { + m_NoDeltaRecursion = false; + } + } + + public override void Delta( MobileDelta flag ) + { + base.Delta( flag ); + + if ( (flag & MobileDelta.Stat) != 0 ) + ValidateEquipment(); + + if ( (flag & (MobileDelta.Name | MobileDelta.Hue)) != 0 ) + InvalidateMyRunUO(); + } + + private static void Disconnect( object state ) + { + NetState ns = ((Mobile)state).NetState; + + if ( ns != null ) + ns.Dispose(); + } + + private static void OnLogout( LogoutEventArgs e ) + { + if( e.Mobile is PlayerMobile ) + ((PlayerMobile)e.Mobile).AutoStablePets(); + } + + private static void EventSink_Connected( ConnectedEventArgs e ) + { + PlayerMobile pm = e.Mobile as PlayerMobile; + + if ( pm != null ) + { + pm.m_SessionStart = DateTime.Now; + + if ( pm.m_Quest != null ) + pm.m_Quest.StartTimer(); + + pm.BedrollLogout = false; + pm.LastOnline = DateTime.Now; + } + + DisguiseTimers.StartTimer( e.Mobile ); + + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( ClearSpecialMovesCallback ), e.Mobile ); + } + + private static void ClearSpecialMovesCallback( object state ) + { + Mobile from = (Mobile)state; + + SpecialMove.ClearAllMoves( from ); + } + + private static void EventSink_Disconnected( DisconnectedEventArgs e ) + { + Mobile from = e.Mobile; + DesignContext context = DesignContext.Find( from ); + + if ( context != null ) + { + /* Client disconnected + * - Remove design context + * - Eject all from house + * - Restore relocated entities + */ + + // Remove design context + DesignContext.Remove( from ); + + // Eject all from house + from.RevealingAction(); + + foreach ( Item item in context.Foundation.GetItems() ) + item.Location = context.Foundation.BanLocation; + + foreach ( Mobile mobile in context.Foundation.GetMobiles() ) + mobile.Location = context.Foundation.BanLocation; + + // Restore relocated entities + context.Foundation.RestoreRelocatedEntities(); + } + + PlayerMobile pm = e.Mobile as PlayerMobile; + + if ( pm != null ) + { + pm.m_GameTime += (DateTime.Now - pm.m_SessionStart); + + if ( pm.m_Quest != null ) + pm.m_Quest.StopTimer(); + + pm.m_SpeechLog = null; + pm.LastOnline = DateTime.Now; + } + + DisguiseTimers.StopTimer( from ); + } + + public override void RevealingAction() + { + if ( m_DesignContext != null ) + return; + + Spells.Sixth.InvisibilitySpell.RemoveTimer( this ); + + base.RevealingAction(); + + m_IsStealthing = false; // IsStealthing should be moved to Server.Mobiles + } + + [CommandProperty( AccessLevel.GameMaster )] + public override bool Hidden + { + get + { + return base.Hidden; + } + set + { + base.Hidden = value; + + RemoveBuff( BuffIcon.Invisibility ); //Always remove, default to the hiding icon EXCEPT in the invis spell where it's explicitly set + + if( !Hidden ) + { + RemoveBuff( BuffIcon.HidingAndOrStealth ); + } + else// if( !InvisibilitySpell.HasTimer( this ) ) + { + BuffInfo.AddBuff( this, new BuffInfo( BuffIcon.HidingAndOrStealth, 1075655 ) ); //Hidden/Stealthing & You Are Hidden + } + } + } + + public override void OnSubItemAdded( Item item ) + { + if ( AccessLevel < AccessLevel.GameMaster && item.IsChildOf( this.Backpack ) ) + { + int maxWeight = WeightOverloading.GetMaxWeight( this ); + int curWeight = Mobile.BodyWeight + this.TotalWeight; + + if ( curWeight > maxWeight ) + this.SendLocalizedMessage( 1019035, true, String.Format( " : {0} / {1}", curWeight, maxWeight ) ); + } + } + + public override bool CanBeHarmful( Mobile target, bool message, bool ignoreOurBlessedness ) + { + if ( m_DesignContext != null || (target is PlayerMobile && ((PlayerMobile)target).m_DesignContext != null) ) + return false; + + if ((target is BaseCreature && ((BaseCreature)target).IsInvulnerable) || target is PlayerVendor || target is TownCrier) + { + if (message) + { + if (target.Title == null) + SendMessage("{0} cannot be harmed.", target.Name); + else + SendMessage("{0} {1} cannot be harmed.", target.Name, target.Title); + } + + return false; + } + + return base.CanBeHarmful( target, message, ignoreOurBlessedness ); + } + + public override bool CanBeBeneficial( Mobile target, bool message, bool allowDead ) + { + if ( m_DesignContext != null || (target is PlayerMobile && ((PlayerMobile)target).m_DesignContext != null) ) + return false; + + return base.CanBeBeneficial( target, message, allowDead ); + } + + public override bool CheckContextMenuDisplay( IEntity target ) + { + return ( m_DesignContext == null ); + } + + public override void OnItemAdded( Item item ) + { + base.OnItemAdded( item ); + + if ( item is BaseArmor || item is BaseWeapon ) + { + Hits=Hits; Stam=Stam; Mana=Mana; + } + + if ( this.NetState != null ) + CheckLightLevels( false ); + + InvalidateMyRunUO(); + } + + public override void OnItemRemoved( Item item ) + { + base.OnItemRemoved( item ); + + if ( item is BaseArmor || item is BaseWeapon ) + { + Hits=Hits; Stam=Stam; Mana=Mana; + } + + if ( this.NetState != null ) + CheckLightLevels( false ); + + InvalidateMyRunUO(); + } + + public override double ArmorRating + { + get + { + //BaseArmor ar; + double rating = 0.0; + + AddArmorRating( ref rating, NeckArmor ); + AddArmorRating( ref rating, HandArmor ); + AddArmorRating( ref rating, HeadArmor ); + AddArmorRating( ref rating, ArmsArmor ); + AddArmorRating( ref rating, LegsArmor ); + AddArmorRating( ref rating, ChestArmor ); + AddArmorRating( ref rating, ShieldArmor ); + + return VirtualArmor + VirtualArmorMod + rating; + } + } + + private void AddArmorRating( ref double rating, Item armor ) + { + BaseArmor ar = armor as BaseArmor; + + if( ar != null && ( !Core.AOS || ar.ArmorAttributes.MageArmor == 0 )) + rating += ar.ArmorRatingScaled; + } + + #region [Stats]Max + [CommandProperty( AccessLevel.GameMaster )] + public override int HitsMax + { + get + { + int strBase; + int strOffs = GetStatOffset( StatType.Str ); + + if ( Core.AOS ) + { + strBase = this.Str; //this.Str already includes GetStatOffset/str + strOffs = AosAttributes.GetValue( this, AosAttribute.BonusHits ); + + if ( Core.ML && strOffs > 25 && AccessLevel <= AccessLevel.Player ) + strOffs = 25; + + if ( AnimalForm.UnderTransformation( this, typeof( BakeKitsune ) ) || AnimalForm.UnderTransformation( this, typeof( GreyWolf ) ) ) + strOffs += 20; + } + else + { + strBase = this.RawStr; + } + + return (strBase / 2) + 50 + strOffs; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int StamMax + { + get{ return base.StamMax + AosAttributes.GetValue( this, AosAttribute.BonusStam ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int ManaMax + { + get{ return base.ManaMax + AosAttributes.GetValue( this, AosAttribute.BonusMana ) + ((Core.ML && Race == Race.Elf) ? 20 : 0); } + } + #endregion + + #region Stat Getters/Setters + + [CommandProperty( AccessLevel.GameMaster )] + public override int Str + { + get + { + if( Core.ML && this.AccessLevel == AccessLevel.Player ) + return Math.Min( base.Str, 150 ); + + return base.Str; + } + set + { + base.Str = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int Int + { + get + { + if( Core.ML && this.AccessLevel == AccessLevel.Player ) + return Math.Min( base.Int, 150 ); + + return base.Int; + } + set + { + base.Int = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int Dex + { + get + { + if( Core.ML && this.AccessLevel == AccessLevel.Player ) + return Math.Min( base.Dex, 150 ); + + return base.Dex; + } + set + { + base.Dex = value; + } + } + + #endregion + + public override bool Move( Direction d ) + { + NetState ns = this.NetState; + + if ( ns != null ) + { + if ( HasGump( typeof( ResurrectGump ) ) ) { + if ( Alive ) { + CloseGump( typeof( ResurrectGump ) ); + } else { + SendLocalizedMessage( 500111 ); // You are frozen and cannot move. + return false; + } + } + } + + TimeSpan speed = ComputeMovementSpeed( d ); + + bool res; + + if ( !Alive ) + Server.Movement.MovementImpl.IgnoreMovableImpassables = true; + + res = base.Move( d ); + + Server.Movement.MovementImpl.IgnoreMovableImpassables = false; + + if ( !res ) + return false; + + m_NextMovementTime += speed; + + return true; + } + + public override bool CheckMovement( Direction d, out int newZ ) + { + DesignContext context = m_DesignContext; + + if ( context == null ) + return base.CheckMovement( d, out newZ ); + + HouseFoundation foundation = context.Foundation; + + newZ = foundation.Z + HouseFoundation.GetLevelZ( context.Level, context.Foundation ); + + int newX = this.X, newY = this.Y; + Movement.Movement.Offset( d, ref newX, ref newY ); + + int startX = foundation.X + foundation.Components.Min.X + 1; + int startY = foundation.Y + foundation.Components.Min.Y + 1; + int endX = startX + foundation.Components.Width - 1; + int endY = startY + foundation.Components.Height - 2; + + return ( newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map ); + } + + public override bool AllowItemUse( Item item ) + { + #region Dueling + if (m_DuelContext != null && !m_DuelContext.AllowItemUse(this, item)) + return false; + #endregion + return DesignContext.Check( this ); + } + + public SkillName[] AnimalFormRestrictedSkills{ get{ return m_AnimalFormRestrictedSkills; } } + + private SkillName[] m_AnimalFormRestrictedSkills = new SkillName[] + { + SkillName.ArmsLore, SkillName.Begging, SkillName.Discordance, SkillName.Forensics, + SkillName.Inscribe, SkillName.ItemID, SkillName.Meditation, SkillName.Peacemaking, + SkillName.Provocation, SkillName.RemoveTrap, SkillName.SpiritSpeak, SkillName.Stealing, + SkillName.TasteID + }; + + public override bool AllowSkillUse( SkillName skill ) + { + if ( AnimalForm.UnderTransformation( this ) ) + { + for( int i = 0; i < m_AnimalFormRestrictedSkills.Length; i++ ) + { + if( m_AnimalFormRestrictedSkills[i] == skill ) + { + SendLocalizedMessage( 1070771 ); // You cannot use that skill in this form. + return false; + } + } + } + #region Dueling + if (m_DuelContext != null && !m_DuelContext.AllowSkillUse(this, skill)) + return false; + #endregion + + return DesignContext.Check( this ); + } + + private bool m_LastProtectedMessage; + private int m_NextProtectionCheck = 10; + + public virtual void RecheckTownProtection() + { + m_NextProtectionCheck = 10; + + Regions.GuardedRegion reg = (Regions.GuardedRegion) this.Region.GetRegion( typeof( Regions.GuardedRegion ) ); + bool isProtected = ( reg != null && !reg.IsDisabled() ); + + if ( isProtected != m_LastProtectedMessage ) + { + if ( isProtected ) + SendLocalizedMessage( 500112 ); // You are now under the protection of the town guards. + else + SendLocalizedMessage( 500113 ); // You have left the protection of the town guards. + + m_LastProtectedMessage = isProtected; + } + } + + public override void MoveToWorld( Point3D loc, Map map ) + { + base.MoveToWorld( loc, map ); + + RecheckTownProtection(); + } + + public override void SetLocation( Point3D loc, bool isTeleport ) + { + if ( !isTeleport && AccessLevel == AccessLevel.Player ) + { + // moving, not teleporting + int zDrop = ( this.Location.Z - loc.Z ); + + if ( zDrop > 20 ) // we fell more than one story + Hits -= ((zDrop / 20) * 10) - 5; // deal some damage; does not kill, disrupt, etc + } + + base.SetLocation( loc, isTeleport ); + + if ( isTeleport || --m_NextProtectionCheck == 0 ) + RecheckTownProtection(); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + // Scriptiz : Ajout des menus contextuels pour mettre en prison un joueur + JailSystem.GetContextMenus(from, this, list); + + if ( from == this ) + { + if ( m_Quest != null ) + m_Quest.GetContextMenuEntries( list ); + + if (Alive) + { + if (InsuranceEnabled) + { + if (Core.SA) + list.Add(new CallbackEntry(1114299, new ContextCallback(OpenItemInsuranceMenu))); // Open Item Insurance Menu + + list.Add(new CallbackEntry(6201, new ContextCallback(ToggleItemInsurance))); // Toggle Item Insurance + + if (!Core.SA) + { + if (AutoRenewInsurance) + list.Add(new CallbackEntry(6202, new ContextCallback(CancelRenewInventoryInsurance))); // Cancel Renewing Inventory Insurance + else + list.Add(new CallbackEntry(6200, new ContextCallback(AutoRenewInventoryInsurance))); // Auto Renew Inventory Insurance + } + } + + if (MLQuestSystem.Enabled) + list.Add(new CallbackEntry(6169, new ContextCallback(ToggleQuestItem))); // Toggle Quest Item + } + + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null ) + { + if ( Alive && house.InternalizedVendors.Count > 0 && house.IsOwner( this ) ) + list.Add( new CallbackEntry( 6204, new ContextCallback( GetVendor ) ) ); + + if (house.IsAosRules && !Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) // Dueling + list.Add( new CallbackEntry( 6207, new ContextCallback( LeaveHouse ) ) ); + } + + if ( m_JusticeProtectors.Count > 0 ) + list.Add( new CallbackEntry( 6157, new ContextCallback( CancelProtection ) ) ); + + if( Alive ) + list.Add( new CallbackEntry( 6210, new ContextCallback( ToggleChampionTitleDisplay ) ) ); + + if (Core.HS) + { + NetState ns = from.NetState; + + if (ns != null && ns.ExtendedStatus) + list.Add(new CallbackEntry(RefuseTrades ? 1154112 : 1154113, new ContextCallback(ToggleTrades))); // Allow Trades / Refuse Trades + } + } + if ( from != this ) + { + if ( Alive && Core.Expansion >= Expansion.AOS ) + { + Party theirParty = from.Party as Party; + Party ourParty = this.Party as Party; + + if ( theirParty == null && ourParty == null ) { + list.Add( new AddToPartyEntry( from, this ) ); + } else if ( theirParty != null && theirParty.Leader == from ) { + if ( ourParty == null ) { + list.Add( new AddToPartyEntry( from, this ) ); + } else if ( ourParty == theirParty ) { + list.Add( new RemoveFromPartyEntry( from, this ) ); + } + } + } + + BaseHouse curhouse = BaseHouse.FindHouseAt( this ); + + if( curhouse != null ) + { + if ( Alive && Core.Expansion >= Expansion.AOS && curhouse.IsAosRules && curhouse.IsFriend( from ) ) + list.Add( new EjectPlayerEntry( from, this ) ); + } + } + } + + private void CancelProtection() + { + for ( int i = 0; i < m_JusticeProtectors.Count; ++i ) + { + Mobile prot = m_JusticeProtectors[i]; + + string args = String.Format( "{0}\t{1}", this.Name, prot.Name ); + + prot.SendLocalizedMessage( 1049371, args ); // The protective relationship between ~1_PLAYER1~ and ~2_PLAYER2~ has been ended. + this.SendLocalizedMessage( 1049371, args ); // The protective relationship between ~1_PLAYER1~ and ~2_PLAYER2~ has been ended. + } + + m_JusticeProtectors.Clear(); + } + + #region Insurance + + private static int GetInsuranceCost(Item item) + { + return 600; // TODO + } + + private void ToggleItemInsurance() + { + if (!CheckAlive()) + return; + + BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleItemInsurance_Callback)); + SendLocalizedMessage(1060868); // Target the item you wish to toggle insurance status on to cancel + } + + private bool CanInsure(Item item) + { + if ((item is Container && !(item is BaseQuiver)) || item is BagOfSending || item is KeyRing || item is PotionKeg || item is Sigil) + return false; + + if (item.Stackable) + return false; + + if (item.LootType == LootType.Cursed) + return false; + + if (item.ItemID == 0x204E) // death shroud + return false; + + if (item.Layer == Layer.Mount) + return false; + + if (item.LootType == LootType.Blessed || item.LootType == LootType.Newbied || item.BlessedFor == this) + { + //SendLocalizedMessage( 1060870, "", 0x23 ); // That item is blessed and does not need to be insured + return false; + } + + return true; + } + + private void ToggleItemInsurance_Callback(Mobile from, object obj) + { + if (!CheckAlive()) + return; + + ToggleItemInsurance_Callback(from, obj as Item, true); + } + + private void ToggleItemInsurance_Callback(Mobile from, Item item, bool target) + { + if (item == null || !item.IsChildOf(this)) + { + if (target) + BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleItemInsurance_Callback)); + + SendLocalizedMessage(1060871, "", 0x23); // You can only insure items that you have equipped or that are in your backpack + } + else if (item.Insured) + { + item.Insured = false; + + SendLocalizedMessage(1060874, "", 0x35); // You cancel the insurance on the item + + if (target) + { + BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleItemInsurance_Callback)); + SendLocalizedMessage(1060868, "", 0x23); // Target the item you wish to toggle insurance status on to cancel + } + } + else if (!CanInsure(item)) + { + if (target) + BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleItemInsurance_Callback)); + + SendLocalizedMessage(1060869, "", 0x23); // You cannot insure that + } + else + { + if (!item.PayedInsurance) + { + int cost = GetInsuranceCost(item); + + if (Banker.Withdraw(from, cost)) + { + SendLocalizedMessage(1060398, cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + item.PayedInsurance = true; + } + else + { + SendLocalizedMessage(1061079, "", 0x23); // You lack the funds to purchase the insurance + return; + } + } + + item.Insured = true; + + SendLocalizedMessage(1060873, "", 0x23); // You have insured the item + + if (target) + { + BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleItemInsurance_Callback)); + SendLocalizedMessage(1060868, "", 0x23); // Target the item you wish to toggle insurance status on to cancel + } + } + } + + private void AutoRenewInventoryInsurance() + { + if (!CheckAlive()) + return; + + SendLocalizedMessage(1060881, "", 0x23); // You have selected to automatically reinsure all insured items upon death + AutoRenewInsurance = true; + } + + private void CancelRenewInventoryInsurance() + { + if (!CheckAlive()) + return; + + if (Core.SE) + { + if (!HasGump(typeof(CancelRenewInventoryInsuranceGump))) + SendGump(new CancelRenewInventoryInsuranceGump(this, null)); + } + else + { + SendLocalizedMessage(1061075, "", 0x23); // You have cancelled automatically reinsuring all insured items upon death + AutoRenewInsurance = false; + } + } + + private class CancelRenewInventoryInsuranceGump : Gump + { + private PlayerMobile m_Player; + private ItemInsuranceMenuGump m_InsuranceGump; + + public CancelRenewInventoryInsuranceGump(PlayerMobile player, ItemInsuranceMenuGump insuranceGump) + : base(250, 200) + { + m_Player = player; + m_InsuranceGump = insuranceGump; + + AddBackground(0, 0, 240, 142, 0x13BE); + AddImageTiled(6, 6, 228, 100, 0xA40); + AddImageTiled(6, 116, 228, 20, 0xA40); + AddAlphaRegion(6, 6, 228, 142); + + AddHtmlLocalized(8, 8, 228, 100, 1071021, 0x7FFF, false, false); // You are about to disable inventory insurance auto-renewal. + + AddButton(6, 116, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(40, 118, 450, 20, 1060051, 0x7FFF, false, false); // CANCEL + + AddButton(114, 116, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(148, 118, 450, 20, 1071022, 0x7FFF, false, false); // DISABLE IT! + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (!m_Player.CheckAlive()) + return; + + if (info.ButtonID == 1) + { + m_Player.SendLocalizedMessage(1061075, "", 0x23); // You have cancelled automatically reinsuring all insured items upon death + m_Player.AutoRenewInsurance = false; + } + else + { + m_Player.SendLocalizedMessage(1042021); // Cancelled. + } + + if (m_InsuranceGump != null) + m_Player.SendGump(m_InsuranceGump.NewInstance()); + } + } + + private void OpenItemInsuranceMenu() + { + if (!CheckAlive()) + return; + + List items = new List(); + + foreach (Item item in Items) + { + if (DisplayInItemInsuranceGump(item)) + items.Add(item); + } + + Container pack = Backpack; + + if (pack != null) + items.AddRange(pack.FindItemsByType(true, DisplayInItemInsuranceGump)); + + // TODO: Investigate item sorting + + CloseGump(typeof(ItemInsuranceMenuGump)); + + if (items.Count == 0) + SendLocalizedMessage(1114915, "", 0x35); // None of your current items meet the requirements for insurance. + else + SendGump(new ItemInsuranceMenuGump(this, items.ToArray())); + } + + private bool DisplayInItemInsuranceGump(Item item) + { + return ((item.Visible || AccessLevel >= AccessLevel.GameMaster) && (item.Insured || CanInsure(item))); + } + + private class ItemInsuranceMenuGump : Gump + { + private PlayerMobile m_From; + private Item[] m_Items; + private bool[] m_Insure; + private int m_Page; + + public ItemInsuranceMenuGump(PlayerMobile from, Item[] items) + : this(from, items, null, 0) + { + } + + public ItemInsuranceMenuGump(PlayerMobile from, Item[] items, bool[] insure, int page) + : base(25, 50) + { + m_From = from; + m_Items = items; + + if (insure == null) + { + insure = new bool[items.Length]; + + for (int i = 0; i < items.Length; ++i) + insure[i] = items[i].Insured; + } + + m_Insure = insure; + m_Page = page; + + AddPage(0); + + AddBackground(0, 0, 520, 510, 0x13BE); + AddImageTiled(10, 10, 500, 30, 0xA40); + AddImageTiled(10, 50, 500, 355, 0xA40); + AddImageTiled(10, 415, 500, 80, 0xA40); + AddAlphaRegion(10, 10, 500, 485); + + AddButton(15, 470, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(50, 472, 80, 20, 1011012, 0x7FFF, false, false); // CANCEL + + if (from.AutoRenewInsurance) + AddButton(360, 10, 9723, 9724, 1, GumpButtonType.Reply, 0); + else + AddButton(360, 10, 9720, 9722, 1, GumpButtonType.Reply, 0); + + AddHtmlLocalized(395, 14, 105, 20, 1114122, 0x7FFF, false, false); // AUTO REINSURE + + AddButton(395, 470, 0xFA5, 0xFA6, 2, GumpButtonType.Reply, 0); + AddHtmlLocalized(430, 472, 50, 20, 1006044, 0x7FFF, false, false); // OK + + AddHtmlLocalized(10, 14, 150, 20, 1114121, 0x7FFF, false, false); //
ITEM INSURANCE MENU
+ + AddHtmlLocalized(45, 54, 70, 20, 1062214, 0x7FFF, false, false); // Item + AddHtmlLocalized(250, 54, 70, 20, 1061038, 0x7FFF, false, false); // Cost + AddHtmlLocalized(400, 54, 70, 20, 1114311, 0x7FFF, false, false); // Insured + + int balance = Banker.GetBalance(from); + int cost = 0; + + for (int i = 0; i < items.Length; ++i) + { + if (insure[i]) + cost += GetInsuranceCost(items[i]); + } + + AddHtmlLocalized(15, 420, 300, 20, 1114310, 0x7FFF, false, false); // GOLD AVAILABLE: + AddLabel(215, 420, 0x481, balance.ToString()); + AddHtmlLocalized(15, 435, 300, 20, 1114123, 0x7FFF, false, false); // TOTAL COST OF INSURANCE: + AddLabel(215, 435, 0x481, cost.ToString()); + + if (cost != 0) + { + AddHtmlLocalized(15, 450, 300, 20, 1114125, 0x7FFF, false, false); // NUMBER OF DEATHS PAYABLE: + AddLabel(215, 450, 0x481, (balance / cost).ToString()); + } + + for (int i = page * 4, y = 72; i < (page + 1) * 4 && i < items.Length; ++i, y += 75) + { + Item item = items[i]; + Rectangle2D b = ItemBounds.Table[item.ItemID]; + + AddImageTiledButton(40, y, 0x918, 0x918, 0, GumpButtonType.Page, 0, item.ItemID, item.Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y); + AddItemProperty(item.Serial); + + if (insure[i]) + { + AddButton(400, y, 9723, 9724, 100 + i, GumpButtonType.Reply, 0); + AddLabel(250, y, 0x481, GetInsuranceCost(item).ToString()); + } + else + { + AddButton(400, y, 9720, 9722, 100 + i, GumpButtonType.Reply, 0); + AddLabel(250, y, 0x66C, GetInsuranceCost(item).ToString()); + } + } + + if (page >= 1) + { + AddButton(15, 380, 0xFAE, 0xFAF, 3, GumpButtonType.Reply, 0); + AddHtmlLocalized(50, 380, 450, 20, 1044044, 0x7FFF, false, false); // PREV PAGE + } + + if ((page + 1) * 4 < items.Length) + { + AddButton(400, 380, 0xFA5, 0xFA7, 4, GumpButtonType.Reply, 0); + AddHtmlLocalized(435, 380, 70, 20, 1044045, 0x7FFF, false, false); // NEXT PAGE + } + } + + public ItemInsuranceMenuGump NewInstance() + { + return new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (info.ButtonID == 0 || !m_From.CheckAlive()) + return; + + switch (info.ButtonID) + { + case 1: // Auto Reinsure + { + if (m_From.AutoRenewInsurance) + { + if (!m_From.HasGump(typeof(CancelRenewInventoryInsuranceGump))) + m_From.SendGump(new CancelRenewInventoryInsuranceGump(m_From, this)); + } + else + { + m_From.AutoRenewInventoryInsurance(); + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); + } + + break; + } + case 2: // OK + { + m_From.SendGump(new ItemInsuranceMenuConfirmGump(m_From, m_Items, m_Insure, m_Page)); + + break; + } + case 3: // Prev + { + if (m_Page >= 1) + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page - 1)); + + break; + } + case 4: // Next + { + if ((m_Page + 1) * 4 < m_Items.Length) + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page + 1)); + + break; + } + default: + { + int idx = info.ButtonID - 100; + + if (idx >= 0 && idx < m_Items.Length) + m_Insure[idx] = !m_Insure[idx]; + + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); + + break; + } + } + } + } + + private class ItemInsuranceMenuConfirmGump : Gump + { + private PlayerMobile m_From; + private Item[] m_Items; + private bool[] m_Insure; + private int m_Page; + + public ItemInsuranceMenuConfirmGump(PlayerMobile from, Item[] items, bool[] insure, int page) + : base(250, 200) + { + m_From = from; + m_Items = items; + m_Insure = insure; + m_Page = page; + + AddBackground(0, 0, 240, 142, 0x13BE); + AddImageTiled(6, 6, 228, 100, 0xA40); + AddImageTiled(6, 116, 228, 20, 0xA40); + AddAlphaRegion(6, 6, 228, 142); + + AddHtmlLocalized(8, 8, 228, 100, 1114300, 0x7FFF, false, false); // Do you wish to insure all newly selected items? + + AddButton(6, 116, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(40, 118, 450, 20, 1060051, 0x7FFF, false, false); // CANCEL + + AddButton(114, 116, 0xFA5, 0xFA7, 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(148, 118, 450, 20, 1073996, 0x7FFF, false, false); // ACCEPT + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (!m_From.CheckAlive()) + return; + + if (info.ButtonID == 1) + { + for (int i = 0; i < m_Items.Length; ++i) + { + Item item = m_Items[i]; + + if (item.Insured != m_Insure[i]) + m_From.ToggleItemInsurance_Callback(m_From, item, false); + } + } + else + { + m_From.SendLocalizedMessage(1042021); // Cancelled. + m_From.SendGump(new ItemInsuranceMenuGump(m_From, m_Items, m_Insure, m_Page)); + } + } + } + + #endregion + + #region Toggle Quest Item + + private void ToggleQuestItem() + { + if (!CheckAlive()) + return; + + ToggleQuestItemTarget(); + } + + private void ToggleQuestItemTarget() + { + Server.Engines.MLQuests.Gumps.BaseQuestGump.CloseOtherGumps(this); + CloseGump(typeof(Server.Engines.MLQuests.Gumps.QuestLogDetailedGump)); + CloseGump(typeof(Server.Engines.MLQuests.Gumps.QuestLogGump)); + CloseGump(typeof(Server.Engines.MLQuests.Gumps.QuestOfferGump)); + //CloseGump( typeof( UnknownGump802 ) ); + //CloseGump( typeof( UnknownGump804 ) ); + + BeginTarget(-1, false, TargetFlags.None, new TargetCallback(ToggleQuestItem_Callback)); + SendLocalizedMessage(1072352); // Target the item you wish to toggle Quest Item status on to cancel + } + + private void ToggleQuestItem_Callback(Mobile from, object obj) + { + if (!CheckAlive()) + return; + + Item item = obj as Item; + + if (item == null) + return; + + if (from.Backpack == null || item.Parent != from.Backpack) + { + SendLocalizedMessage(1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item. + } + else if (item.QuestItem) + { + item.QuestItem = false; + SendLocalizedMessage(1072354); // You remove Quest Item status from the item + } + else if (MLQuestSystem.MarkQuestItem(this, item)) + { + SendLocalizedMessage(1072353); // You set the item to Quest Item status + } + else + { + SendLocalizedMessage(1072355, "", 0x23); // That item does not match any of your quest criteria + } + + ToggleQuestItemTarget(); + } + + #endregion + + private void ToggleTrades() + { + RefuseTrades = !RefuseTrades; + } + + private void GetVendor() + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( CheckAlive() && house != null && house.IsOwner( this ) && house.InternalizedVendors.Count > 0 ) + { + CloseGump( typeof( ReclaimVendorGump ) ); + SendGump( new ReclaimVendorGump( house ) ); + } + } + + private void LeaveHouse() + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null ) + this.Location = house.BanLocation; + } + + private delegate void ContextCallback(); + + private class CallbackEntry : ContextMenuEntry + { + private ContextCallback m_Callback; + + public CallbackEntry( int number, ContextCallback callback ) : this( number, -1, callback ) + { + } + + public CallbackEntry( int number, int range, ContextCallback callback ) : base( number, range ) + { + m_Callback = callback; + } + + public override void OnClick() + { + if ( m_Callback != null ) + m_Callback(); + } + } + + public override void DisruptiveAction() + { + if( Meditating ) + { + RemoveBuff( BuffIcon.ActiveMeditation ); + } + + base.DisruptiveAction(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( this == from && !Warmode ) + { + IMount mount = Mount; + + if ( mount != null && !DesignContext.Check( this ) ) + return; + } + + base.OnDoubleClick( from ); + } + + public override void DisplayPaperdollTo( Mobile to ) + { + if ( DesignContext.Check( this ) ) + base.DisplayPaperdollTo( to ); + } + + private static bool m_NoRecursion; + + public override bool CheckEquip( Item item ) + { + if ( !base.CheckEquip( item ) ) + return false; + + #region Dueling + if (m_DuelContext != null && !m_DuelContext.AllowItemEquip(this, item)) + return false; + #endregion + + #region Factions + FactionItem factionItem = FactionItem.Find( item ); + + if ( factionItem != null ) + { + Faction faction = Faction.Find( this ); + + if ( faction == null ) + { + SendLocalizedMessage( 1010371 ); // You cannot equip a faction item! + return false; + } + else if ( faction != factionItem.Faction ) + { + SendLocalizedMessage( 1010372 ); // You cannot equip an opposing faction's item! + return false; + } + else + { + int maxWearables = FactionItem.GetMaxWearables( this ); + + for ( int i = 0; i < Items.Count; ++i ) + { + Item equiped = Items[i]; + + if ( item != equiped && FactionItem.Find( equiped ) != null ) + { + if ( --maxWearables == 0 ) + { + SendLocalizedMessage( 1010373 ); // You do not have enough rank to equip more faction items! + return false; + } + } + } + } + } + #endregion + + if ( this.AccessLevel < AccessLevel.GameMaster && item.Layer != Layer.Mount && this.HasTrade ) + { + BounceInfo bounce = item.GetBounce(); + + if ( bounce != null ) + { + if ( bounce.m_Parent is Item ) + { + Item parent = (Item) bounce.m_Parent; + + if ( parent == this.Backpack || parent.IsChildOf( this.Backpack ) ) + return true; + } + else if ( bounce.m_Parent == this ) + { + return true; + } + } + + SendLocalizedMessage( 1004042 ); // You can only equip what you are already carrying while you have a trade pending. + return false; + } + + return true; + } + + public override bool CheckTrade( Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, int plusItems, int plusWeight ) + { + int msgNum = 0; + + if ( cont == null ) + { + if ( to.Holding != null ) + msgNum = 1062727; // You cannot trade with someone who is dragging something. + else if ( this.HasTrade ) + msgNum = 1062781; // You are already trading with someone else! + else if ( to.HasTrade ) + msgNum = 1062779; // That person is already involved in a trade + else if (to is PlayerMobile && ((PlayerMobile)to).RefuseTrades) + msgNum = 1154111; // ~1_NAME~ is refusing all trades. + } + + if ( msgNum == 0 ) + { + if ( cont != null ) + { + plusItems += cont.TotalItems; + plusWeight += cont.TotalWeight; + } + + if ( this.Backpack == null || !this.Backpack.CheckHold( this, item, false, checkItems, plusItems, plusWeight ) ) + msgNum = 1004040; // You would not be able to hold this if the trade failed. + else if ( to.Backpack == null || !to.Backpack.CheckHold( to, item, false, checkItems, plusItems, plusWeight ) ) + msgNum = 1004039; // The recipient of this trade would not be able to carry this. + else + msgNum = CheckContentForTrade( item ); + } + + if (msgNum != 0) + { + if (message) + { + if (msgNum == 1154111) + SendLocalizedMessage(msgNum, to.Name); + else + SendLocalizedMessage(msgNum); + } + + return false; + } + + return true; + } + + private static int CheckContentForTrade( Item item ) + { + if ( item is TrapableContainer && ((TrapableContainer)item).TrapType != TrapType.None ) + return 1004044; // You may not trade trapped items. + + if ( SkillHandlers.StolenItem.IsStolen( item ) ) + return 1004043; // You may not trade recently stolen items. + + if ( item is Container ) + { + foreach ( Item subItem in item.Items ) + { + int msg = CheckContentForTrade( subItem ); + + if ( msg != 0 ) + return msg; + } + } + + return 0; + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + if ( !base.CheckNonlocalDrop( from, item, target ) ) + return false; + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + Container pack = this.Backpack; + if ( from == this && this.HasTrade && ( target == pack || target.IsChildOf( pack ) ) ) + { + BounceInfo bounce = item.GetBounce(); + + if ( bounce != null && bounce.m_Parent is Item ) + { + Item parent = (Item) bounce.m_Parent; + + if ( parent == pack || parent.IsChildOf( pack ) ) + return true; + } + + SendLocalizedMessage( 1004041 ); // You can't do that while you have a trade pending. + return false; + } + + return true; + } + + protected override void OnLocationChange( Point3D oldLocation ) + { + CheckLightLevels( false ); + + #region Dueling + if (m_DuelContext != null) + m_DuelContext.OnLocationChanged(this); + #endregion + + DesignContext context = m_DesignContext; + + if ( context == null || m_NoRecursion ) + return; + + m_NoRecursion = true; + + HouseFoundation foundation = context.Foundation; + + int newX = this.X, newY = this.Y; + int newZ = foundation.Z + HouseFoundation.GetLevelZ( context.Level, context.Foundation ); + + int startX = foundation.X + foundation.Components.Min.X + 1; + int startY = foundation.Y + foundation.Components.Min.Y + 1; + int endX = startX + foundation.Components.Width - 1; + int endY = startY + foundation.Components.Height - 2; + + if ( newX >= startX && newY >= startY && newX < endX && newY < endY && Map == foundation.Map ) + { + if ( Z != newZ ) + Location = new Point3D( X, Y, newZ ); + + m_NoRecursion = false; + return; + } + + Location = new Point3D( foundation.X, foundation.Y, newZ ); + Map = foundation.Map; + + m_NoRecursion = false; + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m is BaseCreature && !((BaseCreature)m).Controlled ) + return ( !Alive || !m.Alive || IsDeadBondedPet || m.IsDeadBondedPet ) || ( Hidden && AccessLevel > AccessLevel.Player ); + + #region Dueling + if (Region.IsPartOf(typeof(Engines.ConPVP.SafeZone)) && m is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)m; + + if (pm.DuelContext == null || pm.DuelPlayer == null || !pm.DuelContext.Started || pm.DuelContext.Finished || pm.DuelPlayer.Eliminated) + return true; + } + #endregion + + return base.OnMoveOver( m ); + } + + public override bool CheckShove( Mobile shoved ) + { + if( m_IgnoreMobiles || TransformationSpellHelper.UnderTransformation( shoved, typeof( WraithFormSpell ) ) ) + return true; + else + return base.CheckShove( shoved ); + } + + protected override void OnMapChange( Map oldMap ) + { + if ( (Map != Faction.Facet && oldMap == Faction.Facet) || (Map == Faction.Facet && oldMap != Faction.Facet) ) + InvalidateProperties(); + + #region Dueling + if (m_DuelContext != null) + m_DuelContext.OnMapChanged(this); + #endregion + + DesignContext context = m_DesignContext; + + if ( context == null || m_NoRecursion ) + return; + + m_NoRecursion = true; + + HouseFoundation foundation = context.Foundation; + + if ( Map != foundation.Map ) + Map = foundation.Map; + + m_NoRecursion = false; + } + + public override void OnBeneficialAction( Mobile target, bool isCriminal ) + { + if ( m_SentHonorContext != null ) + m_SentHonorContext.OnSourceBeneficialAction( target ); + + base.OnBeneficialAction( target, isCriminal ); + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + int disruptThreshold; + + if ( !Core.AOS ) + disruptThreshold = 0; + else if ( from != null && from.Player ) + disruptThreshold = 18; + else + disruptThreshold = 25; + + if ( amount > disruptThreshold ) + { + BandageContext c = BandageContext.GetContext( this ); + + if ( c != null ) + c.Slip(); + } + + if( Confidence.IsRegenerating( this ) ) + Confidence.StopRegenerating( this ); + + WeightOverloading.FatigueOnDamage( this, amount ); + + if ( m_ReceivedHonorContext != null ) + m_ReceivedHonorContext.OnTargetDamaged( from, amount ); + if ( m_SentHonorContext != null ) + m_SentHonorContext.OnSourceDamaged( from, amount ); + + if ( willKill && from is PlayerMobile ) + Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( ((PlayerMobile) from).RecoverAmmo ) ); + + base.OnDamage( amount, from, willKill ); + } + + public override void Resurrect() + { + bool wasAlive = this.Alive; + + base.Resurrect(); + + if ( this.Alive && !wasAlive ) + { + Item deathRobe = new DeathRobe(); + + if ( !EquipItem( deathRobe ) ) + deathRobe.Delete(); + } + } + + public override double RacialSkillBonus + { + get + { + if( Core.ML && this.Race == Race.Human ) + return 20.0; + + return 0; + } + } + + public override void OnWarmodeChanged() + { + if ( !Warmode ) + Timer.DelayCall( TimeSpan.FromSeconds( 10 ), new TimerCallback( RecoverAmmo ) ); + } + + private Mobile m_InsuranceAward; + private int m_InsuranceCost; + private int m_InsuranceBonus; + private List m_EquipSnapshot; + + public List EquipSnapshot + { + get { return m_EquipSnapshot; } + } + + private bool FindItems_Callback(Item item) + { + if (!item.Deleted && (item.LootType == LootType.Blessed || item.Insured)) + { + if (this.Backpack != item.ParentEntity) + { + return true; + } + } + return false; + } + + public override bool OnBeforeDeath() + { + NetState state = NetState; + + if ( state != null ) + state.CancelAllTrades(); + + DropHolding(); + + if (Core.AOS && Backpack != null && !Backpack.Deleted) + { + List ilist = Backpack.FindItemsByType(FindItems_Callback); + + for (int i = 0; i < ilist.Count; i++) + { + Backpack.AddItem(ilist[i]); + } + } + + m_EquipSnapshot = new List( this.Items ); + m_NonAutoreinsuredItems = 0; + m_InsuranceCost = 0; + m_InsuranceAward = base.FindMostRecentDamager( false ); + + if ( m_InsuranceAward is BaseCreature ) + { + Mobile master = ((BaseCreature)m_InsuranceAward).GetMaster(); + + if ( master != null ) + m_InsuranceAward = master; + } + + if ( m_InsuranceAward != null && (!m_InsuranceAward.Player || m_InsuranceAward == this) ) + m_InsuranceAward = null; + + if ( m_InsuranceAward is PlayerMobile ) + ((PlayerMobile)m_InsuranceAward).m_InsuranceBonus = 0; + + if ( m_ReceivedHonorContext != null ) + m_ReceivedHonorContext.OnTargetKilled(); + if ( m_SentHonorContext != null ) + m_SentHonorContext.OnSourceKilled(); + + RecoverAmmo(); + + return base.OnBeforeDeath(); + } + + private bool CheckInsuranceOnDeath( Item item ) + { + if ( InsuranceEnabled && item.Insured ) + { + #region Dueling + if (m_DuelPlayer != null && m_DuelContext != null && m_DuelContext.Registered && m_DuelContext.Started && !m_DuelPlayer.Eliminated) + return true; + #endregion + + if (AutoRenewInsurance) + { + int cost = GetInsuranceCost(item); + + if (m_InsuranceAward != null) + cost /= 2; + + if ( Banker.Withdraw( this, cost ) ) + { + m_InsuranceCost += cost; + item.PayedInsurance = true; + SendLocalizedMessage(1060398, cost.ToString()); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + SendLocalizedMessage( 1061079, "", 0x23 ); // You lack the funds to purchase the insurance + item.PayedInsurance = false; + item.Insured = false; + m_NonAutoreinsuredItems++; + } + } + else + { + item.PayedInsurance = false; + item.Insured = false; + } + + if ( m_InsuranceAward != null ) + { + if ( Banker.Deposit( m_InsuranceAward, 300 ) ) + { + if ( m_InsuranceAward is PlayerMobile ) + ((PlayerMobile)m_InsuranceAward).m_InsuranceBonus += 300; + } + } + + return true; + } + + return false; + } + + public override DeathMoveResult GetParentMoveResultFor( Item item ) + { + // It seems all items are unmarked on death, even blessed/insured ones + if (item.QuestItem) + item.QuestItem = false; + + if ( CheckInsuranceOnDeath( item ) ) + return DeathMoveResult.MoveToBackpack; + + DeathMoveResult res = base.GetParentMoveResultFor( item ); + + if ( res == DeathMoveResult.MoveToCorpse && item.Movable && this.Young ) + res = DeathMoveResult.MoveToBackpack; + + return res; + } + + public override DeathMoveResult GetInventoryMoveResultFor( Item item ) + { + // It seems all items are unmarked on death, even blessed/insured ones + if (item.QuestItem) + item.QuestItem = false; + + if ( CheckInsuranceOnDeath( item ) ) + return DeathMoveResult.MoveToBackpack; + + DeathMoveResult res = base.GetInventoryMoveResultFor( item ); + + if ( res == DeathMoveResult.MoveToCorpse && item.Movable && this.Young ) + res = DeathMoveResult.MoveToBackpack; + + return res; + } + + public override void OnDeath( Container c ) + { + if (m_NonAutoreinsuredItems > 0) + { + SendLocalizedMessage(1061115); + } + + base.OnDeath(c); + + HueMod = -1; + NameMod = null; + SavagePaintExpiration = TimeSpan.Zero; + + SetHairMods( -1, -1 ); + + PolymorphSpell.StopTimer( this ); + IncognitoSpell.StopTimer( this ); + DisguiseTimers.RemoveTimer( this ); + + EndAction( typeof( PolymorphSpell ) ); + EndAction( typeof( IncognitoSpell ) ); + + MeerMage.StopEffect( this, false ); + + SkillHandlers.StolenItem.ReturnOnDeath( this, c ); + + if ( m_PermaFlags.Count > 0 ) + { + m_PermaFlags.Clear(); + + if ( c is Corpse ) + ((Corpse)c).Criminal = true; + + if ( SkillHandlers.Stealing.ClassicMode ) + Criminal = true; + } + + if ( this.Kills >= 5 && DateTime.Now >= m_NextJustAward ) + { + Mobile m = FindMostRecentDamager( false ); + + if( m is BaseCreature ) + m = ((BaseCreature)m).GetMaster(); + + if ( m != null && m is PlayerMobile && m != this ) + { + bool gainedPath = false; + + int pointsToGain = 0; + + pointsToGain += (int) Math.Sqrt( this.GameTime.TotalSeconds * 4 ); + pointsToGain *= 5; + pointsToGain += (int) Math.Pow( this.Skills.Total / 250, 2 ); + + if ( VirtueHelper.Award( m, VirtueName.Justice, pointsToGain, ref gainedPath ) ) + { + if ( gainedPath ) + m.SendLocalizedMessage( 1049367 ); // You have gained a path in Justice! + else + m.SendLocalizedMessage( 1049363 ); // You have gained in Justice. + + m.FixedParticles( 0x375A, 9, 20, 5027, EffectLayer.Waist ); + m.PlaySound( 0x1F7 ); + + m_NextJustAward = DateTime.Now + TimeSpan.FromMinutes( pointsToGain / 3 ); + } + } + } + + + if ( m_InsuranceAward is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m_InsuranceAward; + + if ( pm.m_InsuranceBonus > 0 ) + pm.SendLocalizedMessage( 1060397, pm.m_InsuranceBonus.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + } + + Mobile killer = this.FindMostRecentDamager( true ); + + + + if ( killer is BaseCreature ) + { + BaseCreature bc = (BaseCreature)killer; + + Mobile master = bc.GetMaster(); + if( master != null ) + killer = master; + } + + if (this.Young && m_DuelContext == null) + { + if (YoungDeathTeleport()) + Timer.DelayCall(TimeSpan.FromSeconds(2.5), new TimerCallback(SendYoungDeathNotice)); + } + + if (m_DuelContext == null || !m_DuelContext.Registered || !m_DuelContext.Started || m_DuelPlayer == null || m_DuelPlayer.Eliminated) + Faction.HandleDeath(this, killer); + + Server.Guilds.Guild.HandleDeath(this, killer); + + MLQuestSystem.HandleDeath(this); + + #region Dueling + if (m_DuelContext != null) + m_DuelContext.OnDeath(this, c); + #endregion + + if( m_BuffTable != null ) + { + List list = new List(); + + foreach( BuffInfo buff in m_BuffTable.Values ) + { + if( !buff.RetainThroughDeath ) + { + list.Add( buff ); + } + } + + for( int i = 0; i < list.Count; i++ ) + { + RemoveBuff( list[i] ); + } + } + + // Plume : on log les morts + string sKilled = String.Format("{0} ({1})", this.Name, (this.Account != null ? this.Account.Username : "Aucun")); + + string sKiller = "un pouvoir inconnu..."; + if(killer != null) + sKiller = String.Format("{0} ({1})", killer.Name, (killer.Account != null ? killer.Account.Username : killer.GetType().FullName)); + + LogDeath(String.Format(DateTime.Now + ": {0} a �t� tu� par {1}", sKilled, sKiller)); + } + + // Plume : M�thode pour logger les morts + public static void LogDeath(string msg) + { + if (!Directory.Exists("Logs")) + Directory.CreateDirectory("Logs"); + + string directory = "Logs/Death"; + + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + try + { + StreamWriter writer = new StreamWriter(Path.Combine(directory, String.Format("Death-{0}.log", DateTime.Now.ToLongDateString())), true); + writer.AutoFlush = true; + writer.WriteLine(msg); + writer.Close(); + } + catch(Exception ex) + { + Console.WriteLine("PlayerMobile.LogDeath : " + ex.Message); + } + } + + private List m_PermaFlags; + private List m_VisList; + private Hashtable m_AntiMacroTable; + private TimeSpan m_GameTime; + private TimeSpan m_ShortTermElapse; + private TimeSpan m_LongTermElapse; + private DateTime m_SessionStart; + private DateTime m_LastEscortTime; + private DateTime m_LastPetBallTime; + private DateTime m_NextSmithBulkOrder; + private DateTime m_NextTailorBulkOrder; + private DateTime m_SavagePaintExpiration; + private SkillName m_Learning = (SkillName)(-1); + + public SkillName Learning + { + get{ return m_Learning; } + set{ m_Learning = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan SavagePaintExpiration + { + get + { + TimeSpan ts = m_SavagePaintExpiration - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + return ts; + } + set + { + m_SavagePaintExpiration = DateTime.Now + value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan NextSmithBulkOrder + { + get + { + TimeSpan ts = m_NextSmithBulkOrder - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + return ts; + } + set + { + try{ m_NextSmithBulkOrder = DateTime.Now + value; } + catch{} + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan NextTailorBulkOrder + { + get + { + TimeSpan ts = m_NextTailorBulkOrder - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + return ts; + } + set + { + try{ m_NextTailorBulkOrder = DateTime.Now + value; } + catch{} + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastEscortTime + { + get{ return m_LastEscortTime; } + set{ m_LastEscortTime = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastPetBallTime + { + get{ return m_LastPetBallTime; } + set{ m_LastPetBallTime = value; } + } + + public PlayerMobile() + { + m_AutoStabled = new List(); + + m_VisList = new List(); + m_PermaFlags = new List(); + m_AntiMacroTable = new Hashtable(); + m_RecentlyReported = new List(); + + m_BOBFilter = new Engines.BulkOrders.BOBFilter(); + + m_GameTime = TimeSpan.Zero; + m_ShortTermElapse = TimeSpan.FromHours( 8.0 ); + m_LongTermElapse = TimeSpan.FromHours( 40.0 ); + + m_JusticeProtectors = new List(); + m_GuildRank = Guilds.RankDefinition.Lowest; + + m_ChampionTitles = new ChampionTitleInfo(); + + InvalidateMyRunUO(); + } + + public override bool MutateSpeech( List hears, ref string text, ref object context ) + { + if ( Alive ) + return false; + + if ( Core.ML && Skills[SkillName.SpiritSpeak].Value >= 100.0 ) + return false; + + if ( Core.AOS ) + { + for ( int i = 0; i < hears.Count; ++i ) + { + Mobile m = hears[i]; + + if ( m != this && m.Skills[SkillName.SpiritSpeak].Value >= 100.0 ) + return false; + } + } + + return base.MutateSpeech( hears, ref text, ref context ); + } + + public override void DoSpeech( string text, int[] keywords, MessageType type, int hue ) + { + if( Guilds.Guild.NewGuildSystem && (type == MessageType.Guild || type == MessageType.Alliance) ) + { + Guilds.Guild g = this.Guild as Guilds.Guild; + if( g == null ) + { + SendLocalizedMessage( 1063142 ); // You are not in a guild! + } + else if( type == MessageType.Alliance ) + { + if( g.Alliance != null && g.Alliance.IsMember( g ) ) + { + //g.Alliance.AllianceTextMessage( hue, "[Alliance][{0}]: {1}", this.Name, text ); + g.Alliance.AllianceChat( this, text ); + SendToStaffMessage( this, "[Alliance]: {0}", text ); + + m_AllianceMessageHue = hue; + } + else + { + SendLocalizedMessage( 1071020 ); // You are not in an alliance! + } + } + else //Type == MessageType.Guild + { + m_GuildMessageHue = hue; + + g.GuildChat( this, text ); + SendToStaffMessage( this, "[Guild]: {0}", text ); + } + } + else + { + base.DoSpeech( text, keywords, type, hue ); + } + } + + private static void SendToStaffMessage( Mobile from, string text ) + { + Packet p = null; + + foreach( NetState ns in from.GetClientsInRange( 8 ) ) + { + Mobile mob = ns.Mobile; + + if( mob != null && mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > from.AccessLevel ) + { + if( p == null ) + p = Packet.Acquire( new UnicodeMessage( from.Serial, from.Body, MessageType.Regular, from.SpeechHue, 3, from.Language, from.Name, text ) ); + + ns.Send( p ); + } + } + + Packet.Release( p ); + } + + private static void SendToStaffMessage( Mobile from, string format, params object[] args ) + { + SendToStaffMessage( from, String.Format( format, args ) ); + } + + public override void Damage( int amount, Mobile from ) + { + if ( Spells.Necromancy.EvilOmenSpell.TryEndEffect( this ) ) + amount = (int)(amount * 1.25); + + Mobile oath = Spells.Necromancy.BloodOathSpell.GetBloodOath( from ); + + /* Per EA's UO Herald Pub48 (ML): + * ((resist spellsx10)/20 + 10=percentage of damage resisted) + */ + + if ( oath == this ) + { + amount = (int)(amount * 1.1); + + if( amount > 35 && from is PlayerMobile ) /* capped @ 35, seems no expansion */ + { + amount = 35; + } + + if( Core.ML ) + { + from.Damage( (int)(amount * ( 1 - ((( from.Skills.MagicResist.Value * .5 ) + 10) / 100 ))), this ); + } + else + { + from.Damage( amount, this ); + } + } + + if (from != null && Talisman is BaseTalisman) + { + BaseTalisman talisman = (BaseTalisman)Talisman; + + if (talisman.Protection != null && talisman.Protection.Type != null) + { + Type type = talisman.Protection.Type; + + if (type == from.GetType()) + amount *= 1 - (int)(((double)talisman.Protection.Amount) / 100); + } + } + + base.Damage( amount, from ); + } + + #region Poison + + public override ApplyPoisonResult ApplyPoison( Mobile from, Poison poison ) + { + if ( !Alive ) + return ApplyPoisonResult.Immune; + + if ( Spells.Necromancy.EvilOmenSpell.TryEndEffect( this ) ) + poison = PoisonImpl.IncreaseLevel( poison ); + + ApplyPoisonResult result = base.ApplyPoison( from, poison ); + + if ( from != null && result == ApplyPoisonResult.Poisoned && PoisonTimer is PoisonImpl.PoisonTimer ) + (PoisonTimer as PoisonImpl.PoisonTimer).From = from; + + return result; + } + + public override bool CheckPoisonImmunity( Mobile from, Poison poison ) + { + if (this.Young && (DuelContext == null || !DuelContext.Started || DuelContext.Finished)) + return true; + + return base.CheckPoisonImmunity( from, poison ); + } + + public override void OnPoisonImmunity( Mobile from, Poison poison ) + { + if (this.Young && (DuelContext == null || !DuelContext.Started || DuelContext.Finished)) + SendLocalizedMessage(502808); // You would have been poisoned, were you not new to the land of Britannia. Be careful in the future. + else + base.OnPoisonImmunity( from, poison ); + } + + #endregion + + public PlayerMobile( Serial s ) : base( s ) + { + m_VisList = new List(); + m_AntiMacroTable = new Hashtable(); + InvalidateMyRunUO(); + } + + public List VisibilityList + { + get{ return m_VisList; } + } + + public List PermaFlags + { + get{ return m_PermaFlags; } + } + + public override int Luck{ get{ return AosAttributes.GetValue( this, AosAttribute.Luck ); } } + + public override bool IsHarmfulCriminal( Mobile target ) + { + if ( SkillHandlers.Stealing.ClassicMode && target is PlayerMobile && ((PlayerMobile)target).m_PermaFlags.Count > 0 ) + { + int noto = Notoriety.Compute( this, target ); + + if ( noto == Notoriety.Innocent ) + target.Delta( MobileDelta.Noto ); + + return false; + } + + if ( target is BaseCreature && ((BaseCreature)target).InitialInnocent && !((BaseCreature)target).Controlled ) + return false; + + if ( Core.ML && target is BaseCreature && ((BaseCreature)target).Controlled && this == ((BaseCreature)target).ControlMaster ) + return false; + + return base.IsHarmfulCriminal( target ); + } + + public bool AntiMacroCheck( Skill skill, object obj ) + { + if ( obj == null || m_AntiMacroTable == null || this.AccessLevel != AccessLevel.Player ) + return true; + + Hashtable tbl = (Hashtable)m_AntiMacroTable[skill]; + if ( tbl == null ) + m_AntiMacroTable[skill] = tbl = new Hashtable(); + + CountAndTimeStamp count = (CountAndTimeStamp)tbl[obj]; + if ( count != null ) + { + if ( count.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.Now ) + { + count.Count = 1; + return true; + } + else + { + ++count.Count; + if ( count.Count <= SkillCheck.Allowance ) + return true; + else + return false; + } + } + else + { + tbl[obj] = count = new CountAndTimeStamp(); + count.Count = 1; + + return true; + } + } + + private void RevertHair() + { + SetHairMods( -1, -1 ); + } + + private Engines.BulkOrders.BOBFilter m_BOBFilter; + + public Engines.BulkOrders.BOBFilter BOBFilter + { + get{ return m_BOBFilter; } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + int counttype =31; + + switch ( version ) + { + // Plume addiction + case 33: + { + counttype = reader.ReadInt(); + goto case 32; + } + case 32: + { + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + for (int i = 0; i < counttype; i++) + Addiction[i] = reader.ReadDouble(); + + goto case 31; + } + //Vinds : ajout pour les chevaliers d'artedar + case 31: + { + m_IsArtedarKnight = reader.ReadBool(); + goto case 30; + } + + // Scriptiz : ajout pour l'alignement sur Malas + case 30: + { + m_Alignment = (Alignment)reader.ReadInt(); + goto case 29; + } + // Scriptiz : ajout pour les f�es + case 29: + { + m_IsFairy = reader.ReadBool(); + goto case 28; + } + case 28: + { + m_PeacedUntil = reader.ReadDateTime(); + + goto case 27; + } + case 27: + { + m_AnkhNextUse = reader.ReadDateTime(); + + goto case 26; + } + case 26: + { + m_AutoStabled = reader.ReadStrongMobileList(); + + goto case 25; + } + case 25: + { + int recipeCount = reader.ReadInt(); + + if( recipeCount > 0 ) + { + m_AcquiredRecipes = new Dictionary(); + + for( int i = 0; i < recipeCount; i++ ) + { + int r = reader.ReadInt(); + if( reader.ReadBool() ) //Don't add in recipies which we haven't gotten or have been removed + m_AcquiredRecipes.Add( r, true ); + } + } + goto case 24; + } + case 24: + { + m_LastHonorLoss = reader.ReadDeltaTime(); + goto case 23; + } + case 23: + { + m_ChampionTitles = new ChampionTitleInfo( reader ); + goto case 22; + } + case 22: + { + m_LastValorLoss = reader.ReadDateTime(); + goto case 21; + } + case 21: + { + m_ToTItemsTurnedIn = reader.ReadEncodedInt(); + m_ToTTotalMonsterFame = reader.ReadInt(); + goto case 20; + } + case 20: + { + m_AllianceMessageHue = reader.ReadEncodedInt(); + m_GuildMessageHue = reader.ReadEncodedInt(); + + goto case 19; + } + case 19: + { + int rank = reader.ReadEncodedInt(); + int maxRank = Guilds.RankDefinition.Ranks.Length -1; + if( rank > maxRank ) + rank = maxRank; + + m_GuildRank = Guilds.RankDefinition.Ranks[rank]; + m_LastOnline = reader.ReadDateTime(); + goto case 18; + } + case 18: + { + m_SolenFriendship = (SolenFriendship) reader.ReadEncodedInt(); + + goto case 17; + } + case 17: // changed how DoneQuests is serialized + case 16: + { + m_Quest = QuestSerializer.DeserializeQuest( reader ); + + if ( m_Quest != null ) + m_Quest.From = this; + + int count = reader.ReadEncodedInt(); + + if ( count > 0 ) + { + m_DoneQuests = new List(); + + for ( int i = 0; i < count; ++i ) + { + Type questType = QuestSerializer.ReadType( QuestSystem.QuestTypes, reader ); + DateTime restartTime; + + if ( version < 17 ) + restartTime = DateTime.MaxValue; + else + restartTime = reader.ReadDateTime(); + + m_DoneQuests.Add( new QuestRestartInfo( questType, restartTime ) ); + } + } + + m_Profession = reader.ReadEncodedInt(); + goto case 15; + } + case 15: + { + m_LastCompassionLoss = reader.ReadDeltaTime(); + goto case 14; + } + case 14: + { + m_CompassionGains = reader.ReadEncodedInt(); + + if ( m_CompassionGains > 0 ) + m_NextCompassionDay = reader.ReadDeltaTime(); + + goto case 13; + } + case 13: // just removed m_PayedInsurance list + case 12: + { + m_BOBFilter = new Engines.BulkOrders.BOBFilter( reader ); + goto case 11; + } + case 11: + { + if ( version < 13 ) + { + List payed = reader.ReadStrongItemList(); + + for ( int i = 0; i < payed.Count; ++i ) + payed[i].PayedInsurance = true; + } + + goto case 10; + } + case 10: + { + if ( reader.ReadBool() ) + { + m_HairModID = reader.ReadInt(); + m_HairModHue = reader.ReadInt(); + m_BeardModID = reader.ReadInt(); + m_BeardModHue = reader.ReadInt(); + } + + goto case 9; + } + case 9: + { + SavagePaintExpiration = reader.ReadTimeSpan(); + + if ( SavagePaintExpiration > TimeSpan.Zero ) + { + BodyMod = ( Female ? 184 : 183 ); + HueMod = 0; + } + + goto case 8; + } + case 8: + { + m_NpcGuild = (NpcGuild)reader.ReadInt(); + m_NpcGuildJoinTime = reader.ReadDateTime(); + m_NpcGuildGameTime = reader.ReadTimeSpan(); + goto case 7; + } + case 7: + { + m_PermaFlags = reader.ReadStrongMobileList(); + goto case 6; + } + case 6: + { + NextTailorBulkOrder = reader.ReadTimeSpan(); + goto case 5; + } + case 5: + { + NextSmithBulkOrder = reader.ReadTimeSpan(); + goto case 4; + } + case 4: + { + m_LastJusticeLoss = reader.ReadDeltaTime(); + m_JusticeProtectors = reader.ReadStrongMobileList(); + goto case 3; + } + case 3: + { + m_LastSacrificeGain = reader.ReadDeltaTime(); + m_LastSacrificeLoss = reader.ReadDeltaTime(); + m_AvailableResurrects = reader.ReadInt(); + goto case 2; + } + case 2: + { + m_Flags = (PlayerFlag)reader.ReadInt(); + goto case 1; + } + case 1: + { + m_LongTermElapse = reader.ReadTimeSpan(); + m_ShortTermElapse = reader.ReadTimeSpan(); + m_GameTime = reader.ReadTimeSpan(); + goto case 0; + } + case 0: + { + if( version < 26 ) + m_AutoStabled = new List(); + break; + } + } + + if (m_RecentlyReported == null) + m_RecentlyReported = new List(); + + // Professions weren't verified on 1.0 RC0 + if ( !CharacterCreation.VerifyProfession( m_Profession ) ) + m_Profession = 0; + + if ( m_PermaFlags == null ) + m_PermaFlags = new List(); + + if ( m_JusticeProtectors == null ) + m_JusticeProtectors = new List(); + + if ( m_BOBFilter == null ) + m_BOBFilter = new Engines.BulkOrders.BOBFilter(); + + if( m_GuildRank == null ) + m_GuildRank = Guilds.RankDefinition.Member; //Default to member if going from older verstion to new version (only time it should be null) + + if( m_LastOnline == DateTime.MinValue && Account != null ) + m_LastOnline = ((Account)Account).LastLogin; + + if( m_ChampionTitles == null ) + m_ChampionTitles = new ChampionTitleInfo(); + + if ( AccessLevel > AccessLevel.Player ) + m_IgnoreMobiles = true; + + List list = this.Stabled; + + for ( int i = 0; i < list.Count; ++i ) + { + BaseCreature bc = list[i] as BaseCreature; + + if (bc != null) + { + bc.IsStabled = true; + bc.StabledBy = this; + } + } + + CheckAtrophies( this ); + + if( Hidden ) //Hiding is the only buff where it has an effect that's serialized. + AddBuff( new BuffInfo( BuffIcon.HidingAndOrStealth, 1075655 ) ); + } + + public override void Serialize( GenericWriter writer ) + { + //cleanup our anti-macro table + foreach ( Hashtable t in m_AntiMacroTable.Values ) + { + ArrayList remove = new ArrayList(); + foreach ( CountAndTimeStamp time in t.Values ) + { + if ( time.TimeStamp + SkillCheck.AntiMacroExpire <= DateTime.Now ) + remove.Add( time ); + } + + for (int i=0;i kvp in m_AcquiredRecipes ) + { + writer.Write( kvp.Key ); + writer.Write( kvp.Value ); + } + } + + writer.WriteDeltaTime( m_LastHonorLoss ); + + ChampionTitleInfo.Serialize( writer, m_ChampionTitles ); + + writer.Write( m_LastValorLoss ); + writer.WriteEncodedInt( m_ToTItemsTurnedIn ); + writer.Write( m_ToTTotalMonsterFame ); //This ain't going to be a small #. + + writer.WriteEncodedInt( m_AllianceMessageHue ); + writer.WriteEncodedInt( m_GuildMessageHue ); + + writer.WriteEncodedInt( m_GuildRank.Rank ); + writer.Write( m_LastOnline ); + + writer.WriteEncodedInt( (int) m_SolenFriendship ); + + QuestSerializer.Serialize( m_Quest, writer ); + + if ( m_DoneQuests == null ) + { + writer.WriteEncodedInt( (int) 0 ); + } + else + { + writer.WriteEncodedInt( (int) m_DoneQuests.Count ); + + for ( int i = 0; i < m_DoneQuests.Count; ++i ) + { + QuestRestartInfo restartInfo = m_DoneQuests[i]; + + QuestSerializer.Write( (Type) restartInfo.QuestType, QuestSystem.QuestTypes, writer ); + writer.Write( (DateTime) restartInfo.RestartTime ); + } + } + + writer.WriteEncodedInt( (int) m_Profession ); + + writer.WriteDeltaTime( m_LastCompassionLoss ); + + writer.WriteEncodedInt( m_CompassionGains ); + + if ( m_CompassionGains > 0 ) + writer.WriteDeltaTime( m_NextCompassionDay ); + + m_BOBFilter.Serialize( writer ); + + bool useMods = ( m_HairModID != -1 || m_BeardModID != -1 ); + + writer.Write( useMods ); + + if ( useMods ) + { + writer.Write( (int) m_HairModID ); + writer.Write( (int) m_HairModHue ); + writer.Write( (int) m_BeardModID ); + writer.Write( (int) m_BeardModHue ); + } + + writer.Write( SavagePaintExpiration ); + + writer.Write( (int) m_NpcGuild ); + writer.Write( (DateTime) m_NpcGuildJoinTime ); + writer.Write( (TimeSpan) m_NpcGuildGameTime ); + + writer.Write( m_PermaFlags, true ); + + writer.Write( NextTailorBulkOrder ); + + writer.Write( NextSmithBulkOrder ); + + writer.WriteDeltaTime( m_LastJusticeLoss ); + writer.Write( m_JusticeProtectors, true ); + + writer.WriteDeltaTime( m_LastSacrificeGain ); + writer.WriteDeltaTime( m_LastSacrificeLoss ); + writer.Write( m_AvailableResurrects ); + + writer.Write( (int) m_Flags ); + + writer.Write( m_LongTermElapse ); + writer.Write( m_ShortTermElapse ); + writer.Write( this.GameTime ); + } + + public static void CheckAtrophies( Mobile m ) + { + SacrificeVirtue.CheckAtrophy( m ); + JusticeVirtue.CheckAtrophy( m ); + CompassionVirtue.CheckAtrophy( m ); + ValorVirtue.CheckAtrophy( m ); + + + if( m is PlayerMobile ) + ChampionTitleInfo.CheckAtrophy( (PlayerMobile)m ); + } + + //modif des temps de kills + + public void CheckKillDecay() + { + if ( m_ShortTermElapse < this.GameTime ) + { + m_ShortTermElapse += TimeSpan.FromHours( 4 ); + if ( ShortTermMurders > 0 ) + --ShortTermMurders; + } + + if ( m_LongTermElapse < this.GameTime ) + { + m_LongTermElapse += TimeSpan.FromHours( 20 ); + if ( Kills > 0 ) + --Kills; + } + } + + public void ResetKillTime() + { + m_ShortTermElapse = this.GameTime + TimeSpan.FromHours( 4 ); + m_LongTermElapse = this.GameTime + TimeSpan.FromHours( 20 ); + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime SessionStart + { + get{ return m_SessionStart; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan GameTime + { + get + { + if ( NetState != null ) + return m_GameTime + (DateTime.Now - m_SessionStart); + else + return m_GameTime; + } + } + + public virtual void CheckedAnimate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) + { + if (!Mounted) + { + base.Animate(action, frameCount, repeatCount, forward, repeat, delay); + } + } + + public override void Animate(int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay) + { + base.Animate(action, frameCount, repeatCount, forward, repeat, delay); + } + + public override bool CanSee( Mobile m ) + { + if ( m is CharacterStatue ) + ((CharacterStatue) m).OnRequestedAnimation( this ); + + if ( m is PlayerMobile && ((PlayerMobile)m).m_VisList.Contains( this ) ) + return true; + + if (m_DuelContext != null && m_DuelPlayer != null && !m_DuelContext.Finished && m_DuelContext.m_Tournament != null && !m_DuelPlayer.Eliminated) + { + Mobile owner = m; + + if (owner is BaseCreature) + { + BaseCreature bc = (BaseCreature)owner; + + Mobile master = bc.GetMaster(); + + if (master != null) + owner = master; + } + + if (m.AccessLevel == AccessLevel.Player && owner is PlayerMobile && ((PlayerMobile)owner).DuelContext != m_DuelContext) + return false; + } + + return base.CanSee( m ); + } + + public override bool CanSee( Item item ) + { + if ( m_DesignContext != null && m_DesignContext.Foundation.IsHiddenToCustomizer( item ) ) + return false; + + return base.CanSee( item ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + Faction faction = Faction.Find( this ); + + if ( faction != null ) + faction.RemoveMember( this ); + + MLQuestSystem.HandleDeletion(this); + + BaseHouse.HandleDeletion( this ); + + DisguiseTimers.RemoveTimer( this ); + } + + public override bool NewGuildDisplay { get { return Server.Guilds.Guild.NewGuildSystem; } } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( Map == Faction.Facet ) + { + PlayerState pl = PlayerState.Find( this ); + + if ( pl != null ) + { + Faction faction = pl.Faction; + + if ( faction.Commander == this ) + list.Add( 1042733, faction.Definition.PropName ); // Commanding Lord of the ~1_FACTION_NAME~ + else if ( pl.Sheriff != null ) + list.Add( 1042734, "{0}\t{1}", pl.Sheriff.Definition.FriendlyName, faction.Definition.PropName ); // The Sheriff of ~1_CITY~, ~2_FACTION_NAME~ + else if ( pl.Finance != null ) + list.Add( 1042735, "{0}\t{1}", pl.Finance.Definition.FriendlyName, faction.Definition.PropName ); // The Finance Minister of ~1_CITY~, ~2_FACTION_NAME~ + else if ( pl.MerchantTitle != MerchantTitle.None ) + list.Add( 1060776, "{0}\t{1}", MerchantTitles.GetInfo( pl.MerchantTitle ).Title, faction.Definition.PropName ); // ~1_val~, ~2_val~ + else + list.Add( 1060776, "{0}\t{1}", pl.Rank.Title, faction.Definition.PropName ); // ~1_val~, ~2_val~ + } + } + + if ( Core.ML ) + { + for ( int i = AllFollowers.Count - 1; i >= 0; i-- ) + { + BaseCreature c = AllFollowers[ i ] as BaseCreature; + + if ( c != null && c.ControlOrder == OrderType.Guard ) + { + list.Add( 501129 ); // guarded + break; + } + } + } + } + + public override void OnSingleClick( Mobile from ) + { + if ( Map == Faction.Facet ) + { + PlayerState pl = PlayerState.Find( this ); + + if ( pl != null ) + { + string text; + bool ascii = false; + + Faction faction = pl.Faction; + + if ( faction.Commander == this ) + text = String.Concat( this.Female ? "(Commanding Lady of the " : "(Commanding Lord of the ", faction.Definition.FriendlyName, ")" ); + else if ( pl.Sheriff != null ) + text = String.Concat( "(The Sheriff of ", pl.Sheriff.Definition.FriendlyName, ", ", faction.Definition.FriendlyName, ")" ); + else if ( pl.Finance != null ) + text = String.Concat( "(The Finance Minister of ", pl.Finance.Definition.FriendlyName, ", ", faction.Definition.FriendlyName, ")" ); + else + { + ascii = true; + + if ( pl.MerchantTitle != MerchantTitle.None ) + text = String.Concat( "(", MerchantTitles.GetInfo( pl.MerchantTitle ).Title.String, ", ", faction.Definition.FriendlyName, ")" ); + else + text = String.Concat( "(", pl.Rank.Title.String, ", ", faction.Definition.FriendlyName, ")" ); + } + + int hue = ( Faction.Find( from ) == faction ? 98 : 38 ); + + PrivateOverheadMessage( MessageType.Label, hue, ascii, text, from.NetState ); + } + } + + base.OnSingleClick( from ); + } + + protected override bool OnMove( Direction d ) + { + if( !Core.SE ) + return base.OnMove( d ); + + if( AccessLevel != AccessLevel.Player ) + return true; + + if( Hidden && DesignContext.Find( this ) == null ) //Hidden & NOT customizing a house + { + if( !Mounted && Skills.Stealth.Value >= 25.0 ) + { + bool running = (d & Direction.Running) != 0; + + if( running ) + { + if( (AllowedStealthSteps -= 2) <= 0 ) + RevealingAction(); + } + else if( AllowedStealthSteps-- <= 0 ) + { + Server.SkillHandlers.Stealth.OnUse( this ); + } + } + else + { + RevealingAction(); + } + } + + return true; + } + + private bool m_BedrollLogout; + + public bool BedrollLogout + { + get{ return m_BedrollLogout; } + set{ m_BedrollLogout = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override bool Paralyzed + { + get + { + return base.Paralyzed; + } + set + { + base.Paralyzed = value; + + if( value ) + AddBuff( new BuffInfo( BuffIcon.Paralyze, 1075827 ) ); //Paralyze/You are frozen and can not move + else + RemoveBuff( BuffIcon.Paralyze ); + } + } + + #region Ethics + private Ethics.Player m_EthicPlayer; + + [CommandProperty( AccessLevel.GameMaster )] + public Ethics.Player EthicPlayer + { + get { return m_EthicPlayer; } + set { m_EthicPlayer = value; } + } + #endregion + + #region Factions + private PlayerState m_FactionPlayerState; + + public PlayerState FactionPlayerState + { + get{ return m_FactionPlayerState; } + set{ m_FactionPlayerState = value; } + } + #endregion + + #region Dueling + private Engines.ConPVP.DuelContext m_DuelContext; + private Engines.ConPVP.DuelPlayer m_DuelPlayer; + + public Engines.ConPVP.DuelContext DuelContext + { + get { return m_DuelContext; } + } + + public Engines.ConPVP.DuelPlayer DuelPlayer + { + get { return m_DuelPlayer; } + set + { + bool wasInTourny = (m_DuelContext != null && !m_DuelContext.Finished && m_DuelContext.m_Tournament != null); + + m_DuelPlayer = value; + + if (m_DuelPlayer == null) + m_DuelContext = null; + else + m_DuelContext = m_DuelPlayer.Participant.Context; + + bool isInTourny = (m_DuelContext != null && !m_DuelContext.Finished && m_DuelContext.m_Tournament != null); + + if (wasInTourny != isInTourny) + SendEverything(); + } + } + #endregion + + #region Quests + private QuestSystem m_Quest; + private List m_DoneQuests; + private SolenFriendship m_SolenFriendship; + + public QuestSystem Quest + { + get{ return m_Quest; } + set{ m_Quest = value; } + } + + public List DoneQuests + { + get{ return m_DoneQuests; } + set{ m_DoneQuests = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SolenFriendship SolenFriendship + { + get{ return m_SolenFriendship; } + set{ m_SolenFriendship = value; } + } + #endregion + + #region MyRunUO Invalidation + private bool m_ChangedMyRunUO; + + public bool ChangedMyRunUO + { + get{ return m_ChangedMyRunUO; } + set{ m_ChangedMyRunUO = value; } + } + + public void InvalidateMyRunUO() + { + if ( !Deleted && !m_ChangedMyRunUO ) + { + m_ChangedMyRunUO = true; + Engines.MyRunUO.MyRunUO.QueueMobileUpdate( this ); + } + } + + public override void OnKillsChange( int oldValue ) + { + if ( this.Young && this.Kills > oldValue ) + { + Account acc = this.Account as Account; + + if ( acc != null ) + acc.RemoveYoungStatus( 0 ); + } + + InvalidateMyRunUO(); + } + + public override void OnGenderChanged( bool oldFemale ) + { + InvalidateMyRunUO(); + } + + public override void OnGuildChange( Server.Guilds.BaseGuild oldGuild ) + { + InvalidateMyRunUO(); + } + + public override void OnGuildTitleChange( string oldTitle ) + { + InvalidateMyRunUO(); + } + + public override void OnKarmaChange( int oldValue ) + { + InvalidateMyRunUO(); + } + + public override void OnFameChange( int oldValue ) + { + InvalidateMyRunUO(); + } + + public override void OnSkillChange( SkillName skill, double oldBase ) + { + if ( this.Young && this.SkillsTotal >= 4500 ) + { + Account acc = this.Account as Account; + + if ( acc != null ) + acc.RemoveYoungStatus( 1019036 ); // You have successfully obtained a respectable skill level, and have outgrown your status as a young player! + } + + InvalidateMyRunUO(); + } + + public override void OnAccessLevelChanged( AccessLevel oldLevel ) + { + if ( AccessLevel == AccessLevel.Player ) + IgnoreMobiles = false; + else + IgnoreMobiles = true; + + InvalidateMyRunUO(); + } + + public override void OnRawStatChange( StatType stat, int oldValue ) + { + InvalidateMyRunUO(); + } + + public override void OnDelete() + { + if ( m_ReceivedHonorContext != null ) + m_ReceivedHonorContext.Cancel(); + if ( m_SentHonorContext != null ) + m_SentHonorContext.Cancel(); + + InvalidateMyRunUO(); + } + + #endregion + + #region Fastwalk Prevention + private static bool FastwalkPrevention = true; // Is fastwalk prevention enabled? + private static TimeSpan FastwalkThreshold = TimeSpan.FromSeconds( 0.4 ); // Fastwalk prevention will become active after 0.4 seconds + + private DateTime m_NextMovementTime; + + public virtual bool UsesFastwalkPrevention{ get{ return ( AccessLevel < AccessLevel.Counselor ); } } + + public override TimeSpan ComputeMovementSpeed( Direction dir, bool checkTurning ) + { + if ( checkTurning && (dir & Direction.Mask) != (this.Direction & Direction.Mask) ) + return Mobile.RunMount; // We are NOT actually moving (just a direction change) + + TransformContext context = TransformationSpellHelper.GetContext( this ); + + if ( context != null && context.Type == typeof( ReaperFormSpell ) ) + return Mobile.WalkFoot; + + bool running = ( (dir & Direction.Running) != 0 ); + + bool onHorse = ( this.Mount != null ); + + AnimalFormContext animalContext = AnimalForm.GetContext( this ); + + if( onHorse || (animalContext != null && animalContext.SpeedBoost) ) + return ( running ? Mobile.RunMount : Mobile.WalkMount ); + + return ( running ? Mobile.RunFoot : Mobile.WalkFoot ); + } + + public static bool MovementThrottle_Callback( NetState ns ) + { + PlayerMobile pm = ns.Mobile as PlayerMobile; + + if ( pm == null || !pm.UsesFastwalkPrevention ) + return true; + + if ( pm.m_NextMovementTime == DateTime.MinValue ) + { + // has not yet moved + pm.m_NextMovementTime = DateTime.Now; + return true; + } + + TimeSpan ts = pm.m_NextMovementTime - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + { + // been a while since we've last moved + pm.m_NextMovementTime = DateTime.Now; + return true; + } + + return ( ts < FastwalkThreshold ); + } + + #endregion + + #region Enemy of One + private Type m_EnemyOfOneType; + private bool m_WaitingForEnemy; + + public Type EnemyOfOneType + { + get{ return m_EnemyOfOneType; } + set + { + Type oldType = m_EnemyOfOneType; + Type newType = value; + + if ( oldType == newType ) + return; + + m_EnemyOfOneType = value; + + DeltaEnemies( oldType, newType ); + } + } + + public bool WaitingForEnemy + { + get{ return m_WaitingForEnemy; } + set{ m_WaitingForEnemy = value; } + } + + private void DeltaEnemies( Type oldType, Type newType ) + { + foreach ( Mobile m in this.GetMobilesInRange( 18 ) ) + { + Type t = m.GetType(); + + if ( t == oldType || t == newType ) { + NetState ns = this.NetState; + + if ( ns != null ) { + if ( ns.StygianAbyss ) { + ns.Send( new MobileMoving( m, Notoriety.Compute( this, m ), this ) ); + // Scriptiz 3e param�tre pour le syst�me d'hallucinations + } else { + ns.Send( new MobileMovingOld( m, Notoriety.Compute( this, m ), this ) ); + // Scriptiz 3e param�tre pour le syst�me d'hallucinations + } + } + } + } + } + + #endregion + + #region Hair and beard mods + private int m_HairModID = -1, m_HairModHue; + private int m_BeardModID = -1, m_BeardModHue; + + public void SetHairMods( int hairID, int beardID ) + { + if ( hairID == -1 ) + InternalRestoreHair( true, ref m_HairModID, ref m_HairModHue ); + else if ( hairID != -2 ) + InternalChangeHair( true, hairID, ref m_HairModID, ref m_HairModHue ); + + if ( beardID == -1 ) + InternalRestoreHair( false, ref m_BeardModID, ref m_BeardModHue ); + else if ( beardID != -2 ) + InternalChangeHair( false, beardID, ref m_BeardModID, ref m_BeardModHue ); + } + + private void CreateHair( bool hair, int id, int hue ) + { + if( hair ) + { + //TODO Verification? + HairItemID = id; + HairHue = hue; + } + else + { + FacialHairItemID = id; + FacialHairHue = hue; + } + } + + private void InternalRestoreHair( bool hair, ref int id, ref int hue ) + { + if ( id == -1 ) + return; + + if ( hair ) + HairItemID = 0; + else + FacialHairItemID = 0; + + //if( id != 0 ) + CreateHair( hair, id, hue ); + + id = -1; + hue = 0; + } + + private void InternalChangeHair( bool hair, int id, ref int storeID, ref int storeHue ) + { + if ( storeID == -1 ) + { + storeID = hair ? HairItemID : FacialHairItemID; + storeHue = hair ? HairHue : FacialHairHue; + } + CreateHair( hair, id, 0 ); + } + + #endregion + + #region Virtues + private DateTime m_LastSacrificeGain; + private DateTime m_LastSacrificeLoss; + private int m_AvailableResurrects; + + public DateTime LastSacrificeGain{ get{ return m_LastSacrificeGain; } set{ m_LastSacrificeGain = value; } } + public DateTime LastSacrificeLoss{ get{ return m_LastSacrificeLoss; } set{ m_LastSacrificeLoss = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int AvailableResurrects{ get{ return m_AvailableResurrects; } set{ m_AvailableResurrects = value; } } + + private DateTime m_NextJustAward; + private DateTime m_LastJusticeLoss; + private List m_JusticeProtectors; + + public DateTime LastJusticeLoss { get { return m_LastJusticeLoss; } set { m_LastJusticeLoss = value; } } + public List JusticeProtectors { get { return m_JusticeProtectors; } set { m_JusticeProtectors = value; } } + + private DateTime m_LastCompassionLoss; + private DateTime m_NextCompassionDay; + private int m_CompassionGains; + + public DateTime LastCompassionLoss { get { return m_LastCompassionLoss; } set { m_LastCompassionLoss = value; } } + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextCompassionDay { get { return m_NextCompassionDay; } set { m_NextCompassionDay = value; } } + [CommandProperty(AccessLevel.GameMaster)] + public int CompassionGains { get { return m_CompassionGains; } set { m_CompassionGains = value; } } + + private DateTime m_LastValorLoss; + + public DateTime LastValorLoss { get { return m_LastValorLoss; } set { m_LastValorLoss = value; } } + + private DateTime m_LastHonorLoss; + private DateTime m_LastHonorUse; + private bool m_HonorActive; + private HonorContext m_ReceivedHonorContext; + private HonorContext m_SentHonorContext; + public DateTime m_hontime; + + public DateTime LastHonorLoss{ get{ return m_LastHonorLoss; } set{ m_LastHonorLoss = value; } } + public DateTime LastHonorUse{ get{ return m_LastHonorUse; } set{ m_LastHonorUse = value; } } + public bool HonorActive{ get{ return m_HonorActive; } set{ m_HonorActive = value; } } + public HonorContext ReceivedHonorContext{ get{ return m_ReceivedHonorContext; } set{ m_ReceivedHonorContext = value; } } + public HonorContext SentHonorContext{ get{ return m_SentHonorContext; } set{ m_SentHonorContext = value; } } + #endregion + + #region Young system + [CommandProperty( AccessLevel.GameMaster )] + public bool Young + { + get{ return GetFlag( PlayerFlag.Young ); } + set{ SetFlag( PlayerFlag.Young, value ); InvalidateProperties(); } + } + + public override string ApplyNameSuffix( string suffix ) + { + if ( Young ) + { + if ( suffix.Length == 0 ) + suffix = "(Young)"; + else + suffix = String.Concat( suffix, " (Young)" ); + } + + #region Ethics + if ( m_EthicPlayer != null ) + { + if ( suffix.Length == 0 ) + suffix = m_EthicPlayer.Ethic.Definition.Adjunct.String; + else + suffix = String.Concat( suffix, " ", m_EthicPlayer.Ethic.Definition.Adjunct.String ); + } + #endregion + + if ( Core.ML && this.Map == Faction.Facet ) + { + Faction faction = Faction.Find( this ); + + if ( faction != null ) + { + string adjunct = String.Format( "[{0}]", faction.Definition.Abbreviation ); + if ( suffix.Length == 0 ) + suffix = adjunct; + else + suffix = String.Concat( suffix, " ", adjunct ); + } + } + + return base.ApplyNameSuffix( suffix ); + } + + public override TimeSpan GetLogoutDelay() + { + if ( Young || BedrollLogout || TestCenter.Enabled) + return TimeSpan.Zero; + + // Scriptiz : ajout pour les GMs qui ont des persos joueurs + if (Account != null && Account.AccessLevel > AccessLevel.Player) + return TimeSpan.Zero; + + return base.GetLogoutDelay(); + } + + private DateTime m_LastYoungMessage = DateTime.MinValue; + + public bool CheckYoungProtection( Mobile from ) + { + if ( !this.Young ) + return false; + + if (Region is BaseRegion && !((BaseRegion)Region).YoungProtected) + return false; + + if( from is BaseCreature && ((BaseCreature)from).IgnoreYoungProtection ) + return false; + + if ( this.Quest != null && this.Quest.IgnoreYoungProtection( from ) ) + return false; + + if ( DateTime.Now - m_LastYoungMessage > TimeSpan.FromMinutes( 1.0 ) ) + { + m_LastYoungMessage = DateTime.Now; + SendLocalizedMessage( 1019067 ); // A monster looks at you menacingly but does not attack. You would be under attack now if not for your status as a new citizen of Britannia. + } + + return true; + } + + private DateTime m_LastYoungHeal = DateTime.MinValue; + + public bool CheckYoungHealTime() + { + if ( DateTime.Now - m_LastYoungHeal > TimeSpan.FromMinutes( 5.0 ) ) + { + m_LastYoungHeal = DateTime.Now; + return true; + } + + return false; + } + + private static Point3D[] m_TrammelDeathDestinations = new Point3D[] + { + new Point3D( 1481, 1612, 20 ), + new Point3D( 2708, 2153, 0 ), + new Point3D( 2249, 1230, 0 ), + new Point3D( 5197, 3994, 37 ), + new Point3D( 1412, 3793, 0 ), + new Point3D( 3688, 2232, 20 ), + new Point3D( 2578, 604, 0 ), + new Point3D( 4397, 1089, 0 ), + new Point3D( 5741, 3218, -2 ), + new Point3D( 2996, 3441, 15 ), + new Point3D( 624, 2225, 0 ), + new Point3D( 1916, 2814, 0 ), + new Point3D( 2929, 854, 0 ), + new Point3D( 545, 967, 0 ), + new Point3D( 3665, 2587, 0 ) + }; + + private static Point3D[] m_IlshenarDeathDestinations = new Point3D[] + { + new Point3D( 1216, 468, -13 ), + new Point3D( 723, 1367, -60 ), + new Point3D( 745, 725, -28 ), + new Point3D( 281, 1017, 0 ), + new Point3D( 986, 1011, -32 ), + new Point3D( 1175, 1287, -30 ), + new Point3D( 1533, 1341, -3 ), + new Point3D( 529, 217, -44 ), + new Point3D( 1722, 219, 96 ) + }; + + private static Point3D[] m_MalasDeathDestinations = new Point3D[] + { + new Point3D( 2079, 1376, -70 ), + new Point3D( 944, 519, -71 ) + }; + + private static Point3D[] m_TokunoDeathDestinations = new Point3D[] + { + new Point3D( 1166, 801, 27 ), + new Point3D( 782, 1228, 25 ), + new Point3D( 268, 624, 15 ) + }; + + public bool YoungDeathTeleport() + { + if ( this.Region.IsPartOf( typeof( Jail ) ) + || this.Region.IsPartOf( "Samurai start location" ) + || this.Region.IsPartOf( "Ninja start location" ) + || this.Region.IsPartOf( "Ninja cave" ) ) + return false; + + Point3D loc; + Map map; + + DungeonRegion dungeon = (DungeonRegion) this.Region.GetRegion( typeof( DungeonRegion ) ); + if ( dungeon != null && dungeon.EntranceLocation != Point3D.Zero ) + { + loc = dungeon.EntranceLocation; + map = dungeon.EntranceMap; + } + else + { + loc = this.Location; + map = this.Map; + } + + Point3D[] list; + + if ( map == Map.Trammel ) + list = m_TrammelDeathDestinations; + else if ( map == Map.Ilshenar ) + list = m_IlshenarDeathDestinations; + else if ( map == Map.Malas ) + list = m_MalasDeathDestinations; + else if ( map == Map.Tokuno ) + list = m_TokunoDeathDestinations; + else + return false; + + Point3D dest = Point3D.Zero; + int sqDistance = int.MaxValue; + + for ( int i = 0; i < list.Length; i++ ) + { + Point3D curDest = list[i]; + + int width = loc.X - curDest.X; + int height = loc.Y - curDest.Y; + int curSqDistance = width * width + height * height; + + if ( curSqDistance < sqDistance ) + { + dest = curDest; + sqDistance = curSqDistance; + } + } + + this.MoveToWorld( dest, map ); + return true; + } + + private void SendYoungDeathNotice() + { + this.SendGump( new YoungDeathNotice() ); + } + + #endregion + + #region Speech log + private SpeechLog m_SpeechLog; + + public SpeechLog SpeechLog{ get{ return m_SpeechLog; } } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( SpeechLog.Enabled && this.NetState != null ) + { + if ( m_SpeechLog == null ) + m_SpeechLog = new SpeechLog(); + + m_SpeechLog.Add( e.Mobile, e.Speech ); + } + } + + #endregion + + #region Champion Titles + [CommandProperty( AccessLevel.GameMaster )] + public bool DisplayChampionTitle + { + get { return GetFlag( PlayerFlag.DisplayChampionTitle ); } + set { SetFlag( PlayerFlag.DisplayChampionTitle, value ); } + } + + private ChampionTitleInfo m_ChampionTitles; + + [CommandProperty( AccessLevel.GameMaster )] + public ChampionTitleInfo ChampionTitles { get { return m_ChampionTitles; } set { } } + + private void ToggleChampionTitleDisplay() + { + if( !CheckAlive() ) + return; + + if( DisplayChampionTitle ) + SendLocalizedMessage( 1062419, "", 0x23 ); // You have chosen to hide your monster kill title. + else + SendLocalizedMessage( 1062418, "", 0x23 ); // You have chosen to display your monster kill title. + + DisplayChampionTitle = !DisplayChampionTitle; + } + + [PropertyObject] + public class ChampionTitleInfo + { + public static TimeSpan LossDelay = TimeSpan.FromDays( 1.0 ); + public const int LossAmount = 90; + + private class TitleInfo + { + private int m_Value; + private DateTime m_LastDecay; + + public int Value { get { return m_Value; } set { m_Value = value; } } + public DateTime LastDecay { get { return m_LastDecay; } set { m_LastDecay = value; } } + + public TitleInfo() + { + } + + public TitleInfo( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch( version ) + { + case 0: + { + m_Value = reader.ReadEncodedInt(); + m_LastDecay = reader.ReadDateTime(); + break; + } + } + } + + public static void Serialize( GenericWriter writer, TitleInfo info ) + { + writer.WriteEncodedInt( (int)0 ); // version + + writer.WriteEncodedInt( info.m_Value ); + writer.Write( info.m_LastDecay ); + } + } + + private TitleInfo[] m_Values; + + private int m_Harrower; //Harrower titles do NOT decay + + public int GetValue( ChampionSpawnType type ) + { + return GetValue( (int)type ); + } + + public void SetValue( ChampionSpawnType type, int value ) + { + SetValue( (int)type, value ); + } + + public void Award( ChampionSpawnType type, int value ) + { + Award( (int)type, value ); + } + + public int GetValue( int index ) + { + if( m_Values == null || index < 0 || index >= m_Values.Length ) + return 0; + + if( m_Values[index] == null ) + m_Values[index] = new TitleInfo(); + + return m_Values[index].Value; + } + + public DateTime GetLastDecay( int index ) + { + if( m_Values == null || index < 0 || index >= m_Values.Length ) + return DateTime.MinValue; + + if( m_Values[index] == null ) + m_Values[index] = new TitleInfo(); + + return m_Values[index].LastDecay; + } + + public void SetValue( int index, int value ) + { + if( m_Values == null ) + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + if( value < 0 ) + value = 0; + + if( index < 0 || index >= m_Values.Length ) + return; + + if( m_Values[index] == null ) + m_Values[index] = new TitleInfo(); + + m_Values[index].Value = value; + } + + public void Award( int index, int value ) + { + if( m_Values == null ) + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + if( index < 0 || index >= m_Values.Length || value <= 0 ) + return; + + if( m_Values[index] == null ) + m_Values[index] = new TitleInfo(); + + m_Values[index].Value += value; + } + + public void Atrophy( int index, int value ) + { + if( m_Values == null ) + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + if( index < 0 || index >= m_Values.Length || value <= 0 ) + return; + + if( m_Values[index] == null ) + m_Values[index] = new TitleInfo(); + + int before = m_Values[index].Value; + + if( (m_Values[index].Value - value) < 0 ) + m_Values[index].Value = 0; + else + m_Values[index].Value -= value; + + if( before != m_Values[index].Value ) + m_Values[index].LastDecay = DateTime.Now; + } + + public override string ToString() + { + return "..."; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Pestilence { get { return GetValue(ChampionSpawnType.Pestilence); } set { SetValue(ChampionSpawnType.Pestilence, value); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Abyss { get { return GetValue( ChampionSpawnType.Abyss ); } set { SetValue( ChampionSpawnType.Abyss, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Arachnid { get { return GetValue( ChampionSpawnType.Arachnid ); } set { SetValue( ChampionSpawnType.Arachnid, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ColdBlood { get { return GetValue( ChampionSpawnType.ColdBlood ); } set { SetValue( ChampionSpawnType.ColdBlood, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int ForestLord { get { return GetValue( ChampionSpawnType.ForestLord ); } set { SetValue( ChampionSpawnType.ForestLord, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int SleepingDragon { get { return GetValue( ChampionSpawnType.SleepingDragon ); } set { SetValue( ChampionSpawnType.SleepingDragon, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int UnholyTerror { get { return GetValue( ChampionSpawnType.UnholyTerror ); } set { SetValue( ChampionSpawnType.UnholyTerror, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int VerminHorde { get { return GetValue( ChampionSpawnType.VerminHorde ); } set { SetValue( ChampionSpawnType.VerminHorde, value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Harrower { get { return m_Harrower; } set { m_Harrower = value; } } + + public ChampionTitleInfo() + { + } + + public ChampionTitleInfo( GenericReader reader ) + { + int version = reader.ReadEncodedInt(); + + switch( version ) + { + case 0: + { + m_Harrower = reader.ReadEncodedInt(); + + int length = reader.ReadEncodedInt(); + m_Values = new TitleInfo[length]; + + for( int i = 0; i < length; i++ ) + { + m_Values[i] = new TitleInfo( reader ); + } + + if( m_Values.Length != ChampionSpawnInfo.Table.Length ) + { + TitleInfo[] oldValues = m_Values; + m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + for( int i = 0; i < m_Values.Length && i < oldValues.Length; i++ ) + { + m_Values[i] = oldValues[i]; + } + } + break; + } + } + } + + public static void Serialize( GenericWriter writer, ChampionTitleInfo titles ) + { + writer.WriteEncodedInt( (int)0 ); // version + + writer.WriteEncodedInt( titles.m_Harrower ); + + int length = titles.m_Values.Length; + writer.WriteEncodedInt( length ); + + for( int i = 0; i < length; i++ ) + { + if( titles.m_Values[i] == null ) + titles.m_Values[i] = new TitleInfo(); + + TitleInfo.Serialize( writer, titles.m_Values[i] ); + } + } + + public static void CheckAtrophy( PlayerMobile pm ) + { + ChampionTitleInfo t = pm.m_ChampionTitles; + if( t == null ) + return; + + if( t.m_Values == null ) + t.m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + for( int i = 0; i < t.m_Values.Length; i++ ) + { + if( (t.GetLastDecay( i ) + LossDelay) < DateTime.Now ) + { + t.Atrophy( i, LossAmount ); + } + } + } + + public static void AwardHarrowerTitle( PlayerMobile pm ) //Called when killing a harrower. Will give a minimum of 1 point. + { + ChampionTitleInfo t = pm.m_ChampionTitles; + if( t == null ) + return; + + if( t.m_Values == null ) + t.m_Values = new TitleInfo[ChampionSpawnInfo.Table.Length]; + + int count = 1; + + for( int i = 0; i < t.m_Values.Length; i++ ) + { + if( t.m_Values[i].Value > 900 ) + count++; + } + + t.m_Harrower = Math.Max( count, t.m_Harrower ); //Harrower titles never decay. + } + } + + #endregion + + #region Recipes + + private Dictionary m_AcquiredRecipes; + + public virtual bool HasRecipe( Recipe r ) + { + if( r == null ) + return false; + + return HasRecipe( r.ID ); + } + + public virtual bool HasRecipe( int recipeID ) + { + if( m_AcquiredRecipes != null && m_AcquiredRecipes.ContainsKey( recipeID ) ) + return m_AcquiredRecipes[recipeID]; + + return false; + } + + public virtual void AcquireRecipe( Recipe r ) + { + if( r != null ) + AcquireRecipe( r.ID ); + } + + public virtual void AcquireRecipe( int recipeID ) + { + if( m_AcquiredRecipes == null ) + m_AcquiredRecipes = new Dictionary(); + + m_AcquiredRecipes[recipeID] = true; + } + + public virtual void ResetRecipes() + { + m_AcquiredRecipes = null; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int KnownRecipes + { + get + { + if( m_AcquiredRecipes == null ) + return 0; + + return m_AcquiredRecipes.Count; + } + } + + #endregion + + #region Buff Icons + + public void ResendBuffs() + { + if( !BuffInfo.Enabled || m_BuffTable == null ) + return; + + NetState state = this.NetState; + + if( state != null && state.BuffIcon ) + { + foreach( BuffInfo info in m_BuffTable.Values ) + { + state.Send( new AddBuffPacket( this, info ) ); + } + } + } + + private Dictionary m_BuffTable; + + public void AddBuff( BuffInfo b ) + { + if( !BuffInfo.Enabled || b == null ) + return; + + RemoveBuff( b ); //Check & subsequently remove the old one. + + if( m_BuffTable == null ) + m_BuffTable = new Dictionary(); + + m_BuffTable.Add( b.ID, b ); + + NetState state = this.NetState; + + if( state != null && state.BuffIcon ) + { + state.Send( new AddBuffPacket( this, b ) ); + } + } + + public void RemoveBuff( BuffInfo b ) + { + if( b == null ) + return; + + RemoveBuff( b.ID ); + } + + public void RemoveBuff( BuffIcon b ) + { + if( m_BuffTable == null || !m_BuffTable.ContainsKey( b ) ) + return; + + BuffInfo info = m_BuffTable[b]; + + if( info.Timer != null && info.Timer.Running ) + info.Timer.Stop(); + + m_BuffTable.Remove( b ); + + NetState state = this.NetState; + + if( state != null && state.BuffIcon ) + { + state.Send( new RemoveBuffPacket( this, b ) ); + } + + if( m_BuffTable.Count <= 0 ) + m_BuffTable = null; + } + + #endregion + + #region Addiction + + public void IncAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + int index = (int)potion.PotionEffect; + + double value = 1; + if (potion.IntensifiedStrength) + value += 0.5; + if (potion.IntensifiedTime) + value += 0.5; + + if (index >= Addiction.Length) + return; + + Addiction[index]+=value; + + if (Math.Round(Addiction[index] / 10.0, 0) == Addiction[index] - 1) + SendMessage("Vous devriez consommer moins de ce produit"); + } + + public void ClearAddiction() + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + for (int i = 0; i < Addiction.Length; i++) + Addiction[i] = 0; + } + + public double CalculateHealAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + double CurrentAddiction = Addiction[(int)potion.PotionEffect]; + double HealConsumption = CurrentAddiction + Addiction[14]*0.08 + Addiction[15]*0.1 + Addiction[16]*0.14; + + return HealConsumption; + } + + public double[] CalculateAgilityAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + double CurrentAddiction = (Addiction[(int)potion.PotionEffect]); + double GlobalAddiction = CurrentAddiction + Addiction[4] * 0.1 + Addiction[5] * 0.14; + + return new double[] { CurrentAddiction, GlobalAddiction }; + } + + public double[] CalculateStrengthAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + double CurrentAddiction = (Addiction[(int)potion.PotionEffect]); + double GlobalAddiction = CurrentAddiction + Addiction[6] * 0.1 + Addiction[7] * 0.14; + + return new double[] { CurrentAddiction, GlobalAddiction }; + } + + public double CalculateCureAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + double CurrentAddiction = Addiction[(int)potion.PotionEffect]; + double CureConsumption = CurrentAddiction + Addiction[1] * 0.08 + Addiction[2] * 0.1 + Addiction[3] * 0.14; + + return CureConsumption; + } + + public double CalculateNightSightAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + double CurrentAddiction = Addiction[(int)potion.PotionEffect]/4; + + return CurrentAddiction; + } + + public double[] CalculateClumsyAddiction(BasePotion potion) + { + if (Addiction == null) + Addiction = new double[Enum.GetValues(typeof(PotionEffect)).Length]; + + double CurrentAddiction = (Addiction[(int)potion.PotionEffect])/2; + double GlobalAddiction = CurrentAddiction + Addiction[32] * 0.05 + Addiction[33] * 0.07; + + return new double[] { CurrentAddiction, GlobalAddiction }; + } + + #endregion + + public void AutoStablePets() + { + if ( Core.SE && AllFollowers.Count > 0 ) + { + for ( int i = m_AllFollowers.Count - 1; i >= 0; --i ) + { + BaseCreature pet = AllFollowers[i] as BaseCreature; + + if (pet == null || pet.ControlMaster == null) + continue; + + if (pet.Summoned) + { + if (pet.Map != Map) + { + pet.PlaySound( pet.GetAngerSound() ); + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( pet.Delete ) ); + } + continue; + } + + if ( pet is IMount && ((IMount)pet).Rider != null ) + continue; + + if ((pet is PackLlama || pet is PackHorse || pet is Beetle) && (pet.Backpack != null && pet.Backpack.Items.Count > 0)) + continue; + + if ( pet is BaseEscortable ) + continue; + + pet.ControlTarget = null; + pet.ControlOrder = OrderType.Stay; + pet.Internalize(); + + pet.SetControlMaster( null ); + pet.SummonMaster = null; + + pet.IsStabled = true; + pet.StabledBy = this; + + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully happy + + Stabled.Add( pet ); + m_AutoStabled.Add( pet ); + } + } + } + + public void ClaimAutoStabledPets() + { + if ( !Core.SE || m_AutoStabled.Count <= 0 ) + return; + + if ( !Alive ) + { + SendLocalizedMessage( 1076251 ); // Your pet was unable to join you while you are a ghost. Please re-login once you have ressurected to claim your pets. + return; + } + + for ( int i = m_AutoStabled.Count - 1; i >= 0; --i ) + { + BaseCreature pet = m_AutoStabled[i] as BaseCreature; + + if ( pet == null || pet.Deleted ) + { + pet.IsStabled = false; + pet.StabledBy = null; + + if ( Stabled.Contains( pet ) ) + Stabled.Remove( pet ); + + continue; + } + + if ( (Followers + pet.ControlSlots) <= FollowersMax ) + { + pet.SetControlMaster( this ); + + if ( pet.Summoned ) + pet.SummonMaster = this; + + pet.ControlTarget = this; + pet.ControlOrder = OrderType.Follow; + + pet.MoveToWorld( Location, Map ); + + pet.IsStabled = false; + pet.StabledBy = null; + + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy + + if ( Stabled.Contains( pet ) ) + Stabled.Remove( pet ); + } + else + { + SendLocalizedMessage( 1049612, pet.Name ); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + m_AutoStabled.Clear(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Barracoon.cs b/Scripts/Mobiles/Special/Barracoon.cs new file mode 100644 index 0000000..ad3a79d --- /dev/null +++ b/Scripts/Mobiles/Special/Barracoon.cs @@ -0,0 +1,240 @@ +using System; +using Server; +using Server.Items; +using Server.Spells; +using Server.Spells.Seventh; +using Server.Spells.Fifth; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Barracoon : BaseChampion + { + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Greed; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( FangOfRactus ) }; } } + public override Type[] SharedList{ get{ return new Type[] { typeof( EmbroideredOakLeafCloak ), + typeof( DjinnisRing ), + typeof( DetectiveBoots ), + typeof( GuantletsOfAnger ) }; } } + public override Type[] DecorativeList{ get{ return new Type[] { typeof( SwampTile ), typeof( MonsterStatuette ) }; } } + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { MonsterStatuetteType.Slime }; } } + + [Constructable] + public Barracoon() : base( AIType.AI_Melee ) + { + Name = "Barracoon"; + Title = "the piper"; + Body = 0x190; + Hue = 0x83EC; + + SetStr( 305, 425 ); + SetDex( 72, 150 ); + SetInt( 505, 750 ); + + SetHits( 4200 ); + SetStam( 102, 300 ); + + SetDamage( 25, 35 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60, 70 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.MagicResist, 100.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 70; + + AddItem( new FancyShirt( Utility.RandomGreenHue() ) ); + AddItem( new LongPants( Utility.RandomYellowHue() ) ); + AddItem( new JesterHat( Utility.RandomPinkHue() ) ); + AddItem( new Cloak( Utility.RandomPinkHue() ) ); + AddItem( new Sandals() ); + + HairItemID = 0x203B; // Short Hair + HairHue = 0x94; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool AutoDispel{ get{ return true; } } + public override double AutoDispelChance{ get{ return 1.0; } } + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool Uncalmable{ get{ return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + + public override bool ShowFameTitle{ get{ return false; } } + public override bool ClickTitle{ get{ return false; } } + + public void Polymorph( Mobile m ) + { + if ( !m.CanBeginAction( typeof( PolymorphSpell ) ) || !m.CanBeginAction( typeof( IncognitoSpell ) ) || m.IsBodyMod ) + return; + + IMount mount = m.Mount; + + if ( mount != null ) + mount.Rider = null; + + if ( m.Mounted ) + return; + + if ( m.BeginAction( typeof( PolymorphSpell ) ) ) + { + Item disarm = m.FindItemOnLayer( Layer.OneHanded ); + + if ( disarm != null && disarm.Movable ) + m.AddToBackpack( disarm ); + + disarm = m.FindItemOnLayer( Layer.TwoHanded ); + + if ( disarm != null && disarm.Movable ) + m.AddToBackpack( disarm ); + + m.BodyMod = 42; + m.HueMod = 0; + + new ExpirePolymorphTimer( m ).Start(); + } + } + + private class ExpirePolymorphTimer : Timer + { + private Mobile m_Owner; + + public ExpirePolymorphTimer( Mobile owner ) : base( TimeSpan.FromMinutes( 3.0 ) ) + { + m_Owner = owner; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if ( !m_Owner.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + m_Owner.BodyMod = 0; + m_Owner.HueMod = -1; + m_Owner.EndAction( typeof( PolymorphSpell ) ); + } + } + } + + public void SpawnRatmen( Mobile target ) + { + Map map = this.Map; + + if ( map == null ) + return; + + int rats = 0; + + foreach ( Mobile m in this.GetMobilesInRange( 10 ) ) + { + if ( m is Ratman || m is RatmanArcher || m is RatmanMage ) + ++rats; + } + + if ( rats < 16 ) + { + PlaySound( 0x3D ); + + int newRats = Utility.RandomMinMax( 3, 6 ); + + for ( int i = 0; i < newRats; ++i ) + { + BaseCreature rat; + + switch ( Utility.Random( 5 ) ) + { + default: + case 0: case 1: rat = new Ratman(); break; + case 2: case 3: rat = new RatmanArcher(); break; + case 4: rat = new RatmanMage(); break; + } + + rat.Team = this.Team; + + bool validLocation = false; + Point3D loc = this.Location; + + for ( int j = 0; !validLocation && j < 10; ++j ) + { + int x = X + Utility.Random( 3 ) - 1; + int y = Y + Utility.Random( 3 ) - 1; + int z = map.GetAverageZ( x, y ); + + if ( validLocation = map.CanFit( x, y, this.Z, 16, false, false ) ) + loc = new Point3D( x, y, Z ); + else if ( validLocation = map.CanFit( x, y, z, 16, false, false ) ) + loc = new Point3D( x, y, z ); + } + + rat.MoveToWorld( loc, map ); + rat.Combatant = target; + } + } + } + + public void DoSpecialAbility( Mobile target ) + { + if ( target == null || target.Deleted ) //sanity + return; + if ( 0.6 >= Utility.RandomDouble() ) // 60% chance to polymorph attacker into a ratman + Polymorph( target ); + + if ( 0.2 >= Utility.RandomDouble() ) // 20% chance to more ratmen + SpawnRatmen( target ); + + if ( Hits < 500 && !IsBodyMod ) // Baracoon is low on life, polymorph into a ratman + Polymorph( this ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + DoSpecialAbility( attacker ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + DoSpecialAbility( defender ); + } + + public Barracoon( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/BaseChampion.cs b/Scripts/Mobiles/Special/BaseChampion.cs new file mode 100644 index 0000000..fe3916b --- /dev/null +++ b/Scripts/Mobiles/Special/BaseChampion.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public abstract class BaseChampion : BaseCreature + { + public override bool CanMoveOverObstacles { get { return true; } } + public override bool CanDestroyObstacles { get { return true; } } + + public BaseChampion( AIType aiType ) : this( aiType, FightMode.Closest ) + { + } + + public BaseChampion( AIType aiType, FightMode mode ) : base( aiType, mode, 18, 1, 0.1, 0.2 ) + { + } + + public BaseChampion( Serial serial ) : base( serial ) + { + } + + public abstract ChampionSkullType SkullType{ get; } + + public abstract Type[] UniqueList{ get; } + public abstract Type[] SharedList{ get; } + public abstract Type[] DecorativeList{ get; } + public abstract MonsterStatuetteType[] StatueTypes{ get; } + + public virtual bool NoGoodies{ get{ return false; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public Item GetArtifact() + { + double random = Utility.RandomDouble(); + if ( 0.05 >= random ) + return CreateArtifact( UniqueList ); + else if ( 0.15 >= random ) + return CreateArtifact( SharedList ); + else if ( 0.30 >= random ) + return CreateArtifact( DecorativeList ); + return null; + } + + public Item CreateArtifact( Type[] list ) + { + if( list.Length == 0 ) + return null; + + int random = Utility.Random( list.Length ); + + Type type = list[random]; + + Item artifact = Loot.Construct( type ); + + if( artifact is MonsterStatuette && StatueTypes.Length > 0 ) + { + ((MonsterStatuette)artifact).Type = StatueTypes[Utility.Random( StatueTypes.Length )]; + ((MonsterStatuette)artifact).LootType = LootType.Regular; + } + + return artifact; + } + + private PowerScroll CreateRandomPowerScroll() + { + int level; + double random = Utility.RandomDouble(); + + if ( 0.05 >= random ) + level = 20; + else if ( 0.4 >= random ) + level = 15; + else + level = 10; + + return PowerScroll.CreateRandomNoCraft( level, level ); + } + + public void GivePowerScrolls() + { + if ( Map != Map.Felucca ) + return; + + List toGive = new List(); + List rights = BaseCreature.GetLootingRights( this.DamageEntries, this.HitsMax ); + + for ( int i = rights.Count - 1; i >= 0; --i ) + { + DamageStore ds = rights[i]; + + if ( ds.m_HasRight ) + toGive.Add( ds.m_Mobile ); + } + + if ( toGive.Count == 0 ) + return; + + for( int i = 0; i < toGive.Count; i++ ) + { + Mobile m = toGive[i]; + + if( !(m is PlayerMobile) ) + continue; + + bool gainedPath = false; + + int pointsToGain = 800; + + if( VirtueHelper.Award( m, VirtueName.Valor, pointsToGain, ref gainedPath ) ) + { + if( gainedPath ) + m.SendLocalizedMessage( 1054032 ); // You have gained a path in Valor! + else + m.SendLocalizedMessage( 1054030 ); // You have gained in Valor! + + //No delay on Valor gains + } + } + + // Randomize + for ( int i = 0; i < toGive.Count; ++i ) + { + int rand = Utility.Random( toGive.Count ); + Mobile hold = toGive[i]; + toGive[i] = toGive[rand]; + toGive[rand] = hold; + } + + /*for ( int i = 0; i < 6; ++i ) + { + Mobile m = toGive[i % toGive.Count]; + + PowerScroll ps = CreateRandomPowerScroll(); + + GivePowerScrollTo( m, ps ); + }*/ + } + + public static void GivePowerScrollTo( Mobile m, PowerScroll ps ) + { + if( ps == null || m == null ) //sanity + return; + + m.SendLocalizedMessage( 1049524 ); // You have received a scroll of power! + + if( !Core.SE || m.Alive ) + m.AddToBackpack( ps ); + else + { + if( m.Corpse != null && !m.Corpse.Deleted ) + m.Corpse.DropItem( ps ); + else + m.AddToBackpack( ps ); + } + + if( m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + for( int j = 0; j < pm.JusticeProtectors.Count; ++j ) + { + Mobile prot = pm.JusticeProtectors[j]; + + if( prot.Map != m.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion( m, prot ) ) + continue; + + int chance = 0; + + switch( VirtueHelper.GetLevel( prot, VirtueName.Justice ) ) + { + case VirtueLevel.Seeker: chance = 60; break; + case VirtueLevel.Follower: chance = 80; break; + case VirtueLevel.Knight: chance = 100; break; + } + + if( chance > Utility.Random( 100 ) ) + { + PowerScroll powerScroll = new PowerScroll( ps.Skill, ps.Value ); + + prot.SendLocalizedMessage( 1049368 ); // You have been rewarded for your dedication to Justice! + + /*if( !Core.SE || prot.Alive ) + prot.AddToBackpack( powerScroll ); + else + { + if( prot.Corpse != null && !prot.Corpse.Deleted ) + prot.Corpse.DropItem( powerScroll ); + else + prot.AddToBackpack( powerScroll ); + }*/ + } + } + } + } + + public override bool OnBeforeDeath() + { + if ( !NoKillAwards ) + { + //GivePowerScrolls(); + + if( NoGoodies ) + return base.OnBeforeDeath(); + + Map map = this.Map; + + if ( map != null ) + { + for ( int x = -12; x <= 12; ++x ) + { + for ( int y = -12; y <= 12; ++y ) + { + double dist = Math.Sqrt(x*x+y*y); + + if ( dist <= 12 ) + new GoodiesTimer( map, X + x, Y + y ).Start(); + } + } + } + } + + return base.OnBeforeDeath(); + } + + public override void OnDeath( Container c ) + { + if ( Map == Map.Felucca ) + { + //TODO: Confirm SE change or AoS one too? + List rights = BaseCreature.GetLootingRights( this.DamageEntries, this.HitsMax ); + List toGive = new List(); + + for ( int i = rights.Count - 1; i >= 0; --i ) + { + DamageStore ds = rights[i]; + + if ( ds.m_HasRight ) + toGive.Add( ds.m_Mobile ); + } + + if ( toGive.Count > 0 ) + toGive[Utility.Random( toGive.Count )].AddToBackpack( new ChampionSkull( SkullType ) ); + else + c.DropItem( new ChampionSkull( SkullType ) ); + } + + base.OnDeath( c ); + } + + private class GoodiesTimer : Timer + { + private Map m_Map; + private int m_X, m_Y; + + public GoodiesTimer( Map map, int x, int y ) : base( TimeSpan.FromSeconds( Utility.RandomDouble() * 10.0 ) ) + { + m_Map = map; + m_X = x; + m_Y = y; + } + + protected override void OnTick() + { + int z = m_Map.GetAverageZ( m_X, m_Y ); + bool canFit = m_Map.CanFit( m_X, m_Y, z, 6, false, false ); + + for ( int i = -3; !canFit && i <= 3; ++i ) + { + canFit = m_Map.CanFit( m_X, m_Y, z + i, 6, false, false ); + + if ( canFit ) + z += i; + } + + if ( !canFit ) + return; + + Gold g = new Gold( 500, 1000 ); + + g.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map ); + + if ( 0.5 >= Utility.RandomDouble() ) + { + switch ( Utility.Random( 3 ) ) + { + case 0: // Fire column + { + Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x3709, 10, 30, 5052 ); + Effects.PlaySound( g, g.Map, 0x208 ); + + break; + } + case 1: // Explosion + { + Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x36BD, 20, 10, 5044 ); + Effects.PlaySound( g, g.Map, 0x307 ); + + break; + } + case 2: // Ball of fire + { + Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x36FE, 10, 10, 5052 ); + + break; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/BaseShieldGuard.cs b/Scripts/Mobiles/Special/BaseShieldGuard.cs new file mode 100644 index 0000000..554e468 --- /dev/null +++ b/Scripts/Mobiles/Special/BaseShieldGuard.cs @@ -0,0 +1,151 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Guilds; + +namespace Server.Mobiles +{ + public abstract class BaseShieldGuard : BaseCreature + { + public BaseShieldGuard() : base( AIType.AI_Melee, FightMode.Aggressor, 14, 1, 0.8, 1.6 ) + { + InitStats( 1000, 1000, 1000 ); + Title = "the guard"; + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + + AddItem( new FemalePlateChest() ); + AddItem( new PlateArms() ); + AddItem( new PlateLegs() ); + + switch( Utility.Random( 2 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomNondyedHue() ) ); break; + case 1: AddItem( new BodySash( Utility.RandomNondyedHue() ) ); break; + } + + switch( Utility.Random( 2 ) ) + { + case 0: AddItem( new Skirt( Utility.RandomNondyedHue() ) ); break; + case 1: AddItem( new Kilt( Utility.RandomNondyedHue() ) ); break; + } + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + + AddItem( new PlateChest() ); + AddItem( new PlateArms() ); + AddItem( new PlateLegs() ); + + switch( Utility.Random( 3 ) ) + { + case 0: AddItem( new Doublet( Utility.RandomNondyedHue() ) ); break; + case 1: AddItem( new Tunic( Utility.RandomNondyedHue() ) ); break; + case 2: AddItem( new BodySash( Utility.RandomNondyedHue() ) ); break; + } + } + + Utility.AssignRandomHair( this ); + if( Utility.RandomBool() ) + Utility.AssignRandomFacialHair( this, HairHue ); + + VikingSword weapon = new VikingSword(); + weapon.Movable = false; + AddItem( weapon ); + + BaseShield shield = Shield; + shield.Movable = false; + AddItem( shield ); + + PackGold( 250, 500 ); + + Skills[SkillName.Anatomy].Base = 120.0; + Skills[SkillName.Tactics].Base = 120.0; + Skills[SkillName.Swords].Base = 120.0; + Skills[SkillName.MagicResist].Base = 120.0; + Skills[SkillName.DetectHidden].Base = 100.0; + } + + public abstract int Keyword{ get; } + public abstract BaseShield Shield{ get; } + public abstract int SignupNumber{ get; } + public abstract GuildType Type{ get; } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.InRange( this.Location, 2 ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( !e.Handled && e.HasKeyword( Keyword ) && e.Mobile.InRange( this.Location, 2 ) ) + { + e.Handled = true; + + Mobile from = e.Mobile; + Guild g = from.Guild as Guild; + + if ( g == null || g.Type != Type ) + { + Say( SignupNumber ); + } + else + { + Container pack = from.Backpack; + BaseShield shield = Shield; + Item twoHanded = from.FindItemOnLayer( Layer.TwoHanded ); + + if ( (pack != null && pack.FindItemByType( shield.GetType() ) != null) || ( twoHanded != null && shield.GetType().IsAssignableFrom( twoHanded.GetType() ) ) ) + { + Say( 1007110 ); // Why dost thou ask about virtue guards when thou art one? + shield.Delete(); + } + else if ( from.PlaceInBackpack( shield ) ) + { + Say( Utility.Random( 1007101, 5 ) ); + Say( 1007139 ); // I see you are in need of our shield, Here you go. + from.AddToBackpack( shield ); + } + else + { + from.SendLocalizedMessage( 502868 ); // Your backpack is too full. + shield.Delete(); + } + } + } + + base.OnSpeech( e ); + } + + public BaseShieldGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/CapturedHordeMinion.cs b/Scripts/Mobiles/Special/CapturedHordeMinion.cs new file mode 100644 index 0000000..f3f537c --- /dev/null +++ b/Scripts/Mobiles/Special/CapturedHordeMinion.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class CapturedHordeMinion : HordeMinion + { + [Constructable] + public CapturedHordeMinion() + { + this.FightMode = FightMode.None; + } + + public override bool InitialInnocent{ get{ return true; } } + + public override bool CanBeDamaged() + { + return false; + } + + public CapturedHordeMinion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/ChaosGuard.cs b/Scripts/Mobiles/Special/ChaosGuard.cs new file mode 100644 index 0000000..476a338 --- /dev/null +++ b/Scripts/Mobiles/Special/ChaosGuard.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Guilds; + +namespace Server.Mobiles +{ + public class ChaosGuard : BaseShieldGuard + { + public override int Keyword{ get{ return 0x22; } } // *chaos shield* + public override BaseShield Shield{ get{ return new ChaosShield(); } } + public override int SignupNumber{ get{ return 1007140; } } // Sign up with a guild of chaos if thou art interested. + public override GuildType Type{ get{ return GuildType.Chaos; } } + + public override bool BardImmune{ get{ return true; } } + + [Constructable] + public ChaosGuard() + { + } + + public ChaosGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/DarkGuardian.cs b/Scripts/Mobiles/Special/DarkGuardian.cs new file mode 100644 index 0000000..5d92e11 --- /dev/null +++ b/Scripts/Mobiles/Special/DarkGuardian.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("a dark guardians' corpse")] + public class DarkGuardian : BaseCreature + { + [Constructable] + public DarkGuardian() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "a dark guardian"; + Body = 78; + BaseSoundID = 0x3E9; + + SetStr(125, 150); + SetDex(100, 120); + SetInt(200, 235); + + SetHits(150, 180); + + SetDamage(43, 48); + + SetDamageType(ResistanceType.Physical, 10); + SetDamageType(ResistanceType.Cold, 40); + SetDamageType(ResistanceType.Energy, 50); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 20, 45); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 20, 45); + SetResistance(ResistanceType.Energy, 30, 40); + + SetSkill(SkillName.EvalInt, 40.1, 50); + SetSkill(SkillName.Magery, 50.1, 60.0); + SetSkill(SkillName.Meditation, 85.1, 95.0); + SetSkill(SkillName.MagicResist, 50.1, 70.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 50; + PackNecroReg(15, 25); + PackItem(new DaemonBone(30)); + } + + public DarkGuardian(Serial serial) + : base(serial) + { + } + + public override void GenerateLoot() + { + AddLoot(LootPack.Rich); + AddLoot(LootPack.MedScrolls, 2); + } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + + public override int TreasureMapLevel { get { return 2; } } + public override bool BleedImmune { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + public override bool Unprovokable { get { return true; } } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.WriteEncodedInt(0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Dummy.cs b/Scripts/Mobiles/Special/Dummy.cs new file mode 100644 index 0000000..b957f12 --- /dev/null +++ b/Scripts/Mobiles/Special/Dummy.cs @@ -0,0 +1,152 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Mobiles +{ + /// + /// This is a test creature + /// You can set its value in game + /// It die after 5 minutes, so your test server stay clean + /// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2" + /// + /// A iTeam of negative will set a faction at random + /// + /// Say Kill if you want them to die + /// + /// + public class Dummy : BaseCreature + { + public Timer m_Timer; + + [Constructable] + public Dummy(AIType iAI, FightMode iFightMode, int iRangePerception, int iRangeFight, double dActiveSpeed, double dPassiveSpeed) : base(iAI, iFightMode, iRangePerception, iRangeFight, dActiveSpeed, dPassiveSpeed) + { + this.Body = 400 + Utility.Random(2); + this.Hue = Utility.RandomSkinHue(); + + this.Skills[SkillName.DetectHidden].Base = 100; + this.Skills[SkillName.MagicResist].Base = 120; + + Team = Utility.Random(3); + + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + Utility.AssignRandomHair( this, iHue ); + + LeatherGloves glv = new LeatherGloves(); + glv.Hue = iHue; + glv.LootType = LootType.Newbied; + AddItem(glv); + + Container pack = new Backpack(); + + pack.Movable = false; + + AddItem( pack ); + + m_Timer = new AutokillTimer(this); + m_Timer.Start(); + } + + public Dummy( Serial serial ) : base( serial ) + { + m_Timer = new AutokillTimer(this); + m_Timer.Start(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + return base.HandlesOnSpeech( from ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + base.OnSpeech( e ); + + if (e.Mobile.AccessLevel >= AccessLevel.GameMaster) + { + if (e.Speech == "kill") + { + m_Timer.Stop(); + m_Timer.Delay = TimeSpan.FromSeconds( Utility.Random(1, 5) ); + m_Timer.Start(); + } + } + } + + public override void OnTeamChange() + { + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + Item item = FindItemOnLayer( Layer.OuterTorso ); + + if ( item != null ) + item.Hue = jHue; + + item = FindItemOnLayer( Layer.Helm ); + + if ( item != null ) + item.Hue = iHue; + + item = FindItemOnLayer( Layer.Gloves ); + + if ( item != null ) + item.Hue = iHue; + + item = FindItemOnLayer( Layer.Shoes ); + + if ( item != null ) + item.Hue = iHue; + + HairHue = iHue; + + item = FindItemOnLayer( Layer.MiddleTorso ); + + if ( item != null ) + item.Hue = iHue; + + item = FindItemOnLayer( Layer.OuterLegs ); + + if ( item != null ) + item.Hue = iHue; + } + + private class AutokillTimer : Timer + { + private Dummy m_Owner; + + public AutokillTimer( Dummy owner ) : base( TimeSpan.FromMinutes(5.0) ) + { + m_Owner = owner; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Owner.Kill(); + Stop(); + } + } + } +} diff --git a/Scripts/Mobiles/Special/DummySpecific.cs b/Scripts/Mobiles/Special/DummySpecific.cs new file mode 100644 index 0000000..4847710 --- /dev/null +++ b/Scripts/Mobiles/Special/DummySpecific.cs @@ -0,0 +1,816 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Mobiles +{ + /// + /// This is a test creature + /// You can set its value in game + /// It die after 5 minutes, so your test server stay clean + /// Create a macro to help your creation "[add Dummy 1 15 7 -1 0.5 2" + /// + /// A iTeam of negative will set a faction at random + /// + /// Say Kill if you want them to die + /// + /// + + public class DummyMace : Dummy + { + + [Constructable] + public DummyMace() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Macer + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 125, 125, 90 ); + this.Skills[SkillName.Macing].Base = 120; + this.Skills[SkillName.Anatomy].Base = 120; + this.Skills[SkillName.Healing].Base = 120; + this.Skills[SkillName.Tactics].Base = 120; + + + // Name + this.Name = "Macer"; + + // Equip + WarHammer war = new WarHammer(); + war.Movable = true; + war.Crafter = this; + war.Quality = WeaponQuality.Regular; + AddItem( war ); + + Boots bts = new Boots(); + bts.Hue = iHue; + AddItem( bts ); + + ChainChest cht = new ChainChest(); + cht.Movable = false; + cht.LootType = LootType.Newbied; + cht.Crafter = this; + cht.Quality = ArmorQuality.Regular; + AddItem( cht ); + + ChainLegs chl = new ChainLegs(); + chl.Movable = false; + chl.LootType = LootType.Newbied; + chl.Crafter = this; + chl.Quality = ArmorQuality.Regular; + AddItem( chl ); + + PlateArms pla = new PlateArms(); + pla.Movable = false; + pla.LootType = LootType.Newbied; + pla.Crafter = this; + pla.Quality = ArmorQuality.Regular; + AddItem( pla ); + + Bandage band = new Bandage( 50 ); + AddToBackpack( band ); + } + + public DummyMace( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummyFence : Dummy + { + + [Constructable] + public DummyFence() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Fencer + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 125, 125, 90 ); + this.Skills[SkillName.Fencing].Base = 120; + this.Skills[SkillName.Anatomy].Base = 120; + this.Skills[SkillName.Healing].Base = 120; + this.Skills[SkillName.Tactics].Base = 120; + + // Name + this.Name = "Fencer"; + + // Equip + Spear ssp = new Spear(); + ssp.Movable = true; + ssp.Crafter = this; + ssp.Quality = WeaponQuality.Regular; + AddItem( ssp ); + + Boots snd = new Boots(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem( snd ); + + ChainChest cht = new ChainChest(); + cht.Movable = false; + cht.LootType = LootType.Newbied; + cht.Crafter = this; + cht.Quality = ArmorQuality.Regular; + AddItem( cht ); + + ChainLegs chl = new ChainLegs(); + chl.Movable = false; + chl.LootType = LootType.Newbied; + chl.Crafter = this; + chl.Quality = ArmorQuality.Regular; + AddItem( chl ); + + PlateArms pla = new PlateArms(); + pla.Movable = false; + pla.LootType = LootType.Newbied; + pla.Crafter = this; + pla.Quality = ArmorQuality.Regular; + AddItem( pla ); + + Bandage band = new Bandage( 50 ); + AddToBackpack( band ); + } + + public DummyFence( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummySword : Dummy + { + + [Constructable] + public DummySword() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Swordsman + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 125, 125, 90 ); + this.Skills[SkillName.Swords].Base = 120; + this.Skills[SkillName.Anatomy].Base = 120; + this.Skills[SkillName.Healing].Base = 120; + this.Skills[SkillName.Tactics].Base = 120; + this.Skills[SkillName.Parry].Base = 120; + + + // Name + this.Name = "Swordsman"; + + // Equip + Katana kat = new Katana(); + kat.Crafter = this; + kat.Movable = true; + kat.Quality = WeaponQuality.Regular; + AddItem( kat ); + + Boots bts = new Boots(); + bts.Hue = iHue; + AddItem( bts ); + + ChainChest cht = new ChainChest(); + cht.Movable = false; + cht.LootType = LootType.Newbied; + cht.Crafter = this; + cht.Quality = ArmorQuality.Regular; + AddItem( cht ); + + ChainLegs chl = new ChainLegs(); + chl.Movable = false; + chl.LootType = LootType.Newbied; + chl.Crafter = this; + chl.Quality = ArmorQuality.Regular; + AddItem( chl ); + + PlateArms pla = new PlateArms(); + pla.Movable = false; + pla.LootType = LootType.Newbied; + pla.Crafter = this; + pla.Quality = ArmorQuality.Regular; + AddItem( pla ); + + Bandage band = new Bandage( 50 ); + AddToBackpack( band ); + } + + public DummySword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummyNox : Dummy + { + + [Constructable] + public DummyNox() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) + { + + // A Dummy Nox or Pure Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 90, 90, 125 ); + this.Skills[SkillName.Magery].Base = 120; + this.Skills[SkillName.EvalInt].Base = 120; + this.Skills[SkillName.Inscribe].Base = 100; + this.Skills[SkillName.Wrestling].Base = 120; + this.Skills[SkillName.Meditation].Base = 120; + this.Skills[SkillName.Poisoning].Base = 100; + + + // Name + this.Name = "Nox Mage"; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content =0xFFFFFFFFFFFFFFFF; + AddItem( book ); + + Kilt kilt = new Kilt(); + kilt.Hue = jHue; + AddItem( kilt ); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem( snd ); + + SkullCap skc = new SkullCap(); + skc.Hue = iHue; + AddItem( skc ); + + // Spells + AddSpellAttack( typeof(Spells.First.MagicArrowSpell) ); + AddSpellAttack( typeof(Spells.First.WeakenSpell) ); + AddSpellAttack( typeof(Spells.Third.FireballSpell) ); + AddSpellDefense( typeof(Spells.Third.WallOfStoneSpell) ); + AddSpellDefense( typeof(Spells.First.HealSpell) ); + } + + public DummyNox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummyStun : Dummy + { + + [Constructable] + public DummyStun() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) + { + + // A Dummy Stun Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 90, 90, 125 ); + this.Skills[SkillName.Magery].Base = 100; + this.Skills[SkillName.EvalInt].Base = 120; + this.Skills[SkillName.Anatomy].Base = 80; + this.Skills[SkillName.Wrestling].Base = 80; + this.Skills[SkillName.Meditation].Base = 100; + this.Skills[SkillName.Poisoning].Base = 100; + + + // Name + this.Name = "Stun Mage"; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content =0xFFFFFFFFFFFFFFFF; + AddItem( book ); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem( lea ); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem( lec ); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem( leg ); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem( lel ); + + Boots bts = new Boots(); + bts.Hue = iHue; + AddItem( bts ); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem( cap ); + + // Spells + AddSpellAttack( typeof(Spells.First.MagicArrowSpell) ); + AddSpellAttack( typeof(Spells.First.WeakenSpell) ); + AddSpellAttack( typeof(Spells.Third.FireballSpell) ); + AddSpellDefense( typeof(Spells.Third.WallOfStoneSpell) ); + AddSpellDefense( typeof(Spells.First.HealSpell) ); + } + + public DummyStun( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummySuper : Dummy + { + + [Constructable] + public DummySuper() : base(AIType.AI_Mage, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Super Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 125, 125, 125 ); + this.Skills[SkillName.Magery].Base = 120; + this.Skills[SkillName.EvalInt].Base = 120; + this.Skills[SkillName.Anatomy].Base = 120; + this.Skills[SkillName.Wrestling].Base = 120; + this.Skills[SkillName.Meditation].Base = 120; + this.Skills[SkillName.Poisoning].Base = 100; + this.Skills[SkillName.Inscribe].Base = 100; + + // Name + this.Name = "Super Mage"; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content =0xFFFFFFFFFFFFFFFF; + AddItem( book ); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem( lea ); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem( lec ); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem( leg ); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem( lel ); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem( snd ); + + JesterHat jhat = new JesterHat(); + jhat.Hue = iHue; + AddItem( jhat ); + + Doublet dblt = new Doublet(); + dblt.Hue = iHue; + AddItem( dblt ); + + // Spells + AddSpellAttack( typeof(Spells.First.MagicArrowSpell) ); + AddSpellAttack( typeof(Spells.First.WeakenSpell) ); + AddSpellAttack( typeof(Spells.Third.FireballSpell) ); + AddSpellDefense( typeof(Spells.Third.WallOfStoneSpell) ); + AddSpellDefense( typeof(Spells.First.HealSpell) ); + } + + public DummySuper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummyHealer : Dummy + { + + [Constructable] + public DummyHealer() : base(AIType.AI_Healer, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Healer Mage + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 125, 125, 125 ); + this.Skills[SkillName.Magery].Base = 120; + this.Skills[SkillName.EvalInt].Base = 120; + this.Skills[SkillName.Anatomy].Base = 120; + this.Skills[SkillName.Wrestling].Base = 120; + this.Skills[SkillName.Meditation].Base = 120; + this.Skills[SkillName.Healing].Base = 100; + + // Name + this.Name = "Healer"; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content =0xFFFFFFFFFFFFFFFF; + AddItem( book ); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem( lea ); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem( lec ); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem( leg ); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem( lel ); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem( snd ); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem( cap ); + + Robe robe = new Robe(); + robe.Hue = iHue; + AddItem( robe ); + + } + + public DummyHealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class DummyAssassin : Dummy + { + + [Constructable] + public DummyAssassin() : base(AIType.AI_Melee, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Hybrid Assassin + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats( 105, 105, 105 ); + this.Skills[SkillName.Magery].Base = 120; + this.Skills[SkillName.EvalInt].Base = 120; + this.Skills[SkillName.Swords].Base = 120; + this.Skills[SkillName.Tactics].Base = 120; + this.Skills[SkillName.Meditation].Base = 120; + this.Skills[SkillName.Poisoning].Base = 100; + + // Name + this.Name = "Hybrid Assassin"; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content =0xFFFFFFFFFFFFFFFF; + AddToBackpack( book ); + + Katana kat = new Katana(); + kat.Movable = false; + kat.LootType = LootType.Newbied; + kat.Crafter = this; + kat.Poison = Poison.Deadly; + kat.PoisonCharges = 12; + kat.Quality = WeaponQuality.Regular; + AddToBackpack( kat ); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem( lea ); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem( lec ); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem( leg ); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem( lel ); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem( snd ); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem( cap ); + + Robe robe = new Robe(); + robe.Hue = iHue; + AddItem( robe ); + + DeadlyPoisonPotion pota = new DeadlyPoisonPotion(); + pota.LootType = LootType.Newbied; + AddToBackpack( pota ); + + DeadlyPoisonPotion potb = new DeadlyPoisonPotion(); + potb.LootType = LootType.Newbied; + AddToBackpack( potb ); + + DeadlyPoisonPotion potc = new DeadlyPoisonPotion(); + potc.LootType = LootType.Newbied; + AddToBackpack( potc ); + + DeadlyPoisonPotion potd = new DeadlyPoisonPotion(); + potd.LootType = LootType.Newbied; + AddToBackpack( potd ); + + Bandage band = new Bandage( 50 ); + AddToBackpack( band ); + + } + + public DummyAssassin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + [TypeAlias("Server.Mobiles.DummyTheif")] + public class DummyThief : Dummy + { + [Constructable] + public DummyThief() + : base(AIType.AI_Thief, FightMode.Closest, 15, 1, 0.2, 0.6) + { + // A Dummy Hybrid Thief + int iHue = 20 + Team * 40; + int jHue = 25 + Team * 40; + + // Skills and Stats + this.InitStats(105, 105, 105); + this.Skills[SkillName.Healing].Base = 120; + this.Skills[SkillName.Anatomy].Base = 120; + this.Skills[SkillName.Stealing].Base = 120; + this.Skills[SkillName.ArmsLore].Base = 100; + this.Skills[SkillName.Meditation].Base = 120; + this.Skills[SkillName.Wrestling].Base = 120; + + // Name + this.Name = "Hybrid Thief"; + + // Equip + Spellbook book = new Spellbook(); + book.Movable = false; + book.LootType = LootType.Newbied; + book.Content = 0xFFFFFFFFFFFFFFFF; + AddItem(book); + + LeatherArms lea = new LeatherArms(); + lea.Movable = false; + lea.LootType = LootType.Newbied; + lea.Crafter = this; + lea.Quality = ArmorQuality.Regular; + AddItem(lea); + + LeatherChest lec = new LeatherChest(); + lec.Movable = false; + lec.LootType = LootType.Newbied; + lec.Crafter = this; + lec.Quality = ArmorQuality.Regular; + AddItem(lec); + + LeatherGorget leg = new LeatherGorget(); + leg.Movable = false; + leg.LootType = LootType.Newbied; + leg.Crafter = this; + leg.Quality = ArmorQuality.Regular; + AddItem(leg); + + LeatherLegs lel = new LeatherLegs(); + lel.Movable = false; + lel.LootType = LootType.Newbied; + lel.Crafter = this; + lel.Quality = ArmorQuality.Regular; + AddItem(lel); + + Sandals snd = new Sandals(); + snd.Hue = iHue; + snd.LootType = LootType.Newbied; + AddItem(snd); + + Cap cap = new Cap(); + cap.Hue = iHue; + AddItem(cap); + + Robe robe = new Robe(); + robe.Hue = iHue; + AddItem(robe); + + Bandage band = new Bandage(50); + AddToBackpack(band); + } + + public DummyThief(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Harrower.cs b/Scripts/Mobiles/Special/Harrower.cs new file mode 100644 index 0000000..0d108c2 --- /dev/null +++ b/Scripts/Mobiles/Special/Harrower.cs @@ -0,0 +1,671 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Harrower : BaseCreature + { + public Type[] UniqueList{ get{ return new Type[] { typeof( AcidProofRobe ) }; } } + public Type[] SharedList{ get{ return new Type[] { typeof( TheRobeOfBritanniaAri ) }; } } + public Type[] DecorativeList{ get{ return new Type[] { typeof( EvilIdolSkull ), typeof( SkullPole ) }; } } + + private bool m_TrueForm; + private Item m_GateItem; + private List m_Tentacles; + private Timer m_Timer; + + private class SpawnEntry + { + public Point3D m_Location; + public Point3D m_Entrance; + + public SpawnEntry( Point3D loc, Point3D ent ) + { + m_Location = loc; + m_Entrance = ent; + } + } + + private static SpawnEntry[] m_Entries = new SpawnEntry[] + { + new SpawnEntry( new Point3D( 5242, 945, -40 ), new Point3D( 1176, 2638, 0 ) ), // Destard + new SpawnEntry( new Point3D( 5225, 798, 0 ), new Point3D( 1176, 2638, 0 ) ), // Destard + new SpawnEntry( new Point3D( 5556, 886, 30 ), new Point3D( 1298, 1080, 0 ) ), // Despise + new SpawnEntry( new Point3D( 5187, 615, 0 ), new Point3D( 4111, 432, 5 ) ), // Deceit + new SpawnEntry( new Point3D( 5319, 583, 0 ), new Point3D( 4111, 432, 5 ) ), // Deceit + new SpawnEntry( new Point3D( 5713, 1334, -1 ), new Point3D( 2923, 3407, 8 ) ), // Fire + new SpawnEntry( new Point3D( 5860, 1460, -2 ), new Point3D( 2923, 3407, 8 ) ), // Fire + new SpawnEntry( new Point3D( 5328, 1620, 0 ), new Point3D( 5451, 3143, -60 ) ), // Terathan Keep + new SpawnEntry( new Point3D( 5690, 538, 0 ), new Point3D( 2042, 224, 14 ) ), // Wrong + new SpawnEntry( new Point3D( 5609, 195, 0 ), new Point3D( 514, 1561, 0 ) ), // Shame + new SpawnEntry( new Point3D( 5475, 187, 0 ), new Point3D( 514, 1561, 0 ) ), // Shame + new SpawnEntry( new Point3D( 6085, 179, 0 ), new Point3D( 4721, 3822, 0 ) ), // Hythloth + new SpawnEntry( new Point3D( 6084, 66, 0 ), new Point3D( 4721, 3822, 0 ) ), // Hythloth + new SpawnEntry( new Point3D( 5499, 2003, 0 ), new Point3D( 2499, 919, 0 ) ), // Covetous + new SpawnEntry( new Point3D( 5579, 1858, 0 ), new Point3D( 2499, 919, 0 ) ) // Covetous + }; + + private static ArrayList m_Instances = new ArrayList(); + + public static ArrayList Instances{ get{ return m_Instances; } } + + public static Harrower Spawn( Point3D platLoc, Map platMap ) + { + if ( m_Instances.Count > 0 ) + return null; + + SpawnEntry entry = m_Entries[Utility.Random( m_Entries.Length )]; + + Harrower harrower = new Harrower(); + + harrower.MoveToWorld( entry.m_Location, Map.Felucca ); + + harrower.m_GateItem = new HarrowerGate( harrower, platLoc, platMap, entry.m_Entrance, Map.Felucca ); + + return harrower; + } + + public static bool CanSpawn + { + get + { + return ( m_Instances.Count == 0 ); + } + } + + [Constructable] + public Harrower() : base( AIType.AI_Mage, FightMode.Closest, 18, 1, 0.2, 0.4 ) + { + m_Instances.Add( this ); + + Name = "the harrower"; + BodyValue = 146; + + SetStr( 900, 1000 ); + SetDex( 125, 135 ); + SetInt( 1000, 1200 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 60; + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Energy, 50 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 60, 80 ); + SetResistance( ResistanceType.Cold, 60, 80 ); + SetResistance( ResistanceType.Poison, 60, 80 ); + SetResistance( ResistanceType.Energy, 60, 80 ); + + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.2, 110.0 ); + SetSkill( SkillName.MagicResist, 120.2, 160.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + + m_Tentacles = new List(); + + m_Timer = new TeleportTimer( this ); + m_Timer.Start(); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.SuperBoss, 2 ); + AddLoot( LootPack.Meager ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool Unprovokable{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + private static readonly double[] m_Offsets = new double[] + { + Math.Cos( 000.0 / 180.0 * Math.PI ), Math.Sin( 000.0 / 180.0 * Math.PI ), + Math.Cos( 040.0 / 180.0 * Math.PI ), Math.Sin( 040.0 / 180.0 * Math.PI ), + Math.Cos( 080.0 / 180.0 * Math.PI ), Math.Sin( 080.0 / 180.0 * Math.PI ), + Math.Cos( 120.0 / 180.0 * Math.PI ), Math.Sin( 120.0 / 180.0 * Math.PI ), + Math.Cos( 160.0 / 180.0 * Math.PI ), Math.Sin( 160.0 / 180.0 * Math.PI ), + Math.Cos( 200.0 / 180.0 * Math.PI ), Math.Sin( 200.0 / 180.0 * Math.PI ), + Math.Cos( 240.0 / 180.0 * Math.PI ), Math.Sin( 240.0 / 180.0 * Math.PI ), + Math.Cos( 280.0 / 180.0 * Math.PI ), Math.Sin( 280.0 / 180.0 * Math.PI ), + Math.Cos( 320.0 / 180.0 * Math.PI ), Math.Sin( 320.0 / 180.0 * Math.PI ), + }; + + public void Morph() + { + if ( m_TrueForm ) + return; + + m_TrueForm = true; + + Name = "the true harrower"; + BodyValue = 780; + Hue = 0x497; + + Hits = HitsMax; + Stam = StamMax; + Mana = ManaMax; + + ProcessDelta(); + + Say( 1049499 ); // Behold my true form! + + Map map = this.Map; + + if ( map != null ) + { + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + double rx = m_Offsets[i]; + double ry = m_Offsets[i + 1]; + + int dist = 0; + bool ok = false; + int x = 0, y = 0, z = 0; + + while ( !ok && dist < 10 ) + { + int rdist = 10 + dist; + + x = this.X + (int)(rx * rdist); + y = this.Y + (int)(ry * rdist); + z = map.GetAverageZ( x, y ); + + if ( !(ok = map.CanFit( x, y, this.Z, 16, false, false ) ) ) + ok = map.CanFit( x, y, z, 16, false, false ); + + if ( dist >= 0 ) + dist = -(dist + 1); + else + dist = -(dist - 1); + } + + if ( !ok ) + continue; + + HarrowerTentacles spawn = new HarrowerTentacles( this ); + + spawn.Team = this.Team; + + spawn.MoveToWorld( new Point3D( x, y, z ), map ); + + m_Tentacles.Add( spawn ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int HitsMax{ get{ return m_TrueForm ? 65000 : 30000; } } + + [CommandProperty( AccessLevel.GameMaster )] + public override int ManaMax{ get{ return 5000; } } + + public Harrower( Serial serial ) : base( serial ) + { + m_Instances.Add( this ); + } + + public override void OnAfterDelete() + { + m_Instances.Remove( this ); + + base.OnAfterDelete(); + } + + public override bool DisallowAllMoves{ get{ return m_TrueForm; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_TrueForm ); + writer.Write( m_GateItem ); + writer.WriteMobileList( m_Tentacles ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_TrueForm = reader.ReadBool(); + m_GateItem = reader.ReadItem(); + m_Tentacles = reader.ReadStrongMobileList(); + + m_Timer = new TeleportTimer( this ); + m_Timer.Start(); + + break; + } + } + } + + public void GivePowerScrolls() + { + List toGive = new List(); + List rights = BaseCreature.GetLootingRights( this.DamageEntries, this.HitsMax ); + + for ( int i = rights.Count - 1; i >= 0; --i ) + { + DamageStore ds = rights[i]; + + if ( ds.m_HasRight ) + toGive.Add( ds.m_Mobile ); + } + + if ( toGive.Count == 0 ) + return; + + // Randomize + for ( int i = 0; i < toGive.Count; ++i ) + { + int rand = Utility.Random( toGive.Count ); + Mobile hold = toGive[i]; + toGive[i] = toGive[rand]; + toGive[rand] = hold; + } + + for ( int i = 0; i < 16; ++i ) + { + /*int level; + double random = Utility.RandomDouble(); + + if ( 0.1 >= random ) + level = 25; + else if ( 0.25 >= random ) + level = 20; + else if ( 0.45 >= random ) + level = 15; + else if ( 0.70 >= random ) + level = 10; + else + level = 5;*/ + + Mobile m = toGive[i % toGive.Count]; + + /* m.SendLocalizedMessage( 1049524 ); // You have received a scroll of power! + m.AddToBackpack( new StatCapScroll( 225 + level ) );*/ + + if ( m is PlayerMobile ) + { + PlayerMobile pm = (PlayerMobile)m; + + for ( int j = 0; j < pm.JusticeProtectors.Count; ++j ) + { + Mobile prot = (Mobile)pm.JusticeProtectors[j]; + + if ( prot.Map != m.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion( m, prot ) ) + continue; + + int chance = 0; + + switch ( VirtueHelper.GetLevel( prot, VirtueName.Justice ) ) + { + case VirtueLevel.Seeker: chance = 60; break; + case VirtueLevel.Follower: chance = 80; break; + case VirtueLevel.Knight: chance = 100; break; + } + + if ( chance > Utility.Random( 100 ) ) + { + /*prot.SendLocalizedMessage( 1049368 ); // You have been rewarded for your dedication to Justice! + prot.AddToBackpack( new StatCapScroll( 225 + level ) );*/ + } + } + } + } + } + + public override bool OnBeforeDeath() + { + if ( m_TrueForm ) + { + List rights = BaseCreature.GetLootingRights( this.DamageEntries, this.HitsMax ); + + for ( int i = rights.Count - 1; i >= 0; --i ) + { + DamageStore ds = rights[i]; + + if ( ds.m_HasRight && ds.m_Mobile is PlayerMobile ) + PlayerMobile.ChampionTitleInfo.AwardHarrowerTitle( (PlayerMobile)ds.m_Mobile ); + } + + if ( !NoKillAwards ) + { + //GivePowerScrolls(); + + Map map = this.Map; + + if ( map != null ) + { + for ( int x = -16; x <= 16; ++x ) + { + for ( int y = -16; y <= 16; ++y ) + { + double dist = Math.Sqrt(x*x+y*y); + + if ( dist <= 16 ) + new GoodiesTimer( map, X + x, Y + y ).Start(); + } + } + } + + m_DamageEntries = new Dictionary(); + + for ( int i = 0; i < m_Tentacles.Count; ++i ) + { + Mobile m = m_Tentacles[i]; + + if ( !m.Deleted ) + m.Kill(); + + RegisterDamageTo( m ); + } + + m_Tentacles.Clear(); + + RegisterDamageTo( this ); + AwardArtifact( GetArtifact() ); + + if ( m_GateItem != null ) + m_GateItem.Delete(); + } + + return base.OnBeforeDeath(); + } + else + { + Morph(); + return false; + } + } + + Dictionary m_DamageEntries; + + public virtual void RegisterDamageTo( Mobile m ) + { + if( m == null ) + return; + + foreach( DamageEntry de in m.DamageEntries ) + { + Mobile damager = de.Damager; + + Mobile master = damager.GetDamageMaster( m ); + + if( master != null ) + damager = master; + + RegisterDamage( damager, de.DamageGiven ); + } + } + + public void RegisterDamage( Mobile from, int amount ) + { + if( from == null || !from.Player ) + return; + + if( m_DamageEntries.ContainsKey( from ) ) + m_DamageEntries[from] += amount; + else + m_DamageEntries.Add( from, amount ); + + from.SendMessage(String.Format("Total Damage: {0}", m_DamageEntries[from]) ); + } + + public void AwardArtifact( Item artifact ) + { + if (artifact == null ) + return; + + int totalDamage = 0; + + Dictionary validEntries = new Dictionary(); + + foreach (KeyValuePair kvp in m_DamageEntries) + { + if( IsEligible( kvp.Key, artifact ) ) + { + validEntries.Add( kvp.Key, kvp.Value ); + totalDamage += kvp.Value; + } + } + + int randomDamage = Utility.RandomMinMax( 1, totalDamage ); + + totalDamage = 0; + + foreach (KeyValuePair kvp in validEntries) + { + totalDamage += kvp.Value; + + if (totalDamage >= randomDamage) + { + GiveArtifact(kvp.Key, artifact); + return; + } + } + + artifact.Delete(); + } + + public void GiveArtifact( Mobile to, Item artifact ) + { + if ( to == null || artifact == null ) + return; + + Container pack = to.Backpack; + + if ( pack == null || !pack.TryDropItem( to, artifact, false ) ) + artifact.Delete(); + else + to.SendLocalizedMessage( 1062317 ); // For your valor in combating the fallen beast, a special artifact has been bestowed on you. + } + + public bool IsEligible( Mobile m, Item Artifact ) + { + return m.Player && m.Alive && m.InRange( Location, 32 ) && m.Backpack != null && m.Backpack.CheckHold( m, Artifact, false ); + } + + public Item GetArtifact() + { + double random = Utility.RandomDouble(); + if ( 0.05 >= random ) + return CreateArtifact( UniqueList ); + else if ( 0.15 >= random ) + return CreateArtifact( SharedList ); + else if ( 0.30 >= random ) + return CreateArtifact( DecorativeList ); + return null; + } + + public Item CreateArtifact( Type[] list ) + { + if( list.Length == 0 ) + return null; + + int random = Utility.Random( list.Length ); + + Type type = list[random]; + + return Loot.Construct( type ); + } + + private class TeleportTimer : Timer + { + private Mobile m_Owner; + + private static int[] m_Offsets = new int[] + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1 + }; + + public TeleportTimer( Mobile owner ) : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Owner = owner; + } + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + Map map = m_Owner.Map; + + if ( map == null ) + return; + + if ( 0.25 < Utility.RandomDouble() ) + return; + + Mobile toTeleport = null; + + foreach ( Mobile m in m_Owner.GetMobilesInRange( 16 ) ) + { + if ( m != m_Owner && m.Player && m_Owner.CanBeHarmful( m ) && m_Owner.CanSee( m ) ) + { + toTeleport = m; + break; + } + } + + if ( toTeleport != null ) + { + int offset = Utility.Random( 8 ) * 2; + + Point3D to = m_Owner.Location; + + for ( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = m_Owner.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = m_Owner.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if ( map.CanSpawnMobile( x, y, m_Owner.Z ) ) + { + to = new Point3D( x, y, m_Owner.Z ); + break; + } + else + { + int z = map.GetAverageZ( x, y ); + + if ( map.CanSpawnMobile( x, y, z ) ) + { + to = new Point3D( x, y, z ); + break; + } + } + } + + Mobile m = toTeleport; + + Point3D from = m.Location; + + m.Location = to; + + Server.Spells.SpellHelper.Turn( m_Owner, toTeleport ); + Server.Spells.SpellHelper.Turn( toTeleport, m_Owner ); + + m.ProcessDelta(); + + Effects.SendLocationParticles( EffectItem.Create( from, m.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); + Effects.SendLocationParticles( EffectItem.Create( to, m.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023 ); + + m.PlaySound( 0x1FE ); + + m_Owner.Combatant = toTeleport; + } + } + } + + private class GoodiesTimer : Timer + { + private Map m_Map; + private int m_X, m_Y; + + public GoodiesTimer( Map map, int x, int y ) : base( TimeSpan.FromSeconds( Utility.RandomDouble() * 10.0 ) ) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Map = map; + m_X = x; + m_Y = y; + } + + protected override void OnTick() + { + int z = m_Map.GetAverageZ( m_X, m_Y ); + bool canFit = m_Map.CanFit( m_X, m_Y, z, 6, false, false ); + + for ( int i = -3; !canFit && i <= 3; ++i ) + { + canFit = m_Map.CanFit( m_X, m_Y, z + i, 6, false, false ); + + if ( canFit ) + z += i; + } + + if ( !canFit ) + return; + + Gold g = new Gold( 750, 1250 ); + + g.MoveToWorld( new Point3D( m_X, m_Y, z ), m_Map ); + + if ( 0.5 >= Utility.RandomDouble() ) + { + switch ( Utility.Random( 3 ) ) + { + case 0: // Fire column + { + Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x3709, 10, 30, 5052 ); + Effects.PlaySound( g, g.Map, 0x208 ); + + break; + } + case 1: // Explosion + { + Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x36BD, 20, 10, 5044 ); + Effects.PlaySound( g, g.Map, 0x307 ); + + break; + } + case 2: // Ball of fire + { + Effects.SendLocationParticles( EffectItem.Create( g.Location, g.Map, EffectItem.DefaultDuration ), 0x36FE, 10, 10, 5052 ); + + break; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/HarrowerTentacles.cs b/Scripts/Mobiles/Special/HarrowerTentacles.cs new file mode 100644 index 0000000..29ff683 --- /dev/null +++ b/Scripts/Mobiles/Special/HarrowerTentacles.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a tentacles corpse" )] + public class HarrowerTentacles : BaseCreature + { + private Mobile m_Harrower; + + private DrainTimer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Harrower + { + get + { + return m_Harrower; + } + set + { + m_Harrower = value; + } + } + + [Constructable] + public HarrowerTentacles() : this( null ) + { + } + + public HarrowerTentacles( Mobile harrower ) : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + m_Harrower = harrower; + + Name = "tentacles of the harrower"; + Body = 129; + + SetStr( 901, 1000 ); + SetDex( 126, 140 ); + SetInt( 1001, 1200 ); + + SetHits( 541, 600 ); + + SetDamage( 13, 20 ); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Fire, 20 ); + SetDamageType( ResistanceType.Cold, 20 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 20 ); + + SetResistance( ResistanceType.Physical, 55, 65 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 35, 45 ); + SetResistance( ResistanceType.Poison, 35, 45 ); + SetResistance( ResistanceType.Energy, 35, 45 ); + + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 120.1, 140.0 ); + SetSkill( SkillName.Swords, 90.1, 100.0 ); + SetSkill( SkillName.Tactics, 90.1, 100.0 ); + SetSkill( SkillName.Wrestling, 90.1, 100.0 ); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 60; + + m_Timer = new DrainTimer( this ); + m_Timer.Start(); + + PackReg( 50 ); + PackNecroReg( 15, 75 ); + } + + public override void CheckReflect( Mobile caster, ref bool reflect ) + { + reflect = true; + } + + public override int GetIdleSound() + { + return 0x101; + } + + public override int GetAngerSound() + { + return 0x5E; + } + + public override int GetDeathSound() + { + return 0x1C2; + } + + public override int GetAttackSound() + { + return -1; // unknown + } + + public override int GetHurtSound() + { + return 0x289; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.FilthyRich, 2 ); + AddLoot( LootPack.MedScrolls, 3 ); + AddLoot( LootPack.HighScrolls, 2 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool Unprovokable{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override bool DisallowAllMoves{ get{ return true; } } + + public HarrowerTentacles( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Harrower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Harrower = reader.ReadMobile(); + + m_Timer = new DrainTimer( this ); + m_Timer.Start(); + + break; + } + } + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + base.OnAfterDelete(); + } + + private class DrainTimer : Timer + { + private HarrowerTentacles m_Owner; + + public DrainTimer( HarrowerTentacles owner ) : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + m_Owner = owner; + Priority = TimerPriority.TwoFiftyMS; + } + + private static ArrayList m_ToDrain = new ArrayList(); + + protected override void OnTick() + { + if ( m_Owner.Deleted ) + { + Stop(); + return; + } + + foreach ( Mobile m in m_Owner.GetMobilesInRange( 9 ) ) + { + if ( m == m_Owner || m == m_Owner.Harrower || !m_Owner.CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature ) + { + BaseCreature bc = m as BaseCreature; + + if ( bc.Controlled || bc.Summoned ) + m_ToDrain.Add( m ); + } + else if ( m.Player ) + { + m_ToDrain.Add( m ); + } + } + + foreach ( Mobile m in m_ToDrain ) + { + m_Owner.DoHarmful( m ); + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist ); + m.PlaySound( 0x1F1 ); + + int drain = Utility.RandomMinMax( 14, 30 ); + + m_Owner.Hits += drain; + + if ( m_Owner.Harrower != null ) + m_Owner.Harrower.Hits += drain; + + m.Damage( drain, m_Owner ); + } + + m_ToDrain.Clear(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/LordOaks.cs b/Scripts/Mobiles/Special/LordOaks.cs new file mode 100644 index 0000000..c264664 --- /dev/null +++ b/Scripts/Mobiles/Special/LordOaks.cs @@ -0,0 +1,240 @@ +using System; +using Server; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class LordOaks : BaseChampion + { + private Mobile m_Queen; + private bool m_SpawnedQueen; + + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Enlightenment; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( OrcChieftainHelm ) }; } } + public override Type[] SharedList{ get{ return new Type[] { typeof( RoyalGuardSurvivalKnife ), + typeof( DjinnisRing ), + typeof( LieutenantOfTheBritannianRoyalGuard ), + typeof( SamaritanRobe ), + typeof( DetectiveBoots ), + typeof( TheMostKnowledgePerson ) }; } } + public override Type[] DecorativeList{ get{ return new Type[] { typeof( WaterTile ), + typeof( WindSpirit ), + typeof( Pier ), + typeof( DirtPatch )}; + } + } + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { }; } } + + [Constructable] + public LordOaks() : base( AIType.AI_Mage, FightMode.Evil ) + { + Body = 175; + Name = "Lord Oaks"; + + SetStr( 403, 850 ); + SetDex( 101, 150 ); + SetInt( 503, 800 ); + + SetHits( 3000 ); + SetStam( 202, 400 ); + + SetDamage( 21, 33 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Fire, 25 ); + + SetResistance( ResistanceType.Physical, 85, 90 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 80, 90 ); + SetResistance( ResistanceType.Energy, 80, 90 ); + + SetSkill( SkillName.Anatomy, 75.1, 100.0 ); + SetSkill( SkillName.EvalInt, 120.1, 130.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.Meditation, 120.1, 130.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 100.0 ); + + Fame = 22500; + Karma = 22500; + + VirtualArmor = 100; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 5 ); + } + + public override bool AutoDispel{ get{ return true; } } + public override bool CanFly { get { return true; } } + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool Uncalmable{ get{ return Core.SE; } } + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + + public void SpawnPixies( Mobile target ) + { + Map map = this.Map; + + if ( map == null ) + return; + + this.Say( 1042154 ); // You shall never defeat me as long as I have my queen! + + int newPixies = Utility.RandomMinMax( 3, 6 ); + + for ( int i = 0; i < newPixies; ++i ) + { + Pixie pixie = new Pixie(); + + pixie.Team = this.Team; + pixie.FightMode = FightMode.Closest; + + bool validLocation = false; + Point3D loc = this.Location; + + for ( int j = 0; !validLocation && j < 10; ++j ) + { + int x = X + Utility.Random( 3 ) - 1; + int y = Y + Utility.Random( 3 ) - 1; + int z = map.GetAverageZ( x, y ); + + if ( validLocation = map.CanFit( x, y, this.Z, 16, false, false ) ) + loc = new Point3D( x, y, Z ); + else if ( validLocation = map.CanFit( x, y, z, 16, false, false ) ) + loc = new Point3D( x, y, z ); + } + + pixie.MoveToWorld( loc, map ); + pixie.Combatant = target; + } + } + + public override int GetAngerSound() + { + return 0x2F8; + } + + public override int GetIdleSound() + { + return 0x2F8; + } + + public override int GetAttackSound() + { + return Utility.Random( 0x2F5, 2 ); + } + + public override int GetHurtSound() + { + return 0x2F9; + } + + public override int GetDeathSound() + { + return 0x2F7; + } + + public void CheckQueen() + { + if( this.Map == null ) + return; + + if ( !m_SpawnedQueen ) + { + this.Say( 1042153 ); // Come forth my queen! + + m_Queen = new Silvani(); + + ((BaseCreature)m_Queen).Team = this.Team; + + m_Queen.MoveToWorld( this.Location, this.Map ); + + m_SpawnedQueen = true; + } + else if ( m_Queen != null && m_Queen.Deleted ) + { + m_Queen = null; + } + } + + public override void AlterDamageScalarFrom( Mobile caster, ref double scalar ) + { + CheckQueen(); + + if ( m_Queen != null ) + { + scalar *= 0.1; + + if ( 0.1 >= Utility.RandomDouble() ) + SpawnPixies( caster ); + } + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + defender.Damage( Utility.Random( 20, 10 ), this ); + defender.Stam -= Utility.Random( 20, 10 ); + defender.Mana -= Utility.Random( 20, 10 ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + CheckQueen(); + + if ( m_Queen != null && 0.1 >= Utility.RandomDouble() ) + SpawnPixies( attacker ); + + attacker.Damage( Utility.Random( 20, 10 ), this ); + attacker.Stam -= Utility.Random( 20, 10 ); + attacker.Mana -= Utility.Random( 20, 10 ); + } + + public LordOaks( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Queen ); + writer.Write( m_SpawnedQueen ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Queen = reader.ReadMobile(); + m_SpawnedQueen = reader.ReadBool(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Mephitis.cs b/Scripts/Mobiles/Special/Mephitis.cs new file mode 100644 index 0000000..3996677 --- /dev/null +++ b/Scripts/Mobiles/Special/Mephitis.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Mephitis : BaseChampion + { + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Venom; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( Calm ) }; } } + public override Type[] SharedList { get { return new Type[] { typeof(OblivionsNeedle), typeof(ANecromancerShroud), typeof(EmbroideredOakLeafCloak), typeof(TheMostKnowledgePerson) }; } } + public override Type[] DecorativeList { get { return new Type[] { typeof(Web), typeof(MonsterStatuette) }; } } + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { MonsterStatuetteType.Spider }; } } + + [Constructable] + public Mephitis() : base( AIType.AI_Melee ) + { + Body = 173; + Name = "Mephitis"; + + BaseSoundID = 0x183; + + SetStr( 505, 1000 ); + SetDex( 102, 300 ); + SetInt( 402, 600 ); + + SetHits( 3000 ); + SetStam( 105, 600 ); + + SetDamage( 21, 33 ); + + SetDamageType( ResistanceType.Physical, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 75, 80 ); + SetResistance( ResistanceType.Fire, 60, 70 ); + SetResistance( ResistanceType.Cold, 60, 70 ); + SetResistance( ResistanceType.Poison, 100 ); + SetResistance( ResistanceType.Energy, 60, 70 ); + + SetSkill( SkillName.MagicResist, 70.7, 140.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 80; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 4 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override Poison HitPoison{ get{ return Poison.Lethal; } } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + // TODO: Web ability + } + + public Mephitis( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Neira.cs b/Scripts/Mobiles/Special/Neira.cs new file mode 100644 index 0000000..84373fd --- /dev/null +++ b/Scripts/Mobiles/Special/Neira.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Neira : BaseChampion + { + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Death; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( ShroudOfDeciet ) }; } } + public override Type[] SharedList{ get{ return new Type[] { typeof( ANecromancerShroud ), + typeof( CaptainJohnsHat ) }; } } + public override Type[] DecorativeList{ get{ return new Type[] { typeof( WallBlood ), typeof( TatteredAncientMummyWrapping ) }; } } + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { }; } } + + [Constructable] + public Neira() : base( AIType.AI_Mage ) + { + Name = "Neira"; + Title = "the necromancer"; + Body = 401; + Hue = 0x83EC; + + SetStr( 305, 425 ); + SetDex( 72, 150 ); + SetInt( 505, 750 ); + + SetHits( 4800 ); + SetStam( 102, 300 ); + + SetDamage( 25, 35 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 30 ); + SetResistance( ResistanceType.Fire, 35, 45 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.EvalInt, 120.0 ); + SetSkill( SkillName.Magery, 120.0 ); + SetSkill( SkillName.Meditation, 120.0 ); + SetSkill( SkillName.MagicResist, 150.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 30; + Female = true; + + Item shroud = new HoodedShroudOfShadows(); + + shroud.Movable = false; + + AddItem( shroud ); + + Scimitar weapon = new Scimitar(); + + weapon.Skill = SkillName.Wrestling; + weapon.Hue = 38; + weapon.Movable = false; + + AddItem( weapon ); + + //new SkeletalMount().Rider = this; + AddItem( new VirtualMountItem( this ) ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 3 ); + AddLoot( LootPack.Meager ); + } + + public override bool OnBeforeDeath() + { + IMount mount = this.Mount; + + if ( mount != null ) + mount.Rider = null; + + if ( mount is Mobile ) + ((Mobile)mount).Delete(); + + return base.OnBeforeDeath(); + } + + private bool m_SpeedBoost; + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + CheckSpeedBoost(); + base.OnDamage( amount, from, willKill ); + } + + private const double SpeedBoostScalar = 1.2; + + private void CheckSpeedBoost() + { + if( Hits < (HitsMax / 4 ) ) + { + if( !m_SpeedBoost ) + { + ActiveSpeed /= SpeedBoostScalar; + PassiveSpeed /= SpeedBoostScalar; + m_SpeedBoost = true; + } + } + else if( m_SpeedBoost ) + { + ActiveSpeed *= SpeedBoostScalar; + PassiveSpeed *= SpeedBoostScalar; + m_SpeedBoost = false; + } + } + + private class VirtualMount : IMount + { + private VirtualMountItem m_Item; + + public Mobile Rider + { + get { return m_Item.Rider; } + set { } + } + + public VirtualMount( VirtualMountItem item ) + { + m_Item = item; + } + + public virtual void OnRiderDamaged( int amount, Mobile from, bool willKill ) + { + } + } + + private class VirtualMountItem : Item, IMountItem + { + private Mobile m_Rider; + private VirtualMount m_Mount; + + public Mobile Rider { get { return m_Rider; } } + + public VirtualMountItem( Mobile mob ) + : base( 0x3EBB ) + { + Layer = Layer.Mount; + + Movable = false; + + m_Rider = mob; + m_Mount = new VirtualMount( this ); + } + + public IMount Mount + { + get { return m_Mount; } + } + + public VirtualMountItem( Serial serial ) + : base( serial ) + { + m_Mount = new VirtualMount( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (Mobile)m_Rider ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Rider = reader.ReadMobile(); + + if( m_Rider == null ) + Delete(); + } + } + + public override bool AlwaysMurderer{ get{ return true; } } + public override bool BardImmune{ get{ return !Core.SE; } } + public override bool Unprovokable{ get{ return Core.SE; } } + public override bool Uncalmable{ get{ return Core.SE; } } + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + + public override bool ShowFameTitle{ get{ return false; } } + public override bool ClickTitle{ get{ return false; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.1 >= Utility.RandomDouble() ) // 10% chance to drop or throw an unholy bone + AddUnholyBone( defender, 0.25 ); + + CheckSpeedBoost(); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.1 >= Utility.RandomDouble() ) // 10% chance to drop or throw an unholy bone + AddUnholyBone( attacker, 0.25 ); + } + + public override void AlterDamageScalarFrom( Mobile caster, ref double scalar ) + { + base.AlterDamageScalarFrom( caster, ref scalar ); + + if ( 0.1 >= Utility.RandomDouble() ) // 10% chance to throw an unholy bone + AddUnholyBone( caster, 1.0 ); + } + + public void AddUnholyBone( Mobile target, double chanceToThrow ) + { + if( this.Map == null ) + return; + + if ( chanceToThrow >= Utility.RandomDouble() ) + { + Direction = GetDirectionTo( target ); + MovingEffect( target, 0xF7E, 10, 1, true, false, 0x496, 0 ); + new DelayTimer( this, target ).Start(); + } + else + { + new UnholyBone().MoveToWorld( Location, Map ); + } + } + + private class DelayTimer : Timer + { + private Mobile m_Mobile; + private Mobile m_Target; + + public DelayTimer( Mobile m, Mobile target ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_Target = target; + } + + protected override void OnTick() + { + if ( m_Mobile.CanBeHarmful( m_Target ) ) + { + m_Mobile.DoHarmful( m_Target ); + AOS.Damage( m_Target, m_Mobile, Utility.RandomMinMax( 10, 20 ), 100, 0, 0, 0, 0 ); + new UnholyBone().MoveToWorld( m_Target.Location, m_Target.Map ); + } + } + } + + public Neira( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + writer.Write( m_SpeedBoost ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 1: + { + m_SpeedBoost = reader.ReadBool(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/OrderGuard.cs b/Scripts/Mobiles/Special/OrderGuard.cs new file mode 100644 index 0000000..bf370cc --- /dev/null +++ b/Scripts/Mobiles/Special/OrderGuard.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Guilds; + +namespace Server.Mobiles +{ + public class OrderGuard : BaseShieldGuard + { + public override int Keyword{ get{ return 0x21; } } // *order shield* + public override BaseShield Shield{ get{ return new OrderShield(); } } + public override int SignupNumber{ get{ return 1007141; } } // Sign up with a guild of order if thou art interested. + public override GuildType Type{ get{ return GuildType.Order; } } + + public override bool BardImmune{ get{ return true; } } + + [Constructable] + public OrderGuard() + { + } + + public OrderGuard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Paragon.cs b/Scripts/Mobiles/Special/Paragon.cs new file mode 100644 index 0000000..2f1e0b5 --- /dev/null +++ b/Scripts/Mobiles/Special/Paragon.cs @@ -0,0 +1,218 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Paragon + { + public static double ChestChance = .10; // Chance that a paragon will carry a paragon chest + public static double ChocolateIngredientChance = .20; // Chance that a paragon will drop a chocolatiering ingredient + public static Map[] Maps = new Map[] // Maps that paragons will spawn on + { + // Scriptiz : on ne veut pas de monstres Paragon + //Map.Ilshenar + }; + + private static TimeSpan FastRegenRate = TimeSpan.FromSeconds(.5); + private static TimeSpan CPUSaverRate = TimeSpan.FromSeconds(2); + + private class ParagonStamRegen : Timer + { + private BaseCreature m_Owner; + + public ParagonStamRegen(Mobile m) + : base(FastRegenRate, FastRegenRate) + { + this.Priority = TimerPriority.FiftyMS; + + m_Owner = m as BaseCreature; + } + + protected override void OnTick() + { + if (!m_Owner.Deleted && m_Owner.IsParagon && m_Owner.Map != Map.Internal) + { + m_Owner.Stam++; + + Delay = Interval = (m_Owner.Stam < (m_Owner.StamMax * .75)) ? FastRegenRate : CPUSaverRate; + } + else + { + Stop(); + } + } + } + + public static Type[] Artifacts = new Type[] + { + typeof( GoldBricks ), typeof( PhillipsWoodenSteed ), + typeof( AlchemistsBauble ), typeof( ArcticDeathDealer ), + typeof( BlazeOfDeath ), typeof( BowOfTheJukaKing ), + typeof( BurglarsBandana ), typeof( CavortingClub ), + typeof( EnchantedTitanLegBone ), typeof( GwennosHarp ), + typeof( IolosLute ), typeof( LunaLance ), + typeof( NightsKiss ), typeof( NoxRangersHeavyCrossbow ), + typeof( OrcishVisage ), typeof( PolarBearMask ), + typeof( ShieldOfInvulnerability ), typeof( StaffOfPower ), + typeof( VioletCourage ), typeof( HeartOfTheLion ), + typeof( WrathOfTheDryad ), typeof( PixieSwatter ), + typeof( GlovesOfThePugilist ) + }; + + public static int Hue = 0x501; // Paragon hue + + // Buffs + public static double HitsBuff = 5.0; + public static double StrBuff = 1.05; + public static double IntBuff = 1.20; + public static double DexBuff = 1.20; + public static double SkillsBuff = 1.20; + public static double SpeedBuff = 1.20; + public static double FameBuff = 1.40; + public static double KarmaBuff = 1.40; + public static int DamageBuff = 5; + + public static void Convert( BaseCreature bc ) + { + if ( bc.IsParagon ) + return; + + bc.Hue = Hue; + + if ( bc.HitsMaxSeed >= 0 ) + bc.HitsMaxSeed = (int)( bc.HitsMaxSeed * HitsBuff ); + + bc.RawStr = (int)( bc.RawStr * StrBuff ); + bc.RawInt = (int)( bc.RawInt * IntBuff ); + bc.RawDex = (int)( bc.RawDex * DexBuff ); + + bc.Hits = bc.HitsMax; + bc.Mana = bc.ManaMax; + bc.Stam = bc.StamMax; + + for( int i = 0; i < bc.Skills.Length; i++ ) + { + Skill skill = (Skill)bc.Skills[i]; + + if ( skill.Base > 0.0 ) + skill.Base *= SkillsBuff; + } + + bc.PassiveSpeed /= SpeedBuff; + bc.ActiveSpeed /= SpeedBuff; + bc.CurrentSpeed = bc.PassiveSpeed; + + bc.DamageMin += DamageBuff; + bc.DamageMax += DamageBuff; + + if ( bc.Fame > 0 ) + bc.Fame = (int)( bc.Fame * FameBuff ); + + if ( bc.Fame > 32000 ) + bc.Fame = 32000; + + // TODO: Mana regeneration rate = Sqrt( buffedFame ) / 4 + + if ( bc.Karma != 0 ) + { + bc.Karma = (int)( bc.Karma * KarmaBuff ); + + if( Math.Abs( bc.Karma ) > 32000 ) + bc.Karma = 32000 * Math.Sign( bc.Karma ); + } + + new ParagonStamRegen(bc).Start(); + } + + public static void UnConvert(BaseCreature bc) + { + if (!bc.IsParagon) + return; + + bc.Hue = 0; + + if ( bc.HitsMaxSeed >= 0 ) + bc.HitsMaxSeed = (int)( bc.HitsMaxSeed / HitsBuff ); + + bc.RawStr = (int)( bc.RawStr / StrBuff ); + bc.RawInt = (int)( bc.RawInt / IntBuff ); + bc.RawDex = (int)( bc.RawDex / DexBuff ); + + bc.Hits = bc.HitsMax; + bc.Mana = bc.ManaMax; + bc.Stam = bc.StamMax; + + for( int i = 0; i < bc.Skills.Length; i++ ) + { + Skill skill = (Skill)bc.Skills[i]; + + if ( skill.Base > 0.0 ) + skill.Base /= SkillsBuff; + } + + bc.PassiveSpeed *= SpeedBuff; + bc.ActiveSpeed *= SpeedBuff; + bc.CurrentSpeed = bc.PassiveSpeed; + + bc.DamageMin -= DamageBuff; + bc.DamageMax -= DamageBuff; + + if ( bc.Fame > 0 ) + bc.Fame = (int)( bc.Fame / FameBuff ); + if ( bc.Karma != 0 ) + bc.Karma = (int)( bc.Karma / KarmaBuff ); + } + + public static bool CheckConvert( BaseCreature bc ) + { + return CheckConvert( bc, bc.Location, bc.Map ); + } + + public static bool CheckConvert( BaseCreature bc, Point3D location, Map m ) + { + if ( !Core.AOS ) + return false; + + if ( Array.IndexOf( Maps, m ) == -1 ) + return false; + + if (bc is BaseChampion || bc is Harrower || bc is BaseVendor || bc is BaseEscortable || bc is Clone || bc.IsParagon) + return false; + + int fame = bc.Fame; + + if ( fame > 32000 ) + fame = 32000; + + double chance = 1 / Math.Round( 20.0 - ( fame / 3200 )); + + return ( chance > Utility.RandomDouble() ); + } + + public static bool CheckArtifactChance( Mobile m, BaseCreature bc ) + { + if ( !Core.AOS ) + return false; + + double fame = (double)bc.Fame; + + if ( fame > 32000 ) + fame = 32000; + + double chance = 1 / ( Math.Max( 10, 100 * ( 0.83 - Math.Round( Math.Log( Math.Round( fame / 6000, 3 ) + 0.001, 10 ), 3 ) ) ) * ( 100 - Math.Sqrt( m.Luck ) ) / 100.0 ); + + return chance > Utility.RandomDouble(); + } + + public static void GiveArtifactTo( Mobile m ) + { + Item item = (Item)Activator.CreateInstance( Artifacts[Utility.Random(Artifacts.Length)] ); + + if ( m.AddToBackpack( item ) ) + m.SendMessage( "As a reward for slaying the mighty paragon, an artifact has been placed in your backpack." ); + else + m.SendMessage( "As your backpack is full, your reward for destroying the legendary paragon has been placed at your feet." ); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Rikktor.cs b/Scripts/Mobiles/Special/Rikktor.cs new file mode 100644 index 0000000..a74ed56 --- /dev/null +++ b/Scripts/Mobiles/Special/Rikktor.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Spells; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Rikktor : BaseChampion + { + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Power; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( CrownOfTalKeesh ) }; } } + public override Type[] SharedList{ get{ return new Type[] { typeof( TheMostKnowledgePerson ), + typeof( BraveKnightOfTheBritannia ), + typeof( LieutenantOfTheBritannianRoyalGuard ) }; } } + public override Type[] DecorativeList{ get{ return new Type[] { typeof( LavaTile ), + typeof( MonsterStatuette ), + typeof( MonsterStatuette ) }; } } + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { MonsterStatuetteType.OphidianArchMage, + MonsterStatuetteType.OphidianWarrior }; } } + + [Constructable] + public Rikktor() : base( AIType.AI_Melee ) + { + Body = 172; + Name = "Rikktor"; + + SetStr( 701, 900 ); + SetDex( 201, 350 ); + SetInt( 51, 100 ); + + SetHits( 3000 ); + SetStam( 203, 650 ); + + SetDamage( 28, 55 ); + + SetDamageType( ResistanceType.Physical, 25 ); + SetDamageType( ResistanceType.Fire, 50 ); + SetDamageType( ResistanceType.Energy, 25 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 80, 90 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 80, 90 ); + SetResistance( ResistanceType.Energy, 80, 90 ); + + SetSkill( SkillName.Anatomy, 100.0 ); + SetSkill( SkillName.MagicResist, 140.2, 160.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + + Fame = 22500; + Karma = -22500; + + VirtualArmor = 130; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 4 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override ScaleType ScaleType{ get{ return ScaleType.All; } } + public override int Scales{ get{ return 20; } } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.2 >= Utility.RandomDouble() ) + Earthquake(); + } + + public void Earthquake() + { + Map map = this.Map; + + if ( map == null ) + return; + + ArrayList targets = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 8 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team) ) + targets.Add( m ); + else if ( m.Player ) + targets.Add( m ); + } + + PlaySound( 0x2F3 ); + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + double damage = m.Hits * 0.6; + + if ( damage < 10.0 ) + damage = 10.0; + else if ( damage > 75.0 ) + damage = 75.0; + + DoHarmful( m ); + + AOS.Damage( m, this, (int)damage, 100, 0, 0, 0, 0 ); + + if ( m.Alive && m.Body.IsHuman && !m.Mounted ) + m.Animate( 20, 7, 1, true, false, 0 ); // take hit + } + } + + public override int GetAngerSound() + { + return Utility.Random( 0x2CE, 2 ); + } + + public override int GetIdleSound() + { + return 0x2D2; + } + + public override int GetAttackSound() + { + return Utility.Random( 0x2C7, 5 ); + } + + public override int GetHurtSound() + { + return 0x2D1; + } + + public override int GetDeathSound() + { + return 0x2CC; + } + + public Rikktor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Semidar.cs b/Scripts/Mobiles/Special/Semidar.cs new file mode 100644 index 0000000..5d75fdf --- /dev/null +++ b/Scripts/Mobiles/Special/Semidar.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Semidar : BaseChampion + { + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Pain; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( GladiatorsCollar ) }; } } + public override Type[] SharedList { get { return new Type[] { typeof(RoyalGuardSurvivalKnife), typeof(ANecromancerShroud), typeof(LieutenantOfTheBritannianRoyalGuard) }; } } + public override Type[] DecorativeList { get { return new Type[] { typeof(LavaTile), typeof(DemonSkull) }; } } + + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { }; } } + + [Constructable] + public Semidar() : base( AIType.AI_Mage ) + { + Name = "Semidar"; + Body = 174; + BaseSoundID = 0x4B0; + + SetStr( 502, 600 ); + SetDex( 102, 200 ); + SetInt( 601, 750 ); + + SetHits( 1500 ); + SetStam( 103, 250 ); + + SetDamage( 29, 35 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Fire, 25 ); + + SetResistance( ResistanceType.Physical, 20, 30 ); + SetResistance( ResistanceType.Fire, 50, 60 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 20, 30 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.EvalInt, 95.1, 100.0 ); + SetSkill( SkillName.Magery, 90.1, 105.0 ); + SetSkill( SkillName.Meditation, 95.1, 100.0 ); + SetSkill( SkillName.MagicResist, 120.2, 140.0 ); + SetSkill( SkillName.Tactics, 90.1, 105.0 ); + SetSkill( SkillName.Wrestling, 90.1, 105.0 ); + + Fame = 24000; + Karma = -24000; + + VirtualArmor = 20; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 4 ); + AddLoot( LootPack.FilthyRich ); + } + + public override bool Unprovokable{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + + public override void CheckReflect( Mobile caster, ref bool reflect ) + { + if ( caster.Body.IsMale ) + reflect = true; // Always reflect if caster isn't female + } + + public override void AlterDamageScalarFrom( Mobile caster, ref double scalar ) + { + if ( caster.Body.IsMale ) + scalar = 20; // Male bodies always reflect.. damage scaled 20x + } + + public void DrainLife() + { + if( this.Map == null ) + return; + + ArrayList list = new ArrayList(); + + foreach ( Mobile m in this.GetMobilesInRange( 2 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team) ) + list.Add( m ); + else if ( m.Player ) + list.Add( m ); + } + + foreach ( Mobile m in list ) + { + DoHarmful( m ); + + m.FixedParticles( 0x374A, 10, 15, 5013, 0x496, 0, EffectLayer.Waist ); + m.PlaySound( 0x231 ); + + m.SendMessage( "You feel the life drain out of you!" ); + + int toDrain = Utility.RandomMinMax( 10, 40 ); + + Hits += toDrain; + m.Damage( toDrain, this ); + } + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + if ( 0.25 >= Utility.RandomDouble() ) + DrainLife(); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.25 >= Utility.RandomDouble() ) + DrainLife(); + } + + public Semidar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Special/Serado.cs b/Scripts/Mobiles/Special/Serado.cs new file mode 100644 index 0000000..794d7af --- /dev/null +++ b/Scripts/Mobiles/Special/Serado.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Engines.CannedEvil; + +namespace Server.Mobiles +{ + public class Serado : BaseChampion + { + public override ChampionSkullType SkullType{ get{ return ChampionSkullType.Power; } } + + public override Type[] UniqueList{ get{ return new Type[] { typeof( Pacify ) }; } } + public override Type[] SharedList{ get{ return new Type[] { typeof( BraveKnightOfTheBritannia ), + typeof( DetectiveBoots ), + typeof( EmbroideredOakLeafCloak ), + typeof( LieutenantOfTheBritannianRoyalGuard ) }; } } + public override Type[] DecorativeList{ get{ return new Type[] { typeof( Futon ), typeof( SwampTile ) }; } } + + public override MonsterStatuetteType[] StatueTypes{ get{ return new MonsterStatuetteType[] { }; } } + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.DoubleStrike; + } + + [Constructable] + public Serado() : base( AIType.AI_Melee ) + { + Name = "Serado"; + Title = "the awakened"; + + Body = 249; + Hue = 0x96C; + + SetStr( 1000 ); + SetDex( 150 ); + SetInt( 300 ); + + SetHits( 9000 ); + SetMana( 300 ); + + SetDamage( 29, 35 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 20 ); + SetDamageType( ResistanceType.Energy, 10 ); + + SetResistance( ResistanceType.Physical, 30 ); + SetResistance( ResistanceType.Fire, 60 ); + SetResistance( ResistanceType.Cold, 60 ); + SetResistance( ResistanceType.Poison, 90 ); + SetResistance( ResistanceType.Energy, 50 ); + + SetSkill( SkillName.MagicResist, 120.0 ); + SetSkill( SkillName.Tactics, 120.0 ); + SetSkill( SkillName.Wrestling, 70.0 ); + SetSkill( SkillName.Poisoning, 150.0 ); + + Fame = 22500; + Karma = -22500; + + PackItem( Engines.Plants.Seed.RandomBonsaiSeed() ); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 4 ); + AddLoot( LootPack.FilthyRich ); + AddLoot( LootPack.Gems, 6 ); + } + + public override int TreasureMapLevel{ get{ return 5; } } + + public override Poison HitPoison{ get{ return Poison.Lethal; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override double HitPoisonChance{ get{ return 0.8; } } + + public override int Feathers{ get{ return 30; } } + + public override bool ShowFameTitle{ get{ return false; } } + public override bool ClickTitle{ get{ return false; } } + + // TODO: Hit Lightning Area + + public override void OnDamagedBySpell( Mobile attacker ) + { + base.OnDamagedBySpell( attacker ); + + ScaleResistances(); + DoCounter( attacker ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + ScaleResistances(); + DoCounter( attacker ); + } + + private void ScaleResistances() + { + double hitsLost = (HitsMax - Hits) / (double)HitsMax; + + SetResistance( ResistanceType.Physical, 30 + (int)(hitsLost * ( 95 - 30 )) ); + SetResistance( ResistanceType.Fire, 60 + (int)(hitsLost * ( 95 - 60 )) ); + SetResistance( ResistanceType.Cold, 60 + (int)(hitsLost * ( 95 - 60 )) ); + SetResistance( ResistanceType.Poison, 90 + (int)(hitsLost * ( 95 - 90 )) ); + SetResistance( ResistanceType.Energy, 50 + (int)(hitsLost * ( 95 - 50 )) ); + } + + private void DoCounter( Mobile attacker ) + { + if ( this.Map == null || ( attacker is BaseCreature && ((BaseCreature)attacker).BardProvoked ) ) + return; + + if ( 0.2 > Utility.RandomDouble() ) + { + /* Counterattack with Hit Poison Area + * 20-25 damage, unresistable + * Lethal poison, 100% of the time + * Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0" + * Doesn't work on provoked monsters + */ + + Mobile target = null; + + if ( attacker is BaseCreature ) + { + Mobile m = ((BaseCreature)attacker).GetMaster(); + + if ( m != null ) + target = m; + } + + if ( target == null || !target.InRange( this, 25 ) ) + target = attacker; + + this.Animate( 10, 4, 1, true, false, 0 ); + + ArrayList targets = new ArrayList(); + + foreach ( Mobile m in target.GetMobilesInRange( 8 ) ) + { + if ( m == this || !CanBeHarmful( m ) ) + continue; + + if ( m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team) ) + targets.Add( m ); + else if ( m.Player ) + targets.Add( m ); + } + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + DoHarmful( m ); + + AOS.Damage( m, this, Utility.RandomMinMax( 20, 25 ), true, 0, 0, 0, 100, 0 ); + + m.FixedParticles( 0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255 ); + m.ApplyPoison( this, Poison.Lethal ); + } + } + } + + public Serado( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Special/ServantOfSemidar.cs b/Scripts/Mobiles/Special/ServantOfSemidar.cs new file mode 100644 index 0000000..4311ddb --- /dev/null +++ b/Scripts/Mobiles/Special/ServantOfSemidar.cs @@ -0,0 +1,49 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class ServantOfSemidar : BaseCreature + { + [Constructable] + public ServantOfSemidar() : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 ) + { + Name = "a servant of Semidar"; + Body = 0x26; + } + + public override bool DisallowAllMoves{ get{ return true; } } + + public override bool InitialInnocent{ get{ return true; } } + + public override bool CanBeDamaged() + { + return false; + } + + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + list.Add( 1005494 ); // enslaved + } + + public ServantOfSemidar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Silvani.cs b/Scripts/Mobiles/Special/Silvani.cs new file mode 100644 index 0000000..4e2345b --- /dev/null +++ b/Scripts/Mobiles/Special/Silvani.cs @@ -0,0 +1,138 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Silvani : BaseCreature + { + [Constructable] + public Silvani() : base( AIType.AI_Mage, FightMode.Evil, 18, 1, 0.1, 0.2 ) + { + Name = "Silvani"; + Body = 176; + BaseSoundID = 0x467; + + SetStr( 253, 400 ); + SetDex( 157, 850 ); + SetInt( 503, 800 ); + + SetHits( 600 ); + + SetDamage( 27, 38 ); + + SetDamageType( ResistanceType.Physical, 75 ); + SetDamageType( ResistanceType.Cold, 25 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 30, 40 ); + SetResistance( ResistanceType.Cold, 30, 40 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Magery, 97.6, 107.5 ); + SetSkill( SkillName.Meditation, 100.0 ); + SetSkill( SkillName.MagicResist, 100.5, 150.0 ); + SetSkill( SkillName.Tactics, 97.6, 100.0 ); + SetSkill( SkillName.Wrestling, 97.6, 100.0 ); + + Fame = 20000; + Karma = 20000; + + VirtualArmor = 50; + } + + public override void GenerateLoot() + { + AddLoot( LootPack.UltraRich, 2 ); + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override bool CanFly { get { return true; } } + public override bool Unprovokable{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Regular; } } + public override int TreasureMapLevel{ get{ return 5; } } + + public void SpawnPixies( Mobile target ) + { + Map map = this.Map; + + if ( map == null ) + return; + + int newPixies = Utility.RandomMinMax( 3, 6 ); + + for ( int i = 0; i < newPixies; ++i ) + { + Pixie pixie = new Pixie(); + + pixie.Team = this.Team; + pixie.FightMode = FightMode.Closest; + + bool validLocation = false; + Point3D loc = this.Location; + + for ( int j = 0; !validLocation && j < 10; ++j ) + { + int x = X + Utility.Random( 3 ) - 1; + int y = Y + Utility.Random( 3 ) - 1; + int z = map.GetAverageZ( x, y ); + + if ( validLocation = map.CanFit( x, y, this.Z, 16, false, false ) ) + loc = new Point3D( x, y, Z ); + else if ( validLocation = map.CanFit( x, y, z, 16, false, false ) ) + loc = new Point3D( x, y, z ); + } + + pixie.MoveToWorld( loc, map ); + pixie.Combatant = target; + } + } + + public override void AlterDamageScalarFrom( Mobile caster, ref double scalar ) + { + if ( 0.1 >= Utility.RandomDouble() ) + SpawnPixies( caster ); + } + + public override void OnGaveMeleeAttack( Mobile defender ) + { + base.OnGaveMeleeAttack( defender ); + + defender.Damage( Utility.Random( 20, 10 ), this ); + defender.Stam -= Utility.Random( 20, 10 ); + defender.Mana -= Utility.Random( 20, 10 ); + } + + public override void OnGotMeleeAttack( Mobile attacker ) + { + base.OnGotMeleeAttack( attacker ); + + if ( 0.1 >= Utility.RandomDouble() ) + SpawnPixies( attacker ); + } + + public Silvani( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Special/Wanderer.cs b/Scripts/Mobiles/Special/Wanderer.cs new file mode 100644 index 0000000..0ac2879 --- /dev/null +++ b/Scripts/Mobiles/Special/Wanderer.cs @@ -0,0 +1,69 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class Wanderer : Mobile + { + private Timer m_Timer; + + [Constructable] + public Wanderer() + { + this.Name = "Me"; + this.Body = 0x1; + this.AccessLevel = AccessLevel.Counselor; + + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + } + + public Wanderer( Serial serial ) : base( serial ) + { + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + } + + public override void OnDelete() + { + m_Timer.Stop(); + + base.OnDelete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + private class InternalTimer : Timer + { + private Wanderer m_Owner; + private int m_Count = 0; + + public InternalTimer( Wanderer owner ) : base( TimeSpan.FromSeconds( 0.1 ), TimeSpan.FromSeconds( 0.1 ) ) + { + m_Owner = owner; + } + + protected override void OnTick() + { + if ( (m_Count++ & 0x3) == 0 ) + { + m_Owner.Direction = (Direction)(Utility.Random( 8 ) | 0x80); + } + + m_Owner.Move( m_Owner.Direction ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Actor.cs b/Scripts/Mobiles/Townfolk/Actor.cs new file mode 100644 index 0000000..7b5a015 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Actor.cs @@ -0,0 +1,69 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class Actor : BaseCreature + { + [Constructable] + public Actor () : base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + InitStats( 31, 41, 51 ); + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + AddItem( new FancyDress( Utility.RandomDyedHue() ) ); + Title = "l'Actrice"; + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + AddItem( new LongPants( Utility.RandomNeutralHue() ) ); + AddItem( new FancyShirt( Utility.RandomDyedHue() ) ); + Title = "l'Acteur"; + } + + AddItem( new Boots( Utility.RandomNeutralHue() ) ); + + Utility.AssignRandomHair( this ); + + Container pack = new Backpack(); + + pack.DropItem( new Gold( 250, 300 ) ); + + pack.Movable = false; + + AddItem( pack ); + } + + + public override bool ClickTitle{ get{ return false; } } + + public Actor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/Artist.cs b/Scripts/Mobiles/Townfolk/Artist.cs new file mode 100644 index 0000000..8572d7e --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Artist.cs @@ -0,0 +1,74 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class Artist : BaseCreature + { + public override bool CanTeach { get { return true; } } + + [Constructable] + public Artist() + : base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + InitStats( 31, 41, 51 ); + + SetSkill( SkillName.Healing, 36, 68 ); + + + SpeechHue = Utility.RandomDyedHue(); + Title = "l'Artiste"; + Hue = Utility.RandomSkinHue(); + + + if( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + } + AddItem( new Doublet( Utility.RandomDyedHue() ) ); + AddItem( new Sandals( Utility.RandomNeutralHue() ) ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + AddItem( new HalfApron( Utility.RandomDyedHue() ) ); + + Utility.AssignRandomHair( this ); + + Container pack = new Backpack(); + + pack.DropItem( new Gold( 250, 300 ) ); + + pack.Movable = false; + + AddItem( pack ); + } + + public override bool ClickTitle { get { return false; } } + + + public Artist( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/Banker.cs b/Scripts/Mobiles/Townfolk/Banker.cs new file mode 100644 index 0000000..dbb62b6 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Banker.cs @@ -0,0 +1,401 @@ +using System; +using System.Collections.Generic; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class Banker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.MerchantsGuild; } } + + [Constructable] + public Banker() : base( "le Banquier", "la Banquiere" ) + { + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBBanker() ); + } + + public static int GetBalance( Mobile from ) + { + Item[] gold, checks; + + return GetBalance( from, out gold, out checks ); + } + + public static int GetBalance( Mobile from, out Item[] gold, out Item[] checks ) + { + int balance = 0; + + Container bank = from.FindBankNoCreate(); + + if ( bank != null ) + { + gold = bank.FindItemsByType( typeof( Gold ) ); + checks = bank.FindItemsByType( typeof( BankCheck ) ); + + for ( int i = 0; i < gold.Length; ++i ) + balance += gold[i].Amount; + + for ( int i = 0; i < checks.Length; ++i ) + balance += ((BankCheck)checks[i]).Worth; + } + else + { + gold = checks = new Item[0]; + } + + return balance; + } + + public static bool Withdraw( Mobile from, int amount ) + { + Item[] gold, checks; + int balance = GetBalance( from, out gold, out checks ); + + if ( balance < amount ) + return false; + + for ( int i = 0; amount > 0 && i < gold.Length; ++i ) + { + if ( gold[i].Amount <= amount ) + { + amount -= gold[i].Amount; + gold[i].Delete(); + } + else + { + gold[i].Amount -= amount; + amount = 0; + } + } + + for ( int i = 0; amount > 0 && i < checks.Length; ++i ) + { + BankCheck check = (BankCheck)checks[i]; + + if ( check.Worth <= amount ) + { + amount -= check.Worth; + check.Delete(); + } + else + { + check.Worth -= amount; + amount = 0; + } + } + + return true; + } + + public static bool Deposit( Mobile from, int amount ) + { + BankBox box = from.FindBankNoCreate(); + if ( box == null ) + return false; + + List items = new List(); + + while ( amount > 0 ) + { + Item item; + if ( amount < 5000 ) + { + item = new Gold( amount ); + amount = 0; + } + else if ( amount <= 1000000 ) + { + item = new BankCheck( amount ); + amount = 0; + } + else + { + item = new BankCheck( 1000000 ); + amount -= 1000000; + } + + if ( box.TryDropItem( from, item, false ) ) + { + items.Add( item ); + } + else + { + item.Delete(); + foreach ( Item curItem in items ) + { + curItem.Delete(); + } + + return false; + } + } + + return true; + } + + public static int DepositUpTo( Mobile from, int amount ) + { + BankBox box = from.FindBankNoCreate(); + if ( box == null ) + return 0; + + int amountLeft = amount; + while ( amountLeft > 0 ) + { + Item item; + int amountGiven; + + if ( amountLeft < 5000 ) + { + item = new Gold( amountLeft ); + amountGiven = amountLeft; + } + else if ( amountLeft <= 1000000 ) + { + item = new BankCheck( amountLeft ); + amountGiven = amountLeft; + } + else + { + item = new BankCheck( 1000000 ); + amountGiven = 1000000; + } + + if ( box.TryDropItem( from, item, false ) ) + { + amountLeft -= amountGiven; + } + else + { + item.Delete(); + break; + } + } + + return amount - amountLeft; + } + + public static void Deposit( Container cont, int amount ) + { + while ( amount > 0 ) + { + Item item; + + if ( amount < 5000 ) + { + item = new Gold( amount ); + amount = 0; + } + else if ( amount <= 1000000 ) + { + item = new BankCheck( amount ); + amount = 0; + } + else + { + item = new BankCheck( 1000000 ); + amount -= 1000000; + } + + cont.DropItem( item ); + } + } + + public Banker( Serial serial ) : base( serial ) + { + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.InRange( this.Location, 12 ) && from.InLOS(this) ) // Scriptiz : && from.InLOS(this) (ligne de vue) + return true; + + return base.HandlesOnSpeech( from ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( !e.Handled && e.Mobile.InRange( this.Location, 12 ) ) + { + for ( int i = 0; i < e.Keywords.Length; ++i ) + { + int keyword = e.Keywords[i]; + + switch ( keyword ) + { + case 0x0000: // *withdraw* + { + e.Handled = true; + + if ( e.Mobile.Criminal ) + { + this.Say( 500389 ); // I will not do business with a criminal! + break; + } + + string[] split = e.Speech.Split( ' ' ); + + if ( split.Length >= 2 ) + { + int amount; + + Container pack = e.Mobile.Backpack; + + if ( !int.TryParse( split[1], out amount ) ) + break; + + if ( (!Core.ML && amount > 5000) || (Core.ML && amount > 60000) ) + { + this.Say( 500381 ); // Thou canst not withdraw so much at one time! + } + else if (pack == null || pack.Deleted || !(pack.TotalWeight < pack.MaxWeight) || !(pack.TotalItems < pack.MaxItems)) + { + this.Say(1048147); // Your backpack can't hold anything else. + } + else if (amount > 0) + { + BankBox box = e.Mobile.FindBankNoCreate(); + + if (box == null || !box.ConsumeTotal(typeof(Gold), amount)) + { + this.Say(500384); // Ah, art thou trying to fool me? Thou hast not so much gold! + } + else + { + pack.DropItem(new Gold(amount)); + + this.Say(1010005); // Thou hast withdrawn gold from thy account. + } + } + } + + break; + } + case 0x0001: // *balance* + { + e.Handled = true; + + if ( e.Mobile.Criminal ) + { + this.Say( 500389 ); // I will not do business with a criminal! + break; + } + + BankBox box = e.Mobile.FindBankNoCreate(); + + if ( box != null ) + this.Say( 1042759, box.TotalGold.ToString() ); // Thy current bank balance is ~1_AMOUNT~ gold. + else + this.Say( 1042759, "0" ); // Thy current bank balance is ~1_AMOUNT~ gold. + + break; + } + case 0x0002: // *bank* + { + e.Handled = true; + + if ( e.Mobile.Criminal ) + { + this.Say( 500378 ); // Thou art a criminal and cannot access thy bank box. + break; + } + + if (e.Speech.Split(' ').Length <= 3) + this.Say("Un petit peu de politesse s'il vous plait quand vous qu�mandez votre coffre !"); + else + e.Mobile.BankBox.Open(); + + break; + } + case 0x0003: // *check* + { + e.Handled = true; + + if ( e.Mobile.Criminal ) + { + this.Say( 500389 ); // I will not do business with a criminal! + break; + } + + string[] split = e.Speech.Split( ' ' ); + + if ( split.Length >= 2 ) + { + int amount; + + if ( !int.TryParse( split[1], out amount ) ) + break; + + if ( amount < 5000 ) + { + this.Say( 1010006 ); // We cannot create checks for such a paltry amount of gold! + } + else if ( amount > 1000000 ) + { + this.Say( 1010007 ); // Our policies prevent us from creating checks worth that much! + } + else + { + BankCheck check = new BankCheck( amount ); + + BankBox box = e.Mobile.BankBox; + + if ( !box.TryDropItem( e.Mobile, check, false ) ) + { + this.Say( 500386 ); // There's not enough room in your bankbox for the check! + check.Delete(); + } + else if ( !box.ConsumeTotal( typeof( Gold ), amount ) ) + { + this.Say( 500384 ); // Ah, art thou trying to fool me? Thou hast not so much gold! + check.Delete(); + } + else + { + this.Say( 1042673, AffixType.Append, amount.ToString(), "" ); // Into your bank box I have placed a check in the amount of: + } + } + } + + break; + } + } + } + } + + base.OnSpeech( e ); + } + + public override void AddCustomContextEntries( Mobile from, List list ) + { + if ( from.Alive) + list.Add( new OpenBankEntry( from, this ) ); + + base.AddCustomContextEntries( from, list ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/BaseEscortable.cs b/Scripts/Mobiles/Townfolk/BaseEscortable.cs new file mode 100644 index 0000000..a3e63a4 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/BaseEscortable.cs @@ -0,0 +1,780 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; +using Server.ContextMenus; +using EDI = Server.Mobiles.EscortDestinationInfo; +using Server.Engines.MLQuests; +using Server.Engines.MLQuests.Definitions; +using Server.Engines.MLQuests.Objectives; + +namespace Server.Mobiles +{ + public class BaseEscortable : BaseCreature + { + public static readonly TimeSpan EscortDelay = TimeSpan.FromMinutes(5.0); + public static readonly TimeSpan AbandonDelay = MLQuestSystem.Enabled ? TimeSpan.FromMinutes(1.0) : TimeSpan.FromMinutes(2.0); + public static readonly TimeSpan DeleteTime = MLQuestSystem.Enabled ? TimeSpan.FromSeconds(100) : TimeSpan.FromSeconds(30); + + public override bool StaticMLQuester { get { return false; } } // Suppress automatic quest registration on creation/deserialization + + private MLQuest m_MLQuest; + + protected override List ConstructQuestList() + { + if (m_MLQuest == null) + { + Region reg = Region; + Type[] list = reg.IsPartOf("Haven Island") ? m_MLQuestTypesNH : m_MLQuestTypes; + + int randomIdx = Utility.Random(list.Length); + + for (int i = 0; i < list.Length; ++i) + { + Type questType = list[randomIdx]; + + MLQuest quest = MLQuestSystem.FindQuest(questType); + + if (quest != null) + { + bool okay = true; + + foreach (BaseObjective obj in quest.Objectives) + { + if (obj is EscortObjective && ((EscortObjective)obj).Destination.Contains(reg)) + { + okay = false; // We're already there! + break; + } + } + + if (okay) + { + m_MLQuest = quest; + break; + } + } + else if (MLQuestSystem.Debug) + { + Console.WriteLine("Warning: Escortable cannot be assigned quest type '{0}', it is not registered", questType.Name); + } + + randomIdx = (randomIdx + 1) % list.Length; + } + + if (m_MLQuest == null) + { + if (MLQuestSystem.Debug) + Console.WriteLine("Warning: No suitable quest found for escort {0}", Serial); + + return null; + } + } + + List result = new List(); + result.Add(m_MLQuest); + + return result; + } + + public override bool CanShout { get { return (!Controlled && !IsBeingDeleted); } } + + public override void Shout(PlayerMobile pm) + { + /* + * 1072301 - You there! Care to hear how to earn some easy gold? + * 1072302 - Adventurer! I have an offer for you. + * 1072303 - Wait! I have an opportunity for you to make some gold! + */ + MLQuestSystem.Tell(this, pm, Utility.Random(1072301, 3)); + } + + private EDI m_Destination; + private string m_DestinationString; + + private DateTime m_DeleteTime; + private Timer m_DeleteTimer; + + private bool m_DeleteCorpse = false; + + public bool IsBeingDeleted + { + get { return (m_DeleteTimer != null); } + } + + public override bool Commandable { get { return false; } } // Our master cannot boss us around! + public override bool DeleteCorpseOnDeath { get { return m_DeleteCorpse; } } + + + [CommandProperty(AccessLevel.GameMaster)] + public string Destination + { + get { return m_Destination == null ? null : m_Destination.Name; } + set { m_DestinationString = value; m_Destination = EDI.Find(value); } + } + + // Classic list + // Used when: !MLQuestSystem.Enabled && !Core.ML + private static string[] m_TownNames = new string[] + { + "Cove", "Britain", "Jhelom", + "Minoc", "Ocllo", "Trinsic", + "Vesper", "Yew", "Skara Brae", + "Nujel'm", "Moonglow", "Magincia" + }; + + // ML list, pre-ML quest system + // Used when: !MLQuestSystem.Enabled && Core.ML + private static string[] m_MLTownNames = new string[] + { + "Cove", "Serpent's Hold", "Jhelom", + "Nujel'm" + }; + + // ML quest system general list + // Used when: MLQuestSystem.Enabled && !Region.IsPartOf( "Haven Island" ) + private static Type[] m_MLQuestTypes = + { + typeof( EscortToYew ), + typeof( EscortToVesper ), + typeof( EscortToTrinsic ), + typeof( EscortToSkaraBrae ), + typeof( EscortToSerpentsHold ), + typeof( EscortToNujelm ), + typeof( EscortToMoonglow ), + typeof( EscortToMinoc ), + typeof( EscortToMagincia ), + typeof( EscortToJhelom ), + typeof( EscortToCove ), + typeof( EscortToBritain ) + // Ocllo was removed in pub 56 + //typeof( EscortToOcllo ) + }; + + // ML quest system New Haven list + // Used when: MLQuestSystem.Enabled && Region.IsPartOf( "Haven Island" ) + private static Type[] m_MLQuestTypesNH = + { + typeof( EscortToNHAlchemist ), + typeof( EscortToNHBard ), + typeof( EscortToNHWarrior ), + typeof( EscortToNHTailor ), + typeof( EscortToNHCarpenter ), + typeof( EscortToNHMapmaker ), + typeof( EscortToNHMage ), + typeof( EscortToNHInn ), + // Farm destination was removed + //typeof( EscortToNHFarm ), + typeof( EscortToNHDocks ), + typeof( EscortToNHBowyer ), + typeof( EscortToNHBank ) + }; + + [Constructable] + public BaseEscortable() + : base(AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0) + { + InitBody(); + InitOutfit(); + + Fame = 200; + Karma = 4000; + } + + public virtual void InitBody() + { + SetStr(90, 100); + SetDex(90, 100); + SetInt(15, 25); + + Hue = Utility.RandomSkinHue(); + + if (Female = Utility.RandomBool()) + { + Body = 401; + Name = NameList.RandomName("female"); + } + else + { + Body = 400; + Name = NameList.RandomName("male"); + } + } + + public virtual void InitOutfit() + { + AddItem(new FancyShirt(Utility.RandomNeutralHue())); + AddItem(new ShortPants(Utility.RandomNeutralHue())); + AddItem(new Boots(Utility.RandomNeutralHue())); + + Utility.AssignRandomHair(this); + + //PackGold(200, 250); + PackGold(5, 25); // Scriptiz : pour �viter le farm des base escortables pour se faire de l'or + } + + public virtual bool SayDestinationTo(Mobile m) + { + EDI dest = GetDestination(); + + if (dest == null || !m.Alive) + return false; + + Mobile escorter = GetEscorter(); + + if (escorter == null) + { + Say("Je cherche � me rendre � {0},m'y am�nerez-vous?", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name); + return true; + } + else if (escorter == m) + { + Say("Allons! l'or sera v�tre une fois arriv�s � {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name); + return true; + } + + return false; + } + + private static Hashtable m_EscortTable = new Hashtable(); + + public static Hashtable EscortTable + { + get { return m_EscortTable; } + } + + public virtual bool AcceptEscorter(Mobile m) + { + EDI dest = GetDestination(); + + if (dest == null) + return false; + + Mobile escorter = GetEscorter(); + + if (escorter != null || !m.Alive) + return false; + + BaseEscortable escortable = (BaseEscortable)m_EscortTable[m]; + + if (escortable != null && !escortable.Deleted && escortable.GetEscorter() == m) + { + Say("H�las, vous �tes d�j� accompagn�s."); + return false; + } + else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + EscortDelay) >= DateTime.Now) + { + int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + EscortDelay) - DateTime.Now).TotalMinutes); + + Say("Vous devez vous reposer {0} minute{1} avant que nous partions.", minutes, minutes == 1 ? "" : "s"); + return false; + } + else if (SetControlMaster(m)) + { + m_LastSeenEscorter = DateTime.Now; + + if (m is PlayerMobile) + ((PlayerMobile)m).LastEscortTime = DateTime.Now; + + Say("Allons! l'or sera v�tre une fois arriv�s � {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name); + m_EscortTable[m] = this; + StartFollow(); + return true; + } + + return false; + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (MLQuestSystem.Enabled) + return false; + + if (from.InRange(this.Location, 3)) + return true; + + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + EDI dest = GetDestination(); + + if (dest != null && !e.Handled && e.Mobile.InRange(this.Location, 3)) + { + if (e.HasKeyword(0x1D)) // *destination* + e.Handled = SayDestinationTo(e.Mobile); + else if (e.HasKeyword(0x1E)) // *i will take thee* + e.Handled = AcceptEscorter(e.Mobile); + } + } + + public override void OnAfterDelete() + { + if (m_DeleteTimer != null) + m_DeleteTimer.Stop(); + + m_DeleteTimer = null; + + base.OnAfterDelete(); + } + + public override void OnThink() + { + base.OnThink(); + CheckAtDestination(); + } + + protected override bool OnMove(Direction d) + { + if (!base.OnMove(d)) + return false; + + CheckAtDestination(); + + return true; + } + + // TODO: Pre-ML methods below, might be mergeable with the ML methods in EscortObjective + + public virtual void StartFollow() + { + StartFollow(GetEscorter()); + } + + public virtual void StartFollow(Mobile escorter) + { + if (escorter == null) + return; + + ActiveSpeed = 0.1; + PassiveSpeed = 0.2; + + ControlOrder = OrderType.Follow; + ControlTarget = escorter; + + if ((IsPrisoner == true) && (CantWalk == true)) + { + CantWalk = false; + } + CurrentSpeed = 0.1; + } + + public virtual void StopFollow() + { + ActiveSpeed = 0.2; + PassiveSpeed = 1.0; + + ControlOrder = OrderType.None; + ControlTarget = null; + + CurrentSpeed = 1.0; + } + + private DateTime m_LastSeenEscorter; + + public virtual Mobile GetEscorter() + { + if (!Controlled) + return null; + + Mobile master = ControlMaster; + + if (MLQuestSystem.Enabled || master == null) + return master; + + if (master.Deleted || master.Map != this.Map || !master.InRange(Location, 30) || !master.Alive) + { + StopFollow(); + + TimeSpan lastSeenDelay = DateTime.Now - m_LastSeenEscorter; + + if (lastSeenDelay >= AbandonDelay) + { + master.SendLocalizedMessage(1042473); // You have lost the person you were escorting. + Say(1005653); // Hmmm. I seem to have lost my master. + + SetControlMaster(null); + m_EscortTable.Remove(master); + + Timer.DelayCall(TimeSpan.FromSeconds(5.0), new TimerCallback(Delete)); + return null; + } + else + { + ControlOrder = OrderType.Stay; + return master; + } + } + + if (ControlOrder != OrderType.Follow) + StartFollow(master); + + m_LastSeenEscorter = DateTime.Now; + return master; + } + + public virtual void BeginDelete() + { + if (m_DeleteTimer != null) + m_DeleteTimer.Stop(); + + m_DeleteTime = DateTime.Now + DeleteTime; + + m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.Now); + m_DeleteTimer.Start(); + } + + public virtual bool CheckAtDestination() + { + if (MLQuestSystem.Enabled) + return false; + + EDI dest = GetDestination(); + + if (dest == null) + return false; + + Mobile escorter = GetEscorter(); + + if (escorter == null) + return false; + + if (dest.Contains(Location)) + { + Say("Nous sommes arriv�s, je vous remercie {0}! Je n'ai plus besoin de vos services d�sormais. Voici votre or", escorter.Name); // We have arrived! I thank thee, ~1_PLAYER_NAME~! I have no further need of thy services. Here is thy pay. + + // not going anywhere + m_Destination = null; + m_DestinationString = null; + + Container cont = escorter.Backpack; + + if (cont == null) + cont = escorter.BankBox; + + Gold gold = new Gold(500, 1000); + + if (!cont.TryDropItem(escorter, gold, false)) + gold.MoveToWorld(escorter.Location, escorter.Map); + + StopFollow(); + SetControlMaster(null); + m_EscortTable.Remove(escorter); + BeginDelete(); + + Misc.Titles.AwardFame(escorter, 10, true); + + bool gainedPath = false; + + PlayerMobile pm = escorter as PlayerMobile; + + if (pm != null) + { + if (pm.CompassionGains > 0 && DateTime.Now > pm.NextCompassionDay) + { + pm.NextCompassionDay = DateTime.MinValue; + pm.CompassionGains = 0; + } + + if (pm.CompassionGains >= 5) // have already gained 5 times in one day, can gain no more + { + pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again. + } + else if (VirtueHelper.Award(pm, VirtueName.Compassion, this.IsPrisoner ? 400 : 200, ref gainedPath)) + { + if (gainedPath) + pm.SendLocalizedMessage(1053005); // You have achieved a path in compassion! + else + pm.SendLocalizedMessage(1053002); // You have gained in compassion. + + pm.NextCompassionDay = DateTime.Now + TimeSpan.FromDays(1.0); // in one day CompassionGains gets reset to 0 + ++pm.CompassionGains; + + if (pm.CompassionGains >= 5) + pm.SendLocalizedMessage(1053004); // You must wait about a day before you can gain in compassion again. + } + else + { + pm.SendLocalizedMessage(1053003); // You have achieved the highest path of compassion and can no longer gain any further. + } + } + + return true; + } + + return false; + } + + public override bool OnBeforeDeath() + { + m_DeleteCorpse = (Controlled || IsBeingDeleted); + + return base.OnBeforeDeath(); + } + + public BaseEscortable(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + EDI dest = GetDestination(); + + writer.Write(dest != null); + + if (dest != null) + writer.Write(dest.Name); + + writer.Write(m_DeleteTimer != null); + + if (m_DeleteTimer != null) + writer.WriteDeltaTime(m_DeleteTime); + + MLQuestSystem.WriteQuestRef(writer, StaticMLQuester ? null : m_MLQuest); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (reader.ReadBool()) + m_DestinationString = reader.ReadString(); // NOTE: We cannot EDI.Find here, regions have not yet been loaded :-( + + if (reader.ReadBool()) + { + m_DeleteTime = reader.ReadDeltaTime(); + m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.Now); + m_DeleteTimer.Start(); + } + + if (version >= 1) + { + MLQuest quest = MLQuestSystem.ReadQuestRef(reader); + + if (MLQuestSystem.Enabled && quest != null && !StaticMLQuester) + m_MLQuest = quest; + } + } + + public override bool CanBeRenamedBy(Mobile from) + { + return (from.AccessLevel >= AccessLevel.GameMaster); + } + + public override void AddCustomContextEntries(Mobile from, List list) + { + if (from.Alive) + { + Mobile escorter = GetEscorter(); + + if (!MLQuestSystem.Enabled && GetDestination() != null) + { + if (escorter == null || escorter == from) + list.Add(new AskDestinationEntry(this, from)); + + if (escorter == null) + list.Add(new AcceptEscortEntry(this, from)); + } + + if (escorter == from) + list.Add(new AbandonEscortEntry(this, from)); + } + + base.AddCustomContextEntries(from, list); + } + + public virtual string[] GetPossibleDestinations() + { + if (!Core.ML) + return m_TownNames; + else + return m_MLTownNames; + } + + public virtual string PickRandomDestination() + { + if (Map.Felucca.Regions.Count == 0 || Map == null || Map == Map.Internal || Location == Point3D.Zero) + return null; // Not yet fully initialized + + string[] possible = GetPossibleDestinations(); + string picked = null; + + while (picked == null) + { + picked = possible[Utility.Random(possible.Length)]; + EDI test = EDI.Find(picked); + + if (test != null && test.Contains(Location)) + picked = null; + } + + return picked; + } + + public EDI GetDestination() + { + if (MLQuestSystem.Enabled) + return null; + + if (m_DestinationString == null && m_DeleteTimer == null) + m_DestinationString = PickRandomDestination(); + + if (m_Destination != null && m_Destination.Name == m_DestinationString) + return m_Destination; + + if (Map.Felucca.Regions.Count > 0) + return (m_Destination = EDI.Find(m_DestinationString)); + + return (m_Destination = null); + } + + private class DeleteTimer : Timer + { + private Mobile m_Mobile; + + public DeleteTimer(Mobile m, TimeSpan delay) + : base(delay) + { + m_Mobile = m; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Mobile.Delete(); + } + } + } + + public class EscortDestinationInfo + { + private string m_Name; + private Region m_Region; + //private Rectangle2D[] m_Bounds; + + public string Name + { + get { return m_Name; } + } + + public Region Region + { + get { return m_Region; } + } + + /*public Rectangle2D[] Bounds + { + get{ return m_Bounds; } + }*/ + + public bool Contains(Point3D p) + { + return m_Region.Contains(p); + } + + public EscortDestinationInfo(string name, Region region) + { + m_Name = name; + m_Region = region; + } + + private static Hashtable m_Table; + + public static void LoadTable() + { + ICollection list = Map.Felucca.Regions.Values; + + if (list.Count == 0) + return; + + m_Table = new Hashtable(); + + foreach (Region r in list) + { + if (r.Name == null) + continue; + + if (r is Regions.DungeonRegion || r is Regions.TownRegion) + m_Table[r.Name] = new EscortDestinationInfo(r.Name, r); + } + } + + public static EDI Find(string name) + { + if (m_Table == null) + LoadTable(); + + if (name == null || m_Table == null) + return null; + + return (EscortDestinationInfo)m_Table[name]; + } + } + + public class AskDestinationEntry : ContextMenuEntry + { + private BaseEscortable m_Mobile; + private Mobile m_From; + + public AskDestinationEntry(BaseEscortable m, Mobile from) + : base(6100, 3) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.SayDestinationTo(m_From); + } + } + + public class AcceptEscortEntry : ContextMenuEntry + { + private BaseEscortable m_Mobile; + private Mobile m_From; + + public AcceptEscortEntry(BaseEscortable m, Mobile from) + : base(6101, 3) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.AcceptEscorter(m_From); + } + } + + public class AbandonEscortEntry : ContextMenuEntry + { + private BaseEscortable m_Mobile; + private Mobile m_From; + + public AbandonEscortEntry(BaseEscortable m, Mobile from) + : base(6102, 3) + { + m_Mobile = m; + m_From = from; + } + + public override void OnClick() + { + m_Mobile.Delete(); // OSI just seems to delete instantly + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/BrideGroom.cs b/Scripts/Mobiles/Townfolk/BrideGroom.cs new file mode 100644 index 0000000..8348f84 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/BrideGroom.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class BrideGroom : BaseEscortable + { + [Constructable] + public BrideGroom() + { + if ( Female ) + Title = "la Mariee"; + else + Title = "le Marie"; + + } + + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display 'the groom' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + if ( Female ) + AddItem( new FancyDress() ); + else + AddItem( new FancyShirt() ); + + int lowHue = GetRandomHue(); + + AddItem( new LongPants( lowHue ) ); + + if ( Female ) + AddItem( new Shoes( lowHue ) ); + else + AddItem( new Boots( lowHue ) ); + + + + if( Utility.RandomBool() ) + HairItemID = 0x203B; + else + HairItemID = 0x203C; + + HairHue = this.Race.RandomHairHue(); + + PackGold( 200, 250 ); + } + + public BrideGroom( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/EscortableMage.cs b/Scripts/Mobiles/Townfolk/EscortableMage.cs new file mode 100644 index 0000000..61d0e93 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/EscortableMage.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class EscortableMage : BaseEscortable + { + [Constructable] + public EscortableMage() + { + Title = (Female? "la Mage" : "le Mage"); + + SetSkill( SkillName.EvalInt, 80.0, 100.0 ); + SetSkill( SkillName.Inscribe, 80.0, 100.0 ); + SetSkill( SkillName.Magery, 80.0, 100.0 ); + SetSkill( SkillName.Meditation, 80.0, 100.0 ); + SetSkill( SkillName.MagicResist, 80.0, 100.0 ); + } + + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display 'the mage' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 5 ) ) + { + default: + case 0: return Utility.RandomBlueHue(); + case 1: return Utility.RandomGreenHue(); + case 2: return Utility.RandomRedHue(); + case 3: return Utility.RandomYellowHue(); + case 4: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + AddItem( new Robe( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ShortPants( lowHue ) ); + + if ( Female ) + AddItem( new ThighBoots( lowHue ) ); + else + AddItem( new Boots( lowHue ) ); + + Utility.AssignRandomHair( this ); + + PackGold( 200, 250 ); + } + + public EscortableMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Gypsy.cs b/Scripts/Mobiles/Townfolk/Gypsy.cs new file mode 100644 index 0000000..b90cbff --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Gypsy.cs @@ -0,0 +1,82 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class Gypsy : BaseCreature + { + + + [Constructable] + public Gypsy() + : base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + InitStats( 31, 41, 51 ); + + SpeechHue = Utility.RandomDyedHue(); + + SetSkill( SkillName.Cooking, 65, 88 ); + SetSkill( SkillName.Snooping, 65, 88 ); + SetSkill( SkillName.Stealing, 65, 88 ); + + Hue = Utility.RandomSkinHue(); + + if( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + AddItem( new Kilt( Utility.RandomDyedHue() ) ); + AddItem( new Shirt( Utility.RandomDyedHue() ) ); + AddItem( new ThighBoots() ); + Title = "la Gitane"; + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + AddItem( new Shirt( Utility.RandomDyedHue() ) ); + AddItem( new Sandals() ); + Title = "le Gitan"; + } + + AddItem( new Bandana( Utility.RandomDyedHue() ) ); + AddItem( new Dagger() ); + + Utility.AssignRandomHair( this ); + + Container pack = new Backpack(); + + pack.DropItem( new Gold( 250, 300 ) ); + + pack.Movable = false; + + AddItem( pack ); + } + + + public override bool CanTeach { get { return true; } } + public override bool ClickTitle { get { return false; } } + + public Gypsy( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/HarborMaster.cs b/Scripts/Mobiles/Townfolk/HarborMaster.cs new file mode 100644 index 0000000..738df3d --- /dev/null +++ b/Scripts/Mobiles/Townfolk/HarborMaster.cs @@ -0,0 +1,76 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class HarborMaster : BaseCreature + { + public override bool CanTeach { get { return false; } } + + [Constructable] + public HarborMaster() + : base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + InitStats( 31, 41, 51 ); + + SetSkill( SkillName.Mining, 36, 68 ); + + + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + Blessed = true; + + + if( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + Title = "la Maitresse du Port"; + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + Title = "le Maitre du Port"; + } + AddItem( new Shirt( Utility.RandomDyedHue() ) ); + AddItem( new Boots() ); + AddItem( new LongPants( Utility.RandomNeutralHue() ) ); + AddItem( new QuarterStaff() ); + + Utility.AssignRandomHair( this ); + + Container pack = new Backpack(); + + pack.DropItem( new Gold( 250, 300 ) ); + + pack.Movable = false; + + AddItem( pack ); + } + + public override bool ClickTitle { get { return false; } } + + + public HarborMaster( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/Merchant.cs b/Scripts/Mobiles/Townfolk/Merchant.cs new file mode 100644 index 0000000..0f80c98 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Merchant.cs @@ -0,0 +1,85 @@ +using System; +using Server; +using Server.Items; +using EDI=Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class Merchant : BaseEscortable + { + [Constructable] + public Merchant() + { + Title = (Female ?"la Marchande" : "le Marchand"); + SetSkill( SkillName.ItemID, 55.0, 78.0 ); + SetSkill( SkillName.ArmsLore, 55, 78 ); + } + + public override bool CanTeach { get { return true; } } + public override bool ClickTitle { get { return false; } } // Do not display 'the merchant' when single-clicking + + private static int GetRandomHue() + { + switch( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + + } + + public override void InitOutfit() + { + if( Female ) + AddItem( new PlainDress() ); + else + AddItem( new Shirt( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ThighBoots() ); + + if( Female ) + AddItem( new FancyDress( lowHue ) ); + else + AddItem( new FancyShirt( lowHue ) ); + AddItem( new LongPants( lowHue ) ); + + if( !Female ) + AddItem( new BodySash( lowHue ) ); + + + + //if ( !Female ) + //AddItem( new Longsword() ); + + Utility.AssignRandomHair( this ); + + PackGold( 200, 250 ); + } + + public Merchant( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Messenger.cs b/Scripts/Mobiles/Townfolk/Messenger.cs new file mode 100644 index 0000000..c5a66d8 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Messenger.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class Messenger : BaseEscortable + { + [Constructable] + public Messenger() + { + Title = (Female? "la Messagere": "le Messager"); + + } + + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display 'the messenger' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + if ( Female ) + AddItem( new PlainDress() ); + else + AddItem( new Shirt( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ShortPants( lowHue ) ); + + if ( Female ) + AddItem( new Boots( lowHue ) ); + else + AddItem( new Shoes( lowHue ) ); + + //if ( !Female ) + //AddItem( new BodySash( lowHue ) ); + + //AddItem( new Cloak( GetRandomHue() ) ); + + //if ( !Female ) + //AddItem( new Longsword() ); + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new ShortHair( Utility.RandomHairHue() ) ); break; + case 1: AddItem( new TwoPigTails( Utility.RandomHairHue() ) ); break; + case 2: AddItem( new ReceedingHair( Utility.RandomHairHue() ) ); break; + case 3: AddItem( new KrisnaHair( Utility.RandomHairHue() ) ); break; + } + + PackGold( 200, 250 ); + } + + public Messenger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Minter.cs b/Scripts/Mobiles/Townfolk/Minter.cs new file mode 100644 index 0000000..6d7c747 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Minter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; + +namespace Server.Mobiles +{ + public class Minter : Banker + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.MerchantsGuild; } } + + [Constructable] + public Minter() + { + Title = (Female? "la Monnayeuse" : "le Monnayeur"); + } + + public Minter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Ninja.cs b/Scripts/Mobiles/Townfolk/Ninja.cs new file mode 100644 index 0000000..6ecaacd --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Ninja.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Ninja : BaseCreature + { + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public Ninja() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Title = (Female? "la Ninja": "le Ninja"); + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.Fencing, 64.0, 80.0 ); + SetSkill( SkillName.Macing, 64.0, 80.0 ); + SetSkill( SkillName.Ninjitsu, 60.0, 80.0 ); + SetSkill( SkillName.Parry, 64.0, 80.0 ); + SetSkill( SkillName.Tactics, 64.0, 85.0 ); + SetSkill( SkillName.Swords, 64.0, 85.0 ); + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + + if ( !Female ) + AddItem( new LeatherNinjaHood() ); + + AddItem( new LeatherNinjaPants() ); + AddItem( new LeatherNinjaBelt() ); + AddItem( new LeatherNinjaJacket() ); + AddItem( new NinjaTabi() ); + + int hairHue = Utility.RandomNondyedHue(); + + + Utility.AssignRandomHair( this, hairHue ); + + if( Utility.Random( 7 ) != 0 ) + Utility.AssignRandomFacialHair( this, hairHue ); + + PackGold( 250, 300 ); + } + + public Ninja( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/Noble.cs b/Scripts/Mobiles/Townfolk/Noble.cs new file mode 100644 index 0000000..0e5dc98 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Noble.cs @@ -0,0 +1,84 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class Noble : BaseEscortable + { + [Constructable] + public Noble() + { + Title = (Female ? "la Noble" : "le Noble"); + + SetSkill( SkillName.Parry, 80.0, 100.0 ); + SetSkill( SkillName.Swords, 80.0, 100.0 ); + SetSkill( SkillName.Tactics, 80.0, 100.0 ); + } + + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display 'the noble' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + if ( Female ) + AddItem( new FancyDress() ); + else + AddItem( new FancyShirt( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ShortPants( lowHue ) ); + + if ( Female ) + AddItem( new ThighBoots( lowHue ) ); + else + AddItem( new Boots( lowHue ) ); + + if ( !Female ) + AddItem( new BodySash( lowHue ) ); + + AddItem( new Cloak( GetRandomHue() ) ); + + if ( !Female ) + AddItem( new Longsword() ); + + Utility.AssignRandomHair( this ); + + PackGold( 200, 250 ); + } + + public Noble( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Peasant.cs b/Scripts/Mobiles/Townfolk/Peasant.cs new file mode 100644 index 0000000..e7e8acc --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Peasant.cs @@ -0,0 +1,81 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class Peasant : BaseEscortable + { + [Constructable] + public Peasant() + { + Title = (Female ? "la Paysanne" : "le Paysan"); + + } + + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } // Do not display 'the peasant' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + if ( Female ) + AddItem( new PlainDress() ); + else + AddItem( new Shirt( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ShortPants( lowHue ) ); + + if ( Female ) + AddItem( new Boots( lowHue ) ); + else + AddItem( new Shoes( lowHue ) ); + + //if ( !Female ) + //AddItem( new BodySash( lowHue ) ); + + //AddItem( new Cloak( GetRandomHue() ) ); + + //if ( !Female ) + //AddItem( new Longsword() ); + + Utility.AssignRandomHair( this ); + + PackGold( 200, 250 ); + } + + public Peasant( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/Prisoner.cs b/Scripts/Mobiles/Townfolk/Prisoner.cs new file mode 100644 index 0000000..82aae22 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Prisoner.cs @@ -0,0 +1,83 @@ +using System; +using Server.Items; +using Server.Engines.MLQuests; + +namespace Server.Mobiles.Townfolk +{ + public class Prisoner : BaseEscortable + { + [Constructable] + public Prisoner() + { + Title = Female ? "the noblewoman" : "the nobleman"; + + CantWalk = true; + IsPrisoner = true; + } + + public override bool CanTeach { get { return true; } } + public override bool ClickTitle { get { return false; } } + + public override void InitOutfit() + { + if ( Female ) + { + AddItem( new FancyDress( Utility.RandomNondyedHue() ) ); + } + else + { + AddItem( new FancyShirt( Utility.RandomNondyedHue() ) ); + AddItem( new LongPants( Utility.RandomNondyedHue() ) ); + } + + if ( Utility.RandomBool() ) + AddItem( new Boots() ); + else + AddItem( new ThighBoots() ); + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + } + + public override void Shout( PlayerMobile pm ) + { + /* + * 502261 - HELP! + * 502262 - Help me! + * 502263 - Canst thou aid me?! + * 502264 - Help a poor prisoner! + * 502265 - Help! Please! + * 502266 - Aaah! Help me! + * 502267 - Go and get some help! + */ + MLQuestSystem.Tell( this, pm, Utility.Random( 502261, 7 ) ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( CantWalk && InRange( m, 1 ) && !InRange( oldLocation, 1 ) && ( !m.Hidden || m.AccessLevel == AccessLevel.Player ) ) + Say( 502268 ); // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. + } + + public Prisoner( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/Samurai.cs b/Scripts/Mobiles/Townfolk/Samurai.cs new file mode 100644 index 0000000..2f3feb0 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Samurai.cs @@ -0,0 +1,96 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Samurai : BaseCreature + { + public override bool CanTeach{ get{ return true; } } + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public Samurai() : base( AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + + InitStats( 100, 100, 25 ); + + SetSkill( SkillName.ArmsLore, 64.0, 80.0 ); + SetSkill( SkillName.Bushido, 64.0, 85.0 ); + SetSkill( SkillName.Parry, 64.0, 80.0 ); + SetSkill( SkillName.Swords, 64.0, 85.0 ); + + SpeechHue = Utility.RandomDyedHue(); + + Hue = Utility.RandomSkinHue(); + + if ( Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + Title = "la Samurai"; + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + Title = "le Samurai"; + } + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new Lajatang() ); break; + case 1: AddItem( new Wakizashi() ); break; + case 2: AddItem( new NoDachi() ); break; + } + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new LeatherSuneate() ); break; + case 1: AddItem( new PlateSuneate() ); break; + case 2: AddItem( new StuddedHaidate() ); break; + } + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new LeatherJingasa() ); break; + case 1: AddItem( new ChainHatsuburi() ); break; + case 2: AddItem( new HeavyPlateJingasa() ); break; + case 3: AddItem( new DecorativePlateKabuto() ); break; + } + + AddItem( new LeatherDo() ); + AddItem( new LeatherHiroSode() ); + AddItem( new SamuraiTabi( Utility.RandomNondyedHue() ) ); // TODO: Hue + + int hairHue = Utility.RandomNondyedHue(); + + + Utility.AssignRandomHair( this, hairHue ); + + if( Utility.Random( 7 ) != 0 ) + Utility.AssignRandomFacialHair( this, hairHue ); + + PackGold( 250, 300 ); + } + + public Samurai( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/Sculptor.cs b/Scripts/Mobiles/Townfolk/Sculptor.cs new file mode 100644 index 0000000..93c4959 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/Sculptor.cs @@ -0,0 +1,71 @@ +using System; +using Server.Items; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class Sculptor : BaseCreature + { + [Constructable] + public Sculptor() + : base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + InitStats( 31, 41, 51 ); + + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + AddItem( new Kilt( Utility.RandomNeutralHue() ) ); + Title = "la Sculptrice"; + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + AddItem( new LongPants( Utility.RandomNeutralHue() ) ); + Title = "le Sculpteur"; + } + + + + AddItem( new Doublet( Utility.RandomNeutralHue() ) ); + AddItem( new HalfApron() ); + + Utility.AssignRandomHair( this ); + + Container pack = new Backpack(); + + pack.DropItem( new Gold( 250, 300 ) ); + + pack.Movable = false; + + AddItem( pack ); + } + + public override bool ClickTitle { get { return false; } } + + public Sculptor( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs b/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs new file mode 100644 index 0000000..fd56b97 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/SeekerOfAdventure.cs @@ -0,0 +1,99 @@ +using System; +using Server; +using Server.Items; +using EDI = Server.Mobiles.EscortDestinationInfo; + +namespace Server.Mobiles +{ + public class SeekerOfAdventure : BaseEscortable + { + private static string[] m_Dungeons = new string[] + { + "Covetous", "Deceit", "Despise", + "Destard", "Hythloth", "Shame", // Old Code for Pre-ML shards. + "Wrong" + }; + + private static string[] m_MLDestinations = new string[] + { + "Cove", "Serpent's Hold", "Jhelom", // ML List + "Nujel'm" + }; + + public override string[] GetPossibleDestinations() + { + if ( Core.ML ) + return m_MLDestinations; + else + return m_Dungeons; + } + + [Constructable] + public SeekerOfAdventure() + { + Title = (Female ? "l'Aventiere" : "l'Aventurier"); + } + + public override bool ClickTitle{ get{ return false; } } // Do not display 'the seeker of adventure' when single-clicking + + private static int GetRandomHue() + { + switch ( Utility.Random( 6 ) ) + { + default: + case 0: return 0; + case 1: return Utility.RandomBlueHue(); + case 2: return Utility.RandomGreenHue(); + case 3: return Utility.RandomRedHue(); + case 4: return Utility.RandomYellowHue(); + case 5: return Utility.RandomNeutralHue(); + } + } + + public override void InitOutfit() + { + if ( Female ) + AddItem( new FancyDress( GetRandomHue() ) ); + else + AddItem( new FancyShirt( GetRandomHue() ) ); + + int lowHue = GetRandomHue(); + + AddItem( new ShortPants( lowHue ) ); + + if ( Female ) + AddItem( new ThighBoots( lowHue ) ); + else + AddItem( new Boots( lowHue ) ); + + if ( !Female ) + AddItem( new BodySash( lowHue ) ); + + AddItem( new Cloak( GetRandomHue() ) ); + + AddItem( new Longsword() ); + + Utility.AssignRandomHair( this ); + + PackGold( 100, 150 ); + } + + public SeekerOfAdventure( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Townfolk/TownCrier.cs b/Scripts/Mobiles/Townfolk/TownCrier.cs new file mode 100644 index 0000000..140ba79 --- /dev/null +++ b/Scripts/Mobiles/Townfolk/TownCrier.cs @@ -0,0 +1,570 @@ +using System; +using System.Text; +using System.Collections.Generic; +using Server; +using Server.Prompts; +using Server.Gumps; +using Server.Network; +using Server.Items; +using Server.Misc; +using Server.Commands; + +namespace Server.Mobiles +{ + public interface ITownCrierEntryList + { + List Entries{ get; } + TownCrierEntry GetRandomEntry(); + TownCrierEntry AddEntry( string[] lines, TimeSpan duration ); + void RemoveEntry( TownCrierEntry entry ); + } + + public class GlobalTownCrierEntryList : ITownCrierEntryList + { + private static GlobalTownCrierEntryList m_Instance; + + public static void Initialize() + { + CommandSystem.Register( "TownCriers", AccessLevel.GameMaster, new CommandEventHandler( TownCriers_OnCommand ) ); + } + + [Usage( "TownCriers" )] + [Description( "Manages the global town crier list." )] + public static void TownCriers_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendGump( new TownCrierGump( e.Mobile, Instance ) ); + } + + public static GlobalTownCrierEntryList Instance + { + get + { + if ( m_Instance == null ) + m_Instance = new GlobalTownCrierEntryList(); + + return m_Instance; + } + } + + public bool IsEmpty{ get{ return ( m_Entries == null || m_Entries.Count == 0 ); } } + + public GlobalTownCrierEntryList() + { + } + + private List m_Entries; + + public List Entries + { + get{ return m_Entries; } + } + + public TownCrierEntry GetRandomEntry() + { + if ( m_Entries == null || m_Entries.Count == 0 ) + return null; + + for ( int i = m_Entries.Count - 1; m_Entries != null && i >= 0; --i ) + { + if ( i >= m_Entries.Count ) + continue; + + TownCrierEntry tce = m_Entries[i]; + + if ( tce.Expired ) + RemoveEntry( tce ); + } + + if ( m_Entries == null || m_Entries.Count == 0 ) + return null; + + return m_Entries[Utility.Random( m_Entries.Count )]; + } + + public TownCrierEntry AddEntry( string[] lines, TimeSpan duration ) + { + if ( m_Entries == null ) + m_Entries = new List(); + + TownCrierEntry tce = new TownCrierEntry( lines, duration ); + + m_Entries.Add( tce ); + + List instances = TownCrier.Instances; + + for ( int i = 0; i < instances.Count; ++i ) + instances[i].ForceBeginAutoShout(); + + return tce; + } + + public void RemoveEntry( TownCrierEntry tce ) + { + if ( m_Entries == null ) + return; + + m_Entries.Remove( tce ); + + if ( m_Entries.Count == 0 ) + m_Entries = null; + } + } + + public class TownCrierEntry + { + private string[] m_Lines; + private DateTime m_ExpireTime; + + public string[] Lines{ get{ return m_Lines; } } + public DateTime ExpireTime{ get{ return m_ExpireTime; } } + public bool Expired{ get{ return ( DateTime.Now >= m_ExpireTime ); } } + + public TownCrierEntry( string[] lines, TimeSpan duration ) + { + m_Lines = lines; + + if ( duration < TimeSpan.Zero ) + duration = TimeSpan.Zero; + else if ( duration > TimeSpan.FromDays( 365.0 ) ) + duration = TimeSpan.FromDays( 365.0 ); + + m_ExpireTime = DateTime.Now + duration; + } + } + + public class TownCrierDurationPrompt : Prompt + { + private ITownCrierEntryList m_Owner; + + public TownCrierDurationPrompt( ITownCrierEntryList owner ) + { + m_Owner = owner; + } + + public override void OnResponse( Mobile from, string text ) + { + TimeSpan ts; + + if( !TimeSpan.TryParse( text, out ts ) ) + { + from.SendMessage( "Value was not properly formatted. Use: " ); + from.SendGump( new TownCrierGump( from, m_Owner ) ); + return; + } + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + from.SendMessage( "Duration set to: {0}", ts ); + from.SendMessage( "Enter the first line to shout:" ); + + from.Prompt = new TownCrierLinesPrompt( m_Owner, null, new List(), ts ); + } + + public override void OnCancel( Mobile from ) + { + from.SendLocalizedMessage( 502980 ); // Message entry cancelled. + from.SendGump( new TownCrierGump( from, m_Owner ) ); + } + } + + public class TownCrierLinesPrompt : Prompt + { + private ITownCrierEntryList m_Owner; + private TownCrierEntry m_Entry; + private List m_Lines; + private TimeSpan m_Duration; + + public TownCrierLinesPrompt( ITownCrierEntryList owner, TownCrierEntry entry, List lines, TimeSpan duration ) + { + m_Owner = owner; + m_Entry = entry; + m_Lines = lines; + m_Duration = duration; + } + + public override void OnResponse( Mobile from, string text ) + { + m_Lines.Add( text ); + + from.SendMessage( "Enter the next line to shout, or press if the message is finished." ); + from.Prompt = new TownCrierLinesPrompt( m_Owner, m_Entry, m_Lines, m_Duration ); + } + + public override void OnCancel( Mobile from ) + { + if ( m_Entry != null ) + m_Owner.RemoveEntry( m_Entry ); + + if ( m_Lines.Count > 0 ) + { + m_Owner.AddEntry( m_Lines.ToArray(), m_Duration ); + from.SendMessage( "Message has been set." ); + } + else + { + if ( m_Entry != null ) + from.SendMessage( "Message deleted." ); + else + from.SendLocalizedMessage( 502980 ); // Message entry cancelled. + } + + from.SendGump( new TownCrierGump( from, m_Owner ) ); + } + } + + public class TownCrierGump : Gump + { + private Mobile m_From; + private ITownCrierEntryList m_Owner; + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + m_From.SendMessage( "Enter the duration for the new message. Format: " ); + m_From.Prompt = new TownCrierDurationPrompt( m_Owner ); + } + else if ( info.ButtonID > 1 ) + { + List entries = m_Owner.Entries; + int index = info.ButtonID - 2; + + if ( entries != null && index < entries.Count ) + { + TownCrierEntry tce = entries[index]; + TimeSpan ts = tce.ExpireTime - DateTime.Now; + + if ( ts < TimeSpan.Zero ) + ts = TimeSpan.Zero; + + m_From.SendMessage( "Editing entry #{0}.", index + 1 ); + m_From.SendMessage( "Enter the first line to shout:" ); + m_From.Prompt = new TownCrierLinesPrompt( m_Owner, tce, new List(), ts ); + } + } + } + + public TownCrierGump( Mobile from, ITownCrierEntryList owner ) : base( 50, 50 ) + { + m_From = from; + m_Owner = owner; + + from.CloseGump( typeof( TownCrierGump ) ); + + AddPage( 0 ); + + List entries = owner.Entries; + + owner.GetRandomEntry(); // force expiration checks + + int count = 0; + + if ( entries != null ) + count = entries.Count; + + AddImageTiled( 0, 0, 300, 38 + (count == 0 ? 20 : (count * 85)), 0xA40 ); + AddAlphaRegion( 1, 1, 298, 36 + (count == 0 ? 20 : (count * 85)) ); + + AddHtml( 8, 8, 300 - 8 - 30, 20, "
TOWN CRIER MESSAGES
", false, false ); + + AddButton( 300 - 8 - 30, 8, 0xFAB, 0xFAD, 1, GumpButtonType.Reply, 0 ); + + if ( count == 0 ) + { + AddHtml( 8, 30, 284, 20, "The crier has no news.", false, false ); + } + else + { + for ( int i = 0; i < entries.Count; ++i ) + { + TownCrierEntry tce = (TownCrierEntry)entries[i]; + + TimeSpan toExpire = tce.ExpireTime - DateTime.Now; + + if ( toExpire < TimeSpan.Zero ) + toExpire = TimeSpan.Zero; + + StringBuilder sb = new StringBuilder(); + + sb.Append( "[Expires: " ); + + if ( toExpire.TotalHours >= 1 ) + { + sb.Append( (int)toExpire.TotalHours ); + sb.Append( ':' ); + sb.Append( toExpire.Minutes.ToString( "D2" ) ); + } + else + { + sb.Append( toExpire.Minutes ); + } + + sb.Append( ':' ); + sb.Append( toExpire.Seconds.ToString( "D2" ) ); + + sb.Append( "] " ); + + for ( int j = 0; j < tce.Lines.Length; ++j ) + { + if ( j > 0 ) + sb.Append( "
" ); + + sb.Append( tce.Lines[j] ); + } + + AddHtml( 8, 35 + (i * 85), 254, 80, sb.ToString(), true, true ); + + AddButton( 300 - 8 - 26, 35 + (i * 85), 0x15E1, 0x15E5, 2 + i, GumpButtonType.Reply, 0 ); + } + } + } + } + + public class TownCrier : Mobile, ITownCrierEntryList + { + private List m_Entries; + private Timer m_NewsTimer; + private Timer m_AutoShoutTimer; + + public List Entries + { + get{ return m_Entries; } + } + + public TownCrierEntry GetRandomEntry() + { + if ( m_Entries == null || m_Entries.Count == 0 ) + return GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + for ( int i = m_Entries.Count - 1; m_Entries != null && i >= 0; --i ) + { + if ( i >= m_Entries.Count ) + continue; + + TownCrierEntry tce = m_Entries[i]; + + if ( tce.Expired ) + RemoveEntry( tce ); + } + + if ( m_Entries == null || m_Entries.Count == 0 ) + return GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + TownCrierEntry entry = GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + if ( entry == null || Utility.RandomBool() ) + entry = m_Entries[Utility.Random( m_Entries.Count )]; + + return entry; + } + + public void ForceBeginAutoShout() + { + if ( m_AutoShoutTimer == null ) + m_AutoShoutTimer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( AutoShout_Callback ) ); + } + + public TownCrierEntry AddEntry( string[] lines, TimeSpan duration ) + { + if ( m_Entries == null ) + m_Entries = new List(); + + TownCrierEntry tce = new TownCrierEntry( lines, duration ); + + m_Entries.Add( tce ); + + if ( m_AutoShoutTimer == null ) + m_AutoShoutTimer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( AutoShout_Callback ) ); + + return tce; + } + + public void RemoveEntry( TownCrierEntry tce ) + { + if ( m_Entries == null ) + return; + + m_Entries.Remove( tce ); + + if ( m_Entries.Count == 0 ) + m_Entries = null; + + if ( m_Entries == null && GlobalTownCrierEntryList.Instance.IsEmpty ) + { + if ( m_AutoShoutTimer != null ) + m_AutoShoutTimer.Stop(); + + m_AutoShoutTimer = null; + } + } + + private void AutoShout_Callback() + { + TownCrierEntry tce = GetRandomEntry(); + + if ( tce == null ) + { + if ( m_AutoShoutTimer != null ) + m_AutoShoutTimer.Stop(); + + m_AutoShoutTimer = null; + } + else if ( m_NewsTimer == null ) + { + m_NewsTimer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( ShoutNews_Callback ), new object[]{ tce, 0 } ); + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 502976 ); // Hear ye! Hear ye! + } + } + + private void ShoutNews_Callback( object state ) + { + object[] states = (object[])state; + TownCrierEntry tce = (TownCrierEntry)states[0]; + int index = (int)states[1]; + + if ( index < 0 || index >= tce.Lines.Length ) + { + if ( m_NewsTimer != null ) + m_NewsTimer.Stop(); + + m_NewsTimer = null; + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, false, tce.Lines[index] ); + states[1] = index + 1; + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster ) + from.SendGump( new TownCrierGump( from, this ) ); + else + base.OnDoubleClick( from ); + } + + public override bool HandlesOnSpeech( Mobile from ) + { + return ( m_NewsTimer == null && from.Alive && InRange( from, 12 ) ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( m_NewsTimer == null && e.HasKeyword( 0x30 ) && e.Mobile.Alive && InRange( e.Mobile, 12 ) ) // *news* + { + Direction = GetDirectionTo( e.Mobile ); + + TownCrierEntry tce = GetRandomEntry(); + + if ( tce == null ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1005643 ); // I have no news at this time. + } + else + { + m_NewsTimer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( ShoutNews_Callback ), new object[]{ tce, 0 } ); + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 502978 ); // Some of the latest news! + } + } + } + + private static List m_Instances = new List(); + + public static List Instances + { + get{ return m_Instances; } + } + + [Constructable] + public TownCrier() + { + m_Instances.Add( this ); + + InitStats( 100, 100, 25 ); + + + Hue = Utility.RandomSkinHue(); + + if ( !Core.AOS ) + NameHue = 0x35; + + if ( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + Title = "la Crieuse"; + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + Title = "le H�raut"; + } + + AddItem( new FancyShirt( Utility.RandomBlueHue() ) ); + + Item skirt; + + switch ( Utility.Random( 2 ) ) + { + case 0: skirt = new Skirt(); break; + default: case 1: skirt = new Kilt(); break; + } + + skirt.Hue = Utility.RandomGreenHue(); + + AddItem( skirt ); + + AddItem( new FeatheredHat( Utility.RandomGreenHue() ) ); + + Item boots; + + switch ( Utility.Random( 2 ) ) + { + case 0: boots = new Boots(); break; + default: case 1: boots = new ThighBoots(); break; + } + + AddItem( boots ); + + Utility.AssignRandomHair( this ); + } + + public override bool CanBeDamaged() + { + return false; + } + + public override void OnDelete() + { + m_Instances.Remove( this ); + base.OnDelete(); + } + + public TownCrier( Serial serial ) : base( serial ) + { + m_Instances.Add( this ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Core.AOS && NameHue == 0x35 ) + NameHue = -1; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/AnimalBuy.cs b/Scripts/Mobiles/Vendors/AnimalBuy.cs new file mode 100644 index 0000000..0e46819 --- /dev/null +++ b/Scripts/Mobiles/Vendors/AnimalBuy.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + public class AnimalBuyInfo : GenericBuyInfo + { + private int m_ControlSlots; + + public AnimalBuyInfo( int controlSlots, Type type, int price, int amount, int itemID, int hue ) : this( controlSlots, null, type, price, amount, itemID, hue ) + { + } + + public AnimalBuyInfo( int controlSlots, string name, Type type, int price, int amount, int itemID, int hue ) : base( name, type, price, amount, itemID, hue ) + { + m_ControlSlots = controlSlots; + } + + public override int ControlSlots + { + get + { + return m_ControlSlots; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/BaseVendor.cs b/Scripts/Mobiles/Vendors/BaseVendor.cs new file mode 100644 index 0000000..17c586e --- /dev/null +++ b/Scripts/Mobiles/Vendors/BaseVendor.cs @@ -0,0 +1,1569 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Network; +using Server.ContextMenus; +using Server.Mobiles; +using Server.Misc; +using Server.Engines.BulkOrders; +using Server.Regions; +using Server.Factions; + +namespace Server.Mobiles +{ + public enum VendorShoeType + { + None, + Shoes, + Boots, + Sandals, + ThighBoots + } + + public abstract class BaseVendor : BaseCreature, IVendor + { + private const int MaxSell = 500; + + protected abstract List SBInfos { get; } + + private ArrayList m_ArmorBuyInfo = new ArrayList(); + private ArrayList m_ArmorSellInfo = new ArrayList(); + + private DateTime m_LastRestock; + + private DateTime m_NextTrickOrTreat; + + public override bool CanTeach { get { return true; } } + + public override bool BardImmune { get { return true; } } + + public override bool PlayerRangeSensitive { get { return true; } } + + public virtual bool IsActiveVendor { get { return true; } } + public virtual bool IsActiveBuyer { get { return IsActiveVendor; } } // response to vendor SELL + public virtual bool IsActiveSeller { get { return IsActiveVendor; } } // repsonse to vendor BUY + + public virtual NpcGuild NpcGuild { get { return NpcGuild.None; } } + + public override bool IsInvulnerable { get { return true; } } + + public virtual DateTime NextTrickOrTreat { get { return m_NextTrickOrTreat; } set { m_NextTrickOrTreat = value; } } + + public override bool ShowFameTitle { get { return false; } } + + public virtual bool IsValidBulkOrder( Item item ) + { + return false; + } + + public virtual Item CreateBulkOrder( Mobile from, bool fromContextMenu ) + { + return null; + } + + public virtual bool SupportsBulkOrders( Mobile from ) + { + return false; + } + + public virtual TimeSpan GetNextBulkOrder( Mobile from ) + { + return TimeSpan.Zero; + } + + public virtual void OnSuccessfulBulkOrderReceive( Mobile from ) + { + } + + #region Faction + public virtual int GetPriceScalar() + { + Town town = Town.FromRegion( this.Region ); + + if ( town != null ) + return ( 100 + town.Tax ); + + return 100; + } + + public void UpdateBuyInfo() + { + int priceScalar = GetPriceScalar(); + + IBuyItemInfo[] buyinfo = (IBuyItemInfo[])m_ArmorBuyInfo.ToArray( typeof( IBuyItemInfo ) ); + + if ( buyinfo != null ) + { + foreach ( IBuyItemInfo info in buyinfo ) + info.PriceScalar = priceScalar; + } + } + #endregion + + private class BulkOrderInfoEntry : ContextMenuEntry + { + private Mobile m_From; + private BaseVendor m_Vendor; + + public BulkOrderInfoEntry( Mobile from, BaseVendor vendor ) + : base( 6152 ) + { + m_From = from; + m_Vendor = vendor; + } + + public override void OnClick() + { + if ( m_Vendor.SupportsBulkOrders( m_From ) ) + { + TimeSpan ts = m_Vendor.GetNextBulkOrder( m_From ); + + int totalSeconds = (int)ts.TotalSeconds; + int totalHours = ( totalSeconds + 3599 ) / 3600; + int totalMinutes = ( totalSeconds + 59 ) / 60; + + if ( ( ( Core.SE ) ? totalMinutes == 0 : totalHours == 0 ) ) + { + m_From.SendLocalizedMessage( 1049038 ); // You can get an order now. + + if ( Core.AOS ) + { + Item bulkOrder = m_Vendor.CreateBulkOrder( m_From, true ); + + if ( bulkOrder is LargeBOD ) + m_From.SendGump( new LargeBODAcceptGump( m_From, (LargeBOD)bulkOrder ) ); + else if ( bulkOrder is SmallBOD ) + m_From.SendGump( new SmallBODAcceptGump( m_From, (SmallBOD)bulkOrder ) ); + } + } + else + { + int oldSpeechHue = m_Vendor.SpeechHue; + m_Vendor.SpeechHue = 0x3B2; + + if ( Core.SE ) + m_Vendor.SayTo( m_From, 1072058, totalMinutes.ToString() ); // An offer may be available in about ~1_minutes~ minutes. + else + m_Vendor.SayTo( m_From, 1049039, totalHours.ToString() ); // An offer may be available in about ~1_hours~ hours. + + m_Vendor.SpeechHue = oldSpeechHue; + } + } + } + } + public BaseVendor(string title) + : base(AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2) + { + LoadSBInfo(); + + this.Title = title; + //this.Title = title; + InitBody(); + InitOutfit(); + + Container pack; + //these packs MUST exist, or the client will crash when the packets are sent + pack = new Backpack(); + pack.Layer = Layer.ShopBuy; + pack.Movable = false; + pack.Visible = false; + AddItem(pack); + + pack = new Backpack(); + pack.Layer = Layer.ShopResale; + pack.Movable = false; + pack.Visible = false; + AddItem(pack); + + m_LastRestock = DateTime.Now; + } + + //Plume traduction des vendeurs + public BaseVendor(string title, string ftitle) + : base( AIType.AI_Vendor, FightMode.None, 2, 1, 0.5, 2 ) + { + LoadSBInfo(); + Female = Utility.RandomBool(); + this.Title = this.Female ? ftitle : title; + //this.Title = title; + InitBody(); + InitOutfit(); + + Container pack; + //these packs MUST exist, or the client will crash when the packets are sent + pack = new Backpack(); + pack.Layer = Layer.ShopBuy; + pack.Movable = false; + pack.Visible = false; + AddItem( pack ); + + pack = new Backpack(); + pack.Layer = Layer.ShopResale; + pack.Movable = false; + pack.Visible = false; + AddItem( pack ); + + m_LastRestock = DateTime.Now; + } + + + + public BaseVendor( Serial serial ) + : base( serial ) + { + } + + public DateTime LastRestock + { + get + { + return m_LastRestock; + } + set + { + m_LastRestock = value; + } + } + + public virtual TimeSpan RestockDelay + { + get + { + return TimeSpan.FromHours( 1 ); + } + } + + public Container BuyPack + { + get + { + Container pack = FindItemOnLayer( Layer.ShopBuy ) as Container; + + if ( pack == null ) + { + pack = new Backpack(); + pack.Layer = Layer.ShopBuy; + pack.Visible = false; + AddItem( pack ); + } + + return pack; + } + } + + public abstract void InitSBInfo(); + + public virtual bool IsTokunoVendor { get { return ( Map == Map.Tokuno ); } } + + protected void LoadSBInfo() + { + m_LastRestock = DateTime.Now; + + for ( int i = 0; i < m_ArmorBuyInfo.Count; ++i ) + { + GenericBuyInfo buy = m_ArmorBuyInfo[i] as GenericBuyInfo; + + if ( buy != null ) + buy.DeleteDisplayEntity(); + } + + SBInfos.Clear(); + + InitSBInfo(); + + m_ArmorBuyInfo.Clear(); + m_ArmorSellInfo.Clear(); + + for ( int i = 0; i < SBInfos.Count; i++ ) + { + SBInfo sbInfo = (SBInfo)SBInfos[i]; + m_ArmorBuyInfo.AddRange( sbInfo.BuyInfo ); + m_ArmorSellInfo.Add( sbInfo.SellInfo ); + } + } + + public virtual bool GetGender() + { + return Utility.RandomBool(); + } + + public virtual void InitBody() + { + InitStats( 100, 100, 25 ); + + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + + if ( Female ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + } + } + + public virtual int GetRandomHue() + { + switch ( Utility.Random( 5 ) ) + { + default: + case 0: return Utility.RandomBlueHue(); + case 1: return Utility.RandomGreenHue(); + case 2: return Utility.RandomRedHue(); + case 3: return Utility.RandomYellowHue(); + case 4: return Utility.RandomNeutralHue(); + } + } + + public virtual int GetShoeHue() + { + if ( 0.1 > Utility.RandomDouble() ) + return 0; + + return Utility.RandomNeutralHue(); + } + + public virtual VendorShoeType ShoeType + { + get { return VendorShoeType.Shoes; } + } + + public virtual void CheckMorph() + { + if ( CheckGargoyle() ) + return; + + if ( CheckNecromancer() ) + return; + + CheckTokuno(); + } + + public virtual bool CheckTokuno() + { + if ( this.Map != Map.Tokuno ) + return false; + + NameList n; + + if ( Female ) + n = NameList.GetNameList( "tokuno female" ); + else + n = NameList.GetNameList( "tokuno male" ); + + if ( !n.ContainsName( this.Name ) ) + TurnToTokuno(); + + return true; + } + + public virtual void TurnToTokuno() + { + if ( Female ) + this.Name = NameList.RandomName( "tokuno female" ); + else + this.Name = NameList.RandomName( "tokuno male" ); + } + + public virtual bool CheckGargoyle() + { + Map map = this.Map; + + if ( map != Map.Ilshenar ) + return false; + + if ( !Region.IsPartOf( "Gargoyle City" ) ) + return false; + + if ( Body != 0x2F6 || ( Hue & 0x8000 ) == 0 ) + TurnToGargoyle(); + + return true; + } + + public virtual bool CheckNecromancer() + { + Map map = this.Map; + + if ( map != Map.Malas ) + return false; + + if ( !Region.IsPartOf( "Umbra" ) ) + return false; + + if ( Hue != 0x83E8 ) + TurnToNecromancer(); + + return true; + } + + public override void OnAfterSpawn() + { + CheckMorph(); + } + + protected override void OnMapChange( Map oldMap ) + { + base.OnMapChange( oldMap ); + + CheckMorph(); + + LoadSBInfo(); + } + + public virtual int GetRandomNecromancerHue() + { + switch ( Utility.Random( 20 ) ) + { + case 0: return 0; + case 1: return 0x4E9; + default: return Utility.RandomList( 0x485, 0x497 ); + } + } + + public virtual void TurnToNecromancer() + { + for ( int i = 0; i < this.Items.Count; ++i ) + { + Item item = this.Items[i]; + + if ( item is Hair || item is Beard ) + item.Hue = 0; + else if ( item is BaseClothing || item is BaseWeapon || item is BaseArmor || item is BaseTool ) + item.Hue = GetRandomNecromancerHue(); + } + + HairHue = 0; + FacialHairHue = 0; + + Hue = 0x83E8; + } + + public virtual void TurnToGargoyle() + { + for ( int i = 0; i < this.Items.Count; ++i ) + { + Item item = this.Items[i]; + + if ( item is BaseClothing || item is Hair || item is Beard ) + item.Delete(); + } + + HairItemID = 0; + FacialHairItemID = 0; + + Body = 0x2F6; + Hue = Utility.RandomBrightHue() | 0x8000; + Name = NameList.RandomName( "gargoyle vendor" ); + + CapitalizeTitle(); + } + + public virtual void CapitalizeTitle() + { + string title = this.Title; + + if ( title == null ) + return; + + string[] split = title.Split( ' ' ); + + for ( int i = 0; i < split.Length; ++i ) + { + if ( Insensitive.Equals( split[i], "the" ) ) + continue; + + if ( split[i].Length > 1 ) + split[i] = Char.ToUpper( split[i][0] ) + split[i].Substring( 1 ); + else if ( split[i].Length > 0 ) + split[i] = Char.ToUpper( split[i][0] ).ToString(); + } + + this.Title = String.Join( " ", split ); + } + + public virtual int GetHairHue() + { + return Utility.RandomHairHue(); + } + + public virtual void InitOutfit() + { + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new FancyShirt( GetRandomHue() ) ); break; + case 1: AddItem( new Doublet( GetRandomHue() ) ); break; + case 2: AddItem( new Shirt( GetRandomHue() ) ); break; + } + + switch ( ShoeType ) + { + case VendorShoeType.Shoes: AddItem( new Shoes( GetShoeHue() ) ); break; + case VendorShoeType.Boots: AddItem( new Boots( GetShoeHue() ) ); break; + case VendorShoeType.Sandals: AddItem( new Sandals( GetShoeHue() ) ); break; + case VendorShoeType.ThighBoots: AddItem( new ThighBoots( GetShoeHue() ) ); break; + } + + int hairHue = GetHairHue(); + + Utility.AssignRandomHair( this, hairHue ); + Utility.AssignRandomFacialHair( this, hairHue ); + + if ( Female ) + { + switch ( Utility.Random( 6 ) ) + { + case 0: AddItem( new ShortPants( GetRandomHue() ) ); break; + case 1: + case 2: AddItem( new Kilt( GetRandomHue() ) ); break; + case 3: + case 4: + case 5: AddItem( new Skirt( GetRandomHue() ) ); break; + } + } + else + { + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new LongPants( GetRandomHue() ) ); break; + case 1: AddItem( new ShortPants( GetRandomHue() ) ); break; + } + } + + PackGold( 100, 200 ); + } + + public virtual void Restock() + { + m_LastRestock = DateTime.Now; + + IBuyItemInfo[] buyInfo = this.GetBuyInfo(); + + foreach ( IBuyItemInfo bii in buyInfo ) + bii.OnRestock(); + } + + private static TimeSpan InventoryDecayTime = TimeSpan.FromHours( 1.0 ); + + public virtual void VendorBuy( Mobile from ) + { + if ( !IsActiveSeller ) + return; + + if ( !from.CheckAlive() ) + return; + + if ( !CheckVendorAccess( from ) ) + { + Say( 501522 ); // I shall not treat with scum like thee! + return; + } + + if ( DateTime.Now - m_LastRestock > RestockDelay ) + Restock(); + + UpdateBuyInfo(); + + int count = 0; + List list; + IBuyItemInfo[] buyInfo = this.GetBuyInfo(); + IShopSellInfo[] sellInfo = this.GetSellInfo(); + + list = new List(buyInfo.Length); + Container cont = this.BuyPack; + + List opls = null; + + for ( int idx = 0; idx < buyInfo.Length; idx++ ) + { + IBuyItemInfo buyItem = (IBuyItemInfo)buyInfo[idx]; + + if ( buyItem.Amount <= 0 || list.Count >= 250 ) + continue; + + // NOTE: Only GBI supported; if you use another implementation of IBuyItemInfo, this will crash + GenericBuyInfo gbi = (GenericBuyInfo)buyItem; + IEntity disp = gbi.GetDisplayEntity(); + + list.Add( new BuyItemState( buyItem.Name, cont.Serial, disp == null ? (Serial)0x7FC0FFEE : disp.Serial, buyItem.Price, buyItem.Amount, buyItem.ItemID, buyItem.Hue ) ); + count++; + + if ( opls == null ) { + opls = new List(); + } + + if ( disp is Item ) { + opls.Add( ( ( Item ) disp ).PropertyList ); + } else if ( disp is Mobile ) { + opls.Add( ( ( Mobile ) disp ).PropertyList ); + } + } + + List playerItems = cont.Items; + + for ( int i = playerItems.Count - 1; i >= 0; --i ) + { + if ( i >= playerItems.Count ) + continue; + + Item item = playerItems[i]; + + if ( ( item.LastMoved + InventoryDecayTime ) <= DateTime.Now ) + item.Delete(); + } + + for ( int i = 0; i < playerItems.Count; ++i ) + { + Item item = playerItems[i]; + + int price = 0; + string name = null; + + foreach ( IShopSellInfo ssi in sellInfo ) + { + if ( ssi.IsSellable( item ) ) + { + price = ssi.GetBuyPriceFor( item ); + name = ssi.GetNameFor( item ); + break; + } + } + + if ( name != null && list.Count < 250 ) + { + list.Add( new BuyItemState( name, cont.Serial, item.Serial, price, item.Amount, item.ItemID, item.Hue ) ); + count++; + + if ( opls == null ) { + opls = new List(); + } + + opls.Add( item.PropertyList ); + } + } + + //one (not all) of the packets uses a byte to describe number of items in the list. Osi = dumb. + //if ( list.Count > 255 ) + // Console.WriteLine( "Vendor Warning: Vendor {0} has more than 255 buy items, may cause client errors!", this ); + + if ( list.Count > 0 ) + { + list.Sort( new BuyItemStateComparer() ); + + SendPacksTo( from ); + + NetState ns = from.NetState; + + if ( ns == null ) + return; + + if ( ns.ContainerGridLines ) + from.Send( new VendorBuyContent6017( list ) ); + else + from.Send( new VendorBuyContent( list ) ); + + from.Send( new VendorBuyList( this, list ) ); + + if ( ns.HighSeas ) + from.Send( new DisplayBuyListHS( this ) ); + else + from.Send( new DisplayBuyList( this ) ); + + from.Send( new MobileStatusExtended( from ) );//make sure their gold amount is sent + + if ( opls != null ) { + for ( int i = 0; i < opls.Count; ++i ) { + from.Send( opls[i] ); + } + } + + SayTo( from, 500186 ); // Greetings. Have a look around. + } + } + + public virtual void SendPacksTo( Mobile from ) + { + Item pack = FindItemOnLayer( Layer.ShopBuy ); + + if ( pack == null ) + { + pack = new Backpack(); + pack.Layer = Layer.ShopBuy; + pack.Movable = false; + pack.Visible = false; + AddItem( pack ); + } + + from.Send( new EquipUpdate( pack ) ); + + pack = FindItemOnLayer( Layer.ShopSell ); + + if ( pack != null ) + from.Send( new EquipUpdate( pack ) ); + + pack = FindItemOnLayer( Layer.ShopResale ); + + if ( pack == null ) + { + pack = new Backpack(); + pack.Layer = Layer.ShopResale; + pack.Movable = false; + pack.Visible = false; + AddItem( pack ); + } + + from.Send( new EquipUpdate( pack ) ); + } + + public virtual void VendorSell( Mobile from ) + { + if ( !IsActiveBuyer ) + return; + + if ( !from.CheckAlive() ) + return; + + if ( !CheckVendorAccess( from ) ) + { + Say( 501522 ); // I shall not treat with scum like thee! + return; + } + + Container pack = from.Backpack; + + if ( pack != null ) + { + IShopSellInfo[] info = GetSellInfo(); + + Hashtable table = new Hashtable(); + + foreach ( IShopSellInfo ssi in info ) + { + Item[] items = pack.FindItemsByType( ssi.Types ); + + foreach ( Item item in items ) + { + if ( item is Container && ( (Container)item ).Items.Count != 0 ) + continue; + + if ( item.IsStandardLoot() && item.Movable && ssi.IsSellable( item ) ) + table[item] = new SellItemState( item, ssi.GetSellPriceFor( item ), ssi.GetNameFor( item ) ); + } + } + + if ( table.Count > 0 ) + { + SendPacksTo( from ); + + from.Send( new VendorSellList( this, table ) ); + } + else + { + Say( true, "You have nothing I would be interested in." ); + } + } + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + /* TODO: Thou art giving me? and fame/karma for gold gifts */ + + if (dropped is SmallBOD || dropped is LargeBOD) + { + PlayerMobile pm = from as PlayerMobile; + + if (Core.ML && pm != null && pm.NextBODTurnInTime > DateTime.Now) + { + SayTo(from, 1079976); // You'll have to wait a few seconds while I inspect the last order. + return false; + } + else if (!IsValidBulkOrder(dropped)) + { + SayTo(from, 1045130); // That order is for some other shopkeeper. + return false; + } + else if ((dropped is SmallBOD && !((SmallBOD)dropped).Complete) || (dropped is LargeBOD && !((LargeBOD)dropped).Complete)) + { + SayTo(from, 1045131); // You have not completed the order yet. + return false; + } + + Item reward; + int gold, fame; + + if (dropped is SmallBOD) + ((SmallBOD)dropped).GetRewards(out reward, out gold, out fame); + else + ((LargeBOD)dropped).GetRewards(out reward, out gold, out fame); + + from.SendSound(0x3D); + + SayTo(from, 1045132); // Thank you so much! Here is a reward for your effort. + + if (reward != null) + from.AddToBackpack(reward); + + if (gold > 1000) + from.AddToBackpack(new BankCheck(gold)); + else if (gold > 0) + from.AddToBackpack(new Gold(gold)); + + Titles.AwardFame(from, fame, true); + + OnSuccessfulBulkOrderReceive(from); + + if (Core.ML && pm != null) + pm.NextBODTurnInTime = DateTime.Now + TimeSpan.FromSeconds(10.0); + + dropped.Delete(); + return true; + } + + return base.OnDragDrop(from, dropped); + } + + private GenericBuyInfo LookupDisplayObject( object obj ) + { + IBuyItemInfo[] buyInfo = this.GetBuyInfo(); + + for ( int i = 0; i < buyInfo.Length; ++i ) { + GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[i]; + + if ( gbi.GetDisplayEntity() == obj ) + return gbi; + } + + return null; + } + + private void ProcessSinglePurchase(BuyItemResponse buy, IBuyItemInfo bii, List validBuy, ref int controlSlots, ref bool fullPurchase, ref int totalCost) + { + int amount = buy.Amount; + + if ( amount > bii.Amount ) + amount = bii.Amount; + + if ( amount <= 0 ) + return; + + int slots = bii.ControlSlots * amount; + + if ( controlSlots >= slots ) + { + controlSlots -= slots; + } + else + { + fullPurchase = false; + return; + } + + totalCost += bii.Price * amount; + validBuy.Add( buy ); + } + + private void ProcessValidPurchase( int amount, IBuyItemInfo bii, Mobile buyer, Container cont ) + { + if ( amount > bii.Amount ) + amount = bii.Amount; + + if ( amount < 1 ) + return; + + bii.Amount -= amount; + + IEntity o = bii.GetEntity(); + + if ( o is Item ) + { + Item item = (Item)o; + + if (item is Food) + { + Food food = item as Food; + if (Utility.RandomDouble() <= 0.05) + food.Poison = Poison.Lesser; + } + if (item is BaseWeapon) + { + BaseWeapon wpn = item as BaseWeapon; + if (Utility.RandomDouble() <= 0.05) + wpn.Quality = WeaponQuality.Low; + } + if (item is BaseArmor) + { + BaseArmor arm = item as BaseArmor; + if (Utility.RandomDouble() <= 0.05) + arm.Quality = ArmorQuality.Low; + } + if (item is BaseTool) + { + BaseTool tool = item as BaseTool; + if (Utility.RandomDouble() <= 0.05) + tool.UsesRemaining /= 2; + } + + if ( item.Stackable ) + { + item.Amount = amount; + + if ( cont == null || !cont.TryDropItem( buyer, item, false ) ) + item.MoveToWorld( buyer.Location, buyer.Map ); + } + else + { + item.Amount = 1; + + if ( cont == null || !cont.TryDropItem( buyer, item, false ) ) + item.MoveToWorld( buyer.Location, buyer.Map ); + + for ( int i = 1; i < amount; i++ ) + { + item = bii.GetEntity() as Item; + + if ( item != null ) + { + item.Amount = 1; + + if ( cont == null || !cont.TryDropItem( buyer, item, false ) ) + item.MoveToWorld( buyer.Location, buyer.Map ); + } + } + } + } + else if ( o is Mobile ) + { + Mobile m = (Mobile)o; + + m.Direction = (Direction)Utility.Random( 8 ); + m.MoveToWorld( buyer.Location, buyer.Map ); + m.PlaySound( m.GetIdleSound() ); + + if ( m is BaseCreature ) + ( (BaseCreature)m ).SetControlMaster( buyer ); + + for ( int i = 1; i < amount; ++i ) + { + m = bii.GetEntity() as Mobile; + + if ( m != null ) + { + m.Direction = (Direction)Utility.Random( 8 ); + m.MoveToWorld( buyer.Location, buyer.Map ); + + if ( m is BaseCreature ) + ( (BaseCreature)m ).SetControlMaster( buyer ); + } + } + } + } + + public virtual bool OnBuyItems( Mobile buyer, List list ) + { + if ( !IsActiveSeller ) + return false; + + if ( !buyer.CheckAlive() ) + return false; + + if ( !CheckVendorAccess( buyer ) ) + { + Say( 501522 ); // I shall not treat with scum like thee! + return false; + } + + UpdateBuyInfo(); + + IBuyItemInfo[] buyInfo = this.GetBuyInfo(); + IShopSellInfo[] info = GetSellInfo(); + int totalCost = 0; + List validBuy = new List( list.Count ); + Container cont; + bool bought = false; + bool fromBank = false; + bool fullPurchase = true; + int controlSlots = buyer.FollowersMax - buyer.Followers; + + foreach ( BuyItemResponse buy in list ) + { + Serial ser = buy.Serial; + int amount = buy.Amount; + + if ( ser.IsItem ) + { + Item item = World.FindItem( ser ); + + if ( item == null ) + continue; + + GenericBuyInfo gbi = LookupDisplayObject( item ); + + if ( gbi != null ) + { + ProcessSinglePurchase( buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost ); + } + else if ( item != this.BuyPack && item.IsChildOf( this.BuyPack ) ) + { + if ( amount > item.Amount ) + amount = item.Amount; + + if ( amount <= 0 ) + continue; + + foreach ( IShopSellInfo ssi in info ) + { + if ( ssi.IsSellable( item ) ) + { + if ( ssi.IsResellable( item ) ) + { + totalCost += ssi.GetBuyPriceFor( item ) * amount; + validBuy.Add( buy ); + break; + } + } + } + } + } + else if ( ser.IsMobile ) + { + Mobile mob = World.FindMobile( ser ); + + if ( mob == null ) + continue; + + GenericBuyInfo gbi = LookupDisplayObject( mob ); + + if ( gbi != null ) + ProcessSinglePurchase( buy, gbi, validBuy, ref controlSlots, ref fullPurchase, ref totalCost ); + } + }//foreach + + if ( fullPurchase && validBuy.Count == 0 ) + SayTo( buyer, 500190 ); // Thou hast bought nothing! + else if ( validBuy.Count == 0 ) + SayTo( buyer, 500187 ); // Your order cannot be fulfilled, please try again. + + if ( validBuy.Count == 0 ) + return false; + + bought = ( buyer.AccessLevel >= AccessLevel.GameMaster ); + + cont = buyer.Backpack; + if ( !bought && cont != null ) + { + if ( cont.ConsumeTotal( typeof( Gold ), totalCost ) ) + bought = true; + else if ( totalCost < 2000 ) + SayTo(buyer, 500192); // Begging thy pardon, but thou canst not afford that. + } + + if ( !bought && totalCost >= 2000 ) + { + cont = buyer.FindBankNoCreate(); + if ( cont != null && cont.ConsumeTotal( typeof( Gold ), totalCost ) ) + { + bought = true; + fromBank = true; + } + else + { + SayTo( buyer, 500191 ); //Begging thy pardon, but thy bank account lacks these funds. + } + } + + if ( !bought ) + return false; + else + buyer.PlaySound( 0x32 ); + + cont = buyer.Backpack; + if ( cont == null ) + cont = buyer.BankBox; + + foreach ( BuyItemResponse buy in validBuy ) + { + Serial ser = buy.Serial; + int amount = buy.Amount; + + if ( amount < 1 ) + continue; + + if ( ser.IsItem ) + { + Item item = World.FindItem( ser ); + + if ( item == null ) + continue; + + GenericBuyInfo gbi = LookupDisplayObject( item ); + + if ( gbi != null ) + { + ProcessValidPurchase( amount, gbi, buyer, cont ); + } + else + { + if ( amount > item.Amount ) + amount = item.Amount; + + foreach ( IShopSellInfo ssi in info ) + { + if ( ssi.IsSellable( item ) ) + { + if ( ssi.IsResellable( item ) ) + { + Item buyItem; + if ( amount >= item.Amount ) + { + buyItem = item; + } + else + { + buyItem = Mobile.LiftItemDupe( item, item.Amount - amount ); + + if ( buyItem == null ) + buyItem = item; + } + + if ( cont == null || !cont.TryDropItem( buyer, buyItem, false ) ) + buyItem.MoveToWorld( buyer.Location, buyer.Map ); + + break; + } + } + } + } + } + else if ( ser.IsMobile ) + { + Mobile mob = World.FindMobile( ser ); + + if ( mob == null ) + continue; + + GenericBuyInfo gbi = LookupDisplayObject( mob ); + + if ( gbi != null ) + ProcessValidPurchase( amount, gbi, buyer, cont ); + } + }//foreach + + if ( fullPurchase ) + { + if ( buyer.AccessLevel >= AccessLevel.GameMaster ) + SayTo( buyer, true, "I would not presume to charge thee anything. Here are the goods you requested." ); + else if ( fromBank ) + SayTo( buyer, true, "The total of thy purchase is {0} gold, which has been withdrawn from your bank account. My thanks for the patronage.", totalCost ); + else + SayTo( buyer, true, "The total of thy purchase is {0} gold. My thanks for the patronage.", totalCost ); + } + else + { + if ( buyer.AccessLevel >= AccessLevel.GameMaster ) + SayTo( buyer, true, "I would not presume to charge thee anything. Unfortunately, I could not sell you all the goods you requested." ); + else if ( fromBank ) + SayTo( buyer, true, "The total of thy purchase is {0} gold, which has been withdrawn from your bank account. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", totalCost ); + else + SayTo( buyer, true, "The total of thy purchase is {0} gold. My thanks for the patronage. Unfortunately, I could not sell you all the goods you requested.", totalCost ); + } + + return true; + } + + public virtual bool CheckVendorAccess( Mobile from ) + { + if (!from.InLOS(this)) + return false; + + GuardedRegion reg = (GuardedRegion)this.Region.GetRegion( typeof( GuardedRegion ) ); + + if ( reg != null && !reg.CheckVendorAccess( this, from ) ) + return false; + + if ( this.Region != from.Region ) + { + reg = (GuardedRegion)from.Region.GetRegion( typeof( GuardedRegion ) ); + + if ( reg != null && !reg.CheckVendorAccess( this, from ) ) + return false; + } + + return true; + } + + public virtual bool OnSellItems( Mobile seller, List list ) + { + if ( !IsActiveBuyer ) + return false; + + if ( !seller.CheckAlive() ) + return false; + + if ( !CheckVendorAccess( seller ) ) + { + Say( 501522 ); // I shall not treat with scum like thee! + return false; + } + + seller.PlaySound( 0x32 ); + + IShopSellInfo[] info = GetSellInfo(); + IBuyItemInfo[] buyInfo = this.GetBuyInfo(); + int GiveGold = 0; + int Sold = 0; + Container cont; + + foreach ( SellItemResponse resp in list ) + { + if ( resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable || ( resp.Item is Container && ( (Container)resp.Item ).Items.Count != 0 ) ) + continue; + + foreach ( IShopSellInfo ssi in info ) + { + if ( ssi.IsSellable( resp.Item ) ) + { + Sold++; + break; + } + } + } + + if ( Sold > MaxSell ) + { + SayTo( seller, true, "You may only sell {0} items at a time!", MaxSell ); + return false; + } + else if ( Sold == 0 ) + { + return true; + } + + foreach ( SellItemResponse resp in list ) + { + if ( resp.Item.RootParent != seller || resp.Amount <= 0 || !resp.Item.IsStandardLoot() || !resp.Item.Movable || ( resp.Item is Container && ( (Container)resp.Item ).Items.Count != 0 ) ) + continue; + + foreach ( IShopSellInfo ssi in info ) + { + if ( ssi.IsSellable( resp.Item ) ) + { + int amount = resp.Amount; + + if ( amount > resp.Item.Amount ) + amount = resp.Item.Amount; + + if ( ssi.IsResellable( resp.Item ) ) + { + bool found = false; + + foreach ( IBuyItemInfo bii in buyInfo ) + { + if ( bii.Restock( resp.Item, amount ) ) + { + resp.Item.Consume( amount ); + found = true; + + break; + } + } + + if ( !found ) + { + cont = this.BuyPack; + + if ( amount < resp.Item.Amount ) + { + Item item = Mobile.LiftItemDupe( resp.Item, resp.Item.Amount - amount ); + + if ( item != null ) + { + item.SetLastMoved(); + cont.DropItem( item ); + } + else + { + resp.Item.SetLastMoved(); + cont.DropItem( resp.Item ); + } + } + else + { + resp.Item.SetLastMoved(); + cont.DropItem( resp.Item ); + } + } + } + else + { + if ( amount < resp.Item.Amount ) + resp.Item.Amount -= amount; + else + resp.Item.Delete(); + } + + GiveGold += ssi.GetSellPriceFor( resp.Item ) * amount; + break; + } + } + } + + if ( GiveGold > 0 ) + { + while ( GiveGold > 60000 ) + { + seller.AddToBackpack( new Gold( 60000 ) ); + GiveGold -= 60000; + } + + seller.AddToBackpack( new Gold( GiveGold ) ); + + seller.PlaySound( 0x0037 );//Gold dropping sound + + if ( SupportsBulkOrders( seller ) ) + { + Item bulkOrder = CreateBulkOrder( seller, false ); + + if ( bulkOrder is LargeBOD ) + seller.SendGump( new LargeBODAcceptGump( seller, (LargeBOD)bulkOrder ) ); + else if ( bulkOrder is SmallBOD ) + seller.SendGump( new SmallBODAcceptGump( seller, (SmallBOD)bulkOrder ) ); + } + } + //no cliloc for this? + //SayTo( seller, true, "Thank you! I bought {0} item{1}. Here is your {2}gp.", Sold, (Sold > 1 ? "s" : ""), GiveGold ); + + return true; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)1 ); // version + + List sbInfos = this.SBInfos; + + for ( int i = 0; sbInfos != null && i < sbInfos.Count; ++i ) + { + SBInfo sbInfo = sbInfos[i]; + List buyInfo = sbInfo.BuyInfo; + + for ( int j = 0; buyInfo != null && j < buyInfo.Count; ++j ) + { + GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[j]; + + int maxAmount = gbi.MaxAmount; + int doubled = 0; + + switch ( maxAmount ) + { + case 40: doubled = 1; break; + case 80: doubled = 2; break; + case 160: doubled = 3; break; + case 320: doubled = 4; break; + case 640: doubled = 5; break; + case 999: doubled = 6; break; + } + + if ( doubled > 0 ) + { + writer.WriteEncodedInt( 1 + ( ( j * sbInfos.Count ) + i ) ); + writer.WriteEncodedInt( doubled ); + } + } + } + + writer.WriteEncodedInt( 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + LoadSBInfo(); + + List sbInfos = this.SBInfos; + + switch ( version ) + { + case 1: + { + int index; + + while ( ( index = reader.ReadEncodedInt() ) > 0 ) + { + int doubled = reader.ReadEncodedInt(); + + if ( sbInfos != null ) + { + index -= 1; + int sbInfoIndex = index % sbInfos.Count; + int buyInfoIndex = index / sbInfos.Count; + + if ( sbInfoIndex >= 0 && sbInfoIndex < sbInfos.Count ) + { + SBInfo sbInfo = sbInfos[sbInfoIndex]; + List buyInfo = sbInfo.BuyInfo; + + if ( buyInfo != null && buyInfoIndex >= 0 && buyInfoIndex < buyInfo.Count ) + { + GenericBuyInfo gbi = (GenericBuyInfo)buyInfo[buyInfoIndex]; + + int amount = 20; + + switch ( doubled ) + { + case 1: amount = 40; break; + case 2: amount = 80; break; + case 3: amount = 160; break; + case 4: amount = 320; break; + case 5: amount = 640; break; + case 6: amount = 999; break; + } + + gbi.Amount = gbi.MaxAmount = amount; + } + } + } + } + + break; + } + } + + if ( IsParagon ) + IsParagon = false; + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( CheckMorph ) ); + } + + public override void AddCustomContextEntries( Mobile from, List list ) + { + if ( from.Alive && IsActiveVendor ) + { + if ( SupportsBulkOrders( from ) ) + list.Add( new BulkOrderInfoEntry( from, this ) ); + + if ( IsActiveSeller ) + list.Add( new VendorBuyEntry( from, this ) ); + + if ( IsActiveBuyer ) + list.Add( new VendorSellEntry( from, this ) ); + } + + base.AddCustomContextEntries( from, list ); + } + + public virtual IShopSellInfo[] GetSellInfo() + { + return (IShopSellInfo[])m_ArmorSellInfo.ToArray( typeof( IShopSellInfo ) ); + } + + public virtual IBuyItemInfo[] GetBuyInfo() + { + return (IBuyItemInfo[])m_ArmorBuyInfo.ToArray( typeof( IBuyItemInfo ) ); + } + } +} + +namespace Server.ContextMenus +{ + public class VendorBuyEntry : ContextMenuEntry + { + private BaseVendor m_Vendor; + + public VendorBuyEntry( Mobile from, BaseVendor vendor ) + : base( 6103, 8 ) + { + m_Vendor = vendor; + Enabled = vendor.CheckVendorAccess( from ); + } + + public override void OnClick() + { + m_Vendor.VendorBuy( this.Owner.From ); + } + } + + public class VendorSellEntry : ContextMenuEntry + { + private BaseVendor m_Vendor; + + public VendorSellEntry( Mobile from, BaseVendor vendor ) + : base( 6104, 8 ) + { + m_Vendor = vendor; + Enabled = vendor.CheckVendorAccess( from ); + } + + public override void OnClick() + { + m_Vendor.VendorSell( this.Owner.From ); + } + } +} + +namespace Server +{ + public interface IShopSellInfo + { + //get display name for an item + string GetNameFor( Item item ); + + //get price for an item which the player is selling + int GetSellPriceFor( Item item ); + + //get price for an item which the player is buying + int GetBuyPriceFor( Item item ); + + //can we sell this item to this vendor? + bool IsSellable( Item item ); + + //What do we sell? + Type[] Types { get; } + + //does the vendor resell this item? + bool IsResellable( Item item ); + } + + public interface IBuyItemInfo + { + //get a new instance of an object (we just bought it) + IEntity GetEntity(); + + int ControlSlots { get; } + + int PriceScalar { get; set; } + + //display price of the item + int Price { get; } + + //display name of the item + string Name { get; } + + //display hue + int Hue { get; } + + //display id + int ItemID { get; } + + //amount in stock + int Amount { get; set; } + + //max amount in stock + int MaxAmount { get; } + + //Attempt to restock with item, (return true if restock sucessful) + bool Restock( Item item, int amount ); + + //called when its time for the whole shop to restock + void OnRestock(); + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/BeverageBuy.cs b/Scripts/Mobiles/Vendors/BeverageBuy.cs new file mode 100644 index 0000000..fcf433c --- /dev/null +++ b/Scripts/Mobiles/Vendors/BeverageBuy.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + public class BeverageBuyInfo : GenericBuyInfo + { + private BeverageType m_Content; + + public override bool CanCacheDisplay{ get{ return false; } } + + public BeverageBuyInfo( Type type, BeverageType content, int price, int amount, int itemID, int hue ) : this( null, type, content, price, amount, itemID, hue ) + { + } + + public BeverageBuyInfo( string name, Type type, BeverageType content, int price, int amount, int itemID, int hue ) : base( name, type, price, amount, itemID, hue ) + { + m_Content = content; + + if ( type == typeof( Pitcher ) ) + Name = (1048128 + (int)content).ToString(); + else if ( type == typeof( BeverageBottle ) ) + Name = (1042959 + (int)content).ToString(); + else if ( type == typeof( Jug ) ) + Name = (1042965 + (int)content).ToString(); + } + + public override IEntity GetEntity() + { + return (IEntity)Activator.CreateInstance( Type, new object[]{ m_Content } ); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/GenericBuy.cs b/Scripts/Mobiles/Vendors/GenericBuy.cs new file mode 100644 index 0000000..b597fac --- /dev/null +++ b/Scripts/Mobiles/Vendors/GenericBuy.cs @@ -0,0 +1,350 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public class GenericBuyInfo : IBuyItemInfo + { + private class DisplayCache : Container + { + private static DisplayCache m_Cache; + + public static DisplayCache Cache { + get { + if ( m_Cache == null || m_Cache.Deleted ) + m_Cache = new DisplayCache(); + + return m_Cache; + } + } + + private Dictionary m_Table; + private List m_Mobiles; + + public DisplayCache() : base( 0 ) + { + m_Table = new Dictionary(); + m_Mobiles = new List(); + } + + public IEntity Lookup( Type key ) + { + IEntity e = null; + m_Table.TryGetValue( key, out e ); + return e; + } + + public void Store( Type key, IEntity obj, bool cache ) + { + if ( cache ) + m_Table[key] = obj; + + if ( obj is Item ) + AddItem( (Item)obj ); + else if ( obj is Mobile ) + m_Mobiles.Add( (Mobile)obj ); + } + + public DisplayCache( Serial serial ) : base( serial ) + { + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + for ( int i = 0; i < m_Mobiles.Count; ++i ) + m_Mobiles[i].Delete(); + + m_Mobiles.Clear(); + + for ( int i = Items.Count - 1; i >= 0; --i ) + if ( i < Items.Count ) + Items[i].Delete(); + + if ( m_Cache == this ) + m_Cache = null; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Mobiles ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Mobiles = reader.ReadStrongMobileList(); + + for ( int i = 0; i < m_Mobiles.Count; ++i ) + m_Mobiles[i].Delete(); + + m_Mobiles.Clear(); + + for ( int i = Items.Count - 1; i >= 0; --i ) + if ( i < Items.Count ) + Items[i].Delete(); + + if ( m_Cache == null ) + m_Cache = this; + else + Delete(); + + m_Table = new Dictionary(); + } + } + + private Type m_Type; + private string m_Name; + private int m_Price; + private int m_MaxAmount, m_Amount; + private int m_ItemID; + private int m_Hue; + private object[] m_Args; + private IEntity m_DisplayEntity; + + public virtual int ControlSlots{ get{ return 0; } } + + public virtual bool CanCacheDisplay{ get{ return false; } } //return ( m_Args == null || m_Args.Length == 0 ); } + + private bool IsDeleted( IEntity obj ) + { + if ( obj is Item ) + return ((Item)obj).Deleted; + else if ( obj is Mobile ) + return ((Mobile)obj).Deleted; + + return false; + } + + public void DeleteDisplayEntity() + { + if ( m_DisplayEntity == null ) + return; + + m_DisplayEntity.Delete(); + m_DisplayEntity = null; + } + + public IEntity GetDisplayEntity() + { + if ( m_DisplayEntity != null && !IsDeleted( m_DisplayEntity ) ) + return m_DisplayEntity; + + bool canCache = this.CanCacheDisplay; + + if ( canCache ) + m_DisplayEntity = DisplayCache.Cache.Lookup( m_Type ); + + if ( m_DisplayEntity == null || IsDeleted( m_DisplayEntity ) ) + m_DisplayEntity = GetEntity(); + + DisplayCache.Cache.Store( m_Type, m_DisplayEntity, canCache ); + + return m_DisplayEntity; + } + + public Type Type + { + get{ return m_Type; } + set{ m_Type = value; } + } + + public string Name + { + get{ return m_Name; } + set{ m_Name = value; } + } + + public int DefaultPrice{ get{ return m_PriceScalar; } } + + private int m_PriceScalar; + + public int PriceScalar + { + get{ return m_PriceScalar; } + set{ m_PriceScalar = value; } + } + + public int Price + { + get + { + if ( m_PriceScalar != 0 ) + { + if ( m_Price > 5000000 ) + { + long price = m_Price; + + price *= m_PriceScalar; + price += 50; + price /= 100; + + if ( price > int.MaxValue ) + price = int.MaxValue; + + return (int)price; + } + + return ( ((m_Price * m_PriceScalar) + 50) / 100 ); + } + + return m_Price; + } + set{ m_Price = value; } + } + + public int ItemID + { + get{ return m_ItemID; } + set{ m_ItemID = value; } + } + + public int Hue + { + get{ return m_Hue; } + set{ m_Hue = value; } + } + + public int Amount + { + get{ return m_Amount; } + set{ if ( value < 0 ) value = 0; m_Amount = value; } + } + + public int MaxAmount + { + get{ return m_MaxAmount; } + set{ m_MaxAmount = value; } + } + + public object[] Args + { + get{ return m_Args; } + set{ m_Args = value; } + } + + public GenericBuyInfo( Type type, int price, int amount, int itemID, int hue ) : this( null, type, price, amount, itemID, hue, null ) + { + } + + public GenericBuyInfo( string name, Type type, int price, int amount, int itemID, int hue ) : this( name, type, price, amount, itemID, hue, null ) + { + } + + public GenericBuyInfo( Type type, int price, int amount, int itemID, int hue, object[] args ) : this( null, type, price, amount, itemID, hue, args ) + { + } + + public GenericBuyInfo( string name, Type type, int price, int amount, int itemID, int hue, object[] args ) + { + m_Type = type; + m_Price = price; + m_MaxAmount = m_Amount = amount; + m_ItemID = itemID; + m_Hue = hue; + m_Args = args; + + if ( name == null ) + m_Name = itemID < 0x4000 ? (1020000 + itemID).ToString() : (1078872 + itemID).ToString(); + else + m_Name = name; + } + + //get a new instance of an object (we just bought it) + public virtual IEntity GetEntity() + { + if ( m_Args == null || m_Args.Length == 0 ) + return (IEntity)Activator.CreateInstance( m_Type ); + + return (IEntity)Activator.CreateInstance( m_Type, m_Args ); + //return (Item)Activator.CreateInstance( m_Type ); + } + + //Attempt to restock with item, (return true if restock sucessful) + public bool Restock( Item item, int amount ) + { + return false; + /*if ( item.GetType() == m_Type ) + { + if ( item is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)item; + + if ( weapon.Quality == WeaponQuality.Low || weapon.Quality == WeaponQuality.Exceptional || (int)weapon.DurabilityLevel > 0 || (int)weapon.DamageLevel > 0 || (int)weapon.AccuracyLevel > 0 ) + return false; + } + + if ( item is BaseArmor ) + { + BaseArmor armor = (BaseArmor)item; + + if ( armor.Quality == ArmorQuality.Low || armor.Quality == ArmorQuality.Exceptional || (int)armor.Durability > 0 || (int)armor.ProtectionLevel > 0 ) + return false; + } + + m_Amount += amount; + + return true; + } + else + { + return false; + }*/ + } + + public void OnRestock() + { + if (m_Amount <= 0) + { + /* + Core.ML using this vendor system is undefined behavior, so being + as it lends itself to an abusable exploit to cause ingame havok + and the stackable items are not found to be over 20 items, this is + changed until there is a better solution. + */ + + object Obj_Disp = GetDisplayEntity(); + + if (Core.ML && Obj_Disp is Item && !(Obj_Disp as Item).Stackable) + { + m_MaxAmount = Math.Min(20, m_MaxAmount); + } + else + { + m_MaxAmount = Math.Min(999, m_MaxAmount * 2); + } + } + else + { + /* NOTE: According to UO.com, the quantity is halved if the item does not reach 0 + * Here we implement differently: the quantity is halved only if less than half + * of the maximum quantity was bought. That is, if more than half is sold, then + * there's clearly a demand and we should not cut down on the stock. + */ + + int halfQuantity = m_MaxAmount; + + if ( halfQuantity >= 500 ) + halfQuantity = 400; + else if ( halfQuantity > 20 ) + halfQuantity /= 2; + + if ( m_Amount >= halfQuantity ) + m_MaxAmount = halfQuantity; + } + + m_Amount = m_MaxAmount; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/GenericSell.cs b/Scripts/Mobiles/Vendors/GenericSell.cs new file mode 100644 index 0000000..ebd0831 --- /dev/null +++ b/Scripts/Mobiles/Vendors/GenericSell.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class GenericSellInfo : IShopSellInfo + { + private Dictionary m_Table = new Dictionary(); + private Type[] m_Types; + + public GenericSellInfo() + { + } + + public void Add( Type type, int price ) + { + m_Table[type] = price; + m_Types = null; + } + + public int GetSellPriceFor( Item item ) + { + int price = 0; + m_Table.TryGetValue( item.GetType(), out price ); + + if ( item is BaseArmor ) { + BaseArmor armor = (BaseArmor)item; + + if ( armor.Quality == ArmorQuality.Low ) + price = (int)( price * 0.60 ); + else if ( armor.Quality == ArmorQuality.Exceptional ) + price = (int)( price * 1.25 ); + + price += 2 * (int)armor.Durability; + + price += 2 * (int)armor.ProtectionLevel; + + if ( price < 1 ) + price = 1; + } + else if ( item is BaseWeapon ) { + BaseWeapon weapon = (BaseWeapon)item; + + if ( weapon.Quality == WeaponQuality.Low ) + price = (int)( price * 0.60 ); + else if ( weapon.Quality == WeaponQuality.Exceptional ) + price = (int)( price * 1.25 ); + + price += 2 * (int)weapon.DurabilityLevel; + + price += 2 * (int)weapon.DamageLevel; + + if ( price < 1 ) + price = 1; + } + else if ( item is BaseBeverage ) { + int price1 = price, price2 = price; + + if ( item is Pitcher ) + { price1 = 3; price2 = 5; } + else if ( item is BeverageBottle ) + { price1 = 3; price2 = 3; } + else if ( item is Jug ) + { price1 = 6; price2 = 6; } + + BaseBeverage bev = (BaseBeverage)item; + + if ( bev.IsEmpty || bev.Content == BeverageType.Milk ) + price = price1; + else + price = price2; + } + + return price; + } + + public int GetBuyPriceFor( Item item ) + { + return (int)( 1.90 * GetSellPriceFor( item ) ); + } + + public Type[] Types + { + get + { + if ( m_Types == null ) + { + m_Types = new Type[m_Table.Keys.Count]; + m_Table.Keys.CopyTo( m_Types, 0 ); + } + + return m_Types; + } + } + + public string GetNameFor( Item item ) + { + if ( item.Name != null ) + return item.Name; + else + return item.LabelNumber.ToString(); + } + + public bool IsSellable(Item item) + { + if (item.Nontransferable) + return false; + + //if ( item.Hue != 0 ) + //return false; + + return IsInList(item.GetType()); + } + + public bool IsResellable(Item item) + { + if (item.Nontransferable) + return false; + + //if ( item.Hue != 0 ) + //return false; + + return IsInList(item.GetType()); + } + + public bool IsInList( Type type ) + { + return m_Table.ContainsKey( type ); + } + } +} diff --git a/Scripts/Mobiles/Vendors/NPC/Alchemist.cs b/Scripts/Mobiles/Vendors/NPC/Alchemist.cs new file mode 100644 index 0000000..1f574d8 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Alchemist.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Alchemist : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } } + + [Constructable] + public Alchemist() : base( "l'Alchimiste" ) + { + SetSkill( SkillName.Alchemy, 85.0, 100.0 ); + SetSkill( SkillName.TasteID, 65.0, 88.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBAlchemist() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Robe( Utility.RandomPinkHue() ) ); + } + + public Alchemist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs b/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs new file mode 100644 index 0000000..8239c0b --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/AnimalTrainer.cs @@ -0,0 +1,477 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.ContextMenus; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; + +namespace Server.Mobiles +{ + public class AnimalTrainer : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public AnimalTrainer() : base( "le Dresseur","la Dresseuse") + { + SetSkill( SkillName.AnimalLore, 64.0, 100.0 ); + SetSkill( SkillName.AnimalTaming, 90.0, 100.0 ); + SetSkill( SkillName.Veterinary, 65.0, 88.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBAnimalTrainer() ); + } + + public override VendorShoeType ShoeType + { + get{ return Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( Utility.RandomBool() ? (Item)new QuarterStaff() : (Item)new ShepherdsCrook() ); + } + + private class StableEntry : ContextMenuEntry + { + private AnimalTrainer m_Trainer; + private Mobile m_From; + + public StableEntry( AnimalTrainer trainer, Mobile from ) : base( 6126, 12 ) + { + m_Trainer = trainer; + m_From = from; + } + + public override void OnClick() + { + m_Trainer.BeginStable( m_From ); + } + } + + private class ClaimListGump : Gump + { + private AnimalTrainer m_Trainer; + private Mobile m_From; + private List m_List; + + public ClaimListGump( AnimalTrainer trainer, Mobile from, List list ) : base( 50, 50 ) + { + m_Trainer = trainer; + m_From = from; + m_List = list; + + from.CloseGump( typeof( ClaimListGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 325, 50 + (list.Count * 20), 9250 ); + AddAlphaRegion( 5, 5, 315, 40 + (list.Count * 20) ); + + AddHtml( 15, 15, 275, 20, "Select a pet to retrieve from the stables:", false, false ); + + for ( int i = 0; i < list.Count; ++i ) + { + BaseCreature pet = list[i]; + + if ( pet == null || pet.Deleted ) + continue; + + AddButton( 15, 39 + (i * 20), 10006, 10006, i + 1, GumpButtonType.Reply, 0 ); + AddHtml( 32, 35 + (i * 20), 275, 18, String.Format( "{0}", pet.Name ), false, false ); + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_List.Count ) + m_Trainer.EndClaimList( m_From, m_List[index] ); + } + } + + private class ClaimAllEntry : ContextMenuEntry + { + private AnimalTrainer m_Trainer; + private Mobile m_From; + + public ClaimAllEntry( AnimalTrainer trainer, Mobile from ) : base( 6127, 12 ) + { + m_Trainer = trainer; + m_From = from; + } + + public override void OnClick() + { + m_Trainer.Claim( m_From ); + } + } + + public override void AddCustomContextEntries( Mobile from, List list ) + { + if ( from.Alive ) + { + list.Add( new StableEntry( this, from ) ); + + if ( from.Stabled.Count > 0 ) + list.Add( new ClaimAllEntry( this, from ) ); + } + + base.AddCustomContextEntries( from, list ); + } + + public static int GetMaxStabled( Mobile from ) + { + double taming = from.Skills[SkillName.AnimalTaming].Value; + double anlore = from.Skills[SkillName.AnimalLore].Value; + double vetern = from.Skills[SkillName.Veterinary].Value; + double sklsum = taming + anlore + vetern; + + int max; + + if ( sklsum >= 240.0 ) + max = 5; + else if ( sklsum >= 200.0 ) + max = 4; + else if ( sklsum >= 160.0 ) + max = 3; + else + max = 2; + + if ( taming >= 100.0 ) + max += (int)((taming - 90.0) / 10); + + if ( anlore >= 100.0 ) + max += (int)((anlore - 90.0) / 10); + + if ( vetern >= 100.0 ) + max += (int)((vetern - 90.0) / 10); + + return max; + } + + private class StableTarget : Target + { + private AnimalTrainer m_Trainer; + + public StableTarget( AnimalTrainer trainer ) : base( 12, false, TargetFlags.None ) + { + m_Trainer = trainer; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is BaseCreature ) + m_Trainer.EndStable( from, (BaseCreature)targeted ); + else if ( targeted == from ) + m_Trainer.SayTo( from, 502672 ); // HA HA HA! Sorry, I am not an inn. + else + m_Trainer.SayTo( from, 1048053 ); // You can't stable that! + } + } + + private void CloseClaimList( Mobile from ) + { + from.CloseGump( typeof( ClaimListGump ) ); + } + + public void BeginClaimList( Mobile from ) + { + if ( Deleted || !from.CheckAlive() ) + return; + + List list = new List(); + + for ( int i = 0; i < from.Stabled.Count; ++i ) + { + BaseCreature pet = from.Stabled[i] as BaseCreature; + + if ( pet == null || pet.Deleted ) + { + pet.IsStabled = false; + pet.StabledBy = null; + from.Stabled.RemoveAt( i ); + --i; + continue; + } + + list.Add( pet ); + } + + if ( list.Count > 0 ) + from.SendGump( new ClaimListGump( this, from, list ) ); + else + SayTo( from, 502671 ); // But I have no animals stabled with me at the moment! + } + + public void EndClaimList( Mobile from, BaseCreature pet ) + { + if ( pet == null || pet.Deleted || from.Map != this.Map || !from.Stabled.Contains( pet ) || !from.CheckAlive() ) + return; + + if ( !from.InRange( this, 14 ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return; + } + + if ( CanClaim( from, pet ) ) + { + DoClaim( from, pet ); + + from.Stabled.Remove( pet ); + + if (from is PlayerMobile) + ((PlayerMobile)from).AutoStabled.Remove(pet); + } + else + { + SayTo( from, 1049612, pet.Name ); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + public void BeginStable( Mobile from ) + { + if ( Deleted || !from.CheckAlive() ) + return; + + Container bank = from.FindBankNoCreate(); + + if ( ( from.Backpack == null || from.Backpack.GetAmount( typeof( Gold ) ) < 30 ) && ( bank == null || bank.GetAmount( typeof( Gold ) ) < 30 ) ) + { + SayTo( from, 1042556 ); // Thou dost not have enough gold, not even in thy bank account. + } + else + { + /* I charge 30 gold per pet for a real week's stable time. + * I will withdraw it from thy bank account. + * Which animal wouldst thou like to stable here? + */ + from.SendLocalizedMessage(1042558); + + from.Target = new StableTarget( this ); + } + } + + public void EndStable( Mobile from, BaseCreature pet ) + { + if ( Deleted || !from.CheckAlive() ) + return; + + if ( pet.Body.IsHuman ) + { + SayTo( from, 502672 ); // HA HA HA! Sorry, I am not an inn. + } + else if ( !pet.Controlled ) + { + SayTo( from, 1048053 ); // You can't stable that! + } + else if ( pet.ControlMaster != from ) + { + SayTo( from, 1042562 ); // You do not own that pet! + } + else if ( pet.IsDeadPet ) + { + SayTo( from, 1049668 ); // Living pets only, please. + } + else if ( pet.Summoned ) + { + SayTo( from, 502673 ); // I can not stable summoned creatures. + } + /* + else if ( pet.Allured ) + { + SayTo( from, 1048053 ); // You can't stable that! + } +*/ + else if ( (pet is PackLlama || pet is PackHorse || pet is Beetle) && (pet.Backpack != null && pet.Backpack.Items.Count > 0) ) + { + SayTo( from, 1042563 ); // You need to unload your pet. + } + else if ( pet.Combatant != null && pet.InRange( pet.Combatant, 12 ) && pet.Map == pet.Combatant.Map ) + { + SayTo( from, 1042564 ); // I'm sorry. Your pet seems to be busy. + } + else if ( from.Stabled.Count >= GetMaxStabled( from ) ) + { + SayTo( from, 1042565 ); // You have too many pets in the stables! + } + else + { + Container bank = from.FindBankNoCreate(); + + if ( ( from.Backpack != null && from.Backpack.ConsumeTotal( typeof( Gold ), 30 ) ) || ( bank != null && bank.ConsumeTotal( typeof( Gold ), 30 ) ) ) + { + pet.ControlTarget = null; + pet.ControlOrder = OrderType.Stay; + pet.Internalize(); + + pet.SetControlMaster( null ); + pet.SummonMaster = null; + + pet.IsStabled = true; + pet.StabledBy = from; + + if ( Core.SE ) + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully happy + + from.Stabled.Add( pet ); + + SayTo( from, Core.AOS ? 1049677 : 502679 ); // [AOS: Your pet has been stabled.] Very well, thy pet is stabled. Thou mayst recover it by saying 'claim' to me. In one real world week, I shall sell it off if it is not claimed! + } + else + { + SayTo( from, 502677 ); // But thou hast not the funds in thy bank account! + } + } + } + + public void Claim( Mobile from ) + { + Claim( from, null ); + } + + public void Claim( Mobile from, string petName ) + { + if ( Deleted || !from.CheckAlive() ) + return; + + bool claimed = false; + int stabled = 0; + + bool claimByName = ( petName != null ); + + for ( int i = 0; i < from.Stabled.Count; ++i ) + { + BaseCreature pet = from.Stabled[i] as BaseCreature; + + if ( pet == null || pet.Deleted ) + { + pet.IsStabled = false; + pet.StabledBy = null; + from.Stabled.RemoveAt( i ); + --i; + continue; + } + + ++stabled; + + if ( claimByName && !Insensitive.Equals( pet.Name, petName ) ) + continue; + + if ( CanClaim( from, pet ) ) + { + DoClaim( from, pet ); + + from.Stabled.RemoveAt( i ); + + if (from is PlayerMobile) + ((PlayerMobile)from).AutoStabled.Remove(pet); + + --i; + + claimed = true; + } + else + { + SayTo( from, 1049612, pet.Name ); // ~1_NAME~ remained in the stables because you have too many followers. + } + } + + if ( claimed ) + SayTo( from, 1042559 ); // Here you go... and good day to you! + else if ( stabled == 0 ) + SayTo( from, 502671 ); // But I have no animals stabled with me at the moment! + else if ( claimByName ) + BeginClaimList( from ); + } + + public bool CanClaim( Mobile from, BaseCreature pet ) + { + return ((from.Followers + pet.ControlSlots) <= from.FollowersMax); + } + + private void DoClaim( Mobile from, BaseCreature pet ) + { + pet.SetControlMaster( from ); + + if ( pet.Summoned ) + pet.SummonMaster = from; + + pet.ControlTarget = from; + pet.ControlOrder = OrderType.Follow; + + pet.MoveToWorld( from.Location, from.Map ); + + pet.IsStabled = false; + pet.StabledBy = null; + + if ( Core.SE ) + pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully Happy + } + + public override bool HandlesOnSpeech( Mobile from ) + { + return true; + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( !e.Handled && e.HasKeyword( 0x0008 ) ) // *stable* + { + e.Handled = true; + + CloseClaimList( e.Mobile ); + BeginStable( e.Mobile ); + } + else if ( !e.Handled && e.HasKeyword( 0x0009 ) ) // *claim* + { + e.Handled = true; + + CloseClaimList( e.Mobile ); + + int index = e.Speech.IndexOf( ' ' ); + + if ( index != -1 ) + Claim( e.Mobile, e.Speech.Substring( index ).Trim() ); + else + Claim( e.Mobile ); + } + else + { + base.OnSpeech( e ); + } + } + + public AnimalTrainer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Architect.cs b/Scripts/Mobiles/Vendors/NPC/Architect.cs new file mode 100644 index 0000000..7b1b5c7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Architect.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Architect : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.TinkersGuild; } } + + [Constructable] + public Architect() : base( "l'Architecte" ) + { + } + + public override void InitSBInfo() + { + if ( !Core.AOS ) + m_SBInfos.Add( new SBHouseDeed() ); + + m_SBInfos.Add( new SBArchitect() ); + } + + public Architect( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Armorer.cs b/Scripts/Mobiles/Vendors/NPC/Armorer.cs new file mode 100644 index 0000000..420a8f0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Armorer.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Armorer : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Armorer() : base( "l'Armurier", "l'Armuriere" ) + { + SetSkill( SkillName.ArmsLore, 64.0, 100.0 ); + SetSkill( SkillName.Blacksmith, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + switch ( Utility.Random( 4 )) + { + case 0: + { + m_SBInfos.Add( new SBLeatherArmor() ); + m_SBInfos.Add( new SBStuddedArmor() ); + m_SBInfos.Add( new SBMetalShields() ); + m_SBInfos.Add( new SBPlateArmor() ); + m_SBInfos.Add( new SBHelmetArmor() ); + m_SBInfos.Add( new SBChainmailArmor() ); + m_SBInfos.Add( new SBRingmailArmor() ); + break; + } + case 1: + { + m_SBInfos.Add( new SBStuddedArmor() ); + m_SBInfos.Add( new SBLeatherArmor() ); + m_SBInfos.Add( new SBMetalShields() ); + m_SBInfos.Add( new SBHelmetArmor() ); + break; + } + case 2: + { + m_SBInfos.Add( new SBMetalShields() ); + m_SBInfos.Add( new SBPlateArmor() ); + m_SBInfos.Add( new SBHelmetArmor() ); + m_SBInfos.Add( new SBChainmailArmor() ); + m_SBInfos.Add( new SBRingmailArmor() ); + break; + } + case 3: + { + m_SBInfos.Add( new SBMetalShields() ); + m_SBInfos.Add( new SBHelmetArmor() ); + break; + } + } + if ( IsTokunoVendor ) + { + m_SBInfos.Add( new SBSELeatherArmor() ); + m_SBInfos.Add( new SBSEArmor() ); + } + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.Boots; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron( Utility.RandomYellowHue() ) ); + AddItem( new Server.Items.Bascinet() ); + } + + public Armorer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Baker.cs b/Scripts/Mobiles/Vendors/NPC/Baker.cs new file mode 100644 index 0000000..1cc6377 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Baker.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Baker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Baker() : base( "le Boulanger", "la Boulangere" ) + { + SetSkill( SkillName.Cooking, 75.0, 98.0 ); + SetSkill( SkillName.TasteID, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBBaker() ); + } + + public Baker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Bard.cs b/Scripts/Mobiles/Vendors/NPC/Bard.cs new file mode 100644 index 0000000..ee7d37a --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Bard.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Bard : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.BardsGuild; } } + + [Constructable] + public Bard() : base( "le Barde", "la Barde" ) + { + SetSkill( SkillName.Discordance, 64.0, 100.0 ); + SetSkill( SkillName.Musicianship, 64.0, 100.0 ); + SetSkill( SkillName.Peacemaking, 65.0, 88.0 ); + SetSkill( SkillName.Provocation, 60.0, 83.0 ); + SetSkill( SkillName.Archery, 36.0, 68.0 ); + SetSkill( SkillName.Swords, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBBard() ); + } + + public Bard( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs b/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs new file mode 100644 index 0000000..4fc94c0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Barkeeper.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Prompts; +using Server.Network; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class Barkeeper : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBBarkeeper() ); + } + + public override VendorShoeType ShoeType{ get{ return Utility.RandomBool() ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron(Utility.RandomBrightHue())); + } + + [Constructable] + public Barkeeper() : base( "le Barman", "la Barmaid" ) + { + } + + public Barkeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Beekeeper.cs b/Scripts/Mobiles/Vendors/NPC/Beekeeper.cs new file mode 100644 index 0000000..536ba45 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Beekeeper.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Beekeeper : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Beekeeper() : base( "l'Apiculteur", "l'Apicultrice" ) + { + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBBeekeeper() ); + } + + public override VendorShoeType ShoeType{ get{ return VendorShoeType.Boots; } } + + public Beekeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Blacksmith.cs b/Scripts/Mobiles/Vendors/NPC/Blacksmith.cs new file mode 100644 index 0000000..cd17f1d --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Blacksmith.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.BulkOrders; + +namespace Server.Mobiles +{ + public class Blacksmith : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.BlacksmithsGuild; } } + + [Constructable] + public Blacksmith() : base( "le Forgeron", "la Forgeronne" ) + { + SetSkill( SkillName.ArmsLore, 36.0, 68.0 ); + SetSkill( SkillName.Blacksmith, 65.0, 88.0 ); + SetSkill( SkillName.Fencing, 60.0, 83.0 ); + SetSkill( SkillName.Macing, 61.0, 93.0 ); + SetSkill( SkillName.Swords, 60.0, 83.0 ); + SetSkill( SkillName.Tactics, 60.0, 83.0 ); + SetSkill( SkillName.Parry, 61.0, 93.0 ); + } + + public override void InitSBInfo() + { + /*m_SBInfos.Add( new SBSmithTools() ); + + m_SBInfos.Add( new SBMetalShields() ); + m_SBInfos.Add( new SBWoodenShields() ); + + m_SBInfos.Add( new SBPlateArmor() ); + + m_SBInfos.Add( new SBHelmetArmor() ); + m_SBInfos.Add( new SBChainmailArmor() ); + m_SBInfos.Add( new SBRingmailArmor() ); + m_SBInfos.Add( new SBAxeWeapon() ); + m_SBInfos.Add( new SBPoleArmWeapon() ); + m_SBInfos.Add( new SBRangedWeapon() ); + + m_SBInfos.Add( new SBKnifeWeapon() ); + m_SBInfos.Add( new SBMaceWeapon() ); + m_SBInfos.Add( new SBSpearForkWeapon() ); + m_SBInfos.Add( new SBSwordWeapon() );*/ + + m_SBInfos.Add( new SBBlacksmith() ); + if ( IsTokunoVendor ) + { + m_SBInfos.Add( new SBSEArmor() ); + m_SBInfos.Add( new SBSEWeapons() ); + } + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.None; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = ( Utility.RandomBool() ? null : new Server.Items.RingmailChest() ); + + if ( item != null && !EquipItem( item ) ) + { + item.Delete(); + item = null; + } + + if ( item == null ) + AddItem( new Server.Items.FullApron() ); + + AddItem( new Server.Items.Bascinet() ); + AddItem( new Server.Items.SmithHammer() ); + } + /* Retrait des BODs Temporaire + #region Bulk Orders + public override Item CreateBulkOrder( Mobile from, bool fromContextMenu ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || 0.2 > Utility.RandomDouble()) ) + { + double theirSkill = pm.Skills[SkillName.Blacksmith].Base; + + if ( theirSkill >= 70.1 ) + pm.NextSmithBulkOrder = TimeSpan.FromHours( 6.0 ); + else if ( theirSkill >= 50.1 ) + pm.NextSmithBulkOrder = TimeSpan.FromHours( 2.0 ); + else + pm.NextSmithBulkOrder = TimeSpan.FromHours( 1.0 ); + + if ( theirSkill >= 70.1 && ((theirSkill - 40.0) / 300.0) > Utility.RandomDouble() ) + return new LargeSmithBOD(); + + return SmallSmithBOD.CreateRandomFor( from ); + } + + return null; + } + + public override bool IsValidBulkOrder( Item item ) + { + return ( item is SmallSmithBOD || item is LargeSmithBOD ); + } + + public override bool SupportsBulkOrders( Mobile from ) + { + return ( from is PlayerMobile && from.Skills[SkillName.Blacksmith].Base > 0 ); + } + + public override TimeSpan GetNextBulkOrder( Mobile from ) + { + if ( from is PlayerMobile ) + return ((PlayerMobile)from).NextSmithBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive( Mobile from ) + { + if( Core.SE && from is PlayerMobile ) + ((PlayerMobile)from).NextSmithBulkOrder = TimeSpan.Zero; + } + #endregion + */ + public Blacksmith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Bowyer.cs b/Scripts/Mobiles/Vendors/NPC/Bowyer.cs new file mode 100644 index 0000000..a4c2391 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Bowyer.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + [TypeAlias( "Server.Mobiles.Bower" )] + public class Bowyer : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Bowyer() : base( "l'Arctier", "l'Arctiere" ) + { + SetSkill( SkillName.Fletching, 80.0, 100.0 ); + SetSkill( SkillName.Archery, 80.0, 100.0 ); + } + + public override VendorShoeType ShoeType + { + get{ return Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Bow() ); + AddItem( new Server.Items.LeatherGorget() ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBBowyer() ); + m_SBInfos.Add( new SBRangedWeapon() ); + + if ( IsTokunoVendor ) + m_SBInfos.Add( new SBSEBowyer() ); + } + + public Bowyer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Butcher.cs b/Scripts/Mobiles/Vendors/NPC/Butcher.cs new file mode 100644 index 0000000..4554712 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Butcher.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Butcher : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Butcher() : base( "le Boucher", "la Bouchere" ) + { + SetSkill( SkillName.Anatomy, 45.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBButcher() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron() ); + AddItem( new Server.Items.Cleaver() ); + } + + public Butcher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Carpenter.cs b/Scripts/Mobiles/Vendors/NPC/Carpenter.cs new file mode 100644 index 0000000..2e8c483 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Carpenter.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Carpenter : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.TinkersGuild; } } + + [Constructable] + public Carpenter() : base( "le Charpentier", "la Charpentiere" ) + { + SetSkill( SkillName.Carpentry, 85.0, 100.0 ); + SetSkill( SkillName.Lumberjacking, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBStavesWeapon() ); + m_SBInfos.Add( new SBCarpenter() ); + m_SBInfos.Add( new SBWoodenShields() ); + + if ( IsTokunoVendor ) + m_SBInfos.Add( new SBSECarpenter() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron() ); + } + + public Carpenter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Cobbler.cs b/Scripts/Mobiles/Vendors/NPC/Cobbler.cs new file mode 100644 index 0000000..a3be29f --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Cobbler.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Cobbler : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Cobbler() : base( "le Cordonnier", "la Cordonniere" ) + { + SetSkill( SkillName.Tailoring, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBCobbler() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; } + } + + public Cobbler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Cook.cs b/Scripts/Mobiles/Vendors/NPC/Cook.cs new file mode 100644 index 0000000..dcd795b --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Cook.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Cook : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Cook() : base( "le Cuisinier", "la Cuisiniere" ) + { + SetSkill( SkillName.Cooking, 90.0, 100.0 ); + SetSkill( SkillName.TasteID, 75.0, 98.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBCook() ); + + if ( IsTokunoVendor ) + m_SBInfos.Add( new SBSECook() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron() ); + } + + public Cook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs b/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs new file mode 100644 index 0000000..827f853 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/CustomHairstylist.cs @@ -0,0 +1,588 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Server.Mobiles +{ + public class CustomHairstylist : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool ClickTitle{ get{ return false; } } + + public override bool IsActiveBuyer{ get{ return false; } } + public override bool IsActiveSeller{ get{ return true; } } + + public override bool OnBuyItems( Mobile buyer, List list ) + { + return false; + } + + public static readonly object From = new object(); + public static readonly object Vendor = new object(); + public static readonly object Price = new object(); + + private static HairstylistBuyInfo[] m_SellList = new HairstylistBuyInfo[] + { + new HairstylistBuyInfo( "Coupe de cheveux (250 pi�ces)", 250, false, typeof( ChangeHairstyleGump ), + new object[] { From, Vendor, Price, false, ChangeHairstyleEntry.HairEntries } ), + new HairstylistBuyInfo( "Rasage de la barbe (250 pi�ces)" , 250, true, typeof( ChangeHairstyleGump ), + new object[] { From, Vendor, Price, true, ChangeHairstyleEntry.BeardEntries } ), + new HairstylistBuyInfo( "Coloration normale (50 pi�ces)", 50, false, typeof( ChangeHairHueGump ), + new object[] { From, Vendor, Price, true, true, ChangeHairHueEntry.RegularEntries } ), + new HairstylistBuyInfo( "Coloration brillante (50000 pi�ces)", 50000, false, typeof( ChangeHairHueGump ), + new object[] { From, Vendor, Price, true, true, ChangeHairHueEntry.BrightEntries } ), + new HairstylistBuyInfo( "Coloration normale des cheveux uniquement (375 pi�ces)", 375, false, typeof( ChangeHairHueGump ), + new object[] { From, Vendor, Price, true, false, ChangeHairHueEntry.RegularEntries } ), + new HairstylistBuyInfo( "Coloration normale de la barbe uniquement (375 pi�ces)", 375, true, typeof( ChangeHairHueGump ), + new object[] { From, Vendor, Price, false, true, ChangeHairHueEntry.RegularEntries } ), + new HairstylistBuyInfo( "Coloration brillante des cheveux uniquement (75000 pi�ces)", 75000, false, typeof( ChangeHairHueGump ), + new object[] { From, Vendor, Price, true, false, ChangeHairHueEntry.BrightEntries } ), + new HairstylistBuyInfo( "Coloration brillante de la barbe uniquement (75000 pi�ces)", 75000, true, typeof( ChangeHairHueGump ), + new object[] { From, Vendor, Price, false, true, ChangeHairHueEntry.BrightEntries } ) + }; + + public override void VendorBuy( Mobile from ) + { + from.SendGump( new HairstylistBuyGump( from, this, m_SellList ) ); + } + + [Constructable] + public CustomHairstylist() : base( "le Coiffeur", "la Coiffeuse" ) + { + } + + public override int GetHairHue() + { + return Utility.RandomBrightHue(); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Robe( Utility.RandomPinkHue() ) ); + } + + public override void InitSBInfo() + { + } + + public CustomHairstylist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class HairstylistBuyInfo + { + private int m_Title; + private string m_TitleString; + private int m_Price; + private bool m_FacialHair; + private Type m_GumpType; + private object[] m_GumpArgs; + + public int Title{ get{ return m_Title; } } + public string TitleString{ get{ return m_TitleString; } } + public int Price{ get{ return m_Price; } } + public bool FacialHair{ get{ return m_FacialHair; } } + public Type GumpType{ get{ return m_GumpType; } } + public object[] GumpArgs{ get{ return m_GumpArgs; } } + + public HairstylistBuyInfo( int title, int price, bool facialHair, Type gumpType, object[] args ) + { + m_Title = title; + m_Price = price; + m_FacialHair = facialHair; + m_GumpType = gumpType; + m_GumpArgs = args; + } + + public HairstylistBuyInfo( string title, int price, bool facialHair, Type gumpType, object[] args ) + { + m_TitleString = title; + m_Price = price; + m_FacialHair = facialHair; + m_GumpType = gumpType; + m_GumpArgs = args; + } + } + + public class HairstylistBuyGump : Gump + { + private Mobile m_From; + private Mobile m_Vendor; + private HairstylistBuyInfo[] m_SellList; + + public HairstylistBuyGump( Mobile from, Mobile vendor, HairstylistBuyInfo[] sellList ) : base( 50, 50 ) + { + m_From = from; + m_Vendor = vendor; + m_SellList = sellList; + + from.CloseGump( typeof( HairstylistBuyGump ) ); + from.CloseGump( typeof( ChangeHairHueGump ) ); + from.CloseGump( typeof( ChangeHairstyleGump ) ); + + bool isFemale = ( from.Female || from.Body.IsFemale ); + + int balance = Banker.GetBalance( from ); + int canAfford = 0; + + for ( int i = 0; i < sellList.Length; ++i ) + { + if ( balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale) ) + ++canAfford; + } + + AddPage( 0 ); + + AddBackground( 50, 10, 450, 100 + (canAfford * 25), 2600 ); + + AddHtmlLocalized( 100, 40, 350, 20, 1018356, false, false ); // Choose your hairstyle change: + + int index = 0; + + for ( int i = 0; i < sellList.Length; ++i ) + { + if ( balance >= sellList[i].Price && (!sellList[i].FacialHair || !isFemale) ) + { + if ( sellList[i].TitleString != null ) + AddHtml( 140, 75 + (index * 25), 300, 20, sellList[i].TitleString, false, false ); + else + AddHtmlLocalized( 140, 75 + (index * 25), 300, 20, sellList[i].Title, false, false ); + + AddButton( 100, 75 + (index++ * 25), 4005, 4007, 1 + i, GumpButtonType.Reply, 0 ); + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_SellList.Length ) + { + HairstylistBuyInfo buyInfo = m_SellList[index]; + + int balance = Banker.GetBalance( m_From ); + + bool isFemale = ( m_From.Female || m_From.Body.IsFemale ); + + if ( buyInfo.FacialHair && isFemale ) + { + // You cannot place facial hair on a woman! + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1010639, m_From.NetState ); + } + else if ( balance >= buyInfo.Price ) + { + try + { + object[] origArgs = buyInfo.GumpArgs; + object[] args = new object[origArgs.Length]; + + for ( int i = 0; i < args.Length; ++i ) + { + if ( origArgs[i] == CustomHairstylist.Price ) + args[i] = m_SellList[index].Price; + else if ( origArgs[i] == CustomHairstylist.From ) + args[i] = m_From; + else if ( origArgs[i] == CustomHairstylist.Vendor ) + args[i] = m_Vendor; + else + args[i] = origArgs[i]; + } + + Gump g = Activator.CreateInstance( buyInfo.GumpType, args ) as Gump; + + m_From.SendGump( g ); + } + catch + { + } + } + else + { + // You cannot afford my services for that style. + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1042293, m_From.NetState ); + } + } + } + } + + public class ChangeHairHueEntry + { + private string m_Name; + private int[] m_Hues; + + public string Name{ get{ return m_Name; } } + public int[] Hues{ get{ return m_Hues; } } + + public ChangeHairHueEntry( string name, int[] hues ) + { + m_Name = name; + m_Hues = hues; + } + + public ChangeHairHueEntry( string name, int start, int count ) + { + m_Name = name; + + m_Hues = new int[count]; + + for ( int i = 0; i < count; ++i ) + m_Hues[i] = start + i; + } + + public static readonly ChangeHairHueEntry[] BrightEntries = new ChangeHairHueEntry[] + { + new ChangeHairHueEntry( "*****", 12, 10 ), + new ChangeHairHueEntry( "*****", 32, 5 ), + new ChangeHairHueEntry( "*****", 38, 8 ), + new ChangeHairHueEntry( "*****", 54, 3 ), + new ChangeHairHueEntry( "*****", 62, 10 ), + new ChangeHairHueEntry( "*****", 81, 2 ), + new ChangeHairHueEntry( "*****", 89, 2 ), + new ChangeHairHueEntry( "*****", 1153, 2 ) + }; + + public static readonly ChangeHairHueEntry[] RegularEntries = new ChangeHairHueEntry[] + { + new ChangeHairHueEntry( "*****", 1602, 26 ), + new ChangeHairHueEntry( "*****", 1628, 27 ), + new ChangeHairHueEntry( "*****", 1502, 32 ), + new ChangeHairHueEntry( "*****", 1302, 32 ), + new ChangeHairHueEntry( "*****", 1402, 32 ), + new ChangeHairHueEntry( "*****", 1202, 24 ), + new ChangeHairHueEntry( "*****", 2402, 29 ), + new ChangeHairHueEntry( "*****", 2213, 6 ), + new ChangeHairHueEntry( "*****", 1102, 8 ), + new ChangeHairHueEntry( "*****", 1110, 8 ), + new ChangeHairHueEntry( "*****", 1118, 16 ), + new ChangeHairHueEntry( "*****", 1134, 16 ) + }; + } + + public class ChangeHairHueGump : Gump + { + private Mobile m_From; + private Mobile m_Vendor; + private int m_Price; + private bool m_Hair; + private bool m_FacialHair; + private ChangeHairHueEntry[] m_Entries; + + public ChangeHairHueGump( Mobile from, Mobile vendor, int price, bool hair, bool facialHair, ChangeHairHueEntry[] entries ) : base( 50, 50 ) + { + m_From = from; + m_Vendor = vendor; + m_Price = price; + m_Hair = hair; + m_FacialHair = facialHair; + m_Entries = entries; + + from.CloseGump( typeof( HairstylistBuyGump ) ); + from.CloseGump( typeof( ChangeHairHueGump ) ); + from.CloseGump( typeof( ChangeHairstyleGump ) ); + + AddPage( 0 ); + + AddBackground( 100, 10, 350, 370, 2600 ); + AddBackground( 120, 54, 110, 270, 5100 ); + + AddHtmlLocalized( 155, 25, 240, 30, 1011013, false, false ); //
Hair Color Selection Menu
+ + AddHtmlLocalized( 150, 330, 220, 35, 1011014, false, false ); // Dye my hair this color! + AddButton( 380, 330, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + + for ( int i = 0; i < entries.Length; ++i ) + { + ChangeHairHueEntry entry = entries[i]; + + AddLabel( 130, 59 + (i * 22), entry.Hues[0] - 1, entry.Name ); + AddButton( 207, 60 + (i * 22), 5224, 5224, 0, GumpButtonType.Page, 1 + i ); + } + + for ( int i = 0; i < entries.Length; ++i ) + { + ChangeHairHueEntry entry = entries[i]; + int[] hues = entry.Hues; + string name = entry.Name; + + AddPage( 1 + i ); + + for ( int j = 0; j < hues.Length; ++j ) + { + AddLabel( 278 + ((j / 16) * 80), 52 + ((j % 16) * 17), hues[j] - 1, name ); + AddRadio( 260 + ((j / 16) * 80), 52 + ((j % 16) * 17), 210, 211, false, (j * entries.Length) + i ); + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0] % m_Entries.Length; + int offset = switches[0] / m_Entries.Length; + + if ( index >= 0 && index < m_Entries.Length ) + { + if ( offset >= 0 && offset < m_Entries[index].Hues.Length ) + { + if ( m_Hair && m_From.HairItemID > 0 || m_FacialHair && m_From.FacialHairItemID > 0 ) + { + if ( !Banker.Withdraw( m_From, m_Price ) ) + { + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1042293, m_From.NetState ); // You cannot afford my services for that style. + return; + } + + int hue = m_Entries[index].Hues[offset]; + + if ( m_Hair ) + m_From.HairHue = hue; + + if ( m_FacialHair ) + m_From.FacialHairHue = hue; + } + else + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 502623, m_From.NetState ); // You have no hair to dye and you cannot use this. + } + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1013009, m_From.NetState ); + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1013009, m_From.NetState ); + } + } + } + + public class ChangeHairstyleEntry + { + private int m_ItemID; + private int m_GumpID; + private int m_X, m_Y; + + public int ItemID{ get{ return m_ItemID; } } + public int GumpID{ get{ return m_GumpID; } } + public int X{ get{ return m_X; } } + public int Y{ get{ return m_Y; } } + + public ChangeHairstyleEntry( int gumpID, int x, int y, int itemID ) + { + m_GumpID = gumpID; + m_X = x; + m_Y = y; + m_ItemID = itemID; + } + + public static readonly ChangeHairstyleEntry[] HairEntries = new ChangeHairstyleEntry[] + { + new ChangeHairstyleEntry( 50700, 70 - 137, 20 - 60, 0x203B ), + new ChangeHairstyleEntry( 60710, 193 - 260, 18 - 60, 0x2045 ), + new ChangeHairstyleEntry( 50703, 316 - 383, 25 - 60, 0x2044 ), + new ChangeHairstyleEntry( 60701, 70 - 137, 75 - 125, 0x203C ), + new ChangeHairstyleEntry( 60900, 193 - 260, 85 - 125, 0x2047 ), + new ChangeHairstyleEntry( 60713, 320 - 383, 85 - 125, 0x204A ), + new ChangeHairstyleEntry( 60702, 70 - 137, 140 - 190, 0x203D ), + new ChangeHairstyleEntry( 60902, 193 - 260, 140 - 190, 0x2049 ), + new ChangeHairstyleEntry( 60901, 315 - 383, 150 - 190, 0x2048 ), + new ChangeHairstyleEntry( 0, 0, 0, 0 ) + }; + + public static readonly ChangeHairstyleEntry[] BeardEntries = new ChangeHairstyleEntry[] + { + new ChangeHairstyleEntry( 50800, 120 - 187, 30 - 80, 0x2040 ), + new ChangeHairstyleEntry( 50904, 243 - 310, 33 - 80, 0x204B ), + new ChangeHairstyleEntry( 50906, 120 - 187, 100 - 150, 0x204D ), + new ChangeHairstyleEntry( 50801, 243 - 310, 95 - 150, 0x203E ), + new ChangeHairstyleEntry( 50802, 120 - 187, 173 - 220, 0x203F ), + new ChangeHairstyleEntry( 50905, 243 - 310, 165 - 220, 0x204C ), + new ChangeHairstyleEntry( 50808, 120 - 187, 242 - 290, 0x2041 ), + new ChangeHairstyleEntry( 0, 0, 0, 0 ) + }; + } + + public class ChangeHairstyleGump : Gump + { + private Mobile m_From; + private Mobile m_Vendor; + private int m_Price; + private bool m_FacialHair; + private ChangeHairstyleEntry[] m_Entries; + + public ChangeHairstyleGump( Mobile from, Mobile vendor, int price, bool facialHair, ChangeHairstyleEntry[] entries ) : base( 50, 50 ) + { + m_From = from; + m_Vendor = vendor; + m_Price = price; + m_FacialHair = facialHair; + m_Entries = entries; + + from.CloseGump( typeof( HairstylistBuyGump ) ); + from.CloseGump( typeof( ChangeHairHueGump ) ); + from.CloseGump( typeof( ChangeHairstyleGump ) ); + + int tableWidth = ( m_FacialHair ? 2 : 3 ); + int tableHeight = ( (entries.Length + tableWidth - ( m_FacialHair ? 1 : 2 )) / tableWidth ); + int offsetWidth = 123; + int offsetHeight = ( m_FacialHair ? 70 : 65 ); + + AddPage( 0 ); + + AddBackground( 0, 0, 81 + (tableWidth * offsetWidth), 105 + (tableHeight * offsetHeight), 2600 ); + + AddButton( 45, 45 + (tableHeight * offsetHeight), 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 77, 45 + (tableHeight * offsetHeight), 90, 35, 1006044, false, false ); // Ok + + AddButton( 81 + (tableWidth * offsetWidth) - 180, 45 + (tableHeight * offsetHeight), 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 81 + (tableWidth * offsetWidth) - 148, 45 + (tableHeight * offsetHeight), 90, 35, 1006045, false, false ); // Cancel + + if ( !facialHair ) + AddHtmlLocalized( 50, 15, 350, 20, 1018353, false, false ); //
New Hairstyle
+ else + AddHtmlLocalized( 55, 15, 200, 20, 1018354, false, false ); //
New Beard
+ + for ( int i = 0; i < entries.Length; ++i ) + { + int xTable = i % tableWidth; + int yTable = i / tableWidth; + + if ( entries[i].GumpID != 0 ) + { + AddRadio( 40 + (xTable * offsetWidth), 70 + (yTable * offsetHeight), 208, 209, false, i ); + AddBackground( 87 + (xTable * offsetWidth), 50 + (yTable * offsetHeight), 50, 50, 2620 ); + AddImage( 87 + (xTable * offsetWidth) + entries[i].X, 50 + (yTable * offsetHeight) + entries[i].Y, entries[i].GumpID ); + } + else if ( !facialHair ) + { + AddRadio( 40 + ((xTable + 1) * offsetWidth), 240, 208, 209, false, i ); + AddHtmlLocalized( 60 + ((xTable + 1) * offsetWidth), 240, 85, 35, 1011064, false, false ); // Bald + } + else + { + AddRadio( 40 + (xTable * offsetWidth), 70 + (yTable * offsetHeight), 208, 209, false, i ); + AddHtmlLocalized( 60 + (xTable * offsetWidth), 70 + (yTable * offsetHeight), 85, 35, 1011064, false, false ); // Bald + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if ( m_FacialHair && (m_From.Female || m_From.Body.IsFemale) ) + return; + + if ( m_From.Race == Race.Elf || m_From.IsElfBody ) // Scriptiz : "|| IsElfBody" pour l'apparence elfique + { + m_From.SendMessage( "This isn't implemented for elves yet. Sorry!" ); + return; + } + + if ( info.ButtonID == 1 ) + { + int[] switches = info.Switches; + + if ( switches.Length > 0 ) + { + int index = switches[0]; + + if ( index >= 0 && index < m_Entries.Length ) + { + ChangeHairstyleEntry entry = m_Entries[index]; + + if ( m_From is PlayerMobile ) + ((PlayerMobile)m_From).SetHairMods( -1, -1 ); + + int hairID = m_From.HairItemID; + int facialHairID = m_From.FacialHairItemID; + + if ( entry.ItemID == 0 ) + { + if ( m_FacialHair ? (facialHairID == 0) : (hairID == 0) ) + return; + + if ( Banker.Withdraw( m_From, m_Price ) ) + { + if ( m_FacialHair ) + m_From.FacialHairItemID = 0; + else + m_From.HairItemID = 0; + } + else + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1042293, m_From.NetState ); // You cannot afford my services for that style. + } + else + { + if ( m_FacialHair ) + { + if ( facialHairID > 0 && facialHairID == entry.ItemID ) + return; + } + else + { + if ( hairID > 0 && hairID == entry.ItemID ) + return; + } + + if ( Banker.Withdraw( m_From, m_Price ) ) + { + if ( m_FacialHair ) + m_From.FacialHairItemID = entry.ItemID; + else + m_From.HairItemID = entry.ItemID; + } + else + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1042293, m_From.NetState ); // You cannot afford my services for that style. + } + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1013009, m_From.NetState ); + } + } + else + { + // You decide not to change your hairstyle. + m_Vendor.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1013009, m_From.NetState ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Farmer.cs b/Scripts/Mobiles/Vendors/NPC/Farmer.cs new file mode 100644 index 0000000..15715cd --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Farmer.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Farmer : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Farmer() : base( "le Fermier", "la Fermiere" ) + { + SetSkill( SkillName.Lumberjacking, 36.0, 68.0 ); + SetSkill( SkillName.TasteID, 36.0, 68.0 ); + SetSkill( SkillName.Cooking, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBFarmer() ); + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.ThighBoots; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.WideBrimHat( Utility.RandomNeutralHue() ) ); + } + + public Farmer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Fisherman.cs b/Scripts/Mobiles/Vendors/NPC/Fisherman.cs new file mode 100644 index 0000000..b6fea80 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Fisherman.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Fisherman : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.FishermensGuild; } } + + [Constructable] + public Fisherman() : base( "le Pecheur", "la Pecheuse" ) + { + SetSkill( SkillName.Fishing, 75.0, 98.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBFisherman() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.FishingPole() ); + } + + public Fisherman( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Furtrader.cs b/Scripts/Mobiles/Vendors/NPC/Furtrader.cs new file mode 100644 index 0000000..6df6b7d --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Furtrader.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Furtrader : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Furtrader() : base( "le Fourreur", "la Fourreuse" ) + { + SetSkill( SkillName.Camping, 55.0, 78.0 ); + //SetSkill( SkillName.Alchemy, 60.0, 83.0 ); + SetSkill( SkillName.AnimalLore, 85.0, 100.0 ); + SetSkill( SkillName.Cooking, 45.0, 68.0 ); + SetSkill( SkillName.Tracking, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBFurtrader() ); + } + + public Furtrader( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Glassblower.cs b/Scripts/Mobiles/Vendors/NPC/Glassblower.cs new file mode 100644 index 0000000..0854e5b --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Glassblower.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + [TypeAlias( "Server.Mobiles.GargoyleAlchemist" )] + public class Glassblower : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } } + + [Constructable] + public Glassblower() : base( "le Souffleur de verre", "la Souffleuse de verre" ) + { + SetSkill( SkillName.Alchemy, 85.0, 100.0 ); + SetSkill( SkillName.TasteID, 85.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBGlassblower() ); + m_SBInfos.Add( new SBAlchemist() ); + } + + public Glassblower( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Body == 0x2F2 ) + Body = 0x2F6; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/GolemCrafter.cs b/Scripts/Mobiles/Vendors/NPC/GolemCrafter.cs new file mode 100644 index 0000000..87e4615 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/GolemCrafter.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class GolemCrafter : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public GolemCrafter() : base( "le Fabriquant de Golems", "la Frabriquante de Golems" ) + { + SetSkill( SkillName.Lockpicking, 60.0, 83.0 ); + SetSkill( SkillName.RemoveTrap, 75.0, 98.0 ); + SetSkill( SkillName.Tinkering, 64.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBTinker() ); + m_SBInfos.Add( new SBVagabond() ); + } + + public GolemCrafter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs new file mode 100644 index 0000000..0e3a3ce --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/BardGuildmaster.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class BardGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.BardsGuild; } } + + [Constructable] + public BardGuildmaster() : base( "le maitre de la Guilde des bardes", "la maitresse de la Guilde des bardes" ) + { + SetSkill( SkillName.Archery, 80.0, 100.0 ); + SetSkill( SkillName.Discordance, 80.0, 100.0 ); + SetSkill( SkillName.Musicianship, 80.0, 100.0 ); + SetSkill( SkillName.Peacemaking, 80.0, 100.0 ); + SetSkill( SkillName.Provocation, 80.0, 100.0 ); + SetSkill( SkillName.Swords, 80.0, 100.0 ); + } + + public BardGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs new file mode 100644 index 0000000..550ba66 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + public abstract class BaseGuildmaster : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override bool IsActiveVendor{ get{ return false; } } + + public override bool ClickTitle{ get{ return false; } } + + public virtual int JoinCost{ get{ return 500; } } + + public virtual TimeSpan JoinAge{ get{ return TimeSpan.FromDays( 0.0 ); } } + public virtual TimeSpan JoinGameAge{ get{ return TimeSpan.FromDays( 2.0 ); } } + public virtual TimeSpan QuitAge{ get{ return TimeSpan.FromDays( 7.0 ); } } + public virtual TimeSpan QuitGameAge{ get{ return TimeSpan.FromDays( 4.0 ); } } + + public override void InitSBInfo() + { + } + + public virtual bool CheckCustomReqs( PlayerMobile pm ) + { + return true; + } + + public virtual void SayGuildTo( Mobile m ) + { + SayTo( m, 1008055 + (int)NpcGuild ); + } + + public virtual void SayWelcomeTo( Mobile m ) + { + SayTo( m, 1008054 ); // Welcome to the guild! Thou shalt find that fellow members shall grant thee lower prices in shops. + } + + public virtual void SayPriceTo( Mobile m ) + { + m.Send( new MessageLocalizedAffix( Serial, Body, MessageType.Regular, SpeechHue, 3, 1008052, Name, AffixType.Append, JoinCost.ToString(), "" ) ); + } + + public virtual bool WasNamed( string speech ) + { + string name = this.Name; + + return ( name != null && Insensitive.StartsWith( speech, name ) ); + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.InRange( this.Location, 2 ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !e.Handled && from is PlayerMobile && from.InRange( this.Location, 2 ) && WasNamed( e.Speech ) ) + { + PlayerMobile pm = (PlayerMobile)from; + + if ( e.HasKeyword( 0x0004 ) ) // *join* | *member* + { + if ( pm.NpcGuild == this.NpcGuild ) + SayTo( from, 501047 ); // Thou art already a member of our guild. + else if ( pm.NpcGuild != NpcGuild.None ) + SayTo( from, 501046 ); // Thou must resign from thy other guild first. + else if ( pm.GameTime < JoinGameAge || (pm.CreationTime + JoinAge) > DateTime.Now ) + SayTo( from, 501048 ); // You are too young to join my guild... + else if ( CheckCustomReqs( pm ) ) + SayPriceTo( from ); + + e.Handled = true; + } + else if ( e.HasKeyword( 0x0005 ) ) // *resign* | *quit* + { + if ( pm.NpcGuild != this.NpcGuild ) + { + SayTo( from, 501052 ); // Thou dost not belong to my guild! + } + else if ( (pm.NpcGuildJoinTime + QuitAge) > DateTime.Now || (pm.NpcGuildGameTime + QuitGameAge) > pm.GameTime ) + { + SayTo( from, 501053 ); // You just joined my guild! You must wait a week to resign. + } + else + { + SayTo( from, 501054 ); // I accept thy resignation. + pm.NpcGuild = NpcGuild.None; + } + + e.Handled = true; + } + } + + base.OnSpeech( e ); + } + + public override bool OnGoldGiven( Mobile from, Gold dropped ) + { + if ( from is PlayerMobile && dropped.Amount == JoinCost ) + { + PlayerMobile pm = (PlayerMobile)from; + + if ( pm.NpcGuild == this.NpcGuild ) + { + SayTo( from, 501047 ); // Thou art already a member of our guild. + } + else if ( pm.NpcGuild != NpcGuild.None ) + { + SayTo( from, 501046 ); // Thou must resign from thy other guild first. + } + else if ( pm.GameTime < JoinGameAge || (pm.CreationTime + JoinAge) > DateTime.Now ) + { + SayTo( from, 501048 ); // You are too young to join my guild... + } + else if ( CheckCustomReqs( pm ) ) + { + SayWelcomeTo( from ); + + pm.NpcGuild = this.NpcGuild; + pm.NpcGuildJoinTime = DateTime.Now; + pm.NpcGuildGameTime = pm.GameTime; + + dropped.Delete(); + return true; + } + + return false; + } + + return base.OnGoldGiven( from, dropped ); + } + + public BaseGuildmaster( string title, string ftitle ) : base( title, ftitle ) + { + Title = (Female ? ftitle : title); + } + + public BaseGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs new file mode 100644 index 0000000..30ecde2 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/BlacksmithGuildmaster.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class BlacksmithGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.BlacksmithsGuild; } } + + public override bool IsActiveVendor{ get{ return true; } } + + public override bool ClickTitle{ get{ return true; } } + + [Constructable] + public BlacksmithGuildmaster() + : base("le maitre de la Guilde des forgerons", "la maitresse de la Guilde des forgerons") + { + SetSkill( SkillName.ArmsLore, 65.0, 88.0 ); + SetSkill( SkillName.Blacksmith, 90.0, 100.0 ); + SetSkill( SkillName.Macing, 36.0, 68.0 ); + SetSkill( SkillName.Parry, 36.0, 68.0 ); + } + public override void InitSBInfo() + { + SBInfos.Add( new SBBlacksmith() ); + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.ThighBoots; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = ( Utility.RandomBool() ? null : new Server.Items.RingmailChest() ); + + if ( item != null && !EquipItem( item ) ) + { + item.Delete(); + item = null; + } + + if ( item == null ) + AddItem( new Server.Items.FullApron() ); + + AddItem( new Server.Items.Bascinet() ); + AddItem( new Server.Items.SmithHammer() ); + } + + public BlacksmithGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs new file mode 100644 index 0000000..259f23b --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/FisherGuildmaster.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class FisherGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.FishermensGuild; } } + + [Constructable] + public FisherGuildmaster() + : base("le maitre de la Guilde des pecheurs", "la maitresse de la Guilde des pecheurs") + { + SetSkill( SkillName.Fishing, 80.0, 100.0 ); + } + + public FisherGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs new file mode 100644 index 0000000..8a30ad7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/HealerGuildmaster.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class HealerGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.HealersGuild; } } + + [Constructable] + public HealerGuildmaster() + : base("le maitre de la Guilde des soigneurs", "la maitresse de la Guilde des soigneurs") + { + SetSkill( SkillName.Anatomy, 85.0, 100.0 ); + SetSkill( SkillName.Healing, 90.0, 100.0 ); + SetSkill( SkillName.Forensics, 75.0, 98.0 ); + SetSkill( SkillName.MagicResist, 75.0, 98.0 ); + SetSkill( SkillName.SpiritSpeak, 65.0, 88.0 ); + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Robe( Utility.RandomYellowHue() ) ); + } + + public HealerGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs new file mode 100644 index 0000000..ba5a9db --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/MageGuildmaster.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class MageGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } } + + [Constructable] + public MageGuildmaster() + : base("le maitre de la Guilde des mages", "la maitresse de la Guilde des mages") + { + SetSkill( SkillName.EvalInt, 85.0, 100.0 ); + SetSkill( SkillName.Inscribe, 65.0, 88.0 ); + SetSkill( SkillName.MagicResist, 64.0, 100.0 ); + SetSkill( SkillName.Magery, 90.0, 100.0 ); + SetSkill( SkillName.Wrestling, 60.0, 83.0 ); + SetSkill( SkillName.Meditation, 85.0, 100.0 ); + SetSkill( SkillName.Macing, 36.0, 68.0 ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Robe( Utility.RandomBlueHue() ) ); + AddItem( new Server.Items.GnarledStaff() ); + } + + public MageGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs new file mode 100644 index 0000000..ec9c63b --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/MerchantGuildmaster.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class MerchantGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.MerchantsGuild; } } + + [Constructable] + public MerchantGuildmaster() + : base("le maitre de la Guilde des marchands", "la maitresse de la Guilde des marchands") + { + SetSkill( SkillName.ItemID, 85.0, 100.0 ); + SetSkill( SkillName.ArmsLore, 85.0, 100.0 ); + } + + public MerchantGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs new file mode 100644 index 0000000..66f8b78 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/MinerGuildmaster.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class MinerGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.MinersGuild; } } + + [Constructable] + public MinerGuildmaster() + : base("le maitre de la Guilde des mineurs", "la maitresse de la Guilde des mineurs") + { + SetSkill( SkillName.ItemID, 60.0, 83.0 ); + SetSkill( SkillName.Mining, 90.0, 100.0 ); + } + + public MinerGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs new file mode 100644 index 0000000..7431d3d --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/RangerGuildmaster.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class RangerGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.RangersGuild; } } + + [Constructable] + public RangerGuildmaster() + : base("le maitre de la Guilde des rodeurs", "la maitresse de la Guilde des rodeurs") + { + SetSkill( SkillName.AnimalLore, 64.0, 100.0 ); + SetSkill( SkillName.Camping, 75.0, 98.0 ); + SetSkill( SkillName.Hiding, 75.0, 98.0 ); + SetSkill( SkillName.MagicResist, 75.0, 98.0 ); + SetSkill( SkillName.Tactics, 65.0, 88.0 ); + SetSkill( SkillName.Archery, 90.0, 100.0 ); + SetSkill( SkillName.Tracking, 90.0, 100.0 ); + SetSkill( SkillName.Stealth, 60.0, 83.0 ); + SetSkill( SkillName.Fencing, 36.0, 68.0 ); + SetSkill( SkillName.Herding, 36.0, 68.0 ); + SetSkill( SkillName.Swords, 45.0, 68.0 ); + } + + public RangerGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs new file mode 100644 index 0000000..540e625 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/TailorGuildmaster.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class TailorGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.TailorsGuild; } } + + [Constructable] + public TailorGuildmaster() + : base("le maitre de la Guilde des couturiers", "la maitresse de la Guilde des couturiers") + { + SetSkill( SkillName.Tailoring, 90.0, 100.0 ); + } + + public TailorGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs new file mode 100644 index 0000000..84af81d --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/ThiefGuildmaster.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class ThiefGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.ThievesGuild; } } + + public override TimeSpan JoinAge{ get{ return TimeSpan.FromDays( 7.0 ); } } + + [Constructable] + public ThiefGuildmaster() + : base("le maitre de la Guilde des voleurs", "la maitresse de la Guilde des voleurs") + { + SetSkill( SkillName.DetectHidden, 75.0, 98.0 ); + SetSkill( SkillName.Hiding, 65.0, 88.0 ); + SetSkill( SkillName.Lockpicking, 85.0, 100.0 ); + SetSkill( SkillName.Snooping, 90.0, 100.0 ); + SetSkill( SkillName.Poisoning, 60.0, 83.0 ); + SetSkill( SkillName.Stealing, 90.0, 100.0 ); + SetSkill( SkillName.Fencing, 75.0, 98.0 ); + SetSkill( SkillName.Stealth, 85.0, 100.0 ); + SetSkill( SkillName.RemoveTrap, 85.0, 100.0 ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + if ( Utility.RandomBool() ) + AddItem( new Server.Items.Kryss() ); + else + AddItem( new Server.Items.Dagger() ); + } + + public override bool CheckCustomReqs( PlayerMobile pm ) + { + if ( pm.Young ) + { + SayTo( pm, 502089 ); // You cannot be a member of the Thieves' Guild while you are Young. + return false; + } + else if ( pm.Kills > 0 ) + { + SayTo( pm, 501050 ); // This guild is for cunning thieves, not oafish cutthroats. + return false; + } + else if ( pm.Skills[SkillName.Stealing].Base < 60.0 ) + { + SayTo( pm, 501051 ); // You must be at least a journeyman pickpocket to join this elite organization. + return false; + } + + return true; + } + + public override void SayWelcomeTo( Mobile m ) + { + SayTo( m, 1008053 ); // Welcome to the guild! Stay to the shadows, friend. + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.InRange( this.Location, 2 ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !e.Handled && from is PlayerMobile && from.InRange( this.Location, 2 ) && e.HasKeyword( 0x1F ) ) // *disguise* + { + PlayerMobile pm = (PlayerMobile)from; + + if ( pm.NpcGuild == NpcGuild.ThievesGuild ) + SayTo( from, 501839 ); // That particular item costs 700 gold pieces. + else + SayTo( from, 501838 ); // I don't know what you're talking about. + + e.Handled = true; + } + + base.OnSpeech( e ); + } + + public override bool OnGoldGiven( Mobile from, Gold dropped ) + { + if ( from is PlayerMobile && dropped.Amount == 700 ) + { + PlayerMobile pm = (PlayerMobile)from; + + if ( pm.NpcGuild == NpcGuild.ThievesGuild ) + { + from.AddToBackpack( new DisguiseKit() ); + + dropped.Delete(); + return true; + } + } + + return base.OnGoldGiven( from, dropped ); + } + + public ThiefGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs new file mode 100644 index 0000000..5ff1f90 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/TinkerGuildmaster.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class TinkerGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.TinkersGuild; } } + + [Constructable] + public TinkerGuildmaster() + : base("le maitre de la Guilde des bricoleurs", "la maitresse de la Guilde des bricoleurs") + { + SetSkill( SkillName.Lockpicking, 65.0, 88.0 ); + SetSkill( SkillName.Tinkering, 90.0, 100.0 ); + SetSkill( SkillName.RemoveTrap, 85.0, 100.0 ); + } + + public TinkerGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void AddCustomContextEntries( Mobile from, List list ) + { + if ( Core.ML && from.Alive ) + { + RechargeEntry entry = new RechargeEntry( from, this ); + + if ( WeaponEngravingTool.Find( from ) == null ) + entry.Enabled = false; + + list.Add( entry ); + } + + base.AddCustomContextEntries( from, list ); + } + + private class RechargeEntry : ContextMenuEntry + { + private Mobile m_From; + private Mobile m_Vendor; + + public RechargeEntry( Mobile from, Mobile vendor ) : base( 6271, 6 ) + { + m_From = from; + m_Vendor = vendor; + } + + public override void OnClick() + { + if ( !Core.ML || m_Vendor == null || m_Vendor.Deleted ) + return; + + WeaponEngravingTool tool = WeaponEngravingTool.Find( m_From ); + + if ( tool != null && tool.UsesRemaining <= 0 ) + { + if ( Banker.GetBalance( m_From ) >= 100000 ) + m_From.SendGump( new WeaponEngravingTool.ConfirmGump( tool, m_Vendor ) ); + else + m_Vendor.Say( 1076167 ); // You need a 100,000 gold and a blue diamond to recharge the weapon engraver. + } + else + m_Vendor.Say( 1076164 ); // I can only help with this if you are carrying an engraving tool that needs repair. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs b/Scripts/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs new file mode 100644 index 0000000..65ccbc3 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Guildmasters/WarriorGuildmaster.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Mobiles +{ + public class WarriorGuildmaster : BaseGuildmaster + { + public override NpcGuild NpcGuild{ get{ return NpcGuild.WarriorsGuild; } } + + [Constructable] + public WarriorGuildmaster() + : base("le maitre de la Guilde des guerriers", "la maitresse de la Guilde des guerriers") + { + SetSkill( SkillName.ArmsLore, 75.0, 98.0 ); + SetSkill( SkillName.Parry, 85.0, 100.0 ); + SetSkill( SkillName.MagicResist, 60.0, 83.0 ); + SetSkill( SkillName.Tactics, 85.0, 100.0 ); + SetSkill( SkillName.Swords, 90.0, 100.0 ); + SetSkill( SkillName.Macing, 60.0, 83.0 ); + SetSkill( SkillName.Fencing, 60.0, 83.0 ); + } + + public WarriorGuildmaster( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs b/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs new file mode 100644 index 0000000..e784586 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/GypsyAnimalTrainer.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class GypsyAnimalTrainer : AnimalTrainer + { + [Constructable] + public GypsyAnimalTrainer() + { + Title = (Female ? "le Dresseur gitan" : "la Dresseuse gitane"); + } + + public override VendorShoeType ShoeType + { + get{ return Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = FindItemOnLayer( Layer.Pants ); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shirt); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public GypsyAnimalTrainer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs b/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs new file mode 100644 index 0000000..b62b9aa --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/GypsyBanker.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class GypsyBanker : Banker + { + public override bool IsActiveVendor{ get{ return false; } } + public override NpcGuild NpcGuild{ get{ return NpcGuild.None; } } + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public GypsyBanker() + { + Title = (Female ? "le Banquier gitan" : "la Banquiere gitane"); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + switch (Utility.Random(4)) + { + case 0: AddItem(new JesterHat(Utility.RandomBrightHue())); break; + case 1: AddItem(new Bandana(Utility.RandomBrightHue())); break; + case 2: AddItem(new SkullCap(Utility.RandomBrightHue())); break; + } + + Item item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shoes); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shirt); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public GypsyBanker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs b/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs new file mode 100644 index 0000000..543e586 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/GypsyMaiden.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class GypsyMaiden : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public GypsyMaiden() : base( "la Gitane" ) + { + Female = true; + } + + + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBProvisioner() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + switch (Utility.Random(4)) + { + case 0: AddItem(new JesterHat(Utility.RandomBrightHue())); break; + case 1: AddItem(new Bandana(Utility.RandomBrightHue())); break; + case 2: AddItem(new SkullCap(Utility.RandomBrightHue())); break; + } + + if (Utility.RandomBool()) + AddItem(new HalfApron(Utility.RandomBrightHue())); + + Item item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public GypsyMaiden( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/HairStylist.cs b/Scripts/Mobiles/Vendors/NPC/HairStylist.cs new file mode 100644 index 0000000..64b3af7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/HairStylist.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class HairStylist : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public HairStylist() : base( "le Coiffeur", "la Coiffeuse" ) + { + SetSkill( SkillName.Alchemy, 80.0, 100.0 ); + SetSkill( SkillName.Magery, 90.0, 110.0 ); + SetSkill( SkillName.TasteID, 85.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBHairStylist() ); + } + + public HairStylist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Herbalist.cs b/Scripts/Mobiles/Vendors/NPC/Herbalist.cs new file mode 100644 index 0000000..ea634bf --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Herbalist.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Herbalist : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } } + + [Constructable] + public Herbalist() : base( "l'Herboriste" ) + { + SetSkill( SkillName.Alchemy, 80.0, 100.0 ); + SetSkill( SkillName.Cooking, 80.0, 100.0 ); + SetSkill( SkillName.TasteID, 80.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBHerbalist() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public Herbalist( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/HolyMage.cs b/Scripts/Mobiles/Vendors/NPC/HolyMage.cs new file mode 100644 index 0000000..1897037 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/HolyMage.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class HolyMage : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public HolyMage() : base( "le Mage saint", "la Mage sainte" ) + { + SetSkill( SkillName.EvalInt, 65.0, 88.0 ); + SetSkill( SkillName.Inscribe, 60.0, 83.0 ); + SetSkill( SkillName.Magery, 64.0, 100.0 ); + SetSkill( SkillName.Meditation, 60.0, 83.0 ); + SetSkill( SkillName.MagicResist, 65.0, 88.0 ); + SetSkill( SkillName.Wrestling, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBHolyMage() ); + } + + public Item ApplyHue( Item item, int hue ) + { + item.Hue = hue; + + return item; + } + + public override void InitOutfit() + { + AddItem( ApplyHue( new Robe(), 0x47E ) ); + AddItem( ApplyHue( new ThighBoots(), 0x47E ) ); + AddItem( ApplyHue( new BlackStaff(), 0x47E ) ); + + if ( Female ) + { + AddItem( ApplyHue( new LeatherGloves(), 0x47E ) ); + AddItem( ApplyHue( new GoldNecklace(), 0x47E ) ); + } + else + { + AddItem( ApplyHue( new PlateGloves(), 0x47E ) ); + AddItem( ApplyHue( new PlateGorget(), 0x47E ) ); + } + + switch ( Utility.Random( Female ? 2 : 1 ) ) + { + case 0: HairItemID = 0x203C; break; + case 1: HairItemID = 0x203D; break; + } + + HairHue = 0x47E; + + PackGold( 100, 200 ); + } + + public HolyMage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/InnKeeper.cs b/Scripts/Mobiles/Vendors/NPC/InnKeeper.cs new file mode 100644 index 0000000..622bcaa --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/InnKeeper.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class InnKeeper : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public InnKeeper() : base( "l'Aubergiste" ) + { + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBInnKeeper() ); + + if ( IsTokunoVendor ) + m_SBInfos.Add( new SBSEFood() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; } + } + + public InnKeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/IronWorker.cs b/Scripts/Mobiles/Vendors/NPC/IronWorker.cs new file mode 100644 index 0000000..10ece49 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/IronWorker.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class IronWorker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public IronWorker() : base( "le Ferronier", "la Ferroniere" ) + { + SetSkill( SkillName.ArmsLore, 36.0, 68.0 ); + SetSkill( SkillName.Blacksmith, 65.0, 88.0 ); + SetSkill( SkillName.Fencing, 60.0, 83.0 ); + SetSkill( SkillName.Macing, 61.0, 93.0 ); + SetSkill( SkillName.Swords, 60.0, 83.0 ); + SetSkill( SkillName.Tactics, 60.0, 83.0 ); + SetSkill( SkillName.Parry, 61.0, 93.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBAxeWeapon() ); + m_SBInfos.Add( new SBKnifeWeapon() ); + m_SBInfos.Add( new SBMaceWeapon() ); + m_SBInfos.Add( new SBSmithTools() ); + m_SBInfos.Add( new SBPoleArmWeapon() ); + m_SBInfos.Add( new SBSpearForkWeapon() ); + m_SBInfos.Add( new SBSwordWeapon() ); + + m_SBInfos.Add( new SBMetalShields() ); + + m_SBInfos.Add( new SBHelmetArmor() ); + m_SBInfos.Add( new SBPlateArmor() ); + m_SBInfos.Add( new SBChainmailArmor() ); + m_SBInfos.Add( new SBRingmailArmor() ); + m_SBInfos.Add( new SBStuddedArmor() ); + m_SBInfos.Add( new SBLeatherArmor() ); + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.None; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + Item item = ( Utility.RandomBool() ? null : new Server.Items.RingmailChest() ); + + if ( item != null && !EquipItem( item ) ) + { + item.Delete(); + item = null; + } + + switch (Utility.Random(3)) + { + case 0: + case 1: AddItem(new JesterHat(Utility.RandomBrightHue())); break; + case 2: AddItem(new Bandana(Utility.RandomBrightHue())); break; + } + + if (item == null) + AddItem(new FullApron(Utility.RandomBrightHue())); + + AddItem(new Bascinet()); + AddItem(new SmithHammer()); + + item = FindItemOnLayer(Layer.Pants); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerLegs); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.OuterTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.InnerTorso); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + + item = FindItemOnLayer(Layer.Shirt); + + if (item != null) + item.Hue = Utility.RandomBrightHue(); + } + + public IronWorker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Jeweler.cs b/Scripts/Mobiles/Vendors/NPC/Jeweler.cs new file mode 100644 index 0000000..777ad8e --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Jeweler.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Jeweler : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Jeweler() : base( "le Joaillier", "la Joailliere" ) + { + SetSkill( SkillName.ItemID, 64.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBJewel() ); + } + + public Jeweler( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/KeeperOfChivalry.cs b/Scripts/Mobiles/Vendors/NPC/KeeperOfChivalry.cs new file mode 100644 index 0000000..d4ca906 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/KeeperOfChivalry.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class KeeperOfChivalry : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public KeeperOfChivalry() : base( "le Paladin", "la Paladine" ) + { + SetSkill( SkillName.Fencing, 75.0, 85.0 ); + SetSkill( SkillName.Macing, 75.0, 85.0 ); + SetSkill( SkillName.Swords, 75.0, 85.0 ); + SetSkill( SkillName.Chivalry, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBKeeperOfChivalry() ); + } + + public override void InitOutfit() + { + AddItem( new PlateArms() ); + AddItem( new PlateChest() ); + AddItem( new PlateGloves() ); + AddItem( new StuddedGorget() ); + AddItem( new PlateLegs() ); + + switch ( Utility.Random( 4 ) ) + { + case 0: AddItem( new PlateHelm() ); break; + case 1: AddItem( new NorseHelm() ); break; + case 2: AddItem( new CloseHelm() ); break; + case 3: AddItem( new Helmet() ); break; + } + + switch ( Utility.Random( 3 ) ) + { + case 0: AddItem( new BodySash( 0x482 ) ); break; + case 1: AddItem( new Doublet( 0x482 ) ); break; + case 2: AddItem( new Tunic( 0x482 ) ); break; + } + + AddItem( new Broadsword() ); + + Item shield = new MetalKiteShield(); + + shield.Hue = Utility.RandomNondyedHue(); + + AddItem( shield ); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new Boots() ); break; + case 1: AddItem( new ThighBoots() ); break; + } + + PackGold( 100, 200 ); + } + + public KeeperOfChivalry( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/LeatherWorker.cs b/Scripts/Mobiles/Vendors/NPC/LeatherWorker.cs new file mode 100644 index 0000000..62985d6 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/LeatherWorker.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class LeatherWorker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public LeatherWorker() : base( "le Megissier", "la Megissiere" ) + { + } + public override void InitSBInfo() + { + m_SBInfos.Add( new SBLeatherArmor() ); + m_SBInfos.Add( new SBStuddedArmor() ); + m_SBInfos.Add( new SBLeatherWorker() ); + } + public LeatherWorker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Vendors/NPC/Mage.cs b/Scripts/Mobiles/Vendors/NPC/Mage.cs new file mode 100644 index 0000000..f27c458 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Mage.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Mage : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } } + + [Constructable] + public Mage() : base( "le Mage", "la Mage" ) + { + SetSkill( SkillName.EvalInt, 65.0, 88.0 ); + SetSkill( SkillName.Inscribe, 60.0, 83.0 ); + SetSkill( SkillName.Magery, 64.0, 100.0 ); + SetSkill( SkillName.Meditation, 60.0, 83.0 ); + SetSkill( SkillName.MagicResist, 65.0, 88.0 ); + SetSkill( SkillName.Wrestling, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBMage() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Robe( Utility.RandomBlueHue() ) ); + } + + public Mage( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Mapmaker.cs b/Scripts/Mobiles/Vendors/NPC/Mapmaker.cs new file mode 100644 index 0000000..08514ea --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Mapmaker.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Mapmaker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Mapmaker() : base( "le Cartographe", "la Cartographe" ) + { + SetSkill( SkillName.Cartography, 90.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBMapmaker() ); + } + + public Mapmaker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Miller.cs b/Scripts/Mobiles/Vendors/NPC/Miller.cs new file mode 100644 index 0000000..18bc52c --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Miller.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Miller : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Miller() : base( "le Meunier", "la Meuniere" ) + { + + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBMiller() ); + } + + public Miller( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Miner.cs b/Scripts/Mobiles/Vendors/NPC/Miner.cs new file mode 100644 index 0000000..0d6cdc6 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Miner.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Miner : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Miner() : base( "le Mineur", "la Mineure" ) + { + SetSkill( SkillName.Mining, 65.0, 88.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBMiner() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.FancyShirt( 0x3E4 ) ); + AddItem( new Server.Items.LongPants( 0x192 ) ); + AddItem( new Server.Items.Pickaxe() ); + AddItem( new Server.Items.ThighBoots( 0x283 ) ); + } + + public Miner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Monk.cs b/Scripts/Mobiles/Vendors/NPC/Monk.cs new file mode 100644 index 0000000..c305b80 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Monk.cs @@ -0,0 +1,53 @@ + +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Monk : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Monk() : base( "le Moine", "la Nonne" ) + { + SetSkill( SkillName.EvalInt, 100.0 ); + SetSkill( SkillName.Tactics, 70.0, 90.0 ); + SetSkill( SkillName.Wrestling, 70.0, 90.0 ); + SetSkill( SkillName.MagicResist, 70.0, 90.0 ); + SetSkill( SkillName.Macing, 70.0, 90.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBMonk() ); + } + public override void InitOutfit() + { + AddItem( new Sandals() ); + AddItem( new MonkRobe() ); + } + + public Monk( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + } +} diff --git a/Scripts/Mobiles/Vendors/NPC/Provisioner.cs b/Scripts/Mobiles/Vendors/NPC/Provisioner.cs new file mode 100644 index 0000000..889f981 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Provisioner.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Provisioner : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Provisioner() : base( "le Magasinier", "la Magasiniere" ) + { + SetSkill( SkillName.Camping, 45.0, 68.0 ); + SetSkill( SkillName.Tactics, 45.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBProvisioner() ); + + if ( IsTokunoVendor ) + m_SBInfos.Add( new SBSEHats() ); + } + + public Provisioner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Rancher.cs b/Scripts/Mobiles/Vendors/NPC/Rancher.cs new file mode 100644 index 0000000..7e7193c --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Rancher.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class Rancher : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Rancher() : base( "le Cowboy", "la Cowgirl" ) + { + SetSkill( SkillName.AnimalLore, 55.0, 78.0 ); + SetSkill( SkillName.AnimalTaming, 55.0, 78.0 ); + SetSkill( SkillName.Herding, 64.0, 100.0 ); + SetSkill( SkillName.Veterinary, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBRancher() ); + } + + public Rancher( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Ranger.cs b/Scripts/Mobiles/Vendors/NPC/Ranger.cs new file mode 100644 index 0000000..00a60c2 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Ranger.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Ranger : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Ranger() : base( "le Rodeur", "la Rodeuse" ) + { + SetSkill( SkillName.Camping, 55.0, 78.0 ); + SetSkill( SkillName.DetectHidden, 65.0, 88.0 ); + SetSkill( SkillName.Hiding, 45.0, 68.0 ); + SetSkill( SkillName.Archery, 65.0, 88.0 ); + SetSkill( SkillName.Tracking, 65.0, 88.0 ); + SetSkill(SkillName.Throwing, 60.0, 88.0); + SetSkill( SkillName.Veterinary, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBRanger() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Shirt( Utility.RandomNeutralHue() ) ); + AddItem( new Server.Items.LongPants( Utility.RandomNeutralHue() ) ); + AddItem( new Server.Items.Bow() ); + AddItem( new Server.Items.ThighBoots( Utility.RandomNeutralHue() ) ); + } + + public Ranger( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/RealEstateBroker.cs b/Scripts/Mobiles/Vendors/NPC/RealEstateBroker.cs new file mode 100644 index 0000000..e362596 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/RealEstateBroker.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Multis; +using Server.Multis.Deeds; +using Server.Targeting; +using Server.Network; + +namespace Server.Mobiles +{ + public class RealEstateBroker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public RealEstateBroker() : base( "le Courtier immobilier", "la Courti�re immobili�re" ) + { + } + + public override bool HandlesOnSpeech( Mobile from ) + { + if ( from.Alive && from.InRange( this, 3 ) ) + return true; + + return base.HandlesOnSpeech( from ); + } + + private DateTime m_NextCheckPack; + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if ( DateTime.Now > m_NextCheckPack && InRange( m, 4 ) && !InRange( oldLocation, 4 ) && m.Player ) + { + Container pack = m.Backpack; + + if ( pack != null ) + { + m_NextCheckPack = DateTime.Now + TimeSpan.FromSeconds( 2.0 ); + + Item deed = pack.FindItemByType( typeof( HouseDeed ), false ); + + if ( deed != null ) + { + // If you have a deed, I can appraise it or buy it from you... + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 500605, m.NetState ); + + // Simply hand me a deed to sell it. + PrivateOverheadMessage( MessageType.Regular, 0x3B2, 500606, m.NetState ); + } + } + } + + base.OnMovement( m, oldLocation ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( !e.Handled && e.Mobile.Alive && e.HasKeyword( 0x38 ) ) // *appraise* + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500608 ); // Which deed would you like appraised? + e.Mobile.BeginTarget( 12, false, TargetFlags.None, new TargetCallback( Appraise_OnTarget ) ); + e.Handled = true; + } + + base.OnSpeech( e ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is HouseDeed ) + { + HouseDeed deed = (HouseDeed)dropped; + int price = ComputePriceFor( deed ); + + if ( price > 0 ) + { + if ( Banker.Deposit( from, price ) ) + { + // For the deed I have placed gold in your bankbox : + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1008000, AffixType.Append, price.ToString(), "" ); + + deed.Delete(); + return true; + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500390 ); // Your bank box is full. + return false; + } + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500607 ); // I'm not interested in that. + return false; + } + } + + return base.OnDragDrop (from, dropped); + } + + public void Appraise_OnTarget( Mobile from, object obj ) + { + if ( obj is HouseDeed ) + { + HouseDeed deed = (HouseDeed)obj; + int price = ComputePriceFor( deed ); + + if ( price > 0 ) + { + // I will pay you gold for this deed : + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1008001, AffixType.Append, price.ToString(), "" ); + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500610 ); // Simply hand me the deed if you wish to sell it. + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500607 ); // I'm not interested in that. + } + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 500609 ); // I can't appraise things I know nothing about... + } + } + + public int ComputePriceFor( HouseDeed deed ) + { + int price = 0; + + if ( deed is SmallBrickHouseDeed || deed is StonePlasterHouseDeed || deed is FieldStoneHouseDeed || deed is SmallBrickHouseDeed || deed is WoodHouseDeed || deed is WoodPlasterHouseDeed || deed is ThatchedRoofCottageDeed ) + price = 43800; + else if ( deed is BrickHouseDeed ) + price = 144500; + else if ( deed is TwoStoryWoodPlasterHouseDeed || deed is TwoStoryStonePlasterHouseDeed ) + price = 192400; + else if ( deed is TowerDeed ) + price = 433200; + else if ( deed is KeepDeed ) + price = 665200; + else if ( deed is CastleDeed ) + price = 1022800; + else if ( deed is LargePatioDeed ) + price = 152800; + else if ( deed is LargeMarbleDeed ) + price = 192800; + else if ( deed is SmallTowerDeed ) + price = 88500; + else if ( deed is LogCabinDeed ) + price = 97800; + else if ( deed is SandstonePatioDeed ) + price = 90900; + else if ( deed is VillaDeed ) + price = 136500; + else if ( deed is StoneWorkshopDeed ) + price = 60600; + else if ( deed is MarbleWorkshopDeed ) + price = 60300; + + return AOS.Scale( price, 80 ); // refunds 80% of the purchase price + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBRealEstateBroker() ); + } + + public RealEstateBroker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Scribe.cs b/Scripts/Mobiles/Vendors/NPC/Scribe.cs new file mode 100644 index 0000000..e6dcee0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Scribe.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Scribe : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.MagesGuild; } } + + private DateTime m_NextShush; + public static readonly TimeSpan ShushDelay = TimeSpan.FromMinutes(1); + + [Constructable] + public Scribe() : base( "le Scribe", "la Scribe" ) + { + SetSkill( SkillName.EvalInt, 60.0, 83.0 ); + SetSkill( SkillName.Inscribe, 90.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBScribe() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals; } + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Robe( Utility.RandomNeutralHue() ) ); + } + + public override bool HandlesOnSpeech(Mobile from) + { + return from.Player; + } + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + if (!e.Handled && m_NextShush <= DateTime.Now && InLOS(e.Mobile)) + { + Direction = GetDirectionTo(e.Mobile); + + PlaySound(Female ? 0x32F : 0x441); + PublicOverheadMessage(Network.MessageType.Regular, 0x3B2, 1073990); // Shhhh! + + m_NextShush = DateTime.Now + ShushDelay; + e.Handled = true; + } + } + + public Scribe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Shipwright.cs b/Scripts/Mobiles/Vendors/NPC/Shipwright.cs new file mode 100644 index 0000000..49fae95 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Shipwright.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Shipwright : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Shipwright() : base( "l'Armateur", "l'Armatrice" ) + { + SetSkill( SkillName.Carpentry, 60.0, 83.0 ); + SetSkill( SkillName.Macing, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBShipwright() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.SmithHammer() ); + } + + public Shipwright( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/StoneCrafter.cs b/Scripts/Mobiles/Vendors/NPC/StoneCrafter.cs new file mode 100644 index 0000000..67178a7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/StoneCrafter.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + [TypeAlias( "Server.Mobiles.GargoyleStonecrafter" )] + public class StoneCrafter : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.TinkersGuild; } } + + [Constructable] + public StoneCrafter() : base( "le Tailleur de pierres", "la Tailleuse de pierres" ) + { + SetSkill( SkillName.Carpentry, 85.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBStoneCrafter() ); + m_SBInfos.Add( new SBStavesWeapon() ); + m_SBInfos.Add( new SBCarpenter() ); + m_SBInfos.Add( new SBWoodenShields() ); + } + + public StoneCrafter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Title == "the stonecrafter" ) + Title = "the stone crafter"; + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Tailor.cs b/Scripts/Mobiles/Vendors/NPC/Tailor.cs new file mode 100644 index 0000000..33894df --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Tailor.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.BulkOrders; + +namespace Server.Mobiles +{ + public class Tailor : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.TailorsGuild; } } + + [Constructable] + public Tailor() : base( "le Couturier", "la Couturiere" ) + { + SetSkill( SkillName.Tailoring, 64.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBTailor() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Sandals : VendorShoeType.Shoes; } + } + + #region Bulk Orders + public override Item CreateBulkOrder( Mobile from, bool fromContextMenu ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null && pm.NextTailorBulkOrder == TimeSpan.Zero && (fromContextMenu || 0.2 > Utility.RandomDouble()) ) + { + double theirSkill = pm.Skills[SkillName.Tailoring].Base; + + if ( theirSkill >= 70.1 ) + pm.NextTailorBulkOrder = TimeSpan.FromHours( 6.0 ); + else if ( theirSkill >= 50.1 ) + pm.NextTailorBulkOrder = TimeSpan.FromHours( 2.0 ); + else + pm.NextTailorBulkOrder = TimeSpan.FromHours( 1.0 ); + + if ( theirSkill >= 70.1 && ((theirSkill - 40.0) / 300.0) > Utility.RandomDouble() ) + return new LargeTailorBOD(); + + return SmallTailorBOD.CreateRandomFor( from ); + } + + return null; + } + + public override bool IsValidBulkOrder( Item item ) + { + return ( item is SmallTailorBOD || item is LargeTailorBOD ); + } + + public override bool SupportsBulkOrders( Mobile from ) + { + return ( from is PlayerMobile && from.Skills[SkillName.Tailoring].Base > 0 ); + } + + public override TimeSpan GetNextBulkOrder( Mobile from ) + { + if ( from is PlayerMobile ) + return ((PlayerMobile)from).NextTailorBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive( Mobile from ) + { + if( Core.SE && from is PlayerMobile ) + ((PlayerMobile)from).NextTailorBulkOrder = TimeSpan.Zero; + } + #endregion + + public Tailor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Vendors/NPC/Tanner.cs b/Scripts/Mobiles/Vendors/NPC/Tanner.cs new file mode 100644 index 0000000..976f6c7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Tanner.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Tanner : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Tanner() : base( "le Tanneur", "la Tanneuse" ) + { + SetSkill( SkillName.Tailoring, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBTanner() ); + } + + public Tanner( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Mobiles/Vendors/NPC/TavernKeeper.cs b/Scripts/Mobiles/Vendors/NPC/TavernKeeper.cs new file mode 100644 index 0000000..c409fa4 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/TavernKeeper.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class TavernKeeper : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public TavernKeeper() : base( "le Tavernier", "la Taverniere" ) + { + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBTavernKeeper() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron() ); + } + + public TavernKeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Thief.cs b/Scripts/Mobiles/Vendors/NPC/Thief.cs new file mode 100644 index 0000000..d309cf7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Thief.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Thief : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Thief() : base( "le Voleur", "la Voleuse" ) + { + SetSkill( SkillName.Camping, 55.0, 78.0 ); + SetSkill( SkillName.DetectHidden, 65.0, 88.0 ); + SetSkill( SkillName.Hiding, 45.0, 68.0 ); + SetSkill( SkillName.Archery, 65.0, 88.0 ); + SetSkill( SkillName.Tracking, 65.0, 88.0 ); + SetSkill( SkillName.Veterinary, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBThief() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.Shirt( Utility.RandomNeutralHue() ) ); + AddItem( new Server.Items.LongPants( Utility.RandomNeutralHue() ) ); + AddItem( new Server.Items.Dagger() ); + AddItem( new Server.Items.ThighBoots( Utility.RandomNeutralHue() ) ); + } + + public Thief( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Tinker.cs b/Scripts/Mobiles/Vendors/NPC/Tinker.cs new file mode 100644 index 0000000..663aa8c --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Tinker.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Tinker : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.TinkersGuild; } } + + [Constructable] + public Tinker() : base( "la Bricoleuse" ) + { + SetSkill( SkillName.Lockpicking, 60.0, 83.0 ); + SetSkill( SkillName.RemoveTrap, 75.0, 98.0 ); + SetSkill( SkillName.Tinkering, 64.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBTinker() ); + } + + public Tinker( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Vagabond.cs b/Scripts/Mobiles/Vendors/NPC/Vagabond.cs new file mode 100644 index 0000000..20a29c7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Vagabond.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class Vagabond : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Vagabond() : base( "le Vagabond", "la Vagabonde" ) + { + SetSkill( SkillName.ItemID, 60.0, 83.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBTinker() ); + m_SBInfos.Add( new SBVagabond() ); + } + + public override void InitOutfit() + { + AddItem(new FancyShirt(Utility.RandomBrightHue())); + AddItem(new Shoes(GetShoeHue())); + AddItem(new LongPants(GetRandomHue())); + + if (Utility.RandomBool()) + AddItem(new Cloak(Utility.RandomBrightHue())); + + switch ( Utility.Random( 2 ) ) + { + case 0: AddItem( new SkullCap( Utility.RandomNeutralHue() ) ); break; + case 1: AddItem( new Bandana( Utility.RandomNeutralHue() ) ); break; + } + + + Utility.AssignRandomHair( this ); + Utility.AssignRandomFacialHair( this, HairHue ); + + PackGold( 100, 200 ); + } + + public Vagabond( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/VarietyDealer.cs b/Scripts/Mobiles/Vendors/NPC/VarietyDealer.cs new file mode 100644 index 0000000..366b88b --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/VarietyDealer.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class VarietyDealer : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public VarietyDealer() : base( "le Brocantier", "la Brocantiere" ) + { + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBVarietyDealer() ); + } + + public VarietyDealer( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Veterinarian.cs b/Scripts/Mobiles/Vendors/NPC/Veterinarian.cs new file mode 100644 index 0000000..91ae5ee --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Veterinarian.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class Veterinarian : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Veterinarian() : base( "le Veterinaire", "la Veterinaire" ) + { + SetSkill( SkillName.AnimalLore, 85.0, 100.0 ); + SetSkill( SkillName.Veterinary, 90.0, 100.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBVeterinarian() ); + } + + public Veterinarian( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Waiter.cs b/Scripts/Mobiles/Vendors/NPC/Waiter.cs new file mode 100644 index 0000000..5ebb75f --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Waiter.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Waiter : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Waiter() : base( "le Serveur","la Serveuse" ) + { + SetSkill( SkillName.Discordance, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBWaiter() ); + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron() ); + } + + public Waiter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Weaponsmith.cs b/Scripts/Mobiles/Vendors/NPC/Weaponsmith.cs new file mode 100644 index 0000000..c390fb7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Weaponsmith.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.BulkOrders; + +namespace Server.Mobiles +{ + public class Weaponsmith : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + [Constructable] + public Weaponsmith() : base( "le Fabricant d'armes", "la Fabricante d'armes" ) + { + SetSkill( SkillName.ArmsLore, 64.0, 100.0 ); + SetSkill( SkillName.Blacksmith, 65.0, 88.0 ); + SetSkill( SkillName.Fencing, 45.0, 68.0 ); + SetSkill( SkillName.Macing, 45.0, 68.0 ); + SetSkill( SkillName.Swords, 45.0, 68.0 ); + SetSkill( SkillName.Tactics, 36.0, 68.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBWeaponSmith() ); + + if ( IsTokunoVendor ) + m_SBInfos.Add( new SBSEWeapons() ); + } + + public override VendorShoeType ShoeType + { + get{ return Utility.RandomBool() ? VendorShoeType.Boots : VendorShoeType.ThighBoots; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.HalfApron() ); + } + /* Retrait des BODs Temporaire + #region Bulk Orders + public override Item CreateBulkOrder( Mobile from, bool fromContextMenu ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || 0.2 > Utility.RandomDouble()) ) + { + double theirSkill = pm.Skills[SkillName.Blacksmith].Base; + + if ( theirSkill >= 70.1 ) + pm.NextSmithBulkOrder = TimeSpan.FromHours( 6.0 ); + else if ( theirSkill >= 50.1 ) + pm.NextSmithBulkOrder = TimeSpan.FromHours( 2.0 ); + else + pm.NextSmithBulkOrder = TimeSpan.FromHours( 1.0 ); + + if ( theirSkill >= 70.1 && ((theirSkill - 40.0) / 300.0) > Utility.RandomDouble() ) + return new LargeSmithBOD(); + + return SmallSmithBOD.CreateRandomFor( from ); + } + + return null; + } + + public override bool IsValidBulkOrder( Item item ) + { + return ( item is SmallSmithBOD || item is LargeSmithBOD ); + } + + public override bool SupportsBulkOrders( Mobile from ) + { + return ( from is PlayerMobile && Core.AOS && from.Skills[SkillName.Blacksmith].Base > 0 ); + } + + public override TimeSpan GetNextBulkOrder( Mobile from ) + { + if ( from is PlayerMobile ) + return ((PlayerMobile)from).NextSmithBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive( Mobile from ) + { + if( Core.SE && from is PlayerMobile ) + ((PlayerMobile)from).NextSmithBulkOrder = TimeSpan.Zero; + } + #endregion + */ + public Weaponsmith( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/NPC/Weaver.cs b/Scripts/Mobiles/Vendors/NPC/Weaver.cs new file mode 100644 index 0000000..5bdd07c --- /dev/null +++ b/Scripts/Mobiles/Vendors/NPC/Weaver.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Engines.BulkOrders; + +namespace Server.Mobiles +{ + public class Weaver : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override NpcGuild NpcGuild{ get{ return NpcGuild.TailorsGuild; } } + + [Constructable] + public Weaver() : base( "le Tisseur", "la Tisseuse" ) + { + SetSkill( SkillName.Tailoring, 65.0, 88.0 ); + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBWeaver() ); + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.Sandals; } + } + + #region Bulk Orders + public override Item CreateBulkOrder( Mobile from, bool fromContextMenu ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( pm != null && pm.NextTailorBulkOrder == TimeSpan.Zero && (fromContextMenu || 0.2 > Utility.RandomDouble()) ) + { + double theirSkill = pm.Skills[SkillName.Tailoring].Base; + + if ( theirSkill >= 70.1 ) + pm.NextTailorBulkOrder = TimeSpan.FromHours( 6.0 ); + else if ( theirSkill >= 50.1 ) + pm.NextTailorBulkOrder = TimeSpan.FromHours( 2.0 ); + else + pm.NextTailorBulkOrder = TimeSpan.FromHours( 1.0 ); + + if ( theirSkill >= 70.1 && ((theirSkill - 40.0) / 300.0) > Utility.RandomDouble() ) + return new LargeTailorBOD(); + + return SmallTailorBOD.CreateRandomFor( from ); + } + + return null; + } + + public override bool IsValidBulkOrder( Item item ) + { + return ( item is SmallTailorBOD || item is LargeTailorBOD ); + } + + public override bool SupportsBulkOrders( Mobile from ) + { + return ( from is PlayerMobile && from.Skills[SkillName.Tailoring].Base > 0 ); + } + + public override TimeSpan GetNextBulkOrder( Mobile from ) + { + if ( from is PlayerMobile ) + return ((PlayerMobile)from).NextTailorBulkOrder; + + return TimeSpan.Zero; + } + + public override void OnSuccessfulBulkOrderReceive( Mobile from ) + { + if( Core.SE && from is PlayerMobile ) + ((PlayerMobile)from).NextTailorBulkOrder = TimeSpan.Zero; + } + #endregion + + public Weaver( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs b/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs new file mode 100644 index 0000000..ee36dd5 --- /dev/null +++ b/Scripts/Mobiles/Vendors/PlayerBarkeeper.cs @@ -0,0 +1,1073 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Prompts; +using Server.Network; +using Server.ContextMenus; +using Server.Multis; + +namespace Server.Mobiles +{ + public class ChangeRumorMessagePrompt : Prompt + { + private PlayerBarkeeper m_Barkeeper; + private int m_RumorIndex; + + public ChangeRumorMessagePrompt( PlayerBarkeeper barkeeper, int rumorIndex ) + { + m_Barkeeper = barkeeper; + m_RumorIndex = rumorIndex; + } + + public override void OnCancel( Mobile from ) + { + OnResponse( from, "" ); + } + + public override void OnResponse( Mobile from, string text ) + { + if( text.Length > 130 ) + text = text.Substring( 0, 130 ); + + m_Barkeeper.EndChangeRumor( from, m_RumorIndex, text ); + } + } + + public class ChangeRumorKeywordPrompt : Prompt + { + private PlayerBarkeeper m_Barkeeper; + private int m_RumorIndex; + + public ChangeRumorKeywordPrompt( PlayerBarkeeper barkeeper, int rumorIndex ) + { + m_Barkeeper = barkeeper; + m_RumorIndex = rumorIndex; + } + + public override void OnCancel( Mobile from ) + { + OnResponse( from, "" ); + } + + public override void OnResponse( Mobile from, string text ) + { + if( text.Length > 130 ) + text = text.Substring( 0, 130 ); + + m_Barkeeper.EndChangeKeyword( from, m_RumorIndex, text ); + } + } + + public class ChangeTipMessagePrompt : Prompt + { + private PlayerBarkeeper m_Barkeeper; + + public ChangeTipMessagePrompt( PlayerBarkeeper barkeeper ) + { + m_Barkeeper = barkeeper; + } + + public override void OnCancel( Mobile from ) + { + OnResponse( from, "" ); + } + + public override void OnResponse( Mobile from, string text ) + { + if ( text.Length > 130 ) + text = text.Substring( 0, 130 ); + + m_Barkeeper.EndChangeTip( from, text ); + } + } + + public class BarkeeperRumor + { + private string m_Message; + private string m_Keyword; + + public string Message{ get{ return m_Message; } set{ m_Message = value; } } + public string Keyword{ get{ return m_Keyword; } set{ m_Keyword = value; } } + + public BarkeeperRumor( string message, string keyword ) + { + m_Message = message; + m_Keyword = keyword; + } + + public static BarkeeperRumor Deserialize( GenericReader reader ) + { + if ( !reader.ReadBool() ) + return null; + + return new BarkeeperRumor( reader.ReadString(), reader.ReadString() ); + } + + public static void Serialize( GenericWriter writer, BarkeeperRumor rumor ) + { + if ( rumor == null ) + { + writer.Write( false ); + } + else + { + writer.Write( true ); + writer.Write( rumor.m_Message ); + writer.Write( rumor.m_Keyword ); + } + } + } + + public class ManageBarkeeperEntry : ContextMenuEntry + { + private Mobile m_From; + private PlayerBarkeeper m_Barkeeper; + + public ManageBarkeeperEntry( Mobile from, PlayerBarkeeper barkeeper ) : base( 6151, 12 ) + { + m_From = from; + m_Barkeeper = barkeeper; + } + + public override void OnClick() + { + m_Barkeeper.BeginManagement( m_From ); + } + } + + public class PlayerBarkeeper : BaseVendor + { + private Mobile m_Owner; + private BaseHouse m_House; + private string m_TipMessage; + + private BarkeeperRumor[] m_Rumors; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + public BaseHouse House + { + get{ return m_House; } + set + { + if ( m_House != null ) + m_House.PlayerBarkeepers.Remove( this ); + + if ( value != null ) + value.PlayerBarkeepers.Add( this ); + + m_House = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string TipMessage + { + get{ return m_TipMessage; } + set{ m_TipMessage = value; } + } + + public override bool IsActiveBuyer{ get{ return false; } } + public override bool IsActiveSeller{ get{ return ( m_SBInfos.Count > 0 ); } } + + public override bool DisallowAllMoves{ get{ return true; } } + public override bool NoHouseRestrictions{ get{ return true; } } + + public BarkeeperRumor[] Rumors{ get{ return m_Rumors; } } + + public override VendorShoeType ShoeType{ get{ return Utility.RandomBool() ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } } + + public bool GetGender() + { + return false; // always starts as male + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem(new HalfApron(Utility.RandomBrightHue())); + + Container pack = this.Backpack; + + if ( pack != null ) + pack.Delete(); + } + + public override void InitBody() + { + base.InitBody(); + + if (BodyValue == 0x340 || BodyValue == 0x402) + Hue = 0; + else + Hue = 0x83F4; // hue is not random + + Container pack = this.Backpack; + + if ( pack != null ) + pack.Delete(); + } + + public PlayerBarkeeper( Mobile owner, BaseHouse house ) : base( "the barkeeper" ) + { + m_Owner = owner; + House = house; + m_Rumors = new BarkeeperRumor[3]; + + LoadSBInfo(); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if ( InRange( from, 3 ) ) + return true; + + return base.HandlesOnSpeech (from); + } + + private Timer m_NewsTimer; + + private void ShoutNews_Callback( object state ) + { + object[] states = (object[])state; + TownCrierEntry tce = (TownCrierEntry)states[0]; + int index = (int)states[1]; + + if ( index < 0 || index >= tce.Lines.Length ) + { + if ( m_NewsTimer != null ) + m_NewsTimer.Stop(); + + m_NewsTimer = null; + } + else + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, false, tce.Lines[index] ); + states[1] = index + 1; + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + House = null; + } + + public override bool OnBeforeDeath() + { + if ( !base.OnBeforeDeath() ) + return false; + + Item shoes = this.FindItemOnLayer( Layer.Shoes ); + + if ( shoes is Sandals ) + shoes.Hue = 0; + + return true; + } + + public override void OnSpeech( SpeechEventArgs e ) + { + base.OnSpeech( e ); + + if ( !e.Handled && InRange( e.Mobile, 3 ) ) + { + if ( m_NewsTimer == null && e.HasKeyword( 0x30 ) ) // *news* + { + TownCrierEntry tce = GlobalTownCrierEntryList.Instance.GetRandomEntry(); + + if ( tce == null ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, 1005643 ); // I have no news at this time. + } + else + { + m_NewsTimer = Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 3.0 ), new TimerStateCallback( ShoutNews_Callback ), new object[]{ tce, 0 } ); + + PublicOverheadMessage( MessageType.Regular, 0x3B2, 502978 ); // Some of the latest news! + } + } + + for ( int i = 0; i < m_Rumors.Length; ++i ) + { + BarkeeperRumor rumor = m_Rumors[i]; + + if ( rumor == null ) + continue; + + string keyword = rumor.Keyword; + + if ( keyword == null || (keyword = keyword.Trim()).Length == 0 ) + continue; + + if ( Insensitive.Equals( keyword, e.Speech ) ) + { + string message = rumor.Message; + + if ( message == null || (message = message.Trim()).Length == 0 ) + continue; + + PublicOverheadMessage( MessageType.Regular, 0x3B2, false, message ); + } + } + } + } + + public override bool CheckGold( Mobile from, Item dropped ) + { + if ( dropped is Gold ) + { + Gold g = (Gold)dropped; + + if ( g.Amount > 50 ) + { + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "I cannot accept so large a tip!", from.NetState ); + } + else + { + string tip = m_TipMessage; + + if ( tip == null || (tip = tip.Trim()).Length == 0 ) + { + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "It would not be fair of me to take your money and not offer you information in return.", from.NetState ); + } + else + { + Direction = GetDirectionTo( from ); + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, tip, from.NetState ); + + g.Delete(); + return true; + } + } + } + + return false; + } + + public bool IsOwner( Mobile from ) + { + if ( from == null || from.Deleted || this.Deleted ) + return false; + + if ( from.AccessLevel > AccessLevel.GameMaster ) + return true; + + return ( m_Owner == from ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( IsOwner( from ) && from.InLOS( this ) ) + list.Add( new ManageBarkeeperEntry( from, this ) ); + } + + public void BeginManagement( Mobile from ) + { + if ( !IsOwner( from ) ) + return; + + from.SendGump( new BarkeeperGump( from, this ) ); + } + + public void Dismiss() + { + Delete(); + } + + public void BeginChangeRumor( Mobile from, int index ) + { + if ( index < 0 || index >= m_Rumors.Length ) + return; + + from.Prompt = new ChangeRumorMessagePrompt( this, index ); + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Say what news you would like me to tell our guests.", from.NetState ); + } + + public void EndChangeRumor( Mobile from, int index, string text ) + { + if ( index < 0 || index >= m_Rumors.Length ) + return; + + if ( m_Rumors[index] == null ) + m_Rumors[index] = new BarkeeperRumor( text, null ); + else + m_Rumors[index].Message = text; + + from.Prompt = new ChangeRumorKeywordPrompt( this, index ); + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "What keyword should a guest say to me to get this news?", from.NetState ); + } + + public void EndChangeKeyword( Mobile from, int index, string text ) + { + if ( index < 0 || index >= m_Rumors.Length ) + return; + + if ( m_Rumors[index] == null ) + m_Rumors[index] = new BarkeeperRumor( null, text ); + else + m_Rumors[index].Keyword = text; + + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "I'll pass on the message.", from.NetState ); + } + + public void RemoveRumor( Mobile from, int index ) + { + if ( index < 0 || index >= m_Rumors.Length ) + return; + + m_Rumors[index] = null; + } + + public void BeginChangeTip( Mobile from ) + { + from.Prompt = new ChangeTipMessagePrompt( this ); + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Say what you want me to tell guests when they give me a good tip.", from.NetState ); + } + + public void EndChangeTip( Mobile from, string text ) + { + m_TipMessage = text; + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "I'll say that to anyone who gives me a good tip.", from.NetState ); + } + + public void RemoveTip( Mobile from ) + { + m_TipMessage = null; + } + + public void BeginChangeTitle( Mobile from ) + { + from.SendGump( new BarkeeperTitleGump( from, this ) ); + } + + public void EndChangeTitle( Mobile from, string title, bool vendor ) + { + this.Title = title; + + LoadSBInfo(); + } + + public void CancelChangeTitle( Mobile from ) + { + from.SendGump( new BarkeeperGump( from, this ) ); + } + + public void BeginChangeAppearance( Mobile from ) + { + from.CloseGump( typeof( PlayerVendorCustomizeGump ) ); + from.SendGump( new PlayerVendorCustomizeGump( this, from ) ); + } + + public void ChangeGender( Mobile from ) + { + Female = !Female; + + if ( Female ) + { + Body = 401; + Name = NameList.RandomName( "female" ); + + FacialHairItemID = 0; + } + else + { + Body = 400; + Name = NameList.RandomName( "male" ); + } + } + + private List m_SBInfos = new List(); + protected override List SBInfos{ get { return m_SBInfos; } } + + public override void InitSBInfo() + { + if ( Title == "the waiter" || Title == "the barkeeper" || Title == "the baker" || Title == "the innkeeper" || Title == "the chef" ) + { + if ( m_SBInfos.Count == 0 ) + m_SBInfos.Add( new SBPlayerBarkeeper() ); + } + else + { + m_SBInfos.Clear(); + } + } + + public PlayerBarkeeper( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version; + + writer.Write( (Item) m_House ); + + writer.Write( (Mobile) m_Owner ); + + writer.WriteEncodedInt( (int) m_Rumors.Length ); + + for ( int i = 0; i < m_Rumors.Length; ++i ) + BarkeeperRumor.Serialize( writer, m_Rumors[i] ); + + writer.Write( (string) m_TipMessage ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + House = (BaseHouse) reader.ReadItem(); + + goto case 0; + } + case 0: + { + m_Owner = reader.ReadMobile(); + + m_Rumors = new BarkeeperRumor[reader.ReadEncodedInt()]; + + for ( int i = 0; i < m_Rumors.Length; ++i ) + m_Rumors[i] = BarkeeperRumor.Deserialize( reader ); + + m_TipMessage = reader.ReadString(); + + break; + } + } + + if ( version < 1 ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( UpgradeFromVersion0 ) ); + } + + private void UpgradeFromVersion0() + { + House = BaseHouse.FindHouseAt( this ); + } + } + + public class BarkeeperTitleGump : Gump + { + private Mobile m_From; + private PlayerBarkeeper m_Barkeeper; + + private class Entry + { + public string m_Description; + public string m_Title; + public bool m_Vendor; + + public Entry( string desc ) : this( desc, String.Format( "the {0}", desc.ToLower() ), false ) + { + } + + public Entry( string desc, bool vendor ) : this( desc, String.Format( "the {0}", desc.ToLower() ), vendor ) + { + } + + public Entry( string desc, string title, bool vendor ) + { + m_Description = desc; + m_Title = title; + m_Vendor = vendor; + } + } + + private static Entry[] m_Entries = new Entry[] + { + new Entry( "Alchemist" ), + new Entry( "Animal Tamer" ), + new Entry( "Apothecary" ), + new Entry( "Artist" ), + new Entry( "Baker", true ), + new Entry( "Bard" ), + new Entry( "Barkeep", "the barkeeper", true ), + new Entry( "Beggar" ), + new Entry( "Blacksmith" ), + new Entry( "Bounty Hunter" ), + new Entry( "Brigand" ), + new Entry( "Butler" ), + new Entry( "Carpenter" ), + new Entry( "Chef", true ), + new Entry( "Commander" ), + new Entry( "Curator" ), + new Entry( "Drunkard" ), + new Entry( "Farmer" ), + new Entry( "Fisherman" ), + new Entry( "Gambler" ), + new Entry( "Gypsy" ), + new Entry( "Herald" ), + new Entry( "Herbalist" ), + new Entry( "Hermit" ), + new Entry( "Innkeeper", true ), + new Entry( "Jailor" ), + new Entry( "Jester" ), + new Entry( "Librarian" ), + new Entry( "Mage" ), + new Entry( "Mercenary" ), + new Entry( "Merchant" ), + new Entry( "Messenger" ), + new Entry( "Miner" ), + new Entry( "Monk" ), + new Entry( "Noble" ), + new Entry( "Paladin" ), + new Entry( "Peasant" ), + new Entry( "Pirate" ), + new Entry( "Prisoner" ), + new Entry( "Prophet" ), + new Entry( "Ranger" ), + new Entry( "Sage" ), + new Entry( "Sailor" ), + new Entry( "Scholar" ), + new Entry( "Scribe" ), + new Entry( "Sentry" ), + new Entry( "Servant" ), + new Entry( "Shepherd" ), + new Entry( "Soothsayer" ), + new Entry( "Stoic" ), + new Entry( "Storyteller" ), + new Entry( "Tailor" ), + new Entry( "Thief" ), + new Entry( "Tinker" ), + new Entry( "Town Crier" ), + new Entry( "Treasure Hunter" ), + new Entry( "Waiter", true ), + new Entry( "Warrior" ), + new Entry( "Watchman" ), + new Entry( "No Title", null, false ) + }; + + private void RenderBackground() + { + AddPage( 0 ); + + AddBackground( 30, 40, 585, 410, 5054 ); + + AddImage( 30, 40, 9251 ); + AddImage( 180, 40, 9251 ); + AddImage( 30, 40, 9253 ); + AddImage( 30, 130, 9253 ); + AddImage( 598, 40, 9255 ); + AddImage( 598, 130, 9255 ); + AddImage( 30, 433, 9257 ); + AddImage( 180, 433, 9257 ); + AddImage( 30, 40, 9250 ); + AddImage( 598, 40, 9252 ); + AddImage( 598, 433, 9258 ); + AddImage( 30, 433, 9256 ); + + AddItem( 30, 40, 6816 ); + AddItem( 30, 125, 6817 ); + AddItem( 30, 233, 6817 ); + AddItem( 30, 341, 6817 ); + AddItem( 580, 40, 6814 ); + AddItem( 588, 125, 6815 ); + AddItem( 588, 233, 6815 ); + AddItem( 588, 341, 6815 ); + + AddImage( 560, 20, 1417 ); + AddItem( 580, 44, 4033 ); + + AddBackground( 183, 25, 280, 30, 5054 ); + + AddImage( 180, 25, 10460 ); + AddImage( 434, 25, 10460 ); + + AddHtml( 223, 32, 200, 40, "BARKEEP CUSTOMIZATION MENU", false, false ); + AddBackground( 243, 433, 150, 30, 5054 ); + + AddImage( 240, 433, 10460 ); + AddImage( 375, 433, 10460 ); + + AddImage( 80, 398, 2151 ); + AddItem( 72, 406, 2543 ); + + AddHtml( 110, 412, 180, 25, "sells food and drink", false, false ); + } + + private void RenderPage( Entry[] entries, int page ) + { + AddPage( 1 + page ); + + AddHtml( 430, 70, 180, 25, String.Format( "Page {0} of {1}", page + 1, (entries.Length + 19) / 20 ), false, false ); + + for ( int count = 0, i = (page * 20); count < 20 && i < entries.Length; ++count, ++i ) + { + Entry entry = entries[i]; + + AddButton( 80 + ((count / 10) * 260), 100 + ((count % 10) * 30), 4005, 4007, 2 + i, GumpButtonType.Reply, 0 ); + AddHtml( 120 + ((count / 10) * 260), 100 + ((count % 10) * 30), entry.m_Vendor ? 148 : 180, 25, entry.m_Description, true, false ); + + if ( entry.m_Vendor ) + { + AddImage( 270 + ((count / 10) * 260), 98 + ((count % 10) * 30), 2151 ); + AddItem( 262 + ((count / 10) * 260), 106 + ((count % 10) * 30), 2543 ); + } + } + + AddButton( 340, 400, 4005, 4007, 0, GumpButtonType.Page, 1 + ((page + 1) % ((entries.Length + 19) / 20)) ); + AddHtml( 380, 400, 180, 25, "More Job Titles", false, false ); + + AddButton( 338, 437, 4014, 4016, 1, GumpButtonType.Reply, 0 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + } + + public BarkeeperTitleGump( Mobile from, PlayerBarkeeper barkeeper ) : base( 0, 0 ) + { + m_From = from; + m_Barkeeper = barkeeper; + + from.CloseGump( typeof( BarkeeperGump ) ); + from.CloseGump( typeof( BarkeeperTitleGump ) ); + + Entry[] entries = m_Entries; + + RenderBackground(); + + int pageCount = (entries.Length + 19) / 20; + + for ( int i = 0; i < pageCount; ++i ) + RenderPage( entries, i ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int buttonID = info.ButtonID; + + if ( buttonID > 0 ) + { + --buttonID; + + if ( buttonID > 0 ) + { + --buttonID; + + if ( buttonID >= 0 && buttonID < m_Entries.Length ) + m_Barkeeper.EndChangeTitle( m_From, m_Entries[buttonID].m_Title, m_Entries[buttonID].m_Vendor ); + } + else + { + m_Barkeeper.CancelChangeTitle( m_From ); + } + } + } + } + + public class BarkeeperGump : Gump + { + private Mobile m_From; + private PlayerBarkeeper m_Barkeeper; + + public void RenderBackground() + { + AddPage( 0 ); + + AddBackground( 30, 40, 585, 410, 5054 ); + + AddImage( 30, 40, 9251 ); + AddImage( 180, 40, 9251 ); + AddImage( 30, 40, 9253 ); + AddImage( 30, 130, 9253 ); + AddImage( 598, 40, 9255 ); + AddImage( 598, 130, 9255 ); + AddImage( 30, 433, 9257 ); + AddImage( 180, 433, 9257 ); + AddImage( 30, 40, 9250 ); + AddImage( 598, 40, 9252 ); + AddImage( 598, 433, 9258 ); + AddImage( 30, 433, 9256 ); + + AddItem( 30, 40, 6816 ); + AddItem( 30, 125, 6817 ); + AddItem( 30, 233, 6817 ); + AddItem( 30, 341, 6817 ); + AddItem( 580, 40, 6814 ); + AddItem( 588, 125, 6815 ); + AddItem( 588, 233, 6815 ); + AddItem( 588, 341, 6815 ); + + AddBackground( 183, 25, 280, 30, 5054 ); + + AddImage( 180, 25, 10460 ); + AddImage( 434, 25, 10460 ); + AddImage( 560, 20, 1417 ); + + AddHtml( 223, 32, 200, 40, "BARKEEP CUSTOMIZATION MENU", false, false ); + AddBackground( 243, 433, 150, 30, 5054 ); + + AddImage( 240, 433, 10460 ); + AddImage( 375, 433, 10460 ); + } + + public void RenderCategories() + { + AddPage( 1 ); + + AddButton( 130, 120, 4005, 4007, 0, GumpButtonType.Page, 2 ); + AddHtml( 170, 120, 200, 40, "Message Control", false, false ); + + AddButton( 130, 200, 4005, 4007, 0, GumpButtonType.Page, 8 ); + AddHtml( 170, 200, 200, 40, "Customize your barkeep", false, false ); + + AddButton( 130, 280, 4005, 4007, 0, GumpButtonType.Page, 3 ); + AddHtml( 170, 280, 200, 40, "Dismiss your barkeep", false, false ); + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Reply, 0 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 574, 43, 5360 ); + } + + public void RenderMessageManagement() + { + AddPage( 2 ); + + AddButton( 130, 120, 4005, 4007, 0, GumpButtonType.Page, 4 ); + AddHtml( 170, 120, 380, 20, "Add or change a message and keyword", false, false ); + + AddButton( 130, 200, 4005, 4007, 0, GumpButtonType.Page, 5 ); + AddHtml( 170, 200, 380, 20, "Remove a message and keyword from your barkeep", false, false ); + + AddButton( 130, 280, 4005, 4007, 0, GumpButtonType.Page, 6 ); + AddHtml( 170, 280, 380, 20, "Add or change your barkeeper's tip message", false, false ); + + AddButton( 130, 360, 4005, 4007, 0, GumpButtonType.Page, 7 ); + AddHtml( 170, 360, 380, 20, "Delete your barkeepers tip message", false, false ); + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Page, 1 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 580, 46, 4030 ); + } + + public void RenderDismissConfirmation() + { + AddPage( 3 ); + + AddHtml( 170, 160, 380, 20, "Are you sure you want to dismiss your barkeeper?", false, false ); + + AddButton( 205, 280, 4005, 4007, GetButtonID( 0, 0 ), GumpButtonType.Reply, 0 ); + AddHtml( 240, 280, 100, 20,@"Yes", false, false ); + + AddButton( 395, 280, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtml( 430, 280, 100, 20, "No", false, false ); + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Page, 1 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 574, 43, 5360 ); + AddItem( 584, 34, 6579 ); + } + + public void RenderMessageManagement_Message_AddOrChange() + { + AddPage( 4 ); + + AddHtml( 250, 60, 500, 25, "Add or change a message", false, false ); + + BarkeeperRumor[] rumors = m_Barkeeper.Rumors; + + for ( int i = 0; i < rumors.Length; ++i ) + { + BarkeeperRumor rumor = rumors[i]; + + AddHtml( 100, 70 + (i * 120), 50, 20, "Message", false, false ); + AddHtml( 100, 90 + (i * 120), 450, 40, rumor == null ? "No current message" : rumor.Message, true, false ); + AddHtml( 100, 130 + (i * 120), 50, 20, "Keyword", false, false ); + AddHtml( 100, 150 + (i * 120), 450, 40, rumor == null ? "None" : rumor.Keyword, true, false ); + + AddButton( 60, 90 + (i * 120), 4005, 4007, GetButtonID( 1, i ), GumpButtonType.Reply, 0 ); + } + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Page, 2 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 580, 46, 4030 ); + } + + public void RenderMessageManagement_Message_Remove() + { + AddPage( 5 ); + + AddHtml( 190, 60, 500, 25, "Choose the message you would like to remove", false, false ); + + BarkeeperRumor[] rumors = m_Barkeeper.Rumors; + + for ( int i = 0; i < rumors.Length; ++i ) + { + BarkeeperRumor rumor = rumors[i]; + + AddHtml( 100, 70 + (i * 120), 50, 20, "Message", false, false ); + AddHtml( 100, 90 + (i * 120), 450, 40, rumor == null ? "No current message" : rumor.Message, true, false ); + AddHtml( 100, 130 + (i * 120), 50, 20, "Keyword", false, false ); + AddHtml( 100, 150 + (i * 120), 450, 40, rumor == null ? "None" : rumor.Keyword, true, false ); + + AddButton( 60, 90 + (i * 120), 4005, 4007, GetButtonID( 2, i ), GumpButtonType.Reply, 0 ); + } + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Page, 2 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 580, 46, 4030 ); + } + + private int GetButtonID( int type, int index ) + { + return 1 + (index * 6) + type; + } + + private void RenderMessageManagement_Tip_AddOrChange() + { + AddPage( 6 ); + + AddHtml( 250, 95, 500, 20, "Change this tip message", false, false ); + AddHtml( 100, 190, 50, 20, "Message", false, false ); + AddHtml( 100, 210, 450, 40, m_Barkeeper.TipMessage == null ? "No current message" : m_Barkeeper.TipMessage, true, false ); + + AddButton( 60, 210, 4005, 4007, GetButtonID( 3, 0 ), GumpButtonType.Reply, 0 ); + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Page, 2 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 580, 46, 4030 ); + } + + private void RenderMessageManagement_Tip_Remove() + { + AddPage( 7 ); + + AddHtml( 250, 95, 500, 20, "Remove this tip message", false, false ); + AddHtml( 100, 190, 50, 20, "Message", false, false ); + AddHtml( 100, 210, 450, 40, m_Barkeeper.TipMessage == null ? "No current message" : m_Barkeeper.TipMessage, true, false ); + + AddButton( 60, 210, 4005, 4007, GetButtonID( 4, 0 ), GumpButtonType.Reply, 0 ); + + AddButton( 338, 437, 4014, 4016, 0, GumpButtonType.Page, 2 ); + AddHtml( 290, 440, 35, 40, "Back", false, false ); + + AddItem( 580, 46, 4030 ); + } + + private void RenderAppearanceCategories() + { + AddPage( 8 ); + + AddButton( 130, 120, 4005, 4007, GetButtonID( 5, 0 ), GumpButtonType.Reply, 0 ); + AddHtml( 170, 120, 120, 20, "Title", false, false ); + + if (m_Barkeeper.BodyValue != 0x340 && m_Barkeeper.BodyValue != 0x402) + { + AddButton(130, 200, 4005, 4007, GetButtonID(5, 1), GumpButtonType.Reply, 0); + AddHtml(170, 200, 120, 20, "Appearance", false, false); + + AddButton(130, 280, 4005, 4007, GetButtonID(5, 2), GumpButtonType.Reply, 0); + AddHtml(170, 280, 120, 20, "Male / Female", false, false); + + AddButton(338, 437, 4014, 4016, 0, GumpButtonType.Page, 1); + AddHtml(290, 440, 35, 40, "Back", false, false); + } + + AddItem( 580, 44, 4033 ); + } + + public BarkeeperGump( Mobile from, PlayerBarkeeper barkeeper ) : base( 0, 0 ) + { + m_From = from; + m_Barkeeper = barkeeper; + + from.CloseGump( typeof( BarkeeperGump ) ); + from.CloseGump( typeof( BarkeeperTitleGump ) ); + + RenderBackground(); + RenderCategories(); + RenderMessageManagement(); + RenderDismissConfirmation(); + RenderMessageManagement_Message_AddOrChange(); + RenderMessageManagement_Message_Remove(); + RenderMessageManagement_Tip_AddOrChange(); + RenderMessageManagement_Tip_Remove(); + RenderAppearanceCategories(); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( !m_Barkeeper.IsOwner( m_From ) ) + return; + + int index = info.ButtonID - 1; + + if ( index < 0 ) + return; + + int type = index % 6; + index /= 6; + + switch ( type ) + { + case 0: // Controls + { + switch ( index ) + { + case 0: // Dismiss + { + m_Barkeeper.Dismiss(); + break; + } + } + + break; + } + case 1: // Change message + { + m_Barkeeper.BeginChangeRumor( m_From, index ); + break; + } + case 2: // Remove message + { + m_Barkeeper.RemoveRumor( m_From, index ); + break; + } + case 3: // Change tip + { + m_Barkeeper.BeginChangeTip( m_From ); + break; + } + case 4: // Remove tip + { + m_Barkeeper.RemoveTip( m_From ); + break; + } + case 5: // Appearance category selection + { + switch ( index ) + { + case 0: m_Barkeeper.BeginChangeTitle( m_From ); break; + case 1: m_Barkeeper.BeginChangeAppearance( m_From ); break; + case 2: m_Barkeeper.ChangeGender( m_From ); break; + } + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/PlayerVendor.cs b/Scripts/Mobiles/Vendors/PlayerVendor.cs new file mode 100644 index 0000000..79a0179 --- /dev/null +++ b/Scripts/Mobiles/Vendors/PlayerVendor.cs @@ -0,0 +1,1738 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Prompts; +using Server.Targeting; +using Server.Misc; +using Server.Multis; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + [AttributeUsage( AttributeTargets.Class )] + public class PlayerVendorTargetAttribute : Attribute + { + public PlayerVendorTargetAttribute() + { + } + } + + public class VendorItem + { + private Item m_Item; + private int m_Price; + private string m_Description; + private DateTime m_Created; + + private bool m_Valid; + + public Item Item{ get{ return m_Item; } } + public int Price{ get{ return m_Price; } } + + public string FormattedPrice + { + get + { + if ( Core.ML ) + return m_Price.ToString( "N0", CultureInfo.GetCultureInfo( "en-US" ) ); + + return m_Price.ToString(); + } + } + + public string Description + { + get{ return m_Description; } + set + { + if ( value != null ) + m_Description = value; + else + m_Description = ""; + + if ( Valid ) + Item.InvalidateProperties(); + } + } + + public DateTime Created{ get{ return m_Created; } } + + public bool IsForSale{ get{ return Price >= 0; } } + public bool IsForFree{ get{ return Price == 0; } } + + public bool Valid{ get{ return m_Valid; } } + + public VendorItem( Item item, int price, string description, DateTime created ) + { + m_Item = item; + m_Price = price; + + if ( description != null ) + m_Description = description; + else + m_Description = ""; + + m_Created = created; + + m_Valid = true; + } + + public void Invalidate() + { + m_Valid = false; + } + } + + public class VendorBackpack : Backpack + { + public VendorBackpack() + { + Layer = Layer.Backpack; + Weight = 1.0; + } + + public override int DefaultMaxWeight{ get{ return 0; } } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + if ( !base.CheckHold( m, item, message, checkItems, plusItems, plusWeight ) ) + return false; + + if ( Ethics.Ethic.IsImbued( item, true ) ) + { + if ( message ) + m.SendMessage( "Imbued items may not be sold here." ); + + return false; + } + + if ( !BaseHouse.NewVendorSystem && Parent is PlayerVendor ) + { + BaseHouse house = ((PlayerVendor)Parent).House; + + if ( house != null && house.IsAosRules && !house.CheckAosStorage( 1 + item.TotalItems + plusItems ) ) + { + if ( message ) + m.SendLocalizedMessage( 1061839 ); // This action would exceed the secure storage limit of the house. + + return false; + } + } + + return true; + } + + public override bool IsAccessibleTo( Mobile m ) + { + return true; + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( !base.CheckItemUse( from, item ) ) + return false; + + if ( item is Container || item is Engines.BulkOrders.BulkOrderBook ) + return true; + + from.SendLocalizedMessage( 500447 ); // That is not accessible. + return false; + } + + public override bool CheckTarget( Mobile from, Target targ, object targeted ) + { + if ( !base.CheckTarget( from, targ, targeted ) ) + return false; + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return true; + + return targ.GetType().IsDefined( typeof( PlayerVendorTargetAttribute ), false ); + } + + public override void GetChildContextMenuEntries( Mobile from, List list, Item item ) + { + base.GetChildContextMenuEntries( from, list, item ); + + PlayerVendor pv = RootParent as PlayerVendor; + + if ( pv == null || pv.IsOwner( from ) ) + return; + + VendorItem vi = pv.GetVendorItem( item ); + + if ( vi != null ) + list.Add( new BuyEntry( item ) ); + } + + private class BuyEntry : ContextMenuEntry + { + private Item m_Item; + + public BuyEntry( Item item ) : base( 6103 ) + { + m_Item = item; + } + + public override bool NonLocalUse{ get{ return true; } } + + public override void OnClick() + { + if ( m_Item.Deleted ) + return; + + PlayerVendor.TryToBuy( m_Item, Owner.From ); + } + } + + public override void GetChildNameProperties( ObjectPropertyList list, Item item ) + { + base.GetChildNameProperties( list, item ); + + PlayerVendor pv = RootParent as PlayerVendor; + + if ( pv == null ) + return; + + VendorItem vi = pv.GetVendorItem( item ); + + if ( vi == null ) + return; + + if ( !vi.IsForSale ) + list.Add( 1043307 ); // Price: Not for sale. + else if ( vi.IsForFree ) + list.Add( 1043306 ); // Price: FREE! + else + list.Add( 1043304, vi.FormattedPrice ); // Price: ~1_COST~ + } + + public override void GetChildProperties( ObjectPropertyList list, Item item ) + { + base.GetChildProperties( list, item ); + + PlayerVendor pv = RootParent as PlayerVendor; + + if ( pv == null ) + return; + + VendorItem vi = pv.GetVendorItem( item ); + + if ( vi != null && vi.Description != null && vi.Description.Length > 0 ) + list.Add( 1043305, vi.Description ); //
Seller's Description:
"~1_DESC~" + } + + public override void OnSingleClickContained( Mobile from, Item item ) + { + if ( RootParent is PlayerVendor ) + { + PlayerVendor vendor = (PlayerVendor)RootParent; + + VendorItem vi = vendor.GetVendorItem( item ); + + if ( vi != null ) + { + if ( !vi.IsForSale ) + item.LabelTo( from, 1043307 ); // Price: Not for sale. + else if ( vi.IsForFree ) + item.LabelTo( from, 1043306 ); // Price: FREE! + else + item.LabelTo( from, 1043304, vi.FormattedPrice ); // Price: ~1_COST~ + + if ( !String.IsNullOrEmpty( vi.Description ) ) + { + // The localized message (1043305) is no longer valid -
Seller's Description:
"~1_DESC~" + item.LabelTo( from, "Description: {0}", vi.Description ); + } + } + } + + base.OnSingleClickContained( from, item ); + } + + public VendorBackpack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class PlayerVendor : Mobile + { + private Hashtable m_SellItems; + + private Mobile m_Owner; + private BaseHouse m_House; + + private int m_BankAccount; + private int m_HoldGold; + + private string m_ShopName; + + private Timer m_PayTimer; + private DateTime m_NextPayTime; + + private PlayerVendorPlaceholder m_Placeholder; + + public PlayerVendor( Mobile owner, BaseHouse house ) + { + Owner = owner; + House = house; + + if ( BaseHouse.NewVendorSystem ) + { + m_BankAccount = 0; + m_HoldGold = 4; + } + else + { + m_BankAccount = 1000; + m_HoldGold = 0; + } + + ShopName = "Shop Not Yet Named"; + + m_SellItems = new Hashtable(); + + CantWalk = true; + + if ( !Core.AOS ) + NameHue = 0x35; + + InitStats( 100, 100, 25 ); + InitBody(); + InitOutfit(); + + TimeSpan delay = PayTimer.GetInterval(); + + m_PayTimer = new PayTimer( this, delay ); + m_PayTimer.Start(); + + m_NextPayTime = DateTime.Now + delay; + } + + public PlayerVendor( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (bool) BaseHouse.NewVendorSystem ); + writer.Write( (string) m_ShopName ); + writer.WriteDeltaTime( (DateTime) m_NextPayTime ); + writer.Write( (Item) House ); + + writer.Write( (Mobile) m_Owner ); + writer.Write( (int) m_BankAccount ); + writer.Write( (int) m_HoldGold ); + + writer.Write( (int) m_SellItems.Count ); + foreach ( VendorItem vi in m_SellItems.Values ) + { + writer.Write( (Item) vi.Item ); + writer.Write( (int) vi.Price ); + writer.Write( (string) vi.Description ); + + writer.Write( (DateTime) vi.Created ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + bool newVendorSystem = false; + + switch ( version ) + { + case 1: + { + newVendorSystem = reader.ReadBool(); + m_ShopName = reader.ReadString(); + m_NextPayTime = reader.ReadDeltaTime(); + House = (BaseHouse) reader.ReadItem(); + + goto case 0; + } + case 0: + { + m_Owner = reader.ReadMobile(); + m_BankAccount = reader.ReadInt(); + m_HoldGold = reader.ReadInt(); + + m_SellItems = new Hashtable(); + + int count = reader.ReadInt(); + for ( int i = 0; i < count; i++ ) + { + Item item = reader.ReadItem(); + + int price = reader.ReadInt(); + if ( price > 100000000 ) + price = 100000000; + + string description = reader.ReadString(); + + DateTime created = version < 1 ? DateTime.Now : reader.ReadDateTime(); + + if ( item != null ) + { + SetVendorItem( item, version < 1 && price <= 0 ? -1 : price, description, created ); + } + } + + break; + } + } + + bool newVendorSystemActivated = BaseHouse.NewVendorSystem && !newVendorSystem; + + if ( version < 1 || newVendorSystemActivated ) + { + if ( version < 1 ) + { + m_ShopName = "Shop Not Yet Named"; + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( UpgradeFromVersion0 ), newVendorSystemActivated ); + } + else + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixDresswear ) ); + } + + m_NextPayTime = DateTime.Now + PayTimer.GetInterval(); + + if ( newVendorSystemActivated ) + { + m_HoldGold += m_BankAccount; + m_BankAccount = 0; + } + } + + TimeSpan delay = m_NextPayTime - DateTime.Now; + + m_PayTimer = new PayTimer( this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero ); + m_PayTimer.Start(); + + Blessed = false; + + if ( Core.AOS && NameHue == 0x35 ) + NameHue = -1; + } + + private void UpgradeFromVersion0( object newVendorSystem ) + { + List toRemove = new List(); + + foreach ( VendorItem vi in m_SellItems.Values ) + if ( !CanBeVendorItem( vi.Item ) ) + toRemove.Add( vi.Item ); + else + vi.Description = Utility.FixHtml( vi.Description ); + + foreach ( Item item in toRemove ) + RemoveVendorItem( item ); + + House = BaseHouse.FindHouseAt( this ); + + if ( (bool) newVendorSystem ) + ActivateNewVendorSystem(); + } + + private void ActivateNewVendorSystem() + { + FixDresswear(); + + if ( House != null && !House.IsOwner( Owner ) ) + Destroy( false ); + } + + public void InitBody() + { + Hue = Utility.RandomSkinHue(); + SpeechHue = 0x3B2; + + if ( !Core.AOS ) + NameHue = 0x35; + + if ( this.Female = Utility.RandomBool() ) + { + this.Body = 0x191; + this.Name = NameList.RandomName( "female" ); + } + else + { + this.Body = 0x190; + this.Name = NameList.RandomName( "male" ); + } + } + + public virtual void InitOutfit() + { + Item item = new FancyShirt( Utility.RandomNeutralHue() ); + item.Layer = Layer.InnerTorso; + AddItem( item ); + AddItem( new LongPants( Utility.RandomNeutralHue() ) ); + AddItem( new BodySash( Utility.RandomNeutralHue() ) ); + AddItem( new Boots( Utility.RandomNeutralHue() ) ); + AddItem( new Cloak( Utility.RandomNeutralHue() ) ); + + Utility.AssignRandomHair( this ); + + Container pack = new VendorBackpack(); + pack.Movable = false; + AddItem( pack ); + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int BankAccount + { + get{ return m_BankAccount; } + set{ m_BankAccount = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int HoldGold + { + get{ return m_HoldGold; } + set{ m_HoldGold = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string ShopName + { + get{ return m_ShopName; } + set + { + if ( value == null ) + m_ShopName = ""; + else + m_ShopName = value; + + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextPayTime + { + get{ return m_NextPayTime; } + } + + public PlayerVendorPlaceholder Placeholder + { + get{ return m_Placeholder; } + set{ m_Placeholder = value; } + } + + public BaseHouse House + { + get{ return m_House; } + set + { + if ( m_House != null ) + m_House.PlayerVendors.Remove( this ); + + if ( value != null ) + value.PlayerVendors.Add( this ); + + m_House = value; + } + } + + public int ChargePerDay + { + get + { + if ( BaseHouse.NewVendorSystem ) + { + return ChargePerRealWorldDay / 12; + } + else + { + long total = 0; + foreach ( VendorItem vi in m_SellItems.Values ) + { + total += vi.Price; + } + + total -= 500; + + if ( total < 0 ) + total = 0; + + return (int)( 20 + (total / 500) ); + } + } + } + + public int ChargePerRealWorldDay + { + get + { + if ( BaseHouse.NewVendorSystem ) + { + long total = 0; + foreach ( VendorItem vi in m_SellItems.Values ) + { + total += vi.Price; + } + + return (int)( 60 + (total / 500) * 3 ); + } + else + { + return ChargePerDay * 12; + } + } + } + + public virtual bool IsOwner( Mobile m ) + { + if ( m.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if ( BaseHouse.NewVendorSystem && House != null ) + { + return House.IsOwner( m ); + } + else + { + return m == Owner; + } + } + + protected List GetItems() + { + List list = new List(); + + foreach ( Item item in this.Items ) + if ( item.Movable && item != this.Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair ) + list.Add( item ); + + if ( this.Backpack != null ) + list.AddRange( this.Backpack.Items ); + + return list; + } + + public virtual void Destroy( bool toBackpack ) + { + Return(); + + if ( !BaseHouse.NewVendorSystem ) + FixDresswear(); + + /* Possible cases regarding item return: + * + * 1. No item must be returned + * -> do nothing. + * 2. ( toBackpack is false OR the vendor is in the internal map ) AND the vendor is associated with a AOS house + * -> put the items into the moving crate or a vendor inventory, + * depending on whether the vendor owner is also the house owner. + * 3. ( toBackpack is true OR the vendor isn't associated with any AOS house ) AND the vendor isn't in the internal map + * -> put the items into a backpack. + * 4. The vendor isn't associated with any house AND it's in the internal map + * -> do nothing (we can't do anything). + */ + + List list = GetItems(); + + if ( list.Count > 0 || HoldGold > 0 ) // No case 1 + { + if ( ( !toBackpack || this.Map == Map.Internal ) && House != null && House.IsAosRules ) // Case 2 + { + if ( House.IsOwner( Owner ) ) // Move to moving crate + { + if ( House.MovingCrate == null ) + House.MovingCrate = new MovingCrate( House ); + + if ( HoldGold > 0 ) + Banker.Deposit( House.MovingCrate, HoldGold ); + + foreach ( Item item in list ) + { + House.MovingCrate.DropItem( item ); + } + } + else // Move to vendor inventory + { + VendorInventory inventory = new VendorInventory( House, Owner, Name, ShopName ); + inventory.Gold = HoldGold; + + foreach ( Item item in list ) + { + inventory.AddItem( item ); + } + + House.VendorInventories.Add( inventory ); + } + } + else if ( ( toBackpack || House == null || !House.IsAosRules ) && this.Map != Map.Internal ) // Case 3 - Move to backpack + { + Container backpack = new Backpack(); + + if ( HoldGold > 0 ) + Banker.Deposit( backpack, HoldGold ); + + foreach ( Item item in list ) + { + backpack.DropItem( item ); + } + + backpack.MoveToWorld( this.Location, this.Map ); + } + } + + Delete(); + } + + private void FixDresswear() + { + for ( int i = 0; i < Items.Count; ++i ) + { + Item item = Items[i] as Item; + + if ( item is BaseHat ) + item.Layer = Layer.Helm; + else if ( item is BaseMiddleTorso ) + item.Layer = Layer.MiddleTorso; + else if ( item is BaseOuterLegs ) + item.Layer = Layer.OuterLegs; + else if ( item is BaseOuterTorso ) + item.Layer = Layer.OuterTorso; + else if ( item is BasePants ) + item.Layer = Layer.Pants; + else if ( item is BaseShirt ) + item.Layer = Layer.Shirt; + else if ( item is BaseWaist ) + item.Layer = Layer.Waist; + else if ( item is BaseShoes ) + { + if ( item is Sandals ) + item.Hue = 0; + + item.Layer = Layer.Shoes; + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_PayTimer.Stop(); + + House = null; + + if ( Placeholder != null ) + Placeholder.Delete(); + } + + public override bool IsSnoop( Mobile from ) + { + return false; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( BaseHouse.NewVendorSystem ) + { + list.Add( 1062449, ShopName ); // Shop Name: ~1_NAME~ + } + } + + public VendorItem GetVendorItem( Item item ) + { + return (VendorItem) m_SellItems[item]; + } + + private VendorItem SetVendorItem( Item item, int price, string description ) + { + return SetVendorItem( item, price, description, DateTime.Now ); + } + + private VendorItem SetVendorItem( Item item, int price, string description, DateTime created ) + { + RemoveVendorItem( item ); + + VendorItem vi = new VendorItem( item, price, description, created ); + m_SellItems[item] = vi; + + item.InvalidateProperties(); + + return vi; + } + + private void RemoveVendorItem( Item item ) + { + VendorItem vi = GetVendorItem( item ); + + if ( vi != null ) + { + vi.Invalidate(); + m_SellItems.Remove( item ); + + foreach ( Item subItem in item.Items ) + { + RemoveVendorItem( subItem ); + } + + item.InvalidateProperties(); + } + } + + private bool CanBeVendorItem( Item item ) + { + Item parent = item.Parent as Item; + + if ( parent == this.Backpack ) + return true; + + if ( parent is Container ) + { + VendorItem parentVI = GetVendorItem( parent ); + + if ( parentVI != null ) + return !parentVI.IsForSale; + } + + return false; + } + + public override void OnSubItemAdded( Item item ) + { + base.OnSubItemAdded( item ); + + if ( GetVendorItem( item ) == null && CanBeVendorItem( item ) ) + { + // TODO: default price should be dependent to the type of object + SetVendorItem( item, 999, "" ); + } + } + + public override void OnSubItemRemoved( Item item ) + { + base.OnSubItemRemoved( item ); + + if ( item.GetBounce() == null ) + RemoveVendorItem( item ); + } + + public override void OnSubItemBounceCleared( Item item ) + { + base.OnSubItemBounceCleared( item ); + + if ( !CanBeVendorItem( item ) ) + RemoveVendorItem( item ); + } + + public override void OnItemRemoved( Item item ) + { + base.OnItemRemoved( item ); + + if ( item == this.Backpack ) + { + foreach ( Item subItem in item.Items ) + { + RemoveVendorItem( subItem ); + } + } + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( !IsOwner( from ) ) + { + SayTo( from, 503209 ); // I can only take item from the shop owner. + return false; + } + + if ( item is Gold ) + { + if ( BaseHouse.NewVendorSystem ) + { + if ( this.HoldGold < 1000000 ) + { + SayTo( from, 503210 ); // I'll take that to fund my services. + + this.HoldGold += item.Amount; + item.Delete(); + + return true; + } + else + { + from.SendLocalizedMessage( 1062493 ); // Your vendor has sufficient funds for operation and cannot accept this gold. + + return false; + } + } + else + { + if ( this.BankAccount < 1000000 ) + { + SayTo( from, 503210 ); // I'll take that to fund my services. + + this.BankAccount += item.Amount; + item.Delete(); + + return true; + } + else + { + from.SendLocalizedMessage( 1062493 ); // Your vendor has sufficient funds for operation and cannot accept this gold. + + return false; + } + } + } + else + { + bool newItem = ( GetVendorItem( item ) == null ); + + if ( this.Backpack != null && this.Backpack.TryDropItem( from, item, false ) ) + { + if ( newItem ) + OnItemGiven( from, item ); + + return true; + } + else + { + SayTo( from, 503211 ); // I can't carry any more. + return false; + } + } + } + + public override bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + if ( IsOwner( from ) ) + { + if ( GetVendorItem( item ) == null ) + { + // We must wait until the item is added + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( NonLocalDropCallback ), new object[] { from, item } ); + } + + return true; + } + else + { + SayTo( from, 503209 ); // I can only take item from the shop owner. + return false; + } + } + + private void NonLocalDropCallback( object state ) + { + object[] aState = (object[]) state; + + Mobile from = (Mobile) aState[0]; + Item item = (Item) aState[1]; + + OnItemGiven( from, item ); + } + + private void OnItemGiven( Mobile from, Item item ) + { + VendorItem vi = GetVendorItem( item ); + + if ( vi != null ) + { + string name; + if ( !String.IsNullOrEmpty( item.Name ) ) + name = item.Name; + else + name = "#" + item.LabelNumber.ToString(); + + from.SendLocalizedMessage( 1043303, name ); // Type in a price and description for ~1_ITEM~ (ESC=not for sale) + from.Prompt = new VendorPricePrompt( this, vi ); + } + } + + public override bool AllowEquipFrom( Mobile from ) + { + if ( BaseHouse.NewVendorSystem && IsOwner( from ) ) + return true; + + return base.AllowEquipFrom( from ); + } + + public override bool CheckNonlocalLift( Mobile from, Item item ) + { + if ( item.IsChildOf( this.Backpack ) ) + { + if ( IsOwner( from ) ) + { + return true; + } + else + { + SayTo( from, 503223 ); // If you'd like to purchase an item, just ask. + return false; + } + } + else if ( BaseHouse.NewVendorSystem && IsOwner( from ) ) + { + return true; + } + + return base.CheckNonlocalLift( from, item ); + } + + public bool CanInteractWith( Mobile from, bool ownerOnly ) + { + if ( !from.CanSee( this ) || !Utility.InUpdateRange( from, this ) || !from.CheckAlive() ) + return false; + + if ( ownerOnly ) + return IsOwner( from ); + + if ( House != null && House.IsBanned( from ) && !IsOwner( from ) ) + { + from.SendLocalizedMessage( 1062674 ); // You can't shop from this home as you have been banned from this establishment. + return false; + } + + return true; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsOwner( from ) ) + { + SendOwnerGump( from ); + } + else if ( CanInteractWith( from, false ) ) + { + OpenBackpack( from ); + } + } + + public override void DisplayPaperdollTo( Mobile m ) + { + if ( BaseHouse.NewVendorSystem ) + { + base.DisplayPaperdollTo( m ); + } + else if ( CanInteractWith( m, false ) ) + { + OpenBackpack( m ); + } + } + + public void SendOwnerGump( Mobile to ) + { + if ( BaseHouse.NewVendorSystem ) + { + to.CloseGump( typeof( NewPlayerVendorOwnerGump ) ); + to.CloseGump( typeof( NewPlayerVendorCustomizeGump ) ); + + to.SendGump( new NewPlayerVendorOwnerGump( this ) ); + } + else + { + to.CloseGump( typeof( PlayerVendorOwnerGump ) ); + to.CloseGump( typeof( PlayerVendorCustomizeGump ) ); + + to.SendGump( new PlayerVendorOwnerGump( this ) ); + } + } + + public void OpenBackpack( Mobile from ) + { + if ( this.Backpack != null ) + { + SayTo( from, IsOwner( from ) ? 1010642 : 503208 ); // Take a look at my/your goods. + + this.Backpack.DisplayTo( from ); + } + } + + public static void TryToBuy( Item item, Mobile from ) + { + PlayerVendor vendor = item.RootParent as PlayerVendor; + + if ( vendor == null || !vendor.CanInteractWith( from, false ) ) + return; + + if ( vendor.IsOwner( from ) ) + { + vendor.SayTo( from, 503212 ); // You own this shop, just take what you want. + return; + } + + VendorItem vi = vendor.GetVendorItem( item ); + + if ( vi == null ) + { + vendor.SayTo( from, 503216 ); // You can't buy that. + } + else if ( !vi.IsForSale ) + { + vendor.SayTo( from, 503202 ); // This item is not for sale. + } + else if ( vi.Created + TimeSpan.FromMinutes( 1.0 ) > DateTime.Now ) + { + from.SendMessage( "You cannot buy this item right now. Please wait one minute and try again." ); + } + else + { + from.CloseGump( typeof( PlayerVendorBuyGump ) ); + from.SendGump( new PlayerVendorBuyGump( vendor, vi ) ); + } + } + + public void CollectGold( Mobile to ) + { + if ( HoldGold > 0 ) + { + SayTo( to, "How much of the {0} that I'm holding would you like?", HoldGold.ToString() ); + to.SendMessage( "Enter the amount of gold you wish to withdraw (ESC = CANCEL):" ); + + to.Prompt = new CollectGoldPrompt( this ); + } + else + { + SayTo( to, 503215 ); // I am holding no gold for you. + } + } + + public int GiveGold( Mobile to, int amount ) + { + if ( amount <= 0 ) + return 0; + + if ( amount > HoldGold ) + { + SayTo( to, "I'm sorry, but I'm only holding {0} gold for you.", HoldGold.ToString() ); + return 0; + } + + int amountGiven = Banker.DepositUpTo( to, amount ); + HoldGold -= amountGiven; + + if ( amountGiven > 0 ) + { + to.SendLocalizedMessage( 1060397, amountGiven.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + } + + if ( amountGiven == 0 ) + { + SayTo( to, 1070755 ); // Your bank box cannot hold the gold you are requesting. I will keep the gold until you can take it. + } + else if ( amount > amountGiven ) + { + SayTo( to, 1070756 ); // I can only give you part of the gold now, as your bank box is too full to hold the full amount. + } + else if ( HoldGold > 0 ) + { + SayTo( to, 1042639 ); // Your gold has been transferred. + } + else + { + SayTo( to, 503234 ); // All the gold I have been carrying for you has been deposited into your bank account. + } + + return amountGiven; + } + + public void Dismiss( Mobile from ) + { + Container pack = this.Backpack; + + if ( pack != null && pack.Items.Count > 0 ) + { + SayTo( from, 1038325 ); // You cannot dismiss me while I am holding your goods. + return; + } + + if ( HoldGold > 0 ) + { + GiveGold( from, HoldGold ); + + if ( HoldGold > 0 ) + return; + } + + Destroy( true ); + } + + public void Rename( Mobile from ) + { + from.SendLocalizedMessage( 1062494 ); // Enter a new name for your vendor (20 characters max): + + from.Prompt = new VendorNamePrompt( this ); + } + + public void RenameShop( Mobile from ) + { + from.SendLocalizedMessage( 1062433 ); // Enter a new name for your shop (20 chars max): + + from.Prompt = new ShopNamePrompt( this ); + } + + public bool CheckTeleport( Mobile to ) + { + if ( Deleted || !IsOwner( to ) || House == null || this.Map == Map.Internal ) + return false; + + if ( House.IsInside( to ) || to.Map != House.Map || !House.InRange( to, 5 ) ) + return false; + + if ( Placeholder == null ) + { + Placeholder = new PlayerVendorPlaceholder( this ); + Placeholder.MoveToWorld( this.Location, this.Map ); + + this.MoveToWorld( to.Location, to.Map ); + + to.SendLocalizedMessage( 1062431 ); // This vendor has been moved out of the house to your current location temporarily. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. + } + else + { + Placeholder.RestartTimer(); + + to.SendLocalizedMessage( 1062430 ); // This vendor is currently temporarily in a location outside its house. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. + } + + return true; + } + + public void Return() + { + if ( Placeholder != null ) + Placeholder.Delete(); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + if ( from.Alive && Placeholder != null && IsOwner( from ) ) + { + list.Add( new ReturnVendorEntry( this ) ); + } + + base.GetContextMenuEntries( from, list ); + } + + private class ReturnVendorEntry : ContextMenuEntry + { + private PlayerVendor m_Vendor; + + public ReturnVendorEntry( PlayerVendor vendor ) : base( 6214 ) + { + m_Vendor = vendor; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( !m_Vendor.Deleted && m_Vendor.IsOwner( from ) && from.CheckAlive() ) + m_Vendor.Return(); + } + } + + public override bool HandlesOnSpeech( Mobile from ) + { + return ( from.Alive && from.GetDistanceToSqrt( this ) <= 3 ); + } + + public bool WasNamed( string speech ) + { + return this.Name != null && Insensitive.StartsWith( speech, this.Name ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + Mobile from = e.Mobile; + + if ( e.Handled || !from.Alive || from.GetDistanceToSqrt( this ) > 3 ) + return; + + if ( e.HasKeyword( 0x3C ) || (e.HasKeyword( 0x171 ) && WasNamed( e.Speech )) ) // vendor buy, *buy* + { + if ( IsOwner( from ) ) + { + SayTo( from, 503212 ); // You own this shop, just take what you want. + } + else if ( House == null || !House.IsBanned( from ) ) + { + from.SendLocalizedMessage( 503213 ); // Select the item you wish to buy. + from.Target = new PVBuyTarget(); + + e.Handled = true; + } + } + else if ( e.HasKeyword( 0x3D ) || (e.HasKeyword( 0x172 ) && WasNamed( e.Speech )) ) // vendor browse, *browse + { + if ( House != null && House.IsBanned( from ) && !IsOwner( from ) ) + { + SayTo( from, 1062674 ); // You can't shop from this home as you have been banned from this establishment. + } + else + { + if ( WasNamed( e.Speech ) ) + OpenBackpack( from ); + else + { + IPooledEnumerable mobiles = e.Mobile.GetMobilesInRange( 2 ); + + foreach ( Mobile m in mobiles ) + if ( m is PlayerVendor && m.CanSee( e.Mobile ) && m.InLOS( e.Mobile ) ) + ((PlayerVendor)m).OpenBackpack( from ); + + mobiles.Free(); + } + + e.Handled = true; + } + } + else if ( e.HasKeyword( 0x3E ) || (e.HasKeyword( 0x173 ) && WasNamed( e.Speech )) ) // vendor collect, *collect + { + if ( IsOwner( from ) ) + { + CollectGold( from ); + + e.Handled = true; + } + } + else if ( e.HasKeyword( 0x3F ) || (e.HasKeyword( 0x174 ) && WasNamed( e.Speech )) ) // vendor status, *status + { + if ( IsOwner( from ) ) + { + SendOwnerGump( from ); + + e.Handled = true; + } + else + { + SayTo( from, 503226 ); // What do you care? You don't run this shop. + } + } + else if ( e.HasKeyword( 0x40 ) || (e.HasKeyword( 0x175 ) && WasNamed( e.Speech )) ) // vendor dismiss, *dismiss + { + if ( IsOwner( from ) ) + { + Dismiss( from ); + + e.Handled = true; + } + } + else if ( e.HasKeyword( 0x41 ) || (e.HasKeyword( 0x176 ) && WasNamed( e.Speech )) ) // vendor cycle, *cycle + { + if ( IsOwner( from ) ) + { + this.Direction = this.GetDirectionTo( from ); + + e.Handled = true; + } + } + } + + private class PayTimer : Timer + { + public static TimeSpan GetInterval() + { + if ( BaseHouse.NewVendorSystem ) + return TimeSpan.FromDays( 1.0 ); + else + return TimeSpan.FromMinutes( Clock.MinutesPerUODay ); + } + + private PlayerVendor m_Vendor; + + public PayTimer( PlayerVendor vendor, TimeSpan delay ) : base( delay, GetInterval() ) + { + m_Vendor = vendor; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + m_Vendor.m_NextPayTime = DateTime.Now + this.Interval; + + int pay; + int totalGold; + if ( BaseHouse.NewVendorSystem ) + { + pay = m_Vendor.ChargePerRealWorldDay; + totalGold = m_Vendor.HoldGold; + } + else + { + pay = m_Vendor.ChargePerDay; + totalGold = m_Vendor.BankAccount + m_Vendor.HoldGold; + } + + if ( pay > totalGold ) + { + m_Vendor.Destroy( !BaseHouse.NewVendorSystem ); + } + else + { + if ( !BaseHouse.NewVendorSystem ) + { + if ( m_Vendor.BankAccount >= pay ) + { + m_Vendor.BankAccount -= pay; + pay = 0; + } + else + { + pay -= m_Vendor.BankAccount; + m_Vendor.BankAccount = 0; + } + } + + m_Vendor.HoldGold -= pay; + } + } + } + + [PlayerVendorTarget] + private class PVBuyTarget : Target + { + public PVBuyTarget() : base( 3, false, TargetFlags.None ) + { + AllowNonlocal = true; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Item ) + { + TryToBuy( (Item) targeted, from ); + } + } + } + + private class VendorPricePrompt : Prompt + { + private PlayerVendor m_Vendor; + private VendorItem m_VI; + + public VendorPricePrompt( PlayerVendor vendor, VendorItem vi ) + { + m_Vendor = vendor; + m_VI = vi; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_VI.Valid || !m_Vendor.CanInteractWith( from, true ) ) + return; + + string firstWord; + + int sep = text.IndexOfAny( new char[] { ' ', ',' } ); + if ( sep >= 0 ) + firstWord = text.Substring( 0, sep ); + else + firstWord = text; + + int price; + string description; + + if ( int.TryParse( firstWord, out price ) ) + { + if ( sep >= 0 ) + description = text.Substring( sep + 1 ).Trim(); + else + description = ""; + } + else + { + price = -1; + description = text.Trim(); + } + + SetInfo( from, price, Utility.FixHtml( description ) ); + } + + public override void OnCancel( Mobile from ) + { + if ( !m_VI.Valid || !m_Vendor.CanInteractWith( from, true ) ) + return; + + SetInfo( from, -1, "" ); + } + + private void SetInfo( Mobile from, int price, string description ) + { + Item item = m_VI.Item; + + bool setPrice = false; + + if ( price < 0 ) // Not for sale + { + price = -1; + + if ( item is Container ) + { + if ( item is LockableContainer && ((LockableContainer)item).Locked ) + m_Vendor.SayTo( from, 1043298 ); // Locked items may not be made not-for-sale. + else if ( item.Items.Count > 0 ) + m_Vendor.SayTo( from, 1043299 ); // To be not for sale, all items in a container must be for sale. + else + setPrice = true; + } + else if ( item is BaseBook || item is Engines.BulkOrders.BulkOrderBook ) + { + setPrice = true; + } + else + { + m_Vendor.SayTo( from, 1043301 ); // Only the following may be made not-for-sale: books, containers, keyrings, and items in for-sale containers. + } + } + else + { + if ( price > 100000000 ) + { + price = 100000000; + from.SendMessage( "You cannot price items above 100,000,000 gold. The price has been adjusted." ); + } + + setPrice = true; + } + + if ( setPrice ) + { + m_Vendor.SetVendorItem( item, price, description ); + } + else + { + m_VI.Description = description; + } + } + } + + private class CollectGoldPrompt : Prompt + { + private PlayerVendor m_Vendor; + + public CollectGoldPrompt( PlayerVendor vendor ) + { + m_Vendor = vendor; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_Vendor.CanInteractWith( from, true ) ) + return; + + text = text.Trim(); + + int amount; + + if ( !int.TryParse( text, out amount ) ) + amount = 0; + + GiveGold( from, amount ); + } + + public override void OnCancel( Mobile from ) + { + if ( !m_Vendor.CanInteractWith( from, true ) ) + return; + + GiveGold( from, 0 ); + } + + private void GiveGold( Mobile to, int amount ) + { + if ( amount <= 0 ) + { + m_Vendor.SayTo( to, "Very well. I will hold on to the money for now then." ); + } + else + { + m_Vendor.GiveGold( to, amount ); + } + } + } + + private class VendorNamePrompt : Prompt + { + private PlayerVendor m_Vendor; + + public VendorNamePrompt( PlayerVendor vendor ) + { + m_Vendor = vendor; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_Vendor.CanInteractWith( from, true ) ) + return; + + string name = text.Trim(); + + if ( !NameVerification.Validate( name, 1, 20, true, true, true, 0, NameVerification.Empty ) ) + { + m_Vendor.SayTo( from, "That name is unacceptable." ); + return; + } + + m_Vendor.Name = Utility.FixHtml( name ); + + from.SendLocalizedMessage( 1062496 ); // Your vendor has been renamed. + + from.SendGump( new NewPlayerVendorOwnerGump( m_Vendor ) ); + } + } + + private class ShopNamePrompt : Prompt + { + private PlayerVendor m_Vendor; + + public ShopNamePrompt( PlayerVendor vendor ) + { + m_Vendor = vendor; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_Vendor.CanInteractWith( from, true ) ) + return; + + string name = text.Trim(); + + if ( !NameVerification.Validate( name, 1, 20, true, true, true, 0, NameVerification.Empty ) ) + { + m_Vendor.SayTo( from, "That name is unacceptable." ); + return; + } + + m_Vendor.ShopName = Utility.FixHtml( name ); + + from.SendGump( new NewPlayerVendorOwnerGump( m_Vendor ) ); + } + } + + public override bool CanBeDamaged() + { + return false; + } + + } + + public class PlayerVendorPlaceholder : Item + { + private PlayerVendor m_Vendor; + private ExpireTimer m_Timer; + + [CommandProperty( AccessLevel.GameMaster )] + public PlayerVendor Vendor{ get{ return m_Vendor; } } + + public PlayerVendorPlaceholder( PlayerVendor vendor ) : base( 0x1F28 ) + { + Hue = 0x672; + Movable = false; + + m_Vendor = vendor; + + m_Timer = new ExpireTimer( this ); + m_Timer.Start(); + } + + public PlayerVendorPlaceholder( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if ( m_Vendor != null ) + list.Add( 1062498, m_Vendor.Name ); // reserved for vendor ~1_NAME~ + } + + public void RestartTimer() + { + m_Timer.Stop(); + m_Timer.Start(); + } + + private class ExpireTimer : Timer + { + private PlayerVendorPlaceholder m_Placeholder; + + public ExpireTimer( PlayerVendorPlaceholder placeholder ) : base( TimeSpan.FromMinutes( 2.0 ) ) + { + m_Placeholder = placeholder; + + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Placeholder.Delete(); + } + } + + public override void OnDelete() + { + if ( m_Vendor != null && !m_Vendor.Deleted ) + { + m_Vendor.MoveToWorld( this.Location, this.Map ); + m_Vendor.Placeholder = null; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); + + writer.Write( (Mobile) m_Vendor ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Vendor = (PlayerVendor) reader.ReadMobile(); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Delete ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/PresetMapBuy.cs b/Scripts/Mobiles/Vendors/PresetMapBuy.cs new file mode 100644 index 0000000..a581ac1 --- /dev/null +++ b/Scripts/Mobiles/Vendors/PresetMapBuy.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections; +using Server.Items; + +namespace Server.Mobiles +{ + public class PresetMapBuyInfo : GenericBuyInfo + { + private PresetMapEntry m_Entry; + + public override bool CanCacheDisplay{ get{ return false; } } + + public PresetMapBuyInfo( PresetMapEntry entry, int price, int amount ) : base( entry.Name.ToString(), null, price, amount, 0x14EC, 0 ) + { + m_Entry = entry; + } + + public override IEntity GetEntity() + { + return new PresetMap( m_Entry ); + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/RentedVendor.cs b/Scripts/Mobiles/Vendors/RentedVendor.cs new file mode 100644 index 0000000..7fd7a8e --- /dev/null +++ b/Scripts/Mobiles/Vendors/RentedVendor.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Misc; +using Server.Multis; +using Server.ContextMenus; +using Server.Prompts; + +namespace Server.Mobiles +{ + public class VendorRentalDuration + { + public static readonly VendorRentalDuration[] Instances = new VendorRentalDuration[] + { + new VendorRentalDuration( TimeSpan.FromDays( 7.0 ), 1062361 ), // 1 Week + new VendorRentalDuration( TimeSpan.FromDays( 14.0 ), 1062362 ), // 2 Weeks + new VendorRentalDuration( TimeSpan.FromDays( 21.0 ), 1062363 ), // 3 Weeks + new VendorRentalDuration( TimeSpan.FromDays( 28.0 ), 1062364 ) // 1 Month + }; + + private TimeSpan m_Duration; + private int m_Name; + + public TimeSpan Duration{ get{ return m_Duration; } } + public int Name{ get{ return m_Name; } } + + public int ID + { + get + { + for ( int i = 0; i < Instances.Length; i++ ) + { + if ( Instances[i] == this ) + return i; + } + + return 0; + } + } + + private VendorRentalDuration( TimeSpan duration, int name ) + { + m_Duration = duration; + m_Name = name; + } + } + + public class RentedVendor : PlayerVendor + { + private VendorRentalDuration m_RentalDuration; + private int m_RentalPrice; + private bool m_LandlordRenew; + private bool m_RenterRenew; + private int m_RenewalPrice; + + private int m_RentalGold; + + private DateTime m_RentalExpireTime; + private Timer m_RentalExpireTimer; + + public RentedVendor( Mobile owner, BaseHouse house, VendorRentalDuration duration, int rentalPrice, bool landlordRenew, int rentalGold ) : base( owner, house ) + { + m_RentalDuration = duration; + m_RentalPrice = m_RenewalPrice = rentalPrice; + m_LandlordRenew = landlordRenew; + m_RenterRenew = false; + + m_RentalGold = rentalGold; + + m_RentalExpireTime = DateTime.Now + duration.Duration; + m_RentalExpireTimer = new RentalExpireTimer( this, duration.Duration ); + m_RentalExpireTimer.Start(); + } + + public RentedVendor( Serial serial ) : base( serial ) + { + } + + public VendorRentalDuration RentalDuration + { + get{ return m_RentalDuration; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RentalPrice + { + get{ return m_RentalPrice; } + set{ m_RentalPrice = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LandlordRenew + { + get{ return m_LandlordRenew; } + set{ m_LandlordRenew = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RenterRenew + { + get{ return m_RenterRenew; } + set{ m_RenterRenew = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Renew + { + get{ return LandlordRenew && RenterRenew && House != null && House.DecayType != DecayType.Condemned; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RenewalPrice + { + get{ return m_RenewalPrice; } + set{ m_RenewalPrice = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RentalGold + { + get{ return m_RentalGold; } + set{ m_RentalGold = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime RentalExpireTime + { + get{ return m_RentalExpireTime; } + } + + public override bool IsOwner(Mobile m) + { + return m == Owner || m.AccessLevel >= AccessLevel.GameMaster || (Core.ML && AccountHandler.CheckAccount(m, Owner)); + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Landlord + { + get + { + if ( House != null ) + return House.Owner; + + return null; + } + } + + public bool IsLandlord( Mobile m ) + { + return House != null && House.IsOwner( m ); + } + + public void ComputeRentalExpireDelay( out int days, out int hours ) + { + TimeSpan delay = RentalExpireTime - DateTime.Now; + + if ( delay <= TimeSpan.Zero ) + { + days = 0; + hours = 0; + } + else + { + days = delay.Days; + hours = delay.Hours; + } + } + + public void SendRentalExpireMessage( Mobile to ) + { + int days, hours; + ComputeRentalExpireDelay( out days, out hours ); + + to.SendLocalizedMessage( 1062464, days.ToString() + "\t" + hours.ToString() ); // The rental contract on this vendor will expire in ~1_DAY~ day(s) and ~2_HOUR~ hour(s). + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + m_RentalExpireTimer.Stop(); + } + + public override void Destroy( bool toBackpack ) + { + if ( RentalGold > 0 && House != null && House.IsAosRules ) + { + if ( House.MovingCrate == null ) + House.MovingCrate = new MovingCrate( House ); + + Banker.Deposit( House.MovingCrate, RentalGold ); + RentalGold = 0; + } + + base.Destroy( toBackpack ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + if ( from.Alive ) + { + if ( IsOwner( from ) ) + { + list.Add( new ContractOptionsEntry( this ) ); + } + else if ( IsLandlord( from ) ) + { + if ( RentalGold > 0 ) + list.Add( new CollectRentEntry( this ) ); + + list.Add( new TerminateContractEntry( this ) ); + list.Add( new ContractOptionsEntry( this ) ); + } + } + + base.GetContextMenuEntries( from, list ); + } + + private class ContractOptionsEntry : ContextMenuEntry + { + private RentedVendor m_Vendor; + + public ContractOptionsEntry( RentedVendor vendor ) : base( 6209 ) + { + m_Vendor = vendor; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( m_Vendor.Deleted || !from.CheckAlive() ) + return; + + if ( m_Vendor.IsOwner( from ) ) + { + from.CloseGump( typeof( RenterVendorRentalGump ) ); + from.SendGump( new RenterVendorRentalGump( m_Vendor ) ); + + m_Vendor.SendRentalExpireMessage( from ); + } + else if ( m_Vendor.IsLandlord( from ) ) + { + from.CloseGump( typeof( LandlordVendorRentalGump ) ); + from.SendGump( new LandlordVendorRentalGump( m_Vendor ) ); + + m_Vendor.SendRentalExpireMessage( from ); + } + } + } + + private class CollectRentEntry : ContextMenuEntry + { + private RentedVendor m_Vendor; + + public CollectRentEntry( RentedVendor vendor ) : base( 6212 ) + { + m_Vendor = vendor; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( m_Vendor.Deleted || !from.CheckAlive() || !m_Vendor.IsLandlord( from ) ) + return; + + if ( m_Vendor.RentalGold > 0 ) + { + int depositedGold = Banker.DepositUpTo( from, m_Vendor.RentalGold ); + m_Vendor.RentalGold -= depositedGold; + + if ( depositedGold > 0 ) + from.SendLocalizedMessage( 1060397, depositedGold.ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + + if ( m_Vendor.RentalGold > 0 ) + from.SendLocalizedMessage( 500390 ); // Your bank box is full. + } + } + } + + private class TerminateContractEntry : ContextMenuEntry + { + private RentedVendor m_Vendor; + + public TerminateContractEntry( RentedVendor vendor ) : base( 6218 ) + { + m_Vendor = vendor; + } + + public override void OnClick() + { + Mobile from = Owner.From; + + if ( m_Vendor.Deleted || !from.CheckAlive() || !m_Vendor.IsLandlord( from ) ) + return; + + from.SendLocalizedMessage( 1062503 ); // Enter the amount of gold you wish to offer the renter in exchange for immediate termination of this contract? + from.Prompt = new RefundOfferPrompt( m_Vendor ); + } + } + + private class RefundOfferPrompt : Prompt + { + private RentedVendor m_Vendor; + + public RefundOfferPrompt( RentedVendor vendor ) + { + m_Vendor = vendor; + } + + public override void OnResponse( Mobile from, string text ) + { + if ( !m_Vendor.CanInteractWith( from, false ) || !m_Vendor.IsLandlord( from ) ) + return; + + text = text.Trim(); + + int amount; + + if ( !int.TryParse( text, out amount ) ) + amount = -1; + + Mobile owner = m_Vendor.Owner; + if ( owner == null ) + return; + + if ( amount < 0 ) + { + from.SendLocalizedMessage( 1062506 ); // You did not enter a valid amount. Offer canceled. + } + else if ( Banker.GetBalance( from ) < amount ) + { + from.SendLocalizedMessage( 1062507 ); // You do not have that much money in your bank account. + } + else if ( owner.Map != m_Vendor.Map || !owner.InRange( m_Vendor, 5 ) ) + { + from.SendLocalizedMessage( 1062505 ); // The renter must be closer to the vendor in order for you to make this offer. + } + else + { + from.SendLocalizedMessage( 1062504 ); // Please wait while the renter considers your offer. + + owner.CloseGump( typeof( VendorRentalRefundGump ) ); + owner.SendGump( new VendorRentalRefundGump( m_Vendor, from, amount ) ); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.WriteEncodedInt( m_RentalDuration.ID ); + + writer.Write( (int) m_RentalPrice ); + writer.Write( (bool) m_LandlordRenew ); + writer.Write( (bool) m_RenterRenew ); + writer.Write( (int) m_RenewalPrice ); + + writer.Write( (int) m_RentalGold ); + + writer.WriteDeltaTime( (DateTime) m_RentalExpireTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + int durationID = reader.ReadEncodedInt(); + if ( durationID < VendorRentalDuration.Instances.Length ) + m_RentalDuration = VendorRentalDuration.Instances[durationID]; + else + m_RentalDuration = VendorRentalDuration.Instances[0]; + + m_RentalPrice = reader.ReadInt(); + m_LandlordRenew = reader.ReadBool(); + m_RenterRenew = reader.ReadBool(); + m_RenewalPrice = reader.ReadInt(); + + m_RentalGold = reader.ReadInt(); + + m_RentalExpireTime = reader.ReadDeltaTime(); + + TimeSpan delay = m_RentalExpireTime - DateTime.Now; + m_RentalExpireTimer = new RentalExpireTimer( this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero ); + m_RentalExpireTimer.Start(); + } + + private class RentalExpireTimer : Timer + { + private RentedVendor m_Vendor; + + public RentalExpireTimer( RentedVendor vendor, TimeSpan delay ) : base( delay, vendor.RentalDuration.Duration ) + { + m_Vendor = vendor; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + int renewalPrice = m_Vendor.RenewalPrice; + + if ( m_Vendor.Renew && m_Vendor.HoldGold >= renewalPrice ) + { + m_Vendor.HoldGold -= renewalPrice; + m_Vendor.RentalGold += renewalPrice; + + m_Vendor.RentalPrice = renewalPrice; + + m_Vendor.m_RentalExpireTime = DateTime.Now + m_Vendor.RentalDuration.Duration; + } + else + { + m_Vendor.Destroy( false ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs new file mode 100644 index 0000000..4366d8d --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBChainmailArmor.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBChainmailArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBChainmailArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( ChainCoif ), 17, 20, 0x13BB, 0 ) ); + Add( new GenericBuyInfo( typeof( ChainChest ), 143, 20, 0x13BF, 0 ) ); + Add( new GenericBuyInfo( typeof( ChainLegs ), 149, 20, 0x13BE, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( ChainCoif ), 6 ); + Add( typeof( ChainChest ), 71 ); + Add( typeof( ChainLegs ), 74 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs new file mode 100644 index 0000000..9b73225 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBHelmetArmor.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHelmetArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBHelmetArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( PlateHelm ), 21, 20, 0x1412, 0 ) ); + Add( new GenericBuyInfo( typeof( CloseHelm ), 18, 20, 0x1408, 0 ) ); + Add( new GenericBuyInfo( typeof( CloseHelm ), 18, 20, 0x1409, 0 ) ); + Add( new GenericBuyInfo( typeof( Helmet ), 31, 20, 0x140A, 0 ) ); + Add( new GenericBuyInfo( typeof( Helmet ), 18, 20, 0x140B, 0 ) ); + Add( new GenericBuyInfo( typeof( NorseHelm ), 18, 20, 0x140E, 0 ) ); + Add( new GenericBuyInfo( typeof( NorseHelm ), 18, 20, 0x140F, 0 ) ); + Add( new GenericBuyInfo( typeof( Bascinet ), 18, 20, 0x140C, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateHelm ), 21, 20, 0x1419, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bascinet ), 9 ); + Add( typeof( CloseHelm ), 9 ); + Add( typeof( Helmet ), 9 ); + Add( typeof( NorseHelm ), 9 ); + Add( typeof( PlateHelm ), 10 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs new file mode 100644 index 0000000..ae727bd --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBLeatherArmor.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBLeatherArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBLeatherArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( LeatherArms ), 80, 20, 0x13CD, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherChest ), 101, 20, 0x13CC, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherGloves ), 60, 20, 0x13C6, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherGorget ), 74, 20, 0x13C7, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherLegs ), 80, 20, 0x13cb, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherCap ), 10, 20, 0x1DB9, 0 ) ); + Add( new GenericBuyInfo( typeof( FemaleLeatherChest ), 116, 20, 0x1C06, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherBustierArms ), 97, 20, 0x1C0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherShorts ), 86, 20, 0x1C00, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherSkirt ), 87, 20, 0x1C08, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( LeatherArms ), 40 ); + Add( typeof( LeatherChest ), 52 ); + Add( typeof( LeatherGloves ), 30 ); + Add( typeof( LeatherGorget ), 37 ); + Add( typeof( LeatherLegs ), 40 ); + Add( typeof( LeatherCap ), 5 ); + + + Add( typeof( FemaleLeatherChest ), 18 ); + Add( typeof( FemaleStuddedChest ), 25 ); + Add( typeof( LeatherShorts ), 14 ); + Add( typeof( LeatherSkirt ), 11 ); + Add( typeof( LeatherBustierArms ), 11 ); + Add( typeof( StuddedBustierArms ), 27 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs new file mode 100644 index 0000000..03ac4d8 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBMetalShields.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMetalShields : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMetalShields() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BronzeShield ), 66, 20, 0x1B72, 0 ) ); + Add( new GenericBuyInfo( typeof( Buckler ), 50, 20, 0x1B73, 0 ) ); + Add( new GenericBuyInfo( typeof( MetalKiteShield ), 123, 20, 0x1B74, 0 ) ); + Add( new GenericBuyInfo( typeof( HeaterShield ), 231, 20, 0x1B76, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenKiteShield ), 70, 20, 0x1B78, 0 ) ); + Add( new GenericBuyInfo( typeof( MetalShield ), 121, 20, 0x1B7B, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Buckler ), 25 ); + Add( typeof( BronzeShield ), 33 ); + Add( typeof( MetalShield ), 60 ); + Add( typeof( MetalKiteShield ), 62 ); + Add( typeof( HeaterShield ), 115 ); + Add( typeof( WoodenKiteShield ), 35 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs new file mode 100644 index 0000000..a7de9d6 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBPlateArmor.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPlateArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBPlateArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( PlateGorget ), 104, 20, 0x1413, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateChest ), 243, 20, 0x1415, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateLegs ), 218, 20, 0x1411, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateArms ), 188, 20, 0x1410, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateGloves ), 155, 20, 0x1414, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( PlateArms ), 94 ); + Add( typeof( PlateChest ), 121 ); + Add( typeof( PlateGloves ), 72 ); + Add( typeof( PlateGorget ), 52 ); + Add( typeof( PlateLegs ), 109 ); + + Add( typeof( FemalePlateChest ), 113 ); + + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs new file mode 100644 index 0000000..2afd3bc --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBRingmailArmor.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRingmailArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBRingmailArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( RingmailChest ), 121, 20, 0x13ec, 0 ) ); + Add( new GenericBuyInfo( typeof( RingmailLegs ), 90, 20, 0x13F0, 0 ) ); + Add( new GenericBuyInfo( typeof( RingmailArms ), 85, 20, 0x13EE, 0 ) ); + Add( new GenericBuyInfo( typeof( RingmailGloves ), 93, 20, 0x13eb, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( RingmailArms ), 42 ); + Add( typeof( RingmailChest ), 60 ); + Add( typeof( RingmailGloves ), 26 ); + Add( typeof( RingmailLegs ), 45 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs new file mode 100644 index 0000000..a31b76a --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBStuddedArmor.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBStuddedArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBStuddedArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( StuddedArms ), 87, 20, 0x13DC, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedChest ), 128, 20, 0x13DB, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedGloves ), 79, 20, 0x13D5, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedGorget ), 73, 20, 0x13D6, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedLegs ), 103, 20, 0x13DA, 0 ) ); + Add( new GenericBuyInfo( typeof( FemaleStuddedChest ), 142, 20, 0x1C02, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedBustierArms ), 120, 20, 0x1c0c, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( StuddedArms ), 43 ); + Add( typeof( StuddedChest ), 64 ); + Add( typeof( StuddedGloves ), 39 ); + Add( typeof( StuddedGorget ), 36 ); + Add( typeof( StuddedLegs ), 51 ); + Add( typeof( FemaleStuddedChest ), 71 ); + Add( typeof( StuddedBustierArms ), 60 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs new file mode 100644 index 0000000..c91c297 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Armors/SBWoodenShields.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWoodenShields: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBWoodenShields() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( WoodenShield ), 30, 20, 0x1B7A, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( WoodenShield ), 15 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBAlchemist.cs b/Scripts/Mobiles/Vendors/SBInfo/SBAlchemist.cs new file mode 100644 index 0000000..d1c850b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBAlchemist.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBAlchemist : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBAlchemist() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 10, 0xF0B, 0 ) ); + Add( new GenericBuyInfo( typeof( AgilityPotion ), 15, 10, 0xF08, 0 ) ); + Add( new GenericBuyInfo( typeof( NightSightPotion ), 15, 10, 0xF06, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 10, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( StrengthPotion ), 15, 10, 0xF09, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserPoisonPotion ), 15, 10, 0xF0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserCurePotion ), 15, 10, 0xF07, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserExplosionPotion ), 21, 10, 0xF0D, 0 ) ); + Add( new GenericBuyInfo( typeof( MortarPestle ), 8, 10, 0xE9B, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlackPearl ), 5, 20, 0xF7A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 20, 0xF8C, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bottle ), 5, 100, 0xF0E, 0 ) ); + Add( new GenericBuyInfo( typeof( HeatingStand ), 2, 100, 0x1849, 0 ) ); + + Add( new GenericBuyInfo( "1041060", typeof( HairDye ), 37, 10, 0xEFF, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BlackPearl ), 3 ); + Add( typeof( Bloodmoss ), 3 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( SulfurousAsh ), 2 ); + Add( typeof( Bottle ), 3 ); + Add( typeof( MortarPestle ), 4 ); + Add( typeof( HairDye ), 19 ); + + Add( typeof( NightSightPotion ), 7 ); + Add( typeof( AgilityPotion ), 7 ); + Add( typeof( StrengthPotion ), 7 ); + Add( typeof( RefreshPotion ), 7 ); + Add( typeof( LesserCurePotion ), 7 ); + Add( typeof( LesserHealPotion ), 7 ); + Add( typeof( LesserPoisonPotion ), 7 ); + Add( typeof( LesserExplosionPotion ), 10 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs b/Scripts/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs new file mode 100644 index 0000000..952e44b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBAnimalTrainer.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBAnimalTrainer : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBAnimalTrainer() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new AnimalBuyInfo( 1, typeof( Cat ), 132, 10, 201, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Dog ), 170, 10, 217, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Horse ), 550, 10, 204, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( PackHorse ), 631, 10, 291, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( PackLlama ), 565, 10, 292, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Rabbit ), 106, 10, 205, 0 ) ); + + if( !Core.AOS ) + { + Add( new AnimalBuyInfo( 1, typeof( Eagle ), 402, 10, 5, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( BrownBear ), 855, 10, 167, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( GrizzlyBear ), 1767, 10, 212, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Panther ), 1271, 10, 214, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( TimberWolf ), 768, 10, 225, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Rat ), 107, 10, 238, 0 ) ); + } + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBArchitect.cs b/Scripts/Mobiles/Vendors/SBInfo/SBArchitect.cs new file mode 100644 index 0000000..1070610 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBArchitect.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBArchitect : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBArchitect() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( "1041280", typeof( InteriorDecorator ), 10001, 20, 0xFC1, 0 ) ); + if ( Core.AOS ) + Add( new GenericBuyInfo( "1060651", typeof( HousePlacementTool ), 627, 20, 0x14F6, 0 )); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( InteriorDecorator ), 5000 ); + + if ( Core.AOS ) + Add( typeof( HousePlacementTool ), 301 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBaker.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBaker.cs new file mode 100644 index 0000000..20463c6 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBaker.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBaker : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBaker() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BreadLoaf ), 6, 20, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( BreadLoaf ), 5, 20, 0x103C, 0 ) ); + Add( new GenericBuyInfo( typeof( ApplePie ), 7, 20, 0x1041, 0 ) ); //OSI just has Pie, not Apple/Fruit/Meat + Add( new GenericBuyInfo( typeof( Cake ), 13, 20, 0x9E9, 0 ) ); + Add( new GenericBuyInfo( typeof( Muffins ), 3, 20, 0x9EA, 0 ) ); + Add( new GenericBuyInfo( typeof( SackFlour ), 3, 20, 0x1039, 0 ) ); + Add( new GenericBuyInfo( typeof( FrenchBread ), 5, 20, 0x98C, 0 ) ); + Add( new GenericBuyInfo( typeof( Cookies ), 3, 20, 0x160b, 0 ) ); + Add( new GenericBuyInfo( typeof( CheesePizza ), 8, 10, 0x1040, 0 ) ); // OSI just has Pizza + Add( new GenericBuyInfo( typeof( JarHoney ), 3, 20, 0x9ec, 0 ) ); + Add (new GenericBuyInfo( typeof( BowlFlour ), 7, 20, 0xA1E, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BreadLoaf ), 3 ); + Add( typeof( FrenchBread ), 1 ); + Add( typeof( Cake ), 5 ); + Add( typeof( Cookies ), 3 ); + Add( typeof( Muffins ), 2 ); + Add( typeof( CheesePizza ), 4 ); + Add( typeof( ApplePie ), 5 ); + Add( typeof( PeachCobbler ), 5 ); + Add( typeof( Quiche ), 6 ); + Add( typeof( Dough ), 4 ); + Add( typeof( JarHoney ), 1 ); + Add( typeof( Pitcher ), 5 ); + Add( typeof( SackFlour ), 1 ); + Add( typeof( Eggs ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBanker.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBanker.cs new file mode 100644 index 0000000..b77a922 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBanker.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBanker : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBanker() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( "1041243", typeof( ContractOfEmployment ), 1252, 20, 0x14F0, 0 ) ); + + if ( Multis.BaseHouse.NewVendorSystem ) + Add( new GenericBuyInfo( "1062332", typeof( VendorRentalContract ), 1252, 20, 0x14F0, 0x672 ) ); + Add( new GenericBuyInfo( "1047016", typeof( CommodityDeed ), 5, 20, 0x14F0, 0x47 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBard.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBard.cs new file mode 100644 index 0000000..6b78616 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBard.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBard: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBard() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Drums ), 21, ( 10 ), 0x0E9C, 0 ) ); + Add( new GenericBuyInfo( typeof( Tambourine ), 21, ( 10 ), 0x0E9E, 0 ) ); + Add( new GenericBuyInfo( typeof( LapHarp ), 21, ( 10 ), 0x0EB2, 0 ) ); + Add( new GenericBuyInfo( typeof( Lute ), 21, ( 10 ), 0x0EB3, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( LapHarp ), 10 ); + Add( typeof( Lute ), 10 ); + Add( typeof( Drums ), 10 ); + Add( typeof( Harp ), 10 ); + Add( typeof( Tambourine ), 10 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBarkeeper.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBarkeeper.cs new file mode 100644 index 0000000..db9e1e1 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBarkeeper.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBarkeeper : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBarkeeper() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Ale, 7, 20, 0x99F, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Wine, 7, 20, 0x9C7, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Liquor, 7, 20, 0x99B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Jug ), BeverageType.Cider, 13, 20, 0x9C8, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Milk, 56, 20, 0x9F0, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Ale, 88, 20, 0x1F95, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Cider, 88, 20, 0x1F97, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Liquor, 88, 20, 0x1F99, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Wine, 88, 20, 0x1F9B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Water, 88, 20, 0x1F9D, 0 ) ); + + Add( new GenericBuyInfo( typeof( BreadLoaf ), 6, 10, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( CheeseWheel ), 21, 10, 0x97E, 0 ) ); + Add( new GenericBuyInfo( typeof( CookedBird ), 17, 20, 0x9B7, 0 ) ); + Add( new GenericBuyInfo( typeof( LambLeg ), 8, 20, 0x160A, 0 ) ); + + Add( new GenericBuyInfo( typeof( WoodenBowlOfCarrots ), 3, 20, 0x15F9, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfCorn ), 3, 20, 0x15FA, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfLettuce ), 3, 20, 0x15FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfPeas ), 3, 20, 0x15FC, 0 ) ); + Add( new GenericBuyInfo( typeof( EmptyPewterBowl ), 2, 20, 0x15FD, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfCorn ), 3, 20, 0x15FE, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfLettuce ), 3, 20, 0x15FF, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPeas ), 3, 20, 0x1600, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPotatos ), 3, 20, 0x1601, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfStew ), 3, 20, 0x1604, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfTomatoSoup ), 3, 20, 0x1606, 0 ) ); + + Add( new GenericBuyInfo( typeof( ApplePie ), 7, 20, 0x1041, 0 ) ); //OSI just has Pie, not Apple/Fruit/Meat + + Add( new GenericBuyInfo( "1016450", typeof( Chessboard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( "1016449", typeof( CheckerBoard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( typeof( Backgammon ), 2, 20, 0xE1C, 0 ) ); + Add( new GenericBuyInfo( typeof( Dices ), 2, 20, 0xFA7, 0 ) ); + Add( new GenericBuyInfo( "1041243", typeof( ContractOfEmployment ), 1252, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "a barkeep contract", typeof( BarkeepContract ), 1252, 20, 0x14F0, 0 ) ); + if ( Multis.BaseHouse.NewVendorSystem ) + Add( new GenericBuyInfo( "1062332", typeof( VendorRentalContract ), 1252, 20, 0x14F0, 0x672 ) ); + + /*if ( Map == Tokuno ) + { + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); + }*/ + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( WoodenBowlOfCarrots ), 1 ); + Add( typeof( WoodenBowlOfCorn ), 1 ); + Add( typeof( WoodenBowlOfLettuce ), 1 ); + Add( typeof( WoodenBowlOfPeas ), 1 ); + Add( typeof( EmptyPewterBowl ), 1 ); + Add( typeof( PewterBowlOfCorn ), 1 ); + Add( typeof( PewterBowlOfLettuce ), 1 ); + Add( typeof( PewterBowlOfPeas ), 1 ); + Add( typeof( PewterBowlOfPotatos ), 1 ); + Add( typeof( WoodenBowlOfStew ), 1 ); + Add( typeof( WoodenBowlOfTomatoSoup ), 1 ); + Add( typeof( BeverageBottle ), 3 ); + Add( typeof( Jug ), 6 ); + Add( typeof( Pitcher ), 5 ); + Add( typeof( GlassMug ), 1 ); + Add( typeof( BreadLoaf ), 3 ); + Add( typeof( CheeseWheel ), 12 ); + Add( typeof( Ribs ), 6 ); + Add( typeof( Peach ), 1 ); + Add( typeof( Pear ), 1 ); + Add( typeof( Grapes ), 1 ); + Add( typeof( Apple ), 1 ); + Add( typeof( Banana ), 1 ); + Add( typeof( Candle ), 3 ); + Add( typeof( Chessboard ), 1 ); + Add( typeof( CheckerBoard ), 1 ); + Add( typeof( Backgammon ), 1 ); + Add( typeof( Dices ), 1 ); + Add( typeof( ContractOfEmployment ), 626 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBeekeeper.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBeekeeper.cs new file mode 100644 index 0000000..5df5346 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBeekeeper.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBeekeeper : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBeekeeper() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( JarHoney ), 3, 20, 0x9EC, 0 ) ); + Add( new GenericBuyInfo( typeof( Beeswax ), 2, 20, 0x1422, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( JarHoney ), 1 ); + Add( typeof( Beeswax ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBlacksmith.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBlacksmith.cs new file mode 100644 index 0000000..6c3e442 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBlacksmith.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBlacksmith : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBlacksmith() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( IronIngot ), 5, 16, 0x1BF2, 0 ) ); + Add( new GenericBuyInfo( typeof( Tongs ), 13, 14, 0xFBB, 0 ) ); + + Add( new GenericBuyInfo( typeof( BronzeShield ), 66, 20, 0x1B72, 0 ) ); + Add( new GenericBuyInfo( typeof( Buckler ), 50, 20, 0x1B73, 0 ) ); + Add( new GenericBuyInfo( typeof( MetalKiteShield ), 123, 20, 0x1B74, 0 ) ); + Add( new GenericBuyInfo( typeof( HeaterShield ), 231, 20, 0x1B76, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenKiteShield ), 70, 20, 0x1B78, 0 ) ); + Add( new GenericBuyInfo( typeof( MetalShield ), 121, 20, 0x1B7B, 0 ) ); + + Add( new GenericBuyInfo( typeof( WoodenShield ), 30, 20, 0x1B7A, 0 ) ); + + Add( new GenericBuyInfo( typeof( PlateGorget ), 104, 20, 0x1413, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateChest ), 243, 20, 0x1415, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateLegs ), 218, 20, 0x1411, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateArms ), 188, 20, 0x1410, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateGloves ), 155, 20, 0x1414, 0 ) ); + + Add( new GenericBuyInfo( typeof( PlateHelm ), 21, 20, 0x1412, 0 ) ); + Add( new GenericBuyInfo( typeof( CloseHelm ), 18, 20, 0x1408, 0 ) ); + Add( new GenericBuyInfo( typeof( CloseHelm ), 18, 20, 0x1409, 0 ) ); + Add( new GenericBuyInfo( typeof( Helmet ), 31, 20, 0x140A, 0 ) ); + Add( new GenericBuyInfo( typeof( Helmet ), 18, 20, 0x140B, 0 ) ); + Add( new GenericBuyInfo( typeof( NorseHelm ), 18, 20, 0x140E, 0 ) ); + Add( new GenericBuyInfo( typeof( NorseHelm ), 18, 20, 0x140F, 0 ) ); + Add( new GenericBuyInfo( typeof( Bascinet ), 18, 20, 0x140C, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateHelm ), 21, 20, 0x1419, 0 ) ); + + Add( new GenericBuyInfo( typeof( ChainCoif ), 17, 20, 0x13BB, 0 ) ); + Add( new GenericBuyInfo( typeof( ChainChest ), 143, 20, 0x13BF, 0 ) ); + Add( new GenericBuyInfo( typeof( ChainLegs ), 149, 20, 0x13BE, 0 ) ); + + Add( new GenericBuyInfo( typeof( RingmailChest ), 121, 20, 0x13ec, 0 ) ); + Add( new GenericBuyInfo( typeof( RingmailLegs ), 90, 20, 0x13F0, 0 ) ); + Add( new GenericBuyInfo( typeof( RingmailArms ), 85, 20, 0x13EE, 0 ) ); + Add( new GenericBuyInfo( typeof( RingmailGloves ), 93, 20, 0x13eb, 0 ) ); + + Add( new GenericBuyInfo( typeof( ExecutionersAxe ), 30, 20, 0xF45, 0 ) ); + Add( new GenericBuyInfo( typeof( Bardiche ), 60, 20, 0xF4D, 0 ) ); + Add( new GenericBuyInfo( typeof( BattleAxe ), 26, 20, 0xF47, 0 ) ); + Add( new GenericBuyInfo( typeof( TwoHandedAxe ), 32, 20, 0x1443, 0 ) ); + Add( new GenericBuyInfo( typeof( Bow ), 35, 20, 0x13B2, 0 ) ); + Add( new GenericBuyInfo( typeof( ButcherKnife ), 14, 20, 0x13F6, 0 ) ); + Add( new GenericBuyInfo( typeof( Crossbow ), 46, 20, 0xF50, 0 ) ); + Add( new GenericBuyInfo( typeof( HeavyCrossbow ), 55, 20, 0x13FD, 0 ) ); + Add( new GenericBuyInfo( typeof( Cutlass ), 24, 20, 0x1441, 0 ) ); + Add( new GenericBuyInfo( typeof( Dagger ), 21, 20, 0xF52, 0 ) ); + Add( new GenericBuyInfo( typeof( Halberd ), 42, 20, 0x143E, 0 ) ); + Add( new GenericBuyInfo( typeof( HammerPick ), 26, 20, 0x143D, 0 ) ); + Add( new GenericBuyInfo( typeof( Katana ), 33, 20, 0x13FF, 0 ) ); + Add( new GenericBuyInfo( typeof( Kryss ), 32, 20, 0x1401, 0 ) ); + Add( new GenericBuyInfo( typeof( Broadsword ), 35, 20, 0xF5E, 0 ) ); + Add( new GenericBuyInfo( typeof( Longsword ), 55, 20, 0xF61, 0 ) ); + Add( new GenericBuyInfo( typeof( ThinLongsword ), 27, 20, 0x13B8, 0 ) ); + Add( new GenericBuyInfo( typeof( VikingSword ), 55, 20, 0x13B9, 0 ) ); + Add( new GenericBuyInfo( typeof( Cleaver ), 15, 20, 0xEC3, 0 ) ); + Add( new GenericBuyInfo( typeof( Axe ), 40, 20, 0xF49, 0 ) ); + Add( new GenericBuyInfo( typeof( DoubleAxe ), 52, 20, 0xF4B, 0 ) ); + Add( new GenericBuyInfo( typeof( Pickaxe ), 22, 20, 0xE86, 0 ) ); + Add( new GenericBuyInfo( typeof( Pitchfork ), 19, 20, 0xE87, 0 ) ); + Add( new GenericBuyInfo( typeof( Scimitar ), 36, 20, 0x13B6, 0 ) ); + Add( new GenericBuyInfo( typeof( SkinningKnife ), 14, 20, 0xEC4, 0 ) ); + Add( new GenericBuyInfo( typeof( LargeBattleAxe ), 33, 20, 0x13FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WarAxe ), 29, 20, 0x13B0, 0 ) ); + + if ( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( BoneHarvester ), 35, 20, 0x26BB, 0 ) ); + Add( new GenericBuyInfo( typeof( CrescentBlade ), 37, 20, 0x26C1, 0 ) ); + Add( new GenericBuyInfo( typeof( DoubleBladedStaff ), 35, 20, 0x26BF, 0 ) ); + Add( new GenericBuyInfo( typeof( Lance ), 34, 20, 0x26C0, 0 ) ); + Add( new GenericBuyInfo( typeof( Pike ), 39, 20, 0x26BE, 0 ) ); + Add( new GenericBuyInfo( typeof( Scythe ), 39, 20, 0x26BA, 0 ) ); + Add( new GenericBuyInfo( typeof( CompositeBow ), 50, 20, 0x26C2, 0 ) ); + Add( new GenericBuyInfo( typeof( RepeatingCrossbow ), 57, 20, 0x26C3, 0 ) ); + } + + Add( new GenericBuyInfo( typeof( BlackStaff ), 22, 20, 0xDF1, 0 ) ); + Add( new GenericBuyInfo( typeof( Club ), 16, 20, 0x13B4, 0 ) ); + Add( new GenericBuyInfo( typeof( GnarledStaff ), 16, 20, 0x13F8, 0 ) ); + Add( new GenericBuyInfo( typeof( Mace ), 28, 20, 0xF5C, 0 ) ); + Add( new GenericBuyInfo( typeof( Maul ), 21, 20, 0x143B, 0 ) ); + Add( new GenericBuyInfo( typeof( QuarterStaff ), 19, 20, 0xE89, 0 ) ); + Add( new GenericBuyInfo( typeof( ShepherdsCrook ), 20, 20, 0xE81, 0 ) ); + Add( new GenericBuyInfo( typeof( SmithHammer ), 21, 20, 0x13E3, 0 ) ); + Add( new GenericBuyInfo( typeof( ShortSpear ), 23, 20, 0x1403, 0 ) ); + Add( new GenericBuyInfo( typeof( Spear ), 31, 20, 0xF62, 0 ) ); + Add( new GenericBuyInfo( typeof( WarHammer ), 25, 20, 0x1439, 0 ) ); + Add( new GenericBuyInfo( typeof( WarMace ), 31, 20, 0x1407, 0 ) ); + + if( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( Scepter ), 39, 20, 0x26BC, 0 ) ); + Add( new GenericBuyInfo( typeof( BladedStaff ), 40, 20, 0x26BD, 0 ) ); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Tongs ), 7 ); + Add( typeof( IronIngot ), 4 ); + + Add( typeof( Buckler ), 25 ); + Add( typeof( BronzeShield ), 33 ); + Add( typeof( MetalShield ), 60 ); + Add( typeof( MetalKiteShield ), 62 ); + Add( typeof( HeaterShield ), 115 ); + Add( typeof( WoodenKiteShield ), 35 ); + + Add( typeof( WoodenShield ), 15 ); + + Add( typeof( PlateArms ), 94 ); + Add( typeof( PlateChest ), 121 ); + Add( typeof( PlateGloves ), 72 ); + Add( typeof( PlateGorget ), 52 ); + Add( typeof( PlateLegs ), 109 ); + + Add( typeof( FemalePlateChest ), 113 ); + Add( typeof( FemaleLeatherChest ), 18 ); + Add( typeof( FemaleStuddedChest ), 25 ); + Add( typeof( LeatherShorts ), 14 ); + Add( typeof( LeatherSkirt ), 11 ); + Add( typeof( LeatherBustierArms ), 11 ); + Add( typeof( StuddedBustierArms ), 27 ); + + Add( typeof( Bascinet ), 9 ); + Add( typeof( CloseHelm ), 9 ); + Add( typeof( Helmet ), 9 ); + Add( typeof( NorseHelm ), 9 ); + Add( typeof( PlateHelm ), 10 ); + + Add( typeof( ChainCoif ), 6 ); + Add( typeof( ChainChest ), 71 ); + Add( typeof( ChainLegs ), 74 ); + + Add( typeof( RingmailArms ), 42 ); + Add( typeof( RingmailChest ), 60 ); + Add( typeof( RingmailGloves ), 26 ); + Add( typeof( RingmailLegs ), 45 ); + + Add( typeof( BattleAxe ), 13 ); + Add( typeof( DoubleAxe ), 26 ); + Add( typeof( ExecutionersAxe ), 15 ); + Add( typeof( LargeBattleAxe ),16 ); + Add( typeof( Pickaxe ), 11 ); + Add( typeof( TwoHandedAxe ), 16 ); + Add( typeof( WarAxe ), 14 ); + Add( typeof( Axe ), 20 ); + + Add( typeof( Bardiche ), 30 ); + Add( typeof( Halberd ), 21 ); + + Add( typeof( ButcherKnife ), 7 ); + Add( typeof( Cleaver ), 7 ); + Add( typeof( Dagger ), 10 ); + Add( typeof( SkinningKnife ), 7 ); + + Add( typeof( Club ), 8 ); + Add( typeof( HammerPick ), 13 ); + Add( typeof( Mace ), 14 ); + Add( typeof( Maul ), 10 ); + Add( typeof( WarHammer ), 12 ); + Add( typeof( WarMace ), 15 ); + + Add( typeof( HeavyCrossbow ), 27 ); + Add( typeof( Bow ), 17 ); + Add( typeof( Crossbow ), 23 ); + + if( Core.AOS ) + { + Add( typeof( CompositeBow ), 25 ); + Add( typeof( RepeatingCrossbow ), 28 ); + Add( typeof( Scepter ), 20 ); + Add( typeof( BladedStaff ), 20 ); + Add( typeof( Scythe ), 19 ); + Add( typeof( BoneHarvester ), 17 ); + Add( typeof( Scepter ), 18 ); + Add( typeof( BladedStaff ), 16 ); + Add( typeof( Pike ), 19 ); + Add( typeof( DoubleBladedStaff ), 17 ); + Add( typeof( Lance ), 17 ); + Add( typeof( CrescentBlade ), 18 ); + } + + Add( typeof( Spear ), 15 ); + Add( typeof( Pitchfork ), 9 ); + Add( typeof( ShortSpear ), 11 ); + + Add( typeof( BlackStaff ), 11 ); + Add( typeof( GnarledStaff ), 8 ); + Add( typeof( QuarterStaff ), 9 ); + Add( typeof( ShepherdsCrook ), 10 ); + + Add( typeof( SmithHammer ), 10 ); + + Add( typeof( Broadsword ), 17 ); + Add( typeof( Cutlass ), 12 ); + Add( typeof( Katana ), 16 ); + Add( typeof( Kryss ), 16 ); + Add( typeof( Longsword ), 27 ); + Add( typeof( Scimitar ), 18 ); + Add( typeof( ThinLongsword ), 13 ); + Add( typeof( VikingSword ), 27 ); + + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBBowyer.cs b/Scripts/Mobiles/Vendors/SBInfo/SBBowyer.cs new file mode 100644 index 0000000..ccf7315 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBBowyer.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBBowyer : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBBowyer() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( FletcherTools ), 2, 20, 0x1022, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( FletcherTools ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBButcher.cs b/Scripts/Mobiles/Vendors/SBInfo/SBButcher.cs new file mode 100644 index 0000000..c0b8959 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBButcher.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBButcher : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBButcher() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bacon ), 7, 20, 0x979, 0 ) ); + Add( new GenericBuyInfo( typeof( Ham ), 26, 20, 0x9C9, 0 ) ); + Add( new GenericBuyInfo( typeof( Sausage ), 18, 20, 0x9C0, 0 ) ); + Add( new GenericBuyInfo( typeof( RawChickenLeg ), 6, 20, 0x1607, 0 ) ); + Add( new GenericBuyInfo( typeof( RawBird ), 9, 20, 0x9B9, 0 ) ); + Add( new GenericBuyInfo( typeof( RawLambLeg ), 9, 20, 0x1609, 0 ) ); + Add( new GenericBuyInfo( typeof( RawRibs ), 16, 20, 0x9F1, 0 ) ); + Add( new GenericBuyInfo( typeof( ButcherKnife ), 13, 20, 0x13F6, 0 ) ); + Add( new GenericBuyInfo( typeof( Cleaver ), 13, 20, 0xEC3, 0 ) ); + Add( new GenericBuyInfo( typeof( SkinningKnife ), 13, 20, 0xEC4, 0 ) ); + + + + + + + + + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( RawRibs ), 8 ); + Add( typeof( RawLambLeg ), 4 ); + Add( typeof( RawChickenLeg ), 3 ); + Add( typeof( RawBird ), 4 ); + Add( typeof( Bacon ), 3 ); + Add( typeof( Sausage ), 9 ); + Add( typeof( Ham ), 13 ); + Add( typeof( ButcherKnife ), 7 ); + Add( typeof( Cleaver ), 7 ); + Add( typeof( SkinningKnife ), 7 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBCarpenter.cs b/Scripts/Mobiles/Vendors/SBInfo/SBCarpenter.cs new file mode 100644 index 0000000..ca038b0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBCarpenter.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBCarpenter: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBCarpenter() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Nails ), 3, 20, 0x102E, 0 ) ); + Add( new GenericBuyInfo( typeof( Axle ), 2, 20, 0x105B, 0 ) ); + Add( new GenericBuyInfo( typeof( Board ), 3, 20, 0x1BD7, 0 ) ); + Add( new GenericBuyInfo( typeof( DrawKnife ), 10, 20, 0x10E4, 0 ) ); + Add( new GenericBuyInfo( typeof( Froe ), 10, 20, 0x10E5, 0 ) ); + Add( new GenericBuyInfo( typeof( Scorp ), 10, 20, 0x10E7, 0 ) ); + Add( new GenericBuyInfo( typeof( Inshave ), 10, 20, 0x10E6, 0 ) ); + Add( new GenericBuyInfo( typeof( DovetailSaw ), 12, 20, 0x1028, 0 ) ); + Add( new GenericBuyInfo( typeof( Saw ), 15, 20, 0x1034, 0 ) ); + Add( new GenericBuyInfo( typeof( Hammer ), 17, 20, 0x102A, 0 ) ); + Add( new GenericBuyInfo( typeof( MouldingPlane ), 11, 20, 0x102C, 0 ) ); + Add( new GenericBuyInfo( typeof( SmoothingPlane ), 10, 20, 0x1032, 0 ) ); + Add( new GenericBuyInfo( typeof( JointingPlane ), 11, 20, 0x1030, 0 ) ); + Add( new GenericBuyInfo( typeof( Drums ), 21, 20, 0xE9C, 0 ) ); + Add( new GenericBuyInfo( typeof( Tambourine ), 21, 20, 0xE9D, 0 ) ); + Add( new GenericBuyInfo( typeof( LapHarp ), 21, 20, 0xEB2, 0 ) ); + Add( new GenericBuyInfo( typeof( Lute ), 21, 20, 0xEB3, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( WoodenBox ), 7 ); + Add( typeof( SmallCrate ), 5 ); + Add( typeof( MediumCrate ), 6 ); + Add( typeof( LargeCrate ), 7 ); + Add( typeof( WoodenChest ), 15 ); + + Add( typeof( LargeTable ), 10 ); + Add( typeof( Nightstand ), 7 ); + Add( typeof( YewWoodTable ), 10 ); + + Add( typeof( Throne ), 24 ); + Add( typeof( WoodenThrone ), 6 ); + Add( typeof( Stool ), 6 ); + Add( typeof( FootStool ), 6 ); + + Add( typeof( FancyWoodenChairCushion ), 12 ); + Add( typeof( WoodenChairCushion ), 10 ); + Add( typeof( WoodenChair ), 8 ); + Add( typeof( BambooChair ), 6 ); + Add( typeof( WoodenBench ), 6 ); + + Add( typeof( Saw ), 9 ); + Add( typeof( Scorp ), 6 ); + Add( typeof( SmoothingPlane ), 6 ); + Add( typeof( DrawKnife ), 6 ); + Add( typeof( Froe ), 6 ); + Add( typeof( Hammer ), 14 ); + Add( typeof( Inshave ), 6 ); + Add( typeof( JointingPlane ), 6 ); + Add( typeof( MouldingPlane ), 6 ); + Add( typeof( DovetailSaw ), 7 ); + Add( typeof( Board ), 2 ); + Add( typeof( Axle ), 1 ); + + Add( typeof( Club ), 13 ); + + Add( typeof( Lute ), 10 ); + Add( typeof( LapHarp ), 10 ); + Add( typeof( Tambourine ), 10 ); + Add( typeof( Drums ), 10 ); + + Add( typeof( Log ), 1 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBCobbler.cs b/Scripts/Mobiles/Vendors/SBInfo/SBCobbler.cs new file mode 100644 index 0000000..8676f98 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBCobbler.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBCobbler : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBCobbler() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( ThighBoots ), 15, 20, 0x1711, Utility.RandomNeutralHue() ) ); + Add( new GenericBuyInfo( typeof( Shoes ), 8, 20, 0x170f, Utility.RandomNeutralHue() ) ); + Add( new GenericBuyInfo( typeof( Boots ), 10, 20, 0x170b, Utility.RandomNeutralHue() ) ); + Add( new GenericBuyInfo( typeof( Sandals ), 5, 20, 0x170d, Utility.RandomNeutralHue() ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Shoes ), 4 ); + Add( typeof( Boots ), 5 ); + Add( typeof( ThighBoots ), 7 ); + Add( typeof( Sandals ), 2 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBCook.cs b/Scripts/Mobiles/Vendors/SBInfo/SBCook.cs new file mode 100644 index 0000000..8922a6c --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBCook.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBCook : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBCook() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BreadLoaf ), 5, 20, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( BreadLoaf ), 5, 20, 0x103C, 0 ) ); + Add( new GenericBuyInfo( typeof( ApplePie ), 7, 20, 0x1041, 0 ) ); //OSI just has Pie, not Apple/Fruit/Meat + Add( new GenericBuyInfo( typeof( Cake ), 13, 20, 0x9E9, 0 ) ); + Add( new GenericBuyInfo( typeof( Muffins ), 3, 20, 0x9EA, 0 ) ); + + Add( new GenericBuyInfo( typeof( CheeseWheel ), 21, 10, 0x97E, 0 ) ); + Add( new GenericBuyInfo( typeof( CookedBird ), 17, 20, 0x9B7, 0 ) ); + Add( new GenericBuyInfo( typeof( LambLeg ), 8, 20, 0x160A, 0 ) ); + Add( new GenericBuyInfo( typeof( ChickenLeg ), 5, 20, 0x1608, 0 ) ); + + Add( new GenericBuyInfo( typeof( WoodenBowlOfCarrots ), 3, 20, 0x15F9, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfCorn ), 3, 20, 0x15FA, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfLettuce ), 3, 20, 0x15FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfPeas ), 3, 20, 0x15FC, 0 ) ); + Add( new GenericBuyInfo( typeof( EmptyPewterBowl ), 2, 20, 0x15FD, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfCorn ), 3, 20, 0x15FE, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfLettuce ), 3, 20, 0x15FF, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPeas ), 3, 20, 0x1600, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPotatos ), 3, 20, 0x1601, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfStew ), 3, 20, 0x1604, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfTomatoSoup ), 3, 20, 0x1606, 0 ) ); + + Add( new GenericBuyInfo( typeof( RoastPig ), 106, 20, 0x9BB, 0 ) ); + Add( new GenericBuyInfo( typeof( SackFlour ), 3, 20, 0x1039, 0 ) ); + Add( new GenericBuyInfo( typeof( JarHoney ), 3, 20, 0x9EC, 0 ) ); + Add( new GenericBuyInfo( typeof( RollingPin ), 2, 20, 0x1043, 0 ) ); + Add( new GenericBuyInfo( typeof( FlourSifter ), 2, 20, 0x103E, 0 ) ); + Add( new GenericBuyInfo( "1044567", typeof( Skillet ), 3, 20, 0x97F, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( CheeseWheel ), 12 ); + Add( typeof( CookedBird ), 8 ); + Add( typeof( RoastPig ), 53 ); + Add( typeof( Cake ), 5 ); + Add( typeof( JarHoney ), 1 ); + Add( typeof( SackFlour ), 1 ); + Add( typeof( BreadLoaf ), 2 ); + Add( typeof( ChickenLeg ), 3 ); + Add( typeof( LambLeg ), 4 ); + Add( typeof( Skillet ), 1 ); + Add( typeof( FlourSifter ), 1 ); + Add( typeof( RollingPin ), 1 ); + Add( typeof( Muffins ), 1 ); + Add( typeof( ApplePie ), 3 ); + + Add( typeof( WoodenBowlOfCarrots ), 1 ); + Add( typeof( WoodenBowlOfCorn ), 1 ); + Add( typeof( WoodenBowlOfLettuce ), 1 ); + Add( typeof( WoodenBowlOfPeas ), 1 ); + Add( typeof( EmptyPewterBowl ), 1 ); + Add( typeof( PewterBowlOfCorn ), 1 ); + Add( typeof( PewterBowlOfLettuce ), 1 ); + Add( typeof( PewterBowlOfPeas ), 1 ); + Add( typeof( PewterBowlOfPotatos ), 1 ); + Add( typeof( WoodenBowlOfStew ), 1 ); + Add( typeof( WoodenBowlOfTomatoSoup ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBFarmer.cs b/Scripts/Mobiles/Vendors/SBInfo/SBFarmer.cs new file mode 100644 index 0000000..fde8119 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBFarmer.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFarmer : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFarmer() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Cabbage ), 5, 20, 0xC7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Cantaloupe ), 6, 20, 0xC79, 0 ) ); + Add( new GenericBuyInfo( typeof( Carrot ), 3, 20, 0xC78, 0 ) ); + Add( new GenericBuyInfo( typeof( HoneydewMelon ), 7, 20, 0xC74, 0 ) ); + Add( new GenericBuyInfo( typeof( Squash ), 3, 20, 0xC72, 0 ) ); + Add( new GenericBuyInfo( typeof( Lettuce ), 5, 20, 0xC70, 0 ) ); + Add( new GenericBuyInfo( typeof( Onion ), 3, 20, 0xC6D, 0 ) ); + Add( new GenericBuyInfo( typeof( Pumpkin ), 11, 20, 0xC6A, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenGourd ), 3, 20, 0xC66, 0 ) ); + Add( new GenericBuyInfo( typeof( YellowGourd ), 3, 20, 0xC64, 0 ) ); + //Add( new GenericBuyInfo( typeof( Turnip ), 6, 20, XXXXXX, 0 ) ); + Add( new GenericBuyInfo( typeof( Watermelon ), 7, 20, 0xC5C, 0 ) ); + //Add( new GenericBuyInfo( typeof( EarOfCorn ), 3, 20, XXXXXX, 0 ) ); + Add( new GenericBuyInfo( typeof( Eggs ), 3, 20, 0x9B5, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Milk, 56, 20, 0x9AD, 0 ) ); + Add( new GenericBuyInfo( typeof( Peach ), 3, 20, 0x9D2, 0 ) ); + Add( new GenericBuyInfo( typeof( Pear ), 3, 20, 0x994, 0 ) ); + Add( new GenericBuyInfo( typeof( Lemon ), 3, 20, 0x1728, 0 ) ); + Add( new GenericBuyInfo( typeof( Lime ), 3, 20, 0x172A, 0 ) ); + Add( new GenericBuyInfo( typeof( Grapes ), 3, 20, 0x9D1, 0 ) ); + Add( new GenericBuyInfo( typeof( Apple ), 3, 20, 0x9D0, 0 ) ); + Add( new GenericBuyInfo( typeof( SheafOfHay ), 2, 20, 0xF36, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Pitcher ), 5 ); + Add( typeof( Eggs ), 1 ); + Add( typeof( Apple ), 1 ); + Add( typeof( Grapes ), 1 ); + Add( typeof( Watermelon ), 3 ); + Add( typeof( YellowGourd ), 1 ); + Add( typeof( GreenGourd ), 1 ); + Add( typeof( Pumpkin ), 5 ); + Add( typeof( Onion ), 1 ); + Add( typeof( Lettuce ), 2 ); + Add( typeof( Squash ), 1 ); + Add( typeof( Carrot ), 1 ); + Add( typeof( HoneydewMelon ), 3 ); + Add( typeof( Cantaloupe ), 3 ); + Add( typeof( Cabbage ), 2 ); + Add( typeof( Lemon ), 1 ); + Add( typeof( Lime ), 1 ); + Add( typeof( Peach ), 1 ); + Add( typeof( Pear ), 1 ); + Add( typeof( SheafOfHay ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBFisherman.cs b/Scripts/Mobiles/Vendors/SBInfo/SBFisherman.cs new file mode 100644 index 0000000..eb15169 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBFisherman.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFisherman : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFisherman() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( RawFishSteak ), 3, 20, 0x97A, 0 ) ); + //TODO: Add( new GenericBuyInfo( typeof( SmallFish ), 3, 20, 0xDD6, 0 ) ); + //TODO: Add( new GenericBuyInfo( typeof( SmallFish ), 3, 20, 0xDD7, 0 ) ); + Add( new GenericBuyInfo( typeof( Fish ), 6, 80, 0x9CC, 0 ) ); + Add( new GenericBuyInfo( typeof( Fish ), 6, 80, 0x9CD, 0 ) ); + Add( new GenericBuyInfo( typeof( Fish ), 6, 80, 0x9CE, 0 ) ); + Add( new GenericBuyInfo( typeof( Fish ), 6, 80, 0x9CF, 0 ) ); + Add( new GenericBuyInfo( typeof( FishingPole ), 15, 20, 0xDC0, 0 ) ); + + #region Mondain's Legacy + Add(new GenericBuyInfo(typeof(AquariumFishNet), 250, 20, 0xDC8, 0x240)); + Add(new GenericBuyInfo(typeof(AquariumFood), 62, 20, 0xEFC, 0)); + Add(new GenericBuyInfo(typeof(FishBowl), 6312, 20, 0x241C, 0x482)); + Add(new GenericBuyInfo(typeof(VacationWafer), 67, 20, 0x971, 0)); + Add(new GenericBuyInfo(typeof(AquariumNorthDeed), 250002, 20, 0x14F0, 0)); + Add(new GenericBuyInfo(typeof(AquariumEastDeed), 250002, 20, 0x14F0, 0)); + Add(new GenericBuyInfo(typeof(NewAquariumBook), 15, 20, 0xFF2, 0)); + #endregion + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( RawFishSteak ), 1 ); + Add( typeof( Fish ), 1 ); + //TODO: Add( typeof( SmallFish ), 1 ); + Add( typeof( FishingPole ), 7 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs b/Scripts/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs new file mode 100644 index 0000000..02bc618 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBFortuneTeller.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFortuneTeller : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFortuneTeller() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bandage ), 5, 20, 0xE21, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bandage ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBFurtrader.cs b/Scripts/Mobiles/Vendors/SBInfo/SBFurtrader.cs new file mode 100644 index 0000000..7c2c43e --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBFurtrader.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBFurtrader : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFurtrader() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Hides ), 3, 40, 0x1079, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Hides ), 2 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBGlassblower.cs b/Scripts/Mobiles/Vendors/SBInfo/SBGlassblower.cs new file mode 100644 index 0000000..0c54376 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBGlassblower.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBGlassblower : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBGlassblower() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 10, 0xF0B, 0 ) ); + Add( new GenericBuyInfo( typeof( AgilityPotion ), 15, 10, 0xF08, 0 ) ); + Add( new GenericBuyInfo( typeof( NightSightPotion ), 15, 10, 0xF06, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 10, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( StrengthPotion ), 15, 10, 0xF09, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserPoisonPotion ), 15, 10, 0xF0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserCurePotion ), 15, 10, 0xF07, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserExplosionPotion ), 21, 10, 0xF0D, 0 ) ); + + Add( new GenericBuyInfo( typeof( MortarPestle ), 8, 10, 0xE9B, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlackPearl ), 5, 20, 0xF7A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 20, 0xF8C, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bottle ), 5, 100, 0xF0E, 0 ) ); + + Add( new GenericBuyInfo( typeof( HeatingStand ), 2, 100, 0x1849, 0 ) ); + + Add( new GenericBuyInfo( "Crafting Glass With Glassblowing", typeof( GlassblowingBook ), 10637, 30, 0xFF4, 0 ) ); + Add( new GenericBuyInfo( "Finding Glass-Quality Sand", typeof( SandMiningBook ), 10637, 30, 0xFF4, 0 ) ); + Add( new GenericBuyInfo( "1044608", typeof( Blowpipe ), 21, 100, 0xE8A, 0x3B9 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BlackPearl ), 3 ); + Add( typeof( Bloodmoss ), 3 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( SulfurousAsh ), 2 ); + Add( typeof( Bottle ), 3 ); + Add( typeof( MortarPestle ), 4 ); + + Add( typeof( NightSightPotion ), 7 ); + Add( typeof( AgilityPotion ), 7 ); + Add( typeof( StrengthPotion ), 7 ); + Add( typeof( RefreshPotion ), 7 ); + Add( typeof( LesserCurePotion ), 7 ); + Add( typeof( LesserHealPotion ), 7 ); + Add( typeof( LesserPoisonPotion ), 7 ); + Add( typeof( LesserExplosionPotion ), 10 ); + + Add( typeof( GlassblowingBook ), 5000 ); + Add( typeof( SandMiningBook ), 5000 ); + Add( typeof( Blowpipe ), 10 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBHairStylist.cs b/Scripts/Mobiles/Vendors/SBInfo/SBHairStylist.cs new file mode 100644 index 0000000..5251e4a --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBHairStylist.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHairStylist : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBHairStylist() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + // Scriptiz : utiliser le CustomHairStylist � la place ! + /* + Add( new GenericBuyInfo( "special beard dye", typeof( SpecialBeardDye ), 500, 20, 0xE26, 0 ) ); + Add( new GenericBuyInfo( "special hair dye", typeof( SpecialHairDye ), 500, 20, 0xE26, 0 ) ); + Add( new GenericBuyInfo( "1041060", typeof( HairDye ), 60, 20, 0xEFF, 0 ) ); + Add(new GenericBuyInfo("Une coupe de cheveux", typeof(HairRestylingDeed), 120, 20, 0xEFF, 0)); + Add(new GenericBuyInfo("Un changement de barbe", typeof(BeardRestylingDeed), 120, 20, 0xEFF, 0)); + */ + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + /* + Add( typeof( HairDye ), 30 ); + Add( typeof( SpecialBeardDye ), 250 ); + Add( typeof( SpecialHairDye ), 2500 ); + Add(typeof(HairRestylingDeed), 60); + Add(typeof(BeardRestylingDeed), 60); + */ + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBHealer.cs b/Scripts/Mobiles/Vendors/SBInfo/SBHealer.cs new file mode 100644 index 0000000..5434f0d --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBHealer.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHealer : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBHealer() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bandage ), 5, 20, 0xE21, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 20, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 20, 0xF0B, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bandage ), 1 ); + Add( typeof( LesserHealPotion ), 7 ); + Add( typeof( RefreshPotion ), 7 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBHerbalist.cs b/Scripts/Mobiles/Vendors/SBInfo/SBHerbalist.cs new file mode 100644 index 0000000..0af21e7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBHerbalist.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHerbalist : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBHerbalist() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( MortarPestle ), 8, 20, 0xE9B, 0 ) ); + Add( new GenericBuyInfo( typeof( Bottle ), 5, 20, 0xF0E, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bloodmoss ), 3 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( Bottle ), 3 ); + Add( typeof( MortarPestle ), 4 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBHolyMage.cs b/Scripts/Mobiles/Vendors/SBInfo/SBHolyMage.cs new file mode 100644 index 0000000..c5b8495 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBHolyMage.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBHolyMage : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBHolyMage() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Spellbook ), 18, 10, 0xEFA, 0 ) ); + Add( new GenericBuyInfo( typeof( ScribesPen ), 8, 10, 0xFBF, 0 ) ); + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 20, 0x0E34, 0 ) ); + + Add( new GenericBuyInfo( "1041072", typeof( MagicWizardsHat ), 11, 10, 0x1718, Utility.RandomDyedHue() ) ); + + Add( new GenericBuyInfo( typeof( RecallRune ), 15, 10, 0x1f14, 0 ) ); + + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 20, 0xF0B, 0 ) ); + Add( new GenericBuyInfo( typeof( AgilityPotion ), 15, 20, 0xF08, 0 ) ); + Add( new GenericBuyInfo( typeof( NightSightPotion ), 15, 20, 0xF06, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 20, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( StrengthPotion ), 15, 20, 0xF09, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserCurePotion ), 15, 20, 0xF07, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlackPearl ), 5, 20, 0xF7A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 20, 0xF8C, 0 ) ); + + Type[] types = Loot.RegularScrollTypes; + + for ( int i = 0; i < types.Length && i < 8; ++i ) + { + int itemID = 0x1F2E + i; + + if ( i == 6 ) + itemID = 0x1F2D; + else if ( i > 6 ) + --itemID; + + Add(new GenericBuyInfo(types[i], 12 + ((i / 8) * 10), 20, itemID, 0)); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BlackPearl ), 3 ); + Add( typeof( Bloodmoss ), 3 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( SulfurousAsh ), 2 ); + Add( typeof( RecallRune ), 8 ); + Add( typeof( Spellbook ), 9 ); + Add( typeof( BlankScroll ), 5 ); // Scriptiz : 3 + + Add( typeof( NightSightPotion ), 7 ); + Add( typeof( AgilityPotion ), 7 ); + Add( typeof( StrengthPotion ), 7 ); + Add( typeof( RefreshPotion ), 7 ); + Add( typeof( LesserCurePotion ), 7 ); + Add( typeof( LesserHealPotion ), 7 ); + + Type[] types = Loot.RegularScrollTypes; + + for ( int i = 0; i < types.Length; ++i ) + Add(types[i], ((i / 8) + 2) * 2); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBHouseDeed.cs b/Scripts/Mobiles/Vendors/SBInfo/SBHouseDeed.cs new file mode 100644 index 0000000..7004b87 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBHouseDeed.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using Server.Multis.Deeds; + +namespace Server.Mobiles +{ + public class SBHouseDeed: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBHouseDeed() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( "deed to a stone-and-plaster house", typeof( StonePlasterHouseDeed ), 43800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a field stone house", typeof( FieldStoneHouseDeed ), 43800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a small brick house", typeof( SmallBrickHouseDeed), 43800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a wooden house", typeof( WoodHouseDeed ), 43800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a wood-and-plaster house", typeof( WoodPlasterHouseDeed ), 43800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a thatched-roof cottage", typeof( ThatchedRoofCottageDeed ), 43800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a brick house", typeof( BrickHouseDeed ), 144500, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a two-story wood-and-plaster house", typeof( TwoStoryWoodPlasterHouseDeed ), 192400, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a tower", typeof( TowerDeed ), 433200, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a small stone keep", typeof( KeepDeed ), 665200, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a castle", typeof( CastleDeed ), 1022800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a large house with patio", typeof( LargePatioDeed ), 152800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a marble house with patio", typeof( LargeMarbleDeed ), 192000, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a small stone tower", typeof( SmallTowerDeed ), 88500, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a two story log cabin", typeof( LogCabinDeed ), 97800, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a sandstone house with patio", typeof( SandstonePatioDeed ), 90900, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a two story villa", typeof( VillaDeed ), 136500, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a small stone workshop", typeof( StoneWorkshopDeed ), 60600, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "deed to a small marble workshop", typeof( MarbleWorkshopDeed ), 63000, 20, 0x14F0, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + /*Add( typeof( StonePlasterHouseDeed ), 43800 ); + Add( typeof( FieldStoneHouseDeed ), 43800 ); + Add( typeof( SmallBrickHouseDeed ), 43800 ); + Add( typeof( WoodHouseDeed ), 43800 ); + Add( typeof( WoodPlasterHouseDeed ), 43800 ); + Add( typeof( ThatchedRoofCottageDeed ), 43800 ); + Add( typeof( BrickHouseDeed ), 144500 ); + Add( typeof( TwoStoryWoodPlasterHouseDeed ), 192400 ); + Add( typeof( TowerDeed ), 433200 ); + Add( typeof( KeepDeed ), 665200 ); + Add( typeof( CastleDeed ), 1022800 ); + Add( typeof( LargePatioDeed ), 152800 ); + Add( typeof( LargeMarbleDeed ), 192800 ); + Add( typeof( SmallTowerDeed ), 88500 ); + Add( typeof( LogCabinDeed ), 97800 ); + Add( typeof( SandstonePatioDeed ), 90900 ); + Add( typeof( VillaDeed ), 136500 ); + Add( typeof( StoneWorkshopDeed ), 60600 ); + Add( typeof( MarbleWorkshopDeed ), 60300 ); + Add( typeof( SmallBrickHouseDeed ), 43800 );*/ + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs b/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs new file mode 100644 index 0000000..37925f1 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBInfo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public abstract class SBInfo + { + public static readonly List Empty = new List(); + + public SBInfo() + { + } + + public abstract IShopSellInfo SellInfo { get; } + public abstract List BuyInfo { get; } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBInnKeeper.cs b/Scripts/Mobiles/Vendors/SBInfo/SBInnKeeper.cs new file mode 100644 index 0000000..8f2f138 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBInnKeeper.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBInnKeeper : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBInnKeeper() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Ale, 7, 20, 0x99F, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Wine, 7, 20, 0x9C7, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Liquor, 7, 20, 0x99B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Jug ), BeverageType.Cider, 13, 20, 0x9C8, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Milk, 56, 20, 0x9F0, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Ale, 88, 20, 0x1F95, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Cider, 88, 20, 0x1F97, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Liquor, 88, 20, 0x1F99, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Wine, 88, 20, 0x1F9B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Water, 88, 20, 0x1F9D, 0 ) ); + + Add( new GenericBuyInfo( typeof( BreadLoaf ), 6, 10, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( CheeseWheel ), 21, 10, 0x97E, 0 ) ); + Add( new GenericBuyInfo( typeof( CookedBird ), 17, 20, 0x9B7, 0 ) ); + Add( new GenericBuyInfo( typeof( LambLeg ), 8, 20, 0x160A, 0 ) ); + Add( new GenericBuyInfo( typeof( ChickenLeg ), 5, 20, 0x1608, 0 ) ); + Add( new GenericBuyInfo( typeof( Ribs ), 7, 20, 0x9F2, 0 ) ); + + Add( new GenericBuyInfo( typeof( WoodenBowlOfCarrots ), 3, 20, 0x15F9, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfCorn ), 3, 20, 0x15FA, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfLettuce ), 3, 20, 0x15FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfPeas ), 3, 20, 0x15FC, 0 ) ); + Add( new GenericBuyInfo( typeof( EmptyPewterBowl ), 2, 20, 0x15FD, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfCorn ), 3, 20, 0x15FE, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfLettuce ), 3, 20, 0x15FF, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPeas ), 3, 20, 0x1600, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPotatos ), 3, 20, 0x1601, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfStew ), 3, 20, 0x1604, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfTomatoSoup ), 3, 20, 0x1606, 0 ) ); + + Add( new GenericBuyInfo( typeof( ApplePie ), 7, 20, 0x1041, 0 ) ); //OSI just has Pie, not Apple/Fruit/Meat + + Add( new GenericBuyInfo( typeof( Peach ), 3, 20, 0x9D2, 0 ) ); + Add( new GenericBuyInfo( typeof( Pear ), 3, 20, 0x994, 0 ) ); + Add( new GenericBuyInfo( typeof( Grapes ), 3, 20, 0x9D1, 0 ) ); + Add( new GenericBuyInfo( typeof( Apple ), 3, 20, 0x9D0, 0 ) ); + Add( new GenericBuyInfo( typeof( Banana ), 2, 20, 0x171F, 0 ) ); + Add( new GenericBuyInfo( typeof( Torch ), 7, 20, 0xF6B, 0 ) ); + Add( new GenericBuyInfo( typeof( Candle ), 6, 20, 0xA28, 0 ) ); + Add( new GenericBuyInfo( typeof( Beeswax ), 1, 20, 0x1422, 0 ) ); + + Add( new GenericBuyInfo( typeof( Backpack ), 15, 20, 0x9B2, 0 ) ); + Add( new GenericBuyInfo( "1016450", typeof( Chessboard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( "1016449", typeof( CheckerBoard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( typeof( Backgammon ), 2, 20, 0xE1C, 0 ) ); + Add( new GenericBuyInfo( typeof( Dices ), 2, 20, 0xFA7, 0 ) ); + Add( new GenericBuyInfo( "1041243", typeof( ContractOfEmployment ), 1252, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "a barkeep contract", typeof( BarkeepContract ), 1252, 20, 0x14F0, 0 ) ); + + if ( Multis.BaseHouse.NewVendorSystem ) + Add( new GenericBuyInfo( "1062332", typeof( VendorRentalContract ), 1252, 20, 0x14F0, 0x672 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BeverageBottle ), 3 ); + Add( typeof( Jug ), 6 ); + Add( typeof( Pitcher ), 5 ); + Add( typeof( GlassMug ), 1 ); + Add( typeof( BreadLoaf ), 3 ); + Add( typeof( CheeseWheel ), 12 ); + Add( typeof( Ribs ), 6 ); + Add( typeof( Peach ), 1 ); + Add( typeof( Pear ), 1 ); + Add( typeof( Grapes ), 1 ); + Add( typeof( Apple ), 1 ); + Add( typeof( Banana ), 1 ); + Add( typeof( Torch ), 3 ); + Add( typeof( Candle ), 3 ); + Add( typeof( Chessboard ), 1 ); + Add( typeof( CheckerBoard ), 1 ); + Add( typeof( Backgammon ), 1 ); + Add( typeof( Dices ), 1 ); + Add( typeof( ContractOfEmployment ), 626 ); + Add( typeof( Beeswax ), 1 ); + Add( typeof( WoodenBowlOfCarrots ), 1 ); + Add( typeof( WoodenBowlOfCorn ), 1 ); + Add( typeof( WoodenBowlOfLettuce ), 1 ); + Add( typeof( WoodenBowlOfPeas ), 1 ); + Add( typeof( EmptyPewterBowl ), 1 ); + Add( typeof( PewterBowlOfCorn ), 1 ); + Add( typeof( PewterBowlOfLettuce ), 1 ); + Add( typeof( PewterBowlOfPeas ), 1 ); + Add( typeof( PewterBowlOfPotatos ), 1 ); + Add( typeof( WoodenBowlOfStew ), 1 ); + Add( typeof( WoodenBowlOfTomatoSoup ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBJewel.cs b/Scripts/Mobiles/Vendors/SBInfo/SBJewel.cs new file mode 100644 index 0000000..119f14e --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBJewel.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBJewel: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBJewel() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( GoldRing ), 27, 20, 0x108A, 0 ) ); + Add( new GenericBuyInfo( typeof( Necklace ), 26, 20, 0x1085, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldNecklace ), 27, 20, 0x1088, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldBeadNecklace ), 27, 20, 0x1089, 0 ) ); + Add( new GenericBuyInfo( typeof( Beads ), 27, 20, 0x108B, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldBracelet ), 27, 20, 0x1086, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldEarrings ), 27, 20, 0x1087, 0 ) ); + + Add( new GenericBuyInfo( "1060740", typeof( BroadcastCrystal ), 68, 20, 0x1ED0, 0, new object[] { 500 } ) ); // 500 charges + Add( new GenericBuyInfo( "1060740", typeof( BroadcastCrystal ), 131, 20, 0x1ED0, 0, new object[] { 1000 } ) ); // 1000 charges + Add( new GenericBuyInfo( "1060740", typeof( BroadcastCrystal ), 256, 20, 0x1ED0, 0, new object[] { 2000 } ) ); // 2000 charges + + Add( new GenericBuyInfo( "1060740", typeof( ReceiverCrystal ), 6, 20, 0x1ED0, 0 ) ); + + Add( new GenericBuyInfo( typeof( StarSapphire ), 125, 20, 0xF21, 0 ) ); + Add( new GenericBuyInfo( typeof( Emerald ), 100, 20, 0xF10, 0 ) ); + Add( new GenericBuyInfo( typeof( Sapphire ), 100, 20, 0xF19, 0 ) ); + Add( new GenericBuyInfo( typeof( Ruby ), 75, 20, 0xF13, 0 ) ); + Add( new GenericBuyInfo( typeof( Citrine ), 50, 20, 0xF15, 0 ) ); + Add( new GenericBuyInfo( typeof( Amethyst ), 100, 20, 0xF16, 0 ) ); + Add( new GenericBuyInfo( typeof( Tourmaline ), 75, 20, 0xF2D, 0 ) ); + Add( new GenericBuyInfo( typeof( Amber ), 50, 20, 0xF25, 0 ) ); + Add( new GenericBuyInfo( typeof( Diamond ), 200, 20, 0xF26, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Amber ), 25 ); + Add( typeof( Amethyst ), 50 ); + Add( typeof( Citrine ), 25 ); + Add( typeof( Diamond ), 100 ); + Add( typeof( Emerald ), 50 ); + Add( typeof( Ruby ), 37 ); + Add( typeof( Sapphire ), 50 ); + Add( typeof( StarSapphire ), 62 ); + Add( typeof( Tourmaline ), 47 ); + Add( typeof( GoldRing ), 13 ); + Add( typeof( SilverRing ), 10 ); + Add( typeof( Necklace ), 13 ); + Add( typeof( GoldNecklace ), 13 ); + Add( typeof( GoldBeadNecklace ), 13 ); + Add( typeof( SilverNecklace ), 10 ); + Add( typeof( SilverBeadNecklace ), 10 ); + Add( typeof( Beads ), 13 ); + Add( typeof( GoldBracelet ), 13 ); + Add( typeof( SilverBracelet ), 10 ); + Add( typeof( GoldEarrings ), 13 ); + Add( typeof( SilverEarrings ), 10 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs b/Scripts/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs new file mode 100644 index 0000000..3e8bdc9 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBKeeperOfChivalry.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBKeeperOfChivalry : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBKeeperOfChivalry() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + //Add( new GenericBuyInfo( typeof( BookOfChivalry ), 140, 20, 0x2252, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs b/Scripts/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs new file mode 100644 index 0000000..df03824 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBLeatherWorker.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBLeatherWorker: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBLeatherWorker() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Hides ), 4, 999, 0x1078, 0 ) ); + Add( new GenericBuyInfo( typeof( ThighBoots ), 56, 10, 0x1711, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Hides ), 2 ); + Add( typeof( ThighBoots ), 28 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBMage.cs b/Scripts/Mobiles/Vendors/SBInfo/SBMage.cs new file mode 100644 index 0000000..051b1e9 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBMage.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMage : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMage() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Spellbook ), 18, 10, 0xEFA, 0 ) ); + + /*if ( Core.AOS ) + Add( new GenericBuyInfo( typeof( NecromancerSpellbook ), 115, 10, 0x2253, 0 ) );*/ + + Add( new GenericBuyInfo( typeof( ScribesPen ), 8, 10, 0xFBF, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 20, 0x0E34, 0 ) ); + + Add( new GenericBuyInfo( "1041072", typeof( MagicWizardsHat ), 11, 10, 0x1718, Utility.RandomDyedHue() ) ); + + Add( new GenericBuyInfo( typeof( RecallRune ), 15, 10, 0x1F14, 0 ) ); + + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 10, 0xF0B, 0 ) ); + Add( new GenericBuyInfo( typeof( AgilityPotion ), 15, 10, 0xF08, 0 ) ); + Add( new GenericBuyInfo( typeof( NightSightPotion ), 15, 10, 0xF06, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 10, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( StrengthPotion ), 15, 10, 0xF09, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserPoisonPotion ), 15, 10, 0xF0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserCurePotion ), 15, 10, 0xF07, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserExplosionPotion ), 21, 10, 0xF0D, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlackPearl ), 5, 20, 0xF7A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 20, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 20, 0xF8C, 0 ) ); + + /*if ( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( BatWing ), 3, 999, 0xF78, 0 ) ); + Add( new GenericBuyInfo( typeof( DaemonBlood ), 6, 999, 0xF7D, 0 ) ); + Add( new GenericBuyInfo( typeof( PigIron ), 5, 999, 0xF8A, 0 ) ); + Add( new GenericBuyInfo( typeof( NoxCrystal ), 6, 999, 0xF8E, 0 ) ); + Add( new GenericBuyInfo( typeof( GraveDust ), 3, 999, 0xF8F, 0 ) ); + }*/ + + Type[] types = Loot.RegularScrollTypes; + + int circles = 3; + + for ( int i = 0; i < circles*8 && i < types.Length; ++i ) + { + int itemID = 0x1F2E + i; + + if ( i == 6 ) + itemID = 0x1F2D; + else if ( i > 6 ) + --itemID; + + Add( new GenericBuyInfo( types[i], 12 + ((i / 8) * 10), 20, itemID, 0 ) ); + } + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( WizardsHat ), 15 ); + Add( typeof( BlackPearl ), 3 ); + Add( typeof( Bloodmoss ),4 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( SulfurousAsh ), 2 ); + + if ( Core.AOS ) + { + Add( typeof( BatWing ), 1 ); + Add( typeof( DaemonBlood ), 3 ); + Add( typeof( PigIron ), 2 ); + Add( typeof( NoxCrystal ), 3 ); + Add( typeof( GraveDust ), 1 ); + } + + Add( typeof( RecallRune ), 13 ); + Add( typeof( Spellbook ), 25 ); + + Type[] types = Loot.RegularScrollTypes; + + for (int i = 0; i < types.Length; ++i) + Add(types[i], ((i / 8) + 2) * 2); + + + if (Core.SE) + { + Add(typeof(ExorcismScroll), 3); + Add(typeof(AnimateDeadScroll), 8); + Add(typeof(BloodOathScroll), 8); + Add(typeof(CorpseSkinScroll), 8); + Add(typeof(CurseWeaponScroll), 8); + Add(typeof(EvilOmenScroll), 8); + Add(typeof(PainSpikeScroll), 8); + Add(typeof(SummonFamiliarScroll), 8); + Add(typeof(HorrificBeastScroll), 8); + Add(typeof(MindRotScroll), 10); + Add(typeof(PoisonStrikeScroll), 10); + Add(typeof(WraithFormScroll), 15); + Add(typeof(LichFormScroll), 16); + Add(typeof(StrangleScroll), 16); + Add(typeof(WitherScroll), 16); + Add(typeof(VampiricEmbraceScroll), 20); + Add(typeof(VengefulSpiritScroll), 20); + } + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBMapmaker.cs b/Scripts/Mobiles/Vendors/SBInfo/SBMapmaker.cs new file mode 100644 index 0000000..ddce007 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBMapmaker.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMapmaker : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMapmaker() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BlankMap ), 5, 40, 0x14EC, 0 ) ); + Add( new GenericBuyInfo( typeof( MapmakersPen ), 8, 20, 0x0FBF, 0 ) ); + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 40, 0xEF3, 0 ) ); // Scriptiz : price 12 + + for ( int i = 0; i < PresetMapEntry.Table.Length; ++i ) + Add( new PresetMapBuyInfo( PresetMapEntry.Table[i], Utility.RandomMinMax( 7, 10 ), 20 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BlankScroll ), 6 ); + Add( typeof( MapmakersPen ), 4 ); + Add( typeof( BlankMap ), 2 ); + Add( typeof( CityMap ), 3 ); + Add( typeof( LocalMap ), 3 ); + Add( typeof( WorldMap ), 3 ); + Add( typeof( PresetMapEntry ), 3 ); + //TODO: Buy back maps that the mapmaker sells!!! + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBMiller.cs b/Scripts/Mobiles/Vendors/SBInfo/SBMiller.cs new file mode 100644 index 0000000..eda0fc7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBMiller.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMiller : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMiller() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( SackFlour ), 3, 20, 0x1039, 0 ) ); + Add( new GenericBuyInfo( typeof( SheafOfHay ), 2, 20, 0xF36, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( SackFlour ), 1 ); + Add( typeof( SheafOfHay ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBMiner.cs b/Scripts/Mobiles/Vendors/SBInfo/SBMiner.cs new file mode 100644 index 0000000..af506fb --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBMiner.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMiner: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMiner() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bag ), 6, 20, 0xE76, 0 ) ); + Add( new GenericBuyInfo( typeof( Candle ), 6, 10, 0xA28, 0 ) ); + Add( new GenericBuyInfo( typeof( Torch ), 8, 10, 0xF6B, 0 ) ); + Add( new GenericBuyInfo( typeof( Lantern ), 2, 10, 0xA25, 0 ) ); + //Add( new GenericBuyInfo( typeof( OilFlask ), 8, 10, 0x####, 0 ) ); + Add( new GenericBuyInfo( typeof( Pickaxe ), 25, 10, 0xE86, 0 ) ); + Add( new GenericBuyInfo( typeof( Shovel ), 12, 10, 0xF39, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Pickaxe ), 12 ); + Add( typeof( Shovel ), 6 ); + Add( typeof( Lantern ), 1 ); + //Add( typeof( OilFlask ), 4 ); + Add( typeof( Torch ), 3 ); + Add( typeof( Bag ), 3 ); + Add( typeof( Candle ), 3 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBMonk.cs b/Scripts/Mobiles/Vendors/SBInfo/SBMonk.cs new file mode 100644 index 0000000..00443a8 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBMonk.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMonk : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMonk() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + if (Core.AOS) Add(new GenericBuyInfo(typeof(MonkRobe), 136, 20, 0x2687, 0x21E)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBNinja.cs b/Scripts/Mobiles/Vendors/SBInfo/SBNinja.cs new file mode 100644 index 0000000..3a261ae --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBNinja.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBNinja : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBNinja() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BookOfNinjitsu ), 335, 20, 0x23A0, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs b/Scripts/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs new file mode 100644 index 0000000..c821658 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBPlayerBarkeeper.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPlayerBarkeeper : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBPlayerBarkeeper() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Ale, 7, 20, 0x99F, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Wine, 7, 20, 0x9C7, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Liquor, 7, 20, 0x99B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Jug ), BeverageType.Cider, 13, 20, 0x9C8, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Milk, 56, 20, 0x9F0, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Ale, 88, 20, 0x1F95, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Cider, 88, 20, 0x1F97, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Liquor, 88, 20, 0x1F99, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Wine, 88, 20, 0x1F9B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Water, 88, 20, 0x1F9D, 0 ) ); + // TODO: pizza + // TODO: bowl of *, tomato soup + Add( new GenericBuyInfo( "1016450", typeof( Chessboard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( "1016449", typeof( CheckerBoard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( typeof( Backgammon ), 2, 20, 0xE1C, 0 ) ); + Add( new GenericBuyInfo( typeof( Dices ), 2, 20, 0xFA7, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBProvisioner.cs b/Scripts/Mobiles/Vendors/SBInfo/SBProvisioner.cs new file mode 100644 index 0000000..0f14e45 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBProvisioner.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Guilds; + +namespace Server.Mobiles +{ + public class SBProvisioner : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBProvisioner() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + #region Salvage Bag + if( Core.ML ) + Add( new GenericBuyInfo( "1079931", typeof( SalvageBag ), 1255, 20, 0xE76, Utility.RandomBlueHue() ) ); + #endregion + Add( new GenericBuyInfo( "1060834", typeof( Engines.Plants.PlantBowl ), 2, 20, 0x15FD, 0 ) ); + + Add( new GenericBuyInfo( typeof( Arrow ), 2, 20, 0xF3F, 0 ) ); + Add( new GenericBuyInfo( typeof( Bolt ), 5, 20, 0x1BFB, 0 ) ); + + Add( new GenericBuyInfo( typeof( Backpack ), 15, 20, 0x9B2, 0 ) ); + Add( new GenericBuyInfo( typeof( Pouch ), 6, 20, 0xE79, 0 ) ); + Add( new GenericBuyInfo( typeof( Bag ), 6, 20, 0xE76, 0 ) ); + + Add( new GenericBuyInfo( typeof( Candle ), 6, 20, 0xA28, 0 ) ); + Add( new GenericBuyInfo( typeof( Torch ), 8, 20, 0xF6B, 0 ) ); + Add( new GenericBuyInfo( typeof( Lantern ), 2, 20, 0xA25, 0 ) ); + + //TODO: Oil Flask @ 8GP + + Add( new GenericBuyInfo( typeof( Lockpick ), 12, 20, 0x14FC, 0 ) ); + + Add( new GenericBuyInfo( typeof( FloppyHat ), 7, 20, 0x1713, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( WideBrimHat ), 8, 20, 0x1714, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( Cap ), 10, 20, 0x1715, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( TallStrawHat ), 8, 20, 0x1716, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( StrawHat ), 7, 20, 0x1717, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( WizardsHat ), 11, 20, 0x1718, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( LeatherCap ), 10, 20, 0x1DB9, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( FeatheredHat ), 10, 20, 0x171A, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( TricorneHat ), 8, 20, 0x171B, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( Bandana ), 6, 20, 0x1540, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( SkullCap ), 7, 20, 0x1544, Utility.RandomDyedHue() ) ); + + Add( new GenericBuyInfo( typeof( BreadLoaf ), 6, 10, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( LambLeg ), 8, 20, 0x160A, 0 ) ); + Add( new GenericBuyInfo( typeof( ChickenLeg ), 5, 20, 0x1608, 0 ) ); + Add( new GenericBuyInfo( typeof( CookedBird ), 17, 20, 0x9B7, 0 ) ); + + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Ale, 7, 20, 0x99F, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Wine, 7, 20, 0x9C7, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Liquor, 7, 20, 0x99B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Jug ), BeverageType.Cider, 13, 20, 0x9C8, 0 ) ); + + Add( new GenericBuyInfo( typeof( Pear ), 3, 20, 0x994, 0 ) ); + Add( new GenericBuyInfo( typeof( Apple ), 3, 20, 0x9D0, 0 ) ); + + Add( new GenericBuyInfo( typeof( Beeswax ), 1, 20, 0x1422, 0 ) ); + + Add( new GenericBuyInfo( typeof( Garlic ), 3, 20, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 20, 0xF85, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bottle ), 5, 20, 0xF0E, 0 ) ); + + Add(new GenericBuyInfo(typeof(RedBook), 35, 20, 0xFF1, 0)); + Add(new GenericBuyInfo(typeof(BlueBook), 35, 20, 0xFF2, 0)); + Add(new GenericBuyInfo(typeof(TanBook), 35, 20, 0xFF0, 0)); + + Add( new GenericBuyInfo( typeof( WoodenBox ), 14, 20, 0xE7D, 0 ) ); + Add( new GenericBuyInfo( typeof( Key ), 2, 20, 0x100E, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bedroll ), 5, 20, 0xA59, 0 ) ); + Add( new GenericBuyInfo( typeof( Kindling ), 2, 20, 0xDE1, 0 ) ); + + Add( new GenericBuyInfo( "1041205", typeof( Multis.SmallBoatDeed ), 10177, 20, 0x14F2, 0 ) ); + + Add( new GenericBuyInfo( "1041060", typeof( HairDye ), 60, 20, 0xEFF, 0 ) ); + + Add( new GenericBuyInfo( "1016450", typeof( Chessboard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( "1016449", typeof( CheckerBoard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( typeof( Backgammon ), 2, 20, 0xE1C, 0 ) ); + if ( Core.AOS ) + Add( new GenericBuyInfo( typeof( Engines.Mahjong.MahjongGame ), 6, 20, 0xFAA, 0 ) ); + Add( new GenericBuyInfo( typeof( Dices ), 2, 20, 0xFA7, 0 ) ); + + if ( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( SmallBagBall ), 3, 20, 0x2256, 0 ) ); + Add( new GenericBuyInfo( typeof( LargeBagBall ), 3, 20, 0x2257, 0 ) ); + } + + if( !Guild.NewGuildSystem ) + Add( new GenericBuyInfo( "1041055", typeof( GuildDeed ), 12450, 20, 0x14F0, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Arrow ), 1 ); + Add( typeof( Bolt ), 2 ); + Add( typeof( Backpack ), 7 ); + Add( typeof( Pouch ), 3 ); + Add( typeof( Bag ), 3 ); + Add( typeof( Candle ), 3 ); + Add( typeof( Torch ), 4 ); + Add( typeof( Lantern ), 1 ); + Add( typeof( Lockpick ), 6 ); + Add( typeof( FloppyHat ), 3 ); + Add( typeof( WideBrimHat ), 4 ); + Add( typeof( Cap ), 5 ); + Add( typeof( TallStrawHat ), 4 ); + Add( typeof( StrawHat ), 3 ); + Add( typeof( WizardsHat ), 5 ); + Add( typeof( LeatherCap ), 5 ); + Add( typeof( FeatheredHat ), 5 ); + Add( typeof( TricorneHat ), 4 ); + Add( typeof( Bandana ), 3 ); + Add( typeof( SkullCap ), 3 ); + Add( typeof( Bottle ), 3 ); + Add( typeof( RedBook ), 7 ); + Add( typeof( BlueBook ), 7 ); + Add( typeof( TanBook ), 7 ); + Add( typeof( WoodenBox ), 7 ); + Add( typeof( Kindling ), 1 ); + Add( typeof( HairDye ), 30 ); + Add( typeof( Chessboard ), 1 ); + Add( typeof( CheckerBoard ), 1 ); + Add( typeof( Backgammon ), 1 ); + Add( typeof( Dices ), 1 ); + + Add( typeof( Beeswax ), 1 ); + + Add( typeof( Amber ), 25 ); + Add( typeof( Amethyst ), 50 ); + Add( typeof( Citrine ), 25 ); + Add( typeof( Diamond ), 100 ); + Add( typeof( Emerald ), 50 ); + Add( typeof( Ruby ), 37 ); + Add( typeof( Sapphire ), 50 ); + Add( typeof( StarSapphire ), 62 ); + Add( typeof( Tourmaline ), 47 ); + Add( typeof( GoldRing ), 13 ); + Add( typeof( SilverRing ), 10 ); + Add( typeof( Necklace ), 13 ); + Add( typeof( GoldNecklace ), 13 ); + Add( typeof( GoldBeadNecklace ), 13 ); + Add( typeof( SilverNecklace ), 10 ); + Add( typeof( SilverBeadNecklace ), 10 ); + Add( typeof( Beads ), 13 ); + Add( typeof( GoldBracelet ), 13 ); + Add( typeof( SilverBracelet ), 10 ); + Add( typeof( GoldEarrings ), 13 ); + Add( typeof( SilverEarrings ), 10 ); + + if( !Guild.NewGuildSystem ) + Add( typeof( GuildDeed ), 6225 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBRancher.cs b/Scripts/Mobiles/Vendors/SBInfo/SBRancher.cs new file mode 100644 index 0000000..c53e87c --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBRancher.cs @@ -0,0 +1,35 @@ + +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRancher : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBRancher() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new AnimalBuyInfo( 1, typeof( PackHorse ), 631, 10, 291, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBRanger.cs b/Scripts/Mobiles/Vendors/SBInfo/SBRanger.cs new file mode 100644 index 0000000..003af0b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBRanger.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRanger : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBRanger() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new AnimalBuyInfo( 1, typeof( Cat ), 138, 20, 201, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Dog ), 181, 20, 217, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( PackLlama ), 491, 20, 292, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( PackHorse ), 606, 20, 291, 0 ) ); + Add( new GenericBuyInfo( typeof( Bandage ), 5, 20, 0xE21, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs b/Scripts/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs new file mode 100644 index 0000000..8601847 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBRealEstateBroker.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRealEstateBroker : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBRealEstateBroker() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 20, 0x0E34, 0 ) ); + Add( new GenericBuyInfo( typeof( ScribesPen ), 8, 20, 0xFBF, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( ScribesPen ), 4 ); + Add( typeof( BlankScroll ), 5 ); // Scriptiz : 2 + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBSECook.cs b/Scripts/Mobiles/Vendors/SBInfo/SBSECook.cs new file mode 100644 index 0000000..9e7f99b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBSECook.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSECook: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSECook() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); + Add( new GenericBuyInfo( typeof( SushiRolls ), 3, 20, 0x283E, 0 ) ); + Add( new GenericBuyInfo( typeof( SushiPlatter ), 3, 20, 0x2840, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenTea ), 3, 20, 0x284C, 0 ) ); + Add( new GenericBuyInfo( typeof( MisoSoup ), 3, 20, 0x284D, 0 ) ); + Add( new GenericBuyInfo( typeof( WhiteMisoSoup ), 3, 20, 0x284E, 0 ) ); + Add( new GenericBuyInfo( typeof( RedMisoSoup ), 3, 20, 0x284F, 0 ) ); + Add( new GenericBuyInfo( typeof( AwaseMisoSoup ), 3, 20, 0x2850, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Wasabi ), 1 ); + Add( typeof( BentoBox ), 3 ); + Add( typeof( GreenTea ), 1 ); + Add( typeof( SushiRolls ), 1 ); + Add( typeof( SushiPlatter ), 2 ); + Add( typeof( MisoSoup ), 1 ); + Add( typeof( RedMisoSoup ), 1 ); + Add( typeof( WhiteMisoSoup ), 1 ); + Add( typeof( AwaseMisoSoup ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBSEHats.cs b/Scripts/Mobiles/Vendors/SBInfo/SBSEHats.cs new file mode 100644 index 0000000..1b2402b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBSEHats.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEHats: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSEHats() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Kasa ), 31, 20, 0x2798, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherJingasa ), 11, 20, 0x2776, 0 ) ); + Add( new GenericBuyInfo( typeof( ClothNinjaHood ), 33, 20, 0x278F, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Kasa ), 15 ); + Add( typeof( LeatherJingasa ), 5 ); + Add( typeof( ClothNinjaHood ), 16 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBSamurai.cs b/Scripts/Mobiles/Vendors/SBInfo/SBSamurai.cs new file mode 100644 index 0000000..703d430 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBSamurai.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSamurai : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSamurai() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BookOfBushido ), 280, 20, 0x238C, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBScribe.cs b/Scripts/Mobiles/Vendors/SBInfo/SBScribe.cs new file mode 100644 index 0000000..b14fb5a --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBScribe.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBScribe: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBScribe() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( ScribesPen ), 8, 20, 0xFBF, 0 ) ); + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 999, 0x0E34, 0 ) ); + Add( new GenericBuyInfo( typeof( ScribesPen ), 8, 20, 0xFC0, 0 ) ); + Add( new GenericBuyInfo( typeof( BrownBook ), 35, 10, 0xFEF, 0 ) ); + Add(new GenericBuyInfo(typeof(TanBook), 35, 10, 0xFF0, 0)); + Add(new GenericBuyInfo(typeof(BlueBook), 35, 10, 0xFF2, 0)); + //Add( new GenericBuyInfo( "1041267", typeof( Runebook ), 3500, 10, 0xEFA, 0x461 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( ScribesPen ), 4 ); + Add( typeof( BrownBook ), 7 ); + Add( typeof( TanBook ), 7 ); + Add( typeof( BlueBook ), 7 ); + Add( typeof( BlankScroll ), 5 ); // Scriptiz 3 + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBShipwright.cs b/Scripts/Mobiles/Vendors/SBInfo/SBShipwright.cs new file mode 100644 index 0000000..d1fe64a --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBShipwright.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBShipwright : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBShipwright() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( "1041205", typeof( SmallBoatDeed ), 10177, 20, 0x14F2, 0 ) ); + Add( new GenericBuyInfo( "1041206", typeof( SmallDragonBoatDeed ), 11177, 20, 0x14F2, 0 ) ); + Add( new GenericBuyInfo( "1041207", typeof( MediumBoatDeed ), 11552, 20, 0x14F2, 0 ) ); + Add( new GenericBuyInfo( "1041208", typeof( MediumDragonBoatDeed ), 12552, 20, 0x14F2, 0 ) ); + /*Add( new GenericBuyInfo( "1041209", typeof( LargeBoatDeed ), 12927, 20, 0x14F2, 0 ) ); + Add( new GenericBuyInfo( "1041210", typeof( LargeDragonBoatDeed ), 12927, 20, 0x14F2, 0 ) );*/ + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + //You technically CAN sell them back, *BUT* the vendors do not carry enough money to buy with + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBSmithTools.cs b/Scripts/Mobiles/Vendors/SBInfo/SBSmithTools.cs new file mode 100644 index 0000000..e9b9616 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBSmithTools.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSmithTools: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSmithTools() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( IronIngot ), 5, 16, 0x1BF2, 0 ) ); + Add( new GenericBuyInfo( typeof( Tongs ), 13, 14, 0xFBB, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Tongs ), 7 ); + Add( typeof( IronIngot ), 4 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs b/Scripts/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs new file mode 100644 index 0000000..d9f10d0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBStoneCrafter.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBStoneCrafter : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBStoneCrafter() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Nails ), 3, 20, 0x102E, 0 ) ); + Add( new GenericBuyInfo( typeof( Axle ), 2, 20, 0x105B, 0 ) ); + Add( new GenericBuyInfo( typeof( Board ), 3, 20, 0x1BD7, 0 ) ); + Add( new GenericBuyInfo( typeof( DrawKnife ), 10, 20, 0x10E4, 0 ) ); + Add( new GenericBuyInfo( typeof( Froe ), 10, 20, 0x10E5, 0 ) ); + Add( new GenericBuyInfo( typeof( Scorp ), 10, 20, 0x10E7, 0 ) ); + Add( new GenericBuyInfo( typeof( Inshave ), 10, 20, 0x10E6, 0 ) ); + Add( new GenericBuyInfo( typeof( DovetailSaw ), 12, 20, 0x1028, 0 ) ); + Add( new GenericBuyInfo( typeof( Saw ), 15, 20, 0x1034, 0 ) ); + Add( new GenericBuyInfo( typeof( Hammer ), 17, 20, 0x102A, 0 ) ); + Add( new GenericBuyInfo( typeof( MouldingPlane ), 11, 20, 0x102C, 0 ) ); + Add( new GenericBuyInfo( typeof( SmoothingPlane ), 10, 20, 0x1032, 0 ) ); + Add( new GenericBuyInfo( typeof( JointingPlane ), 11, 20, 0x1030, 0 ) ); + + Add( new GenericBuyInfo( "Making Valuables With Stonecrafting", typeof( MasonryBook ), 10625, 10, 0xFBE, 0 ) ); + Add( new GenericBuyInfo( "Mining For Quality Stone", typeof( StoneMiningBook ), 10625, 10, 0xFBE, 0 ) ); + Add( new GenericBuyInfo( "1044515", typeof( MalletAndChisel ), 3, 50, 0x12B3, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( MasonryBook ), 5000 ); + Add( typeof( StoneMiningBook ), 5000 ); + Add( typeof( MalletAndChisel ), 1 ); + + Add( typeof( WoodenBox ), 7 ); + Add( typeof( SmallCrate ), 5 ); + Add( typeof( MediumCrate ), 6 ); + Add( typeof( LargeCrate ), 7 ); + Add( typeof( WoodenChest ), 15 ); + + Add( typeof( LargeTable ), 10 ); + Add( typeof( Nightstand ), 7 ); + Add( typeof( YewWoodTable ), 10 ); + + Add( typeof( Throne ), 24 ); + Add( typeof( WoodenThrone ), 6 ); + Add( typeof( Stool ), 6 ); + Add( typeof( FootStool ), 6 ); + + Add( typeof( FancyWoodenChairCushion ), 12 ); + Add( typeof( WoodenChairCushion ), 10 ); + Add( typeof( WoodenChair ), 8 ); + Add( typeof( BambooChair ), 6 ); + Add( typeof( WoodenBench ), 6 ); + + Add( typeof( Saw ), 9 ); + Add( typeof( Scorp ), 6 ); + Add( typeof( SmoothingPlane ), 6 ); + Add( typeof( DrawKnife ), 6 ); + Add( typeof( Froe ), 6 ); + Add( typeof( Hammer ), 14 ); + Add( typeof( Inshave ), 6 ); + Add( typeof( JointingPlane ), 6 ); + Add( typeof( MouldingPlane ), 6 ); + Add( typeof( DovetailSaw ), 7 ); + Add( typeof( Board ), 2 ); + Add( typeof( Axle ), 1 ); + + Add( typeof( WoodenShield ), 31 ); + Add( typeof( BlackStaff ), 24 ); + Add( typeof( GnarledStaff ), 12 ); + Add( typeof( QuarterStaff ), 15 ); + Add( typeof( ShepherdsCrook ), 12 ); + Add( typeof( Club ), 13 ); + + Add( typeof( Log ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBTailor.cs b/Scripts/Mobiles/Vendors/SBInfo/SBTailor.cs new file mode 100644 index 0000000..f37b5dc --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBTailor.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTailor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBTailor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + + Add( new GenericBuyInfo( typeof( SewingKit ), 3, 20, 0xF9D, 0 ) ); + Add( new GenericBuyInfo( typeof( Scissors ), 11, 20, 0xF9F, 0 ) ); + Add( new GenericBuyInfo( typeof( DyeTub ), 8, 20, 0xFAB, 0 ) ); + Add( new GenericBuyInfo( typeof( Dyes ), 8, 20, 0xFA9, 0 ) ); + + Add( new GenericBuyInfo( typeof( Shirt ), 12, 20, 0x1517, 0 ) ); + Add( new GenericBuyInfo( typeof( ShortPants ), 7, 20, 0x152E, 0 ) ); + Add( new GenericBuyInfo( typeof( FancyShirt ), 21, 20, 0x1EFD, 0 ) ); + Add( new GenericBuyInfo( typeof( LongPants ), 10, 20, 0x1539, 0 ) ); + Add( new GenericBuyInfo( typeof( FancyDress ), 26, 20, 0x1EFF, 0 ) ); + Add( new GenericBuyInfo( typeof( PlainDress ), 13, 20, 0x1F01, 0 ) ); + Add( new GenericBuyInfo( typeof( Kilt ), 11, 20, 0x1537, 0 ) ); + Add( new GenericBuyInfo( typeof( Kilt ), 11, 20, 0x1537, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( HalfApron ), 10, 20, 0x153b, 0 ) ); + Add( new GenericBuyInfo( typeof( Robe ), 18, 20, 0x1F03, 0 ) ); + Add( new GenericBuyInfo( typeof( Cloak ), 8, 20, 0x1515, 0 ) ); + //Add( new GenericBuyInfo( typeof( Cloak ), 8, 20, 0x1515, 0 ) ); + Add( new GenericBuyInfo( typeof( Doublet ), 13, 20, 0x1F7B, 0 ) ); + Add( new GenericBuyInfo( typeof( Tunic ), 18, 20, 0x1FA1, 0 ) ); + Add( new GenericBuyInfo( typeof( JesterSuit ), 26, 20, 0x1F9F, 0 ) ); + + Add( new GenericBuyInfo( typeof( JesterHat ), 12, 20, 0x171C, 0 ) ); + Add( new GenericBuyInfo( typeof( FloppyHat ), 7, 20, 0x1713, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( WideBrimHat ), 8, 20, 0x1714, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( Cap ), 10, 20, 0x1715, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( TallStrawHat ), 8, 20, 0x1716, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( StrawHat ), 7, 20, 0x1717, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( WizardsHat ), 11, 20, 0x1718, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( LeatherCap ), 10, 20, 0x1DB9, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( FeatheredHat ), 10, 20, 0x171A, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( TricorneHat ), 8, 20, 0x171B, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( Bandana ), 6, 20, 0x1540, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( SkullCap ), 7, 20, 0x1544, Utility.RandomDyedHue() ) ); + + // Scriptiz : ajout de chaussures + Add(new GenericBuyInfo(typeof(Shoes), 8, 20, 0x170F, 0)); + + Add( new GenericBuyInfo( typeof( BoltOfCloth ), 100, 20, 0xf95, Utility.RandomDyedHue() ) ); + + Add( new GenericBuyInfo( typeof( Cloth ), 2, 20, 0x1766, Utility.RandomDyedHue() ) ); + Add( new GenericBuyInfo( typeof( UncutCloth ), 2, 20, 0x1767, Utility.RandomDyedHue() ) ); + + Add( new GenericBuyInfo( typeof( Cotton ), 102, 20, 0xDF9, 0 ) ); + Add( new GenericBuyInfo( typeof( Wool ), 62, 20, 0xDF8, 0 ) ); + Add( new GenericBuyInfo( typeof( Flax ), 102, 20, 0x1A9C, 0 ) ); + Add( new GenericBuyInfo( typeof( SpoolOfThread ), 18, 20, 0xFA0, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Scissors ), 6 ); + Add( typeof( SewingKit ), 1 ); + Add( typeof( Dyes ), 4 ); + Add( typeof( DyeTub ), 4 ); + + Add( typeof( BoltOfCloth ), 50 ); + + Add( typeof( FancyShirt ), 10 ); + Add( typeof( Shirt ), 6 ); + + Add( typeof( ShortPants ), 3 ); + Add( typeof( LongPants ), 5 ); + + Add( typeof( Cloak ), 4 ); + Add( typeof( FancyDress ), 12 ); + Add( typeof( Robe ), 9 ); + Add( typeof( PlainDress ), 7 ); + + Add( typeof( Skirt ), 5 ); + Add( typeof( Kilt ), 5 ); + + Add( typeof( Doublet ), 7 ); + Add( typeof( Tunic ), 9 ); + Add( typeof( JesterSuit ), 13 ); + + Add( typeof( FullApron ), 5 ); + Add( typeof( HalfApron ), 5 ); + + Add( typeof( JesterHat ), 6 ); + Add( typeof( FloppyHat ), 3 ); + Add( typeof( WideBrimHat ), 4 ); + Add( typeof( Cap ), 5 ); + Add( typeof( SkullCap ), 3 ); + Add( typeof( Bandana ), 3 ); + Add( typeof( TallStrawHat ), 4 ); + Add( typeof( StrawHat ), 4 ); + Add( typeof( WizardsHat ), 5 ); + Add( typeof( Bonnet ), 4 ); + Add( typeof( FeatheredHat ), 5 ); + Add( typeof( TricorneHat ), 4 ); + + Add( typeof( SpoolOfThread ), 9 ); + + Add( typeof( Flax ), 51 ); + Add( typeof( Cotton ), 51 ); + Add( typeof( Wool ), 31 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBTanner.cs b/Scripts/Mobiles/Vendors/SBInfo/SBTanner.cs new file mode 100644 index 0000000..5146bba --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBTanner.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTanner : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBTanner() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( LeatherGorget ), 31, 20, 0x13C7, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherCap ), 10, 20, 0x1DB9, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherArms ), 37, 20, 0x13CD, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherChest ), 47, 20, 0x13CC, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherLegs ), 36, 20, 0x13CB, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherGloves ), 31, 20, 0x13C6, 0 ) ); + + Add( new GenericBuyInfo( typeof( StuddedGorget ), 50, 20, 0x13D6, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedArms ), 57, 20, 0x13DC, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedChest ), 75, 20, 0x13DB, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedLegs ), 67, 20, 0x13DA, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedGloves ), 45, 20, 0x13D5, 0 ) ); + + Add( new GenericBuyInfo( typeof( FemaleStuddedChest ), 62, 20, 0x1C02, 0 ) ); + Add( new GenericBuyInfo( typeof( FemalePlateChest ), 207, 20, 0x1C04, 0 ) ); + Add( new GenericBuyInfo( typeof( FemaleLeatherChest ), 36, 20, 0x1C06, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherShorts ), 28, 20, 0x1C00, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherSkirt ), 25, 20, 0x1C08, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherBustierArms ), 25, 20, 0x1C0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherBustierArms ), 30, 20, 0x1C0B, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedBustierArms ), 50, 20, 0x1C0C, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedBustierArms ), 47, 20, 0x1C0D, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bag ), 6, 20, 0xE76, 0 ) ); + Add( new GenericBuyInfo( typeof( Pouch ), 6, 20, 0xE79, 0 ) ); + Add( new GenericBuyInfo( typeof( Backpack ), 15, 20, 0x9B2, 0 ) ); + Add( new GenericBuyInfo( typeof( Leather ), 6, 20, 0x1081, 0 ) ); + + Add( new GenericBuyInfo( typeof( SkinningKnife ), 15, 20, 0xEC4, 0 ) ); + + Add( new GenericBuyInfo( "1041279", typeof( TaxidermyKit ), 100000, 20, 0x1EBA, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bag ), 3 ); + Add( typeof( Pouch ), 3 ); + Add( typeof( Backpack ), 7 ); + + Add( typeof( Leather ), 5 ); + + Add( typeof( SkinningKnife ), 7 ); + + Add( typeof( LeatherArms ), 18 ); + Add( typeof( LeatherChest ), 23 ); + Add( typeof( LeatherGloves ), 15 ); + Add( typeof( LeatherGorget ), 15 ); + Add( typeof( LeatherLegs ), 18 ); + Add( typeof( LeatherCap ), 5 ); + + Add( typeof( StuddedArms ), 43 ); + Add( typeof( StuddedChest ), 37 ); + Add( typeof( StuddedGloves ), 39 ); + Add( typeof( StuddedGorget ), 22 ); + Add( typeof( StuddedLegs ), 33 ); + + Add( typeof( FemaleStuddedChest ), 31 ); + Add( typeof( StuddedBustierArms ), 23 ); + Add( typeof( FemalePlateChest), 103 ); + Add( typeof( FemaleLeatherChest ), 18 ); + Add( typeof( LeatherBustierArms ), 12 ); + Add( typeof( LeatherShorts ), 14 ); + Add( typeof( LeatherSkirt ), 12 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs b/Scripts/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs new file mode 100644 index 0000000..e0038c9 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBTavernKeeper.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTavernKeeper : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBTavernKeeper() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Ale, 7, 20, 0x99F, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Wine, 7, 20, 0x9C7, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Liquor, 7, 20, 0x99B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Jug ), BeverageType.Cider, 13, 20, 0x9C8, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Milk, 56, 20, 0x9F0, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Ale, 88, 20, 0x1F95, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Cider, 88, 20, 0x1F97, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Liquor, 88, 20, 0x1F99, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Wine, 88, 20, 0x1F9B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Water, 88, 20, 0x1F9D, 0 ) ); + + Add( new GenericBuyInfo( typeof( BreadLoaf ), 6, 10, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( CheeseWheel ), 21, 10, 0x97E, 0 ) ); + Add( new GenericBuyInfo( typeof( CookedBird ), 17, 20, 0x9B7, 0 ) ); + Add( new GenericBuyInfo( typeof( LambLeg ), 8, 20, 0x160A, 0 ) ); + Add( new GenericBuyInfo( typeof( ChickenLeg ), 5, 20, 0x1608, 0 ) ); + Add( new GenericBuyInfo( typeof( Ribs ), 7, 20, 0x9F2, 0 ) ); + + Add( new GenericBuyInfo( typeof( WoodenBowlOfCarrots ), 3, 20, 0x15F9, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfCorn ), 3, 20, 0x15FA, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfLettuce ), 3, 20, 0x15FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfPeas ), 3, 20, 0x15FC, 0 ) ); + Add( new GenericBuyInfo( typeof( EmptyPewterBowl ), 2, 20, 0x15FD, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfCorn ), 3, 20, 0x15FE, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfLettuce ), 3, 20, 0x15FF, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPeas ), 3, 20, 0x1600, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPotatos ), 3, 20, 0x1601, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfStew ), 3, 20, 0x1604, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfTomatoSoup ), 3, 20, 0x1606, 0 ) ); + + Add( new GenericBuyInfo( typeof( ApplePie ), 7, 20, 0x1041, 0 ) ); //OSI just has Pie, not Apple/Fruit/Meat + + Add( new GenericBuyInfo( "1016450", typeof( Chessboard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( "1016449", typeof( CheckerBoard ), 2, 20, 0xFA6, 0 ) ); + Add( new GenericBuyInfo( typeof( Backgammon ), 2, 20, 0xE1C, 0 ) ); + Add( new GenericBuyInfo( typeof( Dices ), 2, 20, 0xFA7, 0 ) ); + Add( new GenericBuyInfo( "1041243", typeof( ContractOfEmployment ), 1252, 20, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "a barkeep contract", typeof( BarkeepContract ), 1252, 20, 0x14F0, 0 ) ); + + if ( Multis.BaseHouse.NewVendorSystem ) + Add( new GenericBuyInfo( "1062332", typeof( VendorRentalContract ), 1252, 20, 0x14F0, 0x672 ) ); + + /*if ( Map == Tokuno ) + { + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); + }*/ + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( WoodenBowlOfCarrots ), 1 ); + Add( typeof( WoodenBowlOfCorn ), 1 ); + Add( typeof( WoodenBowlOfLettuce ), 1 ); + Add( typeof( WoodenBowlOfPeas ), 1 ); + Add( typeof( EmptyPewterBowl ), 1 ); + Add( typeof( PewterBowlOfCorn ), 1 ); + Add( typeof( PewterBowlOfLettuce ), 1 ); + Add( typeof( PewterBowlOfPeas ), 1 ); + Add( typeof( PewterBowlOfPotatos ), 1 ); + Add( typeof( WoodenBowlOfStew ), 1 ); + Add( typeof( WoodenBowlOfTomatoSoup ), 1 ); + Add( typeof( BeverageBottle ), 3 ); + Add( typeof( Jug ), 6 ); + Add( typeof( Pitcher ), 5 ); + Add( typeof( GlassMug ), 1 ); + Add( typeof( BreadLoaf ), 3 ); + Add( typeof( CheeseWheel ), 12 ); + Add( typeof( Ribs ), 6 ); + Add( typeof( Peach ), 1 ); + Add( typeof( Pear ), 1 ); + Add( typeof( Grapes ), 1 ); + Add( typeof( Apple ), 1 ); + Add( typeof( Banana ), 1 ); + Add( typeof( Candle ), 3 ); + Add( typeof( Chessboard ), 1 ); + Add( typeof( CheckerBoard ), 1 ); + Add( typeof( Backgammon ), 1 ); + Add( typeof( Dices ), 1 ); + Add( typeof( ContractOfEmployment ), 626 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBThief.cs b/Scripts/Mobiles/Vendors/SBInfo/SBThief.cs new file mode 100644 index 0000000..a416668 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBThief.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBThief : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBThief() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Backpack ), 15, 20, 0x9B2, 0 ) ); + Add( new GenericBuyInfo( typeof( Pouch ), 6, 20, 0xE79, 0 ) ); + Add( new GenericBuyInfo( typeof( Torch ), 8, 20, 0xF6B, 0 ) ); + Add( new GenericBuyInfo( typeof( Lantern ), 2, 20, 0xA25, 0 ) ); + //Add( new GenericBuyInfo( typeof( OilFlask ), 8, 20, 0x####, 0 ) ); + Add( new GenericBuyInfo( typeof( Lockpick ), 12, 20, 0x14FC, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBox ), 14, 20, 0x9AA, 0 ) ); + Add( new GenericBuyInfo( typeof( Key ), 2, 20, 0x100E, 0 ) ); + Add( new GenericBuyInfo( typeof( HairDye ), 37, 20, 0xEFF, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Backpack ), 7 ); + Add( typeof( Pouch ), 3 ); + Add( typeof( Torch ), 3 ); + Add( typeof( Lantern ), 1 ); + //Add( typeof( OilFlask ), 4 ); + Add( typeof( Lockpick ), 6 ); + Add( typeof( WoodenBox ), 7 ); + Add( typeof( HairDye ), 19 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBTinker.cs b/Scripts/Mobiles/Vendors/SBInfo/SBTinker.cs new file mode 100644 index 0000000..063f880 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBTinker.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBTinker: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBTinker() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + + Add( new GenericBuyInfo( typeof( Clock ), 22, 20, 0x104B, 0 ) ); + Add( new GenericBuyInfo( typeof( Nails ), 3, 20, 0x102E, 0 ) ); + Add( new GenericBuyInfo( typeof( ClockParts ), 3, 20, 0x104F, 0 ) ); + Add( new GenericBuyInfo( typeof( AxleGears ), 3, 20, 0x1051, 0 ) ); + Add( new GenericBuyInfo( typeof( Gears ), 2, 20, 0x1053, 0 ) ); + Add( new GenericBuyInfo( typeof( Hinge ), 2, 20, 0x1055, 0 ) ); + + Add( new GenericBuyInfo( typeof( Sextant ), 13, 20, 0x1057, 0 ) ); + Add( new GenericBuyInfo( typeof( SextantParts ), 5, 20, 0x1059, 0 ) ); + Add( new GenericBuyInfo( typeof( Axle ), 2, 20, 0x105B, 0 ) ); + Add( new GenericBuyInfo( typeof( Springs ), 3, 20, 0x105D, 0 ) ); + + Add( new GenericBuyInfo( "1024111", typeof( Key ), 8, 20, 0x100F, 0 ) ); + Add( new GenericBuyInfo( "1024112", typeof( Key ), 8, 20, 0x1010, 0 ) ); + Add( new GenericBuyInfo( "1024115", typeof( Key ), 8, 20, 0x1013, 0 ) ); + Add( new GenericBuyInfo( typeof( KeyRing ), 8, 20, 0x1010, 0 ) ); + Add( new GenericBuyInfo( typeof( Lockpick ), 12, 20, 0x14FC, 0 ) ); + + Add(new GenericBuyInfo(typeof(TinkersTools), 7, 20, 0x1EBC, 0)); + Add( new GenericBuyInfo( typeof( Board ), 3, 20, 0x1BD7, 0 ) ); + Add( new GenericBuyInfo( typeof( IronIngot ), 5, 16, 0x1BF2, 0 ) ); + Add( new GenericBuyInfo( typeof( SewingKit ), 3, 20, 0xF9D, 0 ) ); + + Add( new GenericBuyInfo( typeof( DrawKnife ), 10, 20, 0x10E4, 0 ) ); + Add( new GenericBuyInfo( typeof( Froe ), 10, 20, 0x10E5, 0 ) ); + Add( new GenericBuyInfo( typeof( Scorp ), 10, 20, 0x10E7, 0 ) ); + Add( new GenericBuyInfo( typeof( Inshave ), 10, 20, 0x10E6, 0 ) ); + + Add( new GenericBuyInfo( typeof( ButcherKnife ), 13, 20, 0x13F6, 0 ) ); + + Add( new GenericBuyInfo( typeof( Scissors ), 11, 20, 0xF9F, 0 ) ); + + Add( new GenericBuyInfo( typeof( Tongs ), 13, 14, 0xFBB, 0 ) ); + + Add( new GenericBuyInfo( typeof( DovetailSaw ), 12, 20, 0x1028, 0 ) ); + Add( new GenericBuyInfo( typeof( Saw ), 15, 20, 0x1034, 0 ) ); + + Add( new GenericBuyInfo( typeof( Hammer ), 17, 20, 0x102A, 0 ) ); + Add( new GenericBuyInfo( typeof( SmithHammer ), 23, 20, 0x13E3, 0 ) ); + // TODO: Sledgehammer + + Add( new GenericBuyInfo( typeof( Shovel ), 12, 20, 0xF39, 0 ) ); + + Add( new GenericBuyInfo( typeof( MouldingPlane ), 11, 20, 0x102C, 0 ) ); + Add( new GenericBuyInfo( typeof( JointingPlane ), 10, 20, 0x1030, 0 ) ); + Add( new GenericBuyInfo( typeof( SmoothingPlane ), 11, 20, 0x1032, 0 ) ); + + Add( new GenericBuyInfo( typeof( Pickaxe ), 25, 20, 0xE86, 0 ) ); + + + Add( new GenericBuyInfo( typeof( Drums ), 21, 20, 0x0E9C, 0 ) ); + Add( new GenericBuyInfo( typeof( Tambourine ), 21, 20, 0x0E9E, 0 ) ); + Add( new GenericBuyInfo( typeof( LapHarp ), 21, 20, 0x0EB2, 0 ) ); + Add( new GenericBuyInfo( typeof( Lute ), 21, 20, 0x0EB3, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Drums ), 10 ); + Add( typeof( Tambourine ), 10 ); + Add( typeof( LapHarp ), 10 ); + Add( typeof( Lute ), 10 ); + + Add( typeof( Shovel ), 6 ); + Add( typeof( SewingKit ), 1 ); + Add( typeof( Scissors ), 6 ); + Add( typeof( Tongs ), 7 ); + Add( typeof( Key ), 1 ); + + Add( typeof( DovetailSaw ), 6 ); + Add( typeof( MouldingPlane ), 6 ); + Add( typeof( Nails ), 1 ); + Add( typeof( JointingPlane ), 6 ); + Add( typeof( SmoothingPlane ), 6 ); + Add( typeof( Saw ), 7 ); + + Add( typeof( Clock ), 11 ); + Add( typeof( ClockParts ), 1 ); + Add( typeof( AxleGears ), 1 ); + Add( typeof( Gears ), 1 ); + Add( typeof( Hinge ), 1 ); + Add( typeof( Sextant ), 6 ); + Add( typeof( SextantParts ), 2 ); + Add( typeof( Axle ), 1 ); + Add( typeof( Springs ), 1 ); + + Add( typeof( DrawKnife ), 5 ); + Add( typeof( Froe ), 5 ); + Add( typeof( Inshave ), 5 ); + Add( typeof( Scorp ), 5 ); + + Add( typeof( Lockpick ), 6 ); + Add( typeof( TinkerTools ), 3 ); + + Add( typeof( Board ), 1 ); + Add( typeof( Log ), 1 ); + + Add( typeof( Pickaxe ), 16 ); + Add( typeof( Hammer ), 3 ); + Add( typeof( SmithHammer ), 11 ); + Add( typeof( ButcherKnife ), 6 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBVagabond.cs b/Scripts/Mobiles/Vendors/SBInfo/SBVagabond.cs new file mode 100644 index 0000000..b9d53aa --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBVagabond.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBVagabond : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBVagabond() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( GoldRing ), 27, 20, 0x108A, 0 ) ); + Add( new GenericBuyInfo( typeof( Necklace ), 26, 20, 0x1085, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldNecklace ), 27, 20, 0x1088, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldBeadNecklace ), 27, 20, 0x1089, 0 ) ); + Add( new GenericBuyInfo( typeof( Beads ), 27, 20, 0x108B, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldBracelet ), 27, 20, 0x1086, 0 ) ); + Add( new GenericBuyInfo( typeof( GoldEarrings ), 27, 20, 0x1087, 0 ) ); + + Add( new GenericBuyInfo( typeof( Board ), 3, 20, 0x1BD7, 0 ) ); + Add( new GenericBuyInfo( typeof( IronIngot ), 6, 20, 0x1BF2, 0 ) ); + + Add( new GenericBuyInfo( typeof( StarSapphire ), 125, 20, 0xF21, 0 ) ); + Add( new GenericBuyInfo( typeof( Emerald ), 100, 20, 0xF10, 0 ) ); + Add( new GenericBuyInfo( typeof( Sapphire ), 100, 20, 0xF19, 0 ) ); + Add( new GenericBuyInfo( typeof( Ruby ), 75, 20, 0xF13, 0 ) ); + Add( new GenericBuyInfo( typeof( Citrine ), 50, 20, 0xF15, 0 ) ); + Add( new GenericBuyInfo( typeof( Amethyst ), 100, 20, 0xF16, 0 ) ); + Add( new GenericBuyInfo( typeof( Tourmaline ), 75, 20, 0xF2D, 0 ) ); + Add( new GenericBuyInfo( typeof( Amber ), 50, 20, 0xF25, 0 ) ); + Add( new GenericBuyInfo( typeof( Diamond ), 200, 20, 0xF26, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Board ), 1 ); + Add( typeof( IronIngot ), 3 ); + + Add( typeof( Amber ), 25 ); + Add( typeof( Amethyst ), 50 ); + Add( typeof( Citrine ), 25 ); + Add( typeof( Diamond ), 100 ); + Add( typeof( Emerald ), 50 ); + Add( typeof( Ruby ), 37 ); + Add( typeof( Sapphire ), 50 ); + Add( typeof( StarSapphire ), 62 ); + Add( typeof( Tourmaline ), 47 ); + Add( typeof( GoldRing ), 13 ); + Add( typeof( SilverRing ), 10 ); + Add( typeof( Necklace ), 13 ); + Add( typeof( GoldNecklace ), 13 ); + Add( typeof( GoldBeadNecklace ), 13 ); + Add( typeof( SilverNecklace ), 10 ); + Add( typeof( SilverBeadNecklace ), 10 ); + Add( typeof( Beads ), 13 ); + Add( typeof( GoldBracelet ), 13 ); + Add( typeof( SilverBracelet ), 10 ); + Add( typeof( GoldEarrings ), 13 ); + Add( typeof( SilverEarrings ), 10 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs b/Scripts/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs new file mode 100644 index 0000000..f816207 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBVarietyDealer.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBVarietyDealer : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBVarietyDealer() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bandage ), 5, 20, 0xE21, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 999, 0x0E34, 0 ) ); + + Add( new GenericBuyInfo( typeof( NightSightPotion ), 15, 10, 0xF06, 0 ) ); + Add( new GenericBuyInfo( typeof( AgilityPotion ), 15, 10, 0xF08, 0 ) ); + Add( new GenericBuyInfo( typeof( StrengthPotion ), 15, 10, 0xF09, 0 ) ); + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 10, 0xF0B, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserCurePotion ), 15, 10, 0xF07, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 10, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserPoisonPotion ), 15, 10, 0xF0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserExplosionPotion ), 21, 10, 0xF0D, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bolt ), 6, Utility.Random( 30, 60 ), 0x1BFB, 0 ) ); + Add( new GenericBuyInfo( typeof( Arrow ), 3, Utility.Random( 30, 60 ), 0xF3F, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlackPearl ), 5, 999, 0xF7A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 999, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 999, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( Garlic ), 3, 999, 0xF84, 0 ) ); + Add( new GenericBuyInfo( typeof( Ginseng ), 3, 999, 0xF85, 0 ) ); + Add( new GenericBuyInfo( typeof( Nightshade ), 3, 999, 0xF88, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 999, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 999, 0xF8C, 0 ) ); + + Add( new GenericBuyInfo( typeof( BreadLoaf ), 7, 10, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( Backpack ), 15, 20, 0x9B2, 0 ) ); + + Type[] types = Loot.RegularScrollTypes; + int circles = 3; + + for ( int i = 0; i < circles*8 && i < types.Length; ++i ) + { + int itemID = 0x1F2E + i; + + if ( i == 6 ) + itemID = 0x1F2D; + else if ( i > 6 ) + --itemID; + + Add( new GenericBuyInfo( types[i], 12 + ((i / 8) * 10), 20, itemID, 0 ) ); + } + + /*if ( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( BatWing ), 3, 999, 0xF78, 0 ) ); + Add( new GenericBuyInfo( typeof( GraveDust ), 3, 999, 0xF8F, 0 ) ); + Add( new GenericBuyInfo( typeof( DaemonBlood ), 6, 999, 0xF7D, 0 ) ); + Add( new GenericBuyInfo( typeof( NoxCrystal ), 6, 999, 0xF8E, 0 ) ); + Add( new GenericBuyInfo( typeof( PigIron ), 5, 999, 0xF8A, 0 ) ); + + Add( new GenericBuyInfo( typeof( NecromancerSpellbook ), 115, 10, 0x2253, 0 ) ); + }*/ + + Add( new GenericBuyInfo( typeof( RecallRune ), 15, 10, 0x1f14, 0 ) ); + Add( new GenericBuyInfo( typeof( Spellbook ), 18, 10, 0xEFA, 0 ) ); + + Add( new GenericBuyInfo( "1041072", typeof( MagicWizardsHat ), 11, 10, 0x1718, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bandage ), 1 ); + + Add( typeof( BlankScroll ), 5 ); // Scriptiz : 3 + + Add( typeof( NightSightPotion ), 7 ); + Add( typeof( AgilityPotion ), 7 ); + Add( typeof( StrengthPotion ), 7 ); + Add( typeof( RefreshPotion ), 7 ); + Add( typeof( LesserCurePotion ), 7 ); + Add( typeof( LesserHealPotion ), 7 ); + Add( typeof( LesserPoisonPotion ), 7 ); + Add( typeof( LesserExplosionPotion ), 10 ); + + Add( typeof( Bolt ), 3 ); + Add( typeof( Arrow ), 2 ); + + Add( typeof( BlackPearl ), 3 ); + Add( typeof( Bloodmoss ), 3 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( Garlic ), 2 ); + Add( typeof( Ginseng ), 2 ); + Add( typeof( Nightshade ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( SulfurousAsh ), 2 ); + + Add( typeof( BreadLoaf ), 3 ); + Add( typeof( Backpack ), 7 ); + Add( typeof( RecallRune ), 8 ); + Add( typeof( Spellbook ), 9 ); + Add( typeof( BlankScroll ), 3 ); // Scriptiz : 3 + + if ( Core.AOS ) + { + Add( typeof( BatWing ), 2 ); + Add( typeof( GraveDust ), 2 ); + Add( typeof( DaemonBlood ), 3 ); + Add( typeof( NoxCrystal ), 3 ); + Add( typeof( PigIron ), 3 ); + } + + Type[] types = Loot.RegularScrollTypes; + + for ( int i = 0; i < types.Length; ++i ) + Add( types[i], ((i / 8) + 2) * 5 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBVeterinarian.cs b/Scripts/Mobiles/Vendors/SBInfo/SBVeterinarian.cs new file mode 100644 index 0000000..86147f9 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBVeterinarian.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBVeterinarian : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBVeterinarian() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bandage ), 6, 20, 0xE21, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( PackHorse ), 616, 10, 291, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( PackLlama ), 523, 10, 292, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Dog ), 158, 10, 217, 0 ) ); + Add( new AnimalBuyInfo( 1, typeof( Cat ), 131, 10, 201, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bandage ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBWaiter.cs b/Scripts/Mobiles/Vendors/SBInfo/SBWaiter.cs new file mode 100644 index 0000000..514ce8c --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBWaiter.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWaiter : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBWaiter() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Ale, 7, 20, 0x99F, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Wine, 7, 20, 0x9C7, 0 ) ); + Add( new BeverageBuyInfo( typeof( BeverageBottle ), BeverageType.Liquor, 7, 20, 0x99B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Jug ), BeverageType.Cider, 13, 20, 0x9C8, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Milk, 56, 20, 0x9F0, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Ale, 88, 20, 0x1F95, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Cider, 88, 20, 0x1F97, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Liquor, 88, 20, 0x1F99, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Wine, 88, 20, 0x1F9B, 0 ) ); + Add( new BeverageBuyInfo( typeof( Pitcher ), BeverageType.Water, 88, 20, 0x1F9D, 0 ) ); + + Add( new GenericBuyInfo( typeof( BreadLoaf ), 6, 10, 0x103B, 0 ) ); + Add( new GenericBuyInfo( typeof( CheeseWheel ), 21, 10, 0x97E, 0 ) ); + Add( new GenericBuyInfo( typeof( CookedBird ), 17, 20, 0x9B7, 0 ) ); + Add( new GenericBuyInfo( typeof( LambLeg ), 8, 20, 0x160A, 0 ) ); + + Add( new GenericBuyInfo( typeof( WoodenBowlOfCarrots ), 3, 20, 0x15F9, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfCorn ), 3, 20, 0x15FA, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfLettuce ), 3, 20, 0x15FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfPeas ), 3, 20, 0x15FC, 0 ) ); + Add( new GenericBuyInfo( typeof( EmptyPewterBowl ), 2, 20, 0x15FD, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfCorn ), 3, 20, 0x15FE, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfLettuce ), 3, 20, 0x15FF, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPeas ), 3, 20, 0x1600, 0 ) ); + Add( new GenericBuyInfo( typeof( PewterBowlOfPotatos ), 3, 20, 0x1601, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfStew ), 3, 20, 0x1604, 0 ) ); + Add( new GenericBuyInfo( typeof( WoodenBowlOfTomatoSoup ), 3, 20, 0x1606, 0 ) ); + + Add( new GenericBuyInfo( typeof( ApplePie ), 7, 20, 0x1041, 0 ) ); //OSI just has Pie, not Apple/Fruit/Meat + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs b/Scripts/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs new file mode 100644 index 0000000..861dcc0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBWeaponSmith.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWeaponSmith: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBWeaponSmith() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BlackStaff ), 22, 20, 0xDF1, 0 ) ); + Add( new GenericBuyInfo( typeof( Club ), 16, 20, 0x13B4, 0 ) ); + Add( new GenericBuyInfo( typeof( GnarledStaff ), 16, 20, 0x13F8, 0 ) ); + Add( new GenericBuyInfo( typeof( Mace ), 28, 20, 0xF5C, 0 ) ); + Add( new GenericBuyInfo( typeof( Maul ), 21, 20, 0x143B, 0 ) ); + Add( new GenericBuyInfo( typeof( QuarterStaff ), 19, 20, 0xE89, 0 ) ); + Add( new GenericBuyInfo( typeof( ShepherdsCrook ), 20, 20, 0xE81, 0 ) ); + Add( new GenericBuyInfo( typeof( SmithHammer ), 21, 20, 0x13E3, 0 ) ); + Add( new GenericBuyInfo( typeof( ShortSpear ), 23, 20, 0x1403, 0 ) ); + Add( new GenericBuyInfo( typeof( Spear ), 31, 20, 0xF62, 0 ) ); + Add( new GenericBuyInfo( typeof( WarHammer ), 25, 20, 0x1439, 0 ) ); + Add( new GenericBuyInfo( typeof( WarMace ), 31, 20, 0x1407, 0 ) ); + + if( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( Scepter ), 39, 20, 0x26BC, 0 ) ); + Add( new GenericBuyInfo( typeof( BladedStaff ), 40, 20, 0x26BD, 0 ) ); + } + + Add( new GenericBuyInfo( typeof( Hatchet ), 25, 20, 0xF44, 0 ) ); + Add( new GenericBuyInfo( typeof( Hatchet ), 27, 20, 0xF43, 0 ) ); + Add( new GenericBuyInfo( typeof( WarFork ), 32, 20, 0x1405, 0 ) ); + + switch ( Utility.Random( 3 )) + { + case 0: + { + Add( new GenericBuyInfo( typeof( ExecutionersAxe ), 30, 20, 0xF45, 0 ) ); + Add( new GenericBuyInfo( typeof( Bardiche ), 60, 20, 0xF4D, 0 ) ); + Add( new GenericBuyInfo( typeof( BattleAxe ), 26, 20, 0xF47, 0 ) ); + Add( new GenericBuyInfo( typeof( TwoHandedAxe ), 32, 20, 0x1443, 0 ) ); + + Add( new GenericBuyInfo( typeof( Bow ), 35, 20, 0x13B2, 0 ) ); + + Add( new GenericBuyInfo( typeof( ButcherKnife ), 14, 20, 0x13F6, 0 ) ); + + Add( new GenericBuyInfo( typeof( Crossbow ), 46, 20, 0xF50, 0 ) ); + Add( new GenericBuyInfo( typeof( HeavyCrossbow ), 55, 20, 0x13FD, 0 ) ); + + Add( new GenericBuyInfo( typeof( Cutlass ), 24, 20, 0x1441, 0 ) ); + Add( new GenericBuyInfo( typeof( Dagger ), 21, 20, 0xF52, 0 ) ); + Add( new GenericBuyInfo( typeof( Halberd ), 42, 20, 0x143E, 0 ) ); + + Add( new GenericBuyInfo( typeof( HammerPick ), 26, 20, 0x143D, 0 ) ); + + Add( new GenericBuyInfo( typeof( Katana ), 33, 20, 0x13FF, 0 ) ); + Add( new GenericBuyInfo( typeof( Kryss ), 32, 20, 0x1401, 0 ) ); + Add( new GenericBuyInfo( typeof( Broadsword ), 35, 20, 0xF5E, 0 ) ); + Add( new GenericBuyInfo( typeof( Longsword ), 55, 20, 0xF61, 0 ) ); + Add( new GenericBuyInfo( typeof( ThinLongsword ), 27, 20, 0x13B8, 0 ) ); + Add( new GenericBuyInfo( typeof( VikingSword ), 55, 20, 0x13B9, 0 ) ); + + Add( new GenericBuyInfo( typeof( Cleaver ), 15, 20, 0xEC3, 0 ) ); + Add( new GenericBuyInfo( typeof( Axe ), 40, 20, 0xF49, 0 ) ); + Add( new GenericBuyInfo( typeof( DoubleAxe ), 52, 20, 0xF4B, 0 ) ); + Add( new GenericBuyInfo( typeof( Pickaxe ), 22, 20, 0xE86, 0 ) ); + + Add( new GenericBuyInfo( typeof( Pitchfork ), 19, 20, 0xE87, 0 ) ); + + Add( new GenericBuyInfo( typeof( Scimitar ), 36, 20, 0x13B6, 0 ) ); + + Add( new GenericBuyInfo( typeof( SkinningKnife ), 14, 20, 0xEC4, 0 ) ); + + Add( new GenericBuyInfo( typeof( LargeBattleAxe ), 33, 20, 0x13FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WarAxe ), 29, 20, 0x13B0, 0 ) ); + + if ( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( BoneHarvester ), 35, 20, 0x26BB, 0 ) ); + Add( new GenericBuyInfo( typeof( CrescentBlade ), 37, 20, 0x26C1, 0 ) ); + Add( new GenericBuyInfo( typeof( DoubleBladedStaff ), 35, 20, 0x26BF, 0 ) ); + Add( new GenericBuyInfo( typeof( Lance ), 34, 20, 0x26C0, 0 ) ); + Add( new GenericBuyInfo( typeof( Pike ), 39, 20, 0x26BE, 0 ) ); + Add( new GenericBuyInfo( typeof( Scythe ), 39, 20, 0x26BA, 0 ) ); + Add( new GenericBuyInfo( typeof( CompositeBow ), 50, 20, 0x26C2, 0 ) ); + Add( new GenericBuyInfo( typeof( RepeatingCrossbow ), 57, 20, 0x26C3, 0 ) ); + } + + break; + } + + } + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BattleAxe ), 13 ); + Add( typeof( DoubleAxe ), 26 ); + Add( typeof( ExecutionersAxe ), 15 ); + Add( typeof( LargeBattleAxe ),16 ); + Add( typeof( Pickaxe ), 11 ); + Add( typeof( TwoHandedAxe ), 16 ); + Add( typeof( WarAxe ), 14 ); + Add( typeof( Axe ), 20 ); + + Add( typeof( Bardiche ), 30 ); + Add( typeof( Halberd ), 21 ); + + Add( typeof( ButcherKnife ), 7 ); + Add( typeof( Cleaver ), 7 ); + Add( typeof( Dagger ), 10 ); + Add( typeof( SkinningKnife ), 7 ); + + Add( typeof( Club ), 8 ); + Add( typeof( HammerPick ), 13 ); + Add( typeof( Mace ), 14 ); + Add( typeof( Maul ), 10 ); + Add( typeof( WarHammer ), 12 ); + Add( typeof( WarMace ), 15 ); + + Add( typeof( HeavyCrossbow ), 27 ); + Add( typeof( Bow ), 17 ); + Add( typeof( Crossbow ), 23 ); + + if( Core.AOS ) + { + Add( typeof( CompositeBow ), 25 ); + Add( typeof( RepeatingCrossbow ), 28 ); + Add( typeof( Scepter ), 20 ); + Add( typeof( BladedStaff ), 20 ); + Add( typeof( Scythe ), 19 ); + Add( typeof( BoneHarvester ), 17 ); + Add( typeof( Scepter ), 18 ); + Add( typeof( BladedStaff ), 16 ); + Add( typeof( Pike ), 19 ); + Add( typeof( DoubleBladedStaff ), 17 ); + Add( typeof( Lance ), 17 ); + Add( typeof( CrescentBlade ), 18 ); + } + + Add( typeof( Spear ), 15 ); + Add( typeof( Pitchfork ), 9 ); + Add( typeof( ShortSpear ), 11 ); + + Add( typeof( BlackStaff ), 11 ); + Add( typeof( GnarledStaff ), 8 ); + Add( typeof( QuarterStaff ), 9 ); + Add( typeof( ShepherdsCrook ), 10 ); + + Add( typeof( SmithHammer ), 10 ); + + Add( typeof( Broadsword ), 17 ); + Add( typeof( Cutlass ), 12 ); + Add( typeof( Katana ), 16 ); + Add( typeof( Kryss ), 16 ); + Add( typeof( Longsword ), 27 ); + Add( typeof( Scimitar ), 18 ); + Add( typeof( ThinLongsword ), 13 ); + Add( typeof( VikingSword ), 27 ); + + Add( typeof( Hatchet ), 13 ); + Add( typeof( WarFork ), 16 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/SBWeaver.cs b/Scripts/Mobiles/Vendors/SBInfo/SBWeaver.cs new file mode 100644 index 0000000..19c5456 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SBWeaver.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBWeaver: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBWeaver() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Dyes ), 8, 20, 0xFA9, 0 ) ); + Add( new GenericBuyInfo( typeof( DyeTub ), 8, 20, 0xFAB, 0 ) ); + + Add( new GenericBuyInfo( typeof( UncutCloth ), 3, 20, 0x1761, 0 ) ); + Add( new GenericBuyInfo( typeof( UncutCloth ), 3, 20, 0x1762, 0 ) ); + Add( new GenericBuyInfo( typeof( UncutCloth ), 3, 20, 0x1763, 0 ) ); + Add( new GenericBuyInfo( typeof( UncutCloth ), 3, 20, 0x1764, 0 ) ); + + Add( new GenericBuyInfo( typeof( BoltOfCloth ), 100, 20, 0xf9B, 0 ) ); + Add( new GenericBuyInfo( typeof( BoltOfCloth ), 100, 20, 0xf9C, 0 ) ); + Add( new GenericBuyInfo( typeof( BoltOfCloth ), 100, 20, 0xf96, 0 ) ); + Add( new GenericBuyInfo( typeof( BoltOfCloth ), 100, 20, 0xf97, 0 ) ); + + Add( new GenericBuyInfo( typeof( DarkYarn ), 18, 20, 0xE1D, 0 ) ); + Add( new GenericBuyInfo( typeof( LightYarn ), 18, 20, 0xE1E, 0 ) ); + Add( new GenericBuyInfo( typeof( LightYarnUnraveled ), 18, 20, 0xE1F, 0 ) ); + + Add( new GenericBuyInfo( typeof( Scissors ), 11, 20, 0xF9F, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Scissors ), 6 ); + Add( typeof( Dyes ), 4 ); + Add( typeof( DyeTub ), 4 ); + Add( typeof( UncutCloth ), 1 ); + Add( typeof( BoltOfCloth ), 50 ); + Add( typeof( LightYarnUnraveled ), 9 ); + Add( typeof( LightYarn ), 9 ); + Add( typeof( DarkYarn ), 9 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs new file mode 100644 index 0000000..839e9f0 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEArmor.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSEArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( PlateHatsuburi ), 76, 20, 0x2775, 0 ) ); + Add( new GenericBuyInfo( typeof( HeavyPlateJingasa ), 76, 20, 0x2777, 0 ) ); + Add( new GenericBuyInfo( typeof( DecorativePlateKabuto ), 95, 20, 0x2778, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateDo ), 310, 20, 0x277D, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateHiroSode ), 222, 20, 0x2780, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateSuneate ), 224, 20, 0x2788, 0 ) ); + Add( new GenericBuyInfo( typeof( PlateHaidate ), 235, 20, 0x278D, 0 ) ); + Add( new GenericBuyInfo( typeof( ChainHatsuburi ), 76, 20, 0x2774, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( PlateHatsuburi ), 38 ); + Add( typeof( HeavyPlateJingasa ), 38 ); + Add( typeof( DecorativePlateKabuto ), 47 ); + Add( typeof( PlateDo ), 155 ); + Add( typeof( PlateHiroSode ), 111 ); + Add( typeof( PlateSuneate ), 112 ); + Add( typeof( PlateHaidate), 117 ); + Add( typeof( ChainHatsuburi ), 38 ); + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs new file mode 100644 index 0000000..d05e285 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEBowyer.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEBowyer: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSEBowyer() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Yumi ), 53, 20, 0x27A5, 0 ) ); + Add( new GenericBuyInfo( typeof( Fukiya ), 20, 20, 0x27AA, 0 ) ); + Add( new GenericBuyInfo( typeof( Nunchaku ), 35, 20, 0x27AE, 0 ) ); + Add( new GenericBuyInfo( typeof( FukiyaDarts ), 3, 20, 0x2806, 0 ) ); + Add( new GenericBuyInfo( typeof( Bokuto ), 21, 20, 0x27A8, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Yumi ), 26 ); + Add( typeof( Fukiya ), 10 ); + Add( typeof( Nunchaku ), 17 ); + Add( typeof( FukiyaDarts ), 1 ); + Add( typeof( Bokuto ), 10 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs new file mode 100644 index 0000000..f2ea2e6 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSECarpenter.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSECarpenter: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSECarpenter() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bokuto ), 21, 20, 0x27A8, 0 ) ); + Add( new GenericBuyInfo( typeof( Tetsubo ), 43, 20, 0x27A6, 0 ) ); + Add( new GenericBuyInfo( typeof( Fukiya ), 20, 20, 0x27AA, 0 ) ); + Add( new GenericBuyInfo( typeof( BambooFlute ), 21, 20, 0x2805, 0 ) ); + Add( new GenericBuyInfo( typeof( BambooFlute ), 21, 20, 0x2805, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Tetsubo ), 21 ); + Add( typeof( Fukiya ), 10 ); + Add( typeof( BambooFlute ), 10 ); + Add( typeof( Bokuto ), 10 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs new file mode 100644 index 0000000..f05441b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEFood.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEFood: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSEFood() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E8, 0 ) ); + Add( new GenericBuyInfo( typeof( Wasabi ), 2, 20, 0x24E9, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2836, 0 ) ); + Add( new GenericBuyInfo( typeof( BentoBox ), 6, 20, 0x2837, 0 ) ); + Add( new GenericBuyInfo( typeof( GreenTeaBasket ), 2, 20, 0x284B, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Wasabi ), 1 ); + Add( typeof( BentoBox ), 3 ); + Add( typeof( GreenTeaBasket ), 1 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs new file mode 100644 index 0000000..956480f --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSELeatherArmor.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSELeatherArmor: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSELeatherArmor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( LeatherJingasa ), 11, 20, 0x2776, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherDo ), 87, 20, 0x277B, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherHiroSode ), 49, 20, 0x277E, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherSuneate ), 55, 20, 0x2786, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherHaidate), 54, 20, 0x278A, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherNinjaPants ), 49, 20, 0x2791, 0 ) ); + Add( new GenericBuyInfo( typeof( LeatherNinjaJacket ), 51, 20, 0x2793, 0 ) ); + + Add( new GenericBuyInfo( typeof( StuddedMempo ), 61, 20, 0x279D, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedDo ), 130, 20, 0x277C, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedHiroSode ), 73, 20, 0x277F, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedSuneate ), 78, 20, 0x2787, 0 ) ); + Add( new GenericBuyInfo( typeof( StuddedHaidate ), 76, 20, 0x278B, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( LeatherJingasa ), 5 ); + Add( typeof( LeatherDo ), 42 ); + Add( typeof( LeatherHiroSode ), 23 ); + Add( typeof( LeatherSuneate ), 26 ); + Add( typeof( LeatherHaidate), 28 ); + Add( typeof( LeatherNinjaPants ), 25 ); + Add( typeof( LeatherNinjaJacket ), 26 ); + Add( typeof( StuddedMempo ), 28 ); + Add( typeof( StuddedDo ), 66 ); + Add( typeof( StuddedHiroSode ), 32 ); + Add( typeof( StuddedSuneate ), 40 ); + Add( typeof( StuddedHaidate ), 37 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs new file mode 100644 index 0000000..b5ba996 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/SE/SBSEWeapons.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSEWeapons: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSEWeapons() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( NoDachi ), 82, 20, 0x27A2, 0 ) ); + Add( new GenericBuyInfo( typeof( Tessen ), 83, 20, 0x27A3, 0 ) ); + Add( new GenericBuyInfo( typeof( Wakizashi ), 38, 20, 0x27A4, 0 ) ); + Add( new GenericBuyInfo( typeof( Tetsubo ), 43, 20, 0x27A6, 0 ) ); + Add( new GenericBuyInfo( typeof( Lajatang ), 108, 20, 0x27A7, 0 ) ); + Add( new GenericBuyInfo( typeof( Daisho ), 66, 20, 0x27A9, 0 ) ); + Add( new GenericBuyInfo( typeof( Tekagi ), 55, 20, 0x27AB, 0 ) ); + Add( new GenericBuyInfo( typeof( Shuriken ), 18, 20, 0x27AC, 0 ) ); + Add( new GenericBuyInfo( typeof( Kama ), 61, 20, 0x27AD, 0 ) ); + Add( new GenericBuyInfo( typeof( Sai ), 56, 20, 0x27AF, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( NoDachi ), 41 ); + Add( typeof( Tessen ), 41 ); + Add( typeof( Wakizashi ), 19 ); + Add( typeof( Tetsubo ), 21 ); + Add( typeof( Lajatang ), 54 ); + Add( typeof( Daisho ), 33 ); + Add( typeof( Tekagi ), 22 ); + Add( typeof( Shuriken), 9 ); + Add( typeof( Kama ), 30 ); + Add( typeof( Sai ), 28 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs new file mode 100644 index 0000000..31f160b --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBAxeWeapon.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBAxeWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBAxeWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( ExecutionersAxe ), 30, 20, 0xF45, 0 ) ); + Add( new GenericBuyInfo( typeof( BattleAxe ), 26, 20, 0xF47, 0 ) ); + Add( new GenericBuyInfo( typeof( TwoHandedAxe ), 32, 20, 0x1443, 0 ) ); + Add( new GenericBuyInfo( typeof( Axe ), 40, 20, 0xF49, 0 ) ); + Add( new GenericBuyInfo( typeof( DoubleAxe ), 52, 20, 0xF4B, 0 ) ); + Add( new GenericBuyInfo( typeof( Pickaxe ), 22, 20, 0xE86, 0 ) ); + Add( new GenericBuyInfo( typeof( LargeBattleAxe ), 33, 20, 0x13FB, 0 ) ); + Add( new GenericBuyInfo( typeof( WarAxe ), 29, 20, 0x13B0, 0 ) ); + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BattleAxe ), 13 ); + Add( typeof( DoubleAxe ), 26 ); + Add( typeof( ExecutionersAxe ), 15 ); + Add( typeof( LargeBattleAxe ),16 ); + Add( typeof( Pickaxe ), 11 ); + Add( typeof( TwoHandedAxe ), 16 ); + Add( typeof( WarAxe ), 14 ); + Add( typeof( Axe ), 20 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs new file mode 100644 index 0000000..b573042 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBKnifeWeapon.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBKnifeWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBKnifeWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( ButcherKnife ), 14, 20, 0x13F6, 0 ) ); + Add( new GenericBuyInfo( typeof( Dagger ), 21, 20, 0xF52, 0 ) ); + Add( new GenericBuyInfo( typeof( Cleaver ), 15, 20, 0xEC3, 0 ) ); + Add( new GenericBuyInfo( typeof( SkinningKnife ), 14, 20, 0xEC4, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( ButcherKnife ), 7 ); + Add( typeof( Cleaver ), 7 ); + Add( typeof( Dagger ), 10 ); + Add( typeof( SkinningKnife ), 7 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs new file mode 100644 index 0000000..c9d07e7 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBMaceWeapon.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBMaceWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBMaceWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( HammerPick ), 26, 20, 0x143D, 0 ) ); + Add( new GenericBuyInfo( typeof( Club ), 16, 20, 0x13B4, 0 ) ); + Add( new GenericBuyInfo( typeof( Mace ), 28, 20, 0xF5C, 0 ) ); + Add( new GenericBuyInfo( typeof( Maul ), 21, 20, 0x143B, 0 ) ); + Add( new GenericBuyInfo( typeof( WarHammer ), 25, 20, 0x1439, 0 ) ); + Add( new GenericBuyInfo( typeof( WarMace ), 31, 20, 0x1407, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Club ), 8 ); + Add( typeof( HammerPick ), 13 ); + Add( typeof( Mace ), 14 ); + Add( typeof( Maul ), 10 ); + Add( typeof( WarHammer ), 12 ); + Add( typeof( WarMace ), 15 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs new file mode 100644 index 0000000..cd87bb5 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBPoleArmWeapon.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPoleArmWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBPoleArmWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Bardiche ), 60, 20, 0xF4D, 0 ) ); + Add( new GenericBuyInfo( typeof( Halberd ), 42, 20, 0x143E, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bardiche ), 30 ); + Add( typeof( Halberd ), 21 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs new file mode 100644 index 0000000..c494ae3 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBRangedWeapon.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBRangedWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBRangedWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Crossbow ), 55, 20, 0xF50, 0 ) ); + Add( new GenericBuyInfo( typeof( HeavyCrossbow ), 55, 20, 0x13FD, 0 ) ); + if( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( RepeatingCrossbow ), 46, 20, 0x26C3, 0 ) ); + Add( new GenericBuyInfo( typeof( CompositeBow ), 45, 20, 0x26C2, 0 ) ); + } + Add( new GenericBuyInfo( typeof( Bolt ), 2, Utility.Random( 30, 60 ), 0x1BFB, 0 ) ); + Add( new GenericBuyInfo( typeof( Bow ), 40, 20, 0x13B2, 0 ) ); + Add( new GenericBuyInfo( typeof( Arrow ), 2, Utility.Random( 30, 60 ), 0xF3F, 0 ) ); + Add( new GenericBuyInfo( typeof( Feather ), 2, Utility.Random( 30, 60 ), 0x1BD1, 0 ) ); + Add( new GenericBuyInfo( typeof( Shaft ), 3, Utility.Random( 30, 60 ), 0x1BD4, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Bolt ), 1 ); + Add( typeof( Arrow ), 1 ); + Add( typeof( Shaft ), 1 ); + Add( typeof( Feather ), 1 ); + + Add( typeof( HeavyCrossbow ), 27 ); + Add( typeof( Bow ), 17 ); + Add( typeof( Crossbow ), 25 ); + + if( Core.AOS ) + { + Add( typeof( CompositeBow ), 23 ); + Add( typeof( RepeatingCrossbow ), 22 ); + } + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs new file mode 100644 index 0000000..0e44e2f --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBSpearForkWeapon.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSpearForkWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSpearForkWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Pitchfork ), 19, 20, 0xE87, 0 ) ); + Add( new GenericBuyInfo( typeof( ShortSpear ), 23, 20, 0x1403, 0 ) ); + Add( new GenericBuyInfo( typeof( Spear ), 31, 20, 0xF62, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Spear ), 15 ); + Add( typeof( Pitchfork ), 9 ); + Add( typeof( ShortSpear ), 11 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs new file mode 100644 index 0000000..255f773 --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBStavesWeapon.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBStavesWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBStavesWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( BlackStaff ), 22, 20, 0xDF1, 0 ) ); + Add( new GenericBuyInfo( typeof( GnarledStaff ), 16, 20, 0x13F8, 0 ) ); + Add( new GenericBuyInfo( typeof( QuarterStaff ), 19, 20, 0xE89, 0 ) ); + Add( new GenericBuyInfo( typeof( ShepherdsCrook ), 20, 20, 0xE81, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( BlackStaff ), 11 ); + Add( typeof( GnarledStaff ), 8 ); + Add( typeof( QuarterStaff ), 9 ); + Add( typeof( ShepherdsCrook ), 10 ); + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs new file mode 100644 index 0000000..943db5a --- /dev/null +++ b/Scripts/Mobiles/Vendors/SBInfo/Weapons/SBSwordWeapon.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBSwordWeapon: SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBSwordWeapon() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( typeof( Cutlass ), 24, 20, 0x1441, 0 ) ); + Add( new GenericBuyInfo( typeof( Katana ), 33, 20, 0x13FF, 0 ) ); + Add( new GenericBuyInfo( typeof( Kryss ), 32, 20, 0x1401, 0 ) ); + Add( new GenericBuyInfo( typeof( Broadsword ), 35, 20, 0xF5E, 0 ) ); + Add( new GenericBuyInfo( typeof( Longsword ), 55, 20, 0xF61, 0 ) ); + Add( new GenericBuyInfo( typeof( ThinLongsword ), 27, 20, 0x13B8, 0 ) ); + Add( new GenericBuyInfo( typeof( VikingSword ), 55, 20, 0x13B9, 0 ) ); + Add( new GenericBuyInfo( typeof( Scimitar ), 36, 20, 0x13B6, 0 ) ); + + if ( Core.AOS ) + { + Add( new GenericBuyInfo( typeof( BoneHarvester ), 35, 20, 0x26BB, 0 ) ); + Add( new GenericBuyInfo( typeof( CrescentBlade ), 37, 20, 0x26C1, 0 ) ); + Add( new GenericBuyInfo( typeof( DoubleBladedStaff ), 35, 20, 0x26BF, 0 ) ); + Add( new GenericBuyInfo( typeof( Lance ), 34, 20, 0x26C0, 0 ) ); + Add( new GenericBuyInfo( typeof( Pike ), 39, 20, 0x26BE, 0 ) ); + Add( new GenericBuyInfo( typeof( Scythe ), 39, 20, 0x26BA, 0 ) ); + } + + + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Broadsword ), 17 ); + Add( typeof( Cutlass ), 12 ); + Add( typeof( Katana ), 16 ); + Add( typeof( Kryss ), 16 ); + Add( typeof( Longsword ), 27 ); + Add( typeof( Scimitar ), 18 ); + Add( typeof( ThinLongsword ), 13 ); + Add( typeof( VikingSword ), 27 ); + + if ( Core.AOS ) + { + Add( typeof( Scythe ), 19 ); + Add( typeof( BoneHarvester ), 17 ); + Add( typeof( Scepter ), 18 ); + Add( typeof( BladedStaff ), 16 ); + Add( typeof( Pike ), 19 ); + Add( typeof( DoubleBladedStaff ), 17 ); + Add( typeof( Lance ), 17 ); + Add( typeof( CrescentBlade ), 18 ); + } + } + } + } +} diff --git a/Scripts/Mobiles/Vendors/VendorInventory.cs b/Scripts/Mobiles/Vendors/VendorInventory.cs new file mode 100644 index 0000000..ebc4bd4 --- /dev/null +++ b/Scripts/Mobiles/Vendors/VendorInventory.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; + +namespace Server.Mobiles +{ + public class VendorInventory + { + public static readonly TimeSpan GracePeriod = TimeSpan.FromDays( 7.0 ); + + private BaseHouse m_House; + private string m_VendorName; + private string m_ShopName; + private Mobile m_Owner; + + private List m_Items; + private int m_Gold; + + private DateTime m_ExpireTime; + private Timer m_ExpireTimer; + + public VendorInventory( BaseHouse house, Mobile owner, string vendorName, string shopName ) + { + m_House = house; + m_Owner = owner; + m_VendorName = vendorName; + m_ShopName = shopName; + + m_Items = new List(); + + m_ExpireTime = DateTime.Now + GracePeriod; + m_ExpireTimer = new ExpireTimer( this, GracePeriod ); + m_ExpireTimer.Start(); + } + + public BaseHouse House + { + get{ return m_House; } + set{ m_House = value; } + } + + public string VendorName + { + get{ return m_VendorName; } + set{ m_VendorName = value; } + } + + public string ShopName + { + get{ return m_ShopName; } + set{ m_ShopName = value; } + } + + public Mobile Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + public List Items + { + get{ return m_Items; } + } + + public int Gold + { + get{ return m_Gold; } + set{ m_Gold = value; } + } + + public DateTime ExpireTime + { + get{ return m_ExpireTime; } + } + + public void AddItem( Item item ) + { + item.Internalize(); + m_Items.Add( item ); + } + + public void Delete() + { + foreach ( Item item in Items ) + { + item.Delete(); + } + + Items.Clear(); + Gold = 0; + + if ( House != null ) + House.VendorInventories.Remove( this ); + + m_ExpireTimer.Stop(); + } + + public void Serialize( GenericWriter writer ) + { + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (Mobile) m_Owner ); + writer.Write( (string) m_VendorName ); + writer.Write( (string) m_ShopName ); + + writer.Write( m_Items, true ); + writer.Write( (int) m_Gold ); + + writer.WriteDeltaTime( m_ExpireTime ); + } + + public VendorInventory( BaseHouse house, GenericReader reader ) + { + m_House = house; + + int version = reader.ReadEncodedInt(); + + m_Owner = reader.ReadMobile(); + m_VendorName = reader.ReadString(); + m_ShopName = reader.ReadString(); + + m_Items = reader.ReadStrongItemList(); + m_Gold = reader.ReadInt(); + + m_ExpireTime = reader.ReadDeltaTime(); + + if ( m_Items.Count == 0 && m_Gold == 0 ) + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Delete ) ); + } + else + { + TimeSpan delay = m_ExpireTime - DateTime.Now; + m_ExpireTimer = new ExpireTimer( this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero ); + m_ExpireTimer.Start(); + } + } + + private class ExpireTimer : Timer + { + private VendorInventory m_Inventory; + + public ExpireTimer( VendorInventory inventory, TimeSpan delay ) : base( delay ) + { + m_Inventory = inventory; + + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + BaseHouse house = m_Inventory.House; + + if ( house != null ) + { + if ( m_Inventory.Gold > 0 ) + { + if ( house.MovingCrate == null ) + house.MovingCrate = new MovingCrate( house ); + + Banker.Deposit( house.MovingCrate, m_Inventory.Gold ); + } + + foreach ( Item item in m_Inventory.Items ) + { + if ( !item.Deleted ) + house.DropToMovingCrate( item ); + } + + m_Inventory.Gold = 0; + m_Inventory.Items.Clear(); + } + + m_Inventory.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/BaseHouse.cs b/Scripts/Multis/BaseHouse.cs new file mode 100644 index 0000000..4eb6d8b --- /dev/null +++ b/Scripts/Multis/BaseHouse.cs @@ -0,0 +1,3959 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Misc; +using Server.Mobiles; +using Server.Multis.Deeds; +using Server.Regions; +using Server.Network; +using Server.Targeting; +using Server.Accounting; +using Server.ContextMenus; +using Server.Gumps; +using Server.Guilds; +using Server.Engines.BulkOrders; + +namespace Server.Multis +{ + public abstract class BaseHouse : BaseMulti + { + public static bool NewVendorSystem{ get{ return Core.AOS; } } // Is new player vendor system enabled? + + public const int MaxCoOwners = 15; + public static int MaxFriends { get { return !Core.AOS ? 50 : 140; } } + public static int MaxBans { get { return !Core.AOS ? 50 : 140; } } + + #region Dynamic decay system + private DecayLevel m_CurrentStage; + private DateTime m_NextDecayStage; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextDecayStage + { + get { return m_NextDecayStage; } + set { m_NextDecayStage = value; } + } + + public void ResetDynamicDecay() + { + m_CurrentStage = DecayLevel.Ageless; + m_NextDecayStage = DateTime.MinValue; + } + + public void SetDynamicDecay(DecayLevel level) + { + m_CurrentStage = level; + + if (DynamicDecay.Decays(level)) + m_NextDecayStage = DateTime.Now + DynamicDecay.GetRandomDuration(level); + else + m_NextDecayStage = DateTime.MinValue; + } + #endregion + + public const bool DecayEnabled = false; // Scriptiz : on r�activera pour si + de 5 maisons ! + + public static void Decay_OnTick() + { + for ( int i = 0; i < m_AllHouses.Count; ++i ) + m_AllHouses[i].CheckDecay(); + } + + private DateTime m_LastRefreshed; + private bool m_RestrictDecay; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastRefreshed + { + get{ return m_LastRefreshed; } + set{ m_LastRefreshed = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RestrictDecay + { + get{ return m_RestrictDecay; } + set{ m_RestrictDecay = value; } + } + + public virtual TimeSpan DecayPeriod{ get{ return TimeSpan.FromDays( 31.0 ); } } // Scriptiz : default = 5 days + + [CommandProperty(AccessLevel.GameMaster)] + public virtual DecayType DecayType + { + get + { + // Scriptiz : les maisons sur des copies de Trammel et Felucca ne decay pas ! + if (this.Map.MapID >= 6) + return DecayType.Ageless; + + if (m_RestrictDecay || !DecayEnabled || DecayPeriod == TimeSpan.Zero) + return DecayType.Ageless; + + if (m_Owner == null) + return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh; + + Account acct = m_Owner.Account as Account; + + if (acct == null) + return Core.AOS ? DecayType.Condemned : DecayType.ManualRefresh; + + if (acct.AccessLevel >= AccessLevel.GameMaster) + return DecayType.Ageless; + + for (int i = 0; i < acct.Length; ++i) + { + Mobile mob = acct[i]; + + if (mob != null && mob.AccessLevel >= AccessLevel.GameMaster) + return DecayType.Ageless; + } + + if (!Core.AOS) + return DecayType.ManualRefresh; + + if (acct.Inactive) + return DecayType.Condemned; + + List allHouses = new List(); + + for (int i = 0; i < acct.Length; ++i) + { + Mobile mob = acct[i]; + + if (mob != null) + allHouses.AddRange(GetHouses(mob)); + } + + //BaseHouse newest = null; + + //for (int i = 0; i < allHouses.Count; ++i) + //{ + // BaseHouse check = allHouses[i]; + + // if (newest == null || IsNewer(check, newest)) + // newest = check; + //} + + //if (this == newest) + // return DecayType.AutoRefresh; + + // Scriptiz : c'est d�sormais la maison la plus vieille qui est auto-refresh + BaseHouse oldest = null; + + for (int i = 0; i < allHouses.Count; ++i) + { + BaseHouse check = allHouses[i]; + + if (oldest == null || IsOlder(check, oldest)) + oldest = check; + } + + if (this == oldest) + return DecayType.AutoRefresh; + // Scriptiz : fin changement oldest au lieu de newest + + return DecayType.ManualRefresh; + } + } + + public bool IsNewer( BaseHouse check, BaseHouse house ) + { + DateTime checkTime = ( check.LastTraded > check.BuiltOn ? check.LastTraded : check.BuiltOn ); + DateTime houseTime = ( house.LastTraded > house.BuiltOn ? house.LastTraded : house.BuiltOn ); + + return ( checkTime > houseTime ); + } + + // Scriptiz : oldest house (build time) DecayType is AutoRefresh instead of the newest house ! + public bool IsOlder(BaseHouse check, BaseHouse house) + { + DateTime checkTime = (check.LastTraded > check.BuiltOn ? check.LastTraded : check.BuiltOn); + DateTime houseTime = (house.LastTraded > house.BuiltOn ? house.LastTraded : house.BuiltOn); + + return (checkTime < houseTime); + } + + public virtual bool CanDecay + { + get + { + DecayType type = this.DecayType; + + return ( type == DecayType.Condemned || type == DecayType.ManualRefresh ); + } + } + + private DecayLevel m_LastDecayLevel; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual DecayLevel DecayLevel + { + get + { + DecayLevel result; + + if (!CanDecay) + { + if (DynamicDecay.Enabled) + ResetDynamicDecay(); + + m_LastRefreshed = DateTime.Now; + result = DecayLevel.Ageless; + } + else if (DynamicDecay.Enabled) + { + DecayLevel stage = m_CurrentStage; + + if (stage == DecayLevel.Ageless || (DynamicDecay.Decays(stage) && m_NextDecayStage <= DateTime.Now)) + SetDynamicDecay(++stage); + + if (stage == DecayLevel.Collapsed && (HasRentedVendors || VendorInventories.Count > 0)) + result = DecayLevel.DemolitionPending; + else + result = stage; + } + else + { + result = GetOldDecayLevel(); + } + + if (result != m_LastDecayLevel) + { + m_LastDecayLevel = result; + + if (m_Sign != null && !m_Sign.GettingProperties) + m_Sign.InvalidateProperties(); + } + + return result; + } + } + + public DecayLevel GetOldDecayLevel() + { + TimeSpan timeAfterRefresh = DateTime.Now - m_LastRefreshed; + int percent = (int)((timeAfterRefresh.Ticks * 1000) / DecayPeriod.Ticks); + + if (percent >= 1000) // 100.0% + return (HasRentedVendors || VendorInventories.Count > 0) ? DecayLevel.DemolitionPending : DecayLevel.Collapsed; + else if (percent >= 950) // 95.0% - 99.9% + return DecayLevel.IDOC; + else if (percent >= 750) // 75.0% - 94.9% + return DecayLevel.Greatly; + else if (percent >= 500) // 50.0% - 74.9% + return DecayLevel.Fairly; + else if (percent >= 250) // 25.0% - 49.9% + return DecayLevel.Somewhat; + else if (percent >= 005) // 00.5% - 24.9% + return DecayLevel.Slightly; + + return DecayLevel.LikeNew; + } + + public virtual bool RefreshDecay() + { + if (DecayType == DecayType.Condemned) + return false; + + DecayLevel oldLevel = this.DecayLevel; + + m_LastRefreshed = DateTime.Now; + + if (DynamicDecay.Enabled) + ResetDynamicDecay(); + + if (m_Sign != null) + m_Sign.InvalidateProperties(); + + return (oldLevel > DecayLevel.LikeNew); + } + + public virtual bool CheckDecay() + { + if ( !Deleted && this.DecayLevel == DecayLevel.Collapsed ) + { + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Decay_Sandbox ) ); + return true; + } + + return false; + } + + public virtual void KillVendors() + { + ArrayList list = new ArrayList( PlayerVendors ); + + foreach ( PlayerVendor vendor in list ) + vendor.Destroy( true ); + + list = new ArrayList( PlayerBarkeepers ); + + foreach ( PlayerBarkeeper barkeeper in list ) + barkeeper.Delete(); + } + + public virtual void Decay_Sandbox() + { + if ( Deleted ) + return; + + if ( Core.ML ) + new TempNoHousingRegion( this, null ); + + KillVendors(); + Delete(); + } + + public virtual TimeSpan RestrictedPlacingTime { get { return TimeSpan.FromHours( 1.0 ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual double BonusStorageScalar { get { return (Core.ML ? 1.2 : 1.0); } } + + private bool m_Public; + + private HouseRegion m_Region; + private HouseSign m_Sign; + private TrashBarrel m_Trash; + private ArrayList m_Doors; + + private Mobile m_Owner; + + private ArrayList m_Access; + private ArrayList m_Bans; + private ArrayList m_CoOwners; + private ArrayList m_Friends; + + private ArrayList m_PlayerVendors = new ArrayList(); + private ArrayList m_PlayerBarkeepers = new ArrayList(); + + private ArrayList m_LockDowns; + private ArrayList m_VendorRentalContracts; + private ArrayList m_Secures; + + private ArrayList m_Addons; + + private ArrayList m_VendorInventories = new ArrayList(); + private ArrayList m_RelocatedEntities = new ArrayList(); + + private MovingCrate m_MovingCrate; + private ArrayList m_InternalizedVendors; + + private int m_MaxLockDowns; + private int m_MaxSecures; + private int m_Price; + + private int m_Visits; + + private DateTime m_BuiltOn, m_LastTraded; + + private Point3D m_RelativeBanLocation; + + private static Dictionary> m_Table = new Dictionary>(); + + public virtual bool IsAosRules{ get{ return Core.AOS; } } + + public virtual bool IsActive{ get{ return true; } } + + public virtual HousePlacementEntry GetAosEntry() + { + return HousePlacementEntry.Find( this ); + } + + public virtual int GetAosMaxSecures() + { + HousePlacementEntry hpe = GetAosEntry(); + + if ( hpe == null ) + return 0; + + return (int)(hpe.Storage * BonusStorageScalar); + } + + public virtual int GetAosMaxLockdowns() + { + HousePlacementEntry hpe = GetAosEntry(); + + if ( hpe == null ) + return 0; + + return (int)(hpe.Lockdowns * BonusStorageScalar); + } + + public virtual int GetAosCurSecures( out int fromSecures, out int fromVendors, out int fromLockdowns, out int fromMovingCrate ) + { + fromSecures = 0; + fromVendors = 0; + fromLockdowns = 0; + fromMovingCrate = 0; + + ArrayList list = m_Secures; + + if ( list != null ) + { + for ( int i = 0; i < list.Count; ++i ) + { + SecureInfo si = (SecureInfo)list[i]; + + fromSecures += si.Item.TotalItems; + } + + fromLockdowns += list.Count; + } + + + fromLockdowns += GetLockdowns(); + + if ( !NewVendorSystem ) + { + foreach ( PlayerVendor vendor in PlayerVendors ) + { + if ( vendor.Backpack != null ) + { + fromVendors += vendor.Backpack.TotalItems; + } + } + } + + if ( MovingCrate != null ) + { + fromMovingCrate += MovingCrate.TotalItems; + + foreach ( Item item in MovingCrate.Items ) + { + if ( item is PackingBox ) + fromMovingCrate--; + } + } + + return fromSecures + fromVendors + fromLockdowns + fromMovingCrate; + } + + public bool InRange( IPoint2D from, int range ) + { + if ( Region == null ) + return false; + + foreach ( Rectangle3D rect in Region.Area ) + { + if ( from.X >= rect.Start.X - range && from.Y >= rect.Start.Y - range && from.X < rect.End.X + range && from.Y < rect.End.Y + range ) + return true; + } + + return false; + } + + public virtual int GetNewVendorSystemMaxVendors() + { + HousePlacementEntry hpe = GetAosEntry(); + + if ( hpe == null ) + return 0; + + return (int)(hpe.Vendors * BonusStorageScalar); + } + + public virtual bool CanPlaceNewVendor() + { + if ( !IsAosRules ) + return true; + + if ( !NewVendorSystem ) + return CheckAosLockdowns( 10 ); + + return ( (PlayerVendors.Count + VendorRentalContracts.Count) < GetNewVendorSystemMaxVendors() ); + } + + public const int MaximumBarkeepCount = 2; + + public virtual bool CanPlaceNewBarkeep() + { + return ( PlayerBarkeepers.Count < MaximumBarkeepCount ); + } + + public static void IsThereVendor( Point3D location, Map map, out bool vendor, out bool rentalContract ) + { + vendor = false; + rentalContract = false; + + IPooledEnumerable eable = map.GetObjectsInRange( location, 0 ); + + foreach ( IEntity entity in eable ) + { + if ( Math.Abs( location.Z - entity.Z ) <= 16 ) + { + if ( entity is PlayerVendor || entity is PlayerBarkeeper || entity is PlayerVendorPlaceholder ) + { + vendor = true; + break; + } + + if ( entity is VendorRentalContract ) + { + rentalContract = true; + break; + } + } + } + + eable.Free(); + } + + public bool HasPersonalVendors + { + get + { + foreach ( PlayerVendor vendor in PlayerVendors ) + { + if ( !(vendor is RentedVendor) ) + return true; + } + + return false; + } + } + + public bool HasRentedVendors + { + get + { + foreach ( PlayerVendor vendor in PlayerVendors ) + { + if ( vendor is RentedVendor ) + return true; + } + + return false; + } + } + + #region Mondain's Legacy + public bool HasAddonContainers + { + get + { + foreach (Item item in Addons) + { + if (item is BaseAddonContainer) + return true; + } + + return false; + } + } + #endregion + + public ArrayList AvailableVendorsFor( Mobile m ) + { + ArrayList list = new ArrayList(); + + foreach ( PlayerVendor vendor in PlayerVendors ) + { + if ( vendor.CanInteractWith( m, false ) ) + list.Add( vendor ); + } + + return list; + } + + public bool AreThereAvailableVendorsFor( Mobile m ) + { + foreach ( PlayerVendor vendor in PlayerVendors ) + { + if ( vendor.CanInteractWith( m, false ) ) + return true; + } + + return false; + } + + public void MoveAllToCrate() + { + RelocatedEntities.Clear(); + + if ( MovingCrate != null ) + MovingCrate.Hide(); + + if ( m_Trash != null ) + { + m_Trash.Delete(); + m_Trash = null; + } + + foreach ( Item item in LockDowns ) + { + if ( !item.Deleted ) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + + if ( item.Parent == null ) + DropToMovingCrate( item ); + } + } + + LockDowns.Clear(); + + foreach ( Item item in VendorRentalContracts ) + { + if ( !item.Deleted ) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + + if ( item.Parent == null ) + DropToMovingCrate( item ); + } + } + + VendorRentalContracts.Clear(); + + foreach ( SecureInfo info in Secures ) + { + Item item = info.Item; + + if ( !item.Deleted ) + { + if ( item is StrongBox ) + item = ((StrongBox)item).ConvertToStandardContainer(); + + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + + if ( item.Parent == null ) + DropToMovingCrate( item ); + } + } + + Secures.Clear(); + + foreach ( Item addon in Addons ) + { + if ( !addon.Deleted ) + { + Item deed = null; + bool retainDeedHue = false; //if the items aren't hued but the deed itself is + int hue = 0; + + if( addon is IAddon ) + { + deed = ((IAddon)addon).Deed; + + if( addon is BaseAddon && ((BaseAddon)addon).RetainDeedHue) //There are things that are IAddon which aren't BaseAddon + { + BaseAddon ba = (BaseAddon)addon; + retainDeedHue = true; + + for( int i = 0; hue == 0 && i < ba.Components.Count; ++i ) + { + AddonComponent c = ba.Components[i]; + + if( c.Hue != 0 ) + hue = c.Hue; + } + } + } + + if ( deed != null ) + { + + #region Mondain's Legacy + if (deed is BaseAddonContainerDeed && addon is BaseAddonContainer) + { + BaseAddonContainer c = (BaseAddonContainer)addon; + c.DropItemsToGround(); + + ((BaseAddonContainerDeed)deed).Resource = c.Resource; + } + else if (deed is BaseAddonDeed && addon is BaseAddon) + ((BaseAddonDeed)deed).Resource = ((BaseAddon)addon).Resource; + #endregion + + addon.Delete(); + + if( retainDeedHue ) + deed.Hue = hue; + + DropToMovingCrate( deed ); + } + else + { + DropToMovingCrate( addon ); + } + } + } + + Addons.Clear(); + + foreach ( PlayerVendor mobile in PlayerVendors ) + { + mobile.Return(); + mobile.Internalize(); + InternalizedVendors.Add( mobile ); + } + + foreach ( Mobile mobile in PlayerBarkeepers ) + { + mobile.Internalize(); + InternalizedVendors.Add( mobile ); + } + } + + public List GetHouseEntities() + { + List list = new List(); + + if ( MovingCrate != null ) + MovingCrate.Hide(); + + if ( m_Trash != null && m_Trash.Map != Map.Internal ) + list.Add( m_Trash ); + + foreach ( Item item in LockDowns ) + { + if ( item.Parent == null && item.Map != Map.Internal ) + list.Add( item ); + } + + foreach ( Item item in VendorRentalContracts ) + { + if ( item.Parent == null && item.Map != Map.Internal ) + list.Add( item ); + } + + foreach ( SecureInfo info in Secures ) + { + Item item = info.Item; + + if ( item.Parent == null && item.Map != Map.Internal ) + list.Add( item ); + } + + foreach ( Item item in Addons ) + { + if ( item.Parent == null && item.Map != Map.Internal ) + list.Add( item ); + } + + foreach ( PlayerVendor mobile in PlayerVendors ) + { + mobile.Return(); + + if ( mobile.Map != Map.Internal ) + list.Add( mobile ); + } + + foreach ( Mobile mobile in PlayerBarkeepers ) + { + if ( mobile.Map != Map.Internal ) + list.Add( mobile ); + } + + return list; + } + + public void RelocateEntities() + { + foreach ( IEntity entity in GetHouseEntities() ) + { + Point3D relLoc = new Point3D( entity.X - this.X, entity.Y - this.Y, entity.Z - this.Z ); + RelocatedEntity relocEntity = new RelocatedEntity( entity, relLoc ); + + RelocatedEntities.Add( relocEntity ); + + if ( entity is Item ) + ((Item)entity).Internalize(); + else + ((Mobile)entity).Internalize(); + } + } + + public void RestoreRelocatedEntities() + { + foreach ( RelocatedEntity relocEntity in RelocatedEntities ) + { + Point3D relLoc = relocEntity.RelativeLocation; + Point3D location = new Point3D( relLoc.X + this.X, relLoc.Y + this.Y, relLoc.Z + this.Z ); + + IEntity entity = relocEntity.Entity; + if ( entity is Item ) + { + Item item = (Item) entity; + + if ( !item.Deleted ) + { + if ( item is IAddon ) + { + if ( ((IAddon)item).CouldFit( location, this.Map ) ) + { + item.MoveToWorld( location, this.Map ); + continue; + } + } + else + { + int height; + bool requireSurface; + if ( item is VendorRentalContract ) + { + height = 16; + requireSurface = true; + } + else + { + height = item.ItemData.Height; + requireSurface = false; + } + + if ( this.Map.CanFit( location.X, location.Y, location.Z, height, false, false, requireSurface ) ) + { + item.MoveToWorld( location, this.Map ); + continue; + } + } + + // The item can't fit + + if ( item is TrashBarrel ) + { + item.Delete(); // Trash barrels don't go to the moving crate + } + else + { + SetLockdown( item, false ); + item.IsSecure = false; + item.Movable = true; + + Item relocateItem = item; + + if ( item is StrongBox ) + relocateItem = ((StrongBox)item).ConvertToStandardContainer(); + + if( item is IAddon ) + { + Item deed = ((IAddon)item).Deed; + bool retainDeedHue = false; //if the items aren't hued but the deed itself is + int hue = 0; + + if( item is BaseAddon && ((BaseAddon)item).RetainDeedHue ) //There are things that are IAddon which aren't BaseAddon + { + BaseAddon ba = (BaseAddon)item; + retainDeedHue = true; + + for( int i = 0; hue == 0 && i < ba.Components.Count; ++i ) + { + AddonComponent c = ba.Components[i]; + + if( c.Hue != 0 ) + hue = c.Hue; + } + } + + #region Mondain's Legacy + if (deed != null) + { + if (deed is BaseAddonContainerDeed && item is BaseAddonContainer) + { + BaseAddonContainer c = (BaseAddonContainer)item; + c.DropItemsToGround(); + + ((BaseAddonContainerDeed)deed).Resource = c.Resource; + } + else if (deed is BaseAddonDeed && item is BaseAddon) + ((BaseAddonDeed)deed).Resource = ((BaseAddon)item).Resource; + + if (retainDeedHue) + deed.Hue = hue; + } + #endregion + + relocateItem = deed; + item.Delete(); + } + + if ( relocateItem != null ) + DropToMovingCrate( relocateItem ); + } + } + + if ( m_Trash == item ) + m_Trash = null; + + LockDowns.Remove( item ); + VendorRentalContracts.Remove( item ); + Addons.Remove( item ); + for ( int i = Secures.Count - 1; i >= 0; i-- ) + { + if ( ((SecureInfo)Secures[i]).Item == item ) + Secures.RemoveAt( i ); + } + } + else + { + Mobile mobile = (Mobile) entity; + + if ( !mobile.Deleted ) + { + if ( this.Map.CanFit( location, 16, false, false ) ) + { + mobile.MoveToWorld( location, this.Map ); + } + else + { + InternalizedVendors.Add( mobile ); + } + } + } + } + + RelocatedEntities.Clear(); + } + + public void DropToMovingCrate( Item item ) + { + if ( MovingCrate == null ) + MovingCrate = new MovingCrate( this ); + + MovingCrate.DropItem( item ); + } + + public List GetItems() + { + if( this.Map == null || this.Map == Map.Internal ) + return new List(); + + Point2D start = new Point2D( this.X + Components.Min.X, this.Y + Components.Min.Y ); + Point2D end = new Point2D( this.X + Components.Max.X + 1, this.Y + Components.Max.Y + 1 ); + Rectangle2D rect = new Rectangle2D( start, end ); + + List list = new List(); + + IPooledEnumerable eable = this.Map.GetItemsInBounds( rect ); + + foreach ( Item item in eable ) + if ( item.Movable && IsInside( item ) ) + list.Add( item ); + + eable.Free(); + + return list; + } + + public List GetMobiles() + { + if( this.Map == null || this.Map == Map.Internal ) + return new List(); + + List list = new List(); + + foreach ( Mobile mobile in Region.GetMobiles() ) + if ( IsInside( mobile ) ) + list.Add( mobile ); + + return list; + } + + public virtual bool CheckAosLockdowns( int need ) + { + return ( (GetAosCurLockdowns() + need) <= GetAosMaxLockdowns() ); + } + + public virtual bool CheckAosStorage( int need ) + { + int fromSecures, fromVendors, fromLockdowns, fromMovingCrate; + + return ( (GetAosCurSecures( out fromSecures, out fromVendors, out fromLockdowns, out fromMovingCrate ) + need) <= GetAosMaxSecures() ); + } + + public static void Configure() + { + Item.LockedDownFlag = 1; + Item.SecureFlag = 2; + + Timer.DelayCall( TimeSpan.FromMinutes( 1.0 ), TimeSpan.FromMinutes( 1.0 ), new TimerCallback( Decay_OnTick ) ); + } + + public virtual int GetAosCurLockdowns() + { + int v = 0; + + v += GetLockdowns(); + + if ( m_Secures != null ) + v += m_Secures.Count; + + if ( !NewVendorSystem ) + v += PlayerVendors.Count * 10; + + return v; + } + + public static bool CheckLockedDown( Item item ) + { + BaseHouse house = FindHouseAt( item ); + + return ( house != null && house.IsLockedDown( item ) ); + } + + public static bool CheckSecured( Item item ) + { + BaseHouse house = FindHouseAt( item ); + + return ( house != null && house.IsSecure( item ) ); + } + + public static bool CheckLockedDownOrSecured( Item item ) + { + BaseHouse house = FindHouseAt( item ); + + return ( house != null && (house.IsSecure( item ) || house.IsLockedDown( item )) ); + } + + public static List GetHouses( Mobile m ) + { + List list = new List(); + + if ( m != null ) + { + List exists = null; + m_Table.TryGetValue( m, out exists ); + + if ( exists != null ) + { + for ( int i = 0; i < exists.Count; ++i ) + { + BaseHouse house = exists[i]; + + if ( house != null && !house.Deleted && house.Owner == m ) + list.Add( house ); + } + } + } + + return list; + } + + public static bool CheckHold( Mobile m, Container cont, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + BaseHouse house = FindHouseAt( cont ); + + if ( house == null || !house.IsAosRules ) + return true; + + if ( house.IsSecure( cont ) && !house.CheckAosStorage( 1 + item.TotalItems + plusItems ) ) + { + if ( message ) + m.SendLocalizedMessage( 1061839 ); // This action would exceed the secure storage limit of the house. + + return false; + } + + return true; + } + + public static bool CheckAccessible( Mobile m, Item item ) + { + if ( m.AccessLevel >= AccessLevel.GameMaster ) + return true; // Staff can access anything + + BaseHouse house = FindHouseAt( item ); + + if ( house == null ) + return true; + + SecureAccessResult res = house.CheckSecureAccess( m, item ); + + switch ( res ) + { + case SecureAccessResult.Insecure: break; + case SecureAccessResult.Accessible: return true; + case SecureAccessResult.Inaccessible: return false; + } + + if ( house.IsLockedDown( item ) ) + return house.IsCoOwner( m ) && (item is Container); + + return true; + } + + public static BaseHouse FindHouseAt( Mobile m ) + { + if ( m == null || m.Deleted ) + return null; + + return FindHouseAt( m.Location, m.Map, 16 ); + } + + public static BaseHouse FindHouseAt( Item item ) + { + if ( item == null || item.Deleted ) + return null; + + return FindHouseAt( item.GetWorldLocation(), item.Map, item.ItemData.Height ); + } + + public static BaseHouse FindHouseAt( Point3D loc, Map map, int height ) + { + if ( map == null || map == Map.Internal ) + return null; + + Sector sector = map.GetSector( loc ); + + for ( int i = 0; i < sector.Multis.Count; ++i ) + { + BaseHouse house = sector.Multis[i] as BaseHouse; + + if ( house != null && house.IsInside( loc, height ) ) + return house; + } + + return null; + } + + public bool IsInside( Mobile m ) + { + if ( m == null || m.Deleted || m.Map != this.Map ) + return false; + + return IsInside( m.Location, 16 ); + } + + public bool IsInside( Item item ) + { + if ( item == null || item.Deleted || item.Map != this.Map ) + return false; + + return IsInside( item.Location, item.ItemData.Height ); + } + + public bool CheckAccessibility( Item item, Mobile from ) + { + SecureAccessResult res = CheckSecureAccess( from, item ); + + switch ( res ) + { + case SecureAccessResult.Insecure: break; + case SecureAccessResult.Accessible: return true; + case SecureAccessResult.Inaccessible: return false; + } + + if (!IsLockedDown(item)) + return true; + else if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + else if (item is Runebook) + return true; + else if (item is ISecurable) + return HasSecureAccess(from, ((ISecurable)item).Level); + else if (item is Container) + return IsCoOwner(from); + else if (item.Stackable) + return true; + else if (item is BaseLight) + return IsFriend(from); + else if (item is PotionKeg) + return IsFriend(from); + else if (item is BaseBoard) + return true; + else if (item is Dices) + return true; + else if (item is RecallRune) + return true; + else if (item is TreasureMap) + return true; + else if (item is Clock) + return true; + else if (item is BaseInstrument) + return true; + else if (item is Dyes || item is DyeTub) + return true; + else if (item is VendorRentalContract) + return true; + else if (item is RewardBrazier) + return true; + // Scriptiz : pour pouvoir utiliser les poteaux d'arnachement dans les maisons ! + else if (item is PoteauArnachement) + return IsCoOwner(from); + //Plume : Pour la Slayer Forge + else if (item is SlayerForge) + return true; + + return false; + } + + public virtual bool IsInside( Point3D p, int height ) + { + if ( Deleted ) + return false; + + MultiComponentList mcl = Components; + + int x = p.X - (X + mcl.Min.X); + int y = p.Y - (Y + mcl.Min.Y); + + if ( x < 0 || x >= mcl.Width || y < 0 || y >= mcl.Height ) + return false; + + if ( this is HouseFoundation && y < (mcl.Height-1) && p.Z >= this.Z ) + return true; + + StaticTile[] tiles = mcl.Tiles[x][y]; + + for ( int j = 0; j < tiles.Length; ++j ) + { + StaticTile tile = tiles[j]; + int id = tile.ID & TileData.MaxItemValue; + ItemData data = TileData.ItemTable[id]; + + // Slanted roofs do not count; they overhang blocking south and east sides of the multi + if ( (data.Flags & TileFlag.Roof) != 0 ) + continue; + + // Signs and signposts are not considered part of the multi + if ( (id >= 0xB95 && id <= 0xC0E) || (id >= 0xC43 && id <= 0xC44) ) + continue; + + int tileZ = tile.Z + this.Z; + + if ( p.Z == tileZ || (p.Z + height) > tileZ ) + return true; + } + + return false; + } + + public SecureAccessResult CheckSecureAccess( Mobile m, Item item ) + { + if ( m_Secures == null || !(item is Container) ) + return SecureAccessResult.Insecure; + + for ( int i = 0; i < m_Secures.Count; ++i ) + { + SecureInfo info = (SecureInfo)m_Secures[i]; + + if ( info.Item == item ) + return HasSecureAccess( m, info.Level ) ? SecureAccessResult.Accessible : SecureAccessResult.Inaccessible; + } + + return SecureAccessResult.Insecure; + } + + private static List m_AllHouses = new List(); + + public static List AllHouses + { + get { return m_AllHouses; } + } + + public BaseHouse( int multiID, Mobile owner, int MaxLockDown, int MaxSecure ) : base( multiID ) + { + m_AllHouses.Add( this ); + + m_LastRefreshed = DateTime.Now; + + m_BuiltOn = DateTime.Now; + m_LastTraded = DateTime.MinValue; + + m_Doors = new ArrayList(); + m_LockDowns = new ArrayList(); + m_Secures = new ArrayList(); + m_Addons = new ArrayList(); + + m_CoOwners = new ArrayList(); + m_Friends = new ArrayList(); + m_Bans = new ArrayList(); + m_Access = new ArrayList(); + + m_VendorRentalContracts = new ArrayList(); + m_InternalizedVendors = new ArrayList(); + + m_Owner = owner; + + m_MaxLockDowns = MaxLockDown; + m_MaxSecures = MaxSecure; + + m_RelativeBanLocation = this.BaseBanLocation; + + UpdateRegion(); + + if ( owner != null ) + { + List list = null; + m_Table.TryGetValue( owner, out list ); + + if ( list == null ) + m_Table[owner] = list = new List(); + + list.Add( this ); + } + + Movable = false; + } + + public BaseHouse( Serial serial ) : base( serial ) + { + m_AllHouses.Add( this ); + } + + public override void OnMapChange() + { + if ( m_LockDowns == null ) + return; + + UpdateRegion(); + + if ( m_Sign != null && !m_Sign.Deleted ) + m_Sign.Map = this.Map; + + if ( m_Doors != null ) + { + foreach ( Item item in m_Doors ) + item.Map = this.Map; + } + + foreach ( IEntity entity in GetHouseEntities() ) + { + if ( entity is Item ) + ((Item)entity).Map = this.Map; + else + ((Mobile)entity).Map = this.Map; + } + } + + public virtual void ChangeSignType( int itemID ) + { + if ( m_Sign != null ) + m_Sign.ItemID = itemID; + } + + public abstract Rectangle2D[] Area{ get; } + public abstract Point3D BaseBanLocation{ get; } + + public virtual void UpdateRegion() + { + if ( m_Region != null ) + m_Region.Unregister(); + + if ( this.Map != null ) + { + m_Region = new HouseRegion( this ); + m_Region.Register(); + } + else + { + m_Region = null; + } + } + + public override void OnLocationChange( Point3D oldLocation ) + { + if ( m_LockDowns == null ) + return; + + int x = base.Location.X - oldLocation.X; + int y = base.Location.Y - oldLocation.Y; + int z = base.Location.Z - oldLocation.Z; + + if ( m_Sign != null && !m_Sign.Deleted ) + m_Sign.Location = new Point3D( m_Sign.X + x, m_Sign.Y + y, m_Sign.Z + z ); + + UpdateRegion(); + + if ( m_Doors != null ) + { + foreach ( Item item in m_Doors ) + { + if ( !item.Deleted ) + item.Location = new Point3D( item.X + x, item.Y + y, item.Z + z ); + } + } + + foreach ( IEntity entity in GetHouseEntities() ) + { + Point3D newLocation = new Point3D( entity.X + x, entity.Y + y, entity.Z + z ); + + if ( entity is Item ) + ((Item)entity).Location = newLocation; + else + ((Mobile)entity).Location = newLocation; + } + } + + public BaseDoor AddEastDoor( int x, int y, int z ) + { + return AddEastDoor( true, x, y, z ); + } + + public BaseDoor AddEastDoor( bool wood, int x, int y, int z ) + { + BaseDoor door = MakeDoor( wood, DoorFacing.SouthCW ); + + AddDoor( door, x, y, z ); + + return door; + } + + public BaseDoor AddSouthDoor( int x, int y, int z ) + { + return AddSouthDoor( true, x, y, z ); + } + + public BaseDoor AddSouthDoor( bool wood, int x, int y, int z ) + { + BaseDoor door = MakeDoor( wood, DoorFacing.WestCW ); + + AddDoor( door, x, y, z ); + + return door; + } + + public BaseDoor AddEastDoor( int x, int y, int z, uint k ) + { + return AddEastDoor( true, x, y, z, k ); + } + + public BaseDoor AddEastDoor( bool wood, int x, int y, int z, uint k ) + { + BaseDoor door = MakeDoor( wood, DoorFacing.SouthCW ); + + door.Locked = true; + door.KeyValue = k; + + AddDoor( door, x, y, z ); + + return door; + } + + public BaseDoor AddSouthDoor( int x, int y, int z, uint k ) + { + return AddSouthDoor( true, x, y, z, k ); + } + + public BaseDoor AddSouthDoor( bool wood, int x, int y, int z, uint k ) + { + BaseDoor door = MakeDoor( wood, DoorFacing.WestCW ); + + door.Locked = true; + door.KeyValue = k; + + AddDoor( door, x, y, z ); + + return door; + } + + public BaseDoor[] AddSouthDoors( int x, int y, int z, uint k ) + { + return AddSouthDoors( true, x, y, z, k ); + } + + public BaseDoor[] AddSouthDoors( bool wood, int x, int y, int z, uint k ) + { + BaseDoor westDoor = MakeDoor( wood, DoorFacing.WestCW ); + BaseDoor eastDoor = MakeDoor( wood, DoorFacing.EastCCW ); + + westDoor.Locked = true; + eastDoor.Locked = true; + + westDoor.KeyValue = k; + eastDoor.KeyValue = k; + + westDoor.Link = eastDoor; + eastDoor.Link = westDoor; + + AddDoor( westDoor, x, y, z ); + AddDoor( eastDoor, x + 1, y, z ); + + return new BaseDoor[2]{ westDoor, eastDoor }; + } + + public uint CreateKeys( Mobile m ) + { + uint value = Key.RandomValue(); + + if ( !IsAosRules ) + { + Key packKey = new Key( KeyType.Gold ); + Key bankKey = new Key( KeyType.Gold ); + + packKey.KeyValue = value; + bankKey.KeyValue = value; + + packKey.LootType = LootType.Newbied; + bankKey.LootType = LootType.Newbied; + + BankBox box = m.BankBox; + + if ( !box.TryDropItem( m, bankKey, false ) ) + bankKey.Delete(); + + m.AddToBackpack( packKey ); + } + + return value; + } + + public BaseDoor[] AddSouthDoors( int x, int y, int z ) + { + return AddSouthDoors( true, x, y, z, false ); + } + + public BaseDoor[] AddSouthDoors( bool wood, int x, int y, int z, bool inv ) + { + BaseDoor westDoor = MakeDoor( wood, inv ? DoorFacing.WestCCW : DoorFacing.WestCW ); + BaseDoor eastDoor = MakeDoor( wood, inv ? DoorFacing.EastCW : DoorFacing.EastCCW ); + + westDoor.Link = eastDoor; + eastDoor.Link = westDoor; + + AddDoor( westDoor, x, y, z ); + AddDoor( eastDoor, x + 1, y, z ); + + return new BaseDoor[2]{ westDoor, eastDoor }; + } + + public BaseDoor MakeDoor( bool wood, DoorFacing facing ) + { + if ( wood ) + return new DarkWoodHouseDoor( facing ); + else + return new MetalHouseDoor( facing ); + } + + public void AddDoor( BaseDoor door, int xoff, int yoff, int zoff ) + { + door.MoveToWorld( new Point3D( xoff+this.X, yoff+this.Y, zoff+this.Z ), this.Map ); + m_Doors.Add( door ); + } + + public void AddTrashBarrel( Mobile from ) + { + if ( !IsActive ) + return; + + for ( int i = 0; m_Doors != null && i < m_Doors.Count; ++i ) + { + BaseDoor door = m_Doors[i] as BaseDoor; + Point3D p = door.Location; + + if ( door.Open ) + p = new Point3D( p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z ); + + if ( (from.Z + 16) >= p.Z && (p.Z + 16) >= from.Z ) + { + if ( from.InRange( p, 1 ) ) + { + from.SendLocalizedMessage( 502120 ); // You cannot place a trash barrel near a door or near steps. + return; + } + } + } + + if ( m_Trash == null || m_Trash.Deleted ) + { + m_Trash = new TrashBarrel(); + + m_Trash.Movable = false; + m_Trash.MoveToWorld( from.Location, from.Map ); + + from.SendLocalizedMessage( 502121 ); /* You have a new trash barrel. + * Three minutes after you put something in the barrel, the trash will be emptied. + * Be forewarned, this is permanent! */ + } + else + { + from.SendLocalizedMessage( 502117 ); // You already have a trash barrel! + } + } + + public void SetSign( int xoff, int yoff, int zoff ) + { + m_Sign = new HouseSign( this ); + m_Sign.MoveToWorld( new Point3D( this.X + xoff, this.Y + yoff, this.Z + zoff ), this.Map ); + } + + private void SetLockdown( Item i, bool locked ) + { + SetLockdown( i, locked, false ); + } + + private void SetLockdown( Item i, bool locked, bool checkContains ) + { + if ( m_LockDowns == null ) + return; + + i.Movable = !locked; + i.IsLockedDown = locked; + + if ( locked ) + { + if ( i is VendorRentalContract ) + { + if ( !VendorRentalContracts.Contains( i ) ) + VendorRentalContracts.Add( i ); + } + else + { + if ( !checkContains || !m_LockDowns.Contains( i ) ) + m_LockDowns.Add( i ); + } + } + else + { + VendorRentalContracts.Remove( i ); + m_LockDowns.Remove( i ); + } + + if ( !locked ) + i.SetLastMoved(); + + if ((i is Container) && (!locked || !(i is BaseBoard || i is Aquarium || i is FishBowl))) + { + foreach ( Item c in i.Items ) + SetLockdown( c, locked, checkContains ); + } + } + + public bool LockDown( Mobile m, Item item ) + { + return LockDown( m, item, true ); + } + + public bool LockDown( Mobile m, Item item, bool checkIsInside ) + { + if ( !IsCoOwner( m ) || !IsActive ) + return false; + + if ( item.Movable && !IsSecure( item ) ) + { + int amt = 1 + item.TotalItems; + + Item rootItem = item.RootParent as Item; + Item parentItem = item.Parent as Item; + + if ( checkIsInside && item.RootParent is Mobile ) + { + m.SendLocalizedMessage( 1005525 );//That is not in your house + } + else if ( checkIsInside && !IsInside( item.GetWorldLocation(), item.ItemData.Height ) ) + { + m.SendLocalizedMessage( 1005525 );//That is not in your house + } + else if ( Ethics.Ethic.IsImbued( item ) ) + { + m.SendLocalizedMessage( 1005377 );//You cannot lock that down + } + else if ( IsSecure( rootItem ) ) + { + m.SendLocalizedMessage( 501737 ); // You need not lock down items in a secure container. + } + else if ( parentItem != null && !IsLockedDown( parentItem ) ) + { + m.SendLocalizedMessage( 501736 ); // You must lockdown the container first! + } + else if ( !(item is VendorRentalContract) && ( IsAosRules ? (!CheckAosLockdowns( amt ) || !CheckAosStorage( amt )) : (this.LockDownCount + amt) > m_MaxLockDowns ) ) + { + m.SendLocalizedMessage( 1005379 );//That would exceed the maximum lock down limit for this house + } + else + { + SetLockdown( item, true ); + return true; + } + } + else if ( m_LockDowns.IndexOf( item ) != -1 ) + { + m.LocalOverheadMessage( MessageType.Regular, 0x3E9, 1005526 ); //That is already locked down + return true; + } + else if ( item is HouseSign || item is Static ) + { + m.LocalOverheadMessage( MessageType.Regular, 0x3E9, 1005526 ); // This is already locked down. + } + else + { + m.SendLocalizedMessage( 1005377 );//You cannot lock that down + } + + return false; + } + + private class TransferItem : Item + { + private BaseHouse m_House; + + public override string DefaultName + { + get { return "a house transfer contract"; } + } + + public TransferItem( BaseHouse house ) : base( 0x14F0 ) + { + m_House = house; + + Hue = 0x480; + Movable = false; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + string houseName, owner, location; + + houseName = ( m_House == null ? "an unnamed house" : m_House.Sign.GetName() ); + + Mobile houseOwner = ( m_House == null ? null : m_House.Owner ); + + if ( houseOwner == null ) + owner = "nobody"; + else + owner = houseOwner.Name; + + int xLong = 0, yLat = 0, xMins = 0, yMins = 0; + bool xEast = false, ySouth = false; + + bool valid = m_House != null && Sextant.Format( m_House.Location, m_House.Map, ref xLong, ref yLat, ref xMins, ref yMins, ref xEast, ref ySouth ); + + if ( valid ) + location = String.Format( "{0}� {1}'{2}, {3}� {4}'{5}", yLat, yMins, ySouth ? "S" : "N", xLong, xMins, xEast ? "E" : "W" ); + else + location = "unknown"; + + list.Add( 1061112, Utility.FixHtml( houseName ) ); // House Name: ~1_val~ + list.Add( 1061113, owner ); // Owner: ~1_val~ + list.Add( 1061114, location ); // Location: ~1_val~ + } + + public TransferItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + Delete(); + } + + public override bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if ( !base.AllowSecureTrade( from, to, newOwner, accepted ) ) + return false; + else if ( !accepted ) + return true; + + if ( Deleted || m_House == null || m_House.Deleted || !m_House.IsOwner( from ) || !from.CheckAlive() || !to.CheckAlive() ) + return false; + + if ( BaseHouse.HasAccountHouse( to ) ) + { + from.SendLocalizedMessage( 501388 ); // You cannot transfer ownership to another house owner or co-owner! + return false; + } + + return m_House.CheckTransferPosition( from, to ); + } + + public override void OnSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + if ( Deleted ) + return; + + Delete(); + + if ( m_House == null || m_House.Deleted || !m_House.IsOwner( from ) || !from.CheckAlive() || !to.CheckAlive() ) + return; + + + if ( !accepted ) + return; + + from.SendLocalizedMessage( 501338 ); // You have transferred ownership of the house. + to.SendLocalizedMessage( 501339 ); /* You are now the owner of this house. + * The house's co-owner, friend, ban, and access lists have been cleared. + * You should double-check the security settings on any doors and teleporters in the house. + */ + + m_House.RemoveKeys( from ); + m_House.Owner = to; + m_House.Bans.Clear(); + m_House.Friends.Clear(); + m_House.CoOwners.Clear(); + m_House.ChangeLocks( to ); + m_House.LastTraded = DateTime.Now; + } + } + + public bool CheckTransferPosition( Mobile from, Mobile to ) + { + bool isValid = true; + Item sign = m_Sign; + Point3D p = ( sign == null ? Point3D.Zero : sign.GetWorldLocation() ); + + if ( from.Map != Map || to.Map != Map ) + isValid = false; + else if ( sign == null ) + isValid = false; + else if ( from.Map != sign.Map || to.Map != sign.Map ) + isValid = false; + else if ( IsInside( from ) ) + isValid = false; + else if ( IsInside( to ) ) + isValid = false; + else if ( !from.InRange( p, 2 ) ) + isValid = false; + else if ( !to.InRange( p, 2 ) ) + isValid = false; + + if ( !isValid ) + from.SendLocalizedMessage( 1062067 ); // In order to transfer the house, you and the recipient must both be outside the building and within two paces of the house sign. + + return isValid; + } + + public void BeginConfirmTransfer( Mobile from, Mobile to ) + { + if ( Deleted || !from.CheckAlive() || !IsOwner( from ) ) + return; + + if ( NewVendorSystem && HasPersonalVendors ) + { + from.SendLocalizedMessage( 1062467 ); // You cannot trade this house while you still have personal vendors inside. + } + else if ( DecayLevel == DecayLevel.DemolitionPending ) + { + from.SendLocalizedMessage( 1005321 ); // This house has been marked for demolition, and it cannot be transferred. + } + else if ( from == to ) + { + from.SendLocalizedMessage( 1005330 ); // You cannot transfer a house to yourself, silly. + } + else if ( to.Player ) + { + if ( BaseHouse.HasAccountHouse( to ) ) + { + from.SendLocalizedMessage( 501388 ); // You cannot transfer ownership to another house owner or co-owner! + } + else if ( CheckTransferPosition( from, to ) ) + { + from.SendLocalizedMessage( 1005326 ); // Please wait while the other player verifies the transfer. + + if ( HasRentedVendors ) + { + /* You are about to be traded a home that has active vendor contracts. + * While there are active vendor contracts in this house, you + * cannot demolish OR customize the home. + * When you accept this house, you also accept landlordship for every + * contract vendor in the house. + */ + to.SendGump( new WarningGump( 1060635, 30720, 1062487, 32512, 420, 280, new WarningGumpCallback( ConfirmTransfer_Callback ), from ) ); + } + else + { + to.CloseGump( typeof( Gumps.HouseTransferGump ) ); + to.SendGump( new Gumps.HouseTransferGump( from, to, this ) ); + } + } + } + else + { + from.SendLocalizedMessage( 501384 ); // Only a player can own a house! + } + } + + private void ConfirmTransfer_Callback( Mobile to, bool ok, object state ) + { + Mobile from = (Mobile) state; + + if ( !ok || Deleted || !from.CheckAlive() || !IsOwner( from ) ) + return; + + if ( CheckTransferPosition( from, to ) ) + { + to.CloseGump( typeof( Gumps.HouseTransferGump ) ); + to.SendGump( new Gumps.HouseTransferGump( from, to, this ) ); + } + } + + public void EndConfirmTransfer( Mobile from, Mobile to ) + { + if ( Deleted || !from.CheckAlive() || !IsOwner( from ) ) + return; + + if ( NewVendorSystem && HasPersonalVendors ) + { + from.SendLocalizedMessage( 1062467 ); // You cannot trade this house while you still have personal vendors inside. + } + else if ( DecayLevel == DecayLevel.DemolitionPending ) + { + from.SendLocalizedMessage( 1005321 ); // This house has been marked for demolition, and it cannot be transferred. + } + else if ( from == to ) + { + from.SendLocalizedMessage( 1005330 ); // You cannot transfer a house to yourself, silly. + } + else if ( to.Player ) + { + if ( BaseHouse.HasAccountHouse( to ) ) + { + from.SendLocalizedMessage( 501388 ); // You cannot transfer ownership to another house owner or co-owner! + } + else if ( CheckTransferPosition( from, to ) ) + { + NetState fromState = from.NetState, toState = to.NetState; + + if ( fromState != null && toState != null ) + { + if ( from.HasTrade ) + { + from.SendLocalizedMessage( 1062071 ); // You cannot trade a house while you have other trades pending. + } + else if ( to.HasTrade ) + { + to.SendLocalizedMessage( 1062071 ); // You cannot trade a house while you have other trades pending. + } + else if( !to.Alive ) + { + // TODO: Check if the message is correct. + from.SendLocalizedMessage( 1062069 ); // You cannot transfer this house to that person. + } + else + { + Container c = fromState.AddTrade( toState ); + + c.DropItem( new TransferItem( this ) ); + } + } + } + } + else + { + from.SendLocalizedMessage( 501384 ); // Only a player can own a house! + } + } + + public void Release( Mobile m, Item item ) + { + if ( !IsCoOwner( m ) || !IsActive ) + return; + + if ( IsLockedDown( item ) ) + { + item.PublicOverheadMessage( Server.Network.MessageType.Label, 0x3B2, 501657 );//[no longer locked down] + SetLockdown( item, false ); + //TidyItemList( m_LockDowns ); + + if ( item is RewardBrazier ) + ((RewardBrazier) item).TurnOff(); + } + else if ( IsSecure( item ) ) + { + ReleaseSecure( m, item ); + } + else + { + m.LocalOverheadMessage( MessageType.Regular, 0x3E9, 1010416 ); // This is not locked down or secured. + } + } + + public void AddSecure( Mobile m, Item item ) + { + if ( m_Secures == null || !IsOwner( m ) || !IsActive ) + return; + + if ( !IsInside( item ) ) + { + m.SendLocalizedMessage( 1005525 ); // That is not in your house + } + else if ( IsLockedDown( item ) ) + { + m.SendLocalizedMessage( 1010550 ); // This is already locked down and cannot be secured. + } + else if ( !(item is Container) ) + { + LockDown( m, item ); + } + else + { + SecureInfo info = null; + + for ( int i = 0; info == null && i < m_Secures.Count; ++i ) + if ( ((SecureInfo)m_Secures[i]).Item == item ) + info = (SecureInfo)m_Secures[i]; + + if ( info != null ) + { + m.CloseGump( typeof ( SetSecureLevelGump ) ); + m.SendGump( new Gumps.SetSecureLevelGump( m_Owner, info, this ) ); + } + else if ( item.Parent != null ) + { + m.SendLocalizedMessage( 1010423 ); // You cannot secure this, place it on the ground first. + } + else if ( !item.Movable ) + { + m.SendLocalizedMessage( 1010424 ); // You cannot secure this. + } + else if ( !IsAosRules && SecureCount >= MaxSecures ) + { + // The maximum number of secure items has been reached : + m.SendLocalizedMessage( 1008142, true, MaxSecures.ToString() ); + } + else if ( IsAosRules ? !CheckAosLockdowns( 1 ) : ((LockDownCount + 125) >= MaxLockDowns) ) + { + m.SendLocalizedMessage( 1005379 ); // That would exceed the maximum lock down limit for this house + } + else if ( IsAosRules && !CheckAosStorage( item.TotalItems ) ) + { + m.SendLocalizedMessage( 1061839 ); // This action would exceed the secure storage limit of the house. + } + else + { + info = new SecureInfo( (Container)item, SecureLevel.Owner ); + + item.IsLockedDown = false; + item.IsSecure = true; + + m_Secures.Add( info ); + m_LockDowns.Remove( item ); + item.Movable = false; + + m.CloseGump( typeof ( SetSecureLevelGump ) ); + m.SendGump( new Gumps.SetSecureLevelGump( m_Owner, info, this ) ); + } + } + } + + public virtual bool IsCombatRestricted( Mobile m ) + { + if ( m == null || !m.Player || m.AccessLevel >= AccessLevel.GameMaster || !IsAosRules || ( m_Owner != null && m_Owner.AccessLevel >= AccessLevel.GameMaster )) + return false; + + for ( int i = 0; i < m.Aggressed.Count; ++i ) + { + AggressorInfo info = m.Aggressed[i]; + + Guild attackerGuild = m.Guild as Guild; + Guild defenderGuild = info.Defender.Guild as Guild; + + if ( info.Defender.Player && info.Defender.Alive && (DateTime.Now - info.LastCombatTime) < HouseRegion.CombatHeatDelay && (attackerGuild == null || defenderGuild == null || defenderGuild != attackerGuild && !defenderGuild.IsEnemy( attackerGuild )) ) + return true; + } + + return false; + } + + public bool HasSecureAccess( Mobile m, SecureLevel level ) + { + if ( m.AccessLevel >= AccessLevel.GameMaster ) + return true; + + if ( IsCombatRestricted( m ) ) + return false; + + switch ( level ) + { + case SecureLevel.Owner: return IsOwner( m ); + case SecureLevel.CoOwners: return IsCoOwner( m ); + case SecureLevel.Friends: return IsFriend( m ); + case SecureLevel.Anyone: return true; + case SecureLevel.Guild: return IsGuildMember( m ); + } + + return false; + } + + public void ReleaseSecure( Mobile m, Item item ) + { + if ( m_Secures == null || !IsOwner( m ) || item is StrongBox || !IsActive ) + return; + + for ( int i = 0; i < m_Secures.Count; ++i ) + { + SecureInfo info = (SecureInfo)m_Secures[i]; + + if ( info.Item == item && HasSecureAccess( m, info.Level ) ) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + item.SetLastMoved(); + item.PublicOverheadMessage( Server.Network.MessageType.Label, 0x3B2, 501656 );//[no longer secure] + m_Secures.RemoveAt( i ); + return; + } + } + + m.SendLocalizedMessage( 501717 );//This isn't secure... + } + + public override bool Decays + { + get + { + return false; + } + } + + public void AddStrongBox( Mobile from ) + { + if ( !IsCoOwner( from ) || !IsActive ) + return; + + if ( from == Owner ) + { + from.SendLocalizedMessage( 502109 ); // Owners don't get a strong box + return; + } + + if ( IsAosRules ? !CheckAosLockdowns( 1 ) : ((LockDownCount + 1) > m_MaxLockDowns) ) + { + from.SendLocalizedMessage( 1005379 );//That would exceed the maximum lock down limit for this house + return; + } + + foreach ( SecureInfo info in m_Secures ) + { + Container c = info.Item; + + if ( !c.Deleted && c is StrongBox && ((StrongBox)c).Owner == from ) + { + from.SendLocalizedMessage( 502112 );//You already have a strong box + return; + } + } + + for ( int i = 0; m_Doors != null && i < m_Doors.Count; ++i ) + { + BaseDoor door = m_Doors[i] as BaseDoor; + Point3D p = door.Location; + + if ( door.Open ) + p = new Point3D( p.X - door.Offset.X, p.Y - door.Offset.Y, p.Z - door.Offset.Z ); + + if ( (from.Z + 16) >= p.Z && (p.Z + 16) >= from.Z ) + { + if ( from.InRange( p, 1 ) ) + { + from.SendLocalizedMessage( 502113 ); // You cannot place a strongbox near a door or near steps. + return; + } + } + } + + StrongBox sb = new StrongBox( from, this ); + sb.Movable = false; + sb.IsLockedDown = false; + sb.IsSecure = true; + m_Secures.Add( new SecureInfo( sb, SecureLevel.CoOwners ) ); + sb.MoveToWorld( from.Location, from.Map ); + } + + public void Kick( Mobile from, Mobile targ ) + { + if ( !IsFriend( from ) || m_Friends == null ) + return; + + if ( targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel ) + { + from.SendLocalizedMessage( 501346 ); // Uh oh...a bigger boot may be required! + } + else if ( IsFriend( targ ) && !Core.ML ) + { + from.SendLocalizedMessage( 501348 ); // You cannot eject a friend of the house! + } + else if ( targ is PlayerVendor ) + { + from.SendLocalizedMessage( 501351 ); // You cannot eject a vendor. + } + else if ( !IsInside( targ ) ) + { + from.SendLocalizedMessage( 501352 ); // You may not eject someone who is not in your house! + } + else if ( targ is BaseCreature && ((BaseCreature)targ).NoHouseRestrictions ) + { + from.SendLocalizedMessage( 501347 ); // You cannot eject that from the house! + } + else + { + targ.MoveToWorld( BanLocation, Map ); + + from.SendLocalizedMessage( 1042840, targ.Name ); // ~1_PLAYER NAME~ has been ejected from this house. + targ.SendLocalizedMessage( 501341 ); /* You have been ejected from this house. + * If you persist in entering, you may be banned from the house. + */ + } + } + + public void RemoveAccess( Mobile from, Mobile targ ) + { + if ( !IsFriend( from ) || m_Access == null ) + return; + + if ( m_Access.Contains( targ ) ) + { + m_Access.Remove( targ ); + + if ( !HasAccess( targ ) && IsInside( targ ) ) + { + targ.Location = BanLocation; + targ.SendLocalizedMessage( 1060734 ); // Your access to this house has been revoked. + } + + from.SendLocalizedMessage( 1050051 ); // The invitation has been revoked. + } + } + + public void RemoveBan( Mobile from, Mobile targ ) + { + if ( !IsCoOwner( from ) || m_Bans == null ) + return; + + if ( m_Bans.Contains( targ ) ) + { + m_Bans.Remove( targ ); + + from.SendLocalizedMessage( 501297 ); // The ban is lifted. + } + } + + public void Ban( Mobile from, Mobile targ ) + { + if ( !IsFriend( from ) || m_Bans == null ) + return; + + if ( targ.AccessLevel > AccessLevel.Player && from.AccessLevel <= targ.AccessLevel ) + { + from.SendLocalizedMessage( 501354 ); // Uh oh...a bigger boot may be required. + } + else if ( IsFriend( targ ) ) + { + from.SendLocalizedMessage( 501348 ); // You cannot eject a friend of the house! + } + else if ( targ is PlayerVendor ) + { + from.SendLocalizedMessage( 501351 ); // You cannot eject a vendor. + } + else if ( m_Bans.Count >= MaxBans ) + { + from.SendLocalizedMessage( 501355 ); // The ban limit for this house has been reached! + } + else if ( IsBanned( targ ) ) + { + from.SendLocalizedMessage( 501356 ); // This person is already banned! + } + else if ( !IsInside( targ ) ) + { + from.SendLocalizedMessage( 501352 ); // You may not eject someone who is not in your house! + } + else if ( !Public && IsAosRules ) + { + from.SendLocalizedMessage( 1062521 ); // You cannot ban someone from a private house. Revoke their access instead. + } + else if ( targ is BaseCreature && ((BaseCreature)targ).NoHouseRestrictions ) + { + from.SendLocalizedMessage( 1062040 ); // You cannot ban that. + } + else + { + m_Bans.Add( targ ); + + from.SendLocalizedMessage( 1042839, targ.Name ); // ~1_PLAYER_NAME~ has been banned from this house. + targ.SendLocalizedMessage( 501340 ); // You have been banned from this house. + + targ.MoveToWorld( BanLocation, Map ); + } + } + + public void GrantAccess( Mobile from, Mobile targ ) + { + if ( !IsFriend( from ) || m_Access == null ) + return; + + if ( HasAccess( targ ) ) + { + from.SendLocalizedMessage( 1060729 ); // That person already has access to this house. + } + else if ( !targ.Player ) + { + from.SendLocalizedMessage( 1060712 ); // That is not a player. + } + else if ( IsBanned( targ ) ) + { + from.SendLocalizedMessage( 501367 ); // This person is banned! Unban them first. + } + else + { + m_Access.Add( targ ); + + targ.SendLocalizedMessage( 1060735 ); // You have been granted access to this house. + } + } + + public void AddCoOwner( Mobile from, Mobile targ ) + { + if ( !IsOwner( from ) || m_CoOwners == null || m_Friends == null ) + return; + + if ( IsOwner( targ ) ) + { + from.SendLocalizedMessage( 501360 ); // This person is already the house owner! + } + else if ( m_Friends.Contains( targ ) ) + { + from.SendLocalizedMessage( 501361 ); // This person is a friend of the house. Remove them first. + } + else if ( !targ.Player ) + { + from.SendLocalizedMessage( 501362 ); // That can't be a co-owner of the house. + } + else if (!Core.AOS && HasAccountHouse(targ)) + { + from.SendLocalizedMessage( 501364 ); // That person is already a house owner. + } + else if ( IsBanned( targ ) ) + { + from.SendLocalizedMessage( 501367 ); // This person is banned! Unban them first. + } + else if ( m_CoOwners.Count >= MaxCoOwners ) + { + from.SendLocalizedMessage( 501368 ); // Your co-owner list is full! + } + else if ( m_CoOwners.Contains( targ ) ) + { + from.SendLocalizedMessage( 501369 ); // This person is already on your co-owner list! + } + else + { + m_CoOwners.Add( targ ); + + targ.Delta( MobileDelta.Noto ); + targ.SendLocalizedMessage( 501343 ); // You have been made a co-owner of this house. + } + } + + public void RemoveCoOwner( Mobile from, Mobile targ ) + { + if ( !IsOwner( from ) || m_CoOwners == null ) + return; + + if ( m_CoOwners.Contains( targ ) ) + { + m_CoOwners.Remove( targ ); + + targ.Delta( MobileDelta.Noto ); + + from.SendLocalizedMessage( 501299 ); // Co-owner removed from list. + targ.SendLocalizedMessage( 501300 ); // You have been removed as a house co-owner. + + foreach ( SecureInfo info in m_Secures ) + { + Container c = info.Item; + + if ( c is StrongBox && ((StrongBox)c).Owner == targ ) + { + c.IsLockedDown = false; + c.IsSecure = false; + m_Secures.Remove( info ); + c.Destroy(); + break; + } + } + } + } + + public void AddFriend( Mobile from, Mobile targ ) + { + if ( !IsCoOwner( from ) || m_Friends == null || m_CoOwners == null ) + return; + + if ( IsOwner( targ ) ) + { + from.SendLocalizedMessage( 501370 ); // This person is already an owner of the house! + } + else if ( m_CoOwners.Contains( targ ) ) + { + from.SendLocalizedMessage( 501369 ); // This person is already on your co-owner list! + } + else if ( !targ.Player ) + { + from.SendLocalizedMessage( 501371 ); // That can't be a friend of the house. + } + else if ( IsBanned( targ ) ) + { + from.SendLocalizedMessage( 501374 ); // This person is banned! Unban them first. + } + else if ( m_Friends.Count >= MaxFriends ) + { + from.SendLocalizedMessage( 501375 ); // Your friends list is full! + } + else if ( m_Friends.Contains( targ ) ) + { + from.SendLocalizedMessage( 501376 ); // This person is already on your friends list! + } + else + { + m_Friends.Add( targ ); + + targ.Delta( MobileDelta.Noto ); + targ.SendLocalizedMessage( 501337 ); // You have been made a friend of this house. + } + } + + public void RemoveFriend( Mobile from, Mobile targ ) + { + if ( !IsCoOwner( from ) || m_Friends == null ) + return; + + if ( m_Friends.Contains( targ ) ) + { + m_Friends.Remove( targ ); + + targ.Delta( MobileDelta.Noto ); + + from.SendLocalizedMessage( 501298 ); // Friend removed from list. + targ.SendLocalizedMessage( 1060751 ); // You are no longer a friend of this house. + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write((int)15); // version + + if (!DynamicDecay.Enabled) + { + writer.Write((int)-1); + } + else + { + writer.Write((int)m_CurrentStage); + writer.Write(m_NextDecayStage); + } + + writer.Write( (Point3D) m_RelativeBanLocation ); + + writer.WriteItemList( m_VendorRentalContracts, true ); + writer.WriteMobileList( m_InternalizedVendors, true ); + + writer.WriteEncodedInt( m_RelocatedEntities.Count ); + foreach ( RelocatedEntity relEntity in m_RelocatedEntities ) + { + writer.Write( (Point3D) relEntity.RelativeLocation ); + + if ( ( relEntity.Entity is Item && ((Item)relEntity.Entity).Deleted ) || ( relEntity.Entity is Mobile && ((Mobile)relEntity.Entity).Deleted ) ) + writer.Write( (int) Serial.MinusOne ); + else + writer.Write( (int) relEntity.Entity.Serial ); + } + + writer.WriteEncodedInt( m_VendorInventories.Count ); + for ( int i = 0; i < m_VendorInventories.Count; i++ ) + { + VendorInventory inventory = (VendorInventory) m_VendorInventories[i]; + inventory.Serialize( writer ); + } + + writer.Write( (DateTime) m_LastRefreshed ); + writer.Write( (bool) m_RestrictDecay ); + + writer.Write( (int) m_Visits ); + + writer.Write( (int) m_Price ); + + writer.WriteMobileList( m_Access ); + + writer.Write( m_BuiltOn ); + writer.Write( m_LastTraded ); + + writer.WriteItemList( m_Addons, true ); + + writer.Write( m_Secures.Count ); + + for ( int i = 0; i < m_Secures.Count; ++i ) + ((SecureInfo)m_Secures[i]).Serialize( writer ); + + writer.Write( m_Public ); + + //writer.Write( BanLocation ); + + writer.Write( m_Owner ); + + // Version 5 no longer serializes region coords + /*writer.Write( (int)m_Region.Coords.Count ); + foreach( Rectangle2D rect in m_Region.Coords ) + { + writer.Write( rect ); + }*/ + + writer.WriteMobileList( m_CoOwners, true ); + writer.WriteMobileList( m_Friends, true ); + writer.WriteMobileList( m_Bans, true ); + + writer.Write( m_Sign ); + writer.Write( m_Trash ); + + writer.WriteItemList( m_Doors, true ); + writer.WriteItemList( m_LockDowns, true ); + //writer.WriteItemList( m_Secures, true ); + + writer.Write( (int) m_MaxLockDowns ); + writer.Write( (int) m_MaxSecures ); + + // Items in locked down containers that aren't locked down themselves must decay! + for ( int i = 0; i < m_LockDowns.Count; ++i ) + { + Item item = (Item)m_LockDowns[i]; + + if (item is Container && !(item is BaseBoard || item is Aquarium || item is FishBowl)) + { + Container cont = (Container)item; + List children = cont.Items; + + for ( int j = 0; j < children.Count; ++j ) + { + Item child = children[j]; + + if ( child.Decays && !child.IsLockedDown && !child.IsSecure && (child.LastMoved + child.DecayTime) <= DateTime.Now ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( child.Delete ) ); + } + } + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + int count; + bool loadedDynamicDecay = false; + + switch (version) + { + case 15: + { + int stage = reader.ReadInt(); + + if (stage != -1) + { + m_CurrentStage = (DecayLevel)stage; + m_NextDecayStage = reader.ReadDateTime(); + loadedDynamicDecay = true; + } + + goto case 14; + } + case 14: + { + m_RelativeBanLocation = reader.ReadPoint3D(); + goto case 13; + } + case 13: // removed ban location serialization + case 12: + { + m_VendorRentalContracts = reader.ReadItemList(); + m_InternalizedVendors = reader.ReadMobileList(); + + int relocatedCount = reader.ReadEncodedInt(); + for ( int i = 0; i < relocatedCount; i++ ) + { + Point3D relLocation = reader.ReadPoint3D(); + IEntity entity = World.FindEntity( reader.ReadInt() ); + + if ( entity != null ) + m_RelocatedEntities.Add( new RelocatedEntity( entity, relLocation ) ); + } + + int inventoryCount = reader.ReadEncodedInt(); + for ( int i = 0; i < inventoryCount; i++ ) + { + VendorInventory inventory = new VendorInventory( this, reader ); + m_VendorInventories.Add( inventory ); + } + + goto case 11; + } + case 11: + { + m_LastRefreshed = reader.ReadDateTime(); + m_RestrictDecay = reader.ReadBool(); + goto case 10; + } + case 10: // just a signal for updates + case 9: + { + m_Visits = reader.ReadInt(); + goto case 8; + } + case 8: + { + m_Price = reader.ReadInt(); + goto case 7; + } + case 7: + { + m_Access = reader.ReadMobileList(); + goto case 6; + } + case 6: + { + m_BuiltOn = reader.ReadDateTime(); + m_LastTraded = reader.ReadDateTime(); + goto case 5; + } + case 5: // just removed fields + case 4: + { + m_Addons = reader.ReadItemList(); + goto case 3; + } + case 3: + { + count = reader.ReadInt(); + m_Secures = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + SecureInfo info = new SecureInfo( reader ); + + if ( info.Item != null ) + { + info.Item.IsSecure = true; + m_Secures.Add( info ); + } + } + + goto case 2; + } + case 2: + { + m_Public = reader.ReadBool(); + goto case 1; + } + case 1: + { + if ( version < 13 ) + reader.ReadPoint3D(); // house ban location + goto case 0; + } + case 0: + { + if ( version < 14 ) + m_RelativeBanLocation = this.BaseBanLocation; + + if ( version < 12 ) + { + m_VendorRentalContracts = new ArrayList(); + m_InternalizedVendors = new ArrayList(); + } + + if ( version < 4 ) + m_Addons = new ArrayList(); + + if ( version < 7 ) + m_Access = new ArrayList(); + + if ( version < 8 ) + m_Price = DefaultPrice; + + m_Owner = reader.ReadMobile(); + + if ( version < 5 ) + { + count = reader.ReadInt(); + + for(int i=0;i list = null; + m_Table.TryGetValue( m_Owner, out list ); + + if ( list == null ) + m_Table[m_Owner] = list = new List(); + + list.Add( this ); + } + break; + } + } + + if ( version <= 1 ) + ChangeSignType( 0xBD2 );//private house, plain brass sign + + if ( version < 10 ) + { + /* NOTE: This can exceed the house lockdown limit. It must be this way, because + * we do not want players' items to decay without them knowing. Or not even + * having a chance to fix it themselves. + */ + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixLockdowns_Sandbox ) ); + } + + if ( version < 11 ) + m_LastRefreshed = DateTime.Now + TimeSpan.FromHours( 24 * Utility.RandomDouble() ); + + if (DynamicDecay.Enabled && !loadedDynamicDecay) + { + DecayLevel old = GetOldDecayLevel(); + + if (old == DecayLevel.DemolitionPending) + old = DecayLevel.Collapsed; + + SetDynamicDecay(old); + } + + if ( !CheckDecay() ) + { + if ( RelocatedEntities.Count > 0 ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( RestoreRelocatedEntities ) ); + + if ( m_Owner == null && m_Friends.Count == 0 && m_CoOwners.Count == 0 ) + Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), new TimerCallback( Delete ) ); + } + } + + private void FixLockdowns_Sandbox() + { + ArrayList lockDowns = new ArrayList(); + + for ( int i = 0; m_LockDowns != null && i < m_LockDowns.Count; ++i ) + { + Item item = (Item)m_LockDowns[i]; + + if ( item is Container ) + lockDowns.Add( item ); + } + + for ( int i = 0; i < lockDowns.Count; ++i ) + SetLockdown( (Item)lockDowns[i], true, true ); + } + + public static void HandleDeletion( Mobile mob ) + { + List houses = GetHouses( mob ); + + if ( houses.Count == 0 ) + return; + + Account acct = mob.Account as Account; + Mobile trans = null; + + for ( int i = 0; i < acct.Length; ++i ) + { + if ( acct[i] != null && acct[i] != mob ) + trans = acct[i]; + } + + for ( int i = 0; i < houses.Count; ++i ) + { + BaseHouse house = houses[i]; + + bool canClaim = false; + + if ( trans == null ) + canClaim = ( house.CoOwners.Count > 0 ); + /*{ + for ( int j = 0; j < house.CoOwners.Count; ++j ) + { + Mobile check = house.CoOwners[j] as Mobile; + + if ( check != null && !check.Deleted && !HasAccountHouse( check ) ) + { + canClaim = true; + break; + } + } + }*/ + + if ( trans == null && !canClaim ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( house.Delete ) ); + else + house.Owner = trans; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get + { + return m_Owner; + } + set + { + if ( m_Owner != null ) + { + List list = null; + m_Table.TryGetValue( m_Owner, out list ); + + if ( list == null ) + m_Table[m_Owner] = list = new List(); + + list.Remove( this ); + m_Owner.Delta( MobileDelta.Noto ); + } + + m_Owner = value; + + if ( m_Owner != null ) + { + List list = null; + m_Table.TryGetValue( m_Owner, out list ); + + if ( list == null ) + m_Table[m_Owner] = list = new List(); + + list.Add( this ); + m_Owner.Delta( MobileDelta.Noto ); + } + + if ( m_Sign != null ) + m_Sign.InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Visits + { + get{ return m_Visits; } + set{ m_Visits = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Public + { + get + { + return m_Public; + } + set + { + if ( m_Public != value ) + { + m_Public = value; + + if ( !m_Public ) // Privatizing the house, change to brass sign + ChangeSignType( 0xBD2 ); + + if ( m_Sign != null ) + m_Sign.InvalidateProperties(); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxSecures + { + get + { + return m_MaxSecures; + } + set + { + m_MaxSecures = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D BanLocation + { + get + { + if (m_Region != null) + return m_Region.GoLocation; + + Point3D rel = m_RelativeBanLocation; + return new Point3D(this.X + rel.X, this.Y + rel.Y, this.Z + rel.Z); + } + set + { + this.RelativeBanLocation = new Point3D( value.X - this.X, value.Y - this.Y, value.Z - this.Z ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D RelativeBanLocation + { + get + { + return m_RelativeBanLocation; + } + set + { + m_RelativeBanLocation = value; + if (m_Region != null) + m_Region.GoLocation = new Point3D(this.X + value.X, this.Y + value.Y, this.Z + value.Z); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxLockDowns + { + get + { + return m_MaxLockDowns; + } + set + { + m_MaxLockDowns = value; + } + } + + public Region Region{ get{ return m_Region; } } + public ArrayList CoOwners{ get{ return m_CoOwners; } set{ m_CoOwners = value; } } + public ArrayList Friends{ get{ return m_Friends; } set{ m_Friends = value; } } + public ArrayList Access{ get{ return m_Access; } set{ m_Access = value; } } + public ArrayList Bans{ get{ return m_Bans; } set{ m_Bans = value; } } + public ArrayList Doors{ get{ return m_Doors; } set{ m_Doors = value; } } + + public int GetLockdowns() + { + int count = 0; + + if ( m_LockDowns != null ) + { + for ( int i = 0; i < m_LockDowns.Count; ++i ) + { + if ( m_LockDowns[i] is Item ) + { + Item item = (Item)m_LockDowns[i]; + + if ( !(item is Container) ) + count += item.TotalItems; + } + + count++; + } + } + + return count; + } + + public int LockDownCount + { + get + { + int count = 0; + + count += GetLockdowns(); + + if ( m_Secures != null ) + { + for ( int i = 0; i < m_Secures.Count; ++i ) + { + SecureInfo info = (SecureInfo)m_Secures[i]; + + if ( info.Item.Deleted ) + continue; + else if ( info.Item is StrongBox ) + count += 1; + else + count += 125; + } + } + + return count; + } + } + + public int SecureCount + { + get + { + int count = 0; + + if ( m_Secures != null ) + { + for ( int i = 0; i < m_Secures.Count; i++ ) + { + SecureInfo info = (SecureInfo)m_Secures[i]; + + if ( info.Item.Deleted ) + continue; + else if ( !(info.Item is StrongBox) ) + count += 1; + } + } + + return count; + } + } + + public ArrayList Addons{ get{ return m_Addons; } set{ m_Addons = value; } } + public ArrayList LockDowns{ get{ return m_LockDowns; } } + public ArrayList Secures{ get{ return m_Secures; } } + public HouseSign Sign{ get{ return m_Sign; } set{ m_Sign = value; } } + public ArrayList PlayerVendors{ get{ return m_PlayerVendors; } } + public ArrayList PlayerBarkeepers{ get{ return m_PlayerBarkeepers; } } + public ArrayList VendorRentalContracts{ get{ return m_VendorRentalContracts; } } + public ArrayList VendorInventories{ get{ return m_VendorInventories; } } + public ArrayList RelocatedEntities{ get{ return m_RelocatedEntities; } } + public MovingCrate MovingCrate{ get{ return m_MovingCrate; } set{ m_MovingCrate = value; } } + public ArrayList InternalizedVendors{ get{ return m_InternalizedVendors; } } + + public DateTime BuiltOn + { + get{ return m_BuiltOn; } + set{ m_BuiltOn = value; } + } + + public DateTime LastTraded + { + get{ return m_LastTraded; } + set{ m_LastTraded = value; } + } + + public override void OnDelete() + { + RestoreRelocatedEntities(); + + new FixColumnTimer( this ).Start(); + + base.OnDelete(); + } + + private class FixColumnTimer : Timer + { + private Map m_Map; + private int m_StartX, m_StartY, m_EndX, m_EndY; + + public FixColumnTimer( BaseMulti multi ) : base( TimeSpan.Zero ) + { + m_Map = multi.Map; + + MultiComponentList mcl = multi.Components; + + m_StartX = multi.X + mcl.Min.X; + m_StartY = multi.Y + mcl.Min.Y; + m_EndX = multi.X + mcl.Max.X; + m_EndY = multi.Y + mcl.Max.Y; + } + + protected override void OnTick() + { + if ( m_Map == null ) + return; + + for ( int x = m_StartX; x <= m_EndX; ++x ) + for ( int y = m_StartY; y <= m_EndY; ++y ) + m_Map.FixColumn( x, y ); + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Owner != null ) + { + List list = null; + m_Table.TryGetValue( m_Owner, out list ); + + if ( list == null ) + m_Table[m_Owner] = list = new List(); + + list.Remove( this ); + } + + if ( m_Region != null ) + { + m_Region.Unregister(); + m_Region = null; + } + + if ( m_Sign != null ) + m_Sign.Delete(); + + if ( m_Trash != null ) + m_Trash.Delete(); + + if ( m_Doors != null ) + { + for ( int i = 0; i < m_Doors.Count; ++i ) + { + Item item = (Item)m_Doors[i]; + + if ( item != null ) + item.Delete(); + } + + m_Doors.Clear(); + } + + if ( m_LockDowns != null ) + { + for ( int i = 0; i < m_LockDowns.Count; ++i ) + { + Item item = (Item)m_LockDowns[i]; + + if ( item != null ) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + item.SetLastMoved(); + } + } + + m_LockDowns.Clear(); + } + + if ( VendorRentalContracts != null ) + { + for ( int i = 0; i < VendorRentalContracts.Count; ++i ) + { + Item item = (Item)VendorRentalContracts[i]; + + if ( item != null ) + { + item.IsLockedDown = false; + item.IsSecure = false; + item.Movable = true; + item.SetLastMoved(); + } + } + + VendorRentalContracts.Clear(); + } + + if ( m_Secures != null ) + { + for ( int i = 0; i < m_Secures.Count; ++i ) + { + SecureInfo info = (SecureInfo)m_Secures[i]; + + if ( info.Item is StrongBox ) + { + info.Item.Destroy(); + } + else + { + info.Item.IsLockedDown = false; + info.Item.IsSecure = false; + info.Item.Movable = true; + info.Item.SetLastMoved(); + } + } + + m_Secures.Clear(); + } + + if ( m_Addons != null ) + { + for ( int i = 0; i < m_Addons.Count; ++i ) + { + Item item = (Item)m_Addons[i]; + + if ( item != null ) + { + if( !item.Deleted && item is IAddon ) + { + + Item deed = ((IAddon)item).Deed; + bool retainDeedHue = false; //if the items aren't hued but the deed itself is + int hue = 0; + + if( item is BaseAddon && ((BaseAddon)item).RetainDeedHue ) //There are things that are IAddon which aren't BaseAddon + { + BaseAddon ba = (BaseAddon)item; + retainDeedHue = true; + + for( int j = 0; hue == 0 && j < ba.Components.Count; ++j ) + { + AddonComponent c = ba.Components[j]; + + if( c.Hue != 0 ) + hue = c.Hue; + } + } + + if( deed != null ) + { + if( retainDeedHue ) + deed.Hue = hue; + deed.MoveToWorld( item.Location, item.Map ); + } + } + + item.Delete(); + } + } + + m_Addons.Clear(); + } + + ArrayList inventories = new ArrayList( VendorInventories ); + + foreach ( VendorInventory inventory in inventories ) + inventory.Delete(); + + if ( MovingCrate != null ) + MovingCrate.Delete(); + + KillVendors(); + + m_AllHouses.Remove( this ); + } + + public static bool HasHouse( Mobile m ) + { + //if ( m == null ) + // return false; + + //List list = null; + //m_Table.TryGetValue( m, out list ); + + //if ( list == null ) + // return false; + + //for ( int i = 0; i < list.Count; ++i ) + //{ + // BaseHouse h = list[i]; + + // if ( !h.Deleted ) + // return true; + //} + + // Scriptiz : nombre de maisons illimit� ! + return false; + } + + public static bool HasAccountHouse( Mobile m ) + { + Account a = m.Account as Account; + + if ( a == null ) + return false; + + for ( int i = 0; i < a.Length; ++i ) + if ( a[i] != null && HasHouse( a[i] ) ) + return true; + + return false; + } + + public bool IsOwner( Mobile m ) + { + if ( m == null ) + return false; + + if ( m == m_Owner || m.AccessLevel >= AccessLevel.GameMaster ) + return true; + + return IsAosRules && AccountHandler.CheckAccount(m, m_Owner); + } + + public bool IsCoOwner( Mobile m ) + { + if ( m == null || m_CoOwners == null ) + return false; + + if ( IsOwner( m ) || m_CoOwners.Contains( m ) ) + return true; + + return !IsAosRules && AccountHandler.CheckAccount(m, m_Owner); + } + + public bool IsGuildMember( Mobile m ) + { + if( m == null || Owner == null || Owner.Guild == null ) + return false; + + return ( m.Guild == Owner.Guild ); + } + + public void RemoveKeys( Mobile m ) + { + if ( m_Doors != null ) + { + uint keyValue = 0; + + for ( int i = 0; keyValue == 0 && i < m_Doors.Count; ++i ) + { + BaseDoor door = m_Doors[i] as BaseDoor; + + if ( door != null ) + keyValue = door.KeyValue; + } + + Key.RemoveKeys( m, keyValue ); + } + } + + public void ChangeLocks( Mobile m ) + { + uint keyValue = CreateKeys( m ); + + if ( m_Doors != null ) + { + for ( int i = 0; i < m_Doors.Count; ++i ) + { + BaseDoor door = m_Doors[i] as BaseDoor; + + if ( door != null ) + door.KeyValue = keyValue; + } + } + } + + public void RemoveLocks() + { + if ( m_Doors != null ) + { + for (int i=0;i AccessLevel.Player || m_Bans == null ) + return false; + + Account theirAccount = m.Account as Account; + + for ( int i = 0; i < m_Bans.Count; ++i ) + { + Mobile c = (Mobile)m_Bans[i]; + + if ( c == m ) + return true; + + Account bannedAccount = c.Account as Account; + + if ( bannedAccount != null && bannedAccount == theirAccount ) + return true; + } + + return false; + } + + public bool HasAccess( Mobile m ) + { + if ( m == null ) + return false; + + if ( m.AccessLevel > AccessLevel.Player || IsFriend( m ) || ( m_Access != null && m_Access.Contains( m ) ) ) + return true; + + if ( m is BaseCreature ) + { + BaseCreature bc = (BaseCreature)m; + + if ( bc.NoHouseRestrictions ) + return true; + + if ( bc.Controlled || bc.Summoned ) + { + m = bc.ControlMaster; + + if ( m == null ) + m = bc.SummonMaster; + + if ( m == null ) + return false; + + if ( m.AccessLevel > AccessLevel.Player || IsFriend( m ) || ( m_Access != null && m_Access.Contains( m ) ) ) + return true; + } + } + + return false; + } + + public new bool IsLockedDown( Item check ) + { + if ( check == null ) + return false; + + if ( m_LockDowns == null ) + return false; + + return ( m_LockDowns.Contains( check ) || VendorRentalContracts.Contains( check ) ); + } + + public new bool IsSecure( Item item ) + { + if ( item == null ) + return false; + + if ( m_Secures == null ) + return false; + + bool contains = false; + + for ( int i = 0; !contains && i < m_Secures.Count; ++i ) + contains = ( ((SecureInfo)m_Secures[i]).Item == item ); + + return contains; + } + + public virtual Guildstone FindGuildstone() + { + Map map = this.Map; + + if ( map == null ) + return null; + + MultiComponentList mcl = Components; + IPooledEnumerable eable = map.GetItemsInBounds( new Rectangle2D( X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height ) ); + + foreach ( Item item in eable ) + { + if ( item is Guildstone && Contains( item ) ) + { + eable.Free(); + return (Guildstone)item; + } + } + + eable.Free(); + return null; + } + } + + public enum DecayType + { + Ageless, + AutoRefresh, + ManualRefresh, + Condemned + } + + public enum DecayLevel + { + Ageless, + LikeNew, + Slightly, + Somewhat, + Fairly, + Greatly, + IDOC, + Collapsed, + DemolitionPending + } + + public enum SecureAccessResult + { + Insecure, + Accessible, + Inaccessible + } + + public enum SecureLevel + { + Owner, + CoOwners, + Friends, + Anyone, + Guild + } + + public class SecureInfo : ISecurable + { + private Container m_Item; + private SecureLevel m_Level; + + public Container Item{ get{ return m_Item; } } + public SecureLevel Level{ get{ return m_Level; } set{ m_Level = value; } } + + public SecureInfo( Container item, SecureLevel level ) + { + m_Item = item; + m_Level = level; + } + + public SecureInfo( GenericReader reader ) + { + m_Item = reader.ReadItem() as Container; + m_Level = (SecureLevel)reader.ReadByte(); + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( m_Item ); + writer.Write( (byte) m_Level ); + } + } + + public class RelocatedEntity + { + private IEntity m_Entity; + private Point3D m_RelativeLocation; + + public IEntity Entity + { + get{ return m_Entity; } + } + + public Point3D RelativeLocation + { + get{ return m_RelativeLocation; } + } + + public RelocatedEntity( IEntity entity, Point3D relativeLocation ) + { + m_Entity = entity; + m_RelativeLocation = relativeLocation; + } + } + + #region Targets + + public class LockdownTarget : Target + { + private bool m_Release; + private BaseHouse m_House; + + public LockdownTarget( bool release, BaseHouse house ) : base( 12, false, TargetFlags.None ) + { + CheckLOS = false; + + m_Release = release; + m_House = house; + } + + protected override void OnTargetNotAccessible( Mobile from, object targeted ) + { + OnTarget( from, targeted ); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsCoOwner( from ) ) + return; + + if ( targeted is Item ) + { + if ( m_Release ) + { + m_House.Release( from, (Item)targeted ); + } + else + { + if ( targeted is VendorRentalContract ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1062392 ); // You must double click the contract in your pack to lock it down. + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501732 ); // I cannot lock this down! + } + else if ( (Item)targeted is AddonComponent ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 501727 ); // You cannot lock that down! + from.LocalOverheadMessage( MessageType.Regular, 0x3E9, 501732 ); // I cannot lock this down! + } + else + { + m_House.LockDown( from, (Item)targeted ); + } + } + } + else if ( targeted is StaticTarget ) + { + return; + } + else + { + from.SendLocalizedMessage( 1005377 ); //You cannot lock that down + } + } + } + + public class SecureTarget : Target + { + private bool m_Release; + private BaseHouse m_House; + + public SecureTarget( bool release, BaseHouse house ) : base( 12, false, TargetFlags.None ) + { + CheckLOS = false; + + m_Release = release; + m_House = house; + } + + protected override void OnTargetNotAccessible( Mobile from, object targeted ) + { + OnTarget( from, targeted ); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsCoOwner( from ) ) + return; + + if ( targeted is Item ) + { + if ( m_Release ) + { + m_House.ReleaseSecure( from, (Item)targeted ); + } + else + { + if ( targeted is VendorRentalContract ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1062392 ); // You must double click the contract in your pack to lock it down. + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501732 ); // I cannot lock this down! + } + else + { + m_House.AddSecure( from, (Item)targeted ); + } + } + } + else + { + from.SendLocalizedMessage( 1010424 );//You cannot secure this + } + } + } + + public class HouseKickTarget : Target + { + private BaseHouse m_House; + + public HouseKickTarget( BaseHouse house ) : base( -1, false, TargetFlags.None ) + { + CheckLOS = false; + + m_House = house; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsFriend( from ) ) + return; + + if ( targeted is Mobile ) + { + m_House.Kick( from, (Mobile)targeted ); + } + else + { + from.SendLocalizedMessage( 501347 );//You cannot eject that from the house! + } + } + } + + public class HouseBanTarget : Target + { + private BaseHouse m_House; + private bool m_Banning; + + public HouseBanTarget( bool ban, BaseHouse house ) : base( -1, false, TargetFlags.None ) + { + CheckLOS = false; + + m_House = house; + m_Banning = ban; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsFriend( from ) ) + return; + + if ( targeted is Mobile ) + { + if ( m_Banning ) + m_House.Ban( from, (Mobile)targeted ); + else + m_House.RemoveBan( from, (Mobile)targeted ); + } + else + { + from.SendLocalizedMessage( 501347 );//You cannot eject that from the house! + } + } + } + + public class HouseAccessTarget : Target + { + private BaseHouse m_House; + + public HouseAccessTarget( BaseHouse house ) : base( -1, false, TargetFlags.None ) + { + CheckLOS = false; + + m_House = house; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsFriend( from ) ) + return; + + if ( targeted is Mobile ) + m_House.GrantAccess( from, (Mobile)targeted ); + else + from.SendLocalizedMessage( 1060712 ); // That is not a player. + } + } + + public class CoOwnerTarget : Target + { + private BaseHouse m_House; + private bool m_Add; + + public CoOwnerTarget( bool add, BaseHouse house ) : base( 12, false, TargetFlags.None ) + { + CheckLOS = false; + + m_House = house; + m_Add = add; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsOwner( from ) ) + return; + + if ( targeted is Mobile ) + { + if ( m_Add ) + m_House.AddCoOwner( from, (Mobile)targeted ); + else + m_House.RemoveCoOwner( from, (Mobile)targeted ); + } + else + { + from.SendLocalizedMessage( 501362 );//That can't be a coowner + } + } + } + + public class HouseFriendTarget : Target + { + private BaseHouse m_House; + private bool m_Add; + + public HouseFriendTarget( bool add, BaseHouse house ) : base( 12, false, TargetFlags.None ) + { + CheckLOS = false; + + m_House = house; + m_Add = add; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive || m_House.Deleted || !m_House.IsCoOwner( from ) ) + return; + + if ( targeted is Mobile ) + { + if ( m_Add ) + m_House.AddFriend( from, (Mobile)targeted ); + else + m_House.RemoveFriend( from, (Mobile)targeted ); + } + else + { + from.SendLocalizedMessage( 501371 ); // That can't be a friend + } + } + } + + public class HouseOwnerTarget : Target + { + private BaseHouse m_House; + + public HouseOwnerTarget( BaseHouse house ) : base( 12, false, TargetFlags.None ) + { + CheckLOS = false; + + m_House = house; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + m_House.BeginConfirmTransfer( from, (Mobile)targeted ); + else + from.SendLocalizedMessage( 501384 ); // Only a player can own a house! + } + } + + #endregion + + public class SetSecureLevelEntry : ContextMenuEntry + { + private Item m_Item; + private ISecurable m_Securable; + + public SetSecureLevelEntry( Item item, ISecurable securable ) : base( 6203, 6 ) + { + m_Item = item; + m_Securable = securable; + } + + public static ISecurable GetSecurable( Mobile from, Item item ) + { + BaseHouse house = BaseHouse.FindHouseAt( item ); + + if ( house == null || !house.IsOwner( from ) || !house.IsAosRules ) + return null; + + ISecurable sec = null; + + if ( item is ISecurable ) + { + bool isOwned = house.Doors.Contains( item ); + + if ( !isOwned ) + isOwned = ( house is HouseFoundation && ((HouseFoundation)house).IsFixture( item ) ); + + if ( !isOwned ) + isOwned = house.IsLockedDown( item ); + + if ( isOwned ) + sec = (ISecurable)item; + } + else + { + ArrayList list = house.Secures; + + for ( int i = 0; sec == null && list != null && i < list.Count; ++i ) + { + SecureInfo si = (SecureInfo)list[i]; + + if ( si.Item == item ) + sec = si; + } + } + + return sec; + } + + public static void AddTo( Mobile from, Item item, List list ) + { + ISecurable sec = GetSecurable( from, item ); + + if ( sec != null ) + list.Add( new SetSecureLevelEntry( item, sec ) ); + } + + public override void OnClick() + { + ISecurable sec = GetSecurable( Owner.From, m_Item ); + + if ( sec != null ) + { + Owner.From.CloseGump( typeof ( SetSecureLevelGump ) ); + Owner.From.SendGump( new SetSecureLevelGump( Owner.From, sec, BaseHouse.FindHouseAt( m_Item ) ) ); + } + } + } + + public class TempNoHousingRegion : BaseRegion + { + private Mobile m_RegionOwner; + + public TempNoHousingRegion(BaseHouse house, Mobile regionowner) + : base(null, house.Map, Region.DefaultPriority, house.Region.Area) + { + Register(); + + m_RegionOwner = regionowner; + + Timer.DelayCall(house.RestrictedPlacingTime, Unregister); + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + return ( from == m_RegionOwner || AccountHandler.CheckAccount( from, m_RegionOwner ) ); + } + } +} + diff --git a/Scripts/Multis/Boats/BaseBoat.cs b/Scripts/Multis/Boats/BaseBoat.cs new file mode 100644 index 0000000..d3aa38c --- /dev/null +++ b/Scripts/Multis/Boats/BaseBoat.cs @@ -0,0 +1,1931 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Movement; +using Server.Network; + +namespace Server.Multis +{ + public enum BoatOrder + { + Move, + Course, + Single + } + + public abstract class BaseBoat : BaseMulti + { + private static Rectangle2D[] m_BritWrap = new Rectangle2D[]{ new Rectangle2D( 16, 16, 5120 - 32, 4096 - 32 ), new Rectangle2D( 5136, 2320, 992, 1760 ) }; + private static Rectangle2D[] m_IlshWrap = new Rectangle2D[]{ new Rectangle2D( 16, 16, 2304 - 32, 1600 - 32 ) }; + private static Rectangle2D[] m_TokunoWrap = new Rectangle2D[] { new Rectangle2D( 16, 16, 1448 - 32, 1448 - 32 ) }; + + private static TimeSpan BoatDecayDelay = TimeSpan.FromDays( 9.0 ); + + public static BaseBoat FindBoatAt( IPoint2D loc, Map map ) + { + Sector sector = map.GetSector( loc ); + + for ( int i = 0; i < sector.Multis.Count; i++ ) + { + BaseBoat boat = sector.Multis[i] as BaseBoat; + + if ( boat != null && boat.Contains( loc.X, loc.Y ) ) + return boat; + } + + return null; + } + + private Hold m_Hold; + private TillerMan m_TillerMan; + private Mobile m_Owner; + + private Direction m_Facing; + + private Direction m_Moving; + private int m_Speed; + private int m_ClientSpeed; + + private bool m_Anchored; + private string m_ShipName; + + private BoatOrder m_Order; + + private MapItem m_MapItem; + private int m_NextNavPoint; + + private Plank m_PPlank, m_SPlank; + + private DateTime m_DecayTime; + + private Timer m_TurnTimer; + private Timer m_MoveTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public Hold Hold{ get{ return m_Hold; } set{ m_Hold = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public TillerMan TillerMan{ get{ return m_TillerMan; } set{ m_TillerMan = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Plank PPlank{ get{ return m_PPlank; } set{ m_PPlank = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Plank SPlank{ get{ return m_SPlank; } set{ m_SPlank = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner{ get{ return m_Owner; } set{ m_Owner = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Direction Facing{ get{ return m_Facing; } set{ SetFacing( value ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public Direction Moving{ get{ return m_Moving; } set{ m_Moving = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsMoving{ get{ return ( m_MoveTimer != null ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Speed{ get{ return m_Speed; } set{ m_Speed = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Anchored{ get{ return m_Anchored; } set{ m_Anchored = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string ShipName{ get{ return m_ShipName; } set{ m_ShipName = value; if ( m_TillerMan != null ) m_TillerMan.InvalidateProperties(); } } + + [CommandProperty( AccessLevel.GameMaster )] + public BoatOrder Order{ get{ return m_Order; } set{ m_Order = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public MapItem MapItem{ get{ return m_MapItem; } set{ m_MapItem = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int NextNavPoint{ get{ return m_NextNavPoint; } set{ m_NextNavPoint = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime TimeOfDecay{ get{ return m_DecayTime; } set{ m_DecayTime = value; if ( m_TillerMan != null ) m_TillerMan.InvalidateProperties(); } } + + public int Status + { + get + { + DateTime start = TimeOfDecay - BoatDecayDelay; + + if ( DateTime.Now - start < TimeSpan.FromHours( 1.0 ) ) + return 1043010; // This structure is like new. + + if ( DateTime.Now - start < TimeSpan.FromDays( 2.0 ) ) + return 1043011; // This structure is slightly worn. + + if ( DateTime.Now - start < TimeSpan.FromDays( 3.0 ) ) + return 1043012; // This structure is somewhat worn. + + if ( DateTime.Now - start < TimeSpan.FromDays( 4.0 ) ) + return 1043013; // This structure is fairly worn. + + if ( DateTime.Now - start < TimeSpan.FromDays( 5.0 ) ) + return 1043014; // This structure is greatly worn. + + return 1043015; // This structure is in danger of collapsing. + } + } + + public virtual int NorthID{ get{ return 0; } } + public virtual int EastID{ get{ return 0; } } + public virtual int SouthID{ get{ return 0; } } + public virtual int WestID{ get{ return 0; } } + + public virtual int HoldDistance{ get{ return 0; } } + public virtual int TillerManDistance{ get{ return 0; } } + public virtual Point2D StarboardOffset{ get{ return Point2D.Zero; } } + public virtual Point2D PortOffset{ get{ return Point2D.Zero; } } + public virtual Point3D MarkOffset{ get{ return Point3D.Zero; } } + + public virtual BaseDockedBoat DockedBoat{ get{ return null; } } + + private static List m_Instances = new List(); + + public static List Boats{ get{ return m_Instances; } } + + public BaseBoat() : base( 0x0 ) + { + m_DecayTime = DateTime.Now + BoatDecayDelay; + + m_TillerMan = new TillerMan( this ); + m_Hold = new Hold( this ); + + m_PPlank = new Plank( this, PlankSide.Port, 0 ); + m_SPlank = new Plank( this, PlankSide.Starboard, 0 ); + + m_PPlank.MoveToWorld( new Point3D( X + PortOffset.X, Y + PortOffset.Y, Z ), Map ); + m_SPlank.MoveToWorld( new Point3D( X + StarboardOffset.X, Y + StarboardOffset.Y, Z ), Map ); + + Facing = Direction.North; + + m_NextNavPoint = -1; + + Movable = false; + + m_Instances.Add( this ); + } + + public BaseBoat( Serial serial ) : base( serial ) + { + } + + public Point3D GetRotatedLocation( int x, int y ) + { + Point3D p = new Point3D( X + x, Y + y, Z ); + + return Rotate( p, (int)m_Facing / 2 ); + } + + public void UpdateComponents() + { + if ( m_PPlank != null ) + { + m_PPlank.MoveToWorld( GetRotatedLocation( PortOffset.X, PortOffset.Y ), Map ); + m_PPlank.SetFacing( m_Facing ); + } + + if ( m_SPlank != null ) + { + m_SPlank.MoveToWorld( GetRotatedLocation( StarboardOffset.X, StarboardOffset.Y ), Map ); + m_SPlank.SetFacing( m_Facing ); + } + + int xOffset = 0, yOffset = 0; + Movement.Movement.Offset( m_Facing, ref xOffset, ref yOffset ); + + if ( m_TillerMan != null ) + { + m_TillerMan.Location = new Point3D( X + (xOffset * TillerManDistance) + (m_Facing == Direction.North ? 1 : 0), Y + (yOffset * TillerManDistance), m_TillerMan.Z ); + m_TillerMan.SetFacing( m_Facing ); + m_TillerMan.InvalidateProperties(); + } + + if ( m_Hold != null ) + { + m_Hold.Location = new Point3D( X + (xOffset * HoldDistance), Y + (yOffset * HoldDistance), m_Hold.Z ); + m_Hold.SetFacing( m_Facing ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 3 ); + + writer.Write( (Item) m_MapItem ); + writer.Write( (int) m_NextNavPoint ); + + writer.Write( (int) m_Facing ); + + writer.WriteDeltaTime( m_DecayTime ); + + writer.Write( m_Owner ); + writer.Write( m_PPlank ); + writer.Write( m_SPlank ); + writer.Write( m_TillerMan ); + writer.Write( m_Hold ); + writer.Write( m_Anchored ); + writer.Write( m_ShipName ); + + CheckDecay(); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 3: + { + m_MapItem = (MapItem) reader.ReadItem(); + m_NextNavPoint = reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_Facing = (Direction)reader.ReadInt(); + + goto case 1; + } + case 1: + { + m_DecayTime = reader.ReadDeltaTime(); + + goto case 0; + } + case 0: + { + if ( version < 3 ) + m_NextNavPoint = -1; + + if ( version < 2 ) + { + if ( ItemID == NorthID ) + m_Facing = Direction.North; + else if ( ItemID == SouthID ) + m_Facing = Direction.South; + else if ( ItemID == EastID ) + m_Facing = Direction.East; + else if ( ItemID == WestID ) + m_Facing = Direction.West; + } + + m_Owner = reader.ReadMobile(); + m_PPlank = reader.ReadItem() as Plank; + m_SPlank = reader.ReadItem() as Plank; + m_TillerMan = reader.ReadItem() as TillerMan; + m_Hold = reader.ReadItem() as Hold; + m_Anchored = reader.ReadBool(); + m_ShipName = reader.ReadString(); + + if ( version < 1) + Refresh(); + + break; + } + } + + m_Instances.Add( this ); + } + + public void RemoveKeys( Mobile m ) + { + uint keyValue = 0; + + if ( m_PPlank != null ) + keyValue = m_PPlank.KeyValue; + + if ( keyValue == 0 && m_SPlank != null ) + keyValue = m_SPlank.KeyValue; + + Key.RemoveKeys( m, keyValue ); + } + + public uint CreateKeys( Mobile m ) + { + uint value = Key.RandomValue(); + + Key packKey = new Key( KeyType.Gold, value, this ); + Key bankKey = new Key( KeyType.Gold, value, this ); + + packKey.MaxRange = 10; + bankKey.MaxRange = 10; + + packKey.Name = "a ship key"; + bankKey.Name = "a ship key"; + + BankBox box = m.BankBox; + + if ( !box.TryDropItem( m, bankKey, false ) ) + bankKey.Delete(); + else + m.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502484 ); // A ship's key is now in my safety deposit box. + + if ( m.AddToBackpack( packKey ) ) + m.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502485 ); // A ship's key is now in my backpack. + else + m.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502483 ); // A ship's key is now at my feet. + + return value; + } + + public override void OnAfterDelete() + { + if ( m_TillerMan != null ) + m_TillerMan.Delete(); + + if ( m_Hold != null ) + m_Hold.Delete(); + + if ( m_PPlank != null ) + m_PPlank.Delete(); + + if ( m_SPlank != null ) + m_SPlank.Delete(); + + if ( m_TurnTimer != null ) + m_TurnTimer.Stop(); + + if ( m_MoveTimer != null ) + m_MoveTimer.Stop(); + + m_Instances.Remove( this ); + } + + public override void OnLocationChange( Point3D old ) + { + if ( m_TillerMan != null ) + m_TillerMan.Location = new Point3D( X + (m_TillerMan.X - old.X), Y + (m_TillerMan.Y - old.Y), Z + (m_TillerMan.Z - old.Z ) ); + + if ( m_Hold != null ) + m_Hold.Location = new Point3D( X + (m_Hold.X - old.X), Y + (m_Hold.Y - old.Y), Z + (m_Hold.Z - old.Z ) ); + + if ( m_PPlank != null ) + m_PPlank.Location = new Point3D( X + (m_PPlank.X - old.X), Y + (m_PPlank.Y - old.Y), Z + (m_PPlank.Z - old.Z ) ); + + if ( m_SPlank != null ) + m_SPlank.Location = new Point3D( X + (m_SPlank.X - old.X), Y + (m_SPlank.Y - old.Y), Z + (m_SPlank.Z - old.Z ) ); + } + + public override void OnMapChange() + { + if ( m_TillerMan != null ) + m_TillerMan.Map = Map; + + if ( m_Hold != null ) + m_Hold.Map = Map; + + if ( m_PPlank != null ) + m_PPlank.Map = Map; + + if ( m_SPlank != null ) + m_SPlank.Map = Map; + } + + public bool CanCommand( Mobile m ) + { + return true; + } + + public Point3D GetMarkedLocation() + { + Point3D p = new Point3D( X + MarkOffset.X, Y + MarkOffset.Y, Z + MarkOffset.Z ); + + return Rotate( p, (int)m_Facing / 2 ); + } + + public bool CheckKey( uint keyValue ) + { + if ( m_SPlank != null && m_SPlank.KeyValue == keyValue ) + return true; + + if ( m_PPlank != null && m_PPlank.KeyValue == keyValue ) + return true; + + return false; + } + + /* + * Intervals: + * drift forward + * fast | 0.25| 0.25 + * slow | 0.50| 0.50 + * + * Speed: + * drift forward + * fast | 0x4| 0x4 + * slow | 0x3| 0x3 + * + * Tiles (per interval): + * drift forward + * fast | 1| 1 + * slow | 1| 1 + * + * 'walking' in piloting mode has a 1s interval, speed 0x2 + */ + + private static bool NewBoatMovement { get { return Core.HS; } } + + private static TimeSpan SlowInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.50 : 0.75); + private static TimeSpan FastInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.25 : 0.75); + + private static int SlowSpeed = 1; + private static int FastSpeed = NewBoatMovement ? 1 : 3; + + private static TimeSpan SlowDriftInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.50 : 1.50); + private static TimeSpan FastDriftInterval = TimeSpan.FromSeconds(NewBoatMovement ? 0.25 : 0.75); + + private static int SlowDriftSpeed = 1; + private static int FastDriftSpeed = 1; + + private static Direction Forward = Direction.North; + private static Direction ForwardLeft = Direction.Up; + private static Direction ForwardRight = Direction.Right; + private static Direction Backward = Direction.South; + private static Direction BackwardLeft = Direction.Left; + private static Direction BackwardRight = Direction.Down; + private static Direction Left = Direction.West; + private static Direction Right = Direction.East; + private static Direction Port = Left; + private static Direction Starboard = Right; + + private bool m_Decaying; + + public void Refresh() + { + m_DecayTime = DateTime.Now + BoatDecayDelay; + + if( m_TillerMan != null ) + m_TillerMan.InvalidateProperties(); + } + + private class DecayTimer : Timer + { + private BaseBoat m_Boat; + private int m_Count; + + public DecayTimer( BaseBoat boat ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + m_Boat = boat; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if ( m_Count == 5 ) + { + m_Boat.Delete(); + Stop(); + } + else + { + m_Boat.Location = new Point3D( m_Boat.X, m_Boat.Y, m_Boat.Z - 1 ); + + if ( m_Boat.TillerMan != null ) + m_Boat.TillerMan.Say( 1007168 + m_Count ); + + ++m_Count; + } + } + } + + public bool CheckDecay() + { + if ( m_Decaying ) + return true; + + if ( !IsMoving && DateTime.Now >= m_DecayTime ) + { + new DecayTimer( this ).Start(); + + m_Decaying = true; + + return true; + } + + return false; + } + + public bool LowerAnchor( bool message ) + { + if ( CheckDecay() ) + return false; + + if ( m_Anchored ) + { + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501445 ); // Ar, the anchor was already dropped sir. + + return false; + } + + StopMove( false ); + + m_Anchored = true; + + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501444 ); // Ar, anchor dropped sir. + + return true; + } + + public bool RaiseAnchor( bool message ) + { + if ( CheckDecay() ) + return false; + + if ( !m_Anchored ) + { + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501447 ); // Ar, the anchor has not been dropped sir. + + return false; + } + + m_Anchored = false; + + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501446 ); // Ar, anchor raised sir. + + return true; + } + + public bool StartMove(Direction dir, bool fast) + { + if (CheckDecay()) + return false; + + bool drift = (dir != Forward && dir != ForwardLeft && dir != ForwardRight); + TimeSpan interval = (fast ? (drift ? FastDriftInterval : FastInterval) : (drift ? SlowDriftInterval : SlowInterval)); + int speed = (fast ? (drift ? FastDriftSpeed : FastSpeed) : (drift ? SlowDriftSpeed : SlowSpeed)); + int clientSpeed = fast ? 0x4 : 0x3; + + if (StartMove(dir, speed, clientSpeed, interval, false, true)) + { + if (m_TillerMan != null) + m_TillerMan.Say(501429); // Aye aye sir. + + return true; + } + + return false; + } + + public bool OneMove( Direction dir ) + { + if ( CheckDecay() ) + return false; + + bool drift = ( dir != Forward ); + TimeSpan interval = drift ? FastDriftInterval : FastInterval; + int speed = drift ? FastDriftSpeed : FastSpeed; + + if ( StartMove( dir, speed, 0x1, interval, true, true ) ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 501429 ); // Aye aye sir. + + return true; + } + + return false; + } + + public void BeginRename( Mobile from ) + { + if ( CheckDecay() ) + return; + + if ( from.AccessLevel < AccessLevel.GameMaster && from != m_Owner ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( Utility.Random( 1042876, 4 ) ); // Arr, don't do that! | Arr, leave me alone! | Arr, watch what thour'rt doing, matey! | Arr! Do that again and I�ll throw ye overhead! + + return; + } + + if ( m_TillerMan != null ) + m_TillerMan.Say( 502580 ); // What dost thou wish to name thy ship? + + from.Prompt = new RenameBoatPrompt( this ); + } + + public void EndRename( Mobile from, string newName ) + { + if ( Deleted || CheckDecay() ) + return; + + if ( from.AccessLevel < AccessLevel.GameMaster && from != m_Owner ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 1042880 ); // Arr! Only the owner of the ship may change its name! + + return; + } + else if ( !from.Alive ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 502582 ); // You appear to be dead. + + return; + } + + newName = newName.Trim(); + + if ( newName.Length == 0 ) + newName = null; + + Rename( newName ); + } + + public enum DryDockResult{ Valid, Dead, NoKey, NotAnchored, Mobiles, Items, Hold, Decaying } + + public DryDockResult CheckDryDock( Mobile from ) + { + if ( CheckDecay() ) + return DryDockResult.Decaying; + + if ( !from.Alive ) + return DryDockResult.Dead; + + Container pack = from.Backpack; + if ( (m_SPlank == null || !Key.ContainsKey( pack, m_SPlank.KeyValue )) && (m_PPlank == null || !Key.ContainsKey( pack, m_PPlank.KeyValue )) ) + return DryDockResult.NoKey; + + if ( !m_Anchored ) + return DryDockResult.NotAnchored; + + if ( m_Hold != null && m_Hold.Items.Count > 0 ) + return DryDockResult.Hold; + + Map map = Map; + + if ( map == null || map == Map.Internal ) + return DryDockResult.Items; + + List ents = GetMovingEntities(); + + if ( ents.Count >= 1 ) + return ( ents[0] is Mobile ) ? DryDockResult.Mobiles : DryDockResult.Items; + + return DryDockResult.Valid; + } + + public void BeginDryDock( Mobile from ) + { + if ( CheckDecay() ) + return; + + DryDockResult result = CheckDryDock( from ); + + if ( result == DryDockResult.Dead ) + from.SendLocalizedMessage( 502493 ); // You appear to be dead. + else if ( result == DryDockResult.NoKey ) + from.SendLocalizedMessage( 502494 ); // You must have a key to the ship to dock the boat. + else if ( result == DryDockResult.NotAnchored ) + from.SendLocalizedMessage( 1010570 ); // You must lower the anchor to dock the boat. + else if ( result == DryDockResult.Mobiles ) + from.SendLocalizedMessage( 502495 ); // You cannot dock the ship with beings on board! + else if ( result == DryDockResult.Items ) + from.SendLocalizedMessage( 502496 ); // You cannot dock the ship with a cluttered deck. + else if ( result == DryDockResult.Hold ) + from.SendLocalizedMessage( 502497 ); // Make sure your hold is empty, and try again! + else if ( result == DryDockResult.Valid ) + from.SendGump( new ConfirmDryDockGump( from, this ) ); + } + + public void EndDryDock( Mobile from ) + { + if ( Deleted || CheckDecay() ) + return; + + DryDockResult result = CheckDryDock( from ); + + if ( result == DryDockResult.Dead ) + from.SendLocalizedMessage( 502493 ); // You appear to be dead. + else if ( result == DryDockResult.NoKey ) + from.SendLocalizedMessage( 502494 ); // You must have a key to the ship to dock the boat. + else if ( result == DryDockResult.NotAnchored ) + from.SendLocalizedMessage( 1010570 ); // You must lower the anchor to dock the boat. + else if ( result == DryDockResult.Mobiles ) + from.SendLocalizedMessage( 502495 ); // You cannot dock the ship with beings on board! + else if ( result == DryDockResult.Items ) + from.SendLocalizedMessage( 502496 ); // You cannot dock the ship with a cluttered deck. + else if ( result == DryDockResult.Hold ) + from.SendLocalizedMessage( 502497 ); // Make sure your hold is empty, and try again! + + if ( result != DryDockResult.Valid ) + return; + + BaseDockedBoat boat = DockedBoat; + + if ( boat == null ) + return; + + RemoveKeys( from ); + + from.AddToBackpack( boat ); + Delete(); + } + + public void SetName( SpeechEventArgs e ) + { + if ( CheckDecay() ) + return; + + if ( e.Mobile.AccessLevel < AccessLevel.GameMaster && e.Mobile != m_Owner ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 1042880 ); // Arr! Only the owner of the ship may change its name! + + return; + } + else if ( !e.Mobile.Alive ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 502582 ); // You appear to be dead. + + return; + } + + if ( e.Speech.Length > 8 ) + { + string newName = e.Speech.Substring( 8 ).Trim(); + + if ( newName.Length == 0 ) + newName = null; + + Rename( newName ); + } + } + + public void Rename( string newName ) + { + if ( CheckDecay() ) + return; + + if ( newName != null && newName.Length > 40 ) + newName = newName.Substring( 0, 40 ); + + if ( m_ShipName == newName ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 502531 ); // Yes, sir. + + return; + } + + ShipName = newName; + + if ( m_TillerMan != null && m_ShipName != null ) + m_TillerMan.Say( 1042885, m_ShipName ); // This ship is now called the ~1_NEW_SHIP_NAME~. + else if ( m_TillerMan != null ) + m_TillerMan.Say( 502534 ); // This ship now has no name. + } + + public void RemoveName( Mobile m ) + { + if ( CheckDecay() ) + return; + + if ( m.AccessLevel < AccessLevel.GameMaster && m != m_Owner ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 1042880 ); // Arr! Only the owner of the ship may change its name! + + return; + } + else if ( !m.Alive ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 502582 ); // You appear to be dead. + + return; + } + + if ( m_ShipName == null ) + { + if ( m_TillerMan != null ) + m_TillerMan.Say( 502526 ); // Ar, this ship has no name. + + return; + } + + ShipName = null; + + if ( m_TillerMan != null ) + m_TillerMan.Say( 502534 ); // This ship now has no name. + } + + public void GiveName( Mobile m ) + { + if ( m_TillerMan == null || CheckDecay() ) + return; + + if ( m_ShipName == null ) + m_TillerMan.Say( 502526 ); // Ar, this ship has no name. + else + m_TillerMan.Say( 1042881, m_ShipName ); // This is the ~1_BOAT_NAME~. + } + + public void GiveNavPoint() + { + if ( TillerMan == null || CheckDecay() ) + return; + + if ( NextNavPoint < 0 ) + TillerMan.Say( 1042882 ); // I have no current nav point. + else + TillerMan.Say( 1042883, (NextNavPoint + 1).ToString() ); // My current destination navpoint is nav ~1_NAV_POINT_NUM~. + } + + public void AssociateMap( MapItem map ) + { + if ( CheckDecay() ) + return; + + if ( map is BlankMap ) + { + if ( TillerMan != null ) + TillerMan.Say( 502575 ); // Ar, that is not a map, tis but a blank piece of paper! + } + else if ( map.Pins.Count == 0 ) + { + if ( TillerMan != null ) + TillerMan.Say( 502576 ); // Arrrr, this map has no course on it! + } + else + { + StopMove( false ); + + MapItem = map; + NextNavPoint = -1; + + if ( TillerMan != null ) + TillerMan.Say( 502577 ); // A map! + } + } + + public bool StartCourse( string navPoint, bool single, bool message ) + { + int number = -1; + + int start = -1; + for ( int i = 0; i < navPoint.Length; i++ ) + { + if ( Char.IsDigit( navPoint[i] ) ) + { + start = i; + break; + } + } + + if ( start != -1 ) + { + string sNumber = navPoint.Substring( start ); + + if ( !int.TryParse( sNumber, out number ) ) + number = -1; + + if ( number != -1 ) + { + number--; + + if ( MapItem == null || number < 0 || number >= MapItem.Pins.Count ) + { + number = -1; + } + } + } + + if ( number == -1 ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 1042551 ); // I don't see that navpoint, sir. + + return false; + } + + NextNavPoint = number; + return StartCourse( single, message ); + } + + public bool StartCourse( bool single, bool message ) + { + if ( CheckDecay() ) + return false; + + if ( Anchored ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 501419 ); // Ar, the anchor is down sir! + + return false; + } + else if ( MapItem == null || MapItem.Deleted ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 502513 ); // I have seen no map, sir. + + return false; + } + else if ( this.Map != MapItem.Map || !this.Contains( MapItem.GetWorldLocation() ) ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 502514 ); // The map is too far away from me, sir. + + return false; + } + else if ( ( this.Map != Map.Trammel && this.Map != Map.Felucca ) || NextNavPoint < 0 || NextNavPoint >= MapItem.Pins.Count ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 1042551 ); // I don't see that navpoint, sir. + + return false; + } + + Speed = FastSpeed; + Order = single ? BoatOrder.Single : BoatOrder.Course; + + if ( m_MoveTimer != null ) + m_MoveTimer.Stop(); + + m_MoveTimer = new MoveTimer( this, FastInterval, false ); + m_MoveTimer.Start(); + + if ( message && TillerMan != null ) + TillerMan.Say( 501429 ); // Aye aye sir. + + return true; + } + + public override bool HandlesOnSpeech{ get{ return true; } } + + public override void OnSpeech( SpeechEventArgs e ) + { + if ( CheckDecay() ) + return; + + Mobile from = e.Mobile; + + if ( CanCommand( from ) && Contains( from ) ) + { + for ( int i = 0; i < e.Keywords.Length; ++i ) + { + int keyword = e.Keywords[i]; + + if ( keyword >= 0x42 && keyword <= 0x6B ) + { + switch ( keyword ) + { + case 0x42: SetName( e ); break; + case 0x43: RemoveName( e.Mobile ); break; + case 0x44: GiveName( e.Mobile ); break; + case 0x45: StartMove( Forward, true ); break; + case 0x46: StartMove( Backward, true ); break; + case 0x47: StartMove( Left, true ); break; + case 0x48: StartMove( Right, true ); break; + case 0x4B: StartMove( ForwardLeft, true ); break; + case 0x4C: StartMove( ForwardRight, true ); break; + case 0x4D: StartMove( BackwardLeft, true ); break; + case 0x4E: StartMove( BackwardRight, true ); break; + case 0x4F: StopMove( true ); break; + case 0x50: StartMove( Left, false ); break; + case 0x51: StartMove( Right, false ); break; + case 0x52: StartMove( Forward, false ); break; + case 0x53: StartMove( Backward, false ); break; + case 0x54: StartMove( ForwardLeft, false ); break; + case 0x55: StartMove( ForwardRight, false ); break; + case 0x56: StartMove( BackwardRight, false ); break; + case 0x57: StartMove( BackwardLeft, false ); break; + case 0x58: OneMove( Left ); break; + case 0x59: OneMove( Right ); break; + case 0x5A: OneMove( Forward ); break; + case 0x5B: OneMove( Backward ); break; + case 0x5C: OneMove( ForwardLeft ); break; + case 0x5D: OneMove( ForwardRight ); break; + case 0x5E: OneMove( BackwardRight ); break; + case 0x5F: OneMove( BackwardLeft ); break; + case 0x49: case 0x65: StartTurn( 2, true ); break; // turn right + case 0x4A: case 0x66: StartTurn( -2, true ); break; // turn left + case 0x67: StartTurn( -4, true ); break; // turn around, come about + case 0x68: StartMove( Forward, true ); break; + case 0x69: StopMove( true ); break; + case 0x6A: LowerAnchor( true ); break; + case 0x6B: RaiseAnchor( true ); break; + case 0x60: GiveNavPoint(); break; // nav + case 0x61: NextNavPoint = 0; StartCourse( false, true ); break; // start + case 0x62: StartCourse( false, true ); break; // continue + case 0x63: StartCourse( e.Speech, false, true ); break; // goto* + case 0x64: StartCourse( e.Speech, true, true ); break; // single* + } + + break; + } + } + } + } + + public bool StartTurn( int offset, bool message ) + { + if ( CheckDecay() ) + return false; + + if ( m_Anchored ) + { + if ( message ) + m_TillerMan.Say( 501419 ); // Ar, the anchor is down sir! + + return false; + } + else + { + if ( m_MoveTimer != null && this.Order != BoatOrder.Move ) + { + m_MoveTimer.Stop(); + m_MoveTimer = null; + } + + if ( m_TurnTimer != null ) + m_TurnTimer.Stop(); + + m_TurnTimer = new TurnTimer( this, offset ); + m_TurnTimer.Start(); + + if ( message && TillerMan != null ) + TillerMan.Say( 501429 ); // Aye aye sir. + + return true; + } + } + + public bool Turn( int offset, bool message ) + { + if ( m_TurnTimer != null ) + { + m_TurnTimer.Stop(); + m_TurnTimer = null; + } + + if ( CheckDecay() ) + return false; + + if ( m_Anchored ) + { + if ( message ) + m_TillerMan.Say( 501419 ); // Ar, the anchor is down sir! + + return false; + } + else if ( SetFacing( (Direction)(((int)m_Facing + offset) & 0x7) ) ) + { + return true; + } + else + { + if ( message ) + m_TillerMan.Say( 501423 ); // Ar, can't turn sir. + + return false; + } + } + + private class TurnTimer : Timer + { + private BaseBoat m_Boat; + private int m_Offset; + + public TurnTimer( BaseBoat boat, int offset ) : base( TimeSpan.FromSeconds( 0.5 ) ) + { + m_Boat = boat; + m_Offset = offset; + + Priority = TimerPriority.TenMS; + } + + protected override void OnTick() + { + if ( !m_Boat.Deleted ) + m_Boat.Turn( m_Offset, true ); + } + } + + public bool StartMove(Direction dir, int speed, int clientSpeed, TimeSpan interval, bool single, bool message) + { + if (CheckDecay()) + return false; + + if (m_Anchored) + { + if (message && m_TillerMan != null) + m_TillerMan.Say(501419); // Ar, the anchor is down sir! + + return false; + } + + m_Moving = dir; + m_Speed = speed; + m_ClientSpeed = clientSpeed; + m_Order = BoatOrder.Move; + + if (m_MoveTimer != null) + m_MoveTimer.Stop(); + + m_MoveTimer = new MoveTimer(this, interval, single); + m_MoveTimer.Start(); + + return true; + } + + public bool StopMove( bool message ) + { + if ( CheckDecay() ) + return false; + + if ( m_MoveTimer == null ) + { + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501443 ); // Er, the ship is not moving sir. + + return false; + } + + m_Moving = Direction.North; + m_Speed = 0; + m_ClientSpeed = 0; + m_MoveTimer.Stop(); + m_MoveTimer = null; + + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501429 ); // Aye aye sir. + + return true; + } + + public bool CanFit( Point3D p, Map map, int itemID ) + { + if ( map == null || map == Map.Internal || Deleted || CheckDecay() ) + return false; + + MultiComponentList newComponents = MultiData.GetComponents( itemID ); + + for ( int x = 0; x < newComponents.Width; ++x ) + { + for ( int y = 0; y < newComponents.Height; ++y ) + { + int tx = p.X + newComponents.Min.X + x; + int ty = p.Y + newComponents.Min.Y + y; + + if ( newComponents.Tiles[x][y].Length == 0 || Contains( tx, ty ) ) + continue; + + LandTile landTile = map.Tiles.GetLandTile( tx, ty ); + StaticTile[] tiles = map.Tiles.GetStaticTiles( tx, ty, true ); + + bool hasWater = false; + + if ( landTile.Z == p.Z && ((landTile.ID >= 168 && landTile.ID <= 171) || (landTile.ID >= 310 && landTile.ID <= 311)) ) + hasWater = true; + + int z = p.Z; + + //int landZ = 0, landAvg = 0, landTop = 0; + + //map.GetAverageZ( tx, ty, ref landZ, ref landAvg, ref landTop ); + + //if ( !landTile.Ignored && top > landZ && landTop > z ) + // return false; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + bool isWater = ( tile.ID >= 0x1796 && tile.ID <= 0x17B2 ); + + if ( tile.Z == p.Z && isWater ) + hasWater = true; + else if ( tile.Z >= p.Z && !isWater ) + return false; + } + + if ( !hasWater ) + return false; + } + } + + IPooledEnumerable eable = map.GetItemsInBounds( new Rectangle2D( p.X + newComponents.Min.X, p.Y + newComponents.Min.Y, newComponents.Width, newComponents.Height ) ); + + foreach ( Item item in eable ) + { + if ( item is BaseMulti || item.ItemID > TileData.MaxItemValue || item.Z < p.Z || !item.Visible ) + continue; + + int x = item.X - p.X + newComponents.Min.X; + int y = item.Y - p.Y + newComponents.Min.Y; + + if ( x >= 0 && x < newComponents.Width && y >= 0 && y < newComponents.Height && newComponents.Tiles[x][y].Length == 0 ) + continue; + else if ( Contains( item ) ) + continue; + + eable.Free(); + return false; + } + + eable.Free(); + + return true; + } + + public Point3D Rotate( Point3D p, int count ) + { + int rx = p.X - Location.X; + int ry = p.Y - Location.Y; + + for ( int i = 0; i < count; ++i ) + { + int temp = rx; + rx = -ry; + ry = temp; + } + + return new Point3D( Location.X + rx, Location.Y + ry, p.Z ); + } + + public override bool Contains( int x, int y ) + { + if ( base.Contains( x, y ) ) + return true; + + if ( m_TillerMan != null && x == m_TillerMan.X && y == m_TillerMan.Y ) + return true; + + if ( m_Hold != null && x == m_Hold.X && y == m_Hold.Y ) + return true; + + if ( m_PPlank != null && x == m_PPlank.X && y == m_PPlank.Y ) + return true; + + if ( m_SPlank != null && x == m_SPlank.X && y == m_SPlank.Y ) + return true; + + // Scriptiz s'il s'agit d'un bateau orc, on consid�re les statics comme dedans + if (this is OrcBoat) + { + OrcBoat ob = (OrcBoat)this; + foreach (BoatStatic bs in ob.StaticParts) + { + if (bs == null) continue; + if (bs.X == x && bs.Y == y) return true; + } + } + + return false; + } + + public static bool IsValidLocation( Point3D p, Map map ) + { + Rectangle2D[] wrap = GetWrapFor( map ); + + for ( int i = 0; i < wrap.Length; ++i ) + { + if ( wrap[i].Contains( p ) ) + return true; + } + + return false; + } + + public static Rectangle2D[] GetWrapFor( Map m ) + { + if( m == Map.Ilshenar ) + return m_IlshWrap; + else if( m == Map.Tokuno ) + return m_TokunoWrap; + else + return m_BritWrap; + } + + public Direction GetMovementFor( int x, int y, out int maxSpeed ) + { + int dx = x - this.X; + int dy = y - this.Y; + + int adx = Math.Abs( dx ); + int ady = Math.Abs( dy ); + + Direction dir = Utility.GetDirection( this, new Point2D( x, y ) ); + int iDir = (int) dir; + + // Compute the maximum distance we can travel without going too far away + if ( iDir % 2 == 0 ) // North, East, South and West + maxSpeed = Math.Abs( adx - ady ); + else // Right, Down, Left and Up + maxSpeed = Math.Min( adx, ady ); + + return (Direction) ((iDir - (int)Facing) & 0x7); + } + + public bool DoMovement( bool message ) + { + Direction dir; + int speed, clientSpeed; + + if ( this.Order == BoatOrder.Move ) + { + dir = m_Moving; + speed = m_Speed; + clientSpeed = m_ClientSpeed; + } + else if ( MapItem == null || MapItem.Deleted ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 502513 ); // I have seen no map, sir. + + return false; + } + else if ( this.Map != MapItem.Map || !this.Contains( MapItem.GetWorldLocation() ) ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 502514 ); // The map is too far away from me, sir. + + return false; + } + else if ( ( this.Map != Map.Trammel && this.Map != Map.Felucca ) || NextNavPoint < 0 || NextNavPoint >= MapItem.Pins.Count ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 1042551 ); // I don't see that navpoint, sir. + + return false; + } + else + { + Point2D dest = (Point2D) MapItem.Pins[NextNavPoint]; + + int x, y; + MapItem.ConvertToWorld( dest.X, dest.Y, out x, out y ); + + int maxSpeed; + dir = GetMovementFor( x, y, out maxSpeed ); + + if ( maxSpeed == 0 ) + { + if ( message && this.Order == BoatOrder.Single && TillerMan != null ) + TillerMan.Say( 1042874, (NextNavPoint + 1).ToString() ); // We have arrived at nav point ~1_POINT_NUM~ , sir. + + if ( NextNavPoint + 1 < MapItem.Pins.Count ) + { + NextNavPoint++; + + if ( this.Order == BoatOrder.Course ) + { + if ( message && TillerMan != null ) + TillerMan.Say( 1042875, (NextNavPoint + 1).ToString() ); // Heading to nav point ~1_POINT_NUM~, sir. + + return true; + } + + return false; + } + else + { + NextNavPoint = -1; + + if ( message && this.Order == BoatOrder.Course && TillerMan != null ) + TillerMan.Say( 502515 ); // The course is completed, sir. + + return false; + } + } + + if ( dir == Left || dir == BackwardLeft || dir == Backward ) + return Turn( -2, true ); + else if ( dir == Right || dir == BackwardRight ) + return Turn( 2, true ); + + speed = Math.Min( this.Speed, maxSpeed ); + clientSpeed = 0x4; + } + + return Move( dir, speed, clientSpeed, true ); + } + + public bool Move( Direction dir, int speed, int clientSpeed, bool message ) + { + Map map = Map; + + if ( map == null || Deleted || CheckDecay() ) + return false; + + if ( m_Anchored ) + { + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501419 ); // Ar, the anchor is down sir! + + return false; + } + + int rx = 0, ry = 0; + Direction d = (Direction)(((int)m_Facing + (int)dir) & 0x7); + Movement.Movement.Offset( d, ref rx, ref ry ); + + for ( int i = 1; i <= speed; ++i ) + { + if ( !CanFit( new Point3D( X + (i * rx), Y + (i * ry), Z ), Map, ItemID ) ) + { + if ( i == 1 ) + { + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501424 ); // Ar, we've stopped sir. + + return false; + } + + speed = i - 1; + break; + } + } + + int xOffset = speed*rx; + int yOffset = speed*ry; + + int newX = X + xOffset; + int newY = Y + yOffset; + + Rectangle2D[] wrap = GetWrapFor( map ); + + for ( int i = 0; i < wrap.Length; ++i ) + { + Rectangle2D rect = wrap[i]; + + if ( rect.Contains( new Point2D( X, Y ) ) && !rect.Contains( new Point2D( newX, newY ) ) ) + { + if ( newX < rect.X ) + newX = rect.X + rect.Width - 1; + else if ( newX >= rect.X + rect.Width ) + newX = rect.X; + + if ( newY < rect.Y ) + newY = rect.Y + rect.Height - 1; + else if ( newY >= rect.Y + rect.Height ) + newY = rect.Y; + + for ( int j = 1; j <= speed; ++j ) + { + if ( !CanFit( new Point3D( newX + (j * rx), newY + (j * ry), Z ), Map, ItemID ) ) + { + if ( message && m_TillerMan != null ) + m_TillerMan.Say( 501424 ); // Ar, we've stopped sir. + + return false; + } + } + + xOffset = newX - X; + yOffset = newY - Y; + } + } + + if ( !NewBoatMovement || Math.Abs( xOffset ) > 1 || Math.Abs( yOffset ) > 1 ) + { + Teleport( xOffset, yOffset, 0 ); + } + else + { + List toMove = GetMovingEntities(); + + SafeAdd( m_TillerMan, toMove ); + SafeAdd( m_Hold, toMove ); + SafeAdd( m_PPlank, toMove ); + SafeAdd( m_SPlank, toMove ); + + // Packet must be sent before actual locations are changed + foreach ( NetState ns in Map.GetClientsInRange( Location, GetMaxUpdateRange() ) ) + { + Mobile m = ns.Mobile; + + if ( ns.HighSeas && m.CanSee( this ) && m.InRange( Location, GetUpdateRange( m ) ) ) + ns.Send( new MoveBoatHS( m, this, d, clientSpeed, toMove, xOffset, yOffset ) ); + } + + foreach ( IEntity e in toMove ) + { + if ( e is Item ) + { + Item item = (Item)e; + + item.NoMoveHS = true; + + if ( !( item is TillerMan || item is Hold || item is Plank ) ) + item.Location = new Point3D( item.X + xOffset, item.Y + yOffset, item.Z ); + } + else if ( e is Mobile ) + { + Mobile m = (Mobile)e; + + m.NoMoveHS = true; + m.Location = new Point3D( m.X + xOffset, m.Y + yOffset, m.Z ); + } + } + + NoMoveHS = true; + Location = new Point3D( X + xOffset, Y + yOffset, Z ); + + foreach ( IEntity e in toMove ) + { + if ( e is Item ) + ((Item)e).NoMoveHS = false; + else if ( e is Mobile ) + ((Mobile)e).NoMoveHS = false; + } + + NoMoveHS = false; + } + + return true; + } + + private static void SafeAdd( Item item, List toMove ) + { + if ( item != null ) + toMove.Add( item ); + } + + public void Teleport( int xOffset, int yOffset, int zOffset ) + { + List toMove = GetMovingEntities(); + + for ( int i = 0; i < toMove.Count; ++i ) + { + IEntity e = toMove[i]; + + if ( e is Item ) + { + Item item = (Item)e; + + item.Location = new Point3D( item.X + xOffset, item.Y + yOffset, item.Z + zOffset ); + } + else if ( e is Mobile ) + { + Mobile m = (Mobile)e; + + m.Location = new Point3D( m.X + xOffset, m.Y + yOffset, m.Z + zOffset ); + } + } + + Location = new Point3D( X + xOffset, Y + yOffset, Z + zOffset ); + } + + public List GetMovingEntities() + { + List list = new List(); + + Map map = Map; + + if ( map == null || map == Map.Internal ) + return list; + + MultiComponentList mcl = Components; + + foreach ( object o in map.GetObjectsInBounds( new Rectangle2D( X + mcl.Min.X, Y + mcl.Min.Y, mcl.Width, mcl.Height ) ) ) + { + if ( o == this || o is TillerMan || o is Hold || o is Plank ) + continue; + + if ( o is Item ) + { + Item item = (Item)o; + + if ( Contains( item ) && item.Visible && item.Z >= Z ) + list.Add( item ); + } + else if ( o is Mobile ) + { + Mobile m = (Mobile)o; + + if ( Contains( m ) ) + list.Add( m ); + /* + // Scriptiz : on bouge aussi les joueurs sur des boatstatic + else if (this is OrcBoat) + { + OrcBoat ob = (OrcBoat)this; + + int posX = m.X; + int posY = m.Y; + + foreach(BoatStatic bs in ob.StaticParts) + { + if (bs.X == m.X + xOffset && bs.Y == m.Y + yOffset) + { + m.Location = new Point3D(m.X + xOffset, m.Y + yOffset, m.Z + zOffset); + break; + } + } + }*/ + } + } + + return list; + } + + public bool SetFacing( Direction facing ) + { + if ( Parent != null || this.Map == null ) + return false; + + if ( CheckDecay() ) + return false; + + if ( Map != Map.Internal ) + { + switch ( facing ) + { + case Direction.North: if ( !CanFit( Location, Map, NorthID ) ) return false; break; + case Direction.East: if ( !CanFit( Location, Map, EastID ) ) return false; break; + case Direction.South: if ( !CanFit( Location, Map, SouthID ) ) return false; break; + case Direction.West: if ( !CanFit( Location, Map, WestID ) ) return false; break; + } + } + + Direction old = m_Facing; + + m_Facing = facing; + + if ( m_TillerMan != null ) + m_TillerMan.SetFacing( facing ); + + if ( m_Hold != null ) + m_Hold.SetFacing( facing ); + + if ( m_PPlank != null ) + m_PPlank.SetFacing( facing ); + + if ( m_SPlank != null ) + m_SPlank.SetFacing( facing ); + + List toMove = GetMovingEntities(); + + toMove.Add( m_PPlank ); + toMove.Add( m_SPlank ); + + int xOffset = 0, yOffset = 0; + Movement.Movement.Offset( facing, ref xOffset, ref yOffset ); + + if ( m_TillerMan != null ) + m_TillerMan.Location = new Point3D( X + (xOffset * TillerManDistance) + (facing == Direction.North ? 1 : 0), Y + (yOffset * TillerManDistance), m_TillerMan.Z ); + + if ( m_Hold != null ) + m_Hold.Location = new Point3D( X + (xOffset * HoldDistance), Y + (yOffset * HoldDistance), m_Hold.Z ); + + int count = (int)(m_Facing - old) & 0x7; + count /= 2; + + for ( int i = 0; i < toMove.Count; ++i ) + { + IEntity e = toMove[i]; + + if ( e is Item ) + { + Item item = (Item)e; + + item.Location = Rotate( item.Location, count ); + } + else if ( e is Mobile ) + { + Mobile m = (Mobile)e; + + m.Direction = ( m.Direction - old + facing ) & Direction.Mask; + m.Location = Rotate( m.Location, count ); + } + } + + switch ( facing ) + { + case Direction.North: ItemID = NorthID; break; + case Direction.East: ItemID = EastID; break; + case Direction.South: ItemID = SouthID; break; + case Direction.West: ItemID = WestID; break; + } + + return true; + } + + private class MoveTimer : Timer + { + private BaseBoat m_Boat; + + public MoveTimer( BaseBoat boat, TimeSpan interval, bool single ) : base( interval, interval, single ? 1 : 0 ) + { + m_Boat = boat; + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if ( !m_Boat.DoMovement( true ) ) + m_Boat.StopMove( false ); + } + } + + public static void UpdateAllComponents() + { + for ( int i = m_Instances.Count - 1; i >= 0; --i ) + m_Instances[i].UpdateComponents(); + } + + public static void Initialize() + { + new UpdateAllTimer().Start(); + EventSink.WorldSave += new WorldSaveEventHandler( EventSink_WorldSave ); + } + + private static void EventSink_WorldSave( WorldSaveEventArgs e ) + { + new UpdateAllTimer().Start(); + } + + public class UpdateAllTimer : Timer + { + public UpdateAllTimer() : base( TimeSpan.FromSeconds( 1.0 ) ) + { + } + + protected override void OnTick() + { + UpdateAllComponents(); + } + } + #region High Seas + + public override bool AllowsRelativeDrop + { + get { return true; } + } + + /* + * OSI sends the 0xF7 packet instead, holding 0xF3 packets + * for every entity on the boat. Though, the regular 0xF3 + * packets are still being sent as well as entities come + * into sight. Do we really need it? + */ + /* + protected override Packet GetWorldPacketFor( NetState state ) + { + if ( NewBoatMovement && state.HighSeas ) + return new DisplayBoatHS( state.Mobile, this ); + else + return base.GetWorldPacketFor( state ); + } + */ + + public sealed class MoveBoatHS : Packet + { + public MoveBoatHS( Mobile beholder, BaseBoat boat, Direction d, int speed, List ents, int xOffset, int yOffset ) + : base( 0xF6 ) + { + EnsureCapacity( 3 + 15 + ents.Count * 10 ); + + m_Stream.Write( (int) boat.Serial ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) d ); + m_Stream.Write( (byte) boat.Facing ); + m_Stream.Write( (short) ( boat.X + xOffset ) ); + m_Stream.Write( (short) ( boat.Y + yOffset ) ); + m_Stream.Write( (short) boat.Z ); + m_Stream.Write( (short) 0 ); // count placeholder + + int count = 0; + + foreach ( IEntity ent in ents ) + { + if ( !beholder.CanSee( ent ) ) + continue; + + m_Stream.Write( (int) ent.Serial ); + m_Stream.Write( (short) ( ent.X + xOffset ) ); + m_Stream.Write( (short) ( ent.Y + yOffset ) ); + m_Stream.Write( (short) ent.Z ); + ++count; + } + + m_Stream.Seek( 16, System.IO.SeekOrigin.Begin ); + m_Stream.Write( (short) count ); + } + } + + public sealed class DisplayBoatHS : Packet + { + public DisplayBoatHS( Mobile beholder, BaseBoat boat ) + : base( 0xF7 ) + { + List ents = boat.GetMovingEntities(); + + SafeAdd( boat.TillerMan, ents ); + SafeAdd( boat.Hold, ents ); + SafeAdd( boat.PPlank, ents ); + SafeAdd( boat.SPlank, ents ); + + ents.Add( boat ); + + EnsureCapacity( 3 + 2 + ents.Count * 26 ); + + m_Stream.Write( (short) 0 ); // count placeholder + + int count = 0; + + foreach ( IEntity ent in ents ) + { + if ( !beholder.CanSee( ent ) ) + continue; + + // Embedded WorldItemHS packets + m_Stream.Write( (byte) 0xF3 ); + m_Stream.Write( (short) 0x1 ); + + if ( ent is BaseMulti ) + { + BaseMulti bm = (BaseMulti)ent; + + m_Stream.Write( (byte) 0x02 ); + m_Stream.Write( (int) bm.Serial ); + // TODO: Mask no longer needed, merge with Item case? + m_Stream.Write( (ushort) ( bm.ItemID & 0x3FFF ) ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (short) bm.Amount ); + m_Stream.Write( (short) bm.Amount ); + + m_Stream.Write( (short) ( bm.X & 0x7FFF ) ); + m_Stream.Write( (short) ( bm.Y & 0x3FFF ) ); + m_Stream.Write( (sbyte) bm.Z ); + + m_Stream.Write( (byte) bm.Light ); + m_Stream.Write( (short) bm.Hue ); + m_Stream.Write( (byte) bm.GetPacketFlags() ); + } + else if ( ent is Mobile ) + { + Mobile m = (Mobile)ent; + + m_Stream.Write( (byte) 0x01 ); + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) m.Body ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (short) 1 ); + m_Stream.Write( (short) 1 ); + + m_Stream.Write( (short) ( m.X & 0x7FFF ) ); + m_Stream.Write( (short) ( m.Y & 0x3FFF ) ); + m_Stream.Write( (sbyte) m.Z ); + + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (short) m.Hue ); + m_Stream.Write( (byte) m.GetPacketFlags() ); + } + else if ( ent is Item ) + { + Item item = (Item)ent; + + m_Stream.Write( (byte) 0x00 ); + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (ushort) ( item.ItemID & 0xFFFF ) ); + m_Stream.Write( (byte) 0 ); + + m_Stream.Write( (short) item.Amount ); + m_Stream.Write( (short) item.Amount ); + + m_Stream.Write( (short) ( item.X & 0x7FFF ) ); + m_Stream.Write( (short) ( item.Y & 0x3FFF ) ); + m_Stream.Write( (sbyte) item.Z ); + + m_Stream.Write( (byte) item.Light ); + m_Stream.Write( (short) item.Hue ); + m_Stream.Write( (byte) item.GetPacketFlags() ); + } + + m_Stream.Write( (short) 0x00 ); + ++count; + } + + m_Stream.Seek( 3, System.IO.SeekOrigin.Begin ); + m_Stream.Write( (short) count ); + } + } + + #endregion + } +} diff --git a/Scripts/Multis/Boats/BaseBoatDeed.cs b/Scripts/Multis/Boats/BaseBoatDeed.cs new file mode 100644 index 0000000..8c1de61 --- /dev/null +++ b/Scripts/Multis/Boats/BaseBoatDeed.cs @@ -0,0 +1,183 @@ +using System; +using Server; +using Server.Regions; +using Server.Targeting; +using Server.Engines.CannedEvil; +using Server.Network; + +namespace Server.Multis +{ + public abstract class BaseBoatDeed : Item + { + private int m_MultiID; + private Point3D m_Offset; + + [CommandProperty( AccessLevel.GameMaster )] + public int MultiID{ get{ return m_MultiID; } set{ m_MultiID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Offset{ get{ return m_Offset; } set{ m_Offset = value; } } + + public BaseBoatDeed( int id, Point3D offset ) : base( 0x14F2 ) + { + Weight = 1.0; + + if ( !Core.AOS ) + LootType = LootType.Newbied; + + m_MultiID = id; + m_Offset = offset; + } + + public BaseBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_MultiID ); + writer.Write( m_Offset ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_MultiID = reader.ReadInt(); + m_Offset = reader.ReadPoint3D(); + + break; + } + } + + if ( Weight == 0.0 ) + Weight = 1.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.AccessLevel < AccessLevel.GameMaster && (from.Map == Map.Ilshenar || from.Map == Map.Malas) ) + { + from.SendLocalizedMessage( 1010567, null, 0x25 ); // You may not place a boat from this location. + } + else + { + if ( Core.SE ) + from.SendLocalizedMessage( 502482 ); // Where do you wish to place the ship? + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502482 ); // Where do you wish to place the ship? + + from.Target = new InternalTarget( this ); + } + } + + public abstract BaseBoat Boat{ get; } + + public void OnPlacement( Mobile from, Point3D p ) + { + if ( Deleted ) + { + return; + } + else if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + Map map = from.Map; + + if ( map == null ) + return; + + if ( from.AccessLevel < AccessLevel.GameMaster && (map == Map.Ilshenar || map == Map.Malas) ) + { + from.SendLocalizedMessage( 1043284 ); // A ship can not be created here. + return; + } + + if ( from.Region.IsPartOf( typeof( HouseRegion ) ) || BaseBoat.FindBoatAt( from, from.Map ) != null ) + { + from.SendLocalizedMessage( 1010568, null, 0x25 ); // You may not place a ship while on another ship or inside a house. + return; + } + + BaseBoat boat = Boat; + + if ( boat == null ) + return; + + p = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); + + if ( BaseBoat.IsValidLocation( p, map ) && boat.CanFit( p, map, boat.ItemID ) ) + { + Delete(); + + boat.Owner = from; + boat.Anchored = true; + + uint keyValue = boat.CreateKeys( from ); + + if ( boat.PPlank != null ) + boat.PPlank.KeyValue = keyValue; + + if ( boat.SPlank != null ) + boat.SPlank.KeyValue = keyValue; + + boat.MoveToWorld( p, map ); + } + else + { + boat.Delete(); + from.SendLocalizedMessage( 1043284 ); // A ship can not be created here. + } + } + } + + private class InternalTarget : MultiTarget + { + private BaseBoatDeed m_Deed; + + public InternalTarget( BaseBoatDeed deed ) : base( deed.MultiID, deed.Offset ) + { + m_Deed = deed; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D ip = o as IPoint3D; + + if ( ip != null ) + { + if ( ip is Item ) + ip = ((Item)ip).GetWorldTop(); + + Point3D p = new Point3D( ip ); + + Region region = Region.Find( p, from.Map ); + + if ( region.IsPartOf( typeof( DungeonRegion ) ) ) + from.SendLocalizedMessage( 502488 ); // You can not place a ship inside a dungeon. + else if ( region.IsPartOf( typeof( HouseRegion ) ) || region.IsPartOf( typeof( ChampionSpawnRegion ) ) ) + from.SendLocalizedMessage( 1042549 ); // A boat may not be placed in this area. + else + m_Deed.OnPlacement( from, p ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/BaseDockedBoat.cs b/Scripts/Multis/Boats/BaseDockedBoat.cs new file mode 100644 index 0000000..16cdc4f --- /dev/null +++ b/Scripts/Multis/Boats/BaseDockedBoat.cs @@ -0,0 +1,193 @@ +using System; +using Server; +using Server.Regions; +using Server.Targeting; +using Server.Engines.CannedEvil; + +namespace Server.Multis +{ + public abstract class BaseDockedBoat : Item + { + private int m_MultiID; + private Point3D m_Offset; + private string m_ShipName; + + [CommandProperty( AccessLevel.GameMaster )] + public int MultiID{ get{ return m_MultiID; } set{ m_MultiID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Offset{ get{ return m_Offset; } set{ m_Offset = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public string ShipName{ get{ return m_ShipName; } set{ m_ShipName = value; InvalidateProperties(); } } + + public BaseDockedBoat( int id, Point3D offset, BaseBoat boat ) : base( 0x14F4 ) + { + Weight = 1.0; + LootType = LootType.Blessed; + + m_MultiID = id; + m_Offset = offset; + + m_ShipName = boat.ShipName; + } + + public BaseDockedBoat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_MultiID ); + writer.Write( m_Offset ); + writer.Write( m_ShipName ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + case 0: + { + m_MultiID = reader.ReadInt(); + m_Offset = reader.ReadPoint3D(); + m_ShipName = reader.ReadString(); + + if ( version == 0 ) + reader.ReadUInt(); + + break; + } + } + + if ( LootType == LootType.Newbied ) + LootType = LootType.Blessed; + + if ( Weight == 0.0 ) + Weight = 1.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + from.SendLocalizedMessage( 502482 ); // Where do you wish to place the ship? + + from.Target = new InternalTarget( this ); + } + } + + public abstract BaseBoat Boat{ get; } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_ShipName != null ) + list.Add( m_ShipName ); + else + base.AddNameProperty( list ); + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_ShipName != null ) + LabelTo( from, m_ShipName ); + else + base.OnSingleClick( from ); + } + + public void OnPlacement( Mobile from, Point3D p ) + { + if ( Deleted ) + { + return; + } + else if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + Map map = from.Map; + + if ( map == null ) + return; + + BaseBoat boat = Boat; + + if ( boat == null ) + return; + + p = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); + + if ( BaseBoat.IsValidLocation( p, map ) && boat.CanFit( p, map, boat.ItemID ) && map != Map.Ilshenar && map != Map.Malas ) + { + Delete(); + + boat.Owner = from; + boat.Anchored = true; + boat.ShipName = m_ShipName; + + uint keyValue = boat.CreateKeys( from ); + + if ( boat.PPlank != null ) + boat.PPlank.KeyValue = keyValue; + + if ( boat.SPlank != null ) + boat.SPlank.KeyValue = keyValue; + + boat.MoveToWorld( p, map ); + } + else + { + boat.Delete(); + from.SendLocalizedMessage( 1043284 ); // A ship can not be created here. + } + } + } + + private class InternalTarget : MultiTarget + { + private BaseDockedBoat m_Model; + + public InternalTarget( BaseDockedBoat model ) : base( model.MultiID, model.Offset ) + { + m_Model = model; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D ip = o as IPoint3D; + + if ( ip != null ) + { + if ( ip is Item ) + ip = ((Item)ip).GetWorldTop(); + + Point3D p = new Point3D( ip ); + + Region region = Region.Find( p, from.Map ); + + if ( region.IsPartOf( typeof( DungeonRegion ) ) ) + from.SendLocalizedMessage( 502488 ); // You can not place a ship inside a dungeon. + else if ( region.IsPartOf( typeof( HouseRegion ) ) || region.IsPartOf( typeof( ChampionSpawnRegion ) ) ) + from.SendLocalizedMessage( 1042549 ); // A boat may not be placed in this area. + else + m_Model.OnPlacement( from, p ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/ConfirmDryDockGump.cs b/Scripts/Multis/Boats/ConfirmDryDockGump.cs new file mode 100644 index 0000000..116efad --- /dev/null +++ b/Scripts/Multis/Boats/ConfirmDryDockGump.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; + +namespace Server.Multis +{ + public class ConfirmDryDockGump : Gump + { + private Mobile m_From; + private BaseBoat m_Boat; + + public ConfirmDryDockGump( Mobile from, BaseBoat boat ) : base( 150, 200 ) + { + m_From = from; + m_Boat = boat; + + m_From.CloseGump( typeof( ConfirmDryDockGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 220, 170, 5054 ); + AddBackground( 10, 10, 200, 150, 3000 ); + + AddHtmlLocalized( 20, 20, 180, 80, 1018319, true, false ); // Do you wish to dry dock this boat? + + AddHtmlLocalized( 55, 100, 140, 25, 1011011, false, false ); // CONTINUE + AddButton( 20, 100, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + + AddHtmlLocalized( 55, 125, 140, 25, 1011012, false, false ); // CANCEL + AddButton( 20, 125, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID == 2 ) + m_Boat.EndDryDock( m_From ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/Hold.cs b/Scripts/Multis/Boats/Hold.cs new file mode 100644 index 0000000..2b4839f --- /dev/null +++ b/Scripts/Multis/Boats/Hold.cs @@ -0,0 +1,125 @@ +using System; +using Server; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class Hold : Container + { + private BaseBoat m_Boat; + + public Hold( BaseBoat boat ) : base( 0x3EAE ) + { + m_Boat = boat; + Movable = false; + } + + public Hold( Serial serial ) : base( serial ) + { + } + + public void SetFacing( Direction dir ) + { + switch ( dir ) + { + case Direction.East: ItemID = 0x3E65; break; + case Direction.West: ItemID = 0x3E93; break; + case Direction.North: ItemID = 0x3EAE; break; + case Direction.South: ItemID = 0x3EB9; break; + } + } + + public override bool OnDragDrop( Mobile from, Item item ) + { + if ( m_Boat == null || !m_Boat.Contains( from ) || m_Boat.IsMoving ) + return false; + + return base.OnDragDrop( from, item ); + } + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( m_Boat == null || !m_Boat.Contains( from ) || m_Boat.IsMoving ) + return false; + + return base.OnDragDropInto( from, item, p ); + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( item != this && (m_Boat == null || !m_Boat.Contains( from ) || m_Boat.IsMoving) ) + return false; + + return base.CheckItemUse( from, item ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( m_Boat == null || !m_Boat.Contains( from ) || m_Boat.IsMoving ) + return false; + + return base.CheckLift( from, item, ref reject ); + } + + public override void OnAfterDelete() + { + if ( m_Boat != null ) + m_Boat.Delete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Boat == null || !m_Boat.Contains( from ) ) + { + if ( m_Boat.TillerMan != null ) + m_Boat.TillerMan.Say( 502490 ); // You must be on the ship to open the hold. + } + else if ( m_Boat.IsMoving ) + { + if ( m_Boat.TillerMan != null ) + m_Boat.TillerMan.Say( 502491 ); // I can not open the hold while the ship is moving. + } + else + { + base.OnDoubleClick( from ); + } + } + + public override bool IsDecoContainer + { + get{ return false; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + + writer.Write( m_Boat ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Boat = reader.ReadItem() as BaseBoat; + + if ( m_Boat == null || Parent != null ) + Delete(); + + Movable = false; + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/LargeBoat.cs b/Scripts/Multis/Boats/LargeBoat.cs new file mode 100644 index 0000000..699bd71 --- /dev/null +++ b/Scripts/Multis/Boats/LargeBoat.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class LargeBoat : BaseBoat + { + public override int NorthID{ get{ return 0x10; } } + public override int EastID{ get{ return 0x11; } } + public override int SouthID{ get{ return 0x12; } } + public override int WestID{ get{ return 0x13; } } + + public override int HoldDistance{ get{ return 5; } } + public override int TillerManDistance{ get{ return -5; } } + + public override Point2D StarboardOffset{ get{ return new Point2D( 2, -1 ); } } + public override Point2D PortOffset{ get{ return new Point2D( -2, -1 ); } } + + public override Point3D MarkOffset{ get{ return new Point3D( 0, 0, 3 ); } } + + public override BaseDockedBoat DockedBoat{ get{ return new LargeDockedBoat( this ); } } + + [Constructable] + public LargeBoat() + { + } + + public LargeBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class LargeBoatDeed : BaseBoatDeed + { + public override int LabelNumber{ get{ return 1041209; } } // large ship deed + public override BaseBoat Boat{ get{ return new LargeBoat(); } } + + [Constructable] + public LargeBoatDeed() : base( 0x10, new Point3D( 0, -1, 0 ) ) + { + } + + public LargeBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class LargeDockedBoat : BaseDockedBoat + { + public override BaseBoat Boat{ get{ return new LargeBoat(); } } + + public LargeDockedBoat( BaseBoat boat ) : base( 0x10, new Point3D( 0, -1, 0 ), boat ) + { + } + + public LargeDockedBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/LargeDragonBoat.cs b/Scripts/Multis/Boats/LargeDragonBoat.cs new file mode 100644 index 0000000..1c30227 --- /dev/null +++ b/Scripts/Multis/Boats/LargeDragonBoat.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class LargeDragonBoat : BaseBoat + { + public override int NorthID{ get{ return 0x14; } } + public override int EastID{ get{ return 0x15; } } + public override int SouthID{ get{ return 0x16; } } + public override int WestID{ get{ return 0x17; } } + + public override int HoldDistance{ get{ return 5; } } + public override int TillerManDistance{ get{ return -5; } } + + public override Point2D StarboardOffset{ get{ return new Point2D( 2, -1 ); } } + public override Point2D PortOffset{ get{ return new Point2D( -2, -1 ); } } + + public override Point3D MarkOffset{ get{ return new Point3D( 0, 0, 3 ); } } + + public override BaseDockedBoat DockedBoat{ get{ return new LargeDockedDragonBoat( this ); } } + + [Constructable] + public LargeDragonBoat() + { + } + + public LargeDragonBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class LargeDragonBoatDeed : BaseBoatDeed + { + public override int LabelNumber{ get{ return 1041210; } }// large dragon ship deed + public override BaseBoat Boat{ get{ return new LargeDragonBoat(); } } + + [Constructable] + public LargeDragonBoatDeed() : base( 0x14, new Point3D( 0, -1, 0 ) ) + { + } + + public LargeDragonBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class LargeDockedDragonBoat : BaseDockedBoat + { + public override BaseBoat Boat{ get{ return new LargeDragonBoat(); } } + + public LargeDockedDragonBoat( BaseBoat boat ) : base( 0x14, new Point3D( 0, -1, 0 ), boat ) + { + } + + public LargeDockedDragonBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/MediumBoat.cs b/Scripts/Multis/Boats/MediumBoat.cs new file mode 100644 index 0000000..1d853e8 --- /dev/null +++ b/Scripts/Multis/Boats/MediumBoat.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class MediumBoat : BaseBoat + { + public override int NorthID{ get{ return 0x8; } } + public override int EastID{ get{ return 0x9; } } + public override int SouthID{ get{ return 0xA; } } + public override int WestID{ get{ return 0xB; } } + + public override int HoldDistance{ get{ return 4; } } + public override int TillerManDistance{ get{ return -5; } } + + public override Point2D StarboardOffset{ get{ return new Point2D( 2, 0 ); } } + public override Point2D PortOffset{ get{ return new Point2D( -2, 0 ); } } + + public override Point3D MarkOffset{ get{ return new Point3D( 0, 1, 3 ); } } + + public override BaseDockedBoat DockedBoat{ get{ return new MediumDockedBoat( this ); } } + + [Constructable] + public MediumBoat() + { + } + + public MediumBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class MediumBoatDeed : BaseBoatDeed + { + public override int LabelNumber{ get{ return 1041207; } } // medium ship deed + public override BaseBoat Boat{ get{ return new MediumBoat(); } } + + [Constructable] + public MediumBoatDeed() : base( 0x8, Point3D.Zero ) + { + } + + public MediumBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class MediumDockedBoat : BaseDockedBoat + { + public override BaseBoat Boat{ get{ return new MediumBoat(); } } + + public MediumDockedBoat( BaseBoat boat ) : base( 0x8, Point3D.Zero, boat ) + { + } + + public MediumDockedBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/MediumDragonBoat.cs b/Scripts/Multis/Boats/MediumDragonBoat.cs new file mode 100644 index 0000000..f5d2783 --- /dev/null +++ b/Scripts/Multis/Boats/MediumDragonBoat.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class MediumDragonBoat : BaseBoat + { + public override int NorthID{ get{ return 0xC; } } + public override int EastID{ get{ return 0xD; } } + public override int SouthID{ get{ return 0xE; } } + public override int WestID{ get{ return 0xF; } } + + public override int HoldDistance{ get{ return 4; } } + public override int TillerManDistance{ get{ return -5; } } + + public override Point2D StarboardOffset{ get{ return new Point2D( 2, 0 ); } } + public override Point2D PortOffset{ get{ return new Point2D( -2, 0 ); } } + + public override Point3D MarkOffset{ get{ return new Point3D( 0, 1, 3 ); } } + + public override BaseDockedBoat DockedBoat{ get{ return new MediumDockedDragonBoat( this ); } } + + [Constructable] + public MediumDragonBoat() + { + } + + public MediumDragonBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class MediumDragonBoatDeed : BaseBoatDeed + { + public override int LabelNumber{ get{ return 1041208; } } // medium dragon ship deed + public override BaseBoat Boat{ get{ return new MediumDragonBoat(); } } + + [Constructable] + public MediumDragonBoatDeed() : base( 0xC, Point3D.Zero ) + { + } + + public MediumDragonBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class MediumDockedDragonBoat : BaseDockedBoat + { + public override BaseBoat Boat{ get{ return new MediumDragonBoat(); } } + + public MediumDockedDragonBoat( BaseBoat boat ) : base( 0xC, Point3D.Zero, boat ) + { + } + + public MediumDockedDragonBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/Plank.cs b/Scripts/Multis/Boats/Plank.cs new file mode 100644 index 0000000..b123668 --- /dev/null +++ b/Scripts/Multis/Boats/Plank.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections; +using Server; +using Server.Factions; +using Server.Multis; + +namespace Server.Items +{ + public enum PlankSide{ Port, Starboard } + + public class Plank : Item, ILockable + { + private BaseBoat m_Boat; + private PlankSide m_Side; + private bool m_Locked; + private uint m_KeyValue; + + private Timer m_CloseTimer; + + public Plank( BaseBoat boat, PlankSide side, uint keyValue ) : base( 0x3EB1 + (int)side ) + { + m_Boat = boat; + m_Side = side; + m_KeyValue = keyValue; + m_Locked = true; + + Movable = false; + } + + public Plank( Serial serial ) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );//version + + writer.Write( m_Boat ); + writer.Write( (int) m_Side ); + writer.Write( m_Locked ); + writer.Write( m_KeyValue ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Boat = reader.ReadItem() as BaseBoat; + m_Side = (PlankSide) reader.ReadInt(); + m_Locked = reader.ReadBool(); + m_KeyValue = reader.ReadUInt(); + + if ( m_Boat == null ) + Delete(); + + break; + } + } + + if ( IsOpen ) + { + m_CloseTimer = new CloseTimer( this ); + m_CloseTimer.Start(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseBoat Boat{ get{ return m_Boat; } set{ m_Boat = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public PlankSide Side{ get{ return m_Side; } set{ m_Side = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Locked{ get{ return m_Locked; } set{ m_Locked = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public uint KeyValue{ get{ return m_KeyValue; } set{ m_KeyValue = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsOpen{ get{ return ( ItemID == 0x3ED5 || ItemID == 0x3ED4 || ItemID == 0x3E84 || ItemID == 0x3E89 ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Starboard{ get{ return ( m_Side == PlankSide.Starboard ); } } + + public void SetFacing( Direction dir ) + { + if ( IsOpen ) + { + switch ( dir ) + { + case Direction.North: ItemID = Starboard ? 0x3ED4 : 0x3ED5; break; + case Direction.East: ItemID = Starboard ? 0x3E84 : 0x3E89; break; + case Direction.South: ItemID = Starboard ? 0x3ED5 : 0x3ED4; break; + case Direction.West: ItemID = Starboard ? 0x3E89 : 0x3E84; break; + } + } + else + { + switch ( dir ) + { + case Direction.North: ItemID = Starboard ? 0x3EB2 : 0x3EB1; break; + case Direction.East: ItemID = Starboard ? 0x3E85 : 0x3E8A; break; + case Direction.South: ItemID = Starboard ? 0x3EB1 : 0x3EB2; break; + case Direction.West: ItemID = Starboard ? 0x3E8A : 0x3E85; break; + } + } + } + + public void Open() + { + if ( IsOpen || Deleted ) + return; + + if ( m_CloseTimer != null ) + m_CloseTimer.Stop(); + + m_CloseTimer = new CloseTimer( this ); + m_CloseTimer.Start(); + + switch ( ItemID ) + { + case 0x3EB1: ItemID = 0x3ED5; break; + case 0x3E8A: ItemID = 0x3E89; break; + case 0x3EB2: ItemID = 0x3ED4; break; + case 0x3E85: ItemID = 0x3E84; break; + } + + if ( m_Boat != null ) + m_Boat.Refresh(); + } + + public override bool OnMoveOver( Mobile from ) + { + if ( IsOpen ) + { + if (from is BaseFactionGuard) + return false; + + if ( (from.Direction & Direction.Running) != 0 || (m_Boat != null && !m_Boat.Contains( from )) ) + return true; + + Map map = Map; + + if ( map == null ) + return false; + + int rx = 0, ry = 0; + + if ( ItemID == 0x3ED4 ) + rx = 1; + else if ( ItemID == 0x3ED5 ) + rx = -1; + else if ( ItemID == 0x3E84 ) + ry = 1; + else if ( ItemID == 0x3E89 ) + ry = -1; + + for ( int i = 1; i <= 6; ++i ) + { + int x = X + (i*rx); + int y = Y + (i*ry); + int z; + + for ( int j = -8; j <= 8; ++j ) + { + z = from.Z + j; + + if ( map.CanFit( x, y, z, 16, false, false ) && !Server.Spells.SpellHelper.CheckMulti( new Point3D( x, y, z ), map ) && !Region.Find( new Point3D( x, y, z ), map ).IsPartOf( typeof( Factions.StrongholdRegion ) ) ) + { + if ( i == 1 && j >= -2 && j <= 2 ) + return true; + + from.Location = new Point3D( x, y, z ); + return false; + } + } + + z = map.GetAverageZ( x, y ); + + if ( map.CanFit( x, y, z, 16, false, false ) && !Server.Spells.SpellHelper.CheckMulti( new Point3D( x, y, z ), map ) && !Region.Find( new Point3D( x, y, z ), map ).IsPartOf( typeof( Factions.StrongholdRegion ) ) ) + { + if ( i == 1 ) + return true; + + from.Location = new Point3D( x, y, z ); + return false; + } + } + + return true; + } + else + { + return false; + } + } + + public bool CanClose() + { + Map map = Map; + + if ( map == null || Deleted ) + return false; + + foreach ( object o in this.GetObjectsInRange( 0 ) ) + { + if ( o != this ) + return false; + } + + return true; + } + + public void Close() + { + if ( !IsOpen || !CanClose() || Deleted ) + return; + + if ( m_CloseTimer != null ) + m_CloseTimer.Stop(); + + m_CloseTimer = null; + + switch ( ItemID ) + { + case 0x3ED5: ItemID = 0x3EB1; break; + case 0x3E89: ItemID = 0x3E8A; break; + case 0x3ED4: ItemID = 0x3EB2; break; + case 0x3E84: ItemID = 0x3E85; break; + } + + if ( m_Boat != null ) + m_Boat.Refresh(); + } + + public override void OnDoubleClickDead( Mobile from ) + { + OnDoubleClick( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Boat == null ) + return; + + if ( from.InRange( GetWorldLocation(), 8 ) ) + { + if ( m_Boat.Contains( from ) ) + { + if ( IsOpen ) + Close(); + else + Open(); + } + else + { + if ( !IsOpen ) + { + if ( !Locked ) + { + Open(); + } + else if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.LocalOverheadMessage( Network.MessageType.Regular, 0x00, 502502 ); // That is locked but your godly powers allow access + Open(); + } + else + { + from.LocalOverheadMessage( Network.MessageType.Regular, 0x00, 502503 ); // That is locked. + } + } + else if ( !Locked ) + { + from.Location = new Point3D( this.X, this.Y, this.Z + 3 ); + } + else if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.LocalOverheadMessage( Network.MessageType.Regular, 0x00, 502502 ); // That is locked but your godly powers allow access + from.Location = new Point3D( this.X, this.Y, this.Z + 3 ); + } + else + { + from.LocalOverheadMessage( Network.MessageType.Regular, 0x00, 502503 ); // That is locked. + } + } + } + } + + private class CloseTimer : Timer + { + private Plank m_Plank; + + public CloseTimer( Plank plank ) : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + m_Plank = plank; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Plank.Close(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/RenameBoatPrompt.cs b/Scripts/Multis/Boats/RenameBoatPrompt.cs new file mode 100644 index 0000000..49eafb6 --- /dev/null +++ b/Scripts/Multis/Boats/RenameBoatPrompt.cs @@ -0,0 +1,21 @@ +using System; +using Server; +using Server.Prompts; + +namespace Server.Multis +{ + public class RenameBoatPrompt : Prompt + { + private BaseBoat m_Boat; + + public RenameBoatPrompt( BaseBoat boat ) + { + m_Boat = boat; + } + + public override void OnResponse( Mobile from, string text ) + { + m_Boat.EndRename( from, text ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/SmallBoat.cs b/Scripts/Multis/Boats/SmallBoat.cs new file mode 100644 index 0000000..5be84c2 --- /dev/null +++ b/Scripts/Multis/Boats/SmallBoat.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class SmallBoat : BaseBoat + { + public override int NorthID{ get{ return 0x0; } } + public override int EastID{ get{ return 0x1; } } + public override int SouthID{ get{ return 0x2; } } + public override int WestID{ get{ return 0x3; } } + + public override int HoldDistance{ get{ return 4; } } + public override int TillerManDistance{ get{ return -4; } } + + public override Point2D StarboardOffset{ get{ return new Point2D( 2, 0 ); } } + public override Point2D PortOffset{ get{ return new Point2D( -2, 0 ); } } + + public override Point3D MarkOffset{ get{ return new Point3D( 0, 1, 3 ); } } + + public override BaseDockedBoat DockedBoat{ get{ return new SmallDockedBoat( this ); } } + + [Constructable] + public SmallBoat() + { + } + + public SmallBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class SmallBoatDeed : BaseBoatDeed + { + public override int LabelNumber{ get{ return 1041205; } } // small ship deed + public override BaseBoat Boat{ get{ return new SmallBoat(); } } + + [Constructable] + public SmallBoatDeed() : base( 0x0, Point3D.Zero ) + { + } + + public SmallBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class SmallDockedBoat : BaseDockedBoat + { + public override BaseBoat Boat{ get{ return new SmallBoat(); } } + + public SmallDockedBoat( BaseBoat boat ) : base( 0x0, Point3D.Zero, boat ) + { + } + + public SmallDockedBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/SmallDragonBoat.cs b/Scripts/Multis/Boats/SmallDragonBoat.cs new file mode 100644 index 0000000..484e0c6 --- /dev/null +++ b/Scripts/Multis/Boats/SmallDragonBoat.cs @@ -0,0 +1,103 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class SmallDragonBoat : BaseBoat + { + public override int NorthID{ get{ return 0x4; } } + public override int EastID{ get{ return 0x5; } } + public override int SouthID{ get{ return 0x6; } } + public override int WestID{ get{ return 0x7; } } + + public override int HoldDistance{ get{ return 4; } } + public override int TillerManDistance{ get{ return -4; } } + + public override Point2D StarboardOffset{ get{ return new Point2D( 2, 0 ); } } + public override Point2D PortOffset{ get{ return new Point2D( -2, 0 ); } } + + public override Point3D MarkOffset{ get{ return new Point3D( 0, 1, 3 ); } } + + public override BaseDockedBoat DockedBoat{ get{ return new SmallDockedDragonBoat( this ); } } + + [Constructable] + public SmallDragonBoat() + { + } + + public SmallDragonBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class SmallDragonBoatDeed : BaseBoatDeed + { + public override int LabelNumber{ get{ return 1041206; } } // small dragon ship deed + public override BaseBoat Boat{ get{ return new SmallDragonBoat(); } } + + [Constructable] + public SmallDragonBoatDeed() : base( 0x4, Point3D.Zero ) + { + } + + public SmallDragonBoatDeed( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } + + public class SmallDockedDragonBoat : BaseDockedBoat + { + public override BaseBoat Boat{ get{ return new SmallDragonBoat(); } } + + public SmallDockedDragonBoat( BaseBoat boat ) : base( 0x4, Point3D.Zero, boat ) + { + } + + public SmallDockedDragonBoat( Serial serial ) : base( serial ) + { + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/Strandedness.cs b/Scripts/Multis/Boats/Strandedness.cs new file mode 100644 index 0000000..6d1d983 --- /dev/null +++ b/Scripts/Multis/Boats/Strandedness.cs @@ -0,0 +1,184 @@ +using System; +using System.IO; +using Server; + +namespace Server.Misc +{ + public class Strandedness + { + private static Point2D[] m_Felucca = new Point2D[] + { + new Point2D( 2528, 3568 ), new Point2D( 2376, 3400 ), new Point2D( 2528, 3896 ), + new Point2D( 2168, 3904 ), new Point2D( 1136, 3416 ), new Point2D( 1432, 3648 ), + new Point2D( 1416, 4000 ), new Point2D( 4512, 3936 ), new Point2D( 4440, 3120 ), + new Point2D( 4192, 3672 ), new Point2D( 4720, 3472 ), new Point2D( 3744, 2768 ), + new Point2D( 3480, 2432 ), new Point2D( 3560, 2136 ), new Point2D( 3792, 2112 ), + new Point2D( 2800, 2296 ), new Point2D( 2736, 2016 ), new Point2D( 4576, 1456 ), + new Point2D( 4680, 1152 ), new Point2D( 4304, 1104 ), new Point2D( 4496, 984 ), + new Point2D( 4248, 696 ), new Point2D( 4040, 616 ), new Point2D( 3896, 248 ), + new Point2D( 4176, 384 ), new Point2D( 3672, 1104 ), new Point2D( 3520, 1152 ), + new Point2D( 3720, 1360 ), new Point2D( 2184, 2152 ), new Point2D( 1952, 2088 ), + new Point2D( 2056, 1936 ), new Point2D( 1720, 1992 ), new Point2D( 472, 2064 ), + new Point2D( 656, 2096 ), new Point2D( 3008, 3592 ), new Point2D( 2784, 3472 ), + new Point2D( 5456, 2400 ), new Point2D( 5976, 2424 ), new Point2D( 5328, 3112 ), + new Point2D( 5792, 3152 ), new Point2D( 2120, 3616 ), new Point2D( 2136, 3128 ), + new Point2D( 1632, 3528 ), new Point2D( 1328, 3160 ), new Point2D( 1072, 3136 ), + new Point2D( 1128, 2976 ), new Point2D( 960, 2576 ), new Point2D( 752, 1832 ), + new Point2D( 184, 1488 ), new Point2D( 592, 1440 ), new Point2D( 368, 1216 ), + new Point2D( 232, 752 ), new Point2D( 696, 744 ), new Point2D( 304, 1000 ), + new Point2D( 840, 376 ), new Point2D( 1192, 624 ), new Point2D( 1200, 192 ), + new Point2D( 1512, 240 ), new Point2D( 1336, 456 ), new Point2D( 1536, 648 ), + new Point2D( 1104, 952 ), new Point2D( 1864, 264 ), new Point2D( 2136, 200 ), + new Point2D( 2160, 528 ), new Point2D( 1904, 512 ), new Point2D( 2240, 784 ), + new Point2D( 2536, 776 ), new Point2D( 2488, 216 ), new Point2D( 2336, 72 ), + new Point2D( 2648, 288 ), new Point2D( 2680, 576 ), new Point2D( 2896, 88 ), + new Point2D( 2840, 344 ), new Point2D( 3136, 72 ), new Point2D( 2968, 520 ), + new Point2D( 3192, 328 ), new Point2D( 3448, 208 ), new Point2D( 3432, 608 ), + new Point2D( 3184, 752 ), new Point2D( 2800, 704 ), new Point2D( 2768, 1016 ), + new Point2D( 2448, 1232 ), new Point2D( 2272, 920 ), new Point2D( 2072, 1080 ), + new Point2D( 2048, 1264 ), new Point2D( 1808, 1528 ), new Point2D( 1496, 1880 ), + new Point2D( 1656, 2168 ), new Point2D( 2096, 2320 ), new Point2D( 1816, 2528 ), + new Point2D( 1840, 2640 ), new Point2D( 1928, 2952 ), new Point2D( 2120, 2712 ) + }; + + private static Point2D[] m_Trammel = m_Felucca; + + private static Point2D[] m_Ilshenar = new Point2D[] + { + new Point2D( 1252, 1180 ), new Point2D( 1562, 1090 ), new Point2D( 1444, 1016 ), + new Point2D( 1324, 968 ), new Point2D( 1418, 806 ), new Point2D( 1722, 874 ), + new Point2D( 1456, 684 ), new Point2D( 1036, 866 ), new Point2D( 612, 476 ), + new Point2D( 1476, 372 ), new Point2D( 762, 472 ), new Point2D( 812, 1162 ), + new Point2D( 1422, 1144 ), new Point2D( 1254, 1066 ), new Point2D( 1598, 870 ), + new Point2D( 1358, 866 ), new Point2D( 510, 302 ), new Point2D( 510, 392 ) + }; + + private static Point2D[] m_Tokuno = new Point2D[] + { + //Makoto-Jima + new Point2D( 837, 1351 ), new Point2D( 941, 1241 ), new Point2D( 959, 1185 ), + new Point2D( 923, 1091 ), new Point2D( 904, 983 ), new Point2D( 845, 944 ), + new Point2D( 829, 896 ), new Point2D( 794, 852 ), new Point2D( 766, 821 ), + new Point2D( 695, 814 ), new Point2D( 576, 835 ), new Point2D( 518, 840 ), + new Point2D( 519, 902 ), new Point2D( 502, 950 ), new Point2D( 503, 1045 ), + new Point2D( 547, 1131 ), new Point2D( 518, 1204 ), new Point2D( 506, 1243 ), + new Point2D( 526, 1271 ), new Point2D( 562, 1295 ), new Point2D( 616, 1335 ), + new Point2D( 789, 1347 ), new Point2D( 712, 1359 ), + + //Homare-Jima + new Point2D( 202, 498 ), new Point2D( 116, 600 ), new Point2D( 107, 699 ), + new Point2D( 162, 799 ), new Point2D( 158, 889 ), new Point2D( 169, 989 ), + new Point2D( 194, 1101 ), new Point2D( 250, 1163 ), new Point2D( 295, 1176 ), + new Point2D( 280, 1194 ), new Point2D( 286, 1102 ), new Point2D( 250, 1000 ), + new Point2D( 260, 906 ), new Point2D( 360, 838 ), new Point2D( 389, 763 ), + new Point2D( 415, 662 ), new Point2D( 500, 597 ), new Point2D( 570, 572 ), + new Point2D( 631, 577 ), new Point2D( 692, 500 ), new Point2D( 723, 445 ), + new Point2D( 672, 379 ), new Point2D( 626, 332 ), new Point2D( 494, 291 ), + new Point2D( 371, 336 ), new Point2D( 324, 334 ), new Point2D( 270, 362 ), + + //Isamu-Jima + new Point2D( 1240, 1076 ), new Point2D( 1189, 1115 ), new Point2D( 1046, 1039 ), + new Point2D( 1025, 885 ), new Point2D( 907, 809 ), new Point2D( 840, 506 ), + new Point2D( 799, 396 ), new Point2D( 720, 258 ), new Point2D( 744, 158 ), + new Point2D( 904, 37 ), new Point2D( 974, 91 ), new Point2D( 1020, 187 ), + new Point2D( 1035, 288 ), new Point2D( 1104, 395 ), new Point2D( 1215, 462 ), + new Point2D( 1275, 488 ), new Point2D( 1348, 611 ), new Point2D( 1363, 739 ), + new Point2D( 1364, 765 ), new Point2D( 1364, 876 ), new Point2D( 1300, 936 ), + new Point2D( 1240, 1003 ) + + + }; + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static bool IsStranded( Mobile from ) + { + Map map = from.Map; + + if ( map == null ) + return false; + + object surface = map.GetTopSurface( from.Location ); + + if ( surface is LandTile ) { + int id = ((LandTile)surface).ID; + + return (id >= 168 && id <= 171) + || (id >= 310 && id <= 311); + } else if ( surface is StaticTile ) { + int id = ((StaticTile)surface).ID; + + return (id >= 0x1796 && id <= 0x17B2); + } + + return false; + } + + public static void EventSink_Login( LoginEventArgs e ) + { + Mobile from = e.Mobile; + + if ( !IsStranded( from ) ) + return; + + Map map = from.Map; + + Point2D[] list; + + if( map == Map.Felucca ) + list = m_Felucca; + else if( map == Map.Trammel ) + list = m_Trammel; + else if( map == Map.Ilshenar ) + list = m_Ilshenar; + else if( map == Map.Tokuno ) + list = m_Tokuno; + else + return; + + Point2D p = Point2D.Zero; + double pdist = double.MaxValue; + + for ( int i = 0; i < list.Length; ++i ) + { + double dist = from.GetDistanceToSqrt( list[i] ); + + if ( dist < pdist ) + { + p = list[i]; + pdist = dist; + } + } + + int x = p.X, y = p.Y; + int z; + bool canFit = false; + + z = map.GetAverageZ( x, y ); + canFit = map.CanSpawnMobile( x, y, z ); + + for ( int i = 1; !canFit && i <= 40; i += 2 ) + { + for ( int xo = -1; !canFit && xo <= 1; ++xo ) + { + for ( int yo = -1; !canFit && yo <= 1; ++yo ) + { + if ( xo == 0 && yo == 0 ) + continue; + + x = p.X + (xo * i); + y = p.Y + (yo * i); + z = map.GetAverageZ( x, y ); + canFit = map.CanSpawnMobile( x, y, z ); + } + } + } + + if ( canFit ) + from.Location = new Point3D( x, y, z ); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Boats/TillerMan.cs b/Scripts/Multis/Boats/TillerMan.cs new file mode 100644 index 0000000..4ea7835 --- /dev/null +++ b/Scripts/Multis/Boats/TillerMan.cs @@ -0,0 +1,119 @@ +using System; +using Server; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + public class TillerMan : Item + { + private BaseBoat m_Boat; + + public TillerMan( BaseBoat boat ) : base( 0x3E4E ) + { + m_Boat = boat; + Movable = false; + } + + public TillerMan( Serial serial ) : base(serial) + { + } + + public void SetFacing( Direction dir ) + { + switch ( dir ) + { + case Direction.South: ItemID = 0x3E4B; break; + case Direction.North: ItemID = 0x3E4E; break; + case Direction.West: ItemID = 0x3E50; break; + case Direction.East: ItemID = 0x3E55; break; + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( m_Boat.Status ); + } + + public void Say( int number ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, number ); + } + + public void Say( int number, string args ) + { + PublicOverheadMessage( MessageType.Regular, 0x3B2, number, args ); + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_Boat != null && m_Boat.ShipName != null ) + list.Add( 1042884, m_Boat.ShipName ); // the tiller man of the ~1_SHIP_NAME~ + else + base.AddNameProperty( list ); + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Boat != null && m_Boat.ShipName != null ) + LabelTo( from, 1042884, m_Boat.ShipName ); // the tiller man of the ~1_SHIP_NAME~ + else + base.OnSingleClick( from ); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_Boat != null && m_Boat.Contains( from ) ) + m_Boat.BeginRename( from ); + else if ( m_Boat != null ) + m_Boat.BeginDryDock( from ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( dropped is MapItem && m_Boat != null && m_Boat.CanCommand( from ) && m_Boat.Contains( from ) ) + { + m_Boat.AssociateMap( (MapItem) dropped ); + } + + return false; + } + + public override void OnAfterDelete() + { + if ( m_Boat != null ) + m_Boat.Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 );//version + + writer.Write( m_Boat ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Boat = reader.ReadItem() as BaseBoat; + + if ( m_Boat == null ) + Delete(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Camps/BankerCamp.cs b/Scripts/Multis/Camps/BankerCamp.cs new file mode 100644 index 0000000..9b6533f --- /dev/null +++ b/Scripts/Multis/Camps/BankerCamp.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class BankerCamp : BaseCamp + { + [Constructable] + public BankerCamp() : base( 0x1F6 ) + { + } + + public override void AddComponents() + { + BaseDoor west, east; + + AddItem( west = new LightWoodGate( DoorFacing.WestCW ), -4, 4, 7 ); + AddItem( east = new LightWoodGate( DoorFacing.EastCCW ), -3, 4, 7 ); + + west.Link = east; + east.Link = west; + + AddItem( new Sign( SignType.Bank, SignFacing.West ), -5, 5, -4 ); + + AddMobile( new Banker(), 4, -4, 3, 7 ); + AddMobile( new Banker(), 5, 4, -2, 0 ); + } + + public BankerCamp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Camps/BaseCamp.cs b/Scripts/Multis/Camps/BaseCamp.cs new file mode 100644 index 0000000..99bc586 --- /dev/null +++ b/Scripts/Multis/Camps/BaseCamp.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Multis +{ + public abstract class BaseCamp : BaseMulti + { + private List m_Items; + private List m_Mobiles; + private DateTime m_DecayTime; + private Timer m_DecayTimer; + private TimeSpan m_DecayDelay; + + public virtual int EventRange{ get{ return 10; } } + + public virtual TimeSpan DecayDelay + { + get + { + return m_DecayDelay; + } + set + { + m_DecayDelay = value; + RefreshDecay( true ); + } + } + + public BaseCamp( int multiID ) : base( multiID ) + { + m_Items = new List(); + m_Mobiles = new List(); + m_DecayDelay = TimeSpan.FromMinutes( 30.0 ); + RefreshDecay( true ); + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( CheckAddComponents ) ); + } + + public void CheckAddComponents() + { + if ( Deleted ) + return; + + AddComponents(); + } + + public virtual void AddComponents() + { + } + + public virtual void RefreshDecay( bool setDecayTime ) + { + if ( Deleted ) + return; + + if ( m_DecayTimer != null ) + m_DecayTimer.Stop(); + + if ( setDecayTime ) + m_DecayTime = DateTime.Now + DecayDelay; + + m_DecayTimer = Timer.DelayCall( DecayDelay, new TimerCallback( Delete ) ); + } + + public virtual void AddItem( Item item, int xOffset, int yOffset, int zOffset ) + { + m_Items.Add( item ); + + int zavg = Map.GetAverageZ(X + xOffset, Y + yOffset); + item.MoveToWorld( new Point3D( X + xOffset, Y + yOffset, zavg + zOffset ), Map ); + } + + public virtual void AddMobile( Mobile m, int wanderRange, int xOffset, int yOffset, int zOffset ) + { + m_Mobiles.Add(m); + + int zavg = Map.GetAverageZ(X + xOffset, Y + yOffset); + Point3D loc = new Point3D(X + xOffset, Y + yOffset, zavg + zOffset); + BaseCreature bc = m as BaseCreature; + + if ( bc != null ) + { + bc.RangeHome = wanderRange; + bc.Home = loc; + } + + if ( m is BaseVendor || m is Banker ) + m.Direction = Direction.South; + + m.MoveToWorld( loc, this.Map ); + } + + public virtual void OnEnter( Mobile m ) + { + RefreshDecay( true ); + } + + public virtual void OnExit( Mobile m ) + { + RefreshDecay( true ); + } + + public override bool HandlesOnMovement{ get{ return true; } } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + bool inOldRange = Utility.InRange( oldLocation, Location, EventRange ); + bool inNewRange = Utility.InRange( m.Location, Location, EventRange ); + + if ( inNewRange && !inOldRange ) + OnEnter( m ); + else if ( inOldRange && !inNewRange ) + OnExit( m ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + for ( int i = 0; i < m_Items.Count; ++i ) + m_Items[i].Delete(); + + for ( int i = 0; i < m_Mobiles.Count; ++i ) + { + BaseCreature bc = (BaseCreature)m_Mobiles[i]; + + if ( bc.IsPrisoner == false ) + m_Mobiles[i].Delete(); + else if ( m_Mobiles[i].CantWalk == true ) + m_Mobiles[i].Delete(); + } + + m_Items.Clear(); + m_Mobiles.Clear(); + } + + public BaseCamp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Items, true ); + writer.Write( m_Mobiles, true ); + writer.WriteDeltaTime( m_DecayTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Items = reader.ReadStrongItemList(); + m_Mobiles = reader.ReadStrongMobileList(); + m_DecayTime = reader.ReadDeltaTime(); + + RefreshDecay( false ); + + break; + } + } + } + } + + public class LockableBarrel : LockableContainer + { + [Constructable] + public LockableBarrel() : base(0xE77) + { + Weight = 1.0; + } + + public LockableBarrel(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Weight == 8.0) + Weight = 1.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Camps/BrigandCamp.cs b/Scripts/Multis/Camps/BrigandCamp.cs new file mode 100644 index 0000000..e95acf8 --- /dev/null +++ b/Scripts/Multis/Camps/BrigandCamp.cs @@ -0,0 +1,199 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class BrigandCamp : BaseCamp + { + public virtual Mobile Brigands{ get{ return new Brigand(); } } + public virtual Mobile Executioners{ get{ return new Executioner(); } } + + private Mobile m_Prisoner; + + [Constructable] + public BrigandCamp() : base( 0x10EE ) // dummy garbage at center + { + } + + public override void AddComponents() + { + BaseCreature bc; + //BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes( 5.0 ); + + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 7, 0); + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + AddItem( new Item( 0xDE3 ), 0, 7, 0 ); // Campfire + AddItem( new Item( 0x974 ), 0, 7, 1 ); // Cauldron + break; + } + case 1: + { + AddItem( new Item( 0x1E95 ), 0, 7, 1 ); // Rabbit on a spit + break; + } + default: + { + AddItem( new Item( 0x1E94 ), 0, 7, 1 ); // Chicken on a spit + break; + } + } + + AddCampChests(); + + for ( int i = 0; i < 4; i ++ ) + { + AddMobile( Brigands, 6, Utility.RandomMinMax( -7, 7 ), Utility.RandomMinMax( -7, 7 ), 0 ); + } + + switch ( Utility.Random( 2 ) ) + { + case 0: m_Prisoner = new Noble(); break; + default: m_Prisoner = new SeekerOfAdventure(); break; + } + + //be = (BaseEscortable)m_Prisoner; + //be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList( 0x57, 0x67, 0x77, 0x87, 0x117 ); + AddMobile( m_Prisoner, 2, Utility.RandomMinMax( -2, 2 ), Utility.RandomMinMax( -2, 2 ), 0 ); + } + + private void AddCampChests() + { + LockableContainer chest = null; + + switch (Utility.Random(3)) + { + case 0: chest = new MetalChest(); break; + case 1: chest = new MetalGoldenChest(); break; + default: chest = new WoodenChest(); break; + } + + // Plume : Retrait des items magiques du coffre. + chest.LiftOverride = true; + chest.DropItem(new Gold(Utility.RandomMinMax(300, 600))); + chest.RequiredSkill = 36; + chest.LockLevel = 26; + chest.MaxLockLevel = 76; + chest.Locked = true; + //TreasureMapChest.Fill(chest, 1); + + AddItem(chest, -2, -2, 0); + + LockableContainer crates = null; + + switch (Utility.Random(4)) + { + case 0: crates = new SmallCrate(); break; + case 1: crates = new MediumCrate(); break; + case 2: crates = new LargeCrate(); break; + default: crates = new LockableBarrel(); break; + } + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + + crates.Locked = true; + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + if (Utility.RandomDouble() < 0.8) + { + switch (Utility.Random(4)) + { + case 0: crates.DropItem(new LesserCurePotion()); break; + case 1: crates.DropItem(new LesserExplosionPotion()); break; + case 2: crates.DropItem(new LesserHealPotion()); break; + default: crates.DropItem(new LesserPoisonPotion()); break; + } + } + + AddItem(crates, 2, 2, 0); + } + + // Don't refresh decay timer + public override void OnEnter( Mobile m ) + { + if ( m.Player && m_Prisoner != null && m_Prisoner.CantWalk ) + { + int number; + + switch ( Utility.Random( 8 ) ) + { + case 0: number = 502261; break; // HELP! + case 1: number = 502262; break; // Help me! + case 2: number = 502263; break; // Canst thou aid me?! + case 3: number = 502264; break; // Help a poor prisoner! + case 4: number = 502265; break; // Help! Please! + case 5: number = 502266; break; // Aaah! Help me! + case 6: number = 502267; break; // Go and get some help! + default: number = 502268; break; // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. + } + m_Prisoner.Yell( number ); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public BrigandCamp( Serial serial ) : base( serial ) + { + } + + public override void AddItem( Item item, int xOffset, int yOffset, int zOffset ) + { + if ( item != null ) + item.Movable = false; + + base.AddItem( item, xOffset, yOffset, zOffset ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Prisoner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Prisoner = reader.ReadMobile(); + break; + } + } + } + } +} diff --git a/Scripts/Multis/Camps/HealerCamp.cs b/Scripts/Multis/Camps/HealerCamp.cs new file mode 100644 index 0000000..7608014 --- /dev/null +++ b/Scripts/Multis/Camps/HealerCamp.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class HealerCamp : BaseCamp + { + [Constructable] + public HealerCamp() : base( 0x1F4 ) + { + } + + public override void AddComponents() + { + BaseDoor west, east; + + AddItem( west = new LightWoodGate( DoorFacing.WestCW ), -4, 4, 7 ); + AddItem( east = new LightWoodGate( DoorFacing.EastCCW ), -3, 4, 7 ); + + west.Link = east; + east.Link = west; + + AddItem( new Sign( SignType.Healer, SignFacing.West ), -5, 5, -4 ); + + AddMobile( new Healer(), 4, -4, 3, 7 ); + AddMobile( new Healer(), 5, 4, -2, 0 ); + } + + public HealerCamp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Camps/LizardmenCamp.cs b/Scripts/Multis/Camps/LizardmenCamp.cs new file mode 100644 index 0000000..737e4a7 --- /dev/null +++ b/Scripts/Multis/Camps/LizardmenCamp.cs @@ -0,0 +1,193 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class LizardmenCamp : BaseCamp + { + public virtual Mobile Lizardmen{ get{ return new Lizardman(); } } + + private Mobile m_Prisoner; + + [Constructable] + public LizardmenCamp() : base( 0x10EE ) // dummy garbage at center + { + } + + public override void AddComponents() + { + BaseCreature bc; + //BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes( 5.0 ); + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 7, 0); + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + AddItem( new Item( 0xDE3 ), 0, 7, 0 ); // Campfire + AddItem( new Item( 0x974 ), 0, 7, 1); // Cauldron + break; + } + case 1: + { + AddItem( new Item( 0x1E95 ), 0, 7, 1); // Rabbit on a spit + break; + } + default: + { + AddItem( new Item( 0x1E94 ), 0, 7, 1); // Chicken on a spit + break; + } + } + AddItem(new Item(0x41F), 4, 4, 0); // Gruesome Standart South + + AddCampChests(); + + for ( int i = 0; i < 4; i ++ ) + { + AddMobile( Lizardmen, 6, Utility.RandomMinMax( -7, 7 ), Utility.RandomMinMax( -7, 7 ), 0 ); + } + + switch ( Utility.Random( 2 ) ) + { + case 0: m_Prisoner = new Noble(); break; + default: m_Prisoner = new SeekerOfAdventure(); break; + } + + //be = (BaseEscortable)m_Prisoner; + //be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList( 0x57, 0x67, 0x77, 0x87, 0x117 ); + AddMobile( m_Prisoner, 2, Utility.RandomMinMax( -2, 2 ), Utility.RandomMinMax( -2, 2 ), 0 ); + } + + private void AddCampChests() + { + LockableContainer chest = null; + + switch ( Utility.Random( 3 ) ) + { + case 0: chest = new MetalChest(); break; + case 1: chest = new MetalGoldenChest(); break; + default: chest = new WoodenChest(); break; + } + + chest.LiftOverride = true; + + TreasureMapChest.Fill( chest, 1 ); + + AddItem( chest, 2, -2, 0 ); + + LockableContainer crates = null; + + switch ( Utility.Random( 4 ) ) + { + case 0: crates = new SmallCrate(); break; + case 1: crates = new MediumCrate(); break; + case 2: crates = new LargeCrate(); break; + default: crates = new LockableBarrel(); break; + } + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax( 30, 40 ); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem( new Gold( Utility.RandomMinMax( 100, 400 ) ) ); + crates.DropItem( new Arrow( 10 ) ); + crates.DropItem( new Bolt( 10 ) ); + + crates.LiftOverride = true; + + if ( Utility.RandomDouble() < 0.8 ) + { + switch ( Utility.Random( 4 ) ) + { + case 0: crates.DropItem( new LesserCurePotion() ); break; + case 1: crates.DropItem( new LesserExplosionPotion() ); break; + case 2: crates.DropItem( new LesserHealPotion() ); break; + default: crates.DropItem(new LesserPoisonPotion()); break; + } + } + + AddItem( crates, -2, 2, 0 ); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if ( m.Player && m_Prisoner != null && m_Prisoner.CantWalk ) + { + int number; + + switch ( Utility.Random( 8 ) ) + { + case 0: number = 502261; break; // HELP! + case 1: number = 502262; break; // Help me! + case 2: number = 502263; break; // Canst thou aid me?! + case 3: number = 502264; break; // Help a poor prisoner! + case 4: number = 502265; break; // Help! Please! + case 5: number = 502266; break; // Aaah! Help me! + case 6: number = 502267; break; // Go and get some help! + default: number = 502268; break; // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. + } + m_Prisoner.Yell( number ); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public LizardmenCamp( Serial serial ) : base( serial ) + { + } + + public override void AddItem( Item item, int xOffset, int yOffset, int zOffset ) + { + if ( item != null ) + item.Movable = false; + + base.AddItem( item, xOffset, yOffset, zOffset ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Prisoner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Prisoner = reader.ReadMobile(); + break; + } + } + } + } +} diff --git a/Scripts/Multis/Camps/MageCamp.cs b/Scripts/Multis/Camps/MageCamp.cs new file mode 100644 index 0000000..f55a584 --- /dev/null +++ b/Scripts/Multis/Camps/MageCamp.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class MageCamp : BaseCamp + { + [Constructable] + public MageCamp() : base( 0x1F5 ) + { + } + + public override void AddComponents() + { + BaseDoor west, east; + + AddItem( west = new LightWoodGate( DoorFacing.WestCW ), -4, 4, 7 ); + AddItem( east = new LightWoodGate( DoorFacing.EastCCW ), -3, 4, 7 ); + + west.Link = east; + east.Link = west; + + AddItem( new Sign( SignType.Mage, SignFacing.West ), -5, 5, -4 ); + + AddMobile( new Mage(), 4, -4, 3, 7 ); + AddMobile( new Mage(), 5, 4, -2, 0 ); + } + + public MageCamp( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Camps/OrcCamp.cs b/Scripts/Multis/Camps/OrcCamp.cs new file mode 100644 index 0000000..a91f883 --- /dev/null +++ b/Scripts/Multis/Camps/OrcCamp.cs @@ -0,0 +1,200 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class OrcCamp : BaseCamp + { + public virtual Mobile Orcs{ get{ return new Orc(); } } + + private Mobile m_Prisoner; + + [Constructable] + public OrcCamp() : base( 0x10EE ) // dummy garbage at center + { + } + + public override void AddComponents() + { + BaseCreature bc; + //BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes(5.0); + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 7, 0); + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + AddItem( new Item( 0xDE3 ), 0, 7, 0 ); // Campfire + AddItem( new Item( 0x974 ), 0, 7, 1 ); // Cauldron + break; + } + case 1: + { + AddItem( new Item( 0x1E95 ), 0, 7, 1 ); // Rabbit on a spit + break; + } + default: + { + AddItem( new Item( 0x1E94 ), 0, 7, 1 ); // Chicken on a spit + break; + } + } + AddItem(new Item(0x428), -5, -4, 0); // Gruesome Standart West + + AddCampChests(); + + for ( int i = 0; i < 3; i ++ ) + { + AddMobile( Orcs, 6, Utility.RandomMinMax( -7, 7 ), Utility.RandomMinMax( -7, 7 ), 0 ); + } + AddMobile( new OrcCaptain(), 2, Utility.RandomMinMax( -7, 7 ), Utility.RandomMinMax( -7, 7 ), 0 ); + + switch ( Utility.Random( 2 ) ) + { + case 0: m_Prisoner = new Noble(); break; + default: m_Prisoner = new SeekerOfAdventure(); break; + } + + //be = (BaseEscortable)m_Prisoner; + //be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList( 0x57, 0x67, 0x77, 0x87, 0x117 ); + AddMobile( m_Prisoner, 2, Utility.RandomMinMax( -2, 2 ), Utility.RandomMinMax( -2, 2 ), 0 ); + } + + private void AddCampChests() + { + LockableContainer chest = null; + + switch (Utility.Random(3)) + { + case 0: chest = new MetalChest(); break; + case 1: chest = new MetalGoldenChest(); break; + default: chest = new WoodenChest(); break; + } + + chest.LiftOverride = true; + + TreasureMapChest.Fill(chest, 1); + + AddItem(chest, -2, 2, 0); + + LockableContainer crates = null; + + switch (Utility.Random(4)) + { + case 0: crates = new SmallCrate(); break; + case 1: crates = new MediumCrate(); break; + case 2: crates = new LargeCrate(); break; + default: crates = new LockableBarrel(); break; + } + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + if (Utility.RandomDouble() < 0.8) + { + switch (Utility.Random(4)) + { + case 0: crates.DropItem(new LesserCurePotion()); break; + case 1: crates.DropItem(new LesserExplosionPotion()); break; + case 2: crates.DropItem(new LesserHealPotion()); break; + default: crates.DropItem(new LesserPoisonPotion()); break; + } + } + + AddItem(crates, 2, -2, 0); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if ( m.Player && m_Prisoner != null && m_Prisoner.CantWalk ) + { + int number; + + switch ( Utility.Random( 8 ) ) + { + case 0: number = 502261; break; // HELP! + case 1: number = 502262; break; // Help me! + case 2: number = 502263; break; // Canst thou aid me?! + case 3: number = 502264; break; // Help a poor prisoner! + case 4: number = 502265; break; // Help! Please! + case 5: number = 502266; break; // Aaah! Help me! + case 6: number = 502267; break; // Go and get some help! + default: number = 502268; break; // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. + } + m_Prisoner.Yell( number ); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public OrcCamp( Serial serial ) : base( serial ) + { + } + + public override void AddItem( Item item, int xOffset, int yOffset, int zOffset ) + { + if ( item != null ) + item.Movable = false; + + base.AddItem( item, xOffset, yOffset, zOffset ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Prisoner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Prisoner = reader.ReadMobile(); + break; + } + case 0: + { + m_Prisoner = reader.ReadMobile(); + reader.ReadItem(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Camps/RatCamp.cs b/Scripts/Multis/Camps/RatCamp.cs new file mode 100644 index 0000000..a5d574d --- /dev/null +++ b/Scripts/Multis/Camps/RatCamp.cs @@ -0,0 +1,199 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Multis +{ + public class RatCamp : BaseCamp + { + public virtual Mobile Ratmen{ get{ return new Ratman(); } } + + private Mobile m_Prisoner; + + [Constructable] + public RatCamp() : base( 0x10EE ) // dummy garbage at center + { + } + + public override void AddComponents() + { + BaseCreature bc; + //BaseEscortable be; + + Visible = false; + DecayDelay = TimeSpan.FromMinutes(5.0); + AddItem(new Static(0x10ee), 0, 0, 0); + AddItem(new Static(0xfac), 0, 6, 0); + + switch ( Utility.Random( 3 ) ) + { + case 0: + { + AddItem( new Item( 0xDE3 ), 0, 6, 0 ); // Campfire + AddItem( new Item( 0x974 ), 0, 6, 1 ); // Cauldron + break; + } + case 1: + { + AddItem( new Item( 0x1E95 ), 0, 6, 1 ); // Rabbit on a spit + break; + } + default: + { + AddItem( new Item( 0x1E94 ), 0, 6, 1 ); // Chicken on a spit + break; + } + } + AddItem(new Item(0x41F), 5, 5, 0); // Gruesome Standart South + + AddCampChests(); + + for ( int i = 0; i < 4; i ++ ) + { + AddMobile( Ratmen, 6, Utility.RandomMinMax( -7, 7 ), Utility.RandomMinMax( -7, 7 ), 0 ); + } + + switch ( Utility.Random( 2 ) ) + { + case 0: m_Prisoner = new Noble(); break; + default: m_Prisoner = new SeekerOfAdventure(); break; + } + + //be = (BaseEscortable)m_Prisoner; + //be.m_Captive = true; + + bc = (BaseCreature)m_Prisoner; + bc.IsPrisoner = true; + bc.CantWalk = true; + + m_Prisoner.YellHue = Utility.RandomList( 0x57, 0x67, 0x77, 0x87, 0x117 ); + AddMobile( m_Prisoner, 2, Utility.RandomMinMax( -2, 2 ), Utility.RandomMinMax( -2, 2 ), 0 ); + } + + private void AddCampChests() + { + LockableContainer chest = null; + + switch (Utility.Random(3)) + { + case 0: chest = new MetalChest(); break; + case 1: chest = new MetalGoldenChest(); break; + default: chest = new WoodenChest(); break; + } + + chest.LiftOverride = true; + + TreasureMapChest.Fill(chest, 1); + + AddItem(chest, -2, -2, 0); + + LockableContainer crates = null; + + switch (Utility.Random(4)) + { + case 0: crates = new SmallCrate(); break; + case 1: crates = new MediumCrate(); break; + case 2: crates = new LargeCrate(); break; + default: crates = new LockableBarrel(); break; + } + + crates.TrapType = TrapType.ExplosionTrap; + crates.TrapPower = Utility.RandomMinMax(30, 40); + crates.TrapLevel = 2; + + crates.RequiredSkill = 76; + crates.LockLevel = 66; + crates.MaxLockLevel = 116; + crates.Locked = true; + + crates.DropItem(new Gold(Utility.RandomMinMax(100, 400))); + crates.DropItem(new Arrow(10)); + crates.DropItem(new Bolt(10)); + + crates.LiftOverride = true; + + if (Utility.RandomDouble() < 0.8) + { + switch (Utility.Random(4)) + { + case 0: crates.DropItem(new LesserCurePotion()); break; + case 1: crates.DropItem(new LesserExplosionPotion()); break; + case 2: crates.DropItem(new LesserHealPotion()); break; + default: crates.DropItem(new LesserPoisonPotion()); break; + } + } + + AddItem(crates, 2, 2, 0); + } + + // Don't refresh decay timer + public override void OnEnter(Mobile m) + { + if ( m.Player && m_Prisoner != null && m_Prisoner.CantWalk ) + { + int number; + + switch ( Utility.Random( 8 ) ) + { + case 0: number = 502261; break; // HELP! + case 1: number = 502262; break; // Help me! + case 2: number = 502263; break; // Canst thou aid me?! + case 3: number = 502264; break; // Help a poor prisoner! + case 4: number = 502265; break; // Help! Please! + case 5: number = 502266; break; // Aaah! Help me! + case 6: number = 502267; break; // Go and get some help! + default: number = 502268; break; // Quickly, I beg thee! Unlock my chains! If thou dost look at me close thou canst see them. + } + m_Prisoner.Yell( number ); + } + } + + // Don't refresh decay timer + public override void OnExit(Mobile m) + { + } + + public RatCamp( Serial serial ) : base( serial ) + { + } + + public override void AddItem( Item item, int xOffset, int yOffset, int zOffset ) + { + if ( item != null ) + item.Movable = false; + + base.AddItem( item, xOffset, yOffset, zOffset ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Prisoner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Prisoner = reader.ReadMobile(); + break; + } + case 0: + { + m_Prisoner = reader.ReadMobile(); + reader.ReadItem(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/ComponentVerification.cs b/Scripts/Multis/ComponentVerification.cs new file mode 100644 index 0000000..9422b48 --- /dev/null +++ b/Scripts/Multis/ComponentVerification.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Server.Multis +{ + public class ComponentVerification + { + private int[] m_ItemTable; + private int[] m_MultiTable; + + public bool IsItemValid( int itemID ) + { + if ( itemID <= 0 || itemID >= m_ItemTable.Length ) + return false; + + return CheckValidity( m_ItemTable[itemID] ); + } + + public bool IsMultiValid( int multiID ) + { + if ( multiID <= 0 || multiID >= m_MultiTable.Length ) + return false; + + return CheckValidity( m_MultiTable[multiID] ); + } + + public bool CheckValidity( int val ) + { + if ( val == -1 ) + return false; + + return ( val == 0 || (ExpansionInfo.CurrentExpansion.CustomHousingFlag & val) != 0 ); + } + + public ComponentVerification() + { + m_ItemTable = CreateTable( 0x10000 ); + m_MultiTable = CreateTable( 0x4000 ); + + LoadItems( "Data/Components/walls.txt", "South1", "South2", "South3", "Corner", "East1", "East2", "East3", "Post", "WindowS", "AltWindowS", "WindowE", "AltWindowE", "SecondAltWindowS", "SecondAltWindowE" ); + LoadItems( "Data/Components/teleprts.txt", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16" ); + LoadItems( "Data/Components/stairs.txt", "Block", "North", "East", "South", "West", "Squared1", "Squared2", "Rounded1", "Rounded2" ); + LoadItems( "Data/Components/roof.txt", "North", "East", "South", "West", "NSCrosspiece", "EWCrosspiece", "NDent", "EDent", "SDent", "WDent", "NTPiece", "ETPiece", "STPiece", "WTPiece", "XPiece", "Extra Piece" ); + LoadItems( "Data/Components/floors.txt", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16" ); + LoadItems( "Data/Components/misc.txt", "Piece1", "Piece2", "Piece3", "Piece4", "Piece5", "Piece6", "Piece7", "Piece8" ); + LoadItems( "Data/Components/doors.txt", "Piece1", "Piece2", "Piece3", "Piece4", "Piece5", "Piece6", "Piece7", "Piece8" ); + + LoadMultis( "Data/Components/stairs.txt", "MultiNorth", "MultiEast", "MultiSouth", "MultiWest" ); + } + + private int[] CreateTable( int length ) + { + int[] table = new int[length]; + + for ( int i = 0; i < table.Length; ++i ) + table[i] = -1; + + return table; + } + + private void LoadItems( string path, params string[] itemColumns ) + { + LoadSpreadsheet( m_ItemTable, path, itemColumns ); + } + + private void LoadMultis( string path, params string[] multiColumns ) + { + LoadSpreadsheet( m_MultiTable, path, multiColumns ); + } + + private void LoadSpreadsheet( int[] table, string path, params string[] tileColumns ) + { + Spreadsheet ss = new Spreadsheet( path ); + + int[] tileCIDs = new int[tileColumns.Length]; + + for ( int i = 0; i < tileColumns.Length; ++i ) + tileCIDs[i] = ss.GetColumnID( tileColumns[i] ); + + int featureCID = ss.GetColumnID( "FeatureMask" ); + + for ( int i = 0; i < ss.Records.Length; ++i ) + { + DataRecord record = ss.Records[i]; + + int fid = record.GetInt32( featureCID ); + + for ( int j = 0; j < tileCIDs.Length; ++j ) + { + int itemID = record.GetInt32( tileCIDs[j] ); + + if ( itemID <= 0 || itemID >= table.Length ) + continue; + + table[itemID] = fid; + } + } + } + } + + public class Spreadsheet + { + private class ColumnInfo + { + public int m_DataIndex; + + public string m_Type; + public string m_Name; + + public ColumnInfo( int dataIndex, string type, string name ) + { + m_DataIndex = dataIndex; + + m_Type = type; + m_Name = name; + } + } + + private ColumnInfo[] m_Columns; + private DataRecord[] m_Records; + + public DataRecord[] Records { get { return m_Records; } } + + public int GetColumnID( string name ) + { + for ( int i = 0; i < m_Columns.Length; ++i ) + { + if ( m_Columns[i].m_Name == name ) + return i; + } + + return -1; + } + + public Spreadsheet( string path ) + { + using ( StreamReader ip = new StreamReader( path ) ) + { + string[] types = ReadLine( ip ); + string[] names = ReadLine( ip ); + + m_Columns = new ColumnInfo[types.Length]; + + for ( int i = 0; i < m_Columns.Length; ++i ) + m_Columns[i] = new ColumnInfo( i, types[i], names[i] ); + + List records = new List(); + + string[] values; + + while ( ( values = ReadLine( ip ) ) != null ) + { + object[] data = new object[m_Columns.Length]; + + for ( int i = 0; i < m_Columns.Length; ++i ) + { + ColumnInfo ci = m_Columns[i]; + + switch ( ci.m_Type ) + { + case "int": + { + data[i] = Utility.ToInt32( values[ci.m_DataIndex] ); + break; + } + case "string": + { + data[i] = values[ci.m_DataIndex]; + break; + } + } + } + + records.Add( new DataRecord( this, data ) ); + } + + m_Records = records.ToArray(); + } + } + + private string[] ReadLine( StreamReader ip ) + { + string line; + + while ( ( line = ip.ReadLine() ) != null ) + { + if ( line.Length == 0 ) + continue; + + return line.Split( '\t' ); + } + + return null; + } + } + + public class DataRecord + { + private Spreadsheet m_Spreadsheet; + private object[] m_Data; + + public Spreadsheet Spreadsheet { get { return m_Spreadsheet; } } + public object[] Data { get { return m_Data; } } + + public DataRecord( Spreadsheet ss, object[] data ) + { + m_Spreadsheet = ss; + m_Data = data; + } + + public int GetInt32( string name ) + { + return GetInt32( this[name] ); + } + + public int GetInt32( int id ) + { + return GetInt32( this[id] ); + } + + public int GetInt32( object obj ) + { + if ( obj is int ) + return (int) obj; + + return 0; + } + + public string GetString( string name ) + { + return this[name] as string; + } + + public object this[string name] + { + get + { + return this[m_Spreadsheet.GetColumnID( name )]; + } + } + + public object this[int id] + { + get + { + if ( id < 0 ) + return null; + + return m_Data[id]; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Deeds.cs b/Scripts/Multis/Deeds.cs new file mode 100644 index 0000000..d170e99 --- /dev/null +++ b/Scripts/Multis/Deeds.cs @@ -0,0 +1,902 @@ +using System; +using System.Collections; +using Server; +using Server.Multis; +using Server.Targeting; +using Server.Items; +using Server.Regions; + +namespace Server.Multis.Deeds +{ + public class HousePlacementTarget : MultiTarget + { + private HouseDeed m_Deed; + + public HousePlacementTarget( HouseDeed deed ) : base( deed.MultiID, deed.Offset ) + { + m_Deed = deed; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D ip = o as IPoint3D; + + if ( ip != null ) + { + if ( ip is Item ) + ip = ((Item)ip).GetWorldTop(); + + Point3D p = new Point3D( ip ); + + Region reg = Region.Find( new Point3D( p ), from.Map ); + + if ( from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing( from, p ) ) + m_Deed.OnPlacement( from, p ); + else if (reg.IsPartOf(typeof(TempNoHousingRegion))) + from.SendLocalizedMessage(501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + else if (reg.IsPartOf(typeof(TreasureRegion)) || reg.IsPartOf(typeof(HouseRegion))) + from.SendLocalizedMessage(1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + else if (reg.IsPartOf(typeof(HouseRaffleRegion))) + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + else + from.SendLocalizedMessage( 501265 ); // Housing can not be created in this area. + } + } + } + + public abstract class HouseDeed : Item + { + private int m_MultiID; + private Point3D m_Offset; + + [CommandProperty( AccessLevel.GameMaster )] + public int MultiID + { + get + { + return m_MultiID; + } + set + { + m_MultiID = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Point3D Offset + { + get + { + return m_Offset; + } + set + { + m_Offset = value; + } + } + + public HouseDeed( int id, Point3D offset ) : base( 0x14F0 ) + { + Weight = 1.0; + LootType = LootType.Newbied; + + m_MultiID = id; + m_Offset = offset; + } + + public HouseDeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Offset ); + + writer.Write( m_MultiID ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Offset = reader.ReadPoint3D(); + + goto case 0; + } + case 0: + { + m_MultiID = reader.ReadInt(); + + break; + } + } + + if ( Weight == 0.0 ) + Weight = 1.0; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse( from ) ) + { + from.SendLocalizedMessage( 501271 ); // You already own a house, you may not place another! + } + else + { + from.SendLocalizedMessage( 1010433 ); /* House placement cancellation could result in a + * 60 second delay in the return of your deed. + */ + + from.Target = new HousePlacementTarget( this ); + } + } + + public abstract BaseHouse GetHouse( Mobile owner ); + public abstract Rectangle2D[] Area{ get; } + + public void OnPlacement( Mobile from, Point3D p ) + { + if ( Deleted ) + return; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse( from ) ) + { + from.SendLocalizedMessage( 501271 ); // You already own a house, you may not place another! + } + else + { + ArrayList toMove; + Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); + HousePlacementResult res = HousePlacement.Check( from, m_MultiID, center, out toMove ); + + switch ( res ) + { + case HousePlacementResult.Valid: + { + BaseHouse house = GetHouse( from ); + house.MoveToWorld( center, from.Map ); + Delete(); + + for ( int i = 0; i < toMove.Count; ++i ) + { + object o = toMove[i]; + + if ( o is Mobile ) + ((Mobile)o).Location = house.BanLocation; + else if ( o is Item ) + ((Item)o).Location = house.BanLocation; + } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + { + from.SendLocalizedMessage( 1043287 ); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + break; + } + case HousePlacementResult.NoSurface: + { + from.SendMessage( "The house could not be created here. Part of the foundation would not be on any surface." ); + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage( 501265 ); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + from.SendLocalizedMessage( 501270 ); //Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + break; + } + case HousePlacementResult.BadRegionRaffle: + { + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + break; + } + } + } + } + } + + public class StonePlasterHouseDeed : HouseDeed + { + [Constructable] + public StonePlasterHouseDeed() : base( 0x64, new Point3D( 0, 4, 0 ) ) + { + } + + public StonePlasterHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallOldHouse( owner, 0x64 ); + } + + public override int LabelNumber{ get{ return 1041211; } } + public override Rectangle2D[] Area{ get{ return SmallOldHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class FieldStoneHouseDeed : HouseDeed + { + [Constructable] + public FieldStoneHouseDeed() : base( 0x66, new Point3D( 0, 4, 0 ) ) + { + } + + public FieldStoneHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallOldHouse( owner, 0x66 ); + } + + public override int LabelNumber{ get{ return 1041212; } } + public override Rectangle2D[] Area{ get{ return SmallOldHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallBrickHouseDeed : HouseDeed + { + [Constructable] + public SmallBrickHouseDeed() : base( 0x68, new Point3D( 0, 4, 0 ) ) + { + } + + public SmallBrickHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallOldHouse( owner, 0x68 ); + } + + public override int LabelNumber{ get{ return 1041213; } } + public override Rectangle2D[] Area{ get{ return SmallOldHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodHouseDeed : HouseDeed + { + [Constructable] + public WoodHouseDeed() : base( 0x6A, new Point3D( 0, 4, 0 ) ) + { + } + + public WoodHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallOldHouse( owner, 0x6A ); + } + + public override int LabelNumber{ get{ return 1041214; } } + public override Rectangle2D[] Area{ get{ return SmallOldHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class WoodPlasterHouseDeed : HouseDeed + { + [Constructable] + public WoodPlasterHouseDeed() : base( 0x6C, new Point3D( 0, 4, 0 ) ) + { + } + + public WoodPlasterHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallOldHouse( owner, 0x6C ); + } + + public override int LabelNumber{ get{ return 1041215; } } + public override Rectangle2D[] Area{ get{ return SmallOldHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class ThatchedRoofCottageDeed : HouseDeed + { + [Constructable] + public ThatchedRoofCottageDeed() : base( 0x6E, new Point3D( 0, 4, 0 ) ) + { + } + + public ThatchedRoofCottageDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallOldHouse( owner, 0x6E ); + } + + public override int LabelNumber{ get{ return 1041216; } } + public override Rectangle2D[] Area{ get{ return SmallOldHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class BrickHouseDeed : HouseDeed + { + [Constructable] + public BrickHouseDeed() : base( 0x74, new Point3D( -1, 7, 0 ) ) + { + } + + public BrickHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new GuildHouse( owner ); + } + + public override int LabelNumber{ get{ return 1041219; } } + public override Rectangle2D[] Area{ get{ return GuildHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TwoStoryWoodPlasterHouseDeed : HouseDeed + { + [Constructable] + public TwoStoryWoodPlasterHouseDeed() : base( 0x76, new Point3D( -3, 7, 0 ) ) + { + } + + public TwoStoryWoodPlasterHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new TwoStoryHouse( owner, 0x76 ); + } + + public override int LabelNumber{ get{ return 1041220; } } + public override Rectangle2D[] Area{ get{ return TwoStoryHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TwoStoryStonePlasterHouseDeed : HouseDeed + { + [Constructable] + public TwoStoryStonePlasterHouseDeed() : base( 0x78, new Point3D( -3, 7, 0 ) ) + { + } + + public TwoStoryStonePlasterHouseDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new TwoStoryHouse( owner, 0x78 ); + } + + public override int LabelNumber{ get{ return 1041221; } } + public override Rectangle2D[] Area{ get{ return TwoStoryHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class TowerDeed : HouseDeed + { + [Constructable] + public TowerDeed() : base( 0x7A, new Point3D( 0, 7, 0 ) ) + { + } + + public TowerDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new Tower( owner ); + } + + public override int LabelNumber{ get{ return 1041222; } } + public override Rectangle2D[] Area{ get{ return Tower.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class KeepDeed : HouseDeed + { + [Constructable] + public KeepDeed() : base( 0x7C, new Point3D( 0, 11, 0 ) ) + { + } + + public KeepDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new Keep( owner ); + } + + public override int LabelNumber{ get{ return 1041223; } } + public override Rectangle2D[] Area{ get{ return Keep.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CastleDeed : HouseDeed + { + [Constructable] + public CastleDeed() : base( 0x7E, new Point3D( 0, 16, 0 ) ) + { + } + + public CastleDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new Castle( owner ); + } + + public override int LabelNumber{ get{ return 1041224; } } + public override Rectangle2D[] Area{ get{ return Castle.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargePatioDeed : HouseDeed + { + [Constructable] + public LargePatioDeed() : base( 0x8C, new Point3D( -4, 7, 0 ) ) + { + } + + public LargePatioDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new LargePatioHouse( owner ); + } + + public override int LabelNumber{ get{ return 1041231; } } + public override Rectangle2D[] Area{ get{ return LargePatioHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LargeMarbleDeed : HouseDeed + { + [Constructable] + public LargeMarbleDeed() : base( 0x96, new Point3D( -4, 7, 0 ) ) + { + } + + public LargeMarbleDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new LargeMarbleHouse( owner ); + } + + public override int LabelNumber{ get{ return 1041236; } } + public override Rectangle2D[] Area{ get{ return LargeMarbleHouse.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SmallTowerDeed : HouseDeed + { + [Constructable] + public SmallTowerDeed() : base( 0x98, new Point3D( 3, 4, 0 ) ) + { + } + + public SmallTowerDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallTower( owner ); + } + + public override int LabelNumber{ get{ return 1041237; } } + public override Rectangle2D[] Area{ get{ return SmallTower.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class LogCabinDeed : HouseDeed + { + [Constructable] + public LogCabinDeed() : base( 0x9A, new Point3D( 1, 6, 0 ) ) + { + } + + public LogCabinDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new LogCabin( owner ); + } + + public override int LabelNumber{ get{ return 1041238; } } + public override Rectangle2D[] Area{ get{ return LogCabin.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SandstonePatioDeed : HouseDeed + { + [Constructable] + public SandstonePatioDeed() : base( 0x9C, new Point3D( -1, 4, 0 ) ) + { + } + + public SandstonePatioDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SandStonePatio( owner ); + } + + public override int LabelNumber{ get{ return 1041239; } } + public override Rectangle2D[] Area{ get{ return SandStonePatio.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class VillaDeed : HouseDeed + { + [Constructable] + public VillaDeed() : base( 0x9E, new Point3D( 3, 6, 0 ) ) + { + } + + public VillaDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new TwoStoryVilla( owner ); + } + + public override int LabelNumber{ get{ return 1041240; } } + public override Rectangle2D[] Area{ get{ return TwoStoryVilla.AreaArray; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class StoneWorkshopDeed : HouseDeed + { + [Constructable] + public StoneWorkshopDeed() : base( 0xA0, new Point3D( -1, 4, 0 ) ) + { + } + + public StoneWorkshopDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallShop( owner, 0xA0 ); + } + + public override int LabelNumber{ get{ return 1041241; } } + public override Rectangle2D[] Area{ get{ return SmallShop.AreaArray2; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class MarbleWorkshopDeed : HouseDeed + { + [Constructable] + public MarbleWorkshopDeed() : base( 0xA2, new Point3D( -1, 4, 0 ) ) + { + } + + public MarbleWorkshopDeed( Serial serial ) : base( serial ) + { + } + + public override BaseHouse GetHouse( Mobile owner ) + { + return new SmallShop( owner, 0xA2 ); + } + + public override int LabelNumber{ get{ return 1041242; } } + public override Rectangle2D[] Area{ get{ return SmallShop.AreaArray1; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/DynamicDecay.cs b/Scripts/Multis/DynamicDecay.cs new file mode 100644 index 0000000..fa4a8b6 --- /dev/null +++ b/Scripts/Multis/DynamicDecay.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Multis +{ + public class DynamicDecay + { + public static bool Enabled { get { return Core.ML; } } + + private static Dictionary m_Stages; + + static DynamicDecay() + { + m_Stages = new Dictionary(); + + // Scriptiz : on augmente le temps pour tourner vers 31 jours ! + Register(DecayLevel.LikeNew, TimeSpan.FromDays(1), TimeSpan.FromDays(2)); + Register(DecayLevel.Slightly, TimeSpan.FromDays(7), TimeSpan.FromDays(8)); + Register(DecayLevel.Somewhat, TimeSpan.FromDays(7), TimeSpan.FromDays(8)); + Register(DecayLevel.Fairly, TimeSpan.FromDays(7), TimeSpan.FromDays(8)); + Register(DecayLevel.Greatly, TimeSpan.FromDays(7), TimeSpan.FromDays(8)); + Register(DecayLevel.IDOC, TimeSpan.FromDays(2), TimeSpan.FromDays(3)); + + /* + Register( DecayLevel.LikeNew, TimeSpan.FromHours( 1 ), TimeSpan.FromHours( 1 ) ); + Register( DecayLevel.Slightly, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) ); + Register( DecayLevel.Somewhat, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) ); + Register( DecayLevel.Fairly, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) ); + Register( DecayLevel.Greatly, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) ); + Register( DecayLevel.IDOC, TimeSpan.FromHours( 12 ), TimeSpan.FromHours( 24 ) ); + */ + } + + public static void Register( DecayLevel level, TimeSpan min, TimeSpan max ) + { + DecayStageInfo info = new DecayStageInfo( min, max ); + + if ( m_Stages.ContainsKey( level ) ) + m_Stages[level] = info; + else + m_Stages.Add( level, info ); + } + + public static bool Decays( DecayLevel level ) + { + return m_Stages.ContainsKey( level ); + } + + public static TimeSpan GetRandomDuration( DecayLevel level ) + { + if ( !m_Stages.ContainsKey( level ) ) + return TimeSpan.Zero; + + DecayStageInfo info = m_Stages[level]; + long min = info.MinDuration.Ticks; + long max = info.MaxDuration.Ticks; + + return TimeSpan.FromTicks( min + (long)( Utility.RandomDouble() * ( max - min ) ) ); + } + } + + public class DecayStageInfo + { + private TimeSpan m_MinDuration; + private TimeSpan m_MaxDuration; + + public TimeSpan MinDuration + { + get { return m_MinDuration; } + } + + public TimeSpan MaxDuration + { + get { return m_MaxDuration; } + } + + public DecayStageInfo( TimeSpan min, TimeSpan max ) + { + m_MinDuration = min; + m_MaxDuration = max; + } + } +} diff --git a/Scripts/Multis/HouseFoundation.cs b/Scripts/Multis/HouseFoundation.cs new file mode 100644 index 0000000..a3b9fbd --- /dev/null +++ b/Scripts/Multis/HouseFoundation.cs @@ -0,0 +1,2522 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using Server; +using Server.Commands; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells; +using Server.Targeting; + +namespace Server.Multis +{ + public enum FoundationType + { + Stone, + DarkWood, + LightWood, + Dungeon, + Brick, + ElvenGrey, + ElvenNatural, + Crystal, + Shadow + } + + public class HouseFoundation : BaseHouse + { + private DesignState m_Current; // State which is currently visible. + private DesignState m_Design; // State of current design. + private DesignState m_Backup; // State at last user backup. + private Item m_SignHanger; // Item hanging the sign. + private Item m_Signpost; // Item supporting the hanger. + private int m_SignpostGraphic; // ItemID number of the chosen signpost. + private int m_LastRevision; // Latest revision number. + private List m_Fixtures; // List of fixtures (teleporters and doors) associated with this house. + private FoundationType m_Type; // Graphic type of this foundation. + private Mobile m_Customizer; // Who is currently customizing this -or- null if not customizing. + + public FoundationType Type { get { return m_Type; } set { m_Type = value; } } + public int LastRevision { get { return m_LastRevision; } set { m_LastRevision = value; } } + public List Fixtures { get { return m_Fixtures; } } + public Item SignHanger { get { return m_SignHanger; } } + public Item Signpost { get { return m_Signpost; } } + public int SignpostGraphic { get { return m_SignpostGraphic; } set { m_SignpostGraphic = value; } } + public Mobile Customizer { get { return m_Customizer; } set { m_Customizer = value; } } + + public override bool IsAosRules { get { return true; } } + + public override bool IsActive { get { return Customizer == null; } } + + public virtual int CustomizationCost { get { return (Core.AOS ? 0 : 10000); } } + + public bool IsFixture( Item item ) + { + return (m_Fixtures != null && m_Fixtures.Contains( item )); + } + + public override MultiComponentList Components + { + get + { + if( m_Current == null ) + SetInitialState(); + + return m_Current.Components; + } + } + + public override int GetMaxUpdateRange() + { + return 24; + } + + public override int GetUpdateRange( Mobile m ) + { + int w = CurrentState.Components.Width; + int h = CurrentState.Components.Height-1; + int v = 18 + ((w > h ? w : h) / 2); + + if( v > 24 ) + v = 24; + else if( v < 18 ) + v = 18; + + return v; + } + + public DesignState CurrentState + { + get { if( m_Current == null ) SetInitialState(); return m_Current; } + set { m_Current = value; } + } + + public DesignState DesignState + { + get { if( m_Design == null ) SetInitialState(); return m_Design; } + set { m_Design = value; } + } + + public DesignState BackupState + { + get { if( m_Backup == null ) SetInitialState(); return m_Backup; } + set { m_Backup = value; } + } + + public void SetInitialState() + { + // This is a new house, it has not yet loaded a design state + m_Current = new DesignState( this, GetEmptyFoundation() ); + m_Design = new DesignState( m_Current ); + m_Backup = new DesignState( m_Current ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if( m_SignHanger != null ) + m_SignHanger.Delete(); + + if( m_Signpost != null ) + m_Signpost.Delete(); + + if( m_Fixtures == null ) + return; + + for( int i = 0; i < m_Fixtures.Count; ++i ) + { + Item item = m_Fixtures[i]; + + if( item != null ) + item.Delete(); + } + + m_Fixtures.Clear(); + } + + public override void OnLocationChange( Point3D oldLocation ) + { + base.OnLocationChange( oldLocation ); + + int x = Location.X - oldLocation.X; + int y = Location.Y - oldLocation.Y; + int z = Location.Z - oldLocation.Z; + + if( m_SignHanger != null ) + m_SignHanger.MoveToWorld( new Point3D( m_SignHanger.X + x, m_SignHanger.Y + y, m_SignHanger.Z + z ), Map ); + + if( m_Signpost != null ) + m_Signpost.MoveToWorld( new Point3D( m_Signpost.X + x, m_Signpost.Y + y, m_Signpost.Z + z ), Map ); + + if( m_Fixtures == null ) + return; + + for( int i = 0; i < m_Fixtures.Count; ++i ) + { + Item item = m_Fixtures[i]; + + if( Doors.Contains( item ) ) + continue; + + item.MoveToWorld( new Point3D( item.X + x, item.Y + y, item.Z + z ), Map ); + } + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if( m_SignHanger != null ) + m_SignHanger.Map = this.Map; + + if( m_Signpost != null ) + m_Signpost.Map = this.Map; + + if( m_Fixtures == null ) + return; + + for( int i = 0; i < m_Fixtures.Count; ++i ) + m_Fixtures[i].Map = this.Map; + } + + public void ClearFixtures( Mobile from ) + { + if( m_Fixtures == null ) + return; + + RemoveKeys( from ); + + for( int i = 0; i < m_Fixtures.Count; ++i ) + { + m_Fixtures[i].Delete(); + Doors.Remove( m_Fixtures[i] ); + } + + m_Fixtures.Clear(); + } + + public void AddFixtures( Mobile from, MultiTileEntry[] list ) + { + if( m_Fixtures == null ) + m_Fixtures = new List(); + + uint keyValue = 0; + + for( int i = 0; i < list.Length; ++i ) + { + MultiTileEntry mte = list[i]; + int itemID = mte.m_ItemID; + + if( itemID >= 0x181D && itemID < 0x1829 ) + { + HouseTeleporter tp = new HouseTeleporter( itemID ); + + AddFixture( tp, mte ); + } + else + { + BaseDoor door = null; + + if( itemID >= 0x675 && itemID < 0x6F5 ) + { + int type = (itemID - 0x675) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x675) / 2) % 8); + + switch( type ) + { + case 0: door = new GenericHouseDoor( facing, 0x675, 0xEC, 0xF3 ); break; + case 1: door = new GenericHouseDoor( facing, 0x685, 0xEC, 0xF3 ); break; + case 2: door = new GenericHouseDoor( facing, 0x695, 0xEB, 0xF2 ); break; + case 3: door = new GenericHouseDoor( facing, 0x6A5, 0xEA, 0xF1 ); break; + case 4: door = new GenericHouseDoor( facing, 0x6B5, 0xEA, 0xF1 ); break; + case 5: door = new GenericHouseDoor( facing, 0x6C5, 0xEC, 0xF3 ); break; + case 6: door = new GenericHouseDoor( facing, 0x6D5, 0xEA, 0xF1 ); break; + case 7: door = new GenericHouseDoor( facing, 0x6E5, 0xEA, 0xF1 ); break; + } + } + else if( itemID >= 0x314 && itemID < 0x364 ) + { + int type = (itemID - 0x314) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x314) / 2) % 8); + door = new GenericHouseDoor( facing, 0x314 + ( type * 16 ), 0xED, 0xF4 ); + } + else if( itemID >= 0x824 && itemID < 0x834 ) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x824) / 2) % 8); + door = new GenericHouseDoor( facing, 0x824, 0xEC, 0xF3 ); + } + else if( itemID >= 0x839 && itemID < 0x849 ) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x839) / 2) % 8); + door = new GenericHouseDoor( facing, 0x839, 0xEB, 0xF2 ); + } + else if( itemID >= 0x84C && itemID < 0x85C ) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x84C) / 2) % 8); + door = new GenericHouseDoor( facing, 0x84C, 0xEC, 0xF3 ); + } + else if( itemID >= 0x866 && itemID < 0x876 ) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x866) / 2) % 8); + door = new GenericHouseDoor( facing, 0x866, 0xEB, 0xF2 ); + } + else if( itemID >= 0xE8 && itemID < 0xF8 ) + { + DoorFacing facing = (DoorFacing)(((itemID - 0xE8) / 2) % 8); + door = new GenericHouseDoor( facing, 0xE8, 0xED, 0xF4 ); + } + else if( itemID >= 0x1FED && itemID < 0x1FFD ) + { + DoorFacing facing = (DoorFacing)(((itemID - 0x1FED) / 2) % 8); + door = new GenericHouseDoor( facing, 0x1FED, 0xEC, 0xF3 ); + } + else if( itemID >= 0x241F && itemID < 0x2421 ) + { + //DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + door = new GenericHouseDoor( DoorFacing.NorthCCW, 0x2415, -1, -1 ); + } + else if( itemID >= 0x2423 && itemID < 0x2425 ) + { + //DoorFacing facing = (DoorFacing)(((itemID - 0x241F) / 2) % 8); + //This one and the above one are 'special' cases, ie: OSI had the ItemID pattern discombobulated for these + door = new GenericHouseDoor( DoorFacing.WestCW, 0x2423, -1, -1 ); + } + else if( itemID >= 0x2A05 && itemID < 0x2A1D ) + { + DoorFacing facing = (DoorFacing)((((itemID - 0x2A05) / 2) % 4) + 8); + + int sound = (itemID >= 0x2A0D && itemID < 0x2a15) ? 0x539 : -1; + + door = new GenericHouseDoor( facing, 0x29F5 + (8 * ((itemID - 0x2A05) / 8)), sound, sound ); + } + else if( itemID == 0x2D46 ) + { + door = new GenericHouseDoor( DoorFacing.NorthCW, 0x2D46, 0xEA, 0xF1, false ); + } + else if( itemID == 0x2D48 || itemID == 0x2FE2 ) + { + door = new GenericHouseDoor( DoorFacing.SouthCCW, itemID, 0xEA, 0xF1, false ); + } + else if( itemID >= 0x2D63 && itemID < 0x2D70 ) + { + int mod = (itemID - 0x2D63)/2%2; + DoorFacing facing = ( ( mod == 0 ) ? DoorFacing.SouthCCW : DoorFacing.WestCCW ); + + int type = (itemID - 0x2D63) / 4; + + door = new GenericHouseDoor( facing, 0x2D63 + 4*type + mod*2, 0xEA, 0xF1, false ); + } + else if( itemID == 0x2FE4 || itemID == 0x31AE ) + { + door = new GenericHouseDoor( DoorFacing.WestCCW, itemID, 0xEA, 0xF1, false ); + } + else if( itemID >= 0x319C && itemID < 0x31AE ) + { + //special case for 0x31aa <-> 0x31a8 (a9) + + int mod = (itemID - 0x319C) / 2 % 2; + + bool specialCase = (itemID == 0x31AA || itemID == 0x31A8); + + DoorFacing facing; + + if ( itemID == 0x31AA || itemID == 0x31A8 ) + facing = ((mod == 0) ? DoorFacing.NorthCW : DoorFacing.EastCW); + else + facing = ((mod == 0) ? DoorFacing.EastCW : DoorFacing.NorthCW); + + int type = (itemID - 0x319C) / 4; + + door = new GenericHouseDoor( facing, 0x319C + 4 * type + mod * 2, 0xEA, 0xF1, false ); + } + else if( itemID >= 0x367B && itemID < 0x369B ) + { + int type = (itemID - 0x367B) / 16; + DoorFacing facing = (DoorFacing)(((itemID - 0x367B) / 2) % 8); + + switch( type ) + { + case 0: door = new GenericHouseDoor( facing, 0x367B, 0xED, 0xF4 ); break; //crystal + case 1: door = new GenericHouseDoor( facing, 0x368B, 0xEC, 0x3E7 ); break; //shadow + } + } + else if (itemID >= 0x409B && itemID < 0x40A3) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x409B), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x410C && itemID < 0x4114) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x410C), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41C2 && itemID < 0x41CA) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41C2), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x41CF && itemID < 0x41D7) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x41CF), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x436E && itemID < 0x437E) + { + /* These ones had to be different... + * Offset 0 2 4 6 8 10 12 14 + * DoorFacing 2 3 2 3 6 7 6 7 + */ + int offset = itemID - 0x436E; + DoorFacing facing = (DoorFacing)((offset / 2 + 2 * ((1 + offset / 4) % 2)) % 8); + door = new GenericHouseDoor(facing, itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x46DD && itemID < 0x46E5) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x46DD), itemID, 0xEB, 0xF2, false); + } + else if (itemID >= 0x4D22 && itemID < 0x4D2A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x4D22), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50C8 && itemID < 0x50D0) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50C8), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x50D0 && itemID < 0x50D8) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x50D0), itemID, 0xEA, 0xF1, false); + } + else if (itemID >= 0x5142 && itemID < 0x514A) + { + door = new GenericHouseDoor(GetSADoorFacing(itemID - 0x5142), itemID, 0xF0, 0xEF, false); + } + if( door != null ) + { + if( keyValue == 0 ) + keyValue = CreateKeys( from ); + + door.Locked = true; + door.KeyValue = keyValue; + + AddDoor( door, mte.m_OffsetX, mte.m_OffsetY, mte.m_OffsetZ ); + m_Fixtures.Add( door ); + } + } + } + + for( int i = 0; i < m_Fixtures.Count; ++i ) + { + Item fixture = m_Fixtures[i]; + + if( fixture is HouseTeleporter ) + { + HouseTeleporter tp = (HouseTeleporter)fixture; + + for( int j = 1; j <= m_Fixtures.Count; ++j ) + { + HouseTeleporter check = m_Fixtures[(i + j) % m_Fixtures.Count] as HouseTeleporter; + + if( check != null && check.ItemID == tp.ItemID ) + { + tp.Target = check; + break; + } + } + } + else if( fixture is BaseHouseDoor ) + { + BaseHouseDoor door = (BaseHouseDoor)fixture; + + if( door.Link != null ) + continue; + + DoorFacing linkFacing; + int xOffset, yOffset; + + switch( door.Facing ) + { + default: + case DoorFacing.WestCW: linkFacing = DoorFacing.EastCCW; xOffset = 1; yOffset = 0; break; + case DoorFacing.EastCCW: linkFacing = DoorFacing.WestCW; xOffset = -1; yOffset = 0; break; + case DoorFacing.WestCCW: linkFacing = DoorFacing.EastCW; xOffset = 1; yOffset = 0; break; + case DoorFacing.EastCW: linkFacing = DoorFacing.WestCCW; xOffset = -1; yOffset = 0; break; + case DoorFacing.SouthCW: linkFacing = DoorFacing.NorthCCW; xOffset = 0; yOffset = -1; break; + case DoorFacing.NorthCCW: linkFacing = DoorFacing.SouthCW; xOffset = 0; yOffset = 1; break; + case DoorFacing.SouthCCW: linkFacing = DoorFacing.NorthCW; xOffset = 0; yOffset = -1; break; + case DoorFacing.NorthCW: linkFacing = DoorFacing.SouthCCW; xOffset = 0; yOffset = 1; break; + case DoorFacing.SouthSW: linkFacing = DoorFacing.SouthSE; xOffset = 1; yOffset = 0; break; + case DoorFacing.SouthSE: linkFacing = DoorFacing.SouthSW; xOffset = -1; yOffset = 0; break; + case DoorFacing.WestSN: linkFacing = DoorFacing.WestSS; xOffset = 0; yOffset = 1; break; + case DoorFacing.WestSS: linkFacing = DoorFacing.WestSN; xOffset = 0; yOffset = -1; break; + } + + for( int j = i + 1; j < m_Fixtures.Count; ++j ) + { + BaseHouseDoor check = m_Fixtures[j] as BaseHouseDoor; + + if( check != null && check.Link == null && check.Facing == linkFacing && (check.X - door.X) == xOffset && (check.Y - door.Y) == yOffset && (check.Z == door.Z) ) + { + check.Link = door; + door.Link = check; + break; + } + } + } + } + } + + private static DoorFacing GetSADoorFacing(int offset) + { + /* Offset 0 2 4 6 + * DoorFacing 2 3 6 7 + */ + return (DoorFacing)((offset / 2 + 2 * (1 + offset / 4)) % 8); + } + + public void AddFixture( Item item, MultiTileEntry mte ) + { + m_Fixtures.Add( item ); + item.MoveToWorld( new Point3D( X + mte.m_OffsetX, Y + mte.m_OffsetY, Z + mte.m_OffsetZ ), Map ); + } + + public static void GetFoundationGraphics( FoundationType type, out int east, out int south, out int post, out int corner ) + { + switch( type ) + { + default: + case FoundationType.DarkWood: corner = 0x0014; east = 0x0015; south = 0x0016; post = 0x0017; break; + case FoundationType.LightWood: corner = 0x00BD; east = 0x00BE; south = 0x00BF; post = 0x00C0; break; + case FoundationType.Dungeon: corner = 0x02FD; east = 0x02FF; south = 0x02FE; post = 0x0300; break; + case FoundationType.Brick: corner = 0x0041; east = 0x0043; south = 0x0042; post = 0x0044; break; + case FoundationType.Stone: corner = 0x0065; east = 0x0064; south = 0x0063; post = 0x0066; break; + + case FoundationType.ElvenGrey: corner = 0x2DF7; east = 0x2DF9; south = 0x2DFA; post = 0x2DF8; break; + case FoundationType.ElvenNatural: corner = 0x2DFB; east = 0x2DFD; south = 0x2DFE; post = 0x2DFC; break; + + case FoundationType.Crystal: corner = 0x3672; east = 0x3671; south = 0x3670; post = 0x3673; break; + case FoundationType.Shadow: corner = 0x3676; east = 0x3675; south = 0x3674; post = 0x3677; break; + } + } + + public static void ApplyFoundation( FoundationType type, MultiComponentList mcl ) + { + int east, south, post, corner; + + GetFoundationGraphics( type, out east, out south, out post, out corner ); + + int xCenter = mcl.Center.X; + int yCenter = mcl.Center.Y; + + mcl.Add( post, 0 - xCenter, 0 - yCenter, 0 ); + mcl.Add( corner, mcl.Width - 1 - xCenter, mcl.Height - 2 - yCenter, 0 ); + + for( int x = 1; x < mcl.Width; ++x ) + { + mcl.Add( south, x - xCenter, 0 - yCenter, 0 ); + + if( x < mcl.Width-1 ) + mcl.Add( south, x - xCenter, mcl.Height - 2 - yCenter, 0 ); + } + + for( int y = 1; y < mcl.Height - 1; ++y ) + { + mcl.Add( east, 0 - xCenter, y - yCenter, 0 ); + + if( y < mcl.Height - 2 ) + mcl.Add( east, mcl.Width - 1 - xCenter, y - yCenter, 0 ); + } + } + + public static void AddStairsTo( ref MultiComponentList mcl ) + { + // copy the original.. + mcl = new MultiComponentList( mcl ); + + mcl.Resize( mcl.Width, mcl.Height + 1 ); + + int xCenter = mcl.Center.X; + int yCenter = mcl.Center.Y; + int y = mcl.Height - 1; + + for( int x = 0; x < mcl.Width; ++x ) + mcl.Add( 0x63, x - xCenter, y - yCenter, 0 ); + } + + public MultiComponentList GetEmptyFoundation() + { + // Copy original foundation layout + MultiComponentList mcl = new MultiComponentList( MultiData.GetComponents( ItemID ) ); + + mcl.Resize( mcl.Width, mcl.Height + 1 ); + + int xCenter = mcl.Center.X; + int yCenter = mcl.Center.Y; + int y = mcl.Height - 1; + + ApplyFoundation( m_Type, mcl ); + + for( int x = 1; x < mcl.Width; ++x ) + mcl.Add( 0x751, x - xCenter, y - yCenter, 0 ); + + return mcl; + } + + public override Rectangle2D[] Area + { + get + { + MultiComponentList mcl = Components; + + return new Rectangle2D[] { new Rectangle2D( mcl.Min.X, mcl.Min.Y, mcl.Width, mcl.Height ) }; + } + } + + public override Point3D BaseBanLocation { get { return new Point3D( Components.Min.X, Components.Height - 1 - Components.Center.Y, 0 ); } } + + public void CheckSignpost() + { + MultiComponentList mcl = this.Components; + + int x = mcl.Min.X; + int y = mcl.Height - 2 - mcl.Center.Y; + + if( CheckWall( mcl, x, y ) ) + { + if( m_Signpost != null ) + m_Signpost.Delete(); + + m_Signpost = null; + } + else if( m_Signpost == null ) + { + m_Signpost = new Static( m_SignpostGraphic ); + m_Signpost.MoveToWorld( new Point3D( X + x, Y + y, Z + 7 ), Map ); + } + else + { + m_Signpost.ItemID = m_SignpostGraphic; + m_Signpost.MoveToWorld( new Point3D( X + x, Y + y, Z + 7 ), Map ); + } + } + + public bool CheckWall( MultiComponentList mcl, int x, int y ) + { + x += mcl.Center.X; + y += mcl.Center.Y; + + if( x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height ) + { + StaticTile[] tiles = mcl.Tiles[x][y]; + + for( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if( tile.Z == 7 && tile.Height == 20 ) + return true; + } + } + + return false; + } + + public HouseFoundation( Mobile owner, int multiID, int maxLockdowns, int maxSecures ) + : base( multiID, owner, maxLockdowns, maxSecures ) + { + m_SignpostGraphic = 9; + + m_Fixtures = new List(); + + int x = Components.Min.X; + int y = Components.Height - 1 - Components.Center.Y; + + m_SignHanger = new Static( 0xB98 ); + m_SignHanger.MoveToWorld( new Point3D( X + x, Y + y, Z + 7 ), Map ); + + CheckSignpost(); + + SetSign( x, y, 7 ); + } + + public HouseFoundation( Serial serial ) + : base( serial ) + { + } + + public void BeginCustomize( Mobile m ) + { + if (!m.CheckAlive()) + { + return; + } + else if (SpellHelper.CheckCombat(m)) + { + m.SendLocalizedMessage(1005564, "", 0x22); // Wouldst thou flee during the heat of battle?? + return; + } + + RelocateEntities(); + + foreach( Item item in GetItems() ) + { + item.Location = BanLocation; + } + + foreach( Mobile mobile in GetMobiles() ) + { + if( mobile != m ) + mobile.Location = BanLocation; + } + + DesignContext.Add( m, this ); + m.Send( new BeginHouseCustomization( this ) ); + + NetState ns = m.NetState; + if( ns != null ) + SendInfoTo( ns ); + + DesignState.SendDetailedInfoTo( ns ); + } + + public override void SendInfoTo( NetState state, bool sendOplPacket ) + { + base.SendInfoTo( state, sendOplPacket ); + + DesignContext context = DesignContext.Find( state.Mobile ); + DesignState stateToSend; + + if( context != null && context.Foundation == this ) + stateToSend = DesignState; + else + stateToSend = CurrentState; + + stateToSend.SendGeneralInfoTo( state ); + } + + public override void Serialize( GenericWriter writer ) + { + writer.Write( (int)5 ); // version + + writer.Write( m_Signpost ); + writer.Write( (int)m_SignpostGraphic ); + + writer.Write( (int)m_Type ); + + writer.Write( m_SignHanger ); + + writer.Write( (int)m_LastRevision ); + writer.Write( m_Fixtures, true ); + + CurrentState.Serialize( writer ); + DesignState.Serialize( writer ); + BackupState.Serialize( writer ); + + base.Serialize( writer ); + } + + private int m_DefaultPrice; + + public override int DefaultPrice { get { return m_DefaultPrice; } } + + public override void Deserialize( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch( version ) + { + case 5: + case 4: + { + m_Signpost = reader.ReadItem(); + m_SignpostGraphic = reader.ReadInt(); + + goto case 3; + } + case 3: + { + m_Type = (FoundationType)reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_SignHanger = reader.ReadItem(); + + goto case 1; + } + case 1: + { + if( version < 5 ) + m_DefaultPrice = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if( version < 3 ) + m_Type = FoundationType.Stone; + + if( version < 4 ) + m_SignpostGraphic = 9; + + m_LastRevision = reader.ReadInt(); + m_Fixtures = reader.ReadStrongItemList(); + + m_Current = new DesignState( this, reader ); + m_Design = new DesignState( this, reader ); + m_Backup = new DesignState( this, reader ); + + break; + } + } + + base.Deserialize( reader ); + } + + public bool IsHiddenToCustomizer( Item item ) + { + return (item == m_Signpost || item == m_SignHanger || item == Sign || IsFixture(item)); + } + + public static void Initialize() + { + PacketHandlers.RegisterExtended( 0x1E, true, new OnPacketReceive( QueryDesignDetails ) ); + + PacketHandlers.RegisterEncoded( 0x02, true, new OnEncodedPacketReceive( Designer_Backup ) ); + PacketHandlers.RegisterEncoded( 0x03, true, new OnEncodedPacketReceive( Designer_Restore ) ); + PacketHandlers.RegisterEncoded( 0x04, true, new OnEncodedPacketReceive( Designer_Commit ) ); + PacketHandlers.RegisterEncoded( 0x05, true, new OnEncodedPacketReceive( Designer_Delete ) ); + PacketHandlers.RegisterEncoded( 0x06, true, new OnEncodedPacketReceive( Designer_Build ) ); + PacketHandlers.RegisterEncoded( 0x0C, true, new OnEncodedPacketReceive( Designer_Close ) ); + PacketHandlers.RegisterEncoded( 0x0D, true, new OnEncodedPacketReceive( Designer_Stairs ) ); + PacketHandlers.RegisterEncoded( 0x0E, true, new OnEncodedPacketReceive( Designer_Sync ) ); + PacketHandlers.RegisterEncoded( 0x10, true, new OnEncodedPacketReceive( Designer_Clear ) ); + PacketHandlers.RegisterEncoded( 0x12, true, new OnEncodedPacketReceive( Designer_Level ) ); + + PacketHandlers.RegisterEncoded( 0x13, true, new OnEncodedPacketReceive( Designer_Roof ) ); // Samurai Empire roof + PacketHandlers.RegisterEncoded( 0x14, true, new OnEncodedPacketReceive( Designer_RoofDelete ) ); // Samurai Empire roof + + PacketHandlers.RegisterEncoded( 0x1A, true, new OnEncodedPacketReceive( Designer_Revert ) ); + + EventSink.Speech += new SpeechEventHandler( EventSink_Speech ); + } + + private static void EventSink_Speech( SpeechEventArgs e ) + { + if( DesignContext.Find( e.Mobile ) != null ) + { + e.Mobile.SendLocalizedMessage( 1061925 ); // You cannot speak while customizing your house. + e.Blocked = true; + } + } + + public static void Designer_Sync( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client requested state synchronization + * - Resend full house state + */ + + DesignState design = context.Foundation.DesignState; + + // Resend full house state + design.SendDetailedInfoTo( state ); + } + } + + public static void Designer_Clear( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to clear the design + * - Restore empty foundation + * - Construct new design state from empty foundation + * - Assign constructed state to foundation + * - Update revision + * - Update client with new state + */ + + // Restore empty foundation : Construct new design state from empty foundation + DesignState newDesign = new DesignState( context.Foundation, context.Foundation.GetEmptyFoundation() ); + + // Restore empty foundation : Assign constructed state to foundation + context.Foundation.DesignState = newDesign; + + // Update revision + newDesign.OnRevised(); + + // Update client with new state + context.Foundation.SendInfoTo( state ); + newDesign.SendDetailedInfoTo( state ); + } + } + + public static void Designer_Restore( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to restore design to the last backup state + * - Restore backup + * - Construct new design state from backup state + * - Assign constructed state to foundation + * - Update revision + * - Update client with new state + */ + + // Restore backup : Construct new design state from backup state + DesignState backupDesign = new DesignState( context.Foundation.BackupState ); + + // Restore backup : Assign constructed state to foundation + context.Foundation.DesignState = backupDesign; + + // Update revision; + backupDesign.OnRevised(); + + // Update client with new state + context.Foundation.SendInfoTo( state ); + backupDesign.SendDetailedInfoTo( state ); + } + } + + public static void Designer_Backup( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to backup design state + * - Construct a copy of the current design state + * - Assign constructed state to backup state field + */ + + // Construct a copy of the current design state + DesignState copyState = new DesignState( context.Foundation.DesignState ); + + // Assign constructed state to backup state field + context.Foundation.BackupState = copyState; + } + } + + public static void Designer_Revert( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to revert design state to currently visible state + * - Revert design state + * - Construct a copy of the current visible state + * - Freeze fixtures in constructed state + * - Assign constructed state to foundation + * - If a signpost is needed, add it + * - Update revision + * - Update client with new state + */ + + // Revert design state : Construct a copy of the current visible state + DesignState copyState = new DesignState( context.Foundation.CurrentState ); + + // Revert design state : Freeze fixtures in constructed state + copyState.FreezeFixtures(); + + // Revert design state : Assign constructed state to foundation + context.Foundation.DesignState = copyState; + + // Revert design state : If a signpost is needed, add it + context.Foundation.CheckSignpost(); + + // Update revision + copyState.OnRevised(); + + // Update client with new state + context.Foundation.SendInfoTo( state ); + copyState.SendDetailedInfoTo( state ); + } + } + + public void EndConfirmCommit( Mobile from ) + { + int oldPrice = Price; + int newPrice = oldPrice + CustomizationCost + ((DesignState.Components.List.Length - ( CurrentState.Components.List.Length + CurrentState.Fixtures.Length )) * 500); + int cost = newPrice - oldPrice; + + if ( !this.Deleted ) { // Temporary Fix. We should be booting a client out of customization mode in the delete handler. + if ( from.AccessLevel >= AccessLevel.GameMaster && cost != 0 ) + { + from.SendMessage( "{0} gold would have been {1} your bank if you were not a GM.", cost.ToString(), ((cost > 0 )? "withdrawn from" : "deposited into" ) ); + } + else + { + if ( cost > 0 ) + { + if ( Banker.Withdraw( from, cost ) ) + { + from.SendLocalizedMessage( 1060398, cost.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + from.SendLocalizedMessage( 1061903 ); // You cannot commit this house design, because you do not have the necessary funds in your bank box to pay for the upgrade. Please back up your design, obtain the required funds, and commit your design again. + return; + } + } + else if ( cost < 0 ) + { + if ( Banker.Deposit( from, -cost ) ) + from.SendLocalizedMessage( 1060397, ( -cost ).ToString() ); // ~1_AMOUNT~ gold has been deposited into your bank box. + else + return; + } + } + } + + /* Client chose to commit current design state + * - Commit design state + * - Construct a copy of the current design state + * - Clear visible fixtures + * - Melt fixtures from constructed state + * - Add melted fixtures from constructed state + * - Assign constructed state to foundation + * - Update house price + * - Remove design context + * - Notify the client that customization has ended + * - Notify the core that the foundation has changed and should be resent to all clients + * - If a signpost is needed, add it + * - Eject all from house + * - Restore relocated entities + */ + + // Commit design state : Construct a copy of the current design state + DesignState copyState = new DesignState( DesignState ); + + // Commit design state : Clear visible fixtures + ClearFixtures( from ); + + // Commit design state : Melt fixtures from constructed state + copyState.MeltFixtures(); + + // Commit design state : Add melted fixtures from constructed state + AddFixtures( from, copyState.Fixtures ); + + // Commit design state : Assign constructed state to foundation + CurrentState = copyState; + + // Update house price + Price = newPrice - CustomizationCost; + + // Remove design context + DesignContext.Remove( from ); + + // Notify the client that customization has ended + from.Send( new EndHouseCustomization( this ) ); + + // Notify the core that the foundation has changed and should be resent to all clients + Delta( ItemDelta.Update ); + ProcessDelta(); + CurrentState.SendDetailedInfoTo( from.NetState ); + + // If a signpost is needed, add it + CheckSignpost(); + + // Eject all from house + from.RevealingAction(); + + foreach( Item item in GetItems() ) + item.Location = BanLocation; + + foreach( Mobile mobile in GetMobiles() ) + mobile.Location = BanLocation; + + // Restore relocated entities + RestoreRelocatedEntities(); + } + + public static void Designer_Commit( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + int oldPrice = context.Foundation.Price; + int newPrice = oldPrice + context.Foundation.CustomizationCost + ((context.Foundation.DesignState.Components.List.Length - ( context.Foundation.CurrentState.Components.List.Length + context.Foundation.Fixtures.Count) ) * 500); + int bankBalance = Banker.GetBalance( from ); + + from.SendGump( new ConfirmCommitGump( from, context.Foundation, bankBalance, oldPrice, newPrice ) ); + } + } + + public int MaxLevels + { + get + { + MultiComponentList mcl = this.Components; + + if( mcl.Width >= 14 || mcl.Height >= 14 ) + return 4; + else + return 3; + } + } + + public static int GetLevelZ( int level, HouseFoundation house ) + { + if( level < 1 || level > house.MaxLevels ) + level = 1; + + return (level-1)*20 + 7; + + /* + switch( level ) + { + default: + case 1: return 07; + case 2: return 27; + case 3: return 47; + case 4: return 67; + } + * */ + } + + public static int GetZLevel( int z, HouseFoundation house ) + { + int level = (z - 7)/20 +1; + + if( level < 1 || level > house.MaxLevels ) + level = 1; + + return level; + } + + private static ComponentVerification m_Verification; + + public static ComponentVerification Verification + { + get + { + if ( m_Verification == null ) + m_Verification = new ComponentVerification(); + + return m_Verification; + } + } + + public static bool ValidPiece( int itemID ) + { + return ValidPiece( itemID, false ); + } + + public static bool ValidPiece( int itemID, bool roof ) + { + itemID &= TileData.MaxItemValue; + + if ( !roof && ( TileData.ItemTable[itemID].Flags & TileFlag.Roof ) != 0 ) + return false; + else if ( roof && ( TileData.ItemTable[itemID].Flags & TileFlag.Roof ) == 0 ) + return false; + + return Verification.IsItemValid( itemID ); + } + + public static readonly bool AllowStairSectioning = true; + + /* Stair block IDs + * (sorted ascending) + */ + private static int[] m_BlockIDs = new int[] + { + 0x3EE, 0x709, 0x71E, 0x721, + 0x738, 0x750, 0x76C, 0x788, + 0x7A3, 0x7BA, 0x35D2, 0x3609, + 0x4317, 0x4318, 0x4B07, 0x7807 + }; + + /* Stair sequence IDs + * (sorted ascending) + * Use this for stairs in the proper N,W,S,E sequence + */ + private static int[] m_StairSeqs = new int[] + { + 0x3EF, 0x70A, 0x722, 0x739, + 0x751, 0x76D, 0x789, 0x7A4 + }; + + /* Other stair IDs + * Listed in order: north, west, south, east + * Use this for stairs not in the proper sequence + */ + private static int[] m_StairIDs = new int[] + { + 0x71F, 0x736, 0x737, 0x749, + 0x35D4, 0x35D3, 0x35D6, 0x35D5, + 0x360B, 0x360A, 0x360D, 0x360C, + 0x4360, 0x435E, 0x435F, 0x4361, + 0x435C, 0x435A, 0x435B, 0x435D, + 0x4364, 0x4362, 0x4363, 0x4365, + 0x4B05, 0x4B04, 0x4B34, 0x4B33, + 0x7809, 0x7808, 0x780A, 0x780B, + 0x7BB, 0x7BC + }; + + public static bool IsStairBlock( int id ) + { + int delta = -1; + + for( int i = 0; delta < 0 && i < m_BlockIDs.Length; ++i ) + delta = (m_BlockIDs[i] - id); + + return (delta == 0); + + } + + public static bool IsStair( int id, ref int dir ) + { + //dir n=0 w=1 s=2 e=3 + int delta = -4; + + for( int i = 0; delta < -3 && i < m_StairSeqs.Length; ++i ) + delta = (m_StairSeqs[i] - id); + + if( delta >= -3 && delta <= 0 ) + { + dir = -delta; + return true; + } + + for (int i = 0; i < m_StairIDs.Length; ++i) + { + if (m_StairIDs[i] == id) + { + dir = i % 4; + return true; + } + } + + return false; + } + + public static bool DeleteStairs( MultiComponentList mcl, int id, int x, int y, int z ) + { + int ax = x + mcl.Center.X; + int ay = y + mcl.Center.Y; + + if( ax < 0 || ay < 0 || ax >= mcl.Width || ay >= (mcl.Height - 1) || z < 7 || ((z - 7) % 5) != 0 ) + return false; + + if( IsStairBlock( id ) ) + { + StaticTile[] tiles = mcl.Tiles[ax][ay]; + + for( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if( tile.Z == (z + 5) ) + { + id = tile.ID; + z = tile.Z; + + if( !IsStairBlock( id ) ) + break; + } + } + } + + int dir = 0; + + if( !IsStair( id, ref dir ) ) + return false; + + if (AllowStairSectioning) + return true; // skip deletion + + int height = ((z - 7) % 20) / 5; + + int xStart, yStart; + int xInc, yInc; + + switch( dir ) + { + default: + case 0: // North + { + xStart = x; + yStart = y + height; + xInc = 0; + yInc = -1; + break; + } + case 1: // West + { + xStart = x + height; + yStart = y; + xInc = -1; + yInc = 0; + break; + } + case 2: // South + { + xStart = x; + yStart = y - height; + xInc = 0; + yInc = 1; + break; + } + case 3: // East + { + xStart = x - height; + yStart = y; + xInc = 1; + yInc = 0; + break; + } + } + + int zStart = z - (height * 5); + + for( int i = 0; i < 4; ++i ) + { + x = xStart + (i * xInc); + y = yStart + (i * yInc); + + for( int j = 0; j <= i; ++j ) + mcl.RemoveXYZH( x, y, zStart + (j * 5), 5 ); + + ax = x + mcl.Center.X; + ay = y + mcl.Center.Y; + + if( ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1 ) + { + StaticTile[] tiles = mcl.Tiles[ax][ay]; + + bool hasBaseFloor = false; + + for( int j = 0; !hasBaseFloor && j < tiles.Length; ++j ) + hasBaseFloor = (tiles[j].Z == 7 && tiles[j].ID != 1); + + if( !hasBaseFloor ) + mcl.Add( 0x31F4, x, y, 7 ); + } + } + + return true; + } + + public static void Designer_Delete( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to delete a component + * - Read data detailing which component to delete + * - Verify component is deletable + * - Remove the component + * - If needed, replace removed component with a dirt tile + * - Update revision + */ + + // Read data detailing which component to delete + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + int z = pvSrc.ReadInt32(); + + // Verify component is deletable + DesignState design = context.Foundation.DesignState; + MultiComponentList mcl = design.Components; + + int ax = x + mcl.Center.X; + int ay = y + mcl.Center.Y; + + if( z == 0 && ax >= 0 && ax < mcl.Width && ay >= 0 && ay < (mcl.Height - 1) ) + { + /* Component is not deletable + * - Resend design state + * - Return without further processing + */ + + design.SendDetailedInfoTo( state ); + return; + } + + bool fixState = false; + + // Remove the component + if (AllowStairSectioning) + { + if (DeleteStairs(mcl, itemID, x, y, z)) + fixState = true; // The client removes the entire set of stairs locally, resend state + + mcl.Remove(itemID, x, y, z); + } + else + { + if (!DeleteStairs(mcl, itemID, x, y, z)) + mcl.Remove(itemID, x, y, z); + } + + // If needed, replace removed component with a dirt tile + if( ax >= 1 && ax < mcl.Width && ay >= 1 && ay < mcl.Height - 1 ) + { + StaticTile[] tiles = mcl.Tiles[ax][ay]; + + bool hasBaseFloor = false; + + for( int i = 0; !hasBaseFloor && i < tiles.Length; ++i ) + hasBaseFloor = (tiles[i].Z == 7 && tiles[i].ID != 1); + + if( !hasBaseFloor ) + { + // Replace with a dirt tile + mcl.Add( 0x31F4, x, y, 7 ); + } + } + + // Update revision + design.OnRevised(); + + // Resend design state + if (fixState) + design.SendDetailedInfoTo(state); + } + } + + public static void Designer_Stairs( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to add stairs + * - Read data detailing stair type and location + * - Validate stair multi ID + * - Add the stairs + * - Load data describing the stair components + * - Insert described components + * - Update revision + */ + + // Read data detailing stair type and location + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + + // Validate stair multi ID + DesignState design = context.Foundation.DesignState; + + if ( !Verification.IsMultiValid( itemID ) ) + { + /* Specified multi ID is not a stair + * - Resend design state + * - Return without further processing + */ + + TraceValidity( state, itemID ); + design.SendDetailedInfoTo( state ); + return; + } + + // Add the stairs + MultiComponentList mcl = design.Components; + + // Add the stairs : Load data describing stair components + MultiComponentList stairs = MultiData.GetComponents( itemID ); + + // Add the stairs : Insert described components + int z = GetLevelZ( context.Level, context.Foundation ); + + for( int i = 0; i < stairs.List.Length; ++i ) + { + MultiTileEntry entry = stairs.List[i]; + + if( entry.m_ItemID != 1 ) + mcl.Add( entry.m_ItemID, x + entry.m_OffsetX, y + entry.m_OffsetY, z + entry.m_OffsetZ ); + } + + // Update revision + design.OnRevised(); + } + } + + private static void TraceValidity( NetState state, int itemID ) + { + try + { + using ( StreamWriter op = new StreamWriter( "comp_val.log", true ) ) + op.WriteLine( "{0}\t{1}\tInvalid ItemID 0x{2:X4}", state, state.Mobile, itemID ); + } + catch + { + } + } + + public static void Designer_Build( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client chose to add a component + * - Read data detailing component graphic and location + * - Add component + * - Update revision + */ + + // Read data detailing component graphic and location + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + + // Add component + DesignState design = context.Foundation.DesignState; + + if( from.AccessLevel < AccessLevel.GameMaster && !ValidPiece( itemID ) ) + { + TraceValidity( state, itemID ); + design.SendDetailedInfoTo( state ); + return; + } + + MultiComponentList mcl = design.Components; + + int z = GetLevelZ( context.Level, context.Foundation ); + + if( (y + mcl.Center.Y) == (mcl.Height - 1) ) + z = 0; // Tiles placed on the far-south of the house are at 0 Z + + mcl.Add( itemID, x, y, z ); + + // Update revision + design.OnRevised(); + } + } + + public static void Designer_Close( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client closed his house design window + * - Remove design context + * - Notify the client that customization has ended + * - Refresh client with current visible design state + * - If a signpost is needed, add it + * - Eject all from house + * - Restore relocated entities + */ + + // Remove design context + DesignContext.Remove( from ); + + // Notify the client that customization has ended + from.Send( new EndHouseCustomization( context.Foundation ) ); + + // Refresh client with current visible design state + context.Foundation.SendInfoTo( state ); + context.Foundation.CurrentState.SendDetailedInfoTo( state ); + + // If a signpost is needed, add it + context.Foundation.CheckSignpost(); + + // Eject all from house + from.RevealingAction(); + + foreach( Item item in context.Foundation.GetItems() ) + item.Location = context.Foundation.BanLocation; + + foreach( Mobile mobile in context.Foundation.GetMobiles() ) + mobile.Location = context.Foundation.BanLocation; + + // Restore relocated entities + context.Foundation.RestoreRelocatedEntities(); + } + } + + public static void Designer_Level( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) + { + /* Client is moving to a new floor level + * - Read data detailing the target level + * - Validate target level + * - Update design context with new level + * - Teleport mobile to new level + * - Update client + * + */ + + // Read data detailing the target level + int newLevel = pvSrc.ReadInt32(); + + // Validate target level + if( newLevel < 1 || newLevel > context.MaxLevels ) + newLevel = 1; + + // Update design context with new level + context.Level = newLevel; + + // Teleport mobile to new level + from.Location = new Point3D( from.X, from.Y, context.Foundation.Z + GetLevelZ( newLevel, context.Foundation ) ); + + // Update client + context.Foundation.SendInfoTo( state ); + } + } + + public static void QueryDesignDetails( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + HouseFoundation foundation = World.FindItem( pvSrc.ReadInt32() ) as HouseFoundation; + + if( foundation != null && from.Map == foundation.Map && from.InRange( foundation.GetWorldLocation(), 24 ) && from.CanSee( foundation ) ) + { + DesignState stateToSend; + + if( context != null && context.Foundation == foundation ) + stateToSend = foundation.DesignState; + else + stateToSend = foundation.CurrentState; + + stateToSend.SendDetailedInfoTo( state ); + } + } + + public static void Designer_Roof( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null && (Core.SE || from.AccessLevel >= AccessLevel.GameMaster) ) + { + // Read data detailing component graphic and location + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + int z = pvSrc.ReadInt32(); + + // Add component + DesignState design = context.Foundation.DesignState; + + if( from.AccessLevel < AccessLevel.GameMaster && !ValidPiece( itemID, true ) ) + { + TraceValidity( state, itemID ); + design.SendDetailedInfoTo( state ); + return; + } + + MultiComponentList mcl = design.Components; + + if( z < -3 || z > 12 || z % 3 != 0 ) + z = -3; + z += GetLevelZ( context.Level, context.Foundation ); + + MultiTileEntry[] list = mcl.List; + for( int i = 0; i < list.Length; i++ ) + { + MultiTileEntry mte = list[i]; + + if( mte.m_OffsetX == x && mte.m_OffsetY == y && GetZLevel( mte.m_OffsetZ, context.Foundation ) == context.Level && (TileData.ItemTable[mte.m_ItemID & TileData.MaxItemValue].Flags & TileFlag.Roof) != 0 ) + mcl.Remove( mte.m_ItemID, x, y, mte.m_OffsetZ ); + } + + mcl.Add( itemID, x, y, z ); + + // Update revision + design.OnRevised(); + } + } + + public static void Designer_RoofDelete( NetState state, IEntity e, EncodedReader pvSrc ) + { + Mobile from = state.Mobile; + DesignContext context = DesignContext.Find( from ); + + if( context != null ) //No need to check if core.SE if trying to remvoe something that shouldn't be able to be placed anyways + { + // Read data detailing which component to delete + int itemID = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt32(); + int y = pvSrc.ReadInt32(); + int z = pvSrc.ReadInt32(); + + // Verify component is deletable + DesignState design = context.Foundation.DesignState; + MultiComponentList mcl = design.Components; + + if( (TileData.ItemTable[itemID & TileData.MaxItemValue].Flags & TileFlag.Roof) == 0 ) + { + design.SendDetailedInfoTo( state ); + return; + } + + mcl.Remove( itemID, x, y, z ); + + design.OnRevised(); + } + } + + + } + + public class DesignState + { + private HouseFoundation m_Foundation; + private MultiComponentList m_Components; + private MultiTileEntry[] m_Fixtures; + private int m_Revision; + private Packet m_PacketCache; + + public Packet PacketCache + { + get { return m_PacketCache; } + set + { + if( m_PacketCache == value ) + return; + + if( m_PacketCache != null ) + m_PacketCache.Release(); + + m_PacketCache = value; + } + } + + public HouseFoundation Foundation { get { return m_Foundation; } } + public MultiComponentList Components { get { return m_Components; } } + public MultiTileEntry[] Fixtures { get { return m_Fixtures; } } + public int Revision { get { return m_Revision; } set { m_Revision = value; } } + + public DesignState( HouseFoundation foundation, MultiComponentList components ) + { + m_Foundation = foundation; + m_Components = components; + m_Fixtures = new MultiTileEntry[0]; + } + + public DesignState( DesignState toCopy ) + { + m_Foundation = toCopy.m_Foundation; + m_Components = new MultiComponentList( toCopy.m_Components ); + m_Revision = toCopy.m_Revision; + m_Fixtures = new MultiTileEntry[toCopy.m_Fixtures.Length]; + + for( int i = 0; i < m_Fixtures.Length; ++i ) + m_Fixtures[i] = toCopy.m_Fixtures[i]; + } + + public DesignState( HouseFoundation foundation, GenericReader reader ) + { + m_Foundation = foundation; + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_Components = new MultiComponentList( reader ); + + int length = reader.ReadInt(); + + m_Fixtures = new MultiTileEntry[length]; + + for( int i = 0; i < length; ++i ) + { + m_Fixtures[i].m_ItemID = reader.ReadUShort(); + m_Fixtures[i].m_OffsetX = reader.ReadShort(); + m_Fixtures[i].m_OffsetY = reader.ReadShort(); + m_Fixtures[i].m_OffsetZ = reader.ReadShort(); + m_Fixtures[i].m_Flags = reader.ReadInt(); + } + + m_Revision = reader.ReadInt(); + + break; + } + } + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (int)0 ); // version + + m_Components.Serialize( writer ); + + writer.Write( (int)m_Fixtures.Length ); + + for( int i = 0; i < m_Fixtures.Length; ++i ) + { + MultiTileEntry ent = m_Fixtures[i]; + + writer.Write( (ushort)ent.m_ItemID ); + writer.Write( (short)ent.m_OffsetX ); + writer.Write( (short)ent.m_OffsetY ); + writer.Write( (short)ent.m_OffsetZ ); + writer.Write( (int)ent.m_Flags ); + } + + writer.Write( (int)m_Revision ); + } + + public void OnRevised() + { + lock( this ) + { + m_Revision = ++m_Foundation.LastRevision; + + if( m_PacketCache != null ) + m_PacketCache.Release(); + + m_PacketCache = null; + } + } + + public void SendGeneralInfoTo( NetState state ) + { + if( state != null ) + state.Send( new DesignStateGeneral( m_Foundation, this ) ); + } + + public void SendDetailedInfoTo( NetState state ) + { + if( state != null ) + { + lock( this ) + { + if( m_PacketCache == null ) + DesignStateDetailed.SendDetails( state, m_Foundation, this ); + else + state.Send( m_PacketCache ); + } + } + } + + public void FreezeFixtures() + { + OnRevised(); + + for( int i = 0; i < m_Fixtures.Length; ++i ) + { + MultiTileEntry mte = m_Fixtures[i]; + + m_Components.Add( mte.m_ItemID, mte.m_OffsetX, mte.m_OffsetY, mte.m_OffsetZ ); + } + + m_Fixtures = new MultiTileEntry[0]; + } + + public void MeltFixtures() + { + OnRevised(); + + MultiTileEntry[] list = m_Components.List; + int length = 0; + + for( int i = list.Length - 1; i >= 0; --i ) + { + MultiTileEntry mte = list[i]; + + if( IsFixture( mte.m_ItemID ) ) + ++length; + } + + m_Fixtures = new MultiTileEntry[length]; + + for( int i = list.Length - 1; i >= 0; --i ) + { + MultiTileEntry mte = list[i]; + + if( IsFixture( mte.m_ItemID ) ) + { + m_Fixtures[--length] = mte; + m_Components.Remove( mte.m_ItemID, mte.m_OffsetX, mte.m_OffsetY, mte.m_OffsetZ ); + } + } + } + + public static bool IsFixture( int itemID ) + { + if( itemID >= 0x675 && itemID < 0x6F5 ) + return true; + else if( itemID >= 0x314 && itemID < 0x364 ) + return true; + else if( itemID >= 0x824 && itemID < 0x834 ) + return true; + else if( itemID >= 0x839 && itemID < 0x849 ) + return true; + else if( itemID >= 0x84C && itemID < 0x85C ) + return true; + else if( itemID >= 0x866 && itemID < 0x876 ) + return true; + else if( itemID >= 0x0E8 && itemID < 0x0F8 ) + return true; + else if( itemID >= 0x1FED && itemID < 0x1FFD ) + return true; + else if( itemID >= 0x181D && itemID < 0x1829 ) + return true; + else if( itemID >= 0x241F && itemID < 0x2421 ) + return true; + else if( itemID >= 0x2423 && itemID < 0x2425 ) + return true; + else if( itemID >= 0x2A05 && itemID < 0x2A1D ) + return true; + else if( itemID >= 0x319C && itemID < 0x31B0 ) + return true; + else if( itemID == 0x2D46 ||itemID == 0x2D48 || itemID == 0x2FE2 || itemID == 0x2FE4 ) //ML doors begin here. Note funkyness. + return true; + else if( itemID >= 0x2D63 && itemID < 0x2D70 ) + return true; + else if( itemID >= 0x319C && itemID < 0x31AF ) + return true; + else if( itemID >= 0x367B && itemID < 0x369B ) + return true; + #region SA doors + else if (itemID >= 0x409B && itemID < 0x40A3) + return true; + else if (itemID >= 0x410C && itemID < 0x4114) + return true; + else if (itemID >= 0x41C2 && itemID < 0x41CA) + return true; + else if (itemID >= 0x41CF && itemID < 0x41D7) + return true; + else if (itemID >= 0x436E && itemID < 0x437E) + return true; + else if (itemID >= 0x46DD && itemID < 0x46E5) + return true; + else if (itemID >= 0x4D22 && itemID < 0x4D2A) + return true; + else if (itemID >= 0x50C8 && itemID < 0x50D8) + return true; + else if (itemID >= 0x5142 && itemID < 0x514A) + return true; + #endregion + + return false; + } + } + + public class ConfirmCommitGump : Gump + { + private HouseFoundation m_Foundation; + + public ConfirmCommitGump( Mobile from, HouseFoundation foundation, int bankBalance, int oldPrice, int newPrice ) + : base( 50, 50 ) + { + m_Foundation = foundation; + + AddPage( 0 ); + + AddBackground( 0, 0, 320, 320, 5054 ); + + AddImageTiled( 10, 10, 300, 20, 2624 ); + AddImageTiled( 10, 40, 300, 240, 2624 ); + AddImageTiled( 10, 290, 300, 20, 2624 ); + + AddAlphaRegion( 10, 10, 300, 300 ); + + AddHtmlLocalized( 10, 10, 300, 20, 1062060, 32736, false, false ); //
COMMIT DESIGN
+ + AddHtmlLocalized( 10, 40, 300, 140, (newPrice - oldPrice) <= bankBalance ? 1061898 : 1061903, 1023, false, true ); + + AddHtmlLocalized( 10, 190, 150, 20, 1061902, 32736, false, false ); // Bank Balance: + AddLabel( 170, 190, 55, bankBalance.ToString() ); + + AddHtmlLocalized( 10, 215, 150, 20, 1061899, 1023, false, false ); // Old Value: + AddLabel( 170, 215, 90, oldPrice.ToString() ); + + AddHtmlLocalized( 10, 235, 150, 20, 1061900, 1023, false, false ); // Cost To Commit: + AddLabel( 170, 235, 90, newPrice.ToString() ); + + if ( newPrice - oldPrice < 0 ) + { + AddHtmlLocalized( 10, 260, 150, 20, 1062059, 992, false, false ); // Your Refund: + AddLabel( 170, 260, 70, (oldPrice - newPrice).ToString() ); + } + else + { + AddHtmlLocalized( 10, 260, 150, 20, 1061901, 31744, false, false ); // Your Cost: + AddLabel( 170, 260, 40, (newPrice - oldPrice).ToString() ); + } + + AddButton( 10, 290, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 290, 55, 20, 1011036, 32767, false, false ); // OKAY + + AddButton( 170, 290, 4005, 4007, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 195, 290, 55, 20, 1011012, 32767, false, false ); // CANCEL + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + if( info.ButtonID == 1 ) + m_Foundation.EndConfirmCommit( sender.Mobile ); + } + } + + public class DesignContext + { + private HouseFoundation m_Foundation; + private int m_Level; + + public HouseFoundation Foundation { get { return m_Foundation; } } + public int Level { get { return m_Level; } set { m_Level = value; } } + public int MaxLevels { get { return m_Foundation.MaxLevels; } } + + public DesignContext( HouseFoundation foundation ) + { + m_Foundation = foundation; + m_Level = 1; + } + + private static Dictionary m_Table = new Dictionary(); + + public static Dictionary Table { get { return m_Table; } } + + public static DesignContext Find( Mobile from ) + { + if( from == null ) + return null; + + DesignContext d; + m_Table.TryGetValue( from, out d ); + + return d; + } + + public static bool Check( Mobile m ) + { + if( Find( m ) != null ) + { + m.SendLocalizedMessage( 1062206 ); // You cannot do that while customizing a house. + return false; + } + + return true; + } + + public static void Add( Mobile from, HouseFoundation foundation ) + { + if( from == null ) + return; + + DesignContext c = new DesignContext( foundation ); + + m_Table[from] = c; + + if ( from is PlayerMobile ) + ((PlayerMobile)from).DesignContext = c; + + foundation.Customizer = from; + + from.Hidden = true; + from.Location = new Point3D( foundation.X, foundation.Y, foundation.Z + 7 ); + + NetState state = from.NetState; + + if( state == null ) + return; + + List fixtures = foundation.Fixtures; + + for( int i = 0; fixtures != null && i < fixtures.Count; ++i ) + { + Item item = fixtures[i]; + + state.Send( item.RemovePacket ); + } + + if( foundation.Signpost != null ) + state.Send( foundation.Signpost.RemovePacket ); + + if( foundation.SignHanger != null ) + state.Send( foundation.SignHanger.RemovePacket ); + + if( foundation.Sign != null ) + state.Send( foundation.Sign.RemovePacket ); + } + + public static void Remove( Mobile from ) + { + DesignContext context = Find( from ); + + if ( context == null ) + return; + + m_Table.Remove( from ); + + if( from is PlayerMobile ) + ((PlayerMobile)from).DesignContext = null; + + if( context == null ) + return; + + context.Foundation.Customizer = null; + + NetState state = from.NetState; + + if( state == null ) + return; + + List fixtures = context.Foundation.Fixtures; + + for( int i = 0; fixtures != null && i < fixtures.Count; ++i ) + { + Item item = fixtures[i]; + + item.SendInfoTo( state ); + } + + if( context.Foundation.Signpost != null ) + context.Foundation.Signpost.SendInfoTo( state ); + + if( context.Foundation.SignHanger != null ) + context.Foundation.SignHanger.SendInfoTo( state ); + + if( context.Foundation.Sign != null ) + context.Foundation.Sign.SendInfoTo( state ); + } + } + + public class BeginHouseCustomization : Packet + { + public BeginHouseCustomization( HouseFoundation house ) + : base( 0xBF ) + { + EnsureCapacity( 17 ); + + m_Stream.Write( (short)0x20 ); + m_Stream.Write( (int)house.Serial ); + m_Stream.Write( (byte)0x04 ); + m_Stream.Write( (ushort)0x0000 ); + m_Stream.Write( (ushort)0xFFFF ); + m_Stream.Write( (ushort)0xFFFF ); + m_Stream.Write( (byte)0xFF ); + } + } + + public class EndHouseCustomization : Packet + { + public EndHouseCustomization( HouseFoundation house ) + : base( 0xBF ) + { + EnsureCapacity( 17 ); + + m_Stream.Write( (short)0x20 ); + m_Stream.Write( (int)house.Serial ); + m_Stream.Write( (byte)0x05 ); + m_Stream.Write( (ushort)0x0000 ); + m_Stream.Write( (ushort)0xFFFF ); + m_Stream.Write( (ushort)0xFFFF ); + m_Stream.Write( (byte)0xFF ); + } + } + + public sealed class DesignStateGeneral : Packet + { + public DesignStateGeneral( HouseFoundation house, DesignState state ) + : base( 0xBF ) + { + EnsureCapacity( 13 ); + + m_Stream.Write( (short)0x1D ); + m_Stream.Write( (int)house.Serial ); + m_Stream.Write( (int)state.Revision ); + } + } + + public sealed class DesignStateDetailed : Packet + { + public const int MaxItemsPerStairBuffer = 750; + + private static byte[][] m_PlaneBuffers; + private static bool[] m_PlaneUsed; + + private static byte[][] m_StairBuffers; + + private static byte[] m_PrimBuffer = new byte[4]; + + public void Write( int value ) + { + m_PrimBuffer[0] = (byte)(value >> 24); + m_PrimBuffer[1] = (byte)(value >> 16); + m_PrimBuffer[2] = (byte)(value >> 8); + m_PrimBuffer[3] = (byte)value; + + m_Stream.UnderlyingStream.Write( m_PrimBuffer, 0, 4 ); + } + + public void Write( short value ) + { + m_PrimBuffer[0] = (byte)(value >> 8); + m_PrimBuffer[1] = (byte)value; + + m_Stream.UnderlyingStream.Write( m_PrimBuffer, 0, 2 ); + } + + public void Write( byte value ) + { + m_Stream.UnderlyingStream.WriteByte( value ); + } + + public void Write( byte[] buffer, int offset, int size ) + { + m_Stream.UnderlyingStream.Write( buffer, offset, size ); + } + + public static void Clear( byte[] buffer, int size ) + { + for( int i = 0; i < size; ++i ) + buffer[i] = 0; + } + + public DesignStateDetailed( int serial, int revision, int xMin, int yMin, int xMax, int yMax, MultiTileEntry[] tiles ) + : base( 0xD8 ) + { + EnsureCapacity( 17 + (tiles.Length * 5) ); + + Write( (byte)0x03 ); // Compression Type + Write( (byte)0x00 ); // Unknown + Write( (int)serial ); + Write( (int)revision ); + Write( (short)tiles.Length ); + Write( (short)0 ); // Buffer length : reserved + Write( (byte)0 ); // Plane count : reserved + + int totalLength = 1; // includes plane count + + int width = (xMax - xMin) + 1; + int height = (yMax - yMin) + 1; + + if( m_PlaneBuffers == null ) + { + m_PlaneBuffers = new byte[9][]; + m_PlaneUsed = new bool[9]; + + for( int i = 0; i < m_PlaneBuffers.Length; ++i ) + m_PlaneBuffers[i] = new byte[0x400]; + + m_StairBuffers = new byte[6][]; + + for( int i = 0; i < m_StairBuffers.Length; ++i ) + m_StairBuffers[i] = new byte[MaxItemsPerStairBuffer * 5]; + } + else + { + for( int i = 0; i < m_PlaneUsed.Length; ++i ) + m_PlaneUsed[i] = false; + + Clear( m_PlaneBuffers[0], width * height * 2 ); + + for( int i = 0; i < 4; ++i ) + { + Clear( m_PlaneBuffers[1 + i], (width - 1) * (height - 2) * 2 ); + Clear( m_PlaneBuffers[5 + i], width * (height - 1) * 2 ); + } + } + + int totalStairsUsed = 0; + + for( int i = 0; i < tiles.Length; ++i ) + { + MultiTileEntry mte = tiles[i]; + int x = mte.m_OffsetX - xMin; + int y = mte.m_OffsetY - yMin; + int z = mte.m_OffsetZ; + bool floor = (TileData.ItemTable[mte.m_ItemID & TileData.MaxItemValue].Height <= 0); + int plane, size; + + switch( z ) + { + case 0: plane = 0; break; + case 7: plane = 1; break; + case 27: plane = 2; break; + case 47: plane = 3; break; + case 67: plane = 4; break; + default: + { + int stairBufferIndex = (totalStairsUsed / MaxItemsPerStairBuffer); + byte[] stairBuffer = m_StairBuffers[stairBufferIndex]; + + int byteIndex = (totalStairsUsed % MaxItemsPerStairBuffer) * 5; + + stairBuffer[byteIndex++] = (byte)(mte.m_ItemID >> 8); + stairBuffer[byteIndex++] = (byte)mte.m_ItemID; + + stairBuffer[byteIndex++] = (byte)mte.m_OffsetX; + stairBuffer[byteIndex++] = (byte)mte.m_OffsetY; + stairBuffer[byteIndex++] = (byte)mte.m_OffsetZ; + + ++totalStairsUsed; + + continue; + } + } + + if( plane == 0 ) + { + size = height; + } + else if( floor ) + { + size = height - 2; + x -= 1; + y -= 1; + } + else + { + size = height - 1; + plane += 4; + } + + int index = ((x * size) + y) * 2; + + if( x < 0 || y < 0 || y >= size || (index + 1) >= 0x400 ) + { + int stairBufferIndex = (totalStairsUsed / MaxItemsPerStairBuffer); + byte[] stairBuffer = m_StairBuffers[stairBufferIndex]; + + int byteIndex = (totalStairsUsed % MaxItemsPerStairBuffer) * 5; + + stairBuffer[byteIndex++] = (byte)(mte.m_ItemID >> 8); + stairBuffer[byteIndex++] = (byte)mte.m_ItemID; + + stairBuffer[byteIndex++] = (byte)mte.m_OffsetX; + stairBuffer[byteIndex++] = (byte)mte.m_OffsetY; + stairBuffer[byteIndex++] = (byte)mte.m_OffsetZ; + + ++totalStairsUsed; + } + else + { + m_PlaneUsed[plane] = true; + m_PlaneBuffers[plane][index] = (byte)(mte.m_ItemID >> 8); + m_PlaneBuffers[plane][index + 1] = (byte)mte.m_ItemID; + } + } + + int planeCount = 0; + + for( int i = 0; i < m_PlaneBuffers.Length; ++i ) + { + if( !m_PlaneUsed[i] ) + continue; + + ++planeCount; + + int size = 0; + + if( i == 0 ) + size = width * height * 2; + else if( i < 5 ) + size = (width - 1) * (height - 2) * 2; + else + size = width * (height - 1) * 2; + + byte[] inflatedBuffer = m_PlaneBuffers[i]; + + int deflatedLength = m_DeflatedBuffer.Length; + ZLibError ce = Compression.Pack( m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size, ZLibQuality.Default ); + + if( ce != ZLibError.Okay ) + { + Console.WriteLine( "ZLib error: {0} (#{1})", ce, (int)ce ); + deflatedLength = 0; + size = 0; + } + + Write( (byte)(0x20 | i) ); + Write( (byte)size ); + Write( (byte)deflatedLength ); + Write( (byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)) ); + Write( m_DeflatedBuffer, 0, deflatedLength ); + + totalLength += 4 + deflatedLength; + } + + int totalStairBuffersUsed = (totalStairsUsed + (MaxItemsPerStairBuffer - 1)) / MaxItemsPerStairBuffer; + + for( int i = 0; i < totalStairBuffersUsed; ++i ) + { + ++planeCount; + + int count = (totalStairsUsed - (i * MaxItemsPerStairBuffer)); + + if( count > MaxItemsPerStairBuffer ) + count = MaxItemsPerStairBuffer; + + int size = count * 5; + + byte[] inflatedBuffer = m_StairBuffers[i]; + + int deflatedLength = m_DeflatedBuffer.Length; + ZLibError ce = Compression.Pack( m_DeflatedBuffer, ref deflatedLength, inflatedBuffer, size, ZLibQuality.Default ); + + if( ce != ZLibError.Okay ) + { + Console.WriteLine( "ZLib error: {0} (#{1})", ce, (int)ce ); + deflatedLength = 0; + size = 0; + } + + Write( (byte)(9 + i) ); + Write( (byte)size ); + Write( (byte)deflatedLength ); + Write( (byte)(((size >> 4) & 0xF0) | ((deflatedLength >> 8) & 0xF)) ); + Write( m_DeflatedBuffer, 0, deflatedLength ); + + totalLength += 4 + deflatedLength; + } + + m_Stream.Seek( 15, System.IO.SeekOrigin.Begin ); + + Write( (short)totalLength ); // Buffer length + Write( (byte)planeCount ); // Plane count + } + + private static byte[] m_InflatedBuffer = new byte[0x2000]; + private static byte[] m_DeflatedBuffer = new byte[0x2000]; + + private class SendQueueEntry + { + public NetState m_NetState; + public int m_Serial, m_Revision; + public int m_xMin, m_yMin, m_xMax, m_yMax; + public DesignState m_Root; + public MultiTileEntry[] m_Tiles; + + public SendQueueEntry( NetState ns, HouseFoundation foundation, DesignState state ) + { + m_NetState = ns; + m_Serial = foundation.Serial; + m_Revision = state.Revision; + m_Root = state; + + MultiComponentList mcl = state.Components; + + m_xMin = mcl.Min.X; + m_yMin = mcl.Min.Y; + m_xMax = mcl.Max.X; + m_yMax = mcl.Max.Y; + + m_Tiles = mcl.List; + } + } + + private static Queue m_SendQueue; + private static object m_SendQueueSyncRoot; + private static AutoResetEvent m_Sync; + private static Thread m_Thread; + + static DesignStateDetailed() + { + m_SendQueue = new Queue(); + m_SendQueueSyncRoot = ((ICollection)m_SendQueue).SyncRoot; + m_Sync = new AutoResetEvent( false ); + + m_Thread = new Thread( new ThreadStart( CompressionThread ) ); + m_Thread.Name = "AOS Compression Thread"; + m_Thread.Start(); + } + + public static void CompressionThread() + { + while( !Core.Closing ) + { + m_Sync.WaitOne(); + + int count; + + lock ( m_SendQueueSyncRoot ) + count = m_SendQueue.Count; + + while( count > 0 ) + { + SendQueueEntry sqe = null; + + lock ( m_SendQueueSyncRoot ) + sqe = m_SendQueue.Dequeue(); + + try + { + Packet p = null; + + lock( sqe.m_Root ) + p = sqe.m_Root.PacketCache; + + if( p == null ) + { + p = new DesignStateDetailed( sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax, sqe.m_yMax, sqe.m_Tiles ); + p.SetStatic(); + + lock( sqe.m_Root ) + { + if( sqe.m_Revision == sqe.m_Root.Revision ) + sqe.m_Root.PacketCache = p; + } + } + + Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( SendPacket_Sandbox ), new object[] { sqe.m_NetState, p } ); + } + catch( Exception e ) + { + Console.WriteLine( e ); + + try + { + using( StreamWriter op = new StreamWriter( "dsd_exceptions.txt", true ) ) + op.WriteLine( e ); + } + catch + { + } + } + finally + { + lock ( m_SendQueueSyncRoot ) + count = m_SendQueue.Count; + } + + //sqe.m_NetState.Send( new DesignStateDetailed( sqe.m_Serial, sqe.m_Revision, sqe.m_xMin, sqe.m_yMin, sqe.m_xMax, sqe.m_yMax, sqe.m_Tiles ) ); + } + } + } + + public static void SendPacket_Sandbox( object state ) + { + object[] states = (object[])state; + NetState ns = (NetState)states[0]; + Packet p = (Packet)states[1]; + + ns.Send( p ); + } + + public static void SendDetails( NetState ns, HouseFoundation house, DesignState state ) + { + lock ( m_SendQueueSyncRoot ) + m_SendQueue.Enqueue( new SendQueueEntry( ns, house, state ) ); + m_Sync.Set(); + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/HousePlacement.cs b/Scripts/Multis/HousePlacement.cs new file mode 100644 index 0000000..1b9d120 --- /dev/null +++ b/Scripts/Multis/HousePlacement.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Guilds; +using Server.Items; +using Server.Misc; +using Server.Regions; +using Server.Spells; + +namespace Server.Multis +{ + public enum HousePlacementResult + { + Valid, + BadRegion, + BadLand, + BadStatic, + BadItem, + NoSurface, + BadRegionHidden, + BadRegionTemp, + InvalidCastleKeep, + BadRegionRaffle + } + + public class HousePlacement + { + private const int YardSize = 5; + + // Any land tile which matches one of these ID numbers is considered a road and cannot be placed over. + private static int[] m_RoadIDs = new int[] + { + 0x0071, 0x0078, + 0x00E8, 0x00EB, + 0x07AE, 0x07B1, + 0x3FF4, 0x3FF4, + 0x3FF8, 0x3FFB, + 0x0442, 0x0479, // Sand stones + 0x0501, 0x0510, // Sand stones + 0x0009, 0x0015, // Furrows + 0x0150, 0x015C // Furrows + }; + + public static HousePlacementResult Check( Mobile from, int multiID, Point3D center, out ArrayList toMove ) + { + // If this spot is considered valid, every item and mobile in this list will be moved under the house sign + toMove = new ArrayList(); + + Map map = from.Map; + + if ( map == null || map == Map.Internal ) + return HousePlacementResult.BadLand; // A house cannot go here + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + return HousePlacementResult.Valid; // Staff can place anywhere + + if ( map == Map.Ilshenar || SpellHelper.IsFeluccaT2A( map, center ) ) + return HousePlacementResult.BadRegion; // No houses in Ilshenar/T2A + + if ( map == Map.Malas && ( multiID == 0x007C || multiID == 0x007E ) ) + return HousePlacementResult.InvalidCastleKeep; + + NoHousingRegion noHousingRegion = (NoHousingRegion) Region.Find( center, map ).GetRegion( typeof( NoHousingRegion ) ); + + if ( noHousingRegion != null ) + return HousePlacementResult.BadRegion; + + // This holds data describing the internal structure of the house + MultiComponentList mcl = MultiData.GetComponents( multiID ); + + if ( multiID >= 0x13EC && multiID < 0x1D00 ) + HouseFoundation.AddStairsTo( ref mcl ); // this is a AOS house, add the stairs + + // Location of the nortwest-most corner of the house + Point3D start = new Point3D( center.X + mcl.Min.X, center.Y + mcl.Min.Y, center.Z ); + + // These are storage lists. They hold items and mobiles found in the map for further processing + List items = new List(); + List mobiles = new List(); + + // These are also storage lists. They hold location values indicating the yard and border locations. + List yard = new List(), borders = new List(); + + /* RULES: + * + * 1) All tiles which are around the -outside- of the foundation must not have anything impassable. + * 2) No impassable object or land tile may come in direct contact with any part of the house. + * 3) Five tiles from the front and back of the house must be completely clear of all house tiles. + * 4) The foundation must rest flatly on a surface. Any bumps around the foundation are not allowed. + * 5) No foundation tile may reside over terrain which is viewed as a road. + */ + + for ( int x = 0; x < mcl.Width; ++x ) + { + for ( int y = 0; y < mcl.Height; ++y ) + { + int tileX = start.X + x; + int tileY = start.Y + y; + + StaticTile[] addTiles = mcl.Tiles[x][y]; + + if ( addTiles.Length == 0 ) + continue; // There are no tiles here, continue checking somewhere else + + Point3D testPoint = new Point3D( tileX, tileY, center.Z ); + + Region reg = Region.Find( testPoint, map ); + + if ( !reg.AllowHousing( from, testPoint ) ) // Cannot place houses in dungeons, towns, treasure map areas etc + { + if ( reg.IsPartOf( typeof( TempNoHousingRegion ) ) ) + return HousePlacementResult.BadRegionTemp; + + if (reg.IsPartOf(typeof(TreasureRegion)) || reg.IsPartOf(typeof(HouseRegion))) + return HousePlacementResult.BadRegionHidden; + + if (reg.IsPartOf(typeof(HouseRaffleRegion))) + return HousePlacementResult.BadRegionRaffle; + + return HousePlacementResult.BadRegion; + } + + LandTile landTile = map.Tiles.GetLandTile( tileX, tileY ); + int landID = landTile.ID & TileData.MaxLandValue; + + StaticTile[] oldTiles = map.Tiles.GetStaticTiles( tileX, tileY, true ); + + Sector sector = map.GetSector( tileX, tileY ); + + items.Clear(); + + for ( int i = 0; i < sector.Items.Count; ++i ) + { + Item item = sector.Items[i]; + + if ( item.Visible && item.X == tileX && item.Y == tileY ) + items.Add( item ); + } + + mobiles.Clear(); + + for ( int i = 0; i < sector.Mobiles.Count; ++i ) + { + Mobile m = sector.Mobiles[i]; + + if ( m.X == tileX && m.Y == tileY ) + mobiles.Add( m ); + } + + int landStartZ = 0, landAvgZ = 0, landTopZ = 0; + + map.GetAverageZ( tileX, tileY, ref landStartZ, ref landAvgZ, ref landTopZ ); + + bool hasFoundation = false; + + for ( int i = 0; i < addTiles.Length; ++i ) + { + StaticTile addTile = addTiles[i]; + + if ( addTile.ID == 0x1 ) // Nodraw + continue; + + TileFlag addTileFlags = TileData.ItemTable[addTile.ID & TileData.MaxItemValue].Flags; + + bool isFoundation = ( addTile.Z == 0 && (addTileFlags & TileFlag.Wall) != 0 ); + bool hasSurface = false; + + if ( isFoundation ) + hasFoundation = true; + + int addTileZ = center.Z + addTile.Z; + int addTileTop = addTileZ + addTile.Height; + + if ( (addTileFlags & TileFlag.Surface) != 0 ) + addTileTop += 16; + + if ( addTileTop > landStartZ && landAvgZ > addTileZ ) + return HousePlacementResult.BadLand; // Broke rule #2 + + if ( isFoundation && ((TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) == 0) && landAvgZ == center.Z ) + hasSurface = true; + + for ( int j = 0; j < oldTiles.Length; ++j ) + { + StaticTile oldTile = oldTiles[j]; + ItemData id = TileData.ItemTable[oldTile.ID & TileData.MaxItemValue]; + + if ( (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) && addTileTop > oldTile.Z && (oldTile.Z + id.CalcHeight) > addTileZ ) + return HousePlacementResult.BadStatic; // Broke rule #2 + /*else if ( isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (oldTile.Z + id.CalcHeight) == center.Z ) + hasSurface = true;*/ + } + + for ( int j = 0; j < items.Count; ++j ) + { + Item item = items[j]; + ItemData id = item.ItemData; + + if ( addTileTop > item.Z && (item.Z + id.CalcHeight) > addTileZ ) + { + if ( item.Movable ) + toMove.Add( item ); + else if ( (id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0)) ) + return HousePlacementResult.BadItem; // Broke rule #2 + } + /*else if ( isFoundation && !hasSurface && (id.Flags & TileFlag.Surface) != 0 && (item.Z + id.CalcHeight) == center.Z ) + { + hasSurface = true; + }*/ + } + + if ( isFoundation && !hasSurface ) + return HousePlacementResult.NoSurface; // Broke rule #4 + + for ( int j = 0; j < mobiles.Count; ++j ) + { + Mobile m = mobiles[j]; + + if ( addTileTop > m.Z && (m.Z + 16) > addTileZ ) + toMove.Add( m ); + } + } + + for ( int i = 0; i < m_RoadIDs.Length; i += 2 ) + { + if ( landID >= m_RoadIDs[i] && landID <= m_RoadIDs[i + 1] ) + return HousePlacementResult.BadLand; // Broke rule #5 + } + + if ( hasFoundation ) + { + for ( int xOffset = -1; xOffset <= 1; ++xOffset ) + { + for ( int yOffset = -YardSize; yOffset <= YardSize; ++yOffset ) + { + Point2D yardPoint = new Point2D( tileX + xOffset, tileY + yOffset ); + + if ( !yard.Contains( yardPoint ) ) + yard.Add( yardPoint ); + } + } + + for ( int xOffset = -1; xOffset <= 1; ++xOffset ) + { + for ( int yOffset = -1; yOffset <= 1; ++yOffset ) + { + if ( xOffset == 0 && yOffset == 0 ) + continue; + + // To ease this rule, we will not add to the border list if the tile here is under a base floor (z<=8) + + int vx = x + xOffset; + int vy = y + yOffset; + + if ( vx >= 0 && vx < mcl.Width && vy >= 0 && vy < mcl.Height ) + { + StaticTile[] breakTiles = mcl.Tiles[vx][vy]; + bool shouldBreak = false; + + for ( int i = 0; !shouldBreak && i < breakTiles.Length; ++i ) + { + StaticTile breakTile = breakTiles[i]; + + if ( breakTile.Height == 0 && breakTile.Z <= 8 && TileData.ItemTable[breakTile.ID & TileData.MaxItemValue].Surface ) + shouldBreak = true; + } + + if ( shouldBreak ) + continue; + } + + Point2D borderPoint = new Point2D( tileX + xOffset, tileY + yOffset ); + + if ( !borders.Contains( borderPoint ) ) + borders.Add( borderPoint ); + } + } + } + } + } + + for ( int i = 0; i < borders.Count; ++i ) + { + Point2D borderPoint = borders[i]; + + LandTile landTile = map.Tiles.GetLandTile( borderPoint.X, borderPoint.Y ); + int landID = landTile.ID & TileData.MaxLandValue; + + if ( (TileData.LandTable[landID].Flags & TileFlag.Impassable) != 0 ) + return HousePlacementResult.BadLand; + + for ( int j = 0; j < m_RoadIDs.Length; j += 2 ) + { + if ( landID >= m_RoadIDs[j] && landID <= m_RoadIDs[j + 1] ) + return HousePlacementResult.BadLand; // Broke rule #5 + } + + StaticTile[] tiles = map.Tiles.GetStaticTiles( borderPoint.X, borderPoint.Y, true ); + + for ( int j = 0; j < tiles.Length; ++j ) + { + StaticTile tile = tiles[j]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + if ( id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && (tile.Z + id.CalcHeight) > (center.Z + 2)) ) + return HousePlacementResult.BadStatic; // Broke rule #1 + } + + Sector sector = map.GetSector( borderPoint.X, borderPoint.Y ); + List sectorItems = sector.Items; + + for ( int j = 0; j < sectorItems.Count; ++j ) + { + Item item = sectorItems[j]; + + if ( item.X != borderPoint.X || item.Y != borderPoint.Y || item.Movable ) + continue; + + ItemData id = item.ItemData; + + if ( id.Impassable || (id.Surface && (id.Flags & TileFlag.Background) == 0 && (item.Z + id.CalcHeight) > (center.Z + 2)) ) + return HousePlacementResult.BadItem; // Broke rule #1 + } + } + + List _sectors = new List(); + List _houses = new List(); + + for ( int i = 0; i < yard.Count; i++ ) { + Sector sector = map.GetSector( yard[i] ); + + if ( !_sectors.Contains( sector ) ) { + _sectors.Add( sector ); + + if ( sector.Multis != null ) { + for ( int j = 0; j < sector.Multis.Count; j++ ) { + if ( sector.Multis[j] is BaseHouse ) { + BaseHouse _house = (BaseHouse)sector.Multis[j]; + if ( !_houses.Contains( _house ) ) { + _houses.Add( _house ); + } + } + } + } + } + } + + for ( int i = 0; i < yard.Count; ++i ) + { + foreach ( BaseHouse b in _houses ) { + if ( b.Contains( yard[i] ) ) + return HousePlacementResult.BadStatic; // Broke rule #3 + } + + /*Point2D yardPoint = yard[i]; + + IPooledEnumerable eable = map.GetMultiTilesAt( yardPoint.X, yardPoint.Y ); + + foreach ( StaticTile[] tile in eable ) + { + for ( int j = 0; j < tile.Length; ++j ) + { + if ( (TileData.ItemTable[tile[j].ID & TileData.MaxItemValue].Flags & (TileFlag.Impassable | TileFlag.Surface)) != 0 ) + { + eable.Free(); + return HousePlacementResult.BadStatic; // Broke rule #3 + } + } + } + + eable.Free();*/ + } + + return HousePlacementResult.Valid; + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/HousePlacementTool.cs b/Scripts/Multis/HousePlacementTool.cs new file mode 100644 index 0000000..afd36e6 --- /dev/null +++ b/Scripts/Multis/HousePlacementTool.cs @@ -0,0 +1,794 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Mobiles; +using Server.Regions; +using Server.Targeting; + +namespace Server.Items +{ + public class HousePlacementTool : Item + { + public override int LabelNumber{ get{ return 1060651; } } // a house placement tool + + [Constructable] + public HousePlacementTool() : base( 0x14F6 ) + { + Weight = 3.0; + LootType = LootType.Blessed; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( IsChildOf( from.Backpack ) ) + from.SendGump( new HousePlacementCategoryGump( from ) ); + else + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + + public HousePlacementTool( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 0.0 ) + Weight = 3.0; + } + } + + public class HousePlacementCategoryGump : Gump + { + private Mobile m_From; + + private const int LabelColor = 0x7FFF; + private const int LabelColorDisabled = 0x4210; + + public HousePlacementCategoryGump( Mobile from ) : base( 50, 50 ) + { + m_From = from; + + from.CloseGump( typeof( HousePlacementCategoryGump ) ); + from.CloseGump( typeof( HousePlacementListGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 270, 145, 5054 ); + + AddImageTiled( 10, 10, 250, 125, 2624 ); + AddAlphaRegion( 10, 10, 250, 125 ); + + AddHtmlLocalized( 10, 10, 250, 20, 1060239, LabelColor, false, false ); //
HOUSE PLACEMENT TOOL
+ + AddButton( 10, 110, 4017, 4019, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 110, 150, 20, 3000363, LabelColor, false, false ); // Close + + AddButton( 10, 40, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 40, 200, 20, 1060390, LabelColor, false, false ); // Classic Houses + + AddButton( 10, 60, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 60, 200, 20, 1060391, LabelColor, false, false ); // 2-Story Customizable Houses + + AddButton( 10, 80, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 45, 80, 200, 20, 1060392, LabelColor, false, false ); // 3-Story Customizable Houses + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( !m_From.CheckAlive() || m_From.Backpack == null || m_From.Backpack.FindItemByType( typeof( HousePlacementTool ) ) == null ) + return; + + switch ( info.ButtonID ) + { + case 1: // Classic Houses + { + m_From.SendGump( new HousePlacementListGump( m_From, HousePlacementEntry.ClassicHouses ) ); + break; + } + case 2: // 2-Story Customizable Houses + { + m_From.SendGump( new HousePlacementListGump( m_From, HousePlacementEntry.TwoStoryFoundations ) ); + break; + } + case 3: // 3-Story Customizable Houses + { + m_From.SendGump( new HousePlacementListGump( m_From, HousePlacementEntry.ThreeStoryFoundations ) ); + break; + } + } + } + } + + public class HousePlacementListGump : Gump + { + private Mobile m_From; + private HousePlacementEntry[] m_Entries; + + private const int LabelColor = 0x7FFF; + private const int LabelHue = 0x480; + + public HousePlacementListGump( Mobile from, HousePlacementEntry[] entries ) : base( 50, 50 ) + { + m_From = from; + m_Entries = entries; + + from.CloseGump( typeof( HousePlacementCategoryGump ) ); + from.CloseGump( typeof( HousePlacementListGump ) ); + + AddPage( 0 ); + + AddBackground( 0, 0, 520, 420, 5054 ); + + AddImageTiled( 10, 10, 500, 20, 2624 ); + AddAlphaRegion( 10, 10, 500, 20 ); + + AddHtmlLocalized( 10, 10, 500, 20, 1060239, LabelColor, false, false ); //
HOUSE PLACEMENT TOOL
+ + AddImageTiled( 10, 40, 500, 20, 2624 ); + AddAlphaRegion( 10, 40, 500, 20 ); + + AddHtmlLocalized( 50, 40, 225, 20, 1060235, LabelColor, false, false ); // House Description + AddHtmlLocalized( 275, 40, 75, 20, 1060236, LabelColor, false, false ); // Storage + AddHtmlLocalized( 350, 40, 75, 20, 1060237, LabelColor, false, false ); // Lockdowns + AddHtmlLocalized( 425, 40, 75, 20, 1060034, LabelColor, false, false ); // Cost + + AddImageTiled( 10, 70, 500, 280, 2624 ); + AddAlphaRegion( 10, 70, 500, 280 ); + + AddImageTiled( 10, 360, 500, 20, 2624 ); + AddAlphaRegion( 10, 360, 500, 20 ); + + AddHtmlLocalized( 10, 360, 250, 20, 1060645, LabelColor, false, false ); // Bank Balance: + AddLabel( 250, 360, LabelHue, Banker.GetBalance( from ).ToString() ); + + AddImageTiled( 10, 390, 500, 20, 2624 ); + AddAlphaRegion( 10, 390, 500, 20 ); + + AddButton( 10, 390, 4017, 4019, 0, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, 390, 100, 20, 3000363, LabelColor, false, false ); // Close + + for ( int i = 0; i < entries.Length; ++i ) + { + int page = 1 + (i / 14); + int index = i % 14; + + if ( index == 0 ) + { + if ( page > 1 ) + { + AddButton( 450, 390, 4005, 4007, 0, GumpButtonType.Page, page ); + AddHtmlLocalized( 400, 390, 100, 20, 3000406, LabelColor, false, false ); // Next + } + + AddPage( page ); + + if ( page > 1 ) + { + AddButton( 200, 390, 4014, 4016, 0, GumpButtonType.Page, page - 1 ); + AddHtmlLocalized( 250, 390, 100, 20, 3000405, LabelColor, false, false ); // Previous + } + } + + HousePlacementEntry entry = entries[i]; + + int y = 70 + (index * 20); + + AddButton( 10, y, 4005, 4007, 1 + i, GumpButtonType.Reply, 0 ); + AddHtmlLocalized( 50, y, 225, 20, entry.Description, LabelColor, false, false ); + AddLabel( 275, y, LabelHue, entry.Storage.ToString() ); + AddLabel( 350, y, LabelHue, entry.Lockdowns.ToString() ); + AddLabel( 425, y, LabelHue, entry.Cost.ToString() ); + } + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + if ( !m_From.CheckAlive() || m_From.Backpack == null || m_From.Backpack.FindItemByType( typeof( HousePlacementTool ) ) == null ) + return; + + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_Entries.Length ) + { + if ( m_From.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse( m_From ) ) + m_From.SendLocalizedMessage( 501271 ); // You already own a house, you may not place another! + else + m_From.Target = new NewHousePlacementTarget( m_Entries, m_Entries[index] ); + } + else + { + m_From.SendGump( new HousePlacementCategoryGump( m_From ) ); + } + } + } + + public class NewHousePlacementTarget : MultiTarget + { + private HousePlacementEntry m_Entry; + private HousePlacementEntry[] m_Entries; + + private bool m_Placed; + + public NewHousePlacementTarget( HousePlacementEntry[] entries, HousePlacementEntry entry ) : base( entry.MultiID, entry.Offset ) + { + Range = 14; + + m_Entries = entries; + m_Entry = entry; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( !from.CheckAlive() || from.Backpack == null || from.Backpack.FindItemByType( typeof( HousePlacementTool ) ) == null ) + return; + + IPoint3D ip = o as IPoint3D; + + if ( ip != null ) + { + if ( ip is Item ) + ip = ((Item)ip).GetWorldTop(); + + Point3D p = new Point3D( ip ); + + Region reg = Region.Find( new Point3D( p ), from.Map ); + + if ( from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing( from, p ) ) + m_Placed = m_Entry.OnPlacement( from, p ); + else if (reg.IsPartOf(typeof(TempNoHousingRegion))) + from.SendLocalizedMessage(501270); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + else if (reg.IsPartOf(typeof(TreasureRegion)) || reg.IsPartOf(typeof(HouseRegion))) + from.SendLocalizedMessage(1043287); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + else if ( reg.IsPartOf( typeof( HouseRaffleRegion ) ) ) + from.SendLocalizedMessage( 1150493 ); // You must have a deed for this plot of land in order to build here. + else + from.SendLocalizedMessage( 501265 ); // Housing can not be created in this area. + } + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( !from.CheckAlive() || from.Backpack == null || from.Backpack.FindItemByType( typeof( HousePlacementTool ) ) == null ) + return; + + if ( !m_Placed ) + from.SendGump( new HousePlacementListGump( from, m_Entries ) ); + } + } + + public class HousePlacementEntry + { + private Type m_Type; + private int m_Description; + private int m_Storage; + private int m_Lockdowns; + private int m_NewStorage; + private int m_NewLockdowns; + private int m_Vendors; + private int m_Cost; + private int m_MultiID; + private Point3D m_Offset; + + public Type Type{ get{ return m_Type; } } + + public int Description{ get{ return m_Description; } } + public int Storage{ get{ return BaseHouse.NewVendorSystem ? m_NewStorage : m_Storage; } } + public int Lockdowns{ get{ return BaseHouse.NewVendorSystem ? m_NewLockdowns : m_Lockdowns; } } + public int Vendors{ get{ return m_Vendors; } } + public int Cost{ get{ return m_Cost; } } + + public int MultiID{ get{ return m_MultiID; } } + public Point3D Offset{ get{ return m_Offset; } } + + public HousePlacementEntry( Type type, int description, int storage, int lockdowns, int newStorage, int newLockdowns, int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID ) + { + m_Type = type; + m_Description = description; + m_Storage = storage; + m_Lockdowns = lockdowns; + m_NewStorage = newStorage; + m_NewLockdowns = newLockdowns; + m_Vendors = vendors; + m_Cost = cost; + + m_Offset = new Point3D( xOffset, yOffset, zOffset ); + + m_MultiID = multiID; + } + + public BaseHouse ConstructHouse( Mobile from ) + { + try + { + object[] args; + + if ( m_Type == typeof( HouseFoundation ) ) + args = new object[4]{ from, m_MultiID, m_Storage, m_Lockdowns }; + else if ( m_Type == typeof( SmallOldHouse ) || m_Type == typeof( SmallShop ) || m_Type == typeof( TwoStoryHouse ) ) + args = new object[2]{ from, m_MultiID }; + else + args = new object[1]{ from }; + + return Activator.CreateInstance( m_Type, args ) as BaseHouse; + } + catch + { + } + + return null; + } + + public void PlacementWarning_Callback( Mobile from, bool okay, object state ) + { + if ( !from.CheckAlive() || from.Backpack == null || from.Backpack.FindItemByType( typeof( HousePlacementTool ) ) == null ) + return; + + PreviewHouse prevHouse = (PreviewHouse)state; + + if ( !okay ) + { + prevHouse.Delete(); + return; + } + + if ( prevHouse.Deleted ) + { + /* Too much time has passed and the test house you created has been deleted. + * Please try again! + */ + from.SendGump( new NoticeGump( 1060637, 30720, 1060647, 32512, 320, 180, null, null ) ); + + return; + } + + Point3D center = prevHouse.Location; + Map map = prevHouse.Map; + + prevHouse.Delete(); + + ArrayList toMove; + //Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); + HousePlacementResult res = HousePlacement.Check( from, m_MultiID, center, out toMove ); + + switch ( res ) + { + case HousePlacementResult.Valid: + { + if ( from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse( from ) ) + { + from.SendLocalizedMessage( 501271 ); // You already own a house, you may not place another! + } + else + { + BaseHouse house = ConstructHouse( from ); + + if ( house == null ) + return; + + house.Price = m_Cost; + + if ( from.AccessLevel >= AccessLevel.GameMaster ) + { + from.SendMessage( "{0} gold would have been withdrawn from your bank if you were not a GM.", m_Cost.ToString() ); + } + else + { + if ( Banker.Withdraw( from, m_Cost ) ) + { + from.SendLocalizedMessage( 1060398, m_Cost.ToString() ); // ~1_AMOUNT~ gold has been withdrawn from your bank box. + } + else + { + house.RemoveKeys( from ); + house.Delete(); + from.SendLocalizedMessage( 1060646 ); // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. + return; + } + } + + house.MoveToWorld( center, from.Map ); + + for ( int i = 0; i < toMove.Count; ++i ) + { + object o = toMove[ i ]; + + if ( o is Mobile ) + ( (Mobile) o ).Location = house.BanLocation; + else if ( o is Item ) + ( (Item) o ).Location = house.BanLocation; + } + } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + case HousePlacementResult.NoSurface: + { + from.SendLocalizedMessage( 1043287 ); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage( 501265 ); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + from.SendLocalizedMessage( 501270 ); // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + break; + } + case HousePlacementResult.BadRegionRaffle: + { + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + break; + } + case HousePlacementResult.InvalidCastleKeep: + { + from.SendLocalizedMessage( 1061122 ); // Castles and keeps cannot be created here. + break; + } + } + } + + public bool OnPlacement( Mobile from, Point3D p ) + { + if ( !from.CheckAlive() || from.Backpack == null || from.Backpack.FindItemByType( typeof( HousePlacementTool ) ) == null ) + return false; + + ArrayList toMove; + Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); + HousePlacementResult res = HousePlacement.Check( from, m_MultiID, center, out toMove ); + + switch ( res ) + { + case HousePlacementResult.Valid: + { + if ( from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse( from ) ) + { + from.SendLocalizedMessage( 501271 ); // You already own a house, you may not place another! + } + else + { + from.SendLocalizedMessage( 1011576 ); // This is a valid location. + + PreviewHouse prev = new PreviewHouse( m_MultiID ); + + MultiComponentList mcl = prev.Components; + + Point3D banLoc = new Point3D( center.X + mcl.Min.X, center.Y + mcl.Max.Y + 1, center.Z ); + + for ( int i = 0; i < mcl.List.Length; ++i ) + { + MultiTileEntry entry = mcl.List[i]; + + int itemID = entry.m_ItemID; + + if ( itemID >= 0xBA3 && itemID <= 0xC0E ) + { + banLoc = new Point3D( center.X + entry.m_OffsetX, center.Y + entry.m_OffsetY, center.Z ); + break; + } + } + + for ( int i = 0; i < toMove.Count; ++i ) + { + object o = toMove[i]; + + if ( o is Mobile ) + ((Mobile)o).Location = banLoc; + else if ( o is Item ) + ((Item)o).Location = banLoc; + } + + prev.MoveToWorld( center, from.Map ); + + /* You are about to place a new house. + * Placing this house will condemn any and all of your other houses that you may have. + * All of your houses on all shards will be affected. + * + * In addition, you will not be able to place another house or have one transferred to you for one (1) real-life week. + * + * Once you accept these terms, these effects cannot be reversed. + * Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one week timer be removed. + * + * If you are absolutely certain you wish to proceed, click the button next to OKAY below. + * If you do not wish to trade for this house, click CANCEL. + */ + from.SendGump( new WarningGump( 1060635, 30720, 1049583, 32512, 420, 280, new WarningGumpCallback( PlacementWarning_Callback ), prev ) ); + + return true; + } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + case HousePlacementResult.NoSurface: + { + from.SendLocalizedMessage( 1043287 ); // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage( 501265 ); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + from.SendLocalizedMessage( 501270 ); //Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + break; + } + case HousePlacementResult.BadRegionRaffle: + { + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + break; + } + case HousePlacementResult.InvalidCastleKeep: + { + from.SendLocalizedMessage( 1061122 ); // Castles and keeps cannot be created here. + break; + } + } + + return false; + } + + private static Hashtable m_Table; + + static HousePlacementEntry() + { + m_Table = new Hashtable(); + + FillTable( m_ClassicHouses ); + FillTable( m_TwoStoryFoundations ); + FillTable( m_ThreeStoryFoundations ); + } + + public static HousePlacementEntry Find( BaseHouse house ) + { + object obj = m_Table[house.GetType()]; + + if ( obj is HousePlacementEntry ) + { + return ((HousePlacementEntry)obj); + } + else if ( obj is ArrayList ) + { + ArrayList list = (ArrayList)obj; + + for ( int i = 0; i < list.Count; ++i ) + { + HousePlacementEntry e = (HousePlacementEntry)list[i]; + + if ( e.m_MultiID == house.ItemID ) + return e; + } + } + else if ( obj is Hashtable ) + { + Hashtable table = (Hashtable)obj; + + obj = table[house.ItemID]; + + if ( obj is HousePlacementEntry ) + return (HousePlacementEntry)obj; + } + + return null; + } + + private static void FillTable( HousePlacementEntry[] entries ) + { + for ( int i = 0; i < entries.Length; ++i ) + { + HousePlacementEntry e = entries[i]; + + object obj = m_Table[e.m_Type]; + + if ( obj == null ) + { + m_Table[e.m_Type] = e; + } + else if ( obj is HousePlacementEntry ) + { + ArrayList list = new ArrayList(); + + list.Add( obj ); + list.Add( e ); + + m_Table[e.m_Type] = list; + } + else if ( obj is ArrayList ) + { + ArrayList list = (ArrayList)obj; + + if ( list.Count == 8 ) + { + Hashtable table = new Hashtable(); + + for ( int j = 0; j < list.Count; ++j ) + table[((HousePlacementEntry)list[j]).m_MultiID] = list[j]; + + table[e.m_MultiID] = e; + + m_Table[e.m_Type] = table; + } + else + { + list.Add( e ); + } + } + else if ( obj is Hashtable ) + { + ((Hashtable)obj)[e.m_MultiID] = e; + } + } + } + + private static HousePlacementEntry[] m_ClassicHouses = new HousePlacementEntry[] + { + new HousePlacementEntry( typeof( SmallOldHouse ), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064 ), + new HousePlacementEntry( typeof( SmallOldHouse ), 1011304, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0066 ), + new HousePlacementEntry( typeof( SmallOldHouse ), 1011305, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0068 ), + new HousePlacementEntry( typeof( SmallOldHouse ), 1011306, 425, 212, 489, 244, 10, 35250, 0, 4, 0, 0x006A ), + new HousePlacementEntry( typeof( SmallOldHouse ), 1011307, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006C ), + new HousePlacementEntry( typeof( SmallOldHouse ), 1011308, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006E ), + new HousePlacementEntry( typeof( SmallShop ), 1011321, 425, 212, 489, 244, 10, 50500, -1, 4, 0, 0x00A0 ), + new HousePlacementEntry( typeof( SmallShop ), 1011322, 425, 212, 489, 244, 10, 52500, 0, 4, 0, 0x00A2 ), + new HousePlacementEntry( typeof( SmallTower ), 1011317, 580, 290, 667, 333, 14, 73500, 3, 4, 0, 0x0098 ), + new HousePlacementEntry( typeof( TwoStoryVilla ), 1011319, 1100, 550, 1265, 632, 24, 113750, 3, 6, 0, 0x009E ), + new HousePlacementEntry( typeof( SandStonePatio ), 1011320, 850, 425, 1265, 632, 24, 76500, -1, 4, 0, 0x009C ), + new HousePlacementEntry( typeof( LogCabin ), 1011318, 1100, 550, 1265, 632, 24, 81750, 1, 6, 0, 0x009A ), + new HousePlacementEntry( typeof( GuildHouse ), 1011309, 1370, 685, 1576, 788, 28, 131500, -1, 7, 0, 0x0074 ), + new HousePlacementEntry( typeof( TwoStoryHouse ), 1011310, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0076 ), + new HousePlacementEntry( typeof( TwoStoryHouse ), 1011311, 1370, 685, 1576, 788, 28, 162000, -3, 7, 0, 0x0078 ), + new HousePlacementEntry( typeof( LargePatioHouse ), 1011315, 1370, 685, 1576, 788, 28, 129250, -4, 7, 0, 0x008C ), + new HousePlacementEntry( typeof( LargeMarbleHouse ), 1011316, 1370, 685, 1576, 788, 28, 160500, -4, 7, 0, 0x0096 ), + new HousePlacementEntry( typeof( Tower ), 1011312, 2119, 1059, 2437, 1218, 42, 366500, 0, 7, 0, 0x007A ), + new HousePlacementEntry( typeof( Keep ), 1011313, 2625, 1312, 3019, 1509, 52, 572750, 0, 11, 0, 0x007C ), + new HousePlacementEntry( typeof( Castle ), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E ) + }; + + public static HousePlacementEntry[] ClassicHouses{ get{ return m_ClassicHouses; } } + + + + + + private static HousePlacementEntry[] m_TwoStoryFoundations = new HousePlacementEntry[] + { + new HousePlacementEntry( typeof( HouseFoundation ), 1060241, 425, 212, 489, 244, 10, 30500, 0, 4, 0, 0x13EC ), // 7x7 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060242, 580, 290, 667, 333, 14, 34500, 0, 5, 0, 0x13ED ), // 7x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060243, 650, 325, 748, 374, 16, 38500, 0, 5, 0, 0x13EE ), // 7x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060244, 700, 350, 805, 402, 16, 42500, 0, 6, 0, 0x13EF ), // 7x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060245, 750, 375, 863, 431, 16, 46500, 0, 6, 0, 0x13F0 ), // 7x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060246, 800, 400, 920, 460, 18, 50500, 0, 7, 0, 0x13F1 ), // 7x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060253, 580, 290, 667, 333, 14, 34500, 0, 4, 0, 0x13F8 ), // 8x7 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060254, 650, 325, 748, 374, 16, 39000, 0, 5, 0, 0x13F9 ), // 8x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060255, 700, 350, 805, 402, 16, 43500, 0, 5, 0, 0x13FA ), // 8x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060256, 750, 375, 863, 431, 16, 48000, 0, 6, 0, 0x13FB ), // 8x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060257, 800, 400, 920, 460, 18, 52500, 0, 6, 0, 0x13FC ), // 8x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060258, 850, 425, 1265, 632, 24, 57000, 0, 7, 0, 0x13FD ), // 8x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060259, 1100, 550, 1265, 632, 24, 61500, 0, 7, 0, 0x13FE ), // 8x13 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060265, 650, 325, 748, 374, 16, 38500, 0, 4, 0, 0x1404 ), // 9x7 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060266, 700, 350, 805, 402, 16, 43500, 0, 5, 0, 0x1405 ), // 9x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060267, 750, 375, 863, 431, 16, 48500, 0, 5, 0, 0x1406 ), // 9x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060268, 800, 400, 920, 460, 18, 53500, 0, 6, 0, 0x1407 ), // 9x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060269, 850, 425, 1265, 632, 24, 58500, 0, 6, 0, 0x1408 ), // 9x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060270, 1100, 550, 1265, 632, 24, 63500, 0, 7, 0, 0x1409 ), // 9x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060271, 1100, 550, 1265, 632, 24, 68500, 0, 7, 0, 0x140A ), // 9x13 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060277, 700, 350, 805, 402, 16, 42500, 0, 4, 0, 0x1410 ), // 10x7 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060278, 750, 375, 863, 431, 16, 48000, 0, 5, 0, 0x1411 ), // 10x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060279, 800, 400, 920, 460, 18, 53500, 0, 5, 0, 0x1412 ), // 10x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060280, 850, 425, 1265, 632, 24, 59000, 0, 6, 0, 0x1413 ), // 10x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060281, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0, 0x1414 ), // 10x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060282, 1100, 550, 1265, 632, 24, 70000, 0, 7, 0, 0x1415 ), // 10x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060283, 1150, 575, 1323, 661, 24, 75500, 0, 7, 0, 0x1416 ), // 10x13 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060289, 750, 375, 863, 431, 16, 46500, 0, 4, 0, 0x141C ), // 11x7 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060290, 800, 400, 920, 460, 18, 52500, 0, 5, 0, 0x141D ), // 11x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060291, 850, 425, 1265, 632, 24, 58500, 0, 5, 0, 0x141E ), // 11x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060292, 1100, 550, 1265, 632, 24, 64500, 0, 6, 0, 0x141F ), // 11x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060293, 1100, 550, 1265, 632, 24, 70500, 0, 6, 0, 0x1420 ), // 11x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060294, 1150, 575, 1323, 661, 24, 76500, 0, 7, 0, 0x1421 ), // 11x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060295, 1200, 600, 1380, 690, 26, 82500, 0, 7, 0, 0x1422 ), // 11x13 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060301, 800, 400, 920, 460, 18, 50500, 0, 4, 0, 0x1428 ), // 12x7 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060302, 850, 425, 1265, 632, 24, 57000, 0, 5, 0, 0x1429 ), // 12x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060303, 1100, 550, 1265, 632, 24, 63500, 0, 5, 0, 0x142A ), // 12x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060304, 1100, 550, 1265, 632, 24, 70000, 0, 6, 0, 0x142B ), // 12x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060305, 1150, 575, 1323, 661, 24, 76500, 0, 6, 0, 0x142C ), // 12x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060306, 1200, 600, 1380, 690, 26, 83000, 0, 7, 0, 0x142D ), // 12x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060307, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0, 0x142E ), // 12x13 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060314, 1100, 550, 1265, 632, 24, 61500, 0, 5, 0, 0x1435 ), // 13x8 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060315, 1100, 550, 1265, 632, 24, 68500, 0, 5, 0, 0x1436 ), // 13x9 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060316, 1150, 575, 1323, 661, 24, 75500, 0, 6, 0, 0x1437 ), // 13x10 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060317, 1200, 600, 1380, 690, 26, 82500, 0, 6, 0, 0x1438 ), // 13x11 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060318, 1250, 625, 1438, 719, 26, 89500, 0, 7, 0, 0x1439 ), // 13x12 2-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060319, 1300, 650, 1495, 747, 28, 96500, 0, 7, 0, 0x143A ) // 13x13 2-Story Customizable House + }; + + public static HousePlacementEntry[] TwoStoryFoundations{ get{ return m_TwoStoryFoundations; } } + + + + + + private static HousePlacementEntry[] m_ThreeStoryFoundations = new HousePlacementEntry[] + { + new HousePlacementEntry( typeof( HouseFoundation ), 1060272, 1150, 575, 1323, 661, 24, 73500, 0, 8, 0, 0x140B ), // 9x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060284, 1200, 600, 1380, 690, 26, 81000, 0, 8, 0, 0x1417 ), // 10x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060285, 1250, 625, 1438, 719, 26, 86500, 0, 8, 0, 0x1418 ), // 10x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060296, 1250, 625, 1438, 719, 26, 88500, 0, 8, 0, 0x1423 ), // 11x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060297, 1300, 650, 1495, 747, 28, 94500, 0, 8, 0, 0x1424 ), // 11x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060298, 1350, 675, 1553, 776, 28, 100500, 0, 9, 0, 0x1425 ), // 11x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060308, 1300, 650, 1495, 747, 28, 96000, 0, 8, 0, 0x142F ), // 12x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060309, 1350, 675, 1553, 776, 28, 102500, 0, 8, 0, 0x1430 ), // 12x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060310, 1370, 685, 1576, 788, 28, 109000, 0, 9, 0, 0x1431 ), // 12x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060311, 1370, 685, 1576, 788, 28, 115500, 0, 9, 0, 0x1432 ), // 12x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060320, 1350, 675, 1553, 776, 28, 103500, 0, 8, 0, 0x143B ), // 13x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060321, 1370, 685, 1576, 788, 28, 110500, 0, 8, 0, 0x143C ), // 13x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060322, 1370, 685, 1576, 788, 28, 117500, 0, 9, 0, 0x143D ), // 13x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060323, 2119, 1059, 2437, 1218, 42, 124500, 0, 9, 0, 0x143E ), // 13x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060324, 2119, 1059, 2437, 1218, 42, 131500, 0, 10, 0, 0x143F ), // 13x18 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060327, 1150, 575, 1323, 661, 24, 73500, 0, 5, 0, 0x1442 ), // 14x9 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060328, 1200, 600, 1380, 690, 26, 81000, 0, 6, 0, 0x1443 ), // 14x10 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060329, 1250, 625, 1438, 719, 26, 88500, 0, 6, 0, 0x1444 ), // 14x11 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060330, 1300, 650, 1495, 747, 28, 96000, 0, 7, 0, 0x1445 ), // 14x12 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060331, 1350, 675, 1553, 776, 28, 103500, 0, 7, 0, 0x1446 ), // 14x13 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060332, 1370, 685, 1576, 788, 28, 111000, 0, 8, 0, 0x1447 ), // 14x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060333, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0, 0x1448 ), // 14x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060334, 2119, 1059, 2437, 1218, 42, 126000, 0, 9, 0, 0x1449 ), // 14x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060335, 2119, 1059, 2437, 1218, 42, 133500, 0, 9, 0, 0x144A ), // 14x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060336, 2119, 1059, 2437, 1218, 42, 141000, 0, 10, 0, 0x144B ), // 14x18 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060340, 1250, 625, 1438, 719, 26, 86500, 0, 6, 0, 0x144F ), // 15x10 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060341, 1300, 650, 1495, 747, 28, 94500, 0, 6, 0, 0x1450 ), // 15x11 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060342, 1350, 675, 1553, 776, 28, 102500, 0, 7, 0, 0x1451 ), // 15x12 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060343, 1370, 685, 1576, 788, 28, 110500, 0, 7, 0, 0x1452 ), // 15x13 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060344, 1370, 685, 1576, 788, 28, 118500, 0, 8, 0, 0x1453 ), // 15x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060345, 2119, 1059, 2437, 1218, 42, 126500, 0, 8, 0, 0x1454 ), // 15x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060346, 2119, 1059, 2437, 1218, 42, 134500, 0, 9, 0, 0x1455 ), // 15x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060347, 2119, 1059, 2437, 1218, 42, 142500, 0, 9, 0, 0x1456 ), // 15x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060348, 2119, 1059, 2437, 1218, 42, 150500, 0, 10, 0, 0x1457 ), // 15x18 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060353, 1350, 675, 1553, 776, 28, 100500, 0, 6, 0, 0x145C ), // 16x11 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060354, 1370, 685, 1576, 788, 28, 109000, 0, 7, 0, 0x145D ), // 16x12 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060355, 1370, 685, 1576, 788, 28, 117500, 0, 7, 0, 0x145E ), // 16x13 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060356, 2119, 1059, 2437, 1218, 42, 126000, 0, 8, 0, 0x145F ), // 16x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060357, 2119, 1059, 2437, 1218, 42, 134500, 0, 8, 0, 0x1460 ), // 16x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060358, 2119, 1059, 2437, 1218, 42, 143000, 0, 9, 0, 0x1461 ), // 16x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060359, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0, 0x1462 ), // 16x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060360, 2119, 1059, 2437, 1218, 42, 160000, 0, 10, 0, 0x1463 ), // 16x18 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060366, 1370, 685, 1576, 788, 28, 115500, 0, 7, 0, 0x1469 ), // 17x12 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060367, 2119, 1059, 2437, 1218, 42, 124500, 0, 7, 0, 0x146A ), // 17x13 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060368, 2119, 1059, 2437, 1218, 42, 133500, 0, 8, 0, 0x146B ), // 17x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060369, 2119, 1059, 2437, 1218, 42, 142500, 0, 8, 0, 0x146C ), // 17x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060370, 2119, 1059, 2437, 1218, 42, 151500, 0, 9, 0, 0x146D ), // 17x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060371, 2119, 1059, 2437, 1218, 42, 160500, 0, 9, 0, 0x146E ), // 17x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060372, 2119, 1059, 2437, 1218, 42, 169500, 0, 10, 0, 0x146F ), // 17x18 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060379, 2119, 1059, 2437, 1218, 42, 131500, 0, 7, 0, 0x1476 ), // 18x13 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060380, 2119, 1059, 2437, 1218, 42, 141000, 0, 8, 0, 0x1477 ), // 18x14 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060381, 2119, 1059, 2437, 1218, 42, 150500, 0, 8, 0, 0x1478 ), // 18x15 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060382, 2119, 1059, 2437, 1218, 42, 160000, 0, 9, 0, 0x1479 ), // 18x16 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060383, 2119, 1059, 2437, 1218, 42, 169500, 0, 9, 0, 0x147A ), // 18x17 3-Story Customizable House + new HousePlacementEntry( typeof( HouseFoundation ), 1060384, 2119, 1059, 2437, 1218, 42, 179000, 0, 10, 0, 0x147B ) // 18x18 3-Story Customizable House + }; + + public static HousePlacementEntry[] ThreeStoryFoundations{ get{ return m_ThreeStoryFoundations; } } + } +} \ No newline at end of file diff --git a/Scripts/Multis/HouseSign.cs b/Scripts/Multis/HouseSign.cs new file mode 100644 index 0000000..e908b4e --- /dev/null +++ b/Scripts/Multis/HouseSign.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Gumps; +using Server.ContextMenus; + +namespace Server.Multis +{ + public class HouseSign : Item + { + private BaseHouse m_Owner; + private Mobile m_OrgOwner; + + public HouseSign( BaseHouse owner ) : base( 0xBD2 ) + { + m_Owner = owner; + m_OrgOwner = m_Owner.Owner; + Movable = false; + } + + public HouseSign( Serial serial ) : base( serial ) + { + } + + public string GetName() + { + if ( Name == null ) + return "An Unnamed House"; + + return Name; + } + + public BaseHouse Owner + { + get + { + return m_Owner; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool RestrictDecay + { + get{ return ( m_Owner != null && m_Owner.RestrictDecay ); } + set{ if ( m_Owner != null ) m_Owner.RestrictDecay = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile OriginalOwner + { + get + { + return m_OrgOwner; + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Owner != null && !m_Owner.Deleted ) + m_Owner.Delete(); + } + + public override void AddNameProperty(ObjectPropertyList list) + { + list.Add( 1061638 ); // A House Sign + } + + public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } } + + private bool m_GettingProperties; + + public bool GettingProperties + { + get { return m_GettingProperties; } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1061639, Utility.FixHtml( GetName() ) ); // Name: ~1_NAME~ + list.Add( 1061640, (m_Owner == null || m_Owner.Owner == null) ? "nobody" : m_Owner.Owner.Name ); // Owner: ~1_OWNER~ + + if ( m_Owner != null ) + { + list.Add( m_Owner.Public ? 1061641 : 1061642 ); // This House is Open to the Public : This is a Private Home + + m_GettingProperties = true; + DecayLevel level = m_Owner.DecayLevel; + m_GettingProperties = false; + + if ( level == DecayLevel.DemolitionPending ) + { + list.Add( 1062497 ); // Demolition Pending + } + else if ( level != DecayLevel.Ageless ) + { + if ( level == DecayLevel.Collapsed ) + level = DecayLevel.IDOC; + + list.Add( 1062028, String.Format( "#{0}", 1043009 + (int)level ) ); // Condition: This structure is ... + } + } + } + + public override void OnSingleClick( Mobile from ) + { + if ( m_Owner != null && BaseHouse.DecayEnabled && m_Owner.DecayPeriod != TimeSpan.Zero ) + { + string message; + + switch ( m_Owner.DecayLevel ) + { + case DecayLevel.Ageless: message = "ageless"; break; + case DecayLevel.Fairly: message = "fairly worn"; break; + case DecayLevel.Greatly: message = "greatly worn"; break; + case DecayLevel.LikeNew: message = "like new"; break; + case DecayLevel.Slightly: message = "slightly worn"; break; + case DecayLevel.Somewhat: message = "somewhat worn"; break; + default: message = "in danger of collapsing"; break; + } + + LabelTo( from, "This house is {0}.", message ); + } + + base.OnSingleClick( from ); + } + + public void ShowSign( Mobile m ) + { + if ( m_Owner != null ) + { + if ( m_Owner.IsFriend( m ) && m.AccessLevel < AccessLevel.GameMaster ) + { + #region Mondain's Legacy + if ( ( Core.ML && m_Owner.IsOwner( m ) ) || !Core.ML ) + m_Owner.RefreshDecay(); + #endregion + if ( !Core.AOS ) + m.SendLocalizedMessage( 501293 ); // Welcome back to the house, friend! + } + + + if ( m_Owner.IsAosRules ) + m.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Information, m, m_Owner ) ); + else + m.SendGump( new HouseGump( m, m_Owner ) ); + } + } + + public void ClaimGump_Callback( Mobile from, bool okay, object state ) + { + if ( okay && m_Owner != null && m_Owner.Owner == null && m_Owner.DecayLevel != DecayLevel.DemolitionPending ) + { + bool canClaim = false; + + if ( m_Owner.CoOwners == null || m_Owner.CoOwners.Count == 0 ) + canClaim = m_Owner.IsFriend( from ); + else + canClaim = m_Owner.IsCoOwner( from ); + + if ( canClaim && !BaseHouse.HasAccountHouse( from ) ) + { + m_Owner.Owner = from; + m_Owner.LastTraded = DateTime.Now; + } + } + + ShowSign( from ); + } + + public override void OnDoubleClick( Mobile m ) + { + if ( m_Owner == null ) + return; + + if ( m.AccessLevel < AccessLevel.GameMaster && m_Owner.Owner == null && m_Owner.DecayLevel != DecayLevel.DemolitionPending ) + { + bool canClaim = false; + + if ( m_Owner.CoOwners == null || m_Owner.CoOwners.Count == 0 ) + canClaim = m_Owner.IsFriend( m ); + else + canClaim = m_Owner.IsCoOwner( m ); + + if ( canClaim && !BaseHouse.HasAccountHouse( m ) ) + { + /* You do not currently own any house on any shard with this account, + * and this house currently does not have an owner. If you wish, you + * may choose to claim this house and become its rightful owner. If + * you do this, it will become your Primary house and automatically + * refresh. If you claim this house, you will be unable to place + * another house or have another house transferred to you for the + * next 7 days. Do you wish to claim this house? + */ + m.SendGump( new WarningGump( 501036, 32512, 1049719, 32512, 420, 280, new WarningGumpCallback( ClaimGump_Callback ), null ) ); + } + } + + ShowSign( m ); + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + + if ( BaseHouse.NewVendorSystem && from.Alive && Owner != null && Owner.IsAosRules ) + { + if ( Owner.AreThereAvailableVendorsFor( from ) ) + list.Add( new VendorsEntry( this ) ); + + if ( Owner.VendorInventories.Count > 0 ) + list.Add( new ReclaimVendorInventoryEntry( this ) ); + } + } + + private class VendorsEntry : ContextMenuEntry + { + private HouseSign m_Sign; + + public VendorsEntry( HouseSign sign ) : base( 6211 ) + { + m_Sign = sign; + } + + public override void OnClick() + { + Mobile from = this.Owner.From; + + if ( !from.CheckAlive() || m_Sign.Deleted || m_Sign.Owner == null || !m_Sign.Owner.AreThereAvailableVendorsFor( from ) ) + return; + + if ( from.Map != m_Sign.Map || !from.InRange( m_Sign, 5 ) ) + { + from.SendLocalizedMessage( 1062429 ); // You must be within five paces of the house sign to use this option. + } + else + { + from.SendGump( new HouseGumpAOS( HouseGumpPageAOS.Vendors, from, m_Sign.Owner ) ); + } + } + } + + private class ReclaimVendorInventoryEntry : ContextMenuEntry + { + private HouseSign m_Sign; + + public ReclaimVendorInventoryEntry( HouseSign sign ) : base( 6213 ) + { + m_Sign = sign; + } + + public override void OnClick() + { + Mobile from = this.Owner.From; + + if ( m_Sign.Deleted || m_Sign.Owner == null || m_Sign.Owner.VendorInventories.Count == 0 || !from.CheckAlive() ) + return; + + if ( from.Map != m_Sign.Map || !from.InRange( m_Sign, 5 ) ) + { + from.SendLocalizedMessage( 1062429 ); // You must be within five paces of the house sign to use this option. + } + else + { + from.CloseGump( typeof( VendorInventoryGump ) ); + from.SendGump( new VendorInventoryGump( m_Sign.Owner, from ) ); + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Owner ); + writer.Write( m_OrgOwner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Owner = reader.ReadItem() as BaseHouse; + m_OrgOwner = reader.ReadMobile(); + + break; + } + } + + if ( this.Name == "a house sign" ) + this.Name = null; + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/HouseTeleporter.cs b/Scripts/Multis/HouseTeleporter.cs new file mode 100644 index 0000000..bc21841 --- /dev/null +++ b/Scripts/Multis/HouseTeleporter.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections; +using Server; +using Server.Gumps; +using Server.Multis; +using Server.Targeting; +using System.Collections.Generic; +using Server.ContextMenus; + +namespace Server.Items +{ + public class HouseTeleporter : Item, ISecurable + { + private Item m_Target; + private SecureLevel m_Level; + + [CommandProperty( AccessLevel.GameMaster )] + public Item Target + { + get{ return m_Target; } + set{ m_Target = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + [Constructable] + public HouseTeleporter( int itemID ) : this( itemID, null ) + { + } + + public HouseTeleporter( int itemID, Item target ) : base( itemID ) + { + Movable = false; + + m_Level = SecureLevel.Anyone; + + m_Target = target; + } + + public bool CheckAccess( Mobile m ) + { + BaseHouse house = BaseHouse.FindHouseAt( this ); + + if ( house != null && (house.Public ? house.IsBanned( m ) : !house.HasAccess( m )) ) + return false; + + return ( house != null && house.HasSecureAccess( m, m_Level ) ); + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m_Target != null && !m_Target.Deleted ) + { + if ( CheckAccess( m ) ) + { + if ( !m.Hidden || m.AccessLevel == AccessLevel.Player ) + new EffectTimer( Location, Map, 2023, 0x1F0, TimeSpan.FromSeconds( 0.4 ) ).Start(); + + new DelayTimer( this, m ).Start(); + } + else + { + m.SendLocalizedMessage( 1061637 ); // You are not allowed to access this. + } + } + + return true; + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + public HouseTeleporter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( (int) m_Level ); + + writer.Write( (Item) m_Target ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Level = (SecureLevel)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_Target = reader.ReadItem(); + + if ( version < 0 ) + m_Level = SecureLevel.Anyone; + + break; + } + } + } + + private class EffectTimer : Timer + { + private Point3D m_Location; + private Map m_Map; + private int m_EffectID; + private int m_SoundID; + + public EffectTimer( Point3D p, Map map, int effectID, int soundID, TimeSpan delay ) : base( delay ) + { + m_Location = p; + m_Map = map; + m_EffectID = effectID; + m_SoundID = soundID; + } + + protected override void OnTick() + { + Effects.SendLocationParticles( EffectItem.Create( m_Location, m_Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, m_EffectID, 0 ); + + if ( m_SoundID != -1 ) + Effects.PlaySound( m_Location, m_Map, m_SoundID ); + } + } + + private class DelayTimer : Timer + { + private HouseTeleporter m_Teleporter; + private Mobile m_Mobile; + + public DelayTimer( HouseTeleporter tp, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ) ) + { + m_Teleporter = tp; + m_Mobile = m; + } + + protected override void OnTick() + { + Item target = m_Teleporter.m_Target; + + if ( target != null && !target.Deleted ) + { + Mobile m = m_Mobile; + + if ( m.Location == m_Teleporter.Location && m.Map == m_Teleporter.Map ) + { + Point3D p = target.GetWorldTop(); + Map map = target.Map; + + Server.Mobiles.BaseCreature.TeleportPets( m, p, map ); + + m.MoveToWorld( p, map ); + + if ( !m.Hidden || m.AccessLevel == AccessLevel.Player ) + { + Effects.PlaySound( target.Location, target.Map, 0x1FE ); + + Effects.SendLocationParticles( EffectItem.Create( m_Teleporter.Location, m_Teleporter.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023, 0 ); + Effects.SendLocationParticles( EffectItem.Create( target.Location, target.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 5023, 0 ); + + new EffectTimer( target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds( 0.4 ) ).Start(); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/Houses.cs b/Scripts/Multis/Houses.cs new file mode 100644 index 0000000..325587c --- /dev/null +++ b/Scripts/Multis/Houses.cs @@ -0,0 +1,577 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Multis.Deeds; + +namespace Server.Multis +{ + public class SmallOldHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D(-3,-3,7,7 ), new Rectangle2D( -1, 4, 3, 1 ) }; + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 2, 4, 0 ); } } + + public override int DefaultPrice{ get{ return 43800; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.TwoStoryFoundations[0]; } } + + public SmallOldHouse( Mobile owner, int id ) : base( id, owner, 425, 3 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoor( 0, 3, 7, keyValue ); + + SetSign( 2, 4, 5 ); + } + + public SmallOldHouse( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() + { + switch ( ItemID ) + { + case 0x64: return new StonePlasterHouseDeed(); + case 0x66: return new FieldStoneHouseDeed(); + case 0x68: return new SmallBrickHouseDeed(); + case 0x6A: return new WoodHouseDeed(); + case 0x6C: return new WoodPlasterHouseDeed(); + case 0x6E: + default: return new ThatchedRoofCottageDeed(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class GuildHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -7, -7, 14, 14 ), new Rectangle2D( -2, 7, 4, 1 ) }; + + public override int DefaultPrice{ get{ return 144500; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.ThreeStoryFoundations[20]; } } + public override int ConvertOffsetX{ get{ return -1; } } + public override int ConvertOffsetY{ get{ return -1; } } + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 4, 8, 0 ); } } + + public GuildHouse( Mobile owner ) : base( 0x74, owner, 1100, 8 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( -1, 6, 7, keyValue ); + + SetSign( 4, 8, 16 ); + + AddSouthDoor( -3, -1, 7 ); + AddSouthDoor( 3, -1, 7 ); + } + + public GuildHouse( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new BrickHouseDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class TwoStoryHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -7, 0, 14, 7 ), new Rectangle2D( -7, -7, 9, 7 ), new Rectangle2D( -4, 7, 4, 1 ) }; + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 2, 8, 0 ); } } + + public override int DefaultPrice{ get{ return 192400; } } + + public TwoStoryHouse( Mobile owner, int id ) : base( id, owner, 1370, 10 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( -3, 6, 7, keyValue ); + + SetSign( 2, 8, 16 ); + + AddSouthDoor( -3, 0, 7 ); + AddSouthDoor( id == 0x76 ? -2 : -3, 0, 27 ); + } + + public TwoStoryHouse( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() + { + switch( ItemID ) + { + case 0x76: return new TwoStoryWoodPlasterHouseDeed(); + case 0x78: + default: return new TwoStoryStonePlasterHouseDeed(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class Tower : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -7, -7, 16, 14 ), new Rectangle2D( -1, 7, 4, 2 ), new Rectangle2D( -11, 0, 4, 7 ), new Rectangle2D( 9, 0, 4, 7 ) }; + + public override int DefaultPrice{ get{ return 433200; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.ThreeStoryFoundations[37]; } } + public override int ConvertOffsetY{ get{ return -1; } } + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 5, 8, 0 ); } } + + public Tower( Mobile owner ) : base( 0x7A, owner, 2119, 15 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( false, 0, 6, 6, keyValue ); + + SetSign( 5, 8, 16 ); + + AddSouthDoor( false, 3, -2, 6 ); + AddEastDoor( false, 1, 4, 26 ); + AddEastDoor( false, 1, 4, 46 ); + } + + public Tower( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new TowerDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class Keep : BaseHouse//warning: ODD shape! + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -11, -11, 7, 8 ), new Rectangle2D( -11, 5, 7, 8 ), new Rectangle2D( 6, -11, 7, 8 ), new Rectangle2D( 6, 5, 7, 8 ), new Rectangle2D( -9, -3, 5, 8 ), new Rectangle2D( 6, -3, 5, 8 ), new Rectangle2D( -4, -9, 10, 20 ), new Rectangle2D( -1, 11, 4, 1 ) }; + + public override int DefaultPrice{ get{ return 665200; } } + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 5, 13, 0 ); } } + + public Keep( Mobile owner ) : base( 0x7C, owner, 2625, 18 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( false, 0, 10, 6, keyValue ); + + SetSign( 5, 12, 16 ); + } + + public Keep( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new KeepDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class Castle : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -15, -15, 31, 31 ), new Rectangle2D( -1, 16, 4, 1 ) }; + + public override int DefaultPrice{ get{ return 1022800; } } + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 5, 17, 0 ); } } + + public Castle( Mobile owner ) : base( 0x7E, owner, 4076, 28 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( false, 0, 15, 6, keyValue ); + + SetSign( 5, 17, 16 ); + + AddSouthDoors( false, 0, 11, 6, true ); + AddSouthDoors( false, 0, 5, 6, false ); + AddSouthDoors( false, -1, -11, 6, false ); + } + + public Castle( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new CastleDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class LargePatioHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -7, -7, 15, 14 ), new Rectangle2D( -5, 7, 4, 1 ) }; + + public override int DefaultPrice{ get{ return 152800; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.ThreeStoryFoundations[29]; } } + public override int ConvertOffsetY{ get{ return -1; } } + + public override Rectangle2D[] Area { get { return AreaArray; } } + public override Point3D BaseBanLocation { get { return new Point3D( 1, 8, 0 ); } } + + public LargePatioHouse( Mobile owner ) : base( 0x8C, owner, 1100, 8 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( -4, 6, 7, keyValue ); + + SetSign( 1, 8, 16 ); + + AddEastDoor( 1, 4, 7 ); + AddEastDoor( 1, -4, 7 ); + AddSouthDoor( 4, -1, 7 ); + } + + public LargePatioHouse( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new LargePatioDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class LargeMarbleHouse : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -7, -7, 15, 14 ), new Rectangle2D( -6, 7, 6, 1 ) }; + + public override int DefaultPrice{ get{ return 192000; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.ThreeStoryFoundations[29]; } } + public override int ConvertOffsetY{ get{ return -1; } } + + public override Rectangle2D[] Area { get { return AreaArray; } } + public override Point3D BaseBanLocation { get { return new Point3D( 1, 8, 0 ); } } + + public LargeMarbleHouse( Mobile owner ) : base( 0x96, owner, 1370, 10 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( false, -4, 3, 4, keyValue ); + + SetSign( 1, 8, 11 ); + } + + public LargeMarbleHouse( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new LargeMarbleDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class SmallTower : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -3, -3, 8, 7 ), new Rectangle2D( 2, 4, 3, 1 ) }; + + public override int DefaultPrice{ get{ return 88500; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.TwoStoryFoundations[6]; } } + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 1, 4, 0 ); } } + + public SmallTower( Mobile owner ) : base( 0x98, owner, 580, 4 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoor( false, 3, 3, 6, keyValue ); + + SetSign( 1, 4, 5 ); + } + + public SmallTower( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new SmallTowerDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class LogCabin : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -3, -6, 8, 13 ) }; + + public override int DefaultPrice{ get{ return 97800; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.TwoStoryFoundations[12]; } } + + public override Rectangle2D[] Area { get { return AreaArray; } } + public override Point3D BaseBanLocation { get { return new Point3D( 5, 8, 0 ); } } + + public LogCabin( Mobile owner ) : base( 0x9A, owner, 1100, 8 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoor( 1, 4, 8, keyValue ); + + SetSign( 5, 8, 20 ); + + AddSouthDoor( 1, 0, 29 ); + } + + public LogCabin( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new LogCabinDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class SandStonePatio : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -5, -4, 12, 8 ), new Rectangle2D( -2, 4, 3, 1 ) }; + + public override int DefaultPrice{ get{ return 90900; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.TwoStoryFoundations[35]; } } + public override int ConvertOffsetY{ get{ return -1; } } + + public override Rectangle2D[] Area { get { return AreaArray; } } + public override Point3D BaseBanLocation { get { return new Point3D( 4, 6, 0 ); } } + + public SandStonePatio( Mobile owner ) : base( 0x9C, owner, 850, 6 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoor( -1, 3, 6, keyValue ); + + SetSign( 4, 6, 24 ); + } + + public SandStonePatio( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new SandstonePatioDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class TwoStoryVilla : BaseHouse + { + public static Rectangle2D[] AreaArray = new Rectangle2D[]{ new Rectangle2D( -5, -5, 11, 11 ), new Rectangle2D( 2, 6, 4, 1 ) }; + + public override int DefaultPrice{ get{ return 136500; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.TwoStoryFoundations[31]; } } + + public override Rectangle2D[] Area{ get{ return AreaArray; } } + public override Point3D BaseBanLocation{ get{ return new Point3D( 3, 8, 0 ); } } + + public TwoStoryVilla( Mobile owner ) : base( 0x9E, owner, 1100, 8 ) + { + uint keyValue = CreateKeys( owner ); + + AddSouthDoors( 3, 1, 5, keyValue ); + + SetSign( 3, 8, 24 ); + + AddEastDoor( 1, 0, 25 ); + AddSouthDoor( -3, -1, 25 ); + } + + public TwoStoryVilla( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() { return new VillaDeed(); } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class SmallShop : BaseHouse + { + public override Rectangle2D[] Area { get { return ( ItemID == 0x40A2 ? AreaArray1 : AreaArray2 ); } } + public override Point3D BaseBanLocation { get { return new Point3D( 3, 4, 0 ); } } + + public override int DefaultPrice{ get{ return 63000; } } + + public override HousePlacementEntry ConvertEntry{ get{ return HousePlacementEntry.TwoStoryFoundations[0]; } } + + public static Rectangle2D[] AreaArray1 = new Rectangle2D[]{ new Rectangle2D(-3,-3,7,7), new Rectangle2D( -1, 4, 4, 1 ) }; + public static Rectangle2D[] AreaArray2 = new Rectangle2D[]{ new Rectangle2D(-3,-3,7,7), new Rectangle2D( -2, 4, 3, 1 ) }; + + public SmallShop( Mobile owner, int id ) : base( id, owner, 425, 3 ) + { + uint keyValue = CreateKeys( owner ); + + BaseDoor door = MakeDoor( false, DoorFacing.EastCW ); + + door.Locked = true; + door.KeyValue = keyValue; + + if ( door is BaseHouseDoor ) + ((BaseHouseDoor)door).Facing = DoorFacing.EastCCW; + + AddDoor( door, -2, 0, id == 0xA2 ? 24 : 27 ); + + //AddSouthDoor( false, -2, 0, 27 - (id == 0xA2 ? 3 : 0), keyValue ); + + SetSign( 3, 4, 7 - (id == 0xA2 ? 2 : 0) ); + } + + public SmallShop( Serial serial ) : base( serial ) + { + } + + public override HouseDeed GetDeed() + { + switch ( ItemID ) + { + case 0xA0: return new StoneWorkshopDeed(); + case 0xA2: + default: return new MarbleWorkshopDeed(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 );//version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Multis/MovingCrate.cs b/Scripts/Multis/MovingCrate.cs new file mode 100644 index 0000000..01b5405 --- /dev/null +++ b/Scripts/Multis/MovingCrate.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Multis +{ + public class MovingCrate : Container + { + public static readonly int MaxItemsPerSubcontainer = 20; + public static readonly int Rows = 3; + public static readonly int Columns = 5; + public static readonly int HorizontalSpacing = 25; + public static readonly int VerticalSpacing = 25; + + public override int LabelNumber{ get{ return 1061690; } } // Packing Crate + + private BaseHouse m_House; + + private Timer m_InternalizeTimer; + + public BaseHouse House + { + get{ return m_House; } + set{ m_House = value; } + } + + public override int DefaultMaxItems{ get{ return 0; } } + public override int DefaultMaxWeight{ get{ return 0; } } + + public MovingCrate( BaseHouse house ) : base( 0xE3D ) + { + Hue = 0x8A5; + Movable = false; + + m_House = house; + } + + public MovingCrate( Serial serial ) : base( serial ) + { + } + + /* + public override void AddNameProperties( ObjectPropertyList list ) + { + base.AddNameProperties( list ); + + if ( House != null && House.InternalizedVendors.Count > 0 ) + list.Add( 1061833, House.InternalizedVendors.Count.ToString() ); // This packing crate contains ~1_COUNT~ vendors/barkeepers. + } + */ + + public override void DropItem( Item dropped ) + { + // 1. Try to stack the item + foreach ( Item item in this.Items ) + { + if ( item is PackingBox ) + { + List subItems = item.Items; + + for ( int i = 0; i < subItems.Count; i++ ) + { + Item subItem = subItems[i]; + + if ( !(subItem is Container) && subItem.StackWith( null, dropped, false ) ) + return; + } + } + } + + // 2. Try to drop the item into an existing container + foreach ( Item item in this.Items ) + { + if ( item is PackingBox ) + { + Container box = (Container) item; + List subItems = box.Items; + + if ( subItems.Count < MaxItemsPerSubcontainer ) + { + box.DropItem( dropped ); + return; + } + } + } + + // 3. Drop the item into a new container + Container subContainer = new PackingBox(); + subContainer.DropItem( dropped ); + + Point3D location = GetFreeLocation(); + if ( location != Point3D.Zero ) + { + this.AddItem( subContainer ); + subContainer.Location = location; + } + else + { + base.DropItem( subContainer ); + } + } + + private Point3D GetFreeLocation() + { + bool[,] positions = new bool[Rows, Columns]; + + foreach ( Item item in this.Items ) + { + if ( item is PackingBox ) + { + int i = (item.Y - this.Bounds.Y) / VerticalSpacing; + if ( i < 0 ) + i = 0; + else if ( i >= Rows ) + i = Rows - 1; + + int j = (item.X - this.Bounds.X) / HorizontalSpacing; + if ( j < 0 ) + j = 0; + else if ( j >= Columns ) + j = Columns - 1; + + positions[i, j] = true; + } + } + + for ( int i = 0; i < Rows; i++ ) + { + for ( int j = 0; j < Columns; j++ ) + { + if ( !positions[i, j] ) + { + int x = this.Bounds.X + j * HorizontalSpacing; + int y = this.Bounds.Y + i * VerticalSpacing; + + return new Point3D( x, y, 0 ); + } + } + } + + return Point3D.Zero; + } + + public override bool IsDecoContainer + { + get{ return false; } + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + if ( m.AccessLevel < AccessLevel.GameMaster ) + { + m.SendLocalizedMessage( 1061145 ); // You cannot place items into a house moving crate. + return false; + } + + return base.CheckHold( m, item, message, checkItems, plusItems, plusWeight ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + return base.CheckLift( from, item, ref reject ) && House != null && !House.Deleted && House.IsOwner( from ); + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + return base.CheckItemUse( from, item ) && House != null && !House.Deleted && House.IsOwner( from ); + } + + public override void OnItemRemoved( Item item ) + { + base.OnItemRemoved( item ); + + if ( this.TotalItems == 0 ) + Delete(); + } + + public void RestartTimer() + { + if ( m_InternalizeTimer == null ) + { + m_InternalizeTimer = new InternalizeTimer( this ); + m_InternalizeTimer.Start(); + } + else + { + m_InternalizeTimer.Stop(); + m_InternalizeTimer.Start(); + } + } + + public void Hide() + { + if ( m_InternalizeTimer != null ) + { + m_InternalizeTimer.Stop(); + m_InternalizeTimer = null; + } + + List toRemove = new List(); + foreach ( Item item in this.Items ) + if ( item is PackingBox && item.Items.Count == 0 ) + toRemove.Add( item ); + + foreach ( Item item in toRemove ) + item.Delete(); + + if ( this.TotalItems == 0 ) + Delete(); + else + Internalize(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( House != null && House.MovingCrate == this ) + House.MovingCrate = null; + + if ( m_InternalizeTimer != null ) + m_InternalizeTimer.Stop(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); + + writer.Write( (Item) m_House ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_House = reader.ReadItem() as BaseHouse; + + if( m_House != null ) + { + m_House.MovingCrate = this; + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( Hide ) ); + } + else + { + Timer.DelayCall( TimeSpan.Zero, this.Delete ); + } + + if ( version == 0 ) + MaxItems = -1; // reset to default + } + + public class InternalizeTimer : Timer + { + private MovingCrate m_Crate; + + public InternalizeTimer( MovingCrate crate ) : base( TimeSpan.FromMinutes( 5.0 ) ) + { + m_Crate = crate; + + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Crate.Hide(); + } + } + } + + public class PackingBox : BaseContainer + { + public override int LabelNumber{ get{ return 1061690; } } // Packing Crate + + public override int DefaultGumpID{ get{ return 0x4B; } } + public override int DefaultDropSound{ get{ return 0x42; } } + + public override Rectangle2D Bounds + { + get{ return new Rectangle2D( 16, 51, 168, 73 ); } + } + + public override int DefaultMaxItems{ get{ return 0; } } + public override int DefaultMaxWeight{ get{ return 0; } } + + public PackingBox() : base( 0x9A8 ) + { + Movable = false; + } + + public PackingBox( Serial serial ) : base( serial ) + { + } + + public override void SendCantStoreMessage( Mobile to, Item item ) + { + to.SendLocalizedMessage( 1061145 ); // You cannot place items into a house moving crate. + } + + public override void OnItemRemoved( Item item ) + { + base.OnItemRemoved( item ); + + if ( item.GetBounce() == null && this.TotalItems == 0 ) + Delete(); + } + + public override void OnItemBounceCleared( Item item ) + { + base.OnItemBounceCleared( item ); + + if ( this.TotalItems == 0 ) + Delete(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 1 ); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + if ( version == 0 ) + MaxItems = -1; // reset to default + } + } +} \ No newline at end of file diff --git a/Scripts/Multis/PreviewHouse.cs b/Scripts/Multis/PreviewHouse.cs new file mode 100644 index 0000000..df5e873 --- /dev/null +++ b/Scripts/Multis/PreviewHouse.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Multis +{ + public class PreviewHouse : BaseMulti + { + private List m_Components; + private Timer m_Timer; + + public PreviewHouse( int multiID ) : base( multiID ) + { + m_Components = new List(); + + MultiComponentList mcl = this.Components; + + for ( int i = 1; i < mcl.List.Length; ++i ) + { + MultiTileEntry entry = mcl.List[i]; + + if ( entry.m_Flags == 0 ) + { + Item item = new Static( (int)entry.m_ItemID ); + + item.MoveToWorld( new Point3D( X + entry.m_OffsetX, Y + entry.m_OffsetY, Z + entry.m_OffsetZ ), Map ); + + m_Components.Add( item ); + } + } + + m_Timer = new DecayTimer( this ); + m_Timer.Start(); + } + + public override void OnLocationChange( Point3D oldLocation ) + { + base.OnLocationChange( oldLocation ); + + if ( m_Components == null ) + return; + + int xOffset = X - oldLocation.X; + int yOffset = Y - oldLocation.Y; + int zOffset = Z - oldLocation.Z; + + for ( int i = 0; i < m_Components.Count; ++i ) + { + Item item = m_Components[i]; + + item.MoveToWorld( new Point3D( item.X + xOffset, item.Y + yOffset, item.Z + zOffset ), this.Map ); + } + } + + public override void OnMapChange() + { + base.OnMapChange(); + + if ( m_Components == null ) + return; + + for ( int i = 0; i < m_Components.Count; ++i ) + { + Item item = m_Components[i]; + + item.Map = this.Map; + } + } + + public override void OnDelete() + { + base.OnDelete(); + + if ( m_Components == null ) + return; + + for ( int i = 0; i < m_Components.Count; ++i ) + { + Item item = m_Components[i]; + + item.Delete(); + } + } + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + base.OnAfterDelete(); + } + + public PreviewHouse( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Components ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Components = reader.ReadStrongItemList(); + + break; + } + } + + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( this.Delete ) ); + } + + private class DecayTimer : Timer + { + private Item m_Item; + + public DecayTimer( Item item ) : base( TimeSpan.FromSeconds( 20.0 ) ) + { + m_Item = item; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/BaseRegion.cs b/Scripts/Regions/BaseRegion.cs new file mode 100644 index 0000000..8036cf6 --- /dev/null +++ b/Scripts/Regions/BaseRegion.cs @@ -0,0 +1,599 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.ServerSeasons; +using Server.Gumps; + +namespace Server.Regions +{ + public enum SpawnZLevel + { + Lowest, + Highest, + Random + } + + public class BaseRegion : Region, ISeasons + { + #region Scriptiz : gestion des saisons + private Season m_Season = Season.Summer; + public virtual Season Season { get { return m_Season; } set { m_Season = value; UpdateSeason(); } } + + public void UpdateSeason() + { + foreach (Mobile m in this.GetPlayers()) + UpdateSeason(m); + } + + public void UpdateSeason(Mobile m) + { + UpdateSeason(m, (int)m_Season); + } + + private void UpdateSeason(Mobile m, int s) + { + if (s < 0 || s > 4) return; + + if (m is PlayerMobile) + { + NetState state = m.NetState; + + if (state != null) + state.Send(new SeasonChange(s)); + } + } + + public override void OnEnter(Mobile m) + { + if (m is PlayerMobile && ((PlayerMobile)m).Young) + { + if (!this.YoungProtected) + { + m.SendGump(new YoungDungeonWarning()); + } + } + UpdateSeason(m); + } + + public override void OnExit(Mobile m) + { + UpdateSeason(m, m.Map.Season); + base.OnExit(m); + } + #endregion + + public virtual bool YoungProtected { get { return true; } } + public virtual bool YoungMayEnter { get { return true; } } + public virtual bool MountsAllowed { get { return true; } } + public virtual bool DeadMayEnter { get { return true; } } + public virtual bool ResurrectionAllowed { get { return true; } } + public virtual bool LogoutAllowed { get { return true; } } + + + public static void Configure() + { + Region.DefaultRegionType = typeof( BaseRegion ); + } + + private string m_RuneName; + private bool m_NoLogoutDelay; + + private SpawnEntry[] m_Spawns; + private SpawnZLevel m_SpawnZLevel; + private bool m_ExcludeFromParentSpawns; + + public string RuneName{ get{ return m_RuneName; } set{ m_RuneName = value; } } + + public bool NoLogoutDelay{ get{ return m_NoLogoutDelay; } set{ m_NoLogoutDelay = value; } } + + public SpawnEntry[] Spawns + { + get{ return m_Spawns; } + set + { + if ( m_Spawns != null ) + { + for ( int i = 0; i < m_Spawns.Length; i++ ) + m_Spawns[i].Delete(); + } + + m_Spawns = value; + } + } + + public SpawnZLevel SpawnZLevel{ get{ return m_SpawnZLevel; } set{ m_SpawnZLevel = value; } } + + public bool ExcludeFromParentSpawns{ get{ return m_ExcludeFromParentSpawns; } set{ m_ExcludeFromParentSpawns = value; } } + + public override void OnUnregister() + { + base.OnUnregister(); + + this.Spawns = null; + } + + public static string GetRuneNameFor( Region region ) + { + while ( region != null ) + { + BaseRegion br = region as BaseRegion; + + if ( br != null && br.m_RuneName != null ) + return br.m_RuneName; + + region = region.Parent; + } + + return null; + } + + public override TimeSpan GetLogoutDelay( Mobile m ) + { + if ( m_NoLogoutDelay ) + { + if ( m.Aggressors.Count == 0 && m.Aggressed.Count == 0 && !m.Criminal ) + return TimeSpan.Zero; + } + + return base.GetLogoutDelay( m ); + } + + public static bool CanSpawn( Region region, params Type[] types ) + { + while ( region != null ) + { + if ( !region.AllowSpawn() ) + return false; + + BaseRegion br = region as BaseRegion; + + if ( br != null ) + { + if ( br.Spawns != null ) + { + for ( int i = 0; i < br.Spawns.Length; i++ ) + { + SpawnEntry entry = br.Spawns[i]; + + if ( entry.Definition.CanSpawn( types ) ) + return true; + } + } + + if ( br.ExcludeFromParentSpawns ) + return false; + } + + region = region.Parent; + } + + return false; + } + + + + public override bool AcceptsSpawnsFrom( Region region ) + { + if ( region == this || !m_ExcludeFromParentSpawns ) + return base.AcceptsSpawnsFrom( region ); + + return false; + } + + private Rectangle3D[] m_Rectangles; + private int[] m_RectangleWeights; + private int m_TotalWeight; + + private static List m_RectBuffer1 = new List(); + private static List m_RectBuffer2 = new List(); + + private void InitRectangles() + { + if ( m_Rectangles != null ) + return; + + // Test if area rectangles are overlapping, and in that case break them into smaller non overlapping rectangles + for ( int i = 0; i < this.Area.Length; i++ ) + { + m_RectBuffer2.Add( this.Area[i] ); + + for ( int j = 0; j < m_RectBuffer1.Count && m_RectBuffer2.Count > 0; j++ ) + { + Rectangle3D comp = m_RectBuffer1[j]; + + for ( int k = m_RectBuffer2.Count - 1; k >= 0; k-- ) + { + Rectangle3D rect = m_RectBuffer2[k]; + + int l1 = rect.Start.X, r1 = rect.End.X, t1 = rect.Start.Y, b1 = rect.End.Y; + int l2 = comp.Start.X, r2 = comp.End.X, t2 = comp.Start.Y, b2 = comp.End.Y; + + if ( l1 < r2 && r1 > l2 && t1 < b2 && b1 > t2 ) + { + m_RectBuffer2.RemoveAt( k ); + + int sz = rect.Start.Z; + int ez = rect.End.X; + + if ( l1 < l2 ) + { + m_RectBuffer2.Add( new Rectangle3D( new Point3D( l1, t1, sz ), new Point3D( l2, b1, ez ) ) ); + } + + if ( r1 > r2 ) + { + m_RectBuffer2.Add( new Rectangle3D( new Point3D( r2, t1, sz ), new Point3D( r1, b1, ez ) ) ); + } + + if ( t1 < t2 ) + { + m_RectBuffer2.Add( new Rectangle3D( new Point3D( Math.Max( l1, l2 ), t1, sz ), new Point3D( Math.Min( r1, r2 ), t2, ez ) ) ); + } + + if ( b1 > b2 ) + { + m_RectBuffer2.Add( new Rectangle3D( new Point3D( Math.Max( l1, l2 ), b2, sz ), new Point3D( Math.Min( r1, r2 ), b1, ez ) ) ); + } + } + } + } + + m_RectBuffer1.AddRange( m_RectBuffer2 ); + m_RectBuffer2.Clear(); + } + + m_Rectangles = m_RectBuffer1.ToArray(); + m_RectBuffer1.Clear(); + + m_RectangleWeights = new int[m_Rectangles.Length]; + for ( int i = 0; i < m_Rectangles.Length; i++ ) + { + Rectangle3D rect = m_Rectangles[i]; + int weight = rect.Width * rect.Height; + + m_RectangleWeights[i] = weight; + m_TotalWeight += weight; + } + } + + private static List m_SpawnBuffer1 = new List(); + private static List m_SpawnBuffer2 = new List(); + + public Point3D RandomSpawnLocation( int spawnHeight, bool land, bool water, Point3D home, int range ) + { + Map map = this.Map; + + if ( map == Map.Internal ) + return Point3D.Zero; + + InitRectangles(); + + if ( m_TotalWeight <= 0 ) + return Point3D.Zero; + + for ( int i = 0; i < 10; i++ ) // Try 10 times + { + int x, y, minZ, maxZ; + + if ( home == Point3D.Zero ) + { + int rand = Utility.Random( m_TotalWeight ); + + x = int.MinValue; y = int.MinValue; + minZ = int.MaxValue; maxZ = int.MinValue; + for ( int j = 0; j < m_RectangleWeights.Length; j++ ) + { + int curWeight = m_RectangleWeights[j]; + + if ( rand < curWeight ) + { + Rectangle3D rect = m_Rectangles[j]; + + x = rect.Start.X + rand % rect.Width; + y = rect.Start.Y + rand / rect.Width; + + minZ = rect.Start.Z; + maxZ = rect.End.Z; + + break; + } + + rand -= curWeight; + } + } + else + { + x = Utility.RandomMinMax( home.X - range, home.X + range ); + y = Utility.RandomMinMax( home.Y - range, home.Y + range ); + + minZ = int.MaxValue; maxZ = int.MinValue; + for ( int j = 0; j < this.Area.Length; j++ ) + { + Rectangle3D rect = this.Area[j]; + + if ( x >= rect.Start.X && x < rect.End.X && y >= rect.Start.Y && y < rect.End.Y ) + { + minZ = rect.Start.Z; + maxZ = rect.End.Z; + break; + } + } + + if ( minZ == int.MaxValue ) + continue; + } + + if ( x < 0 || y < 0 || x >= map.Width || y >= map.Height ) + continue; + + LandTile lt = map.Tiles.GetLandTile( x, y ); + + int ltLowZ = 0, ltAvgZ = 0, ltTopZ = 0; + map.GetAverageZ( x, y, ref ltLowZ, ref ltAvgZ, ref ltTopZ ); + + TileFlag ltFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + bool ltImpassable = ( (ltFlags & TileFlag.Impassable) != 0 ); + + if ( !lt.Ignored && ltAvgZ >= minZ && ltAvgZ < maxZ ) + if ( (ltFlags & TileFlag.Wet) != 0 ) { + if ( water ) + m_SpawnBuffer1.Add( ltAvgZ ); + } + else if ( land && !ltImpassable ) + m_SpawnBuffer1.Add( ltAvgZ ); + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles( x, y, true ); + + for ( int j = 0; j < staticTiles.Length; j++ ) + { + StaticTile tile = staticTiles[j]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + int tileZ = tile.Z + id.CalcHeight; + + if ( tileZ >= minZ && tileZ < maxZ ) + if ( (id.Flags & TileFlag.Wet) != 0 ) { + if ( water ) + m_SpawnBuffer1.Add( tileZ ); + } + else if ( land && id.Surface && !id.Impassable ) + m_SpawnBuffer1.Add( tileZ ); + } + + + Sector sector = map.GetSector( x, y ); + + for ( int j = 0; j < sector.Items.Count; j++ ) + { + Item item = sector.Items[j]; + + if ( !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint( x, y ) ) + { + m_SpawnBuffer2.Add( item ); + + if ( !item.Movable ) + { + ItemData id = item.ItemData; + int itemZ = item.Z + id.CalcHeight; + + if ( itemZ >= minZ && itemZ < maxZ ) + if ( (id.Flags & TileFlag.Wet) != 0 ) { + if ( water ) + m_SpawnBuffer1.Add( itemZ ); + } + else if ( land && id.Surface && !id.Impassable ) + m_SpawnBuffer1.Add( itemZ ); + } + } + } + + + if ( m_SpawnBuffer1.Count == 0 ) + { + m_SpawnBuffer1.Clear(); + m_SpawnBuffer2.Clear(); + continue; + } + + int z; + switch ( m_SpawnZLevel ) + { + case SpawnZLevel.Lowest: + { + z = int.MaxValue; + + for ( int j = 0; j < m_SpawnBuffer1.Count; j++ ) + { + int l = m_SpawnBuffer1[j]; + + if ( l < z ) + z = l; + } + + break; + } + case SpawnZLevel.Highest: + { + z = int.MinValue; + + for ( int j = 0; j < m_SpawnBuffer1.Count; j++ ) + { + int l = m_SpawnBuffer1[j]; + + if ( l > z ) + z = l; + } + + break; + } + default: // SpawnZLevel.Random + { + int index = Utility.Random( m_SpawnBuffer1.Count ); + z = m_SpawnBuffer1[index]; + + break; + } + } + + m_SpawnBuffer1.Clear(); + + + if ( !Region.Find( new Point3D( x, y, z ), map ).AcceptsSpawnsFrom( this ) ) + { + m_SpawnBuffer2.Clear(); + continue; + } + + int top = z + spawnHeight; + + bool ok = true; + for ( int j = 0; j < m_SpawnBuffer2.Count; j++ ) + { + Item item = m_SpawnBuffer2[j]; + ItemData id = item.ItemData; + + if ( ( id.Surface || id.Impassable ) && item.Z + id.CalcHeight > z && item.Z < top ) + { + ok = false; + break; + } + } + + m_SpawnBuffer2.Clear(); + + if ( !ok ) + continue; + + if ( ltImpassable && ltAvgZ > z && ltLowZ < top ) + continue; + + for ( int j = 0; j < staticTiles.Length; j++ ) + { + StaticTile tile = staticTiles[j]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + if ( ( id.Surface || id.Impassable ) && tile.Z + id.CalcHeight > z && tile.Z < top ) + { + ok = false; + break; + } + } + + if ( !ok ) + continue; + + for ( int j = 0; j < sector.Mobiles.Count; j++ ) + { + Mobile m = sector.Mobiles[j]; + + if ( m.X == x && m.Y == y && ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) ) + if ( m.Z + 16 > z && m.Z < top ) + { + ok = false; + break; + } + } + + if ( ok ) + return new Point3D( x, y, z ); + } + + return Point3D.Zero; + } + + public override string ToString() + { + if ( this.Name != null ) + return this.Name; + else if ( this.RuneName != null ) + return this.RuneName; + else + return this.GetType().Name; + } + + public BaseRegion( string name, Map map, int priority, params Rectangle2D[] area ) : base( name, map, priority, area ) + { + } + + public BaseRegion( string name, Map map, int priority, params Rectangle3D[] area ) : base( name, map, priority, area ) + { + } + + public BaseRegion( string name, Map map, Region parent, params Rectangle2D[] area ) : base( name, map, parent, area ) + { + } + + public BaseRegion( string name, Map map, Region parent, params Rectangle3D[] area ) : base( name, map, parent, area ) + { + } + + public BaseRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + ReadString( xml["rune"], "name", ref m_RuneName, false ); + + bool logoutDelayActive = true; + ReadBoolean( xml["logoutDelay"], "active", ref logoutDelayActive, false ); + m_NoLogoutDelay = !logoutDelayActive; + + + XmlElement spawning = xml["spawning"]; + if ( spawning != null ) + { + ReadBoolean( spawning, "excludeFromParent", ref m_ExcludeFromParentSpawns, false ); + + SpawnZLevel zLevel = SpawnZLevel.Lowest; + ReadEnum( spawning, "zLevel", ref zLevel, false ); + m_SpawnZLevel = zLevel; + + + List list = new List(); + + foreach ( XmlNode node in spawning.ChildNodes ) + { + XmlElement el = node as XmlElement; + + if ( el != null ) + { + SpawnDefinition def = SpawnDefinition.GetSpawnDefinition( el ); + if ( def == null ) + continue; + + int id = 0; + if ( !ReadInt32( el, "id", ref id, true ) ) + continue; + + int amount = 0; + if ( !ReadInt32( el, "amount", ref amount, true ) ) + continue; + + TimeSpan minSpawnTime = SpawnEntry.DefaultMinSpawnTime; + ReadTimeSpan( el, "minSpawnTime", ref minSpawnTime, false ); + + TimeSpan maxSpawnTime = SpawnEntry.DefaultMaxSpawnTime; + ReadTimeSpan( el, "maxSpawnTime", ref maxSpawnTime, false ); + + Point3D home = Point3D.Zero; + int range = 0; + + XmlElement homeEl = el["home"]; + if ( ReadPoint3D( homeEl, map, ref home, false ) ) + ReadInt32( homeEl, "range", ref range, false ); + + Direction dir = SpawnEntry.InvalidDirection; + ReadEnum( el["direction"], "value" , ref dir, false ); + + SpawnEntry entry = new SpawnEntry( id, this, home, range, dir, def, amount, minSpawnTime, maxSpawnTime ); + list.Add( entry ); + } + } + + if ( list.Count > 0 ) + { + m_Spawns = list.ToArray(); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/DungeonRegion.cs b/Scripts/Regions/DungeonRegion.cs new file mode 100644 index 0000000..fb6706a --- /dev/null +++ b/Scripts/Regions/DungeonRegion.cs @@ -0,0 +1,50 @@ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Regions +{ + public class DungeonRegion : BaseRegion + { + + public override bool YoungProtected { get { return false; } } + + private Point3D m_EntranceLocation; + private Map m_EntranceMap; + + public Point3D EntranceLocation{ get{ return m_EntranceLocation; } set{ m_EntranceLocation = value; } } + public Map EntranceMap{ get{ return m_EntranceMap; } set{ m_EntranceMap = value; } } + + public DungeonRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + XmlElement entrEl = xml["entrance"]; + + Map entrMap = map; + ReadMap( entrEl, "map", ref entrMap, false ); + + if ( ReadPoint3D( entrEl, entrMap, ref m_EntranceLocation, false ) ) + m_EntranceMap = entrMap; + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + return false; + } + + + public override void AlterLightLevel( Mobile m, ref int global, ref int personal ) + { + global = LightCycle.DungeonLevel; + } + + public override bool CanUseStuckMenu( Mobile m ) + { + if ( this.Map == Map.Felucca ) + return false; + + return base.CanUseStuckMenu( m ); + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/GreenAcres.cs b/Scripts/Regions/GreenAcres.cs new file mode 100644 index 0000000..6171d7b --- /dev/null +++ b/Scripts/Regions/GreenAcres.cs @@ -0,0 +1,40 @@ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; + +namespace Server.Regions +{ + public class GreenAcres : BaseRegion + { + public GreenAcres( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + if ( from.AccessLevel == AccessLevel.Player ) + return false; + else + return base.AllowHousing( from, p ); + } + + public override bool OnBeginSpellCast( Mobile m, ISpell s ) + { + if ( ( s is GateTravelSpell || s is RecallSpell || s is MarkSpell || s is SacredJourneySpell ) && m.AccessLevel == AccessLevel.Player ) + { + m.SendMessage( "You cannot cast that spell here." ); + return false; + } + else + { + return base.OnBeginSpellCast( m, s ); + } + } + } +} diff --git a/Scripts/Regions/GuardedRegion.cs b/Scripts/Regions/GuardedRegion.cs new file mode 100644 index 0000000..dc59a40 --- /dev/null +++ b/Scripts/Regions/GuardedRegion.cs @@ -0,0 +1,378 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Xml; +using Server; +using Server.Commands; +using Server.Mobiles; +using Server.Spells; + +namespace Server.Regions +{ + public class GuardedRegion : BaseRegion + { + private static object[] m_GuardParams = new object[1]; + private Type m_GuardType; + private bool m_Disabled; + + public bool Disabled{ get{ return m_Disabled; } set{ m_Disabled = value; } } + + public virtual bool IsDisabled() + { + return true; + //return m_Disabled; + } + + public static void Initialize() + { + CommandSystem.Register( "CheckGuarded", AccessLevel.GameMaster, new CommandEventHandler( CheckGuarded_OnCommand ) ); + CommandSystem.Register( "SetGuarded", AccessLevel.Administrator, new CommandEventHandler( SetGuarded_OnCommand ) ); + CommandSystem.Register( "ToggleGuarded", AccessLevel.Administrator, new CommandEventHandler( ToggleGuarded_OnCommand ) ); + } + + [Usage( "CheckGuarded" )] + [Description( "Returns a value indicating if the current region is guarded or not." )] + private static void CheckGuarded_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + GuardedRegion reg = (GuardedRegion) from.Region.GetRegion( typeof( GuardedRegion ) ); + + if ( reg == null ) + from.SendMessage( "You are not in a guardable region." ); + else if ( reg.Disabled ) + from.SendMessage( "The guards in this region have been disabled." ); + else + from.SendMessage( "This region is actively guarded." ); + } + + [Usage( "SetGuarded " )] + [Description( "Enables or disables guards for the current region." )] + private static void SetGuarded_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + + if ( e.Length == 1 ) + { + GuardedRegion reg = (GuardedRegion) from.Region.GetRegion( typeof( GuardedRegion ) ); + + if ( reg == null ) + { + from.SendMessage( "You are not in a guardable region." ); + } + else + { + reg.Disabled = !e.GetBoolean( 0 ); + + if ( reg.Disabled ) + from.SendMessage( "The guards in this region have been disabled." ); + else + from.SendMessage( "The guards in this region have been enabled." ); + } + } + else + { + from.SendMessage( "Format: SetGuarded " ); + } + } + + [Usage( "ToggleGuarded" )] + [Description( "Toggles the state of guards for the current region." )] + private static void ToggleGuarded_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + GuardedRegion reg = (GuardedRegion) from.Region.GetRegion( typeof( GuardedRegion ) ); + + if ( reg == null ) + { + from.SendMessage( "You are not in a guardable region." ); + } + else + { + reg.Disabled = !reg.Disabled; + + if ( reg.Disabled ) + from.SendMessage( "The guards in this region have been disabled." ); + else + from.SendMessage( "The guards in this region have been enabled." ); + } + } + + public static GuardedRegion Disable( GuardedRegion reg ) + { + reg.Disabled = true; + return reg; + } + + public virtual bool AllowReds{ get{ return Core.AOS; } } + + public virtual bool CheckVendorAccess( BaseVendor vendor, Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.GameMaster || IsDisabled() ) + return true; + + return ( from.Kills < 5 ); + } + + public virtual Type DefaultGuardType + { + get + { + if ( this.Map == Map.Ilshenar || this.Map == Map.Malas ) + return typeof( ArcherGuard ); + else + return typeof( WarriorGuard ); + } + } + + public GuardedRegion( string name, Map map, int priority, params Rectangle3D[] area ) : base( name, map, priority, area ) + { + m_GuardType = DefaultGuardType; + } + + public GuardedRegion( string name, Map map, int priority, params Rectangle2D[] area ) + : base( name, map, priority, area ) + { + m_GuardType = DefaultGuardType; + } + + public GuardedRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + XmlElement el = xml["guards"]; + + if ( ReadType( el, "type", ref m_GuardType, false ) ) + { + if ( !typeof( Mobile ).IsAssignableFrom( m_GuardType ) ) + { + Console.WriteLine( "Invalid guard type for region '{0}'", this ); + m_GuardType = DefaultGuardType; + } + } + else + { + m_GuardType = DefaultGuardType; + } + + bool disabled = false; + if ( ReadBoolean( el, "disabled", ref disabled, false ) ) + this.Disabled = disabled; + } + + public override bool OnBeginSpellCast( Mobile m, ISpell s ) + { + if ( !IsDisabled() && !s.OnCastInTown( this ) ) + { + m.SendLocalizedMessage( 500946 ); // You cannot cast this in town! + return false; + } + + return base.OnBeginSpellCast( m, s ); + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + return false; + } + + public override void MakeGuard( Mobile focus ) + { + BaseGuard useGuard = null; + + foreach ( Mobile m in focus.GetMobilesInRange( 8 ) ) + { + if ( m is BaseGuard ) + { + BaseGuard g = (BaseGuard)m; + + if ( g.Focus == null ) // idling + { + useGuard = g; + break; + } + } + } + + if ( useGuard == null ) + { + m_GuardParams[0] = focus; + + try { Activator.CreateInstance( m_GuardType, m_GuardParams ); } catch {} + } + else + useGuard.Focus = focus; + } + + public override void OnEnter( Mobile m ) + { + if ( IsDisabled() ) + return; + + if ( !AllowReds && m.Kills >= 5 ) + CheckGuardCandidate( m ); + } + + public override void OnExit( Mobile m ) + { + if ( IsDisabled() ) + return; + } + + public override void OnSpeech( SpeechEventArgs args ) + { + base.OnSpeech( args ); + + if ( IsDisabled() ) + return; + + if ( args.Mobile.Alive && args.HasKeyword( 0x0007 ) ) // *guards* + CallGuards( args.Mobile.Location ); + } + + public override void OnAggressed( Mobile aggressor, Mobile aggressed, bool criminal ) + { + base.OnAggressed( aggressor, aggressed, criminal ); + + if ( !IsDisabled() && aggressor != aggressed && criminal ) + CheckGuardCandidate( aggressor ); + } + + public override void OnGotBeneficialAction( Mobile helper, Mobile helped ) + { + base.OnGotBeneficialAction( helper, helped ); + + if ( IsDisabled() ) + return; + + int noto = Notoriety.Compute( helper, helped ); + + if ( helper != helped && (noto == Notoriety.Criminal || noto == Notoriety.Murderer) ) + CheckGuardCandidate( helper ); + } + + public override void OnCriminalAction( Mobile m, bool message ) + { + base.OnCriminalAction( m, message ); + + if ( !IsDisabled() ) + CheckGuardCandidate( m ); + } + + private Dictionary m_GuardCandidates = new Dictionary(); + + public void CheckGuardCandidate( Mobile m ) + { + if ( IsDisabled() ) + return; + + if ( IsGuardCandidate( m ) ) + { + GuardTimer timer = null; + m_GuardCandidates.TryGetValue( m, out timer ); + + if ( timer == null ) + { + timer = new GuardTimer( m, m_GuardCandidates ); + timer.Start(); + + m_GuardCandidates[m] = timer; + m.SendLocalizedMessage( 502275 ); // Guards can now be called on you! + + Map map = m.Map; + + if ( map != null ) + { + Mobile fakeCall = null; + double prio = 0.0; + + foreach ( Mobile v in m.GetMobilesInRange( 8 ) ) + { + if( !v.Player && v != m && !IsGuardCandidate( v ) && ((v is BaseCreature)? ((BaseCreature)v).IsHumanInTown() : (v.Body.IsHuman && v.Region.IsPartOf( this ))) ) + { + double dist = m.GetDistanceToSqrt( v ); + + if ( fakeCall == null || dist < prio ) + { + fakeCall = v; + prio = dist; + } + } + } + + if ( fakeCall != null ) + { + fakeCall.Say( Utility.RandomList( 1007037, 501603, 1013037, 1013038, 1013039, 1013041, 1013042, 1013043, 1013052 ) ); + MakeGuard( m ); + timer.Stop(); + m_GuardCandidates.Remove( m ); + m.SendLocalizedMessage( 502276 ); // Guards can no longer be called on you. + } + } + } + else + { + timer.Stop(); + timer.Start(); + } + } + } + + public void CallGuards( Point3D p ) + { + if ( IsDisabled() ) + return; + + IPooledEnumerable eable = Map.GetMobilesInRange( p, 14 ); + + foreach ( Mobile m in eable ) + { + if ( IsGuardCandidate( m ) && ( ( !AllowReds && m.Kills >= 5 && m.Region.IsPartOf( this ) ) || m_GuardCandidates.ContainsKey( m ) ) ) + { + GuardTimer timer = null; + m_GuardCandidates.TryGetValue( m, out timer ); + + if ( timer != null ) + { + timer.Stop(); + m_GuardCandidates.Remove( m ); + } + + MakeGuard( m ); + m.SendLocalizedMessage( 502276 ); // Guards can no longer be called on you. + break; + } + } + + eable.Free(); + } + + public bool IsGuardCandidate( Mobile m ) + { + if (m is BaseGuard || !m.Alive || m.AccessLevel > AccessLevel.Player || m.Blessed || (m is BaseCreature && ((BaseCreature)m).IsInvulnerable) || IsDisabled()) + return false; + + return (!AllowReds && m.Kills >= 5) || m.Criminal; + } + + private class GuardTimer : Timer + { + private Mobile m_Mobile; + private Dictionary m_Table; + + public GuardTimer( Mobile m, Dictionary table ) : base( TimeSpan.FromSeconds( 15.0 ) ) + { + Priority = TimerPriority.TwoFiftyMS; + + m_Mobile = m; + m_Table = table; + } + + protected override void OnTick() + { + if ( m_Table.ContainsKey( m_Mobile ) ) + { + m_Table.Remove( m_Mobile ); + m_Mobile.SendLocalizedMessage( 502276 ); // Guards can no longer be called on you. + } + } + } + } +} diff --git a/Scripts/Regions/HouseRegion.cs b/Scripts/Regions/HouseRegion.cs new file mode 100644 index 0000000..1def0d6 --- /dev/null +++ b/Scripts/Regions/HouseRegion.cs @@ -0,0 +1,435 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Multis; +using Server.Spells; +using Server.Spells.Sixth; +using Server.Guilds; +using Server.Gumps; + +namespace Server.Regions +{ + public class HouseRegion : BaseRegion + { + public static readonly int HousePriority = Region.DefaultPriority + 1; + + private BaseHouse m_House; + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( OnLogin ); + } + + public static void OnLogin( LoginEventArgs e ) + { + BaseHouse house = BaseHouse.FindHouseAt( e.Mobile ); + + if ( house != null && !house.Public && !house.IsFriend( e.Mobile ) ) + e.Mobile.Location = house.BanLocation; + } + + public HouseRegion( BaseHouse house ) : base( null, house.Map, HousePriority, GetArea( house ) ) + { + m_House = house; + + Point3D ban = house.RelativeBanLocation; + + this.GoLocation = new Point3D( house.X + ban.X, house.Y + ban.Y, house.Z + ban.Z ); + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + private static Rectangle3D[] GetArea( BaseHouse house ) + { + int x = house.X; + int y = house.Y; + int z = house.Z; + + Rectangle2D[] houseArea = house.Area; + Rectangle3D[] area = new Rectangle3D[houseArea.Length]; + + for ( int i = 0; i < area.Length; i++ ) + { + Rectangle2D rect = houseArea[i]; + area[i] = Region.ConvertTo3D( new Rectangle2D( x + rect.Start.X, y + rect.Start.Y, rect.Width, rect.Height ) ); + } + + return area; + } + + public override bool SendInaccessibleMessage( Item item, Mobile from ) + { + if ( item is Container ) + item.SendLocalizedMessageTo( from, 501647 ); // That is secure. + else + item.SendLocalizedMessageTo( from, 1061637 ); // You are not allowed to access this. + + return true; + } + + public override bool CheckAccessibility( Item item, Mobile from ) + { + return m_House.CheckAccessibility( item, from ); + } + + private bool m_Recursion; + + // Use OnLocationChanged instead of OnEnter because it can be that we enter a house region even though we're not actually inside the house + public override void OnLocationChanged( Mobile m, Point3D oldLocation ) + { + if ( m_Recursion ) + return; + + base.OnLocationChanged( m, oldLocation ); + + m_Recursion = true; + + if ( m is BaseCreature && ((BaseCreature)m).NoHouseRestrictions ) + { + } + else if ( m is BaseCreature && ((BaseCreature)m).IsHouseSummonable && !(BaseCreature.Summoning || m_House.IsInside( oldLocation, 16 )) ) + { + } + else if ( (m_House.Public || !m_House.IsAosRules) && m_House.IsBanned( m ) && m_House.IsInside( m ) ) + { + m.Location = m_House.BanLocation; + + if( !Core.SE ) + m.SendLocalizedMessage( 501284 ); // You may not enter. + } + else if ( m_House.IsAosRules && !m_House.Public && !m_House.HasAccess( m ) && m_House.IsInside( m ) ) + { + m.Location = m_House.BanLocation; + + if( !Core.SE ) + m.SendLocalizedMessage( 501284 ); // You may not enter. + } + else if ( m_House.IsCombatRestricted( m ) && m_House.IsInside( m ) && !m_House.IsInside( oldLocation, 16 ) ) + { + m.Location = m_House.BanLocation; + m.SendLocalizedMessage( 1061637 ); // You are not allowed to access this. + } + else if ( m_House is HouseFoundation ) + { + HouseFoundation foundation = (HouseFoundation)m_House; + + if ( foundation.Customizer != null && foundation.Customizer != m && m_House.IsInside( m ) ) + m.Location = m_House.BanLocation; + } + + if ( m_House.InternalizedVendors.Count > 0 && m_House.IsInside( m ) && !m_House.IsInside( oldLocation, 16 ) && m_House.IsOwner( m ) && m.Alive && !m.HasGump( typeof( NoticeGump ) ) ) + { + /* This house has been customized recently, and vendors that work out of this + * house have been temporarily relocated. You must now put your vendors back to work. + * To do this, walk to a location inside the house where you wish to station + * your vendor, then activate the context-sensitive menu on your avatar and + * select "Get Vendor". + */ + m.SendGump( new NoticeGump( 1060635, 30720, 1061826, 32512, 320, 180, null, null ) ); + } + + m_Recursion = false; + } + + public override bool OnMoveInto( Mobile from, Direction d, Point3D newLocation, Point3D oldLocation ) + { + if ( !base.OnMoveInto( from, d, newLocation, oldLocation ) ) + return false; + + if ( from is BaseCreature && ((BaseCreature)from).NoHouseRestrictions ) + { + } + else if (from is BaseCreature && !((BaseCreature)from).Controlled) // Untamed creatures cannot enter public houses + { + return false; + } + else if ( from is BaseCreature && ((BaseCreature)from).IsHouseSummonable && !(BaseCreature.Summoning || m_House.IsInside( oldLocation, 16 )) ) + { + return false; + } + else if ( from is BaseCreature && !((BaseCreature)from).Controlled && m_House.IsAosRules && !m_House.Public) + { + return false; + } + else if ( (m_House.Public || !m_House.IsAosRules) && m_House.IsBanned( from ) && m_House.IsInside( newLocation, 16 ) ) + { + from.Location = m_House.BanLocation; + + if( !Core.SE ) + from.SendLocalizedMessage( 501284 ); // You may not enter. + + return false; + } + else if ( m_House.IsAosRules && !m_House.Public && !m_House.HasAccess( from ) && m_House.IsInside( newLocation, 16 ) ) + { + if( !Core.SE ) + from.SendLocalizedMessage( 501284 ); // You may not enter. + + return false; + } + else if ( m_House.IsCombatRestricted( from ) && !m_House.IsInside( oldLocation, 16 ) && m_House.IsInside( newLocation, 16 ) ) + { + from.SendLocalizedMessage( 1061637 ); // You are not allowed to access this. + return false; + } + else if ( m_House is HouseFoundation ) + { + HouseFoundation foundation = (HouseFoundation)m_House; + + if ( foundation.Customizer != null && foundation.Customizer != from && m_House.IsInside( newLocation, 16 ) ) + return false; + } + + if ( m_House.InternalizedVendors.Count > 0 && m_House.IsInside( from ) && !m_House.IsInside( oldLocation, 16 ) && m_House.IsOwner( from ) && from.Alive && !from.HasGump( typeof( NoticeGump ) ) ) + { + /* This house has been customized recently, and vendors that work out of this + * house have been temporarily relocated. You must now put your vendors back to work. + * To do this, walk to a location inside the house where you wish to station + * your vendor, then activate the context-sensitive menu on your avatar and + * select "Get Vendor". + */ + from.SendGump( new NoticeGump( 1060635, 30720, 1061826, 32512, 320, 180, null, null ) ); + } + + return true; + } + + public override bool OnDecay( Item item ) + { + if ( (m_House.IsLockedDown( item ) || m_House.IsSecure( item )) && m_House.IsInside( item ) ) + return false; + else + return base.OnDecay(item ); + } + + public static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds( 30.0 ); + + public override TimeSpan GetLogoutDelay( Mobile m ) + { + if ( m_House.IsFriend( m ) && m_House.IsInside( m ) ) + { + for ( int i = 0; i < m.Aggressed.Count; ++i ) + { + AggressorInfo info = m.Aggressed[i]; + + if ( info.Defender.Player && (DateTime.Now - info.LastCombatTime) < CombatHeatDelay ) + return base.GetLogoutDelay( m ); + } + + return TimeSpan.Zero; + } + + return base.GetLogoutDelay( m ); + } + + public override void OnSpeech( SpeechEventArgs e ) + { + base.OnSpeech( e ); + + Mobile from = e.Mobile; + Item sign = m_House.Sign; + + if ( !from.Alive || !m_House.IsInside( from ) || !m_House.IsActive ) + return; + + bool isOwner = m_House.IsOwner( from ); + bool isCoOwner = isOwner || m_House.IsCoOwner( from ); + bool isFriend = isCoOwner || m_House.IsFriend( from ); + + if ( !isFriend ) + return; + if (!from.Alive) + return; + + if (Core.ML && Insensitive.Equals(e.Speech, "I wish to resize my house")) + { + if (from.Map != sign.Map || !from.InRange(sign, 0)) + { + from.SendLocalizedMessage(500295); // you are too far away to do that. + } + else if (DateTime.Now <= m_House.BuiltOn.AddHours(1)) + { + from.SendLocalizedMessage(1080178); // You must wait one hour between each house demolition. + } + else if (isOwner) + { + from.CloseGump(typeof(ConfirmHouseResize)); + from.CloseGump(typeof(HouseGumpAOS)); + from.SendGump(new ConfirmHouseResize(from, m_House)); + } + else + { + from.SendLocalizedMessage(501320); // Only the house owner may do this. + } + } + + if (!m_House.IsInside(from) || !m_House.IsActive) + return; + + else if (e.HasKeyword(0x33)) // remove thyself + { + if ( isFriend ) + { + from.SendLocalizedMessage( 501326 ); // Target the individual to eject from this house. + from.Target = new HouseKickTarget( m_House ); + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + else if ( e.HasKeyword( 0x34 ) ) // I ban thee + { + if ( !isFriend ) + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + else if ( !m_House.Public && m_House.IsAosRules ) + { + from.SendLocalizedMessage( 1062521 ); // You cannot ban someone from a private house. Revoke their access instead. + } + else + { + from.SendLocalizedMessage( 501325 ); // Target the individual to ban from this house. + from.Target = new HouseBanTarget( true, m_House ); + } + } + else if ( e.HasKeyword( 0x23 ) ) // I wish to lock this down + { + if ( isCoOwner ) + { + from.SendLocalizedMessage( 502097 ); // Lock what down? + from.Target = new LockdownTarget( false, m_House ); + } + else if ( isFriend ) + { + from.SendLocalizedMessage( 1010587 ); // You are not a co-owner of this house. + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + else if ( e.HasKeyword( 0x24 ) ) // I wish to release this + { + if ( isCoOwner ) + { + from.SendLocalizedMessage( 502100 ); // Choose the item you wish to release + from.Target = new LockdownTarget( true, m_House ); + } + else if ( isFriend ) + { + from.SendLocalizedMessage( 1010587 ); // You are not a co-owner of this house. + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + else if ( e.HasKeyword( 0x25 ) ) // I wish to secure this + { + if ( isOwner ) + { + from.SendLocalizedMessage( 502103 ); // Choose the item you wish to secure + from.Target = new SecureTarget( false, m_House ); + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + else if ( e.HasKeyword( 0x26 ) ) // I wish to unsecure this + { + if ( isOwner ) + { + from.SendLocalizedMessage( 502106 ); // Choose the item you wish to unsecure + from.Target = new SecureTarget( true, m_House ); + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + else if ( e.HasKeyword( 0x27 ) ) // I wish to place a strongbox + { + if ( isOwner ) + { + from.SendLocalizedMessage( 502109 ); // Owners do not get a strongbox of their own. + } + else if ( isCoOwner ) + { + m_House.AddStrongBox( from ); + } + else if ( isFriend ) + { + from.SendLocalizedMessage( 1010587 ); // You are not a co-owner of this house. + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + else if ( e.HasKeyword( 0x28 ) ) // trash barrel + { + if ( isCoOwner ) + { + m_House.AddTrashBarrel( from ); + } + else if ( isFriend ) + { + from.SendLocalizedMessage( 1010587 ); // You are not a co-owner of this house. + } + else + { + from.SendLocalizedMessage( 502094 ); // You must be in your house to do this. + } + } + } + + public override bool OnDoubleClick( Mobile from, object o ) + { + if ( o is Container ) + { + Container c = (Container)o; + + SecureAccessResult res = m_House.CheckSecureAccess( from, c ); + + switch ( res ) + { + case SecureAccessResult.Insecure: break; + case SecureAccessResult.Accessible: return true; + case SecureAccessResult.Inaccessible: c.SendLocalizedMessageTo( from, 1010563 ); return false; + } + } + + return base.OnDoubleClick( from, o ); + } + + public override bool OnSingleClick( Mobile from, object o ) + { + if ( o is Item ) + { + Item item = (Item)o; + + if ( m_House.IsLockedDown( item ) ) + item.LabelTo( from, 501643 ); // [locked down] + else if ( m_House.IsSecure( item ) ) + item.LabelTo( from, 501644 ); // [locked down & secure] + } + + return base.OnSingleClick( from, o ); + } + + public BaseHouse House + { + get + { + return m_House; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/Jail.cs b/Scripts/Regions/Jail.cs new file mode 100644 index 0000000..210e742 --- /dev/null +++ b/Scripts/Regions/Jail.cs @@ -0,0 +1,61 @@ +using System; +using System.Xml; +using Server; +using Server.Spells; + +namespace Server.Regions +{ + public class Jail : BaseRegion + { + public Jail( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + } + + public override bool AllowBeneficial( Mobile from, Mobile target ) + { + if ( from.AccessLevel == AccessLevel.Player ) + from.SendMessage( "You may not do that in jail." ); + + return ( from.AccessLevel > AccessLevel.Player ); + } + + public override bool AllowHarmful( Mobile from, Mobile target ) + { + if ( from.AccessLevel == AccessLevel.Player ) + from.SendMessage( "You may not do that in jail." ); + + return ( from.AccessLevel > AccessLevel.Player ); + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + return false; + } + + public override void AlterLightLevel( Mobile m, ref int global, ref int personal ) + { + global = LightCycle.JailLevel; + } + + public override bool OnBeginSpellCast( Mobile from, ISpell s ) + { + if ( from.AccessLevel == AccessLevel.Player ) + from.SendLocalizedMessage( 502629 ); // You cannot cast spells here. + + return ( from.AccessLevel > AccessLevel.Player ); + } + + public override bool OnSkillUse( Mobile from, int Skill ) + { + if ( from.AccessLevel == AccessLevel.Player ) + from.SendMessage( "You may not use skills in jail." ); + + return ( from.AccessLevel > AccessLevel.Player ); + } + + public override bool OnCombatantChange( Mobile from, Mobile Old, Mobile New ) + { + return ( from.AccessLevel > AccessLevel.Player ); + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/NoHousingRegion.cs b/Scripts/Regions/NoHousingRegion.cs new file mode 100644 index 0000000..cc201ea --- /dev/null +++ b/Scripts/Regions/NoHousingRegion.cs @@ -0,0 +1,26 @@ +using System; +using System.Xml; +using Server; + +namespace Server.Regions +{ + public class NoHousingRegion : BaseRegion + { + /* - False: this uses 'stupid OSI' house placement checking: part of the house may be placed here provided that the center is not in the region + * - True: this uses 'smart RunUO' house placement checking: no part of the house may be in the region + */ + private bool m_SmartChecking; + + public bool SmartChecking{ get{ return m_SmartChecking; } } + + public NoHousingRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + ReadBoolean( xml["smartNoHousing"], "active", ref m_SmartChecking, false ); + } + + public override bool AllowHousing( Mobile from, Point3D p ) + { + return m_SmartChecking; + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/Spawning/SpawnDefinition.cs b/Scripts/Regions/Spawning/SpawnDefinition.cs new file mode 100644 index 0000000..6ed3638 --- /dev/null +++ b/Scripts/Regions/Spawning/SpawnDefinition.cs @@ -0,0 +1,409 @@ +using System; +using System.Collections; +using System.IO; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Items; +using System.Collections.Generic; + +namespace Server.Regions +{ + public abstract class SpawnDefinition + { + protected SpawnDefinition() + { + } + + public abstract ISpawnable Spawn( SpawnEntry entry ); + + public abstract bool CanSpawn( params Type[] types ); + + public static SpawnDefinition GetSpawnDefinition( XmlElement xml ) + { + switch ( xml.Name ) + { + case "object": + { + Type type = null; + if ( !Region.ReadType( xml, "type", ref type ) ) + return null; + + if ( typeof( Mobile ).IsAssignableFrom( type ) ) + { + return SpawnMobile.Get( type ); + } + else if ( typeof( Item ).IsAssignableFrom( type ) ) + { + return SpawnItem.Get( type ); + } + else + { + Console.WriteLine( "Invalid type '{0}' in a SpawnDefinition", type.FullName ); + return null; + } + } + case "group": + { + string group = null; + if ( !Region.ReadString( xml, "name", ref group ) ) + return null; + + SpawnDefinition def = (SpawnDefinition) SpawnGroup.Table[group]; + + if ( def == null ) + { + Console.WriteLine( "Could not find group '{0}' in a SpawnDefinition", group ); + return null; + } + else + { + return def; + } + } + case "treasureChest": + { + int itemID = 0xE43; + Region.ReadInt32( xml, "itemID", ref itemID, false ); + + BaseTreasureChest.TreasureLevel level = BaseTreasureChest.TreasureLevel.Level2; + + Region.ReadEnum( xml, "level", ref level, false ); + + return new SpawnTreasureChest( itemID, level ); + } + default: + { + return null; + } + } + } + } + + public abstract class SpawnType : SpawnDefinition + { + private Type m_Type; + private bool m_Init; + + public Type Type{ get{ return m_Type; } } + + public abstract int Height{ get; } + public abstract bool Land{ get; } + public abstract bool Water{ get; } + + protected SpawnType( Type type ) + { + m_Type = type; + m_Init = false; + } + + protected void EnsureInit() + { + if ( m_Init ) + return; + + Init(); + m_Init = true; + } + + protected virtual void Init() + { + } + + public override ISpawnable Spawn( SpawnEntry entry ) + { + BaseRegion region = entry.Region; + Map map = region.Map; + + Point3D loc = entry.RandomSpawnLocation( this.Height, this.Land, this.Water ); + + if ( loc == Point3D.Zero ) + return null; + + return Construct( entry, loc, map ); + } + + protected abstract ISpawnable Construct( SpawnEntry entry, Point3D loc, Map map ); + + public override bool CanSpawn( params Type[] types ) + { + for ( int i = 0; i < types.Length; i++ ) + { + if ( types[i] == m_Type ) + return true; + } + + return false; + } + } + + public class SpawnMobile : SpawnType + { + private static Hashtable m_Table = new Hashtable(); + + public static SpawnMobile Get( Type type ) + { + SpawnMobile sm = (SpawnMobile) m_Table[type]; + + if ( sm == null ) + { + sm = new SpawnMobile( type ); + m_Table[type] = sm; + } + + return sm; + } + + protected bool m_Land; + protected bool m_Water; + + public override int Height{ get{ return 16; } } + public override bool Land{ get{ EnsureInit(); return m_Land; } } + public override bool Water{ get{ EnsureInit(); return m_Water; } } + + protected SpawnMobile( Type type ) : base( type ) + { + } + + protected override void Init() + { + Mobile mob = (Mobile) Activator.CreateInstance( Type ); + + m_Land = !mob.CantWalk; + m_Water = mob.CanSwim; + + mob.Delete(); + } + + protected override ISpawnable Construct(SpawnEntry entry, Point3D loc, Map map) + { + Mobile mobile = CreateMobile(); + + BaseCreature creature = mobile as BaseCreature; + + if ( creature != null ) + { + creature.Home = entry.HomeLocation; + creature.RangeHome = entry.HomeRange; + } + + if ( entry.Direction != SpawnEntry.InvalidDirection ) + mobile.Direction = entry.Direction; + + mobile.OnBeforeSpawn( loc, map ); + mobile.MoveToWorld( loc, map ); + mobile.OnAfterSpawn(); + + return mobile; + } + + protected virtual Mobile CreateMobile() + { + return (Mobile) Activator.CreateInstance( Type ); + } + } + + public class SpawnItem : SpawnType + { + private static Hashtable m_Table = new Hashtable(); + + public static SpawnItem Get( Type type ) + { + SpawnItem si = (SpawnItem) m_Table[type]; + + if ( si == null ) + { + si = new SpawnItem( type ); + m_Table[type] = si; + } + + return si; + } + + protected int m_Height; + + public override int Height{ get{ EnsureInit(); return m_Height; } } + public override bool Land{ get{ return true; } } + public override bool Water{ get{ return false; } } + + protected SpawnItem( Type type ) : base( type ) + { + } + + protected override void Init() + { + Item item = (Item) Activator.CreateInstance( Type ); + + m_Height = item.ItemData.Height; + + item.Delete(); + } + + protected override ISpawnable Construct( SpawnEntry entry, Point3D loc, Map map ) + { + Item item = CreateItem(); + + item.OnBeforeSpawn( loc, map ); + item.MoveToWorld( loc, map ); + item.OnAfterSpawn(); + + return item; + } + + protected virtual Item CreateItem() + { + return (Item) Activator.CreateInstance( Type ); + } + } + + public class SpawnTreasureChest : SpawnItem + { + private int m_ItemID; + private BaseTreasureChest.TreasureLevel m_Level; + + public int ItemID{ get{ return m_ItemID; } } + public BaseTreasureChest.TreasureLevel Level{ get{ return m_Level; } } + + public SpawnTreasureChest( int itemID, BaseTreasureChest.TreasureLevel level ) : base( typeof( BaseTreasureChest ) ) + { + m_ItemID = itemID; + m_Level = level; + } + + protected override void Init() + { + m_Height = TileData.ItemTable[m_ItemID & TileData.MaxItemValue].Height; + } + + protected override Item CreateItem() + { + return new BaseTreasureChest( m_ItemID, m_Level ); + } + } + + public class SpawnGroupElement + { + private SpawnDefinition m_SpawnDefinition; + private int m_Weight; + + public SpawnDefinition SpawnDefinition{ get{ return m_SpawnDefinition; } } + public int Weight{ get{ return m_Weight; } } + + public SpawnGroupElement( SpawnDefinition spawnDefinition, int weight ) + { + m_SpawnDefinition = spawnDefinition; + m_Weight = weight; + } + } + + public class SpawnGroup : SpawnDefinition + { + private static Hashtable m_Table = new Hashtable(); + + public static Hashtable Table{ get{ return m_Table; } } + + public static void Register( SpawnGroup group ) + { + if ( m_Table.Contains( group.Name ) ) + Console.WriteLine( "Warning: Double SpawnGroup name '{0}'", group.Name ); + else + m_Table[group.Name] = group; + } + + static SpawnGroup() + { + string path = Path.Combine( Core.BaseDirectory, "Data/SpawnDefinitions.xml" ); + if ( !File.Exists( path ) ) + return; + + try + { + XmlDocument doc = new XmlDocument(); + doc.Load( path ); + + XmlElement root = doc["spawnDefinitions"]; + if ( root == null ) + return; + + foreach ( XmlElement xmlDef in root.SelectNodes( "spawnGroup" ) ) + { + string name = null; + if ( !Region.ReadString( xmlDef, "name", ref name ) ) + continue; + + List list = new List(); + foreach ( XmlNode node in xmlDef.ChildNodes ) + { + XmlElement el = node as XmlElement; + + if ( el != null ) + { + SpawnDefinition def = GetSpawnDefinition( el ); + if ( def == null ) + continue; + + int weight = 1; + Region.ReadInt32( el, "weight", ref weight, false ); + + SpawnGroupElement groupElement = new SpawnGroupElement( def, weight ); + list.Add( groupElement ); + } + } + + SpawnGroupElement[] elements = list.ToArray(); + SpawnGroup group = new SpawnGroup( name, elements ); + Register( group ); + } + } + catch ( Exception ex ) + { + Console.WriteLine( "Could not load SpawnDefinitions.xml: " + ex.Message ); + } + } + + private string m_Name; + private SpawnGroupElement[] m_Elements; + private int m_TotalWeight; + + public string Name{ get{ return m_Name; } } + public SpawnGroupElement[] Elements{ get{ return m_Elements; } } + + public SpawnGroup( string name, SpawnGroupElement[] elements ) + { + m_Name = name; + m_Elements = elements; + + m_TotalWeight = 0; + for ( int i = 0; i < elements.Length; i++ ) + m_TotalWeight += elements[i].Weight; + } + + public override ISpawnable Spawn(SpawnEntry entry) + { + int index = Utility.Random( m_TotalWeight ); + + for ( int i = 0; i < m_Elements.Length; i++ ) + { + SpawnGroupElement element = m_Elements[i]; + + if ( index < element.Weight ) + return element.SpawnDefinition.Spawn( entry ); + + index -= element.Weight; + } + + return null; + } + + public override bool CanSpawn( params Type[] types ) + { + for ( int i = 0; i < m_Elements.Length; i++ ) + { + if ( m_Elements[i].SpawnDefinition.CanSpawn( types ) ) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/Spawning/SpawnEntry.cs b/Scripts/Regions/Spawning/SpawnEntry.cs new file mode 100644 index 0000000..f62662d --- /dev/null +++ b/Scripts/Regions/Spawning/SpawnEntry.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Commands; + +namespace Server.Regions +{ + public class SpawnEntry : ISpawner + { + public static readonly TimeSpan DefaultMinSpawnTime = TimeSpan.FromMinutes( 2.0 ); + public static readonly TimeSpan DefaultMaxSpawnTime = TimeSpan.FromMinutes( 5.0 ); + + private static Hashtable m_Table = new Hashtable(); + + public static Hashtable Table{ get{ return m_Table; } } + + + // When a creature's AI is deactivated (PlayerRangeSensitive optimization) does it return home? + public bool ReturnOnDeactivate{ get{ return true; } } + + // Are creatures unlinked on taming (true) or should they also go out of the region (false)? + public bool UnlinkOnTaming{ get{ return false; } } + + // Are unlinked and untamed creatures removed after 20 hours? + public bool RemoveIfUntamed{ get{ return true; } } + + + public static readonly Direction InvalidDirection = Direction.Running; + + private int m_ID; + private BaseRegion m_Region; + private Point3D m_Home; + private int m_Range; + private Direction m_Direction; + private SpawnDefinition m_Definition; + private List m_SpawnedObjects; + private int m_Max; + private TimeSpan m_MinSpawnTime; + private TimeSpan m_MaxSpawnTime; + private bool m_Running; + + private DateTime m_NextSpawn; + private Timer m_SpawnTimer; + + public int ID{ get{ return m_ID; } } + public BaseRegion Region{ get{ return m_Region; } } + public Point3D HomeLocation{ get{ return m_Home; } } + public int HomeRange{ get{ return m_Range; } } + public Direction Direction{ get{ return m_Direction; } } + public SpawnDefinition Definition{ get{ return m_Definition; } } + public List SpawnedObjects{ get{ return m_SpawnedObjects; } } + public int Max{ get{ return m_Max; } } + public TimeSpan MinSpawnTime{ get{ return m_MinSpawnTime; } } + public TimeSpan MaxSpawnTime{ get{ return m_MaxSpawnTime; } } + public bool Running{ get{ return m_Running; } } + + public bool Complete{ get{ return m_SpawnedObjects.Count >= m_Max; } } + public bool Spawning{ get{ return m_Running && !this.Complete; } } + + public SpawnEntry( int id, BaseRegion region, Point3D home, int range, Direction direction, SpawnDefinition definition, int max, TimeSpan minSpawnTime, TimeSpan maxSpawnTime ) + { + m_ID = id; + m_Region = region; + m_Home = home; + m_Range = range; + m_Direction = direction; + m_Definition = definition; + m_SpawnedObjects = new List(); + m_Max = max; + m_MinSpawnTime = minSpawnTime; + m_MaxSpawnTime = maxSpawnTime; + m_Running = false; + + if ( m_Table.Contains( id ) ) + Console.WriteLine( "Warning: double SpawnEntry ID '{0}'", id ); + else + m_Table[id] = this; + } + + public Point3D RandomSpawnLocation( int spawnHeight, bool land, bool water ) + { + return m_Region.RandomSpawnLocation( spawnHeight, land, water, m_Home, m_Range ); + } + + public void Start() + { + if ( m_Running ) + return; + + m_Running = true; + CheckTimer(); + } + + public void Stop() + { + if ( !m_Running ) + return; + + m_Running = false; + CheckTimer(); + } + + private void Spawn() + { + ISpawnable spawn = m_Definition.Spawn(this); + + if ( spawn != null ) + Add( spawn ); + } + + private void Add( ISpawnable spawn ) + { + m_SpawnedObjects.Add( spawn ); + + spawn.Spawner = this; + + if ( spawn is BaseCreature ) + ((BaseCreature)spawn).RemoveIfUntamed = this.RemoveIfUntamed; + } + + void ISpawner.Remove( ISpawnable spawn ) + { + m_SpawnedObjects.Remove( spawn ); + + CheckTimer(); + } + + private TimeSpan RandomTime() + { + int min = (int) m_MinSpawnTime.TotalSeconds; + int max = (int) m_MaxSpawnTime.TotalSeconds; + + int rand = Utility.RandomMinMax( min, max ); + return TimeSpan.FromSeconds( rand ); + } + + private void CheckTimer() + { + if ( this.Spawning ) + { + if ( m_SpawnTimer == null ) + { + TimeSpan time = RandomTime(); + m_SpawnTimer = Timer.DelayCall( time, new TimerCallback( TimerCallback ) ); + m_NextSpawn = DateTime.Now + time; + } + } + else if ( m_SpawnTimer != null ) + { + m_SpawnTimer.Stop(); + m_SpawnTimer = null; + } + } + + private void TimerCallback() + { + int amount = Math.Max( (m_Max - m_SpawnedObjects.Count) / 3, 1 ); + + for ( int i = 0; i < amount; i++ ) + Spawn(); + + m_SpawnTimer = null; + CheckTimer(); + } + + public void DeleteSpawnedObjects() + { + InternalDeleteSpawnedObjects(); + + m_Running = false; + CheckTimer(); + } + + private void InternalDeleteSpawnedObjects() + { + foreach ( ISpawnable spawnable in m_SpawnedObjects ) + { + spawnable.Spawner = null; + + bool uncontrolled = !(spawnable is BaseCreature) || !((BaseCreature)spawnable).Controlled; + + if( uncontrolled ) + spawnable.Delete(); + } + + m_SpawnedObjects.Clear(); + } + + public void Respawn() + { + InternalDeleteSpawnedObjects(); + + for ( int i = 0; !this.Complete && i < m_Max; i++ ) + Spawn(); + + m_Running = true; + CheckTimer(); + } + + public void Delete() + { + m_Max = 0; + InternalDeleteSpawnedObjects(); + + if ( m_SpawnTimer != null ) + { + m_SpawnTimer.Stop(); + m_SpawnTimer = null; + } + + if ( m_Table[m_ID] == this ) + m_Table.Remove( m_ID ); + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (int) m_SpawnedObjects.Count ); + + for ( int i = 0; i < m_SpawnedObjects.Count; i++ ) + { + ISpawnable spawn = m_SpawnedObjects[i]; + + int serial = spawn.Serial; + + writer.Write( (int) serial ); + } + + writer.Write( (bool) m_Running ); + + if ( m_SpawnTimer != null ) + { + writer.Write( true ); + writer.WriteDeltaTime( (DateTime) m_NextSpawn ); + } + else + { + writer.Write( false ); + } + } + + public void Deserialize( GenericReader reader, int version ) + { + int count = reader.ReadInt(); + + for ( int i = 0; i < count; i++ ) + { + int serial = reader.ReadInt(); + ISpawnable spawnableEntity = World.FindEntity( serial ) as ISpawnable; + + if (spawnableEntity != null) + Add(spawnableEntity); + } + + m_Running = reader.ReadBool(); + + if ( reader.ReadBool() ) + { + m_NextSpawn = reader.ReadDeltaTime(); + + if ( this.Spawning ) + { + if ( m_SpawnTimer != null ) + m_SpawnTimer.Stop(); + + TimeSpan delay = m_NextSpawn - DateTime.Now; + m_SpawnTimer = Timer.DelayCall( delay > TimeSpan.Zero ? delay : TimeSpan.Zero, new TimerCallback( TimerCallback ) ); + } + } + + CheckTimer(); + } + + private static List m_RemoveList; + + public static void Remove( GenericReader reader, int version ) + { + int count = reader.ReadInt(); + + for ( int i = 0; i < count; i++ ) + { + int serial = reader.ReadInt(); + IEntity entity = World.FindEntity( serial ); + + if ( entity != null ) + { + if ( m_RemoveList == null ) + m_RemoveList = new List(); + + m_RemoveList.Add( entity ); + } + } + + reader.ReadBool(); // m_Running + + if ( reader.ReadBool() ) + reader.ReadDeltaTime(); // m_NextSpawn + } + + public static void Initialize() + { + if ( m_RemoveList != null ) + { + foreach ( IEntity ent in m_RemoveList ) + { + ent.Delete(); + } + + m_RemoveList = null; + } + + SpawnPersistence.EnsureExistence(); + + CommandSystem.Register( "RespawnAllRegions", AccessLevel.Administrator, new CommandEventHandler( RespawnAllRegions_OnCommand ) ); + CommandSystem.Register( "RespawnRegion", AccessLevel.GameMaster, new CommandEventHandler( RespawnRegion_OnCommand ) ); + CommandSystem.Register( "DelAllRegionSpawns", AccessLevel.Administrator, new CommandEventHandler( DelAllRegionSpawns_OnCommand ) ); + CommandSystem.Register( "DelRegionSpawns", AccessLevel.GameMaster, new CommandEventHandler( DelRegionSpawns_OnCommand ) ); + CommandSystem.Register( "StartAllRegionSpawns", AccessLevel.Administrator, new CommandEventHandler( StartAllRegionSpawns_OnCommand ) ); + CommandSystem.Register( "StartRegionSpawns", AccessLevel.GameMaster, new CommandEventHandler( StartRegionSpawns_OnCommand ) ); + CommandSystem.Register( "StopAllRegionSpawns", AccessLevel.Administrator, new CommandEventHandler( StopAllRegionSpawns_OnCommand ) ); + CommandSystem.Register( "StopRegionSpawns", AccessLevel.GameMaster, new CommandEventHandler( StopRegionSpawns_OnCommand ) ); + } + + private static BaseRegion GetCommandData( CommandEventArgs args ) + { + Mobile from = args.Mobile; + + Region reg; + if ( args.Length == 0 ) + { + reg = from.Region; + } + else + { + string name = args.GetString( 0 ); + //reg = (Region) from.Map.Regions[name]; + + if ( !from.Map.Regions.TryGetValue( name, out reg ) ) + { + from.SendMessage( "Could not find region '{0}'.", name ); + return null; + } + } + + BaseRegion br = reg as BaseRegion; + + if ( br == null || br.Spawns == null ) + { + from.SendMessage( "There are no spawners in region '{0}'.", reg ); + return null; + } + + return br; + } + + [Usage( "RespawnAllRegions" )] + [Description( "Respawns all regions and sets the spawners as running." )] + private static void RespawnAllRegions_OnCommand( CommandEventArgs args ) + { + foreach ( SpawnEntry entry in m_Table.Values ) + { + entry.Respawn(); + } + + args.Mobile.SendMessage( "All regions have respawned." ); + } + + [Usage( "RespawnRegion []" )] + [Description( "Respawns the region in which you are (or that you provided) and sets the spawners as running." )] + private static void RespawnRegion_OnCommand( CommandEventArgs args ) + { + BaseRegion region = GetCommandData( args ); + + if ( region == null ) + return; + + for ( int i = 0; i < region.Spawns.Length; i++ ) + region.Spawns[i].Respawn(); + + args.Mobile.SendMessage( "Region '{0}' has respawned.", region ); + } + + [Usage( "DelAllRegionSpawns" )] + [Description( "Deletes all spawned objects of every regions and sets the spawners as not running." )] + private static void DelAllRegionSpawns_OnCommand( CommandEventArgs args ) + { + foreach ( SpawnEntry entry in m_Table.Values ) + { + entry.DeleteSpawnedObjects(); + } + + args.Mobile.SendMessage( "All region spawned objects have been deleted." ); + } + + [Usage( "DelRegionSpawns []" )] + [Description( "Deletes all spawned objects of the region in which you are (or that you provided) and sets the spawners as not running." )] + private static void DelRegionSpawns_OnCommand( CommandEventArgs args ) + { + BaseRegion region = GetCommandData( args ); + + if ( region == null ) + return; + + for ( int i = 0; i < region.Spawns.Length; i++ ) + region.Spawns[i].DeleteSpawnedObjects(); + + args.Mobile.SendMessage( "Spawned objects of region '{0}' have been deleted.", region ); + } + + [Usage( "StartAllRegionSpawns" )] + [Description( "Sets the region spawners of all regions as running." )] + private static void StartAllRegionSpawns_OnCommand( CommandEventArgs args ) + { + foreach ( SpawnEntry entry in m_Table.Values ) + { + entry.Start(); + } + + args.Mobile.SendMessage( "All region spawners have started." ); + } + + [Usage( "StartRegionSpawns []" )] + [Description( "Sets the region spawners of the region in which you are (or that you provided) as running." )] + private static void StartRegionSpawns_OnCommand( CommandEventArgs args ) + { + BaseRegion region = GetCommandData( args ); + + if ( region == null ) + return; + + for ( int i = 0; i < region.Spawns.Length; i++ ) + region.Spawns[i].Start(); + + args.Mobile.SendMessage( "Spawners of region '{0}' have started.", region ); + } + + [Usage( "StopAllRegionSpawns" )] + [Description( "Sets the region spawners of all regions as not running." )] + private static void StopAllRegionSpawns_OnCommand( CommandEventArgs args ) + { + foreach ( SpawnEntry entry in m_Table.Values ) + { + entry.Stop(); + } + + args.Mobile.SendMessage( "All region spawners have stopped." ); + } + + [Usage( "StopRegionSpawns []" )] + [Description( "Sets the region spawners of the region in which you are (or that you provided) as not running." )] + private static void StopRegionSpawns_OnCommand( CommandEventArgs args ) + { + BaseRegion region = GetCommandData( args ); + + if ( region == null ) + return; + + for ( int i = 0; i < region.Spawns.Length; i++ ) + region.Spawns[i].Stop(); + + args.Mobile.SendMessage( "Spawners of region '{0}' have stopped.", region ); + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/Spawning/SpawnPersistence.cs b/Scripts/Regions/Spawning/SpawnPersistence.cs new file mode 100644 index 0000000..3946890 --- /dev/null +++ b/Scripts/Regions/Spawning/SpawnPersistence.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections; +using Server; + +namespace Server.Regions +{ + public class SpawnPersistence : Item + { + private static SpawnPersistence m_Instance; + + public SpawnPersistence Instance{ get{ return m_Instance; } } + + public static void EnsureExistence() + { + if ( m_Instance == null ) + m_Instance = new SpawnPersistence(); + } + + public override string DefaultName + { + get { return "Region spawn persistence - Internal"; } + } + + private SpawnPersistence() : base( 1 ) + { + Movable = false; + } + + public SpawnPersistence( Serial serial ) : base( serial ) + { + m_Instance = this; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( (int) SpawnEntry.Table.Values.Count ); + foreach ( SpawnEntry entry in SpawnEntry.Table.Values ) + { + writer.Write( (int) entry.ID ); + + entry.Serialize( writer ); + } + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + int count = reader.ReadInt(); + for ( int i = 0; i < count; i++ ) + { + int id = reader.ReadInt(); + + SpawnEntry entry = (SpawnEntry) SpawnEntry.Table[id]; + + if ( entry != null ) + entry.Deserialize( reader, version ); + else + SpawnEntry.Remove( reader, version ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Regions/TownRegion.cs b/Scripts/Regions/TownRegion.cs new file mode 100644 index 0000000..0752aeb --- /dev/null +++ b/Scripts/Regions/TownRegion.cs @@ -0,0 +1,13 @@ +using System; +using System.Xml; +using Server; + +namespace Server.Regions +{ + public class TownRegion : GuardedRegion + { + public TownRegion( XmlElement xml, Map map, Region parent ) : base( xml, map, parent ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Scripts.csproj b/Scripts/Scripts.csproj new file mode 100644 index 0000000..f1f34ea --- /dev/null +++ b/Scripts/Scripts.csproj @@ -0,0 +1,4124 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03} + Exe + Properties + Scripts + Scripts + v4.0 + + + 512 + SAK + SAK + SAK + SAK + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {4DD64307-F1D5-43B8-BF40-E27C9A36829D} + Server + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Scripts/Skills/Anatomy.cs b/Scripts/Skills/Anatomy.cs new file mode 100644 index 0000000..420b3d6 --- /dev/null +++ b/Scripts/Skills/Anatomy.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public class Anatomy + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Anatomy].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.Target = new Anatomy.InternalTarget(); + + m.SendMessage( "Qui voulez-vous examiner?" ); // Whom shall I examine? + + return TimeSpan.FromSeconds( 1.0 ); + } + + private class InternalTarget : Target + { + public InternalTarget() : base ( 8, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( from == targeted ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous vous connaissez suffisamment ainsi..." ); // You know yourself quite well enough already. + } + else if ( targeted is TownCrier ) + { + ((TownCrier)targeted).PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cette personne parait bien portante. Peut-�tre m�me a-t-elle des nouvelles pour vous?", from.NetState ); // This person looks fine to me, though he may have some news... + } + else if ( targeted is BaseVendor && ((BaseVendor)targeted).IsInvulnerable ) + { + ((BaseVendor)targeted).PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cette personne semble trop occup�e pour �tre examin�e", from.NetState ); // That can not be inspected. + } + else if ( targeted is Mobile ) + { + Mobile targ = (Mobile)targeted; + + int marginOfError = Math.Max( 0, 25 - (int)(from.Skills[SkillName.Anatomy].Value / 4) ); + + int str = targ.Str + Utility.RandomMinMax( -marginOfError, +marginOfError ); + int dex = targ.Dex + Utility.RandomMinMax( -marginOfError, +marginOfError ); + int stm = ((targ.Stam * 100) / Math.Max( targ.StamMax, 1 )) + Utility.RandomMinMax( -marginOfError, +marginOfError ); + + int strMod = str / 10; + int dexMod = dex / 10; + int stmMod = stm / 10; + + if ( strMod < 0 ) strMod = 0; + else if ( strMod > 10 ) strMod = 10; + + if ( dexMod < 0 ) dexMod = 0; + else if ( dexMod > 10 ) dexMod = 10; + + if ( stmMod > 10 ) stmMod = 10; + else if ( stmMod < 0 ) stmMod = 0; + + if ( from.CheckTargetSkill( SkillName.Anatomy, targ, 0, 100 ) ) + { + targ.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1038045 + (strMod * 11) + dexMod, from.NetState ); // That looks [strong] and [dexterous]. + + if ( from.Skills[SkillName.Anatomy].Base >= 65.0 ) + targ.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1038303 + stmMod, from.NetState ); // That being is at [10,20,...] percent endurance. + } + else + { + targ.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous ne parvenez pas poser un diagnostic complet", from.NetState ); // You can not quite get a sense of their physical characteristics. + } + } + else if ( targeted is Item ) + { + from.SendMessage( "Seuls les �tres vivants ont une anatomie!"); // Only living things have anatomies! + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/AnimalLore.cs b/Scripts/Skills/AnimalLore.cs new file mode 100644 index 0000000..1b21bb0 --- /dev/null +++ b/Scripts/Skills/AnimalLore.cs @@ -0,0 +1,386 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public class AnimalLore + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.AnimalLore].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendMessage( "Quel animal voulez-vous examiner?" ); // What animal should I look at? + + return TimeSpan.FromSeconds( 1.0 ); + } + + private class InternalTarget : Target + { + public InternalTarget() : base( 8, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( !from.Alive ) + { + from.SendMessage( "Les esprits des morts ne font pas partie de votre champ de comp�tence..." ); // The spirits of the dead are not the province of animal lore. + } + else if ( targeted is BaseCreature ) + { + BaseCreature c = (BaseCreature)targeted; + + if ( !c.IsDeadPet ) + { + if ( c.Body.IsAnimal || c.Body.IsMonster || c.Body.IsSea ) + { + if (!c.Controlled && from.Skills[SkillName.AnimalLore].Value < 100.0) + { + from.SendMessage("Vu votre exp�rience, vous ne pouvez approcher que les cr�atures apprivois�es"); // At your skill level, you can only lore tamed creatures. + } + else if (!c.Controlled && !c.Tamable && from.Skills[SkillName.AnimalLore].Value < 110.0) + { + from.SendMessage( "Vu votre exp�rience, seules les cr�atures qui peuvent �tre apprivois�es et les domestiqu�es vous laisseront les approcher" ); // At your skill level, you can only lore tamed or tameable creatures. + } + else if ( !from.CheckTargetSkill( SkillName.AnimalLore, c, 0.0, 120.0 ) ) + { + from.SendMessage( "Vous ne d�cernez rien d'utile" ); // You can't think of anything you know offhand. + } + else + { + from.CloseGump( typeof( AnimalLoreGump ) ); + from.SendGump( new AnimalLoreGump( c ) ); + } + } + else + { + from.SendMessage( "Ceci n'est pas un animal!" ); // That's not an animal! + } + } + else + { + from.SendMessage("Les esprits des morts ne font pas partie de votre champ de comp�tence..."); // The spirits of the dead are not the province of animal lore. + } + } + else + { + from.SendMessage( "Ceci n'est pas un animal!" ); // That's not an animal! + } + } + } + } + + public class AnimalLoreGump : Gump + { + private static string FormatSkill( BaseCreature c, SkillName name ) + { + Skill skill = c.Skills[name]; + + if ( skill.Base < 10.0 ) + return "
---
"; + + return String.Format( "
{0:F1}
", skill.Value ); + } + + private static string FormatAttributes( int cur, int max ) + { + if ( max == 0 ) + return "
---
"; + + return String.Format( "
{0}/{1}
", cur, max ); + } + + private static string FormatStat( int val ) + { + if ( val == 0 ) + return "
---
"; + + return String.Format( "
{0}
", val ); + } + + private static string FormatDouble( double val ) + { + if ( val == 0 ) + return "
---
"; + + return String.Format( "
{0:F1}
", val ); + } + + private static string FormatElement( int val ) + { + if ( val <= 0 ) + return "
---
"; + + return String.Format( "
{0}%
", val ); + } + + #region Mondain's Legacy + private static string FormatDamage( int min, int max ) + { + if ( min <= 0 || max <= 0 ) + return "
---
"; + + return String.Format( "
{0}-{1}
", min, max ); + } + #endregion + + private const int LabelColor = 0x24E5; + + public AnimalLoreGump( BaseCreature c ) : base( 250, 50 ) + { + AddPage( 0 ); + + AddImage( 100, 100, 2080 ); + AddImage( 118, 137, 2081 ); + AddImage( 118, 207, 2081 ); + AddImage( 118, 277, 2081 ); + AddImage( 118, 347, 2083 ); + + AddHtml( 147, 108, 210, 18, String.Format( "
{0}
", c.Name ), false, false ); + + AddButton( 240, 77, 2093, 2093, 2, GumpButtonType.Reply, 0 ); + + AddImage( 140, 138, 2091 ); + AddImage( 140, 335, 2091 ); + + int pages = ( Core.AOS ? 5 : 3 ); + int page = 0; + + + #region Attributes + AddPage( ++page ); + + AddImage( 128, 152, 2086 ); + AddHtmlLocalized( 147, 150, 160, 18, 1049593, 200, false, false ); // Attributes + + AddHtmlLocalized( 153, 168, 160, 18, 1049578, LabelColor, false, false ); // Hits + AddHtml( 280, 168, 75, 18, FormatAttributes( c.Hits, c.HitsMax ), false, false ); + + AddHtmlLocalized( 153, 186, 160, 18, 1049579, LabelColor, false, false ); // Stamina + AddHtml( 280, 186, 75, 18, FormatAttributes( c.Stam, c.StamMax ), false, false ); + + AddHtmlLocalized( 153, 204, 160, 18, 1049580, LabelColor, false, false ); // Mana + AddHtml( 280, 204, 75, 18, FormatAttributes( c.Mana, c.ManaMax ), false, false ); + + AddHtmlLocalized( 153, 222, 160, 18, 1028335, LabelColor, false, false ); // Strength + AddHtml( 320, 222, 35, 18, FormatStat( c.Str ), false, false ); + + AddHtmlLocalized( 153, 240, 160, 18, 3000113, LabelColor, false, false ); // Dexterity + AddHtml( 320, 240, 35, 18, FormatStat( c.Dex ), false, false ); + + AddHtmlLocalized( 153, 258, 160, 18, 3000112, LabelColor, false, false ); // Intelligence + AddHtml( 320, 258, 35, 18, FormatStat( c.Int ), false, false ); + + if ( Core.AOS ) + { + int y = 276; + + if ( Core.SE ) + { + double bd = Items.BaseInstrument.GetBaseDifficulty( c ); + if ( c.Uncalmable ) + bd = 0; + + AddHtmlLocalized( 153, 276, 160, 18, 1070793, LabelColor, false, false ); // Barding Difficulty + AddHtml( 320, y, 35, 18, FormatDouble( bd ), false, false ); + + y += 18; + } + + AddImage( 128, y + 2, 2086 ); + AddHtmlLocalized( 147, y, 160, 18, 1049594, 200, false, false ); // Loyalty Rating + y += 18; + + AddHtmlLocalized( 153, y, 160, 18, (!c.Controlled || c.Loyalty == 0) ? 1061643 : 1049595 + (c.Loyalty / 10), LabelColor, false, false ); + } + else + { + AddImage( 128, 278, 2086 ); + AddHtmlLocalized( 147, 276, 160, 18, 3001016, 200, false, false ); // Miscellaneous + + AddHtmlLocalized( 153, 294, 160, 18, 1049581, LabelColor, false, false ); // Armor Rating + AddHtml( 320, 294, 35, 18, FormatStat( c.VirtualArmor ), false, false ); + } + + AddButton( 340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1 ); + AddButton( 317, 358, 5603, 5607, 0, GumpButtonType.Page, pages ); + #endregion + + #region Resistances + if ( Core.AOS ) + { + AddPage( ++page ); + + AddImage( 128, 152, 2086 ); + AddHtmlLocalized( 147, 150, 160, 18, 1061645, 200, false, false ); // Resistances + + AddHtmlLocalized( 153, 168, 160, 18, 1061646, LabelColor, false, false ); // Physical + AddHtml( 320, 168, 35, 18, FormatElement( c.PhysicalResistance ), false, false ); + + AddHtmlLocalized( 153, 186, 160, 18, 1061647, LabelColor, false, false ); // Fire + AddHtml( 320, 186, 35, 18, FormatElement( c.FireResistance ), false, false ); + + AddHtmlLocalized( 153, 204, 160, 18, 1061648, LabelColor, false, false ); // Cold + AddHtml( 320, 204, 35, 18, FormatElement( c.ColdResistance ), false, false ); + + AddHtmlLocalized( 153, 222, 160, 18, 1061649, LabelColor, false, false ); // Poison + AddHtml( 320, 222, 35, 18, FormatElement( c.PoisonResistance ), false, false ); + + AddHtmlLocalized( 153, 240, 160, 18, 1061650, LabelColor, false, false ); // Energy + AddHtml( 320, 240, 35, 18, FormatElement( c.EnergyResistance ), false, false ); + + AddButton( 340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1 ); + AddButton( 317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1 ); + } + #endregion + + #region Damage + if ( Core.AOS ) + { + AddPage( ++page ); + + AddImage( 128, 152, 2086 ); + AddHtmlLocalized( 147, 150, 160, 18, 1017319, 200, false, false ); // Damage + + AddHtmlLocalized( 153, 168, 160, 18, 1061646, LabelColor, false, false ); // Physical + AddHtml( 320, 168, 35, 18, FormatElement( c.PhysicalDamage ), false, false ); + + AddHtmlLocalized( 153, 186, 160, 18, 1061647, LabelColor, false, false ); // Fire + AddHtml( 320, 186, 35, 18, FormatElement( c.FireDamage ), false, false ); + + AddHtmlLocalized( 153, 204, 160, 18, 1061648, LabelColor, false, false ); // Cold + AddHtml( 320, 204, 35, 18, FormatElement( c.ColdDamage ), false, false ); + + AddHtmlLocalized( 153, 222, 160, 18, 1061649, LabelColor, false, false ); // Poison + AddHtml( 320, 222, 35, 18, FormatElement( c.PoisonDamage ), false, false ); + + AddHtmlLocalized( 153, 240, 160, 18, 1061650, LabelColor, false, false ); // Energy + AddHtml( 320, 240, 35, 18, FormatElement( c.EnergyDamage ), false, false ); + + #region Mondain's Legacy + if ( Core.ML ) + { + AddHtmlLocalized( 153, 258, 160, 18, 1076750, LabelColor, false, false ); // Base Damage + AddHtml( 300, 258, 55, 18, FormatDamage( c.DamageMin, c.DamageMax ), false, false ); + } + #endregion + + AddButton( 340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1 ); + AddButton( 317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1 ); + } + #endregion + + #region Skills + AddPage( ++page ); + + AddImage( 128, 152, 2086 ); + AddHtmlLocalized( 147, 150, 160, 18, 3001030, 200, false, false ); // Combat Ratings + + AddHtmlLocalized( 153, 168, 160, 18, 1044103, LabelColor, false, false ); // Wrestling + AddHtml( 320, 168, 35, 18, FormatSkill( c, SkillName.Wrestling ), false, false ); + + AddHtmlLocalized( 153, 186, 160, 18, 1044087, LabelColor, false, false ); // Tactics + AddHtml( 320, 186, 35, 18, FormatSkill( c, SkillName.Tactics ), false, false ); + + AddHtmlLocalized( 153, 204, 160, 18, 1044086, LabelColor, false, false ); // Magic Resistance + AddHtml( 320, 204, 35, 18, FormatSkill( c, SkillName.MagicResist ), false, false ); + + AddHtmlLocalized( 153, 222, 160, 18, 1044061, LabelColor, false, false ); // Anatomy + AddHtml( 320, 222, 35, 18, FormatSkill( c, SkillName.Anatomy ), false, false ); + + #region Mondain's Legacy + if ( c is CuSidhe ) + { + AddHtmlLocalized( 153, 240, 160, 18, 1044077, LabelColor, false, false ); // Healing + AddHtml( 320, 240, 35, 18, FormatSkill( c, SkillName.Healing ), false, false ); + } + else + { + AddHtmlLocalized( 153, 240, 160, 18, 1044090, LabelColor, false, false ); // Poisoning + AddHtml( 320, 240, 35, 18, FormatSkill( c, SkillName.Poisoning ), false, false ); + } + #endregion + + AddImage( 128, 260, 2086 ); + AddHtmlLocalized( 147, 258, 160, 18, 3001032, 200, false, false ); // Lore & Knowledge + + AddHtmlLocalized( 153, 276, 160, 18, 1044085, LabelColor, false, false ); // Magery + AddHtml( 320, 276, 35, 18, FormatSkill( c, SkillName.Magery ), false, false ); + + AddHtmlLocalized( 153, 294, 160, 18, 1044076, LabelColor, false, false ); // Evaluating Intelligence + AddHtml( 320, 294, 35, 18,FormatSkill( c, SkillName.EvalInt ), false, false ); + + AddHtmlLocalized( 153, 312, 160, 18, 1044106, LabelColor, false, false ); // Meditation + AddHtml( 320, 312, 35, 18, FormatSkill( c, SkillName.Meditation ), false, false ); + + AddButton( 340, 358, 5601, 5605, 0, GumpButtonType.Page, page + 1 ); + AddButton( 317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1 ); + #endregion + + #region Misc + AddPage( ++page ); + + AddImage( 128, 152, 2086 ); + AddHtmlLocalized( 147, 150, 160, 18, 1049563, 200, false, false ); // Preferred Foods + + int foodPref = 3000340; + + if ( (c.FavoriteFood & FoodType.FruitsAndVegies) != 0 ) + foodPref = 1049565; // Fruits and Vegetables + else if ( (c.FavoriteFood & FoodType.GrainsAndHay) != 0 ) + foodPref = 1049566; // Grains and Hay + else if ( (c.FavoriteFood & FoodType.Fish) != 0 ) + foodPref = 1049568; // Fish + else if ( (c.FavoriteFood & FoodType.Meat) != 0 ) + foodPref = 1049564; // Meat + else if ( (c.FavoriteFood & FoodType.Eggs) != 0 ) + foodPref = 1044477; // Eggs + + AddHtmlLocalized( 153, 168, 160, 18, foodPref, LabelColor, false, false ); + + AddImage( 128, 188, 2086 ); + AddHtmlLocalized( 147, 186, 160, 18, 1049569, 200, false, false ); // Pack Instincts + + int packInstinct = 3000340; + + if ( (c.PackInstinct & PackInstinct.Canine) != 0 ) + packInstinct = 1049570; // Canine + else if ( (c.PackInstinct & PackInstinct.Ostard) != 0 ) + packInstinct = 1049571; // Ostard + else if ( (c.PackInstinct & PackInstinct.Feline) != 0 ) + packInstinct = 1049572; // Feline + else if ( (c.PackInstinct & PackInstinct.Arachnid) != 0 ) + packInstinct = 1049573; // Arachnid + else if ( (c.PackInstinct & PackInstinct.Daemon) != 0 ) + packInstinct = 1049574; // Daemon + else if ( (c.PackInstinct & PackInstinct.Bear) != 0 ) + packInstinct = 1049575; // Bear + else if ( (c.PackInstinct & PackInstinct.Equine) != 0 ) + packInstinct = 1049576; // Equine + else if ( (c.PackInstinct & PackInstinct.Bull) != 0 ) + packInstinct = 1049577; // Bull + + AddHtmlLocalized( 153, 204, 160, 18, packInstinct, LabelColor, false, false ); + + if ( !Core.AOS ) + { + AddImage( 128, 224, 2086 ); + AddHtmlLocalized( 147, 222, 160, 18, 1049594, 200, false, false ); // Loyalty Rating + + AddHtmlLocalized( 153, 240, 160, 18, (!c.Controlled || c.Loyalty == 0) ? 1061643 : 1049595 + (c.Loyalty / 10), LabelColor, false, false ); + } + + AddButton( 340, 358, 5601, 5605, 0, GumpButtonType.Page, 1 ); + AddButton( 317, 358, 5603, 5607, 0, GumpButtonType.Page, page - 1 ); + #endregion + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/AnimalTaming.cs b/Scripts/Skills/AnimalTaming.cs new file mode 100644 index 0000000..282528a --- /dev/null +++ b/Scripts/Skills/AnimalTaming.cs @@ -0,0 +1,413 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Factions; +using Server.Spells; +using Server.Spells.Spellweaving; + +namespace Server.SkillHandlers +{ + public class AnimalTaming + { + private static Hashtable m_BeingTamed = new Hashtable(); + + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.AnimalTaming].Callback = new SkillUseCallback( OnUse ); + } + + private static bool m_DisableMessage; + + public static bool DisableMessage + { + get{ return m_DisableMessage; } + set{ m_DisableMessage = value; } + } + + public static TimeSpan OnUse( Mobile m ) + { + m.RevealingAction(); + + m.Target = new InternalTarget(); + m.RevealingAction(); + + if ( !m_DisableMessage ) + m.SendMessage( "Quel animal voulez-vous apprivoiser?" ); // Tame which animal? + + return TimeSpan.FromHours( 6.0 ); + } + + public static bool CheckMastery( Mobile tamer, BaseCreature creature ) + { + BaseCreature familiar = (BaseCreature)Spells.Necromancy.SummonFamiliarSpell.Table[tamer]; + + if ( familiar != null && !familiar.Deleted && familiar is DarkWolfFamiliar ) + { + if ( creature is DireWolf || creature is GreyWolf || creature is TimberWolf || creature is WhiteWolf || creature is BakeKitsune ) + return true; + } + + return false; + } + + public static bool MustBeSubdued( BaseCreature bc ) + { + if (bc.Owners.Count > 0) { return false; } //Checks to see if the animal has been tamed before + return bc.SubdueBeforeTame && (bc.Hits > (bc.HitsMax / 10)); + } + + public static void ScaleStats( BaseCreature bc, double scalar ) + { + if ( bc.RawStr > 0 ) + bc.RawStr = (int)Math.Max( 1, bc.RawStr * scalar ); + + if ( bc.RawDex > 0 ) + bc.RawDex = (int)Math.Max( 1, bc.RawDex * scalar ); + + if ( bc.RawInt > 0 ) + bc.RawInt = (int)Math.Max( 1, bc.RawInt * scalar ); + + if ( bc.HitsMaxSeed > 0 ) + { + bc.HitsMaxSeed = (int)Math.Max( 1, bc.HitsMaxSeed * scalar ); + bc.Hits = bc.Hits; + } + + if ( bc.StamMaxSeed > 0 ) + { + bc.StamMaxSeed = (int)Math.Max( 1, bc.StamMaxSeed * scalar ); + bc.Stam = bc.Stam; + } + } + + public static void ScaleSkills( BaseCreature bc, double scalar ) + { + ScaleSkills( bc, scalar, scalar ); + } + + public static void ScaleSkills( BaseCreature bc, double scalar, double capScalar ) + { + for ( int i = 0; i < bc.Skills.Length; ++i ) + { + bc.Skills[i].Base *= scalar; + + bc.Skills[i].Cap = Math.Max( 100.0, bc.Skills[i].Cap * capScalar ); + + if ( bc.Skills[i].Base > bc.Skills[i].Cap ) + { + bc.Skills[i].Cap = bc.Skills[i].Base; + } + } + } + + private class InternalTarget : Target + { + private bool m_SetSkillTime = true; + + public InternalTarget() : base(Core.AOS ? 3 : 2, false, TargetFlags.None) + { + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_SetSkillTime ) + from.NextSkillTime = DateTime.Now; + } + + public virtual void ResetPacify(object obj) + { + if (obj is BaseCreature) + { + ((BaseCreature)obj).BardPacified = true; + } + } + + protected override void OnTarget( Mobile from, object targeted ) + { + from.RevealingAction(); + + if ( targeted is Mobile ) + { + if ( targeted is BaseCreature ) + { + BaseCreature creature = (BaseCreature)targeted; + + if ( !creature.Tamable ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cette cr�ature ne peut �tre apprivois�e", from.NetState ); // That creature cannot be tamed. + } + else if ( creature.Controlled ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cet animal a d�j� un ma�tre", from.NetState ); // That animal looks tame already. + } + else if ( from.Female && !creature.AllowFemaleTamer ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Seul un homme peut approcher cette cr�ature", from.NetState ); // That creature can only be tamed by males. + } + else if ( !from.Female && !creature.AllowMaleTamer ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Seule une femme peut approcher cette cr�ature", from.NetState ); // That creature can only be tamed by females. + } + else if ( creature is CuSidhe && from.Race != Race.Elf ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous ne pouvez apprivoiser cela!", from.NetState ); // You can't tame that! + } + else if ( from.Followers + creature.ControlSlots > from.FollowersMax ) + { + from.SendMessage( "Vous avez trop d'animaux domestiques pour en apprivoiser un nouveau" ); // You have too many followers to tame that creature. + } + else if ( creature.Owners.Count >= BaseCreature.MaxOwners && !creature.Owners.Contains( from ) ) + { + creature.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Cet animal a eu suffisamment de ma�tre dans le pass� et souhaite qu'on le laisse tranquille", from.NetState); // This animal has had too many owners and is too upset for you to tame. + } + else if ( MustBeSubdued( creature ) ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous devez assujetir cette cr�ature avant de l'apprivoiser", from.NetState ); // You must subdue this creature before you can tame it! + } + else if ( CheckMastery( from, creature ) || from.Skills[SkillName.AnimalTaming].Value >= creature.MinTameSkill ) + { + FactionWarHorse warHorse = creature as FactionWarHorse; + + if ( warHorse != null ) + { + Faction faction = Faction.Find( from ); + + if ( faction == null || faction != warHorse.Faction ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous ne pouvez apprivoiser cette cr�ature", from.NetState ); // You cannot tame this creature. + return; + } + } + + if ( m_BeingTamed.Contains( targeted ) ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Quelqu'un tente d�j� de l'apprivoiser", from.NetState ); // Someone else is already taming this. + } + else if ( creature.CanAngerOnTame && 0.95 >= Utility.RandomDouble() ) + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous irritez la cr�ature!", from.NetState ); // You seem to anger the beast! + creature.PlaySound( creature.GetAngerSound() ); + creature.Direction = creature.GetDirectionTo( from ); + if (creature.BardPacified && Utility.RandomDouble() > .24) + { + Timer.DelayCall(TimeSpan.FromSeconds(2.0), new TimerStateCallback(ResetPacify), creature); + } + else + { + creature.BardEndTime = DateTime.Now; + } + + creature.BardPacified = false; + + if (creature.AIObject != null) + creature.AIObject.DoMove(creature.Direction); + + + if ( from is PlayerMobile && !(( (PlayerMobile)from ).HonorActive || TransformationSpellHelper.UnderTransformation( from, typeof( EtherealVoyageSpell )))) + creature.Combatant = from; + } + else + { + m_BeingTamed[targeted] = from; + + from.LocalOverheadMessage( MessageType.Emote, 0x59, false, "Vous tentez d'apprivoiser la cr�ature" ); // You start to tame the creature. + from.NonlocalOverheadMessage( MessageType.Emote, 0x59, false, "*tente d'apprivoiser une cr�ature*" ); // *begins taming a creature.* + + new InternalTimer( from, creature, Utility.Random( 3, 2 ) ).Start(); + + m_SetSkillTime = false; + } + } + else + { + creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous n'avez aucune chance d'apprivoiser cette cr�ature", from.NetState ); // You have no chance of taming this creature. + } + } + else + { + ((Mobile)targeted).PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cela ne peut �tre apprivois�", from.NetState ); // That being cannot be tamed. + } + } + else + { + from.SendMessage( "Vous ne pouvez apprivoiser cela!" ); // You can't tame that! + } + } + + private class InternalTimer : Timer + { + private Mobile m_Tamer; + private BaseCreature m_Creature; + private int m_MaxCount; + private int m_Count; + private bool m_Paralyzed; + private DateTime m_StartTime; + + public InternalTimer( Mobile tamer, BaseCreature creature, int count ) : base( TimeSpan.FromSeconds( 3.0 ), TimeSpan.FromSeconds( 3.0 ), count ) + { + m_Tamer = tamer; + m_Creature = creature; + m_MaxCount = count; + m_Paralyzed = creature.Paralyzed; + m_StartTime = DateTime.Now; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + m_Count++; + + DamageEntry de = m_Creature.FindMostRecentDamageEntry( false ); + bool alreadyOwned = m_Creature.Owners.Contains( m_Tamer ); + + if (!m_Tamer.InRange(m_Creature, Core.AOS ? 7 : 6)) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous vous �tes trop �loign� pour continuer de l'apprivoiser", m_Tamer.NetState ); // You are too far away to continue taming. + Stop(); + } + else if ( !m_Tamer.CheckAlive() ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous �tes morts et ne pouvez donc continuer de l'apprivoiser", m_Tamer.NetState ); // You are dead, and cannot continue taming. + Stop(); + } + else if ( !m_Tamer.CanSee( m_Creature ) || !m_Tamer.InLOS( m_Creature ) || !CanPath() ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Tamer.SendMessage("Vous n'arrivez pas � suivre l'animal et devez donc cesser de l'apprivoiser"); // You do not have a clear path to the animal you are taming, and must cease your attempt. + Stop(); + } + else if ( !m_Creature.Tamable ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cette cr�ature ne peut �tre apprivois�e", m_Tamer.NetState ); // That creature cannot be tamed. + Stop(); + } + else if ( m_Creature.Controlled ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cet animal a d�j� un ma�tre", m_Tamer.NetState ); // That animal looks tame already. + Stop(); + } + else if ( m_Creature.Owners.Count >= BaseCreature.MaxOwners && !m_Creature.Owners.Contains( m_Tamer ) ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cet animal a eu suffisamment de ma�tre dans le pass� et souhaite qu'on le laisse tranquille", m_Tamer.NetState ); // This animal has had too many owners and is too upset for you to tame. + Stop(); + } + else if ( MustBeSubdued( m_Creature ) ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Vous devez assujetir cette cr�ature avant de l'apprivoiser", m_Tamer.NetState ); // You must subdue this creature before you can tame it! + Stop(); + } + else if ( de != null && de.LastDamage > m_StartTime ) + { + m_BeingTamed.Remove( m_Creature ); + m_Tamer.NextSkillTime = DateTime.Now; + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cet animal est trop irrit� pour �tre apprivois�", m_Tamer.NetState ); // The animal is too angry to continue taming. + Stop(); + } + else if ( m_Count < m_MaxCount ) + { + m_Tamer.RevealingAction(); + + switch ( Utility.Random( 3 ) ) + { + case 0: m_Tamer.PublicOverheadMessage( MessageType.Regular, 0x3B2, Utility.Random( 502790, 4 ) ); break; + case 1: m_Tamer.PublicOverheadMessage( MessageType.Regular, 0x3B2, Utility.Random( 1005608, 6 ) ); break; + case 2: m_Tamer.PublicOverheadMessage( MessageType.Regular, 0x3B2, Utility.Random( 1010593, 4 ) ); break; + } + + if ( !alreadyOwned ) // Passively check animal lore for gain + m_Tamer.CheckTargetSkill( SkillName.AnimalLore, m_Creature, 0.0, 120.0 ); + + if ( m_Creature.Paralyzed ) + m_Paralyzed = true; + } + else + { + m_Tamer.RevealingAction(); + m_Tamer.NextSkillTime = DateTime.Now; + m_BeingTamed.Remove( m_Creature ); + + if ( m_Creature.Paralyzed ) + m_Paralyzed = true; + + if ( !alreadyOwned ) // Passively check animal lore for gain + m_Tamer.CheckTargetSkill( SkillName.AnimalLore, m_Creature, 0.0, 120.0 ); + + double minSkill = m_Creature.MinTameSkill + (m_Creature.Owners.Count * 6.0); + + if ( minSkill > -24.9 && CheckMastery( m_Tamer, m_Creature ) ) + minSkill = -24.9; // 50% at 0.0? + + minSkill += 24.9; + + if ( CheckMastery( m_Tamer, m_Creature ) || alreadyOwned || m_Tamer.CheckTargetSkill( SkillName.AnimalTaming, m_Creature, minSkill - 25.0, minSkill + 25.0 ) ) + { + if ( m_Creature.Owners.Count == 0 ) // First tame + { + if ( m_Creature is GreaterDragon ) + { + ScaleSkills( m_Creature, 0.72, 0.90 ); // 72% of original skills trainable to 90% + m_Creature.Skills[SkillName.Magery].Base = m_Creature.Skills[SkillName.Magery].Cap; // Greater dragons have a 90% cap reduction and 90% skill reduction on magery + } + else if ( m_Paralyzed ) + ScaleSkills( m_Creature, 0.86 ); // 86% of original skills if they were paralyzed during the taming + else + ScaleSkills( m_Creature, 0.90 ); // 90% of original skills + + if ( m_Creature.StatLossAfterTame ) + ScaleStats( m_Creature, 0.50 ); + } + + if ( alreadyOwned ) + { + m_Tamer.SendMessage( "L'animal vient instinctivement pr�s de vous" ); // That wasn't even challenging. + } + else + { + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Il semble vous accepter comme ma�tre", m_Tamer.NetState ); // It seems to accept you as master. + m_Creature.Owners.Add( m_Tamer ); + } + + m_Creature.SetControlMaster( m_Tamer ); + m_Creature.IsBonded = false; + } + else + { + m_Creature.PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "L'animal refuse de vous laisser approcher", m_Tamer.NetState ); // You fail to tame the creature. + } + } + } + + private bool CanPath() + { + IPoint3D p = m_Tamer as IPoint3D; + + if ( p == null ) + return false; + + if( m_Creature.InRange( new Point3D( p ), 1 ) ) + return true; + + MovementPath path = new MovementPath( m_Creature, new Point3D( p ) ); + + return path.Success; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/ArmsLore.cs b/Scripts/Skills/ArmsLore.cs new file mode 100644 index 0000000..9c1f546 --- /dev/null +++ b/Scripts/Skills/ArmsLore.cs @@ -0,0 +1,212 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public class ArmsLore + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.ArmsLore].Callback = new SkillUseCallback(OnUse); + } + + public static TimeSpan OnUse(Mobile m) + { + m.Target = new InternalTarget(); + + m.SendMessage("Quel objet souhaitez-vous faire �valuer?"); // What item do you wish to get information about? + + return TimeSpan.FromSeconds(1.0); + } + + [PlayerVendorTarget] + private class InternalTarget : Target + { + public InternalTarget() + : base(2, false, TargetFlags.None) + { + AllowNonlocal = true; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BaseWeapon || targeted is BaseArmor || targeted is BaseJewel) + { + if (from.CheckTargetSkill(SkillName.ArmsLore, targeted, 0, 100)) + { + string texttype = "Inconnu", textquality = "Inconnue", textresource = "Inconnue", textdurability = "Inconnue"; + + if (targeted is BaseWeapon) + { + BaseWeapon arm = (BaseWeapon)targeted; + + double durability = 0; + + if (arm.MaxHitPoints != 0) + durability = arm.HitPoints / (double)arm.MaxHitPoints; + + switch (arm.Type) + { + case WeaponType.Axe: texttype = "Hache"; break; + case WeaponType.Bashing: texttype = "Arme contondante"; break; + case WeaponType.Fists: texttype = "Arme de pugilat"; break; + case WeaponType.Piercing: texttype = "Arme d'estoc"; break; + case WeaponType.Polearm: texttype = "Arme � longue port�e"; break; + case WeaponType.Ranged: texttype = "Arme de jet"; break; + case WeaponType.Slashing: texttype = "Arme � tranchant"; break; + case WeaponType.Staff: texttype = "Baton"; break; + default: texttype = "Arme"; break; + } + + if (from.Skills[SkillName.ArmsLore].Value > 20) + { + if (arm.Quality == WeaponQuality.Low) + textquality = "Mauvaise"; + else if (arm.Quality == WeaponQuality.Exceptional) + textquality = "Excellente"; + else + textquality = "Commune"; + } + + if (from.Skills[SkillName.Mining].Value > 30 && arm.Resource != CraftResource.None) + textresource = string.Format("{0}", CraftResources.GetName(arm.Resource)); + + if (from.Skills[SkillName.ArmsLore].Value >= 50 && from.Skills[SkillName.ArmsLore].Value <= 75) + { + if (durability < 0.1 || arm.MaxHitPoints < 10) + textdurability = "Fissur�e et menace de se briser!"; + else if (durability < 0.3) + textdurability = "Signes importants de faiblesse"; + else if (durability < 0.6) + textdurability = "Endommag�e"; + else if (durability < 0.85) + textdurability = "Quelques d�gats"; + else if (durability < 1) + textdurability = "Presque neuve"; + else + textdurability = "Aucun d�faut"; + } + else if (from.Skills[SkillName.ArmsLore].Value > 75 && from.Skills[SkillName.ArmsLore].Value <= 95) + textdurability = string.Format("Endommag�e � {0}%", (100 - Math.Round(durability * 100.0))); + else if (from.Skills[SkillName.ArmsLore].Value > 95) + textdurability = string.Format("{0} sur {1}", arm.HitPoints, arm.MaxHitPoints); + else if (durability < 0.15) + textdurability = string.Format("Cette arme tombe en ruine"); + + + from.SendMessage("Type : {0}", texttype); + from.SendMessage("Resource : {0}", textresource); + from.SendMessage("Qualit� : {0}", textquality); + from.SendMessage("Durabilit� : {0}", textdurability);/*, textquality, textresource, textdurability*/ + } + + else if (targeted is BaseArmor) + { + BaseArmor arm = (BaseArmor)targeted; + + double durability = 0; + + if (arm.MaxHitPoints != 0) + durability = arm.HitPoints / (double)arm.MaxHitPoints; + + switch (arm.MaterialType) + { + case ArmorMaterialType.Barbed : + case ArmorMaterialType.Horned : + case ArmorMaterialType.Spined : + case ArmorMaterialType.Studded : + case ArmorMaterialType.Daemon: texttype = "Armure de cuir de demon"; break; + case ArmorMaterialType.Leather: texttype = "Armure de cuir"; break; + case ArmorMaterialType.Bone: texttype = "Armure d'os"; break; + case ArmorMaterialType.Chainmail: texttype = "Armure de chaine"; break; + case ArmorMaterialType.Cloth: texttype = "Armure de tissus"; break; + case ArmorMaterialType.Dragon: texttype = "Armure d'�caille"; break; + case ArmorMaterialType.Ringmail: texttype = "Armure d'anneau"; break; + case ArmorMaterialType.Plate: texttype = "Armure de plaque"; break; + default: texttype= "Armure"; break; + } + + if (from.Skills[SkillName.ArmsLore].Value > 20) + { + if (arm.Quality == ArmorQuality.Low) + textquality = "Mauvaise"; + else if (arm.Quality == ArmorQuality.Exceptional) + textquality = "Excellente"; + else + textquality = "Commune"; + } + + if (arm.MaterialType != ArmorMaterialType.Bone && from.Skills[SkillName.Mining].Value > 30 && arm.Resource != CraftResource.None) + textresource = string.Format(" en {0}.", CraftResources.GetName(arm.Resource)); + + if (from.Skills[SkillName.ArmsLore].Value >= 50 && from.Skills[SkillName.ArmsLore].Value <= 75) + { + if (durability < 0.1 || arm.MaxHitPoints < 10) + textdurability = "Fissur�e et menace de se briser!"; + else if (durability < 0.3) + textdurability = "Signes importants de faiblesse"; + else if (durability < 0.6) + textdurability = "Endommag�e"; + else if (durability < 0.85) + textdurability = "Quelques d�gats"; + else if (durability < 1) + textdurability = "Presque neuve"; + else + textdurability = "Aucun d�faut"; + } + else if (from.Skills[SkillName.ArmsLore].Value > 75 && from.Skills[SkillName.ArmsLore].Value <= 95) + textdurability = string.Format("Endommag�e � {0}%", (100 - Math.Round(durability * 100.0))); + else if (from.Skills[SkillName.ArmsLore].Value > 95) + textdurability = string.Format("{0} sur {1}", arm.HitPoints, arm.MaxHitPoints); + else if (durability < 0.15) + textdurability = string.Format("Cette arme tombe en ruine"); + + from.SendMessage("Type : {0}", texttype); + from.SendMessage("Resource : {0}", textresource); + from.SendMessage("Qualit� : {0}", textquality); + from.SendMessage("Durabilit� : {0}", textdurability); + } + else if (targeted is BaseJewel) + { + BaseJewel arm = (BaseJewel)targeted; + + switch (arm.Layer) + { + case Layer.Earrings: texttype= "Boucles d'oreilles"; break; + case Layer.Neck: texttype = "Pendentif"; break; + case Layer.Bracelet: texttype = "Bracelet"; break; + default: texttype = "Bijou"; break; + } + + if (from.Skills[SkillName.Mining].Value > 30 && arm.Resource != CraftResource.None) + textresource = string.Format("{0}.", CraftResources.GetName(arm.Resource)); + + from.SendMessage("Type : {0}", texttype); + from.SendMessage("Resource : {0}", textresource); + } + else + { + from.SendMessage("Ceci n'est ni une arme, ni une armure, ni un bijou"); // This is neither weapon nor armor. + } + } + else + { + from.SendMessage("Vous �tes incertain..."); // You are not certain... + } + } + else + { + from.SendMessage("Ceci n'est ni une arme, ni une armure, ni un bijou"); // This is neither weapon nor armor. + } + } + + } + } +} + + + + \ No newline at end of file diff --git a/Scripts/Skills/Begging.cs b/Scripts/Skills/Begging.cs new file mode 100644 index 0000000..455d390 --- /dev/null +++ b/Scripts/Skills/Begging.cs @@ -0,0 +1,175 @@ +using System; +using Server; +using Server.Misc; +using Server.Targeting; +using Server.Items; +using Server.Network; + +namespace Server.SkillHandlers +{ + public class Begging + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Begging].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.RevealingAction(); + + m.Target = new InternalTarget(); + m.RevealingAction(); + + m.SendLocalizedMessage( 500397 ); // To whom do you wish to grovel? + + return TimeSpan.FromHours( 6.0 ); + } + + private class InternalTarget : Target + { + private bool m_SetSkillTime = true; + + public InternalTarget() : base ( 12, false, TargetFlags.None ) + { + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_SetSkillTime ) + from.NextSkillTime = DateTime.Now; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + from.RevealingAction(); + + int number = -1; + + if ( targeted is Mobile ) + { + Mobile targ = (Mobile)targeted; + + if ( targ.Player ) // We can't beg from players + { + number = 500398; // Perhaps just asking would work better. + } + else if ( !targ.Body.IsHuman ) // Make sure the NPC is human + { + number = 500399; // There is little chance of getting money from that! + } + else if ( !from.InRange( targ, 2 ) ) + { + if ( !targ.Female ) + number = 500401; // You are too far away to beg from him. + else + number = 500402; // You are too far away to beg from her. + } + else if (!Core.ML && from.Mounted) // If we're on a mount, who would give us money? TODO: guessed it's removed since ML + { + number = 500404; // They seem unwilling to give you any money. + } + else + { + // Face eachother + from.Direction = from.GetDirectionTo( targ ); + targ.Direction = targ.GetDirectionTo( from ); + + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + new InternalTimer( from, targ ).Start(); + + m_SetSkillTime = false; + } + } + else // Not a Mobile + { + number = 500399; // There is little chance of getting money from that! + } + + if ( number != -1 ) + from.SendLocalizedMessage( number ); + } + + private class InternalTimer : Timer + { + private Mobile m_From, m_Target; + + public InternalTimer( Mobile from, Mobile target ) : base( TimeSpan.FromSeconds( 2.0 ) ) + { + m_From = from; + m_Target = target; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + Container theirPack = m_Target.Backpack; + + double badKarmaChance = 0.5 - ((double)m_From.Karma / 8570); + + if ( theirPack == null ) + { + m_From.SendLocalizedMessage( 500404 ); // They seem unwilling to give you any money. + } + else if ( m_From.Karma < 0 && badKarmaChance > Utility.RandomDouble() ) + { + m_Target.PublicOverheadMessage( MessageType.Regular, m_Target.SpeechHue, 500406 ); // Thou dost not look trustworthy... no gold for thee today! + } + else if ( m_From.CheckTargetSkill( SkillName.Begging, m_Target, 0.0, 100.0 ) ) + { + int toConsume = theirPack.GetAmount( typeof( Gold ) ) / 10; + int max = 10 + (m_From.Fame / 2500); + + if ( max > 14 ) + max = 14; + else if ( max < 10 ) + max = 10; + + if ( toConsume > max ) + toConsume = max; + + if ( toConsume > 0 ) + { + int consumed = theirPack.ConsumeUpTo( typeof( Gold ), toConsume ); + + if ( consumed > 0 ) + { + m_Target.PublicOverheadMessage( MessageType.Regular, m_Target.SpeechHue, 500405 ); // I feel sorry for thee... + + Gold gold = new Gold( consumed ); + + m_From.AddToBackpack( gold ); + m_From.PlaySound( gold.GetDropSound() ); + + if ( m_From.Karma > -3000 ) + { + int toLose = m_From.Karma + 3000; + + if ( toLose > 40 ) + toLose = 40; + + Titles.AwardKarma( m_From, -toLose, true ); + } + } + else + { + m_Target.PublicOverheadMessage( MessageType.Regular, m_Target.SpeechHue, 500407 ); // I have not enough money to give thee any! + } + } + else + { + m_Target.PublicOverheadMessage( MessageType.Regular, m_Target.SpeechHue, 500407 ); // I have not enough money to give thee any! + } + } + else + { + m_Target.SendLocalizedMessage( 500404 ); // They seem unwilling to give you any money. + } + + m_From.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/DetectHidden.cs b/Scripts/Skills/DetectHidden.cs new file mode 100644 index 0000000..a841395 --- /dev/null +++ b/Scripts/Skills/DetectHidden.cs @@ -0,0 +1,117 @@ +using System; +using Server.Items; +using Server.Factions; +using Server.Mobiles; +using Server.Multis; +using Server.Targeting; +using Server.Regions; + +namespace Server.SkillHandlers +{ + public class DetectHidden + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.DetectHidden].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile src ) + { + src.SendLocalizedMessage( 500819 );//Where will you search? + src.Target = new InternalTarget(); + + return TimeSpan.FromSeconds( 6.0 ); + } + + private class InternalTarget : Target + { + public InternalTarget() : base( 12, true, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile src, object targ ) + { + bool foundAnyone = false; + + Point3D p; + if ( targ is Mobile ) + p = ((Mobile)targ).Location; + else if ( targ is Item ) + p = ((Item)targ).Location; + else if ( targ is IPoint3D ) + p = new Point3D( (IPoint3D)targ ); + else + p = src.Location; + + double srcSkill = src.Skills[SkillName.DetectHidden].Value; + int range = (int)(srcSkill / 10.0); + + if ( !src.CheckSkill( SkillName.DetectHidden, 0.0, 100.0 ) ) + range /= 2; + + BaseHouse house = BaseHouse.FindHouseAt( p, src.Map, 16 ); + + bool inHouse = ( house != null && house.IsFriend( src ) ); + + if ( inHouse ) + range = 22; + + if ( range > 0 ) + { + IPooledEnumerable inRange = src.Map.GetMobilesInRange( p, range ); + + foreach ( Mobile trg in inRange ) + { + if ( trg.Hidden && src != trg ) + { + double ss = srcSkill + Utility.Random( 21 ) - 10; + double ts = trg.Skills[SkillName.Hiding].Value + Utility.Random( 21 ) - 10; + + if ( src.AccessLevel >= trg.AccessLevel && ( ss >= ts || ( inHouse && house.IsInside( trg ) ) ) ) + { + if ( trg is ShadowKnight && (trg.X != p.X || trg.Y != p.Y) ) + continue; + + trg.RevealingAction(); + trg.SendLocalizedMessage( 500814 ); // You have been revealed! + foundAnyone = true; + } + } + } + + inRange.Free(); + + if ( Faction.Find( src ) != null ) + { + IPooledEnumerable itemsInRange = src.Map.GetItemsInRange( p, range ); + + foreach ( Item item in itemsInRange ) + { + if ( item is BaseFactionTrap ) + { + BaseFactionTrap trap = (BaseFactionTrap) item; + + if ( src.CheckTargetSkill( SkillName.DetectHidden, trap, 80.0, 100.0 ) ) + { + src.SendLocalizedMessage( 1042712, true, " " + (trap.Faction == null ? "" : trap.Faction.Definition.FriendlyName) ); // You reveal a trap placed by a faction: + + trap.Visible = true; + trap.BeginConceal(); + + foundAnyone = true; + } + } + } + + itemsInRange.Free(); + } + } + + if ( !foundAnyone ) + { + src.SendLocalizedMessage( 500817 ); // You can see nothing hidden there. + } + } + } + } +} diff --git a/Scripts/Skills/Discordance.cs b/Scripts/Skills/Discordance.cs new file mode 100644 index 0000000..7efb77e --- /dev/null +++ b/Scripts/Skills/Discordance.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.SkillHandlers +{ + public class Discordance + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Discordance].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.RevealingAction(); + + BaseInstrument.PickInstrument( m, new InstrumentPickedCallback( OnPickedInstrument ) ); + + return TimeSpan.FromSeconds( 1.0 ); // Cannot use another skill for 1 second + } + + public static void OnPickedInstrument( Mobile from, BaseInstrument instrument ) + { + from.RevealingAction(); + from.SendLocalizedMessage( 1049541 ); // Choose the target for your song of discordance. + from.Target = new DiscordanceTarget( from, instrument ); + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 6.0 ); + } + + private class DiscordanceInfo + { + public Mobile m_From; + public Mobile m_Creature; + public DateTime m_EndTime; + public bool m_Ending; + public Timer m_Timer; + public int m_Effect; + public ArrayList m_Mods; + + public DiscordanceInfo( Mobile from, Mobile creature, int effect, ArrayList mods ) + { + m_From = from; + m_Creature = creature; + m_EndTime = DateTime.Now; + m_Ending = false; + m_Effect = effect; + m_Mods = mods; + + Apply(); + } + + public void Apply() + { + for ( int i = 0; i < m_Mods.Count; ++i ) + { + object mod = m_Mods[i]; + + if ( mod is ResistanceMod ) + m_Creature.AddResistanceMod( (ResistanceMod) mod ); + else if ( mod is StatMod ) + m_Creature.AddStatMod( (StatMod) mod ); + else if ( mod is SkillMod ) + m_Creature.AddSkillMod( (SkillMod) mod ); + } + } + + public void Clear() + { + for ( int i = 0; i < m_Mods.Count; ++i ) + { + object mod = m_Mods[i]; + + if ( mod is ResistanceMod ) + m_Creature.RemoveResistanceMod( (ResistanceMod) mod ); + else if ( mod is StatMod ) + m_Creature.RemoveStatMod( ((StatMod) mod).Name ); + else if ( mod is SkillMod ) + m_Creature.RemoveSkillMod( (SkillMod) mod ); + } + } + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool GetEffect( Mobile targ, ref int effect ) + { + DiscordanceInfo info = m_Table[targ] as DiscordanceInfo; + + if ( info == null ) + return false; + + effect = info.m_Effect; + return true; + } + + private static void ProcessDiscordance( DiscordanceInfo info ) + { + Mobile from = info.m_From; + Mobile targ = info.m_Creature; + bool ends = false; + + // According to uoherald bard must remain alive, visible, and + // within range of the target or the effect ends in 15 seconds. + if ( !targ.Alive || targ.Deleted || !from.Alive || from.Hidden ) + ends = true; + else + { + int range = (int) targ.GetDistanceToSqrt( from ); + int maxRange = BaseInstrument.GetBardRange( from, SkillName.Discordance ); + + if ( from.Map != targ.Map || range > maxRange ) + ends = true; + } + + if ( ends && info.m_Ending && info.m_EndTime < DateTime.Now ) + { + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + info.Clear(); + m_Table.Remove( targ ); + } + else + { + if ( ends && !info.m_Ending ) + { + info.m_Ending = true; + info.m_EndTime = DateTime.Now + TimeSpan.FromSeconds( 15 ); + } + else if ( !ends ) + { + info.m_Ending = false; + info.m_EndTime = DateTime.Now; + } + + targ.FixedEffect( 0x376A, 1, 32 ); + } + } + + public class DiscordanceTarget : Target + { + private BaseInstrument m_Instrument; + + public DiscordanceTarget( Mobile from, BaseInstrument inst ) : base( BaseInstrument.GetBardRange( from, SkillName.Discordance ), false, TargetFlags.None ) + { + m_Instrument = inst; + } + + protected override void OnTarget( Mobile from, object target ) + { + from.RevealingAction(); + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 1.0 ); + + if ( !m_Instrument.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062488 ); // The instrument you are trying to play is no longer in your backpack! + } + else if ( target is Mobile ) + { + Mobile targ = (Mobile)target; + + if ( targ == from || (targ is BaseCreature && ( ((BaseCreature)targ).BardImmune || !from.CanBeHarmful( targ, false ) ) && ((BaseCreature)targ).ControlMaster != from) ) + { + from.SendLocalizedMessage( 1049535 ); // A song of discord would have no effect on that. + } + else if ( m_Table.Contains( targ ) ) //Already discorded + { + from.SendLocalizedMessage( 1049537 );// Your target is already in discord. + } + else if ( !targ.Player ) + { + double diff = m_Instrument.GetDifficultyFor( targ ) - 10.0; + double music = from.Skills[SkillName.Musicianship].Value; + + if ( music > 100.0 ) + diff -= (music - 100.0) * 0.5; + + if ( !BaseInstrument.CheckMusicianship( from ) ) + { + from.SendLocalizedMessage( 500612 ); // You play poorly, and there is no effect. + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else if ( from.CheckTargetSkill( SkillName.Discordance, target, diff-25.0, diff+25.0 ) ) + { + from.SendLocalizedMessage( 1049539 ); // You play the song surpressing your targets strength + m_Instrument.PlayInstrumentWell( from ); + m_Instrument.ConsumeUse( from ); + + ArrayList mods = new ArrayList(); + int effect; + double scalar; + + if ( Core.AOS ) + { + double discord = from.Skills[SkillName.Discordance].Value; + + if ( discord > 100.0 ) + effect = -20 + (int)((discord - 100.0) / -2.5); + else + effect = (int)(discord / -5.0); + + if ( Core.SE && BaseInstrument.GetBaseDifficulty( targ ) >= 160.0 ) + effect /= 2; + + scalar = effect * 0.01; + + mods.Add( new ResistanceMod( ResistanceType.Physical, effect ) ); + mods.Add( new ResistanceMod( ResistanceType.Fire, effect ) ); + mods.Add( new ResistanceMod( ResistanceType.Cold, effect ) ); + mods.Add( new ResistanceMod( ResistanceType.Poison, effect ) ); + mods.Add( new ResistanceMod( ResistanceType.Energy, effect ) ); + + for ( int i = 0; i < targ.Skills.Length; ++i ) + { + if ( targ.Skills[i].Value > 0 ) + mods.Add( new DefaultSkillMod( (SkillName)i, true, targ.Skills[i].Value * scalar ) ); + } + } + else + { + effect = (int)( from.Skills[SkillName.Discordance].Value / -5.0 ); + scalar = effect * 0.01; + + mods.Add( new StatMod( StatType.Str, "DiscordanceStr", (int)(targ.RawStr * scalar), TimeSpan.Zero ) ); + mods.Add( new StatMod( StatType.Int, "DiscordanceInt", (int)(targ.RawInt * scalar), TimeSpan.Zero ) ); + mods.Add( new StatMod( StatType.Dex, "DiscordanceDex", (int)(targ.RawDex * scalar), TimeSpan.Zero ) ); + + for ( int i = 0; i < targ.Skills.Length; ++i ) + { + if ( targ.Skills[i].Value > 0 ) + mods.Add( new DefaultSkillMod( (SkillName)i, true, targ.Skills[i].Value * scalar ) ); + } + } + + DiscordanceInfo info = new DiscordanceInfo( from, targ, Math.Abs( effect ), mods ); + info.m_Timer = Timer.DelayCall( TimeSpan.Zero, TimeSpan.FromSeconds( 1.25 ), new TimerStateCallback( ProcessDiscordance ), info ); + + m_Table[targ] = info; + } + else + { + from.SendLocalizedMessage( 1049540 );// You fail to disrupt your target + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 12.0 ); + } + else + { + m_Instrument.PlayInstrumentBadly( from ); + } + } + else + { + from.SendLocalizedMessage( 1049535 ); // A song of discord would have no effect on that. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/EvalInt.cs b/Scripts/Skills/EvalInt.cs new file mode 100644 index 0000000..991018e --- /dev/null +++ b/Scripts/Skills/EvalInt.cs @@ -0,0 +1,89 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.SkillHandlers +{ + public class EvalInt + { + public static void Initialize() + { + SkillInfo.Table[16].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.Target = new EvalInt.InternalTarget(); + + m.SendLocalizedMessage( 500906 ); // What do you wish to evaluate? + + return TimeSpan.FromSeconds( 1.0 ); + } + + private class InternalTarget : Target + { + public InternalTarget() : base ( 8, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( from == targeted ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500910 ); // Hmm, that person looks really silly. + } + else if ( targeted is TownCrier ) + { + ((TownCrier)targeted).PrivateOverheadMessage( MessageType.Regular, 0x3B2, 500907, from.NetState ); // He looks smart enough to remember the news. Ask him about it. + } + else if ( targeted is BaseVendor && ((BaseVendor)targeted).IsInvulnerable ) + { + ((BaseVendor)targeted).PrivateOverheadMessage( MessageType.Regular, 0x3B2, 500909, from.NetState ); // That person could probably calculate the cost of what you buy from them. + } + else if ( targeted is Mobile ) + { + Mobile targ = (Mobile)targeted; + + int marginOfError = Math.Max( 0, 20 - (int)(from.Skills[SkillName.EvalInt].Value / 5) ); + + int intel = targ.Int + Utility.RandomMinMax( -marginOfError, +marginOfError ); + int mana = ((targ.Mana * 100) / Math.Max( targ.ManaMax, 1 )) + Utility.RandomMinMax( -marginOfError, +marginOfError ); + + int intMod = intel / 10; + int mnMod = mana / 10; + + if ( intMod > 10 ) intMod = 10; + else if ( intMod < 0 ) intMod = 0; + + if ( mnMod > 10 ) mnMod = 10; + else if ( mnMod < 0 ) mnMod = 0; + + int body; + + if ( targ.Body.IsHuman ) + body = targ.Female ? 11 : 0; + else + body = 22; + + if ( from.CheckTargetSkill( SkillName.EvalInt, targ, 0.0, 120.0 ) ) + { + targ.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1038169 + intMod + body, from.NetState ); // He/She/It looks [slighly less intelligent than a rock.] [Of Average intellect] [etc...] + + if ( from.Skills[SkillName.EvalInt].Base >= 76.0 ) + targ.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1038202 + mnMod, from.NetState ); // That being is at [10,20,...] percent mental strength. + } + else + { + targ.PrivateOverheadMessage( MessageType.Regular, 0x3B2, 1038166 + (body / 11), from.NetState ); // You cannot judge his/her/its mental abilities. + } + } + else if ( targeted is Item ) + { + ((Item)targeted).SendLocalizedMessageTo( from, 500908, "" ); // It looks smarter than a rock, but dumber than a piece of wood. + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/ForensicEval.cs b/Scripts/Skills/ForensicEval.cs new file mode 100644 index 0000000..e648d95 --- /dev/null +++ b/Scripts/Skills/ForensicEval.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections; +using System.Text; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.SkillHandlers +{ + public class ForensicEvaluation + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Forensics].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.Target = new ForensicTarget(); + m.RevealingAction(); + + m.SendLocalizedMessage(501000); // Show me the crime. + + return TimeSpan.FromSeconds( 1.0 ); + } + + public class ForensicTarget : Target + { + public ForensicTarget() : base( 10, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object target ) + { + if ( target is Mobile ) + { + if ( from.CheckTargetSkill( SkillName.Forensics, target, 40.0, 100.0 ) ) + { + if ( target is PlayerMobile && ((PlayerMobile)target).NpcGuild == NpcGuild.ThievesGuild ) + from.SendLocalizedMessage( 501004 );//That individual is a thief! + else + from.SendLocalizedMessage( 501003 );//You notice nothing unusual. + } + else + { + from.SendLocalizedMessage( 501001 );//You cannot determain anything useful. + } + } + else if ( target is Corpse ) + { + if ( from.CheckTargetSkill( SkillName.Forensics, target, 0.0, 100.0 ) ) + { + Corpse c = (Corpse)target; + + if (c.m_Forensicist != null) + from.SendLocalizedMessage(1042750, c.m_Forensicist); // The forensicist ~1_NAME~ has already discovered that: + else + c.m_Forensicist = from.Name; + + if (((Body)c.Amount).IsHuman) + from.SendLocalizedMessage(1042751, (c.Killer == null ? "no one" : c.Killer.Name));//This person was killed by ~1_KILLER_NAME~ + + + if ( c.Looters.Count > 0 ) + { + StringBuilder sb = new StringBuilder(); + for (int i=0;i0 ) + sb.Append( ", " ); + sb.Append( ((Mobile)c.Looters[i]).Name ); + } + + from.SendLocalizedMessage(1042752, sb.ToString());//This body has been distrubed by ~1_PLAYER_NAMES~ + } + else + { + from.SendLocalizedMessage(501002);//The corpse has not be desecrated. + } + } + else + { + from.SendLocalizedMessage( 501001 );//You cannot determain anything useful. + } + } + else if ( target is ILockpickable ) + { + ILockpickable p = (ILockpickable)target; + if ( p.Picker != null ) + from.SendLocalizedMessage( 1042749, p.Picker.Name );//This lock was opened by ~1_PICKER_NAME~ + else + from.SendLocalizedMessage( 501003 );//You notice nothing unusual. + } + } + } + } +} diff --git a/Scripts/Skills/Hiding.cs b/Scripts/Skills/Hiding.cs new file mode 100644 index 0000000..52a2035 --- /dev/null +++ b/Scripts/Skills/Hiding.cs @@ -0,0 +1,114 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; +using Server.Multis; + +namespace Server.SkillHandlers +{ + public class Hiding + { + private static bool m_CombatOverride; + + public static bool CombatOverride + { + get{ return m_CombatOverride; } + set{ m_CombatOverride = value; } + } + + public static void Initialize() + { + SkillInfo.Table[21].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + if ( m.Spell != null ) + { + m.SendLocalizedMessage( 501238 ); // You are busy doing something else and cannot hide. + return TimeSpan.FromSeconds( 1.0 ); + } + + if ( Core.ML && m.Target != null ) + { + Targeting.Target.Cancel( m ); + } + + double bonus = 0.0; + + BaseHouse house = BaseHouse.FindHouseAt( m ); + + if ( house != null && house.IsFriend( m ) ) + { + bonus = 100.0; + } + else if ( !Core.AOS ) + { + if ( house == null ) + house = BaseHouse.FindHouseAt( new Point3D( m.X - 1, m.Y, 127 ), m.Map, 16 ); + + if ( house == null ) + house = BaseHouse.FindHouseAt( new Point3D( m.X + 1, m.Y, 127 ), m.Map, 16 ); + + if ( house == null ) + house = BaseHouse.FindHouseAt( new Point3D( m.X, m.Y - 1, 127 ), m.Map, 16 ); + + if ( house == null ) + house = BaseHouse.FindHouseAt( new Point3D( m.X, m.Y + 1, 127 ), m.Map, 16 ); + + if ( house != null ) + bonus = 50.0; + } + + //int range = 18 - (int)(m.Skills[SkillName.Hiding].Value / 10); + int range = Math.Min( (int)((100 - m.Skills[SkillName.Hiding].Value)/2) + 8, 18 ); //Cap of 18 not OSI-exact, intentional difference + + bool badCombat = ( !m_CombatOverride && m.Combatant != null && m.InRange( m.Combatant.Location, range ) && m.Combatant.InLOS( m ) ); + bool ok = ( !badCombat /*&& m.CheckSkill( SkillName.Hiding, 0.0 - bonus, 100.0 - bonus )*/ ); + + if ( ok ) + { + if ( !m_CombatOverride ) + { + foreach ( Mobile check in m.GetMobilesInRange( range ) ) + { + if ( check.InLOS( m ) && check.Combatant == m ) + { + badCombat = true; + ok = false; + break; + } + } + } + + ok = ( !badCombat && m.CheckSkill( SkillName.Hiding, 0.0 - bonus, 100.0 - bonus ) ); + } + + if ( badCombat ) + { + m.RevealingAction(); + + m.LocalOverheadMessage( MessageType.Regular, 0x22, 501237 ); // You can't seem to hide right now. + + return TimeSpan.FromSeconds( 1.0 ); + } + else + { + if ( ok ) + { + m.Hidden = true; + m.Warmode = false; + m.LocalOverheadMessage( MessageType.Regular, 0x1F4, 501240 ); // You have hidden yourself well. + } + else + { + m.RevealingAction(); + + m.LocalOverheadMessage( MessageType.Regular, 0x22, 501241 ); // You can't seem to hide here. + } + + return TimeSpan.FromSeconds( 10.0 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Inscribe.cs b/Scripts/Skills/Inscribe.cs new file mode 100644 index 0000000..253ae6d --- /dev/null +++ b/Scripts/Skills/Inscribe.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Items; + +namespace Server.SkillHandlers +{ + public class Inscribe + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Inscribe].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + Target target = new InternalTargetSrc(); + m.Target = target; + m.SendLocalizedMessage( 1046295 ); // Target the book you wish to copy. + target.BeginTimeout( m, TimeSpan.FromMinutes( 1.0 ) ); + + return TimeSpan.FromSeconds( 1.0 ); + } + + private static Hashtable m_UseTable = new Hashtable(); + + private static void SetUser( BaseBook book, Mobile mob ) + { + m_UseTable[book] = mob; + } + + private static void CancelUser( BaseBook book ) + { + m_UseTable.Remove( book ); + } + + public static Mobile GetUser( BaseBook book ) + { + return (Mobile)m_UseTable[book]; + } + + public static bool IsEmpty( BaseBook book ) + { + foreach ( BookPageInfo page in book.Pages ) + { + foreach ( string line in page.Lines ) + { + if ( line.Trim().Length != 0 ) + return false; + } + } + return true; + } + + public static void Copy( BaseBook bookSrc, BaseBook bookDst ) + { + bookDst.Title = bookSrc.Title; + bookDst.Author = bookSrc.Author; + + BookPageInfo[] pagesSrc = bookSrc.Pages; + BookPageInfo[] pagesDst = bookDst.Pages; + for ( int i = 0; i < pagesSrc.Length && i < pagesDst.Length; i++ ) + { + BookPageInfo pageSrc = pagesSrc[i]; + BookPageInfo pageDst = pagesDst[i]; + + int length = pageSrc.Lines.Length; + pageDst.Lines = new string[length]; + + for ( int j = 0; j < length; j++ ) + pageDst.Lines[j] = pageSrc.Lines[j]; + } + } + + private class InternalTargetSrc : Target + { + public InternalTargetSrc() : base ( 3, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + BaseBook book = targeted as BaseBook; + if ( book == null ) + from.SendLocalizedMessage( 1046296 ); // That is not a book + else if ( Inscribe.IsEmpty( book ) ) + from.SendLocalizedMessage( 501611 ); // Can't copy an empty book. + else if ( Inscribe.GetUser( book ) != null ) + from.SendLocalizedMessage( 501621 ); // Someone else is inscribing that item. + else + { + Target target = new InternalTargetDst( book ); + from.Target = target; + from.SendLocalizedMessage( 501612 ); // Select a book to copy this to. + target.BeginTimeout( from, TimeSpan.FromMinutes( 1.0 ) ); + Inscribe.SetUser( book, from ); + } + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + if ( cancelType == TargetCancelType.Timeout ) + from.SendLocalizedMessage( 501619 ); // You have waited too long to make your inscribe selection, your inscription attempt has timed out. + } + } + + private class InternalTargetDst : Target + { + private BaseBook m_BookSrc; + + public InternalTargetDst( BaseBook bookSrc ) : base ( 3, false, TargetFlags.None ) + { + m_BookSrc = bookSrc; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_BookSrc.Deleted ) + return; + + BaseBook bookDst = targeted as BaseBook; + + if ( bookDst == null ) + from.SendLocalizedMessage( 1046296 ); // That is not a book + else if ( Inscribe.IsEmpty( m_BookSrc ) ) + from.SendLocalizedMessage( 501611 ); // Can't copy an empty book. + else if ( bookDst == m_BookSrc ) + from.SendLocalizedMessage( 501616 ); // Cannot copy a book onto itself. + else if ( !bookDst.Writable ) + from.SendLocalizedMessage( 501614 ); // Cannot write into that book. + else if ( Inscribe.GetUser( bookDst ) != null ) + from.SendLocalizedMessage( 501621 ); // Someone else is inscribing that item. + else + { + if ( from.CheckTargetSkill( SkillName.Inscribe, bookDst, 0, 50 ) ) + { + Inscribe.Copy( m_BookSrc, bookDst ); + + from.SendLocalizedMessage( 501618 ); // You make a copy of the book. + from.PlaySound( 0x249 ); + } + else + { + from.SendLocalizedMessage( 501617 ); // You fail to make a copy of the book. + } + } + } + + protected override void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + if ( cancelType == TargetCancelType.Timeout ) + from.SendLocalizedMessage( 501619 ); // You have waited too long to make your inscribe selection, your inscription attempt has timed out. + } + + protected override void OnTargetFinish( Mobile from ) + { + Inscribe.CancelUser( m_BookSrc ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/ItemIdentification.cs b/Scripts/Skills/ItemIdentification.cs new file mode 100644 index 0000000..59e0387 --- /dev/null +++ b/Scripts/Skills/ItemIdentification.cs @@ -0,0 +1,207 @@ +using System; +using Server; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Items +{ + + public class ItemIdentification + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.ItemID].Callback = new SkillUseCallback(OnUse); + } + + public static TimeSpan OnUse(Mobile from) + { + from.SendLocalizedMessage(500343); // What do you wish to appraise and identify? + from.Target = new InternalTarget(); + + return TimeSpan.FromSeconds(1.0); + } + + + + [PlayerVendorTarget] + private class InternalTarget : Target + { + public InternalTarget() + : base(8, false, TargetFlags.None) + { + AllowNonlocal = true; + } + + protected override void OnTarget(Mobile from, object o) + { + if (o is Item) + { + if (from.CheckTargetSkill(SkillName.ItemID, o, 0, 100)) + { + + #region BaseWeapon + if (o is BaseWeapon && !((BaseWeapon)o).Identified) + { + BaseWeapon idarme = (BaseWeapon)o; + + int difficulty = idarme.WeaponDifficulty; + + if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) <= 5) + { + from.SendMessage("Cette arme d�gage un pouvoir trop grand pour vos maigres moyens"); + return; + } + else if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) >= Utility.Random(difficulty * 10)) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s de l'arme"); + idarme.Identified = true; + } + else + { + int consequence = Utility.Random(from.RawInt); + + if (consequence < difficulty) + { + from.SendMessage("Dans votre tentative d'identifier l'arme, vous l'avez bris�e"); + idarme.Delete(); + } + else if (consequence < difficulty * 10) + { + from.SendMessage("Vous n'avez rien d�cel�, mais avez abim� l'arme"); + idarme.MaxHitPoints -= 1; + } + else + from.SendMessage("Vous n'avez rien d�cel�"); + } + } + #endregion + #region BaseArmor + else if (o is BaseArmor && !((BaseArmor)o).Identified) + { + BaseArmor idarmure = (BaseArmor)o; + + int difficulty = idarmure.ArmorDifficulty; + + if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) <= 5) + { + from.SendMessage("Cette armure d�gage un pouvoir trop grand pour vos maigres moyens"); + return; + } + else if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) >= Utility.Random(difficulty * 10)) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s de l'armure"); + idarmure.Identified = true; + } + else + { + int consequence = Utility.Random(from.RawInt); + + if (consequence < difficulty) + { + from.SendMessage("Dans votre tentative d'identifier l'armure, vous l'avez bris�e"); + idarmure.Delete(); + } + else if (consequence < difficulty * 10) + { + from.SendMessage("Vous n'avez rien d�cel�, mais avez abim� l'armure"); + idarmure.MaxHitPoints -= 1; + } + else + from.SendMessage("Vous n'avez rien d�cel�"); + } + } + #endregion + #region BaseClothing + else if (o is BaseClothing && !((BaseClothing)o).Identified) + { + BaseClothing idclothing = (BaseClothing)o; + + int difficulty = idclothing.ClothingDifficulty; + + if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) <= 5) + { + from.SendMessage("Ce v�tement d�gage un pouvoir trop grand pour vos maigres moyens"); + return; + } + else if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) >= Utility.Random(difficulty * 10)) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s du v�tement"); + idclothing.Identified = true; + } + else + { + int consequence = Utility.Random(from.RawInt); + + if (consequence < difficulty) + { + from.SendMessage("Dans votre tentative d'identifier le v�tement, vous l'avez bris�"); + idclothing.Delete(); + } + else if (consequence < difficulty * 10) + { + from.SendMessage("Vous n'avez rien d�cel�, mais avez abim� le v�tement"); + idclothing.MaxHitPoints -= 1; + } + else + from.SendMessage("Vous n'avez rien d�cel�"); + } + } + #endregion + #region BaseJewel + else if (o is BaseJewel && !((BaseJewel)o).Identified) + { + BaseJewel idjewel = (BaseJewel)o; + + int difficulty = idjewel.JewelDifficulty; + + if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) <= 5) + { + from.SendMessage("Ce bijou d�gage un pouvoir trop grand pour vos maigres moyens"); + return; + } + else if ((from.Skills[SkillName.ItemID].Value - (difficulty * 10)) >= Utility.Random(difficulty * 10)) + { + from.SendMessage("Vous parvenez � d�cerner les capacit�s du bijou"); + idjewel.Identified = true; + } + else + { + int consequence = Utility.Random(from.RawInt); + + if (consequence < difficulty*2) + { + from.SendMessage("Dans votre tentative d'identifier le bijou, vous l'avez bris�"); + idjewel.Delete(); + } + else + from.SendMessage("Vous n'avez rien d�cel�"); + } + } + else + { + from.SendMessage("Cet objet est d�j� identifi�"); + } + #endregion + + if (!Core.AOS) + ((Item)o).OnSingleClick(from); + } + else + { + from.SendMessage("Vous ne parvenez pas � vous concentrer."); + } + + } + else if (o is Mobile) + { + ((Mobile)o).OnSingleClick(from); + } + else + { + from.SendMessage("Vous ne pouvez rien apprendre de cela"); + } + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Meditation.cs b/Scripts/Skills/Meditation.cs new file mode 100644 index 0000000..a2589cc --- /dev/null +++ b/Scripts/Skills/Meditation.cs @@ -0,0 +1,101 @@ +using System; +using Server.Items; + +namespace Server.SkillHandlers +{ + class Meditation + { + public static void Initialize() + { + SkillInfo.Table[46].Callback = new SkillUseCallback( OnUse ); + } + + public static bool CheckOkayHolding( Item item ) + { + if ( item == null ) + return true; + + if ( item is Spellbook || item is Runebook ) + return true; + + if ( Core.AOS && item is BaseWeapon && ((BaseWeapon)item).Attributes.SpellChanneling != 0 ) + return true; + + if ( Core.AOS && item is BaseArmor && ((BaseArmor)item).Attributes.SpellChanneling != 0 ) + return true; + + return false; + } + + public static TimeSpan OnUse( Mobile m ) + { + m.RevealingAction(); + + if ( m.Target != null ) + { + m.SendLocalizedMessage( 501845 ); // You are busy doing something else and cannot focus. + + return TimeSpan.FromSeconds( 5.0 ); + } + else if ( !Core.AOS && m.Hits < (m.HitsMax / 10) ) // Less than 10% health + { + m.SendLocalizedMessage( 501849 ); // The mind is strong but the body is weak. + + return TimeSpan.FromSeconds( 5.0 ); + } + else if ( m.Mana >= m.ManaMax ) + { + m.SendLocalizedMessage( 501846 ); // You are at peace. + + return TimeSpan.FromSeconds( Core.AOS ? 10.0 : 5.0 ); + } + else if ( Core.AOS && Server.Misc.RegenRates.GetArmorOffset( m ) > 0 ) + { + m.SendLocalizedMessage( 500135 ); // Regenative forces cannot penetrate your armor! + + return TimeSpan.FromSeconds( 10.0 ); + } + else + { + Item oneHanded = m.FindItemOnLayer( Layer.OneHanded ); + Item twoHanded = m.FindItemOnLayer( Layer.TwoHanded ); + + if (Core.AOS && m.Player) + { + if ( !CheckOkayHolding( oneHanded ) ) + m.AddToBackpack( oneHanded ); + + if ( !CheckOkayHolding( twoHanded ) ) + m.AddToBackpack( twoHanded ); + } + else if ( !CheckOkayHolding( oneHanded ) || !CheckOkayHolding( twoHanded ) ) + { + m.SendLocalizedMessage( 502626 ); // Your hands must be free to cast spells or meditate. + + return TimeSpan.FromSeconds( 2.5 ); + } + + double skillVal = m.Skills[SkillName.Meditation].Value; + double chance = (50.0 + (( skillVal - ( m.ManaMax - m.Mana ) ) * 2)) / 100; + + if ( chance > Utility.RandomDouble() ) + { + m.CheckSkill( SkillName.Meditation, 0.0, 100.0 ); + + m.SendLocalizedMessage( 501851 ); // You enter a meditative trance. + m.Meditating = true; + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.ActiveMeditation, 1075657 ) ); + + if ( m.Player || m.Body.IsHuman ) + m.PlaySound( 0xF9 ); + } + else + { + m.SendLocalizedMessage( 501850 ); // You cannot focus your concentration. + } + + return TimeSpan.FromSeconds( 10.0 ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Peacemaking.cs b/Scripts/Skills/Peacemaking.cs new file mode 100644 index 0000000..45fd933 --- /dev/null +++ b/Scripts/Skills/Peacemaking.cs @@ -0,0 +1,207 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Items; + +namespace Server.SkillHandlers +{ + public class Peacemaking + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Peacemaking].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.RevealingAction(); + + BaseInstrument.PickInstrument( m, new InstrumentPickedCallback( OnPickedInstrument ) ); + + return TimeSpan.FromSeconds( 1.0 ); // Cannot use another skill for 1 second + } + + public static void OnPickedInstrument( Mobile from, BaseInstrument instrument ) + { + from.RevealingAction(); + from.SendLocalizedMessage( 1049525 ); // Whom do you wish to calm? + from.Target = new InternalTarget( from, instrument ); + from.NextSkillTime = DateTime.Now + TimeSpan.FromHours( 6.0 ); + } + + private class InternalTarget : Target + { + private BaseInstrument m_Instrument; + private bool m_SetSkillTime = true; + + public InternalTarget( Mobile from, BaseInstrument instrument ) : base( BaseInstrument.GetBardRange( from, SkillName.Peacemaking ), false, TargetFlags.None ) + { + m_Instrument = instrument; + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_SetSkillTime ) + from.NextSkillTime = DateTime.Now; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + from.RevealingAction(); + + if ( !(targeted is Mobile) ) + { + from.SendLocalizedMessage( 1049528 ); // You cannot calm that! + } + else if (from.Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) + { + from.SendMessage("You may not peacemake in this area."); + } + else if (((Mobile)targeted).Region.IsPartOf(typeof(Engines.ConPVP.SafeZone))) + { + from.SendMessage("You may not peacemake there."); + } + else if ( !m_Instrument.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062488 ); // The instrument you are trying to play is no longer in your backpack! + } + else + { + m_SetSkillTime = false; + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + + if ( targeted == from ) + { + // Standard mode : reset combatants for everyone in the area + + if ( !BaseInstrument.CheckMusicianship( from ) ) + { + from.SendLocalizedMessage( 500612 ); // You play poorly, and there is no effect. + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else if ( !from.CheckSkill( SkillName.Peacemaking, 0.0, 120.0 ) ) + { + from.SendLocalizedMessage( 500613 ); // You attempt to calm everyone, but fail. + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else + { + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 5.0 ); + m_Instrument.PlayInstrumentWell( from ); + m_Instrument.ConsumeUse( from ); + + Map map = from.Map; + + if ( map != null ) + { + int range = BaseInstrument.GetBardRange( from, SkillName.Peacemaking ); + + bool calmed = false; + + foreach ( Mobile m in from.GetMobilesInRange( range ) ) + { + if ((m is BaseCreature && ((BaseCreature)m).Uncalmable) || (m is BaseCreature && ((BaseCreature)m).AreaPeaceImmune) || m == from || !from.CanBeHarmful ( m, false )) + continue; + + calmed = true; + + m.SendLocalizedMessage( 500616 ); // You hear lovely music, and forget to continue battling! + m.Combatant = null; + m.Warmode = false; + + if ( m is BaseCreature && !((BaseCreature)m).BardPacified ) + ((BaseCreature)m).Pacify( from, DateTime.Now + TimeSpan.FromSeconds( 1.0 ) ); + } + + if ( !calmed ) + from.SendLocalizedMessage( 1049648 ); // You play hypnotic music, but there is nothing in range for you to calm. + else + from.SendLocalizedMessage( 500615 ); // You play your hypnotic music, stopping the battle. + } + } + } + else + { + // Target mode : pacify a single target for a longer duration + + Mobile targ = (Mobile)targeted; + + if ( !from.CanBeHarmful( targ, false ) ) + { + from.SendLocalizedMessage( 1049528 ); + m_SetSkillTime = true; + } + else if ( targ is BaseCreature && ((BaseCreature)targ).Uncalmable ) + { + from.SendLocalizedMessage( 1049526 ); // You have no chance of calming that creature. + m_SetSkillTime = true; + } + else if ( targ is BaseCreature && ((BaseCreature)targ).BardPacified ) + { + from.SendLocalizedMessage( 1049527 ); // That creature is already being calmed. + m_SetSkillTime = true; + } + else if ( !BaseInstrument.CheckMusicianship( from ) ) + { + from.SendLocalizedMessage( 500612 ); // You play poorly, and there is no effect. + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 5.0 ); + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else + { + double diff = m_Instrument.GetDifficultyFor( targ ) - 10.0; + double music = from.Skills[SkillName.Musicianship].Value; + + if ( music > 100.0 ) + diff -= (music - 100.0) * 0.5; + + if ( !from.CheckTargetSkill( SkillName.Peacemaking, targ, diff - 25.0, diff + 25.0 ) ) + { + from.SendLocalizedMessage( 1049531 ); // You attempt to calm your target, but fail. + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else + { + m_Instrument.PlayInstrumentWell( from ); + m_Instrument.ConsumeUse( from ); + + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 5.0 ); + if ( targ is BaseCreature ) + { + BaseCreature bc = (BaseCreature)targ; + + from.SendLocalizedMessage( 1049532 ); // You play hypnotic music, calming your target. + + targ.Combatant = null; + targ.Warmode = false; + + double seconds = 100 - (diff / 1.5); + + if ( seconds > 120 ) + seconds = 120; + else if ( seconds < 10 ) + seconds = 10; + + bc.Pacify( from, DateTime.Now + TimeSpan.FromSeconds( seconds ) ); + } + else + { + from.SendLocalizedMessage( 1049532 ); // You play hypnotic music, calming your target. + + targ.SendLocalizedMessage( 500616 ); // You hear lovely music, and forget to continue battling! + targ.Combatant = null; + targ.Warmode = false; + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Poisoning.cs b/Scripts/Skills/Poisoning.cs new file mode 100644 index 0000000..7ff0d44 --- /dev/null +++ b/Scripts/Skills/Poisoning.cs @@ -0,0 +1,179 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; + +namespace Server.SkillHandlers +{ + public class Poisoning + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Poisoning].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.Target = new InternalTargetPoison(); + + m.SendLocalizedMessage( 502137 ); // Select the poison you wish to use + + return TimeSpan.FromSeconds( 10.0 ); // 10 second delay before beign able to re-use a skill + } + + private class InternalTargetPoison : Target + { + public InternalTargetPoison() : base ( 2, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is BasePoisonPotion ) + { + from.SendLocalizedMessage( 502142 ); // To what do you wish to apply the poison? + from.Target = new InternalTarget( (BasePoisonPotion)targeted ); + } + else // Not a Poison Potion + { + from.SendLocalizedMessage( 502139 ); // That is not a poison potion. + } + } + + private class InternalTarget : Target + { + private BasePoisonPotion m_Potion; + + public InternalTarget( BasePoisonPotion potion ) : base ( 2, false, TargetFlags.None ) + { + m_Potion = potion; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Potion.Deleted ) + return; + + bool startTimer = false; + //Plume : Ajout des breuvages + if ( targeted is Food || targeted is BaseBeverage|| targeted is FukiyaDarts || targeted is Shuriken ) + { + startTimer = true; + } + else if ( targeted is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)targeted; + + if ( Core.AOS ) + { + startTimer = ( weapon.PrimaryAbility == WeaponAbility.InfectiousStrike || weapon.SecondaryAbility == WeaponAbility.InfectiousStrike ); + } + else if ( weapon.Layer == Layer.OneHanded ) + { + // Only Bladed or Piercing weapon can be poisoned + startTimer = ( weapon.Type == WeaponType.Slashing || weapon.Type == WeaponType.Piercing ); + } + } + + if ( startTimer ) + { + new InternalTimer( from, (Item)targeted, m_Potion ).Start(); + + from.PlaySound( 0x4F ); + + if (!Engines.ConPVP.DuelContext.IsFreeConsume(from)) + { + m_Potion.Consume(); + from.AddToBackpack(new Bottle()); + } + } + else // Target can't be poisoned + { + if ( Core.AOS ) + from.SendLocalizedMessage( 1060204 ); // You cannot poison that! You can only poison infectious weapons, food or drink. + else + from.SendLocalizedMessage( 502145 ); // You cannot poison that! You can only poison bladed or piercing weapons, food or drink. + } + } + + private class InternalTimer : Timer + { + private Mobile m_From; + private Item m_Target; + private Poison m_Poison; + private double m_MinSkill, m_MaxSkill; + + public InternalTimer( Mobile from, Item target, BasePoisonPotion potion ) : base( TimeSpan.FromSeconds( 2.0 ) ) + { + m_From = from; + m_Target = target; + m_Poison = potion.Poison; + m_MinSkill = potion.MinPoisoningSkill; + m_MaxSkill = potion.MaxPoisoningSkill; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if ( m_From.CheckTargetSkill( SkillName.Poisoning, m_Target, m_MinSkill, m_MaxSkill ) ) + { + if ( m_Target is Food ) + { + ((Food)m_Target).Poison = m_Poison; + } + //Ajout des Breuvages + else if (m_Target is BaseBeverage) + { + ((BaseBeverage)m_Target).Poison = m_Poison; + } + else if ( m_Target is BaseWeapon ) + { + ((BaseWeapon)m_Target).Poison = m_Poison; + ((BaseWeapon)m_Target).PoisonCharges = 18 - (m_Poison.Level * 2); + } + else if ( m_Target is FukiyaDarts ) + { + ((FukiyaDarts)m_Target).Poison = m_Poison; + ((FukiyaDarts)m_Target).PoisonCharges = Math.Min( 18 - (m_Poison.Level * 2), ((FukiyaDarts)m_Target).UsesRemaining ); + } + else if ( m_Target is Shuriken ) + { + ((Shuriken)m_Target).Poison = m_Poison; + ((Shuriken)m_Target).PoisonCharges = Math.Min( 18 - (m_Poison.Level * 2), ((Shuriken)m_Target).UsesRemaining ); + } + + m_From.SendLocalizedMessage( 1010517 ); // You apply the poison + + Misc.Titles.AwardKarma( m_From, -20, true ); + } + else // Failed + { + // 5% of chance of getting poisoned if failed + if ( m_From.Skills[SkillName.Poisoning].Base < 80.0 && Utility.Random( 20 ) == 0 ) + { + m_From.SendLocalizedMessage( 502148 ); // You make a grave mistake while applying the poison. + m_From.ApplyPoison( m_From, m_Poison ); + } + else + { + if ( m_Target is BaseWeapon ) + { + BaseWeapon weapon = (BaseWeapon)m_Target; + + if ( weapon.Type == WeaponType.Slashing ) + m_From.SendLocalizedMessage( 1010516 ); // You fail to apply a sufficient dose of poison on the blade + else + m_From.SendLocalizedMessage( 1010518 ); // You fail to apply a sufficient dose of poison + } + else + { + m_From.SendLocalizedMessage( 1010518 ); // You fail to apply a sufficient dose of poison + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Provocation.cs b/Scripts/Skills/Provocation.cs new file mode 100644 index 0000000..10c1fcc --- /dev/null +++ b/Scripts/Skills/Provocation.cs @@ -0,0 +1,164 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Items; + +namespace Server.SkillHandlers +{ + public class Provocation + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Provocation].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.RevealingAction(); + + BaseInstrument.PickInstrument( m, new InstrumentPickedCallback( OnPickedInstrument ) ); + + return TimeSpan.FromSeconds( 1.0 ); // Cannot use another skill for 1 second + } + + public static void OnPickedInstrument( Mobile from, BaseInstrument instrument ) + { + from.RevealingAction(); + from.SendLocalizedMessage( 501587 ); // Whom do you wish to incite? + from.Target = new InternalFirstTarget( from, instrument ); + } + + private class InternalFirstTarget : Target + { + private BaseInstrument m_Instrument; + + public InternalFirstTarget( Mobile from, BaseInstrument instrument ) : base( BaseInstrument.GetBardRange( from, SkillName.Provocation ), false, TargetFlags.None ) + { + m_Instrument = instrument; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + from.RevealingAction(); + + if ( targeted is BaseCreature && from.CanBeHarmful( (Mobile)targeted, true ) ) + { + BaseCreature creature = (BaseCreature)targeted; + + if ( !m_Instrument.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062488 ); // The instrument you are trying to play is no longer in your backpack! + } + else if ( creature.Controlled ) + { + from.SendLocalizedMessage( 501590 ); // They are too loyal to their master to be provoked. + } + else if ( creature.IsParagon && BaseInstrument.GetBaseDifficulty( creature ) >= 160.0 ) + { + from.SendLocalizedMessage( 1049446 ); // You have no chance of provoking those creatures. + } + else + { + from.RevealingAction(); + m_Instrument.PlayInstrumentWell( from ); + from.SendLocalizedMessage( 1008085 ); // You play your music and your target becomes angered. Whom do you wish them to attack? + from.Target = new InternalSecondTarget( from, m_Instrument, creature ); + } + } + else + { + from.SendLocalizedMessage( 501589 ); // You can't incite that! + } + } + } + + private class InternalSecondTarget : Target + { + private BaseCreature m_Creature; + private BaseInstrument m_Instrument; + + public InternalSecondTarget( Mobile from, BaseInstrument instrument, BaseCreature creature ) : base( BaseInstrument.GetBardRange( from, SkillName.Provocation ), false, TargetFlags.None ) + { + m_Instrument = instrument; + m_Creature = creature; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + from.RevealingAction(); + + if ( targeted is BaseCreature ) + { + BaseCreature creature = (BaseCreature)targeted; + + if ( !m_Instrument.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1062488 ); // The instrument you are trying to play is no longer in your backpack! + } + else if ( m_Creature.Unprovokable ) + { + from.SendLocalizedMessage( 1049446 ); // You have no chance of provoking those creatures. + } + else if ( creature.Unprovokable && !( creature is DemonKnight ) ) + { + from.SendLocalizedMessage( 1049446 ); // You have no chance of provoking those creatures. + } + else if ( m_Creature.Map != creature.Map || !m_Creature.InRange( creature, BaseInstrument.GetBardRange( from, SkillName.Provocation ) ) ) + { + from.SendLocalizedMessage( 1049450 ); // The creatures you are trying to provoke are too far away from each other for your music to have an effect. + } + else if ( m_Creature != creature ) + { + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + + double diff = ((m_Instrument.GetDifficultyFor( m_Creature ) + m_Instrument.GetDifficultyFor( creature )) * 0.5) - 5.0; + double music = from.Skills[SkillName.Musicianship].Value; + + if ( music > 100.0 ) + diff -= (music - 100.0) * 0.5; + + if ( from.CanBeHarmful( m_Creature, true ) && from.CanBeHarmful( creature, true ) ) + { + if ( !BaseInstrument.CheckMusicianship( from ) ) + { + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 5.0 ); + from.SendLocalizedMessage( 500612 ); // You play poorly, and there is no effect. + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else + { + //from.DoHarmful( m_Creature ); + //from.DoHarmful( creature ); + + if ( !from.CheckTargetSkill( SkillName.Provocation, creature, diff-25.0, diff+25.0 ) ) + { + from.NextSkillTime = DateTime.Now + TimeSpan.FromSeconds( 5.0 ); + from.SendLocalizedMessage( 501599 ); // Your music fails to incite enough anger. + m_Instrument.PlayInstrumentBadly( from ); + m_Instrument.ConsumeUse( from ); + } + else + { + from.SendLocalizedMessage( 501602 ); // Your music succeeds, as you start a fight. + m_Instrument.PlayInstrumentWell( from ); + m_Instrument.ConsumeUse( from ); + m_Creature.Provoke( from, creature, true ); + } + } + } + } + else + { + from.SendLocalizedMessage( 501593 ); // You can't tell someone to attack themselves! + } + } + else + { + from.SendLocalizedMessage( 501589 ); // You can't incite that! + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/RemoveTrap.cs b/Scripts/Skills/RemoveTrap.cs new file mode 100644 index 0000000..875e889 --- /dev/null +++ b/Scripts/Skills/RemoveTrap.cs @@ -0,0 +1,127 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; +using Server.Factions; + +namespace Server.SkillHandlers +{ + public class RemoveTrap + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.RemoveTrap].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + if ( m.Skills[SkillName.Lockpicking].Value < 50 ) + { + m.SendLocalizedMessage( 502366 ); // You do not know enough about locks. Become better at picking locks. + } + else if ( m.Skills[SkillName.DetectHidden].Value < 50 ) + { + m.SendLocalizedMessage( 502367 ); // You are not perceptive enough. Become better at detect hidden. + } + else + { + m.Target = new InternalTarget(); + + m.SendLocalizedMessage( 502368 ); // Wich trap will you attempt to disarm? + } + + return TimeSpan.FromSeconds( 10.0 ); // 10 second delay before beign able to re-use a skill + } + + private class InternalTarget : Target + { + public InternalTarget() : base ( 2, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + from.SendLocalizedMessage( 502816 ); // You feel that such an action would be inappropriate + } + else if ( targeted is TrapableContainer ) + { + TrapableContainer targ = (TrapableContainer)targeted; + + from.Direction = from.GetDirectionTo( targ ); + + if ( targ.TrapType == TrapType.None ) + { + from.SendLocalizedMessage( 502373 ); // That doesn't appear to be trapped + return; + } + + from.PlaySound( 0x241 ); + + if ( from.CheckTargetSkill( SkillName.RemoveTrap, targ, targ.TrapPower, targ.TrapPower + 30 ) ) + { + targ.TrapPower = 0; + targ.TrapLevel = 0; + targ.TrapType = TrapType.None; + from.SendLocalizedMessage( 502377 ); // You successfully render the trap harmless + } + else + { + from.SendLocalizedMessage( 502372 ); // You fail to disarm the trap... but you don't set it off + } + } + else if ( targeted is BaseFactionTrap ) + { + BaseFactionTrap trap = (BaseFactionTrap) targeted; + Faction faction = Faction.Find( from ); + + FactionTrapRemovalKit kit = ( from.Backpack == null ? null : from.Backpack.FindItemByType( typeof( FactionTrapRemovalKit ) ) as FactionTrapRemovalKit ); + + bool isOwner = ( trap.Placer == from || ( trap.Faction != null && trap.Faction.IsCommander( from ) ) ); + + if ( faction == null ) + { + from.SendLocalizedMessage( 1010538 ); // You may not disarm faction traps unless you are in an opposing faction + } + else if ( faction == trap.Faction && trap.Faction != null && !isOwner ) + { + from.SendLocalizedMessage( 1010537 ); // You may not disarm traps set by your own faction! + } + else if ( !isOwner && kit == null ) + { + from.SendLocalizedMessage( 1042530 ); // You must have a trap removal kit at the base level of your pack to disarm a faction trap. + } + else + { + if ( (Core.ML && isOwner) || (from.CheckTargetSkill( SkillName.RemoveTrap, trap, 80.0, 100.0 ) && from.CheckTargetSkill( SkillName.Tinkering, trap, 80.0, 100.0 )) ) + { + from.PrivateOverheadMessage( MessageType.Regular, trap.MessageHue, trap.DisarmMessage, from.NetState ); + + if ( !isOwner ) + { + int silver = faction.AwardSilver( from, trap.SilverFromDisarm ); + + if ( silver > 0 ) + from.SendLocalizedMessage( 1008113, true, silver.ToString( "N0" ) ); // You have been granted faction silver for removing the enemy trap : + } + + trap.Delete(); + } + else + { + from.SendLocalizedMessage( 502372 ); // You fail to disarm the trap... but you don't set it off + } + + if ( !isOwner && kit != null ) + kit.ConsumeCharge( from ); + } + } + else + { + from.SendLocalizedMessage( 502373 ); // That does'nt appear to be trapped + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Snooping.cs b/Scripts/Skills/Snooping.cs new file mode 100644 index 0000000..fa49d66 --- /dev/null +++ b/Scripts/Skills/Snooping.cs @@ -0,0 +1,108 @@ +using System; +using Server; +using Server.Misc; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Regions; + +namespace Server.SkillHandlers +{ + public class Snooping + { + public static void Configure() + { + Container.SnoopHandler = new ContainerSnoopHandler( Container_Snoop ); + } + + public static bool CheckSnoopAllowed( Mobile from, Mobile to ) + { + Map map = from.Map; + + if ( to.Player ) + return from.CanBeHarmful( to, false, true ); // normal restrictions + + if ( map != null && (map.Rules & MapRules.HarmfulRestrictions) == 0 ) + return true; // felucca you can snoop anybody + + GuardedRegion reg = (GuardedRegion) to.Region.GetRegion( typeof( GuardedRegion ) ); + + if ( reg == null || reg.IsDisabled() ) + return true; // not in town? we can snoop any npc + + BaseCreature cret = to as BaseCreature; + + if ( to.Body.IsHuman && (cret == null || (!cret.AlwaysAttackable && !cret.AlwaysMurderer)) ) + return false; // in town we cannot snoop blue human npcs + + return true; + } + + public static void Container_Snoop( Container cont, Mobile from ) + { + if ( from.AccessLevel > AccessLevel.Player || from.InRange( cont.GetWorldLocation(), 1 ) ) + { + Mobile root = cont.RootParent as Mobile; + + if ( root != null && !root.Alive ) + return; + + if ( root != null && root.AccessLevel > AccessLevel.Player && from.AccessLevel == AccessLevel.Player ) + { + from.SendLocalizedMessage( 500209 ); // You can not peek into the container. + return; + } + + if ( root != null && from.AccessLevel == AccessLevel.Player && !CheckSnoopAllowed( from, root ) ) + { + from.SendLocalizedMessage( 1001018 ); // You cannot perform negative acts on your target. + return; + } + + if ( root != null && from.AccessLevel == AccessLevel.Player && from.Skills[SkillName.Snooping].Value < Utility.Random( 100 ) ) + { + Map map = from.Map; + + if ( map != null ) + { + string message = String.Format( "You notice {0} attempting to peek into {1}'s belongings.", from.Name, root.Name ); + + IPooledEnumerable eable = map.GetClientsInRange( from.Location, 8 ); + + foreach ( NetState ns in eable ) + { + if (ns.Mobile != from && ns.Mobile.InLOS(from)) + ns.Mobile.SendMessage(message); + if (ns.Mobile != from && ns.Mobile.Skills[SkillName.DetectHidden].Value > from.Skills[SkillName.Hiding].Value - 20) + from.RevealingAction(); + } + + eable.Free(); + } + } + + if ( from.AccessLevel == AccessLevel.Player ) + Titles.AwardKarma( from, -4, true ); + + if ( from.AccessLevel > AccessLevel.Player || from.CheckTargetSkill( SkillName.Snooping, cont, 0.0, 100.0 ) ) + { + if ( cont is TrapableContainer && ((TrapableContainer)cont).ExecuteTrap( from ) ) + return; + + cont.DisplayTo( from ); + } + else + { + from.SendLocalizedMessage( 500210 ); // You failed to peek into the container. + + //if ( from.Skills[SkillName.Hiding].Value / 2 < Utility.Random( 100 ) ) + // from.RevealingAction(); + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/SpiritSpeak.cs b/Scripts/Skills/SpiritSpeak.cs new file mode 100644 index 0000000..a07666c --- /dev/null +++ b/Scripts/Skills/SpiritSpeak.cs @@ -0,0 +1,201 @@ +using System; +using Server; +using Server.Items; +using Server.Spells; +using Server.Network; + +namespace Server.SkillHandlers +{ + class SpiritSpeak + { + public static void Initialize() + { + SkillInfo.Table[32].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + if ( Core.AOS ) + { + Spell spell = new SpiritSpeakSpell( m ); + + spell.Cast(); + + if ( spell.IsCasting ) + return TimeSpan.FromSeconds( 5.0 ); + + return TimeSpan.Zero; + } + + m.RevealingAction(); + + if ( m.CheckSkill( SkillName.SpiritSpeak, 0, 100 ) ) + { + if ( !m.CanHearGhosts ) + { + Timer t = new SpiritSpeakTimer( m ); + double secs = m.Skills[SkillName.SpiritSpeak].Base / 50; + secs *= 90; + if ( secs < 15 ) + secs = 15; + + t.Delay = TimeSpan.FromSeconds( secs );//15seconds to 3 minutes + t.Start(); + m.CanHearGhosts = true; + } + + m.PlaySound( 0x24A ); + m.SendLocalizedMessage( 502444 );//You contact the neitherworld. + } + else + { + m.SendLocalizedMessage( 502443 );//You fail to contact the neitherworld. + m.CanHearGhosts = false; + } + + return TimeSpan.FromSeconds( 1.0 ); + } + + private class SpiritSpeakTimer : Timer + { + private Mobile m_Owner; + public SpiritSpeakTimer( Mobile m ) : base( TimeSpan.FromMinutes( 2.0 ) ) + { + m_Owner = m; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + m_Owner.CanHearGhosts = false; + m_Owner.SendLocalizedMessage( 502445 );//You feel your contact with the neitherworld fading. + } + } + + private class SpiritSpeakSpell : Spell + { + private static SpellInfo m_Info = new SpellInfo( "Spirit Speak", "", 269 ); + + public override bool BlockedByHorrificBeast{ get{ return false; } } + + public SpiritSpeakSpell( Mobile caster ) : base( caster, null, m_Info ) + { + } + + public override bool ClearHandsOnCast{ get{ return false; } } + + public override double CastDelayFastScalar { get { return 0; } } + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override int GetMana() + { + return 0; + } + + public override void OnCasterHurt() + { + if ( IsCasting ) + Disturb( DisturbType.Hurt, false, true ); + } + + public override bool ConsumeReagents() + { + return true; + } + + public override bool CheckFizzle() + { + return true; + } + + public override bool CheckNextSpellTime{ get{ return false; } } + + public override void OnDisturb( DisturbType type, bool message ) + { + Caster.NextSkillTime = DateTime.Now; + + base.OnDisturb( type, message ); + } + + public override bool CheckDisturb( DisturbType type, bool checkFirst, bool resistable ) + { + if ( type == DisturbType.EquipRequest || type == DisturbType.UseRequest ) + return false; + + return true; + } + + public override void SayMantra() + { + // Anh Mi Sah Ko + Caster.PublicOverheadMessage( MessageType.Regular, 0x3B2, 1062074, "", false ); + Caster.PlaySound( 0x24A ); + } + + public override void OnCast() + { + Corpse toChannel = null; + + foreach ( Item item in Caster.GetItemsInRange( 3 ) ) + { + if (item is Corpse && !((Corpse)item).Channeled) + { + toChannel = (Corpse)item; + break; + } + } + + int max, min, mana, number; + + if ( toChannel != null ) + { + min = 1 + (int)(Caster.Skills[SkillName.SpiritSpeak].Value * 0.25); + max = min + 4; + mana = 0; + number = 1061287; // You channel energy from a nearby corpse to heal your wounds. + } + else + { + min = 1 + (int)(Caster.Skills[SkillName.SpiritSpeak].Value * 0.25); + max = min + 4; + mana = 10; + number = 1061286; // You channel your own spiritual energy to heal your wounds. + } + + if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1061285 ); // You lack the mana required to use this skill. + } + else + { + Caster.CheckSkill( SkillName.SpiritSpeak, 0.0, 120.0 ); + + if ( Utility.RandomDouble() > (Caster.Skills[SkillName.SpiritSpeak].Value / 100.0) ) + { + Caster.SendLocalizedMessage( 502443 ); // You fail your attempt at contacting the netherworld. + } + else + { + if ( toChannel != null ) + { + toChannel.Channeled = true; + toChannel.Hue = 0x835; + } + + Caster.Mana -= mana; + Caster.SendLocalizedMessage( number ); + + if ( min > max ) + min = max; + + Caster.Hits += Utility.RandomMinMax( min, max ); + + Caster.FixedParticles( 0x375A, 1, 15, 9501, 2100, 4, EffectLayer.Waist ); + } + } + + FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Stealing.cs b/Scripts/Skills/Stealing.cs new file mode 100644 index 0000000..c9f6aaa --- /dev/null +++ b/Scripts/Skills/Stealing.cs @@ -0,0 +1,491 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; +using Server.Network; +using Server.Factions; +using Server.Spells.Seventh; +using Server.Spells.Fifth; +using Server.Spells.Necromancy; +using Server.Spells; +using Server.Spells.Ninjitsu; + +namespace Server.SkillHandlers +{ + public class Stealing + { + public static void Initialize() + { + SkillInfo.Table[33].Callback = new SkillUseCallback( OnUse ); + } + + public static readonly bool ClassicMode = false; + public static readonly bool SuspendOnMurder = false; + + public static bool IsInGuild( Mobile m ) + { + return ( m is PlayerMobile && ((PlayerMobile)m).NpcGuild == NpcGuild.ThievesGuild ); + } + + public static bool IsInnocentTo( Mobile from, Mobile to ) + { + return ( Notoriety.Compute( from, (Mobile)to ) == Notoriety.Innocent ); + } + + private class StealingTarget : Target + { + private Mobile m_Thief; + + public StealingTarget( Mobile thief ) : base ( 1, false, TargetFlags.None ) + { + m_Thief = thief; + + AllowNonlocal = true; + } + + private Item TryStealItem( Item toSteal, ref bool caught ) + { + Item stolen = null; + + object root = toSteal.RootParent; + + StealableArtifactsSpawner.StealableInstance si = null; + if ( toSteal.Parent == null || !toSteal.Movable ) + si = StealableArtifactsSpawner.GetStealableInstance( toSteal ); + + // Scriptiz : les objets marqu�s non stealables ne peuvent �tre vol�s ! + if (toSteal != null && !toSteal.Stealable) + { + m_Thief.SendMessage("Vous ne pouvez pas voler cet objet."); + } + else if ( !IsEmptyHanded( m_Thief ) ) + { + m_Thief.SendLocalizedMessage( 1005584 ); // Both hands must be free to steal. + } + else if (root is Mobile && ((Mobile)root).Player && !IsInGuild(m_Thief)) + { + m_Thief.SendLocalizedMessage( 1005596 ); // You must be in the thieves guild to steal from other players. + } + else if ( SuspendOnMurder && root is Mobile && ((Mobile)root).Player && IsInGuild( m_Thief ) && m_Thief.Kills > 0 ) + { + m_Thief.SendLocalizedMessage( 502706 ); // You are currently suspended from the thieves guild. + } + else if ( root is BaseVendor && ((BaseVendor)root).IsInvulnerable ) + { + m_Thief.SendLocalizedMessage( 1005598 ); // You can't steal from shopkeepers. + } + else if ( root is PlayerVendor ) + { + m_Thief.SendLocalizedMessage( 502709 ); // You can't steal from vendors. + } + else if ( !m_Thief.CanSee( toSteal ) ) + { + m_Thief.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( m_Thief.Backpack == null || !m_Thief.Backpack.CheckHold( m_Thief, toSteal, false, true ) ) + { + m_Thief.SendLocalizedMessage( 1048147 ); // Your backpack can't hold anything else. + } + #region Sigils + else if ( toSteal is Sigil ) + { + PlayerState pl = PlayerState.Find( m_Thief ); + Faction faction = ( pl == null ? null : pl.Faction ); + + Sigil sig = (Sigil) toSteal; + + if ( !m_Thief.InRange( toSteal.GetWorldLocation(), 1 ) ) + { + m_Thief.SendLocalizedMessage( 502703 ); // You must be standing next to an item to steal it. + } + else if ( root != null ) // not on the ground + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + else if ( faction != null ) + { + if ( !m_Thief.CanBeginAction( typeof( IncognitoSpell ) ) ) + { + m_Thief.SendLocalizedMessage( 1010581 ); // You cannot steal the sigil when you are incognito + } + else if ( DisguiseTimers.IsDisguised( m_Thief ) ) + { + m_Thief.SendLocalizedMessage( 1010583 ); // You cannot steal the sigil while disguised + } + else if ( !m_Thief.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + m_Thief.SendLocalizedMessage( 1010582 ); // You cannot steal the sigil while polymorphed + } + else if( TransformationSpellHelper.UnderTransformation( m_Thief ) ) + { + m_Thief.SendLocalizedMessage( 1061622 ); // You cannot steal the sigil while in that form. + } + else if ( AnimalForm.UnderTransformation( m_Thief ) ) + { + m_Thief.SendLocalizedMessage( 1063222 ); // You cannot steal the sigil while mimicking an animal. + } + else if ( pl.IsLeaving ) + { + m_Thief.SendLocalizedMessage( 1005589 ); // You are currently quitting a faction and cannot steal the town sigil + } + else if ( sig.IsBeingCorrupted && sig.LastMonolith.Faction == faction ) + { + m_Thief.SendLocalizedMessage( 1005590 ); // You cannot steal your own sigil + } + else if ( sig.IsPurifying ) + { + m_Thief.SendLocalizedMessage( 1005592 ); // You cannot steal this sigil until it has been purified + } + else if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, 80.0, 80.0 ) ) + { + if ( Sigil.ExistsOn( m_Thief ) ) + { + m_Thief.SendLocalizedMessage( 1010258 ); // The sigil has gone back to its home location because you already have a sigil. + } + else if ( m_Thief.Backpack == null || !m_Thief.Backpack.CheckHold( m_Thief, sig, false, true ) ) + { + m_Thief.SendLocalizedMessage( 1010259 ); // The sigil has gone home because your backpack is full + } + else + { + if ( sig.IsBeingCorrupted ) + sig.GraceStart = DateTime.Now; // begin grace period + + m_Thief.SendLocalizedMessage( 1010586 ); // YOU STOLE THE SIGIL!!! (woah, calm down now) + + if ( sig.LastMonolith != null && sig.LastMonolith.Sigil != null ) { + sig.LastMonolith.Sigil = null; + sig.LastStolen = DateTime.Now; + } + + return sig; + } + } + else + { + m_Thief.SendLocalizedMessage( 1005594 ); // You do not have enough skill to steal the sigil + } + } + else + { + m_Thief.SendLocalizedMessage( 1005588 ); // You must join a faction to do that + } + } + #endregion + else if ( si == null && ( toSteal.Parent == null || !toSteal.Movable ) ) + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + else if ( toSteal.LootType == LootType.Newbied || toSteal.CheckBlessed( root ) ) + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + else if ( Core.AOS && si == null && toSteal is Container ) + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + else if ( !m_Thief.InRange( toSteal.GetWorldLocation(), 1 ) ) + { + m_Thief.SendLocalizedMessage( 502703 ); // You must be standing next to an item to steal it. + } + else if ( si != null && m_Thief.Skills[SkillName.Stealing].Value < 100.0 ) + { + m_Thief.SendLocalizedMessage( 1060025, "", 0x66D ); // You're not skilled enough to attempt the theft of this item. + } + else if ( toSteal.Parent is Mobile ) + { + m_Thief.SendLocalizedMessage( 1005585 ); // You cannot steal items which are equiped. + } + else if ( root == m_Thief ) + { + m_Thief.SendLocalizedMessage( 502704 ); // You catch yourself red-handed. + } + else if ( root is Mobile && ((Mobile)root).AccessLevel > AccessLevel.Player ) + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + else if ( root is Mobile && !m_Thief.CanBeHarmful( (Mobile)root ) ) + { + } + else if ( root is Corpse ) + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + else + { + double w = toSteal.Weight + toSteal.TotalWeight; + + if ( w > 10 ) + { + m_Thief.SendMessage( "That is too heavy to steal." ); + } + else + { + if ( toSteal.Stackable && toSteal.Amount > 1 ) + { + int maxAmount = (int)((m_Thief.Skills[SkillName.Stealing].Value / 10.0) / toSteal.Weight); + + if ( maxAmount < 1 ) + maxAmount = 1; + else if ( maxAmount > toSteal.Amount ) + maxAmount = toSteal.Amount; + + int amount = Utility.RandomMinMax( 1, maxAmount ); + + if ( amount >= toSteal.Amount ) + { + int pileWeight = (int)Math.Ceiling( toSteal.Weight * toSteal.Amount ); + pileWeight *= 10; + + if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, pileWeight - 22.5, pileWeight + 27.5 ) ) + stolen = toSteal; + } + else + { + int pileWeight = (int)Math.Ceiling( toSteal.Weight * amount ); + pileWeight *= 10; + + if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, pileWeight - 22.5, pileWeight + 27.5 ) ) + { + stolen = Mobile.LiftItemDupe( toSteal, toSteal.Amount - amount ); + + if ( stolen == null ) + stolen = toSteal; + } + } + } + else + { + int iw = (int)Math.Ceiling( w ); + iw *= 10; + + if ( m_Thief.CheckTargetSkill( SkillName.Stealing, toSteal, iw - 22.5, iw + 27.5 ) ) + stolen = toSteal; + } + + if ( stolen != null ) + { + m_Thief.SendLocalizedMessage( 502724 ); // You succesfully steal the item. + + if ( si != null ) + { + toSteal.Movable = true; + si.Item = null; + } + } + else + { + m_Thief.SendLocalizedMessage( 502723 ); // You fail to steal the item. + } + + caught = ( m_Thief.Skills[SkillName.Stealing].Value < Utility.Random( 150 ) ); + } + } + + return stolen; + } + + protected override void OnTarget( Mobile from, object target ) + { + if ((int)from.Skills[SkillName.Stealing].Value < 99) + from.RevealingAction(); + + Item stolen = null; + object root = null; + bool caught = false; + + if ( target is Item ) + { + root = ((Item)target).RootParent; + stolen = TryStealItem( (Item)target, ref caught ); + } + else if ( target is Mobile ) + { + + Container pack = ((Mobile)target).Backpack; + + if ( pack != null && pack.Items.Count > 0 ) + { + int randomIndex = Utility.Random( pack.Items.Count ); + + root = target; + stolen = TryStealItem( pack.Items[randomIndex], ref caught ); + } + } + else + { + m_Thief.SendLocalizedMessage( 502710 ); // You can't steal that! + } + + if ( stolen != null ) + { + from.AddToBackpack( stolen ); + + StolenItem.Add( stolen, m_Thief, root as Mobile ); + } + + if ( caught ) + { + // Si le voleur est prit, on le r�v�le ! + m_Thief.RevealingAction(); + + if ( root == null ) + { + m_Thief.CriminalAction( false ); + } + else if ( root is Corpse && ((Corpse)root).IsCriminalAction( m_Thief ) ) + { + m_Thief.CriminalAction( false ); + } + else if ( root is Mobile ) + { + Mobile mobRoot = (Mobile)root; + + if ( !IsInGuild( mobRoot ) && IsInnocentTo( m_Thief, mobRoot ) ) + m_Thief.CriminalAction( false ); + + string message = String.Format( "You notice {0} trying to steal from {1}.", m_Thief.Name, mobRoot.Name ); + + foreach ( NetState ns in m_Thief.GetClientsInRange( 8 ) ) + { + if ( ns.Mobile != m_Thief && ns.Mobile.InLOS(m_Thief)) + ns.Mobile.SendMessage( message ); + if (ns.Mobile != m_Thief && ns.Mobile.Skills[SkillName.DetectHidden].Value > m_Thief.Skills[SkillName.Hiding].Value - 20) + m_Thief.RevealingAction(); + } + } + } + else if ( root is Corpse && ((Corpse)root).IsCriminalAction( m_Thief ) ) + { + m_Thief.CriminalAction( false ); + } + + if ( root is Mobile && ((Mobile)root).Player && m_Thief is PlayerMobile && IsInnocentTo( m_Thief, (Mobile)root ) && !IsInGuild( (Mobile)root ) ) + { + PlayerMobile pm = (PlayerMobile)m_Thief; + + pm.PermaFlags.Add( (Mobile)root ); + pm.Delta( MobileDelta.Noto ); + } + } + } + + public static bool IsEmptyHanded( Mobile from ) + { + if ( from.FindItemOnLayer( Layer.OneHanded ) != null ) + return false; + + if ( from.FindItemOnLayer( Layer.TwoHanded ) != null ) + return false; + + return true; + } + + public static TimeSpan OnUse( Mobile m ) + { + if ( !IsEmptyHanded( m ) ) + { + m.SendLocalizedMessage( 1005584 ); // Both hands must be free to steal. + } + else + { + m.Target = new Stealing.StealingTarget( m ); + + m.SendLocalizedMessage( 502698 ); // Which item do you want to steal? + } + + return TimeSpan.FromSeconds( 10.0 ); + } + } + + public class StolenItem + { + public static readonly TimeSpan StealTime = TimeSpan.FromMinutes( 2.0 ); + + private Item m_Stolen; + private Mobile m_Thief; + private Mobile m_Victim; + private DateTime m_Expires; + + public Item Stolen{ get{ return m_Stolen; } } + public Mobile Thief{ get{ return m_Thief; } } + public Mobile Victim{ get{ return m_Victim; } } + public DateTime Expires{ get{ return m_Expires; } } + + public bool IsExpired{ get{ return ( DateTime.Now >= m_Expires ); } } + + public StolenItem( Item stolen, Mobile thief, Mobile victim ) + { + m_Stolen = stolen; + m_Thief = thief; + m_Victim = victim; + + m_Expires = DateTime.Now + StealTime; + } + + private static Queue m_Queue = new Queue(); + + public static void Add( Item item, Mobile thief, Mobile victim ) + { + Clean(); + + m_Queue.Enqueue( new StolenItem( item, thief, victim ) ); + } + + public static bool IsStolen( Item item ) + { + Mobile victim = null; + + return IsStolen( item, ref victim ); + } + + public static bool IsStolen( Item item, ref Mobile victim ) + { + Clean(); + + foreach ( StolenItem si in m_Queue ) + { + if ( si.m_Stolen == item && !si.IsExpired ) + { + victim = si.m_Victim; + return true; + } + } + + return false; + } + + public static void ReturnOnDeath( Mobile killed, Container corpse ) + { + Clean(); + + foreach ( StolenItem si in m_Queue ) + { + if ( si.m_Stolen.RootParent == corpse && si.m_Victim != null && !si.IsExpired ) + { + if ( si.m_Victim.AddToBackpack( si.m_Stolen ) ) + si.m_Victim.SendLocalizedMessage( 1010464 ); // the item that was stolen is returned to you. + else + si.m_Victim.SendLocalizedMessage( 1010463 ); // the item that was stolen from you falls to the ground. + + si.m_Expires = DateTime.Now; // such a hack + } + } + } + + public static void Clean() + { + while ( m_Queue.Count > 0 ) + { + StolenItem si = (StolenItem) m_Queue.Peek(); + + if ( si.IsExpired ) + m_Queue.Dequeue(); + else + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Stealth.cs b/Scripts/Skills/Stealth.cs new file mode 100644 index 0000000..50034f1 --- /dev/null +++ b/Scripts/Skills/Stealth.cs @@ -0,0 +1,159 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.SkillHandlers +{ + public class Stealth + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Stealth].Callback = new SkillUseCallback( OnUse ); + } + + public static double HidingRequirement { get { return (Core.ML ? 30.0 : (Core.SE ? 50.0 : 80.0)); } } + + public static int[,] ArmorTable { get { return m_ArmorTable; } } + private static int[,] m_ArmorTable = new int[,] + { + // Gorget Gloves Helmet Arms Legs Chest Shield + /* Cloth */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Leather */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Studded */ { 2, 2, 0, 4, 6, 10, 0 }, + /* Bone */ { 0, 5, 10, 10, 15, 25, 0 }, + /* Spined */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Horned */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Barbed */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Daemon? */ { 0, 0, 0, 0, 0, 0, 0 }, + /* Ring */ { 0, 5, 0, 10, 15, 25, 0 }, + /* Chain */ { 0, 0, 10, 0, 15, 25, 0 }, + /* Plate */ { 5, 5, 10, 10, 15, 25, 0 }, + /* Dragon */ { 0, 5, 10, 10, 15, 25, 0 } + }; + + public static int GetArmorRating( Mobile m ) + { + if( !Core.AOS ) + return (int)m.ArmorRating; + + int ar = 0; + + for( int i = 0; i < m.Items.Count; i++ ) + { + BaseArmor armor = m.Items[i] as BaseArmor; + + if( armor == null ) + continue; + + int materialType = (int)armor.MaterialType; + int bodyPosition = (int)armor.BodyPosition; + + if( materialType >= m_ArmorTable.GetLength( 0 ) || bodyPosition >= m_ArmorTable.GetLength( 1 ) ) + continue; + + if( armor.ArmorAttributes.MageArmor == 0 ) + ar += m_ArmorTable[materialType, bodyPosition]; + } + + return ar; + } + + public static int GetDifficulty(Mobile m) + { + int counter = 0; + foreach (Mobile mob in m.GetMobilesInRange(8)) + { + if (mob.BodyValue == 400 || mob.BodyValue == 401) + { + //Chaque PJ ou NPC compte pour 1 + if (mob != m && mob.Alive && mob.AccessLevel == AccessLevel.Player && mob.InLOS(m)) + { + counter++; + + //Un garde compte pour 2 + if (mob is VivreGuard) + counter++; + + //Un petit ajout pour le tracker + if (mob.Skills[SkillName.Tracking].Value > 80) + counter++; + + //Petit bonus pour DH + if (mob.Skills[SkillName.DetectHidden].Value > (m.Skills[SkillName.Hiding].Value - 10)) + counter += Utility.Random (1, 5); + } + } + } + + //Pour aider les Wraith Form + if (m.BodyValue == 747 || m.BodyValue == 748) + counter = (int)Math.Round(counter / 2.0); + + return counter; + } + + public static TimeSpan OnUse( Mobile m ) + { + if ( !m.Hidden ) + { + m.SendLocalizedMessage( 502725 ); // You must hide first + } + else if (m.Skills[SkillName.Hiding].Base < HidingRequirement) + { + m.SendLocalizedMessage( 502726 ); // You are not hidden well enough. Become better at hiding. + m.RevealingAction(); + } + else if( !m.CanBeginAction( typeof( Stealth ) ) ) + { + m.SendLocalizedMessage( 1063086 ); // You cannot use this skill right now. + m.RevealingAction(); + } + else + { + int difficulty = GetDifficulty(m); + int armorRating = GetArmorRating( m ); + + if (armorRating >= (Core.AOS ? 42 : 26)) //I have a hunch '42' was chosen cause someone's a fan of DNA + { + m.SendLocalizedMessage( 502727 ); // You could not hope to move quietly wearing this much armor. + m.RevealingAction(); + } + else if ((m.CheckSkill(SkillName.Stealth, -20.0 + (armorRating * 2), (Core.AOS ? 60.0 : 80.0) + (armorRating * 2))) && ((m.Skills[SkillName.Stealth].Value - difficulty) > Utility.Random(0, (int)m.Skills[SkillName.Stealth].Value))) + { + int steps = (int)(m.Skills[SkillName.Stealth].Value / (Core.AOS ? 5.0 : 10.0)); + + if( steps < 1 ) + steps = 1; + + m.AllowedStealthSteps = steps; + + + // ------ NERUN's DISTRO - Orc Scout bug fix ----- + if ( m is PlayerMobile ) + { + PlayerMobile pm = m as PlayerMobile; // IsStealthing should be moved to Server.Mobiles + pm.IsStealthing = true; + } +/* + PlayerMobile pm = m as PlayerMobile; // IsStealthing should be moved to Server.Mobiles + + if( pm != null ) + pm.IsStealthing = true; +*/ +// ------ END + + m.SendLocalizedMessage( 502730 ); // You begin to move quietly. + + return TimeSpan.FromSeconds( 10.0 ); + } + else + { + m.SendLocalizedMessage( 502731 ); // You fail in your attempt to move unnoticed. + m.RevealingAction(); + } + } + + return TimeSpan.FromSeconds( 10.0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/TasteID.cs b/Scripts/Skills/TasteID.cs new file mode 100644 index 0000000..f5a2918 --- /dev/null +++ b/Scripts/Skills/TasteID.cs @@ -0,0 +1,159 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; +using Server.Mobiles; + +namespace Server.SkillHandlers +{ + public class TasteID + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.TasteID].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.Target = new InternalTarget(); + + m.SendMessage( "Que souhaitez-vous go�ter?" ); // What would you like to taste? + + return TimeSpan.FromSeconds( 1.0 ); + } + + [PlayerVendorTarget] + private class InternalTarget : Target + { + public InternalTarget() : base ( 2, false, TargetFlags.None ) + { + AllowNonlocal = true; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile ) + { + from.SendMessage( "Une telle action serait inappropri�e..." ); // You feel that such an action would be inappropriate. + return; + } + if (targeted is CookableCheese) + { + Food food = (Food)targeted; + + if (from.CheckTargetSkill(SkillName.TasteID, food, 0, 100)) + { + if (food.Poison != null) + { + from.SendMessage("Des effluves de poison parviennent � votre nez"); // It appears to have poison smeared on it. + } + else + { + // No poison on the food + from.SendMessage("Vous ne d�celez rien d'anormal dans ce que vous go�tez"); // You detect nothing unusual about this substance. + } + } + else + { + // Skill check failed + from.SendMessage("Vous ne discernez pas correctement les aromes"); // You cannot discern anything about this substance. + } + return; + } + + if ( targeted is Food ) + { + Food food = (Food) targeted; + + if ( from.CheckTargetSkill( SkillName.TasteID, food, 0, 100 ) ) + { + if ( food.Poison != null ) + { + from.SendMessage( "Des effluves de poison parviennent � votre nez" ); // It appears to have poison smeared on it. + } + else + { + // No poison on the food + from.SendMessage( "Vous ne d�celez rien d'anormal dans ce que vous go�tez"); // You detect nothing unusual about this substance. + } + } + else + { + // Skill check failed + from.SendMessage( "Vous ne discernez pas correctement les aromes" ); // You cannot discern anything about this substance. + } + return; + } + if (targeted is BaseBeverage) + { + BaseBeverage beverage = (BaseBeverage)targeted; + + if (from.CheckTargetSkill(SkillName.TasteID, beverage, 0, 100)) + { + if (beverage.Poison != null) + { + from.SendMessage("Des effluves de poison parviennent � votre nez"); // It appears to have poison smeared on it. + } + else + { + // No poison on the food + from.SendMessage("Vous ne d�celez rien d'anormal dans ce que vous go�tez"); // You detect nothing unusual about this substance. + } + } + else + { + // Skill check failed + from.SendMessage("Vous ne discernez pas correctement les aromes"); // You cannot discern anything about this substance. + } + return; + } + if (targeted is GenderPotion) + { + GenderPotion potion = (GenderPotion)targeted; + + if (from.Skills[SkillName.TasteID].Value >= 75) + { + if (potion.Female) + from.SendMessage("Cette fiole sent les fleurs"); + else + from.SendMessage("Cette fiole sent la sueur"); + } + else + from.SendMessage("Votre nez n'est pas encore suffisamment d�velopp� pour en d�noter la subtile effluve"); + return; + } + if ( targeted is BasePotion ) + { + BasePotion potion = (BasePotion) targeted; + + potion.SendLocalizedMessageTo( from, 502813 ); // You already know what kind of potion that is. + potion.SendLocalizedMessageTo( from, potion.LabelNumber ); + return; + } + if ( targeted is PotionKeg ) + { + PotionKeg keg = (PotionKeg) targeted; + + if ( keg.Held <= 0 ) + { + keg.SendLocalizedMessageTo( from, 502228 ); // There is nothing in the keg to taste! + } + else + { + keg.SendLocalizedMessageTo( from, 502229 ); // You are already familiar with this keg's contents. + keg.SendLocalizedMessageTo( from, keg.LabelNumber ); + } + return; + } + // The target is not food or potion or potion keg. + from.SendLocalizedMessage( 502820 ); // That's not something you can taste. + + } + + protected override void OnTargetOutOfRange( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 502815 ); // You are too far away to taste that. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Skills/Tracking.cs b/Scripts/Skills/Tracking.cs new file mode 100644 index 0000000..9a0b953 --- /dev/null +++ b/Scripts/Skills/Tracking.cs @@ -0,0 +1,400 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Spells.Necromancy; +using Server.Spells; + +namespace Server.SkillHandlers +{ + public class Tracking + { + public static void Initialize() + { + SkillInfo.Table[(int)SkillName.Tracking].Callback = new SkillUseCallback( OnUse ); + } + + public static TimeSpan OnUse( Mobile m ) + { + m.SendMessage( "Que d�sirez-vous traquer?" ); // What do you wish to track? + + m.CloseGump( typeof( TrackWhatGump ) ); + m.CloseGump( typeof( TrackWhoGump ) ); + m.SendGump( new TrackWhatGump( m ) ); + + return TimeSpan.FromSeconds( 10.0 ); // 10 second delay before beign able to re-use a skill + } + + public class TrackingInfo + { + public Mobile m_Tracker; + public Mobile m_Target; + public Point2D m_Location; + public Map m_Map; + + public TrackingInfo( Mobile tracker, Mobile target ) + { + m_Tracker = tracker; + m_Target = target; + m_Location = new Point2D( target.X, target.Y ); + m_Map = target.Map; + } + } + + private static Dictionary m_Table = new Dictionary(); + + public static void AddInfo( Mobile tracker, Mobile target ) + { + TrackingInfo info = new TrackingInfo( tracker, target ); + m_Table[tracker] = info; + } + + public static double GetStalkingBonus( Mobile tracker, Mobile target ) + { + TrackingInfo info = null; + m_Table.TryGetValue( tracker, out info ); + + if ( info == null || info.m_Target != target || info.m_Map != target.Map ) + return 0.0; + + int xDelta = info.m_Location.X - target.X; + int yDelta = info.m_Location.Y - target.Y; + + double bonus = Math.Sqrt( (xDelta * xDelta) + (yDelta * yDelta) ); + + m_Table.Remove( tracker ); //Reset as of Pub 40, counting it as bug for Core.SE. + + if( Core.ML ) + return Math.Min( bonus, 10 + tracker.Skills.Tracking.Value/10 ); + + return bonus; + } + + + public static void ClearTrackingInfo( Mobile tracker ) + { + m_Table.Remove( tracker ); + } + } + + public class TrackWhatGump : Gump + { + private Mobile m_From; + private bool m_Success; + + public TrackWhatGump( Mobile from ) : base( 20, 30 ) + { + m_From = from; + m_Success = from.CheckSkill( SkillName.Tracking, 0.0, 21.1 ); + + AddPage( 0 ); + + AddBackground( 0, 0, 440, 135, 5054 ); + + AddBackground( 10, 10, 420, 75, 2620 ); + AddBackground( 10, 85, 420, 25, 3000 ); + + AddItem( 20, 20, 9682 ); + AddButton( 20, 110, 4005, 4007, 1, GumpButtonType.Reply, 0 ); + AddHtml( 20, 90, 100, 20, "Animaux", false, false ); // Animals + + AddItem( 120, 20, 9607 ); + AddButton( 120, 110, 4005, 4007, 2, GumpButtonType.Reply, 0 ); + AddHtml( 120, 90, 100, 20, "Monstres", false, false ); // Monsters + + AddItem( 220, 20, 8454 ); + AddButton( 220, 110, 4005, 4007, 3, GumpButtonType.Reply, 0 ); + AddHtml( 220, 90, 100, 20, "PNJs Humains", false, false ); // Human NPCs + + AddItem( 320, 20, 8455 ); + AddButton( 320, 110, 4005, 4007, 4, GumpButtonType.Reply, 0 ); + AddHtml( 320, 90, 100, 20, "Joueurs", false, false ); // Players + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + if ( info.ButtonID >= 1 && info.ButtonID <= 4 ) + TrackWhoGump.DisplayTo( m_Success, m_From, info.ButtonID - 1 ); + } + } + + public delegate bool TrackTypeDelegate( Mobile m ); + + public class TrackWhoGump : Gump + { + private Mobile m_From; + private int m_Range; + + private static TrackTypeDelegate[] m_Delegates = new TrackTypeDelegate[] + { + new TrackTypeDelegate( IsAnimal ), + new TrackTypeDelegate( IsMonster ), + new TrackTypeDelegate( IsHumanNPC ), + new TrackTypeDelegate( IsPlayer ) + }; + + private class InternalSorter : IComparer + { + private Mobile m_From; + + public InternalSorter( Mobile from ) + { + m_From = from; + } + + public int Compare( Mobile x, Mobile y ) + { + if ( x == null && y == null ) + return 0; + else if ( x == null ) + return -1; + else if ( y == null ) + return 1; + + return m_From.GetDistanceToSqrt( x ).CompareTo( m_From.GetDistanceToSqrt( y ) ); + } + } + + public static void DisplayTo( bool success, Mobile from, int type ) + { + if ( !success ) + { + from.SendMessage( "Vous ne d�cernez aucune trace dans les environs" ); // You see no evidence of those in the area. + return; + } + + Map map = from.Map; + + if ( map == null ) + return; + + TrackTypeDelegate check = m_Delegates[type]; + + from.CheckSkill( SkillName.Tracking, 21.1, 100.0 ); // Passive gain + + int range = 10 + (int)(from.Skills[SkillName.Tracking].Value / 10); + + List list = new List(); + + foreach ( Mobile m in from.GetMobilesInRange( range ) ) + { + // Ghosts can no longer be tracked + if ( m != from && (!Core.AOS || m.Alive) && (!m.Hidden || m.AccessLevel == AccessLevel.Player || from.AccessLevel > m.AccessLevel) && check( m ) && CheckDifficulty( from, m ) ) + list.Add( m ); + } + + if ( list.Count > 0 ) + { + list.Sort( new InternalSorter( from ) ); + + from.SendGump( new TrackWhoGump( from, list, range ) ); + from.SendMessage( "S�lectionnerz la piste � suivre" ); // Select the one you would like to track. + } + else + { + if ( type == 0 ) + from.SendMessage( "Vous ne d�celez aucune piste animale dans les environs" ); // You see no evidence of animals in the area. + else if ( type == 1 ) + from.SendMessage( "Vous ne d�celez aucune piste inhabituelle dans les environs" ); // You see no evidence of creatures in the area. + else + from.SendMessage( "Vous ne d�celez aucune pr�sence humaine dans les environs" ); // You see no evidence of people in the area. + } + } + + // Tracking players uses tracking and detect hidden vs. hiding and stealth + private static bool CheckDifficulty( Mobile from, Mobile m ) + { + if ( !Core.AOS || !m.Player ) + return true; + + + + int tracking = from.Skills[SkillName.Tracking].Fixed; + int detectHidden = from.Skills[SkillName.DetectHidden].Fixed; + + if( Core.ML && m.Race == Race.Elf ) + tracking /= 2; //The 'Guide' says that it requires twice as Much tracking SKILL to track an elf. Not the total difficulty to track. + + int hiding = m.Skills[SkillName.Hiding].Fixed; + int stealth = m.Skills[SkillName.Stealth].Fixed; + int divisor = hiding + stealth; + + // Necromancy forms affect tracking difficulty + if ( TransformationSpellHelper.UnderTransformation( m, typeof( HorrificBeastSpell ) ) ) + divisor -= 200; + else if ( TransformationSpellHelper.UnderTransformation( m, typeof( VampiricEmbraceSpell ) ) && divisor < 500 ) + divisor = 500; + else if ( TransformationSpellHelper.UnderTransformation( m, typeof( WraithFormSpell ) ) && divisor <= 2000 ) + divisor += 200; + + int chance; + if ( divisor > 0 ) + { + if ( Core.SE ) + chance = 50 * (tracking * 2 + detectHidden) / divisor; + else + chance = 50 * (tracking + detectHidden + 10 * Utility.RandomMinMax( 1, 20 )) / divisor; + } + else + chance = 100; + + return chance > Utility.Random( 100 ); + } + + private static bool IsAnimal( Mobile m ) + { + return ( !m.Player && m.Body.IsAnimal ); + } + + private static bool IsMonster( Mobile m ) + { + return ( !m.Player && m.Body.IsMonster ); + } + + private static bool IsHumanNPC( Mobile m ) + { + return ( !m.Player && m.Body.IsHuman ); + } + + private static bool IsPlayer( Mobile m ) + { + return m.Player; + } + + private List m_List; + + private TrackWhoGump( Mobile from, List list, int range ) : base( 20, 30 ) + { + m_From = from; + m_List = list; + m_Range = range; + + AddPage( 0 ); + + AddBackground( 0, 0, 440, 155, 5054 ); + + AddBackground( 10, 10, 420, 75, 2620 ); + AddBackground( 10, 85, 420, 45, 3000 ); + + if ( list.Count > 4 ) + { + AddBackground( 0, 155, 440, 155, 5054 ); + + AddBackground( 10, 165, 420, 75, 2620 ); + AddBackground( 10, 240, 420, 45, 3000 ); + + if ( list.Count > 8 ) + { + AddBackground( 0, 310, 440, 155, 5054 ); + + AddBackground( 10, 320, 420, 75, 2620 ); + AddBackground( 10, 395, 420, 45, 3000 ); + } + } + + for ( int i = 0; i < list.Count && i < 12; ++i ) + { + Mobile m = list[i]; + + AddItem( 20 + ((i % 4) * 100), 20 + ((i / 4) * 155), ShrinkTable.Lookup( m ) ); + AddButton( 20 + ((i % 4) * 100), 130 + ((i / 4) * 155), 4005, 4007, i + 1, GumpButtonType.Reply, 0 ); + + if ( m.Name != null ) + AddHtml( 20 + ((i % 4) * 100), 90 + ((i / 4) * 155), 90, 40, m.Name, false, false ); + } + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_List.Count && index < 12 ) + { + Mobile m = m_List[index]; + + m_From.QuestArrow = new TrackArrow( m_From, m, m_Range * 2 ); + + if ( Core.SE ) + Tracking.AddInfo( m_From, m ); + } + } + } + + public class TrackArrow : QuestArrow + { + private Mobile m_From; + private Timer m_Timer; + + public TrackArrow( Mobile from, Mobile target, int range ) : base( from, target ) + { + m_From = from; + m_Timer = new TrackTimer( from, target, range, this ); + m_Timer.Start(); + } + + public override void OnClick( bool rightClick ) + { + if ( rightClick ) + { + Tracking.ClearTrackingInfo( m_From ); + + m_From = null; + + Stop(); + } + } + + public override void OnStop() + { + m_Timer.Stop(); + + if ( m_From != null ) + { + Tracking.ClearTrackingInfo( m_From ); + + m_From.SendMessage( "Vous avez perdu la piste de ce que vous suiviez" ); // You have lost your quarry. + } + } + } + + public class TrackTimer : Timer + { + private Mobile m_From, m_Target; + private int m_Range; + private int m_LastX, m_LastY; + private QuestArrow m_Arrow; + + public TrackTimer( Mobile from, Mobile target, int range, QuestArrow arrow ) : base( TimeSpan.FromSeconds( 0.25 ), TimeSpan.FromSeconds( 2.5 ) ) + { + m_From = from; + m_Target = target; + m_Range = range; + + m_Arrow = arrow; + } + + protected override void OnTick() + { + if ( !m_Arrow.Running ) + { + Stop(); + return; + } + else if ( m_From.NetState == null || m_From.Deleted || m_Target.Deleted || m_From.Map != m_Target.Map || !m_From.InRange( m_Target, m_Range ) || ( m_Target.Hidden && m_Target.AccessLevel > m_From.AccessLevel ) ) + { + m_Arrow.Stop(); + Stop(); + return; + } + + if ( m_LastX != m_Target.X || m_LastY != m_Target.Y ) + { + m_LastX = m_Target.X; + m_LastY = m_Target.Y; + + m_Arrow.Update(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Engines/GiftGiving.cs b/Scripts/SpecialSystems/Engines/GiftGiving.cs new file mode 100644 index 0000000..dfc150a --- /dev/null +++ b/Scripts/SpecialSystems/Engines/GiftGiving.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Accounting; +using Server.Items; + +namespace Server.Misc +{ + public enum GiftResult + { + Backpack, + BankBox + } + + public class GiftGiving + { + private static List m_Givers = new List(); + + public static void Register( GiftGiver giver ) + { + m_Givers.Add( giver ); + } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( EventSink_Login ); + } + + private static void EventSink_Login( LoginEventArgs e ) + { + Account acct = e.Mobile.Account as Account; + + if ( acct == null ) + return; + + DateTime now = DateTime.Now; + + for ( int i = 0; i < m_Givers.Count; ++i ) + { + GiftGiver giver = m_Givers[i]; + + if ( now < giver.Start || now >= giver.Finish ) + continue; // not in the correct timefream + + if ( acct.Created > (giver.Start - giver.MinimumAge) ) + continue; // newly created account + + if ( acct.LastLogin >= giver.Start ) + continue; // already got one + + giver.DelayGiveGift( TimeSpan.FromSeconds( 5.0 ), e.Mobile ); + } + + acct.LastLogin = now; + } + } + + public abstract class GiftGiver + { + public virtual TimeSpan MinimumAge{ get{ return TimeSpan.FromDays( 30.0 ); } } + + public abstract DateTime Start{ get; } + public abstract DateTime Finish{ get; } + public abstract void GiveGift( Mobile mob ); + + public virtual void DelayGiveGift( TimeSpan delay, Mobile mob ) + { + Timer.DelayCall( delay, new TimerStateCallback( DelayGiveGift_Callback ), mob ); + } + + protected virtual void DelayGiveGift_Callback( object state ) + { + GiveGift( (Mobile) state ); + } + + public virtual GiftResult GiveGift( Mobile mob, Item item ) + { + if ( mob.PlaceInBackpack( item ) ) + { + if ( !WeightOverloading.IsOverloaded( mob ) ) + return GiftResult.Backpack; + } + + mob.BankBox.DropItem( item ); + return GiftResult.BankBox; + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Engines/ItemFixes.cs b/Scripts/SpecialSystems/Engines/ItemFixes.cs new file mode 100644 index 0000000..7269d91 --- /dev/null +++ b/Scripts/SpecialSystems/Engines/ItemFixes.cs @@ -0,0 +1,19 @@ +using System; +using Server; + +namespace Server.Misc +{ + public static class ItemFixes + { + public static void Initialize() + { + // Missing NoShoot flags + TileData.ItemTable[0x2A0].Flags |= TileFlag.NoShoot; + TileData.ItemTable[0x3E0].Flags |= TileFlag.NoShoot; + TileData.ItemTable[0x3E1].Flags |= TileFlag.NoShoot; + + // Incorrect height + TileData.ItemTable[0x34D2].Height = 0; + } + } +} diff --git a/Scripts/SpecialSystems/Engines/PreventInaccess.cs b/Scripts/SpecialSystems/Engines/PreventInaccess.cs new file mode 100644 index 0000000..ddce9fd --- /dev/null +++ b/Scripts/SpecialSystems/Engines/PreventInaccess.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Misc +{ + /* + * This system prevents the inability for server staff to + * access their server due to data overflows during login. + * + * Whenever a staff character's NetState is disposed right after + * the login process, the character is moved to and logged out + * at a "safe" alternative. + * + * The location the character was moved from will be reported + * to the player upon the next successful login. + * + * This system does not affect non-staff players. + */ + public static class PreventInaccess + { + public static readonly bool Enabled = true; + + private static readonly LocationInfo[] m_Destinations = new LocationInfo[] + { + new LocationInfo( new Point3D( 5275, 1163, 0 ), Map.Felucca ), // Jail + new LocationInfo( new Point3D( 5275, 1163, 0 ), Map.Trammel ), + new LocationInfo( new Point3D( 5445, 1153, 0 ), Map.Felucca ), // Green acres + new LocationInfo( new Point3D( 5445, 1153, 0 ), Map.Trammel ) + }; + + private static Dictionary m_MoveHistory; + + public static void Initialize() + { + m_MoveHistory = new Dictionary(); + + if ( Enabled ) + EventSink.Login += new LoginEventHandler( OnLogin ); + } + + public static void OnLogin( LoginEventArgs e ) + { + Mobile from = e.Mobile; + + if ( from == null || from.AccessLevel < AccessLevel.Counselor ) + return; + + if ( HasDisconnected( from ) ) + { + if ( !m_MoveHistory.ContainsKey( from ) ) + m_MoveHistory[from] = new LocationInfo( from.Location, from.Map ); + + LocationInfo dest = GetRandomDestination(); + + from.Location = dest.Location; + from.Map = dest.Map; + } + else if ( m_MoveHistory.ContainsKey( from ) ) + { + LocationInfo orig = m_MoveHistory[from]; + from.SendMessage( "Your character was moved from {0} ({1}) due to a detected client crash.", orig.Location, orig.Map ); + + m_MoveHistory.Remove( from ); + } + } + + private static bool HasDisconnected( Mobile m ) + { + return ( m.NetState == null || m.NetState.Socket == null ); + } + + private static LocationInfo GetRandomDestination() + { + return m_Destinations[Utility.Random( m_Destinations.Length )]; + } + + private class LocationInfo + { + private Point3D m_Location; + private Map m_Map; + + public Point3D Location { get { return m_Location; } } + public Map Map { get { return m_Map; } } + + public LocationInfo( Point3D loc, Map map ) + { + m_Location = loc; + m_Map = map; + } + } + } +} diff --git a/Scripts/SpecialSystems/Engines/TestCenter.cs b/Scripts/SpecialSystems/Engines/TestCenter.cs new file mode 100644 index 0000000..3dddc4f --- /dev/null +++ b/Scripts/SpecialSystems/Engines/TestCenter.cs @@ -0,0 +1,253 @@ +using System; +using System.Text; +using Server.Gumps; +using Server.Network; +using Server.Commands; + +namespace Server.Misc +{ + public class TestCenter + { + private const bool m_Enabled = false; + public static bool Enabled { get { return m_Enabled; } } + + public static void Initialize() + { + // Register our speech handler + if (Enabled) + EventSink.Speech += new SpeechEventHandler(EventSink_Speech); + } + + private static void EventSink_Speech(SpeechEventArgs args) + { + if (!args.Handled) + { + if (Insensitive.StartsWith(args.Speech, "set")) + { + Mobile from = args.Mobile; + + string[] split = args.Speech.Split(' '); + + if (split.Length == 3) + { + try + { + string name = split[1]; + double value = Convert.ToDouble(split[2]); + + if (Insensitive.Equals(name, "str")) + ChangeStrength(from, (int)value); + else if (Insensitive.Equals(name, "dex")) + ChangeDexterity(from, (int)value); + else if (Insensitive.Equals(name, "int")) + ChangeIntelligence(from, (int)value); + else + ChangeSkill(from, name, value); + } + catch + { + } + } + } + else if (Insensitive.Equals(args.Speech, "help")) + { + args.Mobile.SendGump(new TCHelpGump()); + + args.Handled = true; + } + } + } + + private static void ChangeStrength(Mobile from, int value) + { + if (value < 10 || value > 125) + { + from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } + else + { + if ((value + from.RawDex + from.RawInt) > from.StatCap) + { + from.SendLocalizedMessage(1005629); // You can not exceed the stat cap. Try setting another stat lower first. + } + else + { + from.RawStr = value; + from.SendLocalizedMessage(1005630); // Your stats have been adjusted. + } + } + } + + private static void ChangeDexterity(Mobile from, int value) + { + if (value < 10 || value > 125) + { + from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } + else + { + if ((from.RawStr + value + from.RawInt) > from.StatCap) + { + from.SendLocalizedMessage(1005629); // You can not exceed the stat cap. Try setting another stat lower first. + } + else + { + from.RawDex = value; + from.SendLocalizedMessage(1005630); // Your stats have been adjusted. + } + } + } + + private static void ChangeIntelligence(Mobile from, int value) + { + if (value < 10 || value > 125) + { + from.SendLocalizedMessage(1005628); // Stats range between 10 and 125. + } + else + { + if ((from.RawStr + from.RawDex + value) > from.StatCap) + { + from.SendLocalizedMessage(1005629); // You can not exceed the stat cap. Try setting another stat lower first. + } + else + { + from.RawInt = value; + from.SendLocalizedMessage(1005630); // Your stats have been adjusted. + } + } + } + + private static void ChangeSkill(Mobile from, string name, double value) + { + SkillName index; +#if Framework_4_0 + if( !Enum.TryParse( name, true, out index ) || (!Core.SE && (int)index > 51) || (!Core.AOS && (int)index > 48) ) + { + from.SendLocalizedMessage( 1005631 ); // You have specified an invalid skill to set. + return; + } +#else + try + { + index = (SkillName)Enum.Parse(typeof(SkillName), name, true); + } + catch + { + from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + return; + } + + if ((!Core.SE && (int)index > 51) || (!Core.AOS && (int)index > 48)) + { + from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + return; + } +#endif + Skill skill = from.Skills[index]; + + if (skill != null) + { + if (value < 0 || value > skill.Cap) + { + from.SendMessage(String.Format("Your skill in {0} is capped at {1:F1}.", skill.Info.Name, skill.Cap)); + } + else + { + int newFixedPoint = (int)(value * 10.0); + int oldFixedPoint = skill.BaseFixedPoint; + + if (((skill.Owner.Total - oldFixedPoint) + newFixedPoint) > skill.Owner.Cap) + { + from.SendMessage("You can not exceed the skill cap. Try setting another skill lower first."); + } + else + { + skill.BaseFixedPoint = newFixedPoint; + } + } + } + else + { + from.SendLocalizedMessage(1005631); // You have specified an invalid skill to set. + } + } + + + public class TCHelpGump : Gump + { + public TCHelpGump() + : base(40, 40) + { + AddPage(0); + AddBackground(0, 0, 160, 120, 5054); + + AddButton(10, 10, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0); + AddLabel(45, 10, 0x34, "RunUO.com"); + + AddButton(10, 35, 0xFB7, 0xFB9, 2, GumpButtonType.Reply, 0); + AddLabel(45, 35, 0x34, "List of skills"); + + AddButton(10, 60, 0xFB7, 0xFB9, 3, GumpButtonType.Reply, 0); + AddLabel(45, 60, 0x34, "Command list"); + + AddButton(10, 85, 0xFB1, 0xFB3, 0, GumpButtonType.Reply, 0); + AddLabel(45, 85, 0x34, "Close"); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + switch (info.ButtonID) + { + case 1: // RunUO.com + { + sender.LaunchBrowser("http://www.RunUO.com"); + break; + } + case 2: // List of skills + { + string[] strings = Enum.GetNames(typeof(SkillName)); + + Array.Sort(strings); + + StringBuilder sb = new StringBuilder(); + + if (strings.Length > 0) + sb.Append(strings[0]); + + for (int i = 1; i < strings.Length; ++i) + { + string v = strings[i]; + + if ((sb.Length + 1 + v.Length) >= 256) + { + sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", sb.ToString())); + sb = new StringBuilder(); + sb.Append(v); + } + else + { + sb.Append(' '); + sb.Append(v); + } + } + + if (sb.Length > 0) + { + sender.Send(new AsciiMessage(Server.Serial.MinusOne, -1, MessageType.Label, 0x35, 3, "System", sb.ToString())); + } + + break; + } + case 3: // Command list + { + sender.Mobile.SendAsciiMessage(0x482, "The command prefix is \"{0}\"", CommandSystem.Prefix); + CommandHandlers.Help_OnCommand(new CommandEventArgs(sender.Mobile, "help", "", new string[0])); + + break; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Ressurection/ResGate.cs b/Scripts/SpecialSystems/Items/Ressurection/ResGate.cs new file mode 100644 index 0000000..d8f4137 --- /dev/null +++ b/Scripts/SpecialSystems/Items/Ressurection/ResGate.cs @@ -0,0 +1,59 @@ +using System; +using Server.Gumps; + +namespace Server.Items +{ + public class ResGate : Item + { + public override string DefaultName + { + get { return "a resurrection gate"; } + } + + [Constructable] + public ResGate() + : base(0xF6C) + { + Movable = false; + Hue = 0x2D1; + Light = LightType.Circle300; + } + + public ResGate(Serial serial) + : base(serial) + { + } + + public override bool OnMoveOver(Mobile m) + { + if (!m.Alive && m.Map != null && m.Map.CanFit(m.Location, 16, false, false)) + { + m.PlaySound(0x214); + m.FixedEffect(0x376A, 10, 16); + + m.CloseGump(typeof(ResurrectGump)); + m.SendGump(new ResurrectGump(m)); + } + else + { + m.SendLocalizedMessage(502391); // Thou can not be resurrected there! + } + + return false; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/AlchemyStone.cs b/Scripts/SpecialSystems/Items/Stones/AlchemyStone.cs new file mode 100644 index 0000000..a856775 --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/AlchemyStone.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class AlchemyStone : Item + { + public override string DefaultName + { + get { return "an Alchemist Supply Stone"; } + } + + [Constructable] + public AlchemyStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x250; + } + + public override void OnDoubleClick( Mobile from ) + { + AlchemyBag alcBag = new AlchemyBag(); + + if ( !from.AddToBackpack( alcBag ) ) + alcBag.Delete(); + } + + public AlchemyStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/GMStone.cs b/Scripts/SpecialSystems/Items/Stones/GMStone.cs new file mode 100644 index 0000000..d223fae --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/GMStone.cs @@ -0,0 +1,56 @@ +#if false +using System; +using Server.Network; +using Server.Commands; + +namespace Server.Items +{ + public class GMStone : Item + { + public override string DefaultName + { + get { return "a GM stone"; } + } + + [Constructable] + public GMStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x489; + } + + public GMStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel < AccessLevel.GameMaster ) + { + from.AccessLevel = AccessLevel.GameMaster; + + from.SendAsciiMessage( 0x482, "The command prefix is \"{0}\"", CommandSystem.Prefix ); + CommandHandlers.Help_OnCommand( new CommandEventArgs( from, "help", "", new string[0] ) ); + } + else + { + from.SendMessage( "The stone has no effect." ); + } + } + } +} +#endif \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/GamblingStone.cs b/Scripts/SpecialSystems/Items/Stones/GamblingStone.cs new file mode 100644 index 0000000..d0d3d2b --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/GamblingStone.cs @@ -0,0 +1,132 @@ +namespace Server.Items +{ + public class GamblingStone : Item + { + private int m_GamblePot = 2500; + + [CommandProperty( AccessLevel.GameMaster )] + public int GamblePot + { + get + { + return m_GamblePot; + } + set + { + m_GamblePot = value; + InvalidateProperties(); + } + } + + public override string DefaultName + { + get { return "a gambling stone"; } + } + + [Constructable] + public GamblingStone() + : base( 0xED4 ) + { + Movable = false; + Hue = 0x56; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( "Jackpot: {0}gp", m_GamblePot ); + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + base.LabelTo( from, "Jackpot: {0}gp", m_GamblePot ); + } + + public override void OnDoubleClick( Mobile from ) + { + Container pack = from.Backpack; + + if( pack != null && pack.ConsumeTotal( typeof( Gold ), 250 ) ) + { + m_GamblePot += 150; + InvalidateProperties(); + + int roll = Utility.Random( 1200 ); + + if( roll == 0 ) // Jackpot + { + int maxCheck = 1000000; + + from.SendMessage( 0x35, "You win the {0}gp jackpot!", m_GamblePot ); + + while( m_GamblePot > maxCheck ) + { + from.AddToBackpack( new BankCheck( maxCheck ) ); + + m_GamblePot -= maxCheck; + } + + from.AddToBackpack( new BankCheck( m_GamblePot ) ); + + m_GamblePot = 2500; + } + else if( roll <= 20 ) // Chance for a regbag + { + from.SendMessage( 0x35, "You win a bag of reagents!" ); + from.AddToBackpack( new BagOfReagents( 50 ) ); + } + else if( roll <= 40 ) // Chance for gold + { + from.SendMessage( 0x35, "You win 1500gp!" ); + from.AddToBackpack( new BankCheck( 1500 ) ); + } + else if( roll <= 100 ) // Another chance for gold + { + from.SendMessage( 0x35, "You win 1000gp!" ); + from.AddToBackpack( new BankCheck( 1000 ) ); + } + else // Loser! + { + from.SendMessage( 0x22, "You lose!" ); + } + } + else + { + from.SendMessage( 0x22, "You need at least 250gp in your backpack to use this." ); + } + } + + public GamblingStone( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (int)m_GamblePot ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_GamblePot = reader.ReadInt(); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/IngotStone.cs b/Scripts/SpecialSystems/Items/Stones/IngotStone.cs new file mode 100644 index 0000000..04b9051 --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/IngotStone.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class IngotStone : Item + { + public override string DefaultName + { + get { return "an Ingot stone"; } + } + + [Constructable] + public IngotStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x480; + } + + public override void OnDoubleClick( Mobile from ) + { + BagOfingots ingotBag = new BagOfingots( 5000 ); + + if ( !from.AddToBackpack( ingotBag ) ) + ingotBag.Delete(); + } + + public IngotStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/RegStone.cs b/Scripts/SpecialSystems/Items/Stones/RegStone.cs new file mode 100644 index 0000000..bd156ff --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/RegStone.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class RegStone : Item + { + public override string DefaultName + { + get { return "a reagent stone"; } + } + + [Constructable] + public RegStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x2D1; + } + + public override void OnDoubleClick( Mobile from ) + { + BagOfReagents regBag = new BagOfReagents( 50 ); + + if ( !from.AddToBackpack( regBag ) ) + regBag.Delete(); + } + + public RegStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/ScribeStone.cs b/Scripts/SpecialSystems/Items/Stones/ScribeStone.cs new file mode 100644 index 0000000..659a4fb --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/ScribeStone.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class ScribeStone : Item + { + public override string DefaultName + { + get { return "a Scribe Supply Stone"; } + } + + [Constructable] + public ScribeStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x105; + } + + public override void OnDoubleClick( Mobile from ) + { + ScribeBag scribeBag = new ScribeBag(); + + if ( !from.AddToBackpack( scribeBag ) ) + scribeBag.Delete(); + } + + public ScribeStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/SmithStone.cs b/Scripts/SpecialSystems/Items/Stones/SmithStone.cs new file mode 100644 index 0000000..d6b619d --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/SmithStone.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class SmithStone : Item + { + public override string DefaultName + { + get { return "a Blacksmith Supply Stone"; } + } + + [Constructable] + public SmithStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x476; + } + + public override void OnDoubleClick( Mobile from ) + { + SmithBag SmithBag = new SmithBag( 5000 ); + + if ( !from.AddToBackpack( SmithBag ) ) + SmithBag.Delete(); + } + + public SmithStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/Stones/TailorStone.cs b/Scripts/SpecialSystems/Items/Stones/TailorStone.cs new file mode 100644 index 0000000..3693a88 --- /dev/null +++ b/Scripts/SpecialSystems/Items/Stones/TailorStone.cs @@ -0,0 +1,46 @@ +using System; +using Server.Items; + +namespace Server.Items +{ + public class TailorStone : Item + { + public override string DefaultName + { + get { return "a Tailor Supply Stone"; } + } + + [Constructable] + public TailorStone() : base( 0xED4 ) + { + Movable = false; + Hue = 0x315; + } + + public override void OnDoubleClick( Mobile from ) + { + TailorBag tailorBag = new TailorBag(); + + if ( !from.AddToBackpack( tailorBag ) ) + tailorBag.Delete(); + } + + public TailorStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/SupplyBags/AlchemyBag.cs b/Scripts/SpecialSystems/Items/SupplyBags/AlchemyBag.cs new file mode 100644 index 0000000..6ac9657 --- /dev/null +++ b/Scripts/SpecialSystems/Items/SupplyBags/AlchemyBag.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AlchemyBag : Bag + { + public override string DefaultName + { + get { return "an Alchemy Kit"; } + } + + [Constructable] + public AlchemyBag() : this( 1 ) + { + Movable = true; + Hue = 0x250; + } + + [Constructable] + public AlchemyBag( int amount ) + { + DropItem( new MortarPestle( 5 ) ); + DropItem( new BagOfReagents( 5000 ) ); + DropItem( new Bottle( 5000 ) ); + } + + public AlchemyBag( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/SupplyBags/BagOfIngots.cs b/Scripts/SpecialSystems/Items/SupplyBags/BagOfIngots.cs new file mode 100644 index 0000000..e5a9448 --- /dev/null +++ b/Scripts/SpecialSystems/Items/SupplyBags/BagOfIngots.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BagOfingots : Bag + { + [Constructable] + public BagOfingots() : this( 5000 ) + { + } + + [Constructable] + public BagOfingots( int amount ) + { + DropItem( new DullcopperIngot ( amount ) ); + DropItem( new ShadowIngot ( amount ) ); + DropItem( new CopperIngot ( amount ) ); + DropItem( new BronzeIngot ( amount ) ); + DropItem( new GoldIngot ( amount ) ); + DropItem( new AgapiteIngot ( amount ) ); + DropItem( new VeriteIngot ( amount ) ); + DropItem( new ValoriteIngot ( amount ) ); + DropItem( new IronIngot ( amount ) ); + DropItem( new Tongs() ); + DropItem( new TinkerTools() ); + + } + + public BagOfingots( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/SpecialSystems/Items/SupplyBags/ScribeBag.cs b/Scripts/SpecialSystems/Items/SupplyBags/ScribeBag.cs new file mode 100644 index 0000000..98bfeae --- /dev/null +++ b/Scripts/SpecialSystems/Items/SupplyBags/ScribeBag.cs @@ -0,0 +1,46 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ScribeBag : Bag + { + public override string DefaultName + { + get { return "a Scribe Kit"; } + } + + [Constructable] + public ScribeBag() : this( 1 ) + { + Movable = true; + Hue = 0x105; + } + + [Constructable] + public ScribeBag( int amount ) + { + DropItem( new BagOfReagents( 5000 ) ); + DropItem( new BlankScroll( 500 ) ); + } + + public ScribeBag( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/Items/SupplyBags/SmithBag.cs b/Scripts/SpecialSystems/Items/SupplyBags/SmithBag.cs new file mode 100644 index 0000000..29959f0 --- /dev/null +++ b/Scripts/SpecialSystems/Items/SupplyBags/SmithBag.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SmithBag : Bag + { + [Constructable] + public SmithBag() : this( 5000 ) + { + } + + [Constructable] + public SmithBag( int amount ) + { + DropItem(new DullcopperIngot(amount)); + DropItem(new ShadowIngot(amount)); + DropItem( new CopperIngot ( amount ) ); + DropItem( new BronzeIngot ( amount ) ); + DropItem( new GoldIngot ( amount ) ); + DropItem( new AgapiteIngot ( amount ) ); + DropItem( new VeriteIngot ( amount ) ); + DropItem( new ValoriteIngot ( amount ) ); + DropItem( new IronIngot ( amount ) ); + DropItem( new Tongs ( amount ) ); + DropItem( new TinkerTools ( amount ) ); + + } + + public SmithBag( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/SpecialSystems/Items/SupplyBags/TailorBag.cs b/Scripts/SpecialSystems/Items/SupplyBags/TailorBag.cs new file mode 100644 index 0000000..b1e4441 --- /dev/null +++ b/Scripts/SpecialSystems/Items/SupplyBags/TailorBag.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class TailorBag : Bag + { + public override string DefaultName + { + get { return "a Tailoring Kit"; } + } + + [Constructable] + public TailorBag() : this( 1 ) + { + Movable = true; + Hue = 0x315; + } + + [Constructable] + public TailorBag( int amount ) + { + DropItem( new SewingKit( 5 ) ); + DropItem( new Scissors() ); + DropItem( new Hides( 500 ) ); + DropItem( new BoltOfCloth( 20 ) ); + DropItem( new DyeTub() ); + DropItem( new DyeTub() ); + DropItem( new BlackDyeTub() ); + DropItem( new Dyes() ); + } + + public TailorBag( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/SpecialSystems/README.TXT b/Scripts/SpecialSystems/README.TXT new file mode 100644 index 0000000..bf4f9eb --- /dev/null +++ b/Scripts/SpecialSystems/README.TXT @@ -0,0 +1,10 @@ +IMPORTANT NOTE +-------------- + +The contents of this directory, are not necessarily OSI-accurate, or even based on +OSI features. Simply, its a small collection of useful tools and systems that a +shard admin may find big help. + +We know its not accurate, we know it cant be made accurate, so .. :) + + diff --git a/Scripts/Spells/Base/DisturbType.cs b/Scripts/Spells/Base/DisturbType.cs new file mode 100644 index 0000000..4c3a36e --- /dev/null +++ b/Scripts/Spells/Base/DisturbType.cs @@ -0,0 +1,15 @@ +using System; +using Server; + +namespace Server.Spells +{ + public enum DisturbType + { + Unspecified, + EquipRequest, + UseRequest, + Hurt, + Kill, + NewCast + } +} \ No newline at end of file diff --git a/Scripts/Spells/Base/MagerySpell.cs b/Scripts/Spells/Base/MagerySpell.cs new file mode 100644 index 0000000..8df4192 --- /dev/null +++ b/Scripts/Spells/Base/MagerySpell.cs @@ -0,0 +1,116 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Spells +{ + public abstract class MagerySpell : Spell + { + public MagerySpell( Mobile caster, Item scroll, SpellInfo info ) + : base( caster, scroll, info ) + { + } + + public abstract SpellCircle Circle { get; } + + public override bool ConsumeReagents() + { + if( base.ConsumeReagents() ) + return true; + + if( ArcaneGem.ConsumeCharges( Caster, (Core.SE ? 1 : 1 + (int)Circle) ) ) + return true; + + return false; + } + + private const double ChanceOffset = 20.0, ChanceLength = 100.0 / 7.0; + + public override void GetCastSkills( out double min, out double max ) + { + int circle = (int)Circle; + + if( Scroll != null ) + circle -= 2; + + double avg = ChanceLength * circle; + + min = avg - ChanceOffset; + max = avg + ChanceOffset; + } + + private static int[] m_ManaTable = new int[] { 4, 6, 9, 11, 14, 20, 40, 50 }; + + public override int GetMana() + { + if( Scroll is BaseWand ) + return 0; + + return m_ManaTable[(int)Circle]; + } + + public override double GetResistSkill( Mobile m ) + { + int maxSkill = (1 + (int)Circle) * 10; + maxSkill += (1 + ((int)Circle / 6)) * 25; + + if( m.Skills[SkillName.MagicResist].Value < maxSkill ) + m.CheckSkill( SkillName.MagicResist, 0.0, m.Skills[SkillName.MagicResist].Cap ); + + return m.Skills[SkillName.MagicResist].Value; + } + + public virtual bool CheckResisted( Mobile target ) + { + double n = GetResistPercent( target ); + + n /= 100.0; + + if( n <= 0.0 ) + return false; + + if( n >= 1.0 ) + return true; + + int maxSkill = (1 + (int)Circle) * 10; + maxSkill += (1 + ((int)Circle / 6)) * 25; + + if( target.Skills[SkillName.MagicResist].Value < maxSkill ) + target.CheckSkill( SkillName.MagicResist, 0.0, target.Skills[SkillName.MagicResist].Cap ); + + return (n >= Utility.RandomDouble()); + } + + public virtual double GetResistPercentForCircle( Mobile target, SpellCircle circle ) + { + double firstPercent = target.Skills[SkillName.MagicResist].Value / 5.0; + double secondPercent = target.Skills[SkillName.MagicResist].Value - (((Caster.Skills[CastSkill].Value - 20.0) / 5.0) + (1 + (int)circle) * 5.0); + + return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0; // Seems should be about half of what stratics says. + } + + public virtual double GetResistPercent( Mobile target ) + { + return GetResistPercentForCircle( target, Circle ); + } + + public override TimeSpan GetCastDelay() + { + if (!Core.ML && Scroll is BaseWand) + return TimeSpan.Zero; + + if( !Core.AOS ) + return TimeSpan.FromSeconds( 0.5 + (0.25 * (int)Circle) ); + + return base.GetCastDelay(); + } + + public override TimeSpan CastDelayBase + { + get + { + return TimeSpan.FromSeconds( (3 + (int)Circle) * CastDelaySecondsPerTick ); + } + } + } +} diff --git a/Scripts/Spells/Base/SpecialMove.cs b/Scripts/Spells/Base/SpecialMove.cs new file mode 100644 index 0000000..294d8f6 --- /dev/null +++ b/Scripts/Spells/Base/SpecialMove.cs @@ -0,0 +1,362 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells.Ninjitsu; +using Server.Spells.Bushido; + +namespace Server.Spells +{ + public abstract class SpecialMove + { + public virtual int BaseMana{ get{ return 0; } } + + public virtual SkillName MoveSkill{ get{ return SkillName.Bushido; } } + public virtual double RequiredSkill{ get{ return 0.0; } } + + public virtual TextDefinition AbilityMessage{ get{ return 0; } } + + public virtual bool BlockedByAnimalForm{ get{ return true; } } + public virtual bool DelayedContext{ get{ return false; } } + + public virtual int GetAccuracyBonus( Mobile attacker ) + { + return 0; + } + + public virtual double GetDamageScalar( Mobile attacker, Mobile defender ) + { + return 1.0; + } + + // Called before swinging, to make sure the accuracy scalar is to be computed. + public virtual bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + return true; + } + + // Called when a hit connects, but before damage is calculated. + public virtual bool OnBeforeDamage( Mobile attacker, Mobile defender ) + { + return true; + } + + // Called as soon as the ability is used. + public virtual void OnUse( Mobile from ) + { + } + + // Called when a hit connects, at the end of the weapon.OnHit() method. + public virtual void OnHit( Mobile attacker, Mobile defender, int damage ) + { + } + + // Called when a hit misses. + public virtual void OnMiss( Mobile attacker, Mobile defender ) + { + } + + // Called when the move is cleared. + public virtual void OnClearMove( Mobile from ) + { + } + + public virtual bool IgnoreArmor( Mobile attacker ) + { + return false; + } + + public virtual double GetPropertyBonus( Mobile attacker ) + { + return 1.0; + } + + public virtual bool CheckSkills( Mobile m ) + { + if ( m.Skills[MoveSkill].Value < RequiredSkill ) + { + string args = String.Format( "{0}\t{1}\t ", RequiredSkill.ToString( "F1" ), MoveSkill.ToString() ); + m.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + return true; + } + + public virtual int ScaleMana( Mobile m, int mana ) + { + double scalar = 1.0; + + if ( !Server.Spells.Necromancy.MindRotSpell.GetMindRotScalar( m, ref scalar ) ) + scalar = 1.0; + + // Lower Mana Cost = 40% + int lmc = Math.Min( AosAttributes.GetValue( m, AosAttribute.LowerManaCost ), 40 ); + + scalar -= (double)lmc / 100; + + int total = (int)(mana * scalar); + + if ( m.Skills[MoveSkill].Value < 50.0 && GetContext( m ) != null ) + total *= 2; + + return total; + } + + public virtual bool CheckMana( Mobile from, bool consume ) + { + int mana = ScaleMana( from, BaseMana ); + + if ( from.Mana < mana ) + { + from.SendLocalizedMessage( 1060181, mana.ToString() ); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack + return false; + } + + if ( consume ) + { + if ( !DelayedContext ) + SetContext( from ); + + from.Mana -= mana; + } + + return true; + } + + public virtual void SetContext( Mobile from ) + { + if ( GetContext( from ) == null ) + { + if ( DelayedContext || from.Skills[MoveSkill].Value < 50.0 ) + { + Timer timer = new SpecialMoveTimer( from ); + timer.Start(); + + AddContext( from, new SpecialMoveContext( timer, this.GetType() ) ); + } + } + } + + public virtual bool Validate( Mobile from ) + { + if ( !from.Player ) + return true; + + if ( Bushido.HonorableExecution.IsUnderPenalty( from ) ) + { + from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now. + return false; + } + + if ( Ninjitsu.AnimalForm.UnderTransformation( from ) ) + { + from.SendLocalizedMessage( 1063024 ); // You cannot perform this special move right now. + return false; + } + + #region Dueling + string option = null; + + if (this is Backstab) + option = "Backstab"; + else if (this is DeathStrike) + option = "Death Strike"; + else if (this is FocusAttack) + option = "Focus Attack"; + else if (this is KiAttack) + option = "Ki Attack"; + else if (this is SurpriseAttack) + option = "Surprise Attack"; + else if (this is HonorableExecution) + option = "Honorable Execution"; + else if (this is LightningStrike) + option = "Lightning Strike"; + else if (this is MomentumStrike) + option = "Momentum Strike"; + + if (option != null && !Engines.ConPVP.DuelContext.AllowSpecialMove(from, option, this)) + return false; + #endregion + + return CheckSkills( from ) && CheckMana( from, false ); + } + + public virtual void CheckGain( Mobile m ) + { + m.CheckSkill( MoveSkill, RequiredSkill, RequiredSkill + 37.5 ); + } + + private static Dictionary m_Table = new Dictionary(); + + public static Dictionary Table{ get{ return m_Table; } } + + public static void ClearAllMoves( Mobile m ) + { + foreach ( KeyValuePair kvp in SpellRegistry.SpecialMoves ) + { + int moveID = kvp.Key; + + if ( moveID != -1 ) + m.Send( new ToggleSpecialAbility( moveID + 1, false ) ); + } + } + + public virtual bool ValidatesDuringHit{ get { return true; } } + + public static SpecialMove GetCurrentMove( Mobile m ) + { + if ( m == null ) + return null; + + if ( !Core.SE ) + { + ClearCurrentMove( m ); + return null; + } + + SpecialMove move = null; + m_Table.TryGetValue( m, out move ); + + if ( move != null && move.ValidatesDuringHit && !move.Validate( m ) ) + { + ClearCurrentMove( m ); + return null; + } + + return move; + } + + public static bool SetCurrentMove( Mobile m, SpecialMove move ) + { + if ( !Core.SE ) + { + ClearCurrentMove( m ); + return false; + } + + if ( move != null && !move.Validate( m ) ) + { + ClearCurrentMove( m ); + return false; + } + + bool sameMove = ( move == GetCurrentMove( m ) ); + + ClearCurrentMove( m ); + + if ( sameMove ) + return true; + + if ( move != null ) + { + WeaponAbility.ClearCurrentAbility( m ); + + m_Table[m] = move; + + move.OnUse( m ); + + int moveID = SpellRegistry.GetRegistryNumber( move ); + + if ( moveID > 0 ) + m.Send( new ToggleSpecialAbility( moveID + 1, true ) ); + + TextDefinition.SendMessageTo( m, move.AbilityMessage ); + } + + return true; + } + + public static void ClearCurrentMove( Mobile m ) + { + SpecialMove move = null; + m_Table.TryGetValue( m, out move ); + + if ( move != null ) + { + move.OnClearMove( m ); + + int moveID = SpellRegistry.GetRegistryNumber( move ); + + if ( moveID > 0 ) + m.Send( new ToggleSpecialAbility( moveID + 1, false ) ); + } + + m_Table.Remove( m ); + } + + public SpecialMove() + { + } + + + private static Dictionary m_PlayersTable = new Dictionary(); + + private static void AddContext( Mobile m, SpecialMoveContext context ) + { + m_PlayersTable[m] = context; + } + + private static void RemoveContext( Mobile m ) + { + SpecialMoveContext context = GetContext( m ); + + if ( context != null ) + { + m_PlayersTable.Remove( m ); + + context.Timer.Stop(); + } + } + + private static SpecialMoveContext GetContext( Mobile m ) + { + return ( m_PlayersTable.ContainsKey( m ) ? m_PlayersTable[m] : null ); + } + + public static bool GetContext( Mobile m, Type type ) + { + SpecialMoveContext context = null; + m_PlayersTable.TryGetValue( m, out context ); + + if ( context == null ) + return false; + + return ( context.Type == type ); + } + + private class SpecialMoveTimer : Timer + { + private Mobile m_Mobile; + + public SpecialMoveTimer( Mobile from ) : base ( TimeSpan.FromSeconds( 3.0 ) ) + { + m_Mobile = from; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + RemoveContext( m_Mobile ); + } + } + + public class SpecialMoveContext + { + private Timer m_Timer; + private Type m_Type; + + public Timer Timer{ get{ return m_Timer; } } + public Type Type{ get{ return m_Type; } } + + public SpecialMoveContext( Timer timer, Type type ) + { + m_Timer = timer; + m_Type = type; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Base/Spell.cs b/Scripts/Spells/Base/Spell.cs new file mode 100644 index 0000000..19d48c7 --- /dev/null +++ b/Scripts/Spells/Base/Spell.cs @@ -0,0 +1,942 @@ +using System; +using Server.Items; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Spells.Second; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using System.Collections.Generic; +using Server.Spells.Spellweaving; +using Server.Spells.Bushido; +using Server.Spells.Druid; + +namespace Server.Spells +{ + public abstract class Spell : ISpell + { + private Mobile m_Caster; + private Item m_Scroll; + private SpellInfo m_Info; + private SpellState m_State; + private DateTime m_StartCastTime; + + public SpellState State{ get{ return m_State; } set{ m_State = value; } } + public Mobile Caster{ get{ return m_Caster; } } + public SpellInfo Info{ get{ return m_Info; } } + public string Name{ get{ return m_Info.Name; } } + public string Mantra{ get{ return m_Info.Mantra; } } + public Type[] Reagents{ get{ return m_Info.Reagents; } } + public Item Scroll{ get{ return m_Scroll; } } + public DateTime StartCastTime { get { return m_StartCastTime; } } + + private static TimeSpan NextSpellDelay = TimeSpan.FromSeconds( 0.75 ); + private static TimeSpan AnimateDelay = TimeSpan.FromSeconds( 1.5 ); + + public virtual SkillName CastSkill{ get{ return SkillName.Magery; } } + public virtual SkillName DamageSkill{ get{ return SkillName.EvalInt; } } + + public virtual bool RevealOnCast{ get{ return true; } } + public virtual bool ClearHandsOnCast{ get{ return true; } } + public virtual bool ShowHandMovement{ get{ return true; } } + + public virtual bool DelayedDamage{ get{ return false; } } + + public virtual bool DelayedDamageStacking { get { return true; } } + //In reality, it's ANY delayed Damage spell Post-AoS that can't stack, but, only + //Expo & Magic Arrow have enough delay and a short enough cast time to bring up + //the possibility of stacking 'em. Note that a MA & an Explosion will stack, but + //of course, two MA's won't. + + private static Dictionary m_ContextTable = new Dictionary(); + + private class DelayedDamageContextWrapper + { + private Dictionary m_Contexts = new Dictionary(); + + public void Add( Mobile m, Timer t ) + { + Timer oldTimer; + if( m_Contexts.TryGetValue( m, out oldTimer ) ) + { + oldTimer.Stop(); + m_Contexts.Remove( m ); + } + + m_Contexts.Add( m, t ); + } + + public void Remove( Mobile m ) + { + m_Contexts.Remove( m ); + } + } + + public void StartDelayedDamageContext( Mobile m, Timer t ) + { + if( DelayedDamageStacking ) + return; //Sanity + + DelayedDamageContextWrapper contexts; + + if( !m_ContextTable.TryGetValue( GetType(), out contexts ) ) + { + contexts = new DelayedDamageContextWrapper(); + m_ContextTable.Add( GetType(), contexts ); + } + + contexts.Add( m, t ); + } + + public void RemoveDelayedDamageContext( Mobile m ) + { + DelayedDamageContextWrapper contexts; + + if( !m_ContextTable.TryGetValue( GetType(), out contexts ) ) + return; + + contexts.Remove( m ); + } + + public void HarmfulSpell(Mobile m) + { + if (m is BaseCreature) + ((BaseCreature)m).OnHarmfulSpell(m_Caster); + } + + public Spell( Mobile caster, Item scroll, SpellInfo info ) + { + m_Caster = caster; + m_Scroll = scroll; + m_Info = info; + } + + public virtual int GetNewAosDamage( int bonus, int dice, int sides, Mobile singleTarget ) + { + if( singleTarget != null ) + { + return GetNewAosDamage( bonus, dice, sides, (Caster.Player && singleTarget.Player), GetDamageScalar( singleTarget ) ); + } + else + { + return GetNewAosDamage( bonus, dice, sides, false ); + } + } + + public virtual int GetNewAosDamage( int bonus, int dice, int sides, bool playerVsPlayer ) + { + return GetNewAosDamage( bonus, dice, sides, playerVsPlayer, 1.0 ); + } + + public virtual int GetNewAosDamage( int bonus, int dice, int sides, bool playerVsPlayer, double scalar ) + { + int damage = Utility.Dice( dice, sides, bonus ) * 100; + int damageBonus = 0; + + int inscribeSkill = GetInscribeFixed( m_Caster ); + int inscribeBonus = (inscribeSkill + (1000 * (inscribeSkill / 1000))) / 200; + damageBonus += inscribeBonus; + + int intBonus = Caster.Int / 10; + damageBonus += intBonus; + + int sdiBonus = AosAttributes.GetValue( m_Caster, AosAttribute.SpellDamage ); + // PvP spell damage increase cap of 15% from an item�s magic property + if ( playerVsPlayer && sdiBonus > 15 ) + sdiBonus = 15; + + damageBonus += sdiBonus; + + TransformContext context = TransformationSpellHelper.GetContext( Caster ); + + if( context != null && context.Spell is ReaperFormSpell ) + damageBonus += ((ReaperFormSpell)context.Spell).SpellDamageBonus; + + damage = AOS.Scale( damage, 100 + damageBonus ); + + int evalSkill = GetDamageFixed( m_Caster ); + int evalScale = 30 + ((9 * evalSkill) / 100); + + damage = AOS.Scale( damage, evalScale ); + + damage = AOS.Scale( damage, (int)(scalar*100) ); + + return damage / 100; + } + + public virtual bool IsCasting{ get{ return m_State == SpellState.Casting; } } + + public virtual void OnCasterHurt() + { + //Confirm: Monsters and pets cannot be disturbed. + if ( !Caster.Player ) + return; + + if ( IsCasting ) + { + object o = ProtectionSpell.Registry[m_Caster]; + bool disturb = true; + + if ( o != null && o is double ) + { + if ( ((double)o) > Utility.RandomDouble()*100.0 ) + disturb = false; + } + + if ( disturb ) + Disturb( DisturbType.Hurt, false, true ); + } + } + + public virtual void OnCasterKilled() + { + Disturb( DisturbType.Kill ); + } + + public virtual void OnConnectionChanged() + { + FinishSequence(); + } + + public virtual bool OnCasterMoving( Direction d ) + { + if ( IsCasting && BlocksMovement ) + { + m_Caster.SendLocalizedMessage( 500111 ); // You are frozen and can not move. + return false; + } + + return true; + } + + public virtual bool OnCasterEquiping( Item item ) + { + if ( IsCasting ) + Disturb( DisturbType.EquipRequest ); + + return true; + } + + public virtual bool OnCasterUsingObject( object o ) + { + if ( m_State == SpellState.Sequencing ) + Disturb( DisturbType.UseRequest ); + + return true; + } + + public virtual bool OnCastInTown( Region r ) + { + return m_Info.AllowTown; + } + + public virtual bool ConsumeReagents() + { + if ( m_Scroll != null || !m_Caster.Player ) + return true; + + if ( AosAttributes.GetValue( m_Caster, AosAttribute.LowerRegCost ) > Utility.Random( 100 ) ) + return true; + + if (Engines.ConPVP.DuelContext.IsFreeConsume(m_Caster)) + return true; + + Container pack = m_Caster.Backpack; + + if ( pack == null ) + return false; + + if ( pack.ConsumeTotal( m_Info.Reagents, m_Info.Amounts ) == -1 ) + return true; + + return false; + } + + public virtual double GetInscribeSkill( Mobile m ) + { + // There is no chance to gain + // m.CheckSkill( SkillName.Inscribe, 0.0, 120.0 ); + + return m.Skills[SkillName.Inscribe].Value; + } + + public virtual int GetInscribeFixed( Mobile m ) + { + // There is no chance to gain + // m.CheckSkill( SkillName.Inscribe, 0.0, 120.0 ); + + return m.Skills[SkillName.Inscribe].Fixed; + } + + public virtual int GetDamageFixed( Mobile m ) + { + //m.CheckSkill( DamageSkill, 0.0, m.Skills[DamageSkill].Cap ); + + return m.Skills[DamageSkill].Fixed; + } + + public virtual double GetDamageSkill( Mobile m ) + { + //m.CheckSkill( DamageSkill, 0.0, m.Skills[DamageSkill].Cap ); + + return m.Skills[DamageSkill].Value; + } + + public virtual double GetResistSkill( Mobile m ) + { + return m.Skills[SkillName.MagicResist].Value; + } + + public virtual double GetDamageScalar( Mobile target ) + { + double scalar = 1.0; + + if( !Core.AOS ) //EvalInt stuff for AoS is handled elsewhere + { + double casterEI = m_Caster.Skills[DamageSkill].Value; + double targetRS = target.Skills[SkillName.MagicResist].Value; + + /* + if( Core.AOS ) + targetRS = 0; + */ + + //m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 ); + + if( casterEI > targetRS ) + scalar = (1.0 + ((casterEI - targetRS) / 500.0)); + else + scalar = (1.0 + ((casterEI - targetRS) / 200.0)); + + // magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill + scalar += (m_Caster.Skills[CastSkill].Value - 100.0) / 400.0; + + if( !target.Player && !target.Body.IsHuman /*&& !Core.AOS*/ ) + scalar *= 2.0; // Double magery damage to monsters/animals if not AOS + } + + if ( target is BaseCreature ) + ((BaseCreature)target).AlterDamageScalarFrom( m_Caster, ref scalar ); + + if ( m_Caster is BaseCreature ) + ((BaseCreature)m_Caster).AlterDamageScalarTo( target, ref scalar ); + + if( Core.SE ) + scalar *= GetSlayerDamageScalar( target ); + + target.Region.SpellDamageScalar( m_Caster, target, ref scalar ); + + if( Evasion.CheckSpellEvasion( target ) ) //Only single target spells an be evaded + scalar = 0; + + return scalar; + } + + public virtual double GetSlayerDamageScalar( Mobile defender ) + { + Spellbook atkBook = Spellbook.FindEquippedSpellbook( m_Caster ); + + double scalar = 1.0; + if( atkBook != null ) + { + SlayerEntry atkSlayer = SlayerGroup.GetEntryByName( atkBook.Slayer ); + SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName( atkBook.Slayer2 ); + + if( atkSlayer != null && atkSlayer.Slays( defender ) || atkSlayer2 != null && atkSlayer2.Slays( defender ) ) + { + defender.FixedEffect( 0x37B9, 10, 5 ); //TODO: Confirm this displays on OSIs + scalar = 2.0; + } + + + TransformContext context = TransformationSpellHelper.GetContext( defender ); + + if( (atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null && context.Type != typeof( HorrificBeastSpell ) ) + scalar +=.25; // Every necromancer transformation other than horrific beast take an additional 25% damage + + if( scalar != 1.0 ) + return scalar; + } + + ISlayer defISlayer = Spellbook.FindEquippedSpellbook( defender ); + + if( defISlayer == null ) + defISlayer = defender.Weapon as ISlayer; + + if( defISlayer != null ) + { + SlayerEntry defSlayer = SlayerGroup.GetEntryByName( defISlayer.Slayer ); + SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName( defISlayer.Slayer2 ); + + if( defSlayer != null && defSlayer.Group.OppositionSuperSlays( m_Caster ) || defSlayer2 != null && defSlayer2.Group.OppositionSuperSlays( m_Caster ) ) + scalar = 2.0; + } + + return scalar; + } + + public virtual void DoFizzle() + { + m_Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 502632 ); // The spell fizzles. + + if ( m_Caster.Player ) + { + if ( Core.AOS ) + m_Caster.FixedParticles( 0x3735, 1, 30, 9503, EffectLayer.Waist ); + else + m_Caster.FixedEffect( 0x3735, 6, 30 ); + + m_Caster.PlaySound( 0x5C ); + } + } + + private CastTimer m_CastTimer; + private AnimTimer m_AnimTimer; + + public void Disturb( DisturbType type ) + { + Disturb( type, true, false ); + } + + public virtual bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable ) + { + if ( resistable && m_Scroll is BaseWand ) + return false; + + return true; + } + + public void Disturb( DisturbType type, bool firstCircle, bool resistable ) + { + if ( !CheckDisturb( type, firstCircle, resistable ) ) + return; + + if ( m_State == SpellState.Casting ) + { + if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First) + return; + + m_State = SpellState.None; + m_Caster.Spell = null; + + OnDisturb( type, true ); + + if ( m_CastTimer != null ) + m_CastTimer.Stop(); + + if ( m_AnimTimer != null ) + m_AnimTimer.Stop(); + + if ( Core.AOS && m_Caster.Player && type == DisturbType.Hurt ) + DoHurtFizzle(); + + m_Caster.NextSpellTime = DateTime.Now + GetDisturbRecovery(); + } + else if ( m_State == SpellState.Sequencing ) + { + if( !firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First ) + return; + + m_State = SpellState.None; + m_Caster.Spell = null; + + OnDisturb( type, false ); + + Targeting.Target.Cancel( m_Caster ); + + if ( Core.AOS && m_Caster.Player && type == DisturbType.Hurt ) + DoHurtFizzle(); + } + } + + public virtual void DoHurtFizzle() + { + m_Caster.FixedEffect( 0x3735, 6, 30 ); + m_Caster.PlaySound( 0x5C ); + } + + public virtual void OnDisturb( DisturbType type, bool message ) + { + if ( message ) + m_Caster.SendLocalizedMessage( 500641 ); // Your concentration is disturbed, thus ruining thy spell. + } + + public virtual bool CheckCast() + { + return true; + } + + public virtual void SayMantra() + { + if ( m_Scroll is BaseWand ) + return; + + if ( m_Info.Mantra != null && m_Info.Mantra.Length > 0 && m_Caster.Player ) + m_Caster.PublicOverheadMessage( MessageType.Spell, m_Caster.SpeechHue, true, m_Info.Mantra, false ); + } + + public virtual bool BlockedByHorrificBeast{ get{ return true; } } + public virtual bool BlockedByAnimalForm{ get{ return true; } } + public virtual bool BlocksMovement{ get{ return true; } } + + public virtual bool CheckNextSpellTime{ get{ return !(m_Scroll is BaseWand); } } + + public bool Cast() + { + m_StartCastTime = DateTime.Now; + + if ( Core.AOS && m_Caster.Spell is Spell && ((Spell)m_Caster.Spell).State == SpellState.Sequencing ) + ((Spell)m_Caster.Spell).Disturb( DisturbType.NewCast ); + + if ( !m_Caster.CheckAlive() ) + { + return false; + } + else if (m_Scroll is BaseWand && m_Caster.Spell != null && m_Caster.Spell.IsCasting) + { + m_Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen. + } + else if ( m_Caster.Spell != null && m_Caster.Spell.IsCasting ) + { + m_Caster.SendLocalizedMessage( 502642 ); // You are already casting a spell. + } + else if ( BlockedByHorrificBeast && TransformationSpellHelper.UnderTransformation( m_Caster, typeof( HorrificBeastSpell ) ) || ( BlockedByAnimalForm && AnimalForm.UnderTransformation( m_Caster ) )) + { + m_Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. + } + else if ( !(m_Scroll is BaseWand) && (m_Caster.Paralyzed || m_Caster.Frozen) ) + { + m_Caster.SendLocalizedMessage( 502643 ); // You can not cast a spell while frozen. + } + else if ( CheckNextSpellTime && DateTime.Now < m_Caster.NextSpellTime ) + { + m_Caster.SendLocalizedMessage( 502644 ); // You have not yet recovered from casting a spell. + } + else if ( m_Caster is PlayerMobile && ( (PlayerMobile) m_Caster ).PeacedUntil > DateTime.Now ) + { + m_Caster.SendLocalizedMessage( 1072060 ); // You cannot cast a spell while calmed. + } + #region Dueling + else if (m_Caster is PlayerMobile && ((PlayerMobile)m_Caster).DuelContext != null && !((PlayerMobile)m_Caster).DuelContext.AllowSpellCast(m_Caster, this)) + { + } + #endregion + else if ( m_Caster.Mana >= ScaleMana( GetMana() ) ) + { + if ( m_Caster.Spell == null && m_Caster.CheckSpellCast( this ) && CheckCast() && m_Caster.Region.OnBeginSpellCast( m_Caster, this ) ) + { + m_State = SpellState.Casting; + m_Caster.Spell = this; + + if (!(m_Scroll is BaseWand) && RevealOnCast) + m_Caster.RevealingAction(); + + SayMantra(); + + TimeSpan castDelay = this.GetCastDelay(); + + if (ShowHandMovement && (m_Caster.Body.IsHuman || (m_Caster.Player && m_Caster.Body.IsMonster))) + { + int count = (int)Math.Ceiling( castDelay.TotalSeconds / AnimateDelay.TotalSeconds ); + + if ( count != 0 ) + { + m_AnimTimer = new AnimTimer( this, count ); + m_AnimTimer.Start(); + } + + if ( m_Info.LeftHandEffect > 0 ) + Caster.FixedParticles( 0, 10, 5, m_Info.LeftHandEffect, EffectLayer.LeftHand ); + + if ( m_Info.RightHandEffect > 0 ) + Caster.FixedParticles( 0, 10, 5, m_Info.RightHandEffect, EffectLayer.RightHand ); + } + + if ( ClearHandsOnCast ) + m_Caster.ClearHands(); + + if ( Core.ML ) + WeaponAbility.ClearCurrentAbility( m_Caster ); + + m_CastTimer = new CastTimer( this, castDelay ); + //m_CastTimer.Start(); + + OnBeginCast(); + + if (castDelay > TimeSpan.Zero) + { + m_CastTimer.Start(); + } + else + { + m_CastTimer.Tick(); + } + + return true; + } + else + { + return false; + } + } + else + { + m_Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 502625 ); // Insufficient mana + } + + return false; + } + + public abstract void OnCast(); + + public virtual void OnBeginCast() + { + } + + public virtual void GetCastSkills( out double min, out double max ) + { + min = max = 0; //Intended but not required for overriding. + } + + public virtual bool CheckFizzle() + { + if ( m_Scroll is BaseWand ) + return true; + + double minSkill, maxSkill; + + GetCastSkills( out minSkill, out maxSkill ); + + if ( DamageSkill != CastSkill ) + Caster.CheckSkill( DamageSkill, 0.0, Caster.Skills[ DamageSkill ].Cap ); + + return Caster.CheckSkill( CastSkill, minSkill, maxSkill ); + } + + public abstract int GetMana(); + + public virtual int ScaleMana( int mana ) + { + double scalar = 1.0; + + if ( !Necromancy.MindRotSpell.GetMindRotScalar( Caster, ref scalar ) ) + scalar = 1.0; + + // Lower Mana Cost = 40% + int lmc = AosAttributes.GetValue( m_Caster, AosAttribute.LowerManaCost ); + if ( lmc > 40 ) + lmc = 40; + + scalar -= (double)lmc / 100; + + return (int)(mana * scalar); + } + + public virtual TimeSpan GetDisturbRecovery() + { + if ( Core.AOS ) + return TimeSpan.Zero; + + double delay = 1.0 - Math.Sqrt( (DateTime.Now - m_StartCastTime).TotalSeconds / GetCastDelay().TotalSeconds ); + + if ( delay < 0.2 ) + delay = 0.2; + + return TimeSpan.FromSeconds( delay ); + } + + public virtual int CastRecoveryBase{ get{ return 6; } } + public virtual int CastRecoveryFastScalar{ get{ return 1; } } + public virtual int CastRecoveryPerSecond{ get{ return 4; } } + public virtual int CastRecoveryMinimum{ get{ return 0; } } + + public virtual TimeSpan GetCastRecovery() + { + if ( !Core.AOS ) + return NextSpellDelay; + + int fcr = AosAttributes.GetValue( m_Caster, AosAttribute.CastRecovery ); + + fcr -= ThunderstormSpell.GetCastRecoveryMalus( m_Caster ); + + int fcrDelay = -(CastRecoveryFastScalar * fcr); + + int delay = CastRecoveryBase + fcrDelay; + + if ( delay < CastRecoveryMinimum ) + delay = CastRecoveryMinimum; + + return TimeSpan.FromSeconds( (double)delay / CastRecoveryPerSecond ); + } + + + + public abstract TimeSpan CastDelayBase { get; } + + public virtual double CastDelayFastScalar { get { return 1; } } + public virtual double CastDelaySecondsPerTick { get { return 0.25; } } + public virtual TimeSpan CastDelayMinimum { get { return TimeSpan.FromSeconds( 0.25 ); } } + + //public virtual int CastDelayBase{ get{ return 3; } } + //public virtual int CastDelayFastScalar{ get{ return 1; } } + //public virtual int CastDelayPerSecond{ get{ return 4; } } + //public virtual int CastDelayMinimum{ get{ return 1; } } + + public virtual TimeSpan GetCastDelay() + { + if (m_Scroll is BaseWand) + return Core.ML ? CastDelayBase : TimeSpan.Zero; // TODO: Should FC apply to wands? + + + // Faster casting cap of 2 (if not using the protection spell) + // Faster casting cap of 0 (if using the protection spell) + // Paladin spells are subject to a faster casting cap of 4 + // Paladins with magery of 70.0 or above are subject to a faster casting cap of 2 + int fcMax = 4; + + if ( CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy || ( CastSkill == SkillName.Chivalry && m_Caster.Skills[SkillName.Magery].Value >= 70.0 ) ) + fcMax = 2; + + int fc = AosAttributes.GetValue( m_Caster, AosAttribute.CastSpeed ); + + if ( fc > fcMax ) + fc = fcMax; + + if ( ProtectionSpell.Registry.Contains( m_Caster ) ) + fc -= 2; + + if( EssenceOfWindSpell.IsDebuffed( m_Caster ) ) + fc -= EssenceOfWindSpell.GetFCMalus( m_Caster ); + + TimeSpan baseDelay = CastDelayBase; + + TimeSpan fcDelay = TimeSpan.FromSeconds( -(CastDelayFastScalar * fc * CastDelaySecondsPerTick) ); + + //int delay = CastDelayBase + circleDelay + fcDelay; + TimeSpan delay = baseDelay + fcDelay; + + if ( delay < CastDelayMinimum ) + delay = CastDelayMinimum; + + //return TimeSpan.FromSeconds( (double)delay / CastDelayPerSecond ); + return delay; + } + + public virtual void FinishSequence() + { + m_State = SpellState.None; + + if ( m_Caster.Spell == this ) + m_Caster.Spell = null; + } + + public virtual int ComputeKarmaAward() + { + return 0; + } + + public virtual bool CheckSequence() + { + int mana = ScaleMana( GetMana() ); + + if ( m_Caster.Deleted || !m_Caster.Alive || m_Caster.Spell != this || m_State != SpellState.Sequencing ) + { + DoFizzle(); + } + else if ( m_Scroll != null && !(m_Scroll is Runebook) && (m_Scroll.Amount <= 0 || m_Scroll.Deleted || m_Scroll.RootParent != m_Caster || (m_Scroll is BaseWand && (((BaseWand)m_Scroll).Charges <= 0 || m_Scroll.Parent != m_Caster))) ) + { + DoFizzle(); + } + else if ( !ConsumeReagents() ) + { + m_Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 502630 ); // More reagents are needed for this spell. + } + else if ( m_Caster.Mana < mana ) + { + m_Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 502625 ); // Insufficient mana for this spell. + } + else if ( Core.AOS && (m_Caster.Frozen || m_Caster.Paralyzed) ) + { + m_Caster.SendLocalizedMessage( 502646 ); // You cannot cast a spell while frozen. + DoFizzle(); + } + else if ( m_Caster is PlayerMobile && ((PlayerMobile) m_Caster).PeacedUntil > DateTime.Now ) + { + m_Caster.SendLocalizedMessage( 1072060 ); // You cannot cast a spell while calmed. + DoFizzle(); + } + else if ( CheckFizzle() ) + { + m_Caster.Mana -= mana; + + if ( m_Scroll is SpellScroll ) + m_Scroll.Consume(); + else if (m_Scroll is BaseWand) + { + ((BaseWand)m_Scroll).ConsumeCharge(m_Caster); + m_Caster.RevealingAction(); + } + + if ( m_Scroll is BaseWand ) + { + bool m = m_Scroll.Movable; + + m_Scroll.Movable = false; + + if ( ClearHandsOnCast ) + m_Caster.ClearHands(); + + m_Scroll.Movable = m; + } + else + { + if ( ClearHandsOnCast ) + m_Caster.ClearHands(); + } + + int karma = ComputeKarmaAward(); + + if ( karma != 0 ) + Misc.Titles.AwardKarma( Caster, karma, true ); + + if( TransformationSpellHelper.UnderTransformation( m_Caster, typeof( VampiricEmbraceSpell ) ) ) + { + bool garlic = false; + + for ( int i = 0; !garlic && i < m_Info.Reagents.Length; ++i ) + garlic = ( m_Info.Reagents[i] == Reagent.Garlic ); + + if ( garlic ) + { + m_Caster.SendLocalizedMessage( 1061651 ); // The garlic burns you! + AOS.Damage( m_Caster, Utility.RandomMinMax( 17, 23 ), 100, 0, 0, 0, 0 ); + } + } + + return true; + } + else + { + DoFizzle(); + } + + return false; + } + + public bool CheckBSequence( Mobile target ) + { + return CheckBSequence( target, false ); + } + + public bool CheckBSequence( Mobile target, bool allowDead ) + { + if ( !target.Alive && !allowDead ) + { + m_Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that! + return false; + } + else if ( Caster.CanBeBeneficial( target, true, allowDead ) && CheckSequence() ) + { + Caster.DoBeneficial( target ); + return true; + } + else + { + return false; + } + } + + public bool CheckHSequence( Mobile target ) + { + if ( !target.Alive ) + { + m_Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that! + return false; + } + else if ( Caster.CanBeHarmful( target ) && CheckSequence() ) + { + Caster.DoHarmful( target ); + return true; + } + else + { + return false; + } + } + + private class AnimTimer : Timer + { + private Spell m_Spell; + + public AnimTimer( Spell spell, int count ) : base( TimeSpan.Zero, AnimateDelay, count ) + { + m_Spell = spell; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Spell.State != SpellState.Casting || m_Spell.m_Caster.Spell != m_Spell ) + { + Stop(); + return; + } + + if (!m_Spell.Caster.Mounted && m_Spell.m_Info.Action >= 0) + { + if (m_Spell.Caster.Body.IsHuman) + m_Spell.Caster.Animate(m_Spell.m_Info.Action, 7, 1, true, false, 0); + else if (m_Spell.Caster.Player && m_Spell.Caster.Body.IsMonster) + m_Spell.Caster.Animate(12, 7, 1, true, false, 0); + } + + if ( !Running ) + m_Spell.m_AnimTimer = null; + } + } + + private class CastTimer : Timer + { + private Spell m_Spell; + + public CastTimer( Spell spell, TimeSpan castDelay ) : base( castDelay ) + { + m_Spell = spell; + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if (m_Spell == null || m_Spell.m_Caster == null) + { + return; + } + else if (m_Spell.m_State == SpellState.Casting && m_Spell.m_Caster.Spell == m_Spell) + { + m_Spell.m_State = SpellState.Sequencing; + m_Spell.m_CastTimer = null; + m_Spell.m_Caster.OnSpellCast(m_Spell); + if (m_Spell.m_Caster.Region != null) + m_Spell.m_Caster.Region.OnSpellCast(m_Spell.m_Caster, m_Spell); + m_Spell.m_Caster.NextSpellTime = DateTime.Now + m_Spell.GetCastRecovery();// Spell.NextSpellDelay; + + Target originalTarget = m_Spell.m_Caster.Target; + + m_Spell.OnCast(); + + if (m_Spell.m_Caster.Player && m_Spell.m_Caster.Target != originalTarget && m_Spell.Caster.Target != null) + m_Spell.m_Caster.Target.BeginTimeout(m_Spell.m_Caster, TimeSpan.FromSeconds(30.0)); + + m_Spell.m_CastTimer = null; + } + } + + public void Tick() + { + OnTick(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Base/SpellCircle.cs b/Scripts/Spells/Base/SpellCircle.cs new file mode 100644 index 0000000..04e15ba --- /dev/null +++ b/Scripts/Spells/Base/SpellCircle.cs @@ -0,0 +1,16 @@ +using System; + +namespace Server.Spells +{ + public enum SpellCircle + { + First, + Second, + Third, + Fourth, + Fifth, + Sixth, + Seventh, + Eighth + } +} \ No newline at end of file diff --git a/Scripts/Spells/Base/SpellHelper.cs b/Scripts/Spells/Base/SpellHelper.cs new file mode 100644 index 0000000..b9fcf7f --- /dev/null +++ b/Scripts/Spells/Base/SpellHelper.cs @@ -0,0 +1,1455 @@ +using System; +using Server; +using Server.Items; +using Server.Guilds; +using Server.Multis; +using Server.Regions; +using Server.Mobiles; +using Server.Targeting; +using Server.Engines.PartySystem; +using Server.Misc; +using Server.Spells.Bushido; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using System.Collections.Generic; +using Server.Spells.Seventh; +using Server.Spells.Fifth; + +namespace Server +{ + public class DefensiveSpell + { + public static void Nullify( Mobile from ) + { + if( !from.CanBeginAction( typeof( DefensiveSpell ) ) ) + new InternalTimer( from ).Start(); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m ) + : base( TimeSpan.FromMinutes( 1.0 ) ) + { + m_Mobile = m; + + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Mobile.EndAction( typeof( DefensiveSpell ) ); + } + } + } +} + +namespace Server.Spells +{ + public enum TravelCheckType + { + RecallFrom, + RecallTo, + GateFrom, + GateTo, + Mark, + TeleportFrom, + TeleportTo + } + + public class SpellHelper + { + private static TimeSpan AosDamageDelay = TimeSpan.FromSeconds( 1.0 ); + private static TimeSpan OldDamageDelay = TimeSpan.FromSeconds( 0.5 ); + + public static TimeSpan GetDamageDelayForSpell( Spell sp ) + { + if( !sp.DelayedDamage ) + return TimeSpan.Zero; + + return (Core.AOS ? AosDamageDelay : OldDamageDelay); + } + + public static bool CheckMulti( Point3D p, Map map ) + { + return CheckMulti( p, map, true, 0); + } + + public static bool CheckMulti(Point3D p, Map map, bool houses) + { + return CheckMulti(p, map, houses, 0); + } + + public static bool CheckMulti( Point3D p, Map map, bool houses, int housingrange ) + { + if( map == null || map == Map.Internal ) + return false; + + Sector sector = map.GetSector( p.X, p.Y ); + + for( int i = 0; i < sector.Multis.Count; ++i ) + { + BaseMulti multi = sector.Multis[i]; + + if( multi is BaseHouse ) + { + BaseHouse bh = (BaseHouse)multi; + + if( ( houses && bh.IsInside( p, 16 ) ) || ( housingrange > 0 && bh.InRange( p, housingrange ) ) ) + return true; + } + else if( multi.Contains( p )) + { + return true; + } + } + + return false; + } + + public static void Turn( Mobile from, object to ) + { + IPoint3D target = to as IPoint3D; + + if( target == null ) + return; + + if( target is Item ) + { + Item item = (Item)target; + + if( item.RootParent != from ) + from.Direction = from.GetDirectionTo( item.GetWorldLocation() ); + } + else if( from != target ) + { + from.Direction = from.GetDirectionTo( target ); + } + } + + private static TimeSpan CombatHeatDelay = TimeSpan.FromSeconds( 30.0 ); + private static bool RestrictTravelCombat = true; + + public static bool CheckCombat( Mobile m ) + { + if( !RestrictTravelCombat ) + return false; + + for( int i = 0; i < m.Aggressed.Count; ++i ) + { + AggressorInfo info = m.Aggressed[i]; + + if( info.Defender.Player && (DateTime.Now - info.LastCombatTime) < CombatHeatDelay ) + return true; + } + + if( Core.Expansion == Expansion.AOS ) + { + for( int i = 0; i < m.Aggressors.Count; ++i ) + { + AggressorInfo info = m.Aggressors[i]; + + if( info.Attacker.Player && (DateTime.Now - info.LastCombatTime) < CombatHeatDelay ) + return true; + } + } + + return false; + } + + public static bool AdjustField( ref Point3D p, Map map, int height, bool mobsBlock ) + { + if( map == null ) + return false; + + for( int offset = 0; offset < 10; ++offset ) + { + Point3D loc = new Point3D( p.X, p.Y, p.Z - offset ); + + if( map.CanFit( loc, height, true, mobsBlock ) ) + { + p = loc; + return true; + } + } + + return false; + } + + public static bool CanRevealCaster( Mobile m ) + { + if ( m is BaseCreature ) + { + BaseCreature c = (BaseCreature)m; + + if ( !c.Controlled ) + return true; + } + + return false; + } + + public static void GetSurfaceTop( ref IPoint3D p ) + { + if( p is Item ) + { + p = ((Item)p).GetSurfaceTop(); + } + else if( p is StaticTarget ) + { + StaticTarget t = (StaticTarget)p; + int z = t.Z; + + if( (t.Flags & TileFlag.Surface) == 0 ) + z -= TileData.ItemTable[t.ItemID & TileData.MaxItemValue].CalcHeight; + + p = new Point3D( t.X, t.Y, z ); + } + } + + public static bool AddStatOffset( Mobile m, StatType type, int offset, TimeSpan duration ) + { + if( offset > 0 ) + return AddStatBonus( m, m, type, offset, duration ); + else if( offset < 0 ) + return AddStatCurse( m, m, type, -offset, duration ); + + return true; + } + + public static bool AddStatBonus( Mobile caster, Mobile target, StatType type ) + { + return AddStatBonus( caster, target, type, GetOffset( caster, target, type, false ), GetDuration( caster, target ) ); + } + + public static bool AddStatBonus( Mobile caster, Mobile target, StatType type, int bonus, TimeSpan duration ) + { + int offset = bonus; + string name = String.Format( "[Magic] {0} Offset", type ); + + StatMod mod = target.GetStatMod( name ); + + if( mod != null && mod.Offset < 0 ) + { + target.AddStatMod( new StatMod( type, name, mod.Offset + offset, duration ) ); + return true; + } + else if( mod == null || mod.Offset < offset ) + { + target.AddStatMod( new StatMod( type, name, offset, duration ) ); + return true; + } + + return false; + } + + public static bool AddStatCurse( Mobile caster, Mobile target, StatType type ) + { + return AddStatCurse( caster, target, type, GetOffset( caster, target, type, true ), GetDuration( caster, target ) ); + } + + public static bool AddStatCurse( Mobile caster, Mobile target, StatType type, int curse, TimeSpan duration ) + { + int offset = -curse; + string name = String.Format( "[Magic] {0} Offset", type ); + + StatMod mod = target.GetStatMod( name ); + + if( mod != null && mod.Offset > 0 ) + { + target.AddStatMod( new StatMod( type, name, mod.Offset + offset, duration ) ); + return true; + } + else if( mod == null || mod.Offset > offset ) + { + target.AddStatMod( new StatMod( type, name, offset, duration ) ); + return true; + } + + return false; + } + + public static TimeSpan GetDuration( Mobile caster, Mobile target ) + { + if( Core.AOS ) + return TimeSpan.FromSeconds( ((6 * caster.Skills.EvalInt.Fixed) / 50) + 1 ); + + return TimeSpan.FromSeconds( caster.Skills[SkillName.Magery].Value * 1.2 ); + } + + private static bool m_DisableSkillCheck; + + public static bool DisableSkillCheck + { + get { return m_DisableSkillCheck; } + set { m_DisableSkillCheck = value; } + } + + public static double GetOffsetScalar( Mobile caster, Mobile target, bool curse ) + { + double percent; + + if( curse ) + percent = 8 + (caster.Skills.EvalInt.Fixed / 100) - (target.Skills.MagicResist.Fixed / 100); + else + percent = 1 + (caster.Skills.EvalInt.Fixed / 100); + + percent *= 0.01; + + if( percent < 0 ) + percent = 0; + + return percent; + } + + public static int GetOffset( Mobile caster, Mobile target, StatType type, bool curse ) + { + if( Core.AOS ) + { + if( !m_DisableSkillCheck ) + { + caster.CheckSkill( SkillName.EvalInt, 0.0, 120.0 ); + + if( curse ) + target.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); + } + + double percent = GetOffsetScalar( caster, target, curse ); + + switch( type ) + { + case StatType.Str: + return (int)(target.RawStr * percent); + case StatType.Dex: + return (int)(target.RawDex * percent); + case StatType.Int: + return (int)(target.RawInt * percent); + } + } + + return 1 + (int)(caster.Skills[SkillName.Magery].Value * 0.1); + } + + public static Guild GetGuildFor( Mobile m ) + { + Guild g = m.Guild as Guild; + + if( g == null && m is BaseCreature ) + { + BaseCreature c = (BaseCreature)m; + m = c.ControlMaster; + + if( m != null ) + g = m.Guild as Guild; + + if( g == null ) + { + m = c.SummonMaster; + + if( m != null ) + g = m.Guild as Guild; + } + } + + return g; + } + + public static bool ValidIndirectTarget( Mobile from, Mobile to ) + { + if( from == to ) + return true; + + if( to.Hidden && to.AccessLevel > from.AccessLevel ) + return false; + + #region Dueling + PlayerMobile pmFrom = from as PlayerMobile; + PlayerMobile pmTarg = to as PlayerMobile; + + if (pmFrom == null && from is BaseCreature) + { + BaseCreature bcFrom = (BaseCreature)from; + + if (bcFrom.Summoned) + pmFrom = bcFrom.SummonMaster as PlayerMobile; + } + + if (pmTarg == null && to is BaseCreature) + { + BaseCreature bcTarg = (BaseCreature)to; + + if (bcTarg.Summoned) + pmTarg = bcTarg.SummonMaster as PlayerMobile; + } + + if (pmFrom != null && pmTarg != null) + { + if (pmFrom.DuelContext != null && pmFrom.DuelContext == pmTarg.DuelContext && pmFrom.DuelContext.Started && pmFrom.DuelPlayer != null && pmTarg.DuelPlayer != null) + return (pmFrom.DuelPlayer.Participant != pmTarg.DuelPlayer.Participant); + } + #endregion + + Guild fromGuild = GetGuildFor( from ); + Guild toGuild = GetGuildFor( to ); + + if( fromGuild != null && toGuild != null && (fromGuild == toGuild || fromGuild.IsAlly( toGuild )) ) + return false; + + Party p = Party.Get( from ); + + if( p != null && p.Contains( to ) ) + return false; + + if( to is BaseCreature ) + { + BaseCreature c = (BaseCreature)to; + + if( c.Controlled || c.Summoned ) + { + if( c.ControlMaster == from || c.SummonMaster == from ) + return false; + + if( p != null && (p.Contains( c.ControlMaster ) || p.Contains( c.SummonMaster )) ) + return false; + } + } + + if( from is BaseCreature ) + { + BaseCreature c = (BaseCreature)from; + + if( c.Controlled || c.Summoned ) + { + if( c.ControlMaster == to || c.SummonMaster == to ) + return false; + + p = Party.Get( to ); + + if( p != null && (p.Contains( c.ControlMaster ) || p.Contains( c.SummonMaster )) ) + return false; + } + } + + if( to is BaseCreature && !((BaseCreature)to).Controlled && ((BaseCreature)to).InitialInnocent ) + return true; + + int noto = Notoriety.Compute( from, to ); + + return (noto != Notoriety.Innocent || from.Kills >= 5); + } + + private static int[] m_Offsets = new int[] + { + -1, -1, + -1, 0, + -1, 1, + 0, -1, + 0, 1, + 1, -1, + 1, 0, + 1, 1 + }; + + public static void Summon( BaseCreature creature, Mobile caster, int sound, TimeSpan duration, bool scaleDuration, bool scaleStats ) + { + Map map = caster.Map; + + if( map == null ) + return; + + double scale = 1.0 + ((caster.Skills[SkillName.Magery].Value - 100.0) / 200.0); + + if( scaleDuration ) + duration = TimeSpan.FromSeconds( duration.TotalSeconds * scale ); + + if( scaleStats ) + { + creature.RawStr = (int)(creature.RawStr * scale); + creature.Hits = creature.HitsMax; + + creature.RawDex = (int)(creature.RawDex * scale); + creature.Stam = creature.StamMax; + + creature.RawInt = (int)(creature.RawInt * scale); + creature.Mana = creature.ManaMax; + } + + Point3D p = new Point3D( caster ); + + if( SpellHelper.FindValidSpawnLocation( map, ref p, true ) ) + { + BaseCreature.Summon( creature, caster, p, sound, duration ); + return; + } + + + /* + int offset = Utility.Random( 8 ) * 2; + + for( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = caster.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = caster.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if( map.CanSpawnMobile( x, y, caster.Z ) ) + { + BaseCreature.Summon( creature, caster, new Point3D( x, y, caster.Z ), sound, duration ); + return; + } + else + { + int z = map.GetAverageZ( x, y ); + + if( map.CanSpawnMobile( x, y, z ) ) + { + BaseCreature.Summon( creature, caster, new Point3D( x, y, z ), sound, duration ); + return; + } + } + } + * */ + + creature.Delete(); + caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + + public static bool FindValidSpawnLocation( Map map, ref Point3D p, bool surroundingsOnly ) + { + if( map == null ) //sanity + return false; + + if( !surroundingsOnly ) + { + if( map.CanSpawnMobile( p ) ) //p's fine. + { + p = new Point3D( p ); + return true; + } + + int z = map.GetAverageZ( p.X, p.Y ); + + if( map.CanSpawnMobile( p.X, p.Y, z ) ) + { + p = new Point3D( p.X, p.Y, z ); + return true; + } + } + + int offset = Utility.Random( 8 ) * 2; + + for( int i = 0; i < m_Offsets.Length; i += 2 ) + { + int x = p.X + m_Offsets[(offset + i) % m_Offsets.Length]; + int y = p.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length]; + + if( map.CanSpawnMobile( x, y, p.Z ) ) + { + p = new Point3D( x, y, p.Z ); + return true; + } + else + { + int z = map.GetAverageZ( x, y ); + + if( map.CanSpawnMobile( x, y, z ) ) + { + p = new Point3D( x, y, z ); + return true; + } + } + } + + return false; + } + + private delegate bool TravelValidator( Map map, Point3D loc ); + + private static TravelValidator[] m_Validators = new TravelValidator[] + { + new TravelValidator( IsFeluccaT2A ), + new TravelValidator( IsKhaldun ), + new TravelValidator( IsIlshenar ), + new TravelValidator( IsTrammelWind ), + new TravelValidator( IsFeluccaWind ), + new TravelValidator( IsFeluccaDungeon ), + new TravelValidator( IsTrammelSolenHive ), + new TravelValidator( IsFeluccaSolenHive ), + new TravelValidator( IsCrystalCave ), + new TravelValidator( IsDoomGauntlet ), + new TravelValidator( IsDoomFerry ), + new TravelValidator( IsSafeZone ), + new TravelValidator( IsFactionStronghold ), + new TravelValidator( IsChampionSpawn ), + new TravelValidator( IsTokunoDungeon ), + new TravelValidator( IsLampRoom ), + new TravelValidator( IsGuardianRoom ), + new TravelValidator( IsMLDungeon ), + new TravelValidator( IsTerMur ) + }; + + private static bool[,] m_Rules = new bool[,] + { + /*T2A(Fel) Khaldun Ilshenar Wind(Tram), Wind(Fel), Dungeons(Fel), Solen(Tram), Solen(Fel), CrystalCave(Malas), Gauntlet(Malas), Gauntlet(Ferry), SafeZone, Stronghold, ChampionSpawn, Dungeons(Tokuno[Malas]), LampRoom(Doom), GuardianRoom(Doom), Heartwood, MLDungeons, TerMur*/ +/* Recall From */ { false, false, true, true, false, false, true, false, false, false, false, true, true, false, true, false, false, false, false, false }, +/* Recall To */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Gate From */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Gate To */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Mark In */ { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }, +/* Tele From */ { true, true, true, true, true, true, true, true, false, true, true, true, false, true, true, true, true, false, true, true }, +/* Tele To */ { true, true, true, true, true, true, true, true, false, true, false, false, false, true, true, true, true, false, false, true }, + }; + + public static void SendInvalidMessage( Mobile caster, TravelCheckType type ) + { + if( type == TravelCheckType.RecallTo || type == TravelCheckType.GateTo ) + caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + else if( type == TravelCheckType.TeleportTo ) + caster.SendLocalizedMessage( 501035 ); // You cannot teleport from here to the destination. + else + caster.SendLocalizedMessage( 501802 ); // Thy spell doth not appear to work... + } + + public static bool CheckTravel(Mobile caster, TravelCheckType type) + { + return CheckTravel(caster, caster.Map, caster.Location, type); + } + + public static bool CheckTravel( Map map, Point3D loc, TravelCheckType type ) + { + return CheckTravel( null, map, loc, type ); + } + + private static Mobile m_TravelCaster; + private static TravelCheckType m_TravelType; + + public static bool CheckTravel( Mobile caster, Map map, Point3D loc, TravelCheckType type ) + { + if( IsInvalid( map, loc ) ) // null, internal, out of bounds + { + if( caster != null ) + SendInvalidMessage( caster, type ); + + return false; + } + + // Scriptiz : ajout des cages (holding cell) + if( caster != null && caster.AccessLevel == AccessLevel.Player && (caster.Region.IsPartOf( typeof( Regions.Jail) ) || caster.Region.IsPartOf( typeof( Regions.HoldingCell) ) )) + { + caster.SendLocalizedMessage(1114345); // You'll need a better jailbreak plan then that! + return false; + } + + // Always allow monsters to teleport + if (caster is BaseCreature && (type == TravelCheckType.TeleportTo || type == TravelCheckType.TeleportFrom)) + { + BaseCreature bc = (BaseCreature)caster; + + if (!bc.Controlled && !bc.Summoned) + return true; + } + + m_TravelCaster = caster; + m_TravelType = type; + + int v = (int)type; + bool isValid = true; + + for( int i = 0; isValid && i < m_Validators.Length; ++i ) + isValid = (m_Rules[v, i] || !m_Validators[i]( map, loc )); + + if( !isValid && caster != null ) + SendInvalidMessage( caster, type ); + + return isValid; + } + + public static bool IsWindLoc( Point3D loc ) + { + int x = loc.X, y = loc.Y; + + return (x >= 5120 && y >= 0 && x < 5376 && y < 256); + } + + public static bool IsFeluccaWind( Map map, Point3D loc ) + { + return (map == Map.Felucca && IsWindLoc( loc )); + } + + public static bool IsTrammelWind( Map map, Point3D loc ) + { + return (map == Map.Trammel && IsWindLoc( loc )); + } + + public static bool IsIlshenar( Map map, Point3D loc ) + { + return (map == Map.Ilshenar); + } + + public static bool IsSolenHiveLoc( Point3D loc ) + { + int x = loc.X, y = loc.Y; + + return (x >= 5640 && y >= 1776 && x < 5935 && y < 2039); + } + + public static bool IsTrammelSolenHive( Map map, Point3D loc ) + { + return (map == Map.Trammel && IsSolenHiveLoc( loc )); + } + + public static bool IsFeluccaSolenHive( Map map, Point3D loc ) + { + return (map == Map.Felucca && IsSolenHiveLoc( loc )); + } + + public static bool IsFeluccaT2A( Map map, Point3D loc ) + { + int x = loc.X, y = loc.Y; + + return (map == Map.Felucca && x >= 5120 && y >= 2304 && x < 6144 && y < 4096); + } + + public static bool IsAnyT2A( Map map, Point3D loc ) + { + int x = loc.X, y = loc.Y; + + return ((map == Map.Trammel || map == Map.Felucca) && x >= 5120 && y >= 2304 && x < 6144 && y < 4096); + } + + public static bool IsFeluccaDungeon( Map map, Point3D loc ) + { + Region region = Region.Find( loc, map ); + return (region.IsPartOf( typeof( DungeonRegion ) ) && region.Map == Map.Felucca); + } + + public static bool IsKhaldun(Map map, Point3D loc) + { + return (Region.Find(loc, map).Name == "Khaldun"); + } + + public static bool IsCrystalCave(Map map, Point3D loc) + { + if (map != Map.Malas || loc.Z >= -80) + return false; + + int x = loc.X, y = loc.Y; + + return (x >= 1182 && y >= 437 && x < 1211 && y < 470) + || (x >= 1156 && y >= 470 && x < 1211 && y < 503) + || (x >= 1176 && y >= 503 && x < 1208 && y < 509) + || (x >= 1188 && y >= 509 && x < 1201 && y < 513); + } + + public static bool IsFactionStronghold( Map map, Point3D loc ) + { + /*// Teleporting is allowed, but only for faction members + if ( !Core.AOS && m_TravelCaster != null && (m_TravelType == TravelCheckType.TeleportTo || m_TravelType == TravelCheckType.TeleportFrom) ) + { + if ( Factions.Faction.Find( m_TravelCaster, true, true ) != null ) + return false; + }*/ + + return (Region.Find( loc, map ).IsPartOf( typeof( Factions.StrongholdRegion ) )); + } + + public static bool IsChampionSpawn( Map map, Point3D loc ) + { + return (Region.Find( loc, map ).IsPartOf( typeof( Engines.CannedEvil.ChampionSpawnRegion ) )); + } + + public static bool IsDoomFerry( Map map, Point3D loc ) + { + if( map != Map.Malas ) + return false; + + int x = loc.X, y = loc.Y; + + if( x >= 426 && y >= 314 && x <= 430 && y <= 331 ) + return true; + + if( x >= 406 && y >= 247 && x <= 410 && y <= 264 ) + return true; + + return false; + } + + public static bool IsSafeZone(Map map, Point3D loc) + { + #region Duels + if (Region.Find(loc, map).IsPartOf(typeof(Engines.ConPVP.SafeZone))) + { + if (m_TravelType == TravelCheckType.TeleportTo || m_TravelType == TravelCheckType.TeleportFrom) + { + PlayerMobile pm = m_TravelCaster as PlayerMobile; + + if (pm != null && pm.DuelPlayer != null && !pm.DuelPlayer.Eliminated) + return true; + } + + return true; + } + #endregion + + return false; + } + + public static bool IsTokunoDungeon( Map map, Point3D loc ) + { + //The tokuno dungeons are really inside malas + if( map != Map.Malas ) + return false; + + int x = loc.X, y = loc.Y, z = loc.Z; + + bool r1 = (x >= 0 && y >= 0 && x <= 128 && y <= 128); + bool r2 = (x >= 45 && y >= 320 && x < 195 && y < 710); + + return (r1 || r2); + } + + public static bool IsDoomGauntlet( Map map, Point3D loc ) + { + if( map != Map.Malas ) + return false; + + int x = loc.X - 256, y = loc.Y - 304; + + return (x >= 0 && y >= 0 && x < 256 && y < 256); + } + + public static bool IsLampRoom( Map map, Point3D loc ) + { + if ( map != Map.Malas ) + return false; + + int x = loc.X, y = loc.Y; + + return ( x >= 465 && y >= 92 && x < 474 && y < 102 ); + } + + public static bool IsGuardianRoom( Map map, Point3D loc ) + { + if ( map != Map.Malas ) + return false; + + int x = loc.X, y = loc.Y; + + return ( x >= 356 && y >= 5 && x < 375 && y < 25 ); + } + public static bool IsHeartwood(Map map, Point3D loc) + { + int x = loc.X, y = loc.Y; + + return (map == Map.Trammel || map == Map.Felucca) && (x >= 6911 && y >= 254 && x < 7167 && y < 511); + } + + public static bool IsMLDungeon(Map map, Point3D loc) + { + return MondainsLegacy.IsMLRegion(Region.Find(loc, map)); + } + + public static bool IsTerMur(Map map, Point3D loc) + { + return (map == Map.TerMur); + } + + public static bool IsInvalid( Map map, Point3D loc ) + { + if( map == null || map == Map.Internal ) + return true; + + int x = loc.X, y = loc.Y; + + return (x < 0 || y < 0 || x >= map.Width || y >= map.Height); + } + + //towns + public static bool IsTown(IPoint3D loc, Mobile caster) + { + if (loc is Item) + loc = ((Item)loc).GetWorldLocation(); + + return IsTown(new Point3D(loc), caster); + } + + public static bool IsTown(Point3D loc, Mobile caster) + { + Map map = caster.Map; + + if (map == null) + return false; + + #region Dueling + Engines.ConPVP.SafeZone sz = (Engines.ConPVP.SafeZone)Region.Find(loc, map).GetRegion(typeof(Engines.ConPVP.SafeZone)); + + if (sz != null) + { + PlayerMobile pm = (PlayerMobile)caster; + + if (pm == null || pm.DuelContext == null || !pm.DuelContext.Started || pm.DuelPlayer == null || pm.DuelPlayer.Eliminated) + return true; + } + #endregion + + GuardedRegion reg = (GuardedRegion)Region.Find(loc, map).GetRegion(typeof(GuardedRegion)); + + return (reg != null && !reg.IsDisabled()); + } + public static bool CheckTown( IPoint3D loc, Mobile caster ) + { + if( loc is Item ) + loc = ((Item)loc).GetWorldLocation(); + + return CheckTown( new Point3D( loc ), caster ); + } + + public static bool CheckTown( Point3D loc, Mobile caster ) + { + if( IsTown( loc, caster ) ) + { + caster.SendLocalizedMessage( 500946 ); // You cannot cast this in town! + return false; + } + + return true; + } + + //magic reflection + public static void CheckReflect( int circle, Mobile caster, ref Mobile target ) + { + CheckReflect( circle, ref caster, ref target ); + } + + public static void CheckReflect( int circle, ref Mobile caster, ref Mobile target ) + { + if( target.MagicDamageAbsorb > 0 ) + { + ++circle; + + target.MagicDamageAbsorb -= circle; + + // This order isn't very intuitive, but you have to nullify reflect before target gets switched + + bool reflect = (target.MagicDamageAbsorb >= 0); + + if( target is BaseCreature ) + ((BaseCreature)target).CheckReflect( caster, ref reflect ); + + if( target.MagicDamageAbsorb <= 0 ) + { + target.MagicDamageAbsorb = 0; + DefensiveSpell.Nullify( target ); + } + + if( reflect ) + { + target.FixedEffect( 0x37B9, 10, 5 ); + + Mobile temp = caster; + caster = target; + target = temp; + } + } + else if( target is BaseCreature ) + { + bool reflect = false; + + ((BaseCreature)target).CheckReflect( caster, ref reflect ); + + if( reflect ) + { + target.FixedEffect( 0x37B9, 10, 5 ); + + Mobile temp = caster; + caster = target; + target = temp; + } + } + } + + public static void Damage( Spell spell, Mobile target, double damage ) + { + TimeSpan ts = GetDamageDelayForSpell( spell ); + + Damage( spell, ts, target, spell.Caster, damage ); + } + + public static void Damage( TimeSpan delay, Mobile target, double damage ) + { + Damage( delay, target, null, damage ); + } + + public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage ) + { + Damage( null, delay, target, from, damage ); + } + + public static void Damage( Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage ) + { + int iDamage = (int)damage; + + if( delay == TimeSpan.Zero ) + { + if( from is BaseCreature ) + ((BaseCreature)from).AlterSpellDamageTo( target, ref iDamage ); + + if( target is BaseCreature ) + ((BaseCreature)target).AlterSpellDamageFrom( from, ref iDamage ); + + target.Damage( iDamage, from ); + } + else + { + new SpellDamageTimer( spell, target, from, iDamage, delay ).Start(); + } + + if( target is BaseCreature && from != null && delay == TimeSpan.Zero ) + { + BaseCreature c = (BaseCreature)target; + + c.OnHarmfulSpell(from); + c.OnDamagedBySpell(from); + } + } + + public static void Damage( Spell spell, Mobile target, double damage, int phys, int fire, int cold, int pois, int nrgy ) + { + TimeSpan ts = GetDamageDelayForSpell( spell ); + + Damage( spell, ts, target, spell.Caster, damage, phys, fire, cold, pois, nrgy, DFAlgorithm.Standard ); + } + + public static void Damage( Spell spell, Mobile target, double damage, int phys, int fire, int cold, int pois, int nrgy, DFAlgorithm dfa ) + { + TimeSpan ts = GetDamageDelayForSpell( spell ); + + Damage( spell, ts, target, spell.Caster, damage, phys, fire, cold, pois, nrgy, dfa ); + } + + public static void Damage( TimeSpan delay, Mobile target, double damage, int phys, int fire, int cold, int pois, int nrgy ) + { + Damage( delay, target, null, damage, phys, fire, cold, pois, nrgy ); + } + + public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, int pois, int nrgy ) + { + Damage( delay, target, from, damage, phys, fire, cold, pois, nrgy, DFAlgorithm.Standard ); + } + + public static void Damage( TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, int pois, int nrgy, DFAlgorithm dfa ) + { + Damage( null, delay, target, from, damage, phys, fire, cold, pois, nrgy, dfa ); + } + + public static void Damage( Spell spell, TimeSpan delay, Mobile target, Mobile from, double damage, int phys, int fire, int cold, int pois, int nrgy, DFAlgorithm dfa ) + { + int iDamage = (int)damage; + + if( delay == TimeSpan.Zero ) + { + if( from is BaseCreature ) + ((BaseCreature)from).AlterSpellDamageTo( target, ref iDamage ); + + if( target is BaseCreature ) + ((BaseCreature)target).AlterSpellDamageFrom( from, ref iDamage ); + + WeightOverloading.DFA = dfa; + + int damageGiven = AOS.Damage( target, from, iDamage, phys, fire, cold, pois, nrgy ); + + if ( from != null ) // sanity check + { + DoLeech( damageGiven, from, target ); + } + + WeightOverloading.DFA = DFAlgorithm.Standard; + } + else + { + new SpellDamageTimerAOS( spell, target, from, iDamage, phys, fire, cold, pois, nrgy, delay, dfa ).Start(); + } + + if( target is BaseCreature && from != null && delay == TimeSpan.Zero ) + { + BaseCreature c = (BaseCreature)target; + + c.OnHarmfulSpell(from); + c.OnDamagedBySpell(from); + } + } + + public static void DoLeech( int damageGiven, Mobile from, Mobile target ) + { + TransformContext context = TransformationSpellHelper.GetContext( from ); + + if ( context != null ) /* cleanup */ + { + if ( context.Type == typeof( WraithFormSpell ) ) + { + int wraithLeech = ( 5 + (int)( ( 15 * from.Skills.SpiritSpeak.Value ) / 100 ) ); // Wraith form gives 5-20% mana leech + int manaLeech = AOS.Scale( damageGiven, wraithLeech ); + if ( manaLeech != 0 ) + { + from.Mana += manaLeech; + from.PlaySound( 0x44D ); + } + } + else if ( context.Type == typeof( VampiricEmbraceSpell ) ) + { + from.Hits += AOS.Scale( damageGiven, 20 ); + from.PlaySound( 0x44D ); + } + } + } + + public static void Heal( int amount, Mobile target, Mobile from ) + { + Heal( amount, target, from, true ); + } + public static void Heal( int amount, Mobile target, Mobile from, bool message ) + { + //TODO: All Healing *spells* go through ArcaneEmpowerment + target.Heal( amount, from, message ); + } + + private class SpellDamageTimer : Timer + { + private Mobile m_Target, m_From; + private int m_Damage; + private Spell m_Spell; + + public SpellDamageTimer( Spell s, Mobile target, Mobile from, int damage, TimeSpan delay ) + : base( delay ) + { + m_Target = target; + m_From = from; + m_Damage = damage; + m_Spell = s; + + if( m_Spell != null && m_Spell.DelayedDamage && !m_Spell.DelayedDamageStacking ) + m_Spell.StartDelayedDamageContext( target, this ); + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if( m_From is BaseCreature ) + ((BaseCreature)m_From).AlterSpellDamageTo( m_Target, ref m_Damage ); + + if( m_Target is BaseCreature ) + ((BaseCreature)m_Target).AlterSpellDamageFrom( m_From, ref m_Damage ); + + m_Target.Damage( m_Damage ); + if( m_Spell != null ) + m_Spell.RemoveDelayedDamageContext( m_Target ); + } + } + + private class SpellDamageTimerAOS : Timer + { + private Mobile m_Target, m_From; + private int m_Damage; + private int m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy; + private DFAlgorithm m_DFA; + private Spell m_Spell; + + public SpellDamageTimerAOS( Spell s, Mobile target, Mobile from, int damage, int phys, int fire, int cold, int pois, int nrgy, TimeSpan delay, DFAlgorithm dfa ) + : base( delay ) + { + m_Target = target; + m_From = from; + m_Damage = damage; + m_Phys = phys; + m_Fire = fire; + m_Cold = cold; + m_Pois = pois; + m_Nrgy = nrgy; + m_DFA = dfa; + m_Spell = s; + if( m_Spell != null && m_Spell.DelayedDamage && !m_Spell.DelayedDamageStacking ) + m_Spell.StartDelayedDamageContext( target, this ); + + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if( m_From is BaseCreature && m_Target != null ) + ((BaseCreature)m_From).AlterSpellDamageTo( m_Target, ref m_Damage ); + + if( m_Target is BaseCreature && m_From != null ) + ((BaseCreature)m_Target).AlterSpellDamageFrom( m_From, ref m_Damage ); + + WeightOverloading.DFA = m_DFA; + + int damageGiven = AOS.Damage( m_Target, m_From, m_Damage, m_Phys, m_Fire, m_Cold, m_Pois, m_Nrgy ); + + if ( m_From != null ) // sanity check + { + DoLeech( damageGiven, m_From, m_Target ); + } + + WeightOverloading.DFA = DFAlgorithm.Standard; + + if( m_Target is BaseCreature && m_From != null ) + { + BaseCreature c = (BaseCreature)m_Target; + + c.OnHarmfulSpell(m_From); + c.OnDamagedBySpell(m_From); + } + + if( m_Spell != null ) + m_Spell.RemoveDelayedDamageContext( m_Target ); + + } + } + } + + public class TransformationSpellHelper + { + #region Context Stuff + private static Dictionary m_Table = new Dictionary(); + + public static void AddContext( Mobile m, TransformContext context ) + { + m_Table[m] = context; + } + + public static void RemoveContext( Mobile m, bool resetGraphics ) + { + TransformContext context = GetContext( m ); + + if( context != null ) + RemoveContext( m, context, resetGraphics ); + } + + public static void RemoveContext( Mobile m, TransformContext context, bool resetGraphics ) + { + if( m_Table.ContainsKey( m ) ) + { + m_Table.Remove( m ); + + List mods = context.Mods; + + for( int i = 0; i < mods.Count; ++i ) + m.RemoveResistanceMod( mods[i] ); + + if( resetGraphics ) + { + m.HueMod = -1; + m.BodyMod = 0; + } + + context.Timer.Stop(); + context.Spell.RemoveEffect( m ); + } + } + + public static TransformContext GetContext( Mobile m ) + { + TransformContext context = null; + + m_Table.TryGetValue( m, out context ); + + return context; + } + + public static bool UnderTransformation( Mobile m ) + { + return (GetContext( m ) != null); + } + + public static bool UnderTransformation( Mobile m, Type type ) + { + TransformContext context = GetContext( m ); + + return (context != null && context.Type == type); + } + #endregion + + public static bool CheckCast( Mobile caster, Spell spell ) + { + if( Factions.Sigil.ExistsOn( caster ) ) + { + caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return false; + } + else if( !caster.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed. + return false; + } + else if( AnimalForm.UnderTransformation( caster ) ) + { + caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. + return false; + } + + return true; + } + + public static bool OnCast( Mobile caster, Spell spell ) + { + ITransformationSpell transformSpell = spell as ITransformationSpell; + + if( transformSpell == null ) + return false; + + if( Factions.Sigil.ExistsOn( caster ) ) + { + caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if( !caster.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + caster.SendLocalizedMessage( 1061628 ); // You can't do that while polymorphed. + } + else if ( DisguiseTimers.IsDisguised( caster ) ) + { + caster.SendLocalizedMessage( 1061631 ); // You can't do that while disguised. + return false; + } + else if( AnimalForm.UnderTransformation( caster ) ) + { + caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. + } + else if( !caster.CanBeginAction( typeof( IncognitoSpell ) ) || (caster.IsBodyMod && GetContext( caster ) == null) ) + { + spell.DoFizzle(); + } + else if( spell.CheckSequence() ) + { + TransformContext context = GetContext( caster ); + Type ourType = spell.GetType(); + + bool wasTransformed = (context != null); + bool ourTransform = (wasTransformed && context.Type == ourType); + + if( wasTransformed ) + { + RemoveContext( caster, context, ourTransform ); + + if( ourTransform ) + { + caster.PlaySound( 0xFA ); + caster.FixedParticles( 0x3728, 1, 13, 5042, EffectLayer.Waist ); + } + } + + if( !ourTransform ) + { + List mods = new List(); + + if( transformSpell.PhysResistOffset != 0 ) + mods.Add( new ResistanceMod( ResistanceType.Physical, transformSpell.PhysResistOffset ) ); + + if( transformSpell.FireResistOffset != 0 ) + mods.Add( new ResistanceMod( ResistanceType.Fire, transformSpell.FireResistOffset ) ); + + if( transformSpell.ColdResistOffset != 0 ) + mods.Add( new ResistanceMod( ResistanceType.Cold, transformSpell.ColdResistOffset ) ); + + if( transformSpell.PoisResistOffset != 0 ) + mods.Add( new ResistanceMod( ResistanceType.Poison, transformSpell.PoisResistOffset ) ); + + if( transformSpell.NrgyResistOffset != 0 ) + mods.Add( new ResistanceMod( ResistanceType.Energy, transformSpell.NrgyResistOffset ) ); + + if( !((Body)transformSpell.Body).IsHuman ) + { + Mobiles.IMount mt = caster.Mount; + + if( mt != null ) + mt.Rider = null; + } + + caster.BodyMod = transformSpell.Body; + caster.HueMod = transformSpell.Hue; + + for( int i = 0; i < mods.Count; ++i ) + caster.AddResistanceMod( mods[i] ); + + transformSpell.DoEffect( caster ); + + Timer timer = new TransformTimer( caster, transformSpell ); + timer.Start(); + + AddContext( caster, new TransformContext( timer, mods, ourType, transformSpell ) ); + return true; + } + } + + return false; + } + } + + public interface ITransformationSpell + { + int Body { get; } + int Hue { get; } + + int PhysResistOffset { get; } + int FireResistOffset { get; } + int ColdResistOffset { get; } + int PoisResistOffset { get; } + int NrgyResistOffset { get; } + + double TickRate { get; } + void OnTick( Mobile m ); + + void DoEffect( Mobile m ); + void RemoveEffect( Mobile m ); + } + + + public class TransformContext + { + private Timer m_Timer; + private List m_Mods; + private Type m_Type; + private ITransformationSpell m_Spell; + + public Timer Timer { get { return m_Timer; } } + public List Mods { get { return m_Mods; } } + public Type Type { get { return m_Type; } } + public ITransformationSpell Spell { get { return m_Spell; } } + + public TransformContext( Timer timer, List mods, Type type, ITransformationSpell spell ) + { + m_Timer = timer; + m_Mods = mods; + m_Type = type; + m_Spell = spell; + } + } + + public class TransformTimer : Timer + { + private Mobile m_Mobile; + private ITransformationSpell m_Spell; + + public TransformTimer( Mobile from, ITransformationSpell spell ) + : base( TimeSpan.FromSeconds( spell.TickRate ), TimeSpan.FromSeconds( spell.TickRate ) ) + { + m_Mobile = from; + m_Spell = spell; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if( m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Spell.Body || m_Mobile.Hue != m_Spell.Hue ) + { + TransformationSpellHelper.RemoveContext( m_Mobile, true ); + Stop(); + } + else + { + m_Spell.OnTick( m_Mobile ); + } + } + } +} diff --git a/Scripts/Spells/Base/SpellInfo.cs b/Scripts/Spells/Base/SpellInfo.cs new file mode 100644 index 0000000..65f9099 --- /dev/null +++ b/Scripts/Spells/Base/SpellInfo.cs @@ -0,0 +1,66 @@ +using System; +using Server; + +namespace Server.Spells +{ + public class SpellInfo + { + private string m_Name; + private string m_Mantra; + private Type[] m_Reagents; + private int[] m_Amounts; + private int m_Action; + private bool m_AllowTown; + private int m_LeftHandEffect, m_RightHandEffect; + + public SpellInfo( string name, string mantra, params Type[] regs ) : this( name, mantra, 16, 0, 0, true, regs ) + { + } + + public SpellInfo( string name, string mantra, bool allowTown, params Type[] regs ) : this( name, mantra, 16, 0, 0, allowTown, regs ) + { + } + + public SpellInfo( string name, string mantra, int action, params Type[] regs ) : this( name, mantra, action, 0, 0, true, regs ) + { + } + + public SpellInfo( string name, string mantra, int action, bool allowTown, params Type[] regs ) : this( name, mantra, action, 0, 0, allowTown, regs ) + { + } + + public SpellInfo( string name, string mantra, int action, int handEffect, params Type[] regs ) : this( name, mantra, action, handEffect, handEffect, true, regs ) + { + } + + public SpellInfo( string name, string mantra, int action, int handEffect, bool allowTown, params Type[] regs ) : this( name, mantra, action, handEffect, handEffect, allowTown, regs ) + { + } + + public SpellInfo( string name, string mantra, int action, int leftHandEffect, int rightHandEffect, bool allowTown, params Type[] regs ) + { + m_Name = name; + m_Mantra = mantra; + m_Action = action; + m_Reagents = regs; + m_AllowTown = allowTown; + + m_LeftHandEffect = leftHandEffect; + m_RightHandEffect = rightHandEffect; + + m_Amounts = new int[regs.Length]; + + for ( int i = 0; i < regs.Length; ++i ) + m_Amounts[i] = 1; + } + + public int Action{ get{ return m_Action; } set{ m_Action = value; } } + public bool AllowTown{ get{ return m_AllowTown; } set{ m_AllowTown = value; } } + public int[] Amounts{ get{ return m_Amounts; } set{ m_Amounts = value; } } + public string Mantra{ get{ return m_Mantra; } set{ m_Mantra = value; } } + public string Name{ get{ return m_Name; } set{ m_Name = value; } } + public Type[] Reagents{ get{ return m_Reagents; } set{ m_Reagents = value; } } + public int LeftHandEffect{ get{ return m_LeftHandEffect; } set{ m_LeftHandEffect = value; } } + public int RightHandEffect{ get{ return m_RightHandEffect; } set{ m_RightHandEffect = value; } } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Base/SpellRegistry.cs b/Scripts/Spells/Base/SpellRegistry.cs new file mode 100644 index 0000000..45d2b8f --- /dev/null +++ b/Scripts/Spells/Base/SpellRegistry.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Server.Spells.Bushido; +using Server.Spells.Chivalry; +using Server.Items; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; +using Server.Spells.Druid; + +namespace Server.Spells +{ + public class SpellRegistry + { + private static Type[] m_Types = new Type[700]; + private static int m_Count; + + public static Type[] Types + { + get + { + m_Count = -1; + return m_Types; + } + } + + //What IS this used for anyways. + public static int Count + { + get + { + if ( m_Count == -1 ) + { + m_Count = 0; + + for ( int i = 0; i < m_Types.Length; ++i ) + if ( m_Types[i] != null ) + ++m_Count; + } + + return m_Count; + } + } + + private static Dictionary m_IDsFromTypes = new Dictionary( m_Types.Length ); + + private static Dictionary m_SpecialMoves = new Dictionary(); + public static Dictionary SpecialMoves { get { return m_SpecialMoves; } } + + public static int GetRegistryNumber( ISpell s ) + { + return GetRegistryNumber( s.GetType() ); + } + + public static int GetRegistryNumber( SpecialMove s ) + { + return GetRegistryNumber( s.GetType() ); + } + + public static int GetRegistryNumber( Type type ) + { + if( m_IDsFromTypes.ContainsKey( type ) ) + return m_IDsFromTypes[type]; + + return -1; + } + + public static void Register( int spellID, Type type ) + { + if ( spellID < 0 || spellID >= m_Types.Length ) + return; + + if ( m_Types[spellID] == null ) + ++m_Count; + + m_Types[spellID] = type; + + if( !m_IDsFromTypes.ContainsKey( type ) ) + m_IDsFromTypes.Add( type, spellID ); + + if( type.IsSubclassOf( typeof( SpecialMove ) ) ) + { + SpecialMove spm = null; + + try + { + spm = Activator.CreateInstance( type ) as SpecialMove; + } + catch + { + } + + if( spm != null ) + m_SpecialMoves.Add( spellID, spm ); + } + } + + public static SpecialMove GetSpecialMove( int spellID ) + { + if ( spellID < 0 || spellID >= m_Types.Length ) + return null; + + Type t = m_Types[spellID]; + + if ( t == null || !t.IsSubclassOf( typeof( SpecialMove ) ) || !m_SpecialMoves.ContainsKey( spellID ) ) + return null; + + return m_SpecialMoves[spellID]; + } + + private static object[] m_Params = new object[2]; + + public static Spell NewSpell( int spellID, Mobile caster, Item scroll ) + { + if ( spellID < 0 || spellID >= m_Types.Length ) + return null; + + Type t = m_Types[spellID]; + + if( t != null && !t.IsSubclassOf( typeof( SpecialMove ) ) ) + { + m_Params[0] = caster; + m_Params[1] = scroll; + + try + { + return (Spell)Activator.CreateInstance( t, m_Params ); + } + catch + { + } + } + + return null; + } + + private static string[] m_CircleNames = new string[] + { + "First", + "Second", + "Third", + "Fourth", + "Fifth", + "Sixth", + "Seventh", + "Eighth", + "Necromancy", + "Chivalry", + "Bushido", + "Ninjitsu", + "Spellweaving", + "Druidic" + }; + + public static Spell NewSpell( string name, Mobile caster, Item scroll ) + { + for ( int i = 0; i < m_CircleNames.Length; ++i ) + { + Type t = ScriptCompiler.FindTypeByFullName( String.Format( "Server.Spells.{0}.{1}", m_CircleNames[i], name ) ); + + if ( t != null && !t.IsSubclassOf( typeof( SpecialMove ) ) ) + { + m_Params[0] = caster; + m_Params[1] = scroll; + + try + { + return (Spell)Activator.CreateInstance( t, m_Params ); + } + catch + { + } + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Base/SpellState.cs b/Scripts/Spells/Base/SpellState.cs new file mode 100644 index 0000000..65544e4 --- /dev/null +++ b/Scripts/Spells/Base/SpellState.cs @@ -0,0 +1,11 @@ +using System; + +namespace Server.Spells +{ + public enum SpellState + { + None = 0, + Casting = 1, // We are in the process of casting (that is, waiting GetCastTime() and doing animations). Spell casting may be interupted in this state. + Sequencing = 2 // Casting completed, but the full spell sequence isn't. Usually waiting for a target response. Some actions are restricted in this state (using skills for example). + } +} \ No newline at end of file diff --git a/Scripts/Spells/Bushido/Confidence.cs b/Scripts/Spells/Bushido/Confidence.cs new file mode 100644 index 0000000..b504181 --- /dev/null +++ b/Scripts/Spells/Bushido/Confidence.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Bushido +{ + public class Confidence : SamuraiSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Confidence", null, + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.25 ); } } + + public override double RequiredSkill{ get{ return 25.0; } } + public override int RequiredMana{ get{ return 10; } } + + public Confidence( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 ); + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + Caster.SendLocalizedMessage( 1063115 ); // You exude confidence. + + Caster.FixedParticles( 0x375A, 1, 17, 0x7DA, 0x960, 0x3, EffectLayer.Waist ); + Caster.PlaySound( 0x51A ); + + OnCastSuccessful( Caster ); + + BeginConfidence( Caster ); + BeginRegenerating( Caster ); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsConfident( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static void BeginConfidence( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + t = new InternalTimer( m ); + + m_Table[m] = t; + + t.Start(); + } + + public static void EndConfidence( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + m_Table.Remove( m ); + + OnEffectEnd( m, typeof( Confidence ) ); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 15.0 ) ) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndConfidence( m_Mobile ); + m_Mobile.SendLocalizedMessage( 1063116 ); // Your confidence wanes. + } + } + + private static Hashtable m_RegenTable = new Hashtable(); + + public static bool IsRegenerating( Mobile m ) + { + return m_RegenTable.Contains( m ); + } + + public static void BeginRegenerating( Mobile m ) + { + Timer t = (Timer)m_RegenTable[m]; + + if ( t != null ) + t.Stop(); + + t = new RegenTimer( m ); + + m_RegenTable[m] = t; + + t.Start(); + } + + public static void StopRegenerating( Mobile m ) + { + Timer t = (Timer)m_RegenTable[m]; + + if ( t != null ) + t.Stop(); + + m_RegenTable.Remove( m ); + } + + private class RegenTimer : Timer + { + private Mobile m_Mobile; + private int m_Ticks; + private int m_Hits; + + public RegenTimer( Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Mobile = m; + m_Hits = 15 + (m.Skills.Bushido.Fixed * m.Skills.Bushido.Fixed / 57600); + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + ++m_Ticks; + + if ( m_Ticks >= 5 ) + { + m_Mobile.Hits += (m_Hits - (m_Hits * 4 / 5)); + StopRegenerating( m_Mobile ); + } + + m_Mobile.Hits += (m_Hits / 5); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Bushido/CounterAttack.cs b/Scripts/Spells/Bushido/CounterAttack.cs new file mode 100644 index 0000000..49b0fbb --- /dev/null +++ b/Scripts/Spells/Bushido/CounterAttack.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Bushido +{ + public class CounterAttack : SamuraiSpell + { + private static SpellInfo m_Info = new SpellInfo( + "CounterAttack", null, + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.25 ); } } + + public override double RequiredSkill{ get{ return 40.0; } } + public override int RequiredMana{ get{ return 5; } } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseShield != null ) + return true; + + if ( Caster.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon != null ) + return true; + + if ( Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon != null ) + return true; + + Caster.SendLocalizedMessage( 1062944 ); // You must have a weapon or a shield equipped to use this ability! + return false; + } + + public CounterAttack( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 ); + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + Caster.SendLocalizedMessage( 1063118 ); // You prepare to respond immediately to the next blocked blow. + + OnCastSuccessful( Caster ); + + StartCountering( Caster ); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsCountering( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static void StartCountering( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + t = new InternalTimer( m ); + + m_Table[m] = t; + + t.Start(); + } + + public static void StopCountering( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + t.Stop(); + + m_Table.Remove( m ); + + OnEffectEnd( m, typeof( CounterAttack ) ); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + StopCountering( m_Mobile ); + m_Mobile.SendLocalizedMessage( 1063119 ); // You return to your normal stance. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Bushido/Evasion.cs b/Scripts/Spells/Bushido/Evasion.cs new file mode 100644 index 0000000..95f5651 --- /dev/null +++ b/Scripts/Spells/Bushido/Evasion.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Spells; +using Server.Targeting; + +namespace Server.Spells.Bushido +{ + public class Evasion : SamuraiSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Evasion", null, + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.25 ); } } + + public override double RequiredSkill { get { return 60.0; } } + public override int RequiredMana { get { return 10; } } + + public override bool CheckCast() + { + if( VerifyCast( Caster, true ) ) + return base.CheckCast(); + + return false; + } + + public static bool VerifyCast( Mobile Caster, bool messages ) + { + if( Caster == null ) // Sanity + return false; + + BaseWeapon weap = Caster.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon; + + if( weap == null ) + weap = Caster.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon; + + if ( weap != null ) { + if ( Core.ML && Caster.Skills[weap.Skill].Base < 50 ) { + if ( messages ) { + Caster.SendLocalizedMessage( 1076206 ); // Your skill with your equipped weapon must be 50 or higher to use Evasion. + } + return false; + } + } else if ( !( Caster.FindItemOnLayer( Layer.TwoHanded ) is BaseShield ) ) { + if ( messages ) { + Caster.SendLocalizedMessage( 1062944 ); // You must have a weapon or a shield equipped to use this ability! + } + return false; + } + + if ( !Caster.CanBeginAction( typeof( Evasion ) ) ) { + if ( messages ) { + Caster.SendLocalizedMessage( 501789 ); // You must wait before trying again. + } + return false; + } + + return true; + } + + public static bool CheckSpellEvasion( Mobile defender ) + { + BaseWeapon weap = defender.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon; + + if ( weap == null ) + weap = defender.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon; + + if ( Core.ML ) { + if ( defender.Spell != null && defender.Spell.IsCasting ) { + return false; + } + + if ( weap != null ) { + if ( defender.Skills[weap.Skill].Base < 50 ) { + return false; + } + } else if ( !( defender.FindItemOnLayer( Layer.TwoHanded ) is BaseShield ) ) { + return false; + } + } + + if ( IsEvading( defender ) && BaseWeapon.CheckParry( defender ) ) { + defender.Emote( "*evades*" ); // Yes. Eew. Blame OSI. + defender.FixedEffect( 0x37B9, 10, 16 ); + return true; + } + + return false; + } + + public Evasion( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect( 0x37C4, 10, 7, 4, 3 ); + } + + public override void OnCast() + { + if( CheckSequence() ) + { + Caster.SendLocalizedMessage( 1063120 ); // You feel that you might be able to deflect any attack! + Caster.FixedParticles( 0x376A, 1, 20, 0x7F5, 0x960, 3, EffectLayer.Waist ); + Caster.PlaySound( 0x51B ); + + OnCastSuccessful( Caster ); + + BeginEvasion( Caster ); + + Caster.BeginAction( typeof( Evasion ) ); + Timer.DelayCall( TimeSpan.FromSeconds( 20.0 ), delegate { Caster.EndAction( typeof( Evasion ) ); } ); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool IsEvading( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static TimeSpan GetEvadeDuration( Mobile m ) + { + + /* Evasion duration now scales with Bushido skill + * + * If the player has higher than GM Bushido, and GM Tactics and Anatomy, they get a 1 second bonus + * Evasion duration range: + * o 3-6 seconds w/o tactics/anatomy + * o 6-7 seconds w/ GM+ Bushido and GM tactics/anatomy + */ + + if( !Core.ML ) + return TimeSpan.FromSeconds( 8.0 ); + + double seconds = 3; + + if( m.Skills.Bushido.Value > 60 ) + seconds += (m.Skills.Bushido.Value - 60) / 20; + + if( m.Skills.Anatomy.Value >= 100.0 && m.Skills.Tactics.Value >= 100.0 && m.Skills.Bushido.Value > 100.0 ) //Bushido being HIGHER than 100 for bonus is intended + seconds++; + + return TimeSpan.FromSeconds( (int)seconds ); + } + + public static double GetParryScalar( Mobile m ) + { + /* Evasion modifier to parry now scales with Bushido skill + * + * If the player has higher than GM Bushido, and at least GM Tactics and Anatomy, they get a bonus to their evasion modifier (10% bonus to the evasion modifier to parry NOT 10% to the final parry chance) + * + * Bonus modifier to parry range: (these are the ranges for the evasion modifier) + * o 16-40% bonus w/o tactics/anatomy + * o 42-50% bonus w/ GM+ bushido and GM tactics/anatomy + */ + + if( !Core.ML ) + return 1.5; + + double bonus = 0; + + if( m.Skills.Bushido.Value >= 60 ) + bonus += ( ( ( m.Skills.Bushido.Value - 60 ) * .004 ) + 0.16 ); + + if( m.Skills.Anatomy.Value >= 100 && m.Skills.Tactics.Value >= 100 && m.Skills.Bushido.Value > 100 ) //Bushido being HIGHER than 100 for bonus is intended + bonus += 0.10; + + return 1.0 + bonus; + } + + public static void BeginEvasion( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if( t != null ) + t.Stop(); + + t = new InternalTimer( m, GetEvadeDuration( m ) ); + + m_Table[m] = t; + + t.Start(); + } + + public static void EndEvasion( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if( t != null ) + t.Stop(); + + m_Table.Remove( m ); + + OnEffectEnd( m, typeof( Evasion ) ); + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + EndEvasion( m_Mobile ); + m_Mobile.SendLocalizedMessage( 1063121 ); // You no longer feel that you could deflect any attack. + } + } + } +} diff --git a/Scripts/Spells/Bushido/HonorableExecution.cs b/Scripts/Spells/Bushido/HonorableExecution.cs new file mode 100644 index 0000000..4008a8e --- /dev/null +++ b/Scripts/Spells/Bushido/HonorableExecution.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Bushido +{ + public class HonorableExecution : SamuraiMove + { + public HonorableExecution() + { + } + + public override int BaseMana{ get{ return 0; } } + public override double RequiredSkill{ get{ return 25.0; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063122 ); } } // You better kill your enemy with your next hit or you'll be rather sorry... + + public override double GetDamageScalar( Mobile attacker, Mobile defender ) + { + double bushido = attacker.Skills[SkillName.Bushido].Value; + + // TODO: 20 -> Perfection + return 1.0 + (bushido * 20) / 10000; + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentMove( attacker ); + + HonorableExecutionInfo info = m_Table[attacker] as HonorableExecutionInfo; + + if ( info != null ) + { + info.Clear(); + + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + } + + if ( !defender.Alive ) + { + attacker.FixedParticles( 0x373A, 1, 17, 0x7E2, EffectLayer.Waist ); + + double bushido = attacker.Skills[SkillName.Bushido].Value; + + attacker.Hits += 20 + (int)((bushido * bushido) / 480.0); + + int swingBonus = Math.Max( 1, (int)((bushido * bushido) / 720.0) ); + + info = new HonorableExecutionInfo( attacker, swingBonus ); + info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 20.0 ), new TimerStateCallback( EndEffect ), info ); + + m_Table[attacker] = info; + } + else + { + ArrayList mods = new ArrayList(); + + mods.Add( new ResistanceMod( ResistanceType.Physical, -40 ) ); + mods.Add( new ResistanceMod( ResistanceType.Fire, -40 ) ); + mods.Add( new ResistanceMod( ResistanceType.Cold, -40 ) ); + mods.Add( new ResistanceMod( ResistanceType.Poison, -40 ) ); + mods.Add( new ResistanceMod( ResistanceType.Energy, -40 ) ); + + double resSpells = attacker.Skills[SkillName.MagicResist].Value; + + if ( resSpells > 0.0 ) + mods.Add( new DefaultSkillMod( SkillName.MagicResist, true, -resSpells ) ); + + info = new HonorableExecutionInfo( attacker, mods ); + info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 7.0 ), new TimerStateCallback( EndEffect ), info ); + + m_Table[attacker] = info; + } + + CheckGain( attacker ); + } + + + private static Hashtable m_Table = new Hashtable(); + + public static int GetSwingBonus( Mobile target ) + { + HonorableExecutionInfo info = m_Table[target] as HonorableExecutionInfo; + + if ( info == null ) + return 0; + + return info.m_SwingBonus; + } + + public static bool IsUnderPenalty( Mobile target ) + { + HonorableExecutionInfo info = m_Table[target] as HonorableExecutionInfo; + + if ( info == null ) + return false; + + return info.m_Penalty; + } + + public static void RemovePenalty( Mobile target ) + { + HonorableExecutionInfo info = m_Table[target] as HonorableExecutionInfo; + + if ( info == null || !info.m_Penalty ) + return; + + info.Clear(); + + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + m_Table.Remove( target ); + } + + private class HonorableExecutionInfo + { + public Mobile m_Mobile; + public int m_SwingBonus; + public ArrayList m_Mods; + public bool m_Penalty; + public Timer m_Timer; + + public HonorableExecutionInfo( Mobile from, int swingBonus ) : this( from, swingBonus, null, false ) + { + } + + public HonorableExecutionInfo( Mobile from, ArrayList mods ) : this( from, 0, mods, true ) + { + } + + public HonorableExecutionInfo( Mobile from, int swingBonus, ArrayList mods, bool penalty ) + { + m_Mobile = from; + m_SwingBonus = swingBonus; + m_Mods = mods; + m_Penalty = penalty; + + Apply(); + } + + public void Apply() + { + if ( m_Mods == null ) + return; + + for ( int i = 0; i < m_Mods.Count; ++i ) + { + object mod = m_Mods[i]; + + if ( mod is ResistanceMod ) + m_Mobile.AddResistanceMod( (ResistanceMod) mod ); + else if ( mod is SkillMod ) + m_Mobile.AddSkillMod( (SkillMod) mod ); + } + } + + public void Clear() + { + if ( m_Mods == null ) + return; + + for ( int i = 0; i < m_Mods.Count; ++i ) + { + object mod = m_Mods[i]; + + if ( mod is ResistanceMod ) + m_Mobile.RemoveResistanceMod( (ResistanceMod) mod ); + else if ( mod is SkillMod ) + m_Mobile.RemoveSkillMod( (SkillMod) mod ); + } + } + } + + public void EndEffect( object state ) + { + HonorableExecutionInfo info = (HonorableExecutionInfo)state; + + RemovePenalty( info.m_Mobile ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Bushido/LightningStrike.cs b/Scripts/Spells/Bushido/LightningStrike.cs new file mode 100644 index 0000000..97640b5 --- /dev/null +++ b/Scripts/Spells/Bushido/LightningStrike.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Bushido +{ + public class LightningStrike : SamuraiMove + { + public LightningStrike() + { + } + + public override int BaseMana{ get{ return 5; } } + public override double RequiredSkill{ get{ return 50.0; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063167 ); } } // You prepare to strike quickly. + + public override bool DelayedContext{ get{ return true; } } + + public override int GetAccuracyBonus( Mobile attacker ) + { + return 50; + } + + public override bool Validate(Mobile from) + { + bool isValid=base.Validate(from); + if (isValid) + { + PlayerMobile ThePlayer = from as PlayerMobile; + ThePlayer.ExecutesLightningStrike = BaseMana; + } + return isValid; + } + + public override bool IgnoreArmor( Mobile attacker ) + { + double bushido = attacker.Skills[SkillName.Bushido].Value; + double criticalChance = (bushido * bushido) / 72000.0; + return ( criticalChance >= Utility.RandomDouble() ); + } + + public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + /* no mana drain before actual hit */ + bool enoughMana = CheckMana(attacker, false); + return Validate(attacker); + } + + public override bool ValidatesDuringHit { get { return false; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + ClearCurrentMove(attacker); + if (CheckMana(attacker, true)) + { + attacker.SendLocalizedMessage(1063168); // You attack with lightning precision! + defender.SendLocalizedMessage(1063169); // Your opponent's quick strike causes extra damage! + defender.FixedParticles(0x3818, 1, 11, 0x13A8, 0, 0, EffectLayer.Waist); + defender.PlaySound(0x51D); + CheckGain(attacker); + SetContext(attacker); + } + } + + public override void OnClearMove( Mobile attacker ) + { + PlayerMobile ThePlayer = attacker as PlayerMobile; // this can be deletet if the PlayerMobile parts are moved to Server.Mobile + ThePlayer.ExecutesLightningStrike = 0; + } + } +} diff --git a/Scripts/Spells/Bushido/MomentumStrike.cs b/Scripts/Spells/Bushido/MomentumStrike.cs new file mode 100644 index 0000000..e6c1084 --- /dev/null +++ b/Scripts/Spells/Bushido/MomentumStrike.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Bushido +{ + public class MomentumStrike : SamuraiMove + { + public MomentumStrike() + { + } + + public override int BaseMana{ get{ return 10; } } + public override double RequiredSkill{ get{ return 70.0; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1070757 ); } } // You prepare to strike two enemies with one blow. + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, false ) ) + return; + + ClearCurrentMove( attacker ); + + BaseWeapon weapon = attacker.Weapon as BaseWeapon; + + List targets = new List(); + + foreach ( Mobile m in attacker.GetMobilesInRange( weapon.MaxRange ) ) + { + if ( m == defender ) + continue; + + if ( m.Combatant != attacker ) + continue; + + targets.Add( m ); + } + + if ( targets.Count > 0 ) + { + if ( !CheckMana( attacker, true ) ) + return; + + Mobile target = targets[Utility.Random( targets.Count )]; + + double damageBonus = attacker.Skills[SkillName.Bushido].Value / 100.0; + + if ( !defender.Alive ) + damageBonus *= 1.5; + + attacker.SendLocalizedMessage( 1063171 ); // You transfer the momentum of your weapon into another enemy! + target.SendLocalizedMessage( 1063172 ); // You were hit by the momentum of a Samurai's weapon! + + target.FixedParticles( 0x37B9, 1, 4, 0x251D, 0, 0, EffectLayer.Waist ); + + attacker.PlaySound( 0x510 ); + + weapon.OnSwing( attacker, target, damageBonus ); + + CheckGain( attacker ); + } + else + { + attacker.SendLocalizedMessage( 1063123 ); // There are no valid targets to attack! + } + } + + public override void CheckGain( Mobile m ) + { + m.CheckSkill( MoveSkill, RequiredSkill, 120.0 ); + } + } +} diff --git a/Scripts/Spells/Bushido/SamuraiMove.cs b/Scripts/Spells/Bushido/SamuraiMove.cs new file mode 100644 index 0000000..e916a6c --- /dev/null +++ b/Scripts/Spells/Bushido/SamuraiMove.cs @@ -0,0 +1,15 @@ +using System; +using Server; + +namespace Server.Spells +{ + public class SamuraiMove : SpecialMove + { + public override SkillName MoveSkill{ get{ return SkillName.Bushido; } } + + public override void CheckGain( Mobile m ) + { + m.CheckSkill( MoveSkill, RequiredSkill - 12.5, RequiredSkill + 37.5 ); //Per five on friday 02/16/07 + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Bushido/SamuraiSpell.cs b/Scripts/Spells/Bushido/SamuraiSpell.cs new file mode 100644 index 0000000..528e126 --- /dev/null +++ b/Scripts/Spells/Bushido/SamuraiSpell.cs @@ -0,0 +1,129 @@ +using System; +using Server; +using Server.Spells; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Bushido +{ + public abstract class SamuraiSpell : Spell + { + public abstract double RequiredSkill{ get; } + public abstract int RequiredMana{ get; } + + public override SkillName CastSkill{ get{ return SkillName.Bushido; } } + public override SkillName DamageSkill{ get{ return SkillName.Bushido; } } + + public override bool ClearHandsOnCast{ get{ return false; } } + public override bool BlocksMovement{ get{ return false; } } + public override bool ShowHandMovement{ get{ return false; } } + + //public override int CastDelayBase{ get{ return 1; } } + public override double CastDelayFastScalar{ get{ return 0; } } + + public override int CastRecoveryBase{ get{ return 7; } } + + public SamuraiSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public static bool CheckExpansion( Mobile from ) + { + if ( !( from is PlayerMobile ) ) + return true; + + if ( from.NetState == null ) + return false; + + return from.NetState.SupportsExpansion( Expansion.SE ); + } + + public override bool CheckCast() + { + int mana = ScaleMana ( RequiredMana ); + + if ( !base.CheckCast() ) + return false; + + if ( !CheckExpansion( Caster ) ) + { + Caster.SendLocalizedMessage( 1063456 ); // You must upgrade to Samurai Empire in order to use that ability. + return false; + } + + if ( Caster.Skills[CastSkill].Value < RequiredSkill ) + { + string args = String.Format( "{0}\t{1}\t ", RequiredSkill.ToString( "F1" ), CastSkill.ToString() ); + Caster.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + else if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + return true; + } + + public override bool CheckFizzle() + { + int mana = ScaleMana( RequiredMana ); + + if ( Caster.Skills[CastSkill].Value < RequiredSkill ) + { + Caster.SendLocalizedMessage( 1070768, RequiredSkill.ToString( "F1" ) ); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack! + return false; + } + else if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + if ( !base.CheckFizzle() ) + return false; + + Caster.Mana -= mana; + + return true; + } + + public override void GetCastSkills( out double min, out double max ) + { + min = RequiredSkill - 12.5; //per 5 on friday, 2/16/07 + max = RequiredSkill + 37.5; + } + + public override int GetMana() + { + return 0; + } + + public virtual void OnCastSuccessful( Mobile caster ) + { + if ( Evasion.IsEvading( caster ) ) + Evasion.EndEvasion( caster ); + + if ( Confidence.IsConfident( caster ) ) + Confidence.EndConfidence( caster ); + + if ( CounterAttack.IsCountering( caster ) ) + CounterAttack.StopCountering( caster ); + + int spellID = SpellRegistry.GetRegistryNumber( this ); + + if ( spellID > 0 ) + caster.Send( new ToggleSpecialAbility( spellID + 1, true ) ); + } + + public static void OnEffectEnd( Mobile caster, Type type ) + { + int spellID = SpellRegistry.GetRegistryNumber( type ); + + if ( spellID > 0 ) + caster.Send( new ToggleSpecialAbility( spellID + 1, false ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/CleanseByFire.cs b/Scripts/Spells/Chivalry/CleanseByFire.cs new file mode 100644 index 0000000..57c2a6f --- /dev/null +++ b/Scripts/Spells/Chivalry/CleanseByFire.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class CleanseByFireSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Cleanse By Fire", "Expor Flamus", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override double RequiredSkill{ get{ return 5.0; } } + public override int RequiredMana{ get{ return 10; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060718; } } // Expor Flamus + public override string ArtedarMantra{ get{ return "Ego Regor";} } + + public CleanseByFireSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !m.Poisoned ) + { + Caster.SendLocalizedMessage( 1060176 ); // That creature is not poisoned! + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Cures the target of poisons, but causes the caster to be burned by fire damage for 13-55 hit points. + * The amount of fire damage is lessened if the caster has high Karma. + */ + + Poison p = m.Poison; + + if ( p != null ) + { + // Cleanse by fire is now difficulty based + int chanceToCure = 10000 + (int)(Caster.Skills[SkillName.Chivalry].Value * 75) - ((p.Level + 1) * 2000); + chanceToCure /= 100; + + if ( chanceToCure > Utility.Random( 100 ) ) + { + if ( m.CurePoison( Caster ) ) + { + if ( Caster != m ) + Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons! + + m.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons. + } + } + else + { + m.SendLocalizedMessage( 1010060 ); // You have failed to cure your target! + } + } + + m.PlaySound( 0x1E0 ); + m.FixedParticles( 0x373A, 1, 15, 5012, 3, 2, EffectLayer.Waist ); + + IEntity from = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z - 5 ), m.Map ); + IEntity to = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z + 45 ), m.Map ); + Effects.SendMovingParticles( from, to, 0x374B, 1, 0, false, false, 63, 2, 9501, 1, 0, EffectLayer.Head, 0x100 ); + + Caster.PlaySound( 0x208 ); + Caster.FixedParticles(0x3709, 1, 30, 9934, (( Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) ? 27 : 0 ), 7, EffectLayer.Waist); //vinds : switch cosmetique suivant le dieu + + int damage = 50 - ComputePowerValue( 4 ); + + // TODO: Should caps be applied? + if ( damage < 13 ) + damage = 13; + else if ( damage > 55 ) + damage = 55; + + AOS.Damage( Caster, Caster, damage, 0, 100, 0, 0, 0, true ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private CleanseByFireSpell m_Owner; + + public InternalTarget( CleanseByFireSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/CloseWounds.cs b/Scripts/Spells/Chivalry/CloseWounds.cs new file mode 100644 index 0000000..f393daf --- /dev/null +++ b/Scripts/Spells/Chivalry/CloseWounds.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Chivalry +{ + public class CloseWoundsSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Close Wounds", "Obsu Vulni", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 0.0; } } + public override int RequiredMana{ get{ return 10; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060719; } } // Obsu Vulni + public override string ArtedarMantra { get { return "Ichor Natalis"; } } + + public CloseWoundsSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.InRange( m, 2 ) ) + { + Caster.SendLocalizedMessage( 1060178 ); // You are too far away to perform that action! + } + else if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead ) + { + Caster.SendLocalizedMessage( 1061654 ); // You cannot heal that which is not alive. + } + else if ( m.IsDeadBondedPet ) + { + Caster.SendLocalizedMessage( 1060177 ); // You cannot heal a creature that is already dead! + } + else if ( m.Hits >= m.HitsMax ) + { + Caster.SendLocalizedMessage( 500955 ); // That being is not damaged! + } + else if ( m.Poisoned || Server.Items.MortalStrike.IsWounded( m ) ) + { + Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, (Caster == m) ? 1005000 : 1010398 ); + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Heals the target for 7 to 39 points of damage. + * The caster's Karma affects the amount of damage healed. + */ + + int toHeal = ComputePowerValue( 6 ) + Utility.RandomMinMax( 0, 2 ); + + // TODO: Should caps be applied? + if ( toHeal < 7 ) + toHeal = 7; + else if ( toHeal > 39 ) + toHeal = 39; + + if ( (m.Hits + toHeal) > m.HitsMax ) + toHeal = m.HitsMax - m.Hits; + + //m.Hits += toHeal; //Was previosuly due to the message + //m.Heal( toHeal, Caster, false ); + SpellHelper.Heal( toHeal, m, Caster, false ); + + m.SendLocalizedMessage( 1060203, toHeal.ToString() ); // You have had ~1_HEALED_AMOUNT~ hit points of damage healed. + + + + if (m is PlayerMobile && ((PlayerMobile)m).IsArtedarKnight) //Vinds : switch cosm�tique suivant le dieu + { + + m.PlaySound(0x202); + m.FixedParticles(0x376A, 1, 62, 9923, 32, 3, EffectLayer.Waist); + m.FixedParticles(0x3779, 1, 46, 9502, 27, 3, EffectLayer.Waist); + } + + else + { + m.PlaySound(0x202); + m.FixedParticles(0x376A, 1, 62, 9923, 3, 3, EffectLayer.Waist); + m.FixedParticles(0x3779, 1, 46, 9502, 5, 3, EffectLayer.Waist); + } + + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private CloseWoundsSpell m_Owner; + + public InternalTarget( CloseWoundsSpell owner ) : base( 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/ConsecrateWeapon.cs b/Scripts/Spells/Chivalry/ConsecrateWeapon.cs new file mode 100644 index 0000000..eaac302 --- /dev/null +++ b/Scripts/Spells/Chivalry/ConsecrateWeapon.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class ConsecrateWeaponSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Consecrate Weapon", "Consecrus Arma", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.5 ); } } + + public override double RequiredSkill{ get{ return 15.0; } } + public override int RequiredMana{ get{ return 10; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060720; } } // Consecrus Arma + public override string ArtedarMantra { get { return "Languor Vindicare"; } } + public override bool BlocksMovement{ get{ return false; } } + + public ConsecrateWeaponSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + BaseWeapon weapon = Caster.Weapon as BaseWeapon; + + if ( weapon == null || weapon is Fists ) + { + Caster.SendLocalizedMessage( 501078 ); // You must be holding a weapon. + } + else if ( CheckSequence() ) + { + /* Temporarily enchants the weapon the caster is currently wielding. + * The type of damage the weapon inflicts when hitting a target will + * be converted to the target's worst Resistance type. + * Duration of the effect is affected by the caster's Karma and lasts for 3 to 11 seconds. + */ + + int itemID, soundID; + + switch ( weapon.Skill ) + { + case SkillName.Macing: itemID = 0xFB4; soundID = 0x232; break; + case SkillName.Archery: itemID = 0x13B1; soundID = 0x145; break; + default: itemID = 0xF5F; soundID = 0x56; break; + } + + Caster.PlaySound( 0x20C ); + Caster.PlaySound( soundID ); + Caster.FixedParticles( 0x3779, 1, 30, 9964,(Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) ? 37 : 3, 3, EffectLayer.Waist ); + + IEntity from = new Entity( Serial.Zero, new Point3D( Caster.X, Caster.Y, Caster.Z ), Caster.Map ); + IEntity to = new Entity( Serial.Zero, new Point3D( Caster.X, Caster.Y, Caster.Z + 50 ), Caster.Map ); + Effects.SendMovingParticles( from, to, itemID, 1, 0, false, false, 33, 3, 9501, 1, 0, EffectLayer.Head, 0x100 ); + + double seconds = ComputePowerValue( 20 ); + + // TODO: Should caps be applied? + if ( seconds < 3.0 ) + seconds = 3.0; + else if ( seconds > 11.0 ) + seconds = 11.0; + + TimeSpan duration = TimeSpan.FromSeconds( seconds ); + + Timer t = (Timer)m_Table[weapon]; + + if ( t != null ) + t.Stop(); + + weapon.Consecrated = true; + + m_Table[weapon] = t = new ExpireTimer( weapon, duration ); + + t.Start(); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private BaseWeapon m_Weapon; + + public ExpireTimer( BaseWeapon weapon, TimeSpan delay ) : base( delay ) + { + m_Weapon = weapon; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Weapon.Consecrated = false; + Effects.PlaySound( m_Weapon.GetWorldLocation(), m_Weapon.Map, 0x1F8 ); + m_Table.Remove( this ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/DispelEvil.cs b/Scripts/Spells/Chivalry/DispelEvil.cs new file mode 100644 index 0000000..0656c63 --- /dev/null +++ b/Scripts/Spells/Chivalry/DispelEvil.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; +using Server.Spells.Necromancy; + +namespace Server.Spells.Chivalry +{ + public class DispelEvilSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Dispel Evil", "Dispiro Malas", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.25 ); } } + + public override double RequiredSkill{ get{ return 35.0; } } + public override int RequiredMana{ get{ return 10; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060721; } } // Dispiro Malas + public override string ArtedarMantra { get { return "Dys Iden Xiah"; } } + public override bool BlocksMovement{ get{ return false; } } + + public DispelEvilSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool DelayedDamage{ get{ return false; } } + + public override void SendCastEffect() + { + Caster.FixedEffect(0x37C4, 10, 7, (Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) ? 37 : 4, 3); // At player + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + List targets = new List(); + + foreach ( Mobile m in Caster.GetMobilesInRange( 8 ) ) + { + if ( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) ) + targets.Add( m ); + } + + Caster.PlaySound( 0xF5 ); + Caster.PlaySound( 0x299 ); + Caster.FixedParticles( 0x37C4, 1, 25, 9922, 14, 3, EffectLayer.Head ); + + int dispelSkill = ComputePowerValue( 2 ); + + double chiv = Caster.Skills.Chivalry.Value; + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + BaseCreature bc = m as BaseCreature; + + if ( bc != null ) + { + bool dispellable = bc.Summoned && !bc.IsAnimatedDead; + + if ( dispellable ) + { + double dispelChance = (50.0 + ((100 * (chiv - bc.DispelDifficulty)) / (bc.DispelFocus*2))) / 100; + dispelChance *= dispelSkill / 100.0; + + if ( dispelChance > Utility.RandomDouble() ) + { + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 ); + Effects.PlaySound( m, m.Map, 0x201 ); + + m.Delete(); + continue; + } + } + + bool evil = !bc.Controlled && bc.Karma < 0; + + if ( evil ) + { + // TODO: Is this right? + double fleeChance = (100 - Math.Sqrt( m.Fame / 2 )) * chiv * dispelSkill; + fleeChance /= 1000000; + + if ( fleeChance > Utility.RandomDouble() ) + { + // guide says 2 seconds, it's longer + bc.BeginFlee( TimeSpan.FromSeconds( 30.0 ) ); + } + } + } + + TransformContext context = TransformationSpellHelper.GetContext( m ); + if( context != null && context.Spell is NecromancerSpell ) //Trees are not evil! TODO: OSI confirm? + { + // transformed .. + + double drainChance = 0.5 * (Caster.Skills.Chivalry.Value / Math.Max( m.Skills.Necromancy.Value, 1 )); + + if ( drainChance > Utility.RandomDouble() ) + { + int drain = (5 * dispelSkill) / 100; + + m.Stam -= drain; + m.Mana -= drain; + } + } + } + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/DivineFury.cs b/Scripts/Spells/Chivalry/DivineFury.cs new file mode 100644 index 0000000..16371b0 --- /dev/null +++ b/Scripts/Spells/Chivalry/DivineFury.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class DivineFurySpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Divine Fury", "Divinum Furis", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override double RequiredSkill{ get{ return 25.0; } } + public override int RequiredMana{ get{ return 15; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060722; } } // Divinum Furis + public override string ArtedarMantra { get { return "Ventus Irae"; } } + public override bool BlocksMovement{ get{ return false; } } + + public DivineFurySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + Caster.PlaySound( 0x20F ); + + Caster.PlaySound( Caster.Female ? 0x338 : 0x44A ); + Caster.FixedParticles( 0x376A, 1, 31, 9961, (Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) ? 37 :1160, 0, EffectLayer.Waist ); // Vinds : encore du cosm�tique + Caster.FixedParticles( 0x37C4, 1, 31, 9502,(Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) ? 27 : 43, 2, EffectLayer.Waist ); + + Caster.Stam = Caster.StamMax; + + Timer t = (Timer)m_Table[Caster]; + + if ( t != null ) + t.Stop(); + + int delay = ComputePowerValue( 10 ); + + // TODO: Should caps be applied? + if ( delay < 7 ) + delay = 7; + else if ( delay > 24 ) + delay = 24; + + m_Table[Caster] = t = Timer.DelayCall( TimeSpan.FromSeconds( delay ), new TimerStateCallback( Expire_Callback ), Caster ); + Caster.Delta( MobileDelta.WeaponDamage ); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.DivineFury, 1060589, 1075634, TimeSpan.FromSeconds(delay), Caster)); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool UnderEffect( Mobile m ) + { + return m_Table.Contains( m ); + } + + private static void Expire_Callback( object state ) + { + Mobile m = (Mobile)state; + + m_Table.Remove( m ); + + m.Delta( MobileDelta.WeaponDamage ); + m.PlaySound( 0xF8 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/EnemyOfOne.cs b/Scripts/Spells/Chivalry/EnemyOfOne.cs new file mode 100644 index 0000000..0694f8e --- /dev/null +++ b/Scripts/Spells/Chivalry/EnemyOfOne.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Chivalry +{ + public class EnemyOfOneSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Enemy of One", "Forul Solum", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.5 ); } } + + public override double RequiredSkill{ get{ return 45.0; } } + public override int RequiredMana{ get{ return 20; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060723; } } // Forul Solum + public override string ArtedarMantra { get { return "Hostium Necatur"; } } + public override bool BlocksMovement{ get{ return false; } } + + public EnemyOfOneSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + Caster.PlaySound( 0x0F5 ); + Caster.PlaySound( 0x1ED ); + Caster.FixedParticles( 0x375A, 1, 30, 9966, 33, 2, EffectLayer.Head ); + Caster.FixedParticles( 0x37B9, 1, 30, 9502, 43, 3, EffectLayer.Head ); + + Timer t = (Timer)m_Table[Caster]; + + if ( t != null ) + t.Stop(); + + double delay = (double)ComputePowerValue( 1 ) / 60; + + // TODO: Should caps be applied? + if ( delay < 1.5 ) + delay = 1.5; + else if ( delay > 3.5 ) + delay = 3.5; + + m_Table[Caster] = Timer.DelayCall( TimeSpan.FromMinutes( delay ), new TimerStateCallback( Expire_Callback ), Caster ); + + if ( Caster is PlayerMobile ) + { + ((PlayerMobile)Caster).EnemyOfOneType = null; + ((PlayerMobile)Caster).WaitingForEnemy = true; + + BuffInfo.AddBuff ( Caster, new BuffInfo ( BuffIcon.EnemyOfOne, 1075653, 1044111, TimeSpan.FromMinutes ( delay ), Caster ) ); + } + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + private static void Expire_Callback( object state ) + { + Mobile m = (Mobile)state; + + m_Table.Remove( m ); + + m.PlaySound( 0x1F8 ); + + if ( m is PlayerMobile ) + { + ((PlayerMobile)m).EnemyOfOneType = null; + ((PlayerMobile)m).WaitingForEnemy = false; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/HolyLight.cs b/Scripts/Spells/Chivalry/HolyLight.cs new file mode 100644 index 0000000..8eea6db --- /dev/null +++ b/Scripts/Spells/Chivalry/HolyLight.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class HolyLightSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Holy Light", "Augus Luminos", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.75 ); } } + + public override double RequiredSkill{ get{ return 55.0; } } + public override int RequiredMana{ get{ return 10; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060724; } } // Augus Luminos + public override string ArtedarMantra { get { return "Ipsos Hemen"; } } + public override bool BlocksMovement{ get{ return false; } } + + public HolyLightSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool DelayedDamage{ get{ return false; } } + + public override void OnCast() + { + if ( CheckSequence() ) + { + List targets = new List(); + + foreach ( Mobile m in Caster.GetMobilesInRange( 3 ) ) + if (Caster != m && SpellHelper.ValidIndirectTarget(Caster, m) && Caster.CanBeHarmful(m, false) && (!Core.AOS || Caster.InLOS(m))) + targets.Add(m); + + Caster.PlaySound( 0x212 ); + Caster.PlaySound( 0x206 ); + + if (Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight)// Vinds : switch cosm�tique + { + Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0x376A, 1, 29, 0x20, 2, 9962, 0); + Effects.SendLocationParticles(EffectItem.Create(new Point3D(Caster.X, Caster.Y, Caster.Z - 7), Caster.Map, EffectItem.DefaultDuration), 0x37C4, 1, 29, 0x1B, 2, 9502, 0); + } + + else + + { + + Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0x376A, 1, 29, 0x47D, 2, 9962, 0); + Effects.SendLocationParticles(EffectItem.Create(new Point3D(Caster.X, Caster.Y, Caster.Z - 7), Caster.Map, EffectItem.DefaultDuration), 0x37C4, 1, 29, 0x47D, 2, 9502, 0); + + } + + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + int damage = ComputePowerValue( 10 ) + Utility.RandomMinMax( 0, 2 ); + + // TODO: Should caps be applied? + if ( damage < 8 ) + damage = 8; + else if ( damage > 24 ) + damage = 24; + + Caster.DoHarmful( m ); + SpellHelper.Damage( this, m, damage, 0, 0, 0, 0, 100 ); + } + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/NobleSacrifice.cs b/Scripts/Spells/Chivalry/NobleSacrifice.cs new file mode 100644 index 0000000..1f78a26 --- /dev/null +++ b/Scripts/Spells/Chivalry/NobleSacrifice.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Gumps; +using Server.Spells.Necromancy; +using Server.Regions; + +namespace Server.Spells.Chivalry +{ + public class NobleSacrificeSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Noble Sacrifice", "Dium Prostra", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 65.0; } } + public override int RequiredMana{ get{ return 20; } } + public override int RequiredTithing{ get{ return 30; } } + public override int MantraNumber{ get{ return 1060725; } } // Dium Prostra + public override string ArtedarMantra { get { return "Via Dolorosa"; } } + public override bool BlocksMovement{ get{ return false; } } + + public NobleSacrificeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + List targets = new List(); + + foreach ( Mobile m in Caster.GetMobilesInRange( 3 ) ) // TODO: Validate range + { + if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead ) + continue; + + if ( Caster != m && m.InLOS( Caster ) && Caster.CanBeBeneficial( m, false, true ) && !(m is Golem) ) + targets.Add( m ); + } + + Caster.PlaySound( 0x244 ); + Caster.FixedParticles( 0x3709, 1, 30, 9965, 5, 7, EffectLayer.Waist ); + Caster.FixedParticles( 0x376A, 1, 30, 9502, 5, 3, EffectLayer.Waist ); + + /* Attempts to Resurrect, Cure and Heal all targets in a radius around the caster. + * If any target is successfully assisted, the Paladin's current + * Hit Points, Mana and Stamina are set to 1. + * Amount of damage healed is affected by the Caster's Karma, from 8 to 24 hit points. + */ + + bool sacrifice = false; + + // TODO: Is there really a resurrection chance? + + double resChance = 0.1 + (0.9 * ((double)Caster.Karma / 10000)); + + if ((Caster is PlayerMobile) && ((PlayerMobile)Caster).IsArtedarKnight) + resChance = 0.1 + (0.9 * ((double)Caster.Fame / 7500)); + + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + if ( !m.Alive ) + { + if ( m.Region != null && m.Region.IsPartOf( "Khaldun" ) ) + { + Caster.SendLocalizedMessage( 1010395 ); // The veil of death in this area is too strong and resists thy efforts to restore life. + } + else if( resChance > Utility.RandomDouble() ) + { + m.FixedParticles( 0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head ); + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, Caster ) ); + sacrifice = true; + } + } + else + { + bool sendEffect = false; + + if ( m.Poisoned && m.CurePoison( Caster ) ) + { + Caster.DoBeneficial( m ); + + if ( Caster != m ) + Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons! + + m.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons. + sendEffect = true; + sacrifice = true; + } + + if ( m.Hits < m.HitsMax ) + { + int toHeal = ComputePowerValue( 10 ) + Utility.RandomMinMax( 0, 2 ); + + // TODO: Should caps be applied? + if ( toHeal < 8 ) + toHeal = 8; + else if ( toHeal > 24 ) + toHeal = 24; + + Caster.DoBeneficial( m ); + m.Heal( toHeal, Caster ); + sendEffect = true; + } + + StatMod mod; + + mod = m.GetStatMod( "[Magic] Str Offset" ); + if ( mod != null && mod.Offset < 0 ) + { + m.RemoveStatMod( "[Magic] Str Offset" ); + sendEffect = true; + } + + mod = m.GetStatMod( "[Magic] Dex Offset" ); + if ( mod != null && mod.Offset < 0 ) + { + m.RemoveStatMod( "[Magic] Dex Offset" ); + sendEffect = true; + } + + mod = m.GetStatMod( "[Magic] Int Offset" ); + if ( mod != null && mod.Offset < 0 ) + { + m.RemoveStatMod( "[Magic] Int Offset" ); + sendEffect = true; + } + + if ( m.Paralyzed ) + { + m.Paralyzed = false; + sendEffect = true; + } + + if ( EvilOmenSpell.TryEndEffect( m ) ) + sendEffect = true; + + if ( StrangleSpell.RemoveCurse( m ) ) + sendEffect = true; + + if ( CorpseSkinSpell.RemoveCurse( m ) ) + sendEffect = true; + + // TODO: Should this remove blood oath? Pain spike? + + if ( sendEffect ) + { + m.FixedParticles( 0x375A, 1, 15, 5005, 5, 3, EffectLayer.Head ); + sacrifice = true; + } + } + } + + if ( sacrifice ) + { + Caster.PlaySound( Caster.Body.IsFemale ? 0x150 : 0x423 ); + Caster.Hits = 1; + Caster.Stam = 1; + Caster.Mana = 1; + } + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/PaladinSpell.cs b/Scripts/Spells/Chivalry/PaladinSpell.cs new file mode 100644 index 0000000..f416bea --- /dev/null +++ b/Scripts/Spells/Chivalry/PaladinSpell.cs @@ -0,0 +1,167 @@ +using System; +using Server; +using Server.Spells; +using Server.Network; +using Server.Mobiles; +using System.Collections; + +namespace Server.Spells.Chivalry +{ + public abstract class PaladinSpell : Spell + { + public abstract double RequiredSkill{ get; } + public abstract int RequiredMana{ get; } + public abstract int RequiredTithing{ get; } + public abstract int MantraNumber{ get; } + public abstract string ArtedarMantra { get; } + + public override SkillName CastSkill{ get{ return SkillName.Chivalry; } } + public override SkillName DamageSkill{ get{ return SkillName.Chivalry; } } + + public override bool ClearHandsOnCast{ get{ return false; } } + + //public override int CastDelayBase{ get{ return 1; } } + + public override int CastRecoveryBase{ get{ return 7; } } + + + public PaladinSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public override bool CheckCast() + { + int mana = ScaleMana( RequiredMana ); + + if ( !base.CheckCast() ) + return false; + + if (Caster.TithingPoints < RequiredTithing) + { + Caster.SendLocalizedMessage( 1060173, RequiredTithing.ToString() ); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, + return false; + } + else if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + return true; + } + + public override bool CheckFizzle() + { + int requiredTithing = this.RequiredTithing; + + if ( AosAttributes.GetValue( Caster, AosAttribute.LowerRegCost ) > Utility.Random( 100 ) ) + requiredTithing = 0; + + int mana = ScaleMana( RequiredMana ); + + if (Caster.TithingPoints < requiredTithing) + { + Caster.SendLocalizedMessage( 1060173, RequiredTithing.ToString() ); // You must have at least ~1_TITHE_REQUIREMENT~ Tithing Points to use this ability, + return false; + } + else if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + Caster.TithingPoints -= requiredTithing; + + if ( !base.CheckFizzle() ) + return false; + + Caster.Mana -= mana; + + return true; + } + + public override void SayMantra() + { + + if ( Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) //Vinds : power words diff�rents pour artedar + Caster.Say(ArtedarMantra); + + else + { + Caster.PublicOverheadMessage( MessageType.Regular, 0x3B2, MantraNumber, "", false ); + } + } + + public override void DoFizzle() + { + Caster.PlaySound( 0x1D6 ); + Caster.NextSpellTime = DateTime.Now; + } + + public override void DoHurtFizzle() + { + Caster.PlaySound( 0x1D6 ); + } + + public override void OnDisturb( DisturbType type, bool message ) + { + base.OnDisturb( type, message ); + + if ( message ) + Caster.PlaySound( 0x1D6 ); + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + SendCastEffect(); + } + + public virtual void SendCastEffect() + { + + Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), (Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight) ? 27 : 4, 3); // vinds : switch cosm�tique suivant le dieu + //Caster.FixedEffect(0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 4, 3); + } + + public override void GetCastSkills( out double min, out double max ) + { + min = RequiredSkill; + max = RequiredSkill + 50.0; + } + + public override int GetMana() + { + return 0; + } + + public int ComputePowerValue( int div ) + { + return ComputePowerValue( Caster, div ); + } + + public static int ComputePowerValue( Mobile from, int div ) + { + if ( from == null ) + return 0; + + if (from is PlayerMobile && ((PlayerMobile)from).IsArtedarKnight) // vinds : la fame est plus importante pour artedar que le karma bon ou mauvais + { + int v = (int)Math.Sqrt(1.75 * (from.Fame) + 20000 + (from.Skills.Chivalry.Fixed * 10)); + if (v > 204) // m�me power cap que pour la chivalry classique + v=204; + return v / div; + + } + + else + { + int v = (int)Math.Sqrt(from.Karma + 20000 + (from.Skills.Chivalry.Fixed * 10)); + return v / div; + } + + + } + } +} diff --git a/Scripts/Spells/Chivalry/RemoveCurse.cs b/Scripts/Spells/Chivalry/RemoveCurse.cs new file mode 100644 index 0000000..d89d6db --- /dev/null +++ b/Scripts/Spells/Chivalry/RemoveCurse.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Spells.Necromancy; +using Server.Spells.Fourth; +using Server.Mobiles; + +namespace Server.Spells.Chivalry +{ + public class RemoveCurseSpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Remove Curse", "Extermo Vomica", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 5.0; } } + public override int RequiredMana{ get{ return 20; } } + public override int RequiredTithing{ get{ return 10; } } + public override int MantraNumber{ get{ return 1060726; } } // Extermo Vomica + public override string ArtedarMantra { get { return "Sanctum Damnare"; } } + + public RemoveCurseSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Attempts to remove all Curse effects from Target. + * Curses include Mage spells such as Clumsy, Weaken, Feeblemind and Paralyze + * as well as all Necromancer curses. + * Chance of removing curse is affected by Caster's Karma. + */ + + int chance = 0; + if (! ( Caster is PlayerMobile && ((PlayerMobile)Caster).IsArtedarKnight)) + { + if ( Caster.Karma < -5000 ) + chance = 0; + else if ( Caster.Karma < 0 ) + chance = (int) Math.Sqrt( 20000 + Caster.Karma ) - 122; + else if ( Caster.Karma < 5625 ) + chance = (int) Math.Sqrt( Caster.Karma ) + 25; + else + chance = 100; + } + + else + { + + if ( Caster.Fame < 1000 ) + chance = 0; + else if ( Caster.Fame < 2000 ) + chance = (int) Math.Sqrt( 20000 + ( 1.75* Caster.Fame) ) - 122; + else if ( Caster.Fame < 5000 ) + chance = (int) Math.Sqrt( Caster.Fame ) + 25; + else + chance = 100; + } + + + if ( chance > Utility.Random( 100 ) ) + { + m.PlaySound( 0xF6 ); + m.PlaySound( 0x1F7 ); + m.FixedParticles( 0x3709, 1, 30, 9963, 13, 3, EffectLayer.Head ); + + IEntity from = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z - 10 ), Caster.Map ); + IEntity to = new Entity( Serial.Zero, new Point3D( m.X, m.Y, m.Z + 50 ), Caster.Map ); + Effects.SendMovingParticles( from, to, 0x2255, 1, 0, false, false, 13, 3, 9501, 1, 0, EffectLayer.Head, 0x100 ); + + StatMod mod; + + mod = m.GetStatMod( "[Magic] Str Offset" ); + if ( mod != null && mod.Offset < 0 ) + m.RemoveStatMod( "[Magic] Str Offset" ); + + mod = m.GetStatMod( "[Magic] Dex Offset" ); + if ( mod != null && mod.Offset < 0 ) + m.RemoveStatMod( "[Magic] Dex Offset" ); + + mod = m.GetStatMod( "[Magic] Int Offset" ); + if ( mod != null && mod.Offset < 0 ) + m.RemoveStatMod( "[Magic] Int Offset" ); + + m.Paralyzed = false; + + EvilOmenSpell.TryEndEffect( m ); + StrangleSpell.RemoveCurse( m ); + CorpseSkinSpell.RemoveCurse( m ); + CurseSpell.RemoveEffect( m ); + MortalStrike.EndWound( m ); + if (Core.ML) { BloodOathSpell.RemoveCurse ( m ); } + MindRotSpell.ClearMindRotScalar ( m ); + + BuffInfo.RemoveBuff( m, BuffIcon.Clumsy ); + BuffInfo.RemoveBuff( m, BuffIcon.FeebleMind ); + BuffInfo.RemoveBuff( m, BuffIcon.Weaken ); + BuffInfo.RemoveBuff ( m, BuffIcon.Curse ); + BuffInfo.RemoveBuff( m, BuffIcon.MassCurse ); + BuffInfo.RemoveBuff( m, BuffIcon.MortalStrike ); + BuffInfo.RemoveBuff ( m, BuffIcon.Mindrot ); + + // TODO: Should this remove blood oath? Pain spike? + } + else + { + m.PlaySound( 0x1DF ); + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private RemoveCurseSpell m_Owner; + + public InternalTarget( RemoveCurseSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Chivalry/SacredJourney.cs b/Scripts/Spells/Chivalry/SacredJourney.cs new file mode 100644 index 0000000..c0660dc --- /dev/null +++ b/Scripts/Spells/Chivalry/SacredJourney.cs @@ -0,0 +1,203 @@ +using System; +using Server; +using Server.Items; +using Server.Multis; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Chivalry +{ + public class SacredJourneySpell : PaladinSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Sacred Journey", "Sanctum Viatas", + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 15.0; } } + public override int RequiredMana{ get{ return 10; } } + public override int RequiredTithing{ get{ return 15; } } + public override int MantraNumber{ get{ return 1060727; } } // Sanctum Viatas + public override string ArtedarMantra { get { return "Quo Vadis"; } } + public override bool BlocksMovement{ get{ return false; } } + + private RunebookEntry m_Entry; + private Runebook m_Book; + + public SacredJourneySpell( Mobile caster, Item scroll ) : this( caster, scroll, null, null ) + { + } + + public SacredJourneySpell( Mobile caster, Item scroll, RunebookEntry entry, Runebook book ) : base( caster, scroll, m_Info ) + { + m_Entry = entry; + m_Book = book; + } + + public override void OnCast() + { + if ( m_Entry == null ) + Caster.Target = new InternalTarget( this ); + else + Effect( m_Entry.Location, m_Entry.Map, true ); + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return false; + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1061282 ); // You cannot use the Sacred Journey ability to flee from combat. + return false; + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ); + } + + public void Effect( Point3D loc, Map map, bool checkMulti ) + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( map == null || (!Core.AOS && Caster.Map != map) ) + { + Caster.SendLocalizedMessage( 1005569 ); // You can not recall to another facet. + } + else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ) ) + { + } + else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.RecallTo ) ) + { + } + else if ( map == Map.Felucca && Caster is PlayerMobile && ((PlayerMobile)Caster).Young ) + { + Caster.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young. + } + else if ( Caster.Kills >= 5 && map != Map.Felucca ) + { + Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1061282 ); // You cannot use the Sacred Journey ability to flee from combat. + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + } + else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( m_Book != null && m_Book.CurCharges <= 0 ) + { + Caster.SendLocalizedMessage( 502412 ); // There are no charges left on that item. + } + else if ( CheckSequence() ) + { + BaseCreature.TeleportPets( Caster, loc, map, true ); + + if ( m_Book != null ) + --m_Book.CurCharges; + + Effects.SendLocationParticles( EffectItem.Create( Caster.Location, Caster.Map, EffectItem.DefaultDuration ), 0, 0, 0, 5033 ); + + Caster.PlaySound( 0x1FC ); + Caster.MoveToWorld( loc, map ); + Caster.PlaySound( 0x1FC ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private SacredJourneySpell m_Owner; + + public InternalTarget( SacredJourneySpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is RecallRune ) + { + RecallRune rune = (RecallRune)o; + + if ( rune.Marked ) + m_Owner.Effect( rune.Target, rune.TargetMap, true ); + else + from.SendLocalizedMessage( 501805 ); // That rune is not yet marked. + } + else if ( o is Runebook ) + { + RunebookEntry e = ((Runebook)o).Default; + + if ( e != null ) + m_Owner.Effect( e.Location, e.Map, true ); + else + from.SendLocalizedMessage( 502354 ); // Target is not marked. + } + else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat ) + { + BaseBoat boat = ((Key)o).Link as BaseBoat; + + if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) ) + m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false ); + else + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object. + } + else if (o is HouseRaffleDeed && ((HouseRaffleDeed)o).ValidLocation()) + { + HouseRaffleDeed deed = (HouseRaffleDeed)o; + + m_Owner.Effect(deed.PlotLocation, deed.PlotFacet, true); + } + else + { + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object. + } + } + + protected override void OnNonlocalTarget( Mobile from, object o ) + { + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/AirElemental.cs b/Scripts/Spells/Eighth/AirElemental.cs new file mode 100644 index 0000000..af5b6cc --- /dev/null +++ b/Scripts/Spells/Eighth/AirElemental.cs @@ -0,0 +1,55 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class AirElementalSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Air Elemental", "Kal Vas Xen Hur", + 269, + 9010, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public AirElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 2) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); + + if ( Core.AOS ) + SpellHelper.Summon( new SummonedAirElemental(), Caster, 0x217, duration, false, false ); + else + SpellHelper.Summon( new AirElemental(), Caster, 0x217, duration, false, false ); + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/EarthElemental.cs b/Scripts/Spells/Eighth/EarthElemental.cs new file mode 100644 index 0000000..31d3cc1 --- /dev/null +++ b/Scripts/Spells/Eighth/EarthElemental.cs @@ -0,0 +1,55 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class EarthElementalSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Earth Elemental", "Kal Vas Xen Ylem", + 269, + 9020, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public EarthElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 2) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); + + if ( Core.AOS ) + SpellHelper.Summon( new SummonedEarthElemental(), Caster, 0x217, duration, false, false ); + else + SpellHelper.Summon( new EarthElemental(), Caster, 0x217, duration, false, false ); + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/Earthquake.cs b/Scripts/Spells/Eighth/Earthquake.cs new file mode 100644 index 0000000..3eb781f --- /dev/null +++ b/Scripts/Spells/Eighth/Earthquake.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class EarthquakeSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Earthquake", "In Vas Por", + 233, + 9012, + false, + Reagent.Bloodmoss, + Reagent.Ginseng, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public EarthquakeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool DelayedDamage{ get{ return !Core.AOS; } } + + public override void OnCast() + { + if ( SpellHelper.CheckTown( Caster, Caster ) && CheckSequence() ) + { + List targets = new List(); + + Map map = Caster.Map; + + if ( map != null ) + foreach ( Mobile m in Caster.GetMobilesInRange( 1 + (int)(Caster.Skills[SkillName.Magery].Value / 15.0) ) ) + if ( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) && (!Core.AOS || Caster.InLOS( m )) ) + targets.Add( m ); + + Caster.PlaySound( 0x220 ); + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + int damage; + + if ( Core.AOS ) + { + damage = m.Hits / 2; + + if ( !m.Player ) + damage = Math.Max( Math.Min( damage, 100 ), 15 ); + damage += Utility.RandomMinMax( 0, 15 ); + + } + else + { + damage = (m.Hits * 6) / 10; + + if ( !m.Player && damage < 10 ) + damage = 10; + else if ( damage > 75 ) + damage = 75; + } + + Caster.DoHarmful( m ); + SpellHelper.Damage( TimeSpan.Zero, m, Caster, damage, 100, 0, 0, 0, 0 ); + } + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/EnergyVortex.cs b/Scripts/Spells/Eighth/EnergyVortex.cs new file mode 100644 index 0000000..37abe35 --- /dev/null +++ b/Scripts/Spells/Eighth/EnergyVortex.cs @@ -0,0 +1,101 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class EnergyVortexSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Energy Vortex", "Vas Corp Por", + 260, + 9032, + false, + Reagent.Bloodmoss, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public EnergyVortexSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + (Core.SE ? 2 : 1)) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop( ref p ); + + if ( map == null || !map.CanSpawnMobile( p.X, p.Y, p.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + TimeSpan duration; + + if ( Core.AOS ) + duration = TimeSpan.FromSeconds( 90.0 ); + else + duration = TimeSpan.FromSeconds( Utility.Random( 80, 40 ) ); + + BaseCreature.Summon( new EnergyVortex(), false, Caster, new Point3D( p ), 0x212, duration ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private EnergyVortexSpell m_Owner; + + public InternalTarget( EnergyVortexSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetOutOfLOS( Mobile from, object o ) + { + from.SendLocalizedMessage( 501943 ); // Target cannot be seen. Try again. + from.Target = new InternalTarget( m_Owner ); + from.Target.BeginTimeout( from, TimeoutTime - DateTime.Now ); + m_Owner = null; + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_Owner != null ) + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/FireElemental.cs b/Scripts/Spells/Eighth/FireElemental.cs new file mode 100644 index 0000000..09341fb --- /dev/null +++ b/Scripts/Spells/Eighth/FireElemental.cs @@ -0,0 +1,56 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class FireElementalSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Fire Elemental", "Kal Vas Xen Flam", + 269, + 9050, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public FireElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 4) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); + + if ( Core.AOS ) + SpellHelper.Summon( new SummonedFireElemental(), Caster, 0x217, duration, false, false ); + else + SpellHelper.Summon( new FireElemental(), Caster, 0x217, duration, false, false ); + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/Resurrection.cs b/Scripts/Spells/Eighth/Resurrection.cs new file mode 100644 index 0000000..87f7e96 --- /dev/null +++ b/Scripts/Spells/Eighth/Resurrection.cs @@ -0,0 +1,113 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Gumps; + +namespace Server.Spells.Eighth +{ + public class ResurrectionSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Resurrection", "An Corp", + 245, + 9062, + Reagent.Bloodmoss, + Reagent.Garlic, + Reagent.Ginseng + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public ResurrectionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( m == Caster ) + { + Caster.SendLocalizedMessage( 501039 ); // Thou can not resurrect thyself. + } + else if ( !Caster.Alive ) + { + Caster.SendLocalizedMessage( 501040 ); // The resurrecter must be alive. + } + else if ( m.Alive ) + { + Caster.SendLocalizedMessage( 501041 ); // Target is not dead. + } + else if ( !Caster.InRange( m, 1 ) ) + { + Caster.SendLocalizedMessage( 501042 ); // Target is not close enough. + } + else if ( !m.Player ) + { + Caster.SendLocalizedMessage( 501043 ); // Target is not a being. + } + else if ( m.Map == null || !m.Map.CanFit( m.Location, 16, false, false ) ) + { + Caster.SendLocalizedMessage( 501042 ); // Target can not be resurrected at that location. + m.SendLocalizedMessage( 502391 ); // Thou can not be resurrected there! + } + else if ( m.Region != null && m.Region.IsPartOf( "Khaldun" ) ) + { + Caster.SendLocalizedMessage( 1010395 ); // The veil of death in this area is too strong and resists thy efforts to restore life. + } + else if ( CheckBSequence( m, true ) ) + { + SpellHelper.Turn( Caster, m ); + + m.PlaySound( 0x214 ); + m.FixedEffect( 0x376A, 10, 16 ); + + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, Caster ) ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private ResurrectionSpell m_Owner; + + public InternalTarget( ResurrectionSpell owner ) : base( 1, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/SummonDaemon.cs b/Scripts/Spells/Eighth/SummonDaemon.cs new file mode 100644 index 0000000..f130e2a --- /dev/null +++ b/Scripts/Spells/Eighth/SummonDaemon.cs @@ -0,0 +1,62 @@ +using System; +using Server.Misc; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class SummonDaemonSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Daemon", "Kal Vas Xen Corp", + 269, + 9050, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public SummonDaemonSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + (Core.SE ? 4 : 5)) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); + + if ( Core.AOS ) /* Why two diff daemons? TODO: solve this */ + { + BaseCreature m_Daemon = new SummonedDaemon(); + SpellHelper.Summon( m_Daemon, Caster, 0x216, duration, false, false ); + m_Daemon.FixedParticles(0x3728, 8, 20, 5042, EffectLayer.Head ); + } + else + SpellHelper.Summon( new Daemon(), Caster, 0x216, duration, false, false ); + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Eighth/WaterElemental.cs b/Scripts/Spells/Eighth/WaterElemental.cs new file mode 100644 index 0000000..dc0dab8 --- /dev/null +++ b/Scripts/Spells/Eighth/WaterElemental.cs @@ -0,0 +1,55 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Eighth +{ + public class WaterElementalSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Water Elemental", "Kal Vas Xen An Flam", + 269, + 9070, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + + public WaterElementalSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 3) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); + + if ( Core.AOS ) + SpellHelper.Summon( new SummonedWaterElemental(), Caster, 0x217, duration, false, false ); + else + SpellHelper.Summon( new WaterElemental(), Caster, 0x217, duration, false, false ); + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fifth/BladeSpirits.cs b/Scripts/Spells/Fifth/BladeSpirits.cs new file mode 100644 index 0000000..9c4d705 --- /dev/null +++ b/Scripts/Spells/Fifth/BladeSpirits.cs @@ -0,0 +1,108 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Fifth +{ + public class BladeSpiritsSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Blade Spirits", "In Jux Hur Ylem", + 266, + 9040, + false, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public BladeSpiritsSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override TimeSpan GetCastDelay() + { + if ( Core.AOS ) + return TimeSpan.FromTicks( base.GetCastDelay().Ticks * ((Core.SE) ? 3 : 5) ); + + return base.GetCastDelay() + TimeSpan.FromSeconds( 6.0 ); + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if( (Caster.Followers + (Core.SE ? 2 : 1)) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop( ref p ); + + if ( map == null || !map.CanSpawnMobile( p.X, p.Y, p.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + TimeSpan duration; + + if ( Core.AOS ) + duration = TimeSpan.FromSeconds( 120 ); + else + duration = TimeSpan.FromSeconds( Utility.Random( 80, 40 ) ); + + BaseCreature.Summon( new BladeSpirits(), false, Caster, new Point3D( p ), 0x212, duration ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private BladeSpiritsSpell m_Owner; + + public InternalTarget( BladeSpiritsSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetOutOfLOS( Mobile from, object o ) + { + from.SendLocalizedMessage( 501943 ); // Target cannot be seen. Try again. + from.Target = new InternalTarget( m_Owner ); + from.Target.BeginTimeout( from, TimeoutTime - DateTime.Now ); + m_Owner = null; + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_Owner != null ) + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fifth/DispelField.cs b/Scripts/Spells/Fifth/DispelField.cs new file mode 100644 index 0000000..b693f06 --- /dev/null +++ b/Scripts/Spells/Fifth/DispelField.cs @@ -0,0 +1,92 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Items; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Spells.Fifth +{ + public class DispelFieldSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Dispel Field", "An Grav", + 206, + 9002, + Reagent.BlackPearl, + Reagent.SpidersSilk, + Reagent.SulfurousAsh, + Reagent.Garlic + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public DispelFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Item item ) + { + Type t = item.GetType(); + + if ( !Caster.CanSee( item ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( !t.IsDefined( typeof( DispellableFieldAttribute ), false ) ) + { + Caster.SendLocalizedMessage( 1005049 ); // That cannot be dispelled. + } + else if ( item is Moongate && !((Moongate)item).Dispellable ) + { + Caster.SendLocalizedMessage( 1005047 ); // That magic is too chaotic + } + else if ( CheckSequence() ) + { + // Scriptiz : Si pas joueur, on ne perd pas de karma + if (!(Caster is PlayerMobile)) Caster.Mana += 14; + + SpellHelper.Turn( Caster, item ); + + Effects.SendLocationParticles( EffectItem.Create( item.Location, item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 20, 5042 ); + Effects.PlaySound( item.GetWorldLocation(), item.Map, 0x201 ); + + item.Delete(); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private DispelFieldSpell m_Owner; + + public InternalTarget( DispelFieldSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Item ) + { + m_Owner.Target( (Item)o ); + } + else + { + m_Owner.Caster.SendLocalizedMessage( 1005049 ); // That cannot be dispelled. + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fifth/Incognito.cs b/Scripts/Spells/Fifth/Incognito.cs new file mode 100644 index 0000000..342f446 --- /dev/null +++ b/Scripts/Spells/Fifth/Incognito.cs @@ -0,0 +1,194 @@ +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Misc; +using Server.Items; +using Server.Gumps; +using Server.Spells; +using Server.Spells.Seventh; + +namespace Server.Spells.Fifth +{ + public class IncognitoSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Incognito", "Kal In Ex", + 206, + 9002, + Reagent.Bloodmoss, + Reagent.Garlic, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public IncognitoSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1010445 ); // You cannot incognito if you have a sigil + return false; + } + else if ( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + return false; + } + else if ( Caster.BodyMod == 183 || Caster.BodyMod == 184 ) + { + Caster.SendLocalizedMessage( 1042402 ); // You cannot use incognito while wearing body paint + return false; + } + + return true; + } + + public override void OnCast() + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1010445 ); // You cannot incognito if you have a sigil + } + else if ( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + else if ( Caster.BodyMod == 183 || Caster.BodyMod == 184 ) + { + Caster.SendLocalizedMessage( 1042402 ); // You cannot use incognito while wearing body paint + } + else if ( DisguiseTimers.IsDisguised( Caster ) ) + { + Caster.SendLocalizedMessage( 1061631 ); // You can't do that while disguised. + } + else if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) || Caster.IsBodyMod ) + { + DoFizzle(); + } + else if ( CheckSequence() ) + { + if ( Caster.BeginAction( typeof( IncognitoSpell ) ) ) + { + DisguiseTimers.StopTimer( Caster ); + + Caster.HueMod = Caster.Race.RandomSkinHue(); + Caster.NameMod = Caster.Female ? NameList.RandomName( "female" ) : NameList.RandomName( "male" ); + + PlayerMobile pm = Caster as PlayerMobile; + + if ( pm != null && pm.Race != null ) + { + pm.SetHairMods( pm.Race.RandomHair( pm.Female ), pm.Race.RandomFacialHair( pm.Female ) ); + pm.HairHue = pm.Race.RandomHairHue(); + pm.FacialHairHue = pm.Race.RandomHairHue(); + } + + Caster.FixedParticles( 0x373A, 10, 15, 5036, EffectLayer.Head ); + Caster.PlaySound( 0x3BD ); + + BaseArmor.ValidateMobile( Caster ); + BaseClothing.ValidateMobile( Caster ); + + StopTimer( Caster ); + + + int timeVal = ((6 * Caster.Skills.Magery.Fixed) / 50) + 1; + + if( timeVal > 144 ) + timeVal = 144; + + TimeSpan length = TimeSpan.FromSeconds( timeVal ); + + + Timer t = new InternalTimer( Caster, length ); + + m_Timers[Caster] = t; + + t.Start(); + + BuffInfo.AddBuff( Caster, new BuffInfo( BuffIcon.Incognito, 1075819, length, Caster ) ); + + } + else + { + Caster.SendLocalizedMessage( 1079022 ); // You're already incognitoed! + } + } + + FinishSequence(); + } + + private static Hashtable m_Timers = new Hashtable(); + + public static bool StopTimer( Mobile m ) + { + Timer t = (Timer)m_Timers[m]; + + if ( t != null ) + { + t.Stop(); + m_Timers.Remove( m ); + BuffInfo.RemoveBuff( m, BuffIcon.Incognito ); + } + + return ( t != null ); + } + + private static int[] m_HairIDs = new int[] + { + 0x2044, 0x2045, 0x2046, + 0x203C, 0x203B, 0x203D, + 0x2047, 0x2048, 0x2049, + 0x204A, 0x0000 + }; + + private static int[] m_BeardIDs = new int[] + { + 0x203E, 0x203F, 0x2040, + 0x2041, 0x204B, 0x204C, + 0x204D, 0x0000 + }; + + private class InternalTimer : Timer + { + private Mobile m_Owner; + + public InternalTimer( Mobile owner, TimeSpan length ) : base( length ) + { + m_Owner = owner; + + /* + int val = ((6 * owner.Skills.Magery.Fixed) / 50) + 1; + + if ( val > 144 ) + val = 144; + + Delay = TimeSpan.FromSeconds( val ); + * */ + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if ( !m_Owner.CanBeginAction( typeof( IncognitoSpell ) ) ) + { + if ( m_Owner is PlayerMobile ) + ((PlayerMobile)m_Owner).SetHairMods( -1, -1 ); + + m_Owner.BodyMod = 0; + m_Owner.HueMod = -1; + m_Owner.NameMod = null; + m_Owner.EndAction( typeof( IncognitoSpell ) ); + + BaseArmor.ValidateMobile( m_Owner ); + BaseClothing.ValidateMobile( m_Owner ); + } + } + } + } +} diff --git a/Scripts/Spells/Fifth/MagicReflect.cs b/Scripts/Spells/Fifth/MagicReflect.cs new file mode 100644 index 0000000..91a1661 --- /dev/null +++ b/Scripts/Spells/Fifth/MagicReflect.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Fifth +{ + public class MagicReflectSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Magic Reflection", "In Jux Sanct", + 242, + 9012, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public MagicReflectSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( Core.AOS ) + return true; + + if ( Caster.MagicDamageAbsorb > 0 ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + return false; + } + else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + return false; + } + + return true; + } + + private static Hashtable m_Table = new Hashtable(); + + public override void OnCast() + { + if ( Core.AOS ) + { + /* The magic reflection spell decreases the caster's physical resistance, while increasing the caster's elemental resistances. + * Physical decrease = 25 - (Inscription/20). + * Elemental resistance = +10 (-20 physical, +10 elemental at GM Inscription) + * The magic reflection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. + * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, even after dying�until you �turn them off� by casting them again. + */ + + if ( CheckSequence() ) + { + Mobile targ = Caster; + + ResistanceMod[] mods = (ResistanceMod[])m_Table[targ]; + + if ( mods == null ) + { + targ.PlaySound( 0x1E9 ); + targ.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist ); + + int physiMod = -25 + (int)(targ.Skills[SkillName.Inscribe].Value / 20); + int otherMod = 10; + + mods = new ResistanceMod[5] + { + new ResistanceMod( ResistanceType.Physical, physiMod ), + new ResistanceMod( ResistanceType.Fire, otherMod ), + new ResistanceMod( ResistanceType.Cold, otherMod ), + new ResistanceMod( ResistanceType.Poison, otherMod ), + new ResistanceMod( ResistanceType.Energy, otherMod ) + }; + + m_Table[targ] = mods; + + for ( int i = 0; i < mods.Length; ++i ) + targ.AddResistanceMod( mods[i] ); + + string buffFormat = String.Format( "{0}\t+{1}\t+{1}\t+{1}\t+{1}", physiMod, otherMod ); + + BuffInfo.AddBuff( targ, new BuffInfo( BuffIcon.MagicReflection, 1075817, buffFormat, true ) ); + } + else + { + targ.PlaySound( 0x1ED ); + targ.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist ); + + m_Table.Remove( targ ); + + for ( int i = 0; i < mods.Length; ++i ) + targ.RemoveResistanceMod( mods[i] ); + + BuffInfo.RemoveBuff( targ, BuffIcon.MagicReflection ); + } + } + + FinishSequence(); + } + else + { + if ( Caster.MagicDamageAbsorb > 0 ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + } + else if ( CheckSequence() ) + { + if ( Caster.BeginAction( typeof( DefensiveSpell ) ) ) + { + int value = (int)(Caster.Skills[SkillName.Magery].Value + Caster.Skills[SkillName.Inscribe].Value); + value = (int)(8 + (value/200)*7.0);//absorb from 8 to 15 "circles" + + Caster.MagicDamageAbsorb = value; + + Caster.FixedParticles( 0x375A, 10, 15, 5037, EffectLayer.Waist ); + Caster.PlaySound( 0x1E9 ); + } + else + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + } + } + + FinishSequence(); + } + } + public static void EndReflect(Mobile m) + { + if (m_Table.Contains(m)) + { + ResistanceMod[] mods = (ResistanceMod[])m_Table[m]; + + if (mods != null) + { + for (int i = 0; i < mods.Length; ++i) + m.RemoveResistanceMod(mods[i]); + } + + m_Table.Remove(m); + BuffInfo.RemoveBuff(m, BuffIcon.MagicReflection); + } + } + } +} diff --git a/Scripts/Spells/Fifth/MindBlast.cs b/Scripts/Spells/Fifth/MindBlast.cs new file mode 100644 index 0000000..2fd249e --- /dev/null +++ b/Scripts/Spells/Fifth/MindBlast.cs @@ -0,0 +1,156 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Fifth +{ + public class MindBlastSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mind Blast", "Por Corp Wis", + 218, + Core.AOS ? 9002 : 9032, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.Nightshade, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public MindBlastSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + if ( Core.AOS ) + m_Info.LeftHandEffect = m_Info.RightHandEffect = 9002; + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + private void AosDelay_Callback( object state ) + { + object[] states = (object[])state; + Mobile caster = (Mobile)states[0]; + Mobile target = (Mobile)states[1]; + Mobile defender = (Mobile)states[2]; + int damage = (int)states[3]; + + if ( caster.HarmfulCheck( defender ) ) + { + SpellHelper.Damage( this, target, Utility.RandomMinMax( damage, damage + 4 ), 0, 0, 100, 0, 0 ); + + target.FixedParticles( 0x374A, 10, 15, 5038, 1181, 2, EffectLayer.Head ); + target.PlaySound( 0x213 ); + } + } + + public override bool DelayedDamage{ get{ return !Core.AOS; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( Core.AOS ) + { + if ( Caster.CanBeHarmful( m ) && CheckSequence() ) + { + Mobile from = Caster, target = m; + + SpellHelper.Turn( from, target ); + + SpellHelper.CheckReflect( (int)this.Circle, ref from, ref target ); + + int damage = (int)((Caster.Skills[SkillName.Magery].Value + Caster.Int) / 5); + + if ( damage > 60 ) + damage = 60; + + Timer.DelayCall( TimeSpan.FromSeconds( 1.0 ), + new TimerStateCallback( AosDelay_Callback ), + new object[]{ Caster, target, m, damage } ); + } + } + else if ( CheckHSequence( m ) ) + { + Mobile from = Caster, target = m; + + SpellHelper.Turn( from, target ); + + SpellHelper.CheckReflect( (int)this.Circle, ref from, ref target ); + + // Algorithm: (highestStat - lowestStat) / 2 [- 50% if resisted] + + int highestStat = target.Str, lowestStat = target.Str; + + if ( target.Dex > highestStat ) + highestStat = target.Dex; + + if ( target.Dex < lowestStat ) + lowestStat = target.Dex; + + if ( target.Int > highestStat ) + highestStat = target.Int; + + if ( target.Int < lowestStat ) + lowestStat = target.Int; + + if ( highestStat > 150 ) + highestStat = 150; + + if ( lowestStat > 150 ) + lowestStat = 150; + + double damage = GetDamageScalar(m) * (highestStat - lowestStat) / 4;//less damage + + if ( damage > 45 ) + damage = 45; + + if ( CheckResisted( target ) ) + { + damage /= 2; + target.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + from.FixedParticles( 0x374A, 10, 15, 2038, EffectLayer.Head ); + + target.FixedParticles( 0x374A, 10, 15, 5038, EffectLayer.Head ); + target.PlaySound( 0x213 ); + + SpellHelper.Damage( this, target, damage, 0, 0, 100, 0, 0 ); + + } + + FinishSequence(); + } + + public override double GetSlayerDamageScalar( Mobile target ) + { + return 1.0; //This spell isn't affected by slayer spellbooks + } + + private class InternalTarget : Target + { + private MindBlastSpell m_Owner; + + public InternalTarget( MindBlastSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fifth/Paralyze.cs b/Scripts/Spells/Fifth/Paralyze.cs new file mode 100644 index 0000000..f06cd93 --- /dev/null +++ b/Scripts/Spells/Fifth/Paralyze.cs @@ -0,0 +1,112 @@ +using System; +using Server.Mobiles; +using Server.Targeting; +using Server.Network; +using Server.Spells.Chivalry; + +namespace Server.Spells.Fifth +{ + public class ParalyzeSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Paralyze", "An Ex Por", + 218, + 9012, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public ParalyzeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( Core.AOS && (m.Frozen || m.Paralyzed || (m.Spell != null && m.Spell.IsCasting && !(m.Spell is PaladinSpell))) ) + { + Caster.SendLocalizedMessage( 1061923 ); // The target is already frozen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + double duration; + + if ( Core.AOS ) + { + int secs = (int)((GetDamageSkill( Caster ) / 10) - (GetResistSkill( m ) / 10)); + + if( !Core.SE ) + secs += 2; + + if ( !m.Player ) + secs *= 3; + + if ( secs < 0 ) + secs = 0; + + duration = secs; + } + else + { + // Algorithm: ((20% of magery) + 7) seconds [- 50% if resisted] + + duration = 7.0 + (Caster.Skills[SkillName.Magery].Value * 0.2); + + if ( CheckResisted( m ) ) + duration *= 0.75; + } + + if ( m is PlagueBeastLord ) + { + ( (PlagueBeastLord) m ).OnParalyzed( Caster ); + duration = 120; + } + + m.Paralyze( TimeSpan.FromSeconds( duration ) ); + + m.PlaySound( 0x204 ); + m.FixedEffect( 0x376A, 6, 1 ); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private ParalyzeSpell m_Owner; + + public InternalTarget( ParalyzeSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fifth/PoisonField.cs b/Scripts/Spells/Fifth/PoisonField.cs new file mode 100644 index 0000000..143c792 --- /dev/null +++ b/Scripts/Spells/Fifth/PoisonField.cs @@ -0,0 +1,301 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Fifth +{ + public class PoisonFieldSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Poison Field", "In Nox Grav", + 230, + 9052, + false, + Reagent.BlackPearl, + Reagent.Nightshade, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public PoisonFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + { + eastToWest = false; + } + else if ( rx >= 0 ) + { + eastToWest = true; + } + else if ( ry >= 0 ) + { + eastToWest = true; + } + else + { + eastToWest = false; + } + + Effects.PlaySound( p, Caster.Map, 0x20B ); + + int itemID = eastToWest ? 0x3915 : 0x3922; + + TimeSpan duration = TimeSpan.FromSeconds( 3 + (Caster.Skills.Magery.Fixed / 25) ); + + for ( int i = -2; i <= 2; ++i ) + { + Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z ); + + new InternalItem( itemID, loc, Caster, Caster.Map, duration, i ); + } + } + + FinishSequence(); + } + + [DispellableField] + public class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Caster; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val ) : base( itemID ) + { + bool canFit = SpellHelper.AdjustField( ref loc, map, 12, false ); + + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld( loc, map ); + + m_Caster = caster; + + m_End = DateTime.Now + duration; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( Math.Abs( val ) * 0.2 ), caster.InLOS( this ), canFit ); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Caster ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Caster = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, TimeSpan.Zero, true, true ); + m_Timer.Start(); + + break; + } + } + } + + public void ApplyPoisonTo( Mobile m ) + { + if ( m_Caster == null ) + return; + + Poison p; + + if ( Core.AOS ) + { + int total = (m_Caster.Skills.Magery.Fixed + m_Caster.Skills.Poisoning.Fixed) / 2; + + if ( total >= 1000 ) + p = Poison.Deadly; + else if ( total > 850 ) + p = Poison.Greater; + else if ( total > 650 ) + p = Poison.Regular; + else + p = Poison.Lesser; + } + else + { + p = Poison.Regular; + } + + if ( m.ApplyPoison( m_Caster, p ) == ApplyPoisonResult.Poisoned ) + if ( SpellHelper.CanRevealCaster( m ) ) + m_Caster.RevealingAction(); + + if (m is BaseCreature) + ((BaseCreature)m).OnHarmfulSpell(m_Caster); + } + + public override bool OnMoveOver( Mobile m ) + { + if ( Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) ) + { + m_Caster.DoHarmful( m ); + + ApplyPoisonTo( m ); + m.PlaySound( 0x474 ); + } + + return true; + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + private bool m_InLOS, m_CanFit; + + private static Queue m_Queue = new Queue(); + + public InternalTimer( InternalItem item, TimeSpan delay, bool inLOS, bool canFit ) : base( delay, TimeSpan.FromSeconds( 1.5 ) ) + { + m_Item = item; + m_InLOS = inLOS; + m_CanFit = canFit; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Item.Deleted ) + return; + + if ( !m_Item.Visible ) + { + if ( m_InLOS && m_CanFit ) + m_Item.Visible = true; + else + m_Item.Delete(); + + if ( !m_Item.Deleted ) + { + m_Item.ProcessDelta(); + Effects.SendLocationParticles( EffectItem.Create( m_Item.Location, m_Item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5040 ); + } + } + else if ( DateTime.Now > m_Item.m_End ) + { + m_Item.Delete(); + Stop(); + } + else + { + Map map = m_Item.Map; + Mobile caster = m_Item.m_Caster; + + if ( map != null && caster != null ) + { + bool eastToWest = ( m_Item.ItemID == 0x3915 ); + IPooledEnumerable eable = map.GetMobilesInBounds( new Rectangle2D( m_Item.X - (eastToWest ? 0 : 1), m_Item.Y - (eastToWest ? 1 : 0), (eastToWest ? 1 : 2), (eastToWest ? 2 : 1) ) ); + + foreach ( Mobile m in eable ) + { + if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && (!Core.AOS || m != caster) && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) ) + m_Queue.Enqueue( m ); + } + + eable.Free(); + + while ( m_Queue.Count > 0 ) + { + Mobile m = (Mobile)m_Queue.Dequeue(); + + caster.DoHarmful( m ); + + m_Item.ApplyPoisonTo( m ); + m.PlaySound( 0x474 ); + } + } + } + } + } + } + + private class InternalTarget : Target + { + private PoisonFieldSpell m_Owner; + + public InternalTarget( PoisonFieldSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fifth/SummonCreature.cs b/Scripts/Spells/Fifth/SummonCreature.cs new file mode 100644 index 0000000..cfc4d4d --- /dev/null +++ b/Scripts/Spells/Fifth/SummonCreature.cs @@ -0,0 +1,98 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Fifth +{ + public class SummonCreatureSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Creature", "Kal Xen", + 16, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + + public SummonCreatureSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + // NOTE: Creature list based on 1hr of summon/release on OSI. + + private static Type[] m_Types = new Type[] + { + typeof( PolarBear ), + typeof( GrizzlyBear ), + typeof( BlackBear ), + typeof( Horse ), + typeof( Walrus ), + typeof( Chicken ), + typeof( Scorpion ), + typeof( GiantSerpent ), + typeof( Llama ), + typeof( Alligator ), + typeof( GreyWolf ), + typeof( Slime ), + typeof( Eagle ), + typeof( Gorilla ), + typeof( SnowLeopard ), + typeof( Pig ), + typeof( Hind ), + typeof( Rabbit ) + }; + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 2) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + try + { + BaseCreature creature = (BaseCreature)Activator.CreateInstance( m_Types[Utility.Random( m_Types.Length )] ); + + //creature.ControlSlots = 2; + + TimeSpan duration; + + if ( Core.AOS ) + duration = TimeSpan.FromSeconds( (2 * Caster.Skills.Magery.Fixed) / 5 ); + else + duration = TimeSpan.FromSeconds( 4.0 * Caster.Skills[SkillName.Magery].Value ); + + SpellHelper.Summon( creature, Caster, 0x215, duration, false, false ); + } + catch + { + } + } + + FinishSequence(); + } + + public override TimeSpan GetCastDelay() + { + if ( Core.AOS ) + return TimeSpan.FromTicks( base.GetCastDelay().Ticks * 5 ); + + return base.GetCastDelay() + TimeSpan.FromSeconds( 6.0 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/Clumsy.cs b/Scripts/Spells/First/Clumsy.cs new file mode 100644 index 0000000..57daac2 --- /dev/null +++ b/Scripts/Spells/First/Clumsy.cs @@ -0,0 +1,83 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.First +{ + public class ClumsySpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Clumsy", "Uus Jux", + 212, + 9031, + Reagent.Bloodmoss, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public ClumsySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + SpellHelper.AddStatCurse( Caster, m, StatType.Dex ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles( 0x3779, 10, 15, 5002, EffectLayer.Head ); + m.PlaySound( 0x1DF ); + + int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, true )*100); + TimeSpan length = SpellHelper.GetDuration( Caster, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Clumsy, 1075831, length, m, percentage.ToString() ) ); + HarmfulSpell(m); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private ClumsySpell m_Owner; + + public InternalTarget( ClumsySpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/CreateFood.cs b/Scripts/Spells/First/CreateFood.cs new file mode 100644 index 0000000..bc2d7de --- /dev/null +++ b/Scripts/Spells/First/CreateFood.cs @@ -0,0 +1,90 @@ +using System; +using Server.Items; + +namespace Server.Spells.First +{ + public class CreateFoodSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Create Food", "In Mani Ylem", + 224, + 9011, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public CreateFoodSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + private static FoodInfo[] m_Food = new FoodInfo[] + { + new FoodInfo( typeof( Grapes ), "a grape bunch" ), + new FoodInfo( typeof( Ham ), "a ham" ), + new FoodInfo( typeof( CheeseWedge ), "a wedge of cheese" ), + new FoodInfo( typeof( Muffins ), "muffins" ), + new FoodInfo( typeof( FishSteak ), "a fish steak" ), + new FoodInfo( typeof( Ribs ), "cut of ribs" ), + new FoodInfo( typeof( CookedBird ), "a cooked bird" ), + new FoodInfo( typeof( Sausage ), "sausage" ), + new FoodInfo( typeof( Apple ), "an apple" ), + new FoodInfo( typeof( Peach ), "a peach" ) + }; + + public override void OnCast() + { + if ( CheckSequence() ) + { + FoodInfo foodInfo = m_Food[Utility.Random( m_Food.Length )]; + Item food = foodInfo.Create(); + + if ( food != null ) + { + Caster.AddToBackpack( food ); + + // You magically create food in your backpack: + Caster.SendLocalizedMessage( 1042695, true, " " + foodInfo.Name ); + + Caster.FixedParticles( 0, 10, 5, 2003, EffectLayer.RightHand ); + Caster.PlaySound( 0x1E2 ); + } + } + + FinishSequence(); + } + } + + public class FoodInfo + { + private Type m_Type; + private string m_Name; + + public Type Type{ get{ return m_Type; } set{ m_Type = value; } } + public string Name{ get{ return m_Name; } set{ m_Name = value; } } + + public FoodInfo( Type type, string name ) + { + m_Type = type; + m_Name = name; + } + + public Item Create() + { + Item item; + + try + { + item = (Item)Activator.CreateInstance( m_Type ); + } + catch + { + item = null; + } + + return item; + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/Feeblemind.cs b/Scripts/Spells/First/Feeblemind.cs new file mode 100644 index 0000000..a20fed6 --- /dev/null +++ b/Scripts/Spells/First/Feeblemind.cs @@ -0,0 +1,84 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.First +{ + public class FeeblemindSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Feeblemind", "Rel Wis", + 212, + 9031, + Reagent.Ginseng, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public FeeblemindSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + SpellHelper.AddStatCurse( Caster, m, StatType.Int ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles( 0x3779, 10, 15, 5004, EffectLayer.Head ); + m.PlaySound( 0x1E4 ); + + int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, true )*100); + TimeSpan length = SpellHelper.GetDuration( Caster, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.FeebleMind, 1075833, length, m, percentage.ToString() ) ); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private FeeblemindSpell m_Owner; + + public InternalTarget( FeeblemindSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/Heal.cs b/Scripts/Spells/First/Heal.cs new file mode 100644 index 0000000..0fd3d20 --- /dev/null +++ b/Scripts/Spells/First/Heal.cs @@ -0,0 +1,117 @@ +using System; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; + +namespace Server.Spells.First +{ + public class HealSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Heal", "In Mani", + 224, + 9061, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public HealSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( m.IsDeadBondedPet ) + { + Caster.SendLocalizedMessage( 1060177 ); // You cannot heal a creature that is already dead! + } + else if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead ) + { + Caster.SendLocalizedMessage( 1061654 ); // You cannot heal that which is not alive. + } + else if ( m is Golem ) + { + Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500951 ); // You cannot heal that. + } + else if ( m.Poisoned || Server.Items.MortalStrike.IsWounded( m ) ) + { + Caster.LocalOverheadMessage( MessageType.Regular, 0x22, (Caster == m) ? 1005000 : 1010398 ); + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + int toHeal; + + if ( Core.AOS ) + { + toHeal = Caster.Skills.Magery.Fixed / 120; + toHeal += Utility.RandomMinMax( 1, 4 ); + + if( Core.SE && Caster != m ) + toHeal = (int)(toHeal * 1.5); + } + else + { + toHeal = (int)(Caster.Skills[SkillName.Magery].Value * 0.1); + toHeal += Utility.Random( 1, 5 ); + } + + //m.Heal( toHeal, Caster ); + SpellHelper.Heal( toHeal, m, Caster ); + + m.FixedParticles( 0x376A, 9, 32, 5005, EffectLayer.Waist ); + m.PlaySound( 0x1F2 ); + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private HealSpell m_Owner; + + public InternalTarget( HealSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/MagicArrow.cs b/Scripts/Spells/First/MagicArrow.cs new file mode 100644 index 0000000..78b4b3f --- /dev/null +++ b/Scripts/Spells/First/MagicArrow.cs @@ -0,0 +1,97 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.First +{ + public class MagicArrowSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Magic Arrow", "In Por Ylem", + 212, + 9041, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public MagicArrowSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool DelayedDamageStacking { get { return !Core.AOS; } } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return true; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + Mobile source = Caster; + + SpellHelper.Turn( source, m ); + + SpellHelper.CheckReflect( (int)this.Circle, ref source, ref m ); + + double damage; + + if ( Core.AOS ) + { + damage = GetNewAosDamage( 10, 1, 4, m ); + } + else + { + damage = Utility.Random( 4, 4 ); + + if ( CheckResisted( m ) ) + { + damage *= 0.75; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar( m ); + } + + source.MovingParticles( m, 0x36E4, 5, 0, false, false, 3006, 0, 0 ); + source.PlaySound( 0x1E5 ); + + SpellHelper.Damage( this, m, damage, 0, 100, 0, 0, 0 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MagicArrowSpell m_Owner; + + public InternalTarget( MagicArrowSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/NightSight.cs b/Scripts/Spells/First/NightSight.cs new file mode 100644 index 0000000..66948cc --- /dev/null +++ b/Scripts/Spells/First/NightSight.cs @@ -0,0 +1,76 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server; + +namespace Server.Spells.First +{ + public class NightSightSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Night Sight", "In Lor", + 236, + 9031, + Reagent.SulfurousAsh, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public NightSightSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new NightSightTarget( this ); + } + + private class NightSightTarget : Target + { + private Spell m_Spell; + + public NightSightTarget( Spell spell ) : base( 12, false, TargetFlags.Beneficial ) + { + m_Spell = spell; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is Mobile && m_Spell.CheckBSequence( (Mobile) targeted ) ) + { + Mobile targ = (Mobile)targeted; + + SpellHelper.Turn( m_Spell.Caster, targ ); + + if ( targ.BeginAction( typeof( LightCycle ) ) ) + { + new LightCycle.NightSightTimer( targ ).Start(); + int level = (int)( LightCycle.DungeonLevel * ( (Core.AOS ? targ.Skills[SkillName.Magery].Value : from.Skills[SkillName.Magery].Value )/ 100 ) ); + + if ( level < 0 ) + level = 0; + + targ.LightLevel = level; + + targ.FixedParticles( 0x376A, 9, 32, 5007, EffectLayer.Waist ); + targ.PlaySound( 0x1E3 ); + + BuffInfo.AddBuff( targ, new BuffInfo( BuffIcon.NightSight, 1075643 ) ); //Night Sight/You ignore lighting effects + } + else + { + from.SendMessage( "{0} already have nightsight.", from == targ ? "You" : "They" ); + } + } + + m_Spell.FinishSequence(); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Spell.FinishSequence(); + } + } + } +} diff --git a/Scripts/Spells/First/ReactiveArmor.cs b/Scripts/Spells/First/ReactiveArmor.cs new file mode 100644 index 0000000..eb4c025 --- /dev/null +++ b/Scripts/Spells/First/ReactiveArmor.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.First +{ + public class ReactiveArmorSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Reactive Armor", "Flam Sanct", + 236, + 9011, + Reagent.Garlic, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public ReactiveArmorSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( Core.AOS ) + return true; + + if ( Caster.MeleeDamageAbsorb > 0 ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + return false; + } + else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + return false; + } + + return true; + } + + private static Hashtable m_Table = new Hashtable(); + + public override void OnCast() + { + if ( Core.AOS ) + { + /* The reactive armor spell increases the caster's physical resistance, while lowering the caster's elemental resistances. + * 15 + (Inscription/20) Physcial bonus + * -5 Elemental + * The reactive armor spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. + * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, even after dying�until you �turn them off� by casting them again. + * (+20 physical -5 elemental at 100 Inscription) + */ + + if ( CheckSequence() ) + { + Mobile targ = Caster; + + ResistanceMod[] mods = (ResistanceMod[])m_Table[targ]; + + if ( mods == null ) + { + targ.PlaySound( 0x1E9 ); + targ.FixedParticles( 0x376A, 9, 32, 5008, EffectLayer.Waist ); + + mods = new ResistanceMod[5] + { + new ResistanceMod( ResistanceType.Physical, 15 + (int)(targ.Skills[SkillName.Inscribe].Value / 20) ), + new ResistanceMod( ResistanceType.Fire, -5 ), + new ResistanceMod( ResistanceType.Cold, -5 ), + new ResistanceMod( ResistanceType.Poison, -5 ), + new ResistanceMod( ResistanceType.Energy, -5 ) + }; + + m_Table[targ] = mods; + + for ( int i = 0; i < mods.Length; ++i ) + targ.AddResistanceMod( mods[i] ); + + int physresist = 15 + (int)(targ.Skills[SkillName.Inscribe].Value / 20); + string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}", physresist, 5, 5, 5, 5); + + BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.ReactiveArmor, 1075812, 1075813, args.ToString())); + } + else + { + targ.PlaySound( 0x1ED ); + targ.FixedParticles( 0x376A, 9, 32, 5008, EffectLayer.Waist ); + + m_Table.Remove( targ ); + + for ( int i = 0; i < mods.Length; ++i ) + targ.RemoveResistanceMod( mods[i] ); + + BuffInfo.RemoveBuff(Caster, BuffIcon.ReactiveArmor); + } + } + + FinishSequence(); + } + else + { + if ( Caster.MeleeDamageAbsorb > 0 ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + } + else if ( CheckSequence() ) + { + if ( Caster.BeginAction( typeof( DefensiveSpell ) ) ) + { + int value = (int)(Caster.Skills[SkillName.Magery].Value + Caster.Skills[SkillName.Meditation].Value + Caster.Skills[SkillName.Inscribe].Value); + value /= 3; + + if ( value < 0 ) + value = 1; + else if ( value > 75 ) + value = 75; + + Caster.MeleeDamageAbsorb = value; + + Caster.FixedParticles( 0x376A, 9, 32, 5008, EffectLayer.Waist ); + Caster.PlaySound( 0x1F2 ); + } + else + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + } + } + + FinishSequence(); + } + } + public static void EndArmor(Mobile m) + { + if (m_Table.Contains(m)) + { + ResistanceMod[] mods = (ResistanceMod[])m_Table[m]; + + if (mods != null) + { + for (int i = 0; i < mods.Length; ++i) + m.RemoveResistanceMod(mods[i]); + } + + m_Table.Remove(m); + BuffInfo.RemoveBuff(m, BuffIcon.ReactiveArmor); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/First/Weaken.cs b/Scripts/Spells/First/Weaken.cs new file mode 100644 index 0000000..53298c1 --- /dev/null +++ b/Scripts/Spells/First/Weaken.cs @@ -0,0 +1,83 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.First +{ + public class WeakenSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Weaken", "Des Mani", + 212, + 9031, + Reagent.Garlic, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.First; } } + + public WeakenSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + SpellHelper.AddStatCurse( Caster, m, StatType.Str ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles( 0x3779, 10, 15, 5009, EffectLayer.Waist ); + m.PlaySound( 0x1E6 ); + + int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, true )*100); + TimeSpan length = SpellHelper.GetDuration( Caster, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Weaken, 1075837, length, m, percentage.ToString() ) ); + HarmfulSpell(m); + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private WeakenSpell m_Owner; + + public InternalTarget( WeakenSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/ArchCure.cs b/Scripts/Spells/Fourth/ArchCure.cs new file mode 100644 index 0000000..e434fcf --- /dev/null +++ b/Scripts/Spells/Fourth/ArchCure.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Fourth +{ + public class ArchCureSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Arch Cure", "Vas An Nox", + 215, + 9061, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public ArchCureSpell(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget(this); + } + + // Arch cure is now 1/4th of a second faster + public override TimeSpan CastDelayBase { get { return base.CastDelayBase - TimeSpan.FromSeconds(0.25); } } + + public void Target(IPoint3D p) + { + if (!Caster.CanSee(p)) + { + Caster.SendLocalizedMessage(500237); // Target can not be seen. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, p); + + SpellHelper.GetSurfaceTop(ref p); + + List targets = new List(); + + Map map = Caster.Map; + Mobile directTarget = p as Mobile; + + if (map != null) + { + bool feluccaRules = (map.Rules == MapRules.FeluccaRules); + + // You can target any living mobile directly, beneficial checks apply + if (directTarget != null && Caster.CanBeBeneficial(directTarget, false)) + targets.Add(directTarget); + + IPooledEnumerable eable = map.GetMobilesInRange(new Point3D(p), 2); + + foreach (Mobile m in eable) + { + if (m == directTarget) + continue; + + if (AreaCanTarget(m, feluccaRules)) + targets.Add(m); + } + + eable.Free(); + } + + Effects.PlaySound(p, Caster.Map, 0x299); + + if (targets.Count > 0) + { + int cured = 0; + + for (int i = 0; i < targets.Count; ++i) + { + Mobile m = targets[i]; + + Caster.DoBeneficial(m); + + Poison poison = m.Poison; + + if (poison != null) + { + int chanceToCure = 10000 + (int)(Caster.Skills[SkillName.Magery].Value * 75) - ((poison.Level + 1) * 1750); + chanceToCure /= 100; + chanceToCure -= 1; + + if (chanceToCure > Utility.Random(100) && m.CurePoison(Caster)) + ++cured; + } + + m.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); + m.PlaySound(0x1E0); + } + + if (cured > 0) + Caster.SendLocalizedMessage(1010058); // You have cured the target of all poisons! + } + } + + FinishSequence(); + } + + private bool AreaCanTarget(Mobile target, bool feluccaRules) + { + /* Arch cure area effect won't cure aggressors, victims, murderers, criminals or monsters. + * In Felucca, it will also not cure summons and pets. + * For red players it will only cure themselves and guild members. + */ + + if (!Caster.CanBeBeneficial(target, false)) + return false; + + if (Core.AOS && target != Caster) + { + if (IsAggressor(target) || IsAggressed(target)) + return false; + + if ((!IsInnocentTo(Caster, target) || !IsInnocentTo(target, Caster)) && !IsAllyTo(Caster, target)) + return false; + + if (feluccaRules && !(target is PlayerMobile)) + return false; + } + + return true; + } + + private bool IsAggressor(Mobile m) + { + foreach (AggressorInfo info in Caster.Aggressors) + { + if (m == info.Attacker && !info.Expired) + return true; + } + + return false; + } + + private bool IsAggressed(Mobile m) + { + foreach (AggressorInfo info in Caster.Aggressed) + { + if (m == info.Defender && !info.Expired) + return true; + } + + return false; + } + + private static bool IsInnocentTo(Mobile from, Mobile to) + { + return (Notoriety.Compute(from, (Mobile)to) == Notoriety.Innocent); + } + + private static bool IsAllyTo(Mobile from, Mobile to) + { + return (Notoriety.Compute(from, (Mobile)to) == Notoriety.Ally); + } + + private class InternalTarget : Target + { + private ArchCureSpell m_Owner; + + public InternalTarget(ArchCureSpell owner) + : base(Core.ML ? 10 : 12, true, TargetFlags.None) + { + m_Owner = owner; + } + + protected override void OnTarget(Mobile from, object o) + { + IPoint3D p = o as IPoint3D; + + if (p != null) + m_Owner.Target(p); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/ArchProtection.cs b/Scripts/Spells/Fourth/ArchProtection.cs new file mode 100644 index 0000000..bd66792 --- /dev/null +++ b/Scripts/Spells/Fourth/ArchProtection.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Engines.PartySystem; + +namespace Server.Spells.Fourth +{ + public class ArchProtectionSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Arch Protection", "Vas Uus Sanct", + Core.AOS ? 239 : 215, + 9011, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public ArchProtectionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + List targets = new List(); + + Map map = Caster.Map; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), Core.AOS ? 2 : 3 ); + + foreach ( Mobile m in eable ) + { + if ( Caster.CanBeBeneficial( m, false ) ) + targets.Add( m ); + } + + eable.Free(); + } + + if ( Core.AOS ) + { + Party party = Party.Get( Caster ); + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + if ( m == Caster || ( party != null && party.Contains( m ) ) ) + { + Caster.DoBeneficial( m ); + Spells.Second.ProtectionSpell.Toggle( Caster, m ); + } + } + } + else + { + Effects.PlaySound( p, Caster.Map, 0x299 ); + + int val = (int)(Caster.Skills[SkillName.Magery].Value/10.0 + 1); + + if ( targets.Count > 0 ) + { + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + if ( m.BeginAction( typeof( ArchProtectionSpell ) ) ) + { + Caster.DoBeneficial( m ); + m.VirtualArmorMod += val; + AddEntry(m, val); + new InternalTimer(m, Caster).Start(); + + + m.FixedParticles( 0x375A, 9, 20, 5027, EffectLayer.Waist ); + m.PlaySound( 0x1F7 ); + } + } + } + } + } + + FinishSequence(); + } + + private static Dictionary _Table = new Dictionary(); + + private static void AddEntry(Mobile m, Int32 v) + { + _Table[m] = v; + } + + public static void RemoveEntry(Mobile m) + { + if (_Table.ContainsKey(m)) + { + int v = _Table[m]; + _Table.Remove(m); + m.EndAction(typeof(ArchProtectionSpell)); + m.VirtualArmorMod -= v; + if (m.VirtualArmorMod < 0) + m.VirtualArmorMod = 0; + } + } + + private class InternalTimer : Timer + { + private Mobile m_Owner; + + public InternalTimer(Mobile target, Mobile caster) + : base(TimeSpan.FromSeconds(0)) + { + double time = caster.Skills[SkillName.Magery].Value * 1.2; + if ( time > 144 ) + time = 144; + Delay = TimeSpan.FromSeconds( time ); + Priority = TimerPriority.OneSecond; + + m_Owner = target; + m_Owner = target; + } + + protected override void OnTick() + { + ArchProtectionSpell.RemoveEntry(m_Owner); + } + } + + private class InternalTarget : Target + { + private ArchProtectionSpell m_Owner; + + public InternalTarget( ArchProtectionSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Spells/Fourth/Curse.cs b/Scripts/Spells/Fourth/Curse.cs new file mode 100644 index 0000000..7c5a13d --- /dev/null +++ b/Scripts/Spells/Fourth/Curse.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Fourth +{ + public class CurseSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Curse", "Des Sanct", + 227, + 9031, + Reagent.Nightshade, + Reagent.Garlic, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public CurseSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + private static Hashtable m_UnderEffect = new Hashtable(); + + public static void RemoveEffect( object state ) + { + Mobile m = (Mobile)state; + + m_UnderEffect.Remove( m ); + + m.UpdateResistances(); + } + + public static bool UnderEffect( Mobile m ) + { + return m_UnderEffect.Contains( m ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + SpellHelper.AddStatCurse( Caster, m, StatType.Str ); SpellHelper.DisableSkillCheck = true; + SpellHelper.AddStatCurse( Caster, m, StatType.Dex ); + SpellHelper.AddStatCurse( Caster, m, StatType.Int ); SpellHelper.DisableSkillCheck = false; + + Timer t = (Timer)m_UnderEffect[m]; + + if ( Caster.Player && m.Player /*&& Caster != m */ && t == null ) //On OSI you CAN curse yourself and get this effect. + { + TimeSpan duration = SpellHelper.GetDuration( Caster, m ); + m_UnderEffect[m] = t = Timer.DelayCall( duration, new TimerStateCallback( RemoveEffect ), m ); + m.UpdateResistances(); + } + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + m.FixedParticles( 0x374A, 10, 15, 5028, EffectLayer.Waist ); + m.PlaySound( 0x1E1 ); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", percentage, percentage, percentage, 10, 10, 10, 10); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, length, m, args.ToString())); + HarmfulSpell(m); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private CurseSpell m_Owner; + + public InternalTarget( CurseSpell owner ) : base( Core.ML? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/FireField.cs b/Scripts/Spells/Fourth/FireField.cs new file mode 100644 index 0000000..1f224dc --- /dev/null +++ b/Scripts/Spells/Fourth/FireField.cs @@ -0,0 +1,315 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Fourth +{ + public class FireFieldSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Fire Field", "In Flam Grav", + 215, + 9041, + false, + Reagent.BlackPearl, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public FireFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + { + eastToWest = false; + } + else if ( rx >= 0 ) + { + eastToWest = true; + } + else if ( ry >= 0 ) + { + eastToWest = true; + } + else + { + eastToWest = false; + } + + Effects.PlaySound( p, Caster.Map, 0x20C ); + + int itemID = eastToWest ? 0x398C : 0x3996; + + TimeSpan duration; + + if ( Core.AOS ) + duration = TimeSpan.FromSeconds( (15 + (Caster.Skills.Magery.Fixed / 5)) / 4 ); + else + duration = TimeSpan.FromSeconds( 4.0 + (Caster.Skills[SkillName.Magery].Value * 0.5) ); + + for ( int i = -2; i <= 2; ++i ) + { + Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z ); + + new FireFieldItem( itemID, loc, Caster, Caster.Map, duration, i ); + } + } + + FinishSequence(); + } + + [DispellableField] + public class FireFieldItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Caster; + private int m_Damage; + + public override bool BlocksFit{ get{ return true; } } + + public FireFieldItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val ) + : this( itemID, loc, caster, map, duration, val, 2 ) + { + } + + public FireFieldItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val, int damage ) : base( itemID ) + { + bool canFit = SpellHelper.AdjustField( ref loc, map, 12, false ); + + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld( loc, map ); + + m_Caster = caster; + + m_Damage = damage; + + m_End = DateTime.Now + duration; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( Math.Abs( val ) * 0.2 ), caster.InLOS( this ), canFit ); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public FireFieldItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + writer.Write( m_Damage ); + writer.Write( m_Caster ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + m_Damage = reader.ReadInt(); + goto case 1; + } + case 1: + { + m_Caster = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, TimeSpan.Zero, true, true ); + m_Timer.Start(); + + break; + } + } + + if( version < 2 ) + m_Damage = 2; + } + + public override bool OnMoveOver( Mobile m ) + { + if ( Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) ) + { + if ( SpellHelper.CanRevealCaster( m ) ) + m_Caster.RevealingAction(); + + m_Caster.DoHarmful( m ); + + int damage = m_Damage; + + if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 30.0 ) ) + { + damage = 1; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + AOS.Damage( m, m_Caster, damage, 0, 100, 0, 0, 0 ); + m.PlaySound( 0x208 ); + + if (m is BaseCreature) + ((BaseCreature)m).OnHarmfulSpell(m_Caster); + } + + return true; + } + + private class InternalTimer : Timer + { + private FireFieldItem m_Item; + private bool m_InLOS, m_CanFit; + + private static Queue m_Queue = new Queue(); + + public InternalTimer( FireFieldItem item, TimeSpan delay, bool inLOS, bool canFit ) : base( delay, TimeSpan.FromSeconds( 1.0 ) ) + { + m_Item = item; + m_InLOS = inLOS; + m_CanFit = canFit; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Item.Deleted ) + return; + + if ( !m_Item.Visible ) + { + if ( m_InLOS && m_CanFit ) + m_Item.Visible = true; + else + m_Item.Delete(); + + if ( !m_Item.Deleted ) + { + m_Item.ProcessDelta(); + Effects.SendLocationParticles( EffectItem.Create( m_Item.Location, m_Item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5029 ); + } + } + else if ( DateTime.Now > m_Item.m_End ) + { + m_Item.Delete(); + Stop(); + } + else + { + Map map = m_Item.Map; + Mobile caster = m_Item.m_Caster; + + if ( map != null && caster != null ) + { + foreach ( Mobile m in m_Item.GetMobilesInRange( 0 ) ) + { + if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && (!Core.AOS || m != caster) && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) ) + m_Queue.Enqueue( m ); + } + + while ( m_Queue.Count > 0 ) + { + Mobile m = (Mobile)m_Queue.Dequeue(); + + if ( SpellHelper.CanRevealCaster( m ) ) + caster.RevealingAction(); + + caster.DoHarmful( m ); + + int damage = m_Item.m_Damage; + + if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 30.0 ) ) + { + damage = 1; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + AOS.Damage( m, caster, damage, 0, 100, 0, 0, 0 ); + m.PlaySound( 0x208 ); + + if (m is BaseCreature) + ((BaseCreature)m).OnHarmfulSpell(caster); + } + } + } + } + } + } + + private class InternalTarget : Target + { + private FireFieldSpell m_Owner; + + public InternalTarget( FireFieldSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/GreaterHeal.cs b/Scripts/Spells/Fourth/GreaterHeal.cs new file mode 100644 index 0000000..a391f23 --- /dev/null +++ b/Scripts/Spells/Fourth/GreaterHeal.cs @@ -0,0 +1,107 @@ +using System; +using Server; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; + +namespace Server.Spells.Fourth +{ + public class GreaterHealSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Greater Heal", "In Vas Mani", + 204, + 9061, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public GreaterHealSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( m is BaseCreature && ((BaseCreature)m).IsAnimatedDead ) + { + Caster.SendLocalizedMessage( 1061654 ); // You cannot heal that which is not alive. + } + else if ( m.IsDeadBondedPet ) + { + Caster.SendLocalizedMessage( 1060177 ); // You cannot heal a creature that is already dead! + } + else if ( m is Golem ) + { + Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 500951 ); // You cannot heal that. + } + else if ( m.Poisoned || Server.Items.MortalStrike.IsWounded( m ) ) + { + Caster.LocalOverheadMessage( MessageType.Regular, 0x22, (Caster == m) ? 1005000 : 1010398 ); + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + // Algorithm: (40% of magery) + (1-10) + + int toHeal = (int)(Caster.Skills[SkillName.Magery].Value * 0.4); + toHeal += Utility.Random( 1, 10 ); + + //m.Heal( toHeal, Caster ); + SpellHelper.Heal( toHeal, m, Caster ); + + m.FixedParticles( 0x376A, 9, 32, 5030, EffectLayer.Waist ); + m.PlaySound( 0x202 ); + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private GreaterHealSpell m_Owner; + + public InternalTarget( GreaterHealSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/Lightning.cs b/Scripts/Spells/Fourth/Lightning.cs new file mode 100644 index 0000000..6a4d774 --- /dev/null +++ b/Scripts/Spells/Fourth/Lightning.cs @@ -0,0 +1,91 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Fourth +{ + public class LightningSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Lightning", "Por Ort Grav", + 239, + 9021, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public LightningSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return false; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + double damage; + + if ( Core.AOS ) + { + damage = GetNewAosDamage( 23, 1, 4, m ); + } + else + { + damage = Utility.Random( 12, 9 ); + + if ( CheckResisted( m ) ) + { + damage *= 0.75; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar( m ); + } + + m.BoltEffect( 0 ); + + SpellHelper.Damage( this, m, damage, 0, 0, 0, 0, 100 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private LightningSpell m_Owner; + + public InternalTarget( LightningSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/ManaDrain.cs b/Scripts/Spells/Fourth/ManaDrain.cs new file mode 100644 index 0000000..9b77a4a --- /dev/null +++ b/Scripts/Spells/Fourth/ManaDrain.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Fourth +{ + public class ManaDrainSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mana Drain", "Ort Rel", + 215, + 9031, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + public ManaDrainSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + private static Dictionary m_Table = new Dictionary(); + + private void AosDelay_Callback( object state ) + { + object[] states = (object[])state; + + Mobile m = (Mobile)states[0]; + int mana = (int)states[1]; + + if ( m.Alive && !m.IsDeadBondedPet ) + { + m.Mana += mana; + + m.FixedEffect( 0x3779, 10, 25 ); + m.PlaySound( 0x28E ); + } + + m_Table.Remove( m ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + if ( Core.AOS ) + { + int toDrain = 40 + (int)(GetDamageSkill( Caster ) - GetResistSkill( m )); + + if ( toDrain < 0 ) + toDrain = 0; + else if ( toDrain > m.Mana ) + toDrain = m.Mana; + + if ( m_Table.ContainsKey( m ) ) + toDrain = 0; + + m.FixedParticles( 0x3789, 10, 25, 5032, EffectLayer.Head ); + m.PlaySound( 0x1F8 ); + + if ( toDrain > 0 ) + { + m.Mana -= toDrain; + + m_Table[m] = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( AosDelay_Callback ), new object[]{ m, toDrain } ); + } + } + else + { + if ( CheckResisted( m ) ) + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + else if ( m.Mana >= 100 ) + m.Mana -= Utility.Random( 1, 100 ); + else + m.Mana -= Utility.Random( 1, m.Mana ); + + m.FixedParticles( 0x374A, 10, 15, 5032, EffectLayer.Head ); + m.PlaySound( 0x1F8 ); + } + HarmfulSpell(m); + } + + FinishSequence(); + } + + public override double GetResistPercent( Mobile target ) + { + return 99.0; + } + + private class InternalTarget : Target + { + private ManaDrainSpell m_Owner; + + public InternalTarget( ManaDrainSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Fourth/Recall.cs b/Scripts/Spells/Fourth/Recall.cs new file mode 100644 index 0000000..4ab0c70 --- /dev/null +++ b/Scripts/Spells/Fourth/Recall.cs @@ -0,0 +1,208 @@ +using System; +using Server.Items; +using Server.Multis; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; +using Server.Regions; +using Server.Spells.Necromancy; + +namespace Server.Spells.Fourth +{ + public class RecallSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Recall", "Kal Ort Por", + 239, + 9031, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + + private RunebookEntry m_Entry; + private Runebook m_Book; + + public RecallSpell( Mobile caster, Item scroll ) : this( caster, scroll, null, null ) + { + } + + public RecallSpell( Mobile caster, Item scroll, RunebookEntry entry, Runebook book ) : base( caster, scroll, m_Info ) + { + m_Entry = entry; + m_Book = book; + } + + public override void GetCastSkills( out double min, out double max ) + { + if ( TransformationSpellHelper.UnderTransformation( Caster, typeof( WraithFormSpell ) ) ) + min = max = 0; + else if( Core.SE && m_Book != null ) //recall using Runebook charge + min = max = 0; + else + base.GetCastSkills( out min, out max ); + } + + public override void OnCast() + { + if ( m_Entry == null ) + Caster.Target = new InternalTarget( this ); + else + Effect( m_Entry.Location, m_Entry.Map, true ); + } + + public override bool CheckCast() + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return false; + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + return false; + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ); + } + + public void Effect( Point3D loc, Map map, bool checkMulti ) + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( map == null || (!Core.AOS && Caster.Map != map) ) + { + Caster.SendLocalizedMessage( 1005569 ); // You can not recall to another facet. + } + else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ) ) + { + } + else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.RecallTo ) ) + { + } + else if ( map == Map.Felucca && Caster is PlayerMobile && ((PlayerMobile)Caster).Young ) + { + Caster.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young. + } + // Scriptiz : PVP r�activ� sur Trammel + //else if ( Caster.Kills >= 5 && map != Map.Felucca ) + //{ + // Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + //} + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + } + else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( m_Book != null && m_Book.CurCharges <= 0 ) + { + Caster.SendLocalizedMessage( 502412 ); // There are no charges left on that item. + } + else if ( CheckSequence() ) + { + BaseCreature.TeleportPets( Caster, loc, map, true ); + + if ( m_Book != null ) + --m_Book.CurCharges; + + Caster.PlaySound( 0x1FC ); + Caster.MoveToWorld( loc, map ); + Caster.PlaySound( 0x1FC ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private RecallSpell m_Owner; + + public InternalTarget( RecallSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + + owner.Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501029 ); // Select Marked item. + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is RecallRune ) + { + RecallRune rune = (RecallRune)o; + + if ( rune.Marked ) + m_Owner.Effect( rune.Target, rune.TargetMap, true ); + else + from.SendLocalizedMessage( 501805 ); // That rune is not yet marked. + } + else if ( o is Runebook ) + { + RunebookEntry e = ((Runebook)o).Default; + + if ( e != null ) + m_Owner.Effect( e.Location, e.Map, true ); + else + from.SendLocalizedMessage( 502354 ); // Target is not marked. + } + else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat ) + { + BaseBoat boat = ((Key)o).Link as BaseBoat; + + if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) ) + m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false ); + else + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object. + } + else if (o is HouseRaffleDeed && ((HouseRaffleDeed)o).ValidLocation()) + { + HouseRaffleDeed deed = (HouseRaffleDeed)o; + + m_Owner.Effect(deed.PlotLocation, deed.PlotFacet, true); + } + else + { + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object. + } + } + + protected override void OnNonlocalTarget( Mobile from, object o ) + { + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Initializer.cs b/Scripts/Spells/Initializer.cs new file mode 100644 index 0000000..0ce60b1 --- /dev/null +++ b/Scripts/Spells/Initializer.cs @@ -0,0 +1,193 @@ +using System; +using Server; + +namespace Server.Spells +{ + public class Initializer + { + public static void Initialize() + { + // First circle + Register(00, typeof(First.ClumsySpell)); + Register(01, typeof(First.CreateFoodSpell)); + Register(02, typeof(First.FeeblemindSpell)); + Register(03, typeof(First.HealSpell)); + Register(04, typeof(First.MagicArrowSpell)); + Register(05, typeof(First.NightSightSpell)); + Register(06, typeof(First.ReactiveArmorSpell)); + Register(07, typeof(First.WeakenSpell)); + + // Second circle + Register(08, typeof(Second.AgilitySpell)); + Register(09, typeof(Second.CunningSpell)); + Register(10, typeof(Second.CureSpell)); + Register(11, typeof(Second.HarmSpell)); + Register(12, typeof(Second.MagicTrapSpell)); + Register(13, typeof(Second.RemoveTrapSpell)); + Register(14, typeof(Second.ProtectionSpell)); + Register(15, typeof(Second.StrengthSpell)); + + // Third circle + Register(16, typeof(Third.BlessSpell)); + Register(17, typeof(Third.FireballSpell)); + Register(18, typeof(Third.MagicLockSpell)); + Register(19, typeof(Third.PoisonSpell)); + Register(20, typeof(Third.TelekinesisSpell)); + Register(21, typeof(Third.TeleportSpell)); + Register(22, typeof(Third.UnlockSpell)); + Register(23, typeof(Third.WallOfStoneSpell)); + + // Fourth circle + Register(24, typeof(Fourth.ArchCureSpell)); + Register(25, typeof(Fourth.ArchProtectionSpell)); + Register(26, typeof(Fourth.CurseSpell)); + Register(27, typeof(Fourth.FireFieldSpell)); + Register(28, typeof(Fourth.GreaterHealSpell)); + Register(29, typeof(Fourth.LightningSpell)); + Register(30, typeof(Fourth.ManaDrainSpell)); + Register(31, typeof(Fourth.RecallSpell)); + + // Fifth circle + Register(32, typeof(Fifth.BladeSpiritsSpell)); + Register(33, typeof(Fifth.DispelFieldSpell)); + Register(34, typeof(Fifth.IncognitoSpell)); + Register(35, typeof(Fifth.MagicReflectSpell)); + Register(36, typeof(Fifth.MindBlastSpell)); + Register(37, typeof(Fifth.ParalyzeSpell)); + Register(38, typeof(Fifth.PoisonFieldSpell)); + Register(39, typeof(Fifth.SummonCreatureSpell)); + + // Sixth circle + Register(40, typeof(Sixth.DispelSpell)); + Register(41, typeof(Sixth.EnergyBoltSpell)); + Register(42, typeof(Sixth.ExplosionSpell)); + Register(43, typeof(Sixth.InvisibilitySpell)); + Register(44, typeof(Sixth.MarkSpell)); + Register(45, typeof(Sixth.MassCurseSpell)); + Register(46, typeof(Sixth.ParalyzeFieldSpell)); + Register(47, typeof(Sixth.RevealSpell)); + + // Seventh circle + Register(48, typeof(Seventh.ChainLightningSpell)); + Register(49, typeof(Seventh.EnergyFieldSpell)); + Register(50, typeof(Seventh.FlameStrikeSpell)); + Register(51, typeof(Seventh.GateTravelSpell)); + Register(52, typeof(Seventh.ManaVampireSpell)); + Register(53, typeof(Seventh.MassDispelSpell)); + Register(54, typeof(Seventh.MeteorSwarmSpell)); + Register(55, typeof(Seventh.PolymorphSpell)); + + // Eighth circle + Register(56, typeof(Eighth.EarthquakeSpell)); + Register(57, typeof(Eighth.EnergyVortexSpell)); + Register(58, typeof(Eighth.ResurrectionSpell)); + Register(59, typeof(Eighth.AirElementalSpell)); + Register(60, typeof(Eighth.SummonDaemonSpell)); + Register(61, typeof(Eighth.EarthElementalSpell)); + Register(62, typeof(Eighth.FireElementalSpell)); + Register(63, typeof(Eighth.WaterElementalSpell)); + + if (Core.AOS) + { + // Necromancy spells + Register(100, typeof(Necromancy.AnimateDeadSpell)); + Register(101, typeof(Necromancy.BloodOathSpell)); + Register(102, typeof(Necromancy.CorpseSkinSpell)); + Register(103, typeof(Necromancy.CurseWeaponSpell)); + Register(104, typeof(Necromancy.EvilOmenSpell)); + Register(105, typeof(Necromancy.HorrificBeastSpell)); + Register(106, typeof(Necromancy.LichFormSpell)); + Register(107, typeof(Necromancy.MindRotSpell)); + Register(108, typeof(Necromancy.PainSpikeSpell)); + Register(109, typeof(Necromancy.PoisonStrikeSpell)); + Register(110, typeof(Necromancy.StrangleSpell)); + Register(111, typeof(Necromancy.SummonFamiliarSpell)); + Register(112, typeof(Necromancy.VampiricEmbraceSpell)); + Register(113, typeof(Necromancy.VengefulSpiritSpell)); + Register(114, typeof(Necromancy.WitherSpell)); + Register(115, typeof(Necromancy.WraithFormSpell)); + + if (Core.SE) + Register(116, typeof(Necromancy.ExorcismSpell)); + + // Paladin abilities + Register(200, typeof(Chivalry.CleanseByFireSpell)); + Register(201, typeof(Chivalry.CloseWoundsSpell)); + Register(202, typeof(Chivalry.ConsecrateWeaponSpell)); + Register(203, typeof(Chivalry.DispelEvilSpell)); + Register(204, typeof(Chivalry.DivineFurySpell)); + Register(205, typeof(Chivalry.EnemyOfOneSpell)); + Register(206, typeof(Chivalry.HolyLightSpell)); + Register(207, typeof(Chivalry.NobleSacrificeSpell)); + Register(208, typeof(Chivalry.RemoveCurseSpell)); + Register(209, typeof(Chivalry.SacredJourneySpell)); + + // Druid Spells + Register(301, typeof(Druid.ShieldOfEarthSpell)); + Register(302, typeof(Druid.HollowReedSpell)); + Register(303, typeof(Druid.PackOfBeastSpell)); + Register(304, typeof(Druid.SpringOfLifeSpell)); + Register(305, typeof(Druid.GraspingRootsSpell)); + Register(306, typeof(Druid.BlendWithForestSpell)); + Register(307, typeof(Druid.SwarmOfInsectsSpell)); + Register(308, typeof(Druid.VolcanicEruptionSpell)); + Register(309, typeof(Druid.TreefellowSpell)); + Register(310, typeof(Druid.StoneCircleSpell)); + + if (Core.SE) + { + // Samurai abilities + Register(400, typeof(Bushido.HonorableExecution)); + Register(401, typeof(Bushido.Confidence)); + Register(402, typeof(Bushido.Evasion)); + Register(403, typeof(Bushido.CounterAttack)); + Register(404, typeof(Bushido.LightningStrike)); + Register(405, typeof(Bushido.MomentumStrike)); + + // Ninja abilities + Register(500, typeof(Ninjitsu.FocusAttack)); + Register(501, typeof(Ninjitsu.DeathStrike)); + Register(502, typeof(Ninjitsu.AnimalForm)); + Register(503, typeof(Ninjitsu.KiAttack)); + Register(504, typeof(Ninjitsu.SurpriseAttack)); + Register(505, typeof(Ninjitsu.Backstab)); + Register(506, typeof(Ninjitsu.Shadowjump)); + Register(507, typeof(Ninjitsu.MirrorImage)); + } + + if (Core.ML) + { + Register(600, typeof(Spellweaving.ArcaneCircleSpell)); + Register(601, typeof(Spellweaving.GiftOfRenewalSpell)); + Register( 602, typeof( Spellweaving.ImmolatingWeaponSpell ) ); + Register(603, typeof(Spellweaving.AttuneWeaponSpell)); + Register(604, typeof(Spellweaving.ThunderstormSpell)); + Register(605, typeof(Spellweaving.NatureFurySpell)); + Register(606, typeof(Spellweaving.SummonFeySpell)); + Register(607, typeof(Spellweaving.SummonFiendSpell)); + Register(608, typeof(Spellweaving.ReaperFormSpell)); + //Register( 609, typeof( Spellweaving.WildfireSpell ) ); + Register(610, typeof(Spellweaving.EssenceOfWindSpell)); + //Register( 611, typeof( Spellweaving.DryadAllureSpell ) ); + Register(612, typeof(Spellweaving.EtherealVoyageSpell)); + Register(613, typeof(Spellweaving.WordOfDeathSpell)); + Register(614, typeof(Spellweaving.GiftOfLifeSpell)); + //Register( 615, typeof( Spellweaving.ArcaneEmpowermentSpell ) ); + } + + // Scriptiz : sorts de n�cro de vivre (TODO : ajouter dans le spellbook.GetTypeForSpell (ligne 130) + Register(700, typeof(VivreNecromancy.SummonUndead)); + Register(701, typeof(VivreNecromancy.AnimateCorpse)); + Register(702, typeof(VivreNecromancy.BoneArmor)); + Register(703, typeof(VivreNecromancy.AbyssLight)); + Register(704, typeof(VivreNecromancy.AbyssFire)); + Register(705, typeof(VivreNecromancy.MinorLifeLeech)); + } + } + + public static void Register(int spellID, Type type) + { + SpellRegistry.Register(spellID, type); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/AnimateDeadSpell.cs b/Scripts/Spells/Necromancy/AnimateDeadSpell.cs new file mode 100644 index 0000000..12005fb --- /dev/null +++ b/Scripts/Spells/Necromancy/AnimateDeadSpell.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; +using Server.Engines.Quests; +using Server.Engines.Quests.Necro; + +namespace Server.Spells.Necromancy +{ + public class AnimateDeadSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Animate Dead", "Uus Corp", + 203, + 9031, + Reagent.GraveDust, + Reagent.DaemonBlood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 40.0; } } + public override int RequiredMana{ get{ return 23; } } + + public AnimateDeadSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + Caster.SendLocalizedMessage( 1061083 ); // Animate what corpse? + } + + private class CreatureGroup + { + public Type[] m_Types; + public SummonEntry[] m_Entries; + + public CreatureGroup( Type[] types, SummonEntry[] entries ) + { + m_Types = types; + m_Entries = entries; + } + } + + private class SummonEntry + { + public Type[] m_ToSummon; + public int m_Requirement; + + public SummonEntry( int requirement, params Type[] toSummon ) + { + m_ToSummon = toSummon; + m_Requirement = requirement; + } + } + + private static CreatureGroup FindGroup( Type type ) + { + for ( int i = 0; i < m_Groups.Length; ++i ) + { + CreatureGroup group = m_Groups[i]; + Type[] types = group.m_Types; + + bool contains = ( types.Length == 0 ); + + for ( int j = 0; !contains && j < types.Length; ++j ) + contains = types[j].IsAssignableFrom(type); + + if ( contains ) + return group; + } + + return null; + } + + private static CreatureGroup[] m_Groups = new CreatureGroup[] + { + // Undead group--empty + new CreatureGroup( SlayerGroup.GetEntryByName( SlayerName.Silver ).Types, new SummonEntry[0] ), + // Insects + new CreatureGroup( new Type[] + { + typeof( DreadSpider ), typeof( FrostSpider ), typeof( GiantSpider ), typeof( GiantBlackWidow ), + typeof( BlackSolenInfiltratorQueen ), typeof( BlackSolenInfiltratorWarrior ), + typeof( BlackSolenQueen ), typeof( BlackSolenWarrior ), typeof( BlackSolenWorker ), + typeof( RedSolenInfiltratorQueen ), typeof( RedSolenInfiltratorWarrior ), + typeof( RedSolenQueen ), typeof( RedSolenWarrior ), typeof( RedSolenWorker ), + typeof( TerathanAvenger ), typeof( TerathanDrone ), typeof( TerathanMatriarch ), + typeof( TerathanWarrior ) + // TODO: Giant beetle? Ant lion? Ophidians? + }, + new SummonEntry[] + { + new SummonEntry( 0, typeof( MoundOfMaggots ) ) + } ), + // Mounts + new CreatureGroup( new Type[] + { + typeof( Horse ), typeof( Nightmare ), typeof( FireSteed ), + typeof( Kirin ), typeof( Unicorn ) + }, new SummonEntry[] + { + new SummonEntry( 10000, typeof( HellSteed ) ), + new SummonEntry( 0, typeof( SkeletalMount ) ) + } ), + // Elementals + new CreatureGroup( new Type[] + { + typeof( BloodElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ), + typeof( AgapiteElemental ), typeof( BronzeElemental ), typeof( CopperElemental ), + typeof( DullCopperElemental ), typeof( GoldenElemental ), typeof( ShadowIronElemental ), + typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( PoisonElemental ), + typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( SnowElemental ), + typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( WaterElemental ), + typeof( SummonedAirElemental ), typeof ( AcidElemental ) + }, new SummonEntry[] + { + new SummonEntry( 5000, typeof( WailingBanshee ) ), + new SummonEntry( 0, typeof( Wraith ) ) + } ), + // Dragons + new CreatureGroup( new Type[] + { + typeof( AncientWyrm ), typeof( Dragon ), typeof( GreaterDragon ), typeof( SerpentineDragon ), + typeof( ShadowWyrm ), typeof( SkeletalDragon ), typeof( WhiteWyrm ), + typeof( Drake ), typeof( Wyvern ), typeof( LesserHiryu ), typeof( Hiryu ) + }, new SummonEntry[] + { + new SummonEntry( 18000, typeof( SkeletalDragon ) ), + new SummonEntry( 10000, typeof( FleshGolem ) ), + new SummonEntry( 5000, typeof( Lich ) ), + new SummonEntry( 3000, typeof( SkeletalKnight ), typeof( BoneKnight ) ), + new SummonEntry( 2000, typeof( Mummy ) ), + new SummonEntry( 1000, typeof( SkeletalMage ), typeof( BoneMagi ) ), + new SummonEntry( 0, typeof( PatchworkSkeleton ) ) + } ), + // Default group + new CreatureGroup( new Type[0], new SummonEntry[] + { + new SummonEntry( 18000, typeof( LichLord ) ), + new SummonEntry( 10000, typeof( FleshGolem ) ), + new SummonEntry( 5000, typeof( Lich ) ), + new SummonEntry( 3000, typeof( SkeletalKnight ), typeof( BoneKnight ) ), + new SummonEntry( 2000, typeof( Mummy ) ), + new SummonEntry( 1000, typeof( SkeletalMage ), typeof( BoneMagi ) ), + new SummonEntry( 0, typeof( PatchworkSkeleton ) ) + } ), + }; + + public void Target( object obj ) + { + MaabusCoffinComponent comp = obj as MaabusCoffinComponent; + + if ( comp != null ) + { + MaabusCoffin addon = comp.Addon as MaabusCoffin; + + if ( addon != null ) + { + PlayerMobile pm = Caster as PlayerMobile; + + if ( pm != null ) + { + QuestSystem qs = pm.Quest; + + if ( qs is DarkTidesQuest ) + { + QuestObjective objective = qs.FindObjective( typeof( AnimateMaabusCorpseObjective ) ); + + if ( objective != null && !objective.Completed ) + { + addon.Awake( Caster ); + objective.Complete(); + } + } + } + + return; + } + } + + Corpse c = obj as Corpse; + + if ( c == null ) + { + Caster.SendLocalizedMessage( 1061084 ); // You cannot animate that. + } + else + { + Type type = null; + + if (c.Owner != null) + { + type = c.Owner.GetType(); + } + if (c.ItemID != 0x2006 || c.Animated || type == typeof(PlayerMobile) || type == null || (c.Owner != null && c.Owner.Fame < 100) || ((c.Owner != null) && (c.Owner is BaseCreature) && (((BaseCreature)c.Owner).Summoned || ((BaseCreature)c.Owner).IsBonded))) + { + Caster.SendLocalizedMessage(1061085); // There's not enough life force there to animate. + } + else + { + CreatureGroup group = FindGroup(type); + + if (group != null) + { + if (group.m_Entries.Length == 0 || type == typeof(DemonKnight)) + { + Caster.SendLocalizedMessage(1061086); // You cannot animate undead remains. + } + else if (CheckSequence()) + { + Point3D p = c.GetWorldLocation(); + Map map = c.Map; + + if (map != null) + { + Effects.PlaySound(p, map, 0x1FB); + Effects.SendLocationParticles(EffectItem.Create(p, map, EffectItem.DefaultDuration), 0x3789, 1, 40, 0x3F, 3, 9907, 0); + + Timer.DelayCall(TimeSpan.FromSeconds(2.0), new TimerStateCallback(SummonDelay_Callback), new object[] { Caster, c, p, map, group }); + } + } + } + } + } + + FinishSequence(); + } + + private static Dictionary> m_Table = new Dictionary>(); + + public static void Unregister( Mobile master, Mobile summoned ) + { + if ( master == null ) + return; + + List list = null; + m_Table.TryGetValue( master, out list ); + + if ( list == null ) + return; + + list.Remove( summoned ); + + if ( list.Count == 0 ) + m_Table.Remove( master ); + } + + public static void Register( Mobile master, Mobile summoned ) + { + if ( master == null ) + return; + + List list = null; + m_Table.TryGetValue( master, out list ); + + if ( list == null ) + m_Table[master] = list = new List(); + + for ( int i = list.Count - 1; i >= 0; --i ) + { + if ( i >= list.Count ) + continue; + + Mobile mob = list[i]; + + if ( mob.Deleted ) + list.RemoveAt( i-- ); + } + + list.Add( summoned ); + + if ( list.Count > 3 ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( list[0].Kill ) ); + + Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( Summoned_Damage ), summoned ); + } + + private static void Summoned_Damage( object state ) + { + Mobile mob = (Mobile)state; + + if ( mob.Hits > 0 ) + --mob.Hits; + else + mob.Kill(); + } + + private static void SummonDelay_Callback( object state ) + { + object[] states = (object[])state; + + Mobile caster = (Mobile)states[0]; + Corpse corpse = (Corpse)states[1]; + Point3D loc = (Point3D)states[2]; + Map map = (Map)states[3]; + CreatureGroup group = (CreatureGroup)states[4]; + + if (corpse.Animated) + return; + + Mobile owner = corpse.Owner; + + if ( owner == null ) + return; + + double necromancy = caster.Skills[SkillName.Necromancy].Value; + double spiritSpeak = caster.Skills[SkillName.SpiritSpeak].Value; + + int casterAbility = 0; + + casterAbility += (int)(necromancy * 30); + casterAbility += (int)(spiritSpeak * 70); + casterAbility /= 10; + casterAbility *= 18; + + if ( casterAbility > owner.Fame ) + casterAbility = owner.Fame; + + if ( casterAbility < 0 ) + casterAbility = 0; + + Type toSummon = null; + SummonEntry[] entries = group.m_Entries; + + for ( int i = 0; toSummon == null && i < entries.Length; ++i ) + { + SummonEntry entry = entries[i]; + + if ( casterAbility < entry.m_Requirement ) + continue; + + Type[] animates = entry.m_ToSummon; + + if ( animates.Length >= 0 ) + toSummon = animates[Utility.Random( animates.Length )]; + } + + if ( toSummon == null ) + return; + + Mobile summoned = null; + + try{ summoned = Activator.CreateInstance( toSummon ) as Mobile; } + catch{} + + if ( summoned == null ) + return; + + if ( summoned is BaseCreature ) + { + BaseCreature bc = (BaseCreature)summoned; + + // to be sure + bc.Tamable = false; + + if ( bc is BaseMount ) + bc.ControlSlots = 1; + else + bc.ControlSlots = 0; + + Effects.PlaySound( loc, map, bc.GetAngerSound() ); + + BaseCreature.Summon( (BaseCreature)summoned, false, caster, loc, 0x28, TimeSpan.FromDays( 1.0 ) ); + } + + if ( summoned is SkeletalDragon ) + Scale( (SkeletalDragon)summoned, 50 ); // lose 50% hp and strength + + summoned.Fame = 0; + summoned.Karma = -1500; + + summoned.MoveToWorld( loc, map ); + + corpse.Hue = 1109; + corpse.Animated = true; + + Register( caster, summoned ); + } + + public static void Scale( BaseCreature bc, int scalar ) + { + int toScale; + + toScale = bc.RawStr; + bc.RawStr = AOS.Scale( toScale, scalar ); + + toScale = bc.HitsMaxSeed; + + if ( toScale > 0 ) + bc.HitsMaxSeed = AOS.Scale( toScale, scalar ); + + bc.Hits = bc.Hits; // refresh hits + } + + private class InternalTarget : Target + { + private AnimateDeadSpell m_Owner; + + public InternalTarget( AnimateDeadSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + m_Owner.Target( o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/BloodOathSpell.cs b/Scripts/Spells/Necromancy/BloodOathSpell.cs new file mode 100644 index 0000000..4a896f1 --- /dev/null +++ b/Scripts/Spells/Necromancy/BloodOathSpell.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class BloodOathSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Blood Oath", "In Jux Mani Xen", + 203, + 9031, + Reagent.DaemonBlood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 20.0; } } + public override int RequiredMana{ get{ return 13; } } + + public BloodOathSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( Caster == m || !(m is PlayerMobile || m is BaseCreature) ) // only PlayerMobile and BaseCreature implement blood oath checking + { + Caster.SendLocalizedMessage( 1060508 ); // You can't curse that. + } + else if ( m_OathTable.Contains( Caster ) ) + { + Caster.SendLocalizedMessage( 1061607 ); // You are already bonded in a Blood Oath. + } + else if ( m_OathTable.Contains( m ) ) + { + if ( m.Player ) + Caster.SendLocalizedMessage( 1061608 ); // That player is already bonded in a Blood Oath. + else + Caster.SendLocalizedMessage( 1061609 ); // That creature is already bonded in a Blood Oath. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Temporarily creates a dark pact between the caster and the target. + * Any damage dealt by the target to the caster is increased, but the target receives the same amount of damage. + * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 80 ) + 8 seconds. + * + * NOTE: The above algorithm must be fixed point, it should be: + * ((ss-rm)/8)+8 + */ + + ExpireTimer timer = (ExpireTimer)m_Table[m]; + if ( timer != null ) + timer.DoExpire(); + + m_OathTable[Caster] = Caster; + m_OathTable[m] = Caster; + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + Caster.PlaySound( 0x175 ); + + Caster.FixedParticles( 0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist ); + Caster.FixedParticles( 0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255 ); + + m.FixedParticles( 0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist ); + m.FixedParticles( 0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255 ); + + TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 8) + 8 ); + m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain + + timer = new ExpireTimer ( Caster, m, duration ); + timer.Start (); + + BuffInfo.AddBuff ( Caster, new BuffInfo ( BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name.ToString () ) ); + BuffInfo.AddBuff ( m, new BuffInfo ( BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name.ToString () ) ); + + m_Table[m] = timer; + HarmfulSpell(m); + } + + FinishSequence(); + } + + public static bool RemoveCurse( Mobile m ) + { + ExpireTimer t = (ExpireTimer)m_Table[m]; + + if ( t == null ) + return false; + + t.DoExpire(); + return true; + } + + private static Hashtable m_OathTable = new Hashtable(); + private static Hashtable m_Table = new Hashtable (); + + public static Mobile GetBloodOath( Mobile m ) + { + if ( m == null ) + return null; + + Mobile oath = (Mobile)m_OathTable[m]; + + if ( oath == m ) + oath = null; + + return oath; + } + + private class ExpireTimer : Timer + { + private Mobile m_Caster; + private Mobile m_Target; + private DateTime m_End; + + public ExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Caster = caster; + m_Target = target; + m_End = DateTime.Now + delay; + + Priority = TimerPriority.TwoFiftyMS; + } + + protected override void OnTick() + { + if ( m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || DateTime.Now >= m_End ) + { + DoExpire (); + } + } + public void DoExpire() + { + if( m_OathTable.Contains( m_Caster ) ) + { + m_Caster.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken. + m_OathTable.Remove ( m_Caster ); + } + + if( m_OathTable.Contains( m_Target ) ) + { + m_Target.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken. + m_OathTable.Remove ( m_Target ); + } + + Stop (); + + BuffInfo.RemoveBuff ( m_Caster, BuffIcon.BloodOathCaster ); + BuffInfo.RemoveBuff ( m_Target, BuffIcon.BloodOathCurse ); + + m_Table.Remove ( m_Caster ); + } + } + + private class InternalTarget : Target + { + private BloodOathSpell m_Owner; + + public InternalTarget( BloodOathSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + else + from.SendLocalizedMessage( 1060508 ); // You can't curse that. + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/CorpseSkin.cs b/Scripts/Spells/Necromancy/CorpseSkin.cs new file mode 100644 index 0000000..852fc27 --- /dev/null +++ b/Scripts/Spells/Necromancy/CorpseSkin.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class CorpseSkinSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Corpse Skin", "In Agle Corp Ylem", + 203, + 9051, + Reagent.BatWing, + Reagent.GraveDust + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 20.0; } } + public override int RequiredMana{ get{ return 11; } } + + public CorpseSkinSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Transmogrifies the flesh of the target creature or player to resemble rotted corpse flesh, + * making them more vulnerable to Fire and Poison damage, + * but increasing their resistance to Physical and Cold damage. + * + * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 25 ) + 40 seconds. + * + * NOTE: Algorithm above is fixed point, should be: + * ((ss-mr)/2.5) + 40 + * + * NOTE: Resistance is not checked if targeting yourself + */ + + ExpireTimer timer = (ExpireTimer)m_Table[m]; + + if ( timer != null ) + timer.DoExpire(); + else + m.SendLocalizedMessage( 1061689 ); // Your skin turns dry and corpselike. + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.FixedParticles( 0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head ); + m.PlaySound( 0x1BB ); + + double ss = GetDamageSkill( Caster ); + double mr = ( Caster == m ? 0.0 : GetResistSkill( m ) ); + m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain + + TimeSpan duration = TimeSpan.FromSeconds( ((ss - mr) / 2.5) + 40.0 ); + + ResistanceMod[] mods = new ResistanceMod[4] + { + new ResistanceMod( ResistanceType.Fire, -15 ), + new ResistanceMod( ResistanceType.Poison, -15 ), + new ResistanceMod( ResistanceType.Cold, +10 ), + new ResistanceMod( ResistanceType.Physical, +10 ) + }; + + timer = new ExpireTimer( m, mods, duration ); + timer.Start(); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.CorpseSkin, 1075663, duration, m ) ); + + m_Table[m] = timer; + + for ( int i = 0; i < mods.Length; ++i ) + m.AddResistanceMod( mods[i] ); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool RemoveCurse( Mobile m ) + { + ExpireTimer t = (ExpireTimer)m_Table[m]; + + if ( t == null ) + return false; + + m.SendLocalizedMessage( 1061688 ); // Your skin returns to normal. + t.DoExpire(); + return true; + } + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + private ResistanceMod[] m_Mods; + + public ExpireTimer( Mobile m, ResistanceMod[] mods, TimeSpan delay ) : base( delay ) + { + m_Mobile = m; + m_Mods = mods; + } + + public void DoExpire() + { + for ( int i = 0; i < m_Mods.Length; ++i ) + m_Mobile.RemoveResistanceMod( m_Mods[i] ); + + Stop(); + BuffInfo.RemoveBuff( m_Mobile, BuffIcon.CorpseSkin ); + m_Table.Remove( m_Mobile ); + } + + protected override void OnTick() + { + m_Mobile.SendLocalizedMessage( 1061688 ); // Your skin returns to normal. + DoExpire(); + } + } + + private class InternalTarget : Target + { + private CorpseSkinSpell m_Owner; + + public InternalTarget( CorpseSkinSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/CurseWeapon.cs b/Scripts/Spells/Necromancy/CurseWeapon.cs new file mode 100644 index 0000000..f2e7e08 --- /dev/null +++ b/Scripts/Spells/Necromancy/CurseWeapon.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class CurseWeaponSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Curse Weapon", "An Sanct Gra Char", + 203, + 9031, + Reagent.PigIron + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.75 ); } } + + public override double RequiredSkill{ get{ return 0.0; } } + public override int RequiredMana{ get{ return 7; } } + + public CurseWeaponSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + BaseWeapon weapon = Caster.Weapon as BaseWeapon; + + if ( weapon == null || weapon is Fists ) + { + Caster.SendLocalizedMessage( 501078 ); // You must be holding a weapon. + } + else if ( CheckSequence() ) + { + /* Temporarily imbues a weapon with a life draining effect. + * Half the damage that the weapon inflicts is added to the necromancer's health. + * The effects lasts for (Spirit Speak skill level / 34) + 1 seconds. + * + * NOTE: Above algorithm is fixed point, should be : + * (Spirit Speak skill level / 3.4) + 1 + * + * TODO: What happens if you curse a weapon then give it to someone else? Should they get the drain effect? + */ + + Caster.PlaySound( 0x387 ); + Caster.FixedParticles( 0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head ); + Caster.FixedParticles( 0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255 ); + new SoundEffectTimer( Caster ).Start(); + + // Scriptiz : le karma n�gatif augmente la dur�e du sort + TimeSpan duration = TimeSpan.FromSeconds((Caster.Skills[SkillName.SpiritSpeak].Value / 3.4) + 1.0 - (Caster.Karma / 1000.0)); + + Timer t = (Timer)m_Table[weapon]; + + if ( t != null ) + t.Stop(); + + weapon.Cursed = true; + + m_Table[weapon] = t = new ExpireTimer( weapon, duration ); + + t.Start(); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + private class ExpireTimer : Timer + { + private BaseWeapon m_Weapon; + + public ExpireTimer( BaseWeapon weapon, TimeSpan delay ) : base( delay ) + { + m_Weapon = weapon; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + m_Weapon.Cursed = false; + Effects.PlaySound( m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA ); + m_Table.Remove( this ); + } + } + + private class SoundEffectTimer : Timer + { + private Mobile m_Mobile; + + public SoundEffectTimer( Mobile m ) : base( TimeSpan.FromSeconds( 0.75 ) ) + { + m_Mobile = m; + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + m_Mobile.PlaySound( 0xFA ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/EvilOmen.cs b/Scripts/Spells/Necromancy/EvilOmen.cs new file mode 100644 index 0000000..1ef5f13 --- /dev/null +++ b/Scripts/Spells/Necromancy/EvilOmen.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class EvilOmenSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Evil Omen", "Pas Tym An Sanct", + 203, + 9031, + Reagent.BatWing, + Reagent.NoxCrystal + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(0.75); } } + + public override double RequiredSkill { get { return 20.0; } } + public override int RequiredMana { get { return 11; } } + + public EvilOmenSpell(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget(this); + } + + public void Target(Mobile m) + { + if (!(m is BaseCreature || m is PlayerMobile)) + { + Caster.SendLocalizedMessage(1060508); // You can't curse that. + } + else if (CheckHSequence(m)) + { + SpellHelper.Turn(Caster, m); + + /* Curses the target so that the next harmful event that affects them is magnified. + * Damage to the target's hit points is increased 25%, + * the poison level of the attack will be 1 higher + * and the Resist Magic skill of the target will be fixed on 50. + * + * The effect lasts for one harmful event only. + */ + + if (m.Spell != null) + m.Spell.OnCasterHurt(); + + m.PlaySound(0xFC); + m.FixedParticles(0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head); + m.FixedParticles(0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head); + + if (!m_Table.Contains(m)) + { + SkillMod mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0); + + if (m.Skills[SkillName.MagicResist].Base > 50.0) + m.AddSkillMod(mod); + + m_Table[m] = mod; + } + + TimeSpan duration = TimeSpan.FromSeconds((Caster.Skills[SkillName.SpiritSpeak].Value / 12) + 1.0); + + Timer.DelayCall(duration, new TimerStateCallback(EffectExpire_Callback), m); + + HarmfulSpell(m); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EvilOmen, 1075647, 1075648, duration, m)); + + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + private static void EffectExpire_Callback(object state) + { + TryEndEffect((Mobile)state); + } + + /* + * The naming here was confusing. Its a 1-off effect spell. + * So, we dont actually "checkeffect"; we endeffect with bool + * return to determine external behaviors. + * + * -refactored. + */ + + public static bool TryEndEffect(Mobile m) + { + SkillMod mod = (SkillMod)m_Table[m]; + + if (mod == null) + return false; + + m_Table.Remove(m); + mod.Remove(); + + return true; + } + + private class InternalTarget : Target + { + private EvilOmenSpell m_Owner; + + public InternalTarget(EvilOmenSpell owner) + : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful) + { + m_Owner = owner; + } + + protected override void OnTarget(Mobile from, object o) + { + if (o is Mobile) + m_Owner.Target((Mobile)o); + else + from.SendLocalizedMessage(1060508); // You can't curse that. + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/Exorcism.cs b/Scripts/Spells/Necromancy/Exorcism.cs new file mode 100644 index 0000000..a7b4c57 --- /dev/null +++ b/Scripts/Spells/Necromancy/Exorcism.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Engines.CannedEvil; +using Server.Guilds; +using Server.Factions; +using Server.Engines.PartySystem; +using Server.Regions; + +namespace Server.Spells.Necromancy +{ + public class ExorcismSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Exorcism", "Ort Corp Grav", + 203, + 9031, + Reagent.NoxCrystal, + Reagent.GraveDust + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill { get { return 80.0; } } + public override int RequiredMana { get { return 40; } } + + public ExorcismSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if( Caster.Skills.SpiritSpeak.Value < 100.0 ) + { + Caster.SendLocalizedMessage( 1072112 ); // You must have GM Spirit Speak to use this spell + return false; + } + + return base.CheckCast(); + } + + + public override bool DelayedDamage { get { return false; } } + + private static readonly int Range = (Core.ML ? 48 : 18); + + public override int ComputeKarmaAward() + { + return 0; //no karma lost from this spell! + } + + public override void OnCast() + { + ChampionSpawnRegion r = Caster.Region.GetRegion( typeof( ChampionSpawnRegion ) ) as ChampionSpawnRegion; + + if( r == null || !Caster.InRange( r.ChampionSpawn, Range ) ) + { + Caster.SendLocalizedMessage( 1072111 ); // You are not in a valid exorcism region. + } + else if( CheckSequence() ) + { + Map map = Caster.Map; + + if( map != null ) + { + List targets = new List(); + + foreach( Mobile m in r.ChampionSpawn.GetMobilesInRange( Range ) ) + if( IsValidTarget( m ) ) + targets.Add( m ); + + for( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + //Suprisingly, no sparkle type effects + + m.Location = GetNearestShrine( m ); + } + } + } + + FinishSequence(); + } + + private bool IsValidTarget( Mobile m ) + { + if( !m.Player || m.Alive ) + return false; + + Corpse c = m.Corpse as Corpse; + Map map = m.Map; + + if( c != null && !c.Deleted && map != null && c.Map == map ) + { + if( SpellHelper.IsAnyT2A( map, c.Location ) && SpellHelper.IsAnyT2A( map, m.Location ) ) + return false; //Same Map, both in T2A, ie, same 'sub server'. + + if( m.Region.IsPartOf( typeof( DungeonRegion ) ) == Region.Find( c.Location, map ).IsPartOf( typeof( DungeonRegion ) ) ) + return false; //Same Map, both in Dungeon region OR They're both NOT in a dungeon region. + + //Just an approximation cause RunUO doens't divide up the world the same way OSI does ;p + + } + + Party p = Party.Get( m ); + + if( p != null && p.Contains( Caster ) ) + return false; + + if( m.Guild != null && Caster.Guild != null ) + { + Guild mGuild = m.Guild as Guild; + Guild cGuild = Caster.Guild as Guild; + + if( mGuild.IsAlly( cGuild ) ) + return false; + + if( mGuild == cGuild ) + return false; + } + + Faction f = Faction.Find( m ); + + if( Faction.Facet == m.Map && f != null && f == Faction.Find( Caster ) ) + return false; + + return true; + } + + private static Point3D GetNearestShrine( Mobile m ) + { + Map map = m.Map; + + Point3D[] locList; + + + if( map == Map.Felucca || map == Map.Trammel ) + locList = m_BritanniaLocs; + else if( map == Map.Ilshenar ) + locList = m_IllshLocs; + else if( map == Map.Tokuno ) + locList = m_TokunoLocs; + else if( map == Map.Malas ) + locList = m_MalasLocs; + else + locList = new Point3D[0]; + + Point3D closest = Point3D.Zero; + double minDist = double.MaxValue; + + for( int i = 0; i < locList.Length; i++ ) + { + Point3D p = locList[i]; + + double dist = m.GetDistanceToSqrt( p ); + if( minDist > dist ) + { + closest = p; + minDist = dist; + } + } + + return closest; + } + + private static readonly Point3D[] m_BritanniaLocs = new Point3D[] + { + new Point3D( 1470, 843, 0 ), + new Point3D( 1857, 865, -1 ), + new Point3D( 4220, 563, 36 ), + new Point3D( 1732, 3528, 0 ), + new Point3D( 1300, 644, 8 ), + new Point3D( 3355, 302, 9 ), + new Point3D( 1606, 2490, 5 ), + new Point3D( 2500, 3931, 3 ), + new Point3D( 4264, 3707, 0 ) + }; + private static readonly Point3D[] m_IllshLocs = new Point3D[] + { + new Point3D( 1222, 474, -17 ), + new Point3D( 718, 1360, -60), + new Point3D( 297, 1014, -19 ), + new Point3D( 986, 1006, -36 ), + new Point3D( 1180, 1288, -30 ), + new Point3D( 1538, 1341, -3 ), + new Point3D( 528, 223, -38 ) + }; + private static readonly Point3D[] m_MalasLocs = new Point3D[] + { + new Point3D ( 976, 517, -30 ) + }; + private static readonly Point3D[] m_TokunoLocs = new Point3D[] + { + new Point3D( 710, 1162, 25 ), + new Point3D( 1034, 515, 18 ), + new Point3D( 295, 712, 55 ) + }; + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/HorrificBeast.cs b/Scripts/Spells/Necromancy/HorrificBeast.cs new file mode 100644 index 0000000..345eb2f --- /dev/null +++ b/Scripts/Spells/Necromancy/HorrificBeast.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class HorrificBeastSpell : TransformationSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Horrific Beast", "Rel Xen Vas Bal", + 203, + 9031, + Reagent.BatWing, + Reagent.DaemonBlood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 40.0; } } + public override int RequiredMana{ get{ return 11; } } + + public override int Body{ get{ return 746; } } + + public HorrificBeastSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void DoEffect( Mobile m ) + { + m.PlaySound( 0x165 ); + m.FixedParticles( 0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head ); + + m.Delta( MobileDelta.WeaponDamage ); + m.CheckStatTimers(); + } + + public override void RemoveEffect( Mobile m ) + { + m.Delta( MobileDelta.WeaponDamage ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/LichForm.cs b/Scripts/Spells/Necromancy/LichForm.cs new file mode 100644 index 0000000..2ace604 --- /dev/null +++ b/Scripts/Spells/Necromancy/LichForm.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class LichFormSpell : TransformationSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Lich Form", "Rel Xen Corp Ort", + 203, + 9031, + Reagent.GraveDust, + Reagent.DaemonBlood, + Reagent.NoxCrystal + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 70.0; } } + public override int RequiredMana{ get{ return 23; } } + + public override int Body{ get{ return 749; } } + + public override int FireResistOffset{ get{ return -10; } } + public override int ColdResistOffset{ get{ return +10; } } + public override int PoisResistOffset{ get{ return +10; } } + + public override double TickRate{ get{ return 2.5; } } + + public LichFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void DoEffect( Mobile m ) + { + m.PlaySound( 0x19C ); + m.FixedParticles( 0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot ); + } + + public override void OnTick( Mobile m ) + { + --m.Hits; + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/MindRot.cs b/Scripts/Spells/Necromancy/MindRot.cs new file mode 100644 index 0000000..da68a68 --- /dev/null +++ b/Scripts/Spells/Necromancy/MindRot.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class MindRotSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mind Rot", "Wis An Ben", + 203, + 9031, + Reagent.BatWing, + Reagent.PigIron, + Reagent.DaemonBlood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return 30.0; } } + public override int RequiredMana{ get{ return 17; } } + + public MindRotSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( HasMindRotScalar( m ) ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Attempts to place a curse on the Target that increases the mana cost of any spells they cast, + * for a duration based off a comparison between the Caster's Spirit Speak skill and the Target's Resisting Spells skill. + * The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 50 ) + 20 seconds. + */ + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.PlaySound( 0x1FB ); + m.PlaySound( 0x258 ); + m.FixedParticles( 0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head ); + + TimeSpan duration = TimeSpan.FromSeconds( (((GetDamageSkill( Caster ) - GetResistSkill( m )) / 5.0) + 20.0) * (m.Player ? 1.0 : 2.0 ) ); + m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain + + if ( m.Player ) + SetMindRotScalar( Caster, m, 1.25, duration ); + else + SetMindRotScalar( Caster, m, 2.00, duration ); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static void ClearMindRotScalar( Mobile m ) + { + if (!m_Table.ContainsKey(m)) + return; + + BuffInfo.RemoveBuff( m, BuffIcon.Mindrot ); + MRBucket tmpB = (MRBucket)m_Table[m]; + MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer; + tmpT.Stop(); + m_Table.Remove(m); + m.SendLocalizedMessage(1060872); // Your mind feels normal again. + } + + public static bool HasMindRotScalar( Mobile m ) + { + return m_Table.ContainsKey(m); + } + + public static bool GetMindRotScalar( Mobile m, ref double scalar ) + { + if (!m_Table.ContainsKey(m)) + return false; + + MRBucket tmpB = (MRBucket)m_Table[m]; + scalar = tmpB.m_Scalar; + return true; + } + + public static void SetMindRotScalar( Mobile caster, Mobile target, double scalar, TimeSpan duration ) + { + if (!m_Table.ContainsKey(target)) + { + m_Table.Add(target, new MRBucket(scalar, new MRExpireTimer(caster, target, duration))); + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target)); + MRBucket tmpB = (MRBucket)m_Table[target]; + MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer; + tmpT.Start(); + target.SendLocalizedMessage(1074384); + } + } + + private class InternalTarget : Target + { + private MindRotSpell m_Owner; + + public InternalTarget( MindRotSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + else + from.SendLocalizedMessage( 1060508 ); // You can't curse that. + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } + + public class MRExpireTimer : Timer + { + private Mobile m_Caster; + private Mobile m_Target; + private DateTime m_End; + + public MRExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_Caster = caster; + m_Target = target; + m_End = DateTime.Now + delay; + Priority = TimerPriority.TwoFiftyMS; + } + + public void RenewDelay(TimeSpan delay) + { + m_End = DateTime.Now + delay; + } + + public void Halt() + { + Stop(); + } + + protected override void OnTick() + { + if ( m_Target.Deleted || !m_Target.Alive || DateTime.Now >= m_End ) + { + MindRotSpell.ClearMindRotScalar( m_Target ); + Stop(); + } + } + } + + public class MRBucket + { + public MRBucket(double theScalar, MRExpireTimer theTimer) + { + m_Scalar = theScalar; + m_MRExpireTimer = theTimer; + } + + public double m_Scalar; + public MRExpireTimer m_MRExpireTimer; + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/NecromancerSpell.cs b/Scripts/Spells/Necromancy/NecromancerSpell.cs new file mode 100644 index 0000000..237a5d4 --- /dev/null +++ b/Scripts/Spells/Necromancy/NecromancerSpell.cs @@ -0,0 +1,59 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Spells.Necromancy +{ + public abstract class NecromancerSpell : Spell + { + public abstract double RequiredSkill{ get; } + public abstract int RequiredMana{ get; } + + public override SkillName CastSkill{ get{ return SkillName.Necromancy; } } + public override SkillName DamageSkill{ get{ return SkillName.SpiritSpeak; } } + + //public override int CastDelayBase{ get{ return base.CastDelayBase; } } // Reference, 3 + + public override bool ClearHandsOnCast{ get{ return false; } } + + public override double CastDelayFastScalar{ get{ return (Core.SE? base.CastDelayFastScalar : 0); } } // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery + + public NecromancerSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public override int ComputeKarmaAward() + { + //TODO: Verify this formula being that Necro spells don't HAVE a circle. + //int karma = -(70 + (10 * (int)Circle)); + int karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick))); + + if (Core.ML) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells." + karma += AOS.Scale(karma, AosAttributes.GetValue(Caster, AosAttribute.IncreasedKarmaLoss)); + + return karma; + } + + public override void GetCastSkills( out double min, out double max ) + { + min = RequiredSkill; + max = Scroll != null ? min : RequiredSkill + 40.0; + } + + public override bool ConsumeReagents() + { + if( base.ConsumeReagents() ) + return true; + + if( ArcaneGem.ConsumeCharges( Caster, 1 ) ) + return true; + + return false; + } + + public override int GetMana() + { + return RequiredMana; + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/PainSpike.cs b/Scripts/Spells/Necromancy/PainSpike.cs new file mode 100644 index 0000000..a7dfad3 --- /dev/null +++ b/Scripts/Spells/Necromancy/PainSpike.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class PainSpikeSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Pain Spike", "In Sar", + 203, + 9031, + Reagent.GraveDust, + Reagent.PigIron + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override double RequiredSkill{ get{ return 20.0; } } + public override int RequiredMana{ get{ return 5; } } + + public PainSpikeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return false; } } + + public void Target( Mobile m ) + { + if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + //SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent asfter AoS + + /* Temporarily causes intense physical pain to the target, dealing direct damage. + * After 10 seconds the spell wears off, and if the target is still alive, + * some of the Hit Points lost through Pain Spike are restored. + */ + + m.FixedParticles( 0x37C4, 1, 8, 9916, 39, 3, EffectLayer.Head ); + m.FixedParticles( 0x37C4, 1, 8, 9502, 39, 4, EffectLayer.Head ); + m.PlaySound( 0x210 ); + + double damage = ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 10) + (m.Player ? 18 : 30); + m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain + + if ( damage < 1 ) + damage = 1; + + TimeSpan buffTime = TimeSpan.FromSeconds( 10.0 ); + + if( m_Table.Contains( m ) ) + { + damage = Utility.RandomMinMax( 3, 7 ); + Timer t = m_Table[m] as Timer; + + if( t != null ) + { + t.Delay += TimeSpan.FromSeconds( 2.0 ); + + buffTime = t.Next - DateTime.Now; + } + } + else + { + new InternalTimer( m, damage ).Start(); + } + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString( (int)damage ) ) ); + + Misc.WeightOverloading.DFA = Misc.DFAlgorithm.PainSpike; + m.Damage( (int) damage, Caster ); + SpellHelper.DoLeech( (int)damage, Caster, m ); + Misc.WeightOverloading.DFA = Misc.DFAlgorithm.Standard; + + //SpellHelper.Damage( this, m, damage, 100, 0, 0, 0, 0, Misc.DFAlgorithm.PainSpike ); + HarmfulSpell(m); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + private int m_ToRestore; + + public InternalTimer( Mobile m, double toRestore ) : base( TimeSpan.FromSeconds( 10.0 ) ) + { + Priority = TimerPriority.OneSecond; + + m_Mobile = m; + m_ToRestore = (int)toRestore; + + m_Table[m] = this; + } + + protected override void OnTick() + { + m_Table.Remove( m_Mobile ); + + if ( m_Mobile.Alive && !m_Mobile.IsDeadBondedPet ) + m_Mobile.Hits += m_ToRestore; + + BuffInfo.RemoveBuff( m_Mobile, BuffIcon.PainSpike ); + } + } + + private class InternalTarget : Target + { + private PainSpikeSpell m_Owner; + + public InternalTarget( PainSpikeSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/PoisonStrike.cs b/Scripts/Spells/Necromancy/PoisonStrike.cs new file mode 100644 index 0000000..d2e674b --- /dev/null +++ b/Scripts/Spells/Necromancy/PoisonStrike.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class PoisonStrikeSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Poison Strike", "In Vas Nox", + 203, + 9031, + Reagent.NoxCrystal + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( (Core.ML ? 1.75 : 1.5) ); } } + + public override double RequiredSkill { get { return 50.0; } } + public override int RequiredMana { get { return 17; } } + + public PoisonStrikeSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage { get { return false; } } + + public void Target( Mobile m ) + { + if( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Creates a blast of poisonous energy centered on the target. + * The main target is inflicted with a large amount of Poison damage, and all valid targets in a radius of 2 tiles around the main target are inflicted with a lesser effect. + * One tile from main target receives 50% damage, two tiles from target receives 33% damage. + */ + + //CheckResisted( m ); // Check magic resist for skill, but do not use return value //reports from OSI: Necro spells don't give Resist gain + + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x36B0, 1, 14, 63, 7, 9915, 0 ); + Effects.PlaySound( m.Location, m.Map, 0x229 ); + + double damage = Utility.RandomMinMax( (Core.ML ? 32 : 36), 40 ) * ((300 + (GetDamageSkill( Caster ) * 9)) / 1000); + + double sdiBonus = (double)AosAttributes.GetValue( Caster, AosAttribute.SpellDamage )/100; + double pvmDamage = damage * (1 + sdiBonus); + + if ( Core.ML && sdiBonus > 0.15 ) + sdiBonus = 0.15; + double pvpDamage = damage * (1 + sdiBonus); + + Map map = m.Map; + + if( map != null ) + { + List targets = new List(); + + if ( Caster.CanBeHarmful(m, false ) ) + targets.Add( m ); + + foreach (Mobile targ in m.GetMobilesInRange(2)) + if (!(Caster is BaseCreature && targ is BaseCreature)) + if ((targ != Caster && m != targ) && (SpellHelper.ValidIndirectTarget(Caster, targ) && Caster.CanBeHarmful(targ, false))) + targets.Add(targ); + + for( int i = 0; i < targets.Count; ++i ) + { + Mobile targ = targets[i]; + + int num; + + if( targ.InRange( m.Location, 0 ) ) + num = 1; + else if( targ.InRange( m.Location, 1 ) ) + num = 2; + else + num = 3; + + Caster.DoHarmful( targ ); + SpellHelper.Damage( this, targ, ((m.Player && Caster.Player) ? pvpDamage : pvmDamage) / num, 0, 0, 0, 100, 0 ); + } + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private PoisonStrikeSpell m_Owner; + + public InternalTarget( PoisonStrikeSpell owner ) + : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/Strangle.cs b/Scripts/Spells/Necromancy/Strangle.cs new file mode 100644 index 0000000..10c330d --- /dev/null +++ b/Scripts/Spells/Necromancy/Strangle.cs @@ -0,0 +1,240 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class StrangleSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Strangle", "In Bal Nox", + 209, + 9031, + Reagent.DaemonBlood, + Reagent.NoxCrystal + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 65.0; } } + public override int RequiredMana{ get{ return 29; } } + + public StrangleSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + //SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent after AoS + + /* Temporarily chokes off the air suply of the target with poisonous fumes. + * The target is inflicted with poison damage over time. + * The amount of damage dealt each "hit" is based off of the caster's Spirit Speak skill and the Target's current Stamina. + * The less Stamina the target has, the more damage is done by Strangle. + * Duration of the effect is Spirit Speak skill level / 10 rounds, with a minimum number of 4 rounds. + * The first round of damage is dealt after 5 seconds, and every next round after that comes 1 second sooner than the one before, until there is only 1 second between rounds. + * The base damage of the effect lies between (Spirit Speak skill level / 10) - 2 and (Spirit Speak skill level / 10) + 1. + * Base damage is multiplied by the following formula: (3 - (target's current Stamina / target's maximum Stamina) * 2). + * Example: + * For a target at full Stamina the damage multiplier is 1, + * for a target at 50% Stamina the damage multiplier is 2 and + * for a target at 20% Stamina the damage multiplier is 2.6 + */ + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.PlaySound( 0x22F ); + m.FixedParticles( 0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head ); + m.FixedParticles( 0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255 ); + + if ( !m_Table.Contains( m ) ) + { + Timer t = new InternalTimer( m, Caster ); + t.Start(); + + m_Table[m] = t; + } + HarmfulSpell(m); + } + + //Calculations for the buff bar + double spiritlevel = Caster.Skills[SkillName.SpiritSpeak].Value / 10; + if (spiritlevel < 4) + spiritlevel = 4; + int d_MinDamage = 4; + int d_MaxDamage = ((int)spiritlevel + 1) * 3; + string args = String.Format("{0}\t{1}", d_MinDamage, d_MaxDamage); + + int i_Count = (int)spiritlevel; + int i_MaxCount = i_Count; + int i_HitDelay = 5; + int i_Length = i_HitDelay; + + while (i_Count > 1) + { + --i_Count; + if (i_HitDelay > 1) + { + if (i_MaxCount < 5) + { + --i_HitDelay; + } + else + { + int delay = (int)(Math.Ceiling((1.0 + (5 * i_Count)) / i_MaxCount)); + + if (delay <= 5) + i_HitDelay = delay; + else + i_HitDelay = 5; + } + } + i_Length += i_HitDelay; + } + TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length); + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args.ToString())); + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool RemoveCurse( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t == null ) + return false; + + t.Stop(); + m.SendLocalizedMessage( 1061687 ); // You can breath normally again. + + m_Table.Remove( m ); + return true; + } + + private class InternalTimer : Timer + { + private Mobile m_Target, m_From; + private double m_MinBaseDamage, m_MaxBaseDamage; + + private DateTime m_NextHit; + private int m_HitDelay; + + private int m_Count, m_MaxCount; + + public InternalTimer( Mobile target, Mobile from ) : base( TimeSpan.FromSeconds( 0.1 ), TimeSpan.FromSeconds( 0.1 ) ) + { + Priority = TimerPriority.FiftyMS; + + m_Target = target; + m_From = from; + + double spiritLevel = from.Skills[SkillName.SpiritSpeak].Value / 10; + + m_MinBaseDamage = spiritLevel - 2; + m_MaxBaseDamage = spiritLevel + 1; + + m_HitDelay = 5; + m_NextHit = DateTime.Now + TimeSpan.FromSeconds( m_HitDelay ); + + m_Count = (int)spiritLevel; + + if ( m_Count < 4 ) + m_Count = 4; + + m_MaxCount = m_Count; + } + + protected override void OnTick() + { + if ( !m_Target.Alive ) + { + m_Table.Remove( m_Target ); + Stop(); + } + + if ( !m_Target.Alive || DateTime.Now < m_NextHit ) + return; + + --m_Count; + + if ( m_HitDelay > 1 ) + { + if ( m_MaxCount < 5 ) + { + --m_HitDelay; + } + else + { + int delay = (int)(Math.Ceiling( (1.0 + (5 * m_Count)) / m_MaxCount ) ); + + if ( delay <= 5 ) + m_HitDelay = delay; + else + m_HitDelay = 5; + } + } + + if ( m_Count == 0 ) + { + m_Target.SendLocalizedMessage( 1061687 ); // You can breath normally again. + m_Table.Remove( m_Target ); + Stop(); + } + else + { + m_NextHit = DateTime.Now + TimeSpan.FromSeconds( m_HitDelay ); + + double damage = m_MinBaseDamage + (Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage)); + + damage *= (3 - (((double)m_Target.Stam / m_Target.StamMax) * 2)); + + if ( damage < 1 ) + damage = 1; + + if ( !m_Target.Player ) + damage *= 1.75; + + AOS.Damage( m_Target, m_From, (int)damage, 0, 0, 0, 100, 0 ); + + if (0.60 <= Utility.RandomDouble()) // OSI: randomly revealed between first and third damage tick, guessing 60% chance + m_Target.RevealingAction(); + } + } + } + + private class InternalTarget : Target + { + private StrangleSpell m_Owner; + + public InternalTarget( StrangleSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/SummonFamiliar.cs b/Scripts/Spells/Necromancy/SummonFamiliar.cs new file mode 100644 index 0000000..ac2a2a1 --- /dev/null +++ b/Scripts/Spells/Necromancy/SummonFamiliar.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Gumps; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class SummonFamiliarSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Familiar", "Kal Xen Bal", + 203, + 9031, + Reagent.BatWing, + Reagent.GraveDust, + Reagent.DaemonBlood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 30.0; } } + public override int RequiredMana{ get{ return 17; } } + + public SummonFamiliarSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + private static Hashtable m_Table = new Hashtable(); + + public static Hashtable Table{ get{ return m_Table; } } + + public override bool CheckCast() + { + BaseCreature check = (BaseCreature)m_Table[Caster]; + + if ( check != null && !check.Deleted ) + { + Caster.SendLocalizedMessage( 1061605 ); // You already have a familiar. + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + Caster.CloseGump( typeof( SummonFamiliarGump ) ); + Caster.SendGump( new SummonFamiliarGump( Caster, m_Entries, this ) ); + } + + FinishSequence(); + } + + private static SummonFamiliarEntry[] m_Entries = new SummonFamiliarEntry[] + { + new SummonFamiliarEntry( typeof( HordeMinionFamiliar ), 1060146, 30.0, 30.0 ), // Horde Minion + new SummonFamiliarEntry( typeof( ShadowWispFamiliar ), 1060142, 50.0, 50.0 ), // Shadow Wisp + new SummonFamiliarEntry( typeof( DarkWolfFamiliar ), 1060143, 60.0, 60.0 ), // Dark Wolf + new SummonFamiliarEntry( typeof( DeathAdder ), 1060145, 80.0, 80.0 ), // Death Adder + new SummonFamiliarEntry( typeof( VampireBatFamiliar ), 1060144, 100.0, 100.0 ) // Vampire Bat + }; + + public static SummonFamiliarEntry[] Entries{ get{ return m_Entries; } } + } + + public class SummonFamiliarEntry + { + private Type m_Type; + private object m_Name; + private double m_ReqNecromancy; + private double m_ReqSpiritSpeak; + + public Type Type{ get{ return m_Type; } } + public object Name{ get{ return m_Name; } } + public double ReqNecromancy{ get{ return m_ReqNecromancy; } } + public double ReqSpiritSpeak{ get{ return m_ReqSpiritSpeak; } } + + public SummonFamiliarEntry( Type type, object name, double reqNecromancy, double reqSpiritSpeak ) + { + m_Type = type; + m_Name = name; + m_ReqNecromancy = reqNecromancy; + m_ReqSpiritSpeak = reqSpiritSpeak; + } + } + + public class SummonFamiliarGump : Gump + { + private Mobile m_From; + private SummonFamiliarEntry[] m_Entries; + + private SummonFamiliarSpell m_Spell; + + private const int EnabledColor16 = 0x0F20; + private const int DisabledColor16 = 0x262A; + + private const int EnabledColor32 = 0x18CD00; + private const int DisabledColor32 = 0x4A8B52; + + public SummonFamiliarGump( Mobile from, SummonFamiliarEntry[] entries, SummonFamiliarSpell spell ) : base( 200, 100 ) + { + m_From = from; + m_Entries = entries; + m_Spell = spell; + + AddPage( 0 ); + + AddBackground( 10, 10, 250, 178, 9270 ); + AddAlphaRegion( 20, 20, 230, 158 ); + + AddImage( 220, 20, 10464 ); + AddImage( 220, 72, 10464 ); + AddImage( 220, 124, 10464 ); + + AddItem( 188, 16, 6883 ); + AddItem( 198, 168, 6881 ); + AddItem( 8, 15, 6882 ); + AddItem( 2, 168, 6880 ); + + AddHtmlLocalized( 30, 26, 200, 20, 1060147, EnabledColor16, false, false ); // Chose thy familiar... + + double necro = from.Skills[SkillName.Necromancy].Value; + double spirit = from.Skills[SkillName.SpiritSpeak].Value; + + for ( int i = 0; i < entries.Length; ++i ) + { + object name = entries[i].Name; + + bool enabled = ( necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak ); + + AddButton( 27, 53 + (i * 21), 9702, 9703, i + 1, GumpButtonType.Reply, 0 ); + + if ( name is int ) + AddHtmlLocalized( 50, 51 + (i * 21), 150, 20, (int)name, enabled ? EnabledColor16 : DisabledColor16, false, false ); + else if ( name is string ) + AddHtml( 50, 51 + (i * 21), 150, 20, String.Format( "{1}", enabled ? EnabledColor32 : DisabledColor32, name ), false, false ); + } + } + + private static Hashtable m_Table = new Hashtable(); + + public override void OnResponse( NetState sender, RelayInfo info ) + { + int index = info.ButtonID - 1; + + if ( index >= 0 && index < m_Entries.Length ) + { + SummonFamiliarEntry entry = m_Entries[index]; + + double necro = m_From.Skills[SkillName.Necromancy].Value; + double spirit = m_From.Skills[SkillName.SpiritSpeak].Value; + + BaseCreature check = (BaseCreature)SummonFamiliarSpell.Table[m_From]; + + + #region Dueling + if (m_From is PlayerMobile && ((PlayerMobile)m_From).DuelContext != null && !((PlayerMobile)m_From).DuelContext.AllowSpellCast(m_From, m_Spell)) + { + } + #endregion + else if (check != null && !check.Deleted) + { + m_From.SendLocalizedMessage( 1061605 ); // You already have a familiar. + } + else if ( necro < entry.ReqNecromancy || spirit < entry.ReqSpiritSpeak ) + { + // That familiar requires ~1_NECROMANCY~ Necromancy and ~2_SPIRIT~ Spirit Speak. + m_From.SendLocalizedMessage( 1061606, String.Format( "{0:F1}\t{1:F1}", entry.ReqNecromancy, entry.ReqSpiritSpeak ) ); + + m_From.CloseGump( typeof( SummonFamiliarGump ) ); + m_From.SendGump( new SummonFamiliarGump( m_From, SummonFamiliarSpell.Entries, m_Spell ) ); + } + else if ( entry.Type == null ) + { + m_From.SendMessage( "That familiar has not yet been defined." ); + + m_From.CloseGump( typeof( SummonFamiliarGump ) ); + m_From.SendGump( new SummonFamiliarGump( m_From, SummonFamiliarSpell.Entries, m_Spell ) ); + } + else + { + try + { + BaseCreature bc = (BaseCreature)Activator.CreateInstance( entry.Type ); + + bc.Skills.MagicResist = m_From.Skills.MagicResist; + + if ( BaseCreature.Summon( bc, m_From, m_From.Location, -1, TimeSpan.FromDays( 1.0 ) ) ) + { + m_From.FixedParticles( 0x3728, 1, 10, 9910, EffectLayer.Head ); + bc.PlaySound( bc.GetIdleSound() ); + SummonFamiliarSpell.Table[m_From] = bc; + } + } + catch + { + } + } + } + else + { + m_From.SendLocalizedMessage( 1061825 ); // You decide not to summon a familiar. + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/TransformationSpell.cs b/Scripts/Spells/Necromancy/TransformationSpell.cs new file mode 100644 index 0000000..46e5248 --- /dev/null +++ b/Scripts/Spells/Necromancy/TransformationSpell.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Spells.Fifth; +using Server.Spells.Seventh; + +namespace Server.Spells.Necromancy +{ + public abstract class TransformationSpell : NecromancerSpell, ITransformationSpell + { + public abstract int Body{ get; } + public virtual int Hue{ get{ return 0; } } + + public virtual int PhysResistOffset{ get{ return 0; } } + public virtual int FireResistOffset{ get{ return 0; } } + public virtual int ColdResistOffset{ get{ return 0; } } + public virtual int PoisResistOffset{ get{ return 0; } } + public virtual int NrgyResistOffset{ get{ return 0; } } + + public TransformationSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public override bool BlockedByHorrificBeast{ get{ return false; } } + + public override bool CheckCast() + { + if( !TransformationSpellHelper.CheckCast( Caster, this ) ) + return false; + + return base.CheckCast(); + } + + public override void OnCast() + { + TransformationSpellHelper.OnCast( Caster, this ); + + FinishSequence(); + } + + public virtual double TickRate{ get{ return 1.0; } } + + public virtual void OnTick( Mobile m ) + { + } + + public virtual void DoEffect( Mobile m ) + { + } + + public virtual void RemoveEffect( Mobile m ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/VampiricEmbrace.cs b/Scripts/Spells/Necromancy/VampiricEmbrace.cs new file mode 100644 index 0000000..7d220e9 --- /dev/null +++ b/Scripts/Spells/Necromancy/VampiricEmbrace.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Necromancy +{ + public class VampiricEmbraceSpell : TransformationSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Vampiric Embrace", "Rel Xen An Sanct", + 203, + 9031, + Reagent.BatWing, + Reagent.NoxCrystal, + Reagent.PigIron + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 99.0; } } + public override int RequiredMana{ get{ return 23; } } + + public override int Body{ get{ return Caster.Female ? 745 : 744; } } + public override int Hue{ get{ return 0x847E; } } + + public override int FireResistOffset{ get{ return -25; } } + + public VampiricEmbraceSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void GetCastSkills( out double min, out double max ) + { + if ( Caster.Skills[CastSkill].Value >= RequiredSkill ) + { + min = 80.0; + max = 120.0; + } + else + { + base.GetCastSkills( out min, out max ); + } + } + + public override void DoEffect( Mobile m ) + { + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x373A, 1, 17, 1108, 7, 9914, 0 ); + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x376A, 1, 22, 67, 7, 9502, 0 ); + Effects.PlaySound( m.Location, m.Map, 0x4B1 ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/VengefulSpirit.cs b/Scripts/Spells/Necromancy/VengefulSpirit.cs new file mode 100644 index 0000000..f59b855 --- /dev/null +++ b/Scripts/Spells/Necromancy/VengefulSpirit.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class VengefulSpiritSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Vengeful Spirit", "Kal Xen Bal Beh", + 203, + 9031, + Reagent.BatWing, + Reagent.GraveDust, + Reagent.PigIron + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 80.0; } } + public override int RequiredMana{ get{ return 41; } } + + public VengefulSpiritSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 3) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public void Target( Mobile m ) + { + if ( Caster == m ) + { + Caster.SendLocalizedMessage( 1061832 ); // You cannot exact vengeance on yourself. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + /* Summons a Revenant which haunts the target until either the target or the Revenant is dead. + * Revenants have the ability to track down their targets wherever they may travel. + * A Revenant's strength is determined by the Necromancy and Spirit Speak skills of the Caster. + * The effect lasts for ((Spirit Speak skill level * 80) / 120) + 10 seconds. + */ + + TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) * 80) / 120) + 10 ); + + Revenant rev = new Revenant( Caster, m, duration ); + + if ( BaseCreature.Summon( rev, false, Caster, m.Location, 0x81, TimeSpan.FromSeconds( duration.TotalSeconds + 2.0 ) ) ) + rev.FixedParticles( 0x373A, 1, 15, 9909, EffectLayer.Waist ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private VengefulSpiritSpell m_Owner; + + public InternalTarget( VengefulSpiritSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/Wither.cs b/Scripts/Spells/Necromancy/Wither.cs new file mode 100644 index 0000000..297d4bb --- /dev/null +++ b/Scripts/Spells/Necromancy/Wither.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class WitherSpell : NecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Wither", "Kal Vas An Flam", + 203, + 9031, + Reagent.NoxCrystal, + Reagent.GraveDust, + Reagent.PigIron + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill { get { return 60.0; } } + + public override int RequiredMana { get { return 23; } } + + public WitherSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override bool DelayedDamage { get { return false; } } + + public override void OnCast() + { + if( CheckSequence() ) + { + /* Creates a withering frost around the Caster, + * which deals Cold Damage to all valid targets in a radius of 5 tiles. + */ + + Map map = Caster.Map; + + if( map != null ) + { + List targets = new List(); + + BaseCreature cbc = Caster as BaseCreature; + bool isMonster = (cbc != null && !cbc.Controlled && !cbc.Summoned); + + foreach (Mobile m in Caster.GetMobilesInRange(Core.ML ? 4 : 5)) + { + if (Caster != m && Caster.InLOS(m) && (isMonster || SpellHelper.ValidIndirectTarget(Caster, m)) && Caster.CanBeHarmful(m, false)) + { + if (isMonster) + { + if (m is BaseCreature) + { + BaseCreature bc = (BaseCreature)m; + + if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team) + continue; + } + else if (!m.Player) + { + continue; + } + } + + targets.Add(m); + } + } + + Effects.PlaySound( Caster.Location, map, 0x1FB ); + Effects.PlaySound( Caster.Location, map, 0x10B ); + Effects.SendLocationParticles( EffectItem.Create( Caster.Location, map, EffectItem.DefaultDuration ), 0x37CC, 1, 40, 97, 3, 9917, 0 ); + + for( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[ i ]; + + Caster.DoHarmful( m ); + m.FixedParticles( 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255 ); + + double damage = Utility.RandomMinMax( 30, 35 ); + + damage *= (300 + (m.Karma / 100) + (GetDamageSkill(Caster) * 10)); + damage /= 1000; + + int sdiBonus = AosAttributes.GetValue( Caster, AosAttribute.SpellDamage ); + + // PvP spell damage increase cap of 15% from an item�s magic property in Publish 33(SE) + if( Core.SE && m.Player && Caster.Player && sdiBonus > 15 ) + sdiBonus = 15; + + damage *= ( 100 + sdiBonus ); + damage /= 100; + + // TODO: cap? + //if ( damage > 40 ) + // damage = 40; + + SpellHelper.Damage( this, m, damage, 0, 0, 100, 0, 0 ); + } + } + } + + FinishSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Necromancy/WraithForm.cs b/Scripts/Spells/Necromancy/WraithForm.cs new file mode 100644 index 0000000..9040bc6 --- /dev/null +++ b/Scripts/Spells/Necromancy/WraithForm.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Necromancy +{ + public class WraithFormSpell : TransformationSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Wraith Form", "Rel Xen Um", + 203, + 9031, + Reagent.NoxCrystal, + Reagent.PigIron + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill{ get{ return 20.0; } } + public override int RequiredMana{ get{ return 17; } } + + public override int Body{ get{ return Caster.Female ? 747 : 748; } } + public override int Hue{ get{ return Caster.Female ? 0 : 0x4001; } } + + public override int PhysResistOffset{ get{ return +15; } } + public override int FireResistOffset{ get{ return -5; } } + public override int ColdResistOffset{ get{ return 0; } } + public override int PoisResistOffset{ get{ return 0; } } + public override int NrgyResistOffset{ get{ return -5; } } + + public WraithFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void DoEffect( Mobile m ) + { + if ( m is PlayerMobile ) + ((PlayerMobile)m).IgnoreMobiles = true; + + m.PlaySound( 0x17F ); + m.FixedParticles( 0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist ); + } + + public override void RemoveEffect( Mobile m ) + { + if ( m is PlayerMobile && m.AccessLevel == AccessLevel.Player ) + ((PlayerMobile)m).IgnoreMobiles = false; + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/AnimalForm.cs b/Scripts/Spells/Ninjitsu/AnimalForm.cs new file mode 100644 index 0000000..6cc1f22 --- /dev/null +++ b/Scripts/Spells/Ninjitsu/AnimalForm.cs @@ -0,0 +1,641 @@ +using System; +using System.Collections; +using Server.Gumps; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Spells.Fifth; +using Server.Spells.Seventh; + +namespace Server.Spells.Ninjitsu +{ + public class AnimalForm : NinjaSpell + { + public static void Initialize() + { + EventSink.Login += new LoginEventHandler(OnLogin); + } + + public static void OnLogin(LoginEventArgs e) + { + AnimalFormContext context = AnimalForm.GetContext(e.Mobile); + + if (context != null && context.SpeedBoost) + e.Mobile.Send(SpeedControl.MountSpeed); + } + + + private static SpellInfo m_Info = new SpellInfo( + "Animal Form", null, + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.0); } } + + public override double RequiredSkill { get { return 0.0; } } + public override int RequiredMana { get { return (Core.ML ? 10 : 0); } } + public override int CastRecoveryBase { get { return (Core.ML ? 10 : base.CastRecoveryBase); } } + + public override bool BlockedByAnimalForm { get { return false; } } + + public AnimalForm(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override bool CheckCast() + { + if (!Caster.CanBeginAction(typeof(PolymorphSpell))) + { + Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + return false; + } + else if (TransformationSpellHelper.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form. + return false; + } + else if (DisguiseTimers.IsDisguised(Caster)) + { + Caster.SendLocalizedMessage(1061631); // You can't do that while disguised. + return false; + } + + return base.CheckCast(); + } + + public override bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable) + { + return false; + } + + private bool CasterIsMoving() + { + return (DateTime.Now - Caster.LastMoveTime <= Caster.ComputeMovementSpeed(Caster.Direction)); + } + + private bool m_WasMoving; + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.FixedEffect(0x37C4, 10, 14, 4, 3); + m_WasMoving = CasterIsMoving(); + } + + public override bool CheckFizzle() + { + // Spell is initially always successful, and with no skill gain. + return true; + } + + public override void OnCast() + { + if (!Caster.CanBeginAction(typeof(PolymorphSpell))) + { + Caster.SendLocalizedMessage(1061628); // You can't do that while polymorphed. + } + else if (TransformationSpellHelper.UnderTransformation(Caster)) + { + Caster.SendLocalizedMessage(1063219); // You cannot mimic an animal while in that form. + } + else if (!Caster.CanBeginAction(typeof(IncognitoSpell)) || (Caster.IsBodyMod && GetContext(Caster) == null)) + { + DoFizzle(); + } + else if (CheckSequence()) + { + AnimalFormContext context = GetContext(Caster); + + int mana = ScaleMana(RequiredMana); + if (mana > Caster.Mana) + { + Caster.SendLocalizedMessage(1060174, mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + } + else if (context != null) + { + RemoveContext(Caster, context, true); + Caster.Mana -= mana; + } + else if (Caster is PlayerMobile) + { + bool skipGump = (m_WasMoving || CasterIsMoving()); + + if (GetLastAnimalForm(Caster) == -1 || !skipGump) + { + Caster.CloseGump(typeof(AnimalFormGump)); + Caster.SendGump(new AnimalFormGump(Caster, m_Entries, this)); + } + else + { + if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail) + { + DoFizzle(); + } + else + { + Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + Caster.Mana -= mana; + } + } + } + else + { + if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail) + { + DoFizzle(); + } + else + { + Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + Caster.Mana -= mana; + } + } + } + + FinishSequence(); + } + + private static Hashtable m_LastAnimalForms = new Hashtable(); + + public int GetLastAnimalForm(Mobile m) + { + if (m_LastAnimalForms.Contains(m)) + return (int)m_LastAnimalForms[m]; + + return -1; + } + + public enum MorphResult + { + Success, + Fail, + NoSkill + } + + public static MorphResult Morph(Mobile m, int entryID) + { + if (entryID < 0 || entryID >= m_Entries.Length) + return MorphResult.Fail; + + AnimalFormEntry entry = m_Entries[entryID]; + + m_LastAnimalForms[m] = entryID; //On OSI, it's the last /attempted/ one not the last succeeded one + + if (m.Skills.Ninjitsu.Value < entry.ReqSkill) + { + string args = String.Format("{0}\t{1}\t ", entry.ReqSkill.ToString("F1"), SkillName.Ninjitsu); + m.SendLocalizedMessage(1063013, args); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return MorphResult.NoSkill; + } + + /* + if( !m.CheckSkill( SkillName.Ninjitsu, entry.ReqSkill, entry.ReqSkill + 37.5 ) ) + return MorphResult.Fail; + * + * On OSI,it seems you can only gain starting at '0' using Animal form. + */ + + double ninjitsu = m.Skills.Ninjitsu.Value; + + if (ninjitsu < entry.ReqSkill + 37.5) + { + double chance = (ninjitsu - entry.ReqSkill) / 37.5; + + if (chance < Utility.RandomDouble()) + return MorphResult.Fail; + } + + m.CheckSkill(SkillName.Ninjitsu, 0.0, 37.5); + + if (!BaseFormTalisman.EntryEnabled(m, entry.Type)) + return MorphResult.Success; // Still consumes mana, just no effect + + BaseMount.Dismount(m); + + int bodyMod = entry.BodyMod; + int hueMod = entry.HueMod; + string namemod = entry.NameMod; + + m.BodyMod = bodyMod; + m.HueMod = hueMod; + m.NameMod = namemod; //Vinds : animal form anonymise, apr�s tout, c'est pour les m�tiers de l'ombre + + if (entry.SpeedBoost) + m.Send(SpeedControl.MountSpeed); + + + SkillMod mod = null; + + if (entry.StealthBonus) + { + mod = new DefaultSkillMod(SkillName.Stealth, true, 20.0); + mod.ObeyCap = true; + m.AddSkillMod(mod); + } + + SkillMod stealingMod = null; + + if (entry.StealingBonus) + { + stealingMod = new DefaultSkillMod(SkillName.Stealing, true, 10.0); + stealingMod.ObeyCap = true; + m.AddSkillMod(stealingMod); + } + + Timer timer = new AnimalFormTimer(m, bodyMod, hueMod); + timer.Start(); + + AddContext(m, new AnimalFormContext(timer, mod, entry.SpeedBoost, entry.Type, stealingMod)); + m.CheckStatTimers(); + return MorphResult.Success; + } + + private static Hashtable m_Table = new Hashtable(); + + public static void AddContext(Mobile m, AnimalFormContext context) + { + m_Table[m] = context; + + if (context.Type == typeof(BakeKitsune) || context.Type == typeof(GreyWolf)) + m.CheckStatTimers(); + } + + public static void RemoveContext(Mobile m, bool resetGraphics) + { + AnimalFormContext context = GetContext(m); + + if (context != null) + RemoveContext(m, context, resetGraphics); + } + + public static void RemoveContext(Mobile m, AnimalFormContext context, bool resetGraphics) + { + m_Table.Remove(m); + + if (context.SpeedBoost) + m.Send(SpeedControl.Disable); + + SkillMod mod = context.Mod; + + if (mod != null) + m.RemoveSkillMod(mod); + + mod = context.StealingMod; + + if (mod != null) + m.RemoveSkillMod(mod); + + if (resetGraphics) + { + m.HueMod = -1; + m.BodyMod = 0; + m.NameMod = null; // vinds retour au nom d'origine lorsque reprise de la forme humaine + } + + m.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist); + + context.Timer.Stop(); + } + + public static AnimalFormContext GetContext(Mobile m) + { + return (m_Table[m] as AnimalFormContext); + } + + public static bool UnderTransformation(Mobile m) + { + return (GetContext(m) != null); + } + + public static bool UnderTransformation(Mobile m, Type type) + { + AnimalFormContext context = GetContext(m); + + return (context != null && context.Type == type); + } + + /* + private delegate void AnimalFormCallback( Mobile from ); + private delegate bool AnimalFormRequirementCallback( Mobile from ); + */ + + public class AnimalFormEntry + { + private Type m_Type; + private TextDefinition m_Name; + private int m_ItemID; + private int m_Hue; + private int m_Tooltip; + private double m_ReqSkill; + private int m_BodyMod; + private int m_HueModMin; + private int m_HueModMax; + private bool m_StealthBonus; + private bool m_SpeedBoost; + private bool m_StealingBonus; + private string m_NameMod; // Vinds : ajout d'une entr�e pour l'anonymisation + + public Type Type { get { return m_Type; } } + public TextDefinition Name { get { return m_Name; } } + public int ItemID { get { return m_ItemID; } } + public int Hue { get { return m_Hue; } } + public int Tooltip { get { return m_Tooltip; } } + public double ReqSkill { get { return m_ReqSkill; } } + public int BodyMod { get { return m_BodyMod; } } + public int HueMod { get { return Utility.RandomMinMax(m_HueModMin, m_HueModMax); } } + public bool StealthBonus { get { return m_StealthBonus; } } + public bool SpeedBoost { get { return m_SpeedBoost; } } + public bool StealingBonus { get { return m_StealingBonus; } } + public string NameMod { get { return m_NameMod; } } + + /* + private AnimalFormCallback m_TransformCallback; + private AnimalFormCallback m_UntransformCallback; + private AnimalFormRequirementCallback m_RequirementCallback; + */ + + public AnimalFormEntry(Type type, TextDefinition name, int itemID, int hue, int tooltip, double reqSkill, int bodyMod, int hueModMin, int hueModMax, bool stealthBonus, bool speedBoost, bool stealingBonus, string NameMod) + { + m_Type = type; + m_Name = name; + m_ItemID = itemID; + m_Hue = hue; + m_Tooltip = tooltip; + m_ReqSkill = reqSkill; + m_BodyMod = bodyMod; + m_HueModMin = hueModMin; + m_HueModMax = hueModMax; + m_StealthBonus = stealthBonus; + m_SpeedBoost = speedBoost; + m_StealingBonus = stealingBonus; + m_NameMod = NameMod; + } + } + + private static AnimalFormEntry[] m_Entries = new AnimalFormEntry[] + { + new AnimalFormEntry( typeof( Panther ), 1015239, 9653, 0, 1070811, 90.0, 0xD6, 0x8FD, 0x90E, false, true, false, "Panthere" ), + //new AnimalFormEntry( typeof( Kirin ), 1029632, 9632, 0, 1070811, 90.0, 0x84, 0, 0, false, true, false, "Kirin" ), + new AnimalFormEntry( typeof( Unicorn ), 1018214, 9678, 0, 1070812, 90.0, 0x7A, 0, 0, false, true, false, "Licorne" ), + new AnimalFormEntry( typeof( BakeKitsune ), 1030083, 10083, 0, 1070810, 82.5, 0xF6, 0, 0, false, true, false, "BakeKitsune" ), + new AnimalFormEntry( typeof( GreyWolf ), 1028482, 9681, 2309, 1070810, 82.5, 0x19, 0x8FD, 0x90E, false, true, false, "Loup" ), + new AnimalFormEntry( typeof( Bird ), 1072464, 8477, 0, 1070809, 70.0, 0x5, 0x8B0, 0x8B0, false, true, false, "Corbeau" ), + new AnimalFormEntry( typeof( ForestOstard ), 1018273, 8503, 2212, 1070809, 70.0, 0xDB, 0x899, 0x8B0, false, true, false, "Ostard" ), + //new AnimalFormEntry( typeof( Llama ), 1028438, 8438, 0, 1070809, 70.0, 0xDC, 0, 0, false, true, false, "Lama" ), + new AnimalFormEntry( typeof( BullFrog ), 1028496, 8496, 2003, 1070807, 50.0, 0x51, 0x7D1, 0x7D6, false, false, false, "Crapaud" ), + new AnimalFormEntry( typeof( GiantSerpent ), 1018114, 9663, 2009, 1070808, 50.0, 0x15, 0x7D1, 0x7E2, false, false, false, "Serpent Geant" ), + new AnimalFormEntry( typeof( Dog ), 1018280, 8476, 2309, 1070806, 40.0, 0xD9, 0x8FD, 0x90E, false, false, false, "Chien" ), + new AnimalFormEntry( typeof( Cat ), 1018264, 8475, 2309, 1070806, 40.0, 0xC9, 0x8FD, 0x90E, false, false, false, "Chat" ), + new AnimalFormEntry( typeof( Rat ), 1018294, 8483, 2309, 1070805, 20.0, 0xEE, 0x8FD, 0x90E, true, false, false, "Rat" ), + new AnimalFormEntry( typeof( Rabbit ), 1028485, 8485, 2309, 1070805, 20.0, 0xCD, 0x8FD, 0x90E, true, false, false, "Lapin" ), + new AnimalFormEntry( typeof( Squirrel ), 1031671, 11671, 0, 0, 20.0, 0x116, 0, 0, false, false, false, "Renard" ), + new AnimalFormEntry( typeof( Ferret ), 1031672, 11672, 0, 1075220, 40.0, 0x117, 0, 0, false, false, true, "Furet" ), + new AnimalFormEntry( typeof( CuSidhe ), 1031670, 11670, 0, 1075221, 60.0, 0x115, 0, 0, false, false, false, "Cu Sidhe" ), + new AnimalFormEntry( typeof( Reptalon ), 1075202, 11669, 0, 1075222, 90.0, 0x114, 0, 0, false, false, false, "Reptalon" ), + }; + + public static AnimalFormEntry[] Entries { get { return m_Entries; } } + + public class AnimalFormGump : Gump + { + //TODO: Convert this for ML to the BaseImageTileButtonsgump + private Mobile m_Caster; + private AnimalForm m_Spell; + private Item m_Talisman; + + public AnimalFormGump(Mobile caster, AnimalFormEntry[] entries, AnimalForm spell) + : base(50, 50) + { + m_Caster = caster; + m_Spell = spell; + m_Talisman = caster.Talisman; + + AddPage(0); + + AddBackground(0, 0, 520, 404, 0x13BE); + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 324, 0xA40); + AddImageTiled(10, 374, 500, 20, 0xA40); + AddAlphaRegion(10, 10, 500, 384); + + AddHtmlLocalized(14, 12, 500, 20, 1063394, 0x7FFF, false, false); //
Polymorph Selection Menu
+ + AddButton(10, 374, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0); + AddHtmlLocalized(45, 376, 450, 20, 1011012, 0x7FFF, false, false); // CANCEL + + double ninjitsu = caster.Skills.Ninjitsu.Value; + + int current = 0; + + for (int i = 0; i < entries.Length; ++i) + { + bool enabled = (ninjitsu >= entries[i].ReqSkill && BaseFormTalisman.EntryEnabled(caster, entries[i].Type)); + + int page = current / 10 + 1; + int pos = current % 10; + + if (pos == 0) + { + if (page > 1) + { + AddButton(400, 374, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page); + AddHtmlLocalized(440, 376, 60, 20, 1043353, 0x7FFF, false, false); // Next + } + + AddPage(page); + + if (page > 1) + { + AddButton(300, 374, 0xFAE, 0xFB0, 0, GumpButtonType.Page, 1); + AddHtmlLocalized(340, 376, 60, 20, 1011393, 0x7FFF, false, false); // Back + } + } + + if (enabled) + { + int x = (pos % 2 == 0) ? 14 : 264; + int y = (pos / 2) * 64 + 44; + + Rectangle2D b = ItemBounds.Table[entries[i].ItemID]; + + AddImageTiledButton(x, y, 0x918, 0x919, i + 1, GumpButtonType.Reply, 0, entries[i].ItemID, entries[i].Hue, 40 - b.Width / 2 - b.X, 30 - b.Height / 2 - b.Y, entries[i].Tooltip); + AddHtmlLocalized(x + 84, y, 250, 60, entries[i].Name, 0x7FFF, false, false); + + current++; + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int entryID = info.ButtonID - 1; + + if (entryID < 0 || entryID >= m_Entries.Length) + return; + + int mana = m_Spell.ScaleMana(m_Spell.RequiredMana); + AnimalFormEntry entry = AnimalForm.Entries[entryID]; + + if (mana > m_Caster.Mana) + { + m_Caster.SendLocalizedMessage(1060174, mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + } + else if ((m_Caster is PlayerMobile) && (m_Caster as PlayerMobile).MountBlockReason != BlockMountType.None) + { + m_Caster.SendLocalizedMessage(1063108); // You cannot use this ability right now. + } + else if (BaseFormTalisman.EntryEnabled(sender.Mobile, entry.Type)) + { + #region Dueling + if (m_Caster is PlayerMobile && ((PlayerMobile)m_Caster).DuelContext != null && !((PlayerMobile)m_Caster).DuelContext.AllowSpellCast(m_Caster, m_Spell)) + { + } + #endregion + else if (AnimalForm.Morph(m_Caster, entryID) == MorphResult.Fail) + { + m_Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles. + m_Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist); + m_Caster.PlaySound(0x5C); + } + else + { + m_Caster.Mana -= mana; + } + } + } + } + } + + public class AnimalFormContext + { + private Timer m_Timer; + private SkillMod m_Mod; + private bool m_SpeedBoost; + private Type m_Type; + private SkillMod m_StealingMod; + + + public Timer Timer { get { return m_Timer; } } + public SkillMod Mod { get { return m_Mod; } } + public bool SpeedBoost { get { return m_SpeedBoost; } } + public Type Type { get { return m_Type; } } + public SkillMod StealingMod { get { return m_StealingMod; } } + + + + public AnimalFormContext(Timer timer, SkillMod mod, bool speedBoost, Type type, SkillMod stealingMod) + { + m_Timer = timer; + m_Mod = mod; + m_SpeedBoost = speedBoost; + m_Type = type; + m_StealingMod = stealingMod; + } + } + + public class AnimalFormTimer : Timer + { + private Mobile m_Mobile; + private int m_Body; + private int m_Hue; + private int m_Counter; + private Mobile m_LastTarget; + + private int m_Duration; // Scriptiz : fin de l'effet + private int m_Ticks; // Scriptiz : pour limiter l'effet + + public AnimalFormTimer(Mobile from, int body, int hue) + : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0)) + { + m_Mobile = from; + m_Body = body; + m_Hue = hue; + m_Counter = 0; + + Priority = TimerPriority.FiftyMS; + + // Scriptiz : Le sort a un effet limit� en fonction de ninjitsu et de la dex + m_Duration = 3 + (int)Math.Floor(from.Skills[SkillName.Ninjitsu].Value * (from.Dex / 40.0)); + m_Ticks = 0; // pour garder le nombre de ticks (1 par seconde) + } + + protected override void OnTick() + { + // Scriptiz : arr�t du sort apr�s un certain temps en rajoutant ceci devant tout : m_Ticks++ > m_Duration || + if (/*++m_Ticks > m_Duration || */m_Mobile.Deleted || !m_Mobile.Alive || m_Mobile.Body != m_Body || m_Mobile.Hue != m_Hue) + + { + AnimalForm.RemoveContext(m_Mobile, true); + Stop(); + } + else + { + if (m_Body == 0x115) // Cu Sidhe + { + if (m_Counter++ >= 8) + { + if (m_Mobile.Hits < m_Mobile.HitsMax && m_Mobile.Backpack != null) + { + Bandage b = m_Mobile.Backpack.FindItemByType(typeof(Bandage)) as Bandage; + + if (b != null) + { + m_Mobile.Hits += Utility.RandomMinMax(20, 50); + b.Consume(); + } + } + + m_Counter = 0; + } + } + else if (m_Body == 0x114) // Reptalon + { + if (m_Mobile.Combatant != null && m_Mobile.Combatant != m_LastTarget) + { + m_Counter = 1; + m_LastTarget = m_Mobile.Combatant; + } + + if (m_Mobile.Warmode && m_LastTarget != null && m_LastTarget.Alive && !m_LastTarget.Deleted && m_Counter-- <= 0) + { + if (m_Mobile.CanBeHarmful(m_LastTarget) && m_LastTarget.Map == m_Mobile.Map && m_LastTarget.InRange(m_Mobile.Location, BaseCreature.DefaultRangePerception) && m_Mobile.InLOS(m_LastTarget)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(m_LastTarget); + m_Mobile.Freeze(TimeSpan.FromSeconds(1)); + m_Mobile.PlaySound(0x16A); + + Timer.DelayCall(TimeSpan.FromSeconds(1.3), new TimerStateCallback(BreathEffect_Callback), m_LastTarget); + } + + m_Counter = Math.Min((int)m_Mobile.GetDistanceToSqrt(m_LastTarget), 10); + } + } + } + } + + public void BreathEffect_Callback(Mobile target) + { + if (m_Mobile.CanBeHarmful(target)) + { + m_Mobile.RevealingAction(); + m_Mobile.PlaySound(0x227); + Effects.SendMovingEffect(m_Mobile, target, 0x36D4, 5, 0, false, false, 0, 0); + + Timer.DelayCall(TimeSpan.FromSeconds(1), new TimerStateCallback(BreathDamage_Callback), target); + } + } + + public void BreathDamage_Callback(Mobile target) + { + if (m_Mobile.CanBeHarmful(target)) + { + m_Mobile.RevealingAction(); + m_Mobile.DoHarmful(target); + AOS.Damage(target, m_Mobile, 20, !target.Player, 0, 100, 0, 0, 0); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/Backstab.cs b/Scripts/Spells/Ninjitsu/Backstab.cs new file mode 100644 index 0000000..ab32504 --- /dev/null +++ b/Scripts/Spells/Ninjitsu/Backstab.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.SkillHandlers; + +namespace Server.Spells.Ninjitsu +{ + public class Backstab : NinjaMove + { + public Backstab() + { + } + + public override int BaseMana{ get{ return 30; } } + public override double RequiredSkill{ get{ return Core.ML ? 40.0 : 20.0; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063089 ); } } // You prepare to Backstab your opponent. + + public override double GetDamageScalar( Mobile attacker, Mobile defender ) + { + double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value; + + return 1.0 + (ninjitsu / 360) + Tracking.GetStalkingBonus( attacker, defender ) / 100; + } + + public override bool Validate( Mobile from ) + { + if( !from.Hidden || from.AllowedStealthSteps <= 0 ) + { + from.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability. + return false; + } + + return base.Validate( from ); + } + + public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + bool valid = Validate( attacker ) && CheckMana( attacker, true ); + + if( valid ) + { + attacker.BeginAction( typeof( Stealth ) ); + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), delegate { attacker.EndAction( typeof( Stealth ) ); } ); + } + + return valid; + + } + + public override bool ValidatesDuringHit { get { return false; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + //Validates before swing + + ClearCurrentMove( attacker ); + + attacker.SendLocalizedMessage( 1063090 ); // You quickly stab your opponent as you come out of hiding! + + defender.FixedParticles( 0x37B9, 1, 5, 0x251D, 0x651, 0, EffectLayer.Waist ); + + attacker.RevealingAction(); + + CheckGain( attacker ); + } + + public override void OnMiss( Mobile attacker, Mobile defender ) + { + ClearCurrentMove( attacker ); + + attacker.SendLocalizedMessage( 1063161 ); // You failed to properly use the element of surprise. + + attacker.RevealingAction(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/DeathStrike.cs b/Scripts/Spells/Ninjitsu/DeathStrike.cs new file mode 100644 index 0000000..b67396f --- /dev/null +++ b/Scripts/Spells/Ninjitsu/DeathStrike.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.SkillHandlers; + +namespace Server.Spells.Ninjitsu +{ + public class DeathStrike : NinjaMove + { + public DeathStrike() + { + } + + public override int BaseMana { get { return 30; } } + public override double RequiredSkill { get { return 85.0; } } + + public override TextDefinition AbilityMessage { get { return new TextDefinition( 1063091 ); } } // You prepare to hit your opponent with a Death Strike. + + public override double GetDamageScalar( Mobile attacker, Mobile defender ) + { + return 0.5; + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + ClearCurrentMove( attacker ); + + double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value; + + double chance; + bool isRanged = false; // should be defined onHit method, what if the player hit and remove the weapon before process? ;) + + if (attacker.Weapon is BaseRanged) + isRanged = true; + + if( ninjitsu < 100 ) //This formula is an approximation from OSI data. TODO: find correct formula + chance = 30 + (ninjitsu - 85) * 2.2; + else + chance = 63 + (ninjitsu - 100) * 1.1; + + if( (chance / 100) < Utility.RandomDouble() ) + { + attacker.SendLocalizedMessage( 1070779 ); // You missed your opponent with a Death Strike. + return; + } + + + DeathStrikeInfo info; + + int damageBonus = 0; + + if( m_Table.Contains( defender ) ) + { + defender.SendLocalizedMessage( 1063092 ); // Your opponent lands another Death Strike! + + info = (DeathStrikeInfo)m_Table[defender]; + + if( info.m_Steps > 0 ) + damageBonus = attacker.Skills[SkillName.Ninjitsu].Fixed / 150; + + if( info.m_Timer != null ) + info.m_Timer.Stop(); + + m_Table.Remove( defender ); + } + else + { + defender.SendLocalizedMessage( 1063093 ); // You have been hit by a Death Strike! Move with caution! + } + + attacker.SendLocalizedMessage( 1063094 ); // You inflict a Death Strike upon your opponent! + + defender.FixedParticles( 0x374A, 1, 17, 0x26BC, EffectLayer.Waist ); + attacker.PlaySound( attacker.Female ? 0x50D : 0x50E ); + + info = new DeathStrikeInfo(defender, attacker, damageBonus, isRanged); + info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), new TimerStateCallback( ProcessDeathStrike ), defender ); + + m_Table[defender] = info; + + CheckGain( attacker ); + } + + + private static Hashtable m_Table = new Hashtable(); + + private class DeathStrikeInfo + { + public Mobile m_Target; + public Mobile m_Attacker; + public int m_Steps; + public int m_DamageBonus; + public Timer m_Timer; + public bool m_isRanged; + + public DeathStrikeInfo(Mobile target, Mobile attacker, int damageBonus, bool isRanged) + { + m_Target = target; + m_Attacker = attacker; + m_DamageBonus = damageBonus; + m_isRanged = isRanged; + } + } + + public static void AddStep( Mobile m ) + { + DeathStrikeInfo info = m_Table[m] as DeathStrikeInfo; + + if( info == null ) + return; + + if( ++info.m_Steps >= 5 ) + ProcessDeathStrike( m ); + } + + private static void ProcessDeathStrike( object state ) + { + Mobile defender = (Mobile)state; + + DeathStrikeInfo info = m_Table[defender] as DeathStrikeInfo; + + if( info == null ) //sanity + return; + + int maxDamage, damage = 0; + + double ninjitsu = info.m_Attacker.Skills[SkillName.Ninjitsu].Value; + double stalkingBonus = Tracking.GetStalkingBonus(info.m_Attacker, info.m_Target); + + if (Core.ML) + { + double scalar = (info.m_Attacker.Skills[SkillName.Hiding].Value + info.m_Attacker.Skills[SkillName.Stealth].Value) / 220; + + if (scalar > 1) + scalar = 1; + + // New formula doesn't apply DamageBonus anymore, caps must be, directly, 60/30. + if (info.m_Steps >= 5) + damage = (int)Math.Floor(Math.Min(60, (ninjitsu / 3) * (0.3 + 0.7 * scalar) + stalkingBonus)); + else + damage = (int)Math.Floor(Math.Min(30, (ninjitsu / 9) * (0.3 + 0.7 * scalar) + stalkingBonus)); + + if (info.m_isRanged) + damage /= 2; + } + else + { + int divisor = (info.m_Steps >= 5) ? 30 : 80; + double baseDamage = ninjitsu / divisor * 10; + + maxDamage = (info.m_Steps >= 5) ? 62 : 22; // DamageBonus is 8 at most. That brings the cap up to 70/30. + damage = Math.Max(0, Math.Min(maxDamage, (int)(baseDamage + stalkingBonus))) + info.m_DamageBonus; + } + + if (Core.ML) + info.m_Target.Damage(damage, info.m_Attacker); // Damage is direct. + else + AOS.Damage(info.m_Target, info.m_Attacker, damage, true, 100, 0, 0, 0, 0, 0, 0, false, false, true); // Damage is physical. + + if( info.m_Timer != null ) + info.m_Timer.Stop(); + + m_Table.Remove( info.m_Target ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/FocusAttack.cs b/Scripts/Spells/Ninjitsu/FocusAttack.cs new file mode 100644 index 0000000..8279e1b --- /dev/null +++ b/Scripts/Spells/Ninjitsu/FocusAttack.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Ninjitsu +{ + public class FocusAttack : NinjaMove + { + public FocusAttack() + { + } + + public override int BaseMana{ get{ return Core.ML ? 10 : 20; } } + public override double RequiredSkill{ get{ return Core.ML? 30.0 : 60 ; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063095 ); } } // You prepare to focus all of your abilities into your next strike. + + public override bool Validate( Mobile from ) + { + if ( from.FindItemOnLayer( Layer.TwoHanded ) as BaseShield != null ) + { + from.SendLocalizedMessage( 1063096 ); // You cannot use this ability while holding a shield. + return false; + } + + Item handOne = from.FindItemOnLayer( Layer.OneHanded ) as BaseWeapon; + + if ( handOne != null && !(handOne is BaseRanged) ) + return base.Validate( from ); + + Item handTwo = from.FindItemOnLayer( Layer.TwoHanded ) as BaseWeapon; + + if ( handTwo != null && !(handTwo is BaseRanged) ) + return base.Validate( from ); + + from.SendLocalizedMessage( 1063097 ); // You must be wielding a melee weapon without a shield to use this ability. + return false; + } + + public override double GetDamageScalar( Mobile attacker, Mobile defender ) + { + double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value; + + return 1.0 + (ninjitsu * ninjitsu) / 43636; + } + + public override double GetPropertyBonus( Mobile attacker ) + { + double ninjitsu = attacker.Skills[SkillName.Ninjitsu].Value; + + double bonus = (ninjitsu * ninjitsu) / 43636; + + return 1.0 + (bonus * 3 + 0.01); + } + + public override bool OnBeforeDamage( Mobile attacker, Mobile defender ) + { + return Validate( attacker ) && CheckMana( attacker, true ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + ClearCurrentMove( attacker ); + + attacker.SendLocalizedMessage( 1063098 ); // You focus all of your abilities and strike with deadly force! + attacker.PlaySound( 0x510 ); + + CheckGain( attacker ); + } + } +} diff --git a/Scripts/Spells/Ninjitsu/KiAttack.cs b/Scripts/Spells/Ninjitsu/KiAttack.cs new file mode 100644 index 0000000..bb656f2 --- /dev/null +++ b/Scripts/Spells/Ninjitsu/KiAttack.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Spells.Ninjitsu +{ + public class KiAttack : NinjaMove + { + public KiAttack() + { + } + + public override int BaseMana{ get{ return 25; } } + public override double RequiredSkill{ get{ return 80.0; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063099 ); } } // Your Ki Attack must be complete within 2 seconds for the damage bonus! + + public override void OnUse( Mobile from ) + { + if ( !Validate( from ) ) + return; + + KiAttackInfo info = new KiAttackInfo( from ); + info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( EndKiAttack ), info ); + + m_Table[from] = info; + } + + public override bool Validate( Mobile from ) + { + if ( from.Hidden && from.AllowedStealthSteps > 0 ) + { + from.SendLocalizedMessage( 1063127 ); // You cannot use this ability while in stealth mode. + return false; + } + + if( Core.ML ) + { + BaseRanged ranged = from.Weapon as BaseRanged; + + if( ranged != null ) + { + from.SendLocalizedMessage( 1075858 ); // You can only use this with melee attacks. + return false; + } + } + + + return base.Validate( from ); + } + + public override double GetDamageScalar( Mobile attacker, Mobile defender ) + { + if ( attacker.Hidden ) + return 1.0; + + /* + * Pub40 changed pvp damage max to 55% + */ + + return 1.0 + GetBonus(attacker) / ( (Core.ML && attacker.Player && defender.Player) ? 40 : 10 ); + } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + if ( !Validate( attacker ) || !CheckMana( attacker, true ) ) + return; + + if ( GetBonus( attacker ) == 0.0 ) + { + attacker.SendLocalizedMessage( 1063101 ); // You were too close to your target to cause any additional damage. + } + else + { + attacker.FixedParticles( 0x37BE, 1, 5, 0x26BD, 0x0, 0x1, EffectLayer.Waist ); + attacker.PlaySound( 0x510 ); + + attacker.SendLocalizedMessage( 1063100 ); // Your quick flight to your target causes extra damage as you strike! + defender.FixedParticles( 0x37BE, 1, 5, 0x26BD, 0, 0x1, EffectLayer.Waist ); + + CheckGain( attacker ); + } + + ClearCurrentMove( attacker ); + } + + public override void OnClearMove( Mobile from ) + { + KiAttackInfo info = m_Table[from] as KiAttackInfo; + + if ( info != null ) + { + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + m_Table.Remove( info.m_Mobile ); + } + } + + private static Hashtable m_Table = new Hashtable(); + + public static double GetBonus( Mobile from ) + { + KiAttackInfo info = m_Table[from] as KiAttackInfo; + + if ( info == null ) + return 0.0; + + int xDelta = info.m_Location.X - from.X; + int yDelta = info.m_Location.Y - from.Y; + + double bonus = Math.Sqrt( (xDelta * xDelta) + (yDelta * yDelta) ); + + if ( bonus > 20.0 ) + bonus = 20.0; + + return bonus; + } + + private class KiAttackInfo + { + public Mobile m_Mobile; + public Point3D m_Location; + public Timer m_Timer; + + public KiAttackInfo( Mobile m ) + { + m_Mobile = m; + m_Location = m.Location; + } + } + + private static void EndKiAttack( object state ) + { + KiAttackInfo info = (KiAttackInfo)state; + + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + ClearCurrentMove( info.m_Mobile ); + info.m_Mobile.SendLocalizedMessage( 1063102 ); // You failed to complete your Ki Attack in time. + + m_Table.Remove( info.m_Mobile ); + } + } +} diff --git a/Scripts/Spells/Ninjitsu/MirrorImage.cs b/Scripts/Spells/Ninjitsu/MirrorImage.cs new file mode 100644 index 0000000..d3b8fee --- /dev/null +++ b/Scripts/Spells/Ninjitsu/MirrorImage.cs @@ -0,0 +1,269 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Spells; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server.Spells.Ninjitsu +{ + public class MirrorImage : NinjaSpell + { + private static Dictionary m_CloneCount = new Dictionary(); + + public static bool HasClone( Mobile m ) + { + return m_CloneCount.ContainsKey( m ); + } + + public static void AddClone( Mobile m ) + { + if ( m == null ) + return; + + if ( m_CloneCount.ContainsKey( m ) ) + m_CloneCount[m]++; + else + m_CloneCount[m] = 1; + } + + public static void RemoveClone( Mobile m ) + { + if ( m == null ) + return; + + if ( m_CloneCount.ContainsKey( m ) ) + { + m_CloneCount[m]--; + + if ( m_CloneCount[m] == 0 ) + m_CloneCount.Remove( m ); + } + } + + private static SpellInfo m_Info = new SpellInfo( + "Mirror Image", null, + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill{ get{ return Core.ML ? 20.0 : 40.0; } } + public override int RequiredMana{ get{ return 10; } } + + public override bool BlockedByAnimalForm{ get{ return false; } } + + public MirrorImage( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( Caster.Mounted ) + { + Caster.SendLocalizedMessage( 1063132 ); // You cannot use this ability while mounted. + return false; + } + else if ( (Caster.Followers + 1) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1063133 ); // You cannot summon a mirror image because you have too many followers. + return false; + } + else if( TransformationSpellHelper.UnderTransformation( Caster, typeof( HorrificBeastSpell ) ) ) + { + Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. + return false; + } + + return base.CheckCast(); + } + + public override bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable ) + { + return false; + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + Caster.SendLocalizedMessage( 1063134 ); // You begin to summon a mirror image of yourself. + } + + public override void OnCast() + { + if ( Caster.Mounted ) + { + Caster.SendLocalizedMessage( 1063132 ); // You cannot use this ability while mounted. + } + else if ( (Caster.Followers + 1) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1063133 ); // You cannot summon a mirror image because you have too many followers. + } + else if( TransformationSpellHelper.UnderTransformation( Caster, typeof( HorrificBeastSpell ) ) ) + { + Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. + } + else if ( CheckSequence() ) + { + Caster.FixedParticles( 0x376A, 1, 14, 0x13B5, EffectLayer.Waist ); + Caster.PlaySound( 0x511 ); + + new Clone( Caster ).MoveToWorld( Caster.Location, Caster.Map ); + } + + FinishSequence(); + } + } +} + +namespace Server.Mobiles +{ + public class Clone : BaseCreature + { + private Mobile m_Caster; + + public Clone( Mobile caster ) : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 ) + { + m_Caster = caster; + + Body = caster.Body; + + Hue = caster.Hue; + Female = caster.Female; + + Name = caster.Name; + NameHue = caster.NameHue; + + Title = caster.Title; + Kills = caster.Kills; + + HairItemID = caster.HairItemID; + HairHue = caster.HairHue; + + FacialHairItemID = caster.FacialHairItemID; + FacialHairHue = caster.FacialHairHue; + + for ( int i = 0; i < caster.Skills.Length; ++i ) + { + Skills[i].Base = caster.Skills[i].Base; + Skills[i].Cap = caster.Skills[i].Cap; + } + + for( int i = 0; i < caster.Items.Count; i++ ) + { + AddItem( CloneItem( caster.Items[i] ) ); + } + + Warmode = true; + + Summoned = true; + SummonMaster = caster; + + ControlOrder = OrderType.Follow; + ControlTarget = caster; + + TimeSpan duration = TimeSpan.FromSeconds( 30 + caster.Skills.Ninjitsu.Fixed / 40 ); + + new UnsummonTimer( caster, this, duration ).Start(); + SummonEnd = DateTime.Now + duration; + + MirrorImage.AddClone( m_Caster ); + } + + protected override BaseAI ForcedAI { get { return new CloneAI( this ); } } + + public override bool IsHumanInTown() { return false; } + + private Item CloneItem( Item item ) + { + Item newItem = new Item( item.ItemID ); + newItem.Hue = item.Hue; + newItem.Layer = item.Layer; + + return newItem; + } + + public override void OnDamage( int amount, Mobile from, bool willKill ) + { + Delete(); + } + + public override bool DeleteCorpseOnDeath { get { return true; } } + + public override void OnDelete() + { + Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 10, 15, 5042 ); + + base.OnDelete(); + } + + public override void OnAfterDelete() + { + MirrorImage.RemoveClone( m_Caster ); + base.OnAfterDelete(); + } + + public override bool IsDispellable { get { return false; } } + public override bool Commandable { get { return false; } } + + public Clone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( 0 ); // version + + writer.Write( m_Caster ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + + m_Caster = reader.ReadMobile(); + + MirrorImage.AddClone( m_Caster ); + } + } +} + + +namespace Server.Mobiles +{ + public class CloneAI : BaseAI + { + public CloneAI( Clone m ) : base ( m ) + { + m.CurrentSpeed = m.ActiveSpeed; + } + + public override bool Think() + { + // Clones only follow their owners + Mobile master = m_Mobile.SummonMaster; + + if ( master != null && master.Map == m_Mobile.Map && master.InRange( m_Mobile, m_Mobile.RangePerception ) ) + { + int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( master ); + bool bRun = (iCurrDist > 5); + + WalkMobileRange( master, 2, bRun, 0, 1 ); + } + else + WalkRandom( 2, 2, 1 ); + + return true; + } + + public override bool CanDetectHidden { get { return false; } } + } +} diff --git a/Scripts/Spells/Ninjitsu/NinjaMove.cs b/Scripts/Spells/Ninjitsu/NinjaMove.cs new file mode 100644 index 0000000..e67481a --- /dev/null +++ b/Scripts/Spells/Ninjitsu/NinjaMove.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Spells +{ + public class NinjaMove : SpecialMove + { + public override SkillName MoveSkill{ get{ return SkillName.Ninjitsu; } } + + public override void CheckGain( Mobile m ) + { + m.CheckSkill( MoveSkill, RequiredSkill - 12.5, RequiredSkill + 37.5 ); //Per five on friday 02/16/07 + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/NinjaSpell.cs b/Scripts/Spells/Ninjitsu/NinjaSpell.cs new file mode 100644 index 0000000..a363dd6 --- /dev/null +++ b/Scripts/Spells/Ninjitsu/NinjaSpell.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Spells; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Ninjitsu +{ + public abstract class NinjaSpell : Spell + { + public abstract double RequiredSkill{ get; } + public abstract int RequiredMana{ get; } + + public override SkillName CastSkill{ get{ return SkillName.Ninjitsu; } } + public override SkillName DamageSkill{ get{ return SkillName.Ninjitsu; } } + + public override bool RevealOnCast{ get{ return false; } } + public override bool ClearHandsOnCast{ get{ return false; } } + public override bool ShowHandMovement{ get{ return false; } } + + public override bool BlocksMovement{ get{ return false; } } + + //public override int CastDelayBase{ get{ return 1; } } + + public override int CastRecoveryBase{ get{ return 7; } } + + public NinjaSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public static bool CheckExpansion( Mobile from ) + { + if ( !( from is PlayerMobile ) ) + return true; + + if ( from.NetState == null ) + return false; + + return from.NetState.SupportsExpansion( Expansion.SE ); + } + + public override bool CheckCast() + { + int mana = ScaleMana( RequiredMana ); + + if ( !base.CheckCast() ) + return false; + + if ( !CheckExpansion( Caster ) ) + { + Caster.SendLocalizedMessage( 1063456 ); // You must upgrade to Samurai Empire in order to use that ability. + return false; + } + + if ( Caster.Skills[CastSkill].Value < RequiredSkill ) + { + string args = String.Format( "{0}\t{1}\t ", RequiredSkill.ToString( "F1" ), CastSkill.ToString() ); + Caster.SendLocalizedMessage( 1063013, args ); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + else if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + return true; + } + + public override bool CheckFizzle() + { + int mana = ScaleMana( RequiredMana ); + + if ( Caster.Skills[CastSkill].Value < RequiredSkill ) + { + Caster.SendLocalizedMessage( 1063352, RequiredSkill.ToString( "F1" ) ); // You need ~1_SKILL_REQUIREMENT~ Ninjitsu skill to perform that attack! + return false; + } + else if ( Caster.Mana < mana ) + { + Caster.SendLocalizedMessage( 1060174, mana.ToString() ); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + + if ( !base.CheckFizzle() ) + return false; + + Caster.Mana -= mana; + + return true; + } + + public override void GetCastSkills( out double min, out double max ) + { + min = RequiredSkill - 12.5; //Per 5 on friday 2/16/07 + max = RequiredSkill + 37.5; + } + + public override int GetMana() + { + return 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/ShadowJump.cs b/Scripts/Spells/Ninjitsu/ShadowJump.cs new file mode 100644 index 0000000..d1b7190 --- /dev/null +++ b/Scripts/Spells/Ninjitsu/ShadowJump.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Regions; +using Server.Targeting; + +namespace Server.Spells.Ninjitsu +{ + public class Shadowjump : NinjaSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Shadowjump", null, + -1, + 9002 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override double RequiredSkill{ get{ return 50.0; } } + public override int RequiredMana{ get{ return 15; } } + + public override bool BlockedByAnimalForm{ get{ return false; } } + + public Shadowjump( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + PlayerMobile pm = Caster as PlayerMobile; // IsStealthing should be moved to Server.Mobiles + if ( !pm.IsStealthing ) + { + Caster.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability. + return false; + } + + return base.CheckCast(); + } + + public override bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable ) + { + return false; + } + + public override void OnCast() + { + Caster.SendLocalizedMessage( 1063088 ); // You prepare to perform a Shadowjump. + Caster.Target = new InternalTarget( this ); + } + + public void Target(IPoint3D p) + { + IPoint3D orig = p; + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + Point3D from = Caster.Location; + Point3D to = new Point3D(p); + + PlayerMobile pm = Caster as PlayerMobile; // IsStealthing should be moved to Server.Mobiles + + if (!pm.IsStealthing) + { + Caster.SendLocalizedMessage(1063087); // You must be in stealth mode to use this ability. + } + else if (Factions.Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (Server.Misc.WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom) || !SpellHelper.CheckTravel(Caster, map, to, TravelCheckType.TeleportTo)) + { + } + else if (map == null || !map.CanSpawnMobile(p.X, p.Y, p.Z)) + { + Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. + } + else if (SpellHelper.CheckMulti(to, map, true, 5)) + { + Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. + } + else if (Region.Find(to, map).GetRegion(typeof(HouseRegion)) != null) + { + Caster.SendLocalizedMessage(502829); // Cannot teleport to that spot. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, orig); + + Mobile m = Caster; + + m.Location = to; + m.ProcessDelta(); + + Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); + + m.PlaySound(0x512); + + Server.SkillHandlers.Stealth.OnUse(m); // stealth check after the a jump + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private Shadowjump m_Owner; + + public InternalTarget( Shadowjump owner ) : base( 11, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Ninjitsu/SurpriseAttack.cs b/Scripts/Spells/Ninjitsu/SurpriseAttack.cs new file mode 100644 index 0000000..fbc4262 --- /dev/null +++ b/Scripts/Spells/Ninjitsu/SurpriseAttack.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using Server.SkillHandlers; + +namespace Server.Spells.Ninjitsu +{ + public class SurpriseAttack : NinjaMove + { + public SurpriseAttack() + { + } + + public override int BaseMana{ get{ return 20; } } + public override double RequiredSkill{ get{ return Core.ML ? 60.0 : 30.0; } } + + public override TextDefinition AbilityMessage{ get{ return new TextDefinition( 1063128 ); } } // You prepare to surprise your prey. + + public override bool Validate( Mobile from ) + { + if( !from.Hidden || from.AllowedStealthSteps <= 0 ) + { + from.SendLocalizedMessage( 1063087 ); // You must be in stealth mode to use this ability. + return false; + } + + return base.Validate( from ); + } + + public override bool OnBeforeSwing( Mobile attacker, Mobile defender ) + { + bool valid = Validate( attacker ) && CheckMana( attacker, true ); + + if( valid ) + { + attacker.BeginAction( typeof( Stealth ) ); + Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), delegate { attacker.EndAction( typeof( Stealth ) ); } ); + } + + return valid; + + } + + public override bool ValidatesDuringHit { get { return false; } } + + public override void OnHit( Mobile attacker, Mobile defender, int damage ) + { + //Validates before swing + + ClearCurrentMove( attacker ); + + attacker.SendLocalizedMessage( 1063129 ); // You catch your opponent off guard with your Surprise Attack! + defender.SendLocalizedMessage( 1063130 ); // Your defenses are lowered as your opponent surprises you! + + defender.FixedParticles( 0x37B9, 1, 5, 0x26DA, 0, 3, EffectLayer.Head ); + + attacker.RevealingAction(); + + SurpriseAttackInfo info; + + if ( m_Table.Contains( defender ) ) + { + info = (SurpriseAttackInfo)m_Table[defender]; + + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + m_Table.Remove( defender ); + } + + int ninjitsu = attacker.Skills[SkillName.Ninjitsu].Fixed; + + int malus = ninjitsu / 60 + (int)Tracking.GetStalkingBonus( attacker, defender ); + + info = new SurpriseAttackInfo( defender, malus ); + info.m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 8.0 ), new TimerStateCallback( EndSurprise ), info ); + + m_Table[defender] = info; + + CheckGain( attacker ); + } + + public override void OnMiss( Mobile attacker, Mobile defender ) + { + ClearCurrentMove( attacker ); + + attacker.SendLocalizedMessage( 1063161 ); // You failed to properly use the element of surprise. + + attacker.RevealingAction(); + } + + + private static Hashtable m_Table = new Hashtable(); + + public static bool GetMalus( Mobile target, ref int malus ) + { + SurpriseAttackInfo info = m_Table[target] as SurpriseAttackInfo; + + if ( info == null ) + return false; + + malus = info.m_Malus; + return true; + } + + private class SurpriseAttackInfo + { + public Mobile m_Target; + public int m_Malus; + public Timer m_Timer; + + public SurpriseAttackInfo( Mobile target, int effect ) + { + m_Target = target; + m_Malus = effect; + } + } + + private static void EndSurprise( object state ) + { + SurpriseAttackInfo info = (SurpriseAttackInfo)state; + + if ( info.m_Timer != null ) + info.m_Timer.Stop(); + + info.m_Target.SendLocalizedMessage( 1063131 ); // Your defenses have returned to normal. + + m_Table.Remove( info.m_Target ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Reagent.cs b/Scripts/Spells/Reagent.cs new file mode 100644 index 0000000..9800744 --- /dev/null +++ b/Scripts/Spells/Reagent.cs @@ -0,0 +1,213 @@ +using System; +using Server.Items; + +namespace Server.Spells +{ + public class Reagent + { + private static Type[] m_Types = new Type[27] // Scriptiz : default is 13 + { + typeof( BlackPearl ), + typeof( Bloodmoss ), + typeof( Garlic ), + typeof( Ginseng ), + typeof( MandrakeRoot ), + typeof( Nightshade ), + typeof( SulfurousAsh ), + typeof( SpidersSilk ), + typeof( BatWing ), + typeof( GraveDust ), + typeof( DaemonBlood ), + typeof( NoxCrystal ), + typeof( PigIron ), + + // Scriptiz : ajouts des r�actifs pour les sorts n�cros de Vivre + typeof(Blackmoor), + typeof(Bloodspawn), + typeof(BloodVial), + typeof(Brimstone), + typeof(EyeOfNewt), + typeof(Obsidian), + typeof(Bone), + typeof(FertileDirt), + typeof(ExecutionersCap), + typeof(DaemonBone), + typeof(DaemonBlood), + + // VIKING : ajout des regs pour druidisme + typeof( Pumice ), + typeof( PetrifiedWood ), + typeof( SpringWater ) + + + + }; + + public Type[] Types + { + get{ return m_Types; } + } + + public static Type BlackPearl + { + get{ return m_Types[0]; } + set{ m_Types[0] = value; } + } + + public static Type Bloodmoss + { + get{ return m_Types[1]; } + set{ m_Types[1] = value; } + } + + public static Type Garlic + { + get{ return m_Types[2]; } + set{ m_Types[2] = value; } + } + + public static Type Ginseng + { + get{ return m_Types[3]; } + set{ m_Types[3] = value; } + } + + public static Type MandrakeRoot + { + get{ return m_Types[4]; } + set{ m_Types[4] = value; } + } + + public static Type Nightshade + { + get{ return m_Types[5]; } + set{ m_Types[5] = value; } + } + + public static Type SulfurousAsh + { + get{ return m_Types[6]; } + set{ m_Types[6] = value; } + } + + public static Type SpidersSilk + { + get{ return m_Types[7]; } + set{ m_Types[7] = value; } + } + + public static Type BatWing + { + get{ return m_Types[8]; } + set{ m_Types[8] = value; } + } + + public static Type GraveDust + { + get{ return m_Types[9]; } + set{ m_Types[9] = value; } + } + + public static Type DaemonBlood + { + get{ return m_Types[10]; } + set{ m_Types[10] = value; } + } + + public static Type NoxCrystal + { + get{ return m_Types[11]; } + set{ m_Types[11] = value; } + } + + public static Type PigIron + { + get{ return m_Types[12]; } + set{ m_Types[12] = value; } + } + + // Scriptiz : Ajout des r�actifs pour Vivre + public static Type Blackmoor + { + get { return m_Types[13]; } + set { m_Types[13] = value; } + } + + public static Type Bloodspawn + { + get { return m_Types[14]; } + set { m_Types[14] = value; } + } + + public static Type BloodVial + { + get { return m_Types[15]; } + set { m_Types[15] = value; } + } + + public static Type Brimstone + { + get { return m_Types[16]; } + set { m_Types[16] = value; } + } + + public static Type EyeOfNewt + { + get { return m_Types[17]; } + set { m_Types[17] = value; } + } + + public static Type Obsidian + { + get { return m_Types[18]; } + set { m_Types[18] = value; } + } + + public static Type Bone + { + get { return m_Types[19]; } + set { m_Types[19] = value; } + } + + public static Type FertileDirt + { + get { return m_Types[20]; } + set { m_Types[20] = value; } + } + + public static Type ExecutionersCap + { + get { return m_Types[21]; } + set { m_Types[21] = value; } + } + + public static Type DaemonBone + { + get { return m_Types[22]; } + set { m_Types[22] = value; } + } + + public static Type DragonBlood + { + get { return m_Types[23]; } + set { m_Types[23] = value; } + } + + public static Type Pumice + { + get { return m_Types[24]; } + set { m_Types[8] = value; } + } + + public static Type PetrifiedWood + { + get { return m_Types[25]; } + set { m_Types[15] = value; } + } + public static Type SpringWater + { + get { return m_Types[26]; } + set { m_Types[16] = value; } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/Agility.cs b/Scripts/Spells/Second/Agility.cs new file mode 100644 index 0000000..6956c2d --- /dev/null +++ b/Scripts/Spells/Second/Agility.cs @@ -0,0 +1,86 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Second +{ + public class AgilitySpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Agility", "Ex Uus", + 212, + 9061, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public AgilitySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.AddStatBonus( Caster, m, StatType.Dex ); + + m.FixedParticles( 0x375A, 10, 15, 5010, EffectLayer.Waist ); + m.PlaySound( 0x1e7 ); + + int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, false )*100); + TimeSpan length = SpellHelper.GetDuration( Caster, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Agility, 1075841, length, m, percentage.ToString() ) ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private AgilitySpell m_Owner; + + public InternalTarget( AgilitySpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/Cunning.cs b/Scripts/Spells/Second/Cunning.cs new file mode 100644 index 0000000..6629dbd --- /dev/null +++ b/Scripts/Spells/Second/Cunning.cs @@ -0,0 +1,86 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Second +{ + public class CunningSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Cunning", "Uus Wis", + 212, + 9061, + Reagent.MandrakeRoot, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public CunningSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.AddStatBonus( Caster, m, StatType.Int ); + + m.FixedParticles( 0x375A, 10, 15, 5011, EffectLayer.Head ); + m.PlaySound( 0x1EB ); + + int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, false )*100); + TimeSpan length = SpellHelper.GetDuration( Caster, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Cunning, 1075843, length, m, percentage.ToString() ) ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private CunningSpell m_Owner; + + public InternalTarget( CunningSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/Cure.cs b/Scripts/Spells/Second/Cure.cs new file mode 100644 index 0000000..86622d4 --- /dev/null +++ b/Scripts/Spells/Second/Cure.cs @@ -0,0 +1,102 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Second +{ + public class CureSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Cure", "An Nox", + 212, + 9061, + Reagent.Garlic, + Reagent.Ginseng + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public CureSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + Poison p = m.Poison; + + if ( p != null ) + { + int chanceToCure = 10000 + (int)(Caster.Skills[SkillName.Magery].Value * 75) - ((p.Level + 1) * (Core.AOS ? (p.Level < 4 ? 3300 : 3100) : 1750)); + chanceToCure /= 100; + + if ( chanceToCure > Utility.Random( 100 ) ) + { + if ( m.CurePoison( Caster ) ) + { + if ( Caster != m ) + Caster.SendLocalizedMessage( 1010058 ); // You have cured the target of all poisons! + + m.SendLocalizedMessage( 1010059 ); // You have been cured of all poisons. + } + } + else + { + m.SendLocalizedMessage( 1010060 ); // You have failed to cure your target! + } + } + + m.FixedParticles( 0x373A, 10, 15, 5012, EffectLayer.Waist ); + m.PlaySound( 0x1E0 ); + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private CureSpell m_Owner; + + public InternalTarget( CureSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/Harm.cs b/Scripts/Spells/Second/Harm.cs new file mode 100644 index 0000000..410716e --- /dev/null +++ b/Scripts/Spells/Second/Harm.cs @@ -0,0 +1,114 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Second +{ + public class HarmSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Harm", "An Mani", + 212, + Core.AOS ? 9001 : 9041, + Reagent.Nightshade, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public HarmSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return false; } } + + + public override double GetSlayerDamageScalar( Mobile target ) + { + return 1.0; //This spell isn't affected by slayer spellbooks + } + + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + double damage; + + if ( Core.AOS ) + { + damage = GetNewAosDamage( 17, 1, 5, m ); + } + else + { + damage = Utility.Random( 1, 15 ); + + if ( CheckResisted( m ) ) + { + damage *= 0.75; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar( m ); + } + + if ( !m.InRange( Caster, 2 ) ) + damage *= 0.25; // 1/4 damage at > 2 tile range + else if ( !m.InRange( Caster, 1 ) ) + damage *= 0.50; // 1/2 damage at 2 tile range + + if ( Core.AOS ) + { + m.FixedParticles( 0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist ); + m.PlaySound( 0x0FC ); + } + else + { + m.FixedParticles( 0x374A, 10, 15, 5013, EffectLayer.Waist ); + m.PlaySound( 0x1F1 ); + } + + SpellHelper.Damage( this, m, damage, 0, 0, 100, 0, 0 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private HarmSpell m_Owner; + + public InternalTarget( HarmSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/MagicTrap.cs b/Scripts/Spells/Second/MagicTrap.cs new file mode 100644 index 0000000..11ddfa9 --- /dev/null +++ b/Scripts/Spells/Second/MagicTrap.cs @@ -0,0 +1,89 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Items; + +namespace Server.Spells.Second +{ + public class MagicTrapSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Magic Trap", "In Jux", + 212, + 9001, + Reagent.Garlic, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public MagicTrapSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( TrapableContainer item ) + { + if ( !Caster.CanSee( item ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( item.TrapType != TrapType.None && item.TrapType != TrapType.MagicTrap ) + { + base.DoFizzle(); + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, item ); + + item.TrapType = TrapType.MagicTrap; + item.TrapPower = Core.AOS ? Utility.RandomMinMax( 10, 50 ) : 1; + item.TrapLevel = 0; + + Point3D loc = item.GetWorldLocation(); + + Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X + 1, loc.Y, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 ); + Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X, loc.Y - 1, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 ); + Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X - 1, loc.Y, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 ); + Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X, loc.Y + 1, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 9502 ); + Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc.X, loc.Y, loc.Z ), item.Map, EffectItem.DefaultDuration ), 0, 0, 0, 5014 ); + + Effects.PlaySound( loc, item.Map, 0x1EF ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MagicTrapSpell m_Owner; + + public InternalTarget( MagicTrapSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is TrapableContainer ) + { + m_Owner.Target( (TrapableContainer)o ); + } + else + { + from.SendMessage( "You can't trap that" ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/Protection.cs b/Scripts/Spells/Second/Protection.cs new file mode 100644 index 0000000..793d947 --- /dev/null +++ b/Scripts/Spells/Second/Protection.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Second +{ + public class ProtectionSpell : MagerySpell + { + private static Hashtable m_Registry = new Hashtable(); + public static Hashtable Registry { get { return m_Registry; } } + + private static SpellInfo m_Info = new SpellInfo( + "Protection", "Uus Sanct", + 236, + 9011, + Reagent.Garlic, + Reagent.Ginseng, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public ProtectionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( Core.AOS ) + return true; + + if ( m_Registry.ContainsKey( Caster ) ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + return false; + } + else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + return false; + } + + return true; + } + + private static Hashtable m_Table = new Hashtable(); + + public static void Toggle( Mobile caster, Mobile target ) + { + /* Players under the protection spell effect can no longer have their spells "disrupted" when hit. + * Players under the protection spell have decreased physical resistance stat value (-15 + (Inscription/20), + * a decreased "resisting spells" skill value by -35 + (Inscription/20), + * and a slower casting speed modifier (technically, a negative "faster cast speed") of 2 points. + * The protection spell has an indefinite duration, becoming active when cast, and deactivated when re-cast. + * Reactive Armor, Protection, and Magic Reflection will stay on�even after logging out, + * even after dying�until you �turn them off� by casting them again. + */ + + object[] mods = (object[])m_Table[target]; + + if ( mods == null ) + { + target.PlaySound( 0x1E9 ); + target.FixedParticles( 0x375A, 9, 20, 5016, EffectLayer.Waist ); + + mods = new object[2] + { + new ResistanceMod( ResistanceType.Physical, -15 + Math.Min( (int)(caster.Skills[SkillName.Inscribe].Value / 20), 15 ) ), + new DefaultSkillMod( SkillName.MagicResist, true, -35 + Math.Min( (int)(caster.Skills[SkillName.Inscribe].Value / 20), 35 ) ) + }; + + m_Table[target] = mods; + Registry[target] = 100.0; + + target.AddResistanceMod( (ResistanceMod)mods[0] ); + target.AddSkillMod( (SkillMod)mods[1] ); + + int physloss = -15 + (int) (caster.Skills[SkillName.Inscribe].Value / 20); + int resistloss = -35 + (int) (caster.Skills[SkillName.Inscribe].Value / 20); + string args = String.Format("{0}\t{1}", physloss, resistloss); + BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Protection, 1075814, 1075815, args.ToString())); + } + else + { + target.PlaySound( 0x1ED ); + target.FixedParticles( 0x375A, 9, 20, 5016, EffectLayer.Waist ); + + m_Table.Remove( target ); + Registry.Remove( target ); + + target.RemoveResistanceMod( (ResistanceMod)mods[0] ); + target.RemoveSkillMod( (SkillMod)mods[1] ); + + BuffInfo.RemoveBuff(target, BuffIcon.Protection); + } + } + + public static void EndProtection(Mobile m) + { + if (m_Table.Contains(m)) + { + object[] mods = (object[])m_Table[m]; + + m_Table.Remove(m); + Registry.Remove(m); + + m.RemoveResistanceMod((ResistanceMod)mods[0]); + m.RemoveSkillMod((SkillMod)mods[1]); + + BuffInfo.RemoveBuff(m, BuffIcon.Protection); + } + } + + public override void OnCast() + { + if ( Core.AOS ) + { + if ( CheckSequence() ) + Toggle( Caster, Caster ); + + FinishSequence(); + } + else + { + if ( m_Registry.ContainsKey( Caster ) ) + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + else if ( !Caster.CanBeginAction( typeof( DefensiveSpell ) ) ) + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + } + else if ( CheckSequence() ) + { + if ( Caster.BeginAction( typeof( DefensiveSpell ) ) ) + { + double value = (int)(Caster.Skills[SkillName.EvalInt].Value + Caster.Skills[SkillName.Meditation].Value + Caster.Skills[SkillName.Inscribe].Value); + value /= 4; + + if ( value < 0 ) + value = 0; + else if ( value > 75 ) + value = 75.0; + + Registry.Add( Caster, value ); + new InternalTimer( Caster ).Start(); + + Caster.FixedParticles( 0x375A, 9, 20, 5016, EffectLayer.Waist ); + Caster.PlaySound( 0x1ED ); + } + else + { + Caster.SendLocalizedMessage( 1005385 ); // The spell will not adhere to you at this time. + } + } + + FinishSequence(); + } + } + + private class InternalTimer : Timer + { + private Mobile m_Caster; + + public InternalTimer( Mobile caster ) : base( TimeSpan.FromSeconds( 0 ) ) + { + double val = caster.Skills[SkillName.Magery].Value * 2.0; + if ( val < 15 ) + val = 15; + else if ( val > 240 ) + val = 240; + + m_Caster = caster; + Delay = TimeSpan.FromSeconds( val ); + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + ProtectionSpell.Registry.Remove( m_Caster ); + DefensiveSpell.Nullify( m_Caster ); + } + } + } +} diff --git a/Scripts/Spells/Second/RemoveTrap.cs b/Scripts/Spells/Second/RemoveTrap.cs new file mode 100644 index 0000000..868103f --- /dev/null +++ b/Scripts/Spells/Second/RemoveTrap.cs @@ -0,0 +1,84 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Items; + +namespace Server.Spells.Second +{ + public class RemoveTrapSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Remove Trap", "An Jux", + 212, + 9001, + Reagent.Bloodmoss, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public RemoveTrapSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + Caster.SendMessage( "What do you wish to untrap?" ); + } + + public void Target( TrapableContainer item ) + { + if ( !Caster.CanSee( item ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( item.TrapType != TrapType.None && item.TrapType != TrapType.MagicTrap ) + { + base.DoFizzle(); + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, item ); + + Point3D loc = item.GetWorldLocation(); + + Effects.SendLocationParticles( EffectItem.Create( loc, item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5015 ); + Effects.PlaySound( loc, item.Map, 0x1F0 ); + + item.TrapType = TrapType.None; + item.TrapPower = 0; + item.TrapLevel = 0; + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private RemoveTrapSpell m_Owner; + + public InternalTarget( RemoveTrapSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is TrapableContainer ) + { + m_Owner.Target( (TrapableContainer)o ); + } + else + { + from.SendMessage( "You can't disarm that" ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Second/Strength.cs b/Scripts/Spells/Second/Strength.cs new file mode 100644 index 0000000..32587c5 --- /dev/null +++ b/Scripts/Spells/Second/Strength.cs @@ -0,0 +1,86 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Second +{ + public class StrengthSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Strength", "Uus Mani", + 212, + 9061, + Reagent.MandrakeRoot, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Second; } } + + public StrengthSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.AddStatBonus( Caster, m, StatType.Str ); + + m.FixedParticles( 0x375A, 10, 15, 5017, EffectLayer.Waist ); + m.PlaySound( 0x1EE ); + + int percentage = (int)(SpellHelper.GetOffsetScalar( Caster, m, false )*100); + TimeSpan length = SpellHelper.GetDuration( Caster, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Strength, 1075845, length, m, percentage.ToString() ) ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private StrengthSpell m_Owner; + + public InternalTarget( StrengthSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/ChainLightning.cs b/Scripts/Spells/Seventh/ChainLightning.cs new file mode 100644 index 0000000..0f13db1 --- /dev/null +++ b/Scripts/Spells/Seventh/ChainLightning.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class ChainLightningSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Chain Lightning", "Vas Ort Grav", + 209, + 9022, + false, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + public ChainLightningSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return true; } } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + if ( p is Item ) + p = ((Item)p).GetWorldLocation(); + + List targets = new List(); + + Map map = Caster.Map; + + bool playerVsPlayer = false; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 2 ); + + foreach ( Mobile m in eable ) + { + if ( Core.AOS && m == Caster ) + continue; + + if ( SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) ) + { + if ( Core.AOS && !Caster.InLOS( m ) ) + continue; + + targets.Add( m ); + + if ( m.Player ) + playerVsPlayer = true; + } + } + + eable.Free(); + } + + double damage; + + if ( Core.AOS ) + damage = GetNewAosDamage( 51, 1, 5, playerVsPlayer ); + else + damage = Utility.Random( 27, 22 ); + + if ( targets.Count > 0 ) + { + if ( Core.AOS && targets.Count > 2 ) + damage = (damage * 2) / targets.Count; + else if ( !Core.AOS ) + damage /= targets.Count; + + double toDeal; + + for ( int i = 0; i < targets.Count; ++i ) + { + toDeal = damage; + Mobile m = targets[i]; + + if ( !Core.AOS && CheckResisted( m ) ) + { + toDeal *= 0.5; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + toDeal *= GetDamageScalar(m); + Caster.DoHarmful( m ); + SpellHelper.Damage( this, m, toDeal, 0, 0, 0, 0, 100 ); + + m.BoltEffect( 0 ); + } + } + else + { + Caster.PlaySound ( 0x29 ); + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private ChainLightningSpell m_Owner; + + public InternalTarget( ChainLightningSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/EnergyField.cs b/Scripts/Spells/Seventh/EnergyField.cs new file mode 100644 index 0000000..127461c --- /dev/null +++ b/Scripts/Spells/Seventh/EnergyField.cs @@ -0,0 +1,208 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Seventh +{ + public class EnergyFieldSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Energy Field", "In Sanct Grav", + 221, + 9022, + false, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + public EnergyFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + { + eastToWest = false; + } + else if ( rx >= 0 ) + { + eastToWest = true; + } + else if ( ry >= 0 ) + { + eastToWest = true; + } + else + { + eastToWest = false; + } + + Effects.PlaySound( p, Caster.Map, 0x20B ); + + TimeSpan duration; + + if ( Core.AOS ) + duration = TimeSpan.FromSeconds( (15 + (Caster.Skills.Magery.Fixed / 5)) / 7 ); + else + duration = TimeSpan.FromSeconds( Caster.Skills[SkillName.Magery].Value * 0.28 + 2.0 ); // (28% of magery) + 2.0 seconds + + int itemID = eastToWest ? 0x3946 : 0x3956; + + for ( int i = -2; i <= 2; ++i ) + { + Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z ); + bool canFit = SpellHelper.AdjustField( ref loc, Caster.Map, 12, false ); + + if ( !canFit ) + continue; + + Item item = new InternalItem( loc, Caster.Map, duration, itemID, Caster ); + item.ProcessDelta(); + + Effects.SendLocationParticles( EffectItem.Create( loc, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5051 ); + } + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private Mobile m_Caster; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, TimeSpan duration, int itemID, Mobile caster ) : base( itemID ) + { + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld( loc, map ); + + m_Caster = caster; + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 5.0 ) ); + m_Timer.Start(); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override bool OnMoveOver( Mobile m ) + { + int noto; + + if ( m is PlayerMobile ) + { + noto = Notoriety.Compute( m_Caster, m ); + if ( noto == Notoriety.Enemy || noto == Notoriety.Ally ) + return false; + } + return base.OnMoveOver( m ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + + public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + private class InternalTarget : Target + { + private EnergyFieldSpell m_Owner; + + public InternalTarget( EnergyFieldSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/FlameStrike.cs b/Scripts/Spells/Seventh/FlameStrike.cs new file mode 100644 index 0000000..9ec40f5 --- /dev/null +++ b/Scripts/Spells/Seventh/FlameStrike.cs @@ -0,0 +1,94 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Seventh +{ + public class FlameStrikeSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Flame Strike", "Kal Vas Flam", + 245, + 9042, + Reagent.SpidersSilk, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + public FlameStrikeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return true; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + double damage; + + if ( Core.AOS ) + { + damage = GetNewAosDamage( 48, 1, 5, m ); + } + else + { + damage = Utility.Random( 27, 22 ); + + if ( CheckResisted( m ) ) + { + damage *= 0.6; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar( m ); + } + + m.FixedParticles( 0x3709, 10, 30, 5052, EffectLayer.LeftFoot ); + m.PlaySound( 0x208 ); + + SpellHelper.Damage( this, m, damage, 0, 100, 0, 0, 0 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private FlameStrikeSpell m_Owner; + + public InternalTarget( FlameStrikeSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/GateTravel.cs b/Scripts/Spells/Seventh/GateTravel.cs new file mode 100644 index 0000000..6a4a40e --- /dev/null +++ b/Scripts/Spells/Seventh/GateTravel.cs @@ -0,0 +1,258 @@ +using System; +using Server.Network; +using Server.Multis; +using Server.Items; +using Server.Targeting; +using Server.Misc; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Spells.Seventh +{ + public class GateTravelSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Gate Travel", "Vas Rel Por", + 263, + 9032, + Reagent.BlackPearl, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + private RunebookEntry m_Entry; + + public GateTravelSpell( Mobile caster, Item scroll ) : this( caster, scroll, null ) + { + } + + public GateTravelSpell( Mobile caster, Item scroll, RunebookEntry entry ) : base( caster, scroll, m_Info ) + { + m_Entry = entry; + } + + public override void OnCast() + { + if ( m_Entry == null ) + Caster.Target = new InternalTarget( this ); + else + Effect( m_Entry.Location, m_Entry.Map, true ); + } + + public override bool CheckCast() + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return false; + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + return false; + } + + return SpellHelper.CheckTravel( Caster, TravelCheckType.GateFrom ); + } + + private bool GateExistsAt(Map map, Point3D loc ) + { + bool _gateFound = false; + + IPooledEnumerable eable = map.GetItemsInRange( loc, 0 ); + foreach ( Item item in eable ) + { + if ( item is Moongate || item is PublicMoongate ) + { + _gateFound = true; + break; + } + } + eable.Free(); + + return _gateFound; + } + + public void Effect( Point3D loc, Map map, bool checkMulti ) + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + } + else if ( map == null || (!Core.AOS && Caster.Map != map) ) + { + Caster.SendLocalizedMessage( 1005570 ); // You can not gate to another facet. + } + else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.GateFrom ) ) + { + } + else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.GateTo ) ) + { + } + else if ( map == Map.Felucca && Caster is PlayerMobile && ((PlayerMobile)Caster).Young ) + { + Caster.SendLocalizedMessage( 1049543 ); // You decide against traveling to Felucca while you are still young. + } + else if ( Caster.Kills >= 5 && map != Map.Felucca ) + { + Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + } + else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( Core.SE && ( GateExistsAt( map, loc ) || GateExistsAt( Caster.Map, Caster.Location ) ) ) // SE restricted stacking gates + { + Caster.SendLocalizedMessage( 1071242 ); // There is already a gate there. + } + else if ( CheckSequence() ) + { + Caster.SendLocalizedMessage( 501024 ); // You open a magical gate to another location + + Effects.PlaySound( Caster.Location, Caster.Map, 0x20E ); + + InternalItem firstGate = new InternalItem( loc, map ); + firstGate.MoveToWorld( Caster.Location, Caster.Map ); + + Effects.PlaySound( loc, map, 0x20E ); + + InternalItem secondGate = new InternalItem( Caster.Location, Caster.Map ); + secondGate.MoveToWorld( loc, map ); + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Moongate + { + public override bool ShowFeluccaWarning{ get{ return Core.AOS; } } + + public InternalItem( Point3D target, Map map ) : base( target, map ) + { + Map = map; + + if ( ShowFeluccaWarning && map == Map.Felucca ) + ItemID = 0xDDA; + + Dispellable = true; + + InternalTimer t = new InternalTimer( this ); + t.Start(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + Delete(); + } + + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + private class InternalTarget : Target + { + private GateTravelSpell m_Owner; + + public InternalTarget( GateTravelSpell owner ) : base( 12, false, TargetFlags.None ) + { + m_Owner = owner; + + owner.Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501029 ); // Select Marked item. + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is RecallRune ) + { + RecallRune rune = (RecallRune)o; + + if ( rune.Marked ) + m_Owner.Effect( rune.Target, rune.TargetMap, true ); + else + from.SendLocalizedMessage( 501803 ); // That rune is not yet marked. + } + else if ( o is Runebook ) + { + RunebookEntry e = ((Runebook)o).Default; + + if ( e != null ) + m_Owner.Effect( e.Location, e.Map, true ); + else + from.SendLocalizedMessage( 502354 ); // Target is not marked. + } + /*else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat ) + { + BaseBoat boat = ((Key)o).Link as BaseBoat; + + if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) ) + m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false ); + else + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 501030, from.Name, "" ) ); // I can not gate travel from that object. + }*/ + else if (o is HouseRaffleDeed && ((HouseRaffleDeed)o).ValidLocation()) + { + HouseRaffleDeed deed = (HouseRaffleDeed)o; + + m_Owner.Effect(deed.PlotLocation, deed.PlotFacet, true); + } + else + { + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 501030, from.Name, "" ) ); // I can not gate travel from that object. + } + } + + protected override void OnNonlocalTarget( Mobile from, object o ) + { + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/ManaVampire.cs b/Scripts/Spells/Seventh/ManaVampire.cs new file mode 100644 index 0000000..4ef254e --- /dev/null +++ b/Scripts/Spells/Seventh/ManaVampire.cs @@ -0,0 +1,122 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Seventh +{ + public class ManaVampireSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mana Vampire", "Ort Sanct", + 221, + 9032, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + public ManaVampireSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + int toDrain = 0; + + if ( Core.AOS ) + { + toDrain = (int)(GetDamageSkill( Caster ) - GetResistSkill( m )); + + if ( !m.Player ) + toDrain /= 2; + + if ( toDrain < 0 ) + toDrain = 0; + else if ( toDrain > m.Mana ) + toDrain = m.Mana; + } + else + { + if ( CheckResisted( m ) ) + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + else + toDrain = m.Mana; + } + + if ( toDrain > (Caster.ManaMax - Caster.Mana) ) + toDrain = Caster.ManaMax - Caster.Mana; + + m.Mana -= toDrain; + Caster.Mana += toDrain; + + if ( Core.AOS ) + { + m.FixedParticles( 0x374A, 1, 15, 5054, 23, 7, EffectLayer.Head ); + m.PlaySound( 0x1F9 ); + + Caster.FixedParticles( 0x0000, 10, 5, 2054, EffectLayer.Head ); + } + else + { + m.FixedParticles( 0x374A, 10, 15, 5054, EffectLayer.Head ); + m.PlaySound( 0x1F9 ); + } + + HarmfulSpell(m); + } + + FinishSequence(); + } + + public override double GetResistPercent( Mobile target ) + { + return 98.0; + } + + private class InternalTarget : Target + { + private ManaVampireSpell m_Owner; + + public InternalTarget( ManaVampireSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/MassDispel.cs b/Scripts/Spells/Seventh/MassDispel.cs new file mode 100644 index 0000000..737a18e --- /dev/null +++ b/Scripts/Spells/Seventh/MassDispel.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using Server.Misc; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Seventh +{ + public class MassDispelSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mass Dispel", "Vas An Ort", + 263, + 9002, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.BlackPearl, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + public MassDispelSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckSequence() ) + { + // Scriptiz : si monstre, il ne perd pas de Mana ! + if (!(Caster is PlayerMobile)) Caster.Mana += 70; + + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + List targets = new List(); + + Map map = Caster.Map; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 8 ); + + foreach ( Mobile m in eable ) + if ( m is BaseCreature && (m as BaseCreature).IsDispellable && Caster.CanBeHarmful( m, false ) ) + targets.Add( m ); + + eable.Free(); + } + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + BaseCreature bc = m as BaseCreature; + + if ( bc == null ) + continue; + + double dispelChance = (50.0 + ((100 * (Caster.Skills.Magery.Value - bc.DispelDifficulty)) / (bc.DispelFocus*2))) / 100; + + if ( dispelChance > Utility.RandomDouble() ) + { + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 ); + Effects.PlaySound( m, m.Map, 0x201 ); + + m.Delete(); + } + else + { + Caster.DoHarmful( m ); + + m.FixedEffect( 0x3779, 10, 20 ); + } + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MassDispelSpell m_Owner; + + public InternalTarget( MassDispelSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/MeteorSwarm.cs b/Scripts/Spells/Seventh/MeteorSwarm.cs new file mode 100644 index 0000000..a4767e6 --- /dev/null +++ b/Scripts/Spells/Seventh/MeteorSwarm.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Seventh +{ + public class MeteorSwarmSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Meteor Swarm", "Flam Kal Des Ylem", + 233, + 9042, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + public MeteorSwarmSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return true; } } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + if ( p is Item ) + p = ((Item)p).GetWorldLocation(); + + List targets = new List(); + + Map map = Caster.Map; + + bool playerVsPlayer = false; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 2 ); + + foreach ( Mobile m in eable ) + { + if ( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) ) + { + if ( Core.AOS && !Caster.InLOS( m ) ) + continue; + + targets.Add( m ); + + if ( m.Player ) + playerVsPlayer = true; + } + } + + eable.Free(); + } + + double damage; + + if ( Core.AOS ) + damage = GetNewAosDamage( 51, 1, 5, playerVsPlayer ); + else + damage = Utility.Random( 27, 22 ); + + if ( targets.Count > 0 ) + { + Effects.PlaySound( p, Caster.Map, 0x160 ); + + if ( Core.AOS && targets.Count > 2 ) + damage = (damage * 2) / targets.Count; + else if ( !Core.AOS ) + damage /= targets.Count; + + double toDeal; + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + toDeal = damage; + + if ( !Core.AOS && CheckResisted( m ) ) + { + damage *= 0.5; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + toDeal *= GetDamageScalar(m); + Caster.DoHarmful( m ); + SpellHelper.Damage( this, m, toDeal, 0, 100, 0, 0, 0 ); + + Caster.MovingParticles( m, 0x36D4, 7, 0, false, true, 9501, 1, 0, 0x100 ); + } + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MeteorSwarmSpell m_Owner; + + public InternalTarget( MeteorSwarmSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Seventh/Polymorph.cs b/Scripts/Spells/Seventh/Polymorph.cs new file mode 100644 index 0000000..b072a25 --- /dev/null +++ b/Scripts/Spells/Seventh/Polymorph.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Spells; +using Server.Spells.Fifth; +using Server.Mobiles; + +namespace Server.Spells.Seventh +{ + public class PolymorphSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Polymorph", "Vas Ylem Rel", + 221, + 9002, + Reagent.Bloodmoss, + Reagent.SpidersSilk, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + + private int m_NewBody; + + public PolymorphSpell( Mobile caster, Item scroll, int body ) : base( caster, scroll, m_Info ) + { + m_NewBody = body; + } + + public PolymorphSpell( Mobile caster, Item scroll ) : this(caster,scroll,0) + { + } + + public override bool CheckCast() + { + /*if ( Caster.Mounted ) + { + Caster.SendLocalizedMessage( 1042561 ); //Please dismount first. + return false; + } + else */ + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1010521 ); // You cannot polymorph while you have a Town Sigil + return false; + } + else if( TransformationSpellHelper.UnderTransformation( Caster ) ) + { + Caster.SendLocalizedMessage( 1061633 ); // You cannot polymorph while in that form. + return false; + } + else if ( DisguiseTimers.IsDisguised( Caster ) ) + { + Caster.SendLocalizedMessage( 502167 ); // You cannot polymorph while disguised. + return false; + } + else if ( Caster.BodyMod == 183 || Caster.BodyMod == 184 ) + { + Caster.SendLocalizedMessage( 1042512 ); // You cannot polymorph while wearing body paint + return false; + } + else if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + if( Core.ML ) + EndPolymorph( Caster ); + else + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + return false; + } + else if ( m_NewBody == 0 ) + { + Gump gump; + if ( Core.SE ) + gump = new NewPolymorphGump( Caster, Scroll ); + else + gump = new PolymorphGump( Caster, Scroll ); + + Caster.SendGump( gump ); + return false; + } + + return true; + } + + // Scriptiz : le sort ne coute pas de r�actifs si utilis� par une f�e pour se transformer en f�e + public override bool ConsumeReagents() + { + // Scriptiz : le sort ne bouffe pas de r�actifs si c'est une f�e qui se transforme en f�e + if (m_NewBody == 128 && Caster is PlayerMobile && ((PlayerMobile)Caster).IsFairy) + return true; + + return base.ConsumeReagents(); + } + + public override void OnCast() + { + /*if ( Caster.Mounted ) + { + Caster.SendLocalizedMessage( 1042561 ); //Please dismount first. + } + else */ + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1010521 ); // You cannot polymorph while you have a Town Sigil + } + else if ( !Caster.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + if( Core.ML ) + EndPolymorph( Caster ); + else + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + else if( TransformationSpellHelper.UnderTransformation( Caster ) ) + { + Caster.SendLocalizedMessage( 1061633 ); // You cannot polymorph while in that form. + } + else if ( DisguiseTimers.IsDisguised( Caster ) ) + { + Caster.SendLocalizedMessage( 502167 ); // You cannot polymorph while disguised. + } + else if ( Caster.BodyMod == 183 || Caster.BodyMod == 184 ) + { + Caster.SendLocalizedMessage( 1042512 ); // You cannot polymorph while wearing body paint + } + else if ( !Caster.CanBeginAction( typeof( IncognitoSpell ) ) || Caster.IsBodyMod ) + { + DoFizzle(); + } + else if ( CheckSequence() ) + { + if ( Caster.BeginAction( typeof( PolymorphSpell ) ) ) + { + if ( m_NewBody != 0 ) + { + if ( !((Body)m_NewBody).IsHuman ) + { + Mobiles.IMount mt = Caster.Mount; + + if ( mt != null ) + mt.Rider = null; + } + + Caster.BodyMod = m_NewBody; + + if ( m_NewBody == 400 || m_NewBody == 401 ) + Caster.HueMod = Utility.RandomSkinHue(); + else + Caster.HueMod = 0; + + // Scriptiz : Blinght est un poulet vert ! + if (m_NewBody == 208 && Caster.Name == "Blinght" && Caster.Account != null && Caster.Account.Username == "Blinght") + Caster.HueMod = 70; + + BaseArmor.ValidateMobile( Caster ); + BaseClothing.ValidateMobile( Caster ); + + if( !Core.ML ) + { + StopTimer( Caster ); + + Timer t = new InternalTimer( Caster ); + + m_Timers[Caster] = t; + + t.Start(); + } + } + } + else + { + Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect. + } + } + + FinishSequence(); + } + + private static Hashtable m_Timers = new Hashtable(); + + public static bool StopTimer( Mobile m ) + { + Timer t = (Timer)m_Timers[m]; + + if ( t != null ) + { + t.Stop(); + m_Timers.Remove( m ); + } + + return ( t != null ); + } + + private static void EndPolymorph( Mobile m ) + { + if( !m.CanBeginAction( typeof( PolymorphSpell ) ) ) + { + m.BodyMod = 0; + m.HueMod = -1; + m.EndAction( typeof( PolymorphSpell ) ); + + BaseArmor.ValidateMobile( m ); + BaseClothing.ValidateMobile( m ); + } + } + + private class InternalTimer : Timer + { + private Mobile m_Owner; + + public InternalTimer( Mobile owner ) : base( TimeSpan.FromSeconds( 0 ) ) + { + m_Owner = owner; + + int val = (int)owner.Skills[SkillName.Magery].Value; + + if ( val > 120 ) + val = 120; + + Delay = TimeSpan.FromSeconds( val ); + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + EndPolymorph( m_Owner ); + } + } + } +} diff --git a/Scripts/Spells/Sixth/Dispel.cs b/Scripts/Spells/Sixth/Dispel.cs new file mode 100644 index 0000000..a463989 --- /dev/null +++ b/Scripts/Spells/Sixth/Dispel.cs @@ -0,0 +1,84 @@ +using System; +using Server.Misc; +using Server.Items; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; + +namespace Server.Spells.Sixth +{ + public class DispelSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Dispel", "An Ort", + 218, + 9002, + Reagent.Garlic, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public DispelSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public class InternalTarget : Target + { + private DispelSpell m_Owner; + + public InternalTarget( DispelSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + Mobile m = (Mobile)o; + BaseCreature bc = m as BaseCreature; + + if ( !from.CanSee( m ) ) + { + from.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( bc == null || !bc.IsDispellable ) + { + from.SendLocalizedMessage( 1005049 ); // That cannot be dispelled. + } + else if ( m_Owner.CheckHSequence( m ) ) + { + SpellHelper.Turn( from, m ); + + double dispelChance = (50.0 + ((100 * (from.Skills.Magery.Value - bc.DispelDifficulty)) / (bc.DispelFocus*2))) / 100; + + if ( dispelChance > Utility.RandomDouble() ) + { + Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x3728, 8, 20, 5042 ); + Effects.PlaySound( m, m.Map, 0x201 ); + + m.Delete(); + } + else + { + m.FixedEffect( 0x3779, 10, 20 ); + from.SendLocalizedMessage( 1010084 ); // The creature resisted the attempt to dispel it! + } + } + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/EnergyBolt.cs b/Scripts/Spells/Sixth/EnergyBolt.cs new file mode 100644 index 0000000..9cfa648 --- /dev/null +++ b/Scripts/Spells/Sixth/EnergyBolt.cs @@ -0,0 +1,97 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Sixth +{ + public class EnergyBoltSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Energy Bolt", "Corp Por", + 230, + 9022, + Reagent.BlackPearl, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public EnergyBoltSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return true; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + Mobile source = Caster; + + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, ref source, ref m ); + + double damage; + + if ( Core.AOS ) + { + damage = GetNewAosDamage( 40, 1, 5, m ); + } + else + { + damage = Utility.Random( 24, 18 ); + + if ( CheckResisted( m ) ) + { + damage *= 0.75; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + // Scale damage based on evalint and resist + damage *= GetDamageScalar( m ); + } + + // Do the effects + source.MovingParticles( m, 0x379F, 7, 0, false, true, 3043, 4043, 0x211 ); + source.PlaySound( 0x20A ); + + // Deal the damage + SpellHelper.Damage( this, m, damage, 0, 0, 0, 0, 100 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private EnergyBoltSpell m_Owner; + + public InternalTarget( EnergyBoltSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/Explosion.cs b/Scripts/Spells/Sixth/Explosion.cs new file mode 100644 index 0000000..70bebff --- /dev/null +++ b/Scripts/Spells/Sixth/Explosion.cs @@ -0,0 +1,131 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Sixth +{ + public class ExplosionSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Explosion", "Vas Ort Flam", + 230, + 9041, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public ExplosionSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override bool DelayedDamageStacking { get { return !Core.AOS; } } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage { get { return false; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( Caster.CanBeHarmful( m ) && CheckSequence() ) + { + Mobile attacker = Caster, defender = m; + + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int) this.Circle, Caster, ref m ); + + InternalTimer t = new InternalTimer( this, attacker, defender, m ); + t.Start(); + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private MagerySpell m_Spell; + private Mobile m_Target; + private Mobile m_Attacker, m_Defender; + + public InternalTimer( MagerySpell spell, Mobile attacker, Mobile defender, Mobile target ) + : base( TimeSpan.FromSeconds( Core.AOS ? 3.0 : 2.5 ) ) + { + m_Spell = spell; + m_Attacker = attacker; + m_Defender = defender; + m_Target = target; + + if ( m_Spell != null ) + m_Spell.StartDelayedDamageContext( attacker, this ); + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Attacker.HarmfulCheck( m_Defender ) ) + { + double damage; + + if ( Core.AOS ) + { + damage = m_Spell.GetNewAosDamage( 40, 1, 5, m_Defender ); + } + else + { + damage = Utility.Random( 23, 22 ); + + if ( m_Spell.CheckResisted( m_Target ) ) + { + damage *= 0.75; + + m_Target.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + damage *= m_Spell.GetDamageScalar( m_Target ); + } + + m_Target.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + m_Target.PlaySound( 0x307 ); + + SpellHelper.Damage( m_Spell, m_Target, damage, 0, 100, 0, 0, 0 ); + + if ( m_Spell != null ) + m_Spell.RemoveDelayedDamageContext( m_Attacker ); + } + } + } + + private class InternalTarget : Target + { + private ExplosionSpell m_Owner; + + public InternalTarget( ExplosionSpell owner ) + : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/Invisibility.cs b/Scripts/Spells/Sixth/Invisibility.cs new file mode 100644 index 0000000..98003ac --- /dev/null +++ b/Scripts/Spells/Sixth/Invisibility.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections; +using Server; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.Sixth +{ + public class InvisibilitySpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Invisibility", "An Lor Xen", + 206, + 9002, + Reagent.Bloodmoss, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public InvisibilitySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( m is Mobiles.BaseVendor || m is Mobiles.PlayerVendor || m is Mobiles.PlayerBarkeeper || m.AccessLevel > Caster.AccessLevel ) + { + Caster.SendLocalizedMessage( 501857 ); // This spell won't work on that! + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + Effects.SendLocationParticles( EffectItem.Create( new Point3D( m.X, m.Y, m.Z + 16 ), Caster.Map, EffectItem.DefaultDuration ), 0x376A, 10, 15, 5045 ); + m.PlaySound( 0x3C4 ); + + m.Hidden = true; + m.Combatant = null; + m.Warmode = false; + + RemoveTimer( m ); + + TimeSpan duration = TimeSpan.FromSeconds( (( 1.2 * Caster.Skills.Magery.Fixed) / 10 )); + + Timer t = new InternalTimer( m, duration ); + + BuffInfo.RemoveBuff( m, BuffIcon.HidingAndOrStealth ); + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Invisibility, 1075825, duration, m ) ); //Invisibility/Invisible + + m_Table[m] = t; + + t.Start(); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool HasTimer( Mobile m ) + { + return m_Table[m] != null; + } + + public static void RemoveTimer( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + { + t.Stop(); + m_Table.Remove( m ); + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.RevealingAction(); + RemoveTimer( m_Mobile ); + } + } + + public class InternalTarget : Target + { + private InvisibilitySpell m_Owner; + + public InternalTarget( InvisibilitySpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/Mark.cs b/Scripts/Spells/Sixth/Mark.cs new file mode 100644 index 0000000..95d71bf --- /dev/null +++ b/Scripts/Spells/Sixth/Mark.cs @@ -0,0 +1,94 @@ +using System; +using Server.Items; +using Server.Targeting; +using Server.Network; +using Server.Regions; + +namespace Server.Spells.Sixth +{ + public class MarkSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mark", "Kal Por Ylem", + 218, + 9002, + Reagent.BlackPearl, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public MarkSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + return SpellHelper.CheckTravel( Caster, TravelCheckType.Mark ); + } + + public void Target( RecallRune rune ) + { + if ( !Caster.CanSee( rune ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.Mark ) ) + { + } + else if ( SpellHelper.CheckMulti( Caster.Location, Caster.Map, !Core.AOS ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( !rune.IsChildOf( Caster.Backpack ) ) + { + Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1062422 ); // You must have this rune in your backpack in order to mark it. + } + else if ( CheckSequence() ) + { + rune.Mark( Caster ); + + Caster.PlaySound( 0x1FA ); + Effects.SendLocationEffect( Caster, Caster.Map, 14201, 16 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MarkSpell m_Owner; + + public InternalTarget( MarkSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is RecallRune ) + { + m_Owner.Target( (RecallRune) o ); + } + else + { + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 501797, from.Name, "" ) ); // I cannot mark that object. + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/MassCurse.cs b/Scripts/Spells/Sixth/MassCurse.cs new file mode 100644 index 0000000..4e37d29 --- /dev/null +++ b/Scripts/Spells/Sixth/MassCurse.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Misc; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Sixth +{ + public class MassCurseSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mass Curse", "Vas Des Sanct", + 218, + 9031, + false, + Reagent.Garlic, + Reagent.Nightshade, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public MassCurseSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + List targets = new List(); + + Map map = Caster.Map; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 2 ); + + foreach ( Mobile m in eable ) + { + if ( Core.AOS && m == Caster ) + continue; + + if ( SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanSee( m ) && Caster.CanBeHarmful( m, false ) ) + targets.Add( m ); + } + + eable.Free(); + } + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + Caster.DoHarmful( m ); + + SpellHelper.AddStatCurse( Caster, m, StatType.Str ); SpellHelper.DisableSkillCheck = true; + SpellHelper.AddStatCurse( Caster, m, StatType.Dex ); + SpellHelper.AddStatCurse( Caster, m, StatType.Int ); SpellHelper.DisableSkillCheck = false; + + m.FixedParticles( 0x374A, 10, 15, 5028, EffectLayer.Waist ); + m.PlaySound( 0x1FB ); + + HarmfulSpell(m); + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MassCurseSpell m_Owner; + + public InternalTarget( MassCurseSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/ParalyzeField.cs b/Scripts/Spells/Sixth/ParalyzeField.cs new file mode 100644 index 0000000..52e5f7f --- /dev/null +++ b/Scripts/Spells/Sixth/ParalyzeField.cs @@ -0,0 +1,237 @@ +using System; +using Server.Targeting; +using Server.Items; +using Server.Network; +using Server.Misc; +using Server.Mobiles; + +namespace Server.Spells.Sixth +{ + public class ParalyzeFieldSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Paralyze Field", "In Ex Grav", + 230, + 9012, + false, + Reagent.BlackPearl, + Reagent.Ginseng, + Reagent.SpidersSilk + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public ParalyzeFieldSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + eastToWest = false; + else if ( rx >= 0 ) + eastToWest = true; + else if ( ry >= 0 ) + eastToWest = true; + else + eastToWest = false; + + Effects.PlaySound( p, Caster.Map, 0x20B ); + + int itemID = eastToWest ? 0x3967 : 0x3979; + + TimeSpan duration = TimeSpan.FromSeconds( 3.0 + (Caster.Skills[SkillName.Magery].Value / 3.0) ); + + for ( int i = -2; i <= 2; ++i ) + { + Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z ); + bool canFit = SpellHelper.AdjustField( ref loc, Caster.Map, 12, false ); + + if ( !canFit ) + continue; + + Item item = new InternalItem( Caster, itemID, loc, Caster.Map, duration ); + item.ProcessDelta(); + + Effects.SendLocationParticles( EffectItem.Create( loc, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5048 ); + } + } + + FinishSequence(); + } + + [DispellableField] + public class InternalItem : Item + { + private Timer m_Timer; + private Mobile m_Caster; + private DateTime m_End; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Mobile caster, int itemID, Point3D loc, Map map, TimeSpan duration ) : base( itemID ) + { + Visible = false; + Movable = false; + Light = LightType.Circle300; + + MoveToWorld( loc, map ); + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Caster = caster; + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Caster ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Caster = reader.ReadMobile(); + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_End - DateTime.Now ); + m_Timer.Start(); + + break; + } + } + } + + public override bool OnMoveOver( Mobile m ) + { + if ( Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) ) + { + if ( SpellHelper.CanRevealCaster( m ) ) + m_Caster.RevealingAction(); + + m_Caster.DoHarmful( m ); + + double duration; + + if ( Core.AOS ) + { + duration = 2.0 + ((int)(m_Caster.Skills[SkillName.EvalInt].Value / 10) - (int)(m.Skills[SkillName.MagicResist].Value / 10)); + + if ( !m.Player ) + duration *= 3.0; + + if ( duration < 0.0 ) + duration = 0.0; + } + else + { + duration = 7.0 + (m_Caster.Skills[SkillName.Magery].Value * 0.2); + } + + m.Paralyze( TimeSpan.FromSeconds( duration ) ); + + m.PlaySound( 0x204 ); + m.FixedEffect( 0x376A, 10, 16 ); + + if (m is BaseCreature) + ((BaseCreature)m).OnHarmfulSpell(m_Caster); + } + + return true; + } + + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + private class InternalTarget : Target + { + private ParalyzeFieldSpell m_Owner; + + public InternalTarget( ParalyzeFieldSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Sixth/Reveal.cs b/Scripts/Spells/Sixth/Reveal.cs new file mode 100644 index 0000000..9376a8f --- /dev/null +++ b/Scripts/Spells/Sixth/Reveal.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Misc; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Sixth +{ + public class RevealSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Reveal", "Wis Quas", + 206, + 9002, + Reagent.Bloodmoss, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + + public RevealSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + List targets = new List(); + + Map map = Caster.Map; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 1 + (int)(Caster.Skills[SkillName.Magery].Value / 20.0) ); + + foreach ( Mobile m in eable ) + { + if ( m is Mobiles.ShadowKnight && (m.X != p.X || m.Y != p.Y) ) + continue; + + if ( m.Hidden && (m.AccessLevel == AccessLevel.Player || Caster.AccessLevel > m.AccessLevel) && CheckDifficulty( Caster, m ) ) + targets.Add( m ); + } + + eable.Free(); + } + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = targets[i]; + + m.RevealingAction(); + + m.FixedParticles( 0x375A, 9, 20, 5049, EffectLayer.Head ); + m.PlaySound( 0x1FD ); + } + } + + FinishSequence(); + } + + // Reveal uses magery and detect hidden vs. hide and stealth + private static bool CheckDifficulty( Mobile from, Mobile m ) + { + // Reveal always reveals vs. invisibility spell + if ( !Core.AOS || InvisibilitySpell.HasTimer( m ) ) + return true; + + int magery = from.Skills[SkillName.Magery].Fixed; + int detectHidden = from.Skills[SkillName.DetectHidden].Fixed; + + int hiding = m.Skills[SkillName.Hiding].Fixed; + int stealth = m.Skills[SkillName.Stealth].Fixed; + int divisor = hiding + stealth; + + int chance; + if ( divisor > 0 ) + chance = 50 * (magery + detectHidden) / divisor; + else + chance = 100; + + return chance > Utility.Random( 100 ); + } + + public class InternalTarget : Target + { + private RevealSpell m_Owner; + + public InternalTarget( RevealSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/ArcaneCircle.cs b/Scripts/Spells/Spellweaving/ArcaneCircle.cs new file mode 100644 index 0000000..5a38306 --- /dev/null +++ b/Scripts/Spells/Spellweaving/ArcaneCircle.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Spellweaving +{ + public class ArcaneCircleSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Arcane Circle", "Myrshalee", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 0.5 ); } } + + public override double RequiredSkill { get { return 0.0; } } + public override int RequiredMana { get { return 24; } } + + public ArcaneCircleSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if( !IsValidLocation( Caster.Location, Caster.Map ) ) + { + Caster.SendLocalizedMessage( 1072705 ); // You must be standing on an arcane circle, pentagram or abbatoir to use this spell. + return false; + } + + if ( GetArcanists().Count < 2 ) + { + Caster.SendLocalizedMessage( 1080452 ); //There are not enough spellweavers present to create an Arcane Focus. + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + if( CheckSequence() ) + { + Caster.FixedParticles( 0x3779, 10, 20, 0x0, EffectLayer.Waist ); + Caster.PlaySound( 0x5C0 ); + + List Arcanists = GetArcanists(); + + TimeSpan duration = TimeSpan.FromHours( Math.Max( 1, (int)(Caster.Skills.Spellweaving.Value / 24) ) ); + + int strengthBonus = Math.Min( Arcanists.Count, IsSanctuary( Caster.Location, Caster.Map ) ? 6 : 5 ); //The Sanctuary is a special, single location place + + for( int i = 0; i < Arcanists.Count; i++ ) + GiveArcaneFocus( Arcanists[i], duration, strengthBonus ); + } + + FinishSequence(); + } + + private static bool IsSanctuary( Point3D p, Map m ) + { + return (m == Map.Trammel || m == Map.Felucca) && p.X == 6267 && p.Y == 131; + } + + private static bool IsValidLocation( Point3D location, Map map ) + { + LandTile lt = map.Tiles.GetLandTile( location.X, location.Y ); // Land Tiles + + if( IsValidTile( lt.ID ) && lt.Z == location.Z ) + return true; + + StaticTile[] tiles = map.Tiles.GetStaticTiles( location.X, location.Y ); // Static Tiles + + for( int i = 0; i < tiles.Length; ++i ) + { + StaticTile t = tiles[i]; + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + int tand = t.ID; + + if( t.Z + id.CalcHeight != location.Z ) + continue; + else if( IsValidTile( tand ) ) + return true; + } + + IPooledEnumerable eable = map.GetItemsInRange( location, 0 ); // Added Tiles + + foreach( Item item in eable ) + { + ItemData id = item.ItemData; + + if( item == null || item.Z + id.CalcHeight != location.Z ) + continue; + else if( IsValidTile( item.ItemID ) ) + { + eable.Free(); + return true; + } + } + + eable.Free(); + return false; + } + + public static bool IsValidTile( int itemID ) + { + //Per OSI, Center tile only + return (itemID == 0xFEA || itemID == 0x1216 || itemID == 0x307F || itemID == 0x1D10 || itemID == 0x1D0F || itemID == 0x1D1F || itemID == 0x1D12 ); // Pentagram center, Abbatoir center, Arcane Circle Center, Bloody Pentagram has 4 tiles at center + } + + private List GetArcanists() + { + List weavers = new List(); + + weavers.Add( Caster ); + + //OSI Verified: Even enemies/combatants count + foreach( Mobile m in Caster.GetMobilesInRange( 1 ) ) //Range verified as 1 + { + if ( m != Caster && m is PlayerMobile && Caster.CanBeBeneficial( m, false ) && Math.Abs( Caster.Skills.Spellweaving.Value - m.Skills.Spellweaving.Value ) <= 20 && !(m is Clone) ) + { + weavers.Add( m ); + } + // Everyone gets the Arcane Focus, power capped elsewhere + } + + return weavers; + } + + private void GiveArcaneFocus( Mobile to, TimeSpan duration, int strengthBonus ) + { + if( to == null ) //Sanity + return; + + ArcaneFocus focus = FindArcaneFocus( to ); + + if( focus == null ) + { + ArcaneFocus f = new ArcaneFocus( duration, strengthBonus ); + if( to.PlaceInBackpack( f ) ) + { + f.SendTimeRemainingMessage( to ); + to.SendLocalizedMessage( 1072740 ); // An arcane focus appears in your backpack. + } + else + { + f.Delete(); + } + + } + else //OSI renewal rules: the new one will override the old one, always. + { + to.SendLocalizedMessage( 1072828 ); // Your arcane focus is renewed. + focus.LifeSpan = duration; + focus.CreationTime = DateTime.Now; + focus.StrengthBonus = strengthBonus; + focus.InvalidateProperties(); + focus.SendTimeRemainingMessage( to ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/ArcaneForm.cs b/Scripts/Spells/Spellweaving/ArcaneForm.cs new file mode 100644 index 0000000..8173478 --- /dev/null +++ b/Scripts/Spells/Spellweaving/ArcaneForm.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Network; +using Server.Spells.Fifth; +using Server.Spells.Seventh; +using Server.Spells.Necromancy; +using Server.Spells.Ninjitsu; + +namespace Server.Spells.Spellweaving +{ + public abstract class ArcaneForm : ArcanistSpell, ITransformationSpell + { + public abstract int Body { get; } + public virtual int Hue { get { return 0; } } + + public virtual int PhysResistOffset { get { return 0; } } + public virtual int FireResistOffset { get { return 0; } } + public virtual int ColdResistOffset { get { return 0; } } + public virtual int PoisResistOffset { get { return 0; } } + public virtual int NrgyResistOffset { get { return 0; } } + + public ArcaneForm( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public override bool CheckCast() + { + if( !TransformationSpellHelper.CheckCast( Caster, this ) ) + return false; + + return base.CheckCast(); + } + + public override void OnCast() + { + TransformationSpellHelper.OnCast( Caster, this ); + + FinishSequence(); + } + + public virtual double TickRate + { + get { return 1.0; } + } + + public virtual void OnTick( Mobile m ) + { + } + + public virtual void DoEffect( Mobile m ) + { + } + + public virtual void RemoveEffect( Mobile m ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/ArcaneSummon.cs b/Scripts/Spells/Spellweaving/ArcaneSummon.cs new file mode 100644 index 0000000..5168522 --- /dev/null +++ b/Scripts/Spells/Spellweaving/ArcaneSummon.cs @@ -0,0 +1,51 @@ +using System; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Spellweaving +{ + public abstract class ArcaneSummon : ArcanistSpell where T : BaseCreature + { + public abstract int Sound { get; } + + public ArcaneSummon( Mobile caster, Item scroll, SpellInfo info ) + : base( caster, scroll, info ) + { + } + + public override bool CheckCast() + { + if( !base.CheckCast() ) + return false; + + if( (Caster.Followers + 1) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1074270 ); // You have too many followers to summon another one. + return false; + } + + return true; + } + + public override void OnCast() + { + if( CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromMinutes( Caster.Skills.Spellweaving.Value /24 + FocusLevel*2 ); + int summons = Math.Min( 1+FocusLevel, Caster.FollowersMax - Caster.Followers ); + + for( int i = 0; i < summons; i++ ) + { + BaseCreature bc; + + try { bc = Activator.CreateInstance(); } + catch { break; } + + SpellHelper.Summon( bc, Caster, Sound, duration, false, false ); + } + + FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/ArcanistSpell.cs b/Scripts/Spells/Spellweaving/ArcanistSpell.cs new file mode 100644 index 0000000..1ca7ca3 --- /dev/null +++ b/Scripts/Spells/Spellweaving/ArcanistSpell.cs @@ -0,0 +1,159 @@ +using System; +using System.Text; +using Server.Items; +using Server.Mobiles; +using Server.Engines.MLQuests; + +namespace Server.Spells.Spellweaving +{ + public abstract class ArcanistSpell : Spell + { + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill { get { return SkillName.Spellweaving; } } + public override SkillName DamageSkill { get { return SkillName.Spellweaving; } } + + public override bool ClearHandsOnCast { get { return false; } } + + private int m_CastTimeFocusLevel; + + public ArcanistSpell( Mobile caster, Item scroll, SpellInfo info ) + : base( caster, scroll, info ) + { + } + + public virtual int FocusLevel + { + get { return m_CastTimeFocusLevel; } + } + + public static int GetFocusLevel( Mobile from ) + { + ArcaneFocus focus = FindArcaneFocus( from ); + + if( focus == null || focus.Deleted ) + return 0; + + return focus.StrengthBonus; + } + + public static ArcaneFocus FindArcaneFocus( Mobile from ) + { + if( from == null || from.Backpack == null ) + return null; + + if ( from.Holding is ArcaneFocus ) + return (ArcaneFocus)from.Holding; + + return from.Backpack.FindItemByType(); + } + + public static bool CheckExpansion( Mobile from ) + { + if( !(from is PlayerMobile) ) + return true; + + if( from.NetState == null ) + return false; + + return from.NetState.SupportsExpansion( Expansion.ML ); + } + + public override bool CheckCast() + { + if( !base.CheckCast() ) + return false; + + Mobile caster = Caster; + + if (!CheckExpansion(caster)) + { + caster.SendLocalizedMessage(1072176); // You must upgrade to the Mondain's Legacy Expansion Pack before using that ability + return false; + } + + if (caster is PlayerMobile) + { + MLQuestContext context = MLQuestSystem.GetContext((PlayerMobile)caster); + + if (context == null || !context.Spellweaving) + { + caster.SendLocalizedMessage(1073220); // You must have completed the epic arcanist quest to use this ability. + return false; + } + } + + int mana = ScaleMana(RequiredMana); + + if (caster.Mana < mana) + { + caster.SendLocalizedMessage(1060174, mana.ToString()); // You must have at least ~1_MANA_REQUIREMENT~ Mana to use this ability. + return false; + } + else if (caster.Skills[CastSkill].Value < RequiredSkill) + { + caster.SendLocalizedMessage(1063013, String.Format("{0}\t{1}", RequiredSkill.ToString("F1"), "#1044114")); // You need at least ~1_SKILL_REQUIREMENT~ ~2_SKILL_NAME~ skill to use that ability. + return false; + } + + return true; + } + + public override void GetCastSkills( out double min, out double max ) + { + min = RequiredSkill - 12.5; //per 5 on friday, 2/16/07 + max = RequiredSkill + 37.5; + } + + public override int GetMana() + { + return RequiredMana; + } + + public override void DoFizzle() + { + Caster.PlaySound( 0x1D6 ); + Caster.NextSpellTime = DateTime.Now; + } + + public override void DoHurtFizzle() + { + Caster.PlaySound( 0x1D6 ); + } + + public override void OnDisturb( DisturbType type, bool message ) + { + base.OnDisturb( type, message ); + + if( message ) + Caster.PlaySound( 0x1D6 ); + } + + public override void OnBeginCast() + { + base.OnBeginCast(); + + SendCastEffect(); + m_CastTimeFocusLevel = GetFocusLevel( Caster ); + } + + public virtual void SendCastEffect() + { + Caster.FixedEffect( 0x37C4, 10, (int)(GetCastDelay().TotalSeconds * 28), 4, 3 ); + } + + public virtual bool CheckResisted( Mobile m ) + { + double percent = (50 + 2*(GetResistSkill( m ) - GetDamageSkill( Caster )))/100; //TODO: According to the guide this is it.. but.. is it correct per OSI? + + if( percent <= 0 ) + return false; + + if( percent >= 1.0 ) + return true; + + return (percent >= Utility.RandomDouble()); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/AttuneWeapon.cs b/Scripts/Spells/Spellweaving/AttuneWeapon.cs new file mode 100644 index 0000000..538a95d --- /dev/null +++ b/Scripts/Spells/Spellweaving/AttuneWeapon.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Spells.Spellweaving +{ + public class AttuneWeaponSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Attune Weapon", "Haeldril", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override double RequiredSkill { get { return 0.0; } } + public override int RequiredMana { get { return 24; } } + + public AttuneWeaponSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if( m_Table.ContainsKey( Caster ) ) + { + Caster.SendLocalizedMessage( 501775 ); // This spell is already in effect. + return false; + } + else if( !Caster.CanBeginAction( typeof( AttuneWeaponSpell ) ) ) + { + Caster.SendLocalizedMessage( 1075124 ); // You must wait before casting that spell again. + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + if( CheckSequence() ) + { + Caster.PlaySound( 0x5C3 ); + Caster.FixedParticles( 0x3728, 1, 13, 0x26B8, 0x455, 7, EffectLayer.Waist ); + Caster.FixedParticles( 0x3779, 1, 15, 0x251E, 0x3F, 7, EffectLayer.Waist ); + + double skill = Caster.Skills[SkillName.Spellweaving].Value; + + int damageAbsorb = (int)(18 + ((skill-10)/10)*3 + (FocusLevel * 6)); + Caster.MeleeDamageAbsorb = damageAbsorb; + + TimeSpan duration = TimeSpan.FromSeconds( 60 + (FocusLevel * 12) ); + + ExpireTimer t = new ExpireTimer( Caster, duration ); + t.Start(); + + m_Table[Caster] = t; + + Caster.BeginAction( typeof( AttuneWeaponSpell ) ); + + BuffInfo.AddBuff( Caster, new BuffInfo( BuffIcon.AttuneWeapon, 1075798, duration, Caster, damageAbsorb.ToString() ) ); + } + + FinishSequence(); + } + + private static Dictionary m_Table = new Dictionary(); + + public static void TryAbsorb( Mobile defender, ref int damage ) + { + if( damage == 0 || !IsAbsorbing( defender ) || defender.MeleeDamageAbsorb <= 0 ) + return; + + int absorbed = Math.Min( damage, defender.MeleeDamageAbsorb ); + + damage -= absorbed; + defender.MeleeDamageAbsorb -= absorbed; + + defender.SendLocalizedMessage( 1075127, String.Format( "{0}\t{1}", absorbed, defender.MeleeDamageAbsorb ) ); // ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain. + + if( defender.MeleeDamageAbsorb <= 0 ) + StopAbsorbing( defender, true ); + } + + public static bool IsAbsorbing( Mobile m ) + { + return m_Table.ContainsKey( m ); + } + + public static void StopAbsorbing( Mobile m, bool message ) + { + ExpireTimer t; + if( m_Table.TryGetValue( m, out t ) ) + { + t.DoExpire( message ); + } + } + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + + public ExpireTimer( Mobile m, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + } + + protected override void OnTick() + { + DoExpire( true ); + } + + public void DoExpire( bool message ) + { + Stop(); + + m_Mobile.MeleeDamageAbsorb = 0; + + if( message ) + { + m_Mobile.SendLocalizedMessage( 1075126 ); // Your attunement fades. + m_Mobile.PlaySound( 0x1F8 ); + } + + m_Table.Remove( m_Mobile ); + + Timer.DelayCall( TimeSpan.FromSeconds( 120 ), delegate { m_Mobile.EndAction( typeof( AttuneWeaponSpell ) ); } ); + BuffInfo.RemoveBuff( m_Mobile, BuffIcon.AttuneWeapon ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/EssenceOfWind.cs b/Scripts/Spells/Spellweaving/EssenceOfWind.cs new file mode 100644 index 0000000..bb70be8 --- /dev/null +++ b/Scripts/Spells/Spellweaving/EssenceOfWind.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Spells.Spellweaving +{ + public class EssenceOfWindSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( "Essence of Wind", "Anathrae", -1 ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 3.0 ); } } + + public override double RequiredSkill { get { return 52.0; } } + public override int RequiredMana { get { return 40; } } + + public EssenceOfWindSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + if( CheckSequence() ) + { + Caster.PlaySound( 0x5C6 ); + + int range = 5 + FocusLevel; + int damage = 25 + FocusLevel; + + double skill = Caster.Skills[SkillName.Spellweaving].Value; + + TimeSpan duration = TimeSpan.FromSeconds( (int)(skill / 24) + FocusLevel ); + + int fcMalus = FocusLevel + 1; + int ssiMalus = 2 * (FocusLevel + 1); + + List targets = new List(); + + foreach( Mobile m in Caster.GetMobilesInRange( range ) ) + { + if( Caster != m && Caster.InLOS( m ) && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) ) + targets.Add( m ); + } + + for( int i = 0; i < targets.Count; i++ ) + { + Mobile m = targets[i]; + + Caster.DoHarmful( m ); + + SpellHelper.Damage( this, m, damage, 0, 0, 100, 0, 0 ); + + if( !CheckResisted( m ) ) //No message on resist + { + m_Table[m] = new EssenceOfWindInfo( m, fcMalus, ssiMalus, duration ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.EssenceOfWind, 1075802, duration, m, String.Format( "{0}\t{1}", fcMalus.ToString(), ssiMalus.ToString() ) ) ); + } + } + } + + FinishSequence(); + } + + private static Dictionary m_Table = new Dictionary(); + + private class EssenceOfWindInfo + { + private Mobile m_Defender; + private int m_FCMalus; + private int m_SSIMalus; + private ExpireTimer m_Timer; + + public Mobile Defender { get { return m_Defender; } } + public int FCMalus { get { return m_FCMalus; } } + public int SSIMalus { get { return m_SSIMalus; } } + public ExpireTimer Timer { get { return m_Timer; } } + + public EssenceOfWindInfo( Mobile defender, int fcMalus, int ssiMalus, TimeSpan duration ) + { + m_Defender = defender; + m_FCMalus = fcMalus; + m_SSIMalus = ssiMalus; + + m_Timer = new ExpireTimer( m_Defender, duration ); + m_Timer.Start(); + } + } + + public static int GetFCMalus( Mobile m ) + { + EssenceOfWindInfo info; + + if( m_Table.TryGetValue( m, out info ) ) + return info.FCMalus; + + return 0; + } + + public static int GetSSIMalus( Mobile m ) + { + EssenceOfWindInfo info; + + if( m_Table.TryGetValue( m, out info ) ) + return info.SSIMalus; + + return 0; + } + + public static bool IsDebuffed( Mobile m ) + { + return m_Table.ContainsKey( m ); + } + + public static void StopDebuffing( Mobile m, bool message ) + { + EssenceOfWindInfo info; + + if( m_Table.TryGetValue( m, out info ) ) + info.Timer.DoExpire( message ); + } + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + + public ExpireTimer( Mobile m, TimeSpan delay ) : base( delay ) + { + m_Mobile = m; + } + + protected override void OnTick() + { + DoExpire( true ); + } + + public void DoExpire( bool message ) + { + Stop(); + /* + if( message ) + { + } + */ + m_Table.Remove( m_Mobile ); + + BuffInfo.RemoveBuff( m_Mobile, BuffIcon.EssenceOfWind ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/EtherealVoyage.cs b/Scripts/Spells/Spellweaving/EtherealVoyage.cs new file mode 100644 index 0000000..cbb01a1 --- /dev/null +++ b/Scripts/Spells/Spellweaving/EtherealVoyage.cs @@ -0,0 +1,88 @@ +using System; + +namespace Server.Spells.Spellweaving +{ + public class EtherealVoyageSpell : ArcaneForm + { + private static SpellInfo m_Info = new SpellInfo( + "Ethereal Voyage", "Orlavdra", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 3.5 ); } } + + public override double RequiredSkill { get { return 24.0; } } + public override int RequiredMana { get { return 32; } } + + public override int Body { get { return 0x302; } } + public override int Hue { get { return 0x48F; } } + + public EtherealVoyageSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public static void Initialize() + { + EventSink.AggressiveAction += new AggressiveActionEventHandler( delegate( AggressiveActionEventArgs e ) + { + if( TransformationSpellHelper.UnderTransformation( e.Aggressor, typeof( EtherealVoyageSpell ) ) ) + { + TransformationSpellHelper.RemoveContext( e.Aggressor, true ); + } + } ); + } + + public override bool CheckCast() + { + if( TransformationSpellHelper.UnderTransformation( Caster, typeof( EtherealVoyageSpell ) ) ) + { + Caster.SendLocalizedMessage( 501775 ); // This spell is already in effect. + } + else if( !Caster.CanBeginAction( typeof( EtherealVoyageSpell ) ) ) + { + Caster.SendLocalizedMessage( 1075124 ); // You must wait before casting that spell again. + } + else if( Caster.Combatant != null ) + { + Caster.SendLocalizedMessage( 1072586 ); // You cannot cast Ethereal Voyage while you are in combat. + } + else + { + return base.CheckCast(); + } + + return false; + } + + public override void DoEffect( Mobile m ) + { + m.PlaySound( 0x5C8 ); + m.SendLocalizedMessage( 1074770 ); // You are now under the effects of Ethereal Voyage. + + double skill = Caster.Skills.Spellweaving.Value; + + TimeSpan duration = TimeSpan.FromSeconds( 12 + (int)(skill / 24) + (FocusLevel * 2) ); + + Timer.DelayCall( duration, new TimerStateCallback( RemoveEffect ), Caster ); + + Caster.BeginAction( typeof( EtherealVoyageSpell ) ); //Cannot cast this spell for another 5 minutes(300sec) after effect removed. + + BuffInfo.AddBuff( Caster, new BuffInfo( BuffIcon.EtherealVoyage, 1031613, 1075805, duration, Caster ) ); + } + + public override void RemoveEffect( Mobile m ) + { + m.SendLocalizedMessage( 1074771 ); // You are no longer under the effects of Ethereal Voyage. + + TransformationSpellHelper.RemoveContext( m, true ); + + Timer.DelayCall( TimeSpan.FromMinutes( 5 ), delegate + { + m.EndAction( typeof( EtherealVoyageSpell ) ); + } ); + + BuffInfo.RemoveBuff( m, BuffIcon.EtherealVoyage ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/GiftOfLife.cs b/Scripts/Spells/Spellweaving/GiftOfLife.cs new file mode 100644 index 0000000..f03f5b5 --- /dev/null +++ b/Scripts/Spells/Spellweaving/GiftOfLife.cs @@ -0,0 +1,218 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Gumps; +using Server.Targeting; + +namespace Server.Spells.Spellweaving +{ + public class GiftOfLifeSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Gift of Life", "Illorae", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 4.0 ); } } + + public override double RequiredSkill { get { return 38.0; } } + public override int RequiredMana { get { return 70; } } + + public GiftOfLifeSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public static void Initialize() + { + EventSink.PlayerDeath += new PlayerDeathEventHandler( delegate( PlayerDeathEventArgs e ) + { + HandleDeath( e.Mobile ); + } ); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + BaseCreature bc = m as BaseCreature; + + if( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if( m.IsDeadBondedPet || !m.Alive ) + { + // As per Osi: Nothing happens. + } + else if( m != Caster && (bc == null || !bc.IsBonded || bc.ControlMaster != Caster) ) + { + Caster.SendLocalizedMessage( 1072077 ); // You may only cast this spell on yourself or a bonded pet. + } + else if( m_Table.ContainsKey( m ) ) + { + Caster.SendLocalizedMessage( 501775 ); // This spell is already in effect. + } + else if( CheckBSequence( m ) ) + { + if( Caster == m ) + { + Caster.SendLocalizedMessage( 1074774 ); // You weave powerful magic, protecting yourself from death. + } + else + { + Caster.SendLocalizedMessage( 1074775 ); // You weave powerful magic, protecting your pet from death. + SpellHelper.Turn( Caster, m ); + } + + + m.PlaySound( 0x244 ); + m.FixedParticles( 0x3709, 1, 30, 0x26ED, 5, 2, EffectLayer.Waist ); + m.FixedParticles( 0x376A, 1, 30, 0x251E, 5, 3, EffectLayer.Waist ); + + double skill = Caster.Skills[SkillName.Spellweaving].Value; + + TimeSpan duration = TimeSpan.FromMinutes( ((int)(skill / 24))* 2 + FocusLevel ); + + ExpireTimer t = new ExpireTimer( m, duration, this ); + t.Start(); + + m_Table[m] = t; + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.GiftOfLife, 1031615, 1075807, duration, m, null, true ) ); + } + + FinishSequence(); + } + + private static Dictionary m_Table = new Dictionary(); + + public static void HandleDeath( Mobile m ) + { + if( m_Table.ContainsKey( m ) ) + Timer.DelayCall( TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 4 ) ), new TimerStateCallback( HandleDeath_OnCallback ), m ); + } + + private static void HandleDeath_OnCallback( Mobile m ) + { + ExpireTimer timer; + + if( m_Table.TryGetValue( m, out timer ) ) + { + double hitsScalar = timer.Spell.HitsScalar; + + if( m is BaseCreature && m.IsDeadBondedPet ) + { + BaseCreature pet = (BaseCreature)m; + Mobile master = pet.GetMaster(); + + if( master != null && master.NetState != null && Utility.InUpdateRange( pet, master ) ) + { + master.CloseGump( typeof( PetResurrectGump ) ); + master.SendGump( new PetResurrectGump( master, pet, hitsScalar ) ); + } + else + { + List friends = pet.Friends; + + for( int i = 0; friends != null && i < friends.Count; i++ ) + { + Mobile friend = friends[i]; + + if( friend.NetState != null && Utility.InUpdateRange( pet, friend ) ) + { + friend.CloseGump( typeof( PetResurrectGump ) ); + friend.SendGump( new PetResurrectGump( friend, pet ) ); + break; + } + } + } + } + else + { + m.CloseGump( typeof( ResurrectGump ) ); + m.SendGump( new ResurrectGump( m, hitsScalar ) ); + } + + //Per OSI, buff is removed when gump sent, irregardless of online status or acceptence + timer.DoExpire(); + } + + } + + public double HitsScalar { get { return ((Caster.Skills.Spellweaving.Value/2.4) + FocusLevel)/100; } } + + public static void OnLogin( LoginEventArgs e ) + { + Mobile m = e.Mobile; + + if( m == null || m.Alive || m_Table[m] == null ) + return; + + HandleDeath_OnCallback( m ); + } + + private class ExpireTimer : Timer + { + private Mobile m_Mobile; + + private GiftOfLifeSpell m_Spell; + + public GiftOfLifeSpell Spell { get { return m_Spell; } } + + public ExpireTimer( Mobile m, TimeSpan delay, GiftOfLifeSpell spell ) + : base( delay ) + { + m_Mobile = m; + m_Spell = spell; + } + + protected override void OnTick() + { + DoExpire(); + } + + public void DoExpire() + { + Stop(); + + m_Mobile.SendLocalizedMessage( 1074776 ); // You are no longer protected with Gift of Life. + m_Table.Remove( m_Mobile ); + + BuffInfo.RemoveBuff( m_Mobile, BuffIcon.GiftOfLife ); + } + } + + public class InternalTarget : Target + { + private GiftOfLifeSpell m_Owner; + + public InternalTarget( GiftOfLifeSpell owner ) + : base( 10, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile m, object o ) + { + if( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + else + { + m.SendLocalizedMessage( 1072077 ); // You may only cast this spell on yourself or a bonded pet. + } + } + + protected override void OnTargetFinish( Mobile m ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/GiftOfRenewal.cs b/Scripts/Spells/Spellweaving/GiftOfRenewal.cs new file mode 100644 index 0000000..0c27f69 --- /dev/null +++ b/Scripts/Spells/Spellweaving/GiftOfRenewal.cs @@ -0,0 +1,187 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Spells.Spellweaving +{ + public class GiftOfRenewalSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Gift of Renewal", "Olorisstra", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 3.0 ); } } + + public override double RequiredSkill { get { return 0.0; } } + public override int RequiredMana { get { return 24; } } + + public GiftOfRenewalSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + if( m_Table.ContainsKey( m ) ) + { + Caster.SendLocalizedMessage( 501775 ); // This spell is already in effect. + } + else if( !Caster.CanBeginAction( typeof( GiftOfRenewalSpell ) ) ) + { + Caster.SendLocalizedMessage( 501789 ); // You must wait before trying again. + } + else if( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + Caster.FixedEffect( 0x374A, 10, 20 ); + Caster.PlaySound( 0x5C9 ); + + if( m.Poisoned ) + { + m.CurePoison( m ); + } + else + { + double skill = Caster.Skills[SkillName.Spellweaving].Value; + + int hitsPerRound = 5 + (int)(skill / 24) + FocusLevel; + TimeSpan duration = TimeSpan.FromSeconds( 30 + (FocusLevel * 10) ); + + GiftOfRenewalInfo info = new GiftOfRenewalInfo( Caster, m, hitsPerRound ); + + Timer.DelayCall( duration, + delegate + { + if( StopEffect( m ) ) + { + m.PlaySound( 0x455 ); + m.SendLocalizedMessage( 1075071 ); // The Gift of Renewal has faded. + } + } ); + + + + m_Table[m] = info; + + Caster.BeginAction( typeof( GiftOfRenewalSpell ) ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.GiftOfRenewal, 1031602, 1075797, duration, m, hitsPerRound.ToString() ) ); + } + } + + FinishSequence(); + } + + private static Dictionary m_Table = new Dictionary(); + + private class GiftOfRenewalInfo + { + public Mobile m_Caster; + public Mobile m_Mobile; + public int m_HitsPerRound; + public InternalTimer m_Timer; + + public GiftOfRenewalInfo( Mobile caster, Mobile mobile, int hitsPerRound ) + { + m_Caster = caster; + m_Mobile = mobile; + m_HitsPerRound = hitsPerRound; + + m_Timer = new InternalTimer( this ); + m_Timer.Start(); + } + } + + private class InternalTimer : Timer + { + public GiftOfRenewalInfo m_Info; + + public InternalTimer( GiftOfRenewalInfo info ) + : base( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.0 ) ) + { + m_Info = info; + } + + protected override void OnTick() + { + Mobile m = m_Info.m_Mobile; + + if( !m_Table.ContainsKey( m ) ) + { + Stop(); + return; + } + + if( !m.Alive ) + { + Stop(); + StopEffect( m ); + return; + } + + if( m.Hits >= m.HitsMax ) + return; + + int toHeal = m_Info.m_HitsPerRound; + + SpellHelper.Heal( toHeal, m, m_Info.m_Caster ); + m.FixedParticles( 0x376A, 9, 32, 5005, EffectLayer.Waist ); + } + } + + public static bool StopEffect( Mobile m ) + { + GiftOfRenewalInfo info; + + if( m_Table.TryGetValue( m, out info ) ) + { + m_Table.Remove( m ); + + info.m_Timer.Stop(); + BuffInfo.RemoveBuff( m, BuffIcon.GiftOfRenewal ); + + Timer.DelayCall( TimeSpan.FromSeconds( 60 ), delegate { info.m_Caster.EndAction( typeof( GiftOfRenewalSpell ) ); } ); + + return true; + } + + return false; + } + + public class InternalTarget : Target + { + private GiftOfRenewalSpell m_Owner; + + public InternalTarget( GiftOfRenewalSpell owner ) + : base( 10, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile m, object o ) + { + if( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile m ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/ImmolatingWeapon.cs b/Scripts/Spells/Spellweaving/ImmolatingWeapon.cs new file mode 100644 index 0000000..1fceadc --- /dev/null +++ b/Scripts/Spells/Spellweaving/ImmolatingWeapon.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Spells.Spellweaving +{ + public class ImmolatingWeaponSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Immolating Weapon", "Thalshara", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.0 ); } } + + public override double RequiredSkill { get { return 10.0; } } + public override int RequiredMana { get { return 32; } } + + public ImmolatingWeaponSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + BaseWeapon weapon = Caster.Weapon as BaseWeapon; + + if ( weapon == null || weapon is Fists || weapon is BaseRanged ) + { + Caster.SendLocalizedMessage( 1060179 ); // You must be wielding a weapon to use this ability! + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + BaseWeapon weapon = Caster.Weapon as BaseWeapon; + + if ( weapon == null || weapon is Fists || weapon is BaseRanged ) + { + Caster.SendLocalizedMessage( 1060179 ); // You must be wielding a weapon to use this ability! + } + else if ( CheckSequence() ) + { + Caster.PlaySound( 0x5CA ); + Caster.FixedParticles( 0x36BD, 20, 10, 5044, EffectLayer.Head ); + + if ( !IsImmolating( weapon ) ) // On OSI, the effect is not re-applied + { + double skill = Caster.Skills.Spellweaving.Value; + + int duration = 10 + (int)( skill / 24 ) + FocusLevel; + int damage = 5 + (int)( skill / 24 ) + FocusLevel; + + Timer stopTimer = Timer.DelayCall( TimeSpan.FromSeconds( duration ), StopImmolating, weapon ); + + m_WeaponDamageTable[weapon] = new ImmolatingWeaponEntry( damage, stopTimer, Caster ); + weapon.InvalidateProperties(); + } + } + + FinishSequence(); + } + + private static Dictionary m_WeaponDamageTable = new Dictionary(); + + public static bool IsImmolating( BaseWeapon weapon ) + { + return m_WeaponDamageTable.ContainsKey( weapon ); + } + + public static int GetImmolatingDamage( BaseWeapon weapon ) + { + ImmolatingWeaponEntry entry; + + if ( m_WeaponDamageTable.TryGetValue( weapon, out entry ) ) + return entry.m_Damage; + + return 0; + } + + public static void DoEffect( BaseWeapon weapon, Mobile target ) + { + Timer.DelayCall( TimeSpan.FromSeconds( 0.25 ), FinishEffect, new DelayedEffectEntry( weapon, target ) ); + } + + private static void FinishEffect( DelayedEffectEntry effect ) + { + ImmolatingWeaponEntry entry; + + if ( m_WeaponDamageTable.TryGetValue( effect.m_Weapon, out entry ) ) + AOS.Damage( effect.m_Target, entry.m_Caster, entry.m_Damage, 0, 100, 0, 0, 0 ); + } + + public static void StopImmolating( BaseWeapon weapon ) + { + ImmolatingWeaponEntry entry; + + if ( m_WeaponDamageTable.TryGetValue( weapon, out entry ) ) + { + if ( entry.m_Caster != null ) + entry.m_Caster.PlaySound( 0x27 ); + + entry.m_Timer.Stop(); + + m_WeaponDamageTable.Remove( weapon ); + + weapon.InvalidateProperties(); + } + } + + private class ImmolatingWeaponEntry + { + public int m_Damage; + public Timer m_Timer; + public Mobile m_Caster; + + public ImmolatingWeaponEntry( int damage, Timer stopTimer, Mobile caster ) + { + m_Damage = damage; + m_Timer = stopTimer; + m_Caster = caster; + } + } + + private class DelayedEffectEntry + { + public BaseWeapon m_Weapon; + public Mobile m_Target; + + public DelayedEffectEntry( BaseWeapon weapon, Mobile target ) + { + m_Weapon = weapon; + m_Target = target; + } + } + } +} diff --git a/Scripts/Spells/Spellweaving/Items/ArcaneFocus.cs b/Scripts/Spells/Spellweaving/Items/ArcaneFocus.cs new file mode 100644 index 0000000..a5edb8b --- /dev/null +++ b/Scripts/Spells/Spellweaving/Items/ArcaneFocus.cs @@ -0,0 +1,67 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ArcaneFocus : TransientItem + { + public override int LabelNumber { get { return 1032629; } } // Arcane Focus + + private int m_StrengthBonus; + + [CommandProperty( AccessLevel.GameMaster )] + public int StrengthBonus + { + get { return m_StrengthBonus; } + set { m_StrengthBonus = value; } + } + + [Constructable] + public ArcaneFocus() + : this(TimeSpan.FromHours(1), 1) + { + } + + [Constructable] + public ArcaneFocus(int lifeSpan, int strengthBonus) + : this(TimeSpan.FromSeconds(lifeSpan), strengthBonus) + { + } + + public ArcaneFocus( TimeSpan lifeSpan, int strengthBonus ) : base( 0x3155, lifeSpan ) + { + LootType = LootType.Blessed; + m_StrengthBonus = strengthBonus; + } + + public ArcaneFocus( Serial serial ) : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1060485, m_StrengthBonus.ToString() ); // strength bonus ~1_val~ + } + + public override TextDefinition InvalidTransferMessage{ get { return 1073480; } } // Your arcane focus disappears. + public override bool Nontransferable { get { return true; } } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 ); + + writer.Write( m_StrengthBonus ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + m_StrengthBonus = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/Items/TransientItem.cs b/Scripts/Spells/Spellweaving/Items/TransientItem.cs new file mode 100644 index 0000000..2576d91 --- /dev/null +++ b/Scripts/Spells/Spellweaving/Items/TransientItem.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class TransientItem : Item + { + private TimeSpan m_LifeSpan; + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan LifeSpan + { + get { return m_LifeSpan; } + set { m_LifeSpan = value; } + } + + private DateTime m_CreationTime; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime CreationTime + { + get { return m_CreationTime; } + set { m_CreationTime = value; } + } + + private Timer m_Timer; + + public override bool Nontransferable { get { return true; } } + public override void HandleInvalidTransfer( Mobile from ) + { + if( InvalidTransferMessage != null ) + TextDefinition.SendMessageTo( from, InvalidTransferMessage ); + + this.Delete(); + } + + public virtual TextDefinition InvalidTransferMessage { get { return null; } } + + + public virtual void Expire( Mobile parent ) + { + if( parent != null ) + parent.SendLocalizedMessage( 1072515, (this.Name == null ? String.Format( "#{0}", LabelNumber ): this.Name) ); // The ~1_name~ expired... + + Effects.PlaySound( GetWorldLocation(), Map, 0x201 ); + + this.Delete(); + } + + public virtual void SendTimeRemainingMessage( Mobile to ) + { + to.SendLocalizedMessage( 1072516, String.Format( "{0}\t{1}", (this.Name == null ? String.Format( "#{0}", LabelNumber ): this.Name), (int)m_LifeSpan.TotalSeconds ) ); // ~1_name~ will expire in ~2_val~ seconds! + } + + public override void OnDelete() + { + if( m_Timer != null ) + m_Timer.Stop(); + + base.OnDelete(); + } + + public virtual void CheckExpiry() + { + if( (m_CreationTime + m_LifeSpan) < DateTime.Now ) + Expire( RootParent as Mobile ); + else + InvalidateProperties(); + } + + [Constructable] + public TransientItem( int itemID, TimeSpan lifeSpan ) + : base( itemID ) + { + m_CreationTime = DateTime.Now; + m_LifeSpan = lifeSpan; + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), new TimerCallback( CheckExpiry ) ); + } + + public TransientItem( Serial serial ) + : base( serial ) + { + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + TimeSpan remaining = ((m_CreationTime + m_LifeSpan) - DateTime.Now); + + list.Add( 1072517, ((int)remaining.TotalSeconds).ToString() ); // Lifespan: ~1_val~ seconds + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int)0 ); + + writer.Write( m_LifeSpan ); + writer.Write( m_CreationTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + m_LifeSpan = reader.ReadTimeSpan(); + m_CreationTime = reader.ReadDateTime(); + + m_Timer = Timer.DelayCall( TimeSpan.FromSeconds( 5 ), TimeSpan.FromSeconds( 5 ), new TimerCallback( CheckExpiry ) ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/Mobiles/ArcaneFey.cs b/Scripts/Spells/Spellweaving/Mobiles/ArcaneFey.cs new file mode 100644 index 0000000..04b607f --- /dev/null +++ b/Scripts/Spells/Spellweaving/Mobiles/ArcaneFey.cs @@ -0,0 +1,66 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + [CorpseName( "a pixie corpse" )] + public class ArcaneFey : BaseCreature + { + public override double DispelDifficulty { get { return 70.0; } } + public override double DispelFocus { get { return 20.0; } } + + public override OppositionGroup OppositionGroup { get { return OppositionGroup.FeyAndUndead; } } + public override bool InitialInnocent { get { return true; } } + + [Constructable] + public ArcaneFey() : base( AIType.AI_Mage, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = NameList.RandomName( "pixie" ); + Body = 128; + BaseSoundID = 0x467; + + SetStr( 20 ); + SetDex( 150 ); + SetInt( 125 ); + + SetDamage( 9, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 80, 90 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 40, 50 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 40, 50 ); + + SetSkill( SkillName.EvalInt, 70.1, 80.0 ); + SetSkill( SkillName.Magery, 70.1, 80.0 ); + SetSkill( SkillName.Meditation, 70.1, 80.0 ); + SetSkill( SkillName.MagicResist, 50.5, 100.0 ); + SetSkill( SkillName.Tactics, 10.1, 20.0 ); + SetSkill( SkillName.Wrestling, 10.1, 12.5 ); + + Fame = 0; + Karma = 0; + + ControlSlots = 1; + } + + public ArcaneFey( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/Mobiles/ArcaneFiend.cs b/Scripts/Spells/Spellweaving/Mobiles/ArcaneFiend.cs new file mode 100644 index 0000000..bf6d7cc --- /dev/null +++ b/Scripts/Spells/Spellweaving/Mobiles/ArcaneFiend.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "an imp corpse" )] + public class ArcaneFiend : BaseCreature + { + public override double DispelDifficulty { get { return 70.0; } } + public override double DispelFocus { get { return 20.0; } } + + public override PackInstinct PackInstinct { get { return PackInstinct.Daemon; } } + public override bool BleedImmune { get { return true; } } //TODO: Verify on OSI. Guide says this. + + [Constructable] + public ArcaneFiend() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "an imp"; + Body = 74; + BaseSoundID = 422; + + SetStr( 55 ); + SetDex( 40 ); + SetInt( 60 ); + + SetDamage( 10, 14 ); + + SetDamageType( ResistanceType.Physical, 0 ); + SetDamageType( ResistanceType.Fire, 50 ); + SetDamageType( ResistanceType.Poison, 50 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 40, 50 ); + SetResistance( ResistanceType.Cold, 20, 30 ); + SetResistance( ResistanceType.Poison, 30, 40 ); + SetResistance( ResistanceType.Energy, 30, 40 ); + + SetSkill( SkillName.EvalInt, 20.1, 30.0 ); + SetSkill( SkillName.Magery, 60.1, 70.0 ); + SetSkill( SkillName.MagicResist, 30.1, 50.0 ); + SetSkill( SkillName.Tactics, 42.1, 50.0 ); + SetSkill( SkillName.Wrestling, 40.1, 44.0 ); + + Fame = 0; + Karma = 0; + + ControlSlots = 1; + } + + public ArcaneFiend( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/Mobiles/NatureFury.cs b/Scripts/Spells/Spellweaving/Mobiles/NatureFury.cs new file mode 100644 index 0000000..e12ab6a --- /dev/null +++ b/Scripts/Spells/Spellweaving/Mobiles/NatureFury.cs @@ -0,0 +1,87 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Mobiles +{ + public class NatureFury : BaseCreature + { + public override bool DeleteCorpseOnDeath { get { return Core.AOS; } } + public override bool IsHouseSummonable { get { return true; } } + + public override double DispelDifficulty { get { return 125.0; } } + public override double DispelFocus { get { return 90.0; } } + + public override bool BleedImmune { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public override bool AlwaysMurderer { get { return true; } } + + [Constructable] + public NatureFury() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "a nature's fury"; + Body = 0x33; + Hue = 0x4001; + + SetStr(150); + SetDex(150); + SetInt(100); + + SetHits(80); + SetStam(250); + SetMana(0); + + SetDamage(6, 8); + + SetDamageType(ResistanceType.Poison, 100); + SetDamageType(ResistanceType.Physical, 0); + SetResistance(ResistanceType.Physical, 90); + + SetSkill(SkillName.Wrestling, 90.0); + SetSkill(SkillName.MagicResist, 70.0); + SetSkill(SkillName.Tactics, 100.0); + + Fame = 0; + Karma = 0; + + ControlSlots = 1; + } + + public override void MoveToWorld(Point3D loc, Map map) + { + base.MoveToWorld(loc, map); + Timer.DelayCall(TimeSpan.Zero, DoEffects); + } + + public void DoEffects() + { + FixedParticles(0x91C, 10, 180, 0x2543, 0, 0, EffectLayer.Waist); + PlaySound(0xE); + PlaySound(0x1BC); + + if (Alive && !Deleted) + Timer.DelayCall(TimeSpan.FromSeconds(7.0), DoEffects); + } + + public NatureFury(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/NatureFury.cs b/Scripts/Spells/Spellweaving/NatureFury.cs new file mode 100644 index 0000000..4c44fed --- /dev/null +++ b/Scripts/Spells/Spellweaving/NatureFury.cs @@ -0,0 +1,122 @@ +using System; +using Server.Mobiles; +using Server.Targeting; +using Server.Regions; + +namespace Server.Spells.Spellweaving +{ + public class NatureFurySpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Nature's Fury", "Rauvvrae", + -1, + false + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill { get { return 0.0; } } + public override int RequiredMana { get { return 24; } } + + public NatureFurySpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( ( Caster.Followers + 1 ) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D point ) + { + Point3D p = new Point3D( point ); + Map map = Caster.Map; + + if ( map == null ) + return; + + HouseRegion r = Region.Find( p, map ).GetRegion( typeof( HouseRegion ) ) as HouseRegion; + + if ( r != null && r.House != null && !r.House.IsFriend( Caster ) ) + return; + + if ( !map.CanSpawnMobile( p.X, p.Y, p.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + TimeSpan duration = TimeSpan.FromSeconds( Caster.Skills.Spellweaving.Value / 24 + 25 + FocusLevel * 2 ); + + NatureFury nf = new NatureFury(); + BaseCreature.Summon( nf, false, Caster, p, 0x5CB, duration ); + + new InternalTimer( nf ).Start(); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private NatureFurySpell m_Owner; + + public InternalTarget( NatureFurySpell owner ) + : base( 10, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + if ( m_Owner != null ) + m_Owner.FinishSequence(); + } + } + + private class InternalTimer : Timer + { + private NatureFury m_NatureFury; + + public InternalTimer( NatureFury nf ) + : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + m_NatureFury = nf; + } + + protected override void OnTick() + { + if ( m_NatureFury.Deleted || !m_NatureFury.Alive || m_NatureFury.DamageMin > 20 ) + { + Stop(); + } + else + { + ++m_NatureFury.DamageMin; + ++m_NatureFury.DamageMax; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/ReaperForm.cs b/Scripts/Spells/Spellweaving/ReaperForm.cs new file mode 100644 index 0000000..bda6293 --- /dev/null +++ b/Scripts/Spells/Spellweaving/ReaperForm.cs @@ -0,0 +1,55 @@ +using System; +using Server.Network; + +namespace Server.Spells.Spellweaving +{ + public class ReaperFormSpell : ArcaneForm + { + private static SpellInfo m_Info = new SpellInfo( "Reaper Form", "Tarisstree", -1 ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.5 ); } } + + public static void Initialize() + { + EventSink.Login += new LoginEventHandler( OnLogin ); + } + + public static void OnLogin( LoginEventArgs e ) + { + TransformContext context = TransformationSpellHelper.GetContext( e.Mobile ); + + if( context != null && context.Type == typeof( ReaperFormSpell ) ) + e.Mobile.Send( SpeedControl.WalkSpeed ); + } + + public override double RequiredSkill { get { return 24.0; } } + public override int RequiredMana { get { return 34; } } + + public override int Body { get { return 0x11D; } } + + public override int FireResistOffset { get { return -25; } } + public override int PhysResistOffset { get { return 5 + FocusLevel; } } + public override int ColdResistOffset { get { return 5 + FocusLevel; } } + public override int PoisResistOffset { get { return 5 + FocusLevel; } } + public override int NrgyResistOffset { get { return 5 + FocusLevel; } } + + public virtual int SwingSpeedBonus { get { return 10 + FocusLevel; } } + public virtual int SpellDamageBonus { get { return 10 + FocusLevel; } } + + public ReaperFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void DoEffect( Mobile m ) + { + m.PlaySound( 0x1BA ); + + m.Send( SpeedControl.WalkSpeed ); + } + + public override void RemoveEffect( Mobile m ) + { + m.Send( SpeedControl.Disable ); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/SummonFey.cs b/Scripts/Spells/Spellweaving/SummonFey.cs new file mode 100644 index 0000000..1f14a39 --- /dev/null +++ b/Scripts/Spells/Spellweaving/SummonFey.cs @@ -0,0 +1,45 @@ +using System; +using Server.Mobiles; +using Server.Engines.MLQuests; + +namespace Server.Spells.Spellweaving +{ + public class SummonFeySpell : ArcaneSummon + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Fey", "Alalithra", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill { get { return 38.0; } } + public override int RequiredMana { get { return 10; } } + + public SummonFeySpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override int Sound { get { return 0x217; } } + + public override bool CheckSequence() + { + Mobile caster = Caster; + + // This is done after casting completes + if (caster is PlayerMobile) + { + MLQuestContext context = MLQuestSystem.GetContext((PlayerMobile)caster); + + if (context == null || !context.SummonFey) + { + caster.SendLocalizedMessage(1074563); // You haven't forged a friendship with the fey and are unable to summon their aid. + return false; + } + } + + return base.CheckSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/SummonFiend.cs b/Scripts/Spells/Spellweaving/SummonFiend.cs new file mode 100644 index 0000000..7cc0c51 --- /dev/null +++ b/Scripts/Spells/Spellweaving/SummonFiend.cs @@ -0,0 +1,45 @@ +using System; +using Server.Mobiles; +using Server.Engines.MLQuests; + +namespace Server.Spells.Spellweaving +{ + public class SummonFiendSpell : ArcaneSummon + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Fiend", "Nylisstra", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2.0 ); } } + + public override double RequiredSkill { get { return 38.0; } } + public override int RequiredMana { get { return 10; } } + + public SummonFiendSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override int Sound { get { return 0x216; } } + + public override bool CheckSequence() + { + Mobile caster = Caster; + + // This is done after casting completes + if (caster is PlayerMobile) + { + MLQuestContext context = MLQuestSystem.GetContext((PlayerMobile)caster); + + if (context == null || !context.SummonFiend) + { + caster.SendLocalizedMessage(1074564); // You haven't demonstrated mastery to summon a fiend. + return false; + } + } + + return base.CheckSequence(); + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/Thunderstorm.cs b/Scripts/Spells/Spellweaving/Thunderstorm.cs new file mode 100644 index 0000000..14246e5 --- /dev/null +++ b/Scripts/Spells/Spellweaving/Thunderstorm.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Spells.Spellweaving +{ + public class ThunderstormSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Thunderstorm", "Erelonia", + -1 + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + + public override double RequiredSkill { get { return 10.0; } } + public override int RequiredMana { get { return 32; } } + + public ThunderstormSpell( Mobile caster, Item scroll ) + : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + if( CheckSequence() ) + { + Caster.PlaySound( 0x5CE ); + + double skill = Caster.Skills[SkillName.Spellweaving].Value; + + int damage = Math.Max( 11, 10 + (int)(skill / 24) ) + FocusLevel; + + int sdiBonus = AosAttributes.GetValue( Caster, AosAttribute.SpellDamage ); + + int pvmDamage = damage * ( 100 + sdiBonus ); + pvmDamage /= 100; + + if ( sdiBonus > 15 ) + sdiBonus = 15; + + int pvpDamage = damage * ( 100 + sdiBonus ); + pvpDamage /= 100; + + int range = 2 + FocusLevel; + TimeSpan duration = TimeSpan.FromSeconds( 5 + FocusLevel ); + + List targets = new List(); + + foreach( Mobile m in Caster.GetMobilesInRange( range ) ) + { + if( Caster != m && SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) && Caster.InLOS( m ) ) + targets.Add( m ); + } + + for( int i = 0; i < targets.Count; i++ ) + { + Mobile m = targets[i]; + + Caster.DoHarmful( m ); + + Spell oldSpell = m.Spell as Spell; + + SpellHelper.Damage( this, m, ( m.Player && Caster.Player ) ? pvpDamage : pvmDamage, 0, 0, 0, 0, 100 ); + + if( oldSpell != null && oldSpell != m.Spell ) + { + if( !CheckResisted( m ) ) + { + m_Table[m] = Timer.DelayCall( duration, DoExpire, m ); + + BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.Thunderstorm, 1075800, duration, m, GetCastRecoveryMalus( m ) ) ); + } + } + } + } + + FinishSequence(); + } + + private static Dictionary m_Table = new Dictionary(); + + public static int GetCastRecoveryMalus( Mobile m ) + { + return m_Table.ContainsKey( m ) ? 6 : 0; + } + + public static void DoExpire( Mobile m ) + { + Timer t; + + if( m_Table.TryGetValue( m, out t ) ) + { + t.Stop(); + m_Table.Remove( m ); + + BuffInfo.RemoveBuff( m, BuffIcon.Thunderstorm ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Spellweaving/WordOfDeath.cs b/Scripts/Spells/Spellweaving/WordOfDeath.cs new file mode 100644 index 0000000..7ec5a2d --- /dev/null +++ b/Scripts/Spells/Spellweaving/WordOfDeath.cs @@ -0,0 +1,93 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Spellweaving +{ + public class WordOfDeathSpell : ArcanistSpell + { + private static SpellInfo m_Info = new SpellInfo( "Word of Death", "Nyraxle", -1 ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 3.5 ); } } + + public override double RequiredSkill { get { return 80.0; } } + public override int RequiredMana { get { return 50; } } + + public WordOfDeathSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if( CheckHSequence( m ) ) + { + Point3D loc = m.Location; + loc.Z += 50; + + m.PlaySound( 0x211 ); + m.FixedParticles( 0x3779, 1, 30, 0x26EC, 0x3, 0x3, EffectLayer.Waist ); + + Effects.SendMovingParticles( new Entity( Serial.Zero, loc, m.Map ), new Entity( Serial.Zero, m.Location, m.Map ), 0xF5F, 1, 0, true, false, 0x21, 0x3F, 0x251D, 0, 0, EffectLayer.Head, 0 ); + + double percentage = 0.05 * FocusLevel; + + int damage; + + if( !m.Player && (((double)m.Hits / (double)m.HitsMax) < percentage )) + { + damage = 300; + } + else + { + int minDamage = (int)Caster.Skills.Spellweaving.Value / 5; + int maxDamage = (int)Caster.Skills.Spellweaving.Value / 3; + damage = Utility.RandomMinMax(minDamage, maxDamage); + int damageBonus = AosAttributes.GetValue( Caster, AosAttribute.SpellDamage ); + if (m.Player && damageBonus > 15) + damageBonus = 15; + damage *= damageBonus + 100; + damage /= 100; + } + + int[] types = new int[4]; + types[Utility.Random( types.Length )] = 100; + + SpellHelper.Damage( this, m, damage, 0, types[0], types[1], types[2], types[3] ); //Chaos damage. Random elemental damage + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private WordOfDeathSpell m_Owner; + + public InternalTarget( WordOfDeathSpell owner ) : base( 10, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile m, object o ) + { + if( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile m ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/Bless.cs b/Scripts/Spells/Third/Bless.cs new file mode 100644 index 0000000..40292d1 --- /dev/null +++ b/Scripts/Spells/Third/Bless.cs @@ -0,0 +1,90 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Third +{ + public class BlessSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Bless", "Rel Sanct", + 203, + 9061, + Reagent.Garlic, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public BlessSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if (Engines.ConPVP.DuelContext.CheckSuddenDeath(Caster)) + { + Caster.SendMessage(0x22, "You cannot cast this spell when in sudden death."); + return false; + } + + return base.CheckCast(); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.AddStatBonus( Caster, m, StatType.Str ); SpellHelper.DisableSkillCheck = true; + SpellHelper.AddStatBonus( Caster, m, StatType.Dex ); + SpellHelper.AddStatBonus( Caster, m, StatType.Int ); SpellHelper.DisableSkillCheck = false; + + m.FixedParticles( 0x373A, 10, 15, 5018, EffectLayer.Waist ); + m.PlaySound( 0x1EA ); + + int percentage = (int)(SpellHelper.GetOffsetScalar(Caster, m, false) * 100); + TimeSpan length = SpellHelper.GetDuration(Caster, m); + + string args = String.Format("{0}\t{1}\t{2}", percentage, percentage, percentage); + + BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bless, 1075847, 1075848, length, m, args.ToString())); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private BlessSpell m_Owner; + + public InternalTarget( BlessSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/Fireball.cs b/Scripts/Spells/Third/Fireball.cs new file mode 100644 index 0000000..18ed0d1 --- /dev/null +++ b/Scripts/Spells/Third/Fireball.cs @@ -0,0 +1,93 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Third +{ + public class FireballSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Fireball", "Vas Flam", + 203, + 9041, + Reagent.BlackPearl + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public FireballSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public override bool DelayedDamage{ get{ return true; } } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + Mobile source = Caster; + + SpellHelper.Turn( source, m ); + + SpellHelper.CheckReflect( (int)this.Circle, ref source, ref m ); + + double damage; + + if ( Core.AOS ) + { + damage = GetNewAosDamage( 19, 1, 5, m ); + } + else + { + damage = Utility.Random( 10, 7 ); + + if ( CheckResisted( m ) ) + { + damage *= 0.75; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + damage *= GetDamageScalar( m ); + } + + source.MovingParticles( m, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160 ); + source.PlaySound( Core.AOS ? 0x15E : 0x44B ); + + SpellHelper.Damage( this, m, damage, 0, 100, 0, 0, 0 ); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private FireballSpell m_Owner; + + public InternalTarget( FireballSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/MagicLock.cs b/Scripts/Spells/Third/MagicLock.cs new file mode 100644 index 0000000..302a124 --- /dev/null +++ b/Scripts/Spells/Third/MagicLock.cs @@ -0,0 +1,87 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Items; + +namespace Server.Spells.Third +{ + public class MagicLockSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Magic Lock", "An Por", + 215, + 9001, + Reagent.Garlic, + Reagent.Bloodmoss, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public MagicLockSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( LockableContainer targ ) + { + if ( Multis.BaseHouse.CheckLockedDownOrSecured( targ ) ) + { + // You cannot cast this on a locked down item. + Caster.LocalOverheadMessage( MessageType.Regular, 0x22, 501761 ); + } + else if ( targ.Locked || targ.LockLevel == 0 || targ is ParagonChest ) + { + // Target must be an unlocked chest. + Caster.SendLocalizedMessage( 501762 ); + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, targ ); + + Point3D loc = targ.GetWorldLocation(); + + Effects.SendLocationParticles( + EffectItem.Create( loc, targ.Map, EffectItem.DefaultDuration ), + 0x376A, 9, 32, 5020 ); + + Effects.PlaySound( loc, targ.Map, 0x1FA ); + + // The chest is now locked! + Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501763 ); + + targ.LockLevel = -255; // signal magic lock + targ.Locked = true; + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private MagicLockSpell m_Owner; + + public InternalTarget( MagicLockSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is LockableContainer ) + m_Owner.Target( (LockableContainer)o ); + else + from.SendLocalizedMessage( 501762 ); // Target must be an unlocked chest. + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/Poison.cs b/Scripts/Spells/Third/Poison.cs new file mode 100644 index 0000000..2195176 --- /dev/null +++ b/Scripts/Spells/Third/Poison.cs @@ -0,0 +1,149 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Third +{ + public class PoisonSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Poison", "In Nox", + 203, + 9051, + Reagent.Nightshade + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public PoisonSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + if ( m.Spell != null ) + m.Spell.OnCasterHurt(); + + m.Paralyzed = false; + + if ( CheckResisted( m ) ) + { + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + else + { + int level; + + if ( Core.AOS ) + { + if ( Caster.InRange( m, 2 ) ) + { + int total = (Caster.Skills.Magery.Fixed + Caster.Skills.Poisoning.Fixed) / 2; + + if ( total >= 1000 ) + level = 3; + else if ( total > 850 ) + level = 2; + else if ( total > 650 ) + level = 1; + else + level = 0; + } + else + { + level = 0; + } + } + else + { + //double total = Caster.Skills[SkillName.Magery].Value + Caster.Skills[SkillName.Poisoning].Value; + + #region Dueling + double total = Caster.Skills[SkillName.Magery].Value; + + if (Caster is Mobiles.PlayerMobile) + { + Mobiles.PlayerMobile pm = (Mobiles.PlayerMobile)Caster; + + if (pm.DuelContext != null && pm.DuelContext.Started && !pm.DuelContext.Finished && !pm.DuelContext.Ruleset.GetOption("Skills", "Poisoning")) + { + } + else + { + total += Caster.Skills[SkillName.Poisoning].Value; + } + } + else + { + total += Caster.Skills[SkillName.Poisoning].Value; + } + #endregion + + double dist = Caster.GetDistanceToSqrt( m ); + + if ( dist >= 3.0 ) + total -= (dist - 3.0) * 10.0; + + if ( total >= 200.0 && 1 > Utility.Random( 10 ) ) + level = 3; + else if ( total > (Core.AOS ? 170.1 : 170.0) ) + level = 2; + else if ( total > (Core.AOS ? 130.1 : 130.0) ) + level = 1; + else + level = 0; + } + + m.ApplyPoison( Caster, Poison.GetPoison( level ) ); + } + + m.FixedParticles( 0x374A, 10, 15, 5021, EffectLayer.Waist ); + m.PlaySound( 0x205 ); + + HarmfulSpell(m); + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private PoisonSpell m_Owner; + + public InternalTarget( PoisonSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/Telekinesis.cs b/Scripts/Spells/Third/Telekinesis.cs new file mode 100644 index 0000000..71edd73 --- /dev/null +++ b/Scripts/Spells/Third/Telekinesis.cs @@ -0,0 +1,110 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Regions; +using Server.Items; + +namespace Server.Spells.Third +{ + public class TelekinesisSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Telekinesis", "Ort Por Ylem", + 203, + 9031, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public TelekinesisSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( ITelekinesisable obj ) + { + if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, obj ); + + obj.OnTelekinesis( Caster ); + } + + FinishSequence(); + } + + public void Target( Container item ) + { + if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, item ); + + object root = item.RootParent; + + if ( !item.IsAccessibleTo( Caster ) ) + { + item.OnDoubleClickNotAccessible( Caster ); + } + else if ( !item.CheckItemUse( Caster, item ) ) + { + } + else if ( root != null && root is Mobile && root != Caster ) + { + item.OnSnoop( Caster ); + } + else if ( item is Corpse && !((Corpse)item).CheckLoot( Caster, null ) ) + { + } + else if ( Caster.Region.OnDoubleClick( Caster, item ) ) + { + Effects.SendLocationParticles( EffectItem.Create( item.Location, item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5022 ); + Effects.PlaySound( item.Location, item.Map, 0x1F5 ); + + + item.OnItemUsed( Caster, item ); + } + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private TelekinesisSpell m_Owner; + + public InternalTarget( TelekinesisSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is ITelekinesisable ) + m_Owner.Target( (ITelekinesisable)o ); + else if ( o is Container ) + m_Owner.Target( (Container)o ); + else + from.SendLocalizedMessage( 501857 ); // This spell won't work on that! + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} + +namespace Server +{ + public interface ITelekinesisable : IPoint3D + { + void OnTelekinesis( Mobile from ); + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/Teleport.cs b/Scripts/Spells/Third/Teleport.cs new file mode 100644 index 0000000..db85ead --- /dev/null +++ b/Scripts/Spells/Third/Teleport.cs @@ -0,0 +1,140 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Regions; +using Server.Items; + +namespace Server.Spells.Third +{ + public class TeleportSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Teleport", "Rel Por", + 215, + 9031, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public TeleportSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override bool CheckCast() + { + if ( Factions.Sigil.ExistsOn( Caster ) ) + { + Caster.SendLocalizedMessage( 1061632 ); // You can't do that while carrying the sigil. + return false; + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel( Caster, TravelCheckType.TeleportFrom ); + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target(IPoint3D p) + { + IPoint3D orig = p; + Map map = Caster.Map; + + SpellHelper.GetSurfaceTop(ref p); + + Point3D from = Caster.Location; + Point3D to = new Point3D(p); + + if (Factions.Sigil.ExistsOn(Caster)) + { + Caster.SendLocalizedMessage(1061632); // You can't do that while carrying the sigil. + } + else if (Server.Misc.WeightOverloading.IsOverloaded(Caster)) + { + Caster.SendLocalizedMessage(502359, "", 0x22); // Thou art too encumbered to move. + } + else if (!SpellHelper.CheckTravel(Caster, TravelCheckType.TeleportFrom)) + { + } + else if (!SpellHelper.CheckTravel(Caster, map, to, TravelCheckType.TeleportTo)) + { + } + else if (map == null || !map.CanSpawnMobile(p.X, p.Y, p.Z)) + { + Caster.SendLocalizedMessage(501942); // That location is blocked. + } + else if (SpellHelper.CheckMulti(to, map)) + { + Caster.SendLocalizedMessage(502831); // Cannot teleport to that spot. + } + else if (Region.Find(to, map).GetRegion(typeof(HouseRegion)) != null) + { + Caster.SendLocalizedMessage(502829); // Cannot teleport to that spot. + } + else if (CheckSequence()) + { + SpellHelper.Turn(Caster, orig); + + Mobile m = Caster; + + m.Location = to; + m.ProcessDelta(); + + if (m.Player) + { + Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); + Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 5023); + } + else + { + m.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist); + } + + m.PlaySound(0x1FE); + + IPooledEnumerable eable = m.GetItemsInRange(0); + + foreach (Item item in eable) + { + if (item is Server.Spells.Sixth.ParalyzeFieldSpell.InternalItem || item is Server.Spells.Fifth.PoisonFieldSpell.InternalItem || item is Server.Spells.Fourth.FireFieldSpell.FireFieldItem) + item.OnMoveOver(m); + } + + eable.Free(); + } + + FinishSequence(); + } + + public class InternalTarget : Target + { + private TeleportSpell m_Owner; + + public InternalTarget( TeleportSpell owner ) : base( Core.ML ? 11 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/Unlock.cs b/Scripts/Spells/Third/Unlock.cs new file mode 100644 index 0000000..7efc914 --- /dev/null +++ b/Scripts/Spells/Third/Unlock.cs @@ -0,0 +1,89 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Items; + +namespace Server.Spells.Third +{ + public class UnlockSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Unlock Spell", "Ex Por", + 215, + 9001, + Reagent.Bloodmoss, + Reagent.SulfurousAsh + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public UnlockSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private UnlockSpell m_Owner; + + public InternalTarget( UnlockSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D loc = o as IPoint3D; + + if ( loc == null ) + return; + + if ( m_Owner.CheckSequence() ) { + SpellHelper.Turn( from, o ); + + Effects.SendLocationParticles( EffectItem.Create( new Point3D( loc ), from.Map, EffectItem.DefaultDuration ), 0x376A, 9, 32, 5024 ); + + Effects.PlaySound( loc, from.Map, 0x1FF ); + + if ( o is Mobile ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 503101 ); // That did not need to be unlocked. + else if ( !( o is LockableContainer ) ) + from.SendLocalizedMessage( 501666 ); // You can't unlock that! + else { + LockableContainer cont = (LockableContainer)o; + + if ( Multis.BaseHouse.CheckSecured( cont ) ) + from.SendLocalizedMessage( 503098 ); // You cannot cast this on a secure item. + else if ( !cont.Locked ) + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 503101 ); // That did not need to be unlocked. + else if ( cont.LockLevel == 0 ) + from.SendLocalizedMessage( 501666 ); // You can't unlock that! + else { + int level = (int)(from.Skills[SkillName.Magery].Value * 0.8) - 4; + + if ( level >= cont.RequiredSkill && !(cont is TreasureMapChest && ((TreasureMapChest)cont).Level > 2) ) { + cont.Locked = false; + + if ( cont.LockLevel == -255 ) + cont.LockLevel = cont.RequiredSkill - 10; + } + else + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 503099 ); // My spell does not seem to have an effect on that lock. + } + } + } + + m_Owner.FinishSequence(); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/Third/WallOfStone.cs b/Scripts/Spells/Third/WallOfStone.cs new file mode 100644 index 0000000..6223816 --- /dev/null +++ b/Scripts/Spells/Third/WallOfStone.cs @@ -0,0 +1,226 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Third +{ + public class WallOfStoneSpell : MagerySpell + { + private static SpellInfo m_Info = new SpellInfo( + "Wall of Stone", "In Sanct Ylem", + 227, + 9011, + false, + Reagent.Bloodmoss, + Reagent.Garlic + ); + + public override SpellCircle Circle { get { return SpellCircle.Third; } } + + public WallOfStoneSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + { + eastToWest = false; + } + else if ( rx >= 0 ) + { + eastToWest = true; + } + else if ( ry >= 0 ) + { + eastToWest = true; + } + else + { + eastToWest = false; + } + + Effects.PlaySound( p, Caster.Map, 0x1F6 ); + + for ( int i = -1; i <= 1; ++i ) + { + Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z ); + bool canFit = SpellHelper.AdjustField( ref loc, Caster.Map, 22, true ); + + //Effects.SendLocationParticles( EffectItem.Create( loc, Caster.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5025 ); + + if ( !canFit ) + continue; + + Item item = new InternalItem( loc, Caster.Map, Caster ); + + Effects.SendLocationParticles( item, 0x376A, 9, 10, 5025 ); + + //new InternalItem( loc, Caster.Map, Caster ); + } + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Caster; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, Mobile caster ) : base( 0x82 ) + { + Visible = false; + Movable = false; + + MoveToWorld( loc, map ); + + m_Caster = caster; + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 10.0 ) ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 10.0 ); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, m_End - DateTime.Now ); + m_Timer.Start(); + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds( 10.0 ); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + + public override bool OnMoveOver( Mobile m ) + { + int noto; + + if ( m is PlayerMobile ) + { + noto = Notoriety.Compute( m_Caster, m ); + if ( noto == Notoriety.Enemy || noto == Notoriety.Ally ) + return false; + } + return base.OnMoveOver( m ); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + + public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration ) + { + Priority = TimerPriority.OneSecond; + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + private class InternalTarget : Target + { + private WallOfStoneSpell m_Owner; + + public InternalTarget( WallOfStoneSpell owner ) : base( Core.ML ? 10 : 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Spells/UnsummonTimer.cs b/Scripts/Spells/UnsummonTimer.cs new file mode 100644 index 0000000..e23298b --- /dev/null +++ b/Scripts/Spells/UnsummonTimer.cs @@ -0,0 +1,24 @@ +using System; +using Server.Mobiles; + +namespace Server.Spells +{ + class UnsummonTimer : Timer + { + private BaseCreature m_Creature; + private Mobile m_Caster; + + public UnsummonTimer( Mobile caster, BaseCreature creature, TimeSpan delay ) : base( delay ) + { + m_Caster = caster; + m_Creature = creature; + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + if ( !m_Creature.Deleted ) + m_Creature.Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Targets/BladedItemTarget.cs b/Scripts/Targets/BladedItemTarget.cs new file mode 100644 index 0000000..e7b8e04 --- /dev/null +++ b/Scripts/Targets/BladedItemTarget.cs @@ -0,0 +1,208 @@ +using System; +using Server; +using Server.Targeting; +using Server.Items; +using Server.Engines.Harvest; +using Server.Mobiles; +using Server.Engines.Quests; +using Server.Engines.Quests.Hag; +using Server.Regions; + +namespace Server.Targets +{ + public class BladedItemTarget : Target + { + private Item m_Item; + + public BladedItemTarget( Item item ) : base( 2, false, TargetFlags.None ) + { + m_Item = item; + } + + protected override void OnTargetOutOfRange( Mobile from, object targeted ) + { + if ( targeted is UnholyBone && from.InRange( ((UnholyBone)targeted), 12 ) ) + ((UnholyBone)targeted).Carve( from, m_Item ); + else + base.OnTargetOutOfRange (from, targeted); + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Item.Deleted ) + return; + + if ( targeted is ICarvable ) + { + ((ICarvable)targeted).Carve( from, m_Item ); + } + else if ( targeted is SwampDragon && ((SwampDragon)targeted).HasBarding ) + { + SwampDragon pet = (SwampDragon)targeted; + + if ( !pet.Controlled || pet.ControlMaster != from ) + from.SendLocalizedMessage( 1053022 ); // You cannot remove barding from a swamp dragon you do not own. + else + pet.HasBarding = false; + } + else if (targeted is Head) + { + Head targ = (Head)targeted; + + if (from.Karma > - 1500) + { + from.SendMessage("Vous n'avez pas le profil d'un d�peceur de cr�ne..."); + return; + } + + if (from.Dex <= Utility.Random(110)) + { + from.SendMessage("Vous avez �t� trop maladroit et avez rat� le d�pe�age"); + targ.Delete(); + return; + } + + from.SendMessage("Vous achevez d'enlever la chair du cr�ne."); + from.AddToBackpack(new Skull()); + targ.Consume(); + } + else if (targeted is Pumpkin) + { + Pumpkin targ = (Pumpkin)targeted; + + if(from.Dex <= Utility.Random(100)) + { + from.SendMessage("Vous avez �t� trop maladroit et avez rat� votre trac�"); + targ.Consume(); + return; + } + + int karma= 0; + + if (from.Karma > 100) + karma ++; + else if (from.Karma < -100) + karma --; + + int chance = Utility.Random(4) + karma; + + if (chance >=2) + from.AddToBackpack(new SmileyPumpkin()); + else + from.AddToBackpack(new EvilPumpkin()); + + from.SendMessage("Vous taillez la citrouille selon votre humeur"); + targ.Consume(); + } + else + { + if ( targeted is StaticTarget ) + { + int itemID = ((StaticTarget)targeted).ItemID; + + if ( itemID == 0xD15 || itemID == 0xD16 ) // red mushroom + { + PlayerMobile player = from as PlayerMobile; + + if ( player != null ) + { + QuestSystem qs = player.Quest; + + if ( qs is WitchApprenticeQuest ) + { + FindIngredientObjective obj = qs.FindObjective( typeof( FindIngredientObjective ) ) as FindIngredientObjective; + + if ( obj != null && !obj.Completed && obj.Ingredient == Ingredient.RedMushrooms ) + { + player.SendLocalizedMessage( 1055036 ); // You slice a red cap mushroom from its stem. + obj.Complete(); + return; + } + } + } + } + } + + HarvestSystem system = Lumberjacking.System; + HarvestDefinition def = Lumberjacking.System.Definition; + + int tileID; + Map map; + Point3D loc; + + if ( !system.GetHarvestDetails( from, m_Item, targeted, out tileID, out map, out loc ) ) + { + from.SendLocalizedMessage( 500494 ); // You can't use a bladed item on that! + } + else if ( !def.Validate( tileID ) ) + { + from.SendLocalizedMessage( 500494 ); // You can't use a bladed item on that! + } + else + { + HarvestBank bank = def.GetBank( map, loc.X, loc.Y ); + + if ( bank == null ) + return; + + if ( bank.Current < 5 ) + { + from.SendLocalizedMessage( 500493 ); // There's not enough wood here to harvest. + } + else + { + bank.Consume( 5, from ); + + if (map.Season == (int)ServerSeasons.Season.Spring && Utility.RandomDouble() < 0.33) + { + from.PrivateOverheadMessage(Network.MessageType.Regular, 0x3B2, false, "De la s�ve se met � couler du tronc, souhaitez-vous la recueillir?", from.NetState); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnSelectTarget)); + return; + } + + Item item = new Kindling(); + + if ( from.PlaceInBackpack( item ) ) + { + from.SendLocalizedMessage( 500491 ); // You put some kindling into your backpack. + from.SendLocalizedMessage( 500492 ); // An axe would probably get you more wood. + } + else + { + from.SendLocalizedMessage( 500490 ); // You can't place any kindling into your backpack! + + item.Delete(); + } + } + } + } + } + public void OnSelectTarget(Mobile from, object obj) + { + if (!(obj is ResourceBucket)) + { + from.SendMessage("Vous devriez utiliser un seau ad�quat"); + return; + } + + ResourceBucket bucket = (ResourceBucket)obj; + + if(bucket.MilkType != Milk.None) + { + from.SendMessage("Cela ferait un trop curieux m�lange"); + return; + } + + if (bucket.Quantity >= bucket.MaxQuantity) + { + from.SendMessage("Votre seau est plein"); + return; + } + + bucket.ResourceType = BucketLiquid.SugarWater; + bucket.Quantity +=Utility.Random(1,5); + + return; + } + } +} \ No newline at end of file diff --git a/Scripts/Targets/MoveTarget.cs b/Scripts/Targets/MoveTarget.cs new file mode 100644 index 0000000..aee6b36 --- /dev/null +++ b/Scripts/Targets/MoveTarget.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Targets +{ + public class MoveTarget : Target + { + private object m_Object; + + public MoveTarget( object o ) : base( -1, true, TargetFlags.None ) + { + m_Object = o; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + { + if ( !BaseCommand.IsAccessible( from, m_Object ) ) + { + from.SendMessage( "That is not accessible." ); + return; + } + + if ( p is Item ) + p = ((Item)p).GetWorldTop(); + + CommandLogging.WriteLine( from, "{0} {1} moving {2} to {3}", from.AccessLevel, CommandLogging.Format( from ), CommandLogging.Format( m_Object ), new Point3D( p ) ); + + if ( m_Object is Item ) + { + Item item = (Item)m_Object; + + if ( !item.Deleted ) + item.MoveToWorld( new Point3D( p ), from.Map ); + } + else if ( m_Object is Mobile ) + { + Mobile m = (Mobile)m_Object; + + if ( !m.Deleted ) + m.MoveToWorld( new Point3D( p ), from.Map ); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Targets/PickMoveTarget.cs b/Scripts/Targets/PickMoveTarget.cs new file mode 100644 index 0000000..56a99de --- /dev/null +++ b/Scripts/Targets/PickMoveTarget.cs @@ -0,0 +1,27 @@ +using System; +using Server; +using Server.Targeting; +using Server.Commands; +using Server.Commands.Generic; + +namespace Server.Targets +{ + public class PickMoveTarget : Target + { + public PickMoveTarget() : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( !BaseCommand.IsAccessible( from, o ) ) + { + from.SendMessage( "That is not accessible." ); + return; + } + + if ( o is Item || o is Mobile ) + from.Target = new MoveTarget( o ); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster1.cs b/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster1.cs new file mode 100644 index 0000000..b798468 --- /dev/null +++ b/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster1.cs @@ -0,0 +1,160 @@ +//Myron : Premier maitre d'arme Bushido +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.Mobiles +{ + public class BushidoMaster1 : BaseCreature + { + private PlayerMobile QuestPlayer; + [Constructable] + public BushidoMaster1() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SetSkill(SkillName.Macing, 50.0, 55.0); + Name = "Cedric"; + Title = ", Le Combattant"; + Direction = Direction.South; + + Body = 400; + Hue = 33825; + Blessed = true; + + InitStats(100, 100, 25); + + SpeechHue = 802; + EmoteHue = 802; + + Backpack bp = new Backpack(); + bp.Movable = false; + AddItem(bp); + AddItem(new Robe(2224)); + AddItem(new QuarterStaff()); + AddItem(new RingmailGloves()); + AddItem(new RingmailChest()); + AddItem(new RingmailLegs()); + Boots b = new Boots(); + b.Hue = 1527; + AddItem(b); + this.HairItemID = 8253; + this.HairHue = 1129; + QuestPlayer = null; + } + + public override bool HandlesOnSpeech(Mobile from) + { + return from.Alive && from.Skills[SkillName.Tactics].Base >= 40 && from.InRange(this, 3); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled) + { + Mobile m = e.Mobile; + + if (m == null || !m.Player) return; + + string speech = e.Speech.ToLower(); + + if (speech.IndexOf("bonjour") >= 0) + Say("Bonjour, Que diriez vous d'un petit duel d'honneur?"); + else if (speech.IndexOf("duel") >= 0) + { + Say("En garde alors!"); + QuestPlayer = (PlayerMobile)e.Mobile; + this.Blessed = false; + this.Attack(e.Mobile); + this.Warmode = true; + } + else if (speech.IndexOf("revoir") >= 0) + { + Say("Au revoir!"); + } + else if (speech.IndexOf("je renonce au bushido") >= 0) + { + + BookOfBushido rb = (BookOfBushido)e.Mobile.Backpack.FindItemByType(typeof(BookOfBushido)); + if (rb != null) + { + Say("Si tel est votre choix."); + rb.Delete(); + } + else { Say("Vous ne vous étiez pas encore engagé dans cette foie de toute façon."); } + + } + else + Emote("*Ne semble pas réagir*"); + } + e.Handled = true; + } + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + if (defender.Hits < 10) { + this.Combatant = null; + QuestPlayer.Criminal = false; + QuestPlayer = null; + this.Warmode = false; + this.Blessed = true; + Say("Encore un peu et vous y passier!"); + } + } + + public override bool OnBeforeDeath() + { + this.Hits = 100; + this.Blessed = true; + if (!(QuestPlayer.Backpack.FindItemByType(typeof(NecromancerSpellbook)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(NecromancerSpellbook)))){ + if (!(QuestPlayer.Backpack.FindItemByType(typeof(BookOfNinjitsu)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfNinjitsu)))) + { + if (!(QuestPlayer.Backpack.FindItemByType(typeof(BookOfChivalry)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfChivalry)))) + { + if (!(QuestPlayer.Backpack.FindItemByType(typeof(BookOfBushido)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfBushido)))) + { + Say("Vous vous êtes battu avec Honneur, prenez ce livre et poursuivez dans cette voie."); + BookOfBushido b = new BookOfBushido(); + b.Content = 3; + QuestPlayer.Backpack.AddItem(b); + if (QuestPlayer.Skills.Bushido.Base < 25.0) + { + QuestPlayer.Skills.Bushido.Base = 25.0; + } + } + } + } + } + Say("C'est toujours agréable de se dégourdir un peu."); + QuestPlayer.Criminal = false; + this.Combatant = null; + this.QuestPlayer = null; + this.Warmode = false; + return false; + } + public override bool ClickTitle { get { return false; } } + + public BushidoMaster1(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster2.cs b/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster2.cs new file mode 100644 index 0000000..d2df0f8 --- /dev/null +++ b/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster2.cs @@ -0,0 +1,152 @@ +//Myron : Second maitre d'arme Bushido +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; +using Server.Spells.Bushido; + +namespace Server.Mobiles +{ + public class BushidoMaster2 : BaseCreature + { + private PlayerMobile QuestPlayer; + + [Constructable] + public BushidoMaster2() + : base(AIType.AI_None, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "Lee"; + Title = ", Le Combattant"; + Direction = Direction.South; + + Body = 400; + Hue = 33825; + Blessed = true; + + InitStats(25, 25, 25); + SetHits(5); + + SpeechHue = 802; + EmoteHue = 802; + + Backpack bp = new Backpack(); + bp.Movable = false; + AddItem(bp); + AddItem(new LeatherDo()); + AddItem(new LeatherHaidate()); + AddItem(new LeatherHiroSode()); + AddItem(new LeatherJingasa()); + Boots b = new Boots(); + b.Hue = 1527; + AddItem(b); + this.HairItemID = 8253; + this.HairHue = 1129; + QuestPlayer = null; + } + + public override bool HandlesOnSpeech(Mobile from) + { + return from.Alive && from.Skills[SkillName.Bushido].Base >= 40 && from.InRange(this, 3); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled) + { + Mobile m = e.Mobile; + + if (m == null || !m.Player) return; + + string speech = e.Speech.ToLower(); + + if (speech.IndexOf("bonjour") >= 0) + Say("Vous arrivez trop tard l'ami...Je suis déjà condamné."); + else if (speech.IndexOf("condamn") >= 0) + { + Say("Des assassins... ils m'ont empoisonné d'un coup de dague dans le dos! Je n'ai rien pu faire."); + } + else if (speech.IndexOf("assassin") >= 0) + { + Say("Une bande de lache sans une once d'honneur. J'aurais mérité une mort plus honorable."); + } + else if (speech.IndexOf("honorable execution") >= 0) + { + Say("Vous me feriez cet honneur?"); + Emote("*se met à genou et baisse la tête*"); + QuestPlayer = (PlayerMobile)e.Mobile; + this.Blessed = false; + } + else if (speech.IndexOf("revoir") >= 0) + { + Say("...adieu..."); + QuestPlayer = null; + this.Blessed = true; + } + else + Emote("Arg...laissez moi donc mourrir en paix..."); + } + e.Handled = true; + } + public override void OnGotMeleeAttack(Mobile attacker) + { + if (!(attacker.Backpack.FindItemByType(typeof(BookOfBushido)) != null + || (attacker.FindItemOnLayer(Layer.FirstValid) != null && attacker.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfBushido)))) + { + QuestPlayer = null; + } + else + { + BookOfBushido rb = (BookOfBushido)attacker.Backpack.FindItemByType(typeof(BookOfBushido)); + if (rb.HasSpell(403)) { QuestPlayer = null; } + } + base.OnGotMeleeAttack(attacker); + } + + public override void OnDeath(Container c) + { + if (QuestPlayer != null) + { + // On vérifie si le questeur est bien le tueur + if (QuestPlayer == LastKiller) + { + // DelayCall pour laisser le temps d'appliquer les bonus et tout le tralala pour le GetSwingBonus + Timer.DelayCall(TimeSpan.FromSeconds(1), GiveBook); + } + } + + base.OnDeath(c); + } + + private void GiveBook() + { + // On vérifie que le questeur à réussi à tuer avec HonorableExecution + if (QuestPlayer != null && HonorableExecution.GetSwingBonus(QuestPlayer) > 0) + { + QuestPlayer.Backpack.AddItem(new CounterAttackScroll()); + } + + QuestPlayer = null; + } + + public override bool ClickTitle { get { return false; } } + + public BushidoMaster2(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster3.cs b/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster3.cs new file mode 100644 index 0000000..11d3ac9 --- /dev/null +++ b/Scripts/Vivre/BushidoQuest/Mobiles/BushidoMaster3.cs @@ -0,0 +1,172 @@ +//Myron : Troisième maitre d'arme Bushido +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.Mobiles +{ + public class BushidoMaster3 : BaseCreature + { + private PlayerMobile QuestPlayer; + [Constructable] + public BushidoMaster3() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + SetSkill(SkillName.Swords, 80.0, 85.0); + SetSkill(SkillName.Parry, 100.0, 100.0); + SetSkill(SkillName.Bushido, 100.0, 100.0); + Name = "Murray"; + Title = ", Le Pirate Honorable"; + Direction = Direction.South; + + Body = 400; + Hue = 33825; + Blessed = true; + + InitStats(100, 100, 25); + + SpeechHue = 802; + EmoteHue = 802; + + Backpack bp = new Backpack(); + bp.Movable = false; + AddItem(bp); + AddItem(new SkullCap(1759)); + AddItem(new Cutlass()); + AddItem(new ShortPants(1759)); + AddItem(new Shirt()); + AddItem(new Shoes(1759)); + + QuestPlayer = null; + } + + public override bool HandlesOnSpeech(Mobile from) + { + return from.Alive && from.Skills[SkillName.Bushido].Base >= 60 && from.InRange(this, 3); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled) + { + Mobile m = e.Mobile; + + if (m == null || !m.Player) return; + + string speech = e.Speech.ToLower(); + + if (speech.IndexOf("bonjour") >= 0) + Say("Bonjour moussaillon! Toi aussi tu viens pour la légende?"); + + else if ((speech.IndexOf("légende") >= 0)||(speech.IndexOf("legende") >= 0)) + { + Say("Et ben oui, le pirate qui a esquivé un boulet de 35, du jamais vu!"); + } + else if (speech.IndexOf("boulet") >= 0) + { + Say("Ca demande de l'entrainement mais c'est faisable tu peux me croire! Si tu as le cran de regarder la mort en face."); + } + else if ((speech.IndexOf("entrainement") >= 0) || (speech.IndexOf("entrainer") >= 0)) + { + Say("Je pourrais peut être te l'apprendre ouais...Mais va falloir me prouver que t'as du cran."); + } + else if (speech.IndexOf("cran") >= 0) + { + Say("Ben viens me montrer que t'en as moussaillon!"); + QuestPlayer = (PlayerMobile)e.Mobile; + this.Blessed = false; + this.Attack(e.Mobile); + this.Warmode = true; + } + else if (speech.IndexOf("revoir") >= 0) + { + Say("Au revoir moussaillon!"); + } + else if (speech.IndexOf("je renonce au bushido") >= 0) + { + + BookOfBushido rb = (BookOfBushido)e.Mobile.Backpack.FindItemByType(typeof(BookOfBushido)); + if (rb != null) + { + Say("Même les pirates ont de l'honneur et toi tu te débine...tu me dégoute."); + rb.Delete(); + } + else { Say("Comme si t'en avais la trempe gamin...C'est un truc d'homme ca."); } + + } + else + Emote("J'ai pas de temps à perdre avec ton baratin."); + } + e.Handled = true; + } + public override void OnGaveMeleeAttack(Mobile defender) + { + base.OnGaveMeleeAttack(defender); + if (defender.Hits < 10) { + this.Combatant = null; + QuestPlayer.Criminal = false; + QuestPlayer = null; + this.Warmode = false; + this.Blessed = true; + Say("Hahaha! Pour le cran faudra repasser. Reviens quand tu seras prêt."); + } + } + + public override bool OnBeforeDeath() + { + this.Hits = 100; + this.Blessed = true; + if (!(QuestPlayer.Backpack.FindItemByType(typeof(NecromancerSpellbook)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(NecromancerSpellbook)))){ + if (!(QuestPlayer.Backpack.FindItemByType(typeof(BookOfNinjitsu)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfNinjitsu)))) + { + if (!(QuestPlayer.Backpack.FindItemByType(typeof(BookOfChivalry)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfChivalry)))) + { + if ((QuestPlayer.Backpack.FindItemByType(typeof(BookOfBushido)) != null + || (QuestPlayer.FindItemOnLayer(Layer.FirstValid) != null && QuestPlayer.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfBushido)))) + { + BookOfBushido b = (BookOfBushido)QuestPlayer.Backpack.FindItemByType(typeof(BookOfBushido)); + if (b != null) { + if (!(b.HasSpell(402))) + { + Say("J'ai vu ce que je voulais voir. Je vais t'apprendre ce que je sais."); + QuestPlayer.Backpack.AddItem(new EvasionScroll()); + QuestPlayer.Backpack.AddItem(new LightningStrikeScroll()); + } + } + } + } + } + } + Say("T'as du cran c'est vrai. Bien joué moussaillon."); + QuestPlayer.Criminal = false; + this.Combatant = null; + this.QuestPlayer = null; + this.Warmode = false; + return false; + } + public override bool ClickTitle { get { return false; } } + + public BushidoMaster3(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/Afk.cs b/Scripts/Vivre/Commands/Afk.cs new file mode 100644 index 0000000..f658ece --- /dev/null +++ b/Scripts/Vivre/Commands/Afk.cs @@ -0,0 +1,136 @@ +using Server.Commands; +using Server.Accounting; +using Server.Network; +using System; +using System.Collections; +using Server; + +namespace Server.Commands +{ + /// + /// Summary description for AFK. + /// + public class AFK : Timer + { + // Scriptiz : Minutes before we kick the AFK players (0 = no kick) + private int kickTime = 5; + + private static Hashtable m_AFK = new Hashtable(); + private Mobile who; + private Point3D where; + private DateTime when; + public string what = ""; + + public static void Initialize() + { + CommandSystem.Register("afk", AccessLevel.Player, new CommandEventHandler(AFK_OnCommand)); + EventSink.Logout += new LogoutEventHandler(OnLogout); + EventSink.Speech += new SpeechEventHandler(OnSpeech); + EventSink.PlayerDeath += new PlayerDeathEventHandler(OnDeath); + } + public static void OnDeath(PlayerDeathEventArgs e) + { + if (m_AFK.Contains(e.Mobile.Serial.Value)) + { + AFK afk = (AFK)m_AFK[e.Mobile.Serial.Value]; + if (afk == null) + { + e.Mobile.SendMessage("L'objet AFK est manquant!"); + return; + } + e.Mobile.PlaySound(e.Mobile.Female ? 814 : 1088); + afk.wakeUp(); + } + } + public static void OnLogout(LogoutEventArgs e) + { + if (m_AFK.Contains(e.Mobile.Serial.Value)) + { + AFK afk = (AFK)m_AFK[e.Mobile.Serial.Value]; + if (afk == null) + { + e.Mobile.SendMessage("L'objet AFK est manquant!"); + return; + } + afk.wakeUp(); + } + } + public static void OnSpeech(SpeechEventArgs e) + { + if (m_AFK.Contains(e.Mobile.Serial.Value)) + { + AFK afk = (AFK)m_AFK[e.Mobile.Serial.Value]; + if (afk == null) + { + e.Mobile.SendMessage("L'objet AFK est manquant!"); + return; + } + afk.wakeUp(); + } + } + public static void AFK_OnCommand(CommandEventArgs e) + { + if (m_AFK.Contains(e.Mobile.Serial.Value)) + { + AFK afk = (AFK)m_AFK[e.Mobile.Serial.Value]; + if (afk == null) + { + e.Mobile.SendMessage("L'objet AFK est manquant!"); + return; + } + afk.wakeUp(); + } + else + { + m_AFK.Add(e.Mobile.Serial.Value, new AFK(e.Mobile, e.ArgString.Trim())); + e.Mobile.SendMessage("AFK activ�."); + e.Mobile.Emote("*est AFK*"); + } + } + public void wakeUp() + { + m_AFK.Remove(who.Serial.Value); + who.Emote("*n'est plus AFK*"); + who.SendMessage("AFK d�sactiv�."); + this.Stop(); + } + public AFK(Mobile afker, string message) + : base(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)) + { + if ((message == null) || (message == "")) message = "est AFK"; + what = message; + who = afker; + when = DateTime.Now; + where = who.Location; + this.Start(); + } + protected override void OnTick() + { + #region KickThemAll + // Scriptiz : Let's kick all theses junkies who are stealing our bandwidth ! + if ((this.kickTime != 0) && (DateTime.Now.Subtract(when).CompareTo(TimeSpan.FromMinutes(this.kickTime)) > 0)) + { + NetState kicked = who.NetState; + + who.SendMessage("Vous �tes absent depuis trop longtemps, le serveur vous d�connecte."); + + if (kicked != null) + { + this.wakeUp(); + kicked.Dispose(); + } + } + #endregion + + if (!(who.Location == where)) + { + this.wakeUp(); + return; + } + who.Say("zZz"); + //TimeSpan ts = DateTime.Now.Subtract(when); + //who.Emote("*{0} ({1}:{2}:{3})*",what,ts.Hours,ts.Minutes,ts.Seconds); + //who.PlaySound( who.Female ? 819 : 1093); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/BandCommands.cs b/Scripts/Vivre/Commands/BandCommands.cs new file mode 100644 index 0000000..d350944 --- /dev/null +++ b/Scripts/Vivre/Commands/BandCommands.cs @@ -0,0 +1,73 @@ +/*************************************************************************** + * BandCommands.cs + * ------------------- + * begin : August 10, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-08-10 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using Server.Mobiles; +using Server.Items; +using Server.Commands; + +namespace Server.Commands +{ + public class Band + { + public static void Initialize() + { + CommandSystem.Register("band", AccessLevel.Player, new CommandEventHandler(Band_OnCommand)); + } + + [Usage("band")] + [Description("Utilise un bandage pour peux que vous en possédiez.")] + public static void Band_OnCommand(CommandEventArgs e) + { + Bandage m_Bandage = (Bandage)e.Mobile.Backpack.FindItemByType(typeof(Bandage)); + + if (m_Bandage == null) + { + e.Mobile.SendMessage("Vous ne possédez pas de bandages."); + return; + } + + m_Bandage.OnDoubleClick(e.Mobile); + } + } + + public class BandSelf + { + public static void Initialize() + { + CommandSystem.Register("bandself", AccessLevel.Player, new CommandEventHandler(BandSelf_OnCommand)); + CommandSystem.Register("bs", AccessLevel.Player, new CommandEventHandler(BandSelf_OnCommand)); + } + + public static void BandSelf_OnCommand(CommandEventArgs e) + { + Mobile pm = e.Mobile; + Item band = pm.Backpack.FindItemByType(typeof(Bandage)); + + if (band != null) + { + Bandage.BandSelfCommandCall(pm, band); + if (band.Amount <= 5) + pm.SendMessage("Attention il ne vous reste que {0} bandages !", band.Amount); + } + else + { + pm.SendMessage("Vous n'avez plus de bandages !"); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/BurnCorpse.cs b/Scripts/Vivre/Commands/BurnCorpse.cs new file mode 100644 index 0000000..cc59e6e --- /dev/null +++ b/Scripts/Vivre/Commands/BurnCorpse.cs @@ -0,0 +1,71 @@ +/*************************************************************************** + * BurnCorpse.cs + * ------------------- + * begin : September 15, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-09-15 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using Server.Mobiles; +using Server.Items; +using Server.Commands; +using Server.Targeting; + +namespace Server.Commands +{ + public class BurnCorpse + { + public static void Initialize() + { + CommandSystem.Register("bruler", AccessLevel.Player, new CommandEventHandler(Burn_OnCommand)); + } + + [Usage("bruler")] + [Description("Permet de cibler un corps afin de brûler celui-ci.")] + public static void Burn_OnCommand(CommandEventArgs e) + { + e.Mobile.BeginTarget(5, false, TargetFlags.None, new TargetCallback(Burn_OnTarget)); + } + + public static void Burn_OnTarget(Mobile from, object target) + { + if (from == null) return; + + if (!(target is Corpse)) + { + from.SendMessage("Vous devez cibler un corps."); + return; + } + + Corpse c = target as Corpse; + + if (c.Owner is PlayerMobile) + { + from.SendMessage("Vous ne pouvez pas mettre le feu à ce corps."); + return; + } + + if (!from.InRange(c.Location, 3)) + { + from.SendMessage("Le corps est trop loin pour que vous y mettiez le feu."); + return; + } + + Effects.PlaySound(c.Location, c.Map, 0x208); + Effects.SendLocationParticles(EffectItem.Create(c.Location, c.Map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052); + + Timer.DelayCall(TimeSpan.FromSeconds(1), c.Delete); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/ClearAddiction.cs b/Scripts/Vivre/Commands/ClearAddiction.cs new file mode 100644 index 0000000..36e98bb --- /dev/null +++ b/Scripts/Vivre/Commands/ClearAddiction.cs @@ -0,0 +1,43 @@ +using Server.Commands; +using Server.Accounting; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using Server.Mobiles; +using Server.Items; +using System; +using System.Collections; +using Server; + +namespace Server.Scripts.Commands +{ + public class ClearAddiction + { + public static void Initialize() + { + CommandSystem.Register("ClearAddiction", AccessLevel.GameMaster, new CommandEventHandler(ClearAddiction_OnCommand)); + } + + [Usage("ClearAddiction")] + [Description("Retire les addictions")] + private static void ClearAddiction_OnCommand(CommandEventArgs e) + { + e.Mobile.BeginTarget(7, false, TargetFlags.None, new TargetCallback(ClearAddiction_Callback)); + } + + public static void ClearAddiction_Callback(Mobile mJoueur, object objCible) + { + if (objCible is PlayerMobile) + { + PlayerMobile addict = objCible as PlayerMobile; + if (addict != null && !addict.Deleted) + { + addict.ClearAddiction(); + addict.SendMessage("Vous n'êtes plus dépendant de rien... sauf de Vivre!"); + } + } + else + mJoueur.SendMessage("Vous devez cibler un joueur"); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/Comparer.cs b/Scripts/Vivre/Commands/Comparer.cs new file mode 100644 index 0000000..7787e85 --- /dev/null +++ b/Scripts/Vivre/Commands/Comparer.cs @@ -0,0 +1,368 @@ +using Server.Commands; +using Server.Accounting; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using Server.Mobiles; +using Server.Items; +using System; +using System.Collections; +using Server; + +namespace Server.Scripts.Commands +{ + public class Comparer + { + public static void Initialize() + { + CommandSystem.Register("Comparer", AccessLevel.Player, new CommandEventHandler(RolePlay_OnCommand)); + } + + [Usage("Comparer")] + [Description("Permet d'effectuer un jet RolePlay")] + private static void RolePlay_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + if (from != null && !from.Deleted) + { + from.SendMessage("Sélectionnez une personne"); + from.Target = new RolePlayTarget(); + } + } + } + + public class RolePlayTarget : Target + { + public RolePlayTarget() + : base(15, false, TargetFlags.None) + { + } + protected override void OnTarget(Mobile from, object target) + { + if (from != null && !from.Deleted && target != null) + { + if (target is PlayerMobile) + { + Mobile targetted = target as Mobile; + if (targetted == from) + { + from.SendMessage("Cela sera un jet sur vous-même..."); + } + else + { + from.SendMessage("Cela sera un jet contre un joueur..."); + targetted.SendMessage("{0} prépare une jet RolePlay avec vous...", from.Name); + } + from.SendGump(new RolePlayGump(from, (Mobile)target, 0, false, 1, false)); + } + else if (target is Mobile) + { + from.SendMessage("Cela sera un jet contre un personnage non joueur..."); + from.SendGump(new RolePlayGump(from, (Mobile)target, 0, false, 1, false)); + } + } + } + } + + + public class RolePlayGump : Server.Gumps.Gump + { + + private Mobile m_Target; + private int sk; + private bool m_dif; + private bool m_playeronly; + private int m_carac; + + public RolePlayGump(Mobile from, Mobile target, int s, bool dif, int carac, bool playeronly) + : base(0, 0) + { + m_Target = target; + sk = s; + m_dif = dif; + m_carac = carac; + m_playeronly = playeronly; + if (sk < 0) sk = 0; + if (sk > 53) sk = 53; + this.Closable = true; + this.Disposable = true; + this.Dragable = true; + this.Resizable = false; + this.AddPage(0); + this.AddBackground(79, 71, 472, 235, 9200); + this.AddBackground(79, 43, 471, 27, 9200); + this.AddImage(88, 46, 10450); + this.AddImage(504, 48, 10450); + this.AddPage(1); + this.AddLabel(88, 96, 0, @"Choisissez la caractéristique"); + this.AddLabel(317, 98, 0, @"Choisissez également la compétence"); + this.AddLabel(88, 120, 0, @"correspondant le mieux à l'action:"); + this.AddLabel(317, 122, 0, @"correspondant le mieux à l'action:"); + this.AddRadio(88, 145, 210, 211, (m_carac == 1), (int)Buttons.FORCE); + this.AddRadio(88, 176, 210, 211, (m_carac == 2), (int)Buttons.INTELLIGENCE); + this.AddRadio(88, 205, 210, 211, (m_carac == 3), (int)Buttons.DEXTERITE); + this.AddLabel(112, 144, 0, @"FORCE"); + this.AddLabel(112, 174, 0, @"INTELLIGENCE"); + this.AddLabel(112, 205, 0, @"DEXTERITE"); + this.AddImage(342, 178, 2440); + if (sk > 0) + this.AddLabel(356, 156, 0, SkillInfo.Table[sk - 1].Name); + else + this.AddLabel(356, 156, 0, @""); + this.AddLabel(356, 180, 0, SkillInfo.Table[sk].Name); + if (sk < 53) + this.AddLabel(356, 204, 0, SkillInfo.Table[sk + 1].Name); + else + this.AddLabel(356, 204, 0, @""); + this.AddButton(324, 162, 250, 251, (int)Buttons.UP, GumpButtonType.Reply, 0); + this.AddButton(324, 195, 252, 253, (int)Buttons.DOWN, GumpButtonType.Reply, 0); + this.AddButton(320, 275, 247, 248, (int)Buttons.OK, GumpButtonType.Reply, 0); + this.AddButton(225, 273, 241, 242, (int)Buttons.CANCEL, GumpButtonType.Reply, 0); + this.AddImageTiled(300, 84, 4, 154, 2701); + this.AddAlphaRegion(344, 155, 163, 19); + this.AddAlphaRegion(345, 204, 162, 20); + this.AddLabel(197, 47, 0, @" Test RolePlay"); + if (from.AccessLevel > AccessLevel.Player) + { + this.AddLabel(376, 240, 0, @"Difficile"); + this.AddCheck(353, 242, 210, 211, m_dif, (int)Buttons.DIFFICILE); + this.AddLabel(176, 240, 0, @"Joueur seul"); + this.AddCheck(153, 242, 210, 211, m_playeronly, (int)Buttons.PLAYER); + } + } + + public enum Buttons + { + EXIT, + FORCE, + INTELLIGENCE, + DEXTERITE, + UP, + DOWN, + OK, + CANCEL, + DIFFICILE, + PLAYER + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + m_dif = false; + + for (int i = 0; i < info.Switches.Length; ++i) + { + if (i == 0) + m_carac = info.Switches[i]; + if (i == 1) + m_dif = true; + if (i == 2) + m_playeronly = true; + } + + switch (info.ButtonID) + { + case (int)Buttons.UP: + from.SendGump(new RolePlayGump(from, m_Target, sk - 1, m_dif, m_carac, m_playeronly)); + return; + case (int)Buttons.DOWN: + from.SendGump(new RolePlayGump(from, m_Target, sk + 1, m_dif, m_carac, m_playeronly)); + return; + case (int)Buttons.OK: + if (m_Target is PlayerMobile) + m_Target.SendGump(new RolePlayConfirmGump(from, m_Target, sk, m_dif, m_carac, m_playeronly)); + else + from.SendGump(new RolePlayConfirmGump(from, m_Target, sk, m_dif, m_carac, m_playeronly)); + from.SendMessage("Demande de test roleplay envoyée à {0}.", m_Target.Name); + break; + case (int)Buttons.CANCEL: + break; + default: + break; + } + } + } + + public class RolePlayConfirmGump : Server.Gumps.Gump + { + + private Mobile m_From; + private int sk; + private bool m_dif; + private bool m_playeronly; + private int m_carac; + private Mobile targ; + + public RolePlayConfirmGump(Mobile from, Mobile target, int s, bool dif, int carac, bool playeronly) + : base(0, 0) + { + m_From = from; + targ = target; + sk = s; + m_dif = dif; + m_carac = carac; + m_playeronly = playeronly; + if (sk < 0) sk = 0; + if (sk > 53) sk = 53; + this.Closable = true; + this.Disposable = false; + this.Dragable = true; + this.Resizable = false; + this.AddPage(0); + this.AddBackground(86, 72, 357, 113, 9200); + this.AddPage(1); + this.AddLabel(219, 78, 0, @"Test RolePlay"); + if (!(target is PlayerMobile)) + { + this.AddLabel(94, 100, 0, @"C'est un jet contre un Personnage Non Joueur."); + } + else if (from == target) + { + this.AddLabel(94, 100, 0, @"Vous faites un test Roleplay sur vous-même."); + } + else if (m_playeronly) + { + this.AddLabel(94, 100, 0, @"Un Test Roleplay est demandé par un Maitre de Jeu."); + } + else + { + this.AddLabel(94, 100, 0, String.Format("{0} veut faire un test Roleplay avec vous.", from.Name)); + this.AddLabel(97, 153, 0, @"Acceptez-vous ?"); + this.AddButton(281, 160, 12018, 12019, (int)Buttons.CANCEL, GumpButtonType.Reply, 0); + } + if (m_carac == 1) + this.AddLabel(96, 117, 0, @"Caractéristique utilisee: FORCE"); + else if (m_carac == 2) + this.AddLabel(96, 117, 0, @"Caractéristique utilisee: INTELLIGENCE"); + else + this.AddLabel(96, 117, 0, @"Caractéristique utilisee: DEXTERITE"); + this.AddLabel(96, 135, 0, String.Format("Compétence utilisée: {0}", SkillInfo.Table[sk].Name)); + this.AddButton(361, 161, 12000, 12001, (int)Buttons.OK, GumpButtonType.Reply, 0); + } + + public enum Buttons + { + CANCEL, + OK + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + switch (info.ButtonID) + { + case (int)Buttons.CANCEL: + m_From.SendMessage("{0} a refusé le test.", targ.Name); + break; + case (int)Buttons.OK: + double scoreA; + double scoreB; + int caracA; + int caracB; + if (m_carac == 1) + { + caracA = m_From.Str; + caracB = targ.Str; + } + else if (m_carac == 2) + { + caracA = m_From.Int; + caracB = targ.Int; + } + else + { + caracA = m_From.Dex; + caracB = targ.Dex; + } + if ((m_From == targ) || m_playeronly) + { + if (m_dif) + scoreA = Utility.RandomDouble() * 100.0 + 25.0; + else + scoreA = Utility.RandomDouble() * 100.0; + } + else + { + scoreA = Utility.RandomDouble() * + (targ.Skills[(SkillName)sk].Value + caracA / 10) / 2; + + } + scoreB = Utility.RandomDouble() * + (targ.Skills[(SkillName)sk].Value + caracA / 10) / 2; + if (scoreA > scoreB) + { + if (m_From == targ) + { + m_From.SendMessage("Test RolePlay réussi."); + IPooledEnumerable eable = + m_From.Map.GetMobilesInRange(m_From.Location, 30); + ArrayList list = new ArrayList(); + foreach (Mobile mob in eable) + { + if (mob.AccessLevel > AccessLevel.Player) + { + mob.SendMessage("{0} a réussi le test RolePlay.", targ.Name); + if (m_carac == 1) + mob.SendMessage("Caractéristique utilisee: FORCE"); + else if (m_carac == 2) + mob.SendMessage("Caractéristique utilisee: INTELLIGENCE"); + else + mob.SendMessage("Caractéristique utilisee: DEXTERITE"); + mob.SendMessage("Compétence utilisée: {0}", SkillInfo.Table[sk].Name); + } + } + eable.Free(); + } + else if (m_playeronly) + { + targ.SendMessage("Test RolePlay réussi."); + m_From.SendMessage("{0} a réussi le test RolePlay.", targ.Name); + } + else + { + targ.SendMessage("Test RolePlay contre {0} réussi.", m_From.Name); + m_From.SendMessage("Test RolePlay contre {0} raté.", targ.Name); + } + } + else + { + if (m_From == targ) + { + m_From.SendMessage("Test RolePlay raté."); + IPooledEnumerable eable = + m_From.Map.GetMobilesInRange(m_From.Location, 30); + ArrayList list = new ArrayList(); + foreach (Mobile mob in eable) + { + if (mob.AccessLevel > AccessLevel.Player) + { + mob.SendMessage("{0} a raté le test RolePlay.", targ.Name); + if (m_carac == 1) + mob.SendMessage("Caractéristique utilisee: FORCE"); + else if (m_carac == 2) + mob.SendMessage("Caractéristique utilisee: INTELLIGENCE"); + else + mob.SendMessage("Caractéristique utilisee: DEXTERITE"); + mob.SendMessage("Compétence utilisée: {0}", SkillInfo.Table[sk].Name); + } + } + eable.Free(); + } + else if (m_playeronly) + { + targ.SendMessage("Test RolePlay raté."); + m_From.SendMessage("{0} a raté le test RolePlay.", targ.Name); + } + else + { + targ.SendMessage("Test RolePlay contre {0} raté.", m_From.Name); + m_From.SendMessage("Test RolePlay contre {0} réussi.", targ.Name); + } + } + break; + default: + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/Emote_fra.cs b/Scripts/Vivre/Commands/Emote_fra.cs new file mode 100644 index 0000000..af0b3b7 --- /dev/null +++ b/Scripts/Vivre/Commands/Emote_fra.cs @@ -0,0 +1,748 @@ +//Emote v2 by CMonkey123 +/* +v2 changes: + -Shortened script + -Added emotes (thanks to zire): + bow, faint, punch, slap, stickouttongue, tapfoot + -Added emote gump (thanks to zire) +*/ +/* Emote v3 by GM Jubal from Ebonspire http://www.ebonspire.com + * I Left the above comments in here for credit to properly go back to those whom originally wrote this + * I simply made it so that the [e command would call the gump if used by itself or if the was + * misspelled, shortened the code down from 1300+ lines down to only 635 lines including these comments. + * Also fixed a couple of typos in the script. + * This has been tested on both RunUO beta .36 and RunUO RC0 1.0 +*/ +/* Emote v4 by Lysdexic + * Updated for RunUO 2.0 RC2 + * Puke command could be used for teleport bug... removed that ability. + * Typos again... +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Gumps; +using Server.Commands.Generic; + +namespace Server.Commands +{ + public enum EmotePage + { + P1, + P2, + P3, + P4, + } + public class Emote_fra + { + public static void Initialize() + { + CommandSystem.Register("emote", AccessLevel.Player, new CommandEventHandler(Emote_OnCommand)); + CommandSystem.Register("e", AccessLevel.Player, new CommandEventHandler(Emote_OnCommand)); + } + + [Usage("")] + [Description("Emote avec des sons, des mots et parfois avec une animation en une commande!")] + private static void Emote_OnCommand(CommandEventArgs e) + { + Mobile pm = e.Mobile; + string em = e.ArgString.Trim(); + int SoundInt; + switch (em) + { + case "dire_ah!": + case "ah!": + case "ah": + SoundInt = 1; + break; + case "dire_ah!ah!": + case "ah!ah!": + case "ahah": + SoundInt = 2; + break; + case "applaudir": //applaud + case "clapclap": + case "clap!clap!": + SoundInt = 3; + break; + case "se_moucher": //blownose + case "sprot": + case "sprot!": + SoundInt = 4; + break; + case "saluer": //bow + case "salut": + case "salut!": + SoundInt = 5; + break; + case "s_etrangler": //bscough + case "gloups": + case "gloups!": + SoundInt = 6; + break; + case "faire_un_rot": //burp + case "rot": + case "rot!": + SoundInt = 7; + break; + case "eclaircir_sa_voix": // eclaicir la voix + case "humhum": + case "humhum!": + SoundInt = 8; + break; + case "tousser": //cough + case "cofcof": + case "cof!cof!": + SoundInt = 9; + break; + case "pleurer": //cry : pleurer + case "bouhou": + case "bouhou!": + SoundInt = 10; + break; + case "tomber": // faint feindre mais cest mieux tomber + case "boum": + case "boum!": + SoundInt = 11; + break; + case "peter": //fart + case "prout": + case "prout!": + SoundInt = 12; + break; + case "haleter": //gasp + case "gasp": + case "gasp!": + SoundInt = 13; + break; + case "pouffer_de_rire": //giggle + case "mouahaha": + case "mouahaha!": + SoundInt = 14; + break; + case "jouir": //groan + case "aaahm": + case "aaahm!": + SoundInt = 15; + break; + case "grogner": //growl + case "grrr": + case "grrr!": + SoundInt = 16; + break; + case "apostropher": //hey + case "eh": + case "eh!": + SoundInt = 17; + break; + case "avoir_le_hoquet": //hippuc + case "hic": + case "hic!": + SoundInt = 18; + break; + case "s_etonner": //huh + case "hein": + case "hein?": + SoundInt = 19; + break; + case "embrasser": //kiss + case "smak": + case "smak!": + SoundInt = 20; + break; + case "rire": //laugh : son a verifier + case "lol": + case "ha!ha!ha!": + SoundInt = 21; + break; + case "nier": //no + case "non": + SoundInt = 22; + break; + case "ho!": //oh + case "ho": + case "dire_ho!": + SoundInt = 23; + break; + case "houu!": //oooh + case "hou": + case "dire_hou!": + SoundInt = 24; + break; + case "s_escuser": + case "oups": + case "oups!": + SoundInt = 25; + break; + case "vomir": //puke + case "blurg!": + SoundInt = 26; + break; + case "cogner": //punch + case "paf": + case "paf!": + SoundInt = 27; + break; + case "hurler": //scream + case "aaah": + case "aaah!": + SoundInt = 28; + break; + case "faire_taire": //shush + case "chut": + case "chut!": + SoundInt = 29; + break; + case "soupirer": //sigh + case "pfff": + case "pfff!": + SoundInt = 30; + break; + case "gifler": //slap + case "baf": + case "baf!": + SoundInt = 31; + break; + case "eternuer": //sneeze + case "atchoum": + case "atchoum!": + SoundInt = 32; + break; + case "renifler": + case "snif": //sniff + case "snif!": + SoundInt = 33; + break; + case "ronfler": //snore + case "zzz": + case "zzz!": + SoundInt = 34; + break; + case "cracher": //spit + case "steuh!": + SoundInt = 35; + break; + case "tirer_la_langue": //stickouttongue + case "meuh!": + case "meuh": + SoundInt = 36; + break; + case "s_impatienter": //tapfoot + case "taptap": + case "tap!tap!": + SoundInt = 37; + break; + case "siffler": //whistle + case "fouit!": + SoundInt = 38; + break; + case "feliciler": //woohoo + case "youhou": + case "youhou!": + SoundInt = 39; + break; + case "bailler": //yawn + case "houam": + case "houam!": + SoundInt = 40; + break; + case "ouais!": //yea + case "ouais": + case "dire_ouais": + SoundInt = 41; + break; + case "cri_de_guerre": // yells + case "yaaah!": + SoundInt = 42; + break; + default: + SoundInt = 0; + e.Mobile.SendGump(new EmoteGump(e.Mobile, EmotePage.P1)); + break; + } + if (SoundInt > 0) + new ESound(pm, SoundInt); + } + } + public class EmoteGump : Gump + { + private Mobile m_From; + private EmotePage m_Page; + private const int Blanco = 0xFFFFFF; + private const int Azul = 0x8080FF; + public void AddPageButton(int x, int y, int buttonID, string text, EmotePage page, params EmotePage[] subpage) + { + bool seleccionado = (m_Page == page); + for (int i = 0; !seleccionado && i < subpage.Length; ++i) + seleccionado = (m_Page == subpage[i]); + AddButton(x, y - 1, seleccionado ? 4006 : 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 200, 20, Color(text, seleccionado ? Azul : Blanco), false, false); + } + public void AddButtonLabeled(int x, int y, int buttonID, string text) + { + AddButton(x, y - 1, 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, Color(text, Blanco), false, false); + } + public int GetButtonID(int type, int index) + { + return 1 + (index * 15) + type; + } + public string Color(string text, int color) + { + return String.Format("{1}", color, text); + } + public EmoteGump(Mobile from, EmotePage page) + : base(600, 50) + { + from.CloseGump(typeof(EmoteGump)); + m_From = from; + m_Page = page; + Closable = true; + Dragable = true; + AddPage(0); + //AddBackground( 0, 65, 130, 360, 5054); + //AddAlphaRegion( 10, 70, 110, 350 ); + //AddImageTiled(10, 70, 110, 20, 9354); + AddBackground(0, 65, 240, 360, 5054); + AddAlphaRegion(10, 70, 220, 350); + AddImageTiled(10, 70, 220, 20, 9354); + AddLabel(13, 70, 200, "Liste des Emotes"); + AddImage(210, 0, 10410); + AddImage(210, 305, 10412); + AddImage(210, 150, 10411); + switch (page) + { + case EmotePage.P1: + { + AddButtonLabeled(10, 90, GetButtonID(1, 1), "dire_ha! (ha!)"); + AddButtonLabeled(10, 115, GetButtonID(1, 2), "dire_ha!ha! (ha!ha!)"); + AddButtonLabeled(10, 140, GetButtonID(1, 3), "applaudir (clap!clap!)"); + AddButtonLabeled(10, 165, GetButtonID(1, 4), "se_moucher (sprot!)"); + AddButtonLabeled(10, 190, GetButtonID(1, 5), "saluer (salut!)"); + AddButtonLabeled(10, 215, GetButtonID(1, 6), "s_etrangler (gloups!)"); + AddButtonLabeled(10, 240, GetButtonID(1, 7), "faire_un_rot (rot!)"); + AddButtonLabeled(10, 265, GetButtonID(1, 8), "eclaicir_sa_voix (humhum!)"); + AddButtonLabeled(10, 290, GetButtonID(1, 9), "tousser (cof!cof!)"); + AddButtonLabeled(10, 315, GetButtonID(1, 10), "pleurer (bouhou!)"); //cry + AddButtonLabeled(10, 340, GetButtonID(1, 11), "tomber (boum!)"); + AddButtonLabeled(10, 365, GetButtonID(1, 12), "peter (prout!)"); + AddButton(70, 380, 4502, 0504, GetButtonID(0, 2), GumpButtonType.Reply, 0); + break; + } + case EmotePage.P2: + { + AddButtonLabeled(10, 90, GetButtonID(1, 13), "haleter (gasp!)"); + AddButtonLabeled(10, 115, GetButtonID(1, 14), "poffer_de_rire (mouahaha!)"); + AddButtonLabeled(10, 140, GetButtonID(1, 15), "jouir (aaahm!)"); + AddButtonLabeled(10, 165, GetButtonID(1, 16), "grogner (grrr!)"); + AddButtonLabeled(10, 190, GetButtonID(1, 17), "apostreopher (he!)"); + AddButtonLabeled(10, 215, GetButtonID(1, 18), "avoir_le_hoquet (hic!)"); + AddButtonLabeled(10, 240, GetButtonID(1, 19), "s_etonner (hein?)"); + AddButtonLabeled(10, 265, GetButtonID(1, 20), "embrasser (smak!)"); + AddButtonLabeled(10, 290, GetButtonID(1, 21), "rire (ha!ha!ha!)"); //Laughs + AddButtonLabeled(10, 315, GetButtonID(1, 22), "nier (non!)"); + AddButtonLabeled(10, 340, GetButtonID(1, 23), "dire_oh! (oh!)"); + AddButtonLabeled(10, 365, GetButtonID(1, 24), "dire_ouh! (Ouh!)"); + AddButton(10, 380, 4506, 4508, GetButtonID(0, 1), GumpButtonType.Reply, 0); + AddButton(70, 380, 4502, 0504, GetButtonID(0, 3), GumpButtonType.Reply, 0); + break; + } + case EmotePage.P3: + { + AddButtonLabeled(10, 90, GetButtonID(1, 25), "s_excuser (oups!)"); + AddButtonLabeled(10, 115, GetButtonID(1, 26), "vomir (blurp!)"); + AddButtonLabeled(10, 140, GetButtonID(1, 27), "cogner (paf!)"); + AddButtonLabeled(10, 165, GetButtonID(1, 28), "hurler (haaa!)"); + AddButtonLabeled(10, 190, GetButtonID(1, 29), "faire_taire (chut!)"); + AddButtonLabeled(10, 215, GetButtonID(1, 30), "soupirer (pfff!)"); + AddButtonLabeled(10, 240, GetButtonID(1, 31), "gifler (baf!)"); + AddButtonLabeled(10, 265, GetButtonID(1, 32), "eternuer (atchoum!)"); + AddButtonLabeled(10, 290, GetButtonID(1, 33), "reniffler (snif!)"); + AddButtonLabeled(10, 315, GetButtonID(1, 34), "ronfler (zzz!)"); + AddButtonLabeled(10, 340, GetButtonID(1, 35), "cracher (steuh!)"); //spit + AddButtonLabeled(10, 365, GetButtonID(1, 36), "tirer_la_langue (meuh!)"); + AddButton(10, 380, 4506, 4508, GetButtonID(0, 2), GumpButtonType.Reply, 0); + AddButton(70, 380, 4502, 0504, GetButtonID(0, 4), GumpButtonType.Reply, 0); + break; + } + case EmotePage.P4: + { + AddButtonLabeled(10, 90, GetButtonID(1, 37), "s_impatienter (tap!tap!)"); + AddButtonLabeled(10, 115, GetButtonID(1, 38), "siffler (fouit!)"); + AddButtonLabeled(10, 140, GetButtonID(1, 39), "feliciter (youhou!)"); + AddButtonLabeled(10, 165, GetButtonID(1, 40), "bailler (houam!)"); + AddButtonLabeled(10, 190, GetButtonID(1, 41), "dire_ouais (ouais!)"); + AddButtonLabeled(10, 215, GetButtonID(1, 42), "cri_de_guerre (yaaah!)"); + AddButton(10, 380, 4506, 4508, GetButtonID(0, 3), GumpButtonType.Reply, 0); + break; + } + } + } + public override void OnResponse(Server.Network.NetState sender, RelayInfo info) + { + int val = info.ButtonID - 1; + if (val < 0) + return; + + Mobile from = m_From; + int type = val % 15; + int index = val / 15; + + switch (type) + { + case 0: + { + EmotePage page; + switch (index) + { + case 1: page = EmotePage.P1; break; + case 2: page = EmotePage.P2; break; + case 3: page = EmotePage.P3; break; + case 4: page = EmotePage.P4; break; + default: return; + } + + from.SendGump(new EmoteGump(from, page)); + break; + } + case 1: + { + if (index > 0 && index < 13) + { + from.SendGump(new EmoteGump(from, EmotePage.P1)); + } + else if (index > 12 && index < 25) + { + from.SendGump(new EmoteGump(from, EmotePage.P2)); + } + else if (index > 24 && index < 37) + { + from.SendGump(new EmoteGump(from, EmotePage.P3)); + } + else if (index > 36 && index < 43) + { + from.SendGump(new EmoteGump(from, EmotePage.P4)); + } + new ESound(from, index); + break; + } + } + } + } + public class ItemRemovalTimer : Timer + { + private Item i_item; + public ItemRemovalTimer(Item item) + : base(TimeSpan.FromSeconds(1.0)) + { + Priority = TimerPriority.OneSecond; + i_item = item; + } + + protected override void OnTick() + { + if ((i_item != null) && (!i_item.Deleted)) + { + i_item.Delete(); + Stop(); + } + } + } + + public class Puke : Item + { + private Timer m_Timer; + + [Constructable] + public Puke() + : base(Utility.RandomList(0xf3b, 0xf3c)) + { + Name = "Du Vomis"; // a pile of puke + Hue = 0x557; + Movable = false; + + m_Timer = new ItemRemovalTimer(this); + m_Timer.Start(); + + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Timer != null) + m_Timer.Stop(); + } + + public override void OnSingleClick(Mobile from) + { + this.LabelTo(from, this.Name); + } + + public Puke(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + this.Delete(); // none when the world starts + } + } + + public class ESound + { + public ESound(Mobile pm, int SoundMade) + { + switch (SoundMade) + { + case 1: + pm.PlaySound(pm.Female ? 778 : 1049); + pm.Say("*ha!*"); + break; + case 2: + pm.PlaySound(pm.Female ? 779 : 1050); + pm.Say("*ha! ha!*"); + break; + case 3: + pm.PlaySound(pm.Female ? 780 : 1051); + pm.Say("*applaudis*"); + break; + case 4: + pm.PlaySound(pm.Female ? 781 : 1052); + pm.Say("*se mouche*"); + if (!pm.Mounted) + pm.Animate(34, 5, 1, true, false, 0); + break; + case 5: + pm.Say("*salut*"); + if (!pm.Mounted) + pm.Animate(32, 5, 1, true, false, 0); + break; + case 6: + pm.PlaySound(pm.Female ? 786 : 1057); + pm.Say("*s'etrangle*"); + break; + case 7: + pm.PlaySound(pm.Female ? 782 : 1053); + pm.Say("*rot!*"); + if (!pm.Mounted) + pm.Animate(33, 5, 1, true, false, 0); + break; + case 8: + pm.PlaySound(pm.Female ? 784 : 1055); + pm.Say("*humhum!*"); + if (!pm.Mounted) + pm.Animate(33, 5, 1, true, false, 0); + break; + case 9: + pm.PlaySound(pm.Female ? 785 : 1056); + pm.Say("*tousse*"); + if (!pm.Mounted) + pm.Animate(33, 5, 1, true, false, 0); + break; + case 10: + pm.PlaySound(pm.Female ? 787 : 1058); + pm.Say("*pleure*"); //cries ?? + break; + case 11: + pm.PlaySound(pm.Female ? 791 : 1063); + pm.Say("*tombe*"); + if (!pm.Mounted) + pm.Animate(22, 5, 1, true, false, 0); + break; + case 12: + pm.PlaySound(pm.Female ? 792 : 1064); + pm.Say("*prout!*"); + break; + case 13: + pm.PlaySound(pm.Female ? 793 : 1065); + pm.Say("*gasp!*"); + break; + case 14: + pm.PlaySound(pm.Female ? 794 : 1066); + pm.Say("*mouahaha!*"); + break; + case 15: + pm.PlaySound(pm.Female ? 795 : 1067); + pm.Say("*jouis...*"); + break; + case 16: + pm.PlaySound(pm.Female ? 796 : 1068); + pm.Say("*grrr!*"); + break; + case 17: + pm.PlaySound(pm.Female ? 797 : 1069); + pm.Say("*h�!*"); + break; + case 18: + pm.PlaySound(pm.Female ? 798 : 1070); + pm.Say("*hic!*"); + break; + case 19: + pm.PlaySound(pm.Female ? 799 : 1071); + pm.Say("*hein?*"); + break; + case 20: + pm.PlaySound(pm.Female ? 800 : 1072); + pm.Say("*embrasse*"); + break; + case 21: + pm.PlaySound(pm.Female ? 801 : 1073); + pm.Say("*rire*"); + break; + case 22: + pm.PlaySound(pm.Female ? 802 : 1074); + pm.Say("*non!*"); + break; + case 23: + pm.PlaySound(pm.Female ? 803 : 1075); + pm.Say("*oh!*"); + break; + case 24: + pm.PlaySound(pm.Female ? 811 : 1085); + pm.Say("*hou!*"); + break; + case 25: + pm.PlaySound(pm.Female ? 812 : 1086); + pm.Say("*oups!*"); + break; + case 26: + pm.PlaySound(pm.Female ? 813 : 1087); + pm.Say("*vomis*"); + if (!pm.Mounted) + pm.Animate(32, 5, 1, true, false, 0); + Point3D p = new Point3D(pm.Location); + switch (pm.Direction) + { + case Direction.North: + p.Y--; break; + case Direction.South: + p.Y++; break; + case Direction.East: + p.X++; break; + case Direction.West: + p.X--; break; + case Direction.Right: + p.X++; p.Y--; break; + case Direction.Down: + p.X++; p.Y++; break; + case Direction.Left: + p.X--; p.Y++; break; + case Direction.Up: + p.X--; p.Y--; break; + default: + break; + } + p.Z = pm.Map.GetAverageZ(p.X, p.Y); + + bool canFit = Server.Spells.SpellHelper.AdjustField(ref p, pm.Map, 12, false); + + if (canFit) + { + Puke puke = new Puke(); + puke.Map = pm.Map; + puke.Location = p; + } + /*else + pm.SendMessage( "your puke won't fit!" ); /* Debug testing */ + break; + case 27: + pm.PlaySound(315); + pm.Say("*frappe*"); + if (!pm.Mounted) + pm.Animate(31, 5, 1, true, false, 0); + break; + case 28: + pm.PlaySound(pm.Female ? 814 : 1088); + pm.Say("*ahhhh!*"); + break; + case 29: + pm.PlaySound(pm.Female ? 815 : 1089); + pm.Say("*chute!*"); + break; + case 30: + pm.PlaySound(pm.Female ? 816 : 1090); + pm.Say("*pfff!*"); + break; + case 31: + pm.PlaySound(948); + pm.Say("*giffle*"); + if (!pm.Mounted) + pm.Animate(11, 5, 1, true, false, 0); + break; + case 32: + pm.PlaySound(pm.Female ? 817 : 1091); + pm.Say("*atchoum!*"); + if (!pm.Mounted) + pm.Animate(32, 5, 1, true, false, 0); + break; + case 33: + pm.PlaySound(pm.Female ? 818 : 1092); + pm.Say("*snif!*"); + if (!pm.Mounted) + pm.Animate(34, 5, 1, true, false, 0); + break; + case 34: + pm.PlaySound(pm.Female ? 819 : 1093); + pm.Say("*ronfle*"); + break; + case 35: + pm.PlaySound(pm.Female ? 820 : 1094); + pm.Say("*crache*"); + if (!pm.Mounted) + pm.Animate(6, 5, 1, true, false, 0); + break; + case 36: + pm.PlaySound(792); + pm.Say("*tire la langue*"); + break; + case 37: + pm.PlaySound(874); + pm.Say("*tape des pieds*"); + if (!pm.Mounted) + pm.Animate(38, 5, 1, true, false, 0); + break; + case 38: + pm.PlaySound(pm.Female ? 821 : 1095); + pm.Say("*siffle*"); + if (!pm.Mounted) + pm.Animate(5, 5, 1, true, false, 0); + break; + case 39: + pm.PlaySound(pm.Female ? 783 : 1054); + pm.Say("*felicite*"); + break; + case 40: + pm.PlaySound(pm.Female ? 822 : 1096); + pm.Say("*baille*"); + if (!pm.Mounted) + pm.Animate(17, 5, 1, true, false, 0); + break; + case 41: + pm.PlaySound(pm.Female ? 823 : 1097); + pm.Say("*ouais!*"); + break; + case 42: + pm.PlaySound(pm.Female ? 824 : 1098); + pm.Say("*crie*"); + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/GM/BindMe.cs b/Scripts/Vivre/Commands/GM/BindMe.cs new file mode 100644 index 0000000..9683db4 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/BindMe.cs @@ -0,0 +1,92 @@ +using System; +using Server; +using System.Collections.Generic; +using Server.Targeting; + +namespace Server.Commands +{ + public class BindMe + { + private static Dictionary binders = new Dictionary(); + + public static void Initialize() + { + EventSink.Speech += new SpeechEventHandler(EventSink_Speech); + EventSink.Logout += new LogoutEventHandler(EventSink_Logout); + EventSink.Login += new LoginEventHandler(EventSink_Login); + CommandSystem.Register("BindMe", AccessLevel.GameMaster, new CommandEventHandler(BindMe_OnCommand)); + } + + private static void BindMe_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new InternalTarget(); + } + + private static void EventSink_Login(LoginEventArgs args) + { + if (binders.ContainsKey(args.Mobile)) + binders.Remove(args.Mobile); + } + + private static void EventSink_Logout(LogoutEventArgs args) + { + if (binders.ContainsKey(args.Mobile)) + binders.Remove(args.Mobile); + } + + private static void EventSink_Speech(SpeechEventArgs args) + { + if (args.Mobile == null) return; + + Mobile speaker = args.Mobile; + + if (!binders.ContainsKey(speaker)) + return; + + Mobile b; + if (binders.TryGetValue(speaker, out b) && b != null && !b.Deleted) + b.Say(args.Speech); + else + { + args.Mobile.SendMessage("Le mobile lié n'existe plus"); + binders.Remove(args.Mobile); + } + } + + private class InternalTarget : Target + { + public InternalTarget() + : base(25, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targ) + { + if (targ is Mobile) + { + Mobile m = (Mobile)targ; + if (m == null) return; + + if (binders.ContainsKey(from)) + { + Mobile b; + + if(binders.TryGetValue(from, out b) && b != null) + from.SendMessage(String.Format("Vous vous déliez de {0}", b.Name)); + + binders.Remove(from); + } + + if (from == m) return; + + binders.Add(from, m); + from.SendMessage("Vous êtes maintenant lié à {0}", m.Name); + } + else + { + from.SendMessage("Veuillez cibler un Mobile."); + } + } + } + } +} diff --git a/Scripts/Vivre/Commands/GM/Core.cs b/Scripts/Vivre/Commands/GM/Core.cs new file mode 100644 index 0000000..f2dbc74 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/Core.cs @@ -0,0 +1,20 @@ +using System; +using Server; + +namespace Server.Commands +{ + public class CoreCmd + { + public static void Initialize() + { + CommandSystem.Register("Core", AccessLevel.GameMaster, new CommandEventHandler(Core_OnCommand)); + } + + private static void Core_OnCommand(CommandEventArgs e) + { + e.Mobile.SendMessage("Core.AOS = " + Core.AOS); + e.Mobile.SendMessage("Core.ML = " + Core.ML); + e.Mobile.SendMessage("Core.SE = " + Core.SE); + } + } +} diff --git a/Scripts/Vivre/Commands/GM/DelayRestart.cs b/Scripts/Vivre/Commands/GM/DelayRestart.cs new file mode 100644 index 0000000..6dd5b5a --- /dev/null +++ b/Scripts/Vivre/Commands/GM/DelayRestart.cs @@ -0,0 +1,132 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Commands +{ + public class DelayRestart + { + private static Timer m_Timer = null; + + public static void Initialize() + { + CommandSystem.Register("dRestart", AccessLevel.Administrator, new CommandEventHandler(Core_OnCommand)); + } + + [Usage("DRestart ")] + [Description("Redémarre le serveur dans secondes")] + public static void Core_OnCommand(CommandEventArgs e) + { + if (e.Arguments.Length == 0 || e.Arguments.Length > 1) + { + e.Mobile.SendMessage("Usage : DRestart "); + return; + } + + if (e.Arguments[0].ToLower() == "stop") + { + m_Timer.Stop(); + World.Broadcast(0x35, false, "Restart annulé."); + m_Timer = null; + Logging.RestartLog(String.Format("{0} a annulé le restart planifié", CommandLogging.Format(e.Mobile))); + return; + } + + if (m_Timer != null) + { + e.Mobile.SendMessage("Un restart est déjà programmé."); + return; + } + + int seconds = 0; + try + { + seconds = Int32.Parse(e.Arguments[0]); + } + catch + { + e.Mobile.SendMessage(" must be an integer !"); + return; + } + + Logging.RestartLog(String.Format("{0} a lancé restart planifié dans {1} secondes", CommandLogging.Format(e.Mobile), seconds)); + + m_Timer = new InternalTimer(seconds); + m_Timer.Start(); + } + + private class InternalTimer : Timer + { + DateTime m_RestartTime; + bool forceBroadcast; + + public InternalTimer(int seconds) + : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)) + { + m_RestartTime = DateTime.Now + TimeSpan.FromSeconds(seconds); + forceBroadcast = true; + } + + protected override void OnTick() + { + if (DateTime.Now >= m_RestartTime) + { + World.Broadcast(0x35, false, "Redémarrage du serveur..."); + Logging.RestartLog("Redémarrage planifié"); + Stop(); + m_Timer = null; + AutoSave.Save(); + Core.Kill(true); + return; + } + + int seconds = (int)(m_RestartTime - DateTime.Now).TotalSeconds; + + string time = ""; + bool broadcast = false; + + if (seconds >= (60 * 60)) + { + int hours = seconds / (60 * 60); + int minutes = seconds / 60; + time = hours + " heure" + (hours > 1 ? "s" : ""); + time += " et " + (minutes % 60) + " minute" + ((minutes % 60) > 1 ? "s" : ""); + Priority = TimerPriority.OneMinute; + + if (hours <= 2 && minutes % 30 == 0) broadcast = true; + if (minutes % 60 == 0) broadcast = true; + } + else if (seconds >= 60) + { + int minutes = seconds / 60; + time = minutes + " minute" + (minutes > 1 ? "s" : ""); + Priority = TimerPriority.OneMinute; + + if (minutes == 1) Priority = TimerPriority.FiveSeconds; + + if (minutes % 10 == 0) broadcast = true; + if (minutes < 10 && minutes >= 5 && minutes % 2 == 0) broadcast = true; + if (minutes < 5) broadcast = true; + + if (Priority == TimerPriority.FiveSeconds && seconds > 61) broadcast = false; + } + else + { + time = seconds + " seconde" + (seconds > 1 ? "s" : ""); + Priority = TimerPriority.OneSecond; + + if (seconds % 10 == 0) broadcast = true; + if (seconds <= 10 && seconds % 2 == 0) broadcast = true; + if (seconds <= 5) broadcast = true; + } + + if(broadcast && !forceBroadcast) World.Broadcast(0x35, false, "Le serveur va redémarrer dans " + time); + else if (forceBroadcast) + { + World.Broadcast(0x35, false, "Un redémarrage du serveur a été planifié dans " + time); + forceBroadcast = false; + } + } + } + } +} diff --git a/Scripts/Vivre/Commands/GM/DeleteNoRecallRunes.cs b/Scripts/Vivre/Commands/GM/DeleteNoRecallRunes.cs new file mode 100644 index 0000000..f8a9ae4 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/DeleteNoRecallRunes.cs @@ -0,0 +1,69 @@ +using System; +using Server; +using Server.Items; +using Server.Regions; +using System.Collections.Generic; +using System.Collections; + +namespace Server.Commands +{ + public class DeleteBuccaneerRunes + { + public static void Initialize() + { + CommandSystem.Register("DeleteNoRecallRunes", AccessLevel.Administrator, new CommandEventHandler(DeleteBuccaneerRunes_OnCommand)); + } + + private static void DeleteBuccaneerRunes_OnCommand(CommandEventArgs e) + { + int count1 = 0, count2 = 0; + foreach (Item i in World.Items.Values) + { + // Si c'est une rune, on la rend vierge + if (i is RecallRune) + { + RecallRune rune = (RecallRune)i; + Console.Write("\nRune found : " + rune.Description); + + if (Region.Find(rune.Target, rune.Map) is NoRecallRegion) + { + Console.Write(" [cleared]"); + rune.Target = new Point3D(0, 0, 0); + rune.TargetMap = null; + rune.Marked = false; + rune.House = null; + rune.Description = null; + count1++; + } + } + // Si c'est une runebook on doit rentrer dans le livre chercher les entrées + else if (i is Runebook) + { + Runebook book = (Runebook)i; + + // On cherche les entrées vers une zone no recall + List entries = new List(); + foreach(RunebookEntry entry in book.Entries) + { + if(entry == null) continue; + Console.Write("\nEntry found : " + entry.Description); + if(Region.Find(entry.Location, entry.Map) is NoRecallRegion) + { + Console.Write(" [deleted]"); + entries.Add(entry); + } + } + + // On supprime les entrées vers les zones no recall + foreach (RunebookEntry entry in entries) + { + book.Entries.Remove(entry); + count2++; + } + } + } + Console.WriteLine(); + e.Mobile.SendMessage(String.Format("{0} runes effacées et {1} entrées de runebook retirées.", count1, count2)); + } + } +} diff --git a/Scripts/Vivre/Commands/GM/Find.cs b/Scripts/Vivre/Commands/GM/Find.cs new file mode 100644 index 0000000..4abdc50 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/Find.cs @@ -0,0 +1,196 @@ +using System; +using Server; +using System.Reflection; +using Server.Items; +using System.Collections; +using Server.Commands; +using System.Collections.Generic; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; + +namespace Server.Commands +{ + public class Find + { + public static void Initialize() + { + CommandSystem.Register( "Find", AccessLevel.Counselor, new CommandEventHandler( Find_OnCommand ) ); + } + + [Usage( "Find " )] + [Description( "Recherche d'item par le type ou par le serial" )] + public static void Find_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + string arg=""; + Type type=null; + List items = new List(); + List mobiles = new List(); + + if (e.Arguments.Length > 0) + { + arg = e.Arguments[0]; + + type = ScriptCompiler.FindTypeByName( arg ); + } + + if(type!=null) + { + if (type.IsSubclassOf(typeof(Item)) || type.Equals(typeof(Item))) + { + Dictionary.Enumerator its = World.Items.GetEnumerator(); + List alItems = new List(); + while (its.MoveNext()) alItems.Add(its.Current.Value); + its.Dispose(); + + for (int k = 0; k < alItems.Count; ++k) + { + Item it = alItems[k] as Item; + + if (it.GetType().Equals(type)) + { + items.Add(it); + } + } + } + else if (type.IsSubclassOf(typeof(Mobile)) || type.Equals(typeof(Mobile))) + { + Dictionary.Enumerator mobs = World.Mobiles.GetEnumerator(); + List alMobiles = new List(); + while (mobs.MoveNext()) alMobiles.Add(mobs.Current.Value); + mobs.Dispose(); + + for (int k = 0; k < alMobiles.Count; ++k) + { + Mobile mob = alMobiles[k] as Mobile; + + if (mob.GetType().Equals(type)) + { + mobiles.Add(mob); + } + } + } + + if(items.Count>0) + { + from.SendGump(new FindGump(from,items,0,arg,e)); + } + else if(mobiles.Count>0) + { + from.SendGump(new FindGump(from,mobiles,0,arg,e)); + } + + } + else from.SendMessage(arg+" n'est pas un type valide."); + + } + + private class FindGump:Gump + { + private List items= new List(); + private List mobiles = new List(); + private Mobile from; + private int index; + private string type; + private CommandEventArgs cmde; + + public FindGump(Mobile f, List its,int i,string arg,CommandEventArgs e): base( 0, 0 ) + { + items = its; + from = f; + index = i; + type = arg; + cmde = e; + Initialize(); + } + + public FindGump(Mobile f, List mobs,int i,string arg,CommandEventArgs e): base( 0, 0 ) + { + mobiles = mobs; + from = f; + index =i; + type = arg; + cmde = e; + Initialize(); + } + + private void Initialize() + { + Closable=true; + Disposable=true; + Dragable=true; + Resizable=false; + + Map m_Map = from.Map; + if(items.Count>0 )m_Map = items[index].Map; + if(mobiles.Count>0 )m_Map = mobiles[index].Map; + + Point3D m_Location; + m_Location = items.Count>0?items[index].Location:mobiles[index].Location; + + AddBackground(0, 0, 182, 109, 9200); + AddButton(8, 78, 4014, 4015, 1, GumpButtonType.Reply, 0); + AddButton(142, 78, 4005, 4006, 2, GumpButtonType.Reply, 0); + AddLabel(8, 40, 0, m_Location.ToString()); + AddLabel(8, 10, 0, type); + AddLabel(115, 40, 0, m_Map.Name); + AddLabel(115, 10, 0, (index+1).ToString()+"/"+(items.Count>0?items.Count.ToString():mobiles.Count.ToString())); + + if(m_Map!=Map.Internal)from.Map = m_Map; + from.Location = m_Location; + } + + public override void OnResponse(NetState state, RelayInfo info ) + { + int idx = info.ButtonID; + + if(idx==1) + { + if(index>0)index--; + else + { + index=items.Count>0?(items.Count-1):(mobiles.Count-1); + } + } + + if(idx==2) + { + index++; + if((items.Count>0 && index==items.Count)||(mobiles.Count>0 && index==mobiles.Count))index=0; + } + + if(idx==1 || idx==2) + { + if(items.Count>0) + { + for(int z=0;z0) + { + for(int z=index;z rocks = new List + { + 6001, 6002, 6003, 6004, + 6005, 6006, 6007, 6008, + 6009, 6010, 6011, 6012 + }; + + [Usage("GenerateCoral")] + [Description("Génére des récifs autour des îles afin d'empêcher la navigation en dehors de cette zone.")] + private static void GenerateCoral_OnCommand(CommandEventArgs e) + { + e.Mobile.SendMessage("Generating Corals..."); + + int count = 0; + for(int i = 0; i < limits.Length; i++) + { + Point2D actual = limits[i]; + Point2D next = (i == limits.Length - 1 ? limits[0] : limits[i + 1]); + + for (int x = actual.X, y = actual.Y; x != next.X || y != next.Y;) + { + if (x != next.X) + { + if (x < next.X) x++; + else x--; + } + if (y != next.Y) + { + if (y < next.Y) y++; + else y--; + } + + Static rock = new Static(rocks[Utility.Random(0, rocks.Count)]); + Item blocker = new Blocker(); + Item losBlocker = new LOSBlocker(); + + int z = map.GetAverageZ(x, y); // on récupère la hauteur du sol à cet endroit + rock.MoveToWorld(new Point3D(x, y, z), map); // le rocher pour la forme + blocker.MoveToWorld(new Point3D(x, y, z), map); // un blocker pour empêcher de passer même avec un sea horse par exemple + losBlocker.MoveToWorld(new Point3D(x, y, z), map); // pour empêcher tout sort de téléport de fonctionner + + count++; + } + } + e.Mobile.SendMessage(String.Format("{0} Corals have been generated !", count)); + } + + [Usage("WipeCoral")] + [Description("Supprime les récifs autour des îles afin de rétablir la navigation en dehors de cette zone.")] + private static void WipeCoral_OnCommand(CommandEventArgs e) + { + e.Mobile.SendMessage("Wiping Corals..."); + + for (int i = 0; i < limits.Length; i++) + { + Point2D actual2D = limits[i]; + Point2D next2D = (i == limits.Length - 1 ? limits[0] : limits[i + 1]); + + Point3D actual = new Point3D(actual2D, map.GetAverageZ(actual2D.X, actual2D.Y)); + Point3D next = new Point3D(next2D, map.GetAverageZ(next2D.X, next2D.Y)); + + Utility.FixPoints(ref actual, ref next); // if you miss this, it won't wipe... fucking bitch ! + + Wipe.DoWipe(e.Mobile, map, actual, next, Wipe.WipeType.Items); + } + + e.Mobile.SendMessage("Corals wiped !"); + } + } +} diff --git a/Scripts/Vivre/Commands/GM/KeysCommands.cs b/Scripts/Vivre/Commands/GM/KeysCommands.cs new file mode 100644 index 0000000..c6e87b1 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/KeysCommands.cs @@ -0,0 +1,183 @@ +/*************************************************************************** + * KeysCommands.cs + * ------------------- + * begin : August 21, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-08-21 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using Server.Mobiles; +using Server.Items; +using Server.Commands; +using Server.Targeting; + +namespace Server.Commands +{ + public class KeysCommands + { + public static void Initialize() + { + CommandSystem.Register("CreateKeys", AccessLevel.GameMaster, new CommandEventHandler(CreateKeys_OnCommand)); + CommandSystem.Register("BindDoor", AccessLevel.GameMaster, new CommandEventHandler(BindDoor_OnCommand)); + } + + [Usage("CreateKeys")] + [Description("Crée une clef pour la porte ciblée.")] + public static void CreateKeys_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + int quantity = 1; + + if (e.Arguments.Length == 1) + { + try + { + quantity = Int32.Parse(e.Arguments[0]); + } + catch + { + from.SendMessage("Vous devez entrer un nombre comme argument !"); + return; + } + } + + if (quantity > 100) + { + from.SendMessage("Seul un fou voudrait créer plus de 100 clefs..."); + quantity = 100; + } + + from.SendMessage("Ciblez la porte pour laquelle vous voulez créer "+quantity+" clef(s)"); + from.Target = new CreateKeysTarget(quantity); + } + + // Classe interne pour cibler la porte pour laquelle les clefs seront générées + private class CreateKeysTarget : Target + { + private int m_Quantity; + + public CreateKeysTarget(int quantity) + : base(10, false, TargetFlags.None) + { + m_Quantity = quantity; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BaseHouseDoor) + { + from.SendMessage("Ce n'est pas conseillé de faire ceci sur une porte de maison..."); + return; + } + + BaseDoor door = targeted as BaseDoor; + + if (door == null) + { + from.SendMessage("Vous devez cibler une porte et non un " + targeted.GetType().Name); + return; + } + + if (door.KeyValue != 0) + { + from.SendMessage("La porte possède déjà un KeyValue !"); + return; + } + + door.KeyValue = (uint)door.Serial.Value; + + Bag keysBag = new Bag(); + keysBag.Hue = Utility.RandomDyedHue(); + for (int i = 1; i <= m_Quantity; i++) + { + Key k = new Key(door.KeyValue); + keysBag.DropItem(k); + } + + if (keysBag.Items.Count > 0) + from.Backpack.AddItem(keysBag); + else + keysBag.Delete(); + } + } + + [Usage("BindDoor")] + [Description("Met le KeyValue de la première porte sur la deuxième")] + public static void BindDoor_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + from.SendMessage("Ciblez une clef déjà générée à laquelle vous souhaitez lier une nouvelle porte."); + from.BeginTarget(10, false, TargetFlags.None, BindDoor_KeyTarget); + } + + // Méthode pour cibler la clef qui servira a ouvrir une nouvelle porte + private static void BindDoor_KeyTarget(Mobile from, object targeted) + { + Key k = targeted as Key; + + if (k == null) + { + from.SendMessage("Veuillez cibler une clef."); + return; + } + + if (k.KeyValue == 0) + { + from.SendMessage("Cette clef n'a pas encore été liée à une porte donc n'a pas de KeyValue !"); + return; + } + + from.SendMessage("Maintenant ciblez la porte que vous souhaitez pouvoir ouvrir à l'aide de cette clef."); + from.Target = new BindDoorTarget(k); + } + + // Classe interne pour cibler la porte que la clef ouvrira (donc mettre le KeyValue de la clef sur la porte) + private class BindDoorTarget : Target + { + private Key m_Key; + + public BindDoorTarget(Key k) + : base(10, false, TargetFlags.None) + { + m_Key = k; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BaseHouseDoor) + { + from.SendMessage("Mieux vaut ne pas faire ceci sur une porte de maison..."); + return; + } + + BaseDoor door = targeted as BaseDoor; + + if (door == null) + { + from.SendMessage("Il fallait cibler une porte."); + return; + } + + if (door.KeyValue != 0) + { + from.SendMessage("Cette porte est déjà liée à une clef. Sa KeyValue n'est pas nulle."); + return; + } + + door.KeyValue = m_Key.KeyValue; + from.SendMessage("Cette porte sera désormais une porte de plus que cette clef ouvrira."); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/GM/MacroCheck/MacroCommand.cs b/Scripts/Vivre/Commands/GM/MacroCheck/MacroCommand.cs new file mode 100644 index 0000000..2dd2298 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/MacroCheck/MacroCommand.cs @@ -0,0 +1,59 @@ +/** + * MacroCheck's Command + * @author Scriptiz + * @date 20090913 + */ +using System; +using Server; +using Server.Targeting; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Commands +{ + public class MacroCommand + { + public static void Initialize() + { + CommandSystem.Register("Macro", AccessLevel.Counselor, new CommandEventHandler(Macro_OnCommand)); + } + + [Usage("Macro [target]")] + [Description("Envoie un avertissement au joueur pour déterminer s'il macrote ou non.")] + private static void Macro_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from != null) + { + from.SendMessage("Qui suspectez vous de macrotage ?"); + + from.Target = new InternalTarget(e.Arguments); + } + } + + private class InternalTarget : Target + { + string[] m_parameter; + + public InternalTarget(params string[] parameter) + : base(-1, true, TargetFlags.None) + { + m_parameter = parameter; + } + + protected override void OnTarget(Mobile from, object targeted) + { + PlayerMobile pm = null; + + if (targeted is PlayerMobile) + pm = (PlayerMobile)targeted; + + if (pm != null && pm.AccessLevel == AccessLevel.Player && !pm.HasGump(typeof(MacroGump))) + { + pm.SendGump(new MacroGump(from, pm)); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/GM/MacroCheck/MacroGump.cs b/Scripts/Vivre/Commands/GM/MacroCheck/MacroGump.cs new file mode 100644 index 0000000..64dad6a --- /dev/null +++ b/Scripts/Vivre/Commands/GM/MacroCheck/MacroGump.cs @@ -0,0 +1,155 @@ +/** + * MacroCheck's Gump + * @author Scriptiz + * @date 20090913 + */ +using System; +using Server; +using Server.Network; +using Server.Accounting; + +namespace Server.Gumps +{ + public class MacroGump : Gump + { + private Mobile jailor; + private Mobile badBoy; + DateTime issued = DateTime.Now; + Timer response; + int gButton = 2; + + public MacroGump(Mobile from, Mobile m) : base(70, 40) + { + jailor = from; + badBoy = m; + + if (jailor == null) + { + jailor = new Mobile(); + jailor.Name = "Le Gardien"; + } + + gButton = (new System.Random()).Next(6); + if (gButton < 1) gButton = 1; + if (gButton > 6) gButton = 6; + + //((Account)m.Account).Comments.Add(new AccountComment("-warning", jailor.Name + " a vérifié si " + badBoy.Name + " était entrain de macroter à : " + DateTime.Now)); + + Closable = false; + Dragable = true; + AddPage(0); + AddBackground(0, 0, 326, 320, 5054); + AddImageTiled(9, 65, 308, 240, 2624); + AddAlphaRegion(9, 65, 308, 240); + //AddLabel( 16, 20, 200, string.Format("{0} is checking to see if you are macroing unattended", jailor.Name)); + this.AddHtml(16, 10, 250, 50, string.Format("{0} vérifie si vous êtes entrain de macroter.", jailor.Name), false, false); + //let them show that they are there by selecting these buttons + AddButton(20, 72, 2472, 2473, 5, GumpButtonType.Reply, 0); + AddLabel(50, 75, 200, gButton == 5 ? "Je suis la !" : "Je confesse, je suis un vilain macroteur."); + AddButton(20, 112, 2472, 2473, 1, GumpButtonType.Reply, 0); + AddLabel(50, 115, 200, gButton == 1 ? "Je suis la !" : "Je confesse, je suis un vilain macroteur."); + AddButton(20, 152, 2472, 2473, 2, GumpButtonType.Reply, 0); + AddLabel(50, 155, 200, gButton == 2 ? "Je suis la !" : "Je confesse, je suis un vilain macroteur."); + AddButton(20, 192, 2472, 2473, 3, GumpButtonType.Reply, 0); + AddLabel(50, 195, 200, gButton == 3 ? "Je suis la !" : "Je confesse, je suis un vilain macroteur."); + AddButton(20, 232, 2472, 2473, 4, GumpButtonType.Reply, 0); + AddLabel(50, 235, 200, gButton == 4 ? "Je suis la !" : "Je confesse, je suis un vilain macroteur."); + AddButton(20, 272, 2472, 2473, 6, GumpButtonType.Reply, 0); + AddLabel(50, 275, 200, gButton == 6 ? "Je suis la !" : "Je confesse, je suis un vilain macroteur."); + + if (jailor != null && badBoy != null) + { + m.SendMessage("Vous êtes suspecté de macrotage, veuillez répondre s'il vous plait."); + response = new MacroTimer(this); + } + else + Closable = true; + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + if (response != null) + response.Stop(); + + if (gButton == info.ButtonID) + { + string mtemp = string.Format("{0} a répondu à la vérification en {1} secondes.", from.Name, ((TimeSpan)(DateTime.Now.Subtract(issued))).Seconds); + //((Account)badBoy.Account).Comments.Add(new AccountComment("-warning", mtemp)); + jailor.SendMessage(mtemp); + } + else + { + string mtemp = string.Format("{0} a été kické pour cause de macrotage.", from.Name); + ((Account)badBoy.Account).Comments.Add(new AccountComment("-warning", mtemp)); + caughtInTheAct(true); + } + from.CloseGump(typeof(MacroGump)); + } + + public void caughtInTheAct(bool confessed) + { + if (!confessed) + jailor.SendMessage("{0} a été kické pour {1} suite au délai de votre avertissement.", badBoy.Name, "Macrotage"); + else + jailor.SendMessage("{0} a été kické pour {1} en avouant ses crimes.", badBoy.Name, "Macrotage"); + + NetState kicked = badBoy.NetState; + + if (kicked != null) + { + badBoy.SendMessage("Vous êtes kické pour cause de Macrotage."); + kicked.Dispose(); + } + + if (response != null) + response.Stop(); + } + + protected class MacroTimer : Timer + { + public MacroGump m_Gump; + int counts = 60; + + public MacroTimer(MacroGump myGump) + : base(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)) + { + m_Gump = myGump; + this.Start(); + } + + protected override void OnTick() + { + counts -= this.Interval.Seconds; + switch (counts) + { + case 50: + case 40: + case 30: + case 20: + this.Interval = TimeSpan.FromSeconds(1); + goto case 10; + case 10: + case 9: + case 8: + case 7: + case 6: + case 5: + case 4: + case 3: + case 2: + case 1: + m_Gump.badBoy.SendMessage("Attention : fermeture dans {0} secondes.", counts); + break; + case 0: + m_Gump.caughtInTheAct(false); + m_Gump.badBoy.CloseGump(typeof(MacroGump)); + this.Stop(); + break; + default: + break; + } + } + } + } +} diff --git a/Scripts/Vivre/Commands/GM/NPChat.cs b/Scripts/Vivre/Commands/GM/NPChat.cs new file mode 100644 index 0000000..014ca22 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/NPChat.cs @@ -0,0 +1,257 @@ +/*************************************************************************** + * NPChat.cs + * ------------------- + * begin : May 14, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-08-03 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server; +using Server.Commands; +using Server.Mobiles; +using Server.Network; +using Server.Misc; +using Server.Targeting; +using Server.Items; +using Server.Gumps; + +namespace Server.Gumps +{ + public class NPChat : Gump + { + public static void Initialize() + { + CommandSystem.Register("npChat", AccessLevel.Counselor, new CommandEventHandler(NPChat_OnCommand)); + CommandSystem.Register("clearTmp", AccessLevel.GameMaster, new CommandEventHandler(ClearTmp_OnCommand)); + } + + [Usage("npChat")] + [Description("Ouvre une fenêtre qui permet de faire parler un NPC.")] + private static void NPChat_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new NPChatTarget(); + e.Mobile.SendMessage("Qui voulez-vous faire parler ?"); + } + + [Usage("clearTmp")] + [Description("Supprime toutes les TmpPoint.")] + private static void ClearTmp_OnCommand(CommandEventArgs e) + { + e.Mobile.SendMessage("Supression des TmpPoint en cours..."); + List tmpPoints = new List(); + foreach (Item i in World.Items.Values) + { + if (i != null && i is WayPoint && i.Name == "TmpPoint") + { + tmpPoints.Add(i); + } + } + + int totalTmpPoint = tmpPoints.Count; + + for (int i = 0; i < tmpPoints.Count; i++) + { + tmpPoints[i].Delete(); + } + + e.Mobile.SendMessage("Il y avait " + totalTmpPoint + " TmpPoint qui ont été supprimés."); + } + + public static void DeplacerMobile(Mobile m, Point3D p) + { + if (m == null) return; + BaseCreature b = null; + if(m is BaseCreature) b = (BaseCreature)m; + if (b == null) return; + + if (b.AI == AIType.AI_None) b.AI = AIType.AI_Melee; + + if (b.CurrentWayPoint != null && b.CurrentWayPoint.Name == "TmpPoint") + b.CurrentWayPoint.Delete(); + + b.CurrentSpeed = 0.2; + + WayPoint point = new WayPoint(); + point.Name = "TmpPoint"; + point.MoveToWorld(p, b.Map); + point.NextPoint = point; + b.CurrentWayPoint = point; + } + + Mobile m_Owner; + Mobile m_Speaker; + int x, y; + + public NPChat(Mobile owner, Mobile speaker) + : this(owner, speaker, PropsConfig.GumpOffsetX, PropsConfig.GumpOffsetY) + { + } + + public NPChat(Mobile owner, Mobile speaker, int x, int y) + : base(x, y) + { + this.m_Owner = owner; + this.m_Speaker = speaker; + int hue = this.m_Speaker.SpeechHue; + + this.Closable = true; + this.Disposable = true; + this.Dragable = true; + this.Resizable = false; + + AddPage(0); + AddBackground(0, 0, 290, 90, 9400); + AddLabel(13, 35, hue, this.m_Speaker.Name); // @"[MobileName]" + AddImage(8, 8, 1143); + AddButton(215, 35, 247, 248, 1, GumpButtonType.Reply, 0); // Send chat + + if (m_Speaker is BaseCreature) + { + AddButton(220, 63, 1209, 1210, 2, GumpButtonType.Reply, 0); // Move button + AddLabel(237, 60, hue, "Move"); + } + + AddButton(15, 63, 1209, 1210, 3, GumpButtonType.Reply, 0); + AddLabel(32, 60, hue, "Goto"); + AddButton(120, 63, 1209, 1210, 4, GumpButtonType.Reply, 0); + AddLabel(137, 60, hue, "Props"); + + AddTextEntry(18, 10, 254, 20, hue, 0, @""); + + // On ajoute le mobile à la liste des mobiles écoutés + NPListener.AddListenedMobile(m_Owner, m_Speaker); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + if (m_Speaker == null || m_Speaker.Deleted) + { + from.SendMessage("Le Mobile que vous controlliez à disparu."); + return; + } + + switch (info.ButtonID) + { + case 0: + { + // Si le gump est fermé on retire le Mobile de la liste des mobiles écoutés + NPListener.RemoveListenedMobile(m_Owner, m_Speaker); + if (m_Speaker != null && m_Speaker is BaseCreature) + { + BaseCreature b = (BaseCreature)m_Speaker; + b.CurrentSpeed = b.PassiveSpeed; + + if (b.CurrentWayPoint != null && b.CurrentWayPoint.Name == "TmpPoint") + { + b.CurrentWayPoint.Delete(); + b.CurrentWayPoint = null; + b.AI = AIType.AI_Use_Default; + } + } + break; + } + case 1: + { + TextRelay entry0 = info.GetTextEntry(0); + string text0 = (entry0 == null ? "" : entry0.Text.Trim()); + if (m_Speaker != null && m_Speaker is Mobile && text0 != "") + { + this.m_Speaker.PublicOverheadMessage(MessageType.Regular, this.m_Speaker.SpeechHue, false, text0); + + if(this.m_Owner.GetDistanceToSqrt(this.m_Speaker) >= 10) + this.m_Owner.SendMessage(this.m_Speaker.SpeechHue, this.m_Speaker.Name + " : " + text0); + + from.SendGump(new NPChat(from, m_Speaker, this.X, this.Y)); + } + break; + } + case 2: + { + if (m_Speaker != null && m_Speaker is Mobile) + { + m_Owner.Target = new DeplacerTarget(m_Speaker); + from.SendGump(new NPChat(from, m_Speaker, this.X, this.Y)); + } + break; + } + case 3: + { + m_Owner.Hidden = true; + m_Owner.MoveToWorld(m_Speaker.Location, m_Speaker.Map); + from.SendGump(new NPChat(from, m_Speaker, this.X, this.Y)); + break; + } + case 4: + { + from.SendGump(new NPChat(from, m_Speaker, this.X, this.Y)); + m_Owner.SendGump(new PropertiesGump(m_Owner, m_Speaker)); + break; + } + } + } + + private class NPChatTarget : Target + { + public NPChatTarget() + : base(15, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object targ) + { + if (targ is Mobile) + { + Mobile m = (Mobile)targ; + from.SendGump(new NPChat(from, m)); + } + else + { + from.SendMessage("Veuillez cibler un Mobile."); + } + } + } + + private class DeplacerTarget : Target + { + Mobile m_MovingMobile; + + public DeplacerTarget(Mobile movingMobile) + : base(25, true, TargetFlags.None) + { + this.m_MovingMobile = movingMobile; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is LandTarget) + { + LandTarget targ = (LandTarget)targeted; + DeplacerMobile(m_MovingMobile, new Point3D(targ.X, targ.Y, targ.Z)); + } + else if (targeted is StaticTarget) + { + StaticTarget targ = (StaticTarget)targeted; + DeplacerMobile(m_MovingMobile, new Point3D(targ.X, targ.Y, targ.Z)); + } + else + { + from.SendMessage("Vous ne pouvez déplacer le mobile sur " + targeted.GetType().ToString()); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/GM/NPListener.cs b/Scripts/Vivre/Commands/GM/NPListener.cs new file mode 100644 index 0000000..dea53bd --- /dev/null +++ b/Scripts/Vivre/Commands/GM/NPListener.cs @@ -0,0 +1,123 @@ +/*************************************************************************** + * NPListener.cs + * ------------------- + * begin : May 25, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-07-23 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Misc +{ + public class NPListener + { + private static int distance = 15; + private static Mobile[][] ListenedMobiles = new Mobile[15][]; // 15 personnes max ! + + public static void Initialize() + { + EventSink.Speech += new SpeechEventHandler(SpeechToNPC); + EventSink.Logout += new LogoutEventHandler(GMLogout); + } + + public static bool AddListenedMobile(Mobile listener, Mobile listened) + { + if (listener == null || listened == null) return false; + + for (int i = 0; i < ListenedMobiles.Length; i++) + { + if (ListenedMobiles[i] == null) + { + ListenedMobiles[i] = new Mobile[2]; + ListenedMobiles[i][0] = listener; + ListenedMobiles[i][1] = listened; + return true; + } + } + + return false; + } + + public static bool RemoveListenedMobile(Mobile listener, Mobile listened) + { + if (listener == null || listened == null) return false; + + bool removed = false; + for (int i = 0; i < ListenedMobiles.Length; i++) + { + if (ListenedMobiles[i] != null && ListenedMobiles[i][0] == listener && ListenedMobiles[i][1] == listened) + { + ListenedMobiles[i][0] = null; + ListenedMobiles[i][1] = null; + ListenedMobiles[i] = null; + removed = true; + } + } + return removed; + } + + private static void SpeechToNPC(SpeechEventArgs args) + { + if (args.Mobile == null) return; + + Mobile speaker = args.Mobile; + + foreach (Mobile m in speaker.GetMobilesInRange(distance)) + { + int index = IndexListened(m); + if (index >= 0) + { + Mobile gm = ListenedMobiles[index][0]; + Mobile pnj = ListenedMobiles[index][1]; + + if (gm.Map != m.Map || gm.GetDistanceToSqrt(m) >= 12) + gm.SendMessage(pnj.SpeechHue, "<" + pnj.Name + "> " + speaker.Name + " : " + args.Speech); + } + } + } + + private static int IndexListened(Mobile listened) + { + for (int i = 0; i < ListenedMobiles.Length; i++) + { + if (ListenedMobiles[i] != null && ListenedMobiles[i][1] == listened && ListenedMobiles[i][0] != null) + return i; + else + { + // On tombe sur un mauvais enregistrement : On le nettoie + if(ListenedMobiles[i] != null && (ListenedMobiles[i][0] == null || ListenedMobiles[i][1] == null)) + ListenedMobiles[i] = null; + } + } + return -1; + } + + // Si un GM se déconnecte on le retire de la liste lui et ses PNJ écoutés + private static void GMLogout(LogoutEventArgs args) + { + if (args.Mobile == null || args.Mobile.AccessLevel == AccessLevel.Player) return; + + Mobile gm = args.Mobile; + + for (int i = 0; i < ListenedMobiles.Length; i++) + { + if (ListenedMobiles[i] != null && ListenedMobiles[i][0] == gm) + ListenedMobiles[i] = null; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/GM/RestartSoon.cs b/Scripts/Vivre/Commands/GM/RestartSoon.cs new file mode 100644 index 0000000..4e0d140 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/RestartSoon.cs @@ -0,0 +1,54 @@ +using System; +using Server; +using Server.Commands; +using Server.Misc; +using Server.Network; + +namespace Server.Commands +{ + public class RestartSoon + { + public static void Initialize() + { + CommandSystem.Register( "RestartSoon", AccessLevel.GameMaster, new CommandEventHandler( RestartSoon_OnCommand ) ); + } + + [Usage( "RestartSoon" )] + [Description( "Restart dès qu'il n'y a plus personne" )] + public static void RestartSoon_OnCommand( CommandEventArgs e ) + { + if(timer!=null) + { + e.Mobile.SendMessage("Le restart est déjà programmé."); + } + else + { + timer = new RestartSoonTimer(e); + timer.Start(); + e.Mobile.SendMessage("Restart programmé."); + } + } + + private static RestartSoonTimer timer; + + private class RestartSoonTimer: Timer + { + private CommandEventArgs m_e; + + public RestartSoonTimer(CommandEventArgs e): base( TimeSpan.FromMinutes( 1 ),TimeSpan.FromMinutes( 1 ) ) + { + m_e = e; + } + + protected override void OnTick() + { + if(NetState.Instances.Count==0) + { + World.Broadcast(0x35, false, "Redémarrage du serveur car plus personne en ligne !"); + AutoRestart.Restart_OnCommand( m_e ); + } + } + } + } +} + diff --git a/Scripts/Vivre/Commands/GM/RestoreAccessLevel.cs b/Scripts/Vivre/Commands/GM/RestoreAccessLevel.cs new file mode 100644 index 0000000..03dc909 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/RestoreAccessLevel.cs @@ -0,0 +1,33 @@ +using System; +using Server; + +namespace Server.Commands +{ + public class RestoreAccessLevel + { + public static void Initialize() + { + CommandSystem.Register("ra", AccessLevel.Player, new CommandEventHandler(RA_OnCommand)); + CommandSystem.Register("pl", AccessLevel.Counselor, new CommandEventHandler(PL_OnCommand)); + } + + private static void RA_OnCommand(CommandEventArgs e) + { + if (e.Mobile.Account != null && e.Mobile.Account.AccessLevel > AccessLevel.Player) + { + e.Mobile.AccessLevel = e.Mobile.Account.AccessLevel; + e.Mobile.SendMessage("Vous avez récupéré vos accès."); + } + else + { + e.Mobile.SendMessage("This command is deprecated."); + } + } + + private static void PL_OnCommand(CommandEventArgs e) + { + e.Mobile.AccessLevel = AccessLevel.Player; + e.Mobile.SendMessage("Vous êtes désormais un joueur."); + } + } +} diff --git a/Scripts/Vivre/Commands/GM/Say.cs b/Scripts/Vivre/Commands/GM/Say.cs new file mode 100644 index 0000000..2f13d9d --- /dev/null +++ b/Scripts/Vivre/Commands/GM/Say.cs @@ -0,0 +1,61 @@ +using System; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Items; + +namespace Server.Commands +{ + public class CustomCmdHandlers + { + public static void Initialize() + { + CommandSystem.Register("Say", AccessLevel.GameMaster, new CommandEventHandler(Say_OnCommand)); + } + + [Usage("Say ")] + [Description("Forces Targeted Mobile or Item to Say .")] + public static void Say_OnCommand(CommandEventArgs e) + { + string toSay = e.ArgString.Trim(); + + if (toSay.Length > 0) + e.Mobile.Target = new SayTarget(toSay); + else + e.Mobile.SendMessage("Format: Say \"\""); + } + + private class SayTarget : Target + { + private string m_toSay; + + public SayTarget(string say) + : base(-1, false, TargetFlags.None) + { + m_toSay = say; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile) + { + Mobile targ = (Mobile)targeted; + + if (from != targ && from.AccessLevel > targ.AccessLevel) + { + CommandLogging.WriteLine(from, "{0} {1} forcing speech on {2}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(targ)); + targ.Say(m_toSay); + } + } + else if (targeted is Item) + { + Item targ = (Item)targeted; + targ.PublicOverheadMessage(MessageType.Regular, Utility.RandomDyedHue(), false, m_toSay); + } + else + from.SendMessage("Invaild Target Type"); + } + } + } +} diff --git a/Scripts/Vivre/Commands/GM/SerializeDuper.cs b/Scripts/Vivre/Commands/GM/SerializeDuper.cs new file mode 100644 index 0000000..40af650 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/SerializeDuper.cs @@ -0,0 +1,1578 @@ +/*************************************************************************** + * SerializeDuper.cs + * ------------------- + * Implements a duplication command based on the Serialize() and + * Deserialize() methods by utilizing a new Writer/Reader combination. + * + * What can be duplicated? + * A GM may duplicate any item or mobile without properties + * above his AccessLevel + * + * What cannot be duplicated? + * PlayerMobiles cannot be duplicated. + * Items/mobiles cannot be duplicated if their references exceed a + * certain depth. + * (e.g. a bag in a bag, in a bag, in a bag, in a backpack of a mobile) + * Items/mobiles cannot be duplicated if the duplicated items exceed + * a certain sanity amount. + * + * You can find the most recent version of this script under the + * following link: + * + * + * Created by Lichtblitz ( GM Aldor ) + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Reflection; +using System.Text; +using Server.Guilds; +using Server.Mobiles; +using Server.Commands; +using Server.Commands.Generic; +using Server.Targeting; +using CPA = Server.CommandPropertyAttribute; +using Server.Items; + +namespace Server.Commands +{ + public class DupeCommand + { + /// + /// Maximum depth of recursions + /// + public const int MAX_RECURSIONS = 5; + + /// + /// Maximum amount of duplicated entities + /// + public const int MAX_ENTITIES = 500; + + public static void Initialize() + { + CommandSystem.Register( "dupe", AccessLevel.GameMaster, new CommandEventHandler( Dupe_OnCommand ) ); + } + + [Usage( "dupe" )] + [Description( "Duplicates any Item or Mobile and any Item or Mobile referenced by them." )] + public static void Dupe_OnCommand( CommandEventArgs e ) + { + e.Mobile.Target = new DupeTarget(); + } + } + + /// + /// Target cursor including duplication methods. + /// + public class DupeTarget : Target + { + public DupeTarget() : base( -1, false, TargetFlags.None ) { } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( from == null || targeted == null || (targeted is Item && ((Item)targeted).Deleted) || (targeted is Mobile && ((Mobile)targeted).Deleted) ) + { + return; + } + + if ( targeted is PlayerMobile ) + { + from.SendMessage( "That's not the way to increase the number of players!" ); + return; + } + + List itemList = new List(); + List mobileList = new List(); + Dictionary serialMapping = new Dictionary(); + + try + { + Dupe( from, targeted, DupeCommand.MAX_RECURSIONS, itemList, mobileList, serialMapping ); + + // Duping messed up the parents; we need to fix this now + foreach ( Item item in itemList.ToArray() ) + { + // Items need to be copied to avoid EnumerationExceptions + foreach ( object child in item.Items.ToArray() ) + { + item.AddItem( (Item)child ); + } + } + + foreach ( Mobile mobile in mobileList.ToArray() ) + { + // Items need to be copied to avoid EnumerationExceptions + foreach ( object child in mobile.Items.ToArray() ) + { + mobile.AddItem( (Item)child ); + } + } + + // If more than one Item has been duped they will be placed inside a colored bag. + Container bag = null; + if ( itemList.Count > 1 ) + { + bag = new Server.Items.Bag(); + bag.Name = "Duped on " + DateTime.Today.ToString( "dd.MM.yyyy" ); + bag.Hue = 6; + } + + // All Items will be placed inside the bag/backpack and all mobiles will be + // moved to the position of the GM + // (except for those on the internal map) + int internalMapCount = 0; + + foreach ( Item item in itemList ) + { + if ( item.Map == Map.Internal ) + { + internalMapCount++; + continue; + } + + if ( (item.Parent == null || (!itemList.Contains( item.Parent as Item ) && !mobileList.Contains( item.Parent as Mobile ))) ) + // Lies on the floor or in any container that is not part of this duplication process + { + item.Parent = null; // Remove any reference to the former parent + if ( bag == null ) + { + from.AddToBackpack( item ); + } + else + { + if ( bag.Items.Count <= 0 ) + { + // The first non-internal item to be placed adds the bag to the callers backpack + from.AddToBackpack( bag ); + } + + bag.AddItem( item ); + from.SendMessage( item.GetType().ToString() ); + } + } + + item.UpdateTotals(); + item.InvalidateProperties(); + } + foreach ( Mobile mobile in mobileList ) + { + if ( mobile.Map == Map.Internal ) + { + internalMapCount++; + continue; + } + + mobile.MoveToWorld( from.Location, from.Map ); + + mobile.UpdateResistances(); + mobile.UpdateTotals(); + mobile.InvalidateProperties(); + } + + // Sending the success message. + from.SendMessage( "{0} Items and {1} Mobiles have been successfully duplicated.", itemList.Count, mobileList.Count ); + if ( internalMapCount > 0 ) + { + from.SendMessage( "{0} of which are on the internal map.", internalMapCount ); + } + + #region InterfaceGump + ArrayList completeList = new ArrayList(); + completeList.AddRange( mobileList ); + completeList.AddRange( itemList ); + + from.SendGump( new InterfaceGump( from, new string[] { "Entity" }, completeList, 0, null ) ); + #endregion + + #region CommandLogging + // Implementing command logging + StringBuilder sb = new StringBuilder(); + sb.AppendFormat( "{0} {1} duping ", from.AccessLevel, CommandLogging.Format( from ) ); + sb.AppendFormat( "at {0} in {1}: ", from.Location, from.Map ); + int serial = (targeted is Item ? ((Item)targeted).Serial : ((Mobile)targeted).Serial); + sb.AppendFormat( "{0} Items and {1} Mobiles via target 0x{2:X}", itemList.Count, mobileList.Count, serial ); + CommandLogging.WriteLine( from, sb.ToString() ); + + sb = new StringBuilder(); + StringBuilder sbm = new StringBuilder(); + + sb.Append( "Serials been duped:" ); + sbm.Append( "Serials:" ); + + foreach ( KeyValuePair kvp in serialMapping ) + { + sb.AppendFormat( " 0x{0:X};", kvp.Key ); + sbm.AppendFormat( " 0x{0:X};", kvp.Value ); + } + CommandLogging.WriteLine( from, sb.ToString() ); + CommandLogging.WriteLine( from, sbm.ToString() ); + #endregion + } + catch ( DupeException ex ) + { + from.SendMessage( ex.Message ); + DeleteAll( itemList, mobileList ); + } + } + + /// + /// Deletes all entities, created so far. + /// + /// List of Items + /// List of Mobiles + private void DeleteAll( List itemList, List mobileList ) + { + foreach ( Item item in itemList ) + { + item.Delete(); + } + foreach ( Mobile mobile in mobileList ) + { + mobile.Delete(); + } + } + + /// + /// Primary dupe method. Will be called recursively. + /// + /// Caller of the dupe command + /// Item to be duped + /// Recursions left + /// List of items created so far + /// List of mobiles created so far + /// Mapping of serials of duped items and their copied counterparts + /// Duplicated entity + public static object Dupe( Mobile from, object toDupe, int recursionDepth, List itemList, List mobileList, Dictionary serialMapping ) + { + object toReturn = null; + + Type type = toDupe.GetType(); + + // Getting all properties + PropertyInfo[] allProps = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public ); + + // Checking if the caller's AccessLevel is high enough to write those + foreach ( PropertyInfo thisProp in allProps ) + { + CPA attr = Properties.GetCPA( thisProp ); + if ( attr != null && (from.AccessLevel < attr.ReadLevel || from.AccessLevel < attr.WriteLevel) ) + { + // Ignoring all properties declared by BaseCreature and Mobile + if ( thisProp.DeclaringType != typeof( BaseCreature ) && thisProp.DeclaringType != typeof( Mobile ) ) + { + throw new AccessLevelTooLowException( "Your AccessLevel is too low to dupe this: " + thisProp.Name ); + } + } + + } + + MemoryStream stream = new MemoryStream(); + DupeWriter writer = new DupeWriter( stream, recursionDepth ); + DupeReader reader = new DupeReader( stream, from, itemList, mobileList, serialMapping ); + + try + { + if ( toDupe is Item ) + { + Item item = (Item)toDupe; + item.Serialize( writer ); + } + else + { + Mobile mobile = (Mobile)toDupe; + mobile.Serialize( writer ); + } + + // YAY! If we arrived here we are allowed to duplicate the item and have collected all necessary data + writer.Flush(); + reader.Seek( 0, SeekOrigin.Begin ); // Reset position of the reader + + // Fetch constructor with serial as parameter + ConstructorInfo ctor = type.GetConstructor( new Type[] { typeof( Serial ) } ); + + if ( toDupe is Item ) + { + Item item = (Item)ctor.Invoke( new object[] { Serial.NewItem } ); + World.AddItem( item ); // We don't want duplicate serials so we add it to the world right away to block its serial. + serialMapping.Add( ((Item)toDupe).Serial, item.Serial ); + itemList.Insert( 0, item ); // Insert at the beginning to reverse the recursive order + + item.Deserialize( reader ); // Deserialize calls Dupe again if it reaches a reference. + toReturn = item; + } + else if ( toDupe is Mobile ) + { + // Konstruktor mit Serial aufrufen + Mobile mobile = (Mobile)ctor.Invoke( new object[] { Serial.NewMobile } ); + World.AddMobile( mobile ); // We don't want duplicate serials so we add it to the world right away to block its serial. + serialMapping.Add( ((Mobile)toDupe).Serial, mobile.Serial ); + mobileList.Insert( 0, mobile ); // Insert at the beginning to reverse the recursive order + + mobile.Deserialize( reader ); // Deserialize calls Dupe again if it reaches a reference. + toReturn = mobile; + } + + if ( !reader.End() ) + { + // The stream is not empty? + throw new DeserializeException( "Cannot dupe " + toReturn.GetType().Name + ". Serialize/Deserialize is either broken or uses hacks." ); + } + + if ( itemList.Count + mobileList.Count > DupeCommand.MAX_ENTITIES ) + { + throw new EntitiesExceededException( "Cannot dupe more than " + DupeCommand.MAX_ENTITIES + " Items/Mobiles!" ); + } + } + finally + { + writer.Close(); + reader.Close(); + stream.Close(); + } + + return toReturn; + } + } +} + +namespace Server +{ + /// + /// Modified , which writes in a + /// instead of a file. + /// + public class DupeWriter : GenericWriter + { + private bool PrefixStrings = true; + private MemoryStream m_File; + + int recursionDepth; + + protected virtual int BufferSize + { + get + { + return 64 * 1024; + } + } + + private byte[] m_Buffer; + + private int m_Index; + + private Encoding m_Encoding; + + public DupeWriter( MemoryStream strm, int recursionDepth ) + { + m_Encoding = Utility.UTF8; + m_Buffer = new byte[BufferSize]; + m_File = strm; + this.recursionDepth = recursionDepth; + } + + public void Flush() + { + if ( m_Index > 0 ) + { + m_Position += m_Index; + + m_File.Write( m_Buffer, 0, m_Index ); + m_Index = 0; + } + } + + private long m_Position; + + public override long Position + { + get + { + return m_Position + m_Index; + } + } + + public Stream UnderlyingStream + { + get + { + if ( m_Index > 0 ) + Flush(); + + return m_File; + } + } + + public override void Close() + { + if ( m_Index > 0 ) + Flush(); + + m_File.Close(); + } + + public override void WriteEncodedInt( int value ) + { + // May dupe + uint v = (uint)value; + + while ( v >= 0x80 ) + { + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = (byte)(v | 0x80); + v >>= 7; + } + + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = (byte)v; + } + + private byte[] m_CharacterBuffer; + private int m_MaxBufferChars; + private const int LargeByteBufferSize = 256; + + internal void InternalWriteString( string value ) + { + int length = m_Encoding.GetByteCount( value ); + + WriteEncodedInt( length ); + + if ( m_CharacterBuffer == null ) + { + m_CharacterBuffer = new byte[LargeByteBufferSize]; + m_MaxBufferChars = LargeByteBufferSize / m_Encoding.GetMaxByteCount( 1 ); + } + + if ( length > LargeByteBufferSize ) + { + int current = 0; + int charsLeft = value.Length; + + while ( charsLeft > 0 ) + { + int charCount = (charsLeft > m_MaxBufferChars) ? m_MaxBufferChars : charsLeft; + int byteLength = m_Encoding.GetBytes( value, current, charCount, m_CharacterBuffer, 0 ); + + if ( (m_Index + byteLength) > BufferSize ) + Flush(); + + Buffer.BlockCopy( m_CharacterBuffer, 0, m_Buffer, m_Index, byteLength ); + m_Index += byteLength; + + current += charCount; + charsLeft -= charCount; + } + } + else + { + int byteLength = m_Encoding.GetBytes( value, 0, value.Length, m_CharacterBuffer, 0 ); + + if ( (m_Index + byteLength) > BufferSize ) + Flush(); + + Buffer.BlockCopy( m_CharacterBuffer, 0, m_Buffer, m_Index, byteLength ); + m_Index += byteLength; + } + } + + public override void Write( string value ) + { + // May dupe + if ( PrefixStrings ) + { + if ( value == null ) + { + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = 0; + } + else + { + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = 1; + + InternalWriteString( value ); + } + } + else + { + InternalWriteString( value ); + } + } + + public override void Write( DateTime value ) + { + // May dupe + Write( value.Ticks ); + } + + public override void WriteDeltaTime( DateTime value ) + { + // May dupe + long ticks = value.Ticks; + long now = DateTime.Now.Ticks; + + TimeSpan d; + + try { d = new TimeSpan( ticks - now ); } + catch { if ( ticks < now ) d = TimeSpan.MaxValue; else d = TimeSpan.MaxValue; } + + Write( d ); + } + + public override void Write( IPAddress value ) + { + // May NOT dupe + ThrowTypeException( "IPAddress" ); + + Write( Utility.GetLongAddressValue( value ) ); + } + + public override void Write( TimeSpan value ) + { + // May dupe + Write( value.Ticks ); + } + + public override void Write( decimal value ) + { + // May dupe + int[] bits = Decimal.GetBits( value ); + + for ( int i = 0; i < bits.Length; ++i ) + Write( bits[i] ); + } + + public override void Write( long value ) + { + // May dupe + if ( (m_Index + 8) > BufferSize ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Buffer[m_Index + 4] = (byte)(value >> 32); + m_Buffer[m_Index + 5] = (byte)(value >> 40); + m_Buffer[m_Index + 6] = (byte)(value >> 48); + m_Buffer[m_Index + 7] = (byte)(value >> 56); + m_Index += 8; + } + + public override void Write( ulong value ) + { + // May dupe + if ( (m_Index + 8) > BufferSize ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Buffer[m_Index + 4] = (byte)(value >> 32); + m_Buffer[m_Index + 5] = (byte)(value >> 40); + m_Buffer[m_Index + 6] = (byte)(value >> 48); + m_Buffer[m_Index + 7] = (byte)(value >> 56); + m_Index += 8; + } + + public override void Write( int value ) + { + // May dupe + if ( (m_Index + 4) > BufferSize ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Index += 4; + } + + public override void Write( uint value ) + { + // May dupe + if ( (m_Index + 4) > BufferSize ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Index += 4; + } + + public override void Write( short value ) + { + // May dupe + if ( (m_Index + 2) > BufferSize ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Index += 2; + } + + public override void Write( ushort value ) + { + // May dupe + if ( (m_Index + 2) > BufferSize ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Index += 2; + } + + public /*unsafe*/ override void Write( double value ) + { + // May dupe; MODIFIED: new implementation since operation was unsafe + + byte[] eightBytes = System.BitConverter.GetBytes( value ); + for ( int i = 0; i < 8; i++ ) + { + Write( eightBytes[i] ); + } + + /* + if( (m_Index + 8) > m_Buffer.Length ) + Flush(); + + fixed( byte* pBuffer = m_Buffer ) + *((double*)(pBuffer + m_Index)) = value; + + m_Index += 8; + */ + } + + public /*unsafe*/ override void Write( float value ) + { + // May dupe; MODIFIED: new implementation since operation was unsafe + + byte[] fourBytes = System.BitConverter.GetBytes( value ); + for ( int i = 0; i < 4; i++ ) + { + Write( fourBytes[i] ); + } + + /* + if ( (m_Index + 4) > BufferSize ) + Flush(); + + fixed ( byte* pBuffer = m_Buffer ) + *((float*)(&pBuffer[m_Index])) = value; + + m_Index += 4; + */ + } + + private char[] m_SingleCharBuffer = new char[1]; + + public override void Write( char value ) + { + // May dupe + if ( (m_Index + 8) > BufferSize ) + Flush(); + + m_SingleCharBuffer[0] = value; + + int byteCount = m_Encoding.GetBytes( m_SingleCharBuffer, 0, 1, m_Buffer, m_Index ); + m_Index += byteCount; + } + + public override void Write( byte value ) + { + // May dupe + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = value; + } + + public override void Write( sbyte value ) + { + // May dupe + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = (byte)value; + } + + public override void Write( bool value ) + { + // May dupe + if ( (m_Index + 1) > BufferSize ) + Flush(); + + m_Buffer[m_Index++] = (byte)(value ? 1 : 0); + } + + public override void Write( Point3D value ) + { + // May dupe + Write( value.X ); + Write( value.Y ); + Write( value.Z ); + } + + public override void Write( Point2D value ) + { + // May dupe + Write( value.X ); + Write( value.Y ); + } + + public override void Write( Rectangle2D value ) + { + // May dupe + Write( value.Start ); + Write( value.End ); + } + + public override void Write( Rectangle3D value ) + { + Write( value.Start ); + Write( value.End ); + } + + public override void Write( Map value ) + { + // May dupe + + if ( value != null ) + Write( (byte)value.MapIndex ); + else + Write( (byte)0xFF ); + } + + public override void Write( Item value ) + { + // May dupe; MODIFIED + if ( recursionDepth < 1 ) + { + ThrowRecursionException(); + } + Write( (int)(recursionDepth - 1) ); // ADDED to keep track of recursions + + if ( value == null || value.Deleted ) + Write( Serial.MinusOne ); + else + Write( value.Serial ); + } + + public override void Write( Mobile value ) + { + // May dupe; MODIFIED + if ( recursionDepth < 1 ) + { + ThrowRecursionException(); + } + + if ( value is PlayerMobile ) + { + ThrowTypeException( "PlayerMobile" ); + } + + Write( (int)(recursionDepth - 1) ); // ADDED to keep track of recursions + + if ( value == null || value.Deleted ) + Write( Serial.MinusOne ); + else + Write( value.Serial ); + } + + public override void Write( BaseGuild value ) + { + if ( value == null ) + Write( 0 ); + else + { + // May NOT dupe + ThrowTypeException( "BaseGuild" ); + Write( value.Id ); + } + } + + public override void WriteItem( T value ) + { + // May dupe + Write( value ); + } + + public override void WriteMobile( T value ) + { + // May dupe + Write( value ); + } + + public override void WriteGuild( T value ) + { + // May dupe + Write( value ); + } + + public override void WriteMobileList( ArrayList list ) + { + // May dupe + WriteMobileList( list, false ); + } + + public override void WriteMobileList( ArrayList list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( ((Mobile)list[i]).Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( (Mobile)list[i] ); + } + + public override void WriteItemList( ArrayList list ) + { + // May dupe + WriteItemList( list, false ); + } + + public override void WriteItemList( ArrayList list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( ((Item)list[i]).Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( (Item)list[i] ); + } + + public override void WriteGuildList( ArrayList list ) + { + // May dupe + WriteGuildList( list, false ); + } + + public override void WriteGuildList( ArrayList list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( ((BaseGuild)list[i]).Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( (BaseGuild)list[i] ); + } + + public override void Write( List list ) + { + Write( list, false ); + } + + public override void Write( List list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteItemList( List list ) + { + // May dupe + WriteItemList( list, false ); + } + + public override void WriteItemList( List list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void Write( List list ) + { + // May dupe + Write( list, false ); + } + + public override void Write( List list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteMobileList( List list ) + { + // May dupe + WriteMobileList( list, false ); + } + + public override void WriteMobileList( List list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void Write( List list ) + { + // May dupe + Write( list, false ); + } + + public override void Write( List list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( list[i].Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteGuildList( List list ) + { + // May dupe + WriteGuildList( list, false ); + } + + public override void WriteGuildList( List list, bool tidy ) + { + // May dupe + if ( tidy ) + { + for ( int i = 0; i < list.Count; ) + { + if ( list[i].Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void Write( Race value ) + { + // May dupe + if ( value != null ) + Write( (byte)value.RaceIndex ); + else + Write( (byte)0xFF ); + } + + private void ThrowTypeException( String typename ) + { + throw new MayNotDupeException( String.Format( "Property of type \"{0}\" is not allowed to dupe!", typename ) ); + } + + private void ThrowRecursionException() + { + throw new RecursionsExceededException( String.Format( "Maximum number of {0} recursions exceeded!", DupeCommand.MAX_RECURSIONS ) ); + } + } + + public class DupeReader : GenericReader + { + private Mobile duper; + private List itemList; + private List mobileList; + private Dictionary serialMapping; + private BinaryReader m_File; + + public DupeReader( MemoryStream stream, Mobile duper, List itemList, List mobileList, Dictionary serialMapping ) + : base() + { + this.m_File = new BinaryReader( stream ); + this.duper = duper; + this.itemList = itemList; + this.mobileList = mobileList; + this.serialMapping = serialMapping; + } + + public void Close() + { + m_File.Close(); + } + + public long Position + { + get + { + return m_File.BaseStream.Position; + } + } + + public long Seek( long offset, SeekOrigin origin ) + { + return m_File.BaseStream.Seek( offset, origin ); + } + + public override string ReadString() + { + if ( ReadByte() != 0 ) + return m_File.ReadString(); + else + return null; + } + + public override DateTime ReadDeltaTime() + { + long ticks = m_File.ReadInt64(); + long now = DateTime.Now.Ticks; + + if ( ticks > 0 && (ticks + now) < 0 ) + return DateTime.MaxValue; + else if ( ticks < 0 && (ticks + now) < 0 ) + return DateTime.MinValue; + + try { return new DateTime( now + ticks ); } + catch { if ( ticks > 0 ) return DateTime.MaxValue; else return DateTime.MinValue; } + } + + public override IPAddress ReadIPAddress() + { + return new IPAddress( m_File.ReadInt64() ); + } + + public override int ReadEncodedInt() + { + int v = 0, shift = 0; + byte b; + + do + { + b = m_File.ReadByte(); + v |= (b & 0x7F) << shift; + shift += 7; + } while ( b >= 0x80 ); + + return v; + } + + public override DateTime ReadDateTime() + { + return new DateTime( m_File.ReadInt64() ); + } + + public override TimeSpan ReadTimeSpan() + { + return new TimeSpan( m_File.ReadInt64() ); + } + + public override decimal ReadDecimal() + { + return m_File.ReadDecimal(); + } + + public override long ReadLong() + { + return m_File.ReadInt64(); + } + + public override ulong ReadULong() + { + return m_File.ReadUInt64(); + } + + public override int ReadInt() + { + return m_File.ReadInt32(); + } + + public override uint ReadUInt() + { + return m_File.ReadUInt32(); + } + + public override short ReadShort() + { + return m_File.ReadInt16(); + } + + public override ushort ReadUShort() + { + return m_File.ReadUInt16(); + } + + public override double ReadDouble() + { + return m_File.ReadDouble(); + } + + public override float ReadFloat() + { + return m_File.ReadSingle(); + } + + public override char ReadChar() + { + return m_File.ReadChar(); + } + + public override byte ReadByte() + { + return m_File.ReadByte(); + } + + public override sbyte ReadSByte() + { + return m_File.ReadSByte(); + } + + public override bool ReadBool() + { + return m_File.ReadBoolean(); + } + + public override Point3D ReadPoint3D() + { + return new Point3D( ReadInt(), ReadInt(), ReadInt() ); + } + + public override Point2D ReadPoint2D() + { + return new Point2D( ReadInt(), ReadInt() ); + } + + public override Rectangle2D ReadRect2D() + { + return new Rectangle2D( ReadPoint2D(), ReadPoint2D() ); + } + + public override Rectangle3D ReadRect3D() + { + return new Rectangle3D( ReadPoint3D(), ReadPoint3D() ); + } + + public override Map ReadMap() + { + return Map.Maps[ReadByte()]; + } + + /// + /// Reads the serial of an item and duplicates that item if it hasn't been + /// duplicated before. + /// + /// Reference to the duplicated item. + public override Item ReadItem() + { + int recursionDepth = ReadInt(); + int serial = ReadInt(); + + // We already duped this Item; use reference to previously duped one + if ( serialMapping.ContainsKey( serial ) ) + { + return World.FindItem( serialMapping[serial] ); + } + + Item toDupe = World.FindItem( serial ); + + if ( toDupe == null ) { return null; } + + return DupeTarget.Dupe( duper, toDupe, recursionDepth, itemList, mobileList, serialMapping ) as Item; + } + + /// + /// Reads the serial of a mobile and duplicates that mobile if it hasn't been + /// duplicated before. + /// + /// Reference to the duplicated mobile. + public override Mobile ReadMobile() + { + int recursionDepth = ReadInt(); + int serial = ReadInt(); + + // We already duped this Mobile; use reference to previously duped one + if ( serialMapping.ContainsKey( serial ) ) + { + return World.FindMobile( serialMapping[serial] ); + } + + Mobile toDupe = World.FindMobile( serial ); + + if ( toDupe == null ) { return null; } + + return DupeTarget.Dupe( duper, toDupe, recursionDepth, itemList, mobileList, serialMapping ) as Mobile; + } + + public override BaseGuild ReadGuild() + { + return BaseGuild.Find( ReadInt() ); + } + + public override T ReadItem() + { + return ReadItem() as T; + } + + public override T ReadMobile() + { + return ReadMobile() as T; + } + + public override T ReadGuild() + { + return ReadGuild() as T; + } + + public override ArrayList ReadItemList() + { + int count = ReadInt(); + + if ( count > 0 ) + { + ArrayList list = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + Item item = ReadItem(); + + if ( item != null ) + { + list.Add( item ); + } + } + + return list; + } + else + { + return new ArrayList(); + } + } + + public override ArrayList ReadMobileList() + { + int count = ReadInt(); + + if ( count > 0 ) + { + ArrayList list = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + Mobile m = ReadMobile(); + + if ( m != null ) + { + list.Add( m ); + } + } + + return list; + } + else + { + return new ArrayList(); + } + } + + public override ArrayList ReadGuildList() + { + int count = ReadInt(); + + if ( count > 0 ) + { + ArrayList list = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) + { + BaseGuild g = ReadGuild(); + + if ( g != null ) + { + list.Add( g ); + } + } + + return list; + } + else + { + return new ArrayList(); + } + } + + public override List ReadStrongItemList() + { + return ReadStrongItemList(); + } + + public override List ReadStrongItemList() + { + int count = ReadInt(); + + if ( count > 0 ) + { + List list = new List( count ); + + for ( int i = 0; i < count; ++i ) + { + T item = ReadItem() as T; + + if ( item != null ) + { + list.Add( item ); + } + } + + return list; + } + else + { + return new List(); + } + } + + public override List ReadStrongMobileList() + { + return ReadStrongMobileList(); + } + + public override List ReadStrongMobileList() + { + int count = ReadInt(); + + if ( count > 0 ) + { + List list = new List( count ); + + for ( int i = 0; i < count; ++i ) + { + T m = ReadMobile() as T; + + if ( m != null ) + { + list.Add( m ); + } + } + + return list; + } + else + { + return new List(); + } + } + + public override List ReadStrongGuildList() + { + return ReadStrongGuildList(); + } + + public override List ReadStrongGuildList() + { + int count = ReadInt(); + + if ( count > 0 ) + { + List list = new List( count ); + + for ( int i = 0; i < count; ++i ) + { + T g = ReadGuild() as T; + + if ( g != null ) + { + list.Add( g ); + } + } + + return list; + } + else + { + return new List(); + } + } + + public override bool End() + { + return m_File.PeekChar() == -1; + } + + public override Race ReadRace() + { + return Race.Races[ReadByte()]; + } + } + + /// + /// Base Exception of all local exceptions. Used for structuring. + /// + public abstract class DupeException : Exception + { + public DupeException( string message ) + : base( message ) + { + } + } + + /// + /// This exception is thrown when tying to duplicate a data type that cannot be duplicated. + /// + public class MayNotDupeException : DupeException + { + public MayNotDupeException( string message ) + : base( message ) + { + } + } + + /// + /// This exception is thrown when the amount of + /// has been exceeded. + /// + public class RecursionsExceededException : DupeException + { + public RecursionsExceededException( string message ) + : base( message ) + { + } + } + + /// + /// This exception is thrown when the amount of + /// has been exceeded. + /// + public class EntitiesExceededException : DupeException + { + public EntitiesExceededException( string message ) + : base( message ) + { + } + } + + /// + /// The Datastream is longer or shorter than its deserialization. Either Serialize/Deserialize + /// is broken or different data types are written and read for the same variable. + /// e.g.: + /// Serialize(): + /// Write( (Mobile) abc); + /// Deserialize: + /// int serial = ReadInt(); + /// abc = World.FindMobile( serial ); + /// + public class DeserializeException : DupeException + { + public DeserializeException( string message ) + : base( message ) + { + } + } + + /// + /// The caller lacks rights to duplicate the property. + /// + public class AccessLevelTooLowException : DupeException + { + public AccessLevelTooLowException( string message ) + : base( message ) + { + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/GM/Status.cs b/Scripts/Vivre/Commands/GM/Status.cs new file mode 100644 index 0000000..66b1922 --- /dev/null +++ b/Scripts/Vivre/Commands/GM/Status.cs @@ -0,0 +1,29 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Commands +{ + public class StatusCommand + { + public static void Initialize() + { + CommandSystem.Register("status", AccessLevel.Counselor, new CommandEventHandler(Status_OnCommand)); + } + + private static void Status_OnCommand(CommandEventArgs e) + { + PlayerMobile pm = e.Mobile as PlayerMobile; + + if (pm != null) + { + pm.ShowInStatus = !pm.ShowInStatus; + + if (pm.ShowInStatus) + pm.SendMessage("Vous êtes désormais visible dans le statut web."); + else + pm.SendMessage("Vous n'êtes plus visible dans le statut web."); + } + } + } +} diff --git a/Scripts/Vivre/Commands/Gifle.cs b/Scripts/Vivre/Commands/Gifle.cs new file mode 100644 index 0000000..8aa75dd --- /dev/null +++ b/Scripts/Vivre/Commands/Gifle.cs @@ -0,0 +1,59 @@ +using System; +using System.Text; +using Server.Commands; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Commands +{ + /// + /// Commandes pour donner et prendre des gifles + /// + public class Gifle + { + public static void Initialize() + { + // Scriptiz : les commandess sont insensibles à la casse + CommandSystem.Register("gifle", AccessLevel.Player, new CommandEventHandler(Gifle_OnCommand)); + //CommandSystem.Register("slap", AccessLevel.Player, new CommandEventHandler(Gifle_OnCommand)); + } + + public static void Gifle_OnCommand(CommandEventArgs e) + { + e.Mobile.BeginTarget(5, false, TargetFlags.None, new TargetCallback(Gifle_Callback)); + } + + /// + /// Execution de la gifle + /// + public static void Gifle_Callback(Mobile mJoueur, object objCible) + { + if (objCible is Mobile) + { + Mobile mCible = objCible as Mobile; + + // si le joueur s'est ciblé lui même + if (mJoueur == mCible) + mJoueur.Emote("*{0} se gifle*", mJoueur.Name); + // si il reussi a donner la gifle + else if (Utility.Random(10) > 3) // Scriptiz : pas besoin de stocker le booléen + { + mJoueur.Emote("*{0} gifle {1}*", mJoueur.Name, mCible.Name); + mCible.Emote("*{0} se prend une gifle de {1}*", mCible.Name, mJoueur.Name); + } + else // quel looseur il s'est manqué + { + mJoueur.Emote("*{0} gifle {1}, mais ratte*", mJoueur.Name, mCible.Name ); + mCible.Emote("*{0} esquive une gifle de {1}*", mCible.Name, mJoueur.Name); + } + + // animation + mCible.Animate(20, 1, 1, true, false, 2); + mJoueur.Animate(33, 1, 1, true, false, 2); + + // Scriptiz : son + mCible.PlaySound(0x135); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/Hasard.cs b/Scripts/Vivre/Commands/Hasard.cs new file mode 100644 index 0000000..30166a2 --- /dev/null +++ b/Scripts/Vivre/Commands/Hasard.cs @@ -0,0 +1,119 @@ +using System; +using Server; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Items; + +namespace Server.Commands +{ + public class HasardCmd + { + public static void Initialize() + { + CommandSystem.Register("Hasard", AccessLevel.Player, new CommandEventHandler(Hasard_OnCommand)); + CommandSystem.Register("PublicHasard", AccessLevel.Player, new CommandEventHandler(PublicHasard_OnCommand)); + } + + [Usage("Hasard ")] + [Description("Check success or fail according to .")] + public static void Hasard_OnCommand(CommandEventArgs e) + { + int dice = 0; + string numString = e.ArgString.Trim(); + bool IsNumber = int.TryParse(numString, out dice); + + if (!IsNumber){ + e.Mobile.SendMessage("Veuillez entrer une valeur num�rique comprise entre 2 et 100"); + return; + } + + else if (dice > 100 || dice < 2){ + e.Mobile.SendMessage("Veuillez entrer une valeur num�rique comprise entre 2 et 100"); + return; + } + + int num1 = Utility.Random(dice); + int num2 = Utility.Random(dice); + + if (num1 == num2) + e.Mobile.SendMessage("Vous r�ussissez votre action"); + else + e.Mobile.SendMessage("Vous �chouez votre action par {1} contre {2} [d{3}]", e.Mobile.Name, num1, num2, dice); + } + + [Usage("PublicHasard ")] + [Description("Check success or fail according to . Result is seen to everyone")] + public static void PublicHasard_OnCommand(CommandEventArgs e) + { + int dice = 0; + string numString = e.ArgString.Trim(); + bool IsNumber = int.TryParse(numString, out dice); + + if (!IsNumber){ + e.Mobile.SendMessage("Veuillez entrer une valeur num�rique comprise entre 2 et 100"); + return; + } + + else if (dice > 100 || dice < 2){ + e.Mobile.SendMessage("Veuillez entrer une valeur num�rique comprise entre 2 et 100"); + return; + } + + int num1 = Utility.Random(dice); + int num2 = Utility.Random(dice); + + if (num1 == num2) + { + e.Mobile.Emote("{0} a r�ussi son action [d{1}]", e.Mobile.Name,dice); + Map map = e.Mobile.Map; + + if (map == null || map == Map.Internal) + return; + + Point3D ourLoc = e.Mobile.Location; + + Point3D startLoc = new Point3D( ourLoc.X, ourLoc.Y, ourLoc.Z + 10 ); + Point3D endLoc = new Point3D( startLoc.X + Utility.RandomMinMax( -2, 2 ), startLoc.Y + Utility.RandomMinMax( -2, 2 ), startLoc.Z + 32 ); + + Effects.SendMovingEffect( new Entity( Serial.Zero, startLoc, map ), new Entity( Serial.Zero, endLoc, map ), + 0x36E4, 5, 0, false, false ); + + Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(FinishLaunch), new object[] { e.Mobile, endLoc, map }); +} + else + e.Mobile.Emote("{0} a �chou� son action par {1} contre {2} [d{3}]", e.Mobile.Name, num1, num2, dice); + } + private static void FinishLaunch(object state) + { + object[] states = (object[])state; + + Mobile from = (Mobile)states[0]; + Point3D endLoc = (Point3D)states[1]; + Map map = (Map)states[2]; + + int hue = Utility.Random(40); + + if (hue < 8) + hue = 0x66D; + else if (hue < 10) + hue = 0x482; + else if (hue < 12) + hue = 0x47E; + else if (hue < 16) + hue = 0x480; + else if (hue < 20) + hue = 0x47F; + else + hue = 0; + + if (Utility.RandomBool()) + hue = Utility.RandomList(0x47E, 0x47F, 0x480, 0x482, 0x66D); + + int renderMode = Utility.RandomList(0, 2, 3, 4, 5, 7); + + Effects.PlaySound(endLoc, map, Utility.Random(0x11B, 4)); + Effects.SendLocationEffect(endLoc, map, 0x373A + (0x10 * Utility.Random(4)), 16, 10, hue, renderMode); + } + } +} diff --git a/Scripts/Vivre/Commands/ItemInfo.cs b/Scripts/Vivre/Commands/ItemInfo.cs new file mode 100644 index 0000000..57a36a7 --- /dev/null +++ b/Scripts/Vivre/Commands/ItemInfo.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Commands +{ + public class ItemInfo + { + public static void Initialize() + { + CommandSystem.Register("ItemInfo", AccessLevel.Player, new CommandEventHandler(ItemInfo_OnCommand)); + } + + [Usage("ItemInfo")] + [Description("Renvoie Type et ItemID")] + public static void ItemInfo_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + from.Target = new InternalTarget(); + } + + private class InternalTarget : Target + { + public InternalTarget() + : base(3, false, TargetFlags.None) + { + } + + protected override void OnTarget(Mobile from, object o) + { + try + { + if (o is Item) + { + Item item = (Item)o as Item; + + if (item != null) + { + string type = item.GetType().ToString(); + string id = "0x" + item.ItemID.ToString("X"); + from.SendMessage(type + " " + id); + } + } + else if (o is StaticTarget) + { + StaticTarget targ = (StaticTarget)o; + from.SendMessage("static " + " " + "0x" + targ.ItemID.ToString("X")); + } + + } + catch + { + from.SendMessage("Ceci n'est pas un objet"); + } + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/KarmaFameCommand.cs b/Scripts/Vivre/Commands/KarmaFameCommand.cs new file mode 100644 index 0000000..8772071 --- /dev/null +++ b/Scripts/Vivre/Commands/KarmaFameCommand.cs @@ -0,0 +1,36 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server; + +namespace Server.Commands +{ + public class InfoCommand + { + public static void Initialize() + { + CommandSystem.Register("Karma", AccessLevel.Player, new CommandEventHandler(Karma_OnCommand)); + CommandSystem.Register("Fame", AccessLevel.Player, new CommandEventHandler(Fame_OnCommand)); + } + + private static void Karma_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from != null) + { + from.SendMessage("KARMA " + from.Karma.ToString()); + } + } + + private static void Fame_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (from != null) + { + from.SendMessage("FAME " + from.Fame.ToString()); + } + } + } +} diff --git a/Scripts/Vivre/Commands/Murmurer.cs b/Scripts/Vivre/Commands/Murmurer.cs new file mode 100644 index 0000000..4806266 --- /dev/null +++ b/Scripts/Vivre/Commands/Murmurer.cs @@ -0,0 +1,55 @@ +// Scriptiz : un peu l'�quivalent du ; mais fonctionne sur une plus longue distance +// et avec une seule autre personne +using System; +using Server; +using Server.Targeting; +using Server.Mobiles; +using Server.Commands; + +namespace Server.Commands +{ + public class Murmurer + { + public static void Initialize() + { + CommandSystem.Register("Murmurer", AccessLevel.Player, new CommandEventHandler(Murmure_OnCommand)); + CommandSystem.Register("mm", AccessLevel.Player, new CommandEventHandler(Murmure_OnCommand)); + } + + [Usage("Murmurer [string]")] + [Description("Murmure presque inaudible.")] + private static void Murmure_OnCommand(CommandEventArgs e) + { + string text = e.ArgString;//e.GetString(0); + e.Mobile.Target = new InternalTarget(text); + } + + private class InternalTarget : Target + { + private string m_text; + + public InternalTarget(string text) + : base(1, false, TargetFlags.None) + { + m_text = text; + } + + protected override void OnTarget(Mobile from, object o) + { + if (o is PlayerMobile) + { + Mobile mobile = (Mobile)o; + + if (from.InRange(mobile, 8)) + { + from.Say("*Murmure � l'oreille de " + mobile.Name + " *"); + mobile.SendMessage(from.Name + " vous murmure: " + m_text); + } + else from.SendMessage("Il est trop loin pour vous entendre..."); + } + else + from.SendMessage("Il ne comprend rien � ce que vous lui murmurez!"); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/PetEmote.cs b/Scripts/Vivre/Commands/PetEmote.cs new file mode 100644 index 0000000..6788900 --- /dev/null +++ b/Scripts/Vivre/Commands/PetEmote.cs @@ -0,0 +1,73 @@ +// Originally PetSpeak by FLuXx() +//Modded by Rhexy for emoting & disallowing squelched players from use. +using System; +using Server; +using Server.Targeting; +using Server.Mobiles; +using Server.Commands; + + +namespace Server.Commands +{ + public class PetThisCmd + { + public static void Initialize() + { + Register("PetEmote", AccessLevel.Player, new CommandEventHandler(PetEmote_OnCommand)); + Register("PE", AccessLevel.Player, new CommandEventHandler(PetEmote_OnCommand)); + } + + public static void Register(string command, AccessLevel access, CommandEventHandler handler) + { + CommandSystem.Register(command, access, handler); + } + + [Usage("PetEmote ")] + [Description("Allows owner to roleplay thier pet")] + public static void PetEmote_OnCommand(CommandEventArgs e) + { + if (e.Mobile.Squelched) + { + e.Mobile.SendMessage("You are squelched and cant use pet emoting."); + } + else + { + string toEmote = "*" + e.ArgString.Trim() + "*"; + + if (toEmote.Length > 0) + e.Mobile.Target = new EmoteThisTarget(toEmote); + else + e.Mobile.SendMessage("Format: PetEmote \"\""); + } + } + + private class EmoteThisTarget : Target + { + private string m_toEmote; + + public EmoteThisTarget(string s) + : base(-1, false, TargetFlags.None) + { + m_toEmote = s; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is BaseCreature) + { + BaseCreature targ = (BaseCreature)targeted; + + if (targ.ControlMaster == from) + { + CommandLogging.WriteLine(from, "{0} {1} forcing speech on {2}", from.AccessLevel, CommandLogging.Format(from), CommandLogging.Format(targ)); + targ.Emote(m_toEmote); + } + else + { + from.SendMessage("You do not own this pet."); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/Regs.cs b/Scripts/Vivre/Commands/Regs.cs new file mode 100644 index 0000000..a46532d --- /dev/null +++ b/Scripts/Vivre/Commands/Regs.cs @@ -0,0 +1,117 @@ +using System; +using Server; +using Server.Gumps; +using Server.Mobiles; +using Server.Network; +using Server.Items; +using Server.Commands; + +namespace Server.Commands +{ + public class CompteurReg + { + public static void Initialize() + { + CommandSystem.Register( "Regs", AccessLevel.Player, new CommandEventHandler( Regs_OnCommand ) ); + } + + [Usage( "Regs" )] + [Description( "Compteur de Reactifs" )] + public static void Regs_OnCommand( CommandEventArgs e ) + { + Mobile somemobile = e.Mobile; + somemobile.SendGump( new RegsGump(somemobile) ); + } + } + + public class RegsGump : Gump + { + PlayerMobile m_From; + int nb; + + private static Type[] m_Types_Mage = new Type[] + { + typeof( BlackPearl ), typeof( Bloodmoss ), + typeof( Garlic ), typeof( Ginseng ), + typeof( MandrakeRoot ), typeof( Nightshade ), + typeof( SulfurousAsh ), typeof( SpidersSilk ) + }; + private static Type[] m_Types_Necro = new Type[] + { + typeof( BatWing ), typeof( DaemonBlood ), + typeof( PigIron ), typeof( NoxCrystal ), + typeof( GraveDust ) + }; + + private static int[] m_Img_Mage = new int[] + { + 0xF7A, 0xF7B, 0xF84, 0xF85, 0xF86, 0xF88, 0xF8C, 0xF8D, + }; + private static int[] m_Img_Necro = new int[] + { + 0xF78, 0xF7D, 0xF8A, 0xF8E, 0xF8F + }; + + private static string[] m_Txt_Mage = new string[] + { + "Perle noire", "Mousse de sang", + "Ail", "Ginseng", + "Mandragore", "Belladone", + "Cendres sulfureuses", "Soie d'araign�e" + }; + + private static string[] m_Txt_Necro = new string[] + { + "Aile de chauve-souris", "Fiole de sang", + "Fonte brute", "Ecaille de serpent", + "Cendre volcanique" + }; + + public RegsGump ( Mobile from ) : base ( 40, 40 ) + { + m_From = from as PlayerMobile; + + m_From.CloseGump( typeof( RegsGump ) ); + + Container backpack = m_From.Backpack; + + AddPage( 0 ); + AddBackground( 0, 0, 440, 270, 5054 ); + AddBlackAlpha( 10, 10, 420, 25 ); + AddBlackAlpha( 10, 45, 200, 215 ); + AddBlackAlpha( 220, 45, 200, 215 ); + + AddLabel( 155, 14, 0x384, "R�actifs" ); + AddLabel( 100, 50, 0x284, "Mages" ); + AddLabel( 295, 50, 0x284, "Necros" ); + + for( int i = 0; i < m_Types_Mage.Length; i++ ) + { + nb = backpack.GetAmount( m_Types_Mage[i] ); + + AddItem( 15, 70 + (i * 20), m_Img_Mage[i] ); + AddLabelCropped( 55, 70 + (i * 20) , 150, 21, 0x384, m_Txt_Mage[i] + " :" ); + AddLabelCropped( 183, 70 + (i * 20) , 46, 21, 0x284, nb.ToString() ); + } + for( int i = 0; i < m_Types_Necro.Length; i++ ) + { + nb = backpack.GetAmount( m_Types_Necro[i] ); + + AddItem( 225, 70 + (i * 22), m_Img_Necro[i] ); + AddLabelCropped( 265, 70 + (i * 20) , 150, 21, 0x384, m_Txt_Necro[i] + " :" ); + AddLabelCropped( 395, 70 + (i * 20) , 46, 21, 0x284, nb.ToString() ); + } + } + + public void AddBlackAlpha( int x, int y, int width, int height ) + { + AddImageTiled( x, y, width, height, 2624 ); + AddAlphaRegion( x, y, width, height ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + + } + } +} diff --git a/Scripts/Vivre/Commands/Season.cs b/Scripts/Vivre/Commands/Season.cs new file mode 100644 index 0000000..c489e17 --- /dev/null +++ b/Scripts/Vivre/Commands/Season.cs @@ -0,0 +1,41 @@ +using System; +using Server.Mobiles; +using Server.Items; +using Server.Commands; +using Server.ServerSeasons; + +namespace Server.Commands +{ + public class SeasonCommand + { + + public static void Initialize() + { + CommandSystem.Register("saison", AccessLevel.Player, new CommandEventHandler(Saison_OnCommand)); + } + + [Usage("saison")] + [Description("Informe le joueur de la saison actuelle")] + public static void Saison_OnCommand(CommandEventArgs e) + { + string season = "la désolation"; + switch (e.Mobile.Map.Season) + { + case (int)Season.Spring: + season = "le printemps"; + break; + case (int)Season.Summer: + season = "l'été"; + break; + case (int)Season.Autumn: + season = "l'automne"; + break; + case (int)Season.Winter: + season = "l'hiver"; + break; + } + + e.Mobile.SendMessage(String.Format("C'est {0}", season)); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/SpecialEmotes.cs b/Scripts/Vivre/Commands/SpecialEmotes.cs new file mode 100644 index 0000000..a0db61b --- /dev/null +++ b/Scripts/Vivre/Commands/SpecialEmotes.cs @@ -0,0 +1,134 @@ +using System; +using System.Text; +using System.Reflection; +using System.Collections; +using Server; +using Server.Network; +using Server.Targeting; + +namespace Server.Commands +{ + public class SpecialEmotes + { + enum EmoteList + { + Kiss, + Slap, + Tete, + } + + public static void Initialize() + { + // Scriptiz : commande anim à partir de Counselor + CommandSystem.Register("Anim", AccessLevel.Counselor, new CommandEventHandler(Anim_OnCommand)); + CommandSystem.Register("Kiss", AccessLevel.Player, new CommandEventHandler(Kiss_OnCommand)); + CommandSystem.Register("Slap", AccessLevel.Player, new CommandEventHandler(Slap_OnCommand)); + CommandSystem.Register("Tete", AccessLevel.Player, new CommandEventHandler(Tete_OnCommand)); + } + + [Usage("Anim")] + [Description("Anime le personnage")] + public static void Anim_OnCommand(CommandEventArgs e) + { + if (e.Length == 1) + e.Mobile.Animate(e.GetInt32(0), 5, 1, true, false, 1); + else + e.Mobile.SendMessage("Format: Anim "); + } + + [Usage("Kiss")] + [Description("Embrasser")] + public static void Kiss_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new GetTarget(EmoteList.Kiss); + } + + [Usage("Slap")] + [Description("Donner une baffe")] + public static void Slap_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new GetTarget(EmoteList.Slap); + } + + [Usage("Tete")] + [Description("Donner un coup de tete")] + public static void Tete_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new GetTarget(EmoteList.Tete); + } + + private class GetTarget : Target + { + private EmoteList m_Emote; + + public GetTarget(EmoteList emote) + : base(-1, true, TargetFlags.None) + { + this.m_Emote = emote; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (!from.Alive) + { + from.SendMessage("Vous ne pouvez pas faire cela en étant mort !"); + return; + } + else if (from.Warmode) + { + from.SendMessage("Vous ne pouvez pas faire cela en combat!"); + return; + } + else if (!(targeted is Mobile)) + { + from.SendMessage("Vous ne pouvez pas cibler cela !"); + return; + } + + Mobile targ = (Mobile)targeted; + + switch (m_Emote) + { + case EmoteList.Kiss: + from.Emote("*Tu vois {0} envoyer un baiser à {1}*", from.Name, targ.Name); + from.Animate(34, 5, 1, true, false, 1); + from.PlaySound(from.Female ? 0x320 : 0x430); + if(targ.BodyValue == 0x51 && from.Female != targ.Female) + { + targ.BodyValue = targ.Female ? 401 : 400; + targ.SendMessage("Au final, vous aurez peut-être trouvé l'amour?"); + } + break; + case EmoteList.Slap: + if (from.InRange(targ.Location, 1)) + { + from.Emote("*Tu vois {0} envoyer une baffe à {1}*", from.Name, targ.Name); + from.Animate(9, 5, 1, true, false, 1); + targ.Emote("*Tu vois {0} recevoir une baffe de {1}*", targ.Name, from.Name); + targ.Animate(20, 5, 1, true, false, 1); + targ.PlaySound(0x135); + + } + else + from.SendMessage("Vous êtes trop loin pour le frapper"); + break; + case EmoteList.Tete: + if (from.InRange(targ.Location, 1)) + { + from.Emote("*Tu vois {0} envoyer un coup de boule à {1}*", from.Name, targ.Name); + from.Animate(12, 5, 1, true, false, 1); + targ.Emote("*Tu vois {0} recevoir un coup de boule de {1}*", targ.Name, from.Name); + if (from.Direction == targ.Direction) + targ.Animate(22, 5, 1, true, false, 1); + else + targ.Animate(21, 5, 1, true, false, 1); + targ.PlaySound(0x135); + } + else + from.SendMessage("Vous êtes trop loin pour le frapper"); + break; + } + } + } + } +} diff --git a/Scripts/Vivre/Commands/ToutDeplacer.cs b/Scripts/Vivre/Commands/ToutDeplacer.cs new file mode 100644 index 0000000..aac48ba --- /dev/null +++ b/Scripts/Vivre/Commands/ToutDeplacer.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Commands; +using Server.Mobiles; + +namespace Server.Commands +{ + public class ToutDeplacer + { + public static void Initialize() + { + CommandSystem.Register("ToutDeplacer", AccessLevel.Player, new CommandEventHandler(ToutDeplacer_OnCommand)); + } + private static void ToutDeplacer_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + from.SendMessage("Pointez un item. Tous les items de m�me type seront d�plac�s."); + from.BeginTarget(-1, true, TargetFlags.None, new TargetCallback(ChooseItem_OnTarget)); + } + public static void ChooseItem_OnTarget(Mobile from, object targeted) + { + Item it = targeted as Item; + + if (it == null || !it.Movable || !(it.Parent is Container) || !(((Container)it.Parent).CheckItemUse(from, it))) + from.SendMessage("Impossible de d�placer ceci!"); + else + { + from.SendMessage("Dans quel contenant voulez vous d�poser le tout ?"); + from.BeginTarget(-1, true, TargetFlags.None, new TargetStateCallback(ChooseBag_OnTarget), it); + } + } + public static void ChooseBag_OnTarget(Mobile from, object targeted, object state) + { + Item it = state as Item; + Container c = null; + + if (targeted is Container) + { + c = targeted as Container; + + } + else if (targeted is PackHorse || targeted is PackLlama) + { + BaseCreature bc = (BaseCreature)targeted; + if (bc != null) + { + if (bc.ControlMaster == from || from.AccessLevel > AccessLevel.Player) + { + c = bc.Backpack; + } + else + { + from.SendMessage("Cet animal ne vous appartient pas!"); + return; + } + } + } + else + { + from.SendMessage("Impossible de d�placer tous ces items ici!"); + return; + } + + if (c != null) + { + Item[] items; + + if (it.Parent is Container) + { + items = ((Container)it.Parent).FindItemsByType(it.GetType(), false); + } + else + { + from.SendMessage("Impossible de d�placer un objet qui n'est pas dans un contenant!"); + return; + } + + foreach (Item item in items) + { + // Scriptiz : on ne peut pas prendre les objets non movable + if (!item.Movable) + continue; + + if (!c.TryDropItem(from, item, false)) + from.SendMessage("Impossible de d�placer tous ces items ici!"); + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/ViewStats.cs b/Scripts/Vivre/Commands/ViewStats.cs new file mode 100644 index 0000000..56ca9d2 --- /dev/null +++ b/Scripts/Vivre/Commands/ViewStats.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Misc; +using Server.Commands; + +namespace Server.Gumps +{ + public class StatsGump : Gump + { + public static void Initialize() + { + CommandSystem.Register( "stats", AccessLevel.Player, new CommandEventHandler( MyStats_OnCommand ) ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + CommandSystem.Register(command, access, handler); + } + + [Usage( "stats" )] + [Description( "Opens Stats Gump." )] + public static void MyStats_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + from.CloseGump( typeof( StatsGump ) ); + from.SendGump( new StatsGump( from ) ); + + } + + public StatsGump ( Mobile from ) : base ( 100,100 ) + { + // configuration + int LRCCap = 100; + int LMCCap = 40; + double BandageSpeedCap = 2.0; + int SwingSpeedCap = 100; + int HCICap = 75; + int DCICap = 75; + int FCCap = 6; + int FCRCap = 8; + int DamageIncreaseCap = 100; + int SDICap = 100; + int ReflectDamageCap = 100; + int SSICap = 100; + + // OSI configuration - prob the default in RUNUO + /* + int LRCCap = 100; + int LMCCap = 40; + double BandageSpeedCap = 2.0; + int SwingSpeedCap = 100; + int HCICap = 45; + int DCICap = 45; + int FCCap = 4; // FC 4 For Paladin, otherwise FC 2 for Mage + int FCRCap = 4; + int DamageIncreaseCap = 100; + int SDICap = 100; + int ReflectDamageCap = 100; + int SSICap = 100; + */ + + int LRC = AosAttributes.GetValue( from, AosAttribute.LowerRegCost ) > LRCCap ? LRCCap : AosAttributes.GetValue( from, AosAttribute.LowerRegCost ); + int LMC = AosAttributes.GetValue( from, AosAttribute.LowerManaCost ) > LMCCap ? LMCCap : AosAttributes.GetValue( from, AosAttribute.LowerManaCost ); + double BandageSpeed = ( 2.0 + (0.5 * ((double)(205 - from.Dex) / 10)) ) < BandageSpeedCap ? BandageSpeedCap : ( 2.0 + (0.5 * ((double)(205 - from.Dex) / 10)) ); + TimeSpan SwingSpeed = (from.Weapon as BaseWeapon).GetDelay(from) > TimeSpan.FromSeconds(SwingSpeedCap) ? TimeSpan.FromSeconds(SwingSpeedCap) : (from.Weapon as BaseWeapon).GetDelay(from); + int HCI = AosAttributes.GetValue( from, AosAttribute.AttackChance ) > HCICap ? HCICap : AosAttributes.GetValue( from, AosAttribute.AttackChance ); + int DCI = AosAttributes.GetValue( from, AosAttribute.DefendChance ) > DCICap ? DCICap : AosAttributes.GetValue( from, AosAttribute.DefendChance ); + int FC = AosAttributes.GetValue( from, AosAttribute.CastSpeed ) > FCCap ? FCCap : AosAttributes.GetValue( from, AosAttribute.CastSpeed ); + int FCR = AosAttributes.GetValue( from, AosAttribute.CastRecovery ) > FCRCap ? FCRCap : AosAttributes.GetValue( from, AosAttribute.CastRecovery ); + int DamageIncrease = AosAttributes.GetValue( from, AosAttribute.WeaponDamage ) > DamageIncreaseCap ? DamageIncreaseCap : AosAttributes.GetValue( from, AosAttribute.WeaponDamage ); + int SDI = AosAttributes.GetValue( from, AosAttribute.SpellDamage ) > SDICap ? SDICap : AosAttributes.GetValue( from, AosAttribute.SpellDamage ); + int ReflectDamage = AosAttributes.GetValue( from, AosAttribute.ReflectPhysical ) > ReflectDamageCap ? ReflectDamageCap : AosAttributes.GetValue( from, AosAttribute.ReflectPhysical ); + int SSI = AosAttributes.GetValue( from, AosAttribute.WeaponSpeed ) > SSICap ? SSICap : AosAttributes.GetValue( from, AosAttribute.WeaponSpeed ); + + + int hue = 1149; + AddPage( 0 ); + AddImage( 0, 0, 30500 ); //Background + AddButton( 348, 400, 247, 248, 0, GumpButtonType.Reply, 1 ); //Ok + AddLabel( 69, 400, hue, String.Format( "{0}", from.Name ) ); //Name + AddLabel( 69, 43, hue, "STATS GUMP" ); + AddImage( 150 - 10, 78, 12 ); //Model + AddImage( 150 - 10, 78, 50970, 47 ); //Robe + //AddImage( 148 - 10, 80, 50619 ); //Weapon + + AddPage( 1 ); + + AddLabel( 69, 72, hue, "Str" ); + AddLabel( 69, 132, hue, "Dex" ); + AddLabel( 69, 192, hue, "Int" ); + AddLabel( 69, 252, hue, "Fame" ); + AddLabel( 69, 312, hue, "Karma" ); + + AddImageTiled( 69, 100, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 160, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 220, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 280, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 340, 111 - 10, 20, 9264 ); + + AddLabel( 69, 100, hue, String.Format(" {0} + {1}", from.RawStr, from.Str - from.RawStr ) ); //str + AddLabel( 69, 160, hue, String.Format(" {0} + {1}", from.RawDex, from.Dex - from.RawDex ) ); //dex + AddLabel( 69, 220, hue, String.Format(" {0} + {1}", from.RawInt, from.Int - from.RawInt ) ); //int + AddLabel( 69, 280, hue, String.Format(" {0} ", from.Fame ) ); //fame + AddLabel( 69, 340, hue, String.Format(" {0} ", from.Karma ) ); //karma + + AddLabel( 190, 72, hue, "Tithing Points" ); + AddLabel( 190, 312, hue, "Kills" ); + + AddImageTiled( 190, 100, 111 - 10, 20, 9264 ); + AddImageTiled( 190, 340, 111 - 10, 20, 9264 ); + + AddLabel( 190, 100, hue, String.Format(" {0} ", from.TithingPoints) ); //tith points + AddLabel( 190, 340, hue, String.Format(" {0} ", from.Kills) ); //kills + + AddLabel( 310, 72, hue, "Lower reg cost" ); + AddLabel( 310, 132, hue, "Lower mana cost" ); + AddLabel( 310, 192, hue, "Bandage Speed" ); + AddLabel( 310, 252, hue, "Swing Speed" ); + AddLabel( 310, 308, hue, "Hit inc / Def inc" ); + + AddImageTiled( 310, 100, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 160, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 220, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 280, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 340, 111 - 10, 20, 9264 ); + + AddLabel( 310, 100, hue, String.Format(" {0} %", LRC ) ); //lrc + AddLabel( 310, 160, hue, String.Format(" {0} %", LMC ) ); //lmc +// AddLabel( 310, 220, hue, String.Format(" {0:0.0} s", BandageSpeed ); //bandage speed + AddLabel( 310, 220, hue, String.Format(" {0:0.0}s", new DateTime(TimeSpan.FromSeconds( BandageSpeed ).Ticks).ToString("s.ff") ) ); //bandage speed + AddLabel( 310, 280, hue, String.Format(" {0}s", new DateTime(SwingSpeed.Ticks).ToString("s.ff") ) ); //swing speed + AddLabel( 310, 340, hue, String.Format(" {0} / {1}", HCI, DCI ) ); //hci/dci + + AddButton( 338, 46, 5601, 5605, 0, GumpButtonType.Page, 2 ); + AddLabel( 360, 43, hue, "Next Page" ); + + AddPage( 2 ); + + AddLabel( 69, 72, hue, "Hits" ); + AddLabel( 69, 132, hue, "Stamina" ); + AddLabel( 69, 192, hue, "Mana" ); + AddLabel( 69, 252, hue, "Faster cast" ); + AddLabel( 69, 312, hue, "Faster cast recov" ); + + AddImageTiled( 69, 100, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 160, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 220, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 280, 111 - 10, 20, 9264 ); + AddImageTiled( 69, 340, 111 - 10, 20, 9264 ); + + AddLabel( 69, 100, hue, String.Format(" {0} + {1}", from.Hits - AosAttributes.GetValue( from, AosAttribute.BonusHits ), AosAttributes.GetValue( from, AosAttribute.BonusHits ) ) ); //hits + AddLabel( 69, 160, hue, String.Format(" {0} + {1}", from.Stam - AosAttributes.GetValue( from, AosAttribute.BonusStam ), AosAttributes.GetValue( from, AosAttribute.BonusStam ) ) ); //stamina + AddLabel( 69, 220, hue, String.Format(" {0} + {1}", from.Mana - AosAttributes.GetValue( from, AosAttribute.BonusMana ), AosAttributes.GetValue( from, AosAttribute.BonusMana ) ) ); //mana + AddLabel( 69, 280, hue, String.Format(" {0}", FC ) ); //fc + AddLabel( 69, 340, hue, String.Format(" {0}", FCR ) ); //fcr + + AddLabel( 190, 72, hue, "Damage Increase" ); + AddLabel( 190, 312, hue, "Spell dmg inc" ); + + AddImageTiled( 190, 100, 111 - 10, 20, 9264 ); + AddImageTiled( 190, 340, 111 - 10, 20, 9264 ); + + AddLabel( 190, 100, hue, String.Format(" {0} %", DamageIncrease ) ); //di + AddLabel( 190, 340, hue, String.Format(" {0} %", SDI ) ); //sdi + + AddLabel( 310, 72, hue, "Hits regen" ); + AddLabel( 310, 132, hue, "Stam regen" ); + AddLabel( 310, 192, hue, "Mana regen" ); + AddLabel( 310, 252, hue, "Reflect dmg" ); + AddLabel( 310, 312, hue, "Swing spd inc" ); + + AddImageTiled( 310, 100, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 160, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 220, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 280, 111 - 10, 20, 9264 ); + AddImageTiled( 310, 340, 111 - 10, 20, 9264 ); + + AddLabel( 310, 100, hue, String.Format(" {0}", AosAttributes.GetValue( from, AosAttribute.RegenHits ) ) ); //hp regen + AddLabel( 310, 160, hue, String.Format(" {0}", AosAttributes.GetValue( from, AosAttribute.RegenStam ) ) ); //s regen + AddLabel( 310, 220, hue, String.Format(" {0}", AosAttributes.GetValue( from, AosAttribute.RegenMana ) ) ); //m regen + AddLabel( 310, 280, hue, String.Format(" {0} %", ReflectDamage ) ); //reflect + AddLabel( 310, 340, hue, String.Format(" {0} %", SSI ) ); //ssi + + AddButton( 338, 46, 5603, 5607, 0, GumpButtonType.Page, 1 ); + AddLabel( 360, 43, hue, "Prev Page" ); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + Mobile from = sender.Mobile; + + switch ( info.ButtonID ) + { + case 1: + { + break; + } + } + } + } + + + +} \ No newline at end of file diff --git a/Scripts/Vivre/Commands/WebCommands.cs b/Scripts/Vivre/Commands/WebCommands.cs new file mode 100644 index 0000000..b4d6583 --- /dev/null +++ b/Scripts/Vivre/Commands/WebCommands.cs @@ -0,0 +1,60 @@ +/*************************************************************************** + * WebCommands.cs + * ------------------- + * begin : August 14, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-08-14 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using Server.Mobiles; +using Server.Items; +using Server.Commands; + +namespace Server.Commands +{ + public class WebCommands + { + // Les urls nécessaires :) + public static string SiteUrl = "http://www.vivre-uo.fr"; + public static string ForumUrl = "http://www.vivre-uo.fr/forum/"; + public static string VoteUrl = "http://www.rpg-paradize.com/?page=vote&vote=23892"; + + public static void Initialize() + { + CommandSystem.Register("site", AccessLevel.Player, new CommandEventHandler(Site_OnCommand)); + CommandSystem.Register("forum", AccessLevel.Player, new CommandEventHandler(Forum_OnCommand)); + CommandSystem.Register("vote", AccessLevel.Player, new CommandEventHandler(Vote_OnCommand)); + } + + [Usage("site")] + [Description("Ouvre une page web vers le site de Vivre.")] + public static void Site_OnCommand(CommandEventArgs e) + { + e.Mobile.LaunchBrowser(SiteUrl); + } + + [Usage("forum")] + [Description("Ouvre une page web vers le forum de Vivre.")] + public static void Forum_OnCommand(CommandEventArgs e) + { + e.Mobile.LaunchBrowser(ForumUrl); + } + + [Usage("vote")] + [Description("Ouvre une page web vers la page vous permettant de voter pour Vivre.")] + public static void Vote_OnCommand(CommandEventArgs e) + { + e.Mobile.LaunchBrowser(VoteUrl); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Context Menus/BeverageEntry.cs b/Scripts/Vivre/Context Menus/BeverageEntry.cs new file mode 100644 index 0000000..8420bce --- /dev/null +++ b/Scripts/Vivre/Context Menus/BeverageEntry.cs @@ -0,0 +1,116 @@ +using System; +using Server.Items; + +namespace Server.ContextMenus +{ + public class BeverageEntry : ContextMenuEntry + { + private Mobile m_From; + private BaseBeverage m_Beverage; + + public BeverageEntry(Mobile from, BaseBeverage beverage) + : base(10176, 1) + { + m_From = from; + m_Beverage = beverage; + } + + public override void OnClick() + { + if (m_Beverage == null || m_From == null) return; + if (m_Beverage.Deleted || !m_Beverage.Movable || !m_From.CheckAlive() || !m_Beverage.CheckItemUse(m_From)) + return; + + if (m_Beverage.Quantity > 0) + { + string typeName = ""; + int typeHue = 0; + + switch (m_Beverage.Content) + { + case BeverageType.LaitChevre: + case BeverageType.LaitBrebis: + case BeverageType.Milk: + typeName = "de lait"; + typeHue = 2050; + break; + case BeverageType.JusRaisin: + typeName = "de jus de raison"; + typeHue = 1172; + break; + case BeverageType.JusPeche: + typeName = "de jus de pêches"; + typeHue = 50; + break; + case BeverageType.JusPomme: + typeName = "de jus de pommes"; + typeHue = 50; + break; + case BeverageType.Wine: + typeName = "de vin"; + typeHue = 1172; + break; + case BeverageType.Liquor: + typeName = "de liqueur"; + typeHue = 96; + break; + case BeverageType.Cider: + typeName = "de cidre"; + typeHue = 50; + break; + case BeverageType.Ale: + case BeverageType.BiereAmbre: + case BeverageType.BiereBrune: + case BeverageType.BiereCommune: + case BeverageType.BiereEpice: + case BeverageType.BiereMiel: + case BeverageType.BiereSorciere: + case BeverageType.Kwak: + case BeverageType.MoinetteYew: + typeName = "de bière"; + typeHue = 51; + break; + default: + typeName = "d'eau"; + typeHue = 92; + break; + } + + m_From.SendMessage("Vous arrosez le sol avec le contenu de votre " + m_Beverage.Name + "."); + m_Beverage.Content = BeverageType.Water; + m_Beverage.Quantity = 0; + m_Beverage.Poison = null; + + int bloodId = Utility.Random(4650, 4); + Static water = new Static(bloodId); + water.Name = "Flaque " + typeName; + water.Hue = typeHue; + water.MoveToWorld(m_From.Location, m_From.Map); + m_From.PlaySound(0x04E); + new WateringTimer(water); + } + else + { + m_From.SendMessage("Vous ne pouvez pas arroser le sol avec quelque chose de vide..."); + } + } + + private class WateringTimer : Timer + { + Static m_Water; + + public WateringTimer(Static water) + : base(TimeSpan.FromSeconds(30)) + { + m_Water = water; + this.Start(); + } + + protected override void OnTick() + { + if(m_Water != null) + m_Water.Delete(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Book/DruidSpellBookGump.cs b/Scripts/Vivre/DuidismeVivre/Book/DruidSpellBookGump.cs new file mode 100644 index 0000000..8b00791 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Book/DruidSpellBookGump.cs @@ -0,0 +1,544 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Network; +using Server.Spells; +using Server.Spells.Druid; +using Server.Prompts; + +namespace Server.Gumps +{ + public class DruidicSpellbookGump : Gump + { + private DruidicSpellbook m_Book; + + int gth = 0x903; + private void AddBackground() + { + AddPage( 0 ); + + AddImage( 100, 10, 0x89B, 0 ); + //AddImage( 255, 10, 0x8AD, 0x48B ); + + + + // AddLabel( 140, 45, gth, "Ohm - Earth" ); + //AddLabel( 140, 60, gth, "Ess - Air" ); + // AddLabel( 140, 75, gth, "Crur - Fire" ); + //AddLabel( 140, 90, gth, "Sepa - Water" ); + //AddLabel( 140, 110, gth, "Kes - One" ); + //AddLabel( 140, 125, gth, "Sec - Whole" ); + //AddLabel( 140, 140, gth, "En - Call" ); + //AddLabel( 140, 155, gth, "Vauk - Banish" ); + //AddLabel( 140, 170, gth, "Tia - Befoul" ); + //AddLabel( 140, 185, gth, "Ante - Cleanse" ); + + } + + public bool HasSpell( Mobile from, int spellID ) + { + return ( m_Book.HasSpell( spellID ) ); + } + + + public DruidicSpellbookGump( Mobile from, DruidicSpellbook book ) : base( 150, 200 ) + { + + m_Book = book; + AddBackground(); + AddPage( 1 ); + AddLabel( 150, 17, gth, "Natural Magic" ); + int sbtn = 0x93A; + int dby = 40; + int dbpy = 40;; + AddButton( 396, 14, 0x89E, 0x89E, 17, GumpButtonType.Page, 2 ); + + if (this.HasSpell( from, 316) ) + { + AddLabel( 145, dbpy, gth, "Summon Firefly" ); + AddButton( 125, dbpy + 3, sbtn, sbtn, 16, GumpButtonType.Reply, 1 ); + dby = dby + 20; + } + if (this.HasSpell( from, 302) ) + { + AddLabel( 145, dby, gth, "Hollow Reed" ); + AddButton( 125, dby + 3, sbtn, sbtn, 2, GumpButtonType.Reply, 1 ); + dby = dby + 20; + + } + if (this.HasSpell( from, 303) ) + { + AddLabel( 145, dby, gth, "Pack Of Beasts" ); + AddButton( 125, dby + 3, sbtn, sbtn, 3, GumpButtonType.Reply, 1 ); + dby = dby + 20; + } + if (this.HasSpell( from, 304) ) + { + AddLabel( 145, dby, gth, "Spring Of Life" ); + AddButton( 125, dby + 3, sbtn, sbtn, 4, GumpButtonType.Reply, 1 ); + dby = dby + 20; + } + if (this.HasSpell( from, 305) ) + { + AddLabel( 145, dby, gth, "Grasping Roots" ); + AddButton( 125, dby + 3, sbtn, sbtn, 5, GumpButtonType.Reply, 1 ); + dby = dby + 20; + } + if (this.HasSpell( from, 306) ) + { + AddLabel( 145, dby, gth, "Blend With Forest" ); + AddButton( 125, dby + 3, sbtn, sbtn, 6, GumpButtonType.Reply, 1 ); + dby = dby + 20; + } + if (this.HasSpell( from, 307) ) + { + AddLabel( 145, dby, gth, "Swarm Of Insects" ); + AddButton( 125, dby + 3, sbtn, sbtn, 7, GumpButtonType.Reply, 1 ); + dby = dby + 20; + } + if (this.HasSpell( from, 308) ) + { + AddLabel( 145, dby, gth, "Volcanic Eruption" ); + AddButton( 125, dby + 3, sbtn, sbtn, 8, GumpButtonType.Reply, 1 ); + } + if (this.HasSpell( from, 309) ) + { + AddLabel( 315, dbpy, gth, "Summon Treefellow" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 9, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 310) ) + { + AddLabel( 315, dbpy, gth, "Stone Circle" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 10, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 311) ) + { + AddLabel( 315, dbpy, gth, "Enchanted Grove" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 11, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 312) ) + { + AddLabel( 315, dbpy, gth, "Lure Stone" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 12, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 313) ) + { + AddLabel( 315, dbpy, gth, "Nature's Passage" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 13, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 314) ) + { + AddLabel( 315, dbpy, gth, "Mushroom Gateway" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 14, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 315) ) + { + AddLabel( 315, dbpy, gth, "Restorative Soil" ); + AddButton( 295, dbpy + 3, sbtn, sbtn, 15, GumpButtonType.Reply, 1 ); + dbpy = dbpy + 20; + } + if (this.HasSpell( from, 301) ) + { + AddLabel( 315, dby, gth, "Shield Of Earth" ); + AddButton( 295, dby + 3, sbtn, sbtn, 1, GumpButtonType.Reply, 1 ); + + } + + int i = 2; + + if (this.HasSpell( from, 316) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Summon Firefly" ); + AddHtml( 130, 59, 123, 132, "Summons a tiny firefly to light the Druid's path. The Firefly is a noncombatant being.", false, false ); + AddLabel( 123, 187, gth, "Kes En Crur" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Sulfurous Ash" ); + AddLabel( 295, 77, gth, "Pumice" ); + AddLabel( 295, 167, gth, "Required Skill: 1" ); + AddLabel( 295, 187, gth, "Required Mana: 10" ); + i++; + } + + if (this.HasSpell( from, 302) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Hollow Reed" ); + AddHtml( 130, 59, 123, 132, "Increases both the strength and the intelligence of the Target.", false, false ); + AddLabel( 123, 187, gth, "Sec Crur Aeta" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Bloodmoss" ); + AddLabel( 295, 77, gth, "Mandrake Root" ); + AddLabel( 295, 97, gth, "Sulfurous Ash" ); + AddLabel( 295, 167, gth, "Required Skill: 30" ); + AddLabel( 295, 187, gth, "Required Mana: 30" ); + i++; + } + + if (this.HasSpell( from, 303) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Pack Of Beasts" ); + AddHtml( 130, 59, 123, 132, "Summons a pack of beasts to fight for the Druid. Spell length increases with skill.", false, false ); + AddLabel( 123, 187, gth, "En Sec Ohm Ess Sepa" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Bloodmoss" ); + AddLabel( 295, 77, gth, "Spider Silk" ); + AddLabel( 295, 97, gth, "Petrified Wood" ); + AddLabel( 295, 167, gth, "Required Skill: 50" ); + AddLabel( 295, 187, gth, "Required Mana: 45" ); + i++; + } + if (this.HasSpell( from, 304) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Spring Of Life" ); + AddHtml( 130, 59, 123, 132, "Creates a magical spring that heals the Druid and their party.", false, false ); + AddLabel( 123, 187, gth, "En Sepa Aete" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Spring Water" ); + AddLabel( 295, 77, gth, "Petrified Wood" ); + AddLabel( 295, 167, gth, "Required Skill: 40" ); + AddLabel( 295, 187, gth, "Required Mana: 40" ); + i++; + } + if (this.HasSpell( from, 305) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Grasping Roots" ); + AddHtml( 130, 59, 123, 132, "Summons roots from the ground to entangle a single target.", false, false ); + AddLabel( 123, 187, gth, "En Ohm Sepa Tia Kes" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Bloodmoss" ); + AddLabel( 295, 77, gth, "Spring Water" ); + AddLabel( 295, 97, gth, "Spiders Silk" ); + AddLabel( 295, 167, gth, "Required Skill: 40" ); + AddLabel( 295, 187, gth, "Required Mana: 40" ); + i++; + } + if (this.HasSpell( from, 306) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Blend With Forest" ); + AddHtml( 130, 59, 123, 132, "Makes the Druid and surrounding group seem to vanish in their surroundings. ", false, false ); + AddLabel( 123, 187, gth, "Kes Ohm" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Bloodmoss" ); + AddLabel( 295, 77, gth, "Spider Silk" ); + AddLabel( 295, 167, gth, "Required Skill: 65" ); + AddLabel( 295, 187, gth, "Required Mana: 50" ); + i++; + } + if (this.HasSpell( from, 307) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Swarm Of Insects" ); + AddHtml( 130, 59, 123, 132, "Summons a swam of insects that bite and sting the targeted enemy.", false, false ); + AddLabel( 123, 167, gth, "Es Ohm En Sec Tia" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Sulfurous Ash" ); + AddLabel( 295, 77, gth, "Bloodmoss" ); + AddLabel( 295, 97, gth, "Pumice" ); + AddLabel( 295, 167, gth, "Required Skill: 75" ); + AddLabel( 295, 187, gth, "Required Mana: 60" ); + i++; + } + if (this.HasSpell( from, 308) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Volcanic Eruption" ); + AddHtml( 130, 59, 123, 132, "A blast of molten lava bursts from the ground, hitting every enemy nearby.", false, false ); + AddLabel( 123, 187, gth, "Vauk Ohm En Tia Crur" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Sulfurous Ash" ); + AddLabel( 295, 77, gth, "Pumice" ); + AddLabel( 295, 167, gth, "Required Skill: 88" ); + AddLabel( 295, 187, gth, "Required Mana: 65" ); + i++; + } + if (this.HasSpell( from, 309) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Summon Treefellow" ); + AddHtml( 130, 59, 123, 132, "Summons a powerful woodland spirit to fight for the Druid.", false, false ); + AddLabel( 123, 187, gth, "Kes En Ohm Sepa" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Bloodmoss" ); + AddLabel( 295, 77, gth, "Spring Water" ); + AddLabel( 295, 97, gth, "Petrified Wood" ); + AddLabel( 295, 167, gth, "Required Skill: 80" ); + AddLabel( 295, 187, gth, "Required Mana: 50" ); + i++; + } + if (this.HasSpell( from, 310) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Stone Circle" ); + AddHtml( 130, 59, 123, 132, "Forms an impassable circle of stones, ideal for trapping enemies.", false, false ); + AddLabel( 123, 187, gth, "En Ess Ohm" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Petrified Wood" ); + AddLabel( 295, 77, gth, "Sulfurous Ash" ); + AddLabel( 295, 97, gth, "Spring Water" ); + AddLabel( 295, 167, gth, "Required Skill: 60" ); + AddLabel( 295, 187, gth, "Required Mana: 45" ); + i++; + } + if (this.HasSpell( from, 311) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Enchanted Grove" ); + AddHtml( 130, 59, 123, 132, "Causes a grove of magical trees to grow. All friendlies who enter the enchanted area regain health and mana.", false, false ); + AddLabel( 123, 187, gth, "En Ante Ohm Sepa" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Petrified Wood" ); + AddLabel( 295, 77, gth, "Mandrake Root" ); + AddLabel( 295, 97, gth, "Spring Water" ); + AddLabel( 295, 167, gth, "Required Skill: 75" ); + AddLabel( 295, 187, gth, "Required Mana: 60" ); + i++; + } + if (this.HasSpell( from, 312) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Lure Stone" ); + AddHtml( 130, 59, 123, 132, "Creates a magical stone that calls all nearby creatures to it.", false, false ); + AddLabel( 123, 187, gth, "En Kes Ohm Crur" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Petrified Wood" ); + AddLabel( 295, 77, gth, "Spring Water" ); + AddLabel( 295, 167, gth, "Required Skill: 25" ); + AddLabel( 295, 187, gth, "Required Mana: 30" ); + i++; + } + if (this.HasSpell( from, 313) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Nature's Passage" ); + AddHtml( 130, 59, 123, 132, "The Druid is turned into flower petals and carried on the wind to a recall rune location.", false, false ); + AddLabel( 123, 187, gth, "Kes Sec Vauk" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Pumice" ); + AddLabel( 295, 77, gth, "Bloodmoss" ); + AddLabel( 295, 97, gth, "Mandrake Root" ); + AddLabel( 295, 167, gth, "Required Skill: 25" ); + AddLabel( 295, 187, gth, "Required Mana: 10" ); + i++; + } + if (this.HasSpell( from, 314) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Mushroom Gateway" ); + AddHtml( 130, 59, 123, 132, "A magical circle of mushrooms opens, allowing the Druid and companions to step through it to a marked location.", false, false ); + AddLabel( 123, 187, gth, "Vauk Sepa Ohm" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Spider Silk" ); + AddLabel( 295, 77, gth, "Spring Water" ); + AddLabel( 295, 97, gth, "Mandrake Root" ); + AddLabel( 295, 167, gth, "Required Skill: 70" ); + AddLabel( 295, 187, gth, "Required Mana: 40" ); + i++; + } + if (this.HasSpell( from, 315) ) + { + AddPage( i ); + AddButton( 396, 14, 0x89E, 0x89E, 18, GumpButtonType.Page, i+1 ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Restorative Soil" ); + AddHtml( 130, 59, 123, 132, "Saturates a patch of land with power, causing healing mud capable of restoring life, but only lasts a few moments.", false, false ); + AddLabel( 123, 187, gth, "Ohm Sepa Ante" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Petrified Wood" ); + AddLabel( 295, 77, gth, "Bloodmoss" ); + AddLabel( 295, 97, gth, "Spring Water" ); + AddLabel( 295, 167, gth, "Required Skill: 85" ); + AddLabel( 295, 187, gth, "Required Mana: 55" ); + i++; + } + if (this.HasSpell( from, 301) ) + { + AddPage( i ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + AddLabel( 150, 37, gth, "Shield Of Earth" ); + AddHtml( 130, 59, 123, 132, "A quick-growing wall of drouse-inducing gases springs from the earth to hinder the foes of the Druid.", false, false ); + AddLabel( 123, 187, gth, "Kes En Sepa Ohm" ); + AddLabel( 295, 37, gth, "Reagents:" ); + AddLabel( 295, 57, gth, "Mandrake Root" ); + AddLabel( 295, 77, gth, "Spider Silk" ); + AddLabel( 295, 167, gth, "Required Skill: 60" ); + AddLabel( 295, 187, gth, "Required Mana: 45" ); + i++; + } + + AddPage( i ); + AddButton( 123, 15, 0x89D, 0x89D, 19, GumpButtonType.Page, i-1 ); + } + + + + + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + switch ( info.ButtonID ) + { + case 0: + { + break; + } + + case 1: + { + new ShieldOfEarthSpell( from, null ).Cast(); + break; + } + + case 2: + { + new HollowReedSpell( from, null ).Cast(); + break; + } + + case 3: + { + new PackOfBeastSpell( from, null ).Cast(); + break; + } + + case 4: + { + new SpringOfLifeSpell( from, null ).Cast(); + break; + } + + case 5: + { + new GraspingRootsSpell( from, null ).Cast(); + break; + } + + case 6: + { + new BlendWithForestSpell( from, null ).Cast(); + break; + } + + case 7: + { + new SwarmOfInsectsSpell( from, null ).Cast(); + break; + } + + case 8: + { + new VolcanicEruptionSpell( from, null ).Cast(); + break; + } + + case 9: + { + new TreefellowSpell( from, null ).Cast(); + break; + } + + case 10: + { + new StoneCircleSpell( from, null ).Cast(); + break; + } + + + case 11: + { + new EnchantedGroveSpell( from, null ).Cast(); + break; + } + + case 12: + { + new LureStoneSpell( from, null ).Cast(); + break; + } + + case 13: + { + new NaturesPassageSpell( from, null ).Cast(); + break; + } + + case 14: + { + new MushroomGatewaySpell( from, null ).Cast(); + break; + } + + case 15: + { + new RestorativeSoilSpell( from, null ).Cast(); + break; + } + + case 16: + { + new FireflySpell( from, null ).Cast(); + break; + } + + case 17: + { + from.PlaySound(0x55); + break; + } + + case 18: + { + from.PlaySound(0x55); + break; + } + + case 19: + { + from.PlaySound(0x55); + break; + } + + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Book/DruidicSpellBook.cs b/Scripts/Vivre/DuidismeVivre/Book/DruidicSpellBook.cs new file mode 100644 index 0000000..3b7dcc9 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Book/DruidicSpellBook.cs @@ -0,0 +1,67 @@ +using System; +using Server.Network; +using Server.Gumps; +using Server.Spells; +using Server.Mobiles; +//using Server.Engines.Classes; + +namespace Server.Items +{ + public class DruidicSpellbook : Spellbook + { + public override SpellbookType SpellbookType{ get{ return SpellbookType.Druidic; } } + public override int BookOffset{ get{ return 301; } } + public override int BookCount{ get{ return 16; } } + + [Constructable] + public DruidicSpellbook() : this( (ulong)0 ) + { + } + + [Constructable] + public DruidicSpellbook( ulong content ) : base( content, 0xEFA ) + { + Hue = 0x48C; + Name = "Tome of Nature"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from is PlayerMobile ) + { + PlayerMobile m = (PlayerMobile)from; + + /*if ( m.Race == null || ( m.Race != null && !( m.Race == Race.Elf ) ) ) + { + m.SendMessage( "Only elves can read from this book." ); + return; + } + + */ + if ( from.InRange( GetWorldLocation(), 1 ) ) + { + from.CloseGump( typeof( DruidicSpellbookGump ) ); + from.SendGump( new DruidicSpellbookGump( from, this ) ); + } + } + } + + public DruidicSpellbook( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Druid Mobiles/Druid.cs b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/Druid.cs new file mode 100644 index 0000000..81f6e66 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/Druid.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class Druid : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + public override NpcGuild NpcGuild { get { return NpcGuild.MagesGuild; } } + + + [Constructable] + public Druid() : base( "the druid initiate" ) + { + SetSkill( SkillName.AnimalLore, 65.0, 88.0 ); + SetSkill( SkillName.Tactics, 36.0, 68.0 ); + SetSkill( SkillName.Macing, 45.0, 68.0 ); + SetSkill( SkillName.MagicResist, 65.0, 88.0 ); + SetSkill( SkillName.Herding, 56.0, 68.0 ); + this.Race = Race.Elf; + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBDruid() ); + } + + + + + public override void InitOutfit() + { + AddItem( new Server.Items.MonksRobe( 0xB0 ) ); + AddItem( new Server.Items.WildStaff() ); + AddItem( new Server.Items.Sandals() ); + } + + public Druid( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Druid Mobiles/DruidCloak.cs b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/DruidCloak.cs new file mode 100644 index 0000000..aba23c7 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/DruidCloak.cs @@ -0,0 +1,96 @@ +using System; +using Server.Misc; + +namespace Server.Items +{ + [FlipableAttribute( 0x1515, 0x1530 )] + public class DruidCloak : Cloak + { + private SkillMod m_SkillMod0; + private SkillMod m_SkillMod1; + private SkillMod m_SkillMod2; + private StatMod m_StatMod0; + + [Constructable] + public DruidCloak() : base( 0x309 ) + { + Name = "Arch Druid Cloak"; + Hue = 2881; + DefineMods(); + } + + private void DefineMods() + { + m_SkillMod0 = new DefaultSkillMod( SkillName.AnimalLore, true, 15 ); + m_SkillMod1 = new DefaultSkillMod( SkillName.Herding, true, 15 ); + m_SkillMod2 = new DefaultSkillMod( SkillName.Tracking, true, 15 ); + m_StatMod0 = new StatMod( StatType.Int, "Arch Druid Cloak", 15, TimeSpan.Zero ); + } + + private void SetMods( Mobile wearer ) + { + wearer.AddSkillMod( m_SkillMod0 ); + wearer.AddSkillMod( m_SkillMod1 ); + wearer.AddSkillMod( m_SkillMod2 ); + wearer.AddStatMod( m_StatMod0 ); + } + + public override bool OnEquip( Mobile from ) + { + SetMods( from ); + return true; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( 1042083 ); // You can not dye that. + return false; + } + + public override void OnRemoved( object parent ) + { + if ( parent is Mobile ) + { + Mobile m = (Mobile)parent; + m.RemoveStatMod( "Arch Druid Cloak" ); + + if ( m.Hits > m.HitsMax ) + m.Hits = m.HitsMax; + + if ( m_SkillMod0 != null ) + m_SkillMod0.Remove(); + + if ( m_SkillMod1 != null ) + m_SkillMod1.Remove(); + + if ( m_SkillMod2 != null ) + m_SkillMod2.Remove(); + } + } + + public override void OnSingleClick( Mobile from ) + { + this.LabelTo( from, Name ); + } + + public DruidCloak( Serial serial ) : base( serial ) + { + DefineMods(); + + if ( Parent != null && this.Parent is Mobile ) + SetMods( (Mobile)Parent ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Druid Mobiles/Evil Druid Info.txt b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/Evil Druid Info.txt new file mode 100644 index 0000000..cc22f57 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/Evil Druid Info.txt @@ -0,0 +1,21 @@ +//created by henry_r +//12/19/07 + +//[RunUO 2.0 RC1] + +//for use with DruidSpellsSubmission by Slithers (original authors of Druid System/spells unknown) + +//contains: Evil Druid mobile with special ability *swarm of insects* +// *swarm of insects* is repelled by holding a lit torch in your hands or death +// + +//mobile drops random Druid Scrolls, random Druid reagents; small chance for Druidic Spellbook, and a smaller chance for Druid Cloak + +//installation instructions: drop Druid Mobiles folder into Druid System folder; restart server; [add evildruid + +//change or modify to suit your needs - enjoy :) + +//modified by Vindicat for RunUO 2.0 RC2 +// 21/04/08 +//Fixed the swarm of insects so it now wears out in time as intended. You no longer have to die if you are caught without a torch! +//There was no Druid Cloak when I got this so I made a powerful one that drops very rarely --- 3 in 1000 chance \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Druid Mobiles/EvilDruid.cs b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/EvilDruid.cs new file mode 100644 index 0000000..1f11548 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/EvilDruid.cs @@ -0,0 +1,255 @@ +//created by henry_r +//12/19/07 +//[RunUO 2.0 RC1] +//See .txt file for info +// +using System; +using System.Collections; +using Server; +using Server.Mobiles; +using Server.Items; +using Server.Spells; +using Server.DruidSystem; + +namespace Server.DruidSystem.Mobiles +{ + [CorpseName( "a evil druid corpse" )] + public class EvilDruid : BaseCreature + { + private static string[] m_Names = new string[] + { + "Amergin", + "Lochru", + "Senias", + "Taliesin", + "Urais", + "Marduk", + "Zamolxis" + }; + + private static string[] m_Titles = new string[] + { + "Protector of the Druids", + "Guardian of the Druids", + "Seer of the Druids", + "The Mysticical Druid", + "Master of the Druids" + }; + + [Constructable] + public EvilDruid() : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = m_Names[Utility.Random( m_Names.Length )]; + Title = m_Titles[Utility.Random( m_Titles.Length )]; + Body = 0x190; + Hue = Utility.RandomSkinHue(); + + SetStr( 90, 100 ); + SetDex( 50, 75 ); + SetInt( 150, 250 ); + SetHits( 900, 1100 ); + SetDamage( 12, 18 ); + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 50, 70 ); + SetResistance( ResistanceType.Fire, 50, 70 ); + SetResistance( ResistanceType.Cold, 50, 70 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 50, 70 ); + + SetSkill( SkillName.Herding, 95.0, 120.0 ); + SetSkill( SkillName.AnimalLore, 95.0, 120.0 ); + SetSkill( SkillName.Meditation, 95.0, 100.0 ); + SetSkill( SkillName.MagicResist, 100.0, 120.0 ); + SetSkill( SkillName.Tactics, 95.0, 120.0 ); + SetSkill( SkillName.Wrestling, 95.0, 120.0 ); + + Fame = 2000; + Karma = -10000; + + VirtualArmor = 70; + + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 2, 5 ) ); + + int hue = Utility.RandomBlueHue(); + AddItem( new Robe( hue ) ); + AddItem( new Sandals() ); + AddItem( new WizardsHat( hue ) ); + + PackGold( 400, 600 ); + + switch (Utility.Random( 16 ) ) + { + + case 0: PackItem( new BlendWithForestScroll() ); break; + case 1: PackItem( new GraspingRootsScroll() ); break; + case 2: PackItem( new MushroomCircleScroll() ); break; + case 3: PackItem( new PackOfBeastScroll() ); break; + case 4: PackItem( new SpringOfLifeScroll() ); break; + case 5: PackItem( new VolcanicEruptionScroll() ); break; + case 6: PackItem( new EnchantedGroveScroll() ); break; + case 7: PackItem( new HollowReedScroll() ); break; + case 8: PackItem( new MushroomGatewayScroll() ); break; + case 9: PackItem( new RestorativeSoilScroll() ); break; + case 10: PackItem( new SwarmOfInsectsScroll() ); break; + case 11: PackItem( new FireflyScroll() ); break; + case 12: PackItem( new LureStoneScroll() ); break; + case 13: PackItem( new NaturesPassageScroll() ); break; + case 14: PackItem( new ShieldOfEarthScroll() ); break; + case 15: PackItem( new TreefellowScroll() ); break; + + + } + + switch (Utility.Random( 3 ) ) + { + + case 0: PackItem( new PetrifiedWood ( Utility.Random( 10 ) + 3) ); break; + case 1: PackItem( new Pumice ( Utility.Random( 10 ) + 3 ) ); break; + case 2: PackItem( new SpringWater ( Utility.Random( 10 ) + 3 ) ); break; + + } + + if ( 0.003 > Utility.RandomDouble() ) + PackItem( new DruidCloak() ); + } + + public override bool CanRummageCorpses{ get{ return false; } } + public override Poison PoisonImmune{ get{ return Poison.Lethal; } } + public override bool ShowFameTitle{ get{ return false; } } + public override bool AlwaysMurderer{ get{ return true; } } + + public override bool InitialInnocent{ get{ return true; } } + + + public override int GetHurtSound() + { + return 0x156; + } + + public override int GetDeathSound() + { + return 0x15C; + } + + private DateTime m_NextAbilityTime; + + public override void OnThink() + { + if ( DateTime.Now >= m_NextAbilityTime ) + { + Mobile combatant = this.Combatant; + + if ( combatant != null && combatant.Map == this.Map && combatant.InRange( this, 12 ) && IsEnemy( combatant ) && !UnderEffect( combatant ) ) + { + m_NextAbilityTime = DateTime.Now + TimeSpan.FromSeconds( Utility.RandomMinMax( 20, 30 ) ); + + this.Say( true, "I call a swarm of insects to sting your flesh!" ); + + m_Table[combatant] = Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 7.0 ), new TimerStateCallback( DoEffect ), new object[]{ combatant, 0 } ); + } + } + + base.OnThink(); + } + + private static Hashtable m_Table = new Hashtable(); + + public static bool UnderEffect( Mobile m ) + { + return m_Table.Contains( m ); + } + + public static void StopEffect( Mobile m, bool message ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + { + if ( message ) + m.PublicOverheadMessage( Network.MessageType.Emote, m.SpeechHue, true, "* The open flame begins to scatter the swarm of insects *" ); + + t.Stop(); + m_Table.Remove( m ); + } + } + + public void DoEffect( object state ) + { + object[] states = (object[])state; + + Mobile m = (Mobile)states[0]; + int count = (int)states[1]; + + if ( !m.Alive ) + { + StopEffect( m, false ); + } + else + { + Torch torch = m.FindItemOnLayer( Layer.TwoHanded ) as Torch; + + if ( torch != null && torch.Burning ) + { + StopEffect( m, true ); + } + else + { + if ( (count % 4) == 0 ) + { + m.LocalOverheadMessage( Network.MessageType.Emote, m.SpeechHue, true, "* The swarm of insects bites and stings your flesh! *" ); + m.NonlocalOverheadMessage( Network.MessageType.Emote, m.SpeechHue, true, String.Format( "* {0} is stung by a swarm of insects *", m.Name ) ); + } + + m.FixedParticles( 0x91C, 10, 180, 9539, EffectLayer.Waist ); + m.PlaySound( 0x00E ); + m.PlaySound( 0x1BC ); + + AOS.Damage( m, this, Utility.RandomMinMax( 30, 40 ) - (Core.AOS ? 0 : 10), 100, 0, 0, 0, 0 ); + + states[1] = count + 1; + + if ( !m.Alive || Utility.Random( 20 ) >18 ) + StopEffect( m, false ); + } + } + } + + + + + public override void OnDeath( Container c ) + + { + + if ( 0.02 > Utility.RandomDouble() ) + { + + { + c.DropItem( new DruidicSpellbook() ); + + } + + } + + base.OnDeath( c ); + } + + + public EvilDruid( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Druid Mobiles/MonksRobe.cs b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/MonksRobe.cs new file mode 100644 index 0000000..f709f31 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/MonksRobe.cs @@ -0,0 +1,48 @@ +using System; +using Server; + +namespace Server.Items +{ + + public class MonksRobe : BaseOuterTorso + { + public override int LabelNumber{ get{ return 1076584; } } // A Monk's Robe + + [Constructable] + public MonksRobe() : this( 0x21E ) + { + } + + [Constructable] + public MonksRobe( int hue ) : base( 0x2683, hue ) + { + + + Weight = 1.0; + } + + public override bool Dye( Mobile from, DyeTub sender ) + { + from.SendLocalizedMessage( sender.FailMessage ); + return false; + } + + public MonksRobe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Druid Mobiles/SBDruid.cs b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/SBDruid.cs new file mode 100644 index 0000000..cae6967 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Druid Mobiles/SBDruid.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBDruid : SBInfo + { + + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + + public SBDruid() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add( new GenericBuyInfo( "Tome of Nature", typeof( DruidicSpellbook ), 350, 10, 0xEFA, 0x48C ) ); + + Add( new GenericBuyInfo( typeof( ScribesPen ), 8, 10, 0xFBF, 0 ) ); + + Add( new GenericBuyInfo( typeof( BlankScroll ), 5, 20, 0x0E34, 0 ) ); + + Add( new GenericBuyInfo( typeof( RefreshPotion ), 15, 10, 0xF0B, 0 ) ); + Add( new GenericBuyInfo( typeof( AgilityPotion ), 15, 10, 0xF08, 0 ) ); + Add( new GenericBuyInfo( typeof( NightSightPotion ), 15, 10, 0xF06, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserHealPotion ), 15, 10, 0xF0C, 0 ) ); + Add( new GenericBuyInfo( typeof( StrengthPotion ), 15, 10, 0xF09, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserPoisonPotion ), 15, 10, 0xF0A, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserCurePotion ), 15, 10, 0xF07, 0 ) ); + Add( new GenericBuyInfo( typeof( LesserExplosionPotion ), 21, 10, 0xF0D, 0 ) ); + + Add( new GenericBuyInfo( "Petrified Wood", typeof( PetrifiedWood ), 5, 20, 0x97A, 0 ) ); + Add( new GenericBuyInfo( typeof( Bloodmoss ), 5, 20, 0xF7B, 0 ) ); + Add( new GenericBuyInfo( "Spring Water", typeof( SpringWater ), 3, 20, 0xE24, 0 ) ); + Add( new GenericBuyInfo( "Pumice", typeof( Pumice ), 5, 20, 0xF8B, 0 ) ); + Add( new GenericBuyInfo( typeof( MandrakeRoot ), 3, 20, 0xF86, 0 ) ); + Add( new GenericBuyInfo( typeof( SpidersSilk ), 3, 20, 0xF8D, 0 ) ); + Add( new GenericBuyInfo( typeof( SulfurousAsh ), 3, 20, 0xF8C, 0 ) ); + Add( new GenericBuyInfo( "Summon Firefly Scroll", typeof( FireflyScroll ), 22, 20, 0xE39, 0x58B ) ); + Add( new GenericBuyInfo( "Lure Stone Scroll", typeof( LureStoneScroll ), 63, 20, 0xE39, 0x58B ) ); + Add( new GenericBuyInfo( "Nature's Passage Scroll", typeof( NaturesPassageScroll ), 63, 20, 0xE39, 0x58B ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( WizardsHat ), 15 ); + Add( typeof( PetrifiedWood ), 3 ); + Add( typeof( Bloodmoss ),4 ); + Add( typeof( MandrakeRoot ), 2 ); + Add( typeof( SpringWater ), 2 ); + Add( typeof( Pumice ), 2 ); + Add( typeof( SpidersSilk ), 2 ); + Add( typeof( SulfurousAsh ), 2 ); + Add( typeof( DruidicSpellbook ), 25 ); + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Extras/SleepingBody.cs b/Scripts/Vivre/DuidismeVivre/Extras/SleepingBody.cs new file mode 100644 index 0000000..d1acc57 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Extras/SleepingBody.cs @@ -0,0 +1,276 @@ +using System; +using System.Collections; +using Server; +using Server.Engines.PartySystem; +using Server.Misc; +using Server.Guilds; +using Server.Mobiles; +using Server.Network; +using Server.ContextMenus; + +namespace Server.Items +{ + public class SleepingBody : Container + { + private Mobile m_Owner; + private string m_SleepingBodyName; // Value of the SleepingNameAttribute attached to the owner when he died -or- null if the owner had no SleepingBodyNameAttribute; use "the remains of ~name~" + private bool m_Blessed; + + private ArrayList m_EquipItems; // List of items equiped when the owner died. Ingame, these items display /on/ the SleepingBody, not just inside + private bool m_spell; + private DateTime m_NextSnoreTrigger; + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Owner + { + get{ return m_Owner; } + } + + public ArrayList EquipItems + { + get{ return m_EquipItems; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Invuln + { + get{ return m_Blessed; } + } + + [Constructable] + public SleepingBody( Mobile owner, bool blessed ) : this( owner, blessed, true ) + { + } + + [Constructable] + public SleepingBody( Mobile owner, bool blessed, bool isSpell ) : base( 0x2006 ) + { + Stackable = true; // To supress console warnings, stackable must be true + Amount = owner.Body; // protocol defines that for itemid 0x2006, amount=body + Stackable = false; + m_Blessed = blessed; + Movable = false; + + m_Owner = owner; + Name = m_Owner.Name; + m_SleepingBodyName = GetBodyName( owner ); + Hue = m_Owner.Hue; + Direction = m_Owner.Direction; + m_spell = isSpell; + + m_EquipItems = new ArrayList(); + AddFromLayer( m_Owner, Layer.FirstValid, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.TwoHanded, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Shoes, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Pants, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Shirt, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Helm, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Gloves, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Ring, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Neck, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Hair, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Waist, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.InnerTorso, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Bracelet, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.FacialHair, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.MiddleTorso, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Earrings, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Arms, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.Cloak, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.OuterTorso, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.OuterLegs, ref m_EquipItems ); + AddFromLayer( m_Owner, Layer.LastUserValid, ref m_EquipItems ); + + + } + + private void AddFromLayer( Mobile from, Layer layer, ref ArrayList list ) + { + if( list == null ) + list = new ArrayList(); + + Item worn = from.FindItemOnLayer( layer ); + if ( worn != null ) + { + Item item = new Item(); + item.ItemID = worn.ItemID; + item.Hue = worn.Hue; + item.Layer = layer; + DropItem( item ); + list.Add( item ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendLocalizedMessage( 1001018 ); // You cannot perform negative acts on your target. + } +public override bool HandlesOnMovement{ get{ return true; } } // Tell the core that we implement OnMovement + + public override bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + from.SendLocalizedMessage( 1005468, "", 0x8A5 ); // Me Sleepy. + + return false; + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + from.SendLocalizedMessage( 1005468, "", 0x8A5 ); // Me Sleepy. + + return false; + } + + public override bool CheckContentDisplay( Mobile from ) + { + return false; + } + + public override bool DisplaysContent{ get{ return false; } } + + public override void OnAfterDelete() + { + + + + if( m_Owner != null ) + { + m_Owner.Z = this.Z; + m_Owner.Blessed = this.m_Blessed; + } + + for( int i = 0; i < m_EquipItems.Count; i++ ) + { + object o = m_EquipItems[i]; + if( o != null && o is Item ) + { + Item item = (Item)o; + item.Delete(); + } + } + + base.OnAfterDelete(); + } + + public SleepingBody( Serial serial ) : base( serial ) + { + } + + //public override void SendInfoTo( NetState state ) + //{ + //base.SendInfoTo( state ); + public override void SendInfoTo( NetState state, bool sendOplPacket ) + { + base.SendInfoTo( state, sendOplPacket ); + if ( ItemID == 0x2006 ) + { + state.Send( new SleepingBodyContent( state.Mobile, this ) ); + state.Send( new SleepingBodyEquip( state.Mobile, this ) ); + } + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + if ( m_SleepingBodyName != null ) + list.Add( m_SleepingBodyName ); + else + list.Add( 1049644, String.Format( "Sleeping {0}", Name ) ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, m_SleepingBodyName == null ? String.Format( "Sleeping {0}", Name ) : m_SleepingBodyName ); + } + + public static string GetBodyName( Mobile m ) + { + Type t = m.GetType(); + + object[] attrs = t.GetCustomAttributes( typeof( SleepingNameAttribute ), true ); + + if ( attrs != null && attrs.Length > 0 ) + { + SleepingNameAttribute attr = attrs[0] as SleepingNameAttribute; + + if ( attr != null ) + return attr.Name; + } + + return m.Name; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.Write(m_spell); // version 1 + + writer.Write(m_Owner); // version 0 + writer.Write(m_SleepingBodyName); + writer.Write(m_Blessed); + + writer.WriteItemList( m_EquipItems, true ); + } + + public override void Deserialize( GenericReader reader ) + { + m_spell = true; + base.Deserialize( reader ); + + int version = reader.ReadInt(); + switch( version ) + { + case 1: + { + m_spell = reader.ReadBool(); + goto case 0; + } + case 0: + { + m_Owner = reader.ReadMobile(); + m_SleepingBodyName = reader.ReadString(); + m_Blessed = reader.ReadBool(); + + m_EquipItems = reader.ReadItemList(); + break; + } + } + m_NextSnoreTrigger = DateTime.Now; + + // Delete on Server restart if spell action + if( m_spell ) + this.Delete(); + } + public bool CheckRange( Point3D loc, Point3D oldLoc, int range ) + { + return CheckRange( loc, range ) && !CheckRange( oldLoc, range ); + } + + public bool CheckRange( Point3D loc, int range ) + { + return ( (this.Z + 8) >= loc.Z && (loc.Z + 16) > this.Z ) + && Utility.InRange( GetWorldLocation(), loc, range ); + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + base.OnMovement( m, oldLocation ); + + if ( m.Location == oldLocation ) + return; + + if ( CheckRange( m.Location, oldLocation, 5 ) && DateTime.Now >= m_NextSnoreTrigger ) + { + m_NextSnoreTrigger = DateTime.Now + TimeSpan.FromSeconds(Utility.Random(5,10)); + + if(this != null&&this.Owner!=null) + { + this.PublicOverheadMessage(0,Owner.SpeechHue,false,"zZz"); + Owner.PlaySound( Owner.Female ? 819 : 1093); + } + } + } + + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Extras/SleepingBodyEquip.cs b/Scripts/Vivre/DuidismeVivre/Extras/SleepingBodyEquip.cs new file mode 100644 index 0000000..b0d13df --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Extras/SleepingBodyEquip.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.Network +{ + public sealed class SleepingBodyEquip : Packet + { + public SleepingBodyEquip( Mobile beholder, SleepingBody beheld ) : base( 0x89 ) + { + ArrayList list = beheld.EquipItems; + + EnsureCapacity( 8 + (list.Count * 5) ); + + m_Stream.Write( (int) beheld.Serial ); + + for ( int i = 0; i < list.Count; ++i ) + { + Item item = (Item)list[i]; + + if ( !item.Deleted && beholder.CanSee( item ) && item.Parent == beheld ) + { + m_Stream.Write( (byte) (item.Layer + 1) ); + m_Stream.Write( (int) item.Serial ); + } + } + + m_Stream.Write( (byte) Layer.Invalid ); + } + } + public sealed class SleepingBodyContent : Packet + { + public SleepingBodyContent( Mobile beholder, SleepingBody beheld ) : base( 0x3C ) + { + ArrayList items = beheld.EquipItems; + int count = items.Count; + + EnsureCapacity( 5 + (count * 19) ); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write( (ushort) 0 ); + + for ( int i = 0; i < count; ++i ) + { + Item child = (Item)items[i]; + + if ( !child.Deleted && child.Parent == beheld && beholder.CanSee( child ) ) + { + m_Stream.Write( (int) child.Serial ); + m_Stream.Write( (ushort) child.ItemID ); + m_Stream.Write( (byte) 0 ); // signed, itemID offset + m_Stream.Write( (ushort) child.Amount ); + m_Stream.Write( (short) child.X ); + m_Stream.Write( (short) child.Y ); + m_Stream.Write( (int) beheld.Serial ); + m_Stream.Write( (ushort) child.Hue ); + + ++written; + } + } + + m_Stream.Seek( pos, SeekOrigin.Begin ); + m_Stream.Write( (ushort) written ); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Extras/SleepingNameAttribute.cs b/Scripts/Vivre/DuidismeVivre/Extras/SleepingNameAttribute.cs new file mode 100644 index 0000000..3ffe204 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Extras/SleepingNameAttribute.cs @@ -0,0 +1,20 @@ +using System; + +namespace Server +{ + [AttributeUsage( AttributeTargets.Class )] + public class SleepingNameAttribute : Attribute + { + private string m_Name; + + public string Name + { + get{ return m_Name; } + } + + public SleepingNameAttribute( string name ) + { + m_Name = name; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Reagents/BagOfDruidReagents.cs b/Scripts/Vivre/DuidismeVivre/Reagents/BagOfDruidReagents.cs new file mode 100644 index 0000000..5de7777 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Reagents/BagOfDruidReagents.cs @@ -0,0 +1,50 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BagOfDruidReagents : Bag + { + + [Constructable] + public BagOfDruidReagents() : this( 1 ) + { + Movable = true; + Hue = 0x48C; + Name = "bag of druid reagents"; + } + + [Constructable] + public BagOfDruidReagents( int amount ) + { + DropItem( new Bloodmoss ( 100 ) ); + DropItem( new MandrakeRoot ( 100 ) ); + DropItem( new SulfurousAsh ( 100 ) ); + DropItem( new SpidersSilk ( 100 ) ); + DropItem( new PetrifiedWood ( 100 ) ); + DropItem( new Pumice ( 100 ) ); + DropItem( new SpringWater ( 100 ) ); + } + + public BagOfDruidReagents( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + + diff --git a/Scripts/Vivre/DuidismeVivre/Reagents/PetrifiedWood.cs b/Scripts/Vivre/DuidismeVivre/Reagents/PetrifiedWood.cs new file mode 100644 index 0000000..e5f29c0 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Reagents/PetrifiedWood.cs @@ -0,0 +1,45 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PetrifiedWood : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + + [Constructable] + public PetrifiedWood() : this( 1 ) + { + } + + [Constructable] + public PetrifiedWood( int amount ) : base( 0x97A, amount ) + { + Hue = 0x46C; + Name = "petrified wood"; + } + + public PetrifiedWood( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + if (version==0) + this.ItemID=3984; + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Reagents/Pumice.cs b/Scripts/Vivre/DuidismeVivre/Reagents/Pumice.cs new file mode 100644 index 0000000..e87da45 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Reagents/Pumice.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Pumice : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Pumice() : this( 1 ) + { + } + + [Constructable] + public Pumice( int amount ) : base( 3979, amount ) + { + } + + public Pumice( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/DuidismeVivre/Reagents/SpringWater.cs b/Scripts/Vivre/DuidismeVivre/Reagents/SpringWater.cs new file mode 100644 index 0000000..3d9885f --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Reagents/SpringWater.cs @@ -0,0 +1,43 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SpringWater : BaseReagent, ICommodity + { + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + + [Constructable] + public SpringWater() : this( 1 ) + { + } + + [Constructable] + public SpringWater( int amount ) : base( 0xE24, amount ) + { + Hue = 0x47F; + Name = "spring water"; + } + + public SpringWater( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/BlendWithForrestScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/BlendWithForrestScroll.cs new file mode 100644 index 0000000..a2dca56 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/BlendWithForrestScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BlendWithForestScroll : SpellScroll + { + [Constructable] + public BlendWithForestScroll() : this( 1 ) + { + } + + [Constructable] + public BlendWithForestScroll( int amount ) : base( 306, 0xE39 ) + { + Name = "Blend With Forest"; + Hue = 0x58B; + } + + public BlendWithForestScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/EnchantedGroveScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/EnchantedGroveScroll.cs new file mode 100644 index 0000000..aa45ba9 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/EnchantedGroveScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EnchantedGroveScroll : SpellScroll + { + [Constructable] + public EnchantedGroveScroll() : this( 1 ) + { + } + + [Constructable] + public EnchantedGroveScroll( int amount ) : base( 311, 0xE39 ) + { + Name = "Enchanted Grove"; + Hue = 0x58B; + } + + public EnchantedGroveScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/FireflyScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/FireflyScroll.cs new file mode 100644 index 0000000..528895c --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/FireflyScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class FireflyScroll : SpellScroll + { + [Constructable] + public FireflyScroll() : this( 1 ) + { + } + + [Constructable] + public FireflyScroll( int amount ) : base( 316, 0xE39 ) + { + Name = "Summon Firefly"; + Hue = 0x58B; + } + + public FireflyScroll( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/GraspingRootsScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/GraspingRootsScroll.cs new file mode 100644 index 0000000..3839cb3 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/GraspingRootsScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class GraspingRootsScroll : SpellScroll + { + [Constructable] + public GraspingRootsScroll() : this( 1 ) + { + } + + [Constructable] + public GraspingRootsScroll( int amount ) : base( 305, 0xE39 ) + { + Name = "Grasping Roots"; + Hue = 0x58B; + } + + public GraspingRootsScroll( Serial serial ) : base( serial ) + { + Name = "Grasping Roots"; + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/HollowReedScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/HollowReedScroll.cs new file mode 100644 index 0000000..b3320ac --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/HollowReedScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class HollowReedScroll : SpellScroll + { + [Constructable] + public HollowReedScroll() : this( 1 ) + { + } + + [Constructable] + public HollowReedScroll( int amount ) : base( 302, 0xE39 ) + { + Name = "Hollow Reed"; + Hue = 0x58B; + } + + public HollowReedScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/LureStoneScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/LureStoneScroll.cs new file mode 100644 index 0000000..42b357a --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/LureStoneScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class LureStoneScroll : SpellScroll + { + [Constructable] + public LureStoneScroll() : this( 1 ) + { + } + + [Constructable] + public LureStoneScroll( int amount ) : base( 312, 0xE39 ) + { + Name = "Lure Stone"; + Hue = 0x58B; + } + + public LureStoneScroll( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/MushroomCircleScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/MushroomCircleScroll.cs new file mode 100644 index 0000000..cce15dc --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/MushroomCircleScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MushroomCircleScroll : SpellScroll + { + [Constructable] + public MushroomCircleScroll() : this( 1 ) + { + } + + [Constructable] + public MushroomCircleScroll( int amount ) : base( 310, 0xE39 ) + { + Name = "Stone Circle"; + Hue = 0x58B; + } + + public MushroomCircleScroll( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/MushroomGatewayScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/MushroomGatewayScroll.cs new file mode 100644 index 0000000..99b79e9 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/MushroomGatewayScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MushroomGatewayScroll : SpellScroll + { + [Constructable] + public MushroomGatewayScroll() : this( 1 ) + { + } + + [Constructable] + public MushroomGatewayScroll( int amount ) : base( 314, 0xE39 ) + { + Name = "Mushroom Gateway"; + Hue = 0x58B; + } + + public MushroomGatewayScroll( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/NaturesPassageScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/NaturesPassageScroll.cs new file mode 100644 index 0000000..98226a2 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/NaturesPassageScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class NaturesPassageScroll : SpellScroll + { + [Constructable] + public NaturesPassageScroll() : this( 1 ) + { + } + + [Constructable] + public NaturesPassageScroll( int amount ) : base( 313, 0xE39 ) + { + Name = "Nature's Passage"; + Hue = 0x58B; + } + + public NaturesPassageScroll( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/PackofBeastScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/PackofBeastScroll.cs new file mode 100644 index 0000000..2ee1511 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/PackofBeastScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PackOfBeastScroll : SpellScroll + { + [Constructable] + public PackOfBeastScroll() : this( 1 ) + { + } + + [Constructable] + public PackOfBeastScroll( int amount ) : base( 303, 0xE39 ) + { + Name = "Pack Of Beast"; + Hue = 0x58B; + } + + public PackOfBeastScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/RestorativeSoilScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/RestorativeSoilScroll.cs new file mode 100644 index 0000000..934db17 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/RestorativeSoilScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class RestorativeSoilScroll : SpellScroll + { + [Constructable] + public RestorativeSoilScroll() : this( 1 ) + { + } + + [Constructable] + public RestorativeSoilScroll( int amount ) : base( 315, 0xE39 ) + { + Name = "Restorative Soil"; + Hue = 0x58B; + } + + public RestorativeSoilScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/ShieldOfEarthScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/ShieldOfEarthScroll.cs new file mode 100644 index 0000000..0bec919 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/ShieldOfEarthScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ShieldOfEarthScroll : SpellScroll + { + [Constructable] + public ShieldOfEarthScroll() : this( 1 ) + { + } + + [Constructable] + public ShieldOfEarthScroll( int amount ) : base( 301, 0xE39 ) + { + Name = "Shield Of Earth"; + Hue = 0x58B; + } + + public ShieldOfEarthScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/SpringOfLifeScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/SpringOfLifeScroll.cs new file mode 100644 index 0000000..39c9610 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/SpringOfLifeScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SpringOfLifeScroll : SpellScroll + { + [Constructable] + public SpringOfLifeScroll() : this( 1 ) + { + } + + [Constructable] + public SpringOfLifeScroll( int amount ) : base( 304, 0xE39 ) + { + Name = "Spring Of Life"; + Hue = 0x58B; + } + + public SpringOfLifeScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/SwarmOfInsectScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/SwarmOfInsectScroll.cs new file mode 100644 index 0000000..fb3b534 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/SwarmOfInsectScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SwarmOfInsectsScroll : SpellScroll + { + [Constructable] + public SwarmOfInsectsScroll() : this( 1 ) + { + } + + [Constructable] + public SwarmOfInsectsScroll( int amount ) : base( 307, 0xE39 ) + { + Name = "Swarm Of Insects"; + Hue = 0x58B; + } + + public SwarmOfInsectsScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/TreefellowScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/TreefellowScroll.cs new file mode 100644 index 0000000..f335e42 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/TreefellowScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class TreefellowScroll : SpellScroll + { + [Constructable] + public TreefellowScroll() : this( 1 ) + { + } + + [Constructable] + public TreefellowScroll( int amount ) : base( 309, 0xE39 ) + { + Name = "Summon Treefellow"; + Hue = 0x58B; + } + + public TreefellowScroll( Serial serial ) : base( serial ) + { + + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Scrolls/VolcanicEruptionScroll.cs b/Scripts/Vivre/DuidismeVivre/Scrolls/VolcanicEruptionScroll.cs new file mode 100644 index 0000000..5b8f488 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Scrolls/VolcanicEruptionScroll.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class VolcanicEruptionScroll : SpellScroll + { + [Constructable] + public VolcanicEruptionScroll() : this( 1 ) + { + } + + [Constructable] + public VolcanicEruptionScroll( int amount ) : base( 308, 0xE39 ) + { + Name = "Volcanic Eruption"; + Hue = 0x58B; + } + + public VolcanicEruptionScroll( Serial serial ) : base( serial ) + { + ItemID=0xE39; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/BlendWithForrestSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/BlendWithForrestSpell.cs new file mode 100644 index 0000000..657ab4c --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/BlendWithForrestSpell.cs @@ -0,0 +1,150 @@ +using System; +using Server.Targeting; +using System.Collections; +using Server.Network; +using Server.Misc; +using Server.Items; + +namespace Server.Spells.Druid +{ + public class BlendWithForestSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Blend With Forest", "Kes Ohm", + //SpellCircle.Sixth, + 206, + 9002, + false, + Reagent.Bloodmoss, + Reagent.Nightshade + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + public override double RequiredSkill{ get{ return 65.0; } } + public override int RequiredMana{ get{ return 50; } } + private bool speak; + + public BlendWithForestSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckSequence() ) + { + if(this.Scroll!=null) + Scroll.Consume(); + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + ArrayList targets = new ArrayList(); + + Map map = Caster.Map; + + if ( map != null ) + { + IPooledEnumerable eable = map.GetMobilesInRange( new Point3D( p ), 3 ); + + foreach ( Mobile m in eable ) + { + if ( Caster.CanBeBeneficial( m, false ) ) + targets.Add( m ); + } + + eable.Free(); + } + + + if ( targets.Count > 0 ) + { + + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + Caster.DoBeneficial( m ); + + Effects.SendLocationParticles( EffectItem.Create( new Point3D( m.X, m.Y, m.Z + 16 ), Caster.Map, EffectItem.DefaultDuration ), 0x376A, 10, 15, 5045 ); + m.PlaySound( 0x3C4 ); + + m.Hidden = true; + + RemoveTimer( m ); + + TimeSpan duration = TimeSpan.FromSeconds( Caster.Skills[SkillName.Spellweaving].Value * 1.2 ); + + Timer t = new InternalTimer( m, duration ); + + m_Table[m] = t; + + t.Start(); + } + } + } + + FinishSequence(); + } + private static Hashtable m_Table = new Hashtable(); + + public static void RemoveTimer( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + { + t.Stop(); + m_Table.Remove( m ); + } + } + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + + public InternalTimer( Mobile m, TimeSpan duration ) : base( duration ) + { + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.RevealingAction(); + RemoveTimer( m_Mobile ); + } + } + private class InternalTarget : Target + { + private BlendWithForestSpell m_Owner; + + public InternalTarget( BlendWithForestSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/BlendWithForrestSpell.old b/Scripts/Vivre/DuidismeVivre/Spells/BlendWithForrestSpell.old new file mode 100644 index 0000000..9f65edf --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/BlendWithForrestSpell.old @@ -0,0 +1,184 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; + +namespace Server.Spells.Druid +{ + public class BlendWithForestSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Blend With Forest", "Kes Ohm", + //SpellCircle.Sixth, + 206, + 9002, + false, + Reagent.Bloodmoss, + Reagent.Nightshade + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + public override double RequiredSkill{ get{ return 75.0; } } + public override int RequiredMana{ get{ return 60; } } + private bool speak; + + public BlendWithForestSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + speak=m.Squelched; + + m.PlaySound( 0x19 ); + m.Paralyze( TimeSpan.FromSeconds( 20.0 ) ); + m.FixedParticles( 0x375A, 2, 10, 5027, 0x3D, 2, EffectLayer.Waist ); + m.Hidden = true; + m.Squelched = true; + + { + Point3D loc = new Point3D( m.X, m.Y, m.Z ); + + Item item = new InternalItem( loc, Caster.Map, Caster,m , speak ); + + } + + + } + + FinishSequence(); + } + + //[DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Owner; + private bool squeltched; + + //public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, Mobile caster, Mobile m, bool talk ) : base( 0xC9E ) + + { + Visible = false; + Movable = false; + m_Owner=m; + squeltched=talk; + + MoveToWorld( loc, map ); + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 20.0 ), m_Owner, squeltched ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + writer.Write(m_Owner); + writer.Write(squeltched); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + m_Owner = reader.ReadMobile(); + squeltched=reader.ReadBool(); + if(m_Owner!=null) + { + m_Owner.Hidden=false; + m_Owner.Squelched=squeltched; + } + this.Delete(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + if(m_Owner!=null) + m_Owner.Squelched=squeltched; + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + private Mobile m_Owner; + private bool speak; + + public InternalTimer( InternalItem item, TimeSpan duration, Mobile caster, bool talk ) : base( duration ) + { + m_Item = item; + m_Owner=caster; + speak=talk; + } + + protected override void OnTick() + { + m_Item.Delete(); + m_Owner.Squelched=speak; + m_Owner.Hidden=false; + } + } + } + + private class InternalTarget : Target + { + private BlendWithForestSpell m_Owner; + + public InternalTarget( BlendWithForestSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/DruidicSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/DruidicSpell.cs new file mode 100644 index 0000000..6f559bc --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/DruidicSpell.cs @@ -0,0 +1,67 @@ +using System; +using Server; + +namespace Server.Spells.Druid +{ + public abstract class DruidicSpell : Spell + { + public abstract SpellCircle Circle { get; } + public abstract double RequiredSkill{ get; } + public abstract int RequiredMana{ get; } + + public override SkillName CastSkill{ get{ return SkillName.Spellweaving; } } + public override SkillName DamageSkill{ get{ return SkillName.Herding; } } + + public override bool ClearHandsOnCast{ get{ return false; } } + + public DruidicSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info ) + { + } + + public override void GetCastSkills( out double min, out double max ) + { + min = RequiredSkill; + max = RequiredSkill + 30.0; + } + + public override int GetMana() + { + return RequiredMana; + } +public virtual bool CheckResisted( Mobile target ) + { + double n = GetResistPercent( target ); + + n /= 100.0; + + if( n <= 0.0 ) + return false; + + if( n >= 1.0 ) + return true; + + int maxSkill = (1 + (int)Circle) * 10; + maxSkill += (1 + ((int)Circle / 6)) * 25; + + if( target.Skills[SkillName.MagicResist].Value < maxSkill ) + target.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); + + return (n >= Utility.RandomDouble()); + } + public virtual double GetResistPercentForCircle( Mobile target, SpellCircle circle ) + { + double firstPercent = target.Skills[SkillName.MagicResist].Value / 5.0; + double secondPercent = target.Skills[SkillName.MagicResist].Value - (((Caster.Skills[CastSkill].Value - 20.0) / 5.0) + (1 + (int)circle) * 5.0); + + return (firstPercent > secondPercent ? firstPercent : secondPercent) / 2.0; // Seems should be about half of what stratics says. + } + public virtual double GetResistPercent( Mobile target ) + { + return GetResistPercentForCircle( target, Circle ); + } + /*public override TimeSpan GetCastDelay() + { + return TimeSpan.FromSeconds( CastDelay ); + }*/ + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/EnchantedGrove.cs b/Scripts/Vivre/DuidismeVivre/Spells/EnchantedGrove.cs new file mode 100644 index 0000000..2ce2692 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/EnchantedGrove.cs @@ -0,0 +1,386 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using System.Collections; +using Server.Mobiles; + +namespace Server.Spells.Druid +{ + public class EnchantedGroveSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Enchanted Grove", "En Ante Ohm Sepa", + // SpellCircle.Eighth, + 266, + 9040, + false, + Reagent.MandrakeRoot, + Reagent.PetrifiedWood, + Reagent.SpringWater + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + public override double RequiredSkill{ get{ return 75.0; } } + public override int RequiredMana{ get{ return 60; } } + + + + public EnchantedGroveSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + + + + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( /*SpellHelper.CheckTown( p, Caster ) &&*/ CheckSequence() ) + { + if(this.Scroll!=null) + Scroll.Consume(); + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + + Effects.PlaySound( p, Caster.Map, 0x2 ); + + + Point3D loc = new Point3D( p.X, p.Y, p.Z ); + int grovex; + int grovey; + int grovez; + InternalItem groveStone = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X; + grovey=loc.Y; + grovez=loc.Z; + groveStone.ItemID=0x08E3; + groveStone.Name="sacred stone"; + Point3D stonexyz = new Point3D(grovex,grovey,grovez); + groveStone.MoveToWorld( stonexyz, Caster.Map ); + + InternalItem grovea = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X-2; + grovey=loc.Y-2; + grovez=loc.Z; + grovea.ItemID=3290; + Point3D grovexyz = new Point3D(grovex,grovey,grovez); + grovea.MoveToWorld( grovexyz, Caster.Map ); + + InternalItem grovec = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X; + grovey=loc.Y-3; + grovez=loc.Z; + grovec.ItemID=3293; + Point3D grovexyzb = new Point3D(grovex,grovey,grovez); + grovec.MoveToWorld( grovexyzb, Caster.Map ); + +InternalItem groved = new InternalItem( Caster.Location, Caster.Map, Caster ); + groved.ItemID=3290; + grovex=loc.X+2; + grovey=loc.Y-2; + grovez=loc.Z; + Point3D grovexyzc = new Point3D(grovex,grovey,grovez); + groved.MoveToWorld( grovexyzc, Caster.Map ); +InternalItem grovee = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X+3; + grovee.ItemID=3290; + grovey=loc.Y; + grovez=loc.Z; + Point3D grovexyzd = new Point3D(grovex,grovey,grovez); + grovee.MoveToWorld( grovexyzd, Caster.Map ); +InternalItem grovef = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovef.ItemID=3293; + grovex=loc.X+2; + grovey=loc.Y+2; + grovez=loc.Z; + Point3D grovexyze = new Point3D(grovex,grovey,grovez); + grovef.MoveToWorld( grovexyze, Caster.Map ); +InternalItem groveg = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X; + groveg.ItemID=3290; + grovey=loc.Y+3; + grovez=loc.Z; + Point3D grovexyzf = new Point3D(grovex,grovey,grovez); + groveg.MoveToWorld( grovexyzf, Caster.Map ); + InternalItem groveh = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X-2; + groveh.ItemID=3293; + grovey=loc.Y+2; + grovez=loc.Z; + Point3D grovexyzg = new Point3D(grovex,grovey,grovez); + groveh.MoveToWorld( grovexyzg, Caster.Map ); + InternalItem grovei = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X-3; + grovei.ItemID=3293; + grovey=loc.Y; + grovez=loc.Z; + Point3D grovexyzh = new Point3D(grovex,grovey,grovez); + grovei.MoveToWorld( grovexyzh, Caster.Map ); + InternalItem leavesa = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X-2; + grovey=loc.Y-2; + grovez=loc.Z; + leavesa.ItemID=3291; + Point3D leafxyz = new Point3D(grovex,grovey,grovez); + leavesa.MoveToWorld( leafxyz, Caster.Map ); + + InternalItem leavesc = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X; + grovey=loc.Y-3; + grovez=loc.Z; + leavesc.ItemID=3294; + Point3D leafxyzb = new Point3D(grovex,grovey,grovez); + leavesc.MoveToWorld( leafxyzb, Caster.Map ); + +InternalItem leavesd = new InternalItem( Caster.Location, Caster.Map, Caster ); + leavesd.ItemID=3291; + grovex=loc.X+2; + grovey=loc.Y-2; + grovez=loc.Z; + Point3D leafxyzc = new Point3D(grovex,grovey,grovez); + leavesd.MoveToWorld( leafxyzc, Caster.Map ); +InternalItem leavese = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X+3; + leavese.ItemID=3291; + grovey=loc.Y; + grovez=loc.Z; + Point3D leafxyzd = new Point3D(grovex,grovey,grovez); + leavese.MoveToWorld( leafxyzd, Caster.Map ); +InternalItem leavesf = new InternalItem( Caster.Location, Caster.Map, Caster ); + leavesf.ItemID=3294; + grovex=loc.X+2; + grovey=loc.Y+2; + grovez=loc.Z; + Point3D leafxyze = new Point3D(grovex,grovey,grovez); + leavesf.MoveToWorld( leafxyze, Caster.Map ); +InternalItem leavesg = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X; + leavesg.ItemID=3291; + grovey=loc.Y+3; + grovez=loc.Z; + Point3D leafxyzf = new Point3D(grovex,grovey,grovez); + leavesg.MoveToWorld( leafxyzf, Caster.Map ); + InternalItem leavesh = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X-2; + leavesh.ItemID=3294; + grovey=loc.Y+2; + grovez=loc.Z; + Point3D leafxyzg = new Point3D(grovex,grovey,grovez); + leavesh.MoveToWorld( leafxyzg, Caster.Map ); + InternalItem leavesi = new InternalItem( Caster.Location, Caster.Map, Caster ); + grovex=loc.X-3; + leavesi.ItemID=3294; + grovey=loc.Y; + grovez=loc.Z; + Point3D leafxyzh = new Point3D(grovex,grovey,grovez); + leavesi.MoveToWorld( leafxyzh, Caster.Map ); + + + + + + + } + + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private Timer m_Bless; + private DateTime m_End; + private Mobile m_Caster; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, Mobile caster ) : base( 0x3274 ) + { + Visible = false; + Movable = false; + MoveToWorld( loc, map ); + m_Caster=caster; + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 30.0 ) ); + m_Timer.Start(); + m_Bless = new BlessTimer( this, m_Caster ); + m_Bless.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + TimeSpan duration = reader.ReadTimeSpan(); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds( 10.0 ); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private Timer m_Bless; + + private InternalItem m_Item; + + public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + private class InternalTarget : Target + { + private EnchantedGroveSpell m_Owner; + + public InternalTarget( EnchantedGroveSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + private class BlessTimer : Timer + { + private Item m_EnchantedGrove; + private Mobile m_Caster; + private DateTime m_Duration; + + private static Queue m_Queue = new Queue(); + + public BlessTimer( Item ap, Mobile ca ) : base( TimeSpan.FromSeconds( 0.5 ), TimeSpan.FromSeconds( 1.0 ) ) + { + Priority = TimerPriority.FiftyMS; + + m_EnchantedGrove = ap; + m_Caster=ca; + m_Duration = DateTime.Now + TimeSpan.FromSeconds( 15.0 + ( Utility.RandomDouble() * 15.0 ) ); + } + + protected override void OnTick() + { + if ( m_EnchantedGrove.Deleted ) + return; + + if ( DateTime.Now > m_Duration ) + { + + Stop(); + } + else + { + ArrayList list = new ArrayList(); + + foreach ( Mobile m in m_EnchantedGrove.GetMobilesInRange( 5 ) ) + { + if ( m.Player && m.Karma >= 0 && m.Alive ) + list.Add( m ); + } + + for ( int i = 0; i < list.Count; ++i ) + { + Mobile m = (Mobile)list[i]; + bool friendly = true; + + for ( int j = 0; friendly && j < m_Caster.Aggressors.Count; ++j ) + friendly = ( ((AggressorInfo)m_Caster.Aggressors[j]).Attacker != m ); + + for ( int j = 0; friendly && j < m_Caster.Aggressed.Count; ++j ) + friendly = ( ((AggressorInfo)m_Caster.Aggressed[j]).Defender != m ); + + if ( friendly ) + { + m.FixedEffect( 0x37C4, 1, 12, 1109, 3 ); // At player + m.Mana += (1 + (m_Caster.Karma / 1000)); + m.Hits += (1 + (m_Caster.Karma / 1000)); + } + } + } + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/FireflyFamiliar.cs b/Scripts/Vivre/DuidismeVivre/Spells/FireflyFamiliar.cs new file mode 100644 index 0000000..f51fb03 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/FireflyFamiliar.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections; +using Server; +using Server.Items; +using Server.Gumps; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a firefly corpse" )] + public class FireflyFamiliar : BaseCreature + { + public FireflyFamiliar(): base( AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4 ) + { + Name = "a firefly"; + Body = 58; + Hue = 1174; + LightLevel = 10; + BaseSoundID = 466; + Blessed = true; + + SetStr( 5 ); + SetDex( 6 ); + SetInt( 10 ); + + SetHits( 5 ); + SetStam( 60 ); + SetMana( 0 ); + + SetDamage( 0 ); + + SetResistance( ResistanceType.Physical, 10, 15 ); + SetResistance( ResistanceType.Fire, 99 ); + SetResistance( ResistanceType.Cold, 10, 15 ); + SetResistance( ResistanceType.Poison, 10, 15 ); + SetResistance( ResistanceType.Energy, 10,15 ); + + SetSkill( SkillName.Wrestling, 10.0 ); + SetSkill( SkillName.Tactics, 10.0 ); + AddItem( new LightSource() ); + ControlSlots = 0; + } + + + public FireflyFamiliar( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/GraspingRootsSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/GraspingRootsSpell.cs new file mode 100644 index 0000000..039127b --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/GraspingRootsSpell.cs @@ -0,0 +1,174 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; + +namespace Server.Spells.Druid +{ + public class GraspingRootsSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Grasping Roots", "En Ohm Sepa Tia Kes", + //SpellCircle.Fifth, + 218, + 9012, + false, + Reagent.SpringWater, + Reagent.Bloodmoss, + Reagent.SpidersSilk + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } + public override SpellCircle Circle { get { return SpellCircle.Fifth; } } + public override double RequiredSkill{ get{ return 40.0; } } + public override int RequiredMana{ get{ return 40; } } + + + public GraspingRootsSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + double duration; + + // Algorithm: ((20% of AnimalTamin) + 7) seconds [- 50% if resisted] seems to work?? + duration = 7.0 + (Caster.Skills[DamageSkill].Value * 0.2); + + // Resist if Str + Dex / 2 is greater than CastSkill eg. AnimalLore seems to work << this formula will almost always be resisted against all but the lowest creatures + if ( ( (Caster.Skills[CastSkill].Value ) + (Caster.Skills[DamageSkill].Value ) ) < ( ( m.Str + m.Dex ) * 0.5 ) ) // << This should work much more often + duration *= 0.5; + + // no less than 0 seconds no more than 9 seconds + if ( duration < 0.0 ) + duration = 0.0; + if ( duration > 9.0 ) + duration = 9.0; + + m.PlaySound( 0x2A1 ); + + m.Paralyze( TimeSpan.FromSeconds( duration ) ); + m.FixedParticles( 0x375A, 2, 10, 5027, 0x3D, 2, EffectLayer.Waist ); + + { + Point3D loc = new Point3D( m.X, m.Y, m.Z ); + + Item item = new InternalItem( loc, Caster.Map, Caster ); + + } + + + } + + FinishSequence(); + } + + //[DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + + //public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, Mobile caster ) : base( 0xC5F ) + { + Visible = false; + Movable = false; + + MoveToWorld( loc, map ); + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 30.0 ) ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + + public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + private class InternalTarget : Target + { + private GraspingRootsSpell m_Owner; + + public InternalTarget( GraspingRootsSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/HollowReedSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/HollowReedSpell.cs new file mode 100644 index 0000000..15d32a6 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/HollowReedSpell.cs @@ -0,0 +1,76 @@ +using System; +using Server.Targeting; +using Server.Network; + +namespace Server.Spells.Druid +{ + public class HollowReedSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Hollow Reed", "Sec Crur Aeta", + //SpellCircle.Second, + 203, + 9061, + false, + Reagent.Bloodmoss, + Reagent.MandrakeRoot, + Reagent.SulfurousAsh + ); + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Second; } } + public override double RequiredSkill{ get{ return 30.0; } } + public override int RequiredMana{ get{ return 30; } } + + public HollowReedSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( !Caster.CanSee( m ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckBSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + SpellHelper.AddStatBonus( Caster, m, StatType.Str ); + SpellHelper.AddStatBonus( Caster, m, StatType.Dex ); + + m.PlaySound( 0x15 ); + m.FixedParticles( 0x373A, 10, 15, 5018, EffectLayer.Waist ); + + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private HollowReedSpell m_Owner; + + public InternalTarget( HollowReedSpell owner ) : base( 12, false, TargetFlags.Beneficial ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + { + m_Owner.Target( (Mobile)o ); + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/LureStone.cs b/Scripts/Vivre/DuidismeVivre/Spells/LureStone.cs new file mode 100644 index 0000000..b56dccd --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/LureStone.cs @@ -0,0 +1,76 @@ + +using Server; +using Server.Gumps; +using Server.Network; +using Server.Menus; +using Server.Menus.Questions; +using Server.Items; +using Server.Targeting; +using System.Collections; +using Server.Mobiles; +using Server.Misc; + + +namespace Server.Items +{ + public class LureStone : Item + { + private Mobile m_Owner; + [Constructable] + public LureStone(Mobile owner): base (0x1355) + { + m_Owner=owner; + Movable = false; + Name="Lure Stone"; +//AddComponent( new AddonComponent( 0x1355 ), 0, 0, 0 ); +// AddComponent( new AddonComponent( 0x1356 ), 0, -1, 0 ); + + + } + + public LureStone( Serial serial ) : base( serial ) + { + + + } +public override bool HandlesOnMovement{ get{ return true;} } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + Delete(); + } + public override void OnMovement(Mobile m, Point3D oldLocation ) + { + if(m_Owner!=null) + { + if ( m.InRange( this, 600 ) ) + { + BaseCreature cret = m as BaseCreature; + if(cret!=null) + if(cret.Tamable&&(cret.Combatant==null||!cret.Combatant.Alive||cret.Combatant.Deleted)) + { + + double tamer = m_Owner.Skills[SkillName.AnimalLore].Value; + double bonus = m_Owner.Skills[SkillName.AnimalTaming].Value/100; + if(cret.MinTameSkill<=(tamer+bonus)+0.1) + cret.TargetLocation = new Point2D( this.X,this.Y ); + } + + } + } + } + + + + + } +} + + diff --git a/Scripts/Vivre/DuidismeVivre/Spells/LureStoneSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/LureStoneSpell.cs new file mode 100644 index 0000000..461daed --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/LureStoneSpell.cs @@ -0,0 +1,330 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using Server.Mobiles; + +namespace Server.Spells.Druid +{ + public class LureStoneSpell : DruidicSpell + { + private LureStone m_Circlea; + private Item m_Circleb; + // private LureStone m_Circlec; + private static SpellInfo m_Info = new SpellInfo( + "Lure Stone", "En Kes Ohm Crur", + //SpellCircle.Second, + 269, + 9020, + false, + Reagent.PetrifiedWood, + Reagent.SpringWater + ); + + public LureStoneSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Second; } } + public override double RequiredSkill{ get{ return 25.0; } } + public override int RequiredMana{ get{ return 30; } } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + + + return true; + } + + public override void OnCast() + { + + Caster.Target = new InternalTarget( this ); + + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( /*SpellHelper.CheckTown( p, Caster ) &&*/ CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + + Effects.PlaySound( p, Caster.Map, 0x243 ); + + int stonex; + int stoney; + int stonez; + + Point3D loc = new Point3D( p.X, p.Y, p.Z ); + Item item = new InternalItema( loc, Caster.Map, Caster ); + stonex=p.X; + stoney=p.Y-1; + stonez=p.Z; + Point3D loca = new Point3D( stonex, stoney, stonez ); + Item itema = new InternalItemb( loca, Caster.Map, Caster ); + + + + + } + + + FinishSequence(); + } + [DispellableField] + private class InternalItema : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Owner; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItema( Point3D loc, Map map, Mobile caster ) : base( 0x1355 ) + { + m_Owner=caster; + Visible = false; + Movable = false; +Name="Lure Stone"; + MoveToWorld( loc, map ); + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 30.0 ) ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItema( Serial serial ) : base( serial ) + { + } +public override bool HandlesOnMovement{ get{ return true;} } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + TimeSpan duration = reader.ReadTimeSpan(); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds( 10.0 ); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + public override void OnMovement(Mobile m, Point3D oldLocation ) + { + if(m_Owner!=null) + { + if ( m.InRange( this, 600 ) ) + { + double tamer = m_Owner.Skills[SkillName.AnimalLore].Value; + double bonus = m_Owner.Skills[SkillName.AnimalTaming].Value/100; + + BaseCreature cret = m as BaseCreature; + if(cret!=null) + if(tamer>=99.9&&(cret.Combatant==null||!cret.Combatant.Alive||cret.Combatant.Deleted)) + { + cret.TargetLocation = new Point2D( this.X,this.Y ); + } + else if(cret.Tamable&&(cret.Combatant==null||!cret.Combatant.Alive||cret.Combatant.Deleted)) + { + + if(cret.MinTameSkill<=(tamer+bonus)+0.1) + cret.TargetLocation = new Point2D( this.X,this.Y ); + } + + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItema m_Item; + + public InternalTimer( InternalItema item, TimeSpan duration ) : base( duration ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + [DispellableField] + private class InternalItemb : Item + { + private Timer m_Timer; + private DateTime m_End; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItemb( Point3D loc, Map map, Mobile caster ) : base( 0x1356 ) + { + Visible = false; + Movable = false; + + MoveToWorld( loc, map ); + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 30.0 ) ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItemb( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + TimeSpan duration = reader.ReadTimeSpan(); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds( 10.0 ); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItemb m_Item; + + public InternalTimer( InternalItemb item, TimeSpan duration ) : base( duration ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + private class InternalTarget : Target + { + private LureStoneSpell m_Owner; + + public InternalTarget( LureStoneSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/MushroomCircle.cs b/Scripts/Vivre/DuidismeVivre/Spells/MushroomCircle.cs new file mode 100644 index 0000000..c8a810d --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/MushroomCircle.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class MushroomCircle : Item + { + private Mobile m_Owner; + private Timer m_Timer; + [Constructable] + public MushroomCircle () + { + + + + + } + + public MushroomCircle( Serial serial ) : base( serial ) + { + } + public override bool OnMoveOver( Mobile m ) +{ +m.SendMessage("The magic of the stones prevents you from crossing."); +return false; + + +} + + public override void OnAfterDelete() + { + if ( m_Timer != null ) + m_Timer.Stop(); + + m_Timer = null; + + + base.OnAfterDelete(); + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + Delete(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/MushroomGateCircle.cs b/Scripts/Vivre/DuidismeVivre/Spells/MushroomGateCircle.cs new file mode 100644 index 0000000..f6f7c25 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/MushroomGateCircle.cs @@ -0,0 +1,75 @@ +using System; +using Server.Network; +using Server.Multis; +using Server.Items; +using Server.Targeting; +using Server.Misc; +using Server.Mobiles; +using Server.Regions; + +namespace Server.Items +{ + [DispellableField] + public class MushroomGateCircle : Moongate + { +private int m_ItemID; + + public MushroomGateCircle (Point3D target, Map map, int item) + { + m_ItemID=item; + // AddComponent( new AddonComponent( 0xD10 ), 0, 0, 0 ); + // AddComponent( new AddonComponent( 0x373A ), 0, 0, 1 ); + // AddComponent( new AddonComponent( 0xD11 ), -1, 1, 0 ); + // AddComponent( new AddonComponent( 0xD0C ), -0, 2, 0 ); + // AddComponent( new AddonComponent( 0xD0D ), 1, 1, 0 ); + // AddComponent( new AddonComponent( 0xD0E ), 2, 0, 0 ); + // AddComponent( new AddonComponent( 0xD0F ), 1, -1, 0 ); + // Map = map; + + if ( ShowFeluccaWarning && map == Map.Felucca ) + { + Hue = 1175; + ItemID=m_ItemID; + } + + // Dispellable = true; + + InternalTimer t = new InternalTimer( this ); + t.Start(); + + } + + public MushroomGateCircle( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + Delete(); + } + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/MushroomGatewaySpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/MushroomGatewaySpell.cs new file mode 100644 index 0000000..b402195 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/MushroomGatewaySpell.cs @@ -0,0 +1,319 @@ +using System; +using Server.Network; +using Server.Multis; +using Server.Items; +using Server.Targeting; +using Server.Misc; +using Server.Regions; + +namespace Server.Spells.Druid +{ + public class MushroomGatewaySpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Mushroom Gateway", "Vauk Sepa Ohm", + //SpellCircle.Seventh, + 263, + 9032, + Reagent.SpidersSilk, + Reagent.MandrakeRoot, + Reagent.SpringWater + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 3 ); } } + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + public override double RequiredSkill{ get{ return 70.0; } } + public override int RequiredMana{ get{ return 40; } } + + private RunebookEntry m_Entry; + + public MushroomGatewaySpell( Mobile caster, Item scroll ) : this( caster, scroll, null ) + { + } + + public MushroomGatewaySpell( Mobile caster, Item scroll, RunebookEntry entry ) : base( caster, scroll, m_Info ) + { + m_Entry = entry; + } + + public override void OnCast() + { + if ( m_Entry == null ) + Caster.Target = new InternalTarget( this ); + else + Effect( m_Entry.Location, m_Entry.Map, true ); + } + + public override bool CheckCast() + { + if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + return false; + } + + return SpellHelper.CheckTravel( Caster, TravelCheckType.GateFrom ); + } + + public void Effect( Point3D loc, Map map, bool checkMulti ) + { + if ( map == null || (!Core.AOS && Caster.Map != map) ) + { + Caster.SendLocalizedMessage( 1005570 ); // You can not gate to another facet. + } + else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.GateFrom ) ) + { + } + else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.GateTo ) ) + { + } + else if ( Caster.Kills >= 5 && map != Map.Felucca ) + { + Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + } + else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( CheckSequence() ) + { + Caster.SendMessage( "You open a mystical portal in a mushroom circle" ); // You open a magical gate to another location + + Effects.PlaySound( Caster.Location, Caster.Map, 0x1 ); + int mushx; + int mushy; + int mushz; + + + InternalItem firstGatea = new InternalItem( loc, map ); + mushx=Caster.X; + mushy=Caster.Y; + mushz=Caster.Z; + firstGatea.ItemID=0xD10; + Point3D mushxyz = new Point3D(mushx,mushy,mushz); + firstGatea.MoveToWorld( mushxyz, Caster.Map ); + InternalItem firstGateb = new InternalItem( loc, map ); + mushx=Caster.X; + mushy=Caster.Y; + firstGateb.ItemID=0x373A; + mushz=Caster.Z+1; + Point3D mushxyza = new Point3D(mushx,mushy,mushz); + firstGateb.MoveToWorld( mushxyza, Caster.Map ); + InternalItem firstGatec = new InternalItem( loc, map ); + mushx=Caster.X-1; + firstGatec.ItemID=0xD11; + mushy=Caster.Y+1; + mushz=Caster.Z; + Point3D mushxyzb = new Point3D(mushx,mushy,mushz); + firstGatec.MoveToWorld( mushxyzb, Caster.Map ); +InternalItem firstGated = new InternalItem( loc, map); + firstGated.ItemID=0xD0C; + mushx=Caster.X; + mushy=Caster.Y+2; + mushz=Caster.Z; + Point3D mushxyzc = new Point3D(mushx,mushy,mushz); + firstGated.MoveToWorld( mushxyzc, Caster.Map ); +InternalItem firstGatee = new InternalItem( loc, map ); + mushx=Caster.X+1; + firstGatee.ItemID=0xD0D; + mushy=Caster.Y+1; + mushz=Caster.Z; + Point3D mushxyzd = new Point3D(mushx,mushy,mushz); + firstGatee.MoveToWorld( mushxyzd, Caster.Map ); +InternalItem firstGatef = new InternalItem( loc, map ); + firstGatef.ItemID=0xD0E; + mushx=Caster.X+2; + mushy=Caster.Y; + mushz=Caster.Z; + Point3D mushxyze = new Point3D(mushx,mushy,mushz); + firstGatef.MoveToWorld( mushxyze, Caster.Map ); +InternalItem firstGateg = new InternalItem( loc, map ); + mushx=Caster.X+1; + firstGateg.ItemID=0xD0F; + + mushy=Caster.Y-1; + mushz=Caster.Z; + Point3D mushxyzf = new Point3D(mushx,mushy,mushz); + firstGateg.MoveToWorld( mushxyzf, Caster.Map ); + + + + Effects.PlaySound( loc, map, 0x1 ); + + InternalItem secondGatea = new InternalItem( Caster.Location, Caster.Map ); + mushx=loc.X; + mushy=loc.Y; + mushz=loc.Z; + secondGatea.ItemID=0xD10; + + Point3D mushaxyz = new Point3D(mushx,mushy,mushz); + secondGatea.MoveToWorld( mushaxyz, map); + InternalItem secondGateb = new InternalItem( Caster.Location, Caster.Map ); + mushx=loc.X; + mushy=loc.Y; + secondGateb.ItemID=0x373A; + mushz=loc.Z+1; + Point3D mushaxyza = new Point3D(mushx,mushy,mushz); + secondGateb.MoveToWorld( mushaxyza, map); + InternalItem secondGatec = new InternalItem( Caster.Location, Caster.Map ); + mushx=loc.X-1; + secondGatec.ItemID=0xD11; + mushy=loc.Y+1; + mushz=loc.Z-1; + Point3D mushaxyzb = new Point3D(mushx,mushy,mushz); + secondGatec.MoveToWorld( mushaxyzb, map); +InternalItem secondGated = new InternalItem( Caster.Location, Caster.Map); + mushx=loc.X; + mushy=loc.Y+2; + secondGated.ItemID=0xD0C; + mushz=loc.Z; + Point3D mushaxyzc = new Point3D(mushx,mushy,mushz); + secondGated.MoveToWorld( mushaxyzc, map); +InternalItem secondGatee = new InternalItem( Caster.Location, Caster.Map ); + mushx=loc.X+1; + mushy=loc.Y+1; + mushz=loc.Z; + secondGatee.ItemID=0xD0D; + Point3D mushaxyzd = new Point3D(mushx,mushy,mushz); + secondGatee.MoveToWorld( mushaxyzd, map); +InternalItem secondGatef = new InternalItem( Caster.Location, Caster.Map ); + mushx=loc.X+2; + mushy=loc.Y; + mushz=loc.Z; + secondGatef.ItemID=0xD0E; + Point3D mushaxyze = new Point3D(mushx,mushy,mushz); + secondGatef.MoveToWorld( mushaxyze, map); +InternalItem secondGateg = new InternalItem( Caster.Location, Caster.Map ); + mushx=loc.X+1; + secondGateg.ItemID=0xD0F; + mushy=loc.Y-1; + mushz=loc.Z; + Point3D mushaxyzf = new Point3D(mushx,mushy,mushz); + secondGateg.MoveToWorld( mushaxyzf, map); + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Moongate + { + public override bool ShowFeluccaWarning{ get{ return Core.AOS; } } + + public InternalItem( Point3D target, Map map ) : base( target, map ) + { + Map = map; + + if ( ShowFeluccaWarning && map == Map.Felucca ) + ItemID = 0xDDA; + + Dispellable = true; + + InternalTimer t = new InternalTimer( this ); + t.Start(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + Delete(); + } + + private class InternalTimer : Timer + { + private Item m_Item; + + public InternalTimer( Item item ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + + private class InternalTarget : Target + { + private MushroomGatewaySpell m_Owner; + + public InternalTarget( MushroomGatewaySpell owner ) : base( 12, false, TargetFlags.None ) + { + m_Owner = owner; + + owner.Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501029 ); // Select Marked item. + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is RecallRune ) + { + RecallRune rune = (RecallRune)o; + + if ( rune.Marked ) + m_Owner.Effect( rune.Target, rune.TargetMap, true ); + else + from.SendLocalizedMessage( 501803 ); // That rune is not yet marked. + } + else if ( o is Runebook ) + { + RunebookEntry e = ((Runebook)o).Default; + + if ( e != null ) + m_Owner.Effect( e.Location, e.Map, true ); + else + from.SendLocalizedMessage( 502354 ); // Target is not marked. + } + /*else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat ) + { + BaseBoat boat = ((Key)o).Link as BaseBoat; + + if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) ) + m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false ); + else + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 501030, from.Name, "" ) ); // I can not gate travel from that object. + }*/ + else + { + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 501030, from.Name, "" ) ); // I can not gate travel from that object. + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} + diff --git a/Scripts/Vivre/DuidismeVivre/Spells/NaturesPassageSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/NaturesPassageSpell.cs new file mode 100644 index 0000000..4f93443 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/NaturesPassageSpell.cs @@ -0,0 +1,180 @@ +using System; +using Server.Items; +using Server.Multis; +using Server.Network; +using Server.Targeting; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Spells.Druid +{ + public class NaturesPassageSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Nature's Passage", "Kes Sec Vauk", + //SpellCircle.Fourth, + 239, + 9031, + Reagent.Pumice, + Reagent.Bloodmoss, + Reagent.MandrakeRoot + ); + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + public override double RequiredSkill{ get{ return 25.0; } } + public override int RequiredMana{ get{ return 10; } } + private RunebookEntry m_Entry; + private Runebook m_Book; + + public NaturesPassageSpell( Mobile caster, Item scroll ) : this( caster, scroll, null, null ) + { + } + + public NaturesPassageSpell( Mobile caster, Item scroll, RunebookEntry entry, Runebook book ) : base( caster, scroll, m_Info ) + { + m_Entry = entry; + m_Book = book; + } + + + + public override void OnCast() + { + if ( m_Entry == null ) + Caster.Target = new InternalTarget( this ); + else + Effect( m_Entry.Location, m_Entry.Map, true ); + } + + public override bool CheckCast() + { + if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + return false; + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + return false; + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + return false; + } + + return SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ); + } + + public void Effect( Point3D loc, Map map, bool checkMulti ) + { + if ( map == null || (!Core.AOS && Caster.Map != map) ) + { + Caster.SendLocalizedMessage( 1005569 ); // You can not recall to another facet. + } + else if ( !SpellHelper.CheckTravel( Caster, TravelCheckType.RecallFrom ) ) + { + } + else if ( !SpellHelper.CheckTravel( Caster, map, loc, TravelCheckType.RecallTo ) ) + { + } + else if ( Caster.Kills >= 5 && map != Map.Felucca ) + { + Caster.SendLocalizedMessage( 1019004 ); // You are not allowed to travel there. + } + else if ( Caster.Criminal ) + { + Caster.SendLocalizedMessage( 1005561, "", 0x22 ); // Thou'rt a criminal and cannot escape so easily. + } + else if ( SpellHelper.CheckCombat( Caster ) ) + { + Caster.SendLocalizedMessage( 1005564, "", 0x22 ); // Wouldst thou flee during the heat of battle?? + } + else if ( Server.Misc.WeightOverloading.IsOverloaded( Caster ) ) + { + Caster.SendLocalizedMessage( 502359, "", 0x22 ); // Thou art too encumbered to move. + } + else if ( !map.CanSpawnMobile( loc.X, loc.Y, loc.Z ) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( (checkMulti && SpellHelper.CheckMulti( loc, map )) ) + { + Caster.SendLocalizedMessage( 501942 ); // That location is blocked. + } + else if ( m_Book != null && m_Book.CurCharges <= 0 ) + { + Caster.SendLocalizedMessage( 502412 ); // There are no charges left on that item. + } + else if ( CheckSequence() ) + { + BaseCreature.TeleportPets( Caster, loc, map, true ); + if ( m_Book != null ) + --m_Book.CurCharges; + + Caster.PlaySound( 0x19 ); + Effects.SendLocationParticles( Caster, 0xC87, 9, 10, 5025 ); + Caster.Map = map; + Caster.Location = loc; + Caster.PlaySound( 0x19 ); + Effects.SendLocationParticles( Caster, 0xC87, 9, 10, 5025 ); + + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private NaturesPassageSpell m_Owner; + + public InternalTarget( NaturesPassageSpell owner ) : base( 12, false, TargetFlags.None ) + { + m_Owner = owner; + + owner.Caster.LocalOverheadMessage( MessageType.Regular, 0x3B2, 501029 ); // Select Marked item. + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is RecallRune ) + { + RecallRune rune = (RecallRune)o; + + if ( rune.Marked ) + m_Owner.Effect( rune.Target, rune.TargetMap, true ); + else + from.SendLocalizedMessage( 501805 ); // That rune is not yet marked. + } + else if ( o is Runebook ) + { + RunebookEntry e = ((Runebook)o).Default; + + if ( e != null ) + m_Owner.Effect( e.Location, e.Map, true ); + else + from.SendLocalizedMessage( 502354 ); // Target is not marked. + } + else if ( o is Key && ((Key)o).KeyValue != 0 && ((Key)o).Link is BaseBoat ) + { + BaseBoat boat = ((Key)o).Link as BaseBoat; + + if ( !boat.Deleted && boat.CheckKey( ((Key)o).KeyValue ) ) + m_Owner.Effect( boat.GetMarkedLocation(), boat.Map, false ); + else + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object. + } + else + { + from.Send( new MessageLocalized( from.Serial, from.Body, MessageType.Regular, 0x3B2, 3, 502357, from.Name, "" ) ); // I can not recall from that object. + } + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/PackOfBeastSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/PackOfBeastSpell.cs new file mode 100644 index 0000000..c65a839 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/PackOfBeastSpell.cs @@ -0,0 +1,90 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Druid +{ + public class PackOfBeastSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Pack Of Beast", "En Sec Ohm Ess Sepa", + //SpellCircle.Third, + 266, + 9040, + false, + Reagent.SpidersSilk, + Reagent.Bloodmoss, + Reagent.PetrifiedWood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Third; } } + public override double RequiredSkill{ get{ return 40.0; } } + public override int RequiredMana{ get{ return 45; } } + + public PackOfBeastSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + private static Type[] m_Types = new Type[] + { + typeof( BrownBear ), + typeof( TimberWolf ), + typeof( Panther ), + typeof( GreatHart ), + typeof( Hind ), + typeof( Alligator ), + typeof( Boar ), + typeof( GiantRat ) + }; + + public override void OnCast() + { + if ( CheckSequence() ) + { + try + { + + Type beasttype = ( m_Types[Utility.Random( m_Types.Length )] ); + + BaseCreature creaturea = (BaseCreature)Activator.CreateInstance( beasttype ); + BaseCreature creatureb = (BaseCreature)Activator.CreateInstance( beasttype ); + BaseCreature creaturec = (BaseCreature)Activator.CreateInstance( beasttype ); + BaseCreature creatured = (BaseCreature)Activator.CreateInstance( beasttype ); + + + SpellHelper.Summon( creaturea, Caster, 0x215, TimeSpan.FromSeconds( 4.0 * Caster.Skills[CastSkill].Value ), false, false ); + SpellHelper.Summon( creatureb, Caster, 0x215, TimeSpan.FromSeconds( 4.0 * Caster.Skills[CastSkill].Value ), false, false ); + + Double morebeast = 0 ; + + morebeast = Utility.Random( 10 ) + ( Caster.Skills[CastSkill].Value * 0.1 ); + + + if ( morebeast > 11 ) + { + SpellHelper.Summon( creaturec, Caster, 0x215, TimeSpan.FromSeconds( 4.0 * Caster.Skills[CastSkill].Value ), false, false ); + } + + if ( morebeast > 18 ) + { + SpellHelper.Summon( creatured, Caster, 0x215, TimeSpan.FromSeconds( 4.0 * Caster.Skills[CastSkill].Value ), false, false ); + } + + + } + catch + { + } + } + + FinishSequence(); + } + + public override TimeSpan GetCastDelay() + { + return TimeSpan.FromSeconds( 7.5 ); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/RestorativeSoilSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/RestorativeSoilSpell.cs new file mode 100644 index 0000000..22c1a4d --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/RestorativeSoilSpell.cs @@ -0,0 +1,213 @@ +using System; +using Server.Targeting; +using Server.Network; +using Server.Misc; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Spells.Druid +{ + public class RestorativeSoilSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Restorative Soil", "Ohm Sepa Ante", + //SpellCircle.Eighth, + 269, + 9020, + Reagent.PetrifiedWood, + Reagent.Bloodmoss, + Reagent.SpringWater + ); + + public RestorativeSoilSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2 ); } } + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + public override double RequiredSkill{ get{ return 85.0; } } + public override int RequiredMana{ get{ return 55; } } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + + + return true; + } + + public override void OnCast() + { + + Caster.Target = new InternalTarget( this ); + + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + + Effects.PlaySound( p, Caster.Map, 0x382 ); + + + Point3D loc = new Point3D( p.X, p.Y, p.Z ); + Item item = new InternalItem( loc, Caster.Map, Caster ); + + + + + + } + + + FinishSequence(); + } + [DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Owner; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, Mobile caster ) : base( 0x913 ) + { + m_Owner=caster; + Visible = false; + Movable = false; +Name="restorative soil"; + MoveToWorld( loc, map ); + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 30.0 ) ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } +public override bool HandlesOnMovement{ get{ return true;} } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + TimeSpan duration = reader.ReadTimeSpan(); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds( 10.0 ); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + public override bool OnMoveOver( Mobile m ) +{ + if(m is PlayerMobile&&!m.Alive) + { + m.SendGump( new ResurrectGump( m ) ); + +m.SendMessage("The power of the soil surges through you!"); + + + } + else + m.PlaySound(0x339); + return true; +} + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + + public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + + private class InternalTarget : Target + { + private RestorativeSoilSpell m_Owner; + + public InternalTarget( RestorativeSoilSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/SacredStone.cs b/Scripts/Vivre/DuidismeVivre/Spells/SacredStone.cs new file mode 100644 index 0000000..32ed96a --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/SacredStone.cs @@ -0,0 +1,166 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items +{ + public class SacredStone : Item + { + private Mobile m_Owner; + private bool m_campSecure = false; + private Timer m_campSecureTimer; + private Timer m_Timer; + + public override bool HandlesOnMovement{ get{ return true; } } + public static int CampingRange{ get{ return 5; } } + + [Constructable] + public SacredStone( Mobile owner ) : base ( 0x8E3 ) + { + Movable = false; + Name="Sacred Stone"; + + m_Owner = owner; + + m_Timer = new DecayTimer( this ); + m_Timer.Start(); + + m_campSecureTimer = new SecureTimer( m_Owner, this ); + m_campSecureTimer.Start(); + } + + public SacredStone( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Owner ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_Owner = reader.ReadMobile(); + m_Timer = new DecayTimer( this ); + m_Timer.Start(); + m_campSecureTimer = new SecureTimer( m_Owner, this ); + m_campSecureTimer.Start(); + break; + } + } + } + + public override void OnMovement( Mobile m, Point3D oldLocation ) + { + if( ( m is PlayerMobile ) && ( m == m_Owner ) ) + { + bool inOldRange = Utility.InRange( oldLocation, Location, CampingRange ); + bool inNewRange = Utility.InRange( m.Location, Location, CampingRange ); + + if ( inNewRange && !inOldRange ) + OnEnter( m ); + else if ( inOldRange && !inNewRange ) + OnExit( m ); + } + } + + public virtual void OnEnter( Mobile m ) + { + StartSecureTimer(); + } + + public virtual void OnExit( Mobile m ) + { + StopSecureTimer(); + m.SendMessage( "You have left the grove." ); + } + + public override void OnAfterDelete() + { + if( m_Timer != null ) + m_Timer.Stop(); + } + + private class DecayTimer : Timer + { + private SacredStone m_Owner; + + public DecayTimer( SacredStone owner ) : base( TimeSpan.FromMinutes( 2.0 ) ) + { + Priority = TimerPriority.FiveSeconds; + m_Owner = owner; + } + + protected override void OnTick() + { + m_Owner.Delete(); + } + } + + + [CommandProperty( AccessLevel.GameMaster )] + public bool CampSecure + { + get { return m_campSecure; } + set { m_campSecure = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Camper{ get { return m_Owner; } } + + public void StartSecureTimer() + { + Camper.SendMessage( "You start to feel secure" ); // You feel it would take a few moments to secure your camp. + if( m_campSecureTimer.Running == false ) + { + m_campSecure = false; + m_campSecureTimer.Start(); + } + } + + public void StopSecureTimer() + { + m_campSecure = false; + m_campSecureTimer.Stop(); + } + + public override void OnDelete() + { + base.OnDelete(); + if( m_campSecureTimer != null ) + StopSecureTimer(); + } + + private class SecureTimer : Timer + { + private Mobile m_Owner; + private SacredStone m_SacredStone; + + public SecureTimer( Mobile owner , SacredStone SacredStone ) : base( TimeSpan.FromSeconds( 30.0 ) ) + { + Priority = TimerPriority.FiveSeconds; + m_SacredStone = SacredStone; + m_Owner = owner; + } + + protected override void OnTick() + { + m_SacredStone.CampSecure = true; + m_Owner.SendMessage( "The power of the grove washes over you." ); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/ShieldOfEarthSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/ShieldOfEarthSpell.cs new file mode 100644 index 0000000..be5087f --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/ShieldOfEarthSpell.cs @@ -0,0 +1,338 @@ +using System; +using Server.Targeting; +using Server.Network; +using System.Collections; +using Server.Misc; +using Server.Items; + +namespace Server.Spells.Druid +{ + public class ShieldOfEarthSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Shield Of Earth", "Kes En Sepa Ohm", + 227, + 9011, + false, + Reagent.MandrakeRoot, + Reagent.SpidersSilk + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + public override double RequiredSkill{ get{ return 60.0; } } + public override int RequiredMana{ get{ return 45; } } + + public ShieldOfEarthSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( /*SpellHelper.CheckTown( p, Caster ) &&*/ CheckSequence() ) + { + + if(this.Scroll!=null) + Scroll.Consume(); + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + int dx = Caster.Location.X - p.X; + int dy = Caster.Location.Y - p.Y; + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + bool eastToWest; + + if ( rx >= 0 && ry >= 0 ) + { + eastToWest = false; + } + else if ( rx >= 0 ) + { + eastToWest = true; + } + else if ( ry >= 0 ) + { + eastToWest = true; + } + else + { + eastToWest = false; + } + + Effects.PlaySound( p, Caster.Map, 0x20B ); + + int itemID = eastToWest ? 0x3915 : 0x3922; + + TimeSpan duration = TimeSpan.FromSeconds( 3.0 + (Caster.Skills[SkillName.Spellweaving].Value * 0.4) ); + + for ( int i = -2; i <= 2; ++i ) + { + Point3D loc = new Point3D( eastToWest ? p.X + i : p.X, eastToWest ? p.Y : p.Y + i, p.Z ); + + new InternalItem( itemID, loc, Caster, Caster.Map, duration, i ); + } + } + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Caster; + private SleepingBody m_Body; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( int itemID, Point3D loc, Mobile caster, Map map, TimeSpan duration, int val ) : base( itemID ) + { + bool canFit = SpellHelper.AdjustField( ref loc, map, 12, false ); + + Visible = false; + Movable = false; + Light = LightType.Circle300; + Hue=1169; + Name="sleep field"; + + MoveToWorld( loc, map ); + + m_Caster = caster; + + m_End = DateTime.Now + duration; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( Math.Abs( val ) * 0.2 ), caster.InLOS( this ), canFit ); + m_Timer.Start(); + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Caster ); + writer.WriteDeltaTime( m_End ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Caster = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_End = reader.ReadDeltaTime(); + + m_Timer = new InternalTimer( this, TimeSpan.Zero, true, true ); + m_Timer.Start(); + + break; + } + } + } + + public void ApplySleepTo( Mobile m ) + { + m.Hidden = true; + m.Frozen=true; + m.Squelched=true; + + SleepingBody body = new SleepingBody(m, m.Blessed); + + body.Map=m.Map; + body.Location=m.Location; + m_Body=body; + m.Z-=100; + + + m.SendMessage("You fall asleep"); + + RemoveTimer( m ); + + TimeSpan duration = TimeSpan.FromSeconds( m_Caster.Skills[SkillName.Magery].Value * 1.2 ); // 120% of magery + + Timer t = new BodyTimer( m, duration, m_Body ); + + m_Table[m] = t; + + t.Start(); + } + private static Hashtable m_Table = new Hashtable(); + + public static void RemoveTimer( Mobile m ) + { + Timer t = (Timer)m_Table[m]; + + if ( t != null ) + { + t.Stop(); + m_Table.Remove( m ); + } + } + + private class BodyTimer : Timer + { + private Mobile m_Mobile; + private SleepingBody m_Body; + + public BodyTimer( Mobile m, TimeSpan duration, SleepingBody body ) : base( duration ) + { + m_Mobile = m; + m_Body=body; + } + + protected override void OnTick() + { + m_Mobile.RevealingAction(); + m_Mobile.Frozen=false; + m_Mobile.Squelched=false; + m_Mobile.Z=m_Body.Z; + + if(m_Body!=null) + { + m_Body.Delete(); + m_Mobile.SendMessage("You wake up!"); + } + RemoveTimer( m_Mobile ); + } + } + public override bool OnMoveOver( Mobile m ) + { + if ( Visible && m_Caster != null && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) ) + { + + ApplySleepTo( m ); + m.PlaySound( 0x474 ); + } + m.Hidden=true; + return false; + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + private bool m_InLOS, m_CanFit; + + private static Queue m_Queue = new Queue(); + + public InternalTimer( InternalItem item, TimeSpan delay, bool inLOS, bool canFit ) : base( delay, TimeSpan.FromSeconds( 1.5 ) ) + { + m_Item = item; + m_InLOS = inLOS; + m_CanFit = canFit; + + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if ( m_Item.Deleted ) + return; + + if ( !m_Item.Visible ) + { + if ( m_InLOS && m_CanFit ) + m_Item.Visible = true; + else + m_Item.Delete(); + + if ( !m_Item.Deleted ) + { + m_Item.ProcessDelta(); + Effects.SendLocationParticles( EffectItem.Create( m_Item.Location, m_Item.Map, EffectItem.DefaultDuration ), 0x376A, 9, 10, 5040 ); + } + } + else if ( DateTime.Now > m_Item.m_End ) + { + m_Item.Delete(); + Stop(); + } + else + { + Map map = m_Item.Map; + Mobile caster = m_Item.m_Caster; + + if ( map != null && caster != null ) + { + bool eastToWest = ( m_Item.ItemID == 0x3915 ); + IPooledEnumerable eable = map.GetMobilesInBounds( new Rectangle2D( m_Item.X - (eastToWest ? 0 : 1), m_Item.Y - (eastToWest ? 1 : 0), (eastToWest ? 1 : 2), (eastToWest ? 2 : 1) ) );; + + foreach ( Mobile m in eable ) + { + if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) ) + m_Queue.Enqueue( m ); + } + + eable.Free(); + + while ( m_Queue.Count > 0 ) + { + Mobile m = (Mobile)m_Queue.Dequeue(); + + m.PlaySound( 0x3C4 ); + m_Item.ApplySleepTo( m ); + + } + } + } + } + } + } + + private class InternalTarget : Target + { + private ShieldOfEarthSpell m_Owner; + + public InternalTarget( ShieldOfEarthSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/SpringOfLifeSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/SpringOfLifeSpell.cs new file mode 100644 index 0000000..1481b20 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/SpringOfLifeSpell.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Spells.Druid; + +namespace Server.Spells.Druid +{ + public class SpringOfLifeSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Spring Of Life", "En Sepa Aete", + //SpellCircle.Fourth, + 204, + 9061, + false, + Reagent.SpringWater, + Reagent.PetrifiedWood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Fourth; } } + public override double RequiredSkill{ get{ return 40.0; } } + public override int RequiredMana{ get{ return 40; } } + + public SpringOfLifeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + ArrayList targets = new ArrayList(); + + IPooledEnumerable eable = Caster.Map.GetMobilesInRange( new Point3D( p ), 3 ); + + foreach ( Mobile m in eable ) + { + if ( Caster.CanBeBeneficial( m, false ) ) + targets.Add( m ); + } + + eable.Free(); + + Effects.PlaySound( p, Caster.Map, 0x11 ); + + int val = (int)(Caster.Skills[CastSkill].Value/20.0 + 5); + + if ( targets.Count > 0 ) + { + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + if ( m.BeginAction( typeof( SpringOfLifeSpell ) ) ) + { + Caster.DoBeneficial( m ); + m.FixedParticles( 0x375A, 9, 20, 5027, EffectLayer.Head ); + + int toHeal = (int)(Caster.Skills[DamageSkill].Value * 0.6); + toHeal += Utility.Random( 1, 10 ); + + m.Heal( toHeal ); + + new InternalTimer( m, Caster, val ).Start(); + m.FixedParticles( 0x375A, 9, 20, 5027, EffectLayer.Waist ); + m.PlaySound( 0xAF ); + } + } + } + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private Mobile m_Owner; + private int m_Val; + + public InternalTimer( Mobile target, Mobile caster, int val ) : base( TimeSpan.FromSeconds( 0 ) ) + { + double time = caster.Skills[SkillName.Herding].Value * 1.2; + if ( time > 300 ) + time = 300; + Delay = TimeSpan.FromSeconds( time ); + Priority = TimerPriority.TwoFiftyMS; + + m_Owner = target; + m_Val = val; + } + + protected override void OnTick() + { + m_Owner.EndAction( typeof( SpringOfLifeSpell ) ); + + + } + } + + private class InternalTarget : Target + { + private SpringOfLifeSpell m_Owner; + + public InternalTarget( SpringOfLifeSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/StoneCircleSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/StoneCircleSpell.cs new file mode 100644 index 0000000..c5c40e6 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/StoneCircleSpell.cs @@ -0,0 +1,309 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Network; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; + +namespace Server.Spells.Druid +{ + public class StoneCircleSpell : DruidicSpell + { + private InternalItem m_Circlea; + + private static SpellInfo m_Info = new SpellInfo( + "Stone Circle", "En Ess Ohm", + //SpellCircle.Sixth, + 266, + 9040, + false, + Reagent.SpidersSilk, + Reagent.MandrakeRoot, + Reagent.SpringWater + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 3 ); } } + public override SpellCircle Circle { get { return SpellCircle.Sixth; } } + public override double RequiredSkill{ get{ return 60.0; } } + public override int RequiredMana{ get{ return 45; } } + + public StoneCircleSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + + + + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( /*SpellHelper.CheckTown( p, Caster ) &&*/ CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + SpellHelper.GetSurfaceTop( ref p ); + + + Effects.PlaySound( p, Caster.Map, 0x222 ); + + + Point3D loc = new Point3D( p.X, p.Y, p.Z ); + int mushx; + int mushy; + int mushz; + + + InternalItem firstFlamea = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-2; + mushy=loc.Y-2; + mushz=loc.Z; + Point3D mushxyz = new Point3D(mushx,mushy,mushz); + firstFlamea.MoveToWorld( mushxyz, Caster.Map ); + + InternalItem firstFlamec = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X; + mushy=loc.Y-3; + mushz=loc.Z; + Point3D mushxyzb = new Point3D(mushx,mushy,mushz); + firstFlamec.MoveToWorld( mushxyzb, Caster.Map ); + +InternalItem firstFlamed = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+2; + mushy=loc.Y-2; + mushz=loc.Z; + Point3D mushxyzc = new Point3D(mushx,mushy,mushz); + firstFlamed.MoveToWorld( mushxyzc, Caster.Map ); + + InternalItem hiddenflame = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+2; + mushy=loc.Y-1; + mushz=loc.Z; + Point3D mushxyzhid = new Point3D(mushx,mushy,mushz); + hiddenflame.MoveToWorld( mushxyzhid, Caster.Map ); + InternalItem hiddenrock = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+2; + mushy=loc.Y+1; + mushz=loc.Z; + Point3D rockaxyz = new Point3D(mushx,mushy,mushz); + hiddenrock.MoveToWorld( rockaxyz, Caster.Map ); + InternalItem hiddenflamea = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-2; + mushy=loc.Y-1; + mushz=loc.Z; + Point3D mushxyzhida = new Point3D(mushx,mushy,mushz); + hiddenflamea.MoveToWorld( mushxyzhida, Caster.Map ); + InternalItem hiddenrocks = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-2; + mushy=loc.Y+1; + mushz=loc.Z; + Point3D rocksaxyz = new Point3D(mushx,mushy,mushz); + hiddenrocks.MoveToWorld( rocksaxyz, Caster.Map ); + InternalItem hiddenrocka = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+1; + mushy=loc.Y+2; + mushz=loc.Z; + Point3D rockbxyz = new Point3D(mushx,mushy,mushz); + hiddenrocka.MoveToWorld( rockbxyz, Caster.Map ); + InternalItem hiddenrockb = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+1; + mushy=loc.Y-2; + mushz=loc.Z; + Point3D rockcxyz = new Point3D(mushx,mushy,mushz); + hiddenrockb.MoveToWorld( rockcxyz, Caster.Map ); + InternalItem hiddenrockc = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-1; + mushy=loc.Y-2; + mushz=loc.Z; + Point3D rockdxyz = new Point3D(mushx,mushy,mushz); + hiddenrockc.MoveToWorld( rockdxyz, Caster.Map ); + InternalItem hiddenrockd = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-1; + mushy=loc.Y+2; + mushz=loc.Z; + Point3D rockexyz = new Point3D(mushx,mushy,mushz); + hiddenrockd.MoveToWorld( rockexyz, Caster.Map ); +InternalItem firstFlamee = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+3; + mushy=loc.Y; + mushz=loc.Z; + Point3D mushxyzd = new Point3D(mushx,mushy,mushz); + firstFlamee.MoveToWorld( mushxyzd, Caster.Map ); +InternalItem firstFlamef = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X+2; + mushy=loc.Y+2; + mushz=loc.Z; + Point3D mushxyze = new Point3D(mushx,mushy,mushz); + firstFlamef.MoveToWorld( mushxyze, Caster.Map ); +InternalItem firstFlameg = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X; + mushy=loc.Y+3; + mushz=loc.Z; + Point3D mushxyzf = new Point3D(mushx,mushy,mushz); + firstFlameg.MoveToWorld( mushxyzf, Caster.Map ); + InternalItem firstFlameh = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-2; + mushy=loc.Y+2; + mushz=loc.Z; + Point3D mushxyzg = new Point3D(mushx,mushy,mushz); + firstFlameh.MoveToWorld( mushxyzg, Caster.Map ); + InternalItem firstFlamei = new InternalItem( Caster.Location, Caster.Map, Caster ); + mushx=loc.X-3; + mushy=loc.Y; + mushz=loc.Z; + Point3D mushxyzh = new Point3D(mushx,mushy,mushz); + firstFlamei.MoveToWorld( mushxyzh, Caster.Map ); + + + + + + + + } + + + FinishSequence(); + } + + [DispellableField] + private class InternalItem : Item + { + private Timer m_Timer; + private DateTime m_End; + private Mobile m_Caster; + private ArrayList frozen; + + public override bool BlocksFit{ get{ return true; } } + + public InternalItem( Point3D loc, Map map, Mobile caster ) : base( 0x08E2 ) + { + Visible = false; + Movable = false; +ItemID=Utility.RandomList(2274,2275,2272,2273,2279,2280); + Name="stone"; + MoveToWorld( loc, map ); + m_Caster=caster; + + if ( caster.InLOS( this ) ) + Visible = true; + else + Delete(); + + if ( Deleted ) + return; + + m_Timer = new InternalTimer( this, TimeSpan.FromSeconds( 30.0 ) ); + m_Timer.Start(); + + m_End = DateTime.Now + TimeSpan.FromSeconds( 30.0 ); + } + + public InternalItem( Serial serial ) : base( serial ) + { + } + public override bool OnMoveOver( Mobile m ) +{ +m.SendMessage("The magic of the stones prevents you from crossing."); +return false; + + +} + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_End - DateTime.Now ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + TimeSpan duration = reader.ReadTimeSpan(); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + case 0: + { + TimeSpan duration = TimeSpan.FromSeconds( 10.0 ); + + m_Timer = new InternalTimer( this, duration ); + m_Timer.Start(); + + m_End = DateTime.Now + duration; + + break; + } + } + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if ( m_Timer != null ) + m_Timer.Stop(); + } + + private class InternalTimer : Timer + { + private InternalItem m_Item; + + public InternalTimer( InternalItem item, TimeSpan duration ) : base( duration ) + { + m_Item = item; + } + + protected override void OnTick() + { + m_Item.Delete(); + } + } + } + private class InternalTarget : Target + { + private StoneCircleSpell m_Owner; + + public InternalTarget( StoneCircleSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is IPoint3D ) + m_Owner.Target( (IPoint3D)o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/SummonFireflySpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/SummonFireflySpell.cs new file mode 100644 index 0000000..fb54e56 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/SummonFireflySpell.cs @@ -0,0 +1,49 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Druid +{ + public class FireflySpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Firefly", "Kes En Crur", + //SpellCircle.First, + 269, + 9020, + false, + Reagent.SulfurousAsh, + Reagent.Pumice + ); + + public FireflySpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.First; } } + public override double RequiredSkill{ get{ return 1.0; } } + public override int RequiredMana{ get{ return 10; } } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + SpellHelper.Summon( new FireflyFamiliar(), Caster, 0x217, TimeSpan.FromSeconds( 4.0 * Caster.Skills[SkillName.Herding].Value ), false, false ); + } + + FinishSequence(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/SummonedTreefellow.cs b/Scripts/Vivre/DuidismeVivre/Spells/SummonedTreefellow.cs new file mode 100644 index 0000000..7fb060d --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/SummonedTreefellow.cs @@ -0,0 +1,56 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName( "a treefellow corpse" )] + public class SummonedTreefellow : BaseCreature + { + [Constructable] + public SummonedTreefellow() : base( AIType.AI_Melee, FightMode.Evil, 10, 1, 0.2, 0.4 ) + { + Name = "a treefellow"; + Body = 301; + BaseSoundID = 442; + + SetStr( 196, 220 ); + SetDex( 31, 55 ); + SetInt( 66, 90 ); + + SetHits( 118, 132 ); + + SetDamage( 12, 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 20, 25 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance( ResistanceType.Poison, 30, 35 ); + SetResistance( ResistanceType.Energy, 20, 30 ); + + SetSkill( SkillName.MagicResist, 65.0 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Wrestling, 90.0 ); + + VirtualArmor = 34; + ControlSlots = 2; + } + + public SummonedTreefellow( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/SwarmofInsectsSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/SwarmofInsectsSpell.cs new file mode 100644 index 0000000..4ce6370 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/SwarmofInsectsSpell.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Druid +{ + public class SwarmOfInsectsSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Swarm Of Insects", "Ess Ohm En Sec Tia", + //SpellCircle.Seventh, + 263, + 9032, + false, + Reagent.SulfurousAsh, + Reagent.Bloodmoss, + Reagent.Pumice + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 2 ); } } + public override SpellCircle Circle { get { return SpellCircle.Seventh; } } + public override double RequiredSkill{ get{ return 75.0; } } + public override int RequiredMana{ get{ return 60; } } + + public SwarmOfInsectsSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( Mobile m ) + { + if ( CheckHSequence( m ) ) + { + SpellHelper.Turn( Caster, m ); + + SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + //SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); + + CheckResisted( m ); // Check magic resist for skill, but do not use return value + + m.FixedParticles( 0x91B, 1, 240, 9916, 0, 3, EffectLayer.Head ); + m.PlaySound( 0x1E5 ); + + double damage = ((Caster.Skills[CastSkill].Value - m.Skills[SkillName.Herding].Value) / 10) + 30; + + if ( damage < 1 ) + damage = 1; + + if ( m_Table.Contains( m ) ) + damage /= 10; + else + new InternalTimer( m, damage * 0.5 ).Start(); + + SpellHelper.Damage( this, m, damage ); + } + + FinishSequence(); + } + + private static Hashtable m_Table = new Hashtable(); + + private class InternalTimer : Timer + { + private Mobile m_Mobile; + private int m_ToRestore; + + public InternalTimer( Mobile m, double toRestore ) : base( TimeSpan.FromSeconds( 20.0 ) ) + { + Priority = TimerPriority.OneSecond; + + m_Mobile = m; + m_ToRestore = (int)toRestore; + + m_Table[m] = this; + } + + protected override void OnTick() + { + m_Table.Remove( m_Mobile ); + + if ( m_Mobile.Alive ) + m_Mobile.Hits += m_ToRestore; + } + } + + private class InternalTarget : Target + { + private SwarmOfInsectsSpell m_Owner; + + public InternalTarget( SwarmOfInsectsSpell owner ) : base( 12, false, TargetFlags.Harmful ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + if ( o is Mobile ) + m_Owner.Target( (Mobile) o ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/TreefellowSpell.cs b/Scripts/Vivre/DuidismeVivre/Spells/TreefellowSpell.cs new file mode 100644 index 0000000..62e3b01 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/TreefellowSpell.cs @@ -0,0 +1,57 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Spells.Druid +{ + public class TreefellowSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Summon Treefellow", "Kes En Ohm Sepa", + //SpellCircle.Eighth, + 269, + 9020, + false, + Reagent.SpringWater, + Reagent.Bloodmoss, + Reagent.PetrifiedWood + ); + + public TreefellowSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + public override double RequiredSkill{ get{ return 80.0; } } + public override int RequiredMana{ get{ return 50; } } + + public override bool CheckCast() + { + if ( !base.CheckCast() ) + return false; + + if ( (Caster.Followers + 2) > Caster.FollowersMax ) + { + Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature. + return false; + } + + return true; + } + + public override void OnCast() + { + if ( CheckSequence() ) + { + if ( Core.AOS ) + SpellHelper.Summon( new SummonedTreefellow(), Caster, 0x217, TimeSpan.FromSeconds( 4.0 * Caster.Skills[SkillName.Herding].Value ), false, false ); + else + SpellHelper.Summon( new Treefellow(), Caster, 0x217, TimeSpan.FromSeconds( 4.0 * Caster.Skills[SkillName.Herding].Value ), false, false ); + } + + FinishSequence(); + } + } +} diff --git a/Scripts/Vivre/DuidismeVivre/Spells/VolcanicEruption.cs b/Scripts/Vivre/DuidismeVivre/Spells/VolcanicEruption.cs new file mode 100644 index 0000000..9541635 --- /dev/null +++ b/Scripts/Vivre/DuidismeVivre/Spells/VolcanicEruption.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Spells.Druid +{ + public class VolcanicEruptionSpell : DruidicSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Volcanic Eruption", "Vauk Ohm En Tia Crur", + //SpellCircle.Eighth, + 245, + 9042, + false, + Reagent.SulfurousAsh, + Reagent.Pumice + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1 ); } } + public override SpellCircle Circle { get { return SpellCircle.Eighth; } } + public override double RequiredSkill{ get{ return 98.0; } } + public override int RequiredMana{ get{ return 85; } } + + public VolcanicEruptionSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) + { + } + + public override void OnCast() + { + Caster.Target = new InternalTarget( this ); + } + + public void Target( IPoint3D p ) + { + if ( !Caster.CanSee( p ) ) + { + Caster.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + else if ( /*SpellHelper.CheckTown( p, Caster ) &&*/ CheckSequence() ) + { + SpellHelper.Turn( Caster, p ); + + if ( p is Item ) + p = ((Item)p).GetWorldLocation(); + + double damage = Utility.Random( 27, 22 ); + + ArrayList targets = new ArrayList(); + + IPooledEnumerable eable = Caster.Map.GetMobilesInRange( new Point3D( p ), 1 + (int)(Caster.Skills[DamageSkill].Value / 10.0) ); + + foreach ( Mobile m in eable ) + { + if ( SpellHelper.ValidIndirectTarget( Caster, m ) && Caster.CanBeHarmful( m, false ) ) + targets.Add( m ); + } + + eable.Free(); + + if ( targets.Count > 0 ) + { + //damage /= targets.Count; // ~ divides damage between targets, kinda sux + + for ( int i = 0; i < targets.Count; ++i ) + { + Mobile m = (Mobile)targets[i]; + + double toDeal = damage; + + if ( CheckResisted( m ) ) + { + toDeal *= 0.7; + + m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy. + } + + Caster.DoHarmful( m ); + SpellHelper.Damage( this, m, toDeal, 50, 100, 0, 0, 0 ); + + m.FixedParticles( 0x3709, 20, 10, 5044, EffectLayer.RightFoot ); + m.PlaySound( 0x21F ); + m.FixedParticles( 0x36BD, 10, 30, 5052, EffectLayer.Head ); + m.PlaySound( 0x208 ); + + } + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private VolcanicEruptionSpell m_Owner; + + public InternalTarget( VolcanicEruptionSpell owner ) : base( 12, true, TargetFlags.None ) + { + m_Owner = owner; + } + + protected override void OnTarget( Mobile from, object o ) + { + IPoint3D p = o as IPoint3D; + + if ( p != null ) + m_Owner.Target( p ); + } + + protected override void OnTargetFinish( Mobile from ) + { + m_Owner.FinishSequence(); + } + } + } +} + diff --git a/Scripts/Vivre/Engines/Agriculture/AgricultureTextes.cs b/Scripts/Vivre/Engines/Agriculture/AgricultureTextes.cs new file mode 100644 index 0000000..11bde7f --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/AgricultureTextes.cs @@ -0,0 +1,36 @@ +using System; + +namespace Server.Items.Crops +{ + public class AgriTxt + { + // Misc + public static String Seed = "Graine"; + public static String Seedling = "Pousse"; + public static String Root = "Racine"; + + // Crops + public static String CannotWorkMounted = "Vous ne pouvez planter en étant sur votre monture."; + public static String CannotGrowHere = "Cette graine ne germera pas ici."; + public static String AlreadyCrop = "Il y a deja une graine de plantée ici."; + public static String TooMuchCrops = "Il y a trop de pousses ici."; + public static String CropPlanted = "Vous plantez la graine."; + public static String PickCrop = "Vous arrachez la pousse."; + public static String TooYoungCrop = "La pousse est trop jeune pour être arrachée."; + public static String WitherCrop = "La plante se flétrit."; + public static String DunnoHowTo = "Vous ne savez pas comment cultiver cela."; + public static String NoCrop = "Il n y a rien à cultiver ici."; + public static String ZeroPicked = "Vous n'obtenez pas de récolte."; + public static String YouPick = "Vous récoltez"; // x plante(s) + public static String TooFar = "Vous êtes trop loin pour cultiver."; + + // Roots + public static String PullRoot = "Vous tirez sur la plante par la racine."; + public static String HardPull = "La plante est dure à arracher."; + public static String NoRoot = "Vous ne trouvez pas de racines utilisables."; + public static String YouCut = "Vous coupez"; + + // Tree + public static String LogsAndFruits = "Vous mettez quelques bûches et des fruits dans votre sac."; + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/CabbageCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/CabbageCrop.00.ScZ.cs new file mode 100644 index 0000000..5f811aa --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/CabbageCrop.00.ScZ.cs @@ -0,0 +1,404 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class CabbageSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public CabbageSeed() + : this(1) + { + } + + [Constructable] + public CabbageSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Chou"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 6 maybe 5 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 5) || ((cropsnear.Count == 5) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new CabbageSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public CabbageSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class CabbageSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public CabbageSeedling(Mobile sower) + : base(0xCB5) + { + Movable = false; + Name = AgriTxt.Seedling + " de Chou"; + m_sower = sower; + + init(this); + } + + public static void init(CabbageSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(CabbageCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public CabbageSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class CabbageCrop : BaseCrop + { + private const int max = 1; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] // debuging + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public CabbageCrop(Mobile sower) + : base(0xC61) + { + Movable = false; + Name = "Chou"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + public static void init(CabbageCrop plant, bool full) + { + plant.PickGraphic = (0xC61); + plant.FullGraphic = (0xC7C); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} chou{1}!", pick, (pick == 1 ? "" : "x")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Cabbage crop = new Cabbage(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + //regrowTimer = new CropTimer( this ); + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private CabbageCrop i_plant; + + public CropTimer(CabbageCrop plant) + : base(TimeSpan.FromSeconds(450), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if (Utility.RandomBool()) + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + } + + public CabbageCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/CarrotCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/CarrotCrop.00.ScZ.cs new file mode 100644 index 0000000..3b78a0a --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/CarrotCrop.00.ScZ.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class CarrotSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public CarrotSeed() + : this(1) + { + } + + [Constructable] + public CarrotSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Carottes"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 3) || ((cropsnear.Count == 3) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new CarrotSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public CarrotSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class CarrotSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public CarrotSeedling(Mobile sower) + : base(0xC68) + { + Movable = false; + Name = AgriTxt.Seedling + " de Carottes"; + m_sower = sower; + + init(this); + } + + public static void init(CarrotSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(CarrotCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public CarrotSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class CarrotCrop : BaseCrop + { + private const int max = 6; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] // debuging + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public CarrotCrop(Mobile sower) + : base(0xC69) + { + Movable = false; + Name = "Botte de Carottes"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + [Constructable] + public CarrotCrop() + : this(null) + { + } + + public static void init(CarrotCrop plant, bool full) + { + plant.PickGraphic = (0xC69); + plant.FullGraphic = (0xC76); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} carotte{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Carrot crop = new Carrot(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private CarrotCrop i_plant; + + public CropTimer(CarrotCrop plant) + : base(TimeSpan.FromSeconds(600), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public CarrotCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/CornCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/CornCrop.00.ScZ.cs new file mode 100644 index 0000000..cd247bb --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/CornCrop.00.ScZ.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class CornSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public CornSeed() + : this(1) + { + } + + [Constructable] + public CornSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de ma�s"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 3) || ((cropsnear.Count == 3) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new CornSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public CornSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class CornSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public CornSeedling(Mobile sower) + : base(0xCB5) + { + Movable = false; + Name = AgriTxt.Seedling + " de ma�s"; + m_sower = sower; + + init(this); + } + + public static void init(CornSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(CornCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public CornSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class CornCrop : BaseCrop + { + private const int max = 3; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] // debuging + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public CornCrop(Mobile sower) + : base(0xC7E) + { + Movable = false; + Name = "Epi de ma�s"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + public static void init(CornCrop plant, bool full) + { + plant.PickGraphic = (0xC7E); + plant.FullGraphic = (0xC7D); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + // *** Limit to one yield until we have Corn item *** + if (pick > 1) pick = 1; + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} �pi{1} de ma�s!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + // ******************************* + // *** Corn does not yet exist *** + // ******************************* + //Corn crop = new Corn( pick ); + Muffins crop = new Muffins(); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private CornCrop i_plant; + + public CropTimer(CornCrop plant) + : base(TimeSpan.FromSeconds(600), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public CornCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/CottonCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/CottonCrop.00.ScZ.cs new file mode 100644 index 0000000..c101473 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/CottonCrop.00.ScZ.cs @@ -0,0 +1,392 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class CottonSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public CottonSeed() : this( 1 ) + { + } + + [Constructable] + public CottonSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de coton"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 1 ); + if ( ( cropsnear.Count > 3 ) || (( cropsnear.Count == 3 ) && Utility.RandomBool() ) ) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new CottonSeedling( from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public CottonSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + + public class CottonSeedling : BaseCrop + { + private Mobile m_sower; + public Timer thisTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [Constructable] + public CottonSeedling( Mobile sower ) : base( Utility.RandomList ( 0xC51, 0xC52 ) ) + { + Movable = false; + Name = AgriTxt.Seedling + " de Coton"; + m_sower = sower; + + init( this ); + } + + public static void init( CottonSeedling plant ) + { + plant.thisTimer = new CropHelper.GrowTimer( plant, typeof(CottonCrop), plant.Sower ); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( ( Utility.RandomDouble() <= .25 ) && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public CottonSeedling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + writer.Write( m_sower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init( this ); + } + } + + public class CottonCrop : BaseCrop + { + private const int max = 10; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastSowerVisit{ get{ return m_lastvisit; } } + + [CommandProperty( AccessLevel.GameMaster )] // debuging + public bool Growing{ get{ return regrowTimer.Running; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public int FullGraphic{ get{ return fullGraphic; } set{ fullGraphic = value; } } + public int PickGraphic{ get{ return pickedGraphic; } set{ pickedGraphic = value; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public CottonCrop( Mobile sower ) : base( Utility.RandomList( 0xC53, 0xC54 ) ) + { + Movable = false; + Name = "Plant de Coton"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init( this, false ); + } + + public static void init ( CottonCrop plant, bool full ) + { + plant.PickGraphic = Utility.RandomList( 0xC53, 0xC54 ); + plant.FullGraphic = Utility.RandomList( 0xC4F, 0xC50 ); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot( Mobile from ) + { + from.SendMessage( AgriTxt.WitherCrop ); + if ( regrowTimer.Running ) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_sower == null || m_sower.Deleted ) + m_sower = from; + + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( lumberValue < 2 ) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage(AgriTxt.NoCrop); + + if ( PlayerCanDestroy && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { + UpRootGump g = new UpRootGump( from, this ); + from.SendGump( g ); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 29:32, 5, 1, true, false, 0 ); + + if ( from == m_sower ) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage( AgriTxt.YouPick + " {0} coton{1}!", pick, ( pick == 1 ? "" : "s" ) ); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Cotton crop = new Cotton( pick ); + from.AddToBackpack( crop ); + + if ( SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { + this.UpRoot( from ); + return; + } + + if ( !regrowTimer.Running ) + { + //regrowTimer = new CropTimer( this ); + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private CottonCrop i_plant; + + public CropTimer( CottonCrop plant ) : base( TimeSpan.FromSeconds( 600 ), TimeSpan.FromSeconds( 15 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public CottonCrop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_lastvisit ); + writer.Write( m_sower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + switch ( version ) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if ( version == 0 ) + m_lastvisit = DateTime.Now; + + init( this, true ); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/CropHelper.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/CropHelper.00.ScZ.cs new file mode 100644 index 0000000..9f8a3ed --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/CropHelper.00.ScZ.cs @@ -0,0 +1,367 @@ +using System; +using Server; +using System.Collections; +using Server.Network; +using Server.Gumps; +using Server.Items; + +namespace Server.Items.Crops +{ + public class BaseCrop : Item + { + // Set defaults here for all Crop types + // Override in Seed scripts to modify per crop type + public virtual bool CanGrowFarm{ get{ return true; } } + public virtual bool CanGrowDirt{ get{ return false; } } // false + public virtual bool CanGrowGround { get { return false; } } // false + public virtual bool CanGrowSwamp { get { return false; } } // false + public virtual bool CanGrowSand { get { return false; } } // false + // For Player Deeded Plots + public virtual bool CanGrowGarden{ get{ return true; } } + + // Default time in which sower must reharvest his crops + // Use TimeSpan.Zero to disable crop decays + // May be overridden in individual Crop scripts + public virtual TimeSpan SowerPickTime{ get{ return TimeSpan.FromDays( 14 ); } } + + // If true any Player can destroy a crop, overriddable in Crop scripts + public virtual bool PlayerCanDestroy{ get{ return false; } } + + private bool i_bumpZ = false; + public bool BumpZ + { + get{ return i_bumpZ; } + set{ i_bumpZ = value; } + } + + public BaseCrop( int itemID ) : base( itemID ) + { + } + + public BaseCrop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class CropHelper + { + // if true Player cannot plant or pick while mounted + public static bool CanWorkMounted{ get{ return false; } } + + public static int[] FarmTiles = new int[] + { + 0x009, 0x00A, + 0x00C, 0x00E, + 0x013, 0x015, + 0x150, 0x155, + 0x15A, 0x15C, + 0x31F8 + }; + + public static int[] DirtTiles = new int[] + { + 0x071, 0x07C, // Roads + 0x165, 0x174, // Roads + 0x1DC, 0x1EF, // Rock Border + 0x306, 0x31F, // Snow Border + 0x08D, 0x0A7, // Steep Slopes + 0x2E5, 0x305, // Steep Slopes + 0x777, 0x791, // Steep Slopes + 0x98C, 0x9BF, // Steep Slopes + }; + + public static int[] GroundTiles = new int[] + { + 0x003, 0x006, + 0x033, 0x03E, + 0x078, 0x08C, + 0x0AC, 0x0DB, + 0x108, 0x10B, + 0x14C, 0x174, + 0x1A4, 0x1A7, + 0x1B1, 0x1B2, + 0x26E, 0x281, + 0x292, 0x295, + 0x355, 0x37E, + 0x3CB, 0x3CE, + 0x547, 0x5A6, + 0x5E3, 0x618, + 0x66B, 0x66E, + 0x6A1, 0x6C2, + 0x6DE, 0x6E1, + 0x73F, 0x742, + }; + + public static int[] SwampTiles = new int[] + { + //0x7DC, 0x808, + 0x3DC1, 0x3DC2, + 0x3DD9, 0x3EF0, + }; + + public static int[] SandTiles = new int[] + { + 0x016, 0x019, + 0x033, 0x03E, + 0x1A8, 0x1AB, + 0x282, 0x291, + 0x335, 0x35C, + 0x3B7, 0x3CA, + 0x5A7, 0x5BA, + 0x64B, 0x66A, + 0x66F, 0x672, + 0x7D5, 0x7D8, + }; + + public static bool CheckCanGrow( BaseCrop crop, Map map, int x, int y ) + { + if ( crop.CanGrowFarm && ValidateFarmLand( map, x, y ) ) + return true; + if ( crop.CanGrowDirt && ValidateDirt( map, x, y ) ) + return true; + if ( crop.CanGrowGround && ValidateGround( map, x, y ) ) + return true; + if ( crop.CanGrowSand && ValidateSand( map, x, y ) ) + return true; + if ( crop.CanGrowSwamp && ValidateSwamp( map, x, y ) ) + return true; + if ( crop.CanGrowGarden ) + { + crop.BumpZ = ValidateGardenPlot( map, x, y ); + return crop.BumpZ; + } + return false; + } + + public static bool ValidateGardenPlot( Map map, int x, int y ) + { + bool ground = false; + + // Test for Dynamic Item + IPooledEnumerable eable = map.GetItemsInBounds( new Rectangle2D( x, y, 1, 1 ) ); + foreach( Item item in eable ) + { + if( item.ItemID == 0x32C9 ) // dirt; possibly also 0x32CA + ground = true; + } + eable.Free(); + + // Test for Frozen into Map + if ( !ground ) + { + StaticTile[] tiles = map.Tiles.GetStaticTiles(x, y, true); + for ( int i = 0; i < tiles.Length; ++i ) + { + if ( ( tiles[i].ID & 0x3FFF ) == 0x32C9 ) + ground = true; + } + } + + return ground; + } + + public static bool ValidateFarmLand( Map map, int x, int y ) + { + // Je mets un try... catch pour etre sur que ca plante pus + try + { + int tileID = map.Tiles.GetLandTile( x, y ).ID & 0x3FFF; + bool ground = false; + + for ( int i = 0; !ground && i < FarmTiles.Length; i += 2 ) + // L'erreur est surment ici + ground = ( tileID >= FarmTiles[i] && tileID <= FarmTiles[i + 1] ); + + return ground; + } catch + { + // Il y a une erreur dans cette fonction + // Un Out of Range + return false; + } + } + + public static bool ValidateDirt( Map map, int x, int y ) + { + int tileID = map.Tiles.GetLandTile( x, y ).ID & 0x3FFF; + bool ground = false; + + for ( int i = 0; !ground && i < DirtTiles.Length; i += 2 ) + ground = ( tileID >= DirtTiles[i] && tileID <= DirtTiles[i + 1] ); + + return ground; + } + + public static bool ValidateGround( Map map, int x, int y ) + { + int tileID = map.Tiles.GetLandTile( x, y ).ID & 0x3FFF; + bool ground = false; + + for ( int i = 0; !ground && i < GroundTiles.Length; i += 2 ) + ground = ( tileID >= GroundTiles[i] && tileID <= GroundTiles[i + 1] ); + + return ground; + } + + public static bool ValidateSwamp( Map map, int x, int y ) + { + int tileID = map.Tiles.GetLandTile( x, y ).ID & 0x3FFF; + bool ground = false; + + for ( int i = 0; !ground && i < SwampTiles.Length; i += 2 ) + ground = ( tileID >= SwampTiles[i] && tileID <= SwampTiles[i + 1] ); + + return ground; + } + + public static bool ValidateSand( Map map, int x, int y ) + { + int tileID = map.Tiles.GetLandTile( x, y ).ID & 0x3FFF; + bool ground = false; + + for ( int i = 0; !ground && i < SandTiles.Length; i += 2 ) + ground = ( tileID >= SandTiles[i] && tileID <= SandTiles[i + 1] ); + + return ground; + } + + public class GrowTimer : Timer + { + private Item i_seedling; + private Type t_crop; + private Mobile m_sower; + private int cnt; + private double lumberValue; + private double rnd; + + public GrowTimer( Item seedling, Type croptype, Mobile sower ) : base( TimeSpan.FromSeconds( 600 ), TimeSpan.FromSeconds( 12 ) ) + { + Priority = TimerPriority.OneSecond; + i_seedling = seedling; + t_crop = croptype; + m_sower = sower; + cnt = 0; + + rnd = Utility.RandomDouble(); + lumberValue = sower.Skills[SkillName.Lumberjacking].Value / 100; + } + + protected override void OnTick() + { + if ( cnt++ / 100 > rnd ) // between 10 and 30 minutes + { + if (( i_seedling != null ) && ( !i_seedling.Deleted )) + { + object[] args = {m_sower}; + Item newitem = Activator.CreateInstance( t_crop, args ) as Item; + + if ( newitem == null || Utility.RandomDouble() > lumberValue ) + { + newitem = new Weeds( m_sower ); + } + + newitem.Location = i_seedling.Location; + newitem.Map = i_seedling.Map; + i_seedling.Delete(); + } + Stop(); + } + } + } + + public static ArrayList CheckCrop( Point3D pnt, Map map, int range ) + { + ArrayList crops = new ArrayList(); + + IPooledEnumerable eable = map.GetItemsInRange( pnt, range ); + foreach ( Item crop in eable ) + { + if ( ( crop != null ) && ( crop is BaseCrop ) ) + crops.Add( (BaseCrop)crop ); + } + eable.Free(); + + return crops; + } + + public class Weeds : BaseCrop + { + private static DateTime planted; + private static Mobile m_sower; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [Constructable] + public Weeds( Mobile sower ) : base( Utility.RandomList( 0xCAD, 0xCAE, 0xCAF ) ) + { + Movable = false; + Name = "Mauvaise herbe"; + + m_sower = sower; + planted = DateTime.Now; + } + + public override void OnDoubleClick(Mobile from) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if (( from == m_sower ) || ( DateTime.Now >= planted.AddDays(3) )) + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 29:32, 5, 1, true, false, 0 ); + + from.SendMessage(AgriTxt.PickCrop); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + + public Weeds( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + writer.Write( m_sower ); + writer.Write((string) planted.ToString()); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + planted = DateTime.Parse(reader.ReadString()); + } + } + } +} + + diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/FlaxCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/FlaxCrop.00.ScZ.cs new file mode 100644 index 0000000..9399eb2 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/FlaxCrop.00.ScZ.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class FlaxSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public FlaxSeed() + : this(1) + { + } + + [Constructable] + public FlaxSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Lin"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 3) || ((cropsnear.Count == 3) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new FlaxSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public FlaxSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class FlaxSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public FlaxSeedling(Mobile sower) + : base(0x1A99) + { + Movable = false; + Name = AgriTxt.Seedling + " de lin"; + m_sower = sower; + + init(this); + } + + public static void init(FlaxSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(FlaxCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public FlaxSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class FlaxCrop : BaseCrop + { + private const int max = 10; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] // debuging + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public FlaxCrop(Mobile sower) + : base(0x1A9A) + { + Movable = false; + Name = "Fleurs de Lin"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + public static void init(FlaxCrop plant, bool full) + { + plant.PickGraphic = (0x1A9A); + plant.FullGraphic = (0x1A9B); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue < 2) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} fleur{1} de lin!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Flax crop = new Flax(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private FlaxCrop i_plant; + + public CropTimer(FlaxCrop plant) + : base(TimeSpan.FromSeconds(600), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public FlaxCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/GarlicCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/GarlicCrop.00.ScZ.cs new file mode 100644 index 0000000..a805882 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/GarlicCrop.00.ScZ.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class GarlicSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public GarlicSeed() + : this(1) + { + } + + [Constructable] + public GarlicSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = "Bulbe d'ail"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 3) || ((cropsnear.Count == 3) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new GarlicSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public GarlicSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class GarlicSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public GarlicSeedling(Mobile sower) + : base(0xC68) + { + Movable = false; + Name = AgriTxt.Seedling + " d'ail"; + m_sower = sower; + + init(this); + } + + public static void init(GarlicSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(GarlicCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public GarlicSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class GarlicCrop : BaseCrop + { + private const int max = 4; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] // debuging + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public GarlicCrop(Mobile sower) + : base(0xC69) + { + Movable = false; + Name = "Gousse d'ail"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + public static void init(GarlicCrop plant, bool full) + { + plant.PickGraphic = (0xC69); + plant.FullGraphic = (0xC6F); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} gousse{1} d'ail!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Garlic crop = new Garlic(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private GarlicCrop i_plant; + + public CropTimer(GarlicCrop plant) + : base(TimeSpan.FromSeconds(600), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public GarlicCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/Hops.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/Hops.00.ScZ.cs new file mode 100644 index 0000000..5d66c22 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/Hops.00.ScZ.cs @@ -0,0 +1,44 @@ +using System; + +namespace Server.Items +{ + public class Hop : Item + { + + + [Constructable] + public Hop() + : this(1) + { + } + + [Constructable] + public Hop(int amount) + : base(0x1AA2) + { + Stackable = false; + Weight = 0.1; + Amount = amount; + Name = "Houblon"; + } + + public Hop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/HoublonCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/HoublonCrop.00.ScZ.cs new file mode 100644 index 0000000..d7b261a --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/HoublonCrop.00.ScZ.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class HoublonSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public HoublonSeed() + : this(1) + { + } + + [Constructable] + public HoublonSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Houblon"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 3) || ((cropsnear.Count == 3) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new HoublonSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public HoublonSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class HoublonSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public HoublonSeedling(Mobile sower) + : base(Utility.RandomList(0xC60, 0xC5E)) + { + Movable = false; + Name = AgriTxt.Seedling + " de Houblon"; + m_sower = sower; + + init(this); + } + + public static void init(HoublonSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(HoublonCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public HoublonSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class HoublonCrop : BaseCrop + { + private const int max = 10; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public HoublonCrop(Mobile sower) + : base(Utility.RandomList(0xC60, 0xC5E)) + { + Movable = false; + Name = "Plant de Houblon"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + [Constructable] + public HoublonCrop() + : this(null) + { + } + + public static void init(HoublonCrop plant, bool full) + { + plant.PickGraphic = Utility.RandomList(0xC60, 0xC5E); + plant.FullGraphic = Utility.RandomList(0x1A9E, 0x1A9F, 0x1AA0, 0x1AA1); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} houblon{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); // use for debuging + ((Item)this).ItemID = pickedGraphic; + + Hop crop = new Hop(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private HoublonCrop i_plant; + + public CropTimer(HoublonCrop plant) + : base(TimeSpan.FromSeconds(600), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); // use for debuging + } + else Stop(); + } + } + + public HoublonCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/LettuceCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/LettuceCrop.00.ScZ.cs new file mode 100644 index 0000000..708ae12 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/LettuceCrop.00.ScZ.cs @@ -0,0 +1,403 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class LettuceSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public LettuceSeed() + : this(1) + { + } + + [Constructable] + public LettuceSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Laitue"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 6 maybe 5 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 5) || ((cropsnear.Count == 5) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new LettuceSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public LettuceSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class LettuceSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public LettuceSeedling(Mobile sower) + : base(0xCB5) + { + Movable = false; + Name = AgriTxt.Seedling + " de laitue"; + m_sower = sower; + + init(this); + } + + public static void init(LettuceSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(LettuceCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public LettuceSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class LettuceCrop : BaseCrop + { + private const int max = 1; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] // debuging + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public LettuceCrop(Mobile sower) + : base(0xC61) + { + Movable = false; + Name = "Laitue"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + public static void init(LettuceCrop plant, bool full) + { + plant.PickGraphic = (0xC61); + plant.FullGraphic = (0xC70); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} laitue{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Lettuce crop = new Lettuce(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + //regrowTimer = new CropTimer( this ); + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private LettuceCrop i_plant; + + public CropTimer(LettuceCrop plant) + : base(TimeSpan.FromSeconds(450), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if (Utility.RandomBool()) + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + } + + public LettuceCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/OnionCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/OnionCrop.00.ScZ.cs new file mode 100644 index 0000000..c49bf99 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/OnionCrop.00.ScZ.cs @@ -0,0 +1,391 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class OnionSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public OnionSeed() : this( 1 ) + { + } + + [Constructable] + public OnionSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = "Bulbe d'oignon"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 1 ); + if ( ( cropsnear.Count > 3 ) || (( cropsnear.Count == 3 ) && Utility.RandomBool() ) ) + { + from.SendMessage( AgriTxt.TooMuchCrops); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new OnionSeedling( from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public OnionSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + + public class OnionSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [Constructable] + public OnionSeedling( Mobile sower ) : base( 0xC68 ) + { + Movable = false; + Name = AgriTxt.Seedling + " d'oignon"; + m_sower = sower; + + init( this ); + } + + public static void init( OnionSeedling plant ) + { + plant.thisTimer = new CropHelper.GrowTimer( plant, typeof(OnionCrop), plant.Sower ); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( ( Utility.RandomDouble() <= .25 ) && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { //25% Chance + from.SendMessage( AgriTxt.PickCrop ); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop ); + } + + public OnionSeedling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + writer.Write( m_sower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init( this ); + } + } + + public class OnionCrop : BaseCrop + { + private const int max = 6; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastSowerVisit{ get{ return m_lastvisit; } } + + [CommandProperty( AccessLevel.GameMaster )] // debuging + public bool Growing{ get{ return regrowTimer.Running; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public int FullGraphic{ get{ return fullGraphic; } set{ fullGraphic = value; } } + public int PickGraphic{ get{ return pickedGraphic; } set{ pickedGraphic = value; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public OnionCrop( Mobile sower ) : base( 0xC69 ) + { + Movable = false; + Name = "Gousse d'oignon"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init( this, false ); + } + + public static void init ( OnionCrop plant, bool full ) + { + plant.PickGraphic = ( 0xC69 ); + plant.FullGraphic = ( 0xC6F ); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot( Mobile from ) + { + from.SendMessage(AgriTxt.WitherCrop); + if ( regrowTimer.Running ) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_sower == null || m_sower.Deleted ) + m_sower = from; + + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( lumberValue == 0 ) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage(AgriTxt.NoCrop); + + if ( PlayerCanDestroy && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { + UpRootGump g = new UpRootGump( from, this ); + from.SendGump( g ); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 29:32, 5, 1, true, false, 0 ); + + if ( from == m_sower ) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage( AgriTxt.YouPick + " {0} gousse{1} d'oignon!", pick, ( pick == 1 ? "" : "s" ) ); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + ((Item)this).ItemID = pickedGraphic; + + Onion crop = new Onion( pick ); + from.AddToBackpack( crop ); + + if ( SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { + this.UpRoot( from ); + return; + } + + if ( !regrowTimer.Running ) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private OnionCrop i_plant; + + public CropTimer( OnionCrop plant ) : base( TimeSpan.FromSeconds( 600 ), TimeSpan.FromSeconds( 15 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public OnionCrop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_lastvisit ); + writer.Write( m_sower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + switch ( version ) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if ( version == 0 ) + m_lastvisit = DateTime.Now; + + init( this, true ); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/OrgeCrop.cs b/Scripts/Vivre/Engines/Agriculture/Crops/OrgeCrop.cs new file mode 100644 index 0000000..c4e4058 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/OrgeCrop.cs @@ -0,0 +1,397 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class OrgeSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public OrgeSeed() : this( 1 ) + { + } + + [Constructable] + public OrgeSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = "Semence d'orge"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage( "Vous ne pouvez planter sur ce type de terrain" ); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage( "Cette graine ne germera pas ici" ); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage( "Il y a deja une graine de plante ici." ); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 1 ); + if ( ( cropsnear.Count > 3 ) || (( cropsnear.Count == 3 ) && Utility.RandomBool() ) ) + { + from.SendMessage( "Il y a trop de pouce ici." ); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage("Vous plantez la graine."); + this.Consume(); + Item item = new OrgeSeedling( from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public OrgeSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + + public class OrgeSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [Constructable] + public OrgeSeedling( Mobile sower ) : base( Utility.RandomList ( 0xDAE, 0xDAF ) ) + { + Movable = false; + Name = "Orge pouce"; + m_sower = sower; + this.Hue = 0x28E; + init( this ); + } + + public static void init( OrgeSeedling plant ) + { + + plant.thisTimer = new CropHelper.GrowTimer( plant, typeof(OrgeCrop), plant.Sower ); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage( "Vous ne pouvez cultiver ici" ); + return; + } + + if ( ( Utility.RandomDouble() <= .25 ) && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { //25% Chance + from.SendMessage( "Vous arrachez la pouce" ); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage( "La pouce est trop jeune pour etre arrache" ); + } + + public OrgeSeedling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + writer.Write( m_sower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init( this ); + } + } + + public class OrgeCrop : BaseCrop + { + private const int max = 10; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastSowerVisit{ get{ return m_lastvisit; } } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Growing{ get{ return regrowTimer.Running; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Sower{ get{ return m_sower; } set{ m_sower = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public int FullGraphic{ get{ return fullGraphic; } set{ fullGraphic = value; } } + public int PickGraphic{ get{ return pickedGraphic; } set{ pickedGraphic = value; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public OrgeCrop( Mobile sower ) : base( Utility.RandomList( 0xC55, 0xC56 ) ) + { + Movable = false; + Name = "Orge Plante"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init( this, false ); + } + + public static void init ( OrgeCrop plant, bool full ) + { + plant.PickGraphic = Utility.RandomList( 0xC55, 0xC56, 0xC57, 0xC59 ); + plant.FullGraphic = Utility.RandomList( 0xC58, 0xC5A, 0xC5B ); + plant.Hue = 0x28E; + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot( Mobile from ) + { + from.SendMessage( "The crop withers away." ); + if ( regrowTimer.Running ) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( m_sower == null || m_sower.Deleted ) + m_sower = from; + + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage( "Vous ne pouvez cultiver ici" ); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( lumberValue == 0 ) + { + from.SendMessage( "Vous ne savez pas comment cultiver cela" ); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage( "Il n y a rien ici a cultiver" ); + + if ( PlayerCanDestroy && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { + UpRootGump g = new UpRootGump( from, this ); + from.SendGump( g ); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 29:32, 5, 1, true, false, 0 ); + + if ( from == m_sower ) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage( "vous n obtenez pas de nouvelle pouce" ); + return; + } + + m_yield -= pick; + from.SendMessage( "Vous Cultivez {0} crop{1}!", pick, ( pick == 1 ? "" : "s" ) ); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); // use for debuging + ((Item)this).ItemID = pickedGraphic; + + // ******************************** + // *** Orge does not yet exist *** + // ******************************** + // Orge crop = new Orge( pick ); + OrgeGerbe crop = new OrgeGerbe( pick ); + from.AddToBackpack( crop ); + + if ( SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !( m_sower.AccessLevel > AccessLevel.Counselor ) ) + { + this.UpRoot( from ); + return; + } + + if ( !regrowTimer.Running ) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage( "Vous etes trop loin pour cultiver" ); + } + } + } + + private class CropTimer : Timer + { + private OrgeCrop i_plant; + + public CropTimer( OrgeCrop plant ) : base( TimeSpan.FromSeconds( 600 ), TimeSpan.FromSeconds( 15 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); // use for debuging + } + else Stop(); + } + } + + public OrgeCrop( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( m_lastvisit ); + writer.Write( m_sower ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + switch ( version ) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if ( version == 0 ) + m_lastvisit = DateTime.Now; + + init( this, true ); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/OrgeGerbe.cs b/Scripts/Vivre/Engines/Agriculture/Crops/OrgeGerbe.cs new file mode 100644 index 0000000..f33fe9a --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/OrgeGerbe.cs @@ -0,0 +1,40 @@ +using System; + +namespace Server.Items +{ + public class OrgeGerbe : Item + { + [Constructable] + public OrgeGerbe() : this( 1 ) + { + } + + [Constructable] + public OrgeGerbe( int amount ) : base( 0X1EBD ) + { + Weight = 1.0; + Stackable = true; + Amount = amount; + Hue = 0x28E; + Name = "Gerbe d'orge"; + } + + public OrgeGerbe( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Crops/WheatCrop.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Crops/WheatCrop.00.ScZ.cs new file mode 100644 index 0000000..1498d96 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Crops/WheatCrop.00.ScZ.cs @@ -0,0 +1,403 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; + +namespace Server.Items.Crops +{ + public class WheatSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public WheatSeed() + : this(1) + { + } + + [Constructable] + public WheatSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de bl�"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 1); + if ((cropsnear.Count > 3) || ((cropsnear.Count == 3) && Utility.RandomBool())) + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new WheatSeedling(from); + item.Location = m_pnt; + item.Map = m_map; + + } + + public WheatSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + + public class WheatSeedling : BaseCrop + { + private static Mobile m_sower; + public Timer thisTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [Constructable] + public WheatSeedling(Mobile sower) + : base(Utility.RandomList(0xDAE, 0xDAF)) + { + Movable = false; + Name = AgriTxt.Seedling + " de bl�"; + m_sower = sower; + + init(this); + } + + public static void init(WheatSeedling plant) + { + plant.thisTimer = new CropHelper.GrowTimer(plant, typeof(WheatCrop), plant.Sower); + plant.thisTimer.Start(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ((Utility.RandomDouble() <= .25) && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { //25% Chance + from.SendMessage(AgriTxt.PickCrop); + thisTimer.Stop(); + this.Delete(); + } + else from.SendMessage(AgriTxt.TooYoungCrop); + } + + public WheatSeedling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_sower = reader.ReadMobile(); + + init(this); + } + } + + public class WheatCrop : BaseCrop + { + private const int max = 10; + private int fullGraphic; + private int pickedGraphic; + private DateTime lastpicked; + + private Mobile m_sower; + private int m_yield; + + public Timer regrowTimer; + + private DateTime m_lastvisit; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime LastSowerVisit { get { return m_lastvisit; } } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Growing { get { return regrowTimer.Running; } } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Sower { get { return m_sower; } set { m_sower = value; } } + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public int FullGraphic { get { return fullGraphic; } set { fullGraphic = value; } } + public int PickGraphic { get { return pickedGraphic; } set { pickedGraphic = value; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public WheatCrop(Mobile sower) + : base(Utility.RandomList(0xC55, 0xC56)) + { + Movable = false; + Name = "Bl�"; + + m_sower = sower; + m_lastvisit = DateTime.Now; + + init(this, false); + } + + public static void init(WheatCrop plant, bool full) + { + plant.PickGraphic = Utility.RandomList(0xC55, 0xC56, 0xC57, 0xC59); + plant.FullGraphic = Utility.RandomList(0xC58, 0xC5A, 0xC5B); + + plant.LastPick = DateTime.Now; + plant.regrowTimer = new CropTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + ((Item)plant).ItemID = plant.FullGraphic; + } + else + { + plant.Yield = 0; + ((Item)plant).ItemID = plant.PickGraphic; + plant.regrowTimer.Start(); + } + } + + public void UpRoot(Mobile from) + { + from.SendMessage(AgriTxt.WitherCrop); + if (regrowTimer.Running) + regrowTimer.Stop(); + + this.Delete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (m_sower == null || m_sower.Deleted) + m_sower = from; + + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (lumberValue == 0) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + + if (PlayerCanDestroy && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + UpRootGump g = new UpRootGump(from, this); + from.SendGump(g); + } + } + else //check skill and sower + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 29 : 32, 5, 1, true, false, 0); + + if (from == m_sower) + { + lumberValue *= 2; + m_lastvisit = DateTime.Now; + } + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} crop{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); // use for debuging + ((Item)this).ItemID = pickedGraphic; + + // ******************************** + // *** Wheat does not yet exist *** + // ******************************** + // Wheat crop = new Wheat( pick ); + BreadLoaf crop = new BreadLoaf(pick); + from.AddToBackpack(crop); + + if (SowerPickTime != TimeSpan.Zero && m_lastvisit + SowerPickTime < DateTime.Now && !(m_sower.AccessLevel > AccessLevel.Counselor)) + { + this.UpRoot(from); + return; + } + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + private class CropTimer : Timer + { + private WheatCrop i_plant; + + public CropTimer(WheatCrop plant) + : base(TimeSpan.FromSeconds(600), TimeSpan.FromSeconds(15)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + ((Item)i_plant).ItemID = i_plant.FullGraphic; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); // use for debuging + } + else Stop(); + } + } + + public WheatCrop(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)1); + writer.Write(m_lastvisit); + writer.Write(m_sower); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + m_lastvisit = reader.ReadDateTime(); + goto case 0; + } + case 0: + { + m_sower = reader.ReadMobile(); + break; + } + } + + if (version == 0) + m_lastvisit = DateTime.Now; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/CouteauJardinier.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Misc/CouteauJardinier.00.ScZ.cs new file mode 100644 index 0000000..859b4a5 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/CouteauJardinier.00.ScZ.cs @@ -0,0 +1,52 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; + +namespace Server.Items +{ + [FlipableAttribute( 3780, 3781 )] + public class couteau : Item + { + [Constructable] + public couteau() : base( 3780 ) + { + Name = "Couteau de jardinier"; + Weight = 1.0; + } + + public couteau( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick( Mobile from ) + { + PlayerMobile pm = from as PlayerMobile; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else + { + from.CloseGump( typeof( UpRootGump ) ); + //from.SendGump( new UpRootGump( from, this ) ); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/DirtCultivable.00.ChS.cs b/Scripts/Vivre/Engines/Agriculture/Misc/DirtCultivable.00.ChS.cs new file mode 100644 index 0000000..9cd4715 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/DirtCultivable.00.ChS.cs @@ -0,0 +1,43 @@ +using System; + +namespace Server.Items +{ + public class DirtCultivable : BaseFloor + { + public static int[] DirtTiles = new int[] + { + 0x31F4, 0x31F5, + 0x31F6, 0x31F7, + 0x31F8, 0x31F9, + 0x31FA, 0x31FB + }; + + [Constructable] + public DirtCultivable() + : base(0x177D, 1) + { + int i = Utility.Random(0, 5); + this.ItemID = DirtTiles[i]; + this.Name = "Terre Labourable"; + } + + public DirtCultivable(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/FarmHand.01.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Misc/FarmHand.01.ScZ.cs new file mode 100644 index 0000000..e769520 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/FarmHand.01.ScZ.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using Server; + +namespace Server.Mobiles +{ + public class FarmHand : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + [Constructable] + public FarmHand() : base("Le Fermier") + { + SetSkill( SkillName.Lumberjacking, 80.0, 100.0 ); + SetSkill( SkillName.TasteID, 80.0, 100.0 ); + Female = false; + } + + public override void InitSBInfo() + { + m_SBInfos.Add( new SBFarmHand() ); + } + + public override VendorShoeType ShoeType + { + get{ return VendorShoeType.Sandals; } + } + + public override int GetShoeHue() + { + return 0; + } + + public override void InitOutfit() + { + base.InitOutfit(); + + AddItem( new Server.Items.WideBrimHat( Utility.RandomNeutralHue() ) ); + } + + public FarmHand( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/GazonCultivable.00.ChS.cs b/Scripts/Vivre/Engines/Agriculture/Misc/GazonCultivable.00.ChS.cs new file mode 100644 index 0000000..4646825 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/GazonCultivable.00.ChS.cs @@ -0,0 +1,41 @@ +using System; + +namespace Server.Items +{ + public class GazonCultivable : BaseFloor + { + public static int[] GazonTiles = new int[] + { + 0x177D, 0x177E, + 0x177F, 0x1780 + }; + + [Constructable] + public GazonCultivable() + : base(0x177D, 1) + { + int i = Utility.Random(0, 3); + this.ItemID = GazonTiles[i]; + this.Name = "Gazon Labourable"; + } + + public GazonCultivable(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/PelleLaboureuseA.00.ChS.c_ b/Scripts/Vivre/Engines/Agriculture/Misc/PelleLaboureuseA.00.ChS.c_ new file mode 100644 index 0000000..cb311db --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/PelleLaboureuseA.00.ChS.c_ @@ -0,0 +1,192 @@ +/** + * Chronos@17/03/09 : Pelle pour labourer la terre Version A + * + * Peut Labourer le gazon + * + **/ + +using System; +using Server; +using Server.Engines.Harvest; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Items; +using Server.Multis; + +namespace Server.Items +{ + public class PelleLaboureuseA : Item + { + private int UsesRemaining; + public static int[] GazonTiles = new int[] //Cases gazon acceptées + { + 0x177D, 0x177E, + 0x177F, 0x1780 + }; + + public static int[] DirtTiles = new int[] //Cases Dirt acceptées + { + 0x31F4, 0x31F5, + 0x31F6, 0x31F7, + 0x31F8, 0x31F9, + 0x31FA, 0x31FB + }; + + + public override void OnDoubleClick(Mobile from) + { + if (!this.IsChildOf(from.Backpack)) + { + from.SendMessage("Vous devez avoir la pelle dans votre inventaire pour pouvoir l'utiliser"); + } + else + { + from.Target = new LabourerTarget(from, from.Map, this); + } + } + + public void decreaseUses(Mobile from) + { + UsesRemaining--; + + if (this.UsesRemaining <= 0) + { + from.SendMessage("La pelle se brise entre vos mains."); + from.PlaySound(0x2A); + this.Delete(); + } + } + + private class LabourerTarget : Target + { + Mobile m_From; + Map m_map; + PelleLaboureuseA m_Pelle; + + public LabourerTarget(Mobile from, Map map, PelleLaboureuseA pelle) + : base(-1, false, TargetFlags.None) + { + m_From = from; + m_map = map; + m_Pelle = pelle; + from.SendMessage("Ciblez le sol à labourer"); + } + + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Mobile) + { + from.SendMessage("Essayez plutôt sur le sol..."); + } + else if (targeted is Item) + { + Item targ = targeted as Item; + IPoint3D t = targeted as IPoint3D; + if (t == null) + return; + + Point3D loc = new Point3D(t); + if (t is StaticTarget) + loc.Z -= TileData.ItemTable[((StaticTarget)t).ItemID & 0x3FFF].CalcHeight; + + int x = loc.X; + int y = loc.Y; + + + int tileID = m_map.Tiles.GetLandTile(x, y).ID & 0x3FFF; + bool ground = false; + + if (targ.Name == "Gazon Labourable") + { + for (int i = 0; ground == false && i < GazonTiles.Length; i++) //Vérifier dans la liste de gazon acceptés si la target est Ok + { + if (GazonTiles[i] == targ.ItemID) + ground = true; + + } + } + + else if (targ.Name == "Terre Labourable") + { + for (int i = 0; ground == false && i < DirtTiles.Length; i++) //Vérifier dans la liste de gazon acceptés si la target est Ok + { + if (DirtTiles[i] == targ.ItemID) + ground = true; + + } + } + + if (ground == false) + from.SendMessage("Vous ne pouvez pas labourer ceci..."); + + if (loc.Y > m_From.Location.Y + 1 || loc.Y < m_From.Location.Y - 1) + { + m_From.SendMessage("C'est trop loin..."); + ground = false; + } + + if (loc.X > m_From.Location.X + 1 || loc.X < m_From.Location.X - 1) + { + m_From.SendMessage("C'est trop loin..."); + ground = false; + } + + + if (ground == true) + { + int[] sons = new int[] { 0x125, 0x126 }; + int son = Utility.Random(0, 1); + from.PlaySound(sons[son]); + from.Animate(11, 1, 1, true, false, 0); + from.Direction = from.GetDirectionTo(loc.X, loc.Y); + from.SendMessage("Vous labourez le terrain"); + + Item item = new Item(0x32C9); + item.Name = "Terre labourée"; + item.Location = loc; + item.Map = m_map; + item.Movable = false; + + } + + } + } + } + + [Constructable] + public PelleLaboureuseA() + : this(50) + { + } + + [Constructable] + public PelleLaboureuseA(int uses) + : base(0xF39) + { + Weight = 5.0; + Name = "Pelle de Fermier"; + UsesRemaining = uses; + } + + public PelleLaboureuseA(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/PelleLaboureuseB.02.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Misc/PelleLaboureuseB.02.ScZ.cs new file mode 100644 index 0000000..8b7bf67 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/PelleLaboureuseB.02.ScZ.cs @@ -0,0 +1,215 @@ +/** + * Pelle permettant de labourer le sol d'une maison custom pour autant qu'il soit vierge + * Auteur : Scriptiz + * Version : 2009-03-18 + */ + +using System; +using Server; +using Server.Engines.Harvest; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Items; +using Server.Items.Crops; +using Server.Multis; +using Server.Engines.Craft; + +namespace Server.Items +{ + public class PelleLaboureuseB : Item + { + public static int[] ploughableTiles = new int[] {0x31F4, 0x31F5, 0x31F6, 0x31F7}; + private int m_UsesRemaining; + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; } + } + + [Constructable] + public PelleLaboureuseB() + : this(50) + { + } + + [Constructable] + public PelleLaboureuseB(int uses) + : base(0xF39) + { + Weight = 5.0; + Name = "Pelle de Fermier"; + UsesRemaining = uses; + } + + public PelleLaboureuseB(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!this.IsChildOf(from.Backpack)) + { + from.SendMessage("Vous devez avoir la pelle dans votre sac pour pouvoir l'utiliser."); + } + else + { + from.SendMessage("Ciblez le sol à labourer."); + from.Target = new LabourerTarget(from, this); + } + } + + public void decreaseUses(Mobile from) + { + UsesRemaining--; + Name = "Pelle de Fermier (" + UsesRemaining + ")"; + + if (this.UsesRemaining <= 0) + { + from.SendMessage("La pelle se brise entre vos mains."); + from.PlaySound(0x2A); + this.Delete(); + } + else + { + int[] sons = new int[] { 0x125, 0x126 }; + int son = Utility.Random(0, 1); + from.PlaySound(sons[son]); + from.Animate(11, 1, 1, true, false, 0); + } + } + + private class LabourerTarget : Target + { + Mobile m_From; + PelleLaboureuseB m_Pelle; + + public LabourerTarget(Mobile from, PelleLaboureuseB pelle) + : base(-1, false, TargetFlags.None) + { + m_From = from; + m_Pelle = pelle; + } + + protected override void OnTarget(Mobile from, object targeted) + { + int groundId = 0; + IPoint3D t = targeted as IPoint3D; + if (t == null) + return; + + Point3D loc = new Point3D(t); + if (t is StaticTarget) + { + loc.Z -= TileData.ItemTable[((StaticTarget)t).ItemID & 0x3FFF].CalcHeight; + + StaticTarget isFarmGround = (StaticTarget)t; + groundId = isFarmGround.ItemID; + } + else if (t is Item) + { + Item isFarmGround = (Item)t; + + if(isFarmGround != null) + { + if(isFarmGround is BaseCrop) + { + isFarmGround.Delete(); + from.SendMessage("Vous arrachez la pousse du sol."); + return; + } + else + groundId = isFarmGround.ItemID; + } + } + + from.Direction = from.GetDirectionTo(loc.X, loc.Y); + + if (ValidatePlacement(loc)) + { + bool ground = false; + for (int i = 0; ground == false && i < ploughableTiles.Length; i++) + { + if (ploughableTiles[i] == groundId) + ground = true; + } + + if (ground) + { + EndPlace(loc); + m_Pelle.decreaseUses(from); + from.SendMessage("Vous labourez le sol pour en faire de la terre cultivable."); + } + else + from.SendMessage("Ce type de sol n'est pas labourable."); + } + } + + public bool ValidatePlacement(Point3D loc) + { + if (m_From.Map == null) + return false; + + BaseHouse house = BaseHouse.FindHouseAt(m_From.Location, m_From.Map, 20); + if (house == null || !house.IsOwner(m_From)) + { + m_From.SendMessage("Vous devez être dans votre maison pour labourer le sol."); + return false; + } + + if (loc.Y > m_From.Location.Y + 1 || loc.Y < m_From.Location.Y - 1) + { + m_From.SendMessage("C'est trop loin..."); + return false; + } + + if (loc.X > m_From.Location.X + 1 || loc.X < m_From.Location.X - 1) + { + m_From.SendMessage("C'est trop loin..."); + return false; + } + return true; + } + + public void EndPlace(Point3D loc) + { + Static farmGround = new Static(13001); + farmGround.Name = "Terre labourée"; + farmGround.Map = m_From.Map; + farmGround.X = loc.X; + farmGround.Y = loc.Y; + farmGround.Z = loc.Z; + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + + // version 1 + writer.Write((int)m_UsesRemaining); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 1: + m_UsesRemaining = reader.ReadInt(); + break; + case 0: + m_UsesRemaining = 50; + break; + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/Reagents.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Misc/Reagents.00.ScZ.cs new file mode 100644 index 0000000..30993ac --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/Reagents.00.ScZ.cs @@ -0,0 +1,83 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Katyl : BaseReagent + { + [Constructable] + public Katyl() + : this(1) + { + Name = "Katyl"; + Hue = 0xb66; + } + + [Constructable] + public Katyl(int amount) + : base(0xF7F, amount) + { + Hue = 0xb66; + Name = "Katyl"; + } + + public Katyl(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + + public class Onax : BaseReagent +{ + [Constructable] + public Onax() + : this(1) + { + Hue = 0x27; + Name = "Onax"; + } + + [Constructable] + public Onax(int amount) + : base(0xF8F, amount) + { + Hue = 0x27; + Name = "Onax"; + } + + public Onax(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/SBFarmHand.01.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Misc/SBFarmHand.01.ScZ.cs new file mode 100644 index 0000000..450e200 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/SBFarmHand.01.ScZ.cs @@ -0,0 +1,95 @@ +using System; +using Server.Items; +using Server.Items.Crops; +using Server.Engines.Plants; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class SBFarmHand : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBFarmHand() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("Pelle laboureuse", typeof(PelleLaboureuseB), 50, 10, 0xF39, 0)); + Add( new GenericBuyInfo( typeof( Apple ), 3, 20, 0x9D0, 0 ) ); + Add( new GenericBuyInfo( typeof( Grapes ), 3, 20, 0x9D1, 0 ) ); + Add( new GenericBuyInfo( typeof( Watermelon ), 7, 20, 0xC5C, 0 ) ); + Add( new GenericBuyInfo( typeof( YellowGourd ), 3, 20, 0xC64, 0 ) ); + Add( new GenericBuyInfo( typeof( Pumpkin ), 11, 20, 0xC6A, 0 ) ); + Add( new GenericBuyInfo( typeof( Onion ), 3, 20, 0xC6D, 0 ) ); + Add( new GenericBuyInfo( typeof( Lettuce ), 5, 20, 0xC70, 0 ) ); + Add( new GenericBuyInfo( typeof( Squash ), 3, 20, 0xC72, 0 ) ); + Add( new GenericBuyInfo( typeof( HoneydewMelon ), 7, 20, 0xC74, 0 ) ); + Add( new GenericBuyInfo( typeof( Carrot ), 3, 20, 0xC77, 0 ) ); + Add( new GenericBuyInfo( typeof( Cantaloupe ), 6, 20, 0xC79, 0 ) ); + Add( new GenericBuyInfo( typeof( Cabbage ), 5, 20, 0xC7B, 0 ) ); + //Add( new GenericBuyInfo( typeof( EarOfCorn ), 3, 20, XXXXXX, 0 ) ); + //Add( new GenericBuyInfo( typeof( Turnip ), 6, 20, XXXXXX, 0 ) ); + //Add( new GenericBuyInfo( typeof( SheafOfHay ), 2, 20, XXXXXX, 0 ) ); + Add( new GenericBuyInfo( typeof( Lemon ), 3, 20, 0x1728, 0 ) ); + Add( new GenericBuyInfo( typeof( Lime ), 3, 20, 0x172A, 0 ) ); + Add( new GenericBuyInfo( typeof( Peach ), 3, 20, 0x9D2, 0 ) ); + Add( new GenericBuyInfo( typeof( Pear ), 3, 20, 0x994, 0 ) ); + Add( new GenericBuyInfo( "Graine de Coton", typeof( CottonSeed ), 250, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Lin", typeof( FlaxSeed ), 250, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Germe de Bl�", typeof( WheatSeed ), 150, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Germe de Ma�s", typeof( CornSeed ), 150, 20, 0xC82, 0 ) ); + Add( new GenericBuyInfo( "Graine de Carotte", typeof( CarrotSeed ), 50, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Bulbe d'Oignon", typeof( OnionSeed ), 50, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Bulbe d'Ail", typeof( GarlicSeed ), 50, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Laitue", typeof( LettuceSeed ), 50, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Chou", typeof( CabbageSeed ), 50, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine myst�rieuse", typeof( Seed ), 100, 5, 0xDCF, 0 ) ); + Add( new GenericBuyInfo( "Graine de Pommier", typeof( AppleSeed ), 1000, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de P�cher", typeof( PeachSeed ), 1000, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Poirier", typeof( PearSeed ), 1000, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Cocotier", typeof( CocoSeed ), 1500, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Bananier", typeof( BananaSeed ), 1500, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Katyliis", typeof( KatylSeed ), 3000, 2, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Tolonax", typeof( OnaxSeed ), 3000, 2, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine d'Orge", typeof( OrgeSeed ), 150, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Graine de Houblon", typeof( HoublonSeed ), 250, 20, 0xF27, 0x5E2 ) ); + Add( new GenericBuyInfo( "Sac de terre", typeof( Sacter ), 500, 10, 0xF27, 0x5E2 ) ); + //Add( new GenericBuyInfo( "Deed de Vigne N-S", typeof( VignesDeedNS ), 3000, 10, 0x14F0, 0 ) ); + //Add( new GenericBuyInfo( "Deed de Vigne E-O", typeof( VignesDeedEO ), 3000, 10, 0x14F0, 0 ) ); + Add( new GenericBuyInfo( "Pot de fleur", typeof( PlantBowl ), 500, 5, 0x15FD, 0 ) ); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + Add( typeof( Apple ), 1 ); + Add( typeof( Grapes ), 1 ); + Add( typeof( Watermelon ), 3 ); + Add( typeof( YellowGourd ), 1 ); + Add( typeof( Pumpkin ), 5 ); + Add( typeof( Onion ), 1 ); + Add( typeof( Lettuce ), 2 ); + Add( typeof( Squash ), 1 ); + Add( typeof( Carrot ), 1 ); + Add( typeof( HoneydewMelon ), 3 ); + Add( typeof( Cantaloupe ), 3 ); + Add( typeof( Cabbage ), 2 ); + Add( typeof( Lemon ), 1 ); + Add( typeof( Lime ), 1 ); + Add( typeof( Peach ), 1 ); + Add( typeof( Pear ), 1 ); + Add(typeof(PelleLaboureuseB), 25); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Misc/Sacter.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Misc/Sacter.00.ScZ.cs new file mode 100644 index 0000000..d9d3a9f --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Misc/Sacter.00.ScZ.cs @@ -0,0 +1,37 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute(4153)] + public class Sacter : Item + { + [Constructable] + public Sacter() : base(4153) + { + Weight = 10.0; + Name = "Sac de terre"; + Hue = 0x907; + } + + public Sacter(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( Weight == 6.0 ) + Weight = 10.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Roots/Ginseng.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Roots/Ginseng.00.ScZ.cs new file mode 100644 index 0000000..9bf7942 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Roots/Ginseng.00.ScZ.cs @@ -0,0 +1,126 @@ +using System; +using Server.Network; +using Server.Targeting; + +namespace Server.Items.Crops +{ + public class GinsengPlant : BaseCrop + { + private double lumberValue; + private DateTime lastpicked; + + [Constructable] + public GinsengPlant() + : base(Utility.RandomList(0x18E9, 0x18EA)) + { + Movable = false; + Name = "Plant de ginseng"; + lastpicked = DateTime.Now; + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null || !from.Alive) return; + + // lumbervalue = 100; will give 100% sucsess in picking + lumberValue = from.Skills[SkillName.Lumberjacking].Value + 20; + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (lumberValue > Utility.Random(100)) + { + from.Direction = from.GetDirectionTo(this); + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.PullRoot); + this.Delete(); + + from.AddToBackpack(new GinsengUprooted()); + } + else from.SendMessage(AgriTxt.HardPull); + } + else + { + from.SendMessage(AgriTxt.TooFar); + } + } + } + + public GinsengPlant(Serial serial) + : base(serial) + { + lastpicked = DateTime.Now; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0x18E7, 0x18E8)] + public class GinsengUprooted : Item, ICarvable + { + public void Carve(Mobile from, Item item) + { + int count = Utility.Random(4); + if (count == 0) + { + from.SendMessage(AgriTxt.NoRoot); + this.Consume(); + } + else + { + base.ScissorHelper(from, new Ginseng(), count); + from.SendMessage(AgriTxt.YouCut + " {0} racine{1} de Ginseng.", count, (count == 1 ? "" : "s")); + } + + } + + [Constructable] + public GinsengUprooted() + : this(1) + { + } + + [Constructable] + public GinsengUprooted(int amount) + : base(Utility.RandomList(0x18EB, 0x18EC)) + { + Stackable = false; + Weight = 1.0; + + Movable = true; + Amount = amount; + + Name = AgriTxt.Root + " de Ginseng"; + } + + public GinsengUprooted(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Roots/Mandrake.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Roots/Mandrake.00.ScZ.cs new file mode 100644 index 0000000..cd165ce --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Roots/Mandrake.00.ScZ.cs @@ -0,0 +1,122 @@ +using System; +using Server.Network; +using Server.Targeting; + +namespace Server.Items.Crops +{ + public class MandrakePlant : BaseCrop + { + private double lumberValue; + private DateTime lastpicked; + + [Constructable] + public MandrakePlant() : base( Utility.RandomList( 0x18DF, 0x18E0 ) ) + { + Movable = false; + Name = "Plant de Mandragore"; + lastpicked = DateTime.Now; + } + + public override void OnDoubleClick(Mobile from) + { + if ( from == null || !from.Alive ) return; + + // lumbervalue = 100; will give 100% sucsess in picking + lumberValue = from.Skills[SkillName.Lumberjacking].Value / 5; + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( lumberValue > Utility.Random( 100 ) ) + { + from.Direction = from.GetDirectionTo( this ); + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.PullRoot); + this.Delete(); + + from.AddToBackpack( new MandrakeUprooted() ); + } + else from.SendMessage(AgriTxt.HardPull); + } + else + { + from.SendMessage( AgriTxt.TooFar); + } + } + } + + public MandrakePlant( Serial serial ) : base( serial ) + { + lastpicked = DateTime.Now; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x18DD, 0x18DE )] + public class MandrakeUprooted : Item, ICarvable + { + public void Carve( Mobile from, Item item ) + { + int count = Utility.Random( 4 ); + if ( count == 0 ) + { + from.SendMessage(AgriTxt.NoRoot); + this.Consume(); + } + else + { + base.ScissorHelper( from, new MandrakeRoot(), count ); + from.SendMessage( AgriTxt.YouCut + " {0} racine{1} de Mandragore.", count, ( count == 1 ? "" : "s" ) ); + } + } + + [Constructable] + public MandrakeUprooted() : this( 1 ) + { + } + + [Constructable] + public MandrakeUprooted(int amount) + : base(Utility.RandomList(0x18DD, 0x18DE)) + { + Stackable = false; + Weight = 1.0; + + Movable = true; + Amount = amount; + + // Name = AgriTxt.Root + (Amount == 1 ? "" : "s") + " de Mandragore" + Name = AgriTxt.Root + " de Mandragore"; + } + + public MandrakeUprooted( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Roots/NightShade.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Roots/NightShade.00.ScZ.cs new file mode 100644 index 0000000..094c58b --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Roots/NightShade.00.ScZ.cs @@ -0,0 +1,121 @@ +using System; +using Server.Network; +using Server.Targeting; + +namespace Server.Items.Crops +{ + public class NightshadePlant : BaseCrop + { + private double lumberValue; + private DateTime lastpicked; + + [Constructable] + public NightshadePlant() : base( Utility.RandomList( 0x18E5, 0x18E6 ) ) + { + Movable = false; + Name = "Solanac�e"; + lastpicked = DateTime.Now; + } + + public override void OnDoubleClick(Mobile from) + { + if ( from == null || !from.Alive ) return; + + // lumbervalue = 100; will give 100% sucsess in picking + lumberValue = from.Skills[SkillName.Lumberjacking].Value / 5; + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( lumberValue > Utility.Random( 100 ) ) + { + from.Direction = from.GetDirectionTo( this ); + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.PullRoot); + this.Delete(); + + from.AddToBackpack( new NightshadeUprooted() ); + } + else from.SendMessage(AgriTxt.HardPull); + } + else + { + from.SendMessage(AgriTxt.HardPull); + } + } + } + + public NightshadePlant( Serial serial ) : base( serial ) + { + lastpicked = DateTime.Now; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute( 0x18E7, 0x18E8 )] + public class NightshadeUprooted : Item, ICarvable + { + public void Carve( Mobile from, Item item ) + { + int count = Utility.Random( 4 ); + if ( count == 0 ) + { + from.SendMessage(AgriTxt.NoRoot); + this.Consume(); + } + else + { + base.ScissorHelper( from, new Nightshade(), count ); + from.SendMessage( AgriTxt.YouCut + " {0} fleur{1} de solanac�e.", count, ( count == 1 ? "" : "s" ) ); + } + + } + + [Constructable] + public NightshadeUprooted() : this( 1 ) + { + } + + [Constructable] + public NightshadeUprooted( int amount ) : base( Utility.RandomList( 0x18E7, 0x18E8 ) ) + { + Stackable = false; + Weight = 1.0; + + Movable = true; + Amount = amount; + + Name = AgriTxt.Root + " de solanac�e"; + } + + public NightshadeUprooted( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Roots/UpRootGump.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Roots/UpRootGump.00.ScZ.cs new file mode 100644 index 0000000..67371cd --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Roots/UpRootGump.00.ScZ.cs @@ -0,0 +1,66 @@ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Items.Crops; + +namespace Server.Gumps +{ + public class UpRootGump : Gump + { + private Mobile m_Owner; + private BaseCrop m_crop; + + public UpRootGump( Mobile owner, BaseCrop crop ) : base( 60, 60 ) + { + owner.CloseGump( typeof( UpRootGump ) ); + + m_Owner = owner; + m_crop = crop; + + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + AddPage( 0 ); + + AddImage( 0, 0, 0x816 ); + AddButton( 34, 74, 0x81A, 0x81B, 1, GumpButtonType.Reply, 0 ); // OK + AddButton( 88, 74, 0x995, 0x996, 2, GumpButtonType.Reply, 0 ); // Cancel + + string msg = "Voulez vous arracher cette pouce ?"; + AddHtml( 30, 25, 120, 40, msg, false, false ); + } + + public override void OnResponse( NetState state, RelayInfo info ) + { + Mobile from = state.Mobile; + + if ( info.ButtonID == 1 ) + { + if ( m_crop != null && !m_crop.Deleted ) + { + if ( m_crop is WheatCrop ) + ((WheatCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is CottonCrop ) + ((CottonCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is CarrotCrop ) + ((CarrotCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is FlaxCrop ) + ((FlaxCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is LettuceCrop ) + ((LettuceCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is OnionCrop ) + ((OnionCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is GarlicCrop ) + ((GarlicCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is CabbageCrop ) + ((CabbageCrop)m_crop).UpRoot( m_Owner ); + else if ( m_crop is CornCrop ) + ((CornCrop)m_crop).UpRoot( m_Owner ); + } + } + } + } +} diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/AppleTree.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/AppleTree.00.ScZ.cs new file mode 100644 index 0000000..be0f954 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/AppleTree.00.ScZ.cs @@ -0,0 +1,408 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; + +namespace Server.Items.Crops +{ + //naga + public class AppleSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public AppleSeed() + : this(1) + { + } + + [Constructable] + public AppleSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de pommier"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 2);//1 + if ((cropsnear.Count > 1) || ((cropsnear.Count == 1) && Utility.RandomBool()))//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new AppleSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public AppleSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + //naga + + + + public class AppleSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty(AccessLevel.GameMaster)] + public String FullGrown { get { return treeTime.ToString("T"); } } + + [Constructable] + public AppleSapling() + : base(Utility.RandomList(0xCE9, 0xCEA)) + { + Movable = false; + Name = AgriTxt.Seedling + " de Pommier"; + + init(this); + } + + public static void init(AppleSapling plant) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer(plant, typeof(AppleTree), delay); + plant.thisTimer.Start(); + } + + public AppleSapling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + init(this); + } + } + + public class AppleTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public AppleTree(Point3D pnt, Map map) + : base(Utility.RandomList(0xD96, 0xD9A)) // leaves + { + Movable = false; + MoveToWorld(pnt, map); + + int trunkID = ((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk(trunkID, this); + i_trunk.MoveToWorld(pnt, map); + + init(this, false); + } + + public static void init(AppleTree plant, bool full) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if ((i_trunk != null) && (!i_trunk.Deleted)) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !TreeHelper.CanPickMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + + if (from.Mounted) + ++lumberValue; + + if (lumberValue < 3) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 26 : 17, 7, 1, true, false, 0); + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} pomme{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Apple crop = new Apple(pick); + from.AddToBackpack(crop); + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private AppleTree i_plant; + + public FruitTimer(AppleTree plant) + : base(TimeSpan.FromSeconds(900), TimeSpan.FromSeconds(30)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop(Mobile from) + { + if (from.InRange(this.GetWorldLocation(), 2)) + { + if ((chopTimer == null) || (!chopTimer.Running)) + { + if ((TreeHelper.TreeOrdinance) && (from.AccessLevel == AccessLevel.Player)) + { + if (from.Region is Regions.GuardedRegion) + from.CriminalAction(true); + } + + chopTimer = new TreeHelper.ChopAction(from); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo(this); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ((lumberValue > .5) && (Utility.RandomDouble() <= lumberValue)) + { + Apple fruit = new Apple((int)Utility.Random(13) + m_yield); + from.AddToBackpack(fruit); + + int cnt = Utility.Random((int)(lumberValue * 10) + 1); + Log logs = new Log(cnt); // Fruitwood Logs ?? + from.AddToBackpack(logs); + + FruitTreeStump i_stump = new FruitTreeStump(typeof(AppleTree)); + Timer poof = new StumpTimer(this, i_stump, from); + poof.Start(); + } + else from.SendLocalizedMessage(500495); // You hack at the tree for a while, but fail to produce any useable wood. + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", lumberValue )); + } + } + else from.SendLocalizedMessage(500446); // That is too far away. + } + + private class StumpTimer : Timer + { + private AppleTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer(AppleTree Tree, FruitTreeStump Stump, Mobile from) + : base(TimeSpan.FromMilliseconds(5500)) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld(i_tree.Location, i_tree.Map); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop(Mobile from) + { + if (!this.Deleted) + Chop(from); + } + + public AppleTree(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + + writer.Write((Item)i_trunk); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if (item != null) + i_trunk = item; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/BananaTree.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/BananaTree.00.ScZ.cs new file mode 100644 index 0000000..fcc633f --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/BananaTree.00.ScZ.cs @@ -0,0 +1,407 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items.Crops +{ + + //naga + public class BananaSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public BananaSeed() + : this(1) + { + } + + [Constructable] + public BananaSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Bananier"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 2);//1 + if ((cropsnear.Count > 1) || ((cropsnear.Count == 1) && Utility.RandomBool()))//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new BananaSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public BananaSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + //naga + + + public class BananaSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty(AccessLevel.GameMaster)] + public String FullGrown { get { return treeTime.ToString("T"); } } + + [Constructable] + public BananaSapling() + : base(Utility.RandomList(0xCA6, 0xCA6)) + { + Movable = false; + Name = AgriTxt.Seedling + " de Bananier"; + + init(this); + } + + public static void init(BananaSapling plant) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer(plant, typeof(BananaTree), delay); + plant.thisTimer.Start(); + } + + public BananaSapling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + init(this); + } + } + + + public class BananaTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public BananaTree(Point3D pnt, Map map) + : base(Utility.RandomList(0xCAA, 0xCA8)) // leaves + { + Movable = false; + MoveToWorld(pnt, map); + Name = "Bananier"; + int trunkID = 0xCAB; //((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk(trunkID, this); + i_trunk.MoveToWorld(pnt, map); + + init(this, false); + } + + public static void init(BananaTree plant, bool full) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if ((i_trunk != null) && (!i_trunk.Deleted)) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !TreeHelper.CanPickMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (from.Mounted) + ++lumberValue; + + if (lumberValue < 3) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 26 : 17, 7, 1, true, false, 0); + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} banane{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Banana crop = new Banana(pick); // naga fruit + from.AddToBackpack(crop); + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private BananaTree i_plant; + + public FruitTimer(BananaTree plant) + : base(TimeSpan.FromSeconds(900), TimeSpan.FromSeconds(30)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop(Mobile from) + { + if (from.InRange(this.GetWorldLocation(), 2)) + { + if ((chopTimer == null) || (!chopTimer.Running)) + { + if ((TreeHelper.TreeOrdinance) && (from.AccessLevel == AccessLevel.Player)) + { + if (from.Region is Regions.GuardedRegion) + from.CriminalAction(true); + } + + chopTimer = new TreeHelper.ChopAction(from); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo(this); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ((lumberValue > .5) && (Utility.RandomDouble() <= lumberValue)) + { + Banana fruit = new Banana((int)Utility.Random(13) + m_yield); + from.AddToBackpack(fruit); + + int cnt = Utility.Random((int)(lumberValue * 10) + 1); + Log logs = new Log(cnt); // Fruitwood Logs ?? + from.AddToBackpack(logs); + + FruitTreeStump i_stump = new FruitTreeStump(typeof(BananaTree)); + Timer poof = new StumpTimer(this, i_stump, from); + poof.Start(); + } + else from.SendLocalizedMessage(500495); // You hack at the tree for a while, but fail to produce any useable wood. + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", lumberValue )); + } + } + else from.SendLocalizedMessage(500446); // That is too far away. + } + + private class StumpTimer : Timer + { + private BananaTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer(BananaTree Tree, FruitTreeStump Stump, Mobile from) + : base(TimeSpan.FromMilliseconds(5500)) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld(i_tree.Location, i_tree.Map); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop(Mobile from) + { + if (!this.Deleted) + Chop(from); + } + + public BananaTree(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + + writer.Write((Item)i_trunk); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if (item != null) + i_trunk = item; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/CoconutPalm.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/CoconutPalm.00.ScZ.cs new file mode 100644 index 0000000..24c3ae0 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/CoconutPalm.00.ScZ.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items.Crops +{ + + //naga + public class CocoSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public CocoSeed() : this( 1 ) + { + } + + [Constructable] + public CocoSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Cocotier"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 2 );//1 + if ( ( cropsnear.Count > 1 ) || (( cropsnear.Count == 1 ) && Utility.RandomBool() ) )//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new CocoSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public CocoSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + //naga + + + public class CocoSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty( AccessLevel.GameMaster )] + public String FullGrown{ get{ return treeTime.ToString( "T" ); } } + + [Constructable] + public CocoSapling() : base( Utility.RandomList ( 0xC9C, 0xC9B ) ) + { + Movable = false; + Name = AgriTxt.Seedling + " de Cocotier"; + + init( this ); + } + + public static void init( CocoSapling plant ) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer( plant, typeof(CocoTree), delay ); + plant.thisTimer.Start(); + } + + public CocoSapling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + init( this ); + } + } + + + public class CocoTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public CocoTree( Point3D pnt, Map map ) : base( Utility.RandomList( 0xC96, 0xC95 ) ) // leaves + { + Name = "Cocotier"; + Movable = false; + MoveToWorld( pnt, map ); + + int trunkID = 0x1B1F; // ((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk( trunkID, this ); + i_trunk.MoveToWorld( pnt, map ); + + init( this, false ); + } + + public static void init ( CocoTree plant, bool full ) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if (( i_trunk != null ) && ( !i_trunk.Deleted )) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !TreeHelper.CanPickMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( from.Mounted ) + ++lumberValue; + + if ( lumberValue < 3 ) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 26:17, 7, 1, true, false, 0 ); + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} noix de coco!", pick); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Coconut crop = new Coconut( pick ); + from.AddToBackpack( crop ); + + if ( !regrowTimer.Running ) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private CocoTree i_plant; + + public FruitTimer( CocoTree plant ) : base( TimeSpan.FromSeconds( 900 ), TimeSpan.FromSeconds( 30 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( ( chopTimer == null ) || ( !chopTimer.Running ) ) + { + if ( ( TreeHelper.TreeOrdinance ) && ( from.AccessLevel == AccessLevel.Player ) ) + { + if ( from.Region is Regions.GuardedRegion ) + from.CriminalAction( true ); + } + + chopTimer = new TreeHelper.ChopAction( from ); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo( this ); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ( ( lumberValue > .5 ) && ( Utility.RandomDouble() <= lumberValue ) ) + { + Coconut fruit = new Coconut( (int)Utility.Random( 13 ) + m_yield ); + from.AddToBackpack( fruit ); + + int cnt = Utility.Random( (int)( lumberValue * 10 ) + 1 ); + Log logs = new Log( cnt ); // Fruitwood Logs ?? + from.AddToBackpack( logs ); + + FruitTreeStump i_stump = new FruitTreeStump( typeof( CocoTree ) ); + Timer poof = new StumpTimer( this, i_stump, from ); + poof.Start(); + } + else from.SendLocalizedMessage( 500495 ); // You hack at the tree for a while, but fail to produce any useable wood. + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", lumberValue )); + } + } + else from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + private class StumpTimer : Timer + { + private CocoTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer( CocoTree Tree, FruitTreeStump Stump, Mobile from ) : base( TimeSpan.FromMilliseconds( 5500 ) ) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld( i_tree.Location, i_tree.Map ); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop( Mobile from ) + { + if ( !this.Deleted ) + Chop( from ); + } + + public CocoTree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + writer.Write( (Item)i_trunk ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if ( item != null ) + i_trunk = item; + + init( this, true ); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/KatylTree.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/KatylTree.00.ScZ.cs new file mode 100644 index 0000000..e61eb19 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/KatylTree.00.ScZ.cs @@ -0,0 +1,398 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items.Crops +{ + + //naga + public class KatylSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public KatylSeed() : this( 1 ) + { + } + + [Constructable] + public KatylSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E1; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Katyliis"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 2 );//1 + if ( ( cropsnear.Count > 1 ) || (( cropsnear.Count == 1 ) && Utility.RandomBool() ) )//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage("Vous plantez la graine"); + this.Consume(); + Item item = new KatylSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public KatylSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + //naga + + + public class KatylSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty( AccessLevel.GameMaster )] + public String FullGrown{ get{ return treeTime.ToString( "T" ); } } + + [Constructable] + public KatylSapling() : base( Utility.RandomList ( 0xCA6, 0xCA6 ) ) + { + Movable = false; + Name = AgriTxt.Seedling + " de Katyliis"; + + init( this ); + } + + public static void init( KatylSapling plant ) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer( plant, typeof(KatylTree), delay ); + plant.thisTimer.Start(); + } + + public KatylSapling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + init( this ); + } + } + + + public class KatylTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public KatylTree( Point3D pnt, Map map ) : base( Utility.RandomList( 0xD37, 0xD38 ) ) // leaves + { + Movable = false; + MoveToWorld( pnt, map ); + Name = "Katyliis"; + int trunkID = 0x1B1F; //((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk( trunkID, this ); + i_trunk.MoveToWorld( pnt, map ); + + init( this, false ); + } + + public static void init ( KatylTree plant, bool full ) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if (( i_trunk != null ) && ( !i_trunk.Deleted )) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !TreeHelper.CanPickMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( from.Mounted ) + ++lumberValue; + + if ( lumberValue < 6 ) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 26:17, 7, 1, true, false, 0 ); + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} Katyl{1}!", pick, ( pick == 1 ? "" : "s" ) ); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Katyl crop = new Katyl( pick ); // naga fruit + from.AddToBackpack( crop ); + + if ( !regrowTimer.Running ) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private KatylTree i_plant; + + public FruitTimer( KatylTree plant ) : base( TimeSpan.FromSeconds( 900 ), TimeSpan.FromSeconds( 30 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( ( chopTimer == null ) || ( !chopTimer.Running ) ) + { + if ( ( TreeHelper.TreeOrdinance ) && ( from.AccessLevel == AccessLevel.Player ) ) + { + if ( from.Region is Regions.GuardedRegion ) + from.CriminalAction( true ); + } + + chopTimer = new TreeHelper.ChopAction( from ); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo( this ); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ( ( lumberValue > .5 ) && ( Utility.RandomDouble() <= lumberValue ) ) + { + Katyl fruit = new Katyl( (int)Utility.Random( 13 ) + m_yield ); + from.AddToBackpack( fruit ); + + int cnt = Utility.Random( (int)( lumberValue * 10 ) + 1 ); + Log logs = new Log( cnt ); // Fruitwood Logs ?? + from.AddToBackpack( logs ); + + FruitTreeStump i_stump = new FruitTreeStump( typeof( KatylTree ) ); + Timer poof = new StumpTimer( this, i_stump, from ); + poof.Start(); + } + else from.SendLocalizedMessage( 500495 ); // You hack at the tree for a while, but fail to produce any useable wood. + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", lumberValue )); + } + } + else from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + private class StumpTimer : Timer + { + private KatylTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer( KatylTree Tree, FruitTreeStump Stump, Mobile from ) : base( TimeSpan.FromMilliseconds( 5500 ) ) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld( i_tree.Location, i_tree.Map ); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop( Mobile from ) + { + if ( !this.Deleted ) + Chop( from ); + } + + public KatylTree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + writer.Write( (Item)i_trunk ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if ( item != null ) + i_trunk = item; + + init( this, true ); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/OnaxTree.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/OnaxTree.00.ScZ.cs new file mode 100644 index 0000000..d02268d --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/OnaxTree.00.ScZ.cs @@ -0,0 +1,407 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items.Crops +{ + + //naga + public class OnaxSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden { get { return true; } } + + [Constructable] + public OnaxSeed() + : this(1) + { + } + + [Constructable] + public OnaxSeed(int amount) + : base(0xF27) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Tolonax"; + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !CropHelper.CanWorkMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042010); //You must have the object in your backpack to use it. + return; + } + + else if (!CropHelper.CheckCanGrow(this, m_map, m_pnt.X, m_pnt.Y)) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop(m_pnt, m_map, 0); + if (cropshere.Count > 0) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop(m_pnt, m_map, 2);//1 + if ((cropsnear.Count > 1) || ((cropsnear.Count == 1) && Utility.RandomBool()))//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if (this.BumpZ) ++m_pnt.Z; + + if (!from.Mounted) + from.Animate(32, 5, 1, true, false, 0); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new OnaxSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public OnaxSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + //naga + + + public class OnaxSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty(AccessLevel.GameMaster)] + public String FullGrown { get { return treeTime.ToString("T"); } } + + [Constructable] + public OnaxSapling() + : base(Utility.RandomList(0xCA6, 0xCA6)) + { + Movable = false; + Name = AgriTxt.Seedling + " de Tolonax"; + + init(this); + } + + public static void init(OnaxSapling plant) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer(plant, typeof(OnaxTree), delay); + plant.thisTimer.Start(); + } + + public OnaxSapling(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + init(this); + } + } + + + public class OnaxTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty(AccessLevel.GameMaster)] + public int Yield { get { return m_yield; } set { m_yield = value; } } + + public int Capacity { get { return max; } } + public DateTime LastPick { get { return lastpicked; } set { lastpicked = value; } } + + [Constructable] + public OnaxTree(Point3D pnt, Map map) + : base(Utility.RandomList(0xC9E, 0xC9E)) // leaves + { + Movable = false; + MoveToWorld(pnt, map); + Name = "Tolonax"; + int trunkID = 0x1B1F; // ((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk(trunkID, this); + i_trunk.MoveToWorld(pnt, map); + + init(this, false); + } + + public static void init(OnaxTree plant, bool full) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer(plant); + + if (full) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if ((i_trunk != null) && (!i_trunk.Deleted)) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.Mounted && !TreeHelper.CanPickMounted) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if (DateTime.Now > lastpicked.AddSeconds(3)) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if (from.Mounted) + ++lumberValue; + + if (lumberValue < 7) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if (from.InRange(this.GetWorldLocation(), 2)) + { + if (m_yield < 1) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo(this); + + from.Animate(from.Mounted ? 26 : 17, 7, 1, true, false, 0); + + if (lumberValue > m_yield) + lumberValue = m_yield + 1; + + int pick = Utility.Random(lumberValue); + if (pick == 0) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} Onax{1}!", pick, (pick == 1 ? "" : "s")); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Onax crop = new Onax(pick); // naga fruit + from.AddToBackpack(crop); + + if (!regrowTimer.Running) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private OnaxTree i_plant; + + public FruitTimer(OnaxTree plant) + : base(TimeSpan.FromSeconds(900), TimeSpan.FromSeconds(30)) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ((i_plant != null) && (!i_plant.Deleted)) + { + int current = i_plant.Yield; + + if (++current >= i_plant.Capacity) + { + current = i_plant.Capacity; + Stop(); + } + else if (current <= 0) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop(Mobile from) + { + if (from.InRange(this.GetWorldLocation(), 2)) + { + if ((chopTimer == null) || (!chopTimer.Running)) + { + if ((TreeHelper.TreeOrdinance) && (from.AccessLevel == AccessLevel.Player)) + { + if (from.Region is Regions.GuardedRegion) + from.CriminalAction(true); + } + + chopTimer = new TreeHelper.ChopAction(from); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo(this); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ((lumberValue > .5) && (Utility.RandomDouble() <= lumberValue)) + { + Onax fruit = new Onax((int)Utility.Random(13) + m_yield); + from.AddToBackpack(fruit); + + int cnt = Utility.Random((int)(lumberValue * 10) + 1); + Log logs = new Log(cnt); // Fruitwood Logs ?? + from.AddToBackpack(logs); + + FruitTreeStump i_stump = new FruitTreeStump(typeof(OnaxTree)); + Timer poof = new StumpTimer(this, i_stump, from); + poof.Start(); + } + else from.SendLocalizedMessage(500495); // You hack at the tree for a while, but fail to produce any useable wood. + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", lumberValue )); + } + } + else from.SendLocalizedMessage(500446); // That is too far away. + } + + private class StumpTimer : Timer + { + private OnaxTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer(OnaxTree Tree, FruitTreeStump Stump, Mobile from) + : base(TimeSpan.FromMilliseconds(5500)) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld(i_tree.Location, i_tree.Map); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop(Mobile from) + { + if (!this.Deleted) + Chop(from); + } + + public OnaxTree(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + + writer.Write((Item)i_trunk); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if (item != null) + i_trunk = item; + + init(this, true); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/PeachTree.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/PeachTree.00.ScZ.cs new file mode 100644 index 0000000..6cc8c7c --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/PeachTree.00.ScZ.cs @@ -0,0 +1,395 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items.Crops +{ + + //naga + public class PeachSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public PeachSeed() : this( 1 ) + { + } + + [Constructable] + public PeachSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de P�cher"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 2 );//1 + if ( ( cropsnear.Count > 1 ) || (( cropsnear.Count == 1 ) && Utility.RandomBool() ) )//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new PeachSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public PeachSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + //naga + + public class PeachSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty( AccessLevel.GameMaster )] + public String FullGrown{ get{ return treeTime.ToString( "T" ); } } + + [Constructable] + public PeachSapling() : base( Utility.RandomList ( 0xCE9, 0xCEA ) ) + { + Movable = false; + Name = AgriTxt.Seedling + " de P�cher"; + + init( this ); + } + + public static void init( PeachSapling plant ) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer( plant, typeof(PeachTree), delay ); + plant.thisTimer.Start(); + } + + public PeachSapling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + init( this ); + } + } + + public class PeachTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public PeachTree( Point3D pnt, Map map ) : base( Utility.RandomList( 0xD9E, 0xDA2 ) ) // leaves + { + Movable = false; + MoveToWorld( pnt, map ); + + int trunkID = ((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk( trunkID, this ); + i_trunk.MoveToWorld( pnt, map ); + + init( this, false ); + } + + public static void init ( PeachTree plant, bool full ) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if (( i_trunk != null ) && ( !i_trunk.Deleted )) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !TreeHelper.CanPickMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( from.Mounted ) + ++lumberValue; + + if ( lumberValue < 3 ) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 26:17, 7, 1, true, false, 0 ); + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} p�che{1}!", pick, ( pick == 1 ? "" : "s" ) ); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Peach crop = new Peach( pick ); + from.AddToBackpack( crop ); + + if ( !regrowTimer.Running ) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private PeachTree i_plant; + + public FruitTimer( PeachTree plant ) : base( TimeSpan.FromSeconds( 900 ), TimeSpan.FromSeconds( 30 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( ( chopTimer == null ) || ( !chopTimer.Running ) ) + { + if ( ( TreeHelper.TreeOrdinance ) && ( from.AccessLevel == AccessLevel.Player ) ) + { + if ( from.Region is Regions.GuardedRegion ) + from.CriminalAction( true ); + } + + chopTimer = new TreeHelper.ChopAction( from ); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo( this ); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ( ( lumberValue > .5 ) && ( Utility.RandomDouble() <= lumberValue ) ) + { + Peach fruit = new Peach( (int)Utility.Random( 13 ) + m_yield ); + from.AddToBackpack( fruit ); + + int cnt = Utility.Random( (int)( lumberValue * 10 ) + 1 ); + Log logs = new Log( cnt ); // Fruitwood Logs ?? + from.AddToBackpack( logs ); + + FruitTreeStump i_stump = new FruitTreeStump( typeof( PeachTree ) ); + Timer poof = new StumpTimer( this, i_stump, from ); + poof.Start(); + } + else from.SendLocalizedMessage( 500495 ); // You hack at the tree for a while, but fail to produce any useable wood. + } + } + else from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + private class StumpTimer : Timer + { + private PeachTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer( PeachTree Tree, FruitTreeStump Stump, Mobile from ) : base( TimeSpan.FromMilliseconds( 5500 ) ) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld( i_tree.Location, i_tree.Map ); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop( Mobile from ) + { + if ( !this.Deleted ) + Chop( from ); + } + + public PeachTree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + writer.Write( (Item)i_trunk ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if ( item != null ) + i_trunk = item; + + init( this, true ); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/PearTree.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/PearTree.00.ScZ.cs new file mode 100644 index 0000000..c21d891 --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/PearTree.00.ScZ.cs @@ -0,0 +1,396 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Items; +using Server.Mobiles; + +namespace Server.Items.Crops +{ + + //naga + public class PearSeed : BaseCrop + { + // return true to allow planting on Dirt Item (ItemID 0x32C9) + // See CropHelper.cs for other overriddable types + public override bool CanGrowGarden{ get{ return true; } } + + [Constructable] + public PearSeed() : this( 1 ) + { + } + + [Constructable] + public PearSeed( int amount ) : base( 0xF27 ) + { + Stackable = true; + Weight = .5; + Hue = 0x5E2; + + Movable = true; + + Amount = amount; + Name = AgriTxt.Seed + " de Poirier"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !CropHelper.CanWorkMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + Point3D m_pnt = from.Location; + Map m_map = from.Map; + + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042010 ); //You must have the object in your backpack to use it. + return; + } + + else if ( !CropHelper.CheckCanGrow( this, m_map, m_pnt.X, m_pnt.Y ) ) + { + from.SendMessage(AgriTxt.CannotGrowHere); + return; + } + + //check for BaseCrop on this tile + ArrayList cropshere = CropHelper.CheckCrop( m_pnt, m_map, 0 ); + if ( cropshere.Count > 0 ) + { + from.SendMessage(AgriTxt.AlreadyCrop); + return; + } + + //check for over planting prohibt if 4 maybe 3 neighboring crops + ArrayList cropsnear = CropHelper.CheckCrop( m_pnt, m_map, 2 );//1 + if ( ( cropsnear.Count > 1 ) || (( cropsnear.Count == 1 ) && Utility.RandomBool() ) )//3 + { + from.SendMessage(AgriTxt.TooMuchCrops); + return; + } + + if ( this.BumpZ ) ++m_pnt.Z; + + if ( !from.Mounted ) + from.Animate( 32, 5, 1, true, false, 0 ); // Bow + + from.SendMessage(AgriTxt.CropPlanted); + this.Consume(); + Item item = new PearSapling();// from ); + item.Location = m_pnt; + item.Map = m_map; + + } + + public PearSeed( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + //naga + + + public class PearSapling : BaseCrop + { + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty( AccessLevel.GameMaster )] + public String FullGrown{ get{ return treeTime.ToString( "T" ); } } + + [Constructable] + public PearSapling() : base( Utility.RandomList ( 0xCE9, 0xCEA ) ) + { + Movable = false; + Name = AgriTxt.Seedling + " de Poirier"; + + init( this ); + } + + public static void init( PearSapling plant ) + { + TimeSpan delay = TreeHelper.SaplingTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.TreeTimer( plant, typeof(PearTree), delay ); + plant.thisTimer.Start(); + } + + public PearSapling( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + init( this ); + } + } + + public class PearTree : BaseTree + { + public Item i_trunk; + private Timer chopTimer; + + private const int max = 12; + private DateTime lastpicked; + private int m_yield; + + public Timer regrowTimer; + + [CommandProperty( AccessLevel.GameMaster )] + public int Yield{ get{ return m_yield; } set{ m_yield = value; } } + + public int Capacity{ get{ return max; } } + public DateTime LastPick{ get{ return lastpicked; } set{ lastpicked = value; } } + + [Constructable] + public PearTree( Point3D pnt, Map map ) : base( Utility.RandomList( 0xDAA, 0xDA6 ) ) // leaves + { + Movable = false; + MoveToWorld( pnt, map ); + + int trunkID = ((Item)this).ItemID - 2; + + i_trunk = new TreeTrunk( trunkID, this ); + i_trunk.MoveToWorld( pnt, map ); + + init( this, false ); + } + + public static void init ( PearTree plant, bool full ) + { + plant.LastPick = DateTime.Now; + plant.regrowTimer = new FruitTimer( plant ); + + if ( full ) + { + plant.Yield = plant.Capacity; + } + else + { + plant.Yield = 0; + plant.regrowTimer.Start(); + } + } + + public override void OnAfterDelete() + { + if (( i_trunk != null ) && ( !i_trunk.Deleted )) + i_trunk.Delete(); + + base.OnAfterDelete(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.Mounted && !TreeHelper.CanPickMounted ) + { + from.SendMessage(AgriTxt.CannotWorkMounted); + return; + } + + if ( DateTime.Now > lastpicked.AddSeconds(3) ) // 3 seconds between picking + { + lastpicked = DateTime.Now; + + int lumberValue = (int)from.Skills[SkillName.Lumberjacking].Value / 5; + if ( from.Mounted ) + ++lumberValue; + + if ( lumberValue < 3 ) + { + from.SendMessage(AgriTxt.DunnoHowTo); + return; + } + + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( m_yield < 1 ) + { + from.SendMessage(AgriTxt.NoCrop); + } + else //check skill + { + from.Direction = from.GetDirectionTo( this ); + + from.Animate( from.Mounted ? 26:17, 7, 1, true, false, 0 ); + + if ( lumberValue > m_yield ) + lumberValue = m_yield + 1; + + int pick = Utility.Random( lumberValue ); + if ( pick == 0 ) + { + from.SendMessage(AgriTxt.ZeroPicked); + return; + } + + m_yield -= pick; + from.SendMessage(AgriTxt.YouPick + " {0} poire{1}!", pick, ( pick == 1 ? "" : "s" ) ); + + //PublicOverheadMessage( MessageType.Regular, 0x3BD, false, string.Format( "{0}", m_yield )); + + Pear crop = new Pear( pick ); + from.AddToBackpack( crop ); + + if ( !regrowTimer.Running ) + { + regrowTimer.Start(); + } + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + } + + private class FruitTimer : Timer + { + private PearTree i_plant; + + public FruitTimer( PearTree plant ) : base( TimeSpan.FromSeconds( 900 ), TimeSpan.FromSeconds( 30 ) ) + { + Priority = TimerPriority.OneSecond; + i_plant = plant; + } + + protected override void OnTick() + { + if ( ( i_plant != null ) && ( !i_plant.Deleted ) ) + { + int current = i_plant.Yield; + + if ( ++current >= i_plant.Capacity ) + { + current = i_plant.Capacity; + Stop(); + } + else if ( current <= 0 ) + current = 1; + + i_plant.Yield = current; + + //i_plant.PublicOverheadMessage( MessageType.Regular, 0x22, false, string.Format( "{0}", current )); + } + else Stop(); + } + } + + public void Chop( Mobile from ) + { + if ( from.InRange( this.GetWorldLocation(), 2 ) ) + { + if ( ( chopTimer == null ) || ( !chopTimer.Running ) ) + { + if ( ( TreeHelper.TreeOrdinance ) && ( from.AccessLevel == AccessLevel.Player ) ) + { + if ( from.Region is Regions.GuardedRegion ) + from.CriminalAction( true ); + } + + chopTimer = new TreeHelper.ChopAction( from ); + + Point3D pnt = this.Location; + Map map = this.Map; + + from.Direction = from.GetDirectionTo( this ); + chopTimer.Start(); + + double lumberValue = from.Skills[SkillName.Lumberjacking].Value / 100; + if ( ( lumberValue > .5 ) && ( Utility.RandomDouble() <= lumberValue ) ) + { + Pear fruit = new Pear( (int)Utility.Random( 13 ) + m_yield ); + from.AddToBackpack( fruit ); + + int cnt = Utility.Random( (int)( lumberValue * 10 ) + 1 ); + Log logs = new Log( cnt ); // Fruitwood Logs ?? + from.AddToBackpack( logs ); + + FruitTreeStump i_stump = new FruitTreeStump( typeof( PearTree ) ); + Timer poof = new StumpTimer( this, i_stump, from ); + poof.Start(); + } + else from.SendLocalizedMessage( 500495 ); // You hack at the tree for a while, but fail to produce any useable wood. + } + } + else from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + private class StumpTimer : Timer + { + private PearTree i_tree; + private FruitTreeStump i_stump; + private Mobile m_chopper; + + public StumpTimer( PearTree Tree, FruitTreeStump Stump, Mobile from ) : base( TimeSpan.FromMilliseconds( 5500 ) ) + { + Priority = TimerPriority.TenMS; + + i_tree = Tree; + i_stump = Stump; + m_chopper = from; + } + + protected override void OnTick() + { + i_stump.MoveToWorld( i_tree.Location, i_tree.Map ); + i_tree.Delete(); + m_chopper.SendMessage(AgriTxt.LogsAndFruits); + } + } + + public override void OnChop( Mobile from ) + { + if ( !this.Deleted ) + Chop( from ); + } + + public PearTree( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + writer.Write( (Item)i_trunk ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if ( item != null ) + i_trunk = item; + + init( this, true ); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Agriculture/Trees/TreeHelper.00.ScZ.cs b/Scripts/Vivre/Engines/Agriculture/Trees/TreeHelper.00.ScZ.cs new file mode 100644 index 0000000..56dd73f --- /dev/null +++ b/Scripts/Vivre/Engines/Agriculture/Trees/TreeHelper.00.ScZ.cs @@ -0,0 +1,390 @@ +using System; +using Server; +using System.Collections; +using Server.Network; +using Server.Gumps; +using Server.Items; + +namespace Server.Items.Crops +{ + public enum TreeType + { + AppleTree, + PearTree, + PeachTree, + CocoTree, + BananaTree, + KatylTree, + OnaxTree + } + + public class TreeHelper + { + public static bool CanPickMounted{ get{ return false; } } // If true Player can pick fruit while mounted + public static bool TreeOrdinance{ get{ return false; } } // Criminal to Chop fruit trees in town. + + public static TimeSpan SaplingTime = TimeSpan.FromHours( 3 ); // Time spent as a Sapling + public static TimeSpan StumpTime = TimeSpan.FromHours( 1 ); // Time spent as a Stump + + public class ChopAction : Timer + { + private Mobile m_chopper; + private int cnt; + + public ChopAction( Mobile from ) : base( TimeSpan.FromMilliseconds( 900 ), TimeSpan.FromMilliseconds( 900 ) ) + { + Priority = TimerPriority.TenMS; + m_chopper = from; + from.CantWalk = true; + cnt = 1; + } + + protected override void OnTick() + { + switch( cnt++ ) + { + case 1: case 3: case 5: + { + m_chopper.Animate( 13, 7, 1, true, false, 0 ); // Chop + break; + } + case 2: case 4: + { + Effects.PlaySound( m_chopper.Location, m_chopper.Map, 0x13E ); + break; + } + case 6: + { + Effects.PlaySound( m_chopper.Location, m_chopper.Map, 0x13E ); + m_chopper.CantWalk = false; + this.Stop(); + break; + } + } + } + } + + public class TreeTimer : Timer + { + private Item i_sapling; + private Type t_crop; + + public TreeTimer( Item sapling, Type croptype, TimeSpan delay ) : base( delay ) + { + Priority = TimerPriority.OneMinute; + + i_sapling = sapling; + t_crop = croptype; + } + + protected override void OnTick() + { + if (( i_sapling != null ) && ( !i_sapling.Deleted )) + { + object[] args = { i_sapling.Location, i_sapling.Map }; + Item newitem = Activator.CreateInstance( t_crop, args ) as Item; + + i_sapling.Delete(); + } + } + } + + public class GrowTimer : Timer + { + private Item i_stump; + private Type t_tree; + private DateTime d_timerstart; + private Item i_newtree; + + public GrowTimer( Item stump, Type treetype, TimeSpan delay ) : base( delay ) + { + Priority = TimerPriority.OneMinute; + + i_stump = stump; + t_tree = treetype; + + d_timerstart = DateTime.Now; + } + + protected override void OnTick() + { + Point3D pnt = i_stump.Location; + Map map = i_stump.Map; + + if ( t_tree == typeof(PeachTree) ) + i_newtree = new PeachSapling(); + + else if ( t_tree == typeof(PearTree) ) + i_newtree = new PearSapling(); + + else if ( t_tree == typeof(CocoTree) ) + i_newtree = new CocoSapling(); + + else if ( t_tree == typeof(BananaTree) ) + i_newtree = new BananaSapling(); + + else if ( t_tree == typeof(KatylTree) ) + i_newtree = new KatylSapling(); + + else if ( t_tree == typeof(OnaxTree) ) + i_newtree = new OnaxSapling(); + + else + i_newtree = new AppleSapling(); + + i_stump.Delete(); + i_newtree.MoveToWorld( pnt, map ); + } + } + } + + public class BaseTree : Item, IChopable + { + public BaseTree( int itemID ) : base( itemID ) + { + } + + public BaseTree( Serial serial ) : base( serial ) + { + } + + public virtual void OnChop( Mobile from ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } + + public class TreeTrunk : Item, IChopable + { + private Item i_leaves; + + public Item Leaves{ get{ return i_leaves; } } + + public TreeTrunk( int itemID, Item TreeLeaves ) : base( itemID ) + { + Movable = false; + i_leaves = TreeLeaves; + } + + public TreeTrunk( Serial serial ) : base( serial ) + { + } + + public override void OnAfterDelete() + { + if (( i_leaves != null ) && ( !i_leaves.Deleted )) + i_leaves.Delete(); + + base.OnAfterDelete(); + } + + public void OnChop( Mobile from ) + { + int testID = ((Item)i_leaves).ItemID; + + switch (testID) + { + case 0xD96: + case 0xD9A: + { + AppleTree thistree = i_leaves as AppleTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + } + case 0xDAA: + case 0xDA6: + { + PearTree thistree = i_leaves as PearTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + } + case 0xD9E: + case 0xDA2: + { + PeachTree thistree = i_leaves as PeachTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + + } + case 0xCAA: + case 0xCA8: + { + BananaTree thistree = i_leaves as BananaTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + + } + case 0xC96: + case 0xC95: + { + CocoTree thistree = i_leaves as CocoTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + + } + + case 0xC9E: + //case 0xC9E: + { + OnaxTree thistree = i_leaves as OnaxTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + + } + case 0xD37: + case 0xD38: + { + KatylTree thistree = i_leaves as KatylTree; + if ( thistree != null ) + thistree.Chop( from ); + break; + + + + + } + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + writer.Write( (Item)i_leaves ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + Item item = reader.ReadItem(); + if ( item != null ) + i_leaves = item; + } + } + + public class FruitTreeStump : Item + { + private Type t_treeType; + private int e_tree; + public Timer thisTimer; + public DateTime treeTime; + + [CommandProperty( AccessLevel.GameMaster )] + public String Sapling{ get{ return treeTime.ToString( "T" ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public String Type + { get + { + switch( e_tree ) + { + case (int)TreeType.AppleTree: return "Pommier"; + case (int)TreeType.PearTree: return "Poirier"; + case (int)TreeType.PeachTree: return "P�cher"; + case (int)TreeType.CocoTree: return "Cocotier"; + case (int)TreeType.BananaTree: return "Bananier"; + case (int)TreeType.KatylTree: return "Katyliis"; + case (int)TreeType.OnaxTree: return "TolOnax"; + + default: return "Error Bad Treetype"; + } + } + } + + [Constructable] + public FruitTreeStump( Type FruitTree ) : base( 0xDAC ) + { + Movable = false; + Hue = 0x74E; + Name = "Tronc d'arbre Coup�"; + + t_treeType = FruitTree; + + if ( FruitTree == typeof( PearTree ) ) + e_tree = (int)TreeType.PearTree; + + else if ( FruitTree == typeof( PeachTree ) ) + e_tree = (int)TreeType.PeachTree; + + else if ( FruitTree == typeof( CocoTree ) ) + e_tree = (int)TreeType.CocoTree; + + else if ( FruitTree == typeof( BananaTree ) ) + e_tree = (int)TreeType.BananaTree; + + else if ( FruitTree == typeof( KatylTree ) ) + e_tree = (int)TreeType.KatylTree; + + else if ( FruitTree == typeof( OnaxTree ) ) + e_tree = (int)TreeType.OnaxTree; + + else + e_tree = (int)TreeType.AppleTree; + + init( this ); + } + + public static void init( FruitTreeStump plant ) + { + TimeSpan delay = TreeHelper.StumpTime; + plant.treeTime = DateTime.Now + delay; + + plant.thisTimer = new TreeHelper.GrowTimer( plant, plant.t_treeType, delay ); + plant.thisTimer.Start(); + } + + public FruitTreeStump( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + + writer.Write( e_tree ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + + int e_tree = reader.ReadInt(); + switch( e_tree ) + { + case (int)TreeType.AppleTree: t_treeType = typeof(AppleTree); break; + case (int)TreeType.PearTree: t_treeType = typeof(PearTree); break; + case (int)TreeType.PeachTree: t_treeType = typeof(PeachTree); break; + case (int)TreeType.CocoTree: t_treeType = typeof(CocoTree); break; + case (int)TreeType.BananaTree: t_treeType = typeof(BananaTree); break; + case (int)TreeType.KatylTree: t_treeType = typeof(KatylTree); break; + case (int)TreeType.OnaxTree: t_treeType = typeof(OnaxTree); break; + } + + init( this ); + } + } +} + + diff --git a/Scripts/Vivre/Engines/Alimentation/Alimentation.cs b/Scripts/Vivre/Engines/Alimentation/Alimentation.cs new file mode 100644 index 0000000..e19971d --- /dev/null +++ b/Scripts/Vivre/Engines/Alimentation/Alimentation.cs @@ -0,0 +1,68 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Network; + +namespace Server.Misc +{ + public class Alimentation + { + public static void CheckHunger(Mobile m) + { + PlayerMobile pm = null; + if (m != null && m is PlayerMobile) + pm = (PlayerMobile)m; + + if (pm != null && pm.Hunger <= 10 && pm.AccessLevel == AccessLevel.Player && (DateTime.Now - pm.LastOnline > TimeSpan.FromSeconds(150))) + { + pm.SendMessage("La faim vous crispe de douleur."); + int damages = (int)((11 - pm.Hunger) * (pm.Str / 40.0)); + if (damages <= 0) damages = 1; + + if(damages > pm.Hits || !pm.Warmode || pm.Target == null) + pm.Damage(damages); + } + } + + public static void CheckThirst(Mobile m) + { + PlayerMobile pm = null; + if (m != null && m is PlayerMobile) + pm = (PlayerMobile)m; + + if (pm != null && pm.Thirst <= 10 && pm.AccessLevel == AccessLevel.Player && (DateTime.Now - pm.LastOnline > TimeSpan.FromSeconds(150))) + { + pm.SendMessage("La soif vous crispe de douleur."); + int damages = (int)((11 - pm.Thirst) * (pm.Str / 40.0)); + if (damages <= 0) damages = 1; + + if (damages > pm.Hits || !pm.Warmode || pm.Target == null) + pm.Damage(damages); + } + } + + public static void UpdateGump(Mobile m) + { + if (m != null && m is PlayerMobile && m.HasGump(typeof(AlimentationGump))) + { + Gump ag = m.FindGump(typeof(AlimentationGump)); + int x = ag.X; + int y = ag.Y; + m.CloseGump(typeof(AlimentationGump)); + m.SendGump(new AlimentationGump(m, x, y)); + } + } + + public static void SendGump(Mobile m) + { + if (m != null && m is PlayerMobile) + { + if (m.HasGump(typeof(AlimentationGump))) + m.CloseGump(typeof(Alimentation)); + + m.SendGump(new AlimentationGump(m)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Alimentation/AlimentationGump.cs b/Scripts/Vivre/Engines/Alimentation/AlimentationGump.cs new file mode 100644 index 0000000..e8305b3 --- /dev/null +++ b/Scripts/Vivre/Engines/Alimentation/AlimentationGump.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Server.Commands; +using Server.Mobiles; +using Server.Network; +using Server.Misc; + +namespace Server.Gumps +{ + public class AlimentationGump : Gump + { + public static void Initialize() + { + CommandSystem.Register("Faim", AccessLevel.Player, new CommandEventHandler(Alimentation_OnCommand)); + CommandSystem.Register("Soif", AccessLevel.Player, new CommandEventHandler(Alimentation_OnCommand)); + } + + [Usage("Faim")] + [Aliases("Soif")] + [Description("Affiche le degré de faim et de soif du joueur en cours.")] + private static void Alimentation_OnCommand(CommandEventArgs e) + { + Alimentation.SendGump(e.Mobile); + } + + Mobile m_Owner; + int x, y; + + public AlimentationGump(Mobile owner) + : this(owner, PropsConfig.GumpOffsetX, PropsConfig.GumpOffsetY) + { + } + + public AlimentationGump(Mobile owner, int x, int y) + : base(x, y) // offset x et y + { + this.m_Owner = owner; + + this.Closable = true; + this.Disposable = false; + this.Dragable = true; + this.Resizable = false; + + AddPage(0); + AddBackground(0, 0, 184, 61, 9200); + + // Hunger background (yellow or red) + if(this.m_Owner.Hunger > 10) + AddImageTiled(60, 15, 109, 11, 2057); + else + AddImageTiled(60, 15, 109, 11, 2053); + + // Hunger foreground (blue) + int hunger = (int)((this.m_Owner.Hunger / 20.0) * 109); + if(hunger > 109) hunger = 109; // To enable hunger boosts + AddImageTiled(60, 15, hunger, 11, 2054); + + // Thirst background (yellow or red) + if(this.m_Owner.Thirst > 10) + AddImageTiled(60, 35, 109, 11, 2057); + else + AddImageTiled(60, 35, 109, 11, 2053); + + // Thirst foreground (blue) + int thirst = (int)((this.m_Owner.Thirst / 20.0) * 109); + if(thirst > 109) thirst = 109; // To enable thirst boosts + AddImageTiled(60, 35, thirst, 11, 2054); + + AddLabel(15, 10, 0, @"Faim"); + AddLabel(15, 30, 0, @"Soif"); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Distillerie/Distillerie.cs b/Scripts/Vivre/Engines/Distillerie/Distillerie.cs new file mode 100644 index 0000000..66fc6a7 --- /dev/null +++ b/Scripts/Vivre/Engines/Distillerie/Distillerie.cs @@ -0,0 +1,430 @@ +using Server; +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Network; +using Server.Targeting; +using Server.Mobiles; +using Server.Targets; +using System.Text; +using System.IO; + +/* Distillerie façon Vivre , Turanar , elle se comporte d'un element principale et de quelques gadget roleplay + * 1 tonneau qui fait le distilleur * j'ai un tiledata pour un vrai mais on ne touche pas au client pour le moment* + * 1 couvercle purement RP + * 2 target 1 pour remplir 'ingrédient , un autre pour prelever le produit finni + * la chose amusante je l'ai fait avec des boléen , il m'a fallu 4 bool la ou 1 int aurais suffit avec la methode C++ + * on peut remplir n'importe quel basebeverage a partir du tonneau + * la skill cooking determine le seuil de hazard de la reussite , un elder ne rate presque jamais + * on peut etiquetter ses boissons , un autre keg sera copier pour des spiritueux. +*/ + + +namespace Server.Items +{ + public class FermentationBarrel : Item + { + public int m_Quantity; + public int m_QuantityMax; + public int m_IdIngredient; + public int m_FromBonusSkill; + private int m_StadeFermentation; + public bool m_FermentationEnCours = false; + public bool m_FermentationSuccess = true; + public bool m_FermentationDone = false; + public bool m_FermentationTimerRun = false; + + [CommandProperty(AccessLevel.GameMaster)] + public int quantity + { + get { return m_Quantity; } + set { m_Quantity = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int quantitymax + { + get { return m_QuantityMax; } + set { m_QuantityMax = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int idingredient + { + get { return m_IdIngredient; } + set { m_IdIngredient = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int FromBonusSkill + { + get { return m_FromBonusSkill; } + set { m_FromBonusSkill = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int stadeFermentation + { + get { return m_StadeFermentation; } + set { m_StadeFermentation = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool fermentationencours + { + get { return m_FermentationEnCours; } + set { m_FermentationEnCours = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool fermentationsuccess + { + get { return m_FermentationSuccess; } + set { m_FermentationSuccess = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool fermentationdone + { + get { return m_FermentationDone; } + set { m_FermentationDone = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public bool FermentationtimerRun + { + get { return m_FermentationTimerRun; } + set { m_FermentationTimerRun = value; InvalidateProperties(); } + } + + + + [Constructable] + public FermentationBarrel() + : base(0xE77) + { + + Weight = 15.0; + quantity = 0; + quantitymax = 50; + Name = "Barrille de Distillation"; + } + + public FermentationBarrel(Serial serial) + : base(serial) + { + } + + public virtual void CheckQuantity() + { + InvalidateProperties(); + if (quantity > 1) + { + Movable = true;//Movable = false; + } + else + { + Movable = true; + } + Weight = quantity + 15; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + list.Add(GetQuantityDescription()); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + LabelTo(from, GetQuantityDescription()); + } + + public virtual string GetQuantityDescription() + { + if (quantity <= 0) + return "C'est vide"; + else if (quantity <= 25) + return "c'est à moitier Vide."; + else if (quantity <= 40) + return "c'est presque plein."; + else + return "c'est plein."; + } + + public override void OnDoubleClick(Mobile from)/*me gave ce truc*/ + { + m_FromBonusSkill = (10 + ((int)(from.Skills[SkillName.Cooking].Value))); + CheckQuantity(); + if ((fermentationencours == false) && (fermentationdone == false)) + { + if ((quantity == 0) && (fermentationencours == false)) + { + from.SendMessage(0x96D, "Quel fruit voulez-vous utiliser ?"); // on lui dit qu'il doit choisir un ingredient + from.Target = new InternalInTarget(from, this); /* on appelle le target pour remplir de fruit*/ + } + else if ((quantity > 0) && (fermentationencours == false)) + { + from.SendMessage(0x96D, "Voulez-vous ajoutez un ingrédient de même type ou fermer le tonneau ?"); // on lui dit qu'il doit choisir un ingredient + from.Target = new InternalInTarget(from, this); /* on appelle le target pour remplir de fruit ou refermer*/ + } + } + else + { + if ((m_FermentationTimerRun == false) && (fermentationdone == false))// faut tester si le timer existe pas + { + new timerDistillerie(this).Start(); + m_FermentationTimerRun = true; + } + else if ((quantity > 0) && (fermentationencours == false) && (fermentationdone == true)) + { + from.SendMessage(0x96D, "Quel recipient vide voulez-vous remplir ?"); + from.Target = new InternalOutTarget(from, this);/* on appelle le target pour remplir les bouteilles*/ + } + else + { + from.PlaySound(0X021); + from.SendMessage(0x96D, "c'est pas en le secouant que ça va allez plus vite ^^"); + } + } + + + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write((int)m_Quantity); + writer.Write((int)m_QuantityMax); + writer.Write((int)m_IdIngredient); + writer.Write((int)m_FromBonusSkill); + writer.Write((bool)m_FermentationEnCours); + writer.Write((bool)m_FermentationSuccess); + writer.Write((bool)m_FermentationDone); + writer.Write((bool)m_FermentationTimerRun); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + + int version = reader.ReadInt(); + switch (version) + { + case 0: + { + m_Quantity = reader.ReadInt(); + m_QuantityMax = reader.ReadInt(); + m_IdIngredient = reader.ReadInt(); + m_FromBonusSkill = reader.ReadInt(); + m_FermentationEnCours = reader.ReadBool(); + m_FermentationSuccess = reader.ReadBool(); + m_FermentationDone = reader.ReadBool(); + m_FermentationTimerRun = reader.ReadBool(); + break; + } + } + } + + /*-------------le target pour ajouter des ingrédients -----------------------------------*/ + + private class InternalInTarget : Target + { + Mobile from; + FermentationBarrel barrel; + int Quantity, QuantityMax, IdIngredient, idFruit; + bool FermentationEnCours; + + /*this is my problem's how to give the items properties to the target ?*/ + /*reponse faut tous refaire ou presque ,c'est simple il parait.... ?*/ + + public InternalInTarget(Mobile from, FermentationBarrel t) + : base(10, false, TargetFlags.None) + { + this.from = from; + this.barrel = t; + Quantity = t.quantity; + QuantityMax = t.quantitymax; + IdIngredient = t.idingredient; + FermentationEnCours = t.fermentationencours; + + } + + protected override void OnTarget(Mobile from, object o) + { + if (!(o is Item)) + { + from.SendMessage("ciblez un objet !"); + return; + } + + int idFruit = ((Item)o).Amount; /*entrez la donnee d'un target apres l'avoir verifier ((Item)o.ce que je veux) ID du tiledata pour une pomme item.id , peach:0x9D2 , raisin: 0x9D1*/ + ArrayList packitems = new ArrayList(from.Backpack.Items); + + if (packitems.Contains(o)) + { + if (Quantity <= QuantityMax) + { + if ((o is Apple) && ((IdIngredient == 0) || (IdIngredient == 1))) + { + barrel.idingredient = 1; + from.Backpack.ConsumeTotal(typeof(Apple), idFruit); + barrel.quantity += idFruit; + } + else if ((o is Grapes) && ((IdIngredient == 0) || (IdIngredient == 2))) + { + barrel.idingredient = 2; + from.Backpack.ConsumeTotal(typeof(Grapes), idFruit); + barrel.quantity += idFruit; + } + else if ((o is Peach) && ((IdIngredient == 0) || (IdIngredient == 3))) + { + barrel.idingredient = 1; + from.Backpack.ConsumeTotal(typeof(Peach), idFruit); + barrel.quantity += idFruit; + } + else if (o is BarrelLid) + { + from.SendMessage(0x96D, "vous refermez le tonneau !"); + barrel.ItemID = 0x0FAE; /*et de 2 */ + barrel.fermentationencours = true; + from.Backpack.ConsumeTotal(typeof(BarrelLid), 1); + from.SendMessage(0x96D, "une fois fermer un simple dclick sur le tonneau fera demarrer la fermentation!"); + } + else + { + + from.SendMessage(0x96D, "il n'y a pas de recettes disponibles pour cet ingrédients"); + return; + } + } + else + { + from.SendMessage(0x96D, "Le tonneau est plein a ras bord "); + barrel.quantity = barrel.quantitymax; + return; + } + } + else + from.SendMessage(0x96D, "L'ingredient doit être dans votre inventaire!"); + return; + } + } + + /* ------------------le target pour remplir avec le produit finni--------------------------- */ + + private class InternalOutTarget : Target + { + Mobile from; + FermentationBarrel barrel; + int Quantity, QuantityMax, IdIngredient, Fruit; + bool FermentationEnCours, FermentationSuccess, FermentationDone; + + public InternalOutTarget(Mobile from, FermentationBarrel t) + : base(5, false, TargetFlags.None) + { + this.from = from; + this.barrel = t; + Quantity = t.quantity; + QuantityMax = t.quantitymax; + IdIngredient = t.idingredient; + FermentationEnCours = t.fermentationencours; + FermentationSuccess = t.fermentationsuccess; + FermentationDone = t.fermentationdone; + } + + protected override void OnTarget(Mobile from, object o) + { + ArrayList packitems = new ArrayList(from.Backpack.Items); + if (packitems.Contains(o)) + if (o is BaseBeverage) + { + BaseBeverage p = (BaseBeverage)o; + + if ((barrel.quantity >= p.Quantity) && (p.Quantity == 0)) + { + if ((barrel.idingredient == 3) && (barrel.fermentationsuccess == true)) + { + p.Content = BeverageType.Liquor; + p.Quantity = p.MaxQuantity; + barrel.quantity = barrel.quantity - p.MaxQuantity; + from.SendMessage(0x96D, "Vous remplissez le recipient avec de la liqueur."); + barrel.Name = "Barille: " + barrel.quantity.ToString() + "/50 Litres de jus de peche."; + from.PlaySound(0X240); + + } + else if ((barrel.idingredient == 3) && (barrel.fermentationsuccess == false)) + { + p.Content = BeverageType.JusPeche; + p.Quantity = p.MaxQuantity; + barrel.quantity = barrel.quantity - p.MaxQuantity; + from.SendMessage(0x96D, "Vous remplissez le recipient avec du jus de peche."); + barrel.Name = "Barille: " + barrel.quantity.ToString() + "/50 Litres de jus de peche."; + from.PlaySound(0X240); + + } + else if ((barrel.idingredient == 2) && (barrel.fermentationsuccess == true)) + { + p.Content = BeverageType.Wine; + p.Quantity = p.MaxQuantity; + barrel.quantity = barrel.quantity - p.MaxQuantity; + from.SendMessage(0x96D, "Vous remplissez le recipient avec du vin."); + from.PlaySound(0X240); + barrel.Name = "Barille: " + barrel.quantity.ToString() + "/50 Litres de vin."; + } + else if ((barrel.idingredient == 2) && (barrel.fermentationsuccess == false)) + { + p.Content = BeverageType.JusRaisin; + p.Quantity = p.MaxQuantity; + barrel.quantity = barrel.quantity - p.MaxQuantity; + from.SendMessage(0x96D, "Vous remplissez le recipient avec de jus de raisin."); + from.PlaySound(0X240); + barrel.Name = "barille: " + barrel.quantity.ToString() + "/50 Litres de jus de raisin."; + } + else if ((barrel.idingredient == 1) && (barrel.fermentationsuccess == true)) + { + p.Content = BeverageType.Cider; + p.Quantity = p.MaxQuantity; + barrel.quantity = barrel.quantity - p.MaxQuantity; + from.SendMessage(0x96D, "Vous remplissez le recipient avec du cidre."); + barrel.Name = "Barille: " + barrel.quantity.ToString() + "/50 Litres de cidre."; + from.PlaySound(0X240); + } + else if ((barrel.idingredient == 1) && (barrel.fermentationsuccess == false)) + { + p.Content = BeverageType.JusPomme; + p.Quantity = p.MaxQuantity; + barrel.quantity = barrel.quantity - p.MaxQuantity; + from.SendMessage(0x96D, "Vous remplissez le recipient avec du jus de pomme."); + barrel.Name = "Barille: " + barrel.quantity.ToString() + "/50 Litres de jus de pomme."; + from.PlaySound(0X240); + } + else + { + from.SendMessage(0x84B, "il y a un problemes de Quantité"); + + } + + } + else + { + from.SendMessage(0x84B, "Utilisez un récipient vide de préférence !"); + + } + + if (barrel.quantity <= 0) + { + barrel.quantity = 0; + barrel.idingredient = 0; + barrel.Name = "Barrille de Distillation : (Vide)"; + barrel.fermentationencours = false; + barrel.fermentationdone = false; + } + + } + else + from.SendMessage(0x96D, "L'objet doit être dans votre inventaire!"); + } + } + /*---------------------------------------------------------------------------------------------------------*/ + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Distillerie/DistillerieTimer.cs b/Scripts/Vivre/Engines/Distillerie/DistillerieTimer.cs new file mode 100644 index 0000000..d2848ff --- /dev/null +++ b/Scripts/Vivre/Engines/Distillerie/DistillerieTimer.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Items; +using Server.Prompts; + +namespace Server.Items +{ + // Le timer de fermentation distçillerie + public class timerDistillerie : Timer + { + private FermentationBarrel barrelDistiTimer; + + + public timerDistillerie(FermentationBarrel m_TimerDistillerie) : base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(10), 100) + //base( TimeSpan.FromSeconds(delai avant premier tick),TimeSpan.FromSeconds(durée du tick),nombre de répétition) + { + Priority = TimerPriority. FiftyMS ; + barrelDistiTimer = m_TimerDistillerie; + } + + protected override void OnTick() + { + if (barrelDistiTimer.stadeFermentation <= 99) + { + ++barrelDistiTimer.stadeFermentation; + barrelDistiTimer.Name = "Fermentation : "+ barrelDistiTimer.stadeFermentation + " %"; + } + if (barrelDistiTimer.stadeFermentation == 100) + { + barrelDistiTimer.Name = "Fermentation : *Pret* plus qu'a gouter"; + barrelDistiTimer.stadeFermentation = 0; + barrelDistiTimer.fermentationencours = false; + barrelDistiTimer.fermentationdone = true; + barrelDistiTimer.FermentationtimerRun = false; + if (barrelDistiTimer.FromBonusSkill < Utility.Random(1, 1201)) + { + barrelDistiTimer.fermentationsuccess = true; + } + else + { + barrelDistiTimer.fermentationsuccess = false; + } + } + } + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Distillerie/Etiquette.cs b/Scripts/Vivre/Engines/Distillerie/Etiquette.cs new file mode 100644 index 0000000..f0503b9 --- /dev/null +++ b/Scripts/Vivre/Engines/Distillerie/Etiquette.cs @@ -0,0 +1,155 @@ +using Server; +using Server.Targeting; +using Server.Gumps; +using Server.Network; +using System.Collections; + +namespace Server.Items +{ + + public class BottleInscriber : Item + { + private int m_UsesRemaining; + + [CommandProperty(AccessLevel.GameMaster)] + public int UsesRemaining + { + get { return m_UsesRemaining; } + set { m_UsesRemaining = value; InvalidateProperties(); } + } + + [Constructable] + public BottleInscriber() + : base(0x0FF3) + { + Weight = 1.0; + Hue = 0x96D; + Name = "Etiquettes"; + UsesRemaining = 20; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add(1060584, UsesRemaining.ToString()); + } + + public virtual void DisplayDurabilityTo(Mobile from) + { + LabelToAffix(from, 1017323, AffixType.Append, ": " + UsesRemaining.ToString()); + } + + public override void OnDoubleClick(Mobile from) + { + from.Target = new InternalTarget(from, this); + } + + public BottleInscriber(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.Write((int)m_UsesRemaining); // on ecrit le nombre de charge + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + + int version = reader.ReadInt(); + switch (version) + { + case 0: + { + m_UsesRemaining = reader.ReadInt();// on lit le nombre de charge + break; + } + } + } + + private class InternalTarget : Target + { + private Mobile m_from; + private BottleInscriber m_tool; + + public InternalTarget(Mobile from, BottleInscriber tool) + : base(10, false, TargetFlags.None) + { + m_from = from; + m_tool = tool; + } + + protected override void OnTarget(Mobile from, object o) + { + if (!(o is Bottle) && !(o is BaseBeverage)) + { + from.SendMessage("Ceci n'est pas étiquetable"); + return; + } + + if ( o is Item && !((Item)o).IsChildOf( from.Backpack )) + { + from.SendMessage("L'objet doit être dans votre sac"); + return; + } + + m_tool.UsesRemaining--; + from.SendGump(new BottleInscriberGump(from, o)); + if (m_tool.UsesRemaining <= 0) + m_tool.Delete(); + } + } + } +} + +namespace Server.Gumps +{ + + public class BottleInscriberGump : Gump + { + private Item m_Bottle; + private Mobile m_From; + + public BottleInscriberGump(Mobile from, object o) + : base(0, 0) + { + m_Bottle = o as Item; + m_From = from; + + AddPage(0); + AddBackground(1, 9, 372, 144, 5054); + AddBackground(11, 19, 352, 124, 3500); + AddLabel(50, 27, 0, "Quel nom désirez vous lui donner ?"); + AddImage(48, 49, 1141); + AddTextEntry(57, 50, 91, 18, 0x000, 0, "Écrire ici"); + AddButton(62, 85, 4023, 4025, 1, GumpButtonType.Reply, 0); + AddButton(222, 85, 4020, 4022, 2, GumpButtonType.Reply, 0); + AddLabel(97, 93, 0, "Ok"); + AddLabel(258, 93, 0, "Annuler"); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + switch (info.ButtonID) + { + case 0: + break; + case 1: + m_Bottle.Name = string.Format("Bouteille de {0}", (string)info.GetTextEntry(0).Text); + break; + case 2: + break; + + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MDDS/Books/SpherePlanaireAnalyse1.cs b/Scripts/Vivre/Engines/MDDS/Books/SpherePlanaireAnalyse1.cs new file mode 100644 index 0000000..4fc59c1 --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/Books/SpherePlanaireAnalyse1.cs @@ -0,0 +1,134 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpherePlanaireAnalyse1 : RedBook + { + public static readonly BookContent Content = new BookContent + ( + "Sph�re planaire t.1", "Moonglow", + + new BookPageInfo + ( + " C'est sous les ruines", + "de Magincia que fut", + "recemment d�couvert", + "par des pillards de" , + "Buccanneer la Sphere", + "planaire. Ils d�couvrirent", + "� leurs d�pends ses", + "pouvoirs,emport�s dans" + ), + new BookPageInfo + ( + "un monde inconnu dont", + "peu revinrent vivants.", + "", + "L'objet nous fut vendu" , + "pour une importante" , + "somme d'argent apr�s" , + "une vente aux ench�res" + ), + new BookPageInfo + ( + "dans les souterrains de", + "l'ile des pirates. Notre" , + "unique rival pour son", + "acquisition n'a pas �t�", + "identifi�,mais ce n'est pas", + "la premi�re fois que des", + "mages ind�pendants tentent", + "de s'approprier des objets" + ), + new BookPageInfo + ( + "magiques,mais c'est" , + "exceptionnel qu'un", + "concurrent puisse mettre", + "autant d'or dans la balance.", + "", + " Nous avons d� recourir �", + "d'autres moyens de pressions", + "pour encourager nos amis" + ), + new BookPageInfo + ( + "pillards � nous la vendre.", + "Les pouvoirs magiques de", + "la Sph�re planaire ont �t�", + "largement affaiblis par nos", + "rituels,afin que nous", + "puissions en contr�ler les", + "effets.", + " Malencontreusement,cela a" + ), + new BookPageInfo + ( + "d�clench� quelque", + "m�canisme de protection et", + " bloqu� une partie de ses", + "effets qui, pour le moment,", + "demeurent hors d'�tudes.", + "", + " Autre probl�matique : notre", + "impossibilit� � rapporter la" + ), + new BookPageInfo + ( + "sph�re planaire � Moonglow.", + "Alors que nous quittons", + " les ruines de Magincia,une", + "temp�te magn�tique se leva", + " aussit�t, nous obligeant", + "� quitter notre cap pour", + "ne pas finir par le fond.", + "Nous avons d� nous arr�ter �" + ), + new BookPageInfo + ( + "Occlo,de la d�funte famille de", + "Roald,et tant qu'une solution ", + "n'aura pas �t� trouv�e la Sph�re", + "devra y demeurer et nos �tudes", + "accomplies sur place. " + ) + + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public SpherePlanaireAnalyse1() : base( false ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( "Sphere planaire T.1" ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, "etude par le Conseil de Moonglow" ); + } + + public SpherePlanaireAnalyse1( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MDDS/Books/SpherePlanaireAnalyse2.cs b/Scripts/Vivre/Engines/MDDS/Books/SpherePlanaireAnalyse2.cs new file mode 100644 index 0000000..7061edc --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/Books/SpherePlanaireAnalyse2.cs @@ -0,0 +1,181 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpherePlanaireAnalyse2 : RedBook + { + public static readonly BookContent Content = new BookContent + ( + "Sph�re planaire t.2", "Moonglow", + + new BookPageInfo + ( +" Nos premi�res expeditions", +"nous ont permis de reunir", +"les informations suivantes:", +"", +"Poser la main sur ell", +"nous absorbe a l'interieur", +"et nous projette dans un ", +"monde souterrain. D'apr�s" + + ), + new BookPageInfo + ( +"nos outils,il s'agit d'un", +"demi-plan interm�diaire", +"d'origine artificielle. Qui", +"qu'en soit le cr�ateur,il", +"maitrise ou maitrisait", +"l'archimagie.", +"", +" Ce monde souterrain est" + ), + new BookPageInfo + ( +"fait de grottes,mais sans ", +"chemin physique entre", +"elles. La circulation se", +" fait exclusivement par", +" le biais de portails ", +"magiques,qui", +"n'apparaissent qu'apr�s", +"resolution d'une epreuve." + ), + new BookPageInfo + ( +"", +" Ces �preuves sont la", +"majorit� du temps", +"sommaires : des", +"confrontations avec des ", +"cr�atures diverses,ne", +"vivant pas ici.", +"Elles semblent invoqu�es," + ), + new BookPageInfo + ( +"ou bien t�l�port�es.", +"Nous pourrions r�sumer", +"l'endroit � des ar�nes.", + "", +" A noter toutefois ", +"qu'exceptionnellement,nous", +"f�mes confront�s � des", +"�preuves differentes,tels" + ), + new BookPageInfo + ( +"des �nigmes ou des s�ries", +"de pi�ges.", +"", +" Pendant nos explorations,", +"nous avons souvent eu le ", +"sentiment d'�tre observ�s,", +"et � de br�ves occasions ", +"avons m�me entendus des" + ), + new BookPageInfo + ( +"voix �tranges. Peut-�tre", +"les fant�mes de ceux ", +"n'ayant eu la chance d'en", +" sortir vivants.", +"", +" Afin de faciliter notre", +"�tude, nous avons impos�", +" � la sph�re planaire de" + ), + new BookPageInfo + ( +"nouvelles r�gles,esp�rant", +"que cela ne provoque pas", +"d'effets n�gatifs. La", +"principale est un", +"sortil�ge pour nous", +"reconduire � l'ext�rieur", +"si nous devions subir un", +" coup fatal." + ), + new BookPageInfo + ( +" Occlo comprends une", +"forte population de", +"jeunes aventuriers :", +"nous pourrions en engager", +"certains pour en explorer", +"r�guli�rement les recoins", +"et les secrets,afin ", +"que nous puissions r�unir" + + ), + new BookPageInfo + ( +" de nouvelles hypoth�ses", +" et rep�rer les plus gros", +"dangers auxquels nos", +"exp�ditions pourraient", +" �tre confront�s.", +"", +" De m�me,n'hesitons pas", +"� envoyer ces" + + ), + + new BookPageInfo + ( +"mercenaires � la recherche", +"d'informations � son sujet.", +"Je suis certain que la", +"Sphere Planaire se trouve", +"sur Tenelia depuis", +"longtemps, et qu'il existe", +"des methodes connues pour", +"en exploiter la pleine" + ), + new BookPageInfo + ( + +"puissance.Reste � les", +"d�couvrir." + ) + + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public SpherePlanaireAnalyse2() : base( false ) + { + } + + public override void AddNameProperty( ObjectPropertyList list ) + { + list.Add( "Sphere planaire T.2" ); + } + + public override void OnSingleClick( Mobile from ) + { + LabelTo( from, "etude par le Conseil de Moonglow" ); + } + + public SpherePlanaireAnalyse2( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int)0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MDDS/MDDSCommands.cs b/Scripts/Vivre/Engines/MDDS/MDDSCommands.cs new file mode 100644 index 0000000..12120c5 --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/MDDSCommands.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Commands; + +namespace Server.MDDS +{ + class MDDSCommands + { + public static void Initialize() + { + CommandSystem.Register("DeleteMDDS", AccessLevel.Administrator, new CommandEventHandler(DeleteMDDS_OnCommand)); + CommandSystem.Register("WhereIsMDDS", AccessLevel.GameMaster, new CommandEventHandler(WhereIsMDDS_OnCommand)); + } + + [Usage("DeleteMDDS")] + [Description("Supprime le MDDSStarter")] + public static void DeleteMDDS_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + List toDel = new List(); + foreach (Item i in World.Items.Values) + { + if (i is MDDSStarter) toDel.Add(i); + } + + for (int i = 0; i < toDel.Count; i++) + { + from.SendMessage("MDDSStarter has been deleted on {0} at [{1},{2},{3}]", toDel[i].Map, toDel[i].X, toDel[i].Y, toDel[i].Z); + toDel[i].Delete(); + } + } + + [Usage("WhereIsMDDS")] + [Description("Indique la position du MDDS")] + public static void WhereIsMDDS_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + foreach (Item i in World.Items.Values) + { + if (i is MDDSStarter) + from.SendMessage("MDDSStarter on {0} at [{1},{2},{3}]", i.Map, i.X, i.Y, i.Z); + } + } + } +} diff --git a/Scripts/Vivre/Engines/MDDS/MDDSCoords.cs b/Scripts/Vivre/Engines/MDDS/MDDSCoords.cs new file mode 100644 index 0000000..bfeced5 --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/MDDSCoords.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.MDDS +{ + class MDDSCoords + { + private static List m_Rooms = new List(); + + public static List Rooms { get { return m_Rooms; } } + + public static void Initialize() + { + m_Rooms.Add(new RoomCoords(new Point3D(5139, 2019, 0), GetExits(1))); // salle 1 + m_Rooms.Add(new RoomCoords(new Point3D(5207, 1994, 0), GetExits(2))); // salle 2 + m_Rooms.Add(new RoomCoords(new Point3D(5239, 2039, 0), GetExits(3))); // salle 3 + m_Rooms.Add(new RoomCoords(new Point3D(5275, 2043, 0), GetExits(4))); // salle 4 - BOSS? + m_Rooms.Add(new RoomCoords(new Point3D(5271, 1935, 0), GetExits(5))); // salle 5 + m_Rooms.Add(new RoomCoords(new Point3D(5187, 1942, 0), GetExits(6))); // salle 6 + m_Rooms.Add(new RoomCoords(new Point3D(5139, 1915, 0), GetExits(7))); // salle 7 + m_Rooms.Add(new RoomCoords(new Point3D(5167, 1831, 0), GetExits(8))); // salle 8 + m_Rooms.Add(new RoomCoords(new Point3D(5222, 1863, 0), GetExits(9))); // salle 9 + m_Rooms.Add(new RoomCoords(new Point3D(5308, 1859, 0), GetExits(10))); // salle 10 + } + + private static List GetExits(int roomNumber) + { + List exits = new List(); + switch (roomNumber) + { + case 1: + exits.Add(new Point3D(5132, 1946, 0)); + exits.Add(new Point3D(5156, 1955, 0)); + exits.Add(new Point3D(5136, 1979, 0)); + break; + case 2: + exits.Add(new Point3D(5226, 1944, 0)); + exits.Add(new Point3D(5261, 1977, 0)); + exits.Add(new Point3D(5219, 1964, 0)); + break; + case 3: + exits.Add(new Point3D(5195, 2011, 0)); + exits.Add(new Point3D(5188, 2025, 0)); + exits.Add(new Point3D(5206, 2031, 0)); + break; + case 4: + exits.Add(new Point3D(5322, 1961, 0)); + exits.Add(new Point3D(5359, 1996, 0)); + exits.Add(new Point3D(5356, 2019, 0)); + break; + case 5: + exits.Add(new Point3D(5286, 1878, 0)); + exits.Add(new Point3D(5331, 1899, 0)); + exits.Add(new Point3D(5329, 1919, 0)); + break; + case 6: + exits.Add(new Point3D(5219, 1889, 0)); + exits.Add(new Point3D(5194, 1877, 0)); + exits.Add(new Point3D(5193, 1900, 0)); + break; + case 7: + exits.Add(new Point3D(5157, 1889, 0)); + exits.Add(new Point3D(5169, 1874, 0)); + exits.Add(new Point3D(5134, 1870, 0)); + break; + case 8: + exits.Add(new Point3D(5149, 1845, 0)); + exits.Add(new Point3D(5140, 1824, 0)); + exits.Add(new Point3D(5153, 1835, 0)); + break; + case 9: + exits.Add(new Point3D(5214, 1833, 0)); + exits.Add(new Point3D(5266, 1849, 0)); + exits.Add(new Point3D(5249, 1837, 0)); + break; + case 10: + exits.Add(new Point3D(5340, 1822, 0)); + exits.Add(new Point3D(5316, 1816, 0)); + exits.Add(new Point3D(5336, 1809, 0)); + break; + } + return exits; + } + } + + class RoomCoords + { + private Point3D m_Entry; + private List m_Exits; + + public Point3D Entry { get { return m_Entry; } } + public List Exits { get { return m_Exits; } } + + public RoomCoords(Point3D entry, List exits) + { + m_Entry = entry; + m_Exits = exits; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MDDS/MDDSGate.cs b/Scripts/Vivre/Engines/MDDS/MDDSGate.cs new file mode 100644 index 0000000..649626c --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/MDDSGate.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.MDDS +{ + class MDDSGate : Moongate + { + private MDDSRoom m_Room; + + public MDDSGate(MDDSRoom room) : base() + { + m_Room = room; + Target = new Point3D(m_Room.Entry); + TargetMap = m_Room.Instance.Map; + Dispellable = false; + } + + public MDDSGate(Serial serial) + { + } + + public override void UseGate(Mobile m) + { + if (m_Room == null) + { + m.SendMessage("Tu reçois une baffe de Scriptiz !"); + return; + } + Target = new Point3D(m_Room.Instance.GetNextRoom(m_Room, m)); + if (m.Map != TargetMap) TargetMap = m.Map; + m_Room.DelGatesExcept(this); + base.UseGate(m); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/MDDS/MDDSInstance.cs b/Scripts/Vivre/Engines/MDDS/MDDSInstance.cs new file mode 100644 index 0000000..1da373b --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/MDDSInstance.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Mobiles; + +namespace Server.MDDS +{ + class MDDSInstance + { + private MDDSStarter m_Starter; + private List m_Followers; + private Map m_Map; + private List m_Rooms; + private Point3D m_Origin; + private Map m_OriginMap; + + public List Followers + { + get { return m_Followers; } + set { m_Followers = value; } + } + + public Map Map { get { return m_Map; } } + + public List Rooms + { + get { return m_Rooms; } + set { m_Rooms = value; } + } + + public MDDSInstance(MDDSStarter starter, Map map, Point3D origin, Map originMap) + { + m_Starter = starter; + m_Followers = new List(); + m_Map = map; + m_Rooms = new List(); + m_Origin = origin; + m_OriginMap = originMap; + } + + public Point3D GetNextRoom(MDDSRoom actualRoom, Mobile m) + { + int index = m_Rooms.IndexOf(actualRoom); + if (++index < m_Rooms.Count) + { + m.SendMessage("Progression : {0} sur {1}.", (index + 1), m_Rooms.Count); + return m_Rooms[index].Entry; + } + else + { + m.Map = m_OriginMap; + m_Followers.Remove(m); + m_Starter.CleanInstances(); + return m_Origin; + } + } + } +} diff --git a/Scripts/Vivre/Engines/MDDS/MDDSRoom.cs b/Scripts/Vivre/Engines/MDDS/MDDSRoom.cs new file mode 100644 index 0000000..3796b2f --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/MDDSRoom.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.MDDS +{ + class MDDSRoom + { + private MDDSInstance m_Instance; + private Point3D m_Entry; + private List m_Exits; + private List m_Monsters; + private List m_ExitGates; + + public MDDSInstance Instance { get { return m_Instance; } } + public Point3D Entry { get { return m_Entry; } } + public List ExitGates { get { return m_ExitGates; } } + + public MDDSRoom(MDDSInstance instance, Point3D entry, List exits) + { + m_Instance = instance; + m_Entry = entry; + m_Exits = exits; + m_Monsters = new List(); + m_ExitGates = new List(); + GenExits(); + } + + public void GenExits() + { + foreach (Point3D p in m_Exits) + { + MDDSGate g = new MDDSGate(this); + g.MoveToWorld(p, m_Instance.Map); + m_ExitGates.Add(g); + } + } + + public void DelGatesExcept(MDDSGate gate) + { + for (int i = 0; i < m_ExitGates.Count; i++) + if (m_ExitGates[i] != gate) m_ExitGates[i].Delete(); + } + } +} diff --git a/Scripts/Vivre/Engines/MDDS/MDDSStarter.cs b/Scripts/Vivre/Engines/MDDS/MDDSStarter.cs new file mode 100644 index 0000000..0c3a534 --- /dev/null +++ b/Scripts/Vivre/Engines/MDDS/MDDSStarter.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using Server; +using Server.Items; + +namespace Server.MDDS +{ + class MDDSStarter : NoxCrystal + { + private List m_Instances = new List(); + private List m_Maps = null; + + [Constructable] + public MDDSStarter() : base() + { + Movable = false; + LootType = LootType.Regular; + } + + public MDDSStarter(Serial serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (m_Maps == null) m_Maps = FillMaps(); + + if (m_Instances.Count >= m_Maps.Count || !from.InRange(this.Location, 2)) + { + base.OnDoubleClick(from); + return; + } + + MDDSInstance newInstance = new MDDSInstance(this, FindFreeMap(), from.Location, from.Map); + ClearGates(newInstance.Map); + newInstance.Rooms = GenRooms(newInstance); + newInstance.Followers.Add(from); + + from.SendMessage("Bienvenue dans le MDDS de la map {0}...", newInstance.Map.Name); + from.MoveToWorld(newInstance.Rooms[0].Entry, newInstance.Map); + + m_Instances.Add(newInstance); + } + + private List FillMaps() + { + List maps = new List(); + maps.Add(Map.Felucca2); + maps.Add(Map.Felucca3); + maps.Add(Map.Felucca4); + maps.Add(Map.Felucca5); + maps.Add(Map.Felucca6); + return maps; + } + + public void CleanInstances() + { + for (int i = 0; i < m_Instances.Count; i++) + { + if (m_Instances[i] != null && m_Instances[i].Followers.Count == 0) + { + for (int j = 0; j < m_Instances[i].Rooms.Count; j++) + { + for (int k = 0; k < m_Instances[i].Rooms[j].ExitGates.Count; k++) + { + m_Instances[i].Rooms[j].ExitGates[k].Delete(); + } + } + m_Instances.Remove(m_Instances[i]); + } + } + } + + private Map FindFreeMap() + { + foreach (Map m in m_Maps) + { + bool isExisting = false; + foreach (MDDSInstance mi in m_Instances) + { + if (mi.Map == m) + { + isExisting = true; + break; + } + } + + if (!isExisting) return m; + } + return null; + } + + private List GenRooms(MDDSInstance instance) + { + List rooms = new List(); + + List tmp = new List(MDDSCoords.Rooms); + while (tmp.Count > 0) + { + int next = Utility.RandomMinMax(0, tmp.Count - 1); + rooms.Add(new MDDSRoom(instance, tmp[next].Entry, tmp[next].Exits)); + tmp.RemoveAt(next); + } + return rooms; + } + + public static void ClearGates(Map map) + { + List toDel = new List(); + foreach (Item i in World.Items.Values) + { + if (i is MDDSGate && i.Map == map) toDel.Add(i); + } + for (int i = 0; i < toDel.Count; i++) + toDel[i].Delete(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/MalasAlignment/AlignCommands.cs b/Scripts/Vivre/Engines/MalasAlignment/AlignCommands.cs new file mode 100644 index 0000000..a7a0260 --- /dev/null +++ b/Scripts/Vivre/Engines/MalasAlignment/AlignCommands.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Misc; + +namespace Server.Commands +{ + public class AlignCommands + { + public static void Initialize() + { + CommandSystem.Register("AlignStats", AccessLevel.GameMaster, new CommandEventHandler(Align_OnCommand)); + CommandSystem.Register("BBMABOB", AccessLevel.Administrator, new CommandEventHandler(BBMABOB_OnCommand)); + // Bob Bring Me A Bottle Of Beer <3 + CommandSystem.Register("AlignReset", AccessLevel.Administrator, new CommandEventHandler(AlignReset_OnCommand)); + + } + + private static void Align_OnCommand(CommandEventArgs e) + { + if (Alignments.Instance.MobilesKills.Keys.Count > 0) + { + e.Mobile.SendMessage("Mobiles kills : "); + foreach (Alignment a in Alignments.Instance.MobilesKills.Keys) + { + e.Mobile.SendMessage(a.ToString() + " : " + Alignments.Instance.MobilesKills[a]); + } + } + + if (Alignments.Instance.PlayersKills.Keys.Count > 0) + { + e.Mobile.SendMessage("Players kills : "); + foreach (Alignment a in Alignments.Instance.PlayersKills.Keys) + { + e.Mobile.SendMessage(a.ToString() + " : " + Alignments.Instance.PlayersKills[a]); + } + } + } + + private static void BBMABOB_OnCommand(CommandEventArgs e) + { + Alignments.Instance.MoveToWorld(e.Mobile.Location, e.Mobile.Map); + } + + private static void AlignReset_OnCommand(CommandEventArgs e) + { + Alignments.Reset(); + } + } +} diff --git a/Scripts/Vivre/Engines/MalasAlignment/Alignments.cs b/Scripts/Vivre/Engines/MalasAlignment/Alignments.cs new file mode 100644 index 0000000..c967765 --- /dev/null +++ b/Scripts/Vivre/Engines/MalasAlignment/Alignments.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Mobiles; + +namespace Server.Misc +{ + public enum Alignment + { + Neutral = 0x0, + Good = 0x1, + Evil = 0x2 + } + + public class Alignments : Item, ISerializable + { + // Scriptiz : Pattern singleton (Plume) + private static Alignments m_Instance; + public static Alignments Instance + { + get + { + if (m_Instance == null) + m_Instance = new Alignments(); + + return m_Instance; + } + } + + // Don't use this !!! (BBMABOB is cool) + public static void Reset() + { + List toDelete = new List(); + foreach (Item i in World.Items.Values) + { + if (i is Alignments && i != null) + { + toDelete.Add(i); + } + } + + for (int i = 0; i < toDelete.Count; i++) + toDelete[i].Delete(); + + if (m_Instance != null) + m_Instance.Delete(); + + m_Instance = new Alignments(); + } + + public static void Initialize() + { + EventSink.PlayerDeath += new PlayerDeathEventHandler(EventSink_PlayerDeath); + } + + public static void EventSink_PlayerDeath(PlayerDeathEventArgs e) + { + PlayerMobile killed = e.Mobile as PlayerMobile; + if (killed == null || !(killed is PlayerMobile) || killed.Map != Map.Malas) return; + PlayerMobile killer = killed.LastKiller as PlayerMobile; + if (killer == null || killer.Map != Map.Malas || killer.AccessLevel > AccessLevel.Player) return; + + // don't mind about neutral alignment + if (killed.Alignment != Alignment.Neutral) + { + // If killed is not in the same alignment, increase counter + // otherwise, decrease it + if (killed.Alignment != killer.Alignment) + Alignments.Instance.incKills(killer.Alignment, killed.Player); + else if (killed.Alignment == killer.Alignment) + Alignments.Instance.decKills(killer.Alignment, killed.Player); + } + } + + private Dictionary m_MobilesKills; + private Dictionary m_PlayersKills; + + public Dictionary MobilesKills + { + get + { + // TODO clone ? + return m_MobilesKills; + } + } + + public Dictionary PlayersKills + { + get + { + // TODO clone ? + return m_PlayersKills; + } + } + + public Alignments() + : base(0x48E3) + { + Name = "Nounours de Scriptiz"; + Weight = 1e3; + Movable = false; + + m_MobilesKills = new Dictionary(); + m_PlayersKills = new Dictionary(); + + m_Instance = this; + } + + public Alignments(Serial serial) + : this() + { + } + + public void incKills(Alignment a, bool player) + { + if (player) + { + if (this.m_PlayersKills.ContainsKey(a)) + this.m_PlayersKills[a]++; + else + this.m_PlayersKills.Add(a, 1); + } + else + { + if (this.m_MobilesKills.ContainsKey(a)) + this.m_MobilesKills[a]++; + else + this.m_MobilesKills.Add(a, 1); + } + } + + public void decKills(Alignment a, bool player) + { + if (player) + { + if (this.m_PlayersKills.ContainsKey(a)) + this.m_PlayersKills[a]++; + else + this.m_PlayersKills.Add(a, 1); + } + else + { + if (this.m_MobilesKills.ContainsKey(a)) + this.m_MobilesKills[a]++; + else + this.m_MobilesKills.Add(a, 1); + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + + // Players kills + writer.Write(m_PlayersKills.Count); + foreach (KeyValuePair kvp in m_PlayersKills) + { + writer.Write((int)kvp.Key); + writer.Write(kvp.Value); + } + + // Mobiles kills + writer.Write(m_MobilesKills.Count); + foreach (KeyValuePair kvp in m_MobilesKills) + { + writer.Write((int)kvp.Key); + writer.Write(kvp.Value); + } + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + // Players kills + int playersKills = reader.ReadInt(); + for (int i = 0; i < playersKills; i++) + { + Alignment key = (Alignment)reader.ReadInt(); + int val = reader.ReadInt(); + m_PlayersKills[key] = val; + } + + // Mobiles kills + int mobilesKills = reader.ReadInt(); + for (int i = 0; i < mobilesKills; i++) + { + Alignment key = (Alignment)reader.ReadInt(); + int val = reader.ReadInt(); + m_MobilesKills[key] = val; + } + break; + } + } + + m_Instance = this; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MalasAlignment/ideas.txt b/Scripts/Vivre/Engines/MalasAlignment/ideas.txt new file mode 100644 index 0000000..8f4782e --- /dev/null +++ b/Scripts/Vivre/Engines/MalasAlignment/ideas.txt @@ -0,0 +1 @@ +- decrease kills counters on killed by a monster \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MilkAndCheese/CheeseForm.cs b/Scripts/Vivre/Engines/MilkAndCheese/CheeseForm.cs new file mode 100644 index 0000000..88aa6aa --- /dev/null +++ b/Scripts/Vivre/Engines/MilkAndCheese/CheeseForm.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Prompts; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Gumps; +using Server.ContextMenus; + +namespace Server.Items +{ + public class CheeseForm : Item + { + private Milk m_Content; + private DateTime m_TimeStart; + private int m_MaxQuantity = 10; + private int m_CheeseAmount = 5; + private int m_Quantity; + private double m_CookingValue; + + [CommandProperty(AccessLevel.GameMaster)] + public Milk Content + { + get { return m_Content; } + set { m_Content = value; ComputeName(); } + } + + [CommandProperty(AccessLevel.Administrator)] + public DateTime TimeStart + { + get { return m_TimeStart; } + set { m_TimeStart = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.Administrator)] + public int MaxQuantity + { + get { return m_MaxQuantity; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Quantity + { + get { return m_Quantity; } + set { m_Quantity = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public double CookingValue + { + get { return m_CookingValue; } + set { m_CookingValue = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int CheeseAmount + { + get { return m_CheeseAmount; } + } + + [Constructable] + public CheeseForm() + : base(0x0E78) + { + Weight = 10.0; + Name = "Moule � fromage"; + Hue = 0x481; + } + + public CheeseForm(Serial serial) + : base(serial) + { + } + + public void ComputeName() + { + string basename = "Moule � fromage"; + string nameaddon = ""; + + switch (Content) + { + case (Milk.Cow): nameaddon += " de vache"; break; + case (Milk.Goat): nameaddon += " de ch�vre"; break; + case (Milk.Sheep): nameaddon += " de brebis"; break; + } + + Name = basename + nameaddon; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (MaxQuantity <= Quantity) + list.Add("En fermentation depuis {0} jours", (int)(DateTime.Now - TimeStart).TotalDays); + + list.Add("Ce moule contient {0} litre{1} de lait", Quantity, (Quantity > 0)?"s":""); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + writer.WriteEncodedInt((int)m_Content); + writer.Write((DateTime)m_TimeStart); + writer.Write((int)m_MaxQuantity); + writer.Write((int)m_Quantity); + writer.Write((double)m_CookingValue); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Content = (Milk)reader.ReadEncodedInt(); + m_TimeStart = reader.ReadDateTime(); + m_MaxQuantity = reader.ReadInt(); + m_Quantity = reader.ReadInt(); + m_CookingValue = reader.ReadDouble(); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && (Quantity >= MaxQuantity)) + list.Add(new ContextMenus.CheeseFormMenu(from, this)); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MilkAndCheese/CheeseFormMenu.cs b/Scripts/Vivre/Engines/MilkAndCheese/CheeseFormMenu.cs new file mode 100644 index 0000000..7ec7a41 --- /dev/null +++ b/Scripts/Vivre/Engines/MilkAndCheese/CheeseFormMenu.cs @@ -0,0 +1,91 @@ +using System; +using Server.Items; + +namespace Server.ContextMenus +{ + public class CheeseFormMenu : ContextMenuEntry + { + private Mobile m_From; + private CheeseForm m_Cheese; + + public CheeseFormMenu(Mobile from, CheeseForm CheeseForm) + : base(5114, 1) + { + m_From = from; + m_Cheese = CheeseForm; + } + + public override void OnClick() + { + DateTime now = DateTime.Now; + + if ((now - m_Cheese.TimeStart).TotalDays <= 2) + { + m_From.SendMessage("Il ne servirait à rien dans l'état actuel de retirer le fromage"); + return; + } + + bool isexceptionnal = false; + double exceptionnalchance = ((m_From.Skills[SkillName.Cooking].Value) / 2 + (m_Cheese.CookingValue / 2) + (m_From.Skills[SkillName.TasteID].Value / 5)) / 150; + + if (exceptionnalchance > Utility.RandomDouble()) + isexceptionnal = true; + + + for (int i = 0; i < m_Cheese.CheeseAmount; i++) + { + + CookableCheese wheel = new CookableCheese(); + wheel.Cook = m_From; + //Type de lait + wheel.CheeseMilk = m_Cheese.Content; + + double delay = (now - m_Cheese.TimeStart).TotalDays; + + if (isexceptionnal) + wheel.Quality = CheeseQuality.Exceptionnal; + + //Poison au besoin + if(delay > 17) + { + if (delay + 11 > 17) + wheel.Poison = Poison.Deadly; + else if (delay + 8 > 17) + wheel.Poison = Poison.Greater; + else if (delay + 5 > 17) + wheel.Poison = Poison.Regular; + else if (delay + 2 > 17) + wheel.Poison = Poison.Lesser; + wheel.Poisoner = m_From; + } + + //Gout du fromage + if (delay <= 5) + wheel.Taste = CheeseTaste.Faible; + else if (delay <= 8) + wheel.Taste = CheeseTaste.Leger; + else if (delay <= 11) + wheel.Taste = CheeseTaste.Modere; + else if (delay <= 14) + wheel.Taste = CheeseTaste.Prononce; + else + wheel.Taste = CheeseTaste.Fort; + + //Pâte du fromage + if (m_Cheese.IsChildOf(m_From.Backpack)) + wheel.Paste = CheesePaste.Molle; + else if (m_Cheese.IsChildOf(typeof(BaseContainer))) + wheel.Paste = CheesePaste.Normale; + else + wheel.Paste = CheesePaste.Dure; + + m_From.AddToBackpack(wheel); + + } + m_From.SendMessage("Vous extrayez le fromage du moule et le coupez lentement..."); + + m_Cheese.Content = Milk.None; + m_Cheese.Quantity = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/MilkAndCheese/CookableCheese.cs b/Scripts/Vivre/Engines/MilkAndCheese/CookableCheese.cs new file mode 100644 index 0000000..3991c8c --- /dev/null +++ b/Scripts/Vivre/Engines/MilkAndCheese/CookableCheese.cs @@ -0,0 +1,289 @@ +using System; +using Server.Network; +using Server.Mobiles; + + +namespace Server.Items +{ + public enum CheesePaste + { + Molle, + Normale, + Dure + } + + public enum CheeseTaste + { + Faible, + Leger, + Modere, + Prononce, + Fort + } + + public enum CheeseQuality + { + Regular, + Exceptionnal + } + + public class CookableCheese : Food + { + private Milk m_Milk; + private CheesePaste m_Paste; + private CheeseTaste m_Taste; + private CheeseQuality m_Quality; + private Mobile m_Cook; + + + [CommandProperty(AccessLevel.GameMaster)] + public Milk CheeseMilk + { + get { return m_Milk; } + set { m_Milk = value; CheeseProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CheesePaste Paste + { + get { return m_Paste; } + set { m_Paste = value; CheeseProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CheeseTaste Taste + { + get { return m_Taste; } + set { m_Taste = value; CheeseProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public CheeseQuality Quality + { + get { return m_Quality; } + set { m_Quality = value; CheeseProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Cook + { + get { return m_Cook; } + set { m_Cook = value; CheeseProperties(); } + } + + [Constructable] + public CookableCheese() + : base(1, 0x97c) + { + Weight = 1.0; + Stackable = false; + FillFactor = 2; + Name = "Fromage"; + } + + public string BaseCheeseName() + { + string basename = "Fromage"; + if (Poisoner != null) + return basename; + if (Paste == CheesePaste.Molle && Taste == CheeseTaste.Fort) + { + basename = "Purin"; + } + else if (Paste == CheesePaste.Molle && Taste == CheeseTaste.Leger) + { + basename = "Caprice"; + } + else if (Paste == CheesePaste.Dure && Taste == CheeseTaste.Modere) + { + basename = "Dormoir"; + } + else if (Paste == CheesePaste.Dure && Taste == CheeseTaste.Prononce) + { + basename = "Accroc"; + } + else if (Paste == CheesePaste.Normale && Taste == CheeseTaste.Faible) + { + basename = "Lait dur"; + } + else if (Paste == CheesePaste.Normale && Taste == CheeseTaste.Fort) + { + basename = "Crottin"; + } + return basename; + } + + public void CheeseProperties() + { + string nameaddon = ""; + + switch (CheeseMilk) + { + case (Milk.Cow): nameaddon += " de vache"; break; + case (Milk.Goat): nameaddon += " de chèvre"; break; + case (Milk.Sheep): nameaddon += " de brebis"; break; + } + + if (Poisoner != null) + { + Name = BaseCheeseName() + nameaddon; + return; + } + + if (Quality == CheeseQuality.Exceptionnal) + { + nameaddon += m_Cook != null ? (m_Cook.Female ? " de la mère " : " du père ") + m_Cook.Name : ""; + FillFactor = 4; + } + + Name = BaseCheeseName() + nameaddon; + } + + public override bool Eat(Mobile from) + { + + if (FillHunger(from, FillFactor)) + { + string tastemsg; + int RatChances = (int)Taste; + if (Poisoner == null) + { + if (RatChances > Utility.Random(8)) + { + BaseCreature rat = new Rat(); + rat.MoveToWorld(from.Location, from.Map); + switch (Utility.Random(4)) + { + case 2: + { + rat.FocusMob = from; + rat.AI = AIType.AI_Predator; + rat.Say("*Semble jaloux de votre fromage*"); + break; + } + default: + { + rat.Controlled = true; + rat.ControlMaster = from; + rat.ControlOrder = OrderType.Come; + rat.Say("*Couinant amoureusement près de vous*"); + break; + } + } + } + + string paste = "Vous mangez"; + string taste = ""; + + switch (Paste) + { + case CheesePaste.Molle: paste = "Vous laissez fondre"; break; + case CheesePaste.Normale: paste = "Vous dégustez"; break; + case CheesePaste.Dure: paste = "Vous grignottez"; break; + } + + switch (Taste) + { + case CheeseTaste.Faible: taste = "au goût subtil"; break; + case CheeseTaste.Leger: taste = "au goût délicat"; break; + case CheeseTaste.Modere: taste = "au goût agréable"; break; + case CheeseTaste.Prononce: taste = "au goût bien présent"; break; + case CheeseTaste.Fort: taste = "au goût persistant"; break; + } + + tastemsg = String.Format("{0} ce fromage {1}", paste, taste); + if (Quality == CheeseQuality.Exceptionnal) + from.Say("*Semble subjugué{0} par le goût de ce fromage*", from.Female ? "e" : ""); + } + else + { + tastemsg = "Le goût de la moisissure vous dégoûte au plus haut point"; + from.PlaySound(from.Female ? 813 : 1087); + + Point3D p = new Point3D(from.Location); + switch (from.Direction) + { + case Direction.North: + p.Y--; break; + case Direction.South: + p.Y++; break; + case Direction.East: + p.X++; break; + case Direction.West: + p.X--; break; + case Direction.Right: + p.X++; p.Y--; break; + case Direction.Down: + p.X++; p.Y++; break; + case Direction.Left: + p.X--; p.Y++; break; + case Direction.Up: + p.X--; p.Y--; break; + default: + break; + } + p.Z = from.Map.GetAverageZ(p.X, p.Y); + + bool canFit = Server.Spells.SpellHelper.AdjustField(ref p, from.Map, 12, false); + + if (canFit) + { + Puke puke = new Puke(); + puke.Map = from.Map; + puke.Location = p; + } + from.Say("*Recrache le fromage, l'air malade*"); + } + + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, tastemsg, from.NetState); + + + // Play a random "eat" sound + from.PlaySound(Utility.Random(0x3A, 3)); + + if (from.Body.IsHuman && !from.Mounted) + from.Animate(34, 5, 1, true, false, 0); + + if (Poison != null) + from.ApplyPoison(Poisoner, Poison); + + Consume(); + + return true; + } + + return false; + } + + public CookableCheese(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.WriteEncodedInt((int)m_Milk); + writer.WriteEncodedInt((int)m_Paste); + writer.WriteEncodedInt((int)m_Taste); + writer.WriteEncodedInt((int)m_Quality); + writer.Write((Mobile)m_Cook); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Milk = (Milk)reader.ReadEncodedInt(); + m_Paste = (CheesePaste)reader.ReadEncodedInt(); + m_Taste = (CheeseTaste)reader.ReadEncodedInt(); + m_Quality = (CheeseQuality)reader.ReadEncodedInt(); + m_Cook = reader.ReadMobile(); + } + } +} diff --git a/Scripts/Vivre/Engines/MilkAndCheese/MilkBucket.cs b/Scripts/Vivre/Engines/MilkAndCheese/MilkBucket.cs new file mode 100644 index 0000000..45b534b --- /dev/null +++ b/Scripts/Vivre/Engines/MilkAndCheese/MilkBucket.cs @@ -0,0 +1,368 @@ +/******************************************************************************************** +**Lait et fromage Crystal/Sna/Cooldev 2003 (laitage.cs,laitage_items.cs et fromage.cs) ** +**le script comprend 1 seau pour traire vache , brebis , chevre . 3 bouteilles de laits ** +**et 3 moule plein de fromages (je prefere les bouteilles que les pichets c'est stackable) ** +** http://invisionfree.com/forums/Hyel_dev/index.php ** +********************************************************************************************/ + +using System; +using Server.Mobiles; +using Server.Targeting; +using Server.Network; +using Server.Engines.Craft; + +namespace Server.Items +{ + public enum Milk + { + None, + Goat, + Sheep, + Cow + } + public enum BucketLiquid + { + None, + SugarWater + } + + + public class ResourceBucket : Item + { + private Milk m_MilkType; + private BucketLiquid m_ResourceType; + private int m_MaxQuantity = 40; + private int m_Quantity; + + + [CommandProperty(AccessLevel.GameMaster)] + public Milk MilkType + { + get { return m_MilkType; } + set + { + if (ResourceType != BucketLiquid.None) + ResourceType = BucketLiquid.None; + m_MilkType = value; ComputeProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public BucketLiquid ResourceType + { + get { return m_ResourceType; } + set + { + if (MilkType != Milk.None) + MilkType = Milk.None; + m_ResourceType = value; ComputeProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxQuantity + { + get { return m_MaxQuantity; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Quantity + { + get { return m_Quantity; } + set { m_Quantity = Math.Min(value, MaxQuantity); InvalidateProperties(); } + } + + + [Constructable] + public ResourceBucket() + : base(0x0FFA) + { + Weight = 10.0; + Name = "Seau"; + Hue = 1001; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add("Contient {0} litre{1} de liquide", Quantity, (Quantity > 1) ? "s" : ""); + } + + public string BucketNameAffix() + { + string affix = ""; + + if (m_ResourceType == BucketLiquid.SugarWater) + affix = " d'eau sucr�e"; + + switch (m_MilkType) + { + case (Milk.Cow): + affix = " de lait de vache"; break; + case (Milk.Goat): + affix = " de lait de ch�vre"; break; + case (Milk.Sheep): + affix = " de lait de brebis"; break; + } + + return affix; + } + + public void ComputeProperties() + { + string prefix = "Seau"; + + Name = prefix + BucketNameAffix(); + } + + public void EmptyBucket() + { + MilkType = Milk.None; + ResourceType = BucketLiquid.None; + Quantity = 0; + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(501816); + return; + } + + if (this.ResourceType == BucketLiquid.SugarWater) + { + if (!this.Find(from, CraftItem.m_HeatSources)) + { + from.SendMessage("Vous devriez faire crystaliser le tout"); + return; + } + if(from.CheckSkill(SkillName.Cooking, 20,80)) + { + from.SendMessage("La chaleur fait figer le tout, donnant une allure diff�rente � cette eau"); + Sugar item = new Sugar(); + item.Amount = this.Quantity; + from.AddToBackpack(item); + this.EmptyBucket(); + } + else + { + from.SendMessage("Vous ne parvenez pas � en faire une mixture ad�quate.."); + this.Quantity--; + if (Quantity == 0) + this.EmptyBucket(); + } + return; + } + + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(ExtractTarget)); + + + } + public ResourceBucket(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // Version + writer.WriteEncodedInt((int)m_MilkType); + writer.WriteEncodedInt((int)m_ResourceType); + writer.Write((int)m_MaxQuantity); + writer.Write((int)m_Quantity); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_MilkType = (Milk)reader.ReadEncodedInt(); + m_ResourceType = (BucketLiquid)reader.ReadEncodedInt(); + m_MaxQuantity = reader.ReadInt(); + m_Quantity = reader.ReadInt(); + } + + public bool Find(int itemID, int[] itemIDs) + { + bool contains = false; + + for (int i = 0; !contains && i < itemIDs.Length; i += 2) + contains = (itemID >= itemIDs[i] && itemID <= itemIDs[i + 1]); + + return contains; + } + + public bool Find(Mobile from, int[] itemIDs) + { + Map map = from.Map; + + if (map == null) + return false; + + IPooledEnumerable eable = map.GetItemsInRange(from.Location, 2); + + foreach (Item item in eable) + { + if ((item.Z + 16) > from.Z && (from.Z + 16) > item.Z && Find(item.ItemID, itemIDs)) + { + eable.Free(); + return true; + } + } + + eable.Free(); + + for (int x = -2; x <= 2; ++x) + { + for (int y = -2; y <= 2; ++y) + { + int vx = from.X + x; + int vy = from.Y + y; + + StaticTile[] tiles = map.Tiles.GetStaticTiles(vx, vy, true); + + for (int i = 0; i < tiles.Length; ++i) + { + int z = tiles[i].Z; + int id = tiles[i].ID; + + if ((z + 16) > from.Z && (from.Z + 16) > z && Find(id, itemIDs)) + return true; + } + } + } + + return false; + } + + public void ExtractTarget(Mobile from, object obj) + { + if (this.MilkType != Milk.None) + { + if (obj is Mobile) + { + Mobile targ = (Mobile)obj; + + if (Quantity >= MaxQuantity) + { + from.SendMessage("Ce seau est plein"); + return; + } + + if (targ.Stam < 10) + { + targ.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous ne pourrez rien enlever � cette pauvre b�te!", from.NetState); + return; + } + + if (targ is Cow && (this.MilkType == Milk.None || this.MilkType == Milk.Cow)) + { + MilkType = Milk.Cow; + Quantity++; + targ.Stam -= 10; + from.SendMessage("Vous obtenez" + BucketNameAffix()); + return; + } + + if (targ is Brebis && (this.MilkType == Milk.None || this.MilkType == Milk.Sheep)) + { + MilkType = Milk.Sheep; + Quantity++; + targ.Stam -= 10; + from.SendMessage("Vous obtenez" + BucketNameAffix()); + return; + } + + if (targ is Chevre && (this.MilkType == Milk.None || this.MilkType == Milk.Goat)) + { + MilkType = Milk.Goat; + Quantity++; + targ.Stam -= 10; + from.SendMessage("Vous obtenez" + BucketNameAffix()); + return; + } + + if (targ == from) + { + from.SendMessage("Versez le contenu dans un r�cipient plus propice pour boire!"); + return; + } + from.SendMessage("Cela ne servira � rien sur cette cr�ature"); + return; + } + if (obj is BaseBeverage) + { + BaseBeverage targ = (BaseBeverage)obj; + + int shared = Math.Min(this.Quantity, (targ.MaxQuantity - targ.Quantity)); + + from.SendMessage("Vous versez{0} dans le contenant", BucketNameAffix()); + targ.Quantity += shared; + this.Quantity -= shared; + + switch (MilkType) + { + case Milk.Cow: targ.Content = BeverageType.Milk; break; + case Milk.Goat: targ.Content = BeverageType.LaitChevre; break; + case Milk.Sheep: targ.Content = BeverageType.LaitBrebis; break; + } + } + + if (obj is CheeseForm) + { + CheeseForm targ = (CheeseForm)obj; + + if (ResourceType != BucketLiquid.None) + { + from.SendMessage("Vous ne pouvez verser cela ici"); + return; + } + + if (targ.Quantity >= targ.MaxQuantity) + { + from.SendMessage("Ce fromage fermente d�j�"); + return; + } + + if (targ.Content != Milk.None && (MilkType != targ.Content)) + { + from.SendMessage("Vous ne pouvez m�langer des laits"); + return; + } + + int shared = Math.Min(Quantity, (targ.MaxQuantity - targ.Quantity)); + + targ.Content = this.MilkType; + + from.SendMessage("Vous versez{0} dans le moule", BucketNameAffix()); + targ.Quantity += shared; + this.Quantity -= shared; + if (targ.Quantity >= targ.MaxQuantity) + { + targ.CookingValue = from.Skills[SkillName.Cooking].Value; + targ.TimeStart = DateTime.Now; + } + + } + + } + + else + { + from.SendMessage("Ce seau est vide"); + return; + } + + if (Quantity <= 0) + EmptyBucket(); + } + } +} + + diff --git a/Scripts/Vivre/Engines/MilkAndCheese/MilkItems.cs b/Scripts/Vivre/Engines/MilkAndCheese/MilkItems.cs new file mode 100644 index 0000000..6cc5448 --- /dev/null +++ b/Scripts/Vivre/Engines/MilkAndCheese/MilkItems.cs @@ -0,0 +1,645 @@ +using System; + +namespace Server.Items +{ + public abstract class MilkBottle : Item + { + private Mobile m_Poisoner; + private Poison m_Poison; + private int m_FillFactor; + + public virtual Item EmptyItem{ get { return null; } } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Poisoner + { + get { return m_Poisoner; } + set { m_Poisoner = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get { return m_Poison; } + set { m_Poison = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int FillFactor + { + get { return m_FillFactor; } + set { m_FillFactor = value; } + } + + public MilkBottle( int itemID ) : base( itemID ) + { + this.FillFactor = 4; + } + + public MilkBottle( Serial serial ) : base( serial ) + { + } + + public void Boire( Mobile from ) + { + if ( soif( from, m_FillFactor ) ) + { + // Play a random drinking sound + from.PlaySound( Utility.Random( 0x30, 2 ) ); + + if ( from.Body.IsHuman && !from.Mounted ) + from.Animate( 34, 5, 1, true, false, 0 ); + + if ( m_Poison != null ) + from.ApplyPoison( m_Poisoner, m_Poison ); + + this.Consume(); + + Item item = EmptyItem; + + if ( item != null ) + from.AddToBackpack( item ); + } + } + + static public bool soif( Mobile from, int fillFactor ) + { + if ( from.Thirst >= 20 ) + { + from.SendMessage( "ah pu soif!" ); + return false; + } + + int iThirst = from.Thirst + fillFactor; + if ( iThirst >= 20 ) + { + from.Thirst = 20; + from.SendMessage( "c'est trop bon , mais la vous pouvez plus!" ); + } + else + { + from.Thirst = iThirst; + + if ( iThirst < 5 ) + from.SendMessage( "Vous buvez cela , mais avez encore tr�s tr�s soif." ); + else if ( iThirst < 10 ) + from.SendMessage( "Vous buvez et vous sentez un peu mieux." ); + else if ( iThirst < 15 ) + from.SendMessage( "Apres avoir vu , vous vous senter bcp mieux." ); + else + from.SendMessage( "Apres cette boisson , vous etes combl�." ); + } + + return true; + } + + + + public override void OnDoubleClick( Mobile from ) + { + if ( !Movable ) + return; + + if ( from.InRange( this.GetWorldLocation(), 1 ) ) + Boire( from ); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write( m_Poisoner ); + + Poison.Serialize( m_Poison, writer ); + writer.Write( m_FillFactor ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_Poisoner = reader.ReadMobile(); + + goto case 0; + } + case 0: + { + m_Poison = Poison.Deserialize( reader ); + m_FillFactor = reader.ReadInt(); + break; + } + } + } + } + public class BottleCowMilk : MilkBottle + { + public override Item EmptyItem{ get { return new Bottle(); } } + + [Constructable] + public BottleCowMilk() : base( 0x0f09 ) + { + this.Weight = 0.2; + this.FillFactor = 4; + this.Name ="Bouteille de lait de vache"; + } + + public BottleCowMilk( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + public class BottleGoatMilk : MilkBottle + { + public override Item EmptyItem{ get { return new Bottle(); } } + + [Constructable] + public BottleGoatMilk() : base( 0x0f09 ) + { + this.Weight = 0.2; + this.FillFactor = 4; + this.Name ="Bouteille de lait de chevre"; + } + + public BottleGoatMilk( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + public class BottleSheepMilk : MilkBottle + { + public override Item EmptyItem{ get { return new Bottle(); } } + + [Constructable] + public BottleSheepMilk() : base( 0x0f09 ) + { + this.Weight = 0.2; + this.FillFactor = 4; + this.Name ="Bouteille de lait de brebis"; + } + + public BottleSheepMilk( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + +/* ***************************** Cheese ******************************** */ + + + + // Cow Cheese + + public class CowCheese : Food, ICarvable + { + public void Carve( Mobile from, Item item ) + { + if ( !Movable ) + return; + + if ( this.Amount > 1 ) // workaround because I can't call scissorhelper twice? + { + from.SendMessage( "Vous ne pouvez decouper que une meule a la fois." ); + return; + } + + base.ScissorHelper( from, new CowCheeseWedge(), 1 ); + + from.AddToBackpack( new CowCheeseWedgeSmall() ); + + from.SendMessage( "Vous decouper un morceau de la meule." ); + } + + [Constructable] + public CowCheese() : this( 1 ) + { + } + + [Constructable] + public CowCheese( int amount ) : base( amount, 0x97E ) + { + this.Weight = 0.4; + this.FillFactor = 12; + this.Name = "Gouda"; + this.Hue = 0x481; + } + + public CowCheese( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CowCheeseWedge : Food, ICarvable + { + public void Carve( Mobile from, Item item ) + { + if ( !Movable ) + return; + + base.ScissorHelper( from, new CowCheeseWedgeSmall(), 3 ); + from.SendMessage( "Vous coupez la meule en 3 morceaux" ); + } + + [Constructable] + public CowCheeseWedge() : this( 1 ) + { + } + + [Constructable] + public CowCheeseWedge( int amount ) : base( amount, 0x97D ) + { + this.Weight = 0.3; + this.FillFactor = 9; + this.Name = "Gruyere"; + this.Hue = 0x481; + } + + public CowCheeseWedge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class CowCheeseWedgeSmall : Food + { + [Constructable] + public CowCheeseWedgeSmall() : this( 1 ) + { + } + + [Constructable] + public CowCheeseWedgeSmall( int amount ) : base( amount, 0x97C ) + { + this.Weight = 0.1; + this.FillFactor = 3; + this.Name = "Gruyere"; + this.Hue = 0x481; + } + + public CowCheeseWedgeSmall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + + // Sheep Cheese + + public class SheepCheese : Food, ICarvable + { + public void Carve( Mobile from, Item item ) + { + if ( !Movable ) + return; + + if ( this.Amount > 1 ) // workaround because I can't call scissorhelper twice? + { + from.SendMessage( "Vous ne pouvez decouper que 1 meule a la fois" ); + return; + } + + base.ScissorHelper( from, new SheepCheeseWedge(), 1 ); + + from.AddToBackpack( new SheepCheeseWedgeSmall() ); + + from.SendMessage( "Vous decouper un morceau de la meule." ); + } + + [Constructable] + public SheepCheese() : this( 1 ) + { + } + + [Constructable] + public SheepCheese( int amount ) : base( amount, 0x97E ) + { + this.Weight = 0.4; + this.FillFactor = 12; + this.Name = "Le brebis d'Igor"; + this.Hue = 0x481; + } + + public SheepCheese( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SheepCheeseWedge : Food, ICarvable + { + public void Carve( Mobile from, Item item ) + { + if ( !Movable ) + return; + + base.ScissorHelper( from, new SheepCheeseWedgeSmall(), 3 ); + from.SendMessage( "Vous coupez la meule en 3 morceaux" ); + } + + [Constructable] + public SheepCheeseWedge() : this( 1 ) + { + } + + [Constructable] + public SheepCheeseWedge( int amount ) : base( amount, 0x97D ) + { + this.Weight = 0.3; + this.FillFactor = 9; + this.Name = "Haut paturage"; + this.Hue = 0x481; + } + + public SheepCheeseWedge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SheepCheeseWedgeSmall : Food + { + [Constructable] + public SheepCheeseWedgeSmall() : this( 1 ) + { + } + + [Constructable] + public SheepCheeseWedgeSmall( int amount ) : base( amount, 0x97C ) + { + this.Weight = 0.1; + this.FillFactor = 3; + this.Name = "Fromage de brebis"; + this.Hue = 0x481; + } + + public SheepCheeseWedgeSmall( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + + + // Goat Cheese + + public class GoatCheese : Food, ICarvable + { + public void Carve( Mobile from, Item item ) + { + if ( !Movable ) + return; + + if ( this.Amount > 1 ) // workaround because I can't call scissorhelper twice? + { + from.SendMessage( "Vous ne pouvez decouper que 1 meule a la fois" ); + return; + } + + base.ScissorHelper( from, new GoatCheeseWedge(), 1 ); + + from.AddToBackpack( new GoatCheeseWedgeSmall() ); + + from.SendMessage( "Vous decouper un morceau de la meule." ); + } + + [Constructable] + public GoatCheese() : this( 1 ) + { + } + + [Constructable] + public GoatCheese( int amount ) : base( amount, 0x97E ) + { + this.Weight = 0.4; + this.FillFactor = 12; + this.Name = "LE chevre de Yew"; + this.Hue = 0x481; + } + + public GoatCheese( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoatCheeseWedge : Food, ICarvable + { + public void Carve( Mobile from, Item item ) + { + if ( !Movable ) + return; + + base.ScissorHelper(from, new GoatCheeseWedgeSmall(), 3); + from.SendMessage( "Vous coupez la meule en 3 morceaux" ); + } + + [Constructable] + public GoatCheeseWedge() : this( 1 ) + { + } + + [Constructable] + public GoatCheeseWedge( int amount ) : base( amount, 0x97D ) + { + this.Weight = 0.3; + this.FillFactor = 9; + this.Name = "Chevrotin de Cove"; + this.Hue = 0x481; + } + + public GoatCheeseWedge( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoatCheeseWedgeSmall : Food + { + [Constructable] + public GoatCheeseWedgeSmall() : this( 1 ) + { + } + + [Constructable] + public GoatCheeseWedgeSmall( int amount ) : base( amount, 0x97C ) + { + this.Weight = 0.1; + this.FillFactor = 3; + this.Name = "fromage de chevre"; + this.Hue = 0x481; + } + + public GoatCheeseWedgeSmall(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + +} diff --git a/Scripts/Vivre/Engines/MilkAndCheese/MilkMagicItems.cs b/Scripts/Vivre/Engines/MilkAndCheese/MilkMagicItems.cs new file mode 100644 index 0000000..8bb7adf --- /dev/null +++ b/Scripts/Vivre/Engines/MilkAndCheese/MilkMagicItems.cs @@ -0,0 +1,163 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseMagicCheese : Item + { + public virtual int Bonus{ get{ return 0; } } + public virtual StatType Type{ get{ return StatType.Str; } } + + public BaseMagicCheese( int hue ) : base( 0x97E ) + { + Weight = 1.0; + // Hue = hue; they're all alike - yellowish + + if ( Utility.RandomBool() ) + Hue = Utility.RandomList(0x135, 0xcd, 0x38, 0x3b, 0x42, 0x4f, 0x11e, 0x60, 0x317, 0x10, 0x136, 0x1f9, 0x1a, 0xeb, 0x86, 0x2e, 0x0497, 0x0481); + else + Hue = 3 + (Utility.Random( 20 ) * 5); + + + } + + public BaseMagicCheese( Serial serial ) : base( serial ) + { + } + + public virtual bool Apply( Mobile from ) + { + bool applied = Spells.SpellHelper.AddStatOffset( from, Type, Bonus, TimeSpan.FromMinutes( 5.0 ) ); + + if ( !applied ) + from.SendLocalizedMessage( 502173 ); // You are already under a similar effect. + + return applied; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // That must be in your pack for you to use it. + } + else if ( Apply( from ) ) + { + from.FixedEffect( 0x375A, 10, 15 ); + from.PlaySound( 0x1E7 ); + Delete(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class GoatCheeseMagic : BaseMagicCheese + { + public override int Bonus{ get{ return 5; } } + public override StatType Type{ get{ return StatType.Str; } } + + //public override int LabelNumber{ get{ return 1041073; } } // prized fish + + [Constructable] + public GoatCheeseMagic() : base( 151 ) + { + this.Name = "Chavroux"; + } + + public GoatCheeseMagic(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + public class CowCheeseMagic : BaseMagicCheese + { + public override int Bonus{ get{ return 5; } } + public override StatType Type{ get{ return StatType.Int; } } + + //public override int LabelNumber{ get{ return 1041073; } } // prized fish + + [Constructable] + public CowCheeseMagic() : base( 151 ) + { + this.Name = "Maroille"; + } + + public CowCheeseMagic(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } + + public class SheepCheeseMagic : BaseMagicCheese + { + public override int Bonus{ get{ return 5; } } + public override StatType Type{ get{ return StatType.Dex; } } + + //public override int LabelNumber{ get{ return 1041073; } } // prized fish + + [Constructable] + public SheepCheeseMagic() : base( 151 ) + { + this.Name = "brebis heppinois"; + } + + public SheepCheeseMagic(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/AI/PomiAI.cs b/Scripts/Vivre/Engines/POMI/AI/PomiAI.cs new file mode 100644 index 0000000..05514cb --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/AI/PomiAI.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Misc; +using Server.Regions; +using Server.SkillHandlers; +using Server.IPOMI; +using Server.ContextMenus; + +namespace Server.Mobiles +{ + public class PomiAI: BaseAI + { + public PomiAI(BaseCreature m) : base (m) + { + } + + private bool isEnnemi(PlayerMobile from, TownStone town) + { + PomiCloak pomicloak = from.FindItemOnLayer(Layer.Cloak) as PomiCloak; + if(pomicloak != null && pomicloak.Name == "Ambassadeur") + return false; + + foreach (TownStone ville in town.Guerre) + if (ville.isCitoyen(from)) + return true; + + return false; + } + + public override bool DoActionWander() + { + // Scriptiz : les gardes ne s'attaquent pas entre eux ! + if (m_Mobile.Combatant != null && m_Mobile.Combatant is PomiGuard) + { + m_Mobile.Combatant.Criminal = false; + m_Mobile.Criminal = false; + m_Mobile.Combatant.Combatant = null; + m_Mobile.Combatant = null; + } + + TownStone m_Town = ((PomiGuard)(m_Mobile)).Town; + m_Mobile.DebugSay("I have no combatant"); + + m_Mobile.Criminal = false; + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true)) + { + m_Mobile.DebugSay("I see {0}", m_Mobile.FocusMob.Name); + if (m_Town.HLL.Contains((PlayerMobile)m_Mobile.FocusMob) || + isEnnemi((PlayerMobile)m_Mobile.FocusMob, m_Town) || + (m_Mobile.FocusMob.Criminal && + !m_Town.isMaire((PlayerMobile)m_Mobile.FocusMob) && + !m_Town.isConseiller((PlayerMobile)m_Mobile.FocusMob) && + !m_Town.isAmbassadeur((PlayerMobile)m_Mobile.FocusMob) && + !m_Town.isCapitaine((PlayerMobile)m_Mobile.FocusMob) && + !m_Town.Gardes.Contains((PlayerMobile)m_Mobile.FocusMob))) + { + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionWander(); + } + } + else + { + base.DoActionWander(); + } + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + Action = ActionType.Wander; + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else + { + if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + m_Mobile.DebugSay("I cannot find {0} him", combatant.Name); + Action = ActionType.Wander; + return true; + } + else + { + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + } + + return true; + } + + public override bool DoActionBackoff() + { + if (m_Mobile.IsHurt() || m_Mobile.Combatant != null) + { + Action = ActionType.Combat; + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) + { + if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) + { + m_Mobile.DebugSay("Well, here I am safe"); + Action = ActionType.Wander; + } + } + else + { + m_Mobile.DebugSay("I have lost my focus, lets relax"); + Action = ActionType.Wander; + } + } + + return true; + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Bugs.txt b/Scripts/Vivre/Engines/POMI/Bugs.txt new file mode 100644 index 0000000..906674f --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Bugs.txt @@ -0,0 +1,15 @@ +- titre des pages +- enlever le gump quand on nome => fixed +- descendre la liste des citoyens => fixed +- doublons de titres => fixed => tous les titres sont reinitialis�s (conseiller, ambassadeur, capitaine, gardes pj et pnj) +- gardes n'attaquent pas le conseil => fixed +- nommer un garde et pas ajouter => fixed +- apres un demenagement, retirer sa candidature aux elections. => fixed (impossible de demenager pour les candidats) +- gerer une distance max entre le spawner de garde et la pierre de ville => fixed +- idem pour les deplacements + +// Scriptiz +- Nomer >>> Nommer +- Quand un bourgmestre nomme quelqu'un qui a d�j� un titre, la personne cumule les deux titres +- Pour mettre des Hors la loi on dirait que le syst�me bug un peu ! A regarder +- Quand la liste des citoyens est fort longue, elle sort sur la droite du gump quand on swith de page => fixed \ No newline at end of file diff --git a/Scripts/Vivre/Engines/POMI/Guards/PomiGuard.cs b/Scripts/Vivre/Engines/POMI/Guards/PomiGuard.cs new file mode 100644 index 0000000..f16b2ac --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Guards/PomiGuard.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections; +using Server.Misc; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; +using System.Collections.Generic; +using Server.ContextMenus; + +namespace Server.IPOMI +{ + public class PomiGuard : BaseCreature + { + private TownStone m_Town; + private GuardSpawner m_spawn; + + public PomiGuard(TownStone town, GuardSpawner spawn) + : base(AIType.AI_Pomi, FightMode.Closest, 15, 1, 0.2, 1) + { + m_spawn = spawn; + Location = m_spawn.Location; + m_Town = town; + Map = spawn.Map; + InitStats(200, 200, 200); + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + Body = 0x190; + Name = NameList.RandomName("male"); + Title = "Garde de " + m_Town.Nom; + + PlateChest chest = new PlateChest(); + chest.Hue = 0; + chest.Movable = false; + AddItem(chest); + PlateArms arms = new PlateArms(); + arms.Hue = 0; + arms.Movable = false; + AddItem(arms); + PlateGloves gloves = new PlateGloves(); + gloves.Hue = 0; + gloves.Movable = false; + AddItem(gloves); + PlateGorget gorget = new PlateGorget(); + gorget.Hue = 0; + gorget.Movable = false; + AddItem(gorget); + PlateLegs legs = new PlateLegs(); + legs.Hue = 0; + legs.Movable = false; + AddItem(legs); + PlateHelm helm = new PlateHelm(); + helm.Hue = 0; + helm.Movable = false; + AddItem(helm); + Surcoat surcoat = new Surcoat(); + surcoat.Hue = m_Town.Hue; + surcoat.Movable = false; + AddItem(surcoat); + + + AddItem(new PomiCloak(m_Town, "Garde")); + + HairItemID = Utility.RandomList(0x203B, 0x203C, 0x203D, 0x2044, 0x2045, 0x2047, 0x2049, 0x204A); + HairHue = Utility.RandomHairHue(); + + if (Utility.RandomBool()) + { + FacialHairItemID = Utility.RandomList(0x203E, 0x203F, 0x2040, 0x2041, 0x204B, 0x204C, 0x204D); + FacialHairHue = HairHue; + } + + Halberd weapon = new Halberd(); + //weapon.Hue = m_Town.Hue; + weapon.Movable = false; + weapon.Crafter = this; + weapon.Quality = WeaponQuality.Exceptional; + VirtualArmor = 100; + + AddItem(weapon); + + Skills[SkillName.Anatomy].Base = 100.0; + Skills[SkillName.Tactics].Base = 110.0; + Skills[SkillName.Swords].Base = 160.0; + Skills[SkillName.MagicResist].Base = 110.0; + Skills[SkillName.DetectHidden].Base = 100.0; + } + + public override bool Unprovokable { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public override bool BardImmune { get { return true; } } + public PomiGuard(Serial serial) + : base(serial) + { + } + + public TownStone Town + { + get { return m_Town; } + } + + public override bool OnBeforeDeath() + { + if(m_spawn != null) + m_spawn.Start(); + + return true; + } + + public override void OnActionCombat() + { + } + + public override void OnCombatantChange() + { + base.OnCombatantChange(); + this.Say("Un Hors la Loi !!! Sortez de cette ville ou mourez!"); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from is PlayerMobile) return true; + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + PlayerMobile from = e.Mobile as PlayerMobile; + + if (from != null && !e.Handled && e.Mobile.InRange(this, 2)) + { + if (m_Town.isCapitaine(from) || m_Town.Gardes.Contains(from)) + { + e.Handled = true; + if (e.Speech.ToLower() == "suivez-moi") + { + this.Say("Je vous suis!"); + this.ControlMaster = from; + this.ControlOrder = OrderType.Guard; + this.Controlled = true; + } + else if (from != ControlMaster) + { + this.Say("Hein que dites vous?"); + } + } + } + base.OnSpeech(e); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + if (this.Controlled && from == this.ControlMaster && from.InRange(this, 14)) + { + list.Add(new InternalEntry(from, 6107, 14, this, this.AIObject, OrderType.Guard)); // Command: Guard + list.Add(new InternalEntry(from, 6108, 14, this, this.AIObject, OrderType.Follow)); // Command: Follow + + //list.Add( new InternalEntry( from, 6111, 14, m_Mobile, this, OrderType.Attack ) ); // Command: Kill + list.Add(new InternalEntry(from, 6112, 14, this, this.AIObject, OrderType.Stop)); // Command: Stop + list.Add(new InternalEntry(from, 6114, 14, this, this.AIObject, OrderType.Stay)); // Command: Stay + + list.Add(new InternalEntry(from, 6118, 14, this, this.AIObject, OrderType.Release)); // Release + } + //base.GetContextMenuEntries(from, list); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.Write((GuardSpawner)m_spawn); + writer.Write((TownStone)m_Town); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_spawn = (GuardSpawner)reader.ReadItem(); + m_Town = (TownStone)reader.ReadItem(); + } + + + private class InternalEntry : ContextMenuEntry + { + private Mobile m_From; + private BaseCreature m_Mobile; + private BaseAI m_AI; + private OrderType m_Order; + + public InternalEntry(Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order) + : base(number, range) + { + m_From = from; + m_Mobile = mobile; + m_AI = ai; + m_Order = order; + } + + public override void OnClick() + { + if (!m_Mobile.Deleted && m_Mobile.Controlled && m_From == m_Mobile.ControlMaster) + { + switch (m_Order) + { + case OrderType.Follow: + { + m_Mobile.Say("Je vous suis!"); + m_Mobile.ControlTarget = m_From; + m_Mobile.ControlOrder = m_Order; + break; + } + case OrderType.Release: + { + m_Mobile.Controlled = false; + m_Mobile.ControlOrder = OrderType.Release; + m_Mobile.Say("A vos ordres"); + m_Mobile.ControlMaster = null; + break; + } + default: + { + if (Math.Sqrt((m_Mobile.X - ((PomiGuard)(m_Mobile)).Town.X) * + (m_Mobile.X - ((PomiGuard)(m_Mobile)).Town.X) + + (m_Mobile.Y - ((PomiGuard)(m_Mobile)).Town.Y) * + (m_Mobile.Y - ((PomiGuard)(m_Mobile)).Town.Y)) < + ((PomiGuard)(m_Mobile)).Town.MaxDistance) + { + m_Mobile.Say("Tr�s bien!"); + m_Mobile.ControlOrder = m_Order; + } + else + { + m_Mobile.Location = m_Mobile.Home; + m_Mobile.Controlled = false; + m_Mobile.ControlOrder = OrderType.Release; + m_Mobile.ControlMaster = null; + } + break; + } + } + } + } + + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/POMI/Gumps/BoxGump.cs b/Scripts/Vivre/Engines/POMI/Gumps/BoxGump.cs new file mode 100644 index 0000000..9fea575 --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Gumps/BoxGump.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Gumps; +using Server; +using Server.Regions; +using Server.Accounting; +using Server.Mobiles; +using Server.HuePickers; + +namespace Server.IPOMI +{ + public class BoxGump : Gump + { + private TownBox m_Box; + private TownStone m_Town; + public int valeurdon; + + public BoxGump( PlayerMobile from,TownStone town, TownBox box ) : base( 20, 30 ) + { + m_Box = box; + m_Town = town; + bool isMaire = town.isMaire(from); + bool isConseiller = town.isConseiller(from) || isMaire; + bool isAmbassadeur = town.isAmbassadeur(from) || isConseiller; + bool isCapitaine = town.isCapitaine(from); + bool isGarde = town.isGarde(from) || isCapitaine; + bool isCitoyen = town.isCitoyen(from) || isAmbassadeur || isGarde; + bool isHLL = town.isHLL(from); + bool IsGM = isGM(from); + string payeurs = ""; + //int don = 0; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 430, 5054 ); + AddBackground( 10, 10, 400,410, 3000 ); + + AddLabel( 12, 12, 0,"Insp Gadget v1.0"); + AddLabel( 32, 32, 0,"Freeze v1.1"); + + AddImage( 130, 0, 100 ); + AddLabel( 130 + ((143 - (town.Nom.Length * 8)) / 2), 40, 0, m_Town.Nom ); + + AddLabel( 55, 103, 0, "Infos" ); // INFO + AddButton( 20, 103, 4005, 4007, 0, GumpButtonType.Page, 1 ); + if(isCitoyen || IsGM) + { + AddLabel( 170, 103, 0,"Taxes" ); // Feuille de paiement + AddButton( 135, 103, 4005, 4007, 0, GumpButtonType.Page, 2 ); + } + if(isConseiller || isCapitaine || IsGM ) + { + AddLabel( 295, 103, 0,"Gestion" ); // Gestion + AddButton( 260, 103, 4005, 4007, 0, GumpButtonType.Page, 3 ); + } + + AddLabel( 345, 390, 0,"Quitter" ); // Quitter + AddButton( 310, 390, 0xFB4, 0x0FB6, 0, GumpButtonType.Reply, 0 ); + + + AddLabel( 20, 390, 0,"Faire un don de : Po à la ville!"); + AddButton( 270, 390, 4005, 4007, 10, GumpButtonType.Reply, 0 ); + AddTextEntry(130, 390, 50, 20, 0x384, 5, "0"); + + + + + + + //INFOS + AddPage( 1 ); + AddLabel( 20, 130, 0, "Trésorie de la ville de " + m_Town.Nom); + AddLabel(20, 200, 0, "Les taxes sont de " + m_Box.Taxe + " pieces d'or par semaine"); + if(m_Box.Retard_1.Contains(from)) + AddLabel(20, 250, 0x7E, "Vous avez du retard dans le paiement des taxes"); + if(m_Box.Retard_2.Contains(from)) + AddLabel(20, 270, 0x25, "Si vous ne payez pas vous serez expulsé"); + + AddLabel(20, 300, 0, String.Format("Prochain paiement le : {0}",m_Box.EndDate)); + + //TAXES + AddPage( 2 ); + if(m_Box.Payeurs.Contains(from)) + AddLabel(20, 130, 0, "Vous avez payer vos taxes"); + else + { + AddLabel(45, 130, 0, String.Format("Verser {0} pieces d'or", m_Box.Taxe)); + AddButton( 20, 130, 2714, 2715, 20, GumpButtonType.Reply, 0); + } + + AddLabel(20, 170, 0, "Budget de la ville :"); + AddLabel(30, 190, 0, String.Format("Caisses de la ville {0}", m_Box.CaisseVille) ); + AddLabel(30, 210, 0, String.Format("Caisses de la Garde {0}", m_Box.CaisseGarde) ); + + //GESTION + AddPage( 3 ); + if(isConseiller || IsGM) + { + AddLabel(20, 130, 0, "Montant de la Taxe : pieces"); + AddTextEntry(160, 130, 50, 20, 0x384, 1, m_Box.Taxe.ToString()); + AddButton(270, 130, 2714, 2715, 30, GumpButtonType.Reply, 0); + } + else + AddLabel(20, 130, 0, String.Format("Montant de la Taxe : {0}",m_Box.Taxe)); + if(isMaire || IsGM) + { + AddLabel(20, 150, 0, "Retirer Po de la Caisse Ville"); + AddTextEntry(70, 150, 50, 20, 0x384, 2, m_Box.CaisseVille.ToString()); + AddButton(270, 150, 2714, 2715, 31, GumpButtonType.Reply, 0); + } + if(isCapitaine || isMaire || IsGM) + { + AddLabel(20, 170, 0, "Retirer Po de la caisse Garde"); + AddTextEntry(70, 170, 50, 20, 0x384, 3, m_Box.CaisseGarde.ToString()); + AddButton(270, 170, 2714, 2715, 32, GumpButtonType.Reply, 0); + } + + if( isMaire || IsGM) + { + AddLabel(20, 190, 0, "Basculer Po vers caisses : Ville Garde"); + AddTextEntry(73, 190, 50, 20, 0x384, 4,"0" ); + AddButton(270, 190, 2714, 2715, 34, GumpButtonType.Reply, 0); + AddButton(350, 190, 2714, 2715, 35, GumpButtonType.Reply, 0); + } + + if (isConseiller || IsGM) + { + AddLabel(20, 220, 0, "Creer un contrat Vendeur pour 2000 Po"); + AddButton(270, 220, 2714, 2715, 33, GumpButtonType.Reply, 0); + } + AddLabel(20, 240, 0, "Liste des payeurs :"); + foreach(PlayerMobile mobile in m_Box.Payeurs) + payeurs = payeurs + mobile.Name + ", "; + AddHtml(20, 260, 380, 120, payeurs, true, true); + + } + + public bool isGM (PlayerMobile from) + { + return from.AccessLevel >= AccessLevel.GameMaster; + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile from = sender.Mobile as PlayerMobile; + + switch ( info.ButtonID ) + { + case 10 : //Don a la ville + { + try + { + valeurdon = Int32.Parse(info.GetTextEntry(5).Text); + } + catch + { + from.SendMessage("Entrer une valeur numerique!"); + } + m_Box.Donnation(from,valeurdon); + break; + } + + + + case 20 : //paiement de la taxe + { + m_Box.Paiement(from,true); + break; + } + case 30 : //montant de la taxe + { + try + { + m_Box.Taxe = Int32.Parse(info.GetTextEntry(1).Text); + } + catch + { + from.SendMessage("Entrer une valeur numerique!"); + } + break; + } + + + case 31 : // Retirer de la caisse ville + { + try + { + if(Int32.Parse(info.GetTextEntry(2).Text) <= m_Box.CaisseVille) + { + from.Backpack.DropItem(new BankCheck(Int32.Parse(info.GetTextEntry(2).Text))); + m_Box.CaisseVille -= Int32.Parse(info.GetTextEntry(2).Text); + } + else + from.SendMessage("Il n'y a pas assez d'or dans les Caisses"); + } + catch + { + from.SendMessage("Entrer une valeur numerique!"); + } + break; + } + case 32 : //Retirer des Caisses de la garde + { + try + { + if(Int32.Parse(info.GetTextEntry(3).Text) <= m_Box.CaisseGarde) + { + from.Backpack.DropItem(new BankCheck(Int32.Parse(info.GetTextEntry(3).Text))); + m_Box.CaisseGarde -= Int32.Parse(info.GetTextEntry(3).Text); + } + else + from.SendMessage("Il n'y a pas assez d'or dans les Caisses"); + Console.WriteLine(m_Box.CaisseGarde); + } + catch + { + from.SendMessage("Entrer une valeur numerique!"); + } + break; + } + + case 33 : //vendeurs + { + try + { + if(2000 <= m_Box.CaisseVille) + { + from.Backpack.DropItem(new ContractOfEmployment()); + m_Box.CaisseVille -= 2000; + } + else + from.SendMessage("Il n'y a pas assez d'or dans les Caisses"); + } + catch + { + } + break; + } + + case 34 : //Basculler VERS Caisses de la ville + { + try + { + if(Int32.Parse(info.GetTextEntry(4).Text) <= m_Box.CaisseGarde) + { + m_Box.CaisseGarde -= Int32.Parse(info.GetTextEntry(4).Text); + m_Box.CaisseVille += Int32.Parse(info.GetTextEntry(4).Text); + } + else + from.SendMessage("Il n'y a pas assez d'or dans les Caisses"); + } + catch + { + from.SendMessage("Entrer une valeur numerique!"); + } + break; + } + + case 35 : //Basculer VERS caise de la Garde + { + try + { + if(Int32.Parse(info.GetTextEntry(4).Text) <= m_Box.CaisseVille) + { + m_Box.CaisseGarde += Int32.Parse(info.GetTextEntry(4).Text); + m_Box.CaisseVille -= Int32.Parse(info.GetTextEntry(4).Text); + } + else + from.SendMessage("Il n'y a pas assez d'or dans les Caisses"); + } + catch + { + from.SendMessage("Entrer une valeur numerique!"); + } + break; + } + } + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Gumps/CapitaineBookGump.cs b/Scripts/Vivre/Engines/POMI/Gumps/CapitaineBookGump.cs new file mode 100644 index 0000000..f652f0f --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Gumps/CapitaineBookGump.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Gumps; +using Server; +using Server.Regions; +using Server.Accounting; +using Server.Mobiles; +using Server.HuePickers; + +namespace Server.IPOMI +{ + public class CapitaineBookGump : Gump + { + private TownStone m_Town; + private CapitaineBook m_book; + + public CapitaineBookGump(PlayerMobile from, TownStone town, CapitaineBook book) + : base(20, 30) + { + m_Town = town; + m_book = book; + int i; + + AddPage(0); + + AddBackground(0, 0, 420, 430, 5054); + AddBackground(10, 10, 400, 410, 3000); + AddLabel(150, 10, 0, "Livre du Capitaine"); + AddLabel(130 + ((143 - (town.Nom.Length * 8)) / 2), 30, 0, town.Nom); + + if (m_Town.Gardes.Count < 10) + { + AddLabel(40, 75, 0, "Nommer un Garde"); + AddButton(20, 75, 2714, 2715, 1, GumpButtonType.Reply, 0); + } + if (m_Town.GardesPNJ.Count > 0) + { + AddLabel(250, 75, 0, "Rayon :"); + AddTextEntry(300, 75, 100, 20, 0x384, 1, String.Format("{0}", ((GuardSpawner)(m_Town.GardesPNJ[0])).RangeHome)); + AddButton(340, 75, 2714, 2715, 2, GumpButtonType.Reply, 0); + } + i = 0; + foreach (PlayerMobile mobile in m_Town.Gardes) + { + AddLabel(40, 120 + i * 30, 0, mobile.Name); + AddButton(15, 120 + i * 30, 0xA94, 0xA95, 100 + i, GumpButtonType.Reply, 0); + + try + { + AddLabel(220, 120 + i * 30, 0, String.Format("{0} {1}", ((GuardSpawner)(m_Town.GardesPNJ[i])).Name, ((GuardSpawner)(m_Town.GardesPNJ[i])).Location)); + AddButton(200, 120 + i * 30, 0xA94, 0xA95, 250 + i, GumpButtonType.Reply, 0); + } + catch + { + AddLabel(220, 120 + i * 30, 0, "Ajouter Garde PNJ"); + AddButton(200, 120 + i * 30, 2714, 2715, 200 + i, GumpButtonType.Reply, 0); + } + i++; + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + PlayerMobile from = sender.Mobile as PlayerMobile; + + switch (info.ButtonID) + { + case 1: + { + from.Target = new GardeTarget(m_Town); + break; + } + case 2: + { + try + { + int range = Int32.Parse(info.GetTextEntry(1).Text); + foreach (GuardSpawner guard in m_Town.GardesPNJ) + { + guard.RangeHome = range; + if (guard.SpawnedGuard != null) + guard.SpawnedGuard.RangeHome = range; + } + } + catch + { + from.SendMessage("Entrez une valeur numerique"); + } + break; + } + default: + { + try + { + if (info.ButtonID >= 100 && info.ButtonID < 200) + { + try + { + ((GuardSpawner)(m_Town.GardesPNJ[info.ButtonID - 100])).Delete(); + m_Town.GardesPNJ.RemoveAt(info.ButtonID - 100); + } + catch + { } + m_Town.Gardes.RemoveAt(info.ButtonID - 100); + ((PomiCloak)(m_Town.GardeCloak[info.ButtonID - 100])).Delete(); + m_Town.GardeCloak.RemoveAt(info.ButtonID - 100); + } + if (info.ButtonID >= 200 && info.ButtonID < 250) + { + from.Target = new PNJTarget(m_Town); + } + if (info.ButtonID >= 250 && info.ButtonID < 300) + { + try + { + ((GuardSpawner)(m_Town.GardesPNJ[info.ButtonID - 250])).Delete(); + m_Town.GardesPNJ.RemoveAt(info.ButtonID - 250); + } + catch { } + } + } + catch + { + from.SendMessage("Cette operation a deja ete faite par quelqu'un"); + } + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/POMI/Gumps/DiplomatieGump.cs b/Scripts/Vivre/Engines/POMI/Gumps/DiplomatieGump.cs new file mode 100644 index 0000000..46d3731 --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Gumps/DiplomatieGump.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Gumps; +using Server; +using Server.Regions; +using Server.Accounting; +using Server.Mobiles; +using Server.HuePickers; + +namespace Server.IPOMI +{ + public class DiplomatieGump : Gump + { + private TownStone m_Town; + + public DiplomatieGump( PlayerMobile from, TownStone town) : base( 20, 30 ) + { + m_Town = town; + + AddPage( 0 ); + + AddBackground( 0, 0, 420, 430, 5054 ); + AddBackground( 10, 10, 400, 410, 3000 ); + AddLabel( 160, 10, 0, "Diplomatie"); + AddLabel( 130 + ((143 - (town.Nom.Length * 8)) / 2), 30, 0, town.Nom ); + + AddButton( 20, 70, 4005, 4007, 0, GumpButtonType.Page, 10 ); + AddLabel( 55, 70, 0, "Alliés"); + AddButton( 120, 70, 4005, 4007, 0, GumpButtonType.Page, 20 ); + AddLabel( 155, 70, 0, "Paix"); + AddButton( 220, 70, 4005, 4007, 0, GumpButtonType.Page, 30 ); + AddLabel( 255, 70, 0, "Guerre"); + AddButton( 320, 70, 4005, 4007, 0, GumpButtonType.Page, 40 ); + AddLabel( 355, 70, 0, "Neutre"); + + AddLabel( 335, 390, 0,"Retour" ); // Quitter + AddButton( 300, 390, 0xFAE, 0x0FB0, 1, GumpButtonType.Reply, 0 ); + + AjoutePage(1, m_Town.Allies); + AjoutePage(2, m_Town.Paix); + AjoutePage(3, m_Town.Guerre); + AjoutePage(4, m_Town.Neutre); + } + + private void AjoutePage(int index, ArrayList status) + { + int i = 0; + int x = 0; + int page = 0; + int nb_pages = status.Count / 36; + + AddPage( index * 10 ); + switch(index) + { + case 1 : + { + if(status.Count == 0 ) + AddLabel( 55, 120, 0, "Aucune Ville Alliée" ); + else + AddLabel( 55, 120, 0, "Ville(s) Alliée(s)" ); + break; + } + case 2 : + { + if(status.Count == 0 ) + AddLabel( 55, 120, 0, "Aucune Ville en Paix"); + else + AddLabel( 55, 120, 0, "Ville(s) en Paix" ); + break; + } + case 3 : + { + if(status.Count == 0 ) + AddLabel( 55, 120, 0, "Aucune Ville en Guerre"); + else + AddLabel( 55, 120, 0, "Ville(s) en Guerre" ); + break; + } + case 4 : + { + if(status.Count <= 1 ) + AddLabel( 55, 120, 0, "Aucune Ville Neutre"); + else + AddLabel( 55, 120, 0, "Ville(s) Neutre(s)" ); + break; + } + } + foreach (TownStone ville in status ) + { + if( x == 36 ) + { + if( page > 0 && page < nb_pages) + { + AddButton( 60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, index * 10 + page - 1 ); //previous + AddButton( 160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, index * 10 + page + 1 ); //next + } + if( page == 0 && nb_pages > 0) + AddButton( 160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, index * 10 + page + 1 ); //next + x = 0; + page++; + AddPage( index * 10 + page ); + if( page == nb_pages && nb_pages > 0) + AddButton( 60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, index * 10 + page - 1 ); //previous + } + if(ville != m_Town) + { + AddLabel( 60 + ((x / 12) * 125), 137 + ((x % 12) * 20), 0 , ville.Nom ); + i++; + x++; + } + } + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile from = sender.Mobile as PlayerMobile; + if(info.ButtonID == 1) + from.SendGump(new TownGump(from, m_Town)); + } + } + + public class ChangeStatusGump : Gump + { + private TownStone m_Town; + private TownStone m_Conflict; + + public ChangeStatusGump( TownStone town, TownStone conflict) : base( 50, 30 ) + { + m_Town = town; + m_Conflict = conflict; + AddPage( 0 ); + AddBackground( 0, 0, 110, 120, 5054 ); + AddBackground( 10, 10, 90, 100, 3000 ); + AddButton(20, 20, 2714, 2715 , 1, GumpButtonType.Reply, 0); + AddLabel(50, 21, 0, "Alliance"); + AddButton(20, 40, 2714, 2715, 2, GumpButtonType.Reply, 0); + AddLabel(50, 41, 0, "Paix"); + AddButton(20, 60, 2714, 2715, 3, GumpButtonType.Reply, 0); + AddLabel(50, 61, 0, "Guerre"); + AddButton(20, 80, 2714, 2715, 4, GumpButtonType.Reply, 0); + AddLabel(50, 81, 0, "Neutre"); + } + + public override void OnResponse( NetState sender, RelayInfo info ) + { + PlayerMobile from = sender.Mobile as PlayerMobile; + switch(info.ButtonID) + { + case 1 : //Alliance + { + Alliance(m_Conflict); + foreach(TownStone ville in m_Conflict.Guerre) + Guerre(ville); + break; + } + case 2 : //Paix + { + Paix(m_Conflict); + break; + } + case 3 : //Guerre + { + Guerre(m_Conflict); + foreach(TownStone ville in m_Conflict.Allies) + Guerre(ville); + break; + } + case 4 : //Neutre + { + Neutre(m_Conflict); + break; + } + default : + { + from.SendGump(new TownGump(from, m_Town)); + break; + } + } + } + + private void Alliance(TownStone Conflict) + { + if(m_Town.Neutre.Contains(Conflict)) + m_Town.Neutre.Remove(Conflict); + if(m_Town.Paix.Contains(Conflict)) + m_Town.Paix.Remove(Conflict); + if(m_Town.Guerre.Contains(Conflict)) + m_Town.Guerre.Remove(Conflict); + if(!m_Town.Allies.Contains(Conflict)) + m_Town.Allies.Add(Conflict); + } + + private void Paix(TownStone Conflict) + { + if(m_Town.Neutre.Contains(Conflict)) + m_Town.Neutre.Remove(Conflict); + if(m_Town.Allies.Contains(Conflict)) + m_Town.Allies.Remove(Conflict); + if(m_Town.Guerre.Contains(Conflict)) + m_Town.Guerre.Remove(Conflict); + if(!m_Town.Paix.Contains(Conflict)) + m_Town.Paix.Add(Conflict); + } + + private void Guerre(TownStone Conflict) + { + if(m_Town.Neutre.Contains(Conflict)) + m_Town.Neutre.Remove(Conflict); + if(m_Town.Paix.Contains(Conflict)) + m_Town.Paix.Remove(Conflict); + if(m_Town.Allies.Contains(Conflict)) + m_Town.Allies.Remove(Conflict); + if(!m_Town.Guerre.Contains(Conflict)) + m_Town.Guerre.Add(Conflict); + } + + private void Neutre(TownStone Conflict) + { + if(m_Town.Allies.Contains(Conflict)) + m_Town.Allies.Remove(Conflict); + if(m_Town.Paix.Contains(Conflict)) + m_Town.Paix.Remove(Conflict); + if(m_Town.Guerre.Contains(Conflict)) + m_Town.Guerre.Remove(Conflict); + if(!m_Town.Neutre.Contains(Conflict)) + m_Town.Neutre.Add(Conflict); + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Gumps/TownGump.cs b/Scripts/Vivre/Engines/POMI/Gumps/TownGump.cs new file mode 100644 index 0000000..24ad5ae --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Gumps/TownGump.cs @@ -0,0 +1,759 @@ +using System; +using System.Collections; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Gumps; +using Server; +using Server.Regions; +using Server.Accounting; +using Server.Mobiles; +using Server.HuePickers; +using System.IO; + +namespace Server.IPOMI +{ + public class TownGump : Gump + { + private TownStone m_Town; + + public TownGump(PlayerMobile from, TownStone town) + : base(20, 30) + { + m_Town = town; + bool isMaire = town.isMaire(from); + bool isConseiller = town.isConseiller(from) || isMaire; + bool isAmbassadeur = town.isAmbassadeur(from) || isConseiller; + bool isCapitaine = town.isCapitaine(from) || isConseiller; + bool isGarde = town.isGarde(from) || isCapitaine; + bool isCitoyen = town.isCitoyen(from) || isAmbassadeur || isGarde; + bool isHLL = town.isHLL(from); + bool IsGM = isGM(from); + + int i; + int x; + int page; + int nb_pages; + + AddPage(0); + + AddBackground(0, 0, 420, 430, 5054); + AddBackground(10, 10, 400, 410, 3000); + + AddImage(130, 0, 100); + AddLabel(130 + ((143 - (town.Nom.Length * 8)) / 2), 40, 0, town.Nom); + + AddLabel(55, 103, 0, "Infos"); // INFO + AddButton(20, 103, 4005, 4007, 0, GumpButtonType.Page, 1); + if (isCitoyen || IsGM) + { + AddLabel(170, 103, 0, "Citoyens"); // Citoyens + AddButton(135, 103, 4005, 4007, 0, GumpButtonType.Page, 20); + } + if (isCapitaine || isAmbassadeur || IsGM) + { + AddLabel(295, 103, 0, "Gestion"); // Gestion + AddButton(260, 103, 4005, 4007, 0, GumpButtonType.Page, 3); + } + + AddLabel(335, 390, 0, "Quitter"); // Quitter + AddButton(300, 390, 0xFB4, 0x0FB6, 0, GumpButtonType.Reply, 0); + + // Info page + AddPage(1); + // Scriptiz : on affiche les rawname au lieu de name pour éviter les modifs de la cagoule + if (town.Maire != null) + AddLabel(20, 130, 0, "Bourgmestre de la ville : " + town.Maire.RawName); // Maire de la ville + else + AddLabel(20, 130, 0, "Bourgmestre de la ville : [ Poste vacant ]"); + + if (town.Conseiller != null) + AddLabel(20, 150, 0, "Conseiller du Bourgmestre : " + town.Conseiller.RawName); // Conseiller + else + AddLabel(20, 150, 0, "Conseiller du Bourgmestre : [ Poste vacant ]"); + if (town.Ambassadeur != null) + AddLabel(20, 170, 0, "Ambassadeur : " + town.Ambassadeur.RawName); // Ambassadeur + else + AddLabel(20, 170, 0, "Ambassadeur : [ Poste vacant ]"); + if (town.Capitaine != null) + AddLabel(20, 190, 0, "Capitaine de la Garde : " + town.Capitaine.RawName); // Capitaine + else + AddLabel(20, 190, 0, "Capitaine de la Garde : [ Poste vacant ]"); + + AddHtml(20, 220, 380, 140, town.Charte0 + "
" + + town.Charte1 + "
" + + town.Charte2 + "
" + + town.Charte3 + "
" + + town.Charte4 + "
" + + town.Charte5 + "
" + + town.Charte6 + "
" + + town.Charte7, true, true); + + AddButton(90, 367, 2714, 2715, 0, GumpButtonType.Page, 50); + AddLabel(115, 367, 0, "Hors la Loi"); + AddButton(230, 367, 2714, 2715, 104, GumpButtonType.Reply, 0); + AddLabel(255, 367, 0, "Diplomatie"); + + + if (m_Town.Candidats.Contains(from)) + { + AddButton(30, 390, 0xFB1, 0xFB3, 102, GumpButtonType.Reply, 0); + AddLabel(65, 390, 0, "Retirer sa candidature"); + } + else if (m_Town.Citoyens.Contains(from)) + { + AddButton(30, 390, 0xFA2, 0xFA4, 103, GumpButtonType.Reply, 0); + AddLabel(65, 390, 0, "Demenager"); + } + else if (m_Town.Citoyens.Count < 499) + { + AddButton(30, 390, 0xFBD, 0xFBF, 101, GumpButtonType.Reply, 0); + AddLabel(65, 390, 0, "Devenir Citoyen"); + } + + + // Citoyens + AddPage(20); + + AddLabel(17, 125, 0x25, "Bourgmestre"); + AddLabel(92, 125, 0x4D, "Conseiller"); + AddLabel(149, 125, 0x7E, "Ambassadeur"); + AddLabel(226, 125, 0x5A, "Capitaine"); + AddLabel(284, 125, 0x5B, "Garde"); + AddButton(319, 50, 0xFA8, 0xFAA, 0, GumpButtonType.Page, 8); + AddLabel(350, 50, 0, "Elections"); + i = 0; + x = 0; + page = 0; + nb_pages = m_Town.Citoyens.Count / 33; + foreach (PlayerMobile mobile in m_Town.Citoyens) + { + int couleur = 0; + if (m_Town.isMaire(mobile)) couleur = 0x25; + if (m_Town.isConseiller(mobile)) couleur = 0x4D; + if (m_Town.isAmbassadeur(mobile)) couleur = 0x7E; + if (m_Town.isCapitaine(mobile)) couleur = 0x5A; + if (m_Town.isGarde(mobile)) couleur = 0x5B; + if (x == 33) + { + if (page > 0 && page < nb_pages) + { + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 20 + page - 1); //previous + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 20 + page + 1); //next + } + if (page == 0 && nb_pages > 0) + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 20 + page + 1); //next + x = 0; + page++; + AddPage(20 + page); + if (page == nb_pages && nb_pages > 0) + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 20 + page - 1); //previous + } + AddLabel(20 + (((i / 11) % 3) * 125), 145 + ((i % 11) * 20), couleur, mobile.RawName); // Scriptiz : vrai nom + i++; + x++; + } + + // Gestion de la ville + AddPage(3); + + AddLabel(15, 130, 0, "Ville de"); + if (IsGM) + { + AddTextEntry(70, 130, 100, 50, 0x384, 1, town.Nom); + AddButton(170, 130, 2714, 2715, 301, GumpButtonType.Reply, 0); // Renomer la ville + AddLabel(240, 130, 0, "Reinitialisation"); + AddButton(380, 130, 2714, 2715, 311, GumpButtonType.Reply, 0); // Reinit de la ville + AddLabel(240, 150, 0, "Nomer le Bourgmestre"); + AddButton(380, 150, 2714, 2715, 302, GumpButtonType.Reply, 0); // Nomer le Maire + AddLabel(240, 170, 0, "Forcer Elections"); + AddButton(380, 170, 2714, 2715, 312, GumpButtonType.Reply, 0); // Forcer les Elections + + } + else + AddLabel(70, 130, 0, town.Nom); + if (m_Town.Maire == from && !IsGM) + { + AddLabel(250, 130, 0, "Refaire une cape"); + AddButton(350, 130, 2714, 2715, 310, GumpButtonType.Reply, 0); + } + if (isConseiller || IsGM) + { + AddLabel(45, 160, 0, "Liste des Citoyens"); //Liste des citoyens + AddButton(20, 160, 2714, 2715, 0, GumpButtonType.Page, 60); + AddLabel(45, 180, 0, "Liste des Candidats"); // Liste des Candidats + AddButton(20, 180, 2714, 2715, 0, GumpButtonType.Page, 40); + AddLabel(20, 240, 0, "Renvoyer"); + AddLabel(125, 240, 0, "Nomer l'Ambassadeur"); // Nommer l'Ambassadeur + AddButton(100, 240, 2714, 2715, 304, GumpButtonType.Reply, 0); + AddButton(75, 240, 0xA94, 0xA95, 307, GumpButtonType.Reply, 0); + AddLabel(20, 260, 0, "Renvoyer"); + AddLabel(125, 260, 0, "Nomer le Capitaine de la Garde"); // Nommer le capitaine + AddButton(100, 260, 2714, 2715, 305, GumpButtonType.Reply, 0); + AddButton(75, 260, 0xA94, 0xA95, 308, GumpButtonType.Reply, 0); + AddLabel(45, 280, 0, "Couleur de la Ville"); //Couleurs de la ville + AddButton(20, 280, 2714, 2715, 309, GumpButtonType.Reply, 0); + AddLabel(45, 300, 0, "Charte de la ville"); + AddButton(20, 300, 2714, 2715, 312, GumpButtonType.Page, 7); + AddLabel(45, 320, 0, "Diplomatie"); + AddButton(20, 320, 2714, 2715, 312, GumpButtonType.Page, 90); + } + if (isMaire || IsGM) + { + AddLabel(20, 220, 0, "Renvoyer"); + AddLabel(125, 220, 0, "Nomer le Conseiller"); // Nommer le conseiller + AddButton(100, 220, 2714, 2715, 303, GumpButtonType.Reply, 0); + AddButton(75, 220, 0xA94, 0xA95, 306, GumpButtonType.Reply, 0); + } + + if (isCapitaine || IsGM) + { + AddLabel(45, 200, 0, "Gestion des Hors la Loi"); //Gestion des HLL + AddButton(20, 200, 2714, 2715, 0, GumpButtonType.Page, 50); + } + + + // Affiche les candidatures + i = 0; + x = 0; + page = 0; + nb_pages = m_Town.Candidats.Count / 36; + AddPage(40); + foreach (PlayerMobile mobile in m_Town.Candidats) + { + if (x == 36) + { + if (page > 0 && page < nb_pages) + { + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 40 + page - 1); //previous + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 40 + page + 1); //next + } + if (page == 0 && nb_pages > 0) + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 40 + page + 1); //next + x = 0; + page++; + AddPage(40 + page); + if (page == nb_pages && nb_pages > 0) + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 40 + page - 1); //previous + } + AddLabel(60 + ((x / 12) * 125), 137 + ((x % 12) * 20), 0, mobile.RawName); // Scriptiz : vrai nom + AddButton(40 + ((x / 12) * 125), 137 + ((x % 12) * 20), 2714, 2715, 4000 + i, GumpButtonType.Reply, 0); + AddButton(15 + ((x / 12) * 125), 137 + ((x % 12) * 20), 0xA94, 0xA95, 4500 + i, GumpButtonType.Reply, 0); + i++; + x++; + } + + + + //Gestion des HLL + AddPage(50); + if (isCapitaine || IsGM) + { + AddLabel(15, 125, 0, "Ajouter aux Hors la loi de la ville"); + AddTextEntry(70, 125, 100, 50, 0x384, 2, "Entrer un nom"); + AddButton(170, 126, 2714, 2715, 551, GumpButtonType.Reply, 0); + } + else + AddLabel(15, 125, 0, "Liste des Hors la loi de la ville"); + + i = 0; + x = 0; + page = 0; + nb_pages = m_Town.HLL.Count / 33; + foreach (PlayerMobile mobile in m_Town.HLL) + { + if (x == 33) + { + if (page > 0 && page < nb_pages) + { + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 50 + page - 1); //previous + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 50 + page + 1); //next + } + if (page == 0 && nb_pages > 0) + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 50 + page + 1); //next + x = 0; + page++; + AddPage(50 + page); + if (page == nb_pages && nb_pages > 0) + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 50 + page - 1); //previous + } + AddLabel(40 + ((x / 11) * 125), 145 + ((x % 11) * 20), 0, mobile.RawName); // Scriptiz : on affiche le vrai nom ! + if (isCapitaine || IsGM) AddButton(15 + ((x / 11) * 125), 146 + ((x % 11) * 20), 0xA94, 0xA95, 5000 + i, GumpButtonType.Reply, 0); + i++; + x++; + } + + //Liste des citoyens + AddPage(60); + + i = 0; + x = 0; + page = 0; + nb_pages = m_Town.Citoyens.Count / 36; + + foreach (PlayerMobile mobile in m_Town.Citoyens) + { + if (x == 36) + { + if (page > 0 && page < nb_pages) + { + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 60 + page - 1); //previous + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 60 + page + 1); //next + } + if (page == 0 && nb_pages > 0) + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 60 + page + 1); //next + x = 0; + page++; + AddPage(60 + page); + if (page == nb_pages && nb_pages > 0) + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 60 + page - 1); //previous + } + AddLabel(40 + ((x / 12) * 125), 137 + ((x % 12) * 20), 0, mobile.RawName); // Scriptiz : vrai nom + AddButton(15 + ((x / 12) * 125), 137 + ((x % 12) * 20), 0xA94, 0xA95, 6000 + i, GumpButtonType.Reply, 0); + i++; + x++; + } + + //Charte de la ville + AddPage(7); + AddBackground(18, 138, 384, 24, 3000); + AddTextEntry(20, 140, 380, 20, 0, 3, town.Charte0); + AddBackground(18, 168, 384, 24, 3000); + AddTextEntry(20, 170, 380, 20, 0, 4, town.Charte1); + AddBackground(18, 198, 384, 24, 3000); + AddTextEntry(20, 200, 380, 20, 0, 5, town.Charte2); + AddBackground(18, 228, 384, 24, 3000); + AddTextEntry(20, 230, 380, 20, 0, 6, town.Charte3); + AddBackground(18, 258, 384, 24, 3000); + AddTextEntry(20, 260, 380, 20, 0, 7, town.Charte4); + AddBackground(18, 288, 384, 24, 3000); + AddTextEntry(20, 290, 380, 20, 0, 8, town.Charte5); + AddBackground(18, 318, 384, 24, 3000); + AddTextEntry(20, 320, 380, 20, 0, 9, town.Charte6); + AddBackground(18, 348, 384, 24, 3000); + AddTextEntry(20, 350, 380, 20, 0, 10, town.Charte7); + AddButton(50, 390, 4005, 4007, 701, GumpButtonType.Reply, 0); + + //Elections + AddPage(8); + AddLabel(15, 125, 0, String.Format("Fin des elections le {0} ", m_Town.EndDate)); + i = 0; + + if (!m_Town.Votants.Contains(from)) + { + if (!m_Town.Elections.Contains(from) && m_Town.Elections.Count < 10) + { + AddLabel(75, 390, 0, "Candidature"); + AddButton(40, 390, 0xFBD, 0xFBF, 81, GumpButtonType.Reply, 0); //Candidature Maire + } + } + else + { + AddLabel(60, 390, 0, "Vous etes loyal a " + ((PlayerMobile)m_Town.Resultats[m_Town.Votants.IndexOf(from)]).RawName); // Scriptiz : vrai nom + } + foreach (PlayerMobile mobile in m_Town.Elections) + { + AddLabel(65, 150 + i * 20, 0, mobile.RawName); // Scriptiz : vrai nom + if (!m_Town.Votants.Contains(from)) + AddButton(40, 150 + i * 20, 2714, 2715, 800 + i, GumpButtonType.Reply, 0); + if (IsGM) + AddButton(15, 150 + i * 20, 0xA94, 0xA95, 850 + i, GumpButtonType.Reply, 0); + i++; + } + + //Diplomatie + AddPage(90); + + AddLabel(20, 125, 0x25, "Guerre"); + AddLabel(63, 125, 0x4D, "Neutre"); + AddLabel(130, 125, 0x7E, "Alliance"); + AddLabel(210, 125, 0x5A, "Paix"); + + i = 0; + x = 0; + page = 0; + nb_pages = m_Town.Pomi.Villes.Count / 33; + foreach (TownStone ville in m_Town.Pomi.Villes) + { + int couleur = 0; + if (x == 33) + { + if (page > 0 && page < nb_pages) + { + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 90 + page - 1); //previous + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 90 + page + 1); //next + } + if (page == 0 && nb_pages > 0) + AddButton(160, 390, 0xFA5, 0x0FA7, 0, GumpButtonType.Page, 90 + page + 1); //next + x = 0; + page++; + AddPage(90 + page); + if (page == nb_pages && nb_pages > 0) + AddButton(60, 390, 0xFAE, 0x0FB0, 0, GumpButtonType.Page, 90 + page - 1); //previous + } + if (m_Town.Guerre.Contains(ville)) couleur = 0x25; + if (m_Town.Neutre.Contains(ville)) couleur = 0x4D; + if (m_Town.Allies.Contains(ville)) couleur = 0x7E; + if (m_Town.Paix.Contains(ville)) couleur = 0x5A; + if (ville != m_Town) + { + AddLabel(40 + ((x / 11) * 125), 145 + ((x % 11) * 20), couleur, ville.Nom); + AddButton(15 + ((x / 11) * 125), 146 + ((x % 11) * 20), 0xA94, 0xA95, 9000 + i, GumpButtonType.Reply, 0); + x++; + } + i++; + + } + + } + + public bool isGM(PlayerMobile from) + { + // if (from.AccessLevel == AccessLevel.GameMaster|| from.AccessLevel == AccessLevel.Counselor||from.AccessLevel == AccessLevel.Administrator) + if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + else + return false; + } + + public bool TestRace(Mobile from, TownStone m_Town) + { + string raceville = m_Town.VilleRace.ToString(); + string racejoueur = ((PlayerMobile)from).Race.Name; + + if (raceville == "Aucune") + return true; + else if (from.AccessLevel >= AccessLevel.GameMaster) + return true; + else if (raceville == "Humain" && ((racejoueur == "HumainHyel") || (racejoueur == "HumainOelm") || (racejoueur == "Voyageur"))) + return true; + else if (raceville == "Drow" && racejoueur == "Drow") + return true; + else if (raceville == "ElfeGlace" && racejoueur == "ElfeGlace") + return true; + else if (raceville == "ElfeSylvain" && racejoueur == "ElfeSylvain") + return true; + else if (raceville == "HautElfe" && racejoueur == "HautElfe") + return true; + else if (raceville == "HautEtSylvain" && ((racejoueur == "HautElfe") || (racejoueur == "ElfeSylvain"))) + return true; + else if (raceville == "Hobbit" && racejoueur == "Hobbit") + return true; + else if (raceville == "Nain" && ((racejoueur == "NainMontagne") || (racejoueur == "NainColline"))) + return true; + else + return false; + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + try + { + if (!(sender.Mobile is PlayerMobile)) + { + World.Broadcast(0x35, false, "Quelqu'un chipote avec le POMI, merci de donner les détails à Scriptiz !"); + return; + } + + PlayerMobile from = sender.Mobile as PlayerMobile; + + switch (info.ButtonID) + { + case 101: //Devenir Citoyen + { + if (!m_Town.InOtherTown(from)) + { + if (TestRace(from, m_Town)) + { + m_Town.Candidats.Add(from); + from.SendMessage("Vous etes candidat a la citoyenneté de " + m_Town.Nom); + } + else + { + from.SendMessage(38, "Cette ville ne correspond pas à votre race et ne vous acceptera pas !"); + break; + } + } + else + from.SendMessage("Vous etes deja candidat ou citoyen d'une ville"); + break; + } + case 102: //retirer sa candidature + { + if (m_Town.Candidats.Contains(from)) + m_Town.Candidats.Remove(from); + break; + } + case 103: //Demenager + { + if (!m_Town.isMaire(from) && + !m_Town.isConseiller(from) && + !m_Town.isAmbassadeur(from) && + !m_Town.isCapitaine(from) && + !m_Town.Gardes.Contains(from) && + !m_Town.Elections.Contains(from) && + m_Town.Citoyens.Contains(from)) + { + m_Town.Citoyens.Remove(from); + } + else + from.SendMessage("Vos engagements vous empechent de quitter la ville"); + break; + } + case 104: //Diplomatie + { + from.SendGump(new DiplomatieGump(from, m_Town)); + break; + } + case 301: // Renomer la ville + { + m_Town.Nom = info.GetTextEntry(1).Text; + m_Town.Name = "Pierre de " + m_Town.Nom; + break; + } + case 302: //Nomer le Maire + case 303: //Nomer le conseiller + case 304: //Nomer l'Ambassadeur + case 305: //Nomer le Capitaine + { + from.Target = new GestionTarget(m_Town, info.ButtonID); + break; + } + case 306: //Renvoyer le conseiller + { + m_Town.Conseiller = null; + if (m_Town.ConseillerCloak != null) + m_Town.ConseillerCloak.Delete(); + break; + } + case 307: //Renvoyer l'Ambassadeur + { + m_Town.Ambassadeur = null; + if (m_Town.AmbassadeurCloak != null) + m_Town.AmbassadeurCloak.Delete(); + break; + } + case 308: //Renvoyer le Capitaine + { + m_Town.Capitaine = null; + if (m_Town.CapitaineCloak != null) + m_Town.CapitaineCloak.Delete(); + if (m_Town.CptBook != null) + m_Town.CptBook.Delete(); + break; + } + case 309: //changer les couleurs + { + from.SendHuePicker(new TownHuePicker(7974, m_Town)); + break; + } + case 310: //nouvelle cape + { + + if (m_Town.MaireCloak != null) + m_Town.MaireCloak.Delete(); + m_Town.MaireCloak = new PomiCloak(m_Town, "Bourgmestre"); + from.Backpack.DropItem(m_Town.MaireCloak); + break; + + + } + case 311: //Reinit de la ville + { + m_Town.Initialisation(); + break; + } + case 312: + { + m_Town.ElecTimer.Stop(); + //m_Town.ElecTimer = new ElectionTimer(m_Town, TimeSpan.FromSeconds( 5.0 )); + m_Town.ElecTimer.Start(); + break; + } + //Ajout d'un HLL + case 551: + { + bool addok = false; + if (info.GetTextEntry(2) == null) return; // Scriptiz : crash + foreach (Mobile mobile in World.Mobiles.Values) + { + // Scriptiz : correction d'un sale crash + if (mobile == null || !(mobile is PlayerMobile)) continue; + + // Scriptiz : on traite le vrai nom ! (éviter les abus cagoules) + if (mobile.RawName.ToLower().Trim() == info.GetTextEntry(2).Text.ToLower().Trim()) + { + if (!m_Town.HLL.Contains((PlayerMobile)mobile)) + { + m_Town.HLL.Add((PlayerMobile)mobile); + addok = true; + } + } + } + if (addok) + from.SendMessage(info.GetTextEntry(2).Text + " a ete ajout aux Hors la Loi"); + else + from.SendMessage("Cette personne n'existe pas ou est deja Hors la Loi"); + from.SendGump(new TownGump(from, m_Town)); + break; + } + //Modif de la Charte + case 701: + { + m_Town.Charte0 = info.GetTextEntry(3).Text; + m_Town.Charte1 = info.GetTextEntry(4).Text; + m_Town.Charte2 = info.GetTextEntry(5).Text; + m_Town.Charte3 = info.GetTextEntry(6).Text; + m_Town.Charte4 = info.GetTextEntry(7).Text; + m_Town.Charte5 = info.GetTextEntry(8).Text; + m_Town.Charte6 = info.GetTextEntry(9).Text; + m_Town.Charte7 = info.GetTextEntry(10).Text; + from.SendGump(new TownGump(from, m_Town)); + break; + } + //Candidat a la Mairie + case 81: + { + m_Town.Elections.Add(from); + from.SendGump(new TownGump(from, m_Town)); + break; + } + default: + { + try + { + //Acceptation / refus des candidats + if (info.ButtonID >= 4000 && info.ButtonID < 5000) + { + if (info.ButtonID < 4500) + { + m_Town.Citoyens.Add(m_Town.Candidats[info.ButtonID - 4000]); + ((PlayerMobile)m_Town.Candidats[info.ButtonID - 4000]).SendMessage("Votre candidature à été acceptée"); + m_Town.Candidats.RemoveAt(info.ButtonID - 4000); + } + if (info.ButtonID > 4500) + { + ((PlayerMobile)m_Town.Candidats[info.ButtonID - 4500]).SendMessage("Votre candidature à été refusée"); + m_Town.Candidats.RemoveAt(info.ButtonID - 4500); + } + } + //Suppression d'un HLL + if (info.ButtonID >= 5000 && info.ButtonID < 5500) + { + m_Town.HLL.RemoveAt(info.ButtonID - 5000); + from.SendGump(new TownGump(from, m_Town)); + } + //Suppression d'un Citoyen + if (info.ButtonID >= 6000 && info.ButtonID < 6500) + { + if (!m_Town.isMaire((PlayerMobile)m_Town.Citoyens[info.ButtonID - 6000]) && + !m_Town.isConseiller((PlayerMobile)m_Town.Citoyens[info.ButtonID - 6000]) && + !m_Town.isAmbassadeur((PlayerMobile)m_Town.Citoyens[info.ButtonID - 6000]) && + !m_Town.isCapitaine((PlayerMobile)m_Town.Citoyens[info.ButtonID - 6000]) && + !m_Town.Elections.Contains((PlayerMobile)m_Town.Citoyens[info.ButtonID - 6000])) + m_Town.Citoyens.RemoveAt(info.ButtonID - 6000); + else + from.SendMessage("C'est un membre du conseil ou un candidat!"); + } + //Elections + if (info.ButtonID >= 800 && info.ButtonID < 850) + { + m_Town.Votants.Add(from); + m_Town.Resultats.Add((PlayerMobile)m_Town.Elections[info.ButtonID - 800]); + } + if (info.ButtonID >= 850 && info.ButtonID < 900) + { + + foreach (PlayerMobile mobile in m_Town.Resultats) + { + if (((PlayerMobile)m_Town.Elections[info.ButtonID - 850]) == mobile) + { + m_Town.Votants.RemoveAt(m_Town.Resultats.IndexOf(mobile)); + } + } + while (m_Town.Resultats.Contains(m_Town.Elections[info.ButtonID - 850])) + { + m_Town.Resultats.Remove(m_Town.Elections[info.ButtonID - 850]); + } + m_Town.Elections.Remove(m_Town.Elections[info.ButtonID - 850]); + } + + //diplomatie + if (info.ButtonID >= 9000 && info.ButtonID < 10000) + { + from.SendGump(new ChangeStatusGump(m_Town, (TownStone)(m_Town.Pomi.Villes[info.ButtonID - 9000]))); + break; + } + if (info.ButtonID != 0) from.SendGump(new TownGump(from, m_Town)); + } + catch + { + from.SendMessage("Quelqu'un a deja fait cette operation"); + } + break; + } + } + //m_Town.AdminInUse = false; + } + catch + { + // Scriptiz : debug du POMI ! + using (StreamWriter sw = new StreamWriter("pomi_debug.log", true)) + { + string name = sender.Mobile != null ? sender.Mobile.RawName : "null"; + string username = sender.Account != null ? sender.Account.Username : "null"; + sw.WriteLine(String.Format("{0} : {1} ({2}) a envoyé {3}", DateTime.Now, name, username, info.ButtonID)); + foreach (TextRelay tr in info.TextEntries) + { + sw.WriteLine(String.Format("\t{0} : {1}", tr.EntryID, tr.Text)); + } + } + } + } + } + + public class TownHuePicker : HuePicker + { + private TownStone m_town; + + public TownHuePicker(int ItemID, TownStone town) + : base(ItemID) + { + m_town = town; + } + public override void OnResponse(int hue) + { + //if (m_town.MaireCloak != null) + // m_town.MaireCloak.Hue = hue; + //if (m_town.ConseillerCloak != null) + // m_town.ConseillerCloak.Hue = hue; + //if (m_town.AmbassadeurCloak != null) + // m_town.AmbassadeurCloak.Hue = hue; + //if (m_town.CapitaineCloak != null) + // m_town.CapitaineCloak.Hue = hue; + //if (m_town.CptBook != null) + // m_town.CptBook.Hue = hue; + //foreach (PomiCloak cloak in m_town.GardeCloak) + // cloak.Hue = hue; + //PomiCloak pnjcloak; + //Halberd arme; + //foreach (GuardSpawner guard in m_town.GardesPNJ) + //{ + // try + // { + // arme = guard.SpawnedGuard.FindItemOnLayer(Layer.TwoHanded) as Halberd; + // pnjcloak = guard.SpawnedGuard.FindItemOnLayer(Layer.Cloak) as PomiCloak; + // if (pnjcloak != null) + // pnjcloak.Hue = hue; + // if (arme != null) + // arme.Hue = hue; + // } + // catch { } + + //} + + m_town.Hue = hue; + //m_town.Box.Hue = hue; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/POMI/Items/CapitaineBook.cs b/Scripts/Vivre/Engines/POMI/Items/CapitaineBook.cs new file mode 100644 index 0000000..6cb631c --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Items/CapitaineBook.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.IPOMI +{ + public class CapitaineBook : Item + { + private TownStone m_town; + + public CapitaineBook(TownStone town) : base(0xEFA) + { + m_town = town; + LootType = LootType.Newbied; + Weight = 0; + Name = "Livre du Capitaine"; + Hue = town.Hue; + } + + public CapitaineBook( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick(Mobile from) + { + if(m_town.Capitaine == (PlayerMobile)from) + { + from.SendGump(new CapitaineBookGump((PlayerMobile)from, m_town, this)); + } + else + from.SendMessage("Vous ne pouvez pas utiliser ce livre"); + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + writer.Write( (TownStone)m_town ); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_town = (TownStone)reader.ReadItem(); + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Items/GuardSpawner.cs b/Scripts/Vivre/Engines/POMI/Items/GuardSpawner.cs new file mode 100644 index 0000000..f1aff4c --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Items/GuardSpawner.cs @@ -0,0 +1,130 @@ +using System; +using System.IO; +using System.Collections; +using Server; +using Server.Items; + +namespace Server.IPOMI +{ + public class GuardSpawner : Item + { + private TownStone m_Town; + private TimeSpan m_Delay; + private PomiGuard m_SpawnedGuard; + private int m_RangeHome; + private SpawnTimer m_timer; + private static bool m_Running; + + public GuardSpawner(Point3D location, TownStone town) : base( 0x1f13 ) + { + m_Running = false; + Location = location; + Map = town.Map; + m_SpawnedGuard = null; + m_Town = town; + m_Delay = TimeSpan.FromSeconds( 600.0 ); + Visible = false; + Movable = false; + PomiGuard guard = new PomiGuard(m_Town, this); + m_SpawnedGuard = guard; + if(m_Town.GardesPNJ.Count > 0 ) + m_RangeHome = ((GuardSpawner)(m_Town.GardesPNJ[0])).RangeHome; + else + m_RangeHome = 5; + guard.Home = Location; + guard.RangeHome = 5; + Name = guard.Name; + } + + public PomiGuard SpawnedGuard + { + get{ return m_SpawnedGuard;} + set{ m_SpawnedGuard = value;} + } + + public int RangeHome + { + get{ return m_RangeHome;} + set{ m_RangeHome = value;} + } + + public bool Running + { + get{ return m_Running;} + set{ m_Running = value;} + } + + public GuardSpawner( Serial serial ) : base( serial ) + { + } + + public void Start() + { + m_timer = new SpawnTimer(m_Town, this, m_Delay); + m_timer.Start(); + m_Running = true; + } + + public override void OnDelete() + { + if(m_SpawnedGuard != null) + m_SpawnedGuard.Delete(); + if(m_timer != null) + { + m_timer.Stop(); + } + m_Running = false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.Write( m_Delay); + writer.Write( (TownStone)m_Town ); + writer.Write( (PomiGuard)m_SpawnedGuard); + writer.Write( m_RangeHome ); + writer.Write( m_Running ); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + m_Delay = reader.ReadTimeSpan(); + m_Town = (TownStone)reader.ReadItem(); + m_SpawnedGuard = (PomiGuard)reader.ReadMobile(); + m_RangeHome = reader.ReadInt(); + m_Running = reader.ReadBool(); + if(m_Running) + { + m_timer = new SpawnTimer(m_Town, this, m_Delay); + m_timer.Start(); + } + + } + + private class SpawnTimer : Timer + { + private TownStone m_Town; + private GuardSpawner m_spawner; + public SpawnTimer(TownStone town, GuardSpawner spawner, TimeSpan delay) : base( delay ) + { + m_Town = town; + m_spawner = spawner; + } + protected override void OnTick() + { + PomiGuard guard = new PomiGuard(m_Town, m_spawner); + m_spawner.SpawnedGuard = guard; + guard.Home = m_spawner.Location; + guard.RangeHome = 5; + m_spawner.Name = guard.Name; + m_spawner.Running = false; + } + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Items/POMIStone.cs b/Scripts/Vivre/Engines/POMI/Items/POMIStone.cs new file mode 100644 index 0000000..b395d57 --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Items/POMIStone.cs @@ -0,0 +1,161 @@ +using System; +using Server.Network; +using System.Collections; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.IPOMI +{ + public class POMI : Item + { + private ArrayList m_Villes; + + // Scriptiz : possibilit� de changer la hue avec un .set hue xxx tout en impactant les changements sur tout le pomi + public override int Hue + { + get + { + return base.Hue; + } + set + { + base.Hue = value; + + } + } + + [Constructable] + public POMI() : base( 0xED4 ) + { + Movable = false; + m_Villes = new ArrayList(); + Hue = 0x489; + Name = "POMI"; + } + + public POMI( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public ArrayList Villes + { + get{return m_Villes;} + } + + [CommandProperty( AccessLevel.GameMaster )] + public int NbVilles + { + get{return m_Villes.Count;} + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.WriteItemList( m_Villes, true ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_Villes = reader.ReadItemList(); + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel >= AccessLevel.Administrator ) + { + TownStone town = new TownStone(this); + from.Backpack.DropItem(town); + m_Villes.Add(town); + from.Backpack.DropItem(new TownBox(town)); + foreach(TownStone othertown in m_Villes) + { + if(othertown != town ) + othertown.Neutre.Add(town); + town.Neutre.Add(othertown); + } + from.SendAsciiMessage( 0x482, "Nouvelle pierre de ville creee" ); + } + else + { + from.SendMessage( "Vous n'avez pas les acces pour administrer POMI" ); + } + } + + /** + * Scriptiz : divers ajouts pour le POMI + */ + // Scriptiz : m�thode pour trouver la pierre POMI principale (celle qui a le plus de villes) + public static POMI FindPomi() + { + POMI mainPomi = null; + + foreach (Item i in World.Items.Values) + { + if (i is POMI) + { + if (mainPomi == null) + mainPomi = (POMI)i; + else if (((POMI)i).Villes.Count > mainPomi.Villes.Count) + mainPomi = (POMI)i; + } + } + return mainPomi; + } + + // Scriptiz : m�thode pour v�rifier si un point se trouve � l'int�rieur de la ville d'un PJ + public static bool IsPointInPlayerTown(PlayerMobile from, Point2D location) + { + if (from == null) return false; + + ArrayList villesPomi = POMI.FindPomi().Villes; + TownStone ts = null; + foreach (object o in villesPomi) + { + if (o is TownStone) + ts = (TownStone)o; + + if (ts != null) + { + if (ts.Citoyens.Contains(from) && ts.Map == from.Map) + { + double distance = Math.Sqrt(Math.Pow(ts.Location.X - location.X, 2) + Math.Pow(ts.Location.Y - location.Y, 2)); + if (distance > ts.MaxDistance) + { + from.SendMessage("Vous ne pouvez pas b�tir en dehors de votre ville."); + return false; + } + } + } + } + return true; + } + + // M�thode pour v�rifier qu'un joueur soit bien citoyen d'une ville donn�e + public static bool IsPlayerCitizenOf(Mobile from, string town) + { + if (from == null) return false; + + POMI thePomi = POMI.FindPomi(); + if (thePomi == null) return false; + + foreach (object v in thePomi.Villes) + { + if(v == null || !(v is TownStone)) continue; + + TownStone ville = (TownStone)v; + + if (ville.Nom.ToLower() == town.ToLower()) + return ville.Citoyens.Contains(from); + } + return false; + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Items/PomiCloak.cs b/Scripts/Vivre/Engines/POMI/Items/PomiCloak.cs new file mode 100644 index 0000000..46175ea --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Items/PomiCloak.cs @@ -0,0 +1,103 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.IPOMI +{ + [FlipableAttribute( 0x1515, 0x1530 )] + public class PomiCloak : BaseCloak + { + private TownStone m_town; + private string m_titre = null; + + public PomiCloak(TownStone town, string titre) : base(0x1515) + { + m_town = town; + m_titre = titre; + LootType = LootType.Newbied; + Weight = 0; + Name = titre; + Hue = town.Hue; + } + + public TownStone Town + { + get{ return m_town; } + } + + public PomiCloak( Serial serial ) : base( serial ) + { + } + + public override bool OnEquip(Mobile from) + { + /*try + { + if((m_town.Maire == (PlayerMobile)from) && m_titre == "Bourgmestre"); + if((m_town.Conseiller == (PlayerMobile)from) && m_titre == "Conseiller"); + if((m_town.Ambassadeur == (PlayerMobile)from) && m_titre == "Ambassadeur"); + if((m_town.Capitaine == (PlayerMobile)from) && m_titre == "Capitaine"); + if(m_town.Gardes.Contains((PlayerMobile)from) && m_titre == "Garde"); + } + catch{} + if(m_titre != null) + { + from.Title = m_titre + " de " + m_town.Nom; + //m_titre = null; + return true; + } + else + { + from.SendMessage("Vous ne pouvez pas porter cette cape"); + return false; + }*/ + bool Ok = false; + + if(m_town.Maire != null) + if((m_town.Maire == (PlayerMobile)from) && m_titre == "Bourgmestre") + Ok = true; + if(m_town.Conseiller != null) + if((m_town.Conseiller == (PlayerMobile)from) && m_titre == "Conseiller") + Ok = true; + if(m_town.Ambassadeur != null) + if((m_town.Ambassadeur == (PlayerMobile)from) && m_titre == "Ambassadeur") + Ok = true; + if(m_town.Capitaine != null) + if((m_town.Capitaine == (PlayerMobile)from) && m_titre == "Capitaine") + Ok = true; + if(m_town.Gardes.Contains((PlayerMobile)from) && m_titre == "Garde") + Ok = true; + + if(Ok) + { + from.Title = m_titre + " de " + m_town.Nom; + return true; + } + + from.SendMessage("Vous ne pouvez pas porter cette cape"); + return false; + } + + public override void OnRemoved( object parent ) + { + if ( parent is Mobile ) + ((Mobile)parent).Title = null; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 1 ); + writer.Write( (TownStone)m_town ); + writer.Write((string)m_titre); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_town = (TownStone)reader.ReadItem(); + m_titre = reader.ReadString(); + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Items/TownBox.cs b/Scripts/Vivre/Engines/POMI/Items/TownBox.cs new file mode 100644 index 0000000..8c1b9a4 --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Items/TownBox.cs @@ -0,0 +1,313 @@ +using System; +using Server.Network; +using System.Collections; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.IPOMI +{ + public class TownBox : Item + { + private TownStone m_Town; + private ArrayList m_Payeurs; + private ArrayList m_HistoPayeurs; + private ArrayList m_Retard_1; + private ArrayList m_Retard_2; + private int m_Taxe; + private int m_CaisseVille; + private int m_CaisseGarde; + private TaxeTimer m_TaxeTimer; + private TimeSpan m_Delay; + private DateTime m_EndDate; + private int m_Don; + + public int Don + { + get{return m_Don;} + set{m_Don = value;} + } + + public ArrayList Payeurs + { + get{return m_Payeurs;} + set{m_Payeurs = value;} + } + public ArrayList HistoPayeurs + { + get{return m_HistoPayeurs;} + set{m_HistoPayeurs = value;} + } + + + public ArrayList Retard_1 + { + get{return m_Retard_1;} + set{m_Retard_1 = value;} + } + + + public ArrayList Retard_2 + { + get{return m_Retard_2;} + set{m_Retard_2 = value;} + } + + [CommandProperty( AccessLevel.Administrator )] + public int Taxe + { + get{return m_Taxe;} + set{m_Taxe = Math.Abs(value);} + } + + [CommandProperty( AccessLevel.Administrator )] + public int CaisseVille + { + get{return m_CaisseVille;} + set{m_CaisseVille = value;} + } + + [CommandProperty( AccessLevel.Administrator )] + public int CaisseGarde + { + get{return m_CaisseGarde;} + set{m_CaisseGarde = value;} + } + + [CommandProperty( AccessLevel.Administrator )] + public TaxeTimer TaxTimer + { + get{return m_TaxeTimer;} + set{m_TaxeTimer = value;} + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan TaxeDelay + { + get{return m_Delay;} + set{m_Delay = value;} + } + + public DateTime EndDate + { + get {return m_EndDate;} + set {m_EndDate = value;} + } + + public TownBox(TownStone Town) : base( 0xE41 ) + { + m_Town = Town; + Name = "Tr�sorerie"; + Hue = Town.Hue; + m_Town.Box = this; + m_Payeurs = new ArrayList(); + m_HistoPayeurs = new ArrayList(); + m_Retard_1 = new ArrayList(); + m_Retard_2 = new ArrayList(); + m_Taxe = 500; + m_CaisseVille = 0; + m_CaisseGarde = 0; + m_Delay = TimeSpan.FromDays( 7.0 ); + m_EndDate = DateTime.Now + m_Delay; + m_TaxeTimer = new TaxeTimer(m_Town, m_Delay); + m_TaxeTimer.Start(); + } + + public TownBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.Write( (TownStone)m_Town); + writer.WriteMobileList( m_Payeurs, true); + writer.WriteMobileList( m_HistoPayeurs, true); + writer.WriteMobileList( m_Retard_1, true); + writer.WriteMobileList( m_Retard_2, true); + writer.Write( (int)m_Taxe ); + writer.Write( (int)m_CaisseVille ); + writer.Write( (int)m_CaisseGarde ); + writer.Write( m_EndDate ); + writer.Write( m_Delay ); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Town = (TownStone)reader.ReadItem(); + m_Payeurs = reader.ReadMobileList(); + m_HistoPayeurs = reader.ReadMobileList(); + m_Retard_1 = reader.ReadMobileList(); + m_Retard_2 = reader.ReadMobileList(); + m_Taxe = reader.ReadInt(); + m_CaisseVille = reader.ReadInt(); + m_CaisseGarde = reader.ReadInt(); + m_EndDate = reader.ReadDateTime(); + m_TaxeTimer = new TaxeTimer(m_Town, m_EndDate - DateTime.Now); + m_TaxeTimer.Start(); + m_Delay = reader.ReadTimeSpan(); + } + + public override void OnSingleClick(Mobile from) + { + LabelTo(from, "[ " + m_Town.Nom + " ]"); + LabelTo(from, Name); + } + + public override void OnDoubleClick( Mobile from ) + { + from.SendGump(new BoxGump((PlayerMobile)from,m_Town,this)); + } + + public void Donnation(PlayerMobile from,int valeur) + { + // Scriptiz : loggons les paiements pour �tre sur + try + { + using (System.IO.StreamWriter sw = new System.IO.StreamWriter("taxes.log", true)) + { + string name = (from != null ? from.Name : "null"); + string acc = (from != null && from.Account != null ? from.Account.Username : "null"); + sw.WriteLine(String.Format("{0} : {1} ({2}) fait un don de {3} po � {4}", DateTime.Now, name, acc, valeur, m_Town.Name)); + } + } + catch { } + + // trap the cheaters + valeur = Math.Abs(valeur); + + if (valeur == 0 ) + { + from.SendMessage("Radin!"); + return; + } + else if(from.BankBox.TotalGold >= valeur ) + { + from.BankBox.ConsumeTotal(typeof(Gold), valeur); + m_CaisseVille += valeur; + from.SendMessage("La ville vous remercie!"); + } + else + from.SendMessage("Vous n'avez pas assez d'or dans votre Banque!"); + + + } + + + + public void Paiement(PlayerMobile from, bool manuel) + { + // Scriptiz : taxes automatiques d�sactiv�es + if (!manuel) + return; + + // Scriptiz : loggons les paiements pour �tre sur + try + { + using (System.IO.StreamWriter sw = new System.IO.StreamWriter("taxes.log", true)) + { + string name = (from != null ? from.Name : "null"); + string acc = (from != null && from.Account != null ? from.Account.Username : "null"); + sw.WriteLine(String.Format("{0} : {1} ({2}) paye {3} po � {4} [{5}]", DateTime.Now, name, acc, m_Taxe, m_Town.Name, (manuel ? "Don" : "Taxes"))); + } + } + catch { } + + if(!(m_Town.isMaire(from) || + m_Town.isConseiller(from) || + m_Town.isAmbassadeur(from) || + m_Town.isCapitaine(from) )) + { + if(from.BankBox.TotalGold >= m_Taxe ) + { + from.BankBox.ConsumeTotal(typeof(Gold), m_Taxe); + m_CaisseVille += m_Taxe / 2; + m_CaisseGarde += m_Taxe / 2; + if(manuel) + { + if(m_Retard_2.Contains(from)) + { + m_Retard_2.Remove(from); + m_Retard_1.Add(from); + } + else if(m_Retard_1.Contains(from)) + m_Retard_1.Remove(from); + else + m_Payeurs.Add(from); + } + else + { + if(!m_Retard_1.Contains(from) && !m_Retard_2.Contains(from)) + m_Payeurs.Add(from); + } + } + else + { + if(!manuel) + { + if(m_Retard_1.Contains(from)) + { + m_Retard_1.Remove(from); + m_Retard_2.Add(from); + } + else + m_Retard_1.Add(from); + } + else + from.SendMessage("Vous n'avez pas assez d'or dans votre Banque!"); + } + } + } + } + + public class TaxeTimer : Timer + { + private TownStone m_Town; + + public TaxeTimer(TownStone town, TimeSpan delay) : base( delay ) + { + m_Town = town; + } + + protected override void OnTick() + { + ArrayList m_Exclus = new ArrayList(); + m_Town.Box.HistoPayeurs.Clear(); + foreach(PlayerMobile mobile in m_Town.Citoyens) + { + if(m_Town.Box.Retard_2.Contains(mobile)) + { + m_Town.Box.Retard_2.Remove(mobile); + m_Exclus.Add(mobile); + } + else + if(!m_Town.Box.Payeurs.Contains(mobile)) + m_Town.Box.Paiement(mobile,false); + } + foreach(PlayerMobile mobile in m_Exclus) + { + foreach(PlayerMobile result in m_Town.Resultats) + { + if(mobile == result) + m_Town.Votants.RemoveAt(m_Town.Resultats.IndexOf(result)); + } + while(m_Town.Resultats.Contains(mobile)) + m_Town.Resultats.Remove(mobile); + m_Town.Resultats.Remove(mobile); + m_Town.Citoyens.Remove(mobile); + } + foreach(PlayerMobile mobile in m_Town.Box.Payeurs) + m_Town.Box.HistoPayeurs.Add(mobile); + m_Town.Box.Payeurs.Clear(); + + m_Town.Box.EndDate = DateTime.Now + m_Town.Box.TaxeDelay; + //m_Town.Box.TaxTimer = new TaxeTimer(m_Town, m_Town.Box.TaxeDelay); + m_Town.Box.TaxTimer.Start(); + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/Items/TownStone.cs b/Scripts/Vivre/Engines/POMI/Items/TownStone.cs new file mode 100644 index 0000000..2e8f56c --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/Items/TownStone.cs @@ -0,0 +1,854 @@ +using System; +using Server.Network; +using System.Collections; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.IPOMI +{ + public class TownStone : Item + { + private POMI m_Pomi; + private ArrayList m_Citoyens; + private ArrayList m_Candidats; + private ArrayList m_HLL; + private ArrayList m_gardes_pnj; + private ArrayList m_Allies; + private ArrayList m_Paix; + private ArrayList m_Guerre; + private ArrayList m_Neutre; + private PlayerMobile m_Maire; + private PlayerMobile m_Conseiller; + private PlayerMobile m_Ambassadeur; + private PlayerMobile m_Capitaine; + private ArrayList m_Gardes; + private PomiCloak m_MaireCloak; + private PomiCloak m_ConseillerCloak; + private PomiCloak m_AmbassadeurCloak; + private PomiCloak m_CapitaineCloak; + private CapitaineBook m_CapitaineBook; + private ArrayList m_GardeCloak; + private string m_Nom; + private string m_Charte0; + private string m_Charte1; + private string m_Charte2; + private string m_Charte3; + private string m_Charte4; + private string m_Charte5; + private string m_Charte6; + private string m_Charte7; + private ArrayList m_Votants; + private ArrayList m_Elections; + private ArrayList m_Resultats; + private DateTime m_EndDate; + private ElectionTimer m_ElecTimer; + private TimeSpan m_ElecDelay; + private int m_MaxDistance; + private TownBox m_Box; + private VilleRaciale m_VilleRace; + //private bool m_AdminInUse; + + public TownStone(POMI Pomi) : base( 0xED4 ) + { + m_Pomi = Pomi; + m_Citoyens = new ArrayList(); + m_Candidats = new ArrayList(); + m_HLL = new ArrayList(); + m_Allies = new ArrayList(); + m_Paix = new ArrayList(); + m_Guerre = new ArrayList(); + m_Neutre = new ArrayList(); + m_Maire = null; + m_Conseiller = null; + m_Ambassadeur = null; + m_Capitaine = null; + m_Gardes = new ArrayList(); + m_gardes_pnj = new ArrayList(); + m_MaireCloak = null; + m_ConseillerCloak = null; + m_AmbassadeurCloak = null; + m_CapitaineCloak = null; + m_CapitaineBook = null; + m_GardeCloak = new ArrayList(); + Name = "Pierre de ville"; + m_Nom = "Sans nom"; + m_Votants = new ArrayList(); + m_Elections = new ArrayList(); + m_Resultats = new ArrayList(); + m_ElecDelay = TimeSpan.FromDays( 14.0 ); + m_EndDate = DateTime.Now + m_ElecDelay; + m_ElecTimer = new ElectionTimer(this, m_ElecDelay); + m_ElecTimer.Start(); + m_MaxDistance = 100; + //m_AdminInUse = false; + } + + public TownStone( Serial serial ) : base( serial ) + { + } + + + public enum VilleRaciale + { + Aucune, + Humain, + Drow, + ElfeGlace, + ElfeSylvain, + HautElfe, + HautEtSylvain, + Hobbit, + Nain + } + + public bool isMaire(PlayerMobile from) + { + if(from == m_Maire) return true; + return false; + } + + public bool isConseiller(PlayerMobile from) + { + if(from == m_Conseiller) return true; + return false; + } + + public bool isAmbassadeur(PlayerMobile from) + { + if(from == m_Ambassadeur) return true; + return false; + } + + public bool isCapitaine(PlayerMobile from) + { + if(from == m_Capitaine) return true; + return false; + } + + public bool isGarde(PlayerMobile from) + { + if(m_Gardes.Contains(from)) return true; + return false; + } + + public bool isCitoyen(PlayerMobile from) + { + if(m_Citoyens.Contains(from)) return true; + return false; + } + + public bool isHLL(PlayerMobile from) + { + if(m_HLL.Contains(from)) return true; + return false; + } + + public POMI Pomi + { + get{return m_Pomi;} + } + + public string Nom + { + get {return m_Nom;} + set {m_Nom = value;} + } + + public PlayerMobile Maire + { + get {return m_Maire;} + set {m_Maire = value;} + } + + public PlayerMobile Conseiller + { + get {return m_Conseiller;} + set {m_Conseiller = value;} + } + + public PlayerMobile Ambassadeur + { + get {return m_Ambassadeur;} + set {m_Ambassadeur = value;} + } + + public PlayerMobile Capitaine + { + get {return m_Capitaine;} + set {m_Capitaine = value;} + } + + public ArrayList Citoyens + { + get {return m_Citoyens;} + set {m_Citoyens = value;} + } + + public ArrayList Candidats + { + get {return m_Candidats;} + set {m_Candidats = value;} + } + + public ArrayList Gardes + { + get {return m_Gardes;} + set {m_Gardes = value;} + } + + public ArrayList GardesPNJ + { + get {return m_gardes_pnj;} + set {m_gardes_pnj = value;} + } + + public ArrayList HLL + { + get {return m_HLL;} + set {m_HLL = value;} + } + + public ArrayList Allies + { + get {return m_Allies;} + set {m_Allies = value;} + } + + public ArrayList Paix + { + get {return m_Paix;} + set {m_Paix = value;} + } + + public ArrayList Guerre + { + get {return m_Guerre;} + set {m_Guerre = value;} + } + + public ArrayList Neutre + { + get {return m_Neutre;} + set {m_Neutre = value;} + } + + public PomiCloak MaireCloak + { + get {return m_MaireCloak;} + set {m_MaireCloak = value;} + } + + public PomiCloak ConseillerCloak + { + get {return m_ConseillerCloak;} + set {m_ConseillerCloak = value;} + } + + public PomiCloak AmbassadeurCloak + { + get {return m_AmbassadeurCloak;} + set {m_AmbassadeurCloak = value;} + } + + public PomiCloak CapitaineCloak + { + get {return m_CapitaineCloak;} + set {m_CapitaineCloak = value;} + } + + public CapitaineBook CptBook + { + get {return m_CapitaineBook;} + set {m_CapitaineBook = value;} + } + + public ArrayList GardeCloak + { + get {return m_GardeCloak;} + set {m_GardeCloak = value;} + } + + public string Charte0 + { + get {return m_Charte0;} + set {m_Charte0 = value;} + } + + public string Charte1 + { + get {return m_Charte1;} + set {m_Charte1 = value;} + } + public string Charte2 + { + get {return m_Charte2;} + set {m_Charte2 = value;} + } + public string Charte3 + { + get {return m_Charte3;} + set {m_Charte3 = value;} + } + public string Charte4 + { + get {return m_Charte4;} + set {m_Charte4 = value;} + } + public string Charte5 + { + get {return m_Charte5;} + set {m_Charte5 = value;} + } + public string Charte6 + { + get {return m_Charte6;} + set {m_Charte6 = value;} + } + public string Charte7 + { + get {return m_Charte7;} + set {m_Charte7 = value;} + } + + public ArrayList Votants + { + get {return m_Votants;} + set {m_Votants = value;} + } + + public ArrayList Elections + { + get {return m_Elections;} + set {m_Elections = value;} + } + + public ArrayList Resultats + { + get {return m_Resultats;} + set {m_Resultats = value;} + } + + public DateTime EndDate + { + get {return m_EndDate;} + set {m_EndDate = value;} + } + + public ElectionTimer ElecTimer + { + get {return m_ElecTimer;} + set {m_ElecTimer = value;} + } + + [CommandProperty( AccessLevel.GameMaster )] + public TimeSpan ElecDelay + { + get {return m_ElecDelay;} + set {m_ElecDelay = value;} + } + + [CommandProperty( AccessLevel.GameMaster )] + public VilleRaciale VilleRace + { + get {return m_VilleRace;} + set {m_VilleRace = value;} + } + + public TownBox Box + { + get {return m_Box;} + set {m_Box = value;} + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxDistance + { + get {return m_MaxDistance;} + set {m_MaxDistance = value;} + } + + /*public bool AdminInUse + { + get {return m_AdminInUse;} + set {m_AdminInUse = value;} + }*/ + + // Scriptiz : possibilit� de changer la hue avec un .set hue xxx tout en impactant les changements sur tout le pomi + [CommandProperty(AccessLevel.GameMaster)] + public override int Hue + { + get { return base.Hue; } + set + { + base.Hue = value; + if (this.MaireCloak != null) + this.MaireCloak.Hue = value; + if (this.ConseillerCloak != null) + this.ConseillerCloak.Hue = value; + if (this.AmbassadeurCloak != null) + this.AmbassadeurCloak.Hue = value; + if (this.CapitaineCloak != null) + this.CapitaineCloak.Hue = value; + if (this.CptBook != null) + this.CptBook.Hue = value; + foreach (PomiCloak cloak in this.GardeCloak) + cloak.Hue = value; + + PomiCloak pnjcloak; + //Halberd arme; + foreach (GuardSpawner guard in this.GardesPNJ) + { + try + { + //arme = guard.SpawnedGuard.FindItemOnLayer(Layer.TwoHanded) as Halberd; + pnjcloak = guard.SpawnedGuard.FindItemOnLayer(Layer.Cloak) as PomiCloak; + if (pnjcloak != null) + pnjcloak.Hue = value; + //if (arme != null) + //arme.Hue = hue; + } + catch { } + + } + + //this.Hue = value; + this.Box.Hue = value; + } + } + + public void Initialisation() + { + m_Citoyens.Clear(); + m_Candidats.Clear(); + m_HLL.Clear(); + m_Allies.Clear(); + m_Paix.Clear(); + m_Guerre.Clear(); + m_Neutre.Clear(); + if(m_Maire != null) + m_Maire.Title = null; + m_Maire = null; + m_Nom = "Sans nom"; + Name = "Pierre de ville"; + Hue = 0; + NouveauConseil(); + m_ElecTimer.Stop(); + m_ElecTimer = new ElectionTimer(this, m_ElecDelay); + m_ElecTimer.Start(); + m_VilleRace = VilleRaciale.Aucune; + } + + public void NouveauConseil() + { + if(m_MaireCloak != null) + m_MaireCloak.Delete(); + m_MaireCloak = null; + + if(m_Conseiller != null) + m_Conseiller.Title = null; + m_Conseiller = null; + if(m_ConseillerCloak != null) + m_ConseillerCloak.Delete(); + m_ConseillerCloak = null; + + if(m_Ambassadeur != null) + m_Ambassadeur.Title = null; + m_Ambassadeur = null; + if(m_AmbassadeurCloak != null) + m_AmbassadeurCloak.Delete(); + m_AmbassadeurCloak = null; + + if(m_Capitaine != null) + m_Capitaine.Title = null; + m_Capitaine = null; + if(m_CapitaineCloak != null) + m_CapitaineCloak.Delete(); + m_CapitaineCloak = null; + if(m_CapitaineBook != null) + m_CapitaineBook.Delete(); + m_CapitaineBook = null; + + + foreach(PlayerMobile GardePlayer in m_Gardes) + GardePlayer.Title = null; + m_Gardes.Clear(); + foreach(GuardSpawner guard in m_gardes_pnj) + guard.Delete(); + m_gardes_pnj.Clear(); + foreach(PomiCloak cloak in m_GardeCloak) + cloak.Delete(); + m_GardeCloak.Clear(); + m_Votants.Clear(); + m_Elections.Clear(); + m_Resultats.Clear(); + } + + public bool InOtherTown(Mobile mobile) + { + bool exist = false; + foreach(TownStone town in m_Pomi.Villes) + { + if(town != this) + if(town.Citoyens.Contains(mobile) || town.Candidats.Contains(mobile)) exist = true; + } + return exist; + } + + public override void OnDelete() + { + Initialisation(); + foreach(TownStone ville in m_Pomi.Villes) + { + if(ville.Allies.Contains(this)) + ville.Allies.Remove(this); + if(ville.Paix.Contains(this)) + ville.Paix.Remove(this); + if(ville.Guerre.Contains(this)) + ville.Guerre.Remove(this); + if(ville.Neutre.Contains(this)) + ville.Neutre.Remove(this); + } + m_Pomi.Villes.Remove(this); + try + { + m_Box.Delete(); + } + catch{} + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + //version 1 Freeze 6 nov 2004 + + writer.Write( (byte) m_VilleRace ); + + // version 0 + + + writer.WriteMobileList( m_Citoyens, true ); + writer.WriteMobileList( m_Candidats, true ); + writer.WriteMobileList( m_HLL, true ); + writer.WriteMobileList( m_Gardes, true ); + writer.WriteItemList( m_gardes_pnj, true ); + writer.Write( (Mobile)m_Maire ); + writer.Write( (Mobile)m_Conseiller ); + writer.Write( (Mobile)m_Ambassadeur ); + writer.Write( (Mobile)m_Capitaine ); + writer.Write( (POMI)m_Pomi); + writer.Write( (PomiCloak)m_MaireCloak); + writer.Write( (PomiCloak)m_ConseillerCloak); + writer.Write( (PomiCloak)m_AmbassadeurCloak); + writer.Write( (PomiCloak)m_CapitaineCloak); + writer.Write( (CapitaineBook)m_CapitaineBook); + writer.WriteItemList( m_GardeCloak, true ); + writer.Write((string)m_Nom); + writer.Write((string)m_Charte0); + writer.Write((string)m_Charte1); + writer.Write((string)m_Charte2); + writer.Write((string)m_Charte3); + writer.Write((string)m_Charte4); + writer.Write((string)m_Charte5); + writer.Write((string)m_Charte6); + writer.Write((string)m_Charte7); + writer.WriteMobileList( m_Votants, true ); + writer.WriteMobileList( m_Elections, true ); + writer.WriteMobileList( m_Resultats, true ); + writer.Write( m_EndDate ); + writer.Write( m_ElecDelay ); + writer.Write( m_MaxDistance ); + writer.WriteItemList( m_Allies, true ); + writer.WriteItemList( m_Paix, true ); + writer.WriteItemList( m_Guerre, true ); + writer.WriteItemList( m_Neutre, true ); + writer.Write( (TownBox)m_Box); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + m_VilleRace = (VilleRaciale)reader.ReadByte(); + + goto case 0; + } + + case 0: + { + + m_Citoyens = reader.ReadMobileList(); + m_Candidats = reader.ReadMobileList(); + m_HLL = reader.ReadMobileList(); + m_Gardes = reader.ReadMobileList(); + m_gardes_pnj = reader.ReadItemList(); + m_Maire = (PlayerMobile)reader.ReadMobile(); + m_Conseiller = (PlayerMobile)reader.ReadMobile(); + m_Ambassadeur = (PlayerMobile)reader.ReadMobile(); + m_Capitaine = (PlayerMobile)reader.ReadMobile(); + m_Pomi = (POMI)reader.ReadItem(); + m_MaireCloak = (PomiCloak)reader.ReadItem(); + m_ConseillerCloak = (PomiCloak)reader.ReadItem(); + m_AmbassadeurCloak = (PomiCloak)reader.ReadItem(); + m_CapitaineCloak = (PomiCloak)reader.ReadItem(); + m_CapitaineBook = (CapitaineBook)reader.ReadItem(); + m_GardeCloak = reader.ReadItemList(); + m_Nom = reader.ReadString(); + m_Charte0 = reader.ReadString(); + m_Charte1 = reader.ReadString(); + m_Charte2 = reader.ReadString(); + m_Charte3 = reader.ReadString(); + m_Charte4 = reader.ReadString(); + m_Charte5 = reader.ReadString(); + m_Charte6 = reader.ReadString(); + m_Charte7 = reader.ReadString(); + m_Votants = reader.ReadMobileList(); + m_Elections = reader.ReadMobileList(); + m_Resultats = reader.ReadMobileList(); + m_EndDate = reader.ReadDateTime(); + m_ElecTimer = new ElectionTimer(this, m_EndDate - DateTime.Now); + m_ElecTimer.Start(); + m_ElecDelay = reader.ReadTimeSpan(); + m_MaxDistance = reader.ReadInt(); + m_Allies = reader.ReadItemList(); + m_Paix = reader.ReadItemList(); + m_Guerre = reader.ReadItemList(); + m_Neutre = reader.ReadItemList(); + m_Box = (TownBox)reader.ReadItem(); + break; + } + } + + } + + public override void OnDoubleClick( Mobile from ) + { + //if(!m_AdminInUse) + //{ + from.SendGump(new TownGump((PlayerMobile)from,this)); + // m_AdminInUse = true; + // } + //else + // from.SendMessage("Pierre de Ville en cours d'utilisation"); + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + LabelTo(from,"[ {0} ]", m_Nom); + } + } + + public class GestionTarget : Target + { + TownStone m_Town; + int m_ButtonID; + + public GestionTarget(TownStone town, int ButtonID) : base( -1, true, TargetFlags.None ) + { + m_Town = town; + m_ButtonID = ButtonID; + } + protected override void OnTarget( Mobile mobile, object targeted ) + { + if(targeted is PlayerMobile) + { + PlayerMobile target = targeted as PlayerMobile; + if(m_Town.Citoyens.Contains(target)) + switch(m_ButtonID) + { + case 302: //Nomer le Maire + { + if(m_Town.MaireCloak != null) + m_Town.MaireCloak.Delete(); + m_Town.MaireCloak = new PomiCloak(m_Town, "Bourgmestre"); + target.Backpack.DropItem(m_Town.MaireCloak); + m_Town.Maire = target; //initalisation avec le Maire target + target.SendMessage("Vous devenez le Bourgmestre de " + m_Town.Nom); + break; + } + case 303: //Nomer le Conseiller + { + if(m_Town.Maire != target && m_Town.Ambassadeur != target && m_Town.Capitaine != target) + { + if(m_Town.ConseillerCloak != null) + m_Town.ConseillerCloak.Delete(); + m_Town.ConseillerCloak = new PomiCloak(m_Town, "Conseiller"); + target.Backpack.DropItem(m_Town.ConseillerCloak); + m_Town.Conseiller = target; + target.SendMessage("Vous devenez le Conseiller de " + m_Town.Nom); + } + else + mobile.SendMessage("Cette personne a deja un Titre"); + break; + } + case 304: //Nomer l'Ambassadeur + { + if(m_Town.Maire != target && m_Town.Conseiller != target && m_Town.Capitaine != target) + { + if(m_Town.AmbassadeurCloak != null) + m_Town.AmbassadeurCloak.Delete(); + m_Town.AmbassadeurCloak = new PomiCloak(m_Town, "Ambassadeur"); + target.Backpack.DropItem(m_Town.AmbassadeurCloak); + m_Town.Ambassadeur = target; + target.SendMessage("Vous devenez l'Ambassadeur de " + m_Town.Nom); + } + else + mobile.SendMessage("Cette personne a deja un Titre"); + break; + } + case 305: //Nomer le Capitaine + { + if(m_Town.Maire != target && m_Town.Ambassadeur != target && m_Town.Conseiller != target) + { + if(m_Town.CapitaineCloak != null) + m_Town.CapitaineCloak.Delete(); + m_Town.CapitaineCloak = new PomiCloak(m_Town, "Capitaine"); + if(m_Town.CptBook != null) + m_Town.CptBook.Delete(); + m_Town.CptBook = new CapitaineBook(m_Town); + target.Backpack.DropItem(m_Town.CapitaineCloak); + target.Backpack.DropItem(m_Town.CptBook); + m_Town.Capitaine = target; + target.SendMessage("Vous devenez le Capitaine de la Garde de " + m_Town.Nom); + } + else + mobile.SendMessage("Cette personne a deja un Titre"); + break; + } + } + else + mobile.SendMessage("Cette personne n'est pas citoyenne"); + } + } + } + + public class GardeTarget : Target + { + TownStone m_Town; + + public GardeTarget(TownStone town) : base( -1, true, TargetFlags.None ) + { + m_Town = town; + } + protected override void OnTarget( Mobile mobile, object targeted ) + { + if(targeted is PlayerMobile) + { + PlayerMobile target = targeted as PlayerMobile; + if(m_Town.Citoyens.Contains(target)) + { + if(!m_Town.Gardes.Contains(target) && + (m_Town.Maire != target) && + (m_Town.Ambassadeur != target) && + (m_Town.Conseiller != target) && + (m_Town.Capitaine != target)) + { + m_Town.Gardes.Add(target); + PomiCloak cloak = new PomiCloak(m_Town, "Garde"); + m_Town.GardeCloak.Add(cloak); + target.Backpack.DropItem(cloak); + } + else + mobile.SendMessage("Cette personne a deja un titre"); + } + else + mobile.SendMessage("Cette personne n'est pas citoyenne"); + } + } + } + + public class PNJTarget : Target + { + TownStone m_Town; + public PNJTarget(TownStone town) : base( -1, true, TargetFlags.None ) + { + m_Town = town; + } + + protected override void OnTarget( Mobile mobile, object targeted ) + { + IPoint3D target = targeted as IPoint3D; + if(target != null) + { + if( Math.Sqrt( (m_Town.X - target.X)*(m_Town.X - target.X) + (m_Town.Y - target.Y)*(m_Town.Y - target.Y) ) < m_Town.MaxDistance) + { + GuardSpawner guard = new GuardSpawner(new Point3D(target.X, target.Y,target.Z), m_Town); + m_Town.GardesPNJ.Add(guard); + } + else + mobile.SendMessage("C'est trop loin de la pierre de ville"); + } + } + } + + public class ElectionTimer : Timer + { + private TownStone m_Town; + ArrayList LitigeMaire = new ArrayList(); + PlayerMobile NouveauMaire = null; + int nbvoies = 0; + + public ElectionTimer(TownStone town, TimeSpan delay) : base( delay ) + { + //Priority = TimerPriority.OneSecond; + m_Town = town; + } + + protected override void OnTick() + { + int result = 0; + foreach(PlayerMobile mobile in m_Town.Elections) + { + result = CompteVoies(mobile); + if(result > nbvoies) + { + nbvoies = result; + NouveauMaire = mobile; + LitigeMaire.Clear(); + } + else if(result == nbvoies && result != 0) + { + if(!LitigeMaire.Contains(NouveauMaire)) + LitigeMaire.Add(NouveauMaire); + LitigeMaire.Add(mobile); + } + } + if(LitigeMaire.Count>0) + NouveauMaire = (PlayerMobile)LitigeMaire[Utility.Random(LitigeMaire.Count)]; + if(NouveauMaire != null && NouveauMaire != m_Town.Maire) + { + m_Town.NouveauConseil(); + m_Town.Maire = NouveauMaire; + m_Town.MaireCloak = new PomiCloak(m_Town, "Bourgmestre"); + m_Town.Maire.Backpack.DropItem(m_Town.MaireCloak); + } + m_Town.Votants.Clear(); + m_Town.Elections.Clear(); + m_Town.Resultats.Clear(); + m_Town.EndDate = DateTime.Now + m_Town.ElecDelay; + //m_Town.ElecTimer = new ElectionTimer(m_Town, m_Town.ElecDelay); + m_Town.ElecTimer.Start(); + } + + private int CompteVoies(PlayerMobile from) + { + int result = 0; + foreach(PlayerMobile mobile in m_Town.Resultats) + { + if(mobile == from) + result++; + } + return result; + } + } +} diff --git a/Scripts/Vivre/Engines/POMI/POMICommandeAdmin.cs b/Scripts/Vivre/Engines/POMI/POMICommandeAdmin.cs new file mode 100644 index 0000000..6e5df47 --- /dev/null +++ b/Scripts/Vivre/Engines/POMI/POMICommandeAdmin.cs @@ -0,0 +1,155 @@ +using System; +using Server; +using Server.Mobiles; +using Server.Network; +using Server.Gumps; +using Server.IPOMI; +using Server.Targeting; +using System.Collections; + +namespace Server.Commands +{ + + /// + /// ///////////////////////////////////////// EFFACEMENT VILLE CONTENU DANS POMI V1.0 ///////////// M. FREEZE V1.0 + /// + public class EffaceVillePOMI + { + public static void Initialize() + { + CommandSystem.Register( "EffaceVillePOMI", AccessLevel.Administrator, new CommandEventHandler( EffaceVillePOMI_OnCommand ) ); + } + + [Usage( "EffaceVillePOMI " )] + [Description( "Efface une ville contenu dans la pierre POMI par son Index, verifiez avec .Adminpomi" )] + public static void EffaceVillePOMI_OnCommand( CommandEventArgs e ) + { + + string index = e.ArgString.Trim(); + + if ( (index.Length > 0) && (index.Length < 2) ) + { + Mobile from = e.Mobile; + from.SendMessage("Visez une PIERRE POMI"); + from.Target = new EffaceVillePOMITarget(index); + } + else + e.Mobile.SendMessage( "Usage: EffaceVillePOMI " ); + } + } + + public class EffaceVillePOMITarget : Target + { + private string m_index; + private string text; + public EffaceVillePOMITarget(string index) : base( -1, false, TargetFlags.None ) + { + m_index = index; + } + + protected override void OnTarget( Mobile mobile, object targeted ) + { + PlayerMobile from = (PlayerMobile) mobile; + if ( targeted is POMI ) + { + POMI cible = (POMI)targeted; + int test = Utility.ToInt32(m_index); + + Console.WriteLine("test = " + test +" index = "+m_index); + if ( (test >=0) && ( test < (cible.Villes.Count))) + { + //((POMI)targeted).Villes.Remove(test); + cible.Villes.RemoveAt(test); + + } + } + else + from.SendMessage("CECI N'EST PAS UNE PIERRE POMI !"); + + } + } + +/// +/// ///////////////////////////////////////// AFFICHAGE DES VILLES CONTENU DANS POMI //////// M.FREEZE V1.0 +/// + + public class AdminPOMI + { + public static void Initialize() + { + CommandSystem.Register( "AdminPOMI", AccessLevel.Administrator, new CommandEventHandler( AdminPOMI_OnCommand ) ); + } + + [Usage( "AdminPOMI" )] + [Description( "Affiche les villes contenues dans POMI" )] + public static void AdminPOMI_OnCommand( CommandEventArgs e ) + { + Mobile from = e.Mobile; + from.SendMessage("Visez une PIERRE POMI"); + from.Target = new AdminPOMITarget(); + + + } + } + + public class AdminPOMITarget : Target + { + + public AdminPOMITarget( ) : base( -1, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile mobile, object targeted ) + { + PlayerMobile from = (PlayerMobile) mobile; + if ( targeted is POMI ) + { + from.SendGump( new gumpAdminPOMI ( from , (POMI)targeted ) ); + } + else + from.SendMessage("CECI N'EST PAS UNE PIERRE POMI !"); + + } + } +} + +namespace Server.Gumps +{ + public class gumpAdminPOMI : Gump + { + + public gumpAdminPOMI(Mobile from, POMI cible) : base(0,0) + { + Closable = true; + Dragable = true; + int i = 50; + int j = 0; + // POMI Pomicible = (POMI)cible; + AddPage(0); + + AddBackground( 0, 0, 295, 400, 5054); + AddBackground( 15, 15, 265, 370, 3500); + AddLabel( 100, 30, 0, string.Format( "VILLES POMI")); + if (cible.Villes.Count <= 0) + { + from.SendMessage("Il n'y a pas de ville sur cette pierre POMI! [Count = " + cible.Villes.Count +" ]"); + + } + else + { + foreach(TownStone ville in cible.Villes) + { + AddLabel( 30 ,(10+i), 0, (j +"- " +ville.Name) ); + i=i+15; + j++; + } + } + } + + public override void OnResponse( Server.Network.NetState sender, RelayInfo info ) + { + + } + } +} + diff --git a/Scripts/Vivre/Engines/SlayerSystem/SlayerForge.cs b/Scripts/Vivre/Engines/SlayerSystem/SlayerForge.cs new file mode 100644 index 0000000..13235b2 --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SlayerForge.cs @@ -0,0 +1,485 @@ +using System; +using Server; +using System.Collections.Generic; +using Server.Network; +using Server.ContextMenus; +using Server.Targeting; + +using Server.Mobiles; + +namespace Server.Items +{ + public enum SuperSlayerType + { + None, + Repond, + Reptile, + Exorcism, + Elemental, + Fey, + Silver, + Arachnid + } + public class SlayerForge : Item + { + private int[] VialTypes; + private bool m_CanAddRelic; + + private SuperSlayerType m_SuperSlayer; + + + + [CommandProperty(AccessLevel.GameMaster)] + public bool CanAddRelic + { + get { return m_CanAddRelic; } + } + + [CommandProperty(AccessLevel.GameMaster)] + public SuperSlayerType SuperSlayer + { + get { return m_SuperSlayer; } + set { m_SuperSlayer = value; } + } + + [CommandProperty(AccessLevel.Administrator, true)] + public int MaxVials + { + get { return 30; } + } + + [CommandProperty(AccessLevel.GameMaster, true)] + public int CountVial + { + get + { + int total = 0; + for (int i = 0; i < VialTypes.Length; i++) + { + total += VialTypes[i]; + } + return total; + } + } + + [CommandProperty(AccessLevel.GameMaster, true)] + public int CountType + { + get + { + int typecounter = 0; + + for (int i = 0; i < VialTypes.Length; i++) + { + if (VialTypes[i] > 0) + typecounter++; + } + return typecounter; + } + } + + [Constructable] + public SlayerForge() + : base(0x44C7) + { + Name = "Bassin à Slayers"; + VialTypes = new int[Enum.GetValues(typeof(LiquidType)).Length]; + Weight = 50; + EmptyForge(); + } + + public void AddVial(AlchemyVial vial) + { + int index = (int)vial.AlchemyLiquidType; + + if (index >= VialTypes.Length) + return; + + VialTypes[index]++; + } + + public void EmptyForge() + { + for (int i = 0; i < VialTypes.Length; i++) + VialTypes[i] = 0; + + SuperSlayer = SuperSlayerType.None; + } + + public override bool OnDragLift(Mobile from) + { + if (CountVial >= 1) + { + EmptyForge(); + from.SendMessage("Vous videz la forge afin de mieux la transporter"); + } + return base.OnDragLift(from); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + + if (from.Alive && CountVial >= 1) + list.Add(new ContextMenus.SlayerForgeEntry(from, this)); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + if (CountVial == 1) + list.Add("Une fiole y a été versée"); + else if (CountVial > 1) + list.Add("{0} fioles y ont été versées"); + + if (CountType == 1) + list.Add("Liquide pur"); + else if (CountType > 1) + list.Add("Liquide impur"); + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(501816); + return; + } + int VialAmount = CountVial; + + int Elemental = VialTypes[4] + VialTypes[5] + VialTypes[6] + VialTypes[7] + VialTypes[8] + VialTypes[9] + VialTypes[10]; + int Humanoid = VialTypes[1] + VialTypes[2] + VialTypes[3]; + int Arachnid = VialTypes[12] + VialTypes[13] + VialTypes[14]; + int Reptile = VialTypes[15] + VialTypes[16] + VialTypes[17] + VialTypes[18]; + + double FillingPercent = VialAmount / (double)MaxVials; + + if (VialAmount == 0) + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "La forge est vide"); + else if (CountType > 1 && Elemental != VialAmount && Humanoid != VialAmount && Arachnid != VialAmount && Reptile != VialAmount) + { + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "Le mélange ne donnera rien de bon... la forge le détruit"); + EmptyForge(); + } + else if (VialAmount >= MaxVials) + { + if (CountType > 1 && ((Elemental == VialAmount && SuperSlayer != SuperSlayerType.Elemental) || (Humanoid == VialAmount && SuperSlayer != SuperSlayerType.Repond) || (Arachnid == VialAmount && SuperSlayer != SuperSlayerType.Arachnid) || (Reptile == VialAmount && SuperSlayer != SuperSlayerType.Reptile))) + { + m_CanAddRelic = true; + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "Une relique appartenant au souverain sera nécessaire pour achever votre travail"); + } + else if ((VialTypes[21] == VialAmount && SuperSlayer != SuperSlayerType.Exorcism) || (VialTypes[20] == VialAmount && SuperSlayer != SuperSlayerType.Fey) || (VialTypes[19] == VialAmount && SuperSlayer != SuperSlayerType.Silver)) + { + m_CanAddRelic = true; + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "Une relique appartenant au souverain sera nécessaire pour achever votre travail"); + } + else + { + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "La forge est prête à recevoir l'arme"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(WeaponSlayerTarget)); + + } + } + else + { + if (FillingPercent < 0.2) + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "La forge est presque vide"); + else if (FillingPercent >= 0.2 && FillingPercent < 0.5) + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "La forge sera bientôt à moitié vide"); + else if (FillingPercent >= 0.5 && FillingPercent < 0.8) + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "La forge est plus qu'à moitié pleine"); + else + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "La forge est presque pleine"); + } + } + + public SlayerForge(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)2); // version + + writer.Write((int)VialTypes.Length); + + for (int i = 0; i < VialTypes.Length; i++) + writer.Write(VialTypes[i]); + + writer.WriteEncodedInt((int)m_SuperSlayer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + int count = 23; + + if( version > 1) + count = reader.ReadInt(); + + VialTypes = new int[Enum.GetValues(typeof(LiquidType)).Length]; + for (int i = 0; i < count; i++) + VialTypes[i] = reader.ReadInt(); + + m_SuperSlayer = (SuperSlayerType)reader.ReadEncodedInt(); + } + + public void WeaponSlayerTarget(Mobile from, object obj) + { + + if(obj is BaseWeapon) + { + Console.WriteLine("Test"); + BaseWeapon slayertarget = (BaseWeapon)obj; + + if (slayertarget.Slayer2 != SlayerName.None && slayertarget.Slayer != SlayerName.None) + { + from.SendMessage("Cette arme a déjà des slayers, vous ne pouvez en ajouter"); + return; + } + Console.WriteLine("Test1"); + + double skillmin = Math.Min(from.Skills[SkillName.ArmsLore].Value, from.Skills[SkillName.Blacksmith].Value) + 1; + + double malus = slayertarget.WeaponDifficulty; + + double bonus = 0; + double superbonus = 1; + if (slayertarget.Crafter != null && slayertarget.Crafter.Serial == from.Serial) + superbonus = 2; + Console.WriteLine("Test1"); + if (from.Skills[SkillName.Alchemy].Value > 80) + bonus += 5; + if (from.Skills[SkillName.ItemID].Value > 80) + bonus += 5; + + foreach (Mobile m in from.GetMobilesInRange(1)) + { + PlayerMobile pm = m as PlayerMobile; + if (pm == null || pm == from) continue; + if (pm.AccessLevel > AccessLevel.Player) continue; // Scriptiz : évitons qu'un GM observant le procédé soit une aide + if (pm.Hidden) continue; // Scriptiz : si le PJ est caché il sert à rien + if (!pm.Alive) continue; // Scriptiz : un PJ mort ne sert à rien non plus + + int checkBonus = 0; + if (pm.Skills[SkillName.Alchemy].Value > 80) + checkBonus += 1; + if (pm.Skills[SkillName.Blacksmith].Value > 80) + checkBonus += 1; + if (pm.Skills[SkillName.ArmsLore].Value > 80) + checkBonus += 1; + if (pm.Skills[SkillName.ItemID].Value > 80) + checkBonus += 1; + + if (checkBonus > 1) + bonus += 5; + + if (slayertarget.Crafter != null && slayertarget.Crafter.Serial == pm.Serial) + superbonus = 1.5; + + if (slayertarget.Resource == CraftResource.MGlowing && VialTypes[19] > 0) + superbonus += 1; + } + + if (bonus > 25) + bonus = 25; + + if (slayertarget.PlayerConstructed) + bonus *=2; + + if (CountType > 1 || VialTypes[21] == CountVial || VialTypes[20] == CountVial || VialTypes[19] == CountVial) + malus *= 2; + + if (slayertarget.Slayer != SlayerName.None) + malus *= 2; + + double chances = Math.Round(((skillmin + bonus) / malus * superbonus),2); + if (chances >= 90) + chances = 100 - malus; + + if (chances < Utility.Random(100)) + { + from.SendMessage("Vous appliquez le slayer sur l'arme."); + if (slayertarget.Slayer == SlayerName.None) + slayertarget.Slayer = AddSlayer(); + else + slayertarget.Slayer2 = AddSlayer(); + } + else if (Utility.Random(100) <= malus*2) + { + from.SendMessage("Vous échouez. Le slayer ronge lentement l'arme, tout est perdu."); + slayertarget.Delete(); + } + else + from.SendMessage("Vous échouez, mais parvenez à conserver l'arme."); + + EmptyForge(); + return; + } + else if (obj is Spellbook) + { + Spellbook slayertarget = (Spellbook)obj; + + if (slayertarget.SpellbookType != SpellbookType.Regular ) + { + from.SendMessage("Seul les livres arcaniques peuvent accepter un slayer"); + return; + } + + if (slayertarget.Slayer2 != SlayerName.None && slayertarget.Slayer != SlayerName.None) + { + from.SendMessage("Ce livre a déjà des slayers, vous ne pouvez en ajouter"); + return; + } + + double skillmin = (Math.Min(from.Skills[SkillName.EvalInt].Value, from.Skills[SkillName.Inscribe].Value) + 1); + + double malus = (65 - slayertarget.SpellCount); + + + double bonus = 0; + double superbonus = 1; + if (slayertarget.Crafter != null && slayertarget.Crafter.Serial == from.Serial) + superbonus = 1.8; + + if (from.Skills[SkillName.Alchemy].Value > 80) + bonus += 4; + if (from.Skills[SkillName.ItemID].Value > 80) + bonus += 4; + + foreach (Mobile m in from.GetMobilesInRange(1)) + { + PlayerMobile pm = m as PlayerMobile; + if (pm == null || pm == from) continue; + if (pm.AccessLevel > AccessLevel.Player) continue; // Scriptiz : évitons qu'un GM observant le procédé soit une aide + if (pm.Hidden) continue; // Scriptiz : si le PJ est caché il sert à rien + if (!pm.Alive) continue; // Scriptiz : un PJ mort ne sert à rien non plus + + int checkBonus = 0; + if (pm.Skills[SkillName.Alchemy].Value > 80) + checkBonus += 1; + if (pm.Skills[SkillName.Magery].Value > 80) + checkBonus += 1; + if (pm.Skills[SkillName.EvalInt].Value > 80) + checkBonus += 1; + if (pm.Skills[SkillName.ItemID].Value > 80) + checkBonus += 1; + + if (checkBonus > 2) + bonus += 5; + + if (slayertarget.Crafter != null && slayertarget.Crafter.Serial == pm.Serial) + superbonus = 1.4; + + } + + if (bonus > 25) + bonus = 25; + + if (CountType > 1 || VialTypes[21] == CountVial || VialTypes[20] == CountVial || VialTypes[19] == CountVial) + malus *= 2; + + if (slayertarget.Slayer != SlayerName.None) + malus *= 2; + + double chances = Math.Round(((skillmin + bonus) / Math.Sqrt(malus) * superbonus), 2); + if (chances >= 90) + chances = 90 - malus; + + if (chances < Utility.Random(100)) + { + from.SendMessage("Vous appliquez le slayer sur le livre."); + if (slayertarget.Slayer == SlayerName.None) + slayertarget.Slayer = AddSlayer(); + else + slayertarget.Slayer2 = AddSlayer(); + } + else if (Utility.Random(100) <= malus * 2) + { + from.SendMessage("Vous échouez. Le slayer ronge lentement le livre, tout est perdu."); + slayertarget.Delete(); + } + else + from.SendMessage("Vous échouez, mais parvenez à conserver le livre."); + + EmptyForge(); + return; + } + else + { + from.SendMessage("Ceci n'est pas un livre de sorts ou une arme"); + } + + } + + + public SlayerName AddSlayer() + { + if (CountType == 1) + { + if (VialTypes[1] != 0) + return SlayerName.OgreTrashing; + if (VialTypes[2] != 0) + return SlayerName.OrcSlaying; + if (VialTypes[3] != 0) + return SlayerName.TrollSlaughter; + if (VialTypes[4] != 0) + return SlayerName.BloodDrinking; + if (VialTypes[5] != 0) + return SlayerName.EarthShatter; + if (VialTypes[6] != 0) + return SlayerName.ElementalHealth; + if (VialTypes[7] != 0) + return SlayerName.FlameDousing; + if (VialTypes[8] != 0) + return SlayerName.SummerWind; + if (VialTypes[9] != 0) + return SlayerName.Vacuum; + if (VialTypes[10] != 0) + return SlayerName.WaterDissipation; + if (VialTypes[11] != 0) + return SlayerName.GargoylesFoe; + if (VialTypes[12] != 0) + return SlayerName.ScorpionsBane; + if (VialTypes[13] != 0) + return SlayerName.SpidersDeath; + if (VialTypes[14] != 0) + return SlayerName.Terathan; + if (VialTypes[15] != 0) + return SlayerName.LizardmanSlaughter; + if (VialTypes[16] != 0) + return SlayerName.DragonSlaying; + if (VialTypes[17] != 0) + return SlayerName.Ophidian; + if (VialTypes[18] != 0) + return SlayerName.SnakesBane; + if (VialTypes[19] != 0) + return SlayerName.Silver; + if (VialTypes[20] != 0) + return SlayerName.Fey; + if (VialTypes[21] != 0) + return SlayerName.Exorcism; + } + if (CountType > 1) + { + if ((VialTypes[4] + VialTypes[5] + VialTypes[6] + VialTypes[7] + VialTypes[8] + VialTypes[9] + VialTypes[10]) == MaxVials) + return SlayerName.ElementalBan; + if ((VialTypes[1] + VialTypes[2] + VialTypes[3]) == MaxVials) + return SlayerName.Repond; + if ((VialTypes[15] + VialTypes[16] + VialTypes[17] + VialTypes[18]) == MaxVials) + return SlayerName.ReptilianDeath; + if ((VialTypes[12] + VialTypes[13] + VialTypes[14]) == MaxVials) + return SlayerName.ArachnidDoom; + } + return SlayerName.None; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/SlayerSystem/SlayerForgeEntry.cs b/Scripts/Vivre/Engines/SlayerSystem/SlayerForgeEntry.cs new file mode 100644 index 0000000..a7143ba --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SlayerForgeEntry.cs @@ -0,0 +1,24 @@ +using System; +using Server.Items; + +namespace Server.ContextMenus +{ + public class SlayerForgeEntry : ContextMenuEntry + { + private Mobile m_From; + private SlayerForge m_Forge; + + public SlayerForgeEntry(Mobile from, SlayerForge SlayerForge) + : base(5043, 1) + { + m_From = from; + m_Forge = SlayerForge; + } + + public override void OnClick() + { + m_Forge.EmptyForge(); + m_From.SendMessage("Vous videz le contenu de la forge, annulant tous vos efforts"); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ArachnidRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ArachnidRelic.cs new file mode 100644 index 0000000..1ea6d59 --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ArachnidRelic.cs @@ -0,0 +1,62 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class ArachnidRelic : Item + { + [Constructable] + public ArachnidRelic() + : base(0x5720) + { + Name = "Une carapace d'araignée"; + Weight = 2.0; + } + + public ArachnidRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Arachnid; + this.Delete(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/DemonRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/DemonRelic.cs new file mode 100644 index 0000000..218e5f8 --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/DemonRelic.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class DemonRelic : Item + { + [Constructable] + public DemonRelic() + : base(0x5721) + { + Name = "Une serre de démon"; + Weight = 2.0; + } + + public DemonRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + if (!(forge.CanAddRelic)) + { + from.SendMessage("Cette forge ne peut accepter de relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Exorcism; + this.Delete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ElementalRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ElementalRelic.cs new file mode 100644 index 0000000..09aa71a --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ElementalRelic.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class ElementalRelic : Item + { + [Constructable] + public ElementalRelic() + : base(0x5738) + { + Name = "Des éclats d'élémental"; + Weight = 2.0; + } + + public ElementalRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + if (!(forge.CanAddRelic)) + { + from.SendMessage("Cette forge ne peut accepter de relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Elemental; + this.Delete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/FeyRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/FeyRelic.cs new file mode 100644 index 0000000..e50deaa --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/FeyRelic.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class FeyRelic : Item + { + [Constructable] + public FeyRelic() + : base(0x5726) + { + Name = "Des ailes de fée"; + Weight = 2.0; + } + + public FeyRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + if (!(forge.CanAddRelic)) + { + from.SendMessage("Cette forge ne peut accepter de relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Fey; + this.Delete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/RepondRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/RepondRelic.cs new file mode 100644 index 0000000..a2d99ec --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/RepondRelic.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class RepondRelic : Item + { + [Constructable] + public RepondRelic() + : base(0x5746) + { + Name = "Une langue de géant"; + Weight = 2.0; + } + + public RepondRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + if (!(forge.CanAddRelic)) + { + from.SendMessage("Cette forge ne peut accepter de relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Repond; + this.Delete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ReptileRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ReptileRelic.cs new file mode 100644 index 0000000..ee80afb --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/ReptileRelic.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class ReptiledRelic : Item + { + [Constructable] + public ReptiledRelic() + : base(0x5744) + { + Name = "Une mue de serpent"; + Weight = 2.0; + } + + public ReptiledRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + if (!(forge.CanAddRelic)) + { + from.SendMessage("Cette forge ne peut accepter de relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Reptile; + this.Delete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/UndeadRelic.cs b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/UndeadRelic.cs new file mode 100644 index 0000000..df6b205 --- /dev/null +++ b/Scripts/Vivre/Engines/SlayerSystem/SuperSlayerRelic/UndeadRelic.cs @@ -0,0 +1,67 @@ +using System; +using Server; +using Server.Items; +using Server.Targeting; + +namespace Server.Items +{ + public class UndeadRelic : Item + { + [Constructable] + public UndeadRelic() + : base(0x5731) + { + Name = "De la chair putréfiée"; + Weight = 2.0; + } + + public UndeadRelic(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Dans quelle forge voulez-vous la jeter?"); + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(DropTarget)); + } + + public void DropTarget(Mobile from, object obj) + { + if(!(obj is SlayerForge)) + { + from.SendMessage("Ceci n'est pas une forge adéquate"); + return; + } + + SlayerForge forge = (SlayerForge)obj; + + if(forge.SuperSlayer != SuperSlayerType.None) + { + from.SendMessage("Cette forge contient déjà une relique"); + return; + } + + if (!(forge.CanAddRelic)) + { + from.SendMessage("Cette forge ne peut accepter de relique"); + return; + } + + from.SendMessage("Vous jetez la relique dans la forge"); + forge.SuperSlayer = SuperSlayerType.Silver; + this.Delete(); + } + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Engines/SphereImport/LowerSkillsGump.cs b/Scripts/Vivre/Engines/SphereImport/LowerSkillsGump.cs new file mode 100644 index 0000000..aa92603 --- /dev/null +++ b/Scripts/Vivre/Engines/SphereImport/LowerSkillsGump.cs @@ -0,0 +1,134 @@ +/*************************************************************************** + * LowerSkillsGump.cs + * ----------------------------- + * begin : May 25, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-06-25 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Accounting; +using Server.Engines.VeteranRewards; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class LowerSkillGump : Gump + { + public static void Initialize() + { + EventSink.Login += new LoginEventHandler(EventSink_Login); + } + + public static void EventSink_Login(LoginEventArgs e) + { + if (e.Mobile.SkillsTotal > e.Mobile.SkillsCap && e.Mobile.AccessLevel == AccessLevel.Player) + { + e.Mobile.SendGump(new LowerSkillGump(e.Mobile)); + } + } + + public LowerSkillGump(Mobile from) + : base(25, 50) + { + this.Closable = false; + this.Dragable = false; + + AddPage(0); + + AddBackground(0, 0, 520, 440, 0x13BE); + + AddImageTiled(10, 10, 500, 20, 0xA40); + AddImageTiled(10, 40, 500, 360, 0xA40); + AddImageTiled(10, 410, 500, 20, 0xA40); + + AddAlphaRegion(10, 10, 500, 420); + + AddHtml(10, 12, 500, 20, "Quelle skill voulez-vous descendre pour respecter votre skills cap?", false, false); + + AddHtml(10, 412, 500, 20, "Skills total : " + (from.SkillsTotal / 10) + " / " + (from.SkillsCap / 10), false, false); + + for (int i = 0, n = 0; i < from.Skills.Length; i++) + { + Skill skill = from.Skills[i]; + + if (skill.Base > 0.0) + { + int p = n % 30; + + if (p == 0) + { + int page = n / 30; + + if (page > 0) + { + AddButton(260, 380, 0xFA5, 0xFA6, 0, GumpButtonType.Page, page + 1); + AddHtmlLocalized(305, 382, 200, 20, 1011066, 0x7FFF, false, false); // Next page + } + + AddPage(page + 1); + + if (page > 0) + { + AddButton(10, 380, 0xFAE, 0xFAF, 0, GumpButtonType.Page, page); + AddHtmlLocalized(55, 382, 200, 20, 1011067, 0x7FFF, false, false); // Previous page + } + } + + int x = (p % 2 == 0) ? 10 : 260; + int y = (p / 2) * 20 + 40; + + AddButton(x, y, 0xFA5, 0xFA6, i + 1, GumpButtonType.Reply, 0); + AddHtmlLocalized(x + 45, y + 2, 200, 20, 1044060 + i, 0x7FFF, false, false); + AddHtml(x + 220, y + 2, 25, 20, "" + from.Skills[i].Base, false, false); + + n++; + } + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + int iSkill = info.ButtonID - 1; + if (iSkill < 0 || iSkill >= from.Skills.Length) + { + from.SendMessage("Petit malin va ! Il te faut descendre tes skills !"); + from.SendGump(new LowerSkillGump(from)); + return; + } + + Skill skill = from.Skills[iSkill]; + if (skill.Base <= 0.0) + { + from.SendGump(new LowerSkillGump(from)); + return; + } + + skill.Base -= 10; + + if (from.SkillsTotal > from.SkillsCap) + from.SendGump(new LowerSkillGump(from)); + else + { + from.SendMessage("Vos skills sont en ordre. Bon jeu !"); + from.CloseGump(typeof(LowerSkillGump)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/SphereImport/LowerStatsGump.cs b/Scripts/Vivre/Engines/SphereImport/LowerStatsGump.cs new file mode 100644 index 0000000..ecd1d65 --- /dev/null +++ b/Scripts/Vivre/Engines/SphereImport/LowerStatsGump.cs @@ -0,0 +1,116 @@ +/*************************************************************************** + * LowerStatsGump.cs + * ----------------------------- + * begin : July 5, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-07-06 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using Server; +using Server.Gumps; +using Server.Network; +using Server.Accounting; +using Server.Engines.VeteranRewards; +using Server.Multis; +using Server.Mobiles; + +namespace Server.Gumps +{ + public class LowerStatsGump : Gump + { + public static void Initialize() + { + EventSink.Login += new LoginEventHandler(EventSink_Login); + } + + public static void EventSink_Login(LoginEventArgs e) + { + if (e.Mobile.RawStatTotal > e.Mobile.StatCap && e.Mobile.AccessLevel == AccessLevel.Player) + { + e.Mobile.SendGump(new LowerStatsGump(e.Mobile)); + } + } + + public LowerStatsGump(Mobile from) + : base(550, 50) + { + this.Closable = false; + this.Dragable = false; + + AddPage(0); + + AddBackground(0, 0, 260, 240, 0x13BE); + + AddImageTiled(10, 10, 240, 40, 0xA40); // top region + AddImageTiled(10, 60, 240, 140, 0xA40); + AddImageTiled(10, 210, 240, 20, 0xA40); + + AddAlphaRegion(10, 10, 240, 220); + + AddHtml(10, 12, 500, 20, "Quelle stat voulez-vous descendre", false, false); + AddHtml(10, 32, 500, 20, "pour respecter votre stats cap?", false, false); + + AddHtml(10, 212, 500, 20, "Stats total : " + from.RawStatTotal + " / " + from.StatCap, false, false); + + int x = 10, y = 60, i = 1; + AddButton(x, y, 0xFA5, 0xFA6, i, GumpButtonType.Reply, 0); + AddHtml(x + 45, y + 2, 200, 20, "Strength", false, false); + AddHtml(x + 220, y + 2, 25, 20, "" + from.Str, false, false); + + y += 20; i++; + AddButton(x, y, 0xFA5, 0xFA6, i, GumpButtonType.Reply, 0); + AddHtml(x + 45, y + 2, 200, 20, "Dexterity", false, false); + AddHtml(x + 220, y + 2, 25, 20, "" + from.Dex, false, false); + + y += 20; i++; + AddButton(x, y, 0xFA5, 0xFA6, i, GumpButtonType.Reply, 0); + AddHtml(x + 45, y + 2, 200, 20, "Intelligence", false, false); + AddHtml(x + 220, y + 2, 25, 20, "" + from.Int, false, false); + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + int iStat = info.ButtonID; + if (iStat < 1 || iStat > 3) + { + from.SendMessage("Petit malin va ! Il te faut descendre tes skills !"); + from.SendGump(new LowerSkillGump(from)); + return; + } + + switch (iStat) + { + case 1: + from.Str -= 5; + break; + case 2 : + from.Dex -= 5; + break; + case 3: + from.Int -= 5; + break; + } + + if (from.RawStatTotal > from.StatCap) + from.SendGump(new LowerStatsGump(from)); + else + { + from.SendMessage("Vos stats sont en ordre. Bon jeu !"); + from.CloseGump(typeof(LowerStatsGump)); + } + } + } +} diff --git a/Scripts/Vivre/Engines/SphereImport/SphereAccountsImporter.cs b/Scripts/Vivre/Engines/SphereImport/SphereAccountsImporter.cs new file mode 100644 index 0000000..0b757cb --- /dev/null +++ b/Scripts/Vivre/Engines/SphereImport/SphereAccountsImporter.cs @@ -0,0 +1,107 @@ +/*************************************************************************** + * SphereAccountsImporter.cs + * ------------------------- + * begin : May 25, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-06-25 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using Server.Accounting; +using Server.Misc; + +namespace Server.Commands +{ + public class AccountImporter + { + public static void Initialize() + { + CommandSystem.Register("importSphereAccounts", AccessLevel.Owner, new CommandEventHandler(ImportSphereAccounts_OnCommand)); + } + + [Usage("importSphereAccounts")] + [Description("Importe les comptes du fichier de sauvegarde sphere")] + private static void ImportSphereAccounts_OnCommand(CommandEventArgs e) + { + // Vérification de l'existence des fichiers nécessaires + if (!SphereFiles.checkSourceFiles()) return; + if (!SphereFiles.checkDataFiles()) return; + + // On lit tout le fichier des comptes + int count = 0; + Dictionary accountData = null; + foreach (string line in File.ReadAllLines(SphereFiles.accountFile)) + { + // Si la ligne définit un nouvel enregistrement + if(line.StartsWith("[")) + { + // et que l'on avait déjà des données d'un compte, on l'ajoute + if (accountData != null) + { + // On essaye d'importer le compte avec les données récupérée + if(ImportAccount(accountData)) + count++; + } + + // Ensuite on réinitialise les données du compte et on enregistre le LOGIN du nouveau compte + accountData = new Dictionary(); + accountData.Add("LOGIN", line.Substring(1, line.Length - 2)); + } + + // Si la ligne n'est pas vide et contient un = + if (line.Trim() != "" && line.Contains("=")) + { + // On coupe la ligne en deux au niveau du = + string[] split = line.Split('='); + try + { + // On ajoute les données récupérées au données du compte + accountData.Add(split[0], split[1]); + } + catch //(ArgumentException ae) + { + } + } + } + World.Save(); // On fait une save pour sauvegarder les comptes importés + e.Mobile.SendMessage(count + " accounts imported."); + } + + private static bool ImportAccount(Dictionary accountData) + { + try + { + // On vérifie s'il y a déjà un compte qui existe avec ce login, si oui on ne fait rien + IAccount account = Accounts.GetAccount(accountData["LOGIN"]); + if (account != null) return false; + + // On vérifie que le joueur n'ait pas de plevel pour ne pas importer les comptes GM et autres + string plevel = null; + accountData.TryGetValue("PLEVEL", out plevel); + if (plevel != null) return false; + + // On crée un nouveau compte et on l'ajoute à la liste des comtes + IAccount newAccount = new Account(accountData["LOGIN"], accountData["PASSWORD"]); + Accounts.Add(newAccount); + } + catch //(KeyNotFoundException knfe) + { + // S'il manque des informations comme le login ou le password on n'importe pas le compte + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/SphereImport/SphereFiles.cs b/Scripts/Vivre/Engines/SphereImport/SphereFiles.cs new file mode 100644 index 0000000..2c69030 --- /dev/null +++ b/Scripts/Vivre/Engines/SphereImport/SphereFiles.cs @@ -0,0 +1,114 @@ +/*************************************************************************** + * SphereFiles.cs + * ----------------------------- + * begin : July 6, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-07-06 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using Server; +using System.IO; +using System.Collections.Generic; + +namespace Server.Misc +{ + class SphereFiles + { + // Source + public static string sphereDir = @"Data\Sphere"; + public static string accountFile = @"Data\Sphere\sphereaccu.scp"; + public static string saveFile = @"Data\Sphere\spherechars.scp"; + + // Generated + public static string playerFile = @"Data\Sphere\sphereplayers.scp"; + public static string hairFile = @"Data\Sphere\spherehair.scp"; + public static string goldFile = @"Data\Sphere\spheregold.scp"; + public static string backFile = @"Data\Sphere\spherebackpack.scp"; + public static string bankFile = @"Data\Sphere\spherebankbox.scp"; + + public static bool checkSourceFiles() + { + string missing = null; + if (!Directory.Exists(sphereDir)) missing = sphereDir; + else if (!File.Exists(accountFile)) missing = accountFile; + else if (!File.Exists(saveFile)) missing = saveFile; + + if (missing != null) Console.WriteLine("[SphereFiles] This file is missing : " + missing); + return missing == null; + } + + public static bool checkDataFiles() + { + string missing = null; + + if (!checkSourceFiles()) return false; + + if (!File.Exists(hairFile)) missing = hairFile; + else if (!File.Exists(goldFile)) missing = goldFile; + else if (!File.Exists(backFile)) missing = backFile; + else if (!File.Exists(bankFile)) missing = bankFile; + + if (missing != null) + { + if (cutSaveFile()) return true; + Console.WriteLine("[SphereFiles] This file is missing : " + missing); + } + + return missing == null; + } + + public static bool cutSaveFile() + { + if (!checkSourceFiles()) return false; + + List hairTypes = new List(); + + StreamWriter srPlayer = new StreamWriter(playerFile); + StreamWriter srHair = new StreamWriter(hairFile); + StreamWriter srGold = new StreamWriter(goldFile); + StreamWriter srBack = new StreamWriter(backFile); + StreamWriter srBank = new StreamWriter(bankFile); + + bool isPlayer = false, isHair = false, isGold = false, isBack = false, isBank = false; + + foreach (string line in File.ReadAllLines(saveFile)) + { + if (line.StartsWith("[")) + { + isPlayer = isHair = isGold = isBack = isBank = false; + } + + if (line.StartsWith("[WORLDCHAR c_")) isPlayer = true; + else if (line.StartsWith("[WORLDITEM i_hair_") || line.StartsWith("[WORLDITEM i_beard_")) isHair = true; + else if (line.StartsWith("[WORLDITEM i_gold]")) isGold = true; + else if (line.StartsWith("[WORLDITEM i_backpack]")) isBack = true; + else if (line.StartsWith("[WORLDITEM i_bankbox]")) isBank = true; + + if (isPlayer) srPlayer.WriteLine(line); + else if (isHair) srHair.WriteLine(line); + else if (isGold) srGold.WriteLine(line); + else if (isBack) srBack.WriteLine(line); + else if (isBank) srBank.WriteLine(line); + } + + srPlayer.Close(); + srHair.Close(); + srGold.Close(); + srBack.Close(); + srBank.Close(); + + return true; + } + } +} diff --git a/Scripts/Vivre/Engines/SphereImport/SpherePlayerMobileImporter.cs b/Scripts/Vivre/Engines/SphereImport/SpherePlayerMobileImporter.cs new file mode 100644 index 0000000..22993d7 --- /dev/null +++ b/Scripts/Vivre/Engines/SphereImport/SpherePlayerMobileImporter.cs @@ -0,0 +1,548 @@ +/*************************************************************************** + * SpherePlayerMobileImporter.cs + * ----------------------------- + * begin : June 25, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-06-25 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using System.IO; +using Server.Accounting; +using Server.Mobiles; +using Server.Items; +using System.Globalization; + +namespace Server.Misc +{ + class SpherePlayerMobileImporter + { + public static void Initialize() + { + // Appelons l'import lors de la connexion du joueur (avant la liste des persos disponibles) + EventSink.AccountLogin += new AccountLoginEventHandler(EventSink_AccountLogin); + } + + public static void EventSink_AccountLogin(AccountLoginEventArgs e) + { + try + { + IAccount a = Accounts.GetAccount(e.Username); + if (a == null) return; // si pas de compte (bug xD) on sort + + Account acc = a as Account; + if (a == null || a.Count > 0) return; // Si cast en compte est null ou s'il y a déjà des joueurs pour ce compte, on n'importe pas les joueurs de la save sphere + else if (acc != null && acc.Comments != null && acc.Comments.Count > 0) return; // pareil s'il y a déjà un commentaire sur le compte + //else if (acc != null && acc.TotalGameTime > TimeSpan.FromMinutes(15)) return; + + // Vérifions que les fichiers nécessaires existent bien + if (!SphereFiles.checkDataFiles()) return; + + // Commencons par récupérer les SERIAL des personnages associés au compte + List charUIDs = new List(); + int totalTime = 0; // on récupère le temps en sec joué par le joueurs sur sphere + bool found = false; + string username = e.Username.ToLower(); + foreach (string line in File.ReadAllLines(SphereFiles.accountFile)) + { + // On cherche d'abord à retrouver l'utilisateur + if (line.ToLower() == "[" + username + "]") + { + found = true; + continue; + } + + // Ensuite une fois qu'on l'a trouvé on ajout les SERIAL de ses personnages + // jusqu'à tombé sur un autre compte (ou la fin du fichier) + if (found) + { + if (line.StartsWith("[")) break; + + if (line.StartsWith("TOTALCONNECTTIME=")) + totalTime = Int32.Parse(line.Split('=')[1]); + + if (line.StartsWith("CHARUID")) + charUIDs.Add(line.Split('=')[1]); + } + } + + // On traite chacun des SERIAL des personnages des joueurs + foreach (string c in charUIDs) + { + Mobile pm = null; // Le mobile qui sera créé + found = false; // on remet found à false car on ne l'a pas encore trouvé + bool woman = false; // dans le cas on on serait sur une femme il faut s'en souvenir + bool hasHouse = false; + + // On parcourt toutes les lignes du fichier contenant les personnages + foreach (string line in File.ReadAllLines(SphereFiles.playerFile)) + { + // Si l'on recontre une femme on s'en souvient pour lui mettre des seins ! + if (line.StartsWith("[WORLDCHAR")) + woman = line.Contains("woman"); + + // Si l'on tombe sur le SERIAL du joueur que l'on cherche on peut passer au traitement + if (line.StartsWith("SERIAL=")) + { + if (line.Split('=')[1] == c) + { + found = true; + continue; + } + } + + // On est sur le bon joueur, il faut en extraire les informations + if (found) + { + // Si le Mobile est encore null on l'instancie et on l'initialise + if (pm == null) + { + pm = new PlayerMobile(); + pm.Player = true; // !!! nécessaire pour lire le paperdoll + pm.AccessLevel = AccessLevel.Player; + pm.Map = Map.Internal; // pour que le joueur soit déconnecté + pm.LogoutLocation = new Point3D(3503, 2574, 14); // endroit de départ des joueurs + pm.LogoutMap = Map.Trammel; // map de départ des joueurs + pm.BodyValue = (woman ? 401 : 400); + pm.Female = woman; + pm.SkillsCap = 7000; // skill cap de 700 + pm.StatCap = 225; // stat cap de 225 + + // Ajoutons un backpack au joueur pour qu'il puisse y ranger ses affaires + Container pack = pm.Backpack; + if (pack == null) + { + pack = new Backpack(); + pack.Movable = false; + pm.AddItem(pack); + } + + // Une cape pour les vétérans ! + pm.Backpack.DropItem(new VeteranCloak()); + } + + // Si l'on arrive sur un autre joueur on ajoute l'actuel et on continue de chercher + // les éventuels autres joueurs du compte + if (line.StartsWith("[")) + { + // Effectuons quelques petits trucs avant d'ajouter le joueur sur le compte + getHair(c, pm); // on récupère et on remet les cheveux du joueur + getGold(c, pm); // on récupère l'or du joueur + dressPlayer(pm); // on habille le joueur + + // On remet au joueur un cheque s'il avait une maison + if (hasHouse) + { + Container bank = pm.BankBox; + if (bank != null) + { + BankCheck check = new BankCheck(50000); + check.Name = "Rémunération Maison"; + bank.DropItem(check); + } + } + hasHouse = false; + + // On remet de l'argent au joueur en fonction du temps joué sur Sphere + if (totalTime > 0) + { + Container bank = pm.BankBox; + if (bank != null) + { + BankCheck check = new BankCheck((int)(totalTime / (charUIDs.Count * 1.0))); + check.Name = "Temps joué"; + bank.DropItem(check); + } + } + + // Et maintenant on ajoute le joueur au compte à la première place libre + for (int i = 0; i < a.Length; ++i) + { + if (a[i] == null) + { + a[i] = pm; + break; + } + } + pm = null; + break; + } + + #region Traitement des différentes propriétés à importer + // Nom + if (line.StartsWith("NAME=")) + pm.Name = line.Split('=')[1]; + // Body Hue + else if (line.StartsWith("COLOR=")) + pm.Hue = Int32.Parse(line.Split('=')[1], NumberStyles.HexNumber); + // Body Hue si corps différent + else if (pm.Hue == 0 && line.StartsWith("OSKIN=")) + pm.Hue = Int32.Parse(line.Split('=')[1], NumberStyles.HexNumber); + // Description paperdoll + else if (line.StartsWith("PROFILE=")) + pm.Profile = line.Split('=')[1].Replace("\\r", "\r"); + // Force + else if (line.StartsWith("STR=")) + pm.Str = Int32.Parse(line.Split('=')[1]); + // Int + else if (line.StartsWith("INT=")) + pm.Int = Int32.Parse(line.Split('=')[1]); + // Dex + else if (line.StartsWith("DEX=")) + pm.Dex = Int32.Parse(line.Split('=')[1]); + // Karma + else if (line.StartsWith("KARMA=")) + pm.Karma = Int32.Parse(line.Split('=')[1]); + // Fame + else if (line.StartsWith("FAME=")) + pm.Fame = Int32.Parse(line.Split('=')[1]); + // Female + else if (line.StartsWith("FAME=")) + pm.Fame = Int32.Parse(line.Split('=')[1]); + // Titre RP + else if (line.StartsWith("TITLE=")) + pm.Title = line.Split('=')[1]; + // Pour la rémunération de la maison + else if (line.StartsWith("HOME=")) + hasHouse = true; + /* Position X,Y,Z + else if (line.StartsWith("P=")) + { + string[] location = line.Split('=')[1].Split(','); + pm.Location = new Point3D(Int32.Parse(location[0]), Int32.Parse(location[1]), Int32.Parse(location[2])); + } + */ + // Alchemy + else if (line.StartsWith("Alchemy=")) + pm.Skills[SkillName.Alchemy].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Anatomy + else if (line.StartsWith("Anatomy=")) + pm.Skills[SkillName.Anatomy].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Animal Lore + else if (line.StartsWith("AnimalLore=")) + pm.Skills[SkillName.AnimalLore].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Archery + else if (line.StartsWith("Archery=")) + pm.Skills[SkillName.Archery].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Arms Lore + else if (line.StartsWith("ArmsLore=")) + pm.Skills[SkillName.ArmsLore].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Begging + else if (line.StartsWith("Begging=")) + pm.Skills[SkillName.Begging].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Blacksmithing + else if (line.StartsWith("Blacksmithing=")) + pm.Skills[SkillName.Blacksmith].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Bowcraft + else if (line.StartsWith("Bowcraft=")) + pm.Skills[SkillName.Fletching].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Camping + else if (line.StartsWith("Camping=")) + pm.Skills[SkillName.Camping].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Carpentry + else if (line.StartsWith("Carpentry=")) + pm.Skills[SkillName.Carpentry].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Cartography + else if (line.StartsWith("Cartography=")) + pm.Skills[SkillName.Cartography].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Cooking + else if (line.StartsWith("Cooking=")) + pm.Skills[SkillName.Cooking].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //DetectingHidden + else if (line.StartsWith("DetectingHidden=")) + pm.Skills[SkillName.DetectHidden].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Enticement + else if (line.StartsWith("Enticement=")) + pm.Skills[SkillName.Discordance].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //EvaluatingIntel + else if (line.StartsWith("EvaluatingIntel=")) + pm.Skills[SkillName.EvalInt].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Fencing + else if (line.StartsWith("Fencing=")) + pm.Skills[SkillName.Fencing].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Fishing + else if (line.StartsWith("Fishing=")) + pm.Skills[SkillName.Fishing].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Forensics + else if (line.StartsWith("Forensics=")) + pm.Skills[SkillName.Forensics].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Healing + else if (line.StartsWith("Healing=")) + pm.Skills[SkillName.Healing].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Herding + else if (line.StartsWith("Herding=")) + pm.Skills[SkillName.Herding].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Hiding + else if (line.StartsWith("Hiding=")) + pm.Skills[SkillName.Hiding].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Inscription + else if (line.StartsWith("Inscription=")) + pm.Skills[SkillName.Inscribe].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //ItemID + else if (line.StartsWith("ItemID=")) + pm.Skills[SkillName.ItemID].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //LockPicking + else if (line.StartsWith("LockPicking=")) + pm.Skills[SkillName.Lockpicking].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Lumberjacking + else if (line.StartsWith("Lumberjacking=")) + pm.Skills[SkillName.Lumberjacking].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Macefighting + else if (line.StartsWith("Macefighting=")) + pm.Skills[SkillName.Macing].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Magery + else if (line.StartsWith("Magery=")) + pm.Skills[SkillName.Magery].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //MagicResistance + else if (line.StartsWith("MagicResistance=")) + pm.Skills[SkillName.MagicResist].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Meditation + else if (line.StartsWith("Meditation=")) + pm.Skills[SkillName.Meditation].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Mining + else if (line.StartsWith("Mining=")) + pm.Skills[SkillName.Mining].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Musicianship + else if (line.StartsWith("Musicianship=")) + pm.Skills[SkillName.Musicianship].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Necromancy + else if (line.StartsWith("Necromancy=")) + pm.Skills[SkillName.Necromancy].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Parrying + else if (line.StartsWith("Parrying=")) + pm.Skills[SkillName.Parry].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Peacemaking + else if (line.StartsWith("Peacemaking=")) + pm.Skills[SkillName.Peacemaking].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Poisoning + else if (line.StartsWith("Poisoning=")) + pm.Skills[SkillName.Poisoning].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Provocation + else if (line.StartsWith("Provocation=")) + pm.Skills[SkillName.Provocation].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //RemoveTrap + else if (line.StartsWith("RemoveTrap=")) + pm.Skills[SkillName.RemoveTrap].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //SpiritSpeak + else if (line.StartsWith("SpiritSpeak=")) + pm.Skills[SkillName.SpiritSpeak].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Stealth + else if (line.StartsWith("Stealth=")) + pm.Skills[SkillName.Stealth].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + // Swordsmanship + else if (line.StartsWith("Swordsmanship=")) + pm.Skills[SkillName.Swords].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Tactics + else if (line.StartsWith("Tactics=")) + pm.Skills[SkillName.Tactics].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Tailoring + else if (line.StartsWith("Tailoring=")) + pm.Skills[SkillName.Tailoring].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Taming + else if (line.StartsWith("Taming=")) + pm.Skills[SkillName.AnimalTaming].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //TasteID + else if (line.StartsWith("TasteID=")) + pm.Skills[SkillName.TasteID].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Tinkering + else if (line.StartsWith("Tinkering=")) + pm.Skills[SkillName.Tinkering].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Tracking + else if (line.StartsWith("Tracking=")) + pm.Skills[SkillName.Tracking].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Snooping + else if (line.StartsWith("Snooping=")) + pm.Skills[SkillName.Snooping].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Stealing + else if (line.StartsWith("Stealing=")) + pm.Skills[SkillName.Stealing].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Veterinary + else if (line.StartsWith("Veterinary=")) + pm.Skills[SkillName.Veterinary].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + //Wrestling + else if (line.StartsWith("Wrestling=")) + pm.Skills[SkillName.Wrestling].BaseFixedPoint = Int32.Parse(line.Split('=')[1]); + #endregion + + // On cap les skills à 100 maxi ! + for (int i = 0; i < pm.Skills.Length; i++) + { + Skill skill = pm.Skills[i]; + if (skill.Base > 100) skill.Base = 100; + } + } + } + } + + // Ajoutons un commentaire pour indiquer l'importation des personnages à cette date + if (a.Count > 0 && a is Account) + ((Account)a).Comments.Add(new AccountComment("SphereImporter", a.Count + " players imported from Sphere save file.")); + } + catch (Exception ex) + { + Console.WriteLine("SpherePlayerMobileImporter.EventSink_AccountLogin : " + ex.Message); + } + } + + private static void getHair(string charUID, Mobile pm) + { + // Liste des correspondances pour les cheveux + Dictionary hairTypes = new Dictionary(); + hairTypes.Add("[WORLDITEM i_hair_long]", 0x203C); + hairTypes.Add("[WORLDITEM i_hair_buns]", 0x2046); + hairTypes.Add("[WORLDITEM i_hair_ponytail]", 0x203D); + hairTypes.Add("[WORLDITEM i_hair_afro]", 0x2047); + hairTypes.Add("[WORLDITEM i_hair_short]", 0x203B); + hairTypes.Add("[WORLDITEM i_hair_receding]", 0x2048); + hairTypes.Add("[WORLDITEM i_hair_mohawk]", 0x2044); + hairTypes.Add("[WORLDITEM i_hair_2_pigtails]", 0x2049); + hairTypes.Add("[WORLDITEM i_hair_pageboy]", 0x2045); + hairTypes.Add("[WORLDITEM i_hair_krisna]", 0x204A); + hairTypes.Add("[WORLDITEM i_hair_cutter]", 0); + + // Liste des correspondances pour les barbes + Dictionary beardTypes = new Dictionary(); + beardTypes.Add("[WORLDITEM i_beard_long_med]", 0x204C); + beardTypes.Add("[WORLDITEM i_beard_long]", 0x203E); + beardTypes.Add("[WORLDITEM i_beard_short]", 0x203F); + beardTypes.Add("[WORLDITEM i_beard_vandyke]", 0x204D); + beardTypes.Add("[WORLDITEM i_beard_short_med]", 0x204B); + beardTypes.Add("[WORLDITEM i_beard_goatee]", 0x2040); + beardTypes.Add("[WORLDITEM i_beard_mustache]", 0x2041); + + string facialType = null; + int color = 0; + foreach (string line in File.ReadAllLines(SphereFiles.hairFile)) + { + // On réinitialise les données lorsque l'on rencontre un nouvel enregistrement + if (line.StartsWith("[")) { facialType = null; color = 0; } + + // Si l'on est bien en face d'un enregistrement de cheveux ou de barbe on note duquel il s'agit + if (line.StartsWith("[WORLDITEM i_hair_") || line.StartsWith("[WORLDITEM i_beard_")) facialType = line; + + // On stocke la couleur lorsqu'on la rencontre + if (line.StartsWith("COLOR=")) + color = Int32.Parse(line.Split('=')[1], System.Globalization.NumberStyles.HexNumber); + + if (line.StartsWith("CONT=")) + { + // Si l'on tombe sur le champ CONT, on vérifie qu'il s'agisse bien du joueur que l'on est entrain de créé + if (line.Split('=')[1] == charUID) + { + // Si ce sont des cheveux on récupère l'id dans le dico et on set la couleur + if (facialType.StartsWith("[WORLDITEM i_hair_")) + { + pm.HairItemID = hairTypes[facialType]; + pm.HairHue = color; + } + // Pareil dans le cas d'une barbe + else if (facialType.StartsWith("[WORLDITEM i_beard_")) + { + pm.FacialHairItemID = beardTypes[facialType]; + pm.FacialHairHue = color; + } + continue; + } + } + } + } + + private static void getGold(string charUID, Mobile pm) + { + int amount = 0; // montants d'or + int bankboxAmount = 0; + string backpack = getPlayerItemSerial(charUID, SphereFiles.backFile); // sac du joueur + string bankbox = getPlayerItemSerial(charUID, SphereFiles.bankFile); // banque du joueur + + // On parcourt le fichier qui contient tous les enregistrements d'or + foreach (string line in File.ReadAllLines(SphereFiles.goldFile)) + { + if (line.StartsWith("AMOUNT=")) + amount = Int32.Parse(line.Split('=')[1]); + + if (amount > 0 && line.StartsWith("CONT=") && line.Split('=')[1] == backpack) + { + Item gold = new Gold(amount); + Container pack = pm.Backpack; + + if (pack != null) + pack.DropItem(gold); + else + gold.Delete(); + + amount = 0; + } + else if (amount > 0 && line.StartsWith("CONT=") && line.Split('=')[1] == bankbox) + { + bankboxAmount += amount; + amount = 0; + //Item gold = new Gold(amount); + //Container bank = pm.BankBox; + + //if (bank != null) + // bank.DropItem(gold); + //else + // gold.Delete(); + } + } + + if (bankboxAmount > 0) + { + Container bank = pm.BankBox; + if (bank != null) + { + BankCheck check = new BankCheck(bankboxAmount); + check.Name = "Or Banque"; + bank.DropItem(check); + } + } + bankboxAmount = 0; + } + + private static string getPlayerItemSerial(string charUID, string file) + { + string serial = null; + foreach (string line in File.ReadAllLines(file)) + { + if (line.StartsWith("SERIAL=")) + serial = line.Split('=')[1]; + + if (line.StartsWith("CONT=") && line.Split('=')[1] == charUID) + return serial; + } + return null; + } + + private static void dressPlayer(Mobile pm) + { + if (pm == null) return; + + // Une robe d'une couleur aléatoire + Item i = new Robe(); + i.Hue = Utility.RandomDyedHue(); + pm.EquipItem(i); + + // Des chaussures + pm.EquipItem(new Shoes()); + + // Quelques objets dans le sac s'il en a un + if (pm.Backpack != null) + { + pm.Backpack.DropItem(new Dagger()); // dague + pm.Backpack.DropItem(new Candle()); // bougie + pm.Backpack.DropItem(new RedBook()); // un petit livre rouge pour honoré le président Mao... + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Weather/Commands.cs b/Scripts/Vivre/Engines/Weather/Commands.cs new file mode 100644 index 0000000..3e7013b --- /dev/null +++ b/Scripts/Vivre/Engines/Weather/Commands.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +using Server; +using Server.Regions; +using Server.Commands; +using Server.Network; + +namespace Server.ServerSeasons +{ + public class RegionCommands + { + public static void Initialize() + { + CommandSystem.Register("SetMapSeason", AccessLevel.Administrator, new CommandEventHandler(SetMapSeason_OnCommand)); + CommandSystem.Register("SetSeason", AccessLevel.GameMaster, new CommandEventHandler(SetSeason_OnCommand)); + } + + [Description("Sets the Season for the current region.")] + private static void SetSeason_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (e.Length >= 1) + { + Region reg = from.Region; + + if (reg == null || !(reg is ISeasons)) + { + from.SendMessage("You are not in a region that supports Seasons."); + from.SendMessage("To set the Map Season, use {0}SetMapSeason", CommandSystem.Prefix); + } + else + { + try + { + ISeasons sreg = reg as ISeasons; + + sreg.Season = (Season)Enum.Parse(typeof(Season), (e.GetString(0).Trim()), true); + from.SendMessage("Season has been set to {0}.", sreg.Season.ToString()); + } + catch + { + from.SendMessage("Format: SetSeason < Spring | Summer | Autumn/Fall | Winter | Desolation >"); + } + } + } + else + { + from.SendMessage("Format: SetSeason < Spring | Summer | Autumn/Fall | Winter | Desolation >"); + } + } + + [Description("Sets the Season for the current map.")] + private static void SetMapSeason_OnCommand(CommandEventArgs e) + { + Mobile from = e.Mobile; + + if (e.Length >= 1) + { + Map map = from.Map; + + if (map == null || map == Map.Internal) + { + from.SendMessage("Could not set the Season for this map."); + } + else + { + try + { + map.Season = (int)((Season)Enum.Parse(typeof(Season), (e.GetString(0).Trim()), true)); + from.SendMessage("Season has been set to {0}.", ((Season)map.Season).ToString()); + + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + if (m != null) + { + state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); + m.SendEverything(); + } + } + } + catch + { + from.SendMessage("Format: SetMapSeason < Spring | Summer | Autumn/Fall | Winter | Desolation >"); + } + } + } + else + { + from.SendMessage("Format: SetMapSeason < Spring | Summer | Autumn/Fall | Winter | Desolation >"); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Weather/ISeasons.cs b/Scripts/Vivre/Engines/Weather/ISeasons.cs new file mode 100644 index 0000000..c4d7656 --- /dev/null +++ b/Scripts/Vivre/Engines/Weather/ISeasons.cs @@ -0,0 +1,28 @@ +//To enable RUNUO 2.0 compatibility, simply comment out the next line (#define); +//#define RUNUO_1 + +using System; +using System.Collections; +using System.Collections.Generic; + +using Server; + +namespace Server.ServerSeasons +{ + public enum Season + { + Spring = 0, + Summer = 1, + Autumn = 2, + Winter = 3, + Desolation = 4, + Fall = Autumn, + } + + public interface ISeasons + { + Season Season { get; set; } + void UpdateSeason(); + void UpdateSeason(Mobile m); + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Weather/SeasonManager.cs b/Scripts/Vivre/Engines/Weather/SeasonManager.cs new file mode 100644 index 0000000..8f46977 --- /dev/null +++ b/Scripts/Vivre/Engines/Weather/SeasonManager.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using Server; +using Server.Regions; +using Server.Network; + +namespace Server.ServerSeasons +{ + public class SeasonManager : Timer + { + public static void Initialize() + { + new SeasonManager().Start(); + } + + public SeasonManager() + : base(TimeSpan.FromSeconds(10), TimeSpan.FromHours(12)) + { + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + UpdateSeasons(); + Priority = TimerPriority.OneMinute; + } + + public static int GetWeekNumber(DateTime dtPassed) + { + CultureInfo ciCurr = CultureInfo.CurrentCulture; + int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); + return weekNum; + } + + public static void UpdateSeasons() + { + // Define the actual season + Season actualSeason = Season.Summer; + + // Scriptiz : saisons basées sur un cycle + int week = GetWeekNumber(DateTime.Today); + switch (week % 8) + { + case 0: + case 1: + actualSeason = Season.Winter; + break; + case 2: + case 3: + actualSeason = Season.Spring; + break; + case 4: + case 5: + actualSeason = Season.Summer; + break; + case 6: + case 7: + actualSeason = Season.Autumn; + break; + default: + actualSeason = Season.Summer; + break; + } + + if (week > 49) actualSeason = Season.Winter; + + // Scriptiz : saisons basées sur les saisons IRL + /* + int month = DateTime.Today.Month; + switch (month) + { + case 12: + case 1: + case 2: + actualSeason = Season.Winter; + break; + case 3: + case 4: + case 5: + actualSeason = Season.Spring; + break; + case 6: + case 7: + case 8: + actualSeason = Season.Summer; + break; + case 9: + case 10: + case 11: + actualSeason = Season.Autumn; + break; + default: + actualSeason = Season.Summer; + break; + } + */ + Console.WriteLine("[SeasonManager] Actual season is " + actualSeason + "."); + + int count = 0; + foreach (Map m in Map.Maps) + { + if (m == null || m == Map.Internal) continue; + + // Si c'est la felucca d'origine on laisse Desolation ! + if (m == Map.Felucca) m.Season = (int)Season.Desolation; + else m.Season = (int)actualSeason; + + count++; + } + Console.WriteLine("Season updated for " + count + " on " + Map.Maps.Length + " maps."); + + count = 0; + foreach (Region r in Region.Regions) + { + if (r == null || !(r is ISeasons)) continue; + ISeasons s = r as ISeasons; + s.Season = actualSeason; + count++; + } + Console.WriteLine("Season updated for " + count + " on " + Region.Regions.Count + " regions."); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Engines/Weather/SeasonTracker.cs b/Scripts/Vivre/Engines/Weather/SeasonTracker.cs new file mode 100644 index 0000000..852d83f --- /dev/null +++ b/Scripts/Vivre/Engines/Weather/SeasonTracker.cs @@ -0,0 +1,245 @@ +//To enable RUNUO 2.0 compatibility, simply comment out the next line (#define); +//#define RUNUO_1 + +using System; +using System.Security; +using System.Security.Cryptography; +using System.Net; +using System.Collections; +using System.Text; +using System.IO; + +using Server; + +namespace Server.ServerSeasons +{ + public static class SeasonTracker + { + private static int LoadedCount = 0; + private static int SavedCount = 0; + + private static MD5CryptoServiceProvider m_MD5HashProvider; + private static byte[] m_MD5HashBuffer; + + public static string MD5Hash(string plainText) + { + if (m_MD5HashProvider == null) + m_MD5HashProvider = new MD5CryptoServiceProvider(); + + if (m_MD5HashBuffer == null) + m_MD5HashBuffer = new byte[256]; + + int length = Encoding.ASCII.GetBytes(plainText, 0, plainText.Length > 256 ? 256 : plainText.Length, m_MD5HashBuffer, 0); + byte[] hashed = m_MD5HashProvider.ComputeHash(m_MD5HashBuffer, 0, length); + + return BitConverter.ToString(hashed); + } + + /// + /// Configuration Events + /// + public static void Configure() + { + EventSink.ServerStarted += new ServerStartedEventHandler(OnLoad); + EventSink.WorldSave += new WorldSaveEventHandler(OnSave); + } + + /// + /// Serialize + /// + /// + private static void OnSave(WorldSaveEventArgs e) + { + string CurRegion = ""; + + try + { + if (Directory.Exists("Saves/Regions/Seasons/")) + Directory.Delete("Saves/Regions/Seasons/", true); + + foreach (Region r in Region.Regions) + { + if (r != null) + { + if (!(r is ISeasons)) + continue; + + if (r.GetType().IsAbstract || !r.GetType().IsSubclassOf(typeof(Region))) + continue; + + CurRegion = r.Name; + + + if (!Directory.Exists("Saves/Regions/Seasons/" + r.Map + "/")) + Directory.CreateDirectory("Saves/Regions/Seasons/" + r.Map + "/"); + + string name = "(" + r.Name + ")"; + string nameTmp = ""; + +#if(RUNUO_1) + if( r.Coords != null ) + { + for( int i = 0; i < r.Coords.Count; ++i ) + { + object obj = r.Coords[i]; + + if( obj is Rectangle3D ) + { + Rectangle3D r3d = ( Rectangle3D )obj; + + nameTmp += r3d.ToString( ); + } + else if( obj is Rectangle2D ) + { + Rectangle2D r2d = ( Rectangle2D )obj; + + nameTmp += r2d.ToString( ); + } + } + + name += "(" + MD5Hash( nameTmp ) + ")"; + } + + if( name == null || name == "" || name.Length == 0 ) + { + name += "(" + r.UId + ")"; + } +#else + if (r.Area != null) + { + for (int i = 0; i < r.Area.Length; ++i) + { + Rectangle3D r3d = r.Area[i]; + nameTmp += r3d.ToString(); + } + + name += "(" + MD5Hash(nameTmp) + ")"; + } +#endif + + try + { + GenericWriter writer = new BinaryFileWriter(Path.Combine("Saves/Regions/Seasons/" + r.Map + "/", name + ".bin"), true); + Season season = ((ISeasons)r).Season; + writer.Write((int)season); + SavedCount++; + writer.Close(); + } + catch (Exception ex1) + { + Console.WriteLine("[SeasonTracker] Serialize: ({0})", CurRegion); + Console.WriteLine(ex1.ToString()); + } + } + } + } + catch (Exception ex2) + { + Console.WriteLine("[SeasonTracker] OnSave: ({0})", CurRegion); + Console.WriteLine(ex2.ToString()); + } + + Console.WriteLine("[SeasonTracker] Saved {0} Region Seasons!", SavedCount); + SavedCount = 0; + } + + /// + /// Deserialize + /// + private static void OnLoad() + { + string CurRegion = ""; + + try + { + foreach (Region r in Region.Regions) + { + if (r != null) + { + if (!(r is ISeasons)) + continue; + + if (r.GetType().IsAbstract || !r.GetType().IsSubclassOf(typeof(Region))) + continue; + + CurRegion = r.Name; + + if (!Directory.Exists("Saves/Regions/Seasons/" + r.Map + "/")) + Directory.CreateDirectory("Saves/Regions/Seasons/" + r.Map + "/"); + + string name = "(" + r.Name + ")"; + string nameTmp = ""; + +#if(RUNUO_1) + if (r.Coords != null) + { + for (int i = 0; i < r.Coords.Count; ++i) + { + object obj = r.Coords[i]; + + if (obj is Rectangle3D) + { + Rectangle3D r3d = (Rectangle3D)obj; + + nameTmp += r3d.ToString(); + } + else if (obj is Rectangle2D) + { + Rectangle2D r2d = (Rectangle2D)obj; + + nameTmp += r2d.ToString(); + } + } + + name += "(" + MD5Hash(nameTmp) + ")"; + } + + if (name == null || name == "" || name.Length == 0) + { + name += "(" + r.UId + ")"; + } +#else + if (r.Area != null) + { + for (int i = 0; i < r.Area.Length; ++i) + { + Rectangle3D r3d = r.Area[i]; + nameTmp += r3d.ToString(); + } + + name += "(" + MD5Hash(nameTmp) + ")"; + } +#endif + + if (!File.Exists(Path.Combine("Saves/Regions/Seasons/" + r.Map + "/", name + ".bin"))) + return; + + using (FileStream bin = new FileStream(Path.Combine("Saves/Regions/Seasons/" + r.Map + "/", name + ".bin"), FileMode.Open, FileAccess.Read, FileShare.Read)) + { + try + { + GenericReader reader = new BinaryFileReader(new BinaryReader(bin)); + Season season = (Season)reader.ReadInt(); + ((ISeasons)r).Season = season; + LoadedCount++; + } + catch (Exception ex1) + { + Console.WriteLine("[SeasonTracker] Deserialize: ({0})", CurRegion); + Console.WriteLine(ex1.ToString()); + } + } + } + } + } + catch (Exception ex2) + { + Console.WriteLine("[SeasonTracker] OnLoad: ({0})", CurRegion); + Console.WriteLine(ex2.ToString()); + } + + Console.WriteLine("[SeasonTracker] Tracking {0} Regions' Seasons...", LoadedCount); + LoadedCount = 0; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Alchimie/AlchemyRegs.cs b/Scripts/Vivre/Items/Alchimie/AlchemyRegs.cs new file mode 100644 index 0000000..9f1ff77 --- /dev/null +++ b/Scripts/Vivre/Items/Alchimie/AlchemyRegs.cs @@ -0,0 +1,41 @@ +using System; + +namespace Server.Items +{ + public class BullFrogLard : Item + { + + [Constructable] + public BullFrogLard() + : base(0x3183) + { + Name = "Gras de crapaud"; + Hue = 50; + Movable = true; + Stackable = true; + } + + public BullFrogLard(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + if (!Stackable) + Stackable = true; + } + } + + +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Alchimie/AlchemyVial.cs b/Scripts/Vivre/Items/Alchimie/AlchemyVial.cs new file mode 100644 index 0000000..707b34c --- /dev/null +++ b/Scripts/Vivre/Items/Alchimie/AlchemyVial.cs @@ -0,0 +1,474 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.ContextMenus; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public enum LiquidType //Attention! Changer la version du slayerforge si modifié + { + None, + OgreBlood, + OrcBlood, + TrollBlood, + BloodElemental, + EarthElemental, + PoisonElemental, + FireElemental, + IceElemental, + AirElemental, + WaterElemental, + GargoyleBlood, + ScorpionBlood, + SpiderBlood, + TerathanBlood, + LizardmanBlood, + DragonBlood, + OphidianBlood, + SerpentBlood, + /*Special*/ + UndeadBlood, + FairyBlood, + DaemonBlood, + /*EndSpecial*/ + ChangelingBlood + } + + public class AlchemyVial : Item + { + private LiquidType m_AlchemyLiquidType; + + [CommandProperty(AccessLevel.GameMaster)] + public LiquidType AlchemyLiquidType + { + get { return m_AlchemyLiquidType; } + set { m_AlchemyLiquidType = value; ComputeProperties(); } + } + + [Constructable] + public AlchemyVial() + : base(0x0E24) + { + Name = "Éprouvette vide"; + Weight = 1.0; + Movable = true; + Stackable = true; + } + + public override bool StackWith(Mobile from, Item dropped, bool playSound) + { + if (dropped.Hue != Hue) + return false; + + return base.StackWith(from, dropped, playSound); + } + + public void ComputeProperties() + { + #region Choisi le Hue et le Name + switch (AlchemyLiquidType) + { + case (LiquidType.OgreBlood): + { + Hue = 1372; + Name = "Éprouvette de sang d'ogre"; + break; + } + case (LiquidType.OrcBlood): + { + Hue = 2601; + Name = "Éprouvette de sang d'orc"; + break; + } + case (LiquidType.TrollBlood): + { + Hue = 70; + Name = "Éprouvette de sang de troll"; + break; + } + case (LiquidType.BloodElemental): + { + Hue = 32; + Name = "Éprouvette d'élément de sang"; + break; + } + case (LiquidType.EarthElemental): + { + Hue = 152; + Name = "Éprouvette d'élément de terre"; + break; + } + case (LiquidType.PoisonElemental): + { + Hue = 67; + Name = "Éprouvette d'élément de poison"; + break; + } + case (LiquidType.FireElemental): + { + Hue = 1260; + Name = "Éprouvette d'élément de feu"; + break; + } + case (LiquidType.IceElemental): + { + Hue = 86; + Name = "Éprouvette d'élément de glace"; + break; + } + case (LiquidType.AirElemental): + { + Hue = 2042; + Name = "Éprouvette d'élément d'air"; + break; + } + case (LiquidType.WaterElemental): + { + Hue = 93; + Name = "Éprouvette d'élément d'eau"; + break; + } + case (LiquidType.GargoyleBlood): + { + Hue = 2504; + Name = "Éprouvette de sang de gargouille"; + break; + } + case (LiquidType.SpiderBlood): + { + Hue = 12; + Name = "Éprouvette de sang d'araignée"; + break; + } + case (LiquidType.TerathanBlood): + { + Hue = 1177; + Name = "Éprouvette de sang de terathan"; + break; + } + case (LiquidType.LizardmanBlood): + { + Hue = 74; + Name = "Éprouvette de sang d'homme lézard"; + break; + } + case (LiquidType.DragonBlood): + { + Hue = 132; + Name = "Éprouvette de sang de dragon"; + break; + } + case (LiquidType.OphidianBlood): + { + Hue = 154; + Name = "Éprouvette de sang d'ophidien "; + break; + } + case (LiquidType.SerpentBlood): + { + Hue = 168; + Name = "Éprouvette de sang de serpent "; + break; + } + case (LiquidType.ScorpionBlood): + { + Hue = 1196; + Name = "Éprouvette de sang de scorpion "; + break; + } + case (LiquidType.UndeadBlood): + { + Hue = 1375; + Name = "Éprouvette de sang de mort-vivant "; + break; + } + case (LiquidType.FairyBlood): + { + Hue = 1166; + Name = "Éprouvette de sang féérique"; + break; + } + case (LiquidType.DaemonBlood): + { + Hue = 1; + Name = "Éprouvette de sang démoniaque"; + break; + } + case (LiquidType.ChangelingBlood): + { + Hue = 19; + Name = "Éprouvette de sang de changeling "; + break; + } + + default: + { + Hue = 0; + Name = "Éprouvette vide"; + break; + } + } + #endregion + } + + public override void OnDoubleClick(Mobile from) + { + + if (!IsChildOf(from.Backpack)) + { + from.SendMessage("Vous devez avoir l'éprouvette dans votre sac pour l'utiliser"); + return; + } + + else if (AlchemyLiquidType != LiquidType.None) + { + from.SendMessage("Où voulez-vous verser le liquide?"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnDropTarget)); + return; + } + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + from.SendMessage("Sélectionnez l'échantillon à récolter"); + } + + + public void OnTarget(Mobile from, object obj) + { + if (!(obj is Corpse)) + { + from.SendMessage("Il vous faut trouver autre chose pour la remplir"); + return; + } + + Corpse targcorpse = (Corpse)obj; + + if (targcorpse.Channeled) + { + from.SendMessage("Vous ne pouvez récolter que sur un corps frais"); + return; + } + + Type type = null; + + if (targcorpse.Owner != null) + type = targcorpse.Owner.GetType(); + + AlchemyVial vial = new AlchemyVial(); + + #region Check des différents corps + // Ogre Trashing + if (type == typeof(Ogre) || type == typeof(OgreLord) || type == typeof(ArcticOgreLord)) + { + from.SendMessage("Vous recueillez du sang d'ogre"); + vial.AlchemyLiquidType = LiquidType.OgreBlood; + } + //Orc Slaying + else if (type == typeof(Orc) || type == typeof(OrcBomber) || type == typeof(OrcBrute) || type == typeof(OrcCaptain) || type == typeof(OrcScout) || type == typeof(OrcishLord) || type == typeof(OrcishMage)) + { + from.SendMessage("Vous recueillez du sang d'orc"); + vial.AlchemyLiquidType = LiquidType.OrcBlood; + } + //Troll Slaughter + else if (type == typeof(Troll) || type == typeof(FrostTroll)) + { + from.SendMessage("Vous recueillez du sang de troll"); + vial.AlchemyLiquidType = LiquidType.TrollBlood; + } + //Blood Drinking + else if (type == typeof(BloodElemental)) + { + from.SendMessage("Vous recueillez de l'élément de sang"); + vial.AlchemyLiquidType = LiquidType.BloodElemental; + } + //Earth Shatter + else if (type == typeof(AgapiteElemental) || type == typeof(BronzeElemental) || type == typeof(CopperElemental) || type == typeof(DullCopperElemental) || type == typeof(EarthElemental) || type == typeof(GoldenElemental) || type == typeof(ShadowIronElemental) || type == typeof(ValoriteElemental) || type == typeof(VeriteElemental)) + { + from.SendMessage("Vous recueillez de l'élément de terre"); + vial.AlchemyLiquidType = LiquidType.EarthElemental; + } + //Elemental Health + else if (type == typeof(PoisonElemental)) + { + from.SendMessage("Vous recueillez de l'élément de poison"); + vial.AlchemyLiquidType = LiquidType.PoisonElemental; + } + //Flame Dousing + else if (type == typeof(FireElemental)) + { + from.SendMessage("Vous recueillez de l'élément de feu"); + vial.AlchemyLiquidType = LiquidType.FireElemental; + } + //Summer Wind + else if (type == typeof(SnowElemental) || type == typeof(IceElemental)) + { + from.SendMessage("Vous recueillez de l'élément de glace"); + vial.AlchemyLiquidType = LiquidType.IceElemental; + } + //Vacuum + else if (type == typeof(AirElemental)) + { + from.SendMessage("Vous recueillez de l'élément de vent"); + vial.AlchemyLiquidType = LiquidType.AirElemental; + } + //Water Dissipation + else if (type == typeof(WaterElemental)) + { + from.SendMessage("Vous recueillez de l'élément d'eau"); + vial.AlchemyLiquidType = LiquidType.WaterElemental; + } + //Gargoyle Foes + else if (type == typeof(EnslavedGargoyle) || type == typeof(FireGargoyle) || type == typeof(Gargoyle) || type == typeof(GargoyleDestroyer) || type == typeof(GargoyleEnforcer) || type == typeof(StoneGargoyle)) + { + from.SendMessage("Vous recueillez du sang de gargouille"); + vial.AlchemyLiquidType = LiquidType.GargoyleBlood; + } + //Scorpions Bane + else if (type == typeof(Scorpion)) + { + from.SendMessage("Vous recueillez du sang de scorpion"); + vial.AlchemyLiquidType = LiquidType.ScorpionBlood; + } + //Spiders Death + else if (type == typeof(DreadSpider) || type == typeof(FrostSpider) || type == typeof(GiantBlackWidow) || type == typeof(GiantSpider) || type == typeof(Mephitis)) + { + from.SendMessage("Vous recueillez du sang d'araignée"); + vial.AlchemyLiquidType = LiquidType.SpiderBlood; + } + //Terathan Avenger + else if (type == typeof(TerathanAvenger) || type == typeof(TerathanDrone) || type == typeof(TerathanMatriarch) || type == typeof(TerathanWarrior)) + { + from.SendMessage("Vous recueillez du sang de Terathan"); + vial.AlchemyLiquidType = LiquidType.TerathanBlood; + } + //Dragon Slayer + else if (type == typeof(AncientWyrm) || type == typeof(GreaterDragon) || type == typeof(Dragon) || type == typeof(Drake) || type == typeof(Hiryu) || type == typeof(LesserHiryu) || type == typeof(SerpentineDragon) || type == typeof(ShadowWyrm) || type == typeof(SkeletalDragon) || type == typeof(SwampDragon) || type == typeof(WhiteWyrm) || type == typeof(Wyvern)) + { + from.SendMessage("Vous recueillez du sang de dragon"); + vial.AlchemyLiquidType = LiquidType.DragonBlood; + } + //Lizardman Slaughter + else if (type == typeof(Lizardman)) + { + from.SendMessage("Vous recueillez du sang d'homme lézard"); + vial.AlchemyLiquidType = LiquidType.LizardmanBlood; + } + //Ophidian + else if (type == typeof(OphidianArchmage) || type == typeof(OphidianKnight) || type == typeof(OphidianMage) || type == typeof(OphidianMatriarch) || type == typeof(OphidianWarrior)) + { + from.SendMessage("Vous recueillez du sang d'ophidien"); + vial.AlchemyLiquidType = LiquidType.OphidianBlood; + } + //Snakes Bane + else if (type == typeof(DeepSeaSerpent) || type == typeof(GiantIceWorm) || type == typeof(GiantSerpent) || type == typeof(IceSerpent) || type == typeof(IceSnake) || type == typeof(LavaSerpent) || type == typeof(LavaSnake) || type == typeof(SeaSerpent) || type == typeof(Serado) || type == typeof(SilverSerpent) || type == typeof(Snake) || type == typeof(Yamandon)) + { + from.SendMessage("Vous recueillez du sang de serpent"); + vial.AlchemyLiquidType = LiquidType.SerpentBlood; + } + else if (type == typeof(AncientLich) || type == typeof(DarknightCreeper) || type == typeof(FleshGolem) || type == typeof(LadyOfTheSnow) || type == typeof(Lich) || type == typeof(LichLord) || type == typeof(Mummy) || type == typeof(PestilentBandage) || type == typeof(RevenantLion) || type == typeof(RottingCorpse) || type == typeof(ShadowKnight)) + { + from.SendMessage("Vous recueillez du sang de mort-vivant"); + vial.AlchemyLiquidType = LiquidType.UndeadBlood; + } + else if (type == typeof(Centaur) || type == typeof(EtherealWarrior) || type == typeof(Kirin) || type == typeof(LordOaks) || type == typeof(Silvani) || type == typeof(Treefellow) || type == typeof(Unicorn) || type == typeof(MLDryad) || type == typeof(Satyr)) + { + from.SendMessage("Vous recueillez du sang féérique"); + vial.AlchemyLiquidType = LiquidType.FairyBlood; + } + else if (type == typeof(AbysmalHorror) || type == typeof(ArcaneDaemon) || type == typeof(Balron) || type == typeof(BoneDemon) || type == typeof(ChaosDaemon) || type == typeof(Daemon) || type == typeof(DemonKnight) || type == typeof(Devourer) || type == typeof(FanDancer) || type == typeof(Gibberling) || type == typeof(IceFiend) || type == typeof(Impaler) || type == typeof(Oni) || type == typeof(Ravager) || type == typeof(Semidar) || type == typeof(Succubus) || type == typeof(TsukiWolf)) + { + from.SendMessage("Vous recueillez du sang démoniaque"); + vial.AlchemyLiquidType = LiquidType.DaemonBlood; + } + //Potion de changement de sexe + else if (type == typeof(Changeling)) + { + from.SendMessage("Vous recueillez du sang de changeling"); + vial.AlchemyLiquidType = LiquidType.ChangelingBlood; + } + else + { + from.SendMessage("Cela ne vous servira à rien"); + return; + } + #endregion + + from.AddItem(vial); + Consume(); + targcorpse.Channeled = true; + } + + public void OnDropTarget(Mobile from, object obj) + { + if (!(obj is SlayerForge)) + { + from.SendMessage("Cela ne servirait à rien de verser le liquide ici"); + return; + } + + SlayerForge targ = (SlayerForge)obj; + + if (targ.Movable) + { + from.SendMessage("Cela doit être fixé dans une maison pour être utilisé"); + return; + } + + if (this.AlchemyLiquidType == LiquidType.None) + { + from.SendMessage("Vous ne pouvez verser une éprouvette vide"); + return; + } + + if (this.AlchemyLiquidType == LiquidType.ChangelingBlood) + { + from.SendMessage("Ce contenu est destiné à un autre usage"); + return; + } + + if (targ.CountVial >= targ.MaxVials) + { + from.SendMessage("Cette bassine est pleine"); + return; + } + + from.SendMessage("Vous jetez le contenu de l'éprouvette dans la forge"); + targ.AddVial(this); + Consume(); + + if (Utility.RandomDouble() < (from.RawDex-10)) + from.AddItem(new AlchemyVial()); + else + { + from.SendMessage("L'éprouvette vous glisse des mains et se brise"); + } + } + + + + public AlchemyVial(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.WriteEncodedInt((int)m_AlchemyLiquidType); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_AlchemyLiquidType = (LiquidType)reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Alchimie/MorphBase.cs b/Scripts/Vivre/Items/Alchimie/MorphBase.cs new file mode 100644 index 0000000..844051c --- /dev/null +++ b/Scripts/Vivre/Items/Alchimie/MorphBase.cs @@ -0,0 +1,83 @@ +using System; +using Server.Targeting; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class MorphBase : Item + { + + [Constructable] + public MorphBase() + : base(0x182B) + { + Name = "Base de métamorphose"; + Movable = true; + Stackable = true; + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Y ajouter un élément contraire à vous pourrait bien avoir un effet surprenant!"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(ChangelingDropTarget)); + base.OnDoubleClick(from); + } + + public void ChangelingDropTarget(Mobile from, object obj) + { + if (!(obj is HairStrand)) + { + from.SendMessage("Cela ne servirait à rien de verser le liquide ici"); + return; + } + + HairStrand targ = (HairStrand)obj; + + if (from.Skills[SkillName.Alchemy].Value < 60) + { + from.SendMessage("Vos maigres talents d'alchimistes ne permettraient pas une pareille mixture..."); + return; + } + + if (!from.CheckTargetSkill(SkillName.Alchemy, targ, 55, 95)) + { + from.SendMessage("Vous mettez trop de cheveux à l'intérieur, ce qui gâche le mélange..."); + targ.Delete(); + return; + } + + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous mélangez doucement le tout et terminez le mélange...", from.NetState); + GenderPotion potion = new GenderPotion(); + potion.Female = targ.HairOwner.Female; + from.AddToBackpack(potion); + this.Delete(); + targ.Delete(); + return; + } + + + public MorphBase(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + if (!Stackable) + Stackable = true; + } + } + + +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Alchimie/Teintures/Teinture.cs b/Scripts/Vivre/Items/Alchimie/Teintures/Teinture.cs new file mode 100644 index 0000000..85e3e77 --- /dev/null +++ b/Scripts/Vivre/Items/Alchimie/Teintures/Teinture.cs @@ -0,0 +1,361 @@ +using System; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class TeintureBottle : Item + { + [Constructable] + public TeintureBottle() + : this(1) + { + } + + [Constructable] + public TeintureBottle(int amount) + : base(0xF0E) + { + Stackable = false; + Weight = 1.0; + Amount = amount; + } + + public TeintureBottle(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + from.BeginTarget(-1, false, TargetFlags.None, new TargetCallback(OnMixTeinture)); + from.SendMessage("Dans quoi souhaitez-vous verser cette bouteille?"); + } + + public void OnMixTeinture(Mobile from, object obj) + { + if (obj is TeintureBottle) + { + TeintureBottle tb = (TeintureBottle)obj; + + if(tb.Hue == this.Hue) + { + from.SendMessage("Cela ne sert à rien de mélanger deux fois la même teinture"); + return; + } + if (tb.Hue == 0x47E || this.Hue == 0x47E) + { + if (tb.Hue == 0x484 || this.Hue == 0x484) + { + this.Hue = 0x48D; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48D || this.Hue == 0x48D) + { + this.Hue = 0x47f; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x489 || this.Hue == 0x489) + { + this.Hue = 0x491; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x485 || this.Hue == 0x485) + { + this.Hue = 0x484; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x484 || this.Hue == 0x484) + { + this.Hue = 0x48E; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48C || this.Hue == 0x48C) + { + this.Hue = 0x48F; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48B || this.Hue == 0x48B) + { + this.Hue = 0x490; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48A || this.Hue == 0x48A) + { + this.Hue = 0x495; + tb.ReplaceWith(new Bottle()); + } + else + { + from.SendMessage("Il ne sert à rien de mélanger ces deux teintures"); + tb.ReplaceWith(new Bottle()); + this.ReplaceWith(new Bottle()); + return; + } + this.Name = "Teinture mélangée"; + from.SendMessage("Vous créez une teinture d'une autre coloration"); + return; + } + else if (tb.Hue == 0x497 || this.Hue == 0x497) + { + if (tb.Hue == 0x48C || this.Hue == 0x48C) + { + this.Hue = 0x483; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48B || this.Hue == 0x48B) + { + this.Hue = 0x486; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48A || this.Hue == 0x48A) + { + this.Hue = 0x488; + tb.ReplaceWith(new Bottle()); + } + else + { + from.SendMessage("Il ne sert à rien de mélanger ces deux teintures"); + tb.ReplaceWith(new Bottle()); + this.ReplaceWith(new Bottle()); + return; + } + this.Name = "Teinture mélangée"; + from.SendMessage("Vous créez une teinture d'une autre coloration"); + return; + } + else if (tb.Hue == 0x484 || this.Hue == 0x484) + { + if (tb.Hue == 0x489 || this.Hue == 0x489) + { + this.Hue = 0x48C; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x485 || this.Hue == 0x485) + { + this.Hue = 0x48B; + tb.ReplaceWith(new Bottle()); + } + else if (tb.Hue == 0x48C || this.Hue == 0x48C) + { + this.Hue = 0x48A; + tb.ReplaceWith(new Bottle()); + } + else + { + from.SendMessage("Il ne sert à rien de mélanger ces deux teintures"); + tb.ReplaceWith(new Bottle()); + this.ReplaceWith(new Bottle()); + return; + } + this.Name = "Teinture mélangée"; + from.SendMessage("Vous créez une teinture d'une autre coloration"); + return; + } + else + { + from.SendMessage("Il ne sert à rien de mélanger ces deux teintures"); + tb.ReplaceWith(new Bottle()); + this.ReplaceWith(new Bottle()); + return; + } + } + else if(obj is SpecialDyeTub) + { + SpecialDyeTub dt = (SpecialDyeTub)obj; + + if(dt.Redyable) + { + dt.DyedHue = this.Hue; + dt.Redyable = false; + dt.Charges = 10; + from.SendMessage("Vous préparez le bac de teinture"); + return; + } + + from.SendMessage("Ce bac doit d'abord être lavé avant d'être utilisé") ; + } + else + from.SendMessage("Vous ne pouvez que colorer une autre teinture ou un bac spécial vide"); + } + } + public class WhiteTeinture : TeintureBottle + { + + [Constructable] + public WhiteTeinture() : base() + { + Name = "Teinture blanche"; + Hue = 0x47E; + Movable = true; + Stackable = false; + } + + public WhiteTeinture(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + public class BlackTeinture : TeintureBottle + { + + [Constructable] + public BlackTeinture() + : base() + { + Name = "Teinture noire"; + Hue = 0x497; + Movable = true; + Stackable = false; + } + + public BlackTeinture(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + public class CyanTeinture : TeintureBottle + { + + [Constructable] + public CyanTeinture() + : base() + { + Name = "Teinture cyan"; + Hue = 0x484; + Movable = true; + Stackable = false; + } + + public CyanTeinture(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + public class YellowTeinture : TeintureBottle + { + + [Constructable] + public YellowTeinture() + : base() + { + Name = "Teinture jaune"; + Hue = 0x489; + Movable = true; + Stackable = false; + } + + public YellowTeinture(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } + public class MagentaTeinture : TeintureBottle + { + + [Constructable] + public MagentaTeinture() + : base() + { + Name = "Teinture magenta"; + Hue = 0x485; + Movable = true; + Stackable = false; + } + + public MagentaTeinture(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } +} + diff --git a/Scripts/Vivre/Items/Armor/Leather/VivreCagoule.cs b/Scripts/Vivre/Items/Armor/Leather/VivreCagoule.cs new file mode 100644 index 0000000..d0a1efe --- /dev/null +++ b/Scripts/Vivre/Items/Armor/Leather/VivreCagoule.cs @@ -0,0 +1,116 @@ +//Myron - Cagoule pour les criminels +using System; +using Server.Items; + +namespace Server.Items +{ + public class VivreCagoule : BaseArmor + { + private string m_Title; + private CagouleTimer timer; + public override int BasePhysicalResistance { get { return 2; } } + public override int BaseFireResistance { get { return 3; } } + public override int BaseColdResistance { get { return 3; } } + public override int BasePoisonResistance { get { return 3; } } + public override int BaseEnergyResistance { get { return 4; } } + + public override int InitMinHits { get { return 25; } } + public override int InitMaxHits { get { return 45; } } + + public override int AosStrReq { get { return 10; } } + public override int OldStrReq { get { return 10; } } + + public override int ArmorBase { get { return 3; } } + + public override ArmorMaterialType MaterialType { get { return ArmorMaterialType.Leather; } } + public override CraftResource DefaultResource { get { return CraftResource.RegularLeather; } } + + public override ArmorMeditationAllowance DefMedAllowance { get { return ArmorMeditationAllowance.All; } } + + [Constructable] + public VivreCagoule() + : base(0x278E) + { + Name = "Cagoule"; + Weight = 2.0; + } + + private class CagouleTimer : Timer + { + private Mobile m; + + public CagouleTimer(Mobile from) + : base(TimeSpan.FromSeconds(100), TimeSpan.FromSeconds(100)) + { + m = from; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + if ((m.FindItemOnLayer(Layer.Helm) != null) && (m.FindItemOnLayer(Layer.Helm).GetType() == typeof(VivreCagoule))) + { + m.Criminal = false; + m.Criminal = true; + } + else + this.Stop(); + } + } + + public override bool OnEquip(Mobile from) + { + if (from.Female) + from.NameMod = "Femme en cagoule"; + else + from.NameMod = "Homme en cagoule"; + + m_Title = from.Title; + from.Title = null; + from.DisplayGuildTitle = false; + from.Criminal = false; + from.Criminal = true; + from.SendMessage("Vous portez une cagoule et �tes donc consider� comme un criminel."); + timer = new CagouleTimer(from); + timer.Start(); + return base.OnEquip(from); + } + + public override void OnRemoved(object parent) + { + if (parent is Mobile) + { + Mobile from = (Mobile)parent; + from.Title = m_Title; + from.NameMod = null; + } + + if (timer != null) + { + timer.Stop(); + timer = null; + } + + base.OnRemoved(parent); + } + + public VivreCagoule(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + writer.Write((string)m_Title); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_Title = reader.ReadString(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/BaseWearable.cs b/Scripts/Vivre/Items/BaseWearable.cs new file mode 100644 index 0000000..c5d2b18 --- /dev/null +++ b/Scripts/Vivre/Items/BaseWearable.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class BaseWearable : Item + { + private bool MessageColorization = true; // Messages will retain color of item equipped + private int EquipSound = 0x57; + + private Mobile m_Mobile; + private Container m_Cont; + + public override void OnDoubleClick(Mobile from) + { + if (!this.Movable || this.Layer == Layer.Invalid || this.Parent is Corpse) + return; + + if (!from.InRange(this.GetWorldLocation(), 2)) // Do not equip items further than 2 tiles + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } + + m_Mobile = from; + m_Cont = this.Parent as Container; + bool backpack = from.Backpack != null; + + if (from.FindItemOnLayer(this.Layer) == this) + { + if (!backpack) + { + from.SendMessage(35, "You have no inventory. Equip inventory bag first."); + } + else if (from.Backpack.TryDropItem(from, this, true)) + { + from.PlaySound(EquipSound); + //from.SendMessage(MessageColorization ? this.Hue : 55, "You put {0} into your backpack.", this.Name != null ? this.Name : this.ItemData.Name); + } + return; + } + + if (this.Layer == Layer.TwoHanded && !(this is BaseShield)) // If item is Two-handed weapon + { + if (from.FindItemOnLayer(Layer.OneHanded) != null || from.FindItemOnLayer(this.Layer) != null) + { + if (!backpack) + { + from.SendMessage(35, "You have no inventory. Equip inventory bag first."); + return; + } + } + if (from.FindItemOnLayer(Layer.OneHanded) != null && from.FindItemOnLayer(this.Layer) == null) + { + Item item = from.FindItemOnLayer(Layer.OneHanded); + DoSwap(item); + from.PlaySound(EquipSound); + return; + } + else if (from.FindItemOnLayer(Layer.OneHanded) != null && from.FindItemOnLayer(this.Layer) != null) + { + Item firstHand = from.FindItemOnLayer(Layer.OneHanded); + Item secondHand = from.FindItemOnLayer(this.Layer); + DoSwap(firstHand, secondHand); + from.PlaySound(EquipSound); + return; + } + } + + if (from.FindItemOnLayer(this.Layer) != null) + { + if (!backpack) + { + from.SendMessage(35, "You have no inventory. Equip inventory bag first."); + return; + } + Item item = from.FindItemOnLayer(this.Layer); + DoSwap(item); + from.PlaySound(EquipSound); + } + else if (this.Layer == Layer.OneHanded && from.FindItemOnLayer(Layer.TwoHanded) != null && !(from.FindItemOnLayer(Layer.TwoHanded) is BaseShield)) + { + Item item = from.FindItemOnLayer(Layer.TwoHanded); + DoSwap(item); + from.PlaySound(EquipSound); + } + else + { + from.EquipItem(this); + if (from.FindItemOnLayer(this.Layer) == this) + { + from.PlaySound(EquipSound); + //from.SendMessage(MessageColorization ? this.Hue : 75, "You equipped {0}.", this.Name != null ? this.Name : this.ItemData.Name); + } + } + } + + public void DoSwap(Item item1) + { + DoSwap(item1, null); + } + + public void DoSwap(Item firstHand, Item secondHand) + { + if (secondHand == null) + { + if (m_Cont == null) + { + //m_Mobile.SendMessage(MessageColorization ? this.Hue : 49, "You swapped {0} for {1}.", this.Name != null ? this.Name : this.ItemData.Name, firstHand.Name != null ? firstHand.Name : firstHand.ItemData.Name); + firstHand.MoveToWorld(this.Location); + m_Mobile.EquipItem(this); + } + else if (m_Cont.TryDropItem(m_Mobile, firstHand, true)) + { + //m_Mobile.SendMessage(MessageColorization ? this.Hue : 49, "You swapped {0} for {1}.", this.Name != null ? this.Name : this.ItemData.Name, firstHand.Name != null ? firstHand.Name : firstHand.ItemData.Name); + firstHand.Location = this.Location; + m_Mobile.EquipItem(this); + } + } + else + { + if (m_Cont == null) + { + //m_Mobile.SendMessage(MessageColorization ? this.Hue : 49, "You swapped {0} for {1} and {2}.", this.Name != null ? this.Name : this.ItemData.Name, firstHand.Name != null ? firstHand.Name : firstHand.ItemData.Name, secondHand.Name != null ? secondHand.Name : secondHand.ItemData.Name); + firstHand.MoveToWorld(this.Location); + secondHand.MoveToWorld(this.Location); + m_Mobile.EquipItem(this); + } + else if (m_Cont.TryDropItem(m_Mobile, firstHand, true) && m_Cont.TryDropItem(m_Mobile, secondHand, true)) + { + //m_Mobile.SendMessage(MessageColorization ? this.Hue : 49, "You swapped {0} for {1} and {2}.", this.Name != null ? this.Name : this.ItemData.Name, firstHand.Name != null ? firstHand.Name : firstHand.ItemData.Name, secondHand.Name != null ? secondHand.Name : secondHand.ItemData.Name); + firstHand.Location = this.Location; + secondHand.Location = this.Location; + m_Mobile.EquipItem(this); + } + } + } + + public BaseWearable(int itemID) + : base(itemID) + { + } + + public BaseWearable(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/BeardRestylingDeed.cs b/Scripts/Vivre/Items/BeardRestylingDeed.cs new file mode 100644 index 0000000..3faa713 --- /dev/null +++ b/Scripts/Vivre/Items/BeardRestylingDeed.cs @@ -0,0 +1,151 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Prompts; +using Server.Items; +using Server.Targeting; +using Server.Gumps; + +namespace Server.Items +{ + public class BeardRestylingDeed : Item + { + + + [Constructable] + public BeardRestylingDeed() + : base(0x14F0) + { + Weight = 1.0; + LootType = LootType.Blessed; + Name = "Changement de barbe"; + } + + public BeardRestylingDeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(1042001); // That must be in your pack... + } + else if (from.Female) + { + from.SendMessage("Allons jolie damoiselle, ceci est pour un homme"); // That must be in your pack... + } + else + { + from.SendGump(new InternalGump(from, this)); + } + } + + private class InternalGump : Gump + { + private Mobile m_From; + private BeardRestylingDeed m_Deed; + + public InternalGump(Mobile from, BeardRestylingDeed deed) + : base(50, 50) + { + m_From = from; + m_Deed = deed; + + from.CloseGump(typeof(InternalGump)); + + AddBackground(100, 10, 400, 385, 0xA28); + + AddHtmlLocalized(100, 25, 400, 35, 1013008, false, false); + AddButton(175, 340, 0xFA5, 0xFA7, 0x0, GumpButtonType.Reply, 0); // CANCEL + + AddHtmlLocalized(210, 342, 90, 35, 1011012, false, false);//
HAIRSTYLE SELECTION MENU
+ + int[][] RacialData = HumanArray; + + for (int i = 1; i < RacialData.Length; i++) + { + AddHtmlLocalized(LayoutArray[i][2], LayoutArray[i][3], (i == 1) ? 125 : 80, (i == 1) ? 70 : 35, RacialData[i][0], false, false); + if (LayoutArray[i][4] != 0) + { + AddBackground(LayoutArray[i][0], LayoutArray[i][1], 50, 50, 0xA3C); + AddImage(LayoutArray[i][4], LayoutArray[i][5], RacialData[i][2]); + } + AddButton(LayoutArray[i][6], LayoutArray[i][7], 0xFA5, 0xFA7, i, GumpButtonType.Reply, 0); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + if (m_From == null || !m_From.Alive) + return; + + if (m_Deed.Deleted) + return; + + if (info.ButtonID < 1 || info.ButtonID > 10) + return; + + int[][] RacialData = HumanArray; + + if (m_From is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)m_From; + + pm.SetHairMods(-1, -1); // clear any hairmods (disguise kit, incognito) + m_From.HairItemID = RacialData[info.ButtonID][1]; + m_Deed.Delete(); + } + } + /* + gump data: bgX, bgY, htmlX, htmlY, imgX, imgY, butX, butY + */ + + int[][] LayoutArray = + { + new int[] { 0 }, /* padding: its more efficient than code to ++ the index/buttonid */ + new int[] { 425, 280, 342, 295, 000, 000, 310, 292 }, + new int[] { 235, 060, 150, 075, 168, 020, 118, 073 }, + new int[] { 235, 115, 150, 130, 168, 070, 118, 128 }, + new int[] { 235, 170, 150, 185, 168, 130, 118, 183 }, + new int[] { 235, 225, 150, 240, 168, 185, 118, 238 }, + new int[] { 425, 060, 342, 075, 358, 018, 310, 073 }, + new int[] { 425, 115, 342, 130, 358, 075, 310, 128 }, + new int[] { 425, 170, 342, 185, 358, 125, 310, 183 }, + new int[] { 425, 225, 342, 240, 358, 185, 310, 238 }, + new int[] { 235, 280, 150, 295, 168, 245, 118, 292 } // slot 10, Curly - N/A for elfs. + }; + + /* + racial arrays are: cliloc_M, ItemID_M, gump_img_M + */ + int[][] HumanArray = /* why on earth cant these utilies be consistent with hex/dec */ + { + new int[] { 0 }, + new int[] { 3000340, 0, 0 }, + new int[] { 3000352, 0x203E, 0xC671 }, + new int[] { 3000353, 0x203F, 0xc672 }, + new int[] { 3000351, 0x2040, 0xc670 }, + new int[] { 3000354, 0x2041, 0xC673 }, + new int[] { 3000355, 0x204B, 0xC676 }, + new int[] { 3000356, 0x204C, 0xC675 }, + new int[] { 3000357, 0x204D, 0xC677 } + }; + + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Blacksmithy/IronBeetleBody.cs b/Scripts/Vivre/Items/Blacksmithy/IronBeetleBody.cs new file mode 100644 index 0000000..821ec2f --- /dev/null +++ b/Scripts/Vivre/Items/Blacksmithy/IronBeetleBody.cs @@ -0,0 +1,95 @@ +using System; +using Server.Mobiles; +using Server.Targeting; + +namespace Server.Items +{ + public class IronBeetleBody : Item + { + private double m_SummonScalar; + private int m_Durability; + + [CommandProperty(AccessLevel.GameMaster)] + public double SummonScalar + { + get { return m_SummonScalar; } + set { m_SummonScalar = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Durability + { + get { return m_Durability; } + set { m_Durability = value; InvalidateProperties(); } + } + + [Constructable] + public IronBeetleBody() + : base(0x210F) + { + Weight = 150; + Stackable = false; + Name = "Corps d'Iron Beetle"; + Durability = 100; + } + + public override void OnDoubleClick(Mobile from) + { + if (SummonScalar == 0) + { + base.OnDoubleClick(from); + } + else + { + if (!from.CheckSkill(SkillName.Mysticism, 0, 35)) + { + from.SendMessage("Le mécanisme, sous vos mains non initiées en magie, s'abime"); + Durability--; + } + else + { + from.SendMessage("La bestiole prend vie"); + + IronBeetle beetle = new IronBeetle(); + beetle.SummonScalar = this.SummonScalar; + beetle.Controlled = true; + beetle.ControlMaster = from; + beetle.Crafted = true; + beetle.MoveToWorld(from.Location, from.Map); + this.Delete(); + } + if (Durability == 0) + { + from.SendMessage("Vous détruisez la carapace"); + Delete(); + } + } + base.OnDoubleClick(from); + } + + public IronBeetleBody(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + + writer.Write((double)m_SummonScalar); + writer.Write((int)m_Durability); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_SummonScalar = reader.ReadDouble(); + m_Durability = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/Items/CarvedPumpkin.cs b/Scripts/Vivre/Items/CarvedPumpkin.cs new file mode 100644 index 0000000..0826aaf --- /dev/null +++ b/Scripts/Vivre/Items/CarvedPumpkin.cs @@ -0,0 +1,154 @@ +using System; +using Server.Targeting; + +namespace Server.Items +{ + public class SmileyPumpkin : BaseLight + { + public override int LitItemID { get { return 0x4695; } } + public override int UnlitItemID { get { return 0x4698; } } + + [Constructable] + public SmileyPumpkin() + : base(0x4698) + { + Burning = false; + Light = LightType.NorthSmall; + Weight = 1.0; + } + + public override void OnDoubleClick(Mobile from) + { + if (Protected && from.AccessLevel == AccessLevel.Player) + return; + + if (!from.InRange(this.GetWorldLocation(), 2)) + return; + + if (Burning) + { + from.SendMessage("Comme elle est magnifique!"); + } + else + { + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + from.SendMessage("Elle serait encore mieux avec une chandelle à l'intérieur, non?"); + } + } + + public void OnTarget(Mobile from, object obj) + { + if (obj is Candle) + { + Candle targ = (Candle)obj; + + from.SendMessage("Vous déposez la chandelle dans la citrouille!"); + this.Ignite(); + targ.Delete(); + Timer.DelayCall(TimeSpan.FromMinutes(20), Douse); + return; + } + if (obj is CandleSkull) + { + from.SendMessage("Ceci fait bien trop peur pour une citrouille si jolie..."); + return; + } + + from.SendMessage("Cela n'entrera pas dans la citrouille."); + } + + public SmileyPumpkin(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class EvilPumpkin : BaseLight + { + public override int LitItemID { get { return 0x4691; } } + public override int UnlitItemID { get { return 0x4694; } } + + + [Constructable] + public EvilPumpkin() + : base(0x4694) + { + Burning = false; + Light = LightType.NorthSmall; + Weight = 1.0; + } + + public EvilPumpkin(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (Protected && from.AccessLevel == AccessLevel.Player) + return; + + if (!from.InRange(this.GetWorldLocation(), 2)) + return; + + if (Burning) + { + from.SendMessage("Comme elle est effrayante!"); + } + else + { + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + from.SendMessage("Elle serait encore mieux avec une chandelle à l'intérieur, non?"); + } + } + + public void OnTarget(Mobile from, object obj) + { + if (obj is Candle) + { + + from.SendMessage("Pour une citrouille aussi effrayante, il faut une chandelle tout aussi effrayante"); + return; + } + if(obj is CandleSkull) + { + CandleSkull targ = (CandleSkull)obj; + from.SendMessage("Vous déposez la chandelle dans la citrouille!"); + targ.Delete(); + this.Ignite(); + Timer.DelayCall(TimeSpan.FromMinutes(20), Douse); + return; + } + + from.SendMessage("Cela n'entrera pas dans la citrouille."); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/CloakVeteran.cs b/Scripts/Vivre/Items/CloakVeteran.cs new file mode 100644 index 0000000..3a92504 --- /dev/null +++ b/Scripts/Vivre/Items/CloakVeteran.cs @@ -0,0 +1,45 @@ +using System; + +namespace Server.Items +{ + [Flipable] + public class VeteranCloak : BaseCloak + { + + [Constructable] + public VeteranCloak() : this(0) + { + } + + [Constructable] + public VeteranCloak( int hue ) : base( 0x1515, hue ) + { + Name = "Cape des survivants"; + Weight = 5.0; + Hue = 577; + LootType = LootType.Blessed; + } + + public VeteranCloak (Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Container/DonationBox.cs b/Scripts/Vivre/Items/Container/DonationBox.cs new file mode 100644 index 0000000..8076e24 --- /dev/null +++ b/Scripts/Vivre/Items/Container/DonationBox.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + [DynamicFliping] + [Flipable(0x9A8, 0xE80)] + public class DonationBox : LockableContainer + { + [Constructable] + public DonationBox() + : base(0x9A8) + { + Name = "Boite à dons (Or seulement)"; + } + + public DonationBox(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + } +} diff --git a/Scripts/Vivre/Items/Container/SalaryChest.cs b/Scripts/Vivre/Items/Container/SalaryChest.cs new file mode 100644 index 0000000..04d4f2c --- /dev/null +++ b/Scripts/Vivre/Items/Container/SalaryChest.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Multis; +using Server.Network; + +namespace Server.Items +{ + [DynamicFliping] + [Flipable(0x4025, 0x4026)] + public class SalaryChest : BaseContainer + { + private bool m_Active; + private int m_Salary; + private Mobile m_Employer; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Active + { + get + { + return m_Active; + } + set + { + m_Active = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Salary + { + get + { + return m_Salary; + } + set + { + m_Salary = value; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Employer + { + get + { + return m_Employer; + } + set + { + m_Employer = value; + } + } + + + [Constructable] + public SalaryChest() + : base(0x4025) + { + Name = "Coffre à salaire"; + } + + public SalaryChest(Serial serial) : base(serial) + { + } + + public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage) + { + from.SendMessage("Vous ne pouvez rien déposer ici"); + return false; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.Write((bool)m_Active); + writer.Write((int)m_Salary); + writer.Write((Mobile)m_Employer); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Active = reader.ReadBool(); + m_Salary = reader.ReadInt(); + m_Employer = reader.ReadMobile(); + } + } +} diff --git a/Scripts/Vivre/Items/CustomSigns.cs b/Scripts/Vivre/Items/CustomSigns.cs new file mode 100644 index 0000000..1273d60 --- /dev/null +++ b/Scripts/Vivre/Items/CustomSigns.cs @@ -0,0 +1,189 @@ +using Server; +using Server.Items; +using Server.Multis; +using Server.Network; +using System; +using Server.Prompts; + +namespace Server.Items +{ + [FlipableAttribute(0xBA5, 0xBA6)] + public class TailorSign : BaseSign + { + [Constructable] + public TailorSign() + : base(0xBA5) + { + Movable = true; + } + + public TailorSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0xBA7, 0xBA8)] + public class TinkerSign : BaseSign + { + [Constructable] + public TinkerSign() + : base(0xBA7) + { + Movable = true; + } + + public TinkerSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0xBAF, 0xBB0)] + public class WoodworkerSign : BaseSign + { + [Constructable] + public WoodworkerSign() + : base(0xBAF) + { + Movable = true; + } + + public WoodworkerSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0xBC7, 0xBC8)] + public class BlacksmithSign : BaseSign + { + [Constructable] + public BlacksmithSign() + : base(0xBC7) + { + Movable = true; + } + + public BlacksmithSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0xBD1, 0xBD2)] + public class GoldSign : BaseSign + { + [Constructable] + public GoldSign() + : base(0xBD1) + { + Movable = true; + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Que souhaitez-vous graver sur ce panneau?"); + from.Prompt = new RenamePrompt(this); + } + + public GoldSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } + + [FlipableAttribute(0xBCF, 0xBD0)] + public class WoodenSign : BaseSign + { + [Constructable] + public WoodenSign() + : base(0xBCF) + { + Movable = true; + } + + public override void OnDoubleClick(Mobile from) + { + from.SendMessage("Que souhaitez-vous graver sur ce panneau?"); + from.Prompt = new RenamePrompt(this); + } + + public WoodenSign(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Dismounter.cs b/Scripts/Vivre/Items/Dismounter.cs new file mode 100644 index 0000000..43e684f --- /dev/null +++ b/Scripts/Vivre/Items/Dismounter.cs @@ -0,0 +1,126 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class Dismounter : Item + { + private bool m_Active; + private Direction m_Direction; + + [CommandProperty( AccessLevel.GameMaster )] + public bool Active + { + get { return m_Active; } + set { m_Active = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Direction Facing + { + get { return m_Direction; } + set { m_Direction = value; InvalidateProperties(); } + } + + [Constructable] + public Dismounter() : this( Direction.Down, true ) + { + } + + [Constructable] + public Dismounter( Direction dir ) : this( dir, true ) + { + } + + [Constructable] + public Dismounter( Direction dir, bool active ) : base( 0x1B7A ) + { + Movable = false; + Visible = false; + Name = "Dismounter"; + + m_Active = active; + m_Direction = dir; + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( this.Name ); + + if ( m_Active ) + list.Add( 1060742 ); // active + else + list.Add( 1060743 ); // inactive + + list.Add( (m_Direction == Direction.Mask) ? "Up" : ((Direction)m_Direction).ToString() ); + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( m_Active ) + { + LabelTo( from, "Facing " + ((m_Direction == Direction.Mask) ? "Up" : ((Direction)m_Direction).ToString()) ); + } + else + { + LabelTo( from, "(inactive)" ); + } + } + + public override bool OnMoveOver( Mobile m ) + { + if ( m_Active ) + { + if (m.Player && m.Mounted && m.AccessLevel < AccessLevel.GameMaster) + { + IMount mount = (IMount)m.Mount; + mount.Rider = null; + if (mount is BaseMount) + { + ((BaseMount)mount).Direction = m_Direction; + + // Scriptiz : ajout pour �viter les abus de certains joueurs. + ((BaseMount)mount).ControlOrder = OrderType.Stay; + } + } + } + return true; + } + + public Dismounter( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( m_Active ); + writer.Write( (int)m_Direction ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Active = reader.ReadBool(); + m_Direction = (Direction)reader.ReadInt(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Food/GreenLollipop.cs b/Scripts/Vivre/Items/Food/GreenLollipop.cs new file mode 100644 index 0000000..8788c72 --- /dev/null +++ b/Scripts/Vivre/Items/Food/GreenLollipop.cs @@ -0,0 +1,129 @@ +using System; +using Server.Network; +using Server.Mobiles; + + +namespace Server.Items +{ + public class GreenLollipop : Food + { + + [Constructable] + public GreenLollipop() + : base(1, 0x468F) + { + Name = "Une sucette au melon"; + Weight = 1.0; + FillFactor = 1; + Stackable = false; + } + + public GreenLollipop(Serial serial) + : base(serial) + { + } + + + private bool CanEat = true; + + public void ChangeCanEat() + { + CanEat = true; + } + + public override void OnDoubleClick(Mobile from) + { + if (!CanEat) + { + from.SendMessage("Laissez-vous le temps de la savourer"); + return; + } + base.OnDoubleClick(from); + } + + public override bool Eat(Mobile from) + { + + if (!IsChildOf(from.Backpack)) + { + from.SendMessage("Ceci doit être dans votre sac"); + return false; + } + + // Fill the Mobile with FillFactor + if (from is PlayerMobile) + { + CanEat = false; + Timer.DelayCall(TimeSpan.FromSeconds(3), ChangeCanEat); + // Play a random "eat" sound + from.PlaySound(Utility.Random(0x3A, 3)); + + if (from.Body.IsHuman && !from.Mounted) + from.Animate(34, 5, 1, true, false, 0); + + if (Poison != null) + from.ApplyPoison(Poisoner, Poison); + + if (from.Hunger < 20) + from.Hunger += Utility.Random(FillFactor); + + DoEffect(from); + + return true; + } + return false; + } + + public void DoEffect(Mobile from) + { + int effect = Utility.Random(30); + + if (effect <= 30 && effect >= 25) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous terminez la sucette...", from.NetState); + from.Say("Sa langue est toute verte!"); + this.Consume(); + return; + } + + if (effect <= 23 && effect >= 20) + { + from.Say("*Affiche un large sourire*"); + return; + } + + if (effect <= 18 && effect >= 15) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "*Le goût du melon vous appaise*",from.NetState); + return; + } + + if (effect <= 13 && effect >= 10) + { + from.Say("*Lèche bruyamment la sucette*"); + return; + } + + if (effect <= 5 && effect >= 0) + { + from.Say("*Joue avec le bâton de la sucette*"); + return; + } + return; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Food/HallucinogenMushroom.cs b/Scripts/Vivre/Items/Food/HallucinogenMushroom.cs new file mode 100644 index 0000000..8adf400 --- /dev/null +++ b/Scripts/Vivre/Items/Food/HallucinogenMushroom.cs @@ -0,0 +1,65 @@ +using System; +using Server.Mobiles; + +namespace Server.Items +{ + public class HallucinogenMushroom : Food + { + [Constructable] + public HallucinogenMushroom() + : base(0x1125) + { + Name = "Champignon hallucinogène"; + Stackable = true; + Weight = 1.0; + FillFactor = 1; + Poison = Utility.RandomBool() ? Poison.Regular : Poison.Lethal; + } + + public override bool Eat(Mobile from) + { + if (CheckHunger(from)) + { + from.PlaySound(Utility.Random(0x3A, 3)); + + if (from.Body.IsHuman && !from.Mounted) + from.Animate(34, 5, 1, true, false, 0); + + if (from is PlayerMobile || !from.IsHallucinated) + { + PlayerMobile junkie = from as PlayerMobile; + junkie.Hallucinating = true; + junkie.IncAddiction(new HallucinogenPotion()); + Timer.DelayCall(TimeSpan.FromMinutes(5), HallucinogenPotion.StopHallucinate, junkie); + } + else if (Poison != null) + from.ApplyPoison(Poisoner, Poison); + + Consume(); + + return true; + } + + return false; + } + + public HallucinogenMushroom(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Food/Jellybeans.cs b/Scripts/Vivre/Items/Food/Jellybeans.cs new file mode 100644 index 0000000..312a250 --- /dev/null +++ b/Scripts/Vivre/Items/Food/Jellybeans.cs @@ -0,0 +1,142 @@ +using System; +using Server.Network; +using Server.Mobiles; + + +namespace Server.Items +{ + public class Jellybeans : Food + { + private int m_Charges; + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get { return m_Charges; } + set { m_Charges = value; InvalidateProperties(); } + } + + [Constructable] + public Jellybeans() + : base(1, 0x468C) + { + Name = "Dragées surprises"; + Weight = 1.0; + FillFactor = 1; + Stackable = false; + m_Charges = 10; + } + + public Jellybeans(Serial serial) + : base(serial) + { + } + + + private bool CanEat = true; + + public void ChangeCanEat() + { + CanEat = true; + } + + public override void OnDoubleClick(Mobile from) + { + if (!CanEat) + { + from.SendMessage("Laissez-vous le temps de la savourer"); + return; + } + base.OnDoubleClick(from); + } + + public override bool Eat(Mobile from) + { + + if (!IsChildOf(from.Backpack)) + { + from.SendMessage("Ceci doit être dans votre sac"); + return false; + } + + // Fill the Mobile with FillFactor + if (from is PlayerMobile) + { + CanEat = false; + Timer.DelayCall(TimeSpan.FromSeconds(1), ChangeCanEat); + // Play a random "eat" sound + from.PlaySound(Utility.Random(0x3A, 3)); + + if (from.Body.IsHuman && !from.Mounted) + from.Animate(34, 5, 1, true, false, 0); + + if (Poison != null) + from.ApplyPoison(Poisoner, Poison); + + if (from.Hunger < 20) + from.Hunger += Utility.Random(FillFactor); + + DoEffect(from); + + return true; + } + return false; + } + + public void DoEffect(Mobile from) + { + int effect = Utility.Random(15); + string flavour = "de rien"; + + switch(effect) + { + case 0: flavour = "de pomme"; break; + case 1: flavour = "de pêche"; break; + case 2: flavour = "de poire"; break; + case 3: flavour = "de melon"; break; + case 4: flavour = "de citron"; break; + case 5: flavour = "de lime"; break; + case 6: flavour = "de raisin"; break; + case 7: flavour = "de banane"; break; + case 8: flavour = "de noix de coco"; break; + case 9: flavour = "de dattes"; break; + case 10: flavour = "de terre"; break; + case 11: flavour = "de carotte"; break; + case 12: flavour = "d'ail"; break; + case 13: flavour = "de sang"; break; + case 14: flavour = "de vomi"; break; + } + + Charges--; + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Celle-ci avait le goût " + flavour, from.NetState); + + if (Charges <= 0) + this.Consume(); + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add("{0} dragées restantes", Charges); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Charges); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_Charges = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Food/Nougat.cs b/Scripts/Vivre/Items/Food/Nougat.cs new file mode 100644 index 0000000..b22ee58 --- /dev/null +++ b/Scripts/Vivre/Items/Food/Nougat.cs @@ -0,0 +1,65 @@ +using System; +using Server.Network; +using Server.Mobiles; + + +namespace Server.Items +{ + public class Nougat : Food + { + + [Constructable] + public Nougat() + : base(1, 0x4690) + { + Name = "Morceau de nougat"; + Weight = 1.0; + FillFactor = 1; + Stackable = true; + } + + public void ChangeSpeed(Mobile from) + { + from.Send(SpeedControl.Disable); + from.SendMessage("Cette euphorie s'est dissipée"); + } + + + public override bool Eat(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendMessage("Ceci doit être dans votre sac"); + return false; + } + + if (Utility.Random(5) == 2) + { + from.SendMessage("Vous vous sentez pousser des ailes, rien ne vous arrêterait"); + from.Send(SpeedControl.MountSpeed); + Timer.DelayCall(TimeSpan.FromSeconds((int)from.RawDex/5), ChangeSpeed, from); + } + + return base.Eat(from); + } + + public Nougat(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Food/RedLollipop.cs b/Scripts/Vivre/Items/Food/RedLollipop.cs new file mode 100644 index 0000000..2a08628 --- /dev/null +++ b/Scripts/Vivre/Items/Food/RedLollipop.cs @@ -0,0 +1,130 @@ +using System; +using Server.Network; +using Server.Mobiles; + + +namespace Server.Items +{ + public class RedLollipop : Food + { + [Constructable] + public RedLollipop() + : base(1, 0x468D) + { + Name = "Une sucette à la pomme"; + Weight = 1.0; + FillFactor = 1; + Stackable = false; + } + + public RedLollipop(Serial serial) + : base(serial) + { + } + + private bool CanEat = true; + + public void ChangeCanEat() + { + CanEat = true; + } + + public override void OnDoubleClick(Mobile from) + { + if (!CanEat) + { + from.SendMessage("Laissez-vous le temps de la savourer"); + return; + } + base.OnDoubleClick(from); + } + + public override bool Eat(Mobile from) + { + + if(!IsChildOf(from.Backpack)) + { + from.SendMessage("Ceci doit être dans votre sac"); + return false; + } + + // Fill the Mobile with FillFactor + if (from is PlayerMobile) + { + CanEat = false; + Timer.DelayCall(TimeSpan.FromSeconds(3), ChangeCanEat); + + // Play a random "eat" sound + from.PlaySound(Utility.Random(0x3A, 3)); + + if (from.Body.IsHuman && !from.Mounted) + from.Animate(34, 5, 1, true, false, 0); + + if (Poison != null) + from.ApplyPoison(Poisoner, Poison); + + if (from.Hunger < 20) + from.Hunger += Utility.Random(FillFactor); + + DoEffect(from); + + return true; + } + return false; + } + + public void DoEffect(Mobile from) + { + int effect = Utility.Random(30); + + if (effect <= 30 && effect >= 25) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous terminez la sucette...", from.NetState); + from.Say("Sa langue est toute rouge!"); + this.Consume(); + return; + } + + if (effect <= 23 && effect >= 20) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "*Le goût sucré de la pomme chatouille vos papilles", from.NetState); + return; + } + + if (effect <= 18 && effect >= 15) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "*Vous salivez abondamment*",from.NetState); + return; + } + + if (effect <= 13 && effect >= 10) + { + from.Say("*Croque le bonbon, produisant un bruit sourd*"); + return; + } + + if (effect <= 5 && effect >= 0) + { + from.Say("*Lèche bruyamment la sucette*"); + return; + } + return; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + + } + } +} diff --git a/Scripts/Vivre/Items/Food/YellowLollipop.cs b/Scripts/Vivre/Items/Food/YellowLollipop.cs new file mode 100644 index 0000000..7c6796d --- /dev/null +++ b/Scripts/Vivre/Items/Food/YellowLollipop.cs @@ -0,0 +1,128 @@ +using System; +using Server.Network; +using Server.Mobiles; + + +namespace Server.Items +{ + public class YellowLollipop : Food + { + [Constructable] + public YellowLollipop() + : base(1, 0x468E) + { + Name = "Une sucette au citron"; + Weight = 1.0; + FillFactor = 1; + Stackable = false; + } + + public YellowLollipop(Serial serial) + : base(serial) + { + } + + + private bool CanEat = true; + + public void ChangeCanEat() + { + CanEat = true; + } + + public override void OnDoubleClick(Mobile from) + { + if (!CanEat) + { + from.SendMessage("Laissez-vous le temps de la savourer"); + return; + } + base.OnDoubleClick(from); + } + + public override bool Eat(Mobile from) + { + + if (!IsChildOf(from.Backpack)) + { + from.SendMessage("Ceci doit être dans votre sac"); + return false; + } + + // Fill the Mobile with FillFactor + if (from is PlayerMobile) + { + CanEat = false; + Timer.DelayCall(TimeSpan.FromSeconds(3), ChangeCanEat); + // Play a random "eat" sound + from.PlaySound(Utility.Random(0x3A, 3)); + + if (from.Body.IsHuman && !from.Mounted) + from.Animate(34, 5, 1, true, false, 0); + + if (Poison != null) + from.ApplyPoison(Poisoner, Poison); + + if (from.Hunger < 20) + from.Hunger += Utility.Random(FillFactor); + + DoEffect(from); + + return true; + } + return false; + } + + public void DoEffect(Mobile from) + { + int effect = Utility.Random(30); + + if (effect <= 30 && effect >= 25) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous terminez la sucette... enfin!", from.NetState); + from.Say("Sa langue est toute jaune!"); + this.Consume(); + return; + } + + if (effect <= 23 && effect >= 20) + { + from.Say("*Grimace*"); + return; + } + + if (effect <= 18 && effect >= 15) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, "*L'acidité du bonbon vous fait frémir*",from.NetState); + return; + } + + if (effect <= 13 && effect >= 10) + { + from.Say("*Fait cogner le bonbon contre ses dents*"); + return; + } + + if (effect <= 5 && effect >= 0) + { + from.Say("*Slurp!*"); + return; + } + return; + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/FriableRock.cs b/Scripts/Vivre/Items/FriableRock.cs new file mode 100644 index 0000000..edf897c --- /dev/null +++ b/Scripts/Vivre/Items/FriableRock.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using Server.Engines.Harvest; + +namespace Server.Items +{ + public class FriableRock : Item + { + // Type of rocks used for the coral barrier + private static List rocks = new List + { + // non passables (plus que de passables) + 6002, 6010, + //6002, 6010, + //6002, 6010, + + // passables (retirés, si on les rajoute, pensez à mettre plus de non passables + //6001, // trop petit et même couleur qu'un des non passables + //6006 + }; + + private int m_Hits; + private int m_HitsMax; + private DateTime lastHit; + + [CommandProperty(AccessLevel.GameMaster)] + public int Hits + { + get { return m_Hits; } + set + { + if (value > HitsMax) + m_Hits = HitsMax; + + if (value < 0) + return; + + m_Hits = value; + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HitsMax + { + get { return (m_HitsMax > 0 ? m_HitsMax : 1); } + set + { + if (value <= 0) + return; + + if (value < Hits) + Hits = HitsMax; + + m_HitsMax = value; + InvalidateProperties(); + } + } + + [Constructable] + public FriableRock() + : this(10) + { + } + + [Constructable] + public FriableRock(int hits) + : base(6001) + { + Name = "Rocher friable"; + + HitsMax = hits; + Hits = hits; + + // ItemID aléatoire + ItemID = rocks[Utility.Random(0, rocks.Count)]; + } + + // On ajoute le pourcentage de destruction lors du survol + public override void AddNameProperty(ObjectPropertyList list) + { + base.AddNameProperty(list); + + list.Add(String.Format("{0} %", (int)(((double)Hits / HitsMax) * 100))); + } + + // Pas besoin d'afficher le poids + public override bool DisplayWeight + { + get { return false; } + } + + // Ne Decay pas ! + public override bool Decays + { + get { return false; } + } + + // Vu qu'on laisse Movable pour avoir le pourcentage de destruction, on interdit de le prendre + public override bool OnDragLift(Mobile from) + { + from.SendMessage("C'est trop lourd ..."); + return false; + } + + public void OnHit(Mobile from, Item tool) + { + // Vérifions que le joueur ne soit pas trop loin ^^ + if(from.GetDistanceToSqrt(this.Location) > 2) + { + from.SendMessage("Vous êtes trop loin"); + return; + } + + // Pour ne pas taper dessus trop vite + if (lastHit + TimeSpan.FromSeconds(1) > DateTime.Now) + return; + + lastHit = DateTime.Now; + + // On retire un point + Hits--; + + // Petite animation + from.Direction = from.GetDirectionTo(this); + from.Animate(Utility.RandomList(Mining.System.Definitions[0].EffectActions), 5, 1, true, false, 0); + from.PlaySound(Utility.RandomList(Mining.System.Definitions[0].EffectSounds)); + + // S'il n'y a plus de points on delete le rocher + if (Hits == 0) + { + // Delete après l'animation de minage + Timer.DelayCall(TimeSpan.FromMilliseconds(900), new TimerCallback(Delete)); + + // On réduit de 1 le nombre d'utilisation de l'outil ayant servis + if (tool is IUsesRemaining) + { + ((IUsesRemaining)tool).UsesRemaining--; + } + + // Et la récompense tordue :p + int max = Utility.Random(5); + int countGem = 0; + int countOre = 0; + for (int i = 0; i < max; i++) + { + if (Utility.RandomBool()) + { + countGem++; + from.AddToBackpack(Loot.Construct(Loot.GemTypes, Utility.Random(Loot.GemTypes.Length))); + } + else + { + if (Utility.RandomBool()) + { + countOre++; + int chance = Utility.Random(100); + + if (chance > 0) + from.AddToBackpack(new IronOre()); + else + from.AddToBackpack(new SilverOre()); // environ 1 chance sur 200 + } + } + } + + if (countGem > 0) + { + from.SendMessage(String.Format("Vous avez trouver {0} gemmes", countGem)); + + if (countOre > 0) + from.SendMessage("ainsi qu'un peu de minerai..."); + } + else + { + if (countOre > 0) + from.SendMessage("Vous trouvez un peu de minerai..."); + } + } + } + + public FriableRock(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + + writer.Write(Hits); + writer.Write(HitsMax); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + Hits = reader.ReadInt(); + HitsMax = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/HairStrand.cs b/Scripts/Vivre/Items/HairStrand.cs new file mode 100644 index 0000000..f3d6c0a --- /dev/null +++ b/Scripts/Vivre/Items/HairStrand.cs @@ -0,0 +1,65 @@ +using System; +using Server.Targeting; + +namespace Server.Items +{ + public class HairStrand : Item + { + public override string DefaultName + { + get + { + return "Mèche de cheveux" + (m_HairOwner != null ? " de " + m_HairOwner.Name : ""); + } + } + + + private Mobile m_HairOwner; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile HairOwner + { + get + { + return m_HairOwner; + } + set + { + m_HairOwner = value; + } + } + + [Constructable] + public HairStrand() + : base(0x1E99) + { + Hue = 150; + Weight = 1.0; + m_HairOwner = null; + Stackable = false; + } + + public HairStrand(Serial serial) + : base(serial) + { + + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + writer.Write((Mobile)m_HairOwner); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_HairOwner = reader.ReadMobile(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Inacheve/Book/CelestialBook.cs b/Scripts/Vivre/Items/Inacheve/Book/CelestialBook.cs new file mode 100644 index 0000000..cffe207 --- /dev/null +++ b/Scripts/Vivre/Items/Inacheve/Book/CelestialBook.cs @@ -0,0 +1,294 @@ +using System; +using Server; + +namespace Server.Items +{ +public class CelestialBook : BaseBook + { + public static readonly BookContent Content = new BookContent + ( + "Notes d'une vie", "Celestial", + new BookPageInfo + ( + "This volume, and", + "others in the series,", + "are sponsored by", + "donations from Lord", + "Blackthorn, ever a", + "supporter of", + "understanding the", + "other sentient races" + ), + new BookPageInfo + ( + "of Britannia.", + "-", + "", + " The Orcish tongue", + "may fall unpleasingly", + "'pon the ear, yet it", + "has within it a", + "complex grammar oft" + ), + new BookPageInfo + ( + "misunderstood by", + "those who merely", + "hear the few broken", + "words of English our", + "orcish brothers", + "manage without", + "education.", + " These are the basic" + ), + new BookPageInfo + ( + "rules of orcish:", + " Orcish has five", + "tenses: present, past,", + "future imperfect,", + "present interjectional,", + "and prehensile.", + " Examples: gugroflu,", + "gugrofloog, gugrobo," + ), + new BookPageInfo + ( + "gugroglu!, gugrogug.", + " All transitive verbs", + "in the prehensile", + "tense end in \"ug.\"", + " Examples:", + "urgleighug,", + "biggugdaghgug,", + "curdakalmug." + ), + new BookPageInfo + ( + " All present", + "interjectional", + "conjugations start", + "with the letter G", + "unless the contain the", + "third declensive", + "accent of the letter U.", + " Examples:" + ), + new BookPageInfo + ( + "ghothudunglug, but not", + "azhbuugub.", + " The past tense can", + "only refer to events", + "since the last meal,", + "but the prehensile", + "tense can refer to", + "any event within" + ), + new BookPageInfo + ( + "reach.", + " The present tense", + "is conjugated like the", + "future imperfect", + "tense, when the", + "interrogative mode is", + "used by pitching the", + "sound a quarter-tone" + ), + new BookPageInfo + ( + "higher.", + "Orcish hath no", + "concept of person, as", + "in first person, third", + "person, I, we, etc.", + " Orcish grammar", + "relies upon the three", + "cardinal rules of" + ), + new BookPageInfo + ( + "accretion, prefixing,", + "and agglutination, in", + "addition to pitch. In", + "the former, phonemes", + "combine into larger", + "words which may", + "contain full phrasal", + "significance. In the" + ), + new BookPageInfo + ( + "second, prefixing", + "specific phonetic", + "sounds changes the", + "subject of the", + "sentence into object,", + "interrogative,", + "addressed individual,", + "or dinner." + ), + new BookPageInfo + ( + " Agglutination occurs", + "whenever four of the", + "same letter are", + "present in a word, in", + "which case, any two", + "of them may be", + "removed or slurred.", + " Pitch changes the" + ), + new BookPageInfo + ( + "phoneme value of", + "individual syllables,", + "thus completely", + "altering what a word", + "may mean. The", + "classic example is", + "\"Aktgluthugrot", + "bigglogubuu" + ), + new BookPageInfo + ( + "dargilgaglug lublublub\"", + "which can mean \"You", + "are such a pretty", + "girl,\" \"My mother ate", + "your primroses,\" or", + "\"Jellyfish nose paints", + "alms potato,\"", + "depending on pitch." + ), + new BookPageInfo + ( + " Orcish poetry often", + "relies upon repeating", + "the same phrase in", + "multiple pitches, even", + "changing pitch", + "midword. None of", + "this great art is", + "translatable." + ), + new BookPageInfo + ( + " The orcish language", + "uses the following", + "vowels: ab, ad, ag, akt,", + "at, augh, auh, azh, e,", + "i, o, oo, u, uu. The", + "vowel sound a is not", + "recognized as a vowel", + "and does not exist in" + ), + new BookPageInfo + ( + "their alphabet.", + "The orcish alphabet is", + "best learned using the", + "classic rhyme", + "repeated at 23", + "different pitches:", + " Lugnog ghu blat", + "suggaroglug," + ), + new BookPageInfo + ( + "Gaghbuu dakdar ab", + "highugbo,", + " Gothnogbuim ad", + "gilgubbugbuilug", + "Bilgeaugh thurggulg", + "stuiggro!", + "", + "A translation of the" + ), + new BookPageInfo + ( + "first pitch:", + "Eat food, the first", + "letter is ab,", + "Kill people, next letter", + "is ad,", + "I forget the rest", + "But augh is in there", + "somewhere!" + ), + new BookPageInfo + ( + "", + " What follows is a", + "complete phonetic", + "library of the orcish", + "language:", + "ab, ad, ag, akt, alm,", + "at, augh, auh, azh,", + "ba, ba, bag, bar, baz," + ), + new BookPageInfo + ( + "bid, bilge, bo, bog, bog,", + "brui, bu, buad, bug,", + "bug, buil, buim, bum,", + "buo, buor, buu, ca,", + "car, clog, cro, cuk,", + "cur, da, dagh, dagh,", + "dak, dar, deak, der,", + "dil, dit, dor, dre, dri," + ), + new BookPageInfo + ( + "dru, du, dud, duf,", + "dug, dug, duh, dun,", + "eag, eg, egg, eichel,", + "ek, ep, ewk, faugh,", + "fid, flu, fog, foo,", + "foz, fruk, fu, fub,", + "fud, fun, fup, fur,", + "gaa, gag, gagh, gan," + ), + new BookPageInfo + ( + "gar, gh, gha, ghat,", + "ghed, ghig, gho, ghu,", + "gig, gil, gka, glu, glu,", + "glug, gna, gno, gnu,", + "gol, gom, goth, grunt,", + "grut, gu, gub, gub,", + "gug, gug, gugh, guk,", + "guk," + ) + ); + + public override BookContent DefaultContent{ get{ return Content; } } + + [Constructable] + public CelestialBook() + : base(0x2252, false) + { + Hue = 1154; + } + + public CelestialBook(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.WriteEncodedInt( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadEncodedInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Inacheve/ForgeInacheve.cs b/Scripts/Vivre/Items/Inacheve/ForgeInacheve.cs new file mode 100644 index 0000000..a371d4f --- /dev/null +++ b/Scripts/Vivre/Items/Inacheve/ForgeInacheve.cs @@ -0,0 +1,75 @@ +using System; +using Server; + +namespace Server.Items +{ + public class SpecialForge : Item + { + private CraftResource m_Resource; + + [CommandProperty(AccessLevel.GameMaster)] + public CraftResource Resource + { + get { return m_Resource; } + set { m_Resource = value; Hue = CraftResources.GetHue(m_Resource); InvalidateProperties(); } + } + + + public override void AddNameProperty(ObjectPropertyList list) + { + string oreType; + string complete = "Une forge achevée"; + + switch (m_Resource) + { + case CraftResource.MShadow: oreType = "Une forge d'ombre"; break; + case CraftResource.MBloodrock: oreType = "Une Forge de sang"; break; + case CraftResource.MBlackrock: oreType = "Une forge de désespoir"; break; + case CraftResource.MVulcan: oreType = "Une forge volcanique"; break; + case CraftResource.MAcid: oreType = "Une forge toxique"; break; + case CraftResource.MAqua: oreType = "Une forge aquatique"; break; + case CraftResource.MGlowing: oreType = "Une forge céleste"; break; + default: oreType = null; break; + } + + if (oreType != null) + list.Add(oreType); + else if (m_Resource != CraftResource.None) + list.Add(complete); + else + list.Add(Name); + + } + + [Constructable] + public SpecialForge() + : base(0xFB1) + { + Stackable = false; + Name = "Forge inachevée"; + Weight = 200; + } + + public SpecialForge(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.WriteEncodedInt((int)m_Resource); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Resource = (CraftResource)reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Inacheve/Mobiles/Celestial.cs b/Scripts/Vivre/Items/Inacheve/Mobiles/Celestial.cs new file mode 100644 index 0000000..70f473e --- /dev/null +++ b/Scripts/Vivre/Items/Inacheve/Mobiles/Celestial.cs @@ -0,0 +1,176 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName("Corps de Celestial")] + public class Celestial : BaseCreature + { + [Constructable] + public Celestial() + : base(AIType.AI_Melee, FightMode.Aggressor, 5, 2, 0.2, 0.4) + { + Name = "Celestial, le forgeron divin"; + Body = 0x7B; + Hue = 0x47E; + YellowHealthbar = true; + + SetStr(609, 843); + SetDex(191, 243); + SetInt(351, 458); + + SetHits(1458, 1627); + + SetDamage(13, 19); + + SetDamageType(ResistanceType.Energy, 100); + + SetResistance(ResistanceType.Physical, 80, 90); + SetResistance(ResistanceType.Fire, 45, 50); + SetResistance(ResistanceType.Cold, 40, 50); + SetResistance(ResistanceType.Poison, 30, 40); + SetResistance(ResistanceType.Energy, 120); + + SetSkill(SkillName.Anatomy, 51.1, 74.2); + SetSkill(SkillName.EvalInt, 90.3, 99.8); + SetSkill(SkillName.Magery, 99.1, 120.0); + SetSkill(SkillName.Meditation, 90.1, 99.6); + SetSkill(SkillName.MagicResist, 90.6, 99.5); + SetSkill(SkillName.Tactics, 90.1, 99.5); + SetSkill(SkillName.Wrestling, 97.7, 100.0); + } + + public override Poison PoisonImmune { get { return Poison.Lethal; } } + public override bool BardImmune { get { return true;} } + public override bool BleedImmune{ get { return true;} } + public override bool AutoDispel{ get { return true;} } + private bool DayDmg; + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.ParalyzingBlow; + } + + public override void OnCombatantChange() + { + int hours = 0; + int minutes = 0; + + Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + + if (hours < 18 && hours > 7) + { + DayDmg = true; + } + else + { + DayDmg = false; + } + base.OnCombatantChange(); + } + + public override void CheckReflect(Mobile caster, ref bool reflect) + { + if(caster.FindItemOnLayer(Layer.Neck) is BaseJewel) + { + BaseJewel neck = (BaseJewel) caster.FindItemOnLayer(Layer.Neck); + if (neck.Resource != CraftResource.MGlowing) + reflect = false; + } + else if(Utility.RandomDouble()<0.5) + { + reflect = true; // Always reflect is not protected by Glowing + caster.SendMessage("Un porte bonheur de lumière, voilà ce qu'il manque"); + } + + return; + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + if (DayDmg && Utility.RandomDouble()<.20) + { + Say("Je me nourris de votre lumière!"); + Str += 1; + } + else if (defender.LightLevel < -8) + { + Say("Quelle noirceur! *cri de douleur*"); + AOS.Damage(this, defender, Utility.Random(10,15), true, 0, 0, 0, 0, 0, 0, 100, false, false, false); + } + base.OnGaveMeleeAttack(defender); + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + int bonusdmg = (Math.Max((int)attacker.Skills[SkillName.Chivalry].Value,(int)attacker.Skills[SkillName.Blacksmith].Value)/20); + + AOS.Damage(this, attacker, bonusdmg, true, 0, 0, 0, 0, 0, 0, 100, false, false, false); + + if(attacker is BaseCreature) + { + Say("Meurt, toi qui n'est pas digne de me reconnaitre"); + attacker.Kill(); + } + + if (attacker.FindItemOnLayer(Layer.OneHanded) is BaseWeapon) + { + BaseWeapon wpn = (BaseWeapon)attacker.FindItemOnLayer(Layer.OneHanded); + if (wpn.Resource < CraftResource.MGlowing && Utility.RandomDouble()<.10) + { + Emote("Votre arme perce sa lumière, vous offrant un second souffle"); + attacker.Heal(Utility.Random(1,15)); + } + } + + base.OnGotMeleeAttack(attacker); + } + + + public override void OnDeath(Container c) + { + SmithHammer hammer = new SmithHammer(); + hammer.Resource = CraftResource.MGlowing; + hammer.UsesRemaining = Utility.Random(100, 200); + hammer.Name = "Marteau de Celestial"; + c.DropItem(hammer); + + c.DropItem(new BlueDiamond(Utility.Random(16,25))); + + + base.OnDeath(c); + + } + + + public override int GetAttackSound() { return Utility.Random(0x2F5, 2); } + public override int GetDeathSound() { return 0x2F7; } + public override int GetAngerSound() { return 0x2F8; } + public override int GetHurtSound() { return 0x2F9; } + public override int GetIdleSound() { return 0x2FA; } + + public Celestial(Serial serial) + : base(serial) + { + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Inacheve/Mobiles/Kalientir.cs b/Scripts/Vivre/Items/Inacheve/Mobiles/Kalientir.cs new file mode 100644 index 0000000..2f4b8f4 --- /dev/null +++ b/Scripts/Vivre/Items/Inacheve/Mobiles/Kalientir.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Spells; + +namespace Server.Mobiles +{ + [CorpseName("Cadavre de Kalientir")] + public class Kalientir : BaseCreature + { + [Constructable] + public Kalientir() + : base(AIType.AI_Melee, FightMode.Aggressor, 5, 2, 0.13, 0.24) + { + Name = "Kalientir, la brulante"; + Body = 0x313; + Hue = 0x4E9; + YellowHealthbar = true; + + SetStr(609, 843); + SetDex(191, 243); + SetInt(351, 458); + + SetHits(1558, 1627); + + SetDamage(13, 19); + + SetDamageType(ResistanceType.Energy, 100); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 120); + SetResistance(ResistanceType.Cold, 20, 30); + SetResistance(ResistanceType.Poison, 70, 90); + SetResistance(ResistanceType.Energy, 50,60); + + SetSkill(SkillName.Anatomy, 51.1, 74.2); + SetSkill(SkillName.EvalInt, 90.3, 99.8); + SetSkill(SkillName.Magery, 99.1, 120.0); + SetSkill(SkillName.Meditation, 90.1, 99.6); + SetSkill(SkillName.MagicResist, 110.6, 130.5); + SetSkill(SkillName.Tactics, 90.1, 99.5); + SetSkill(SkillName.Wrestling, 97.7, 100.0); + } + + public override Poison PoisonImmune { get { return Poison.Lethal; } } + public override bool BardImmune { get { return true;} } + public override bool BleedImmune{ get { return true;} } + public override bool AutoDispel{ get { return true;} } + + + public override WeaponAbility GetWeaponAbility() + { + return WeaponAbility.MortalStrike; + } + + public override void OnCombatantChange() + { + + } + + public override void CheckReflect(Mobile caster, ref bool reflect) + { + + } + + public override void OnGaveMeleeAttack(Mobile defender) + { + + } + + public override void OnGotMeleeAttack(Mobile attacker) + { + + } + + + public override void OnDeath(Container c) + { + SmithHammer hammer = new SmithHammer(); + hammer.Resource = CraftResource.MVulcan; + hammer.UsesRemaining = Utility.Random(100, 200); + hammer.Name = "Mandibule de Kalientir"; + c.DropItem(hammer); + + c.DropItem(new FireRuby(Utility.Random(16,25))); + + + base.OnDeath(c); + + } + + + public override int GetAttackSound() { return Utility.Random(0x2F5, 2); } + public override int GetDeathSound() { return 0x2F7; } + public override int GetAngerSound() { return 0x2F8; } + public override int GetHurtSound() { return 0x2F9; } + public override int GetIdleSound() { return 0x2FA; } + + public Kalientir(Serial serial) + : base(serial) + { + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Jewel/BaseGem.cs b/Scripts/Vivre/Items/Jewel/BaseGem.cs new file mode 100644 index 0000000..d732f96 --- /dev/null +++ b/Scripts/Vivre/Items/Jewel/BaseGem.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Items +{ + public class BaseGem : Item + { + private GemType m_GemType; + + [CommandProperty(AccessLevel.Administrator)] + public GemType Gems + { + get { return m_GemType; } + set { m_GemType = value; InvalidateProperties(); } + } + + public BaseGem(int itemID) + : base(itemID) + { + } + + public BaseGem(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write( (int) 0 ); // version + writer.WriteEncodedInt((int)m_GemType); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + m_GemType = (GemType)reader.ReadEncodedInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Jewel/Diademe.cs b/Scripts/Vivre/Items/Jewel/Diademe.cs new file mode 100644 index 0000000..589a2e5 --- /dev/null +++ b/Scripts/Vivre/Items/Jewel/Diademe.cs @@ -0,0 +1,91 @@ +using System; + +namespace Server.Items +{ + public abstract class BaseDiademe : BaseJewel + { + public override int BaseGemTypeNumber { get { return 1044203; } } // star sapphire earrings + + public BaseDiademe(int itemID) + : base(itemID, Layer.Helm) + { + } + + public BaseDiademe(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + [FlipableAttribute(0x2B6E, 0x3165)] + public class Diademe : BaseDiademe + { + [Constructable] + public Diademe() + : base(0x2B6E) + { + Weight = 0.1; + } + + public Diademe(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + [FlipableAttribute(0x2B70, 0x3167)] + public class DiademeDecore : BaseDiademe + { + [Constructable] + public DiademeDecore() + : base(0x2B70) + { + Weight = 0.1; + } + + public DiademeDecore(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Jouets/PelucheBarde.cs b/Scripts/Vivre/Items/Jouets/PelucheBarde.cs new file mode 100644 index 0000000..e6c29a4 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheBarde.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PelucheBarde : Item + { + [Constructable] + public PelucheBarde() : base(0x25FB) + { + Name = "Le Barde"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheBarde(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick( Mobile from ) + { + switch (Utility.Random(5)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Euh je suis timide"); break; + case 1: from.PlaySound(0x004C); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Euh desolé c'est ma fille.."); break; + case 3: from.PlaySound(0x020B); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Je sais pas je vais demander à ma femme."); break; + } + + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PelucheBlackBear.cs b/Scripts/Vivre/Items/Jouets/PelucheBlackBear.cs new file mode 100644 index 0000000..cd33d23 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheBlackBear.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PelucheBlackBear : Item + { + [Constructable] + public PelucheBlackBear() : base( 0x2118 ) + { + Name = "Ben"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheBlackBear(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick( Mobile from ) + { + from.PlaySound(0x005f); + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + + + \ No newline at end of file diff --git a/Scripts/Vivre/Items/Jouets/PelucheBrownBear.cs b/Scripts/Vivre/Items/Jouets/PelucheBrownBear.cs new file mode 100644 index 0000000..0ec7d7f --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheBrownBear.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PelucheBrownBear : Item + { + [Constructable] + public PelucheBrownBear() : base( 0x20CF ) + { + Name = "Winnie L'Ourson"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheBrownBear( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + from.PlaySound(0x005f); + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + + + \ No newline at end of file diff --git a/Scripts/Vivre/Items/Jouets/PelucheCrystal.cs b/Scripts/Vivre/Items/Jouets/PelucheCrystal.cs new file mode 100644 index 0000000..0b57e17 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheCrystal.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PelucheCrystal : Item + { + [Constructable] + public PelucheCrystal() : base(0x25FB) + { + Name = "Crystal la barbare!"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheCrystal(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick( Mobile from ) + { + switch (Utility.Random(10)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Ragisacam tu es un homme mort..."); break; + case 1: from.PlaySound(0x005F); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Non c'est pas un bug..."); break; + case 3: from.PlaySound(0x0069); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Non ça on ne fait pas!!!"); break; + case 5: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Vous avez peté un plomb là"); break; + case 6: from.PlaySound(0x006C); break; + case 7: this.PublicOverheadMessage(MessageType.Regular, 0, false, "C'est en test là"); break; + case 8: from.PlaySound(0x0085); break; + case 9: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Encore un OUIN OUIN OUIN"); break; + } + + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PelucheDrow.cs b/Scripts/Vivre/Items/Jouets/PelucheDrow.cs new file mode 100644 index 0000000..5b77ebe --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheDrow.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PelucheDrow : Item + { + [Constructable] + public PelucheDrow() : base(0x25A4) + { + Name = "L'Elfe Noire"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheDrow(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick( Mobile from ) + { + switch (Utility.Random(5)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Je suis votre pire cauchemar"); break; + case 1: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Venez vous battre!"); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Vous brulerez en enfer"); break; + case 3: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Vous n'avez pas du Blackrock?"); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Par tous le chaos que vous êtes stupide"); break; + } + + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PelucheElfe.cs b/Scripts/Vivre/Items/Jouets/PelucheElfe.cs new file mode 100644 index 0000000..a4563f1 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheElfe.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PelucheElfe : Item + { + [Constructable] + public PelucheElfe() : base( 0x2D8A ) + { + Name = "L'Elfe des Bois"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheElfe( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + switch (Utility.Random(5)) + { + default: + case 0: this.PublicOverheadMessage( MessageType.Regular, 0, false, "Je suis votre bien aimé" ); break; + case 1: this.PublicOverheadMessage( MessageType.Regular, 0, false, "Je brule pour vous" ); break; + case 2: this.PublicOverheadMessage( MessageType.Regular, 0, false, "Emmenez-moi dans les bois" ); break; + case 3: this.PublicOverheadMessage( MessageType.Regular, 0, false, "La vie est si courte! Il faut en profiter!" ); break; + case 4: this.PublicOverheadMessage( MessageType.Regular, 0, false, "Mon dieu que vous êtes beau!" ); break; + } + + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PeluchePolarBear.cs b/Scripts/Vivre/Items/Jouets/PeluchePolarBear.cs new file mode 100644 index 0000000..8b2b2fa --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PeluchePolarBear.cs @@ -0,0 +1,40 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class PeluchePolarBear : Item + { + [Constructable] + public PeluchePolarBear() : base( 0x20E1 ) + { + Name = "Neige le Nounours"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PeluchePolarBear( Serial serial ) : base( serial ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + from.PlaySound(0x005f); + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + + + \ No newline at end of file diff --git a/Scripts/Vivre/Items/Jouets/PelucheSulfur.cs b/Scripts/Vivre/Items/Jouets/PelucheSulfur.cs new file mode 100644 index 0000000..74c0662 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheSulfur.cs @@ -0,0 +1,48 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PelucheSulfur : Item + { + [Constructable] + public PelucheSulfur() : base(0x25FB) + { + Name = "Aventurier audacieux"; + LootType = LootType.Newbied; + Weight = 1.0; + } + + public PelucheSulfur(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick( Mobile from ) + { + switch (Utility.Random(5)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Tu oses me defier !"); break; + case 1: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Je vais faire un petit tour a Hythloth,moi !"); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "J'ai 1444 d�c�s !"); break; + case 3: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Prend donc ca dans ta tronche ridicule vermine"); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Arretons les blabla passons a l'action ! aux armes !"); break; + } + + + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PelucheToubazar.cs b/Scripts/Vivre/Items/Jouets/PelucheToubazar.cs new file mode 100644 index 0000000..2dc47f8 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PelucheToubazar.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PelucheToubazar : Item + { + [Constructable] + public PelucheToubazar() : base(0x25FB) + { + Name = "Le Magnifique"; + LootType = LootType.Newbied; + Weight = 1.0; + //Couleur a introduire. + } + + public PelucheToubazar(Serial serial) : base(serial) + { + } + + public override void OnDoubleClick( Mobile from ) + { + switch (Utility.Random(9)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Comment osez vous penetrer dans l'intimite de ma chambre ! Sortez, Sortez !"); break; + case 1: this.PublicOverheadMessage(MessageType.Regular, 0, false, "C'est agacant, hein ?"); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "NON!! N'essayez pas de m'approcher !! vous avez des PUCES !!"); break; + case 3: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Regardez, je peux danser.. et courrrrrirrrr.. Sauter ! ET VOUS TUER !!!"); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Quoi ? Le Grand Toubazar ne peut plus regaler le monde de sa grace ?! Intolerable !!"); break; + case 5: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Des murs... DES MURS !!! j'en ai horreur, c'est a cause d'eux qu'on a besoin de portes !!!"); break; + case 6: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Laissez moi vous dire, vos gouts vestimentaires sont ridicules !"); break; + case 7: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Tiens un lapin !"); break; + case 8: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Decidement, je suis incroyable !! Ah, qu'il est bon d'etre MOI !! ahaha !"); break; + } + + + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PoupeeFemale.cs b/Scripts/Vivre/Items/Jouets/PoupeeFemale.cs new file mode 100644 index 0000000..1eb8c73 --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PoupeeFemale.cs @@ -0,0 +1,56 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PoupeeFemale : Item + { + [Constructable] + public PoupeeFemale() + : base(0x2107) + { + Name = NameList.RandomName("female"); + Weight = 1.0; + } + + public PoupeeFemale(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(501816); + return; + } + + + switch (Utility.Random(6)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Oh non! Mes ongles!"); break; + case 1: this.PublicOverheadMessage(MessageType.Regular, 0, false, "J'ai une amie qui... oh non... je ne suis pas une commère comme elle"); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "S'il te plaît, laisse-moi faire le ménage!"); break; + case 3: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Mon rêve? La paix dans le monde!"); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Quand je serai grande, je veux un mari pour qui cuisiner!"); break; + case 5: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Arrête, j'ai mal à la tête!"); break; + + } + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/PoupeeMale.cs b/Scripts/Vivre/Items/Jouets/PoupeeMale.cs new file mode 100644 index 0000000..185d54b --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/PoupeeMale.cs @@ -0,0 +1,52 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Items +{ + public class PoupeeMale : Item + { + [Constructable] + public PoupeeMale() : base(0x2106) + { + Name = NameList.RandomName("male"); + Weight = 1.0; + } + + public PoupeeMale(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(501816); + return; + } + + switch (Utility.Random(5)) + { + default: + case 0: this.PublicOverheadMessage(MessageType.Regular, 0, false, "T'as vu comment sa poupée est bien roulée!"); break; + case 1: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Tu me regardes encore comme ça et je t'éclate la tronche!"); break; + case 2: this.PublicOverheadMessage(MessageType.Regular, 0, false, "De la bière, vite!"); break; + case 3: this.PublicOverheadMessage(MessageType.Regular, 0, false, "Tu vois bien que je suis occupé!"); break; + case 4: this.PublicOverheadMessage(MessageType.Regular, 0, false, "En tout cas, c'est moi qui ai la plus grosse..."); break; + } + } + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/Jouets/Vaudou/VoodooDoll.cs b/Scripts/Vivre/Items/Jouets/Vaudou/VoodooDoll.cs new file mode 100644 index 0000000..e798e3c --- /dev/null +++ b/Scripts/Vivre/Items/Jouets/Vaudou/VoodooDoll.cs @@ -0,0 +1,183 @@ +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; + +namespace Server.Items +{ + public class BaseVoodooDoll : Item + { + private int m_Punishment; + + [CommandProperty(AccessLevel.GameMaster)] + public int Charges + { + get { return m_Punishment; } + set { m_Punishment = value; InvalidateProperties(); } + } + + + private Mobile m_Possessed; + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Possessed + { + get + { + return m_Possessed; + } + set + { + m_Possessed = value; + } + } + + public BaseVoodooDoll(int itemID) : base(itemID) + { + Movable = true; + Stackable = false; + Name = "Une poupée"; + m_Possessed = null; + m_Punishment = 0; + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(501816); + return; + } + + if(m_Possessed != null) + { + from.SendMessage("Cette poupée ressemble à quelqu'un... ne la laissez pas entre de mauvaises mains..."); + return; + } + from.SendMessage("Cette poupée serait plus terrible avec des cheveux!"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + } + + public void OnTarget(Mobile from, object obj) + { + if(!(obj is HairStrand)) + { + from.SendMessage("Ce ne sont pas des cheveux!"); + return; + } + + HairStrand hair = (HairStrand)obj; + + if(hair.HairOwner == null) + { + from.SendMessage("Ces cheveux doivent être des faux!"); + return; + } + + if(hair.HairOwner.Skills[SkillName.MagicResist].Value > from.Skills[SkillName.SpiritSpeak].Value) + { + from.SendMessage("La magie rémanente dans les cheveux est trop forte pour vous."); + return; + } + + if(hair.HairOwner.Female && ItemID != 0x2107) + { + from.SendMessage("Des cheveux de femme sur un corps d'homme, quelle idée!"); + return; + } + if (!hair.HairOwner.Female && ItemID != 0x2106) + { + from.SendMessage("Des cheveux d'homme sur un corps de femme, quelle idée!"); + return; + } + + from.SendMessage("Vous appliquez des cheveux à la poupée"); + m_Possessed = hair.HairOwner; + m_Punishment = (int) from.Skills[SkillName.SpiritSpeak].Value / 5; + Name += " ressemblant à " + m_Possessed.Name; + hair.Delete(); + } + + public BaseVoodooDoll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + writer.Write((Mobile)m_Possessed); + writer.Write(m_Punishment); + + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_Possessed = reader.ReadMobile(); + m_Punishment = reader.ReadInt(); + } + } + + + public class VoodooDollFemale : BaseVoodooDoll + { + + [Constructable] + public VoodooDollFemale() : base(0x2107) + { + } + + public VoodooDollFemale(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class VoodooDollMale : BaseVoodooDoll + { + + [Constructable] + public VoodooDollMale() + : base(0x2106) + { + } + + public VoodooDollMale(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/MetalRegs.cs b/Scripts/Vivre/Items/MetalRegs.cs new file mode 100644 index 0000000..c7d070d --- /dev/null +++ b/Scripts/Vivre/Items/MetalRegs.cs @@ -0,0 +1,72 @@ +using System; + +namespace Server.Items +{ + public class TitanTooth : Item + { + + [Constructable] + public TitanTooth() + : base(0x5747) + { + Name = "Dent de Titan"; + Movable = true; + Stackable = true; + } + + public TitanTooth(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + if (!Stackable) + Stackable = true; + } + } + + public class TitanToothPowder : Item + { + + [Constructable] + public TitanToothPowder() + : base(0x573D) + { + Name = "Poudre de Dent de Titan"; + Movable = true; + Stackable = true; + } + + public TitanToothPowder(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + if (!Stackable) + Stackable = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Peddler Item/DragonLamp.cs b/Scripts/Vivre/Items/Peddler Item/DragonLamp.cs new file mode 100644 index 0000000..d19d702 --- /dev/null +++ b/Scripts/Vivre/Items/Peddler Item/DragonLamp.cs @@ -0,0 +1,59 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class DragonLantern : BaseLight + { + public override int LitItemID{ get { return 0x49C1; } } + public override int UnlitItemID{ get { return 0x49C2; } } + public override int LitSound{ get { return 362; } } + + + [Constructable] + public DragonLantern() : base(0x49C2) + { + Name = "La Lanterne du Grand Dragon"; + Movable = true; + Duration = TimeSpan.Zero; // Never burnt out + Burning = false; + Weight = 3.0; + Light = LightType.Circle300; + } + + public override void OnDoubleClick(Mobile from) + { + if (this.IsLockedDown) + { + if (this.ItemID == 0x49C2) + { + from.PlaySound(362); + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052); + } + else + Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3709, 1, 30, 1108, 6, 9904, 0); + + base.OnDoubleClick(from); + } + else + from.SendMessage("Vous devez d'abord poser cette oeuvre d'art dans un endroit convenable"); + } + + public DragonLantern( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/PoteauArnachement.cs b/Scripts/Vivre/Items/PoteauArnachement.cs new file mode 100644 index 0000000..cb96dee --- /dev/null +++ b/Scripts/Vivre/Items/PoteauArnachement.cs @@ -0,0 +1,491 @@ +/* + * MODIFICATIONS + * + * NUM�RO DATE AUTEUR + * ------ ---------- ------ + * #01 2007-06-30 Merlock + * > L'animal devient invul + * #02 2008-03-08 Gargouille + * > le temps pass� attach� ne compte plus pour le Bonding + * #03 2008-03-13 Merlock + * > les poteaux de villes !!! + * #04 partage du pet entre lesmobs de l'account //Corrected by Plume + * */ +using System; +using Server; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; +using Server.Commands; +using Server.Multis; +using Server.Accounting;//#04 + +namespace Server.Items +{ + public class LPTarget : Target + { + public LPTarget() + : base( 5, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is PoteauArnachement ) + { + PoteauArnachement pa = (PoteauArnachement)targeted; + BaseHouse bh = BaseHouse.FindHouseAt( pa ); + if ( pa == null || bh == null || ( !bh.IsOwner( from ) && !bh.IsCoOwner( from ) ) || pa.Animal == null ) + from.SendMessage( "Vous devez cibler un poteau avec une monture attach�e qui est sur votre terrain !!" ); + else + { + pa.Libere( null ); + from.SendMessage( "La monture s'en va d'elle-m�me" ); + } + } + else + from.SendMessage( "Vous devez cibler un poteau" ); + } + } + + public class CPTarget : Target + { + public CPTarget() + : base( 5, false, TargetFlags.None ) + { + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( targeted is PoteauArnachement && !( targeted is PoteauDeVille ) ) + { + PoteauArnachement pa = (PoteauArnachement)targeted; + PoteauDeVille pdv = new PoteauDeVille(); + pdv.Location = pa.Location; + pdv.Map = pa.Map; + pdv.Movable = false; + pdv.Animal = pa.Animal; + pdv.Maitre = pa.Maitre; + pdv.Loyaute = pa.Loyaute; + pdv.AI = pa.AI; + pa.Delete(); + from.SendMessage( "Le poteau est maintenant un poteau de ville" ); + } + else + from.SendMessage( "Ceci n'est pas un poteau de joueur" ); + } + } + + [FlipableAttribute( 0x14E7, 0x14E8 )] + public class PoteauDeVille : PoteauArnachement + { + public new static void Initialize() + { + CommandSystem.Register( "ConvertPoteau", AccessLevel.Counselor, new CommandEventHandler( ConvertPoteau_OnCommand ) ); + } + + private static void ConvertPoteau_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Vous devez cibler un poteau de joueur a convertir" ); //You have to choose a mobile + e.Mobile.Target = new CPTarget(); + } + + private DateTime m_TempsRestant; + [CommandProperty( AccessLevel.GameMaster )] + public DateTime TempsRestant + { + get + { + return m_TempsRestant; + } + set + { + m_TempsRestant = value; + } + } + + [Constructable] + public PoteauDeVille() + { + } + + public PoteauDeVille( Serial serial ) + : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (DateTime)m_TempsRestant ); + + if(Animal != null && m_TempsRestant + TimeSpan.FromHours(12) < DateTime.Now) + Libere(null); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + m_TempsRestant = reader.ReadDateTime(); + } + } + + [FlipableAttribute( 0x14E7, 0x14E8 )] + public class PoteauArnachement : Item + { + public static void Initialize() + { + CommandSystem.Register( "LiberePoteau", AccessLevel.Player, new CommandEventHandler( LiberePoteau_OnCommand ) ); + } + + private static void LiberePoteau_OnCommand( CommandEventArgs e ) + { + e.Mobile.SendMessage( "Vous devez cibler un poteau" ); //You have to choose a mobile + e.Mobile.Target = new LPTarget(); + } + + private Mobile m_Maitre; + private BaseCreature m_Animal; + private int m_Loyaute; + private AIType m_AI; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile Maitre + { + get + { + return m_Maitre; + } + set + { + m_Maitre = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public BaseCreature Animal + { + get + { + return m_Animal; + } + set + { + m_Animal = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Loyaute + { + get + { + return m_Loyaute; + } + set + { + m_Loyaute = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public AIType AI + { + get + { + return m_AI; + } + set + { + m_AI = value; + } + } + + [Constructable] + public PoteauArnachement() + : base( 0x14E8 ) + { + Weight = 10.0; + Name = "Poteau d'arnachement"; + } + + public PoteauArnachement( Serial serial ) + : base( serial ) + { + } + + public void Libere( Mobile from ) + { + m_Animal.Blessed = false; // Ajout #01 + + /* + //***Ajout #02 d�but + if ( m_Animal.IsBondable && !m_Animal.IsBonded && ( m_Animal.BondingBegin != DateTime.MinValue ) ) + { + TimeSpan inactive = (TimeSpan)( DateTime.Now - m_Animal.LastStable ); + m_Animal.BondingBegin += inactive; + } + m_Animal.LastStable = DateTime.MinValue; + //***Ajout #02 fin + * */ + + if ( from == null ) + { + m_Animal.Tamable = true; + m_Animal.Controlled = false; + m_Animal.Loyalty = m_Loyaute; + m_Animal.AI = m_AI; + m_Animal.ControlOrder = OrderType.Release; + m_Animal = null; + } + else + { + m_Animal.Tamable = true; + m_Animal.Controlled = true; + m_Animal.ControlMaster = m_Maitre; + m_Animal.Loyalty = m_Loyaute; + m_Animal.AI = m_AI; + m_Animal.ControlTarget = m_Maitre; + m_Animal.ControlOrder = OrderType.Follow; + m_Animal = null; + from.Say( "*d�tache sa monture*" ); + } + } + + public override void OnDoubleClick( Mobile from ) + { + if (this.Movable) + { + //from.SendMessage("Le poteau doit �tre fix� au sol pour pouvoir l'utiliser"); + + // Scriptiz : on ajoute le fait qu'un double clic lock l'item si il est devant la maison + BaseHouse house = BaseHouse.FindHouseAt(this.Location, this.Map, 16); // dans la maison + + if (house == null) house = BaseHouse.FindHouseAt(new Point3D(this.X, this.Y - 1, this.Z), this.Map, 16); // devant la maison + if (house == null) house = BaseHouse.FindHouseAt(new Point3D(this.X - 1, this.Y, this.Z), this.Map, 16); // � droite de la maison + + // Pas de maison trouv�e + if (house == null) + { + from.SendMessage("Pour fixer le poteau au sol il doit se trouver dans ou devant une maison."); + return; + } + + // pas propri�taire de la maison + if (!house.IsOwner(from) || !house.IsCoOwner(from)) + { + from.SendMessage("Ce poteau ne peux pas �tre plac� dans ou devant une maison qui ne vous appartient pas."); + return; + } + + this.Movable = false; + from.SendMessage("Le poteau a �t� fix� au sol, vous pouvez d�sormais l'utiliser."); + from.SendMessage("Pour le retirer double cliquer dessus puis ciblez le poteau."); + } + else if (!from.InRange(this.GetWorldLocation(), 2)) + from.SendLocalizedMessage(500486); //That is too far away. + else if (Animal != null) + { + if (m_Animal.Deleted) + m_Animal = null; + else + { + if (Maitre == null || Maitre.Deleted) + { + Libere(null); + from.SendMessage("La monture s'en va d'elle-m�me"); + } + else if (from == m_Maitre || CheckAccount(from)) + { + //if (from.Skills[SkillName.AnimalTaming].Base < m_Animal.MinTameSkill && m_Animal.MinTameSkill > 29.1)//#04 + //from.SendMessage("Vous n'�tes pas en mesure de controler cette cr�ature."); + + if (from.Followers + m_Animal.ControlSlots > from.FollowersMax) + from.SendMessage("Vous avez trop de suivant pour d�tacher cette cr�ature."); + else + { + // Scriptiz : am�lioration des control chance // Plume : On retire cette condition, inutile... + /* if (!(m_Animal is BaseMount) && !m_Animal.CheckControlChance(from)) + from.SendMessage("Vous n'�tes pas en mesure de controler cette cr�ature."); + else*/ + Libere(from); + } + } + else + from.SendMessage("Ce poteau est d�j� utilis� par {0}", m_Maitre.Name); + } + } + else + { + from.Target = new PoteauArnachementTarget(this); + from.SendMessage("Quel animal voulez vous attacher ?"); + } + } + + //#04 + private bool CheckAccount(Mobile from) + { + Account a = Maitre.Account as Account; + + if ( a != null ) + { + for ( int i = 0; i < a.Length; ++i ) + { + if ( a[i] == from ) + { + m_Maitre = a[i]; + return true; + } + } + } + + return false; + } + // + + private class PoteauArnachementTarget : Target + { + private PoteauArnachement m_Poteau; + + public PoteauArnachementTarget( PoteauArnachement poteau ) + : base( 1, true, TargetFlags.None ) + { + m_Poteau = poteau; + } + + protected override void OnTarget( Mobile from, object targ ) + { + if ( !( m_Poteau.Deleted ) ) + { + // Scriptiz : on ajoute le fait qu'un double clic d�lock l'item si on le cible lui m�me + if (targ is PoteauArnachement) + { + if (targ != m_Poteau) + { + from.SendMessage("Vous devez cibler le m�me poteau pour le retirer du sol."); + return; + } + + BaseHouse house = BaseHouse.FindHouseAt(m_Poteau.Location, m_Poteau.Map, 16); // dans la maison + + if (house == null) house = BaseHouse.FindHouseAt(new Point3D(m_Poteau.X, m_Poteau.Y - 1, m_Poteau.Z), m_Poteau.Map, 16); // devant la maison + if (house == null) house = BaseHouse.FindHouseAt(new Point3D(m_Poteau.X - 1, m_Poteau.Y, m_Poteau.Z), m_Poteau.Map, 16); // � droite de la maison + + // pas propri�taire de la maison + if (house != null && (!house.IsOwner(from) || !house.IsCoOwner(from))) + { + from.SendMessage("Vous ne pouvez pas d�tacher un poteau d'une maison qui ne vous appartient pas."); + return; + } + + // Pas de maison trouv�e + if (house == null) + from.SendMessage("Le poteau n'est plus li� a une maison et vous pouvez donc le retirer du sol."); + else + from.SendMessage("Le poteau a �t� retir� du sol, vous pouvez d�sormais le ramasser."); + + m_Poteau.Movable = true; + + return; + } + + if ( targ is BaseMount || targ is PackHorse || targ is PackLlama ) + { + BaseCreature creature = targ as BaseCreature; + + if ( ( creature.Controlled && creature.ControlMaster == from ) ) + { + m_Poteau.Animal = creature; + m_Poteau.Maitre = from; + m_Poteau.Loyaute = creature.Loyalty; + m_Poteau.AI = creature.AI; + creature.AI = AIType.AI_None; + //creature.Controlled = false; + creature.Tamable = false; + creature.ControlMaster = null; + creature.Blessed = true; // Ajout #01 + + /* + //***Ajout #02 d�but + if ( creature.IsBondable && !creature.IsBonded && ( creature.BondingBegin != DateTime.MinValue ) ) + { + creature.LastStable = DateTime.Now; + } + //***Ajout #02 fin + */ + + if ( m_Poteau is PoteauDeVille ) + ( (PoteauDeVille)m_Poteau ).TempsRestant = DateTime.Now; + + from.Say( "*attache sa monture au poteau*" ); + } + else if ( creature.AI == AIType.AI_None ) + { + from.SendMessage( "Cette creature est d�j� attach�e !" ); + } + else + { + from.SendMessage( "Cette creature n'est pas sous votre controle !" ); + } + } + else if ( targ is PlayerMobile ) + { + Mobile m = (Mobile)targ; + + if ( m == from ) + { + from.Say( "*a essaye de s'attacher au poteau*" ); + } + else + { + from.Say( "*a essaye d'attacher {0}, mais n'a pas reussi", m.Name ); + } + } + else + { + from.SendMessage( "Cette creature n'est pas une monture !" ); + } + } + return; + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int)0 ); // version + + writer.Write( (Mobile)m_Animal ); + writer.Write( (Mobile)m_Maitre ); + writer.Write( (int)m_Loyaute ); + writer.Write( (int)m_AI ); + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Animal = (BaseCreature)reader.ReadMobile(); + m_Maitre = reader.ReadMobile(); + m_Loyaute = reader.ReadInt(); + m_AI = (AIType)reader.ReadInt(); + break; + } + } + } + } +} diff --git a/Scripts/Vivre/Items/Potions/Clumsy Potions/BaseClumsyPotion.cs b/Scripts/Vivre/Items/Potions/Clumsy Potions/BaseClumsyPotion.cs new file mode 100644 index 0000000..4f9a742 --- /dev/null +++ b/Scripts/Vivre/Items/Potions/Clumsy Potions/BaseClumsyPotion.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Targeting; +using Server.Spells; +using Server.Mobiles; +using Server.Misc; + +namespace Server.Items +{ + public abstract class BaseClumsyPotion : BasePotion + { + public override bool CIT { get { return true; } } + public override bool CIS { get { return true; } } + private int Radius = 4; + public abstract int DexOffset { get; } + public abstract TimeSpan Duration { get; } + + public BaseClumsyPotion(PotionEffect effect) + : base(0xF08, effect) + { + } + + public BaseClumsyPotion( Serial serial ) : base( serial ) + { + } + + public void DoClumsy(Mobile from) + { + //Plume : Addiction + if (from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + + double CurrentAddiction = drinker.CalculateAgilityAddiction(this)[0]; + double GlobalAddiction = drinker.CalculateAgilityAddiction(this)[1]; + int DexScalar = (int)Math.Floor(Math.Sqrt(CurrentAddiction/2)); + double DurationScalar = GlobalAddiction * 0.95; + + if (GlobalAddiction > 100) + { + drinker.SendMessage("Votre corps ne supporte plus ce traitement"); + drinker.Dex --; + return; + } + + if ( Spells.SpellHelper.AddStatOffset( from, StatType.Dex, (Scale( from, DexOffset+Math.Min(DexOffset,DexScalar))*-1),Duration+ TimeSpan.FromSeconds(DurationScalar )) ) + { + from.FixedEffect( 0x375A, 10, 15 ); + from.PlaySound( 0x1E7 ); + return; + } + drinker.IncAddiction(this); + } + + if ( Spells.SpellHelper.AddStatOffset( from, StatType.Dex, Scale( from, DexOffset), Duration ) ) + { + from.FixedEffect( 0x375A, 10, 15 ); + from.PlaySound( 0x1E7 ); + return; + } + + from.SendLocalizedMessage( 502173 ); // You are already under a similar effect. + return; + } + + public override void Drink(Mobile from) + { + if (Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting))) + { + from.SendLocalizedMessage(1062725); // You can not use that potion while paralyzed. + return; + } + + int delay = GetDelay(from); + + if (delay > 0) + { + from.SendLocalizedMessage(1072529, String.Format("{0}\t{1}", delay, delay > 1 ? "seconds." : "second.")); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~ + return; + } + + ThrowTarget targ = from.Target as ThrowTarget; + + if (targ != null && targ.Potion == this) + return; + + from.RevealingAction(); + + if (!m_Users.Contains(from)) + m_Users.Add(from); + + from.Target = new ThrowTarget(this); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private List m_Users = new List(); + + public void Explode_Callback(object state) + { + object[] states = (object[])state; + + Explode((Mobile)states[0], (Point3D)states[1], (Map)states[2]); + } + + public virtual void Explode(Mobile from, Point3D loc, Map map) + { + if (Deleted || map == null) + return; + + Consume(); + + // Check if any other players are using this potion + for (int i = 0; i < m_Users.Count; i++) + { + ThrowTarget targ = m_Users[i].Target as ThrowTarget; + + if (targ != null && targ.Potion == this) + Target.Cancel(from); + } + + // Effects + Effects.PlaySound(loc, map, 0x207); + + Geometry.Circle2D(loc, map, Radius, new DoEffect_Callback(BlastEffect), 270, 90); + + Timer.DelayCall(TimeSpan.FromSeconds(0.3), new TimerStateCallback(CircleEffect2), new object[] { loc, map }); + + foreach (Mobile mobile in map.GetMobilesInRange(loc, Radius)) + { + this.DoClumsy(from); + } + } + + #region Effects + public virtual void BlastEffect(Point3D p, Map map) + { + if (map.CanFit(p, 12, true, false)) + Effects.SendLocationEffect(p, map, 0x376A, 4, 9); + } + + public void CircleEffect2(object state) + { + object[] states = (object[])state; + + Geometry.Circle2D((Point3D)states[0], (Map)states[1], Radius, new DoEffect_Callback(BlastEffect), 90, 270); + } + #endregion + + #region Delay + private static Hashtable m_Delay = new Hashtable(); + + public static void AddDelay(Mobile m) + { + Timer timer = m_Delay[m] as Timer; + + if (timer != null) + timer.Stop(); + + m_Delay[m] = Timer.DelayCall(TimeSpan.FromSeconds(60), new TimerStateCallback(EndDelay_Callback), m); + } + + public static int GetDelay(Mobile m) + { + Timer timer = m_Delay[m] as Timer; + + if (timer != null && timer.Next > DateTime.Now) + return (int)(timer.Next - DateTime.Now).TotalSeconds; + + return 0; + } + + private static void EndDelay_Callback(object obj) + { + if (obj is Mobile) + EndDelay((Mobile)obj); + } + + public static void EndDelay(Mobile m) + { + Timer timer = m_Delay[m] as Timer; + + if (timer != null) + { + timer.Stop(); + m_Delay.Remove(m); + } + } + #endregion + + private class ThrowTarget : Target + { + private BaseClumsyPotion m_Potion; + + public BaseClumsyPotion Potion + { + get { return m_Potion; } + } + + public ThrowTarget(BaseClumsyPotion potion) + : base(12, true, TargetFlags.None) + { + m_Potion = potion; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Potion.Deleted || m_Potion.Map == Map.Internal) + return; + + IPoint3D p = targeted as IPoint3D; + + if (p == null || from.Map == null) + return; + + // Add delay + BaseClumsyPotion.AddDelay(from); + + SpellHelper.GetSurfaceTop(ref p); + + from.RevealingAction(); + + IEntity to; + + if (p is Mobile) + to = (Mobile)p; + else + to = new Entity(Serial.Zero, new Point3D(p), from.Map); + + Effects.SendMovingEffect(from, to, 0xF0D, 7, 0, false, false, m_Potion.Hue, 0); + Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(m_Potion.Explode_Callback), new object[] { from, new Point3D(p), from.Map }); + } + } + } +} diff --git a/Scripts/Vivre/Items/Potions/Clumsy Potions/ClumsyPotion.cs b/Scripts/Vivre/Items/Potions/Clumsy Potions/ClumsyPotion.cs new file mode 100644 index 0000000..c70a626 --- /dev/null +++ b/Scripts/Vivre/Items/Potions/Clumsy Potions/ClumsyPotion.cs @@ -0,0 +1,35 @@ +using System; +using Server; + +namespace Server.Items +{ + public class ClumsyPotion : BaseAgilityPotion + { + public override int DexOffset { get { return IntensifiedStrength ? 9 : 6; } } + public override TimeSpan Duration{ get{ return TimeSpan.FromMinutes( IntensifiedTime ? 2.5:1.5); } } + + [Constructable] + public ClumsyPotion() : base( PotionEffect.Clumsy ) + { + } + + public ClumsyPotion(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Potions/Clumsy Potions/GreaterClumsyPotion.cs b/Scripts/Vivre/Items/Potions/Clumsy Potions/GreaterClumsyPotion.cs new file mode 100644 index 0000000..fe91642 --- /dev/null +++ b/Scripts/Vivre/Items/Potions/Clumsy Potions/GreaterClumsyPotion.cs @@ -0,0 +1,34 @@ +using System; +using Server; + +namespace Server.Items +{ + public class GreaterClumsyPotion : BaseAgilityPotion + { + public override int DexOffset{ get{ return IntensifiedStrength?15:12; } } + public override TimeSpan Duration{ get{ return TimeSpan.FromMinutes( IntensifiedTime?2.5:1.5 ); } } + + [Constructable] + public GreaterClumsyPotion() : base( PotionEffect.ClumsyGreater ) + { + } + + public GreaterClumsyPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Potions/FrogMorph.cs b/Scripts/Vivre/Items/Potions/FrogMorph.cs new file mode 100644 index 0000000..952e363 --- /dev/null +++ b/Scripts/Vivre/Items/Potions/FrogMorph.cs @@ -0,0 +1,54 @@ +using System; +using Server; +namespace Server.Items +{ + public class FrogMorphPotion : BasePotion + { + [Constructable] + public FrogMorphPotion() : base( 0xF07, PotionEffect.FrogMorph ) + { + Name = "Potion d'amour v�ritable"; + Hue = 0x2D; + Stackable =true; + } + + public FrogMorphPotion(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + + } + + public override void Drink( Mobile from ) + { + from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); + from.PlaySound(0x1E3); + + BasePotion.PlayDrinkEffect(from); + + from.BodyValue = 0x51; + if(from.Female) + from.SendMessage("Trouvez-vous un Prince"); + else + from.SendMessage("Trouvez-vous une Princesse"); + + from.Say("*L�che la potion, une grimace de douleur d�figurant son visage*"); + this.Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Potions/GenderPotion.cs b/Scripts/Vivre/Items/Potions/GenderPotion.cs new file mode 100644 index 0000000..eaaf7cc --- /dev/null +++ b/Scripts/Vivre/Items/Potions/GenderPotion.cs @@ -0,0 +1,78 @@ +using System; +using Server; +//Plume : Transformation en fiole +namespace Server.Items +{ + public class GenderPotion : BasePotion + { + private bool m_Female; + + [CommandProperty(AccessLevel.GameMaster)] + public bool Female + { + get { return m_Female; } + set { m_Female = value; InvalidateProperties(); } + } + + [Constructable] + public GenderPotion() : base( 0x0E24, PotionEffect.GenderSwap ) + { + Name = "Potion rouge et noire"; + Hue = 2075; + Stackable =false; + m_Female = Utility.RandomBool(); + + if (!m_Female) + Name = "Potion noire et rouge"; + } + + public GenderPotion( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + + writer.Write((bool)m_Female); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch(version) + { + case 1: m_Female = reader.ReadBool(); break; + } + + if (ItemID == 0xF06) + ItemID = 0x0E24; + } + + public override void Drink( Mobile from ) + { + from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); + from.PlaySound(0x1E3); + + BasePotion.PlayDrinkEffect(from); + + if (from.Female == this.Female) + { + from.SendMessage("Vous buvez le tout et attendez... vous pourriez attendre tr�s longtemps..."); + this.Delete(); + from.AddToBackpack(new AlchemyVial()); + return; + } + + from.Female = this.Female; + + from.Say("*L�che la potion, une grimace de douleur d�figurant son visage*"); + this.Delete(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Potions/HallucinatingPotion.cs b/Scripts/Vivre/Items/Potions/HallucinatingPotion.cs new file mode 100644 index 0000000..5ddec39 --- /dev/null +++ b/Scripts/Vivre/Items/Potions/HallucinatingPotion.cs @@ -0,0 +1,60 @@ +using System; +using Server; +using Server.Mobiles; +namespace Server.Items +{ + public class HallucinogenPotion : BasePotion + { + [Constructable] + public HallucinogenPotion() : base( 0xF07, PotionEffect.Hallucinogen ) + { + Name = "Potion hallucinog�ne"; + Hue = 0x369; + Stackable =true; + } + + public HallucinogenPotion(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0); // version + + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + + } + + public override void Drink( Mobile from ) + { + from.FixedParticles(0x376A, 9, 32, 5007, EffectLayer.Waist); + from.PlaySound(0x1E3); + + BasePotion.PlayDrinkEffect(from); + if(from is PlayerMobile) + { + PlayerMobile drinker = from as PlayerMobile; + drinker.Hallucinating = true; + Timer.DelayCall(TimeSpan.FromSeconds(180), StopHallucinate, drinker); + } + this.Consume(); + } + + public static void StopHallucinate(PlayerMobile from) + { + + from.Hallucinating = false; + from.SendMessage("Cette euphorie s'est dissip�e"); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/PowerCrystal/NewPowerCrystal.cs b/Scripts/Vivre/Items/PowerCrystal/NewPowerCrystal.cs new file mode 100644 index 0000000..cbb37df --- /dev/null +++ b/Scripts/Vivre/Items/PowerCrystal/NewPowerCrystal.cs @@ -0,0 +1,181 @@ +//Incomplet jusqu'à nouvel ordre. Suffisant pour les Irons Beetles +using System; +using Server.Mobiles; +using Server.Network; +using Server.Targeting; +using Server.ContextMenus; +using System.Collections.Generic; + +namespace Server.Items +{ + public class MysticPowerCrystal : Item + { + private int m_Completion; + + [CommandProperty(AccessLevel.GameMaster)] + public int Completion + { + get + { + return m_Completion; + } + set + { + m_Completion = value; InvalidateProperties(); + } + } + + + [Constructable] + public MysticPowerCrystal() + : base(0x1F1C) + { + Name = "Crystal de Pouvoir"; + Movable = true; + Stackable = false; + Completion = 0; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + list.Add("{0} %", Completion); + } + + public override void OnDoubleClick(Mobile from) + { + if(!IsChildOf(from.Backpack)) + { + from.SendMessage("Le crystal doit être entre vos mains"); + } + else if (Completion == 100) + { + from.SendMessage("Le crystal ne pourrait absorber davantage de pouvoir!"); + } + else + { + from.SendMessage("Quel pouvoir souhaitez-vous absorber?"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(AbsorbTarget)); + } + + base.OnDoubleClick(from); + } + + public void AbsorbTarget(Mobile from, object obj) + { + if (!(obj is Beetle)) + { + from.SendMessage("Ce pouvoir vous serait inutile pour la seule utilisation actuelle de ce crystal..."); + return; + } + + Beetle targ = (Beetle)obj; + + if(!targ.Controlled || targ.ControlMaster != from || !targ.IsBonded) + { + from.SendMessage("La créature à qui vous capturerez l'âme doit vous être fortement liée."); + return; + } + + bool skill = from.CheckSkill(SkillName.Mysticism, 10, 60); + + if (!skill) + { + from.SendMessage("Vous échouez dans votre tentative d'absorber l'âme de cette créature"); + + int bad = Utility.Random(1, 100); + if (bad == 5) + { + targ.Emote("S'effondre au sol, inerte"); + targ.IsBonded = false; + targ.Kill(); + } + else if (bad > 5 && bad <9) + { + targ.Emote("S'effondre au sol, inanimée"); + targ.Kill(); + } + else if (bad < 4) + { + from.Emote("Le Crystal explore"); + this.Delete(); + } + else if (bad > 10 && bad < 20) + { + targ.Emote("Faiblit"); + targ.Str--; + if (targ.Str == 0) + targ.Delete(); + } + else if (bad > 20 && bad < 30) + { + targ.Emote("Faiblit"); + targ.Dex--; + if (targ.Dex == 0) + targ.Delete(); + } + else if (bad > 30 && bad < 40) + { + targ.Emote("Faiblit"); + targ.Int--; + if (targ.Int == 0) + targ.Delete(); + } + return; + } + + from.SendMessage("Vous absorbez une partie de l'âme de la bête"); + this.Completion += Math.Max(Utility.Random(1, 2), (int)from.Skills[SkillName.Mysticism].Value / 10); + + if (Completion > 100) + Completion = 100; + + if (!from.CheckSkill(SkillName.AnimalLore, 0, 40)) + { + targ.Emote("Exprime une douleur intense et ne semble pas vous reconnaitre"); + targ.IsBonded = false; + targ.Controlled = false; + targ.ControlMaster = null; + } + else if (!from.CheckSkill(SkillName.AnimalLore, 0, 120)) + { + targ.Emote("Exprime une douleur intense et vous observe avec crainte"); + targ.IsBonded = false; + } + else + targ.Emote("Semble ne pas comprendre"); + + return; + } + + public MysticPowerCrystal(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + writer.Write((int)m_Completion); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + int m_Completion = reader.ReadInt(); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (from.Alive && (Completion > 20)) + list.Add(new ContextMenus.PowerCrystalMenu(from, this)); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/PowerCrystal/PowerCrystalMenu.cs b/Scripts/Vivre/Items/PowerCrystal/PowerCrystalMenu.cs new file mode 100644 index 0000000..d010ca5 --- /dev/null +++ b/Scripts/Vivre/Items/PowerCrystal/PowerCrystalMenu.cs @@ -0,0 +1,53 @@ +using System; +using Server.Items; +using Server.Targeting; + +namespace Server.ContextMenus +{ + public class PowerCrystalMenu : ContextMenuEntry + { + private Mobile m_From; + private MysticPowerCrystal m_Crystal; + + public PowerCrystalMenu(Mobile from, MysticPowerCrystal Crystal) + : base(5114, 1) + { + m_From = from; + m_Crystal = Crystal; + } + + public override void OnClick() + { + m_From.SendMessage("Que souhaitez-vous imprégner de ce pouvoir?"); + m_From.BeginTarget(2, false, TargetFlags.None, new TargetCallback(PowerTarget)); + } + + public void PowerTarget(Mobile from, object obj) + { + if (!(obj is IronBeetleBody)) + { + m_From.SendMessage("Cela ne servirait à rien sur cet objet"); + return; + } + + IronBeetleBody targ = (IronBeetleBody)obj; + + if (targ.SummonScalar != 0) + { + from.SendMessage("Ce corps est déjà été imprégné d'une âme"); + return; + } + from.SendMessage("L'esprit contenu dans le Crystal se dissipe sur la carapace"); + targ.SummonScalar = m_Crystal.Completion / 100; + + if (!from.CheckSkill(SkillName.Mysticism, 60)) + { + from.SendMessage("Le crystal se brise pendant le transfert"); + m_Crystal.Delete(); + } + + m_Crystal.Completion = 0; + return; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Resources/BasketFrame.cs b/Scripts/Vivre/Items/Resources/BasketFrame.cs new file mode 100644 index 0000000..3c2af84 --- /dev/null +++ b/Scripts/Vivre/Items/Resources/BasketFrame.cs @@ -0,0 +1,36 @@ +using System; + +namespace Server.Items +{ + public class BasketFrame : Item + { + + [Constructable] + public BasketFrame() + : base(0x407B) + { + Movable = true; + Stackable = false; + Name = "Corps de panier"; + } + + public BasketFrame(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Resources/Cacao.cs b/Scripts/Vivre/Items/Resources/Cacao.cs new file mode 100644 index 0000000..15f763b --- /dev/null +++ b/Scripts/Vivre/Items/Resources/Cacao.cs @@ -0,0 +1,68 @@ +using System; + +namespace Server.Items +{ + public class CacaoSeed : Item + { + + [Constructable] + public CacaoSeed() : base(0xF19) + { + Movable = true; + Stackable = true; + Name = "F�ve de cacao"; + Hue = 57; + } + + public CacaoSeed(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } + + public class CacaoPowder : Item + { + + [Constructable] + public CacaoPowder() : base(0x573D) + { + Movable = true; + Stackable = true; + Name = "Poudre de cacao"; + Hue = 57; + } + + public CacaoPowder(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Resources/CacaoBag.cs b/Scripts/Vivre/Items/Resources/CacaoBag.cs new file mode 100644 index 0000000..955057b --- /dev/null +++ b/Scripts/Vivre/Items/Resources/CacaoBag.cs @@ -0,0 +1,43 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CacaoBag : Bag + { + [Constructable] + public CacaoBag() : this(Utility.Random(3,8)) + { + } + + [Constructable] + public CacaoBag(int amount) + { + CacaoSeed treasure = new CacaoSeed(); + treasure.Amount = amount; + DropItem(treasure); + Hue = 47; + Name = "Sac en tissu d'orient"; + } + + public CacaoBag(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Resources/Ginger.cs b/Scripts/Vivre/Items/Resources/Ginger.cs new file mode 100644 index 0000000..249f2a7 --- /dev/null +++ b/Scripts/Vivre/Items/Resources/Ginger.cs @@ -0,0 +1,37 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute(0x2BE3, 0x2BE4)] + public class GingerRoot : Item + { + + [Constructable] + public GingerRoot() + : base(0x2BE3) + { + Movable = true; + Stackable = false ; + Name = "Gingembre"; + } + + public GingerRoot(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Resources/Skull.cs b/Scripts/Vivre/Items/Resources/Skull.cs new file mode 100644 index 0000000..359a170 --- /dev/null +++ b/Scripts/Vivre/Items/Resources/Skull.cs @@ -0,0 +1,64 @@ +using System; +using Server.Targeting; + +namespace Server.Items +{ + public class Skull : Item + { + + [Constructable] + public Skull() : base(0x1AE2) + { + Movable = true; + Stackable = false; + Name = "Crane"; + } + + + public override void OnDoubleClick(Mobile from) + { + if (from.Karma > -2500) + { + base.OnDoubleClick(from); + return; + } + + from.SendMessage("Vous seriez assez m�chant pour en faire une d�coration!"); + from.BeginTarget(2, false, TargetFlags.None, new TargetCallback(OnTarget)); + } + + public void OnTarget(Mobile from, object obj) + { + if (obj is Candle) + { + Candle targ = (Candle)obj; + from.SendMessage("En appuyant fortement, vous parvenez � fixer la chandelle sur le cr�ne"); + from.AddToBackpack(new CandleSkull()); + this.Delete(); + targ.Delete(); + return; + } + + from.SendMessage("Vous ne pouvez fixer cela sur le cr�ne"); + } + + public Skull(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Resources/Sugar.cs b/Scripts/Vivre/Items/Resources/Sugar.cs new file mode 100644 index 0000000..c0a97b7 --- /dev/null +++ b/Scripts/Vivre/Items/Resources/Sugar.cs @@ -0,0 +1,38 @@ +using System; + +namespace Server.Items +{ + [FlipableAttribute(0x11EA, 0x11EB)] + public class Sugar : Item + { + + [Constructable] + public Sugar() : base(0x11EA) + { + Movable = true; + Stackable = true; + Name = "Sucre"; + Hue = 0x3E9; + Amount = Utility.Random(1, 4); + } + + public Sugar(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Items/RobesACapuche.cs b/Scripts/Vivre/Items/RobesACapuche.cs new file mode 100644 index 0000000..4d5206e --- /dev/null +++ b/Scripts/Vivre/Items/RobesACapuche.cs @@ -0,0 +1,44 @@ + using System; + + namespace Server.Items + { + + public class RobeACapuche : BaseOuterTorso + { + [Constructable] + public RobeACapuche() + : this(0) + { + } + + [Constructable] + public RobeACapuche(int hue) + : base(0x2684, hue) + { + Name = "Robe à capuche"; + Weight = 1.0; + } + + public RobeACapuche(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (ItemID == 0x204E) + ItemID = 0x2684; + } + } + } \ No newline at end of file diff --git a/Scripts/Vivre/Items/RustyNails.cs b/Scripts/Vivre/Items/RustyNails.cs new file mode 100644 index 0000000..0b640dd --- /dev/null +++ b/Scripts/Vivre/Items/RustyNails.cs @@ -0,0 +1,424 @@ +using Server.Mobiles; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using Server.Commands; +using System; + +namespace Server.Items +{ + [Flipable(0x102E, 0x102F)] + public class RustyNails : Item + { + + [Constructable] + public RustyNails() + : base(0x102E) + { + Name = "Clous rouillés"; + Weight = 2.0; + } + + public RustyNails(Serial serial) + : base(serial) + { + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2) || !from.InLOS(this)) + { + from.SendLocalizedMessage(501816); + return; + } + + from.SendMessage("Dans quoi souhaitez-vous l'enfoncer?"); + from.BeginTarget(1, false, TargetFlags.Harmful, new TargetCallback(OnTarget)); + } + + public void OnTarget(Mobile from, object obj) + { + if (obj is PlayerMobile) + { + PlayerMobile pm = (PlayerMobile)obj; + + pm.Hits -= 1; + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous piquez " + pm.Name); + pm.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "Vous êtes piqué par " + from.Name); + + if (Utility.Random(20) == 7) + { + pm.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "La rouille empoisonne votre sang"); + pm.Poison = Poison.Lesser; + } + + this.Delete(); + return; + } + + if (obj is BaseVoodooDoll) + { + BaseVoodooDoll doll = (BaseVoodooDoll)obj; + + Mobile victim = doll.Possessed; + if (victim == null) + { + from.SendMessage("Aucune âme n'hante le corps de cette poupée"); + return; + } + if (victim.AccessLevel > from.AccessLevel) + { + from.SendMessage("Attention il/elle pourrait se retourner contre vous..."); + return; + } + if (!victim.Alive) + { + from.SendMessage("Faire mal à un mort ne vous servira à rien, hélas"); + return; + } + if (victim.Map == Map.Internal) + { + from.SendMessage("Faire mal à un jouer non connecté ne vous servira à rien, hélas"); + return; + } + if (Utility.Random(10) == 9) + { + from.SendMessage("Vous n'avez plus de clous rouillés"); + this.Delete(); + } + from.SendGump(new EffectGump(from, victim, doll)); + } + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (Name == null) + Name = "Clous rouillés"; + } + } + + + public class EffectGump : Gump + { + private Mobile m_From; + private Mobile m_Suffer; + private BaseVoodooDoll m_Doll; + private const int Blanco = 0xFFFFFF; + private const int Azul = 0x8080FF; + + public void AddButtonLabeled(int x, int y, int buttonID, string text) + { + AddButton(x, y - 1, 4005, 4007, buttonID, GumpButtonType.Reply, 0); + AddHtml(x + 35, y, 240, 20, Color(text, Blanco), false, false); + } + public int GetButtonID(int type, int index) + { + return 1 + (index * 15) + type; + } + public string Color(string text, int color) + { + return string.Format("{1}", color, text); + } + public EffectGump(Mobile from, Mobile victim, BaseVoodooDoll voodoodoll) + : base(600, 50) + { + m_From = from; + m_Suffer = victim; + m_Doll = voodoodoll; + Closable = true; + Dragable = true; + AddPage(0); + //AddBackground( 0, 65, 130, 360, 5054); + //AddAlphaRegion( 10, 70, 110, 350 ); + //AddImageTiled(10, 70, 110, 20, 9354); + AddBackground(0, 65, 240, 360, 5054); + AddAlphaRegion(10, 70, 220, 350); + AddImageTiled(10, 70, 220, 20, 9354); + AddLabel(13, 70, 200, "Liste des souffrances"); + AddImage(210, 0, 10410); + AddImage(210, 305, 10412); + AddImage(210, 150, 10411); + + AddButtonLabeled(10, 90, GetButtonID(1, 1), "Bras"); + AddButtonLabeled(10, 115, GetButtonID(1, 2), "Main"); + AddButtonLabeled(10, 140, GetButtonID(1, 3), "Cuisse"); + AddButtonLabeled(10, 165, GetButtonID(1, 4), "Pied"); + AddButtonLabeled(10, 190, GetButtonID(1, 5), "Ventre"); + AddButtonLabeled(10, 215, GetButtonID(1, 6), "Dos"); + AddButtonLabeled(10, 240, GetButtonID(1, 7), "Nez"); + AddButtonLabeled(10, 265, GetButtonID(1, 8), "Yeux"); + AddButtonLabeled(10, 290, GetButtonID(1, 9), "Bouche"); + AddButtonLabeled(10, 315, GetButtonID(1, 10), "Fesses"); + + } + public override void OnResponse(NetState sender, RelayInfo info) + { + int val = info.ButtonID - 1; + if (val < 0) + return; + + Mobile from = m_From; + Mobile victim = m_Suffer; + BaseVoodooDoll voodoodoll = m_Doll; + int type = val % 15; + int index = val / 15; + + string frommsg = "Vous piquez "; + string victimmsg = "*Vous ressentez une douleur "; + string publicmsg = null; + int sound = victim.Female ? 814 : 1088; + + switch (index) + { + default: break; + case 1: + { + frommsg += "son bras"; + victimmsg += "au bras*"; + publicmsg = "*Se prend le bras*"; + victim.Animate(120, 5, 1, true, false, 0); + + break; + } + case 2: + { + frommsg += "sa main"; + victimmsg += "à la main*"; + if (from.Skills[SkillName.Anatomy].Value > Utility.Random(200)) + { + Item item = victim.FindItemOnLayer(Layer.OneHanded); + if (item != null) + { + item.MoveToWorld(victim.Location); + publicmsg = "*Lâche ce qu'il tient sous la douleur*"; + if (!victim.Mounted) + victim.Animate(120, 5, 1, true, false, 0); + } + else + publicmsg = "*Se prend la main*"; + } + else + publicmsg = "*Se prend le bras*"; + break; + } + case 3: + { + frommsg += "sa cuisse"; + victimmsg += "à la cuisse*"; + publicmsg = "*boite légèrement*"; + break; + } + case 4: + { + frommsg += "son pied"; + victimmsg += "au pied*"; + publicmsg = "*Sautille*"; + if (!victim.Mounted) + victim.Animate(25, 5, 1, true, true, 3); + if (from.Skills[SkillName.Anatomy].Value > Utility.Random(150)) + { + victim.CantWalk = true; + Timer.DelayCall(TimeSpan.FromSeconds(3), ChangeWalk, victim); + } + break; + } + case 5: + { + frommsg += "son ventre"; + victimmsg += "au ventre*"; + if (from.Skills[SkillName.Anatomy].Value > Utility.Random(80)) + { + sound = victim.Female ? 813 : 1087; + + Point3D p = new Point3D(victim.Location); + switch (victim.Direction) + { + case Direction.North: + p.Y--; break; + case Direction.South: + p.Y++; break; + case Direction.East: + p.X++; break; + case Direction.West: + p.X--; break; + case Direction.Right: + p.X++; p.Y--; break; + case Direction.Down: + p.X++; p.Y++; break; + case Direction.Left: + p.X--; p.Y++; break; + case Direction.Up: + p.X--; p.Y--; break; + default: + break; + } + p.Z = victim.Map.GetAverageZ(p.X, p.Y); + + bool canFit = Server.Spells.SpellHelper.AdjustField(ref p, victim.Map, 12, false); + + if (canFit) + { + Puke puke = new Puke(); + puke.Map = victim.Map; + puke.Location = p; + } + } + else + publicmsg = "*Se tient le ventre*"; + if (!victim.Mounted) + victim.Animate(32, 5, 1, true, false, 0); + break; + } + case 6: + { + frommsg += "son dos"; + victimmsg += "Au dos*"; + publicmsg = "*Courbe l'échine*"; + if (!victim.Mounted) + victim.Animate(32, 5, 1, true, true, 3); + break; + } + case 7: + { + frommsg += "son nez"; + victimmsg += "au nez*"; + publicmsg = "*Éternue bruyamment*"; + sound = victim.Female ? 817 : 1091; + if (!victim.Mounted) + victim.Animate(32, 5, 1, true, false, 0); + break; + } + case 8: + { + frommsg += "ses yeux"; + victimmsg += "aux yeux*"; + publicmsg = "*Pleure abondamment*"; + sound = victim.Female ? 787 : 1058; + break; + } + case 9: + { + frommsg += "sa bouche"; + victimmsg += "aux lèvres*"; + publicmsg = "*Ses lèvres se closent*"; + sound = victim.Female ? 784 : 1055; + if (!victim.Mounted) + victim.Animate(33, 5, 1, true, false, 0); + if (from.Skills[SkillName.Anatomy].Value > Utility.Random(150)) + { + victim.Squelched = true; + Timer.DelayCall(TimeSpan.FromSeconds(5), ChangeSquelch, victim); + } + break; + } + case 10: + { + frommsg += "ses fesses"; + victimmsg += "aux fesses*"; + publicmsg = "*Pète*"; + sound = victim.Female ? 792 : 1064; + victim.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist); + break; + } + } + from.CloseGump(typeof(EffectGump)); + + from.SendMessage(frommsg); + + from.SendMessage("Vous perdez du Karma"); + from.Karma -= Utility.Random(100); + + victim.PrivateOverheadMessage(MessageType.Regular, 0x3B2, false, victimmsg, victim.NetState); + + if (publicmsg != null) + victim.Say(publicmsg); + + victim.PlaySound(sound); + + voodoodoll.Charges--; + + if (voodoodoll.Charges <= 0) + { + from.SendMessage("La poupée perd ses cheveux, redevenant inutile"); + if (voodoodoll is VoodooDollFemale) + from.AddToBackpack(new PoupeeFemale()); + else + from.AddToBackpack(new PoupeeMale()); + + voodoodoll.Delete(); + } + + } + public void ChangeWalk(Mobile from) + { + from.CantWalk = false; + } + + public void ChangeSquelch(Mobile from) + { + from.Squelched = false; + } + } + + public class Puke : Item + { + private Timer m_Timer; + + [Constructable] + public Puke() + : base(Utility.RandomList(0xf3b, 0xf3c)) + { + Name = "Du Vomi"; // a pile of puke + Hue = 0x557; + Movable = false; + + m_Timer = new ItemRemovalTimer(this); + m_Timer.Start(); + + } + + public override void OnAfterDelete() + { + base.OnAfterDelete(); + + if (m_Timer != null) + m_Timer.Stop(); + } + + public override void OnSingleClick(Mobile from) + { + this.LabelTo(from, this.Name); + } + + public Puke(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + this.Delete(); // none when the world starts + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/SeedBox.cs b/Scripts/Vivre/Items/SeedBox.cs new file mode 100644 index 0000000..6c5d456 --- /dev/null +++ b/Scripts/Vivre/Items/SeedBox.cs @@ -0,0 +1,708 @@ +using System; +using System.Collections; +using Server; +using Server.Engines.Plants; +using Server.Gumps; +using Server.Items; +using Server.Multis; +using System.Collections.Generic; +using Server.ContextMenus; + +/*************************************** + * SeedBox by Kelon, 18.Aug.2005 + * ************************************* + * A box to store all seeds more easily + * ************************************/ + +namespace Server.Items +{ + public class SeedBox : Item, ISecurable + { + /// + /// Maximum number of seeds that can be stored in a SeedBox + /// + private const int MaxStorage = 10000; + + private int m_Stored; + private ArrayList m_KnownStorage; + private ArrayList m_UnknownStorage; + private SecureLevel m_Level; + + /// + /// Number of stored seeds + /// + public int Stored + { + get { return m_Stored; } + set + { + m_Stored = value; + Weight = 3 + m_Stored * 0.03; + InvalidateProperties(); + } + } + + /// + /// Seeds, that are showing their type + /// + public ArrayList KnownStorage + { + get { return m_KnownStorage; } + } + + /// + /// Seeds, that are not showing their type + /// + public ArrayList UnknownStorage + { + get { return m_UnknownStorage; } + } + + #region ISecurable Members + + [CommandProperty( AccessLevel.GameMaster )] + public SecureLevel Level + { + get{ return m_Level; } + set{ m_Level = value; } + } + + #endregion + + public override int LabelNumber {get{ return 3010154; }} // Plant Seeds + + [Constructable] + public SeedBox() : base( 0x09B1 ) // Basket graphics + { + Weight = 3; + Hue = 0x084F; + m_KnownStorage = new ArrayList(); + m_UnknownStorage = new ArrayList(); + m_Stored = 0; + } + + public SeedBox( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + int stored = 0; // recalculate to ensure + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + writer.Write( (int)m_Level ); + writer.Write( m_UnknownStorage.Count ); + foreach( SeedInfo si in m_UnknownStorage ) + { + writer.Write( (int)si.Type ); + writer.Write( si.Hues.Count ); + foreach( SeedHue sh in si.Hues ) + { + writer.Write( (int)sh.Hue ); + writer.Write( (int)sh.Amount ); + stored += sh.Amount; + } + } + + writer.Write( m_KnownStorage.Count ); + foreach( SeedInfo si in m_KnownStorage ) + { + writer.Write( (int)si.Type ); + writer.Write( si.Hues.Count ); + foreach( SeedHue sh in si.Hues ) + { + writer.Write( (int)sh.Hue ); + writer.Write( (int)sh.Amount ); + stored += sh.Amount; + } + } + m_Stored = stored; + } + + public override void Deserialize( GenericReader reader ) + { + int stored = 0; + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_Level = (SecureLevel)reader.ReadInt(); + m_UnknownStorage = new ArrayList(); + + for( int i = reader.ReadInt(); i > 0 ; i-- ) + { + SeedInfo si = new SeedInfo( (PlantType)reader.ReadInt() ); + for( int c = reader.ReadInt(); c > 0; c-- ) + { + SeedHue sh = new SeedHue( (PlantHue)reader.ReadInt(), reader.ReadInt() ); + si.Hues.Add( sh ); + stored += sh.Amount; + } + m_UnknownStorage.Add( si ); + } + + m_KnownStorage = new ArrayList(); + for( int i = reader.ReadInt(); i > 0; i-- ) + { + SeedInfo si = new SeedInfo( (PlantType)reader.ReadInt() ); + for( int c = reader.ReadInt(); c > 0; c-- ) + { + SeedHue sh = new SeedHue( (PlantHue)reader.ReadInt(), reader.ReadInt() ); + si.Hues.Add( sh ); + stored += sh.Amount; + } + m_KnownStorage.Add( si ); + } + m_Stored = stored; + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties (list); + list.Add( 1060838, m_Stored.ToString() ); // ~1_val~ seed + } + + public override void GetContextMenuEntries( Mobile from, List list ) + { + base.GetContextMenuEntries( from, list ); + SetSecureLevelEntry.AddTo( from, this, list ); + } + + /// + /// + /// + /// + /// + /// Since this isn't a container, it's false + public override bool OnDragDrop(Mobile from, Item dropped) + { + Seed drop = dropped as Seed; + if( drop == null ) // Must be a seed + { + from.SendLocalizedMessage( 1042276 ); // You cannot drop that there. + return false; + } + if( m_Stored < MaxStorage ) + { + AddSeed( drop ); + drop.Delete(); + return false; + } + from.SendLocalizedMessage( 1042972 ); // It's full. + return false; + + } + + public override void OnDoubleClick(Mobile from) + { + if( from.InRange( this.GetWorldLocation(), 3 ) && from.InLOS( this.GetWorldLocation() ) ) + from.SendGump( new SeedBoxGump( from, this ) ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + /// + /// Adds a seed to the storage list + /// + /// Item + public void AddSeed( Seed seed ) + { + // First, we start searching for similiar seeds + if( seed.ShowType ) + { + foreach( SeedInfo fsi in m_KnownStorage ) + { + if( fsi.Type == seed.PlantType ) + { + fsi.Add( seed.PlantHue, 1); + Stored++; + return; + } + } + // Second, if no similiar seeds were found, we're adding this one. + SeedInfo ssi = new SeedInfo( seed.PlantType ); // Damn scope bug! + ssi.Add( seed.PlantHue, 1 ); + m_KnownStorage.Add( ssi ); + m_KnownStorage.Sort( new PlantTypeComparer() ); + Stored++; + } + else + { + foreach( SeedInfo fsi in m_UnknownStorage ) + { + if( fsi.Type == seed.PlantType ) + { + fsi.Add( seed.PlantHue, 1); + Stored++; + return; + } + } + // Second, if no similiar seeds were found, we're adding this one. + SeedInfo ssi = new SeedInfo( seed.PlantType ); + ssi.Add( seed.PlantHue, 1 ); + // No sorting with unknown seeds + m_UnknownStorage.Add( ssi ); + Stored++; + } + } + + private class PlantTypeComparer : IComparer + { + public int Compare( object x, object y) + { + return Compare( (int)((SeedInfo)x).Type, (int)((SeedInfo)y).Type ); + } + public int Compare( int x, int y) + { + return x - y; + } + } + + private class PlantHueComparer : IComparer + { + public int Compare( object x, object y) + { + return Compare( (int)((SeedHue)x).Hue, (int)((SeedHue)y).Hue ); + } + public int Compare( int x, int y) + { + x = x | 0x4000000; // ignore non-crossables + y = y | 0x4000000; + return x - y; + } + } + + /// + /// Information about the stores seeds + /// + private class SeedInfo + { + public PlantType Type; + public ArrayList Hues; + + public SeedInfo( PlantType type ) + { + Type = type; + Hues = new ArrayList(); + } + + /// + /// Adds a seed to the list + /// + /// + /// + public void Add( PlantHue hue, int amount ) + { + foreach( SeedHue si in Hues ) + { + if( si.Hue == hue ) + { + si.Amount += amount; + return; + } + } + Hues.Add( new SeedHue( hue, amount ) ); + Hues.Sort( new PlantHueComparer() ); + } + } + + private class SeedHue + { + public PlantHue Hue; + public int Amount; + + public SeedHue( PlantHue hue, int amount ) + { + Hue = hue; + Amount = amount; + } + } + + /// + /// The gump to get the seeds + /// + private class SeedBoxGump : Gump + { + private Mobile m_Owner; + private SeedBox m_Box; + + private SeedInfo seedinfo;//#01 + private bool unknownstorage;//#01 + + public SeedBoxGump( Mobile owner, SeedBox box ) : this( owner, box, null, true){}//#01 + + //public SeedBoxGump( Mobile owner, SeedBox box ) : base( 0, 0 )//#01 + public SeedBoxGump( Mobile owner, SeedBox box, SeedInfo si, bool unknown ) : base( 0, 0 ) + { + m_Owner = owner; + m_Box = box; + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + + seedinfo = si;//#01 + unknownstorage = unknown;//#01 + + if( box == null || box.Deleted ) + return; + + int max = AddBackground(); // Custom method to calculate size + AddBackground( 170, 40, 82, 80, 9350 ); // Image window + + AddPages( max ); + + } + + /// + /// Custom method to calculate the minimal size + /// + /// Possible items per row + private int AddBackground() + { + int maxhues = 0; + int maxperrow = 0; + int typesadd = m_Box.KnownStorage.Count - 5; + foreach( SeedInfo si in m_Box.UnknownStorage ) + maxhues += si.Hues.Count; + foreach( SeedInfo si in m_Box.KnownStorage ) + if( si.Hues.Count > maxhues ) + maxhues = si.Hues.Count; + + maxhues = ( maxhues / 2 + maxhues % 2 ) - 3; + maxperrow = ( maxhues > typesadd ? maxhues : typesadd ); // subtract 3 for backgrounds size calculation + maxperrow = maxperrow > 0 ? maxperrow : 0; + int verticaladd = maxperrow * 20; + AddPage( 0 ); + AddBackground( 20, 20, 450, 187 + verticaladd, 3500 ); // White paper background + AddImageTiled( 150, 30, 20, 167 + verticaladd, 3503 ); // White paper separator + AddImageTiled( 250, 50, 210, 17, 1803 ); // White paper horizontal bar + AddItem( 40, 170 + verticaladd, 3224, 0 ); // Large fern deco + return maxperrow + 3; + } + + /// + /// Adds the page buttons (PlantTypes). + /// + private void AddPages( int MaxPerRow ) + { + int pageindex = 1; + int itemindex = 0; + int buttonindex = 1; + int verticaladd = 0; // temporary + + //#01 d�but + if(seedinfo != null && !unknownstorage)//si un type en m�moire et que ce n'est pas l'unknown + { + PlantTypeInfo pii = null; + foreach( SeedInfo si in m_Box.KnownStorage ) + { + if(si.Type == seedinfo.Type)//on met sa page en premier dans la liste + { + pii = PlantTypeInfo.GetInfo( si.Type ); + AddButton( 37, 55, 2103, 2104, 0, GumpButtonType.Page, pageindex ); // Type button + AddHtmlLocalized( 50, 50, 110, 20, pii.Name, false, false ); // Plant name + pageindex++; + } + } + if( m_Box.UnknownStorage.Count > 0 )//et donc les unknown en second + { + AddButton( 37, 35 + pageindex * 20, 2103, 2104, 0, GumpButtonType.Page, pageindex ); // Type button + AddHtmlLocalized( 50, 30 + pageindex * 20, 110, 20, 1060800, false, false ); // Plant name: unknown + pageindex++; + } + } + else//sinon comme d'hab + { + //#01 fin + if( m_Box.UnknownStorage.Count > 0 ) + { + AddButton( 37, 55, 2103, 2104, 0, GumpButtonType.Page, pageindex ); // Type button + AddHtmlLocalized( 50, 50, 110, 20, 1060800, false, false ); // Plant name: unknown + pageindex++; + } + }//#01 fini le else + + PlantTypeInfo pi = null; + + //#01 d�but + if(seedinfo != null)//toujours si un type en memoire + { + foreach( SeedInfo si in m_Box.KnownStorage )//le reste de la liste SANS celui en m�moire puisqu'il est dej� en premier + { + if(si.Type != seedinfo.Type) + { + pi = PlantTypeInfo.GetInfo( si.Type ); + AddButton( 37, 35 + pageindex * 20, 2103, 2104, 0, GumpButtonType.Page, pageindex ); // Type button + AddHtmlLocalized( 50, 30 + pageindex * 20, 110, 20, pi.Name, false, false ); // Plant name + pageindex++; + } + } + } + else + {//#01 fin + foreach( SeedInfo si in m_Box.KnownStorage ) + { + pi = PlantTypeInfo.GetInfo( si.Type ); + AddButton( 37, 35 + pageindex * 20, 2103, 2104, 0, GumpButtonType.Page, pageindex ); // Type button + AddHtmlLocalized( 50, 30 + pageindex * 20, 110, 20, pi.Name, false, false ); // Plant name + pageindex++; + } + }//#01 fini le else + + pageindex = 1; // reset + + PlantHueInfo ph = null; + + //#01 d�but + + if(seedinfo != null && !unknownstorage)//si un type en memoire, sa page est la premi�re, + //mais si c'est l'unknown, on fait comme d'hab (elle est la premiere) + { + PlantType planttype = seedinfo.Type; + + foreach( SeedInfo si in m_Box.KnownStorage ) + { + if(si.Type == planttype) + { + pi = PlantTypeInfo.GetInfo( si.Type ); + AddPage( 1); + AddItem( 187 + pi.OffsetX, 50 + pi.OffsetY, pi.ItemID, 0 ); // Plant picture + AddHtmlLocalized( 264, 45, 170, 20, pi.Name, false, false ); // Type description + + itemindex = 0; + verticaladd = 0; + foreach( SeedHue sh in si.Hues ) + { + ph = PlantHueInfo.GetInfo( sh.Hue ); + AddButton( 170 + verticaladd, 130 + itemindex * 20, 22407, 22406, buttonindex++, GumpButtonType.Reply, 0 ); // Take button + AddLabel( 190 + verticaladd, 130 + itemindex * 20, 0x835, sh.Amount.ToString() ); + + if( (int)sh.Hue < 0x8000000 ) + AddHtmlLocalized( 220 + verticaladd, 130 + itemindex * 20, 100, 20, ph.Name, false, false ); // Hue description + else + { + AddLabel( 220 + verticaladd, 130 + itemindex * 20, 0, "bright" ); + AddHtmlLocalized( 260 + verticaladd, 130 + itemindex * 20, 100, 20, ph.Name, false, false ); // Hue description + } + itemindex++; + if( itemindex >= MaxPerRow ) // start next row + { + itemindex = 0; + verticaladd = 150; + } + } + pageindex++; + } + } + } + //#01 fin + + if( m_Box.UnknownStorage.Count > 0 ) + { + AddPage( pageindex ); + AddItem( 190, 60, 1, 0 ); // Plant picture + AddHtmlLocalized( 264, 45, 170, 20, 3000575, false, false ); // Type description: UNKNOWN + + // Unknown seeds are displayed in a single category + foreach( SeedInfo si in m_Box.UnknownStorage ) + { + foreach( SeedHue sh in si.Hues ) + { + ph = PlantHueInfo.GetInfo( sh.Hue ); + AddButton( 170 + verticaladd, 130 + itemindex * 20, 22407, 22406, buttonindex++, GumpButtonType.Reply, 0 ); // Take button + AddLabel( 190 + verticaladd, 130 + itemindex * 20, 0x835, sh.Amount.ToString() ); + AddHtmlLocalized( 220 + verticaladd, 130 + itemindex * 20, 100, 20, ph.Name, false, false ); // Hue description + itemindex++; + if( itemindex >= MaxPerRow ) // Start next row + { + itemindex = 0; + verticaladd = 150; + } + } + } + pageindex++; + } + + foreach( SeedInfo si in m_Box.KnownStorage ) + { + if(seedinfo == null || si.Type != seedinfo.Type)//#01 + { + + pi = PlantTypeInfo.GetInfo( si.Type ); + AddPage( pageindex ); + AddItem( 187 + pi.OffsetX, 50 + pi.OffsetY, pi.ItemID, 0 ); // Plant picture + AddHtmlLocalized( 264, 45, 170, 20, pi.Name, false, false ); // Type description + + itemindex = 0; + verticaladd = 0; + foreach( SeedHue sh in si.Hues ) + { + ph = PlantHueInfo.GetInfo( sh.Hue ); + AddButton( 170 + verticaladd, 130 + itemindex * 20, 22407, 22406, buttonindex++, GumpButtonType.Reply, 0 ); // Take button + AddLabel( 190 + verticaladd, 130 + itemindex * 20, 0x835, sh.Amount.ToString() ); + + if( (int)sh.Hue < 0x8000000 ) + AddHtmlLocalized( 220 + verticaladd, 130 + itemindex * 20, 100, 20, ph.Name, false, false ); // Hue description + else + { + AddLabel( 220 + verticaladd, 130 + itemindex * 20, 0, "bright" ); + AddHtmlLocalized( 260 + verticaladd, 130 + itemindex * 20, 100, 20, ph.Name, false, false ); // Hue description + } + itemindex++; + if( itemindex >= MaxPerRow ) // start next row + { + itemindex = 0; + verticaladd = 150; + } + } + pageindex++; + }//#01 fin du if + } + + // Check if something was added + if( pageindex == 1 ) + { + AddPage( pageindex ); + AddImage( 175, 45, 7012, 2406 ); + AddHtmlLocalized( 264, 45, 170, 20, 501038, false, false ); // Claim List is empty + } + } + + public override void OnResponse(Server.Network.NetState sender, RelayInfo info) + { + if( m_Box == null || m_Box.Deleted || info.ButtonID == 0 ) + return; + + Mobile from = sender.Mobile; + + int curritem = 1; + + SeedInfo inf = null; + + if(seedinfo != null && !unknownstorage) + { + PlantType planttype = seedinfo.Type; + + foreach( SeedInfo si in m_Box.KnownStorage ) + { + if(si.Type == planttype) + { + foreach( SeedHue sh in si.Hues ) + { + if( info.ButtonID == curritem ) + { + if( AddToPack( from, si.Type, sh.Hue, true ) ) + { + sh.Amount--; + m_Box.Stored--; + if( sh.Amount < 1 ) + si.Hues.Remove( sh ); + if( si.Hues.Count < 1 ) + m_Box.UnknownStorage.Remove( si ); + } + //from.SendGump( new SeedBoxGump( from, m_Box ) );//#01 + inf = si;//#01 + if(si.Hues.Count < 1 )inf = null;//#01 + from.SendGump( new SeedBoxGump( from, m_Box, inf, false) );//#01 + return; + } + curritem++; + } + } + } + } + + foreach( SeedInfo si in m_Box.UnknownStorage ) + { + foreach( SeedHue sh in si.Hues ) + { + if( info.ButtonID == curritem ) + { + if( AddToPack( from, si.Type, sh.Hue, false ) ) + { + sh.Amount--; + m_Box.Stored--; + if( sh.Amount < 1 ) + si.Hues.Remove( sh ); + if( si.Hues.Count < 1 ) + m_Box.UnknownStorage.Remove( si ); + } + //from.SendGump( new SeedBoxGump( from, m_Box ) );//#01 + inf = si;//#01 + if(si.Hues.Count < 1 )inf = null;//#01 + from.SendGump( new SeedBoxGump( from, m_Box, inf, true) );//#01 + return; + } + curritem++; + } + } + foreach( SeedInfo si in m_Box.KnownStorage ) + { + if(seedinfo == null || si.Type != seedinfo.Type)//#01 + { + + foreach( SeedHue sh in si.Hues ) + { + if( info.ButtonID == curritem ) + { + if( AddToPack( from, si.Type, sh.Hue, true ) ) + { + sh.Amount--; + m_Box.Stored--; + if( sh.Amount < 1 ) + si.Hues.Remove( sh ); + if( si.Hues.Count < 1 ) + m_Box.KnownStorage.Remove( si ); + } + //from.SendGump( new SeedBoxGump( from, m_Box ) );//#01 + inf = si;//#01 + if(si.Hues.Count < 1 )inf = null;//#01 + from.SendGump( new SeedBoxGump( from, m_Box, inf, false) );//#01 + return; + } + curritem++; + } + }//#01 fin du if + } + from.SendLocalizedMessage( 500065 ); // Object not found + } + + private bool AddToPack( Mobile from, PlantType type, PlantHue hue, bool showtype ) + { + if( from == null || from.Deleted || from.Backpack == null || from.Backpack.Deleted ) + return false; + + if( !from.InRange( m_Box.GetWorldLocation(), 3 ) || !from.InLOS( m_Box.GetWorldLocation() ) ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + return false; + } + + Seed seed = new Seed( type, hue, showtype ); + if( !from.Backpack.TryDropItem( from, seed, true ) ) + { + seed.MoveToWorld( from.Location, from.Map ); + } + return true; + } + } + } +} + + + + + + + + + + + + + + + + + + diff --git a/Scripts/Vivre/Items/Skills Item/Magical/BlankWand.cs b/Scripts/Vivre/Items/Skills Item/Magical/BlankWand.cs new file mode 100644 index 0000000..e779a13 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/BlankWand.cs @@ -0,0 +1,51 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + public class BlankWand : BaseBashing + { + public override WeaponAbility PrimaryAbility { get { return WeaponAbility.Dismount; } } + public override WeaponAbility SecondaryAbility { get { return WeaponAbility.Disarm; } } + + public override int AosStrengthReq { get { return 5; } } + public override int AosMinDamage { get { return 9; } } + public override int AosMaxDamage { get { return 11; } } + public override int AosSpeed { get { return 40; } } + + public override int OldStrengthReq { get { return 0; } } + public override int OldMinDamage { get { return 2; } } + public override int OldMaxDamage { get { return 6; } } + public override int OldSpeed { get { return 35; } } + + public override int InitMinHits { get { return 31; } } + public override int InitMaxHits { get { return 110; } } + + [Constructable] + public BlankWand() : base(Utility.RandomList( 0xDF2, 0xDF3, 0xDF4, 0xDF5 )) + { + Name = "Baguette de bois"; + Weight = 1.0; + } + + public BlankWand(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/ConfidenceScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/ConfidenceScroll.cs new file mode 100644 index 0000000..b8354e3 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/ConfidenceScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ConfidenceScroll : SpellScroll + { + [Constructable] + public ConfidenceScroll() : this( 1 ) + { + } + + [Constructable] + public ConfidenceScroll(int amount) + : base(401, 0x46B3, amount) + { + Name = "Confidence Scroll"; + } + + public ConfidenceScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/CouterAttackScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/CouterAttackScroll.cs new file mode 100644 index 0000000..16d8fe0 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/CouterAttackScroll.cs @@ -0,0 +1,43 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CounterAttackScroll : SpellScroll + { + [Constructable] + public CounterAttackScroll() : this( 1 ) + { + } + + [Constructable] + public CounterAttackScroll(int amount) + : base(403, 0x46B3, amount) + { + //Myron : Correction du nom qui �tait Consecrate Weapon Scroll + Name = "Counter Attack Scroll"; + } + + public CounterAttackScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/EvasionScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/EvasionScroll.cs new file mode 100644 index 0000000..9143965 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/EvasionScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EvasionScroll : SpellScroll + { + [Constructable] + public EvasionScroll() : this( 1 ) + { + } + + [Constructable] + public EvasionScroll( int amount ) : base( 402, 0x46B2, amount ) + { + Name = "Evasion Scroll"; + } + + public EvasionScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/HonorableExecutionScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/HonorableExecutionScroll.cs new file mode 100644 index 0000000..531f58b --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/HonorableExecutionScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class HonorableExecutionScroll : SpellScroll + { + [Constructable] + public HonorableExecutionScroll() : this( 1 ) + { + } + + [Constructable] + public HonorableExecutionScroll(int amount) + : base(400, 0x46B3, amount) + { + Name = "Honorable Execution Scroll"; + } + + public HonorableExecutionScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/LightningStrikeScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/LightningStrikeScroll.cs new file mode 100644 index 0000000..6f52a61 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/LightningStrikeScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class LightningStrikeScroll : SpellScroll + { + [Constructable] + public LightningStrikeScroll() : this( 1 ) + { + } + + [Constructable] + public LightningStrikeScroll(int amount) + : base(404, 0x46B2, amount) + { + Name = "Lightning Strike Scroll"; + } + + public LightningStrikeScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/MomentumStrikeScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/MomentumStrikeScroll.cs new file mode 100644 index 0000000..b4182b0 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Bushido Scrolls/MomentumStrikeScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MomentumStrikeScroll : SpellScroll + { + [Constructable] + public MomentumStrikeScroll() : this( 1 ) + { + } + + [Constructable] + public MomentumStrikeScroll(int amount) + : base(405, 0x46B2, amount) + { + Name = "Momentum Strike Scroll"; + } + + public MomentumStrikeScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/CleanseByFireScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/CleanseByFireScroll.cs new file mode 100644 index 0000000..cc05567 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/CleanseByFireScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CleanseByFireScroll : SpellScroll + { + [Constructable] + public CleanseByFireScroll() : this( 1 ) + { + } + + [Constructable] + public CleanseByFireScroll( int amount ) : base( 200, 0x227C, amount ) + { + Name = "Cleanse By Fire Scroll"; + } + + public CleanseByFireScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/CloseWoundsScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/CloseWoundsScroll.cs new file mode 100644 index 0000000..06fa7ed --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/CloseWoundsScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class CloseWoundsScroll : SpellScroll + { + [Constructable] + public CloseWoundsScroll() : this( 1 ) + { + } + + [Constructable] + public CloseWoundsScroll( int amount ) : base( 201, 0x227C, amount ) + { + Name = "Close Wounds Scroll"; + } + + public CloseWoundsScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/ConsecrateWeaponScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/ConsecrateWeaponScroll.cs new file mode 100644 index 0000000..98dc424 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/ConsecrateWeaponScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ConsecrateWeaponScroll : SpellScroll + { + [Constructable] + public ConsecrateWeaponScroll() : this( 1 ) + { + } + + [Constructable] + public ConsecrateWeaponScroll( int amount ) : base( 202, 0x227C, amount ) + { + Name = "Consecrate Weapon Scroll"; + } + + public ConsecrateWeaponScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/DispelEvilScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/DispelEvilScroll.cs new file mode 100644 index 0000000..f818f74 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/DispelEvilScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DispelEvilScroll : SpellScroll + { + [Constructable] + public DispelEvilScroll() : this( 1 ) + { + } + + [Constructable] + public DispelEvilScroll( int amount ) : base( 203, 0x227C, amount ) + { + Name = "Dispel Evil Scroll"; + } + + public DispelEvilScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/DivineFuryScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/DivineFuryScroll.cs new file mode 100644 index 0000000..e7a45ac --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/DivineFuryScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DivineFuryScroll : SpellScroll + { + [Constructable] + public DivineFuryScroll() : this( 1 ) + { + } + + [Constructable] + public DivineFuryScroll( int amount ) : base( 204, 0x227C, amount ) + { + Name = "Divine Fury Scroll"; + } + + public DivineFuryScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/EnemyOfOneScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/EnemyOfOneScroll.cs new file mode 100644 index 0000000..ce69111 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/EnemyOfOneScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EnemyOfOneScroll : SpellScroll + { + [Constructable] + public EnemyOfOneScroll() : this( 1 ) + { + } + + [Constructable] + public EnemyOfOneScroll( int amount ) : base( 205, 0x227C, amount ) + { + Name = "Enemy Of One Scroll"; + } + + public EnemyOfOneScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/HolyLightScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/HolyLightScroll.cs new file mode 100644 index 0000000..1bb32b6 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/HolyLightScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class HolyLightScroll : SpellScroll + { + [Constructable] + public HolyLightScroll() : this( 1 ) + { + } + + [Constructable] + public HolyLightScroll( int amount ) : base( 206, 0x227C, amount ) + { + Name = "Holy Light Scroll"; + } + + public HolyLightScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/NobleSacrificeScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/NobleSacrificeScroll.cs new file mode 100644 index 0000000..2635c3f --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/NobleSacrificeScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class NobleSacrificeScroll : SpellScroll + { + [Constructable] + public NobleSacrificeScroll() : this( 1 ) + { + } + + [Constructable] + public NobleSacrificeScroll( int amount ) : base( 207, 0x227C, amount ) + { + Name = "Noble Sacrifice Scroll"; + } + + public NobleSacrificeScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/RemoveCurseScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/RemoveCurseScroll.cs new file mode 100644 index 0000000..94c2ab9 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/RemoveCurseScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class RemoveCurseScroll : SpellScroll + { + [Constructable] + public RemoveCurseScroll() : this( 1 ) + { + } + + [Constructable] + public RemoveCurseScroll( int amount ) : base( 208, 0x227C, amount ) + { + Name = "Remove Curse Scroll"; + } + + public RemoveCurseScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/SacredJourneyScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/SacredJourneyScroll.cs new file mode 100644 index 0000000..6d3cbdc --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/Chivalry Scrolls/SacredJourneyScroll.cs @@ -0,0 +1,41 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SacredJourneyScroll : SpellScroll + { + [Constructable] + public SacredJourneyScroll() : this( 1 ) + { + } + + [Constructable] + public SacredJourneyScroll( int amount ) : base( 209, 0x227C, amount ) + { + Name = "Sacred Journey Scroll"; + } + + public SacredJourneyScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/AnimalFormScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/AnimalFormScroll.cs new file mode 100644 index 0000000..e4cf668 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/AnimalFormScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AnimalFormScroll : SpellScroll + { + [Constructable] + public AnimalFormScroll() : this( 1 ) + { + } + + [Constructable] + public AnimalFormScroll(int amount) + : base(502, 0x46AF, amount) + { + Name = "Animal Form Scroll"; + } + + public AnimalFormScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/BackstabScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/BackstabScroll.cs new file mode 100644 index 0000000..ba750a4 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/BackstabScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BackstabScroll : SpellScroll + { + [Constructable] + public BackstabScroll() : this( 1 ) + { + } + + [Constructable] + public BackstabScroll(int amount) + : base(505, 0x46AE, amount) + { + Name = "Backstab Scroll"; + } + + public BackstabScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/DeathStrikeScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/DeathStrikeScroll.cs new file mode 100644 index 0000000..e87b3ef --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/DeathStrikeScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DeathStrikeScroll : SpellScroll + { + [Constructable] + public DeathStrikeScroll() : this( 1 ) + { + } + + [Constructable] + public DeathStrikeScroll(int amount) + : base(501, 0x46AF, amount) + { + Name = "Death Strike Scroll"; + } + + public DeathStrikeScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/FocusAttackScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/FocusAttackScroll.cs new file mode 100644 index 0000000..00deb89 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/FocusAttackScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class FocusAttackScroll : SpellScroll + { + [Constructable] + public FocusAttackScroll() : this( 1 ) + { + } + + [Constructable] + public FocusAttackScroll(int amount) + : base(500, 0x46AF, amount) + { + Name = "Focus Attack Scroll"; + } + + public FocusAttackScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/KiAttackScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/KiAttackScroll.cs new file mode 100644 index 0000000..3bcc44f --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/KiAttackScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class KiAttackScroll : SpellScroll + { + [Constructable] + public KiAttackScroll() : this( 1 ) + { + } + + [Constructable] + public KiAttackScroll(int amount) + : base(503, 0x46AF, amount) + { + Name = "Ki Attack Scroll"; + } + + public KiAttackScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/MirrorImageScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/MirrorImageScroll.cs new file mode 100644 index 0000000..a975847 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/MirrorImageScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MirrorImageScroll : SpellScroll + { + [Constructable] + public MirrorImageScroll() : this( 1 ) + { + } + + [Constructable] + public MirrorImageScroll(int amount) + : base(507, 0x46AE, amount) + { + Name = "Mirror Image Scroll"; + } + + public MirrorImageScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/ShadowjumpScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/ShadowjumpScroll.cs new file mode 100644 index 0000000..bfba9b4 --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/ShadowjumpScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class ShadowjumpScroll : SpellScroll + { + [Constructable] + public ShadowjumpScroll() : this( 1 ) + { + } + + [Constructable] + public ShadowjumpScroll(int amount) + : base(506, 0x46AE, amount) + { + Name = "Shadowjump Scroll"; + } + + public ShadowjumpScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/SurpriseAttackScroll.cs b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/SurpriseAttackScroll.cs new file mode 100644 index 0000000..2c3a8ed --- /dev/null +++ b/Scripts/Vivre/Items/Skills Item/Magical/Scroll/NinjitsuScroll/SurpriseAttackScroll.cs @@ -0,0 +1,42 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SurpriseAttackScroll : SpellScroll + { + [Constructable] + public SurpriseAttackScroll() : this( 1 ) + { + } + + [Constructable] + public SurpriseAttackScroll(int amount) + : base(504, 0x46AE, amount) + { + Name = "Surprise Attack Scroll"; + } + + public SurpriseAttackScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Tailoring/RubanCheveux.cs b/Scripts/Vivre/Items/Tailoring/RubanCheveux.cs new file mode 100644 index 0000000..8d7b4db --- /dev/null +++ b/Scripts/Vivre/Items/Tailoring/RubanCheveux.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using Server.Gumps; +using Server.Network; + + +namespace Server.Items +{ + public class RubanCheveux : Item, IDyable + { + + [Constructable] + public RubanCheveux() + : base(0xE20) + { + Name = "Ruban à cheveux"; + Weight = 1; + Stackable = false; + + } + + + public override void OnDoubleClick(Mobile from) + { + // Scriptiz : comment un int peut-il être null? ^^ + //if (from.HairItemID == null ) return; + + if (! ((from.BodyValue == 0x190) || (from.BodyValue == 0x191) ) ) + { + from.SendMessage("Désolé, vous ne semblez pas morphologiquements compatible"); + return; + } + + + if ( !IsChildOf(from.Backpack) ) + { + from.SendMessage("Ce serait beaucoup plus pratique s'il était sur vous"); + return ; + } + + + + if ((from.HairItemID == 0x203C) || (from.HairItemID == 0x203D) || (from.HairItemID == 0x2049)) // respectivement cheveux longs, queue de cheval, tresses + + from.SendGump( new GrubanCheveuxGump() ); + + + else + + from.SendMessage("Désolé, il va falloir les laisser pousser un peu"); + + + } + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + else if (RootParent is Mobile && from != RootParent) + return false; + + Hue = sender.DyedHue; + + return true; + } + + + public RubanCheveux(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} + +namespace Server.Gumps +{ + public class GrubanCheveuxGump : Gump + { + public GrubanCheveuxGump() + : base(0, 0) + { + Closable = true; + Disposable = true; + Dragable = true; + Resizable = false; + AddPage(0); + AddBackground(0, 0, 285, 185, 9270); + AddButton(100, 55, 0xA9A, 0xA9B, 1, GumpButtonType.Reply, 0); + AddButton(100, 95, 0xA9A, 0xA9B, 2, GumpButtonType.Reply, 0); + AddButton(100, 135, 0xA9A, 0xA9B, 3, GumpButtonType.Reply, 0); + AddLabel(95, 16, 0x111, "Choix de coiffure"); + AddLabel(150, 55, 0x111, "Attachés"); + AddLabel(150, 95, 0x111, "Détachés"); + AddLabel(150, 135, 0x111, "Tressés"); + + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + int cheveux = from.HairItemID; + + switch (info.ButtonID) + { + + + + case 1: + { + + if (cheveux == 0x203d) + { + from.SendMessage("Vos cheveux sont déja attachés"); + break; + } + + else + { + from.SendMessage("Vous attachez vos cheveux "); + from.PlaySound(0x57); + from.HairItemID = 0x203D; + + break; + } + } + + case 2: + { + if (cheveux == 0x203c) + { + from.SendMessage("Vos cheveux sont déja détachés"); + break; + } + + else + { + from.SendMessage("Vous détachez vos cheveux "); + from.PlaySound(0x57); + from.HairItemID = 0x203c; + + break; + + + } + } + + case 3: + { + if (cheveux == 0x2049) + { + from.SendMessage("Vos cheveux sont déja tressés"); + break; + } + + else + { + from.SendMessage("Vous tressez vos cheveux "); + from.PlaySound(0x57); + from.HairItemID = 0x2049; + + break; + + } + + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Tailoring/pillows.cs b/Scripts/Vivre/Items/Tailoring/pillows.cs new file mode 100644 index 0000000..9339135 --- /dev/null +++ b/Scripts/Vivre/Items/Tailoring/pillows.cs @@ -0,0 +1,256 @@ +using System; +using Server.Engines.Craft; +using System.Collections.Generic; +using Server.Network; + + +namespace Server.Items +{ + public class SmallPillow : Item , IDyable + { + + [Constructable] + public SmallPillow() : base( 0x1397 ) + { + Weight = 1.0; + Name = "petit coussin"; + } + + + + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + else if (RootParent is Mobile && from != RootParent) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public SmallPillow(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + + + } + + public class Pillow : Item, IDyable + { + + [Constructable] + public Pillow() + : base(0x163c) + { + Weight = 1.0; + Name = "coussin"; + } + + + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + else if (RootParent is Mobile && from != RootParent) + return false; + + Hue = sender.DyedHue; + + return true; + } + + + public Pillow(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + + + } + + + public class BigPillow : Item, IDyable + { + + [Constructable] + public BigPillow() + : base(0x163A) + { + Weight = 1.0; + Name = "gros coussin"; + } + + + + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + else if (RootParent is Mobile && from != RootParent) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public BigPillow(Serial serial) + : base(serial) + { + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + + + } + + public class SmallDiagPillow : Item, IDyable + { + + [Constructable] + public SmallDiagPillow() + : base(0x13AB) + { + Weight = 1.0; + Name = "petit oreiller"; + } + + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + else if (RootParent is Mobile && from != RootParent) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public SmallDiagPillow(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + + + } + + + public class DiagPillow : Item, IDyable + { + + [Constructable] + public DiagPillow() + : base(0x163B) + { + Weight = 1.0; + Name = "petit oreiller"; + } + + + public virtual bool Dye(Mobile from, DyeTub sender) + { + if (Deleted) + return false; + else if (RootParent is Mobile && from != RootParent) + return false; + + Hue = sender.DyedHue; + + return true; + } + + public DiagPillow(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + } + + + } + + + + + +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Trap/HallucinogenTrap.cs b/Scripts/Vivre/Items/Trap/HallucinogenTrap.cs new file mode 100644 index 0000000..a4786cb --- /dev/null +++ b/Scripts/Vivre/Items/Trap/HallucinogenTrap.cs @@ -0,0 +1,114 @@ +using System; +using Server; +using Server.Network; +using Server.Regions; +using Server.Mobiles; + +namespace Server.Items +{ + public class HallucinogenTrap : BaseTrap, ICarvable + { + [Constructable] + public HallucinogenTrap() + : base(0x1125) + { + } + + public override bool PassivelyTriggered { get { return true; } } + public override TimeSpan PassiveTriggerDelay { get { return TimeSpan.FromSeconds(6); } } + public override int PassiveTriggerRange { get { return 6; } } + public override TimeSpan ResetDelay { get { return TimeSpan.Zero; } } + + private DateTime m_NextHarvestTime; + + [CommandProperty(AccessLevel.GameMaster)] + public DateTime HarvestTime + { + get { return m_NextHarvestTime; } + set { m_NextHarvestTime = value; } + } + + public void Carve(Mobile from, Item item) + { + if (from.IsHallucinated || from.Poisoned) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, true, "Vous ne pouvez cueillir convenablement dans cet état", from.NetState); + return; + } + if (DateTime.Now < m_NextHarvestTime) + { + from.PrivateOverheadMessage(MessageType.Regular, 0x3B2, true, "Il n'y a pas assez de spores à récolter", from.NetState); + return; + } + + from.SendMessage("Vous cueillez le champignon"); + from.AddToBackpack(new HallucinogenMushroom()); + + HarvestTime = DateTime.Now + TimeSpan.FromHours(Utility.RandomMinMax(2,10)); // TODO: Proper time delay + } + + + public override void OnTrigger(Mobile from) + { + if (!from.Alive || ItemID != 0x1125 || from.AccessLevel > AccessLevel.Player) + return; + + ItemID = 0x1126; + Effects.PlaySound(Location, Map, 0x306); + + foreach (NetState state in this.GetClientsInRange(PassiveTriggerRange)) + { + if (state.Mobile is PlayerMobile) + { + PlayerMobile junkie = state.Mobile as PlayerMobile; + + if ( junkie.FindItemOnLayer(Layer.Helm) is VivreCagoule) //à changer! + return; + + if (junkie.Hallucinating) + junkie.ApplyPoison(junkie, Utility.RandomBool() ? Poison.Regular : Poison.Lethal); + else + { + junkie.Hallucinating = true; + Timer.DelayCall(TimeSpan.FromMinutes(5), HallucinogenPotion.StopHallucinate, junkie); + } + junkie.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "*Semble étouffé par les spores du champignon*"); + } + else if (!state.Mobile.Poisoned) + state.Mobile.ApplyPoison(state.Mobile, Utility.RandomBool() ? Poison.Regular : Poison.Greater); + } + Timer.DelayCall(TimeSpan.FromSeconds(2), new TimerCallback(OnMushroomReset)); + } + + public virtual void OnMushroomReset() + { + if(Utility.RandomBool()) + Delete(); + else + ItemID = 0x1125; // reset + } + + public HallucinogenTrap(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + writer.WriteDeltaTime(m_NextHarvestTime); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + m_NextHarvestTime = reader.ReadDeltaTime(); + if (ItemID == 0x1126) + OnMushroomReset(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Weapon/Swords/PaladinSword.cs b/Scripts/Vivre/Items/Weapon/Swords/PaladinSword.cs new file mode 100644 index 0000000..8dfe516 --- /dev/null +++ b/Scripts/Vivre/Items/Weapon/Swords/PaladinSword.cs @@ -0,0 +1,57 @@ +//Myron : Paladin sword - 20-24 comme sur osi +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute(0x26ce, 0x26cf)] + public class PaladinSword : BaseSword + { + public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.WhirlwindAttack; } } + public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.Disarm; } } + + public override int AosStrengthReq{ get{ return 85; } } + public override int AosMinDamage{ get{ return 20; } } + public override int AosMaxDamage{ get{ return 24; } } + public override int AosSpeed{ get{ return 22; } } + public override float MlSpeed{ get{ return 5.0f; } } + + public override int OldStrengthReq{ get{ return 85; } } + public override int OldMinDamage{ get{ return 20; } } + public override int OldMaxDamage{ get{ return 24; } } + public override int OldSpeed{ get{ return 30; } } + + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 36; } } + public override int InitMaxHits{ get{ return 48; } } + + + [Constructable] + public PaladinSword() : base(0x26ce) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + } + + public PaladinSword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Weapon/TrainingBow.cs b/Scripts/Vivre/Items/Weapon/TrainingBow.cs new file mode 100644 index 0000000..8d3e948 --- /dev/null +++ b/Scripts/Vivre/Items/Weapon/TrainingBow.cs @@ -0,0 +1,62 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13B2, 0x13B1 )] + public class TrainingBow : BaseRanged + { + public override int EffectID{ get{ return 0xF42; } } + public override Type AmmoType{ get{ return typeof( Arrow ); } } + public override Item Ammo{ get{ return new Arrow(); } } + + public override int AosStrengthReq{ get{ return 15; } } + public override int AosMinDamage{ get{ return 2;} } + public override int AosMaxDamage{ get{ return 4; } } + public override int AosSpeed{ get{ return 20; } } + public override float MlSpeed{ get{ return 5.25f; } } + + public override int OldStrengthReq{ get{ return 20; } } + public override int OldMinDamage{ get{ return 9; } } + public override int OldMaxDamage{ get{ return 41; } } + public override int OldSpeed{ get{ return 20; } } + + public override int DefMaxRange{ get{ return 6; } } + + public override int InitMinHits{ get{ return 15; } } + public override int InitMaxHits{ get{ return 20; } } + + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } } + + [Constructable] + public TrainingBow() : base( 0x13B2 ) + { + Weight = 6.0; + Layer = Layer.TwoHanded; + Name = "Arc d'entrainement"; + } + + public TrainingBow(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( Weight == 7.0 ) + Weight = 6.0; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Weapon/TrainingClub.cs b/Scripts/Vivre/Items/Weapon/TrainingClub.cs new file mode 100644 index 0000000..e1bd0d9 --- /dev/null +++ b/Scripts/Vivre/Items/Weapon/TrainingClub.cs @@ -0,0 +1,50 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0x13b4, 0x13b3 )] + public class TrainingClub : BaseBashing + { + public override int AosStrengthReq{ get{ return 30; } } + public override int AosMinDamage{ get{ return 2; } } + public override int AosMaxDamage{ get{ return 4; } } + public override int AosSpeed{ get{ return 44; } } + public override float MlSpeed{ get{ return 3.50f; } } + + public override int OldStrengthReq{ get{ return 10; } } + public override int OldMinDamage{ get{ return 8; } } + public override int OldMaxDamage{ get{ return 24; } } + public override int OldSpeed{ get{ return 40; } } + + public override int InitMinHits{ get{ return 15; } } + public override int InitMaxHits{ get{ return 20; } } + + [Constructable] + public TrainingClub() : base( 0x13B4 ) + { + Weight = 9.0; + Name = "Masse d'entrainement"; + } + + public TrainingClub(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Weapon/TrainingDagger.cs b/Scripts/Vivre/Items/Weapon/TrainingDagger.cs new file mode 100644 index 0000000..3b27d93 --- /dev/null +++ b/Scripts/Vivre/Items/Weapon/TrainingDagger.cs @@ -0,0 +1,55 @@ +using System; +using Server.Network; +using Server.Targeting; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF52, 0xF51 )] + public class TrainingDagger : BaseKnife + { + public override int AosStrengthReq{ get{ return 10; } } + public override int AosMinDamage{ get{ return 2; } } + public override int AosMaxDamage{ get{ return 4; } } + public override int AosSpeed{ get{ return 56; } } + public override float MlSpeed{ get{ return 3.00f; } } + + public override int OldStrengthReq{ get{ return 1; } } + public override int OldMinDamage{ get{ return 3; } } + public override int OldMaxDamage{ get{ return 15; } } + public override int OldSpeed{ get{ return 55; } } + + public override int InitMinHits{ get{ return 15; } } + public override int InitMaxHits{ get{ return 20; } } + + public override SkillName DefSkill{ get{ return SkillName.Fencing; } } + public override WeaponType DefType{ get{ return WeaponType.Piercing; } } + public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.Pierce1H; } } + + [Constructable] + public TrainingDagger() : base( 0xF52 ) + { + Weight = 1.0; + Name = "Dague d'entrainement"; + } + + public TrainingDagger(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Items/Weapon/TrainingSword.cs b/Scripts/Vivre/Items/Weapon/TrainingSword.cs new file mode 100644 index 0000000..521f6d8 --- /dev/null +++ b/Scripts/Vivre/Items/Weapon/TrainingSword.cs @@ -0,0 +1,54 @@ +using System; +using Server.Network; +using Server.Items; + +namespace Server.Items +{ + [FlipableAttribute( 0xF61, 0xF60 )] + public class TrainingSword : BaseSword + { + + public override int AosStrengthReq{ get{ return 20; } } + public override int AosMinDamage{ get{ return 2; } } + public override int AosMaxDamage{ get{ return 4; } } + public override int AosSpeed{ get{ return 30; } } + public override float MlSpeed{ get{ return 4.50f; } } + + public override int OldStrengthReq{ get{ return 25; } } + public override int OldMinDamage{ get{ return 5; } } + public override int OldMaxDamage{ get{ return 33; } } + public override int OldSpeed{ get{ return 35; } } + + public override int DefHitSound{ get{ return 0x237; } } + public override int DefMissSound{ get{ return 0x23A; } } + + public override int InitMinHits{ get{ return 15; } } + public override int InitMaxHits{ get{ return 20; } } + + [Constructable] + public TrainingSword() + : base(0xF61) + { + Weight = 7.0; + Name = "�p�e d'entrainement"; + } + + public TrainingSword( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mercenaries/BaseMercenary.cs b/Scripts/Vivre/Mercenaries/BaseMercenary.cs new file mode 100644 index 0000000..07ba947 --- /dev/null +++ b/Scripts/Vivre/Mercenaries/BaseMercenary.cs @@ -0,0 +1,67 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("Corps d'un mercenaire")] + public class BaseMercenary : BaseCreature + { + public BaseMercenary() + : base(AIType.AI_Melee, FightMode.Closest, 10, 2, 0.1, 0.2) + { + BodyValue = 400; + Hue = Utility.RandomSkinHue(); + + Utility.AssignRandomHair(this); + HairHue = Utility.RandomHairHue(); + + if (Utility.Random(20) > 15) + { + Utility.AssignRandomFacialHair(this); + FacialHairHue = HairHue; + } + + SpeechHue = Utility.RandomDyedHue(); + + Backpack bp = new Backpack(); + bp.Movable = false; + AddItem(bp); + } + + public override void OnDeath(Container c) + { + // No loot ! + foreach (Item i in c.Items) + { + i.Delete(); + } + + // fun? + if (Utility.Random(25) == 10) + { + Item apple = new Apple(); + apple.Name = "Pomme qui tua Blanche-Neige"; + c.AddItem(apple); + } + + base.OnDeath(c); + } + + public BaseMercenary(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mercenaries/MercenaryA.cs b/Scripts/Vivre/Mercenaries/MercenaryA.cs new file mode 100644 index 0000000..cb298f2 --- /dev/null +++ b/Scripts/Vivre/Mercenaries/MercenaryA.cs @@ -0,0 +1,48 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class MercenaryA : BaseMercenary + { + public static int Price = 50; + + [Constructable] + public MercenaryA() + : base() + { + Name = "Compagnon"; + + // stats + SetStr(20, 40); + SetDex(20, 40); + SetInt(20, 40); + + // equip + AddItem(new Shirt(Utility.RandomDyedHue())); + AddItem(new LongPants(Utility.RandomDyedHue())); + AddItem(new Dagger()); + AddItem(new Shoes(1527)); + + // skills + SetSkill(SkillName.Fencing, 40); + } + + public MercenaryA(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mercenaries/MercenaryB.cs b/Scripts/Vivre/Mercenaries/MercenaryB.cs new file mode 100644 index 0000000..f63067d --- /dev/null +++ b/Scripts/Vivre/Mercenaries/MercenaryB.cs @@ -0,0 +1,55 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class MercenaryB : BaseMercenary + { + public static int Price = 500; + + [Constructable] + public MercenaryB() + : base() + { + Name = "Homme de main"; + + // stats + SetStr(50, 70); + SetDex(50, 70); + SetInt(20, 40); + + // equip + AddItem(new ChainChest()); + AddItem(new ChainCoif()); + AddItem(new ChainLegs()); + AddItem(new Broadsword()); + int hue = Utility.RandomDyedHue(); + AddItem(new Cloak(hue)); + AddItem(new Surcoat(hue)); + AddItem(new Shoes(1527)); + + // skills + SetSkill(SkillName.Swords, 50, 70); + SetSkill(SkillName.Parry, 30, 50); + SetSkill(SkillName.Anatomy, 30, 50); + SetSkill(SkillName.Tactics, 30, 50); + } + + public MercenaryB(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mercenaries/MercenaryC.cs b/Scripts/Vivre/Mercenaries/MercenaryC.cs new file mode 100644 index 0000000..dee1fc2 --- /dev/null +++ b/Scripts/Vivre/Mercenaries/MercenaryC.cs @@ -0,0 +1,68 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class MercenaryC : BaseMercenary + { + public static int Price = 1000; + + [Constructable] + public MercenaryC() + : base() + { + Name = "Mercenaire aguerri"; + + // stats + SetStr(90, 100); + SetDex(70, 100); + SetInt(30, 50); + + // equip + AddItem(new PlateArms()); + Console.WriteLine("1"); + AddItem(new PlateChest()); + Console.WriteLine("2"); + AddItem(new PlateGloves()); + Console.WriteLine("3"); + AddItem(new PlateGorget()); + Console.WriteLine("4"); + AddItem(new PlateHelm()); + Console.WriteLine("5"); + AddItem(new PlateLegs()); + Console.WriteLine("6"); + AddItem(new Broadsword()); + Console.WriteLine("7"); + AddItem(new Cloak(Utility.RandomDyedHue())); + Console.WriteLine("8"); + Item shield = new HeaterShield(Utility.RandomDyedHue()); + AddItem(shield); + Console.WriteLine("9"); + AddItem(new Shoes(1527)); + Console.WriteLine("0"); + + // skills + SetSkill(SkillName.Swords, 50, 70); + SetSkill(SkillName.Parry, 30, 50); + SetSkill(SkillName.Anatomy, 30, 50); + SetSkill(SkillName.Tactics, 30, 50); + } + + public MercenaryC(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Misc/IPRestarter.cs b/Scripts/Vivre/Misc/IPRestarter.cs new file mode 100644 index 0000000..b556999 --- /dev/null +++ b/Scripts/Vivre/Misc/IPRestarter.cs @@ -0,0 +1,66 @@ +using System; +using System.Net; + +namespace Server.Misc +{ + public class IPRestarter + { + private static Timer m_IPTimer; + + public static void Initialize() + { + m_IPTimer = new IPCheckTimer(); + m_IPTimer.Start(); + } + + private class IPCheckTimer : Timer + { + private string m_Adress; + + public IPCheckTimer() + : base(TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)) + { + IPAddress ip = ServerList.FindPublicAddress(); + + // On ne lance pas le timer si pas d'adresse IP trouvée sur internet + if(ip == null) + { + Console.WriteLine("Adresse IP introuvable, êtes vous connecté à internet?"); + Console.WriteLine("IPRestarter désactivé car pas d'adresse IP."); + Stop(); + } + else + { + m_Adress = ServerList.FindPublicAddress().ToString(); + } + } + + protected override void OnTick() + { + // Si pas d'IP enregistrée on arrête le timer + if(m_Adress == null) + { + Stop(); + return; + } + + // Si on ne trouve pas l'ip, on ne reboot pas et on continue le timer. + IPAddress ip = ServerList.FindPublicAddress(); + if(ip == null) + { + Console.WriteLine("Adresse IP introuvable, vérifiez votre connexion à internet."); + return; + } + + // Si adresse IP changée et personne en ligne, on reboot + if (m_Adress != ip.ToString() && Network.NetState.Instances.Count == 0) + { + World.Broadcast(0x35, false, "Changement d'adresse IP détecté, redémarrage en cours..."); + Logging.RestartLog("Redémarrage du serveur car changement d'adresse IP détecté"); + AutoSave.Save(); + Core.Kill(true); + } + } + } + } +} diff --git a/Scripts/Vivre/Misc/Logging.cs b/Scripts/Vivre/Misc/Logging.cs new file mode 100644 index 0000000..f5a6c1a --- /dev/null +++ b/Scripts/Vivre/Misc/Logging.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; + +namespace Server.Misc +{ + public class Logging + { + public static void DebugLog(string text) + { + using (StreamWriter sw = new StreamWriter("debug.log", true)) + { + sw.WriteLine(String.Format("{0} : {1}", DateTime.Now, text)); + Console.WriteLine("[Debug] : " + text); + } + } + + public static void RestartLog(string text) + { + using (StreamWriter sw = new StreamWriter("restart.log", true)) + { + sw.WriteLine(String.Format("{0} : {1}", DateTime.Now, text)); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Misc/SalaryPayment.cs b/Scripts/Vivre/Misc/SalaryPayment.cs new file mode 100644 index 0000000..c07c1b5 --- /dev/null +++ b/Scripts/Vivre/Misc/SalaryPayment.cs @@ -0,0 +1,81 @@ +using System; +using Server.Network; +using Server; +using Server.Mobiles; +using Server.Regions; +using Server.Items; +using System.Collections; + +namespace Server.Misc +{ + public class SalaryTimer : Timer + { + public static void Initialize() + { + new SalaryTimer().Start(); + } + + + public SalaryTimer() + : base(TimeSpan.FromDays(1), TimeSpan.FromDays(1)) + { + Priority = TimerPriority.OneMinute; + } + + protected override void OnTick() + { + SalaryPayment(); + } + + public static void SalaryPayment() + { + ArrayList payment = new ArrayList(); + + foreach (Item item in World.Items.Values) + { + if (item is SalaryChest) + payment.Add(item); + } + + foreach (Item item in payment) + { + SalaryChest chest = item as SalaryChest; + + if (!chest.Active) + continue; + + if (chest.Employer == null || chest.Employer.AccessLevel >= AccessLevel.GameMaster) + { + + Item check = chest.FindItemByType(typeof(BankCheck)); + if (check != null) + { + BankCheck dropcheck = check as BankCheck; + dropcheck.Worth += chest.Salary; + } + else chest.DropItem(new BankCheck(chest.Salary)); + } + else + { + Container cont = chest.Employer.FindBankNoCreate(); + + if (cont != null && Banker.Withdraw( chest.Employer, chest.Salary )) + { + Item check = chest.FindItemByType(typeof(BankCheck)); + if (check != null) + { + BankCheck dropcheck = check as BankCheck; + dropcheck.Worth += chest.Salary; + } + else chest.DropItem(new BankCheck(chest.Salary)); + } + else + { + chest.Active = false; + } + } + } + } + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/AngryDragon/AngryDragon.cs b/Scripts/Vivre/Mobiles/AngryDragon/AngryDragon.cs new file mode 100644 index 0000000..6e42d9a --- /dev/null +++ b/Scripts/Vivre/Mobiles/AngryDragon/AngryDragon.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class AngryDragon : BaseCreature + { + [Constructable] + public AngryDragon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un dragon Enrag�"; + Body = Utility.RandomList( 12, 59 ); + BaseSoundID = 362; + + SetStr( 796 ); + SetDex( 86 ); + SetInt( 436 ); + + SetHits( 478 ); + + SetDamage( 16 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 55 ); + SetResistance( ResistanceType.Fire, 60 ); + SetResistance( ResistanceType.Cold, 30 ); + SetResistance( ResistanceType.Poison, 25 ); + SetResistance( ResistanceType.Energy, 35 ); + + SetSkill( SkillName.EvalInt, 30.1 ); + SetSkill( SkillName.Magery, 30.1 ); + SetSkill( SkillName.MagicResist, 99.1 ); + SetSkill( SkillName.Tactics, 97.6 ); + SetSkill( SkillName.Wrestling, 90.1 ); + + VirtualArmor = 60; + + } + + public override bool ReacquireOnMovement{ get{ return true; } } + public override bool HasBreath{ get{ return true; } } // fire breath enabled + public override bool AutoDispel{ get{ return true; } } + public override bool BardImmune {get {return true;} } + + public override bool OnBeforeDeath() + { + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "*La b�te s'envole, vaincue*"); + this.YellowHealthbar = true; + Timer.DelayCall(TimeSpan.FromSeconds(3), Delete); + return false; + } + + + public AngryDragon(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/AngryDragon/AngryDrake.cs b/Scripts/Vivre/Mobiles/AngryDragon/AngryDrake.cs new file mode 100644 index 0000000..482d131 --- /dev/null +++ b/Scripts/Vivre/Mobiles/AngryDragon/AngryDrake.cs @@ -0,0 +1,74 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a drake corpse" )] + public class AngryDrake : BaseCreature + { + [Constructable] + public AngryDrake () : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Un drake enrag�"; + Body = Utility.RandomList( 60, 61 ); + BaseSoundID = 362; + + SetStr( 401 ); + SetDex( 133 ); + SetInt( 101 ); + + SetHits( 241); + + SetDamage( 11 ); + + SetDamageType( ResistanceType.Physical, 80 ); + SetDamageType( ResistanceType.Fire, 20 ); + + SetResistance( ResistanceType.Physical, 45 ); + SetResistance( ResistanceType.Fire, 50 ); + SetResistance( ResistanceType.Cold, 40 ); + SetResistance( ResistanceType.Poison, 20 ); + SetResistance( ResistanceType.Energy, 30 ); + + SetSkill( SkillName.MagicResist, 65.1 ); + SetSkill( SkillName.Tactics, 65.1 ); + SetSkill( SkillName.Wrestling, 65.1 ); + + VirtualArmor = 46; + + + } + + public override bool ReacquireOnMovement { get { return true; } } + public override bool HasBreath { get { return true; } } // fire breath enabled + public override bool AutoDispel { get { return true; } } + public override bool BardImmune { get { return true; } } + + public override bool OnBeforeDeath() + { + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "*La b�te s'envole, vaincue*"); + this.YellowHealthbar = true; + Timer.DelayCall(TimeSpan.FromSeconds(3), Delete); + return false; + } + + public AngryDrake(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/AngryDragon/AngryGreaterDragon.cs b/Scripts/Vivre/Mobiles/AngryDragon/AngryGreaterDragon.cs new file mode 100644 index 0000000..496ab77 --- /dev/null +++ b/Scripts/Vivre/Mobiles/AngryDragon/AngryGreaterDragon.cs @@ -0,0 +1,78 @@ +using System; +using Server; +using Server.Items; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "a dragon corpse" )] + public class AngryGreaterDragon : BaseCreature + { + + [Constructable] + public AngryGreaterDragon () : base( AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5 ) + { + Name = "Un grand dragon enrag�"; + Body = Utility.RandomList( 12, 59 ); + BaseSoundID = 362; + + SetStr( 1025 ); + SetDex( 81); + SetInt( 475 ); + + SetHits( 1000 ); + SetStam( 120); + + SetDamage( 24); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 60 ); + SetResistance( ResistanceType.Fire, 65 ); + SetResistance( ResistanceType.Cold, 40 ); + SetResistance( ResistanceType.Poison, 40 ); + SetResistance( ResistanceType.Energy, 50 ); + + SetSkill( SkillName.EvalInt, 110.0 ); + SetSkill( SkillName.Magery, 110.0 ); + SetSkill( SkillName.MagicResist, 110.0); + SetSkill( SkillName.Tactics, 110.0 ); + SetSkill( SkillName.Wrestling, 115.0 ); + + + VirtualArmor = 60; + + } + + public override bool ReacquireOnMovement { get { return true; } } + public override bool HasBreath { get { return true; } } // fire breath enabled + public override bool AutoDispel { get { return true; } } + public override bool BardImmune { get { return true; } } + + public override bool OnBeforeDeath() + { + this.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, "*La b�te s'envole, vaincue*"); + this.YellowHealthbar = true; + Timer.DelayCall(TimeSpan.FromSeconds(3), Delete); + return false; + } + + + public AngryGreaterDragon(Serial serial) + : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mobiles/Animals/Brebis.cs b/Scripts/Vivre/Mobiles/Animals/Brebis.cs new file mode 100644 index 0000000..c31ddc5 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Animals/Brebis.cs @@ -0,0 +1,111 @@ +using System; +using Server; +using Server.Items; +using Server.Mobiles; +using Server.Network; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de brebis" )] + public class Brebis : BaseCreature, ICarvable + { + private DateTime m_NextWoolTime; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextWoolTime + { + get{ return m_NextWoolTime; } + set{ m_NextWoolTime = value; Body = ( DateTime.Now >= m_NextWoolTime ) ? 0xCF : 0xDF; } + } + + public void Carve( Mobile from, Item item ) + { + if ( DateTime.Now < m_NextWoolTime ) + { + // This sheep is not yet ready to be shorn. + PrivateOverheadMessage( MessageType.Regular, 0x3B2, false, "Cette brebis n'est pas pr�te pour la tonte", from.NetState ); + return; + } + + from.SendMessage( "Vous placez la laine tondue dans votre sac" ); // You place the gathered wool into your backpack. + from.AddToBackpack( new Wool( Map == Map.Felucca ? 2 : 1 ) ); + + NextWoolTime = DateTime.Now + TimeSpan.FromHours( 3.0 ); // TODO: Proper time delay + } + + public override void OnThink() + { + base.OnThink(); + Body = ( DateTime.Now >= m_NextWoolTime ) ? 0xCF : 0xDF; + } + + [Constructable] + public Brebis() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une brebis"; + Body = 0xCF; + BaseSoundID = 0xD6; + + SetStr( 19 ); + SetDex( 25 ); + SetInt( 5 ); + + SetHits( 12 ); + SetMana( 0 ); + + SetDamage( 1, 2 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 6.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 300; + Karma = 0; + + VirtualArmor = 6; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public override int Meat{ get{ return 2; } } + public override MeatType MeatType{ get{ return MeatType.LambLeg; } } + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + public override bool NoHouseRestrictions { get { return true; } } + public override int Wool{ get{ return (Body == 0xCF ? 2 : 0); } } + + public Brebis(Serial serial) : base(serial) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); + + writer.WriteDeltaTime( m_NextWoolTime ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 1: + { + NextWoolTime = reader.ReadDeltaTime(); + break; + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Animals/Chevre.cs b/Scripts/Vivre/Mobiles/Animals/Chevre.cs new file mode 100644 index 0000000..334c659 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Animals/Chevre.cs @@ -0,0 +1,66 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Un corps de ch�vre" )] + public class Chevre : BaseCreature + { + [Constructable] + public Chevre() : base( AIType.AI_Animal, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + Name = "Une ch�vre"; + Body = 0xD1; + BaseSoundID = 0x99; + + SetStr( 19 ); + SetDex( 15 ); + SetInt( 5 ); + + SetHits( 12 ); + SetMana( 0 ); + + SetDamage( 3, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 15 ); + + SetSkill( SkillName.MagicResist, 5.0 ); + SetSkill( SkillName.Tactics, 5.0 ); + SetSkill( SkillName.Wrestling, 5.0 ); + + Fame = 150; + Karma = 0; + + VirtualArmor = 10; + + Tamable = true; + ControlSlots = 1; + MinTameSkill = 11.1; + } + + public override int Meat{ get{ return 2; } } + public override int Hides{ get{ return 4; } } + public override FoodType FavoriteFood{ get{ return FoodType.GrainsAndHay | FoodType.FruitsAndVegies; } } + public override bool NoHouseRestrictions { get { return true; } } + public Chevre(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/DraconisCultists/AssassinAI.cs b/Scripts/Vivre/Mobiles/DraconisCultists/AssassinAI.cs new file mode 100644 index 0000000..36bb90c --- /dev/null +++ b/Scripts/Vivre/Mobiles/DraconisCultists/AssassinAI.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections; +using Server.Targeting; +using Server.Network; + +// +// Vinds : Exp�rimentations pour une ai type rodeur/assassin. +// Avouons le, peut mieux faire. +// + +namespace Server.Mobiles +{ + public class AssassinAI : BaseAI + { + public AssassinAI(BaseCreature m) + : base(m) + { + } + + + public override bool DoActionWander() + { + if (!(m_Mobile.Hidden)) + { + m_Mobile.UseSkill(SkillName.Hiding); + } + + + if (m_Mobile.Hidden) + { + m_Mobile.UseSkill(SkillName.Stealth); + } + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + + if (!(m_Mobile.Hidden)) + { + m_Mobile.UseSkill(SkillName.Hiding); + } + + m_Mobile.UseSkill(SkillName.Stealth); + Action = ActionType.Combat; + } + + else + { + base.DoActionWander(); + } + + return true; + } + + + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + + if (!(m_Mobile.Hidden)) + { + m_Mobile.DebugSay("Il n'y a pas d'enemis en vue donc j'essaie de me cacher"); + + m_Mobile.UseSkill(SkillName.Hiding); + + } + + Action = ActionType.Guard; + return true; + } + + if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception)) + { + // They are somewhat far away, can we find something else? + if (!(m_Mobile.Hidden)) + { + m_Mobile.UseSkill(SkillName.Hiding); + } + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (!(m_Mobile.Hidden)) + { + + m_Mobile.UseSkill(SkillName.Hiding); + } + + + m_Mobile.Combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + else if (!m_Mobile.InRange(combatant, m_Mobile.RangePerception * 3)) + { + m_Mobile.Combatant = null; + } + + combatant = m_Mobile.Combatant; + + if (combatant == null) + { + + + if (!(m_Mobile.Hidden)) + { + m_Mobile.DebugSay("l'�nemi a fui, je me cache "); + + m_Mobile.UseSkill(SkillName.Hiding); + } + + else if (m_Mobile.Hidden) + { + + m_Mobile.UseSkill(SkillName.Stealth); + } + + Action = ActionType.Guard; + + return true; + } + } + + /*if ( !m_Mobile.InLOS( combatant ) ) + { + if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) + { + m_Mobile.Combatant = combatant = m_Mobile.FocusMob; + m_Mobile.FocusMob = null; + } + }*/ + + if (MoveTo(combatant, true, m_Mobile.RangeFight)) + { + if (m_Mobile.Hidden) + { + m_Mobile.UseSkill(SkillName.Stealth); + + } + + + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant);// + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant) | Direction.Running; + } + else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Hidden) + { + m_Mobile.UseSkill(SkillName.Stealth); + + } + if (m_Mobile.Debug) + m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + + return true; + } + else if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + + + if (!(m_Mobile.Hidden)) + { + m_Mobile.DebugSay("j'ai perdu l'�nemi de vue donc j'essaie de me cacher"); + + m_Mobile.UseSkill(SkillName.Hiding); + } + + + Action = ActionType.Guard; + + return true; + } + else + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + + if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee) + { + if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100) + { + // We are low on health, should we flee? + + bool flee = false; + + if (m_Mobile.Hits < combatant.Hits) + { + // We are more hurt than them + + int diff = combatant.Hits - m_Mobile.Hits; + + flee = (Utility.Random(0, 100) < (10 + diff)); // (10 + diff)% chance to flee + } + else + { + flee = Utility.Random(0, 100) < 20; // 20% chance to flee + } + + if (flee) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I am going to flee from {0}", combatant.Name); + + if ((m_Mobile.Hidden)) + { + m_Mobile.DebugSay("je veux fuire tout en restant invisible"); + + m_Mobile.UseSkill(SkillName.Stealth); + } + + Action = ActionType.Flee; + } + } + } + + return true; + } + + public override bool DoActionGuard() + { + if (!(m_Mobile.Hidden)) + { + m_Mobile.DebugSay("l'�nemi a fui, je me cache "); + + m_Mobile.UseSkill(SkillName.Hiding); + } + + + if (m_Mobile.Hidden) + { + m_Mobile.UseSkill(SkillName.Stealth); + + } + + + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + if (m_Mobile.Debug) + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + { + base.DoActionGuard(); + } + + return true; + } + + + + + public override bool DoActionFlee() + { + if (m_Mobile.Hits > m_Mobile.HitsMax / 2) + { + m_Mobile.DebugSay("I am stronger now, so I will continue fighting"); + Action = ActionType.Combat; + } + else + { + if ((m_Mobile.Mana >= 20) && !(m_Mobile.Hidden) && (Utility.Random(100) > 49 ) ) + { + m_Mobile.Emote("*Avale une potion*"); + m_Mobile.Hits += 30; + m_Mobile.Hidden = true; + + m_Mobile.UseSkill(SkillName.Stealth); + } + + m_Mobile.FocusMob = m_Mobile.Combatant; + base.DoActionBackoff(); + } + + return true; + } + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/DraconisCultists/CultistAssassin.cs b/Scripts/Vivre/Mobiles/DraconisCultists/CultistAssassin.cs new file mode 100644 index 0000000..dc3db1b --- /dev/null +++ b/Scripts/Vivre/Mobiles/DraconisCultists/CultistAssassin.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; +using Server.Mobiles; +using Server.Engines.XmlSpawner2; + +namespace Server.Mobiles +{ + [CorpseName( "Assassin du Culte" )] + public class CultistAssassin : BaseCreature + { + [Constructable] + public CultistAssassin() : base( AIType.AI_Assassin, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Assassin du Culte"; + Body = 0x190; + + SetStr( 85, 120 ); + SetDex( 100, 120 ); + SetInt( 151, 200 ); + + SetHits( 200 ); + SetStam( 150 ); + SetMana( 120 ); + + SetDamage( 8, 10 ); + + SetDamageType( ResistanceType.Physical, 70 ); + SetDamageType( ResistanceType.Poison, 30 ); + + SetResistance( ResistanceType.Physical, 30, 40 ); + SetResistance( ResistanceType.Fire, 60, 80 ); + SetResistance( ResistanceType.Cold, 40, 40 ); + SetResistance( ResistanceType.Poison, 40, 50 ); + SetResistance( ResistanceType.Energy, 50, 60 ); + + SetSkill( SkillName.Poisoning, 120.0 ); + SetSkill( SkillName.MagicResist, 100, 120 ); + SetSkill( SkillName.Tactics, 100.0 ); + SetSkill( SkillName.Fencing, 90.1, 110.0 ); + SetSkill( SkillName.Anatomy, 100.0 ); + SetSkill(SkillName.Hiding,100); + SetSkill(SkillName.Stealth, 120.0); + SetSkill(SkillName.Focus, 120.0); + + + ActiveSpeed = 0.12; + PassiveSpeed = 0.250; + + + Fame = 5000; + Karma = -5000; + + VirtualArmor = 40; + + + HairItemID = 0; + AddItem(new StuddedChest()); + AddItem(new StuddedArms()); + AddItem(new StuddedGloves()); + AddItem(new StuddedGorget()); + AddItem(new StuddedLegs()); + AddItem(new Boots()); + + Dagger weapon = new Dagger(); + + weapon.Movable = false; + weapon.Quality = WeaponQuality.Exceptional; + weapon.Attributes.WeaponDamage = 40; + weapon.WeaponAttributes.HitLeechHits = 30; + AddItem(weapon); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Rich, 2 ); + } + + public override Poison PoisonImmune{ get{ return Poison.Deadly; } } + public override Poison HitPoison{ get{ return Poison.Deadly; } } + public override int TreasureMapLevel{ get{ return 5; } } + + + public override void OnGotMeleeAttack(Mobile attacker) + { + base.OnGotMeleeAttack(attacker); + + if (attacker is BaseCreature && ((BaseCreature)attacker).Summoned) //pas subtil, mais la bestiole peut tanker...un peu :) + { + Hidden = true; + UseSkill(SkillName.Stealth); + Combatant = ((BaseCreature)attacker).SummonMaster; + + attacker.RawStr = 10; + attacker.RawInt = 1; + attacker.RawDex = 10; + attacker.Mana = 5; + attacker.Stam = 0; + + } + + } + public override void OnGaveMeleeAttack(Mobile defender) + { + + base.OnGaveMeleeAttack(defender); + + if (defender is BaseCreature && ((BaseCreature)defender).Summoned) + { + Hidden = true; + UseSkill(SkillName.Stealth); + Combatant = ((BaseCreature)defender).SummonMaster; + + defender.RawStr = 10; + defender.RawInt = 1; + defender.RawDex = 10; + defender.Mana = 5; + defender.Stam = 0; + } + } + + public override void OnDamagedBySpell(Mobile from) + { + base.OnDamagedBySpell(from); + this.Hidden = true; + this.UseSkill(SkillName.Stealth); + return; + } + + public CultistAssassin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Misc/OrcBanker.cs b/Scripts/Vivre/Mobiles/Misc/OrcBanker.cs new file mode 100644 index 0000000..2d3cac0 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Misc/OrcBanker.cs @@ -0,0 +1,83 @@ +using System; +using Server.Items; + +namespace Server.Mobiles +{ + public class OrcBanker : BaseCreature + { + [Constructable] + public OrcBanker() + : base(AIType.AI_Vendor, FightMode.None, 12, 1, 2, 2) + { + Name = NameList.RandomName("orc"); + Title = "L'Orc Sympathique"; + Body = 17; + BaseSoundID = 0x45A; + Blessed = true; + Hue = 2001; + } + + public OrcBanker(Serial serial) + : base(serial) + { + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from is PlayerMobile && from.InRange(this, 12)) + return true; + + return false; + } + + public override void OnSpeech(SpeechEventArgs e) + { + base.OnSpeech(e); + + string speech = e.Speech.ToLower(); + + if (speech.IndexOf("banque") != -1) + Say("Toi donner pomme, moi amener coffre."); + else if (speech.IndexOf("orc") != -1) + Say("Moi entendre toi parler de moi ! *grogne*"); + else if (speech.IndexOf("bonjour") != -1) + Say("Toi vouloir coffre de banque ?"); + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is Apple && from != null) + { + dropped.Consume(); + Emote("*dévore la pomme*"); + PlaySound(Utility.Random(0x3A, 3)); + + if (dropped.Amount >= 2 || Utility.Random(5) > 0) + { + Say("Voici coffre !"); + from.BankBox.Open(); + } + else + Say("Moi encore faim !"); + + return true; + } + else + return base.OnDragDrop(from, dropped); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mobiles/Misc/RidableBoura.cs b/Scripts/Vivre/Mobiles/Misc/RidableBoura.cs new file mode 100644 index 0000000..49e0da0 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Misc/RidableBoura.cs @@ -0,0 +1,40 @@ +using System; +using Server.Mobiles; +using Server.Items; +using Server.Spells; +using Server.Engines.VeteranRewards; + +namespace Server.Items +{ + public class RideableBoura : EtherealMount + { + public override int LabelNumber { get { return 1150006; } } + + [Constructable] + public RideableBoura() + : base(0x46F9, 0x3EC6) + { + } + + public override int EtherealHue { get { return 0; } } + + public RideableBoura(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Mustangs/BaseMustang.cs b/Scripts/Vivre/Mobiles/Mustangs/BaseMustang.cs new file mode 100644 index 0000000..9233b9f --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/BaseMustang.cs @@ -0,0 +1,70 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "un mustang mort" )] + public abstract class BaseMustang : BaseMount + { + + + public BaseMustang( int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, int rangeFight, double activeSpeed, double passiveSpeed ) : base ( "Un Mustang", bodyID, itemID, aiType, fightMode, rangePerception, rangeFight, activeSpeed, passiveSpeed ) + { + + BaseSoundID = 0xA8; + + SetStr( 70, 120 ); + SetDex( 70, 105 ); + SetInt( 9, 15 ); + + SetHits( 80, 120 ); + SetMana( 0 ); + + SetDamage( 3, 4 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 10, 20 ); + SetResistance( ResistanceType.Cold, 10, 20 ); + SetResistance( ResistanceType.Poison, 10, 20 ); + SetResistance( ResistanceType.Energy, 10, 20 ); + + SetSkill( SkillName.MagicResist, 25.1, 30.0 ); + SetSkill( SkillName.Tactics, 29.3, 44.0 ); + SetSkill( SkillName.Wrestling, 29.3, 44.0 ); + + Fame = 300; + Karma = 300; + + Tamable = true; + ControlSlots = 1; + } + + public override FoodType FavoriteFood{ get{ return FoodType.FruitsAndVegies | FoodType.GrainsAndHay; } } + + public BaseMustang( Serial serial ) : base( serial ) + { + } + public override double GetControlChance(Mobile m, bool useBaseSkill) + { + return 0.6; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangBleuCiel.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangBleuCiel.cs new file mode 100644 index 0000000..131cc61 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangBleuCiel.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangBleuCiel : BaseMustang + { + + [Constructable] + public MustangBleuCiel() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x0263; + Name = "Mustang Bleu Ciel"; + + MinTameSkill = 74.1; + } + + public MustangBleuCiel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangChocolat.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangChocolat.cs new file mode 100644 index 0000000..29d0cf5 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangChocolat.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangChocolat : BaseMustang + { + + [Constructable] + public MustangChocolat() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x01bb; + Name = "Mustang Chocolat"; + + MinTameSkill = 74.1; + } + + public MustangChocolat( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + + + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangCrimson.Cs b/Scripts/Vivre/Mobiles/Mustangs/MustangCrimson.Cs new file mode 100644 index 0000000..83a07bd --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangCrimson.Cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangCrimson : BaseMustang + { + + [Constructable] + public MustangCrimson() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x1b6; + Name = "Mustang Crimson"; + + MinTameSkill = 79.1; + } + + public MustangCrimson( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangGris.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangGris.cs new file mode 100644 index 0000000..5d7a4a4 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangGris.cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangGris : BaseMustang + { + + [Constructable] + public MustangGris() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x03e7; + Name = "Mustang Gris"; + + MinTameSkill = 69.1; + } + + public MustangGris( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangGrisCiel.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangGrisCiel.cs new file mode 100644 index 0000000..17cf346 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangGrisCiel.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangGrisCiel : BaseMustang + { + + [Constructable] + public MustangGrisCiel() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x031c; + Name = "Mustang Gris Ciel"; + + MinTameSkill = 69.1; + } + + public MustangGrisCiel( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangNoir.Cs b/Scripts/Vivre/Mobiles/Mustangs/MustangNoir.Cs new file mode 100644 index 0000000..e54a3a7 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangNoir.Cs @@ -0,0 +1,37 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangBlack : BaseMustang + { + + [Constructable] + public MustangBlack() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x455; + Name = "Mustang noir"; + + MinTameSkill = 79.1; + } + + public MustangBlack( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangPanamino.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangPanamino.cs new file mode 100644 index 0000000..472ad25 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangPanamino.cs @@ -0,0 +1,39 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangPamamino : BaseMustang + { + + [Constructable] + public MustangPamamino() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x033; + Name = "Mustang Pamamino"; + + MinTameSkill = 74.1; + } + + public MustangPamamino( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangRougeBasane.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangRougeBasane.cs new file mode 100644 index 0000000..d12ce5f --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangRougeBasane.cs @@ -0,0 +1,40 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangRougeBasane : BaseMustang + { + + [Constructable] + public MustangRougeBasane() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x0279; + Name = "Mustang Rouge basan�"; + + MinTameSkill = 79.1; + } + + public MustangRougeBasane( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + + + diff --git a/Scripts/Vivre/Mobiles/Mustangs/MustangWimmimate.cs b/Scripts/Vivre/Mobiles/Mustangs/MustangWimmimate.cs new file mode 100644 index 0000000..69f2982 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Mustangs/MustangWimmimate.cs @@ -0,0 +1,38 @@ +using System; +using Server; + +namespace Server.Mobiles +{ + public class MustangWimmimate : BaseMustang + { + + [Constructable] + public MustangWimmimate() : base( 0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4 ) + { + + Hue = 0x0158; + Name = "Mustang Wimmimate"; + + MinTameSkill = 69.1; + } + + public MustangWimmimate( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/Mobiles/Vendors/SBInfo/SBPeddler.cs b/Scripts/Vivre/Mobiles/Vendors/SBInfo/SBPeddler.cs new file mode 100644 index 0000000..eb3a07f --- /dev/null +++ b/Scripts/Vivre/Mobiles/Vendors/SBInfo/SBPeddler.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Mobiles +{ + public class SBPeddler : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBPeddler() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo("La lanterne du Grand Dragon", typeof(DragonLantern), 500000, 1, 0x49C2, 0)); + /* + Add(new GenericBuyInfo(typeof(Bacon), 7, 20, 0x979, 0)); + Add(new GenericBuyInfo(typeof(Ham), 26, 20, 0x9C9, 0)); + Add(new GenericBuyInfo(typeof(Sausage), 18, 20, 0x9C0, 0)); + Add(new GenericBuyInfo(typeof(RawChickenLeg), 6, 20, 0x1607, 0)); + Add(new GenericBuyInfo(typeof(RawBird), 9, 20, 0x9B9, 0)); + Add(new GenericBuyInfo(typeof(RawLambLeg), 9, 20, 0x1609, 0)); + Add(new GenericBuyInfo(typeof(RawRibs), 16, 20, 0x9F1, 0)); + Add(new GenericBuyInfo(typeof(ButcherKnife), 13, 20, 0x13F6, 0)); + Add(new GenericBuyInfo(typeof(Cleaver), 13, 20, 0xEC3, 0)); + Add(new GenericBuyInfo(typeof(SkinningKnife), 13, 20, 0xEC4, 0)); + */ + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Vendors/ThePeddler.cs b/Scripts/Vivre/Mobiles/Vendors/ThePeddler.cs new file mode 100644 index 0000000..ff24995 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Vendors/ThePeddler.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using Server; +using System.Runtime.CompilerServices; + +namespace Server.Mobiles +{ + public class ThePeddler : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + private Timer peddlerSpeech; // le timer pour qu'il parle + + // la chanson du peddler + public static List Lyrics = new List() { + "Moi je viens d'un pays de désert infini,", + "Où les caravanes rêvent et flânent.", + "Où, pendant ton sommeil,", + "Les serpents t'ensorcellent !", + "C'est bizarre çà ?", + "Mais, eh, c'est chez moi !", + "Quand le vent vient de l'Est,", + "Le soleil est à l'Ouest,", + "Et s'endort dans les sables d'or...", + "C'est l'instant envoûtant,", + "Vole en tapis volant,", + "Vers la magie des nuits d'Orient !", + "Oh Nuits d'arabie,", + "Mille et une folies.", + "Insomnie d'amour,", + "Plus chaude à minuit", + "Qu'au soleil, en plein jour !", + "Oh Nuits d'arabie,", + "Au parfum de velours.", + "Pour le fou qui se perd,", + "Au coeur du désert,", + "Fatal est l'amour ! " + }; + + // les phrases du peddler + public static List Speech = new List() + { + "Aaaah, salam ! Je vous souhaite le bonsoir mon noble ami. Approchez, approchez, venez plus prêt...", + "TROP PRET! Un peu trop prêt, voilà.", + "Bienvenue à Agrabba, cité de la magie noire, des enchantements...", + "Et les plus belles marchandises du Jourdan en soldes aujourd'hui, profitez-en !", + "Regardez, oui, un combiné narguilé et cafetière qui fait aussi les pommes de terres frites !", + "Incassable, incass... cassé.", + "Ooooooh, regardez, c'est la première fois que j'en vois un aussi bien conservé, c'est le célèbre Tupperware de la Mer Morte, écoutez! *PROUT*", + "Aaah, il fonctionne, huhu.", + "Attendez une seconde, je vois que vous vous intéressez qu'aux objets exceptionnellement rare.", + "Il me semble avoir ici de quoi faire votre bonheur, voyez !", + "Ne vous laissez pas rebuter par son apparente banalité comme tant d’autres choses ce n’est pas ce qu’il y a à l’extérieur, mais ce qu’il y a à l’intérieur qui compte !", + "Ce n’est pas n’importe quelle lampe ! Elle a même changé le cours de la vie d’un jeune homme.", + "Et ce jeune homme, tout comme cette lampe, valait beaucoup plus qu’on ne l’estimait...", + "Un diamant d’innocence !", + "Je vous raconte cette histoire ?", + "Elle commence par une nuit... noire, où l’on découvre un homme en noir, nourrissant de noirs desseins." + }; + + + [Constructable] + public ThePeddler() + : base("le Colporteur") + { + Name = "Ikboul"; + Female = false; + SpeechHue = 234; + peddlerSpeech = new PeddlerSpeechTimer(this); + peddlerSpeech.Start(); + } + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBPeddler()); + } + + public ThePeddler(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + private class PeddlerSpeechTimer : Timer + { + private Mobile m_Peddler; + private int indexLyrics; + private int indexSpeech; + + private bool isSinging; + private bool isSpeaking; + + public PeddlerSpeechTimer(Mobile peddler) + : base(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)) + { + m_Peddler = peddler; + indexLyrics = indexSpeech = 0; + isSinging = isSpeaking = false; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + protected override void OnTick() + { + base.OnTick(); + + bool doSing = false; + bool doSpeak = false; + + foreach (Mobile m in m_Peddler.GetMobilesInRange(12)) + { + if (m is PlayerMobile && m != null && !m.Hidden && m != m_Peddler) + { + if (m_Peddler.GetDistanceToSqrt(m) < 16) doSing = true; + + if (m_Peddler.GetDistanceToSqrt(m) < 6) + { + doSing = false; + doSpeak = true; + } + } + } + + if (!isSinging && !isSpeaking) + { + if (doSing) Sing(); + else if(doSpeak) Speak(); + } + } + + [MethodImpl(MethodImplOptions.Synchronized)] + private void Sing() + { + // Si la chanson est finie on s'arrête + if (indexLyrics >= ThePeddler.Lyrics.Count) + { + indexLyrics = 0; + isSinging = false; + return; + } + else + { + // Sinon on vérifie si personne n'est trop prêt + bool stop = true; + foreach (Mobile m in m_Peddler.GetMobilesInRange(6)) + { + stop = false; + if (m != null && m is PlayerMobile) + { + // Si il y a quelqu'un trop prêt on arrête la chanson et on dit "approchez ..." + isSinging = false; + isSpeaking = true; + indexLyrics = indexSpeech = 0; + Speak(); + return; + } + } + + m_Peddler.Say(ThePeddler.Lyrics[indexLyrics++]); + if(!stop) Timer.DelayCall(TimeSpan.FromSeconds(8), new TimerCallback(Sing)); + } + } + + [MethodImpl(MethodImplOptions.Synchronized)] + private void Speak() + { + // Si c'est la fin du speech on s'arrête + if (indexSpeech >= ThePeddler.Speech.Count) + { + indexLyrics = 0; + isSpeaking = false; + return; + } + else + { + // Sinon on vérifie qu'il reste des gens tout prêt + bool stop = true; + foreach (Mobile m in m_Peddler.GetMobilesInRange(6)) + { + if (m != null && m == m_Peddler) continue; + if (m.Hidden || !(m is PlayerMobile)) continue; + + stop = false; + break; + } + + m_Peddler.Say(ThePeddler.Speech[indexSpeech++]); + if (!stop) Timer.DelayCall(TimeSpan.FromSeconds(15), new TimerCallback(Speak)); + else + { + isSinging = false; + isSpeaking = false; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/VivreGuards/AI/VivreGuardAI.cs b/Scripts/Vivre/Mobiles/VivreGuards/AI/VivreGuardAI.cs new file mode 100644 index 0000000..c7c4cd0 --- /dev/null +++ b/Scripts/Vivre/Mobiles/VivreGuards/AI/VivreGuardAI.cs @@ -0,0 +1,173 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using Server.Targeting; +using Server.Network; +using Server.Mobiles; +using Server.Items; +using Server.Gumps; +using Server.Misc; +using Server.Regions; +using Server.SkillHandlers; +using Server.ContextMenus; +using Server.Spells; + +namespace Server.Mobiles +{ + public class VivreGuardAI : BaseAI + { + public VivreGuardAI(BaseCreature m) + : base(m) + { + } + + private bool isGuard(Mobile from) + { + if (from.FindItemOnLayer(Layer.Cloak) is GuardCloak) return true; + + return false; + } + + private bool isEnnemi(Mobile from) + { + if (isGuard(from)) return false; + + if (from.Criminal == true) return true; + + if (from is BaseCreature) { + BaseCreature mobfrom = (BaseCreature)from; + + if (mobfrom.AI == AIType.AI_Archer || mobfrom.AI == AIType.AI_Berserk || mobfrom.AI == AIType.AI_Melee || mobfrom.AI == AIType.AI_Ninja || mobfrom.AI == AIType.AI_OrcScout || mobfrom.AI == AIType.AI_Predator || mobfrom.AI == AIType.AI_Mage) + return !mobfrom.Controlled; + } + return false; + } + + public override bool DoActionWander() + { + m_Mobile.DebugSay("I have no combatant"); + m_Mobile.Criminal = false; + + // Scriptiz : on dégomme les criminal + foreach (Mobile m in m_Mobile.GetMobilesInRange(m_Mobile.RangePerception)) + { + if (m == null) continue; + if (m == m_Mobile) continue; + if(!(m is PlayerMobile)) continue; + + if (isGuard(m) && m.Combatant != null && m.Combatant.Alive && !isGuard(m.Combatant) && !m.Combatant.Hidden) + { + m_Mobile.Combatant = m.Combatant; + m.Criminal = false; + } + else if (m.Criminal && m.Alive && isEnnemi(m) && !m.Hidden) + { + m_Mobile.Combatant = m; + } + + // Scriptiz : criminalité descendue dans les villes, on réduit les gardes (pas de teleport) + //if (m_Mobile.Combatant != null) + //{ + // Mobile crim = m_Mobile.Combatant; + + // // Si trop proche ça ne sert à rien + // if (m_Mobile.GetDistanceToSqrt(crim.Location) < 10) continue; + + // // Sinon on téléporte le garde + // IPoint3D p = crim.Location as IPoint3D; + + // SpellHelper.GetSurfaceTop(ref p); + + // Point3D fromLoc = m_Mobile.Location; + // Point3D toLoc = new Point3D(p); + + // m_Mobile.Location = toLoc; + // m_Mobile.ProcessDelta(); + + // if (!crim.Hidden) + // crim.Hidden = false; + + // Effects.SendLocationParticles(EffectItem.Create(fromLoc, m_Mobile.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); + // Effects.SendLocationParticles(EffectItem.Create(toLoc, crim.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 5023); + + // m.PlaySound(0x1FE); + //} + } + + if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true)) + { + m_Mobile.DebugSay("I see {0}", m_Mobile.FocusMob.Name); + if (isEnnemi((Mobile)m_Mobile.FocusMob)) + { + m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name); + m_Mobile.Combatant = m_Mobile.FocusMob; + Action = ActionType.Combat; + } + else + base.DoActionWander(); + } + else + base.DoActionWander(); + + return true; + } + + public override bool DoActionCombat() + { + Mobile combatant = m_Mobile.Combatant; + + if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map) + { + m_Mobile.DebugSay("My combatant is gone, so my guard is up"); + Action = ActionType.Wander; + return true; + } + + if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight)) + { + m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant); + } + else + { + if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1) + { + m_Mobile.DebugSay("I cannot find {0} him", combatant.Name); + Action = ActionType.Wander; + return true; + } + else + { + m_Mobile.DebugSay("I should be closer to {0}", combatant.Name); + } + } + + return true; + } + + public override bool DoActionBackoff() + { + if (m_Mobile.IsHurt() || m_Mobile.Combatant != null) + { + Action = ActionType.Combat; + } + else + { + if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true)) + { + if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2)) + { + m_Mobile.DebugSay("Well, here I am safe"); + Action = ActionType.Wander; + } + } + else + { + m_Mobile.DebugSay("I have lost my focus, lets relax"); + Action = ActionType.Wander; + } + } + + return true; + } + } +} diff --git a/Scripts/Vivre/Mobiles/VivreGuards/Guards/VivreGuard.cs b/Scripts/Vivre/Mobiles/VivreGuards/Guards/VivreGuard.cs new file mode 100644 index 0000000..d20dbd4 --- /dev/null +++ b/Scripts/Vivre/Mobiles/VivreGuards/Guards/VivreGuard.cs @@ -0,0 +1,176 @@ +using System; +using Server.Items; +using Server.Mobiles; + +namespace Server.Mobiles +{ + public class VivreGuard : BaseCreature + { + private String m_TownName; + + [CommandProperty(AccessLevel.GameMaster)] + public int TownHue + { + get + { + if (m_TownName.ToLower() == "haven") + return 1779; + else if (m_TownName.ToLower() == "fort serpent") + return 2112; + else + return 0; + } + } + + [Constructable] + public VivreGuard(String townName) + : base(AIType.AI_VivreGuard, FightMode.Closest, 18, 1, 0.12, 1) // 0.15 echapable à pied, 0.05 = très rapide + { + m_TownName = townName; + InitStats(200, 200, 200); + SpeechHue = Utility.RandomDyedHue(); + Hue = Utility.RandomSkinHue(); + Body = 0x190; + Name = NameList.RandomName("male"); + Title = ", Garde de " + m_TownName; + Karma = 12000; + + PlateChest chest = new PlateChest(); + chest.Hue = 0; + chest.Resource = CraftResource.MBronze; + chest.Movable = false; + AddItem(chest); + PlateArms arms = new PlateArms(); + arms.Hue = 0; + arms.Movable = false; + arms.Resource = CraftResource.MBronze; + AddItem(arms); + PlateGloves gloves = new PlateGloves(); + gloves.Hue = 0; + gloves.Movable = false; + gloves.Resource = CraftResource.MBronze; + AddItem(gloves); + PlateGorget gorget = new PlateGorget(); + gorget.Hue = 0; + gorget.Movable = false; + gorget.Resource = CraftResource.MBronze; + AddItem(gorget); + PlateLegs legs = new PlateLegs(); + legs.Hue = 0; + legs.Movable = false; + legs.Resource = CraftResource.MBronze; + AddItem(legs); + NorseHelm helm = new NorseHelm(); + helm.Hue = 0; + helm.Movable = false; + helm.Resource = CraftResource.MBronze; + AddItem(helm); + Surcoat surcoat = new Surcoat(); + surcoat.Hue = 0; + surcoat.Movable = false; + AddItem(surcoat); + Cloak cloak = new Cloak(); + cloak.Hue = TownHue; + cloak.Movable = false; + AddItem(cloak); + + + HairItemID = Utility.RandomList(0x203B, 0x203C, 0x203D, 0x2044, 0x2045, 0x2047, 0x2049, 0x204A); + HairHue = Utility.RandomHairHue(); + + if (Utility.RandomBool()) + { + FacialHairItemID = Utility.RandomList(0x203E, 0x203F, 0x2040, 0x2041, 0x204B, 0x204C, 0x204D); + FacialHairHue = HairHue; + } + + Halberd weapon = new Halberd(); + weapon.Movable = false; + weapon.Crafter = this; + weapon.Quality = WeaponQuality.Exceptional; + VirtualArmor = 100; + + AddItem(weapon); + + Skills[SkillName.Anatomy].Base = 100.0; + Skills[SkillName.Tactics].Base = 110.0; + Skills[SkillName.Swords].Base = 160.0; + Skills[SkillName.MagicResist].Base = 110.0; + Skills[SkillName.DetectHidden].Base = 100.0; + } + + // Scriptiz : pour capté les baseCreature ;) + public override bool IsEnemy(Mobile m) + { + if (m != null && (m.Criminal == true || m is BaseCreature)) + return true; + else + return base.IsEnemy(m); + } + + public override bool Unprovokable { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public override bool BardImmune { get { return true; } } + public VivreGuard(Serial serial) + : base(serial) + { + } + + public String TownName + { + get { return m_TownName; } + set { m_TownName = value; } + } + + public override bool OnBeforeDeath() + { + return true; + } + + public override void OnCombatantChange() + { + base.OnCombatantChange(); + + if (Combatant != null) + this.Say("Un Hors la Loi !!! Sortez de cette ville ou mourez!"); + } + + public override bool HandlesOnSpeech(Mobile from) + { + if (from is PlayerMobile) return true; + return base.HandlesOnSpeech(from); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && e.Mobile.InRange(this.Location, 1)) + { + PlayerMobile from = e.Mobile as PlayerMobile; + { + e.Handled = true; + this.Say("Veuillez circuler citoyen..."); + base.OnSpeech(e); + } + } + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_TownName); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + m_TownName = reader.ReadString(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/VivreGuards/Item/GuardCloak.cs b/Scripts/Vivre/Mobiles/VivreGuards/Item/GuardCloak.cs new file mode 100644 index 0000000..71bf6c9 --- /dev/null +++ b/Scripts/Vivre/Mobiles/VivreGuards/Item/GuardCloak.cs @@ -0,0 +1,41 @@ +using System; +using Server; + +namespace Server.Items +{ + [Flipable] + public class GuardCloak : Item + { + [Constructable] + public GuardCloak() : base(0x1515) + { + Layer = Layer.Cloak; + Weight = 5.0; + LootType = LootType.Blessed; // Scriptiz : on préfère éviter que ça se promène partout + } + + // Scriptiz : cape non échangeable + public override bool Nontransferable + { + get { return true; } + } + + public GuardCloak(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Yeths/Melee/AmphibienYeth.cs b/Scripts/Vivre/Mobiles/Yeths/Melee/AmphibienYeth.cs new file mode 100644 index 0000000..fab85d9 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Yeths/Melee/AmphibienYeth.cs @@ -0,0 +1,73 @@ +using System; +using Server.Mobiles; + +namespace Server.Mobiles +{ + [CorpseName( "Corps d'Amphibien Yeth" )] + public class AmphibienYeth : BaseCreature + { + [Constructable] + public AmphibienYeth() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + Name = "Amphibien Yeth"; + Body = 0xCA; + Hue = 0455; + BaseSoundID = 660; + + SetStr( 1500, 1700 ); + SetDex( 90, 95 ); + SetInt( 1, 2 ); + + SetHits( 46, 60 ); + SetStam( 46, 65 ); + SetMana( 0 ); + + SetDamage( 5, 15 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 25, 35 ); + SetResistance( ResistanceType.Fire, 100, 100 ); + SetResistance( ResistanceType.Poison, 100, 100 ); + + SetSkill(SkillName.Parry, 50.0, 60.0); + SetSkill(SkillName.Poisoning, 50.0, 60.0); + SetSkill( SkillName.MagicResist, 25.1, 40.0 ); + SetSkill( SkillName.Tactics, 35.1, 50.0 ); + SetSkill( SkillName.Wrestling, 40.1, 60.0 ); + + Fame = 3000; + Karma = -7000; + + VirtualArmor = 30; + + Tamable = false; + } + + public override int Meat{ get{ return 1; } } + public override int Hides{ get{ return 12; } } + public override HideType HideType{ get{ return HideType.Spined; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish; } } + + public AmphibienYeth(Serial serial) : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int) 0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if ( BaseSoundID == 0x5A ) + BaseSoundID = 660; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Yeths/Melee/Brigand_possede.cs b/Scripts/Vivre/Mobiles/Yeths/Melee/Brigand_possede.cs new file mode 100644 index 0000000..8c17f34 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Yeths/Melee/Brigand_possede.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; +using Server.Mobiles; + +namespace Server.Mobiles +{ + public class Brigand_possede : BaseCreature + { + public override bool ClickTitle{ get{ return false; } } + + [Constructable] + public Brigand_possede() : base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 ) + { + SpeechHue = Utility.RandomNeutralHue(); + Title = "Le brigand"; + Hue = Utility.RandomSkinHue(); + + if ( this.Female = Utility.RandomBool() ) + { + Body = 0x191; + Name = NameList.RandomName( "female" ); + AddItem( new Skirt( Utility.RandomNeutralHue() ) ); + } + else + { + Body = 0x190; + Name = NameList.RandomName( "male" ); + AddItem( new ShortPants( Utility.RandomNeutralHue() ) ); + } + + + SetStr(66, 80); + SetDex(81, 95); + SetInt( 61, 75 ); + + SetDamage( 10, 23 ); + + SetSkill( SkillName.Swords, 35.0, 58); + SetSkill( SkillName.Wrestling, 35.0, 58.0); + SetSkill(SkillName.MagicResist, 45.0, 75.0); + SetSkill(SkillName.Macing, 35.50, 59.50); + Fame = RandomMinMaxScaled(2500, 4000); + Karma = -3500; + + AddItem( new Boots( Utility.RandomNeutralHue() ) ); + AddItem( new FancyShirt()); + AddItem( new Bandana()); + + switch ( Utility.Random( 7 )) + { + case 0: AddItem( new Longsword() ); break; + case 1: AddItem( new Cutlass() ); break; + case 2: AddItem( new Broadsword() ); break; + case 3: AddItem( new Axe() ); break; + case 4: AddItem( new Club() ); break; + case 5: AddItem( new Dagger() ); break; + case 6: AddItem( new Spear() ); break; + } + + Utility.AssignRandomHair( this ); + } + + + public override void OnDeath(Container c) + { + ObservateurYeth spawn = new ObservateurYeth(); + Map map = this.Map; + Point3D loc = this.Location; + spawn.MoveToWorld(loc, map); + base.OnDeath(c); + } + + public override void OnActionCombat() + { + int caseSwitch = RandomMinMaxScaled(1, 3); + switch(caseSwitch) + { + case 1: + this.Say("Ils sont en moi... Raah... ! Je suis en toi !"); + break ; + case 2: + this.Say("Je vois leur monde...horreur! Que d'horreur!"); + break ; + case 3: + this.Say("Ils nous veulent pour esclaves...Tu es esclave !"); + break ; + } + base.OnActionCombat(); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Average ); + } + + public override bool AlwaysMurderer{ get{ return true; } } + + public Brigand_possede( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Mobiles/Yeths/Melee/EssenceYeth.cs b/Scripts/Vivre/Mobiles/Yeths/Melee/EssenceYeth.cs new file mode 100644 index 0000000..8d8e2ae --- /dev/null +++ b/Scripts/Vivre/Mobiles/Yeths/Melee/EssenceYeth.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName( "Corps d'Essence Yeth" )] + public class EssenceYeth : BaseCreature + { + [Constructable] + public EssenceYeth() : base( AIType.AI_Melee, FightMode.Closest, 25, 1, 0.2, 0.4 ) + { + Name = "Essence Yeth"; + Body = 51; + BaseSoundID = 456; + Hue = Utility.RandomSlimeHue(); + + SetStr( 700, 800 ); + SetDex( 180, 220 ); + SetInt( 1, 2 ); + + SetHits( 15, 19 ); + + SetDamage( 1, 5 ); + + SetDamageType( ResistanceType.Physical, 100 ); + + SetResistance( ResistanceType.Physical, 5, 10 ); + SetResistance( ResistanceType.Poison, 100, 100 ); + + SetSkill( SkillName.Poisoning, 30.1, 40.0 ); + SetSkill( SkillName.MagicResist, 50.1, 60.0 ); + SetSkill( SkillName.Tactics, 20.0, 35.0 ); + SetSkill( SkillName.Wrestling, 25.0, 40.0 ); + + Fame = 300; + Karma = -300; + + VirtualArmor = 8; + + Tamable = false; + } + + public override bool OnBeforeDeath() + { + Say("L'Essence Yeth se separe en deux!"); + EssenceYeth spawn = new EssenceYeth(); + Map map = this.Map; + Point3D loc = this.Location; + spawn.MoveToWorld(loc, map); + return base.OnBeforeDeath(); + } + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + AddLoot( LootPack.Gems ); + } + + public override Poison PoisonImmune{ get{ return Poison.Lesser; } } + public override Poison HitPoison{ get{ return Poison.Lesser; } } + public override FoodType FavoriteFood{ get{ return FoodType.Meat | FoodType.Fish | FoodType.FruitsAndVegies | FoodType.GrainsAndHay | FoodType.Eggs; } } + + public EssenceYeth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/Mobiles/Yeths/Melee/ObservateurYeth.cs b/Scripts/Vivre/Mobiles/Yeths/Melee/ObservateurYeth.cs new file mode 100644 index 0000000..ed0cfe1 --- /dev/null +++ b/Scripts/Vivre/Mobiles/Yeths/Melee/ObservateurYeth.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections; +using Server.Items; +using Server.ContextMenus; +using Server.Misc; +using Server.Network; +using Server.Mobiles; + +namespace Server.Mobiles +{ + class ObservateurYeth : BaseCreature + { + [Constructable] + public ObservateurYeth() : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "Observateur de Yeth"; + Body = 13; + BaseSoundID = 263; + Hue = 0455; + SetStr(60, 70); + SetDex(40, 50); + SetInt(50, 60); + + SetHits( 196, 213 ); + SetDamage(3, 7); + + SetDamageType( ResistanceType.Physical, 20 ); + SetDamageType( ResistanceType.Cold, 80 ); + + SetResistance( ResistanceType.Physical, 45, 55 ); + SetResistance( ResistanceType.Fire, 10, 15 ); + SetResistance( ResistanceType.Cold, 50, 60 ); + SetResistance(ResistanceType.Poison, 100, 100); + SetResistance(ResistanceType.Energy, 25, 35); + + SetSkill( SkillName.MagicResist, 15.0, 35.0 ); + SetSkill( SkillName.Tactics, 35.1, 45.0 ); + SetSkill( SkillName.Wrestling, 35.0, 50.0); + + Fame = 4000; + Karma = -7000; + + VirtualArmor = 50; + + PackItem( new BlackPearl( 3 ) ); + } + + public override void OnActionCombat() + { + int caseSwitch = RandomMinMaxScaled(1, 4); + switch(caseSwitch) + { + case 1: + this.Say("Ce n'etait qu'un esclave parmi tant d'autres..."); + break ; + case 2: + this.Say("Me tuer ne suffira pas..."); + break ; + case 3: + this.Say("Je n'en suis qu'un parmi des milliers..."); + break ; + case 4: + this.Say("Vous etes revenus pour mieux nous servir..."); + break ; + } + base.OnActionCombat(); + } + + public override void GenerateLoot() + { + AddLoot( LootPack.Poor ); + } + + public override bool BleedImmune{ get{ return true; } } + + public override int TreasureMapLevel{ get{ return Utility.RandomList( 2, 3 ); } } + + public ObservateurYeth( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} + diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Bosses/MasterNecromancer1.cs b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/MasterNecromancer1.cs new file mode 100644 index 0000000..cd5ce70 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/MasterNecromancer1.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName("Corp d'un Nécromant Sombre")] + public class MasterNecromancer1 : BaseCreature, NecroBoss + { + [Constructable] + public MasterNecromancer1() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "Gror'tak Maitre des Squelettes"; + Body = 400; + Hue = 1109; + + Item shroud = new RobeACapuche(1870); + shroud.Movable = false; + AddItem(shroud); + + Item dagger = new Dagger(); + dagger.Name = "Dague Maudite"; + dagger.Hue = 34; + dagger.Movable = false; + AddItem(dagger); + + SetStr(250, 400); + SetDex(50); + SetInt(300, 400); + + SetHits(250, 400); + + SetDamage(15, 25); + + SetDamageType(ResistanceType.Physical, 100); + + SetResistance(ResistanceType.Physical, 100); + SetResistance(ResistanceType.Fire, 50); + SetResistance(ResistanceType.Cold, 50, 70); + SetResistance(ResistanceType.Poison, 50, 70); + SetResistance(ResistanceType.Energy, 70, 90); + + SetSkill(SkillName.MagicResist, 20.1, 30.0); + SetSkill(SkillName.Fencing, 80.1, 100.0); + SetSkill(SkillName.Tactics, 80.1, 100.0); + SetSkill(SkillName.EvalInt, 100); + SetSkill(SkillName.Magery, 60.1, 100.0); + SetSkill(SkillName.Necromancy, 60.1, 100.0); + Fame = 15000; + Karma = -15000; + + VirtualArmor = 80; + + PackItem(new CurseWeaponScroll()); + + if (Utility.Random(4) == 0) + PackItem(new CurseWeaponScroll()); + + if (Utility.Random(20) == 0) + PackItem(new RobeACapuche(1870)); + + PackNecroReg(10, 30); + } + + public override bool Unprovokable { get { return true; } } + public override bool BardImmune { get { return true; } } + public override bool ShowFameTitle { get { return false; } } + public override bool ClickTitle { get { return false; } } + public override bool AlwaysMurderer { get { return true; } } + + public override int GetIdleSound() + { + return 0x107; + } + + public override int GetDeathSound() + { + return 0xFD; + } + + public MasterNecromancer1(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroBeast.cs b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroBeast.cs new file mode 100644 index 0000000..ba1d17e --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroBeast.cs @@ -0,0 +1,82 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("un corps énorme")] + public class NecroBeast : BaseCreature, NecroBoss + { + [Constructable] + public NecroBeast() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "Ulk le géant vert"; + Body = 746; + BaseSoundID = 0x24D; + Hue = 2005; + + SetStr(467, 645); + SetDex(50); + SetInt(126, 150); + + SetHits(296, 372); + SetMana(46, 70); + + SetDamage(18, 22); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 50); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 35, 45); + SetResistance(ResistanceType.Poison, 90, 100); + SetResistance(ResistanceType.Energy, 35, 45); + + SetSkill(SkillName.EvalInt, 70.3, 100.0); + SetSkill(SkillName.Magery, 70.3, 100.0); + SetSkill(SkillName.Poisoning, 60.1, 80.0); + SetSkill(SkillName.MagicResist, 65.1, 80.0); + SetSkill(SkillName.Tactics, 90.1, 100.0); + SetSkill(SkillName.Wrestling, 90.1, 100.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 50; + + PackItem(new HorrificBeastScroll()); + + if (Utility.Random(4) == 0) + PackItem(new AnimateDeadScroll()); + + PackNecroReg(10, 30); + } + + public override Poison PoisonImmune { get { return Poison.Deadly; } } + public override Poison HitPoison { get { return Poison.Deadly; } } + public override bool Unprovokable { get { return true; } } + public override bool BardImmune { get { return true; } } + public override bool ShowFameTitle { get { return false; } } + public override bool ClickTitle { get { return false; } } + public override bool AlwaysMurderer { get { return true; } } + + public NecroBeast(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroBoss.cs b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroBoss.cs new file mode 100644 index 0000000..6efb1a1 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroBoss.cs @@ -0,0 +1,8 @@ +using Server; + +namespace Server.Mobiles +{ + interface NecroBoss + { + } +} diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroLichLord.cs b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroLichLord.cs new file mode 100644 index 0000000..d349792 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroLichLord.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("corps de seigneur liche terrifiant")] + public class NecroLichLord : BaseCreature, NecroBoss + { + [Constructable] + public NecroLichLord() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "Un Seigneur Liche Terrifiant"; + Body = 79; + BaseSoundID = 412; + Hue = 1172; + + SetStr(416, 505); + SetDex(50); + SetInt(566, 655); + + //SetHits(250, 303); + SetHits(350, 403); + SetMana(3000); + + SetDamage(15, 18); + + SetDamageType(ResistanceType.Physical, 0); + SetDamageType(ResistanceType.Cold, 60); + SetDamageType(ResistanceType.Energy, 40); + + SetResistance(ResistanceType.Physical, 40, 50); + SetResistance(ResistanceType.Fire, 30, 40); + SetResistance(ResistanceType.Cold, 50, 60); + SetResistance(ResistanceType.Poison, 50, 60); + SetResistance(ResistanceType.Energy, 40, 50); + + SetSkill(SkillName.EvalInt, 90.1, 100.0); + SetSkill(SkillName.Magery, 90.1, 100.0); + SetSkill(SkillName.MagicResist, 150.5, 200.0); + SetSkill(SkillName.Tactics, 50.1, 70.0); + SetSkill(SkillName.Wrestling, 60.1, 80.0); + + Fame = 18000; + Karma = -18000; + + VirtualArmor = 50; + + int scrolls = Utility.Random(0, 10); + switch (scrolls) + { + case 0: + goto default; + case 1: case 2: case 3: case 4: + PackItem(new MindRotScroll()); + break; + case 5: case 6: case 7: + PackItem(new SummonFamiliarScroll()); + break; + case 8: case 9: + PackItem(new MindRotScroll()); + PackItem(new SummonFamiliarScroll()); + break; + default: + Item i = new Item(8807); + i.Name = "Un Faux Parchemin"; + PackItem(i); + break; + } + + PackNecroReg(30, 50); + } + + public override OppositionGroup OppositionGroup + { + get { return OppositionGroup.FeyAndUndead; } + } + + public override bool CanRummageCorpses { get { return true; } } + public override bool BleedImmune { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + public override int TreasureMapLevel { get { return 4; } } + public override bool BardImmune { get { return true; } } + public override bool Unprovokable { get { return true; } } + + public NecroLichLord(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroMummy.cs b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroMummy.cs new file mode 100644 index 0000000..61d9d19 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/NecroMummy.cs @@ -0,0 +1,111 @@ +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("a necromummy corpse")] + class NecroMummy : BaseCreature, NecroBoss + { + [Constructable] + public NecroMummy() : base( AIType.AI_Melee, FightMode.Closest, 10, 2, 0.2, 0.4 ) + { + Name = "a Necromummy"; + Body = 154; + BaseSoundID = 471; + Hue = 1271; + + SetStr( 350, 500 ); + SetDex(50); + SetInt( 300, 500 ); + + SetHits( 300, 450 ); + + SetDamage( 20, 30 ); + + SetDamageType( ResistanceType.Physical, 40 ); + SetDamageType( ResistanceType.Cold, 60 ); + + SetResistance( ResistanceType.Physical, 70, 90 ); + SetResistance( ResistanceType.Fire, 50 ); + SetResistance( ResistanceType.Cold, 100 ); + SetResistance( ResistanceType.Poison, 50, 70 ); + SetResistance( ResistanceType.Energy, 50, 70 ); + + SetSkill(SkillName.MagicResist, 30.1, 40.0); + SetSkill(SkillName.Wrestling, 90.1, 110.0); + SetSkill(SkillName.Tactics, 90.1, 110.0); + + Fame = 15000; + Karma = -15000; + + VirtualArmor = 82; + + // Loot de sorts + int count = 0; + if (Utility.Random(1, 10) >= 5) + { + PackItem(new EvilOmenScroll()); + count++; + } + + if (Utility.Random(1, 10) >= 6) + { + PackItem(new BloodOathScroll()); + count++; + } + + if (Utility.Random(1, 10) >= 7) + { + PackItem(new CorpseSkinScroll()); + count++; + } + + if (Utility.Random(1, 10) >= 8) + { + PackItem(new WraithFormScroll()); + count++; + } + + if (Utility.Random(1, 10) >= 9) + { + PackItem(new PainSpikeScroll()); + count++; + } + + // Si zéro ou un seul sort, on met le scroll evil omen pour pas que ça soit vide... + if (count <= 1) + PackItem(new EvilOmenScroll()); + + PackNecroReg(20, 40); + } + + public override bool BleedImmune{ get{ return true; } } + public override Poison PoisonImmune{ get{ return Poison.Greater; } } + public override bool Unprovokable { get { return true; } } + public override bool BardImmune { get { return true; } } + public override bool ShowFameTitle { get { return false; } } + public override bool ClickTitle { get { return false; } } + public override bool AlwaysMurderer { get { return true; } } + + public NecroMummy(Serial serial) + : base(serial) + { + } + + public override OppositionGroup OppositionGroup + { + get{ return OppositionGroup.FeyAndUndead; } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Bosses/SleepinessCold.cs b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/SleepinessCold.cs new file mode 100644 index 0000000..5d927dc --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Bosses/SleepinessCold.cs @@ -0,0 +1,106 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + [CorpseName("Azoth")] + public class SleepinessCold : BaseCreature, NecroBoss + { + [Constructable] + public SleepinessCold() + : base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4) + { + Name = "Azoth, le froid glacial"; + Body = 0x105; + + SetStr(509, 538); + SetDex(50); + SetInt(1513, 1578); + + SetHits(750, 1000); + + SetDamage(25, 31); + + SetDamageType(ResistanceType.Physical, 20); + SetDamageType(ResistanceType.Fire, 20); + SetDamageType(ResistanceType.Cold, 20); + SetDamageType(ResistanceType.Poison, 20); + SetDamageType(ResistanceType.Energy, 20); + + SetResistance(ResistanceType.Physical, 75, 76); + SetResistance(ResistanceType.Fire, 60, 65); + SetResistance(ResistanceType.Cold, 60, 70); + SetResistance(ResistanceType.Poison, 76, 80); + SetResistance(ResistanceType.Energy, 75, 78); + + SetSkill(SkillName.Wrestling, 100.2, 101.4); + SetSkill(SkillName.Tactics, 105.5, 102.1); + SetSkill(SkillName.MagicResist, 150); + SetSkill(SkillName.Magery, 150.0); + SetSkill(SkillName.EvalInt, 150.0); + SetSkill(SkillName.Meditation, 120.0); + + Fame = 8000; + Karma = -8000; + + VirtualArmor = 70; + + PackItem(new GnarledStaff()); + PackNecroReg(15, 25); + + PackItem(new WitherScroll()); + + int nScrolls = Utility.Random(4); + for (int i = 0; i < nScrolls; i++) + { + if (Utility.RandomBool()) + PackItem(new WitherScroll()); + } + } + + public override bool CanRummageCorpses { get { return true; } } + public override Poison PoisonImmune { get { return Poison.Lethal; } } + + public override bool AutoDispel { get { return true; } } + public override int TreasureMapLevel { get { return 5; } } + + public SleepinessCold(Serial serial) + : base(serial) + { + } + + public override int GetIdleSound() + { + return 0x1BF; + } + + public override int GetAttackSound() + { + return 0x1C0; + } + + public override int GetHurtSound() + { + return 0x1C1; + } + + public override int GetDeathSound() + { + return 0x1C2; + } + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/NecroTemple/Mobiles/MortysTheMaster.cs b/Scripts/Vivre/NecroTemple/Mobiles/MortysTheMaster.cs new file mode 100644 index 0000000..273df3a --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/MortysTheMaster.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; + +namespace Server.Mobiles +{ + public class MortysTheMaster : BaseCreature + { + [Constructable] + public MortysTheMaster() + : base(AIType.AI_None, FightMode.None, 10, 1, 0.2, 0.4) + { + Name = "Mortys"; + Title = "Le Maitre"; + Direction = Direction.South; + + Body = 400; + Hue = 33797; + Blessed = true; + + InitStats(75, 75, 75); + + SpeechHue = 33; + EmoteHue = 33; + + Backpack bp = new Backpack(); + bp.Movable = false; + AddItem(bp); + AddItem(new RobeACapuche(1109)); + Lantern l = new Lantern(); + l.Hue = 1109; + AddItem(l); + l.Ignite(); + Boots b = new Boots(); + b.Hue = 1109; + AddItem(b); + } + + public override bool HandlesOnSpeech(Mobile from) + { + return from.Alive && from.Skills[SkillName.SpiritSpeak].Base >= 40 && from.InRange(this, 3); + } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled) + { + Mobile m = e.Mobile; + + if (m == null || !m.Player) return; + + string speech = e.Speech.ToLower(); + + if (speech.IndexOf("maitre") >= 0 || speech.IndexOf("maître") >= 0) + { + if (speech.IndexOf("bonjour") >= 0) + Say("*grogne* Que me voulez-vous?"); + else if (speech.IndexOf("livre") >= 0) + { + Say("Vous croyez que je vais vous le donner comme ça? *ricanne*"); + PlaySound(0x246); + Timer.DelayCall(TimeSpan.FromSeconds(3), Say, "Apportez-moi 50 os et je verrais ce que je peux en faire."); + } + else if (speech.IndexOf("os") >= 0) + Say("Si vous avez les os, donnez les moi au lieu d'attendre là !"); + else if (speech.IndexOf("merci") >= 0) + { + Say("Ne me remerciez pas, ce n'est que le début de vos souffrances !"); + Timer.DelayCall(TimeSpan.FromSeconds(3), Say, "N'oubliez pas qui vous servez... *retourne à son grimoire*"); + } + else + Emote("*reste de marbre*"); + } + else if (speech.IndexOf("scriptiz") >= 0) + Say("Ici c'est moi le maître et non cet hurluberlu qui parle chinois !"); + else + Emote("*étudie un grimoire aux pages ravagées sans se soucier de ce qui l'entoure*"); + + e.Handled = true; + } + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is Gold) + { + Emote("*prend l'argent et le glisse dans une petite bourse en ricannant*"); + PlaySound(0x246); + return true; + } + else if (dropped is Bone) + { + if (dropped.Amount >= 50) + { + if (from.Backpack == null) + Say("Et vous le mettrez où votre livre? Revenez quand vous aurez un sac!"); + else if (from.Backpack.FindItemByType(typeof(NecromancerSpellbook)) != null || (from.FindItemOnLayer(Layer.FirstValid) != null && from.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(NecromancerSpellbook))) + Say("Vous avez déjà un livre, déguerpissez !"); + else if (from.Backpack.FindItemByType(typeof(BookOfBushido)) != null || (from.FindItemOnLayer(Layer.FirstValid) != null && from.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfBushido))) + Say("Vous avez déjà choisi une voie qui n'est pas compatible avec l'art sombre que j'enseigne ici..."); + else if (from.Backpack.FindItemByType(typeof(BookOfNinjitsu)) != null || (from.FindItemOnLayer(Layer.FirstValid) != null && from.FindItemOnLayer(Layer.FirstValid).GetType() == typeof(BookOfNinjitsu))) + Say("Vous avez déjà choisi une voie qui n'est pas compatible avec l'art sombre que j'enseigne ici..."); + else + { + Emote("*prend les os et tend un livre sombre en échange*"); + from.Backpack.AddItem(new NecromancerSpellbook()); + } + return true; + } + else + { + Emote("*ricanne*"); + PlaySound(0x246); + Timer.DelayCall(TimeSpan.FromSeconds(2), Say, "Vous me croyez aveugle? Il n'y en a pas assez ! Ramenez le bon nombre la prochaine fois..."); + } + return true; + } + + Say("Ne me refilez pas toutes vos crasses !"); + return false; + } + + public override bool ClickTitle { get { return false; } } + + public MortysTheMaster(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/NecroTemple/Mobiles/NoviceNecromancer.cs b/Scripts/Vivre/NecroTemple/Mobiles/NoviceNecromancer.cs new file mode 100644 index 0000000..309d513 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/NoviceNecromancer.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Targeting; + +namespace Server.Mobiles +{ + [CorpseName("Corp d'un Nécromant")] + public class NoviceNecromancer : BaseCreature + { + [Constructable] + public NoviceNecromancer() + : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.6) + { + Name = "un apprenti nécromant"; + Body = 400; + Hue = 1109; + + Item shroud = new RobeACapuche(1109); + shroud.Movable = false; + AddItem(shroud); + + Item staff = new GnarledStaff(); + staff.Hue = 2211; + staff.Movable = false; + AddItem(staff); + + SetStr(46, 70); + SetDex(31, 50); + SetInt(26, 60); + + SetHits(45, 60); + + SetDamage(5, 13); + + SetDamageType(ResistanceType.Physical, 50); + SetDamageType(ResistanceType.Poison, 25); + SetDamageType(ResistanceType.Energy, 25); + + SetResistance(ResistanceType.Physical, 15, 25); + SetResistance(ResistanceType.Fire, 5, 10); + SetResistance(ResistanceType.Poison, 5, 10); + SetResistance(ResistanceType.Cold, 5, 10); + SetResistance(ResistanceType.Energy, 15, 25); + + SetSkill(SkillName.MagicResist, 15.1, 40.0); + SetSkill(SkillName.Tactics, 35.1, 50.0); + SetSkill(SkillName.Macing, 35.1, 50.0); + SetSkill(SkillName.Necromancy, 35.1, 50.0); + SetSkill(SkillName.Focus, 35.1, 50.0); + SetSkill(SkillName.SpiritSpeak, 35.1, 50.0); + SetSkill(SkillName.Meditation, 35.1, 50.0); + + Fame = 600; + Karma = -600; + + VirtualArmor = 25; + + PackNecroReg(5, 10); + } + + public override bool BleedImmune { get { return false; } } + public override Poison PoisonImmune { get { return Poison.Regular; } } + public override bool BardImmune { get { return true; } } + public override void DisplayPaperdollTo(Mobile to) { } + public override bool AlwaysMurderer { get { return true; } } + + public NoviceNecromancer(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Vendors/NecroVendor.cs b/Scripts/Vivre/NecroTemple/Mobiles/Vendors/NecroVendor.cs new file mode 100644 index 0000000..c4da0dd --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Vendors/NecroVendor.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using Server; +using Server.Items; + +namespace Server.Mobiles +{ + public class NecroVendor : BaseVendor + { + private List m_SBInfos = new List(); + protected override List SBInfos { get { return m_SBInfos; } } + + [Constructable] + public NecroVendor() + : base("le Disciple", "la Disciple") + { + } + + public override void InitSBInfo() + { + m_SBInfos.Add(new SBNecroVendor()); + } + + public override void InitOutfit() + { + //base.InitOutfit(); + + Hue = 33777; + + Item shroud = new RobeACapuche(1109); + shroud.Movable = false; + AddItem(shroud); + + Item staff = new GnarledStaff(); + staff.Hue = 2211; + staff.Movable = false; + AddItem(staff); + } + + public NecroVendor(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/NecroTemple/Mobiles/Vendors/SBInfo/SBNecroVendor.cs b/Scripts/Vivre/NecroTemple/Mobiles/Vendors/SBInfo/SBNecroVendor.cs new file mode 100644 index 0000000..a418622 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/Mobiles/Vendors/SBInfo/SBNecroVendor.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Server.Items; +using Server.Multis; + +namespace Server.Mobiles +{ + public class SBNecroVendor : SBInfo + { + private List m_BuyInfo = new InternalBuyInfo(); + private IShopSellInfo m_SellInfo = new InternalSellInfo(); + + public SBNecroVendor() + { + } + + public override IShopSellInfo SellInfo { get { return m_SellInfo; } } + public override List BuyInfo { get { return m_BuyInfo; } } + + public class InternalBuyInfo : List + { + public InternalBuyInfo() + { + Add(new GenericBuyInfo(typeof(BatWing), 6, 20, 0xF78, 0)); + Add(new GenericBuyInfo(typeof(DaemonBlood), 12, 20, 0xF7D, 0)); + Add(new GenericBuyInfo(typeof(PigIron), 10, 20, 0xF8A, 0)); + Add(new GenericBuyInfo(typeof(NoxCrystal), 12, 20, 0xF8E, 0)); + Add(new GenericBuyInfo(typeof(GraveDust), 6, 20, 0xF8F, 0)); + } + } + + public class InternalSellInfo : GenericSellInfo + { + public InternalSellInfo() + { + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/NecroTemple/NecroExiter.cs b/Scripts/Vivre/NecroTemple/NecroExiter.cs new file mode 100644 index 0000000..d0e802c --- /dev/null +++ b/Scripts/Vivre/NecroTemple/NecroExiter.cs @@ -0,0 +1,65 @@ +/*************************************************************************** + * NecroExiter.cs + * ----------------------------- + * begin : August 10, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-08-10 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Mobiles; +using Server.Misc; + +namespace Server.Items +{ + public class NecroExiter : Teleporter + { + private void EndMessageLock(object state) + { + ((Mobile)state).EndAction(this); + } + + public override bool OnMoveOver(Mobile m) + { + int deleted = ScrollDeleter.DeleteNecroScrolls(m); + if (deleted > 0) m.SendMessage(ScrollDeleter.Message); + + return base.OnMoveOver(m); + } + + [Constructable] + public NecroExiter() + { + } + + public NecroExiter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/NecroTemple/NecroRegion.cs b/Scripts/Vivre/NecroTemple/NecroRegion.cs new file mode 100644 index 0000000..493dac4 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/NecroRegion.cs @@ -0,0 +1,150 @@ +/*************************************************************************** + * NecroRegion.cs + * ----------------------------- + * begin : July 10, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-07-20 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Spells; +using Server.Items; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Third; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; +using Server.Spells.Ninjitsu; +using Server.ServerSeasons; +using Server.Misc; +using Server.Multis; + +namespace Server.Regions +{ + public class NecroRegion : BaseRegion, ISeasons + { + public override Season Season + { + get + { + return ServerSeasons.Season.Desolation; + } + set + { + base.Season = ServerSeasons.Season.Desolation; + } + } + + private Point3D m_EntranceLocation; + private Map m_EntranceMap; + + public Point3D EntranceLocation { get { return m_EntranceLocation; } set { m_EntranceLocation = value; } } + public Map EntranceMap { get { return m_EntranceMap; } set { m_EntranceMap = value; } } + + public NecroRegion(XmlElement xml, Map map, Region parent) + : base(xml, map, parent) + { + XmlElement entrEl = xml["entrance"]; + + Map entrMap = map; + ReadMap(entrEl, "map", ref entrMap, false); + + if (ReadPoint3D(entrEl, entrMap, ref m_EntranceLocation, false)) + m_EntranceMap = entrMap; + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override void OnEnter(Mobile m) + { + if (m is PlayerMobile && ((PlayerMobile)m).Young) + ((PlayerMobile)m).Young = false; + + int deleted = ScrollDeleter.DeleteNecroScrolls(m); + if (deleted > 0) m.SendMessage(ScrollDeleter.Message); + + base.OnEnter(m); + } + + public override void OnExit(Mobile m) + { + int deleted = ScrollDeleter.DeleteNecroScrolls(m); + if (deleted > 0) m.SendMessage(ScrollDeleter.Message); + + base.OnExit(m); + } + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + global = LightCycle.DungeonLevel; + + if(m == null || m.AccessLevel <= AccessLevel.Counselor) + personal = 0; + } + + public override bool CanUseStuckMenu(Mobile m) + { + return false; + } + + public override bool CheckAccessibility(Item item, Mobile from) + { + // Scriptiz : pour empêcher de monter sur un bateau (teleport et recall déjà coupés) + if (item is Plank && from.AccessLevel == AccessLevel.Player) + { + from.SendMessage("Il serait plus sage de ne pas faire cela."); + return false; + } + + return base.CheckAccessibility(item, from); + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if ((s is GateTravelSpell || s is RecallSpell || s is MarkSpell || s is SacredJourneySpell || s is TeleportSpell || s is Shadowjump) && m.AccessLevel == AccessLevel.Player) + { + m.SendMessage("You cannot cast that spell here."); + return false; + } + + // Pour limiter blade spirit à certains endroits + if (s is BladeSpirits) + { + if (this.Name == "Ilot vaseux") + { + m.SendMessage("Les lames s'enfonceraient dans la vase, ce serait bête de jeter ce sort ici."); + return false; + } + } + + return base.OnBeginSpellCast(m, s); + } + + public override bool OnSkillUse(Mobile from, int Skill) + { + if (from.AccessLevel == AccessLevel.Player && Skill == (int)SkillName.Chivalry) + { + from.SendMessage("Une ombre passe au dessus de vous et absorbe la force magique que vous essayez d'invoquer"); + return false; ; + } + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/NecroTemple/NecroTeleporter.cs b/Scripts/Vivre/NecroTemple/NecroTeleporter.cs new file mode 100644 index 0000000..1c6a2a8 --- /dev/null +++ b/Scripts/Vivre/NecroTemple/NecroTeleporter.cs @@ -0,0 +1,364 @@ +/*************************************************************************** + * NecroTeleporter.cs + * ----------------------------- + * begin : July 10, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-07-20 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Items +{ + public class NecroTeleporter : Teleporter + { + private string m_Keyword; // Mot clef + private int m_Range; // Range pour la téléportation + private double m_PlayerNecroRequired; // montant de nécro requis par joueur + private double m_PlayerSpiritRequired; // montant de spirit speak requis par joueur + private int m_PlayerKarmaRequired; // karma requis par joueur + private double m_GroupNecroRequired; // necro totale du groupe requise + private int m_NumNecroRequired; // nombre de joueurs nécros requis + private int m_SpellId1; // sort 1 trouvé dans la salle + private int m_SpellId2; // sort 2 trouvé dans la salle + private int m_SpellId3; // sort 3 trouvé dans la salle + private int m_SpellId4; // sort 4 trouvé dans la salle + private int m_SpellId5; // sort 5 trouvé dans la salle + private int m_SpellId6; // sort 6 trouvé dans la salle + + #region Getters & Setters + [CommandProperty(AccessLevel.Administrator)] + public string Keyword + { + get { return m_Keyword; } + set { m_Keyword = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.Administrator)] + public int Range + { + get { return m_Range; } + set { m_Range = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.Administrator)] + public double PlayerNecroRequired + { + get { return m_PlayerNecroRequired; } + set { m_PlayerNecroRequired = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public double PlayerSpiritRequired + { + get { return m_PlayerSpiritRequired; } + set { m_PlayerSpiritRequired = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int PlayerKarmaRequired + { + get { return m_PlayerKarmaRequired; } + set { m_PlayerKarmaRequired = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public double GroupNecroRequired + { + get { return m_GroupNecroRequired; } + set { m_GroupNecroRequired = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int NumNecroRequired + { + get { return m_NumNecroRequired; } + set { m_NumNecroRequired = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int SpellId1 + { + get { return m_SpellId1; } + set { m_SpellId1 = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int SpellId2 + { + get { return m_SpellId2; } + set { m_SpellId2 = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int SpellId3 + { + get { return m_SpellId3; } + set { m_SpellId3 = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int SpellId4 + { + get { return m_SpellId4; } + set { m_SpellId4 = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int SpellId5 + { + get { return m_SpellId5; } + set { m_SpellId5 = value; } + } + + [CommandProperty(AccessLevel.Administrator)] + public int SpellId6 + { + get { return m_SpellId6; } + set { m_SpellId6 = value; } + } + #endregion + + public override bool HandlesOnSpeech { get { return true; } } + + public override void OnSpeech(SpeechEventArgs e) + { + if (!e.Handled && Active) + { + Mobile m = e.Mobile; + + if (!Creatures && !m.Player) + return; + + if (!m.InRange(GetWorldLocation(), m_Range)) + return; + + // Scriptiz : on vérifie si le mot clé est présent + if (m_Keyword == null) return; + if (e.Speech.ToLower().IndexOf(m_Keyword.ToLower()) < 0) return; + + // On vérifie que chaque joueur possède bien la nécro requise, le spirit speak requis + // le karma requis, et que le groupe possède suffisament de nécro + List necros = new List(); + double totalNecro = 0; + foreach (Mobile mob in this.GetMobilesInRange(m_Range)) + { + PlayerMobile pm = mob as PlayerMobile; + if (pm == null) continue; + if (pm.AccessLevel > AccessLevel.Player) continue; + if (!pm.Alive) continue; + + // Si un joueur ne possède pas le montant de nécro requis, on annule le transfert + Skill sk = m.Skills[SkillName.Necromancy]; + if (sk == null || sk.Base < m_PlayerNecroRequired) + { + pm.SendMessage("Votre connaissance des arts nécromants est trop faible pour continuer."); + return; + } + + // On ajoute le montant de nécro du joueur au total nécro pour vérif ultérieure + totalNecro += sk.Base; + + // Si un joueur ne possède pas le montant de Spirit Speak requis, on annule le transfert + sk = pm.Skills[SkillName.SpiritSpeak]; + if(sk == null || sk.Base < m_PlayerSpiritRequired) + { + pm.SendMessage("Votre connaissance du monde des morts est trop faible pour continuer."); + return; + } + + // Si le joueur ne possède pas assez de Karma négatif, on annule le transfert + if (pm.Karma > m_PlayerKarmaRequired) + { + pm.SendMessage("Vous n'êtes pas encore assez impur pour continuer."); + return; + } + + necros.Add(pm); // On ajoute le PM a la liste des PJ qui se présentent + } + + // S'il n'y a pas assez de nécro on annule le transfert + if (necros.Count < m_NumNecroRequired) + { + foreach (PlayerMobile pm in necros) + if (pm != null) + pm.SendMessage("Vous n'êtes pas assez pour activer cette salle."); + + return; + } + + // Si le montant de nécro de l'ensemble des joueurs n'est pas suffisant on annule le transfert + if (totalNecro < m_GroupNecroRequired) + { + foreach (PlayerMobile pm in necros) + if (pm != null) + pm.SendMessage("Vos connaissances des arts nécromants réunies ne parviennent pas à activer cette salle."); + + return; + } + + // On regarde si tous les nécros ont les sorts que l'on peut trouver dans la salle + bool allHaveSpells = true; + foreach (PlayerMobile pm in necros) + { + if (pm == null) continue; + + bool haveNecroBook = false; + foreach (Item i in pm.Items) + { + if (i is NecromancerSpellbook) + { + haveNecroBook = true; + NecromancerSpellbook nsb = (NecromancerSpellbook)i; + if (m_SpellId1 != -1 && !nsb.HasSpell(m_SpellId1)) allHaveSpells = false; + else if (m_SpellId2 != -1 && !nsb.HasSpell(m_SpellId2)) allHaveSpells = false; + else if (m_SpellId3 != -1 && !nsb.HasSpell(m_SpellId3)) allHaveSpells = false; + else if (m_SpellId4 != -1 && !nsb.HasSpell(m_SpellId4)) allHaveSpells = false; + else if (m_SpellId5 != -1 && !nsb.HasSpell(m_SpellId5)) allHaveSpells = false; + else if (m_SpellId6 != -1 && !nsb.HasSpell(m_SpellId6)) allHaveSpells = false; + if (!allHaveSpells) break; + } + } + if (!haveNecroBook) + { + pm.SendMessage("Vous devez équiper votre livre afin d'ouvrir le passage."); + return; + } + if (!allHaveSpells) break; + } + + // S'ils ont tous les sorts que l'on peut trouver, on annule le transfert + if (allHaveSpells) + { + foreach (PlayerMobile pm in necros) + if (pm != null) + pm.SendMessage("Vous possédez déjà tous ce que vous pourriez trouver ici."); + + return; + } + + // Si tout est bon on téléporte les nécros ! + e.Handled = true; + foreach(PlayerMobile pm in necros) + if (pm != null) + StartTeleport(pm); + } + } + + public override void StartTeleport(Mobile m) + { + // Faire quelque chose avant le téléport + Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x3789, 1, 40, 33, 3, 9907, 0); + m.PlaySound(0x246); + + base.StartTeleport(m); + } + + public override void DoTeleport(Mobile m) + { + base.DoTeleport(m); + + // Faire quelque chose après le téléport + } + + public override bool OnMoveOver(Mobile m) + { + return true; + } + + public override void GetProperties(ObjectPropertyList list) + { + AddNameProperties(list); + list.Add((Active ? "Active" : "Inactive")); + } + + [Constructable] + public NecroTeleporter() + { + // On set quelques trucs par défaut sur les minimats + m_Keyword = null; + m_Range = 3; + m_PlayerNecroRequired = 20; + m_PlayerSpiritRequired = 50; + m_PlayerKarmaRequired = -1000; + m_GroupNecroRequired = 50; + m_NumNecroRequired = 2; + m_SpellId1 = -1; + m_SpellId2 = -1; + m_SpellId3 = -1; + m_SpellId4 = -1; + m_SpellId5 = -1; + m_SpellId6 = -1; + Delay = TimeSpan.FromMilliseconds(500); + // Scriptiz : un son bien glauque avant de téléporter + SoundID = 0x246; + } + + public NecroTeleporter(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + + writer.Write(m_Keyword); + writer.Write(m_Range); + writer.Write(m_PlayerNecroRequired); + writer.Write(m_PlayerSpiritRequired); + writer.Write(m_PlayerKarmaRequired); + writer.Write(m_GroupNecroRequired); + writer.Write(m_NumNecroRequired); + writer.Write(m_SpellId1); + writer.Write(m_SpellId2); + writer.Write(m_SpellId3); + writer.Write(m_SpellId4); + writer.Write(m_SpellId5); + writer.Write(m_SpellId6); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + switch (version) + { + case 0: + { + m_Keyword = reader.ReadString(); + m_Range = reader.ReadInt(); + m_PlayerNecroRequired = reader.ReadDouble(); + m_PlayerSpiritRequired = reader.ReadDouble(); + m_PlayerKarmaRequired = reader.ReadInt(); + m_GroupNecroRequired = reader.ReadDouble(); + m_NumNecroRequired = reader.ReadInt(); + m_SpellId1 = reader.ReadInt(); + m_SpellId2 = reader.ReadInt(); + m_SpellId3 = reader.ReadInt(); + m_SpellId4 = reader.ReadInt(); + m_SpellId5 = reader.ReadInt(); + m_SpellId6 = reader.ReadInt(); + + break; + } + } + } + } +} diff --git a/Scripts/Vivre/NecroTemple/ScrollDeleter.cs b/Scripts/Vivre/NecroTemple/ScrollDeleter.cs new file mode 100644 index 0000000..a0f6d9c --- /dev/null +++ b/Scripts/Vivre/NecroTemple/ScrollDeleter.cs @@ -0,0 +1,77 @@ +/*************************************************************************** + * NecroExiter.cs + * ----------------------------- + * begin : August 10, 2011 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2011-08-10 + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using System.Text; +using Server.Items; +using Server.Mobiles; + +namespace Server.Misc +{ + public class ScrollDeleter + { + public static string Message = "Vous remarquez que des parchemins nécros ont disparus dans votre sac."; + + public static int DeleteNecroScrolls(Mobile m) + { + if (m == null) return 0; + + // On traite les bosses pour ne pas leur retiré leurs sorts + if (m is NecroBoss) return 0; + + Container c = m.Backpack; + if (c == null) return 0; + + int deleted = 0, count = 0; + + List otherScrolls = new List(); + + SpellScroll scroll = null; + while ((scroll = c.FindItemByType(typeof(SpellScroll)) as SpellScroll) != null) + { + count++; + if (scroll.SpellID >= 100 && scroll.SpellID <= 116) + { + scroll.Delete(); + deleted++; + } + else + { + Container bank = m.BankBox; + bank.DropItem(scroll); + otherScrolls.Add(scroll); + } + + if (count > 250) + { + Console.WriteLine("!!! Exception Scroll Deleter !!!"); + break; + } + } + + foreach (SpellScroll ss in otherScrolls) + { + if(ss != null) + m.Backpack.DropItem(ss); + } + + return deleted; + } + } +} diff --git a/Scripts/Vivre/NewBoats/BoatStatic.cs b/Scripts/Vivre/NewBoats/BoatStatic.cs new file mode 100644 index 0000000..19e6c3a --- /dev/null +++ b/Scripts/Vivre/NewBoats/BoatStatic.cs @@ -0,0 +1,30 @@ +using System; + +namespace Server.Items +{ + public class BoatStatic : Static + { + public BoatStatic(int itemID) + : base(itemID) + { + } + + public BoatStatic(Serial serial) + { + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + } +} diff --git a/Scripts/Vivre/NewBoats/OrcBoat.cs b/Scripts/Vivre/NewBoats/OrcBoat.cs new file mode 100644 index 0000000..7c47dcc --- /dev/null +++ b/Scripts/Vivre/NewBoats/OrcBoat.cs @@ -0,0 +1,212 @@ +using System; +using Server; +using Server.Items; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Multis +{ + public class OrcBoat : BaseBoat + { + public override int NorthID { get { return 0x18; } } + public override int EastID { get { return 0x19; } } + public override int SouthID { get { return 0x1A; } } + public override int WestID { get { return 0x1B; } } + + public override int HoldDistance { get { return 5; } } + public override int TillerManDistance { get { return -5; } } + + public override Point2D StarboardOffset { get { return new Point2D(2, -1); } } + public override Point2D PortOffset { get { return new Point2D(-2, -1); } } + + public override Point3D MarkOffset { get { return new Point3D(0, 0, 3); } } + + public override BaseDockedBoat DockedBoat { get { return new OrcDockedBoat(this); } } + + private Direction dirSpawned = Direction.ValueMask; + + private List m_StaticParts = new List(); + public List StaticParts + { + get { return m_StaticParts; } + } + + [Constructable] + public OrcBoat() + : base() + { + } + + [Constructable] + public OrcBoat(Direction dir) + { + Facing = dir; + } + + public OrcBoat( Serial serial ) : base( serial ) + { + } + + public override void OnDelete() + { + base.OnDelete(); + CleanStaticParts(); + } + + private void CleanStaticParts() + { + foreach (BoatStatic bs in m_StaticParts) + { + if (bs == null) continue; + bs.Delete(); + } + + m_StaticParts.Clear(); + } + + public void AddMissingComponents() + { + if (this.Map == Map.Internal) return; + if (dirSpawned == Facing) return; + + // On rend certains composants invisibles + TillerMan.Visible = false; + PPlank.Visible = false; + SPlank.Visible = false; + Hold.Visible = false; + + int multiID = 0; + + switch (Facing) + { + case Direction.North: multiID = NorthID; break; + case Direction.East: multiID = EastID; break; + case Direction.South: multiID = SouthID; break; + case Direction.West: multiID = WestID; break; + } + + if (multiID == 0) return; + dirSpawned = this.Facing; + + CleanStaticParts(); + + MultiComponentList mcl = MultiData.GetComponents(multiID); + + MultiTileEntry[] mte = mcl.List; + + for (int i = 0; i < mte.Length; i++) + { + if (mte[i].m_Flags == 0) + { + BoatStatic s = new BoatStatic((int)mte[i].m_ItemID); + s.MoveToWorld(new Point3D(this.X + mte[i].m_OffsetX, this.Y + mte[i].m_OffsetY, this.Z + mte[i].m_OffsetZ), this.Map); + s.Movable = false; + m_StaticParts.Add(s); + } + } + } + + public override void OnLocationChange(Point3D old) + { + base.OnLocationChange(old); + AddMissingComponents(); + } + + public override void OnMapChange() + { + base.OnMapChange(); + DeleteOldStatics(); + AddMissingComponents(); + } + + private void DeleteOldStatics() + { + List items = new List(); + + foreach (Item i in this.GetItemsInRange(15)) + { + items.Add(i); + } + + for (int i = 0; i < items.Count; i++) + { + if (items[i] != null && items[i] is BoatStatic) items[i].Delete(); + } + AddMissingComponents(); + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + + Timer.DelayCall(TimeSpan.FromSeconds(10), DeleteOldStatics); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); + } + } + + public class OrcBoatDeed : BaseBoatDeed + { + public override int LabelNumber { get { return 1116738; } } // large ship deed + public override BaseBoat Boat { get { return new OrcBoat(); } } + + [Constructable] + public OrcBoatDeed() + : base(0x18, new Point3D(0, -1, 0)) + { + } + + public OrcBoatDeed(Serial serial) + : base(serial) + { + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + } + + public class OrcDockedBoat : BaseDockedBoat + { + public override BaseBoat Boat { get { return new OrcBoat(); } } + + public OrcDockedBoat(BaseBoat boat) + : base(0x18, new Point3D(0, -1, 0), boat) + { + } + + public OrcDockedBoat(Serial serial) + : base(serial) + { + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Regions/ArenaRegion.cs b/Scripts/Vivre/Regions/ArenaRegion.cs new file mode 100644 index 0000000..22b8ddf --- /dev/null +++ b/Scripts/Vivre/Regions/ArenaRegion.cs @@ -0,0 +1,69 @@ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Spells; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Third; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; +using Server.Spells.Ninjitsu; +using Server.ServerSeasons; + +namespace Server.Regions +{ + public class ArenaRegion : BaseRegion + { + public ArenaRegion(XmlElement xml, Map map, Region parent) + : base(xml, map, parent) + { + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override void OnEnter(Mobile m) + { + if (m is PlayerMobile && ((PlayerMobile)m).Young) + ((PlayerMobile)m).Young = false; + + base.OnEnter(m); + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + // Si ce sont des joueurs + PlayerMobile pm = m as PlayerMobile; + if (pm != null && pm.AccessLevel == AccessLevel.Player) + { + // Ok si duelistes + if (pm.IsInChallenge) return base.OnBeginSpellCast(m, s); + + // Interdit si spectateurs + pm.SendMessage("Les spectateurs ne sont pas autorisés à faire cela !"); + return false; + } + return base.OnBeginSpellCast(m, s); + } + + public override bool OnSkillUse(Mobile from, int Skill) + { + // Si ce sont des joueurs + PlayerMobile pm = from as PlayerMobile; + if (pm != null && pm.AccessLevel == AccessLevel.Player) + { + // Ok si duelistes + if (pm.IsInChallenge) return base.OnSkillUse(from, Skill); + + // Interdit si spectateurs + pm.SendMessage("Les spectateurs ne sont pas autorisés à faire cela !"); + return false; + } + return base.OnSkillUse(from, Skill); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Regions/NinjitsuRegion.cs b/Scripts/Vivre/Regions/NinjitsuRegion.cs new file mode 100644 index 0000000..2fcdab8 --- /dev/null +++ b/Scripts/Vivre/Regions/NinjitsuRegion.cs @@ -0,0 +1,58 @@ +using System.Xml; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; +using Server.ServerSeasons; + +namespace Server.Regions +{ + public class NinjitsuRegion : BaseRegion + { + private Point3D m_EntranceLocation; + private Map m_EntranceMap; + + public Point3D EntranceLocation { get { return m_EntranceLocation; } set { m_EntranceLocation = value; } } + public Map EntranceMap { get { return m_EntranceMap; } set { m_EntranceMap = value; } } + + public NinjitsuRegion(XmlElement xml, Map map, Region parent) + : base(xml, map, parent) + { + XmlElement entrEl = xml["entrance"]; + + Map entrMap = map; + ReadMap(entrEl, "map", ref entrMap, false); + + if (ReadPoint3D(entrEl, entrMap, ref m_EntranceLocation, false)) + m_EntranceMap = entrMap; + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + global = LightCycle.NightLevel; + + if (m == null || m.AccessLevel <= AccessLevel.Counselor) + personal = 0; + } + + public override bool CanUseStuckMenu(Mobile m) + { + return false; + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if ((s is GateTravelSpell || s is RecallSpell || s is MarkSpell || s is SacredJourneySpell) && m.AccessLevel == AccessLevel.Player) + { + m.SendMessage("You cannot cast that spell here."); + return false; + } + return base.OnBeginSpellCast(m, s); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Regions/NoRecallRegion.cs b/Scripts/Vivre/Regions/NoRecallRegion.cs new file mode 100644 index 0000000..8181e8b --- /dev/null +++ b/Scripts/Vivre/Regions/NoRecallRegion.cs @@ -0,0 +1,54 @@ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Spells; +using Server.Items; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Third; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; +using Server.Spells.Ninjitsu; +using Server.ServerSeasons; +using Server.Misc; + +namespace Server.Regions +{ + public class NoRecallRegion : BaseRegion + { + private Point3D m_EntranceLocation; + private Map m_EntranceMap; + + public Point3D EntranceLocation { get { return m_EntranceLocation; } set { m_EntranceLocation = value; } } + public Map EntranceMap { get { return m_EntranceMap; } set { m_EntranceMap = value; } } + + public NoRecallRegion(XmlElement xml, Map map, Region parent) + : base(xml, map, parent) + { + XmlElement entrEl = xml["entrance"]; + + Map entrMap = map; + ReadMap(entrEl, "map", ref entrMap, false); + + if (ReadPoint3D(entrEl, entrMap, ref m_EntranceLocation, false)) + m_EntranceMap = entrMap; + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if ((s is GateTravelSpell || s is RecallSpell || s is MarkSpell || s is SacredJourneySpell) && m.AccessLevel == AccessLevel.Player) + { + m.SendMessage("You cannot cast that spell here."); + return false; + } + return base.OnBeginSpellCast(m, s); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Regions/StuckDungeonRegion.cs b/Scripts/Vivre/Regions/StuckDungeonRegion.cs new file mode 100644 index 0000000..9936afb --- /dev/null +++ b/Scripts/Vivre/Regions/StuckDungeonRegion.cs @@ -0,0 +1,62 @@ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Spells; +using Server.Items; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Third; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; +using Server.Spells.Ninjitsu; +using Server.ServerSeasons; +using Server.Misc; + +namespace Server.Regions +{ + public class StuckDungeonRegion : BaseRegion + { + private Point3D m_EntranceLocation; + private Map m_EntranceMap; + + public Point3D EntranceLocation { get { return m_EntranceLocation; } set { m_EntranceLocation = value; } } + public Map EntranceMap { get { return m_EntranceMap; } set { m_EntranceMap = value; } } + + public StuckDungeonRegion(XmlElement xml, Map map, Region parent) + : base(xml, map, parent) + { + XmlElement entrEl = xml["entrance"]; + + Map entrMap = map; + ReadMap(entrEl, "map", ref entrMap, false); + + if (ReadPoint3D(entrEl, entrMap, ref m_EntranceLocation, false)) + m_EntranceMap = entrMap; + } + + public override bool AllowHousing(Mobile from, Point3D p) + { + return false; + } + + public override void AlterLightLevel(Mobile m, ref int global, ref int personal) + { + global = LightCycle.DungeonLevel; + + if (m == null || m.AccessLevel <= AccessLevel.Counselor) + personal = 0; + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if ((s is GateTravelSpell || s is RecallSpell || s is MarkSpell || s is SacredJourneySpell || s is TeleportSpell || s is Shadowjump) && m.AccessLevel == AccessLevel.Player) + { + m.SendMessage("You cannot cast that spell here."); + return false; + } + return base.OnBeginSpellCast(m, s); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/Regions/TownJail.cs b/Scripts/Vivre/Regions/TownJail.cs new file mode 100644 index 0000000..5bd98d6 --- /dev/null +++ b/Scripts/Vivre/Regions/TownJail.cs @@ -0,0 +1,59 @@ +using System; +using System.Xml; +using Server; +using Server.Mobiles; +using Server.Gumps; +using Server.Spells; +using Server.Spells.Seventh; +using Server.Spells.Fourth; +using Server.Spells.Third; +using Server.Spells.Sixth; +using Server.Spells.Chivalry; +using Server.Spells.Ninjitsu; +using Server.ServerSeasons; + +namespace Server.Regions +{ + public class TownJail : Jail + { + public TownJail(XmlElement xml, Map map, Region parent) + : base(xml, map, parent) + { + } + + public override bool AllowBeneficial(Mobile from, Mobile target) + { + return true; + } + + public override bool AllowHarmful(Mobile from, Mobile target) + { + return true; + } + + public override bool OnBeginSpellCast(Mobile m, ISpell s) + { + if ((s is GateTravelSpell || s is RecallSpell || s is MarkSpell || s is SacredJourneySpell || s is TeleportSpell || s is Shadowjump) && m.AccessLevel == AccessLevel.Player) + { + m.SendMessage("You cannot cast that spell here."); + return false; + } + return true; + } + + public override bool CanUseStuckMenu(Mobile m) + { + return false; + } + + public override bool OnSkillUse(Mobile from, int Skill) + { + return true; + } + + public override bool OnCombatantChange(Mobile from, Mobile Old, Mobile New) + { + return true; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/NecroRobe.cs b/Scripts/Vivre/VivreNecromancy/NecroRobe.cs new file mode 100644 index 0000000..ba74367 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/NecroRobe.cs @@ -0,0 +1,37 @@ +using Server; + +namespace Server.Items +{ + class NecroRobe : Robe + { + [Constructable] + public NecroRobe() + : this(1109) + { + } + + public NecroRobe(int hue) + : base(hue) + { + } + + public NecroRobe(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Vivre/VivreNecromancy/NecroSpellBook.cs b/Scripts/Vivre/VivreNecromancy/NecroSpellBook.cs new file mode 100644 index 0000000..b9c380b --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/NecroSpellBook.cs @@ -0,0 +1,50 @@ +using System; +using Server.Network; +using Server.Spells; + +namespace Server.Items +{ + public class NecroSpellbook : Spellbook + { + public override SpellbookType SpellbookType { get { return SpellbookType.Necromancer; } } // to change + public override int BookOffset { get { return 700; } } + public override int BookCount { get { return 6; } } + + [Constructable] + public NecroSpellbook() + : this((ulong)0) + { + } + + [Constructable] + public NecroSpellbook(ulong content) + : base(content, 0x2253) + { + Layer = (Core.ML ? Layer.OneHanded : Layer.Invalid); + // Scriptiz : on ne peut pas looter les livres de magie + Lootable = false; + } + + public NecroSpellbook(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)1); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + + if (version == 0 && Core.ML) + Layer = Layer.OneHanded; + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/Blackmoor.cs b/Scripts/Vivre/VivreNecromancy/Reagents/Blackmoor.cs new file mode 100644 index 0000000..be071e5 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/Blackmoor.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Blackmoor : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} blackmoor", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Blackmoor() + : this(1) + { + } + + [Constructable] + public Blackmoor(int amount) + : base(0xF79, amount) + { + } + + public Blackmoor(Serial serial) + : base(serial) + { + } + + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/BloodVial.cs b/Scripts/Vivre/VivreNecromancy/Reagents/BloodVial.cs new file mode 100644 index 0000000..e330e8e --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/BloodVial.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BloodVial : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} vial of blood", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public BloodVial() + : this(1) + { + } + + [Constructable] + public BloodVial(int amount) + : base(0xF7D, amount) + { + } + + public BloodVial(Serial serial) + : base(serial) + { + } + + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/Bloodspawn.cs b/Scripts/Vivre/VivreNecromancy/Reagents/Bloodspawn.cs new file mode 100644 index 0000000..797d392 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/Bloodspawn.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Bloodspawn : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} bloodspawn", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Bloodspawn() + : this(1) + { + } + + [Constructable] + public Bloodspawn(int amount) + : base(0xF7C, amount) + { + } + + public Bloodspawn(Serial serial) + : base(serial) + { + } + + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/Brimstone.cs b/Scripts/Vivre/VivreNecromancy/Reagents/Brimstone.cs new file mode 100644 index 0000000..26bcc55 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/Brimstone.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Brimstone : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} brimstone", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Brimstone() + : this(1) + { + } + + [Constructable] + public Brimstone(int amount) + : base(0xF7F, amount) + { + } + + public Brimstone(Serial serial) + : base(serial) + { + } + + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/DragonBlood.cs b/Scripts/Vivre/VivreNecromancy/Reagents/DragonBlood.cs new file mode 100644 index 0000000..6a91923 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/DragonBlood.cs @@ -0,0 +1,49 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class DragonBlood : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} dragon's blood", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public DragonBlood() + : this(1) + { + } + + [Constructable] + public DragonBlood(int amount) + : base(0x4077, amount) + { + } + + public DragonBlood(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/EyeOfNewt.cs b/Scripts/Vivre/VivreNecromancy/Reagents/EyeOfNewt.cs new file mode 100644 index 0000000..82e30e5 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/EyeOfNewt.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class EyeOfNewt : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} eye of newt", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public EyeOfNewt() + : this(1) + { + } + + [Constructable] + public EyeOfNewt(int amount) + : base(0x0F87, amount) + { + } + + public EyeOfNewt(Serial serial) + : base(serial) + { + } + + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Reagents/Obsidian.cs b/Scripts/Vivre/VivreNecromancy/Reagents/Obsidian.cs new file mode 100644 index 0000000..ad649eb --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Reagents/Obsidian.cs @@ -0,0 +1,53 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class Obsidian : BaseReagent, ICommodity + { + string Description + { + get + { + return String.Format("{0} obsidian", Amount); + } + } + + int ICommodity.DescriptionNumber { get { return LabelNumber; } } + bool ICommodity.IsDeedable { get { return true; } } + + [Constructable] + public Obsidian() + : this(1) + { + } + + [Constructable] + public Obsidian(int amount) + : base(0xF89, amount) + { + } + + public Obsidian(Serial serial) + : base(serial) + { + } + + + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/AbyssFireScroll.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/AbyssFireScroll.cs new file mode 100644 index 0000000..925b694 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/AbyssFireScroll.cs @@ -0,0 +1,52 @@ +/*************************************************************************** + * AbyssFireScroll.cs + * --------------------- + * begin : August 26, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-09-24 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AbyssFireScroll : SpellScroll + { + [Constructable] + public AbyssFireScroll() + : this(1) + { + } + + [Constructable] + public AbyssFireScroll(int amount) + : base(704, 0x2260, amount) + { + Name = "Parchemin feu des abysses"; + } + + public AbyssFireScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/AbyssLightScroll.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/AbyssLightScroll.cs new file mode 100644 index 0000000..bd5bf4f --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/AbyssLightScroll.cs @@ -0,0 +1,52 @@ +/*************************************************************************** + * AnimateDeadScroll.cs + * --------------------- + * begin : August 26, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-09-19 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AbyssLightScroll : SpellScroll + { + [Constructable] + public AbyssLightScroll() + : this(1) + { + } + + [Constructable] + public AbyssLightScroll(int amount) + : base(703, 0x2260, amount) + { + Name = "Parchemin lumière des abysses"; + } + + public AbyssLightScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/AnimateCorpseScroll.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/AnimateCorpseScroll.cs new file mode 100644 index 0000000..06019b3 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/AnimateCorpseScroll.cs @@ -0,0 +1,52 @@ +/*************************************************************************** + * AnimateDeadScroll.cs + * --------------------- + * begin : August 26, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-08-29 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class AnimateCorpseScroll : SpellScroll + { + [Constructable] + public AnimateCorpseScroll() + : this(1) + { + } + + [Constructable] + public AnimateCorpseScroll(int amount) + : base(701, 0x2260, amount) + { + Name = "Parchemin libérer la mort"; + } + + public AnimateCorpseScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/BoneArmorScroll.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/BoneArmorScroll.cs new file mode 100644 index 0000000..26ca19d --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/BoneArmorScroll.cs @@ -0,0 +1,52 @@ +/*************************************************************************** + * AnimateDeadScroll.cs + * --------------------- + * begin : August 29, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-07-29 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BoneArmorScroll : SpellScroll + { + [Constructable] + public BoneArmorScroll() + : this(1) + { + Name = "Parchemin d'armure d'os"; + } + + [Constructable] + public BoneArmorScroll(int amount) + : base(702, 0x2260, amount) + { + } + + public BoneArmorScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/MinorLifeLeech.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/MinorLifeLeech.cs new file mode 100644 index 0000000..6bc950c --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/MinorLifeLeech.cs @@ -0,0 +1,99 @@ +/*************************************************************************** + * MinorLifeLeech.cs + * --------------- + * begin : August 29 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-09-24 + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public class MinorLifeLeech : VivreNecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Drain de vie mineur", "An Mani Vas Corp", + 269, + 9031, + false, + Reagent.DragonBlood, + Reagent.DaemonBone + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.5); } } + + public override double RequiredSkill { get { return 30.0; } } + public override int RequiredMana { get { return 40; } } + + public MinorLifeLeech(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + Caster.Mana -= RequiredMana; + Caster.Target = new InternalTarget(this); + } + + public void Target(object obj) + { + if (CheckSequence() && CheckCast()) + { + Mobile target = null; + if (obj is Mobile) target = (Mobile)obj; + + if (target == null) + { + Caster.SendMessage("Cette cible ne peut pas subir cet effet."); + return; + } + + SpellHelper.Turn(Caster, target); + target.MovingParticles(Caster, 0x36D4, 7, 0, false, false, 33, 0, 9502, 1, 0, 0x100); + Caster.PlaySound(Core.AOS ? 0x15E : 0x44B); + + int leech = (int)(6 * (Caster.Skills.EvalInt.Base / 25)); + int lifeToHeal = target.Hits; + target.Damage(leech, Caster); + lifeToHeal -= target.Hits; + + if (Caster.Hits == Caster.HitsMax) + { + Caster.Damage(leech * 2); + Caster.SendMessage("L'afflux de sang vous rend malade."); + } + else if(lifeToHeal > 0) Caster.Heal(lifeToHeal); + } + FinishSequence(); + } + + private class InternalTarget : Target + { + private MinorLifeLeech m_Owner; + + public InternalTarget(MinorLifeLeech owner) + : base(Core.ML ? 10 : 12, true, TargetFlags.None) + { + m_Owner = owner; + } + + protected override void OnTarget(Mobile from, object o) + { + m_Owner.Target(o); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/MinorLifeLeechScroll.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/MinorLifeLeechScroll.cs new file mode 100644 index 0000000..05e17c5 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/MinorLifeLeechScroll.cs @@ -0,0 +1,50 @@ +/*************************************************************************** + * MinorLifeLeechScroll.cs + * --------------------- + * begin : August 26, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-09-24 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class MinorLifeLeechScroll : SpellScroll + { + [Constructable] + public MinorLifeLeechScroll() + : this(1) + { + } + + [Constructable] + public MinorLifeLeechScroll(int amount) + : base(705, 0x2260, amount) + { + Name = "Parchemin drain de vie mineur"; + } + + public MinorLifeLeechScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Scrolls/SummonUndeadScroll.cs b/Scripts/Vivre/VivreNecromancy/Scrolls/SummonUndeadScroll.cs new file mode 100644 index 0000000..87a2f14 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Scrolls/SummonUndeadScroll.cs @@ -0,0 +1,52 @@ +/*************************************************************************** + * SummonUndeadScroll.cs + * --------------------- + * begin : July 25, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-07-25 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class SummonUndeadScroll : SpellScroll + { + [Constructable] + public SummonUndeadScroll() + : this(1) + { + } + + [Constructable] + public SummonUndeadScroll(int amount) + : base(700, 0x2260, amount) + { + Name = "Parchemin d'invocation des mort"; + } + + public SummonUndeadScroll(Serial serial) + : base(serial) + { + } + + public override void Serialize(GenericWriter writer) + { + base.Serialize(writer); + + writer.Write((int)0); // version + } + + public override void Deserialize(GenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + } + + + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Spells/AbyssFire.cs b/Scripts/Vivre/VivreNecromancy/Spells/AbyssFire.cs new file mode 100644 index 0000000..15d8771 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Spells/AbyssFire.cs @@ -0,0 +1,89 @@ +/*************************************************************************** + * AbyssFire.cs + * --------------- + * begin : August 29 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-09-24 + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public class AbyssFire : VivreNecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Feu des abysses", "Vas Flam Por", + 269, + 9031, + false, + Reagent.Bloodspawn, + Reagent.Brimstone + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(1.5); } } + + public override double RequiredSkill { get { return 30.0; } } + public override int RequiredMana { get { return 9; } } + + public AbyssFire(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + Caster.Mana -= RequiredMana; + Caster.Target = new InternalTarget(this); + } + + public void Target(object obj) + { + if (CheckSequence()) + { + Mobile target = null; + if (obj is Mobile) target = (Mobile)obj; + + if (target == null) + { + Caster.SendMessage("Cette cible ne peut pas subir cet effet."); + return; + } + + SpellHelper.Turn(Caster, target); + int damage = (int)(8 * (Caster.Skills.EvalInt.Base / 25)); + target.Damage(damage, Caster); + Caster.MovingParticles(target, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160); + Caster.PlaySound(Core.AOS ? 0x15E : 0x44B); + } + FinishSequence(); + } + + private class InternalTarget : Target + { + private AbyssFire m_Owner; + + public InternalTarget(AbyssFire owner) + : base(Core.ML ? 10 : 12, true, TargetFlags.None) + { + m_Owner = owner; + } + + protected override void OnTarget(Mobile from, object o) + { + m_Owner.Target(o); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Spells/AbyssLight.cs b/Scripts/Vivre/VivreNecromancy/Spells/AbyssLight.cs new file mode 100644 index 0000000..54aafa6 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Spells/AbyssLight.cs @@ -0,0 +1,89 @@ +/*************************************************************************** + * AbyssLight.cs + * --------------- + * begin : August 29 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-09-19 + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public class AbyssLight : VivreNecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Lumière des abysses", "Kal Lor", + 269, + 9031, + false, + Reagent.BatWing, + Reagent.EyeOfNewt + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(0.5); } } + + public override double RequiredSkill { get { return 10.0; } } + public override int RequiredMana { get { return 4; } } + + public AbyssLight(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + if (CheckSequence()) + { + LightSource light = new LightSource(); + light.Light = LightType.Circle300; + light.Layer = Layer.Unused_xF; + light.Movable = false; + + if (Caster.FindItemOnLayer(Layer.Unused_xF) != null) + Caster.FindItemOnLayer(Layer.Unused_xF).Delete(); + + Caster.EquipItem(light); + + new InternalTimer(Caster); + + Caster.Karma -= 500; + Caster.Mana -= RequiredMana; + Effects.PlaySound(Caster.Location, Caster.Map, 0x54); + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private Mobile Caster; + + public InternalTimer(Mobile caster) + : base(TimeSpan.FromMinutes(5)) + { + Caster = caster; + + Delay = TimeSpan.FromSeconds((Caster.Skills.Necromancy.Base + Caster.Skills.EvalInt.Base) * 3); + this.Start(); + } + + protected override void OnTick() + { + Item light = Caster.FindItemOnLayer(Layer.Unused_xF); + if (light != null && light is LightSource) + { + light.Delete(); + Effects.PlaySound(Caster.Location, Caster.Map, 0x4BB); + } + this.Stop(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Spells/AnimateCorpse.cs b/Scripts/Vivre/VivreNecromancy/Spells/AnimateCorpse.cs new file mode 100644 index 0000000..1f1577f --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Spells/AnimateCorpse.cs @@ -0,0 +1,124 @@ +/*************************************************************************** + * AnimateDead.cs + * --------------- + * begin : August 26, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-08-30 + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public class AnimateCorpse : VivreNecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Libérer la mort", "Ex Corp", + 269, + 9031, + false, + Reagent.BloodVial, + Reagent.ExecutionersCap + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(2.5); } } // TODO : Cast doublé? + + public override double RequiredSkill { get { return 50.0; } } + public override int RequiredMana { get { return 14; } } // TODO : mana doublée? + + public AnimateCorpse(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + Caster.Mana -= RequiredMana; + Caster.Target = new InternalTarget(this); + Caster.SendMessage("Quel cadavre souhaitez vous animer?"); + } + + public void Target(object obj) + { + if (CheckSequence()) + { + Corpse c = obj as Corpse; + + if (c == null) + { + Caster.SendLocalizedMessage(1061084); // You cannot animate that. + } + else + { + SpellHelper.Turn(Caster, c); + Type type = null; + + if (c.Owner != null) + type = c.Owner.GetType(); + + if (c.ItemID != 0x2006 || c.Channeled || type == typeof(PlayerMobile) || type == null || (c.Owner != null && c.Owner.Fame < 100) || ((c.Owner != null) && (c.Owner is BaseCreature) && (((BaseCreature)c.Owner).Summoned || ((BaseCreature)c.Owner).IsBonded))) + { + Caster.SendLocalizedMessage(1061085); // There's not enough life force there to animate. + } + else + { + object[] paramObject = new object[] { }; + object summoned = Activator.CreateInstance(type, paramObject); + + if (summoned is BaseCreature) + { + BaseCreature bc = (BaseCreature)summoned; + + bc.Tamable = false; + + if (bc is BaseMount) + bc.ControlSlots = 1; + else + bc.ControlSlots = 0; + + Effects.PlaySound(c.Location, c.Map, 0x1FB); + //Effects.PlaySound(loc, map, bc.GetAngerSound()); + Effects.SendLocationParticles(EffectItem.Create(c.Location, c.Map, EffectItem.DefaultDuration), 0x3789, 1, 40, 0x3F, 3, 9907, 0); + + // On s'occupe du corps + c.Items.Clear(); + c.TurnToBones(); + + TimeSpan delay = TimeSpan.FromMinutes((Caster.Skills.Necromancy.Base + Caster.Skills.EvalInt.Base) * 3); + BaseCreature.Summon(bc, false, Caster, c.Location, 0x28, delay); + } + } + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private AnimateCorpse m_Owner; + + public InternalTarget(AnimateCorpse owner) + : base(Core.ML ? 10 : 12, true, TargetFlags.None) + { + m_Owner = owner; + } + + protected override void OnTarget(Mobile from, object o) + { + m_Owner.Target(o); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Spells/BoneArmor.cs b/Scripts/Vivre/VivreNecromancy/Spells/BoneArmor.cs new file mode 100644 index 0000000..897377c --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Spells/BoneArmor.cs @@ -0,0 +1,138 @@ +/*************************************************************************** + * BoneArmor.cs + * --------------- + * begin : August 29 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-08-29 + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public class BoneArmor : VivreNecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Armure d'os", "In Sanct Ylem Corp", + 269, + 9031, + false, + Reagent.Bone, + Reagent.FertileDirt + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(0.0); } } + + public override double RequiredSkill { get { return 40.0; } } + public override int RequiredMana { get { return 30; } } + + public BoneArmor(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + if (CheckSequence()) + { + List bonePieces = new List(); + List equipedPieces = new List(); + + bonePieces.Add(new BoneArms()); + bonePieces.Add(new BoneChest()); + bonePieces.Add(new BoneGloves()); + bonePieces.Add(new BoneHelm()); + bonePieces.Add(new BoneLegs()); + + foreach (Item i in bonePieces) + { + // On retire les pièces d'armures déjà équipées et on les met dans le sac + Item equiped = Caster.FindItemOnLayer(i.Layer); + + if (equiped != null && equiped.Movable) + { + equipedPieces.Add(equiped); + Caster.RemoveItem(equiped); + Caster.AddToBackpack(equiped); + } + + if (equiped != null && !equiped.Movable) + { + Caster.SendMessage("Vous portez déjà des objets invoqués."); + return; + } + + // On équipe la pièce d'armure + BaseArmor ba = null; + if(i is BaseArmor) ba = (BaseArmor)i; + + if (ba != null) + { + ba.Movable = false; + ba.Hue = 1109; + ba.ArmorAttributes.LowerStatReq = 100; + Caster.EquipItem(ba); + } + } + + new InternalTimer(Caster, bonePieces, equipedPieces); + + Caster.Karma -= 500; + Caster.Mana -= RequiredMana; + Effects.PlaySound(Caster.Location, Caster.Map, 0x1FB); + Effects.SendLocationParticles(EffectItem.Create(Caster.Location, Caster.Map, EffectItem.DefaultDuration), 0x3789, 1, 40, 0x3F, 3, 9907, 0); + } + + FinishSequence(); + } + + private class InternalTimer : Timer + { + private Mobile Caster; + private List BonePieces; + private List EquipedPieces; + + public InternalTimer(Mobile caster, List bonePieces, List equipedPieces) + : base(TimeSpan.FromMinutes(5)) + { + Caster = caster; + BonePieces = bonePieces; + EquipedPieces = equipedPieces; + + Delay = TimeSpan.FromSeconds((Caster.Skills.Necromancy.Base + Caster.Skills.EvalInt.Base) * 3); + this.Start(); + } + + protected override void OnTick() + { + foreach (Item i in BonePieces) + { + if (i == null || i.Deleted) continue; + + i.Delete(); + } + + foreach (Item i in EquipedPieces) + { + if (i == null || i.Deleted) continue; + + if (i.IsChildOf(Caster.Backpack)) + { + Caster.EquipItem(i); + } + else + { + Caster.SendMessage("Un objet ne se trouve plus dans votre sac et n'a donc pas été rééquipé."); + } + } + this.Stop(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Spells/SummonUndead.cs b/Scripts/Vivre/VivreNecromancy/Spells/SummonUndead.cs new file mode 100644 index 0000000..57a5449 --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Spells/SummonUndead.cs @@ -0,0 +1,122 @@ +/*************************************************************************** + * SummonUndead.cs + * --------------- + * begin : July 25, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-08-30 + * + ***************************************************************************/ +using System; +using System.Collections.Generic; +using Server.Network; +using Server.Mobiles; +using Server.Targeting; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public class SummonUndead : VivreNecromancerSpell + { + private static SpellInfo m_Info = new SpellInfo( + "Invocation des morts", "Kal An Mani", + 269, + 9031, + false, + Reagent.GraveDust, // orbisdian et blackmoor + Reagent.DaemonBlood + ); + + public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds(6.0); } } + + public override double RequiredSkill { get { return 40.0; } } + public override int RequiredMana { get { return 30; } } + + public SummonUndead(Mobile caster, Item scroll) + : base(caster, scroll, m_Info) + { + } + + public override void OnCast() + { + Caster.Mana -= RequiredMana; + Caster.Target = new InternalTarget(this); + Caster.SendMessage("Où voulez-vous invoquer un mort?"); // Animate what corpse? + } + + public void Target(object obj) + { + if (CheckSequence()) + { + // Scriptiz : Amélioration en ciblant un Mobile, le mort l'attaque + Point3D location; + + if (obj is LandTarget) + location = ((LandTarget)obj).Location; + else if(obj is Mobile) + location = ((Mobile)obj).Location; + else + { + Caster.SendMessage("Veuillez cibler une zone valide. (" + obj.GetType().ToString() + ")"); + return; + } + + SpellHelper.Turn(Caster, location); + + double getLich = Caster.Skills.Necromancy.Value / 10; + double getSkeleton = Caster.Skills.Necromancy.Value / 5; + + int chance = Utility.Random(100); + + BaseCreature undead; + + if (chance <= getLich) + undead = new Lich(); + else if (chance <= getSkeleton) + undead = new Skeleton(); + else + undead = new Zombie(); + + undead.ControlSlots = 1; + undead.Fame = 0; + undead.Karma = -1500; + + Caster.Karma -= 500; + Effects.PlaySound(location, Caster.Map, 0x1FB); + Effects.SendLocationParticles(EffectItem.Create(location, Caster.Map, EffectItem.DefaultDuration), 0x3789, 1, 40, 0x3F, 3, 9907, 0); + + TimeSpan delay = TimeSpan.FromMinutes((Caster.Skills.Necromancy.Base + Caster.Skills.EvalInt.Base) * 3); + BaseCreature.Summon(undead, false, Caster, location, 0x28, delay); + + // Si la cible est une mobile on l'attaque + if (obj is Mobile) + { + undead.Attack((Mobile)obj); + } + } + + FinishSequence(); + } + + private class InternalTarget : Target + { + private SummonUndead m_Owner; + + public InternalTarget(SummonUndead owner) + : base(Core.ML ? 10 : 12, true, TargetFlags.None) + { + m_Owner = owner; + } + + protected override void OnTarget(Mobile from, object o) + { + m_Owner.Target(o); + } + + protected override void OnTargetFinish(Mobile from) + { + m_Owner.FinishSequence(); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Vivre/VivreNecromancy/Spells/VivreNecromancerSpell.cs b/Scripts/Vivre/VivreNecromancy/Spells/VivreNecromancerSpell.cs new file mode 100644 index 0000000..14f80fc --- /dev/null +++ b/Scripts/Vivre/VivreNecromancy/Spells/VivreNecromancerSpell.cs @@ -0,0 +1,88 @@ +/*************************************************************************** + * VivreNecromancerSpell.cs + * ------------------------ + * begin : July 25, 2010 + * copyright : (C) Scriptiz + * email : maeliguul@hotmail.com + * version : 2010-07-25 + * + ***************************************************************************/ +using System; +using Server; +using Server.Items; + +namespace Server.Spells.VivreNecromancy +{ + public abstract class VivreNecromancerSpell : Spell + { + public abstract double RequiredSkill { get; } + public abstract int RequiredMana { get; } + + public override SkillName CastSkill { get { return SkillName.Necromancy; } } + public override SkillName DamageSkill { get { return SkillName.EvalInt; } } + + //public override int CastDelayBase{ get{ return base.CastDelayBase; } } // Reference, 3 + + public override bool ClearHandsOnCast { get { return false; } } + + public override double CastDelayFastScalar { get { return (Core.SE ? base.CastDelayFastScalar : 0); } } // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery + + public VivreNecromancerSpell(Mobile caster, Item scroll, SpellInfo info) + : base(caster, scroll, info) + { + } + + public override int ComputeKarmaAward() + { + //TODO: Verify this formula being that Necro spells don't HAVE a circle. + + //return -(70 + (10 * (int)Circle)); + + return -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick))); + } + + public override void GetCastSkills(out double min, out double max) + { + min = RequiredSkill; + max = Scroll != null ? min : RequiredSkill + 25.0; + } + + public override bool ConsumeReagents() + { + if (base.ConsumeReagents()) + return true; + + if (ArcaneGem.ConsumeCharges(Caster, 1)) + return true; + + return false; + } + + public override int GetMana() + { + return RequiredMana; + } + + public bool CheckCast(Mobile m) + { + if (m == null) return false; + + // Scriptiz : On vérifie que le joueur porte bien sa robe de nécromant + Item necroRobe = m.FindItemOnLayer(Layer.OuterTorso); + + if (necroRobe == null || !(necroRobe is NecroRobe)) + { + Caster.SendMessage("Vous devez porter des habits particuliers pour pouvoir incanter ce sort."); + return false; + } + + return base.CheckCast(); + } + + public override bool CheckCast() + { + if(CheckCast(Caster)) return base.CheckCast(); + return false; + } + } +} \ No newline at end of file diff --git a/Scripts/app.config b/Scripts/app.config new file mode 100644 index 0000000..e365603 --- /dev/null +++ b/Scripts/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Server.exe b/Server.exe new file mode 100644 index 0000000..9bee9cf Binary files /dev/null and b/Server.exe differ diff --git a/Server.exe.config b/Server.exe.config new file mode 100644 index 0000000..e365603 --- /dev/null +++ b/Server.exe.config @@ -0,0 +1,3 @@ + + + diff --git a/Server.vshost.exe b/Server.vshost.exe new file mode 100644 index 0000000..f443805 Binary files /dev/null and b/Server.vshost.exe differ diff --git a/Server.vshost.exe.config b/Server.vshost.exe.config new file mode 100644 index 0000000..e365603 --- /dev/null +++ b/Server.vshost.exe.config @@ -0,0 +1,3 @@ + + + diff --git a/Server.vshost.exe.manifest b/Server.vshost.exe.manifest new file mode 100644 index 0000000..061c9ca --- /dev/null +++ b/Server.vshost.exe.manifest @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Server/AggressorInfo.cs b/Server/AggressorInfo.cs new file mode 100644 index 0000000..bda6a7a --- /dev/null +++ b/Server/AggressorInfo.cs @@ -0,0 +1,212 @@ +/*************************************************************************** + * AggressorInfo.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: AggressorInfo.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; + +namespace Server +{ + public class AggressorInfo + { + private Mobile m_Attacker, m_Defender; + private DateTime m_LastCombatTime; + private bool m_CanReportMurder; + private bool m_Reported; + private bool m_CriminalAggression; + + private bool m_Queued; + + private static Queue m_Pool = new Queue(); + + public static AggressorInfo Create( Mobile attacker, Mobile defender, bool criminal ) + { + AggressorInfo info; + + if ( m_Pool.Count > 0 ) + { + info = m_Pool.Dequeue(); + + info.m_Attacker = attacker; + info.m_Defender = defender; + + info.m_CanReportMurder = criminal; + info.m_CriminalAggression = criminal; + + info.m_Queued = false; + + info.Refresh(); + } + else + { + info = new AggressorInfo( attacker, defender, criminal ); + } + + return info; + } + + public void Free() + { + if ( m_Queued ) + return; + + m_Queued = true; + m_Pool.Enqueue( this ); + } + + private AggressorInfo( Mobile attacker, Mobile defender, bool criminal ) + { + m_Attacker = attacker; + m_Defender = defender; + + m_CanReportMurder = criminal; + m_CriminalAggression = criminal; + + Refresh(); + } + + private static TimeSpan m_ExpireDelay = TimeSpan.FromMinutes( 2.0 ); + + public static TimeSpan ExpireDelay + { + get{ return m_ExpireDelay; } + set{ m_ExpireDelay = value; } + } + + public static void DumpAccess() + { + using ( StreamWriter op = new StreamWriter( "warnings.log", true ) ) + { + op.WriteLine( "Warning: Access to queued AggressorInfo:" ); + op.WriteLine( new System.Diagnostics.StackTrace() ); + op.WriteLine(); + op.WriteLine(); + } + } + + public bool Expired + { + get + { + if ( m_Queued ) + DumpAccess(); + + return ( m_Attacker.Deleted || m_Defender.Deleted || DateTime.Now >= (m_LastCombatTime + m_ExpireDelay) ); + } + } + + public bool CriminalAggression + { + get + { + if ( m_Queued ) + DumpAccess(); + + return m_CriminalAggression; + } + set + { + if ( m_Queued ) + DumpAccess(); + + m_CriminalAggression = value; + } + } + + public Mobile Attacker + { + get + { + if ( m_Queued ) + DumpAccess(); + + return m_Attacker; + } + } + + public Mobile Defender + { + get + { + if ( m_Queued ) + DumpAccess(); + + return m_Defender; + } + } + + public DateTime LastCombatTime + { + get + { + if ( m_Queued ) + DumpAccess(); + + return m_LastCombatTime; + } + } + + public bool Reported + { + get + { + if ( m_Queued ) + DumpAccess(); + + return m_Reported; + } + set + { + if ( m_Queued ) + DumpAccess(); + + m_Reported = value; + } + } + + public bool CanReportMurder + { + get + { + if ( m_Queued ) + DumpAccess(); + + return m_CanReportMurder; + } + set + { + if ( m_Queued ) + DumpAccess(); + + m_CanReportMurder = value; + } + } + + public void Refresh() + { + if ( m_Queued ) + DumpAccess(); + + m_LastCombatTime = DateTime.Now; + m_Reported = false; + } + } +} \ No newline at end of file diff --git a/Server/AssemblyInfo.cs b/Server/AssemblyInfo.cs new file mode 100644 index 0000000..e5d34fe --- /dev/null +++ b/Server/AssemblyInfo.cs @@ -0,0 +1,81 @@ +/*************************************************************************** + * AssemblyInfo.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: AssemblyInfo.cs 805 2012-01-02 12:08:28Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("RunUO Server Core")] //Having just RunUO there is reundant, ie, RunUO.exe with the word 'RunUO' under it +[assembly: AssemblyDescription("UO Server Software")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The RunUO Team")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("2.2.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] + +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/Server/Attributes.cs b/Server/Attributes.cs new file mode 100644 index 0000000..7094933 --- /dev/null +++ b/Server/Attributes.cs @@ -0,0 +1,224 @@ +/*************************************************************************** + * Attributes.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Attributes.cs 274 2007-12-17 20:41:34Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Server +{ + [AttributeUsage( AttributeTargets.Property )] + public class HueAttribute : Attribute + { + public HueAttribute() + { + } + } + + [AttributeUsage( AttributeTargets.Property )] + public class BodyAttribute : Attribute + { + public BodyAttribute() + { + } + } + + [AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct )] + public class PropertyObjectAttribute : Attribute + { + public PropertyObjectAttribute() + { + } + } + + [AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct )] + public class NoSortAttribute : Attribute + { + public NoSortAttribute() + { + } + } + + [AttributeUsage( AttributeTargets.Method )] + public class CallPriorityAttribute : Attribute + { + private int m_Priority; + + public int Priority + { + get{ return m_Priority; } + set{ m_Priority = value; } + } + + public CallPriorityAttribute( int priority ) + { + m_Priority = priority; + } + } + + public class CallPriorityComparer : IComparer + { + public int Compare( MethodInfo x, MethodInfo y ) + { + if ( x == null && y == null ) + return 0; + + if ( x == null ) + return 1; + + if ( y == null ) + return -1; + + return GetPriority( x ) - GetPriority( y ); + } + + private int GetPriority( MethodInfo mi ) + { + object[] objs = mi.GetCustomAttributes( typeof( CallPriorityAttribute ), true ); + + if ( objs == null ) + return 0; + + if ( objs.Length == 0 ) + return 0; + + CallPriorityAttribute attr = objs[0] as CallPriorityAttribute; + + if ( attr == null ) + return 0; + + return attr.Priority; + } + } + + [AttributeUsage( AttributeTargets.Class )] + public class TypeAliasAttribute : Attribute + { + private string[] m_Aliases; + + public string[] Aliases + { + get + { + return m_Aliases; + } + } + + public TypeAliasAttribute( params string[] aliases ) + { + m_Aliases = aliases; + } + } + + [AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct )] + public class ParsableAttribute : Attribute + { + public ParsableAttribute() + { + } + } + + [AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum )] + public class CustomEnumAttribute : Attribute + { + private string[] m_Names; + + public string[] Names + { + get + { + return m_Names; + } + } + + public CustomEnumAttribute( string[] names ) + { + m_Names = names; + } + } + + [AttributeUsage( AttributeTargets.Constructor )] + public class ConstructableAttribute : Attribute + { + private AccessLevel m_AccessLevel; + + public AccessLevel AccessLevel + { + get { return m_AccessLevel; } + set { m_AccessLevel = value; } + } + + public ConstructableAttribute() : this( AccessLevel.Player ) //Lowest accesslevel for current functionality (Level determined by access to [add) + { + } + + public ConstructableAttribute( AccessLevel accessLevel ) + { + m_AccessLevel = accessLevel; + } + } + + [AttributeUsage( AttributeTargets.Property )] + public class CommandPropertyAttribute : Attribute + { + private AccessLevel m_ReadLevel, m_WriteLevel; + private bool m_ReadOnly; + + public AccessLevel ReadLevel + { + get + { + return m_ReadLevel; + } + } + + public AccessLevel WriteLevel + { + get + { + return m_WriteLevel; + } + } + + public bool ReadOnly + { + get + { + return m_ReadOnly; + } + } + + public CommandPropertyAttribute( AccessLevel level, bool readOnly ) + { + m_ReadLevel = level; + m_ReadOnly = readOnly; + } + + public CommandPropertyAttribute( AccessLevel level ) : this( level, level ) + { + } + + public CommandPropertyAttribute( AccessLevel readLevel, AccessLevel writeLevel ) + { + m_ReadLevel = readLevel; + m_WriteLevel = writeLevel; + } + } +} diff --git a/Server/BaseVendor.cs b/Server/BaseVendor.cs new file mode 100644 index 0000000..bf25da9 --- /dev/null +++ b/Server/BaseVendor.cs @@ -0,0 +1,214 @@ +/*************************************************************************** + * BaseVendor.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: BaseVendor.cs 511 2010-04-25 06:09:43Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using Server.Items; +using Server.Network; +using Server.ContextMenus; +using Server.Mobiles; +using System.Collections.Generic; + +namespace Server.Mobiles +{ + public class BuyItemStateComparer : IComparer + { + public int Compare( BuyItemState l, BuyItemState r ) + { + if ( l == null && r == null ) return 0; + if ( l == null ) return -1; + if ( r == null ) return 1; + + return l.MySerial.CompareTo( r.MySerial ); + } + } + + public class BuyItemResponse + { + private Serial m_Serial; + private int m_Amount; + + public BuyItemResponse( Serial serial, int amount ) + { + m_Serial = serial; + m_Amount = amount; + } + + public Serial Serial + { + get + { + return m_Serial; + } + } + + public int Amount + { + get + { + return m_Amount; + } + } + } + + public class SellItemResponse + { + private Item m_Item; + private int m_Amount; + + public SellItemResponse( Item i, int amount ) + { + m_Item = i; + m_Amount = amount; + } + + public Item Item + { + get + { + return m_Item; + } + } + + public int Amount + { + get + { + return m_Amount; + } + } + } + + public class SellItemState + { + private Item m_Item; + private int m_Price; + private string m_Name; + + public SellItemState( Item item, int price, string name ) + { + m_Item = item; + m_Price = price; + m_Name = name; + } + + public Item Item + { + get + { + return m_Item; + } + } + + public int Price + { + get + { + return m_Price; + } + } + + public string Name + { + get + { + return m_Name; + } + } + } + + public class BuyItemState + { + private Serial m_ContSer; + private Serial m_MySer; + private int m_ItemID; + private int m_Amount; + private int m_Hue; + private int m_Price; + private string m_Desc; + + public BuyItemState( string name, Serial cont, Serial serial, int price, int amount, int itemID, int hue ) + { + m_Desc = name; + m_ContSer = cont; + m_MySer = serial; + m_Price = price; + m_Amount = amount; + m_ItemID = itemID; + m_Hue = hue; + } + + public int Price + { + get + { + return m_Price; + } + } + + public Serial MySerial + { + get + { + return m_MySer; + } + } + + public Serial ContainerSerial + { + get + { + return m_ContSer; + } + } + + public int ItemID + { + get + { + return m_ItemID; + } + } + + public int Amount + { + get + { + return m_Amount; + } + } + + public int Hue + { + get + { + return m_Hue; + } + } + + public string Description + { + get + { + return m_Desc; + } + } + } +} diff --git a/Server/Body.cs b/Server/Body.cs new file mode 100644 index 0000000..566d891 --- /dev/null +++ b/Server/Body.cs @@ -0,0 +1,283 @@ +/*************************************************************************** + * Body.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Body.cs 844 2012-03-07 13:47:33Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; + +namespace Server +{ + public enum BodyType : byte + { + Empty, + Monster, + Sea, + Animal, + Human, + Equipment + } + + public struct Body + { + private int m_BodyID; + + private static BodyType[] m_Types; + + static Body() + { + if ( File.Exists( "Data/bodyTable.cfg" ) ) + { + using ( StreamReader ip = new StreamReader( "Data/bodyTable.cfg" ) ) + { + m_Types = new BodyType[0x1000]; + + string line; + + while ( (line = ip.ReadLine()) != null ) + { + if ( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + string[] split = line.Split( '\t' ); +#if Framework_4_0 + BodyType type; + int bodyID; + + if( int.TryParse( split[0], out bodyID ) && Enum.TryParse( split[1], true, out type ) && bodyID >= 0 && bodyID < m_Types.Length ) + { + m_Types[bodyID] = type; + } + else + { + Console.WriteLine( "Warning: Invalid bodyTable entry:" ); + Console.WriteLine( line ); + } +#else + try + { + int bodyID = int.Parse( split[0] ); + BodyType type = (BodyType)Enum.Parse( typeof( BodyType ), split[1], true ); + + if ( bodyID >= 0 && bodyID < m_Types.Length ) + m_Types[bodyID] = type; + } + catch + { + Console.WriteLine( "Warning: Invalid bodyTable entry:" ); + Console.WriteLine( line ); + } +#endif + } + } + } + else + { + Console.WriteLine( "Warning: Data/bodyTable.cfg does not exist" ); + + m_Types = new BodyType[0]; + } + } + + public Body( int bodyID ) + { + m_BodyID = bodyID; + } + + public BodyType Type + { + get + { + if ( m_BodyID >= 0 && m_BodyID < m_Types.Length ) + return m_Types[m_BodyID]; + else + return BodyType.Empty; + } + } + + public bool IsHuman + { + get + { + return m_BodyID >= 0 + && m_BodyID < m_Types.Length + && m_Types[m_BodyID] == BodyType.Human + && m_BodyID != 402 + && m_BodyID != 403 + && m_BodyID != 607 + && m_BodyID != 608 + && m_BodyID != 970; + } + } + + public bool IsMale + { + get + { + return m_BodyID == 183 + || m_BodyID == 185 + || m_BodyID == 400 + || m_BodyID == 402 + || m_BodyID == 605 + || m_BodyID == 607 + || m_BodyID == 750; + } + } + + public bool IsFemale + { + get + { + return m_BodyID == 184 + || m_BodyID == 186 + || m_BodyID == 401 + || m_BodyID == 403 + || m_BodyID == 606 + || m_BodyID == 608 + || m_BodyID == 751; + } + } + + public bool IsGhost + { + get + { + return m_BodyID == 402 + || m_BodyID == 403 + || m_BodyID == 607 + || m_BodyID == 608 + || m_BodyID == 970; + } + } + + public bool IsMonster + { + get + { + return m_BodyID >= 0 + && m_BodyID < m_Types.Length + && m_Types[m_BodyID] == BodyType.Monster; + } + } + + public bool IsAnimal + { + get + { + return m_BodyID >= 0 + && m_BodyID < m_Types.Length + && m_Types[m_BodyID] == BodyType.Animal; + } + } + + public bool IsEmpty + { + get + { + return m_BodyID >= 0 + && m_BodyID < m_Types.Length + && m_Types[m_BodyID] == BodyType.Empty; + } + } + + public bool IsSea + { + get + { + return m_BodyID >= 0 + && m_BodyID < m_Types.Length + && m_Types[m_BodyID] == BodyType.Sea; + } + } + + public bool IsEquipment + { + get + { + return m_BodyID >= 0 + && m_BodyID < m_Types.Length + && m_Types[m_BodyID] == BodyType.Equipment; + } + } + + public int BodyID + { + get + { + return m_BodyID; + } + } + + public static implicit operator int( Body a ) + { + return a.m_BodyID; + } + + public static implicit operator Body( int a ) + { + return new Body( a ); + } + + public override string ToString() + { + return string.Format( "0x{0:X}", m_BodyID ); + } + + public override int GetHashCode() + { + return m_BodyID; + } + + public override bool Equals( object o ) + { + if ( o == null || !(o is Body) ) return false; + + return ((Body)o).m_BodyID == m_BodyID; + } + + public static bool operator == ( Body l, Body r ) + { + return l.m_BodyID == r.m_BodyID; + } + + public static bool operator != ( Body l, Body r ) + { + return l.m_BodyID != r.m_BodyID; + } + + public static bool operator > ( Body l, Body r ) + { + return l.m_BodyID > r.m_BodyID; + } + + public static bool operator >= ( Body l, Body r ) + { + return l.m_BodyID >= r.m_BodyID; + } + + public static bool operator < ( Body l, Body r ) + { + return l.m_BodyID < r.m_BodyID; + } + + public static bool operator <= ( Body l, Body r ) + { + return l.m_BodyID <= r.m_BodyID; + } + } +} \ No newline at end of file diff --git a/Server/ClientVersion.cs b/Server/ClientVersion.cs new file mode 100644 index 0000000..a6cfef5 --- /dev/null +++ b/Server/ClientVersion.cs @@ -0,0 +1,300 @@ +/*************************************************************************** + * ClientVersion.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ClientVersion.cs 521 2010-06-17 07:11:43Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Text; +using System.Collections; + +namespace Server +{ + public enum ClientType + { + Regular, + UOTD, + God, + SA + } + + public class ClientVersion : IComparable, IComparer + { + private int m_Major, m_Minor, m_Revision, m_Patch; + private ClientType m_Type; + private string m_SourceString; + + public int Major + { + get + { + return m_Major; + } + } + + public int Minor + { + get + { + return m_Minor; + } + } + + public int Revision + { + get + { + return m_Revision; + } + } + + public int Patch + { + get + { + return m_Patch; + } + } + + public ClientType Type + { + get + { + return m_Type; + } + } + + public string SourceString + { + get + { + return m_SourceString; + } + } + + public ClientVersion( int maj, int min, int rev, int pat ) : this( maj, min, rev, pat, ClientType.Regular ) + { + } + + public ClientVersion( int maj, int min, int rev, int pat, ClientType type ) + { + m_Major = maj; + m_Minor = min; + m_Revision = rev; + m_Patch = pat; + m_Type = type; + + m_SourceString = ToString(); + } + + public static bool operator == ( ClientVersion l, ClientVersion r ) + { + return ( Compare( l, r ) == 0 ); + } + + public static bool operator != ( ClientVersion l, ClientVersion r ) + { + return ( Compare( l, r ) != 0 ); + } + + public static bool operator >= ( ClientVersion l, ClientVersion r ) + { + return ( Compare( l, r ) >= 0 ); + } + + public static bool operator > ( ClientVersion l, ClientVersion r ) + { + return ( Compare( l, r ) > 0 ); + } + + public static bool operator <= ( ClientVersion l, ClientVersion r ) + { + return ( Compare( l, r ) <= 0 ); + } + + public static bool operator < ( ClientVersion l, ClientVersion r ) + { + return ( Compare( l, r ) < 0 ); + } + + public override int GetHashCode() + { + return m_Major ^ m_Minor ^ m_Revision ^ m_Patch ^ (int)m_Type; + } + + public override bool Equals( object obj ) + { + if ( obj == null ) + return false; + + ClientVersion v = obj as ClientVersion; + + if ( v == null ) + return false; + + return m_Major == v.m_Major + && m_Minor == v.m_Minor + && m_Revision == v.m_Revision + && m_Patch == v.m_Patch + && m_Type == v.m_Type; + } + + public override string ToString() + { + StringBuilder builder = new StringBuilder( 16 ); + + builder.Append( m_Major ); + builder.Append( '.' ); + builder.Append( m_Minor ); + builder.Append( '.' ); + builder.Append( m_Revision ); + + if( m_Major <= 5 && m_Minor <= 0 && m_Revision <= 6 ) //Anything before 5.0.7 + { + if( m_Patch > 0 ) + builder.Append( (char)('a' + (m_Patch - 1)) ); + } + else + { + builder.Append( '.' ); + builder.Append( m_Patch ); + } + + if ( m_Type != ClientType.Regular ) + { + builder.Append( ' ' ); + builder.Append( m_Type.ToString() ); + } + + return builder.ToString(); + } + + public ClientVersion( string fmt ) + { + m_SourceString = fmt; + + try + { + fmt = fmt.ToLower(); + + int br1 = fmt.IndexOf( '.' ); + int br2 = fmt.IndexOf( '.', br1 + 1 ); + + int br3 = br2 + 1; + while ( br3 < fmt.Length && Char.IsDigit( fmt, br3 ) ) + br3++; + + m_Major = Utility.ToInt32( fmt.Substring( 0, br1 ) ); + m_Minor = Utility.ToInt32( fmt.Substring( br1 + 1, br2 - br1 - 1 ) ); + m_Revision = Utility.ToInt32( fmt.Substring( br2 + 1, br3 - br2 - 1 ) ); + + if( br3 < fmt.Length ) + { + if( m_Major <= 5 && m_Minor <= 0 && m_Revision <= 6 ) //Anything before 5.0.7 + { + if( !Char.IsWhiteSpace( fmt, br3 ) ) + m_Patch = (fmt[br3] - 'a') + 1; + } + else + { + m_Patch = Utility.ToInt32( fmt.Substring( br3+1, fmt.Length - br3 - 1 ) ); + } + } + + if ( fmt.IndexOf( "god" ) >= 0 || fmt.IndexOf( "gq" ) >= 0 ) + m_Type = ClientType.God; + else if ( fmt.IndexOf( "third dawn" ) >= 0 || fmt.IndexOf( "uo:td" ) >= 0 || fmt.IndexOf( "uotd" ) >= 0 || fmt.IndexOf( "uo3d" ) >= 0 || fmt.IndexOf( "uo:3d" ) >= 0 ) + m_Type = ClientType.UOTD; + else + m_Type = ClientType.Regular; + } + catch + { + m_Major = 0; + m_Minor = 0; + m_Revision = 0; + m_Patch = 0; + m_Type = ClientType.Regular; + } + } + + public int CompareTo( object obj ) + { + if ( obj == null ) + return 1; + + ClientVersion o = obj as ClientVersion; + + if ( o == null ) + throw new ArgumentException(); + + if ( m_Major > o.m_Major ) + return 1; + else if ( m_Major < o.m_Major ) + return -1; + else if ( m_Minor > o.m_Minor ) + return 1; + else if ( m_Minor < o.m_Minor ) + return -1; + else if ( m_Revision > o.m_Revision ) + return 1; + else if ( m_Revision < o.m_Revision ) + return -1; + else if ( m_Patch > o.m_Patch ) + return 1; + else if ( m_Patch < o.m_Patch ) + return -1; + else + return 0; + } + + public static bool IsNull( object x ) + { + return Object.ReferenceEquals( x, null ); + } + + public int Compare( object x, object y ) + { + if ( IsNull( x ) && IsNull( y ) ) + return 0; + else if ( IsNull( x ) ) + return -1; + else if ( IsNull( y ) ) + return 1; + + ClientVersion a = x as ClientVersion; + ClientVersion b = y as ClientVersion; + + if ( IsNull( a ) || IsNull( b ) ) + throw new ArgumentException(); + + return a.CompareTo( b ); + } + + public static int Compare( ClientVersion a, ClientVersion b ) + { + if ( IsNull( a ) && IsNull( b ) ) + return 0; + else if ( IsNull( a ) ) + return -1; + else if ( IsNull( b ) ) + return 1; + + return a.CompareTo( b ); + } + } +} \ No newline at end of file diff --git a/Server/Commands.cs b/Server/Commands.cs new file mode 100644 index 0000000..663f064 --- /dev/null +++ b/Server/Commands.cs @@ -0,0 +1,347 @@ +/*************************************************************************** + * Commands.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Commands.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server.Guilds; +using Server.Gumps; +using Server.Menus; +using Server.Menus.ItemLists; +using Server.Menus.Questions; +using Server.Network; +using Server.Items; +using Server.Targeting; + +namespace Server.Commands +{ + public delegate void CommandEventHandler( CommandEventArgs e ); + + public class CommandEventArgs : EventArgs + { + private Mobile m_Mobile; + private string m_Command, m_ArgString; + private string[] m_Arguments; + + public Mobile Mobile + { + get + { + return m_Mobile; + } + } + + public string Command + { + get + { + return m_Command; + } + } + + public string ArgString + { + get + { + return m_ArgString; + } + } + + public string[] Arguments + { + get + { + return m_Arguments; + } + } + + public int Length + { + get + { + return m_Arguments.Length; + } + } + + public string GetString( int index ) + { + if ( index < 0 || index >= m_Arguments.Length ) + return ""; + + return m_Arguments[index]; + } + + public int GetInt32( int index ) + { + if ( index < 0 || index >= m_Arguments.Length ) + return 0; + + return Utility.ToInt32( m_Arguments[index] ); + } + + public bool GetBoolean( int index ) + { + if ( index < 0 || index >= m_Arguments.Length ) + return false; + + return Utility.ToBoolean( m_Arguments[index] ); + } + + public double GetDouble( int index ) + { + if ( index < 0 || index >= m_Arguments.Length ) + return 0.0; + + return Utility.ToDouble( m_Arguments[index] ); + } + + public TimeSpan GetTimeSpan( int index ) + { + if ( index < 0 || index >= m_Arguments.Length ) + return TimeSpan.Zero; + + return Utility.ToTimeSpan( m_Arguments[index] ); + } + + public CommandEventArgs( Mobile mobile, string command, string argString, string[] arguments ) + { + m_Mobile = mobile; + m_Command = command; + m_ArgString = argString; + m_Arguments = arguments; + } + } + + public class CommandEntry : IComparable + { + private string m_Command; + private CommandEventHandler m_Handler; + private AccessLevel m_AccessLevel; + + public string Command + { + get + { + return m_Command; + } + } + + public CommandEventHandler Handler + { + get + { + return m_Handler; + } + } + + public AccessLevel AccessLevel + { + get + { + return m_AccessLevel; + } + } + + public CommandEntry( string command, CommandEventHandler handler, AccessLevel accessLevel ) + { + m_Command = command; + m_Handler = handler; + m_AccessLevel = accessLevel; + } + + public int CompareTo( object obj ) + { + if ( obj == this ) + return 0; + else if ( obj == null ) + return 1; + + CommandEntry e = obj as CommandEntry; + + if ( e == null ) + throw new ArgumentException(); + + return m_Command.CompareTo( e.m_Command ); + } + } + + public static class CommandSystem + { + private static string m_Prefix = "["; + + public static string Prefix + { + get + { + return m_Prefix; + } + set + { + m_Prefix = value; + } + } + + public static string[] Split( string value ) + { + char[] array = value.ToCharArray(); + List list = new List(); + + int start = 0, end = 0; + + while ( start < array.Length ) + { + char c = array[start]; + + if ( c == '"' ) + { + ++start; + end = start; + + while ( end < array.Length ) + { + if ( array[end] != '"' || array[end - 1] == '\\' ) + ++end; + else + break; + } + + list.Add( value.Substring( start, end - start ) ); + + start = end + 2; + } + else if ( c != ' ' ) + { + end = start; + + while ( end < array.Length ) + { + if ( array[end] != ' ' ) + ++end; + else + break; + } + + list.Add( value.Substring( start, end - start ) ); + + start = end + 1; + } + else + { + ++start; + } + } + + return list.ToArray(); + } + + private static Dictionary m_Entries; + + public static Dictionary Entries + { + get + { + return m_Entries; + } + } + + static CommandSystem() + { + m_Entries = new Dictionary( StringComparer.OrdinalIgnoreCase ); + } + + public static void Register( string command, AccessLevel access, CommandEventHandler handler ) + { + m_Entries[command] = new CommandEntry( command, handler, access ); + } + + private static AccessLevel m_BadCommandIngoreLevel = AccessLevel.Player; + + public static AccessLevel BadCommandIgnoreLevel{ get{ return m_BadCommandIngoreLevel; } set{ m_BadCommandIngoreLevel = value; } } + + public static bool Handle( Mobile from, string text ) + { + return Handle( from, text, MessageType.Regular ); + } + + public static bool Handle( Mobile from, string text, MessageType type ) + { + if ( text.StartsWith( m_Prefix ) || type == MessageType.Command ) + { + if( type != MessageType.Command ) + text = text.Substring( m_Prefix.Length ); + + int indexOf = text.IndexOf( ' ' ); + + string command; + string[] args; + string argString; + + if ( indexOf >= 0 ) + { + argString = text.Substring( indexOf + 1 ); + + command = text.Substring( 0, indexOf ); + args = Split( argString ); + } + else + { + argString = ""; + command = text.ToLower(); + args = new string[0]; + } + + CommandEntry entry = null; + m_Entries.TryGetValue( command, out entry ); + + if ( entry != null ) + { + if ( from.AccessLevel >= entry.AccessLevel ) + { + if ( entry.Handler != null ) + { + CommandEventArgs e = new CommandEventArgs( from, command, argString, args ); + entry.Handler( e ); + EventSink.InvokeCommand( e ); + } + } + else + { + if ( from.AccessLevel <= m_BadCommandIngoreLevel ) + return false; + + from.SendMessage( "You do not have access to that command." ); + } + } + else + { + if ( from.AccessLevel <= m_BadCommandIngoreLevel ) + return false; + + from.SendMessage( "That is not a valid command." ); + } + + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Server/ContextMenus/ContextMenu.cs b/Server/ContextMenus/ContextMenu.cs new file mode 100644 index 0000000..5a82fd2 --- /dev/null +++ b/Server/ContextMenus/ContextMenu.cs @@ -0,0 +1,115 @@ +/*************************************************************************** + * ContextMenu.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ContextMenu.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.ContextMenus +{ + /// + /// Represents the state of an active context menu. This includes who opened the menu, the menu's focus object, and a list of entries that the menu is composed of. + /// + /// + public class ContextMenu + { + private Mobile m_From; + private object m_Target; + private ContextMenuEntry[] m_Entries; + + /// + /// Gets the who opened this ContextMenu. + /// + public Mobile From + { + get{ return m_From; } + } + + /// + /// Gets an object of the or for which this ContextMenu is on. + /// + public object Target + { + get{ return m_Target; } + } + + /// + /// Gets the list of entries contained in this ContextMenu. + /// + public ContextMenuEntry[] Entries + { + get{ return m_Entries; } + } + + /// + /// Instantiates a new ContextMenu instance. + /// + /// + /// The who opened this ContextMenu. + /// + /// + /// + /// The or for which this ContextMenu is on. + /// + /// + public ContextMenu( Mobile from, object target ) + { + m_From = from; + m_Target = target; + + List list = new List(); + + if ( target is Mobile ) + { + ((Mobile)target).GetContextMenuEntries( from, list ); + } + else if ( target is Item ) + { + ((Item)target).GetContextMenuEntries( from, list ); + } + + //m_Entries = (ContextMenuEntry[])list.ToArray( typeof( ContextMenuEntry ) ); + + m_Entries = list.ToArray(); + + for ( int i = 0; i < m_Entries.Length; ++i ) + { + m_Entries[i].Owner = this; + } + } + + /// + /// Returns true if this ContextMenu requires packet version 2. + /// + public bool RequiresNewPacket + { + get + { + for (int i = 0; i < m_Entries.Length; ++i) + { + if (m_Entries[i].Number < 3000000 || m_Entries[i].Number > 3032767) + return true; + } + + return false; + } + } + } +} \ No newline at end of file diff --git a/Server/ContextMenus/ContextMenuEntry.cs b/Server/ContextMenus/ContextMenuEntry.cs new file mode 100644 index 0000000..5b26d9f --- /dev/null +++ b/Server/ContextMenus/ContextMenuEntry.cs @@ -0,0 +1,143 @@ +/*************************************************************************** + * ContextMenuEntry.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ContextMenuEntry.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server; +using Server.Network; + +namespace Server.ContextMenus +{ + /// + /// Represents a single entry of a context menu. + /// + /// + public class ContextMenuEntry + { + private int m_Number; + private int m_Color; + private bool m_Enabled; + private int m_Range; + private CMEFlags m_Flags; + private ContextMenu m_Owner; + + /// + /// Gets or sets additional flags used in client communication. + /// + public CMEFlags Flags + { + get{ return m_Flags; } + set{ m_Flags = value; } + } + + /// + /// Gets or sets the that owns this entry. + /// + public ContextMenu Owner + { + get{ return m_Owner; } + set{ m_Owner = value; } + } + + /// + /// Gets or sets the localization number containing the name of this entry. + /// + public int Number + { + get{ return m_Number; } + set{ m_Number = value; } + } + + /// + /// Gets or sets the maximum range at which this entry may be used, in tiles. A value of -1 signifies no maximum range. + /// + public int Range + { + get{ return m_Range; } + set{ m_Range = value; } + } + + /// + /// Gets or sets the color for this entry. Format is A1-R5-G5-B5. + /// + public int Color + { + get{ return m_Color; } + set{ m_Color = value; } + } + + /// + /// Gets or sets whether this entry is enabled. When false, the entry will appear in a gray hue and will never be invoked. + /// + public bool Enabled + { + get{ return m_Enabled; } + set{ m_Enabled = value; } + } + + /// + /// Gets a value indicating if non local use of this entry is permitted. + /// + public virtual bool NonLocalUse + { + get{ return false; } + } + + /// + /// Instantiates a new ContextMenuEntry with a given localization number (). No maximum range is used. + /// + /// + /// The localization number containing the name of this entry. + /// + /// + public ContextMenuEntry( int number ) : this( number, -1 ) + { + } + + /// + /// Instantiates a new ContextMenuEntry with a given localization number () and maximum range (). + /// + /// + /// The localization number containing the name of this entry. + /// + /// + /// + /// The maximum range at which this entry can be used. + /// + /// + public ContextMenuEntry(int number, int range) + { + if (number <= 0x7FFF) // Legacy code support + m_Number = 3000000 + number; + else + m_Number = number; + + m_Range = range; + m_Enabled = true; + m_Color = 0xFFFF; + } + + /// + /// Overridable. Virtual event invoked when the entry is clicked. + /// + public virtual void OnClick() + { + } + } +} \ No newline at end of file diff --git a/Server/ContextMenus/OpenBackpackEntry.cs b/Server/ContextMenus/OpenBackpackEntry.cs new file mode 100644 index 0000000..a0b100e --- /dev/null +++ b/Server/ContextMenus/OpenBackpackEntry.cs @@ -0,0 +1,40 @@ +/*************************************************************************** + * OpenBackpackEntry.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: OpenBackpackEntry.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Items; + +namespace Server.ContextMenus +{ + public class OpenBackpackEntry : ContextMenuEntry + { + private Mobile m_Mobile; + + public OpenBackpackEntry( Mobile m ) : base( 6145 ) + { + m_Mobile = m; + } + + public override void OnClick() + { + m_Mobile.Use( m_Mobile.Backpack ); + } + } +} \ No newline at end of file diff --git a/Server/ContextMenus/PaperdollEntry.cs b/Server/ContextMenus/PaperdollEntry.cs new file mode 100644 index 0000000..72ba668 --- /dev/null +++ b/Server/ContextMenus/PaperdollEntry.cs @@ -0,0 +1,40 @@ +/*************************************************************************** + * PaperdollEntry.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: PaperdollEntry.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.ContextMenus +{ + public class PaperdollEntry : ContextMenuEntry + { + private Mobile m_Mobile; + + public PaperdollEntry( Mobile m ) : base( 6123, 18 ) + { + m_Mobile = m; + } + + public override void OnClick() + { + if ( m_Mobile.CanPaperdollBeOpenedBy( Owner.From ) ) + m_Mobile.DisplayPaperdollTo( Owner.From ); + } + } +} \ No newline at end of file diff --git a/Server/Diagnostics/BaseProfile.cs b/Server/Diagnostics/BaseProfile.cs new file mode 100644 index 0000000..37162ff --- /dev/null +++ b/Server/Diagnostics/BaseProfile.cs @@ -0,0 +1,112 @@ +/*************************************************************************** + * PacketProfile.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: BaseProfile.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Server.Diagnostics { + public abstract class BaseProfile { + public static void WriteAll( TextWriter op, IEnumerable profiles ) where T : BaseProfile { + List list = new List( profiles ); + + list.Sort( delegate( T a, T b ) { + return -a.TotalTime.CompareTo( b.TotalTime ); + } ); + + foreach ( T prof in list ) { + prof.WriteTo( op ); + op.WriteLine(); + } + } + + private string _name; + + private long _count; + + private TimeSpan _totalTime; + private TimeSpan _peakTime; + + private Stopwatch _stopwatch; + + public string Name { + get { + return _name; + } + } + + public long Count { + get { + return _count; + } + } + + public TimeSpan AverageTime { + get { + return TimeSpan.FromTicks( _totalTime.Ticks / Math.Max( 1, _count ) ); + } + } + + public TimeSpan PeakTime { + get { + return _peakTime; + } + } + + public TimeSpan TotalTime { + get { + return _totalTime; + } + } + + protected BaseProfile( string name ) { + _name = name; + + _stopwatch = new Stopwatch(); + } + + public virtual void Start() { + if ( _stopwatch.IsRunning ) { + _stopwatch.Reset(); + } + + _stopwatch.Start(); + } + + public virtual void Finish() { + TimeSpan elapsed = _stopwatch.Elapsed; + + _totalTime += elapsed; + + if ( elapsed > _peakTime ) { + _peakTime = elapsed; + } + + _count++; + + _stopwatch.Reset(); + } + + public virtual void WriteTo( TextWriter op ) { + op.Write( "{0,-100} {1,12:N0} {2,12:F5} {3,-12:F5} {4,12:F5}", Name, Count, AverageTime.TotalSeconds, PeakTime.TotalSeconds, TotalTime.TotalSeconds ); + } + } +} \ No newline at end of file diff --git a/Server/Diagnostics/GumpProfile.cs b/Server/Diagnostics/GumpProfile.cs new file mode 100644 index 0000000..380a070 --- /dev/null +++ b/Server/Diagnostics/GumpProfile.cs @@ -0,0 +1,53 @@ +/*************************************************************************** + * PacketProfile.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpProfile.cs 169 2007-04-22 07:31:23Z krrios $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Diagnostics { + public class GumpProfile : BaseProfile { + private static Dictionary _profiles = new Dictionary(); + + public static IEnumerable Profiles { + get { + return _profiles.Values; + } + } + + public static GumpProfile Acquire( Type type ) { + if ( !Core.Profiling ) { + return null; + } + + GumpProfile prof; + + if ( !_profiles.TryGetValue( type, out prof ) ) { + _profiles.Add( type, prof = new GumpProfile( type ) ); + } + + return prof; + } + + public GumpProfile( Type type ) + : base( type.FullName ) { + } + } +} \ No newline at end of file diff --git a/Server/Diagnostics/PacketProfile.cs b/Server/Diagnostics/PacketProfile.cs new file mode 100644 index 0000000..b97ce52 --- /dev/null +++ b/Server/Diagnostics/PacketProfile.cs @@ -0,0 +1,131 @@ +/*************************************************************************** + * PacketProfile.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: PacketProfile.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace Server.Diagnostics { + public abstract class BasePacketProfile : BaseProfile { + private long _totalLength; + + public long TotalLength { + get { + return _totalLength; + } + } + + public double AverageLength { + get { + return ( double ) _totalLength / Math.Max( 1, this.Count ); + } + } + + protected BasePacketProfile(string name) + : base( name ) { + } + + public void Finish( int length ) { + Finish(); + + _totalLength += length; + } + + public override void WriteTo( TextWriter op ) { + base.WriteTo( op ); + + op.Write( "\t{0,12:F2} {1,-12:N0}", AverageLength, TotalLength ); + } + } + + public class PacketSendProfile : BasePacketProfile { + private static Dictionary _profiles = new Dictionary(); + + public static IEnumerable Profiles { + get { + return _profiles.Values; + } + } + + public static PacketSendProfile Acquire( Type type ) { + if ( !Core.Profiling ) { + return null; + } + + PacketSendProfile prof; + + if ( !_profiles.TryGetValue( type, out prof ) ) { + _profiles.Add( type, prof = new PacketSendProfile( type ) ); + } + + return prof; + } + + private long _created; + + public long Created { + get { + return _created; + } + set { + _created = value; + } + } + + public PacketSendProfile( Type type ) + : base( type.FullName ) { + } + + public override void WriteTo( TextWriter op ) { + base.WriteTo( op ); + + op.Write( "\t{0,12:N0}", Created ); + } + } + + public class PacketReceiveProfile : BasePacketProfile { + private static Dictionary _profiles = new Dictionary(); + + public static IEnumerable Profiles { + get { + return _profiles.Values; + } + } + + public static PacketReceiveProfile Acquire( int packetId ) { + if ( !Core.Profiling ) { + return null; + } + + PacketReceiveProfile prof; + + if ( !_profiles.TryGetValue( packetId, out prof ) ) { + _profiles.Add( packetId, prof = new PacketReceiveProfile( packetId ) ); + } + + return prof; + } + + public PacketReceiveProfile( int packetId ) + : base( String.Format( "0x{0:X2}", packetId ) ) { + } + } +} \ No newline at end of file diff --git a/Server/Diagnostics/TargetProfile.cs b/Server/Diagnostics/TargetProfile.cs new file mode 100644 index 0000000..f0780c4 --- /dev/null +++ b/Server/Diagnostics/TargetProfile.cs @@ -0,0 +1,53 @@ +/*************************************************************************** + * PacketProfile.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TargetProfile.cs 169 2007-04-22 07:31:23Z krrios $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Server.Diagnostics { + public class TargetProfile : BaseProfile { + private static Dictionary _profiles = new Dictionary(); + + public static IEnumerable Profiles { + get { + return _profiles.Values; + } + } + + public static TargetProfile Acquire( Type type ) { + if ( !Core.Profiling ) { + return null; + } + + TargetProfile prof; + + if ( !_profiles.TryGetValue( type, out prof ) ) { + _profiles.Add( type, prof = new TargetProfile( type ) ); + } + + return prof; + } + + public TargetProfile( Type type ) + : base( type.FullName ) { + } + } +} \ No newline at end of file diff --git a/Server/Diagnostics/TimerProfile.cs b/Server/Diagnostics/TimerProfile.cs new file mode 100644 index 0000000..006ea11 --- /dev/null +++ b/Server/Diagnostics/TimerProfile.cs @@ -0,0 +1,89 @@ +/*************************************************************************** + * PacketProfile.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TimerProfile.cs 169 2007-04-22 07:31:23Z krrios $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; + +namespace Server.Diagnostics { + public class TimerProfile : BaseProfile { + private static Dictionary _profiles = new Dictionary(); + + public static IEnumerable Profiles { + get { + return _profiles.Values; + } + } + + public static TimerProfile Acquire( string name ) { + if ( !Core.Profiling ) { + return null; + } + + TimerProfile prof; + + if ( !_profiles.TryGetValue( name, out prof ) ) { + _profiles.Add( name, prof = new TimerProfile( name ) ); + } + + return prof; + } + + private long _created, _started, _stopped; + + public long Created { + get { + return _created; + } + set { + _created = value; + } + } + + public long Started { + get { + return _started; + } + set { + _started = value; + } + } + + public long Stopped { + get { + return _stopped; + } + set { + _stopped = value; + } + } + + public TimerProfile( string name ) + : base( name ) { + } + + public override void WriteTo( TextWriter op ) { + base.WriteTo( op ); + + op.Write( "\t{0,12:N0} {1,12:N0} {2,-12:N0}", _created, _started, _stopped ); + } + } +} \ No newline at end of file diff --git a/Server/Effects.cs b/Server/Effects.cs new file mode 100644 index 0000000..48299f2 --- /dev/null +++ b/Server/Effects.cs @@ -0,0 +1,405 @@ +/*************************************************************************** + * Effects.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Effects.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using Server.Network; + +namespace Server +{ + public enum EffectLayer + { + Head = 0, + RightHand = 1, + LeftHand = 2, + Waist = 3, + LeftFoot = 4, + RightFoot = 5, + CenterFeet = 7 + } + + public enum ParticleSupportType + { + Full, + Detect, + None + } + + public static class Effects + { + private static ParticleSupportType m_ParticleSupportType = ParticleSupportType.Detect; + + public static ParticleSupportType ParticleSupportType + { + get{ return m_ParticleSupportType; } + set{ m_ParticleSupportType = value; } + } + + public static bool SendParticlesTo( NetState state ) + { + return ( m_ParticleSupportType == ParticleSupportType.Full || (m_ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient) ); + } + + public static void PlaySound( IPoint3D p, Map map, int soundID ) + { + if ( soundID <= -1 ) + return; + + if ( map != null ) + { + Packet playSound = null; + + IPooledEnumerable eable = map.GetClientsInRange( new Point3D( p ) ); + + foreach ( NetState state in eable ) + { + state.Mobile.ProcessDelta(); + + if ( playSound == null ) + playSound = Packet.Acquire( new PlaySound( soundID, p ) ); + + state.Send( playSound ); + } + + Packet.Release( playSound ); + + eable.Free(); + } + } + + public static void SendBoltEffect( IEntity e ) + { + SendBoltEffect( e, true, 0 ); + } + + public static void SendBoltEffect( IEntity e, bool sound ) + { + SendBoltEffect( e, sound, 0 ); + } + + public static void SendBoltEffect( IEntity e, bool sound, int hue ) + { + Map map = e.Map; + + if ( map == null ) + return; + + e.ProcessDelta(); + + Packet preEffect = null, boltEffect = null, playSound = null; + + IPooledEnumerable eable = map.GetClientsInRange( e.Location ); + + foreach ( NetState state in eable ) + { + if ( state.Mobile.CanSee( e ) ) + { + if ( SendParticlesTo( state ) ) + { + if ( preEffect == null ) + preEffect = Packet.Acquire( new TargetParticleEffect( e, 0, 10, 5, 0, 0, 5031, 3, 0 ) ); + + state.Send( preEffect ); + } + + if ( boltEffect == null ) + boltEffect = Packet.Acquire( new BoltEffect( e, hue ) ); + + state.Send( boltEffect ); + + if ( sound ) + { + if ( playSound == null ) + playSound = Packet.Acquire( new PlaySound( 0x29, e ) ); + + state.Send( playSound ); + } + } + } + + Packet.Release( preEffect ); + Packet.Release( boltEffect ); + Packet.Release( playSound ); + + eable.Free(); + } + + public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration ) + { + SendLocationEffect( p, map, itemID, duration, 10, 0, 0 ); + } + + public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration, int speed ) + { + SendLocationEffect( p, map, itemID, duration, speed, 0, 0 ); + } + + public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration, int hue, int renderMode ) + { + SendLocationEffect( p, map, itemID, duration, 10, hue, renderMode ); + } + + public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration, int speed, int hue, int renderMode ) + { + SendPacket( p, map, new LocationEffect( p, itemID, speed, duration, hue, renderMode ) ); + } + + public static void SendLocationParticles( IEntity e, int itemID, int speed, int duration, int effect ) + { + SendLocationParticles( e, itemID, speed, duration, 0, 0, effect, 0 ); + } + + public static void SendLocationParticles( IEntity e, int itemID, int speed, int duration, int effect, int unknown ) + { + SendLocationParticles( e, itemID, speed, duration, 0, 0, effect, unknown ); + } + + public static void SendLocationParticles( IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown ) + { + Map map = e.Map; + + if ( map != null ) + { + Packet particles = null, regular = null; + + IPooledEnumerable eable = map.GetClientsInRange( e.Location ); + + foreach ( NetState state in eable ) + { + state.Mobile.ProcessDelta(); + + if ( SendParticlesTo( state ) ) + { + if ( particles == null ) + particles = Packet.Acquire( new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) ); + + state.Send( particles ); + } + else if ( itemID != 0 ) + { + if ( regular == null ) + regular = Packet.Acquire( new LocationEffect( e, itemID, speed, duration, hue, renderMode ) ); + + state.Send( regular ); + } + } + + Packet.Release( particles ); + Packet.Release( regular ); + + eable.Free(); + } + //SendPacket( e.Location, e.Map, new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) ); + } + + public static void SendTargetEffect( IEntity target, int itemID, int duration ) + { + SendTargetEffect( target, itemID, duration, 0, 0 ); + } + + public static void SendTargetEffect( IEntity target, int itemID, int speed, int duration ) + { + SendTargetEffect( target, itemID, speed, duration, 0, 0 ); + } + + public static void SendTargetEffect( IEntity target, int itemID, int duration, int hue, int renderMode ) + { + SendTargetEffect( target, itemID, 10, duration, hue, renderMode ); + } + + public static void SendTargetEffect( IEntity target, int itemID, int speed, int duration, int hue, int renderMode ) + { + if ( target is Mobile ) + ((Mobile)target).ProcessDelta(); + + SendPacket( target.Location, target.Map, new TargetEffect( target, itemID, speed, duration, hue, renderMode ) ); + } + + public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int effect, EffectLayer layer ) + { + SendTargetParticles( target, itemID, speed, duration, 0, 0, effect, layer, 0 ); + } + + public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int effect, EffectLayer layer, int unknown ) + { + SendTargetParticles( target, itemID, speed, duration, 0, 0, effect, layer, unknown ); + } + + public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int hue, int renderMode, int effect, EffectLayer layer, int unknown ) + { + if ( target is Mobile ) + ((Mobile)target).ProcessDelta(); + + Map map = target.Map; + + if ( map != null ) + { + Packet particles = null, regular = null; + + IPooledEnumerable eable = map.GetClientsInRange( target.Location ); + + foreach ( NetState state in eable ) + { + state.Mobile.ProcessDelta(); + + if ( SendParticlesTo( state ) ) + { + if ( particles == null ) + particles = Packet.Acquire( new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) ); + + state.Send( particles ); + } + else if ( itemID != 0 ) + { + if ( regular == null ) + regular = Packet.Acquire( new TargetEffect( target, itemID, speed, duration, hue, renderMode ) ); + + state.Send( regular ); + } + } + + Packet.Release( particles ); + Packet.Release( regular ); + + eable.Free(); + } + + //SendPacket( target.Location, target.Map, new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) ); + } + + public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes ) + { + SendMovingEffect( from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0 ); + } + + public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode ) + { + if ( from is Mobile ) + ((Mobile)from).ProcessDelta(); + + if ( to is Mobile ) + ((Mobile)to).ProcessDelta(); + + SendPacket( from.Location, from.Map, new MovingEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode ) ); + } + + public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound ) + { + SendMovingParticles( from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, 0 ); + } + + public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown ) + { + SendMovingParticles( from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, unknown ); + } + + public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, int unknown ) + { + SendMovingParticles( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, (EffectLayer)255, unknown ); + } + + public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, int unknown ) + { + if ( from is Mobile ) + ((Mobile)from).ProcessDelta(); + + if ( to is Mobile ) + ((Mobile)to).ProcessDelta(); + + Map map = from.Map; + + if ( map != null ) + { + Packet particles = null, regular = null; + + IPooledEnumerable eable = map.GetClientsInRange( from.Location ); + + foreach ( NetState state in eable ) + { + state.Mobile.ProcessDelta(); + + if ( SendParticlesTo( state ) ) + { + if ( particles == null ) + particles = Packet.Acquire( new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer, unknown ) ); + + state.Send( particles ); + } + else if ( itemID > 1 ) + { + if ( regular == null ) + regular = Packet.Acquire( new MovingEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode ) ); + + state.Send( regular ); + } + } + + Packet.Release( particles ); + Packet.Release( regular ); + + eable.Free(); + } + + //SendPacket( from.Location, from.Map, new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, unknown ) ); + } + + public static void SendPacket( Point3D origin, Map map, Packet p ) + { + if ( map != null ) + { + IPooledEnumerable eable = map.GetClientsInRange( origin ); + + p.Acquire(); + + foreach ( NetState state in eable ) + { + state.Mobile.ProcessDelta(); + + state.Send( p ); + } + + p.Release(); + + eable.Free(); + } + } + + public static void SendPacket( IPoint3D origin, Map map, Packet p ) + { + if ( map != null ) + { + IPooledEnumerable eable = map.GetClientsInRange( new Point3D( origin ) ); + + p.Acquire(); + + foreach ( NetState state in eable ) + { + state.Mobile.ProcessDelta(); + + state.Send( p ); + } + + p.Release(); + + eable.Free(); + } + } + } +} \ No newline at end of file diff --git a/Server/EventLog.cs b/Server/EventLog.cs new file mode 100644 index 0000000..2069140 --- /dev/null +++ b/Server/EventLog.cs @@ -0,0 +1,67 @@ +/*************************************************************************** + * EventLog.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: EventLog.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Diagnostics; +using DiagELog = System.Diagnostics.EventLog; + +namespace Server +{ + public static class EventLog + { + static EventLog() + { + if ( !DiagELog.SourceExists( "RunUO" ) ) + { + DiagELog.CreateEventSource( "RunUO", "Application" ); + } + } + + public static void Error( int eventID, string text ) + { + DiagELog.WriteEntry( "RunUO", text, EventLogEntryType.Error, eventID ); + } + + public static void Error( int eventID, string format, params object[] args ) + { + Error( eventID, String.Format( format, args ) ); + } + + public static void Warning( int eventID, string text ) + { + DiagELog.WriteEntry( "RunUO", text, EventLogEntryType.Warning, eventID ); + } + + public static void Warning( int eventID, string format, params object[] args ) + { + Warning( eventID, String.Format( format, args ) ); + } + + public static void Inform( int eventID, string text ) + { + DiagELog.WriteEntry( "RunUO", text, EventLogEntryType.Information, eventID ); + } + + public static void Inform( int eventID, string format, params object[] args ) + { + Inform( eventID, String.Format( format, args ) ); + } + } +} \ No newline at end of file diff --git a/Server/EventSink.cs b/Server/EventSink.cs new file mode 100644 index 0000000..0f2cc71 --- /dev/null +++ b/Server/EventSink.cs @@ -0,0 +1,1133 @@ +/*************************************************************************** + * EventSink.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: EventSink.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Collections; +using System.Collections.Generic; +using Server; +using Server.Items; +using Server.Accounting; +using Server.Network; +using Server.Guilds; +using Server.Commands; + +namespace Server +{ + public delegate void CharacterCreatedEventHandler( CharacterCreatedEventArgs e ); + public delegate void OpenDoorMacroEventHandler( OpenDoorMacroEventArgs e ); + public delegate void SpeechEventHandler( SpeechEventArgs e ); + public delegate void LoginEventHandler( LoginEventArgs e ); + public delegate void ServerListEventHandler( ServerListEventArgs e ); + public delegate void MovementEventHandler( MovementEventArgs e ); + public delegate void HungerChangedEventHandler( HungerChangedEventArgs e ); + public delegate void CrashedEventHandler( CrashedEventArgs e ); + public delegate void ShutdownEventHandler( ShutdownEventArgs e ); + public delegate void HelpRequestEventHandler( HelpRequestEventArgs e ); + public delegate void DisarmRequestEventHandler( DisarmRequestEventArgs e ); + public delegate void StunRequestEventHandler( StunRequestEventArgs e ); + public delegate void OpenSpellbookRequestEventHandler( OpenSpellbookRequestEventArgs e ); + public delegate void CastSpellRequestEventHandler( CastSpellRequestEventArgs e ); + public delegate void AnimateRequestEventHandler( AnimateRequestEventArgs e ); + public delegate void LogoutEventHandler( LogoutEventArgs e ); + public delegate void SocketConnectEventHandler( SocketConnectEventArgs e ); + public delegate void ConnectedEventHandler( ConnectedEventArgs e ); + public delegate void DisconnectedEventHandler( DisconnectedEventArgs e ); + public delegate void RenameRequestEventHandler( RenameRequestEventArgs e ); + public delegate void PlayerDeathEventHandler( PlayerDeathEventArgs e ); + public delegate void VirtueGumpRequestEventHandler( VirtueGumpRequestEventArgs e ); + public delegate void VirtueItemRequestEventHandler( VirtueItemRequestEventArgs e ); + public delegate void VirtueMacroRequestEventHandler( VirtueMacroRequestEventArgs e ); + public delegate void ChatRequestEventHandler( ChatRequestEventArgs e ); + public delegate void AccountLoginEventHandler( AccountLoginEventArgs e ); + public delegate void PaperdollRequestEventHandler( PaperdollRequestEventArgs e ); + public delegate void ProfileRequestEventHandler( ProfileRequestEventArgs e ); + public delegate void ChangeProfileRequestEventHandler( ChangeProfileRequestEventArgs e ); + public delegate void AggressiveActionEventHandler( AggressiveActionEventArgs e ); + public delegate void GameLoginEventHandler( GameLoginEventArgs e ); + public delegate void DeleteRequestEventHandler( DeleteRequestEventArgs e ); + public delegate void WorldLoadEventHandler(); + public delegate void WorldSaveEventHandler( WorldSaveEventArgs e ); + public delegate void SetAbilityEventHandler( SetAbilityEventArgs e ); + public delegate void FastWalkEventHandler( FastWalkEventArgs e ); + public delegate void ServerStartedEventHandler(); + public delegate BaseGuild CreateGuildHandler( CreateGuildEventArgs e ); + public delegate void GuildGumpRequestHandler( GuildGumpRequestArgs e ); + public delegate void QuestGumpRequestHandler( QuestGumpRequestArgs e ); + public delegate void ClientVersionReceivedHandler( ClientVersionReceivedArgs e ); + + public class ClientVersionReceivedArgs : EventArgs + { + private NetState m_State; + private ClientVersion m_Version; + + public NetState State { get { return m_State; } } + public ClientVersion Version { get { return m_Version; } } + + public ClientVersionReceivedArgs( NetState state, ClientVersion cv ) + { + m_State = state; + m_Version = cv; + } + } + + public class CreateGuildEventArgs : EventArgs + { + private int m_Id; + public int Id { get { return m_Id; } set { m_Id = value; } } + + public CreateGuildEventArgs( int id ) + { + m_Id = id; + } + } + + public class GuildGumpRequestArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public GuildGumpRequestArgs( Mobile mobile ) + { + m_Mobile = mobile; + } + } + + public class QuestGumpRequestArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile { get { return m_Mobile; } } + + public QuestGumpRequestArgs( Mobile mobile ) + { + m_Mobile = mobile; + } + } + + public class SetAbilityEventArgs : EventArgs + { + private Mobile m_Mobile; + private int m_Index; + + public Mobile Mobile{ get{ return m_Mobile; } } + public int Index{ get{ return m_Index; } } + + public SetAbilityEventArgs( Mobile mobile, int index ) + { + m_Mobile = mobile; + m_Index = index; + } + } + + public class DeleteRequestEventArgs : EventArgs + { + private NetState m_State; + private int m_Index; + + public NetState State{ get{ return m_State; } } + public int Index{ get{ return m_Index; } } + + public DeleteRequestEventArgs( NetState state, int index ) + { + m_State = state; + m_Index = index; + } + } + + public class GameLoginEventArgs : EventArgs + { + private NetState m_State; + private string m_Username; + private string m_Password; + private bool m_Accepted; + private CityInfo[] m_CityInfo; + + public NetState State{ get{ return m_State; } } + public string Username{ get{ return m_Username; } } + public string Password{ get{ return m_Password; } } + public bool Accepted{ get{ return m_Accepted; } set{ m_Accepted = value; } } + public CityInfo[] CityInfo{ get{ return m_CityInfo; } set{ m_CityInfo = value; } } + + public GameLoginEventArgs( NetState state, string un, string pw ) + { + m_State = state; + m_Username = un; + m_Password = pw; + } + } + + public class AggressiveActionEventArgs : EventArgs + { + private Mobile m_Aggressed; + private Mobile m_Aggressor; + private bool m_Criminal; + + public Mobile Aggressed{ get{ return m_Aggressed; } } + public Mobile Aggressor{ get{ return m_Aggressor; } } + public bool Criminal{ get{ return m_Criminal; } } + + private static Queue m_Pool = new Queue(); + + public static AggressiveActionEventArgs Create( Mobile aggressed, Mobile aggressor, bool criminal ) + { + AggressiveActionEventArgs args; + + if ( m_Pool.Count > 0 ) + { + args = m_Pool.Dequeue(); + + args.m_Aggressed = aggressed; + args.m_Aggressor = aggressor; + args.m_Criminal = criminal; + } + else + { + args = new AggressiveActionEventArgs( aggressed, aggressor, criminal ); + } + + return args; + } + + private AggressiveActionEventArgs( Mobile aggressed, Mobile aggressor, bool criminal ) + { + m_Aggressed = aggressed; + m_Aggressor = aggressor; + m_Criminal = criminal; + } + + public void Free() + { + m_Pool.Enqueue( this ); + } + } + + public class ProfileRequestEventArgs : EventArgs + { + private Mobile m_Beholder; + private Mobile m_Beheld; + + public Mobile Beholder{ get{ return m_Beholder; } } + public Mobile Beheld{ get{ return m_Beheld; } } + + public ProfileRequestEventArgs( Mobile beholder, Mobile beheld ) + { + m_Beholder = beholder; + m_Beheld = beheld; + } + } + + public class ChangeProfileRequestEventArgs : EventArgs + { + private Mobile m_Beholder; + private Mobile m_Beheld; + private string m_Text; + + public Mobile Beholder{ get{ return m_Beholder; } } + public Mobile Beheld{ get{ return m_Beheld; } } + public string Text{ get{ return m_Text; } } + + public ChangeProfileRequestEventArgs( Mobile beholder, Mobile beheld, string text ) + { + m_Beholder = beholder; + m_Beheld = beheld; + m_Text = text; + } + } + + public class PaperdollRequestEventArgs : EventArgs + { + private Mobile m_Beholder; + private Mobile m_Beheld; + + public Mobile Beholder{ get{ return m_Beholder; } } + public Mobile Beheld{ get{ return m_Beheld; } } + + public PaperdollRequestEventArgs( Mobile beholder, Mobile beheld ) + { + m_Beholder = beholder; + m_Beheld = beheld; + } + } + + public class AccountLoginEventArgs : EventArgs + { + private NetState m_State; + private string m_Username; + private string m_Password; + + private bool m_Accepted; + private ALRReason m_RejectReason; + + public NetState State{ get{ return m_State; } } + public string Username{ get{ return m_Username; } } + public string Password{ get{ return m_Password; } } + public bool Accepted{ get{ return m_Accepted; } set{ m_Accepted = value; } } + public ALRReason RejectReason{ get{ return m_RejectReason; } set{ m_RejectReason = value; } } + + public AccountLoginEventArgs( NetState state, string username, string password ) + { + m_State = state; + m_Username = username; + m_Password = password; + } + } + + public class VirtueItemRequestEventArgs : EventArgs + { + private Mobile m_Beholder; + private Mobile m_Beheld; + private int m_GumpID; + + public Mobile Beholder{ get{ return m_Beholder; } } + public Mobile Beheld{ get{ return m_Beheld; } } + public int GumpID{ get{ return m_GumpID; } } + + public VirtueItemRequestEventArgs( Mobile beholder, Mobile beheld, int gumpID ) + { + m_Beholder = beholder; + m_Beheld = beheld; + m_GumpID = gumpID; + } + } + + public class VirtueGumpRequestEventArgs : EventArgs + { + private Mobile m_Beholder, m_Beheld; + + public Mobile Beholder{ get{ return m_Beholder; } } + public Mobile Beheld{ get{ return m_Beheld; } } + + public VirtueGumpRequestEventArgs( Mobile beholder, Mobile beheld ) + { + m_Beholder = beholder; + m_Beheld = beheld; + } + } + + public class VirtueMacroRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + private int m_VirtueID; + + public Mobile Mobile{ get{ return m_Mobile; } } + public int VirtueID{ get{ return m_VirtueID; } } + + public VirtueMacroRequestEventArgs( Mobile mobile, int virtueID ) + { + m_Mobile = mobile; + m_VirtueID = virtueID; + } + } + + public class ChatRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public ChatRequestEventArgs( Mobile mobile ) + { + m_Mobile = mobile; + } + } + + public class PlayerDeathEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public PlayerDeathEventArgs( Mobile mobile ) + { + m_Mobile = mobile; + } + } + + public class RenameRequestEventArgs : EventArgs + { + private Mobile m_From, m_Target; + private string m_Name; + + public Mobile From{ get{ return m_From; } } + public Mobile Target{ get{ return m_Target; } } + public string Name{ get{ return m_Name; } } + + public RenameRequestEventArgs( Mobile from, Mobile target, string name ) + { + m_From = from; + m_Target = target; + m_Name = name; + } + } + + public class LogoutEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public LogoutEventArgs( Mobile m ) + { + m_Mobile = m; + } + } + + public class SocketConnectEventArgs : EventArgs + { + private Socket m_Socket; + private bool m_AllowConnection; + + public Socket Socket{ get{ return m_Socket; } } + public bool AllowConnection{ get { return m_AllowConnection; } set { m_AllowConnection = value; } } + + public SocketConnectEventArgs( Socket s ) + { + m_Socket = s; + m_AllowConnection = true; + } + } + + public class ConnectedEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public ConnectedEventArgs( Mobile m ) + { + m_Mobile = m; + } + } + + public class DisconnectedEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public DisconnectedEventArgs( Mobile m ) + { + m_Mobile = m; + } + } + + public class AnimateRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + private string m_Action; + + public Mobile Mobile{ get{ return m_Mobile; } } + public string Action{ get{ return m_Action; } } + + public AnimateRequestEventArgs( Mobile m, string action ) + { + m_Mobile = m; + m_Action = action; + } + } + + public class CastSpellRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + private Item m_Spellbook; + private int m_SpellID; + + public Mobile Mobile{ get{ return m_Mobile; } } + public Item Spellbook{ get{ return m_Spellbook; } } + public int SpellID{ get{ return m_SpellID; } } + + public CastSpellRequestEventArgs( Mobile m, int spellID, Item book ) + { + m_Mobile = m; + m_Spellbook = book; + m_SpellID = spellID; + } + } + + public class OpenSpellbookRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + private int m_Type; + + public Mobile Mobile{ get{ return m_Mobile; } } + public int Type{ get{ return m_Type; } } + + public OpenSpellbookRequestEventArgs( Mobile m, int type ) + { + m_Mobile = m; + m_Type = type; + } + } + + public class StunRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public StunRequestEventArgs( Mobile m ) + { + m_Mobile = m; + } + } + + public class DisarmRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public DisarmRequestEventArgs( Mobile m ) + { + m_Mobile = m; + } + } + + public class HelpRequestEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public HelpRequestEventArgs( Mobile m ) + { + m_Mobile = m; + } + } + + public class ShutdownEventArgs : EventArgs + { + public ShutdownEventArgs() + { + } + } + + public class CrashedEventArgs : EventArgs + { + private Exception m_Exception; + private bool m_Close; + + public Exception Exception{ get{ return m_Exception; } } + public bool Close{ get{ return m_Close; } set{ m_Close = value; } } + + public CrashedEventArgs( Exception e ) + { + m_Exception = e; + } + } + + public class HungerChangedEventArgs : EventArgs + { + private Mobile m_Mobile; + private int m_OldValue; + + public Mobile Mobile{ get{ return m_Mobile; } } + public int OldValue{ get{ return m_OldValue; } } + + public HungerChangedEventArgs( Mobile mobile, int oldValue ) + { + m_Mobile = mobile; + m_OldValue = oldValue; + } + } + + public class MovementEventArgs : EventArgs + { + private Mobile m_Mobile; + private Direction m_Direction; + private bool m_Blocked; + + public Mobile Mobile{ get{ return m_Mobile; } } + public Direction Direction{ get{ return m_Direction; } } + public bool Blocked{ get{ return m_Blocked; } set{ m_Blocked = value; } } + + private static Queue m_Pool = new Queue(); + + public static MovementEventArgs Create( Mobile mobile, Direction dir ) + { + MovementEventArgs args; + + if ( m_Pool.Count > 0 ) + { + args = m_Pool.Dequeue(); + + args.m_Mobile = mobile; + args.m_Direction = dir; + args.m_Blocked = false; + } + else + { + args = new MovementEventArgs( mobile, dir ); + } + + return args; + } + + public MovementEventArgs( Mobile mobile, Direction dir ) + { + m_Mobile = mobile; + m_Direction = dir; + } + + public void Free() + { + m_Pool.Enqueue( this ); + } + } + + public class ServerListEventArgs : EventArgs + { + private NetState m_State; + private IAccount m_Account; + private bool m_Rejected; + private List m_Servers; + + public NetState State{ get{ return m_State; } } + public IAccount Account{ get{ return m_Account; } } + public bool Rejected{ get{ return m_Rejected; } set{ m_Rejected = value; } } + public List Servers{ get{ return m_Servers; } } + + public void AddServer( string name, IPEndPoint address ) + { + AddServer( name, 0, TimeZone.CurrentTimeZone, address ); + } + + public void AddServer( string name, int fullPercent, TimeZone tz, IPEndPoint address ) + { + m_Servers.Add( new ServerInfo( name, fullPercent, tz, address ) ); + } + + public ServerListEventArgs( NetState state, IAccount account ) + { + m_State = state; + m_Account = account; + m_Servers = new List(); + } + } + + public struct SkillNameValue + { + private SkillName m_Name; + private int m_Value; + + public SkillName Name{ get{ return m_Name; } } + public int Value{ get{ return m_Value; } } + + public SkillNameValue( SkillName name, int value ) + { + m_Name = name; + m_Value = value; + } + } + + public class CharacterCreatedEventArgs : EventArgs + { + private NetState m_State; + private IAccount m_Account; + private CityInfo m_City; + private SkillNameValue[] m_Skills; + private int m_ShirtHue, m_PantsHue; + private int m_HairID, m_HairHue; + private int m_BeardID, m_BeardHue; + private string m_Name; + private bool m_Female; + private int m_Hue; + private int m_Str, m_Dex, m_Int; + private int m_Profession; + private Mobile m_Mobile; + + private Race m_Race; + + public NetState State{ get{ return m_State; } } + public IAccount Account{ get{ return m_Account; } } + public Mobile Mobile{ get{ return m_Mobile; } set{ m_Mobile = value; } } + public string Name{ get{ return m_Name; } } + public bool Female{ get{ return m_Female; } } + public int Hue{ get{ return m_Hue; } } + public int Str{ get{ return m_Str; } } + public int Dex{ get{ return m_Dex; } } + public int Int{ get{ return m_Int; } } + public CityInfo City{ get{ return m_City; } } + public SkillNameValue[] Skills{ get{ return m_Skills; } } + public int ShirtHue{ get{ return m_ShirtHue; } } + public int PantsHue{ get{ return m_PantsHue; } } + public int HairID{ get{ return m_HairID; } } + public int HairHue{ get{ return m_HairHue; } } + public int BeardID{ get{ return m_BeardID; } } + public int BeardHue{ get{ return m_BeardHue; } } + public int Profession{ get{ return m_Profession; } set{ m_Profession = value; }} + public Race Race { get { return m_Race; } } + + public CharacterCreatedEventArgs( NetState state, IAccount a, string name, bool female, int hue, int str, int dex, int intel, CityInfo city, SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, int beardID, int beardHue, int profession, Race race ) + { + m_State = state; + m_Account = a; + m_Name = name; + m_Female = female; + m_Hue = hue; + m_Str = str; + m_Dex = dex; + m_Int = intel; + m_City = city; + m_Skills = skills; + m_ShirtHue = shirtHue; + m_PantsHue = pantsHue; + m_HairID = hairID; + m_HairHue = hairHue; + m_BeardID = beardID; + m_BeardHue = beardHue; + m_Profession = profession; + m_Race = race; + } + } + + public class OpenDoorMacroEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public OpenDoorMacroEventArgs( Mobile mobile ) + { + m_Mobile = mobile; + } + } + + public class SpeechEventArgs : EventArgs + { + private Mobile m_Mobile; + private string m_Speech; + private MessageType m_Type; + private int m_Hue; + private int[] m_Keywords; + private bool m_Handled; + private bool m_Blocked; + + public Mobile Mobile{ get{ return m_Mobile; } } + public string Speech{ get{ return m_Speech; } set{ m_Speech = value; } } + public MessageType Type{ get{ return m_Type; } } + public int Hue{ get{ return m_Hue; } } + public int[] Keywords{ get{ return m_Keywords; } } + public bool Handled{ get{ return m_Handled; } set{ m_Handled = value; } } + public bool Blocked{ get{ return m_Blocked; } set{ m_Blocked = value; } } + + public bool HasKeyword( int keyword ) + { + for ( int i = 0; i < m_Keywords.Length; ++i ) + if ( m_Keywords[i] == keyword ) + return true; + + return false; + } + + public SpeechEventArgs( Mobile mobile, string speech, MessageType type, int hue, int[] keywords ) + { + m_Mobile = mobile; + m_Speech = speech; + m_Type = type; + m_Hue = hue; + m_Keywords = keywords; + } + } + + public class LoginEventArgs : EventArgs + { + private Mobile m_Mobile; + + public Mobile Mobile{ get{ return m_Mobile; } } + + public LoginEventArgs( Mobile mobile ) + { + m_Mobile = mobile; + } + } + + public class WorldSaveEventArgs : EventArgs + { + private bool m_Msg; + + public bool Message{ get{ return m_Msg; } } + + public WorldSaveEventArgs( bool msg ) + { + m_Msg = msg; + } + } + + public class FastWalkEventArgs + { + private NetState m_State; + private bool m_Blocked; + + public FastWalkEventArgs( NetState state ) + { + m_State = state; + m_Blocked = false; + } + + public NetState NetState{ get{ return m_State; } } + public bool Blocked{ get{ return m_Blocked; } set{ m_Blocked = value; } } + } + + public static class EventSink + { + public static event CharacterCreatedEventHandler CharacterCreated; + public static event OpenDoorMacroEventHandler OpenDoorMacroUsed; + public static event SpeechEventHandler Speech; + public static event LoginEventHandler Login; + public static event ServerListEventHandler ServerList; + public static event MovementEventHandler Movement; + public static event HungerChangedEventHandler HungerChanged; + public static event CrashedEventHandler Crashed; + public static event ShutdownEventHandler Shutdown; + public static event HelpRequestEventHandler HelpRequest; + public static event DisarmRequestEventHandler DisarmRequest; + public static event StunRequestEventHandler StunRequest; + public static event OpenSpellbookRequestEventHandler OpenSpellbookRequest; + public static event CastSpellRequestEventHandler CastSpellRequest; + public static event AnimateRequestEventHandler AnimateRequest; + public static event LogoutEventHandler Logout; + public static event SocketConnectEventHandler SocketConnect; + public static event ConnectedEventHandler Connected; + public static event DisconnectedEventHandler Disconnected; + public static event RenameRequestEventHandler RenameRequest; + public static event PlayerDeathEventHandler PlayerDeath; + public static event VirtueGumpRequestEventHandler VirtueGumpRequest; + public static event VirtueItemRequestEventHandler VirtueItemRequest; + public static event VirtueMacroRequestEventHandler VirtueMacroRequest; + public static event ChatRequestEventHandler ChatRequest; + public static event AccountLoginEventHandler AccountLogin; + public static event PaperdollRequestEventHandler PaperdollRequest; + public static event ProfileRequestEventHandler ProfileRequest; + public static event ChangeProfileRequestEventHandler ChangeProfileRequest; + public static event AggressiveActionEventHandler AggressiveAction; + public static event CommandEventHandler Command; + public static event GameLoginEventHandler GameLogin; + public static event DeleteRequestEventHandler DeleteRequest; + public static event WorldLoadEventHandler WorldLoad; + public static event WorldSaveEventHandler WorldSave; + public static event SetAbilityEventHandler SetAbility; + public static event FastWalkEventHandler FastWalk; + public static event CreateGuildHandler CreateGuild; + public static event ServerStartedEventHandler ServerStarted; + public static event GuildGumpRequestHandler GuildGumpRequest; + public static event QuestGumpRequestHandler QuestGumpRequest; + public static event ClientVersionReceivedHandler ClientVersionReceived; + + public static void InvokeClientVersionReceived( ClientVersionReceivedArgs e ) + { + if( ClientVersionReceived != null ) + ClientVersionReceived( e ); + } + + public static void InvokeServerStarted() + { + if ( ServerStarted != null ) + ServerStarted(); + } + + public static BaseGuild InvokeCreateGuild( CreateGuildEventArgs e ) + { + if ( CreateGuild != null ) + return CreateGuild( e ); + else + return null; + } + + public static void InvokeSetAbility( SetAbilityEventArgs e ) + { + if ( SetAbility != null ) + SetAbility( e ); + } + + public static void InvokeGuildGumpRequest( GuildGumpRequestArgs e ) + { + if( GuildGumpRequest != null ) + GuildGumpRequest( e ); + } + + public static void InvokeQuestGumpRequest( QuestGumpRequestArgs e ) + { + if( QuestGumpRequest != null ) + QuestGumpRequest( e ); + } + + public static void InvokeFastWalk( FastWalkEventArgs e ) + { + if ( FastWalk != null ) + FastWalk( e ); + } + + public static void InvokeDeleteRequest( DeleteRequestEventArgs e ) + { + if ( DeleteRequest != null ) + DeleteRequest( e ); + } + + public static void InvokeGameLogin( GameLoginEventArgs e ) + { + if ( GameLogin != null ) + GameLogin( e ); + } + + public static void InvokeCommand( CommandEventArgs e ) + { + if ( Command != null ) + Command( e ); + } + + public static void InvokeAggressiveAction( AggressiveActionEventArgs e ) + { + if ( AggressiveAction != null ) + AggressiveAction( e ); + } + + public static void InvokeProfileRequest( ProfileRequestEventArgs e ) + { + if ( ProfileRequest != null ) + ProfileRequest( e ); + } + + public static void InvokeChangeProfileRequest( ChangeProfileRequestEventArgs e ) + { + if ( ChangeProfileRequest != null ) + ChangeProfileRequest( e ); + } + + public static void InvokePaperdollRequest( PaperdollRequestEventArgs e ) + { + if ( PaperdollRequest != null ) + PaperdollRequest( e ); + } + + public static void InvokeAccountLogin( AccountLoginEventArgs e ) + { + if ( AccountLogin != null ) + AccountLogin( e ); + } + + public static void InvokeChatRequest( ChatRequestEventArgs e ) + { + if ( ChatRequest != null ) + ChatRequest( e ); + } + + public static void InvokeVirtueItemRequest( VirtueItemRequestEventArgs e ) + { + if ( VirtueItemRequest != null ) + VirtueItemRequest( e ); + } + + public static void InvokeVirtueGumpRequest( VirtueGumpRequestEventArgs e ) + { + if ( VirtueGumpRequest != null ) + VirtueGumpRequest( e ); + } + + public static void InvokeVirtueMacroRequest( VirtueMacroRequestEventArgs e ) + { + if ( VirtueMacroRequest != null ) + VirtueMacroRequest( e ); + } + + public static void InvokePlayerDeath( PlayerDeathEventArgs e ) + { + if ( PlayerDeath != null ) + PlayerDeath( e ); + } + + public static void InvokeRenameRequest( RenameRequestEventArgs e ) + { + if ( RenameRequest != null ) + RenameRequest( e ); + } + + public static void InvokeLogout( LogoutEventArgs e ) + { + if ( Logout != null ) + Logout( e ); + } + + public static void InvokeSocketConnect( SocketConnectEventArgs e ) + { + if ( SocketConnect != null ) + SocketConnect( e ); + } + + public static void InvokeConnected( ConnectedEventArgs e ) + { + if ( Connected != null ) + Connected( e ); + } + + public static void InvokeDisconnected( DisconnectedEventArgs e ) + { + if ( Disconnected != null ) + Disconnected( e ); + } + + public static void InvokeAnimateRequest( AnimateRequestEventArgs e ) + { + if ( AnimateRequest != null ) + AnimateRequest( e ); + } + + public static void InvokeCastSpellRequest( CastSpellRequestEventArgs e ) + { + if ( CastSpellRequest != null ) + CastSpellRequest( e ); + } + + public static void InvokeOpenSpellbookRequest( OpenSpellbookRequestEventArgs e ) + { + if ( OpenSpellbookRequest != null ) + OpenSpellbookRequest( e ); + } + + public static void InvokeDisarmRequest( DisarmRequestEventArgs e ) + { + if ( DisarmRequest != null ) + DisarmRequest( e ); + } + + public static void InvokeStunRequest( StunRequestEventArgs e ) + { + if ( StunRequest != null ) + StunRequest( e ); + } + + public static void InvokeHelpRequest( HelpRequestEventArgs e ) + { + if ( HelpRequest != null ) + HelpRequest( e ); + } + + public static void InvokeShutdown( ShutdownEventArgs e ) + { + if ( Shutdown != null ) + Shutdown( e ); + } + + public static void InvokeCrashed( CrashedEventArgs e ) + { + if ( Crashed != null ) + Crashed( e ); + } + + public static void InvokeHungerChanged( HungerChangedEventArgs e ) + { + if ( HungerChanged != null ) + HungerChanged( e ); + } + + public static void InvokeMovement( MovementEventArgs e ) + { + if ( Movement != null ) + Movement( e ); + } + + public static void InvokeServerList( ServerListEventArgs e ) + { + if ( ServerList != null ) + ServerList( e ); + } + + public static void InvokeLogin( LoginEventArgs e ) + { + if ( Login != null ) + Login( e ); + } + + public static void InvokeSpeech( SpeechEventArgs e ) + { + if ( Speech != null ) + Speech( e ); + } + + public static void InvokeCharacterCreated( CharacterCreatedEventArgs e ) + { + if ( CharacterCreated != null ) + CharacterCreated( e ); + } + + public static void InvokeOpenDoorMacroUsed( OpenDoorMacroEventArgs e ) + { + if ( OpenDoorMacroUsed != null ) + OpenDoorMacroUsed( e ); + } + + public static void InvokeWorldLoad() + { + if ( WorldLoad != null ) + WorldLoad(); + } + + public static void InvokeWorldSave( WorldSaveEventArgs e ) + { + if ( WorldSave != null ) + WorldSave( e ); + } + + public static void Reset() + { + CharacterCreated = null; + OpenDoorMacroUsed = null; + Speech = null; + Login = null; + ServerList = null; + Movement = null; + HungerChanged = null; + Crashed = null; + Shutdown = null; + HelpRequest = null; + DisarmRequest = null; + StunRequest = null; + OpenSpellbookRequest = null; + CastSpellRequest = null; + AnimateRequest = null; + Logout = null; + SocketConnect = null; + Connected = null; + Disconnected = null; + RenameRequest = null; + PlayerDeath = null; + VirtueGumpRequest = null; + VirtueItemRequest = null; + VirtueMacroRequest = null; + ChatRequest = null; + AccountLogin = null; + PaperdollRequest = null; + ProfileRequest = null; + ChangeProfileRequest = null; + AggressiveAction = null; + Command = null; + GameLogin = null; + DeleteRequest = null; + WorldLoad = null; + WorldSave = null; + SetAbility = null; + GuildGumpRequest = null; + QuestGumpRequest = null; + } + } +} \ No newline at end of file diff --git a/Server/ExpansionInfo.cs b/Server/ExpansionInfo.cs new file mode 100644 index 0000000..c866a8f --- /dev/null +++ b/Server/ExpansionInfo.cs @@ -0,0 +1,199 @@ +/*************************************************************************** + * ExpansionInfo.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ExpansionInfo.cs 898 2012-08-26 23:03:36Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public enum Expansion + { + None, + T2A, + UOR, + UOTD, + LBR, + AOS, + SE, + ML, + SA, + HS + } + + [Flags] + public enum ClientFlags + { + None = 0x00000000, + Felucca = 0x00000001, + Trammel = 0x00000002, + Ilshenar = 0x00000004, + Malas = 0x00000008, + Tokuno = 0x00000010, + TerMur = 0x00000020, + Unk1 = 0x00000040, + Unk2 = 0x00000080, + UOTD = 0x00000100 + } + + [Flags] + public enum FeatureFlags + { + None = 0x00000000, + T2A = 0x00000001, + UOR = 0x00000002, + UOTD = 0x00000004, + LBR = 0x00000008, + AOS = 0x00000010, + SixthCharacterSlot = 0x00000020, + SE = 0x00000040, + ML = 0x00000080, + Unk1 = 0x00000100, + Unk2 = 0x00000200, + Unk3 = 0x00000400, + Unk4 = 0x00000800, + SeventhCharacterSlot = 0x00001000, + Unk5 = 0x00002000, + Unk6 = 0x00004000, + Unk7 = 0x00008000, + SA = 0x00010000, + HS = 0x00020000, + Gothic = 0x00040000, + Rustic = 0x00080000, + + + ExpansionNone = None, + ExpansionT2A = T2A, + ExpansionUOR = ExpansionT2A | UOR, + ExpansionUOTD = ExpansionUOR | UOTD, + ExpansionLBR = ExpansionUOTD | LBR, + ExpansionAOS = ExpansionLBR | AOS | Unk7, + ExpansionSE = ExpansionAOS | SE, + ExpansionML = ExpansionSE | ML | Unk2, + ExpansionSA = ExpansionML | SA | Gothic | Rustic, + ExpansionHS = ExpansionSA + } + + [Flags] + public enum CharacterListFlags + { + None = 0x00000000, + Unk1 = 0x00000001, + Unk2 = 0x00000002, + OneCharacterSlot = 0x00000004, + ContextMenus = 0x00000008, + SlotLimit = 0x00000010, + AOS = 0x00000020, + SixthCharacterSlot = 0x00000040, + SE = 0x00000080, + ML = 0x00000100, + Unk4 = 0x00000200, + Unk5 = 0x00000400, + Unk6 = 0x00000800, + SeventhCharacterSlot = 0x00001000, + Unk7 = 0x00002000, + + ExpansionNone = ContextMenus, // + ExpansionT2A = ContextMenus, // + ExpansionUOR = ContextMenus, // None + ExpansionUOTD = ContextMenus, // + ExpansionLBR = ContextMenus, // + ExpansionAOS = ContextMenus | AOS, + ExpansionSE = ExpansionAOS | SE, + ExpansionML = ExpansionSE | ML, + ExpansionSA = ExpansionML, + ExpansionHS = ExpansionSA + } + + public class ExpansionInfo + { + public static ExpansionInfo[] Table { get { return m_Table; } } + private static ExpansionInfo[] m_Table = new ExpansionInfo[] + { + new ExpansionInfo( 0, "None", ClientFlags.None, FeatureFlags.ExpansionNone, CharacterListFlags.ExpansionNone, 0x0000 ), + new ExpansionInfo( 1, "The Second Age", ClientFlags.Felucca, FeatureFlags.ExpansionT2A, CharacterListFlags.ExpansionT2A, 0x0000 ), + new ExpansionInfo( 2, "Renaissance", ClientFlags.Trammel, FeatureFlags.ExpansionUOR, CharacterListFlags.ExpansionUOR, 0x0000 ), + new ExpansionInfo( 3, "Third Dawn", ClientFlags.Ilshenar, FeatureFlags.ExpansionUOTD, CharacterListFlags.ExpansionUOTD, 0x0000 ), + new ExpansionInfo( 4, "Blackthorn's Revenge", ClientFlags.Ilshenar, FeatureFlags.ExpansionLBR, CharacterListFlags.ExpansionLBR, 0x0000 ), + new ExpansionInfo( 5, "Age of Shadows", ClientFlags.Malas, FeatureFlags.ExpansionAOS, CharacterListFlags.ExpansionAOS, 0x0000 ), + new ExpansionInfo( 6, "Samurai Empire", ClientFlags.Tokuno, FeatureFlags.ExpansionSE, CharacterListFlags.ExpansionSE, 0x00C0 ), // 0x20 | 0x80 + new ExpansionInfo( 7, "Mondain's Legacy", new ClientVersion( "5.0.0a" ), FeatureFlags.ExpansionML, CharacterListFlags.ExpansionML, 0x02C0 ), // 0x20 | 0x80 | 0x200 + new ExpansionInfo( 8, "Stygian Abyss", ClientFlags.TerMur, FeatureFlags.ExpansionSA, CharacterListFlags.ExpansionSA, 0xD02C0 ), // 0x20 | 0x80 | 0x200 | 0x10000 | 0x40000 | 0x80000 + new ExpansionInfo( 9, "High Seas", new ClientVersion( "7.0.9.0" ), FeatureFlags.ExpansionHS, CharacterListFlags.ExpansionHS, 0xD02C0 ) // 0x20 | 0x80 | 0x200 | 0x10000 | 0x40000 | 0x80000 + }; + + private string m_Name; + private int m_ID, m_CustomHousingFlag; + + private ClientFlags m_ClientFlags; + private FeatureFlags m_SupportedFeatures; + private CharacterListFlags m_CharListFlags; + + private ClientVersion m_RequiredClient; // Used as an alternative to the flags + + public string Name{ get{ return m_Name; } } + public int ID{ get{ return m_ID; } } + public ClientFlags ClientFlags{ get{ return m_ClientFlags; } } + public FeatureFlags SupportedFeatures{ get{ return m_SupportedFeatures; } } + public CharacterListFlags CharacterListFlags { get { return m_CharListFlags; } } + public int CustomHousingFlag { get{ return m_CustomHousingFlag; } } + public ClientVersion RequiredClient { get { return m_RequiredClient; } } + + public ExpansionInfo( int id, string name, ClientFlags clientFlags, FeatureFlags supportedFeatures, CharacterListFlags charListFlags, int customHousingFlag ) + { + m_Name = name; + m_ID = id; + m_ClientFlags = clientFlags; + m_SupportedFeatures = supportedFeatures; + m_CharListFlags = charListFlags; + m_CustomHousingFlag = customHousingFlag; + } + + public ExpansionInfo( int id, string name, ClientVersion requiredClient, FeatureFlags supportedFeatures, CharacterListFlags charListFlags, int customHousingFlag ) + { + m_Name = name; + m_ID = id; + m_SupportedFeatures = supportedFeatures; + m_CharListFlags = charListFlags; + m_CustomHousingFlag = customHousingFlag; + m_RequiredClient = requiredClient; + } + + public static ExpansionInfo GetInfo( Expansion ex ) + { + return GetInfo( (int)ex ); + } + + public static ExpansionInfo GetInfo( int ex ) + { + int v = (int)ex; + + if( v < 0 || v >= m_Table.Length ) + v = 0; + + return m_Table[v]; + } + + public static ExpansionInfo CurrentExpansion { get { return GetInfo( Core.Expansion ); } } + + public override string ToString() + { + return m_Name; + } + } +} diff --git a/Server/Geometry.cs b/Server/Geometry.cs new file mode 100644 index 0000000..09b1db6 --- /dev/null +++ b/Server/Geometry.cs @@ -0,0 +1,638 @@ +/*************************************************************************** + * Geometry.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Geometry.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + [Parsable] + public struct Point2D : IPoint2D, IComparable, IComparable + { + internal int m_X; + internal int m_Y; + + public static readonly Point2D Zero = new Point2D( 0, 0 ); + + public Point2D( int x, int y ) + { + m_X = x; + m_Y = y; + } + + public Point2D( IPoint2D p ) : this( p.X, p.Y ) + { + } + + [CommandProperty( AccessLevel.Counselor )] + public int X + { + get + { + return m_X; + } + set + { + m_X = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Y + { + get + { + return m_Y; + } + set + { + m_Y = value; + } + } + + public override string ToString() + { + return String.Format( "({0}, {1})", m_X, m_Y ); + } + + public static Point2D Parse( string value ) + { + int start = value.IndexOf( '(' ); + int end = value.IndexOf( ',', start + 1 ); + + string param1 = value.Substring( start + 1, end - (start + 1) ).Trim(); + + start = end; + end = value.IndexOf( ')', start + 1 ); + + string param2 = value.Substring( start + 1, end - (start + 1) ).Trim(); + + return new Point2D( Convert.ToInt32( param1 ), Convert.ToInt32( param2 ) ); + } + + public int CompareTo( Point2D other ) + { + int v = ( m_X.CompareTo( other.m_X ) ); + + if ( v == 0 ) + v = ( m_Y.CompareTo( other.m_Y ) ); + + return v; + } + + public int CompareTo( object other ) + { + if ( other is Point2D ) + return this.CompareTo( (Point2D) other ); + else if ( other == null ) + return -1; + + throw new ArgumentException(); + } + + public override bool Equals( object o ) + { + if ( o == null || !(o is IPoint2D) ) return false; + + IPoint2D p = (IPoint2D)o; + + return m_X == p.X && m_Y == p.Y; + } + + public override int GetHashCode() + { + return m_X ^ m_Y; + } + + public static bool operator == ( Point2D l, Point2D r ) + { + return l.m_X == r.m_X && l.m_Y == r.m_Y; + } + + public static bool operator != ( Point2D l, Point2D r ) + { + return l.m_X != r.m_X || l.m_Y != r.m_Y; + } + + public static bool operator == ( Point2D l, IPoint2D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X == r.X && l.m_Y == r.Y; + } + + public static bool operator != ( Point2D l, IPoint2D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X !=r.X || l.m_Y != r.Y; + } + + public static bool operator > ( Point2D l, Point2D r ) + { + return l.m_X > r.m_X && l.m_Y > r.m_Y; + } + + public static bool operator > ( Point2D l, Point3D r ) + { + return l.m_X > r.m_X && l.m_Y > r.m_Y; + } + + public static bool operator > ( Point2D l, IPoint2D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X > r.X && l.m_Y > r.Y; + } + + public static bool operator < ( Point2D l, Point2D r ) + { + return l.m_X < r.m_X && l.m_Y < r.m_Y; + } + + public static bool operator < ( Point2D l, Point3D r ) + { + return l.m_X < r.m_X && l.m_Y < r.m_Y; + } + + public static bool operator < ( Point2D l, IPoint2D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X < r.X && l.m_Y < r.Y; + } + + public static bool operator >= ( Point2D l, Point2D r ) + { + return l.m_X >= r.m_X && l.m_Y >= r.m_Y; + } + + public static bool operator >= ( Point2D l, Point3D r ) + { + return l.m_X >= r.m_X && l.m_Y >= r.m_Y; + } + + public static bool operator >= ( Point2D l, IPoint2D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X >= r.X && l.m_Y >= r.Y; + } + + public static bool operator <= ( Point2D l, Point2D r ) + { + return l.m_X <= r.m_X && l.m_Y <= r.m_Y; + } + + public static bool operator <= ( Point2D l, Point3D r ) + { + return l.m_X <= r.m_X && l.m_Y <= r.m_Y; + } + + public static bool operator <= ( Point2D l, IPoint2D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X <= r.X && l.m_Y <= r.Y; + } + } + + [Parsable] + public struct Point3D : IPoint3D, IComparable, IComparable + { + internal int m_X; + internal int m_Y; + internal int m_Z; + + public static readonly Point3D Zero = new Point3D( 0, 0, 0 ); + + public Point3D( int x, int y, int z ) + { + m_X = x; + m_Y = y; + m_Z = z; + } + + public Point3D( IPoint3D p ) + : this( p.X, p.Y, p.Z ) + { + } + + public Point3D( IPoint2D p, int z ) + : this( p.X, p.Y, z ) + { + } + + [CommandProperty( AccessLevel.Counselor )] + public int X + { + get + { + return m_X; + } + set + { + m_X = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Y + { + get + { + return m_Y; + } + set + { + m_Y = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Z + { + get + { + return m_Z; + } + set + { + m_Z = value; + } + } + + public override string ToString() + { + return String.Format( "({0}, {1}, {2})", m_X, m_Y, m_Z ); + } + + public override bool Equals( object o ) + { + if ( o == null || !( o is IPoint3D ) ) + return false; + + IPoint3D p = (IPoint3D) o; + + return m_X == p.X && m_Y == p.Y && m_Z == p.Z; + } + + public override int GetHashCode() + { + return m_X ^ m_Y ^ m_Z; + } + + public static Point3D Parse( string value ) + { + int start = value.IndexOf( '(' ); + int end = value.IndexOf( ',', start + 1 ); + + string param1 = value.Substring( start + 1, end - ( start + 1 ) ).Trim(); + + start = end; + end = value.IndexOf( ',', start + 1 ); + + string param2 = value.Substring( start + 1, end - ( start + 1 ) ).Trim(); + + start = end; + end = value.IndexOf( ')', start + 1 ); + + string param3 = value.Substring( start + 1, end - ( start + 1 ) ).Trim(); + + return new Point3D( Convert.ToInt32( param1 ), Convert.ToInt32( param2 ), Convert.ToInt32( param3 ) ); + } + + public static bool operator ==( Point3D l, Point3D r ) + { + return l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z; + } + + public static bool operator !=( Point3D l, Point3D r ) + { + return l.m_X != r.m_X || l.m_Y != r.m_Y || l.m_Z != r.m_Z; + } + + public static bool operator ==( Point3D l, IPoint3D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z; + } + + public static bool operator !=( Point3D l, IPoint3D r ) + { + if ( Object.ReferenceEquals( r, null ) ) + return false; + + return l.m_X != r.X || l.m_Y != r.Y || l.m_Z != r.Z; + } + + public int CompareTo( Point3D other ) + { + int v = ( m_X.CompareTo( other.m_X ) ); + + if ( v == 0 ) + { + v = ( m_Y.CompareTo( other.m_Y ) ); + + if ( v == 0 ) + v = ( m_Z.CompareTo( other.m_Z ) ); + } + + return v; + } + + public int CompareTo( object other ) + { + if ( other is Point3D ) + return this.CompareTo( (Point3D) other ); + else if ( other == null ) + return -1; + + throw new ArgumentException(); + } + } + + [NoSort] + [Parsable] + [PropertyObject] + public struct Rectangle2D + { + private Point2D m_Start; + private Point2D m_End; + + public Rectangle2D( IPoint2D start, IPoint2D end ) + { + m_Start = new Point2D( start ); + m_End = new Point2D( end ); + } + + public Rectangle2D( int x, int y, int width, int height ) + { + m_Start = new Point2D( x, y ); + m_End = new Point2D( x + width, y + height ); + } + + public void Set( int x, int y, int width, int height ) + { + m_Start = new Point2D( x, y ); + m_End = new Point2D( x + width, y + height ); + } + + public static Rectangle2D Parse( string value ) + { + int start = value.IndexOf( '(' ); + int end = value.IndexOf( ',', start + 1 ); + + string param1 = value.Substring( start + 1, end - (start + 1) ).Trim(); + + start = end; + end = value.IndexOf( ',', start + 1 ); + + string param2 = value.Substring( start + 1, end - (start + 1) ).Trim(); + + start = end; + end = value.IndexOf( ',', start + 1 ); + + string param3 = value.Substring( start + 1, end - (start + 1) ).Trim(); + + start = end; + end = value.IndexOf( ')', start + 1 ); + + string param4 = value.Substring( start + 1, end - (start + 1) ).Trim(); + + return new Rectangle2D( Convert.ToInt32( param1 ), Convert.ToInt32( param2 ), Convert.ToInt32( param3 ), Convert.ToInt32( param4 ) ); + } + + [CommandProperty( AccessLevel.Counselor )] + public Point2D Start + { + get + { + return m_Start; + } + set + { + m_Start = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public Point2D End + { + get + { + return m_End; + } + set + { + m_End = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int X + { + get + { + return m_Start.m_X; + } + set + { + m_Start.m_X = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Y + { + get + { + return m_Start.m_Y; + } + set + { + m_Start.m_Y = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Width + { + get + { + return m_End.m_X - m_Start.m_X; + } + set + { + m_End.m_X = m_Start.m_X + value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Height + { + get + { + return m_End.m_Y - m_Start.m_Y; + } + set + { + m_End.m_Y = m_Start.m_Y + value; + } + } + + public void MakeHold( Rectangle2D r ) + { + if ( r.m_Start.m_X < m_Start.m_X ) + m_Start.m_X = r.m_Start.m_X; + + if ( r.m_Start.m_Y < m_Start.m_Y ) + m_Start.m_Y = r.m_Start.m_Y; + + if ( r.m_End.m_X > m_End.m_X ) + m_End.m_X = r.m_End.m_X; + + if ( r.m_End.m_Y > m_End.m_Y ) + m_End.m_Y = r.m_End.m_Y; + } + + public bool Contains( Point3D p ) + { + return ( m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y ); + //return ( m_Start <= p && m_End > p ); + } + + public bool Contains( Point2D p ) + { + return ( m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y ); + //return ( m_Start <= p && m_End > p ); + } + + public bool Contains( IPoint2D p ) + { + return ( m_Start <= p && m_End > p ); + } + + public override string ToString() + { + return String.Format( "({0}, {1})+({2}, {3})", X, Y, Width, Height ); + } + } + + [NoSort] + [PropertyObject] + public struct Rectangle3D + { + private Point3D m_Start; + private Point3D m_End; + + public Rectangle3D( Point3D start, Point3D end ) + { + m_Start = start; + m_End = end; + } + + public Rectangle3D( int x, int y, int z, int width, int height, int depth ) + { + m_Start = new Point3D( x, y, z ); + m_End = new Point3D( x + width, y + height, z + depth ); + } + + [CommandProperty( AccessLevel.Counselor )] + public Point3D Start + { + get + { + return m_Start; + } + set + { + m_Start = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public Point3D End + { + get + { + return m_End; + } + set + { + m_End = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Width + { + get + { + return m_End.X - m_Start.X; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Height + { + get + { + return m_End.Y - m_Start.Y; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Depth + { + get + { + return m_End.Z - m_Start.Z; + } + } + + public bool Contains( Point3D p ) + { + return ( p.m_X >= m_Start.m_X ) + && ( p.m_X < m_End.m_X ) + && ( p.m_Y >= m_Start.m_Y ) + && ( p.m_Y < m_End.m_Y ) + && ( p.m_Z >= m_Start.m_Z ) + && ( p.m_Z < m_End.m_Z ); + } + + public bool Contains( IPoint3D p ) + { + return ( p.X >= m_Start.m_X ) + && ( p.X < m_End.m_X ) + && ( p.Y >= m_Start.m_Y ) + && ( p.Y < m_End.m_Y ) + && ( p.Z >= m_Start.m_Z ) + && ( p.Z < m_End.m_Z ); + } + } +} \ No newline at end of file diff --git a/Server/Guild.cs b/Server/Guild.cs new file mode 100644 index 0000000..1c42f93 --- /dev/null +++ b/Server/Guild.cs @@ -0,0 +1,145 @@ +/*************************************************************************** + * Guild.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Guild.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; + +namespace Server.Guilds +{ + public enum GuildType + { + Regular, + Chaos, + Order + } + + public abstract class BaseGuild : ISerializable + { + private int m_Id; + + protected BaseGuild( int Id )//serialization ctor + { + m_Id = Id; + m_GuildList.Add( m_Id, this ); + if ( m_Id+1 > m_NextID ) + m_NextID = m_Id + 1; + } + + protected BaseGuild() + { + m_Id = m_NextID++; + m_GuildList.Add( m_Id, this ); + } + + [CommandProperty( AccessLevel.Counselor )] + public int Id { get { return m_Id; } } + + int ISerializable.TypeReference { + get { return 0; } + } + + int ISerializable.SerialIdentity { + get { return m_Id; } + } + + public abstract void Deserialize( GenericReader reader ); + public abstract void Serialize( GenericWriter writer ); + + public abstract string Abbreviation { get; set; } + public abstract string Name { get; set; } + public abstract GuildType Type { get; set; } + public abstract bool Disbanded{ get; } + public abstract void OnDelete( Mobile mob ); + + private static Dictionary m_GuildList = new Dictionary(); + private static int m_NextID = 1; + + public static Dictionary List + { + get + { + return m_GuildList; + } + } + + public static BaseGuild Find( int id ) + { + BaseGuild g; + + m_GuildList.TryGetValue( id, out g ); + + return g; + } + + public static BaseGuild FindByName( string name ) + { + foreach ( BaseGuild g in m_GuildList.Values ) + { + if ( g.Name == name ) + return g; + } + + return null; + } + + public static BaseGuild FindByAbbrev( string abbr ) + { + foreach ( BaseGuild g in m_GuildList.Values ) + { + if ( g.Abbreviation == abbr ) + return g; + } + + return null; + } + + public static List Search( string find ) + { + string[] words = find.ToLower().Split( ' ' ); + List results = new List(); + + foreach ( BaseGuild g in m_GuildList.Values ) + { + bool match = true; + string name = g.Name.ToLower(); + for (int i=0;i m_Entries; + private List m_Strings; + + internal int m_TextEntries, m_Switches; + + private static int m_NextSerial = 1; + + private int m_Serial; + private int m_TypeID; + private int m_X, m_Y; + + private bool m_Dragable = true; + private bool m_Closable = true; + private bool m_Resizable = true; + private bool m_Disposable = true; + + public static int GetTypeID( Type type ) + { + return type.FullName.GetHashCode(); + } + + public Gump( int x, int y ) + { + do + { + m_Serial = m_NextSerial++; + } while ( m_Serial == 0 ); // standard client apparently doesn't send a gump response packet if serial == 0 + + m_X = x; + m_Y = y; + + m_TypeID = GetTypeID( this.GetType() ); + + m_Entries = new List(); + m_Strings = new List(); + } + + public void Invalidate() + { + //if ( m_Strings.Count > 0 ) + // m_Strings.Clear(); + } + + public int TypeID + { + get + { + return m_TypeID; + } + } + + public List Entries + { + get{ return m_Entries; } + } + + public int Serial + { + get + { + return m_Serial; + } + set + { + if ( m_Serial != value ) + { + m_Serial = value; + Invalidate(); + } + } + } + + public int X + { + get + { + return m_X; + } + set + { + if ( m_X != value ) + { + m_X = value; + Invalidate(); + } + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + if ( m_Y != value ) + { + m_Y = value; + Invalidate(); + } + } + } + + public bool Disposable + { + get + { + return m_Disposable; + } + set + { + if ( m_Disposable != value ) + { + m_Disposable = value; + Invalidate(); + } + } + } + + public bool Resizable + { + get + { + return m_Resizable; + } + set + { + if ( m_Resizable != value ) + { + m_Resizable = value; + Invalidate(); + } + } + } + + public bool Dragable + { + get + { + return m_Dragable; + } + set + { + if ( m_Dragable != value ) + { + m_Dragable = value; + Invalidate(); + } + } + } + + public bool Closable + { + get + { + return m_Closable; + } + set + { + if ( m_Closable != value ) + { + m_Closable = value; + Invalidate(); + } + } + } + + public void AddPage( int page ) + { + Add( new GumpPage( page ) ); + } + + public void AddAlphaRegion( int x, int y, int width, int height ) + { + Add( new GumpAlphaRegion( x, y, width, height ) ); + } + + public void AddBackground( int x, int y, int width, int height, int gumpID ) + { + Add( new GumpBackground( x, y, width, height, gumpID ) ); + } + + public void AddButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param ) + { + Add( new GumpButton( x, y, normalID, pressedID, buttonID, type, param ) ); + } + + public void AddCheck( int x, int y, int inactiveID, int activeID, bool initialState, int switchID ) + { + Add( new GumpCheck( x, y, inactiveID, activeID, initialState, switchID ) ); + } + + public void AddGroup( int group ) + { + Add( new GumpGroup( group ) ); + } + + public void AddTooltip( int number ) + { + Add( new GumpTooltip( number ) ); + } + + public void AddHtml( int x, int y, int width, int height, string text, bool background, bool scrollbar ) + { + Add( new GumpHtml( x, y, width, height, text, background, scrollbar ) ); + } + + public void AddHtmlLocalized( int x, int y, int width, int height, int number, bool background, bool scrollbar ) + { + Add( new GumpHtmlLocalized( x, y, width, height, number, background, scrollbar ) ); + } + + public void AddHtmlLocalized( int x, int y, int width, int height, int number, int color, bool background, bool scrollbar ) + { + Add( new GumpHtmlLocalized( x, y, width, height, number, color, background, scrollbar ) ); + } + + public void AddHtmlLocalized( int x, int y, int width, int height, int number, string args, int color, bool background, bool scrollbar ) + { + Add( new GumpHtmlLocalized( x, y, width, height, number, args, color, background, scrollbar ) ); + } + + public void AddImage( int x, int y, int gumpID ) + { + Add( new GumpImage( x, y, gumpID ) ); + } + + public void AddImage( int x, int y, int gumpID, int hue ) + { + Add( new GumpImage( x, y, gumpID, hue ) ); + } + + public void AddImageTiled( int x, int y, int width, int height, int gumpID ) + { + Add( new GumpImageTiled( x, y, width, height, gumpID ) ); + } + + public void AddImageTiledButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height ) + { + Add( new GumpImageTileButton( x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height ) ); + } + public void AddImageTiledButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height, int localizedTooltip ) + { + Add( new GumpImageTileButton( x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height, localizedTooltip ) ); + } + + public void AddItem( int x, int y, int itemID ) + { + Add( new GumpItem( x, y, itemID ) ); + } + + public void AddItem( int x, int y, int itemID, int hue ) + { + Add( new GumpItem( x, y, itemID, hue ) ); + } + + public void AddLabel( int x, int y, int hue, string text ) + { + Add( new GumpLabel( x, y, hue, text ) ); + } + + public void AddLabelCropped( int x, int y, int width, int height, int hue, string text ) + { + Add( new GumpLabelCropped( x, y, width, height, hue, text ) ); + } + + public void AddRadio( int x, int y, int inactiveID, int activeID, bool initialState, int switchID ) + { + Add( new GumpRadio( x, y, inactiveID, activeID, initialState, switchID ) ); + } + + public void AddTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText ) + { + Add( new GumpTextEntry( x, y, width, height, hue, entryID, initialText ) ); + } + + public void AddTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText, int size ) { + Add( new GumpTextEntryLimited( x, y, width, height, hue, entryID, initialText, size ) ); + } + + public void AddItemProperty(int serial) + { + Add(new GumpItemProperty(serial)); + } + + public void Add( GumpEntry g ) + { + if ( g.Parent != this ) + { + g.Parent = this; + } + else if ( !m_Entries.Contains( g ) ) + { + Invalidate(); + m_Entries.Add( g ); + } + } + + public void Remove( GumpEntry g ) + { + Invalidate(); + m_Entries.Remove( g ); + g.Parent = null; + } + + public int Intern( string value ) + { + int indexOf = m_Strings.IndexOf( value ); + + if ( indexOf >= 0 ) + { + return indexOf; + } + else + { + Invalidate(); + m_Strings.Add( value ); + return m_Strings.Count - 1; + } + } + + public void SendTo( NetState state ) + { + state.AddGump( this ); + state.Send( Compile( state ) ); + } + + public static byte[] StringToBuffer( string str ) + { + return Encoding.ASCII.GetBytes( str ); + } + + private static byte[] m_BeginLayout = StringToBuffer( "{ " ); + private static byte[] m_EndLayout = StringToBuffer( " }" ); + + private static byte[] m_NoMove = StringToBuffer( "{ nomove }" ); + private static byte[] m_NoClose = StringToBuffer( "{ noclose }" ); + private static byte[] m_NoDispose = StringToBuffer( "{ nodispose }" ); + private static byte[] m_NoResize = StringToBuffer( "{ noresize }" ); + + private Packet Compile() + { + return Compile( null ); + } + + private Packet Compile( NetState ns ) + { + IGumpWriter disp; + + if ( ns != null && ns.Unpack ) + disp = new DisplayGumpPacked( this ); + else + disp = new DisplayGumpFast( this ); + + if ( !m_Dragable ) + disp.AppendLayout( m_NoMove ); + + if ( !m_Closable ) + disp.AppendLayout( m_NoClose ); + + if ( !m_Disposable ) + disp.AppendLayout( m_NoDispose ); + + if ( !m_Resizable ) + disp.AppendLayout( m_NoResize ); + + int count = m_Entries.Count; + GumpEntry e; + + for ( int i = 0; i < count; ++i ) + { + e = m_Entries[i]; + + disp.AppendLayout( m_BeginLayout ); + e.AppendTo( disp ); + disp.AppendLayout( m_EndLayout ); + } + + disp.WriteStrings( m_Strings ); + + disp.Flush(); + + m_TextEntries = disp.TextEntries; + m_Switches = disp.Switches; + + return disp as Packet; + } + + public virtual void OnResponse( NetState sender, RelayInfo info ) + { + } + + public virtual void OnServerClose( NetState owner ) { + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpAlphaRegion.cs b/Server/Gumps/GumpAlphaRegion.cs new file mode 100644 index 0000000..0946599 --- /dev/null +++ b/Server/Gumps/GumpAlphaRegion.cs @@ -0,0 +1,103 @@ +/*************************************************************************** + * GumpAlphaRegion.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpAlphaRegion.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpAlphaRegion : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public GumpAlphaRegion( int x, int y, int width, int height ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + } + + public override string Compile() + { + return String.Format( "{{ checkertrans {0} {1} {2} {3} }}", m_X, m_Y, m_Width, m_Height ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "checkertrans" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpBackground.cs b/Server/Gumps/GumpBackground.cs new file mode 100644 index 0000000..75d24d7 --- /dev/null +++ b/Server/Gumps/GumpBackground.cs @@ -0,0 +1,118 @@ +/*************************************************************************** + * GumpBackground.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpBackground.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpBackground : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + private int m_GumpID; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public int GumpID + { + get + { + return m_GumpID; + } + set + { + Delta( ref m_GumpID, value ); + } + } + + public GumpBackground( int x, int y, int width, int height, int gumpID ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_GumpID = gumpID; + } + + public override string Compile() + { + return String.Format( "{{ resizepic {0} {1} {2} {3} {4} }}", m_X, m_Y, m_GumpID, m_Width, m_Height ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "resizepic" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_GumpID ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpButton.cs b/Server/Gumps/GumpButton.cs new file mode 100644 index 0000000..0a5806d --- /dev/null +++ b/Server/Gumps/GumpButton.cs @@ -0,0 +1,164 @@ +/*************************************************************************** + * GumpButton.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpButton.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public enum GumpButtonType + { + Page = 0, + Reply = 1 + } + + public class GumpButton : GumpEntry + { + private int m_X, m_Y; + private int m_ID1, m_ID2; + private int m_ButtonID; + private GumpButtonType m_Type; + private int m_Param; + + public GumpButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param ) + { + m_X = x; + m_Y = y; + m_ID1 = normalID; + m_ID2 = pressedID; + m_ButtonID = buttonID; + m_Type = type; + m_Param = param; + } + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int NormalID + { + get + { + return m_ID1; + } + set + { + Delta( ref m_ID1, value ); + } + } + + public int PressedID + { + get + { + return m_ID2; + } + set + { + Delta( ref m_ID2, value ); + } + } + + public int ButtonID + { + get + { + return m_ButtonID; + } + set + { + Delta( ref m_ButtonID, value ); + } + } + + public GumpButtonType Type + { + get + { + return m_Type; + } + set + { + if ( m_Type != value ) + { + m_Type = value; + + Gump parent = Parent; + + if ( parent != null ) + { + parent.Invalidate(); + } + } + } + } + + public int Param + { + get + { + return m_Param; + } + set + { + Delta( ref m_Param, value ); + } + } + + public override string Compile() + { + return String.Format( "{{ button {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_ID1, m_ID2, (int)m_Type, m_Param, m_ButtonID ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "button" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_ID1 ); + disp.AppendLayout( m_ID2 ); + disp.AppendLayout( (int)m_Type ); + disp.AppendLayout( m_Param ); + disp.AppendLayout( m_ButtonID ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpCheck.cs b/Server/Gumps/GumpCheck.cs new file mode 100644 index 0000000..07dd9fb --- /dev/null +++ b/Server/Gumps/GumpCheck.cs @@ -0,0 +1,135 @@ +/*************************************************************************** + * GumpCheck.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpCheck.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpCheck : GumpEntry + { + private int m_X, m_Y; + private int m_ID1, m_ID2; + private bool m_InitialState; + private int m_SwitchID; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int InactiveID + { + get + { + return m_ID1; + } + set + { + Delta( ref m_ID1, value ); + } + } + + public int ActiveID + { + get + { + return m_ID2; + } + set + { + Delta( ref m_ID2, value ); + } + } + + public bool InitialState + { + get + { + return m_InitialState; + } + set + { + Delta( ref m_InitialState, value ); + } + } + + public int SwitchID + { + get + { + return m_SwitchID; + } + set + { + Delta( ref m_SwitchID, value ); + } + } + + public GumpCheck( int x, int y, int inactiveID, int activeID, bool initialState, int switchID ) + { + m_X = x; + m_Y = y; + m_ID1 = inactiveID; + m_ID2 = activeID; + m_InitialState = initialState; + m_SwitchID = switchID; + } + + public override string Compile() + { + return String.Format( "{{ checkbox {0} {1} {2} {3} {4} {5} }}", m_X, m_Y, m_ID1, m_ID2, m_InitialState ? 1 : 0, m_SwitchID ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "checkbox" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_ID1 ); + disp.AppendLayout( m_ID2 ); + disp.AppendLayout( m_InitialState ); + disp.AppendLayout( m_SwitchID ); + + disp.Switches++; + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpEntry.cs b/Server/Gumps/GumpEntry.cs new file mode 100644 index 0000000..62a1332 --- /dev/null +++ b/Server/Gumps/GumpEntry.cs @@ -0,0 +1,98 @@ +/*************************************************************************** + * GumpEntry.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpEntry.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public abstract class GumpEntry + { + private Gump m_Parent; + + protected GumpEntry() + { + } + + protected void Delta( ref int var, int val ) + { + if ( var != val ) + { + var = val; + + if ( m_Parent != null ) + { + m_Parent.Invalidate(); + } + } + } + + protected void Delta( ref bool var, bool val ) + { + if ( var != val ) + { + var = val; + + if ( m_Parent != null ) + { + m_Parent.Invalidate(); + } + } + } + + protected void Delta( ref string var, string val ) + { + if ( var != val ) + { + var = val; + + if ( m_Parent != null ) + { + m_Parent.Invalidate(); + } + } + } + + public Gump Parent + { + get + { + return m_Parent; + } + set + { + if ( m_Parent != value ) + { + if ( m_Parent != null ) + { + m_Parent.Remove( this ); + } + + m_Parent = value; + + m_Parent.Add( this ); + } + } + } + + public abstract string Compile(); + public abstract void AppendTo( IGumpWriter disp ); + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpGroup.cs b/Server/Gumps/GumpGroup.cs new file mode 100644 index 0000000..d27339d --- /dev/null +++ b/Server/Gumps/GumpGroup.cs @@ -0,0 +1,60 @@ +/*************************************************************************** + * GumpGroup.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpGroup.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpGroup : GumpEntry + { + private int m_Group; + + public GumpGroup( int group ) + { + m_Group = group; + } + + public int Group + { + get + { + return m_Group; + } + set + { + Delta( ref m_Group, value ); + } + } + + public override string Compile() + { + return String.Format( "{{ group {0} }}", m_Group ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "group" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_Group ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpHtml.cs b/Server/Gumps/GumpHtml.cs new file mode 100644 index 0000000..203126e --- /dev/null +++ b/Server/Gumps/GumpHtml.cs @@ -0,0 +1,147 @@ +/*************************************************************************** + * GumpHtml.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpHtml.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpHtml : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + private string m_Text; + private bool m_Background, m_Scrollbar; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public string Text + { + get + { + return m_Text; + } + set + { + Delta( ref m_Text, value ); + } + } + + public bool Background + { + get + { + return m_Background; + } + set + { + Delta( ref m_Background, value ); + } + } + + public bool Scrollbar + { + get + { + return m_Scrollbar; + } + set + { + Delta( ref m_Scrollbar, value ); + } + } + + public GumpHtml( int x, int y, int width, int height, string text, bool background, bool scrollbar ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Text = text; + m_Background = background; + m_Scrollbar = scrollbar; + } + + public override string Compile() + { + return String.Format( "{{ htmlgump {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_Width, m_Height, Parent.Intern( m_Text ), m_Background ? 1 : 0, m_Scrollbar ? 1 : 0 ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "htmlgump" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( Parent.Intern( m_Text ) ); + disp.AppendLayout( m_Background ); + disp.AppendLayout( m_Scrollbar ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpHtmlLocalized.cs b/Server/Gumps/GumpHtmlLocalized.cs new file mode 100644 index 0000000..294cdd7 --- /dev/null +++ b/Server/Gumps/GumpHtmlLocalized.cs @@ -0,0 +1,287 @@ +/*************************************************************************** + * GumpHtmlLocalized.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpHtmlLocalized.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public enum GumpHtmlLocalizedType + { + Plain, + Color, + Args + } + + public class GumpHtmlLocalized : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + private int m_Number; + private string m_Args; + private int m_Color; + private bool m_Background, m_Scrollbar; + + private GumpHtmlLocalizedType m_Type; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public int Number + { + get + { + return m_Number; + } + set + { + Delta( ref m_Number, value ); + } + } + + public string Args + { + get + { + return m_Args; + } + set + { + Delta( ref m_Args, value ); + } + } + + public int Color + { + get + { + return m_Color; + } + set + { + Delta( ref m_Color, value ); + } + } + + public bool Background + { + get + { + return m_Background; + } + set + { + Delta( ref m_Background, value ); + } + } + + public bool Scrollbar + { + get + { + return m_Scrollbar; + } + set + { + Delta( ref m_Scrollbar, value ); + } + } + + public GumpHtmlLocalizedType Type + { + get + { + return m_Type; + } + set + { + if ( m_Type != value ) + { + m_Type = value; + + if ( Parent != null ) + Parent.Invalidate(); + } + } + } + + public GumpHtmlLocalized( int x, int y, int width, int height, int number, bool background, bool scrollbar ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Number = number; + m_Background = background; + m_Scrollbar = scrollbar; + + m_Type = GumpHtmlLocalizedType.Plain; + } + + public GumpHtmlLocalized( int x, int y, int width, int height, int number, int color, bool background, bool scrollbar ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Number = number; + m_Color = color; + m_Background = background; + m_Scrollbar = scrollbar; + + m_Type = GumpHtmlLocalizedType.Color; + } + + public GumpHtmlLocalized( int x, int y, int width, int height, int number, string args, int color, bool background, bool scrollbar ) + { + // Are multiple arguments unsupported? And what about non ASCII arguments? + + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Number = number; + m_Args = args; + m_Color = color; + m_Background = background; + m_Scrollbar = scrollbar; + + m_Type = GumpHtmlLocalizedType.Args; + } + + public override string Compile() + { + switch ( m_Type ) + { + case GumpHtmlLocalizedType.Plain: + return String.Format( "{{ xmfhtmlgump {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_Width, m_Height, m_Number, m_Background ? 1 : 0, m_Scrollbar ? 1 : 0 ); + + case GumpHtmlLocalizedType.Color: + return String.Format( "{{ xmfhtmlgumpcolor {0} {1} {2} {3} {4} {5} {6} {7} }}", m_X, m_Y, m_Width, m_Height, m_Number, m_Background ? 1 : 0, m_Scrollbar ? 1 : 0, m_Color ); + + default: // GumpHtmlLocalizedType.Args + return String.Format( "{{ xmfhtmltok {0} {1} {2} {3} {4} {5} {6} {7} @{8}@ }}", m_X, m_Y, m_Width, m_Height, m_Background ? 1 : 0, m_Scrollbar ? 1 : 0, m_Color, m_Number, m_Args ); + } + } + + private static byte[] m_LayoutNamePlain = Gump.StringToBuffer( "xmfhtmlgump" ); + private static byte[] m_LayoutNameColor = Gump.StringToBuffer( "xmfhtmlgumpcolor" ); + private static byte[] m_LayoutNameArgs = Gump.StringToBuffer( "xmfhtmltok" ); + + public override void AppendTo( IGumpWriter disp ) + { + switch ( m_Type ) + { + case GumpHtmlLocalizedType.Plain: + { + disp.AppendLayout( m_LayoutNamePlain ); + + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_Number ); + disp.AppendLayout( m_Background ); + disp.AppendLayout( m_Scrollbar ); + + break; + } + + case GumpHtmlLocalizedType.Color: + { + disp.AppendLayout( m_LayoutNameColor ); + + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_Number ); + disp.AppendLayout( m_Background ); + disp.AppendLayout( m_Scrollbar ); + disp.AppendLayout( m_Color ); + + break; + } + + case GumpHtmlLocalizedType.Args: + { + disp.AppendLayout( m_LayoutNameArgs ); + + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_Background ); + disp.AppendLayout( m_Scrollbar ); + disp.AppendLayout( m_Color ); + disp.AppendLayout( m_Number ); + disp.AppendLayout( m_Args ); + + break; + } + } + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpImage.cs b/Server/Gumps/GumpImage.cs new file mode 100644 index 0000000..e08ec37 --- /dev/null +++ b/Server/Gumps/GumpImage.cs @@ -0,0 +1,117 @@ +/*************************************************************************** + * GumpImage.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpImage.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpImage : GumpEntry + { + private int m_X, m_Y; + private int m_GumpID; + private int m_Hue; + + public GumpImage( int x, int y, int gumpID ) : this( x, y, gumpID, 0 ) + { + } + + public GumpImage( int x, int y, int gumpID, int hue ) + { + m_X = x; + m_Y = y; + m_GumpID = gumpID; + m_Hue = hue; + } + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int GumpID + { + get + { + return m_GumpID; + } + set + { + Delta( ref m_GumpID, value ); + } + } + + public int Hue + { + get + { + return m_Hue; + } + set + { + Delta( ref m_Hue, value ); + } + } + + public override string Compile() + { + if ( m_Hue == 0 ) + return String.Format( "{{ gumppic {0} {1} {2} }}", m_X, m_Y, m_GumpID ); + else + return String.Format( "{{ gumppic {0} {1} {2} hue={3} }}", m_X, m_Y, m_GumpID, m_Hue ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "gumppic" ); + private static byte[] m_HueEquals = Gump.StringToBuffer( " hue=" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_GumpID ); + + if ( m_Hue != 0 ) + { + disp.AppendLayout( m_HueEquals ); + disp.AppendLayoutNS( m_Hue ); + } + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpImageTileButton.cs b/Server/Gumps/GumpImageTileButton.cs new file mode 100644 index 0000000..b77ab91 --- /dev/null +++ b/Server/Gumps/GumpImageTileButton.cs @@ -0,0 +1,251 @@ +/*************************************************************************** + * GumpImageTileButton.cs + * ------------------- + * begin : April 26, 2005 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpImageTileButton.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpImageTileButton : GumpEntry + { + //Note, on OSI, The tooltip supports ONLY clilocs as far as I can figure out, and the tooltip ONLY works after the buttonTileArt (as far as I can tell from testing) + private int m_X, m_Y; + private int m_ID1, m_ID2; + private int m_ButtonID; + private GumpButtonType m_Type; + private int m_Param; + + private int m_ItemID; + private int m_Hue; + private int m_Width; + private int m_Height; + + private int m_LocalizedTooltip; + + public GumpImageTileButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height ) : this(x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height, -1 ) + { + } + public GumpImageTileButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height, int localizedTooltip ) + { + m_X = x; + m_Y = y; + m_ID1 = normalID; + m_ID2 = pressedID; + m_ButtonID = buttonID; + m_Type = type; + m_Param = param; + + m_ItemID = itemID; + m_Hue = hue; + m_Width = width; + m_Height = height; + + m_LocalizedTooltip = localizedTooltip; + } + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int NormalID + { + get + { + return m_ID1; + } + set + { + Delta( ref m_ID1, value ); + } + } + + public int PressedID + { + get + { + return m_ID2; + } + set + { + Delta( ref m_ID2, value ); + } + } + + public int ButtonID + { + get + { + return m_ButtonID; + } + set + { + Delta( ref m_ButtonID, value ); + } + } + + public GumpButtonType Type + { + get + { + return m_Type; + } + set + { + if( m_Type != value ) + { + m_Type = value; + + Gump parent = Parent; + + if( parent != null ) + { + parent.Invalidate(); + } + } + } + } + + public int Param + { + get + { + return m_Param; + } + set + { + Delta( ref m_Param, value ); + } + } + + public int ItemID + { + get + { + return m_ItemID; + } + set + { + Delta( ref m_ItemID, value ); + } + } + + public int Hue + { + get + { + return m_Hue; + } + set + { + Delta( ref m_Hue, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public int LocalizedTooltip + { + get + { + return m_LocalizedTooltip; + } + set + { + m_LocalizedTooltip = value; + } + } + + public override string Compile() + { + if( m_LocalizedTooltip > 0 ) + return String.Format( "{{ buttontileart {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} }}{{ tooltip {11} }}", m_X, m_Y, m_ID1, m_ID2, (int)m_Type, m_Param, m_ButtonID, m_ItemID, m_Hue, m_Width, m_Height, m_LocalizedTooltip ); + else + return String.Format( "{{ buttontileart {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} }}", m_X, m_Y, m_ID1, m_ID2, (int)m_Type, m_Param, m_ButtonID, m_ItemID, m_Hue, m_Width, m_Height ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "buttontileart" ); + private static byte[] m_LayoutTooltip = Gump.StringToBuffer( " }{ tooltip" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_ID1 ); + disp.AppendLayout( m_ID2 ); + disp.AppendLayout( (int)m_Type ); + disp.AppendLayout( m_Param ); + disp.AppendLayout( m_ButtonID ); + + disp.AppendLayout( m_ItemID ); + disp.AppendLayout( m_Hue ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + + if( m_LocalizedTooltip > 0 ) + { + disp.AppendLayout( m_LayoutTooltip ); + disp.AppendLayout( m_LocalizedTooltip ); + } + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpImageTiled.cs b/Server/Gumps/GumpImageTiled.cs new file mode 100644 index 0000000..9c5d3da --- /dev/null +++ b/Server/Gumps/GumpImageTiled.cs @@ -0,0 +1,118 @@ +/*************************************************************************** + * GumpImageTiled.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpImageTiled.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpImageTiled : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + private int m_GumpID; + + public GumpImageTiled( int x, int y, int width, int height, int gumpID ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_GumpID = gumpID; + } + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public int GumpID + { + get + { + return m_GumpID; + } + set + { + Delta( ref m_GumpID, value ); + } + } + + public override string Compile() + { + return String.Format( "{{ gumppictiled {0} {1} {2} {3} {4} }}", m_X, m_Y, m_Width, m_Height, m_GumpID ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "gumppictiled" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_GumpID ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpItem.cs b/Server/Gumps/GumpItem.cs new file mode 100644 index 0000000..e49a2e6 --- /dev/null +++ b/Server/Gumps/GumpItem.cs @@ -0,0 +1,114 @@ +/*************************************************************************** + * GumpItem.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpItem.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpItem : GumpEntry + { + private int m_X, m_Y; + private int m_ItemID; + private int m_Hue; + + public GumpItem( int x, int y, int itemID ) : this( x, y, itemID, 0 ) + { + } + + public GumpItem( int x, int y, int itemID, int hue ) + { + m_X = x; + m_Y = y; + m_ItemID = itemID; + m_Hue = hue; + } + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int ItemID + { + get + { + return m_ItemID; + } + set + { + Delta( ref m_ItemID, value ); + } + } + + public int Hue + { + get + { + return m_Hue; + } + set + { + Delta( ref m_Hue, value ); + } + } + + public override string Compile() + { + if ( m_Hue == 0 ) + return String.Format( "{{ tilepic {0} {1} {2} }}", m_X, m_Y, m_ItemID ); + else + return String.Format( "{{ tilepichue {0} {1} {2} {3} }}", m_X, m_Y, m_ItemID, m_Hue ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "tilepic" ); + private static byte[] m_LayoutNameHue = Gump.StringToBuffer( "tilepichue" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_Hue == 0 ? m_LayoutName : m_LayoutNameHue ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_ItemID ); + + if ( m_Hue != 0 ) + disp.AppendLayout( m_Hue ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpItemProperty.cs b/Server/Gumps/GumpItemProperty.cs new file mode 100644 index 0000000..ed97f0c --- /dev/null +++ b/Server/Gumps/GumpItemProperty.cs @@ -0,0 +1,60 @@ +/*************************************************************************** + * GumpItemProperty.cs + * ------------------- + * begin : May 26, 2013 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpItemProperty.cs 1065 2013-06-02 13:12:09Z eos@runuo.com $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpItemProperty : GumpEntry + { + private int m_Serial; + + public GumpItemProperty(int serial) + { + m_Serial = serial; + } + + public int Serial + { + get + { + return m_Serial; + } + set + { + Delta(ref m_Serial, value); + } + } + + public override string Compile() + { + return String.Format("{{ itemproperty {0} }}", m_Serial); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer("itemproperty"); + + public override void AppendTo(IGumpWriter disp) + { + disp.AppendLayout(m_LayoutName); + disp.AppendLayout(m_Serial); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpLabel.cs b/Server/Gumps/GumpLabel.cs new file mode 100644 index 0000000..18bf4b5 --- /dev/null +++ b/Server/Gumps/GumpLabel.cs @@ -0,0 +1,104 @@ +/*************************************************************************** + * GumpLabel.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpLabel.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpLabel : GumpEntry + { + private int m_X, m_Y; + private int m_Hue; + private string m_Text; + + public GumpLabel( int x, int y, int hue, string text ) + { + m_X = x; + m_Y = y; + m_Hue = hue; + m_Text = text; + } + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Hue + { + get + { + return m_Hue; + } + set + { + Delta( ref m_Hue, value ); + } + } + + public string Text + { + get + { + return m_Text; + } + set + { + Delta( ref m_Text, value ); + } + } + + public override string Compile() + { + return String.Format( "{{ text {0} {1} {2} {3} }}", m_X, m_Y, m_Hue, Parent.Intern( m_Text ) ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "text" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Hue ); + disp.AppendLayout( Parent.Intern( m_Text ) ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpLabelCropped.cs b/Server/Gumps/GumpLabelCropped.cs new file mode 100644 index 0000000..24c6d5a --- /dev/null +++ b/Server/Gumps/GumpLabelCropped.cs @@ -0,0 +1,133 @@ +/*************************************************************************** + * GumpLabelCropped.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpLabelCropped.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpLabelCropped : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + private int m_Hue; + private string m_Text; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public int Hue + { + get + { + return m_Hue; + } + set + { + Delta( ref m_Hue, value ); + } + } + + public string Text + { + get + { + return m_Text; + } + set + { + Delta( ref m_Text, value ); + } + } + + public GumpLabelCropped( int x, int y, int width, int height, int hue, string text ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Hue = hue; + m_Text = text; + } + + public override string Compile() + { + return String.Format( "{{ croppedtext {0} {1} {2} {3} {4} {5} }}", m_X, m_Y, m_Width, m_Height, m_Hue, Parent.Intern( m_Text ) ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "croppedtext" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_Hue ); + disp.AppendLayout( Parent.Intern( m_Text ) ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpPage.cs b/Server/Gumps/GumpPage.cs new file mode 100644 index 0000000..829f00a --- /dev/null +++ b/Server/Gumps/GumpPage.cs @@ -0,0 +1,60 @@ +/*************************************************************************** + * GumpPage.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpPage.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpPage : GumpEntry + { + private int m_Page; + + public GumpPage( int page ) + { + m_Page = page; + } + + public int Page + { + get + { + return m_Page; + } + set + { + Delta( ref m_Page, value ); + } + } + + public override string Compile() + { + return String.Format( "{{ page {0} }}", m_Page ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "page" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_Page ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpRadio.cs b/Server/Gumps/GumpRadio.cs new file mode 100644 index 0000000..51e2a9d --- /dev/null +++ b/Server/Gumps/GumpRadio.cs @@ -0,0 +1,135 @@ +/*************************************************************************** + * GumpRadio.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpRadio.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpRadio : GumpEntry + { + private int m_X, m_Y; + private int m_ID1, m_ID2; + private bool m_InitialState; + private int m_SwitchID; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int InactiveID + { + get + { + return m_ID1; + } + set + { + Delta( ref m_ID1, value ); + } + } + + public int ActiveID + { + get + { + return m_ID2; + } + set + { + Delta( ref m_ID2, value ); + } + } + + public bool InitialState + { + get + { + return m_InitialState; + } + set + { + Delta( ref m_InitialState, value ); + } + } + + public int SwitchID + { + get + { + return m_SwitchID; + } + set + { + Delta( ref m_SwitchID, value ); + } + } + + public GumpRadio( int x, int y, int inactiveID, int activeID, bool initialState, int switchID ) + { + m_X = x; + m_Y = y; + m_ID1 = inactiveID; + m_ID2 = activeID; + m_InitialState = initialState; + m_SwitchID = switchID; + } + + public override string Compile() + { + return String.Format( "{{ radio {0} {1} {2} {3} {4} {5} }}", m_X, m_Y, m_ID1, m_ID2, m_InitialState ? 1 : 0, m_SwitchID ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "radio" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_ID1 ); + disp.AppendLayout( m_ID2 ); + disp.AppendLayout( m_InitialState ); + disp.AppendLayout( m_SwitchID ); + + disp.Switches++; + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpTextEntry.cs b/Server/Gumps/GumpTextEntry.cs new file mode 100644 index 0000000..0b94606 --- /dev/null +++ b/Server/Gumps/GumpTextEntry.cs @@ -0,0 +1,150 @@ +/*************************************************************************** + * GumpTextEntry.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpTextEntry.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpTextEntry : GumpEntry + { + private int m_X, m_Y; + private int m_Width, m_Height; + private int m_Hue; + private int m_EntryID; + private string m_InitialText; + + public int X + { + get + { + return m_X; + } + set + { + Delta( ref m_X, value ); + } + } + + public int Y + { + get + { + return m_Y; + } + set + { + Delta( ref m_Y, value ); + } + } + + public int Width + { + get + { + return m_Width; + } + set + { + Delta( ref m_Width, value ); + } + } + + public int Height + { + get + { + return m_Height; + } + set + { + Delta( ref m_Height, value ); + } + } + + public int Hue + { + get + { + return m_Hue; + } + set + { + Delta( ref m_Hue, value ); + } + } + + public int EntryID + { + get + { + return m_EntryID; + } + set + { + Delta( ref m_EntryID, value ); + } + } + + public string InitialText + { + get + { + return m_InitialText; + } + set + { + Delta( ref m_InitialText, value ); + } + } + + public GumpTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText ) + { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Hue = hue; + m_EntryID = entryID; + m_InitialText = initialText; + } + + public override string Compile() + { + return String.Format( "{{ textentry {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_Width, m_Height, m_Hue, m_EntryID, Parent.Intern( m_InitialText ) ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "textentry" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_Hue ); + disp.AppendLayout( m_EntryID ); + disp.AppendLayout( Parent.Intern( m_InitialText ) ); + + disp.TextEntries++; + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpTextEntryLimited.cs b/Server/Gumps/GumpTextEntryLimited.cs new file mode 100644 index 0000000..ca6dc8c --- /dev/null +++ b/Server/Gumps/GumpTextEntryLimited.cs @@ -0,0 +1,136 @@ +/*************************************************************************** + * GumpTextEntryLimited.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpTextEntryLimited.cs 77 2006-08-27 19:36:26Z krrios $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps { + public class GumpTextEntryLimited : GumpEntry { + private int m_X, m_Y; + private int m_Width, m_Height; + private int m_Hue; + private int m_EntryID; + private string m_InitialText; + private int m_Size; + + public int X { + get { + return m_X; + } + set { + Delta( ref m_X, value ); + } + } + + public int Y { + get { + return m_Y; + } + set { + Delta( ref m_Y, value ); + } + } + + public int Width { + get { + return m_Width; + } + set { + Delta( ref m_Width, value ); + } + } + + public int Height { + get { + return m_Height; + } + set { + Delta( ref m_Height, value ); + } + } + + public int Hue { + get { + return m_Hue; + } + set { + Delta( ref m_Hue, value ); + } + } + + public int EntryID { + get { + return m_EntryID; + } + set { + Delta( ref m_EntryID, value ); + } + } + + public string InitialText { + get { + return m_InitialText; + } + set { + Delta( ref m_InitialText, value ); + } + } + + public int Size { + get { + return m_Size; + } + set { + Delta( ref m_Size, value ); + } + } + + public GumpTextEntryLimited( int x, int y, int width, int height, int hue, int entryID, string initialText, int size ) { + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + m_Hue = hue; + m_EntryID = entryID; + m_InitialText = initialText; + m_Size = size; + } + + public override string Compile() { + return String.Format( "{{ textentrylimited {0} {1} {2} {3} {4} {5} {6} {7} }}", m_X, m_Y, m_Width, m_Height, m_Hue, m_EntryID, Parent.Intern( m_InitialText ), m_Size ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "textentrylimited" ); + + public override void AppendTo( IGumpWriter disp ) { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_X ); + disp.AppendLayout( m_Y ); + disp.AppendLayout( m_Width ); + disp.AppendLayout( m_Height ); + disp.AppendLayout( m_Hue ); + disp.AppendLayout( m_EntryID ); + disp.AppendLayout( Parent.Intern( m_InitialText ) ); + disp.AppendLayout( m_Size ); + + disp.TextEntries++; + } + } +} \ No newline at end of file diff --git a/Server/Gumps/GumpTooltip.cs b/Server/Gumps/GumpTooltip.cs new file mode 100644 index 0000000..17950ae --- /dev/null +++ b/Server/Gumps/GumpTooltip.cs @@ -0,0 +1,60 @@ +/*************************************************************************** + * GumpTooltip.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: GumpTooltip.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Gumps +{ + public class GumpTooltip : GumpEntry + { + private int m_Number; + + public GumpTooltip( int number ) + { + m_Number = number; + } + + public int Number + { + get + { + return m_Number; + } + set + { + Delta( ref m_Number, value ); + } + } + + public override string Compile() + { + return String.Format( "{{ tooltip {0} }}", m_Number ); + } + + private static byte[] m_LayoutName = Gump.StringToBuffer( "tooltip" ); + + public override void AppendTo( IGumpWriter disp ) + { + disp.AppendLayout( m_LayoutName ); + disp.AppendLayout( m_Number ); + } + } +} \ No newline at end of file diff --git a/Server/Gumps/RelayInfo.cs b/Server/Gumps/RelayInfo.cs new file mode 100644 index 0000000..56e86e1 --- /dev/null +++ b/Server/Gumps/RelayInfo.cs @@ -0,0 +1,116 @@ +/*************************************************************************** + * RelayInfo.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: RelayInfo.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Gumps +{ + public class TextRelay + { + private int m_EntryID; + private string m_Text; + + public TextRelay( int entryID, string text ) + { + m_EntryID = entryID; + m_Text = text; + } + + public int EntryID + { + get + { + return m_EntryID; + } + } + + public string Text + { + get + { + return m_Text; + } + } + } + + public class RelayInfo + { + private int m_ButtonID; + private int[] m_Switches; + private TextRelay[] m_TextEntries; + + public RelayInfo( int buttonID, int[] switches, TextRelay[] textEntries ) + { + m_ButtonID = buttonID; + m_Switches = switches; + m_TextEntries = textEntries; + } + + public int ButtonID + { + get + { + return m_ButtonID; + } + } + + public int[] Switches + { + get + { + return m_Switches; + } + } + + public TextRelay[] TextEntries + { + get + { + return m_TextEntries; + } + } + + public bool IsSwitched( int switchID ) + { + for ( int i = 0; i < m_Switches.Length; ++i ) + { + if ( m_Switches[i] == switchID ) + { + return true; + } + } + + return false; + } + + public TextRelay GetTextEntry( int entryID ) + { + for ( int i = 0; i < m_TextEntries.Length; ++i ) + { + if ( m_TextEntries[i].EntryID == entryID ) + { + return m_TextEntries[i]; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/Server/HuePicker.cs b/Server/HuePicker.cs new file mode 100644 index 0000000..dd698fe --- /dev/null +++ b/Server/HuePicker.cs @@ -0,0 +1,69 @@ +/*************************************************************************** + * HuePicker.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: HuePicker.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.HuePickers +{ + public class HuePicker + { + private static int m_NextSerial = 1; + + private int m_Serial; + private int m_ItemID; + + public int Serial + { + get + { + return m_Serial; + } + } + + public int ItemID + { + get + { + return m_ItemID; + } + } + + public HuePicker( int itemID ) + { + do + { + m_Serial = m_NextSerial++; + } while ( m_Serial == 0 ); + + m_ItemID = itemID; + } + + public virtual void OnResponse( int hue ) + { + } + + public void SendTo( NetState state ) + { + state.Send( new DisplayHuePicker( this ) ); + state.AddHuePicker( this ); + } + } +} \ No newline at end of file diff --git a/Server/IAccount.cs b/Server/IAccount.cs new file mode 100644 index 0000000..541935d --- /dev/null +++ b/Server/IAccount.cs @@ -0,0 +1,39 @@ +/*************************************************************************** + * IAccount.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: IAccount.cs 856 2012-03-21 22:25:44Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Accounting +{ + public interface IAccount : IComparable + { + string Username { get; set; } + AccessLevel AccessLevel { get; set; } + + int Length { get; } + int Limit { get; } + int Count { get; } + Mobile this[int index] { get; set; } + + void Delete(); + void SetPassword( string password ); + bool CheckPassword( string password ); + } +} diff --git a/Server/IEntity.cs b/Server/IEntity.cs new file mode 100644 index 0000000..f7e9213 --- /dev/null +++ b/Server/IEntity.cs @@ -0,0 +1,113 @@ +/*************************************************************************** + * IEntity.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: IEntity.cs 149 2007-01-19 22:10:11Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public interface IEntity : IPoint3D, IComparable, IComparable + { + Serial Serial{ get; } + Point3D Location{ get; } + Map Map{ get; } + + void Delete(); + void ProcessDelta(); + } + + public class Entity : IEntity, IComparable + { + public int CompareTo( IEntity other ) + { + if ( other == null ) + return -1; + + return m_Serial.CompareTo( other.Serial ); + } + + public int CompareTo( Entity other ) + { + return this.CompareTo( (IEntity) other ); + } + + public int CompareTo( object other ) + { + if ( other == null || other is IEntity ) + return this.CompareTo( (IEntity) other ); + + throw new ArgumentException(); + } + + private Serial m_Serial; + private Point3D m_Location; + private Map m_Map; + + public Entity( Serial serial, Point3D loc, Map map ) + { + m_Serial = serial; + m_Location = loc; + m_Map = map; + } + + public Serial Serial { + get { + return m_Serial; + } + } + + public Point3D Location { + get { + return m_Location; + } + } + + public int X { + get { + return m_Location.X; + } + } + + public int Y { + get { + return m_Location.Y; + } + } + + public int Z { + get { + return m_Location.Z; + } + } + + public Map Map { + get { + return m_Map; + } + } + + public void Delete() + { + } + + public void ProcessDelta() + { + } + } +} \ No newline at end of file diff --git a/Server/Insensitive.cs b/Server/Insensitive.cs new file mode 100644 index 0000000..de7a10c --- /dev/null +++ b/Server/Insensitive.cs @@ -0,0 +1,77 @@ +/*************************************************************************** + * Insensitive.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Insensitive.cs 567 2010-10-20 01:09:57Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; + +namespace Server +{ + public static class Insensitive + { + private static IComparer m_Comparer = CaseInsensitiveComparer.Default; + + public static IComparer Comparer + { + get{ return m_Comparer; } + } + + public static int Compare( string a, string b ) + { + return m_Comparer.Compare( a, b ); + } + + public static bool Equals( string a, string b ) + { + if ( a == null && b == null ) + return true; + else if ( a == null || b == null || a.Length != b.Length ) + return false; + + return ( m_Comparer.Compare( a, b ) == 0 ); + } + + public static bool StartsWith( string a, string b ) + { + if ( a == null || b == null || a.Length < b.Length ) + return false; + + return ( m_Comparer.Compare( a.Substring( 0, b.Length ), b ) == 0 ); + } + + public static bool EndsWith( string a, string b ) + { + if ( a == null || b == null || a.Length < b.Length ) + return false; + + return ( m_Comparer.Compare( a.Substring( a.Length - b.Length ), b ) == 0 ); + } + + public static bool Contains( string a, string b ) + { + if ( a == null || b == null || a.Length < b.Length ) + return false; + + a = a.ToLower(); + b = b.ToLower(); + + return ( a.IndexOf( b ) >= 0 ); + } + } +} \ No newline at end of file diff --git a/Server/Interfaces.cs b/Server/Interfaces.cs new file mode 100644 index 0000000..2e8f078 --- /dev/null +++ b/Server/Interfaces.cs @@ -0,0 +1,116 @@ +/*************************************************************************** + * Interfaces.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Interfaces.cs 649 2010-12-26 05:18:57Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using Server.Mobiles; + +namespace Server.Mobiles +{ + public interface IMount + { + Mobile Rider{ get; set; } + void OnRiderDamaged( int amount, Mobile from, bool willKill ); + } + + public interface IMountItem + { + IMount Mount{ get; } + } +} + +namespace Server +{ + public interface IVendor + { + bool OnBuyItems( Mobile from, List list ); + bool OnSellItems( Mobile from, List list ); + + DateTime LastRestock{ get; set; } + TimeSpan RestockDelay{ get; } + void Restock(); + } + + public interface IPoint2D + { + int X{ get; } + int Y{ get; } + } + + public interface IPoint3D : IPoint2D + { + int Z{ get; } + } + + public interface ICarvable + { + void Carve( Mobile from, Item item ); + } + + public interface IWeapon + { + int MaxRange{ get; } + void OnBeforeSwing( Mobile attacker, Mobile defender ); + TimeSpan OnSwing( Mobile attacker, Mobile defender ); + void GetStatusDamage( Mobile from, out int min, out int max ); + } + + public interface IHued + { + int HuedItemID{ get; } + } + + public interface ISpell + { + bool IsCasting{ get; } + void OnCasterHurt(); + void OnCasterKilled(); + void OnConnectionChanged(); + bool OnCasterMoving( Direction d ); + bool OnCasterEquiping( Item item ); + bool OnCasterUsingObject( object o ); + bool OnCastInTown( Region r ); + } + + public interface IParty + { + void OnStamChanged( Mobile m ); + void OnManaChanged( Mobile m ); + void OnStatsQuery( Mobile beholder, Mobile beheld ); + } + + public interface ISpawner + { + bool UnlinkOnTaming { get; } + Point3D HomeLocation { get; } + int HomeRange { get; } + + void Remove(ISpawnable spawn); + } + + public interface ISpawnable : IEntity + { + void OnBeforeSpawn(Point3D location, Map map); + void MoveToWorld(Point3D location, Map map); + void OnAfterSpawn(); + + ISpawner Spawner { get; set; } + } +} \ No newline at end of file diff --git a/Server/Item.cs b/Server/Item.cs new file mode 100644 index 0000000..1f3a2c1 --- /dev/null +++ b/Server/Item.cs @@ -0,0 +1,4729 @@ +/*************************************************************************** + * Item.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Item.cs 1037 2013-02-24 00:31:44Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using Server.Network; +using Server.Items; +using Server.ContextMenus; + +namespace Server +{ + /// + /// Enumeration of item layer values. + /// + public enum Layer : byte + { + /// + /// Invalid layer. + /// + Invalid = 0x00, + /// + /// First valid layer. Equivalent to Layer.OneHanded. + /// + FirstValid = 0x01, + /// + /// One handed weapon. + /// + OneHanded = 0x01, + /// + /// Two handed weapon or shield. + /// + TwoHanded = 0x02, + /// + /// Shoes. + /// + Shoes = 0x03, + /// + /// Pants. + /// + Pants = 0x04, + /// + /// Shirts. + /// + Shirt = 0x05, + /// + /// Helmets, hats, and masks. + /// + Helm = 0x06, + /// + /// Gloves. + /// + Gloves = 0x07, + /// + /// Rings. + /// + Ring = 0x08, + /// + /// Talismans. + /// + Talisman = 0x09, + /// + /// Gorgets and necklaces. + /// + Neck = 0x0A, + /// + /// Hair. + /// + Hair = 0x0B, + /// + /// Half aprons. + /// + Waist = 0x0C, + /// + /// Torso, inner layer. + /// + InnerTorso = 0x0D, + /// + /// Bracelets. + /// + Bracelet = 0x0E, + /// + /// Unused. + /// + Unused_xF = 0x0F, + /// + /// Beards and mustaches. + /// + FacialHair = 0x10, + /// + /// Torso, outer layer. + /// + MiddleTorso = 0x11, + /// + /// Earings. + /// + Earrings = 0x12, + /// + /// Arms and sleeves. + /// + Arms = 0x13, + /// + /// Cloaks. + /// + Cloak = 0x14, + /// + /// Backpacks. + /// + Backpack = 0x15, + /// + /// Torso, outer layer. + /// + OuterTorso = 0x16, + /// + /// Leggings, outer layer. + /// + OuterLegs = 0x17, + /// + /// Leggings, inner layer. + /// + InnerLegs = 0x18, + /// + /// Last valid non-internal layer. Equivalent to Layer.InnerLegs. + /// + LastUserValid= 0x18, + /// + /// Mount item layer. + /// + Mount = 0x19, + /// + /// Vendor 'buy pack' layer. + /// + ShopBuy = 0x1A, + /// + /// Vendor 'resale pack' layer. + /// + ShopResale = 0x1B, + /// + /// Vendor 'sell pack' layer. + /// + ShopSell = 0x1C, + /// + /// Bank box layer. + /// + Bank = 0x1D, + /// + /// Last valid layer. Equivalent to Layer.Bank. + /// + LastValid = 0x1D + } + + /// + /// Internal flags used to signal how the item should be updated and resent to nearby clients. + /// + [Flags] + public enum ItemDelta + { + /// + /// Nothing. + /// + None = 0x00000000, + /// + /// Resend the item. + /// + Update = 0x00000001, + /// + /// Resend the item only if it is equiped. + /// + EquipOnly = 0x00000002, + /// + /// Resend the item's properties. + /// + Properties = 0x00000004 + } + + /// + /// Enumeration containing possible ways to handle item ownership on death. + /// + public enum DeathMoveResult + { + /// + /// The item should be placed onto the corpse. + /// + MoveToCorpse, + /// + /// The item should remain equiped. + /// + RemainEquiped, + /// + /// The item should be placed into the owners backpack. + /// + MoveToBackpack + } + + /// + /// Enumeration containing all possible light types. These are only applicable to light source items, like lanterns, candles, braziers, etc. + /// + public enum LightType + { + /// + /// Window shape, arched, ray shining east. + /// + ArchedWindowEast, + /// + /// Medium circular shape. + /// + Circle225, + /// + /// Small circular shape. + /// + Circle150, + /// + /// Door shape, shining south. + /// + DoorSouth, + /// + /// Door shape, shining east. + /// + DoorEast, + /// + /// Large semicircular shape (180 degrees), north wall. + /// + NorthBig, + /// + /// Large pie shape (90 degrees), north-east corner. + /// + NorthEastBig, + /// + /// Large semicircular shape (180 degrees), east wall. + /// + EastBig, + /// + /// Large semicircular shape (180 degrees), west wall. + /// + WestBig, + /// + /// Large pie shape (90 degrees), south-west corner. + /// + SouthWestBig, + /// + /// Large semicircular shape (180 degrees), south wall. + /// + SouthBig, + /// + /// Medium semicircular shape (180 degrees), north wall. + /// + NorthSmall, + /// + /// Medium pie shape (90 degrees), north-east corner. + /// + NorthEastSmall, + /// + /// Medium semicircular shape (180 degrees), east wall. + /// + EastSmall, + /// + /// Medium semicircular shape (180 degrees), west wall. + /// + WestSmall, + /// + /// Medium semicircular shape (180 degrees), south wall. + /// + SouthSmall, + /// + /// Shaped like a wall decoration, north wall. + /// + DecorationNorth, + /// + /// Shaped like a wall decoration, north-east corner. + /// + DecorationNorthEast, + /// + /// Small semicircular shape (180 degrees), east wall. + /// + EastTiny, + /// + /// Shaped like a wall decoration, west wall. + /// + DecorationWest, + /// + /// Shaped like a wall decoration, south-west corner. + /// + DecorationSouthWest, + /// + /// Small semicircular shape (180 degrees), south wall. + /// + SouthTiny, + /// + /// Window shape, rectangular, no ray, shining south. + /// + RectWindowSouthNoRay, + /// + /// Window shape, rectangular, no ray, shining east. + /// + RectWindowEastNoRay, + /// + /// Window shape, rectangular, ray shining south. + /// + RectWindowSouth, + /// + /// Window shape, rectangular, ray shining east. + /// + RectWindowEast, + /// + /// Window shape, arched, no ray, shining south. + /// + ArchedWindowSouthNoRay, + /// + /// Window shape, arched, no ray, shining east. + /// + ArchedWindowEastNoRay, + /// + /// Window shape, arched, ray shining south. + /// + ArchedWindowSouth, + /// + /// Large circular shape. + /// + Circle300, + /// + /// Large pie shape (90 degrees), north-west corner. + /// + NorthWestBig, + /// + /// Negative light. Medium pie shape (90 degrees), south-east corner. + /// + DarkSouthEast, + /// + /// Negative light. Medium semicircular shape (180 degrees), south wall. + /// + DarkSouth, + /// + /// Negative light. Medium pie shape (90 degrees), north-west corner. + /// + DarkNorthWest, + /// + /// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to LightType.SouthEast. + /// + DarkSouthEast2, + /// + /// Negative light. Medium circular shape (180 degrees), east wall. + /// + DarkEast, + /// + /// Negative light. Large circular shape. + /// + DarkCircle300, + /// + /// Opened door shape, shining south. + /// + DoorOpenSouth, + /// + /// Opened door shape, shining east. + /// + DoorOpenEast, + /// + /// Window shape, square, ray shining east. + /// + SquareWindowEast, + /// + /// Window shape, square, no ray, shining east. + /// + SquareWindowEastNoRay, + /// + /// Window shape, square, ray shining south. + /// + SquareWindowSouth, + /// + /// Window shape, square, no ray, shining south. + /// + SquareWindowSouthNoRay, + /// + /// Empty. + /// + Empty, + /// + /// Window shape, skinny, no ray, shining south. + /// + SkinnyWindowSouthNoRay, + /// + /// Window shape, skinny, ray shining east. + /// + SkinnyWindowEast, + /// + /// Window shape, skinny, no ray, shining east. + /// + SkinnyWindowEastNoRay, + /// + /// Shaped like a hole, shining south. + /// + HoleSouth, + /// + /// Shaped like a hole, shining south. + /// + HoleEast, + /// + /// Large circular shape with a moongate graphic embeded. + /// + Moongate, + /// + /// Unknown usage. Many rows of slightly angled lines. + /// + Strips, + /// + /// Shaped like a small hole, shining south. + /// + SmallHoleSouth, + /// + /// Shaped like a small hole, shining east. + /// + SmallHoleEast, + /// + /// Large semicircular shape (180 degrees), north wall. Identical graphic as LightType.NorthBig, but slightly different positioning. + /// + NorthBig2, + /// + /// Large semicircular shape (180 degrees), west wall. Identical graphic as LightType.WestBig, but slightly different positioning. + /// + WestBig2, + /// + /// Large pie shape (90 degrees), north-west corner. Equivalent to LightType.NorthWestBig. + /// + NorthWestBig2 + } + + /// + /// Enumeration of an item's loot and steal state. + /// + public enum LootType : byte + { + /// + /// Stealable. Lootable. + /// + Regular = 0, + /// + /// Unstealable. Unlootable, unless owned by a murderer. + /// + Newbied = 1, + /// + /// Unstealable. Unlootable, always. + /// + Blessed = 2, + /// + /// Stealable. Lootable, always. + /// + Cursed = 3 + } + + public class BounceInfo + { + public Map m_Map; + public Point3D m_Location, m_WorldLoc; + public object m_Parent; + + public BounceInfo( Item item ) + { + m_Map = item.Map; + m_Location = item.Location; + m_WorldLoc = item.GetWorldLocation(); + m_Parent = item.Parent; + } + + private BounceInfo( Map map, Point3D loc, Point3D worldLoc, object parent ) + { + m_Map = map; + m_Location = loc; + m_WorldLoc = worldLoc; + m_Parent = parent; + } + + public static BounceInfo Deserialize( GenericReader reader ) + { + if ( reader.ReadBool() ) + { + Map map = reader.ReadMap(); + Point3D loc = reader.ReadPoint3D(); + Point3D worldLoc = reader.ReadPoint3D(); + + object parent; + + Serial serial = reader.ReadInt(); + + if ( serial.IsItem ) + parent = World.FindItem( serial ); + else if ( serial.IsMobile ) + parent = World.FindMobile( serial ); + else + parent = null; + + return new BounceInfo( map, loc, worldLoc, parent ); + } + else + { + return null; + } + } + + public static void Serialize( BounceInfo info, GenericWriter writer ) + { + if ( info == null ) + { + writer.Write( false ); + } + else + { + writer.Write( true ); + + writer.Write( info.m_Map ); + writer.Write( info.m_Location ); + writer.Write( info.m_WorldLoc ); + + if ( info.m_Parent is Mobile ) + writer.Write( (Mobile) info.m_Parent ); + else if ( info.m_Parent is Item ) + writer.Write( (Item) info.m_Parent ); + else + writer.Write( (Serial) 0 ); + } + } + } + + public enum TotalType + { + Gold, + Items, + Weight, + } + + [Flags] + public enum ExpandFlag + { + None = 0x000, + + Name = 0x001, + Items = 0x002, + Bounce = 0x004, + Holder = 0x008, + Blessed = 0x010, + TempFlag = 0x020, + SaveFlag = 0x040, + Weight = 0x080, + Spawner = 0x100 + } + + public class Item : IEntity, IHued, IComparable, ISerializable, ISpawnable + { + public static readonly List EmptyItems = new List(); + + public int CompareTo( IEntity other ) + { + if ( other == null ) + return -1; + + return m_Serial.CompareTo( other.Serial ); + } + + public int CompareTo( Item other ) + { + return this.CompareTo( (IEntity) other ); + } + + public int CompareTo( object other ) + { + if ( other == null || other is IEntity ) + return this.CompareTo( (IEntity) other ); + + throw new ArgumentException(); + } + + #region Standard fields + private Serial m_Serial; + private Point3D m_Location; + private int m_ItemID; + private int m_Hue; + private int m_Amount; + private Layer m_Layer; + private object m_Parent; // Mobile, Item, or null=World + private Map m_Map; + private LootType m_LootType; + private DateTime m_LastMovedTime; + private Direction m_Direction; + + // Scriptiz : Ajouts + private bool m_Lootable = true; + private bool m_Stealable = true; + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public bool Lootable + { + get { return m_Lootable; } + set { m_Lootable = value; } + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public bool Stealable + { + get { return m_Stealable; } + set { m_Stealable = value; } + } + #endregion + + private ItemDelta m_DeltaFlags; + private ImplFlag m_Flags; + + #region Packet caches + private Packet m_WorldPacket; + private Packet m_WorldPacketSA; + private Packet m_WorldPacketHS; + private Packet m_RemovePacket; + + private Packet m_OPLPacket; + private ObjectPropertyList m_PropertyList; + #endregion + + public int TempFlags + { + get + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + return info.m_TempFlags; + + return 0; + } + set + { + CompactInfo info = AcquireCompactInfo(); + + info.m_TempFlags = value; + + if ( info.m_TempFlags == 0 ) + VerifyCompactInfo(); + } + } + + public int SavedFlags + { + get + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + return info.m_SavedFlags; + + return 0; + } + set + { + CompactInfo info = AcquireCompactInfo(); + + info.m_SavedFlags = value; + + if ( info.m_SavedFlags == 0 ) + VerifyCompactInfo(); + } + } + + /// + /// The who is currently holding this item. + /// + public Mobile HeldBy + { + get + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + return info.m_HeldBy; + + return null; + } + set + { + CompactInfo info = AcquireCompactInfo(); + + info.m_HeldBy = value; + + if ( info.m_HeldBy == null ) + VerifyCompactInfo(); + } + } + + [Flags] + private enum ImplFlag : byte + { + None = 0x00, + Visible = 0x01, + Movable = 0x02, + Deleted = 0x04, + Stackable = 0x08, + InQueue = 0x10, + Insured = 0x20, + PayedInsurance = 0x40, + QuestItem = 0x80 + } + + private class CompactInfo + { + public string m_Name; + + public List m_Items; + public BounceInfo m_Bounce; + + public Mobile m_HeldBy; + public Mobile m_BlessedFor; + + public ISpawner m_Spawner; + + public int m_TempFlags; + public int m_SavedFlags; + + public double m_Weight = -1; + } + + private CompactInfo m_CompactInfo; + + public ExpandFlag GetExpandFlags() + { + CompactInfo info = LookupCompactInfo(); + + ExpandFlag flags = 0; + + if ( info != null ) + { + if ( info.m_BlessedFor != null ) + flags |= ExpandFlag.Blessed; + + if ( info.m_Bounce != null ) + flags |= ExpandFlag.Bounce; + + if ( info.m_HeldBy != null ) + flags |= ExpandFlag.Holder; + + if ( info.m_Items != null ) + flags |= ExpandFlag.Items; + + if ( info.m_Name != null ) + flags |= ExpandFlag.Name; + + if (info.m_Spawner != null) + flags |= ExpandFlag.Spawner; + + if ( info.m_SavedFlags != 0 ) + flags |= ExpandFlag.SaveFlag; + + if ( info.m_TempFlags != 0 ) + flags |= ExpandFlag.TempFlag; + + if ( info.m_Weight != -1 ) + flags |= ExpandFlag.Weight; + } + + return flags; + } + + private CompactInfo LookupCompactInfo() + { + return m_CompactInfo; + } + + private CompactInfo AcquireCompactInfo() + { + if ( m_CompactInfo == null ) + m_CompactInfo = new CompactInfo(); + + return m_CompactInfo; + } + + private void ReleaseCompactInfo() + { + m_CompactInfo = null; + } + + private void VerifyCompactInfo() + { + CompactInfo info = m_CompactInfo; + + if ( info == null ) + return; + + bool isValid = ( info.m_Name != null ) + || ( info.m_Items != null ) + || ( info.m_Bounce != null ) + || ( info.m_HeldBy != null ) + || ( info.m_BlessedFor != null ) + || (info.m_Spawner != null) + || ( info.m_TempFlags != 0 ) + || ( info.m_SavedFlags != 0 ) + || ( info.m_Weight != -1 ); + + if ( !isValid ) + ReleaseCompactInfo(); + } + + public List LookupItems() + { + if ( this is Container ) + return ( this as Container ).m_Items; + + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + return info.m_Items; + + return null; + } + + public List AcquireItems() + { + if ( this is Container ) + { + Container cont = this as Container; + + if (cont.m_Items == null) + cont.m_Items = new List(); + + return cont.m_Items; + } + + CompactInfo info = AcquireCompactInfo(); + + if ( info.m_Items == null ) + info.m_Items = new List(); + + return info.m_Items; + } + + private void SetFlag( ImplFlag flag, bool value ) + { + if ( value ) + m_Flags |= flag; + else + m_Flags &= ~flag; + } + + private bool GetFlag( ImplFlag flag ) + { + return ( (m_Flags & flag) != 0 ); + } + + public BounceInfo GetBounce() + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + return info.m_Bounce; + + return null; + } + + public void RecordBounce() + { + CompactInfo info = AcquireCompactInfo(); + + info.m_Bounce = new BounceInfo( this ); + } + + public void ClearBounce() + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + { + BounceInfo bounce = info.m_Bounce; + + if ( bounce != null ) + { + info.m_Bounce = null; + + if ( bounce.m_Parent is Item ) + { + Item parent = (Item) bounce.m_Parent; + + if ( !parent.Deleted ) + parent.OnItemBounceCleared( this ); + } + else if ( bounce.m_Parent is Mobile ) + { + Mobile parent = (Mobile) bounce.m_Parent; + + if ( !parent.Deleted ) + parent.OnItemBounceCleared( this ); + } + + VerifyCompactInfo(); + } + } + } + + /// + /// Overridable. Virtual event invoked when a client, , invokes a 'help request' for the Item. Seemingly no longer functional in newer clients. + /// + public virtual void OnHelpRequest( Mobile from ) + { + } + + /// + /// Overridable. Method checked to see if the item can be traded. + /// + /// True if the trade is allowed, false if not. + public virtual bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when a trade has completed, either successfully or not. + /// + public virtual void OnSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted ) + { + } + + /// + /// Overridable. Method checked to see if the elemental resistances of this Item conflict with another Item on the . + /// + /// + /// + /// + /// True + /// There is a confliction. The elemental resistance bonuses of this Item should not be applied to the + /// + /// + /// False + /// There is no confliction. The bonuses should be applied. + /// + /// + /// + public virtual bool CheckPropertyConfliction( Mobile m ) + { + return false; + } + + /// + /// Overridable. Sends the object property list to . + /// + public virtual void SendPropertiesTo( Mobile from ) + { + from.Send( PropertyList ); + } + + /// + /// Overridable. Adds the name of this item to the given . This method should be overriden if the item requires a complex naming format. + /// + public virtual void AddNameProperty( ObjectPropertyList list ) + { + string name = this.Name; + + if ( name == null ) + { + if ( m_Amount <= 1 ) + list.Add( LabelNumber ); + else + list.Add( 1050039, "{0}\t#{1}", m_Amount, LabelNumber ); // ~1_NUMBER~ ~2_ITEMNAME~ + } + else + { + if ( m_Amount <= 1 ) + list.Add( name ); + else + list.Add( 1050039, "{0}\t{1}", m_Amount, Name ); // ~1_NUMBER~ ~2_ITEMNAME~ + } + } + + /// + /// Overridable. Adds the loot type of this item to the given . By default, this will be either 'blessed', 'cursed', or 'insured'. + /// + public virtual void AddLootTypeProperty( ObjectPropertyList list ) + { + if ( m_LootType == LootType.Blessed ) + list.Add( 1038021 ); // blessed + else if ( m_LootType == LootType.Cursed ) + list.Add( 1049643 ); // cursed + else if ( Insured ) + list.Add( 1061682 ); // insured + } + + /// + /// Overridable. Adds any elemental resistances of this item to the given . + /// + public virtual void AddResistanceProperties( ObjectPropertyList list ) + { + int v = PhysicalResistance; + + if ( v != 0 ) + list.Add( 1060448, v.ToString() ); // physical resist ~1_val~% + + v = FireResistance; + + if ( v != 0 ) + list.Add( 1060447, v.ToString() ); // fire resist ~1_val~% + + v = ColdResistance; + + if ( v != 0 ) + list.Add( 1060445, v.ToString() ); // cold resist ~1_val~% + + v = PoisonResistance; + + if ( v != 0 ) + list.Add( 1060449, v.ToString() ); // poison resist ~1_val~% + + v = EnergyResistance; + + if ( v != 0 ) + list.Add( 1060446, v.ToString() ); // energy resist ~1_val~% + } + + /// + /// Overridable. Determines whether the item will show . + /// + public virtual bool DisplayWeight + { + get + { + if ( !Core.ML ) + return false; + + if ( !Movable && !( IsLockedDown || IsSecure ) && ItemData.Weight == 255 ) + return false; + + return true; + } + } + + /// + /// Overridable. Displays cliloc 1072788-1072789. + /// + public virtual void AddWeightProperty( ObjectPropertyList list ) + { + int weight = this.PileWeight + this.TotalWeight; + + if ( weight == 1 ) { + list.Add( 1072788, weight.ToString() ); //Weight: ~1_WEIGHT~ stone + } else { + list.Add( 1072789, weight.ToString() ); //Weight: ~1_WEIGHT~ stones + } + } + + /// + /// Overridable. Adds header properties. By default, this invokes , (if applicable), and (if ). + /// + public virtual void AddNameProperties( ObjectPropertyList list ) + { + AddNameProperty( list ); + + if ( IsSecure ) + AddSecureProperty( list ); + else if ( IsLockedDown ) + AddLockedDownProperty( list ); + + Mobile blessedFor = this.BlessedFor; + + if ( blessedFor != null && !blessedFor.Deleted ) + AddBlessedForProperty( list, blessedFor ); + + if ( DisplayLootType ) + AddLootTypeProperty( list ); + + if ( DisplayWeight ) + AddWeightProperty( list ); + + if( QuestItem ) + AddQuestItemProperty( list ); + + + AppendChildNameProperties( list ); + } + + /// + /// Overridable. Adds the "Quest Item" property to the given . + /// + public virtual void AddQuestItemProperty( ObjectPropertyList list ) + { + list.Add( 1072351 ); // Quest Item + } + + /// + /// Overridable. Adds the "Locked Down & Secure" property to the given . + /// + public virtual void AddSecureProperty( ObjectPropertyList list ) + { + list.Add( 501644 ); // locked down & secure + } + + /// + /// Overridable. Adds the "Locked Down" property to the given . + /// + public virtual void AddLockedDownProperty( ObjectPropertyList list ) + { + list.Add( 501643 ); // locked down + } + + /// + /// Overridable. Adds the "Blessed for ~1_NAME~" property to the given . + /// + public virtual void AddBlessedForProperty( ObjectPropertyList list, Mobile m ) + { + list.Add( 1062203, "{0}", m.Name ); // Blessed for ~1_NAME~ + } + + /// + /// Overridable. Fills an with everything applicable. By default, this invokes , then Item.GetChildProperties or Mobile.GetChildProperties. This method should be overriden to add any custom properties. + /// + public virtual void GetProperties( ObjectPropertyList list ) + { + AddNameProperties( list ); + } + + /// + /// Overridable. Event invoked when a child () is building it's . Recursively calls Item.GetChildProperties or Mobile.GetChildProperties. + /// + public virtual void GetChildProperties( ObjectPropertyList list, Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).GetChildProperties( list, item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).GetChildProperties( list, item ); + } + + /// + /// Overridable. Event invoked when a child () is building it's Name . Recursively calls Item.GetChildNameProperties or Mobile.GetChildNameProperties. + /// + public virtual void GetChildNameProperties( ObjectPropertyList list, Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).GetChildNameProperties( list, item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).GetChildNameProperties( list, item ); + } + + public virtual bool IsChildVisibleTo( Mobile m, Item child ) + { + return true; + } + + public void Bounce( Mobile from ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).RemoveItem( this ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).RemoveItem( this ); + + m_Parent = null; + + BounceInfo bounce = this.GetBounce(); + + if ( bounce != null ) + { + object parent = bounce.m_Parent; + + if ( parent is Item && !((Item)parent).Deleted ) + { + Item p = (Item)parent; + object root = p.RootParent; + if ( p.IsAccessibleTo( from ) && ( !(root is Mobile) || ((Mobile)root).CheckNonlocalDrop( from, this, p ) ) ) + { + Location = bounce.m_Location; + p.AddItem( this ); + } + else + { + MoveToWorld( from.Location, from.Map ); + } + } + else if ( parent is Mobile && !((Mobile)parent).Deleted ) + { + if ( !((Mobile)parent).EquipItem( this ) ) + MoveToWorld( bounce.m_WorldLoc, bounce.m_Map ); + } + else + { + MoveToWorld( bounce.m_WorldLoc, bounce.m_Map ); + } + + ClearBounce(); + } + else + { + MoveToWorld( from.Location, from.Map ); + } + } + + /// + /// Overridable. Method checked to see if this item may be equiped while casting a spell. By default, this returns false. It is overriden on spellbook and spell channeling weapons or shields. + /// + /// True if it may, false if not. + /// + /// + /// public override bool AllowEquipedCast( Mobile from ) + /// { + /// if ( from.Int >= 100 ) + /// return true; + /// + /// return base.AllowEquipedCast( from ); + /// } + /// + /// When placed in an Item script, the item may be cast when equiped if the has 100 or more intelligence. Otherwise, it will drop to their backpack. + /// + public virtual bool AllowEquipedCast( Mobile from ) + { + return false; + } + + public virtual bool CheckConflictingLayer( Mobile m, Item item, Layer layer ) + { + return ( m_Layer == layer ); + } + + public virtual bool CanEquip( Mobile m ) + { + return ( m_Layer != Layer.Invalid && m.FindItemOnLayer( m_Layer ) == null ); + } + + public virtual void GetChildContextMenuEntries( Mobile from, List list, Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).GetChildContextMenuEntries( from, list, item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).GetChildContextMenuEntries( from, list, item ); + } + + public virtual void GetContextMenuEntries( Mobile from, List list ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).GetChildContextMenuEntries( from, list, this ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).GetChildContextMenuEntries( from, list, this ); + } + + public virtual bool VerifyMove( Mobile from ) + { + return Movable; + } + + public virtual DeathMoveResult OnParentDeath( Mobile parent ) + { + if ( !Movable ) + return DeathMoveResult.RemainEquiped; + else if ( parent.KeepsItemsOnDeath ) + return DeathMoveResult.MoveToBackpack; + else if ( CheckBlessed( parent ) ) + return DeathMoveResult.MoveToBackpack; + else if ( CheckNewbied() && parent.Kills < 5 ) + return DeathMoveResult.MoveToBackpack; + else if( parent.Player && Nontransferable ) + return DeathMoveResult.MoveToBackpack; + else + return DeathMoveResult.MoveToCorpse; + } + + public virtual DeathMoveResult OnInventoryDeath( Mobile parent ) + { + if ( !Movable ) + return DeathMoveResult.MoveToBackpack; + else if ( parent.KeepsItemsOnDeath ) + return DeathMoveResult.MoveToBackpack; + else if ( CheckBlessed( parent ) ) + return DeathMoveResult.MoveToBackpack; + else if ( CheckNewbied() && parent.Kills < 5 ) + return DeathMoveResult.MoveToBackpack; + else if( parent.Player && Nontransferable ) + return DeathMoveResult.MoveToBackpack; + else + return DeathMoveResult.MoveToCorpse; + } + + /// + /// Moves the Item to . The Item does not change maps. + /// + public virtual void MoveToWorld( Point3D location ) + { + MoveToWorld( location, m_Map ); + } + + public void LabelTo( Mobile to, int number ) + { + to.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", "" ) ); + } + + public void LabelTo( Mobile to, int number, string args ) + { + to.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", args ) ); + } + + public void LabelTo( Mobile to, string text ) + { + to.Send( new UnicodeMessage( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", text ) ); + } + + public void LabelTo( Mobile to, string format, params object[] args ) + { + LabelTo( to, String.Format( format, args ) ); + } + + public void LabelToAffix( Mobile to, int number, AffixType type, string affix ) + { + to.Send( new MessageLocalizedAffix( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, "" ) ); + } + + public void LabelToAffix( Mobile to, int number, AffixType type, string affix, string args ) + { + to.Send( new MessageLocalizedAffix( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, args ) ); + } + + public virtual void LabelLootTypeTo( Mobile to ) + { + if ( m_LootType == LootType.Blessed ) + LabelTo( to, 1041362 ); // (blessed) + else if ( m_LootType == LootType.Cursed ) + LabelTo( to, "(cursed)" ); + } + + public bool AtWorldPoint( int x, int y ) + { + return ( m_Parent == null && m_Location.m_X == x && m_Location.m_Y == y ); + } + + public bool AtPoint( int x, int y ) + { + return ( m_Location.m_X == x && m_Location.m_Y == y ); + } + + /// + /// Moves the Item to a given and . + /// + public void MoveToWorld( Point3D location, Map map ) + { + if ( Deleted ) + return; + + Point3D oldLocation = GetWorldLocation(); + Point3D oldRealLocation = m_Location; + + SetLastMoved(); + + if ( Parent is Mobile ) + ((Mobile)Parent).RemoveItem( this ); + else if ( Parent is Item ) + ((Item)Parent).RemoveItem( this ); + + if ( m_Map != map ) + { + Map old = m_Map; + + if ( m_Map != null ) + { + m_Map.OnLeave( this ); + + if ( oldLocation.m_X != 0 ) + { + Packet remPacket = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( oldLocation, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.InRange( oldLocation, GetUpdateRange( m ) ) ) + { + if ( remPacket == null ) + remPacket = this.RemovePacket; + + state.Send( remPacket ); + } + } + + eable.Free(); + } + } + + m_Location = location; + this.OnLocationChange( oldRealLocation ); + + ReleaseWorldPackets(); + + List items = LookupItems(); + + if ( items != null ) + { + for ( int i = 0; i < items.Count; ++i ) + items[i].Map = map; + } + + m_Map = map; + + if ( m_Map != null ) + m_Map.OnEnter( this ); + + OnMapChange(); + + if ( m_Map != null ) + { + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( m_Location, GetUpdateRange( m ) ) ) + SendInfoTo( state ); + } + + eable.Free(); + } + + RemDelta( ItemDelta.Update ); + + if ( old == null || old == Map.Internal ) + InvalidateProperties(); + } + else if ( m_Map != null ) + { + IPooledEnumerable eable; + + if ( oldLocation.m_X != 0 ) + { + Packet removeThis = null; + + eable = m_Map.GetClientsInRange( oldLocation, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( !m.InRange( location, GetUpdateRange( m ) ) ) + { + if ( removeThis == null ) + removeThis = this.RemovePacket; + + state.Send( removeThis ); + } + } + + eable.Free(); + } + + Point3D oldInternalLocation = m_Location; + + m_Location = location; + this.OnLocationChange( oldRealLocation ); + + ReleaseWorldPackets(); + + eable = m_Map.GetClientsInRange( m_Location, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( m_Location, GetUpdateRange( m ) ) ) + SendInfoTo( state ); + } + + eable.Free(); + + m_Map.OnMove( oldInternalLocation, this ); + + RemDelta( ItemDelta.Update ); + } + else + { + Map = map; + Location = location; + } + } + + /// + /// Has the item been deleted? + /// + public bool Deleted{ get{ return GetFlag( ImplFlag.Deleted ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public LootType LootType + { + get + { + return m_LootType; + } + set + { + if ( m_LootType != value ) + { + m_LootType = value; + + if ( DisplayLootType ) + InvalidateProperties(); + } + } + } + + private static TimeSpan m_DDT = TimeSpan.FromHours( 1.0 ); + + public static TimeSpan DefaultDecayTime{ get{ return m_DDT; } set{ m_DDT = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual TimeSpan DecayTime + { + get + { + return m_DDT; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool Decays + { + get + { + // TODO: Make item decay an option on the spawner + return (Movable && Visible/* && Spawner == null*/); + } + } + + public virtual bool OnDecay() + { + return ( Decays && Parent == null && Map != Map.Internal && Region.Find( Location, Map ).OnDecay( this ) ); + } + + public void SetLastMoved() + { + m_LastMovedTime = DateTime.Now; + } + + public DateTime LastMoved + { + get + { + return m_LastMovedTime; + } + set + { + m_LastMovedTime = value; + } + } + + public bool StackWith( Mobile from, Item dropped ) + { + return StackWith( from, dropped, true ); + } + + public virtual bool StackWith(Mobile from, Item dropped, bool playSound) + { + if (dropped.Stackable && Stackable && dropped.GetType() == GetType() && dropped.ItemID == ItemID && dropped.Hue == Hue && dropped.Name == Name && (dropped.Amount + Amount) <= 60000 && dropped != this && !dropped.Nontransferable && !Nontransferable) + { + if ( m_LootType != dropped.m_LootType ) + m_LootType = LootType.Regular; + + Amount += dropped.Amount; + dropped.Delete(); + + if ( playSound && from != null ) + { + int soundID = GetDropSound(); + + if ( soundID == -1 ) + soundID = 0x42; + + from.SendSound( soundID, GetWorldLocation() ); + } + + return true; + } + + return false; + } + + public virtual bool OnDragDrop( Mobile from, Item dropped ) + { + if ( Parent is Container ) + return ((Container)Parent).OnStackAttempt( from, this, dropped ); + + return StackWith( from, dropped ); + } + + public Rectangle2D GetGraphicBounds() + { + int itemID = m_ItemID; + bool doubled = m_Amount > 1; + + if ( itemID >= 0xEEA && itemID <= 0xEF2 ) // Are we coins? + { + int coinBase = (itemID - 0xEEA) / 3; + coinBase *= 3; + coinBase += 0xEEA; + + doubled = false; + + if ( m_Amount <= 1 ) + { + // A single coin + itemID = coinBase; + } + else if ( m_Amount <= 5 ) + { + // A stack of coins + itemID = coinBase + 1; + } + else // m_Amount > 5 + { + // A pile of coins + itemID = coinBase + 2; + } + } + + Rectangle2D bounds = ItemBounds.Table[itemID & 0x3FFF]; + + if ( doubled ) + { + bounds.Set( bounds.X, bounds.Y, bounds.Width + 5, bounds.Height + 5 ); + } + + return bounds; + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Stackable + { + get{ return GetFlag( ImplFlag.Stackable ); } + set{ SetFlag( ImplFlag.Stackable, value ); } + } + + public Packet RemovePacket + { + get + { + if ( m_RemovePacket == null ) + { + m_RemovePacket = new RemoveItem( this ); + m_RemovePacket.SetStatic(); + } + + return m_RemovePacket; + } + } + + public Packet OPLPacket + { + get + { + if ( m_OPLPacket == null ) + { + m_OPLPacket = new OPLInfo( PropertyList ); + m_OPLPacket.SetStatic(); + } + + return m_OPLPacket; + } + } + + public ObjectPropertyList PropertyList + { + get + { + if ( m_PropertyList == null ) + { + m_PropertyList = new ObjectPropertyList( this ); + + GetProperties( m_PropertyList ); + AppendChildProperties( m_PropertyList ); + + m_PropertyList.Terminate(); + m_PropertyList.SetStatic(); + } + + return m_PropertyList; + } + } + + public virtual void AppendChildProperties( ObjectPropertyList list ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).GetChildProperties( list, this ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).GetChildProperties( list, this ); + } + + public virtual void AppendChildNameProperties( ObjectPropertyList list ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).GetChildNameProperties( list, this ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).GetChildNameProperties( list, this ); + } + + public void ClearProperties() + { + Packet.Release( ref m_PropertyList ); + Packet.Release( ref m_OPLPacket ); + } + + public void InvalidateProperties() + { + if ( !ObjectPropertyList.Enabled ) + return; + + if ( m_Map != null && m_Map != Map.Internal && !World.Loading ) + { + ObjectPropertyList oldList = m_PropertyList; + m_PropertyList = null; + ObjectPropertyList newList = PropertyList; + + if ( oldList == null || oldList.Hash != newList.Hash ) + { + Packet.Release( ref m_OPLPacket ); + Delta( ItemDelta.Properties ); + } + } + else + { + ClearProperties(); + } + } + + public Packet WorldPacket + { + get + { + // This needs to be invalidated when any of the following changes: + // - ItemID + // - Amount + // - Location + // - Hue + // - Packet Flags + // - Direction + + if ( m_WorldPacket == null ) + { + m_WorldPacket = new WorldItem( this ); + m_WorldPacket.SetStatic(); + } + + return m_WorldPacket; + } + } + + public Packet WorldPacketSA + { + get + { + // This needs to be invalidated when any of the following changes: + // - ItemID + // - Amount + // - Location + // - Hue + // - Packet Flags + // - Direction + + if ( m_WorldPacketSA == null ) + { + m_WorldPacketSA = new WorldItemSA( this ); + m_WorldPacketSA.SetStatic(); + } + + return m_WorldPacketSA; + } + } + + public Packet WorldPacketHS + { + get + { + // This needs to be invalidated when any of the following changes: + // - ItemID + // - Amount + // - Location + // - Hue + // - Packet Flags + // - Direction + + if ( m_WorldPacketHS == null ) + { + m_WorldPacketHS = new WorldItemHS( this ); + m_WorldPacketHS.SetStatic(); + } + + return m_WorldPacketHS; + } + } + + public void ReleaseWorldPackets() + { + Packet.Release( ref m_WorldPacket ); + Packet.Release( ref m_WorldPacketSA ); + Packet.Release( ref m_WorldPacketHS ); + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Visible + { + get{ return GetFlag( ImplFlag.Visible ); } + set + { + if ( GetFlag( ImplFlag.Visible ) != value ) + { + SetFlag( ImplFlag.Visible, value ); + ReleaseWorldPackets(); + + if ( m_Map != null ) + { + Packet removeThis = null; + Point3D worldLoc = GetWorldLocation(); + + IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( !m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) + { + if ( removeThis == null ) + removeThis = this.RemovePacket; + + state.Send( removeThis ); + } + } + + eable.Free(); + } + + Delta( ItemDelta.Update ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Movable + { + get{ return GetFlag( ImplFlag.Movable ); } + set + { + if ( GetFlag( ImplFlag.Movable ) != value ) + { + SetFlag( ImplFlag.Movable, value ); + ReleaseWorldPackets(); + Delta( ItemDelta.Update ); + } + } + } + + public virtual bool ForceShowProperties{ get{ return false; } } + + public virtual int GetPacketFlags() + { + int flags = 0; + + if ( !Visible ) + flags |= 0x80; + + if ( Movable || ForceShowProperties ) + flags |= 0x20; + + return flags; + } + + public virtual bool OnMoveOff( Mobile m ) + { + return true; + } + + public virtual bool OnMoveOver( Mobile m ) + { + return true; + } + + public virtual bool HandlesOnMovement{ get{ return false; } } + + public virtual void OnMovement( Mobile m, Point3D oldLocation ) + { + } + + public void Internalize() + { + MoveToWorld( Point3D.Zero, Map.Internal ); + } + + public virtual void OnMapChange() + { + } + + public virtual void OnRemoved( object parent ) + { + } + + public virtual void OnAdded( object parent ) + { + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Map Map + { + get + { + return m_Map; + } + set + { + if ( m_Map != value ) + { + Map old = m_Map; + + if ( m_Map != null && m_Parent == null ) + { + m_Map.OnLeave( this ); + SendRemovePacket(); + } + + List items = LookupItems(); + + if ( items != null ) + { + for ( int i = 0; i < items.Count; ++i ) + items[i].Map = value; + } + + m_Map = value; + + if ( m_Map != null && m_Parent == null ) + m_Map.OnEnter( this ); + + Delta( ItemDelta.Update ); + + this.OnMapChange(); + + if ( old == null || old == Map.Internal ) + InvalidateProperties(); + } + } + } + + [Flags] + private enum SaveFlag + { + None = 0x00000000, + Direction = 0x00000001, + Bounce = 0x00000002, + LootType = 0x00000004, + LocationFull = 0x00000008, + ItemID = 0x00000010, + Hue = 0x00000020, + Amount = 0x00000040, + Layer = 0x00000080, + Name = 0x00000100, + Parent = 0x00000200, + Items = 0x00000400, + WeightNot1or0 = 0x00000800, + Map = 0x00001000, + Visible = 0x00002000, + Movable = 0x00004000, + Stackable = 0x00008000, + WeightIs0 = 0x00010000, + LocationSByteZ = 0x00020000, + LocationShortXY = 0x00040000, + LocationByteXY = 0x00080000, + ImplFlags = 0x00100000, + InsuredFor = 0x00200000, + BlessedFor = 0x00400000, + HeldBy = 0x00800000, + IntWeight = 0x01000000, + SavedFlags = 0x02000000, + NullWeight = 0x04000000 + } + + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + int ISerializable.TypeReference { + get { return m_TypeRef; } + } + + int ISerializable.SerialIdentity { + get { return m_Serial; } + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.Write( 10 ); // version + + // Scriptiz : version 10 + writer.Write(m_Lootable); + writer.Write(m_Stealable); + + // Scriptiz : version 9 before my edit + SaveFlag flags = SaveFlag.None; + + int x = m_Location.m_X, y = m_Location.m_Y, z = m_Location.m_Z; + + if ( x != 0 || y != 0 || z != 0 ) + { + if ( x >= short.MinValue && x <= short.MaxValue && y >= short.MinValue && y <= short.MaxValue && z >= sbyte.MinValue && z <= sbyte.MaxValue ) + { + if ( x != 0 || y != 0 ) + { + if ( x >= byte.MinValue && x <= byte.MaxValue && y >= byte.MinValue && y <= byte.MaxValue ) + flags |= SaveFlag.LocationByteXY; + else + flags |= SaveFlag.LocationShortXY; + } + + if ( z != 0 ) + flags |= SaveFlag.LocationSByteZ; + } + else + { + flags |= SaveFlag.LocationFull; + } + } + + CompactInfo info = LookupCompactInfo(); + List items = LookupItems(); + + if ( m_Direction != Direction.North ) + flags |= SaveFlag.Direction; + if ( info != null && info.m_Bounce != null ) + flags |= SaveFlag.Bounce; + if ( m_LootType != LootType.Regular ) + flags |= SaveFlag.LootType; + if ( m_ItemID != 0 ) + flags |= SaveFlag.ItemID; + if ( m_Hue != 0 ) + flags |= SaveFlag.Hue; + if ( m_Amount != 1 ) + flags |= SaveFlag.Amount; + if ( m_Layer != Layer.Invalid ) + flags |= SaveFlag.Layer; + if ( info != null && info.m_Name != null ) + flags |= SaveFlag.Name; + if ( m_Parent != null ) + flags |= SaveFlag.Parent; + if ( items != null && items.Count > 0 ) + flags |= SaveFlag.Items; + if ( m_Map != Map.Internal ) + flags |= SaveFlag.Map; + //if ( m_InsuredFor != null && !m_InsuredFor.Deleted ) + //flags |= SaveFlag.InsuredFor; + if ( info != null && info.m_BlessedFor != null && !info.m_BlessedFor.Deleted ) + flags |= SaveFlag.BlessedFor; + if ( info != null && info.m_HeldBy != null && !info.m_HeldBy.Deleted ) + flags |= SaveFlag.HeldBy; + if ( info != null && info.m_SavedFlags != 0 ) + flags |= SaveFlag.SavedFlags; + + if ( info == null || info.m_Weight == -1 ) + { + flags |= SaveFlag.NullWeight; + } + else + { + if ( info.m_Weight == 0.0 ) + { + flags |= SaveFlag.WeightIs0; + } + else if ( info.m_Weight != 1.0 ) + { + if ( info.m_Weight == (int) info.m_Weight ) + flags |= SaveFlag.IntWeight; + else + flags |= SaveFlag.WeightNot1or0; + } + } + + ImplFlag implFlags = ( m_Flags & ( ImplFlag.Visible | ImplFlag.Movable | ImplFlag.Stackable | ImplFlag.Insured | ImplFlag.PayedInsurance | ImplFlag.QuestItem ) ); + + if ( implFlags != ( ImplFlag.Visible | ImplFlag.Movable ) ) + flags |= SaveFlag.ImplFlags; + + writer.Write( (int) flags ); + + /* begin last moved time optimization */ + long ticks = m_LastMovedTime.Ticks; + long now = DateTime.Now.Ticks; + + TimeSpan d; + + try { d = new TimeSpan( ticks - now ); } + catch { if ( ticks < now ) d = TimeSpan.MaxValue; else d = TimeSpan.MaxValue; } + + double minutes = -d.TotalMinutes; + + if ( minutes < int.MinValue ) + minutes = int.MinValue; + else if ( minutes > int.MaxValue ) + minutes = int.MaxValue; + + writer.WriteEncodedInt( (int) minutes ); + /* end */ + + if ( GetSaveFlag( flags, SaveFlag.Direction ) ) + writer.Write( (byte) m_Direction ); + + if ( GetSaveFlag( flags, SaveFlag.Bounce ) ) + BounceInfo.Serialize( info.m_Bounce, writer ); + + if ( GetSaveFlag( flags, SaveFlag.LootType ) ) + writer.Write( (byte) m_LootType ); + + if ( GetSaveFlag( flags, SaveFlag.LocationFull ) ) + { + writer.WriteEncodedInt( x ); + writer.WriteEncodedInt( y ); + writer.WriteEncodedInt( z ); + } + else + { + if ( GetSaveFlag( flags, SaveFlag.LocationByteXY ) ) + { + writer.Write( (byte) x ); + writer.Write( (byte) y ); + } + else if ( GetSaveFlag( flags, SaveFlag.LocationShortXY ) ) + { + writer.Write( (short) x ); + writer.Write( (short) y ); + } + + if ( GetSaveFlag( flags, SaveFlag.LocationSByteZ ) ) + writer.Write( (sbyte) z ); + } + + if ( GetSaveFlag( flags, SaveFlag.ItemID ) ) + writer.WriteEncodedInt( (int) m_ItemID ); + + if ( GetSaveFlag( flags, SaveFlag.Hue ) ) + writer.WriteEncodedInt( (int) m_Hue ); + + if ( GetSaveFlag( flags, SaveFlag.Amount ) ) + writer.WriteEncodedInt( (int) m_Amount ); + + if ( GetSaveFlag( flags, SaveFlag.Layer ) ) + writer.Write( (byte) m_Layer ); + + if ( GetSaveFlag( flags, SaveFlag.Name ) ) + writer.Write( (string) info.m_Name ); + + if ( GetSaveFlag( flags, SaveFlag.Parent ) ) + { + if ( m_Parent is Mobile && !( (Mobile) m_Parent ).Deleted ) + writer.Write( ( (Mobile) m_Parent ).Serial ); + else if ( m_Parent is Item && !( (Item) m_Parent ).Deleted ) + writer.Write( ( (Item) m_Parent ).Serial ); + else + writer.Write( (int) Serial.MinusOne ); + } + + if ( GetSaveFlag( flags, SaveFlag.Items ) ) + writer.Write( items, false ); + + if ( GetSaveFlag( flags, SaveFlag.IntWeight ) ) + writer.WriteEncodedInt( (int) info.m_Weight ); + else if ( GetSaveFlag( flags, SaveFlag.WeightNot1or0 ) ) + writer.Write( (double) info.m_Weight ); + + if ( GetSaveFlag( flags, SaveFlag.Map ) ) + writer.Write( (Map) m_Map ); + + if ( GetSaveFlag( flags, SaveFlag.ImplFlags ) ) + writer.WriteEncodedInt( (int) implFlags ); + + if ( GetSaveFlag( flags, SaveFlag.InsuredFor ) ) + writer.Write( (Mobile) null ); + + if ( GetSaveFlag( flags, SaveFlag.BlessedFor ) ) + writer.Write( info.m_BlessedFor ); + + if ( GetSaveFlag( flags, SaveFlag.HeldBy ) ) + writer.Write( info.m_HeldBy ); + + if ( GetSaveFlag( flags, SaveFlag.SavedFlags ) ) + writer.WriteEncodedInt( info.m_SavedFlags ); + } + + public IPooledEnumerable GetObjectsInRange( int range ) + { + Map map = m_Map; + + if ( map == null ) + return Server.Map.NullEnumerable.Instance; + + if ( m_Parent == null ) + return map.GetObjectsInRange( m_Location, range ); + + return map.GetObjectsInRange( GetWorldLocation(), range ); + } + + public IPooledEnumerable GetItemsInRange( int range ) + { + Map map = m_Map; + + if ( map == null ) + return Server.Map.NullEnumerable.Instance; + + if ( m_Parent == null ) + return map.GetItemsInRange( m_Location, range ); + + return map.GetItemsInRange( GetWorldLocation(), range ); + } + + public IPooledEnumerable GetMobilesInRange( int range ) + { + Map map = m_Map; + + if ( map == null ) + return Server.Map.NullEnumerable.Instance; + + if ( m_Parent == null ) + return map.GetMobilesInRange( m_Location, range ); + + return map.GetMobilesInRange( GetWorldLocation(), range ); + } + + public IPooledEnumerable GetClientsInRange( int range ) + { + Map map = m_Map; + + if ( map == null ) + return Server.Map.NullEnumerable.Instance; + + if ( m_Parent == null ) + return map.GetClientsInRange( m_Location, range ); + + return map.GetClientsInRange( GetWorldLocation(), range ); + } + + private static int m_LockedDownFlag; + private static int m_SecureFlag; + + public static int LockedDownFlag + { + get{ return m_LockedDownFlag; } + set{ m_LockedDownFlag = value; } + } + + public static int SecureFlag + { + get{ return m_SecureFlag; } + set{ m_SecureFlag = value; } + } + + public bool IsLockedDown + { + get{ return GetTempFlag( m_LockedDownFlag ); } + set{ SetTempFlag( m_LockedDownFlag, value ); InvalidateProperties(); } + } + + public bool IsSecure + { + get{ return GetTempFlag( m_SecureFlag ); } + set{ SetTempFlag( m_SecureFlag, value ); InvalidateProperties(); } + } + + public bool GetTempFlag( int flag ) + { + CompactInfo info = LookupCompactInfo(); + + if ( info == null ) + return false; + + return ( (info.m_TempFlags & flag) != 0 ); + } + + public void SetTempFlag( int flag, bool value ) + { + CompactInfo info = AcquireCompactInfo(); + + if ( value ) + info.m_TempFlags |= flag; + else + info.m_TempFlags &= ~flag; + + if ( info.m_TempFlags == 0 ) + VerifyCompactInfo(); + } + + public bool GetSavedFlag( int flag ) + { + CompactInfo info = LookupCompactInfo(); + + if ( info == null ) + return false; + + return ( ( info.m_SavedFlags & flag ) != 0 ); + } + + public void SetSavedFlag( int flag, bool value ) + { + CompactInfo info = AcquireCompactInfo(); + + if ( value ) + info.m_SavedFlags |= flag; + else + info.m_SavedFlags &= ~flag; + + if ( info.m_SavedFlags == 0 ) + VerifyCompactInfo(); + } + + public virtual void Deserialize( GenericReader reader ) + { + int version = reader.ReadInt(); + + SetLastMoved(); + + switch ( version ) + { + // Scriptiz : case 10 + case 10: + { + m_Lootable = reader.ReadBool(); + m_Stealable = reader.ReadBool(); + goto case 9; + } + case 9: + case 8: + case 7: + case 6: + { + SaveFlag flags = (SaveFlag)reader.ReadInt(); + + if ( version < 7 ) + { + LastMoved = reader.ReadDeltaTime(); + } + else + { + int minutes = reader.ReadEncodedInt(); + + try{ LastMoved = DateTime.Now - TimeSpan.FromMinutes( minutes ); } + catch{ LastMoved = DateTime.Now; } + } + + if ( GetSaveFlag( flags, SaveFlag.Direction ) ) + m_Direction = (Direction)reader.ReadByte(); + + if ( GetSaveFlag( flags, SaveFlag.Bounce ) ) + AcquireCompactInfo().m_Bounce = BounceInfo.Deserialize( reader ); + + if ( GetSaveFlag( flags, SaveFlag.LootType ) ) + m_LootType = (LootType)reader.ReadByte(); + + int x = 0, y = 0, z = 0; + + if ( GetSaveFlag( flags, SaveFlag.LocationFull ) ) + { + x = reader.ReadEncodedInt(); + y = reader.ReadEncodedInt(); + z = reader.ReadEncodedInt(); + } + else + { + if ( GetSaveFlag( flags, SaveFlag.LocationByteXY ) ) + { + x = reader.ReadByte(); + y = reader.ReadByte(); + } + else if ( GetSaveFlag( flags, SaveFlag.LocationShortXY ) ) + { + x = reader.ReadShort(); + y = reader.ReadShort(); + } + + if ( GetSaveFlag( flags, SaveFlag.LocationSByteZ ) ) + z = reader.ReadSByte(); + } + + m_Location = new Point3D( x, y, z ); + + if ( GetSaveFlag( flags, SaveFlag.ItemID ) ) + m_ItemID = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Hue ) ) + m_Hue = reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.Amount ) ) + m_Amount = reader.ReadEncodedInt(); + else + m_Amount = 1; + + if ( GetSaveFlag( flags, SaveFlag.Layer ) ) + m_Layer = (Layer)reader.ReadByte(); + + if ( GetSaveFlag( flags, SaveFlag.Name ) ) + { + string name = reader.ReadString(); + + if ( name != this.DefaultName ) + AcquireCompactInfo().m_Name = name; + } + + if ( GetSaveFlag( flags, SaveFlag.Parent ) ) + { + Serial parent = reader.ReadInt(); + + if ( parent.IsMobile ) + m_Parent = World.FindMobile( parent ); + else if ( parent.IsItem ) + m_Parent = World.FindItem( parent ); + else + m_Parent = null; + + if ( m_Parent == null && (parent.IsMobile || parent.IsItem) ) + Delete(); + } + + if ( GetSaveFlag( flags, SaveFlag.Items ) ) + { + List items = reader.ReadStrongItemList(); + + if ( this is Container ) + ( this as Container ).m_Items = items; + else + AcquireCompactInfo().m_Items = items; + } + + if ( version < 8 || !GetSaveFlag( flags, SaveFlag.NullWeight ) ) + { + double weight; + + if ( GetSaveFlag( flags, SaveFlag.IntWeight ) ) + weight = reader.ReadEncodedInt(); + else if ( GetSaveFlag( flags, SaveFlag.WeightNot1or0 ) ) + weight = reader.ReadDouble(); + else if ( GetSaveFlag( flags, SaveFlag.WeightIs0 ) ) + weight = 0.0; + else + weight = 1.0; + + if ( weight != DefaultWeight ) + AcquireCompactInfo().m_Weight = weight; + } + + if ( GetSaveFlag( flags, SaveFlag.Map ) ) + m_Map = reader.ReadMap(); + else + m_Map = Map.Internal; + + if ( GetSaveFlag( flags, SaveFlag.Visible ) ) + SetFlag( ImplFlag.Visible, reader.ReadBool() ); + else + SetFlag( ImplFlag.Visible, true ); + + if ( GetSaveFlag( flags, SaveFlag.Movable ) ) + SetFlag( ImplFlag.Movable, reader.ReadBool() ); + else + SetFlag( ImplFlag.Movable, true ); + + if ( GetSaveFlag( flags, SaveFlag.Stackable ) ) + SetFlag( ImplFlag.Stackable, reader.ReadBool() ); + + if ( GetSaveFlag( flags, SaveFlag.ImplFlags ) ) + m_Flags = (ImplFlag)reader.ReadEncodedInt(); + + if ( GetSaveFlag( flags, SaveFlag.InsuredFor ) ) + /*m_InsuredFor = */reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.BlessedFor ) ) + AcquireCompactInfo().m_BlessedFor = reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.HeldBy ) ) + AcquireCompactInfo().m_HeldBy = reader.ReadMobile(); + + if ( GetSaveFlag( flags, SaveFlag.SavedFlags ) ) + AcquireCompactInfo().m_SavedFlags = reader.ReadEncodedInt(); + + if ( m_Map != null && m_Parent == null ) + m_Map.OnEnter( this ); + + break; + } + case 5: + { + SaveFlag flags = (SaveFlag)reader.ReadInt(); + + LastMoved = reader.ReadDeltaTime(); + + if ( GetSaveFlag( flags, SaveFlag.Direction ) ) + m_Direction = (Direction)reader.ReadByte(); + + if ( GetSaveFlag( flags, SaveFlag.Bounce ) ) + AcquireCompactInfo().m_Bounce = BounceInfo.Deserialize( reader ); + + if ( GetSaveFlag( flags, SaveFlag.LootType ) ) + m_LootType = (LootType)reader.ReadByte(); + + if ( GetSaveFlag( flags, SaveFlag.LocationFull ) ) + m_Location = reader.ReadPoint3D(); + + if ( GetSaveFlag( flags, SaveFlag.ItemID ) ) + m_ItemID = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Hue ) ) + m_Hue = reader.ReadInt(); + + if ( GetSaveFlag( flags, SaveFlag.Amount ) ) + m_Amount = reader.ReadInt(); + else + m_Amount = 1; + + if ( GetSaveFlag( flags, SaveFlag.Layer ) ) + m_Layer = (Layer)reader.ReadByte(); + + if ( GetSaveFlag( flags, SaveFlag.Name ) ) + { + string name = reader.ReadString(); + + if ( name != this.DefaultName ) + AcquireCompactInfo().m_Name = name; + } + + if ( GetSaveFlag( flags, SaveFlag.Parent ) ) + { + Serial parent = reader.ReadInt(); + + if ( parent.IsMobile ) + m_Parent = World.FindMobile( parent ); + else if ( parent.IsItem ) + m_Parent = World.FindItem( parent ); + else + m_Parent = null; + + if ( m_Parent == null && (parent.IsMobile || parent.IsItem) ) + Delete(); + } + + if ( GetSaveFlag( flags, SaveFlag.Items ) ) + { + List items = reader.ReadStrongItemList(); + + if ( this is Container ) + ( this as Container ).m_Items = items; + else + AcquireCompactInfo().m_Items = items; + } + + double weight; + + if ( GetSaveFlag( flags, SaveFlag.IntWeight ) ) + weight = reader.ReadEncodedInt(); + else if ( GetSaveFlag( flags, SaveFlag.WeightNot1or0 ) ) + weight = reader.ReadDouble(); + else if ( GetSaveFlag( flags, SaveFlag.WeightIs0 ) ) + weight = 0.0; + else + weight = 1.0; + + if ( weight != DefaultWeight ) + AcquireCompactInfo().m_Weight = weight; + + if ( GetSaveFlag( flags, SaveFlag.Map ) ) + m_Map = reader.ReadMap(); + else + m_Map = Map.Internal; + + if ( GetSaveFlag( flags, SaveFlag.Visible ) ) + SetFlag( ImplFlag.Visible, reader.ReadBool() ); + else + SetFlag( ImplFlag.Visible, true ); + + if ( GetSaveFlag( flags, SaveFlag.Movable ) ) + SetFlag( ImplFlag.Movable, reader.ReadBool() ); + else + SetFlag( ImplFlag.Movable, true ); + + if ( GetSaveFlag( flags, SaveFlag.Stackable ) ) + SetFlag( ImplFlag.Stackable, reader.ReadBool() ); + + if ( m_Map != null && m_Parent == null ) + m_Map.OnEnter( this ); + + break; + } + case 4: // Just removed variables + case 3: + { + m_Direction = (Direction)reader.ReadInt(); + + goto case 2; + } + case 2: + { + AcquireCompactInfo().m_Bounce = BounceInfo.Deserialize( reader ); + LastMoved = reader.ReadDeltaTime(); + + goto case 1; + } + case 1: + { + m_LootType = (LootType) reader.ReadByte();//m_Newbied = reader.ReadBool(); + + goto case 0; + } + case 0: + { + m_Location = reader.ReadPoint3D(); + m_ItemID = reader.ReadInt(); + m_Hue = reader.ReadInt(); + m_Amount = reader.ReadInt(); + m_Layer = (Layer) reader.ReadByte(); + + string name = reader.ReadString(); + + if ( name != this.DefaultName ) + AcquireCompactInfo().m_Name = name; + + Serial parent = reader.ReadInt(); + + if ( parent.IsMobile ) + m_Parent = World.FindMobile( parent ); + else if ( parent.IsItem ) + m_Parent = World.FindItem( parent ); + else + m_Parent = null; + + if ( m_Parent == null && (parent.IsMobile || parent.IsItem) ) + Delete(); + + int count = reader.ReadInt(); + + if ( count > 0 ) + { + List items = new List( count ); + + for ( int i = 0; i < count; ++i ) + { + Item item = reader.ReadItem(); + + if ( item != null ) + items.Add( item ); + } + + if ( this is Container ) + ( this as Container ).m_Items = items; + else + AcquireCompactInfo().m_Items = items; + } + + double weight = reader.ReadDouble(); + + if ( weight != DefaultWeight ) + AcquireCompactInfo().m_Weight = weight; + + if ( version <= 3 ) + { + reader.ReadInt(); + reader.ReadInt(); + reader.ReadInt(); + } + + m_Map = reader.ReadMap(); + SetFlag( ImplFlag.Visible, reader.ReadBool() ); + SetFlag( ImplFlag.Movable, reader.ReadBool() ); + + if ( version <= 3 ) + /*m_Deleted =*/ reader.ReadBool(); + + Stackable = reader.ReadBool(); + + if ( m_Map != null && m_Parent == null ) + m_Map.OnEnter( this ); + + break; + } + } + + if ( this.HeldBy != null ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixHolding_Sandbox ) ); + + //if ( version < 9 ) + VerifyCompactInfo(); + } + + private void FixHolding_Sandbox() + { + Mobile heldBy = this.HeldBy; + + if ( heldBy != null ) + { + if ( this.GetBounce() != null ) + { + Bounce( heldBy ); + } + else + { + heldBy.Holding = null; + heldBy.AddToBackpack( this ); + ClearBounce(); + } + } + } + + public virtual int GetMaxUpdateRange() + { + return 18; + } + + public virtual int GetUpdateRange( Mobile m ) + { + return 18; + } + + public void SendInfoTo( NetState state ) { + SendInfoTo( state, ObjectPropertyList.Enabled ); + } + + public virtual void SendInfoTo( NetState state, bool sendOplPacket ) { + state.Send( GetWorldPacketFor( state ) ); + + if ( sendOplPacket ) { + state.Send( OPLPacket ); + } + } + + protected virtual Packet GetWorldPacketFor( NetState state ) { + if ( state.HighSeas ) + return this.WorldPacketHS; + else if ( state.StygianAbyss ) + return this.WorldPacketSA; + else + return this.WorldPacket; + } + + public virtual bool IsVirtualItem{ get{ return false; } } + + public virtual int GetTotal( TotalType type ) + { + return 0; + } + + public virtual void UpdateTotal( Item sender, TotalType type, int delta ) + { + if ( !IsVirtualItem ) + { + if ( m_Parent is Item ) + ( m_Parent as Item ).UpdateTotal( sender, type, delta ); + else if ( m_Parent is Mobile ) + ( m_Parent as Mobile ).UpdateTotal( sender, type, delta ); + else if ( this.HeldBy != null ) + ( this.HeldBy as Mobile ).UpdateTotal( sender, type, delta ); + } + } + + public virtual void UpdateTotals() + { + } + + public virtual int LabelNumber + { + get + { + if ( m_ItemID < 0x4000 ) + return 1020000 + m_ItemID; + else + return 1078872 + m_ItemID; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalGold + { + get { return GetTotal( TotalType.Gold ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalItems + { + get { return GetTotal( TotalType.Items ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalWeight + { + get { return GetTotal( TotalType.Weight ); } + } + + public virtual double DefaultWeight + { + get + { + if ( m_ItemID < 0 || m_ItemID > TileData.MaxItemValue || this is BaseMulti ) + return 0; + + int weight = TileData.ItemTable[m_ItemID].Weight; + + if ( weight == 255 || weight == 0 ) + weight = 1; + + return weight; + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public double Weight + { + get + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null && info.m_Weight != -1 ) + return info.m_Weight; + + return this.DefaultWeight; + } + set + { + if ( this.Weight != value ) + { + CompactInfo info = AcquireCompactInfo(); + + int oldPileWeight = this.PileWeight; + + info.m_Weight = value; + + if ( info.m_Weight == -1 ) + VerifyCompactInfo(); + + int newPileWeight = this.PileWeight; + + UpdateTotal( this, TotalType.Weight, newPileWeight - oldPileWeight ); + + InvalidateProperties(); + } + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int PileWeight + { + get + { + return (int)Math.Ceiling( this.Weight * this.Amount ); + } + } + + public virtual int HuedItemID + { + get + { + return m_ItemID; + } + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public virtual int Hue + { + get + { + return m_Hue; + } + set + { + if ( m_Hue != value ) + { + m_Hue = value; + ReleaseWorldPackets(); + + Delta( ItemDelta.Update ); + } + } + } + + public const int QuestItemHue = 0x4EA; // Hmmmm... "for EA"? + + public virtual bool Nontransferable + { + get { return QuestItem; } + } + + public virtual void HandleInvalidTransfer( Mobile from ) + { + // OSI sends 1074769, bug! + if (QuestItem) + from.SendLocalizedMessage(1049343); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest. + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual Layer Layer + { + get + { + return m_Layer; + } + set + { + if ( m_Layer != value ) + { + m_Layer = value; + + Delta( ItemDelta.EquipOnly ); + } + } + } + + public List Items + { + get + { + List items = LookupItems(); + + if( items == null ) + items = EmptyItems; + + return items; + } + } + + public object RootParent + { + get + { + object p = m_Parent; + + while ( p is Item ) + { + Item item = (Item)p; + + if ( item.m_Parent == null ) + { + break; + } + else + { + p = item.m_Parent; + } + } + + return p; + } + } + + public bool ParentsContain() where T : Item + { + object p = m_Parent; + + while( p is Item ) + { + if( p is T ) + return true; + + Item item = (Item)p; + + if( item.m_Parent == null ) + { + break; + } + else + { + p = item.m_Parent; + } + } + + return false; + } + + public virtual void AddItem( Item item ) + { + if ( item == null || item.Deleted || item.m_Parent == this ) + { + return; + } + else if ( item == this ) + { + Console.WriteLine( "Warning: Adding item to itself: [0x{0:X} {1}].AddItem( [0x{2:X} {3}] )", this.Serial.Value, this.GetType().Name, item.Serial.Value, item.GetType().Name ); + Console.WriteLine( new System.Diagnostics.StackTrace() ); + return; + } + else if ( IsChildOf( item ) ) + { + Console.WriteLine( "Warning: Adding parent item to child: [0x{0:X} {1}].AddItem( [0x{2:X} {3}] )", this.Serial.Value, this.GetType().Name, item.Serial.Value, item.GetType().Name ); + Console.WriteLine( new System.Diagnostics.StackTrace() ); + return; + } + else if ( item.m_Parent is Mobile ) + { + ((Mobile)item.m_Parent).RemoveItem( item ); + } + else if ( item.m_Parent is Item ) + { + ((Item)item.m_Parent).RemoveItem( item ); + } + else + { + item.SendRemovePacket(); + } + + item.Parent = this; + item.Map = m_Map; + + List items = AcquireItems(); + + items.Add( item ); + + if ( !item.IsVirtualItem ) + { + UpdateTotal( item, TotalType.Gold, item.TotalGold ); + UpdateTotal( item, TotalType.Items, item.TotalItems + 1 ); + UpdateTotal( item, TotalType.Weight, item.TotalWeight + item.PileWeight ); + } + + item.Delta( ItemDelta.Update ); + + item.OnAdded( this ); + OnItemAdded( item ); + } + + private static List m_DeltaQueue = new List(); + + public void Delta( ItemDelta flags ) + { + if ( m_Map == null || m_Map == Map.Internal ) + return; + + m_DeltaFlags |= flags; + + if ( !GetFlag( ImplFlag.InQueue ) ) + { + SetFlag( ImplFlag.InQueue, true ); + + m_DeltaQueue.Add( this ); + } + + Core.Set(); + } + + public void RemDelta( ItemDelta flags ) + { + m_DeltaFlags &= ~flags; + + if ( GetFlag( ImplFlag.InQueue ) && m_DeltaFlags == ItemDelta.None ) + { + SetFlag( ImplFlag.InQueue, false ); + + m_DeltaQueue.Remove( this ); + } + } + + private bool m_NoMoveHS; + + public bool NoMoveHS + { + get { return m_NoMoveHS; } + set { m_NoMoveHS = value; } + } + + public void ProcessDelta() + { + ItemDelta flags = m_DeltaFlags; + + SetFlag( ImplFlag.InQueue, false ); + m_DeltaFlags = ItemDelta.None; + + Map map = m_Map; + + if ( map != null && !Deleted ) + { + bool sendOPLUpdate = ObjectPropertyList.Enabled && (flags & ItemDelta.Properties) != 0; + + Container contParent = m_Parent as Container; + + if ( contParent != null && !contParent.IsPublicContainer ) + { + if ( (flags & ItemDelta.Update) != 0 ) + { + Point3D worldLoc = GetWorldLocation(); + + Mobile rootParent = contParent.RootParent as Mobile; + Mobile tradeRecip = null; + + if ( rootParent != null ) + { + NetState ns = rootParent.NetState; + + if ( ns != null ) + { + if ( rootParent.CanSee( this ) && rootParent.InRange( worldLoc, GetUpdateRange( rootParent ) ) ) + { + if ( ns.ContainerGridLines ) + ns.Send( new ContainerContentUpdate6017( this ) ); + else + ns.Send( new ContainerContentUpdate( this ) ); + + if ( ObjectPropertyList.Enabled ) + ns.Send( OPLPacket ); + } + } + } + + SecureTradeContainer stc = this.GetSecureTradeCont(); + + if ( stc != null ) + { + SecureTrade st = stc.Trade; + + if ( st != null ) + { + Mobile test = st.From.Mobile; + + if ( test != null && test != rootParent ) + tradeRecip = test; + + test = st.To.Mobile; + + if ( test != null && test != rootParent ) + tradeRecip = test; + + if ( tradeRecip != null ) + { + NetState ns = tradeRecip.NetState; + + if ( ns != null ) + { + if ( tradeRecip.CanSee( this ) && tradeRecip.InRange( worldLoc, GetUpdateRange( tradeRecip ) ) ) + { + if ( ns.ContainerGridLines ) + ns.Send( new ContainerContentUpdate6017( this ) ); + else + ns.Send( new ContainerContentUpdate( this ) ); + + if ( ObjectPropertyList.Enabled ) + ns.Send( OPLPacket ); + } + } + } + } + } + + List openers = contParent.Openers; + + if ( openers != null ) + { + for ( int i = 0; i < openers.Count; ++i ) + { + Mobile mob = openers[i]; + + int range = GetUpdateRange( mob ); + + if ( mob.Map != map || !mob.InRange( worldLoc, range ) ) + { + openers.RemoveAt( i-- ); + } + else + { + if ( mob == rootParent || mob == tradeRecip ) + continue; + + NetState ns = mob.NetState; + + if ( ns != null ) + { + if ( mob.CanSee( this ) ) + { + if ( ns.ContainerGridLines ) + ns.Send( new ContainerContentUpdate6017( this ) ); + else + ns.Send( new ContainerContentUpdate( this ) ); + + if ( ObjectPropertyList.Enabled ) + ns.Send( OPLPacket ); + } + } + } + } + + if ( openers.Count == 0 ) + contParent.Openers = null; + } + return; + } + } + + if ( (flags & ItemDelta.Update) != 0 ) + { + Packet p = null; + Point3D worldLoc = GetWorldLocation(); + + IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { + if ( m_Parent == null ) { + SendInfoTo( state, ObjectPropertyList.Enabled ); + } else { + if ( p == null ) { + if ( m_Parent is Item ) { + if ( state.ContainerGridLines ) + state.Send( new ContainerContentUpdate6017( this ) ); + else + state.Send( new ContainerContentUpdate( this ) ); + } else if ( m_Parent is Mobile ) { + p = new EquipUpdate( this ); + p.Acquire(); + state.Send( p ); + } + } else { + state.Send( p ); + } + + if ( ObjectPropertyList.Enabled ) { + state.Send( OPLPacket ); + } + } + } + } + + if ( p != null ) + Packet.Release( p ); + + eable.Free(); + sendOPLUpdate = false; + } + else if ( (flags & ItemDelta.EquipOnly ) != 0 ) + { + if ( m_Parent is Mobile ) + { + Packet p = null; + Point3D worldLoc = GetWorldLocation(); + + IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) + { + //if ( sendOPLUpdate ) + // state.Send( RemovePacket ); + + if ( p == null ) + p = Packet.Acquire( new EquipUpdate( this ) ); + + state.Send( p ); + + if ( ObjectPropertyList.Enabled ) + state.Send( OPLPacket ); + } + } + + Packet.Release( p ); + + eable.Free(); + sendOPLUpdate = false; + } + } + + if ( sendOPLUpdate ) + { + Point3D worldLoc = GetWorldLocation(); + IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) + state.Send( OPLPacket ); + } + + eable.Free(); + } + } + } + + public static void ProcessDeltaQueue() + { + int count = m_DeltaQueue.Count; + + for ( int i = 0; i < m_DeltaQueue.Count; ++i ) + { + m_DeltaQueue[i].ProcessDelta(); + + if ( i >= count ) + break; + } + + if ( m_DeltaQueue.Count > 0 ) + m_DeltaQueue.Clear(); + } + + public virtual void OnDelete() + { + if (this.Spawner != null) + { + this.Spawner.Remove(this); + this.Spawner = null; + } + } + + public virtual void OnParentDeleted( object parent ) + { + this.Delete(); + } + + public virtual void FreeCache() + { + ReleaseWorldPackets(); + Packet.Release( ref m_RemovePacket ); + Packet.Release( ref m_OPLPacket ); + Packet.Release( ref m_PropertyList ); + } + + public virtual void Delete() + { + if ( Deleted ) + return; + else if ( !World.OnDelete( this ) ) + return; + + OnDelete(); + + List items = LookupItems(); + + if ( items != null ) + { + for ( int i = items.Count - 1; i >= 0; --i ) + { + if ( i < items.Count ) + items[i].OnParentDeleted( this ); + } + } + + SendRemovePacket(); + + SetFlag( ImplFlag.Deleted, true ); + + if ( Parent is Mobile ) + ((Mobile)Parent).RemoveItem( this ); + else if ( Parent is Item ) + ((Item)Parent).RemoveItem( this ); + + ClearBounce(); + + if ( m_Map != null ) + { + if ( m_Parent == null ) + m_Map.OnLeave( this ); + m_Map = null; + } + + World.RemoveItem( this ); + + OnAfterDelete(); + + FreeCache(); + } + + public void PublicOverheadMessage( MessageType type, int hue, bool ascii, string text ) + { + if ( m_Map != null ) + { + Packet p = null; + Point3D worldLoc = GetWorldLocation(); + + IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) + { + if ( p == null ) + { + if ( ascii ) + p = new AsciiMessage( m_Serial, m_ItemID, type, hue, 3, this.Name, text ); + else + p = new UnicodeMessage( m_Serial, m_ItemID, type, hue, 3, "ENU", this.Name, text ); + + p.Acquire(); + } + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + public void PublicOverheadMessage( MessageType type, int hue, int number ) + { + PublicOverheadMessage( type, hue, number, "" ); + } + + public void PublicOverheadMessage( MessageType type, int hue, int number, string args ) + { + if ( m_Map != null ) + { + Packet p = null; + Point3D worldLoc = GetWorldLocation(); + + IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) + { + if ( p == null ) + p = Packet.Acquire( new MessageLocalized( m_Serial, m_ItemID, type, hue, 3, number, this.Name, args ) ); + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + public virtual void OnAfterDelete() + { + } + + public virtual void RemoveItem( Item item ) + { + List items = LookupItems(); + + if ( items != null && items.Contains( item ) ) + { + item.SendRemovePacket(); + + items.Remove( item ); + + if ( !item.IsVirtualItem ) + { + UpdateTotal( item, TotalType.Gold, -item.TotalGold ); + UpdateTotal( item, TotalType.Items, -( item.TotalItems + 1 ) ); + UpdateTotal( item, TotalType.Weight, -( item.TotalWeight + item.PileWeight ) ); + } + + item.Parent = null; + + item.OnRemoved( this ); + OnItemRemoved( item ); + } + } + + public virtual void OnAfterDuped( Item newItem ) + { + } + + public virtual bool OnDragLift( Mobile from ) + { + return true; + } + + public virtual bool OnEquip( Mobile from ) + { + return true; + } + + public ISpawner Spawner + { + get + { + CompactInfo info = LookupCompactInfo(); + + if (info != null) + return info.m_Spawner; + + return null; + + } + set + { + CompactInfo info = AcquireCompactInfo(); + + info.m_Spawner = value; + + if (info.m_Spawner == null) + VerifyCompactInfo(); + } + } + + public virtual void OnBeforeSpawn( Point3D location, Map m ) + { + } + + public virtual void OnAfterSpawn() + { + } + + public virtual int PhysicalResistance{ get{ return 0; } } + public virtual int FireResistance{ get{ return 0; } } + public virtual int ColdResistance{ get{ return 0; } } + public virtual int PoisonResistance{ get{ return 0; } } + public virtual int EnergyResistance{ get{ return 0; } } + + [CommandProperty( AccessLevel.Counselor )] + public Serial Serial + { + get + { + return m_Serial; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public IEntity ParentEntity + { + get + { + IEntity p = Parent as IEntity; + + return p; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public IEntity RootParentEntity + { + get + { + IEntity p = RootParent as IEntity; + + return p; + } + } + + #region Location Location Location! + + public virtual void OnLocationChange( Point3D oldLocation ) + { + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public virtual Point3D Location + { + get + { + return m_Location; + } + set + { + Point3D oldLocation = m_Location; + + if ( oldLocation != value ) + { + if ( m_Map != null ) + { + if ( m_Parent == null ) + { + IPooledEnumerable eable; + + if ( m_Location.m_X != 0 ) + { + Packet removeThis = null; + + eable = m_Map.GetClientsInRange( oldLocation, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( !m.InRange( value, GetUpdateRange( m ) ) ) + { + if ( removeThis == null ) + removeThis = this.RemovePacket; + + state.Send( removeThis ); + } + } + + eable.Free(); + } + + Point3D oldLoc = m_Location; + m_Location = value; + ReleaseWorldPackets(); + + SetLastMoved(); + + eable = m_Map.GetClientsInRange( m_Location, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if (m.CanSee(this) && m.InRange(m_Location, GetUpdateRange(m)) && (!state.HighSeas || !m_NoMoveHS || (m_DeltaFlags & ItemDelta.Update) != 0 || !m.InRange(oldLoc, GetUpdateRange(m)))) + SendInfoTo(state); + } + + eable.Free(); + + RemDelta( ItemDelta.Update ); + } + else if ( m_Parent is Item ) + { + m_Location = value; + ReleaseWorldPackets(); + + Delta( ItemDelta.Update ); + } + else + { + m_Location = value; + ReleaseWorldPackets(); + } + + if ( m_Parent == null ) + m_Map.OnMove( oldLocation, this ); + } + else + { + m_Location = value; + ReleaseWorldPackets(); + } + + this.OnLocationChange( oldLocation ); + } + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int X + { + get{ return m_Location.m_X; } + set{ Location = new Point3D( value, m_Location.m_Y, m_Location.m_Z ); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Y + { + get{ return m_Location.m_Y; } + set{ Location = new Point3D( m_Location.m_X, value, m_Location.m_Z ); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Z + { + get{ return m_Location.m_Z; } + set{ Location = new Point3D( m_Location.m_X, m_Location.m_Y, value ); } + } + #endregion + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int ItemID + { + get + { + return m_ItemID; + } + set + { + if ( m_ItemID != value ) + { + int oldPileWeight = this.PileWeight; + + m_ItemID = value; + ReleaseWorldPackets(); + + int newPileWeight = this.PileWeight; + + UpdateTotal( this, TotalType.Weight, newPileWeight - oldPileWeight ); + + InvalidateProperties(); + Delta( ItemDelta.Update ); + } + } + } + + public virtual string DefaultName + { + get { return null; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Name + { + get + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null && info.m_Name != null ) + return info.m_Name; + + return this.DefaultName; + } + set + { + if ( value == null || value != DefaultName ) + { + CompactInfo info = AcquireCompactInfo(); + + info.m_Name = value; + + if ( info.m_Name == null ) + VerifyCompactInfo(); + + InvalidateProperties(); + } + } + } + + public virtual object Parent + { + get + { + return m_Parent; + } + set + { + if ( m_Parent == value ) + return; + + object oldParent = m_Parent; + + m_Parent = value; + + if ( m_Map != null ) + { + if ( oldParent != null && m_Parent == null ) + m_Map.OnEnter( this ); + else if ( m_Parent != null ) + m_Map.OnLeave( this ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public LightType Light + { + get + { + return (LightType)m_Direction; + } + set + { + if ( (LightType)m_Direction != value ) + { + m_Direction = (Direction)value; + ReleaseWorldPackets(); + + Delta( ItemDelta.Update ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Direction Direction + { + get + { + return m_Direction; + } + set + { + if ( m_Direction != value ) + { + m_Direction = value; + ReleaseWorldPackets(); + + Delta( ItemDelta.Update ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Amount + { + get + { + return m_Amount; + } + set + { + int oldValue = m_Amount; + + if ( oldValue != value ) + { + int oldPileWeight = this.PileWeight; + + m_Amount = value; + ReleaseWorldPackets(); + + int newPileWeight = this.PileWeight; + + UpdateTotal( this, TotalType.Weight, newPileWeight - oldPileWeight ); + + OnAmountChange( oldValue ); + + Delta( ItemDelta.Update ); + + if ( oldValue > 1 || value > 1 ) + InvalidateProperties(); + + if ( !Stackable && m_Amount > 1 ) + Console.WriteLine( "Warning: 0x{0:X}: Amount changed for non-stackable item '{2}'. ({1})", m_Serial.Value, m_Amount, GetType().Name ); + } + } + } + + protected virtual void OnAmountChange( int oldValue ) + { + } + + public virtual bool HandlesOnSpeech{ get{ return false; } } + + public virtual void OnSpeech( SpeechEventArgs e ) + { + } + + public virtual bool OnDroppedToMobile( Mobile from, Mobile target ) + { + if (Nontransferable && from.Player) + { + HandleInvalidTransfer( from ); + return false; + } + + return true; + } + + public virtual bool DropToMobile( Mobile from, Mobile target, Point3D p ) + { + if ( Deleted || from.Deleted || target.Deleted || from.Map != target.Map || from.Map == null || target.Map == null ) + return false; + else if ( from.AccessLevel < AccessLevel.GameMaster && !from.InRange( target.Location, 2 ) ) + return false; + else if ( !from.CanSee( target ) || !from.InLOS( target ) ) + return false; + else if ( !from.OnDroppedItemToMobile( this, target ) ) + return false; + else if ( !OnDroppedToMobile( from, target ) ) + return false; + else if ( !target.OnDragDrop( from, this ) ) + return false; + else + return true; + } + + public virtual bool OnDroppedInto( Mobile from, Container target, Point3D p ) + { + if( !from.OnDroppedItemInto( this, target, p ) ) + { + return false; + } + else if (Nontransferable && from.Player && target != from.Backpack) + { + HandleInvalidTransfer( from ); + return false; + } + + return target.OnDragDropInto( from, this, p ); + } + + public virtual bool OnDroppedOnto( Mobile from, Item target ) + { + if ( Deleted || from.Deleted || target.Deleted || from.Map != target.Map || from.Map == null || target.Map == null ) + return false; + else if ( from.AccessLevel < AccessLevel.GameMaster && !from.InRange( target.GetWorldLocation(), 2 ) ) + return false; + else if ( !from.CanSee( target ) || !from.InLOS( target ) ) + return false; + else if ( !target.IsAccessibleTo( from ) ) + return false; + else if ( !from.OnDroppedItemOnto( this, target ) ) + return false; + else if (Nontransferable && from.Player && target != from.Backpack) + { + HandleInvalidTransfer( from ); + return false; + } + else + return target.OnDragDrop( from, this ); + } + + public virtual bool DropToItem( Mobile from, Item target, Point3D p ) + { + if ( Deleted || from.Deleted || target.Deleted || from.Map != target.Map || from.Map == null || target.Map == null ) + return false; + + object root = target.RootParent; + + if ( from.AccessLevel < AccessLevel.GameMaster && !from.InRange( target.GetWorldLocation(), 2 ) ) + return false; + else if ( !from.CanSee( target ) || !from.InLOS( target ) ) + return false; + else if ( !target.IsAccessibleTo( from ) ) + return false; + else if ( root is Mobile && !((Mobile)root).CheckNonlocalDrop( from, this, target ) ) + return false; + else if ( !from.OnDroppedItemToItem( this, target, p ) ) + return false; + else if ( target is Container && p.m_X != -1 && p.m_Y != -1 ) + return OnDroppedInto( from, (Container)target, p ); + else + return OnDroppedOnto( from, target ); + } + + public virtual bool OnDroppedToWorld( Mobile from, Point3D p ) + { + if (Nontransferable && from.Player) + { + HandleInvalidTransfer( from ); + return false; + } + + return true; + } + + public virtual int GetLiftSound( Mobile from ) + { + return 0x57; + } + + private static int m_OpenSlots; + + public virtual bool DropToWorld( Mobile from, Point3D p ) + { + if ( Deleted || from.Deleted || from.Map == null ) + return false; + else if ( !from.InRange( p, 2 ) ) + return false; + + Map map = from.Map; + + if ( map == null ) + return false; + + int x = p.m_X, y = p.m_Y; + int z = int.MinValue; + + int maxZ = from.Z + 16; + + LandTile landTile = map.Tiles.GetLandTile( x, y ); + TileFlag landFlags = TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags; + + int landZ = 0, landAvg = 0, landTop = 0; + map.GetAverageZ( x, y, ref landZ, ref landAvg, ref landTop ); + + if ( !landTile.Ignored && (landFlags & TileFlag.Impassable) == 0 ) + { + if ( landAvg <= maxZ ) + z = landAvg; + } + + StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y, true ); + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + if ( !id.Surface ) + continue; + + int top = tile.Z + id.CalcHeight; + + if ( top > maxZ || top < z ) + continue; + + z = top; + } + + List items = new List(); + + IPooledEnumerable eable = map.GetItemsInRange( p, 0 ); + + foreach ( Item item in eable ) + { + if ( item is BaseMulti || item.ItemID > TileData.MaxItemValue ) + continue; + + items.Add( item ); + + ItemData id = item.ItemData; + + if ( !id.Surface ) + continue; + + int top = item.Z + id.CalcHeight; + + if ( top > maxZ || top < z ) + continue; + + z = top; + } + + eable.Free(); + + if ( z == int.MinValue ) + return false; + + if ( z > maxZ ) + return false; + + m_OpenSlots = (1<<20)-1; + + int surfaceZ = z; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + int checkZ = tile.Z; + int checkTop = checkZ + id.CalcHeight; + + if ( checkTop == checkZ && !id.Surface ) + ++checkTop; + + int zStart = checkZ - z; + int zEnd = checkTop - z; + + if ( zStart >= 20 || zEnd < 0 ) + continue; + + if ( zStart < 0 ) + zStart = 0; + + if ( zEnd > 19 ) + zEnd = 19; + + int bitCount = zEnd-zStart; + + m_OpenSlots &= ~(((1<= 20 || zEnd < 0 ) + continue; + + if ( zStart < 0 ) + zStart = 0; + + if ( zEnd > 19 ) + zEnd = 19; + + int bitCount = zEnd-zStart; + + m_OpenSlots &= ~(((1< 30 ) + height = 30; + + int match = (1< 20 ) + match >>= 1; + + okay = ((m_OpenSlots>>i)&match) == match; + + if ( okay ) + { + z += i; + break; + } + } + + if ( !okay ) + return false; + + height = ItemData.Height; + + if ( height == 0 ) + ++height; + + if ( landAvg > z && (z + height) > landZ ) + return false; + else if ( (landFlags & TileFlag.Impassable) != 0 && landAvg > surfaceZ && (z + height) > landZ ) + return false; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + int checkZ = tile.Z; + int checkTop = checkZ + id.CalcHeight; + + if ( checkTop > z && (z + height) > checkZ ) + return false; + else if ( (id.Surface || id.Impassable) && checkTop > surfaceZ && (z + height) > checkZ ) + return false; + } + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + ItemData id = item.ItemData; + + //int checkZ = item.Z; + //int checkTop = checkZ + id.CalcHeight; + + if ( (item.Z + id.CalcHeight) > z && (z + height) > item.Z ) + return false; + } + + p = new Point3D( x, y, z ); + + if ( !from.InLOS( new Point3D( x, y, z + 1 ) ) ) + return false; + else if ( !from.OnDroppedItemToWorld( this, p ) ) + return false; + else if ( !OnDroppedToWorld( from, p ) ) + return false; + + int soundID = GetDropSound(); + + MoveToWorld( p, from.Map ); + + from.SendSound( soundID == -1 ? 0x42 : soundID, GetWorldLocation() ); + + return true; + } + + public void SendRemovePacket() + { + if ( !Deleted && m_Map != null ) + { + Packet p = null; + Point3D worldLoc = GetWorldLocation(); + + IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); + + foreach ( NetState state in eable ) + { + Mobile m = state.Mobile; + + if ( m.InRange( worldLoc, GetUpdateRange( m ) ) ) + { + if ( p == null ) + p = this.RemovePacket; + + state.Send( p ); + } + } + + eable.Free(); + } + } + + public virtual int GetDropSound() + { + return -1; + } + + public Point3D GetWorldLocation() + { + object root = RootParent; + + if ( root == null ) + return m_Location; + else + return ((IEntity)root).Location; + + //return root == null ? m_Location : new Point3D( (IPoint3D) root ); + } + + public virtual bool BlocksFit{ get{ return false; } } + + public Point3D GetSurfaceTop() + { + object root = RootParent; + + if ( root == null ) + return new Point3D( m_Location.m_X, m_Location.m_Y, m_Location.m_Z + (ItemData.Surface ? ItemData.CalcHeight : 0) ); + else + return ((IEntity)root).Location; + } + + public Point3D GetWorldTop() + { + object root = RootParent; + + if ( root == null ) + return new Point3D( m_Location.m_X, m_Location.m_Y, m_Location.m_Z + ItemData.CalcHeight ); + else + return ((IEntity)root).Location; + } + + public void SendLocalizedMessageTo( Mobile to, int number ) + { + if ( Deleted || !to.CanSee( this ) ) + return; + + to.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", "" ) ); + } + + public void SendLocalizedMessageTo( Mobile to, int number, string args ) + { + if ( Deleted || !to.CanSee( this ) ) + return; + + to.Send( new MessageLocalized( Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", args ) ); + } + + public void SendLocalizedMessageTo( Mobile to, int number, AffixType affixType, string affix, string args ) + { + if ( Deleted || !to.CanSee( this ) ) + return; + + to.Send( new MessageLocalizedAffix( Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", affixType, affix, args ) ); + } + + #region OnDoubleClick[...] + + public virtual void OnDoubleClick( Mobile from ) + { + } + + public virtual void OnDoubleClickOutOfRange( Mobile from ) + { + } + + public virtual void OnDoubleClickCantSee( Mobile from ) + { + } + + public virtual void OnDoubleClickDead( Mobile from ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019048 ); // I am dead and cannot do that. + } + + public virtual void OnDoubleClickNotAccessible( Mobile from ) + { + from.SendLocalizedMessage( 500447 ); // That is not accessible. + } + + public virtual void OnDoubleClickSecureTrade( Mobile from ) + { + from.SendLocalizedMessage( 500447 ); // That is not accessible. + } + #endregion + + public virtual void OnSnoop( Mobile from ) + { + } + + public bool InSecureTrade + { + get + { + return ( GetSecureTradeCont() != null ); + } + } + + public SecureTradeContainer GetSecureTradeCont() + { + object p = this; + + while ( p is Item ) + { + if ( p is SecureTradeContainer ) + return (SecureTradeContainer)p; + + p = ((Item)p).m_Parent; + } + + return null; + } + + public virtual void OnItemAdded( Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSubItemAdded( item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnSubItemAdded( item ); + } + + public virtual void OnItemRemoved( Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSubItemRemoved( item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnSubItemRemoved( item ); + } + + public virtual void OnSubItemAdded( Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSubItemAdded( item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnSubItemAdded( item ); + } + + public virtual void OnSubItemRemoved( Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSubItemRemoved( item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnSubItemRemoved( item ); + } + + public virtual void OnItemBounceCleared( Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSubItemBounceCleared( item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnSubItemBounceCleared( item ); + } + + public virtual void OnSubItemBounceCleared( Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSubItemBounceCleared( item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnSubItemBounceCleared( item ); + } + + public virtual bool CheckTarget( Mobile from, Server.Targeting.Target targ, object targeted ) + { + if ( m_Parent is Item ) + return ((Item)m_Parent).CheckTarget( from, targ, targeted ); + else if ( m_Parent is Mobile ) + return ((Mobile)m_Parent).CheckTarget( from, targ, targeted ); + + return true; + } + + public virtual bool IsAccessibleTo( Mobile check ) + { + if ( m_Parent is Item ) + return ((Item)m_Parent).IsAccessibleTo( check ); + + Region reg = Region.Find( GetWorldLocation(), m_Map ); + + return reg.CheckAccessibility( this, check ); + + /*SecureTradeContainer cont = GetSecureTradeCont(); + + if ( cont != null && !cont.IsChildOf( check ) ) + return false; + + return true;*/ + } + + public bool IsChildOf( object o ) + { + return IsChildOf( o, false ); + } + + public bool IsChildOf( object o, bool allowNull ) + { + object p = m_Parent; + + if ( (p == null || o == null) && !allowNull ) + return false; + + if ( p == o ) + return true; + + while ( p is Item ) + { + Item item = (Item)p; + + if ( item.m_Parent == null ) + { + break; + } + else + { + p = item.m_Parent; + + if ( p == o ) + return true; + } + } + + return false; + } + + public ItemData ItemData + { + get + { + return TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; + } + } + + public virtual void OnItemUsed( Mobile from, Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnItemUsed( from, item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnItemUsed( from, item ); + } + + public bool CheckItemUse( Mobile from ) + { + return CheckItemUse( from, this ); + } + + public virtual bool CheckItemUse( Mobile from, Item item ) + { + if ( m_Parent is Item ) + return ((Item)m_Parent).CheckItemUse( from, item ); + else if ( m_Parent is Mobile ) + return ((Mobile)m_Parent).CheckItemUse( from, item ); + else + return true; + } + + public virtual void OnItemLifted( Mobile from, Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnItemLifted( from, item ); + else if ( m_Parent is Mobile ) + ((Mobile)m_Parent).OnItemLifted( from, item ); + } + + public bool CheckLift( Mobile from ) + { + LRReason reject = LRReason.Inspecific; + + return CheckLift( from, this, ref reject ); + } + + public virtual bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( m_Parent is Item ) + return ((Item)m_Parent).CheckLift( from, item, ref reject ); + else if ( m_Parent is Mobile ) + return ((Mobile)m_Parent).CheckLift( from, item, ref reject ); + else + return true; + } + + public virtual bool CanTarget{ get{ return true; } } + public virtual bool DisplayLootType{ get{ return true; } } + + public virtual void OnSingleClickContained( Mobile from, Item item ) + { + if ( m_Parent is Item ) + ((Item)m_Parent).OnSingleClickContained( from, item ); + } + + public virtual void OnAosSingleClick( Mobile from ) + { + ObjectPropertyList opl = this.PropertyList; + + if ( opl.Header > 0 ) + from.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, opl.Header, this.Name, opl.HeaderArgs ) ); + } + + public virtual void OnSingleClick( Mobile from ) + { + if ( Deleted || !from.CanSee( this ) ) + return; + + if ( DisplayLootType ) + LabelLootTypeTo( from ); + + NetState ns = from.NetState; + + if ( ns != null ) + { + if ( this.Name == null ) + { + if ( m_Amount <= 1 ) + ns.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", "" ) ); + else + ns.Send( new MessageLocalizedAffix( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", AffixType.Append, String.Format( " : {0}", m_Amount ), "" ) ); + } + else + { + ns.Send( new UnicodeMessage( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", this.Name + ( m_Amount > 1 ? " : " + m_Amount : "" ) ) ); + } + } + } + + private static bool m_ScissorCopyLootType; + + public static bool ScissorCopyLootType + { + get{ return m_ScissorCopyLootType; } + set{ m_ScissorCopyLootType = value; } + } + + public virtual void ScissorHelper( Mobile from, Item newItem, int amountPerOldItem ) + { + ScissorHelper( from, newItem, amountPerOldItem, true ); + } + + public virtual void ScissorHelper( Mobile from, Item newItem, int amountPerOldItem, bool carryHue ) + { + int amount = Amount; + + if ( amount > (60000 / amountPerOldItem) ) // let's not go over 60000 + amount = (60000 / amountPerOldItem); + + Amount -= amount; + + int ourHue = Hue; + Map thisMap = this.Map; + object thisParent = this.m_Parent; + Point3D worldLoc = this.GetWorldLocation(); + LootType type = this.LootType; + + if ( Amount == 0 ) + Delete(); + + newItem.Amount = amount * amountPerOldItem; + + if ( carryHue ) + newItem.Hue = ourHue; + + if ( m_ScissorCopyLootType ) + newItem.LootType = type; + + if ( !(thisParent is Container) || !((Container)thisParent).TryDropItem( from, newItem, false ) ) + newItem.MoveToWorld( worldLoc, thisMap ); + } + + public virtual void Consume() + { + Consume( 1 ); + } + + public virtual void Consume( int amount ) + { + this.Amount -= amount; + + if ( this.Amount <= 0 ) + this.Delete(); + } + + public virtual void ReplaceWith(Item newItem) + { + if (m_Parent is Container) + { + ((Container)m_Parent).AddItem(newItem); + newItem.Location = m_Location; + } + else + { + newItem.MoveToWorld(GetWorldLocation(), m_Map); + } + + Delete(); + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool QuestItem + { + get { return GetFlag( ImplFlag.QuestItem ); } + set + { + SetFlag( ImplFlag.QuestItem, value ); + + InvalidateProperties(); + + ReleaseWorldPackets(); + + Delta( ItemDelta.Update ); + } + } + + public bool Insured + { + get{ return GetFlag( ImplFlag.Insured ); } + set{ SetFlag( ImplFlag.Insured, value ); InvalidateProperties(); } + } + + public bool PayedInsurance + { + get{ return GetFlag( ImplFlag.PayedInsurance ); } + set{ SetFlag( ImplFlag.PayedInsurance, value ); } + } + + public Mobile BlessedFor + { + get + { + CompactInfo info = LookupCompactInfo(); + + if ( info != null ) + return info.m_BlessedFor; + + return null; + } + set + { + CompactInfo info = AcquireCompactInfo(); + + info.m_BlessedFor = value; + + if ( info.m_BlessedFor == null ) + VerifyCompactInfo(); + + InvalidateProperties(); + } + } + + public virtual bool CheckBlessed( object obj ) + { + return CheckBlessed( obj as Mobile ); + } + + public virtual bool CheckBlessed( Mobile m ) + { + if ( m_LootType == LootType.Blessed || (Mobile.InsuranceEnabled && Insured) ) + return true; + + return ( m != null && m == this.BlessedFor ); + } + + public virtual bool CheckNewbied() + { + return ( m_LootType == LootType.Newbied ); + } + + public virtual bool IsStandardLoot() + { + if ( Mobile.InsuranceEnabled && Insured ) + return false; + + if ( this.BlessedFor != null ) + return false; + + return ( m_LootType == LootType.Regular ); + } + + public override string ToString() + { + return String.Format( "0x{0:X} \"{1}\"", m_Serial.Value, GetType().Name ); + } + + internal int m_TypeRef; + + public Item() + { + m_Serial = Serial.NewItem; + + //m_Items = new ArrayList( 1 ); + Visible = true; + Movable = true; + Amount = 1; + m_Map = Map.Internal; + + SetLastMoved(); + + World.AddItem( this ); + + Type ourType = this.GetType(); + m_TypeRef = World.m_ItemTypes.IndexOf( ourType ); + + if ( m_TypeRef == -1 ) + { + World.m_ItemTypes.Add( ourType ); + m_TypeRef = World.m_ItemTypes.Count - 1; + } + } + + [Constructable] + public Item( int itemID ) : this() + { + m_ItemID = itemID; + } + + public Item( Serial serial ) + { + m_Serial = serial; + + Type ourType = this.GetType(); + m_TypeRef = World.m_ItemTypes.IndexOf( ourType ); + + if ( m_TypeRef == -1 ) + { + World.m_ItemTypes.Add( ourType ); + m_TypeRef = World.m_ItemTypes.Count - 1; + } + } + + public virtual void OnSectorActivate() + { + } + + public virtual void OnSectorDeactivate() + { + } + } +} \ No newline at end of file diff --git a/Server/ItemBounds.cs b/Server/ItemBounds.cs new file mode 100644 index 0000000..85b4d8d --- /dev/null +++ b/Server/ItemBounds.cs @@ -0,0 +1,69 @@ +/*************************************************************************** + * ItemBounds.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ItemBounds.cs 804 2012-01-02 10:24:08Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; + +namespace Server +{ + public static class ItemBounds + { + private static Rectangle2D[] m_Bounds; + + public static Rectangle2D[] Table + { + get + { + return m_Bounds; + } + } + + static ItemBounds() + { + m_Bounds = new Rectangle2D[TileData.ItemTable.Length]; + + if (File.Exists("Data/Binary/Bounds.bin")) + { + using (FileStream fs = new FileStream("Data/Binary/Bounds.bin", FileMode.Open, FileAccess.Read, FileShare.Read)) + { + BinaryReader bin = new BinaryReader(fs); + + int count = Math.Min(m_Bounds.Length, (int)(fs.Length / 8)); + + for (int i = 0; i < count; ++i) + { + int xMin = bin.ReadInt16(); + int yMin = bin.ReadInt16(); + int xMax = bin.ReadInt16(); + int yMax = bin.ReadInt16(); + + m_Bounds[i].Set(xMin, yMin, (xMax - xMin) + 1, (yMax - yMin) + 1); + } + + bin.Close(); + } + } + else + { + Console.WriteLine("Warning: Data/Binary/Bounds.bin does not exist"); + } + } + } +} \ No newline at end of file diff --git a/Server/Items/BaseMulti.cs b/Server/Items/BaseMulti.cs new file mode 100644 index 0000000..5cf35e3 --- /dev/null +++ b/Server/Items/BaseMulti.cs @@ -0,0 +1,179 @@ +/*************************************************************************** + * BaseMulti.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: BaseMulti.cs 1064 2013-05-28 17:44:07Z mark@runuo.com $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Items +{ + public class BaseMulti : Item + { + [Constructable] + public BaseMulti( int itemID ) : base( itemID ) + { + Movable = false; + } + + public BaseMulti( Serial serial ) : base( serial ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int ItemID { + get { + return base.ItemID; + } + set { + if ( base.ItemID != value ) { + Map facet = ( this.Parent == null ? this.Map : null ); + + if ( facet != null ) { + facet.OnLeave( this ); + } + + base.ItemID = value; + + if ( facet != null ) { + facet.OnEnter( this ); + } + } + } + } + + [Obsolete( "Replace with calls to OnLeave and OnEnter surrounding component invalidation.", true )] + public virtual void RefreshComponents() + { + if ( this.Parent == null ) { + Map facet = this.Map; + + if ( facet != null ) { + facet.OnLeave( this ); + facet.OnEnter( this ); + } + } + } + + public override int LabelNumber + { + get + { + MultiComponentList mcl = this.Components; + + if ( mcl.List.Length > 0 ) { + int id = mcl.List[0].m_ItemID; + + if ( id < 0x4000 ) + return 1020000 + id; + else + return 1078872 + id; + } + + return base.LabelNumber; + } + } + + public virtual bool AllowsRelativeDrop + { + get { return false; } + } + + public override int GetMaxUpdateRange() + { + return 22; + } + + public override int GetUpdateRange( Mobile m ) + { + return 22; + } + + public virtual MultiComponentList Components + { + get + { + return MultiData.GetComponents( ItemID ); + } + } + + public virtual bool Contains( Point2D p ) + { + return Contains( p.m_X, p.m_Y ); + } + + public virtual bool Contains( Point3D p ) + { + return Contains( p.m_X, p.m_Y ); + } + + public virtual bool Contains( IPoint3D p ) + { + return Contains( p.X, p.Y ); + } + + public virtual bool Contains( int x, int y ) + { + MultiComponentList mcl = this.Components; + + x -= this.X + mcl.Min.m_X; + y -= this.Y + mcl.Min.m_Y; + + return x >= 0 + && x < mcl.Width + && y >= 0 + && y < mcl.Height + && mcl.Tiles[x][y].Length > 0; + } + + public bool Contains( Mobile m ) + { + if ( m.Map == this.Map ) + return Contains( m.X, m.Y ); + else + return false; + } + + public bool Contains( Item item ) + { + if ( item.Map == this.Map ) + return Contains( item.X, item.Y ); + else + return false; + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 1 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + if ( version == 0 ) { + if ( ItemID >= 0x4000 ) { + ItemID -= 0x4000; + } + } + } + } +} \ No newline at end of file diff --git a/Server/Items/Container.cs b/Server/Items/Container.cs new file mode 100644 index 0000000..80853e5 --- /dev/null +++ b/Server/Items/Container.cs @@ -0,0 +1,1841 @@ +/*************************************************************************** + * Container.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Container.cs 564 2010-10-18 04:56:28Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server.Network; + +namespace Server.Items +{ + public delegate void OnItemConsumed( Item item, int amount ); + public delegate int CheckItemGroup( Item a, Item b ); + + public delegate void ContainerSnoopHandler( Container cont, Mobile from ); + + public class Container : Item + { + private static ContainerSnoopHandler m_SnoopHandler; + + public static ContainerSnoopHandler SnoopHandler + { + get{ return m_SnoopHandler; } + set{ m_SnoopHandler = value; } + } + + private ContainerData m_ContainerData; + + private int m_DropSound; + private int m_GumpID; + private int m_MaxItems; + + private int m_TotalItems; + private int m_TotalWeight; + private int m_TotalGold; + + private bool m_LiftOverride; + + internal List m_Items; + + public ContainerData ContainerData + { + get + { + if ( m_ContainerData == null ) + UpdateContainerData(); + + return m_ContainerData; + } + set{ m_ContainerData = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public override int ItemID + { + get{ return base.ItemID; } + set + { + int oldID = this.ItemID; + + base.ItemID = value; + + if ( this.ItemID != oldID ) + UpdateContainerData(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int GumpID + { + get{ return ( m_GumpID == -1 ? DefaultGumpID : m_GumpID ); } + set{ m_GumpID = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int DropSound + { + get{ return ( m_DropSound == -1 ? DefaultDropSound : m_DropSound ); } + set{ m_DropSound = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MaxItems + { + get{ return ( m_MaxItems == -1 ? DefaultMaxItems : m_MaxItems ); } + set{ m_MaxItems = value; InvalidateProperties(); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int MaxWeight + { + get + { + if ( Parent is Container && ((Container)Parent).MaxWeight == 0 ) + { + return 0; + } + else + { + return DefaultMaxWeight; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool LiftOverride + { + get{ return m_LiftOverride; } + set{ m_LiftOverride = value; } + } + + public virtual void UpdateContainerData() + { + this.ContainerData = ContainerData.GetData( this.ItemID ); + } + + public virtual Rectangle2D Bounds{ get{ return ContainerData.Bounds; } } + public virtual int DefaultGumpID{ get{ return ContainerData.GumpID; } } + public virtual int DefaultDropSound{ get{ return ContainerData.DropSound; } } + + public virtual int DefaultMaxItems{ get{ return m_GlobalMaxItems; } } + public virtual int DefaultMaxWeight{ get{ return m_GlobalMaxWeight; } } + + public virtual bool IsDecoContainer + { + get{ return !Movable && !IsLockedDown && !IsSecure && Parent == null && !m_LiftOverride; } + } + + public virtual int GetDroppedSound( Item item ) + { + int dropSound = item.GetDropSound(); + + return dropSound != -1 ? dropSound : DropSound; + } + + public override void OnSnoop( Mobile from ) + { + if ( m_SnoopHandler != null ) + m_SnoopHandler( this, from ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + if ( from.AccessLevel < AccessLevel.GameMaster && IsDecoContainer ) + { + reject = LRReason.CannotLift; + return false; + } + + return base.CheckLift( from, item, ref reject ); + } + + public override bool CheckItemUse( Mobile from, Item item ) + { + if ( item != this && from.AccessLevel < AccessLevel.GameMaster && IsDecoContainer ) + { + from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019045 ); // I can't reach that. + return false; + } + + return base.CheckItemUse( from, item ); + } + + public bool CheckHold( Mobile m, Item item, bool message ) + { + return CheckHold( m, item, message, true, 0, 0 ); + } + + public bool CheckHold( Mobile m, Item item, bool message, bool checkItems ) + { + return CheckHold( m, item, message, checkItems, 0, 0 ); + } + + public virtual bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + if ( m.AccessLevel < AccessLevel.GameMaster ) + { + if ( IsDecoContainer ) + { + if ( message ) + SendCantStoreMessage( m, item ); + + return false; + } + + int maxItems = this.MaxItems; + + if ( checkItems && maxItems != 0 && (this.TotalItems + plusItems + item.TotalItems + (item.IsVirtualItem ? 0 : 1)) > maxItems ) + { + if ( message ) + SendFullItemsMessage( m, item ); + + return false; + } + else + { + int maxWeight = this.MaxWeight; + + if ( maxWeight != 0 && (this.TotalWeight + plusWeight + item.TotalWeight + item.PileWeight) > maxWeight ) + { + if ( message ) + SendFullWeightMessage( m, item ); + + return false; + } + } + } + + object parent = this.Parent; + + while ( parent != null ) + { + if ( parent is Container ) + return ((Container)parent).CheckHold( m, item, message, checkItems, plusItems, plusWeight ); + else if ( parent is Item ) + parent = ((Item)parent).Parent; + else + break; + } + + return true; + } + + public virtual void SendFullItemsMessage( Mobile to, Item item ) + { + to.SendMessage( "That container cannot hold more items." ); + } + + public virtual void SendFullWeightMessage( Mobile to, Item item ) + { + to.SendMessage( "That container cannot hold more weight." ); + } + + public virtual void SendCantStoreMessage( Mobile to, Item item ) + { + to.SendLocalizedMessage( 500176 ); // That is not your container, you can't store things here. + } + + public virtual bool OnDragDropInto( Mobile from, Item item, Point3D p ) + { + if ( !CheckHold( from, item, true, true ) ) + return false; + + item.Location = new Point3D( p.m_X, p.m_Y, 0 ); + AddItem( item ); + + from.SendSound( GetDroppedSound( item ), GetWorldLocation() ); + + return true; + } + + private class GroupComparer : IComparer + { + private CheckItemGroup m_Grouper; + + public GroupComparer( CheckItemGroup grouper ) + { + m_Grouper = grouper; + } + + public int Compare( object x, object y ) + { + Item a = (Item)x; + Item b = (Item)y; + + return m_Grouper( a, b ); + } + } + + #region Consume[...] + + public bool ConsumeTotalGrouped( Type type, int amount, bool recurse, OnItemConsumed callback, CheckItemGroup grouper ) + { + if ( grouper == null ) + throw new ArgumentNullException(); + + Item[] typedItems = FindItemsByType( type, recurse ); + + List> groups = new List>(); + int idx = 0; + + while ( idx < typedItems.Length ) + { + Item a = typedItems[idx++]; + List group = new List(); + + group.Add( a ); + + while ( idx < typedItems.Length ) + { + Item b = typedItems[idx]; + int v = grouper( a, b ); + + if ( v == 0 ) + group.Add( b ); + else + break; + + ++idx; + } + + groups.Add( group ); + } + + Item[][] items = new Item[groups.Count][]; + int[] totals = new int[groups.Count]; + + bool hasEnough = false; + + for ( int i = 0; i < groups.Count; ++i ) + { + items[i] = groups[i].ToArray(); + //items[i] = (Item[])(((ArrayList)groups[i]).ToArray( typeof( Item ) )); + + for ( int j = 0; j < items[i].Length; ++j ) + totals[i] += items[i][j].Amount; + + if ( totals[i] >= amount ) + hasEnough = true; + } + + if ( !hasEnough ) + return false; + + for ( int i = 0; i < items.Length; ++i ) + { + if ( totals[i] >= amount ) + { + int need = amount; + + for ( int j = 0; j < items[i].Length; ++j ) + { + Item item = items[i][j]; + + int theirAmount = item.Amount; + + if ( theirAmount < need ) + { + if ( callback != null ) + callback( item, theirAmount ); + + item.Delete(); + need -= theirAmount; + } + else + { + if ( callback != null ) + callback( item, need ); + + item.Consume( need ); + break; + } + } + + break; + } + } + + return true; + } + + public int ConsumeTotalGrouped( Type[] types, int[] amounts, bool recurse, OnItemConsumed callback, CheckItemGroup grouper ) + { + if ( types.Length != amounts.Length ) + throw new ArgumentException(); + else if ( grouper == null ) + throw new ArgumentNullException(); + + Item[][][] items = new Item[types.Length][][]; + int[][] totals = new int[types.Length][]; + + for ( int i = 0; i < types.Length; ++i ) + { + Item[] typedItems = FindItemsByType( types[i], recurse ); + + List> groups = new List>(); + int idx = 0; + + while ( idx < typedItems.Length ) + { + Item a = typedItems[idx++]; + List group = new List(); + + group.Add( a ); + + while ( idx < typedItems.Length ) + { + Item b = typedItems[idx]; + int v = grouper( a, b ); + + if ( v == 0 ) + group.Add( b ); + else + break; + + ++idx; + } + + groups.Add( group ); + } + + items[i] = new Item[groups.Count][]; + totals[i] = new int[groups.Count]; + + bool hasEnough = false; + + for ( int j = 0; j < groups.Count; ++j ) + { + items[i][j] = groups[j].ToArray(); + //items[i][j] = (Item[])(((ArrayList)groups[j]).ToArray( typeof( Item ) )); + + for ( int k = 0; k < items[i][j].Length; ++k ) + totals[i][j] += items[i][j][k].Amount; + + if ( totals[i][j] >= amounts[i] ) + hasEnough = true; + } + + if ( !hasEnough ) + return i; + } + + for ( int i = 0; i < items.Length; ++i ) + { + for ( int j = 0; j < items[i].Length; ++j ) + { + if ( totals[i][j] >= amounts[i] ) + { + int need = amounts[i]; + + for ( int k = 0; k < items[i][j].Length; ++k ) + { + Item item = items[i][j][k]; + + int theirAmount = item.Amount; + + if ( theirAmount < need ) + { + if ( callback != null ) + callback( item, theirAmount ); + + item.Delete(); + need -= theirAmount; + } + else + { + if ( callback != null ) + callback( item, need ); + + item.Consume( need ); + break; + } + } + + break; + } + } + } + + return -1; + } + + public int ConsumeTotalGrouped( Type[][] types, int[] amounts, bool recurse, OnItemConsumed callback, CheckItemGroup grouper ) + { + if ( types.Length != amounts.Length ) + throw new ArgumentException(); + else if ( grouper == null ) + throw new ArgumentNullException(); + + Item[][][] items = new Item[types.Length][][]; + int[][] totals = new int[types.Length][]; + + for ( int i = 0; i < types.Length; ++i ) + { + Item[] typedItems = FindItemsByType( types[i], recurse ); + + List> groups = new List>(); + int idx = 0; + + while ( idx < typedItems.Length ) + { + Item a = typedItems[idx++]; + List group = new List(); + + group.Add( a ); + + while ( idx < typedItems.Length ) + { + Item b = typedItems[idx]; + int v = grouper( a, b ); + + if ( v == 0 ) + group.Add( b ); + else + break; + + ++idx; + } + + groups.Add( group ); + } + + items[i] = new Item[groups.Count][]; + totals[i] = new int[groups.Count]; + + bool hasEnough = false; + + for ( int j = 0; j < groups.Count; ++j ) + { + items[i][j] = groups[j].ToArray(); + + for ( int k = 0; k < items[i][j].Length; ++k ) + totals[i][j] += items[i][j][k].Amount; + + if ( totals[i][j] >= amounts[i] ) + hasEnough = true; + } + + if ( !hasEnough ) + return i; + } + + for ( int i = 0; i < items.Length; ++i ) + { + for ( int j = 0; j < items[i].Length; ++j ) + { + if ( totals[i][j] >= amounts[i] ) + { + int need = amounts[i]; + + for ( int k = 0; k < items[i][j].Length; ++k ) + { + Item item = items[i][j][k]; + + int theirAmount = item.Amount; + + if ( theirAmount < need ) + { + if ( callback != null ) + callback( item, theirAmount ); + + item.Delete(); + need -= theirAmount; + } + else + { + if ( callback != null ) + callback( item, need ); + + item.Consume( need ); + break; + } + } + + break; + } + } + } + + return -1; + } + + public int ConsumeTotal( Type[][] types, int[] amounts ) + { + return ConsumeTotal( types, amounts, true, null ); + } + + public int ConsumeTotal( Type[][] types, int[] amounts, bool recurse ) + { + return ConsumeTotal( types, amounts, recurse, null ); + } + + public int ConsumeTotal( Type[][] types, int[] amounts, bool recurse, OnItemConsumed callback ) + { + if ( types.Length != amounts.Length ) + throw new ArgumentException(); + + Item[][] items = new Item[types.Length][]; + int[] totals = new int[types.Length]; + + for ( int i = 0; i < types.Length; ++i ) + { + items[i] = FindItemsByType( types[i], recurse ); + + for ( int j = 0; j < items[i].Length; ++j ) + totals[i] += items[i][j].Amount; + + if ( totals[i] < amounts[i] ) + return i; + } + + for ( int i = 0; i < types.Length; ++i ) + { + int need = amounts[i]; + + for ( int j = 0; j < items[i].Length; ++j ) + { + Item item = items[i][j]; + + int theirAmount = item.Amount; + + if ( theirAmount < need ) + { + if ( callback != null ) + callback( item, theirAmount ); + + item.Delete(); + need -= theirAmount; + } + else + { + if ( callback != null ) + callback( item, need ); + + item.Consume( need ); + break; + } + } + } + + return -1; + } + + public int ConsumeTotal( Type[] types, int[] amounts ) + { + return ConsumeTotal( types, amounts, true, null ); + } + + public int ConsumeTotal( Type[] types, int[] amounts, bool recurse ) + { + return ConsumeTotal( types, amounts, recurse, null ); + } + + public int ConsumeTotal( Type[] types, int[] amounts, bool recurse, OnItemConsumed callback ) + { + if ( types.Length != amounts.Length ) + throw new ArgumentException(); + + Item[][] items = new Item[types.Length][]; + int[] totals = new int[types.Length]; + + for ( int i = 0; i < types.Length; ++i ) + { + items[i] = FindItemsByType( types[i], recurse ); + + for ( int j = 0; j < items[i].Length; ++j ) + totals[i] += items[i][j].Amount; + + if ( totals[i] < amounts[i] ) + return i; + } + + for ( int i = 0; i < types.Length; ++i ) + { + int need = amounts[i]; + + for ( int j = 0; j < items[i].Length; ++j ) + { + Item item = items[i][j]; + + int theirAmount = item.Amount; + + if ( theirAmount < need ) + { + if ( callback != null ) + callback( item, theirAmount ); + + item.Delete(); + need -= theirAmount; + } + else + { + if ( callback != null ) + callback( item, need ); + + item.Consume( need ); + break; + } + } + } + + return -1; + } + + public bool ConsumeTotal( Type type, int amount ) + { + return ConsumeTotal( type, amount, true, null ); + } + + public bool ConsumeTotal( Type type, int amount, bool recurse ) + { + return ConsumeTotal( type, amount, recurse, null ); + } + + public bool ConsumeTotal( Type type, int amount, bool recurse, OnItemConsumed callback ) + { + Item[] items = FindItemsByType( type, recurse ); + + // First pass, compute total + int total = 0; + + for( int i = 0; i < items.Length; ++i ) + total += items[i].Amount; + + if( total >= amount ) + { + // We've enough, so consume it + + int need = amount; + + for( int i = 0; i < items.Length; ++i ) + { + Item item = items[i]; + + int theirAmount = item.Amount; + + if( theirAmount < need ) + { + if( callback != null ) + callback( item, theirAmount ); + + item.Delete(); + need -= theirAmount; + } + else + { + if( callback != null ) + callback( item, need ); + + item.Consume( need ); + + return true; + } + } + } + + return false; + } + + public int ConsumeUpTo( Type type, int amount ) + { + return ConsumeUpTo( type, amount, true ); + } + + public int ConsumeUpTo( Type type, int amount, bool recurse ) + { + int consumed = 0; + + Queue toDelete = new Queue(); + + RecurseConsumeUpTo( this, type, amount, recurse, ref consumed, toDelete ); + + while( toDelete.Count > 0 ) + toDelete.Dequeue().Delete(); + + return consumed; + } + + private static void RecurseConsumeUpTo( Item current, Type type, int amount, bool recurse, ref int consumed, Queue toDelete ) + { + if( current != null && current.Items.Count > 0 ) + { + List list = current.Items; + + for( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if( type.IsAssignableFrom( item.GetType() ) ) + { + int need = amount - consumed; + int theirAmount = item.Amount; + + if( theirAmount <= need ) + { + toDelete.Enqueue( item ); + consumed += theirAmount; + } + else + { + item.Amount -= need; + consumed += need; + + return; + } + } + else if( recurse && item is Container ) + { + RecurseConsumeUpTo( item, type, amount, recurse, ref consumed, toDelete ); + } + } + } + } + + #endregion + + #region Get[BestGroup]Amount + public int GetBestGroupAmount( Type type, bool recurse, CheckItemGroup grouper ) + { + if( grouper == null ) + throw new ArgumentNullException(); + + int best = 0; + + Item[] typedItems = FindItemsByType( type, recurse ); + + List> groups = new List>(); + int idx = 0; + + while( idx < typedItems.Length ) + { + Item a = typedItems[idx++]; + List group = new List(); + + group.Add( a ); + + while( idx < typedItems.Length ) + { + Item b = typedItems[idx]; + int v = grouper( a, b ); + + if( v == 0 ) + group.Add( b ); + else + break; + + ++idx; + } + + groups.Add( group ); + } + + for( int i = 0; i < groups.Count; ++i ) + { + Item[] items = groups[i].ToArray(); + + //Item[] items = (Item[])(((ArrayList)groups[i]).ToArray( typeof( Item ) )); + int total = 0; + + for( int j = 0; j < items.Length; ++j ) + total += items[j].Amount; + + if( total >= best ) + best = total; + } + + return best; + } + + public int GetBestGroupAmount( Type[] types, bool recurse, CheckItemGroup grouper ) + { + if( grouper == null ) + throw new ArgumentNullException(); + + int best = 0; + + Item[] typedItems = FindItemsByType( types, recurse ); + + List> groups = new List>(); + int idx = 0; + + while( idx < typedItems.Length ) + { + Item a = typedItems[idx++]; + List group = new List(); + + group.Add( a ); + + while( idx < typedItems.Length ) + { + Item b = typedItems[idx]; + int v = grouper( a, b ); + + if( v == 0 ) + group.Add( b ); + else + break; + + ++idx; + } + + groups.Add( group ); + } + + for( int j = 0; j < groups.Count; ++j ) + { + Item[] items = groups[j].ToArray(); + //Item[] items = (Item[])(((ArrayList)groups[j]).ToArray( typeof( Item ) )); + int total = 0; + + for( int k = 0; k < items.Length; ++k ) + total += items[k].Amount; + + if( total >= best ) + best = total; + } + + return best; + } + + public int GetBestGroupAmount( Type[][] types, bool recurse, CheckItemGroup grouper ) + { + if( grouper == null ) + throw new ArgumentNullException(); + + int best = 0; + + for( int i = 0; i < types.Length; ++i ) + { + Item[] typedItems = FindItemsByType( types[i], recurse ); + + List> groups = new List>(); + int idx = 0; + + while( idx < typedItems.Length ) + { + Item a = typedItems[idx++]; + List group = new List(); + + group.Add( a ); + + while( idx < typedItems.Length ) + { + Item b = typedItems[idx]; + int v = grouper( a, b ); + + if( v == 0 ) + group.Add( b ); + else + break; + + ++idx; + } + + groups.Add( group ); + } + + for( int j = 0; j < groups.Count; ++j ) + { + Item[] items = groups[j].ToArray(); + //Item[] items = (Item[])(((ArrayList)groups[j]).ToArray( typeof( Item ) )); + int total = 0; + + for( int k = 0; k < items.Length; ++k ) + total += items[k].Amount; + + if( total >= best ) + best = total; + } + } + + return best; + } + + public int GetAmount( Type type ) + { + return GetAmount( type, true ); + } + + public int GetAmount( Type type, bool recurse ) + { + Item[] items = FindItemsByType( type, recurse ); + + int amount = 0; + + for ( int i = 0; i < items.Length; ++i ) + amount += items[i].Amount; + + return amount; + } + + public int GetAmount( Type[] types ) + { + return GetAmount( types, true ); + } + + public int GetAmount( Type[] types, bool recurse ) + { + Item[] items = FindItemsByType( types, recurse ); + + int amount = 0; + + for ( int i = 0; i < items.Length; ++i ) + amount += items[i].Amount; + + return amount; + } + #endregion + + private static List m_FindItemsList = new List(); + + #region Non-Generic FindItem[s] by Type + public Item[] FindItemsByType( Type type ) + { + return FindItemsByType( type, true ); + } + + public Item[] FindItemsByType( Type type, bool recurse ) + { + if ( m_FindItemsList.Count > 0 ) + m_FindItemsList.Clear(); + + RecurseFindItemsByType( this, type, recurse, m_FindItemsList ); + + return m_FindItemsList.ToArray(); + } + + private static void RecurseFindItemsByType( Item current, Type type, bool recurse, List list ) + { + if ( current != null && current.Items.Count > 0 ) + { + List items = current.Items; + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if ( type.IsAssignableFrom( item.GetType() ) )// item.GetType().IsAssignableFrom( type ) ) + list.Add( item ); + + if ( recurse && item is Container ) + RecurseFindItemsByType( item, type, recurse, list ); + } + } + } + + public Item[] FindItemsByType( Type[] types ) + { + return FindItemsByType( types, true ); + } + + public Item[] FindItemsByType( Type[] types, bool recurse ) + { + if( m_FindItemsList.Count > 0 ) + m_FindItemsList.Clear(); + + RecurseFindItemsByType( this, types, recurse, m_FindItemsList ); + + return m_FindItemsList.ToArray(); + } + + private static void RecurseFindItemsByType( Item current, Type[] types, bool recurse, List list ) + { + if( current != null && current.Items.Count > 0 ) + { + List items = current.Items; + + for( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if( InTypeList( item, types ) ) + list.Add( item ); + + if( recurse && item is Container ) + RecurseFindItemsByType( item, types, recurse, list ); + } + } + } + + public Item FindItemByType( Type type ) + { + return FindItemByType( type, true ); + } + + public Item FindItemByType( Type type, bool recurse ) + { + return RecurseFindItemByType( this, type, recurse ); + } + + private static Item RecurseFindItemByType( Item current, Type type, bool recurse ) + { + if( current != null && current.Items.Count > 0 ) + { + List list = current.Items; + + for( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if( type.IsAssignableFrom( item.GetType() ) ) + { + return item; + } + else if( recurse && item is Container ) + { + Item check = RecurseFindItemByType( item, type, recurse ); + + if( check != null ) + return check; + } + } + } + + return null; + } + + public Item FindItemByType( Type[] types ) + { + return FindItemByType( types, true ); + } + + public Item FindItemByType( Type[] types, bool recurse ) + { + return RecurseFindItemByType( this, types, recurse ); + } + + private static Item RecurseFindItemByType( Item current, Type[] types, bool recurse ) + { + if( current != null && current.Items.Count > 0 ) + { + List list = current.Items; + + for( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if( InTypeList( item, types ) ) + { + return item; + } + else if( recurse && item is Container ) + { + Item check = RecurseFindItemByType( item, types, recurse ); + + if( check != null ) + return check; + } + } + } + + return null; + } + + #endregion + + #region Generic FindItem[s] by Type + public List FindItemsByType() where T : Item + { + return FindItemsByType( true, null ); + } + + public List FindItemsByType( bool recurse ) where T : Item + { + return FindItemsByType( recurse, null ); + } + + public List FindItemsByType( Predicate predicate ) where T : Item + { + return FindItemsByType( true, predicate ); + } + + public List FindItemsByType( bool recurse, Predicate predicate ) where T : Item + { + if( m_FindItemsList.Count > 0 ) + m_FindItemsList.Clear(); + + List list = new List(); + + RecurseFindItemsByType( this, recurse, list, predicate ); + + return list; + } + + private static void RecurseFindItemsByType( Item current, bool recurse, List list, Predicate predicate ) where T : Item + { + if( current != null && current.Items.Count > 0 ) + { + List items = current.Items; + + for( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if( typeof( T ).IsAssignableFrom( item.GetType() ) ) + { + T typedItem = (T)item; + + if( predicate == null || predicate( typedItem ) ) + list.Add( typedItem ); + } + + if( recurse && item is Container ) + RecurseFindItemsByType( item, recurse, list, predicate ); + } + } + } + + public T FindItemByType() where T : Item + { + return FindItemByType( true ); + } + + + public T FindItemByType( Predicate predicate ) where T : Item + { + return FindItemByType( true, predicate ); + } + + public T FindItemByType( bool recurse ) where T : Item + { + return FindItemByType( recurse, null ); + } + + public T FindItemByType( bool recurse, Predicate predicate ) where T : Item + { + return RecurseFindItemByType( this, recurse, predicate ); + } + + private static T RecurseFindItemByType( Item current, bool recurse, Predicate predicate ) where T : Item + { + if( current != null && current.Items.Count > 0 ) + { + List list = current.Items; + + for( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if( typeof( T ).IsAssignableFrom( item.GetType() ) ) + { + T typedItem = (T)item; + + if( predicate == null || predicate( typedItem ) ) + return typedItem; + } + else if( recurse && item is Container ) + { + T check = RecurseFindItemByType( item, recurse, predicate ); + + if( check != null ) + return check; + } + } + } + + return null; + } + #endregion + + + private static bool InTypeList( Item item, Type[] types ) + { + Type t = item.GetType(); + + for ( int i = 0; i < types.Length; ++i ) + if ( types[i].IsAssignableFrom( t ) ) + return true; + + return false; + } + + private static void SetSaveFlag( ref SaveFlag flags, SaveFlag toSet, bool setIf ) + { + if ( setIf ) + flags |= toSet; + } + + private static bool GetSaveFlag( SaveFlag flags, SaveFlag toGet ) + { + return ( (flags & toGet) != 0 ); + } + + [Flags] + private enum SaveFlag : byte + { + None = 0x00000000, + MaxItems = 0x00000001, + GumpID = 0x00000002, + DropSound = 0x00000004, + LiftOverride = 0x00000008 + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 2 ); // version + + SaveFlag flags = SaveFlag.None; + + SetSaveFlag( ref flags, SaveFlag.MaxItems, m_MaxItems != -1 ); + SetSaveFlag( ref flags, SaveFlag.GumpID, m_GumpID != -1 ); + SetSaveFlag( ref flags, SaveFlag.DropSound, m_DropSound != -1 ); + SetSaveFlag( ref flags, SaveFlag.LiftOverride, m_LiftOverride ); + + writer.Write( (byte) flags ); + + if ( GetSaveFlag( flags, SaveFlag.MaxItems ) ) + writer.WriteEncodedInt( (int) m_MaxItems ); + + if ( GetSaveFlag( flags, SaveFlag.GumpID ) ) + writer.WriteEncodedInt( (int) m_GumpID ); + + if ( GetSaveFlag( flags, SaveFlag.DropSound ) ) + writer.WriteEncodedInt( (int) m_DropSound ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 2: + { + SaveFlag flags = (SaveFlag)reader.ReadByte(); + + if ( GetSaveFlag( flags, SaveFlag.MaxItems ) ) + m_MaxItems = reader.ReadEncodedInt(); + else + m_MaxItems = -1; + + if ( GetSaveFlag( flags, SaveFlag.GumpID ) ) + m_GumpID = reader.ReadEncodedInt(); + else + m_GumpID = -1; + + if ( GetSaveFlag( flags, SaveFlag.DropSound ) ) + m_DropSound = reader.ReadEncodedInt(); + else + m_DropSound = -1; + + m_LiftOverride = GetSaveFlag( flags, SaveFlag.LiftOverride ); + + break; + } + case 1: + { + m_MaxItems = reader.ReadInt(); + goto case 0; + } + case 0: + { + if ( version < 1 ) + m_MaxItems = m_GlobalMaxItems; + + m_GumpID = reader.ReadInt(); + m_DropSound = reader.ReadInt(); + + if ( m_GumpID == DefaultGumpID ) + m_GumpID = -1; + + if ( m_DropSound == DefaultDropSound ) + m_DropSound = -1; + + if ( m_MaxItems == DefaultMaxItems ) + m_MaxItems = -1; + + //m_Bounds = new Rectangle2D( reader.ReadPoint2D(), reader.ReadPoint2D() ); + reader.ReadPoint2D(); + reader.ReadPoint2D(); + + break; + } + } + + UpdateContainerData(); + } + + private static int m_GlobalMaxItems = 125; + private static int m_GlobalMaxWeight = 400; + + public static int GlobalMaxItems{ get{ return m_GlobalMaxItems; } set{ m_GlobalMaxItems = value; } } + public static int GlobalMaxWeight{ get{ return m_GlobalMaxWeight; } set{ m_GlobalMaxWeight = value; } } + + public Container( int itemID ) : base( itemID ) + { + m_GumpID = -1; + m_DropSound = -1; + m_MaxItems = -1; + + UpdateContainerData(); + } + + public override int GetTotal( TotalType type ) + { + switch ( type ) + { + case TotalType.Gold: + return m_TotalGold; + + case TotalType.Items: + return m_TotalItems; + + case TotalType.Weight: + return m_TotalWeight; + } + + return base.GetTotal( type ); + } + + public override void UpdateTotal( Item sender, TotalType type, int delta ) + { + if ( sender != this && delta != 0 && !sender.IsVirtualItem ) + { + switch ( type ) + { + case TotalType.Gold: + m_TotalGold += delta; + break; + + case TotalType.Items: + m_TotalItems += delta; + InvalidateProperties(); + break; + + case TotalType.Weight: + m_TotalWeight += delta; + InvalidateProperties(); + break; + } + } + + base.UpdateTotal( sender, type, delta ); + } + + public override void UpdateTotals() + { + m_TotalGold = 0; + m_TotalItems = 0; + m_TotalWeight = 0; + + List items = m_Items; + + if ( items == null ) + return; + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + item.UpdateTotals(); + + if ( item.IsVirtualItem ) + continue; + + m_TotalGold += item.TotalGold; + m_TotalItems += item.TotalItems + 1; + m_TotalWeight += item.TotalWeight + item.PileWeight; + } + } + + public Container( Serial serial ) : base( serial ) + { + } + + public virtual bool OnStackAttempt( Mobile from, Item stack, Item dropped ) + { + if ( !CheckHold( from, dropped, true, false ) ) + return false; + + return stack.StackWith( from, dropped ); + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( TryDropItem( from, dropped, true ) ) + { + from.SendSound( GetDroppedSound( dropped ), GetWorldLocation() ); + + return true; + } + else + { + return false; + } + } + + public virtual bool TryDropItem( Mobile from, Item dropped, bool sendFullMessage ) + { + if ( !CheckHold( from, dropped, sendFullMessage, true ) ) + return false; + + List list = this.Items; + + for ( int i = 0; i < list.Count; ++i ) + { + Item item = list[i]; + + if ( !(item is Container) && item.StackWith( from, dropped, false ) ) + return true; + } + + DropItem( dropped ); + + return true; + } + + public virtual void Destroy() + { + Point3D loc = GetWorldLocation(); + Map map = Map; + + for ( int i = Items.Count - 1; i >= 0; --i ) + { + if ( i < Items.Count ) + { + Items[i].SetLastMoved(); + Items[i].MoveToWorld( loc, map ); + } + } + + Delete(); + } + + public virtual void DropItem( Item dropped ) + { + if ( dropped == null ) + return; + + AddItem( dropped ); + + Rectangle2D bounds = dropped.GetGraphicBounds(); + Rectangle2D ourBounds = this.Bounds; + + int x, y; + + if ( bounds.Width >= ourBounds.Width ) + x = (ourBounds.Width - bounds.Width) / 2; + else + x = Utility.Random( ourBounds.Width - bounds.Width ); + + if ( bounds.Height >= ourBounds.Height ) + y = (ourBounds.Height - bounds.Height) / 2; + else + y = Utility.Random( ourBounds.Height - bounds.Height ); + + x += ourBounds.X; + x -= bounds.X; + + y += ourBounds.Y; + y -= bounds.Y; + + dropped.Location = new Point3D( x, y, 0 ); + } + + public override void OnDoubleClickSecureTrade( Mobile from ) + { + if ( from.InRange( GetWorldLocation(), 2 ) ) + { + DisplayTo( from ); + + SecureTradeContainer cont = GetSecureTradeCont(); + + if ( cont != null ) + { + SecureTrade trade = cont.Trade; + + if ( trade != null && trade.From.Mobile == from ) + DisplayTo( trade.To.Mobile ); + else if ( trade != null && trade.To.Mobile == from ) + DisplayTo( trade.From.Mobile ); + } + } + else + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + + public virtual bool DisplaysContent{ get{ return true; } } + + public virtual bool CheckContentDisplay( Mobile from ) + { + if ( !DisplaysContent ) + return false; + + object root = this.RootParent; + + if ( root == null || root is Item || root == from || from.AccessLevel > AccessLevel.Player ) + return true; + + return false; + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + if ( CheckContentDisplay( from ) ) + LabelTo( from, "({0} items, {1} stones)", TotalItems, TotalWeight ); + } + + private List m_Openers; + + public List Openers + { + get{ return m_Openers; } + set{ m_Openers = value; } + } + + public virtual bool IsPublicContainer{ get{ return false; } } + + public override void OnDelete() + { + base.OnDelete(); + + m_Openers = null; + } + + public virtual void DisplayTo( Mobile to ) + { + ProcessOpeners( to ); + + NetState ns = to.NetState; + + if ( ns == null ) + return; + + if ( ns.HighSeas ) + to.Send( new ContainerDisplayHS( this ) ); + else + to.Send( new ContainerDisplay( this ) ); + + if ( ns.ContainerGridLines ) + to.Send( new ContainerContent6017( to, this ) ); + else + to.Send( new ContainerContent( to, this ) ); + + if ( ObjectPropertyList.Enabled ) + { + List items = this.Items; + + for ( int i = 0; i < items.Count; ++i ) + to.Send( items[i].OPLPacket ); + } + } + + public void ProcessOpeners( Mobile opener ) + { + if ( !IsPublicContainer ) + { + bool contains = false; + + if ( m_Openers != null ) + { + Point3D worldLoc = GetWorldLocation(); + Map map = this.Map; + + for ( int i = 0; i < m_Openers.Count; ++i ) + { + Mobile mob = m_Openers[i]; + + if ( mob == opener ) + { + contains = true; + } + else + { + int range = GetUpdateRange( mob ); + + if ( mob.Map != map || !mob.InRange( worldLoc, range ) ) + m_Openers.RemoveAt( i-- ); + } + } + } + + if ( !contains ) + { + if ( m_Openers == null ) + { + m_Openers = new List(); + } + + m_Openers.Add( opener ); + } + else if ( m_Openers != null && m_Openers.Count == 0 ) + { + m_Openers = null; + } + } + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + if( DisplaysContent )//CheckContentDisplay( from ) ) + { + if( Core.ML ) + { + if( ParentsContain() ) //Root Parent is the Mobile. Parent could be another containter. + list.Add( 1073841, "{0}\t{1}\t{2}", TotalItems, MaxItems, TotalWeight ); // Contents: ~1_COUNT~/~2_MAXCOUNT~ items, ~3_WEIGHT~ stones + else + list.Add( 1072241, "{0}\t{1}\t{2}\t{3}", TotalItems, MaxItems, TotalWeight, MaxWeight ); // Contents: ~1_COUNT~/~2_MAXCOUNT~ items, ~3_WEIGHT~/~4_MAXWEIGHT~ stones + + //TODO: Where do the other clilocs come into play? 1073839 & 1073840? + } + else + { + list.Add( 1050044, "{0}\t{1}", TotalItems, TotalWeight ); // ~1_COUNT~ items, ~2_WEIGHT~ stones + } + } + } + + public override void OnDoubleClick( Mobile from ) + { + if ( from.AccessLevel > AccessLevel.Player || from.InRange( this.GetWorldLocation(), 2 ) ) + DisplayTo( from ); + else + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + } + + public class ContainerData + { + static ContainerData() + { + m_Table = new Dictionary(); + + string path = Path.Combine( Core.BaseDirectory, "Data/containers.cfg" ); + + if ( !File.Exists( path ) ) + { + m_Default = new ContainerData( 0x3C, new Rectangle2D( 44, 65, 142, 94 ), 0x48 ); + return; + } + + using ( StreamReader reader = new StreamReader( path ) ) + { + string line; + + while ( (line = reader.ReadLine()) != null ) + { + line = line.Trim(); + + if ( line.Length == 0 || line.StartsWith( "#" ) ) + continue; + + try + { + string[] split = line.Split( '\t' ); + + if ( split.Length >= 3 ) + { + int gumpID = Utility.ToInt32( split[0] ); + + string[] aRect = split[1].Split( ' ' ); + if ( aRect.Length < 4 ) + continue; + + int x = Utility.ToInt32( aRect[0] ); + int y = Utility.ToInt32( aRect[1] ); + int width = Utility.ToInt32( aRect[2] ); + int height = Utility.ToInt32( aRect[3] ); + + Rectangle2D bounds = new Rectangle2D( x, y, width, height ); + + int dropSound = Utility.ToInt32( split[2] ); + + ContainerData data = new ContainerData( gumpID, bounds, dropSound ); + + if ( m_Default == null ) + m_Default = data; + + if ( split.Length >= 4 ) + { + string[] aIDs = split[3].Split( ',' ); + + for ( int i = 0; i < aIDs.Length; i++ ) + { + int id = Utility.ToInt32( aIDs[i] ); + + if ( m_Table.ContainsKey( id ) ) + { + Console.WriteLine( @"Warning: double ItemID entry in Data\containers.cfg" ); + } + else + { + m_Table[id] = data; + } + } + } + } + } + catch + { + } + } + } + + if ( m_Default == null ) + m_Default = new ContainerData( 0x3C, new Rectangle2D( 44, 65, 142, 94 ), 0x48 ); + } + + private static ContainerData m_Default; + private static Dictionary m_Table; + + public static ContainerData Default + { + get{ return m_Default; } + set{ m_Default = value; } + } + + public static ContainerData GetData( int itemID ) + { + ContainerData data = null; + m_Table.TryGetValue( itemID, out data ); + + if ( data != null ) + return data; + else + return m_Default; + } + + private int m_GumpID; + private Rectangle2D m_Bounds; + private int m_DropSound; + + public int GumpID{ get{ return m_GumpID; } } + public Rectangle2D Bounds{ get{ return m_Bounds; } } + public int DropSound{ get{ return m_DropSound; } } + + public ContainerData( int gumpID, Rectangle2D bounds, int dropSound ) + { + m_GumpID = gumpID; + m_Bounds = bounds; + m_DropSound = dropSound; + } + } +} \ No newline at end of file diff --git a/Server/Items/Containers.cs b/Server/Items/Containers.cs new file mode 100644 index 0000000..afb8f4d --- /dev/null +++ b/Server/Items/Containers.cs @@ -0,0 +1,166 @@ +/*************************************************************************** + * Containers.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Containers.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Items +{ + public class BankBox : Container + { + private Mobile m_Owner; + private bool m_Open; + + public override int DefaultMaxWeight + { + get + { + return 0; + } + } + + public override bool IsVirtualItem + { + get { return true; } + } + + public BankBox( Serial serial ) : base( serial ) + { + } + + public Mobile Owner + { + get + { + return m_Owner; + } + } + + public bool Opened + { + get + { + return m_Open; + } + } + + public void Open() + { + m_Open = true; + + if ( m_Owner != null ) + { + m_Owner.PrivateOverheadMessage( MessageType.Regular, 0x3B2, true, String.Format( "Bank container has {0} items, {1} stones", TotalItems, TotalWeight ), m_Owner.NetState ); + m_Owner.Send( new EquipUpdate( this ) ); + DisplayTo( m_Owner ); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + + writer.Write( (Mobile) m_Owner ); + writer.Write( (bool) m_Open ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + + switch ( version ) + { + case 0: + { + m_Owner = reader.ReadMobile(); + m_Open = reader.ReadBool(); + + if ( m_Owner == null ) + Delete(); + + break; + } + } + + if ( this.ItemID == 0xE41 ) + this.ItemID = 0xE7C; + } + + private static bool m_SendRemovePacket; + + public static bool SendDeleteOnClose{ get{ return m_SendRemovePacket; } set{ m_SendRemovePacket = value; } } + + public void Close() + { + m_Open = false; + + if ( m_Owner != null && m_SendRemovePacket ) + m_Owner.Send( this.RemovePacket ); + } + + public override void OnSingleClick( Mobile from ) + { + } + + public override void OnDoubleClick( Mobile from ) + { + } + + public override DeathMoveResult OnParentDeath( Mobile parent ) + { + return DeathMoveResult.RemainEquiped; + } + + public BankBox( Mobile owner ) : base( 0xE7C ) + { + Layer = Layer.Bank; + Movable = false; + m_Owner = owner; + } + + public override bool IsAccessibleTo(Mobile check) + { + if ( ( check == m_Owner && m_Open ) || check.AccessLevel >= AccessLevel.GameMaster ) + return base.IsAccessibleTo (check); + else + return false; + } + + public override bool OnDragDrop( Mobile from, Item dropped ) + { + if ( ( from == m_Owner && m_Open ) || from.AccessLevel >= AccessLevel.GameMaster ) + return base.OnDragDrop( from, dropped ); + else + return false; + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if ( ( from == m_Owner && m_Open ) || from.AccessLevel >= AccessLevel.GameMaster ) + return base.OnDragDropInto (from, item, p); + else + return false; + } + } +} \ No newline at end of file diff --git a/Server/Items/SecureTradeContainer.cs b/Server/Items/SecureTradeContainer.cs new file mode 100644 index 0000000..9f7ce8f --- /dev/null +++ b/Server/Items/SecureTradeContainer.cs @@ -0,0 +1,119 @@ +/*************************************************************************** + * SecureTradeContainer.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: SecureTradeContainer.cs 793 2011-12-18 05:09:31Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Items +{ + public class SecureTradeContainer : Container + { + private SecureTrade m_Trade; + + public SecureTrade Trade + { + get + { + return m_Trade; + } + } + + public SecureTradeContainer( SecureTrade trade ) : base( 0x1E5E ) + { + m_Trade = trade; + + Movable = false; + } + + public SecureTradeContainer( Serial serial ) : base( serial ) + { + } + + public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight ) + { + Mobile to; + + if ( this.Trade.From.Container != this ) + to = this.Trade.From.Mobile; + else + to = this.Trade.To.Mobile; + + return m.CheckTrade( to, item, this, message, checkItems, plusItems, plusWeight ); + } + + public override bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + reject = LRReason.CannotLift; + return false; + } + + public override bool IsAccessibleTo( Mobile check ) + { + if (!IsChildOf(check) || m_Trade == null || !m_Trade.Valid) + return false; + + return base.IsAccessibleTo( check ); + } + + public override void OnItemAdded( Item item ) + { + ClearChecks(); + } + + public override void OnItemRemoved( Item item ) + { + ClearChecks(); + } + + public override void OnSubItemAdded( Item item ) + { + ClearChecks(); + } + + public override void OnSubItemRemoved( Item item ) + { + ClearChecks(); + } + + public void ClearChecks() + { + if ( m_Trade != null ) + { + m_Trade.From.Accepted = false; + m_Trade.To.Accepted = false; + m_Trade.Update(); + } + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + + int version = reader.ReadInt(); + } + } +} \ No newline at end of file diff --git a/Server/Items/VirtualHair.cs b/Server/Items/VirtualHair.cs new file mode 100644 index 0000000..7358dfd --- /dev/null +++ b/Server/Items/VirtualHair.cs @@ -0,0 +1,177 @@ +/*************************************************************************** + * VirtualHair.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: VirtualHair.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server; +using Server.Network; + +namespace Server +{ + public abstract class BaseHairInfo + { + private int m_ItemID; + private int m_Hue; + + [CommandProperty( AccessLevel.GameMaster )] + public int ItemID { get { return m_ItemID; } set { m_ItemID = value; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int Hue { get { return m_Hue; } set { m_Hue = value; } } + + protected BaseHairInfo( int itemid ) + : this( itemid, 0 ) + { + } + + protected BaseHairInfo( int itemid, int hue ) + { + m_ItemID = itemid; + m_Hue = hue; + } + + protected BaseHairInfo( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch( version ) + { + case 0: + { + m_ItemID = reader.ReadInt(); + m_Hue = reader.ReadInt(); + break; + } + } + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.Write( (int)0 ); //version + writer.Write( (int)m_ItemID ); + writer.Write( (int)m_Hue ); + } + } + + public class HairInfo : BaseHairInfo + { + public HairInfo( int itemid ) + : base( itemid, 0 ) + { + } + + public HairInfo( int itemid, int hue ) + : base( itemid, hue ) + { + } + + public HairInfo( GenericReader reader ) + : base( reader ) + { + } + + public static int FakeSerial( Mobile parent ) + { + return (0x7FFFFFFF - 0x400 - (parent.Serial * 4)); + } + } + + public class FacialHairInfo : BaseHairInfo + { + public FacialHairInfo( int itemid ) + : base( itemid, 0 ) + { + } + + public FacialHairInfo( int itemid, int hue ) + : base( itemid, hue ) + { + } + + public FacialHairInfo( GenericReader reader ) + : base( reader ) + { + } + + public static int FakeSerial( Mobile parent ) + { + return (0x7FFFFFFF - 0x400 - 1 - (parent.Serial * 4)); + } + } + + public sealed class HairEquipUpdate : Packet + { + public HairEquipUpdate( Mobile parent ) + : base( 0x2E, 15 ) + { + int hue = parent.HairHue; + + if( parent.SolidHueOverride >= 0 ) + hue = parent.SolidHueOverride; + + int hairSerial = HairInfo.FakeSerial( parent ); + + m_Stream.Write( (int)hairSerial ); + m_Stream.Write( (short)parent.HairItemID ); + m_Stream.Write( (byte)0 ); + m_Stream.Write( (byte)Layer.Hair ); + m_Stream.Write( (int)parent.Serial ); + m_Stream.Write( (short)hue ); + } + } + + public sealed class FacialHairEquipUpdate : Packet + { + public FacialHairEquipUpdate( Mobile parent ) + : base( 0x2E, 15 ) + { + int hue = parent.FacialHairHue; + + if( parent.SolidHueOverride >= 0 ) + hue = parent.SolidHueOverride; + + int hairSerial = FacialHairInfo.FakeSerial( parent ); + + m_Stream.Write( (int)hairSerial ); + m_Stream.Write( (short)parent.FacialHairItemID ); + m_Stream.Write( (byte)0 ); + m_Stream.Write( (byte)Layer.FacialHair ); + m_Stream.Write( (int)parent.Serial ); + m_Stream.Write( (short)hue ); + } + } + + public sealed class RemoveHair : Packet + { + public RemoveHair( Mobile parent ) + : base( 0x1D, 5 ) + { + m_Stream.Write( (int)HairInfo.FakeSerial( parent ) ); + } + } + + public sealed class RemoveFacialHair : Packet + { + public RemoveFacialHair( Mobile parent ) + : base( 0x1D, 5 ) + { + m_Stream.Write( (int)FacialHairInfo.FakeSerial( parent ) ); + } + } +} \ No newline at end of file diff --git a/Server/KeywordList.cs b/Server/KeywordList.cs new file mode 100644 index 0000000..a120444 --- /dev/null +++ b/Server/KeywordList.cs @@ -0,0 +1,85 @@ +/*************************************************************************** + * KeywordList.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: KeywordList.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public class KeywordList + { + private int[] m_Keywords; + private int m_Count; + + public KeywordList() + { + m_Keywords = new int[8]; + m_Count = 0; + } + + public int Count + { + get + { + return m_Count; + } + } + + public bool Contains( int keyword ) + { + bool contains = false; + + for ( int i = 0; !contains && i < m_Count; ++i ) + contains = ( keyword == m_Keywords[i] ); + + return contains; + } + + public void Add( int keyword ) + { + if ( (m_Count + 1) > m_Keywords.Length ) + { + int[] old = m_Keywords; + m_Keywords = new int[old.Length * 2]; + + for ( int i = 0; i < old.Length; ++i ) + m_Keywords[i] = old[i]; + } + + m_Keywords[m_Count++] = keyword; + } + + private static int[] m_EmptyInts = new int[0]; + + public int[] ToArray() + { + if ( m_Count == 0 ) + return m_EmptyInts; + + int[] keywords = new int[m_Count]; + + for ( int i = 0; i < m_Count; ++i ) + keywords[i] = m_Keywords[i]; + + m_Count = 0; + + return keywords; + } + } +} \ No newline at end of file diff --git a/Server/Main.cs b/Server/Main.cs new file mode 100644 index 0000000..e195131 --- /dev/null +++ b/Server/Main.cs @@ -0,0 +1,799 @@ +/*************************************************************************** + * Main.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Main.cs 1064 2013-05-28 17:44:07Z mark@runuo.com $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +#if Framework_4_0 +using System.Threading.Tasks; +#endif + +using Server; +using Server.Accounting; +using Server.Gumps; +using Server.Network; +using System.Runtime; + +namespace Server +{ + public delegate void Slice(); + + public static class Core + { + private static bool m_Crashed; + private static Thread timerThread; + private static string m_BaseDirectory; + private static string m_ExePath; + private static List m_DataDirectories = new List(); + private static Assembly m_Assembly; + private static Process m_Process; + private static Thread m_Thread; + private static bool m_Service; + private static bool m_Debug; + private static bool m_Cache = true; + private static bool m_HaltOnWarning; + private static bool m_VBdotNET; + private static MultiTextWriter m_MultiConOut; + + private static bool m_Profiling; + private static DateTime m_ProfileStart; + private static TimeSpan m_ProfileTime; + + private static MessagePump m_MessagePump; + + public static MessagePump MessagePump + { + get { return m_MessagePump; } + set { m_MessagePump = value; } + } + + public static Slice Slice; + + public static bool Profiling + { + get { return m_Profiling; } + set + { + if( m_Profiling == value ) + return; + + m_Profiling = value; + + if( m_ProfileStart > DateTime.MinValue ) + m_ProfileTime += DateTime.Now - m_ProfileStart; + + m_ProfileStart = (m_Profiling ? DateTime.Now : DateTime.MinValue); + } + } + + public static TimeSpan ProfileTime + { + get + { + if( m_ProfileStart > DateTime.MinValue ) + return m_ProfileTime + (DateTime.Now - m_ProfileStart); + + return m_ProfileTime; + } + } + + public static bool Service { get { return m_Service; } } + public static bool Debug { get { return m_Debug; } } + internal static bool HaltOnWarning { get { return m_HaltOnWarning; } } + internal static bool VBdotNet { get { return m_VBdotNET; } } + public static List DataDirectories { get { return m_DataDirectories; } } + public static Assembly Assembly { get { return m_Assembly; } set { m_Assembly = value; } } + public static Version Version { get { return m_Assembly.GetName().Version; } } + public static Process Process { get { return m_Process; } } + public static Thread Thread { get { return m_Thread; } } + public static MultiTextWriter MultiConsoleOut { get { return m_MultiConOut; } } + +#if Framework_4_0 + public static readonly bool Is64Bit = Environment.Is64BitProcess; +#else + public static readonly bool Is64Bit = (IntPtr.Size == 8); //Returns the size for the current /process/ +#endif + + private static bool m_MultiProcessor; + private static int m_ProcessorCount; + + public static bool MultiProcessor { get { return m_MultiProcessor; } } + public static int ProcessorCount { get { return m_ProcessorCount; } } + + private static bool m_Unix; + + public static bool Unix { get { return m_Unix; } } + + public static string FindDataFile( string path ) + { + if( m_DataDirectories.Count == 0 ) + throw new InvalidOperationException( "Attempted to FindDataFile before DataDirectories list has been filled." ); + + string fullPath = null; + + for( int i = 0; i < m_DataDirectories.Count; ++i ) + { + fullPath = Path.Combine( m_DataDirectories[i], path ); + + if( File.Exists( fullPath ) ) + break; + + fullPath = null; + } + + return fullPath; + } + + public static string FindDataFile( string format, params object[] args ) + { + return FindDataFile( String.Format( format, args ) ); + } + + #region Expansions + + private static Expansion m_Expansion; + public static Expansion Expansion + { + get { return m_Expansion; } + set { m_Expansion = value; } + } + + public static bool T2A + { + get { return m_Expansion >= Expansion.T2A; } + } + + public static bool UOR + { + get { return m_Expansion >= Expansion.UOR; } + } + + public static bool UOTD + { + get { return m_Expansion >= Expansion.UOTD; } + } + + public static bool LBR + { + get { return m_Expansion >= Expansion.LBR; } + } + + public static bool AOS + { + get { return m_Expansion >= Expansion.AOS; } + } + + public static bool SE + { + get { return m_Expansion >= Expansion.SE; } + } + + public static bool ML + { + get { return m_Expansion >= Expansion.ML; } + } + + public static bool SA + { + get { return m_Expansion >= Expansion.SA; } + } + + public static bool HS + { + get { return m_Expansion >= Expansion.HS; } + } + + #endregion + + public static string ExePath + { + get + { + if( m_ExePath == null ) + { + m_ExePath = Assembly.Location; + //m_ExePath = Process.GetCurrentProcess().MainModule.FileName; + } + + return m_ExePath; + } + } + + public static string BaseDirectory + { + get + { + if( m_BaseDirectory == null ) + { + try + { + m_BaseDirectory = ExePath; + + if( m_BaseDirectory.Length > 0 ) + m_BaseDirectory = Path.GetDirectoryName( m_BaseDirectory ); + } + catch + { + m_BaseDirectory = ""; + } + } + + return m_BaseDirectory; + } + } + + private static void CurrentDomain_UnhandledException( object sender, UnhandledExceptionEventArgs e ) + { + Console.WriteLine( e.IsTerminating ? "Error:" : "Warning:" ); + Console.WriteLine( e.ExceptionObject ); + + if( e.IsTerminating ) + { + m_Crashed = true; + + bool close = false; + + try + { + CrashedEventArgs args = new CrashedEventArgs( e.ExceptionObject as Exception ); + + EventSink.InvokeCrashed( args ); + + close = args.Close; + } + catch + { + } + + if( !close && !m_Service ) + { + try + { + for( int i = 0; i < m_MessagePump.Listeners.Length; i++ ) + { + m_MessagePump.Listeners[i].Dispose(); + } + } + catch + { + } + + Console.WriteLine("This exception is fatal, press return to exit"); + Console.ReadLine(); + } + + Kill(); + } + } + + private enum ConsoleEventType + { + CTRL_C_EVENT, + CTRL_BREAK_EVENT, + CTRL_CLOSE_EVENT, + CTRL_LOGOFF_EVENT=5, + CTRL_SHUTDOWN_EVENT + } + + private delegate bool ConsoleEventHandler( ConsoleEventType type ); + private static ConsoleEventHandler m_ConsoleEventHandler; + + [DllImport( "Kernel32" )] + private static extern bool SetConsoleCtrlHandler( ConsoleEventHandler callback, bool add ); + + private static bool OnConsoleEvent( ConsoleEventType type ) + { + if( World.Saving || ( m_Service && type == ConsoleEventType.CTRL_LOGOFF_EVENT ) ) + return true; + + Kill(); //Kill -> HandleClosed will hadnle waiting for the completion of flushign to disk + + return true; + } + + private static void CurrentDomain_ProcessExit( object sender, EventArgs e ) + { + HandleClosed(); + } + + private static bool m_Closing; + public static bool Closing { get { return m_Closing; } } + + private static long m_CycleIndex = 1; + private static float[] m_CyclesPerSecond = new float[100]; + + public static float CyclesPerSecond + { + get { return m_CyclesPerSecond[(m_CycleIndex - 1) % m_CyclesPerSecond.Length]; } + } + + public static float AverageCPS + { + get + { + float t = 0.0f; + int c = 0; + + for( int i = 0; i < m_CycleIndex && i < m_CyclesPerSecond.Length; ++i ) + { + t += m_CyclesPerSecond[i]; + ++c; + } + + return (t / Math.Max( c, 1 )); + } + } + + public static void Kill() + { + Kill( false ); + } + + public static void Kill( bool restart ) + { + HandleClosed(); + + if ( restart ) + Process.Start( ExePath, Arguments ); + + m_Process.Kill(); + } + + private static void HandleClosed() + { + if( m_Closing ) + return; + + m_Closing = true; + + Console.Write( "Exiting..." ); + + World.WaitForWriteCompletion(); + + if( !m_Crashed ) + EventSink.InvokeShutdown( new ShutdownEventArgs() ); + + Timer.TimerThread.Set(); + + Console.WriteLine( "done" ); + } + + private static AutoResetEvent m_Signal = new AutoResetEvent( true ); + public static void Set() { m_Signal.Set(); } + + public static void Main( string[] args ) + { + AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler( CurrentDomain_UnhandledException ); + AppDomain.CurrentDomain.ProcessExit += new EventHandler( CurrentDomain_ProcessExit ); + + for( int i = 0; i < args.Length; ++i ) + { + if ( Insensitive.Equals( args[i], "-debug" ) ) + m_Debug = true; + else if ( Insensitive.Equals( args[i], "-service" ) ) + m_Service = true; + else if ( Insensitive.Equals( args[i], "-profile" ) ) + Profiling = true; + else if ( Insensitive.Equals( args[i], "-nocache" ) ) + m_Cache = false; + else if ( Insensitive.Equals( args[i], "-haltonwarning" ) ) + m_HaltOnWarning = true; + else if ( Insensitive.Equals( args[i], "-vb" ) ) + m_VBdotNET = true; + } + + try + { + if( m_Service ) + { + if( !Directory.Exists( "Logs" ) ) + Directory.CreateDirectory( "Logs" ); + + Console.SetOut( m_MultiConOut = new MultiTextWriter( new FileLogger( "Logs/Console.log" ) ) ); + } + else + { + Console.SetOut( m_MultiConOut = new MultiTextWriter( Console.Out ) ); + } + } + catch + { + } + + m_Thread = Thread.CurrentThread; + m_Process = Process.GetCurrentProcess(); + m_Assembly = Assembly.GetEntryAssembly(); + + if( m_Thread != null ) + m_Thread.Name = "Core Thread"; + + if( BaseDirectory.Length > 0 ) + Directory.SetCurrentDirectory( BaseDirectory ); + + Timer.TimerThread ttObj = new Timer.TimerThread(); + timerThread = new Thread( new ThreadStart( ttObj.TimerMain ) ); + timerThread.Name = "Timer Thread"; + + Version ver = m_Assembly.GetName().Version; + + // Added to help future code support on forums, as a 'check' people can ask for to it see if they recompiled core or not + Console.WriteLine( "RunUO - [www.runuo.com] Version {0}.{1}, Build {2}.{3}", ver.Major, ver.Minor, ver.Build, ver.Revision ); + Console.WriteLine( "Core: Running on .NET Framework Version {0}.{1}.{2}", Environment.Version.Major, Environment.Version.Minor, Environment.Version.Build ); + + string s = Arguments; + + if( s.Length > 0 ) + Console.WriteLine( "Core: Running with arguments: {0}", s ); + + m_ProcessorCount = Environment.ProcessorCount; + + if( m_ProcessorCount > 1 ) + m_MultiProcessor = true; + + if( m_MultiProcessor || Is64Bit ) + Console.WriteLine( "Core: Optimizing for {0} {2}processor{1}", m_ProcessorCount, m_ProcessorCount == 1 ? "" : "s", Is64Bit ? "64-bit " : "" ); + + int platform = (int)Environment.OSVersion.Platform; + if( platform == 4 || platform == 128 ) { // MS 4, MONO 128 + m_Unix = true; + Console.WriteLine( "Core: Unix environment detected" ); + } + else { + m_ConsoleEventHandler = new ConsoleEventHandler( OnConsoleEvent ); + SetConsoleCtrlHandler( m_ConsoleEventHandler, true ); + } + + if ( GCSettings.IsServerGC ) + Console.WriteLine("Core: Server garbage collection mode enabled"); + + while( !ScriptCompiler.Compile( m_Debug, m_Cache ) ) + { + Console.WriteLine( "Scripts: One or more scripts failed to compile or no script files were found." ); + + if( m_Service ) + return; + + Console.WriteLine( " - Press return to exit, or R to try again." ); + + if( Console.ReadKey( true ).Key != ConsoleKey.R ) + return; + } + + ScriptCompiler.Invoke( "Configure" ); + + Region.Load(); + World.Load(); + + ScriptCompiler.Invoke( "Initialize" ); + + MessagePump messagePump = m_MessagePump = new MessagePump(); + + timerThread.Start(); + + for( int i = 0; i < Map.AllMaps.Count; ++i ) + Map.AllMaps[i].Tiles.Force(); + + NetState.Initialize(); + + EventSink.InvokeServerStarted(); + + try + { + DateTime now, last = DateTime.UtcNow; + + const int sampleInterval = 100; + const float ticksPerSecond = (float)(TimeSpan.TicksPerSecond * sampleInterval); + TimeSpan _oneMS = TimeSpan.FromMilliseconds(1); + + long sample = 0; + + while (!m_Closing) + { + m_Signal.WaitOne(_oneMS); + + Mobile.ProcessDeltaQueue(); + Item.ProcessDeltaQueue(); + + Timer.Slice(); + messagePump.Slice(); + + NetState.FlushAll(); + NetState.ProcessDisposedQueue(); + + if( Slice != null ) + Slice(); + + if( (++sample % sampleInterval) == 0 ) + { + now = DateTime.UtcNow; + m_CyclesPerSecond[m_CycleIndex++ % m_CyclesPerSecond.Length] = + ticksPerSecond / (now.Ticks - last.Ticks); + last = now; + } + } + } + catch( Exception e ) + { + CurrentDomain_UnhandledException( null, new UnhandledExceptionEventArgs( e, true ) ); + } + } + + public static string Arguments + { + get + { + StringBuilder sb = new StringBuilder(); + + if( Core.Debug ) + Utility.Separate( sb, "-debug", " " ); + + if( Core.Service ) + Utility.Separate( sb, "-service", " " ); + + if( Core.Profiling ) + Utility.Separate( sb, "-profile", " " ); + + if( !m_Cache ) + Utility.Separate( sb, "-nocache", " " ); + + if( m_HaltOnWarning ) + Utility.Separate( sb, "-haltonwarning", " " ); + + if ( m_VBdotNET ) + Utility.Separate( sb, "-vb", " " ); + + return sb.ToString(); + } + } + + private static int m_GlobalMaxUpdateRange = 24; + + public static int GlobalMaxUpdateRange + { + get { return m_GlobalMaxUpdateRange; } + set { m_GlobalMaxUpdateRange = value; } + } + + private static int m_ItemCount, m_MobileCount; + + public static int ScriptItems { get { return m_ItemCount; } } + public static int ScriptMobiles { get { return m_MobileCount; } } + + public static void VerifySerialization() + { + m_ItemCount = 0; + m_MobileCount = 0; + + VerifySerialization( Assembly.GetCallingAssembly() ); + + for( int a = 0; a < ScriptCompiler.Assemblies.Length; ++a ) + VerifySerialization( ScriptCompiler.Assemblies[a] ); + } + + private static readonly Type[] m_SerialTypeArray = new Type[1] { typeof(Serial) }; + + private static void VerifyType( Type t ) + { + bool isItem = t.IsSubclassOf(typeof(Item)); + + if (isItem || t.IsSubclassOf(typeof(Mobile))) + { + if (isItem) + { + //++m_ItemCount; + Interlocked.Increment(ref m_ItemCount); + } + else + { + //++m_MobileCount; + Interlocked.Increment(ref m_MobileCount); + } + + StringBuilder warningSb = null; + + try + { + /* + if( isItem && t.IsPublic && !t.IsAbstract ) + { + ConstructorInfo cInfo = t.GetConstructor( Type.EmptyTypes ); + + if( cInfo == null ) + { + if (warningSb == null) + warningSb = new StringBuilder(); + + warningSb.AppendLine(" - No zero paramater constructor"); + } + }*/ + + if (t.GetConstructor(m_SerialTypeArray) == null) + { + if (warningSb == null) + warningSb = new StringBuilder(); + + warningSb.AppendLine(" - No serialization constructor"); + } + + if (t.GetMethod("Serialize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) == null) + { + if (warningSb == null) + warningSb = new StringBuilder(); + + warningSb.AppendLine(" - No Serialize() method"); + } + + if (t.GetMethod("Deserialize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) == null) + { + if (warningSb == null) + warningSb = new StringBuilder(); + + warningSb.AppendLine(" - No Deserialize() method"); + } + + if (warningSb != null && warningSb.Length > 0) + { + Console.WriteLine("Warning: {0}\n{1}", t, warningSb.ToString()); + } + } + catch + { + Console.WriteLine("Warning: Exception in serialization verification of type {0}", t); + } + } + } + + private static void VerifySerialization( Assembly a ) + { + if( a == null ) + return; + +#if Framework_4_0 + Parallel.ForEach(a.GetTypes(), t => + { + VerifyType(t); + }); +#else + foreach (Type t in a.GetTypes()) + { + VerifyType(t); + } +#endif + } + } + + public class FileLogger : TextWriter, IDisposable + { + private string m_FileName; + private bool m_NewLine; + public const string DateFormat = "[MMMM dd hh:mm:ss.f tt]: "; + + public string FileName { get { return m_FileName; } } + + public FileLogger( string file ) + : this( file, false ) + { + } + + public FileLogger( string file, bool append ) + { + m_FileName = file; + using( StreamWriter writer = new StreamWriter( new FileStream( m_FileName, append ? FileMode.Append : FileMode.Create, FileAccess.Write, FileShare.Read ) ) ) + { + writer.WriteLine( ">>>Logging started on {0}.", DateTime.Now.ToString( "f" ) ); //f = Tuesday, April 10, 2001 3:51 PM + } + m_NewLine = true; + } + + public override void Write( char ch ) + { + using( StreamWriter writer = new StreamWriter( new FileStream( m_FileName, FileMode.Append, FileAccess.Write, FileShare.Read ) ) ) + { + if( m_NewLine ) + { + writer.Write( DateTime.Now.ToString( DateFormat ) ); + m_NewLine = false; + } + writer.Write( ch ); + } + } + + public override void Write( string str ) + { + using( StreamWriter writer = new StreamWriter( new FileStream( m_FileName, FileMode.Append, FileAccess.Write, FileShare.Read ) ) ) + { + if( m_NewLine ) + { + writer.Write( DateTime.Now.ToString( DateFormat ) ); + m_NewLine = false; + } + writer.Write( str ); + } + } + + public override void WriteLine( string line ) + { + using( StreamWriter writer = new StreamWriter( new FileStream( m_FileName, FileMode.Append, FileAccess.Write, FileShare.Read ) ) ) + { + if( m_NewLine ) + writer.Write( DateTime.Now.ToString( DateFormat ) ); + writer.WriteLine( line ); + m_NewLine = true; + } + } + + public override System.Text.Encoding Encoding + { + get { return System.Text.Encoding.Default; } + } + } + + public class MultiTextWriter : TextWriter + { + private List m_Streams; + + public MultiTextWriter( params TextWriter[] streams ) + { + m_Streams = new List( streams ); + + if( m_Streams.Count < 0 ) + throw new ArgumentException( "You must specify at least one stream." ); + } + + public void Add( TextWriter tw ) + { + m_Streams.Add( tw ); + } + + public void Remove( TextWriter tw ) + { + m_Streams.Remove( tw ); + } + + public override void Write( char ch ) + { + for( int i = 0; i < m_Streams.Count; i++ ) + m_Streams[i].Write( ch ); + } + + public override void WriteLine( string line ) + { + for( int i = 0; i < m_Streams.Count; i++ ) + m_Streams[i].WriteLine( line ); + } + + public override void WriteLine( string line, params object[] args ) + { + WriteLine( String.Format( line, args ) ); + } + + public override Encoding Encoding + { + get { return Encoding.Default; } + } + } +} \ No newline at end of file diff --git a/Server/Map.cs b/Server/Map.cs new file mode 100644 index 0000000..c4cc55d --- /dev/null +++ b/Server/Map.cs @@ -0,0 +1,2109 @@ +/*************************************************************************** + * Map.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Map.cs 871 2012-04-29 00:13:41Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Server.Items; +using Server.Network; +using Server.Targeting; + +namespace Server +{ + [Flags] + public enum MapRules + { + None = 0x0000, + Internal = 0x0001, // Internal map (used for dragging, commodity deeds, etc) + FreeMovement = 0x0002, // Anyone can move over anyone else without taking stamina loss + BeneficialRestrictions = 0x0004, // Disallow performing beneficial actions on criminals/murderers + HarmfulRestrictions = 0x0008, // Disallow performing harmful actions on innocents + TrammelRules = FreeMovement | BeneficialRestrictions | HarmfulRestrictions, + FeluccaRules = None + } + + public interface IPooledEnumerable : IEnumerable + { + void Free(); + } + + public interface IPooledEnumerator : IEnumerator + { + IPooledEnumerable Enumerable{ get; set; } + void Free(); + } + + [Parsable] + //[CustomEnum( new string[]{ "Felucca", "Trammel", "Ilshenar", "Malas", "Internal" } )] + public sealed class Map : IComparable, IComparable + { + public const int SectorSize = 16; + public const int SectorShift = 4; + public static int SectorActiveRange = 2; + + private static Map[] m_Maps = new Map[0x100]; + + public static Map[] Maps { get { return m_Maps; } } + + public static Map Felucca { get { return m_Maps[0]; } } + public static Map Trammel { get { return m_Maps[1]; } } + public static Map Ilshenar { get { return m_Maps[2]; } } + public static Map Malas { get { return m_Maps[3]; } } + public static Map Tokuno { get { return m_Maps[4]; } } + public static Map TerMur { get { return m_Maps[5]; } } + public static Map Internal { get { return m_Maps[0x7F]; } } + + // Scriptiz : ajout des 5 copies de Felucca (plus facile que de v�rifier le Name) + public static Map Felucca2 { get { return m_Maps[6]; } } + public static Map Felucca3 { get { return m_Maps[7]; } } + public static Map Felucca4 { get { return m_Maps[8]; } } + public static Map Felucca5 { get { return m_Maps[9]; } } + public static Map Felucca6 { get { return m_Maps[10]; } } + + // Scriptiz : ajout des 5 copies de Trammel (plus facile que de v�rifier le Name) + public static Map Trammel2 { get { return m_Maps[11]; } } + public static Map Trammel3 { get { return m_Maps[12]; } } + public static Map Trammel4 { get { return m_Maps[13]; } } + public static Map Trammel5 { get { return m_Maps[14]; } } + public static Map Trammel6 { get { return m_Maps[15]; } } + + private static List m_AllMaps = new List(); + + public static List AllMaps { get { return m_AllMaps; } } + + private int m_MapID, m_MapIndex, m_FileIndex; + + private int m_Width, m_Height; + private int m_SectorsWidth, m_SectorsHeight; + private int m_Season; + private Dictionary m_Regions; + private Region m_DefaultRegion; + + public int Season { get { return m_Season; } set { m_Season = value; } } + + private string m_Name; + private MapRules m_Rules; + private Sector[][] m_Sectors; + private Sector m_InvalidSector; + + private TileMatrix m_Tiles; + + private static string[] m_MapNames; + private static Map[] m_MapValues; + + public static string[] GetMapNames() + { + CheckNamesAndValues(); + return m_MapNames; + } + + public static Map[] GetMapValues() + { + CheckNamesAndValues(); + return m_MapValues; + } + + public static Map Parse( string value ) + { + CheckNamesAndValues(); + + for ( int i = 0; i < m_MapNames.Length; ++i ) + { + if ( Insensitive.Equals( m_MapNames[i], value ) ) + return m_MapValues[i]; + } + + int index; + + if( int.TryParse( value, out index ) ) + { + if( index >= 0 && index < m_Maps.Length && m_Maps[index] != null ) + return m_Maps[index]; + } + + throw new ArgumentException( "Invalid map name" ); + } + + private static void CheckNamesAndValues() + { + if ( m_MapNames != null && m_MapNames.Length == m_AllMaps.Count ) + return; + + m_MapNames = new string[m_AllMaps.Count]; + m_MapValues = new Map[m_AllMaps.Count]; + + for ( int i = 0; i < m_AllMaps.Count; ++i ) + { + Map map = m_AllMaps[i]; + + m_MapNames[i] = map.Name; + m_MapValues[i] = map; + } + } + + public override string ToString() + { + return m_Name; + } + + public int GetAverageZ( int x, int y ) + { + int z = 0, avg = 0, top = 0; + + GetAverageZ( x, y, ref z, ref avg, ref top ); + + return avg; + } + + public void GetAverageZ( int x, int y, ref int z, ref int avg, ref int top ) + { + int zTop = Tiles.GetLandTile( x, y ).Z; + int zLeft = Tiles.GetLandTile( x, y + 1 ).Z; + int zRight = Tiles.GetLandTile( x + 1, y ).Z; + int zBottom = Tiles.GetLandTile( x + 1, y + 1 ).Z; + + z = zTop; + if ( zLeft < z ) + z = zLeft; + if ( zRight < z ) + z = zRight; + if ( zBottom < z ) + z = zBottom; + + top = zTop; + if ( zLeft > top ) + top = zLeft; + if ( zRight > top ) + top = zRight; + if ( zBottom > top ) + top = zBottom; + + if ( Math.Abs( zTop - zBottom ) > Math.Abs( zLeft - zRight ) ) + avg = FloorAverage( zLeft, zRight ); + else + avg = FloorAverage( zTop, zBottom ); + } + + private static int FloorAverage( int a, int b ) + { + int v = a + b; + + if ( v < 0 ) + --v; + + return ( v / 2 ); + } + + #region Get*InRange/Bounds + public IPooledEnumerable GetObjectsInRange( Point3D p ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( ObjectEnumerator.Instantiate( this, new Rectangle2D( p.m_X - 18, p.m_Y - 18, 37, 37 ) ) ); + } + + public IPooledEnumerable GetObjectsInRange( Point3D p, int range ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( ObjectEnumerator.Instantiate( this, new Rectangle2D( p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1 ) ) ); + } + + public IPooledEnumerable GetObjectsInBounds( Rectangle2D bounds ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( ObjectEnumerator.Instantiate( this, bounds ) ); + } + + public IPooledEnumerable GetClientsInRange( Point3D p ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, new Rectangle2D( p.m_X - 18, p.m_Y - 18, 37, 37 ), SectorEnumeratorType.Clients ) ); + } + + public IPooledEnumerable GetClientsInRange( Point3D p, int range ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, new Rectangle2D( p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1 ), SectorEnumeratorType.Clients ) ); + } + + public IPooledEnumerable GetClientsInBounds( Rectangle2D bounds ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, bounds, SectorEnumeratorType.Clients ) ); + } + + public IPooledEnumerable GetItemsInRange( Point3D p ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, new Rectangle2D( p.m_X - 18, p.m_Y - 18, 37, 37 ), SectorEnumeratorType.Items ) ); + } + + public IPooledEnumerable GetItemsInRange( Point3D p, int range ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, new Rectangle2D( p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1 ), SectorEnumeratorType.Items ) ); + } + + public IPooledEnumerable GetItemsInBounds( Rectangle2D bounds ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, bounds, SectorEnumeratorType.Items ) ); + } + + public IPooledEnumerable GetMobilesInRange( Point3D p ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, new Rectangle2D( p.m_X - 18, p.m_Y - 18, 37, 37 ), SectorEnumeratorType.Mobiles ) ); + } + + public IPooledEnumerable GetMobilesInRange( Point3D p, int range ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, new Rectangle2D( p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1 ), SectorEnumeratorType.Mobiles ) ); + } + + public IPooledEnumerable GetMobilesInBounds( Rectangle2D bounds ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( TypedEnumerator.Instantiate( this, bounds, SectorEnumeratorType.Mobiles ) ); + } + #endregion + + public IPooledEnumerable GetMultiTilesAt( int x, int y ) + { + if ( this == Map.Internal ) + return NullEnumerable.Instance; + + Sector sector = GetSector( x, y ); + + if ( sector.Multis.Count == 0 ) + return NullEnumerable.Instance; + + return PooledEnumerable.Instantiate( MultiTileEnumerator.Instantiate( sector, new Point2D( x, y ) ) ); + } + + #region CanFit + public bool CanFit( Point3D p, int height, bool checkBlocksFit ) + { + return CanFit( p.m_X, p.m_Y, p.m_Z, height, checkBlocksFit, true, true ); + } + + public bool CanFit( Point3D p, int height, bool checkBlocksFit, bool checkMobiles ) + { + return CanFit( p.m_X, p.m_Y, p.m_Z, height, checkBlocksFit, checkMobiles, true ); + } + + public bool CanFit( Point2D p, int z, int height, bool checkBlocksFit ) + { + return CanFit( p.m_X, p.m_Y, z, height, checkBlocksFit, true, true ); + } + + public bool CanFit( Point3D p, int height ) + { + return CanFit( p.m_X, p.m_Y, p.m_Z, height, false, true, true ); + } + + public bool CanFit( Point2D p, int z, int height ) + { + return CanFit( p.m_X, p.m_Y, z, height, false, true, true ); + } + + public bool CanFit( int x, int y, int z, int height ) + { + return CanFit( x, y, z, height, false, true, true ); + } + + public bool CanFit( int x, int y, int z, int height, bool checksBlocksFit ) + { + return CanFit( x, y, z, height, checksBlocksFit, true, true ); + } + + public bool CanFit( int x, int y, int z, int height, bool checkBlocksFit, bool checkMobiles ) + { + return CanFit( x, y, z, height, checkBlocksFit, checkMobiles, true ); + } + + public bool CanFit( int x, int y, int z, int height, bool checkBlocksFit, bool checkMobiles, bool requireSurface ) + { + if ( this == Map.Internal ) + return false; + + if ( x < 0 || y < 0 || x >= m_Width || y >= m_Height ) + return false; + + bool hasSurface = false; + + LandTile lt = Tiles.GetLandTile( x, y ); + int lowZ = 0, avgZ = 0, topZ = 0; + + GetAverageZ( x, y, ref lowZ, ref avgZ, ref topZ ); + TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + + if ( ( landFlags & TileFlag.Impassable ) != 0 && avgZ > z && ( z + height ) > lowZ ) + return false; + else if ( ( landFlags & TileFlag.Impassable ) == 0 && z == avgZ && !lt.Ignored ) + hasSurface = true; + + StaticTile[] staticTiles = Tiles.GetStaticTiles( x, y, true ); + + bool surface, impassable; + + for ( int i = 0; i < staticTiles.Length; ++i ) + { + ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + surface = id.Surface; + impassable = id.Impassable; + + if ( ( surface || impassable ) && ( staticTiles[i].Z + id.CalcHeight ) > z && ( z + height ) > staticTiles[i].Z ) + return false; + else if ( surface && !impassable && z == ( staticTiles[i].Z + id.CalcHeight ) ) + hasSurface = true; + } + + Sector sector = GetSector( x, y ); + List items = sector.Items; + List mobs = sector.Mobiles; + + for ( int i = 0; i < items.Count; ++i ) + { + Item item = items[i]; + + if ( !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint( x, y ) ) + { + ItemData id = item.ItemData; + surface = id.Surface; + impassable = id.Impassable; + + if ( ( surface || impassable || ( checkBlocksFit && item.BlocksFit ) ) && ( item.Z + id.CalcHeight ) > z && ( z + height ) > item.Z ) + return false; + else if ( surface && !impassable && !item.Movable && z == ( item.Z + id.CalcHeight ) ) + hasSurface = true; + } + } + + if ( checkMobiles ) + { + for ( int i = 0; i < mobs.Count; ++i ) + { + Mobile m = mobs[i]; + + if ( m.Location.m_X == x && m.Location.m_Y == y && ( m.AccessLevel == AccessLevel.Player || !m.Hidden ) ) + if ( ( m.Z + 16 ) > z && ( z + height ) > m.Z ) + return false; + } + } + + return !requireSurface || hasSurface; + } + + #endregion + + #region CanSpawnMobile + public bool CanSpawnMobile( Point3D p ) + { + return CanSpawnMobile( p.m_X, p.m_Y, p.m_Z ); + } + + public bool CanSpawnMobile( Point2D p, int z ) + { + return CanSpawnMobile( p.m_X, p.m_Y, z ); + } + + public bool CanSpawnMobile( int x, int y, int z ) + { + if ( !Region.Find( new Point3D( x, y, z ), this ).AllowSpawn() ) + return false; + + return CanFit( x, y, z, 16 ); + } + #endregion + + private class ZComparer : IComparer + { + public static readonly ZComparer Default = new ZComparer(); + + public int Compare( Item x, Item y ) + { + return x.Z.CompareTo( y.Z ); + } + } + + public void FixColumn( int x, int y ) + { + LandTile landTile = Tiles.GetLandTile( x, y ); + + int landZ = 0, landAvg = 0, landTop = 0; + GetAverageZ( x, y, ref landZ, ref landAvg, ref landTop ); + + StaticTile[] tiles = Tiles.GetStaticTiles( x, y, true ); + + List items = new List(); + + IPooledEnumerable eable = GetItemsInRange( new Point3D( x, y, 0 ), 0 ); + + foreach ( Item item in eable ) + { + if ( !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue ) + { + items.Add( item ); + + if ( items.Count > 100 ) + break; + } + } + + eable.Free(); + + if ( items.Count > 100 ) + return; + + items.Sort( ZComparer.Default ); + + for ( int i = 0; i < items.Count; ++i ) + { + Item toFix = items[i]; + + if ( !toFix.Movable ) + continue; + + int z = int.MinValue; + int currentZ = toFix.Z; + + if ( !landTile.Ignored && landAvg <= currentZ ) + z = landAvg; + + for ( int j = 0; j < tiles.Length; ++j ) + { + StaticTile tile = tiles[j]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + int checkZ = tile.Z; + int checkTop = checkZ + id.CalcHeight; + + if ( checkTop == checkZ && !id.Surface ) + ++checkTop; + + if ( checkTop > z && checkTop <= currentZ ) + z = checkTop; + } + + for ( int j = 0; j < items.Count; ++j ) + { + if ( j == i ) + continue; + + Item item = items[j]; + ItemData id = item.ItemData; + + int checkZ = item.Z; + int checkTop = checkZ + id.CalcHeight; + + if ( checkTop == checkZ && !id.Surface ) + ++checkTop; + + if ( checkTop > z && checkTop <= currentZ ) + z = checkTop; + } + + if ( z != int.MinValue ) + toFix.Location = new Point3D( toFix.X, toFix.Y, z ); + } + } + + /* This could be probably be re-implemented if necessary (perhaps via an ITile interface?). + public List GetTilesAt( Point2D p, bool items, bool land, bool statics ) + { + List list = new List(); + + if ( this == Map.Internal ) + return list; + + if ( land ) + list.Add( Tiles.GetLandTile( p.m_X, p.m_Y ) ); + + if ( statics ) + list.AddRange( Tiles.GetStaticTiles( p.m_X, p.m_Y, true ) ); + + if ( items ) + { + Sector sector = GetSector( p ); + + foreach ( Item item in sector.Items ) + if ( item.AtWorldPoint( p.m_X, p.m_Y ) ) + list.Add( new StaticTile( (ushort)item.ItemID, (sbyte) item.Z ) ); + } + + return list; + } + */ + + /// + /// Gets the highest surface that is lower than . + /// + /// The reference point. + /// A surface or . + public object GetTopSurface( Point3D p ) + { + if ( this == Map.Internal ) + return null; + + object surface = null; + int surfaceZ = int.MinValue; + + + LandTile lt = Tiles.GetLandTile( p.X, p.Y ); + + if ( !lt.Ignored ) + { + int avgZ = GetAverageZ( p.X, p.Y ); + + if ( avgZ <= p.Z ) + { + surface = lt; + surfaceZ = avgZ; + + if ( surfaceZ == p.Z ) + return surface; + } + } + + + StaticTile[] staticTiles = Tiles.GetStaticTiles( p.X, p.Y, true ); + + for ( int i = 0; i < staticTiles.Length; i++ ) + { + StaticTile tile = staticTiles[i]; + ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; + + if ( id.Surface || ( id.Flags & TileFlag.Wet ) != 0 ) + { + int tileZ = tile.Z + id.CalcHeight; + + if ( tileZ > surfaceZ && tileZ <= p.Z ) + { + surface = tile; + surfaceZ = tileZ; + + if ( surfaceZ == p.Z ) + return surface; + } + } + } + + + Sector sector = GetSector( p.X, p.Y ); + + for ( int i = 0; i < sector.Items.Count; i++ ) + { + Item item = sector.Items[i]; + + if ( !(item is BaseMulti) && item.ItemID <= TileData.MaxItemValue && item.AtWorldPoint( p.X, p.Y ) && !item.Movable ) + { + ItemData id = item.ItemData; + + if ( id.Surface || ( id.Flags & TileFlag.Wet ) != 0 ) + { + int itemZ = item.Z + id.CalcHeight; + + if ( itemZ > surfaceZ && itemZ <= p.Z ) + { + surface = item; + surfaceZ = itemZ; + + if ( surfaceZ == p.Z ) + return surface; + } + } + } + } + + + return surface; + } + + public void Bound( int x, int y, out int newX, out int newY ) + { + if ( x < 0 ) + newX = 0; + else if ( x >= m_Width ) + newX = m_Width - 1; + else + newX = x; + + if ( y < 0 ) + newY = 0; + else if ( y >= m_Height ) + newY = m_Height - 1; + else + newY = y; + } + + public Point2D Bound( Point2D p ) + { + int x = p.m_X, y = p.m_Y; + + if ( x < 0 ) + x = 0; + else if ( x >= m_Width ) + x = m_Width - 1; + + if ( y < 0 ) + y = 0; + else if ( y >= m_Height ) + y = m_Height - 1; + + return new Point2D( x, y ); + } + + public Map( int mapID, int mapIndex, int fileIndex, int width, int height, int season, string name, MapRules rules ) + { + m_MapID = mapID; + m_MapIndex = mapIndex; + m_FileIndex = fileIndex; + m_Width = width; + m_Height = height; + m_Season = season; + m_Name = name; + m_Rules = rules; + m_Regions = new Dictionary( StringComparer.OrdinalIgnoreCase ); + m_InvalidSector = new Sector( 0, 0, this ); + m_SectorsWidth = width >> SectorShift; + m_SectorsHeight = height >> SectorShift; + m_Sectors = new Sector[m_SectorsWidth][]; + } + + #region GetSector + public Sector GetSector( Point3D p ) + { + return InternalGetSector( p.m_X >> SectorShift, p.m_Y >> SectorShift ); + } + + public Sector GetSector( Point2D p ) + { + return InternalGetSector( p.m_X >> SectorShift, p.m_Y >> SectorShift ); + } + + public Sector GetSector( IPoint2D p ) + { + return InternalGetSector( p.X >> SectorShift, p.Y >> SectorShift ); + } + + public Sector GetSector( int x, int y ) + { + return InternalGetSector( x >> SectorShift, y >> SectorShift ); + } + + public Sector GetRealSector( int x, int y ) + { + return InternalGetSector( x, y ); + } + + private Sector InternalGetSector( int x, int y ) + { + if ( x >= 0 && x < m_SectorsWidth && y >= 0 && y < m_SectorsHeight ) + { + Sector[] xSectors = m_Sectors[x]; + + if ( xSectors == null ) + m_Sectors[x] = xSectors = new Sector[m_SectorsHeight]; + + Sector sec = xSectors[y]; + + if ( sec == null ) + xSectors[y] = sec = new Sector( x, y, this ); + + return sec; + } + else + { + return m_InvalidSector; + } + } + #endregion + + public void ActivateSectors( int cx, int cy ) + { + for ( int x = cx - SectorActiveRange; x <= cx + SectorActiveRange; ++x ) + { + for ( int y = cy - SectorActiveRange; y <= cy + SectorActiveRange; ++y ) + { + Sector sect = GetRealSector( x, y ); + if ( sect != m_InvalidSector ) + sect.Activate(); + } + } + } + + public void DeactivateSectors( int cx, int cy ) + { + for ( int x = cx - SectorActiveRange; x <= cx + SectorActiveRange; ++x ) + { + for ( int y = cy - SectorActiveRange; y <= cy + SectorActiveRange; ++y ) + { + Sector sect = GetRealSector( x, y ); + if ( sect != m_InvalidSector && !PlayersInRange( sect, SectorActiveRange ) ) + sect.Deactivate(); + } + } + } + + private bool PlayersInRange( Sector sect, int range ) + { + for ( int x = sect.X - range; x <= sect.X + range; ++x ) + { + for ( int y = sect.Y - range; y <= sect.Y + range; ++y ) + { + Sector check = GetRealSector( x, y ); + if ( check != m_InvalidSector && check.Players.Count > 0 ) + return true; + } + } + + return false; + } + + public void OnClientChange( NetState oldState, NetState newState, Mobile m ) + { + if ( this == Map.Internal ) + return; + + GetSector( m ).OnClientChange( oldState, newState ); + } + + public void OnEnter( Mobile m ) + { + if ( this == Map.Internal ) + return; + + Sector sector = GetSector( m ); + + sector.OnEnter( m ); + } + + public void OnEnter( Item item ) + { + if ( this == Map.Internal ) + return; + + GetSector( item ).OnEnter( item ); + + if ( item is BaseMulti ) + { + BaseMulti m = (BaseMulti)item; + MultiComponentList mcl = m.Components; + + Sector start = GetMultiMinSector( item.Location, mcl ); + Sector end = GetMultiMaxSector( item.Location, mcl ); + + AddMulti( m, start, end ); + } + } + + public void OnLeave( Mobile m ) + { + if ( this == Map.Internal ) + return; + + Sector sector = GetSector( m ); + + sector.OnLeave( m ); + } + + public void OnLeave( Item item ) + { + if ( this == Map.Internal ) + return; + + GetSector( item ).OnLeave( item ); + + if ( item is BaseMulti ) + { + BaseMulti m = (BaseMulti)item; + MultiComponentList mcl = m.Components; + + Sector start = GetMultiMinSector( item.Location, mcl ); + Sector end = GetMultiMaxSector( item.Location, mcl ); + + RemoveMulti( m, start, end ); + } + } + + public void RemoveMulti( BaseMulti m, Sector start, Sector end ) + { + if ( this == Map.Internal ) + return; + + for ( int x = start.X; x <= end.X; ++x ) + for ( int y = start.Y; y <= end.Y; ++y ) + InternalGetSector( x, y ).OnMultiLeave( m ); + } + + public void AddMulti( BaseMulti m, Sector start, Sector end ) + { + if ( this == Map.Internal ) + return; + + for ( int x = start.X; x <= end.X; ++x ) + for ( int y = start.Y; y <= end.Y; ++y ) + InternalGetSector( x, y ).OnMultiEnter( m ); + } + + public Sector GetMultiMinSector( Point3D loc, MultiComponentList mcl ) + { + return GetSector( Bound( new Point2D( loc.m_X + mcl.Min.m_X, loc.m_Y + mcl.Min.m_Y ) ) ); + } + + public Sector GetMultiMaxSector( Point3D loc, MultiComponentList mcl ) + { + return GetSector( Bound( new Point2D( loc.m_X + mcl.Max.m_X, loc.m_Y + mcl.Max.m_Y ) ) ); + } + + public void OnMove( Point3D oldLocation, Mobile m ) + { + if ( this == Map.Internal ) + return; + + Sector oldSector = GetSector( oldLocation ); + Sector newSector = GetSector( m.Location ); + + if ( oldSector != newSector ) + { + oldSector.OnLeave( m ); + newSector.OnEnter( m ); + } + } + + public void OnMove( Point3D oldLocation, Item item ) + { + if ( this == Map.Internal ) + return; + + Sector oldSector = GetSector( oldLocation ); + Sector newSector = GetSector( item.Location ); + + if ( oldSector != newSector ) + { + oldSector.OnLeave( item ); + newSector.OnEnter( item ); + } + + if ( item is BaseMulti ) + { + BaseMulti m = (BaseMulti)item; + MultiComponentList mcl = m.Components; + + Sector start = GetMultiMinSector( item.Location, mcl ); + Sector end = GetMultiMaxSector( item.Location, mcl ); + + Sector oldStart = GetMultiMinSector( oldLocation, mcl ); + Sector oldEnd = GetMultiMaxSector( oldLocation, mcl ); + + if ( oldStart != start || oldEnd != end ) + { + RemoveMulti( m, oldStart, oldEnd ); + AddMulti( m, start, end ); + } + } + } + + public TileMatrix Tiles + { + get + { + if ( m_Tiles == null ) + m_Tiles = new TileMatrix( this, m_FileIndex, m_MapID, m_Width, m_Height ); + + return m_Tiles; + } + } + + public int MapID + { + get + { + return m_MapID; + } + } + + public int MapIndex + { + get + { + return m_MapIndex; + } + } + + public int Width + { + get + { + return m_Width; + } + } + + public int Height + { + get + { + return m_Height; + } + } + + public Dictionary Regions + { + get + { + return m_Regions; + } + } + + public void RegisterRegion( Region reg ) + { + string regName = reg.Name; + + if ( regName != null ) + { + if ( m_Regions.ContainsKey( regName ) ) + Console.WriteLine( "Warning: Duplicate region name '{0}' for map '{1}'", regName, this.Name ); + else + m_Regions[regName] = reg; + } + } + + public void UnregisterRegion( Region reg ) + { + string regName = reg.Name; + + if ( regName != null ) + m_Regions.Remove( regName ); + } + + public Region DefaultRegion + { + get + { + if ( m_DefaultRegion == null ) + m_DefaultRegion = new Region( null, this, 0, new Rectangle3D[0] ); + + return m_DefaultRegion; + } + set + { + m_DefaultRegion = value; + } + } + + public MapRules Rules + { + get + { + return m_Rules; + } + set + { + m_Rules = value; + } + } + + public Sector InvalidSector + { + get + { + return m_InvalidSector; + } + } + + public string Name + { + get + { + return m_Name; + } + set + { + m_Name = value; + } + } + + #region Enumerables + public class NullEnumerable : IPooledEnumerable + { + private InternalEnumerator m_Enumerator; + + public static readonly NullEnumerable Instance = new NullEnumerable(); + + private NullEnumerable() + { + m_Enumerator = new InternalEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return m_Enumerator; + } + + public void Free() + { + } + + private class InternalEnumerator : IEnumerator + { + public void Reset() + { + } + + public object Current + { + get + { + return null; + } + } + + public bool MoveNext() + { + return false; + } + } + } + + private class PooledEnumerable : IPooledEnumerable, IDisposable + { + private IPooledEnumerator m_Enumerator; + + private static Queue m_InstancePool = new Queue(); + private static int m_Depth = 0; + + public static PooledEnumerable Instantiate(IPooledEnumerator etor) + { + ++m_Depth; + + if (m_Depth >= 5) + Console.WriteLine("Warning: Make sure to call .Free() on pooled enumerables."); + + PooledEnumerable e; + + if (m_InstancePool.Count > 0) + { + e = m_InstancePool.Dequeue(); + e.m_Enumerator = etor; + } + else + { + e = new PooledEnumerable(etor); + } + + etor.Enumerable = e; + + return e; + } + + private PooledEnumerable(IPooledEnumerator etor) + { + m_Enumerator = etor; + } + + public IEnumerator GetEnumerator() + { + if (m_Enumerator == null) + throw new ObjectDisposedException("PooledEnumerable", "GetEnumerator() called after Free()"); + + return m_Enumerator; + } + + public void Free() + { + if (m_Enumerator != null) + { + m_InstancePool.Enqueue(this); + + m_Enumerator.Free(); + m_Enumerator = null; + + --m_Depth; + } + } + + public void Dispose() + { + Free(); + } + } + #endregion + + #region Enumerators + private enum SectorEnumeratorType + { + Mobiles, + Items, + Clients + } + + private class TypedEnumerator : IPooledEnumerator, IDisposable + { + private IPooledEnumerable m_Enumerable; + + public IPooledEnumerable Enumerable + { + get { return m_Enumerable; } + set { m_Enumerable = value; } + } + + private Map m_Map; + private Rectangle2D m_Bounds; + private SectorEnumerator m_Enumerator; + private SectorEnumeratorType m_Type; + private object m_Current; + + private static Queue m_InstancePool = new Queue(); + + public static TypedEnumerator Instantiate(Map map, Rectangle2D bounds, SectorEnumeratorType type) + { + TypedEnumerator e; + + if (m_InstancePool.Count > 0) + { + e = m_InstancePool.Dequeue(); + + e.m_Map = map; + e.m_Bounds = bounds; + e.m_Type = type; + + e.Reset(); + } + else + { + e = new TypedEnumerator(map, bounds, type); + } + + return e; + } + + public void Free() + { + if (m_Map == null) + return; + + m_InstancePool.Enqueue(this); + + m_Map = null; + + if (m_Enumerator != null) + { + m_Enumerator.Free(); + m_Enumerator = null; + } + + if (m_Enumerable != null) + m_Enumerable.Free(); + } + + public TypedEnumerator(Map map, Rectangle2D bounds, SectorEnumeratorType type) + { + m_Map = map; + m_Bounds = bounds; + m_Type = type; + + Reset(); + } + + public object Current + { + get + { + return m_Current; + } + } + + public bool MoveNext() + { + while (true) + { + if (m_Enumerator.MoveNext()) + { + object o; + + try + { + o = m_Enumerator.Current; + } + catch + { + continue; + } + + if (o is Mobile) + { + Mobile m = (Mobile)o; + + if (!m.Deleted && m_Bounds.Contains(m.Location)) + { + m_Current = o; + return true; + } + } + else if (o is Item) + { + Item item = (Item)o; + + if (!item.Deleted && item.Parent == null && m_Bounds.Contains(item.Location)) + { + m_Current = o; + return true; + } + } + else if (o is NetState) + { + Mobile m = ((NetState)o).Mobile; + + if (m != null && !m.Deleted && m_Bounds.Contains(m.Location)) + { + m_Current = o; + return true; + } + } + } + else + { + m_Current = null; + + m_Enumerator.Free(); + m_Enumerator = null; + + return false; + } + } + } + + public void Reset() + { + m_Current = null; + + if (m_Enumerator != null) + m_Enumerator.Free(); + + m_Enumerator = SectorEnumerator.Instantiate(m_Map, m_Bounds, m_Type);//new SectorEnumerator( m_Map, m_Origin, m_Type, m_Range ); + } + + public void Dispose() + { + Free(); + } + } + + private class MultiTileEnumerator : IPooledEnumerator, IDisposable + { + private IPooledEnumerable m_Enumerable; + + public IPooledEnumerable Enumerable + { + get { return m_Enumerable; } + set { m_Enumerable = value; } + } + + private List m_List; + private Point2D m_Location; + private object m_Current; + private int m_Index; + + private static Queue m_InstancePool = new Queue(); + + public static MultiTileEnumerator Instantiate(Sector sector, Point2D loc) + { + MultiTileEnumerator e; + + if (m_InstancePool.Count > 0) + { + e = m_InstancePool.Dequeue(); + + e.m_List = sector.Multis; + e.m_Location = loc; + + e.Reset(); + } + else + { + e = new MultiTileEnumerator(sector, loc); + } + + return e; + } + + private MultiTileEnumerator(Sector sector, Point2D loc) + { + m_List = sector.Multis; + m_Location = loc; + + Reset(); + } + + public object Current + { + get + { + return m_Current; + } + } + + public bool MoveNext() + { + while (++m_Index < m_List.Count) + { + BaseMulti m = m_List[m_Index]; + + if (m != null && !m.Deleted) + { + MultiComponentList list = m.Components; + + int xOffset = m_Location.m_X - (m.Location.m_X + list.Min.m_X); + int yOffset = m_Location.m_Y - (m.Location.m_Y + list.Min.m_Y); + + if (xOffset >= 0 && xOffset < list.Width && yOffset >= 0 && yOffset < list.Height) + { + StaticTile[] tiles = list.Tiles[xOffset][yOffset]; + + if (tiles.Length > 0) + { + // TODO: How to avoid this copy? + StaticTile[] copy = new StaticTile[tiles.Length]; + + for (int i = 0; i < copy.Length; ++i) + { + copy[i] = tiles[i]; + copy[i].Z += m.Z; + } + + m_Current = copy; + return true; + } + } + } + } + + return false; + } + + public void Free() + { + if (m_List == null) + return; + + m_InstancePool.Enqueue(this); + + m_List = null; + + if (m_Enumerable != null) + m_Enumerable.Free(); + } + + public void Reset() + { + m_Current = null; + m_Index = -1; + } + + public void Dispose() + { + Free(); + } + } + + private class ObjectEnumerator : IPooledEnumerator, IDisposable + { + private IPooledEnumerable m_Enumerable; + + public IPooledEnumerable Enumerable + { + get { return m_Enumerable; } + set { m_Enumerable = value; } + } + + private Map m_Map; + private Rectangle2D m_Bounds; + private SectorEnumerator m_Enumerator; + private int m_Stage; // 0 = items, 1 = mobiles + private object m_Current; + + private static Queue m_InstancePool = new Queue(); + + public static ObjectEnumerator Instantiate(Map map, Rectangle2D bounds) + { + ObjectEnumerator e; + + if (m_InstancePool.Count > 0) + { + e = m_InstancePool.Dequeue(); + + e.m_Map = map; + e.m_Bounds = bounds; + + e.Reset(); + } + else + { + e = new ObjectEnumerator(map, bounds); + } + + return e; + } + + public void Free() + { + if (m_Map == null) + return; + + m_InstancePool.Enqueue(this); + + m_Map = null; + + if (m_Enumerator != null) + { + m_Enumerator.Free(); + m_Enumerator = null; + } + + if (m_Enumerable != null) + m_Enumerable.Free(); + } + + private ObjectEnumerator(Map map, Rectangle2D bounds) + { + m_Map = map; + m_Bounds = bounds; + + Reset(); + } + + public object Current + { + get + { + return m_Current; + } + } + + public bool MoveNext() + { + while (true) + { + if (m_Enumerator.MoveNext()) + { + object o; + + try + { + o = m_Enumerator.Current; + } + catch + { + continue; + } + + if (o is Mobile) + { + Mobile m = (Mobile)o; + + if (m_Bounds.Contains(m.Location)) + { + m_Current = o; + return true; + } + } + else if (o is Item) + { + Item item = (Item)o; + + if (item.Parent == null && m_Bounds.Contains(item.Location)) + { + m_Current = o; + return true; + } + } + } + else if (m_Stage == 0) + { + m_Enumerator.Free(); + m_Enumerator = SectorEnumerator.Instantiate(m_Map, m_Bounds, SectorEnumeratorType.Mobiles); + + m_Current = null; + m_Stage = 1; + } + else + { + m_Enumerator.Free(); + m_Enumerator = null; + + m_Current = null; + m_Stage = -1; + + return false; + } + } + } + + public void Reset() + { + m_Stage = 0; + + m_Current = null; + + if (m_Enumerator != null) + m_Enumerator.Free(); + + m_Enumerator = SectorEnumerator.Instantiate(m_Map, m_Bounds, SectorEnumeratorType.Items); + } + + public void Dispose() + { + Free(); + } + } + + private class SectorEnumerator : IPooledEnumerator, IDisposable + { + private IPooledEnumerable m_Enumerable; + + public IPooledEnumerable Enumerable + { + get { return m_Enumerable; } + set { m_Enumerable = value; } + } + + private Map m_Map; + private Rectangle2D m_Bounds; + + private int m_xSector, m_ySector; + private int m_xSectorStart, m_ySectorStart; + private int m_xSectorEnd, m_ySectorEnd; + private IList m_CurrentList; + private int m_CurrentIndex; + private SectorEnumeratorType m_Type; + + private static Queue m_InstancePool = new Queue(); + + public static SectorEnumerator Instantiate(Map map, Rectangle2D bounds, SectorEnumeratorType type) + { + SectorEnumerator e; + + if (m_InstancePool.Count > 0) + { + e = m_InstancePool.Dequeue(); + + e.m_Map = map; + e.m_Bounds = bounds; + e.m_Type = type; + + e.Reset(); + } + else + { + e = new SectorEnumerator(map, bounds, type); + } + + return e; + } + + public void Free() + { + if (m_Map == null) + return; + + m_InstancePool.Enqueue(this); + + m_Map = null; + + if (m_Enumerable != null) + m_Enumerable.Free(); + } + + private SectorEnumerator(Map map, Rectangle2D bounds, SectorEnumeratorType type) + { + m_Map = map; + m_Bounds = bounds; + m_Type = type; + + Reset(); + } + + private IList GetListForSector(Sector sector) + { + switch (m_Type) + { + case SectorEnumeratorType.Clients: + return sector.Clients; + case SectorEnumeratorType.Mobiles: + return sector.Mobiles; + case SectorEnumeratorType.Items: + return sector.Items; + default: + throw new Exception("Invalid SectorEnumeratorType"); + } + } + + public object Current + { + get + { + return m_CurrentList[m_CurrentIndex]; + /*try + { + return m_CurrentList[m_CurrentIndex]; + } + catch + { + Console.WriteLine( "Warning: Object removed during enumeration. May not be recoverable" ); + + m_CurrentIndex = -1; + m_CurrentList = GetListForSector( m_Map.InternalGetSector( m_xSector, m_ySector ) ); + + if ( MoveNext() ) + { + return Current; + } + else + { + throw new Exception( "Object disposed during enumeration. Was not recoverable." ); + } + }*/ + } + } + + public bool MoveNext() + { + while (true) + { + ++m_CurrentIndex; + + if (m_CurrentIndex == m_CurrentList.Count) + { + ++m_ySector; + + if (m_ySector > m_ySectorEnd) + { + m_ySector = m_ySectorStart; + ++m_xSector; + + if (m_xSector > m_xSectorEnd) + { + m_CurrentIndex = -1; + m_CurrentList = null; + + return false; + } + } + + m_CurrentIndex = -1; + m_CurrentList = GetListForSector(m_Map.InternalGetSector(m_xSector, m_ySector));//m_Map.m_Sectors[m_xSector][m_ySector] ); + } + else + { + return true; + } + } + } + + public void Reset() + { + m_Map.Bound(m_Bounds.Start.m_X, m_Bounds.Start.m_Y, out m_xSectorStart, out m_ySectorStart); + m_Map.Bound(m_Bounds.End.m_X - 1, m_Bounds.End.m_Y - 1, out m_xSectorEnd, out m_ySectorEnd); + + m_xSector = m_xSectorStart >>= Map.SectorShift; + m_ySector = m_ySectorStart >>= Map.SectorShift; + + m_xSectorEnd >>= Map.SectorShift; + m_ySectorEnd >>= Map.SectorShift; + + m_CurrentIndex = -1; + m_CurrentList = GetListForSector(m_Map.InternalGetSector(m_xSector, m_ySector)); + } + + public void Dispose() + { + Free(); + } + } + #endregion + + public Point3D GetPoint(object o, bool eye) + { + Point3D p; + + if (o is Mobile) + { + p = ((Mobile)o).Location; + p.Z += 14;//eye ? 15 : 10; + } + else if (o is Item) + { + p = ((Item)o).GetWorldLocation(); + p.Z += (((Item)o).ItemData.Height / 2) + 1; + } + else if (o is Point3D) + { + p = (Point3D)o; + } + else if (o is LandTarget) + { + p = ((LandTarget)o).Location; + + int low = 0, avg = 0, top = 0; + GetAverageZ(p.X, p.Y, ref low, ref avg, ref top); + + p.Z = top + 1; + } + else if (o is StaticTarget) + { + StaticTarget st = (StaticTarget)o; + ItemData id = TileData.ItemTable[st.ItemID & TileData.MaxItemValue]; + + p = new Point3D(st.X, st.Y, st.Z - id.CalcHeight + (id.Height / 2) + 1); + } + else if (o is IPoint3D) + { + p = new Point3D((IPoint3D)o); + } + else + { + Console.WriteLine("Warning: Invalid object ({0}) in line of sight", o); + p = Point3D.Zero; + } + + return p; + } + + #region Line Of Sight + private static int m_MaxLOSDistance = 25; + + public static int MaxLOSDistance + { + get { return m_MaxLOSDistance; } + set { m_MaxLOSDistance = value; } + } + + public bool LineOfSight(Point3D org, Point3D dest) + { + if (this == Map.Internal) + return false; + + if (!Utility.InRange(org, dest, m_MaxLOSDistance)) + return false; + + Point3D start = org; + Point3D end = dest; + + if (org.X > dest.X || (org.X == dest.X && org.Y > dest.Y) || (org.X == dest.X && org.Y == dest.Y && org.Z > dest.Z)) + { + Point3D swap = org; + org = dest; + dest = swap; + } + + double rise, run, zslp; + double sq3d; + double x, y, z; + int xd, yd, zd; + int ix, iy, iz; + int height; + bool found; + Point3D p; + Point3DList path = m_PathList; + TileFlag flags; + + if (org == dest) + return true; + + if (path.Count > 0) + path.Clear(); + + xd = dest.m_X - org.m_X; + yd = dest.m_Y - org.m_Y; + zd = dest.m_Z - org.m_Z; + zslp = Math.Sqrt(xd * xd + yd * yd); + if (zd != 0) + sq3d = Math.Sqrt(zslp * zslp + zd * zd); + else + sq3d = zslp; + + rise = ((float)yd) / sq3d; + run = ((float)xd) / sq3d; + zslp = ((float)zd) / sq3d; + + y = org.m_Y; + z = org.m_Z; + x = org.m_X; + while (Utility.NumberBetween(x, dest.m_X, org.m_X, 0.5) && Utility.NumberBetween(y, dest.m_Y, org.m_Y, 0.5) && Utility.NumberBetween(z, dest.m_Z, org.m_Z, 0.5)) + { + ix = (int)Math.Round(x); + iy = (int)Math.Round(y); + iz = (int)Math.Round(z); + if (path.Count > 0) + { + p = path.Last; + + if (p.m_X != ix || p.m_Y != iy || p.m_Z != iz) + path.Add(ix, iy, iz); + } + else + { + path.Add(ix, iy, iz); + } + x += run; + y += rise; + z += zslp; + } + + if (path.Count == 0) + return true;//<--should never happen, but to be safe. + + p = path.Last; + + if (p != dest) + path.Add(dest); + + Point3D pTop = org, pBottom = dest; + Utility.FixPoints(ref pTop, ref pBottom); + + int pathCount = path.Count; + int endTop = end.m_Z + 1; + + for (int i = 0; i < pathCount; ++i) + { + Point3D point = path[i]; + int pointTop = point.m_Z + 1; + + LandTile landTile = Tiles.GetLandTile(point.X, point.Y); + int landZ = 0, landAvg = 0, landTop = 0; + GetAverageZ(point.m_X, point.m_Y, ref landZ, ref landAvg, ref landTop); + + if (landZ <= pointTop && landTop >= point.m_Z && (point.m_X != end.m_X || point.m_Y != end.m_Y || landZ > endTop || landTop < end.m_Z) && !landTile.Ignored) + return false; + + /* --Do land tiles need to be checked? There is never land between two people, always statics.-- + LandTile landTile = Tiles.GetLandTile( point.X, point.Y ); + if ( landTile.Z-1 >= point.Z && landTile.Z+1 <= point.Z && (TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags & TileFlag.Impassable) != 0 ) + return false; + */ + + StaticTile[] statics = Tiles.GetStaticTiles(point.m_X, point.m_Y, true); + + bool contains = false; + int ltID = landTile.ID; + + for (int j = 0; !contains && j < m_InvalidLandTiles.Length; ++j) + contains = (ltID == m_InvalidLandTiles[j]); + + if (contains && statics.Length == 0) + { + IPooledEnumerable eable = GetItemsInRange(point, 0); + + foreach (Item item in eable) + { + if (item.Visible) + contains = false; + + if (!contains) + break; + } + + eable.Free(); + + if (contains) + return false; + } + + for (int j = 0; j < statics.Length; ++j) + { + StaticTile t = statics[j]; + + ItemData id = TileData.ItemTable[t.ID & TileData.MaxItemValue]; + + flags = id.Flags; + height = id.CalcHeight; + + if (t.Z <= pointTop && t.Z + height >= point.Z && (flags & (TileFlag.Window | TileFlag.NoShoot)) != 0) + { + if (point.m_X == end.m_X && point.m_Y == end.m_Y && t.Z <= endTop && t.Z + height >= end.m_Z) + continue; + + return false; + } + + /*if ( t.Z <= point.Z && t.Z+height >= point.Z && (flags&TileFlag.Window)==0 && (flags&TileFlag.NoShoot)!=0 + && ( (flags&TileFlag.Wall)!=0 || (flags&TileFlag.Roof)!=0 || (((flags&TileFlag.Surface)!=0 && zd != 0)) ) )*/ + /*{ + //Console.WriteLine( "LoS: Blocked by Static \"{0}\" Z:{1} T:{3} P:{2} F:x{4:X}", TileData.ItemTable[t.ID&TileData.MaxItemValue].Name, t.Z, point, t.Z+height, flags ); + //Console.WriteLine( "if ( {0} && {1} && {2} && ( {3} || {4} || {5} || ({6} && {7} && {8}) ) )", t.Z <= point.Z, t.Z+height >= point.Z, (flags&TileFlag.Window)==0, (flags&TileFlag.Impassable)!=0, (flags&TileFlag.Wall)!=0, (flags&TileFlag.Roof)!=0, (flags&TileFlag.Surface)!=0, t.Z != dest.Z, zd != 0 ) ; + return false; + }*/ + } + } + + Rectangle2D rect = new Rectangle2D(pTop.m_X, pTop.m_Y, (pBottom.m_X - pTop.m_X) + 1, (pBottom.m_Y - pTop.m_Y) + 1); + + IPooledEnumerable area = GetItemsInBounds(rect); + + foreach (Item i in area) + { + if (!i.Visible) + continue; + + if (i is BaseMulti || i.ItemID > TileData.MaxItemValue) + continue; + + ItemData id = i.ItemData; + flags = id.Flags; + + if ((flags & (TileFlag.Window | TileFlag.NoShoot)) == 0) + continue; + + height = id.CalcHeight; + + found = false; + + int count = path.Count; + + for (int j = 0; j < count; ++j) + { + Point3D point = path[j]; + int pointTop = point.m_Z + 1; + Point3D loc = i.Location; + + //if ( t.Z <= point.Z && t.Z+height >= point.Z && ( height != 0 || ( t.Z == dest.Z && zd != 0 ) ) ) + if (loc.m_X == point.m_X && loc.m_Y == point.m_Y && + loc.m_Z <= pointTop && loc.m_Z + height >= point.m_Z) + { + if (loc.m_X == end.m_X && loc.m_Y == end.m_Y && loc.m_Z <= endTop && loc.m_Z + height >= end.m_Z) + continue; + + found = true; + break; + } + } + + if (!found) + continue; + + area.Free(); + return false; + + /*if ( (flags & (TileFlag.Impassable | TileFlag.Surface | TileFlag.Roof)) != 0 ) + + //flags = TileData.ItemTable[i.ItemID&TileData.MaxItemValue].Flags; + //if ( (flags&TileFlag.Window)==0 && (flags&TileFlag.NoShoot)!=0 && ( (flags&TileFlag.Wall)!=0 || (flags&TileFlag.Roof)!=0 || (((flags&TileFlag.Surface)!=0 && zd != 0)) ) ) + { + //height = TileData.ItemTable[i.ItemID&TileData.MaxItemValue].Height; + //Console.WriteLine( "LoS: Blocked by ITEM \"{0}\" P:{1} T:{2} F:x{3:X}", TileData.ItemTable[i.ItemID&TileData.MaxItemValue].Name, i.Location, i.Location.Z+height, flags ); + area.Free(); + return false; + }*/ + } + + area.Free(); + + return true; + } + + public bool LineOfSight(object from, object dest) + { + if (from == dest || (from is Mobile && ((Mobile)from).AccessLevel > AccessLevel.Player)) + return true; + else if (dest is Item && from is Mobile && ((Item)dest).RootParent == from) + return true; + + return LineOfSight(GetPoint(from, true), GetPoint(dest, false)); + } + + public bool LineOfSight(Mobile from, Point3D target) + { + if (from.AccessLevel > AccessLevel.Player) + return true; + + Point3D eye = from.Location; + + eye.Z += 14; + + return LineOfSight(eye, target); + } + + public bool LineOfSight(Mobile from, Mobile to) + { + if (from == to || from.AccessLevel > AccessLevel.Player) + return true; + + Point3D eye = from.Location; + Point3D target = to.Location; + + eye.Z += 14; + target.Z += 14;//10; + + return LineOfSight(eye, target); + } + #endregion + + private static int[] m_InvalidLandTiles = new int[] { 0x244 }; + + public static int[] InvalidLandTiles + { + get { return m_InvalidLandTiles; } + set { m_InvalidLandTiles = value; } + } + + private static Point3DList m_PathList = new Point3DList(); + public int CompareTo(Map other) + { + if (other == null) + return -1; + + return m_MapID.CompareTo(other.m_MapID); + } + + public int CompareTo(object other) + { + if (other == null || other is Map) + return this.CompareTo(other); + + throw new ArgumentException(); + } + } +} \ No newline at end of file diff --git a/Server/Menus/IMenu.cs b/Server/Menus/IMenu.cs new file mode 100644 index 0000000..05d9e5b --- /dev/null +++ b/Server/Menus/IMenu.cs @@ -0,0 +1,34 @@ +/*************************************************************************** + * IMenu.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: IMenu.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Menus +{ + public interface IMenu + { + int Serial{ get; } + int EntryLength{ get; } + void SendTo( NetState state ); + void OnCancel( NetState state ); + void OnResponse( NetState state, int index ); + } +} \ No newline at end of file diff --git a/Server/Menus/ItemListMenu.cs b/Server/Menus/ItemListMenu.cs new file mode 100644 index 0000000..3f745ca --- /dev/null +++ b/Server/Menus/ItemListMenu.cs @@ -0,0 +1,140 @@ +/*************************************************************************** + * ItemListMenu.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ItemListMenu.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Menus.ItemLists +{ + public class ItemListEntry + { + private string m_Name; + private int m_ItemID; + private int m_Hue; + + public string Name + { + get + { + return m_Name; + } + } + + public int ItemID + { + get + { + return m_ItemID; + } + } + + public int Hue + { + get + { + return m_Hue; + } + } + + public ItemListEntry( string name, int itemID ) : this( name, itemID, 0 ) + { + } + + public ItemListEntry( string name, int itemID, int hue ) + { + m_Name = name; + m_ItemID = itemID; + m_Hue = hue; + } + } + + public class ItemListMenu : IMenu + { + private string m_Question; + private ItemListEntry[] m_Entries; + + private int m_Serial; + private static int m_NextSerial; + + int IMenu.Serial + { + get + { + return m_Serial; + } + } + + int IMenu.EntryLength + { + get + { + return m_Entries.Length; + } + } + + public string Question + { + get + { + return m_Question; + } + } + + public ItemListEntry[] Entries + { + get + { + return m_Entries; + } + set + { + m_Entries = value; + } + } + + public ItemListMenu( string question, ItemListEntry[] entries ) + { + m_Question = question; + m_Entries = entries; + + do + { + m_Serial = m_NextSerial++; + m_Serial &= 0x7FFFFFFF; + } while ( m_Serial == 0 ); + + m_Serial = (int)((uint)m_Serial | 0x80000000); + } + + public virtual void OnCancel( NetState state ) + { + } + + public virtual void OnResponse( NetState state, int index ) + { + } + + public void SendTo( NetState state ) + { + state.AddMenu( this ); + state.Send( new DisplayItemListMenu( this ) ); + } + } +} \ No newline at end of file diff --git a/Server/Menus/QuestionMenu.cs b/Server/Menus/QuestionMenu.cs new file mode 100644 index 0000000..cf643e7 --- /dev/null +++ b/Server/Menus/QuestionMenu.cs @@ -0,0 +1,96 @@ +/*************************************************************************** + * QuestionMenu.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: QuestionMenu.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Menus.Questions +{ + public class QuestionMenu : IMenu + { + private string m_Question; + private string[] m_Answers; + + private int m_Serial; + private static int m_NextSerial; + + int IMenu.Serial + { + get + { + return m_Serial; + } + } + + int IMenu.EntryLength + { + get + { + return m_Answers.Length; + } + } + + public string Question + { + get + { + return m_Question; + } + set + { + m_Question = value; + } + } + + public string[] Answers + { + get + { + return m_Answers; + } + } + + public QuestionMenu( string question, string[] answers ) + { + m_Question = question; + m_Answers = answers; + + do + { + m_Serial = ++m_NextSerial; + m_Serial &= 0x7FFFFFFF; + } while ( m_Serial == 0 ); + } + + public virtual void OnCancel( NetState state ) + { + } + + public virtual void OnResponse( NetState state, int index ) + { + } + + public void SendTo( NetState state ) + { + state.AddMenu( this ); + state.Send( new DisplayQuestionMenu( this ) ); + } + } +} \ No newline at end of file diff --git a/Server/Mobile.cs b/Server/Mobile.cs new file mode 100644 index 0000000..6992b8a --- /dev/null +++ b/Server/Mobile.cs @@ -0,0 +1,11456 @@ +/*************************************************************************** + * Mobile.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Mobile.cs 1058 2013-05-07 19:19:24Z eos@runuo.com $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Server; +using Server.Accounting; +using Server.Commands; +using Server.ContextMenus; +using Server.Guilds; +using Server.Gumps; +using Server.HuePickers; +using Server.Items; +using Server.Menus; +using Server.Mobiles; +using Server.Network; +using Server.Prompts; +using Server.Targeting; + +namespace Server +{ + #region Callbacks + public delegate void TargetCallback( Mobile from, object targeted ); + public delegate void TargetStateCallback( Mobile from, object targeted, object state ); + public delegate void TargetStateCallback( Mobile from, object targeted, T state ); + + public delegate void PromptCallback( Mobile from, string text ); + public delegate void PromptStateCallback( Mobile from, string text, object state ); + public delegate void PromptStateCallback( Mobile from, string text, T state ); + #endregion + + #region [...]Mods + public class TimedSkillMod : SkillMod + { + private DateTime m_Expire; + + public TimedSkillMod( SkillName skill, bool relative, double value, TimeSpan delay ) + : this( skill, relative, value, DateTime.Now + delay ) + { + } + + public TimedSkillMod( SkillName skill, bool relative, double value, DateTime expire ) + : base( skill, relative, value ) + { + m_Expire = expire; + } + + public override bool CheckCondition() + { + return (DateTime.Now < m_Expire); + } + } + + public class EquipedSkillMod : SkillMod + { + private Item m_Item; + private Mobile m_Mobile; + + public EquipedSkillMod( SkillName skill, bool relative, double value, Item item, Mobile mobile ) + : base( skill, relative, value ) + { + m_Item = item; + m_Mobile = mobile; + } + + public override bool CheckCondition() + { + return (!m_Item.Deleted && !m_Mobile.Deleted && m_Item.Parent == m_Mobile); + } + } + + public class DefaultSkillMod : SkillMod + { + public DefaultSkillMod( SkillName skill, bool relative, double value ) + : base( skill, relative, value ) + { + } + + public override bool CheckCondition() + { + return true; + } + } + + public abstract class SkillMod + { + private Mobile m_Owner; + private SkillName m_Skill; + private bool m_Relative; + private double m_Value; + private bool m_ObeyCap; + + protected SkillMod( SkillName skill, bool relative, double value ) + { + m_Skill = skill; + m_Relative = relative; + m_Value = value; + } + + public bool ObeyCap + { + get { return m_ObeyCap; } + set + { + m_ObeyCap = value; + + if( m_Owner != null ) + { + Skill sk = m_Owner.Skills[m_Skill]; + + if( sk != null ) + sk.Update(); + } + } + } + + public Mobile Owner + { + get + { + return m_Owner; + } + set + { + if( m_Owner != value ) + { + if( m_Owner != null ) + m_Owner.RemoveSkillMod( this ); + + m_Owner = value; + + if( m_Owner != value ) + m_Owner.AddSkillMod( this ); + } + } + } + + public void Remove() + { + Owner = null; + } + + public SkillName Skill + { + get + { + return m_Skill; + } + set + { + if( m_Skill != value ) + { + Skill oldUpdate = (m_Owner != null ? m_Owner.Skills[m_Skill] : null); + + m_Skill = value; + + if( m_Owner != null ) + { + Skill sk = m_Owner.Skills[m_Skill]; + + if( sk != null ) + sk.Update(); + } + + if( oldUpdate != null ) + oldUpdate.Update(); + } + } + } + + public bool Relative + { + get + { + return m_Relative; + } + set + { + if( m_Relative != value ) + { + m_Relative = value; + + if( m_Owner != null ) + { + Skill sk = m_Owner.Skills[m_Skill]; + + if( sk != null ) + sk.Update(); + } + } + } + } + + public bool Absolute + { + get + { + return !m_Relative; + } + set + { + if( m_Relative == value ) + { + m_Relative = !value; + + if( m_Owner != null ) + { + Skill sk = m_Owner.Skills[m_Skill]; + + if( sk != null ) + sk.Update(); + } + } + } + } + + public double Value + { + get + { + return m_Value; + } + set + { + if( m_Value != value ) + { + m_Value = value; + + if( m_Owner != null ) + { + Skill sk = m_Owner.Skills[m_Skill]; + + if( sk != null ) + sk.Update(); + } + } + } + } + + public abstract bool CheckCondition(); + } + + public class ResistanceMod + { + private Mobile m_Owner; + private ResistanceType m_Type; + private int m_Offset; + + public Mobile Owner + { + get { return m_Owner; } + set { m_Owner = value; } + } + + public ResistanceType Type + { + get { return m_Type; } + set + { + if( m_Type != value ) + { + m_Type = value; + + if( m_Owner != null ) + m_Owner.UpdateResistances(); + } + } + } + + public int Offset + { + get { return m_Offset; } + set + { + if( m_Offset != value ) + { + m_Offset = value; + + if( m_Owner != null ) + m_Owner.UpdateResistances(); + } + } + } + + public ResistanceMod( ResistanceType type, int offset ) + { + m_Type = type; + m_Offset = offset; + } + } + + public class StatMod + { + private StatType m_Type; + private string m_Name; + private int m_Offset; + private TimeSpan m_Duration; + private DateTime m_Added; + + public StatType Type { get { return m_Type; } } + public string Name { get { return m_Name; } } + public int Offset { get { return m_Offset; } } + + public bool HasElapsed() + { + if( m_Duration == TimeSpan.Zero ) + return false; + + return (DateTime.Now - m_Added) >= m_Duration; + } + + public StatMod( StatType type, string name, int offset, TimeSpan duration ) + { + m_Type = type; + m_Name = name; + m_Offset = offset; + m_Duration = duration; + m_Added = DateTime.Now; + } + } + + #endregion + + public class DamageEntry + { + private Mobile m_Damager; + private int m_DamageGiven; + private DateTime m_LastDamage; + private List m_Responsible; + + public Mobile Damager { get { return m_Damager; } } + public int DamageGiven { get { return m_DamageGiven; } set { m_DamageGiven = value; } } + public DateTime LastDamage { get { return m_LastDamage; } set { m_LastDamage = value; } } + public bool HasExpired { get { return (DateTime.Now > (m_LastDamage + m_ExpireDelay)); } } + public List Responsible { get { return m_Responsible; } set { m_Responsible = value; } } + + private static TimeSpan m_ExpireDelay = TimeSpan.FromMinutes( 2.0 ); + + public static TimeSpan ExpireDelay + { + get { return m_ExpireDelay; } + set { m_ExpireDelay = value; } + } + + public DamageEntry( Mobile damager ) + { + m_Damager = damager; + } + } + + #region Enums + [Flags] + public enum StatType + { + Str=1, + Dex=2, + Int=4, + All=7 + } + + public enum StatLockType : byte + { + Up, + Down, + Locked + } + + [CustomEnum( new string[] { "North", "Right", "East", "Down", "South", "Left", "West", "Up" } )] + public enum Direction : byte + { + North=0x0, + Right=0x1, + East=0x2, + Down=0x3, + South=0x4, + Left=0x5, + West=0x6, + Up=0x7, + + Mask=0x7, + Running=0x80, + ValueMask=0x87 + } + + [Flags] + public enum MobileDelta + { + None= 0x00000000, + Name= 0x00000001, + Flags= 0x00000002, + Hits= 0x00000004, + Mana= 0x00000008, + Stam= 0x00000010, + Stat= 0x00000020, + Noto= 0x00000040, + Gold= 0x00000080, + Weight= 0x00000100, + Direction= 0x00000200, + Hue= 0x00000400, + Body= 0x00000800, + Armor= 0x00001000, + StatCap= 0x00002000, + GhostUpdate= 0x00004000, + Followers= 0x00008000, + Properties= 0x00010000, + TithingPoints= 0x00020000, + Resistances= 0x00040000, + WeaponDamage= 0x00080000, + Hair= 0x00100000, + FacialHair= 0x00200000, + Race= 0x00400000, + HealthbarYellow=0x00800000, + HealthbarPoison=0x01000000, + + Attributes= 0x0000001C + } + + public enum AccessLevel + { + Player, + Counselor, + GameMaster, + Seer, + Administrator, + Developer, + Owner + } + + public enum VisibleDamageType + { + None, + Related, + Everyone + } + + public enum ResistanceType + { + Physical, + Fire, + Cold, + Poison, + Energy + } + + public enum ApplyPoisonResult + { + Poisoned, + Immune, + HigherPoisonActive, + Cured + } + #endregion + + public class MobileNotConnectedException : Exception + { + public MobileNotConnectedException( Mobile source, string message ) + : base( message ) + { + this.Source = source.ToString(); + } + } + + #region Delegates + + public delegate bool SkillCheckTargetHandler( Mobile from, SkillName skill, object target, double minSkill, double maxSkill ); + public delegate bool SkillCheckLocationHandler( Mobile from, SkillName skill, double minSkill, double maxSkill ); + + public delegate bool SkillCheckDirectTargetHandler( Mobile from, SkillName skill, object target, double chance ); + public delegate bool SkillCheckDirectLocationHandler( Mobile from, SkillName skill, double chance ); + + public delegate TimeSpan RegenRateHandler( Mobile from ); + + public delegate bool AllowBeneficialHandler( Mobile from, Mobile target ); + public delegate bool AllowHarmfulHandler( Mobile from, Mobile target ); + + public delegate Container CreateCorpseHandler( Mobile from, HairInfo hair, FacialHairInfo facialhair, List initialContent, List equipedItems ); + + public delegate int AOSStatusHandler(Mobile from, int index); + + #endregion + + /// + /// Base class representing players, npcs, and creatures. + /// + public class Mobile : IEntity, IHued, IComparable, ISerializable, ISpawnable + { + #region CompareTo(...) + public int CompareTo( IEntity other ) + { + if( other == null ) + return -1; + + return m_Serial.CompareTo( other.Serial ); + } + + public int CompareTo( Mobile other ) + { + return this.CompareTo( (IEntity)other ); + } + + public int CompareTo( object other ) + { + if( other == null || other is IEntity ) + return this.CompareTo( (IEntity)other ); + + throw new ArgumentException(); + } + #endregion + + private static bool m_DragEffects = true; + + public static bool DragEffects + { + get { return m_DragEffects; } + set { m_DragEffects = value; } + } + + #region Scriptiz : permet de d�finir que le joueur poss�de un corps d'elfe + private bool m_IsElfBody = false; + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsElfBody + { + get { return m_IsElfBody; } + set + { + List bodies = new List() { 400, 401, 402, 403, 605, 606, 607, 608 }; + if (!bodies.Contains(BodyValue)) + { + //(AccessLevel.Counselor, e.Mobile.SpeechHue, String.Format("[{0}] {1}", e.Mobile.Name, e.ArgString)); + foreach (NetState state in NetState.Instances) + { + Mobile m = state.Mobile; + + if (m != null && m.AccessLevel >= AccessLevel.GameMaster) + m.SendMessage(33, "Mobile incompatible avec l'apparence elfique : " + this.Name + " (" + this.GetType().Name + ")"); + } + return; + } + m_IsElfBody = value; + if (m_IsElfBody) + this.BodyValue = (Alive ? Race.Elf.AliveBody(this.Female) : Race.Elf.GhostBody(this.Female)); + else + this.BodyValue = (Alive ? this.Race.AliveBody(this.Female) : this.Race.GhostBody(this.Female)); + } + } + #endregion + + #region Scriptiz : compteur des morts du mobile + private int m_Deaths = 0; + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public int Deaths + { + get { return m_Deaths; } + set { m_Deaths = value; } + } + #endregion + + #region Scriptiz : syst�me d'hallucinations + public virtual bool IsHallucinated { get { return false; } } + + public virtual short GetBody(Mobile toSend) + { + return (short)toSend.Body; + } + + public virtual int GetHue(Mobile toSend) + { + return toSend.Hue; + } + #endregion + + #region Handlers + + private static AllowBeneficialHandler m_AllowBeneficialHandler; + private static AllowHarmfulHandler m_AllowHarmfulHandler; + + public static AllowBeneficialHandler AllowBeneficialHandler + { + get { return m_AllowBeneficialHandler; } + set { m_AllowBeneficialHandler = value; } + } + + public static AllowHarmfulHandler AllowHarmfulHandler + { + get { return m_AllowHarmfulHandler; } + set { m_AllowHarmfulHandler = value; } + } + + private static SkillCheckTargetHandler m_SkillCheckTargetHandler; + private static SkillCheckLocationHandler m_SkillCheckLocationHandler; + private static SkillCheckDirectTargetHandler m_SkillCheckDirectTargetHandler; + private static SkillCheckDirectLocationHandler m_SkillCheckDirectLocationHandler; + + public static SkillCheckTargetHandler SkillCheckTargetHandler + { + get { return m_SkillCheckTargetHandler; } + set { m_SkillCheckTargetHandler = value; } + } + + public static SkillCheckLocationHandler SkillCheckLocationHandler + { + get { return m_SkillCheckLocationHandler; } + set { m_SkillCheckLocationHandler = value; } + } + + public static SkillCheckDirectTargetHandler SkillCheckDirectTargetHandler + { + get { return m_SkillCheckDirectTargetHandler; } + set { m_SkillCheckDirectTargetHandler = value; } + } + + public static SkillCheckDirectLocationHandler SkillCheckDirectLocationHandler + { + get { return m_SkillCheckDirectLocationHandler; } + set { m_SkillCheckDirectLocationHandler = value; } + } + + private static AOSStatusHandler m_AOSStatusHandler; + + public static AOSStatusHandler AOSStatusHandler + { + get { return m_AOSStatusHandler; } + set { m_AOSStatusHandler = value; } + } + + #endregion + + #region Regeneration + + private static RegenRateHandler m_HitsRegenRate, m_StamRegenRate, m_ManaRegenRate; + private static TimeSpan m_DefaultHitsRate, m_DefaultStamRate, m_DefaultManaRate; + + public static RegenRateHandler HitsRegenRateHandler + { + get { return m_HitsRegenRate; } + set { m_HitsRegenRate = value; } + } + + public static TimeSpan DefaultHitsRate + { + get { return m_DefaultHitsRate; } + set { m_DefaultHitsRate = value; } + } + + public static RegenRateHandler StamRegenRateHandler + { + get { return m_StamRegenRate; } + set { m_StamRegenRate = value; } + } + + public static TimeSpan DefaultStamRate + { + get { return m_DefaultStamRate; } + set { m_DefaultStamRate = value; } + } + + public static RegenRateHandler ManaRegenRateHandler + { + get { return m_ManaRegenRate; } + set { m_ManaRegenRate = value; } + } + + public static TimeSpan DefaultManaRate + { + get { return m_DefaultManaRate; } + set { m_DefaultManaRate = value; } + } + + public static TimeSpan GetHitsRegenRate( Mobile m ) + { + if( m_HitsRegenRate == null ) + return m_DefaultHitsRate; + else + return m_HitsRegenRate( m ); + } + + public static TimeSpan GetStamRegenRate( Mobile m ) + { + if( m_StamRegenRate == null ) + return m_DefaultStamRate; + else + return m_StamRegenRate( m ); + } + + public static TimeSpan GetManaRegenRate( Mobile m ) + { + if( m_ManaRegenRate == null ) + return m_DefaultManaRate; + else + return m_ManaRegenRate( m ); + } + + #endregion + + private class MovementRecord + { + public DateTime m_End; + + private static Queue m_InstancePool = new Queue(); + + public static MovementRecord NewInstance( DateTime end ) + { + MovementRecord r; + + if( m_InstancePool.Count > 0 ) + { + r = m_InstancePool.Dequeue(); + + r.m_End = end; + } + else + { + r = new MovementRecord( end ); + } + + return r; + } + + private MovementRecord( DateTime end ) + { + m_End = end; + } + + public bool Expired() + { + bool v = (DateTime.Now >= m_End); + + if( v ) + m_InstancePool.Enqueue( this ); + + return v; + } + } + + #region Var declarations + private Serial m_Serial; + private Map m_Map; + private Point3D m_Location; + private Direction m_Direction; + private Body m_Body; + private int m_Hue; + private Poison m_Poison; + private Timer m_PoisonTimer; + private BaseGuild m_Guild; + private string m_GuildTitle; + private bool m_Criminal; + private string m_Name; + private int m_Kills, m_ShortTermMurders; + private int m_SpeechHue, m_EmoteHue, m_WhisperHue, m_YellHue; + private string m_Language; + private NetState m_NetState; + private bool m_Female, m_Warmode, m_Hidden, m_Blessed, m_Flying; + private int m_StatCap; + private int m_Str, m_Dex, m_Int; + private int m_Hits, m_Stam, m_Mana; + private int m_Fame, m_Karma; + private AccessLevel m_AccessLevel; + private Skills m_Skills; + private List m_Items; + private bool m_Player; + private string m_Title; + private string m_Profile; + private bool m_ProfileLocked; + private int m_LightLevel; + private int m_TotalGold, m_TotalItems, m_TotalWeight; + private List m_StatMods; + private ISpell m_Spell; + private Target m_Target; + private Prompt m_Prompt; + private ContextMenu m_ContextMenu; + private List m_Aggressors, m_Aggressed; + private Mobile m_Combatant; + private List m_Stabled; + private bool m_AutoPageNotify; + private bool m_Meditating; + private bool m_CanHearGhosts; + private bool m_CanSwim, m_CantWalk; + private int m_TithingPoints; + private bool m_DisplayGuildTitle; + private Mobile m_GuildFealty; + private DateTime m_NextSpellTime; + private DateTime[] m_StuckMenuUses; + private Timer m_ExpireCombatant; + private Timer m_ExpireCriminal; + private Timer m_ExpireAggrTimer; + private Timer m_LogoutTimer; + private Timer m_CombatTimer; + private Timer m_ManaTimer, m_HitsTimer, m_StamTimer; + private DateTime m_NextSkillTime; + private DateTime m_NextActionTime; + private DateTime m_NextActionMessage; + private bool m_Paralyzed; + private ParalyzedTimer m_ParaTimer; + private bool m_Frozen; + private FrozenTimer m_FrozenTimer; + private int m_AllowedStealthSteps; + private int m_Hunger; + private int m_NameHue = -1; + private Region m_Region; + private bool m_DisarmReady, m_StunReady; + private int m_BaseSoundID; + private int m_VirtualArmor; + private bool m_Squelched; + private int m_MeleeDamageAbsorb; + private int m_MagicDamageAbsorb; + private int m_Followers, m_FollowersMax; + private List _actions; // prefer List over ArrayList for more specific profiling information + private Queue m_MoveRecords; + private int m_WarmodeChanges = 0; + private DateTime m_NextWarmodeChange; + private WarmodeTimer m_WarmodeTimer; + private int m_Thirst, m_BAC; + private int m_VirtualArmorMod; + private VirtueInfo m_Virtues; + private object m_Party; + private List m_SkillMods; + private Body m_BodyMod; + private DateTime m_LastStrGain; + private DateTime m_LastIntGain; + private DateTime m_LastDexGain; + private Race m_Race; + + #endregion + + private static readonly TimeSpan WarmodeSpamCatch = TimeSpan.FromSeconds( (Core.SE ? 1.0 : 0.5) ); + private static readonly TimeSpan WarmodeSpamDelay = TimeSpan.FromSeconds( (Core.SE ? 4.0 : 2.0) ); + private const int WarmodeCatchCount = 4; // Allow four warmode changes in 0.5 seconds, any more will be delay for two seconds + + [CommandProperty( AccessLevel.GameMaster )] + public Race Race + { + get + { + if( m_Race == null ) + m_Race = Race.DefaultRace; + + return m_Race; + } + set + { + Race oldRace = this.Race; + + m_Race = value; + + if( m_Race == null ) + m_Race = Race.DefaultRace; + + this.Body = m_Race.Body( this ); + this.UpdateResistances(); + + Delta( MobileDelta.Race ); + + OnRaceChange( oldRace ); + } + } + + protected virtual void OnRaceChange( Race oldRace ) + { + } + + public virtual double RacialSkillBonus { get { return 0; } } + + private List m_ResistMods; + + private int[] m_Resistances; + + public int[] Resistances { get { return m_Resistances; } } + + public virtual int BasePhysicalResistance { get { return 0; } } + public virtual int BaseFireResistance { get { return 0; } } + public virtual int BaseColdResistance { get { return 0; } } + public virtual int BasePoisonResistance { get { return 0; } } + public virtual int BaseEnergyResistance { get { return 0; } } + + public virtual void ComputeLightLevels( out int global, out int personal ) + { + ComputeBaseLightLevels( out global, out personal ); + + if( m_Region != null ) + m_Region.AlterLightLevel( this, ref global, ref personal ); + } + + public virtual void ComputeBaseLightLevels( out int global, out int personal ) + { + global = 0; + personal = m_LightLevel; + } + + public virtual void CheckLightLevels( bool forceResend ) + { + } + + [CommandProperty( AccessLevel.Counselor )] + public virtual int PhysicalResistance + { + get { return GetResistance( ResistanceType.Physical ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public virtual int FireResistance + { + get { return GetResistance( ResistanceType.Fire ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public virtual int ColdResistance + { + get { return GetResistance( ResistanceType.Cold ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public virtual int PoisonResistance + { + get { return GetResistance( ResistanceType.Poison ); } + } + + [CommandProperty( AccessLevel.Counselor )] + public virtual int EnergyResistance + { + get { return GetResistance( ResistanceType.Energy ); } + } + + public virtual void UpdateResistances() + { + if( m_Resistances == null ) + m_Resistances = new int[5] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; + + bool delta = false; + + for( int i = 0; i < m_Resistances.Length; ++i ) + { + if( m_Resistances[i] != int.MinValue ) + { + m_Resistances[i] = int.MinValue; + delta = true; + } + } + + if( delta ) + Delta( MobileDelta.Resistances ); + } + + public virtual int GetResistance( ResistanceType type ) + { + if( m_Resistances == null ) + m_Resistances = new int[5] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; + + int v = (int)type; + + if( v < 0 || v >= m_Resistances.Length ) + return 0; + + int res = m_Resistances[v]; + + if( res == int.MinValue ) + { + ComputeResistances(); + res = m_Resistances[v]; + } + + return res; + } + + public List ResistanceMods + { + get { return m_ResistMods; } + set { m_ResistMods = value; } + } + + public virtual void AddResistanceMod( ResistanceMod toAdd ) + { + if ( m_ResistMods == null ) { + m_ResistMods = new List(); + } + + m_ResistMods.Add( toAdd ); + UpdateResistances(); + } + + public virtual void RemoveResistanceMod( ResistanceMod toRemove ) + { + if( m_ResistMods != null ) + { + m_ResistMods.Remove( toRemove ); + + if( m_ResistMods.Count == 0 ) + m_ResistMods = null; + } + + UpdateResistances(); + } + + private static int m_MaxPlayerResistance = 70; + + public static int MaxPlayerResistance { get { return m_MaxPlayerResistance; } set { m_MaxPlayerResistance = value; } } + + public virtual void ComputeResistances() + { + if( m_Resistances == null ) + m_Resistances = new int[5] { int.MinValue, int.MinValue, int.MinValue, int.MinValue, int.MinValue }; + + for( int i = 0; i < m_Resistances.Length; ++i ) + m_Resistances[i] = 0; + + m_Resistances[0] += this.BasePhysicalResistance; + m_Resistances[1] += this.BaseFireResistance; + m_Resistances[2] += this.BaseColdResistance; + m_Resistances[3] += this.BasePoisonResistance; + m_Resistances[4] += this.BaseEnergyResistance; + + for( int i = 0; m_ResistMods != null && i < m_ResistMods.Count; ++i ) + { + ResistanceMod mod = m_ResistMods[i]; + int v = (int)mod.Type; + + if( v >= 0 && v < m_Resistances.Length ) + m_Resistances[v] += mod.Offset; + } + + for( int i = 0; i < m_Items.Count; ++i ) + { + Item item = m_Items[i]; + + if( item.CheckPropertyConfliction( this ) ) + continue; + + m_Resistances[0] += item.PhysicalResistance; + m_Resistances[1] += item.FireResistance; + m_Resistances[2] += item.ColdResistance; + m_Resistances[3] += item.PoisonResistance; + m_Resistances[4] += item.EnergyResistance; + } + + for( int i = 0; i < m_Resistances.Length; ++i ) + { + int min = GetMinResistance( (ResistanceType)i ); + int max = GetMaxResistance( (ResistanceType)i ); + + if( max < min ) + max = min; + + if( m_Resistances[i] > max ) + m_Resistances[i] = max; + else if( m_Resistances[i] < min ) + m_Resistances[i] = min; + } + } + + public virtual int GetMinResistance( ResistanceType type ) + { + return int.MinValue; + } + + public virtual int GetMaxResistance( ResistanceType type ) + { + if( m_Player ) + return m_MaxPlayerResistance; + + return int.MaxValue; + } + + public int GetAOSStatus(int index) + { + return (m_AOSStatusHandler == null) ? 0 : m_AOSStatusHandler(this, index); + } + + public virtual void SendPropertiesTo( Mobile from ) + { + from.Send( PropertyList ); + } + + public virtual void OnAosSingleClick( Mobile from ) + { + ObjectPropertyList opl = this.PropertyList; + + if( opl.Header > 0 ) + { + int hue; + + if( m_NameHue != -1 ) + hue = m_NameHue; + else if( m_AccessLevel > AccessLevel.Player ) + hue = 11; + else + hue = Notoriety.GetHue( Notoriety.Compute( from, this ) ); + + from.Send( new MessageLocalized( m_Serial, Body, MessageType.Label, hue, 3, opl.Header, Name, opl.HeaderArgs ) ); + } + } + + public virtual string ApplyNameSuffix( string suffix ) + { + return suffix; + } + + public virtual void AddNameProperties( ObjectPropertyList list ) + { + string name = Name; + + if( name == null ) + name = String.Empty; + + string prefix = ""; + + if( ShowFameTitle && (m_Player || m_Body.IsHuman) && m_Fame >= 10000 ) + prefix = m_Female ? "La Grande" : "Le Grand"; + + string suffix = ""; + + if( PropertyTitle && Title != null && Title.Length > 0 ) + suffix = Title; + + BaseGuild guild = m_Guild; + + //if( guild != null && (m_Player || m_DisplayGuildTitle) ) + if (guild != null && (m_Player && m_DisplayGuildTitle)) // Scriptiz : on cache le titre et l'abr�viation ! + { + if( suffix.Length > 0 ) + suffix = String.Format( "{0} [{1}]", suffix, Utility.FixHtml( guild.Abbreviation ) ); + else + suffix = String.Format( "[{0}]", Utility.FixHtml( guild.Abbreviation ) ); + } + + suffix = ApplyNameSuffix( suffix ); + + list.Add( 1050045, "{0} \t{1}\t {2}", prefix, name, suffix ); // ~1_PREFIX~~2_NAME~~3_SUFFIX~ + + if( guild != null && (m_DisplayGuildTitle || (m_Player && guild.Type != GuildType.Regular)) ) + { + string type; + + if( guild.Type >= 0 && (int)guild.Type < m_GuildTypes.Length ) + type = m_GuildTypes[(int)guild.Type]; + else + type = ""; + + string title = GuildTitle; + + if( title == null ) + title = ""; + else + title = title.Trim(); + + if( NewGuildDisplay && title.Length > 0 ) + { + list.Add( "{0}, {1}", Utility.FixHtml( title ), Utility.FixHtml( guild.Name ) ); + } + else + { + if( title.Length > 0 ) + list.Add( "{0}, {1} Guild{2}", Utility.FixHtml( title ), Utility.FixHtml( guild.Name ), type ); + else + list.Add( Utility.FixHtml( guild.Name ) ); + } + } + } + + public virtual bool NewGuildDisplay { get { return false; } } + + public virtual void GetProperties( ObjectPropertyList list ) + { + AddNameProperties( list ); + } + + public virtual void GetChildProperties( ObjectPropertyList list, Item item ) + { + } + + public virtual void GetChildNameProperties( ObjectPropertyList list, Item item ) + { + } + + private void UpdateAggrExpire() + { + if( m_Deleted || (m_Aggressors.Count == 0 && m_Aggressed.Count == 0) ) + { + StopAggrExpire(); + } + else if( m_ExpireAggrTimer == null ) + { + m_ExpireAggrTimer = new ExpireAggressorsTimer( this ); + m_ExpireAggrTimer.Start(); + } + } + + private void StopAggrExpire() + { + if( m_ExpireAggrTimer != null ) + m_ExpireAggrTimer.Stop(); + + m_ExpireAggrTimer = null; + } + + private void CheckAggrExpire() + { + for( int i = m_Aggressors.Count - 1; i >= 0; --i ) + { + if( i >= m_Aggressors.Count ) + continue; + + AggressorInfo info = m_Aggressors[i]; + + if( info.Expired ) + { + Mobile attacker = info.Attacker; + attacker.RemoveAggressed( this ); + + m_Aggressors.RemoveAt( i ); + info.Free(); + + if( m_NetState != null && this.CanSee( attacker ) && Utility.InUpdateRange( m_Location, attacker.m_Location ) ) { + m_NetState.Send(MobileIncoming.Create(m_NetState, this, attacker)); + } + } + } + + for( int i = m_Aggressed.Count - 1; i >= 0; --i ) + { + if( i >= m_Aggressed.Count ) + continue; + + AggressorInfo info = m_Aggressed[i]; + + if( info.Expired ) + { + Mobile defender = info.Defender; + defender.RemoveAggressor( this ); + + m_Aggressed.RemoveAt( i ); + info.Free(); + + if( m_NetState != null && this.CanSee( defender ) && Utility.InUpdateRange( m_Location, defender.m_Location ) ) { + m_NetState.Send(MobileIncoming.Create(m_NetState, this, defender)); + } + } + } + + UpdateAggrExpire(); + } + + public List Stabled { get { return m_Stabled; } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public VirtueInfo Virtues { get { return m_Virtues; } set { } } + + public object Party { get { return m_Party; } set { m_Party = value; } } + public List SkillMods { get { return m_SkillMods; } } + + [CommandProperty( AccessLevel.GameMaster )] + public int VirtualArmorMod + { + get + { + return m_VirtualArmorMod; + } + set + { + if( m_VirtualArmorMod != value ) + { + m_VirtualArmorMod = value; + + Delta( MobileDelta.Armor ); + } + } + } + + /// + /// Overridable. Virtual event invoked when changes in some way. + /// + public virtual void OnSkillInvalidated( Skill skill ) + { + } + + public virtual void UpdateSkillMods() + { + ValidateSkillMods(); + + for( int i = 0; i < m_SkillMods.Count; ++i ) + { + SkillMod mod = m_SkillMods[i]; + + Skill sk = m_Skills[mod.Skill]; + + if( sk != null ) + sk.Update(); + } + } + + public virtual void ValidateSkillMods() + { + for( int i = 0; i < m_SkillMods.Count; ) + { + SkillMod mod = m_SkillMods[i]; + + if( mod.CheckCondition() ) + ++i; + else + InternalRemoveSkillMod( mod ); + } + } + + public virtual void AddSkillMod( SkillMod mod ) + { + if( mod == null ) + return; + + ValidateSkillMods(); + + if( !m_SkillMods.Contains( mod ) ) + { + m_SkillMods.Add( mod ); + mod.Owner = this; + + Skill sk = m_Skills[mod.Skill]; + + if( sk != null ) + sk.Update(); + } + } + + public virtual void RemoveSkillMod( SkillMod mod ) + { + if( mod == null ) + return; + + ValidateSkillMods(); + + InternalRemoveSkillMod( mod ); + } + + private void InternalRemoveSkillMod( SkillMod mod ) + { + if( m_SkillMods.Contains( mod ) ) + { + m_SkillMods.Remove( mod ); + mod.Owner = null; + + Skill sk = m_Skills[mod.Skill]; + + if( sk != null ) + sk.Update(); + } + } + + private class WarmodeTimer : Timer + { + private Mobile m_Mobile; + private bool m_Value; + + public bool Value + { + get + { + return m_Value; + } + set + { + m_Value = value; + } + } + + public WarmodeTimer( Mobile m, bool value ) + : base( WarmodeSpamDelay ) + { + m_Mobile = m; + m_Value = value; + } + + protected override void OnTick() + { + m_Mobile.Warmode = m_Value; + m_Mobile.m_WarmodeChanges = 0; + + m_Mobile.m_WarmodeTimer = null; + } + } + + /// + /// Overridable. Virtual event invoked when a client, , invokes a 'help request' for the Mobile. Seemingly no longer functional in newer clients. + /// + public virtual void OnHelpRequest( Mobile from ) + { + } + + public void DelayChangeWarmode( bool value ) + { + if( m_WarmodeTimer != null ) + { + m_WarmodeTimer.Value = value; + return; + } + + if( m_Warmode == value ) + return; + + DateTime now = DateTime.Now, next = m_NextWarmodeChange; + + if( now > next || m_WarmodeChanges == 0 ) + { + m_WarmodeChanges = 1; + m_NextWarmodeChange = now + WarmodeSpamCatch; + } + else if( m_WarmodeChanges == WarmodeCatchCount ) + { + m_WarmodeTimer = new WarmodeTimer( this, value ); + m_WarmodeTimer.Start(); + + return; + } + else + { + ++m_WarmodeChanges; + } + + Warmode = value; + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MeleeDamageAbsorb + { + get + { + return m_MeleeDamageAbsorb; + } + set + { + m_MeleeDamageAbsorb = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int MagicDamageAbsorb + { + get + { + return m_MagicDamageAbsorb; + } + set + { + m_MagicDamageAbsorb = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SkillsTotal + { + get + { + return m_Skills == null ? 0 : m_Skills.Total; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SkillsCap + { + get + { + return m_Skills == null ? 0 : m_Skills.Cap; + } + set + { + if( m_Skills != null ) + m_Skills.Cap = value; + } + } + + public bool InLOS( Mobile target ) + { + if( m_Deleted || m_Map == null ) + return false; + else if( target == this || m_AccessLevel > AccessLevel.Player ) + return true; + + return m_Map.LineOfSight( this, target ); + } + + public bool InLOS( object target ) + { + if( m_Deleted || m_Map == null ) + return false; + else if( target == this || m_AccessLevel > AccessLevel.Player ) + return true; + else if( target is Item && ((Item)target).RootParent == this ) + return true; + + return m_Map.LineOfSight( this, target ); + } + + public bool InLOS( Point3D target ) + { + if( m_Deleted || m_Map == null ) + return false; + else if( m_AccessLevel > AccessLevel.Player ) + return true; + + return m_Map.LineOfSight( this, target ); + } + + [CommandProperty( AccessLevel.GameMaster )] + public int BaseSoundID + { + get + { + return m_BaseSoundID; + } + set + { + m_BaseSoundID = value; + } + } + + public DateTime NextCombatTime + { + get + { + return m_NextCombatTime; + } + set + { + m_NextCombatTime = value; + } + } + + public bool BeginAction( object toLock ) + { + if ( _actions == null ) { + _actions = new List(); + + _actions.Add( toLock ); + + return true; + } else if ( !_actions.Contains( toLock ) ) { + _actions.Add( toLock ); + + return true; + } + + return false; + } + + public bool CanBeginAction( object toLock ) + { + return ( _actions == null || !_actions.Contains( toLock ) ); + } + + public void EndAction( object toLock ) + { + if ( _actions != null ) { + _actions.Remove( toLock ); + + if ( _actions.Count == 0 ) { + _actions = null; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int NameHue + { + get + { + return m_NameHue; + } + set + { + m_NameHue = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int Hunger + { + get + { + return m_Hunger; + } + set + { + int oldValue = m_Hunger; + + if( oldValue != value ) + { + m_Hunger = value; + + EventSink.InvokeHungerChanged( new HungerChangedEventArgs( this, oldValue ) ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual int Thirst + { + get + { + return m_Thirst; + } + set + { + m_Thirst = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int BAC + { + get + { + return m_BAC; + } + set + { + m_BAC = value; + } + } + + private DateTime m_LastMoveTime; + + /// + /// Gets or sets the number of steps this player may take when hidden before being revealed. + /// + [CommandProperty( AccessLevel.GameMaster )] + public int AllowedStealthSteps + { + get + { + return m_AllowedStealthSteps; + } + set + { + m_AllowedStealthSteps = value; + } + } + + /* Logout: + * + * When a client logs into mobile x + * - if ( x is Internalized ) move x to logout location and map + * + * When a client attached to a mobile disconnects + * - LogoutTimer is started + * - Delay is taken from Region.GetLogoutDelay to allow insta-logout regions. + * - OnTick : Location and map are stored, and mobile is internalized + * + * Some things to consider: + * - An internalized person getting killed (say, by poison). Where does the body go? + * - Regions now have a GetLogoutDelay( Mobile m ); virtual function (see above) + */ + private Point3D m_LogoutLocation; + private Map m_LogoutMap; + + public virtual TimeSpan GetLogoutDelay() + { + return Region.GetLogoutDelay( this ); + } + + private StatLockType m_StrLock, m_DexLock, m_IntLock; + + private Item m_Holding; + + public Item Holding + { + get + { + return m_Holding; + } + set + { + if( m_Holding != value ) + { + if( m_Holding != null ) + { + UpdateTotal( m_Holding, TotalType.Weight, -(m_Holding.TotalWeight + m_Holding.PileWeight) ); + + if( m_Holding.HeldBy == this ) + m_Holding.HeldBy = null; + } + + if( value != null && m_Holding != null ) + DropHolding(); + + m_Holding = value; + + if( m_Holding != null ) + { + UpdateTotal( m_Holding, TotalType.Weight, m_Holding.TotalWeight + m_Holding.PileWeight ); + + if( m_Holding.HeldBy == null ) + m_Holding.HeldBy = this; + } + } + } + } + + public DateTime LastMoveTime + { + get + { + return m_LastMoveTime; + } + set + { + m_LastMoveTime = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool Paralyzed + { + get + { + return m_Paralyzed; + } + set + { + if( m_Paralyzed != value ) + { + m_Paralyzed = value; + Delta(MobileDelta.Flags); + + this.SendLocalizedMessage( m_Paralyzed ? 502381 : 502382 ); + + if( m_ParaTimer != null ) + { + m_ParaTimer.Stop(); + m_ParaTimer = null; + } + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool DisarmReady + { + get + { + return m_DisarmReady; + } + set + { + m_DisarmReady = value; + //SendLocalizedMessage( value ? 1019013 : 1019014 ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool StunReady + { + get + { + return m_StunReady; + } + set + { + m_StunReady = value; + //SendLocalizedMessage( value ? 1019011 : 1019012 ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Frozen + { + get + { + return m_Frozen; + } + set + { + if( m_Frozen != value ) + { + m_Frozen = value; + Delta(MobileDelta.Flags); + + if( m_FrozenTimer != null ) + { + m_FrozenTimer.Stop(); + m_FrozenTimer = null; + } + } + } + } + + public void Paralyze( TimeSpan duration ) + { + if( !m_Paralyzed ) + { + Paralyzed = true; + + m_ParaTimer = new ParalyzedTimer( this, duration ); + m_ParaTimer.Start(); + } + } + + public void Freeze( TimeSpan duration ) + { + if( !m_Frozen ) + { + Frozen = true; + + m_FrozenTimer = new FrozenTimer( this, duration ); + m_FrozenTimer.Start(); + } + } + + /// + /// Gets or sets the lock state for the property. + /// + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public StatLockType StrLock + { + get + { + return m_StrLock; + } + set + { + if( m_StrLock != value ) + { + m_StrLock = value; + + if( m_NetState != null ) + m_NetState.Send( new StatLockInfo( this ) ); + } + } + } + + /// + /// Gets or sets the lock state for the property. + /// + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public StatLockType DexLock + { + get + { + return m_DexLock; + } + set + { + if( m_DexLock != value ) + { + m_DexLock = value; + + if( m_NetState != null ) + m_NetState.Send( new StatLockInfo( this ) ); + } + } + } + + /// + /// Gets or sets the lock state for the property. + /// + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public StatLockType IntLock + { + get + { + return m_IntLock; + } + set + { + if( m_IntLock != value ) + { + m_IntLock = value; + + if( m_NetState != null ) + m_NetState.Send( new StatLockInfo( this ) ); + } + } + } + + public override string ToString() + { + return String.Format( "0x{0:X} \"{1}\"", m_Serial.Value, Name ); + } + + public DateTime NextActionTime + { + get + { + return m_NextActionTime; + } + set + { + m_NextActionTime = value; + } + } + + public DateTime NextActionMessage + { + get + { + return m_NextActionMessage; + } + set + { + m_NextActionMessage = value; + } + } + + private static TimeSpan m_ActionMessageDelay = TimeSpan.FromSeconds( 0.125 ); + + public static TimeSpan ActionMessageDelay + { + get { return m_ActionMessageDelay; } + set { m_ActionMessageDelay = value; } + } + + public virtual void SendSkillMessage() + { + if( DateTime.Now < m_NextActionMessage ) + return; + + m_NextActionMessage = DateTime.Now + m_ActionMessageDelay; + + SendLocalizedMessage( 500118 ); // You must wait a few moments to use another skill. + } + + public virtual void SendActionMessage() + { + if( DateTime.Now < m_NextActionMessage ) + return; + + m_NextActionMessage = DateTime.Now + m_ActionMessageDelay; + + SendLocalizedMessage( 500119 ); // You must wait to perform another action. + } + + public virtual void ClearHands() + { + ClearHand( FindItemOnLayer( Layer.OneHanded ) ); + ClearHand( FindItemOnLayer( Layer.TwoHanded ) ); + } + + public virtual void ClearHand( Item item ) + { + if( item != null && item.Movable && !item.AllowEquipedCast( this ) ) + { + Container pack = this.Backpack; + + if( pack == null ) + AddToBackpack( item ); + else + pack.DropItem( item ); + } + } + + + private static bool m_GlobalRegenThroughPoison = true; + + public static bool GlobalRegenThroughPoison + { + get { return m_GlobalRegenThroughPoison; } + set { m_GlobalRegenThroughPoison = value; } + } + + public virtual bool RegenThroughPoison { get { return m_GlobalRegenThroughPoison; } } + + public virtual bool CanRegenHits { get { return this.Alive && (RegenThroughPoison || !this.Poisoned); } } + public virtual bool CanRegenStam { get { return this.Alive; } } + public virtual bool CanRegenMana { get { return this.Alive; } } + + #region Timers + + private class ManaTimer : Timer + { + private Mobile m_Owner; + + public ManaTimer( Mobile m ) + : base( Mobile.GetManaRegenRate( m ), Mobile.GetManaRegenRate( m ) ) + { + this.Priority = TimerPriority.FiftyMS; + m_Owner = m; + } + + protected override void OnTick() + { + if( m_Owner.CanRegenMana )// m_Owner.Alive ) + m_Owner.Mana++; + + Delay = Interval = Mobile.GetManaRegenRate( m_Owner ); + } + } + + private class HitsTimer : Timer + { + private Mobile m_Owner; + + public HitsTimer( Mobile m ) + : base( Mobile.GetHitsRegenRate( m ), Mobile.GetHitsRegenRate( m ) ) + { + this.Priority = TimerPriority.FiftyMS; + m_Owner = m; + } + + protected override void OnTick() + { + if( m_Owner.CanRegenHits )// m_Owner.Alive && !m_Owner.Poisoned ) + m_Owner.Hits++; + + Delay = Interval = Mobile.GetHitsRegenRate( m_Owner ); + } + } + + private class StamTimer : Timer + { + private Mobile m_Owner; + + public StamTimer( Mobile m ) + : base( Mobile.GetStamRegenRate( m ), Mobile.GetStamRegenRate( m ) ) + { + this.Priority = TimerPriority.FiftyMS; + m_Owner = m; + } + + protected override void OnTick() + { + if( m_Owner.CanRegenStam )// m_Owner.Alive ) + m_Owner.Stam++; + + Delay = Interval = Mobile.GetStamRegenRate( m_Owner ); + } + } + + private class LogoutTimer : Timer + { + private Mobile m_Mobile; + + public LogoutTimer( Mobile m ) + : base( TimeSpan.FromDays( 1.0 ) ) + { + Priority = TimerPriority.OneSecond; + m_Mobile = m; + } + + protected override void OnTick() + { + if( m_Mobile.m_Map != Map.Internal ) + { + EventSink.InvokeLogout( new LogoutEventArgs( m_Mobile ) ); + + m_Mobile.m_LogoutLocation = m_Mobile.m_Location; + m_Mobile.m_LogoutMap = m_Mobile.m_Map; + + m_Mobile.Internalize(); + } + } + } + + private class ParalyzedTimer : Timer + { + private Mobile m_Mobile; + + public ParalyzedTimer( Mobile m, TimeSpan duration ) + : base( duration ) + { + this.Priority = TimerPriority.TwentyFiveMS; + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.Paralyzed = false; + } + } + + private class FrozenTimer : Timer + { + private Mobile m_Mobile; + + public FrozenTimer( Mobile m, TimeSpan duration ) + : base( duration ) + { + this.Priority = TimerPriority.TwentyFiveMS; + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.Frozen = false; + } + } + + private class CombatTimer : Timer + { + private Mobile m_Mobile; + + public CombatTimer( Mobile m ) + : base( TimeSpan.FromSeconds( 0.0 ), TimeSpan.FromSeconds( 0.01 ), 0 ) + { + m_Mobile = m; + + if( !m_Mobile.m_Player && m_Mobile.m_Dex <= 100 ) + Priority = TimerPriority.FiftyMS; + } + + protected override void OnTick() + { + if( DateTime.Now > m_Mobile.m_NextCombatTime ) + { + Mobile combatant = m_Mobile.Combatant; + + // If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat + if( combatant == null || combatant.m_Deleted || m_Mobile.m_Deleted || combatant.m_Map != m_Mobile.m_Map || !combatant.Alive || !m_Mobile.Alive || !m_Mobile.CanSee( combatant ) || combatant.IsDeadBondedPet || m_Mobile.IsDeadBondedPet ) + { + m_Mobile.Combatant = null; + return; + } + + IWeapon weapon = m_Mobile.Weapon; + + if( !m_Mobile.InRange( combatant, weapon.MaxRange ) ) + return; + + if( m_Mobile.InLOS( combatant ) ) + { + weapon.OnBeforeSwing( m_Mobile, combatant ); //OnBeforeSwing for checking in regards to being hidden and whatnot + m_Mobile.RevealingAction(); + m_Mobile.m_NextCombatTime = DateTime.Now + weapon.OnSwing( m_Mobile, combatant ); + } + } + } + } + + private class ExpireCombatantTimer : Timer + { + private Mobile m_Mobile; + + public ExpireCombatantTimer( Mobile m ) + : base( TimeSpan.FromMinutes( 1.0 ) ) + { + this.Priority = TimerPriority.FiveSeconds; + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.Combatant = null; + } + } + + private static TimeSpan m_ExpireCriminalDelay = TimeSpan.FromMinutes( 2.0 ); + + public static TimeSpan ExpireCriminalDelay + { + get { return m_ExpireCriminalDelay; } + set { m_ExpireCriminalDelay = value; } + } + + private class ExpireCriminalTimer : Timer + { + private Mobile m_Mobile; + + public ExpireCriminalTimer( Mobile m ) + : base( m_ExpireCriminalDelay ) + { + this.Priority = TimerPriority.FiveSeconds; + m_Mobile = m; + } + + protected override void OnTick() + { + m_Mobile.Criminal = false; + } + } + + private class ExpireAggressorsTimer : Timer + { + private Mobile m_Mobile; + + public ExpireAggressorsTimer( Mobile m ) + : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) ) + { + m_Mobile = m; + Priority = TimerPriority.FiveSeconds; + } + + protected override void OnTick() + { + if( m_Mobile.Deleted || (m_Mobile.Aggressors.Count == 0 && m_Mobile.Aggressed.Count == 0) ) + m_Mobile.StopAggrExpire(); + else + m_Mobile.CheckAggrExpire(); + } + } + + #endregion + + private DateTime m_NextCombatTime; + + public DateTime NextSkillTime + { + get + { + return m_NextSkillTime; + } + set + { + m_NextSkillTime = value; + } + } + + public List Aggressors + { + get + { + return m_Aggressors; + } + } + + public List Aggressed + { + get + { + return m_Aggressed; + } + } + + private int m_ChangingCombatant; + + public bool ChangingCombatant + { + get { return (m_ChangingCombatant > 0); } + } + + public virtual void Attack( Mobile m ) + { + if( CheckAttack( m ) ) + Combatant = m; + } + + public virtual bool CheckAttack( Mobile m ) + { + return (Utility.InUpdateRange( this, m ) && CanSee( m ) && InLOS( m )); + } + + /// + /// Overridable. Gets or sets which Mobile that this Mobile is currently engaged in combat with. + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual Mobile Combatant + { + get + { + return m_Combatant; + } + set + { + if( m_Deleted ) + return; + + if( m_Combatant != value && value != this ) + { + Mobile old = m_Combatant; + + ++m_ChangingCombatant; + m_Combatant = value; + + if( (m_Combatant != null && !CanBeHarmful( m_Combatant, false )) || !Region.OnCombatantChange( this, old, m_Combatant ) ) + { + m_Combatant = old; + --m_ChangingCombatant; + return; + } + + if( m_NetState != null ) + m_NetState.Send( new ChangeCombatant( m_Combatant ) ); + + if( m_Combatant == null ) + { + if( m_ExpireCombatant != null ) + m_ExpireCombatant.Stop(); + + if( m_CombatTimer != null ) + m_CombatTimer.Stop(); + + m_ExpireCombatant = null; + m_CombatTimer = null; + } + else + { + if( m_ExpireCombatant == null ) + m_ExpireCombatant = new ExpireCombatantTimer( this ); + + m_ExpireCombatant.Start(); + + if( m_CombatTimer == null ) + m_CombatTimer = new CombatTimer( this ); + + m_CombatTimer.Start(); + } + + if( m_Combatant != null && CanBeHarmful( m_Combatant, false ) ) + { + DoHarmful( m_Combatant ); + + if( m_Combatant != null ) + m_Combatant.PlaySound( m_Combatant.GetAngerSound() ); + } + + OnCombatantChange(); + --m_ChangingCombatant; + } + } + } + + /// + /// Overridable. Virtual event invoked after the property has changed. + /// + /// + public virtual void OnCombatantChange() + { + } + + public double GetDistanceToSqrt( Point3D p ) + { + int xDelta = m_Location.m_X - p.m_X; + int yDelta = m_Location.m_Y - p.m_Y; + + return Math.Sqrt( (xDelta * xDelta) + (yDelta * yDelta) ); + } + + public double GetDistanceToSqrt( Mobile m ) + { + int xDelta = m_Location.m_X - m.m_Location.m_X; + int yDelta = m_Location.m_Y - m.m_Location.m_Y; + + return Math.Sqrt( (xDelta * xDelta) + (yDelta * yDelta) ); + } + + public double GetDistanceToSqrt( IPoint2D p ) + { + int xDelta = m_Location.m_X - p.X; + int yDelta = m_Location.m_Y - p.Y; + + return Math.Sqrt( (xDelta * xDelta) + (yDelta * yDelta) ); + } + + public virtual void AggressiveAction( Mobile aggressor ) + { + AggressiveAction( aggressor, false ); + } + + public virtual void AggressiveAction( Mobile aggressor, bool criminal ) + { + if( aggressor == this ) + return; + + AggressiveActionEventArgs args = AggressiveActionEventArgs.Create( this, aggressor, criminal ); + + EventSink.InvokeAggressiveAction( args ); + + args.Free(); + + if( Combatant == aggressor ) + { + if( m_ExpireCombatant == null ) + m_ExpireCombatant = new ExpireCombatantTimer( this ); + else + m_ExpireCombatant.Stop(); + + m_ExpireCombatant.Start(); + } + + bool addAggressor = true; + + List list = m_Aggressors; + + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( info.Attacker == aggressor ) + { + info.Refresh(); + info.CriminalAggression = criminal; + info.CanReportMurder = criminal; + + addAggressor = false; + } + } + + list = aggressor.m_Aggressors; + + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( info.Attacker == this ) + { + info.Refresh(); + + addAggressor = false; + } + } + + bool addAggressed = true; + + list = m_Aggressed; + + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( info.Defender == aggressor ) + { + info.Refresh(); + + addAggressed = false; + } + } + + list = aggressor.m_Aggressed; + + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( info.Defender == this ) + { + info.Refresh(); + info.CriminalAggression = criminal; + info.CanReportMurder = criminal; + + addAggressed = false; + } + } + + bool setCombatant = false; + + if( addAggressor ) + { + m_Aggressors.Add( AggressorInfo.Create( aggressor, this, criminal ) ); // new AggressorInfo( aggressor, this, criminal, true ) ); + + if( this.CanSee( aggressor ) && m_NetState != null ) { + m_NetState.Send(MobileIncoming.Create(m_NetState, this, aggressor)); + } + + if( Combatant == null ) + setCombatant = true; + + UpdateAggrExpire(); + } + + if( addAggressed ) + { + aggressor.m_Aggressed.Add( AggressorInfo.Create( aggressor, this, criminal ) ); // new AggressorInfo( aggressor, this, criminal, false ) ); + + if( this.CanSee( aggressor ) && m_NetState != null ) { + m_NetState.Send(MobileIncoming.Create(m_NetState, this, aggressor)); + } + + if( Combatant == null ) + setCombatant = true; + + UpdateAggrExpire(); + } + + if( setCombatant ) + Combatant = aggressor; + + Region.OnAggressed( aggressor, this, criminal ); + } + + public void RemoveAggressed( Mobile aggressed ) + { + if( m_Deleted ) + return; + + List list = m_Aggressed; + + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( info.Defender == aggressed ) + { + m_Aggressed.RemoveAt( i ); + info.Free(); + + if( m_NetState != null && this.CanSee( aggressed ) ) { + if ( m_NetState.StygianAbyss ) { + m_NetState.Send( new MobileIncoming( this, aggressed ) ); + } else { + m_NetState.Send( new MobileIncomingOld( this, aggressed ) ); + } + } + + break; + } + } + + UpdateAggrExpire(); + } + + public void RemoveAggressor( Mobile aggressor ) + { + if( m_Deleted ) + return; + + List list = m_Aggressors; + + for( int i = 0; i < list.Count; ++i ) + { + AggressorInfo info = list[i]; + + if( info.Attacker == aggressor ) + { + m_Aggressors.RemoveAt( i ); + info.Free(); + + if( m_NetState != null && this.CanSee( aggressor ) ) { + m_NetState.Send(MobileIncoming.Create(m_NetState, this, aggressor)); + } + + break; + } + } + + UpdateAggrExpire(); + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalGold + { + get { return GetTotal( TotalType.Gold ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalItems + { + get { return GetTotal( TotalType.Items ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TotalWeight + { + get { return GetTotal( TotalType.Weight ); } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int TithingPoints + { + get + { + return m_TithingPoints; + } + set + { + if( m_TithingPoints != value ) + { + m_TithingPoints = value; + + Delta( MobileDelta.TithingPoints ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Followers + { + get + { + return m_Followers; + } + set + { + if( m_Followers != value ) + { + m_Followers = value; + + Delta( MobileDelta.Followers ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int FollowersMax + { + get + { + return m_FollowersMax; + } + set + { + if( m_FollowersMax != value ) + { + m_FollowersMax = value; + + Delta( MobileDelta.Followers ); + } + } + } + + public virtual int GetTotal( TotalType type ) + { + switch( type ) + { + case TotalType.Gold: + return m_TotalGold; + + case TotalType.Items: + return m_TotalItems; + + case TotalType.Weight: + return m_TotalWeight; + } + + return 0; + } + + public virtual void UpdateTotal( Item sender, TotalType type, int delta ) + { + if( delta == 0 || sender.IsVirtualItem ) + return; + + switch( type ) + { + case TotalType.Gold: + m_TotalGold += delta; + Delta( MobileDelta.Gold ); + break; + + case TotalType.Items: + m_TotalItems += delta; + break; + + case TotalType.Weight: + m_TotalWeight += delta; + Delta( MobileDelta.Weight ); + OnWeightChange( m_TotalWeight - delta ); + break; + } + } + + public virtual void UpdateTotals() + { + if( m_Items == null ) + return; + + int oldWeight = m_TotalWeight; + + m_TotalGold = 0; + m_TotalItems = 0; + m_TotalWeight = 0; + + for( int i = 0; i < m_Items.Count; ++i ) + { + Item item = m_Items[i]; + + item.UpdateTotals(); + + if( item.IsVirtualItem ) + continue; + + m_TotalGold += item.TotalGold; + m_TotalItems += item.TotalItems + 1; + m_TotalWeight += item.TotalWeight + item.PileWeight; + } + + if( m_Holding != null ) + m_TotalWeight += m_Holding.TotalWeight + m_Holding.PileWeight; + + if( m_TotalWeight != oldWeight ) + OnWeightChange( oldWeight ); + } + + public void ClearQuestArrow() + { + m_QuestArrow = null; + } + + public void ClearTarget() + { + m_Target = null; + } + + private bool m_TargetLocked; + + public bool TargetLocked + { + get + { + return m_TargetLocked; + } + set + { + m_TargetLocked = value; + } + } + + private class SimpleTarget : Target + { + private TargetCallback m_Callback; + + public SimpleTarget( int range, TargetFlags flags, bool allowGround, TargetCallback callback ) + : base( range, allowGround, flags ) + { + m_Callback = callback; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if( m_Callback != null ) + m_Callback( from, targeted ); + } + } + + public Target BeginTarget( int range, bool allowGround, TargetFlags flags, TargetCallback callback ) + { + Target t = new SimpleTarget( range, flags, allowGround, callback ); + + this.Target = t; + + return t; + } + + private class SimpleStateTarget : Target + { + private TargetStateCallback m_Callback; + private object m_State; + + public SimpleStateTarget( int range, TargetFlags flags, bool allowGround, TargetStateCallback callback, object state ) + : base( range, allowGround, flags ) + { + m_Callback = callback; + m_State = state; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if( m_Callback != null ) + m_Callback( from, targeted, m_State ); + } + } + + public Target BeginTarget( int range, bool allowGround, TargetFlags flags, TargetStateCallback callback, object state ) + { + Target t = new SimpleStateTarget( range, flags, allowGround, callback, state ); + + this.Target = t; + + return t; + } + + private class SimpleStateTarget : Target + { + private TargetStateCallback m_Callback; + private T m_State; + + public SimpleStateTarget(int range, TargetFlags flags, bool allowGround, TargetStateCallback callback, T state) + : base(range, allowGround, flags) + { + m_Callback = callback; + m_State = state; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Callback != null) + m_Callback(from, targeted, m_State); + } + } + public Target BeginTarget(int range, bool allowGround, TargetFlags flags, TargetStateCallback callback, T state) + { + Target t = new SimpleStateTarget(range, flags, allowGround, callback, state); + + this.Target = t; + + return t; + } + + public Target Target + { + get + { + return m_Target; + } + set + { + Target oldTarget = m_Target; + Target newTarget = value; + + if( oldTarget == newTarget ) + return; + + m_Target = null; + + if( oldTarget != null && newTarget != null ) + oldTarget.Cancel( this, TargetCancelType.Overriden ); + + m_Target = newTarget; + + if( newTarget != null && m_NetState != null && !m_TargetLocked ) + m_NetState.Send( newTarget.GetPacketFor( m_NetState ) ); + + OnTargetChange(); + } + } + + /// + /// Overridable. Virtual event invoked after the Target property has changed. + /// + protected virtual void OnTargetChange() + { + } + + public ContextMenu ContextMenu + { + get + { + return m_ContextMenu; + } + set + { + m_ContextMenu = value; + + if (m_ContextMenu != null && m_NetState != null) + { + // Old packet is preferred until assistants catch up + if (m_NetState.NewHaven && m_ContextMenu.RequiresNewPacket) + Send(new DisplayContextMenu(m_ContextMenu)); + else + Send(new DisplayContextMenuOld(m_ContextMenu)); + } + } + } + + public virtual bool CheckContextMenuDisplay( IEntity target ) + { + return true; + } + + #region Prompts + private class SimplePrompt : Prompt + { + private PromptCallback m_Callback; + private PromptCallback m_CancelCallback; + private bool m_CallbackHandlesCancel; + + public SimplePrompt( PromptCallback callback, PromptCallback cancelCallback ) + { + m_Callback = callback; + m_CancelCallback = cancelCallback; + } + + public SimplePrompt( PromptCallback callback, bool callbackHandlesCancel ) + { + m_Callback = callback; + m_CallbackHandlesCancel = callbackHandlesCancel; + } + + public SimplePrompt( PromptCallback callback ) + : this( callback, false ) + { + } + + public override void OnResponse( Mobile from, string text ) + { + if( m_Callback != null ) + m_Callback( from, text ); + } + + public override void OnCancel( Mobile from ) + { + if( m_CallbackHandlesCancel && m_Callback != null ) + m_Callback( from, "" ); + else if( m_CancelCallback != null ) + m_CancelCallback( from, "" ); + } + } + public Prompt BeginPrompt( PromptCallback callback, PromptCallback cancelCallback ) + { + Prompt p = new SimplePrompt( callback, cancelCallback ); + + this.Prompt = p; + return p; + } + public Prompt BeginPrompt( PromptCallback callback, bool callbackHandlesCancel ) + { + Prompt p = new SimplePrompt( callback, callbackHandlesCancel ); + + this.Prompt = p; + return p; + } + public Prompt BeginPrompt( PromptCallback callback ) + { + return BeginPrompt( callback, false ); + } + + private class SimpleStatePrompt : Prompt + { + private PromptStateCallback m_Callback; + private PromptStateCallback m_CancelCallback; + + private bool m_CallbackHandlesCancel; + + private object m_State; + + public SimpleStatePrompt( PromptStateCallback callback, PromptStateCallback cancelCallback, object state ) + { + m_Callback = callback; + m_CancelCallback = cancelCallback; + m_State = state; + } + public SimpleStatePrompt( PromptStateCallback callback, bool callbackHandlesCancel, object state ) + { + m_Callback = callback; + m_State = state; + m_CallbackHandlesCancel = callbackHandlesCancel; + } + public SimpleStatePrompt( PromptStateCallback callback, object state ) + : this( callback, false, state ) + { + } + + public override void OnResponse( Mobile from, string text ) + { + if( m_Callback != null ) + m_Callback( from, text, m_State ); + } + + public override void OnCancel( Mobile from ) + { + if( m_CallbackHandlesCancel && m_Callback != null ) + m_Callback( from, "", m_State ); + else if( m_CancelCallback != null ) + m_CancelCallback( from, "", m_State ); + } + } + public Prompt BeginPrompt( PromptStateCallback callback, PromptStateCallback cancelCallback, object state ) + { + Prompt p = new SimpleStatePrompt( callback, cancelCallback, state ); + + this.Prompt = p; + return p; + } + public Prompt BeginPrompt( PromptStateCallback callback, bool callbackHandlesCancel, object state ) + { + Prompt p = new SimpleStatePrompt( callback, callbackHandlesCancel, state ); + + this.Prompt = p; + return p; + } + public Prompt BeginPrompt( PromptStateCallback callback, object state ) + { + return BeginPrompt( callback, false, state ); + } + + private class SimpleStatePrompt : Prompt + { + private PromptStateCallback m_Callback; + private PromptStateCallback m_CancelCallback; + + private bool m_CallbackHandlesCancel; + + private T m_State; + + public SimpleStatePrompt(PromptStateCallback callback, PromptStateCallback cancelCallback, T state) + { + m_Callback = callback; + m_CancelCallback = cancelCallback; + m_State = state; + } + public SimpleStatePrompt(PromptStateCallback callback, bool callbackHandlesCancel, T state) + { + m_Callback = callback; + m_State = state; + m_CallbackHandlesCancel = callbackHandlesCancel; + } + public SimpleStatePrompt(PromptStateCallback callback, T state) + : this(callback, false, state) + { + } + + public override void OnResponse(Mobile from, string text) + { + if (m_Callback != null) + m_Callback(from, text, m_State); + } + + public override void OnCancel(Mobile from) + { + if (m_CallbackHandlesCancel && m_Callback != null) + m_Callback(from, "", m_State); + else if (m_CancelCallback != null) + m_CancelCallback(from, "", m_State); + } + } + public Prompt BeginPrompt(PromptStateCallback callback, PromptStateCallback cancelCallback, T state) + { + Prompt p = new SimpleStatePrompt(callback, cancelCallback, state); + + this.Prompt = p; + return p; + } + public Prompt BeginPrompt(PromptStateCallback callback, bool callbackHandlesCancel, T state) + { + Prompt p = new SimpleStatePrompt(callback, callbackHandlesCancel, state); + + this.Prompt = p; + return p; + } + public Prompt BeginPrompt(PromptStateCallback callback, T state) + { + return BeginPrompt(callback, false, state); + } + + public Prompt Prompt + { + get + { + return m_Prompt; + } + set + { + Prompt oldPrompt = m_Prompt; + Prompt newPrompt = value; + + if( oldPrompt == newPrompt ) + return; + + m_Prompt = null; + + if( oldPrompt != null && newPrompt != null ) + oldPrompt.OnCancel( this ); + + m_Prompt = newPrompt; + + if( newPrompt != null ) + Send( new UnicodePrompt( newPrompt ) ); + } + } + #endregion + + private bool InternalOnMove( Direction d ) + { + if( !OnMove( d ) ) + return false; + + MovementEventArgs e = MovementEventArgs.Create( this, d ); + + EventSink.InvokeMovement( e ); + + bool ret = !e.Blocked; + + e.Free(); + + return ret; + } + + /// + /// Overridable. Event invoked before the Mobile moves. + /// + /// True if the move is allowed, false if not. + protected virtual bool OnMove( Direction d ) + { + if( m_Hidden && m_AccessLevel == AccessLevel.Player ) + { + if( m_AllowedStealthSteps-- <= 0 || (d & Direction.Running) != 0 || this.Mounted ) + RevealingAction(); + } + + return true; + } + + // Scriptiz : 4 packets de 8 au lieu de 2 de 8 pour le syst�me d'hallucinations ! + private static Packet[][] m_MovingPacketCache = new Packet[4][] + { + new Packet[8], + new Packet[8], + new Packet[8], + new Packet[8] + }; + + private bool m_Pushing; + + public bool Pushing + { + get + { + return m_Pushing; + } + set + { + m_Pushing = value; + } + } + + private static TimeSpan m_WalkFoot = TimeSpan.FromSeconds( 0.4 ); + private static TimeSpan m_RunFoot = TimeSpan.FromSeconds( 0.2 ); + private static TimeSpan m_WalkMount = TimeSpan.FromSeconds( 0.2 ); + private static TimeSpan m_RunMount = TimeSpan.FromSeconds( 0.1 ); + + public static TimeSpan WalkFoot { get { return m_WalkFoot; } } + public static TimeSpan RunFoot { get { return m_RunFoot; } } + public static TimeSpan WalkMount { get { return m_WalkMount; } } + public static TimeSpan RunMount { get { return m_RunMount; } } + + private DateTime m_EndQueue; + + private static ArrayList m_MoveList = new ArrayList(); + + private static AccessLevel m_FwdAccessOverride = AccessLevel.Counselor; + private static bool m_FwdEnabled = true; + private static bool m_FwdUOTDOverride = false; + private static int m_FwdMaxSteps = 4; + + public static AccessLevel FwdAccessOverride { get { return m_FwdAccessOverride; } set { m_FwdAccessOverride = value; } } + public static bool FwdEnabled { get { return m_FwdEnabled; } set { m_FwdEnabled = value; } } + public static bool FwdUOTDOverride { get { return m_FwdUOTDOverride; } set { m_FwdUOTDOverride = value; } } + public static int FwdMaxSteps { get { return m_FwdMaxSteps; } set { m_FwdMaxSteps = value; } } + + public virtual void ClearFastwalkStack() + { + if( m_MoveRecords != null && m_MoveRecords.Count > 0 ) + m_MoveRecords.Clear(); + + m_EndQueue = DateTime.Now; + } + + public virtual bool CheckMovement( Direction d, out int newZ ) + { + return Movement.Movement.CheckMovement( this, d, out newZ ); + } + + public virtual bool Move( Direction d ) + { + if( m_Deleted ) + return false; + + BankBox box = FindBankNoCreate(); + + if( box != null && box.Opened ) + box.Close(); + + Point3D newLocation = m_Location; + Point3D oldLocation = newLocation; + + if( (m_Direction & Direction.Mask) == (d & Direction.Mask) ) + { + // We are actually moving (not just a direction change) + + if( m_Spell != null && !m_Spell.OnCasterMoving( d ) ) + return false; + + if( m_Paralyzed || m_Frozen ) + { + SendLocalizedMessage( 500111 ); // You are frozen and can not move. + + return false; + } + + int newZ; + + if( CheckMovement( d, out newZ ) ) + { + int x = oldLocation.m_X, y = oldLocation.m_Y; + int oldX = x, oldY = y; + int oldZ = oldLocation.m_Z; + + switch( d & Direction.Mask ) + { + case Direction.North: + --y; + break; + case Direction.Right: + ++x; + --y; + break; + case Direction.East: + ++x; + break; + case Direction.Down: + ++x; + ++y; + break; + case Direction.South: + ++y; + break; + case Direction.Left: + --x; + ++y; + break; + case Direction.West: + --x; + break; + case Direction.Up: + --x; + --y; + break; + } + + newLocation.m_X = x; + newLocation.m_Y = y; + newLocation.m_Z = newZ; + + m_Pushing = false; + + Map map = m_Map; + + if( map != null ) + { + Sector oldSector = map.GetSector( oldX, oldY ); + Sector newSector = map.GetSector( x, y ); + + if( oldSector != newSector ) + { + for( int i = 0; i < oldSector.Mobiles.Count; ++i ) + { + Mobile m = oldSector.Mobiles[i]; + + if( m != this && m.X == oldX && m.Y == oldY && (m.Z + 15) > oldZ && (oldZ + 15) > m.Z && !m.OnMoveOff( this ) ) + return false; + } + + for( int i = 0; i < oldSector.Items.Count; ++i ) + { + Item item = oldSector.Items[i]; + + if( item.AtWorldPoint( oldX, oldY ) && (item.Z == oldZ || ((item.Z + item.ItemData.Height) > oldZ && (oldZ + 15) > item.Z)) && !item.OnMoveOff( this ) ) + return false; + } + + for( int i = 0; i < newSector.Mobiles.Count; ++i ) + { + Mobile m = newSector.Mobiles[i]; + + if( m.X == x && m.Y == y && (m.Z + 15) > newZ && (newZ + 15) > m.Z && !m.OnMoveOver( this ) ) + return false; + } + + for( int i = 0; i < newSector.Items.Count; ++i ) + { + Item item = newSector.Items[i]; + + if( item.AtWorldPoint( x, y ) && (item.Z == newZ || ((item.Z + item.ItemData.Height) > newZ && (newZ + 15) > item.Z)) && !item.OnMoveOver( this ) ) + return false; + } + } + else + { + for( int i = 0; i < oldSector.Mobiles.Count; ++i ) + { + Mobile m = oldSector.Mobiles[i]; + + if( m != this && m.X == oldX && m.Y == oldY && (m.Z + 15) > oldZ && (oldZ + 15) > m.Z && !m.OnMoveOff( this ) ) + return false; + else if( m.X == x && m.Y == y && (m.Z + 15) > newZ && (newZ + 15) > m.Z && !m.OnMoveOver( this ) ) + return false; + } + + for( int i = 0; i < oldSector.Items.Count; ++i ) + { + Item item = oldSector.Items[i]; + + if( item.AtWorldPoint( oldX, oldY ) && (item.Z == oldZ || ((item.Z + item.ItemData.Height) > oldZ && (oldZ + 15) > item.Z)) && !item.OnMoveOff( this ) ) + return false; + else if( item.AtWorldPoint( x, y ) && (item.Z == newZ || ((item.Z + item.ItemData.Height) > newZ && (newZ + 15) > item.Z)) && !item.OnMoveOver( this ) ) + return false; + } + } + + if( !Region.CanMove( this, d, newLocation, oldLocation, m_Map ) ) + return false; + } + else + { + return false; + } + + if( !InternalOnMove( d ) ) + return false; + + if( m_FwdEnabled && m_NetState != null && m_AccessLevel < m_FwdAccessOverride && (!m_FwdUOTDOverride || !m_NetState.IsUOTDClient) ) + { + if( m_MoveRecords == null ) + m_MoveRecords = new Queue( 6 ); + + while( m_MoveRecords.Count > 0 ) + { + MovementRecord r = m_MoveRecords.Peek(); + + if( r.Expired() ) + m_MoveRecords.Dequeue(); + else + break; + } + + if( m_MoveRecords.Count >= m_FwdMaxSteps ) + { + FastWalkEventArgs fw = new FastWalkEventArgs( m_NetState ); + EventSink.InvokeFastWalk( fw ); + + if( fw.Blocked ) + return false; + } + + TimeSpan delay = ComputeMovementSpeed( d ); + + DateTime end; + + if( m_MoveRecords.Count > 0 ) + end = m_EndQueue + delay; + else + end = DateTime.Now + delay; + + m_MoveRecords.Enqueue( MovementRecord.NewInstance( end ) ); + + m_EndQueue = end; + } + + m_LastMoveTime = DateTime.Now; + } + else + { + return false; + } + + DisruptiveAction(); + } + + if( m_NetState != null ) + m_NetState.Send( MovementAck.Instantiate( m_NetState.Sequence, this ) );//new MovementAck( m_NetState.Sequence, this ) ); + + SetLocation( newLocation, false ); + SetDirection( d ); + + if( m_Map != null ) + { + IPooledEnumerable eable = m_Map.GetObjectsInRange( m_Location, Core.GlobalMaxUpdateRange ); + + foreach( object o in eable ) + { + if( o == this ) + continue; + + if( o is Mobile ) + { + m_MoveList.Add( o ); + } + else if( o is Item ) + { + Item item = (Item)o; + + if( item.HandlesOnMovement ) + m_MoveList.Add( item ); + } + } + + eable.Free(); + + Packet[][] cache = m_MovingPacketCache; + + for( int i = 0; i < cache.Length; ++i ) + for( int j = 0; j < cache[i].Length; ++j ) + Packet.Release( ref cache[i][j] ); + + for( int i = 0; i < m_MoveList.Count; ++i ) + { + object o = m_MoveList[i]; + + if( o is Mobile ) + { + Mobile m = (Mobile)m_MoveList[i]; + NetState ns = m.NetState; + + if( ns != null && Utility.InUpdateRange( m_Location, m.m_Location ) && m.CanSee( this ) ) + { + Packet p = null; + + if ( ns.StygianAbyss ) { + int noto = Notoriety.Compute( m, this ); + + // Scriptiz : syst�me d'hallucinations + if (m.IsHallucinated) + { + p = cache[2][noto]; + if (p == null) + cache[2][noto] = p = Packet.Acquire(new MobileMoving(this, noto, m)); + // Scriptiz : 3e param�tre pour les hallucinations + } + else + { + p = cache[0][noto]; + if (p == null) + cache[0][noto] = p = Packet.Acquire(new MobileMoving(this, noto, m)); + // Scriptiz : 3e param�tre pour les hallucinations + } + } else { + int noto = Notoriety.Compute( m, this ); + + if (m.IsHallucinated) + { + p = cache[3][noto]; + if (p == null) + cache[3][noto] = p = Packet.Acquire(new MobileMovingOld(this, noto, m)); + // Scriptiz : 3e param�tre pour les hallucinations + } + else + { + p = cache[1][noto]; + + if (p == null) + cache[1][noto] = p = Packet.Acquire(new MobileMovingOld(this, noto, m)); + // Scriptiz : 3e param�tre pour les hallucinations + } + } + + ns.Send( p ); + } + + m.OnMovement( this, oldLocation ); + } + else if( o is Item ) + { + ((Item)o).OnMovement( this, oldLocation ); + } + } + + for( int i = 0; i < cache.Length; ++i ) + for( int j = 0; j < cache[i].Length; ++j ) + Packet.Release( ref cache[i][j] ); + + if( m_MoveList.Count > 0 ) + m_MoveList.Clear(); + } + + OnAfterMove( oldLocation ); + return true; + } + + public virtual void OnAfterMove( Point3D oldLocation ) + { + } + + public TimeSpan ComputeMovementSpeed() + { + return ComputeMovementSpeed( this.Direction, false ); + } + + public TimeSpan ComputeMovementSpeed( Direction dir ) + { + return ComputeMovementSpeed( dir, true ); + } + + public virtual TimeSpan ComputeMovementSpeed( Direction dir, bool checkTurning ) + { + TimeSpan delay; + + if( Mounted ) + delay = (dir & Direction.Running) != 0 ? m_RunMount : m_WalkMount; + else + delay = (dir & Direction.Running) != 0 ? m_RunFoot : m_WalkFoot; + + return delay; + } + + /// + /// Overridable. Virtual event invoked when a Mobile moves off this Mobile. + /// + /// True if the move is allowed, false if not. + public virtual bool OnMoveOff( Mobile m ) + { + return true; + } + + public virtual bool IsDeadBondedPet { get { return false; } } + + /// + /// Overridable. Event invoked when a Mobile moves over this Mobile. + /// + /// True if the move is allowed, false if not. + public virtual bool OnMoveOver( Mobile m ) + { + if( m_Map == null || m_Deleted ) + return true; + + return m.CheckShove( this ); + } + + public virtual bool CheckShove( Mobile shoved ) + { + if( (m_Map.Rules & MapRules.FreeMovement) == 0 ) + { + if( !shoved.Alive || !Alive || shoved.IsDeadBondedPet || IsDeadBondedPet ) + return true; + else if( shoved.m_Hidden && shoved.m_AccessLevel > AccessLevel.Player ) + return true; + + if( !m_Pushing ) + { + m_Pushing = true; + + int number; + + if( this.AccessLevel > AccessLevel.Player ) + { + number = shoved.m_Hidden ? 1019041 : 1019040; + } + else + { + if( Stam == StamMax ) + { + number = shoved.m_Hidden ? 1019043 : 1019042; + Stam -= 10; + + RevealingAction(); + } + else + { + return false; + } + } + + SendLocalizedMessage( number ); + } + } + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile sees another Mobile, , move. + /// + public virtual void OnMovement( Mobile m, Point3D oldLocation ) + { + } + + public ISpell Spell + { + get + { + return m_Spell; + } + set + { + if( m_Spell != null && value != null ) + Console.WriteLine( "Warning: Spell has been overwritten" ); + + m_Spell = value; + } + } + + [CommandProperty( AccessLevel.Administrator )] + public bool AutoPageNotify + { + get + { + return m_AutoPageNotify; + } + set + { + m_AutoPageNotify = value; + } + } + + public virtual void CriminalAction( bool message ) + { + if( m_Deleted ) + return; + + Criminal = true; + + this.Region.OnCriminalAction( this, message ); + } + + public virtual bool CanUseStuckMenu() + { + if( m_StuckMenuUses == null ) + { + return true; + } + else + { + for( int i = 0; i < m_StuckMenuUses.Length; ++i ) + { + if( (DateTime.Now - m_StuckMenuUses[i]) > TimeSpan.FromDays( 1.0 ) ) + { + return true; + } + } + + return false; + } + } + + public virtual bool IsSnoop( Mobile from ) + { + return (from != this); + } + + /// + /// Overridable. Any call to will silently fail if this method returns false. + /// + /// + public virtual bool CheckResurrect() + { + return true; + } + + /// + /// Overridable. Event invoked before the Mobile is resurrected. + /// + /// + public virtual void OnBeforeResurrect() + { + } + + /// + /// Overridable. Event invoked after the Mobile is resurrected. + /// + /// + public virtual void OnAfterResurrect() + { + } + + public virtual void Resurrect() + { + if( !Alive ) + { + if( !Region.OnResurrect( this ) ) + return; + + if( !CheckResurrect() ) + return; + + OnBeforeResurrect(); + + BankBox box = FindBankNoCreate(); + + if( box != null && box.Opened ) + box.Close(); + + Poison = null; + + Warmode = false; + + Hits = 10; + Stam = StamMax; + Mana = 0; + + BodyMod = 0; + Body = this.Race.AliveBody( this ); + + // Scriptiz : on remet un corps d'elfe s'il faut + if (this.IsElfBody) Body = Race.Elf.AliveBody(this); + + ProcessDeltaQueue(); + + for( int i = m_Items.Count - 1; i >= 0; --i ) + { + if( i >= m_Items.Count ) + continue; + + Item item = m_Items[i]; + + if( item.ItemID == 0x204E ) + item.Delete(); + } + + this.SendIncomingPacket(); + this.SendIncomingPacket(); + + OnAfterResurrect(); + + //Send( new DeathStatus( false ) ); + } + } + + private IAccount m_Account; + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Owner)] + public IAccount Account + { + get + { + return m_Account; + } + set + { + m_Account = value; + } + } + + private bool m_Deleted; + + public bool Deleted + { + get + { + return m_Deleted; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int VirtualArmor + { + get + { + return m_VirtualArmor; + } + set + { + if( m_VirtualArmor != value ) + { + m_VirtualArmor = value; + + Delta( MobileDelta.Armor ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual double ArmorRating + { + get + { + return 0.0; + } + } + + public void DropHolding() + { + Item holding = m_Holding; + + if( holding != null ) + { + if ( !holding.Deleted && holding.HeldBy == this && holding.Map == Map.Internal ) + AddToBackpack( holding ); + + Holding = null; + holding.ClearBounce(); + } + } + + public virtual void Delete() + { + if( m_Deleted ) + return; + else if( !World.OnDelete( this ) ) + return; + + if( m_NetState != null ) + m_NetState.CancelAllTrades(); + + if( m_NetState != null ) + m_NetState.Dispose(); + + DropHolding(); + + Region.OnRegionChange( this, m_Region, null ); + + m_Region = null; + //Is the above line REALLY needed? The old Region system did NOT have said line + //and worked fine, because of this a LOT of extra checks have to be done everywhere... + //I guess this should be there for Garbage collection purposes, but, still, is it /really/ needed? + + OnDelete(); + + for( int i = m_Items.Count - 1; i >= 0; --i ) + if( i < m_Items.Count ) + m_Items[i].OnParentDeleted( this ); + + for( int i = 0; i < m_Stabled.Count; i++ ) + m_Stabled[i].Delete(); + + SendRemovePacket(); + + if( m_Guild != null ) + m_Guild.OnDelete( this ); + + m_Deleted = true; + + if( m_Map != null ) + { + m_Map.OnLeave( this ); + m_Map = null; + } + + m_Hair = null; + m_FacialHair = null; + m_MountItem = null; + + World.RemoveMobile( this ); + + OnAfterDelete(); + + FreeCache(); + } + + /// + /// Overridable. Virtual event invoked before the Mobile is deleted. + /// + public virtual void OnDelete() + { + if( m_Spawner != null ) + { + m_Spawner.Remove( this ); + m_Spawner = null; + } + } + + /// + /// Overridable. Returns true if the player is alive, false if otherwise. By default, this is computed by: !Deleted && (!Player || !Body.IsGhost) + /// + [CommandProperty( AccessLevel.Counselor )] + public virtual bool Alive + { + get + { + return !m_Deleted && (!m_Player || !m_Body.IsGhost); + } + } + + public virtual bool CheckSpellCast( ISpell spell ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile casts a . + /// + /// + public virtual void OnSpellCast( ISpell spell ) + { + } + + /// + /// Overridable. Virtual event invoked after changes. + /// + public virtual void OnWeightChange( int oldValue ) + { + } + + /// + /// Overridable. Virtual event invoked when the or property of changes. + /// + public virtual void OnSkillChange( SkillName skill, double oldBase ) + { + } + + /// + /// Overridable. Invoked after the mobile is deleted. When overriden, be sure to call the base method. + /// + public virtual void OnAfterDelete() + { + StopAggrExpire(); + + CheckAggrExpire(); + + if( m_PoisonTimer != null ) + m_PoisonTimer.Stop(); + + if( m_HitsTimer != null ) + m_HitsTimer.Stop(); + + if( m_StamTimer != null ) + m_StamTimer.Stop(); + + if( m_ManaTimer != null ) + m_ManaTimer.Stop(); + + if( m_CombatTimer != null ) + m_CombatTimer.Stop(); + + if( m_ExpireCombatant != null ) + m_ExpireCombatant.Stop(); + + if( m_LogoutTimer != null ) + m_LogoutTimer.Stop(); + + if( m_ExpireCriminal != null ) + m_ExpireCriminal.Stop(); + + if( m_WarmodeTimer != null ) + m_WarmodeTimer.Stop(); + + if( m_ParaTimer != null ) + m_ParaTimer.Stop(); + + if( m_FrozenTimer != null ) + m_FrozenTimer.Stop(); + + if( m_AutoManifestTimer != null ) + m_AutoManifestTimer.Stop(); + } + + public virtual bool AllowSkillUse( SkillName name ) + { + return true; + } + + public virtual bool UseSkill( SkillName name ) + { + return Skills.UseSkill( this, name ); + } + + public virtual bool UseSkill( int skillID ) + { + return Skills.UseSkill( this, skillID ); + } + + private static CreateCorpseHandler m_CreateCorpse; + + public static CreateCorpseHandler CreateCorpseHandler + { + get { return m_CreateCorpse; } + set { m_CreateCorpse = value; } + } + + public virtual DeathMoveResult GetParentMoveResultFor( Item item ) + { + return item.OnParentDeath( this ); + } + + public virtual DeathMoveResult GetInventoryMoveResultFor( Item item ) + { + return item.OnInventoryDeath( this ); + } + + public virtual bool RetainPackLocsOnDeath { get { return Core.AOS; } } + + public virtual void Kill() + { + if( !CanBeDamaged() ) + return; + else if( !Alive || IsDeadBondedPet ) + return; + else if( m_Deleted ) + return; + else if( !Region.OnBeforeDeath( this ) ) + return; + else if( !OnBeforeDeath() ) + return; + + BankBox box = FindBankNoCreate(); + + if( box != null && box.Opened ) + box.Close(); + + if( m_NetState != null ) + m_NetState.CancelAllTrades(); + + if( m_Spell != null ) + m_Spell.OnCasterKilled(); + //m_Spell.Disturb( DisturbType.Kill ); + + if( m_Target != null ) + m_Target.Cancel( this, TargetCancelType.Canceled ); + + DisruptiveAction(); + + Warmode = false; + + DropHolding(); + + Hits = 0; + Stam = 0; + Mana = 0; + + Poison = null; + Combatant = null; + + if( Paralyzed ) + { + Paralyzed = false; + + if( m_ParaTimer != null ) + m_ParaTimer.Stop(); + } + + if( Frozen ) + { + Frozen = false; + + if( m_FrozenTimer != null ) + m_FrozenTimer.Stop(); + } + + List content = new List(); + List equip = new List(); + List moveToPack = new List(); + + List itemsCopy = new List( m_Items ); + + Container pack = this.Backpack; + + for( int i = 0; i < itemsCopy.Count; ++i ) + { + Item item = itemsCopy[i]; + + if( item == pack ) + continue; + + DeathMoveResult res = GetParentMoveResultFor( item ); + + switch( res ) + { + case DeathMoveResult.MoveToCorpse: + { + content.Add( item ); + equip.Add( item ); + break; + } + case DeathMoveResult.MoveToBackpack: + { + moveToPack.Add( item ); + break; + } + } + } + + if( pack != null ) + { + List packCopy = new List( pack.Items ); + + for( int i = 0; i < packCopy.Count; ++i ) + { + Item item = packCopy[i]; + + DeathMoveResult res = GetInventoryMoveResultFor( item ); + + if( res == DeathMoveResult.MoveToCorpse ) + content.Add( item ); + else + moveToPack.Add( item ); + } + + for( int i = 0; i < moveToPack.Count; ++i ) + { + Item item = moveToPack[i]; + + if( RetainPackLocsOnDeath && item.Parent == pack ) + continue; + + pack.DropItem( item ); + } + } + + HairInfo hair = null; + if( m_Hair != null ) + hair = new HairInfo( m_Hair.ItemID, m_Hair.Hue ); + + FacialHairInfo facialhair = null; + if( m_FacialHair != null ) + facialhair = new FacialHairInfo( m_FacialHair.ItemID, m_FacialHair.Hue ); + + Container c = (m_CreateCorpse == null ? null : m_CreateCorpse( this, hair, facialhair, content, equip )); + + + /*m_Corpse = c; + + for ( int i = 0; c != null && i < content.Count; ++i ) + c.DropItem( (Item)content[i] ); + + if ( c != null ) + c.MoveToWorld( this.Location, this.Map );*/ + + if( m_Map != null ) + { + Packet animPacket = null;//new DeathAnimation( this, c ); + Packet remPacket = null;//this.RemovePacket; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state != m_NetState ) + { + if( animPacket == null ) + animPacket = Packet.Acquire( new DeathAnimation( this, c ) ); + + state.Send( animPacket ); + + if( !state.Mobile.CanSee( this ) ) + { + if( remPacket == null ) + remPacket = this.RemovePacket; + + state.Send( remPacket ); + } + } + } + + Packet.Release( animPacket ); + + eable.Free(); + } + + Region.OnDeath( this ); + OnDeath( c ); + } + + private Container m_Corpse; + + [CommandProperty( AccessLevel.GameMaster )] + public Container Corpse + { + get + { + return m_Corpse; + } + set + { + m_Corpse = value; + } + } + + /// + /// Overridable. Event invoked before the Mobile is killed. + /// + /// + /// + /// True to continue with death, false to override it. + public virtual bool OnBeforeDeath() + { + return true; + } + + /// + /// Overridable. Event invoked after the Mobile is killed. Primarily, this method is responsible for deleting an NPC or turning a PC into a ghost. + /// + /// + /// + public virtual void OnDeath( Container c ) + { + // Scriptiz : on incr�mente de 1 le compteur du nombre de morts du mobile + this.Deaths++; + + int sound = this.GetDeathSound(); + + if( sound >= 0 ) + Effects.PlaySound( this, this.Map, sound ); + + if( !m_Player ) + { + Delete(); + } + else + { + Send( DeathStatus.Instantiate( true ) ); + + Warmode = false; + + BodyMod = 0; + //Body = this.Female ? 0x193 : 0x192; + Body = this.Race.GhostBody( this ); + + // Scriptiz : on met un corps d'elfe si le joueur � l'apparence elfique + if (this.IsElfBody) Body = Race.Elf.GhostBody(this); + + Item deathShroud = new Item( 0x204E ); + + deathShroud.Movable = false; + deathShroud.Layer = Layer.OuterTorso; + + AddItem( deathShroud ); + + m_Items.Remove( deathShroud ); + m_Items.Insert( 0, deathShroud ); + + Poison = null; + Combatant = null; + + Hits = 0; + Stam = 0; + Mana = 0; + + EventSink.InvokePlayerDeath( new PlayerDeathEventArgs( this ) ); + + ProcessDeltaQueue(); + + Send( DeathStatus.Instantiate( false ) ); + + CheckStatTimers(); + } + } + + #region Get*Sound + + public virtual int GetAngerSound() + { + if( m_BaseSoundID != 0 ) + return m_BaseSoundID; + + return -1; + } + + public virtual int GetIdleSound() + { + if( m_BaseSoundID != 0 ) + return m_BaseSoundID + 1; + + return -1; + } + + public virtual int GetAttackSound() + { + if( m_BaseSoundID != 0 ) + return m_BaseSoundID + 2; + + return -1; + } + + public virtual int GetHurtSound() + { + if( m_BaseSoundID != 0 ) + return m_BaseSoundID + 3; + + return -1; + } + + public virtual int GetDeathSound() + { + if( m_BaseSoundID != 0 ) + { + return m_BaseSoundID + 4; + } + else if( m_Body.IsHuman ) + { + return Utility.Random( m_Female ? 0x314 : 0x423, m_Female ? 4 : 5 ); + } + else + { + return -1; + } + } + + #endregion + + private static char[] m_GhostChars = new char[2] { 'o', 'O' }; + + public static char[] GhostChars { get { return m_GhostChars; } set { m_GhostChars = value; } } + + private static bool m_NoSpeechLOS; + + public static bool NoSpeechLOS { get { return m_NoSpeechLOS; } set { m_NoSpeechLOS = value; } } + + private static TimeSpan m_AutoManifestTimeout = TimeSpan.FromSeconds( 5.0 ); + + public static TimeSpan AutoManifestTimeout { get { return m_AutoManifestTimeout; } set { m_AutoManifestTimeout = value; } } + + private Timer m_AutoManifestTimer; + + private class AutoManifestTimer : Timer + { + private Mobile m_Mobile; + + public AutoManifestTimer( Mobile m, TimeSpan delay ) + : base( delay ) + { + m_Mobile = m; + } + + protected override void OnTick() + { + if( !m_Mobile.Alive ) + m_Mobile.Warmode = false; + } + } + + public virtual bool CheckTarget( Mobile from, Target targ, object targeted ) + { + return true; + } + + private static bool m_InsuranceEnabled; + + public static bool InsuranceEnabled + { + get { return m_InsuranceEnabled; } + set { m_InsuranceEnabled = value; } + } + + public virtual void Use( Item item ) + { + if (item == null || item.Deleted || item.QuestItem || this.Deleted) + return; + + DisruptiveAction(); + + if( m_Spell != null && !m_Spell.OnCasterUsingObject( item ) ) + return; + + object root = item.RootParent; + bool okay = false; + + if( !Utility.InUpdateRange( this, item.GetWorldLocation() ) ) + item.OnDoubleClickOutOfRange( this ); + else if( !CanSee( item ) ) + item.OnDoubleClickCantSee( this ); + else if( !item.IsAccessibleTo( this ) ) + { + Region reg = Region.Find( item.GetWorldLocation(), item.Map ); + + if( reg == null || !reg.SendInaccessibleMessage( item, this ) ) + item.OnDoubleClickNotAccessible( this ); + } + else if( !CheckAlive( false ) ) + item.OnDoubleClickDead( this ); + else if( item.InSecureTrade ) + item.OnDoubleClickSecureTrade( this ); + else if( !AllowItemUse( item ) ) + okay = false; + else if( !item.CheckItemUse( this, item ) ) + okay = false; + else if( root != null && root is Mobile && ((Mobile)root).IsSnoop( this ) ) + item.OnSnoop( this ); + else if( this.Region.OnDoubleClick( this, item ) ) + okay = true; + + if( okay ) + { + if( !item.Deleted ) + item.OnItemUsed( this, item ); + + if( !item.Deleted ) + item.OnDoubleClick( this ); + } + } + + public virtual void Use( Mobile m ) + { + if( m == null || m.Deleted || this.Deleted ) + return; + + DisruptiveAction(); + + if( m_Spell != null && !m_Spell.OnCasterUsingObject( m ) ) + return; + + if( !Utility.InUpdateRange( this, m ) ) + m.OnDoubleClickOutOfRange( this ); + else if( !CanSee( m ) ) + m.OnDoubleClickCantSee( this ); + else if( !CheckAlive( false ) ) + m.OnDoubleClickDead( this ); + else if( this.Region.OnDoubleClick( this, m ) && !m.Deleted ) + m.OnDoubleClick( this ); + } + + private static TimeSpan m_ActionDelay = TimeSpan.FromSeconds(0.5); + + public static TimeSpan ActionDelay + { + get { return m_ActionDelay; } + set { m_ActionDelay = value; } + } + + public virtual void Lift( Item item, int amount, out bool rejected, out LRReason reject ) + { + rejected = true; + reject = LRReason.Inspecific; + + if( item == null ) + return; + + Mobile from = this; + NetState state = m_NetState; + + if( from.AccessLevel >= AccessLevel.GameMaster || DateTime.Now >= from.NextActionTime ) + { + if( from.CheckAlive() ) + { + from.DisruptiveAction(); + + if( from.Holding != null ) + { + reject = LRReason.AreHolding; + } + else if( from.AccessLevel < AccessLevel.GameMaster && !from.InRange( item.GetWorldLocation(), 2 ) ) + { + reject = LRReason.OutOfRange; + } + else if( !from.CanSee( item ) || !from.InLOS( item ) ) + { + reject = LRReason.OutOfSight; + } + else if( !item.VerifyMove( from ) ) + { + reject = LRReason.CannotLift; + } + else if( !item.IsAccessibleTo( from ) ) + { + reject = LRReason.CannotLift; + } + else if (item.Nontransferable && amount != item.Amount) + { + if (item.QuestItem) + from.SendLocalizedMessage(1074868); // Stacks of quest items cannot be unstacked. + + reject = LRReason.CannotLift; + } + else if( !item.CheckLift( from, item, ref reject ) ) + { + } + else + { + object root = item.RootParent; + + if( root != null && root is Mobile && !((Mobile)root).CheckNonlocalLift( from, item ) ) + { + reject = LRReason.TryToSteal; + } + else if( !from.OnDragLift( item ) || !item.OnDragLift( from ) ) + { + reject = LRReason.Inspecific; + } + else if( !from.CheckAlive() ) + { + reject = LRReason.Inspecific; + } + else + { + item.SetLastMoved(); + + if( item.Spawner != null ) + { + item.Spawner.Remove( item ); + item.Spawner = null; + } + + if( amount == 0 ) + amount = 1; + + if( amount > item.Amount ) + amount = item.Amount; + + int oldAmount = item.Amount; + //item.Amount = amount; //Set in LiftItemDupe + + if( amount < oldAmount ) + LiftItemDupe( item, amount ); + //item.Dupe( oldAmount - amount ); + + Map map = from.Map; + + if( m_DragEffects && map != null && (root == null || root is Item) ) + { + IPooledEnumerable eable = map.GetClientsInRange( from.Location ); + Packet p = null; + + foreach( NetState ns in eable ) + { + if (ns.Mobile != from && ns.Mobile.CanSee(from) && ns.Mobile.InLOS(from) && ns.Mobile.CanSee(root)) + { + if( p == null ) + { + IEntity src; + + if( root == null ) + src = new Entity( Serial.Zero, item.Location, map ); + else + src = new Entity( ((Item)root).Serial, ((Item)root).Location, map ); + + p = Packet.Acquire( new DragEffect( src, from, item.ItemID, item.Hue, amount ) ); + } + + ns.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + + Point3D fixLoc = item.Location; + Map fixMap = item.Map; + bool shouldFix = (item.Parent == null); + + item.RecordBounce(); + item.OnItemLifted( from, item ); + item.Internalize(); + + from.Holding = item; + + int liftSound = item.GetLiftSound( from ); + + if( liftSound != -1 ) + from.Send( new PlaySound( liftSound, from ) ); + + from.NextActionTime = DateTime.Now + m_ActionDelay; + + if( fixMap != null && shouldFix ) + fixMap.FixColumn( fixLoc.m_X, fixLoc.m_Y ); + + reject = LRReason.Inspecific; + rejected = false; + } + } + } + else + { + reject = LRReason.Inspecific; + } + } + else + { + SendActionMessage(); + reject = LRReason.Inspecific; + } + + if( rejected && state != null ) + { + state.Send( new LiftRej( reject ) ); + + if (item.Deleted) + return; + + if( item.Parent is Item ) { + if ( state.ContainerGridLines ) + state.Send( new ContainerContentUpdate6017( item ) ); + else + state.Send( new ContainerContentUpdate( item ) ); + } else if( item.Parent is Mobile ) + state.Send( new EquipUpdate( item ) ); + else + item.SendInfoTo( state ); + + if( ObjectPropertyList.Enabled && item.Parent != null ) + state.Send( item.OPLPacket ); + } + } + + public static Item LiftItemDupe( Item oldItem, int amount ) + { + Item item; + try + { + item = (Item)Activator.CreateInstance( oldItem.GetType() ); + } + catch + { + Console.WriteLine( "Warning: 0x{0:X}: Item must have a zero paramater constructor to be separated from a stack. '{1}'.", oldItem.Serial.Value, oldItem.GetType().Name ); + return null; + } + item.Visible = oldItem.Visible; + item.Movable = oldItem.Movable; + item.LootType = oldItem.LootType; + item.Direction = oldItem.Direction; + item.Hue = oldItem.Hue; + item.ItemID = oldItem.ItemID; + item.Location = oldItem.Location; + item.Layer = oldItem.Layer; + item.Name = oldItem.Name; + item.Weight = oldItem.Weight; + + item.Amount = oldItem.Amount - amount; + item.Map = oldItem.Map; + + oldItem.Amount = amount; + oldItem.OnAfterDuped( item ); + + if( oldItem.Parent is Mobile ) + { + ((Mobile)oldItem.Parent).AddItem( item ); + } + else if( oldItem.Parent is Item ) + { + ((Item)oldItem.Parent).AddItem( item ); + } + + item.Delta( ItemDelta.Update ); + + return item; + } + + public virtual void SendDropEffect(Item item) + { + if (m_DragEffects && !item.Deleted) + { + Map map = m_Map; + object root = item.RootParent; + + if (map != null && (root == null || root is Item)) + { + IPooledEnumerable eable = map.GetClientsInRange(m_Location); + Packet p = null; + + bool sameLoc = false; + + foreach (NetState ns in eable) + { + if (ns.Mobile != this && ns.Mobile.CanSee(this) && ns.Mobile.InLOS(this) && ns.Mobile.CanSee(root)) + { + if (p == null) + { + IEntity trg; + + if (root == null) + trg = new Entity(Serial.Zero, item.Location, map); + else + trg = new Entity(((Item)root).Serial, ((Item)root).Location, map); + + if (m_Location == trg.Location) + sameLoc = true; + + p = Packet.Acquire(new DragEffect(this, trg, item.ItemID, item.Hue, item.Amount)); + } + + if (ns.StygianAbyss && sameLoc) + continue; // prevents crash + + ns.Send(p); + } + } + + Packet.Release(p); + + eable.Free(); + } + } + } + + public virtual bool Drop( Item to, Point3D loc ) + { + Mobile from = this; + Item item = from.Holding; + + bool valid = ( item != null && item.HeldBy == from && item.Map == Map.Internal ); + + from.Holding = null; + + if ( !valid ) { + return false; + } + + bool bounced = true; + + item.SetLastMoved(); + + if( to == null || !item.DropToItem( from, to, loc ) ) + item.Bounce( from ); + else + bounced = false; + + item.ClearBounce(); + + if( !bounced ) + SendDropEffect( item ); + + return !bounced; + } + + public virtual bool Drop( Point3D loc ) + { + Mobile from = this; + Item item = from.Holding; + + bool valid = ( item != null && item.HeldBy == from && item.Map == Map.Internal ); + + from.Holding = null; + + if ( !valid ) { + return false; + } + + bool bounced = true; + + item.SetLastMoved(); + + if( !item.DropToWorld( from, loc ) ) + item.Bounce( from ); + else + bounced = false; + + item.ClearBounce(); + + if( !bounced ) + SendDropEffect( item ); + + return !bounced; + } + + public virtual bool Drop( Mobile to, Point3D loc ) + { + Mobile from = this; + Item item = from.Holding; + + bool valid = ( item != null && item.HeldBy == from && item.Map == Map.Internal ); + + from.Holding = null; + + if ( !valid ) { + return false; + } + + bool bounced = true; + + item.SetLastMoved(); + + if( to == null || !item.DropToMobile( from, to, loc ) ) + item.Bounce( from ); + else + bounced = false; + + item.ClearBounce(); + + if( !bounced ) + SendDropEffect( item ); + + return !bounced; + } + + private static object m_GhostMutateContext = new object(); + + public virtual bool MutateSpeech( List hears, ref string text, ref object context ) + { + if( Alive ) + return false; + + StringBuilder sb = new StringBuilder( text.Length, text.Length ); + + for( int i = 0; i < text.Length; ++i ) + { + if( text[i] != ' ' ) + sb.Append( m_GhostChars[Utility.Random( m_GhostChars.Length )] ); + else + sb.Append( ' ' ); + } + + text = sb.ToString(); + context = m_GhostMutateContext; + return true; + } + + public virtual void Manifest( TimeSpan delay ) + { + Warmode = true; + + if( m_AutoManifestTimer == null ) + m_AutoManifestTimer = new AutoManifestTimer( this, delay ); + else + m_AutoManifestTimer.Stop(); + + m_AutoManifestTimer.Start(); + } + + public virtual bool CheckSpeechManifest() + { + if( Alive ) + return false; + + TimeSpan delay = m_AutoManifestTimeout; + + if( delay > TimeSpan.Zero && (!Warmode || m_AutoManifestTimer != null) ) + { + Manifest( delay ); + return true; + } + + return false; + } + + public virtual bool CheckHearsMutatedSpeech( Mobile m, object context ) + { + if( context == m_GhostMutateContext ) + return (m.Alive && !m.CanHearGhosts); + + return true; + } + + private void AddSpeechItemsFrom( ArrayList list, Container cont ) + { + for( int i = 0; i < cont.Items.Count; ++i ) + { + Item item = cont.Items[i]; + + if( item.HandlesOnSpeech ) + list.Add( item ); + + if( item is Container ) + AddSpeechItemsFrom( list, (Container)item ); + } + } + + private class LocationComparer : IComparer + { + private static LocationComparer m_Instance; + + public static LocationComparer GetInstance( IPoint3D relativeTo ) + { + if( m_Instance == null ) + m_Instance = new LocationComparer( relativeTo ); + else + m_Instance.m_RelativeTo = relativeTo; + + return m_Instance; + } + + private IPoint3D m_RelativeTo; + + public IPoint3D RelativeTo + { + get { return m_RelativeTo; } + set { m_RelativeTo = value; } + } + + public LocationComparer( IPoint3D relativeTo ) + { + m_RelativeTo = relativeTo; + } + + private int GetDistance( IPoint3D p ) + { + int x = m_RelativeTo.X - p.X; + int y = m_RelativeTo.Y - p.Y; + int z = m_RelativeTo.Z - p.Z; + + x *= 11; + y *= 11; + + return (x * x) + (y * y) + (z * z); + } + + public int Compare( object x, object y ) + { + IPoint3D a = x as IPoint3D; + IPoint3D b = y as IPoint3D; + + return GetDistance( a ) - GetDistance( b ); + } + } + + #region Get*InRange + + public IPooledEnumerable GetItemsInRange( int range ) + { + Map map = m_Map; + + if( map == null ) + return Server.Map.NullEnumerable.Instance; + + return map.GetItemsInRange( m_Location, range ); + } + + public IPooledEnumerable GetObjectsInRange( int range ) + { + Map map = m_Map; + + if( map == null ) + return Server.Map.NullEnumerable.Instance; + + return map.GetObjectsInRange( m_Location, range ); + } + + public IPooledEnumerable GetMobilesInRange( int range ) + { + Map map = m_Map; + + if( map == null ) + return Server.Map.NullEnumerable.Instance; + + return map.GetMobilesInRange( m_Location, range ); + } + + public IPooledEnumerable GetClientsInRange( int range ) + { + Map map = m_Map; + + if( map == null ) + return Server.Map.NullEnumerable.Instance; + + return map.GetClientsInRange( m_Location, range ); + } + + #endregion + + private static List m_Hears; + private static ArrayList m_OnSpeech; + + public virtual void DoSpeech( string text, int[] keywords, MessageType type, int hue ) + { + if( m_Deleted || CommandSystem.Handle( this, text, type ) ) + return; + + int range = 15; + + switch( type ) + { + case MessageType.Regular: + m_SpeechHue = hue; + break; + case MessageType.Emote: + m_EmoteHue = hue; + break; + case MessageType.Whisper: + m_WhisperHue = hue; + range = 1; + break; + case MessageType.Yell: + m_YellHue = hue; + range = 18; + break; + default: + type = MessageType.Regular; + break; + } + + SpeechEventArgs regArgs = new SpeechEventArgs( this, text, type, hue, keywords ); + + EventSink.InvokeSpeech( regArgs ); + this.Region.OnSpeech( regArgs ); + OnSaid( regArgs ); + + if( regArgs.Blocked ) + return; + + text = regArgs.Speech; + + if( string.IsNullOrEmpty( text ) ) + return; + + if( m_Hears == null ) + m_Hears = new List(); + else if( m_Hears.Count > 0 ) + m_Hears.Clear(); + + if( m_OnSpeech == null ) + m_OnSpeech = new ArrayList(); + else if( m_OnSpeech.Count > 0 ) + m_OnSpeech.Clear(); + + List hears = m_Hears; + ArrayList onSpeech = m_OnSpeech; + + if( m_Map != null ) + { + IPooledEnumerable eable = m_Map.GetObjectsInRange( m_Location, range ); + + foreach( object o in eable ) + { + if( o is Mobile ) + { + Mobile heard = (Mobile)o; + + if( heard.CanSee( this ) && (m_NoSpeechLOS || !heard.Player || heard.InLOS( this )) ) + { + if( heard.m_NetState != null ) + hears.Add( heard ); + + if( heard.HandlesOnSpeech( this ) ) + onSpeech.Add( heard ); + + for( int i = 0; i < heard.Items.Count; ++i ) + { + Item item = heard.Items[i]; + + if( item.HandlesOnSpeech ) + onSpeech.Add( item ); + + if( item is Container ) + AddSpeechItemsFrom( onSpeech, (Container)item ); + } + } + } + else if( o is Item ) + { + if( ((Item)o).HandlesOnSpeech ) + onSpeech.Add( o ); + + if( o is Container ) + AddSpeechItemsFrom( onSpeech, (Container)o ); + } + } + + //eable.Free(); + + object mutateContext = null; + string mutatedText = text; + SpeechEventArgs mutatedArgs = null; + + if( MutateSpeech( hears, ref mutatedText, ref mutateContext ) ) + mutatedArgs = new SpeechEventArgs( this, mutatedText, type, hue, new int[0] ); + + CheckSpeechManifest(); + + ProcessDelta(); + + Packet regp = null; + Packet mutp = null; + + for( int i = 0; i < hears.Count; ++i ) + { + Mobile heard = hears[i]; + + if( mutatedArgs == null || !CheckHearsMutatedSpeech( heard, mutateContext ) ) + { + heard.OnSpeech( regArgs ); + + NetState ns = heard.NetState; + + if( ns != null ) + { + if( regp == null ) + regp = Packet.Acquire( new UnicodeMessage( m_Serial, Body, type, hue, 3, m_Language, Name, text ) ); + + ns.Send( regp ); + } + } + else + { + heard.OnSpeech( mutatedArgs ); + + NetState ns = heard.NetState; + + if( ns != null ) + { + if( mutp == null ) + mutp = Packet.Acquire( new UnicodeMessage( m_Serial, Body, type, hue, 3, m_Language, Name, mutatedText ) ); + + ns.Send( mutp ); + } + } + } + + Packet.Release( regp ); + Packet.Release( mutp ); + + if( onSpeech.Count > 1 ) + onSpeech.Sort( LocationComparer.GetInstance( this ) ); + + for( int i = 0; i < onSpeech.Count; ++i ) + { + object obj = onSpeech[i]; + + if( obj is Mobile ) + { + Mobile heard = (Mobile)obj; + + if( mutatedArgs == null || !CheckHearsMutatedSpeech( heard, mutateContext ) ) + heard.OnSpeech( regArgs ); + else + heard.OnSpeech( mutatedArgs ); + } + else + { + Item item = (Item)obj; + + item.OnSpeech( regArgs ); + } + } + } + } + + private static VisibleDamageType m_VisibleDamageType; + + public static VisibleDamageType VisibleDamageType + { + get { return m_VisibleDamageType; } + set { m_VisibleDamageType = value; } + } + + private List m_DamageEntries; + + public List DamageEntries + { + get { return m_DamageEntries; } + } + + public static Mobile GetDamagerFrom( DamageEntry de ) + { + return (de == null ? null : de.Damager); + } + + public Mobile FindMostRecentDamager( bool allowSelf ) + { + return GetDamagerFrom( FindMostRecentDamageEntry( allowSelf ) ); + } + + public DamageEntry FindMostRecentDamageEntry( bool allowSelf ) + { + for( int i = m_DamageEntries.Count - 1; i >= 0; --i ) + { + if( i >= m_DamageEntries.Count ) + continue; + + DamageEntry de = m_DamageEntries[i]; + + if( de.HasExpired ) + m_DamageEntries.RemoveAt( i ); + else if( allowSelf || de.Damager != this ) + return de; + } + + return null; + } + + public Mobile FindLeastRecentDamager( bool allowSelf ) + { + return GetDamagerFrom( FindLeastRecentDamageEntry( allowSelf ) ); + } + + public DamageEntry FindLeastRecentDamageEntry( bool allowSelf ) + { + for( int i = 0; i < m_DamageEntries.Count; ++i ) + { + if( i < 0 ) + continue; + + DamageEntry de = m_DamageEntries[i]; + + if( de.HasExpired ) + { + m_DamageEntries.RemoveAt( i ); + --i; + } + else if( allowSelf || de.Damager != this ) + { + return de; + } + } + + return null; + } + + public Mobile FindMostTotalDamger( bool allowSelf ) + { + return GetDamagerFrom( FindMostTotalDamageEntry( allowSelf ) ); + } + + public DamageEntry FindMostTotalDamageEntry( bool allowSelf ) + { + DamageEntry mostTotal = null; + + for( int i = m_DamageEntries.Count - 1; i >= 0; --i ) + { + if( i >= m_DamageEntries.Count ) + continue; + + DamageEntry de = m_DamageEntries[i]; + + if( de.HasExpired ) + m_DamageEntries.RemoveAt( i ); + else if( (allowSelf || de.Damager != this) && (mostTotal == null || de.DamageGiven > mostTotal.DamageGiven) ) + mostTotal = de; + } + + return mostTotal; + } + + public Mobile FindLeastTotalDamger( bool allowSelf ) + { + return GetDamagerFrom( FindLeastTotalDamageEntry( allowSelf ) ); + } + + public DamageEntry FindLeastTotalDamageEntry( bool allowSelf ) + { + DamageEntry mostTotal = null; + + for( int i = m_DamageEntries.Count - 1; i >= 0; --i ) + { + if( i >= m_DamageEntries.Count ) + continue; + + DamageEntry de = m_DamageEntries[i]; + + if( de.HasExpired ) + m_DamageEntries.RemoveAt( i ); + else if( (allowSelf || de.Damager != this) && (mostTotal == null || de.DamageGiven < mostTotal.DamageGiven) ) + mostTotal = de; + } + + return mostTotal; + } + + public DamageEntry FindDamageEntryFor( Mobile m ) + { + for( int i = m_DamageEntries.Count - 1; i >= 0; --i ) + { + if( i >= m_DamageEntries.Count ) + continue; + + DamageEntry de = m_DamageEntries[i]; + + if( de.HasExpired ) + m_DamageEntries.RemoveAt( i ); + else if( de.Damager == m ) + return de; + } + + return null; + } + + public virtual Mobile GetDamageMaster( Mobile damagee ) + { + return null; + } + + public virtual DamageEntry RegisterDamage( int amount, Mobile from ) + { + DamageEntry de = FindDamageEntryFor( from ); + + if( de == null ) + de = new DamageEntry( from ); + + de.DamageGiven += amount; + de.LastDamage = DateTime.Now; + + m_DamageEntries.Remove( de ); + m_DamageEntries.Add( de ); + + Mobile master = from.GetDamageMaster( this ); + + if( master != null ) + { + List list = de.Responsible; + + if( list == null ) + de.Responsible = list = new List(); + + DamageEntry resp = null; + + for( int i = 0; i < list.Count; ++i ) + { + DamageEntry check = list[i]; + + if( check.Damager == master ) + { + resp = check; + break; + } + } + + if( resp == null ) + list.Add( resp = new DamageEntry( master ) ); + + resp.DamageGiven += amount; + resp.LastDamage = DateTime.Now; + } + + return de; + } + + private Mobile m_LastKiller; + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile LastKiller + { + get { return m_LastKiller; } + set { m_LastKiller = value; } + } + + /// + /// Overridable. Virtual event invoked when the Mobile is damaged. It is called before hit points are lowered or the Mobile is killed. + /// + /// + /// + /// + public virtual void OnDamage( int amount, Mobile from, bool willKill ) + { + } + + public virtual void Damage( int amount ) + { + Damage( amount, null ); + } + + public virtual bool CanBeDamaged() + { + return !m_Blessed; + } + + public virtual void Damage( int amount, Mobile from ) + { + Damage( amount, from, true ); + } + + public virtual void Damage( int amount, Mobile from, bool informMount ) + { + if( !CanBeDamaged() || m_Deleted ) + return; + + if( !this.Region.OnDamage( this, ref amount ) ) + return; + + if( amount > 0 ) + { + int oldHits = Hits; + int newHits = oldHits - amount; + + if( m_Spell != null ) + m_Spell.OnCasterHurt(); + + //if ( m_Spell != null && m_Spell.State == SpellState.Casting ) + // m_Spell.Disturb( DisturbType.Hurt, false, true ); + + if( from != null ) + RegisterDamage( amount, from ); + + DisruptiveAction(); + + Paralyzed = false; + + switch( m_VisibleDamageType ) + { + case VisibleDamageType.Related: + { + NetState ourState = m_NetState, theirState = (from == null ? null : from.m_NetState); + + if( ourState == null ) + { + Mobile master = GetDamageMaster( from ); + + if( master != null ) + ourState = master.m_NetState; + } + + if( theirState == null && from != null ) + { + Mobile master = from.GetDamageMaster( this ); + + if( master != null ) + theirState = master.m_NetState; + } + + if( amount > 0 && (ourState != null || theirState != null) ) + { + Packet p = null;// = new DamagePacket( this, amount ); + + if( ourState != null ) + { + if( ourState.DamagePacket ) + p = Packet.Acquire( new DamagePacket( this, amount ) ); + else + p = Packet.Acquire( new DamagePacketOld( this, amount ) ); + + ourState.Send( p ); + } + + if( theirState != null && theirState != ourState ) + { + bool newPacket = theirState.DamagePacket; + + if( newPacket && (p == null || !(p is DamagePacket)) ) + { + Packet.Release( p ); + p = Packet.Acquire( new DamagePacket( this, amount ) ); + } + else if( !newPacket && (p == null || !(p is DamagePacketOld)) ) + { + Packet.Release( p ); + p = Packet.Acquire( new DamagePacketOld( this, amount ) ); + } + + theirState.Send( p ); + } + + Packet.Release( p ); + } + + break; + } + case VisibleDamageType.Everyone: + { + SendDamageToAll( amount ); + break; + } + } + + OnDamage( amount, from, newHits < 0 ); + + IMount m = this.Mount; + if( m != null && informMount ) + m.OnRiderDamaged( amount, from, newHits < 0 ); + + if( newHits < 0 ) + { + m_LastKiller = from; + + Hits = 0; + + if( oldHits >= 0 ) + Kill(); + } + else + { + Hits = newHits; + } + } + } + + public virtual void SendDamageToAll( int amount ) + { + if( amount < 0 ) + return; + + Map map = m_Map; + + if( map == null ) + return; + + IPooledEnumerable eable = map.GetClientsInRange( m_Location ); + + Packet pNew = null; + Packet pOld = null; + + foreach( NetState ns in eable ) + { + if( ns.Mobile.CanSee( this ) ) + { + Packet p; + + if( ns.DamagePacket ) + { + if( pNew == null ) + pNew = Packet.Acquire( new DamagePacket( this, amount ) ); + + p = pNew; + } + else + { + if( pOld == null ) + pOld = Packet.Acquire( new DamagePacketOld( this, amount ) ); + + p = pOld; + } + + ns.Send( p ); + } + } + + Packet.Release( pNew ); + Packet.Release( pOld ); + + eable.Free(); + } + + public void Heal( int amount ) + { + Heal( amount, this, true ); + } + + public void Heal( int amount, Mobile from ) + { + Heal( amount, from, true ); + } + + public void Heal( int amount, Mobile from, bool message ) + { + if( !Alive || IsDeadBondedPet ) + return; + + if( !Region.OnHeal( this, ref amount ) ) + return; + + OnHeal( ref amount, from ); + + if( (Hits + amount) > HitsMax ) + { + amount = HitsMax - Hits; + } + + Hits += amount; + + if( message && amount > 0 && m_NetState != null ) + m_NetState.Send( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Label, 0x3B2, 3, 1008158, "", AffixType.Append | AffixType.System, amount.ToString(), "" ) ); + } + + public virtual void OnHeal( ref int amount, Mobile from ) + { + } + + public void UsedStuckMenu() + { + if( m_StuckMenuUses == null ) + { + m_StuckMenuUses = new DateTime[2]; + } + + for( int i = 0; i < m_StuckMenuUses.Length; ++i ) + { + if( (DateTime.Now - m_StuckMenuUses[i]) > TimeSpan.FromDays( 1.0 ) ) + { + m_StuckMenuUses[i] = DateTime.Now; + return; + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Squelched + { + get + { + return m_Squelched; + } + set + { + m_Squelched = value; + } + } + + public virtual void Deserialize( GenericReader reader ) + { + int version = reader.ReadInt(); + + switch( version ) + { + // Scriptiz : le compteur du nombre de morts + case 33: + { + m_Deaths = reader.ReadInt(); + goto case 32; + } + // Scriptiz : pour l'apparence elfique + case 32: + { + m_IsElfBody = reader.ReadBool(); + goto case 31; + } + case 31: + { + m_LastStrGain = reader.ReadDeltaTime(); + m_LastIntGain = reader.ReadDeltaTime(); + m_LastDexGain = reader.ReadDeltaTime(); + + goto case 30; + } + case 30: + { + byte hairflag = reader.ReadByte(); + + if( (hairflag & 0x01) != 0 ) + m_Hair = new HairInfo( reader ); + if( (hairflag & 0x02) != 0 ) + m_FacialHair = new FacialHairInfo( reader ); + + goto case 29; + } + case 29: + { + m_Race = reader.ReadRace(); + goto case 28; + } + case 28: + { + if( version <= 30 ) + LastStatGain = reader.ReadDeltaTime(); + + goto case 27; + } + case 27: + { + m_TithingPoints = reader.ReadInt(); + + goto case 26; + } + case 26: + case 25: + case 24: + { + m_Corpse = reader.ReadItem() as Container; + + goto case 23; + } + case 23: + { + m_CreationTime = reader.ReadDateTime(); + + goto case 22; + } + case 22: // Just removed followers + case 21: + { + m_Stabled = reader.ReadStrongMobileList(); + + goto case 20; + } + case 20: + { + m_CantWalk = reader.ReadBool(); + + goto case 19; + } + case 19: // Just removed variables + case 18: + { + m_Virtues = new VirtueInfo( reader ); + + goto case 17; + } + case 17: + { + m_Thirst = reader.ReadInt(); + m_BAC = reader.ReadInt(); + + goto case 16; + } + case 16: + { + m_ShortTermMurders = reader.ReadInt(); + + if( version <= 24 ) + { + reader.ReadDateTime(); + reader.ReadDateTime(); + } + + goto case 15; + } + case 15: + { + if( version < 22 ) + reader.ReadInt(); // followers + + m_FollowersMax = reader.ReadInt(); + + goto case 14; + } + case 14: + { + m_MagicDamageAbsorb = reader.ReadInt(); + + goto case 13; + } + case 13: + { + m_GuildFealty = reader.ReadMobile(); + + goto case 12; + } + case 12: + { + m_Guild = reader.ReadGuild(); + + goto case 11; + } + case 11: + { + m_DisplayGuildTitle = reader.ReadBool(); + + goto case 10; + } + case 10: + { + m_CanSwim = reader.ReadBool(); + + goto case 9; + } + case 9: + { + m_Squelched = reader.ReadBool(); + + goto case 8; + } + case 8: + { + m_Holding = reader.ReadItem(); + + goto case 7; + } + case 7: + { + m_VirtualArmor = reader.ReadInt(); + + goto case 6; + } + case 6: + { + m_BaseSoundID = reader.ReadInt(); + + goto case 5; + } + case 5: + { + m_DisarmReady = reader.ReadBool(); + m_StunReady = reader.ReadBool(); + + goto case 4; + } + case 4: + { + if( version <= 25 ) + { + Poison.Deserialize( reader ); + } + + goto case 3; + } + case 3: + { + m_StatCap = reader.ReadInt(); + + goto case 2; + } + case 2: + { + m_NameHue = reader.ReadInt(); + + goto case 1; + } + case 1: + { + m_Hunger = reader.ReadInt(); + + goto case 0; + } + case 0: + { + if( version < 21 ) + m_Stabled = new List(); + + if( version < 18 ) + m_Virtues = new VirtueInfo(); + + if( version < 11 ) + m_DisplayGuildTitle = true; + + if( version < 3 ) + m_StatCap = 225; + + if( version < 15 ) + { + m_Followers = 0; + m_FollowersMax = 5; + } + + m_Location = reader.ReadPoint3D(); + m_Body = new Body( reader.ReadInt() ); + m_Name = reader.ReadString(); + m_GuildTitle = reader.ReadString(); + m_Criminal = reader.ReadBool(); + m_Kills = reader.ReadInt(); + m_SpeechHue = reader.ReadInt(); + m_EmoteHue = reader.ReadInt(); + m_WhisperHue = reader.ReadInt(); + m_YellHue = reader.ReadInt(); + m_Language = reader.ReadString(); + m_Female = reader.ReadBool(); + m_Warmode = reader.ReadBool(); + m_Hidden = reader.ReadBool(); + m_Direction = (Direction)reader.ReadByte(); + m_Hue = reader.ReadInt(); + m_Str = reader.ReadInt(); + m_Dex = reader.ReadInt(); + m_Int = reader.ReadInt(); + m_Hits = reader.ReadInt(); + m_Stam = reader.ReadInt(); + m_Mana = reader.ReadInt(); + m_Map = reader.ReadMap(); + m_Blessed = reader.ReadBool(); + m_Fame = reader.ReadInt(); + m_Karma = reader.ReadInt(); + m_AccessLevel = (AccessLevel)reader.ReadByte(); + + m_Skills = new Skills( this, reader ); + + m_Items = reader.ReadStrongItemList(); + + m_Player = reader.ReadBool(); + m_Title = reader.ReadString(); + m_Profile = reader.ReadString(); + m_ProfileLocked = reader.ReadBool(); + + if( version <= 18 ) + { + reader.ReadInt(); + reader.ReadInt(); + reader.ReadInt(); + } + + m_AutoPageNotify = reader.ReadBool(); + + m_LogoutLocation = reader.ReadPoint3D(); + m_LogoutMap = reader.ReadMap(); + + m_StrLock = (StatLockType)reader.ReadByte(); + m_DexLock = (StatLockType)reader.ReadByte(); + m_IntLock = (StatLockType)reader.ReadByte(); + + m_StatMods = new List(); + m_SkillMods = new List(); + + if( reader.ReadBool() ) + { + m_StuckMenuUses = new DateTime[reader.ReadInt()]; + + for( int i = 0; i < m_StuckMenuUses.Length; ++i ) + { + m_StuckMenuUses[i] = reader.ReadDateTime(); + } + } + else + { + m_StuckMenuUses = null; + } + + if( m_Player && m_Map != Map.Internal ) + { + m_LogoutLocation = m_Location; + m_LogoutMap = m_Map; + + m_Map = Map.Internal; + } + + if( m_Map != null ) + m_Map.OnEnter( this ); + + if( m_Criminal ) + { + if( m_ExpireCriminal == null ) + m_ExpireCriminal = new ExpireCriminalTimer( this ); + + m_ExpireCriminal.Start(); + } + + if( ShouldCheckStatTimers ) + CheckStatTimers(); + + if( !m_Player && m_Dex <= 100 && m_CombatTimer != null ) + m_CombatTimer.Priority = TimerPriority.FiftyMS; + else if( m_CombatTimer != null ) + m_CombatTimer.Priority = TimerPriority.EveryTick; + + UpdateRegion(); + + UpdateResistances(); + + break; + } + } + + if( !m_Player ) + Utility.Intern( ref m_Name ); + + Utility.Intern( ref m_Title ); + Utility.Intern( ref m_Language ); + + /* //Moved into cleanup in scripts. + if( version < 30 ) + Timer.DelayCall( TimeSpan.Zero, new TimerCallback( ConvertHair ) ); + * */ + + } + + public void ConvertHair() + { + Item hair; + + if( (hair = FindItemOnLayer( Layer.Hair )) != null ) + { + HairItemID = hair.ItemID; + HairHue = hair.Hue; + hair.Delete(); + } + + if( (hair = FindItemOnLayer( Layer.FacialHair )) != null ) + { + FacialHairItemID = hair.ItemID; + FacialHairHue = hair.Hue; + hair.Delete(); + } + } + + public virtual bool ShouldCheckStatTimers { get { return true; } } + + public virtual void CheckStatTimers() + { + if( m_Deleted ) + return; + + if( Hits < HitsMax ) + { + if( CanRegenHits ) + { + if( m_HitsTimer == null ) + m_HitsTimer = new HitsTimer( this ); + + m_HitsTimer.Start(); + } + else if( m_HitsTimer != null ) + { + m_HitsTimer.Stop(); + } + } + else + { + Hits = HitsMax; + } + + if( Stam < StamMax ) + { + if( CanRegenStam ) + { + if( m_StamTimer == null ) + m_StamTimer = new StamTimer( this ); + + m_StamTimer.Start(); + } + else if( m_StamTimer != null ) + { + m_StamTimer.Stop(); + } + } + else + { + Stam = StamMax; + } + + if( Mana < ManaMax ) + { + if( CanRegenMana ) + { + if( m_ManaTimer == null ) + m_ManaTimer = new ManaTimer( this ); + + m_ManaTimer.Start(); + } + else if( m_ManaTimer != null ) + { + m_ManaTimer.Stop(); + } + } + else + { + Mana = ManaMax; + } + } + + private DateTime m_CreationTime; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime CreationTime + { + get + { + return m_CreationTime; + } + } + + int ISerializable.TypeReference + { + get { return m_TypeRef; } + } + + int ISerializable.SerialIdentity + { + get { return m_Serial; } + } + + public virtual void Serialize( GenericWriter writer ) + { + writer.Write( (int)33 ); // version + + // Scriptiz [v.33] : on comptabilise le nombre de morts + writer.Write((int)m_Deaths); + + // Scriptiz [v.32] : pour savoir si le joueur poss�de un corps d'elfe + writer.Write((bool)m_IsElfBody); + + writer.WriteDeltaTime( m_LastStrGain ); + writer.WriteDeltaTime( m_LastIntGain ); + writer.WriteDeltaTime( m_LastDexGain ); + + byte hairflag = 0x00; + + if( m_Hair != null ) + hairflag |= 0x01; + if( m_FacialHair != null ) + hairflag |= 0x02; + + writer.Write( (byte)hairflag ); + + if( (hairflag & 0x01) != 0 ) + m_Hair.Serialize( writer ); + if( (hairflag & 0x02) != 0 ) + m_FacialHair.Serialize( writer ); + + writer.Write( this.Race ); + + writer.Write( (int)m_TithingPoints ); + + writer.Write( m_Corpse ); + + writer.Write( m_CreationTime ); + + writer.Write( m_Stabled, true ); + + writer.Write( m_CantWalk ); + + VirtueInfo.Serialize( writer, m_Virtues ); + + writer.Write( m_Thirst ); + writer.Write( m_BAC ); + + writer.Write( m_ShortTermMurders ); + //writer.Write( m_ShortTermElapse ); + //writer.Write( m_LongTermElapse ); + + //writer.Write( m_Followers ); + writer.Write( m_FollowersMax ); + + writer.Write( m_MagicDamageAbsorb ); + + writer.Write( m_GuildFealty ); + + writer.Write( m_Guild ); + + writer.Write( m_DisplayGuildTitle ); + + writer.Write( m_CanSwim ); + + writer.Write( m_Squelched ); + + writer.Write( m_Holding ); + + writer.Write( m_VirtualArmor ); + + writer.Write( m_BaseSoundID ); + + writer.Write( m_DisarmReady ); + writer.Write( m_StunReady ); + + //Poison.Serialize( m_Poison, writer ); + + writer.Write( m_StatCap ); + + writer.Write( m_NameHue ); + + writer.Write( m_Hunger ); + + writer.Write( m_Location ); + writer.Write( (int)m_Body ); + writer.Write( m_Name ); + writer.Write( m_GuildTitle ); + writer.Write( m_Criminal ); + writer.Write( m_Kills ); + writer.Write( m_SpeechHue ); + writer.Write( m_EmoteHue ); + writer.Write( m_WhisperHue ); + writer.Write( m_YellHue ); + writer.Write( m_Language ); + writer.Write( m_Female ); + writer.Write( m_Warmode ); + writer.Write( m_Hidden ); + writer.Write( (byte)m_Direction ); + writer.Write( m_Hue ); + writer.Write( m_Str ); + writer.Write( m_Dex ); + writer.Write( m_Int ); + writer.Write( m_Hits ); + writer.Write( m_Stam ); + writer.Write( m_Mana ); + + writer.Write( m_Map ); + + writer.Write( m_Blessed ); + writer.Write( m_Fame ); + writer.Write( m_Karma ); + writer.Write( (byte)m_AccessLevel ); + m_Skills.Serialize( writer ); + + writer.Write( m_Items ); + + writer.Write( m_Player ); + writer.Write( m_Title ); + writer.Write( m_Profile ); + writer.Write( m_ProfileLocked ); + writer.Write( m_AutoPageNotify ); + + writer.Write( m_LogoutLocation ); + writer.Write( m_LogoutMap ); + + writer.Write( (byte)m_StrLock ); + writer.Write( (byte)m_DexLock ); + writer.Write( (byte)m_IntLock ); + + if( m_StuckMenuUses != null ) + { + writer.Write( true ); + + writer.Write( m_StuckMenuUses.Length ); + + for( int i = 0; i < m_StuckMenuUses.Length; ++i ) + { + writer.Write( m_StuckMenuUses[i] ); + } + } + else + { + writer.Write( false ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int LightLevel + { + get + { + return m_LightLevel; + } + set + { + if( m_LightLevel != value ) + { + m_LightLevel = value; + + CheckLightLevels( false ); + + /*if ( m_NetState != null ) + m_NetState.Send( new PersonalLightLevel( this ) );*/ + } + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public string Profile + { + get + { + return m_Profile; + } + set + { + m_Profile = value; + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public bool ProfileLocked + { + get + { + return m_ProfileLocked; + } + set + { + m_ProfileLocked = value; + } + } + + [CommandProperty( AccessLevel.GameMaster, AccessLevel.Administrator )] + public bool Player + { + get + { + return m_Player; + } + set + { + m_Player = value; + InvalidateProperties(); + + if( !m_Player && m_Dex <= 100 && m_CombatTimer != null ) + m_CombatTimer.Priority = TimerPriority.FiftyMS; + else if( m_CombatTimer != null ) + m_CombatTimer.Priority = TimerPriority.EveryTick; + + CheckStatTimers(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Title + { + get + { + return m_Title; + } + set + { + m_Title = value; + InvalidateProperties(); + } + } + + private static string[] m_AccessLevelNames = new string[] + { + "a player", + "a counselor", + "a game master", + "a seer", + "an administrator", + "a developer", + "an owner" + }; + + public static string GetAccessLevelName( AccessLevel level ) + { + return m_AccessLevelNames[(int)level]; + } + + public virtual bool CanPaperdollBeOpenedBy( Mobile from ) + { + return (Body.IsHuman || Body.IsGhost || IsBodyMod ||Body.BodyID == 1253); + } + + public virtual void GetChildContextMenuEntries( Mobile from, List list, Item item ) + { + } + + public virtual void GetContextMenuEntries( Mobile from, List list ) + { + if( m_Deleted ) + return; + + if( CanPaperdollBeOpenedBy( from ) ) + list.Add( new PaperdollEntry( this ) ); + + if( from == this && Backpack != null && CanSee( Backpack ) && CheckAlive( false ) ) + list.Add( new OpenBackpackEntry( this ) ); + } + + public void Internalize() + { + Map = Map.Internal; + } + + public List Items + { + get + { + return m_Items; + } + } + + /// + /// Overridable. Virtual event invoked when is added from the Mobile, such as when it is equiped. + /// + /// + /// + public virtual void OnItemAdded( Item item ) + { + } + + /// + /// Overridable. Virtual event invoked when is removed from the Mobile. + /// + /// + /// + public virtual void OnItemRemoved( Item item ) + { + } + + /// + /// Overridable. Virtual event invoked when is becomes a child of the Mobile; it's worn or contained at some level of the Mobile's backpack or bank box + /// + /// + /// + public virtual void OnSubItemAdded( Item item ) + { + } + + /// + /// Overridable. Virtual event invoked when is removed from the Mobile, its backpack, or its bank box. + /// + /// + /// + public virtual void OnSubItemRemoved( Item item ) + { + } + + public virtual void OnItemBounceCleared( Item item ) + { + } + + public virtual void OnSubItemBounceCleared( Item item ) + { + } + + public virtual int MaxWeight { get { return int.MaxValue; } } + + public void AddItem( Item item ) + { + if( item == null || item.Deleted ) + return; + + if( item.Parent == this ) + return; + else if( item.Parent is Mobile ) + ((Mobile)item.Parent).RemoveItem( item ); + else if( item.Parent is Item ) + ((Item)item.Parent).RemoveItem( item ); + else + item.SendRemovePacket(); + + item.Parent = this; + item.Map = m_Map; + + m_Items.Add( item ); + + if( !item.IsVirtualItem ) + { + UpdateTotal( item, TotalType.Gold, item.TotalGold ); + UpdateTotal( item, TotalType.Items, item.TotalItems + 1 ); + UpdateTotal( item, TotalType.Weight, item.TotalWeight + item.PileWeight ); + } + + item.Delta( ItemDelta.Update ); + + item.OnAdded( this ); + OnItemAdded( item ); + + if( item.PhysicalResistance != 0 || item.FireResistance != 0 || item.ColdResistance != 0 || + item.PoisonResistance != 0 || item.EnergyResistance != 0 ) + UpdateResistances(); + } + + private static IWeapon m_DefaultWeapon; + + public static IWeapon DefaultWeapon + { + get + { + return m_DefaultWeapon; + } + set + { + m_DefaultWeapon = value; + } + } + + public void RemoveItem( Item item ) + { + if( item == null || m_Items == null ) + return; + + if( m_Items.Contains( item ) ) + { + item.SendRemovePacket(); + + //int oldCount = m_Items.Count; + + m_Items.Remove( item ); + + if( !item.IsVirtualItem ) + { + UpdateTotal( item, TotalType.Gold, -item.TotalGold ); + UpdateTotal( item, TotalType.Items, -(item.TotalItems + 1) ); + UpdateTotal( item, TotalType.Weight, -(item.TotalWeight + item.PileWeight) ); + } + + item.Parent = null; + + item.OnRemoved( this ); + OnItemRemoved( item ); + + if( item.PhysicalResistance != 0 || item.FireResistance != 0 || item.ColdResistance != 0 || + item.PoisonResistance != 0 || item.EnergyResistance != 0 ) + UpdateResistances(); + } + } + + public virtual void Animate( int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay ) + { + Map map = m_Map; + + if( map != null ) + { + ProcessDelta(); + + Packet p = null; + //Packet pNew = null; + + IPooledEnumerable eable = map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state.Mobile.CanSee( this ) ) + { + state.Mobile.ProcessDelta(); + + //if ( state.StygianAbyss ) { + //if( pNew == null ) + //pNew = Packet.Acquire( new NewMobileAnimation( this, action, frameCount, delay ) ); + + //state.Send( pNew ); + //} else { + if( p == null ) + p = Packet.Acquire( new MobileAnimation( this, action, frameCount, repeatCount, forward, repeat, delay ) ); + + state.Send( p ); + //} + } + } + + Packet.Release( p ); + //Packet.Release( pNew ); + + eable.Free(); + } + } + + public void SendSound( int soundID ) + { + if( soundID != -1 && m_NetState != null ) + Send( new PlaySound( soundID, this ) ); + } + + public void SendSound( int soundID, IPoint3D p ) + { + if( soundID != -1 && m_NetState != null ) + Send( new PlaySound( soundID, p ) ); + } + + public void PlaySound( int soundID ) + { + if( soundID == -1 ) + return; + + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state.Mobile.CanSee( this ) ) + { + if( p == null ) + p = Packet.Acquire( new PlaySound( soundID, this ) ); + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + [CommandProperty( AccessLevel.Counselor )] + public Skills Skills + { + get + { + return m_Skills; + } + set + { + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.Administrator )] + public AccessLevel AccessLevel + { + get + { + return m_AccessLevel; + } + set + { + AccessLevel oldValue = m_AccessLevel; + + if( oldValue != value ) + { + m_AccessLevel = value; + Delta( MobileDelta.Noto ); + InvalidateProperties(); + + SendMessage( "Your access level has been changed. You are now {0}.", GetAccessLevelName( value ) ); + + ClearScreen(); + SendEverything(); + + OnAccessLevelChanged( oldValue ); + } + } + } + + public virtual void OnAccessLevelChanged( AccessLevel oldLevel ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Fame + { + get + { + return m_Fame; + } + set + { + int oldValue = m_Fame; + + if( oldValue != value ) + { + m_Fame = value; + + if( ShowFameTitle && (m_Player || m_Body.IsHuman) && (oldValue >= 10000) != (value >= 10000) ) + InvalidateProperties(); + + OnFameChange( oldValue ); + } + } + } + + public virtual void OnFameChange( int oldValue ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public int Karma + { + get + { + return m_Karma; + } + set + { + int old = m_Karma; + + if( old != value ) + { + m_Karma = value; + OnKarmaChange( old ); + } + } + } + + public virtual void OnKarmaChange( int oldValue ) + { + } + + // Mobile did something which should unhide him + public virtual void RevealingAction() + { + if( m_Hidden && m_AccessLevel == AccessLevel.Player ) + Hidden = false; + + DisruptiveAction(); // Anything that unhides you will also distrupt meditation + } + + #region Say/SayTo/Emote/Whisper/Yell + public void SayTo( Mobile to, bool ascii, string text ) + { + PrivateOverheadMessage( MessageType.Regular, m_SpeechHue, ascii, text, to.NetState ); + } + + public void SayTo( Mobile to, string text ) + { + SayTo( to, false, text ); + } + + public void SayTo( Mobile to, string format, params object[] args ) + { + SayTo( to, false, String.Format( format, args ) ); + } + + public void SayTo( Mobile to, bool ascii, string format, params object[] args ) + { + SayTo( to, ascii, String.Format( format, args ) ); + } + + public void SayTo( Mobile to, int number ) + { + to.Send( new MessageLocalized( m_Serial, Body, MessageType.Regular, m_SpeechHue, 3, number, Name, "" ) ); + } + + public void SayTo( Mobile to, int number, string args ) + { + to.Send( new MessageLocalized( m_Serial, Body, MessageType.Regular, m_SpeechHue, 3, number, Name, args ) ); + } + + public void Say( bool ascii, string text ) + { + PublicOverheadMessage( MessageType.Regular, m_SpeechHue, ascii, text ); + } + + public void Say( string text ) + { + PublicOverheadMessage( MessageType.Regular, m_SpeechHue, false, text ); + } + + public void Say( string format, params object[] args ) + { + Say( String.Format( format, args ) ); + } + + public void Say( int number, AffixType type, string affix, string args ) + { + PublicOverheadMessage( MessageType.Regular, m_SpeechHue, number, type, affix, args ); + } + + public void Say( int number ) + { + Say( number, "" ); + } + + public void Say( int number, string args ) + { + PublicOverheadMessage( MessageType.Regular, m_SpeechHue, number, args ); + } + + public void Emote( string text ) + { + PublicOverheadMessage( MessageType.Emote, m_EmoteHue, false, text ); + } + + public void Emote( string format, params object[] args ) + { + Emote( String.Format( format, args ) ); + } + + public void Emote( int number ) + { + Emote( number, "" ); + } + + public void Emote( int number, string args ) + { + PublicOverheadMessage( MessageType.Emote, m_EmoteHue, number, args ); + } + + public void Whisper( string text ) + { + PublicOverheadMessage( MessageType.Whisper, m_WhisperHue, false, text ); + } + + public void Whisper( string format, params object[] args ) + { + Whisper( String.Format( format, args ) ); + } + + public void Whisper( int number ) + { + Whisper( number, "" ); + } + + public void Whisper( int number, string args ) + { + PublicOverheadMessage( MessageType.Whisper, m_WhisperHue, number, args ); + } + + public void Yell( string text ) + { + PublicOverheadMessage( MessageType.Yell, m_YellHue, false, text ); + } + + public void Yell( string format, params object[] args ) + { + Yell( String.Format( format, args ) ); + } + + public void Yell( int number ) + { + Yell( number, "" ); + } + + public void Yell( int number, string args ) + { + PublicOverheadMessage( MessageType.Yell, m_YellHue, number, args ); + } + #endregion + + [CommandProperty( AccessLevel.GameMaster )] + public bool Blessed + { + get + { + return m_Blessed; + } + set + { + if( m_Blessed != value ) + { + m_Blessed = value; + Delta( MobileDelta.HealthbarYellow ); + } + } + } + + public void SendRemovePacket() + { + SendRemovePacket( true ); + } + + public void SendRemovePacket( bool everyone ) + { + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state != m_NetState && (everyone || !state.Mobile.CanSee( this )) ) + { + if( p == null ) + p = this.RemovePacket; + + state.Send( p ); + } + } + + eable.Free(); + } + } + + public void ClearScreen() + { + NetState ns = m_NetState; + + if( m_Map != null && ns != null ) + { + IPooledEnumerable eable = m_Map.GetObjectsInRange( m_Location, Core.GlobalMaxUpdateRange ); + + foreach( object o in eable ) + { + if( o is Mobile ) + { + Mobile m = (Mobile)o; + + if( m != this && Utility.InUpdateRange( m_Location, m.m_Location ) ) + ns.Send( m.RemovePacket ); + } + else if( o is Item ) + { + Item item = (Item)o; + + if( InRange( item.Location, item.GetUpdateRange( this ) ) ) + ns.Send( item.RemovePacket ); + } + } + + eable.Free(); + } + } + + public bool Send( Packet p ) { + return Send( p, false ); + } + + public bool Send( Packet p, bool throwOnOffline ) { + if ( m_NetState != null ) { + m_NetState.Send( p ); + return true; + } else if ( throwOnOffline ) { + throw new MobileNotConnectedException( this, "Packet could not be sent." ); + } else { + return false; + } + } + + #region Gumps/Menus + + public bool SendHuePicker( HuePicker p ) { + return SendHuePicker( p, false ); + } + + public bool SendHuePicker( HuePicker p, bool throwOnOffline ) { + if ( m_NetState != null ) { + p.SendTo( m_NetState ); + return true; + } else if ( throwOnOffline ) { + throw new MobileNotConnectedException( this, "Hue picker could not be sent." ); + } else { + return false; + } + } + + public Gump FindGump( Type type ) { + NetState ns = m_NetState; + + if ( ns != null ) { + foreach ( Gump gump in ns.Gumps ) { + if ( type.IsAssignableFrom( gump.GetType() ) ) { + return gump; + } + } + } + + return null; + } + + public bool CloseGump( Type type ) { + if ( m_NetState != null ) { + Gump gump = FindGump( type ); + + if ( gump != null ) { + m_NetState.Send( new CloseGump( gump.TypeID, 0 ) ); + + m_NetState.RemoveGump( gump ); + + gump.OnServerClose( m_NetState ); + } + + return true; + } else { + return false; + } + } + + [Obsolete( "Use CloseGump( Type ) instead." )] + public bool CloseGump( Type type, int buttonID ) { + return CloseGump( type ); + } + + [Obsolete( "Use CloseGump( Type ) instead." )] + public bool CloseGump( Type type, int buttonID, bool throwOnOffline ) { + return CloseGump( type ); + } + + public bool CloseAllGumps() { + NetState ns = m_NetState; + + if ( ns != null ) { + List gumps = new List( ns.Gumps ); + + ns.ClearGumps(); + + foreach ( Gump gump in gumps ) { + ns.Send( new CloseGump( gump.TypeID, 0 ) ); + + gump.OnServerClose( ns ); + } + + return true; + } else { + return false; + } + } + + [Obsolete( "Use CloseAllGumps() instead.", false )] + public bool CloseAllGumps( bool throwOnOffline ) { + return CloseAllGumps(); + } + + public bool HasGump( Type type ) { + return ( FindGump( type ) != null ); + } + + [Obsolete( "Use HasGump( Type ) instead.", false )] + public bool HasGump( Type type, bool throwOnOffline ) { + return HasGump( type ); + } + + public bool SendGump( Gump g ) { + return SendGump( g, false ); + } + + public bool SendGump( Gump g, bool throwOnOffline ) { + if ( m_NetState != null ) { + g.SendTo( m_NetState ); + return true; + } else if ( throwOnOffline ) { + throw new MobileNotConnectedException( this, "Gump could not be sent." ); + } else { + return false; + } + } + + public bool SendMenu( IMenu m ) { + return SendMenu( m, false ); + } + + public bool SendMenu( IMenu m, bool throwOnOffline ) { + if ( m_NetState != null ) { + m.SendTo( m_NetState ); + return true; + } else if ( throwOnOffline ) { + throw new MobileNotConnectedException( this, "Menu could not be sent." ); + } else { + return false; + } + } + + #endregion + + /// + /// Overridable. Event invoked before the Mobile says something. + /// + /// + public virtual void OnSaid( SpeechEventArgs e ) + { + if( m_Squelched ) + { + if( Core.ML ) + this.SendLocalizedMessage( 500168 ); // You can not say anything, you have been muted. + else + this.SendMessage( "You can not say anything, you have been squelched." ); //Cliloc ITSELF changed during ML. + + e.Blocked = true; + } + + if( !e.Blocked ) + RevealingAction(); + } + + public virtual bool HandlesOnSpeech( Mobile from ) + { + return false; + } + + /// + /// Overridable. Virtual event invoked when the Mobile hears speech. This event will only be invoked if returns true. + /// + /// + public virtual void OnSpeech( SpeechEventArgs e ) + { + } + + public void SendEverything() + { + NetState ns = m_NetState; + + if( m_Map != null && ns != null ) + { + IPooledEnumerable eable = m_Map.GetObjectsInRange( m_Location, Core.GlobalMaxUpdateRange ); + + foreach( object o in eable ) + { + if( o is Item ) + { + Item item = (Item)o; + + if( CanSee( item ) && InRange( item.Location, item.GetUpdateRange( this ) ) ) + item.SendInfoTo( ns ); + } + else if( o is Mobile ) + { + Mobile m = (Mobile)o; + + if( CanSee( m ) && Utility.InUpdateRange( m_Location, m.m_Location ) ) + { + ns.Send(MobileIncoming.Create(ns, this, m)); + + if (ns.StygianAbyss) + { + if ( m.Poisoned ) + ns.Send( new HealthbarPoison( m ) ); + + if ( m.Blessed || m.YellowHealthbar ) + ns.Send( new HealthbarYellow( m ) ); + } + + if( m.IsDeadBondedPet ) + ns.Send( new BondedStatus( 0, m.m_Serial, 1 ) ); + + if( ObjectPropertyList.Enabled ) + { + ns.Send( m.OPLPacket ); + + //foreach ( Item item in m.m_Items ) + // ns.Send( item.OPLPacket ); + } + } + } + } + + eable.Free(); + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Map Map + { + get + { + return m_Map; + } + set + { + if( m_Deleted ) + return; + + if( m_Map != value ) + { + if( m_NetState != null ) + m_NetState.ValidateAllTrades(); + + Map oldMap = m_Map; + + if( m_Map != null ) + { + m_Map.OnLeave( this ); + + ClearScreen(); + SendRemovePacket(); + } + + for( int i = 0; i < m_Items.Count; ++i ) + m_Items[i].Map = value; + + m_Map = value; + + UpdateRegion(); + + if( m_Map != null ) + m_Map.OnEnter( this ); + + NetState ns = m_NetState; + + if( ns != null && m_Map != null ) + { + ns.Sequence = 0; + ns.Send( new MapChange( this ) ); + ns.Send( new MapPatches() ); + ns.Send( SeasonChange.Instantiate( GetSeason(), true ) ); + + if ( ns.StygianAbyss ) + ns.Send( new MobileUpdate( this ) ); + else + ns.Send( new MobileUpdateOld( this ) ); + + ClearFastwalkStack(); + } + + if( ns != null ) + { + if( m_Map != null ) + ns.Send(new ServerChange(this, m_Map)); + + ns.Sequence = 0; + ClearFastwalkStack(); + + ns.Send(MobileIncoming.Create(ns, this, this)); + + if ( ns.StygianAbyss ) { + ns.Send(new MobileUpdate(this)); + CheckLightLevels( true ); + ns.Send(new MobileUpdate(this)); + } else { + ns.Send(new MobileUpdateOld(this)); + CheckLightLevels( true ); + ns.Send(new MobileUpdateOld(this)); + } + } + + SendEverything(); + SendIncomingPacket(); + + if( ns != null ) + { + ns.Sequence = 0; + ClearFastwalkStack(); + + ns.Send(MobileIncoming.Create(ns, this, this)); + + if ( ns.StygianAbyss ) { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdate(this)); + ns.Send(new MobileAttributes(this)); + } else { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdateOld(this)); + ns.Send(new MobileAttributes(this)); + } + } + + OnMapChange( oldMap ); + } + } + } + + public void UpdateRegion() + { + if( m_Deleted ) + return; + + Region newRegion = Region.Find( m_Location, m_Map ); + + if( newRegion != m_Region ) + { + Region.OnRegionChange( this, m_Region, newRegion ); + + m_Region = newRegion; + OnRegionChange( m_Region, newRegion ); + } + } + + /// + /// Overridable. Virtual event invoked when changes. + /// + protected virtual void OnMapChange( Map oldMap ) + { + } + + #region Beneficial Checks/Actions + + public virtual bool CanBeBeneficial( Mobile target ) + { + return CanBeBeneficial( target, true, false ); + } + + public virtual bool CanBeBeneficial( Mobile target, bool message ) + { + return CanBeBeneficial( target, message, false ); + } + + public virtual bool CanBeBeneficial( Mobile target, bool message, bool allowDead ) + { + if( target == null ) + return false; + + if (m_Deleted || target.m_Deleted || !Alive || IsDeadBondedPet || (!allowDead && (!target.Alive || target.IsDeadBondedPet))) + { + if( message ) + SendLocalizedMessage( 1001017 ); // You can not perform beneficial acts on your target. + + return false; + } + + if( target == this ) + return true; + + if( /*m_Player &&*/ !Region.AllowBeneficial( this, target ) ) + { + // TODO: Pets + //if ( !(target.m_Player || target.Body.IsHuman || target.Body.IsAnimal) ) + //{ + if( message ) + SendLocalizedMessage( 1001017 ); // You can not perform beneficial acts on your target. + + return false; + //} + } + + return true; + } + + public virtual bool IsBeneficialCriminal( Mobile target ) + { + if( this == target ) + return false; + + int n = Notoriety.Compute( this, target ); + + return (n == Notoriety.Criminal || n == Notoriety.Murderer); + } + + /// + /// Overridable. Event invoked when the Mobile does a beneficial action. + /// + public virtual void OnBeneficialAction( Mobile target, bool isCriminal ) + { + if( isCriminal ) + CriminalAction( false ); + } + + public virtual void DoBeneficial( Mobile target ) + { + if( target == null ) + return; + + OnBeneficialAction( target, IsBeneficialCriminal( target ) ); + + Region.OnBeneficialAction( this, target ); + target.Region.OnGotBeneficialAction( this, target ); + } + + public virtual bool BeneficialCheck( Mobile target ) + { + if( CanBeBeneficial( target, true ) ) + { + DoBeneficial( target ); + return true; + } + + return false; + } + + #endregion + + #region Harmful Checks/Actions + + public virtual bool CanBeHarmful( Mobile target ) + { + return CanBeHarmful( target, true ); + } + + public virtual bool CanBeHarmful( Mobile target, bool message ) + { + return CanBeHarmful( target, message, false ); + } + + public virtual bool CanBeHarmful( Mobile target, bool message, bool ignoreOurBlessedness ) + { + if( target == null ) + return false; + + if( m_Deleted || (!ignoreOurBlessedness && m_Blessed) || target.m_Deleted || target.m_Blessed || !Alive || IsDeadBondedPet || !target.Alive || target.IsDeadBondedPet ) + { + if( message ) + SendLocalizedMessage( 1001018 ); // You can not perform negative acts on your target. + + return false; + } + + if( target == this ) + return true; + + // TODO: Pets + if( /*m_Player &&*/ !Region.AllowHarmful( this, target ) )//(target.m_Player || target.Body.IsHuman) && !Region.AllowHarmful( this, target ) ) + { + if( message ) + SendLocalizedMessage( 1001018 ); // You can not perform negative acts on your target. + + return false; + } + + return true; + } + + public virtual bool IsHarmfulCriminal( Mobile target ) + { + if( this == target ) + return false; + + return (Notoriety.Compute( this, target ) == Notoriety.Innocent); + } + + /// + /// Overridable. Event invoked when the Mobile does a harmful action. + /// + public virtual void OnHarmfulAction( Mobile target, bool isCriminal ) + { + if( isCriminal ) + CriminalAction( false ); + } + + public virtual void DoHarmful( Mobile target ) + { + DoHarmful( target, false ); + } + + public virtual void DoHarmful( Mobile target, bool indirect ) + { + if( target == null || m_Deleted ) + return; + + bool isCriminal = IsHarmfulCriminal( target ); + + OnHarmfulAction( target, isCriminal ); + target.AggressiveAction( this, isCriminal ); + + this.Region.OnDidHarmful( this, target ); + target.Region.OnGotHarmful( this, target ); + + if( !indirect ) + Combatant = target; + + if( m_ExpireCombatant == null ) + m_ExpireCombatant = new ExpireCombatantTimer( this ); + else + m_ExpireCombatant.Stop(); + + m_ExpireCombatant.Start(); + } + + public virtual bool HarmfulCheck( Mobile target ) + { + if( CanBeHarmful( target ) ) + { + DoHarmful( target ); + return true; + } + + return false; + } + + #endregion + + #region Stats + + /// + /// Gets a list of all StatMod's currently active for the Mobile. + /// + public List StatMods { get { return m_StatMods; } } + + public bool RemoveStatMod( string name ) + { + for( int i = 0; i < m_StatMods.Count; ++i ) + { + StatMod check = m_StatMods[i]; + + if( check.Name == name ) + { + m_StatMods.RemoveAt( i ); + CheckStatTimers(); + Delta( MobileDelta.Stat | GetStatDelta( check.Type ) ); + return true; + } + } + + return false; + } + + public StatMod GetStatMod( string name ) + { + for( int i = 0; i < m_StatMods.Count; ++i ) + { + StatMod check = m_StatMods[i]; + + if( check.Name == name ) + return check; + } + + return null; + } + + public void AddStatMod( StatMod mod ) + { + for( int i = 0; i < m_StatMods.Count; ++i ) + { + StatMod check = m_StatMods[i]; + + if( check.Name == mod.Name ) + { + Delta( MobileDelta.Stat | GetStatDelta( check.Type ) ); + m_StatMods.RemoveAt( i ); + break; + } + } + + m_StatMods.Add( mod ); + Delta( MobileDelta.Stat | GetStatDelta( mod.Type ) ); + CheckStatTimers(); + } + + private MobileDelta GetStatDelta( StatType type ) + { + MobileDelta delta = 0; + + if( (type & StatType.Str) != 0 ) + delta |= MobileDelta.Hits; + + if( (type & StatType.Dex) != 0 ) + delta |= MobileDelta.Stam; + + if( (type & StatType.Int) != 0 ) + delta |= MobileDelta.Mana; + + return delta; + } + + /// + /// Computes the total modified offset for the specified stat type. Expired instances are removed. + /// + public int GetStatOffset( StatType type ) + { + int offset = 0; + + for( int i = 0; i < m_StatMods.Count; ++i ) + { + StatMod mod = m_StatMods[i]; + + if( mod.HasElapsed() ) + { + m_StatMods.RemoveAt( i ); + Delta( MobileDelta.Stat | GetStatDelta( mod.Type ) ); + CheckStatTimers(); + + --i; + } + else if( (mod.Type & type) != 0 ) + { + offset += mod.Offset; + } + } + + return offset; + } + + /// + /// Overridable. Virtual event invoked when the changes. + /// + /// + /// + public virtual void OnRawStrChange( int oldValue ) + { + } + + /// + /// Overridable. Virtual event invoked when changes. + /// + /// + /// + public virtual void OnRawDexChange( int oldValue ) + { + } + + /// + /// Overridable. Virtual event invoked when the changes. + /// + /// + /// + public virtual void OnRawIntChange( int oldValue ) + { + } + + /// + /// Overridable. Virtual event invoked when the , , or changes. + /// + /// + /// + /// + public virtual void OnRawStatChange( StatType stat, int oldValue ) + { + } + + /// + /// Gets or sets the base, unmodified, strength of the Mobile. Ranges from 1 to 65000, inclusive. + /// + /// + /// + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public int RawStr + { + get + { + return m_Str; + } + set + { + if( value < 1 ) + value = 1; + else if( value > 65000 ) + value = 65000; + + if( m_Str != value ) + { + int oldValue = m_Str; + + m_Str = value; + Delta( MobileDelta.Stat | MobileDelta.Hits ); + + if( Hits < HitsMax ) + { + if( m_HitsTimer == null ) + m_HitsTimer = new HitsTimer( this ); + + m_HitsTimer.Start(); + } + else if( Hits > HitsMax ) + { + Hits = HitsMax; + } + + OnRawStrChange( oldValue ); + OnRawStatChange( StatType.Str, oldValue ); + } + } + } + + /// + /// Gets or sets the effective strength of the Mobile. This is the sum of the plus any additional modifiers. Any attempts to set this value when under the influence of a will result in no change. It ranges from 1 to 65000, inclusive. + /// + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual int Str + { + get + { + int value = m_Str + GetStatOffset( StatType.Str ); + + if( value < 1 ) + value = 1; + else if( value > 65000 ) + value = 65000; + + return value; + } + set + { + if( m_StatMods.Count == 0 ) + RawStr = value; + } + } + + /// + /// Gets or sets the base, unmodified, dexterity of the Mobile. Ranges from 1 to 65000, inclusive. + /// + /// + /// + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public int RawDex + { + get + { + return m_Dex; + } + set + { + if( value < 1 ) + value = 1; + else if( value > 65000 ) + value = 65000; + + if( m_Dex != value ) + { + int oldValue = m_Dex; + + m_Dex = value; + Delta( MobileDelta.Stat | MobileDelta.Stam ); + + if( Stam < StamMax ) + { + if( m_StamTimer == null ) + m_StamTimer = new StamTimer( this ); + + m_StamTimer.Start(); + } + else if( Stam > StamMax ) + { + Stam = StamMax; + } + + OnRawDexChange( oldValue ); + OnRawStatChange( StatType.Dex, oldValue ); + } + } + } + + /// + /// Gets or sets the effective dexterity of the Mobile. This is the sum of the plus any additional modifiers. Any attempts to set this value when under the influence of a will result in no change. It ranges from 1 to 65000, inclusive. + /// + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual int Dex + { + get + { + int value = m_Dex + GetStatOffset( StatType.Dex ); + + if( value < 1 ) + value = 1; + else if( value > 65000 ) + value = 65000; + + return value; + } + set + { + if( m_StatMods.Count == 0 ) + RawDex = value; + } + } + + /// + /// Gets or sets the base, unmodified, intelligence of the Mobile. Ranges from 1 to 65000, inclusive. + /// + /// + /// + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public int RawInt + { + get + { + return m_Int; + } + set + { + if( value < 1 ) + value = 1; + else if( value > 65000 ) + value = 65000; + + if( m_Int != value ) + { + int oldValue = m_Int; + + m_Int = value; + Delta( MobileDelta.Stat | MobileDelta.Mana ); + + if( Mana < ManaMax ) + { + if( m_ManaTimer == null ) + m_ManaTimer = new ManaTimer( this ); + + m_ManaTimer.Start(); + } + else if( Mana > ManaMax ) + { + Mana = ManaMax; + } + + OnRawIntChange( oldValue ); + OnRawStatChange( StatType.Int, oldValue ); + } + } + } + + /// + /// Gets or sets the effective intelligence of the Mobile. This is the sum of the plus any additional modifiers. Any attempts to set this value when under the influence of a will result in no change. It ranges from 1 to 65000, inclusive. + /// + /// + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual int Int + { + get + { + int value = m_Int + GetStatOffset( StatType.Int ); + + if( value < 1 ) + value = 1; + else if( value > 65000 ) + value = 65000; + + return value; + } + set + { + if( m_StatMods.Count == 0 ) + RawInt = value; + } + } + + public virtual void OnHitsChange( int oldValue ) + { + } + + public virtual void OnStamChange( int oldValue ) + { + } + + public virtual void OnManaChange( int oldValue ) + { + } + + /// + /// Gets or sets the current hit point of the Mobile. This value ranges from 0 to , inclusive. When set to the value of , the CanReportMurder flag of all aggressors is reset to false, and the list of damage entries is cleared. + /// + [CommandProperty( AccessLevel.GameMaster )] + public int Hits + { + get + { + return m_Hits; + } + set + { + if( m_Deleted ) + return; + + if( value < 0 ) + { + value = 0; + } + else if( value >= HitsMax ) + { + value = HitsMax; + + if( m_HitsTimer != null ) + m_HitsTimer.Stop(); + + for( int i = 0; i < m_Aggressors.Count; i++ ) //reset reports on full HP + m_Aggressors[i].CanReportMurder = false; + + if( m_DamageEntries.Count > 0 ) + m_DamageEntries.Clear(); // reset damage entries on full HP + } + + if( value < HitsMax ) + { + if( CanRegenHits ) + { + if( m_HitsTimer == null ) + m_HitsTimer = new HitsTimer( this ); + + m_HitsTimer.Start(); + } + else if( m_HitsTimer != null ) + { + m_HitsTimer.Stop(); + } + } + + if( m_Hits != value ) + { + int oldValue = m_Hits; + m_Hits = value; + Delta( MobileDelta.Hits ); + OnHitsChange( oldValue ); + } + } + } + + /// + /// Overridable. Gets the maximum hit point of the Mobile. By default, this returns: 50 + ( / 2) + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual int HitsMax + { + get + { + return 50 + (Str / 2); + } + } + + /// + /// Gets or sets the current stamina of the Mobile. This value ranges from 0 to , inclusive. + /// + [CommandProperty( AccessLevel.GameMaster )] + public int Stam + { + get + { + return m_Stam; + } + set + { + if( m_Deleted ) + return; + + if( value < 0 ) + { + value = 0; + } + else if( value >= StamMax ) + { + value = StamMax; + + if( m_StamTimer != null ) + m_StamTimer.Stop(); + } + + if( value < StamMax ) + { + if( CanRegenStam ) + { + if( m_StamTimer == null ) + m_StamTimer = new StamTimer( this ); + + m_StamTimer.Start(); + } + else if( m_StamTimer != null ) + { + m_StamTimer.Stop(); + } + } + + if( m_Stam != value ) + { + int oldValue = m_Stam; + m_Stam = value; + Delta( MobileDelta.Stam ); + OnStamChange( oldValue ); + } + } + } + + /// + /// Overridable. Gets the maximum stamina of the Mobile. By default, this returns: + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual int StamMax + { + get + { + return Dex; + } + } + + /// + /// Gets or sets the current stamina of the Mobile. This value ranges from 0 to , inclusive. + /// + [CommandProperty( AccessLevel.GameMaster )] + public int Mana + { + get + { + return m_Mana; + } + set + { + if( m_Deleted ) + return; + + if( value < 0 ) + { + value = 0; + } + else if( value >= ManaMax ) + { + value = ManaMax; + + if( m_ManaTimer != null ) + m_ManaTimer.Stop(); + + if( Meditating ) + { + Meditating = false; + SendLocalizedMessage( 501846 ); // You are at peace. + } + } + + if( value < ManaMax ) + { + if( CanRegenMana ) + { + if( m_ManaTimer == null ) + m_ManaTimer = new ManaTimer( this ); + + m_ManaTimer.Start(); + } + else if( m_ManaTimer != null ) + { + m_ManaTimer.Stop(); + } + } + + if( m_Mana != value ) + { + int oldValue = m_Mana; + m_Mana = value; + Delta( MobileDelta.Mana ); + OnManaChange( oldValue ); + } + } + } + + /// + /// Overridable. Gets the maximum mana of the Mobile. By default, this returns: + /// + [CommandProperty( AccessLevel.GameMaster )] + public virtual int ManaMax + { + get + { + return Int; + } + } + + #endregion + + public virtual int Luck + { + get { return 0; } + } + + public virtual int HuedItemID + { + get + { + return (m_Female ? 0x2107 : 0x2106); + } + } + + private int m_HueMod = -1; + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public int HueMod + { + get + { + return m_HueMod; + } + set + { + if( m_HueMod != value ) + { + m_HueMod = value; + + Delta( MobileDelta.Hue ); + } + } + } + + [Hue, CommandProperty( AccessLevel.GameMaster )] + public virtual int Hue + { + get + { + if( m_HueMod != -1 ) + return m_HueMod; + + return m_Hue; + } + set + { + int oldHue = m_Hue; + + if( oldHue != value ) + { + m_Hue = value; + + Delta( MobileDelta.Hue ); + } + } + } + + + public void SetDirection( Direction dir ) + { + m_Direction = dir; + } + + [CommandProperty( AccessLevel.GameMaster )] + public Direction Direction + { + get + { + return m_Direction; + } + set + { + if( m_Direction != value ) + { + m_Direction = value; + + Delta( MobileDelta.Direction ); + //ProcessDelta(); + } + } + } + + public virtual int GetSeason() + { + if( m_Map != null ) + return m_Map.Season; + + return 1; + } + + public virtual int GetPacketFlags() + { + int flags = 0x0; + + if (m_Paralyzed || m_Frozen) + flags |= 0x01; + + if( m_Female ) + flags |= 0x02; + + if( m_Flying ) + flags |= 0x04; + + if( m_Blessed || m_YellowHealthbar ) + flags |= 0x08; + + if( m_Warmode ) + flags |= 0x40; + + if( m_Hidden ) + flags |= 0x80; + + return flags; + } + + // Pre-7.0.0.0 Packet Flags + public virtual int GetOldPacketFlags() + { + int flags = 0x0; + + if (m_Paralyzed || m_Frozen) + flags |= 0x01; + + if( m_Female ) + flags |= 0x02; + + if( m_Poison != null ) + flags |= 0x04; + + if( m_Blessed || m_YellowHealthbar ) + flags |= 0x08; + + if( m_Warmode ) + flags |= 0x40; + + if( m_Hidden ) + flags |= 0x80; + + return flags; + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Female + { + get + { + return m_Female; + } + set + { + if( m_Female != value ) + { + m_Female = value; + + // Scriptiz : si on change female, on modifie le bodyvalue s'il a un corps adapt� + List bodies = new List() { 400, 401, 402, 403, 605, 606, 607, 608 }; + if (bodies.Contains(BodyValue)) + { + if (Alive) + BodyValue = (IsElfBody ? Race.Elf.AliveBody(m_Female) : this.Race.AliveBody(m_Female)); + else + BodyValue = (IsElfBody? Race.Elf.GhostBody(m_Female) : this.Race.GhostBody(m_Female)); + } + + Delta( MobileDelta.Flags ); + OnGenderChanged( !m_Female ); + } + } + } + + public virtual void OnGenderChanged( bool oldFemale ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Flying + { + get + { + return m_Flying; + } + set + { + if( m_Flying != value ) + { + m_Flying = value; + Delta( MobileDelta.Flags ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Warmode + { + get + { + return m_Warmode; + } + set + { + if( m_Deleted ) + return; + + if( m_Warmode != value ) + { + if( m_AutoManifestTimer != null ) + { + m_AutoManifestTimer.Stop(); + m_AutoManifestTimer = null; + } + + m_Warmode = value; + Delta( MobileDelta.Flags ); + + if( m_NetState != null ) + Send( SetWarMode.Instantiate( value ) ); + + if( !m_Warmode ) + Combatant = null; + + if( !Alive ) + { + if( value ) + Delta( MobileDelta.GhostUpdate ); + else + SendRemovePacket( false ); + } + + OnWarmodeChanged(); + } + } + } + + /// + /// Overridable. Virtual event invoked after the Warmode property has changed. + /// + public virtual void OnWarmodeChanged() + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool Hidden + { + get + { + return m_Hidden; + } + set + { + if( m_Hidden != value ) + { + m_AllowedStealthSteps = 0; + + m_Hidden = value; + //Delta( MobileDelta.Flags ); + + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( !state.Mobile.CanSee( this ) ) + { + if( p == null ) + p = this.RemovePacket; + + state.Send( p ); + } + else + { + state.Send(MobileIncoming.Create(state, state.Mobile, this)); + + if( IsDeadBondedPet ) + state.Send( new BondedStatus( 0, m_Serial, 1 ) ); + + if( ObjectPropertyList.Enabled ) + { + state.Send( OPLPacket ); + + //foreach ( Item item in m_Items ) + // state.Send( item.OPLPacket ); + } + } + } + + eable.Free(); + } + } + } + } + + public virtual void OnConnected() + { + } + + public virtual void OnDisconnected() + { + } + + public virtual void OnNetStateChanged() + { + } + + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Owner)] + public NetState NetState + { + get + { + if( m_NetState != null && m_NetState.Socket == null ) + NetState = null; + + return m_NetState; + } + set + { + if( m_NetState != value ) + { + if( m_Map != null ) + m_Map.OnClientChange( m_NetState, value, this ); + + if( m_Target != null ) + m_Target.Cancel( this, TargetCancelType.Disconnected ); + + if( m_QuestArrow != null ) + QuestArrow = null; + + if( m_Spell != null ) + m_Spell.OnConnectionChanged(); + + //if ( m_Spell != null ) + // m_Spell.FinishSequence(); + + if( m_NetState != null ) + m_NetState.CancelAllTrades(); + + BankBox box = FindBankNoCreate(); + + if( box != null && box.Opened ) + box.Close(); + + // REMOVED: + //m_Actions.Clear(); + + m_NetState = value; + + if( m_NetState == null ) + { + OnDisconnected(); + EventSink.InvokeDisconnected( new DisconnectedEventArgs( this ) ); + + // Disconnected, start the logout timer + + if( m_LogoutTimer == null ) + m_LogoutTimer = new LogoutTimer( this ); + else + m_LogoutTimer.Stop(); + + m_LogoutTimer.Delay = GetLogoutDelay(); + m_LogoutTimer.Start(); + } + else + { + OnConnected(); + EventSink.InvokeConnected( new ConnectedEventArgs( this ) ); + + // Connected, stop the logout timer and if needed, move to the world + + if( m_LogoutTimer != null ) + m_LogoutTimer.Stop(); + + m_LogoutTimer = null; + + if( m_Map == Map.Internal && m_LogoutMap != null ) + { + Map = m_LogoutMap; + Location = m_LogoutLocation; + } + } + + for( int i = m_Items.Count - 1; i >= 0; --i ) + { + if( i >= m_Items.Count ) + continue; + + Item item = m_Items[i]; + + if( item is SecureTradeContainer ) + { + for( int j = item.Items.Count - 1; j >= 0; --j ) + { + if( j < item.Items.Count ) + { + item.Items[j].OnSecureTrade( this, this, this, false ); + AddToBackpack( item.Items[j] ); + } + } + + Timer.DelayCall( TimeSpan.Zero, delegate { item.Delete(); } ); + } + } + + DropHolding(); + OnNetStateChanged(); + } + } + } + + public virtual bool CanSee( object o ) + { + if( o is Item ) + { + return CanSee( (Item)o ); + } + else if( o is Mobile ) + { + return CanSee( (Mobile)o ); + } + else + { + return true; + } + } + + public virtual bool CanSee( Item item ) + { + if( m_Map == Map.Internal ) + return false; + else if( item.Map == Map.Internal ) + return false; + + if( item.Parent != null ) + { + if( item.Parent is Item ) + { + Item parent = item.Parent as Item; + + if ( !(CanSee( parent ) && parent.IsChildVisibleTo( this, item )) ) + return false; + } + else if( item.Parent is Mobile ) + { + if( !CanSee( (Mobile)item.Parent ) ) + return false; + } + } + + if( item is BankBox ) + { + BankBox box = item as BankBox; + + if( box != null && m_AccessLevel <= AccessLevel.Counselor && (box.Owner != this || !box.Opened) ) + return false; + } + else if( item is SecureTradeContainer ) + { + SecureTrade trade = ((SecureTradeContainer)item).Trade; + + if( trade != null && trade.From.Mobile != this && trade.To.Mobile != this ) + return false; + } + + return !item.Deleted && item.Map == m_Map && (item.Visible || m_AccessLevel > AccessLevel.Counselor); + } + + public virtual bool CanSee( Mobile m ) + { + if( m_Deleted || m.m_Deleted || m_Map == Map.Internal || m.m_Map == Map.Internal ) + return false; + + return this == m || ( + m.m_Map == m_Map && + (!m.Hidden || (m_AccessLevel != AccessLevel.Player && (m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator))) && + ((m.Alive || (Core.SE && Skills.SpiritSpeak.Value >= 100.0)) || !Alive || m_AccessLevel > AccessLevel.Player || m.Warmode)); + + } + + public virtual bool CanBeRenamedBy( Mobile from ) + { + return (from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel); + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Language + { + get + { + return m_Language; + } + set + { + if( m_Language != value ) + m_Language = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int SpeechHue + { + get + { + return m_SpeechHue; + } + set + { + m_SpeechHue = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int EmoteHue + { + get + { + return m_EmoteHue; + } + set + { + m_EmoteHue = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int WhisperHue + { + get + { + return m_WhisperHue; + } + set + { + m_WhisperHue = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int YellHue + { + get + { + return m_YellHue; + } + set + { + m_YellHue = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string GuildTitle + { + get + { + return m_GuildTitle; + } + set + { + string old = m_GuildTitle; + + if( old != value ) + { + m_GuildTitle = value; + + if( m_Guild != null && !m_Guild.Disbanded && m_GuildTitle != null ) + this.SendLocalizedMessage( 1018026, true, m_GuildTitle ); // Your guild title has changed : + + InvalidateProperties(); + + OnGuildTitleChange( old ); + } + } + } + + public virtual void OnGuildTitleChange( string oldTitle ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool DisplayGuildTitle + { + get + { + return m_DisplayGuildTitle; + } + set + { + m_DisplayGuildTitle = value; + InvalidateProperties(); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Mobile GuildFealty + { + get + { + return m_GuildFealty; + } + set + { + m_GuildFealty = value; + } + } + + private string m_NameMod; + + [CommandProperty( AccessLevel.GameMaster )] + public string NameMod + { + get + { + return m_NameMod; + } + set + { + if( m_NameMod != value ) + { + m_NameMod = value; + Delta( MobileDelta.Name ); + InvalidateProperties(); + } + } + } + + private bool m_YellowHealthbar; + + [CommandProperty( AccessLevel.GameMaster )] + public bool YellowHealthbar + { + get + { + return m_YellowHealthbar; + } + set + { + m_YellowHealthbar = value; + Delta( MobileDelta.HealthbarYellow ); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string RawName + { + get { return m_Name; } + set { Name = value; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public string Name + { + get + { + if( m_NameMod != null ) + return m_NameMod; + + return m_Name; + } + set + { + if (m_Name != value) // I'm leaving out the && m_NameMod == null + { + string oldName = m_Name; + m_Name = value; + OnAfterNameChange(oldName, m_Name); + Delta(MobileDelta.Name); + InvalidateProperties(); + } + } + } + + public virtual void OnAfterNameChange(string oldName, string newName) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastStrGain + { + get + { + return m_LastStrGain; + } + set + { + m_LastStrGain = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastIntGain + { + get + { + return m_LastIntGain; + } + set + { + m_LastIntGain = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime LastDexGain + { + get + { + return m_LastDexGain; + } + set + { + m_LastDexGain = value; + } + } + + public DateTime LastStatGain + { + get + { + DateTime d = m_LastStrGain; + + if( m_LastIntGain > d ) + d = m_LastIntGain; + + if( m_LastDexGain > d ) + d = m_LastDexGain; + + return d; + } + set + { + m_LastStrGain = value; + m_LastIntGain = value; + m_LastDexGain = value; + } + } + + public BaseGuild Guild + { + get + { + return m_Guild; + } + set + { + BaseGuild old = m_Guild; + + if( old != value ) + { + if( value == null ) + GuildTitle = null; + + m_Guild = value; + + Delta( MobileDelta.Noto ); + InvalidateProperties(); + + OnGuildChange( old ); + } + } + } + + public virtual void OnGuildChange( BaseGuild oldGuild ) + { + } + + #region Poison/Curing + + public Timer PoisonTimer + { + get { return m_PoisonTimer; } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Poison Poison + { + get + { + return m_Poison; + } + set + { + /*if ( m_Poison != value && (m_Poison == null || value == null || m_Poison.Level < value.Level) ) + {*/ + m_Poison = value; + Delta( MobileDelta.HealthbarPoison ); + + if( m_PoisonTimer != null ) + { + m_PoisonTimer.Stop(); + m_PoisonTimer = null; + } + + if( m_Poison != null ) + { + m_PoisonTimer = m_Poison.ConstructTimer( this ); + + if( m_PoisonTimer != null ) + m_PoisonTimer.Start(); + } + + CheckStatTimers(); + /*}*/ + } + } + + /// + /// Overridable. Event invoked when a call to failed because returned false: the Mobile was resistant to the poison. By default, this broadcasts an overhead message: * The poison seems to have no effect. * + /// + /// + /// + /// + public virtual void OnPoisonImmunity( Mobile from, Poison poison ) + { + this.PublicOverheadMessage( MessageType.Emote, 0x3B2, 1005534 ); // * The poison seems to have no effect. * + } + + /// + /// Overridable. Virtual event invoked when a call to failed because returned false: the Mobile was already poisoned by an equal or greater strength poison. + /// + /// + /// + /// + public virtual void OnHigherPoison( Mobile from, Poison poison ) + { + } + + /// + /// Overridable. Event invoked when a call to succeeded. By default, this broadcasts an overhead message varying by the level of the poison. Example: * Zippy begins to spasm uncontrollably. * + /// + /// + /// + public virtual void OnPoisoned( Mobile from, Poison poison, Poison oldPoison ) + { + if( poison != null ) + { + this.LocalOverheadMessage( MessageType.Regular, 0x21, 1042857 + (poison.Level * 2) ); + this.NonlocalOverheadMessage( MessageType.Regular, 0x21, 1042858 + (poison.Level * 2), Name ); + } + } + + /// + /// Overridable. Called from , this method checks if the Mobile is immune to some . If true, will be invoked and is returned. + /// + /// + /// + /// + public virtual bool CheckPoisonImmunity( Mobile from, Poison poison ) + { + return false; + } + + /// + /// Overridable. Called from , this method checks if the Mobile is already poisoned by some of equal or greater strength. If true, will be invoked and is returned. + /// + /// + /// + /// + public virtual bool CheckHigherPoison( Mobile from, Poison poison ) + { + return (m_Poison != null && m_Poison.Level >= poison.Level); + } + + /// + /// Overridable. Attempts to apply poison to the Mobile. Checks are made such that no higher poison is active and that the Mobile is not immune to the poison. Provided those assertions are true, the is applied and is invoked. + /// + /// + /// + /// One of four possible values: + /// + /// + /// Cured + /// The parameter was null and so was invoked. + /// + /// + /// HigherPoisonActive + /// The call to returned false. + /// + /// + /// Immune + /// The call to returned false. + /// + /// + /// Poisoned + /// The was successfully applied. + /// + /// + /// + public virtual ApplyPoisonResult ApplyPoison( Mobile from, Poison poison ) + { + if( poison == null ) + { + CurePoison( from ); + return ApplyPoisonResult.Cured; + } + + if( CheckHigherPoison( from, poison ) ) + { + OnHigherPoison( from, poison ); + return ApplyPoisonResult.HigherPoisonActive; + } + + if( CheckPoisonImmunity( from, poison ) ) + { + OnPoisonImmunity( from, poison ); + return ApplyPoisonResult.Immune; + } + + Poison oldPoison = m_Poison; + this.Poison = poison; + + OnPoisoned( from, poison, oldPoison ); + + return ApplyPoisonResult.Poisoned; + } + + /// + /// Overridable. Called from , this method checks to see that the Mobile can be cured of + /// + /// + /// + public virtual bool CheckCure( Mobile from ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when a call to succeeded. + /// + /// + /// + /// + public virtual void OnCured( Mobile from, Poison oldPoison ) + { + } + + /// + /// Overridable. Virtual event invoked when a call to failed. + /// + /// + /// + /// + public virtual void OnFailedCure( Mobile from ) + { + } + + /// + /// Overridable. Attempts to cure any poison that is currently active. + /// + /// True if poison was cured, false if otherwise. + public virtual bool CurePoison( Mobile from ) + { + if( CheckCure( from ) ) + { + Poison oldPoison = m_Poison; + this.Poison = null; + + OnCured( from, oldPoison ); + + return true; + } + + OnFailedCure( from ); + + return false; + } + + #endregion + + private ISpawner m_Spawner; + + public ISpawner Spawner { get { return m_Spawner; } set { m_Spawner = value; } } + + private Region m_WalkRegion; + + public Region WalkRegion { get { return m_WalkRegion; } set { m_WalkRegion = value; } } + + public virtual void OnBeforeSpawn( Point3D location, Map m ) + { + } + + public virtual void OnAfterSpawn() + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Poisoned + { + get + { + return (m_Poison != null); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool IsBodyMod + { + get + { + return (m_BodyMod.BodyID != 0); + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public Body BodyMod + { + get + { + return m_BodyMod; + } + set + { + if( m_BodyMod != value ) + { + m_BodyMod = value; + + Delta( MobileDelta.Body ); + InvalidateProperties(); + + CheckStatTimers(); + } + } + } + + private static int[] m_InvalidBodies = new int[] + { + 32, + 95, + 156, + 197, + 198, + }; + + [Body, CommandProperty( AccessLevel.GameMaster )] + public Body Body + { + get + { + if( IsBodyMod ) + return m_BodyMod; + + return m_Body; + } + set + { + if( m_Body != value && !IsBodyMod ) + { + m_Body = SafeBody( value ); + + Delta( MobileDelta.Body ); + InvalidateProperties(); + + CheckStatTimers(); + } + } + } + + public virtual int SafeBody( int body ) + { + int delta = -1; + + for( int i = 0; delta < 0 && i < m_InvalidBodies.Length; ++i ) + delta = (m_InvalidBodies[i] - body); + + if( delta != 0 ) + return body; + + return 0; + } + + [Body, CommandProperty( AccessLevel.GameMaster )] + public int BodyValue + { + get + { + return Body.BodyID; + } + set + { + Body = value; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public Serial Serial + { + get + { + return m_Serial; + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Point3D Location + { + get + { + return m_Location; + } + set + { + SetLocation( value, true ); + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Point3D LogoutLocation + { + get + { + return m_LogoutLocation; + } + set + { + m_LogoutLocation = value; + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public Map LogoutMap + { + get + { + return m_LogoutMap; + } + set + { + m_LogoutMap = value; + } + } + + public Region Region + { + get + { + if( m_Region == null ) + if( this.Map == null ) + return Map.Internal.DefaultRegion; + else + return this.Map.DefaultRegion; + else + return m_Region; + } + } + + public void FreeCache() + { + Packet.Release( ref m_RemovePacket ); + Packet.Release( ref m_PropertyList ); + Packet.Release( ref m_OPLPacket ); + } + + private Packet m_RemovePacket; + + public Packet RemovePacket + { + get + { + if( m_RemovePacket == null ) + { + m_RemovePacket = new RemoveMobile( this ); + m_RemovePacket.SetStatic(); + } + + return m_RemovePacket; + } + } + + private Packet m_OPLPacket; + + public Packet OPLPacket + { + get + { + if( m_OPLPacket == null ) + { + m_OPLPacket = new OPLInfo( PropertyList ); + m_OPLPacket.SetStatic(); + } + + return m_OPLPacket; + } + } + + private ObjectPropertyList m_PropertyList; + + public ObjectPropertyList PropertyList + { + get + { + if( m_PropertyList == null ) + { + m_PropertyList = new ObjectPropertyList( this ); + + GetProperties( m_PropertyList ); + + m_PropertyList.Terminate(); + m_PropertyList.SetStatic(); + } + + return m_PropertyList; + } + } + + public void ClearProperties() + { + Packet.Release( ref m_PropertyList ); + Packet.Release( ref m_OPLPacket ); + } + + public void InvalidateProperties() + { + if( !ObjectPropertyList.Enabled ) + return; + + if( m_Map != null && m_Map != Map.Internal && !World.Loading ) + { + ObjectPropertyList oldList = m_PropertyList; + Packet.Release( ref m_PropertyList ); + ObjectPropertyList newList = PropertyList; + + if( oldList == null || oldList.Hash != newList.Hash ) + { + Packet.Release( ref m_OPLPacket ); + Delta( MobileDelta.Properties ); + } + } + else + { + ClearProperties(); + } + } + + private int m_SolidHueOverride = -1; + + [CommandProperty( AccessLevel.GameMaster )] + public int SolidHueOverride + { + get { return m_SolidHueOverride; } + set { if( m_SolidHueOverride == value ) return; m_SolidHueOverride = value; Delta( MobileDelta.Hue | MobileDelta.Body ); } + } + + public virtual void MoveToWorld( Point3D newLocation, Map map ) + { + if( m_Deleted ) + return; + + if( m_Map == map ) + { + SetLocation( newLocation, true ); + return; + } + + BankBox box = FindBankNoCreate(); + + if( box != null && box.Opened ) + box.Close(); + + Point3D oldLocation = m_Location; + Map oldMap = m_Map; + + Region oldRegion = m_Region; + + if( oldMap != null ) + { + oldMap.OnLeave( this ); + + ClearScreen(); + SendRemovePacket(); + } + + for( int i = 0; i < m_Items.Count; ++i ) + m_Items[i].Map = map; + + m_Map = map; + + m_Location = newLocation; + + NetState ns = m_NetState; + + if( m_Map != null ) + { + m_Map.OnEnter( this ); + + UpdateRegion(); + + if( ns != null && m_Map != null ) + { + ns.Sequence = 0; + ns.Send( new MapChange( this ) ); + ns.Send( new MapPatches() ); + ns.Send( SeasonChange.Instantiate( GetSeason(), true ) ); + + if ( ns.StygianAbyss ) + ns.Send( new MobileUpdate( this ) ); + else + ns.Send( new MobileUpdateOld( this ) ); + + ClearFastwalkStack(); + } + } + else + { + UpdateRegion(); + } + + if( ns != null ) + { + if( m_Map != null ) + Send( new ServerChange( this, m_Map ) ); + + ns.Sequence = 0; + ClearFastwalkStack(); + + ns.Send(MobileIncoming.Create(ns, this, this)); + + if ( ns.StygianAbyss ) { + ns.Send(new MobileUpdate(this)); + CheckLightLevels( true ); + ns.Send(new MobileUpdate(this)); + } else { + ns.Send(new MobileUpdateOld(this)); + CheckLightLevels( true ); + ns.Send(new MobileUpdateOld(this)); + } + } + + SendEverything(); + SendIncomingPacket(); + + if( ns != null ) + { + ns.Sequence = 0; + ClearFastwalkStack(); + + ns.Send(MobileIncoming.Create(ns, this, this)); + + if ( ns.StygianAbyss ) { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdate(this)); + ns.Send(new MobileAttributes(this)); + } else { + ns.Send(SupportedFeatures.Instantiate(ns)); + ns.Send(new MobileUpdateOld(this)); + ns.Send(new MobileAttributes(this)); + } + } + + OnMapChange( oldMap ); + OnLocationChange( oldLocation ); + + if( m_Region != null ) + m_Region.OnLocationChanged( this, oldLocation ); + } + + public virtual void SetLocation( Point3D newLocation, bool isTeleport ) + { + if( m_Deleted ) + return; + + Point3D oldLocation = m_Location; + + if( oldLocation != newLocation ) + { + m_Location = newLocation; + UpdateRegion(); + + BankBox box = FindBankNoCreate(); + + if( box != null && box.Opened ) + box.Close(); + + if( m_NetState != null ) + m_NetState.ValidateAllTrades(); + + if( m_Map != null ) + m_Map.OnMove( oldLocation, this ); + + if (isTeleport && m_NetState != null && (!m_NetState.HighSeas || !m_NoMoveHS)) + { + m_NetState.Sequence = 0; + + if ( m_NetState.StygianAbyss ) + m_NetState.Send( new MobileUpdate( this ) ); + else + m_NetState.Send( new MobileUpdateOld( this ) ); + + ClearFastwalkStack(); + } + + Map map = m_Map; + + if( map != null ) + { + // First, send a remove message to everyone who can no longer see us. (inOldRange && !inNewRange) + Packet removeThis = null; + + IPooledEnumerable eable = map.GetClientsInRange( oldLocation ); + + foreach( NetState ns in eable ) + { + if( ns != m_NetState && !Utility.InUpdateRange( newLocation, ns.Mobile.Location ) ) + { + if( removeThis == null ) + removeThis = this.RemovePacket; + + ns.Send( removeThis ); + } + } + + eable.Free(); + + NetState ourState = m_NetState; + + // Check to see if we are attached to a client + if( ourState != null ) + { + eable = map.GetObjectsInRange( newLocation, Core.GlobalMaxUpdateRange ); + + // We are attached to a client, so it's a bit more complex. We need to send new items and people to ourself, and ourself to other clients + foreach( object o in eable ) + { + if( o is Item ) + { + Item item = (Item)o; + + int range = item.GetUpdateRange( this ); + Point3D loc = item.Location; + + if( !Utility.InRange( oldLocation, loc, range ) && Utility.InRange( newLocation, loc, range ) && CanSee( item ) ) + item.SendInfoTo( ourState ); + } + else if( o != this && o is Mobile ) + { + Mobile m = (Mobile)o; + + if( !Utility.InUpdateRange( newLocation, m.m_Location ) ) + continue; + + bool inOldRange = Utility.InUpdateRange( oldLocation, m.m_Location ); + + if (m.m_NetState != null && ((isTeleport && (!m.m_NetState.HighSeas || !m_NoMoveHS)) || !inOldRange) && m.CanSee(this)) + { + m.m_NetState.Send(MobileIncoming.Create(m.m_NetState, m, this)); + + if (m.m_NetState.StygianAbyss) + { + if ( m_Poison != null ) + m.m_NetState.Send( new HealthbarPoison( this ) ); + + if ( m_Blessed || m_YellowHealthbar ) + m.m_NetState.Send( new HealthbarYellow( this ) ); + } + + if( IsDeadBondedPet ) + m.m_NetState.Send( new BondedStatus( 0, m_Serial, 1 ) ); + + if( ObjectPropertyList.Enabled ) + { + m.m_NetState.Send( OPLPacket ); + + //foreach ( Item item in m_Items ) + // m.m_NetState.Send( item.OPLPacket ); + } + } + + if( !inOldRange && CanSee( m ) ) + { + ourState.Send(MobileIncoming.Create(ourState, this, m)); + + if (ourState.StygianAbyss) + { + if ( m.Poisoned ) + ourState.Send( new HealthbarPoison( m ) ); + + if ( m.Blessed || m.YellowHealthbar ) + ourState.Send( new HealthbarYellow( m ) ); + } + + if( m.IsDeadBondedPet ) + ourState.Send( new BondedStatus( 0, m.m_Serial, 1 ) ); + + if( ObjectPropertyList.Enabled ) + { + ourState.Send( m.OPLPacket ); + + //foreach ( Item item in m.m_Items ) + // ourState.Send( item.OPLPacket ); + } + } + } + } + + eable.Free(); + } + else + { + eable = map.GetClientsInRange( newLocation ); + + // We're not attached to a client, so simply send an Incoming + foreach( NetState ns in eable ) + { + if (((isTeleport && (!ns.HighSeas || !m_NoMoveHS)) || !Utility.InUpdateRange(oldLocation, ns.Mobile.Location)) && ns.Mobile.CanSee(this)) + { + ns.Send(MobileIncoming.Create(ns, ns.Mobile, this)); + + if (ns.StygianAbyss) + { + if ( m_Poison != null ) + ns.Send( new HealthbarPoison( this ) ); + + if ( m_Blessed || m_YellowHealthbar ) + ns.Send( new HealthbarYellow( this ) ); + } + + if( IsDeadBondedPet ) + ns.Send( new BondedStatus( 0, m_Serial, 1 ) ); + + if( ObjectPropertyList.Enabled ) + { + ns.Send( OPLPacket ); + + //foreach ( Item item in m_Items ) + // ns.Send( item.OPLPacket ); + } + } + } + + eable.Free(); + } + } + + OnLocationChange( oldLocation ); + + this.Region.OnLocationChanged( this, oldLocation ); + } + } + + /// + /// Overridable. Virtual event invoked when changes. + /// + protected virtual void OnLocationChange( Point3D oldLocation ) + { + } + + #region Hair + + private HairInfo m_Hair; + private FacialHairInfo m_FacialHair; + + [CommandProperty( AccessLevel.GameMaster )] + public int HairItemID + { + get + { + if( m_Hair == null ) + return 0; + + return m_Hair.ItemID; + } + set + { + if( m_Hair == null && value > 0 ) + m_Hair = new HairInfo( value ); + else if( value <= 0 ) + m_Hair = null; + else + m_Hair.ItemID = value; + + Delta( MobileDelta.Hair ); + } + } + + // [CommandProperty( AccessLevel.GameMaster )] + // public int HairSerial { get { return HairInfo.FakeSerial( this ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int FacialHairItemID + { + get + { + if( m_FacialHair == null ) + return 0; + + return m_FacialHair.ItemID; + } + set + { + if( m_FacialHair == null && value > 0 ) + m_FacialHair = new FacialHairInfo( value ); + else if( value <= 0 ) + m_FacialHair = null; + else + m_FacialHair.ItemID = value; + + Delta( MobileDelta.FacialHair ); + } + } + + // [CommandProperty( AccessLevel.GameMaster )] + // public int FacialHairSerial { get { return FacialHairInfo.FakeSerial( this ); } } + + [CommandProperty( AccessLevel.GameMaster )] + public int HairHue + { + get + { + if( m_Hair == null ) + return 0; + return m_Hair.Hue; + } + set + { + if( m_Hair != null ) + { + m_Hair.Hue = value; + Delta( MobileDelta.Hair ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int FacialHairHue + { + get + { + if( m_FacialHair == null ) + return 0; + + return m_FacialHair.Hue; + } + set + { + if( m_FacialHair != null ) + { + m_FacialHair.Hue = value; + Delta( MobileDelta.FacialHair ); + } + } + } + + #endregion + + public bool HasFreeHand() + { + return FindItemOnLayer( Layer.TwoHanded ) == null; + } + + private IWeapon m_Weapon; + + [CommandProperty( AccessLevel.GameMaster )] + public virtual IWeapon Weapon + { + get + { + Item item = m_Weapon as Item; + + if( item != null && !item.Deleted && item.Parent == this && CanSee( item ) ) + return m_Weapon; + + m_Weapon = null; + + item = FindItemOnLayer( Layer.OneHanded ); + + if( item == null ) + item = FindItemOnLayer( Layer.TwoHanded ); + + if( item is IWeapon ) + return (m_Weapon = (IWeapon)item); + else + return GetDefaultWeapon(); + } + } + + public virtual IWeapon GetDefaultWeapon() + { + return m_DefaultWeapon; + } + + private BankBox m_BankBox; + + [CommandProperty( AccessLevel.GameMaster )] + public BankBox BankBox + { + get + { + if( m_BankBox != null && !m_BankBox.Deleted && m_BankBox.Parent == this ) + return m_BankBox; + + m_BankBox = FindItemOnLayer( Layer.Bank ) as BankBox; + + if( m_BankBox == null ) + AddItem( m_BankBox = new BankBox( this ) ); + + return m_BankBox; + } + } + + public BankBox FindBankNoCreate() + { + if( m_BankBox != null && !m_BankBox.Deleted && m_BankBox.Parent == this ) + return m_BankBox; + + m_BankBox = FindItemOnLayer( Layer.Bank ) as BankBox; + + return m_BankBox; + } + + private Container m_Backpack; + + [CommandProperty( AccessLevel.GameMaster )] + public Container Backpack + { + get + { + if( m_Backpack != null && !m_Backpack.Deleted && m_Backpack.Parent == this ) + return m_Backpack; + + return (m_Backpack = (FindItemOnLayer( Layer.Backpack ) as Container)); + } + } + + public virtual bool KeepsItemsOnDeath { get { return m_AccessLevel > AccessLevel.Player; } } + + public Item FindItemOnLayer( Layer layer ) + { + List eq = m_Items; + int count = eq.Count; + + for( int i = 0; i < count; ++i ) + { + Item item = eq[i]; + + if( !item.Deleted && item.Layer == layer ) + { + return item; + } + } + + return null; + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int X + { + get { return m_Location.m_X; } + set { Location = new Point3D( value, m_Location.m_Y, m_Location.m_Z ); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Y + { + get { return m_Location.m_Y; } + set { Location = new Point3D( m_Location.m_X, value, m_Location.m_Z ); } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Z + { + get { return m_Location.m_Z; } + set { Location = new Point3D( m_Location.m_X, m_Location.m_Y, value ); } + } + + #region Effects & Particles + + public void MovingEffect( IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode ) + { + Effects.SendMovingEffect( this, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode ); + } + + public void MovingEffect( IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes ) + { + Effects.SendMovingEffect( this, to, itemID, speed, duration, fixedDirection, explodes, 0, 0 ); + } + + public void MovingParticles( IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, int unknown ) + { + Effects.SendMovingParticles( this, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer, unknown ); + } + + public void MovingParticles( IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, int unknown ) + { + Effects.SendMovingParticles( this, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, (EffectLayer)255, unknown ); + } + + public void MovingParticles( IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown ) + { + Effects.SendMovingParticles( this, to, itemID, speed, duration, fixedDirection, explodes, effect, explodeEffect, explodeSound, unknown ); + } + + public void MovingParticles( IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound ) + { + Effects.SendMovingParticles( this, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, 0 ); + } + + public void FixedEffect( int itemID, int speed, int duration, int hue, int renderMode ) + { + Effects.SendTargetEffect( this, itemID, speed, duration, hue, renderMode ); + } + + public void FixedEffect( int itemID, int speed, int duration ) + { + Effects.SendTargetEffect( this, itemID, speed, duration, 0, 0 ); + } + + public void FixedParticles( int itemID, int speed, int duration, int effect, int hue, int renderMode, EffectLayer layer, int unknown ) + { + Effects.SendTargetParticles( this, itemID, speed, duration, hue, renderMode, effect, layer, unknown ); + } + + public void FixedParticles( int itemID, int speed, int duration, int effect, int hue, int renderMode, EffectLayer layer ) + { + Effects.SendTargetParticles( this, itemID, speed, duration, hue, renderMode, effect, layer, 0 ); + } + + public void FixedParticles( int itemID, int speed, int duration, int effect, EffectLayer layer, int unknown ) + { + Effects.SendTargetParticles( this, itemID, speed, duration, 0, 0, effect, layer, unknown ); + } + + public void FixedParticles( int itemID, int speed, int duration, int effect, EffectLayer layer ) + { + Effects.SendTargetParticles( this, itemID, speed, duration, 0, 0, effect, layer, 0 ); + } + + public void BoltEffect( int hue ) + { + Effects.SendBoltEffect( this, true, hue ); + } + + #endregion + + public void SendIncomingPacket() + { + if( m_Map != null ) + { + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state.Mobile.CanSee( this ) ) + { + state.Send(MobileIncoming.Create(state, state.Mobile, this)); + + if (state.StygianAbyss) + { + if ( m_Poison != null ) + state.Send( new HealthbarPoison( this ) ); + + if ( m_Blessed || m_YellowHealthbar ) + state.Send( new HealthbarYellow( this ) ); + } + + if( IsDeadBondedPet ) + state.Send( new BondedStatus( 0, m_Serial, 1 ) ); + + if( ObjectPropertyList.Enabled ) + { + state.Send( OPLPacket ); + + //foreach ( Item item in m_Items ) + // state.Send( item.OPLPacket ); + } + } + } + + eable.Free(); + } + } + + public bool PlaceInBackpack( Item item ) + { + if( item.Deleted ) + return false; + + Container pack = this.Backpack; + + return pack != null && pack.TryDropItem( this, item, false ); + } + + public bool AddToBackpack( Item item ) + { + if( item.Deleted ) + return false; + + if( !PlaceInBackpack( item ) ) + { + Point3D loc = m_Location; + Map map = m_Map; + + if( (map == null || map == Map.Internal) && m_LogoutMap != null ) + { + loc = m_LogoutLocation; + map = m_LogoutMap; + } + + item.MoveToWorld( loc, map ); + return false; + } + + return true; + } + + public virtual bool CheckLift( Mobile from, Item item, ref LRReason reject ) + { + return true; + } + + public virtual bool CheckNonlocalLift( Mobile from, Item item ) + { + if( from == this || (from.AccessLevel > this.AccessLevel && from.AccessLevel >= AccessLevel.GameMaster) ) + return true; + + return false; + } + + public bool HasTrade + { + get + { + if( m_NetState != null ) + return m_NetState.Trades.Count > 0; + + return false; + } + } + + public virtual bool CheckTrade( Mobile to, Item item, SecureTradeContainer cont, bool message, bool checkItems, int plusItems, int plusWeight ) + { + return true; + } + + /// + /// Overridable. Event invoked when a Mobile () drops an onto the Mobile. + /// + public virtual bool OnDragDrop( Mobile from, Item dropped ) + { + if( from == this ) + { + Container pack = this.Backpack; + + if( pack != null ) + return dropped.DropToItem( from, pack, new Point3D( -1, -1, 0 ) ); + + return false; + } + else if( from.Player && this.Player && from.Alive && this.Alive && from.InRange( Location, 2 ) ) + { + NetState ourState = m_NetState; + NetState theirState = from.m_NetState; + + if( ourState != null && theirState != null ) + { + SecureTradeContainer cont = theirState.FindTradeContainer( this ); + + if( !from.CheckTrade( this, dropped, cont, true, true, 0, 0 ) ) + return false; + + if( cont == null ) + cont = theirState.AddTrade( ourState ); + + cont.DropItem( dropped ); + + return true; + } + + return false; + } + else + { + return false; + } + } + + public virtual bool CheckEquip( Item item ) + { + for( int i = 0; i < m_Items.Count; ++i ) + if( m_Items[i].CheckConflictingLayer( this, item, item.Layer ) || item.CheckConflictingLayer( this, m_Items[i], m_Items[i].Layer ) ) + return false; + + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to wear . + /// + /// True if the request is accepted, false if otherwise. + public virtual bool OnEquip(Item item) + { + // For some reason OSI allows equipping quest items, but they are unmarked in the process + if (item.QuestItem) + { + item.QuestItem = false; + SendLocalizedMessage(1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item. + } + + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to lift . + /// + /// True if the lift is allowed, false if otherwise. + /// + /// The following example demonstrates usage. It will disallow any attempts to pick up a pick axe if the Mobile does not have enough strength. + /// + /// public override bool OnDragLift( Item item ) + /// { + /// if ( item is Pickaxe && this.Str < 60 ) + /// { + /// SendMessage( "That is too heavy for you to lift." ); + /// return false; + /// } + /// + /// return base.OnDragLift( item ); + /// } + /// + public virtual bool OnDragLift( Item item ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to drop into a . + /// + /// True if the drop is allowed, false if otherwise. + public virtual bool OnDroppedItemInto( Item item, Container container, Point3D loc ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to drop directly onto another , . This is the case of stacking items. + /// + /// True if the drop is allowed, false if otherwise. + public virtual bool OnDroppedItemOnto( Item item, Item target ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to drop into another , . The target item is most likely a . + /// + /// True if the drop is allowed, false if otherwise. + public virtual bool OnDroppedItemToItem( Item item, Item target, Point3D loc ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to give to a Mobile (). + /// + /// True if the drop is allowed, false if otherwise. + public virtual bool OnDroppedItemToMobile( Item item, Mobile target ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when the Mobile attempts to drop to the world at a . + /// + /// True if the drop is allowed, false if otherwise. + public virtual bool OnDroppedItemToWorld( Item item, Point3D location ) + { + return true; + } + + /// + /// Overridable. Virtual event when successfully uses while it's on this Mobile. + /// + /// + public virtual void OnItemUsed( Mobile from, Item item ) + { + } + + public virtual bool CheckNonlocalDrop( Mobile from, Item item, Item target ) + { + if( from == this || (from.AccessLevel > this.AccessLevel && from.AccessLevel >= AccessLevel.GameMaster) ) + return true; + + return false; + } + + public virtual bool CheckItemUse( Mobile from, Item item ) + { + return true; + } + + /// + /// Overridable. Virtual event invoked when successfully lifts from this Mobile. + /// + /// + public virtual void OnItemLifted( Mobile from, Item item ) + { + } + + public virtual bool AllowItemUse( Item item ) + { + return true; + } + + public virtual bool AllowEquipFrom( Mobile mob ) + { + return (mob == this || (mob.AccessLevel >= AccessLevel.GameMaster && mob.AccessLevel > this.AccessLevel)); + } + + public virtual bool EquipItem( Item item ) + { + if( item == null || item.Deleted || !item.CanEquip( this ) ) + return false; + + if( CheckEquip( item ) && OnEquip( item ) && item.OnEquip( this ) ) + { + if( m_Spell != null && !m_Spell.OnCasterEquiping( item ) ) + return false; + + //if ( m_Spell != null && m_Spell.State == SpellState.Casting ) + // m_Spell.Disturb( DisturbType.EquipRequest ); + + AddItem( item ); + return true; + } + + return false; + } + + internal int m_TypeRef; + + public Mobile( Serial serial ) + { + m_Region = Map.Internal.DefaultRegion; + m_Serial = serial; + m_Aggressors = new List(); + m_Aggressed = new List(); + m_NextSkillTime = DateTime.MinValue; + m_DamageEntries = new List(); + + Type ourType = this.GetType(); + m_TypeRef = World.m_MobileTypes.IndexOf( ourType ); + + if( m_TypeRef == -1 ) + { + World.m_MobileTypes.Add( ourType ); + m_TypeRef = World.m_MobileTypes.Count - 1; + } + } + + public Mobile() + { + m_Region = Map.Internal.DefaultRegion; + m_Serial = Server.Serial.NewMobile; + + DefaultMobileInit(); + + World.AddMobile( this ); + + Type ourType = this.GetType(); + m_TypeRef = World.m_MobileTypes.IndexOf( ourType ); + + if( m_TypeRef == -1 ) + { + World.m_MobileTypes.Add( ourType ); + m_TypeRef = World.m_MobileTypes.Count - 1; + } + } + + public void DefaultMobileInit() + { + m_StatCap = 225; + m_FollowersMax = 5; + m_Skills = new Skills( this ); + m_Items = new List(); + m_StatMods = new List(); + m_SkillMods = new List(); + Map = Map.Internal; + m_AutoPageNotify = true; + m_Aggressors = new List(); + m_Aggressed = new List(); + m_Virtues = new VirtueInfo(); + m_Stabled = new List(); + m_DamageEntries = new List(); + + m_NextSkillTime = DateTime.MinValue; + m_CreationTime = DateTime.Now; + } + + private static Queue m_DeltaQueue = new Queue(); + + private bool m_InDeltaQueue; + private MobileDelta m_DeltaFlags; + + public virtual void Delta( MobileDelta flag ) + { + if( m_Map == null || m_Map == Map.Internal || m_Deleted ) + return; + + m_DeltaFlags |= flag; + + if( !m_InDeltaQueue ) + { + m_InDeltaQueue = true; + + m_DeltaQueue.Enqueue( this ); + } + + Core.Set(); + } + + private bool m_NoMoveHS; + + public bool NoMoveHS + { + get { return m_NoMoveHS; } + set { m_NoMoveHS = value; } + } + + #region GetDirectionTo[..] + + public Direction GetDirectionTo( int x, int y ) + { + int dx = m_Location.m_X - x; + int dy = m_Location.m_Y - y; + + int rx = (dx - dy) * 44; + int ry = (dx + dy) * 44; + + int ax = Math.Abs( rx ); + int ay = Math.Abs( ry ); + + Direction ret; + + if( ((ay >> 1) - ax) >= 0 ) + ret = (ry > 0) ? Direction.Up : Direction.Down; + else if( ((ax >> 1) - ay) >= 0 ) + ret = (rx > 0) ? Direction.Left : Direction.Right; + else if( rx >= 0 && ry >= 0 ) + ret = Direction.West; + else if( rx >= 0 && ry < 0 ) + ret = Direction.South; + else if( rx < 0 && ry < 0 ) + ret = Direction.East; + else + ret = Direction.North; + + return ret; + } + + public Direction GetDirectionTo( Point2D p ) + { + return GetDirectionTo( p.m_X, p.m_Y ); + } + + public Direction GetDirectionTo( Point3D p ) + { + return GetDirectionTo( p.m_X, p.m_Y ); + } + + public Direction GetDirectionTo( IPoint2D p ) + { + if( p == null ) + return Direction.North; + + return GetDirectionTo( p.X, p.Y ); + } + + #endregion + + public virtual void ProcessDelta() + { + Mobile m = this; + MobileDelta delta; + + delta = m.m_DeltaFlags; + + if( delta == MobileDelta.None ) + return; + + MobileDelta attrs = delta & MobileDelta.Attributes; + + m.m_DeltaFlags = MobileDelta.None; + m.m_InDeltaQueue = false; + + bool sendHits = false, sendStam = false, sendMana = false, sendAll = false, sendAny = false; + bool sendIncoming = false, sendNonlocalIncoming = false; + bool sendUpdate = false, sendRemove = false; + bool sendPublicStats = false, sendPrivateStats = false; + bool sendMoving = false, sendNonlocalMoving = false; + bool sendOPLUpdate = ObjectPropertyList.Enabled && (delta & MobileDelta.Properties) != 0; + + bool sendHair = false, sendFacialHair = false, removeHair = false, removeFacialHair = false; + + bool sendHealthbarPoison = false, sendHealthbarYellow = false; + + if( attrs != MobileDelta.None ) + { + sendAny = true; + + if( attrs == MobileDelta.Attributes ) + { + sendAll = true; + } + else + { + sendHits = ((attrs & MobileDelta.Hits) != 0); + sendStam = ((attrs & MobileDelta.Stam) != 0); + sendMana = ((attrs & MobileDelta.Mana) != 0); + } + } + + if( (delta & MobileDelta.GhostUpdate) != 0 ) + { + sendNonlocalIncoming = true; + } + + if( (delta & MobileDelta.Hue) != 0 ) + { + sendNonlocalIncoming = true; + sendUpdate = true; + sendRemove = true; + } + + if( (delta & MobileDelta.Direction) != 0 ) + { + sendNonlocalMoving = true; + sendUpdate = true; + } + + if( (delta & MobileDelta.Body) != 0 ) + { + sendUpdate = true; + sendIncoming = true; + } + + /*if ( (delta & MobileDelta.Hue) != 0 ) + { + sendNonlocalIncoming = true; + sendUpdate = true; + } + else if ( (delta & (MobileDelta.Direction | MobileDelta.Body)) != 0 ) + { + sendNonlocalMoving = true; + sendUpdate = true; + } + else*/ + if( (delta & (MobileDelta.Flags | MobileDelta.Noto)) != 0 ) + { + sendMoving = true; + } + + if( (delta & MobileDelta.HealthbarPoison) != 0 ) + { + sendHealthbarPoison = true; + } + + if( (delta & MobileDelta.HealthbarYellow) != 0 ) + { + sendHealthbarYellow = true; + } + + if( (delta & MobileDelta.Name) != 0 ) + { + sendAll = false; + sendHits = false; + sendAny = sendStam || sendMana; + sendPublicStats = true; + } + + if( (delta & (MobileDelta.WeaponDamage | MobileDelta.Resistances | MobileDelta.Stat | MobileDelta.Weight | MobileDelta.Gold | MobileDelta.Armor | MobileDelta.StatCap | MobileDelta.Followers | MobileDelta.TithingPoints | MobileDelta.Race)) != 0 ) + { + sendPrivateStats = true; + } + + if( (delta & MobileDelta.Hair) != 0 ) + { + if( m.HairItemID <= 0 ) + removeHair = true; + + sendHair = true; + } + + if( (delta & MobileDelta.FacialHair) != 0 ) + { + if( m.FacialHairItemID <= 0 ) + removeFacialHair = true; + + sendFacialHair = true; + } + + Packet[][] cache = m_MovingPacketCache; + + if( sendMoving || sendNonlocalMoving || sendHealthbarPoison || sendHealthbarYellow ) + { + for( int i = 0; i < cache.Length; ++i ) + for( int j = 0; j < cache[i].Length; ++j ) + Packet.Release( ref cache[i][j] ); + } + + NetState ourState = m.m_NetState; + + if( ourState != null ) + { + if( sendUpdate ) + { + ourState.Sequence = 0; + + if ( ourState.StygianAbyss ) + ourState.Send( new MobileUpdate( m ) ); + else + ourState.Send( new MobileUpdateOld( m ) ); + + ClearFastwalkStack(); + } + + if (sendIncoming) + ourState.Send(MobileIncoming.Create(ourState, m, m)); + + if (ourState.StygianAbyss) + { + if( sendMoving ) + { + int noto = Notoriety.Compute( m, m ); + ourState.Send( cache[0][noto] = Packet.Acquire( new MobileMoving( m, noto, this ) ) ); + // Scriptiz : 3e param�tre pour les hallucinations + } + + if ( sendHealthbarPoison ) + ourState.Send( new HealthbarPoison( m ) ); + + if ( sendHealthbarYellow ) + ourState.Send( new HealthbarYellow( m ) ); + } else { + if( sendMoving || sendHealthbarPoison || sendHealthbarYellow ) + { + int noto = Notoriety.Compute( m, m ); + ourState.Send( cache[1][noto] = Packet.Acquire( new MobileMovingOld( m, noto, this ) ) ); + // Scriptiz : 3e param�tre pour les hallucinations + } + } + + if( sendPublicStats || sendPrivateStats ) + { + ourState.Send( new MobileStatusExtended( m, m_NetState ) ); + } + else if( sendAll ) + { + ourState.Send( new MobileAttributes( m ) ); + } + else if( sendAny ) + { + if( sendHits ) + ourState.Send( new MobileHits( m ) ); + + if( sendStam ) + ourState.Send( new MobileStam( m ) ); + + if( sendMana ) + ourState.Send( new MobileMana( m ) ); + } + + if( sendStam || sendMana ) + { + IParty ip = m_Party as IParty; + + if( ip != null && sendStam ) + ip.OnStamChanged( this ); + + if( ip != null && sendMana ) + ip.OnManaChanged( this ); + } + + if( sendHair ) + { + if( removeHair ) + ourState.Send( new RemoveHair( m ) ); + else + ourState.Send( new HairEquipUpdate( m ) ); + } + + if( sendFacialHair ) + { + if( removeFacialHair ) + ourState.Send( new RemoveFacialHair( m ) ); + else + ourState.Send( new FacialHairEquipUpdate( m ) ); + } + + if( sendOPLUpdate ) + ourState.Send( OPLPacket ); + } + + sendMoving = sendMoving || sendNonlocalMoving; + sendIncoming = sendIncoming || sendNonlocalIncoming; + sendHits = sendHits || sendAll; + + if( m.m_Map != null && (sendRemove || sendIncoming || sendPublicStats || sendHits || sendMoving || sendOPLUpdate || sendHair || sendFacialHair || sendHealthbarPoison || sendHealthbarYellow) ) + { + Mobile beholder; + + IPooledEnumerable eable = m.Map.GetClientsInRange( m.m_Location ); + + Packet hitsPacket = null; + Packet statPacketTrue = null, statPacketFalse = null; + Packet deadPacket = null; + Packet hairPacket = null, facialhairPacket = null; + Packet hbpPacket = null, hbyPacket = null; + + foreach( NetState state in eable ) + { + beholder = state.Mobile; + + if( beholder != m && beholder.CanSee( m ) ) + { + if( sendRemove ) + state.Send( m.RemovePacket ); + + if( sendIncoming ) + { + state.Send(MobileIncoming.Create(state, beholder, m)); + + if( m.IsDeadBondedPet ) + { + if( deadPacket == null ) + deadPacket = Packet.Acquire( new BondedStatus( 0, m.m_Serial, 1 ) ); + + state.Send( deadPacket ); + } + } + + if ( state.StygianAbyss ) { + if( sendMoving ) + { + int noto = Notoriety.Compute( beholder, m ); + + Packet p = cache[0][noto]; + + if( p == null ) + cache[0][noto] = p = Packet.Acquire( new MobileMoving( m, noto, this ) ); + // Scriptiz : 3e param�tre pour les hallucinations + + state.Send( p ); + } + + if ( sendHealthbarPoison ) { + if ( hbpPacket == null ) + hbpPacket = Packet.Acquire( new HealthbarPoison( m ) ); + + state.Send( hbpPacket ); + } + + if ( sendHealthbarYellow ) { + if ( hbyPacket == null ) + hbyPacket = Packet.Acquire( new HealthbarYellow( m ) ); + state.Send( hbyPacket ); + } + } else { + if( sendMoving || sendHealthbarPoison || sendHealthbarYellow ) + { + int noto = Notoriety.Compute( beholder, m ); + + Packet p = cache[1][noto]; + + if( p == null ) + cache[1][noto] = p = Packet.Acquire( new MobileMovingOld( m, noto, this ) ); + // Scriptiz : 3e param�tre pour les hallucinations + + state.Send( p ); + } + } + + if( sendPublicStats ) + { + if( m.CanBeRenamedBy( beholder ) ) + { + if( statPacketTrue == null ) + statPacketTrue = Packet.Acquire( new MobileStatusCompact( true, m ) ); + + state.Send( statPacketTrue ); + } + else + { + if( statPacketFalse == null ) + statPacketFalse = Packet.Acquire( new MobileStatusCompact( false, m ) ); + + state.Send( statPacketFalse ); + } + } + else if( sendHits ) + { + if( hitsPacket == null ) + hitsPacket = Packet.Acquire( new MobileHitsN( m ) ); + + state.Send( hitsPacket ); + } + + if( sendHair ) + { + if( hairPacket == null ) + { + if( removeHair ) + hairPacket = Packet.Acquire( new RemoveHair( m ) ); + else + hairPacket = Packet.Acquire( new HairEquipUpdate( m ) ); + } + + state.Send( hairPacket ); + } + + if( sendFacialHair ) + { + if( facialhairPacket == null ) + { + if( removeFacialHair ) + facialhairPacket = Packet.Acquire( new RemoveFacialHair( m ) ); + else + facialhairPacket = Packet.Acquire( new FacialHairEquipUpdate( m ) ); + } + + state.Send( facialhairPacket ); + } + + if( sendOPLUpdate ) + state.Send( OPLPacket ); + } + } + + Packet.Release( hitsPacket ); + Packet.Release( statPacketTrue ); + Packet.Release( statPacketFalse ); + Packet.Release( deadPacket ); + Packet.Release( hairPacket ); + Packet.Release( facialhairPacket ); + Packet.Release( hbpPacket ); + Packet.Release( hbyPacket ); + + eable.Free(); + } + + if( sendMoving || sendNonlocalMoving || sendHealthbarPoison || sendHealthbarYellow ) + { + for( int i = 0; i < cache.Length; ++i ) + for( int j = 0; j < cache.Length; ++j ) + Packet.Release( ref cache[i][j] ); + } + } + + public static void ProcessDeltaQueue() + { + int count = m_DeltaQueue.Count; + int index = 0; + + while( m_DeltaQueue.Count > 0 && index++ < count ) + m_DeltaQueue.Dequeue().ProcessDelta(); + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Kills + { + get + { + return m_Kills; + } + set + { + int oldValue = m_Kills; + + if( m_Kills != value ) + { + m_Kills = value; + + if( m_Kills < 0 ) + m_Kills = 0; + + if( (oldValue >= 5) != (m_Kills >= 5) ) + { + Delta( MobileDelta.Noto ); + InvalidateProperties(); + } + + OnKillsChange( oldValue ); + } + } + } + + public virtual void OnKillsChange( int oldValue ) + { + } + + [CommandProperty( AccessLevel.GameMaster )] + public int ShortTermMurders + { + get + { + return m_ShortTermMurders; + } + set + { + if( m_ShortTermMurders != value ) + { + m_ShortTermMurders = value; + + if( m_ShortTermMurders < 0 ) + m_ShortTermMurders = 0; + } + } + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public bool Criminal + { + get + { + return m_Criminal; + } + set + { + if( m_Criminal != value ) + { + m_Criminal = value; + Delta( MobileDelta.Noto ); + InvalidateProperties(); + } + + if( m_Criminal ) + { + if( m_ExpireCriminal == null ) + m_ExpireCriminal = new ExpireCriminalTimer( this ); + else + m_ExpireCriminal.Stop(); + + m_ExpireCriminal.Start(); + } + else if( m_ExpireCriminal != null ) + { + m_ExpireCriminal.Stop(); + m_ExpireCriminal = null; + } + } + } + + public bool CheckAlive() + { + return CheckAlive( true ); + } + + public bool CheckAlive( bool message ) + { + if( !Alive ) + { + if( message ) + this.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1019048 ); // I am dead and cannot do that. + + return false; + } + else + { + return true; + } + } + + #region Overhead messages + + public void PublicOverheadMessage( MessageType type, int hue, bool ascii, string text ) + { + PublicOverheadMessage( type, hue, ascii, text, true ); + } + + public void PublicOverheadMessage( MessageType type, int hue, bool ascii, string text, bool noLineOfSight ) + { + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state.Mobile.CanSee( this ) && (noLineOfSight || state.Mobile.InLOS( this )) ) + { + if( p == null ) + { + if( ascii ) + p = new AsciiMessage( m_Serial, Body, type, hue, 3, Name, text ); + else + p = new UnicodeMessage( m_Serial, Body, type, hue, 3, m_Language, Name, text ); + + p.Acquire(); + } + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + public void PublicOverheadMessage( MessageType type, int hue, int number ) + { + PublicOverheadMessage( type, hue, number, "", true ); + } + + public void PublicOverheadMessage( MessageType type, int hue, int number, string args ) + { + PublicOverheadMessage( type, hue, number, args, true ); + } + + public void PublicOverheadMessage( MessageType type, int hue, int number, string args, bool noLineOfSight ) + { + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state.Mobile.CanSee( this ) && (noLineOfSight || state.Mobile.InLOS( this )) ) + { + if( p == null ) + p = Packet.Acquire( new MessageLocalized( m_Serial, Body, type, hue, 3, number, Name, args ) ); + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + public void PublicOverheadMessage( MessageType type, int hue, int number, AffixType affixType, string affix, string args ) + { + PublicOverheadMessage( type, hue, number, affixType, affix, args, true ); + } + + public void PublicOverheadMessage( MessageType type, int hue, int number, AffixType affixType, string affix, string args, bool noLineOfSight ) + { + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state.Mobile.CanSee( this ) && (noLineOfSight || state.Mobile.InLOS( this )) ) + { + if( p == null ) + p = Packet.Acquire( new MessageLocalizedAffix( m_Serial, Body, type, hue, 3, number, Name, affixType, affix, args ) ); + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + public void PrivateOverheadMessage( MessageType type, int hue, bool ascii, string text, NetState state ) + { + if( state == null ) + return; + + if( ascii ) + state.Send( new AsciiMessage( m_Serial, Body, type, hue, 3, Name, text ) ); + else + state.Send( new UnicodeMessage( m_Serial, Body, type, hue, 3, m_Language, Name, text ) ); + } + + public void PrivateOverheadMessage( MessageType type, int hue, int number, NetState state ) + { + PrivateOverheadMessage( type, hue, number, "", state ); + } + + public void PrivateOverheadMessage( MessageType type, int hue, int number, string args, NetState state ) + { + if( state == null ) + return; + + state.Send( new MessageLocalized( m_Serial, Body, type, hue, 3, number, Name, args ) ); + } + + public void LocalOverheadMessage( MessageType type, int hue, bool ascii, string text ) + { + NetState ns = m_NetState; + + if( ns != null ) + { + if( ascii ) + ns.Send( new AsciiMessage( m_Serial, Body, type, hue, 3, Name, text ) ); + else + ns.Send( new UnicodeMessage( m_Serial, Body, type, hue, 3, m_Language, Name, text ) ); + } + } + + public void LocalOverheadMessage( MessageType type, int hue, int number ) + { + LocalOverheadMessage( type, hue, number, "" ); + } + + public void LocalOverheadMessage( MessageType type, int hue, int number, string args ) + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( new MessageLocalized( m_Serial, Body, type, hue, 3, number, Name, args ) ); + } + + public void NonlocalOverheadMessage( MessageType type, int hue, int number ) + { + NonlocalOverheadMessage( type, hue, number, "" ); + } + + public void NonlocalOverheadMessage( MessageType type, int hue, int number, string args ) + { + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state != m_NetState && state.Mobile.CanSee( this ) ) + { + if( p == null ) + p = Packet.Acquire( new MessageLocalized( m_Serial, Body, type, hue, 3, number, Name, args ) ); + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + public void NonlocalOverheadMessage( MessageType type, int hue, bool ascii, string text ) + { + if( m_Map != null ) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + + foreach( NetState state in eable ) + { + if( state != m_NetState && state.Mobile.CanSee( this ) ) + { + if( p == null ) + { + if( ascii ) + p = new AsciiMessage( m_Serial, Body, type, hue, 3, Name, text ); + else + p = new UnicodeMessage( m_Serial, Body, type, hue, 3, Language, Name, text ); + + p.Acquire(); + } + + state.Send( p ); + } + } + + Packet.Release( p ); + + eable.Free(); + } + } + + #endregion + + #region SendLocalizedMessage + + public void SendLocalizedMessage( int number ) + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( MessageLocalized.InstantiateGeneric( number ) ); + } + + public void SendLocalizedMessage( int number, string args ) + { + SendLocalizedMessage( number, args, 0x3B2 ); + } + + public void SendLocalizedMessage( int number, string args, int hue ) + { + if( hue == 0x3B2 && (args == null || args.Length == 0) ) + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( MessageLocalized.InstantiateGeneric( number ) ); + } + else + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( new MessageLocalized( Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", args ) ); + } + } + + public void SendLocalizedMessage( int number, bool append, string affix ) + { + SendLocalizedMessage( number, append, affix, "", 0x3B2 ); + } + + public void SendLocalizedMessage( int number, bool append, string affix, string args ) + { + SendLocalizedMessage(number, append, affix, args, 0x3B2); + } + + public void SendLocalizedMessage( int number, bool append, string affix, string args, int hue ) + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( new MessageLocalizedAffix( Serial.MinusOne, -1, MessageType.Regular, hue, 3, number, "System", (append ? AffixType.Append : AffixType.Prepend) | AffixType.System, affix, args ) ); + } + + #endregion + + public void LaunchBrowser( string url ) + { + if( m_NetState != null ) + m_NetState.LaunchBrowser( url ); + } + + #region Send[ASCII]Message + + public void SendMessage( string text ) + { + SendMessage( 0x3B2, text ); + } + + public void SendMessage( string format, params object[] args ) + { + SendMessage( 0x3B2, String.Format( format, args ) ); + } + + public void SendMessage( int hue, string text ) + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( new UnicodeMessage( Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text ) ); + } + + public void SendMessage( int hue, string format, params object[] args ) + { + SendMessage( hue, String.Format( format, args ) ); + } + + public void SendAsciiMessage( string text ) + { + SendAsciiMessage( 0x3B2, text ); + } + + public void SendAsciiMessage( string format, params object[] args ) + { + SendAsciiMessage( 0x3B2, String.Format( format, args ) ); + } + + public void SendAsciiMessage( int hue, string text ) + { + NetState ns = m_NetState; + + if( ns != null ) + ns.Send( new AsciiMessage( Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text ) ); + } + + public void SendAsciiMessage( int hue, string format, params object[] args ) + { + SendAsciiMessage( hue, String.Format( format, args ) ); + } + + #endregion + + #region InRange + public bool InRange( Point2D p, int range ) + { + return (p.m_X >= (m_Location.m_X - range)) + && (p.m_X <= (m_Location.m_X + range)) + && (p.m_Y >= (m_Location.m_Y - range)) + && (p.m_Y <= (m_Location.m_Y + range)); + } + + public bool InRange( Point3D p, int range ) + { + return (p.m_X >= (m_Location.m_X - range)) + && (p.m_X <= (m_Location.m_X + range)) + && (p.m_Y >= (m_Location.m_Y - range)) + && (p.m_Y <= (m_Location.m_Y + range)); + } + + public bool InRange( IPoint2D p, int range ) + { + return (p.X >= (m_Location.m_X - range)) + && (p.X <= (m_Location.m_X + range)) + && (p.Y >= (m_Location.m_Y - range)) + && (p.Y <= (m_Location.m_Y + range)); + } + #endregion + + public void InitStats( int str, int dex, int intel ) + { + m_Str = str; + m_Dex = dex; + m_Int = intel; + + Hits = HitsMax; + Stam = StamMax; + Mana = ManaMax; + + Delta( MobileDelta.Stat | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana ); + } + + public virtual void DisplayPaperdollTo( Mobile to ) + { + EventSink.InvokePaperdollRequest( new PaperdollRequestEventArgs( to, this ) ); + } + + private static bool m_DisableDismountInWarmode; + + public static bool DisableDismountInWarmode { get { return m_DisableDismountInWarmode; } set { m_DisableDismountInWarmode = value; } } + + #region OnDoubleClick[..] + + /// + /// Overridable. Event invoked when the Mobile is double clicked. By default, this method can either dismount or open the paperdoll. + /// + /// + /// + public virtual void OnDoubleClick( Mobile from ) + { + if( this == from && (!m_DisableDismountInWarmode || !m_Warmode) ) + { + IMount mount = Mount; + + if( mount != null ) + { + mount.Rider = null; + return; + } + } + + if( CanPaperdollBeOpenedBy( from ) ) + DisplayPaperdollTo( from ); + } + + /// + /// Overridable. Virtual event invoked when the Mobile is double clicked by someone who is over 18 tiles away. + /// + /// + public virtual void OnDoubleClickOutOfRange( Mobile from ) + { + } + + /// + /// Overridable. Virtual event invoked when the Mobile is double clicked by someone who can no longer see the Mobile. This may happen, for example, using 'Last Object' after the Mobile has hidden. + /// + /// + public virtual void OnDoubleClickCantSee( Mobile from ) + { + } + + /// + /// Overridable. Event invoked when the Mobile is double clicked by someone who is not alive. Similar to , this method will show the paperdoll. It does not, however, provide any dismount functionality. + /// + /// + public virtual void OnDoubleClickDead( Mobile from ) + { + if( CanPaperdollBeOpenedBy( from ) ) + DisplayPaperdollTo( from ); + } + + #endregion + + /// + /// Overridable. Event invoked when the Mobile requests to open his own paperdoll via the 'Open Paperdoll' macro. + /// + public virtual void OnPaperdollRequest() + { + if( CanPaperdollBeOpenedBy( this ) ) + DisplayPaperdollTo( this ); + } + + private static int m_BodyWeight = 14; + + public static int BodyWeight { get { return m_BodyWeight; } set { m_BodyWeight = value; } } + + /// + /// Overridable. Event invoked when wants to see this Mobile's stats. + /// + /// + public virtual void OnStatsQuery( Mobile from ) + { + if( from.Map == this.Map && Utility.InUpdateRange( this, from ) && from.CanSee( this ) ) + from.Send( new MobileStatus( from, this, m_NetState ) ); + + if( from == this ) + Send( new StatLockInfo( this ) ); + + IParty ip = m_Party as IParty; + + if( ip != null ) + ip.OnStatsQuery( from, this ); + } + + /// + /// Overridable. Event invoked when wants to see this Mobile's skills. + /// + public virtual void OnSkillsQuery( Mobile from ) + { + if( from == this ) + Send( new SkillUpdate( m_Skills ) ); + } + + /// + /// Overridable. Virtual event invoked when changes. + /// + public virtual void OnRegionChange( Region Old, Region New ) + { + } + + private Item m_MountItem; + + [CommandProperty( AccessLevel.GameMaster )] + public IMount Mount + { + get + { + IMountItem mountItem = null; + + if( m_MountItem != null && !m_MountItem.Deleted && m_MountItem.Parent == this ) + mountItem = (IMountItem)m_MountItem; + + if( mountItem == null ) + m_MountItem = (mountItem = (FindItemOnLayer( Layer.Mount ) as IMountItem)) as Item; + + return mountItem == null ? null : mountItem.Mount; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Mounted + { + get + { + return (Mount != null); + } + } + + private QuestArrow m_QuestArrow; + + public QuestArrow QuestArrow + { + get + { + return m_QuestArrow; + } + set + { + if( m_QuestArrow != value ) + { + if( m_QuestArrow != null ) + m_QuestArrow.Stop(); + + m_QuestArrow = value; + } + } + } + + private static string[] m_GuildTypes = new string[] + { + "", + " (Chaos)", + " (Order)" + }; + + public virtual bool CanTarget { get { return true; } } + public virtual bool ClickTitle { get { return true; } } + + public virtual bool PropertyTitle { get { return m_OldPropertyTitles ? ClickTitle : true; } } + + private static bool m_DisableHiddenSelfClick = true; + private static bool m_AsciiClickMessage = true; + private static bool m_GuildClickMessage = true; + private static bool m_OldPropertyTitles; + + public static bool DisableHiddenSelfClick { get { return m_DisableHiddenSelfClick; } set { m_DisableHiddenSelfClick = value; } } + public static bool AsciiClickMessage { get { return m_AsciiClickMessage; } set { m_AsciiClickMessage = value; } } + public static bool GuildClickMessage { get { return m_GuildClickMessage; } set { m_GuildClickMessage = value; } } + public static bool OldPropertyTitles { get { return m_OldPropertyTitles; } set { m_OldPropertyTitles = value; } } + + public virtual bool ShowFameTitle { get { return true; } }//(m_Player || m_Body.IsHuman) && m_Fame >= 10000; } + + /// + /// Overridable. Event invoked when the Mobile is single clicked. + /// + public virtual void OnSingleClick( Mobile from ) + { + if( m_Deleted ) + return; + else if( AccessLevel == AccessLevel.Player && DisableHiddenSelfClick && Hidden && from == this ) + return; + + if( m_GuildClickMessage ) + { + BaseGuild guild = m_Guild; + + if( guild != null && (m_DisplayGuildTitle || (m_Player && guild.Type != GuildType.Regular)) ) + { + string title = GuildTitle; + string type; + + if( title == null ) + title = ""; + else + title = title.Trim(); + + if( guild.Type >= 0 && (int)guild.Type < m_GuildTypes.Length ) + type = m_GuildTypes[(int)guild.Type]; + else + type = ""; + + string text = String.Format( title.Length <= 0 ? "[{1}]{2}" : "[{0}, {1}]{2}", title, guild.Abbreviation, type ); + + PrivateOverheadMessage( MessageType.Regular, SpeechHue, true, text, from.NetState ); + } + } + + int hue; + + if( m_NameHue != -1 ) + hue = m_NameHue; + else if( AccessLevel > AccessLevel.Player ) + hue = 11; + else + hue = Notoriety.GetHue( Notoriety.Compute( from, this ) ); + + string name = Name; + + if( name == null ) + name = String.Empty; + + string prefix = ""; + + if( ShowFameTitle && (m_Player || m_Body.IsHuman) && m_Fame >= 10000 ) + prefix = (m_Female ? "La Grande" : "Le Grand"); + + string suffix = ""; + + if( ClickTitle && Title != null && Title.Length > 0 ) + suffix = Title; + + suffix = ApplyNameSuffix( suffix ); + + string val; + + if( prefix.Length > 0 && suffix.Length > 0 ) + val = String.Concat( prefix, " ", name, " ", suffix ); + else if( prefix.Length > 0 ) + val = String.Concat( prefix, " ", name ); + else if( suffix.Length > 0 ) + val = String.Concat( name, " ", suffix ); + else + val = name; + + PrivateOverheadMessage( MessageType.Label, hue, m_AsciiClickMessage, val, from.NetState ); + } + + public bool CheckSkill( SkillName skill, double minSkill, double maxSkill ) + { + if( m_SkillCheckLocationHandler == null ) + return false; + else + return m_SkillCheckLocationHandler( this, skill, minSkill, maxSkill ); + } + + public bool CheckSkill( SkillName skill, double chance ) + { + if( m_SkillCheckDirectLocationHandler == null ) + return false; + else + return m_SkillCheckDirectLocationHandler( this, skill, chance ); + } + + public bool CheckTargetSkill( SkillName skill, object target, double minSkill, double maxSkill ) + { + if( m_SkillCheckTargetHandler == null ) + return false; + else + return m_SkillCheckTargetHandler( this, skill, target, minSkill, maxSkill ); + } + + public bool CheckTargetSkill( SkillName skill, object target, double chance ) + { + if( m_SkillCheckDirectTargetHandler == null ) + return false; + else + return m_SkillCheckDirectTargetHandler( this, skill, target, chance ); + } + + public virtual void DisruptiveAction() + { + if( Meditating ) + { + Meditating = false; + SendLocalizedMessage( 500134 ); // You stop meditating. + } + } + + #region Armor + public Item ShieldArmor + { + get + { + return FindItemOnLayer( Layer.TwoHanded ) as Item; + } + } + + public Item NeckArmor + { + get + { + return FindItemOnLayer( Layer.Neck ) as Item; + } + } + + public Item HandArmor + { + get + { + return FindItemOnLayer( Layer.Gloves ) as Item; + } + } + + public Item HeadArmor + { + get + { + return FindItemOnLayer( Layer.Helm ) as Item; + } + } + + public Item ArmsArmor + { + get + { + return FindItemOnLayer( Layer.Arms ) as Item; + } + } + + public Item LegsArmor + { + get + { + Item ar = FindItemOnLayer( Layer.InnerLegs ) as Item; + + if( ar == null ) + ar = FindItemOnLayer( Layer.Pants ) as Item; + + return ar; + } + } + + public Item ChestArmor + { + get + { + Item ar = FindItemOnLayer( Layer.InnerTorso ) as Item; + + if( ar == null ) + ar = FindItemOnLayer( Layer.Shirt ) as Item; + + return ar; + } + } + + public Item Talisman + { + get + { + return FindItemOnLayer( Layer.Talisman ) as Item; + } + } + #endregion + + /// + /// Gets or sets the maximum attainable value for , , and . + /// + [CommandProperty( AccessLevel.GameMaster )] + public int StatCap + { + get + { + return m_StatCap; + } + set + { + if( m_StatCap != value ) + { + m_StatCap = value; + + Delta( MobileDelta.StatCap ); + } + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool Meditating + { + get + { + return m_Meditating; + } + set + { + m_Meditating = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public virtual bool CanSwim + { + get + { + return m_CanSwim; + } + set + { + m_CanSwim = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool CantWalk + { + get + { + return m_CantWalk; + } + set + { + m_CantWalk = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public bool CanHearGhosts + { + get + { + return m_CanHearGhosts || AccessLevel >= AccessLevel.Counselor; + } + set + { + m_CanHearGhosts = value; + } + } + + [CommandProperty( AccessLevel.GameMaster )] + public int RawStatTotal + { + get + { + return RawStr + RawDex + RawInt; + } + } + + public DateTime NextSpellTime + { + get + { + return m_NextSpellTime; + } + set + { + m_NextSpellTime = value; + } + } + + /// + /// Overridable. Virtual event invoked when the sector this Mobile is in gets activated. + /// + public virtual void OnSectorActivate() + { + } + + /// + /// Overridable. Virtual event invoked when the sector this Mobile is in gets deactivated. + /// + public virtual void OnSectorDeactivate() + { + } + } +} \ No newline at end of file diff --git a/Server/Movement.cs b/Server/Movement.cs new file mode 100644 index 0000000..be99070 --- /dev/null +++ b/Server/Movement.cs @@ -0,0 +1,75 @@ +/*************************************************************************** + * Movement.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Movement.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; + +namespace Server.Movement +{ + public static class Movement + { + private static IMovementImpl m_Impl; + + public static IMovementImpl Impl + { + get{ return m_Impl; } + set{ m_Impl = value; } + } + + public static bool CheckMovement( Mobile m, Direction d, out int newZ ) + { + if ( m_Impl != null ) + return m_Impl.CheckMovement( m, d, out newZ ); + + newZ = m.Z; + return false; + } + + public static bool CheckMovement( Mobile m, Map map, Point3D loc, Direction d, out int newZ ) + { + if ( m_Impl != null ) + return m_Impl.CheckMovement( m, map, loc, d, out newZ ); + + newZ = m.Z; + return false; + } + + public static void Offset( Direction d, ref int x, ref int y ) + { + switch ( d & Direction.Mask ) + { + case Direction.North: --y; break; + case Direction.South: ++y; break; + case Direction.West: --x; break; + case Direction.East: ++x; break; + case Direction.Right: ++x; --y; break; + case Direction.Left: --x; ++y; break; + case Direction.Down: ++x; ++y; break; + case Direction.Up: --x; --y; break; + } + } + } + + public interface IMovementImpl + { + bool CheckMovement( Mobile m, Direction d, out int newZ ); + bool CheckMovement( Mobile m, Map map, Point3D loc, Direction d, out int newZ ); + } +} \ No newline at end of file diff --git a/Server/MultiData.cs b/Server/MultiData.cs new file mode 100644 index 0000000..88d0f24 --- /dev/null +++ b/Server/MultiData.cs @@ -0,0 +1,596 @@ +/*************************************************************************** + * MultiData.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: MultiData.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.IO; + +namespace Server +{ + public static class MultiData + { + private static MultiComponentList[] m_Components; + + private static FileStream m_Index, m_Stream; + private static BinaryReader m_IndexReader, m_StreamReader; + + public static MultiComponentList GetComponents( int multiID ) + { + MultiComponentList mcl; + + if ( multiID >= 0 && multiID < m_Components.Length ) + { + mcl = m_Components[multiID]; + + if ( mcl == null ) + m_Components[multiID] = mcl = Load( multiID ); + } + else + { + mcl = MultiComponentList.Empty; + } + + return mcl; + } + + public static MultiComponentList Load( int multiID ) + { + try + { + m_IndexReader.BaseStream.Seek( multiID * 12, SeekOrigin.Begin ); + + int lookup = m_IndexReader.ReadInt32(); + int length = m_IndexReader.ReadInt32(); + + if ( lookup < 0 || length <= 0 ) + return MultiComponentList.Empty; + + m_StreamReader.BaseStream.Seek( lookup, SeekOrigin.Begin ); + + return new MultiComponentList( m_StreamReader, length / ( MultiComponentList.PostHSFormat ? 16 : 12 ) ); + } + catch + { + return MultiComponentList.Empty; + } + } + + static MultiData() + { + string idxPath = Core.FindDataFile( "multi.idx" ); + string mulPath = Core.FindDataFile( "multi.mul" ); + + if ( File.Exists( idxPath ) && File.Exists( mulPath ) ) + { + m_Index = new FileStream( idxPath, FileMode.Open, FileAccess.Read, FileShare.Read ); + m_IndexReader = new BinaryReader( m_Index ); + + m_Stream = new FileStream( mulPath, FileMode.Open, FileAccess.Read, FileShare.Read ); + m_StreamReader = new BinaryReader( m_Stream ); + + m_Components = new MultiComponentList[(int)(m_Index.Length / 12)]; + + string vdPath = Core.FindDataFile( "verdata.mul" ); + + if ( File.Exists( vdPath ) ) + { + using ( FileStream fs = new FileStream( vdPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + BinaryReader bin = new BinaryReader( fs ); + + int count = bin.ReadInt32(); + + for ( int i = 0; i < count; ++i ) + { + int file = bin.ReadInt32(); + int index = bin.ReadInt32(); + int lookup = bin.ReadInt32(); + int length = bin.ReadInt32(); + int extra = bin.ReadInt32(); + + if ( file == 14 && index >= 0 && index < m_Components.Length && lookup >= 0 && length > 0 ) + { + bin.BaseStream.Seek( lookup, SeekOrigin.Begin ); + + m_Components[index] = new MultiComponentList( bin, length / 12 ); + + bin.BaseStream.Seek( 24 + (i * 20), SeekOrigin.Begin ); + } + } + + bin.Close(); + } + } + } + else + { + Console.WriteLine( "Warning: Multi data files not found" ); + + m_Components = new MultiComponentList[0]; + } + } + } + + public struct MultiTileEntry + { + public ushort m_ItemID; + public short m_OffsetX, m_OffsetY, m_OffsetZ; + public int m_Flags; + + public MultiTileEntry( ushort itemID, short xOffset, short yOffset, short zOffset, int flags ) + { + m_ItemID = itemID; + m_OffsetX = xOffset; + m_OffsetY = yOffset; + m_OffsetZ = zOffset; + m_Flags = flags; + } + } + + public sealed class MultiComponentList + { + public static bool PostHSFormat { + get { return _PostHSFormat; } + set { _PostHSFormat = value; } + } + + private static bool _PostHSFormat = false; + + private Point2D m_Min, m_Max, m_Center; + private int m_Width, m_Height; + private StaticTile[][][] m_Tiles; + private MultiTileEntry[] m_List; + + public static readonly MultiComponentList Empty = new MultiComponentList(); + + public Point2D Min{ get{ return m_Min; } } + public Point2D Max{ get{ return m_Max; } } + + public Point2D Center{ get{ return m_Center; } } + + public int Width{ get{ return m_Width; } } + public int Height{ get{ return m_Height; } } + + public StaticTile[][][] Tiles{ get{ return m_Tiles; } } + public MultiTileEntry[] List{ get{ return m_List; } } + + public void Add( int itemID, int x, int y, int z ) + { + int vx = x + m_Center.m_X; + int vy = y + m_Center.m_Y; + + if ( vx >= 0 && vx < m_Width && vy >= 0 && vy < m_Height ) + { + StaticTile[] oldTiles = m_Tiles[vx][vy]; + + for ( int i = oldTiles.Length - 1; i >= 0; --i ) + { + ItemData data = TileData.ItemTable[itemID & TileData.MaxItemValue]; + + if ( oldTiles[i].Z == z && (oldTiles[i].Height > 0 == data.Height > 0 ) ) + { + bool newIsRoof = ( data.Flags & TileFlag.Roof) != 0; + bool oldIsRoof = (TileData.ItemTable[oldTiles[i].ID & TileData.MaxItemValue].Flags & TileFlag.Roof ) != 0; + + if ( newIsRoof == oldIsRoof ) + Remove( oldTiles[i].ID, x, y, z ); + } + } + + oldTiles = m_Tiles[vx][vy]; + + StaticTile[] newTiles = new StaticTile[oldTiles.Length + 1]; + + for ( int i = 0; i < oldTiles.Length; ++i ) + newTiles[i] = oldTiles[i]; + + newTiles[oldTiles.Length] = new StaticTile( (ushort)itemID, (sbyte)z ); + + m_Tiles[vx][vy] = newTiles; + + MultiTileEntry[] oldList = m_List; + MultiTileEntry[] newList = new MultiTileEntry[oldList.Length + 1]; + + for ( int i = 0; i < oldList.Length; ++i ) + newList[i] = oldList[i]; + + newList[oldList.Length] = new MultiTileEntry( (ushort)itemID, (short)x, (short)y, (short)z, 1 ); + + m_List = newList; + + if ( x < m_Min.m_X ) + m_Min.m_X = x; + + if ( y < m_Min.m_Y ) + m_Min.m_Y = y; + + if ( x > m_Max.m_X ) + m_Max.m_X = x; + + if ( y > m_Max.m_Y ) + m_Max.m_Y = y; + } + } + + public void RemoveXYZH( int x, int y, int z, int minHeight ) + { + int vx = x + m_Center.m_X; + int vy = y + m_Center.m_Y; + + if ( vx >= 0 && vx < m_Width && vy >= 0 && vy < m_Height ) + { + StaticTile[] oldTiles = m_Tiles[vx][vy]; + + for ( int i = 0; i < oldTiles.Length; ++i ) + { + StaticTile tile = oldTiles[i]; + + if ( tile.Z == z && tile.Height >= minHeight ) + { + StaticTile[] newTiles = new StaticTile[oldTiles.Length - 1]; + + for ( int j = 0; j < i; ++j ) + newTiles[j] = oldTiles[j]; + + for ( int j = i + 1; j < oldTiles.Length; ++j ) + newTiles[j - 1] = oldTiles[j]; + + m_Tiles[vx][vy] = newTiles; + + break; + } + } + + MultiTileEntry[] oldList = m_List; + + for ( int i = 0; i < oldList.Length; ++i ) + { + MultiTileEntry tile = oldList[i]; + + if ( tile.m_OffsetX == (short)x && tile.m_OffsetY == (short)y && tile.m_OffsetZ == (short)z && TileData.ItemTable[tile.m_ItemID & TileData.MaxItemValue].Height >= minHeight ) + { + MultiTileEntry[] newList = new MultiTileEntry[oldList.Length - 1]; + + for ( int j = 0; j < i; ++j ) + newList[j] = oldList[j]; + + for ( int j = i + 1; j < oldList.Length; ++j ) + newList[j - 1] = oldList[j]; + + m_List = newList; + + break; + } + } + } + } + + public void Remove( int itemID, int x, int y, int z ) + { + int vx = x + m_Center.m_X; + int vy = y + m_Center.m_Y; + + if ( vx >= 0 && vx < m_Width && vy >= 0 && vy < m_Height ) + { + StaticTile[] oldTiles = m_Tiles[vx][vy]; + + for ( int i = 0; i < oldTiles.Length; ++i ) + { + StaticTile tile = oldTiles[i]; + + if ( tile.ID == itemID && tile.Z == z ) + { + StaticTile[] newTiles = new StaticTile[oldTiles.Length - 1]; + + for ( int j = 0; j < i; ++j ) + newTiles[j] = oldTiles[j]; + + for ( int j = i + 1; j < oldTiles.Length; ++j ) + newTiles[j - 1] = oldTiles[j]; + + m_Tiles[vx][vy] = newTiles; + + break; + } + } + + MultiTileEntry[] oldList = m_List; + + for ( int i = 0; i < oldList.Length; ++i ) + { + MultiTileEntry tile = oldList[i]; + + if ( tile.m_ItemID == itemID && tile.m_OffsetX == (short)x && tile.m_OffsetY == (short)y && tile.m_OffsetZ == (short)z ) + { + MultiTileEntry[] newList = new MultiTileEntry[oldList.Length - 1]; + + for ( int j = 0; j < i; ++j ) + newList[j] = oldList[j]; + + for ( int j = i + 1; j < oldList.Length; ++j ) + newList[j - 1] = oldList[j]; + + m_List = newList; + + break; + } + } + } + } + + public void Resize( int newWidth, int newHeight ) + { + int oldWidth = m_Width, oldHeight = m_Height; + StaticTile[][][] oldTiles = m_Tiles; + + int totalLength = 0; + + StaticTile[][][] newTiles = new StaticTile[newWidth][][]; + + for ( int x = 0; x < newWidth; ++x ) + { + newTiles[x] = new StaticTile[newHeight][]; + + for ( int y = 0; y < newHeight; ++y ) + { + if ( x < oldWidth && y < oldHeight ) + newTiles[x][y] = oldTiles[x][y]; + else + newTiles[x][y] = new StaticTile[0]; + + totalLength += newTiles[x][y].Length; + } + } + + m_Tiles = newTiles; + m_List = new MultiTileEntry[totalLength]; + m_Width = newWidth; + m_Height = newHeight; + + m_Min = Point2D.Zero; + m_Max = Point2D.Zero; + + int index = 0; + + for ( int x = 0; x < newWidth; ++x ) + { + for ( int y = 0; y < newHeight; ++y ) + { + StaticTile[] tiles = newTiles[x][y]; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + int vx = x - m_Center.X; + int vy = y - m_Center.Y; + + if ( vx < m_Min.m_X ) + m_Min.m_X = vx; + + if ( vy < m_Min.m_Y ) + m_Min.m_Y = vy; + + if ( vx > m_Max.m_X ) + m_Max.m_X = vx; + + if ( vy > m_Max.m_Y ) + m_Max.m_Y = vy; + + m_List[index++] = new MultiTileEntry( (ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, 1 ); + } + } + } + } + + public MultiComponentList( MultiComponentList toCopy ) + { + m_Min = toCopy.m_Min; + m_Max = toCopy.m_Max; + + m_Center = toCopy.m_Center; + + m_Width = toCopy.m_Width; + m_Height = toCopy.m_Height; + + m_Tiles = new StaticTile[m_Width][][]; + + for ( int x = 0; x < m_Width; ++x ) + { + m_Tiles[x] = new StaticTile[m_Height][]; + + for ( int y = 0; y < m_Height; ++y ) + { + m_Tiles[x][y] = new StaticTile[toCopy.m_Tiles[x][y].Length]; + + for ( int i = 0; i < m_Tiles[x][y].Length; ++i ) + m_Tiles[x][y][i] = toCopy.m_Tiles[x][y][i]; + } + } + + m_List = new MultiTileEntry[toCopy.m_List.Length]; + + for ( int i = 0; i < m_List.Length; ++i ) + m_List[i] = toCopy.m_List[i]; + } + + public void Serialize( GenericWriter writer ) + { + writer.Write( (int) 1 ); // version; + + writer.Write( m_Min ); + writer.Write( m_Max ); + writer.Write( m_Center ); + + writer.Write( (int) m_Width ); + writer.Write( (int) m_Height ); + + writer.Write( (int) m_List.Length ); + + for ( int i = 0; i < m_List.Length; ++i ) + { + MultiTileEntry ent = m_List[i]; + + writer.Write( (ushort) ent.m_ItemID ); + writer.Write( (short) ent.m_OffsetX ); + writer.Write( (short) ent.m_OffsetY ); + writer.Write( (short) ent.m_OffsetZ ); + writer.Write( (int) ent.m_Flags ); + } + } + + public MultiComponentList( GenericReader reader ) + { + int version = reader.ReadInt(); + + m_Min = reader.ReadPoint2D(); + m_Max = reader.ReadPoint2D(); + m_Center = reader.ReadPoint2D(); + m_Width = reader.ReadInt(); + m_Height = reader.ReadInt(); + + int length = reader.ReadInt(); + + MultiTileEntry[] allTiles = m_List = new MultiTileEntry[length]; + + if ( version == 0 ) { + for ( int i = 0; i < length; ++i ) + { + int id = reader.ReadShort(); + if ( id >= 0x4000 ) + id -= 0x4000; + + allTiles[i].m_ItemID = (ushort)id; + allTiles[i].m_OffsetX = reader.ReadShort(); + allTiles[i].m_OffsetY = reader.ReadShort(); + allTiles[i].m_OffsetZ = reader.ReadShort(); + allTiles[i].m_Flags = reader.ReadInt(); + } + } else { + for ( int i = 0; i < length; ++i ) + { + allTiles[i].m_ItemID = reader.ReadUShort(); + allTiles[i].m_OffsetX = reader.ReadShort(); + allTiles[i].m_OffsetY = reader.ReadShort(); + allTiles[i].m_OffsetZ = reader.ReadShort(); + allTiles[i].m_Flags = reader.ReadInt(); + } + } + + TileList[][] tiles = new TileList[m_Width][]; + m_Tiles = new StaticTile[m_Width][][]; + + for ( int x = 0; x < m_Width; ++x ) + { + tiles[x] = new TileList[m_Height]; + m_Tiles[x] = new StaticTile[m_Height][]; + + for ( int y = 0; y < m_Height; ++y ) + tiles[x][y] = new TileList(); + } + + for ( int i = 0; i < allTiles.Length; ++i ) + { + if ( i == 0 || allTiles[i].m_Flags != 0 ) + { + int xOffset = allTiles[i].m_OffsetX + m_Center.m_X; + int yOffset = allTiles[i].m_OffsetY + m_Center.m_Y; + + tiles[xOffset][yOffset].Add( (ushort)allTiles[i].m_ItemID, (sbyte)allTiles[i].m_OffsetZ ); + } + } + + for ( int x = 0; x < m_Width; ++x ) + for ( int y = 0; y < m_Height; ++y ) + m_Tiles[x][y] = tiles[x][y].ToArray(); + } + + public MultiComponentList( BinaryReader reader, int count ) + { + MultiTileEntry[] allTiles = m_List = new MultiTileEntry[count]; + + for ( int i = 0; i < count; ++i ) + { + allTiles[i].m_ItemID = reader.ReadUInt16(); + allTiles[i].m_OffsetX = reader.ReadInt16(); + allTiles[i].m_OffsetY = reader.ReadInt16(); + allTiles[i].m_OffsetZ = reader.ReadInt16(); + allTiles[i].m_Flags = reader.ReadInt32(); + + if ( _PostHSFormat ) + reader.ReadInt32(); // ?? + + MultiTileEntry e = allTiles[i]; + + if ( i == 0 || e.m_Flags != 0 ) + { + if ( e.m_OffsetX < m_Min.m_X ) + m_Min.m_X = e.m_OffsetX; + + if ( e.m_OffsetY < m_Min.m_Y ) + m_Min.m_Y = e.m_OffsetY; + + if ( e.m_OffsetX > m_Max.m_X ) + m_Max.m_X = e.m_OffsetX; + + if ( e.m_OffsetY > m_Max.m_Y ) + m_Max.m_Y = e.m_OffsetY; + } + } + + m_Center = new Point2D( -m_Min.m_X, -m_Min.m_Y ); + m_Width = (m_Max.m_X - m_Min.m_X) + 1; + m_Height = (m_Max.m_Y - m_Min.m_Y) + 1; + + TileList[][] tiles = new TileList[m_Width][]; + m_Tiles = new StaticTile[m_Width][][]; + + for ( int x = 0; x < m_Width; ++x ) + { + tiles[x] = new TileList[m_Height]; + m_Tiles[x] = new StaticTile[m_Height][]; + + for ( int y = 0; y < m_Height; ++y ) + tiles[x][y] = new TileList(); + } + + for ( int i = 0; i < allTiles.Length; ++i ) + { + if ( i == 0 || allTiles[i].m_Flags != 0 ) + { + int xOffset = allTiles[i].m_OffsetX + m_Center.m_X; + int yOffset = allTiles[i].m_OffsetY + m_Center.m_Y; + + tiles[xOffset][yOffset].Add( (ushort)allTiles[i].m_ItemID, (sbyte)allTiles[i].m_OffsetZ ); + } + } + + for ( int x = 0; x < m_Width; ++x ) + for ( int y = 0; y < m_Height; ++y ) + m_Tiles[x][y] = tiles[x][y].ToArray(); + } + + private MultiComponentList() + { + m_Tiles = new StaticTile[0][][]; + m_List = new MultiTileEntry[0]; + } + } +} \ No newline at end of file diff --git a/Server/NativeReader.cs b/Server/NativeReader.cs new file mode 100644 index 0000000..a0791c4 --- /dev/null +++ b/Server/NativeReader.cs @@ -0,0 +1,68 @@ +/*************************************************************************** + * NativeReader.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: NativeReader.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Server { + public static class NativeReader { + + private static readonly INativeReader m_NativeReader; + + static NativeReader() { + if ( Core.Unix ) + m_NativeReader = new NativeReaderUnix(); + else + m_NativeReader = new NativeReaderWin32(); + } + + public static unsafe void Read( IntPtr ptr, void *buffer, int length ) { + m_NativeReader.Read( ptr, buffer, length ); + } + } + + public interface INativeReader { + unsafe void Read( IntPtr ptr, void *buffer, int length ); + } + + public sealed class NativeReaderWin32 : INativeReader { + [DllImport( "kernel32" )] + private unsafe static extern int _lread( IntPtr hFile, void *lpBuffer, int wBytes ); + + public NativeReaderWin32() { + } + + public unsafe void Read( IntPtr ptr, void *buffer, int length ) { + _lread( ptr, buffer, length ); + } + } + + public sealed class NativeReaderUnix : INativeReader { + [DllImport( "libc" )] + private unsafe static extern int read( IntPtr ptr, void *buffer, int length ); + + public NativeReaderUnix() { + } + + public unsafe void Read( IntPtr ptr, void *buffer, int length ) { + read( ptr, buffer, length ); + } + } +} \ No newline at end of file diff --git a/Server/Network/BufferPool.cs b/Server/Network/BufferPool.cs new file mode 100644 index 0000000..882414f --- /dev/null +++ b/Server/Network/BufferPool.cs @@ -0,0 +1,102 @@ +/*************************************************************************** + * BufferPool.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: BufferPool.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Network +{ + public class BufferPool + { + private static List m_Pools = new List(); + + public static List Pools{ get{ return m_Pools; } set{ m_Pools = value; } } + + private string m_Name; + + private int m_InitialCapacity; + private int m_BufferSize; + + private int m_Misses; + + private Queue m_FreeBuffers; + + public void GetInfo( out string name, out int freeCount, out int initialCapacity, out int currentCapacity, out int bufferSize, out int misses ) + { + lock ( this ) + { + name = m_Name; + freeCount = m_FreeBuffers.Count; + initialCapacity = m_InitialCapacity; + currentCapacity = m_InitialCapacity * (1 + m_Misses); + bufferSize = m_BufferSize; + misses = m_Misses; + } + } + + public BufferPool( string name, int initialCapacity, int bufferSize ) + { + m_Name = name; + + m_InitialCapacity = initialCapacity; + m_BufferSize = bufferSize; + + m_FreeBuffers = new Queue( initialCapacity ); + + for ( int i = 0; i < initialCapacity; ++i ) + m_FreeBuffers.Enqueue( new byte[bufferSize] ); + + lock ( m_Pools ) + m_Pools.Add( this ); + } + + public byte[] AcquireBuffer() + { + lock ( this ) + { + if ( m_FreeBuffers.Count > 0 ) + return m_FreeBuffers.Dequeue(); + + ++m_Misses; + + for ( int i = 0; i < m_InitialCapacity; ++i ) + m_FreeBuffers.Enqueue( new byte[m_BufferSize] ); + + return m_FreeBuffers.Dequeue(); + } + } + + public void ReleaseBuffer( byte[] buffer ) + { + if ( buffer == null ) + return; + + lock ( this ) + m_FreeBuffers.Enqueue( buffer ); + } + + public void Free() + { + lock ( m_Pools ) + m_Pools.Remove( this ); + } + } +} \ No newline at end of file diff --git a/Server/Network/ByteQueue.cs b/Server/Network/ByteQueue.cs new file mode 100644 index 0000000..a3c496c --- /dev/null +++ b/Server/Network/ByteQueue.cs @@ -0,0 +1,153 @@ +/*************************************************************************** + * ByteQueue.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ByteQueue.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; + +namespace Server.Network +{ + public class ByteQueue + { + private int m_Head; + private int m_Tail; + private int m_Size; + + private byte[] m_Buffer; + + public int Length{ get{ return m_Size; } } + + public ByteQueue() + { + m_Buffer = new byte[2048]; + } + + public void Clear() + { + m_Head = 0; + m_Tail = 0; + m_Size = 0; + } + + private void SetCapacity( int capacity ) + { + byte[] newBuffer = new byte[capacity]; + + if ( m_Size > 0 ) + { + if ( m_Head < m_Tail ) + { + Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Size ); + } + else + { + Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Buffer.Length - m_Head ); + Buffer.BlockCopy( m_Buffer, 0, newBuffer, m_Buffer.Length - m_Head, m_Tail ); + } + } + + m_Head = 0; + m_Tail = m_Size; + m_Buffer = newBuffer; + } + + public byte GetPacketID() + { + if ( m_Size >= 1 ) + return m_Buffer[m_Head]; + + return 0xFF; + } + + public int GetPacketLength() + { + if ( m_Size >= 3 ) + return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length]; + + return 0; + } + + public int Dequeue( byte[] buffer, int offset, int size ) + { + if ( size > m_Size ) + size = m_Size; + + if ( size == 0 ) + return 0; + + if ( m_Head < m_Tail ) + { + Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size ); + } + else + { + int rightLength = ( m_Buffer.Length - m_Head ); + + if ( rightLength >= size ) + { + Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size ); + } + else + { + Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, rightLength ); + Buffer.BlockCopy( m_Buffer, 0, buffer, offset + rightLength, size - rightLength ); + } + } + + m_Head = ( m_Head + size ) % m_Buffer.Length; + m_Size -= size; + + if ( m_Size == 0 ) + { + m_Head = 0; + m_Tail = 0; + } + + return size; + } + + public void Enqueue( byte[] buffer, int offset, int size ) + { + if ( (m_Size + size) > m_Buffer.Length ) + SetCapacity( (m_Size + size + 2047) & ~2047 ); + + if ( m_Head < m_Tail ) + { + int rightLength = ( m_Buffer.Length - m_Tail ); + + if ( rightLength >= size ) + { + Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size ); + } + else + { + Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, rightLength ); + Buffer.BlockCopy( buffer, offset + rightLength, m_Buffer, 0, size - rightLength ); + } + } + else + { + Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size ); + } + + m_Tail = ( m_Tail + size ) % m_Buffer.Length; + m_Size += size; + } + } +} \ No newline at end of file diff --git a/Server/Network/Compression.cs b/Server/Network/Compression.cs new file mode 100644 index 0000000..32e7f3e --- /dev/null +++ b/Server/Network/Compression.cs @@ -0,0 +1,388 @@ +/*************************************************************************** + * Compression.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Compression.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace Server.Network { + /// + /// Handles outgoing packet compression for the network. + /// + public static class Compression { + private static int[] _huffmanTable = new int[514] + { + 0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032, + 0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057, + 0x8, 0x071, 0x8, 0x05B, 0x9, 0x1CC, 0x8, 0x0A7, 0x7, 0x025, 0x7, 0x04F, 0x8, 0x066, 0x8, 0x07D, + 0x9, 0x191, 0x9, 0x1CE, 0x7, 0x03F, 0x9, 0x090, 0x8, 0x059, 0x8, 0x07B, 0x8, 0x091, 0x8, 0x0C6, + 0x6, 0x02D, 0x9, 0x186, 0x8, 0x06F, 0x9, 0x093, 0xA, 0x1CC, 0x8, 0x05A, 0xA, 0x1AE, 0xA, 0x1C0, + 0x9, 0x148, 0x9, 0x14A, 0x9, 0x082, 0xA, 0x19F, 0x9, 0x171, 0x9, 0x120, 0x9, 0x0E7, 0xA, 0x1F3, + 0x9, 0x14B, 0x9, 0x100, 0x9, 0x190, 0x6, 0x013, 0x9, 0x161, 0x9, 0x125, 0x9, 0x133, 0x9, 0x195, + 0x9, 0x173, 0x9, 0x1CA, 0x9, 0x086, 0x9, 0x1E9, 0x9, 0x0DB, 0x9, 0x1EC, 0x9, 0x08B, 0x9, 0x085, + 0x5, 0x00A, 0x8, 0x096, 0x8, 0x09C, 0x9, 0x1C3, 0x9, 0x19C, 0x9, 0x08F, 0x9, 0x18F, 0x9, 0x091, + 0x9, 0x087, 0x9, 0x0C6, 0x9, 0x177, 0x9, 0x089, 0x9, 0x0D6, 0x9, 0x08C, 0x9, 0x1EE, 0x9, 0x1EB, + 0x9, 0x084, 0x9, 0x164, 0x9, 0x175, 0x9, 0x1CD, 0x8, 0x05E, 0x9, 0x088, 0x9, 0x12B, 0x9, 0x172, + 0x9, 0x10A, 0x9, 0x08D, 0x9, 0x13A, 0x9, 0x11C, 0xA, 0x1E1, 0xA, 0x1E0, 0x9, 0x187, 0xA, 0x1DC, + 0xA, 0x1DF, 0x7, 0x074, 0x9, 0x19F, 0x8, 0x08D, 0x8, 0x0E4, 0x7, 0x079, 0x9, 0x0EA, 0x9, 0x0E1, + 0x8, 0x040, 0x7, 0x041, 0x9, 0x10B, 0x9, 0x0B0, 0x8, 0x06A, 0x8, 0x0C1, 0x7, 0x071, 0x7, 0x078, + 0x8, 0x0B1, 0x9, 0x14C, 0x7, 0x043, 0x8, 0x076, 0x7, 0x066, 0x7, 0x04D, 0x9, 0x08A, 0x6, 0x02F, + 0x8, 0x0C9, 0x9, 0x0CE, 0x9, 0x149, 0x9, 0x160, 0xA, 0x1BA, 0xA, 0x19E, 0xA, 0x39F, 0x9, 0x0E5, + 0x9, 0x194, 0x9, 0x184, 0x9, 0x126, 0x7, 0x030, 0x8, 0x06C, 0x9, 0x121, 0x9, 0x1E8, 0xA, 0x1C1, + 0xA, 0x11D, 0xA, 0x163, 0xA, 0x385, 0xA, 0x3DB, 0xA, 0x17D, 0xA, 0x106, 0xA, 0x397, 0xA, 0x24E, + 0x7, 0x02E, 0x8, 0x098, 0xA, 0x33C, 0xA, 0x32E, 0xA, 0x1E9, 0x9, 0x0BF, 0xA, 0x3DF, 0xA, 0x1DD, + 0xA, 0x32D, 0xA, 0x2ED, 0xA, 0x30B, 0xA, 0x107, 0xA, 0x2E8, 0xA, 0x3DE, 0xA, 0x125, 0xA, 0x1E8, + 0x9, 0x0E9, 0xA, 0x1CD, 0xA, 0x1B5, 0x9, 0x165, 0xA, 0x232, 0xA, 0x2E1, 0xB, 0x3AE, 0xB, 0x3C6, + 0xB, 0x3E2, 0xA, 0x205, 0xA, 0x29A, 0xA, 0x248, 0xA, 0x2CD, 0xA, 0x23B, 0xB, 0x3C5, 0xA, 0x251, + 0xA, 0x2E9, 0xA, 0x252, 0x9, 0x1EA, 0xB, 0x3A0, 0xB, 0x391, 0xA, 0x23C, 0xB, 0x392, 0xB, 0x3D5, + 0xA, 0x233, 0xA, 0x2CC, 0xB, 0x390, 0xA, 0x1BB, 0xB, 0x3A1, 0xB, 0x3C4, 0xA, 0x211, 0xA, 0x203, + 0x9, 0x12A, 0xA, 0x231, 0xB, 0x3E0, 0xA, 0x29B, 0xB, 0x3D7, 0xA, 0x202, 0xB, 0x3AD, 0xA, 0x213, + 0xA, 0x253, 0xA, 0x32C, 0xA, 0x23D, 0xA, 0x23F, 0xA, 0x32F, 0xA, 0x11C, 0xA, 0x384, 0xA, 0x31C, + 0xA, 0x17C, 0xA, 0x30A, 0xA, 0x2E0, 0xA, 0x276, 0xA, 0x250, 0xB, 0x3E3, 0xA, 0x396, 0xA, 0x18F, + 0xA, 0x204, 0xA, 0x206, 0xA, 0x230, 0xA, 0x265, 0xA, 0x212, 0xA, 0x23E, 0xB, 0x3AC, 0xB, 0x393, + 0xB, 0x3E1, 0xA, 0x1DE, 0xB, 0x3D6, 0xA, 0x31D, 0xB, 0x3E5, 0xB, 0x3E4, 0xA, 0x207, 0xB, 0x3C7, + 0xA, 0x277, 0xB, 0x3D4, 0x8, 0x0C0, 0xA, 0x162, 0xA, 0x3DA, 0xA, 0x124, 0xA, 0x1B4, 0xA, 0x264, + 0xA, 0x33D, 0xA, 0x1D1, 0xA, 0x1AF, 0xA, 0x39E, 0xA, 0x24F, 0xB, 0x373, 0xA, 0x249, 0xB, 0x372, + 0x9, 0x167, 0xA, 0x210, 0xA, 0x23A, 0xA, 0x1B8, 0xB, 0x3AF, 0xA, 0x18E, 0xA, 0x2EC, 0x7, 0x062, + 0x4, 0x00D + }; + + private const int CountIndex = 0; + private const int ValueIndex = 1; + + // UO packets may not exceed 64kb in length + private const int BufferSize = 0x10000; + + // Optimal compression ratio is 2 / 8; worst compression ratio is 11 / 8 + private const int MinimalCodeLength = 2; + private const int MaximalCodeLength = 11; + + // Fixed overhead, in bits, per compression call + private const int TerminalCodeLength = 4; + + // If our input exceeds this length, we cannot possibly compress it within the buffer + private const int DefiniteOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MinimalCodeLength; + + // If our input exceeds this length, we may potentially overflow the buffer + private const int PossibleOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MaximalCodeLength; + + private static object _syncRoot = new object(); + + private static byte[] _outputBuffer = new byte[BufferSize]; + + [Obsolete( "Use Compress( byte[], int, int, ref int ) instead.", false )] + public static void Compress( byte[] input, int length, out byte[] output, out int outputLength ) { + outputLength = 0; + output = Compress( input, 0, length, ref outputLength ); + } + + public unsafe static byte[] Compress( byte[] input, int offset, int count, ref int length ) { + if ( input == null ) { + throw new ArgumentNullException( "input" ); + } else if ( offset < 0 || offset >= input.Length ) { + throw new ArgumentOutOfRangeException( "offset" ); + } else if ( count < 0 || count > input.Length ) { + throw new ArgumentOutOfRangeException( "count" ); + } else if ( ( input.Length - offset ) < count ) { + throw new ArgumentException(); + } + + length = 0; + + if ( count > DefiniteOverflow ) { + return null; + } + + lock ( _syncRoot ) { + int bitCount = 0; + int bitValue = 0; + + fixed ( int* pTable = _huffmanTable ) { + int* pEntry; + + fixed ( byte* pInputBuffer = input ) { + byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count; + + fixed ( byte* pOutputBuffer = _outputBuffer ) { + byte* pOutput = pOutputBuffer, pOutputEnd = pOutput + BufferSize; + + while ( pInput < pInputEnd ) { + pEntry = &pTable[*pInput++ << 1]; + + bitCount += pEntry[CountIndex]; + + bitValue <<= pEntry[CountIndex]; + bitValue |= pEntry[ValueIndex]; + + while ( bitCount >= 8 ) { + bitCount -= 8; + + if ( pOutput < pOutputEnd ) { + *pOutput++ = ( byte ) ( bitValue >> bitCount ); + } else { + return null; + } + } + } + + // terminal code + pEntry = &pTable[0x200]; + + bitCount += pEntry[CountIndex]; + + bitValue <<= pEntry[CountIndex]; + bitValue |= pEntry[ValueIndex]; + + // align on byte boundary + if ( ( bitCount & 7 ) != 0 ) { + bitValue <<= ( 8 - ( bitCount & 7 ) ); + bitCount += ( 8 - ( bitCount & 7 ) ); + } + + while ( bitCount >= 8 ) { + bitCount -= 8; + + if ( pOutput < pOutputEnd ) { + *pOutput++ = ( byte ) ( bitValue >> bitCount ); + } else { + return null; + } + } + + length = ( int ) ( pOutput - pOutputBuffer ); + return _outputBuffer; + } + } + } + } + } + + public static readonly ICompressor Compressor; + + static Compression() { + if ( Core.Unix ) { + if ( Core.Is64Bit ) { + Compressor = new CompressorUnix64(); + } else { + Compressor = new CompressorUnix32(); + } + } else if ( Core.Is64Bit ) { + Compressor = new Compressor64(); + } else { + Compressor = new Compressor32(); + } + } + + public static ZLibError Pack( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return Compressor.Compress( dest, ref destLength, source, sourceLength ); + } + + public static ZLibError Pack( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) { + return Compressor.Compress( dest, ref destLength, source, sourceLength, quality ); + } + + public static ZLibError Unpack( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return Compressor.Decompress( dest, ref destLength, source, sourceLength ); + } + } + + public interface ICompressor { + string Version { + get; + } + + ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ); + ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ); + + ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ); + } + + public sealed class Compressor32 : ICompressor { + [DllImport("zlib32", CallingConvention = CallingConvention.Cdecl)] + private static extern string zlibVersion(); + + [DllImport( "zlib32", CallingConvention=CallingConvention.Cdecl)] + private static extern ZLibError compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ); + + [DllImport("zlib32", CallingConvention = CallingConvention.Cdecl)] + private static extern ZLibError compress2( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ); + + [DllImport("zlib32", CallingConvention = CallingConvention.Cdecl)] + private static extern ZLibError uncompress( byte[] dest, ref int destLen, byte[] source, int sourceLen ); + + public Compressor32() { + } + + public string Version { + get { + return zlibVersion(); + } + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return compress( dest, ref destLength, source, sourceLength ); + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) { + return compress2( dest, ref destLength, source, sourceLength, quality ); + } + + public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return uncompress( dest, ref destLength, source, sourceLength ); + } + } + + public sealed class Compressor64 : ICompressor { + [DllImport("zlib64", CallingConvention = CallingConvention.Cdecl)] + private static extern string zlibVersion(); + + [DllImport("zlib64", CallingConvention = CallingConvention.Cdecl)] + private static extern ZLibError compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ); + + [DllImport("zlib64", CallingConvention = CallingConvention.Cdecl)] + private static extern ZLibError compress2( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ); + + [DllImport("zlib64", CallingConvention = CallingConvention.Cdecl)] + private static extern ZLibError uncompress( byte[] dest, ref int destLen, byte[] source, int sourceLen ); + + public Compressor64() { + } + + public string Version { + get { + return zlibVersion(); + } + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return compress( dest, ref destLength, source, sourceLength ); + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) { + return compress2( dest, ref destLength, source, sourceLength, quality ); + } + + public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return uncompress( dest, ref destLength, source, sourceLength ); + } + } + + public sealed class CompressorUnix32 : ICompressor { + [DllImport( "libz" )] + private static extern string zlibVersion(); + + [DllImport( "libz" )] + private static extern ZLibError compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ); + + [DllImport( "libz" )] + private static extern ZLibError compress2( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ); + + [DllImport( "libz" )] + private static extern ZLibError uncompress( byte[] dest, ref int destLen, byte[] source, int sourceLen ); + + public CompressorUnix32() { + } + + public string Version { + get { + return zlibVersion(); + } + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return compress( dest, ref destLength, source, sourceLength ); + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) { + return compress2( dest, ref destLength, source, sourceLength, quality ); + } + + public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + return uncompress( dest, ref destLength, source, sourceLength ); + } + } + + public sealed class CompressorUnix64 : ICompressor { + [DllImport( "libz" )] + private static extern string zlibVersion(); + + [DllImport( "libz" )] + private static extern ZLibError compress( byte[] dest, ref ulong destLength, byte[] source, int sourceLength ); + + [DllImport( "libz" )] + private static extern ZLibError compress2( byte[] dest, ref ulong destLength, byte[] source, int sourceLength, ZLibQuality quality ); + + [DllImport( "libz" )] + private static extern ZLibError uncompress( byte[] dest, ref ulong destLen, byte[] source, int sourceLen ); + + public CompressorUnix64() { + } + + public string Version { + get { + return zlibVersion(); + } + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + ulong destLengthLong = (ulong)destLength; + ZLibError z = compress( dest, ref destLengthLong, source, sourceLength ); + destLength = (int)destLengthLong; + return z; + } + + public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) { + ulong destLengthLong = (ulong)destLength; + ZLibError z = compress2( dest, ref destLengthLong, source, sourceLength, quality ); + destLength = (int)destLengthLong; + return z; + } + + public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) { + ulong destLengthLong = (ulong)destLength; + ZLibError z = uncompress( dest, ref destLengthLong, source, sourceLength ); + destLength = (int)destLengthLong; + return z; + } + } + + public enum ZLibError : int { + VersionError = -6, + BufferError = -5, + MemoryError = -4, + DataError = -3, + StreamError = -2, + FileError = -1, + + Okay = 0, + + StreamEnd = 1, + NeedDictionary = 2 + } + + public enum ZLibQuality : int { + Default = -1, + + None = 0, + + Speed = 1, + Size = 9 + } +} \ No newline at end of file diff --git a/Server/Network/EncodedPacketHandler.cs b/Server/Network/EncodedPacketHandler.cs new file mode 100644 index 0000000..e25f439 --- /dev/null +++ b/Server/Network/EncodedPacketHandler.cs @@ -0,0 +1,64 @@ +/*************************************************************************** + * EncodedPacketHandler.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: EncodedPacketHandler.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Network +{ + public delegate void OnEncodedPacketReceive( NetState state, IEntity ent, EncodedReader pvSrc ); + + public class EncodedPacketHandler + { + private int m_PacketID; + private bool m_Ingame; + private OnEncodedPacketReceive m_OnReceive; + + public EncodedPacketHandler( int packetID, bool ingame, OnEncodedPacketReceive onReceive ) + { + m_PacketID = packetID; + m_Ingame = ingame; + m_OnReceive = onReceive; + } + + public int PacketID + { + get + { + return m_PacketID; + } + } + + public OnEncodedPacketReceive OnReceive + { + get + { + return m_OnReceive; + } + } + + public bool Ingame + { + get + { + return m_Ingame; + } + } + } +} \ No newline at end of file diff --git a/Server/Network/EncodedReader.cs b/Server/Network/EncodedReader.cs new file mode 100644 index 0000000..33902f1 --- /dev/null +++ b/Server/Network/EncodedReader.cs @@ -0,0 +1,85 @@ +/*************************************************************************** + * EncodedReader.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: EncodedReader.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Text; +using System.IO; + +namespace Server.Network +{ + public class EncodedReader + { + private PacketReader m_Reader; + + public EncodedReader( PacketReader reader ) + { + m_Reader = reader; + } + + public byte[] Buffer + { + get + { + return m_Reader.Buffer; + } + } + + public void Trace( NetState state ) + { + m_Reader.Trace( state ); + } + + public int ReadInt32() + { + if ( m_Reader.ReadByte() != 0 ) + return 0; + + return m_Reader.ReadInt32(); + } + + public Point3D ReadPoint3D() + { + if ( m_Reader.ReadByte() != 3 ) + return Point3D.Zero; + + return new Point3D( m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte() ); + } + + public string ReadUnicodeStringSafe() + { + if ( m_Reader.ReadByte() != 2 ) + return ""; + + int length = m_Reader.ReadUInt16(); + + return m_Reader.ReadUnicodeStringSafe( length ); + } + + public string ReadUnicodeString() + { + if ( m_Reader.ReadByte() != 2 ) + return ""; + + int length = m_Reader.ReadUInt16(); + + return m_Reader.ReadUnicodeString( length ); + } + } +} \ No newline at end of file diff --git a/Server/Network/Listener.cs b/Server/Network/Listener.cs new file mode 100644 index 0000000..ad26933 --- /dev/null +++ b/Server/Network/Listener.cs @@ -0,0 +1,325 @@ +/*************************************************************************** + * Listener.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Listener.cs 826 2012-02-08 03:32:56Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Threading; +using Server; + +namespace Server.Network +{ + public class Listener : IDisposable + { + private Socket m_Listener; + + private Queue m_Accepted; + private object m_AcceptedSyncRoot; + +#if NewAsyncSockets + private SocketAsyncEventArgs m_EventArgs; +#else + private AsyncCallback m_OnAccept; +#endif + + private static Socket[] m_EmptySockets = new Socket[0]; + + private static IPEndPoint[] m_EndPoints; + + public static IPEndPoint[] EndPoints + { + get { return m_EndPoints; } + set { m_EndPoints = value; } + } + + public Listener(IPEndPoint ipep) + { + m_Accepted = new Queue(); + m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot; + + m_Listener = Bind(ipep); + + if (m_Listener == null) + return; + + DisplayListener(); + +#if NewAsyncSockets + m_EventArgs = new SocketAsyncEventArgs(); + m_EventArgs.Completed += new EventHandler( Accept_Completion ); + Accept_Start(); +#else + m_OnAccept = new AsyncCallback(OnAccept); + try + { + IAsyncResult res = m_Listener.BeginAccept(m_OnAccept, m_Listener); + } + catch (SocketException ex) + { + NetState.TraceException(ex); + } + catch (ObjectDisposedException) + { + } +#endif + } + + private Socket Bind(IPEndPoint ipep) + { + Socket s = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + try + { + s.LingerState.Enabled = false; +#if !MONO + s.ExclusiveAddressUse = false; +#endif + s.Bind(ipep); + //Plume : Net 4 + //s.Listen(8); + s.Listen(100); + + return s; + } + catch (Exception e) + { + if (e is SocketException) + { + SocketException se = (SocketException)e; + + if (se.ErrorCode == 10048) + { // WSAEADDRINUSE + Console.WriteLine("Listener Failed: {0}:{1} (In Use)", ipep.Address, ipep.Port); + } + else if (se.ErrorCode == 10049) + { // WSAEADDRNOTAVAIL + Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", ipep.Address, ipep.Port); + } + else + { + Console.WriteLine("Listener Exception:"); + Console.WriteLine(e); + } + } + + return null; + } + } + + private void DisplayListener() + { + IPEndPoint ipep = m_Listener.LocalEndPoint as IPEndPoint; + + if (ipep == null) + return; + + if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any)) + { + NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); + foreach (NetworkInterface adapter in adapters) + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + foreach (IPAddressInformation unicast in properties.UnicastAddresses) + { + if (ipep.AddressFamily == unicast.Address.AddressFamily) + Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port); + } + } + /* + try { + Console.WriteLine( "Listening: {0}:{1}", IPAddress.Loopback, ipep.Port ); + IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() ); + IPAddress[] ip = iphe.AddressList; + for ( int i = 0; i < ip.Length; ++i ) + Console.WriteLine( "Listening: {0}:{1}", ip[i], ipep.Port ); + } + catch { } + */ + } + else + { + Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port); + } + } + +#if NewAsyncSockets + private void Accept_Start() + { + bool result = false; + + do { + try { + result = !m_Listener.AcceptAsync( m_EventArgs ); + } catch ( SocketException ex ) { + NetState.TraceException( ex ); + break; + } catch ( ObjectDisposedException ) { + break; + } + + if ( result ) + Accept_Process( m_EventArgs ); + } while ( result ); + } + + private void Accept_Completion( object sender, SocketAsyncEventArgs e ) + { + Accept_Process( e ); + + Accept_Start(); + } + + private void Accept_Process( SocketAsyncEventArgs e ) + { + if ( e.SocketError == SocketError.Success && VerifySocket( e.AcceptSocket ) ) { + Enqueue( e.AcceptSocket ); + } else { + Release( e.AcceptSocket ); + } + + e.AcceptSocket = null; + } + +#else + + private void OnAccept(IAsyncResult asyncResult) + { + Socket listener = (Socket)asyncResult.AsyncState; + + Socket accepted = null; + + try + { + accepted = listener.EndAccept(asyncResult); + } + catch (SocketException ex) + { + NetState.TraceException(ex); + } + catch (ObjectDisposedException) + { + return; + } + + if (accepted != null) + { + if (VerifySocket(accepted)) + { + Enqueue(accepted); + } + else + { + Release(accepted); + } + } + + try + { + listener.BeginAccept(m_OnAccept, listener); + } + catch (SocketException ex) + { + NetState.TraceException(ex); + } + catch (ObjectDisposedException) + { + } + } +#endif + + private bool VerifySocket(Socket socket) + { + try + { + SocketConnectEventArgs args = new SocketConnectEventArgs(socket); + + EventSink.InvokeSocketConnect(args); + + return args.AllowConnection; + } + catch (Exception ex) + { + NetState.TraceException(ex); + + return false; + } + } + + private void Enqueue(Socket socket) + { + lock (m_AcceptedSyncRoot) + { + m_Accepted.Enqueue(socket); + } + + Core.Set(); + } + + private void Release(Socket socket) + { + try + { + socket.Shutdown(SocketShutdown.Both); + } + catch (SocketException ex) + { + NetState.TraceException(ex); + } + + try + { + socket.Close(); + } + catch (SocketException ex) + { + NetState.TraceException(ex); + } + } + + public Socket[] Slice() + { + Socket[] array; + + lock (m_AcceptedSyncRoot) + { + if (m_Accepted.Count == 0) + return m_EmptySockets; + + array = m_Accepted.ToArray(); + m_Accepted.Clear(); + } + + return array; + } + + public void Dispose() + { + Socket socket = Interlocked.Exchange(ref m_Listener, null); + + if (socket != null) + { + socket.Close(); + } + } + } +} \ No newline at end of file diff --git a/Server/Network/MessagePump.cs b/Server/Network/MessagePump.cs new file mode 100644 index 0000000..2a06cb0 --- /dev/null +++ b/Server/Network/MessagePump.cs @@ -0,0 +1,289 @@ +/*************************************************************************** + * MessagePump.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: MessagePump.cs 402 2009-10-17 07:28:17Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Server; +using Server.Diagnostics; +using Server.Network; + +namespace Server.Network +{ + public class MessagePump + { + private Listener[] m_Listeners; + private Queue m_Queue; + private Queue m_WorkingQueue; + private Queue m_Throttled; + private byte[] m_Peek; + + public MessagePump() + { + IPEndPoint[] ipep = Listener.EndPoints; + + m_Listeners = new Listener[ipep.Length]; + + bool success = false; + + do { + for ( int i = 0; i < ipep.Length; i++ ) { + Listener l = new Listener( ipep[i] ); + if ( !success && l != null ) + success = true; + m_Listeners[i] = l; + } + + if ( !success ) { + Console.WriteLine( "Retrying..." ); + Thread.Sleep( 10000 ); + } + } while ( !success ); + + m_Queue = new Queue(); + m_WorkingQueue = new Queue(); + m_Throttled = new Queue(); + m_Peek = new byte[4]; + } + + public Listener[] Listeners + { + get{ return m_Listeners; } + set{ m_Listeners = value; } + } + + public void AddListener( Listener l ) + { + Listener[] old = m_Listeners; + + m_Listeners = new Listener[old.Length + 1]; + + for ( int i = 0; i < old.Length; ++i ) + m_Listeners[i] = old[i]; + + m_Listeners[old.Length] = l; + } + + private void CheckListener() + { + for ( int j = 0; j < m_Listeners.Length; ++j ) + { + Socket[] accepted = m_Listeners[j].Slice(); + + for ( int i = 0; i < accepted.Length; ++i ) + { + NetState ns = new NetState( accepted[i], this ); + ns.Start(); + + if ( ns.Running ) + Console.WriteLine( "Client: {0}: Connected. [{1} Online]", ns, NetState.Instances.Count ); + } + } + } + + public void OnReceive( NetState ns ) + { + lock ( this ) + m_Queue.Enqueue( ns ); + + Core.Set(); + } + + public void Slice() + { + CheckListener(); + + lock ( this ) + { + Queue temp = m_WorkingQueue; + m_WorkingQueue = m_Queue; + m_Queue = temp; + } + + while ( m_WorkingQueue.Count > 0 ) + { + NetState ns = m_WorkingQueue.Dequeue(); + + if ( ns.Running ) + HandleReceive( ns ); + } + + lock ( this ) + { + while ( m_Throttled.Count > 0 ) + m_Queue.Enqueue( m_Throttled.Dequeue() ); + } + } + + private const int BufferSize = 4096; + private BufferPool m_Buffers = new BufferPool( "Processor", 4, BufferSize ); + + public bool HandleReceive( NetState ns ) + { + ByteQueue buffer = ns.Buffer; + + if ( buffer == null || buffer.Length <= 0 ) + return true; + + lock ( buffer ) + { + int length = buffer.Length; + + if ( !ns.Seeded ) + { + if ( buffer.GetPacketID() == 0xEF ) + { + // new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet + // 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients. + ns.Seeded = true; + } + else if ( buffer.Length >= 4 ) + { + buffer.Dequeue( m_Peek, 0, 4 ); + + int seed = (m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]; + + if ( seed == 0 ) + { + Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", ns ); + ns.Dispose(); + return false; + } + + ns.m_Seed = seed; + ns.Seeded = true; + + length = buffer.Length; + } + else + { + return true; + } + } + + while ( length > 0 && ns.Running ) + { + int packetID = buffer.GetPacketID(); + + if ( !ns.SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 && packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF ) + { + Console.WriteLine( "Client: {0}: Encrypted client detected, disconnecting", ns ); + ns.Dispose(); + break; + } + + PacketHandler handler = ns.GetHandler( packetID ); + + if ( handler == null ) + { + byte[] data = new byte[length]; + length = buffer.Dequeue( data, 0, length ); + + new PacketReader( data, length, false ).Trace( ns ); + + break; + } + + int packetLength = handler.Length; + + if ( packetLength <= 0 ) + { + if ( length >= 3 ) + { + packetLength = buffer.GetPacketLength(); + + if ( packetLength < 3 ) + { + ns.Dispose(); + break; + } + } + else + { + break; + } + } + + if ( length >= packetLength ) + { + if ( handler.Ingame && ns.Mobile == null ) + { + Console.WriteLine( "Client: {0}: Sent ingame packet (0x{1:X2}) before having been attached to a mobile", ns, packetID ); + ns.Dispose(); + break; + } + else if ( handler.Ingame && ns.Mobile.Deleted ) + { + ns.Dispose(); + break; + } + else + { + ThrottlePacketCallback throttler = handler.ThrottleCallback; + + if ( throttler != null && !throttler( ns ) ) + { + m_Throttled.Enqueue( ns ); + return false; + } + + PacketReceiveProfile prof = PacketReceiveProfile.Acquire( packetID ); + + if ( prof != null ) { + prof.Start(); + } + + byte[] packetBuffer; + + if ( BufferSize >= packetLength ) + packetBuffer = m_Buffers.AcquireBuffer(); + else + packetBuffer = new byte[packetLength]; + + packetLength = buffer.Dequeue( packetBuffer, 0, packetLength ); + + PacketReader r = new PacketReader( packetBuffer, packetLength, handler.Length != 0 ); + + handler.OnReceive( ns, r ); + length = buffer.Length; + + if ( BufferSize >= packetLength ) + m_Buffers.ReleaseBuffer( packetBuffer ); + + if ( prof != null ) { + prof.Finish( packetLength ); + } + } + } + else + { + break; + } + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Server/Network/NetState.cs b/Server/Network/NetState.cs new file mode 100644 index 0000000..ec44a69 --- /dev/null +++ b/Server/Network/NetState.cs @@ -0,0 +1,1596 @@ +/*************************************************************************** + * NetState.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: NetState.cs 892 2012-07-29 02:41:00Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Server; +using Server.Accounting; +using Server.Network; +using Server.Items; +using Server.Gumps; +using Server.Menus; +using Server.HuePickers; +using Server.Diagnostics; + +namespace Server.Network +{ + public interface IPacketEncoder + { + void EncodeOutgoingPacket(NetState to, ref byte[] buffer, ref int length); + void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length); + } + + public delegate void NetStateCreatedCallback(NetState ns); + + public class NetState : IComparable { + + private Socket m_Socket; + private IPAddress m_Address; + private ByteQueue m_Buffer; + private byte[] m_RecvBuffer; + private SendQueue m_SendQueue; + private bool m_Seeded; + private bool m_Running; + +#if NewAsyncSockets + private SocketAsyncEventArgs m_ReceiveEventArgs, m_SendEventArgs; + //Plume : Net 4 + public static SocketAsyncEventArgsPool m_SocketAsyncReceiveEventPool = new SocketAsyncEventArgsPool(100); + public static SocketAsyncEventArgsPool m_SocketAsyncSendEventPool = new SocketAsyncEventArgsPool(100); +#else + private AsyncCallback m_OnReceive, m_OnSend; +#endif + + private MessagePump m_MessagePump; + private ServerInfo[] m_ServerInfo; + private IAccount m_Account; + private Mobile m_Mobile; + private CityInfo[] m_CityInfo; + private List m_Gumps; + private List m_HuePickers; + private List m_Menus; + private List m_Trades; + private int m_Sequence; + private bool m_CompressionEnabled; + private string m_ToString; + private ClientVersion m_Version; + private bool m_SentFirstPacket; + private bool m_BlockAllPackets; + + private DateTime m_ConnectedOn; + + public DateTime ConnectedOn + { + get + { + return m_ConnectedOn; + } + } + + public TimeSpan ConnectedFor + { + get + { + return (DateTime.Now - m_ConnectedOn); + } + } + + internal int m_Seed; + internal int m_AuthID; + + public IPAddress Address + { + get + { + return m_Address; + } + } + + private ClientFlags m_Flags; + + private static bool m_Paused; + + [Flags] + private enum AsyncState + { + Pending = 0x01, + Paused = 0x02 + } + + private AsyncState m_AsyncState; + private object m_AsyncLock = new object(); + + private IPacketEncoder m_Encoder = null; + + public IPacketEncoder PacketEncoder + { + get + { + return m_Encoder; + } + set + { + m_Encoder = value; + } + } + + private static NetStateCreatedCallback m_CreatedCallback; + + public static NetStateCreatedCallback CreatedCallback + { + get + { + return m_CreatedCallback; + } + set + { + m_CreatedCallback = value; + } + } + + public bool SentFirstPacket + { + get + { + return m_SentFirstPacket; + } + set + { + m_SentFirstPacket = value; + } + } + + public bool BlockAllPackets + { + get + { + return m_BlockAllPackets; + } + set + { + m_BlockAllPackets = value; + } + } + + public ClientFlags Flags + { + get + { + return m_Flags; + } + set + { + m_Flags = value; + } + } + + public ClientVersion Version + { + get + { + return m_Version; + } + set + { + m_Version = value; + + if ( value >= m_Version70331 ) { + _ProtocolChanges = ProtocolChanges.Version70331; + } else if (value >= m_Version70300) { + _ProtocolChanges = ProtocolChanges.Version70300; + } + else if (value >= m_Version70160) + { + _ProtocolChanges = ProtocolChanges.Version70160; + } + else if (value >= m_Version70130) + { + _ProtocolChanges = ProtocolChanges.Version70130; + } + else if (value >= m_Version7090) + { + _ProtocolChanges = ProtocolChanges.Version7090; + } + else if (value >= m_Version7000) + { + _ProtocolChanges = ProtocolChanges.Version7000; + } + else if (value >= m_Version60142) + { + _ProtocolChanges = ProtocolChanges.Version60142; + } + else if (value >= m_Version6017) + { + _ProtocolChanges = ProtocolChanges.Version6017; + } + else if (value >= m_Version6000) + { + _ProtocolChanges = ProtocolChanges.Version6000; + } + else if (value >= m_Version502b) + { + _ProtocolChanges = ProtocolChanges.Version502b; + } + else if (value >= m_Version500a) + { + _ProtocolChanges = ProtocolChanges.Version500a; + } + else if (value >= m_Version407a) + { + _ProtocolChanges = ProtocolChanges.Version407a; + } + else if (value >= m_Version400a) + { + _ProtocolChanges = ProtocolChanges.Version400a; + } + } + } + + private static ClientVersion m_Version400a = new ClientVersion("4.0.0a"); + private static ClientVersion m_Version407a = new ClientVersion("4.0.7a"); + private static ClientVersion m_Version500a = new ClientVersion("5.0.0a"); + private static ClientVersion m_Version502b = new ClientVersion("5.0.2b"); + private static ClientVersion m_Version6000 = new ClientVersion("6.0.0.0"); + private static ClientVersion m_Version6017 = new ClientVersion("6.0.1.7"); + private static ClientVersion m_Version60142 = new ClientVersion("6.0.14.2"); + private static ClientVersion m_Version7000 = new ClientVersion("7.0.0.0"); + private static ClientVersion m_Version7090 = new ClientVersion("7.0.9.0"); + private static ClientVersion m_Version70130 = new ClientVersion("7.0.13.0"); + private static ClientVersion m_Version70160 = new ClientVersion("7.0.16.0"); + private static ClientVersion m_Version70300 = new ClientVersion("7.0.30.0"); + private static ClientVersion m_Version70331 = new ClientVersion("7.0.33.1"); + + private ProtocolChanges _ProtocolChanges; + + private enum ProtocolChanges + { + NewSpellbook = 0x00000001, + DamagePacket = 0x00000002, + Unpack = 0x00000004, + BuffIcon = 0x00000008, + NewHaven = 0x00000010, + ContainerGridLines = 0x00000020, + ExtendedSupportedFeatures = 0x00000040, + StygianAbyss = 0x00000080, + HighSeas = 0x00000100, + NewCharacterList = 0x00000200, + NewCharacterCreation = 0x00000400, + ExtendedStatus = 0x00000800, + NewMobileIncoming = 0x00001000, + + Version400a = NewSpellbook, + Version407a = Version400a | DamagePacket, + Version500a = Version407a | Unpack, + Version502b = Version500a | BuffIcon, + Version6000 = Version502b | NewHaven, + Version6017 = Version6000 | ContainerGridLines, + Version60142 = Version6017 | ExtendedSupportedFeatures, + Version7000 = Version60142 | StygianAbyss, + Version7090 = Version7000 | HighSeas, + Version70130 = Version7090 | NewCharacterList, + Version70160 = Version70130 | NewCharacterCreation, + Version70300 = Version70160 | ExtendedStatus, + Version70331 = Version70300 | NewMobileIncoming + } + + public bool NewSpellbook { get { return ((_ProtocolChanges & ProtocolChanges.NewSpellbook) != 0); } } + public bool DamagePacket { get { return ((_ProtocolChanges & ProtocolChanges.DamagePacket) != 0); } } + public bool Unpack { get { return ((_ProtocolChanges & ProtocolChanges.Unpack) != 0); } } + public bool BuffIcon { get { return ((_ProtocolChanges & ProtocolChanges.BuffIcon) != 0); } } + public bool NewHaven { get { return ((_ProtocolChanges & ProtocolChanges.NewHaven) != 0); } } + public bool ContainerGridLines { get { return ((_ProtocolChanges & ProtocolChanges.ContainerGridLines) != 0); } } + public bool ExtendedSupportedFeatures { get { return ((_ProtocolChanges & ProtocolChanges.ExtendedSupportedFeatures) != 0); } } + public bool StygianAbyss { get { return ((_ProtocolChanges & ProtocolChanges.StygianAbyss) != 0); } } + public bool HighSeas { get { return ((_ProtocolChanges & ProtocolChanges.HighSeas) != 0); } } + public bool NewCharacterList { get { return ((_ProtocolChanges & ProtocolChanges.NewCharacterList) != 0); } } + public bool NewCharacterCreation { get { return ((_ProtocolChanges & ProtocolChanges.NewCharacterCreation) != 0); } } + public bool ExtendedStatus { get { return ((_ProtocolChanges & ProtocolChanges.ExtendedStatus) != 0); } } + public bool NewMobileIncoming { get { return ((_ProtocolChanges & ProtocolChanges.NewMobileIncoming) != 0); } } + + public bool IsUOTDClient + { + get + { + return ((m_Flags & ClientFlags.UOTD) != 0 || (m_Version != null && m_Version.Type == ClientType.UOTD)); + } + } + + public bool IsSAClient + { + get + { + return (m_Version != null && m_Version.Type == ClientType.SA); + } + } + + public List Trades + { + get + { + return m_Trades; + } + } + + public void ValidateAllTrades() + { + for (int i = m_Trades.Count - 1; i >= 0; --i) + { + if (i >= m_Trades.Count) + { + continue; + } + + SecureTrade trade = m_Trades[i]; + + if (trade.From.Mobile.Deleted || trade.To.Mobile.Deleted || !trade.From.Mobile.Alive || !trade.To.Mobile.Alive || !trade.From.Mobile.InRange(trade.To.Mobile, 2) || trade.From.Mobile.Map != trade.To.Mobile.Map) + { + trade.Cancel(); + } + } + } + + public void CancelAllTrades() + { + for (int i = m_Trades.Count - 1; i >= 0; --i) + { + if (i < m_Trades.Count) + { + m_Trades[i].Cancel(); + } + } + } + + public void RemoveTrade(SecureTrade trade) + { + m_Trades.Remove(trade); + } + + public SecureTrade FindTrade(Mobile m) + { + for (int i = 0; i < m_Trades.Count; ++i) + { + SecureTrade trade = m_Trades[i]; + + if (trade.From.Mobile == m || trade.To.Mobile == m) + { + return trade; + } + } + + return null; + } + + public SecureTradeContainer FindTradeContainer(Mobile m) + { + for (int i = 0; i < m_Trades.Count; ++i) + { + SecureTrade trade = m_Trades[i]; + + SecureTradeInfo from = trade.From; + SecureTradeInfo to = trade.To; + + if (from.Mobile == m_Mobile && to.Mobile == m) + { + return from.Container; + } + else if (from.Mobile == m && to.Mobile == m_Mobile) + { + return to.Container; + } + } + + return null; + } + + public SecureTradeContainer AddTrade(NetState state) + { + SecureTrade newTrade = new SecureTrade(m_Mobile, state.m_Mobile); + + m_Trades.Add(newTrade); + state.m_Trades.Add(newTrade); + + return newTrade.From.Container; + } + + public bool CompressionEnabled + { + get + { + return m_CompressionEnabled; + } + set + { + m_CompressionEnabled = value; + } + } + + public int Sequence + { + get + { + return m_Sequence; + } + set + { + m_Sequence = value; + } + } + + public IEnumerable Gumps + { + get + { + return m_Gumps; + } + } + + public IEnumerable HuePickers + { + get + { + return m_HuePickers; + } + } + + public IEnumerable Menus + { + get + { + return m_Menus; + } + } + + private static int m_GumpCap = 512, m_HuePickerCap = 512, m_MenuCap = 512; + + public static int GumpCap + { + get + { + return m_GumpCap; + } + set + { + m_GumpCap = value; + } + } + + public static int HuePickerCap + { + get + { + return m_HuePickerCap; + } + set + { + m_HuePickerCap = value; + } + } + + public static int MenuCap + { + get + { + return m_MenuCap; + } + set + { + m_MenuCap = value; + } + } + + public void WriteConsole(string text) + { + Console.WriteLine("Client: {0}: {1}", this, text); + } + + public void WriteConsole(string format, params object[] args) + { + WriteConsole(String.Format(format, args)); + } + + public void AddMenu(IMenu menu) + { + if (m_Menus == null) + { + m_Menus = new List(); + } + + if (m_Menus.Count < m_MenuCap) + { + m_Menus.Add(menu); + } + else + { + WriteConsole("Exceeded menu cap, disconnecting..."); + Dispose(); + } + } + + public void RemoveMenu(IMenu menu) + { + if (m_Menus != null) + { + m_Menus.Remove(menu); + } + } + + public void RemoveMenu(int index) + { + if (m_Menus != null) + { + m_Menus.RemoveAt(index); + } + } + + public void ClearMenus() + { + if (m_Menus != null) + { + m_Menus.Clear(); + } + } + + public void AddHuePicker(HuePicker huePicker) + { + if (m_HuePickers == null) + { + m_HuePickers = new List(); + } + + if (m_HuePickers.Count < m_HuePickerCap) + { + m_HuePickers.Add(huePicker); + } + else + { + WriteConsole("Exceeded hue picker cap, disconnecting..."); + Dispose(); + } + } + + public void RemoveHuePicker(HuePicker huePicker) + { + if (m_HuePickers != null) + { + m_HuePickers.Remove(huePicker); + } + } + + public void RemoveHuePicker(int index) + { + if (m_HuePickers != null) + { + m_HuePickers.RemoveAt(index); + } + } + + public void ClearHuePickers() + { + if (m_HuePickers != null) + { + m_HuePickers.Clear(); + } + } + + public void AddGump(Gump gump) + { + if (m_Gumps == null) + { + m_Gumps = new List(); + } + + if (m_Gumps.Count < m_GumpCap) + { + m_Gumps.Add(gump); + } + else + { + WriteConsole("Exceeded gump cap, disconnecting..."); + Dispose(); + } + } + + public void RemoveGump(Gump gump) + { + if (m_Gumps != null) + { + m_Gumps.Remove(gump); + } + } + + public void RemoveGump(int index) + { + if (m_Gumps != null) + { + m_Gumps.RemoveAt(index); + } + } + + public void ClearGumps() + { + if (m_Gumps != null) + { + m_Gumps.Clear(); + } + } + + public void LaunchBrowser(string url) + { + Send(new MessageLocalized(Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", "")); + Send(new LaunchBrowser(url)); + } + + public CityInfo[] CityInfo + { + get + { + return m_CityInfo; + } + set + { + m_CityInfo = value; + } + } + + public Mobile Mobile + { + get + { + return m_Mobile; + } + set + { + m_Mobile = value; + } + } + + public ServerInfo[] ServerInfo + { + get + { + return m_ServerInfo; + } + set + { + m_ServerInfo = value; + } + } + + public IAccount Account + { + get + { + return m_Account; + } + set + { + m_Account = value; + } + } + + public override string ToString() + { + return m_ToString; + } + + private static List m_Instances = new List(); + + public static List Instances + { + get + { + return m_Instances; + } + } + + private static BufferPool m_ReceiveBufferPool = new BufferPool("Receive", 2048, 2048); + + public NetState(Socket socket, MessagePump messagePump) + { + m_Socket = socket; + m_Buffer = new ByteQueue(); + m_Seeded = false; + m_Running = false; + m_RecvBuffer = m_ReceiveBufferPool.AcquireBuffer(); + m_MessagePump = messagePump; + m_Gumps = new List(); + m_HuePickers = new List(); + m_Menus = new List(); + m_Trades = new List(); + + m_SendQueue = new SendQueue(); + + m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes(0.5); + + m_Instances.Add(this); + //Plume : Net 4 + /*try + { + m_Address = Utility.Intern(((IPEndPoint)m_Socket.RemoteEndPoint).Address); + m_ToString = m_Address.ToString(); + } + catch (Exception ex) + { + TraceException(ex); + m_Address = IPAddress.None; + m_ToString = "(error)"; + }*/ + + ReadAddress(); + + m_ConnectedOn = DateTime.Now; + + if (m_CreatedCallback != null) + { + m_CreatedCallback(this); + } + } + + public virtual void Send(Packet p) + { + if (m_Socket == null || m_BlockAllPackets) + { + p.OnSend(); + return; + } + + PacketSendProfile prof = PacketSendProfile.Acquire(p.GetType()); + + int length; + byte[] buffer = p.Compile(m_CompressionEnabled, out length); + + if (buffer != null) + { + if (buffer.Length <= 0 || length <= 0) + { + p.OnSend(); + return; + } + + if (prof != null) + { + prof.Start(); + } + + if (m_Encoder != null) + { + m_Encoder.EncodeOutgoingPacket(this, ref buffer, ref length); + } + + try + { + SendQueue.Gram gram; + + lock (m_SendQueue) + { + gram = m_SendQueue.Enqueue(buffer, length); + } + //Plume : Net 4 + //if (gram != null) + if ((gram != null) && !m_Disposing) + { +#if NewAsyncSockets + m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length ); + Send_Start(); +#else + try + { + m_Socket.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket); + } + catch (Exception ex) + { + TraceException(ex); + Dispose(false); + } +#endif + } + } + catch (CapacityExceededException) + { + Console.WriteLine("Client: {0}: Too much data pending, disconnecting...", this); + Dispose(false); + } + + p.OnSend(); + + if (prof != null) + { + prof.Finish(length); + } + } + else + { + Console.WriteLine("Client: {0}: null buffer send, disconnecting...", this); + using (StreamWriter op = new StreamWriter("null_send.log", true)) + { + op.WriteLine("{0} Client: {1}: null buffer send, disconnecting...", DateTime.Now, this); + op.WriteLine(new System.Diagnostics.StackTrace()); + } + Dispose(); + } + } + +#if NewAsyncSockets + public void Start() { + //Plume : Net 4 + //m_ReceiveEventArgs = new SocketAsyncEventArgs(); + m_ReceiveEventArgs = m_SocketAsyncReceiveEventPool.Pop(); + m_ReceiveEventArgs.Completed += new EventHandler( Receive_Completion ); + m_ReceiveEventArgs.SetBuffer( m_RecvBuffer, 0, m_RecvBuffer.Length ); + + //Plume : Net 4 + //m_SendEventArgs = new SocketAsyncEventArgs(); + m_SendEventArgs = m_SocketAsyncSendEventPool.Pop(); + m_SendEventArgs.Completed += new EventHandler( Send_Completion ); + + m_Running = true; + + if ( m_Socket == null || m_Paused ) { + return; + } + + Receive_Start(); + } + + private void Receive_Start() + { + try { + bool result = false; + + do { + lock ( m_AsyncLock ) { + if ( ( m_AsyncState & ( AsyncState.Pending | AsyncState.Paused ) ) == 0 ) { + m_AsyncState |= AsyncState.Pending; + result = !m_Socket.ReceiveAsync( m_ReceiveEventArgs ); + + if ( result ) + Receive_Process( m_ReceiveEventArgs ); + } + } + //Plume : Net 4 + //} while ( result ); + } while ( result && !m_Disposing ); + } catch ( Exception ex ) { + TraceException( ex ); + Dispose( false ); + } + } + + private void Receive_Completion( object sender, SocketAsyncEventArgs e ) + { + Receive_Process( e ); + + if ( !m_Disposing ) + Receive_Start(); + } + + private void Receive_Process( SocketAsyncEventArgs e ) + { + //Plume : Net 4 + /*int byteCount = e.BytesTransferred; + + if ( e.SocketError != SocketError.Success || byteCount <= 0 ) { + Dispose( false ); + return; + } + + m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 ); + + byte[] buffer = m_RecvBuffer; + + if ( m_Encoder != null ) + m_Encoder.DecodeIncomingPacket( this, ref buffer, ref byteCount ); + + lock ( m_Buffer ) + m_Buffer.Enqueue( buffer, 0, byteCount ); + + m_MessagePump.OnReceive( this ); + + lock ( m_AsyncLock ) { + m_AsyncState &= ~AsyncState.Pending;*/ + + try + { + if (!m_Disposing) + { + int byteCount = e.BytesTransferred; + if ( e.SocketError != SocketError.Success || byteCount <= 0 ) + { + Dispose( false ); + return; + } + else + { + m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 ); + byte[] buffer = m_RecvBuffer; + if ( m_Encoder != null ) + m_Encoder.DecodeIncomingPacket( this, ref buffer, ref byteCount ); + if (m_Buffer != null) + { + lock ( m_Buffer ) + m_Buffer.Enqueue( buffer, 0, byteCount ); + if (!m_Disposing) + { + m_MessagePump.OnReceive( this ); + lock ( m_AsyncLock ) + { + m_AsyncState &= ~AsyncState.Pending; + } + } + } + } + } + } + catch (Exception ex) + { + Console.WriteLine("Exception on Netstate in Receive_Process"); + Console.WriteLine(ex.Message); + Console.WriteLine(ex.StackTrace); + } + } + } + + private void Send_Start() + { + try { + bool result = false; + + do { + result = !m_Socket.SendAsync( m_SendEventArgs ); + + if ( result ) + Send_Process( m_SendEventArgs ); + //Plume : Net 4 + //} while ( result ); + } while ( result && !m_Disposing ); + } catch ( Exception ex ) { + TraceException( ex ); + Dispose( false ); + } + } + + private void Send_Completion( object sender, SocketAsyncEventArgs e ) + { + Send_Process( e ); + + if ( m_Disposing ) + return; + + if ( m_CoalesceSleep >= 0 ) { + Thread.Sleep( m_CoalesceSleep ); + } + + SendQueue.Gram gram; + + lock ( m_SendQueue ) { + gram = m_SendQueue.Dequeue(); + } + //Plume : Net 4 + //if ( gram != null ) { + if ( gram != null && !m_Disposing ) { + m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length ); + Send_Start(); + } + } + + private void Send_Process( SocketAsyncEventArgs e ) + { + int bytes = e.BytesTransferred; + + if ( e.SocketError != SocketError.Success || bytes <= 0 ) { + Dispose( false ); + return; + } + + m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes( 1.2 ); + } + + public static void Pause() { + m_Paused = true; + + for ( int i = 0; i < m_Instances.Count; ++i ) { + NetState ns = m_Instances[i]; + + lock ( ns.m_AsyncLock ) { + ns.m_AsyncState |= AsyncState.Paused; + } + } + } + + public static void Resume() { + m_Paused = false; + + for ( int i = 0; i < m_Instances.Count; ++i ) { + NetState ns = m_Instances[i]; + + if ( ns.m_Socket == null ) { + continue; + } + + lock ( ns.m_AsyncLock ) { + ns.m_AsyncState &= ~AsyncState.Paused; + + if ( ( ns.m_AsyncState & AsyncState.Pending ) == 0 ) + ns.Receive_Start(); + } + } + } + + public bool Flush() { + if ( m_Socket == null || !m_SendQueue.IsFlushReady ) { + return false; + } + + SendQueue.Gram gram; + + lock ( m_SendQueue ) { + gram = m_SendQueue.CheckFlushReady(); + } + + if ( gram != null ) { + m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length ); + Send_Start(); + } + + return false; + } + +#else + + public void Start() + { + m_OnReceive = new AsyncCallback(OnReceive); + m_OnSend = new AsyncCallback(OnSend); + + m_Running = true; + + if (m_Socket == null || m_Paused) + { + return; + } + + try + { + lock (m_AsyncLock) + { + if ((m_AsyncState & (AsyncState.Pending | AsyncState.Paused)) == 0) + { + InternalBeginReceive(); + } + } + } + catch (Exception ex) + { + TraceException(ex); + Dispose(false); + } + } + + private void InternalBeginReceive() + { + m_AsyncState |= AsyncState.Pending; + + m_Socket.BeginReceive(m_RecvBuffer, 0, m_RecvBuffer.Length, SocketFlags.None, m_OnReceive, m_Socket); + } + + private void OnReceive(IAsyncResult asyncResult) + { + Socket s = (Socket)asyncResult.AsyncState; + + try + { + int byteCount = s.EndReceive(asyncResult); + + if (byteCount > 0) + { + m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes(1.2); + + byte[] buffer = m_RecvBuffer; + + if (m_Encoder != null) + m_Encoder.DecodeIncomingPacket(this, ref buffer, ref byteCount); + + lock (m_Buffer) + m_Buffer.Enqueue(buffer, 0, byteCount); + + m_MessagePump.OnReceive(this); + + lock (m_AsyncLock) + { + m_AsyncState &= ~AsyncState.Pending; + + if ((m_AsyncState & AsyncState.Paused) == 0) + { + try + { + InternalBeginReceive(); + } + catch (Exception ex) + { + TraceException(ex); + Dispose(false); + } + } + } + } + else + { + Dispose(false); + } + } + catch + { + Dispose(false); + } + } + + private void OnSend(IAsyncResult asyncResult) + { + Socket s = (Socket)asyncResult.AsyncState; + + try + { + int bytes = s.EndSend(asyncResult); + + if (bytes <= 0) + { + Dispose(false); + return; + } + + m_NextCheckActivity = DateTime.Now + TimeSpan.FromMinutes(1.2); + + if (m_CoalesceSleep >= 0) + { + Thread.Sleep(m_CoalesceSleep); + } + + SendQueue.Gram gram; + + lock (m_SendQueue) + { + gram = m_SendQueue.Dequeue(); + } + + if (gram != null) + { + try + { + s.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s); + } + catch (Exception ex) + { + TraceException(ex); + Dispose(false); + } + } + } + catch (Exception) + { + Dispose(false); + } + } + + public static void Pause() + { + m_Paused = true; + + for (int i = 0; i < m_Instances.Count; ++i) + { + NetState ns = m_Instances[i]; + + lock (ns.m_AsyncLock) + { + ns.m_AsyncState |= AsyncState.Paused; + } + } + } + + public static void Resume() + { + m_Paused = false; + + for (int i = 0; i < m_Instances.Count; ++i) + { + NetState ns = m_Instances[i]; + + if (ns.m_Socket == null) + { + continue; + } + + lock (ns.m_AsyncLock) + { + ns.m_AsyncState &= ~AsyncState.Paused; + + try + { + if ((ns.m_AsyncState & AsyncState.Pending) == 0) + ns.InternalBeginReceive(); + } + catch (Exception ex) + { + TraceException(ex); + ns.Dispose(false); + } + } + } + } + + public bool Flush() + { + if (m_Socket == null || !m_SendQueue.IsFlushReady) + { + return false; + } + + SendQueue.Gram gram; + + lock (m_SendQueue) + { + gram = m_SendQueue.CheckFlushReady(); + } + + if (gram != null) + { + try + { + m_Socket.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket); + return true; + } + catch (Exception ex) + { + TraceException(ex); + Dispose(false); + } + } + + return false; + } +#endif + + public PacketHandler GetHandler(int packetID) + { + if (ContainerGridLines) + return PacketHandlers.Get6017Handler(packetID); + else + return PacketHandlers.GetHandler(packetID); + } + + public static void FlushAll() + { + for (int i = 0; i < m_Instances.Count; ++i) + { + NetState ns = m_Instances[i]; + + ns.Flush(); + } + } + + private static int m_CoalesceSleep = -1; + + public static int CoalesceSleep + { + get + { + return m_CoalesceSleep; + } + set + { + m_CoalesceSleep = value; + } + } + + private DateTime m_NextCheckActivity; + + public bool CheckAlive() + { + if (m_Socket == null) + return false; + + if (DateTime.Now < m_NextCheckActivity) + { + return true; + } + + Console.WriteLine("Client: {0}: Disconnecting due to inactivity...", this); + + Dispose(); + return false; + } + + public static void TraceException(Exception ex) + { + if (!Core.Debug) + return; + + try + { + using (StreamWriter op = new StreamWriter("network-errors.log", true)) + { + op.WriteLine("# {0}", DateTime.Now); + + op.WriteLine(ex); + + op.WriteLine(); + op.WriteLine(); + } + } + catch + { + } + + try + { + Console.WriteLine(ex); + } + catch + { + } + } + + private bool m_Disposing; + + public void Dispose() + { + Dispose(true); + } + + public virtual void Dispose(bool flush) + { + if (m_Socket == null || m_Disposing) + { + return; + } + + m_Disposing = true; + + if (flush) + flush = Flush(); + + try + { + m_Socket.Shutdown(SocketShutdown.Both); + } + catch (SocketException ex) + { + TraceException(ex); + } + + try + { + m_Socket.Close(); + } + catch (SocketException ex) + { + TraceException(ex); + } + + if (m_RecvBuffer != null) + m_ReceiveBufferPool.ReleaseBuffer(m_RecvBuffer); + //Plume : Net 4 +#if NewAsyncSockets + m_ReceiveEventArgs.Completed -= new EventHandler(Receive_Completion); + m_SendEventArgs.Completed -= new EventHandler(Send_Completion); + m_SocketAsyncReceiveEventPool.Push(m_ReceiveEventArgs); + m_SocketAsyncSendEventPool.Push(m_SendEventArgs); + m_Socket = null; + + m_Buffer = null; + m_RecvBuffer = null; + +//#if NewAsyncSockets + //m_ReceiveEventArgs = null; + //m_SendEventArgs = null; +#else + //Plume : Net 4 + m_Socket = null; + m_Buffer = null; + m_RecvBuffer = null; + + m_OnReceive = null; + m_OnSend = null; +#endif + + m_Running = false; + + m_Disposed.Enqueue(this); + + if ( /*!flush &&*/ !m_SendQueue.IsEmpty) + { + lock (m_SendQueue) + m_SendQueue.Clear(); + } + } + + public static void Initialize() + { + Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.5), new TimerCallback(CheckAllAlive)); + } + + public static void CheckAllAlive() + { + try + { + for (int i = 0; i < m_Instances.Count; ++i) + { + m_Instances[i].CheckAlive(); + } + } + catch (Exception ex) + { + TraceException(ex); + } + } + + private static Queue m_Disposed = Queue.Synchronized(new Queue()); + + public static void ProcessDisposedQueue() + { + int breakout = 0; + + while (breakout < 200 && m_Disposed.Count > 0) + { + ++breakout; + + NetState ns = (NetState)m_Disposed.Dequeue(); + + Mobile m = ns.m_Mobile; + IAccount a = ns.m_Account; + + if (m != null) + { + m.NetState = null; + ns.m_Mobile = null; + } + + ns.m_Gumps.Clear(); + ns.m_Menus.Clear(); + ns.m_HuePickers.Clear(); + ns.m_Account = null; + ns.m_ServerInfo = null; + ns.m_CityInfo = null; + + m_Instances.Remove(ns); + + if (a != null) + { + ns.WriteConsole("Disconnected. [{0} Online] [{1}]", m_Instances.Count, a); + } + else + { + ns.WriteConsole("Disconnected. [{0} Online]", m_Instances.Count); + } + } + } + //Plume : Net 4 + public virtual void ReadAddress() + { + try { + m_Address = Utility.Intern( ( ( IPEndPoint ) m_Socket.RemoteEndPoint ).Address ); + m_ToString = m_Address.ToString(); + } catch ( Exception ex ) { + TraceException( ex ); + m_Address = IPAddress.None; + m_ToString = "(error)"; + } + } + + public bool Running + { + get + { + return m_Running; + } + } + + public bool Seeded + { + get + { + return m_Seeded; + } + set + { + m_Seeded = value; + } + } + + public Socket Socket + { + get + { + return m_Socket; + } + } + + public ByteQueue Buffer + { + get + { + return m_Buffer; + } + } + + public ExpansionInfo ExpansionInfo + { + get + { + for (int i = ExpansionInfo.Table.Length - 1; i >= 0; i--) + { + ExpansionInfo info = ExpansionInfo.Table[i]; + + if ((info.RequiredClient != null && this.Version >= info.RequiredClient) || ((this.Flags & info.ClientFlags) != 0)) + { + return info; + } + } + + return ExpansionInfo.GetInfo(Expansion.None); + } + } + + public Expansion Expansion + { + get + { + return (Expansion)this.ExpansionInfo.ID; + } + } + + public bool SupportsExpansion(ExpansionInfo info, bool checkCoreExpansion) + { + if (info == null || (checkCoreExpansion && (int)Core.Expansion < info.ID)) + return false; + + if (info.RequiredClient != null) + return (this.Version >= info.RequiredClient); + + return ((this.Flags & info.ClientFlags) != 0); + } + + public bool SupportsExpansion(Expansion ex, bool checkCoreExpansion) + { + return SupportsExpansion(ExpansionInfo.GetInfo(ex), checkCoreExpansion); + } + + public bool SupportsExpansion(Expansion ex) + { + return SupportsExpansion(ex, true); + } + + public bool SupportsExpansion(ExpansionInfo info) + { + return SupportsExpansion(info, true); + } + + public int CompareTo( NetState other ) { + if ( other == null ) + return 1; + + return m_ToString.CompareTo( other.m_ToString ); + } + } +} \ No newline at end of file diff --git a/Server/Network/PacketHandler.cs b/Server/Network/PacketHandler.cs new file mode 100644 index 0000000..8a09668 --- /dev/null +++ b/Server/Network/PacketHandler.cs @@ -0,0 +1,82 @@ +/*************************************************************************** + * PacketHandler.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: PacketHandler.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Network +{ + public delegate void OnPacketReceive( NetState state, PacketReader pvSrc ); + public delegate bool ThrottlePacketCallback( NetState state ); + + public class PacketHandler + { + private int m_PacketID; + private int m_Length; + private bool m_Ingame; + private OnPacketReceive m_OnReceive; + private ThrottlePacketCallback m_ThrottleCallback; + + public PacketHandler( int packetID, int length, bool ingame, OnPacketReceive onReceive ) + { + m_PacketID = packetID; + m_Length = length; + m_Ingame = ingame; + m_OnReceive = onReceive; + } + + public int PacketID + { + get + { + return m_PacketID; + } + } + + public int Length + { + get + { + return m_Length; + } + } + + public OnPacketReceive OnReceive + { + get + { + return m_OnReceive; + } + } + + public ThrottlePacketCallback ThrottleCallback + { + get{ return m_ThrottleCallback; } + set{ m_ThrottleCallback = value; } + } + + public bool Ingame + { + get + { + return m_Ingame; + } + } + } +} \ No newline at end of file diff --git a/Server/Network/PacketHandlers.cs b/Server/Network/PacketHandlers.cs new file mode 100644 index 0000000..669246f --- /dev/null +++ b/Server/Network/PacketHandlers.cs @@ -0,0 +1,2663 @@ +/*************************************************************************** + * PacketHandlers.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: PacketHandlers.cs 1064 2013-05-28 17:44:07Z mark@runuo.com $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using Server.Accounting; +using Server.Gumps; +using Server.Targeting; +using Server.Items; +using Server.Menus; +using Server.Mobiles; +using Server.Movement; +using Server.Prompts; +using Server.HuePickers; +using Server.ContextMenus; +using Server.Diagnostics; +using CV = Server.ClientVersion; + +namespace Server.Network +{ + public enum MessageType + { + Regular = 0x00, + System = 0x01, + Emote = 0x02, + Label = 0x06, + Focus = 0x07, + Whisper = 0x08, + Yell = 0x09, + Spell = 0x0A, + + Guild = 0x0D, + Alliance = 0x0E, + Command = 0x0F, + + Encoded = 0xC0 + } + + public static class PacketHandlers + { + private static PacketHandler[] m_Handlers; + private static PacketHandler[] m_6017Handlers; + + private static PacketHandler[] m_ExtendedHandlersLow; + private static Dictionary m_ExtendedHandlersHigh; + + private static EncodedPacketHandler[] m_EncodedHandlersLow; + private static Dictionary m_EncodedHandlersHigh; + + public static PacketHandler[] Handlers + { + get{ return m_Handlers; } + } + + static PacketHandlers() + { + m_Handlers = new PacketHandler[0x100]; + m_6017Handlers = new PacketHandler[0x100]; + + m_ExtendedHandlersLow = new PacketHandler[0x100]; + m_ExtendedHandlersHigh = new Dictionary(); + + m_EncodedHandlersLow = new EncodedPacketHandler[0x100]; + m_EncodedHandlersHigh = new Dictionary(); + + Register(0x00, 104, false, new OnPacketReceive(CreateCharacter)); + Register(0x01, 5, false, new OnPacketReceive(Disconnect)); + Register(0x02, 7, true, new OnPacketReceive(MovementReq)); + Register(0x03, 0, true, new OnPacketReceive(AsciiSpeech)); + Register(0x04, 2, true, new OnPacketReceive(GodModeRequest)); + Register(0x05, 5, true, new OnPacketReceive(AttackReq)); + Register(0x06, 5, true, new OnPacketReceive(UseReq)); + Register(0x07, 7, true, new OnPacketReceive(LiftReq)); + Register(0x08, 14, true, new OnPacketReceive(DropReq)); + Register(0x09, 5, true, new OnPacketReceive(LookReq)); + Register(0x0A, 11, true, new OnPacketReceive(Edit)); + Register(0x12, 0, true, new OnPacketReceive(TextCommand)); + Register(0x13, 10, true, new OnPacketReceive(EquipReq)); + Register(0x14, 6, true, new OnPacketReceive(ChangeZ)); + Register(0x22, 3, true, new OnPacketReceive(Resynchronize)); + Register(0x2C, 2, true, new OnPacketReceive(DeathStatusResponse)); + Register(0x34, 10, true, new OnPacketReceive(MobileQuery)); + Register(0x3A, 0, true, new OnPacketReceive(ChangeSkillLock)); + Register(0x3B, 0, true, new OnPacketReceive(VendorBuyReply)); + Register(0x47, 11, true, new OnPacketReceive(NewTerrain)); + Register(0x48, 73, true, new OnPacketReceive(NewAnimData)); + Register(0x58, 106, true, new OnPacketReceive(NewRegion)); + Register(0x5D, 73, false, new OnPacketReceive(PlayCharacter)); + Register(0x61, 9, true, new OnPacketReceive(DeleteStatic)); + Register(0x6C, 19, true, new OnPacketReceive(TargetResponse)); + Register(0x6F, 0, true, new OnPacketReceive(SecureTrade)); + Register(0x72, 5, true, new OnPacketReceive(SetWarMode)); + Register(0x73, 2, false, new OnPacketReceive(PingReq)); + Register(0x75, 35, true, new OnPacketReceive(RenameRequest)); + Register(0x79, 9, true, new OnPacketReceive(ResourceQuery)); + Register(0x7E, 2, true, new OnPacketReceive(GodviewQuery)); + Register(0x7D, 13, true, new OnPacketReceive(MenuResponse)); + Register(0x80, 62, false, new OnPacketReceive(AccountLogin)); + Register(0x83, 39, false, new OnPacketReceive(DeleteCharacter)); + Register(0x91, 65, false, new OnPacketReceive(GameLogin)); + Register(0x95, 9, true, new OnPacketReceive(HuePickerResponse)); + Register(0x96, 0, true, new OnPacketReceive(GameCentralMoniter)); + Register(0x98, 0, true, new OnPacketReceive(MobileNameRequest)); + Register(0x9A, 0, true, new OnPacketReceive(AsciiPromptResponse)); + Register(0x9B, 258, true, new OnPacketReceive(HelpRequest)); + Register(0x9D, 51, true, new OnPacketReceive(GMSingle)); + Register(0x9F, 0, true, new OnPacketReceive(VendorSellReply)); + Register(0xA0, 3, false, new OnPacketReceive(PlayServer)); + Register(0xA4, 149, false, new OnPacketReceive(SystemInfo)); + Register(0xA7, 4, true, new OnPacketReceive(RequestScrollWindow)); + Register(0xAD, 0, true, new OnPacketReceive(UnicodeSpeech)); + Register(0xB1, 0, true, new OnPacketReceive(DisplayGumpResponse)); + Register(0xB5, 64, true, new OnPacketReceive(ChatRequest)); + Register(0xB6, 9, true, new OnPacketReceive(ObjectHelpRequest)); + Register(0xB8, 0, true, new OnPacketReceive(ProfileReq)); + Register(0xBB, 9, false, new OnPacketReceive(AccountID)); + Register(0xBD, 0, false, new OnPacketReceive(ClientVersion)); + Register(0xBE, 0, true, new OnPacketReceive(AssistVersion)); + Register(0xBF, 0, true, new OnPacketReceive(ExtendedCommand)); + Register(0xC2, 0, true, new OnPacketReceive(UnicodePromptResponse)); + Register(0xC8, 2, true, new OnPacketReceive(SetUpdateRange)); + Register(0xC9, 6, true, new OnPacketReceive(TripTime)); + Register(0xCA, 6, true, new OnPacketReceive(UTripTime)); + Register(0xCF, 0, false, new OnPacketReceive(AccountLogin)); + Register(0xD0, 0, true, new OnPacketReceive(ConfigurationFile)); + Register(0xD1, 2, true, new OnPacketReceive(LogoutReq)); + Register(0xD6, 0, true, new OnPacketReceive(BatchQueryProperties)); + Register(0xD7, 0, true, new OnPacketReceive(EncodedCommand)); + Register(0xE1, 0, false, new OnPacketReceive(ClientType)); + Register(0xEF, 21, false, new OnPacketReceive(LoginServerSeed)); + //Plume : Net 4 + Register(0xF4, 0, true, new OnPacketReceive(ClientCrashReport)); + + Register(0xF8, 106, false, new OnPacketReceive(CreateCharacter70160)); + + + Register6017( 0x08, 15, true, new OnPacketReceive( DropReq6017 ) ); + + RegisterExtended( 0x05, false, new OnPacketReceive( ScreenSize ) ); + RegisterExtended( 0x06, true, new OnPacketReceive( PartyMessage ) ); + RegisterExtended( 0x07, true, new OnPacketReceive( QuestArrow ) ); + RegisterExtended( 0x09, true, new OnPacketReceive( DisarmRequest ) ); + RegisterExtended( 0x0A, true, new OnPacketReceive( StunRequest ) ); + RegisterExtended( 0x0B, false, new OnPacketReceive( Language ) ); + RegisterExtended( 0x0C, true, new OnPacketReceive( CloseStatus ) ); + RegisterExtended( 0x0E, true, new OnPacketReceive( Animate ) ); + RegisterExtended( 0x0F, false, new OnPacketReceive( Empty ) ); // What's this? + RegisterExtended( 0x10, true, new OnPacketReceive( QueryProperties ) ); + RegisterExtended( 0x13, true, new OnPacketReceive( ContextMenuRequest ) ); + RegisterExtended( 0x15, true, new OnPacketReceive( ContextMenuResponse ) ); + RegisterExtended( 0x1A, true, new OnPacketReceive( StatLockChange ) ); + RegisterExtended( 0x1C, true, new OnPacketReceive( CastSpell ) ); + RegisterExtended( 0x24, false, new OnPacketReceive( UnhandledBF ) ); + + RegisterEncoded( 0x19, true, new OnEncodedPacketReceive( SetAbility ) ); + RegisterEncoded( 0x28, true, new OnEncodedPacketReceive( GuildGumpRequest ) ); + + RegisterEncoded( 0x32, true, new OnEncodedPacketReceive( QuestGumpRequest ) ); + } + + public static void Register( int packetID, int length, bool ingame, OnPacketReceive onReceive ) + { + m_Handlers[packetID] = new PacketHandler( packetID, length, ingame, onReceive ); + + if ( m_6017Handlers[packetID] == null ) + m_6017Handlers[packetID] = new PacketHandler( packetID, length, ingame, onReceive ); + } + + public static PacketHandler GetHandler( int packetID ) + { + return m_Handlers[packetID]; + } + + public static void Register6017( int packetID, int length, bool ingame, OnPacketReceive onReceive ) + { + m_6017Handlers[packetID] = new PacketHandler( packetID, length, ingame, onReceive ); + } + + public static PacketHandler Get6017Handler( int packetID ) + { + return m_6017Handlers[packetID]; + } + + public static void RegisterExtended( int packetID, bool ingame, OnPacketReceive onReceive ) + { + if ( packetID >= 0 && packetID < 0x100 ) + m_ExtendedHandlersLow[packetID] = new PacketHandler( packetID, 0, ingame, onReceive ); + else + m_ExtendedHandlersHigh[packetID] = new PacketHandler( packetID, 0, ingame, onReceive ); + } + + public static PacketHandler GetExtendedHandler( int packetID ) + { + if ( packetID >= 0 && packetID < 0x100 ) + return m_ExtendedHandlersLow[packetID]; + else + { + PacketHandler handler; + m_ExtendedHandlersHigh.TryGetValue( packetID, out handler ); + return handler; + } + } + + public static void RemoveExtendedHandler( int packetID ) + { + if ( packetID >= 0 && packetID < 0x100 ) + m_ExtendedHandlersLow[packetID] = null; + else + m_ExtendedHandlersHigh.Remove( packetID ); + } + + public static void RegisterEncoded( int packetID, bool ingame, OnEncodedPacketReceive onReceive ) + { + if ( packetID >= 0 && packetID < 0x100 ) + m_EncodedHandlersLow[packetID] = new EncodedPacketHandler( packetID, ingame, onReceive ); + else + m_EncodedHandlersHigh[packetID] = new EncodedPacketHandler( packetID, ingame, onReceive ); + } + + public static EncodedPacketHandler GetEncodedHandler( int packetID ) + { + if ( packetID >= 0 && packetID < 0x100 ) + return m_EncodedHandlersLow[packetID]; + else + { + EncodedPacketHandler handler; + m_EncodedHandlersHigh.TryGetValue( packetID, out handler ); + return handler; + } + } + + public static void RemoveEncodedHandler( int packetID ) + { + if ( packetID >= 0 && packetID < 0x100 ) + m_EncodedHandlersLow[packetID] = null; + else + m_EncodedHandlersHigh.Remove( packetID ); + } + + public static void RegisterThrottler( int packetID, ThrottlePacketCallback t ) + { + PacketHandler ph = GetHandler( packetID ); + + if ( ph != null ) + ph.ThrottleCallback = t; + + ph = Get6017Handler( packetID ); + + if ( ph != null ) + ph.ThrottleCallback = t; + } + + private static void UnhandledBF( NetState state, PacketReader pvSrc ) + { + } + + public static void Empty( NetState state, PacketReader pvSrc ) + { + } + + public static void SetAbility( NetState state, IEntity e, EncodedReader reader ) + { + EventSink.InvokeSetAbility( new SetAbilityEventArgs( state.Mobile, reader.ReadInt32() ) ); + } + + public static void GuildGumpRequest( NetState state, IEntity e, EncodedReader reader ) + { + EventSink.InvokeGuildGumpRequest( new GuildGumpRequestArgs( state.Mobile ) ); + } + + public static void QuestGumpRequest( NetState state, IEntity e, EncodedReader reader ) + { + EventSink.InvokeQuestGumpRequest( new QuestGumpRequestArgs( state.Mobile ) ); + } + + public static void EncodedCommand( NetState state, PacketReader pvSrc ) + { + IEntity e = World.FindEntity( pvSrc.ReadInt32() ); + int packetID = pvSrc.ReadUInt16(); + + EncodedPacketHandler ph = GetEncodedHandler( packetID ); + + if ( ph != null ) + { + if ( ph.Ingame && state.Mobile == null ) + { + Console.WriteLine( "Client: {0}: Sent ingame packet (0xD7x{1:X2}) before having been attached to a mobile", state, packetID ); + state.Dispose(); + } + else if ( ph.Ingame && state.Mobile.Deleted ) + { + state.Dispose(); + } + else + { + ph.OnReceive( state, e, new EncodedReader( pvSrc ) ); + } + } + else + { + pvSrc.Trace( state ); + } + } + + public static void RenameRequest( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + Mobile targ = World.FindMobile( pvSrc.ReadInt32() ); + + if ( targ != null ) + EventSink.InvokeRenameRequest( new RenameRequestEventArgs( from, targ, pvSrc.ReadStringSafe() ) ); + } + + public static void ChatRequest( NetState state, PacketReader pvSrc ) + { + EventSink.InvokeChatRequest( new ChatRequestEventArgs( state.Mobile ) ); + } + + public static void SecureTrade( NetState state, PacketReader pvSrc ) + { + switch ( pvSrc.ReadByte() ) + { + case 1: // Cancel + { + Serial serial = pvSrc.ReadInt32(); + + SecureTradeContainer cont = World.FindItem( serial ) as SecureTradeContainer; + + if ( cont != null && cont.Trade != null && (cont.Trade.From.Mobile == state.Mobile || cont.Trade.To.Mobile == state.Mobile) ) + cont.Trade.Cancel(); + + break; + } + case 2: // Check + { + Serial serial = pvSrc.ReadInt32(); + + SecureTradeContainer cont = World.FindItem( serial ) as SecureTradeContainer; + + if ( cont != null ) + { + SecureTrade trade = cont.Trade; + + bool value = ( pvSrc.ReadInt32() != 0 ); + + if ( trade != null && trade.From.Mobile == state.Mobile ) + { + trade.From.Accepted = value; + trade.Update(); + } + else if ( trade != null && trade.To.Mobile == state.Mobile ) + { + trade.To.Accepted = value; + trade.Update(); + } + } + + break; + } + } + } + + public static void VendorBuyReply( NetState state, PacketReader pvSrc ) + { + pvSrc.Seek( 1, SeekOrigin.Begin ); + + int msgSize = pvSrc.ReadUInt16(); + Mobile vendor = World.FindMobile( pvSrc.ReadInt32() ); + byte flag = pvSrc.ReadByte(); + + if ( vendor == null ) + { + return; + } + else if ( vendor.Deleted || !Utility.RangeCheck( vendor.Location, state.Mobile.Location, 10 ) ) + { + state.Send( new EndVendorBuy( vendor ) ); + return; + } + + if ( flag == 0x02 ) + { + msgSize -= 1+2+4+1; + + if ( (msgSize / 7) > 100 ) + return; + + List buyList = new List( msgSize / 7 ); + for ( ;msgSize>0;msgSize-=7) + { + byte layer = pvSrc.ReadByte(); + Serial serial = pvSrc.ReadInt32(); + int amount = pvSrc.ReadInt16(); + + buyList.Add( new BuyItemResponse( serial, amount ) ); + } + + if ( buyList.Count > 0 ) + { + IVendor v = vendor as IVendor; + + if ( v != null && v.OnBuyItems( state.Mobile, buyList ) ) + state.Send( new EndVendorBuy( vendor ) ); + } + } + else + { + state.Send( new EndVendorBuy( vendor ) ); + } + } + + public static void VendorSellReply( NetState state, PacketReader pvSrc ) + { + Serial serial = pvSrc.ReadInt32(); + Mobile vendor = World.FindMobile( serial ); + + if ( vendor == null ) + { + return; + } + else if ( vendor.Deleted || !Utility.RangeCheck( vendor.Location, state.Mobile.Location, 10 ) ) + { + state.Send( new EndVendorSell( vendor ) ); + return; + } + + int count = pvSrc.ReadUInt16(); + if ( count < 100 && pvSrc.Size == (1+2+4+2+(count*6)) ) + { + List sellList = new List( count ); + + for (int i=0;i 0 ) + sellList.Add( new SellItemResponse( item, Amount ) ); + } + + if ( sellList.Count > 0 ) + { + IVendor v = vendor as IVendor; + + if ( v != null && v.OnSellItems( state.Mobile, sellList ) ) + state.Send( new EndVendorSell( vendor ) ); + } + } + } + + public static void DeleteCharacter( NetState state, PacketReader pvSrc ) + { + pvSrc.Seek( 30, SeekOrigin.Current ); + int index = pvSrc.ReadInt32(); + + EventSink.InvokeDeleteRequest( new DeleteRequestEventArgs( state, index ) ); + } + + public static void ResourceQuery( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + } + } + + public static void GameCentralMoniter( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + int type = pvSrc.ReadByte(); + int num1 = pvSrc.ReadInt32(); + + Console.WriteLine( "God Client: {0}: Game central moniter", state ); + Console.WriteLine( " - Type: {0}", type ); + Console.WriteLine( " - Number: {0}", num1 ); + + pvSrc.Trace( state ); + } + } + + public static void GodviewQuery( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + Console.WriteLine( "God Client: {0}: Godview query 0x{1:X}", state, pvSrc.ReadByte() ); + } + } + + public static void GMSingle( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + pvSrc.Trace( state ); + } + + public static void DeathStatusResponse( NetState state, PacketReader pvSrc ) + { + // Ignored + } + + public static void ObjectHelpRequest( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + Serial serial = pvSrc.ReadInt32(); + int unk = pvSrc.ReadByte(); + string lang = pvSrc.ReadString( 3 ); + + if ( serial.IsItem ) + { + Item item = World.FindItem( serial ); + + if ( item != null && from.Map == item.Map && Utility.InUpdateRange( item.GetWorldLocation(), from.Location ) && from.CanSee( item ) ) + item.OnHelpRequest( from ); + } + else if ( serial.IsMobile ) + { + Mobile m = World.FindMobile( serial ); + + if ( m != null && from.Map == m.Map && Utility.InUpdateRange( m.Location, from.Location ) && from.CanSee( m ) ) + m.OnHelpRequest( m ); + } + } + + public static void MobileNameRequest( NetState state, PacketReader pvSrc ) + { + Mobile m = World.FindMobile( pvSrc.ReadInt32() ); + + if ( m != null && Utility.InUpdateRange( state.Mobile, m ) && state.Mobile.CanSee( m ) ) + state.Send( new MobileName( m ) ); + } + + public static void RequestScrollWindow( NetState state, PacketReader pvSrc ) + { + int lastTip = pvSrc.ReadInt16(); + int type = pvSrc.ReadByte(); + } + + public static void AttackReq( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + Mobile m = World.FindMobile( pvSrc.ReadInt32() ); + + if ( m != null ) + from.Attack( m ); + } + + public static void HuePickerResponse( NetState state, PacketReader pvSrc ) { + int serial = pvSrc.ReadInt32(); + int value = pvSrc.ReadInt16(); + int hue = pvSrc.ReadInt16() & 0x3FFF; + + hue = Utility.ClipDyedHue( hue ); + + foreach ( HuePicker huePicker in state.HuePickers ) { + if ( huePicker.Serial == serial ) { + state.RemoveHuePicker( huePicker ); + + huePicker.OnResponse( hue ); + + break; + } + } + } + + public static void TripTime( NetState state, PacketReader pvSrc ) + { + int unk1 = pvSrc.ReadByte(); + int unk2 = pvSrc.ReadInt32(); + + state.Send( new TripTimeResponse( unk1 ) ); + } + + public static void UTripTime( NetState state, PacketReader pvSrc ) + { + int unk1 = pvSrc.ReadByte(); + int unk2 = pvSrc.ReadInt32(); + + state.Send( new UTripTimeResponse( unk1 ) ); + } + + public static void ChangeZ( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + + Console.WriteLine( "God Client: {0}: Change Z ({1}, {2}, {3})", state, x, y, z ); + } + } + + public static void SystemInfo( NetState state, PacketReader pvSrc ) + { + int v1 = pvSrc.ReadByte(); + int v2 = pvSrc.ReadUInt16(); + int v3 = pvSrc.ReadByte(); + string s1 = pvSrc.ReadString( 32 ); + string s2 = pvSrc.ReadString( 32 ); + string s3 = pvSrc.ReadString( 32 ); + string s4 = pvSrc.ReadString( 32 ); + int v4 = pvSrc.ReadUInt16(); + int v5 = pvSrc.ReadUInt16(); + int v6 = pvSrc.ReadInt32(); + int v7 = pvSrc.ReadInt32(); + int v8 = pvSrc.ReadInt32(); + } + + public static void Edit( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + int type = pvSrc.ReadByte(); // 10 = static, 7 = npc, 4 = dynamic + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int id = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + int hue = pvSrc.ReadUInt16(); + + Console.WriteLine( "God Client: {0}: Edit {6} ({1}, {2}, {3}) 0x{4:X} (0x{5:X})", state, x, y, z, id, hue, type ); + } + } + + public static void DeleteStatic( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadInt16(); + int id = pvSrc.ReadUInt16(); + + Console.WriteLine( "God Client: {0}: Delete Static ({1}, {2}, {3}) 0x{4:X}", state, x, y, z, id ); + } + } + + public static void NewAnimData( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + Console.WriteLine( "God Client: {0}: New tile animation", state ); + + pvSrc.Trace( state ); + } + } + + public static void NewTerrain( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int id = pvSrc.ReadUInt16(); + int width = pvSrc.ReadInt16(); + int height = pvSrc.ReadInt16(); + + Console.WriteLine( "God Client: {0}: New Terrain ({1}, {2})+({3}, {4}) 0x{5:X4}", state, x, y, width, height, id ); + } + } + + public static void NewRegion( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + string name = pvSrc.ReadString( 40 ); + int unk = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int width = pvSrc.ReadInt16(); + int height = pvSrc.ReadInt16(); + int zStart = pvSrc.ReadInt16(); + int zEnd = pvSrc.ReadInt16(); + string desc = pvSrc.ReadString( 40 ); + int soundFX = pvSrc.ReadInt16(); + int music = pvSrc.ReadInt16(); + int nightFX = pvSrc.ReadInt16(); + int dungeon = pvSrc.ReadByte(); + int light = pvSrc.ReadInt16(); + + Console.WriteLine( "God Client: {0}: New Region '{1}' ('{2}')", state, name, desc ); + } + } + + public static void AccountID( NetState state, PacketReader pvSrc ) + { + } + + public static bool VerifyGC( NetState state ) + { + if ( state.Mobile == null || state.Mobile.AccessLevel <= AccessLevel.Counselor ) + { + if ( state.Running ) + Console.WriteLine( "Warning: {0}: Player using godclient, disconnecting", state ); + + state.Dispose(); + return false; + } + else + { + return true; + } + } + + public static void TextCommand( NetState state, PacketReader pvSrc ) + { + int type = pvSrc.ReadByte(); + string command = pvSrc.ReadString(); + + Mobile m = state.Mobile; + + switch ( type ) + { + case 0x00: // Go + { + if ( VerifyGC( state ) ) + { + try + { + string[] split = command.Split( ' ' ); + + int x = Utility.ToInt32( split[0] ); + int y = Utility.ToInt32( split[1] ); + + int z; + + if ( split.Length >= 3 ) + z = Utility.ToInt32( split[2] ); + else if ( m.Map != null ) + z = m.Map.GetAverageZ( x, y ); + else + z = 0; + + m.Location = new Point3D( x, y, z ); + } + catch + { + } + } + + break; + } + case 0xC7: // Animate + { + EventSink.InvokeAnimateRequest( new AnimateRequestEventArgs( m, command ) ); + + break; + } + case 0x24: // Use skill + { + int skillIndex; + + if ( !int.TryParse( command.Split( ' ' )[0], out skillIndex ) ) + break; + + Skills.UseSkill( m, skillIndex ); + + break; + } + case 0x43: // Open spellbook + { + int booktype; + + if ( !int.TryParse( command, out booktype ) ) + booktype = 1; + + EventSink.InvokeOpenSpellbookRequest( new OpenSpellbookRequestEventArgs( m, booktype ) ); + + break; + } + case 0x27: // Cast spell from book + { + string[] split = command.Split( ' ' ); + + if ( split.Length > 0 ) + { + int spellID = Utility.ToInt32( split[0] ) - 1; + int serial = split.Length > 1 ? Utility.ToInt32( split[1] ) : -1; + + EventSink.InvokeCastSpellRequest( new CastSpellRequestEventArgs( m, spellID, World.FindItem( serial ) ) ); + } + + break; + } + case 0x58: // Open door + { + EventSink.InvokeOpenDoorMacroUsed( new OpenDoorMacroEventArgs( m ) ); + + break; + } + case 0x56: // Cast spell from macro + { + int spellID = Utility.ToInt32( command ) - 1; + + EventSink.InvokeCastSpellRequest( new CastSpellRequestEventArgs( m, spellID, null ) ); + + break; + } + case 0xF4: // Invoke virtues from macro + { + int virtueID = Utility.ToInt32( command ) - 1; + + EventSink.InvokeVirtueMacroRequest( new VirtueMacroRequestEventArgs( m, virtueID ) ); + + break; + } + case 0x2F: // Old scroll double click + { + /* + * This command is still sent for items 0xEF3 - 0xEF9 + * + * Command is one of three, depending on the item ID of the scroll: + * - [scroll serial] + * - [scroll serial] [target serial] + * - [scroll serial] [x] [y] [z] + */ + break; + } + default: + { + Console.WriteLine( "Client: {0}: Unknown text-command type 0x{1:X2}: {2}", state, type, command ); + break; + } + } + } + + public static void GodModeRequest( NetState state, PacketReader pvSrc ) + { + if ( VerifyGC( state ) ) + { + state.Send( new GodModeReply( pvSrc.ReadBoolean() ) ); + } + } + + public static void AsciiPromptResponse( NetState state, PacketReader pvSrc ) + { + int serial = pvSrc.ReadInt32(); + int prompt = pvSrc.ReadInt32(); + int type = pvSrc.ReadInt32(); + string text = pvSrc.ReadStringSafe(); + + if ( text.Length > 128 ) + return; + + Mobile from = state.Mobile; + Prompt p = from.Prompt; + + if ( p != null && p.Serial == serial && p.Serial == prompt ) + { + from.Prompt = null; + + if ( type == 0 ) + p.OnCancel( from ); + else + p.OnResponse( from, text ); + } + } + + public static void UnicodePromptResponse( NetState state, PacketReader pvSrc ) + { + int serial = pvSrc.ReadInt32(); + int prompt = pvSrc.ReadInt32(); + int type = pvSrc.ReadInt32(); + string lang = pvSrc.ReadString( 4 ); + string text = pvSrc.ReadUnicodeStringLESafe(); + + if ( text.Length > 128 ) + return; + + Mobile from = state.Mobile; + Prompt p = from.Prompt; + + if ( p != null && p.Serial == serial && p.Serial == prompt ) + { + from.Prompt = null; + + if ( type == 0 ) + p.OnCancel( from ); + else + p.OnResponse( from, text ); + } + } + + public static void MenuResponse( NetState state, PacketReader pvSrc ) { + int serial = pvSrc.ReadInt32(); + int menuID = pvSrc.ReadInt16(); // unused in our implementation + int index = pvSrc.ReadInt16(); + int itemID = pvSrc.ReadInt16(); + int hue = pvSrc.ReadInt16(); + + index -= 1; // convert from 1-based to 0-based + + foreach ( IMenu menu in state.Menus ) { + if ( menu.Serial == serial ) { + state.RemoveMenu( menu ); + + if ( index >= 0 && index < menu.EntryLength ) { + menu.OnResponse( state, index ); + } else { + menu.OnCancel( state ); + } + + break; + } + } + } + + public static void ProfileReq( NetState state, PacketReader pvSrc ) + { + int type = pvSrc.ReadByte(); + Serial serial = pvSrc.ReadInt32(); + + Mobile beholder = state.Mobile; + Mobile beheld = World.FindMobile( serial ); + + if ( beheld == null ) + return; + + switch ( type ) + { + case 0x00: // display request + { + EventSink.InvokeProfileRequest( new ProfileRequestEventArgs( beholder, beheld ) ); + + break; + } + case 0x01: // edit request + { + pvSrc.ReadInt16(); // Skip + int length = pvSrc.ReadUInt16(); + + if ( length > 511 ) + return; + + string text = pvSrc.ReadUnicodeString( length ); + + EventSink.InvokeChangeProfileRequest( new ChangeProfileRequestEventArgs( beholder, beheld, text ) ); + + break; + } + } + } + + public static void Disconnect( NetState state, PacketReader pvSrc ) + { + int minusOne = pvSrc.ReadInt32(); + } + + public static void LiftReq( NetState state, PacketReader pvSrc ) + { + Serial serial = pvSrc.ReadInt32(); + int amount = pvSrc.ReadUInt16(); + Item item = World.FindItem( serial ); + + bool rejected; + LRReason reject; + + state.Mobile.Lift( item, amount, out rejected, out reject ); + } + + public static void EquipReq( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + Item item = from.Holding; + + bool valid = ( item != null && item.HeldBy == from && item.Map == Map.Internal ); + + from.Holding = null; + + if ( !valid ) { + return; + } + + pvSrc.Seek( 5, SeekOrigin.Current ); + Mobile to = World.FindMobile( pvSrc.ReadInt32() ); + + if ( to == null ) + to = from; + + if ( !to.AllowEquipFrom( from ) || !to.EquipItem( item ) ) + item.Bounce( from ); + + item.ClearBounce(); + } + + public static void DropReq( NetState state, PacketReader pvSrc ) + { + pvSrc.ReadInt32(); // serial, ignored + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + Serial dest = pvSrc.ReadInt32(); + + Point3D loc = new Point3D( x, y, z ); + + Mobile from = state.Mobile; + + if (dest.IsMobile) + { + from.Drop(World.FindMobile(dest), loc); + } + else if (dest.IsItem) + { + Item item = World.FindItem(dest); + + if (item is BaseMulti && ((BaseMulti)item).AllowsRelativeDrop) + { + loc.m_X += item.X; + loc.m_Y += item.Y; + from.Drop(loc); + } + else + { + from.Drop(item, loc); + } + } + else + { + from.Drop(loc); + } + } + + public static void DropReq6017( NetState state, PacketReader pvSrc ) + { + pvSrc.ReadInt32(); // serial, ignored + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + pvSrc.ReadByte(); // Grid Location? + Serial dest = pvSrc.ReadInt32(); + + Point3D loc = new Point3D( x, y, z ); + + Mobile from = state.Mobile; + + if (dest.IsMobile) + { + from.Drop(World.FindMobile(dest), loc); + } + else if (dest.IsItem) + { + Item item = World.FindItem(dest); + + if (item is BaseMulti && ((BaseMulti)item).AllowsRelativeDrop) + { + loc.m_X += item.X; + loc.m_Y += item.Y; + from.Drop(loc); + } + else + { + from.Drop(item, loc); + } + } + else + { + from.Drop(loc); + } + } + + public static void ConfigurationFile( NetState state, PacketReader pvSrc ) + { + } + + public static void LogoutReq( NetState state, PacketReader pvSrc ) + { + state.Send( new LogoutAck() ); + } + + public static void ChangeSkillLock( NetState state, PacketReader pvSrc ) + { + Skill s = state.Mobile.Skills[pvSrc.ReadInt16()]; + + if ( s != null ) + s.SetLockNoRelay( (SkillLock)pvSrc.ReadByte() ); + } + + public static void HelpRequest( NetState state, PacketReader pvSrc ) + { + EventSink.InvokeHelpRequest( new HelpRequestEventArgs( state.Mobile ) ); + } + + public static void TargetResponse( NetState state, PacketReader pvSrc ) + { + int type = pvSrc.ReadByte(); + int targetID = pvSrc.ReadInt32(); + int flags = pvSrc.ReadByte(); + Serial serial = pvSrc.ReadInt32(); + int x = pvSrc.ReadInt16(), y = pvSrc.ReadInt16(), z = pvSrc.ReadInt16(); + int graphic = pvSrc.ReadUInt16(); + + if ( targetID == unchecked( (int) 0xDEADBEEF ) ) + return; + + Mobile from = state.Mobile; + + Target t = from.Target; + + if ( t != null ) + { + TargetProfile prof = TargetProfile.Acquire( t.GetType() ); + + if ( prof != null ) { + prof.Start(); + } + + try + { + if (x == -1 && y == -1 && !serial.IsValid) + { + // User pressed escape + t.Cancel(from, TargetCancelType.Canceled); + } + else if (Target.TargetIDValidation && t.TargetID != targetID) + { + // Sanity, prevent fake target + return; + } + else + { + object toTarget; + + if ( type == 1 ) + { + if ( graphic == 0 ) + { + toTarget = new LandTarget( new Point3D( x, y, z ), from.Map ); + } + else + { + Map map = from.Map; + + if ( map == null || map == Map.Internal ) + { + t.Cancel( from, TargetCancelType.Canceled ); + return; + } + else + { + StaticTile[] tiles = map.Tiles.GetStaticTiles( x, y, !t.DisallowMultis ); + + bool valid = false; + + if ( state.HighSeas ) { + ItemData id = TileData.ItemTable[graphic&TileData.MaxItemValue]; + if ( id.Surface ) { + z -= id.Height; + } + } + + for ( int i = 0; !valid && i < tiles.Length; ++i ) + { + if ( tiles[i].Z == z && tiles[i].ID == graphic ) + valid = true; + } + + if ( !valid ) + { + t.Cancel( from, TargetCancelType.Canceled ); + return; + } + else + { + toTarget = new StaticTarget( new Point3D( x, y, z ), graphic ); + } + } + } + } + else if ( serial.IsMobile ) + { + toTarget = World.FindMobile( serial ); + } + else if ( serial.IsItem ) + { + toTarget = World.FindItem( serial ); + } + else + { + t.Cancel( from, TargetCancelType.Canceled ); + return; + } + + t.Invoke( from, toTarget ); + } + } finally { + if ( prof != null ) { + prof.Finish(); + } + } + } + } + + public static void DisplayGumpResponse( NetState state, PacketReader pvSrc ) { + int serial = pvSrc.ReadInt32(); + int typeID = pvSrc.ReadInt32(); + int buttonID = pvSrc.ReadInt32(); + + foreach ( Gump gump in state.Gumps ) { + if ( gump.Serial == serial && gump.TypeID == typeID ) { + int switchCount = pvSrc.ReadInt32(); + + if ( switchCount < 0 || switchCount > gump.m_Switches ) { + state.WriteConsole( "Invalid gump response, disconnecting..." ); + state.Dispose(); + return; + } + + int[] switches = new int[switchCount]; + + for ( int j = 0; j < switches.Length; ++j ) + switches[j] = pvSrc.ReadInt32(); + + int textCount = pvSrc.ReadInt32(); + + if ( textCount < 0 || textCount > gump.m_TextEntries ) { + state.WriteConsole( "Invalid gump response, disconnecting..." ); + state.Dispose(); + return; + } + + TextRelay[] textEntries = new TextRelay[textCount]; + + for ( int j = 0; j < textEntries.Length; ++j ) { + int entryID = pvSrc.ReadUInt16(); + int textLength = pvSrc.ReadUInt16(); + + if ( textLength > 239 ) { + state.WriteConsole( "Invalid gump response, disconnecting..." ); + state.Dispose(); + return; + } + + string text = pvSrc.ReadUnicodeStringSafe( textLength ); + textEntries[j] = new TextRelay( entryID, text ); + } + + state.RemoveGump( gump ); + + GumpProfile prof = GumpProfile.Acquire( gump.GetType() ); + + if ( prof != null ) { + prof.Start(); + } + + gump.OnResponse( state, new RelayInfo( buttonID, switches, textEntries ) ); + + if ( prof != null ) { + prof.Finish(); + } + + return; + } + } + + if ( typeID == 461 ) { // Virtue gump + int switchCount = pvSrc.ReadInt32(); + + if ( buttonID == 1 && switchCount > 0 ) { + Mobile beheld = World.FindMobile( pvSrc.ReadInt32() ); + + if ( beheld != null ) { + EventSink.InvokeVirtueGumpRequest( new VirtueGumpRequestEventArgs( state.Mobile, beheld ) ); + } + } else { + Mobile beheld = World.FindMobile( serial ); + + if ( beheld != null ) { + EventSink.InvokeVirtueItemRequest( new VirtueItemRequestEventArgs( state.Mobile, beheld, buttonID ) ); + } + } + } + } + + public static void SetWarMode( NetState state, PacketReader pvSrc ) + { + state.Mobile.DelayChangeWarmode( pvSrc.ReadBoolean() ); + } + + public static void Resynchronize( NetState state, PacketReader pvSrc ) + { + Mobile m = state.Mobile; + + if ( state.StygianAbyss ) { + state.Send( new MobileUpdate( m ) ); + } else { + state.Send( new MobileUpdateOld( m ) ); + } + + state.Send(MobileIncoming.Create(state, m, m)); + + m.SendEverything(); + + state.Sequence = 0; + + m.ClearFastwalkStack(); + } + + private static int[] m_EmptyInts = new int[0]; + + public static void AsciiSpeech( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + MessageType type = (MessageType)pvSrc.ReadByte(); + int hue = pvSrc.ReadInt16(); + pvSrc.ReadInt16(); // font + string text = pvSrc.ReadStringSafe().Trim(); + + if ( text.Length <= 0 || text.Length > 128 ) + return; + + if ( !Enum.IsDefined( typeof( MessageType ), type ) ) + type = MessageType.Regular; + + from.DoSpeech( text, m_EmptyInts, type, Utility.ClipDyedHue( hue ) ); + } + + private static KeywordList m_KeywordList = new KeywordList(); + + public static void UnicodeSpeech( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + MessageType type = (MessageType)pvSrc.ReadByte(); + int hue = pvSrc.ReadInt16(); + pvSrc.ReadInt16(); // font + string lang = pvSrc.ReadString( 4 ); + string text; + + bool isEncoded = (type & MessageType.Encoded) != 0; + int[] keywords; + + if ( isEncoded ) + { + int value = pvSrc.ReadInt16(); + int count = (value & 0xFFF0) >> 4; + int hold = value & 0xF; + + if ( count < 0 || count > 50 ) + return; + + KeywordList keyList = m_KeywordList; + + for ( int i = 0; i < count; ++i ) + { + int speechID; + + if ( (i & 1) == 0 ) + { + hold <<= 8; + hold |= pvSrc.ReadByte(); + speechID = hold; + hold = 0; + } + else + { + value = pvSrc.ReadInt16(); + speechID = (value & 0xFFF0) >> 4; + hold = value & 0xF; + } + + if ( !keyList.Contains( speechID ) ) + keyList.Add( speechID ); + } + + text = pvSrc.ReadUTF8StringSafe(); + + keywords = keyList.ToArray(); + } + else + { + text = pvSrc.ReadUnicodeStringSafe(); + + keywords = m_EmptyInts; + } + + text = text.Trim(); + + if ( text.Length <= 0 || text.Length > 128 ) + return; + + type &= ~MessageType.Encoded; + + if ( !Enum.IsDefined( typeof( MessageType ), type ) ) + type = MessageType.Regular; + + from.Language = lang; + from.DoSpeech( text, keywords, type, Utility.ClipDyedHue( hue ) ); + } + + public static void UseReq( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + if ( from.AccessLevel >= AccessLevel.Counselor || DateTime.Now >= from.NextActionTime ) + { + int value = pvSrc.ReadInt32(); + + if ( (value & ~0x7FFFFFFF) != 0 ) + { + from.OnPaperdollRequest(); + } + else + { + Serial s = value; + + if ( s.IsMobile ) + { + Mobile m = World.FindMobile( s ); + + if ( m != null && !m.Deleted ) + from.Use( m ); + } + else if ( s.IsItem ) + { + Item item = World.FindItem( s ); + + if ( item != null && !item.Deleted ) + from.Use( item ); + } + } + + from.NextActionTime = DateTime.Now + Mobile.ActionDelay; + } + else + { + from.SendActionMessage(); + } + } + + private static bool m_SingleClickProps; + + public static bool SingleClickProps + { + get{ return m_SingleClickProps; } + set{ m_SingleClickProps = value; } + } + + public static void LookReq( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + Serial s = pvSrc.ReadInt32(); + + if ( s.IsMobile ) + { + Mobile m = World.FindMobile( s ); + + if ( m != null && from.CanSee( m ) && Utility.InUpdateRange( from, m ) ) + { + if ( m_SingleClickProps ) + { + m.OnAosSingleClick( from ); + } + else + { + if ( from.Region.OnSingleClick( from, m ) ) + m.OnSingleClick( from ); + } + } + } + else if ( s.IsItem ) + { + Item item = World.FindItem( s ); + + if ( item != null && !item.Deleted && from.CanSee( item ) && Utility.InUpdateRange( from.Location, item.GetWorldLocation() ) ) + { + if ( m_SingleClickProps ) + { + item.OnAosSingleClick( from ); + } + else if ( from.Region.OnSingleClick( from, item ) ) + { + if ( item.Parent is Item ) + ((Item)item.Parent).OnSingleClickContained( from, item ); + + item.OnSingleClick( from ); + } + } + } + } + + public static void PingReq( NetState state, PacketReader pvSrc ) + { + state.Send( PingAck.Instantiate( pvSrc.ReadByte() ) ); + } + + public static void SetUpdateRange( NetState state, PacketReader pvSrc ) + { + state.Send( ChangeUpdateRange.Instantiate( 18 ) ); + } + + private const int BadFood = unchecked( (int)0xBAADF00D ); + private const int BadUOTD = unchecked( (int)0xFFCEFFCE ); + + public static void MovementReq( NetState state, PacketReader pvSrc ) + { + Direction dir = (Direction)pvSrc.ReadByte(); + int seq = pvSrc.ReadByte(); + int key = pvSrc.ReadInt32(); + + Mobile m = state.Mobile; + + if ( (state.Sequence == 0 && seq != 0) || !m.Move( dir ) ) + { + state.Send( new MovementRej( seq, m ) ); + state.Sequence = 0; + + m.ClearFastwalkStack(); + } + else + { + ++seq; + + if ( seq == 256 ) + seq = 1; + + state.Sequence = seq; + } + } + + public static int[] m_ValidAnimations = new int[] + { + 6, 21, 32, 33, + 100, 101, 102, + 103, 104, 105, + 106, 107, 108, + 109, 110, 111, + 112, 113, 114, + 115, 116, 117, + 118, 119, 120, + 121, 123, 124, + 125, 126, 127, + 128 + }; + + public static int[] ValidAnimations{ get{ return m_ValidAnimations; } set{ m_ValidAnimations = value; } } + + public static void Animate( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + int action = pvSrc.ReadInt32(); + + bool ok = false; + + for ( int i = 0; !ok && i < m_ValidAnimations.Length; ++i ) + ok = ( action == m_ValidAnimations[i] ); + + if ( from != null && ok && from.Alive && from.Body.IsHuman && !from.Mounted ) + from.Animate( action, 7, 1, true, false, 0 ); + } + + public static void QuestArrow( NetState state, PacketReader pvSrc ) + { + bool rightClick = pvSrc.ReadBoolean(); + Mobile from = state.Mobile; + + if ( from != null && from.QuestArrow != null ) + from.QuestArrow.OnClick( rightClick ); + } + + public static void ExtendedCommand( NetState state, PacketReader pvSrc ) + { + int packetID = pvSrc.ReadUInt16(); + + PacketHandler ph = GetExtendedHandler( packetID ); + + if ( ph != null ) + { + if ( ph.Ingame && state.Mobile == null ) + { + Console.WriteLine( "Client: {0}: Sent ingame packet (0xBFx{1:X2}) before having been attached to a mobile", state, packetID ); + state.Dispose(); + } + else if ( ph.Ingame && state.Mobile.Deleted ) + { + state.Dispose(); + } + else + { + ph.OnReceive( state, pvSrc ); + } + } + else + { + pvSrc.Trace( state ); + } + } + + public static void CastSpell( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + if ( from == null ) + return; + + Item spellbook = null; + + if ( pvSrc.ReadInt16() == 1 ) + spellbook = World.FindItem( pvSrc.ReadInt32() ); + + int spellID = pvSrc.ReadInt16() - 1; + + EventSink.InvokeCastSpellRequest( new CastSpellRequestEventArgs( from, spellID, spellbook ) ); + } + + public static void BatchQueryProperties( NetState state, PacketReader pvSrc ) + { + if ( !ObjectPropertyList.Enabled ) + return; + + Mobile from = state.Mobile; + + int length = pvSrc.Size-3; + + if ( length < 0 || (length%4) != 0 ) + return; + + int count = length/4; + + for ( int i = 0; i < count; ++i ) + { + Serial s = pvSrc.ReadInt32(); + + if ( s.IsMobile ) + { + Mobile m = World.FindMobile( s ); + + if ( m != null && from.CanSee( m ) && Utility.InUpdateRange( from, m ) ) + m.SendPropertiesTo( from ); + } + else if ( s.IsItem ) + { + Item item = World.FindItem( s ); + + if ( item != null && !item.Deleted && from.CanSee( item ) && Utility.InUpdateRange( from.Location, item.GetWorldLocation() ) ) + item.SendPropertiesTo( from ); + } + } + } + + public static void QueryProperties( NetState state, PacketReader pvSrc ) + { + if ( !ObjectPropertyList.Enabled ) + return; + + Mobile from = state.Mobile; + + Serial s = pvSrc.ReadInt32(); + + if ( s.IsMobile ) + { + Mobile m = World.FindMobile( s ); + + if ( m != null && from.CanSee( m ) && Utility.InUpdateRange( from, m ) ) + m.SendPropertiesTo( from ); + } + else if ( s.IsItem ) + { + Item item = World.FindItem( s ); + + if ( item != null && !item.Deleted && from.CanSee( item ) && Utility.InUpdateRange( from.Location, item.GetWorldLocation() ) ) + item.SendPropertiesTo( from ); + } + } + + public static void PartyMessage( NetState state, PacketReader pvSrc ) + { + if ( state.Mobile == null ) + return; + + switch ( pvSrc.ReadByte() ) + { + case 0x01: PartyMessage_AddMember( state, pvSrc ); break; + case 0x02: PartyMessage_RemoveMember( state, pvSrc ); break; + case 0x03: PartyMessage_PrivateMessage( state, pvSrc ); break; + case 0x04: PartyMessage_PublicMessage( state, pvSrc ); break; + case 0x06: PartyMessage_SetCanLoot( state, pvSrc ); break; + case 0x08: PartyMessage_Accept( state, pvSrc ); break; + case 0x09: PartyMessage_Decline( state, pvSrc ); break; + default: pvSrc.Trace( state ); break; + } + } + + public static void PartyMessage_AddMember( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnAdd( state.Mobile ); + } + + public static void PartyMessage_RemoveMember( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnRemove( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ) ); + } + + public static void PartyMessage_PrivateMessage( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnPrivateMessage( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ), pvSrc.ReadUnicodeStringSafe() ); + } + + public static void PartyMessage_PublicMessage( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnPublicMessage( state.Mobile, pvSrc.ReadUnicodeStringSafe() ); + } + + public static void PartyMessage_SetCanLoot( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnSetCanLoot( state.Mobile, pvSrc.ReadBoolean() ); + } + + public static void PartyMessage_Accept( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnAccept( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ) ); + } + + public static void PartyMessage_Decline( NetState state, PacketReader pvSrc ) + { + if ( PartyCommands.Handler != null ) + PartyCommands.Handler.OnDecline( state.Mobile, World.FindMobile( pvSrc.ReadInt32() ) ); + } + + public static void StunRequest( NetState state, PacketReader pvSrc ) + { + EventSink.InvokeStunRequest( new StunRequestEventArgs( state.Mobile ) ); + } + + public static void DisarmRequest( NetState state, PacketReader pvSrc ) + { + EventSink.InvokeDisarmRequest( new DisarmRequestEventArgs( state.Mobile ) ); + } + + public static void StatLockChange( NetState state, PacketReader pvSrc ) + { + int stat = pvSrc.ReadByte(); + int lockValue = pvSrc.ReadByte(); + + if ( lockValue > 2 ) lockValue = 0; + + Mobile m = state.Mobile; + + if ( m != null ) + { + switch ( stat ) + { + case 0: m.StrLock = (StatLockType)lockValue; break; + case 1: m.DexLock = (StatLockType)lockValue; break; + case 2: m.IntLock = (StatLockType)lockValue; break; + } + } + } + + public static void ScreenSize( NetState state, PacketReader pvSrc ) + { + int width = pvSrc.ReadInt32(); + int unk = pvSrc.ReadInt32(); + } + + public static void ContextMenuResponse( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + if ( from != null ) + { + ContextMenu menu = from.ContextMenu; + + from.ContextMenu = null; + + if ( menu != null && from != null && from == menu.From ) + { + IEntity entity = World.FindEntity( pvSrc.ReadInt32() ); + + if ( entity != null && entity == menu.Target && from.CanSee( entity ) ) + { + Point3D p; + + if ( entity is Mobile ) + p = entity.Location; + else if ( entity is Item ) + p = ((Item)entity).GetWorldLocation(); + else + return; + + int index = pvSrc.ReadUInt16(); + + if ( index >= 0 && index < menu.Entries.Length ) + { + ContextMenuEntry e = menu.Entries[index]; + + int range = e.Range; + + if ( range == -1 ) + range = 18; + + if ( e.Enabled && from.InRange( p, range ) ) + e.OnClick(); + } + } + } + } + } + + public static void ContextMenuRequest( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + IEntity target = World.FindEntity( pvSrc.ReadInt32() ); + + if ( from != null && target != null && from.Map == target.Map && from.CanSee( target ) ) + { + if ( target is Mobile && !Utility.InUpdateRange( from.Location, target.Location ) ) + return; + else if ( target is Item && !Utility.InUpdateRange( from.Location, ((Item)target).GetWorldLocation() ) ) + return; + + if ( !from.CheckContextMenuDisplay( target ) ) + return; + + ContextMenu c = new ContextMenu( from, target ); + + if ( c.Entries.Length > 0 ) + { + if ( target is Item ) + { + object root = ((Item)target).RootParent; + + if ( root is Mobile && root != from && ((Mobile)root).AccessLevel >= from.AccessLevel ) + { + for ( int i = 0; i < c.Entries.Length; ++i ) + { + if ( !c.Entries[i].NonLocalUse ) + c.Entries[i].Enabled = false; + } + } + } + + from.ContextMenu = c; + } + } + } + + public static void CloseStatus( NetState state, PacketReader pvSrc ) + { + Serial serial = pvSrc.ReadInt32(); + } + + public static void Language( NetState state, PacketReader pvSrc ) + { + string lang = pvSrc.ReadString( 4 ); + + if ( state.Mobile != null ) + state.Mobile.Language = lang; + } + + public static void AssistVersion( NetState state, PacketReader pvSrc ) + { + int unk = pvSrc.ReadInt32(); + string av = pvSrc.ReadString(); + } + + public static void ClientVersion( NetState state, PacketReader pvSrc ) + { + CV version = state.Version = new CV( pvSrc.ReadString() ); + + EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) ); + } + + public static void ClientType( NetState state, PacketReader pvSrc ) + { + pvSrc.ReadUInt16(); + + int type = pvSrc.ReadUInt16(); + CV version = state.Version = new CV( pvSrc.ReadString() ); + + //EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) );//todo + } + + public static void MobileQuery( NetState state, PacketReader pvSrc ) + { + Mobile from = state.Mobile; + + pvSrc.ReadInt32(); // 0xEDEDEDED + int type = pvSrc.ReadByte(); + Mobile m = World.FindMobile( pvSrc.ReadInt32() ); + + if ( m != null ) + { + switch ( type ) + { + case 0x00: // Unknown, sent by godclient + { + if ( VerifyGC( state ) ) + Console.WriteLine( "God Client: {0}: Query 0x{1:X2} on {2} '{3}'", state, type, m.Serial, m.Name ); + + break; + } + case 0x04: // Stats + { + m.OnStatsQuery( from ); + break; + } + case 0x05: + { + m.OnSkillsQuery( from ); + break; + } + default: + { + pvSrc.Trace( state ); + break; + } + } + } + } + + public delegate void PlayCharCallback(NetState state, bool val); + + public static PlayCharCallback ThirdPartyAuthCallback = null, ThirdPartyHackedCallback = null; + + private static byte[] m_ThirdPartyAuthKey = new byte[] + { + 0x9, 0x11, 0x83, (byte)'+', 0x4, 0x17, 0x83, + 0x5, 0x24, 0x85, + 0x7, 0x17, 0x87, + 0x6, 0x19, 0x88, + }; + + private class LoginTimer : Timer + { + private NetState m_State; + private Mobile m_Mobile; + + public LoginTimer( NetState state, Mobile m ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) ) + { + m_State = state; + m_Mobile = m; + } + + protected override void OnTick() + { + if ( m_State == null ) + Stop(); + if ( m_State.Version != null ) + { + m_State.BlockAllPackets = false; + DoLogin( m_State, m_Mobile ); + Stop(); + } + } + } + + public static void PlayCharacter( NetState state, PacketReader pvSrc ) + { + pvSrc.ReadInt32(); // 0xEDEDEDED + + string name = pvSrc.ReadString( 30 ); + + pvSrc.Seek( 2, SeekOrigin.Current ); + int flags = pvSrc.ReadInt32(); + + if (FeatureProtection.DisabledFeatures != 0 && ThirdPartyAuthCallback != null) + { + bool authOK = false; + + ulong razorFeatures = (((ulong)pvSrc.ReadUInt32()) << 32) | ((ulong)pvSrc.ReadUInt32()); + + if (razorFeatures == (ulong)FeatureProtection.DisabledFeatures) + { + bool match = true; + for (int i = 0; match && i < m_ThirdPartyAuthKey.Length; i++) + match = match && pvSrc.ReadByte() == m_ThirdPartyAuthKey[i]; + + if (match) + authOK = true; + } + else + { + pvSrc.Seek(16, SeekOrigin.Current); + } + + ThirdPartyAuthCallback(state, authOK); + } + else + { + pvSrc.Seek(24, SeekOrigin.Current); + } + + if (ThirdPartyHackedCallback != null) + { + pvSrc.Seek(-2, SeekOrigin.Current); + if (pvSrc.ReadUInt16() == 0xDEAD) + ThirdPartyHackedCallback(state, true); + } + + if (!state.Running) + return; + + int charSlot = pvSrc.ReadInt32(); + int clientIP = pvSrc.ReadInt32(); + + IAccount a = state.Account; + + if ( a == null || charSlot < 0 || charSlot >= a.Length ) + { + state.Dispose(); + } + else + { + Mobile m = a[charSlot]; + + // Check if anyone is using this account + for ( int i = 0; i < a.Length; ++i ) + { + Mobile check = a[i]; + + if ( check != null && check.Map != Map.Internal && check != m ) + { + Console.WriteLine( "Login: {0}: Account in use", state ); + state.Send( new PopupMessage( PMMessage.CharInWorld ) ); + return; + } + } + + if ( m == null ) + { + state.Dispose(); + } + else + { + if ( m.NetState != null ) + m.NetState.Dispose(); + + NetState.ProcessDisposedQueue(); + + state.Send( new ClientVersionReq() ); + + state.BlockAllPackets = true; + + state.Flags = (ClientFlags)flags; + + state.Mobile = m; + m.NetState = state; + + new LoginTimer( state, m ).Start(); + } + } + } + + public static void DoLogin( NetState state, Mobile m ) + { + state.Send( new LoginConfirm( m ) ); + + if ( m.Map != null ) + state.Send( new MapChange( m ) ); + + state.Send( new MapPatches() ); + + state.Send( SeasonChange.Instantiate( m.GetSeason(), true ) ); + + state.Send( SupportedFeatures.Instantiate( state ) ); + + state.Sequence = 0; + + if (state.NewMobileIncoming) { + state.Send(new MobileUpdate(m)); + state.Send(new MobileUpdate(m)); + + m.CheckLightLevels(true); + + state.Send(new MobileUpdate(m)); + + state.Send(new MobileIncoming(m, m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Server.Network.SetWarMode.Instantiate(m.Warmode)); + + m.SendEverything(); + + state.Send(SupportedFeatures.Instantiate(state)); + state.Send(new MobileUpdate(m)); + //state.Send( new MobileAttributes( m ) ); + state.Send(new MobileStatus(m, m)); + state.Send(Server.Network.SetWarMode.Instantiate(m.Warmode)); + state.Send(new MobileIncoming(m, m)); + } else if ( state.StygianAbyss ) { + state.Send( new MobileUpdate( m ) ); + state.Send( new MobileUpdate( m ) ); + + m.CheckLightLevels( true ); + + state.Send( new MobileUpdate( m ) ); + + state.Send(new MobileIncomingSA(m, m)); + //state.Send( new MobileAttributes( m ) ); + state.Send( new MobileStatus( m, m ) ); + state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); + + m.SendEverything(); + + state.Send( SupportedFeatures.Instantiate( state ) ); + state.Send( new MobileUpdate( m ) ); + //state.Send( new MobileAttributes( m ) ); + state.Send( new MobileStatus( m, m ) ); + state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); + state.Send(new MobileIncomingSA(m, m)); + } else { + state.Send( new MobileUpdateOld( m ) ); + state.Send( new MobileUpdateOld( m ) ); + + m.CheckLightLevels( true ); + + state.Send( new MobileUpdateOld( m ) ); + + state.Send( new MobileIncomingOld( m, m ) ); + //state.Send( new MobileAttributes( m ) ); + state.Send( new MobileStatus( m, m ) ); + state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); + + m.SendEverything(); + + state.Send( SupportedFeatures.Instantiate( state ) ); + state.Send( new MobileUpdateOld( m ) ); + //state.Send( new MobileAttributes( m ) ); + state.Send( new MobileStatus( m, m ) ); + state.Send( Server.Network.SetWarMode.Instantiate( m.Warmode ) ); + state.Send( new MobileIncomingOld( m, m ) ); + } + + state.Send( LoginComplete.Instance ); + state.Send( new CurrentTime() ); + state.Send( SeasonChange.Instantiate( m.GetSeason(), true ) ); + state.Send( new MapChange( m ) ); + + EventSink.InvokeLogin( new LoginEventArgs( m ) ); + + m.ClearFastwalkStack(); + } + + public static void CreateCharacter(NetState state, PacketReader pvSrc) + { + int unk1 = pvSrc.ReadInt32(); + int unk2 = pvSrc.ReadInt32(); + int unk3 = pvSrc.ReadByte(); + string name = pvSrc.ReadString(30); + + pvSrc.Seek(2, SeekOrigin.Current); + int flags = pvSrc.ReadInt32(); + pvSrc.Seek(8, SeekOrigin.Current); + int prof = pvSrc.ReadByte(); + pvSrc.Seek(15, SeekOrigin.Current); + + //bool female = pvSrc.ReadBoolean(); + + int genderRace = pvSrc.ReadByte(); + + int str = pvSrc.ReadByte(); + int dex = pvSrc.ReadByte(); + int intl = pvSrc.ReadByte(); + int is1 = pvSrc.ReadByte(); + int vs1 = pvSrc.ReadByte(); + int is2 = pvSrc.ReadByte(); + int vs2 = pvSrc.ReadByte(); + int is3 = pvSrc.ReadByte(); + int vs3 = pvSrc.ReadByte(); + int hue = pvSrc.ReadUInt16(); + int hairVal = pvSrc.ReadInt16(); + int hairHue = pvSrc.ReadInt16(); + int hairValf = pvSrc.ReadInt16(); + int hairHuef = pvSrc.ReadInt16(); + pvSrc.ReadByte(); + int cityIndex = pvSrc.ReadByte(); + int charSlot = pvSrc.ReadInt32(); + int clientIP = pvSrc.ReadInt32(); + int shirtHue = pvSrc.ReadInt16(); + int pantsHue = pvSrc.ReadInt16(); + + /* + Pre-7.0.0.0: + 0x00, 0x01 -> Human Male, Human Female + 0x02, 0x03 -> Elf Male, Elf Female + + Post-7.0.0.0: + 0x00, 0x01 + 0x02, 0x03 -> Human Male, Human Female + 0x04, 0x05 -> Elf Male, Elf Female + 0x05, 0x06 -> Gargoyle Male, Gargoyle Female + */ + + bool female = ((genderRace % 2) != 0); + + Race race = null; + + if (state.StygianAbyss) + { + byte raceID = (byte)(genderRace < 4 ? 0 : ((genderRace / 2) - 1)); + race = Race.Races[raceID]; + } + else + { + race = Race.Races[(byte)(genderRace / 2)]; + } + + if (race == null) + race = Race.DefaultRace; + + CityInfo[] info = state.CityInfo; + IAccount a = state.Account; + + if (info == null || a == null || cityIndex < 0 || cityIndex >= info.Length) + { + state.Dispose(); + } + else + { + // Check if anyone is using this account + for (int i = 0; i < a.Length; ++i) + { + Mobile check = a[i]; + + if (check != null && check.Map != Map.Internal) + { + Console.WriteLine("Login: {0}: Account in use", state); + state.Send(new PopupMessage(PMMessage.CharInWorld)); + return; + } + } + + state.Flags = (ClientFlags)flags; + + CharacterCreatedEventArgs args = new CharacterCreatedEventArgs( + state, a, + name, female, hue, + str, dex, intl, + info[cityIndex], + new SkillNameValue[3] + { + new SkillNameValue( (SkillName)is1, vs1 ), + new SkillNameValue( (SkillName)is2, vs2 ), + new SkillNameValue( (SkillName)is3, vs3 ), + }, + shirtHue, pantsHue, + hairVal, hairHue, + hairValf, hairHuef, + prof, + race + ); + + state.Send(new ClientVersionReq()); + + state.BlockAllPackets = true; + + EventSink.InvokeCharacterCreated(args); + + Mobile m = args.Mobile; + + if (m != null) + { + state.Mobile = m; + m.NetState = state; + new LoginTimer(state, m).Start(); + } + else + { + state.BlockAllPackets = false; + state.Dispose(); + } + } + } + + public static void CreateCharacter70160(NetState state, PacketReader pvSrc) + { + int unk1 = pvSrc.ReadInt32(); + int unk2 = pvSrc.ReadInt32(); + int unk3 = pvSrc.ReadByte(); + string name = pvSrc.ReadString(30); + + pvSrc.Seek(2, SeekOrigin.Current); + int flags = pvSrc.ReadInt32(); + pvSrc.Seek(8, SeekOrigin.Current); + int prof = pvSrc.ReadByte(); + pvSrc.Seek(15, SeekOrigin.Current); + + int genderRace = pvSrc.ReadByte(); + + int str = pvSrc.ReadByte(); + int dex = pvSrc.ReadByte(); + int intl = pvSrc.ReadByte(); + int is1 = pvSrc.ReadByte(); + int vs1 = pvSrc.ReadByte(); + int is2 = pvSrc.ReadByte(); + int vs2 = pvSrc.ReadByte(); + int is3 = pvSrc.ReadByte(); + int vs3 = pvSrc.ReadByte(); + int is4 = pvSrc.ReadByte(); + int vs4 = pvSrc.ReadByte(); + + int hue = pvSrc.ReadUInt16(); + int hairVal = pvSrc.ReadInt16(); + int hairHue = pvSrc.ReadInt16(); + int hairValf = pvSrc.ReadInt16(); + int hairHuef = pvSrc.ReadInt16(); + pvSrc.ReadByte(); + int cityIndex = pvSrc.ReadByte(); + int charSlot = pvSrc.ReadInt32(); + int clientIP = pvSrc.ReadInt32(); + int shirtHue = pvSrc.ReadInt16(); + int pantsHue = pvSrc.ReadInt16(); + + /* + 0x00, 0x01 + 0x02, 0x03 -> Human Male, Human Female + 0x04, 0x05 -> Elf Male, Elf Female + 0x05, 0x06 -> Gargoyle Male, Gargoyle Female + */ + + bool female = ((genderRace % 2) != 0); + + Race race = null; + + byte raceID = (byte)(genderRace < 4 ? 0 : ((genderRace / 2) - 1)); + race = Race.Races[raceID]; + + if (race == null) + race = Race.DefaultRace; + + CityInfo[] info = state.CityInfo; + IAccount a = state.Account; + + if (info == null || a == null || cityIndex < 0 || cityIndex >= info.Length) + { + state.Dispose(); + } + else + { + // Check if anyone is using this account + for (int i = 0; i < a.Length; ++i) + { + Mobile check = a[i]; + + if (check != null && check.Map != Map.Internal) + { + Console.WriteLine("Login: {0}: Account in use", state); + state.Send(new PopupMessage(PMMessage.CharInWorld)); + return; + } + } + + state.Flags = (ClientFlags)flags; + + CharacterCreatedEventArgs args = new CharacterCreatedEventArgs( + state, a, + name, female, hue, + str, dex, intl, + info[cityIndex], + new SkillNameValue[4] + { + new SkillNameValue( (SkillName)is1, vs1 ), + new SkillNameValue( (SkillName)is2, vs2 ), + new SkillNameValue( (SkillName)is3, vs3 ), + new SkillNameValue( (SkillName)is4, vs4 ), + }, + shirtHue, pantsHue, + hairVal, hairHue, + hairValf, hairHuef, + prof, + race + ); + + state.Send(new ClientVersionReq()); + + state.BlockAllPackets = true; + + EventSink.InvokeCharacterCreated(args); + + Mobile m = args.Mobile; + + if (m != null) + { + state.Mobile = m; + m.NetState = state; + new LoginTimer(state, m).Start(); + } + else + { + state.BlockAllPackets = false; + state.Dispose(); + } + } + } + + private static bool m_ClientVerification = true; + + public static bool ClientVerification + { + get{ return m_ClientVerification; } + set{ m_ClientVerification = value; } + } + + internal struct AuthIDPersistence { + public DateTime Age; + public ClientVersion Version; + + public AuthIDPersistence( ClientVersion v ) { + Age = DateTime.Now; + Version = v; + } + } + + private const int m_AuthIDWindowSize = 128; + private static Dictionary m_AuthIDWindow = new Dictionary( m_AuthIDWindowSize ); + + private static int GenerateAuthID( NetState state ) + { + if ( m_AuthIDWindow.Count == m_AuthIDWindowSize ) { + int oldestID = 0; + DateTime oldest = DateTime.MaxValue; + + foreach ( KeyValuePair kvp in m_AuthIDWindow ) { + if ( kvp.Value.Age < oldest ) { + oldestID = kvp.Key; + oldest = kvp.Value.Age; + } + } + + m_AuthIDWindow.Remove( oldestID ); + } + + int authID; + + do { + authID = Utility.Random( 1, int.MaxValue - 1 ); + + if ( Utility.RandomBool() ) + authID |= 1<<31; + } while ( m_AuthIDWindow.ContainsKey( authID ) ); + + m_AuthIDWindow[authID] = new AuthIDPersistence( state.Version ); + + return authID; + } + + public static void GameLogin( NetState state, PacketReader pvSrc ) + { + if ( state.SentFirstPacket ) + { + state.Dispose(); + return; + } + + state.SentFirstPacket = true; + + int authID = pvSrc.ReadInt32(); + + if ( m_AuthIDWindow.ContainsKey( authID ) ) { + AuthIDPersistence ap = m_AuthIDWindow[authID]; + m_AuthIDWindow.Remove( authID ); + + state.Version = ap.Version; + } else if ( m_ClientVerification ) { + Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", state ); + state.Dispose(); + return; + } + + if ( state.m_AuthID != 0 && authID != state.m_AuthID ) + { + Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", state ); + state.Dispose(); + return; + } + else if ( state.m_AuthID == 0 && authID != state.m_Seed ) + { + Console.WriteLine( "Login: {0}: Invalid client detected, disconnecting", state ); + state.Dispose(); + return; + } + + string username = pvSrc.ReadString( 30 ); + string password = pvSrc.ReadString( 30 ); + + GameLoginEventArgs e = new GameLoginEventArgs( state, username, password ); + + EventSink.InvokeGameLogin( e ); + + if ( e.Accepted ) + { + state.CityInfo = e.CityInfo; + state.CompressionEnabled = true; + + state.Send( SupportedFeatures.Instantiate( state ) ); + + if (state.NewCharacterList) + { + state.Send(new CharacterList(state.Account, state.CityInfo)); + } + else + { + state.Send(new CharacterListOld(state.Account, state.CityInfo)); + } + } + else + { + state.Dispose(); + } + } + + public static void PlayServer( NetState state, PacketReader pvSrc ) + { + int index = pvSrc.ReadInt16(); + ServerInfo[] info = state.ServerInfo; + IAccount a = state.Account; + + if ( info == null || a == null || index < 0 || index >= info.Length ) + { + state.Dispose(); + } + else + { + ServerInfo si = info[index]; + + state.m_AuthID = PlayServerAck.m_AuthID = GenerateAuthID( state ); + + state.SentFirstPacket = false; + state.Send( new PlayServerAck( si ) ); + } + } + + public static void LoginServerSeed( NetState state, PacketReader pvSrc ) + { + state.m_Seed = pvSrc.ReadInt32(); + state.Seeded = true; + + if ( state.m_Seed == 0 ) + { + Console.WriteLine("Login: {0}: Invalid client detected, disconnecting", state); + state.Dispose(); + return; + } + + int clientMaj = pvSrc.ReadInt32(); + int clientMin = pvSrc.ReadInt32(); + int clientRev = pvSrc.ReadInt32(); + int clientPat = pvSrc.ReadInt32(); + + state.Version = new ClientVersion( clientMaj, clientMin, clientRev, clientPat ); + } + + public static void AccountLogin( NetState state, PacketReader pvSrc ) + { + if ( state.SentFirstPacket ) + { + state.Dispose(); + return; + } + + state.SentFirstPacket = true; + + string username = pvSrc.ReadString( 30 ); + string password = pvSrc.ReadString( 30 ); + + AccountLoginEventArgs e = new AccountLoginEventArgs( state, username, password ); + + EventSink.InvokeAccountLogin( e ); + + if ( e.Accepted ) + AccountLogin_ReplyAck( state ); + else + AccountLogin_ReplyRej( state, e.RejectReason ); + } + + public static void AccountLogin_ReplyAck( NetState state ) + { + ServerListEventArgs e = new ServerListEventArgs( state, state.Account ); + + EventSink.InvokeServerList( e ); + + if ( e.Rejected ) + { + state.Account = null; + state.Send( new AccountLoginRej( ALRReason.BadComm ) ); + state.Dispose(); + } + else + { + ServerInfo[] info = e.Servers.ToArray(); + + state.ServerInfo = info; + state.Send(new ClientVersionReq()); + state.Send( new AccountLoginAck( info ) ); + } + } + + public static void AccountLogin_ReplyRej( NetState state, ALRReason reason ) + { + state.Send( new AccountLoginRej( reason ) ); + state.Dispose(); + } + //Plume : Net 4 + public static void ClientCrashReport(NetState state, PacketReader pvSrc) + { + int maj = pvSrc.ReadByte(); + int min = pvSrc.ReadByte(); + int rev = pvSrc.ReadByte(); + int pat = pvSrc.ReadByte(); + int x = pvSrc.ReadInt16(); + int y = pvSrc.ReadInt16(); + int z = pvSrc.ReadSByte(); + int map = pvSrc.ReadByte(); + string acct = pvSrc.ReadString(0x20); + string pg = pvSrc.ReadString(0x20); + string ip = pvSrc.ReadString(15); + pvSrc.ReadInt32(); + int excode = pvSrc.ReadInt32(); + string procname = pvSrc.ReadString(100); + string crashrep = pvSrc.ReadString(100); + pvSrc.ReadByte(); + int exoffset = pvSrc.ReadInt32(); + List list = new List(); + int addrcount = pvSrc.ReadByte(); + for (int i = 0; i < addrcount; i++) + { + list.Add(pvSrc.ReadInt32()); + } + Server.ClientVersion version = new Server.ClientVersion(maj, min, rev, pat); + if (!Directory.Exists("Logs/ClientCrashes")) + { + Directory.CreateDirectory("Logs/ClientCrashes"); + } + using (StreamWriter writer = new StreamWriter(Path.Combine("Logs/ClientCrashes", string.Format("{0}.log", DateTime.Now.ToLongDateString())), true)) + { + writer.Write("Time: {0} Ip:{1} Account: {2} Character: {3}\r\nClientVersion {4}\r\nLocation: {5}, {6}, {7}\r\nMap: {8}\r\nExceptionCode: {9}\r\nProcessName: {10}\r\nCrashReport: {11}\r\nExceptionOffset: {12}\r\nAddressCount: {13}\r\n", new object[] { DateTime.Now.ToString(), ip, acct, pg, version.ToString(), x.ToString(), y.ToString(), z.ToString(), map.ToString(), excode.ToString(), procname, crashrep, exoffset.ToString(), addrcount.ToString() }); + for (int j = 0; j < addrcount; j++) + { + writer.WriteLine("Address: {0}", list[j].ToString()); + } + writer.WriteLine(""); + } + } + } +} \ No newline at end of file diff --git a/Server/Network/PacketReader.cs b/Server/Network/PacketReader.cs new file mode 100644 index 0000000..bbb5439 --- /dev/null +++ b/Server/Network/PacketReader.cs @@ -0,0 +1,459 @@ +/*************************************************************************** + * PacketReader.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: PacketReader.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Text; +using System.IO; + +namespace Server.Network +{ + public class PacketReader + { + private byte[] m_Data; + private int m_Size; + private int m_Index; + + public PacketReader( byte[] data, int size, bool fixedSize ) + { + m_Data = data; + m_Size = size; + m_Index = fixedSize ? 1 : 3; + } + + public byte[] Buffer + { + get + { + return m_Data; + } + } + + public int Size + { + get + { + return m_Size; + } + } + + public void Trace( NetState state ) + { + try + { + using ( StreamWriter sw = new StreamWriter( "Packets.log", true ) ) + { + byte[] buffer = m_Data; + if (buffer[0] != 0xF0) + { + if ( buffer.Length > 0 ) + sw.WriteLine( "Client: {0}: Unhandled packet 0x{1:X2}", state, buffer[0] ); + + using ( MemoryStream ms = new MemoryStream( buffer ) ) + Utility.FormatBuffer( sw, ms, buffer.Length ); + + sw.WriteLine(); + sw.WriteLine(); + } + } + } + catch + { + } + } + + public int Seek( int offset, SeekOrigin origin ) + { + switch ( origin ) + { + case SeekOrigin.Begin: m_Index = offset; break; + case SeekOrigin.Current: m_Index += offset; break; + case SeekOrigin.End: m_Index = m_Size - offset; break; + } + + return m_Index; + } + + public int ReadInt32() + { + if ( (m_Index + 4) > m_Size ) + return 0; + + return (m_Data[m_Index++] << 24) + | (m_Data[m_Index++] << 16) + | (m_Data[m_Index++] << 8) + | m_Data[m_Index++]; + } + + public short ReadInt16() + { + if ( (m_Index + 2) > m_Size ) + return 0; + + return (short)((m_Data[m_Index++] << 8) | m_Data[m_Index++]); + } + + public byte ReadByte() + { + if ( (m_Index + 1) > m_Size ) + return 0; + + return m_Data[m_Index++]; + } + + public uint ReadUInt32() + { + if ( (m_Index + 4) > m_Size ) + return 0; + + return (uint)((m_Data[m_Index++] << 24) | (m_Data[m_Index++] << 16) | (m_Data[m_Index++] << 8) | m_Data[m_Index++]); + } + + public ushort ReadUInt16() + { + if ( (m_Index + 2) > m_Size ) + return 0; + + return (ushort)((m_Data[m_Index++] << 8) | m_Data[m_Index++]); + } + + public sbyte ReadSByte() + { + if ( (m_Index + 1) > m_Size ) + return 0; + + return (sbyte)m_Data[m_Index++]; + } + + public bool ReadBoolean() + { + if ( (m_Index + 1) > m_Size ) + return false; + + return ( m_Data[m_Index++] != 0 ); + } + + public string ReadUnicodeStringLE() + { + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < m_Size && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0 ) + sb.Append( (char)c ); + + return sb.ToString(); + } + + public string ReadUnicodeStringLESafe( int fixedLength ) + { + int bound = m_Index + (fixedLength << 1); + int end = bound; + + if ( bound > m_Size ) + bound = m_Size; + + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < bound && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0 ) + { + if ( IsSafeChar( c ) ) + sb.Append( (char)c ); + } + + m_Index = end; + + return sb.ToString(); + } + + public string ReadUnicodeStringLESafe() + { + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < m_Size && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0 ) + { + if ( IsSafeChar( c ) ) + sb.Append( (char)c ); + } + + return sb.ToString(); + } + + public string ReadUnicodeStringSafe() + { + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < m_Size && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 ) + { + if ( IsSafeChar( c ) ) + sb.Append( (char)c ); + } + + return sb.ToString(); + } + + public string ReadUnicodeString() + { + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < m_Size && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 ) + sb.Append( (char)c ); + + return sb.ToString(); + } + + public bool IsSafeChar( int c ) + { + return ( c >= 0x20 && c < 0xFFFE ); + } + + public string ReadUTF8StringSafe( int fixedLength ) + { + if ( m_Index >= m_Size ) + { + m_Index += fixedLength; + return String.Empty; + } + + int bound = m_Index + fixedLength; + //int end = bound; + + if ( bound > m_Size ) + bound = m_Size; + + int count = 0; + int index = m_Index; + int start = m_Index; + + while ( index < bound && m_Data[index++] != 0 ) + ++count; + + index = 0; + + byte[] buffer = new byte[count]; + int value = 0; + + while ( m_Index < bound && (value = m_Data[m_Index++]) != 0 ) + buffer[index++] = (byte)value; + + string s = Utility.UTF8.GetString( buffer ); + + bool isSafe = true; + + for ( int i = 0; isSafe && i < s.Length; ++i ) + isSafe = IsSafeChar( (int) s[i] ); + + m_Index = start + fixedLength; + + if ( isSafe ) + return s; + + StringBuilder sb = new StringBuilder( s.Length ); + + for ( int i = 0; i < s.Length; ++i ) + if ( IsSafeChar( (int) s[i] ) ) + sb.Append( s[i] ); + + return sb.ToString(); + } + + public string ReadUTF8StringSafe() + { + if ( m_Index >= m_Size ) + return String.Empty; + + int count = 0; + int index = m_Index; + + while ( index < m_Size && m_Data[index++] != 0 ) + ++count; + + index = 0; + + byte[] buffer = new byte[count]; + int value = 0; + + while ( m_Index < m_Size && (value = m_Data[m_Index++]) != 0 ) + buffer[index++] = (byte)value; + + string s = Utility.UTF8.GetString( buffer ); + + bool isSafe = true; + + for ( int i = 0; isSafe && i < s.Length; ++i ) + isSafe = IsSafeChar( (int) s[i] ); + + if ( isSafe ) + return s; + + StringBuilder sb = new StringBuilder( s.Length ); + + for ( int i = 0; i < s.Length; ++i ) + { + if ( IsSafeChar( (int) s[i] ) ) + sb.Append( s[i] ); + } + + return sb.ToString(); + } + + public string ReadUTF8String() + { + if ( m_Index >= m_Size ) + return String.Empty; + + int count = 0; + int index = m_Index; + + while ( index < m_Size && m_Data[index++] != 0 ) + ++count; + + index = 0; + + byte[] buffer = new byte[count]; + int value = 0; + + while ( m_Index < m_Size && (value = m_Data[m_Index++]) != 0 ) + buffer[index++] = (byte)value; + + return Utility.UTF8.GetString( buffer ); + } + + public string ReadString() + { + StringBuilder sb = new StringBuilder(); + + int c; + + while ( m_Index < m_Size && (c = m_Data[m_Index++]) != 0 ) + sb.Append( (char)c ); + + return sb.ToString(); + } + + public string ReadStringSafe() + { + StringBuilder sb = new StringBuilder(); + + int c; + + while ( m_Index < m_Size && (c = m_Data[m_Index++]) != 0 ) + { + if ( IsSafeChar( c ) ) + sb.Append( (char)c ); + } + + return sb.ToString(); + } + + public string ReadUnicodeStringSafe( int fixedLength ) + { + int bound = m_Index + (fixedLength << 1); + int end = bound; + + if ( bound > m_Size ) + bound = m_Size; + + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < bound && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 ) + { + if ( IsSafeChar( c ) ) + sb.Append( (char)c ); + } + + m_Index = end; + + return sb.ToString(); + } + + public string ReadUnicodeString( int fixedLength ) + { + int bound = m_Index + (fixedLength << 1); + int end = bound; + + if ( bound > m_Size ) + bound = m_Size; + + StringBuilder sb = new StringBuilder(); + + int c; + + while ( (m_Index + 1) < bound && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0 ) + sb.Append( (char)c ); + + m_Index = end; + + return sb.ToString(); + } + + public string ReadStringSafe( int fixedLength ) + { + int bound = m_Index + fixedLength; + int end = bound; + + if ( bound > m_Size ) + bound = m_Size; + + StringBuilder sb = new StringBuilder(); + + int c; + + while ( m_Index < bound && (c = m_Data[m_Index++]) != 0 ) + { + if ( IsSafeChar( c ) ) + sb.Append( (char)c ); + } + + m_Index = end; + + return sb.ToString(); + } + + public string ReadString( int fixedLength ) + { + int bound = m_Index + fixedLength; + int end = bound; + + if ( bound > m_Size ) + bound = m_Size; + + StringBuilder sb = new StringBuilder(); + + int c; + + while ( m_Index < bound && (c = m_Data[m_Index++]) != 0 ) + sb.Append( (char)c ); + + m_Index = end; + + return sb.ToString(); + } + } +} \ No newline at end of file diff --git a/Server/Network/PacketWriter.cs b/Server/Network/PacketWriter.cs new file mode 100644 index 0000000..3c1529e --- /dev/null +++ b/Server/Network/PacketWriter.cs @@ -0,0 +1,470 @@ +/*************************************************************************** + * PacketWriter.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: PacketWriter.cs 114 2006-12-13 18:28:37Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Network +{ + /// + /// Provides functionality for writing primitive binary data. + /// + public class PacketWriter + { + private static Stack m_Pool = new Stack(); + + public static PacketWriter CreateInstance() + { + return CreateInstance( 32 ); + } + + public static PacketWriter CreateInstance( int capacity ) + { + PacketWriter pw = null; + + lock ( m_Pool ) + { + if ( m_Pool.Count > 0 ) + { + pw = m_Pool.Pop(); + + if ( pw != null ) + { + pw.m_Capacity = capacity; + pw.m_Stream.SetLength( 0 ); + } + } + } + + if ( pw == null ) + pw = new PacketWriter( capacity ); + + return pw; + } + + public static void ReleaseInstance( PacketWriter pw ) + { + lock ( m_Pool ) + { + if ( !m_Pool.Contains( pw ) ) + { + m_Pool.Push( pw ); + } + else + { + try + { + using ( StreamWriter op = new StreamWriter( "neterr.log" ) ) + { + op.WriteLine( "{0}\tInstance pool contains writer", DateTime.Now ); + } + } + catch + { + Console.WriteLine( "net error" ); + } + } + } + } + + /// + /// Internal stream which holds the entire packet. + /// + private MemoryStream m_Stream; + + private int m_Capacity; + + /// + /// Internal format buffer. + /// + private static byte[] m_Buffer = new byte[4]; + + /// + /// Instantiates a new PacketWriter instance with the default capacity of 4 bytes. + /// + public PacketWriter() : this( 32 ) + { + } + + /// + /// Instantiates a new PacketWriter instance with a given capacity. + /// + /// Initial capacity for the internal stream. + public PacketWriter( int capacity ) + { + m_Stream = new MemoryStream( capacity ); + m_Capacity = capacity; + } + + /// + /// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1. + /// + public void Write( bool value ) + { + m_Stream.WriteByte( (byte)(value ? 1 : 0) ); + } + + /// + /// Writes a 1-byte unsigned integer value to the underlying stream. + /// + public void Write( byte value ) + { + m_Stream.WriteByte( value ); + } + + /// + /// Writes a 1-byte signed integer value to the underlying stream. + /// + public void Write( sbyte value ) + { + m_Stream.WriteByte( (byte) value ); + } + + /// + /// Writes a 2-byte signed integer value to the underlying stream. + /// + public void Write( short value ) + { + m_Buffer[0] = (byte)(value >> 8); + m_Buffer[1] = (byte) value; + + m_Stream.Write( m_Buffer, 0, 2 ); + } + + /// + /// Writes a 2-byte unsigned integer value to the underlying stream. + /// + public void Write( ushort value ) + { + m_Buffer[0] = (byte)(value >> 8); + m_Buffer[1] = (byte) value; + + m_Stream.Write( m_Buffer, 0, 2 ); + } + + /// + /// Writes a 4-byte signed integer value to the underlying stream. + /// + public void Write( int value ) + { + m_Buffer[0] = (byte)(value >> 24); + m_Buffer[1] = (byte)(value >> 16); + m_Buffer[2] = (byte)(value >> 8); + m_Buffer[3] = (byte) value; + + m_Stream.Write( m_Buffer, 0, 4 ); + } + + /// + /// Writes a 4-byte unsigned integer value to the underlying stream. + /// + public void Write( uint value ) + { + m_Buffer[0] = (byte)(value >> 24); + m_Buffer[1] = (byte)(value >> 16); + m_Buffer[2] = (byte)(value >> 8); + m_Buffer[3] = (byte) value; + + m_Stream.Write( m_Buffer, 0, 4 ); + } + + /// + /// Writes a sequence of bytes to the underlying stream + /// + public void Write( byte[] buffer, int offset, int size ) + { + m_Stream.Write( buffer, offset, size ); + } + + /// + /// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters. + /// + public void WriteAsciiFixed( string value, int size ) + { + if ( value == null ) + { + Console.WriteLine( "Network: Attempted to WriteAsciiFixed() with null value" ); + value = String.Empty; + } + + int length = value.Length; + + m_Stream.SetLength( m_Stream.Length + size ); + + if ( length >= size ) + m_Stream.Position += Encoding.ASCII.GetBytes( value, 0, size, m_Stream.GetBuffer(), (int)m_Stream.Position ); + else + { + Encoding.ASCII.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + m_Stream.Position += size; + } + + /*byte[] buffer = Encoding.ASCII.GetBytes( value ); + + if ( buffer.Length >= size ) + { + m_Stream.Write( buffer, 0, size ); + } + else + { + m_Stream.Write( buffer, 0, buffer.Length ); + Fill( size - buffer.Length ); + }*/ + } + + /// + /// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character. + /// + public void WriteAsciiNull( string value ) + { + if ( value == null ) + { + Console.WriteLine( "Network: Attempted to WriteAsciiNull() with null value" ); + value = String.Empty; + } + + int length = value.Length; + + m_Stream.SetLength( m_Stream.Length + length + 1 ); + + Encoding.ASCII.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + m_Stream.Position += length + 1; + + /*byte[] buffer = Encoding.ASCII.GetBytes( value ); + + m_Stream.Write( buffer, 0, buffer.Length ); + m_Stream.WriteByte( 0 );*/ + } + + /// + /// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null character. + /// + public void WriteLittleUniNull( string value ) + { + if ( value == null ) + { + Console.WriteLine( "Network: Attempted to WriteLittleUniNull() with null value" ); + value = String.Empty; + } + + int length = value.Length; + + m_Stream.SetLength( m_Stream.Length + ( ( length + 1 ) * 2 ) ); + + m_Stream.Position += Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + m_Stream.Position += 2; + + /*byte[] buffer = Encoding.Unicode.GetBytes( value ); + + m_Stream.Write( buffer, 0, buffer.Length ); + + m_Buffer[0] = 0; + m_Buffer[1] = 0; + m_Stream.Write( m_Buffer, 0, 2 );*/ + } + + /// + /// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters. + /// + public void WriteLittleUniFixed( string value, int size ) + { + if ( value == null ) + { + Console.WriteLine( "Network: Attempted to WriteLittleUniFixed() with null value" ); + value = String.Empty; + } + + size *= 2; + + int length = value.Length; + + m_Stream.SetLength( m_Stream.Length + size ); + + if ( ( length * 2 ) >= size ) + m_Stream.Position += Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + else + { + Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + m_Stream.Position += size; + } + + /*size *= 2; + + byte[] buffer = Encoding.Unicode.GetBytes( value ); + + if ( buffer.Length >= size ) + { + m_Stream.Write( buffer, 0, size ); + } + else + { + m_Stream.Write( buffer, 0, buffer.Length ); + Fill( size - buffer.Length ); + }*/ + } + + /// + /// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character. + /// + public void WriteBigUniNull( string value ) + { + if ( value == null ) + { + Console.WriteLine( "Network: Attempted to WriteBigUniNull() with null value" ); + value = String.Empty; + } + + int length = value.Length; + + m_Stream.SetLength( m_Stream.Length + ( ( length + 1 ) * 2 ) ); + + m_Stream.Position += Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + m_Stream.Position += 2; + + /*byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value ); + + m_Stream.Write( buffer, 0, buffer.Length ); + + m_Buffer[0] = 0; + m_Buffer[1] = 0; + m_Stream.Write( m_Buffer, 0, 2 );*/ + } + + /// + /// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters. + /// + public void WriteBigUniFixed( string value, int size ) + { + if ( value == null ) + { + Console.WriteLine( "Network: Attempted to WriteBigUniFixed() with null value" ); + value = String.Empty; + } + + size *= 2; + + int length = value.Length; + + m_Stream.SetLength( m_Stream.Length + size ); + + if ( ( length * 2 ) >= size ) + m_Stream.Position += Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + else + { + Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position ); + m_Stream.Position += size; + } + + /*size *= 2; + + byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value ); + + if ( buffer.Length >= size ) + { + m_Stream.Write( buffer, 0, size ); + } + else + { + m_Stream.Write( buffer, 0, buffer.Length ); + Fill( size - buffer.Length ); + }*/ + } + + /// + /// Fills the stream from the current position up to (capacity) with 0x00's + /// + public void Fill() + { + Fill( (int) (m_Capacity - m_Stream.Length) ); + } + + /// + /// Writes a number of 0x00 byte values to the underlying stream. + /// + public void Fill( int length ) + { + if ( m_Stream.Position == m_Stream.Length ) + { + m_Stream.SetLength( m_Stream.Length + length ); + m_Stream.Seek( 0, SeekOrigin.End ); + } + else + { + m_Stream.Write( new byte[length], 0, length ); + } + } + + /// + /// Gets the total stream length. + /// + public long Length + { + get + { + return m_Stream.Length; + } + } + + /// + /// Gets or sets the current stream position. + /// + public long Position + { + get + { + return m_Stream.Position; + } + set + { + m_Stream.Position = value; + } + } + + /// + /// The internal stream used by this PacketWriter instance. + /// + public MemoryStream UnderlyingStream + { + get + { + return m_Stream; + } + } + + /// + /// Offsets the current position from an origin. + /// + public long Seek( long offset, SeekOrigin origin ) + { + return m_Stream.Seek( offset, origin ); + } + + /// + /// Gets the entire stream content as a byte array. + /// + public byte[] ToArray() + { + return m_Stream.ToArray(); + } + } +} \ No newline at end of file diff --git a/Server/Network/Packets.cs b/Server/Network/Packets.cs new file mode 100644 index 0000000..9dc4459 --- /dev/null +++ b/Server/Network/Packets.cs @@ -0,0 +1,4793 @@ +/*************************************************************************** + * Packets.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Packets.cs 1064 2013-05-28 17:44:07Z mark@runuo.com $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +#if Framework_4_0 +using System.Threading; +#endif +using Server.Accounting; +using Server.Targeting; +using Server.Items; +using Server.Mobiles; +using Server.Gumps; +using Server.Menus; +using Server.Menus.ItemLists; +using Server.Menus.Questions; +using Server.Prompts; +using Server.HuePickers; +using Server.ContextMenus; +using Server.Diagnostics; + +namespace Server.Network +{ + public enum PMMessage : byte + { + CharNoExist = 1, + CharExists = 2, + CharInWorld = 5, + LoginSyncError = 6, + IdleWarning = 7 + } + + public enum LRReason : byte + { + CannotLift = 0, + OutOfRange = 1, + OutOfSight = 2, + TryToSteal = 3, + AreHolding = 4, + Inspecific = 5 + } + + /*public enum CMEFlags + { + None = 0x00, + Locked = 0x01, + Arrow = 0x02, + x0004 = 0x04, + Color = 0x20, + x0040 = 0x40, + x0080 = 0x80 + }*/ + + public sealed class DamagePacketOld : Packet + { + public DamagePacketOld( Mobile m, int amount ) : base( 0xBF ) + { + EnsureCapacity( 11 ); + + m_Stream.Write( (short) 0x22 ); + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (int) m.Serial ); + + if ( amount > 255 ) + amount = 255; + else if ( amount < 0 ) + amount = 0; + + m_Stream.Write( (byte)amount ); + } + } + + public sealed class DamagePacket : Packet + { + public DamagePacket( Mobile m, int amount ) : base( 0x0B, 7 ) + { + m_Stream.Write( (int) m.Serial ); + + if ( amount > 0xFFFF ) + amount = 0xFFFF; + else if ( amount < 0 ) + amount = 0; + + m_Stream.Write( (ushort) amount ); + } + + /*public DamagePacket( Mobile m, int amount ) : base( 0xBF ) + { + EnsureCapacity( 11 ); + + m_Stream.Write( (short) 0x22 ); + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (int) m.Serial ); + + if ( amount > 255 ) + amount = 255; + else if ( amount < 0 ) + amount = 0; + + m_Stream.Write( (byte)amount ); + }*/ + } + + public sealed class CancelArrow : Packet + { + public CancelArrow() : base( 0xBA, 6 ) + { + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) -1 ); + m_Stream.Write( (short) -1 ); + } + } + + public sealed class SetArrow : Packet + { + public SetArrow( int x, int y ) : base( 0xBA, 6 ) + { + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (short) x ); + m_Stream.Write( (short) y ); + } + } + + public sealed class CancelArrowHS : Packet + { + public CancelArrowHS( int x, int y, Serial s ) : base( 0xBA, 10 ) + { + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) x ); + m_Stream.Write( (short) y ); + m_Stream.Write( (int) s ); + } + } + + public sealed class SetArrowHS : Packet + { + public SetArrowHS( int x, int y, Serial s ) : base( 0xBA, 10 ) + { + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (short) x ); + m_Stream.Write( (short) y ); + m_Stream.Write( (int) s ); + } + } + + public sealed class DisplaySecureTrade : Packet + { + public DisplaySecureTrade( Mobile them, Container first, Container second, string name ) : base( 0x6F ) + { + if ( name == null ) + name = ""; + + EnsureCapacity( 18 + name.Length ); + + m_Stream.Write( (byte) 0 ); // Display + m_Stream.Write( (int) them.Serial ); + m_Stream.Write( (int) first.Serial ); + m_Stream.Write( (int) second.Serial ); + m_Stream.Write( (bool) true ); + + m_Stream.WriteAsciiFixed( name, 30 ); + } + } + + public sealed class CloseSecureTrade : Packet + { + public CloseSecureTrade( Container cont ) : base( 0x6F ) + { + EnsureCapacity( 8 ); + + m_Stream.Write( (byte) 1 ); // Close + m_Stream.Write( (int) cont.Serial ); + } + } + + public sealed class UpdateSecureTrade : Packet + { + public UpdateSecureTrade( Container cont, bool first, bool second ) : base( 0x6F ) + { + EnsureCapacity( 8 ); + + m_Stream.Write( (byte) 2 ); // Update + m_Stream.Write( (int) cont.Serial ); + m_Stream.Write( (int) (first ? 1 : 0) ); + m_Stream.Write( (int) (second ? 1 : 0) ); + } + } + + public sealed class SecureTradeEquip : Packet + { + public SecureTradeEquip( Item item, Mobile m ) : base( 0x25, 20 ) + { + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (short) item.ItemID ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) item.Amount ); + m_Stream.Write( (short) item.X ); + m_Stream.Write( (short) item.Y ); + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) item.Hue ); + } + } + + public sealed class SecureTradeEquip6017 : Packet + { + public SecureTradeEquip6017( Item item, Mobile m ) : base( 0x25, 21 ) + { + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (short) item.ItemID ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) item.Amount ); + m_Stream.Write( (short) item.X ); + m_Stream.Write( (short) item.Y ); + m_Stream.Write( (byte) 0 ); // Grid Location? + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) item.Hue ); + } + } + + public sealed class MapPatches : Packet + { + public MapPatches() : base( 0xBF ) + { + EnsureCapacity( 9 + (3 * 8) ); + + m_Stream.Write( (short) 0x0018 ); + + m_Stream.Write( (int) 4 ); + + m_Stream.Write( (int) Map.Felucca.Tiles.Patch.StaticBlocks ); + m_Stream.Write( (int) Map.Felucca.Tiles.Patch.LandBlocks ); + + m_Stream.Write( (int) Map.Trammel.Tiles.Patch.StaticBlocks ); + m_Stream.Write( (int) Map.Trammel.Tiles.Patch.LandBlocks ); + + m_Stream.Write( (int) Map.Ilshenar.Tiles.Patch.StaticBlocks ); + m_Stream.Write( (int) Map.Ilshenar.Tiles.Patch.LandBlocks ); + + m_Stream.Write( (int) Map.Malas.Tiles.Patch.StaticBlocks ); + m_Stream.Write( (int) Map.Malas.Tiles.Patch.LandBlocks ); + } + } + + public sealed class ObjectHelpResponse : Packet + { + public ObjectHelpResponse( IEntity e, string text ) : base( 0xB7 ) + { + this.EnsureCapacity( 9 + (text.Length * 2) ); + + m_Stream.Write( (int) e.Serial ); + m_Stream.WriteBigUniNull( text ); + } + } + + public sealed class VendorBuyContent : Packet + { + public VendorBuyContent( List list ) + : base( 0x3c ) + { + this.EnsureCapacity( list.Count*19 + 5 ); + + m_Stream.Write( (short)list.Count ); + + //The client sorts these by their X/Y value. + //OSI sends these in wierd order. X/Y highest to lowest and serial loest to highest + //These are already sorted by serial (done by the vendor class) but we have to send them by x/y + //(the x74 packet is sent in 'correct' order.) + for ( int i = list.Count - 1; i >= 0; --i ) + { + BuyItemState bis = (BuyItemState)list[i]; + + m_Stream.Write( (int)bis.MySerial ); + m_Stream.Write( (ushort)bis.ItemID ); + m_Stream.Write( (byte)0 );//itemid offset + m_Stream.Write( (ushort)bis.Amount ); + m_Stream.Write( (short)(i+1) );//x + m_Stream.Write( (short)1 );//y + m_Stream.Write( (int)bis.ContainerSerial ); + m_Stream.Write( (ushort)bis.Hue ); + } + } + } + + public sealed class VendorBuyContent6017 : Packet + { + public VendorBuyContent6017( List list ) : base( 0x3c ) + { + this.EnsureCapacity( list.Count*20 + 5 ); + + m_Stream.Write( (short)list.Count ); + + //The client sorts these by their X/Y value. + //OSI sends these in wierd order. X/Y highest to lowest and serial loest to highest + //These are already sorted by serial (done by the vendor class) but we have to send them by x/y + //(the x74 packet is sent in 'correct' order.) + for ( int i = list.Count - 1; i >= 0; --i ) + { + BuyItemState bis = (BuyItemState)list[i]; + + m_Stream.Write( (int)bis.MySerial ); + m_Stream.Write( (ushort)bis.ItemID ); + m_Stream.Write( (byte)0 );//itemid offset + m_Stream.Write( (ushort)bis.Amount ); + m_Stream.Write( (short)(i+1) );//x + m_Stream.Write( (short)1 );//y + m_Stream.Write( (byte)0 ); // Grid Location? + m_Stream.Write( (int)bis.ContainerSerial ); + m_Stream.Write( (ushort)bis.Hue ); + } + } + } + + public sealed class DisplayBuyList : Packet + { + public DisplayBuyList( Mobile vendor ) : base( 0x24, 7 ) + { + m_Stream.Write( (int)vendor.Serial ); + m_Stream.Write( (short) 0x30 ); // buy window id? + } + } + + public sealed class DisplayBuyListHS : Packet + { + public DisplayBuyListHS( Mobile vendor ) : base( 0x24, 9 ) + { + m_Stream.Write( (int)vendor.Serial ); + m_Stream.Write( (short) 0x30 ); // buy window id? + m_Stream.Write( (short) 0x00 ); + } + } + + public sealed class VendorBuyList : Packet + { + public VendorBuyList( Mobile vendor, List list ) + : base( 0x74 ) + { + this.EnsureCapacity( 256 ); + + Container BuyPack = vendor.FindItemOnLayer( Layer.ShopBuy ) as Container; + m_Stream.Write( (int)(BuyPack == null ? Serial.MinusOne : BuyPack.Serial) ); + + m_Stream.Write( (byte)list.Count ); + + for ( int i = 0; i < list.Count; ++i ) + { + BuyItemState bis = list[i]; + + m_Stream.Write( (int) bis.Price ); + + string desc = bis.Description; + + if ( desc == null ) + desc = ""; + + m_Stream.Write( (byte)(desc.Length + 1) ); + m_Stream.WriteAsciiNull( desc ); + } + } + } + + public sealed class VendorSellList : Packet + { + public VendorSellList( Mobile shopkeeper, Hashtable table ) : base( 0x9E ) + { + this.EnsureCapacity( 256 ); + + m_Stream.Write( (int) shopkeeper.Serial ); + + m_Stream.Write( (ushort) table.Count ); + + foreach ( SellItemState state in table.Values ) + { + m_Stream.Write( (int) state.Item.Serial ); + m_Stream.Write( (ushort) state.Item.ItemID ); + m_Stream.Write( (ushort) state.Item.Hue ); + m_Stream.Write( (ushort) state.Item.Amount ); + m_Stream.Write( (ushort) state.Price ); + + string name = state.Item.Name; + + if ( name == null || (name = name.Trim()).Length <= 0 ) + name = state.Name; + + if ( name == null ) + name = ""; + + m_Stream.Write( (ushort) (name.Length) ); + m_Stream.WriteAsciiFixed( name, (ushort) (name.Length) ); + } + } + } + + public sealed class EndVendorSell : Packet + { + public EndVendorSell( Mobile Vendor ) : base( 0x3B, 8 ) + { + m_Stream.Write( (ushort)8 );//length + m_Stream.Write( (int)Vendor.Serial ); + m_Stream.Write( (byte)0 ); + } + } + + public sealed class EndVendorBuy : Packet + { + public EndVendorBuy( Mobile Vendor ) : base( 0x3B, 8 ) + { + m_Stream.Write( (ushort)8 );//length + m_Stream.Write( (int)Vendor.Serial ); + m_Stream.Write( (byte)0 ); + } + } + + public sealed class DeathAnimation : Packet + { + public DeathAnimation( Mobile killed, Item corpse ) : base( 0xAF, 13 ) + { + m_Stream.Write( (int) killed.Serial ); + m_Stream.Write( (int) (corpse == null ? Serial.Zero : corpse.Serial) ); + m_Stream.Write( (int) 0 ) ; + } + } + + public sealed class StatLockInfo : Packet + { + public StatLockInfo( Mobile m ) : base( 0xBF ) + { + this.EnsureCapacity( 12 ); + + m_Stream.Write( (short) 0x19 ); + m_Stream.Write( (byte) 2 ); + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (byte) 0 ); + + int lockBits = 0; + + lockBits |= (int)m.StrLock << 4; + lockBits |= (int)m.DexLock << 2; + lockBits |= (int)m.IntLock; + + m_Stream.Write( (byte) lockBits ); + } + } + + public class EquipInfoAttribute + { + private int m_Number; + private int m_Charges; + + public int Number + { + get + { + return m_Number; + } + } + + public int Charges + { + get + { + return m_Charges; + } + } + + public EquipInfoAttribute( int number ) : this( number, -1 ) + { + } + + public EquipInfoAttribute( int number, int charges ) + { + m_Number = number; + m_Charges = charges; + } + } + + public class EquipmentInfo + { + private int m_Number; + private Mobile m_Crafter; + private bool m_Unidentified; + private EquipInfoAttribute[] m_Attributes; + + public int Number + { + get + { + return m_Number; + } + } + + public Mobile Crafter + { + get + { + return m_Crafter; + } + } + + public bool Unidentified + { + get + { + return m_Unidentified; + } + } + + public EquipInfoAttribute[] Attributes + { + get + { + return m_Attributes; + } + } + + public EquipmentInfo( int number, Mobile crafter, bool unidentified, EquipInfoAttribute[] attributes ) + { + m_Number = number; + m_Crafter = crafter; + m_Unidentified = unidentified; + m_Attributes = attributes; + } + } + + public sealed class DisplayEquipmentInfo : Packet + { + public DisplayEquipmentInfo( Item item, EquipmentInfo info ) : base( 0xBF ) + { + EquipInfoAttribute[] attrs = info.Attributes; + + this.EnsureCapacity( 17 + (info.Crafter == null ? 0 : 6 + info.Crafter.Name == null ? 0 : info.Crafter.Name.Length) + (info.Unidentified ? 4 : 0) + (attrs.Length * 6) ); + + m_Stream.Write( (short) 0x10 ); + m_Stream.Write( (int) item.Serial ); + + m_Stream.Write( (int) info.Number ); + + if ( info.Crafter != null ) + { + string name = info.Crafter.Name; + + m_Stream.Write( (int) -3 ); + + if ( name == null ) + m_Stream.Write( (ushort) 0 ); + else + { + int length = name.Length; + m_Stream.Write( (ushort) length ); + m_Stream.WriteAsciiFixed( name, length ); + } + } + + if ( info.Unidentified ) + { + m_Stream.Write( (int) -4 ); + } + + for ( int i = 0; i < attrs.Length; ++i ) + { + m_Stream.Write( (int) attrs[i].Number ); + m_Stream.Write( (short) attrs[i].Charges ); + } + + m_Stream.Write( (int) -1 ); + } + } + + public sealed class ChangeUpdateRange : Packet + { + private static ChangeUpdateRange[] m_Cache = new ChangeUpdateRange[0x100]; + + public static ChangeUpdateRange Instantiate( int range ) + { + byte idx = (byte)range; + ChangeUpdateRange p = m_Cache[idx]; + + if ( p == null ) + { + m_Cache[idx] = p = new ChangeUpdateRange( range ); + p.SetStatic(); + } + + return p; + } + + public ChangeUpdateRange( int range ) : base( 0xC8, 2 ) + { + m_Stream.Write( (byte) range ); + } + } + + public sealed class ChangeCombatant : Packet + { + public ChangeCombatant( Mobile combatant ) : base( 0xAA, 5 ) + { + m_Stream.Write( combatant != null ? combatant.Serial : Serial.Zero ); + } + } + + public sealed class DisplayHuePicker : Packet + { + public DisplayHuePicker( HuePicker huePicker ) : base( 0x95, 9 ) + { + m_Stream.Write( (int) huePicker.Serial ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) huePicker.ItemID ); + } + } + + public sealed class TripTimeResponse : Packet + { + public TripTimeResponse( int unk ) : base( 0xC9, 6 ) + { + m_Stream.Write( (byte) unk ); + m_Stream.Write( (int) Environment.TickCount ); + } + } + + public sealed class UTripTimeResponse : Packet + { + public UTripTimeResponse( int unk ) : base( 0xCA, 6 ) + { + m_Stream.Write( (byte) unk ); + m_Stream.Write( (int) Environment.TickCount ); + } + } + + public sealed class UnicodePrompt : Packet + { + public UnicodePrompt( Prompt prompt ) : base( 0xC2 ) + { + this.EnsureCapacity( 21 ); + + m_Stream.Write( (int) prompt.Serial ); + m_Stream.Write( (int) prompt.Serial ); + m_Stream.Write( (int) 0 ); + m_Stream.Write( (int) 0 ); + m_Stream.Write( (short) 0 ); + } + } + + public sealed class ChangeCharacter : Packet + { + public ChangeCharacter( IAccount a ) : base( 0x81 ) + { + this.EnsureCapacity( 305 ); + + int count = 0; + + for ( int i = 0; i < a.Length; ++i ) + { + if ( a[i] != null ) + ++count; + } + + m_Stream.Write( (byte) count ); + m_Stream.Write( (byte) 0 ); + + for ( int i = 0; i < a.Length; ++i ) + { + if ( a[i] != null ) + { + string name = a[i].Name; + + if ( name == null ) + name = "-null-"; + else if ( (name = name.Trim()).Length == 0 ) + name = "-empty-"; + + m_Stream.WriteAsciiFixed( name, 30 ); + m_Stream.Fill( 30 ); // password + } + else + { + m_Stream.Fill( 60 ); + } + } + } + } + + public sealed class DeathStatus : Packet + { + public static readonly Packet Dead = Packet.SetStatic( new DeathStatus( true ) ); + public static readonly Packet Alive = Packet.SetStatic( new DeathStatus( false ) ); + + public static Packet Instantiate( bool dead ) + { + return ( dead ? Dead : Alive ); + } + + public DeathStatus( bool dead ) : base( 0x2C, 2 ) + { + m_Stream.Write( (byte) (dead ? 0 : 2) ); + } + } + + public sealed class SpeedControl : Packet + { + public static readonly Packet WalkSpeed = Packet.SetStatic( new SpeedControl( 2 ) ); + public static readonly Packet MountSpeed = Packet.SetStatic( new SpeedControl( 1 ) ); + public static readonly Packet Disable = Packet.SetStatic( new SpeedControl( 0 ) ); + + public SpeedControl( int speedControl ) + : base( 0xBF ) + { + EnsureCapacity( 3 ); + + m_Stream.Write( (short)0x26 ); + m_Stream.Write( (byte)speedControl ); + } + } + + public sealed class InvalidMapEnable : Packet + { + public InvalidMapEnable() : base( 0xC6, 1 ) + { + } + } + + public sealed class BondedStatus : Packet + { + public BondedStatus( int val1, Serial serial, int val2 ) : base( 0xBF ) + { + this.EnsureCapacity( 11 ); + + m_Stream.Write( (short) 0x19 ); + m_Stream.Write( (byte) val1 ); + m_Stream.Write( (int) serial ); + m_Stream.Write( (byte) val2 ); + } + } + + public sealed class ToggleSpecialAbility : Packet + { + public ToggleSpecialAbility( int abilityID, bool active ) + : base( 0xBF ) + { + EnsureCapacity( 7 ); + + m_Stream.Write( (short)0x25 ); + + m_Stream.Write( (short)abilityID ); + m_Stream.Write( (bool)active ); + } + } + + public sealed class DisplayItemListMenu : Packet + { + public DisplayItemListMenu( ItemListMenu menu ) : base( 0x7C ) + { + this.EnsureCapacity( 256 ); + + m_Stream.Write( (int) ((IMenu)menu).Serial ); + m_Stream.Write( (short) 0 ); + + string question = menu.Question; + + if ( question == null ) + m_Stream.Write( (byte) 0 ); + else + { + int questionLength = question.Length; + m_Stream.Write( (byte) questionLength ); + m_Stream.WriteAsciiFixed( question, questionLength ); + } + + ItemListEntry[] entries = menu.Entries; + + int entriesLength = (byte)entries.Length; + + m_Stream.Write( (byte) entriesLength ); + + for ( int i = 0; i < entriesLength; ++i ) + { + ItemListEntry e = entries[i]; + + m_Stream.Write( (ushort) e.ItemID ); + m_Stream.Write( (short) e.Hue ); + + string name = e.Name; + + if ( name == null ) + m_Stream.Write( (byte) 0 ); + else + { + int nameLength = name.Length; + m_Stream.Write( (byte) nameLength ); + m_Stream.WriteAsciiFixed( name, nameLength ); + } + } + } + } + + public sealed class DisplayQuestionMenu : Packet + { + public DisplayQuestionMenu( QuestionMenu menu ) : base( 0x7C ) + { + this.EnsureCapacity( 256 ); + + m_Stream.Write( (int) ((IMenu)menu).Serial ); + m_Stream.Write( (short) 0 ); + + string question = menu.Question; + + if ( question == null ) + m_Stream.Write( (byte) 0 ); + else + { + int questionLength = question.Length; + m_Stream.Write( (byte) questionLength ); + m_Stream.WriteAsciiFixed( question, questionLength ); + } + + string[] answers = menu.Answers; + + int answersLength = (byte)answers.Length; + + m_Stream.Write( (byte) answersLength ); + + for ( int i = 0; i < answersLength; ++i ) + { + m_Stream.Write( (int) 0 ); + + string answer = answers[i]; + + if ( answer == null ) + m_Stream.Write( (byte) 0 ); + else + { + int answerLength = answer.Length; + m_Stream.Write( (byte) answerLength ); + m_Stream.WriteAsciiFixed( answer, answerLength ); + } + } + } + } + + public sealed class GlobalLightLevel : Packet + { + private static GlobalLightLevel[] m_Cache = new GlobalLightLevel[0x100]; + + public static GlobalLightLevel Instantiate( int level ) + { + byte lvl = (byte)level; + GlobalLightLevel p = m_Cache[lvl]; + + if ( p == null ) + { + m_Cache[lvl] = p = new GlobalLightLevel( level ); + p.SetStatic(); + } + + return p; + } + + public GlobalLightLevel( int level ) : base( 0x4F, 2 ) + { + m_Stream.Write( (sbyte) level ); + } + } + + public sealed class PersonalLightLevel : Packet + { + public PersonalLightLevel( Mobile m ) : this( m, m.LightLevel ) + { + } + + public PersonalLightLevel( Mobile m, int level ) : base( 0x4E, 6 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (sbyte) level ); + } + } + + public sealed class PersonalLightLevelZero : Packet + { + public PersonalLightLevelZero( Mobile m ) : base( 0x4E, 6 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (sbyte) 0 ); + } + } + + public enum CMEFlags + { + None = 0x00, + Disabled = 0x01, + Arrow = 0x02, + Highlighted = 0x04, + Colored = 0x20 + } + + public sealed class DisplayContextMenu : Packet + { + public DisplayContextMenu(ContextMenu menu) + : base(0xBF) + { + ContextMenuEntry[] entries = menu.Entries; + + int length = (byte)entries.Length; + + this.EnsureCapacity(12 + (length * 8)); + + m_Stream.Write((short)0x14); + m_Stream.Write((short)0x02); + + IEntity target = menu.Target as IEntity; + + m_Stream.Write((int)(target == null ? Serial.MinusOne : target.Serial)); + + m_Stream.Write((byte)length); + + Point3D p; + + if (target is Mobile) + p = target.Location; + else if (target is Item) + p = ((Item)target).GetWorldLocation(); + else + p = Point3D.Zero; + + for (int i = 0; i < length; ++i) + { + ContextMenuEntry e = entries[i]; + + m_Stream.Write((int)e.Number); + m_Stream.Write((short)i); + + int range = e.Range; + + if (range == -1) + range = 18; + + CMEFlags flags = (e.Enabled && menu.From.InRange(p, range)) ? CMEFlags.None : CMEFlags.Disabled; + + flags |= e.Flags; + + m_Stream.Write((short)flags); + } + } + } + + public sealed class DisplayContextMenuOld : Packet + { + public DisplayContextMenuOld(ContextMenu menu) + : base(0xBF) + { + ContextMenuEntry[] entries = menu.Entries; + + int length = (byte)entries.Length; + + this.EnsureCapacity(12 + (length * 8)); + + m_Stream.Write((short)0x14); + m_Stream.Write((short)0x01); + + IEntity target = menu.Target as IEntity; + + m_Stream.Write((int)(target == null ? Serial.MinusOne : target.Serial)); + + m_Stream.Write((byte)length); + + Point3D p; + + if (target is Mobile) + p = target.Location; + else if (target is Item) + p = ((Item)target).GetWorldLocation(); + else + p = Point3D.Zero; + + for (int i = 0; i < length; ++i) + { + ContextMenuEntry e = entries[i]; + + m_Stream.Write((short)i); + m_Stream.Write((ushort)(e.Number - 3000000)); + + int range = e.Range; + + if (range == -1) + range = 18; + + CMEFlags flags = (e.Enabled && menu.From.InRange(p, range)) ? CMEFlags.None : CMEFlags.Disabled; + + int color = e.Color & 0xFFFF; + + if (color != 0xFFFF) + flags |= CMEFlags.Colored; + + flags |= e.Flags; + + m_Stream.Write((short)flags); + + if ((flags & CMEFlags.Colored) != 0) + m_Stream.Write((short)color); + } + } + } + + public sealed class DisplayProfile : Packet + { + public DisplayProfile( bool realSerial, Mobile m, string header, string body, string footer ) : base( 0xB8 ) + { + if ( header == null ) + header = ""; + + if ( body == null ) + body = ""; + + if ( footer == null ) + footer = ""; + + EnsureCapacity( 12 + header.Length + (footer.Length * 2) + (body.Length * 2) ); + + m_Stream.Write( (int) (realSerial ? m.Serial : Serial.Zero) ); + m_Stream.WriteAsciiNull( header ); + m_Stream.WriteBigUniNull( footer ); + m_Stream.WriteBigUniNull( body ); + } + } + + public sealed class CloseGump : Packet + { + public CloseGump( int typeID, int buttonID ) : base( 0xBF ) + { + this.EnsureCapacity( 13 ); + + m_Stream.Write( (short) 0x04 ); + m_Stream.Write( (int) typeID ); + m_Stream.Write( (int) buttonID ); + } + } + + public sealed class EquipUpdate : Packet + { + public EquipUpdate( Item item ) : base( 0x2E, 15 ) + { + Serial parentSerial; + + if ( item.Parent is Mobile ) + { + parentSerial = ((Mobile)item.Parent).Serial; + } + else + { + Console.WriteLine( "Warning: EquipUpdate on item with !(parent is Mobile)" ); + parentSerial = Serial.Zero; + } + + int hue = item.Hue; + + if ( item.Parent is Mobile ) + { + Mobile mob = (Mobile)item.Parent; + + if ( mob.SolidHueOverride >= 0 ) + hue = mob.SolidHueOverride; + } + + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (short) item.ItemID ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) item.Layer ); + m_Stream.Write( (int) parentSerial ); + m_Stream.Write( (short) hue ); + } + } + + public sealed class WorldItem : Packet + { + public WorldItem( Item item ) : base( 0x1A ) + { + this.EnsureCapacity( 20 ); + + // 14 base length + // +2 - Amount + // +2 - Hue + // +1 - Flags + + uint serial = (uint)item.Serial.Value; + int itemID = item.ItemID & 0x3FFF; + int amount = item.Amount; + Point3D loc = item.Location; + int x = loc.m_X; + int y = loc.m_Y; + int hue = item.Hue; + int flags = item.GetPacketFlags(); + int direction = (int)item.Direction; + + if ( amount != 0 ) + { + serial |= 0x80000000; + } + else + { + serial &= 0x7FFFFFFF; + } + + m_Stream.Write( (uint) serial ); + + if ( item is BaseMulti ) + m_Stream.Write( (short) (itemID | 0x4000) ); + else + m_Stream.Write( (short) itemID ); + + if ( amount != 0 ) + { + m_Stream.Write( (short) amount ); + } + + x &= 0x7FFF; + + if ( direction != 0 ) + { + x |= 0x8000; + } + + m_Stream.Write( (short) x ); + + y &= 0x3FFF; + + if ( hue != 0 ) + { + y |= 0x8000; + } + + if ( flags != 0 ) + { + y |= 0x4000; + } + + m_Stream.Write( (short) y ); + + if ( direction != 0 ) + m_Stream.Write( (byte) direction ); + + m_Stream.Write( (sbyte) loc.m_Z ); + + if ( hue != 0 ) + m_Stream.Write( (ushort) hue ); + + if ( flags != 0 ) + m_Stream.Write( (byte) flags ); + } + } + + public sealed class WorldItemSA : Packet + { + public WorldItemSA( Item item ) : base( 0xF3, 24 ) + { + m_Stream.Write( (short) 0x1 ); + + int itemID = item.ItemID; + + if ( item is BaseMulti ) { + m_Stream.Write( (byte) 0x02 ); + + m_Stream.Write( (int) item.Serial ); + + itemID &= 0x3FFF; + + m_Stream.Write( (short) itemID ); + + m_Stream.Write( (byte) 0 ); + /*} else if ( ) { + m_Stream.Write( (byte) 0x01 ); + + m_Stream.Write( (int) item.Serial ); + + m_Stream.Write( (short) itemID ); + + m_Stream.Write( (byte) item.Direction );*/ + } else { + m_Stream.Write( (byte) 0x00 ); + + m_Stream.Write( (int) item.Serial ); + + itemID &= 0x7FFF; + + m_Stream.Write( (short) itemID ); + + m_Stream.Write( (byte) 0 ); + } + + int amount = item.Amount; + m_Stream.Write( (short) amount ); + m_Stream.Write( (short) amount ); + + Point3D loc = item.Location; + int x = loc.m_X & 0x7FFF; + int y = loc.m_Y & 0x3FFF; + m_Stream.Write( (short) x ); + m_Stream.Write( (short) y ); + m_Stream.Write( (sbyte) loc.m_Z ); + + m_Stream.Write( (byte) item.Light ); + m_Stream.Write( (short) item.Hue ); + m_Stream.Write( (byte) item.GetPacketFlags() ); + } + } + + public sealed class WorldItemHS : Packet + { + public WorldItemHS( Item item ) : base( 0xF3, 26 ) + { + m_Stream.Write( (short) 0x1 ); + + int itemID = item.ItemID; + + if ( item is BaseMulti ) { + m_Stream.Write( (byte) 0x02 ); + + m_Stream.Write( (int) item.Serial ); + + itemID &= 0x3FFF; + + m_Stream.Write( (ushort) itemID ); + + m_Stream.Write( (byte) 0 ); + /*} else if ( ) { + m_Stream.Write( (byte) 0x01 ); + + m_Stream.Write( (int) item.Serial ); + + m_Stream.Write( (ushort) itemID ); + + m_Stream.Write( (byte) item.Direction );*/ + } else { + m_Stream.Write( (byte) 0x00 ); + + m_Stream.Write( (int) item.Serial ); + + itemID &= 0xFFFF; + + m_Stream.Write( (ushort) itemID ); + + m_Stream.Write( (byte) 0 ); + } + + int amount = item.Amount; + m_Stream.Write( (short) amount ); + m_Stream.Write( (short) amount ); + + Point3D loc = item.Location; + int x = loc.m_X & 0x7FFF; + int y = loc.m_Y & 0x3FFF; + m_Stream.Write( (short) x ); + m_Stream.Write( (short) y ); + m_Stream.Write( (sbyte) loc.m_Z ); + + m_Stream.Write( (byte) item.Light ); + m_Stream.Write( (short) item.Hue ); + m_Stream.Write( (byte) item.GetPacketFlags() ); + + m_Stream.Write( (short) 0x00 ); // ?? + } + } + + public sealed class LiftRej : Packet + { + public LiftRej( LRReason reason ) : base( 0x27, 2 ) + { + m_Stream.Write( (byte) reason ); + } + } + + public sealed class LogoutAck : Packet + { + public LogoutAck() : base( 0xD1, 2 ) + { + m_Stream.Write( (byte) 0x01 ); + } + } + + public sealed class Weather : Packet + { + public Weather( int v1, int v2, int v3 ) : base( 0x65, 4 ) + { + m_Stream.Write( (byte) v1 ); + m_Stream.Write( (byte) v2 ); + m_Stream.Write( (byte) v3 ); + } + } + + public sealed class UnkD3 : Packet + { + public UnkD3( Mobile beholder, Mobile beheld ) : base( 0xD3 ) + { + this.EnsureCapacity( 256 ); + + //int + //short + //short + //short + //byte + //byte + //short + //byte + //byte + //short + //short + //short + //while ( int != 0 ) + //{ + //short + //byte + //short + //} + + m_Stream.Write( (int) beheld.Serial ); + m_Stream.Write( (short) beheld.Body ); + m_Stream.Write( (short) beheld.X ); + m_Stream.Write( (short) beheld.Y ); + m_Stream.Write( (sbyte) beheld.Z ); + m_Stream.Write( (byte) beheld.Direction ); + m_Stream.Write( (ushort) beheld.Hue ); + m_Stream.Write( (byte) beheld.GetPacketFlags() ); + m_Stream.Write( (byte) Notoriety.Compute( beholder, beheld ) ); + + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 0 ); + + m_Stream.Write( (int) 0 ); + } + } + + public sealed class GQRequest : Packet + { + public GQRequest() : base( 0xC3 ) + { + this.EnsureCapacity( 256 ); + + m_Stream.Write( (int) 1 ); + m_Stream.Write( (int) 2 ); // ID + m_Stream.Write( (int) 3 ); // Customer ? (this) + m_Stream.Write( (int) 4 ); // Customer this (?) + m_Stream.Write( (int) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 6 ); + m_Stream.Write( (byte) 'r' ); + m_Stream.Write( (byte) 'e' ); + m_Stream.Write( (byte) 'g' ); + m_Stream.Write( (byte) 'i' ); + m_Stream.Write( (byte) 'o' ); + m_Stream.Write( (byte) 'n' ); + m_Stream.Write( (int) 7 ); // Call time in seconds + m_Stream.Write( (short) 2 ); // Map (0=fel,1=tram,2=ilsh) + m_Stream.Write( (int) 8 ); // X + m_Stream.Write( (int) 9 ); // Y + m_Stream.Write( (int) 10 ); // Z + m_Stream.Write( (int) 11 ); // Volume + m_Stream.Write( (int) 12 ); // Rank + m_Stream.Write( (int) -1 ); + m_Stream.Write( (int) 1 ); // type + } + } + + /// + /// Causes the client to walk in a given direction. It does not send a movement request. + /// + public sealed class PlayerMove : Packet + { + public PlayerMove( Direction d ) : base( 0x97, 2 ) + { + m_Stream.Write( (byte) d ); + + // @4C63B0 + } + } + + /// + /// Displays a message "There are currently [count] available calls in the global queue.". + /// + public sealed class GQCount : Packet + { + public GQCount( int unk, int count ) : base( 0xCB, 7 ) + { + m_Stream.Write( (short) unk ); + m_Stream.Write( (int) count ); + } + } + + /// + /// Asks the client for it's version + /// + public sealed class ClientVersionReq : Packet + { + public ClientVersionReq() : base( 0xBD ) + { + this.EnsureCapacity( 3 ); + } + } + + /// + /// Asks the client for it's "assist version". (Perhaps for UOAssist?) + /// + public sealed class AssistVersionReq : Packet + { + public AssistVersionReq( int unk ) : base( 0xBE ) + { + this.EnsureCapacity( 7 ); + + m_Stream.Write( (int) unk ); + } + } + + public enum EffectType + { + Moving = 0x00, + Lightning = 0x01, + FixedXYZ = 0x02, + FixedFrom = 0x03 + } + + public class ParticleEffect : Packet + { + public ParticleEffect( EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, Serial serial, int layer, int unknown ) : base( 0xC7, 49 ) + { + m_Stream.Write( (byte) type ); + m_Stream.Write( (int) from ); + m_Stream.Write( (int) to ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) fromPoint.m_X ); + m_Stream.Write( (short) fromPoint.m_Y ); + m_Stream.Write( (sbyte) fromPoint.m_Z ); + m_Stream.Write( (short) toPoint.m_X ); + m_Stream.Write( (short) toPoint.m_Y ); + m_Stream.Write( (sbyte) toPoint.m_Z ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (bool) fixedDirection ); + m_Stream.Write( (bool) explode ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + m_Stream.Write( (short) effect ); + m_Stream.Write( (short) explodeEffect ); + m_Stream.Write( (short) explodeSound ); + m_Stream.Write( (int) serial ); + m_Stream.Write( (byte) layer ); + m_Stream.Write( (short) unknown ); + } + + public ParticleEffect( EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, Serial serial, int layer, int unknown ) : base( 0xC7, 49 ) + { + m_Stream.Write( (byte) type ); + m_Stream.Write( (int) from ); + m_Stream.Write( (int) to ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) fromPoint.X ); + m_Stream.Write( (short) fromPoint.Y ); + m_Stream.Write( (sbyte) fromPoint.Z ); + m_Stream.Write( (short) toPoint.X ); + m_Stream.Write( (short) toPoint.Y ); + m_Stream.Write( (sbyte) toPoint.Z ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (bool) fixedDirection ); + m_Stream.Write( (bool) explode ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + m_Stream.Write( (short) effect ); + m_Stream.Write( (short) explodeEffect ); + m_Stream.Write( (short) explodeSound ); + m_Stream.Write( (int) serial ); + m_Stream.Write( (byte) layer ); + m_Stream.Write( (short) unknown ); + } + } + + public class HuedEffect : Packet + { + public HuedEffect( EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) type ); + m_Stream.Write( (int) from ); + m_Stream.Write( (int) to ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) fromPoint.m_X ); + m_Stream.Write( (short) fromPoint.m_Y ); + m_Stream.Write( (sbyte) fromPoint.m_Z ); + m_Stream.Write( (short) toPoint.m_X ); + m_Stream.Write( (short) toPoint.m_Y ); + m_Stream.Write( (sbyte) toPoint.m_Z ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (bool) fixedDirection ); + m_Stream.Write( (bool) explode ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + } + + public HuedEffect( EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) type ); + m_Stream.Write( (int) from ); + m_Stream.Write( (int) to ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) fromPoint.X ); + m_Stream.Write( (short) fromPoint.Y ); + m_Stream.Write( (sbyte) fromPoint.Z ); + m_Stream.Write( (short) toPoint.X ); + m_Stream.Write( (short) toPoint.Y ); + m_Stream.Write( (sbyte) toPoint.Z ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (bool) fixedDirection ); + m_Stream.Write( (bool) explode ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + } + } + + public sealed class TargetParticleEffect : ParticleEffect + { + public TargetParticleEffect( IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int layer, int unknown ) : base( EffectType.FixedFrom, e.Serial, Serial.Zero, itemID, e.Location, e.Location, speed, duration, true, false, hue, renderMode, effect, 1, 0, e.Serial, layer, unknown ) + { + } + } + + public sealed class TargetEffect : HuedEffect + { + public TargetEffect( IEntity e, int itemID, int speed, int duration, int hue, int renderMode ) : base( EffectType.FixedFrom, e.Serial, Serial.Zero, itemID, e.Location, e.Location, speed, duration, true, false, hue, renderMode ) + { + } + } + + public sealed class LocationParticleEffect : ParticleEffect + { + public LocationParticleEffect( IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown ) : base( EffectType.FixedXYZ, e.Serial, Serial.Zero, itemID, e.Location, e.Location, speed, duration, true, false, hue, renderMode, effect, 1, 0, e.Serial, 255, unknown ) + { + } + } + + public sealed class LocationEffect : HuedEffect + { + public LocationEffect( IPoint3D p, int itemID, int speed, int duration, int hue, int renderMode ) : base( EffectType.FixedXYZ, Serial.Zero, Serial.Zero, itemID, p, p, speed, duration, true, false, hue, renderMode ) + { + } + } + + public sealed class MovingParticleEffect : ParticleEffect + { + public MovingParticleEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, int unknown ) : base( EffectType.Moving, from.Serial, to.Serial, itemID, from.Location, to.Location, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, Serial.Zero, (int)layer, unknown ) + { + } + } + + public sealed class MovingEffect : HuedEffect + { + public MovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode ) : base( EffectType.Moving, from.Serial, to.Serial, itemID, from.Location, to.Location, speed, duration, fixedDirection, explodes, hue, renderMode ) + { + } + } + + public enum ScreenEffectType + { + FadeOut = 0x00, + FadeIn = 0x01, + LightFlash = 0x02, + FadeInOut = 0x03, + DarkFlash = 0x04 + } + + public class ScreenEffect : Packet + { + public ScreenEffect(ScreenEffectType type) + : base(0x70, 28) + { + m_Stream.Write((byte)0x04); + m_Stream.Fill(8); + m_Stream.Write((short)type); + m_Stream.Fill(16); + } + } + + public sealed class ScreenFadeOut : ScreenEffect + { + public static readonly Packet Instance = Packet.SetStatic(new ScreenFadeOut()); + + public ScreenFadeOut() + : base(ScreenEffectType.FadeOut) + { + } + } + + public sealed class ScreenFadeIn : ScreenEffect + { + public static readonly Packet Instance = Packet.SetStatic(new ScreenFadeIn()); + + public ScreenFadeIn() + : base(ScreenEffectType.FadeIn) + { + } + } + + public sealed class ScreenFadeInOut : ScreenEffect + { + public static readonly Packet Instance = Packet.SetStatic(new ScreenFadeInOut()); + + public ScreenFadeInOut() + : base(ScreenEffectType.FadeInOut) + { + } + } + + public sealed class ScreenLightFlash : ScreenEffect + { + public static readonly Packet Instance = Packet.SetStatic(new ScreenLightFlash()); + + public ScreenLightFlash() + : base(ScreenEffectType.LightFlash) + { + } + } + + public sealed class ScreenDarkFlash : ScreenEffect + { + public static readonly Packet Instance = Packet.SetStatic(new ScreenDarkFlash()); + + public ScreenDarkFlash() + : base(ScreenEffectType.DarkFlash) + { + } + } + + public enum DeleteResultType + { + PasswordInvalid, + CharNotExist, + CharBeingPlayed, + CharTooYoung, + CharQueued, + BadRequest + } + + public sealed class DeleteResult : Packet + { + public DeleteResult( DeleteResultType res ) : base( 0x85, 2 ) + { + m_Stream.Write( (byte) res ); + } + } + + /*public sealed class MovingEffect : Packet + { + public MovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool turn, int hue, int renderMode ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) 0x00 ); + m_Stream.Write( (int) from.Serial ); + m_Stream.Write( (int) to.Serial ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) from.Location.m_X ); + m_Stream.Write( (short) from.Location.m_Y ); + m_Stream.Write( (sbyte) from.Location.m_Z ); + m_Stream.Write( (short) to.Location.m_X ); + m_Stream.Write( (short) to.Location.m_Y ); + m_Stream.Write( (sbyte) to.Location.m_Z ); + m_Stream.Write( (byte) speed ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (bool) fixedDirection ); + m_Stream.Write( (bool) turn ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + } + }*/ + + /*public sealed class LocationEffect : Packet + { + public LocationEffect( IPoint3D p, int itemID, int duration, int hue, int renderMode ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) 0x02 ); + m_Stream.Write( (int) Serial.Zero ); + m_Stream.Write( (int) Serial.Zero ); + m_Stream.Write( (short) itemID ); + m_Stream.Write( (short) p.X ); + m_Stream.Write( (short) p.Y ); + m_Stream.Write( (sbyte) p.Z ); + m_Stream.Write( (short) p.X ); + m_Stream.Write( (short) p.Y ); + m_Stream.Write( (sbyte) p.Z ); + m_Stream.Write( (byte) 10 ); + m_Stream.Write( (byte) duration ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 1 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) renderMode ); + } + }*/ + + public sealed class BoltEffect : Packet + { + public BoltEffect( IEntity target, int hue ) : base( 0xC0, 36 ) + { + m_Stream.Write( (byte) 0x01 ); // type + m_Stream.Write( (int) target.Serial ); + m_Stream.Write( (int) Serial.Zero ); + m_Stream.Write( (short) 0 ); // itemID + m_Stream.Write( (short) target.X ); + m_Stream.Write( (short) target.Y ); + m_Stream.Write( (sbyte) target.Z ); + m_Stream.Write( (short) target.X ); + m_Stream.Write( (short) target.Y ); + m_Stream.Write( (sbyte) target.Z ); + m_Stream.Write( (byte) 0 ); // speed + m_Stream.Write( (byte) 0 ); // duration + m_Stream.Write( (short) 0 ); // unk + m_Stream.Write( false ); // fixed direction + m_Stream.Write( false ); // explode + m_Stream.Write( (int) hue ); + m_Stream.Write( (int) 0 ); // render mode + } + } + + public sealed class DisplaySpellbook : Packet + { + public DisplaySpellbook( Item book ) : base( 0x24, 7 ) + { + m_Stream.Write( (int) book.Serial ); + m_Stream.Write( (short) -1 ); + } + } + + public sealed class DisplaySpellbookHS : Packet + { + public DisplaySpellbookHS( Item book ) : base( 0x24, 9 ) + { + m_Stream.Write( (int) book.Serial ); + m_Stream.Write( (short) -1 ); + m_Stream.Write( (short) 0x7D ); + } + } + + public sealed class NewSpellbookContent : Packet + { + public NewSpellbookContent( Item item, int graphic, int offset, ulong content ) : base( 0xBF ) + { + EnsureCapacity( 23 ); + + m_Stream.Write( (short) 0x1B ); + m_Stream.Write( (short) 0x01 ); + + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (short) graphic ); + m_Stream.Write( (short) offset ); + + for ( int i = 0; i < 8; ++i ) + m_Stream.Write( (byte)(content >> (i * 8)) ); + } + } + + public sealed class SpellbookContent : Packet + { + public SpellbookContent( int count, int offset, ulong content, Item item ) : base( 0x3C ) + { + this.EnsureCapacity( 5 + (count * 19) ); + + int written = 0; + + m_Stream.Write( (ushort) 0 ); + + ulong mask = 1; + + for ( int i = 0; i < 64; ++i, mask <<= 1 ) + { + if ( (content & mask) != 0 ) + { + m_Stream.Write( (int) (0x7FFFFFFF - i) ); + m_Stream.Write( (ushort) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (ushort) (i + offset) ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (short) 0 ); + + ++written; + } + } + + m_Stream.Seek( 3, SeekOrigin.Begin ); + m_Stream.Write( (ushort) written ); + } + } + + public sealed class SpellbookContent6017 : Packet + { + public SpellbookContent6017( int count, int offset, ulong content, Item item ) : base( 0x3C ) + { + this.EnsureCapacity( 5 + (count * 20) ); + + int written = 0; + + m_Stream.Write( (ushort) 0 ); + + ulong mask = 1; + + for ( int i = 0; i < 64; ++i, mask <<= 1 ) + { + if ( (content & mask) != 0 ) + { + m_Stream.Write( (int) (0x7FFFFFFF - i) ); + m_Stream.Write( (ushort) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (ushort) (i + offset) ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (byte) 0 ); // Grid Location? + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (short) 0 ); + + ++written; + } + } + + m_Stream.Seek( 3, SeekOrigin.Begin ); + m_Stream.Write( (ushort) written ); + } + } + + public sealed class ContainerDisplay : Packet + { + public ContainerDisplay( Container c ) : base( 0x24, 7 ) + { + m_Stream.Write( (int) c.Serial ); + m_Stream.Write( (short) c.GumpID ); + } + } + + public sealed class ContainerDisplayHS : Packet + { + public ContainerDisplayHS( Container c ) : base( 0x24, 9 ) + { + m_Stream.Write( (int) c.Serial ); + m_Stream.Write( (short) c.GumpID ); + m_Stream.Write( (short) 0x7D ); + } + } + + public sealed class ContainerContentUpdate : Packet + { + public ContainerContentUpdate( Item item ) : base( 0x25, 20 ) + { + Serial parentSerial; + + if ( item.Parent is Item ) + { + parentSerial = ((Item)item.Parent).Serial; + } + else + { + Console.WriteLine( "Warning: ContainerContentUpdate on item with !(parent is Item)" ); + parentSerial = Serial.Zero; + } + + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (ushort) item.ItemID ); + m_Stream.Write( (byte) 0 ); // signed, itemID offset + m_Stream.Write( (ushort) item.Amount ); + m_Stream.Write( (short) item.X ); + m_Stream.Write( (short) item.Y ); + m_Stream.Write( (int) parentSerial ); + m_Stream.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue)); + } + } + + public sealed class ContainerContentUpdate6017 : Packet + { + public ContainerContentUpdate6017( Item item ) : base( 0x25, 21 ) + { + Serial parentSerial; + + if ( item.Parent is Item ) + { + parentSerial = ((Item)item.Parent).Serial; + } + else + { + Console.WriteLine( "Warning: ContainerContentUpdate on item with !(parent is Item)" ); + parentSerial = Serial.Zero; + } + + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (ushort) item.ItemID ); + m_Stream.Write( (byte) 0 ); // signed, itemID offset + m_Stream.Write( (ushort) item.Amount ); + m_Stream.Write( (short) item.X ); + m_Stream.Write( (short) item.Y ); + m_Stream.Write( (byte) 0 ); // Grid Location? + m_Stream.Write( (int) parentSerial ); + m_Stream.Write((ushort)(item.QuestItem ? Item.QuestItemHue : item.Hue)); + } + } + + public sealed class ContainerContent : Packet + { + public ContainerContent( Mobile beholder, Item beheld ) : base( 0x3C ) + { + List items = beheld.Items; + int count = items.Count; + + this.EnsureCapacity( 5 + (count * 19) ); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write( (ushort) 0 ); + + for ( int i = 0; i < count; ++i ) + { + Item child = items[i]; + + if ( !child.Deleted && beholder.CanSee( child ) ) + { + Point3D loc = child.Location; + + m_Stream.Write( (int) child.Serial ); + m_Stream.Write( (ushort) child.ItemID ); + m_Stream.Write( (byte) 0 ); // signed, itemID offset + m_Stream.Write( (ushort) child.Amount ); + m_Stream.Write( (short) loc.m_X ); + m_Stream.Write( (short) loc.m_Y ); + m_Stream.Write( (int) beheld.Serial ); + m_Stream.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue)); + + ++written; + } + } + + m_Stream.Seek( pos, SeekOrigin.Begin ); + m_Stream.Write( (ushort) written ); + } + } + + public sealed class ContainerContent6017 : Packet + { + public ContainerContent6017( Mobile beholder, Item beheld ) : base( 0x3C ) + { + List items = beheld.Items; + int count = items.Count; + + this.EnsureCapacity( 5 + (count * 20) ); + + long pos = m_Stream.Position; + + int written = 0; + + m_Stream.Write( (ushort) 0 ); + + for ( int i = 0; i < count; ++i ) + { + Item child = items[i]; + + if ( !child.Deleted && beholder.CanSee( child ) ) + { + Point3D loc = child.Location; + + m_Stream.Write( (int) child.Serial ); + m_Stream.Write( (ushort) child.ItemID ); + m_Stream.Write( (byte) 0 ); // signed, itemID offset + m_Stream.Write( (ushort) child.Amount ); + m_Stream.Write( (short) loc.m_X ); + m_Stream.Write( (short) loc.m_Y ); + m_Stream.Write( (byte) 0 ); // Grid Location? + m_Stream.Write( (int) beheld.Serial ); + m_Stream.Write((ushort)(child.QuestItem ? Item.QuestItemHue : child.Hue)); + + ++written; + } + } + + m_Stream.Seek( pos, SeekOrigin.Begin ); + m_Stream.Write( (ushort) written ); + } + } + + public sealed class SetWarMode : Packet + { + public static readonly Packet InWarMode = Packet.SetStatic( new SetWarMode( true ) ); + public static readonly Packet InPeaceMode = Packet.SetStatic( new SetWarMode( false ) ); + + public static Packet Instantiate( bool mode ) + { + return ( mode ? InWarMode : InPeaceMode ); + } + + public SetWarMode( bool mode ) : base( 0x72, 5 ) + { + m_Stream.Write( mode ); + m_Stream.Write( (byte) 0x00 ); + m_Stream.Write( (byte) 0x32 ); + m_Stream.Write( (byte) 0x00 ); + //m_Stream.Fill(); + } + } + + public sealed class Swing : Packet + { + public Swing( int flag, Mobile attacker, Mobile defender ) : base( 0x2F, 10 ) + { + m_Stream.Write( (byte) flag ); + m_Stream.Write( (int) attacker.Serial ); + m_Stream.Write( (int) defender.Serial ); + } + } + + public sealed class NullFastwalkStack : Packet + { + public NullFastwalkStack() : base( 0xBF ) + { + EnsureCapacity(256); + m_Stream.Write( (short) 0x1 ); + m_Stream.Write( (int) 0x0 ); + m_Stream.Write( (int) 0x0 ); + m_Stream.Write( (int) 0x0 ); + m_Stream.Write( (int) 0x0 ); + m_Stream.Write( (int) 0x0 ); + m_Stream.Write( (int) 0x0 ); + } + } + + public sealed class RemoveItem : Packet + { + public RemoveItem( Item item ) : base( 0x1D, 5 ) + { + m_Stream.Write( (int) item.Serial ); + } + } + + public sealed class RemoveMobile : Packet + { + public RemoveMobile( Mobile m ) : base( 0x1D, 5 ) + { + m_Stream.Write( (int) m.Serial ); + } + } + + public sealed class ServerChange : Packet + { + public ServerChange( Mobile m, Map map ) : base( 0x76, 16 ) + { + m_Stream.Write( (short) m.X ); + m_Stream.Write( (short) m.Y ); + m_Stream.Write( (short) m.Z ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) map.Width ); + m_Stream.Write( (short) map.Height ); + } + } + + public sealed class SkillUpdate : Packet + { + public SkillUpdate( Skills skills ) : base( 0x3A ) + { + this.EnsureCapacity( 6 + (skills.Length * 9) ); + + m_Stream.Write( (byte) 0x02 ); // type: absolute, capped + + for ( int i = 0; i < skills.Length; ++i ) + { + Skill s = skills[i]; + + double v = s.NonRacialValue; + int uv = (int)(v * 10); + + if ( uv < 0 ) + uv = 0; + else if ( uv >= 0x10000 ) + uv = 0xFFFF; + + m_Stream.Write( (ushort) (s.Info.SkillID + 1) ); + m_Stream.Write( (ushort) uv ); + m_Stream.Write( (ushort) s.BaseFixedPoint ); + m_Stream.Write( (byte) s.Lock ); + m_Stream.Write( (ushort) s.CapFixedPoint ); + } + + m_Stream.Write( (short) 0 ); // terminate + } + } + + public sealed class Sequence : Packet + { + public Sequence( int num ) : base( 0x7B, 2 ) + { + m_Stream.Write( (byte)num ); + } + } + + public sealed class SkillChange : Packet + { + public SkillChange( Skill skill ) : base( 0x3A ) + { + this.EnsureCapacity( 13 ); + + double v = skill.NonRacialValue; + int uv = (int)(v * 10); + + if ( uv < 0 ) + uv = 0; + else if ( uv >= 0x10000 ) + uv = 0xFFFF; + + m_Stream.Write( (byte) 0xDF ); // type: delta, capped + m_Stream.Write( (ushort) skill.Info.SkillID ); + m_Stream.Write( (ushort) uv ); + m_Stream.Write( (ushort) skill.BaseFixedPoint ); + m_Stream.Write( (byte) skill.Lock ); + m_Stream.Write( (ushort) skill.CapFixedPoint ); + + /*m_Stream.Write( (short) skill.Info.SkillID ); + m_Stream.Write( (short) (skill.Value * 10.0) ); + m_Stream.Write( (short) (skill.Base * 10.0) ); + m_Stream.Write( (byte) skill.Lock ); + m_Stream.Write( (short) skill.CapFixedPoint );*/ + } + } + + public sealed class LaunchBrowser : Packet + { + public LaunchBrowser( string url ) : base( 0xA5 ) + { + if ( url == null ) url = ""; + + this.EnsureCapacity( 4 + url.Length ); + + m_Stream.WriteAsciiNull( url ); + } + } + + public sealed class MessageLocalized : Packet + { + private static MessageLocalized[] m_Cache_IntLoc = new MessageLocalized[15000]; + private static MessageLocalized[] m_Cache_CliLoc = new MessageLocalized[100000]; + private static MessageLocalized[] m_Cache_CliLocCmp = new MessageLocalized[5000]; + + public static MessageLocalized InstantiateGeneric( int number ) + { + MessageLocalized[] cache = null; + int index = 0; + + if ( number >= 3000000 ) + { + cache = m_Cache_IntLoc; + index = number - 3000000; + } + else if ( number >= 1000000 ) + { + cache = m_Cache_CliLoc; + index = number - 1000000; + } + else if ( number >= 500000 ) + { + cache = m_Cache_CliLocCmp; + index = number - 500000; + } + + MessageLocalized p; + + if ( cache != null && index >= 0 && index < cache.Length ) + { + p = cache[index]; + + if ( p == null ) + { + cache[index] = p = new MessageLocalized( Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, number, "System", "" ); + p.SetStatic(); + } + } + else + { + p = new MessageLocalized( Serial.MinusOne, -1, MessageType.Regular, 0x3B2, 3, number, "System", "" ); + } + + return p; + } + + public MessageLocalized( Serial serial, int graphic, MessageType type, int hue, int font, int number, string name, string args ) : base( 0xC1 ) + { + if ( name == null ) name = ""; + if ( args == null ) args = ""; + + if ( hue == 0 ) + hue = 0x3B2; + + this.EnsureCapacity( 50 + (args.Length * 2) ); + + m_Stream.Write( (int) serial ); + m_Stream.Write( (short) graphic ); + m_Stream.Write( (byte) type ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (short) font ); + m_Stream.Write( (int) number ); + m_Stream.WriteAsciiFixed( name, 30 ); + m_Stream.WriteLittleUniNull( args ); + } + } + + public sealed class MobileMoving : Packet + { + public MobileMoving( Mobile m, int noto, Mobile receiver ) : base( 0x77, 17 ) + { + Point3D loc = m.Location; + + //int hue = m.Hue; + int hue = receiver.GetHue(m); // Scriptiz : hallucinations + + if ( m.SolidHueOverride >= 0 ) + hue = m.SolidHueOverride; + + m_Stream.Write( (int) m.Serial ); + //m_Stream.Write( (short) m.Body ); + m_Stream.Write((short)receiver.GetBody(m)); // Scriptiz : hallucinations + m_Stream.Write( (short) loc.m_X ); + m_Stream.Write( (short) loc.m_Y ); + m_Stream.Write( (sbyte) loc.m_Z ); + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (byte) m.GetPacketFlags() ); + m_Stream.Write( (byte) noto ); + } + } + + // Pre-7.0.0.0 Mobile Moving + public sealed class MobileMovingOld : Packet + { + public MobileMovingOld( Mobile m, int noto, Mobile receiver ) : base( 0x77, 17 ) + { + Point3D loc = m.Location; + + //int hue = m.Hue; + int hue = receiver.GetHue(m); // Scriptiz : hallucinations + + if ( m.SolidHueOverride >= 0 ) + hue = m.SolidHueOverride; + + m_Stream.Write( (int) m.Serial ); + //m_Stream.Write( (short) m.Body ); + m_Stream.Write((short)receiver.GetBody(m)); // Scriptiz : hallucinations + m_Stream.Write( (short) loc.m_X ); + m_Stream.Write( (short) loc.m_Y ); + m_Stream.Write( (sbyte) loc.m_Z ); + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (byte) m.GetOldPacketFlags() ); + m_Stream.Write( (byte) noto ); + } + } + + public sealed class MultiTargetReqHS : Packet + { + public MultiTargetReqHS( MultiTarget t ) : base( 0x99, 30 ) + { + m_Stream.Write( (bool) t.AllowGround ); + m_Stream.Write( (int) t.TargetID ); + m_Stream.Write( (byte) t.Flags ); + + m_Stream.Fill(); + + m_Stream.Seek( 18, SeekOrigin.Begin ); + m_Stream.Write( (short) t.MultiID ); + m_Stream.Write( (short) t.Offset.X ); + m_Stream.Write( (short) t.Offset.Y ); + m_Stream.Write( (short) t.Offset.Z ); + } + } + + public sealed class MultiTargetReq : Packet + { + public MultiTargetReq( MultiTarget t ) : base( 0x99, 26 ) + { + m_Stream.Write( (bool) t.AllowGround ); + m_Stream.Write( (int) t.TargetID ); + m_Stream.Write( (byte) t.Flags ); + + m_Stream.Fill(); + + m_Stream.Seek( 18, SeekOrigin.Begin ); + m_Stream.Write( (short) t.MultiID ); + m_Stream.Write( (short) t.Offset.X ); + m_Stream.Write( (short) t.Offset.Y ); + m_Stream.Write( (short) t.Offset.Z ); + } + } + + public sealed class CancelTarget : Packet + { + public static readonly Packet Instance = Packet.SetStatic( new CancelTarget() ); + + public CancelTarget() : base( 0x6C, 19 ) + { + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (int) 0 ); + m_Stream.Write( (byte) 3 ); + m_Stream.Fill(); + } + } + + public sealed class TargetReq : Packet + { + public TargetReq( Target t ) : base( 0x6C, 19 ) + { + m_Stream.Write( (bool) t.AllowGround ); + m_Stream.Write( (int) t.TargetID ); + m_Stream.Write( (byte) t.Flags ); + m_Stream.Fill(); + } + } + + public sealed class DragEffect : Packet + { + public DragEffect( IEntity src, IEntity trg, int itemID, int hue, int amount ) : base( 0x23, 26 ) + { + m_Stream.Write( (short) itemID ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (short) amount ); + m_Stream.Write( (int) src.Serial ); + m_Stream.Write( (short) src.X ); + m_Stream.Write( (short) src.Y ); + m_Stream.Write( (sbyte) src.Z ); + m_Stream.Write( (int) trg.Serial ); + m_Stream.Write( (short) trg.X ); + m_Stream.Write( (short) trg.Y ); + m_Stream.Write( (sbyte) trg.Z ); + } + } + + public interface IGumpWriter + { + int TextEntries { get; set; } + int Switches { get; set; } + + void AppendLayout( bool val ); + void AppendLayout( int val ); + void AppendLayoutNS( int val ); + void AppendLayout( string text ); + void AppendLayout( byte[] buffer ); + void WriteStrings( List strings ); + void Flush(); + } + + public sealed class DisplayGumpPacked : Packet, IGumpWriter + { + private int m_TextEntries, m_Switches; + + public int TextEntries { get { return m_TextEntries; } set { m_TextEntries = value; } } + public int Switches { get { return m_Switches; } set { m_Switches = value; } } + + private Gump m_Gump; + + private PacketWriter m_Layout; + private PacketWriter m_Strings; + + private int m_StringCount; + + public DisplayGumpPacked( Gump gump ) + : base( 0xDD ) + { + m_Gump = gump; + + m_Layout = PacketWriter.CreateInstance( 8192 ); + m_Strings = PacketWriter.CreateInstance( 8192 ); + } + + private static byte[] m_True = Gump.StringToBuffer( " 1" ); + private static byte[] m_False = Gump.StringToBuffer( " 0" ); + + private static byte[] m_BeginTextSeparator = Gump.StringToBuffer( " @" ); + private static byte[] m_EndTextSeparator = Gump.StringToBuffer( "@" ); + + private static byte[] m_Buffer = new byte[48]; + + static DisplayGumpPacked() + { + m_Buffer[0] = (byte)' '; + } + + public void AppendLayout( bool val ) + { + AppendLayout( val ? m_True : m_False ); + } + + public void AppendLayout( int val ) + { + string toString = val.ToString(); + int bytes = System.Text.Encoding.ASCII.GetBytes( toString, 0, toString.Length, m_Buffer, 1 ) + 1; + + m_Layout.Write( m_Buffer, 0, bytes ); + } + + public void AppendLayoutNS( int val ) + { + string toString = val.ToString(); + int bytes = System.Text.Encoding.ASCII.GetBytes( toString, 0, toString.Length, m_Buffer, 1 ); + + m_Layout.Write( m_Buffer, 1, bytes ); + } + + public void AppendLayout( string text ) + { + AppendLayout( m_BeginTextSeparator ); + + m_Layout.WriteAsciiFixed( text, text.Length ); + + AppendLayout( m_EndTextSeparator ); + } + + public void AppendLayout( byte[] buffer ) + { + m_Layout.Write( buffer, 0, buffer.Length ); + } + + public void WriteStrings( List strings ) + { + m_StringCount = strings.Count; + + for ( int i = 0; i < strings.Count; ++i ) + { + string v = strings[i]; + + if ( v == null ) + v = String.Empty; + + m_Strings.Write( (ushort) v.Length ); + m_Strings.WriteBigUniFixed( v, v.Length ); + } + } + + public void Flush() + { + EnsureCapacity( 28 + (int) m_Layout.Length + (int) m_Strings.Length ); + + m_Stream.Write( (int) m_Gump.Serial ); + m_Stream.Write( (int) m_Gump.TypeID ); + m_Stream.Write( (int) m_Gump.X ); + m_Stream.Write( (int) m_Gump.Y ); + + // Note: layout MUST be null terminated (don't listen to krrios) + m_Layout.Write( (byte) 0 ); + WritePacked( m_Layout ); + + m_Stream.Write( (int) m_StringCount ); + + WritePacked( m_Strings ); + + PacketWriter.ReleaseInstance( m_Layout ); + PacketWriter.ReleaseInstance( m_Strings ); + } + + private static byte[] m_PackBuffer; + + private void WritePacked( PacketWriter src ) + { + byte[] buffer = src.UnderlyingStream.GetBuffer(); + int length = (int) src.Length; + + if ( length == 0 ) + { + m_Stream.Write( (int) 0 ); + return; + } + + int wantLength = 1 + ( ( buffer.Length * 1024 ) / 1000 ); + + wantLength += 4095; + wantLength &= ~4095; + + if ( m_PackBuffer == null || m_PackBuffer.Length < wantLength ) + m_PackBuffer = new byte[wantLength]; + + int packLength = m_PackBuffer.Length; + + Compression.Pack( m_PackBuffer, ref packLength, buffer, length, ZLibQuality.Default ); + + m_Stream.Write( (int) ( 4 + packLength ) ); + m_Stream.Write( (int) length ); + m_Stream.Write( m_PackBuffer, 0, packLength ); + } + } + + public sealed class DisplayGumpFast : Packet, IGumpWriter + { + private int m_TextEntries, m_Switches; + + private int m_LayoutLength; + + public int TextEntries{ get{ return m_TextEntries; } set{ m_TextEntries = value; } } + public int Switches{ get{ return m_Switches; } set{ m_Switches = value; } } + + public DisplayGumpFast( Gump g ) : base( 0xB0 ) + { + EnsureCapacity( 4096 ); + + m_Stream.Write( (int) g.Serial ); + m_Stream.Write( (int) g.TypeID ); + m_Stream.Write( (int) g.X ); + m_Stream.Write( (int) g.Y ); + m_Stream.Write( (ushort) 0xFFFF ); + } + + private static byte[] m_True = Gump.StringToBuffer( " 1" ); + private static byte[] m_False = Gump.StringToBuffer( " 0" ); + + private static byte[] m_BeginTextSeparator = Gump.StringToBuffer( " @" ); + private static byte[] m_EndTextSeparator = Gump.StringToBuffer( "@" ); + + private static byte[] m_Buffer = new byte[48]; + + static DisplayGumpFast() + { + m_Buffer[0] = (byte)' '; + } + + public void AppendLayout( bool val ) + { + AppendLayout( val ? m_True : m_False ); + } + + public void AppendLayout( int val ) + { + string toString = val.ToString(); + int bytes = System.Text.Encoding.ASCII.GetBytes( toString, 0, toString.Length, m_Buffer, 1 ) + 1; + + m_Stream.Write( m_Buffer, 0, bytes ); + m_LayoutLength += bytes; + } + + public void AppendLayoutNS( int val ) + { + string toString = val.ToString(); + int bytes = System.Text.Encoding.ASCII.GetBytes( toString, 0, toString.Length, m_Buffer, 1 ); + + m_Stream.Write( m_Buffer, 1, bytes ); + m_LayoutLength += bytes; + } + + public void AppendLayout( string text ) + { + AppendLayout( m_BeginTextSeparator ); + + int length = text.Length; + m_Stream.WriteAsciiFixed( text, length ); + m_LayoutLength += length; + + AppendLayout( m_EndTextSeparator ); + } + + public void AppendLayout( byte[] buffer ) + { + int length = buffer.Length; + m_Stream.Write( buffer, 0, length ); + m_LayoutLength += length; + } + + public void WriteStrings( List text ) + { + m_Stream.Seek( 19, SeekOrigin.Begin ); + m_Stream.Write( (ushort) m_LayoutLength ); + m_Stream.Seek( 0, SeekOrigin.End ); + + m_Stream.Write( (ushort) text.Count ); + + for ( int i = 0; i < text.Count; ++i ) + { + string v = text[i]; + + if ( v == null ) + v = String.Empty; + + int length = (ushort) v.Length; + + m_Stream.Write( (ushort) length ); + m_Stream.WriteBigUniFixed( v, length ); + } + } + + public void Flush() + { + } + } + + public sealed class DisplayGump : Packet + { + public DisplayGump( Gump g, string layout, string[] text ) : base( 0xB0 ) + { + if ( layout == null ) layout = ""; + + this.EnsureCapacity( 256 ); + + m_Stream.Write( (int) g.Serial ); + m_Stream.Write( (int) g.TypeID ); + m_Stream.Write( (int) g.X ); + m_Stream.Write( (int) g.Y ); + m_Stream.Write( (ushort) (layout.Length + 1) ); + m_Stream.WriteAsciiNull( layout ); + + m_Stream.Write( (ushort) text.Length ); + + for ( int i = 0; i < text.Length; ++i ) + { + string v = text[i]; + + if ( v == null ) v = ""; + + int length = (ushort) v.Length; + + m_Stream.Write( (ushort) length ); + m_Stream.WriteBigUniFixed( v, length ); + } + } + } + + public sealed class DisplayPaperdoll : Packet + { + public DisplayPaperdoll( Mobile m, string text, bool canLift ) : base( 0x88, 66 ) + { + byte flags = 0x00; + + if ( m.Warmode ) + flags |= 0x01; + + if ( canLift ) + flags |= 0x02; + + m_Stream.Write( (int) m.Serial ); + m_Stream.WriteAsciiFixed( text, 60 ); + m_Stream.Write( (byte) flags ); + } + } + + public sealed class PopupMessage : Packet + { + public PopupMessage( PMMessage msg ) : base( 0x53, 2 ) + { + m_Stream.Write( (byte)msg ); + } + } + + public sealed class PlaySound : Packet + { + public PlaySound( int soundID, IPoint3D target ) : base( 0x54, 12 ) + { + m_Stream.Write( (byte) 1 ); // flags + m_Stream.Write( (short) soundID ); + m_Stream.Write( (short) 0 ); // volume + m_Stream.Write( (short) target.X ); + m_Stream.Write( (short) target.Y ); + m_Stream.Write( (short) target.Z ); + } + } + + public sealed class PlayMusic : Packet + { + public static readonly Packet InvalidInstance = Packet.SetStatic( new PlayMusic( MusicName.Invalid ) ); + + private static Packet[] m_Instances = new Packet[60]; + + public static Packet GetInstance( MusicName name ) + { + if ( name == MusicName.Invalid ) + return InvalidInstance; + + int v = (int)name; + Packet p; + + if ( v >= 0 && v < m_Instances.Length ) + { + p = m_Instances[v]; + + if ( p == null ) + m_Instances[v] = p = Packet.SetStatic( new PlayMusic( name ) ); + } + else + { + p = new PlayMusic( name ); + } + + return p; + } + + public PlayMusic( MusicName name ) : base( 0x6D, 3 ) + { + m_Stream.Write( (short)name ); + } + } + + public sealed class ScrollMessage : Packet + { + public ScrollMessage( int type, int tip, string text ) : base( 0xA6 ) + { + if ( text == null ) text = ""; + + this.EnsureCapacity( 10 + text.Length ); + + m_Stream.Write( (byte) type ); + m_Stream.Write( (int) tip ); + m_Stream.Write( (ushort) text.Length ); + m_Stream.WriteAsciiFixed( text, text.Length ); + } + } + + public sealed class CurrentTime : Packet + { + public CurrentTime() : base( 0x5B, 4 ) + { + DateTime now = DateTime.Now; + + m_Stream.Write( (byte) now.Hour ); + m_Stream.Write( (byte) now.Minute ); + m_Stream.Write( (byte) now.Second ); + } + } + + public sealed class MapChange : Packet + { + public MapChange( Mobile m ) : base( 0xBF ) + { + this.EnsureCapacity( 6 ); + + m_Stream.Write( (short) 0x08 ); + m_Stream.Write( (byte) (m.Map == null ? 0 : m.Map.MapID) ); + } + } + + public sealed class SeasonChange : Packet + { + private static SeasonChange[][] m_Cache = new SeasonChange[5][] + { + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2], + new SeasonChange[2] + }; + + public static SeasonChange Instantiate( int season ) + { + return Instantiate( season, true ); + } + + public static SeasonChange Instantiate( int season, bool playSound ) + { + if ( season >= 0 && season < m_Cache.Length ) + { + int idx = playSound ? 1 : 0; + + SeasonChange p = m_Cache[season][idx]; + + if ( p == null ) + { + m_Cache[season][idx] = p = new SeasonChange( season, playSound ); + p.SetStatic(); + } + + return p; + } + else + { + return new SeasonChange( season, playSound ); + } + } + + public SeasonChange( int season ) : this( season, true ) + { + } + + public SeasonChange( int season, bool playSound ) : base( 0xBC, 3 ) + { + m_Stream.Write( (byte) season ); + m_Stream.Write( (bool) playSound ); + } + } + + public sealed class SupportedFeatures : Packet + { + private static FeatureFlags m_AdditionalFlags; + + public static FeatureFlags Value{ get{ return m_AdditionalFlags; } set{ m_AdditionalFlags = value; } } + + public static SupportedFeatures Instantiate( NetState ns ) + { + return new SupportedFeatures( ns ); + } + + public SupportedFeatures( NetState ns ) : base( 0xB9, ns.ExtendedSupportedFeatures ? 5 : 3 ) + { + FeatureFlags flags = ExpansionInfo.CurrentExpansion.SupportedFeatures; + + flags |= m_AdditionalFlags; + + IAccount acct = ns.Account as IAccount; + + if ( acct != null && acct.Limit >= 6 ) + { + flags |= FeatureFlags.Unk7; + flags &= ~FeatureFlags.UOTD; + + if ( acct.Limit > 6 ) + flags |= FeatureFlags.SeventhCharacterSlot; + else + flags |= FeatureFlags.SixthCharacterSlot; + } + + if ( ns.ExtendedSupportedFeatures ) { + m_Stream.Write( (uint) flags ); + } else { + m_Stream.Write( (ushort) flags ); + } + } + } + + public static class AttributeNormalizer + { + private static int m_Maximum = 25; + private static bool m_Enabled = true; + + public static int Maximum + { + get{ return m_Maximum; } + set{ m_Maximum = value; } + } + + public static bool Enabled + { + get{ return m_Enabled; } + set{ m_Enabled = value; } + } + + public static void Write( PacketWriter stream, int cur, int max ) + { + if ( m_Enabled && max != 0 ) + { + stream.Write( (short) m_Maximum ); + stream.Write( (short) ((cur * m_Maximum) / max) ); + } + else + { + stream.Write( (short) max ); + stream.Write( (short) cur ); + } + } + + public static void WriteReverse( PacketWriter stream, int cur, int max ) + { + if ( m_Enabled && max != 0 ) + { + stream.Write( (short) ((cur * m_Maximum) / max) ); + stream.Write( (short) m_Maximum ); + } + else + { + stream.Write( (short) cur ); + stream.Write( (short) max ); + } + } + } + + public sealed class MobileHits : Packet + { + public MobileHits( Mobile m ) : base( 0xA1, 9 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) m.HitsMax ); + m_Stream.Write( (short) m.Hits ); + } + } + + public sealed class MobileHitsN : Packet + { + public MobileHitsN( Mobile m ) : base( 0xA1, 9 ) + { + m_Stream.Write( (int) m.Serial ); + AttributeNormalizer.Write( m_Stream, m.Hits, m.HitsMax ); + } + } + + public sealed class MobileMana : Packet + { + public MobileMana( Mobile m ) : base( 0xA2, 9 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) m.ManaMax ); + m_Stream.Write( (short) m.Mana ); + } + } + + public sealed class MobileManaN : Packet + { + public MobileManaN( Mobile m ) : base( 0xA2, 9 ) + { + m_Stream.Write( (int) m.Serial ); + AttributeNormalizer.Write( m_Stream, m.Mana, m.ManaMax ); + } + } + + public sealed class MobileStam : Packet + { + public MobileStam( Mobile m ) : base( 0xA3, 9 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) m.StamMax ); + m_Stream.Write( (short) m.Stam ); + } + } + + public sealed class MobileStamN : Packet + { + public MobileStamN( Mobile m ) : base( 0xA3, 9 ) + { + m_Stream.Write( (int) m.Serial ); + AttributeNormalizer.Write( m_Stream, m.Stam, m.StamMax ); + } + } + + public sealed class MobileAttributes : Packet + { + public MobileAttributes( Mobile m ) : base( 0x2D, 17 ) + { + m_Stream.Write( m.Serial ); + + m_Stream.Write( (short) m.HitsMax ); + m_Stream.Write( (short) m.Hits ); + + m_Stream.Write( (short) m.ManaMax ); + m_Stream.Write( (short) m.Mana ); + + m_Stream.Write( (short) m.StamMax ); + m_Stream.Write( (short) m.Stam ); + } + } + + public sealed class MobileAttributesN : Packet + { + public MobileAttributesN( Mobile m ) : base( 0x2D, 17 ) + { + m_Stream.Write( m.Serial ); + + AttributeNormalizer.Write( m_Stream, m.Hits, m.HitsMax ); + AttributeNormalizer.Write( m_Stream, m.Mana, m.ManaMax ); + AttributeNormalizer.Write( m_Stream, m.Stam, m.StamMax ); + } + } + + public sealed class PathfindMessage : Packet + { + public PathfindMessage( IPoint3D p ) : base( 0x38, 7 ) + { + m_Stream.Write( (short) p.X ); + m_Stream.Write( (short) p.Y ); + m_Stream.Write( (short) p.Z ); + } + } + + // unsure of proper format, client crashes + public sealed class MobileName : Packet + { + public MobileName( Mobile m ) : base( 0x98 ) + { + string name = m.Name; + + if ( name == null ) name = ""; + + this.EnsureCapacity( 37 ); + + m_Stream.Write( (int) m.Serial ); + m_Stream.WriteAsciiFixed( name, 30 ); + } + } + + public sealed class MobileAnimation : Packet + { + public MobileAnimation( Mobile m, int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay ) : base( 0x6E, 14 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) action ); + m_Stream.Write( (short) frameCount ); + m_Stream.Write( (short) repeatCount ); + m_Stream.Write( (bool) !forward ); // protocol has really "reverse" but I find this more intuitive + m_Stream.Write( (bool) repeat ); + m_Stream.Write( (byte) delay ); + } + } + + public sealed class NewMobileAnimation : Packet + { + public NewMobileAnimation( Mobile m, int action, int frameCount, int delay ) : base( 0xE2, 10 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) action ); + m_Stream.Write( (short) frameCount ); + m_Stream.Write( (byte) delay ); + } + } + + public sealed class MobileStatusCompact : Packet + { + public MobileStatusCompact( bool canBeRenamed, Mobile m ) : base( 0x11 ) + { + string name = m.Name; + if ( name == null ) name = ""; + + this.EnsureCapacity( 43 ); + + m_Stream.Write( (int) m.Serial ); + m_Stream.WriteAsciiFixed( name, 30 ); + + AttributeNormalizer.WriteReverse( m_Stream, m.Hits, m.HitsMax ); + + m_Stream.Write( canBeRenamed ); + + m_Stream.Write( (byte) 0 ); // type + } + } + + public sealed class MobileStatusExtended : Packet + { + public MobileStatusExtended( Mobile m ) : this( m, m.NetState ) + { + } + + public MobileStatusExtended( Mobile m, NetState ns ) : base( 0x11 ) + { + string name = m.Name; + if ( name == null ) name = ""; + + int type; + + if (Core.HS && ns != null && ns.ExtendedStatus) + { + type = 6; + EnsureCapacity(121); + } + else if (Core.ML && ns != null && ns.SupportsExpansion(Expansion.ML)) + { + type = 5; + EnsureCapacity(91); + } + else + { + type = Core.AOS ? 4 : 3; + EnsureCapacity(88); + } + + m_Stream.Write( (int) m.Serial ); + m_Stream.WriteAsciiFixed( name, 30 ); + + m_Stream.Write( (short) m.Hits ); + m_Stream.Write( (short) m.HitsMax ); + + m_Stream.Write( m.CanBeRenamedBy( m ) ); + + m_Stream.Write((byte)type); + + m_Stream.Write( m.Female ); + + m_Stream.Write( (short) m.Str ); + m_Stream.Write( (short) m.Dex ); + m_Stream.Write( (short) m.Int ); + + m_Stream.Write( (short) m.Stam ); + m_Stream.Write( (short) m.StamMax ); + + m_Stream.Write( (short) m.Mana ); + m_Stream.Write( (short) m.ManaMax ); + + m_Stream.Write( (int) m.TotalGold ); + m_Stream.Write( (short) (Core.AOS ? m.PhysicalResistance : (int)(m.ArmorRating + 0.5)) ); + m_Stream.Write( (short) (Mobile.BodyWeight + m.TotalWeight) ); + + if (type >= 5) + { + m_Stream.Write( (short)m.MaxWeight ); + m_Stream.Write( (byte)(m.Race.RaceID + 1)); // Would be 0x00 if it's a non-ML enabled account but... + } + + m_Stream.Write( (short) m.StatCap ); + + m_Stream.Write( (byte) m.Followers ); + m_Stream.Write( (byte) m.FollowersMax ); + + if (type >= 4) + { + m_Stream.Write( (short) m.FireResistance ); // Fire + m_Stream.Write( (short) m.ColdResistance ); // Cold + m_Stream.Write( (short) m.PoisonResistance ); // Poison + m_Stream.Write( (short) m.EnergyResistance ); // Energy + m_Stream.Write( (short) m.Luck ); // Luck + + IWeapon weapon = m.Weapon; + + int min = 0, max = 0; + + if ( weapon != null ) + weapon.GetStatusDamage( m, out min, out max ); + + m_Stream.Write( (short) min ); // Damage min + m_Stream.Write( (short) max ); // Damage max + + m_Stream.Write( (int) m.TithingPoints ); + } + + if (type >= 6) + { + for (int i = 0; i < 15; ++i) + m_Stream.Write((short)m.GetAOSStatus(i)); + } + } + } + + public sealed class MobileStatus : Packet + { + public MobileStatus( Mobile beholder, Mobile beheld ) : this( beholder, beheld, beheld.NetState ) + { + } + + public MobileStatus( Mobile beholder, Mobile beheld, NetState ns ) : base( 0x11 ) + { + string name = beheld.Name; + if ( name == null ) name = ""; + + int type; + + if (beholder != beheld) + { + type = 0; + EnsureCapacity(43); + } + else if (Core.HS && ns != null && ns.ExtendedStatus) + { + type = 6; + EnsureCapacity(121); + } + else if (Core.ML && ns != null && ns.SupportsExpansion(Expansion.ML)) + { + type = 5; + EnsureCapacity(91); + } + else + { + type = Core.AOS ? 4 : 3; + EnsureCapacity(88); + } + + m_Stream.Write( beheld.Serial ); + + m_Stream.WriteAsciiFixed( name, 30 ); + + if ( beholder == beheld ) + WriteAttr( beheld.Hits, beheld.HitsMax ); + else + WriteAttrNorm( beheld.Hits, beheld.HitsMax ); + + m_Stream.Write( beheld.CanBeRenamedBy( beholder ) ); + + m_Stream.Write((byte)type); + + if (type > 0) + { + + m_Stream.Write( beheld.Female ); + + m_Stream.Write( (short) beheld.Str ); + m_Stream.Write( (short) beheld.Dex ); + m_Stream.Write( (short) beheld.Int ); + + WriteAttr( beheld.Stam, beheld.StamMax ); + WriteAttr( beheld.Mana, beheld.ManaMax ); + + m_Stream.Write( (int) beheld.TotalGold ); + m_Stream.Write( (short) (Core.AOS ? beheld.PhysicalResistance : (int)(beheld.ArmorRating + 0.5)) ); + m_Stream.Write( (short) (Mobile.BodyWeight + beheld.TotalWeight) ); + + if (type >= 5) + { + m_Stream.Write( (short)beheld.MaxWeight ); + m_Stream.Write( (byte)(beheld.Race.RaceID + 1) ); // Would be 0x00 if it's a non-ML enabled account but... + } + + m_Stream.Write( (short) beheld.StatCap ); + + m_Stream.Write( (byte) beheld.Followers ); + m_Stream.Write( (byte) beheld.FollowersMax ); + + if (type >= 4) + { + m_Stream.Write( (short) beheld.FireResistance ); // Fire + m_Stream.Write( (short) beheld.ColdResistance ); // Cold + m_Stream.Write( (short) beheld.PoisonResistance ); // Poison + m_Stream.Write( (short) beheld.EnergyResistance ); // Energy + m_Stream.Write( (short) beheld.Luck ); // Luck + + IWeapon weapon = beheld.Weapon; + + int min = 0, max = 0; + + if ( weapon != null ) + weapon.GetStatusDamage( beheld, out min, out max ); + + m_Stream.Write( (short) min ); // Damage min + m_Stream.Write( (short) max ); // Damage max + + m_Stream.Write( (int) beheld.TithingPoints ); + } + + if ( type >= 6 ) + { + for ( int i = 0; i < 15; ++i ) + m_Stream.Write( (short) beheld.GetAOSStatus( i ) ); + } + } + } + + private void WriteAttr( int current, int maximum ) + { + m_Stream.Write( (short) current ); + m_Stream.Write( (short) maximum ); + } + + private void WriteAttrNorm( int current, int maximum ) + { + AttributeNormalizer.WriteReverse( m_Stream, current, maximum ); + } + } + + public sealed class HealthbarPoison : Packet + { + public HealthbarPoison( Mobile m ) : base( 0x17 ) + { + EnsureCapacity( 12 ); + + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) 1 ); + + m_Stream.Write( (short) 1 ); + + Poison p = m.Poison; + + if ( p != null ) { + m_Stream.Write( (byte) (p.Level + 1) ); + } else { + m_Stream.Write( (byte) 0 ); + } + } + } + + public sealed class HealthbarYellow : Packet + { + public HealthbarYellow( Mobile m ) : base( 0x17 ) + { + EnsureCapacity( 12 ); + + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (short) 1 ); + + m_Stream.Write( (short) 2 ); + + if ( m.Blessed || m.YellowHealthbar ) { + m_Stream.Write( (byte) 1 ); + } else { + m_Stream.Write( (byte) 0 ); + } + } + } + + public sealed class MobileUpdate : Packet + { + public MobileUpdate( Mobile m ) : base( 0x20, 19 ) + { + //int hue = m.Hue; + int hue = m.GetHue(m); // Scriptiz : hallucinations + + if ( m.SolidHueOverride >= 0 ) + hue = m.SolidHueOverride; + + m_Stream.Write( (int) m.Serial ); + //m_Stream.Write( (short) m.Body ); + m_Stream.Write((short)m.GetBody(m)); // Scriptiz : hallucinations + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (byte) m.GetPacketFlags() ); + m_Stream.Write( (short) m.X ); + m_Stream.Write( (short) m.Y ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (sbyte) m.Z ); + } + } + + // Pre-7.0.0.0 Mobile Update + public sealed class MobileUpdateOld : Packet + { + public MobileUpdateOld( Mobile m ) : base( 0x20, 19 ) + { + //int hue = m.Hue; + int hue = m.GetHue(m); // Scriptiz : hallucinations + + if ( m.SolidHueOverride >= 0 ) + hue = m.SolidHueOverride; + + m_Stream.Write( (int) m.Serial ); + //m_Stream.Write( (short) m.Body ); + m_Stream.Write((short)m.GetBody(m)); // Scriptiz : hallucinations + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (byte) m.GetOldPacketFlags() ); + m_Stream.Write( (short) m.X ); + m_Stream.Write( (short) m.Y ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (sbyte) m.Z ); + } + } + + public sealed class MobileIncoming : Packet + { + public static Packet Create(NetState ns, Mobile beholder, Mobile beheld) + { + if (ns.NewMobileIncoming) + return new MobileIncoming(beholder, beheld); + else if (ns.StygianAbyss) + return new MobileIncomingSA(beholder, beheld); + else + return new MobileIncomingOld(beholder, beheld); + } + +#if Framework_4_0 + private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => {return new int[256];}); + private static ThreadLocal m_VersionTL = new ThreadLocal(); +#else + private static int[] m_DupedLayers = new int[256]; + private static int m_Version; +#endif + + public Mobile m_Beheld; + + public MobileIncoming(Mobile beholder, Mobile beheld) + : base(0x78) + { + m_Beheld = beheld; + +#if Framework_4_0 + int m_Version = ++(m_VersionTL.Value); + int[] m_DupedLayers = m_DupedLayersTL.Value; +#else + ++m_Version; +#endif + + List eq = beheld.Items; + int count = eq.Count; + + if (beheld.HairItemID > 0) + count++; + if (beheld.FacialHairItemID > 0) + count++; + + this.EnsureCapacity(23 + (count * 9)); + + int hue = beheld.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + m_Stream.Write((int)beheld.Serial); + m_Stream.Write((short)beheld.Body); + m_Stream.Write((short)beheld.X); + m_Stream.Write((short)beheld.Y); + m_Stream.Write((sbyte)beheld.Z); + m_Stream.Write((byte)beheld.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)beheld.GetPacketFlags()); + m_Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + for (int i = 0; i < eq.Count; ++i) + { + Item item = eq[i]; + + byte layer = (byte)item.Layer; + + if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = item.ItemID & 0xFFFF; + + m_Stream.Write((int)item.Serial); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)layer); + + m_Stream.Write((short)hue); + } + } + + if (beheld.HairItemID > 0) + { + if (m_DupedLayers[(int)Layer.Hair] != m_Version) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.HairItemID & 0xFFFF; + + m_Stream.Write((int)HairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.Hair); + + m_Stream.Write((short)hue); + } + } + + if (beheld.FacialHairItemID > 0) + { + if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.FacialHairItemID & 0xFFFF; + + m_Stream.Write((int)FacialHairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.FacialHair); + + m_Stream.Write((short)hue); + } + } + + m_Stream.Write((int)0); // terminate + } + } + + public sealed class MobileIncomingSA : Packet + { +#if Framework_4_0 + private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => {return new int[256];}); + private static ThreadLocal m_VersionTL = new ThreadLocal(); +#else + private static int[] m_DupedLayers = new int[256]; + private static int m_Version; +#endif + + public Mobile m_Beheld; + + public MobileIncomingSA(Mobile beholder, Mobile beheld) + : base(0x78) + { + m_Beheld = beheld; + +#if Framework_4_0 + int m_Version = ++(m_VersionTL.Value); + int[] m_DupedLayers = m_DupedLayersTL.Value; +#else + ++m_Version; +#endif + List eq = beheld.Items; + int count = eq.Count; + + if (beheld.HairItemID > 0) + count++; + if (beheld.FacialHairItemID > 0) + count++; + + this.EnsureCapacity(23 + (count * 9)); + + //int hue = beheld.Hue; + int hue = beholder.GetHue(beheld); // Scriptiz : hallucinations + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + m_Stream.Write((int)beheld.Serial); + //m_Stream.Write( (short) beheld.Body ); + m_Stream.Write((short)beholder.GetBody(beheld)); // Scriptiz : hallucinations + m_Stream.Write((short)beheld.X); + m_Stream.Write((short)beheld.Y); + m_Stream.Write((sbyte)beheld.Z); + m_Stream.Write((byte)beheld.Direction); + m_Stream.Write((short)hue); + m_Stream.Write((byte)beheld.GetPacketFlags()); + m_Stream.Write((byte)Notoriety.Compute(beholder, beheld)); + + for (int i = 0; i < eq.Count; ++i) + { + Item item = eq[i]; + + byte layer = (byte)item.Layer; + + if (!item.Deleted && beholder.CanSee(item) && m_DupedLayers[layer] != m_Version) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = item.ItemID & 0x7FFF; + bool writeHue = (hue != 0); + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write((int)item.Serial); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)layer); + + if (writeHue) + m_Stream.Write((short)hue); + } + } + + if (beheld.HairItemID > 0) + { + if (m_DupedLayers[(int)Layer.Hair] != m_Version) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.HairItemID & 0x7FFF; + + bool writeHue = (hue != 0); + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write((int)HairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.Hair); + + if (writeHue) + m_Stream.Write((short)hue); + } + } + + if (beheld.FacialHairItemID > 0) + { + if (m_DupedLayers[(int)Layer.FacialHair] != m_Version) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if (beheld.SolidHueOverride >= 0) + hue = beheld.SolidHueOverride; + + int itemID = beheld.FacialHairItemID & 0x7FFF; + + bool writeHue = (hue != 0); + + if (writeHue) + itemID |= 0x8000; + + m_Stream.Write((int)FacialHairInfo.FakeSerial(beheld)); + m_Stream.Write((ushort)itemID); + m_Stream.Write((byte)Layer.FacialHair); + + if (writeHue) + m_Stream.Write((short)hue); + } + } + + m_Stream.Write((int)0); // terminate + } + } + + // Pre-7.0.0.0 Mobile Incoming + public sealed class MobileIncomingOld : Packet + { + #if Framework_4_0 + private static ThreadLocal m_DupedLayersTL = new ThreadLocal(() => {return new int[256];}); + private static ThreadLocal m_VersionTL = new ThreadLocal(); + #else + private static int[] m_DupedLayers = new int[256]; + private static int m_Version; + #endif + + public Mobile m_Beheld; + + public MobileIncomingOld( Mobile beholder, Mobile beheld ) : base( 0x78 ) + { + m_Beheld = beheld; + + #if Framework_4_0 + int m_Version = ++(m_VersionTL.Value); + int[] m_DupedLayers = m_DupedLayersTL.Value; + #else + ++m_Version; + #endif + + List eq = beheld.Items; + int count = eq.Count; + + if( beheld.HairItemID > 0 ) + count++; + if( beheld.FacialHairItemID > 0 ) + count++; + + this.EnsureCapacity( 23 + (count * 9) ); + + int hue = beheld.Hue; + + if ( beheld.SolidHueOverride >= 0 ) + hue = beheld.SolidHueOverride; + + m_Stream.Write( (int) beheld.Serial ); + m_Stream.Write( (short) beheld.Body ); + m_Stream.Write( (short) beheld.X ); + m_Stream.Write( (short) beheld.Y ); + m_Stream.Write( (sbyte) beheld.Z ); + m_Stream.Write( (byte) beheld.Direction ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (byte) beheld.GetOldPacketFlags() ); + m_Stream.Write( (byte) Notoriety.Compute( beholder, beheld ) ); + + for ( int i = 0; i < eq.Count; ++i ) + { + Item item = eq[i]; + + byte layer = (byte) item.Layer; + + if ( !item.Deleted && beholder.CanSee( item ) && m_DupedLayers[layer] != m_Version ) + { + m_DupedLayers[layer] = m_Version; + + hue = item.Hue; + + if ( beheld.SolidHueOverride >= 0 ) + hue = beheld.SolidHueOverride; + + int itemID = item.ItemID & 0x7FFF; + bool writeHue = ( hue != 0 ); + + if ( writeHue ) + itemID |= 0x8000; + + m_Stream.Write( (int) item.Serial ); + m_Stream.Write( (ushort) itemID ); + m_Stream.Write( (byte) layer ); + + if ( writeHue ) + m_Stream.Write( (short) hue ); + } + } + + if( beheld.HairItemID > 0 ) + { + if( m_DupedLayers[(int)Layer.Hair] != m_Version ) + { + m_DupedLayers[(int)Layer.Hair] = m_Version; + hue = beheld.HairHue; + + if( beheld.SolidHueOverride >= 0 ) + hue = beheld.SolidHueOverride; + + int itemID = beheld.HairItemID & 0x7FFF; + + bool writeHue = (hue != 0); + + if( writeHue ) + itemID |= 0x8000; + + m_Stream.Write( (int)HairInfo.FakeSerial( beheld ) ); + m_Stream.Write( (ushort)itemID ); + m_Stream.Write( (byte)Layer.Hair ); + + if( writeHue ) + m_Stream.Write( (short)hue ); + } + } + + if( beheld.FacialHairItemID > 0 ) + { + if( m_DupedLayers[(int)Layer.FacialHair] != m_Version ) + { + m_DupedLayers[(int)Layer.FacialHair] = m_Version; + hue = beheld.FacialHairHue; + + if( beheld.SolidHueOverride >= 0 ) + hue = beheld.SolidHueOverride; + + int itemID = beheld.FacialHairItemID & 0x7FFF; + + bool writeHue = (hue != 0); + + if( writeHue ) + itemID |= 0x8000; + + m_Stream.Write( (int)FacialHairInfo.FakeSerial( beheld ) ); + m_Stream.Write( (ushort)itemID ); + m_Stream.Write( (byte)Layer.FacialHair ); + + if( writeHue ) + m_Stream.Write( (short)hue ); + } + } + + m_Stream.Write( (int) 0 ); // terminate + } + } + + public sealed class AsciiMessage : Packet + { + public AsciiMessage( Serial serial, int graphic, MessageType type, int hue, int font, string name, string text ) : base( 0x1C ) + { + if ( name == null ) + name = ""; + + if ( text == null ) + text = ""; + + if ( hue == 0 ) + hue = 0x3B2; + + this.EnsureCapacity( 45 + text.Length ); + + m_Stream.Write( (int) serial ); + m_Stream.Write( (short) graphic ); + m_Stream.Write( (byte) type ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (short) font ); + m_Stream.WriteAsciiFixed( name, 30 ); + m_Stream.WriteAsciiNull( text ); + } + } + + public sealed class UnicodeMessage : Packet + { + public UnicodeMessage( Serial serial, int graphic, MessageType type, int hue, int font, string lang, string name, string text ) : base( 0xAE ) + { + if ( string.IsNullOrEmpty( lang ) ) lang = "ENU"; + if ( name == null ) name = ""; + if ( text == null ) text = ""; + + if ( hue == 0 ) + hue = 0x3B2; + + this.EnsureCapacity( 50 + (text.Length * 2) ); + + m_Stream.Write( (int) serial ); + m_Stream.Write( (short) graphic ); + m_Stream.Write( (byte) type ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (short) font ); + m_Stream.WriteAsciiFixed( lang, 4 ); + m_Stream.WriteAsciiFixed( name, 30 ); + m_Stream.WriteBigUniNull( text ); + } + } + + public sealed class PingAck : Packet + { + private static PingAck[] m_Cache = new PingAck[0x100]; + + public static PingAck Instantiate( byte ping ) + { + PingAck p = m_Cache[ping]; + + if ( p == null ) + { + m_Cache[ping] = p = new PingAck( ping ); + p.SetStatic(); + } + + return p; + } + + public PingAck( byte ping ) : base( 0x73, 2 ) + { + m_Stream.Write( ping ); + } + } + + public sealed class MovementRej : Packet + { + public MovementRej( int seq, Mobile m ) : base( 0x21, 8 ) + { + m_Stream.Write( (byte) seq ); + m_Stream.Write( (short) m.X ); + m_Stream.Write( (short) m.Y ); + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (sbyte) m.Z ); + } + } + + public sealed class MovementAck : Packet + { + private static MovementAck[][] m_Cache = new MovementAck[8][] + { + new MovementAck[256], + new MovementAck[256], + new MovementAck[256], + new MovementAck[256], + new MovementAck[256], + new MovementAck[256], + new MovementAck[256], + new MovementAck[256] + }; + + public static MovementAck Instantiate( int seq, Mobile m ) + { + int noto = Notoriety.Compute( m, m ); + + MovementAck p = m_Cache[noto][seq]; + + if ( p == null ) + { + m_Cache[noto][seq] = p = new MovementAck( seq, noto ); + p.SetStatic(); + } + + return p; + } + + private MovementAck( int seq, int noto ) : base( 0x22, 3 ) + { + m_Stream.Write( (byte) seq ); + m_Stream.Write( (byte) noto ); + } + } + + public sealed class LoginConfirm : Packet + { + public LoginConfirm( Mobile m ) : base( 0x1B, 37 ) + { + m_Stream.Write( (int) m.Serial ); + m_Stream.Write( (int) 0 ); + m_Stream.Write( (short) m.Body ); + m_Stream.Write( (short) m.X ); + m_Stream.Write( (short) m.Y ); + m_Stream.Write( (short) m.Z ); + m_Stream.Write( (byte) m.Direction ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (int) -1 ); + + Map map = m.Map; + + if ( map == null || map == Map.Internal ) + map = m.LogoutMap; + + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) 0 ); + m_Stream.Write( (short) (map==null?6144:map.Width) ); + m_Stream.Write( (short) (map==null?4096:map.Height) ); + + m_Stream.Fill(); + } + } + + public sealed class LoginComplete : Packet + { + public static readonly Packet Instance = Packet.SetStatic( new LoginComplete() ); + + public LoginComplete() : base( 0x55, 1 ) + { + } + } + + public sealed class CityInfo + { + private string m_City; + private string m_Building; + private int m_Description; + private Point3D m_Location; + private Map m_Map; + + public CityInfo(string city, string building, int description, int x, int y, int z, Map m) + { + m_City = city; + m_Building = building; + m_Description = description; + m_Location = new Point3D(x, y, z); + m_Map = m; + } + + public CityInfo(string city, string building, int x, int y, int z, Map m) + : this(city, building, 0, x, y, z, m) + { + } + + public CityInfo(string city, string building, int description, int x, int y, int z) + : this(city, building, description, x, y, z, Map.Trammel) + { + } + + public CityInfo(string city, string building, int x, int y, int z) + : this(city, building, 0, x, y, z, Map.Trammel) + { + } + + public string City + { + get + { + return m_City; + } + set + { + m_City = value; + } + } + + public string Building + { + get + { + return m_Building; + } + set + { + m_Building = value; + } + } + + public int Description + { + get + { + return m_Description; + } + set + { + m_Description = value; + } + } + + public int X + { + get + { + return m_Location.X; + } + set + { + m_Location.X = value; + } + } + + public int Y + { + get + { + return m_Location.Y; + } + set + { + m_Location.Y = value; + } + } + + public int Z + { + get + { + return m_Location.Z; + } + set + { + m_Location.Z = value; + } + } + + public Point3D Location + { + get + { + return m_Location; + } + set + { + m_Location = value; + } + } + + public Map Map + { + get { return m_Map; } + set { m_Map = value; } + } + } + + public sealed class CharacterListUpdate : Packet + { + public CharacterListUpdate(IAccount a) + : base(0x86) + { + this.EnsureCapacity(4 + (a.Length * 60)); + + int highSlot = -1; + + for (int i = 0; i < a.Length; ++i) + { + if (a[i] != null) + highSlot = i; + } + + int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); + + m_Stream.Write((byte)count); + + for (int i = 0; i < count; ++i) + { + Mobile m = a[i]; + + if (m != null) + { + m_Stream.WriteAsciiFixed(m.Name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + } + } + } + + [Flags] + public enum ThirdPartyFeature : ulong + { + FilterWeather = 1 << 0, + FilterLight = 1 << 1, + + SmartTarget = 1 << 2, + RangedTarget = 1 << 3, + + AutoOpenDoors = 1 << 4, + + DequipOnCast = 1 << 5, + AutoPotionEquip = 1 << 6, + + ProtectHeals = 1 << 7, + + LoopedMacros = 1 << 8, + + UseOnceAgent = 1 << 9, + RestockAgent = 1 << 10, + SellAgent = 1 << 11, + BuyAgent = 1 << 12, + + PotionHotkeys = 1 << 13, + + RandomTargets = 1 << 14, + ClosestTargets = 1 << 15, // All closest target hotkeys + OverheadHealth = 1 << 16, // Health and Mana/Stam messages shown over player's heads + AutolootAgent = 1 << 17, + BoneCutterAgent = 1 << 18, + AdvancedMacros = 1 << 19, + AutoRemount = 1 << 20, + AutoBandage = 1 << 21, + EnemyTargetShare = 1 << 22, + FilterSeason = 1 << 23, + SpellTargetShare = 1 << 24, + + All = ulong.MaxValue + } + + public static class FeatureProtection + { + private static ThirdPartyFeature m_Disabled = 0; + + public static ThirdPartyFeature DisabledFeatures + { + get { return m_Disabled; } + } + + public static void Disable(ThirdPartyFeature feature) + { + SetDisabled(feature, true); + } + + public static void Enable(ThirdPartyFeature feature) + { + SetDisabled(feature, false); + } + + public static void SetDisabled(ThirdPartyFeature feature, bool value) + { + if (value) + m_Disabled |= feature; + else + m_Disabled &= ~feature; + } + } + + public sealed class CharacterList : Packet + { + public CharacterList(IAccount a, CityInfo[] info) + : base(0xA9) + { + this.EnsureCapacity(11 + (a.Length * 60) + (info.Length * 89)); + + int highSlot = -1; + + for (int i = 0; i < a.Length; ++i) + { + if (a[i] != null) + highSlot = i; + } + + int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); + + m_Stream.Write((byte)count); + + for (int i = 0; i < count; ++i) + { + if (a[i] != null) + { + m_Stream.WriteAsciiFixed(a[i].Name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + } + + m_Stream.Write((byte)info.Length); + + for (int i = 0; i < info.Length; ++i) + { + CityInfo ci = info[i]; + + m_Stream.Write((byte)i); + m_Stream.WriteAsciiFixed(ci.City, 32); + m_Stream.WriteAsciiFixed(ci.Building, 32); + m_Stream.Write((int)ci.X); + m_Stream.Write((int)ci.Y); + m_Stream.Write((int)ci.Z); + m_Stream.Write((int)ci.Map.MapID); + m_Stream.Write((int)ci.Description); + m_Stream.Write((int)0); + } + + CharacterListFlags flags = ExpansionInfo.CurrentExpansion.CharacterListFlags; + + if (count > 6) + flags |= (CharacterListFlags.SeventhCharacterSlot | CharacterListFlags.SixthCharacterSlot); // 7th Character Slot - TODO: Is SixthCharacterSlot Required? + else if (count == 6) + flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot + else if (a.Limit == 1) + flags |= (CharacterListFlags.SlotLimit & CharacterListFlags.OneCharacterSlot); // Limit Characters & One Character + + m_Stream.Write((int)(flags | m_AdditionalFlags)); // Additional Flags + + m_Stream.Write((short)-1); + + ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; + + if (disabled != 0) + { + if (m_MD5Provider == null) + m_MD5Provider = new System.Security.Cryptography.MD5CryptoServiceProvider(); + + m_Stream.UnderlyingStream.Flush(); + + byte[] hashCode = m_MD5Provider.ComputeHash(m_Stream.UnderlyingStream.GetBuffer(), 0, (int)m_Stream.UnderlyingStream.Length); + byte[] buffer = new byte[28]; + + for (int i = 0; i < count; ++i) + { + Utility.RandomBytes(buffer); + + m_Stream.Seek(35 + (i * 60), SeekOrigin.Begin); + m_Stream.Write(buffer, 0, buffer.Length); + } + + m_Stream.Seek(35, SeekOrigin.Begin); + m_Stream.Write((int)((long)disabled >> 32)); + m_Stream.Write((int)disabled); + + m_Stream.Seek(95, SeekOrigin.Begin); + m_Stream.Write(hashCode, 0, hashCode.Length); + } + } + + private static System.Security.Cryptography.MD5CryptoServiceProvider m_MD5Provider; + + + private static CharacterListFlags m_AdditionalFlags; + + public static CharacterListFlags AdditionalFlags + { + get { return m_AdditionalFlags; } + set { m_AdditionalFlags = value; } + } + } + + public sealed class CharacterListOld : Packet + { + public CharacterListOld(IAccount a, CityInfo[] info) + : base(0xA9) + { + this.EnsureCapacity(9 + (a.Length * 60) + (info.Length * 63)); + + int highSlot = -1; + + for (int i = 0; i < a.Length; ++i) + { + if (a[i] != null) + highSlot = i; + } + + int count = Math.Max(Math.Max(highSlot + 1, a.Limit), 5); + + m_Stream.Write((byte)count); + + for (int i = 0; i < count; ++i) + { + if (a[i] != null) + { + m_Stream.WriteAsciiFixed(a[i].Name, 30); + m_Stream.Fill(30); // password + } + else + { + m_Stream.Fill(60); + } + } + + m_Stream.Write((byte)info.Length); + + for (int i = 0; i < info.Length; ++i) + { + CityInfo ci = info[i]; + + m_Stream.Write((byte)i); + m_Stream.WriteAsciiFixed(ci.City, 31); + m_Stream.WriteAsciiFixed(ci.Building, 31); + } + + CharacterListFlags flags = ExpansionInfo.CurrentExpansion.CharacterListFlags; + + if (count > 6) + flags |= (CharacterListFlags.SeventhCharacterSlot | CharacterListFlags.SixthCharacterSlot); // 7th Character Slot - TODO: Is SixthCharacterSlot Required? + else if (count == 6) + flags |= CharacterListFlags.SixthCharacterSlot; // 6th Character Slot + else if (a.Limit == 1) + flags |= (CharacterListFlags.SlotLimit & CharacterListFlags.OneCharacterSlot); // Limit Characters & One Character + + m_Stream.Write((int)(flags | CharacterList.AdditionalFlags)); // Additional Flags + ThirdPartyFeature disabled = FeatureProtection.DisabledFeatures; + + if (disabled != 0) + { + if (m_MD5Provider == null) + m_MD5Provider = new System.Security.Cryptography.MD5CryptoServiceProvider(); + + m_Stream.UnderlyingStream.Flush(); + + byte[] hashCode = m_MD5Provider.ComputeHash(m_Stream.UnderlyingStream.GetBuffer(), 0, (int)m_Stream.UnderlyingStream.Length); + byte[] buffer = new byte[28]; + + for (int i = 0; i < count; ++i) + { + Utility.RandomBytes(buffer); + + m_Stream.Seek(35 + (i * 60), SeekOrigin.Begin); + m_Stream.Write(buffer, 0, buffer.Length); + } + + m_Stream.Seek(35, SeekOrigin.Begin); + m_Stream.Write((int)((long)disabled >> 32)); + m_Stream.Write((int)disabled); + + m_Stream.Seek(95, SeekOrigin.Begin); + m_Stream.Write(hashCode, 0, hashCode.Length); + } + } + + private static System.Security.Cryptography.MD5CryptoServiceProvider m_MD5Provider; + } + + public sealed class ClearWeaponAbility : Packet + { + public static readonly Packet Instance = Packet.SetStatic( new ClearWeaponAbility() ); + + public ClearWeaponAbility() : base( 0xBF ) + { + EnsureCapacity( 5 ); + + m_Stream.Write( (short) 0x21 ); + } + } + + public enum ALRReason : byte + { + Invalid = 0x00, + InUse = 0x01, + Blocked = 0x02, + BadPass = 0x03, + Idle = 0xFE, + BadComm = 0xFF + } + + public sealed class AccountLoginRej : Packet + { + public AccountLoginRej( ALRReason reason ) : base( 0x82, 2 ) + { + m_Stream.Write( (byte)reason ); + } + } + + public enum AffixType : byte + { + Append = 0x00, + Prepend = 0x01, + System = 0x02 + } + + public sealed class MessageLocalizedAffix : Packet + { + public MessageLocalizedAffix( Serial serial, int graphic, MessageType messageType, int hue, int font, int number, string name, AffixType affixType, string affix, string args ) : base( 0xCC ) + { + if ( name == null ) name = ""; + if ( affix == null ) affix = ""; + if ( args == null ) args = ""; + + if ( hue == 0 ) + hue = 0x3B2; + + this.EnsureCapacity( 52 + affix.Length + (args.Length * 2) ); + + m_Stream.Write( (int) serial ); + m_Stream.Write( (short) graphic ); + m_Stream.Write( (byte) messageType ); + m_Stream.Write( (short) hue ); + m_Stream.Write( (short) font ); + m_Stream.Write( (int) number ); + m_Stream.Write( (byte) affixType ); + m_Stream.WriteAsciiFixed( name, 30 ); + m_Stream.WriteAsciiNull( affix ); + m_Stream.WriteBigUniNull( args ); + } + } + + public sealed class ServerInfo + { + private string m_Name; + private int m_FullPercent; + private int m_TimeZone; + private IPEndPoint m_Address; + + public string Name + { + get + { + return m_Name; + } + set + { + m_Name = value; + } + } + + public int FullPercent + { + get + { + return m_FullPercent; + } + set + { + m_FullPercent = value; + } + } + + public int TimeZone + { + get + { + return m_TimeZone; + } + set + { + m_TimeZone = value; + } + } + + public IPEndPoint Address + { + get + { + return m_Address; + } + set + { + m_Address = value; + } + } + + public ServerInfo( string name, int fullPercent, TimeZone tz, IPEndPoint address ) + { + m_Name = name; + m_FullPercent = fullPercent; + m_TimeZone = tz.GetUtcOffset( DateTime.Now ).Hours; + m_Address = address; + } + } + + public sealed class FollowMessage : Packet + { + public FollowMessage( Serial serial1, Serial serial2 ) : base( 0x15, 9 ) + { + m_Stream.Write( (int) serial1 ); + m_Stream.Write( (int) serial2 ); + } + } + + public sealed class AccountLoginAck : Packet + { + public AccountLoginAck( ServerInfo[] info ) : base( 0xA8 ) + { + this.EnsureCapacity( 6 + (info.Length * 40) ); + + m_Stream.Write( (byte) 0x5D ); // Unknown + + m_Stream.Write( (ushort) info.Length ); + + for ( int i = 0; i < info.Length; ++i ) + { + ServerInfo si = info[i]; + + m_Stream.Write( (ushort) i ); + m_Stream.WriteAsciiFixed( si.Name, 32 ); + m_Stream.Write( (byte) si.FullPercent ); + m_Stream.Write( (sbyte) si.TimeZone ); + m_Stream.Write( (int) Utility.GetAddressValue( si.Address.Address ) ); + } + } + } + + public sealed class DisplaySignGump : Packet + { + public DisplaySignGump( Serial serial, int gumpID, string unknown, string caption ) : base( 0x8B ) + { + if ( unknown == null ) unknown = ""; + if ( caption == null ) caption = ""; + + this.EnsureCapacity( 16 + unknown.Length + caption.Length ); + + m_Stream.Write( (int) serial ); + m_Stream.Write( (short) gumpID ); + m_Stream.Write( (short) (unknown.Length) ); + m_Stream.WriteAsciiFixed( unknown, unknown.Length ); + m_Stream.Write( (short) (caption.Length + 1) ); + m_Stream.WriteAsciiFixed( caption, caption.Length + 1 ); + } + } + + public sealed class GodModeReply : Packet + { + public GodModeReply( bool reply ) : base( 0x2B, 2 ) + { + m_Stream.Write( reply ); + } + } + + public sealed class PlayServerAck : Packet + { + internal static int m_AuthID = -1; + + public PlayServerAck( ServerInfo si ) : base( 0x8C, 11 ) + { + int addr = Utility.GetAddressValue( si.Address.Address ); + + m_Stream.Write( (byte) addr ); + m_Stream.Write( (byte)(addr >> 8) ); + m_Stream.Write( (byte)(addr >> 16) ); + m_Stream.Write( (byte)(addr >> 24) ); + + m_Stream.Write( (short) si.Address.Port ); + m_Stream.Write( (int) m_AuthID ); + } + } + + public abstract class Packet + { + [Flags] + private enum State + { + Inactive = 0x00, + Static = 0x01, + Acquired = 0x02, + Accessed = 0x04, + Buffered = 0x08, + Warned = 0x10 + } + + protected PacketWriter m_Stream; + private int m_PacketID; + private int m_Length; + private State m_State; + + public int PacketID + { + get{ return m_PacketID; } + } + + protected Packet( int packetID ) + { + m_PacketID = packetID; + + PacketSendProfile prof = PacketSendProfile.Acquire( GetType() ); + + if ( prof != null ) { + prof.Created++; + } + } + + public void EnsureCapacity( int length ) + { + m_Stream = PacketWriter.CreateInstance( length );// new PacketWriter( length ); + m_Stream.Write( (byte) m_PacketID ); + m_Stream.Write( (short) 0 ); + } + + protected Packet( int packetID, int length ) + { + m_PacketID = packetID; + m_Length = length; + + m_Stream = PacketWriter.CreateInstance( length );// new PacketWriter( length ); + m_Stream.Write( ( byte ) packetID ); + + PacketSendProfile prof = PacketSendProfile.Acquire( GetType() ); + + if ( prof != null ) { + prof.Created++; + } + } + + public PacketWriter UnderlyingStream + { + get + { + return m_Stream; + } + } + + private const int BufferSize = 4096; + private static BufferPool m_Buffers = new BufferPool( "Compressed", 16, BufferSize ); + + public static Packet SetStatic( Packet p ) + { + p.SetStatic(); + return p; + } + + public static Packet Acquire( Packet p ) + { + p.Acquire(); + return p; + } + + public static void Release( ref ObjectPropertyList p ) + { + if ( p != null ) + p.Release(); + + p = null; + } + + public static void Release( ref RemoveItem p ) + { + if ( p != null ) + p.Release(); + + p = null; + } + + public static void Release( ref RemoveMobile p ) + { + if ( p != null ) + p.Release(); + + p = null; + } + + public static void Release( ref OPLInfo p ) + { + if ( p != null ) + p.Release(); + + p = null; + } + + public static void Release( ref Packet p ) + { + if ( p != null ) + p.Release(); + + p = null; + } + + public static void Release( Packet p ) + { + if ( p != null ) + p.Release(); + } + + public void SetStatic() + { + m_State |= State.Static | State.Acquired; + } + + public void Acquire() + { + m_State |= State.Acquired; + } + + public void OnSend() + { + Core.Set(); + + if ( (m_State & (State.Acquired | State.Static)) == 0 ) + Free(); + } + + private void Free() + { + if ( m_CompiledBuffer == null ) + return; + + if ( (m_State & State.Buffered) != 0 ) + m_Buffers.ReleaseBuffer( m_CompiledBuffer ); + + m_State &= ~(State.Static | State.Acquired | State.Buffered); + + m_CompiledBuffer = null; + } + + public void Release() + { + if ( (m_State & State.Acquired) != 0 ) + Free(); + } + + private byte[] m_CompiledBuffer; + private int m_CompiledLength; + + public byte[] Compile( bool compress, out int length ) + { + if ( m_CompiledBuffer == null ) + { + if ( (m_State & State.Accessed) == 0 ) + { + m_State |= State.Accessed; + } + else + { + if ( (m_State & State.Warned) == 0 ) + { + m_State |= State.Warned; + + try + { + using ( StreamWriter op = new StreamWriter( "net_opt.log", true ) ) + { + op.WriteLine( "Redundant compile for packet {0}, use Acquire() and Release()", this.GetType() ); + op.WriteLine( new System.Diagnostics.StackTrace() ); + } + } + catch + { + } + } + + m_CompiledBuffer = new byte[0]; + m_CompiledLength = 0; + + length = m_CompiledLength; + return m_CompiledBuffer; + } + + InternalCompile( compress ); + } + + length = m_CompiledLength; + return m_CompiledBuffer; + } + + private void InternalCompile( bool compress ) + { + if ( m_Length == 0 ) + { + long streamLen = m_Stream.Length; + + m_Stream.Seek( 1, SeekOrigin.Begin ); + m_Stream.Write( (ushort) streamLen ); + } + else if ( m_Stream.Length != m_Length ) + { + int diff = (int)m_Stream.Length - m_Length; + + Console.WriteLine( "Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)", m_PacketID, diff >= 0 ? "+" : "", diff ); + } + + MemoryStream ms = m_Stream.UnderlyingStream; + + m_CompiledBuffer = ms.GetBuffer(); + int length = (int)ms.Length; + + if ( compress ) + { + m_CompiledBuffer = Compression.Compress( + m_CompiledBuffer, 0, length, + ref length + ); + + if ( m_CompiledBuffer == null ) + { + Console.WriteLine( "Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})", m_PacketID, GetType().Name, length ); + using ( StreamWriter op = new StreamWriter( "compression_overflow.log", true ) ) + { + op.WriteLine( "{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})", DateTime.Now, m_PacketID, GetType().Name, length ); + op.WriteLine( new System.Diagnostics.StackTrace() ); + } + } + } + + if ( m_CompiledBuffer != null ) + { + m_CompiledLength = length; + + byte[] old = m_CompiledBuffer; + + if ( length > BufferSize || (m_State & State.Static) != 0 ) + { + m_CompiledBuffer = new byte[length]; + } + else + { + m_CompiledBuffer = m_Buffers.AcquireBuffer(); + m_State |= State.Buffered; + } + + Buffer.BlockCopy( old, 0, m_CompiledBuffer, 0, length ); + } + + PacketWriter.ReleaseInstance( m_Stream ); + m_Stream = null; + } + } +} diff --git a/Server/Network/SendQueue.cs b/Server/Network/SendQueue.cs new file mode 100644 index 0000000..5fbda1d --- /dev/null +++ b/Server/Network/SendQueue.cs @@ -0,0 +1,237 @@ +/*************************************************************************** + * SendQueue.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: SendQueue.cs 80 2006-08-27 20:41:31Z krrios $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Network { + public class SendQueue { + public class Gram { + private static Stack _pool = new Stack(); + + public static Gram Acquire() { + lock ( _pool ) { + Gram gram; + + if ( _pool.Count > 0 ) { + gram = _pool.Pop(); + } else { + gram = new Gram(); + } + + gram._buffer = AcquireBuffer(); + gram._length = 0; + + return gram; + } + } + + private byte[] _buffer; + private int _length; + + public byte[] Buffer { + get { + return _buffer; + } + } + + public int Length { + get { + return _length; + } + } + + public int Available { + get { + return ( _buffer.Length - _length ); + } + } + + public bool IsFull { + get { + return ( _length == _buffer.Length ); + } + } + + private Gram() { + } + + public int Write( byte[] buffer, int offset, int length ) { + int write = Math.Min( length, this.Available ); + + System.Buffer.BlockCopy( buffer, offset, _buffer, _length, write ); + + _length += write; + + return write; + } + + public void Release() { + lock ( _pool ) { + _pool.Push( this ); + ReleaseBuffer( _buffer ); + } + } + } + + private static int m_CoalesceBufferSize = 512; + private static BufferPool m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize ); + + public static int CoalesceBufferSize { + get { + return m_CoalesceBufferSize; + } + set { + if ( m_CoalesceBufferSize == value ) + return; + + if ( m_UnusedBuffers != null ) + m_UnusedBuffers.Free(); + + m_CoalesceBufferSize = value; + m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize ); + } + } + + public static byte[] AcquireBuffer() { + return m_UnusedBuffers.AcquireBuffer(); + } + + public static void ReleaseBuffer( byte[] buffer ) { + if ( buffer != null && buffer.Length == m_CoalesceBufferSize ) { + m_UnusedBuffers.ReleaseBuffer( buffer ); + } + } + + private Queue _pending; + + private Gram _buffered; + + public bool IsFlushReady { + get { + return ( _pending.Count == 0 && _buffered != null ); + } + } + + public bool IsEmpty { + get { + return ( _pending.Count == 0 && _buffered == null ); + } + } + + public SendQueue() { + _pending = new Queue(); + } + + public Gram CheckFlushReady() { + Gram gram = null; + + if ( _pending.Count == 0 && _buffered != null ) { + gram = _buffered; + + _pending.Enqueue( _buffered ); + _buffered = null; + } + + return gram; + } + + public Gram Dequeue() { + Gram gram = null; + + if ( _pending.Count > 0 ) { + _pending.Dequeue().Release(); + + if ( _pending.Count > 0 ) { + gram = _pending.Peek(); + } + } + + return gram; + } + + private const int PendingCap = 96 * 1024; + + public Gram Enqueue( byte[] buffer, int length ) { + return Enqueue( buffer, 0, length ); + } + + public Gram Enqueue( byte[] buffer, int offset, int length ) { + if ( buffer == null ) { + throw new ArgumentNullException( "buffer" ); + } else if ( !(offset >= 0 && offset < buffer.Length) ) { + throw new ArgumentOutOfRangeException( "offset", offset, "Offset must be greater than or equal to zero and less than the size of the buffer." ); + } else if ( length < 0 || length > buffer.Length ) { + throw new ArgumentOutOfRangeException( "length", length, "Length cannot be less than zero or greater than the size of the buffer." ); + } else if ( ( buffer.Length - offset ) < length ) { + throw new ArgumentException( "Offset and length do not point to a valid segment within the buffer." ); + } + + int existingBytes = ( _pending.Count * m_CoalesceBufferSize ) + ( _buffered == null ? 0 : _buffered.Length ); + + if ( ( existingBytes + length ) > PendingCap ) { + throw new CapacityExceededException(); + } + + Gram gram = null; + + while ( length > 0 ) { + if ( _buffered == null ) { // nothing yet buffered + _buffered = Gram.Acquire(); + } + + int bytesWritten = _buffered.Write( buffer, offset, length ); + + offset += bytesWritten; + length -= bytesWritten; + + if ( _buffered.IsFull ) { + if ( _pending.Count == 0 ) { + gram = _buffered; + } + + _pending.Enqueue( _buffered ); + _buffered = null; + } + } + + return gram; + } + + public void Clear() { + if ( _buffered != null ) { + _buffered.Release(); + _buffered = null; + } + + while ( _pending.Count > 0 ) { + _pending.Dequeue().Release(); + } + } + } + + public sealed class CapacityExceededException : Exception { + public CapacityExceededException() + : base( "Too much data pending." ) { + } + } +} \ No newline at end of file diff --git a/Server/Network/SocketPool.cs b/Server/Network/SocketPool.cs new file mode 100644 index 0000000..735027f --- /dev/null +++ b/Server/Network/SocketPool.cs @@ -0,0 +1,62 @@ +#if NewAsyncSockets +using System; +using System.Collections.Generic; +using System.Net.Sockets; + +namespace Server.Network +{ + public class SocketAsyncEventArgsPool + { + private Stack m_EventsPool; + + public SocketAsyncEventArgsPool(int numConnection) + { + m_EventsPool = new Stack(numConnection); + } + + public void Dispose() + { + using (Stack.Enumerator enumerator = m_EventsPool.GetEnumerator()) + { + while (enumerator.MoveNext()) + { + enumerator.Current.Dispose(); + } + } + m_EventsPool.Clear(); + } + + public SocketAsyncEventArgs Pop() + { + lock (m_EventsPool) + { + if (m_EventsPool.Count == 0) + { + return new SocketAsyncEventArgs(); + } + return m_EventsPool.Pop(); + } + } + + public void Push(SocketAsyncEventArgs item) + { + if (item == null) + { + throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); + } + lock (m_EventsPool) + { + m_EventsPool.Push(item); + } + } + + public int Count + { + get + { + return m_EventsPool.Count; + } + } + } +} +#endif \ No newline at end of file diff --git a/Server/Notoriety.cs b/Server/Notoriety.cs new file mode 100644 index 0000000..d8062a6 --- /dev/null +++ b/Server/Notoriety.cs @@ -0,0 +1,80 @@ +/*************************************************************************** + * Notoriety.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Notoriety.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using Server; +using Server.Guilds; +using Server.Items; + +namespace Server +{ + public delegate int NotorietyHandler( Mobile source, Mobile target ); + + public static class Notoriety + { + public const int Innocent = 1; + public const int Ally = 2; + public const int CanBeAttacked = 3; + public const int Criminal = 4; + public const int Enemy = 5; + public const int Murderer = 6; + public const int Invulnerable = 7; + + private static NotorietyHandler m_Handler; + + public static NotorietyHandler Handler + { + get{ return m_Handler; } + set{ m_Handler = value; } + } + + private static int[] m_Hues = new int[] + { + 0x000, + 0x059, + 0x03F, + 0x3B2, + 0x3B2, + 0x090, + 0x022, + 0x035 + }; + + public static int[] Hues + { + get{ return m_Hues; } + set{ m_Hues = value; } + } + + public static int GetHue( int noto ) + { + if ( noto < 0 || noto >= m_Hues.Length ) + return 0; + + return m_Hues[noto]; + } + + public static int Compute( Mobile source, Mobile target ) + { + return m_Handler == null ? CanBeAttacked : m_Handler( source, target ); + } + } +} \ No newline at end of file diff --git a/Server/ObjectPropertyList.cs b/Server/ObjectPropertyList.cs new file mode 100644 index 0000000..41b13f8 --- /dev/null +++ b/Server/ObjectPropertyList.cs @@ -0,0 +1,198 @@ +/*************************************************************************** + * ObjectPropertyList.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ObjectPropertyList.cs 653 2010-12-31 11:09:18Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Text; +using Server; +using Server.Network; + +namespace Server +{ + public sealed class ObjectPropertyList : Packet + { + private IEntity m_Entity; + private int m_Hash; + private int m_Header; + private int m_Strings; + private string m_HeaderArgs; + + public IEntity Entity{ get{ return m_Entity; } } + public int Hash{ get{ return 0x40000000 + m_Hash; } } + + public int Header{ get{ return m_Header; } set{ m_Header = value; } } + public string HeaderArgs{ get{ return m_HeaderArgs; } set{ m_HeaderArgs = value; } } + + private static bool m_Enabled = false; + + public static bool Enabled{ get{ return m_Enabled; } set{ m_Enabled = value; } } + + public ObjectPropertyList( IEntity e ) : base( 0xD6 ) + { + EnsureCapacity( 128 ); + + m_Entity = e; + + m_Stream.Write( (short) 1 ); + m_Stream.Write( (int) e.Serial ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (byte) 0 ); + m_Stream.Write( (int) e.Serial ); + } + + public void Add( int number ) + { + if ( number == 0 ) + return; + + AddHash( number ); + + if ( m_Header == 0 ) + { + m_Header = number; + m_HeaderArgs = ""; + } + + m_Stream.Write( number ); + m_Stream.Write( (short) 0 ); + } + + public void Terminate() + { + m_Stream.Write( (int) 0 ); + + m_Stream.Seek( 11, System.IO.SeekOrigin.Begin ); + m_Stream.Write( (int) m_Hash ); + } + + private static byte[] m_Buffer = new byte[1024]; + private static Encoding m_Encoding = Encoding.Unicode; + + public void AddHash( int val ) + { + m_Hash ^= (val & 0x3FFFFFF); + m_Hash ^= (val >> 26) & 0x3F; + } + + public void Add( int number, string arguments ) + { + if ( number == 0 ) + return; + + if ( arguments == null ) + arguments = ""; + + if ( m_Header == 0 ) + { + m_Header = number; + m_HeaderArgs = arguments; + } + + AddHash( number ); + AddHash( arguments.GetHashCode() ); + + m_Stream.Write( number ); + + int byteCount = m_Encoding.GetByteCount( arguments ); + + if ( byteCount > m_Buffer.Length ) + m_Buffer = new byte[byteCount]; + + byteCount = m_Encoding.GetBytes( arguments, 0, arguments.Length, m_Buffer, 0 ); + + m_Stream.Write( (short) byteCount ); + m_Stream.Write( m_Buffer, 0, byteCount ); + } + + public void Add( int number, string format, object arg0 ) + { + Add( number, String.Format( format, arg0 ) ); + } + + public void Add( int number, string format, object arg0, object arg1 ) + { + Add( number, String.Format( format, arg0, arg1 ) ); + } + + public void Add( int number, string format, object arg0, object arg1, object arg2 ) + { + Add( number, String.Format( format, arg0, arg1, arg2 ) ); + } + + public void Add( int number, string format, params object[] args ) + { + Add( number, String.Format( format, args ) ); + } + + // Each of these are localized to "~1_NOTHING~" which allows the string argument to be used + private static int[] m_StringNumbers = new int[] + { + 1042971, + 1070722 + }; + + private int GetStringNumber() + { + return m_StringNumbers[m_Strings++ % m_StringNumbers.Length]; + } + + public void Add( string text ) + { + Add( GetStringNumber(), text ); + } + + public void Add( string format, string arg0 ) + { + Add( GetStringNumber(), String.Format( format, arg0 ) ); + } + + public void Add( string format, string arg0, string arg1 ) + { + Add( GetStringNumber(), String.Format( format, arg0, arg1 ) ); + } + + public void Add( string format, string arg0, string arg1, string arg2 ) + { + Add( GetStringNumber(), String.Format( format, arg0, arg1, arg2 ) ); + } + + public void Add( string format, params object[] args ) + { + Add( GetStringNumber(), String.Format( format, args ) ); + } + } + + public sealed class OPLInfo : Packet + { + /*public OPLInfo( ObjectPropertyList list ) : base( 0xBF ) + { + EnsureCapacity( 13 ); + + m_Stream.Write( (short) 0x10 ); + m_Stream.Write( (int) list.Entity.Serial ); + m_Stream.Write( (int) list.Hash ); + }*/ + + public OPLInfo( ObjectPropertyList list ) : base( 0xDC, 9 ) + { + m_Stream.Write( (int) list.Entity.Serial ); + m_Stream.Write( (int) list.Hash ); + } + } +} \ No newline at end of file diff --git a/Server/Party.cs b/Server/Party.cs new file mode 100644 index 0000000..f5736f7 --- /dev/null +++ b/Server/Party.cs @@ -0,0 +1,39 @@ +/*************************************************************************** + * Party.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Party.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public abstract class PartyCommands + { + private static PartyCommands m_Handler; + + public static PartyCommands Handler{ get{ return m_Handler; } set{ m_Handler = value; } } + + public abstract void OnAdd( Mobile from ); + public abstract void OnRemove( Mobile from, Mobile target ); + public abstract void OnPrivateMessage( Mobile from, Mobile target, string text ); + public abstract void OnPublicMessage( Mobile from, string text ); + public abstract void OnSetCanLoot( Mobile from, bool canLoot ); + public abstract void OnAccept( Mobile from, Mobile leader ); + public abstract void OnDecline( Mobile from, Mobile leader ); + } +} \ No newline at end of file diff --git a/Server/Persistence/BinaryMemoryWriter.cs b/Server/Persistence/BinaryMemoryWriter.cs new file mode 100644 index 0000000..51f5033 --- /dev/null +++ b/Server/Persistence/BinaryMemoryWriter.cs @@ -0,0 +1,86 @@ +/*************************************************************************** + * BinaryMemoryWriter.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: BinaryMemoryWriter.cs 37 2006-06-19 17:28:24Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +namespace Server { + public sealed class BinaryMemoryWriter : BinaryFileWriter { + private MemoryStream stream; + + protected override int BufferSize { + get { return 512; } + } + + public BinaryMemoryWriter() + : base( new MemoryStream( 512 ), true ) { + this.stream = this.UnderlyingStream as MemoryStream; + } + + private static byte[] indexBuffer; + + public int CommitTo( SequentialFileWriter dataFile, SequentialFileWriter indexFile, int typeCode, int serial ) { + Flush(); + + byte[] buffer = stream.GetBuffer(); + int length = ( int ) stream.Length; + + long position = dataFile.Position; + + dataFile.Write( buffer, 0, length ); + + if ( indexBuffer == null ) { + indexBuffer = new byte[20]; + } + + indexBuffer[0] = ( byte ) ( typeCode ); + indexBuffer[1] = ( byte ) ( typeCode >> 8 ); + indexBuffer[2] = ( byte ) ( typeCode >> 16 ); + indexBuffer[3] = ( byte ) ( typeCode >> 24 ); + + indexBuffer[4] = ( byte ) ( serial ); + indexBuffer[5] = ( byte ) ( serial >> 8 ); + indexBuffer[6] = ( byte ) ( serial >> 16 ); + indexBuffer[7] = ( byte ) ( serial >> 24 ); + + indexBuffer[8] = ( byte ) ( position ); + indexBuffer[9] = ( byte ) ( position >> 8 ); + indexBuffer[10] = ( byte ) ( position >> 16 ); + indexBuffer[11] = ( byte ) ( position >> 24 ); + indexBuffer[12] = ( byte ) ( position >> 32 ); + indexBuffer[13] = ( byte ) ( position >> 40 ); + indexBuffer[14] = ( byte ) ( position >> 48 ); + indexBuffer[15] = ( byte ) ( position >> 56 ); + + indexBuffer[16] = ( byte ) ( length ); + indexBuffer[17] = ( byte ) ( length >> 8 ); + indexBuffer[18] = ( byte ) ( length >> 16 ); + indexBuffer[19] = ( byte ) ( length >> 24 ); + + indexFile.Write( indexBuffer, 0, indexBuffer.Length ); + + stream.SetLength( 0 ); + + return length; + } + } +} \ No newline at end of file diff --git a/Server/Persistence/DualSaveStrategy.cs b/Server/Persistence/DualSaveStrategy.cs new file mode 100644 index 0000000..b8eb338 --- /dev/null +++ b/Server/Persistence/DualSaveStrategy.cs @@ -0,0 +1,60 @@ +/*************************************************************************** + * DualSaveStrategy.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: DualSaveStrategy.cs 642 2010-12-20 11:31:46Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Threading; +using System.Diagnostics; + +using Server; +using Server.Guilds; + +namespace Server { + public sealed class DualSaveStrategy : StandardSaveStrategy { + public override string Name { + get { return "Dual"; } + } + + public DualSaveStrategy() { + } + + public override void Save( SaveMetrics metrics, bool permitBackgroundWrite ) + { + this.PermitBackgroundWrite = permitBackgroundWrite; + + Thread saveThread = new Thread( delegate() { + SaveItems(metrics); + } ); + + saveThread.Name = "Item Save Subset"; + saveThread.Start(); + + SaveMobiles(metrics); + SaveGuilds(metrics); + + saveThread.Join(); + + if (permitBackgroundWrite && UseSequentialWriters) //If we're permitted to write in the background, but we don't anyways, then notify. + World.NotifyDiskWriteComplete(); + } + } +} \ No newline at end of file diff --git a/Server/Persistence/DynamicSaveStrategy.cs b/Server/Persistence/DynamicSaveStrategy.cs new file mode 100644 index 0000000..442e9c4 --- /dev/null +++ b/Server/Persistence/DynamicSaveStrategy.cs @@ -0,0 +1,317 @@ +/*************************************************************************** + * DynamicSaveStrategy.cs + * ------------------- + * begin : December 16, 2010 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: DynamicSaveStrategy.cs 844 2012-03-07 13:47:33Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +#if Framework_4_0 + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Diagnostics; +using System.Collections.Concurrent; +using System.Linq; + +using Server; +using Server.Guilds; + +namespace Server +{ + public sealed class DynamicSaveStrategy : SaveStrategy + { + public override string Name { get { return "Dynamic"; } } + + private SaveMetrics _metrics; + + private SequentialFileWriter _itemData, _itemIndex; + private SequentialFileWriter _mobileData, _mobileIndex; + private SequentialFileWriter _guildData, _guildIndex; + + private ConcurrentBag _decayBag; + + private BlockingCollection _itemThreadWriters; + private BlockingCollection _mobileThreadWriters; + private BlockingCollection _guildThreadWriters; + + public DynamicSaveStrategy() + { + _decayBag = new ConcurrentBag(); + _itemThreadWriters = new BlockingCollection(); + _mobileThreadWriters = new BlockingCollection(); + _guildThreadWriters = new BlockingCollection(); + } + + public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + { + this._metrics = metrics; + + OpenFiles(); + + Task[] saveTasks = new Task[3]; + + saveTasks[0] = SaveItems(); + saveTasks[1] = SaveMobiles(); + saveTasks[2] = SaveGuilds(); + + SaveTypeDatabases(); + + if (permitBackgroundWrite) + { + //This option makes it finish the writing to disk in the background, continuing even after Save() returns. + Task.Factory.ContinueWhenAll(saveTasks, _ => + { + CloseFiles(); + + World.NotifyDiskWriteComplete(); + }); + } + else + { + Task.WaitAll(saveTasks); //Waits for the completion of all of the tasks(committing to disk) + CloseFiles(); + } + } + + private Task StartCommitTask(BlockingCollection threadWriter, SequentialFileWriter data, SequentialFileWriter index) + { + Task commitTask = Task.Factory.StartNew(() => + { + while (!(threadWriter.IsCompleted)) + { + QueuedMemoryWriter writer; + + try + { + writer = threadWriter.Take(); + } + catch (InvalidOperationException) + { + //Per MSDN, it's fine if we're here, successful completion of adding can rarely put us into this state. + break; + } + + writer.CommitTo(data, index); + } + }); + + return commitTask; + } + + private Task SaveItems() + { + //Start the blocking consumer; this runs in background. + Task commitTask = StartCommitTask(_itemThreadWriters, _itemData, _itemIndex); + + IEnumerable items = World.Items.Values; + + //Start the producer. + Parallel.ForEach(items, () => new QueuedMemoryWriter(), + (Item item, ParallelLoopState state, QueuedMemoryWriter writer) => + { + long startPosition = writer.Position; + + item.Serialize(writer); + + int size = (int)(writer.Position - startPosition); + + writer.QueueForIndex(item, size); + + if (item.Decays && item.Parent == null && item.Map != Map.Internal && DateTime.Now > (item.LastMoved + item.DecayTime)) + { + _decayBag.Add(item); + } + + if (_metrics != null) + { + _metrics.OnItemSaved(size); + } + + return writer; + }, + (writer) => + { + writer.Flush(); + + _itemThreadWriters.Add(writer); + }); + + _itemThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task + + return commitTask; + } + + + + private Task SaveMobiles() + { + //Start the blocking consumer; this runs in background. + Task commitTask = StartCommitTask( _mobileThreadWriters, _mobileData, _mobileIndex ); + + IEnumerable mobiles = World.Mobiles.Values; + + //Start the producer. + Parallel.ForEach(mobiles, () => new QueuedMemoryWriter(), + (Mobile mobile, ParallelLoopState state, QueuedMemoryWriter writer) => + { + long startPosition = writer.Position; + + mobile.Serialize(writer); + + int size = (int)(writer.Position - startPosition); + + writer.QueueForIndex(mobile, size); + + if (_metrics != null) + { + _metrics.OnMobileSaved(size); + } + + return writer; + }, + (writer) => + { + writer.Flush(); + + _mobileThreadWriters.Add(writer); + }); + + _mobileThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task tell the consumer that we're done + + return commitTask; + } + + private Task SaveGuilds() + { + //Start the blocking consumer; this runs in background. + Task commitTask = StartCommitTask(_guildThreadWriters, _guildData, _guildIndex); + + IEnumerable guilds = BaseGuild.List.Values; + + //Start the producer. + Parallel.ForEach(guilds, () => new QueuedMemoryWriter(), + (BaseGuild guild, ParallelLoopState state, QueuedMemoryWriter writer) => + { + long startPosition = writer.Position; + + guild.Serialize(writer); + + int size = (int)(writer.Position - startPosition ); + + writer.QueueForIndex(guild, size); + + if (_metrics != null) + { + _metrics.OnGuildSaved(size); + } + + return writer; + }, + (writer) => + { + writer.Flush(); + + _guildThreadWriters.Add(writer); + }); + + _guildThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task + + return commitTask; + } + + public override void ProcessDecay() + { + Item item; + + while( _decayBag.TryTake( out item ) ) + { + if( item.OnDecay() ) + { + item.Delete(); + } + } + } + + private void OpenFiles() + { + _itemData = new SequentialFileWriter(World.ItemDataPath, _metrics); + _itemIndex = new SequentialFileWriter(World.ItemIndexPath, _metrics); + + _mobileData = new SequentialFileWriter(World.MobileDataPath, _metrics); + _mobileIndex = new SequentialFileWriter(World.MobileIndexPath, _metrics); + + _guildData = new SequentialFileWriter(World.GuildDataPath, _metrics); + _guildIndex = new SequentialFileWriter(World.GuildIndexPath, _metrics); + + WriteCount(_itemIndex, World.Items.Count); + WriteCount(_mobileIndex, World.Mobiles.Count); + WriteCount(_guildIndex, BaseGuild.List.Count); + } + + private void CloseFiles() + { + _itemData.Close(); + _itemIndex.Close(); + + _mobileData.Close(); + _mobileIndex.Close(); + + _guildData.Close(); + _guildIndex.Close(); + } + + private void WriteCount(SequentialFileWriter indexFile, int count) + { + //Equiv to GenericWriter.Write( (int)count ); + byte[] buffer = new byte[4]; + + buffer[0] = (byte)(count); + buffer[1] = (byte)(count >> 8); + buffer[2] = (byte)(count >> 16); + buffer[3] = (byte)(count >> 24); + + indexFile.Write(buffer, 0, buffer.Length); + } + + private void SaveTypeDatabases() + { + SaveTypeDatabase(World.ItemTypesPath, World.m_ItemTypes); + SaveTypeDatabase(World.MobileTypesPath, World.m_MobileTypes); + } + + private void SaveTypeDatabase(string path, List types) + { + BinaryFileWriter bfw = new BinaryFileWriter(path, false); + + bfw.Write(types.Count); + + foreach (Type type in types) + { + bfw.Write(type.FullName); + } + + bfw.Flush(); + + bfw.Close(); + } + } + +} +#endif \ No newline at end of file diff --git a/Server/Persistence/FileOperations.cs b/Server/Persistence/FileOperations.cs new file mode 100644 index 0000000..a210474 --- /dev/null +++ b/Server/Persistence/FileOperations.cs @@ -0,0 +1,141 @@ +/*************************************************************************** + * FileOperations.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: FileOperations.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +#if !MONO +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +#endif + +namespace Server { + public static class FileOperations { + public const int KB = 1024; + public const int MB = 1024 * KB; + +#if !MONO + private const FileOptions NoBuffering = ( FileOptions ) 0x20000000; + + [DllImport( "Kernel32", CharSet = CharSet.Auto, SetLastError = true )] + private static extern SafeFileHandle CreateFile( string lpFileName, int dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile ); +#endif + + private static int bufferSize = 1 * MB; + private static int concurrency = 1; + + private static bool unbuffered = true; + + public static int BufferSize { + get { + return bufferSize; + } + set { + bufferSize = value; + } + } + + public static int Concurrency { + get { + return concurrency; + } + set { + concurrency = value; + } + } + + public static bool Unbuffered { + get { + return unbuffered; + } + set { + unbuffered = value; + } + } + + public static bool AreSynchronous { + get { + return ( concurrency < 1 ); + } + } + + public static bool AreAsynchronous { + get { + return ( concurrency > 0 ); + } + } + + public static FileStream OpenSequentialStream( string path, FileMode mode, FileAccess access, FileShare share ) { + FileOptions options = FileOptions.SequentialScan; + + if ( concurrency > 0 ) { + options |= FileOptions.Asynchronous; + } + +#if MONO + return new FileStream( path, mode, access, share, bufferSize, options ); +#else + if ( unbuffered ) { + options |= NoBuffering; + } else { + return new FileStream( path, mode, access, share, bufferSize, options ); + } + + SafeFileHandle fileHandle = CreateFile( path, (int) access, share, IntPtr.Zero, mode, (int) options, IntPtr.Zero ); + + if ( fileHandle.IsInvalid ) { + throw new IOException(); + } + + return new UnbufferedFileStream( fileHandle, access, bufferSize, ( concurrency > 0 ) ); +#endif + } + +#if !MONO + private class UnbufferedFileStream : FileStream { + private SafeFileHandle fileHandle; + + public UnbufferedFileStream( SafeFileHandle fileHandle, FileAccess access, int bufferSize, bool isAsync ) + : base( fileHandle, access, bufferSize, isAsync ) { + this.fileHandle = fileHandle; + } + + public override void Write( byte[] array, int offset, int count ) { + base.Write( array, offset, bufferSize ); + } + + public override IAsyncResult BeginWrite( byte[] array, int offset, int numBytes, AsyncCallback userCallback, object stateObject ) { + return base.BeginWrite( array, offset, bufferSize, userCallback, stateObject ); + } + + protected override void Dispose( bool disposing ) { + if ( !fileHandle.IsClosed ) { + fileHandle.Close(); + } + + base.Dispose( disposing ); + } + } +#endif + } +} diff --git a/Server/Persistence/FileQueue.cs b/Server/Persistence/FileQueue.cs new file mode 100644 index 0000000..ec33ee8 --- /dev/null +++ b/Server/Persistence/FileQueue.cs @@ -0,0 +1,251 @@ +/*************************************************************************** + * FileQueue.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: FileQueue.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +using Server; +using Server.Network; + +namespace Server { + public delegate void FileCommitCallback( FileQueue.Chunk chunk ); + + public sealed class FileQueue : IDisposable { + public sealed class Chunk { + private FileQueue owner; + private int slot; + + private byte[] buffer; + private int offset; + private int size; + + public byte[] Buffer { + get { + return buffer; + } + } + + public int Offset { + get { + return 0; + } + } + + public int Size { + get { + return size; + } + } + + public Chunk( FileQueue owner, int slot, byte[] buffer, int offset, int size ) { + this.owner = owner; + this.slot = slot; + + this.buffer = buffer; + this.offset = offset; + this.size = size; + } + + public void Commit() { + owner.Commit( this, this.slot ); + } + } + + private struct Page { + public byte[] buffer; + public int length; + } + + private static int bufferSize; + private static BufferPool bufferPool; + + static FileQueue() { + bufferSize = FileOperations.BufferSize; + bufferPool = new BufferPool( "File Buffers", 64, bufferSize ); + } + + private object syncRoot; + + private Chunk[] active; + private int activeCount; + + private Queue pending; + private Page buffered; + + private FileCommitCallback callback; + + private ManualResetEvent idle; + + private long position; + + public long Position { + get { + return position; + } + } + + public FileQueue( int concurrentWrites, FileCommitCallback callback ) { + if ( concurrentWrites < 1 ) { + throw new ArgumentOutOfRangeException( "concurrentWrites" ); + } else if ( bufferSize < 1 ) { + throw new ArgumentOutOfRangeException( "bufferSize" ); + } else if ( callback == null ) { + throw new ArgumentNullException( "callback" ); + } + + this.syncRoot = new object(); + + this.active = new Chunk[concurrentWrites]; + this.pending = new Queue(); + + this.callback = callback; + + this.idle = new ManualResetEvent( true ); + } + + private void Append( Page page ) { + lock ( syncRoot ) { + if ( activeCount == 0 ) { + idle.Reset(); + } + + ++activeCount; + + for ( int slot = 0; slot < active.Length; ++slot ) { + if ( active[slot] == null ) { + active[slot] = new Chunk( this, slot, page.buffer, 0, page.length ); + + callback( active[slot] ); + + return; + } + } + + pending.Enqueue( page ); + } + } + + public void Dispose() { + if ( idle != null ) { + idle.Close(); + idle = null; + } + } + + public void Flush() { + if ( buffered.buffer != null ) { + Append( buffered ); + + buffered.buffer = null; + buffered.length = 0; + } + + /*lock ( syncRoot ) { + if ( pending.Count > 0 ) { + idle.Reset(); + } + + for ( int slot = 0; slot < active.Length && pending.Count > 0; ++slot ) { + if ( active[slot] == null ) { + Page page = pending.Dequeue(); + + active[slot] = new Chunk( this, slot, page.buffer, 0, page.length ); + + ++activeCount; + + callback( active[slot] ); + } + } + }*/ + + idle.WaitOne(); + } + + private void Commit( Chunk chunk, int slot ) { + if ( slot < 0 || slot >= active.Length ) { + throw new ArgumentOutOfRangeException( "slot" ); + } + + lock ( syncRoot ) { + if ( active[slot] != chunk ) { + throw new ArgumentException(); + } + + bufferPool.ReleaseBuffer( chunk.Buffer ); + + if ( pending.Count > 0 ) { + Page page = pending.Dequeue(); + + active[slot] = new Chunk( this, slot, page.buffer, 0, page.length ); + + callback( active[slot] ); + } else { + active[slot] = null; + } + + --activeCount; + + if ( activeCount == 0 ) { + idle.Set(); + } + } + } + + public void Enqueue( byte[] buffer, int offset, int size ) { + if ( buffer == null ) { + throw new ArgumentNullException( "buffer" ); + } else if ( offset < 0 ) { + throw new ArgumentOutOfRangeException( "offset" ); + } else if ( size < 0 ) { + throw new ArgumentOutOfRangeException( "size" ); + } else if ( ( buffer.Length - offset ) < size ) { + throw new ArgumentException(); + } + + position += size; + + while ( size > 0 ) { + if ( buffered.buffer == null ) { // nothing yet buffered + buffered.buffer = bufferPool.AcquireBuffer(); + } + + byte[] page = buffered.buffer; // buffer page + int pageSpace = page.Length - buffered.length; // available bytes in page + int byteCount = ( size > pageSpace ? pageSpace : size ); // how many bytes we can copy over + + Buffer.BlockCopy( buffer, offset, page, buffered.length, byteCount ); + + buffered.length += byteCount; + offset += byteCount; + size -= byteCount; + + if ( buffered.length == page.Length ) { // page full + Append( buffered ); + + buffered.buffer = null; + buffered.length = 0; + } + } + } + } +} \ No newline at end of file diff --git a/Server/Persistence/ParallelSaveStrategy.cs b/Server/Persistence/ParallelSaveStrategy.cs new file mode 100644 index 0000000..fe80d50 --- /dev/null +++ b/Server/Persistence/ParallelSaveStrategy.cs @@ -0,0 +1,345 @@ +/*************************************************************************** + * ParallelSaveStrategy.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ParallelSaveStrategy.cs 641 2010-12-20 03:34:25Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Threading; +using System.Diagnostics; + +using Server; +using Server.Guilds; + +namespace Server { + public sealed class ParallelSaveStrategy : SaveStrategy { + public override string Name { + get { return "Parallel"; } + } + + private int processorCount; + + public ParallelSaveStrategy( int processorCount ) { + this.processorCount = processorCount; + + _decayQueue = new Queue(); + } + + private int GetThreadCount() { + return processorCount - 1; + } + + private SaveMetrics metrics; + + private SequentialFileWriter itemData, itemIndex; + private SequentialFileWriter mobileData, mobileIndex; + private SequentialFileWriter guildData, guildIndex; + + private Queue _decayQueue; + + private Consumer[] consumers; + private int cycle; + + private bool finished; + + public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + { + this.metrics = metrics; + + OpenFiles(); + + consumers = new Consumer[GetThreadCount()]; + + for ( int i = 0; i < consumers.Length; ++i ) { + consumers[i] = new Consumer( this, 256 ); + } + + IEnumerable collection = new Producer(); + + foreach ( ISerializable value in collection ) { + while ( !Enqueue( value ) ) { + if ( !Commit() ) { + Thread.Sleep( 0 ); + } + } + } + + finished = true; + + SaveTypeDatabases(); + + WaitHandle.WaitAll( + Array.ConvertAll( + consumers, + delegate( Consumer input ) { + return input.completionEvent; + } + ) + ); + + Commit(); + + CloseFiles(); + } + + public override void ProcessDecay() { + while ( _decayQueue.Count > 0 ) { + Item item = _decayQueue.Dequeue(); + + if ( item.OnDecay() ) { + item.Delete(); + } + } + } + + private void SaveTypeDatabases() { + SaveTypeDatabase( World.ItemTypesPath, World.m_ItemTypes ); + SaveTypeDatabase( World.MobileTypesPath, World.m_MobileTypes ); + } + + private void SaveTypeDatabase( string path, List types ) { + BinaryFileWriter bfw = new BinaryFileWriter( path, false ); + + bfw.Write( types.Count ); + + foreach ( Type type in types ) { + bfw.Write( type.FullName ); + } + + bfw.Flush(); + + bfw.Close(); + } + + private void OpenFiles() { + itemData = new SequentialFileWriter( World.ItemDataPath, metrics ); + itemIndex = new SequentialFileWriter( World.ItemIndexPath, metrics ); + + mobileData = new SequentialFileWriter( World.MobileDataPath, metrics ); + mobileIndex = new SequentialFileWriter( World.MobileIndexPath, metrics ); + + guildData = new SequentialFileWriter( World.GuildDataPath, metrics ); + guildIndex = new SequentialFileWriter( World.GuildIndexPath, metrics ); + + WriteCount( itemIndex, World.Items.Count ); + WriteCount( mobileIndex, World.Mobiles.Count ); + WriteCount( guildIndex, BaseGuild.List.Count ); + } + + private void WriteCount( SequentialFileWriter indexFile, int count ) { + byte[] buffer = new byte[4]; + + buffer[0] = ( byte ) ( count ); + buffer[1] = ( byte ) ( count >> 8 ); + buffer[2] = ( byte ) ( count >> 16 ); + buffer[3] = ( byte ) ( count >> 24 ); + + indexFile.Write( buffer, 0, buffer.Length ); + } + + private void CloseFiles() { + itemData.Close(); + itemIndex.Close(); + + mobileData.Close(); + mobileIndex.Close(); + + guildData.Close(); + guildIndex.Close(); + + World.NotifyDiskWriteComplete(); + } + + private void OnSerialized( ConsumableEntry entry ) { + ISerializable value = entry.value; + BinaryMemoryWriter writer = entry.writer; + + Item item = value as Item; + + if ( item != null ) { + Save( item, writer ); + } else { + Mobile mob = value as Mobile; + + if ( mob != null ) { + Save( mob, writer ); + } else { + BaseGuild guild = value as BaseGuild; + + if ( guild != null ) { + Save( guild, writer ); + } + } + } + } + + private void Save( Item item, BinaryMemoryWriter writer ) { + int length = writer.CommitTo( itemData, itemIndex, item.m_TypeRef, item.Serial ); + + if ( metrics != null ) { + metrics.OnItemSaved( length ); + } + + if ( item.Decays && item.Parent == null && item.Map != Map.Internal && DateTime.Now > ( item.LastMoved + item.DecayTime ) ) { + _decayQueue.Enqueue( item ); + } + } + + private void Save( Mobile mob, BinaryMemoryWriter writer ) { + int length = writer.CommitTo( mobileData, mobileIndex, mob.m_TypeRef, mob.Serial ); + + if ( metrics != null ) { + metrics.OnMobileSaved( length ); + } + } + + private void Save( BaseGuild guild, BinaryMemoryWriter writer ) { + int length = writer.CommitTo( guildData, guildIndex, 0, guild.Id ); + + if ( metrics != null ) { + metrics.OnGuildSaved( length ); + } + } + + private bool Enqueue( ISerializable value ) { + for ( int i = 0; i < consumers.Length; ++i ) { + Consumer consumer = consumers[cycle++ % consumers.Length]; + + if ( ( consumer.tail - consumer.head ) < consumer.buffer.Length ) { + consumer.buffer[consumer.tail % consumer.buffer.Length].value = value; + consumer.tail++; + + return true; + } + } + + return false; + } + + private bool Commit() { + bool committed = false; + + for ( int i = 0; i < consumers.Length; ++i ) { + Consumer consumer = consumers[i]; + + while ( consumer.head < consumer.done ) { + OnSerialized( consumer.buffer[consumer.head % consumer.buffer.Length] ); + consumer.head++; + + committed = true; + } + } + + return committed; + } + + private sealed class Producer : IEnumerable { + private IEnumerable items; + private IEnumerable mobiles; + private IEnumerable guilds; + + public Producer() { + items = World.Items.Values; + mobiles = World.Mobiles.Values; + guilds = BaseGuild.List.Values; + } + + public IEnumerator GetEnumerator() { + foreach ( Item item in items ) { + yield return item; + } + + foreach ( Mobile mob in mobiles ) { + yield return mob; + } + + foreach ( BaseGuild guild in guilds ) { + yield return guild; + } + } + + IEnumerator IEnumerable.GetEnumerator() { + throw new NotImplementedException(); + } + } + + private struct ConsumableEntry { + public ISerializable value; + public BinaryMemoryWriter writer; + } + + private sealed class Consumer { + private ParallelSaveStrategy owner; + + public ManualResetEvent completionEvent; + + public ConsumableEntry[] buffer; + public int head, done, tail; + + private Thread thread; + + public Consumer( ParallelSaveStrategy owner, int bufferSize ) { + this.owner = owner; + + this.buffer = new ConsumableEntry[bufferSize]; + + for ( int i = 0; i < this.buffer.Length; ++i ) { + this.buffer[i].writer = new BinaryMemoryWriter(); + } + + this.completionEvent = new ManualResetEvent( false ); + + thread = new Thread( Processor ); + + thread.Name = "Parallel Serialization Thread"; + + thread.Start(); + } + + private void Processor() { + try { + while ( !owner.finished ) { + Process(); + Thread.Sleep( 0 ); + } + + Process(); + + completionEvent.Set(); + } catch ( Exception ex ) { + Console.WriteLine( ex ); + } + } + + private void Process() { + ConsumableEntry entry; + + while ( done < tail ) { + entry = buffer[done % buffer.Length]; + + entry.value.Serialize( entry.writer ); + + ++done; + } + } + } + } +} \ No newline at end of file diff --git a/Server/Persistence/QueuedMemoryWriter.cs b/Server/Persistence/QueuedMemoryWriter.cs new file mode 100644 index 0000000..33a024d --- /dev/null +++ b/Server/Persistence/QueuedMemoryWriter.cs @@ -0,0 +1,126 @@ +/*************************************************************************** + * QueuedMemoryWriter.cs + * ------------------- + * begin : December 16, 2010 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: QueuedMemoryWriter.cs 645 2010-12-23 11:36:25Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +namespace Server +{ + public sealed class QueuedMemoryWriter : BinaryFileWriter + { + private struct IndexInfo + { + public int size; + public int typeCode; + public int serial; + } + + private MemoryStream _memStream; + private List _orderedIndexInfo = new List(); + + protected override int BufferSize + { + get { return 512; } + } + + public QueuedMemoryWriter() + : base(new MemoryStream(1024 * 1024), true) + { + this._memStream = this.UnderlyingStream as MemoryStream; + } + + public void QueueForIndex(ISerializable serializable, int size) + { + IndexInfo info; + + info.size = size; + + info.typeCode = serializable.TypeReference; //For guilds, this will automagically be zero. + info.serial = serializable.SerialIdentity; + + _orderedIndexInfo.Add(info); + } + + public void CommitTo(SequentialFileWriter dataFile, SequentialFileWriter indexFile) + { + this.Flush(); + + int memLength = (int)_memStream.Position; + + if (memLength > 0) + { + byte[] memBuffer = _memStream.GetBuffer(); + + long actualPosition = dataFile.Position; + + dataFile.Write(memBuffer, 0, memLength); //The buffer contains the data from many items. + + //Console.WriteLine("Writing {0} bytes starting at {1}, with {2} things", memLength, actualPosition, _orderedIndexInfo.Count); + + byte[] indexBuffer = new byte[20]; + + //int indexWritten = _orderedIndexInfo.Count * indexBuffer.Length; + //int totalWritten = memLength + indexWritten + + for (int i = 0; i < _orderedIndexInfo.Count; i++) + { + IndexInfo info = _orderedIndexInfo[i]; + + int typeCode = info.typeCode; + int serial = info.serial; + int length = info.size; + + + indexBuffer[0] = (byte)(info.typeCode); + indexBuffer[1] = (byte)(info.typeCode >> 8); + indexBuffer[2] = (byte)(info.typeCode >> 16); + indexBuffer[3] = (byte)(info.typeCode >> 24); + + indexBuffer[4] = (byte)(info.serial); + indexBuffer[5] = (byte)(info.serial >> 8); + indexBuffer[6] = (byte)(info.serial >> 16); + indexBuffer[7] = (byte)(info.serial >> 24); + + indexBuffer[8] = (byte)(actualPosition); + indexBuffer[9] = (byte)(actualPosition >> 8); + indexBuffer[10] = (byte)(actualPosition >> 16); + indexBuffer[11] = (byte)(actualPosition >> 24); + indexBuffer[12] = (byte)(actualPosition >> 32); + indexBuffer[13] = (byte)(actualPosition >> 40); + indexBuffer[14] = (byte)(actualPosition >> 48); + indexBuffer[15] = (byte)(actualPosition >> 56); + + indexBuffer[16] = (byte)(info.size); + indexBuffer[17] = (byte)(info.size >> 8); + indexBuffer[18] = (byte)(info.size >> 16); + indexBuffer[19] = (byte)(info.size >> 24); + + indexFile.Write(indexBuffer, 0, indexBuffer.Length); + + actualPosition += info.size; + } + } + + this.Close(); //We're done with this writer. + } + } +} \ No newline at end of file diff --git a/Server/Persistence/SaveMetrics.cs b/Server/Persistence/SaveMetrics.cs new file mode 100644 index 0000000..e2347b5 --- /dev/null +++ b/Server/Persistence/SaveMetrics.cs @@ -0,0 +1,131 @@ +/*************************************************************************** + * SaveMetrics.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: SaveMetrics.cs 632 2010-12-18 11:00:57Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Server { + public sealed class SaveMetrics : IDisposable { + private const string PerformanceCategoryName = "RunUO 2.1"; + private const string PerformanceCategoryDesc = "Performance counters for RunUO 2.1."; + + private PerformanceCounter numberOfWorldSaves; + + private PerformanceCounter itemsPerSecond; + private PerformanceCounter mobilesPerSecond; + + private PerformanceCounter serializedBytesPerSecond; + private PerformanceCounter writtenBytesPerSecond; + + public SaveMetrics() { + if ( !PerformanceCounterCategory.Exists( PerformanceCategoryName ) ) { + CounterCreationDataCollection counters = new CounterCreationDataCollection(); + + counters.Add( new CounterCreationData( + "Save - Count", + "Number of world saves.", + PerformanceCounterType.NumberOfItems32 + ) + ); + + counters.Add( new CounterCreationData( + "Save - Items/sec", + "Number of items saved per second.", + PerformanceCounterType.RateOfCountsPerSecond32 + ) + ); + + counters.Add( new CounterCreationData( + "Save - Mobiles/sec", + "Number of mobiles saved per second.", + PerformanceCounterType.RateOfCountsPerSecond32 + ) + ); + + counters.Add( new CounterCreationData( + "Save - Serialized bytes/sec", + "Amount of world-save bytes serialized per second.", + PerformanceCounterType.RateOfCountsPerSecond32 + ) + ); + + counters.Add( new CounterCreationData( + "Save - Written bytes/sec", + "Amount of world-save bytes written to disk per second.", + PerformanceCounterType.RateOfCountsPerSecond32 + ) + ); + +#if !MONO + PerformanceCounterCategory.Create( PerformanceCategoryName, PerformanceCategoryDesc, PerformanceCounterCategoryType.SingleInstance, counters ); +#endif + } + + numberOfWorldSaves = new PerformanceCounter( PerformanceCategoryName, "Save - Count", false ); + + itemsPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Items/sec", false ); + mobilesPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Mobiles/sec", false ); + + serializedBytesPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Serialized bytes/sec", false ); + writtenBytesPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Written bytes/sec", false ); + + // increment number of world saves + numberOfWorldSaves.Increment(); + } + + public void OnItemSaved( int numberOfBytes ) { + itemsPerSecond.Increment(); + + serializedBytesPerSecond.IncrementBy( numberOfBytes ); + } + + public void OnMobileSaved( int numberOfBytes ) { + mobilesPerSecond.Increment(); + + serializedBytesPerSecond.IncrementBy( numberOfBytes ); + } + + public void OnGuildSaved( int numberOfBytes ) { + serializedBytesPerSecond.IncrementBy( numberOfBytes ); + } + + public void OnFileWritten( int numberOfBytes ) { + writtenBytesPerSecond.IncrementBy( numberOfBytes ); + } + + private bool isDisposed; + + public void Dispose() { + if ( !isDisposed ) { + isDisposed = true; + + numberOfWorldSaves.Dispose(); + + itemsPerSecond.Dispose(); + mobilesPerSecond.Dispose(); + + serializedBytesPerSecond.Dispose(); + writtenBytesPerSecond.Dispose(); + } + } + } +} diff --git a/Server/Persistence/SaveStrategy.cs b/Server/Persistence/SaveStrategy.cs new file mode 100644 index 0000000..187db9d --- /dev/null +++ b/Server/Persistence/SaveStrategy.cs @@ -0,0 +1,61 @@ +/*************************************************************************** + * SaveStrategy.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: SaveStrategy.cs 844 2012-03-07 13:47:33Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server; + +namespace Server +{ + public abstract class SaveStrategy + { + public static SaveStrategy Acquire() + { + if (Core.MultiProcessor) + { + int processorCount = Core.ProcessorCount; + +#if Framework_4_0 + if (processorCount > 2) + { + return new DynamicSaveStrategy(); + } +#else + if (processorCount > 16) + { + return new ParallelSaveStrategy(processorCount); + } +#endif + else + { + return new DualSaveStrategy(); + } + } + else + { + return new StandardSaveStrategy(); + } + } + + public abstract string Name { get; } + public abstract void Save(SaveMetrics metrics, bool permitBackgroundWrite); + + public abstract void ProcessDecay(); + } +} \ No newline at end of file diff --git a/Server/Persistence/SequentialFileWriter.cs b/Server/Persistence/SequentialFileWriter.cs new file mode 100644 index 0000000..1cfe037 --- /dev/null +++ b/Server/Persistence/SequentialFileWriter.cs @@ -0,0 +1,141 @@ +/*************************************************************************** + * SequentialFileWriter.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: SequentialFileWriter.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Server { + public sealed class SequentialFileWriter : Stream { + private FileStream fileStream; + private FileQueue fileQueue; + + private AsyncCallback writeCallback; + + private SaveMetrics metrics; + + public SequentialFileWriter( string path, SaveMetrics metrics ) { + if ( path == null ) { + throw new ArgumentNullException( "path" ); + } + + this.metrics = metrics; + + this.fileStream = FileOperations.OpenSequentialStream( path, FileMode.Create, FileAccess.Write, FileShare.None ); + + fileQueue = new FileQueue( + Math.Max( 1, FileOperations.Concurrency ), + FileCallback + ); + } + + public override long Position { + get { + return fileQueue.Position; + } + set { + throw new InvalidOperationException(); + } + } + + private void FileCallback( FileQueue.Chunk chunk ) { + if ( FileOperations.AreSynchronous ) { + fileStream.Write( chunk.Buffer, chunk.Offset, chunk.Size ); + + if ( metrics != null ) { + metrics.OnFileWritten( chunk.Size ); + } + + chunk.Commit(); + } else { + if ( writeCallback == null ) { + writeCallback = this.OnWrite; + } + + fileStream.BeginWrite( chunk.Buffer, chunk.Offset, chunk.Size, writeCallback, chunk ); + } + } + + private void OnWrite( IAsyncResult asyncResult ) { + FileQueue.Chunk chunk = asyncResult.AsyncState as FileQueue.Chunk; + + fileStream.EndWrite( asyncResult ); + + if ( metrics != null ) { + metrics.OnFileWritten( chunk.Size ); + } + + chunk.Commit(); + } + + public override void Write( byte[] buffer, int offset, int size ) { + fileQueue.Enqueue( buffer, offset, size ); + } + + public override void Flush() { + fileQueue.Flush(); + fileStream.Flush(); + } + + protected override void Dispose( bool disposing ) { + if ( fileStream != null ) { + Flush(); + + fileQueue.Dispose(); + fileQueue = null; + + fileStream.Close(); + fileStream = null; + } + + base.Dispose( disposing ); + } + + public override bool CanRead { + get { return false; } + } + + public override bool CanSeek { + get { return false; } + } + + public override bool CanWrite { + get { return true; } + } + + public override long Length { + get { return this.Position; } + } + + public override int Read( byte[] buffer, int offset, int count ) { + throw new InvalidOperationException(); + } + + public override long Seek( long offset, SeekOrigin origin ) { + throw new InvalidOperationException(); + } + + public override void SetLength( long value ) { + fileStream.SetLength( value ); + } + } +} \ No newline at end of file diff --git a/Server/Persistence/StandardSaveStrategy.cs b/Server/Persistence/StandardSaveStrategy.cs new file mode 100644 index 0000000..e75ac37 --- /dev/null +++ b/Server/Persistence/StandardSaveStrategy.cs @@ -0,0 +1,232 @@ +/*************************************************************************** + * StandardSaveStrategy.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: StandardSaveStrategy.cs 828 2012-02-11 04:36:54Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Threading; +using System.Diagnostics; + +using Server; +using Server.Guilds; + +namespace Server +{ + public class StandardSaveStrategy : SaveStrategy + { + public enum SaveOption + { + Normal, + Threaded + } + + public static SaveOption SaveType = SaveOption.Normal; + + public override string Name + { + get { return "Standard"; } + } + + private Queue _decayQueue; + private bool _permitBackgroundWrite; + + public StandardSaveStrategy() + { + _decayQueue = new Queue(); + } + + protected bool PermitBackgroundWrite { get { return _permitBackgroundWrite; } set { _permitBackgroundWrite = value; } } + + protected bool UseSequentialWriters { get { return (StandardSaveStrategy.SaveType == SaveOption.Normal || !_permitBackgroundWrite); } } + + public override void Save(SaveMetrics metrics, bool permitBackgroundWrite) + { + _permitBackgroundWrite = permitBackgroundWrite; + + SaveMobiles(metrics); + SaveItems(metrics); + SaveGuilds(metrics); + + if (permitBackgroundWrite && UseSequentialWriters) //If we're permitted to write in the background, but we don't anyways, then notify. + World.NotifyDiskWriteComplete(); + } + + protected void SaveMobiles(SaveMetrics metrics) + { + Dictionary mobiles = World.Mobiles; + + GenericWriter idx; + GenericWriter tdb; + GenericWriter bin; + + if (UseSequentialWriters) + { + idx = new BinaryFileWriter(World.MobileIndexPath, false); + tdb = new BinaryFileWriter(World.MobileTypesPath, false); + bin = new BinaryFileWriter(World.MobileDataPath, true); + } + else + { + idx = new AsyncWriter(World.MobileIndexPath, false); + tdb = new AsyncWriter(World.MobileTypesPath, false); + bin = new AsyncWriter(World.MobileDataPath, true); + } + + idx.Write((int)mobiles.Count); + foreach (Mobile m in mobiles.Values) + { + long start = bin.Position; + + idx.Write((int)m.m_TypeRef); + idx.Write((int)m.Serial); + idx.Write((long)start); + + m.Serialize(bin); + + if (metrics != null) + { + metrics.OnMobileSaved((int)(bin.Position - start)); + } + + idx.Write((int)(bin.Position - start)); + + m.FreeCache(); + } + + tdb.Write((int)World.m_MobileTypes.Count); + + for (int i = 0; i < World.m_MobileTypes.Count; ++i) + tdb.Write(World.m_MobileTypes[i].FullName); + + idx.Close(); + tdb.Close(); + bin.Close(); + } + + protected void SaveItems(SaveMetrics metrics) + { + Dictionary items = World.Items; + + GenericWriter idx; + GenericWriter tdb; + GenericWriter bin; + + if (UseSequentialWriters) + { + idx = new BinaryFileWriter(World.ItemIndexPath, false); + tdb = new BinaryFileWriter(World.ItemTypesPath, false); + bin = new BinaryFileWriter(World.ItemDataPath, true); + } + else + { + idx = new AsyncWriter(World.ItemIndexPath, false); + tdb = new AsyncWriter(World.ItemTypesPath, false); + bin = new AsyncWriter(World.ItemDataPath, true); + } + + idx.Write((int)items.Count); + foreach (Item item in items.Values) + { + if (item.Decays && item.Parent == null && item.Map != Map.Internal && (item.LastMoved + item.DecayTime) <= DateTime.Now) + { + _decayQueue.Enqueue(item); + } + + long start = bin.Position; + + idx.Write((int)item.m_TypeRef); + idx.Write((int)item.Serial); + idx.Write((long)start); + + item.Serialize(bin); + + if (metrics != null) + { + metrics.OnItemSaved((int)(bin.Position - start)); + } + + idx.Write((int)(bin.Position - start)); + + item.FreeCache(); + } + + tdb.Write((int)World.m_ItemTypes.Count); + for (int i = 0; i < World.m_ItemTypes.Count; ++i) + tdb.Write(World.m_ItemTypes[i].FullName); + + idx.Close(); + tdb.Close(); + bin.Close(); + } + + protected void SaveGuilds(SaveMetrics metrics) + { + GenericWriter idx; + GenericWriter bin; + + if (UseSequentialWriters) + { + idx = new BinaryFileWriter(World.GuildIndexPath, false); + bin = new BinaryFileWriter(World.GuildDataPath, true); + } + else + { + idx = new AsyncWriter(World.GuildIndexPath, false); + bin = new AsyncWriter(World.GuildDataPath, true); + } + + idx.Write((int)BaseGuild.List.Count); + foreach (BaseGuild guild in BaseGuild.List.Values) + { + long start = bin.Position; + + idx.Write((int)0);//guilds have no typeid + idx.Write((int)guild.Id); + idx.Write((long)start); + + guild.Serialize(bin); + + if (metrics != null) + { + metrics.OnGuildSaved((int)(bin.Position - start)); + } + + idx.Write((int)(bin.Position - start)); + } + + idx.Close(); + bin.Close(); + } + + public override void ProcessDecay() + { + while (_decayQueue.Count > 0) + { + Item item = _decayQueue.Dequeue(); + + if (item.OnDecay()) + { + item.Delete(); + } + } + } + } +} \ No newline at end of file diff --git a/Server/Point3DList.cs b/Server/Point3DList.cs new file mode 100644 index 0000000..cb7febd --- /dev/null +++ b/Server/Point3DList.cs @@ -0,0 +1,113 @@ +/*************************************************************************** + * Point3DList.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Point3DList.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public class Point3DList + { + private Point3D[] m_List; + private int m_Count; + + public Point3DList() + { + m_List = new Point3D[8]; + m_Count = 0; + } + + public int Count + { + get + { + return m_Count; + } + } + + public void Clear() + { + m_Count = 0; + } + + public Point3D Last + { + get{ return m_List[m_Count - 1]; } + } + + public Point3D this[int index] + { + get + { + return m_List[index]; + } + } + + public void Add( int x, int y, int z ) + { + if ( (m_Count + 1) > m_List.Length ) + { + Point3D[] old = m_List; + m_List = new Point3D[old.Length * 2]; + + for ( int i = 0; i < old.Length; ++i ) + m_List[i] = old[i]; + } + + m_List[m_Count].m_X = x; + m_List[m_Count].m_Y = y; + m_List[m_Count].m_Z = z; + ++m_Count; + } + + public void Add( Point3D p ) + { + if ( (m_Count + 1) > m_List.Length ) + { + Point3D[] old = m_List; + m_List = new Point3D[old.Length * 2]; + + for ( int i = 0; i < old.Length; ++i ) + m_List[i] = old[i]; + } + + m_List[m_Count].m_X = p.m_X; + m_List[m_Count].m_Y = p.m_Y; + m_List[m_Count].m_Z = p.m_Z; + ++m_Count; + } + + private static Point3D[] m_EmptyList = new Point3D[0]; + + public Point3D[] ToArray() + { + if ( m_Count == 0 ) + return m_EmptyList; + + Point3D[] list = new Point3D[m_Count]; + + for ( int i = 0; i < m_Count; ++i ) + list[i] = m_List[i]; + + m_Count = 0; + + return list; + } + } +} \ No newline at end of file diff --git a/Server/Poison.cs b/Server/Poison.cs new file mode 100644 index 0000000..dd54352 --- /dev/null +++ b/Server/Poison.cs @@ -0,0 +1,144 @@ +/*************************************************************************** + * Poison.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Poison.cs 511 2010-04-25 06:09:43Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server +{ + [Parsable] + public abstract class Poison + { + /*public abstract TimeSpan Interval{ get; } + public abstract TimeSpan Duration{ get; }*/ + public abstract string Name { get; } + public abstract int Level { get; } + public abstract Timer ConstructTimer( Mobile m ); + /*public abstract void OnDamage( Mobile m, ref object state );*/ + + public override string ToString() + { + return this.Name; + } + + + private static List m_Poisons = new List(); + + public static void Register( Poison reg ) + { + string regName = reg.Name.ToLower(); + + for ( int i = 0; i < m_Poisons.Count; i++ ) + { + if ( reg.Level == m_Poisons[i].Level ) + throw new Exception( "A poison with that level already exists." ); + else if ( regName == m_Poisons[i].Name.ToLower() ) + throw new Exception( "A poison with that name already exists." ); + } + + m_Poisons.Add( reg ); + } + + public static Poison Lesser { get { return GetPoison( "Lesser" ); } } + public static Poison Regular { get { return GetPoison( "Regular" ); } } + public static Poison Greater { get { return GetPoison( "Greater" ); } } + public static Poison Deadly { get { return GetPoison( "Deadly" ); } } + public static Poison Lethal { get { return GetPoison( "Lethal" ); } } + + public static List Poisons + { + get + { + return m_Poisons; + } + } + + public static Poison Parse( string value ) + { + Poison p = null; + + int plevel; + + if ( int.TryParse( value, out plevel ) ) + p = GetPoison( plevel ); + + if ( p == null ) + p = GetPoison( value ); + + return p; + } + + public static Poison GetPoison( int level ) + { + for ( int i = 0; i < m_Poisons.Count; ++i ) + { + Poison p = m_Poisons[i]; + + if ( p.Level == level ) + return p; + } + + return null; + } + + public static Poison GetPoison( string name ) + { + for ( int i = 0; i < m_Poisons.Count; ++i ) + { + Poison p = m_Poisons[i]; + + if ( Utility.InsensitiveCompare( p.Name, name ) == 0 ) + return p; + } + + return null; + } + + public static void Serialize( Poison p, GenericWriter writer ) + { + if ( p == null ) + { + writer.Write( (byte)0 ); + } + else + { + writer.Write( (byte)1 ); + writer.Write( (byte)p.Level ); + } + } + + public static Poison Deserialize( GenericReader reader ) + { + switch ( reader.ReadByte() ) + { + case 1: return GetPoison( reader.ReadByte() ); + case 2: + //no longer used, safe to remove? + reader.ReadInt(); + reader.ReadDouble(); + reader.ReadInt(); + reader.ReadTimeSpan(); + break; + } + return null; + } + } +} diff --git a/Server/Prompt.cs b/Server/Prompt.cs new file mode 100644 index 0000000..c538d12 --- /dev/null +++ b/Server/Prompt.cs @@ -0,0 +1,55 @@ +/*************************************************************************** + * Prompt.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Prompt.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Prompts +{ + public abstract class Prompt + { + private int m_Serial; + private static int m_Serials; + + public int Serial + { + get + { + return m_Serial; + } + } + + protected Prompt() + { + do + { + m_Serial = ++m_Serials; + } while ( m_Serial == 0 ); + } + + public virtual void OnCancel( Mobile from ) + { + } + + public virtual void OnResponse( Mobile from, string text ) + { + } + } +} \ No newline at end of file diff --git a/Server/QuestArrow.cs b/Server/QuestArrow.cs new file mode 100644 index 0000000..93570ed --- /dev/null +++ b/Server/QuestArrow.cs @@ -0,0 +1,123 @@ +/*************************************************************************** + * QuestArrow.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: QuestArrow.cs 619 2010-12-12 23:55:08Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server; +using Server.Network; + +namespace Server +{ + public class QuestArrow + { + private Mobile m_Mobile; + private Mobile m_Target; + private bool m_Running; + + public Mobile Mobile + { + get + { + return m_Mobile; + } + } + + public Mobile Target + { + get + { + return m_Target; + } + } + + public bool Running + { + get + { + return m_Running; + } + } + + public void Update() + { + Update( m_Target.X, m_Target.Y ); + } + + public void Update( int x, int y ) + { + if ( !m_Running ) + return; + + NetState ns = m_Mobile.NetState; + + if ( ns == null ) + return; + + if ( ns.HighSeas ) + ns.Send( new SetArrowHS( x, y, m_Target.Serial ) ); + else + ns.Send( new SetArrow( x, y ) ); + } + + public void Stop() + { + Stop( m_Target.X, m_Target.Y ); + } + + public void Stop( int x, int y ) + { + if ( !m_Running ) + return; + + m_Mobile.ClearQuestArrow(); + + NetState ns = m_Mobile.NetState; + + if ( ns != null ) { + if ( ns.HighSeas ) + ns.Send( new CancelArrowHS( x, y, m_Target.Serial ) ); + else + ns.Send( new CancelArrow() ); + } + + m_Running = false; + OnStop(); + } + + public virtual void OnStop() + { + } + + public virtual void OnClick( bool rightClick ) + { + } + + public QuestArrow( Mobile m, Mobile t ) + { + m_Running = true; + m_Mobile = m; + m_Target = t; + } + + public QuestArrow( Mobile m, Mobile t, int x, int y ) : this( m, t ) + { + Update( x, y ); + } + } +} \ No newline at end of file diff --git a/Server/Race.cs b/Server/Race.cs new file mode 100644 index 0000000..564db96 --- /dev/null +++ b/Server/Race.cs @@ -0,0 +1,211 @@ +/*************************************************************************** + * Race.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Race.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Server.Network; + +namespace Server +{ + [Parsable] + public abstract class Race + { + public static Race DefaultRace { get { return m_Races[0]; } } + + private static Race[] m_Races = new Race[0x100]; + + public static Race[] Races { get { return m_Races; } } + + public static Race Human { get { return m_Races[0]; } } + public static Race Elf { get { return m_Races[1]; } } + + private static List m_AllRaces = new List(); + + public static List AllRaces { get { return m_AllRaces; } } + + private int m_RaceID, m_RaceIndex; + + private string m_Name, m_PluralName; + + private static string[] m_RaceNames; + private static Race[] m_RaceValues; + + public static string[] GetRaceNames() + { + CheckNamesAndValues(); + return m_RaceNames; + } + + public static Race[] GetRaceValues() + { + CheckNamesAndValues(); + return m_RaceValues; + } + + public static Race Parse( string value ) + { + CheckNamesAndValues(); + + for( int i = 0; i < m_RaceNames.Length; ++i ) + { + if( Insensitive.Equals( m_RaceNames[i], value ) ) + return m_RaceValues[i]; + } + + int index; + if( int.TryParse( value, out index ) ) + { + if( index >= 0 && index < m_Races.Length && m_Races[index] != null ) + return m_Races[index]; + } + + throw new ArgumentException( "Invalid race name" ); + } + + private static void CheckNamesAndValues() + { + if( m_RaceNames != null && m_RaceNames.Length == m_AllRaces.Count ) + return; + + m_RaceNames = new string[m_AllRaces.Count]; + m_RaceValues = new Race[m_AllRaces.Count]; + + for( int i = 0; i < m_AllRaces.Count; ++i ) + { + Race race = m_AllRaces[i]; + + m_RaceNames[i] = race.Name; + m_RaceValues[i] = race; + } + } + + public override string ToString() + { + return m_Name; + } + + private int m_MaleBody, m_FemaleBody, m_MaleGhostBody, m_FemaleGhostBody; + + private Expansion m_RequiredExpansion; + + public Expansion RequiredExpansion { get { return m_RequiredExpansion; } } + + public int MaleBody { get { return m_MaleBody; } } + public int MaleGhostBody { get { return m_MaleGhostBody; } } + + public int FemaleBody { get { return m_FemaleBody; } } + public int FemaleGhostBody { get { return m_FemaleGhostBody; } } + + protected Race( int raceID, int raceIndex, string name, string pluralName, int maleBody, int femaleBody, int maleGhostBody, int femaleGhostBody, Expansion requiredExpansion ) + { + m_RaceID = raceID; + m_RaceIndex = raceIndex; + + m_Name = name; + + m_MaleBody = maleBody; + m_FemaleBody = femaleBody; + m_MaleGhostBody = maleGhostBody; + m_FemaleGhostBody = femaleGhostBody; + + m_RequiredExpansion = requiredExpansion; + m_PluralName = pluralName; + } + + public virtual bool ValidateHair( Mobile m, int itemID ) { return ValidateHair( m.Female, itemID ); } + public abstract bool ValidateHair( bool female, int itemID ); + + public virtual int RandomHair( Mobile m ) { return RandomHair( m.Female ); } + public abstract int RandomHair( bool female ); + + public virtual bool ValidateFacialHair( Mobile m, int itemID ) { return ValidateFacialHair( m.Female, itemID ); } + public abstract bool ValidateFacialHair( bool female, int itemID ); + + public virtual int RandomFacialHair( Mobile m ) { return RandomFacialHair( m.Female ); } + public abstract int RandomFacialHair( bool female ); //For the *ahem* bearded ladies + + public abstract int ClipSkinHue( int hue ); + public abstract int RandomSkinHue(); + + public abstract int ClipHairHue( int hue ); + public abstract int RandomHairHue(); + + public virtual int Body( Mobile m ) + { + if( m.Alive ) + return AliveBody( m.Female ); + + return GhostBody( m.Female ); + } + + public virtual int AliveBody( Mobile m ) { return AliveBody( m.Female ); } + public virtual int AliveBody( bool female ) + { + return (female ? m_FemaleBody : m_MaleBody); + } + + public virtual int GhostBody( Mobile m ) { return GhostBody( m.Female ); } + public virtual int GhostBody( bool female ) + { + return (female ? m_FemaleGhostBody : m_MaleGhostBody); + } + + public int RaceID + { + get + { + return m_RaceID; + } + } + + public int RaceIndex + { + get + { + return m_RaceIndex; + } + } + + public string Name + { + get + { + return m_Name; + } + set + { + m_Name = value; + } + } + + public string PluralName + { + get + { + return m_PluralName; + } + set + { + m_PluralName = value; + } + } + } +} \ No newline at end of file diff --git a/Server/Region.cs b/Server/Region.cs new file mode 100644 index 0000000..73177cf --- /dev/null +++ b/Server/Region.cs @@ -0,0 +1,1320 @@ +/*************************************************************************** + * Region.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Region.cs 844 2012-03-07 13:47:33Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Xml; +using Server.Network; +using Server.Targeting; + +namespace Server +{ + public enum MusicName + { + Invalid = -1, + OldUlt01 = 0, + Create1, + DragFlit, + OldUlt02, + OldUlt03, + OldUlt04, + OldUlt05, + OldUlt06, + Stones2, + Britain1, + Britain2, + Bucsden, + Jhelom, + LBCastle, + Linelle, + Magincia, + Minoc, + Ocllo, + Samlethe, + Serpents, + Skarabra, + Trinsic, + Vesper, + Wind, + Yew, + Cave01, + Dungeon9, + Forest_a, + InTown01, + Jungle_a, + Mountn_a, + Plains_a, + Sailing, + Swamp_a, + Tavern01, + Tavern02, + Tavern03, + Tavern04, + Combat1, + Combat2, + Combat3, + Approach, + Death, + Victory, + BTCastle, + Nujelm, + Dungeon2, + Cove, + Moonglow, + Zento, + TokunoDungeon, + Taiko, + DreadHornArea, + ElfCity, + GrizzleDungeon, + MelisandesLair, + ParoxysmusLair, + GwennoConversation, + GoodEndGame, + GoodVsEvil, + GreatEarthSerpents, + Humanoids_U9, + MinocNegative, + Paws, + SelimsBar, + SerpentIsleCombat_U7, + ValoriaShips, + // Scriptiz : ajout des nouvelles musiques + TheWanderer, // 67 + Castle, + Festival, + Honor, + Medieval, + BattleOnStones, + Docktown, + GargoyleQueen, + GenericCombat, + Holycity, + HumanLevel, + LoginLoop, + NorthernForestBattleonStones, + PrimevalLich, + QueenPalace, + RoyalCity, + SlasherVeil, + StygianAbyss, + StygianDragon, + Void, + CodexShrine // 87 + } + + public class Region : IComparable + { + private static List m_Regions = new List(); + + public static List Regions{ get{ return m_Regions; } } + + public static Region Find( Point3D p, Map map ) + { + if ( map == null ) + return Map.Internal.DefaultRegion; + + Sector sector = map.GetSector( p ); + List list = sector.RegionRects; + + for ( int i = 0; i < list.Count; ++i ) + { + RegionRect regRect = list[i]; + + if ( regRect.Contains( p ) ) + return regRect.Region; + } + + return map.DefaultRegion; + } + + private static Type m_DefaultRegionType = typeof( Region ); + public static Type DefaultRegionType{ get{ return m_DefaultRegionType; } set{ m_DefaultRegionType = value; } } + + private static TimeSpan m_StaffLogoutDelay = TimeSpan.Zero; + private static TimeSpan m_DefaultLogoutDelay = TimeSpan.FromMinutes(5.0); + + public static TimeSpan StaffLogoutDelay{ get{ return m_StaffLogoutDelay; } set{ m_StaffLogoutDelay = value; } } + public static TimeSpan DefaultLogoutDelay{ get{ return m_DefaultLogoutDelay; } set{ m_DefaultLogoutDelay = value; } } + + public static readonly int DefaultPriority = 50; + + public static readonly int MinZ = sbyte.MinValue; + public static readonly int MaxZ = sbyte.MaxValue + 1; + + public static Rectangle3D ConvertTo3D( Rectangle2D rect ) + { + return new Rectangle3D( new Point3D( rect.Start, MinZ ), new Point3D( rect.End, MaxZ ) ); + } + + public static Rectangle3D[] ConvertTo3D( Rectangle2D[] rects ) + { + Rectangle3D[] ret = new Rectangle3D[rects.Length]; + + for ( int i = 0; i < ret.Length; i++ ) + { + ret[i] = ConvertTo3D( rects[i] ); + } + + return ret; + } + + + private string m_Name; + private Map m_Map; + private Region m_Parent; + private List m_Children = new List(); + private Rectangle3D[] m_Area; + private Sector[] m_Sectors; + private bool m_Dynamic; + private int m_Priority; + private int m_ChildLevel; + private bool m_Registered; + + private Point3D m_GoLocation; + private MusicName m_Music; + + public string Name{ get{ return m_Name; } } + public Map Map{ get{ return m_Map; } } + public Region Parent{ get{ return m_Parent; } } + public List Children{ get{ return m_Children; } } + public Rectangle3D[] Area{ get{ return m_Area; } } + public Sector[] Sectors{ get{ return m_Sectors; } } + public bool Dynamic{ get{ return m_Dynamic; } } + public int Priority{ get{ return m_Priority; } } + public int ChildLevel{ get{ return m_ChildLevel; } } + public bool Registered{ get{ return m_Registered; } } + + public Point3D GoLocation{ get{ return m_GoLocation; } set { m_GoLocation = value; } } + public MusicName Music{ get{ return m_Music; } set{ m_Music = value; } } + + public bool IsDefault{ get{ return m_Map.DefaultRegion == this; } } + public virtual MusicName DefaultMusic{ get{ return m_Parent != null ? m_Parent.Music : MusicName.Invalid; } } + + public Region( string name, Map map, int priority, params Rectangle2D[] area ) : this( name, map, priority, ConvertTo3D( area ) ) + { + } + + public Region( string name, Map map, int priority, params Rectangle3D[] area ) : this( name, map, null, area ) + { + m_Priority = priority; + } + + public Region( string name, Map map, Region parent, params Rectangle2D[] area ) : this( name, map, parent, ConvertTo3D( area ) ) + { + } + + public Region( string name, Map map, Region parent, params Rectangle3D[] area ) + { + m_Name = name; + m_Map = map; + m_Parent = parent; + m_Area = area; + m_Dynamic = true; + m_Music = this.DefaultMusic; + + if ( m_Parent == null ) + { + m_ChildLevel = 0; + m_Priority = DefaultPriority; + } + else + { + m_ChildLevel = m_Parent.ChildLevel + 1; + m_Priority = m_Parent.Priority; + } + } + + public void Register() + { + if ( m_Registered ) + return; + + OnRegister(); + + m_Registered = true; + + if ( m_Parent != null ) + { + m_Parent.m_Children.Add( this ); + m_Parent.OnChildAdded( this ); + } + + m_Regions.Add( this ); + + m_Map.RegisterRegion( this ); + + List sectors = new List(); + + for ( int i = 0; i < m_Area.Length; i++ ) + { + Rectangle3D rect = m_Area[i]; + + Point2D start = m_Map.Bound( new Point2D( rect.Start ) ); + Point2D end = m_Map.Bound( new Point2D( rect.End ) ); + + Sector startSector = m_Map.GetSector( start ); + Sector endSector = m_Map.GetSector( end ); + + for ( int x = startSector.X; x <= endSector.X; x++ ) + { + for ( int y = startSector.Y; y <= endSector.Y; y++ ) + { + Sector sector = m_Map.GetRealSector( x, y ); + + sector.OnEnter( this, rect ); + + if ( !sectors.Contains( sector ) ) + sectors.Add( sector ); + } + } + } + + m_Sectors = sectors.ToArray(); + } + + public void Unregister() + { + if ( !m_Registered ) + return; + + OnUnregister(); + + m_Registered = false; + + if ( m_Children.Count > 0 ) + Console.WriteLine( "Warning: Unregistering region '{0}' with children", this ); + + if ( m_Parent != null ) + { + m_Parent.m_Children.Remove( this ); + m_Parent.OnChildRemoved( this ); + } + + m_Regions.Remove( this ); + + m_Map.UnregisterRegion( this ); + + if ( m_Sectors != null ) + { + for ( int i = 0; i < m_Sectors.Length; i++ ) + m_Sectors[i].OnLeave( this ); + } + + m_Sectors = null; + } + + public bool Contains( Point3D p ) + { + for ( int i = 0; i < m_Area.Length; i++ ) + { + Rectangle3D rect = m_Area[i]; + + if ( rect.Contains( p ) ) + return true; + } + + return false; + } + + public bool IsChildOf( Region region ) + { + if ( region == null ) + return false; + + Region p = m_Parent; + + while ( p != null ) + { + if ( p == region ) + return true; + + p = p.m_Parent; + } + + return false; + } + + public Region GetRegion( Type regionType ) + { + if ( regionType == null ) + return null; + + Region r = this; + + do + { + if ( regionType.IsAssignableFrom( r.GetType() ) ) + return r; + + r = r.m_Parent; + } + while ( r != null ); + + return null; + } + + public Region GetRegion( string regionName ) + { + if ( regionName == null ) + return null; + + Region r = this; + + do + { + if ( r.m_Name == regionName ) + return r; + + r = r.m_Parent; + } + while ( r != null ); + + return null; + } + + public bool IsPartOf( Region region ) + { + if ( this == region ) + return true; + + return IsChildOf( region ); + } + + public bool IsPartOf( Type regionType ) + { + return ( GetRegion( regionType ) != null ); + } + + public bool IsPartOf( string regionName ) + { + return ( GetRegion( regionName ) != null ); + } + + public virtual bool AcceptsSpawnsFrom( Region region ) + { + if ( !AllowSpawn() ) + return false; + + if ( region == this ) + return true; + + if ( m_Parent != null ) + return m_Parent.AcceptsSpawnsFrom( region ); + + return false; + } + + public List GetPlayers() + { + List list = new List(); + + if ( m_Sectors != null ) + { + for ( int i = 0; i < m_Sectors.Length; i++ ) + { + Sector sector = m_Sectors[i]; + + foreach ( Mobile player in sector.Players ) + { + if ( player.Region.IsPartOf( this ) ) + list.Add( player ); + } + } + } + + return list; + } + + public int GetPlayerCount() + { + int count = 0; + + if ( m_Sectors != null ) + { + for ( int i = 0; i < m_Sectors.Length; i++ ) + { + Sector sector = m_Sectors[i]; + + foreach ( Mobile player in sector.Players ) + { + if ( player.Region.IsPartOf( this ) ) + count++; + } + } + } + + return count; + } + + public List GetMobiles() + { + List list = new List(); + + if ( m_Sectors != null ) + { + for ( int i = 0; i < m_Sectors.Length; i++ ) + { + Sector sector = m_Sectors[i]; + + foreach ( Mobile mobile in sector.Mobiles ) + { + if ( mobile.Region.IsPartOf( this ) ) + list.Add( mobile ); + } + } + } + + return list; + } + + public int GetMobileCount() + { + int count = 0; + + if ( m_Sectors != null ) + { + for ( int i = 0; i < m_Sectors.Length; i++ ) + { + Sector sector = m_Sectors[i]; + + foreach ( Mobile mobile in sector.Mobiles ) + { + if ( mobile.Region.IsPartOf( this ) ) + count++; + } + } + } + + return count; + } + + int IComparable.CompareTo( object obj ) + { + if ( obj == null ) + return 1; + + Region reg = obj as Region; + + if ( reg == null ) + throw new ArgumentException( "obj is not a Region", "obj" ); + + // Dynamic regions go first + if ( this.Dynamic ) + { + if ( !reg.Dynamic ) + return -1; + } + else if ( reg.Dynamic ) + { + return 1; + } + + int thisPriority = this.Priority; + int regPriority = reg.Priority; + + if ( thisPriority != regPriority ) + return ( regPriority - thisPriority ); + + return ( reg.ChildLevel - this.ChildLevel ); + } + + public override string ToString() + { + if ( m_Name != null ) + return m_Name; + else + return GetType().Name; + } + + + public virtual void OnRegister() + { + } + + public virtual void OnUnregister() + { + } + + public virtual void OnChildAdded( Region child ) + { + } + + public virtual void OnChildRemoved( Region child ) + { + } + + public virtual bool OnMoveInto( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation ) + { + return ( m.WalkRegion == null || AcceptsSpawnsFrom( m.WalkRegion ) ); + } + + public virtual void OnEnter( Mobile m ) + { + } + + public virtual void OnExit( Mobile m ) + { + } + + public virtual void MakeGuard( Mobile focus ) + { + if ( m_Parent != null ) + m_Parent.MakeGuard( focus ); + } + + public virtual Type GetResource( Type type ) + { + if ( m_Parent != null ) + return m_Parent.GetResource( type ); + + return type; + } + + public virtual bool CanUseStuckMenu( Mobile m ) + { + if ( m_Parent != null ) + return m_Parent.CanUseStuckMenu( m ); + + return true; + } + + public virtual void OnAggressed( Mobile aggressor, Mobile aggressed, bool criminal ) + { + if ( m_Parent != null ) + m_Parent.OnAggressed( aggressor, aggressed, criminal ); + } + + public virtual void OnDidHarmful( Mobile harmer, Mobile harmed ) + { + if ( m_Parent != null ) + m_Parent.OnDidHarmful( harmer, harmed ); + } + + public virtual void OnGotHarmful( Mobile harmer, Mobile harmed ) + { + if ( m_Parent != null ) + m_Parent.OnGotHarmful( harmer, harmed ); + } + + public virtual void OnLocationChanged( Mobile m, Point3D oldLocation ) + { + if ( m_Parent != null ) + m_Parent.OnLocationChanged( m, oldLocation ); + } + + public virtual bool OnTarget( Mobile m, Target t, object o ) + { + if ( m_Parent != null ) + return m_Parent.OnTarget( m, t, o ); + + return true; + } + + public virtual bool OnCombatantChange( Mobile m, Mobile Old, Mobile New ) + { + if ( m_Parent != null ) + return m_Parent.OnCombatantChange( m, Old, New ); + + return true; + } + + public virtual bool AllowHousing( Mobile from, Point3D p ) + { + if ( m_Parent != null ) + return m_Parent.AllowHousing( from, p ); + + return true; + } + + public virtual bool SendInaccessibleMessage( Item item, Mobile from ) + { + if ( m_Parent != null ) + return m_Parent.SendInaccessibleMessage( item, from ); + + return false; + } + + public virtual bool CheckAccessibility( Item item, Mobile from ) + { + if ( m_Parent != null ) + return m_Parent.CheckAccessibility( item, from ); + + return true; + } + + public virtual bool OnDecay( Item item ) + { + if ( m_Parent != null ) + return m_Parent.OnDecay( item ); + + return true; + } + + public virtual bool AllowHarmful( Mobile from, Mobile target ) + { + if ( m_Parent != null ) + return m_Parent.AllowHarmful( from, target ); + + if ( Mobile.AllowHarmfulHandler != null ) + return Mobile.AllowHarmfulHandler( from, target ); + + return true; + } + + public virtual void OnCriminalAction( Mobile m, bool message ) + { + if ( m_Parent != null ) + m_Parent.OnCriminalAction( m, message ); + else if ( message ) + m.SendLocalizedMessage( 1005040 ); // You've committed a criminal act!! + } + + public virtual bool AllowBeneficial( Mobile from, Mobile target ) + { + if ( m_Parent != null ) + return m_Parent.AllowBeneficial( from, target ); + + if ( Mobile.AllowBeneficialHandler != null ) + return Mobile.AllowBeneficialHandler( from, target ); + + return true; + } + + public virtual void OnBeneficialAction( Mobile helper, Mobile target ) + { + if ( m_Parent != null ) + m_Parent.OnBeneficialAction( helper, target ); + } + + public virtual void OnGotBeneficialAction( Mobile helper, Mobile target ) + { + if ( m_Parent != null ) + m_Parent.OnGotBeneficialAction( helper, target ); + } + + public virtual void SpellDamageScalar( Mobile caster, Mobile target, ref double damage ) + { + if ( m_Parent != null ) + m_Parent.SpellDamageScalar( caster, target, ref damage ); + } + + public virtual void OnSpeech( SpeechEventArgs args ) + { + if ( m_Parent != null ) + m_Parent.OnSpeech( args ); + } + + public virtual bool OnSkillUse( Mobile m, int Skill ) + { + if ( m_Parent != null ) + return m_Parent.OnSkillUse( m, Skill ); + + return true; + } + + public virtual bool OnBeginSpellCast( Mobile m, ISpell s ) + { + if ( m_Parent != null ) + return m_Parent.OnBeginSpellCast( m, s ); + + return true; + } + + public virtual void OnSpellCast( Mobile m, ISpell s ) + { + if ( m_Parent != null ) + m_Parent.OnSpellCast( m, s ); + } + + public virtual bool OnResurrect( Mobile m ) + { + if ( m_Parent != null ) + return m_Parent.OnResurrect( m ); + + return true; + } + + public virtual bool OnBeforeDeath( Mobile m ) + { + if ( m_Parent != null ) + return m_Parent.OnBeforeDeath( m ); + + return true; + } + + public virtual void OnDeath( Mobile m ) + { + if ( m_Parent != null ) + m_Parent.OnDeath( m ); + } + + public virtual bool OnDamage( Mobile m, ref int Damage ) + { + if ( m_Parent != null ) + return m_Parent.OnDamage( m, ref Damage ); + + return true; + } + + public virtual bool OnHeal( Mobile m, ref int Heal ) + { + if ( m_Parent != null ) + return m_Parent.OnHeal( m, ref Heal ); + + return true; + } + + public virtual bool OnDoubleClick( Mobile m, object o ) + { + if ( m_Parent != null ) + return m_Parent.OnDoubleClick( m, o ); + + return true; + } + + public virtual bool OnSingleClick( Mobile m, object o ) + { + if ( m_Parent != null ) + return m_Parent.OnSingleClick( m, o ); + + return true; + } + + public virtual bool AllowSpawn() + { + if ( m_Parent != null ) + return m_Parent.AllowSpawn(); + + return true; + } + + public virtual void AlterLightLevel( Mobile m, ref int global, ref int personal ) + { + if ( m_Parent != null ) + m_Parent.AlterLightLevel( m, ref global, ref personal ); + } + + public virtual TimeSpan GetLogoutDelay( Mobile m ) + { + if ( m_Parent != null ) + return m_Parent.GetLogoutDelay( m ); + else if ( m.AccessLevel > AccessLevel.Player ) + return m_StaffLogoutDelay; + else + return m_DefaultLogoutDelay; + } + + + internal static bool CanMove( Mobile m, Direction d, Point3D newLocation, Point3D oldLocation, Map map ) + { + Region oldRegion = m.Region; + Region newRegion = Find( newLocation, map ); + + while ( oldRegion != newRegion ) + { + if ( !newRegion.OnMoveInto( m, d, newLocation, oldLocation ) ) + return false; + + if ( newRegion.m_Parent == null ) + return true; + + newRegion = newRegion.m_Parent; + } + + return true; + } + + internal static void OnRegionChange( Mobile m, Region oldRegion, Region newRegion ) + { + if ( newRegion != null && m.NetState != null ) + { + m.CheckLightLevels( false ); + + if ( oldRegion == null || oldRegion.Music != newRegion.Music ) + { + m.Send( PlayMusic.GetInstance( newRegion.Music ) ); + } + } + + Region oldR = oldRegion; + Region newR = newRegion; + + while ( oldR != newR ) + { + int oldRChild = ( oldR != null ? oldR.ChildLevel : -1 ); + int newRChild = ( newR != null ? newR.ChildLevel : -1 ); + + if ( oldRChild >= newRChild ) + { + oldR.OnExit( m ); + oldR = oldR.Parent; + } + + if ( newRChild >= oldRChild ) + { + newR.OnEnter( m ); + newR = newR.Parent; + } + } + } + + + internal static void Load() + { + if ( !System.IO.File.Exists( "Data/Regions.xml" ) ) + { + Console.WriteLine( "Error: Data/Regions.xml does not exist" ); + return; + } + + Console.Write( "Regions: Loading..." ); + + XmlDocument doc = new XmlDocument(); + doc.Load( System.IO.Path.Combine( Core.BaseDirectory, "Data/Regions.xml" ) ); + + XmlElement root = doc["ServerRegions"]; + + if ( root == null ) + { + Console.WriteLine( "Could not find root element 'ServerRegions' in Regions.xml" ); + } + else + { + foreach ( XmlElement facet in root.SelectNodes( "Facet" ) ) + { + Map map = null; + if ( ReadMap( facet, "name", ref map ) ) + { + if ( map == Map.Internal ) + Console.WriteLine( "Invalid internal map in a facet element" ); + else + LoadRegions( facet, map, null ); + } + } + } + + Console.WriteLine( "done" ); + } + + private static void LoadRegions( XmlElement xml, Map map, Region parent ) + { + foreach ( XmlElement xmlReg in xml.SelectNodes( "region" ) ) + { + Type type = DefaultRegionType; + + ReadType( xmlReg, "type", ref type, false ); + + if ( !typeof( Region ).IsAssignableFrom( type ) ) + { + Console.WriteLine( "Invalid region type '{0}' in regions.xml", type.FullName ); + continue; + } + + Region region = null; + try + { + region = (Region) Activator.CreateInstance( type, new object[] { xmlReg, map, parent } ); + } + catch ( Exception ex ) + { + Console.WriteLine( "Error during the creation of region type '{0}': {1}", type.FullName, ex ); + continue; + } + + region.Register(); + + LoadRegions( xmlReg, map, region ); + } + } + + public Region( XmlElement xml, Map map, Region parent ) + { + m_Map = map; + m_Parent = parent; + m_Dynamic = false; + + if ( m_Parent == null ) + { + m_ChildLevel = 0; + m_Priority = DefaultPriority; + } + else + { + m_ChildLevel = m_Parent.ChildLevel + 1; + m_Priority = m_Parent.Priority; + } + + ReadString( xml, "name", ref m_Name, false ); + + if ( parent == null ) + ReadInt32( xml, "priority", ref m_Priority, false ); + + + int minZ = MinZ; + int maxZ = MaxZ; + + XmlElement zrange = xml["zrange"]; + ReadInt32( zrange, "min", ref minZ, false ); + ReadInt32( zrange, "max", ref maxZ, false ); + + + List area = new List(); + foreach ( XmlElement xmlRect in xml.SelectNodes( "rect" ) ) + { + Rectangle3D rect = new Rectangle3D(); + if ( ReadRectangle3D( xmlRect, minZ, maxZ, ref rect ) ) + area.Add( rect ); + } + + m_Area = area.ToArray(); + + if ( m_Area.Length == 0 ) + Console.WriteLine( "Empty area for region '{0}'", this ); + + + if ( !ReadPoint3D( xml["go"], map, ref m_GoLocation, false ) && m_Area.Length > 0 ) + { + Point3D start = m_Area[0].Start; + Point3D end = m_Area[0].End; + + int x = start.X + (end.X - start.X) / 2; + int y = start.Y + (end.Y - start.Y) / 2; + + m_GoLocation = new Point3D( x, y, m_Map.GetAverageZ( x, y ) ); + } + + + MusicName music = this.DefaultMusic; + + ReadEnum( xml["music"], "name", ref music, false ); + + m_Music = music; + } + + protected static string GetAttribute( XmlElement xml, string attribute, bool mandatory ) + { + if ( xml == null ) + { + if ( mandatory ) + Console.WriteLine( "Missing element for attribute '{0}'", attribute ); + + return null; + } + else if ( xml.HasAttribute( attribute ) ) + { + return xml.GetAttribute( attribute ); + } + else + { + if ( mandatory ) + Console.WriteLine( "Missing attribute '{0}' in element '{1}'", attribute, xml.Name ); + + return null; + } + } + + public static bool ReadString( XmlElement xml, string attribute, ref string value ) + { + return ReadString( xml, attribute, ref value, true ); + } + + public static bool ReadString( XmlElement xml, string attribute, ref string value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + value = s; + return true; + } + + public static bool ReadInt32( XmlElement xml, string attribute, ref int value ) + { + return ReadInt32( xml, attribute, ref value, true ); + } + + public static bool ReadInt32( XmlElement xml, string attribute, ref int value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + try + { + value = XmlConvert.ToInt32( s ); + } + catch + { + Console.WriteLine( "Could not parse integer attribute '{0}' in element '{1}'", attribute, xml.Name ); + return false; + } + + return true; + } + + public static bool ReadBoolean( XmlElement xml, string attribute, ref bool value ) + { + return ReadBoolean( xml, attribute, ref value, true ); + } + + public static bool ReadBoolean( XmlElement xml, string attribute, ref bool value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + try + { + value = XmlConvert.ToBoolean( s ); + } + catch + { + Console.WriteLine( "Could not parse boolean attribute '{0}' in element '{1}'", attribute, xml.Name ); + return false; + } + + return true; + } + + public static bool ReadDateTime( XmlElement xml, string attribute, ref DateTime value ) + { + return ReadDateTime( xml, attribute, ref value, true ); + } + + public static bool ReadDateTime( XmlElement xml, string attribute, ref DateTime value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + try + { + value = XmlConvert.ToDateTime( s, XmlDateTimeSerializationMode.Local ); + } + catch + { + Console.WriteLine( "Could not parse DateTime attribute '{0}' in element '{1}'", attribute, xml.Name ); + return false; + } + + return true; + } + + public static bool ReadTimeSpan( XmlElement xml, string attribute, ref TimeSpan value ) + { + return ReadTimeSpan( xml, attribute, ref value, true ); + } + + public static bool ReadTimeSpan( XmlElement xml, string attribute, ref TimeSpan value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + try + { + value = XmlConvert.ToTimeSpan( s ); + } + catch + { + Console.WriteLine( "Could not parse TimeSpan attribute '{0}' in element '{1}'", attribute, xml.Name ); + return false; + } + + return true; + } + + public static bool ReadEnum( XmlElement xml, string attribute, ref T value ) where T : struct + { + return ReadEnum( xml, attribute, ref value, true ); + } + + public static bool ReadEnum( XmlElement xml, string attribute, ref T value, bool mandatory ) where T : struct // We can't limit the where clause to Enums only + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + Type type = typeof(T); +#if Framework_4_0 + T tempVal; + + if( type.IsEnum && Enum.TryParse( s, true, out tempVal ) ) + { + value = tempVal; + return true; + } + else + { + Console.WriteLine( "Could not parse {0} enum attribute '{1}' in element '{2}'", type, attribute, xml.Name ); + return false; + } +#else + try + { + value = (T)Enum.Parse(type, s, true); + } + catch + { + Console.WriteLine( "Could not parse {0} enum attribute '{1}' in element '{2}'", type, attribute, xml.Name ); + return false; + } + + return true; +#endif + } + + public static bool ReadMap( XmlElement xml, string attribute, ref Map value ) + { + return ReadMap( xml, attribute, ref value, true ); + } + + public static bool ReadMap( XmlElement xml, string attribute, ref Map value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + try + { + value = Map.Parse( s ); + } + catch + { + Console.WriteLine( "Could not parse Map attribute '{0}' in element '{1}'", attribute, xml.Name ); + return false; + } + + return true; + } + + public static bool ReadType( XmlElement xml, string attribute, ref Type value ) + { + return ReadType( xml, attribute, ref value, true ); + } + + public static bool ReadType( XmlElement xml, string attribute, ref Type value, bool mandatory ) + { + string s = GetAttribute( xml, attribute, mandatory ); + + if ( s == null ) + return false; + + Type type; + try + { + type = ScriptCompiler.FindTypeByName( s, false ); + } + catch + { + Console.WriteLine( "Could not parse Type attribute '{0}' in element '{1}'", attribute, xml.Name ); + return false; + } + + if ( type == null ) + { + Console.WriteLine( "Could not find Type '{0}'", s ); + return false; + } + + value = type; + return true; + } + + public static bool ReadPoint3D( XmlElement xml, Map map, ref Point3D value ) + { + return ReadPoint3D( xml, map, ref value, true ); + } + + public static bool ReadPoint3D( XmlElement xml, Map map, ref Point3D value, bool mandatory ) + { + int x = 0, y = 0, z = 0; + + bool xyOk = ReadInt32( xml, "x", ref x, mandatory ) & ReadInt32( xml, "y", ref y, mandatory ); + bool zOk = ReadInt32( xml, "z", ref z, mandatory && map == null ); + + if ( xyOk && ( zOk || map != null ) ) + { + if ( !zOk ) + z = map.GetAverageZ( x, y ); + + value = new Point3D( x, y, z ); + return true; + } + + return false; + } + + public static bool ReadRectangle3D( XmlElement xml, int defaultMinZ, int defaultMaxZ, ref Rectangle3D value ) + { + return ReadRectangle3D( xml, defaultMinZ, defaultMaxZ, ref value, true ); + } + + public static bool ReadRectangle3D( XmlElement xml, int defaultMinZ, int defaultMaxZ, ref Rectangle3D value, bool mandatory ) + { + int x1 = 0, y1 = 0, x2 = 0, y2 = 0; + + if ( xml.HasAttribute( "x" ) ) + { + if ( ReadInt32( xml, "x", ref x1, mandatory ) + & ReadInt32( xml, "y", ref y1, mandatory ) + & ReadInt32( xml, "width", ref x2, mandatory ) + & ReadInt32( xml, "height", ref y2, mandatory ) ) + { + x2 += x1; + y2 += y1; + } + else + { + return false; + } + } + else + { + if ( !ReadInt32( xml, "x1", ref x1, mandatory ) + | !ReadInt32( xml, "y1", ref y1, mandatory ) + | !ReadInt32( xml, "x2", ref x2, mandatory ) + | !ReadInt32( xml, "y2", ref y2, mandatory ) ) + { + return false; + } + } + + int z1 = defaultMinZ; + int z2 = defaultMaxZ; + + ReadInt32( xml, "zmin", ref z1, false ); + ReadInt32( xml, "zmax", ref z2, false ); + + value = new Rectangle3D( new Point3D( x1, y1, z1 ), new Point3D( x2, y2, z2 ) ); + + return true; + } + } +} \ No newline at end of file diff --git a/Server/ScriptCompiler.cs b/Server/ScriptCompiler.cs new file mode 100644 index 0000000..a2b93e9 --- /dev/null +++ b/Server/ScriptCompiler.cs @@ -0,0 +1,797 @@ +/*************************************************************************** + * ScriptCompiler.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: ScriptCompiler.cs 856 2012-03-21 22:25:44Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Reflection; +using System.Security.Cryptography; +using Microsoft.CSharp; +using Microsoft.VisualBasic; +using System.Diagnostics; + +namespace Server +{ + public static class ScriptCompiler + { + private static Assembly[] m_Assemblies; + + public static Assembly[] Assemblies + { + get + { + return m_Assemblies; + } + set + { + m_Assemblies = value; + } + } + + private static List m_AdditionalReferences = new List(); + + public static string[] GetReferenceAssemblies() + { + List list = new List(); + +#if Framework_4_0 + string path = Path.Combine( Core.BaseDirectory, "Data/Assemblies_4_0.cfg" ); +#else + string path = Path.Combine( Core.BaseDirectory, "Data/Assemblies.cfg" ); +#endif + + if( File.Exists( path ) ) + { + using( StreamReader ip = new StreamReader( path ) ) + { + string line; + + while( (line = ip.ReadLine()) != null ) + { + if( line.Length > 0 && !line.StartsWith( "#" ) ) + list.Add( line ); + } + } + } + + list.Add( Core.ExePath ); + + list.AddRange( m_AdditionalReferences ); + + return list.ToArray(); + } + + public static string GetCompilerOptions( bool debug ) + { + StringBuilder sb = null; + + if( !debug ) + AppendCompilerOption( ref sb, "/optimize" ); + +#if MONO + AppendCompilerOption( ref sb, "/d:MONO" ); +#endif + + //These two defines are legacy, ie, depreciated. + if( Core.Is64Bit ) + AppendCompilerOption( ref sb, "/d:x64" ); + + AppendCompilerOption( ref sb, "/d:Framework_2_0" ); +#if Framework_4_0 + AppendCompilerOption( ref sb, "/d:Framework_4_0" ); +#endif + + return (sb == null ? null : sb.ToString()); + } + + private static void AppendCompilerOption( ref StringBuilder sb, string define ) + { + if( sb == null ) + sb = new StringBuilder(); + else + sb.Append( ' ' ); + + sb.Append( define ); + } + + private static byte[] GetHashCode( string compiledFile, string[] scriptFiles, bool debug ) + { + using( MemoryStream ms = new MemoryStream() ) + { + using( BinaryWriter bin = new BinaryWriter( ms ) ) + { + FileInfo fileInfo = new FileInfo( compiledFile ); + + bin.Write( fileInfo.LastWriteTimeUtc.Ticks ); + + foreach( string scriptFile in scriptFiles ) + { + fileInfo = new FileInfo( scriptFile ); + + bin.Write( fileInfo.LastWriteTimeUtc.Ticks ); + } + + bin.Write( debug ); + bin.Write( Core.Version.ToString() ); + + ms.Position = 0; + + using( SHA1 sha1 = SHA1.Create() ) + { + return sha1.ComputeHash( ms ); + } + } + } + } + + public static bool CompileCSScripts( out Assembly assembly ) + { + return CompileCSScripts( false, true, out assembly ); + } + + public static bool CompileCSScripts( bool debug, out Assembly assembly ) + { + return CompileCSScripts( debug, true, out assembly ); + } + + public static bool CompileCSScripts( bool debug, bool cache, out Assembly assembly ) + { + Console.Write( "Scripts: Compiling C# scripts..." ); + string[] files = GetScripts( "*.cs" ); + + if( files.Length == 0 ) + { + Console.WriteLine( "no files found." ); + assembly = null; + return true; + } + + if( File.Exists( "Scripts/Output/Scripts.CS.dll" ) ) + { + if( cache && File.Exists( "Scripts/Output/Scripts.CS.hash" ) ) + { + try + { + byte[] hashCode = GetHashCode( "Scripts/Output/Scripts.CS.dll", files, debug ); + + using( FileStream fs = new FileStream( "Scripts/Output/Scripts.CS.hash", FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + using( BinaryReader bin = new BinaryReader( fs ) ) + { + byte[] bytes = bin.ReadBytes( hashCode.Length ); + + if( bytes.Length == hashCode.Length ) + { + bool valid = true; + + for( int i = 0; i < bytes.Length; ++i ) + { + if( bytes[i] != hashCode[i] ) + { + valid = false; + break; + } + } + + if( valid ) + { + assembly = Assembly.LoadFrom( "Scripts/Output/Scripts.CS.dll" ); + + if( !m_AdditionalReferences.Contains( assembly.Location ) ) + { + m_AdditionalReferences.Add( assembly.Location ); + } + + Console.WriteLine( "done (cached)" ); + + return true; + } + } + } + } + } + catch + { + } + } + } + + DeleteFiles( "Scripts.CS*.dll" ); + + using ( CSharpCodeProvider provider = new CSharpCodeProvider() ) + { + string path = GetUnusedPath( "Scripts.CS" ); + + CompilerParameters parms = new CompilerParameters( GetReferenceAssemblies(), path, debug ); + + string options = GetCompilerOptions( debug ); + + if( options != null ) + parms.CompilerOptions = options; + + if( Core.HaltOnWarning ) + parms.WarningLevel = 4; + +#if !MONO + CompilerResults results = provider.CompileAssemblyFromFile( parms, files ); +#else + parms.CompilerOptions = String.Format( "{0} /nowarn:169,219,414 /recurse:Scripts/*.cs", parms.CompilerOptions ); + CompilerResults results = provider.CompileAssemblyFromFile( parms, "" ); +#endif + m_AdditionalReferences.Add( path ); + + Display( results ); + +#if !MONO + if( results.Errors.Count > 0 ) + { + assembly = null; + return false; + } +#else + if( results.Errors.Count > 0 ) { + foreach( CompilerError err in results.Errors ) { + if ( !err.IsWarning ) { + assembly = null; + return false; + } + } + } +#endif + + + if( cache && Path.GetFileName( path ) == "Scripts.CS.dll" ) + { + try + { + byte[] hashCode = GetHashCode( path, files, debug ); + + using( FileStream fs = new FileStream( "Scripts/Output/Scripts.CS.hash", FileMode.Create, FileAccess.Write, FileShare.None ) ) + { + using( BinaryWriter bin = new BinaryWriter( fs ) ) + { + bin.Write( hashCode, 0, hashCode.Length ); + } + } + } + catch + { + } + } + + assembly = results.CompiledAssembly; + return true; + } + } + + public static bool CompileVBScripts( out Assembly assembly ) + { + return CompileVBScripts( false, out assembly ); + } + + public static bool CompileVBScripts( bool debug, out Assembly assembly ) + { + return CompileVBScripts( debug, true, out assembly ); + } + + public static bool CompileVBScripts( bool debug, bool cache, out Assembly assembly ) + { + Console.Write( "Scripts: Compiling VB.NET scripts..." ); + string[] files = GetScripts( "*.vb" ); + + if( files.Length == 0 ) + { + Console.WriteLine( "no files found." ); + assembly = null; + return true; + } + + if( File.Exists( "Scripts/Output/Scripts.VB.dll" ) ) + { + if( cache && File.Exists( "Scripts/Output/Scripts.VB.hash" ) ) + { + byte[] hashCode = GetHashCode( "Scripts/Output/Scripts.VB.dll", files, debug ); + + try + { + using( FileStream fs = new FileStream( "Scripts/Output/Scripts.VB.hash", FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + using( BinaryReader bin = new BinaryReader( fs ) ) + { + byte[] bytes = bin.ReadBytes( hashCode.Length ); + + if( bytes.Length == hashCode.Length ) + { + bool valid = true; + + for( int i = 0; i < bytes.Length; ++i ) + { + if( bytes[i] != hashCode[i] ) + { + valid = false; + break; + } + } + + if( valid ) + { + assembly = Assembly.LoadFrom( "Scripts/Output/Scripts.VB.dll" ); + + if( !m_AdditionalReferences.Contains( assembly.Location ) ) + { + m_AdditionalReferences.Add( assembly.Location ); + } + + Console.WriteLine( "done (cached)" ); + + return true; + } + } + } + } + } + catch + { + } + } + } + + DeleteFiles( "Scripts.VB*.dll" ); + + using ( VBCodeProvider provider = new VBCodeProvider() ) + { + string path = GetUnusedPath( "Scripts.VB" ); + + CompilerParameters parms = new CompilerParameters( GetReferenceAssemblies(), path, debug ); + + string options = GetCompilerOptions( debug ); + + if( options != null ) + parms.CompilerOptions = options; + + if( Core.HaltOnWarning ) + parms.WarningLevel = 4; + + CompilerResults results = provider.CompileAssemblyFromFile( parms, files ); + m_AdditionalReferences.Add( path ); + + Display( results ); + + if( results.Errors.Count > 0 ) + { + assembly = null; + return false; + } + + if( cache && Path.GetFileName( path ) == "Scripts.VB.dll" ) + { + try + { + byte[] hashCode = GetHashCode( path, files, debug ); + + using( FileStream fs = new FileStream( "Scripts/Output/Scripts.VB.hash", FileMode.Create, FileAccess.Write, FileShare.None ) ) + { + using( BinaryWriter bin = new BinaryWriter( fs ) ) + { + bin.Write( hashCode, 0, hashCode.Length ); + } + } + } + catch + { + } + } + + assembly = results.CompiledAssembly; + return true; + } + } + + public static void Display( CompilerResults results ) + { + if( results.Errors.Count > 0 ) + { + Dictionary> errors = new Dictionary>( results.Errors.Count, StringComparer.OrdinalIgnoreCase ); + Dictionary> warnings = new Dictionary>( results.Errors.Count, StringComparer.OrdinalIgnoreCase ); + + foreach( CompilerError e in results.Errors ) + { + string file = e.FileName; + + // Ridiculous. FileName is null if the warning/error is internally generated in csc. + if ( string.IsNullOrEmpty( file ) ) { + Console.WriteLine( "ScriptCompiler: {0}: {1}", e.ErrorNumber, e.ErrorText ); + continue; + } + + Dictionary> table = (e.IsWarning ? warnings : errors); + + List list = null; + table.TryGetValue( file, out list ); + + if( list == null ) + table[file] = list = new List(); + + list.Add( e ); + } + + if( errors.Count > 0 ) + Console.WriteLine( "failed ({0} errors, {1} warnings)", errors.Count, warnings.Count ); + else + Console.WriteLine( "done ({0} errors, {1} warnings)", errors.Count, warnings.Count ); + + string scriptRoot = Path.GetFullPath( Path.Combine( Core.BaseDirectory, "Scripts" + Path.DirectorySeparatorChar ) ); + Uri scriptRootUri = new Uri( scriptRoot ); + + Utility.PushColor( ConsoleColor.Yellow ); + + if( warnings.Count > 0 ) + Console.WriteLine( "Warnings:" ); + + foreach( KeyValuePair> kvp in warnings ) + { + string fileName = kvp.Key; + List list = kvp.Value; + + string fullPath = Path.GetFullPath( fileName ); + string usedPath = Uri.UnescapeDataString( scriptRootUri.MakeRelativeUri( new Uri( fullPath ) ).OriginalString ); + + Console.WriteLine( " + {0}:", usedPath ); + + Utility.PushColor( ConsoleColor.DarkYellow ); + + foreach( CompilerError e in list ) + Console.WriteLine( " {0}: Line {1}: {3}", e.ErrorNumber, e.Line, e.Column, e.ErrorText ); + + Utility.PopColor(); + } + + Utility.PopColor(); + + Utility.PushColor( ConsoleColor.Red ); + + if( errors.Count > 0 ) + Console.WriteLine( "Errors:" ); + + foreach( KeyValuePair> kvp in errors ) + { + string fileName = kvp.Key; + List list = kvp.Value; + + string fullPath = Path.GetFullPath( fileName ); + string usedPath = Uri.UnescapeDataString( scriptRootUri.MakeRelativeUri( new Uri( fullPath ) ).OriginalString ); + + Console.WriteLine( " + {0}:", usedPath ); + + Utility.PushColor( ConsoleColor.DarkRed ); + + foreach( CompilerError e in list ) + Console.WriteLine( " {0}: Line {1}: {3}", e.ErrorNumber, e.Line, e.Column, e.ErrorText ); + + Utility.PopColor(); + } + + Utility.PopColor(); + } + else + { + Console.WriteLine( "done (0 errors, 0 warnings)" ); + } + } + + public static string GetUnusedPath( string name ) + { + string path = Path.Combine( Core.BaseDirectory, String.Format( "Scripts/Output/{0}.dll", name ) ); + + for( int i = 2; File.Exists( path ) && i <= 1000; ++i ) + path = Path.Combine( Core.BaseDirectory, String.Format( "Scripts/Output/{0}.{1}.dll", name, i ) ); + + return path; + } + + public static void DeleteFiles( string mask ) + { + try + { + string[] files = Directory.GetFiles( Path.Combine( Core.BaseDirectory, "Scripts/Output" ), mask ); + + foreach( string file in files ) + { + try { File.Delete( file ); } + catch { } + } + } + catch + { + } + } + + private delegate CompilerResults Compiler( bool debug ); + + public static bool Compile() + { + return Compile( false ); + } + + public static bool Compile( bool debug ) + { + return Compile( debug, true ); + } + + public static bool Compile( bool debug, bool cache ) + { + EnsureDirectory( "Scripts/" ); + EnsureDirectory( "Scripts/Output/" ); + + if( m_AdditionalReferences.Count > 0 ) + m_AdditionalReferences.Clear(); + + List assemblies = new List(); + + Assembly assembly; + + if( CompileCSScripts( debug, cache, out assembly ) ) + { + if( assembly != null ) + { + assemblies.Add( assembly ); + } + } + else + { + return false; + } + + if ( Core.VBdotNet ) + { + if ( CompileVBScripts( debug, cache, out assembly ) ) + { + if ( assembly != null ) + { + assemblies.Add( assembly ); + } + } + else + { + return false; + } + } + else + { + Console.WriteLine( "Scripts: Skipping VB.NET Scripts...done (use -vb to enable)"); + } + + if( assemblies.Count == 0 ) + { + return false; + } + + m_Assemblies = assemblies.ToArray(); + + Console.Write( "Scripts: Verifying..." ); + + Stopwatch watch = Stopwatch.StartNew(); + + Core.VerifySerialization(); + + watch.Stop(); + + Console.WriteLine("done ({0} items, {1} mobiles) ({2:F2} seconds)", Core.ScriptItems, Core.ScriptMobiles, watch.Elapsed.TotalSeconds); + + return true; + } + + public static void Invoke( string method ) + { + List invoke = new List(); + + for( int a = 0; a < m_Assemblies.Length; ++a ) + { + Type[] types = m_Assemblies[a].GetTypes(); + + for( int i = 0; i < types.Length; ++i ) + { + MethodInfo m = types[i].GetMethod( method, BindingFlags.Static | BindingFlags.Public ); + + if( m != null ) + invoke.Add( m ); + } + } + + invoke.Sort( new CallPriorityComparer() ); + + for( int i = 0; i < invoke.Count; ++i ) + invoke[i].Invoke( null, null ); + } + + private static Dictionary m_TypeCaches = new Dictionary(); + private static TypeCache m_NullCache; + + public static TypeCache GetTypeCache( Assembly asm ) + { + if( asm == null ) + { + if( m_NullCache == null ) + m_NullCache = new TypeCache( null ); + + return m_NullCache; + } + + TypeCache c = null; + m_TypeCaches.TryGetValue( asm, out c ); + + if( c == null ) + m_TypeCaches[asm] = c = new TypeCache( asm ); + + return c; + } + + public static Type FindTypeByFullName( string fullName ) + { + return FindTypeByFullName( fullName, true ); + } + + public static Type FindTypeByFullName( string fullName, bool ignoreCase ) + { + Type type = null; + + for( int i = 0; type == null && i < m_Assemblies.Length; ++i ) + type = GetTypeCache( m_Assemblies[i] ).GetTypeByFullName( fullName, ignoreCase ); + + if( type == null ) + type = GetTypeCache( Core.Assembly ).GetTypeByFullName( fullName, ignoreCase ); + + return type; + } + + public static Type FindTypeByName( string name ) + { + return FindTypeByName( name, true ); + } + + public static Type FindTypeByName( string name, bool ignoreCase ) + { + Type type = null; + + for( int i = 0; type == null && i < m_Assemblies.Length; ++i ) + type = GetTypeCache( m_Assemblies[i] ).GetTypeByName( name, ignoreCase ); + + if( type == null ) + type = GetTypeCache( Core.Assembly ).GetTypeByName( name, ignoreCase ); + + return type; + } + + public static void EnsureDirectory( string dir ) + { + string path = Path.Combine( Core.BaseDirectory, dir ); + + if( !Directory.Exists( path ) ) + Directory.CreateDirectory( path ); + } + + public static string[] GetScripts( string filter ) + { + List list = new List(); + + GetScripts( list, Path.Combine( Core.BaseDirectory, "Scripts" ), filter ); + + return list.ToArray(); + } + + public static void GetScripts( List list, string path, string filter ) + { + foreach( string dir in Directory.GetDirectories( path ) ) + GetScripts( list, dir, filter ); + + list.AddRange( Directory.GetFiles( path, filter ) ); + } + } + + public class TypeCache + { + private Type[] m_Types; + private TypeTable m_Names, m_FullNames; + + public Type[] Types { get { return m_Types; } } + public TypeTable Names { get { return m_Names; } } + public TypeTable FullNames { get { return m_FullNames; } } + + public Type GetTypeByName( string name, bool ignoreCase ) + { + return m_Names.Get( name, ignoreCase ); + } + + public Type GetTypeByFullName( string fullName, bool ignoreCase ) + { + return m_FullNames.Get( fullName, ignoreCase ); + } + + public TypeCache( Assembly asm ) + { + if( asm == null ) + m_Types = Type.EmptyTypes; + else + m_Types = asm.GetTypes(); + + m_Names = new TypeTable( m_Types.Length ); + m_FullNames = new TypeTable( m_Types.Length ); + + Type typeofTypeAliasAttribute = typeof( TypeAliasAttribute ); + + for( int i = 0; i < m_Types.Length; ++i ) + { + Type type = m_Types[i]; + + m_Names.Add( type.Name, type ); + m_FullNames.Add( type.FullName, type ); + + if( type.IsDefined( typeofTypeAliasAttribute, false ) ) + { + object[] attrs = type.GetCustomAttributes( typeofTypeAliasAttribute, false ); + + if( attrs != null && attrs.Length > 0 ) + { + TypeAliasAttribute attr = attrs[0] as TypeAliasAttribute; + + if( attr != null ) + { + for( int j = 0; j < attr.Aliases.Length; ++j ) + m_FullNames.Add( attr.Aliases[j], type ); + } + } + } + } + } + } + + public class TypeTable + { + private Dictionary m_Sensitive, m_Insensitive; + + public void Add( string key, Type type ) + { + m_Sensitive[key] = type; + m_Insensitive[key] = type; + } + + public Type Get( string key, bool ignoreCase ) + { + Type t = null; + + if( ignoreCase ) + m_Insensitive.TryGetValue( key, out t ); + else + m_Sensitive.TryGetValue( key, out t ); + + return t; + } + + public TypeTable( int capacity ) + { + m_Sensitive = new Dictionary( capacity ); + m_Insensitive = new Dictionary( capacity, StringComparer.OrdinalIgnoreCase ); + } + } +} diff --git a/Server/Sector.cs b/Server/Sector.cs new file mode 100644 index 0000000..1ae7ef6 --- /dev/null +++ b/Server/Sector.cs @@ -0,0 +1,319 @@ +/*************************************************************************** + * Sector.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Sector.cs 24 2006-06-16 22:31:18Z krrios $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server { + public class RegionRect : IComparable { + private Region m_Region; + private Rectangle3D m_Rect; + + public Region Region { get { return m_Region; } } + public Rectangle3D Rect { get { return m_Rect; } } + + public RegionRect( Region region, Rectangle3D rect ) { + m_Region = region; + m_Rect = rect; + } + + public bool Contains( Point3D loc ) { + return m_Rect.Contains( loc ); + } + + int IComparable.CompareTo( object obj ) { + if ( obj == null ) + return 1; + + RegionRect regRect = obj as RegionRect; + + if ( regRect == null ) + throw new ArgumentException( "obj is not a RegionRect", "obj" ); + + return ( ( IComparable ) m_Region ).CompareTo( regRect.m_Region ); + } + } + + + public class Sector { + private int m_X, m_Y; + private Map m_Owner; + private List m_Mobiles; + private List m_Players; + private List m_Items; + private List m_Clients; + private List m_Multis; + private List m_RegionRects; + private bool m_Active; + + // TODO: Can we avoid this? + private static List m_DefaultMobileList = new List(); + private static List m_DefaultItemList = new List(); + private static List m_DefaultClientList = new List(); + private static List m_DefaultMultiList = new List(); + private static List m_DefaultRectList = new List(); + + public Sector( int x, int y, Map owner ) { + m_X = x; + m_Y = y; + m_Owner = owner; + m_Active = false; + } + + private void Add( ref List list, T value ) { + if ( list == null ) { + list = new List(); + } + + list.Add( value ); + } + + private void Remove( ref List list, T value ) { + if ( list != null ) { + list.Remove( value ); + + if ( list.Count == 0 ) { + list = null; + } + } + } + + private void Replace( ref List list, T oldValue, T newValue ) { + if ( oldValue != null && newValue != null ) { + int index = ( list != null ? list.IndexOf( oldValue ) : -1 ); + + if ( index >= 0 ) { + list[index] = newValue; + } else { + Add( ref list, newValue ); + } + } else if ( oldValue != null ) { + Remove( ref list, oldValue ); + } else if ( newValue != null ) { + Add( ref list, newValue ); + } + } + + public void OnClientChange( NetState oldState, NetState newState ) { + Replace( ref m_Clients, oldState, newState ); + } + + public void OnEnter( Item item ) { + Add( ref m_Items, item ); + } + + public void OnLeave( Item item ) { + Remove( ref m_Items, item ); + } + + public void OnEnter( Mobile mob ) { + Add( ref m_Mobiles, mob ); + + if ( mob.NetState != null ) { + Add( ref m_Clients, mob.NetState ); + } + + if ( mob.Player ) { + if ( m_Players == null ) { + m_Owner.ActivateSectors( m_X, m_Y ); + } + + Add( ref m_Players, mob ); + } + } + + public void OnLeave( Mobile mob ) { + Remove( ref m_Mobiles, mob ); + + if ( mob.NetState != null ) { + Remove( ref m_Clients, mob.NetState ); + } + + if ( mob.Player && m_Players != null ) { + Remove( ref m_Players, mob ); + + if ( m_Players == null ) { + m_Owner.DeactivateSectors( m_X, m_Y ); + } + } + } + + public void OnEnter( Region region, Rectangle3D rect ) { + Add( ref m_RegionRects, new RegionRect( region, rect ) ); + + m_RegionRects.Sort(); + + UpdateMobileRegions(); + } + + public void OnLeave( Region region ) { + if ( m_RegionRects != null ) { + for ( int i = m_RegionRects.Count - 1; i >= 0; i-- ) { + RegionRect regRect = m_RegionRects[i]; + + if ( regRect.Region == region ) { + m_RegionRects.RemoveAt( i ); + } + } + + if ( m_RegionRects.Count == 0 ) { + m_RegionRects = null; + } + } + + UpdateMobileRegions(); + } + + private void UpdateMobileRegions() { + if ( m_Mobiles != null ) { + List sandbox = new List( m_Mobiles ); + + foreach ( Mobile mob in sandbox ) { + mob.UpdateRegion(); + } + } + } + + public void OnMultiEnter( BaseMulti multi ) { + Add( ref m_Multis, multi ); + } + + public void OnMultiLeave( BaseMulti multi ) { + Remove( ref m_Multis, multi ); + } + + public void Activate() { + if ( !Active && m_Owner != Map.Internal ) { + if ( m_Items != null ) { + foreach ( Item item in m_Items ) { + item.OnSectorActivate(); + } + } + + if ( m_Mobiles != null ) { + foreach ( Mobile mob in m_Mobiles ) { + mob.OnSectorActivate(); + } + } + + m_Active = true; + } + } + + public void Deactivate() { + if ( Active ) { + if ( m_Items != null ) { + foreach ( Item item in m_Items ) { + item.OnSectorDeactivate(); + } + } + + if ( m_Mobiles != null ) { + foreach ( Mobile mob in m_Mobiles ) { + mob.OnSectorDeactivate(); + } + } + + m_Active = false; + } + } + + public List RegionRects { + get { + if ( m_RegionRects == null ) + return m_DefaultRectList; + + return m_RegionRects; + } + } + + public List Multis { + get { + if ( m_Multis == null ) + return m_DefaultMultiList; + + return m_Multis; + } + } + + public List Mobiles { + get { + if ( m_Mobiles == null ) + return m_DefaultMobileList; + + return m_Mobiles; + } + } + + public List Items { + get { + if ( m_Items == null ) + return m_DefaultItemList; + + return m_Items; + } + } + + public List Clients { + get { + if ( m_Clients == null ) + return m_DefaultClientList; + + return m_Clients; + } + } + + public List Players { + get { + if ( m_Players == null ) + return m_DefaultMobileList; + + return m_Players; + } + } + + public bool Active { + get { + return ( m_Active && m_Owner != Map.Internal ); + } + } + + public Map Owner { + get { + return m_Owner; + } + } + + public int X { + get { + return m_X; + } + } + + public int Y { + get { + return m_Y; + } + } + } +} \ No newline at end of file diff --git a/Server/SecureTrade.cs b/Server/SecureTrade.cs new file mode 100644 index 0000000..7c0b794 --- /dev/null +++ b/Server/SecureTrade.cs @@ -0,0 +1,297 @@ +/*************************************************************************** + * SecureTrade.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: SecureTrade.cs 521 2010-06-17 07:11:43Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using Server.Items; +using Server.Network; + +namespace Server +{ + public class SecureTrade + { + private SecureTradeInfo m_From, m_To; + private bool m_Valid; + + public SecureTradeInfo From + { + get + { + return m_From; + } + } + + public SecureTradeInfo To + { + get + { + return m_To; + } + } + + public bool Valid + { + get + { + return m_Valid; + } + } + + public void Cancel() + { + if ( !m_Valid ) + return; + + List list = m_From.Container.Items; + + for ( int i = list.Count - 1; i >= 0; --i ) + { + if ( i < list.Count ) + { + Item item = list[i]; + + item.OnSecureTrade( m_From.Mobile, m_To.Mobile, m_From.Mobile, false ); + + if ( !item.Deleted ) + m_From.Mobile.AddToBackpack( item ); + } + } + + list = m_To.Container.Items; + + for ( int i = list.Count - 1; i >= 0; --i ) + { + if ( i < list.Count ) + { + Item item = list[i]; + + item.OnSecureTrade( m_To.Mobile, m_From.Mobile, m_To.Mobile, false ); + + if ( !item.Deleted ) + m_To.Mobile.AddToBackpack( item ); + } + } + + Close(); + } + + public void Close() + { + if ( !m_Valid ) + return; + + m_From.Mobile.Send( new CloseSecureTrade( m_From.Container ) ); + m_To.Mobile.Send( new CloseSecureTrade( m_To.Container ) ); + + m_Valid = false; + + NetState ns = m_From.Mobile.NetState; + + if ( ns != null ) + ns.RemoveTrade( this ); + + ns = m_To.Mobile.NetState; + + if ( ns != null ) + ns.RemoveTrade( this ); + + Timer.DelayCall( TimeSpan.Zero, delegate{ m_From.Container.Delete(); } ); + Timer.DelayCall( TimeSpan.Zero, delegate{ m_To.Container.Delete(); } ); + } + + public void Update() + { + if ( !m_Valid ) + return; + + if ( m_From.Accepted && m_To.Accepted ) + { + List list = m_From.Container.Items; + + bool allowed = true; + + for ( int i = list.Count - 1; allowed && i >= 0; --i ) + { + if ( i < list.Count ) + { + Item item = list[i]; + + if ( !item.AllowSecureTrade( m_From.Mobile, m_To.Mobile, m_To.Mobile, true ) ) + allowed = false; + } + } + + list = m_To.Container.Items; + + for ( int i = list.Count - 1; allowed && i >= 0; --i ) + { + if ( i < list.Count ) + { + Item item = list[i]; + + if ( !item.AllowSecureTrade( m_To.Mobile, m_From.Mobile, m_From.Mobile, true ) ) + allowed = false; + } + } + + if ( !allowed ) + { + m_From.Accepted = false; + m_To.Accepted = false; + + m_From.Mobile.Send( new UpdateSecureTrade( m_From.Container, m_From.Accepted, m_To.Accepted ) ); + m_To.Mobile.Send( new UpdateSecureTrade( m_To.Container, m_To.Accepted, m_From.Accepted ) ); + + return; + } + + list = m_From.Container.Items; + + for ( int i = list.Count - 1; i >= 0; --i ) + { + if ( i < list.Count ) + { + Item item = list[i]; + + item.OnSecureTrade( m_From.Mobile, m_To.Mobile, m_To.Mobile, true ); + + if ( !item.Deleted ) + m_To.Mobile.AddToBackpack( item ); + } + } + + list = m_To.Container.Items; + + for ( int i = list.Count - 1; i >= 0; --i ) + { + if ( i < list.Count ) + { + Item item = list[i]; + + item.OnSecureTrade( m_To.Mobile, m_From.Mobile, m_From.Mobile, true ); + + if ( !item.Deleted ) + m_From.Mobile.AddToBackpack( item ); + } + } + + Close(); + } + else + { + m_From.Mobile.Send( new UpdateSecureTrade( m_From.Container, m_From.Accepted, m_To.Accepted ) ); + m_To.Mobile.Send( new UpdateSecureTrade( m_To.Container, m_To.Accepted, m_From.Accepted ) ); + } + } + + public SecureTrade( Mobile from, Mobile to ) + { + m_Valid = true; + + m_From = new SecureTradeInfo( this, from, new SecureTradeContainer( this ) ); + m_To = new SecureTradeInfo( this, to, new SecureTradeContainer( this ) ); + + bool from6017 = ( from.NetState == null ? false : from.NetState.ContainerGridLines ); + bool to6017 = ( to.NetState == null ? false : to.NetState.ContainerGridLines ); + + from.Send( new MobileStatus( from, to ) ); + from.Send( new UpdateSecureTrade( m_From.Container, false, false ) ); + if ( from6017 ) + from.Send( new SecureTradeEquip6017( m_To.Container, to ) ); + else + from.Send( new SecureTradeEquip( m_To.Container, to ) ); + from.Send( new UpdateSecureTrade( m_From.Container, false, false ) ); + if ( from6017 ) + from.Send( new SecureTradeEquip6017( m_From.Container, from ) ); + else + from.Send( new SecureTradeEquip( m_From.Container, from ) ); + from.Send( new DisplaySecureTrade( to, m_From.Container, m_To.Container, to.Name ) ); + from.Send( new UpdateSecureTrade( m_From.Container, false, false ) ); + + to.Send( new MobileStatus( to, from ) ); + to.Send( new UpdateSecureTrade( m_To.Container, false, false ) ); + if ( to6017 ) + to.Send( new SecureTradeEquip6017( m_From.Container, from ) ); + else + to.Send( new SecureTradeEquip( m_From.Container, from ) ); + to.Send( new UpdateSecureTrade( m_To.Container, false, false ) ); + if ( to6017 ) + to.Send( new SecureTradeEquip6017( m_To.Container, to ) ); + else + to.Send( new SecureTradeEquip( m_To.Container, to ) ); + to.Send( new DisplaySecureTrade( from, m_To.Container, m_From.Container, from.Name ) ); + to.Send( new UpdateSecureTrade( m_To.Container, false, false ) ); + } + } + + public class SecureTradeInfo + { + private SecureTrade m_Owner; + private Mobile m_Mobile; + private SecureTradeContainer m_Container; + private bool m_Accepted; + + public SecureTradeInfo( SecureTrade owner, Mobile m, SecureTradeContainer c ) + { + m_Owner = owner; + m_Mobile = m; + m_Container = c; + + m_Mobile.AddItem( m_Container ); + } + + public SecureTrade Owner + { + get + { + return m_Owner; + } + } + + public Mobile Mobile + { + get + { + return m_Mobile; + } + } + + public SecureTradeContainer Container + { + get + { + return m_Container; + } + } + + public bool Accepted + { + get + { + return m_Accepted; + } + set + { + m_Accepted = value; + } + } + } +} \ No newline at end of file diff --git a/Server/Serial.cs b/Server/Serial.cs new file mode 100644 index 0000000..fb2b493 --- /dev/null +++ b/Server/Serial.cs @@ -0,0 +1,172 @@ +/*************************************************************************** + * Serial.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Serial.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public struct Serial : IComparable, IComparable + { + private int m_Serial; + + private static Serial m_LastMobile = Zero; + private static Serial m_LastItem = 0x40000000; + + public static Serial LastMobile { get { return m_LastMobile; } } + public static Serial LastItem { get { return m_LastItem; } } + + public static readonly Serial MinusOne = new Serial( -1 ); + public static readonly Serial Zero = new Serial( 0 ); + + public static Serial NewMobile + { + get + { + while ( World.FindMobile( m_LastMobile = (m_LastMobile + 1) ) != null ); + + return m_LastMobile; + } + } + + public static Serial NewItem + { + get + { + while ( World.FindItem( m_LastItem = (m_LastItem + 1) ) != null ); + + return m_LastItem; + } + } + + private Serial( int serial ) + { + m_Serial = serial; + } + + public int Value + { + get + { + return m_Serial; + } + } + + public bool IsMobile + { + get + { + return ( m_Serial > 0 && m_Serial < 0x40000000 ); + } + } + + public bool IsItem + { + get + { + return ( m_Serial >= 0x40000000 && m_Serial <= 0x7FFFFFFF ); + } + } + + public bool IsValid + { + get + { + return ( m_Serial > 0 ); + } + } + + public override int GetHashCode() + { + return m_Serial; + } + + public int CompareTo( Serial other ) + { + return m_Serial.CompareTo( other.m_Serial ); + } + + public int CompareTo( object other ) + { + if ( other is Serial ) + return this.CompareTo( (Serial) other ); + else if ( other == null ) + return -1; + + throw new ArgumentException(); + } + + public override bool Equals( object o ) + { + if ( o == null || !(o is Serial) ) return false; + + return ((Serial)o).m_Serial == m_Serial; + } + + public static bool operator == ( Serial l, Serial r ) + { + return l.m_Serial == r.m_Serial; + } + + public static bool operator != ( Serial l, Serial r ) + { + return l.m_Serial != r.m_Serial; + } + + public static bool operator > ( Serial l, Serial r ) + { + return l.m_Serial > r.m_Serial; + } + + public static bool operator < ( Serial l, Serial r ) + { + return l.m_Serial < r.m_Serial; + } + + public static bool operator >= ( Serial l, Serial r ) + { + return l.m_Serial >= r.m_Serial; + } + + public static bool operator <= ( Serial l, Serial r ) + { + return l.m_Serial <= r.m_Serial; + } + + /*public static Serial operator ++ ( Serial l ) + { + return new Serial( l + 1 ); + }*/ + + public override string ToString() + { + return String.Format( "0x{0:X8}", m_Serial ); + } + + public static implicit operator int( Serial a ) + { + return a.m_Serial; + } + + public static implicit operator Serial( int a ) + { + return new Serial( a ); + } + } +} \ No newline at end of file diff --git a/Server/Serialization.cs b/Server/Serialization.cs new file mode 100644 index 0000000..3fb9b75 --- /dev/null +++ b/Server/Serialization.cs @@ -0,0 +1,2082 @@ +/*************************************************************************** + * Serialization.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Serialization.cs 1003 2013-02-03 01:05:17Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.Threading; +using System.Net; + +using Server; +using Server.Guilds; + +namespace Server +{ + public abstract class GenericReader + { + protected GenericReader() { } + + public abstract string ReadString(); + public abstract DateTime ReadDateTime(); +#if Framework_4_0 + public abstract DateTimeOffset ReadDateTimeOffset(); +#endif + public abstract TimeSpan ReadTimeSpan(); + public abstract DateTime ReadDeltaTime(); + public abstract decimal ReadDecimal(); + public abstract long ReadLong(); + public abstract ulong ReadULong(); + public abstract int ReadInt(); + public abstract uint ReadUInt(); + public abstract short ReadShort(); + public abstract ushort ReadUShort(); + public abstract double ReadDouble(); + public abstract float ReadFloat(); + public abstract char ReadChar(); + public abstract byte ReadByte(); + public abstract sbyte ReadSByte(); + public abstract bool ReadBool(); + public abstract int ReadEncodedInt(); + public abstract IPAddress ReadIPAddress(); + + public abstract Point3D ReadPoint3D(); + public abstract Point2D ReadPoint2D(); + public abstract Rectangle2D ReadRect2D(); + public abstract Rectangle3D ReadRect3D(); + public abstract Map ReadMap(); + + public abstract Item ReadItem(); + public abstract Mobile ReadMobile(); + public abstract BaseGuild ReadGuild(); + + public abstract T ReadItem() where T : Item; + public abstract T ReadMobile() where T : Mobile; + public abstract T ReadGuild() where T : BaseGuild; + + public abstract ArrayList ReadItemList(); + public abstract ArrayList ReadMobileList(); + public abstract ArrayList ReadGuildList(); + + public abstract List ReadStrongItemList(); + public abstract List ReadStrongItemList() where T : Item; + + public abstract List ReadStrongMobileList(); + public abstract List ReadStrongMobileList() where T : Mobile; + + public abstract List ReadStrongGuildList(); + public abstract List ReadStrongGuildList() where T : BaseGuild; +#if Framework_4_0 + public abstract HashSet ReadItemSet(); + public abstract HashSet ReadItemSet() where T: Item; + + public abstract HashSet ReadMobileSet(); + public abstract HashSet ReadMobileSet() where T : Mobile; + + public abstract HashSet ReadGuildSet(); + public abstract HashSet ReadGuildSet() where T : BaseGuild; +#endif + public abstract Race ReadRace(); + + public abstract bool End(); + } + + public abstract class GenericWriter + { + protected GenericWriter() { } + + public abstract void Close(); + + public abstract long Position { get; } + + public abstract void Write( string value ); + public abstract void Write( DateTime value ); +#if Framework_4_0 + public abstract void Write( DateTimeOffset value ); +#endif + public abstract void Write( TimeSpan value ); + public abstract void Write( decimal value ); + public abstract void Write( long value ); + public abstract void Write( ulong value ); + public abstract void Write( int value ); + public abstract void Write( uint value ); + public abstract void Write( short value ); + public abstract void Write( ushort value ); + public abstract void Write( double value ); + public abstract void Write( float value ); + public abstract void Write( char value ); + public abstract void Write( byte value ); + public abstract void Write( sbyte value ); + public abstract void Write( bool value ); + public abstract void WriteEncodedInt( int value ); + public abstract void Write( IPAddress value ); + + public abstract void WriteDeltaTime( DateTime value ); + + public abstract void Write( Point3D value ); + public abstract void Write( Point2D value ); + public abstract void Write( Rectangle2D value ); + public abstract void Write( Rectangle3D value ); + public abstract void Write( Map value ); + + public abstract void Write( Item value ); + public abstract void Write( Mobile value ); + public abstract void Write( BaseGuild value ); + + public abstract void WriteItem( T value ) where T : Item; + public abstract void WriteMobile( T value ) where T : Mobile; + public abstract void WriteGuild( T value ) where T : BaseGuild; + + public abstract void Write( Race value ); + + public abstract void WriteItemList( ArrayList list ); + public abstract void WriteItemList( ArrayList list, bool tidy ); + + public abstract void WriteMobileList( ArrayList list ); + public abstract void WriteMobileList( ArrayList list, bool tidy ); + + public abstract void WriteGuildList( ArrayList list ); + public abstract void WriteGuildList( ArrayList list, bool tidy ); + + public abstract void Write( List list ); + public abstract void Write( List list, bool tidy ); + + public abstract void WriteItemList( List list ) where T : Item; + public abstract void WriteItemList( List list, bool tidy ) where T : Item; +#if Framework_4_0 + public abstract void Write( HashSet list ); + public abstract void Write( HashSet list, bool tidy ); + + public abstract void WriteItemSet( HashSet set ) where T : Item; + public abstract void WriteItemSet( HashSet set, bool tidy ) where T : Item; +#endif + public abstract void Write( List list ); + public abstract void Write( List list, bool tidy ); + + public abstract void WriteMobileList( List list ) where T : Mobile; + public abstract void WriteMobileList( List list, bool tidy ) where T : Mobile; +#if Framework_4_0 + public abstract void Write( HashSet list ); + public abstract void Write( HashSet list, bool tidy ); + + public abstract void WriteMobileSet( HashSet set ) where T : Mobile; + public abstract void WriteMobileSet( HashSet set, bool tidy ) where T : Mobile; +#endif + public abstract void Write( List list ); + public abstract void Write( List list, bool tidy ); + + public abstract void WriteGuildList( List list ) where T : BaseGuild; + public abstract void WriteGuildList( List list, bool tidy ) where T : BaseGuild; +#if Framework_4_0 + public abstract void Write( HashSet list ); + public abstract void Write( HashSet list, bool tidy ); + + public abstract void WriteGuildSet( HashSet set ) where T : BaseGuild; + public abstract void WriteGuildSet( HashSet set, bool tidy ) where T : BaseGuild; +#endif + // Compiler won't notice their 'where' to differentiate the generic methods. + } + + public class BinaryFileWriter : GenericWriter + { + private bool PrefixStrings; + private Stream m_File; + + protected virtual int BufferSize + { + get + { + return 64 * 1024; + } + } + + private byte[] m_Buffer; + + private int m_Index; + + private Encoding m_Encoding; + + public BinaryFileWriter( Stream strm, bool prefixStr ) + { + PrefixStrings = prefixStr; + m_Encoding = Utility.UTF8; + m_Buffer = new byte[BufferSize]; + m_File = strm; + } + + public BinaryFileWriter( string filename, bool prefixStr ) + { + PrefixStrings = prefixStr; + m_Buffer = new byte[BufferSize]; + m_File = new FileStream( filename, FileMode.Create, FileAccess.Write, FileShare.None ); + m_Encoding = Utility.UTF8WithEncoding; + } + + public void Flush() + { + if( m_Index > 0 ) + { + m_Position += m_Index; + + m_File.Write( m_Buffer, 0, m_Index ); + m_Index = 0; + } + } + + private long m_Position; + + public override long Position + { + get + { + return m_Position + m_Index; + } + } + + public Stream UnderlyingStream + { + get + { + if( m_Index > 0 ) + Flush(); + + return m_File; + } + } + + public override void Close() + { + if( m_Index > 0 ) + Flush(); + + m_File.Close(); + } + + public override void WriteEncodedInt( int value ) + { + uint v = (uint)value; + + while( v >= 0x80 ) + { + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = (byte)(v | 0x80); + v >>= 7; + } + + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = (byte)v; + } + + private byte[] m_CharacterBuffer; + private int m_MaxBufferChars; + private const int LargeByteBufferSize = 256; + + internal void InternalWriteString( string value ) + { + int length = m_Encoding.GetByteCount( value ); + + WriteEncodedInt( length ); + + if( m_CharacterBuffer == null ) + { + m_CharacterBuffer = new byte[LargeByteBufferSize]; + m_MaxBufferChars = LargeByteBufferSize / m_Encoding.GetMaxByteCount( 1 ); + } + + if( length > LargeByteBufferSize ) + { + int current = 0; + int charsLeft = value.Length; + + while( charsLeft > 0 ) + { + int charCount = (charsLeft > m_MaxBufferChars) ? m_MaxBufferChars : charsLeft; + int byteLength = m_Encoding.GetBytes( value, current, charCount, m_CharacterBuffer, 0 ); + + if( (m_Index + byteLength) > m_Buffer.Length ) + Flush(); + + Buffer.BlockCopy( m_CharacterBuffer, 0, m_Buffer, m_Index, byteLength ); + m_Index += byteLength; + + current += charCount; + charsLeft -= charCount; + } + } + else + { + int byteLength = m_Encoding.GetBytes( value, 0, value.Length, m_CharacterBuffer, 0 ); + + if( (m_Index + byteLength) > m_Buffer.Length ) + Flush(); + + Buffer.BlockCopy( m_CharacterBuffer, 0, m_Buffer, m_Index, byteLength ); + m_Index += byteLength; + } + } + + public override void Write( string value ) + { + if( PrefixStrings ) + { + if( value == null ) + { + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = 0; + } + else + { + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = 1; + + InternalWriteString( value ); + } + } + else + { + InternalWriteString( value ); + } + } + + public override void Write( DateTime value ) + { + Write( value.Ticks ); + } +#if Framework_4_0 + public override void Write( DateTimeOffset value ) + { + Write( value.Ticks ); + Write( value.Offset.Ticks ); + } +#endif + public override void WriteDeltaTime( DateTime value ) + { + long ticks = value.Ticks; + long now = DateTime.Now.Ticks; + + TimeSpan d; + + try { d = new TimeSpan( ticks-now ); } + catch { if( ticks < now ) d = TimeSpan.MaxValue; else d = TimeSpan.MaxValue; } + + Write( d ); + } + + public override void Write( IPAddress value ) + { + Write( Utility.GetLongAddressValue( value ) ); + } + + public override void Write( TimeSpan value ) + { + Write( value.Ticks ); + } + + public override void Write( decimal value ) + { + int[] bits = Decimal.GetBits( value ); + + for( int i = 0; i < bits.Length; ++i ) + Write( bits[i] ); + } + + public override void Write( long value ) + { + if( (m_Index + 8) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Buffer[m_Index + 4] = (byte)(value >> 32); + m_Buffer[m_Index + 5] = (byte)(value >> 40); + m_Buffer[m_Index + 6] = (byte)(value >> 48); + m_Buffer[m_Index + 7] = (byte)(value >> 56); + m_Index += 8; + } + + public override void Write( ulong value ) + { + if( (m_Index + 8) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Buffer[m_Index + 4] = (byte)(value >> 32); + m_Buffer[m_Index + 5] = (byte)(value >> 40); + m_Buffer[m_Index + 6] = (byte)(value >> 48); + m_Buffer[m_Index + 7] = (byte)(value >> 56); + m_Index += 8; + } + + public override void Write( int value ) + { + if( (m_Index + 4) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Index += 4; + } + + public override void Write( uint value ) + { + if( (m_Index + 4) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Buffer[m_Index + 2] = (byte)(value >> 16); + m_Buffer[m_Index + 3] = (byte)(value >> 24); + m_Index += 4; + } + + public override void Write( short value ) + { + if( (m_Index + 2) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Index += 2; + } + + public override void Write( ushort value ) + { + if( (m_Index + 2) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index] = (byte)value; + m_Buffer[m_Index + 1] = (byte)(value >> 8); + m_Index += 2; + } + + public unsafe override void Write( double value ) + { + if( (m_Index + 8) > m_Buffer.Length ) + Flush(); + + fixed( byte* pBuffer = m_Buffer ) + *((double*)(pBuffer + m_Index)) = value; + + m_Index += 8; + } + + public unsafe override void Write( float value ) + { + if( (m_Index + 4) > m_Buffer.Length ) + Flush(); + + fixed( byte* pBuffer = m_Buffer ) + *((float*)(pBuffer + m_Index)) = value; + + m_Index += 4; + } + + private char[] m_SingleCharBuffer = new char[1]; + + public override void Write( char value ) + { + if( (m_Index + 8) > m_Buffer.Length ) + Flush(); + + m_SingleCharBuffer[0] = value; + + int byteCount = m_Encoding.GetBytes( m_SingleCharBuffer, 0, 1, m_Buffer, m_Index ); + m_Index += byteCount; + } + + public override void Write( byte value ) + { + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = value; + } + + public override void Write( sbyte value ) + { + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = (byte)value; + } + + public override void Write( bool value ) + { + if( (m_Index + 1) > m_Buffer.Length ) + Flush(); + + m_Buffer[m_Index++] = (byte)(value ? 1 : 0); + } + + public override void Write( Point3D value ) + { + Write( value.m_X ); + Write( value.m_Y ); + Write( value.m_Z ); + } + + public override void Write( Point2D value ) + { + Write( value.m_X ); + Write( value.m_Y ); + } + + public override void Write( Rectangle2D value ) + { + Write( value.Start ); + Write( value.End ); + } + + public override void Write( Rectangle3D value ) + { + Write( value.Start ); + Write( value.End ); + } + + public override void Write( Map value ) + { + if( value != null ) + Write( (byte)value.MapIndex ); + else + Write( (byte)0xFF ); + } + + public override void Write( Race value ) + { + if( value != null ) + Write( (byte)value.RaceIndex ); + else + Write( (byte)0xFF ); + } + + public override void Write( Item value ) + { + if( value == null || value.Deleted ) + Write( Serial.MinusOne ); + else + Write( value.Serial ); + } + + public override void Write( Mobile value ) + { + if( value == null || value.Deleted ) + Write( Serial.MinusOne ); + else + Write( value.Serial ); + } + + public override void Write( BaseGuild value ) + { + if( value == null ) + Write( 0 ); + else + Write( value.Id ); + } + + public override void WriteItem( T value ) + { + Write( value ); + } + + public override void WriteMobile( T value ) + { + Write( value ); + } + + public override void WriteGuild( T value ) + { + Write( value ); + } + + public override void WriteMobileList( ArrayList list ) + { + WriteMobileList( list, false ); + } + public override void WriteMobileList( ArrayList list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( ((Mobile)list[i]).Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( (Mobile)list[i] ); + } + + public override void WriteItemList( ArrayList list ) + { + WriteItemList( list, false ); + } + public override void WriteItemList( ArrayList list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( ((Item)list[i]).Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( (Item)list[i] ); + } + + public override void WriteGuildList( ArrayList list ) + { + WriteGuildList( list, false ); + } + public override void WriteGuildList( ArrayList list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( ((BaseGuild)list[i]).Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( (BaseGuild)list[i] ); + } + + public override void Write( List list ) + { + Write( list, false ); + } + public override void Write( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteItemList( List list ) + { + WriteItemList( list, false ); + } + public override void WriteItemList( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } +#if Framework_4_0 + public override void Write( HashSet set ) + { + Write( set, false ); + } + public override void Write( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( item => item.Deleted ); + } + + Write( set.Count ); + + foreach( Item item in set ) + { + Write( item ); + } + } + + public override void WriteItemSet( HashSet set ) + { + WriteItemSet( set, false ); + } + public override void WriteItemSet( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( item => item.Deleted ); + } + + Write( set.Count ); + + foreach( Item item in set ) + { + Write( item ); + } + } +#endif + public override void Write( List list ) + { + Write( list, false ); + } + public override void Write( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteMobileList( List list ) + { + WriteMobileList( list, false ); + } + public override void WriteMobileList( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } +#if Framework_4_0 + public override void Write( HashSet set ) + { + Write( set, false ); + } + public override void Write( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( mobile => mobile.Deleted ); + } + + Write( set.Count ); + + foreach( Mobile mob in set ) + { + Write( mob ); + } + } + + public override void WriteMobileSet( HashSet set ) + { + WriteMobileSet( set, false ); + } + public override void WriteMobileSet( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( mob => mob.Deleted ); + } + + Write( set.Count ); + + foreach( Mobile mob in set ) + { + Write( mob ); + } + } +#endif + public override void Write( List list ) + { + Write( list, false ); + } + public override void Write( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteGuildList( List list ) + { + WriteGuildList( list, false ); + } + public override void WriteGuildList( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } +#if Framework_4_0 + public override void Write( HashSet set ) + { + Write( set, false ); + } + public override void Write( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( guild => guild.Disbanded ); + } + + Write( set.Count ); + + foreach( BaseGuild guild in set ) + { + Write( guild ); + } + } + + public override void WriteGuildSet( HashSet set ) + { + WriteGuildSet( set, false ); + } + public override void WriteGuildSet( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( guild => guild.Disbanded ); + } + + Write( set.Count ); + + foreach( BaseGuild guild in set ) + { + Write( guild ); + } + } +#endif + } + + public sealed class BinaryFileReader : GenericReader + { + private BinaryReader m_File; + + public BinaryFileReader( BinaryReader br ) { m_File = br; } + + public void Close() + { + m_File.Close(); + } + + public long Position + { + get + { + return m_File.BaseStream.Position; + } + } + + public long Seek( long offset, SeekOrigin origin ) + { + return m_File.BaseStream.Seek( offset, origin ); + } + + public override string ReadString() + { + if( ReadByte() != 0 ) + return m_File.ReadString(); + else + return null; + } + + public override DateTime ReadDeltaTime() + { + long ticks = m_File.ReadInt64(); + long now = DateTime.Now.Ticks; + + if( ticks > 0 && (ticks+now) < 0 ) + return DateTime.MaxValue; + else if( ticks < 0 && (ticks+now) < 0 ) + return DateTime.MinValue; + + try { return new DateTime( now+ticks ); } + catch { if( ticks > 0 ) return DateTime.MaxValue; else return DateTime.MinValue; } + } + + public override IPAddress ReadIPAddress() + { + return new IPAddress( m_File.ReadInt64() ); + } + + public override int ReadEncodedInt() + { + int v = 0, shift = 0; + byte b; + + do + { + b = m_File.ReadByte(); + v |= (b & 0x7F) << shift; + shift += 7; + } while( b >= 0x80 ); + + return v; + } + + public override DateTime ReadDateTime() + { + return new DateTime( m_File.ReadInt64() ); + } +#if Framework_4_0 + public override DateTimeOffset ReadDateTimeOffset() + { + long ticks = m_File.ReadInt64(); + TimeSpan offset = new TimeSpan( m_File.ReadInt64() ); + + return new DateTimeOffset( ticks, offset ); + } +#endif + public override TimeSpan ReadTimeSpan() + { + return new TimeSpan( m_File.ReadInt64() ); + } + + public override decimal ReadDecimal() + { + return m_File.ReadDecimal(); + } + + public override long ReadLong() + { + return m_File.ReadInt64(); + } + + public override ulong ReadULong() + { + return m_File.ReadUInt64(); + } + + public override int ReadInt() + { + return m_File.ReadInt32(); + } + + public override uint ReadUInt() + { + return m_File.ReadUInt32(); + } + + public override short ReadShort() + { + return m_File.ReadInt16(); + } + + public override ushort ReadUShort() + { + return m_File.ReadUInt16(); + } + + public override double ReadDouble() + { + return m_File.ReadDouble(); + } + + public override float ReadFloat() + { + return m_File.ReadSingle(); + } + + public override char ReadChar() + { + return m_File.ReadChar(); + } + + public override byte ReadByte() + { + return m_File.ReadByte(); + } + + public override sbyte ReadSByte() + { + return m_File.ReadSByte(); + } + + public override bool ReadBool() + { + return m_File.ReadBoolean(); + } + + public override Point3D ReadPoint3D() + { + return new Point3D( ReadInt(), ReadInt(), ReadInt() ); + } + + public override Point2D ReadPoint2D() + { + return new Point2D( ReadInt(), ReadInt() ); + } + + public override Rectangle2D ReadRect2D() + { + return new Rectangle2D( ReadPoint2D(), ReadPoint2D() ); + } + + public override Rectangle3D ReadRect3D() + { + return new Rectangle3D( ReadPoint3D(), ReadPoint3D() ); + } + + public override Map ReadMap() + { + return Map.Maps[ReadByte()]; + } + + public override Item ReadItem() + { + return World.FindItem( ReadInt() ); + } + + public override Mobile ReadMobile() + { + return World.FindMobile( ReadInt() ); + } + + public override BaseGuild ReadGuild() + { + return BaseGuild.Find( ReadInt() ); + } + + public override T ReadItem() + { + return ReadItem() as T; + } + + public override T ReadMobile() + { + return ReadMobile() as T; + } + + public override T ReadGuild() + { + return ReadGuild() as T; + } + + public override ArrayList ReadItemList() + { + int count = ReadInt(); + + if ( count > 0 ) { + ArrayList list = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) { + Item item = ReadItem(); + + if ( item != null ) { + list.Add( item ); + } + } + + return list; + } else { + return new ArrayList(); + } + } + + public override ArrayList ReadMobileList() + { + int count = ReadInt(); + + if ( count > 0 ) { + ArrayList list = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) { + Mobile m = ReadMobile(); + + if ( m != null ) { + list.Add( m ); + } + } + + return list; + } else { + return new ArrayList(); + } + } + + public override ArrayList ReadGuildList() + { + int count = ReadInt(); + + if ( count > 0 ) { + ArrayList list = new ArrayList( count ); + + for ( int i = 0; i < count; ++i ) { + BaseGuild g = ReadGuild(); + + if ( g != null ) { + list.Add( g ); + } + } + + return list; + } else { + return new ArrayList(); + } + } + + public override List ReadStrongItemList() + { + return ReadStrongItemList(); + } + + public override List ReadStrongItemList() + { + int count = ReadInt(); + + if ( count > 0 ) { + List list = new List( count ); + + for ( int i = 0; i < count; ++i ) { + T item = ReadItem() as T; + + if ( item != null ) { + list.Add( item ); + } + } + + return list; + } else { + return new List(); + } + } +#if Framework_4_0 + public override HashSet ReadItemSet() + { + return ReadItemSet(); + } + + public override HashSet ReadItemSet() + { + int count = ReadInt(); + + if( count > 0 ) + { + HashSet set = new HashSet(); + + for( int i = 0; i < count; ++i ) + { + T item = ReadItem() as T; + + if( item != null ) + { + set.Add( item ); + } + } + + return set; + } + else + { + return new HashSet(); + } + } +#endif + public override List ReadStrongMobileList() + { + return ReadStrongMobileList(); + } + + public override List ReadStrongMobileList() + { + int count = ReadInt(); + + if ( count > 0 ) { + List list = new List( count ); + + for ( int i = 0; i < count; ++i ) { + T m = ReadMobile() as T; + + if ( m != null ) { + list.Add( m ); + } + } + + return list; + } else { + return new List(); + } + } +#if Framework_4_0 + public override HashSet ReadMobileSet() + { + return ReadMobileSet(); + } + + public override HashSet ReadMobileSet() + { + int count = ReadInt(); + + if( count > 0 ) + { + HashSet set = new HashSet(); + + for( int i = 0; i < count; ++i ) + { + T item = ReadMobile() as T; + + if( item != null ) + { + set.Add( item ); + } + } + + return set; + } + else + { + return new HashSet(); + } + } +#endif + public override List ReadStrongGuildList() + { + return ReadStrongGuildList(); + } + + public override List ReadStrongGuildList() + { + int count = ReadInt(); + + if ( count > 0 ) { + List list = new List( count ); + + for ( int i = 0; i < count; ++i ) { + T g = ReadGuild() as T; + + if ( g != null ) { + list.Add( g ); + } + } + + return list; + } else { + return new List(); + } + } +#if Framework_4_0 + public override HashSet ReadGuildSet() + { + return ReadGuildSet(); + } + + public override HashSet ReadGuildSet() + { + int count = ReadInt(); + + if( count > 0 ) + { + HashSet set = new HashSet(); + + for( int i = 0; i < count; ++i ) + { + T item = ReadGuild() as T; + + if( item != null ) + { + set.Add( item ); + } + } + + return set; + } + else + { + return new HashSet(); + } + } +#endif + public override Race ReadRace() + { + return Race.Races[ReadByte()]; + } + + public override bool End() + { + return m_File.PeekChar() == -1; + } + } + + public sealed class AsyncWriter : GenericWriter + { + private static int m_ThreadCount = 0; + public static int ThreadCount { get { return m_ThreadCount; } } + + + private int BufferSize; + + private long m_LastPos, m_CurPos; + private bool m_Closed; + private bool PrefixStrings; + + private MemoryStream m_Mem; + private BinaryWriter m_Bin; + private FileStream m_File; + + private Queue m_WriteQueue; + private Thread m_WorkerThread; + + public AsyncWriter( string filename, bool prefix ) + : this( filename, 1048576, prefix )//1 mb buffer + { + } + + public AsyncWriter( string filename, int buffSize, bool prefix ) + { + PrefixStrings = prefix; + m_Closed = false; + m_WriteQueue = Queue.Synchronized( new Queue() ); + BufferSize = buffSize; + + m_File = new FileStream( filename, FileMode.Create, FileAccess.Write, FileShare.None ); + m_Mem = new MemoryStream( BufferSize + 1024 ); + m_Bin = new BinaryWriter( m_Mem, Utility.UTF8WithEncoding ); + } + + private void Enqueue( MemoryStream mem ) + { + m_WriteQueue.Enqueue( mem ); + + if( m_WorkerThread == null || !m_WorkerThread.IsAlive ) + { + m_WorkerThread = new Thread( new ThreadStart( new WorkerThread( this ).Worker ) ); + m_WorkerThread.Priority = ThreadPriority.BelowNormal; + m_WorkerThread.Start(); + } + } + + private class WorkerThread + { + private AsyncWriter m_Owner; + + public WorkerThread( AsyncWriter owner ) + { + m_Owner = owner; + } + + public void Worker() + { + AsyncWriter.m_ThreadCount++; + while( m_Owner.m_WriteQueue.Count > 0 ) + { + MemoryStream mem = (MemoryStream)m_Owner.m_WriteQueue.Dequeue(); + + if( mem != null && mem.Length > 0 ) + mem.WriteTo( m_Owner.m_File ); + } + + if( m_Owner.m_Closed ) + m_Owner.m_File.Close(); + + AsyncWriter.m_ThreadCount--; + + if (AsyncWriter.m_ThreadCount <= 0) + World.NotifyDiskWriteComplete(); + } + } + + private void OnWrite() + { + long curlen = m_Mem.Length; + m_CurPos += curlen - m_LastPos; + m_LastPos = curlen; + if( curlen >= BufferSize ) + { + Enqueue( m_Mem ); + m_Mem = new MemoryStream( BufferSize + 1024 ); + m_Bin = new BinaryWriter( m_Mem, Utility.UTF8WithEncoding ); + m_LastPos = 0; + } + } + + public MemoryStream MemStream + { + get + { + return m_Mem; + } + set + { + if( m_Mem.Length > 0 ) + Enqueue( m_Mem ); + + m_Mem = value; + m_Bin = new BinaryWriter( m_Mem, Utility.UTF8WithEncoding ); + m_LastPos = 0; + m_CurPos = m_Mem.Length; + m_Mem.Seek( 0, SeekOrigin.End ); + } + } + + public override void Close() + { + Enqueue( m_Mem ); + m_Closed = true; + } + + public override long Position + { + get + { + return m_CurPos; + } + } + + public override void Write( IPAddress value ) + { + m_Bin.Write( Utility.GetLongAddressValue( value ) ); + OnWrite(); + } + + public override void Write( string value ) + { + if( PrefixStrings ) + { + if( value == null ) + { + m_Bin.Write( (byte)0 ); + } + else + { + m_Bin.Write( (byte)1 ); + m_Bin.Write( value ); + } + } + else + { + m_Bin.Write( value ); + } + OnWrite(); + } + + public override void WriteDeltaTime( DateTime value ) + { + long ticks = value.Ticks; + long now = DateTime.Now.Ticks; + + TimeSpan d; + + try { d = new TimeSpan( ticks-now ); } + catch { if( ticks < now ) d = TimeSpan.MaxValue; else d = TimeSpan.MaxValue; } + + Write( d ); + } + + public override void Write( DateTime value ) + { + m_Bin.Write( value.Ticks ); + OnWrite(); + } +#if Framework_4_0 + public override void Write( DateTimeOffset value ) + { + m_Bin.Write( value.Ticks ); + m_Bin.Write( value.Offset.Ticks ); + OnWrite(); + } +#endif + public override void Write( TimeSpan value ) + { + m_Bin.Write( value.Ticks ); + OnWrite(); + } + + public override void Write( decimal value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( long value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( ulong value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void WriteEncodedInt( int value ) + { + uint v = (uint)value; + + while( v >= 0x80 ) + { + m_Bin.Write( (byte)(v | 0x80) ); + v >>= 7; + } + + m_Bin.Write( (byte)v ); + OnWrite(); + } + + public override void Write( int value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( uint value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( short value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( ushort value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( double value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( float value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( char value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( byte value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( sbyte value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( bool value ) + { + m_Bin.Write( value ); + OnWrite(); + } + + public override void Write( Point3D value ) + { + Write( value.m_X ); + Write( value.m_Y ); + Write( value.m_Z ); + } + + public override void Write( Point2D value ) + { + Write( value.m_X ); + Write( value.m_Y ); + } + + public override void Write( Rectangle2D value ) + { + Write( value.Start ); + Write( value.End ); + } + + public override void Write( Rectangle3D value ) + { + Write( value.Start ); + Write( value.End ); + } + + public override void Write( Map value ) + { + if( value != null ) + Write( (byte)value.MapIndex ); + else + Write( (byte)0xFF ); + } + + public override void Write( Race value ) + { + if( value != null ) + Write( (byte)value.RaceIndex ); + else + Write( (byte)0xFF ); + } + + public override void Write( Item value ) + { + if( value == null || value.Deleted ) + Write( Serial.MinusOne ); + else + Write( value.Serial ); + } + + public override void Write( Mobile value ) + { + if( value == null || value.Deleted ) + Write( Serial.MinusOne ); + else + Write( value.Serial ); + } + + public override void Write( BaseGuild value ) + { + if( value == null ) + Write( 0 ); + else + Write( value.Id ); + } + + public override void WriteItem( T value ) + { + Write( value ); + } + + public override void WriteMobile( T value ) + { + Write( value ); + } + + public override void WriteGuild( T value ) + { + Write( value ); + } + + public override void WriteMobileList( ArrayList list ) + { + WriteMobileList( list, false ); + } + public override void WriteMobileList( ArrayList list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( ((Mobile)list[i]).Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( (Mobile)list[i] ); + } + + public override void WriteItemList( ArrayList list ) + { + WriteItemList( list, false ); + } + public override void WriteItemList( ArrayList list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( ((Item)list[i]).Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( (Item)list[i] ); + } + + public override void WriteGuildList( ArrayList list ) + { + WriteGuildList( list, false ); + } + public override void WriteGuildList( ArrayList list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( ((BaseGuild)list[i]).Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( (BaseGuild)list[i] ); + } + + public override void Write( List list ) + { + Write( list, false ); + } + public override void Write( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteItemList( List list ) + { + WriteItemList( list, false ); + } + public override void WriteItemList( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } +#if Framework_4_0 + public override void Write( HashSet set ) + { + Write( set, false ); + } + public override void Write( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( item => item.Deleted ); + } + + Write( set.Count ); + + foreach( Item item in set ) + { + Write( item ); + } + } + + public override void WriteItemSet( HashSet set ) + { + WriteItemSet( set, false ); + } + public override void WriteItemSet( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( item => item.Deleted ); + } + + Write( set.Count ); + + foreach( Item item in set ) + { + Write( item ); + } + } +#endif + public override void Write( List list ) + { + Write( list, false ); + } + public override void Write( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteMobileList( List list ) + { + WriteMobileList( list, false ); + } + public override void WriteMobileList( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Deleted ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } +#if Framework_4_0 + public override void Write( HashSet set ) + { + Write( set, false ); + } + public override void Write( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( mobile => mobile.Deleted ); + } + + Write( set.Count ); + + foreach( Mobile mob in set ) + { + Write( mob ); + } + } + + public override void WriteMobileSet( HashSet set ) + { + WriteMobileSet( set, false ); + } + public override void WriteMobileSet( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( mob => mob.Deleted ); + } + + Write( set.Count ); + + foreach( Mobile mob in set ) + { + Write( mob ); + } + } +#endif + public override void Write( List list ) + { + Write( list, false ); + } + public override void Write( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } + + public override void WriteGuildList( List list ) + { + WriteGuildList( list, false ); + } + public override void WriteGuildList( List list, bool tidy ) + { + if( tidy ) + { + for( int i = 0; i < list.Count; ) + { + if( list[i].Disbanded ) + list.RemoveAt( i ); + else + ++i; + } + } + + Write( list.Count ); + + for( int i = 0; i < list.Count; ++i ) + Write( list[i] ); + } +#if Framework_4_0 + public override void Write( HashSet set ) + { + Write( set, false ); + } + public override void Write( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( guild => guild.Disbanded ); + } + + Write( set.Count ); + + foreach( BaseGuild guild in set ) + { + Write( guild ); + } + } + + public override void WriteGuildSet( HashSet set ) + { + WriteGuildSet( set, false ); + } + public override void WriteGuildSet( HashSet set, bool tidy ) + { + if( tidy ) + { + set.RemoveWhere( guild => guild.Disbanded ); + } + + Write( set.Count ); + + foreach( BaseGuild guild in set ) + { + Write( guild ); + } + } +#endif + } + + public interface ISerializable + { + int TypeReference { get; } + int SerialIdentity { get; } + void Serialize( GenericWriter writer ); + } +} \ No newline at end of file diff --git a/Server/Server.csproj b/Server/Server.csproj new file mode 100644 index 0000000..1f15580 --- /dev/null +++ b/Server/Server.csproj @@ -0,0 +1,190 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D} + Exe + Properties + Server + Server + v4.0 + + + 512 + SAK + SAK + SAK + SAK + + + x64 + true + full + true + ..\ + DEBUG;TRACE + prompt + 4 + true + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + runuo.ico + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Server/Skills.cs b/Server/Skills.cs new file mode 100644 index 0000000..3385e4d --- /dev/null +++ b/Server/Skills.cs @@ -0,0 +1,1131 @@ +/*************************************************************************** + * Skills.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Skills.cs 841 2012-03-07 08:27:20Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using Server.Network; + +namespace Server +{ + public delegate TimeSpan SkillUseCallback(Mobile user); + + public enum SkillLock : byte + { + Up = 0, + Down = 1, + Locked = 2 + } + + public enum SkillName + { + Alchemy = 0, + Anatomy = 1, + AnimalLore = 2, + ItemID = 3, + ArmsLore = 4, + Parry = 5, + Begging = 6, + Blacksmith = 7, + Fletching = 8, + Peacemaking = 9, + Camping = 10, + Carpentry = 11, + Cartography = 12, + Cooking = 13, + DetectHidden = 14, + Discordance = 15, + EvalInt = 16, + Healing = 17, + Fishing = 18, + Forensics = 19, + Herding = 20, + Hiding = 21, + Provocation = 22, + Inscribe = 23, + Lockpicking = 24, + Magery = 25, + MagicResist = 26, + Tactics = 27, + Snooping = 28, + Musicianship = 29, + Poisoning = 30, + Archery = 31, + SpiritSpeak = 32, + Stealing = 33, + Tailoring = 34, + AnimalTaming = 35, + TasteID = 36, + Tinkering = 37, + Tracking = 38, + Veterinary = 39, + Swords = 40, + Macing = 41, + Fencing = 42, + Wrestling = 43, + Lumberjacking = 44, + Mining = 45, + Meditation = 46, + Stealth = 47, + RemoveTrap = 48, + Necromancy = 49, + Focus = 50, + Chivalry = 51, + Bushido = 52, + Ninjitsu = 53, + Spellweaving = 54, + Mysticism = 55, + Imbuing = 56, + Throwing = 57 + } + + [PropertyObject] + public class Skill + { + private Skills m_Owner; + private SkillInfo m_Info; + private ushort m_Base; + private ushort m_Cap; + private SkillLock m_Lock; + + public override string ToString() + { + return String.Format("[{0}: {1}]", Name, Base); + } + + public Skill(Skills owner, SkillInfo info, GenericReader reader) + { + m_Owner = owner; + m_Info = info; + + int version = reader.ReadByte(); + + switch (version) + { + case 0: + { + m_Base = reader.ReadUShort(); + m_Cap = reader.ReadUShort(); + m_Lock = (SkillLock)reader.ReadByte(); + + break; + } + case 0xFF: + { + m_Base = 0; + m_Cap = 1000; + m_Lock = SkillLock.Up; + + break; + } + default: + { + if ((version & 0xC0) == 0x00) + { + if ((version & 0x1) != 0) + m_Base = reader.ReadUShort(); + + if ((version & 0x2) != 0) + m_Cap = reader.ReadUShort(); + else + m_Cap = 1000; + + if ((version & 0x4) != 0) + m_Lock = (SkillLock)reader.ReadByte(); + } + + break; + } + } + + if (m_Lock < SkillLock.Up || m_Lock > SkillLock.Locked) + { + Console.WriteLine("Bad skill lock -> {0}.{1}", owner.Owner, m_Lock); + m_Lock = SkillLock.Up; + } + } + + public Skill(Skills owner, SkillInfo info, int baseValue, int cap, SkillLock skillLock) + { + m_Owner = owner; + m_Info = info; + m_Base = (ushort)baseValue; + m_Cap = (ushort)cap; + m_Lock = skillLock; + } + + public void SetLockNoRelay(SkillLock skillLock) + { + if (skillLock < SkillLock.Up || skillLock > SkillLock.Locked) + return; + + m_Lock = skillLock; + } + + public void Serialize(GenericWriter writer) + { + if (m_Base == 0 && m_Cap == 1000 && m_Lock == SkillLock.Up) + { + writer.Write((byte)0xFF); // default + } + else + { + int flags = 0x0; + + if (m_Base != 0) + flags |= 0x1; + + if (m_Cap != 1000) + flags |= 0x2; + + if (m_Lock != SkillLock.Up) + flags |= 0x4; + + writer.Write((byte)flags); // version + + if (m_Base != 0) + writer.Write((short)m_Base); + + if (m_Cap != 1000) + writer.Write((short)m_Cap); + + if (m_Lock != SkillLock.Up) + writer.Write((byte)m_Lock); + } + } + + public Skills Owner + { + get + { + return m_Owner; + } + } + + public SkillName SkillName + { + get + { + return (SkillName)m_Info.SkillID; + } + } + + public int SkillID + { + get + { + return m_Info.SkillID; + } + } + + [CommandProperty(AccessLevel.Counselor)] + public string Name + { + get + { + return m_Info.Name; + } + } + + public SkillInfo Info + { + get + { + return m_Info; + } + } + + [CommandProperty(AccessLevel.Counselor)] + public SkillLock Lock + { + get + { + return m_Lock; + } + } + + public int BaseFixedPoint + { + get + { + return m_Base; + } + set + { + if (value < 0) + value = 0; + else if (value >= 0x10000) + value = 0xFFFF; + + ushort sv = (ushort)value; + + int oldBase = m_Base; + + if (m_Base != sv) + { + m_Owner.Total = (m_Owner.Total - m_Base) + sv; + + m_Base = sv; + + m_Owner.OnSkillChange(this); + + Mobile m = m_Owner.Owner; + + if (m != null) + m.OnSkillChange(SkillName, (double)oldBase / 10); + } + } + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public double Base + { + get + { + return ((double)m_Base / 10.0); + } + set + { + BaseFixedPoint = (int)(value * 10.0); + } + } + + public int CapFixedPoint + { + get + { + return m_Cap; + } + set + { + if (value < 0) + value = 0; + else if (value >= 0x10000) + value = 0xFFFF; + + ushort sv = (ushort)value; + + if (m_Cap != sv) + { + m_Cap = sv; + + m_Owner.OnSkillChange(this); + } + } + } + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public double Cap + { + get + { + return ((double)m_Cap / 10.0); + } + set + { + CapFixedPoint = (int)(value * 10.0); + } + } + + private static bool m_UseStatMods; + + public static bool UseStatMods { get { return m_UseStatMods; } set { m_UseStatMods = value; } } + + public int Fixed + { + get { return (int)(Value * 10); } + } + + [CommandProperty(AccessLevel.Counselor)] + public double Value + { + get + { + //There has to be this distinction between the racial values and not to account for gaining skills and these skills aren't displayed nor Totaled up. + double value = this.NonRacialValue; + + double raceBonus = m_Owner.Owner.RacialSkillBonus; + + if (raceBonus > value) + value = raceBonus; + + return value; + } + } + + [CommandProperty(AccessLevel.Counselor)] + public double NonRacialValue + { + get + { + double baseValue = Base; + double inv = 100.0 - baseValue; + + if (inv < 0.0) inv = 0.0; + + inv /= 100.0; + + double statsOffset = ((m_UseStatMods ? m_Owner.Owner.Str : m_Owner.Owner.RawStr) * m_Info.StrScale) + ((m_UseStatMods ? m_Owner.Owner.Dex : m_Owner.Owner.RawDex) * m_Info.DexScale) + ((m_UseStatMods ? m_Owner.Owner.Int : m_Owner.Owner.RawInt) * m_Info.IntScale); + double statTotal = m_Info.StatTotal * inv; + + statsOffset *= inv; + + if (statsOffset > statTotal) + statsOffset = statTotal; + + double value = baseValue + statsOffset; + + m_Owner.Owner.ValidateSkillMods(); + + List mods = m_Owner.Owner.SkillMods; + + double bonusObey = 0.0, bonusNotObey = 0.0; + + for (int i = 0; i < mods.Count; ++i) + { + SkillMod mod = mods[i]; + + if (mod.Skill == (SkillName)m_Info.SkillID) + { + if (mod.Relative) + { + if (mod.ObeyCap) + bonusObey += mod.Value; + else + bonusNotObey += mod.Value; + } + else + { + bonusObey = 0.0; + bonusNotObey = 0.0; + value = mod.Value; + } + } + } + + value += bonusNotObey; + + if (value < Cap) + { + value += bonusObey; + + if (value > Cap) + value = Cap; + } + + return value; + } + } + + public void Update() + { + m_Owner.OnSkillChange(this); + } + } + + public class SkillInfo + { + private int m_SkillID; + private string m_Name; + private string m_Title; + private string m_FTitle; + private double m_StrScale; + private double m_DexScale; + private double m_IntScale; + private double m_StatTotal; + private SkillUseCallback m_Callback; + private double m_StrGain; + private double m_DexGain; + private double m_IntGain; + private double m_GainFactor; + + public SkillInfo(int skillID, string name, double strScale, double dexScale, double intScale, string title, string ftitle, SkillUseCallback callback, double strGain, double dexGain, double intGain, double gainFactor) + { + m_Name = name; + m_Title = title; + m_FTitle = ftitle; + m_SkillID = skillID; + m_StrScale = strScale / 100.0; + m_DexScale = dexScale / 100.0; + m_IntScale = intScale / 100.0; + m_Callback = callback; + m_StrGain = strGain; + m_DexGain = dexGain; + m_IntGain = intGain; + m_GainFactor = gainFactor; + + m_StatTotal = strScale + dexScale + intScale; + } + + public SkillUseCallback Callback + { + get + { + return m_Callback; + } + set + { + m_Callback = value; + } + } + + public int SkillID + { + get + { + return m_SkillID; + } + } + + public string Name + { + get + { + return m_Name; + } + set + { + m_Name = value; + } + } + + public string Title + { + get + { + return m_Title; + } + set + { + m_Title = value; + } + } + + public string FTitle + { + get + { + return m_FTitle; + } + set + { + m_FTitle = value; + } + } + + public double StrScale + { + get + { + return m_StrScale; + } + set + { + m_StrScale = value; + } + } + + public double DexScale + { + get + { + return m_DexScale; + } + set + { + m_DexScale = value; + } + } + + public double IntScale + { + get + { + return m_IntScale; + } + set + { + m_IntScale = value; + } + } + + public double StatTotal + { + get + { + return m_StatTotal; + } + set + { + m_StatTotal = value; + } + } + + public double StrGain + { + get + { + return m_StrGain; + } + set + { + m_StrGain = value; + } + } + + public double DexGain + { + get + { + return m_DexGain; + } + set + { + m_DexGain = value; + } + } + + public double IntGain + { + get + { + return m_IntGain; + } + set + { + m_IntGain = value; + } + } + + public double GainFactor + { + get + { + return m_GainFactor; + } + set + { + m_GainFactor = value; + } + } + + private static SkillInfo[] m_Table = new SkillInfo[58] + { + new SkillInfo( 0, "Alchemy", 0.0, 5.0, 5.0, "Alchimiste", "Alchimiste", null, 0.0, 0.5, 0.5, 1.0 ), + new SkillInfo( 1, "Anatomy", 0.0, 0.0, 0.0, "Biologiste", "Biologiste", null, 0.15, 0.15, 0.7, 1.0 ), + new SkillInfo( 2, "Animal Lore", 0.0, 0.0, 0.0, "Naturaliste", "Naturaliste", null, 0.0, 0.0, 1.0, 1.0 ), + new SkillInfo( 3, "Item Identification", 0.0, 0.0, 0.0, "Marchand", "Marchande", null, 0.0, 0.0, 1.0, 1.0 ), + new SkillInfo( 4, "Arms Lore", 0.0, 0.0, 0.0, "Ma�tre d'Armes", "Ma�tre d'Armes", null, 0.75, 0.15, 0.1, 1.0 ), + new SkillInfo( 5, "Parrying", 7.5, 2.5, 0.0, "Gardien", "Gardien", null, 0.75, 0.25, 0.0, 1.0 ), + new SkillInfo( 6, "Begging", 0.0, 0.0, 0.0, "Mendiant", "Mendiante", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 7, "Blacksmithy", 10.0, 0.0, 0.0, "Forgeron", "Forgeronne", null, 1.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 8, "Bowcraft/Fletching", 6.0, 16.0, 0.0, "Arctier", "Arctiere", null, 0.6, 1.6, 0.0, 1.0 ), + new SkillInfo( 9, "Peacemaking", 0.0, 0.0, 0.0, "Pacificateur", "Pacificatrice", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 10, "Camping", 20.0, 15.0, 15.0, "Explorateur", "Exploratrice", null, 2.0, 1.5, 1.5, 1.0 ), + new SkillInfo( 11, "Carpentry", 20.0, 5.0, 0.0, "Charpentier", "Charpentiere", null, 2.0, 0.5, 0.0, 1.0 ), + new SkillInfo( 12, "Cartography", 0.0, 7.5, 7.5, "Cartographe", "Cartographe", null, 0.0, 0.75, 0.75, 1.0 ), + new SkillInfo( 13, "Cooking", 0.0, 20.0, 30.0, "Cuisinier", "Cuisiniere", null, 0.0, 2.0, 3.0, 1.0 ), + new SkillInfo( 14, "Detecting Hidden", 0.0, 0.0, 0.0, "Eclaireur", "Eclaireuse", null, 0.0, 0.4, 0.6, 1.0 ), + new SkillInfo( 15, "Discordance", 0.0, 2.5, 2.5, "Demoralisateur", "Demolarisatrice", null, 0.0, 0.25, 0.25, 1.0 ), + new SkillInfo( 16, "Evaluating Intelligence", 0.0, 0.0, 0.0, "Erudit","Erudite", null, 0.0, 0.0, 1.0, 1.0 ), + new SkillInfo( 17, "Healing", 6.0, 6.0, 8.0, "Soigneur", "Soigneuse", null, 0.6, 0.6, 0.8, 1.0 ), + new SkillInfo( 18, "Fishing", 0.0, 0.0, 0.0, "Pecheur", "Pecheuse", null, 0.5, 0.5, 0.0, 1.0 ), + new SkillInfo( 19, "Forensic Evaluation", 0.0, 0.0, 0.0, "Detective", "Detective", null, 0.0, 0.2, 0.8, 1.0 ), + new SkillInfo( 20, "Herding", 16.25, 6.25, 2.5, "Berger", "Bergere", null, 1.625, 0.625, 0.25, 1.0 ), + new SkillInfo( 21, "Hiding", 0.0, 0.0, 0.0, "Ombre", "Ombre", null, 0.0, 0.8, 0.2, 1.0 ), + new SkillInfo( 22, "Provocation", 0.0, 4.5, 0.5, "Provocateur", "Provocatrice", null, 0.0, 0.45, 0.05, 1.0 ), + new SkillInfo( 23, "Inscription", 0.0, 2.0, 8.0, "Scribe", "Scribe", null, 0.0, 0.2, 0.8, 1.0 ), + new SkillInfo( 24, "Lockpicking", 0.0, 25.0, 0.0, "Serrurier", "Serruriere",null, 0.0, 2.0, 0.0, 1.0 ), + new SkillInfo( 25, "Magery", 0.0, 0.0, 15.0, "Mage", "Mage", null, 0.0, 0.0, 1.5, 1.0 ), + new SkillInfo( 26, "Resisting Spells", 0.0, 0.0, 0.0, "Sorcier", "Sorciere", null, 0.25, 0.25, 0.5, 1.0 ), + new SkillInfo( 27, "Tactics", 0.0, 0.0, 0.0, "Tacticien", "Tacticienne", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 28, "Snooping", 0.0, 25.0, 0.0, "Espion", "Espionne", null, 0.0, 2.5, 0.0, 1.0 ), + new SkillInfo( 29, "Musicianship", 0.0, 0.0, 0.0, "Barde", "Barde", null, 0.0, 0.8, 0.2, 1.0 ), + new SkillInfo( 30, "Poisoning", 0.0, 4.0, 16.0, "Assassin", "Assassine", null, 0.0, 0.4, 1.6, 1.0 ), + new SkillInfo( 31, "Archery", 2.5, 7.5, 0.0, "Archer", "Archere", null, 0.25, 0.75, 0.0, 1.0 ), + new SkillInfo( 32, "Spirit Speak", 0.0, 0.0, 0.0, "Voyant", "Voyante", null, 0.0, 0.0, 1.0, 1.0 ), + new SkillInfo( 33, "Stealing", 0.0, 10.0, 0.0, "Roublard", "Roublarde", null, 0.0, 1.0, 0.0, 1.0 ), + new SkillInfo( 34, "Tailoring", 3.75, 16.25, 5.0, "Couturier", "Couturiere", null, 0.38, 1.63, 0.5, 1.0 ), + new SkillInfo( 35, "Animal Taming", 14.0, 2.0, 4.0, "Animalier", "Animaliere", null, 1.4, 0.2, 0.4, 1.0 ), + new SkillInfo( 36, "Taste Identification", 0.0, 0.0, 0.0, "Gouteur", "Gouteuse", null, 0.2, 0.0, 0.8, 1.0 ), + new SkillInfo( 37, "Tinkering", 5.0, 2.0, 3.0, "Bricoleur", "Bricoleuse", null, 0.5, 0.2, 0.3, 1.0 ), + new SkillInfo( 38, "Tracking", 0.0, 12.5, 12.5, "Pisteur", "Pisteuse", null, 0.0, 1.25, 1.25, 1.0 ), + new SkillInfo( 39, "Veterinary", 8.0, 4.0, 8.0, "Veterinaire", "Veterinaire", null, 0.8, 0.4, 0.8, 1.0 ), + new SkillInfo( 40, "Swordsmanship", 7.5, 2.5, 0.0, "Epeiste", "Epeiste" ,null, 0.75, 0.25, 0.0, 1.0 ), + new SkillInfo( 41, "Mace Fighting", 9.0, 1.0, 0.0, "Mercenaire", "Mercenaire", null, 0.9, 0.1, 0.0, 1.0 ), + new SkillInfo( 42, "Fencing", 4.5, 5.5, 0.0, "Escrimeur", "Escrimeuse", null, 0.45, 0.55, 0.0, 1.0 ), + new SkillInfo( 43, "Wrestling", 9.0, 1.0, 0.0, "Lutteur", "Lutteuse", null, 0.9, 0.1, 0.0, 1.0 ), + new SkillInfo( 44, "Lumberjacking", 20.0, 0.0, 0.0, "Bucheron", "Bucheronne", null, 2.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 45, "Mining", 20.0, 0.0, 0.0, "Mineur", "Mineuse", null, 2.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 46, "Meditation", 0.0, 0.0, 0.0, "Sage", "Sage", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 47, "Stealth", 0.0, 0.0, 0.0, "Rogue", "Rogue", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 48, "Remove Trap", 0.0, 0.0, 0.0, "Trappeur", "Trappeuse", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 49, "Necromancy", 0.0, 0.0, 0.0, "Necromancien", "Necromancienne", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 50, "Focus", 0.0, 0.0, 0.0, "Athlete", "Athlete", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 51, "Chivalry", 0.0, 0.0, 0.0, "Paladin", "Paladine", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 52, "Bushido", 0.0, 0.0, 0.0, "Protecteur", "Protectrice", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 53, "Ninjitsu", 0.0, 0.0, 0.0, "Assassin", "Assassine", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 54, "Spellweaving", 0.0, 0.0, 0.0, "Arcaniste", "Arcaniste", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 55, "Mysticism", 0.0, 0.0, 0.0, "Mystique", "Mystique", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 56, "Imbuing", 0.0, 0.0, 0.0, "Artificier", "Artificiere", null, 0.0, 0.0, 0.0, 1.0 ), + new SkillInfo( 57, "Throwing", 0.0, 0.0, 0.0, "Lanceur de couteaux", "Lanceuse de couteaux", null, 0.0, 0.0, 0.0, 1.0 ), + }; + + public static SkillInfo[] Table + { + get + { + return m_Table; + } + set + { + m_Table = value; + } + } + } + + [PropertyObject] + public class Skills : IEnumerable + { + private Mobile m_Owner; + private Skill[] m_Skills; + private int m_Total, m_Cap; + private Skill m_Highest; + + #region Skill Getters & Setters + [CommandProperty(AccessLevel.Counselor)] + public Skill Alchemy { get { return this[SkillName.Alchemy]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Anatomy { get { return this[SkillName.Anatomy]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill AnimalLore { get { return this[SkillName.AnimalLore]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill ItemID { get { return this[SkillName.ItemID]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill ArmsLore { get { return this[SkillName.ArmsLore]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Parry { get { return this[SkillName.Parry]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Begging { get { return this[SkillName.Begging]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Blacksmith { get { return this[SkillName.Blacksmith]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Fletching { get { return this[SkillName.Fletching]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Peacemaking { get { return this[SkillName.Peacemaking]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Camping { get { return this[SkillName.Camping]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Carpentry { get { return this[SkillName.Carpentry]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Cartography { get { return this[SkillName.Cartography]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Cooking { get { return this[SkillName.Cooking]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill DetectHidden { get { return this[SkillName.DetectHidden]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Discordance { get { return this[SkillName.Discordance]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill EvalInt { get { return this[SkillName.EvalInt]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Healing { get { return this[SkillName.Healing]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Fishing { get { return this[SkillName.Fishing]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Forensics { get { return this[SkillName.Forensics]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Herding { get { return this[SkillName.Herding]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Hiding { get { return this[SkillName.Hiding]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Provocation { get { return this[SkillName.Provocation]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Inscribe { get { return this[SkillName.Inscribe]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Lockpicking { get { return this[SkillName.Lockpicking]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Magery { get { return this[SkillName.Magery]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill MagicResist { get { return this[SkillName.MagicResist]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Tactics { get { return this[SkillName.Tactics]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Snooping { get { return this[SkillName.Snooping]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Musicianship { get { return this[SkillName.Musicianship]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Poisoning { get { return this[SkillName.Poisoning]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Archery { get { return this[SkillName.Archery]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill SpiritSpeak { get { return this[SkillName.SpiritSpeak]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Stealing { get { return this[SkillName.Stealing]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Tailoring { get { return this[SkillName.Tailoring]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill AnimalTaming { get { return this[SkillName.AnimalTaming]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill TasteID { get { return this[SkillName.TasteID]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Tinkering { get { return this[SkillName.Tinkering]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Tracking { get { return this[SkillName.Tracking]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Veterinary { get { return this[SkillName.Veterinary]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Swords { get { return this[SkillName.Swords]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Macing { get { return this[SkillName.Macing]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Fencing { get { return this[SkillName.Fencing]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Wrestling { get { return this[SkillName.Wrestling]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Lumberjacking { get { return this[SkillName.Lumberjacking]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Mining { get { return this[SkillName.Mining]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Meditation { get { return this[SkillName.Meditation]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Stealth { get { return this[SkillName.Stealth]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill RemoveTrap { get { return this[SkillName.RemoveTrap]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Necromancy { get { return this[SkillName.Necromancy]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Focus { get { return this[SkillName.Focus]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Chivalry { get { return this[SkillName.Chivalry]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Bushido { get { return this[SkillName.Bushido]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Ninjitsu { get { return this[SkillName.Ninjitsu]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Spellweaving { get { return this[SkillName.Spellweaving]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Mysticism { get { return this[SkillName.Mysticism]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Imbuing { get { return this[SkillName.Imbuing]; } set { } } + + [CommandProperty(AccessLevel.Counselor)] + public Skill Throwing { get { return this[SkillName.Throwing]; } set { } } + + #endregion + + [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] + public int Cap + { + get { return m_Cap; } + set { m_Cap = value; } + } + + public int Total + { + get { return m_Total; } + set { m_Total = value; } + } + + public Mobile Owner + { + get { return m_Owner; } + } + + public int Length + { + get { return m_Skills.Length; } + } + + public Skill this[SkillName name] + { + get { return this[(int)name]; } + } + + public Skill this[int skillID] + { + get + { + if (skillID < 0 || skillID >= m_Skills.Length) + return null; + + Skill sk = m_Skills[skillID]; + + if (sk == null) + m_Skills[skillID] = sk = new Skill(this, SkillInfo.Table[skillID], 0, 1000, SkillLock.Up); + + return sk; + } + } + + public override string ToString() + { + return "..."; + } + + public static bool UseSkill(Mobile from, SkillName name) + { + return UseSkill(from, (int)name); + } + + public static bool UseSkill(Mobile from, int skillID) + { + if (!from.CheckAlive()) + return false; + else if (!from.Region.OnSkillUse(from, skillID)) + return false; + else if (!from.AllowSkillUse((SkillName)skillID)) + return false; + + if (skillID >= 0 && skillID < SkillInfo.Table.Length) + { + SkillInfo info = SkillInfo.Table[skillID]; + + if (info.Callback != null) + { + if (from.NextSkillTime <= DateTime.Now && from.Spell == null) + { + from.DisruptiveAction(); + + from.NextSkillTime = DateTime.Now + info.Callback(from); + + return true; + } + else + { + from.SendSkillMessage(); + } + } + else + { + from.SendLocalizedMessage(500014); // That skill cannot be used directly. + } + } + + return false; + } + + public Skill Highest + { + get + { + if (m_Highest == null) + { + Skill highest = null; + int value = int.MinValue; + + for (int i = 0; i < m_Skills.Length; ++i) + { + Skill sk = m_Skills[i]; + + if (sk != null && sk.BaseFixedPoint > value) + { + value = sk.BaseFixedPoint; + highest = sk; + } + } + + if (highest == null && m_Skills.Length > 0) + highest = this[0]; + + m_Highest = highest; + } + + return m_Highest; + } + } + + public void Serialize(GenericWriter writer) + { + m_Total = 0; + + writer.Write((int)3); // version + + writer.Write((int)m_Cap); + writer.Write((int)m_Skills.Length); + + for (int i = 0; i < m_Skills.Length; ++i) + { + Skill sk = m_Skills[i]; + + if (sk == null) + { + writer.Write((byte)0xFF); + } + else + { + sk.Serialize(writer); + m_Total += sk.BaseFixedPoint; + } + } + } + + public Skills(Mobile owner) + { + m_Owner = owner; + m_Cap = 7000; + + SkillInfo[] info = SkillInfo.Table; + + m_Skills = new Skill[info.Length]; + + //for ( int i = 0; i < info.Length; ++i ) + // m_Skills[i] = new Skill( this, info[i], 0, 1000, SkillLock.Up ); + } + + public Skills(Mobile owner, GenericReader reader) + { + m_Owner = owner; + + int version = reader.ReadInt(); + + switch (version) + { + case 3: + case 2: + { + m_Cap = reader.ReadInt(); + + goto case 1; + } + case 1: + { + if (version < 2) + m_Cap = 7000; + + if (version < 3) + /*m_Total =*/ + reader.ReadInt(); + + SkillInfo[] info = SkillInfo.Table; + + m_Skills = new Skill[info.Length]; + + int count = reader.ReadInt(); + + for (int i = 0; i < count; ++i) + { + if (i < info.Length) + { + Skill sk = new Skill(this, info[i], reader); + + if (sk.BaseFixedPoint != 0 || sk.CapFixedPoint != 1000 || sk.Lock != SkillLock.Up) + { + m_Skills[i] = sk; + m_Total += sk.BaseFixedPoint; + } + } + else + { + new Skill(this, null, reader); + } + } + + //for ( int i = count; i < info.Length; ++i ) + // m_Skills[i] = new Skill( this, info[i], 0, 1000, SkillLock.Up ); + + break; + } + case 0: + { + reader.ReadInt(); + + goto case 1; + } + } + } + + public void OnSkillChange(Skill skill) + { + if (skill == m_Highest) // could be downgrading the skill, force a recalc + m_Highest = null; + else if (m_Highest != null && skill.BaseFixedPoint > m_Highest.BaseFixedPoint) + m_Highest = skill; + + m_Owner.OnSkillInvalidated(skill); + + NetState ns = m_Owner.NetState; + + if (ns != null) + ns.Send(new SkillChange(skill)); + } + + public IEnumerator GetEnumerator() + { + return m_Skills.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Server/Targeting/LandTarget.cs b/Server/Targeting/LandTarget.cs new file mode 100644 index 0000000..e39d554 --- /dev/null +++ b/Server/Targeting/LandTarget.cs @@ -0,0 +1,104 @@ +/*************************************************************************** + * LandTarget.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: LandTarget.cs 591 2010-12-06 06:45:45Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Targeting +{ + public class LandTarget : IPoint3D + { + private Point3D m_Location; + private int m_TileID; + + public LandTarget( Point3D location, Map map ) + { + m_Location = location; + + if ( map != null ) + { + m_Location.Z = map.GetAverageZ( m_Location.X, m_Location.Y ); + m_TileID = map.Tiles.GetLandTile( m_Location.X, m_Location.Y ).ID & TileData.MaxLandValue; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public string Name + { + get + { + return TileData.LandTable[m_TileID].Name; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public TileFlag Flags + { + get + { + return TileData.LandTable[m_TileID].Flags; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int TileID + { + get + { + return m_TileID; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public Point3D Location + { + get + { + return m_Location; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int X + { + get + { + return m_Location.X; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Y + { + get + { + return m_Location.Y; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Z + { + get + { + return m_Location.Z; + } + } + } +} \ No newline at end of file diff --git a/Server/Targeting/MultiTarget.cs b/Server/Targeting/MultiTarget.cs new file mode 100644 index 0000000..46927d0 --- /dev/null +++ b/Server/Targeting/MultiTarget.cs @@ -0,0 +1,76 @@ +/*************************************************************************** + * MultiTarget.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: MultiTarget.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server; +using Server.Network; + +namespace Server.Targeting +{ + public abstract class MultiTarget : Target + { + private int m_MultiID; + private Point3D m_Offset; + + public int MultiID + { + get + { + return m_MultiID; + } + set + { + m_MultiID = value; + } + } + + public Point3D Offset + { + get + { + return m_Offset; + } + set + { + m_Offset = value; + } + } + + protected MultiTarget( int multiID, Point3D offset ) + : this( multiID, offset, 10, true, TargetFlags.None ) + { + } + + protected MultiTarget( int multiID, Point3D offset, int range, bool allowGround, TargetFlags flags ) + : base( range, allowGround, flags ) + { + m_MultiID = multiID; + m_Offset = offset; + } + + public override Packet GetPacketFor( NetState ns ) + { + if ( ns.HighSeas ) + return new MultiTargetReqHS( this ); + else + return new MultiTargetReq( this ); + } + } +} \ No newline at end of file diff --git a/Server/Targeting/StaticTarget.cs b/Server/Targeting/StaticTarget.cs new file mode 100644 index 0000000..7910f84 --- /dev/null +++ b/Server/Targeting/StaticTarget.cs @@ -0,0 +1,100 @@ +/*************************************************************************** + * StaticTarget.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: StaticTarget.cs 591 2010-12-06 06:45:45Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Targeting +{ + public class StaticTarget : IPoint3D + { + private Point3D m_Location; + private int m_ItemID; + + public StaticTarget( Point3D location, int itemID ) + { + m_Location = location; + m_ItemID = itemID & TileData.MaxItemValue; + m_Location.Z += TileData.ItemTable[m_ItemID].CalcHeight; + } + + [CommandProperty( AccessLevel.Counselor )] + public Point3D Location + { + get + { + return m_Location; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public string Name + { + get + { + return TileData.ItemTable[m_ItemID].Name; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public TileFlag Flags + { + get + { + return TileData.ItemTable[m_ItemID].Flags; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int X + { + get + { + return m_Location.X; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Y + { + get + { + return m_Location.Y; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int Z + { + get + { + return m_Location.Z; + } + } + + [CommandProperty( AccessLevel.Counselor )] + public int ItemID + { + get + { + return m_ItemID; + } + } + } +} \ No newline at end of file diff --git a/Server/Targeting/Target.cs b/Server/Targeting/Target.cs new file mode 100644 index 0000000..961c498 --- /dev/null +++ b/Server/Targeting/Target.cs @@ -0,0 +1,384 @@ +/*************************************************************************** + * Target.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Target.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using Server.Network; + +namespace Server.Targeting +{ + public abstract class Target + { + private static int m_NextTargetID; + + private static bool m_TargetIDValidation = true; + + public static bool TargetIDValidation + { + get { return m_TargetIDValidation; } + set { m_TargetIDValidation = value; } + } + + private int m_TargetID; + private int m_Range; + private bool m_AllowGround; + private bool m_CheckLOS; + private bool m_AllowNonlocal; + private bool m_DisallowMultis; + private TargetFlags m_Flags; + private DateTime m_TimeoutTime; + + public DateTime TimeoutTime{ get{ return m_TimeoutTime; } } + + protected Target( int range, bool allowGround, TargetFlags flags ) + { + m_TargetID = ++m_NextTargetID; + m_Range = range; + m_AllowGround = allowGround; + m_Flags = flags; + + m_CheckLOS = true; + } + + public static void Cancel( Mobile m ) + { + NetState ns = m.NetState; + + if ( ns != null ) + ns.Send( CancelTarget.Instance ); + + Target targ = m.Target; + + if ( targ != null ) + targ.OnTargetCancel( m, TargetCancelType.Canceled ); + } + + private Timer m_TimeoutTimer; + + public void BeginTimeout( Mobile from, TimeSpan delay ) + { + m_TimeoutTime = DateTime.Now + delay; + + if ( m_TimeoutTimer != null ) + m_TimeoutTimer.Stop(); + + m_TimeoutTimer = new TimeoutTimer( this, from, delay ); + m_TimeoutTimer.Start(); + } + + public void CancelTimeout() + { + if ( m_TimeoutTimer != null ) + m_TimeoutTimer.Stop(); + + m_TimeoutTimer = null; + } + + public void Timeout( Mobile from ) + { + CancelTimeout(); + from.ClearTarget(); + + Cancel( from ); + + OnTargetCancel( from, TargetCancelType.Timeout ); + OnTargetFinish( from ); + } + + private class TimeoutTimer : Timer + { + private Target m_Target; + private Mobile m_Mobile; + + private static TimeSpan ThirtySeconds = TimeSpan.FromSeconds( 30.0 ); + private static TimeSpan TenSeconds = TimeSpan.FromSeconds( 10.0 ); + private static TimeSpan OneSecond = TimeSpan.FromSeconds( 1.0 ); + + public TimeoutTimer( Target target, Mobile m, TimeSpan delay ) : base( delay ) + { + m_Target = target; + m_Mobile = m; + + if ( delay >= ThirtySeconds ) + Priority = TimerPriority.FiveSeconds; + else if ( delay >= TenSeconds ) + Priority = TimerPriority.OneSecond; + else if ( delay >= OneSecond ) + Priority = TimerPriority.TwoFiftyMS; + else + Priority = TimerPriority.TwentyFiveMS; + } + + protected override void OnTick() + { + if ( m_Mobile.Target == m_Target ) + m_Target.Timeout( m_Mobile ); + } + } + + public bool CheckLOS + { + get + { + return m_CheckLOS; + } + set + { + m_CheckLOS = value; + } + } + + public bool DisallowMultis + { + get + { + return m_DisallowMultis; + } + set + { + m_DisallowMultis = value; + } + } + + public bool AllowNonlocal + { + get + { + return m_AllowNonlocal; + } + set + { + m_AllowNonlocal = value; + } + } + + public int TargetID + { + get + { + return m_TargetID; + } + } + + public virtual Packet GetPacketFor( NetState ns ) + { + return new TargetReq( this ); + } + + public void Cancel( Mobile from, TargetCancelType type ) + { + CancelTimeout(); + from.ClearTarget(); + + OnTargetCancel( from, type ); + OnTargetFinish( from ); + } + + public void Invoke( Mobile from, object targeted ) + { + CancelTimeout(); + from.ClearTarget(); + + if ( from.Deleted ) + { + OnTargetCancel( from, TargetCancelType.Canceled ); + OnTargetFinish( from ); + return; + } + + Point3D loc; + Map map; + + if ( targeted is LandTarget ) + { + loc = ((LandTarget)targeted).Location; + map = from.Map; + } + else if ( targeted is StaticTarget ) + { + loc = ((StaticTarget)targeted).Location; + map = from.Map; + } + else if ( targeted is Mobile ) + { + if ( ((Mobile)targeted).Deleted ) + { + OnTargetDeleted( from, targeted ); + OnTargetFinish( from ); + return; + } + else if ( !((Mobile)targeted).CanTarget ) + { + OnTargetUntargetable( from, targeted ); + OnTargetFinish( from ); + return; + } + + loc = ((Mobile)targeted).Location; + map = ((Mobile)targeted).Map; + } + else if ( targeted is Item ) + { + Item item = (Item)targeted; + + if ( item.Deleted ) + { + OnTargetDeleted( from, targeted ); + OnTargetFinish( from ); + return; + } + else if ( !item.CanTarget ) + { + OnTargetUntargetable( from, targeted ); + OnTargetFinish( from ); + return; + } + + object root = item.RootParent; + + if ( !m_AllowNonlocal && root is Mobile && root != from && from.AccessLevel == AccessLevel.Player ) + { + OnNonlocalTarget( from, targeted ); + OnTargetFinish( from ); + return; + } + + loc = item.GetWorldLocation(); + map = item.Map; + } + else + { + OnTargetCancel( from, TargetCancelType.Canceled ); + OnTargetFinish( from ); + return; + } + + if ( map == null || map != from.Map || ( m_Range != -1 && !from.InRange( loc, m_Range ) ) ) + { + OnTargetOutOfRange( from, targeted ); + } + else + { + if ( !from.CanSee( targeted ) ) + OnCantSeeTarget( from, targeted ); + else if ( m_CheckLOS && !from.InLOS( targeted ) ) + OnTargetOutOfLOS( from, targeted ); + else if ( targeted is Item && ((Item)targeted).InSecureTrade ) + OnTargetInSecureTrade( from, targeted ); + else if ( targeted is Item && !((Item)targeted).IsAccessibleTo( from ) ) + OnTargetNotAccessible( from, targeted ); + else if ( targeted is Item && !((Item)targeted).CheckTarget( from, this, targeted ) ) + OnTargetUntargetable( from, targeted ); + else if ( targeted is Mobile && !((Mobile)targeted).CheckTarget( from, this, targeted ) ) + OnTargetUntargetable( from, targeted ); + else if ( from.Region.OnTarget( from, this, targeted ) ) + OnTarget( from, targeted ); + } + + OnTargetFinish( from ); + } + + protected virtual void OnTarget( Mobile from, object targeted ) + { + } + + protected virtual void OnTargetNotAccessible( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500447 ); // That is not accessible. + } + + protected virtual void OnTargetInSecureTrade( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500447 ); // That is not accessible. + } + + protected virtual void OnNonlocalTarget( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500447 ); // That is not accessible. + } + + protected virtual void OnCantSeeTarget( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + + protected virtual void OnTargetOutOfLOS( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500237 ); // Target can not be seen. + } + + protected virtual void OnTargetOutOfRange( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500446 ); // That is too far away. + } + + protected virtual void OnTargetDeleted( Mobile from, object targeted ) + { + } + + protected virtual void OnTargetUntargetable( Mobile from, object targeted ) + { + from.SendLocalizedMessage( 500447 ); // That is not accessible. + } + + protected virtual void OnTargetCancel( Mobile from, TargetCancelType cancelType ) + { + } + + protected virtual void OnTargetFinish( Mobile from ) + { + } + + public int Range + { + get + { + return m_Range; + } + set + { + m_Range = value; + } + } + + public bool AllowGround + { + get + { + return m_AllowGround; + } + set + { + m_AllowGround = value; + } + } + + public TargetFlags Flags + { + get + { + return m_Flags; + } + set + { + m_Flags = value; + } + } + } +} \ No newline at end of file diff --git a/Server/Targeting/TargetCancelType.cs b/Server/Targeting/TargetCancelType.cs new file mode 100644 index 0000000..7e02b36 --- /dev/null +++ b/Server/Targeting/TargetCancelType.cs @@ -0,0 +1,32 @@ +/*************************************************************************** + * TargetCancelType.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TargetCancelType.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Targeting +{ + public enum TargetCancelType + { + Overriden, + Canceled, + Disconnected, + Timeout + } +} \ No newline at end of file diff --git a/Server/Targeting/TargetFlags.cs b/Server/Targeting/TargetFlags.cs new file mode 100644 index 0000000..78738b2 --- /dev/null +++ b/Server/Targeting/TargetFlags.cs @@ -0,0 +1,31 @@ +/*************************************************************************** + * TargetFlags.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TargetFlags.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server.Targeting +{ + public enum TargetFlags : byte + { + None = 0x00, + Harmful = 0x01, + Beneficial = 0x02, + } +} \ No newline at end of file diff --git a/Server/TileData.cs b/Server/TileData.cs new file mode 100644 index 0000000..2bae0db --- /dev/null +++ b/Server/TileData.cs @@ -0,0 +1,372 @@ +/*************************************************************************** + * TileData.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TileData.cs 644 2010-12-23 09:18:45Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Text; + +namespace Server +{ + public struct LandData + { + private string m_Name; + private TileFlag m_Flags; + + public LandData( string name, TileFlag flags ) + { + m_Name = name; + m_Flags = flags; + } + + public string Name + { + get{ return m_Name; } + set{ m_Name = value; } + } + + public TileFlag Flags + { + get{ return m_Flags; } + set{ m_Flags = value; } + } + } + + public struct ItemData + { + private string m_Name; + private TileFlag m_Flags; + private byte m_Weight; + private byte m_Quality; + private byte m_Quantity; + private byte m_Value; + private byte m_Height; + + public ItemData( string name, TileFlag flags, int weight, int quality, int quantity, int value, int height ) + { + m_Name = name; + m_Flags = flags; + m_Weight = (byte)weight; + m_Quality = (byte)quality; + m_Quantity = (byte)quantity; + m_Value = (byte)value; + m_Height = (byte)height; + } + + public string Name + { + get{ return m_Name; } + set{ m_Name = value; } + } + + public TileFlag Flags + { + get{ return m_Flags; } + set{ m_Flags = value; } + } + + public bool Bridge + { + get{ return (m_Flags & TileFlag.Bridge) != 0; } + set + { + if ( value ) + m_Flags |= TileFlag.Bridge; + else + m_Flags &= ~TileFlag.Bridge; + } + } + + public bool Impassable + { + get{ return (m_Flags & TileFlag.Impassable) != 0; } + set + { + if ( value ) + m_Flags |= TileFlag.Impassable; + else + m_Flags &= ~TileFlag.Impassable; + } + } + + public bool Surface + { + get{ return (m_Flags & TileFlag.Surface) != 0; } + set + { + if ( value ) + m_Flags |= TileFlag.Surface; + else + m_Flags &= ~TileFlag.Surface; + } + } + + public int Weight + { + get{ return m_Weight; } + set{ m_Weight = (byte)value; } + } + + public int Quality + { + get{ return m_Quality; } + set{ m_Quality = (byte)value; } + } + + public int Quantity + { + get{ return m_Quantity; } + set{ m_Quantity = (byte)value; } + } + + public int Value + { + get{ return m_Value; } + set{ m_Value = (byte)value; } + } + + public int Height + { + get{ return m_Height; } + set{ m_Height = (byte)value; } + } + + public int CalcHeight + { + get + { + if ( (m_Flags & TileFlag.Bridge) != 0 ) + return m_Height / 2; + else + return m_Height; + } + } + } + + [Flags] + public enum TileFlag : long + { + None = 0x00000000, + Background = 0x00000001, + Weapon = 0x00000002, + Transparent = 0x00000004, + Translucent = 0x00000008, + Wall = 0x00000010, + Damaging = 0x00000020, + Impassable = 0x00000040, + Wet = 0x00000080, + Unknown1 = 0x00000100, + Surface = 0x00000200, + Bridge = 0x00000400, + Generic = 0x00000800, + Window = 0x00001000, + NoShoot = 0x00002000, + ArticleA = 0x00004000, + ArticleAn = 0x00008000, + Internal = 0x00010000, + Foliage = 0x00020000, + PartialHue = 0x00040000, + Unknown2 = 0x00080000, + Map = 0x00100000, + Container = 0x00200000, + Wearable = 0x00400000, + LightSource = 0x00800000, + Animation = 0x01000000, + NoDiagonal = 0x02000000, + Unknown3 = 0x04000000, + Armor = 0x08000000, + Roof = 0x10000000, + Door = 0x20000000, + StairBack = 0x40000000, + StairRight = 0x80000000 + } + + public static class TileData + { + private static LandData[] m_LandData; + private static ItemData[] m_ItemData; + + public static LandData[] LandTable + { + get + { + return m_LandData; + } + } + + public static ItemData[] ItemTable + { + get + { + return m_ItemData; + } + } + + private static int m_MaxLandValue; + private static int m_MaxItemValue; + + public static int MaxLandValue { + get { return m_MaxLandValue; } + } + + public static int MaxItemValue { + get { return m_MaxItemValue; } + } + + private static byte[] m_StringBuffer = new byte[20]; + + private static string ReadNameString( BinaryReader bin ) + { + bin.Read( m_StringBuffer, 0, 20 ); + + int count; + + for ( count = 0; count < 20 && m_StringBuffer[count] != 0; ++count ); + + return Encoding.ASCII.GetString( m_StringBuffer, 0, count ); + } + + static TileData() + { + string filePath = Core.FindDataFile( "tiledata.mul" ); + + if ( File.Exists( filePath ) ) + { + using ( FileStream fs = new FileStream( filePath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + BinaryReader bin = new BinaryReader( fs ); + + if ( fs.Length == 3188736 ) { // 7.0.9.0 + m_LandData = new LandData[0x4000]; + + for ( int i = 0; i < 0x4000; ++i ) + { + if ( i == 1 || ( i > 0 && (i & 0x1F) == 0 ) ) + { + bin.ReadInt32(); // header + } + + TileFlag flags = (TileFlag)bin.ReadInt64(); + bin.ReadInt16(); // skip 2 bytes -- textureID + + m_LandData[i] = new LandData( ReadNameString( bin ), flags ); + } + + m_ItemData = new ItemData[0x10000]; + + for ( int i = 0; i < 0x10000; ++i ) + { + if ( (i & 0x1F) == 0 ) + { + bin.ReadInt32(); // header + } + + TileFlag flags = (TileFlag)bin.ReadInt64(); + int weight = bin.ReadByte(); + int quality = bin.ReadByte(); + bin.ReadInt16(); + bin.ReadByte(); + int quantity = bin.ReadByte(); + bin.ReadInt32(); + bin.ReadByte(); + int value = bin.ReadByte(); + int height = bin.ReadByte(); + + m_ItemData[i] = new ItemData( ReadNameString( bin ), flags, weight, quality, quantity, value, height ); + } + } else { + m_LandData = new LandData[0x4000]; + + for ( int i = 0; i < 0x4000; ++i ) + { + if ( (i & 0x1F) == 0 ) + { + bin.ReadInt32(); // header + } + + TileFlag flags = (TileFlag)bin.ReadInt32(); + bin.ReadInt16(); // skip 2 bytes -- textureID + + m_LandData[i] = new LandData( ReadNameString( bin ), flags ); + } + + if ( fs.Length == 1644544 ) { // 7.0.0.0 + m_ItemData = new ItemData[0x8000]; + + for ( int i = 0; i < 0x8000; ++i ) + { + if ( (i & 0x1F) == 0 ) + { + bin.ReadInt32(); // header + } + + TileFlag flags = (TileFlag)bin.ReadInt32(); + int weight = bin.ReadByte(); + int quality = bin.ReadByte(); + bin.ReadInt16(); + bin.ReadByte(); + int quantity = bin.ReadByte(); + bin.ReadInt32(); + bin.ReadByte(); + int value = bin.ReadByte(); + int height = bin.ReadByte(); + + m_ItemData[i] = new ItemData( ReadNameString( bin ), flags, weight, quality, quantity, value, height ); + } + } else { + m_ItemData = new ItemData[0x4000]; + + for ( int i = 0; i < 0x4000; ++i ) + { + if ( (i & 0x1F) == 0 ) + { + bin.ReadInt32(); // header + } + + TileFlag flags = (TileFlag)bin.ReadInt32(); + int weight = bin.ReadByte(); + int quality = bin.ReadByte(); + bin.ReadInt16(); + bin.ReadByte(); + int quantity = bin.ReadByte(); + bin.ReadInt32(); + bin.ReadByte(); + int value = bin.ReadByte(); + int height = bin.ReadByte(); + + m_ItemData[i] = new ItemData( ReadNameString( bin ), flags, weight, quality, quantity, value, height ); + } + } + } + } + + m_MaxLandValue = m_LandData.Length - 1; + m_MaxItemValue = m_ItemData.Length - 1; + } + else + { + Console.WriteLine( "tiledata.mul was not found" ); + Console.WriteLine( "Make sure your Scripts/Misc/DataPath.cs is properly configured" ); + Console.WriteLine( "After pressing return an exception will be thrown and the server will terminate" ); + + throw new Exception( String.Format( "TileData: {0} not found", filePath ) ); + } + } + } +} \ No newline at end of file diff --git a/Server/TileList.cs b/Server/TileList.cs new file mode 100644 index 0000000..1055d7a --- /dev/null +++ b/Server/TileList.cs @@ -0,0 +1,92 @@ +/*************************************************************************** + * TileList.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TileList.cs 591 2010-12-06 06:45:45Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + public class TileList + { + private StaticTile[] m_Tiles; + private int m_Count; + + public TileList() + { + m_Tiles = new StaticTile[8]; + m_Count = 0; + } + + public int Count + { + get + { + return m_Count; + } + } + + public void AddRange( StaticTile[] tiles ) + { + if ( (m_Count + tiles.Length) > m_Tiles.Length ) + { + StaticTile[] old = m_Tiles; + m_Tiles = new StaticTile[(m_Count + tiles.Length) * 2]; + + for ( int i = 0; i < old.Length; ++i ) + m_Tiles[i] = old[i]; + } + + for ( int i = 0; i < tiles.Length; ++i ) + m_Tiles[m_Count++] = tiles[i]; + } + + public void Add( ushort id, sbyte z ) + { + if ( (m_Count + 1) > m_Tiles.Length ) + { + StaticTile[] old = m_Tiles; + m_Tiles = new StaticTile[old.Length * 2]; + + for ( int i = 0; i < old.Length; ++i ) + m_Tiles[i] = old[i]; + } + + m_Tiles[m_Count].m_ID = id; + m_Tiles[m_Count].m_Z = z; + ++m_Count; + } + + private static StaticTile[] m_EmptyTiles = new StaticTile[0]; + + public StaticTile[] ToArray() + { + if ( m_Count == 0 ) + return m_EmptyTiles; + + StaticTile[] tiles = new StaticTile[m_Count]; + + for ( int i = 0; i < m_Count; ++i ) + tiles[i] = m_Tiles[i]; + + m_Count = 0; + + return tiles; + } + } +} \ No newline at end of file diff --git a/Server/TileMatrix.cs b/Server/TileMatrix.cs new file mode 100644 index 0000000..be74778 --- /dev/null +++ b/Server/TileMatrix.cs @@ -0,0 +1,778 @@ +/*************************************************************************** + * TileMatrix.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TileMatrix.cs 895 2012-07-31 07:07:44Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; + +namespace Server +{ + public class TileMatrix + { + private StaticTile[][][][][] m_StaticTiles; + private LandTile[][][] m_LandTiles; + + private LandTile[] m_InvalidLandBlock; + private StaticTile[][][] m_EmptyStaticBlock; + + private FileStream m_Map; + private UOPIndex m_MapIndex; + + private FileStream m_Index; + private BinaryReader m_IndexReader; + + private FileStream m_Statics; + + private int m_FileIndex; + private int m_BlockWidth, m_BlockHeight; + private int m_Width, m_Height; + + private Map m_Owner; + + private TileMatrixPatch m_Patch; + private int[][] m_StaticPatches; + private int[][] m_LandPatches; + + public Map Owner + { + get + { + return m_Owner; + } + } + + public TileMatrixPatch Patch + { + get + { + return m_Patch; + } + } + + public int BlockWidth + { + get + { + return m_BlockWidth; + } + } + + public int BlockHeight + { + get + { + return m_BlockHeight; + } + } + + public int Width + { + get + { + return m_Width; + } + } + + public int Height + { + get + { + return m_Height; + } + } + + public FileStream MapStream + { + get { return m_Map; } + set { m_Map = value; } + } + + public bool MapUOPPacked + { + get { return (m_MapIndex != null); } + } + + public FileStream IndexStream + { + get { return m_Index; } + set { m_Index = value; } + } + + public FileStream DataStream + { + get { return m_Statics; } + set { m_Statics = value; } + } + + public BinaryReader IndexReader + { + get { return m_IndexReader; } + set { m_IndexReader = value; } + } + + public bool Exists + { + get { return (m_Map != null && m_Index != null && m_Statics != null); } + } + + private static List m_Instances = new List(); + private List m_FileShare = new List(); + + public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height) + { + for (int i = 0; i < m_Instances.Count; ++i) + { + TileMatrix tm = m_Instances[i]; + + if (tm.m_FileIndex == fileIndex) + { + tm.m_FileShare.Add(this); + m_FileShare.Add(tm); + } + } + + m_Instances.Add(this); + m_FileIndex = fileIndex; + m_Width = width; + m_Height = height; + m_BlockWidth = width >> 3; + m_BlockHeight = height >> 3; + + m_Owner = owner; + + if (fileIndex != 0x7F) + { + string mapPath = Core.FindDataFile("map{0}.mul", fileIndex); + + if (File.Exists(mapPath)) + { + m_Map = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + else + { + mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex); + + if (File.Exists(mapPath)) + { + m_Map = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + m_MapIndex = new UOPIndex(m_Map); + } + } + + string indexPath = Core.FindDataFile("staidx{0}.mul", fileIndex); + + if (File.Exists(indexPath)) + { + m_Index = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + m_IndexReader = new BinaryReader(m_Index); + } + + string staticsPath = Core.FindDataFile("statics{0}.mul", fileIndex); + + if (File.Exists(staticsPath)) + m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + + m_EmptyStaticBlock = new StaticTile[8][][]; + + for (int i = 0; i < 8; ++i) + { + m_EmptyStaticBlock[i] = new StaticTile[8][]; + + for (int j = 0; j < 8; ++j) + m_EmptyStaticBlock[i][j] = new StaticTile[0]; + } + + m_InvalidLandBlock = new LandTile[196]; + + m_LandTiles = new LandTile[m_BlockWidth][][]; + m_StaticTiles = new StaticTile[m_BlockWidth][][][][]; + m_StaticPatches = new int[m_BlockWidth][]; + m_LandPatches = new int[m_BlockWidth][]; + + m_Patch = new TileMatrixPatch(this, mapID); + } + + public StaticTile[][][] EmptyStaticBlock + { + get + { + return m_EmptyStaticBlock; + } + } + + public void SetStaticBlock(int x, int y, StaticTile[][][] value) + { + if (x < 0 || y < 0 || x >= m_BlockWidth || y >= m_BlockHeight) + return; + + if (m_StaticTiles[x] == null) + m_StaticTiles[x] = new StaticTile[m_BlockHeight][][][]; + + m_StaticTiles[x][y] = value; + + if (m_StaticPatches[x] == null) + m_StaticPatches[x] = new int[(m_BlockHeight + 31) >> 5]; + + m_StaticPatches[x][y >> 5] |= 1 << (y & 0x1F); + } + + public StaticTile[][][] GetStaticBlock(int x, int y) + { + if (x < 0 || y < 0 || x >= m_BlockWidth || y >= m_BlockHeight || m_Statics == null || m_Index == null) + return m_EmptyStaticBlock; + + if (m_StaticTiles[x] == null) + m_StaticTiles[x] = new StaticTile[m_BlockHeight][][][]; + + StaticTile[][][] tiles = m_StaticTiles[x][y]; + + if (tiles == null) + { + for (int i = 0; tiles == null && i < m_FileShare.Count; ++i) + { + TileMatrix shared = m_FileShare[i]; + + if (x >= 0 && x < shared.m_BlockWidth && y >= 0 && y < shared.m_BlockHeight) + { + StaticTile[][][][] theirTiles = shared.m_StaticTiles[x]; + + if (theirTiles != null) + tiles = theirTiles[y]; + + if (tiles != null) + { + int[] theirBits = shared.m_StaticPatches[x]; + + if (theirBits != null && (theirBits[y >> 5] & (1 << (y & 0x1F))) != 0) + tiles = null; + } + } + } + + if (tiles == null) + tiles = ReadStaticBlock(x, y); + + m_StaticTiles[x][y] = tiles; + } + + return tiles; + } + + public StaticTile[] GetStaticTiles(int x, int y) + { + StaticTile[][][] tiles = GetStaticBlock(x >> 3, y >> 3); + + return tiles[x & 0x7][y & 0x7]; + } + + private static TileList m_TilesList = new TileList(); + + public StaticTile[] GetStaticTiles(int x, int y, bool multis) + { + StaticTile[][][] tiles = GetStaticBlock(x >> 3, y >> 3); + + if (multis) + { + IPooledEnumerable eable = m_Owner.GetMultiTilesAt(x, y); + + if (eable == Map.NullEnumerable.Instance) + return tiles[x & 0x7][y & 0x7]; + + bool any = false; + + foreach (StaticTile[] multiTiles in eable) + { + if (!any) + any = true; + + m_TilesList.AddRange(multiTiles); + } + + eable.Free(); + + if (!any) + return tiles[x & 0x7][y & 0x7]; + + m_TilesList.AddRange(tiles[x & 0x7][y & 0x7]); + + return m_TilesList.ToArray(); + } + else + { + return tiles[x & 0x7][y & 0x7]; + } + } + + public void SetLandBlock(int x, int y, LandTile[] value) + { + if (x < 0 || y < 0 || x >= m_BlockWidth || y >= m_BlockHeight) + return; + + if (m_LandTiles[x] == null) + m_LandTiles[x] = new LandTile[m_BlockHeight][]; + + m_LandTiles[x][y] = value; + + if (m_LandPatches[x] == null) + m_LandPatches[x] = new int[(m_BlockHeight + 31) >> 5]; + + m_LandPatches[x][y >> 5] |= 1 << (y & 0x1F); + } + + public LandTile[] GetLandBlock(int x, int y) + { + if (x < 0 || y < 0 || x >= m_BlockWidth || y >= m_BlockHeight || m_Map == null) + return m_InvalidLandBlock; + + if (m_LandTiles[x] == null) + m_LandTiles[x] = new LandTile[m_BlockHeight][]; + + LandTile[] tiles = m_LandTiles[x][y]; + + if (tiles == null) + { + for (int i = 0; tiles == null && i < m_FileShare.Count; ++i) + { + TileMatrix shared = m_FileShare[i]; + + if (x >= 0 && x < shared.m_BlockWidth && y >= 0 && y < shared.m_BlockHeight) + { + LandTile[][] theirTiles = shared.m_LandTiles[x]; + + if (theirTiles != null) + tiles = theirTiles[y]; + + if (tiles != null) + { + int[] theirBits = shared.m_LandPatches[x]; + + if (theirBits != null && (theirBits[y >> 5] & (1 << (y & 0x1F))) != 0) + tiles = null; + } + } + } + + if (tiles == null) + tiles = ReadLandBlock(x, y); + + m_LandTiles[x][y] = tiles; + } + + return tiles; + } + + public LandTile GetLandTile(int x, int y) + { + LandTile[] tiles = GetLandBlock(x >> 3, y >> 3); + + return tiles[((y & 0x7) << 3) + (x & 0x7)]; + } + + private static TileList[][] m_Lists; + + private static StaticTile[] m_TileBuffer = new StaticTile[128]; + + private unsafe StaticTile[][][] ReadStaticBlock(int x, int y) + { + try + { + m_IndexReader.BaseStream.Seek(((x * m_BlockHeight) + y) * 12, SeekOrigin.Begin); + + int lookup = m_IndexReader.ReadInt32(); + int length = m_IndexReader.ReadInt32(); + + if (lookup < 0 || length <= 0) + { + return m_EmptyStaticBlock; + } + else + { + int count = length / 7; + + m_Statics.Seek(lookup, SeekOrigin.Begin); + + if (m_TileBuffer.Length < count) + m_TileBuffer = new StaticTile[count]; + + StaticTile[] staTiles = m_TileBuffer;//new StaticTile[tileCount]; + + fixed (StaticTile* pTiles = staTiles) + { +#if !MONO + NativeReader.Read(m_Statics.SafeFileHandle.DangerousGetHandle(), pTiles, length); +#else + NativeReader.Read( m_Statics.Handle, pTiles, length ); +#endif + if (m_Lists == null) + { + m_Lists = new TileList[8][]; + + for (int i = 0; i < 8; ++i) + { + m_Lists[i] = new TileList[8]; + + for (int j = 0; j < 8; ++j) + m_Lists[i][j] = new TileList(); + } + } + + TileList[][] lists = m_Lists; + + StaticTile* pCur = pTiles, pEnd = pTiles + count; + + while (pCur < pEnd) + { + lists[pCur->m_X & 0x7][pCur->m_Y & 0x7].Add(pCur->m_ID, pCur->m_Z); + pCur = pCur + 1; + } + + StaticTile[][][] tiles = new StaticTile[8][][]; + + for (int i = 0; i < 8; ++i) + { + tiles[i] = new StaticTile[8][]; + + for (int j = 0; j < 8; ++j) + tiles[i][j] = lists[i][j].ToArray(); + } + + return tiles; + } + } + } + catch (EndOfStreamException) + { + if (DateTime.Now >= m_NextStaticWarning) + { + Console.WriteLine("Warning: Static EOS for {0} ({1}, {2})", m_Owner, x, y); + m_NextStaticWarning = DateTime.Now + TimeSpan.FromMinutes(1.0); + } + + return m_EmptyStaticBlock; + } + } + + private DateTime m_NextStaticWarning; + private DateTime m_NextLandWarning; + + public void Force() + { + if (ScriptCompiler.Assemblies == null || ScriptCompiler.Assemblies.Length == 0) + throw new Exception(); + } + + private unsafe LandTile[] ReadLandBlock(int x, int y) + { + try + { + int offset = ((x * m_BlockHeight) + y) * 196 + 4; + + if (m_MapIndex != null) + offset = m_MapIndex.Lookup(offset); + + m_Map.Seek(offset, SeekOrigin.Begin); + + LandTile[] tiles = new LandTile[64]; + + fixed (LandTile* pTiles = tiles) + { +#if !MONO + NativeReader.Read(m_Map.SafeFileHandle.DangerousGetHandle(), pTiles, 192); +#else + NativeReader.Read( m_Map.Handle, pTiles, 192 ); +#endif + } + + return tiles; + } + catch + { + if (DateTime.Now >= m_NextLandWarning) + { + Console.WriteLine("Warning: Land EOS for {0} ({1}, {2})", m_Owner, x, y); + m_NextLandWarning = DateTime.Now + TimeSpan.FromMinutes(1.0); + } + + return m_InvalidLandBlock; + } + } + + public void Dispose() + { + if (m_MapIndex != null) + m_MapIndex.Close(); + else if (m_Map != null) + m_Map.Close(); + + if (m_Statics != null) + m_Statics.Close(); + + if (m_IndexReader != null) + m_IndexReader.Close(); + } + } + + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)] + public struct LandTile + { + internal short m_ID; + internal sbyte m_Z; + + public int ID + { + get { return m_ID; } + } + + public int Z + { + get { return m_Z; } + set { m_Z = (sbyte)value; } + } + + public int Height + { + get { return 0; } + + } + + public bool Ignored + { + get { return (m_ID == 2 || m_ID == 0x1DB || (m_ID >= 0x1AE && m_ID <= 0x1B5)); } + } + + public LandTile(short id, sbyte z) + { + m_ID = id; + m_Z = z; + } + + public void Set(short id, sbyte z) + { + m_ID = id; + m_Z = z; + } + } + + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)] + public struct StaticTile + { + internal ushort m_ID; + internal byte m_X; + internal byte m_Y; + internal sbyte m_Z; + internal short m_Hue; + + public int ID + { + get { return m_ID; } + } + + public int X + { + get { return m_X; } + set { m_X = (byte)value; } + } + + public int Y + { + get { return m_Y; } + set { m_Y = (byte)value; } + } + + public int Z + { + get { return m_Z; } + set { m_Z = (sbyte)value; } + } + + public int Hue + { + get { return m_Hue; } + set { m_Hue = (short)value; } + } + + public int Height + { + get { return TileData.ItemTable[m_ID & TileData.MaxItemValue].Height; } + } + + public StaticTile(ushort id, sbyte z) + { + m_ID = id; + m_Z = z; + + m_X = 0; + m_Y = 0; + m_Hue = 0; + } + + public StaticTile(ushort id, byte x, byte y, sbyte z, short hue) + { + m_ID = id; + m_X = x; + m_Y = y; + m_Z = z; + m_Hue = hue; + } + + public void Set(ushort id, sbyte z) + { + m_ID = id; + m_Z = z; + } + + public void Set(ushort id, byte x, byte y, sbyte z, short hue) + { + m_ID = id; + m_X = x; + m_Y = y; + m_Z = z; + m_Hue = hue; + } + } + + public class UOPIndex + { + private class UOPEntry : IComparable + { + public int m_Offset; + public int m_Length; + public int m_Order; + + public UOPEntry(int offset, int length) + { + m_Offset = offset; + m_Length = length; + m_Order = 0; + } + + public int CompareTo(UOPEntry other) + { + return m_Order.CompareTo(other.m_Order); + } + } + + private class OffsetComparer : IComparer + { + public static readonly IComparer Instance = new OffsetComparer(); + + public OffsetComparer() + { + } + + public int Compare(UOPEntry x, UOPEntry y) + { + return x.m_Offset.CompareTo(y.m_Offset); + } + } + + private BinaryReader m_Reader; + private int m_Length; + private int m_Version; + private UOPEntry[] m_Entries; + + public int Version + { + get { return m_Version; } + } + + public UOPIndex(FileStream stream) + { + m_Reader = new BinaryReader(stream); + m_Length = (int)stream.Length; + + if (m_Reader.ReadInt32() != 0x50594D) + throw new ArgumentException("Invalid UOP file."); + + m_Version = m_Reader.ReadInt32(); + m_Reader.ReadInt32(); + int nextTable = m_Reader.ReadInt32(); + + List entries = new List(); + + do + { + stream.Seek(nextTable, SeekOrigin.Begin); + int count = m_Reader.ReadInt32(); + nextTable = m_Reader.ReadInt32(); + m_Reader.ReadInt32(); + + for (int i = 0; i < count; ++i) + { + int offset = m_Reader.ReadInt32(); + + if (offset == 0) + { + stream.Seek(30, SeekOrigin.Current); + continue; + } + + m_Reader.ReadInt64(); + int length = m_Reader.ReadInt32(); + + entries.Add(new UOPEntry(offset, length)); + + stream.Seek(18, SeekOrigin.Current); + } + } + while (nextTable != 0 && nextTable < m_Length); + + entries.Sort(OffsetComparer.Instance); + + for (int i = 0; i < entries.Count; ++i) + { + stream.Seek(entries[i].m_Offset + 2, SeekOrigin.Begin); + + int dataOffset = m_Reader.ReadInt16(); + entries[i].m_Offset += 4 + dataOffset; + + stream.Seek(dataOffset, SeekOrigin.Current); + entries[i].m_Order = m_Reader.ReadInt32(); + } + + entries.Sort(); + m_Entries = entries.ToArray(); + } + + public int Lookup(int offset) + { + int total = 0; + + for (int i = 0; i < m_Entries.Length; ++i) + { + int newTotal = total + m_Entries[i].m_Length; + + if (offset < newTotal) + return m_Entries[i].m_Offset + (offset - total); + + total = newTotal; + } + + return m_Length; + } + + public void Close() + { + m_Reader.Close(); + } + } +} \ No newline at end of file diff --git a/Server/TileMatrixPatch.cs b/Server/TileMatrixPatch.cs new file mode 100644 index 0000000..8e04bc9 --- /dev/null +++ b/Server/TileMatrixPatch.cs @@ -0,0 +1,207 @@ +/*************************************************************************** + * TileMatrixPatch.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: TileMatrixPatch.cs 621 2010-12-13 03:37:33Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace Server +{ + public class TileMatrixPatch + { + private int m_LandBlocks, m_StaticBlocks; + + private static bool m_Enabled = true; + + public static bool Enabled + { + get + { + return m_Enabled; + } + set + { + m_Enabled = value; + } + } + + public int LandBlocks + { + get + { + return m_LandBlocks; + } + } + + public int StaticBlocks + { + get + { + return m_StaticBlocks; + } + } + + public TileMatrixPatch( TileMatrix matrix, int index ) + { + if ( !m_Enabled ) + return; + + string mapDataPath = Core.FindDataFile( "mapdif{0}.mul", index ); + string mapIndexPath = Core.FindDataFile( "mapdifl{0}.mul", index ); + + if ( File.Exists( mapDataPath ) && File.Exists( mapIndexPath ) ) + m_LandBlocks = PatchLand( matrix, mapDataPath, mapIndexPath ); + + string staDataPath = Core.FindDataFile( "stadif{0}.mul", index ); + string staIndexPath = Core.FindDataFile( "stadifl{0}.mul", index ); + string staLookupPath = Core.FindDataFile( "stadifi{0}.mul", index ); + + if ( File.Exists( staDataPath ) && File.Exists( staIndexPath ) && File.Exists( staLookupPath ) ) + m_StaticBlocks = PatchStatics( matrix, staDataPath, staIndexPath, staLookupPath ); + } + + private unsafe int PatchLand( TileMatrix matrix, string dataPath, string indexPath ) + { + using ( FileStream fsData = new FileStream( dataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + using ( FileStream fsIndex = new FileStream( indexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + BinaryReader indexReader = new BinaryReader( fsIndex ); + + int count = (int)(indexReader.BaseStream.Length / 4); + + for ( int i = 0; i < count; ++i ) + { + int blockID = indexReader.ReadInt32(); + int x = blockID / matrix.BlockHeight; + int y = blockID % matrix.BlockHeight; + + fsData.Seek( 4, SeekOrigin.Current ); + + LandTile[] tiles = new LandTile[64]; + + fixed ( LandTile *pTiles = tiles ) + { +#if !MONO + NativeReader.Read( fsData.SafeFileHandle.DangerousGetHandle(), pTiles, 192 ); +#else + NativeReader.Read( fsData.Handle, pTiles, 192 ); +#endif + } + + matrix.SetLandBlock( x, y, tiles ); + } + + indexReader.Close(); + + return count; + } + } + } + + private static StaticTile[] m_TileBuffer = new StaticTile[128]; + + private unsafe int PatchStatics( TileMatrix matrix, string dataPath, string indexPath, string lookupPath ) + { + using ( FileStream fsData = new FileStream( dataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + using ( FileStream fsIndex = new FileStream( indexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + using ( FileStream fsLookup = new FileStream( lookupPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) + { + BinaryReader indexReader = new BinaryReader( fsIndex ); + BinaryReader lookupReader = new BinaryReader( fsLookup ); + + int count = (int)(indexReader.BaseStream.Length / 4); + + TileList[][] lists = new TileList[8][]; + + for ( int x = 0; x < 8; ++x ) + { + lists[x] = new TileList[8]; + + for ( int y = 0; y < 8; ++y ) + lists[x][y] = new TileList(); + } + + for ( int i = 0; i < count; ++i ) + { + int blockID = indexReader.ReadInt32(); + int blockX = blockID / matrix.BlockHeight; + int blockY = blockID % matrix.BlockHeight; + + int offset = lookupReader.ReadInt32(); + int length = lookupReader.ReadInt32(); + lookupReader.ReadInt32(); // Extra + + if ( offset < 0 || length <= 0 ) + { + matrix.SetStaticBlock( blockX, blockY, matrix.EmptyStaticBlock ); + continue; + } + + fsData.Seek( offset, SeekOrigin.Begin ); + + int tileCount = length / 7; + + if ( m_TileBuffer.Length < tileCount ) + m_TileBuffer = new StaticTile[tileCount]; + + StaticTile[] staTiles = m_TileBuffer; + + fixed ( StaticTile *pTiles = staTiles ) + { +#if !MONO + NativeReader.Read( fsData.SafeFileHandle.DangerousGetHandle(), pTiles, length ); +#else + NativeReader.Read( fsData.Handle, pTiles, length ); +#endif + StaticTile *pCur = pTiles, pEnd = pTiles + tileCount; + + while ( pCur < pEnd ) + { + lists[pCur->m_X & 0x7][pCur->m_Y & 0x7].Add( (ushort)pCur->m_ID, pCur->m_Z ); + pCur = pCur + 1; + } + + StaticTile[][][] tiles = new StaticTile[8][][]; + + for ( int x = 0; x < 8; ++x ) + { + tiles[x] = new StaticTile[8][]; + + for ( int y = 0; y < 8; ++y ) + tiles[x][y] = lists[x][y].ToArray(); + } + + matrix.SetStaticBlock( blockX, blockY, tiles ); + } + } + + indexReader.Close(); + lookupReader.Close(); + + return count; + } + } + } + } + } +} \ No newline at end of file diff --git a/Server/Timer.cs b/Server/Timer.cs new file mode 100644 index 0000000..ac2884b --- /dev/null +++ b/Server/Timer.cs @@ -0,0 +1,679 @@ +/*************************************************************************** + * Timer.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Timer.cs 816 2012-01-04 08:45:24Z asayre $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading; +using Server.Diagnostics; + +namespace Server +{ + public enum TimerPriority + { + EveryTick, + TenMS, + TwentyFiveMS, + FiftyMS, + TwoFiftyMS, + OneSecond, + FiveSeconds, + OneMinute + } + + public delegate void TimerCallback(); + public delegate void TimerStateCallback( object state ); + public delegate void TimerStateCallback( T state ); + + public class Timer + { + private DateTime m_Next; + private TimeSpan m_Delay; + private TimeSpan m_Interval; + private bool m_Running; + private int m_Index, m_Count; + private TimerPriority m_Priority; + private List m_List; + private bool m_PrioritySet; + + private static string FormatDelegate( Delegate callback ) + { + if ( callback == null ) + return "null"; + + return String.Format( "{0}.{1}", callback.Method.DeclaringType.FullName, callback.Method.Name ); + } + + public static void DumpInfo( TextWriter tw ) + { + TimerThread.DumpInfo( tw ); + } + + public TimerPriority Priority + { + get + { + return m_Priority; + } + set + { + if ( !m_PrioritySet ) + m_PrioritySet = true; + + if ( m_Priority != value ) + { + m_Priority = value; + + if ( m_Running ) + TimerThread.PriorityChange( this, (int)m_Priority ); + } + } + } + + public DateTime Next + { + get { return m_Next; } + } + + public TimeSpan Delay + { + get { return m_Delay; } + set { m_Delay = value; } + } + + public TimeSpan Interval + { + get { return m_Interval; } + set { m_Interval = value; } + } + + public bool Running + { + get { return m_Running; } + set { + if ( value ) { + Start(); + } else { + Stop(); + } + } + } + + public TimerProfile GetProfile() + { + if ( !Core.Profiling ) { + return null; + } + + string name = ToString(); + + if ( name == null ) { + name = "null"; + } + + return TimerProfile.Acquire( name ); + } + + public class TimerThread + { + private static Queue m_ChangeQueue = Queue.Synchronized( new Queue() ); + + private static DateTime[] m_NextPriorities = new DateTime[8]; + private static TimeSpan[] m_PriorityDelays = new TimeSpan[8] + { + TimeSpan.Zero, + TimeSpan.FromMilliseconds( 10.0 ), + TimeSpan.FromMilliseconds( 25.0 ), + TimeSpan.FromMilliseconds( 50.0 ), + TimeSpan.FromMilliseconds( 250.0 ), + TimeSpan.FromSeconds( 1.0 ), + TimeSpan.FromSeconds( 5.0 ), + TimeSpan.FromMinutes( 1.0 ) + }; + + private static List[] m_Timers = new List[8] + { + new List(), + new List(), + new List(), + new List(), + new List(), + new List(), + new List(), + new List(), + }; + + public static void DumpInfo( TextWriter tw ) + { + for ( int i = 0; i < 8; ++i ) + { + tw.WriteLine( "Priority: {0}", (TimerPriority)i ); + tw.WriteLine(); + + Dictionary> hash = new Dictionary>(); + + for ( int j = 0; j < m_Timers[i].Count; ++j ) + { + Timer t = m_Timers[i][j]; + + string key = t.ToString(); + + List list; + hash.TryGetValue( key, out list ); + + if ( list == null ) + hash[key] = list = new List(); + + list.Add( t ); + } + + foreach ( KeyValuePair> kv in hash ) + { + string key = kv.Key; + List list = kv.Value; + + tw.WriteLine( "Type: {0}; Count: {1}; Percent: {2}%", key, list.Count, (int)(100 * (list.Count / (double)m_Timers[i].Count)) ); + } + + tw.WriteLine(); + tw.WriteLine(); + } + } + + private class TimerChangeEntry + { + public Timer m_Timer; + public int m_NewIndex; + public bool m_IsAdd; + + private TimerChangeEntry( Timer t, int newIndex, bool isAdd ) + { + m_Timer = t; + m_NewIndex = newIndex; + m_IsAdd = isAdd; + } + + public void Free() + { + //m_InstancePool.Enqueue( this ); + } + + private static Queue m_InstancePool = new Queue(); + + public static TimerChangeEntry GetInstance( Timer t, int newIndex, bool isAdd ) + { + TimerChangeEntry e; + + if ( m_InstancePool.Count > 0 ) + { + e = m_InstancePool.Dequeue(); + + if ( e == null ) + e = new TimerChangeEntry( t, newIndex, isAdd ); + else + { + e.m_Timer = t; + e.m_NewIndex = newIndex; + e.m_IsAdd = isAdd; + } + } + else + { + e = new TimerChangeEntry( t, newIndex, isAdd ); + } + + return e; + } + } + + public TimerThread() + { + } + + public static void Change( Timer t, int newIndex, bool isAdd ) + { + m_ChangeQueue.Enqueue( TimerChangeEntry.GetInstance( t, newIndex, isAdd ) ); + m_Signal.Set(); + } + + public static void AddTimer( Timer t ) + { + Change( t, (int)t.Priority, true ); + } + + public static void PriorityChange( Timer t, int newPrio ) + { + Change( t, newPrio, false ); + } + + public static void RemoveTimer( Timer t ) + { + Change( t, -1, false ); + } + + private static void ProcessChangeQueue() + { + while ( m_ChangeQueue.Count > 0 ) + { + TimerChangeEntry tce = (TimerChangeEntry)m_ChangeQueue.Dequeue(); + Timer timer = tce.m_Timer; + int newIndex = tce.m_NewIndex; + + if ( timer.m_List != null ) + timer.m_List.Remove( timer ); + + if ( tce.m_IsAdd ) + { + timer.m_Next = DateTime.Now + timer.m_Delay; + timer.m_Index = 0; + } + + if ( newIndex >= 0 ) + { + timer.m_List = m_Timers[newIndex]; + timer.m_List.Add( timer ); + } + else + { + timer.m_List = null; + } + + tce.Free(); + } + } + + private static AutoResetEvent m_Signal = new AutoResetEvent( false ); + public static void Set() { m_Signal.Set(); } + + public void TimerMain() + { + DateTime now; + int i, j; + bool loaded; + + while ( !Core.Closing ) + { + ProcessChangeQueue(); + + loaded = false; + + for ( i = 0; i < m_Timers.Length; i++) + { + now = DateTime.Now; + if ( now < m_NextPriorities[i] ) + break; + + m_NextPriorities[i] = now + m_PriorityDelays[i]; + + for ( j = 0; j < m_Timers[i].Count; j++) + { + Timer t = m_Timers[i][j]; + + if ( !t.m_Queued && now > t.m_Next ) + { + t.m_Queued = true; + + lock ( m_Queue ) + m_Queue.Enqueue( t ); + + loaded = true; + + if ( t.m_Count != 0 && (++t.m_Index >= t.m_Count) ) + { + t.Stop(); + } + else + { + t.m_Next = now + t.m_Interval; + } + } + } + } + + if ( loaded ) + Core.Set(); + + m_Signal.WaitOne( 10, false ); + } + } + } + + private static Queue m_Queue = new Queue(); + private static int m_BreakCount = 20000; + + public static int BreakCount{ get{ return m_BreakCount; } set{ m_BreakCount = value; } } + + private static int m_QueueCountAtSlice; + + private bool m_Queued; + + public static void Slice() + { + lock ( m_Queue ) + { + m_QueueCountAtSlice = m_Queue.Count; + + int index = 0; + + while ( index < m_BreakCount && m_Queue.Count != 0 ) + { + Timer t = m_Queue.Dequeue(); + TimerProfile prof = t.GetProfile(); + + if ( prof != null ) { + prof.Start(); + } + + t.OnTick(); + t.m_Queued = false; + ++index; + + if ( prof != null ) { + prof.Finish(); + } + } + } + } + + public Timer( TimeSpan delay ) : this( delay, TimeSpan.Zero, 1 ) + { + } + + public Timer( TimeSpan delay, TimeSpan interval ) : this( delay, interval, 0 ) + { + } + + public virtual bool DefRegCreation + { + get{ return true; } + } + + public virtual void RegCreation() + { + TimerProfile prof = GetProfile(); + + if ( prof != null ) { + prof.Created++; + } + } + + public Timer( TimeSpan delay, TimeSpan interval, int count ) + { + m_Delay = delay; + m_Interval = interval; + m_Count = count; + + if ( !m_PrioritySet ) { + if ( count == 1 ) { + m_Priority = ComputePriority( delay ); + } else { + m_Priority = ComputePriority( interval ); + } + m_PrioritySet = true; + } + + if ( DefRegCreation ) + RegCreation(); + } + + public override string ToString() + { + return GetType().FullName; + } + + public static TimerPriority ComputePriority( TimeSpan ts ) + { + if ( ts >= TimeSpan.FromMinutes( 1.0 ) ) + return TimerPriority.FiveSeconds; + + if ( ts >= TimeSpan.FromSeconds( 10.0 ) ) + return TimerPriority.OneSecond; + + if ( ts >= TimeSpan.FromSeconds( 5.0 ) ) + return TimerPriority.TwoFiftyMS; + + if ( ts >= TimeSpan.FromSeconds( 2.5 ) ) + return TimerPriority.FiftyMS; + + if ( ts >= TimeSpan.FromSeconds( 1.0 ) ) + return TimerPriority.TwentyFiveMS; + + if ( ts >= TimeSpan.FromSeconds( 0.5 ) ) + return TimerPriority.TenMS; + + return TimerPriority.EveryTick; + } + + #region DelayCall(..) + + public static Timer DelayCall(TimerCallback callback) + { + return DelayCall(TimeSpan.Zero, TimeSpan.Zero, 1, callback); + } + + public static Timer DelayCall(TimeSpan delay, TimerCallback callback) + { + return DelayCall(delay, TimeSpan.Zero, 1, callback); + } + + public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerCallback callback) + { + return DelayCall(delay, interval, 0, callback); + } + + public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, TimerCallback callback) + { + Timer t = new DelayCallTimer(delay, interval, count, callback); + + if (count == 1) + t.Priority = ComputePriority(delay); + else + t.Priority = ComputePriority(interval); + + t.Start(); + + return t; + } + + public static Timer DelayCall(TimerStateCallback callback, object state) + { + return DelayCall(TimeSpan.Zero, TimeSpan.Zero, 1, callback, state); + } + + public static Timer DelayCall(TimeSpan delay, TimerStateCallback callback, object state) + { + return DelayCall(delay, TimeSpan.Zero, 1, callback, state); + } + + public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerStateCallback callback, object state) + { + return DelayCall(delay, interval, 0, callback, state); + } + + public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, object state) + { + Timer t = new DelayStateCallTimer(delay, interval, count, callback, state); + + if (count == 1) + t.Priority = ComputePriority(delay); + else + t.Priority = ComputePriority(interval); + + t.Start(); + + return t; + } + #endregion + + #region DelayCall(..) + public static Timer DelayCall(TimerStateCallback callback, T state) + { + return DelayCall(TimeSpan.Zero, TimeSpan.Zero, 1, callback, state); + } + + public static Timer DelayCall(TimeSpan delay, TimerStateCallback callback, T state) + { + return DelayCall(delay, TimeSpan.Zero, 1, callback, state); + } + + public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerStateCallback callback, T state) + { + return DelayCall(delay, interval, 0, callback, state); + } + + public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, T state) + { + Timer t = new DelayStateCallTimer(delay, interval, count, callback, state); + + if (count == 1) + t.Priority = ComputePriority(delay); + else + t.Priority = ComputePriority(interval); + + t.Start(); + + return t; + } + #endregion + + #region DelayCall Timers + private class DelayCallTimer : Timer + { + private TimerCallback m_Callback; + + public TimerCallback Callback{ get{ return m_Callback; } } + + public override bool DefRegCreation{ get{ return false; } } + + public DelayCallTimer( TimeSpan delay, TimeSpan interval, int count, TimerCallback callback ) : base( delay, interval, count ) + { + m_Callback = callback; + RegCreation(); + } + + protected override void OnTick() + { + if ( m_Callback != null ) + m_Callback(); + } + + public override string ToString() + { + return String.Format( "DelayCallTimer[{0}]", FormatDelegate( m_Callback ) ); + } + } + + private class DelayStateCallTimer : Timer + { + private TimerStateCallback m_Callback; + private object m_State; + + public TimerStateCallback Callback{ get{ return m_Callback; } } + + public override bool DefRegCreation{ get{ return false; } } + + public DelayStateCallTimer( TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, object state ) : base( delay, interval, count ) + { + m_Callback = callback; + m_State = state; + + RegCreation(); + } + + protected override void OnTick() + { + if ( m_Callback != null ) + m_Callback( m_State ); + } + + public override string ToString() + { + return String.Format( "DelayStateCall[{0}]", FormatDelegate( m_Callback ) ); + } + } + + private class DelayStateCallTimer : Timer + { + private TimerStateCallback m_Callback; + private T m_State; + + public TimerStateCallback Callback { get { return m_Callback; } } + + public override bool DefRegCreation { get { return false; } } + + public DelayStateCallTimer( TimeSpan delay, TimeSpan interval, int count, TimerStateCallback callback, T state ) + : base( delay, interval, count ) + { + m_Callback = callback; + m_State = state; + + RegCreation(); + } + + protected override void OnTick() + { + if( m_Callback != null ) + m_Callback( m_State ); + } + + public override string ToString() + { + return String.Format( "DelayStateCall[{0}]", FormatDelegate( m_Callback ) ); + } + } + #endregion + + public void Start() + { + if ( !m_Running ) + { + m_Running = true; + TimerThread.AddTimer( this ); + + TimerProfile prof = GetProfile(); + + if ( prof != null ) { + prof.Started++; + } + } + } + + public void Stop() + { + if ( m_Running ) + { + m_Running = false; + TimerThread.RemoveTimer( this ); + + TimerProfile prof = GetProfile(); + + if ( prof != null ) { + prof.Stopped++; + } + } + } + + protected virtual void OnTick() + { + } + } +} \ No newline at end of file diff --git a/Server/Utility.cs b/Server/Utility.cs new file mode 100644 index 0000000..7061025 --- /dev/null +++ b/Server/Utility.cs @@ -0,0 +1,1353 @@ +/*************************************************************************** + * Utility.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: Utility.cs 1003 2013-02-03 01:05:17Z eos $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Text; +using System.Xml; +using Microsoft.Win32; +using Server.Network; + +namespace Server +{ + public static class Utility + { + private static Random m_Random = new Random(); + private static Encoding m_UTF8, m_UTF8WithEncoding; + + public static Encoding UTF8 + { + get + { + if ( m_UTF8 == null ) + m_UTF8 = new UTF8Encoding( false, false ); + + return m_UTF8; + } + } + + public static Encoding UTF8WithEncoding + { + get + { + if ( m_UTF8WithEncoding == null ) + m_UTF8WithEncoding = new UTF8Encoding( true, false ); + + return m_UTF8WithEncoding; + } + } + + public static void Separate( StringBuilder sb, string value, string separator ) + { + if ( sb.Length > 0 ) + sb.Append( separator ); + + sb.Append( value ); + } + + public static string Intern( string str ) + { + if ( str == null ) + return null; + else if ( str.Length == 0 ) + return String.Empty; + + return String.Intern( str ); + } + + public static void Intern( ref string str ) + { + str = Intern( str ); + } + + private static Dictionary _ipAddressTable; + + public static IPAddress Intern( IPAddress ipAddress ) { + if ( _ipAddressTable == null ) { + _ipAddressTable = new Dictionary(); + } + + IPAddress interned; + + if ( !_ipAddressTable.TryGetValue( ipAddress, out interned ) ) { + interned = ipAddress; + _ipAddressTable[ipAddress] = interned; + } + + return interned; + } + + public static void Intern( ref IPAddress ipAddress ) { + ipAddress = Intern( ipAddress ); + } + + public static bool IsValidIP( string text ) + { + bool valid = true; + + IPMatch( text, IPAddress.None, ref valid ); + + return valid; + } + + public static bool IPMatch( string val, IPAddress ip ) + { + bool valid = true; + + return IPMatch( val, ip, ref valid ); + } + + public static string FixHtml( string str ) + { + if( str == null ) + return ""; + + bool hasOpen = ( str.IndexOf( '<' ) >= 0 ); + bool hasClose = ( str.IndexOf( '>' ) >= 0 ); + bool hasPound = ( str.IndexOf( '#' ) >= 0 ); + + if ( !hasOpen && !hasClose && !hasPound ) + return str; + + StringBuilder sb = new StringBuilder( str ); + + if ( hasOpen ) + sb.Replace( '<', '(' ); + + if ( hasClose ) + sb.Replace( '>', ')' ); + + if ( hasPound ) + sb.Replace( '#', '-' ); + + return sb.ToString(); + } + + public static bool IPMatchCIDR( string cidr, IPAddress ip ) + { + if ( ip == null || ip.AddressFamily == AddressFamily.InterNetworkV6 ) + return false; //Just worry about IPv4 for now + + + /* + string[] str = cidr.Split( '/' ); + + if ( str.Length != 2 ) + return false; + + /* ************************************************** + IPAddress cidrPrefix; + + if ( !IPAddress.TryParse( str[0], out cidrPrefix ) ) + return false; + * */ + + /* + string[] dotSplit = str[0].Split( '.' ); + + if ( dotSplit.Length != 4 ) //At this point and time, and for speed sake, we'll only worry about IPv4 + return false; + + byte[] bytes = new byte[4]; + + for ( int i = 0; i < 4; i++ ) + { + byte.TryParse( dotSplit[i], out bytes[i] ); + } + + uint cidrPrefix = OrderedAddressValue( bytes ); + + int cidrLength = Utility.ToInt32( str[1] ); + //The below solution is the fastest solution of the three + + */ + + byte[] bytes = new byte[4]; + string[] split = cidr.Split( '.' ); + bool cidrBits = false; + int cidrLength = 0; + + for ( int i = 0; i < 4; i++ ) + { + int part = 0; + + int partBase = 10; + + string pattern = split[i]; + + for ( int j = 0; j < pattern.Length; j++ ) + { + char c = (char)pattern[j]; + + + if ( c == 'x' || c == 'X' ) + { + partBase = 16; + } + else if ( c >= '0' && c <= '9' ) + { + int offset = c - '0'; + + if ( cidrBits ) + { + cidrLength *= partBase; + cidrLength += offset; + } + else + { + part *= partBase; + part += offset; + } + } + else if ( c >= 'a' && c <= 'f' ) + { + int offset = 10 + ( c - 'a' ); + + if ( cidrBits ) + { + cidrLength *= partBase; + cidrLength += offset; + } + else + { + part *= partBase; + part += offset; + } + } + else if ( c >= 'A' && c <= 'F' ) + { + int offset = 10 + ( c - 'A' ); + + if ( cidrBits ) + { + cidrLength *= partBase; + cidrLength += offset; + } + else + { + part *= partBase; + part += offset; + } + } + else if ( c == '/' ) + { + if ( cidrBits || i != 3 ) //If there's two '/' or the '/' isn't in the last byte + { + return false; + } + + partBase = 10; + cidrBits = true; + } + else + { + return false; + } + } + + bytes[i] = (byte)part; + } + + uint cidrPrefix = OrderedAddressValue( bytes ); + + return IPMatchCIDR( cidrPrefix, ip, cidrLength ); + } + + public static bool IPMatchCIDR( IPAddress cidrPrefix, IPAddress ip, int cidrLength ) + { + if ( cidrPrefix == null || ip == null || cidrPrefix.AddressFamily == AddressFamily.InterNetworkV6 ) //Ignore IPv6 for now + return false; + + uint cidrValue = SwapUnsignedInt( (uint)GetLongAddressValue( cidrPrefix ) ); + uint ipValue = SwapUnsignedInt( (uint)GetLongAddressValue( ip ) ); + + return IPMatchCIDR( cidrValue, ipValue, cidrLength ); + } + + public static bool IPMatchCIDR( uint cidrPrefixValue, IPAddress ip, int cidrLength ) + { + if ( ip == null || ip.AddressFamily == AddressFamily.InterNetworkV6) + return false; + + uint ipValue = SwapUnsignedInt( (uint)GetLongAddressValue( ip ) ); + + return IPMatchCIDR( cidrPrefixValue, ipValue, cidrLength ); + } + + public static bool IPMatchCIDR( uint cidrPrefixValue, uint ipValue, int cidrLength ) + { + if ( cidrLength <= 0 || cidrLength >= 32 ) //if invalid cidr Length, just compare IPs + return cidrPrefixValue == ipValue; + + uint mask = uint.MaxValue << 32-cidrLength; + + return ( ( cidrPrefixValue & mask ) == ( ipValue & mask ) ); + } + + private static uint OrderedAddressValue( byte[] bytes ) + { + if ( bytes.Length != 4 ) + return 0; + + return (uint)(((( bytes[0] << 0x18 ) | (bytes[1] << 0x10)) | (bytes[2] << 8)) | bytes[3]) & ((uint)0xffffffff); + } + + private static uint SwapUnsignedInt( uint source ) + { + return (uint)( ( ( ( source & 0x000000FF ) << 0x18 ) + | ( ( source & 0x0000FF00 ) << 8 ) + | ( ( source & 0x00FF0000 ) >> 8 ) + | ( ( source & 0xFF000000 ) >> 0x18 ) ) ); + } + + public static bool TryConvertIPv6toIPv4( ref IPAddress address ) + { + if ( !Socket.OSSupportsIPv6 || address.AddressFamily == AddressFamily.InterNetwork ) + return true; + + byte[] addr = address.GetAddressBytes(); + if ( addr.Length == 16 ) //sanity 0 - 15 //10 11 //12 13 14 15 + { + if ( addr[10] != 0xFF || addr[11] != 0xFF ) + return false; + + for ( int i = 0; i < 10; i++ ) + { + if ( addr[i] != 0 ) + return false; + } + + byte[] v4Addr = new byte[4]; + + for ( int i = 0; i < 4; i++ ) + { + v4Addr[i] = addr[12 + i]; + } + + address = new IPAddress( v4Addr ); + return true; + } + + return false; + } + + public static bool IPMatch( string val, IPAddress ip, ref bool valid ) + { + valid = true; + + string[] split = val.Split( '.' ); + + for ( int i = 0; i < 4; ++i ) + { + int lowPart, highPart; + + if ( i >= split.Length ) + { + lowPart = 0; + highPart = 255; + } + else + { + string pattern = split[i]; + + if ( pattern == "*" ) + { + lowPart = 0; + highPart = 255; + } + else + { + lowPart = 0; + highPart = 0; + + bool highOnly = false; + int lowBase = 10; + int highBase = 10; + + for ( int j = 0; j < pattern.Length; ++j ) + { + char c = (char)pattern[j]; + + if ( c == '?' ) + { + if ( !highOnly ) + { + lowPart *= lowBase; + lowPart += 0; + } + + highPart *= highBase; + highPart += highBase - 1; + } + else if ( c == '-' ) + { + highOnly = true; + highPart = 0; + } + else if ( c == 'x' || c == 'X' ) + { + lowBase = 16; + highBase = 16; + } + else if ( c >= '0' && c <= '9' ) + { + int offset = c - '0'; + + if ( !highOnly ) + { + lowPart *= lowBase; + lowPart += offset; + } + + highPart *= highBase; + highPart += offset; + } + else if ( c >= 'a' && c <= 'f' ) + { + int offset = 10 + (c - 'a'); + + if ( !highOnly ) + { + lowPart *= lowBase; + lowPart += offset; + } + + highPart *= highBase; + highPart += offset; + } + else if ( c >= 'A' && c <= 'F' ) + { + int offset = 10 + (c - 'A'); + + if ( !highOnly ) + { + lowPart *= lowBase; + lowPart += offset; + } + + highPart *= highBase; + highPart += offset; + } + else + { + valid = false; //high & lowpart would be 0 if it got to here. + } + } + } + } + + int b = (byte)(Utility.GetAddressValue( ip ) >> (i * 8)); + + if ( b < lowPart || b > highPart ) + return false; + } + + return true; + } + + public static bool IPMatchClassC( IPAddress ip1, IPAddress ip2 ) + { + return ( (Utility.GetAddressValue( ip1 ) & 0xFFFFFF) == (Utility.GetAddressValue( ip2 ) & 0xFFFFFF) ); + } + + public static int InsensitiveCompare( string first, string second ) + { + return Insensitive.Compare( first, second ); + } + + public static bool InsensitiveStartsWith( string first, string second ) + { + return Insensitive.StartsWith( first, second ); + } + + #region To[Something] + public static bool ToBoolean( string value ) + { + bool b; + bool.TryParse( value, out b ); + + return b; + } + + public static double ToDouble( string value ) + { + double d; + double.TryParse( value, out d ); + + return d; + } + + public static TimeSpan ToTimeSpan( string value ) + { + TimeSpan t; + TimeSpan.TryParse( value, out t ); + + return t; + } + + public static int ToInt32( string value ) + { + int i; + + if( value.StartsWith( "0x" ) ) + int.TryParse( value.Substring( 2 ), NumberStyles.HexNumber, null, out i ); + else + int.TryParse( value, out i ); + + return i; + } + #endregion + + #region Get[Something] + public static int GetXMLInt32( string intString, int defaultValue ) + { + try + { + return XmlConvert.ToInt32( intString ); + } + catch + { + int val; + if ( int.TryParse( intString, out val ) ) + return val; + + return defaultValue; + } + } + + public static DateTime GetXMLDateTime( string dateTimeString, DateTime defaultValue ) + { + try + { + return XmlConvert.ToDateTime( dateTimeString, XmlDateTimeSerializationMode.Local ); + } + catch + { + DateTime d; + + if( DateTime.TryParse( dateTimeString, out d ) ) + return d; + + return defaultValue; + } + } +#if Framework_4_0 + public static DateTimeOffset GetXMLDateTimeOffset( string dateTimeOffsetString, DateTimeOffset defaultValue ) + { + try + { + return XmlConvert.ToDateTimeOffset( dateTimeOffsetString ); + } + catch + { + DateTimeOffset d; + + if( DateTimeOffset.TryParse( dateTimeOffsetString, out d ) ) + return d; + + return defaultValue; + } + } +#endif + public static TimeSpan GetXMLTimeSpan( string timeSpanString, TimeSpan defaultValue ) + { + try + { + return XmlConvert.ToTimeSpan( timeSpanString ); + } + catch + { + return defaultValue; + } + } + + public static string GetAttribute( XmlElement node, string attributeName ) + { + return GetAttribute( node, attributeName, null ); + } + + public static string GetAttribute( XmlElement node, string attributeName, string defaultValue ) + { + if ( node == null ) + return defaultValue; + + XmlAttribute attr = node.Attributes[attributeName]; + + if ( attr == null ) + return defaultValue; + + return attr.Value; + } + + public static string GetText( XmlElement node, string defaultValue ) + { + if ( node == null ) + return defaultValue; + + return node.InnerText; + } + + public static int GetAddressValue( IPAddress address ) + { +#pragma warning disable 618 + return (int)address.Address; +#pragma warning restore 618 + } + + public static long GetLongAddressValue( IPAddress address ) + { +#pragma warning disable 618 + return address.Address; +#pragma warning restore 618 + } + #endregion + + public static double RandomDouble() + { + return m_Random.NextDouble(); + } + #region In[...]Range + public static bool InRange( Point3D p1, Point3D p2, int range ) + { + return ( p1.m_X >= (p2.m_X - range) ) + && ( p1.m_X <= (p2.m_X + range) ) + && ( p1.m_Y >= (p2.m_Y - range) ) + && ( p1.m_Y <= (p2.m_Y + range) ); + } + + public static bool InUpdateRange( Point3D p1, Point3D p2 ) + { + return ( p1.m_X >= (p2.m_X - 18) ) + && ( p1.m_X <= (p2.m_X + 18) ) + && ( p1.m_Y >= (p2.m_Y - 18) ) + && ( p1.m_Y <= (p2.m_Y + 18) ); + } + + public static bool InUpdateRange( Point2D p1, Point2D p2 ) + { + return ( p1.m_X >= (p2.m_X - 18) ) + && ( p1.m_X <= (p2.m_X + 18) ) + && ( p1.m_Y >= (p2.m_Y - 18) ) + && ( p1.m_Y <= (p2.m_Y + 18) ); + } + + public static bool InUpdateRange( IPoint2D p1, IPoint2D p2 ) + { + return ( p1.X >= (p2.X - 18) ) + && ( p1.X <= (p2.X + 18) ) + && ( p1.Y >= (p2.Y - 18) ) + && ( p1.Y <= (p2.Y + 18) ); + } + + #endregion + public static Direction GetDirection( IPoint2D from, IPoint2D to ) + { + int dx = to.X - from.X; + int dy = to.Y - from.Y; + + int adx = Math.Abs( dx ); + int ady = Math.Abs( dy ); + + if ( adx >= ady * 3 ) + { + if ( dx > 0 ) + return Direction.East; + else + return Direction.West; + } + else if ( ady >= adx * 3 ) + { + if ( dy > 0 ) + return Direction.South; + else + return Direction.North; + } + else if ( dx > 0 ) + { + if ( dy > 0 ) + return Direction.Down; + else + return Direction.Right; + } + else + { + if ( dy > 0 ) + return Direction.Left; + else + return Direction.Up; + } + } + + /* Should probably be rewritten to use an ITile interface + + public static bool CanMobileFit( int z, StaticTile[] tiles ) + { + int checkHeight = 15; + int checkZ = z; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if ( ((checkZ + checkHeight) > tile.Z && checkZ < (tile.Z + tile.Height))*//* || (tile.Z < (checkZ + checkHeight) && (tile.Z + tile.Height) > checkZ)*//* ) + { + return false; + } + else if ( checkHeight == 0 && tile.Height == 0 && checkZ == tile.Z ) + { + return false; + } + } + + return true; + } + + public static bool IsInContact( StaticTile check, StaticTile[] tiles ) + { + int checkHeight = check.Height; + int checkZ = check.Z; + + for ( int i = 0; i < tiles.Length; ++i ) + { + StaticTile tile = tiles[i]; + + if ( ((checkZ + checkHeight) > tile.Z && checkZ < (tile.Z + tile.Height))*//* || (tile.Z < (checkZ + checkHeight) && (tile.Z + tile.Height) > checkZ)*//* ) + { + return true; + } + else if ( checkHeight == 0 && tile.Height == 0 && checkZ == tile.Z ) + { + return true; + } + } + + return false; + } + */ + + public static object GetArrayCap( Array array, int index ) + { + return GetArrayCap( array, index, null ); + } + + public static object GetArrayCap( Array array, int index, object emptyValue ) + { + if ( array.Length > 0 ) + { + if ( index < 0 ) + { + index = 0; + } + else if ( index >= array.Length ) + { + index = array.Length - 1; + } + + return array.GetValue( index ); + } + else + { + return emptyValue; + } + } + + //4d6+8 would be: Utility.Dice( 4, 6, 8 ) + public static int Dice( int numDice, int numSides, int bonus ) + { + int total = 0; + for (int i=0;i max ) + { + int copy = min; + min = max; + max = copy; + } + else if ( min == max ) + { + return min; + } + + return min + m_Random.Next( (max - min) + 1 ); + } + + public static int Random( int from, int count ) + { + if ( count == 0 ) + { + return from; + } + else if ( count > 0 ) + { + return from + m_Random.Next( count ); + } + else + { + return from - m_Random.Next( -count ); + } + } + + public static int Random( int count ) + { + return m_Random.Next( count ); + } + + public static void RandomBytes(byte[] buffer) + { + m_Random.NextBytes(buffer); + } + + #region Random Hues + + /// + /// Random pink, blue, green, orange, red or yellow hue + /// + /// + public static int RandomNondyedHue() + { + switch ( Random( 6 ) ) + { + case 0: return RandomPinkHue(); + case 1: return RandomBlueHue(); + case 2: return RandomGreenHue(); + case 3: return RandomOrangeHue(); + case 4: return RandomRedHue(); + case 5: return RandomYellowHue(); + } + + return 0; + } + + /// + /// Random hue in the range 1201-1254 + /// + public static int RandomPinkHue() + { + return Random(1201, 54); + } + + /// + /// Random hue in the range 1301-1354 + /// + public static int RandomBlueHue() + { + return Random(1301, 54); + } + + /// + /// Random hue in the range 1401-1454 + /// + public static int RandomGreenHue() + { + return Random(1401, 54); + } + + /// + /// Random hue in the range 1501-1554 + /// + public static int RandomOrangeHue() + { + return Random(1501, 54); + } + + /// + /// Random hue in the range 1601-1654 + /// + public static int RandomRedHue() + { + return Random(1601, 54); + } + + /// + /// Random hue in the range 1701-1754 + /// + public static int RandomYellowHue() + { + return Random(1701, 54); + } + + /// + /// Random hue in the range 1801-1908 + /// + public static int RandomNeutralHue() + { + return Random(1801, 108); + } + + /// + /// Random hue in the range 2001-2018 + /// + public static int RandomSnakeHue() + { + return Random(2001, 18); + } + + /// + /// Random hue in the range 2101-2130 + /// + public static int RandomBirdHue() + { + return Random(2101, 30); + } + + /// + /// Random hue in the range 2201-2224 + /// + public static int RandomSlimeHue() + { + return Random(2201, 24); + } + + /// + /// Random hue in the range 2301-2318 + /// + public static int RandomAnimalHue() + { + return Random(2301, 18); + } + + /// + /// Random hue in the range 2401-2430 + /// + public static int RandomMetalHue() + { + return Random( 2401, 30 ); + } + + public static int ClipDyedHue( int hue ) + { + if ( hue < 2 ) + return 2; + else if ( hue > 1001 ) + return 1001; + else + return hue; + } + + /// + /// Random hue in the range 2-1001 + /// + public static int RandomDyedHue() + { + return Random(2, 1000); + } + + /// + /// Random hue from 0x62, 0x71, 0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59 + /// + public static int RandomBrightHue() + { + if (Utility.RandomDouble() < 0.1) + return Utility.RandomList(0x62, 0x71); + + return Utility.RandomList(0x03, 0x0D, 0x13, 0x1C, 0x21, 0x30, 0x37, 0x3A, 0x44, 0x59); + } + + //[Obsolete( "Depreciated, use the methods for the Mobile's race", false )] + public static int ClipSkinHue( int hue ) + { + if ( hue < 1002 ) + return 1002; + else if ( hue > 1058 ) + return 1058; + else + return hue; + } + + //[Obsolete( "Depreciated, use the methods for the Mobile's race", false )] + public static int RandomSkinHue() + { + return Random( 1002, 57 ) | 0x8000; + } + + //[Obsolete( "Depreciated, use the methods for the Mobile's race", false )] + public static int ClipHairHue( int hue ) + { + if ( hue < 1102 ) + return 1102; + else if ( hue > 1149 ) + return 1149; + else + return hue; + } + + //[Obsolete( "Depreciated, use the methods for the Mobile's race", false )] + public static int RandomHairHue() + { + return Random( 1102, 48 ); + } + + #endregion + + private static SkillName[] m_AllSkills = new SkillName[] + { + SkillName.Alchemy, + SkillName.Anatomy, + SkillName.AnimalLore, + SkillName.ItemID, + SkillName.ArmsLore, + SkillName.Parry, + SkillName.Begging, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Peacemaking, + SkillName.Camping, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.DetectHidden, + SkillName.Discordance, + SkillName.EvalInt, + SkillName.Healing, + SkillName.Fishing, + SkillName.Forensics, + SkillName.Herding, + SkillName.Hiding, + SkillName.Provocation, + SkillName.Inscribe, + SkillName.Lockpicking, + SkillName.Magery, + SkillName.MagicResist, + SkillName.Tactics, + SkillName.Snooping, + SkillName.Musicianship, + SkillName.Poisoning, + SkillName.Archery, + SkillName.SpiritSpeak, + SkillName.Stealing, + SkillName.Tailoring, + SkillName.AnimalTaming, + SkillName.TasteID, + SkillName.Tinkering, + SkillName.Tracking, + SkillName.Veterinary, + SkillName.Swords, + SkillName.Macing, + SkillName.Fencing, + SkillName.Wrestling, + SkillName.Lumberjacking, + SkillName.Mining, + SkillName.Meditation, + SkillName.Stealth, + SkillName.RemoveTrap, + SkillName.Necromancy, + SkillName.Focus, + SkillName.Chivalry, + SkillName.Bushido, + SkillName.Ninjitsu, + SkillName.Spellweaving + }; + + private static SkillName[] m_CombatSkills = new SkillName[] + { + SkillName.Archery, + SkillName.Swords, + SkillName.Macing, + SkillName.Fencing, + SkillName.Wrestling + }; + + private static SkillName[] m_CraftSkills = new SkillName[] + { + SkillName.Alchemy, + SkillName.Blacksmith, + SkillName.Fletching, + SkillName.Carpentry, + SkillName.Cartography, + SkillName.Cooking, + SkillName.Inscribe, + SkillName.Tailoring, + SkillName.Tinkering + }; + + public static SkillName RandomSkill() + { + return m_AllSkills[Utility.Random(m_AllSkills.Length - ( Core.ML ? 0 : Core.SE ? 1 : Core.AOS ? 3 : 6 ) )]; + } + + public static SkillName RandomCombatSkill() + { + return m_CombatSkills[Utility.Random(m_CombatSkills.Length)]; + } + + public static SkillName RandomCraftSkill() + { + return m_CraftSkills[Utility.Random(m_CraftSkills.Length)]; + } + + public static void FixPoints( ref Point3D top, ref Point3D bottom ) + { + if ( bottom.m_X < top.m_X ) + { + int swap = top.m_X; + top.m_X = bottom.m_X; + bottom.m_X = swap; + } + + if ( bottom.m_Y < top.m_Y ) + { + int swap = top.m_Y; + top.m_Y = bottom.m_Y; + bottom.m_Y = swap; + } + + if ( bottom.m_Z < top.m_Z ) + { + int swap = top.m_Z; + top.m_Z = bottom.m_Z; + bottom.m_Z = swap; + } + } + + public static ArrayList BuildArrayList( IEnumerable enumerable ) + { + IEnumerator e = enumerable.GetEnumerator(); + + ArrayList list = new ArrayList(); + + while ( e.MoveNext() ) + { + list.Add( e.Current ); + } + + return list; + } + + public static bool RangeCheck( IPoint2D p1, IPoint2D p2, int range ) + { + return ( p1.X >= (p2.X - range) ) + && ( p1.X <= (p2.X + range) ) + && ( p1.Y >= (p2.Y - range) ) + && ( p2.Y <= (p2.Y + range) ); + } + + public static void FormatBuffer( TextWriter output, Stream input, int length ) + { + output.WriteLine( " 0 1 2 3 4 5 6 7 8 9 A B C D E F" ); + output.WriteLine( " -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --" ); + + int byteIndex = 0; + + int whole = length >> 4; + int rem = length & 0xF; + + for ( int i = 0; i < whole; ++i, byteIndex += 16 ) + { + StringBuilder bytes = new StringBuilder( 49 ); + StringBuilder chars = new StringBuilder( 16 ); + + for ( int j = 0; j < 16; ++j ) + { + int c = input.ReadByte(); + + bytes.Append( c.ToString( "X2" ) ); + + if ( j != 7 ) + { + bytes.Append( ' ' ); + } + else + { + bytes.Append( " " ); + } + + if (c >= 0x20 && c < 0x7F) + { + chars.Append( (char)c ); + } + else + { + chars.Append( '.' ); + } + } + + output.Write( byteIndex.ToString( "X4" ) ); + output.Write( " " ); + output.Write( bytes.ToString() ); + output.Write( " " ); + output.WriteLine( chars.ToString() ); + } + + if ( rem != 0 ) + { + StringBuilder bytes = new StringBuilder( 49 ); + StringBuilder chars = new StringBuilder( rem ); + + for ( int j = 0; j < 16; ++j ) + { + if ( j < rem ) + { + int c = input.ReadByte(); + + bytes.Append( c.ToString( "X2" ) ); + + if ( j != 7 ) + { + bytes.Append( ' ' ); + } + else + { + bytes.Append( " " ); + } + + if (c >= 0x20 && c < 0x7F) + { + chars.Append( (char)c ); + } + else + { + chars.Append( '.' ); + } + } + else + { + bytes.Append( " " ); + } + } + + output.Write( byteIndex.ToString( "X4" ) ); + output.Write( " " ); + output.Write( bytes.ToString() ); + output.Write( " " ); + output.WriteLine( chars.ToString() ); + } + } + + private static Stack m_ConsoleColors = new Stack(); + + public static void PushColor( ConsoleColor color ) + { + try + { + m_ConsoleColors.Push( Console.ForegroundColor ); + Console.ForegroundColor = color; + } + catch + { + } + } + + public static void PopColor() + { + try + { + Console.ForegroundColor = m_ConsoleColors.Pop(); + } + catch + { + } + } + + public static bool NumberBetween( double num, int bound1, int bound2, double allowance ) + { + if ( bound1 > bound2 ) + { + int i = bound1; + bound1 = bound2; + bound2 = i; + } + + return ( numbound1-allowance ); + } + + public static void AssignRandomHair( Mobile m ) + { + AssignRandomHair( m, true ); + } + public static void AssignRandomHair( Mobile m, int hue ) + { + m.HairItemID = m.Race.RandomHair( m ); + m.HairHue = hue; + } + public static void AssignRandomHair( Mobile m, bool randomHue ) + { + m.HairItemID = m.Race.RandomHair( m ); + + if( randomHue ) + m.HairHue = m.Race.RandomHairHue(); + } + + public static void AssignRandomFacialHair( Mobile m ) + { + AssignRandomFacialHair( m, true ); + } + public static void AssignRandomFacialHair( Mobile m, int hue ) + { + m.FacialHairItemID = m.Race.RandomFacialHair(m); + m.FacialHairHue = hue; + } + public static void AssignRandomFacialHair( Mobile m, bool randomHue ) + { + m.FacialHairItemID = m.Race.RandomFacialHair( m ); + + if( randomHue ) + m.FacialHairHue = m.Race.RandomHairHue(); + } + +#if MONO + public static List CastConvertList( List list ) where TInput : class where TOutput : class + { + return list.ConvertAll( new Converter( delegate( TInput value ) { return value as TOutput; } ) ); + } +#else + public static List CastConvertList( List list ) where TOutput : TInput + { + return list.ConvertAll( new Converter( delegate( TInput value ) { return (TOutput)value; } ) ); + } +#endif + + public static List SafeConvertList( List list ) where TOutput : class + { + List output = new List( list.Capacity ); + + for( int i = 0; i < list.Count; i++ ) + { + TOutput t = list[i] as TOutput; + + if( t != null ) + output.Add( t ); + } + + return output; + } + } +} \ No newline at end of file diff --git a/Server/VirtueInfo.cs b/Server/VirtueInfo.cs new file mode 100644 index 0000000..9fdced0 --- /dev/null +++ b/Server/VirtueInfo.cs @@ -0,0 +1,147 @@ +/*************************************************************************** + * VirtueInfo.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: VirtueInfo.cs 4 2006-06-15 04:28:39Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; + +namespace Server +{ + [PropertyObject] + public class VirtueInfo + { + private int[] m_Values; + + public int[] Values + { + get + { + return m_Values; + } + } + + public int GetValue( int index ) + { + if ( m_Values == null ) + return 0; + else + return m_Values[index]; + } + + public void SetValue( int index, int value ) + { + if ( m_Values == null ) + m_Values = new int[8]; + + m_Values[index] = value; + } + + public override string ToString() + { + return "..."; + } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Humility{ get{ return GetValue( 0 ); } set{ SetValue( 0, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Sacrifice{ get{ return GetValue( 1 ); } set{ SetValue( 1, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Compassion{ get{ return GetValue( 2 ); } set{ SetValue( 2, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Spirituality{ get{ return GetValue( 3 ); } set{ SetValue( 3, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Valor{ get{ return GetValue( 4 ); } set{ SetValue( 4, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Honor{ get{ return GetValue( 5 ); } set{ SetValue( 5, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Justice{ get{ return GetValue( 6 ); } set{ SetValue( 6, value ); } } + + [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] + public int Honesty{ get{ return GetValue( 7 ); } set{ SetValue( 7, value ); } } + + public VirtueInfo() + { + } + + public VirtueInfo( GenericReader reader ) + { + int version = reader.ReadByte(); + + switch ( version ) + { + case 1: //Changed the values throughout the virtue system + case 0: + { + int mask = reader.ReadByte(); + + if ( mask != 0 ) + { + m_Values = new int[8]; + + for ( int i = 0; i < 8; ++i ) + if ( (mask & (1 << i)) != 0 ) + m_Values[i] = reader.ReadInt(); + } + + break; + } + } + + if( version == 0 ) + { + Compassion *= 200; + Sacrifice *= 250; //Even though 40 (the max) only gives 10k, It's because it was formerly too easy + + //No direct conversion factor for Justice, this is just an approximation + Justice *= 500; + + //All the other virtues haven't been defined at 'version 0' point in time in the scripts. + } + } + + public static void Serialize( GenericWriter writer, VirtueInfo info ) + { + writer.Write( (byte) 1 ); // version + + if ( info.m_Values == null ) + { + writer.Write( (byte) 0 ); + } + else + { + int mask = 0; + + for ( int i = 0; i < 8; ++i ) + if ( info.m_Values[i] != 0 ) + mask |= 1 << i; + + writer.Write( (byte) mask ); + + for ( int i = 0; i < 8; ++i ) + if ( info.m_Values[i] != 0 ) + writer.Write( (int) info.m_Values[i] ); + } + } + } +} \ No newline at end of file diff --git a/Server/World.cs b/Server/World.cs new file mode 100644 index 0000000..fa47042 --- /dev/null +++ b/Server/World.cs @@ -0,0 +1,1250 @@ +/*************************************************************************** + * World.cs + * ------------------- + * begin : May 1, 2002 + * copyright : (C) The RunUO Software Team + * email : info@runuo.com + * + * $Id: World.cs 844 2012-03-07 13:47:33Z mark $ + * + ***************************************************************************/ + +/*************************************************************************** + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + ***************************************************************************/ + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Diagnostics; +using Server; +using Server.Mobiles; +using Server.Accounting; +using Server.Network; +using Server.Guilds; + +namespace Server { + public static class World { + + private static Dictionary m_Mobiles; + private static Dictionary m_Items; + + private static bool m_Loading; + private static bool m_Loaded; + + private static bool m_Saving; + private static ManualResetEvent m_DiskWriteHandle = new ManualResetEvent(true); + + private static Queue _addQueue, _deleteQueue; + + public static bool Saving { get { return m_Saving; } } + public static bool Loaded { get { return m_Loaded; } } + public static bool Loading { get { return m_Loading; } } + + public readonly static string MobileIndexPath = Path.Combine( "Saves/Mobiles/", "Mobiles.idx" ); + public readonly static string MobileTypesPath = Path.Combine( "Saves/Mobiles/", "Mobiles.tdb" ); + public readonly static string MobileDataPath = Path.Combine( "Saves/Mobiles/", "Mobiles.bin" ); + + public readonly static string ItemIndexPath = Path.Combine( "Saves/Items/", "Items.idx" ); + public readonly static string ItemTypesPath = Path.Combine( "Saves/Items/", "Items.tdb" ); + public readonly static string ItemDataPath = Path.Combine( "Saves/Items/", "Items.bin" ); + + public readonly static string GuildIndexPath = Path.Combine( "Saves/Guilds/", "Guilds.idx" ); + public readonly static string GuildDataPath = Path.Combine( "Saves/Guilds/", "Guilds.bin" ); + + public static void NotifyDiskWriteComplete() + { + if( m_DiskWriteHandle.Set()) + { + Console.WriteLine("Closing Save Files. "); + } + } + + public static void WaitForWriteCompletion() + { + m_DiskWriteHandle.WaitOne(); + } + + public static Dictionary Mobiles { + get { return m_Mobiles; } + } + + public static Dictionary Items { + get { return m_Items; } + } + + public static bool OnDelete( IEntity entity ) { + if ( m_Saving || m_Loading ) { + if ( m_Saving ) { + AppendSafetyLog( "delete", entity ); + } + + _deleteQueue.Enqueue( entity ); + + return false; + } + + return true; + } + + public static void Broadcast( int hue, bool ascii, string text ) { + Packet p; + + if ( ascii ) + p = new AsciiMessage( Serial.MinusOne, -1, MessageType.Regular, hue, 3, "System", text ); + else + p = new UnicodeMessage( Serial.MinusOne, -1, MessageType.Regular, hue, 3, "ENU", "System", text ); + + List list = NetState.Instances; + + p.Acquire(); + + for ( int i = 0; i < list.Count; ++i ) { + if ( list[i].Mobile != null ) + list[i].Send( p ); + } + + p.Release(); + + NetState.FlushAll(); + } + + public static void Broadcast( int hue, bool ascii, string format, params object[] args ) { + Broadcast( hue, ascii, String.Format( format, args ) ); + } + + private interface IEntityEntry { + Serial Serial { get; } + int TypeID { get; } + long Position { get; } + int Length { get; } + } + + private sealed class GuildEntry : IEntityEntry { + private BaseGuild m_Guild; + private long m_Position; + private int m_Length; + + public BaseGuild Guild { + get { + return m_Guild; + } + } + + public Serial Serial { + get { + return m_Guild == null ? 0 : m_Guild.Id; + } + } + + public int TypeID { + get { + return 0; + } + } + + public long Position { + get { + return m_Position; + } + } + + public int Length { + get { + return m_Length; + } + } + + public GuildEntry( BaseGuild g, long pos, int length ) { + m_Guild = g; + m_Position = pos; + m_Length = length; + } + } + + private sealed class ItemEntry : IEntityEntry { + private Item m_Item; + private int m_TypeID; + private string m_TypeName; + private long m_Position; + private int m_Length; + + public Item Item { + get { + return m_Item; + } + } + + public Serial Serial { + get { + return m_Item == null ? Serial.MinusOne : m_Item.Serial; + } + } + + public int TypeID { + get { + return m_TypeID; + } + } + + public string TypeName { + get { + return m_TypeName; + } + } + + public long Position { + get { + return m_Position; + } + } + + public int Length { + get { + return m_Length; + } + } + + public ItemEntry( Item item, int typeID, string typeName, long pos, int length ) { + m_Item = item; + m_TypeID = typeID; + m_TypeName = typeName; + m_Position = pos; + m_Length = length; + } + } + + private sealed class MobileEntry : IEntityEntry { + private Mobile m_Mobile; + private int m_TypeID; + private string m_TypeName; + private long m_Position; + private int m_Length; + + public Mobile Mobile { + get { + return m_Mobile; + } + } + + public Serial Serial { + get { + return m_Mobile == null ? Serial.MinusOne : m_Mobile.Serial; + } + } + + public int TypeID { + get { + return m_TypeID; + } + } + + public string TypeName { + get { + return m_TypeName; + } + } + + public long Position { + get { + return m_Position; + } + } + + public int Length { + get { + return m_Length; + } + } + + public MobileEntry( Mobile mobile, int typeID, string typeName, long pos, int length ) { + m_Mobile = mobile; + m_TypeID = typeID; + m_TypeName = typeName; + m_Position = pos; + m_Length = length; + } + } + + private static string m_LoadingType; + + public static string LoadingType { + get { return m_LoadingType; } + } + + private static readonly Type[] m_SerialTypeArray = new Type[1] { typeof(Serial) }; +#if Framework_4_0 + private static List> ReadTypes( BinaryReader tdbReader ) + { + int count = tdbReader.ReadInt32(); + + List> types = new List>( count ); + + for (int i = 0; i < count; ++i) + { + string typeName = tdbReader.ReadString(); + + Type t = ScriptCompiler.FindTypeByFullName(typeName); + + if (t == null) + { + Console.WriteLine("failed"); + + if (!Core.Service) + { + Console.WriteLine("Error: Type '{0}' was not found. Delete all of those types? (y/n)", typeName); + + if (Console.ReadKey(true).Key == ConsoleKey.Y) + { + types.Add(null); + Console.Write("World: Loading..."); + continue; + } + + Console.WriteLine("Types will not be deleted. An exception will be thrown."); + } + else + { + Console.WriteLine("Error: Type '{0}' was not found.", typeName); + } + + throw new Exception(String.Format("Bad type '{0}'", typeName)); + } + + ConstructorInfo ctor = t.GetConstructor(m_SerialTypeArray); + + if (ctor != null) + { + types.Add( new Tuple( ctor, typeName ) ); + } + else + { + throw new Exception(String.Format("Type '{0}' does not have a serialization constructor", t)); + } + } + + return types; + } + + public static void Load() { + if ( m_Loaded ) + return; + + m_Loaded = true; + m_LoadingType = null; + + Console.Write( "World: Loading..." ); + + Stopwatch watch = Stopwatch.StartNew(); + + m_Loading = true; + + _addQueue = new Queue(); + _deleteQueue = new Queue(); + + int mobileCount = 0, itemCount = 0, guildCount = 0; + + object[] ctorArgs = new object[1]; + + List items = new List(); + List mobiles = new List(); + List guilds = new List(); + + if ( File.Exists( MobileIndexPath ) && File.Exists( MobileTypesPath ) ) { + using ( FileStream idx = new FileStream( MobileIndexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader idxReader = new BinaryReader( idx ); + + using ( FileStream tdb = new FileStream( MobileTypesPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader tdbReader = new BinaryReader( tdb ); + + List> types = ReadTypes( tdbReader ); + + mobileCount = idxReader.ReadInt32(); + + m_Mobiles = new Dictionary( mobileCount ); + + for ( int i = 0; i < mobileCount; ++i ) { + int typeID = idxReader.ReadInt32(); + int serial = idxReader.ReadInt32(); + long pos = idxReader.ReadInt64(); + int length = idxReader.ReadInt32(); + + Tuple objs = types[typeID]; + + if ( objs == null ) + continue; + + Mobile m = null; + ConstructorInfo ctor = objs.Item1; + string typeName = objs.Item2; + + try { + ctorArgs[0] = ( Serial ) serial; + m = ( Mobile ) ( ctor.Invoke( ctorArgs ) ); + } catch { + } + + if ( m != null ) { + mobiles.Add( new MobileEntry( m, typeID, typeName, pos, length ) ); + AddMobile( m ); + } + } + + tdbReader.Close(); + } + + idxReader.Close(); + } + } else { + m_Mobiles = new Dictionary(); + } + + if ( File.Exists( ItemIndexPath ) && File.Exists( ItemTypesPath ) ) { + using ( FileStream idx = new FileStream( ItemIndexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader idxReader = new BinaryReader( idx ); + + using ( FileStream tdb = new FileStream( ItemTypesPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader tdbReader = new BinaryReader( tdb ); + + List> types = ReadTypes( tdbReader ); + + itemCount = idxReader.ReadInt32(); + + m_Items = new Dictionary( itemCount ); + + for ( int i = 0; i < itemCount; ++i ) { + int typeID = idxReader.ReadInt32(); + int serial = idxReader.ReadInt32(); + long pos = idxReader.ReadInt64(); + int length = idxReader.ReadInt32(); + + Tuple objs = types[typeID]; + + if ( objs == null ) + continue; + + Item item = null; + ConstructorInfo ctor = objs.Item1; + string typeName = objs.Item2; + + try { + ctorArgs[0] = ( Serial ) serial; + item = ( Item ) ( ctor.Invoke( ctorArgs ) ); + } catch { + } + + if ( item != null ) { + items.Add( new ItemEntry( item, typeID, typeName, pos, length ) ); + AddItem( item ); + } + } + + tdbReader.Close(); + } + + idxReader.Close(); + } + } else { + m_Items = new Dictionary(); + } + + if ( File.Exists( GuildIndexPath ) ) { + using ( FileStream idx = new FileStream( GuildIndexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader idxReader = new BinaryReader( idx ); + + guildCount = idxReader.ReadInt32(); + + CreateGuildEventArgs createEventArgs = new CreateGuildEventArgs( -1 ); + for ( int i = 0; i < guildCount; ++i ) { + idxReader.ReadInt32();//no typeid for guilds + int id = idxReader.ReadInt32(); + long pos = idxReader.ReadInt64(); + int length = idxReader.ReadInt32(); + + createEventArgs.Id = id; + BaseGuild guild = EventSink.InvokeCreateGuild( createEventArgs ); + if ( guild != null ) + guilds.Add( new GuildEntry( guild, pos, length ) ); + } + + idxReader.Close(); + } + } + + bool failedMobiles = false, failedItems = false, failedGuilds = false; + Type failedType = null; + Serial failedSerial = Serial.Zero; + Exception failed = null; + int failedTypeID = 0; + + if ( File.Exists( MobileDataPath ) ) { + using ( FileStream bin = new FileStream( MobileDataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) ); + + for ( int i = 0; i < mobiles.Count; ++i ) { + MobileEntry entry = mobiles[i]; + Mobile m = entry.Mobile; + + if ( m != null ) { + reader.Seek( entry.Position, SeekOrigin.Begin ); + + try { + m_LoadingType = entry.TypeName; + m.Deserialize( reader ); + + if ( reader.Position != ( entry.Position + entry.Length ) ) + throw new Exception( String.Format( "***** Bad serialize on {0} *****", m.GetType() ) ); + } catch ( Exception e ) { + mobiles.RemoveAt( i ); + + failed = e; + failedMobiles = true; + failedType = m.GetType(); + failedTypeID = entry.TypeID; + failedSerial = m.Serial; + + break; + } + } + } + + reader.Close(); + } + } + + if ( !failedMobiles && File.Exists( ItemDataPath ) ) { + using ( FileStream bin = new FileStream( ItemDataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) ); + + for ( int i = 0; i < items.Count; ++i ) { + ItemEntry entry = items[i]; + Item item = entry.Item; + + if ( item != null ) { + reader.Seek( entry.Position, SeekOrigin.Begin ); + + try { + m_LoadingType = entry.TypeName; + item.Deserialize( reader ); + + if ( reader.Position != ( entry.Position + entry.Length ) ) + throw new Exception( String.Format( "***** Bad serialize on {0} *****", item.GetType() ) ); + } catch ( Exception e ) { + items.RemoveAt( i ); + + failed = e; + failedItems = true; + failedType = item.GetType(); + failedTypeID = entry.TypeID; + failedSerial = item.Serial; + + break; + } + } + } + + reader.Close(); + } + } + + m_LoadingType = null; + + if ( !failedMobiles && !failedItems && File.Exists( GuildDataPath ) ) { + using ( FileStream bin = new FileStream( GuildDataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) ); + + for ( int i = 0; i < guilds.Count; ++i ) { + GuildEntry entry = guilds[i]; + BaseGuild g = entry.Guild; + + if ( g != null ) { + reader.Seek( entry.Position, SeekOrigin.Begin ); + + try { + g.Deserialize( reader ); + + if ( reader.Position != ( entry.Position + entry.Length ) ) + throw new Exception( String.Format( "***** Bad serialize on Guild {0} *****", g.Id ) ); + } catch ( Exception e ) { + guilds.RemoveAt( i ); + + failed = e; + failedGuilds = true; + failedType = typeof( BaseGuild ); + failedTypeID = g.Id; + failedSerial = g.Id; + + break; + } + } + } + + reader.Close(); + } + } + + if ( failedItems || failedMobiles || failedGuilds ) { + Console.WriteLine( "An error was encountered while loading a saved object" ); + + Console.WriteLine( " - Type: {0}", failedType ); + Console.WriteLine( " - Serial: {0}", failedSerial ); + + if ( !Core.Service ) { + Console.WriteLine( "Delete the object? (y/n)" ); + + if ( Console.ReadKey( true ).Key == ConsoleKey.Y ) { + if ( failedType != typeof( BaseGuild ) ) { + Console.WriteLine( "Delete all objects of that type? (y/n)" ); + + if ( Console.ReadKey( true ).Key == ConsoleKey.Y ) { + if ( failedMobiles ) { + for ( int i = 0; i < mobiles.Count; ) { + if ( mobiles[i].TypeID == failedTypeID ) + mobiles.RemoveAt( i ); + else + ++i; + } + } else if ( failedItems ) { + for ( int i = 0; i < items.Count; ) { + if ( items[i].TypeID == failedTypeID ) + items.RemoveAt( i ); + else + ++i; + } + } + } + } + + SaveIndex( mobiles, MobileIndexPath ); + SaveIndex( items, ItemIndexPath ); + SaveIndex( guilds, GuildIndexPath ); + } + + Console.WriteLine( "After pressing return an exception will be thrown and the server will terminate." ); + Console.ReadLine(); + } else { + Console.WriteLine( "An exception will be thrown and the server will terminate." ); + } + + throw new Exception( String.Format( "Load failed (items={0}, mobiles={1}, guilds={2}, type={3}, serial={4})", failedItems, failedMobiles, failedGuilds, failedType, failedSerial ), failed ); + } + + EventSink.InvokeWorldLoad(); + + m_Loading = false; + + ProcessSafetyQueues(); + + foreach ( Item item in m_Items.Values ) { + if ( item.Parent == null ) + item.UpdateTotals(); + + item.ClearProperties(); + } + + foreach ( Mobile m in m_Mobiles.Values ) { + m.UpdateRegion(); // Is this really needed? + m.UpdateTotals(); + + m.ClearProperties(); + } + + watch.Stop(); + + Console.WriteLine( "done ({1} items, {2} mobiles) ({0:F2} seconds)", watch.Elapsed.TotalSeconds, m_Items.Count, m_Mobiles.Count ); + } +#else + private static List ReadTypes( BinaryReader tdbReader ) + { + int count = tdbReader.ReadInt32(); + + List types = new List(count); + + for (int i = 0; i < count; ++i) + { + string typeName = tdbReader.ReadString(); + + Type t = ScriptCompiler.FindTypeByFullName(typeName); + + if (t == null) + { + Console.WriteLine("failed"); + + if (!Core.Service) + { + Console.WriteLine("Error: Type '{0}' was not found. Delete all of those types? (y/n)", typeName); + + if (Console.ReadKey(true).Key == ConsoleKey.Y) + { + types.Add(null); + Console.Write("World: Loading..."); + continue; + } + + Console.WriteLine("Types will not be deleted. An exception will be thrown."); + } + else + { + Console.WriteLine("Error: Type '{0}' was not found.", typeName); + } + + throw new Exception(String.Format("Bad type '{0}'", typeName)); + } + + ConstructorInfo ctor = t.GetConstructor(m_SerialTypeArray); + + if (ctor != null) + { + types.Add(new object[] { ctor, typeName }); + } + else + { + throw new Exception(String.Format("Type '{0}' does not have a serialization constructor", t)); + } + } + + return types; + } + + public static void Load() { + if ( m_Loaded ) + return; + + m_Loaded = true; + m_LoadingType = null; + + Console.Write( "World: Loading..." ); + + Stopwatch watch = Stopwatch.StartNew(); + + m_Loading = true; + + _addQueue = new Queue(); + _deleteQueue = new Queue(); + + int mobileCount = 0, itemCount = 0, guildCount = 0; + + object[] ctorArgs = new object[1]; + + List items = new List(); + List mobiles = new List(); + List guilds = new List(); + + if ( File.Exists( MobileIndexPath ) && File.Exists( MobileTypesPath ) ) { + using ( FileStream idx = new FileStream( MobileIndexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader idxReader = new BinaryReader( idx ); + + using ( FileStream tdb = new FileStream( MobileTypesPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader tdbReader = new BinaryReader( tdb ); + + List types = ReadTypes( tdbReader ); + + mobileCount = idxReader.ReadInt32(); + + m_Mobiles = new Dictionary( mobileCount ); + + for ( int i = 0; i < mobileCount; ++i ) { + int typeID = idxReader.ReadInt32(); + int serial = idxReader.ReadInt32(); + long pos = idxReader.ReadInt64(); + int length = idxReader.ReadInt32(); + + object[] objs = types[typeID]; + + if ( objs == null ) + continue; + + Mobile m = null; + ConstructorInfo ctor = ( ConstructorInfo ) objs[0]; + string typeName = ( string ) objs[1]; + + try { + ctorArgs[0] = ( Serial ) serial; + m = ( Mobile ) ( ctor.Invoke( ctorArgs ) ); + } catch { + } + + if ( m != null ) { + mobiles.Add( new MobileEntry( m, typeID, typeName, pos, length ) ); + AddMobile( m ); + } + } + + tdbReader.Close(); + } + + idxReader.Close(); + } + } else { + m_Mobiles = new Dictionary(); + } + + if ( File.Exists( ItemIndexPath ) && File.Exists( ItemTypesPath ) ) { + using ( FileStream idx = new FileStream( ItemIndexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader idxReader = new BinaryReader( idx ); + + using ( FileStream tdb = new FileStream( ItemTypesPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader tdbReader = new BinaryReader( tdb ); + + List types = ReadTypes( tdbReader ); + + itemCount = idxReader.ReadInt32(); + + m_Items = new Dictionary( itemCount ); + + for ( int i = 0; i < itemCount; ++i ) { + int typeID = idxReader.ReadInt32(); + int serial = idxReader.ReadInt32(); + long pos = idxReader.ReadInt64(); + int length = idxReader.ReadInt32(); + + object[] objs = types[typeID]; + + if ( objs == null ) + continue; + + Item item = null; + ConstructorInfo ctor = ( ConstructorInfo ) objs[0]; + string typeName = ( string ) objs[1]; + + try { + ctorArgs[0] = ( Serial ) serial; + item = ( Item ) ( ctor.Invoke( ctorArgs ) ); + } catch { + } + + if ( item != null ) { + items.Add( new ItemEntry( item, typeID, typeName, pos, length ) ); + AddItem( item ); + } + } + + tdbReader.Close(); + } + + idxReader.Close(); + } + } else { + m_Items = new Dictionary(); + } + + if ( File.Exists( GuildIndexPath ) ) { + using ( FileStream idx = new FileStream( GuildIndexPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryReader idxReader = new BinaryReader( idx ); + + guildCount = idxReader.ReadInt32(); + + CreateGuildEventArgs createEventArgs = new CreateGuildEventArgs( -1 ); + for ( int i = 0; i < guildCount; ++i ) { + idxReader.ReadInt32();//no typeid for guilds + int id = idxReader.ReadInt32(); + long pos = idxReader.ReadInt64(); + int length = idxReader.ReadInt32(); + + createEventArgs.Id = id; + BaseGuild guild = EventSink.InvokeCreateGuild( createEventArgs ); + if ( guild != null ) + guilds.Add( new GuildEntry( guild, pos, length ) ); + } + + idxReader.Close(); + } + } + + bool failedMobiles = false, failedItems = false, failedGuilds = false; + Type failedType = null; + Serial failedSerial = Serial.Zero; + Exception failed = null; + int failedTypeID = 0; + + if ( File.Exists( MobileDataPath ) ) { + using ( FileStream bin = new FileStream( MobileDataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) ); + + for ( int i = 0; i < mobiles.Count; ++i ) { + MobileEntry entry = mobiles[i]; + Mobile m = entry.Mobile; + + if ( m != null ) { + reader.Seek( entry.Position, SeekOrigin.Begin ); + + try { + m_LoadingType = entry.TypeName; + m.Deserialize( reader ); + + if ( reader.Position != ( entry.Position + entry.Length ) ) + throw new Exception( String.Format( "***** Bad serialize on {0} *****", m.GetType() ) ); + } catch ( Exception e ) { + mobiles.RemoveAt( i ); + + failed = e; + failedMobiles = true; + failedType = m.GetType(); + failedTypeID = entry.TypeID; + failedSerial = m.Serial; + + break; + } + } + } + + reader.Close(); + } + } + + if ( !failedMobiles && File.Exists( ItemDataPath ) ) { + using ( FileStream bin = new FileStream( ItemDataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) ); + + for ( int i = 0; i < items.Count; ++i ) { + ItemEntry entry = items[i]; + Item item = entry.Item; + + if ( item != null ) { + reader.Seek( entry.Position, SeekOrigin.Begin ); + + try { + m_LoadingType = entry.TypeName; + item.Deserialize( reader ); + + if ( reader.Position != ( entry.Position + entry.Length ) ) + throw new Exception( String.Format( "***** Bad serialize on {0} *****", item.GetType() ) ); + } catch ( Exception e ) { + items.RemoveAt( i ); + + failed = e; + failedItems = true; + failedType = item.GetType(); + failedTypeID = entry.TypeID; + failedSerial = item.Serial; + + break; + } + } + } + + reader.Close(); + } + } + + m_LoadingType = null; + + if ( !failedMobiles && !failedItems && File.Exists( GuildDataPath ) ) { + using ( FileStream bin = new FileStream( GuildDataPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { + BinaryFileReader reader = new BinaryFileReader( new BinaryReader( bin ) ); + + for ( int i = 0; i < guilds.Count; ++i ) { + GuildEntry entry = guilds[i]; + BaseGuild g = entry.Guild; + + if ( g != null ) { + reader.Seek( entry.Position, SeekOrigin.Begin ); + + try { + g.Deserialize( reader ); + + if ( reader.Position != ( entry.Position + entry.Length ) ) + throw new Exception( String.Format( "***** Bad serialize on Guild {0} *****", g.Id ) ); + } catch ( Exception e ) { + guilds.RemoveAt( i ); + + failed = e; + failedGuilds = true; + failedType = typeof( BaseGuild ); + failedTypeID = g.Id; + failedSerial = g.Id; + + break; + } + } + } + + reader.Close(); + } + } + + if ( failedItems || failedMobiles || failedGuilds ) { + Console.WriteLine( "An error was encountered while loading a saved object" ); + + Console.WriteLine( " - Type: {0}", failedType ); + Console.WriteLine( " - Serial: {0}", failedSerial ); + + if ( !Core.Service ) { + Console.WriteLine( "Delete the object? (y/n)" ); + + if ( Console.ReadKey( true ).Key == ConsoleKey.Y ) { + if ( failedType != typeof( BaseGuild ) ) { + Console.WriteLine( "Delete all objects of that type? (y/n)" ); + + if ( Console.ReadKey( true ).Key == ConsoleKey.Y ) { + if ( failedMobiles ) { + for ( int i = 0; i < mobiles.Count; ) { + if ( mobiles[i].TypeID == failedTypeID ) + mobiles.RemoveAt( i ); + else + ++i; + } + } else if ( failedItems ) { + for ( int i = 0; i < items.Count; ) { + if ( items[i].TypeID == failedTypeID ) + items.RemoveAt( i ); + else + ++i; + } + } + } + } + + SaveIndex( mobiles, MobileIndexPath ); + SaveIndex( items, ItemIndexPath ); + SaveIndex( guilds, GuildIndexPath ); + } + + Console.WriteLine( "After pressing return an exception will be thrown and the server will terminate." ); + Console.ReadLine(); + } else { + Console.WriteLine( "An exception will be thrown and the server will terminate." ); + } + + throw new Exception( String.Format( "Load failed (items={0}, mobiles={1}, guilds={2}, type={3}, serial={4})", failedItems, failedMobiles, failedGuilds, failedType, failedSerial ), failed ); + } + + EventSink.InvokeWorldLoad(); + + m_Loading = false; + + ProcessSafetyQueues(); + + foreach ( Item item in m_Items.Values ) { + if ( item.Parent == null ) + item.UpdateTotals(); + + item.ClearProperties(); + } + + foreach ( Mobile m in m_Mobiles.Values ) { + m.UpdateRegion(); // Is this really needed? + m.UpdateTotals(); + + m.ClearProperties(); + } + + watch.Stop(); + + Console.WriteLine( "done ({1} items, {2} mobiles) ({0:F2} seconds)", watch.Elapsed.TotalSeconds, m_Items.Count, m_Mobiles.Count ); + } +#endif + + private static void ProcessSafetyQueues() { + while ( _addQueue.Count > 0 ) { + IEntity entity = _addQueue.Dequeue(); + + Item item = entity as Item; + + if ( item != null ) { + AddItem( item ); + } else { + Mobile mob = entity as Mobile; + + if ( mob != null ) { + AddMobile( mob ); + } + } + } + + while ( _deleteQueue.Count > 0 ) { + IEntity entity = _deleteQueue.Dequeue(); + + Item item = entity as Item; + + if ( item != null ) { + item.Delete(); + } else { + Mobile mob = entity as Mobile; + + if ( mob != null ) { + mob.Delete(); + } + } + } + } + + private static void AppendSafetyLog( string action, IEntity entity ) { + string message = String.Format( "Warning: Attempted to {1} {2} during world save." + + "{0}This action could cause inconsistent state." + + "{0}It is strongly advised that the offending scripts be corrected.", + Environment.NewLine, + action, entity + ); + + Console.WriteLine( message ); + + try { + using ( StreamWriter op = new StreamWriter( "world-save-errors.log", true ) ) { + op.WriteLine( "{0}\t{1}", DateTime.Now, message ); + op.WriteLine( new StackTrace( 2 ).ToString() ); + op.WriteLine(); + } + } catch { + } + } + + private static void SaveIndex( List list, string path ) where T : IEntityEntry { + if ( !Directory.Exists( "Saves/Mobiles/" ) ) + Directory.CreateDirectory( "Saves/Mobiles/" ); + + if ( !Directory.Exists( "Saves/Items/" ) ) + Directory.CreateDirectory( "Saves/Items/" ); + + if ( !Directory.Exists( "Saves/Guilds/" ) ) + Directory.CreateDirectory( "Saves/Guilds/" ); + + using ( FileStream idx = new FileStream( path, FileMode.Create, FileAccess.Write, FileShare.None ) ) { + BinaryWriter idxWriter = new BinaryWriter( idx ); + + idxWriter.Write( list.Count ); + + for ( int i = 0; i < list.Count; ++i ) { + T e = list[i]; + + idxWriter.Write( e.TypeID ); + idxWriter.Write( e.Serial ); + idxWriter.Write( e.Position ); + idxWriter.Write( e.Length ); + } + + idxWriter.Close(); + } + } + + internal static int m_Saves; + + public static void Save() { + Save( true, false ); + } + + public static void Save( bool message, bool permitBackgroundWrite ) { + if ( m_Saving ) + return; + + ++m_Saves; + + NetState.FlushAll(); + NetState.Pause(); + + World.WaitForWriteCompletion();//Blocks Save until current disk flush is done. + + m_Saving = true; + + m_DiskWriteHandle.Reset(); + + if ( message ) + Broadcast( 0x35, true, "The world is saving, please wait." ); + + SaveStrategy strategy = SaveStrategy.Acquire(); + Console.WriteLine( "Core: Using {0} save strategy", strategy.Name.ToLowerInvariant() ); + + Console.Write( "World: Saving..." ); + + Stopwatch watch = Stopwatch.StartNew(); + + if ( !Directory.Exists( "Saves/Mobiles/" ) ) + Directory.CreateDirectory( "Saves/Mobiles/" ); + if ( !Directory.Exists( "Saves/Items/" ) ) + Directory.CreateDirectory( "Saves/Items/" ); + if ( !Directory.Exists( "Saves/Guilds/" ) ) + Directory.CreateDirectory( "Saves/Guilds/" ); + + + /*using ( SaveMetrics metrics = new SaveMetrics() ) {*/ + strategy.Save( null, permitBackgroundWrite ); + /*}*/ + + try { + EventSink.InvokeWorldSave( new WorldSaveEventArgs( message ) ); + } catch ( Exception e ) { + throw new Exception( "World Save event threw an exception. Save failed!", e ); + } + + watch.Stop(); + + m_Saving = false; + + if (!permitBackgroundWrite) + World.NotifyDiskWriteComplete(); //Sets the DiskWriteHandle. If we allow background writes, we leave this upto the individual save strategies. + + ProcessSafetyQueues(); + + strategy.ProcessDecay(); + + Console.WriteLine( "Save done in {0:F2} seconds.", watch.Elapsed.TotalSeconds ); + + if ( message ) + Broadcast( 0x35, true, "World save complete. The entire process took {0:F1} seconds.", watch.Elapsed.TotalSeconds ); + + NetState.Resume(); + } + + internal static List m_ItemTypes = new List(); + internal static List m_MobileTypes = new List(); + + public static IEntity FindEntity( Serial serial ) { + if ( serial.IsItem ) + return FindItem( serial ); + else if ( serial.IsMobile ) + return FindMobile( serial ); + + return null; + } + + public static Mobile FindMobile( Serial serial ) { + Mobile mob; + + m_Mobiles.TryGetValue( serial, out mob ); + + return mob; + } + + public static void AddMobile( Mobile m ) { + if ( m_Saving ) { + AppendSafetyLog( "add", m ); + _addQueue.Enqueue( m ); + } else { + m_Mobiles[m.Serial] = m; + } + } + + public static Item FindItem( Serial serial ) { + Item item; + + m_Items.TryGetValue( serial, out item ); + + return item; + } + + public static void AddItem( Item item ) { + if ( m_Saving ) { + AppendSafetyLog( "add", item ); + _addQueue.Enqueue( item ); + } else { + m_Items[item.Serial] = item; + } + } + + public static void RemoveMobile( Mobile m ) { + m_Mobiles.Remove( m.Serial ); + } + + public static void RemoveItem( Item item ) { + m_Items.Remove( item.Serial ); + } + } +} \ No newline at end of file diff --git a/Server/app.config b/Server/app.config new file mode 100644 index 0000000..e365603 --- /dev/null +++ b/Server/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Server/runuo.ico b/Server/runuo.ico new file mode 100644 index 0000000..d77808b Binary files /dev/null and b/Server/runuo.ico differ diff --git a/UOArchitectInterface.dll b/UOArchitectInterface.dll new file mode 100644 index 0000000..b021972 Binary files /dev/null and b/UOArchitectInterface.dll differ diff --git a/Ultima.dll b/Ultima.dll new file mode 100644 index 0000000..9f404a9 Binary files /dev/null and b/Ultima.dll differ diff --git a/Vivre.sln b/Vivre.sln new file mode 100644 index 0000000..7c29e98 --- /dev/null +++ b/Vivre.sln @@ -0,0 +1,81 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts", "Scripts\Scripts.csproj", "{AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{4DD64307-F1D5-43B8-BF40-E27C9A36829D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlQuestNPC", "XmlQuestNPC\XmlQuestNPC.csproj", "{8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 5 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = https://gobbe.visualstudio.com/defaultcollection + SccLocalPath0 = . + SccProjectUniqueName1 = Scripts\\Scripts.csproj + SccProjectName1 = Scripts + SccLocalPath1 = Scripts + SccProjectUniqueName2 = Server\\Server.csproj + SccProjectName2 = Server + SccLocalPath2 = Server + SccProjectUniqueName3 = Data\\Data.csproj + SccProjectName3 = Data + SccLocalPath3 = Data + SccProjectUniqueName4 = XmlQuestNPC\\XmlQuestNPC.csproj + SccProjectName4 = XmlQuestNPC + SccLocalPath4 = XmlQuestNPC + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Debug|Any CPU.ActiveCfg = Debug|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Debug|x86.ActiveCfg = Debug|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Debug|x86.Build.0 = Debug|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Release|Any CPU.ActiveCfg = Release|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Release|Mixed Platforms.Build.0 = Release|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Release|x86.ActiveCfg = Release|x86 + {AC8C04EB-1BB1-4C77-AB16-AA4CD84A4F03}.Release|x86.Build.0 = Release|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Debug|Any CPU.ActiveCfg = Debug|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Debug|x86.ActiveCfg = Debug|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Debug|x86.Build.0 = Debug|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Release|Any CPU.ActiveCfg = Release|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Release|Mixed Platforms.Build.0 = Release|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Release|x86.ActiveCfg = Release|x86 + {4DD64307-F1D5-43B8-BF40-E27C9A36829D}.Release|x86.Build.0 = Release|x86 + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Debug|x86.ActiveCfg = Debug|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Release|Any CPU.Build.0 = Release|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F7A42D69-4FF4-48FB-AE9D-1EC70D68CC7D}.Release|x86.ActiveCfg = Release|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Debug|x86.ActiveCfg = Debug|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Release|Any CPU.Build.0 = Release|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/XmlQuestNPC/App.config b/XmlQuestNPC/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/XmlQuestNPC/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/XmlQuestNPC/MyronBanquier.npc b/XmlQuestNPC/MyronBanquier.npc new file mode 100644 index 0000000..0e30914 --- /dev/null +++ b/XmlQuestNPC/MyronBanquier.npc @@ -0,0 +1,53 @@ + + + + Castalia + True + 5 + 16 + Magincia c'est sympa,keyring + False + 10 + 2 + 3 + + + 0 + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Ouvrez un compte chez nous et obtenez un magnifique [cadeau] de bienvenue! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Merci,voici pour vous ! + cadeau + GIVE,1/<keyring/hue/523/name/Magincia c'est sympa> + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/MyronBushido1.npc b/XmlQuestNPC/MyronBushido1.npc new file mode 100644 index 0000000..4c081b6 --- /dev/null +++ b/XmlQuestNPC/MyronBushido1.npc @@ -0,0 +1,67 @@ + + + + Cedric + True + 3 + 16 + False + 10 + 15 + 4 + + + 1 + 1 + Bonjour! Que diriez vous d'un petit duel d'honneur? + + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Et bien en garde alors! Oserez-vous me laisser frapper le premier? + duel + 1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Vous êtes vraiment un homme d'honneur! Je pense que ceci vous intéressera. + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Au revoir! + revoir + 1 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/MyronMendiant.npc b/XmlQuestNPC/MyronMendiant.npc new file mode 100644 index 0000000..7c6efad --- /dev/null +++ b/XmlQuestNPC/MyronMendiant.npc @@ -0,0 +1,68 @@ + + + + Ron + True + 5 + 16 + False + 10 + 1 + 4 + + + 0 + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Z'auriez pas une petite [pièce] pour une pauv' cloche? + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + J'dirai du bien d'vous! Merci! + pièce,pièces,piece,pieces + TAKEBYTYPE,1,1/GOLD + AMOUNTCARRIED,GOLD>0 + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + C'est dégeulasse de me faire croire ca en ayant les poches vides. + pièce,pièces,piece,pieces + AMOUNTCARRIED,GOLD<1 + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/NinjitsuNathaniel.npc b/XmlQuestNPC/NinjitsuNathaniel.npc new file mode 100644 index 0000000..1068a7e --- /dev/null +++ b/XmlQuestNPC/NinjitsuNathaniel.npc @@ -0,0 +1,139 @@ + + + + Nathaniel + True + 3 + 16 + Je marcherai parmis les Ombres | ATTACHMENT,Je marcherai parmis les Ombres,XmlQuestAttachement + False + 10 + 5 + NinjitsuNathaniel + 9 + + + 0 + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + TAKE,1,1,false/Lassombra;SETONCARRIED,Je marcherai parmis les Ombres,questholder/Completed1/true/DELETE + GETONCARRIED,Lassombra,Visible=true;GETONCARRIED,Je marcherai parmis les Ombres,Visible=true + -1 + 1 + -1 + True + False + False + Regular + -1 + GUMP,Nathaniel,0/Oui !! c'est bien elle ! Vous vous êtes montré prometteur...Ecoutez, je ne devrais pas vous dire ça, mais si vous voulez en savoir plus...rendez vous à la guilde des voleurs de la vieille Haven. Dites que vous venez de ma part. Le mot de passe est Rose Trémière. Non, ne vous demandez pas pourquoi. Allez, maintenant ! + + + 20 + 20 + Mon enfant, j'ai un problème que vous pourrez peut être m'aider à résoudre...m'aiderez-vous ? + GETONTRIGMOB,skills.hiding.value>40 + -2 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + oui,aide,bien sur + GETONTRIGMOB,skills.hiding.value>40 + 20 + 1 + -1 + True + False + False + Regular + -1 + GUMP,Nathaniel,4/C'est un travail qui demande une personne de la discrétion, et je ne voudrais pas que cela s'ébruite;Voici qui est intriguant, je vous en prie, poursuivez;accept;Hmm,vous me semblez sournois et biaiseux, n'y comptez pas;refuse + + + 40 + 40 + accept + GETONTRIGMOB,skills.hiding.value>40 + 30 + 1 + -1 + True + False + False + Regular + -1 + GUMP,Nathaniel,4/Si vous m'aidez, je pourrais vous apprendre à bénéficier des ombres comme personne...Une forme de magie redoutable... Alors, interressé ?;C'est un pouvoir que je désire, j'oeuvrerai pour vous;accept1;Pfff, je n'ai pas besoin de tels artifices. je décline.;refuse1 + + + 50 + 50 + refuse + SETONTHIS/MSG/Tant pis, revenez me voir si vous changez d'avis.../doreset/true + 30,40,60 + 1 + -1 + True + False + False + Regular + -1 + + + 60 + 60 + accept1 + 40 + 1 + -1 + True + False + False + Regular + -1 + GUMP,Nathaniel,4/Très bien, l'affaire est délicate...Un marchand m'a dérobé quelque chose auquel je tiens particulièrement, une vielle dague sans intéret. Je veux la récupérer. Mais pour cela il faudra lui tendre une embuscade. Il devrait passer non loin de la mine au sud de Haven. Prenez une bonne cachette, et attendez le. Mais attention, il risque d'être accompagné !;Pas de problème, il est comme mort;quest;Non, je ne donne pas dans ce genre la. Adieu ! ;refuse + + + 70 + 70 + quest + GIVE/<questholder/name/Je marcherai parmis les Ombres/notestring/Prenez le marchand en embuscade, il ne doit se douter de rien ! Puis récupérez Lassombra s et rendez la à Nathaniel /objective1/COLLECTNAMED,Lassombra ,1/autoreward/false/repeatable/false;SETONTHIS/MSG/Je vous attendrais ici, bonne chance.../doreset/true + 60 + 1 + -1 + True + False + False + Regular + -1 + + + 80 + 80 + + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsAmbushNin1.npc b/XmlQuestNPC/VindsAmbushNin1.npc new file mode 100644 index 0000000..dc6653e --- /dev/null +++ b/XmlQuestNPC/VindsAmbushNin1.npc @@ -0,0 +1,78 @@ + + + + Brett + True + 20 + 16 + False + 10 + 1 + VindsAmbushNin1 + 5 + + + 0 + 0 + + 1 + -1 + True + False + True + Regular + -1 + + + 10 + 10 + *avance d'un pas méfiant * + -1 + 1 + -1 + True + False + True + Regular + -1 + + + 20 + 20 + Dépéchons nous de rallier la forteresse orque, j'ai un mauvais pressentiment + 10 + 1 + -1 + True + False + True + Regular + -1 + + + 30 + 30 + Aucune idée, mais ne l'ennervez pas comme la derniere fois + 20 + 1 + -1 + True + False + True + Regular + -1 + + + 40 + 40 + Elle à le palais délicat, franchement lui proposer des...Hmm..il y a quelque chose qui cloche... + 30 + 1 + -1 + True + False + True + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsAmbushNin2.npc b/XmlQuestNPC/VindsAmbushNin2.npc new file mode 100644 index 0000000..35a531d --- /dev/null +++ b/XmlQuestNPC/VindsAmbushNin2.npc @@ -0,0 +1,38 @@ + + + + Fireki + True + 3 + 16 + False + 10 + 1 + 2 + + + 0 + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + sshhkk, c'est encore loin , Grand Schtimpfe ? + forteresse + -1 + 1 + -1 + True + False + True + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivAdriel.npc b/XmlQuestNPC/VindsChivAdriel.npc new file mode 100644 index 0000000..957d68b --- /dev/null +++ b/XmlQuestNPC/VindsChivAdriel.npc @@ -0,0 +1,26 @@ + + + + Adriel + True + 8 + 16 + False + 10 + 1 + 1 + + + 0 + 0 + Il suffit ! Vous etes enchaine pour une bonne eternite, et pauvre de moi, je suis tout aussi enchaine a vous surveiller pendant ce temps. Taisez-vous ! + -1 + 1 + -1 + True + False + False + Regular + 1758 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivAgril.npc b/XmlQuestNPC/VindsChivAgril.npc new file mode 100644 index 0000000..b3b4a19 --- /dev/null +++ b/XmlQuestNPC/VindsChivAgril.npc @@ -0,0 +1,179 @@ + + + + Thai + True + 3 + 16 + False + 10 + 1 + VindsChivAgril + 12 + + + 0 + 0 + Oh, quelle joie, encore invoque par un petit mortel. Dites ca ne vous lasse pas a la longue ? J'imagine que vous voulez parler de quelqu'un ? + -1 + 1 + -1 + True + False + False + Regular + 567 + + + 10 + 10 + Ah, oui...l'empoisonneur... toute une famille massacree. Terrible, non ? Et les Huiric ne lui avaient absolument rien fait ! + Aidan + 0,20 + 1 + -1 + True + False + False + Regular + 567 + + + 20 + 20 + Un mage s'adonnant aux arts les plus sombres. Il ne voulait rien de moins que l'eradication de Aidan et sa clique. Vous connaissez la politique, hein... + Huiric + 0,10 + 1 + -1 + True + False + False + Regular + 567 + + + 30 + 30 + Ca, c'est moi. Serviteur des abysses, contractuel. Hmm...dites moi, ca vous tenterais de passer un petit marche ? Allez, votre ame est deja entachee pour m'avoir invoque. Autant qu ca serve a quelque chose non ? + Agril + 0,10,20 + 1 + -1 + True + False + False + Regular + 567 + + + 40 + 40 + oui,marche, marché + 30 + 1 + -1 + True + False + False + Regular + 567 + GUMP,Agril Sharnak,4/Oooh, je savais que vous etiez un peu plus fute que l'aspirant chevalier moyen. Et bien...admettons que pour une petite partie de votre ame, une toute petite j'exauce l'une de vos requetes ?;Meme si mon ame est deja entachee, hors de question que je la brade !;refuse;Tres bien, racontes moi l'histoire alors...;story;Hmm...au diable ces bondieuseries Theodosiennes, donne moi la puissance !!;power + + + 50 + 50 + Tres bien, disparaissez, mortel ! Je garde une partie de vous avec moi, de toute maniere ! + refuse + SETONTRIGMOB/ATTACH/xmlvalue,chivsummon,3 + 40 + 1 + -1 + True + False + False + Regular + 567 + + + 60 + 60 + Oh, une histoire banale. Vous ne l'aviez pas deja comprise ? c'etait pourtant evident. Huiric m'a invoque et lie a son service, me demandant les choses habituelles. Pouvoir, savoir, puissance..et la mort de ses rivaux. Aidan allait etre un rival potentiel, vous savez. Un jour ou l'autre. Comment pouvais-je m'abstenir de l'avertir, hein ? Comme je le dis toujours, il faut prendre le mal a sa source ! + story + SETONTRIGMOB/ATTACH/xmlvalue,chivsummon,1 + 40 + 1 + -1 + True + False + False + Regular + 567 + + + 70 + 70 + Ahaha ! Bien sur, mortel, prenez cette epee buveuse d'ames, et fichez moi le camp ! + power + GIVE/<paladinsword/name/Lame Lourde de Terreur (invocation)/hue/2106/weaponattributes.usebestskill/1/weaponattributes.hitleechhits/20/attributes.attackchance/20/ATTACH/temporaryquestobject,Lame Lourde,10080>;SETONTRIGMOB/ATTACH/xmlvalue,chivsummon,2 + 40 + 1 + -1 + True + False + False + Regular + 567 + + + 80 + 80 + SETONNEARBY,2,Agrilspawn/doreset/true + 50 + 1 + 30 + True + False + False + Regular + -1 + + + 90 + 90 + + 1 + -1 + True + False + False + Regular + -1 + + + 100 + 100 + SETONNEARBY,2,Agrilspawn/doreset/true + 60 + 1 + 30 + True + False + False + Regular + -1 + + + 110 + 110 + SETONNEARBY,2,Agrilspawn/doreset/true + 70 + 1 + 30 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivAidan.npc b/XmlQuestNPC/VindsChivAidan.npc new file mode 100644 index 0000000..aa02be3 --- /dev/null +++ b/XmlQuestNPC/VindsChivAidan.npc @@ -0,0 +1,69 @@ + + + + Esprit du Seigneur Aidan + True + 6 + 16 + False + 10 + 1 + 4 + + + 0 + 0 + Pfff, oui sans desir de richesse, de pouvoir, de puissance... + Aidan + -1 + 1 + -1 + True + False + True + Regular + 1774 + + + 10 + 10 + Hmmff, je ne vois vraiment pas pourquoi. Tu n'as jamais exprime le moindre regret pour m'avoir tue + redemption + 0 + 1 + -1 + True + False + True + Regular + 1774 + + + 20 + 20 + Et alors ? Quelle idee de croire un demon ! Qui plus est, il ne t'etait pas meme lie ! C'etait MON invocation ! + influence + SETONNEARBY,7,Adrielspawn/running/true + 10 + 1 + -1 + True + False + True + Regular + 1774 + + + 30 + 30 + SETONNEARBY,4,Damnedspawn/doreset/true + 20 + 1 + 60 + True + False + False + Regular + -1774 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivDore.npc b/XmlQuestNPC/VindsChivDore.npc new file mode 100644 index 0000000..2a7d1b3 --- /dev/null +++ b/XmlQuestNPC/VindsChivDore.npc @@ -0,0 +1,72 @@ + + + + Doré le Jeune + True + 3 + 16 + False + 10 + 0.5 + VindsChivDore + 4 + + + 0 + 0 + Bonjour, jeune ami. Que Theodos guide vos actes ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Ah, mais vous etes deja un fidele ! + chevalerie,chivalry,livre,paladin + SETONTHIS/doreset/true + GETONCARRIED,Saint Codex de Theodos,bookofchivalry,,visible=true + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Très bien. Pour cela, vous devrez passer une petite...epreuve de foi...Desirez vous y aller maintenant ? Ah, au fait, vous n'aurez qu'une seule chance. Theodos n'accepte avec lui que les plus meritants. + chevalerie,chivalry,paladin,livre + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Très bien...alors je ne vous souhaiterais pas bonne chance, mais plutot...que la foi vous guide ! + oui + SETONTRIGMOB/ATTACH/xmlvalue,fiole,0/ATTACH/xmlvalue,noblesse,0/map/Ilshenar/location/(1984,1102,-28) + 20 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivGuard.npc b/XmlQuestNPC/VindsChivGuard.npc new file mode 100644 index 0000000..d25f8f8 --- /dev/null +++ b/XmlQuestNPC/VindsChivGuard.npc @@ -0,0 +1,95 @@ + + + + Garde Noir + True + 3 + 16 + False + 10 + 0.333333333333333 + 6 + + + 0 + 0 + Halte, Mortel ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Sache ceci : Derriere ces portes se trouve le jugement de Théodos, pour ce qu'il vaut. + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Vous avez fait preuve de compassion. Et par votre faute, un coupable n'a pas été chatié. Théodos vous pardonnera sans doute... entrez. + GETONTRIGMOB,[ATTACHMENT,xmlvalue,noblesse,value]=1 + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Vous avez fait preuve de fermeté. Il n'y a nul innocent en cette affaire, mais le plus grand coupable est intouché. Redoutez le jugement. + GETONTRIGMOB,[ATTACHMENT,xmlvalue,noblesse,value]=2 + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 40 + 40 + Quel exploit ! Vous avez mis votre ame en péril, pour un résultat que Théodos apprécierait. Entrez sans crainte et prenez ceci. + GETONTRIGMOB,[ATTACHMENT,xmlvalue,noblesse,value]=3 + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 50 + 50 + Quelle fermeté ! Vous êtes impitoyable, tout comme la prétendue justice. Théodos n'appréciera pas, mais Paladine s'en moque. Entrez. + GETONTRIGMOB,[ATTACHMENT,xmlvalue,noblesse,value]=4 + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivHadriel.npc b/XmlQuestNPC/VindsChivHadriel.npc new file mode 100644 index 0000000..543ca03 --- /dev/null +++ b/XmlQuestNPC/VindsChivHadriel.npc @@ -0,0 +1,104 @@ + + + + Adriel + True + 8 + 16 + False + 10 + 1 + 7 + + + 0 + 0 + Il suffit ! Vous etes enchaine pour une bonne eternite, et pauvre de moi, je suis tout aussi enchaine a vous surveiller pendant ce temps. Taisez-vous ! + -1 + 5 + -1 + True + False + False + Regular + 1758 + + + 10 + 10 + Vous, Mortel ! Oui, vous ! La ! Je vous supplie ! Faites quelque chose avant que je ne devienne fou ! + 0 + 5 + -1 + True + False + False + Regular + 1758 + + + 20 + 20 + Voila ce que je vais faire ! Je vais vous donner le pouvoir de liberer un ou deux de ces idiots. Mais gare ! + 10 + 5 + -1 + True + False + False + Regular + 1758 + + + 30 + 30 + Vous devrez rendre votre decision en ame et conscience, sinon, votre ame risquerait d'en etre entachee ! + 20 + 5 + -1 + True + False + False + Regular + -1 + + + 40 + 40 + Quand vous aurez choisit, vous pourrez rendre votre verdict a l'autel du Jugement, la, dehors... + 30 + 5 + -1 + True + False + False + Regular + 1758 + + + 50 + 50 + Bon, il est temps pour nous de retourner un peu dans les limbes. Bonne chance, mortel ! + 40 + 5 + -1 + True + False + False + Regular + -1 + + + 60 + 60 + SETONNEARBY,2,Adrielspawn/doreset/true;SETONNEARBY,8,Damnedspawn/Doreset/true;SETONCARRIED,Cierge de Compassion/DELETE;GIVE/<dagger/name/Jugement/movable/false/hue/1158> + 50 + 5 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivHuiric.npc b/XmlQuestNPC/VindsChivHuiric.npc new file mode 100644 index 0000000..4130a36 --- /dev/null +++ b/XmlQuestNPC/VindsChivHuiric.npc @@ -0,0 +1,54 @@ + + + + Esprit de Huiric + True + 6 + 16 + False + 10 + 1.5 + 3 + + + 0 + 0 + Oh, regarde, Aidan ! Encore un nooooble guerrier venu nous liberer, sans aucune arriere pensee ! + -1 + 1 + -1 + True + False + True + Regular + 2129 + + + 10 + 10 + Remarque, on ne sait jamais. J'aimerais bien gouter une fois a la redemption + desir + 0 + 1 + -1 + True + False + True + Regular + 2129 + + + 20 + 20 + Je l'ai fait sous influence ! C'est Agril Sharnak qui m'a dit que tu allais tous nous empoisonner ! + regret + 10 + 1 + -1 + True + False + True + Regular + 2129 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivRagots1.npc b/XmlQuestNPC/VindsChivRagots1.npc new file mode 100644 index 0000000..04bc152 --- /dev/null +++ b/XmlQuestNPC/VindsChivRagots1.npc @@ -0,0 +1,54 @@ + + + + Killian + True + 6 + 16 + Codex de Bataille,bookofchivalry + False + 10 + 1 + 3 + + + 0 + 0 + hrmppf + -1 + 1 + -1 + False + False + True + Regular + -1 + + + 10 + 10 + ...Ouaip, comm'j'te dis, y z'ont vire leur chef a grands coup d'pied ou j'pense... + 0 + 1 + -1 + False + False + True + Regular + -1 + + + 20 + 20 + Ouais, c'est bien lui. Toujours a courir les filles, surtout celles avec de jolies robes. Il est parti piccoler ailleurs. + Nerval + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsChivragots2.npc b/XmlQuestNPC/VindsChivragots2.npc new file mode 100644 index 0000000..e069686 --- /dev/null +++ b/XmlQuestNPC/VindsChivragots2.npc @@ -0,0 +1,67 @@ + + + + Ridgley + True + 6 + 16 + False + 10 + 1 + 4 + + + 0 + 0 + Quand meme pas celui qui piccolait et toujours a se ballader cul nul ? + chef + -1 + 1 + -1 + False + False + True + Regular + -1 + + + 10 + 10 + Sans doute dans la forêt de Haven, y a de bon coins, la bas. Mais c'est un roi de l'evasion, faudrait l'attirer comme il faut. + ailleurs, piccoler + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Enfin, si vous tenez VRAIMENT a le rencontrer. Ca en vaut pas vraiment la peine, voyez ? + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Evidemment, ce serait plus simple si vous etiez une jolie fille bien habillee...Heu... + 20 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsCobblerSerpent.npc b/XmlQuestNPC/VindsCobblerSerpent.npc new file mode 100644 index 0000000..cd0fc58 --- /dev/null +++ b/XmlQuestNPC/VindsCobblerSerpent.npc @@ -0,0 +1,52 @@ + + + + Gadosse + True + 4 + 16 + False + 10 + 1 + 3 + + + 0 + 0 + Bottes sur mesure ! Recloutage ! Talonettes ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + N'Hésitez pas, trouvez chaussure à votre pied avec Gadosse la Godasse ! + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + *se ravise* Hmmpf, c'est l'heure de ma pause. Dégagez. + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsEmilie.npc b/XmlQuestNPC/VindsEmilie.npc new file mode 100644 index 0000000..c283381 --- /dev/null +++ b/XmlQuestNPC/VindsEmilie.npc @@ -0,0 +1,40 @@ + + + + La Petite Emilie + True + 3 + 16 + False + 10 + 10 + VindsEmilie + 2 + + + 10 + 10 + Des intrus, au secours, sonnez l'alarme ! A moi, au secours !!! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Mais !! Vous etes tous petits en fait ! Je vais vous Kraaaaser !! + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsFabianTalk.npc b/XmlQuestNPC/VindsFabianTalk.npc new file mode 100644 index 0000000..9354444 --- /dev/null +++ b/XmlQuestNPC/VindsFabianTalk.npc @@ -0,0 +1,171 @@ + + + + Fabian + True + 5 + 16 + Codex de Bataille,bookofchivalry + False + 10 + 1 + VindsFabianTalk + 11 + + + 0 + 0 + J'hésite, tout de même, j'ai peur de m'y ennuyer...*scrute intensément l'océan* + -2 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Ah, de la visite. Je vous en prie, laissez moi à mes pensées. Je suis maudit et je dois agir en conséquence. + Bonjour + 0 + 1 + -1 + True + False + False + Regular + 2123 + + + 20 + 20 + Et bien, comme vous pouvez le constater, je ne suis plus exactement le bellâtre que j'étais. Je n'ai même plus la peau sur les os, si vous voyez ce que je veux dire. + maudit + 10 + 4 + -1 + True + False + False + Regular + 2123 + + + 30 + 30 + J'étais autrefois un chevalier, et un bon, jusqu'a ce que, et bien...je sois moins bon. Ce qui m'amène à cette situation génante. + 20 + 1 + -1 + True + False + False + Regular + 2123 + + + 40 + 40 + Je suis un mort-vivant, bon sang ! Il ne me reste plus qu'a me jeter dans l'océan pour y mourir ! Enfin, tout du moins pour y attendre, mais c'est l'intention qui compte. Et personne à qui transmettre mon recueil de prières ... + situation,genante + 30 + 1 + -1 + True + False + False + Regular + 2123 + + + 50 + 50 + Oh ! vous souhaitez devenir chevalier ? + priere,recueil + 40 + 1 + -1 + True + False + False + Regular + 2123 + + + 60 + 60 + Hmm...Vous avez un drôle de passé pour un ecuyer. Voulez-vous abandonner votre voie actuelle ? + oui,chevalier,paladin + GETONCARRIED,*,bookofninjitsu,,visible=true + 50 + 1 + -1 + True + False + False + Regular + 2123 + + + 70 + 70 + Vous rigolez, là ? Je sens en vous la même énergie qui m'a fait celà ! Bon, je veux bien vous laisser une chance, mais vous devez abandonner votre voie actuelle ! + oui,chevalier,paladin + GETONCARRIED,*,NecromancerSpellBook,,visible=true + 50 + 1 + -1 + True + False + False + Regular + 2123 + + + 80 + 80 + Hmm...C'est une noble voie que vous avez choisit, mais la voie du chevalier est exclusive. Voulez vous abandonner l'art du duel honorable ? + oui,chevalier,paladin + GETONCARRIED,*,bookofbushido,,visible=true + 50 + 1 + -1 + True + False + False + Regular + 2123 + + + 90 + 90 + Qu'il en soit ainsi... + abandonner,oui + SETONCARRIED,*,necromancerspellbook,,/DELETE ; SETONCARRIED,*,bookofninjitsu,,/DELETE ; SETONCARRIED,*,bookofbushdo,,/DELETE + 60,70,80 + 1 + -1 + True + False + False + Regular + 2123 + + + 100 + 100 + Très bien.. N'oubliez jamais vos idéaux. Bon, et maintenant, laissez moi réfléchir... + GIVE/<bookofchivalry/name/Codex de Bataille>;GIVE/closewoundsscroll;SETONCARRIED,*,necromancerspellbook,,/DELETE;SETONCARRIED,*,BookOfBushido,,/DELETE + 50,90 + 1 + -1 + True + False + False + Regular + 2123 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsGaspode.npc b/XmlQuestNPC/VindsGaspode.npc new file mode 100644 index 0000000..09732b6 --- /dev/null +++ b/XmlQuestNPC/VindsGaspode.npc @@ -0,0 +1,81 @@ + + + + gaspode + True + 6 + 16 + False + 10 + 1 + 5 + + + 0 + 0 + Aboie, aboie ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Wah ! wah ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + gemit, geint ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Tu devrais donner une saucisse au petit chien + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 40 + 40 + Merci, ca c'est gentil..heu.. je voulais dire.. aboie, aboie ! fretille ! + saucisse + TAKEBYTYPE,1,1/sausage + AMOUNTCARRIED,sausage>0 + 30 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsGuardSpeech.npc b/XmlQuestNPC/VindsGuardSpeech.npc new file mode 100644 index 0000000..57b492c --- /dev/null +++ b/XmlQuestNPC/VindsGuardSpeech.npc @@ -0,0 +1,52 @@ + + + + Kaede + True + 3 + 16 + False + 10 + 1 + 3 + + + 10 + 10 + Aux armes, aux armes !! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Gibier de potence, tu vas mourir ! + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Pas de pitie pour les criminels dans ton genre ! + 20 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsHealerSerpent.npc b/XmlQuestNPC/VindsHealerSerpent.npc new file mode 100644 index 0000000..32164db --- /dev/null +++ b/XmlQuestNPC/VindsHealerSerpent.npc @@ -0,0 +1,52 @@ + + + + Elwood + True + 3 + 16 + False + 10 + 1 + 3 + + + 0 + 0 + Et dire que j'ai fait voeu de piété envers tous...quelle sottise ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Ne saignez pas sur mon plancher, étranger ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Ah, ces étrangers, quelle maladresse... + -1 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsIronCalice.npc b/XmlQuestNPC/VindsIronCalice.npc new file mode 100644 index 0000000..e50469b --- /dev/null +++ b/XmlQuestNPC/VindsIronCalice.npc @@ -0,0 +1,30 @@ + + + + Calice de fer + True + 3 + 16 + Codex de Bataille,BookofChivalry + False + 10 + 0.166666666666667 + 1 + + + 0 + 0 + *Vous avez la sensation qu'une force indefectible vous penetre* + Théodos + SETONCARRIED,La Voie de la Vertu/Completed1/true/Objective2/Retournez voir le Vieux Prêtre;GIVE/ConsecrateWeaponScroll + GETONCARRIED,La Voie de la Vertu,completed1=false + -1 + 1 + -1 + True + False + False + Regular + 1266 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsNinEngence.npc b/XmlQuestNPC/VindsNinEngence.npc new file mode 100644 index 0000000..c63dd0c --- /dev/null +++ b/XmlQuestNPC/VindsNinEngence.npc @@ -0,0 +1,65 @@ + + + + a moloch + True + 3 + 16 + False + 10 + 2 + 4 + + + 0 + 0 + *sort de l'ombre* + -1 + 1 + -1 + True + False + False + Regular + 6 + + + 10 + 10 + Gnihihihiiii....Je vais vous demembrer, vous DEMEMBRER !!!! + 0 + 1 + -1 + True + False + False + Regular + 37 + + + 20 + 20 + TUER TUER TUEEEEERRRRR !!!! + 10 + 1 + 10 + True + False + False + Regular + 37 + + + 30 + 30 + Rejoignez moi dans l'ombre ! + 20 + 1 + 5 + True + False + False + Regular + 37 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsNinMaster.npc b/XmlQuestNPC/VindsNinMaster.npc new file mode 100644 index 0000000..d4cbfca --- /dev/null +++ b/XmlQuestNPC/VindsNinMaster.npc @@ -0,0 +1,183 @@ + + + + Le Vieil Homme + True + 5 + 16 + ATTACHMENT,Decouvrir les Ombres,xmlquestattachment + False + 10 + 0.25 + 12 + + + 0 + 0 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Bienvenue dans mon petit paradis. Prenez vos aises, faites comme chez vous...Qu'est ce que vous voulez ? parler Théologie ? + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Vous n'avez pas à connaitre mon nom. Pour vous, je serais le Vieil Homme. + qui + SETONTHIS/doreset/true + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Je suis le vieil homme. J'en sais beaucoup, mais vous n'avez pas à en savoir autant que moi. Le privilège de l'âge, si vous voulez...*rire* + Vieill Homme, vieil homme,Vieil homme + SETONTHIS/doreset/true + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 40 + 40 + Une messagère de sombres auspices pour certains, de renouveau pour d'autres. Elle est ancienne, mais presque tous ont oublié le temps ou son nom était Gorgothra. + Lueur Noire,lueur noire,Lueur noir + SETONTHIS/doreset/true + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 50 + 50 + La Dague du Destin, prodigue tout à la fois en benedictions et en caprices... + Yrtuir + SETONTHIS/doreset/true + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 60 + 60 + La protectrice des miséreux, et l'une de nos plus fiables alliées... Elle oeuvre pour ceux qui comprennent réellement le sens de la vie... + Hansy + SETONTHIS/doreset/true + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 70 + 70 + Le Patron des Guerisseurs et des alchimistes...et le Maitre des Poisons. + Sulimo + SETONTHIS/doreset/true + 10 + 1 + -1 + True + False + False + Regular + -1 + + + 80 + 80 + Nathaniel + 10 + 1 + -1 + True + False + False + Regular + -1 + GUMP,Le Vieil Homme,4/Donc vous venez de la part de "Nathaniel"...dois je en déduire que vous désirez acquérir la maitrise des Ombres ?;Je desire ce pouvoir;accept;Non, je me debrouille tres bien sans;refuse + + + 90 + 90 + accept + GIVE,1/<questholder/name/Decouvrir les Ombres/notestring/Le Liber Occultatum est enfoui quelque part dans le Tombeau du Roi Silencieux. Erik Patte de Pie est l'un des rares aventuriers à en etre sorti vivant. Peut etre detient il quelques informations à meme de vous aider ? Le Vieil Homme peut à tout moment vous envoyer au Tombeau du Roi Silencieux. Préparez vous bien !/objective1/Trouvez Erik Patte de Pie/objective3/Trouvez le Liber Occultatum dans le Tombeau du Roi Silencieux/autoreward/false/repeatable/false + 80 + 1 + -1 + True + False + False + Regular + -1 + GUMP,Le Vieil Homme,4/Très bien, voici un petit carnet vous expliquant la marche à suivre..ne le perdez surtout pas !! + + + 110 + 110 + Tres bien, vous savez ou me trouver... + refuse + + 1 + -1 + True + False + False + Regular + -1 + + + 120 + 120 + 10 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsNinjitsuDoor.npc b/XmlQuestNPC/VindsNinjitsuDoor.npc new file mode 100644 index 0000000..99f78c0 --- /dev/null +++ b/XmlQuestNPC/VindsNinjitsuDoor.npc @@ -0,0 +1,29 @@ + + + + Porte + True + 5 + 16 + Lassombra,dagger&Yeux d'Yrtuir,dices&Sang de Sulimo,bloodvial + False + 10 + 0,0833333333333333 + 1 + + + 0 + 0 + Les Sceaux Antiques ont etes brises. + Gorgothra + SETONTHIS/OFFSET,0,-1,0,;SOUND,542;SETONNEARBY,2,Spawner/running/true + -1 + 1 + -1 + True + False + False + Regular + 495 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsOrcSentinelle.npc b/XmlQuestNPC/VindsOrcSentinelle.npc new file mode 100644 index 0000000..ce1beb5 --- /dev/null +++ b/XmlQuestNPC/VindsOrcSentinelle.npc @@ -0,0 +1,29 @@ + + + + Sentinelle Orque + True + 8 + 16 + False + 10 + 1 + VindsOrcSentinelle + 1 + + + 0 + 0 + Alerte, alerte ! Des Intrus, sonnez les tambours de guerre ! + SETONNEARBY,20,*/combatant/TRIGMOB/warmode/true/MSG/Aux armes, aux armes !! + TRIGMOB/Hidden/false + -1 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsTavernSerpent.npc b/XmlQuestNPC/VindsTavernSerpent.npc new file mode 100644 index 0000000..0262028 --- /dev/null +++ b/XmlQuestNPC/VindsTavernSerpent.npc @@ -0,0 +1,65 @@ + + + + Herbert + True + 3 + 16 + False + 10 + 1 + 4 + + + 0 + 0 + Hrmmpff + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + *jette un regard mauvais* + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + *crache* Vous voulez quoi ? + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Ils prennent nos terres, notre seigneur, et maintenant nos bouteilles.. + -1 + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindsTheodosPriest.npc b/XmlQuestNPC/VindsTheodosPriest.npc new file mode 100644 index 0000000..0cb8a3f --- /dev/null +++ b/XmlQuestNPC/VindsTheodosPriest.npc @@ -0,0 +1,140 @@ + + + + Terry + True + 3 + 16 + Codex de Bataille,Bookofchivalry + ATTACHMENT,La Voie de la Vertu,XmlQuestAttachment + False + 10 + 1 + VindsTheodosPriest + 9 + + + 0 + 0 + -2 + 1 + -1 + True + False + False + Regular + -1 + + + 10 + 10 + Vous avez réussi ?! Fantastique ! Quelle bataille cela à du être ! Je ne peux plus rien vous apprendre, mais acceptez ceci, avec ma bénédiction ! + GIVE/dispelevilscroll ;SETONCARRIED,La Voie de la Vertu/DELETE ; SETONTRIGMOB/ATTACH/La Voie de la Vertu,XmlQuestAttachment + GETONCARRIED,La Voie de la Vertu,questholder,,completed3=true + 0,-2 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + Ah, vous revoici ! Tenez, pour vous récompenser de votre dévotion. Et si maintenant nous parlions un peu ? + GIVE/<removecursescroll>;SETONCARRIED,La Voie de la Vertu/completed2/true + GETONCARRIED,La Voie de la Vertu,questholder,,completed1=true & GETONCARRIED,La Voie de la Vertu,questholder,,completed2=false & GETONCARRIED,La Voie de la Vertu,questholder,,completed3=false + 0,-2 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Bonjour, que désirez vous ? + ~GETONCARRIED,La Voie de la Vertu,Visible=true + 0,-2 + 1 + -1 + True + False + False + Regular + -1 + + + 40 + 40 + Hmm, vous possédez une copie de notre recueil de Psaumes, mais il est incomplet. Ou vous etes vous donc procuré cela ? + paladin,chevalerie + 30 + 1 + -1 + True + False + False + Regular + -1 + + + 50 + 50 + Les brigands qui infestent les fermes semblent se rassembler sous la banière d'un certain Nerval. + 20 + 1 + -1 + True + False + False + Regular + -1 + + + 60 + 60 + Il semble complètement insaisissable. Si vous pouviez enquéter... + SETONCARRIED,La Voie de la Vertu/Objective3/Enquéter sur Nerval, le seigneur Bandit + 50 + 1 + -1 + True + False + False + Regular + -1 + + + 60 + 60 + Je vois. Mais suivez vous vraiment la voie de la Justice ? Plus qu'une idée, c'est une vocation. Si vous voulez que nous poursuivions, vous devriez tout d'abord aller prier à l'autel de Théodos. + Fabian + GIVE/<questholder/name/La Voie de la Vertu/titlestring/La Voie de la Vertu/Objective1/Allez prier à l'autel de Théodos/repeatable/false/Autoreward/false + 40 + 1 + -1 + True + False + False + Regular + -1 + + + 80 + 80 + + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/VindschauffeurSerpent.npc b/XmlQuestNPC/VindschauffeurSerpent.npc new file mode 100644 index 0000000..4a39386 --- /dev/null +++ b/XmlQuestNPC/VindschauffeurSerpent.npc @@ -0,0 +1,90 @@ + + + + Yvan + True + 30 + 16 + False + 10 + 1 + 6 + + + 10 + 10 + Allez, on acclame bien fort le Duc, citoyens ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 20 + 20 + On exprime un peu plus sa joie, s'il vous plait ! *agite sa hallebarde* + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 30 + 30 + Hmm, t'as pas l'air très convaincu, toi... + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 40 + 40 + Longue vie au Duc, Longue vie aux Tarragons ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 50 + 50 + Louez les Tarragons qui vous libèrent de la tyrannie ! + -1 + 1 + -1 + True + False + False + Regular + -1 + + + 60 + 60 + + 1 + -1 + True + False + False + Regular + -1 + + \ No newline at end of file diff --git a/XmlQuestNPC/XmlQuestNPC.csproj b/XmlQuestNPC/XmlQuestNPC.csproj new file mode 100644 index 0000000..a3cb215 --- /dev/null +++ b/XmlQuestNPC/XmlQuestNPC.csproj @@ -0,0 +1,78 @@ + + + + + Debug + AnyCPU + {8F286FFF-4090-4AA8-B0EA-0E289FBD9D28} + Exe + Properties + XmlQuestNPC + XmlQuestNPC + v4.5 + 512 + SAK + SAK + SAK + SAK + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/web/favicon.ico b/web/favicon.ico new file mode 100644 index 0000000..b7cc658 Binary files /dev/null and b/web/favicon.ico differ diff --git a/web/status.html b/web/status.html new file mode 100644 index 0000000..d095428 --- /dev/null +++ b/web/status.html @@ -0,0 +1,47 @@ + + + + +Vivre Server Status + + + + +

Vivre Server Status

+ + + + + + + + + + + + + + + + + +
NomRégionTemps connecté
ScriptizInconnue +46 minutes
ErzeHythloth +45 minutes
Val Aurite [Technicien, CA] +44 minutes
Rolix de Hyel +43 minutes
Iscariote Sa'Duj +41 minutes
VindsvalInconnue +39 minutes
Sophie-Anne +36 minutes
Ethan +26 minutes
Sareth [Oeil du Serpent, Oph]New Haven +17 minutes
Aril StanPrison de Magincia +13 minutes
Kassgul Illumina [Disciple de Kalynr, MN]New Haven +15 minutes
Guilhem +9 minutes
+ + + diff --git a/web/style.css b/web/style.css new file mode 100644 index 0000000..9830fa5 --- /dev/null +++ b/web/style.css @@ -0,0 +1,50 @@ +body { + background-color: #000000; + color: #C1C1C1; + font-size: 12px; + font-family: Tahoma, Arial, sans-serif; + width: 600px; + margin: auto; + border: 1px solid #C1C1C1; + /*min-height: 500px;*/ + margin-top: 3px; +} + +h1 { + font-family: Tahoma, Arial, sans-serif; + font-size: 18px; + padding-left: 3px; +} + +p#header { + padding: 3px; +} + +table#players { + width: 600px; + margin: auto; +} + +tr.titleRow { + background-color: #270303; + font-family: Tahoma, Arial, sans-serif; + font-weight: bold; + font-size: 13px; + text-align: left; + color : #968865; +} + +tr.light { + background-color: #333333; +} + +th, td { + padding: 3px; +} + +p#footer { + margin-top: 30px; + margin-right: 3px; + font-size: 10px; + text-align: right; +} \ No newline at end of file diff --git a/zlib32.dll b/zlib32.dll new file mode 100644 index 0000000..13c58dc Binary files /dev/null and b/zlib32.dll differ diff --git a/zlib64.dll b/zlib64.dll new file mode 100644 index 0000000..a43d73d Binary files /dev/null and b/zlib64.dll differ